From f41967cfa32f4b08a9fc97cda1d6498c9acc8534 Mon Sep 17 00:00:00 2001 From: sanctum32 Date: Fri, 11 Oct 2013 19:23:29 +0300 Subject: [PATCH] =?UTF-8?q?[12682]=20Add=20ACTION=5FT=5FTHROW=5FAI=5FEVENT?= =?UTF-8?q?=20and=20EVENT=5FT=5FRECEIVE=5FAI=5FEVENT=20to=20=E2=80=A6?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit original author @Schmoozerd, commit is based on https://github.com/cmangos/mangos-cata/commit/64fa443957ba51731d2a7c1d90a948d84e641748 --- src/game/CreatureEventAI.cpp | 54 +++++++++++++++++++++++---------- src/game/CreatureEventAI.h | 43 ++++++++++++++++++-------- src/game/CreatureEventAIMgr.cpp | 36 +++++++++++++++++++++- src/shared/revision_nr.h | 2 +- 4 files changed, 105 insertions(+), 30 deletions(-) diff --git a/src/game/CreatureEventAI.cpp b/src/game/CreatureEventAI.cpp index cf024ff60..71e6457d6 100644 --- a/src/game/CreatureEventAI.cpp +++ b/src/game/CreatureEventAI.cpp @@ -158,7 +158,7 @@ inline bool IsTimerBasedEvent(EventAI_Type type) } } -bool CreatureEventAI::ProcessEvent(CreatureEventAIHolder& pHolder, Unit* pActionInvoker) +bool CreatureEventAI::ProcessEvent(CreatureEventAIHolder& pHolder, Unit* pActionInvoker, Creature* pAIEventSender) { if (!pHolder.Enabled || pHolder.Time) return false; @@ -412,6 +412,8 @@ bool CreatureEventAI::ProcessEvent(CreatureEventAIHolder& pHolder, Unit* pAction pHolder.UpdateRepeatTimer(m_creature, event.buffed.repeatMin, event.buffed.repeatMax); break; } + case EVENT_T_RECEIVE_AI_EVENT: + break; default: sLog.outErrorEventAI("Creature %u using Event %u has invalid Event Type(%u), missing from ProcessEvent() Switch.", m_creature->GetEntry(), pHolder.Event.event_id, pHolder.Event.event_type); break; @@ -432,7 +434,7 @@ bool CreatureEventAI::ProcessEvent(CreatureEventAIHolder& pHolder, Unit* pAction if (!(pHolder.Event.event_flags & EFLAG_RANDOM_ACTION)) { for (uint32 j = 0; j < MAX_ACTIONS; ++j) - ProcessAction(pHolder.Event.action[j], rnd, pHolder.Event.event_id, pActionInvoker); + ProcessAction(pHolder.Event.action[j], rnd, pHolder.Event.event_id, pActionInvoker, pAIEventSender); } // Process actions, random case else @@ -460,13 +462,13 @@ bool CreatureEventAI::ProcessEvent(CreatureEventAIHolder& pHolder, Unit* pAction } } - ProcessAction(pHolder.Event.action[j], rnd, pHolder.Event.event_id, pActionInvoker); + ProcessAction(pHolder.Event.action[j], rnd, pHolder.Event.event_id, pActionInvoker, pAIEventSender); } } return true; } -void CreatureEventAI::ProcessAction(CreatureEventAI_Action const& action, uint32 rnd, uint32 EventId, Unit* pActionInvoker) +void CreatureEventAI::ProcessAction(CreatureEventAI_Action const& action, uint32 rnd, uint32 EventId, Unit* pActionInvoker, Creature* pAIEventSender) { if (action.type == ACTION_T_NONE) return; @@ -588,7 +590,7 @@ void CreatureEventAI::ProcessAction(CreatureEventAI_Action const& action, uint32 selectFlags = SELECT_FLAG_IN_LOS; } - Unit* target = GetTargetByType(action.cast.target, pActionInvoker, spellId, selectFlags); + Unit* target = GetTargetByType(action.cast.target, pActionInvoker, pAIEventSender, spellId, selectFlags); if (!target) { sLog.outDebug("CreatureEventAI: NULL target for ACTION_T_CAST creature entry %u casting spell id %u", m_creature->GetEntry(), action.cast.spellId); @@ -629,7 +631,7 @@ void CreatureEventAI::ProcessAction(CreatureEventAI_Action const& action, uint32 } case ACTION_T_SUMMON: { - Unit* target = GetTargetByType(action.summon.target, pActionInvoker); + Unit* target = GetTargetByType(action.summon.target, pActionInvoker, pAIEventSender); Creature* pCreature = NULL; @@ -645,7 +647,7 @@ void CreatureEventAI::ProcessAction(CreatureEventAI_Action const& action, uint32 break; } case ACTION_T_THREAT_SINGLE_PCT: - if (Unit* target = GetTargetByType(action.threat_single_pct.target, pActionInvoker)) + if (Unit* target = GetTargetByType(action.threat_single_pct.target, pActionInvoker, pAIEventSender)) m_creature->getThreatManager().modifyThreatPercent(target, action.threat_single_pct.percent); break; case ACTION_T_THREAT_ALL_PCT: @@ -657,18 +659,18 @@ void CreatureEventAI::ProcessAction(CreatureEventAI_Action const& action, uint32 break; } case ACTION_T_QUEST_EVENT: - if (Unit* target = GetTargetByType(action.quest_event.target, pActionInvoker)) + if (Unit* target = GetTargetByType(action.quest_event.target, pActionInvoker, pAIEventSender)) if (target->GetTypeId() == TYPEID_PLAYER) ((Player*)target)->AreaExploredOrEventHappens(action.quest_event.questId); break; case ACTION_T_CAST_EVENT: - if (Unit* target = GetTargetByType(action.cast_event.target, pActionInvoker, 0, SELECT_FLAG_PLAYER)) + if (Unit* target = GetTargetByType(action.cast_event.target, pActionInvoker, pAIEventSender, 0, SELECT_FLAG_PLAYER)) if (target->GetTypeId() == TYPEID_PLAYER) ((Player*)target)->CastedCreatureOrGO(action.cast_event.creatureId, m_creature->GetObjectGuid(), action.cast_event.spellId); break; case ACTION_T_SET_UNIT_FIELD: { - Unit* target = GetTargetByType(action.set_unit_field.target, pActionInvoker); + Unit* target = GetTargetByType(action.set_unit_field.target, pActionInvoker, pAIEventSender); // not allow modify important for integrity object fields if (action.set_unit_field.field < OBJECT_END || action.set_unit_field.field >= UNIT_END) @@ -680,11 +682,11 @@ void CreatureEventAI::ProcessAction(CreatureEventAI_Action const& action, uint32 break; } case ACTION_T_SET_UNIT_FLAG: - if (Unit* target = GetTargetByType(action.unit_flag.target, pActionInvoker)) + if (Unit* target = GetTargetByType(action.unit_flag.target, pActionInvoker, pAIEventSender)) target->SetFlag(UNIT_FIELD_FLAGS, action.unit_flag.value); break; case ACTION_T_REMOVE_UNIT_FLAG: - if (Unit* target = GetTargetByType(action.unit_flag.target, pActionInvoker)) + if (Unit* target = GetTargetByType(action.unit_flag.target, pActionInvoker, pAIEventSender)) target->RemoveFlag(UNIT_FIELD_FLAGS, action.unit_flag.value); break; case ACTION_T_AUTO_ATTACK: @@ -744,7 +746,7 @@ void CreatureEventAI::ProcessAction(CreatureEventAI_Action const& action, uint32 break; } case ACTION_T_REMOVEAURASFROMSPELL: - if (Unit* target = GetTargetByType(action.remove_aura.target, pActionInvoker)) + if (Unit* target = GetTargetByType(action.remove_aura.target, pActionInvoker, pAIEventSender)) target->RemoveAurasDueToSpell(action.remove_aura.spellId); break; case ACTION_T_RANGED_MOVEMENT: @@ -773,7 +775,7 @@ void CreatureEventAI::ProcessAction(CreatureEventAI_Action const& action, uint32 break; case ACTION_T_SUMMON_ID: { - Unit* target = GetTargetByType(action.summon_id.target, pActionInvoker); + Unit* target = GetTargetByType(action.summon_id.target, pActionInvoker, pAIEventSender); CreatureEventAI_Summon_Map::const_iterator i = sEventAIMgr.GetCreatureEventAISummonMap().find(action.summon_id.spawnId); if (i == sEventAIMgr.GetCreatureEventAISummonMap().end()) @@ -821,7 +823,7 @@ void CreatureEventAI::ProcessAction(CreatureEventAI_Action const& action, uint32 } case ACTION_T_SET_INST_DATA64: { - Unit* target = GetTargetByType(action.set_inst_data64.target, pActionInvoker); + Unit* target = GetTargetByType(action.set_inst_data64.target, pActionInvoker, pAIEventSender); if (!target) { sLog.outErrorEventAI("Event %d attempt to set instance data64 but Target == NULL. Creature %d", EventId, m_creature->GetEntry()); @@ -907,6 +909,11 @@ void CreatureEventAI::ProcessAction(CreatureEventAI_Action const& action, uint32 break; } + case ACTION_T_THROW_AI_EVENT: + { + SendAIEvent(AIEventType(action.throwEvent.eventType), pActionInvoker, 0, action.throwEvent.radius); + break; + } } } @@ -1070,6 +1077,19 @@ void CreatureEventAI::SummonedCreatureDespawn(Creature* pUnit) } } +void CreatureEventAI::ReceiveAIEvent(AIEventType eventType, Creature* pSender, Unit* pInvoker) +{ + if (m_bEmptyList || !pSender) + return; + + for (CreatureEventAIList::iterator itr = m_CreatureEventAIList.begin(); itr != m_CreatureEventAIList.end(); ++itr) + { + if (itr->Event.event_type == EVENT_T_RECEIVE_AI_EVENT && + itr->Event.receiveAIEvent.eventType == eventType && (!itr->Event.receiveAIEvent.senderEntry || itr->Event.receiveAIEvent.senderEntry == pSender->GetEntry())) + ProcessEvent(*itr, pInvoker, pSender); + } +} + void CreatureEventAI::EnterCombat(Unit* enemy) { // Check for on combat start events @@ -1288,7 +1308,7 @@ inline int32 CreatureEventAI::GetRandActionParam(uint32 rnd, int32 param1, int32 return 0; } -inline Unit* CreatureEventAI::GetTargetByType(uint32 Target, Unit* pActionInvoker, uint32 forSpellId, uint32 selectFlags) +inline Unit* CreatureEventAI::GetTargetByType(uint32 Target, Unit* pActionInvoker, Creature* pAIEventSender, uint32 forSpellId, uint32 selectFlags) { switch (Target) { @@ -1312,6 +1332,8 @@ inline Unit* CreatureEventAI::GetTargetByType(uint32 Target, Unit* pActionInvoke return pActionInvoker; case TARGET_T_ACTION_INVOKER_OWNER: return pActionInvoker ? pActionInvoker->GetCharmerOrOwnerOrSelf() : NULL; + case TARGET_T_EVENT_SENDER: + return pAIEventSender; default: return NULL; }; diff --git a/src/game/CreatureEventAI.h b/src/game/CreatureEventAI.h index 5bcd49112..22a6c69d3 100644 --- a/src/game/CreatureEventAI.h +++ b/src/game/CreatureEventAI.h @@ -63,6 +63,7 @@ enum EventAI_Type EVENT_T_MISSING_AURA = 27, // Param1 = SpellID, Param2 = Number of time stacked expected, Param3/4 Repeat Min/Max EVENT_T_TARGET_MISSING_AURA = 28, // Param1 = SpellID, Param2 = Number of time stacked expected, Param3/4 Repeat Min/Max EVENT_T_TIMER_GENERIC = 29, // InitialMin, InitialMax, RepeatMin, RepeatMax + EVENT_T_RECEIVE_AI_EVENT = 30, // AIEventType, Sender-Entry, unused, unused EVENT_T_END, }; @@ -114,6 +115,7 @@ enum EventAI_ActionType ACTION_T_SET_INVINCIBILITY_HP_LEVEL = 42, // MinHpValue, format(0-flat,1-percent from max health) ACTION_T_MOUNT_TO_ENTRY_OR_MODEL = 43, // Creature_template entry(param1) OR ModelId (param2) (or 0 for both to unmount) ACTION_T_CHANCED_TEXT = 44, // Chance to display the text, TextId1, optionally TextId2. If more than just -TextId1 is defined, randomize. Negative values. + ACTION_T_THROW_AI_EVENT = 45, // EventType, Radius, unused ACTION_T_END, }; @@ -123,19 +125,20 @@ enum Target TARGET_T_SELF = 0, // Self cast // Hostile targets (if pet then returns pet owner) - TARGET_T_HOSTILE, // Our current target (ie: highest aggro) - TARGET_T_HOSTILE_SECOND_AGGRO, // Second highest aggro (generaly used for cleaves and some special attacks) - TARGET_T_HOSTILE_LAST_AGGRO, // Dead last on aggro (no idea what this could be used for) - TARGET_T_HOSTILE_RANDOM, // Just any random target on our threat list - TARGET_T_HOSTILE_RANDOM_NOT_TOP, // Any random target except top threat + TARGET_T_HOSTILE = 1, // Our current target (ie: highest aggro) + TARGET_T_HOSTILE_SECOND_AGGRO = 2, // Second highest aggro (generaly used for cleaves and some special attacks) + TARGET_T_HOSTILE_LAST_AGGRO = 3, // Dead last on aggro (no idea what this could be used for) + TARGET_T_HOSTILE_RANDOM = 4, // Just any random target on our threat list + TARGET_T_HOSTILE_RANDOM_NOT_TOP = 5, // Any random target except top threat // Invoker targets (if pet then returns pet owner) - TARGET_T_ACTION_INVOKER, // Unit who caused this Event to occur (only works for EVENT_T_AGGRO, EVENT_T_KILL, EVENT_T_DEATH, EVENT_T_SPELLHIT, EVENT_T_OOC_LOS, EVENT_T_FRIENDLY_HP, EVENT_T_FRIENDLY_IS_CC, EVENT_T_FRIENDLY_MISSING_BUFF) - TARGET_T_ACTION_INVOKER_OWNER, // Unit who is responsible for Event to occur (only works for EVENT_T_AGGRO, EVENT_T_KILL, EVENT_T_DEATH, EVENT_T_SPELLHIT, EVENT_T_OOC_LOS, EVENT_T_FRIENDLY_HP, EVENT_T_FRIENDLY_IS_CC, EVENT_T_FRIENDLY_MISSING_BUFF) + TARGET_T_ACTION_INVOKER = 6, // Unit who caused this Event to occur (only works for EVENT_T_AGGRO, EVENT_T_KILL, EVENT_T_DEATH, EVENT_T_SPELLHIT, EVENT_T_OOC_LOS, EVENT_T_FRIENDLY_HP, EVENT_T_FRIENDLY_IS_CC, EVENT_T_FRIENDLY_MISSING_BUFF) + TARGET_T_ACTION_INVOKER_OWNER = 7, // Unit who is responsible for Event to occur (only works for EVENT_T_AGGRO, EVENT_T_KILL, EVENT_T_DEATH, EVENT_T_SPELLHIT, EVENT_T_OOC_LOS, EVENT_T_FRIENDLY_HP, EVENT_T_FRIENDLY_IS_CC, EVENT_T_FRIENDLY_MISSING_BUFF) + TARGET_T_EVENT_SENDER = 10, // Unit who sent an AIEvent that was received with EVENT_T_RECEIVE_AI_EVENT // Hostile targets (including pets) - TARGET_T_HOSTILE_RANDOM_PLAYER, // Just any random player on our threat list - TARGET_T_HOSTILE_RANDOM_NOT_TOP_PLAYER, // Any random player from threat list except top threat + TARGET_T_HOSTILE_RANDOM_PLAYER = 8, // Just any random player on our threat list + TARGET_T_HOSTILE_RANDOM_NOT_TOP_PLAYER = 9, // Any random player from threat list except top threat TARGET_T_END }; @@ -392,6 +395,13 @@ struct CreatureEventAI_Action uint32 chance; int32 TextId[2]; } chanced_text; + // ACTION_T_THROW_AI_EVENT = 45 + struct + { + uint32 eventType; + uint32 radius; + uint32 unused; + } throwEvent; // RAW struct { @@ -537,6 +547,14 @@ struct CreatureEventAI_Event uint32 repeatMin; uint32 repeatMax; } buffed; + // EVENT_T_RECEIVE_AI_EVENT = 30 + struct + { + uint32 eventType; // See CreatureAI.h enum AIEventType - Receive only events of this type + uint32 senderEntry; // Optional npc from only whom this event can be received + uint32 unused1; + uint32 unused2; + } receiveAIEvent; // RAW struct { @@ -607,14 +625,15 @@ class MANGOS_DLL_SPEC CreatureEventAI : public CreatureAI void ReceiveEmote(Player* pPlayer, uint32 text_emote) override; void SummonedCreatureJustDied(Creature* unit) override; void SummonedCreatureDespawn(Creature* unit) override; + void ReceiveAIEvent(AIEventType eventType, Creature* pSender, Unit* pInvoker) override; static int Permissible(const Creature*); - bool ProcessEvent(CreatureEventAIHolder& pHolder, Unit* pActionInvoker = NULL); - void ProcessAction(CreatureEventAI_Action const& action, uint32 rnd, uint32 EventId, Unit* pActionInvoker); + bool ProcessEvent(CreatureEventAIHolder& pHolder, Unit* pActionInvoker = NULL, Creature* pAIEventSender = NULL); + void ProcessAction(CreatureEventAI_Action const& action, uint32 rnd, uint32 EventId, Unit* pActionInvoker, Creature* pAIEventSender); inline uint32 GetRandActionParam(uint32 rnd, uint32 param1, uint32 param2, uint32 param3); inline int32 GetRandActionParam(uint32 rnd, int32 param1, int32 param2, int32 param3); - inline Unit* GetTargetByType(uint32 Target, Unit* pActionInvoker, uint32 forSpellId = 0, uint32 selectFlags = 0); + inline Unit* GetTargetByType(uint32 Target, Unit* pActionInvoker, Creature* pAIEventSender, uint32 forSpellId = 0, uint32 selectFlags = 0); void DoScriptText(int32 textEntry, WorldObject* pSource, Unit* target); diff --git a/src/game/CreatureEventAIMgr.cpp b/src/game/CreatureEventAIMgr.cpp index 3ba8d717a..cbec4ad8a 100644 --- a/src/game/CreatureEventAIMgr.cpp +++ b/src/game/CreatureEventAIMgr.cpp @@ -27,6 +27,7 @@ #include "ObjectGuid.h" #include "GridDefines.h" #include "SpellMgr.h" +#include "World.h" INSTANTIATE_SINGLETON_1(CreatureEventAIMgr); @@ -486,7 +487,22 @@ void CreatureEventAIMgr::LoadCreatureEventAI_Scripts() sLog.outErrorEventAI("Creature %u are using repeatable event(%u) with param4 < param3 (RepeatMax < RepeatMin). Event will never repeat.", temp.creature_id, i); break; } - + case EVENT_T_RECEIVE_AI_EVENT: + { + // Sender-Creature does not exist in database + if (temp.receiveAIEvent.senderEntry && !sCreatureStorage.LookupEntry(temp.receiveAIEvent.senderEntry)) + { + sLog.outErrorDb("CreatureEventAI: Event %u has nonexisting creature (%u) defined for event RECEIVE_AI_EVENT, skipping.", i, temp.receiveAIEvent.senderEntry); + continue; + } + // Event-Type is not defined + if (temp.receiveAIEvent.eventType >= MAXIMAL_AI_EVENT_EVENTAI) + { + sLog.outErrorDb("CreatureEventAI: Event %u has unfitting event-type (%u) defined for event RECEIVE_AI_EVENT (must be less than %u), skipping.", i, temp.receiveAIEvent.eventType, MAXIMAL_AI_EVENT_EVENTAI); + continue; + } + break; + } default: sLog.outErrorEventAI("Creature %u using not checked at load event (%u) in event %u. Need check code update?", temp.creature_id, temp.event_id, i); break; @@ -831,6 +847,24 @@ void CreatureEventAIMgr::LoadCreatureEventAI_Scripts() case ACTION_T_RANDOM_TEXTEMOTE: sLog.outErrorEventAI("Event %u Action %u currently unused ACTION type. Did you forget to update database?", i, j + 1); break; + + case ACTION_T_THROW_AI_EVENT: + if (action.throwEvent.eventType >= MAXIMAL_AI_EVENT_EVENTAI) + { + sLog.outErrorDb("CreatureEventAI: Event %u Action %u uses invalid event type %u (must be less than %u), skipping", i, j + 1, action.throwEvent.eventType, MAXIMAL_AI_EVENT_EVENTAI); + continue; + } + if (action.throwEvent.radius > SIZE_OF_GRIDS) + sLog.outErrorDb("CreatureEventAI: Event %u Action %u uses unexpectedly huge radius %u (expected to be less than %f)", i, j + 1, action.throwEvent.radius, SIZE_OF_GRIDS); + + if (action.throwEvent.radius == 0) + { + sLog.outErrorDb("CreatureEventAI: Event %u Action %u uses unexpected radius 0 (set to %f of CONFIG_FLOAT_CREATURE_FAMILY_ASSISTANCE_RADIUS)", i, j + 1, sWorld.getConfig(CONFIG_FLOAT_CREATURE_FAMILY_ASSISTANCE_RADIUS)); + action.throwEvent.radius = uint32(sWorld.getConfig(CONFIG_FLOAT_CREATURE_FAMILY_ASSISTANCE_RADIUS)); + } + + break; + default: sLog.outErrorEventAI("Event %u Action %u have currently not checked at load action type (%u). Need check code update?", i, j + 1, temp.action[j].type); break; diff --git a/src/shared/revision_nr.h b/src/shared/revision_nr.h index 2c500a467..69dd54cbc 100644 --- a/src/shared/revision_nr.h +++ b/src/shared/revision_nr.h @@ -1,4 +1,4 @@ #ifndef __REVISION_NR_H__ #define __REVISION_NR_H__ - #define REVISION_NR "12681" + #define REVISION_NR "12682" #endif // __REVISION_NR_H__