From dd39592ddd3ee6c6ceee372387cd72ff90435134 Mon Sep 17 00:00:00 2001 From: Patman64 Date: Sun, 11 Jan 2015 18:48:38 -0500 Subject: [PATCH] Allow binding event handlers to individual Creatures. Because GUIDs are, in fact, not globally unique on mangos, the actual unique identifier is the GUID/instance ID pair of the Creature. On Trinity Creatures in instances are assigned new GUIDs. This means that the instance ID part is redundant but must be used anyway for consistency. --- ElunaBinding.h | 127 +++++++++++++++++++++++++++++++++++++ GlobalMethods.h | 103 ++++++++++++++++++++++++++++-- HookMgr.cpp | 160 ++++++++++++++++++++++++++++------------------- LuaEngine.cpp | 26 +++++--- LuaEngine.h | 38 +++++++---- LuaFunctions.cpp | 2 + 6 files changed, 367 insertions(+), 89 deletions(-) diff --git a/ElunaBinding.h b/ElunaBinding.h index d65a94e..312ce37 100644 --- a/ElunaBinding.h +++ b/ElunaBinding.h @@ -17,6 +17,11 @@ extern "C" #include "lauxlib.h" }; +#ifdef WIN32 +// VC++ complains about UniqueBind because one of its template types is really long. +#pragma warning(disable:4503) +#endif + class ElunaBind : public ElunaUtil::RWLockable { public: @@ -243,4 +248,126 @@ public: EntryToEventsMap Bindings; // Binding store Bindings[entryId][eventId] = {(funcRef, counter)}; }; +template +class UniqueBind : public ElunaBind +{ +public: + typedef UNORDERED_MAP InstanceToEventsMap; + typedef UNORDERED_MAP GUIDToInstancesMap; + + UniqueBind(const char* bindGroupName, Eluna& _E) : ElunaBind(bindGroupName, _E) + { + } + + // unregisters all registered functions and clears all registered events from the bindmap + void Clear() override + { + WriteGuard guard(GetLock()); + + for (GUIDToInstancesMap::iterator iter = Bindings.begin(); iter != Bindings.end(); ++iter) + { + InstanceToEventsMap& eventsMap = iter->second; + for (InstanceToEventsMap::iterator itr = eventsMap.begin(); itr != eventsMap.end(); ++itr) + { + EventToFunctionsMap& funcmap = itr->second; + for (EventToFunctionsMap::iterator it = funcmap.begin(); it != funcmap.end(); ++it) + { + FunctionRefVector& funcrefvec = it->second; + for (FunctionRefVector::iterator i = funcrefvec.begin(); i != funcrefvec.end(); ++i) + delete *i; + funcrefvec.clear(); + } + funcmap.clear(); + } + eventsMap.clear(); + } + Bindings.clear(); + } + + void Clear(uint64 guid, uint32 instanceId, uint32 event_id) + { + WriteGuard guard(GetLock()); + FunctionRefVector& v = Bindings[guid][instanceId][event_id]; + + for (FunctionRefVector::iterator itr = v.begin(); itr != v.end(); ++itr) + delete *itr; + v.clear(); + } + + // Pushes the function references and updates the counters on the binds and erases them if the counter would reach 0 + void PushFuncRefs(lua_State* L, int event_id, uint64 guid, uint32 instanceId) + { + WriteGuard guard(GetLock()); + FunctionRefVector& v = Bindings[guid][instanceId][event_id]; + + for (FunctionRefVector::iterator it = v.begin(); it != v.end();) + { + FunctionRefVector::iterator it_old = it++; + Binding* binding = (*it_old); + + lua_rawgeti(L, LUA_REGISTRYINDEX, binding->functionReference); + + if (binding->isTemporary) + { + binding->remainingShots--; + if (binding->remainingShots == 0) + { + delete binding; + v.erase(it_old); + } + } + } + + if (Bindings[guid][instanceId][event_id].empty()) + Bindings[guid][instanceId].erase(event_id); + + if (Bindings[guid][instanceId].empty()) + Bindings[guid].erase(instanceId); + + if (Bindings[guid].empty()) + Bindings.erase(guid); + }; + + void Insert(uint64 guid, uint32 instanceId, int eventId, int funcRef, uint32 shots) // Inserts a new registered event + { + WriteGuard guard(GetLock()); + Bindings[guid][instanceId][eventId].push_back(new Binding(E, funcRef, shots)); + } + + // Returns true if the entry has registered binds + bool HasEvents(T eventId, uint64 guid, uint32 instanceId) + { + ReadGuard guard(GetLock()); + + if (Bindings.empty()) + return false; + + GUIDToInstancesMap::const_iterator itr = Bindings.find(guid); + if (itr == Bindings.end()) + return false; + + InstanceToEventsMap::const_iterator it = itr->second.find(instanceId); + if (it == itr->second.end()) + return false; + + return it->second.find(eventId) != it->second.end(); + } + + bool HasEvents(uint64 guid, uint32 instanceId) + { + ReadGuard guard(GetLock()); + + if (Bindings.empty()) + return false; + + GUIDToInstancesMap::const_iterator itr = Bindings.find(guid); + if (itr == Bindings.end()) + return false; + + return itr->second.find(instanceId) != itr->second.end(); + } + + GUIDToInstancesMap Bindings; // Binding store Bindings[guid][instanceId][eventId] = {(funcRef, counter)}; +}; + #endif diff --git a/GlobalMethods.h b/GlobalMethods.h index 8812f96..27217be 100644 --- a/GlobalMethods.h +++ b/GlobalMethods.h @@ -494,7 +494,7 @@ namespace LuaGlobalFunctions lua_pushvalue(L, 3); int functionRef = luaL_ref(L, LUA_REGISTRYINDEX); if (functionRef >= 0) - E->Register(regtype, entry, ev, functionRef, shots); + E->Register(regtype, entry, 0, 0, ev, functionRef, shots); else luaL_argerror(L, 3, "unable to make a ref to function"); } @@ -508,11 +508,27 @@ namespace LuaGlobalFunctions lua_pushvalue(L, 2); int functionRef = luaL_ref(L, LUA_REGISTRYINDEX); if (functionRef >= 0) - E->Register(regtype, 0, ev, functionRef, shots); + E->Register(regtype, 0, 0, 0, ev, functionRef, shots); else luaL_argerror(L, 2, "unable to make a ref to function"); } + static void RegisterUniqueHelper(Eluna* E, lua_State* L, int regtype) + { + uint64 guid = Eluna::CHECKVAL(L, 1); + uint32 instanceId = Eluna::CHECKVAL(L, 2); + uint32 ev = Eluna::CHECKVAL(L, 3); + luaL_checktype(L, 4, LUA_TFUNCTION); + uint32 shots = Eluna::CHECKVAL(L, 5, 0); + + lua_pushvalue(L, 4); + int functionRef = luaL_ref(L, LUA_REGISTRYINDEX); + if (functionRef >= 0) + E->Register(regtype, 0, guid, instanceId, ev, functionRef, shots); + else + luaL_argerror(L, 4, "unable to make a ref to function"); + } + /** * Registers a server event handler. * @@ -921,9 +937,9 @@ namespace LuaGlobalFunctions * }; * * - * @param uint32 entry : [Creature] entry Id - * @param uint32 event : [Creature] event Id, refer to CreatureEvents above - * @param function function : function to register + * @param uint32 entry : the ID of one or more [Creature]s + * @param uint32 event : refer to CreatureEvents above + * @param function function : function that will be called when the event occurs * @param uint32 shots = 0 : the number of times the function will be called, 0 means "always call this function" */ int RegisterCreatureEvent(Eluna* E, lua_State* L) @@ -932,6 +948,65 @@ namespace LuaGlobalFunctions return 0; } + /** + * Registers a [Creature] event handler for a *single* [Creature]. + * + *
+     * enum CreatureEvents
+     * {
+     *     CREATURE_EVENT_ON_ENTER_COMBAT                    = 1,  // (event, creature, target)
+     *     CREATURE_EVENT_ON_LEAVE_COMBAT                    = 2,  // (event, creature)
+     *     CREATURE_EVENT_ON_TARGET_DIED                     = 3,  // (event, creature, victim)
+     *     CREATURE_EVENT_ON_DIED                            = 4,  // (event, creature, killer)
+     *     CREATURE_EVENT_ON_SPAWN                           = 5,  // (event, creature)
+     *     CREATURE_EVENT_ON_REACH_WP                        = 6,  // (event, creature, type, id)
+     *     CREATURE_EVENT_ON_AIUPDATE                        = 7,  // (event, creature, diff)
+     *     CREATURE_EVENT_ON_RECEIVE_EMOTE                   = 8,  // (event, creature, player, emoteid)
+     *     CREATURE_EVENT_ON_DAMAGE_TAKEN                    = 9,  // (event, creature, attacker, damage) - Can return new damage
+     *     CREATURE_EVENT_ON_PRE_COMBAT                      = 10, // (event, creature, target)
+     *     CREATURE_EVENT_ON_ATTACKED_AT                     = 11, // (event, creature, attacker)
+     *     CREATURE_EVENT_ON_OWNER_ATTACKED                  = 12, // (event, creature, target)    // Not on mangos
+     *     CREATURE_EVENT_ON_OWNER_ATTACKED_AT               = 13, // (event, creature, attacker)  // Not on mangos
+     *     CREATURE_EVENT_ON_HIT_BY_SPELL                    = 14, // (event, creature, caster, spellid)
+     *     CREATURE_EVENT_ON_SPELL_HIT_TARGET                = 15, // (event, creature, target, spellid)
+     *     // UNUSED                                         = 16, // (event, creature)
+     *     // UNUSED                                         = 17, // (event, creature)
+     *     // UNUSED                                         = 18, // (event, creature)
+     *     CREATURE_EVENT_ON_JUST_SUMMONED_CREATURE          = 19, // (event, creature, summon)
+     *     CREATURE_EVENT_ON_SUMMONED_CREATURE_DESPAWN       = 20, // (event, creature, summon)
+     *     CREATURE_EVENT_ON_SUMMONED_CREATURE_DIED          = 21, // (event, creature, summon, killer)    // Not on mangos
+     *     CREATURE_EVENT_ON_SUMMONED                        = 22, // (event, creature, summoner)
+     *     CREATURE_EVENT_ON_RESET                           = 23, // (event, creature)
+     *     CREATURE_EVENT_ON_REACH_HOME                      = 24, // (event, creature)
+     *     // UNUSED                                         = 25, // (event, creature)
+     *     CREATURE_EVENT_ON_CORPSE_REMOVED                  = 26, // (event, creature, respawndelay) - Can return new respawndelay
+     *     CREATURE_EVENT_ON_MOVE_IN_LOS                     = 27, // (event, creature, unit) - Does not actually check LOS. Just uses the sight range
+     *     // UNUSED                                         = 28, // (event, creature)
+     *     // UNUSED                                         = 29, // (event, creature)
+     *     CREATURE_EVENT_ON_DUMMY_EFFECT                    = 30, // (event, caster, spellid, effindex, creature)
+     *     CREATURE_EVENT_ON_QUEST_ACCEPT                    = 31, // (event, player, creature, quest)
+     *     // UNUSED                                         = 32, // (event, creature)
+     *     // UNUSED                                         = 33, // (event, creature)
+     *     CREATURE_EVENT_ON_QUEST_REWARD                    = 34, // (event, player, creature, quest, opt)
+     *     CREATURE_EVENT_ON_DIALOG_STATUS                   = 35, // (event, player, creature)
+     *     CREATURE_EVENT_ON_ADD                             = 36, // (event, creature)
+     *     CREATURE_EVENT_ON_REMOVE                          = 37, // (event, creature)
+     *     CREATURE_EVENT_COUNT
+     * };
+     * 
+ * + * @param uint64 guid : the GUID of a single [Creature] + * @param uint32 instance_id : the instance ID of a single [Creature] + * @param uint32 event : refer to CreatureEvents above + * @param function function : function that will be called when the event occurs + * @param uint32 shots = 0 : the number of times the function will be called, 0 means "always call this function" + */ + int RegisterUniqueCreatureEvent(Eluna* E, lua_State* L) + { + RegisterUniqueHelper(E, L, HookMgr::REGTYPE_CREATURE); + return 0; + } + /** * Registers a [GameObject] event handler. * @@ -2355,7 +2430,7 @@ namespace LuaGlobalFunctions /** * Unbinds all event handlers for a particular [Creature] event/entry combination. * - * @param uint32 entry : the ID of a [Creature] whose handlers will be cleared + * @param uint32 entry : the ID of one or more [Creature]s whose handlers will be cleared * @param uint32 event_type : the event whose handlers will be cleared, see [Global:RegisterCreatureEvent] */ int ClearCreatureEvents(Eluna* E, lua_State* L) @@ -2366,6 +2441,22 @@ namespace LuaGlobalFunctions return 0; } + /** + * Unbinds all event handlers for a particular [Creature] and event combination. + * + * @param uint64 guid : the GUID of a single [Creature] whose handlers will be cleared + * @param uint32 instance_id : the instance ID of a single [Creature] whose handlers will be cleared + * @param uint32 event_type : the event whose handlers will be cleared, see [Global:RegisterCreatureEvent] + */ + int ClearUniqueCreatureEvents(Eluna* E, lua_State* L) + { + uint64 guid = Eluna::CHECKVAL(L, 1); + uint32 instanceId = Eluna::CHECKVAL(L, 2); + uint32 event_type = Eluna::CHECKVAL(L, 3); + E->CreatureUniqueBindings->Clear(guid, instanceId, event_type); + return 0; + } + /** * Unbinds all event handlers for a particular [Creature] gossip event/entry combination. * diff --git a/HookMgr.cpp b/HookMgr.cpp index ad727cb..e9509b3 100644 --- a/HookMgr.cpp +++ b/HookMgr.cpp @@ -94,7 +94,7 @@ using namespace HookMgr; * Use the simpler overloads for just EventBind or EntryBind instead of this overload in hooks. */ template -int Eluna::SetupStack(EventBind* event_bindings, EntryBind* entry_bindings, T event_id, uint32 entry, int number_of_arguments) +int Eluna::SetupStack(EventBind* event_bindings, EntryBind* entry_bindings, UniqueBind* guid_bindings, T event_id, uint32 entry, uint64 guid, uint32 instanceId, int number_of_arguments) { // Ensure that if `entry_bindings` is not NULL, a valid entry is supplied. ASSERT(!entry_bindings || (entry_bindings && entry > 0)); @@ -118,6 +118,9 @@ int Eluna::SetupStack(EventBind* event_bindings, EntryBind* entry_bindings if (entry_bindings) entry_bindings->PushFuncRefs(L, (int)event_id, entry); + + if (guid_bindings) + guid_bindings->PushFuncRefs(L, (int)event_id, guid, instanceId); // Stack: event_id, [arguments], [functions] int number_of_functions = lua_gettop(L) - arguments_top; @@ -188,12 +191,12 @@ void Eluna::CleanUpStack(int number_of_arguments) * Call all event handlers registered to the event ID/entry combination and ignore any results. */ template -void Eluna::CallAllFunctions(EventBind* event_bindings, EntryBind* entry_bindings, T event_id, uint32 entry) +void Eluna::CallAllFunctions(EventBind* event_bindings, EntryBind* entry_bindings, UniqueBind* guid_bindings, T event_id, uint32 entry, uint64 guid, uint32 instanceId) { int number_of_arguments = this->push_counter; // Stack: [arguments] - int number_of_functions = SetupStack(event_bindings, entry_bindings, event_id, entry, number_of_arguments); + int number_of_functions = SetupStack(event_bindings, entry_bindings, guid_bindings, event_id, entry, guid, instanceId, number_of_arguments); // Stack: event_id, [arguments], [functions] while (number_of_functions > 0) @@ -214,14 +217,14 @@ void Eluna::CallAllFunctions(EventBind* event_bindings, EntryBind* entry_b * otherwise returns the opposite of `default_value`. */ template -bool Eluna::CallAllFunctionsBool(EventBind* event_bindings, EntryBind* entry_bindings, T event_id, uint32 entry, bool default_value) +bool Eluna::CallAllFunctionsBool(EventBind* event_bindings, EntryBind* entry_bindings, UniqueBind* guid_bindings, T event_id, uint32 entry, uint64 guid, uint32 instanceId, bool default_value) { bool result = default_value; // Note: number_of_arguments here does not count in eventID, which is pushed in SetupStack int number_of_arguments = this->push_counter; // Stack: [arguments] - int number_of_functions = SetupStack(event_bindings, entry_bindings, event_id, entry, number_of_arguments); + int number_of_functions = SetupStack(event_bindings, entry_bindings, guid_bindings, event_id, entry, guid, instanceId, number_of_arguments); // Stack: event_id, [arguments], [functions] while (number_of_functions > 0) @@ -1734,14 +1737,15 @@ void Eluna::OnRemove(Creature* creature) bool Eluna::OnDummyEffect(Unit* pCaster, uint32 spellId, SpellEffIndex effIndex, Creature* pTarget) { if (!CreatureEventBindings->HasEvents(CREATURE_EVENT_ON_DUMMY_EFFECT, pTarget->GetEntry())) - return false; + if (!CreatureUniqueBindings->HasEvents(CREATURE_EVENT_ON_DUMMY_EFFECT, pTarget->GET_GUID(), pTarget->GetInstanceId())) + return false; LOCK_ELUNA; Push(pCaster); Push(spellId); Push(effIndex); Push(pTarget); - return CallAllFunctionsBool(CreatureEventBindings, CREATURE_EVENT_ON_DUMMY_EFFECT, pTarget->GetEntry()); + return CallAllFunctionsBool(CreatureEventBindings, CreatureUniqueBindings, CREATURE_EVENT_ON_DUMMY_EFFECT, pTarget->GetEntry(), pTarget->GET_GUID(), pTarget->GetInstanceId()); } bool Eluna::OnGossipHello(Player* pPlayer, Creature* pCreature) @@ -1788,80 +1792,87 @@ bool Eluna::OnGossipSelectCode(Player* pPlayer, Creature* pCreature, uint32 send bool Eluna::OnQuestAccept(Player* pPlayer, Creature* pCreature, Quest const* pQuest) { if (!CreatureEventBindings->HasEvents(CREATURE_EVENT_ON_QUEST_ACCEPT, pCreature->GetEntry())) - return false; + if (!CreatureUniqueBindings->HasEvents(CREATURE_EVENT_ON_QUEST_ACCEPT, pCreature->GET_GUID(), pCreature->GetInstanceId())) + return false; LOCK_ELUNA; Push(pPlayer); Push(pCreature); Push(pQuest); - return CallAllFunctionsBool(CreatureEventBindings, CREATURE_EVENT_ON_QUEST_ACCEPT, pCreature->GetEntry()); + return CallAllFunctionsBool(CreatureEventBindings, CreatureUniqueBindings, CREATURE_EVENT_ON_QUEST_ACCEPT, pCreature->GetEntry(), pCreature->GET_GUID(), pCreature->GetInstanceId()); } bool Eluna::OnQuestReward(Player* pPlayer, Creature* pCreature, Quest const* pQuest, uint32 opt) { if (!CreatureEventBindings->HasEvents(CREATURE_EVENT_ON_QUEST_REWARD, pCreature->GetEntry())) - return false; + if (!CreatureUniqueBindings->HasEvents(CREATURE_EVENT_ON_QUEST_REWARD, pCreature->GET_GUID(), pCreature->GetInstanceId())) + return false; LOCK_ELUNA; Push(pPlayer); Push(pCreature); Push(pQuest); Push(opt); - return CallAllFunctionsBool(CreatureEventBindings, CREATURE_EVENT_ON_QUEST_REWARD, pCreature->GetEntry()); + return CallAllFunctionsBool(CreatureEventBindings, CreatureUniqueBindings, CREATURE_EVENT_ON_QUEST_REWARD, pCreature->GetEntry(), pCreature->GET_GUID(), pCreature->GetInstanceId()); } uint32 Eluna::GetDialogStatus(Player* pPlayer, Creature* pCreature) { if (!CreatureEventBindings->HasEvents(CREATURE_EVENT_ON_DIALOG_STATUS, pCreature->GetEntry())) - return DIALOG_STATUS_SCRIPTED_NO_STATUS; + if (!CreatureUniqueBindings->HasEvents(CREATURE_EVENT_ON_DIALOG_STATUS, pCreature->GET_GUID(), pCreature->GetInstanceId())) + return DIALOG_STATUS_SCRIPTED_NO_STATUS; LOCK_ELUNA; Push(pPlayer); Push(pCreature); - CallAllFunctions(CreatureEventBindings, CREATURE_EVENT_ON_DIALOG_STATUS, pCreature->GetEntry()); + CallAllFunctions(CreatureEventBindings, CreatureUniqueBindings, CREATURE_EVENT_ON_DIALOG_STATUS, pCreature->GetEntry(), pCreature->GET_GUID(), pCreature->GetInstanceId()); return DIALOG_STATUS_SCRIPTED_NO_STATUS; } void Eluna::OnAddToWorld(Creature* creature) { if (!CreatureEventBindings->HasEvents(CREATURE_EVENT_ON_ADD, creature->GetEntry())) - return; + if (!CreatureUniqueBindings->HasEvents(CREATURE_EVENT_ON_ADD, creature->GET_GUID(), creature->GetInstanceId())) + return; LOCK_ELUNA; Push(creature); - CallAllFunctions(CreatureEventBindings, CREATURE_EVENT_ON_ADD, creature->GetEntry()); + CallAllFunctions(CreatureEventBindings, CreatureUniqueBindings, CREATURE_EVENT_ON_ADD, creature->GetEntry(), creature->GET_GUID(), creature->GetInstanceId()); } void Eluna::OnRemoveFromWorld(Creature* creature) { if (!CreatureEventBindings->HasEvents(CREATURE_EVENT_ON_REMOVE, creature->GetEntry())) - return; + if (!CreatureUniqueBindings->HasEvents(CREATURE_EVENT_ON_REMOVE, creature->GET_GUID(), creature->GetInstanceId())) + return; LOCK_ELUNA; Push(creature); - CallAllFunctions(CreatureEventBindings, CREATURE_EVENT_ON_REMOVE, creature->GetEntry()); + CallAllFunctions(CreatureEventBindings, CreatureUniqueBindings, CREATURE_EVENT_ON_REMOVE, creature->GetEntry(), creature->GET_GUID(), creature->GetInstanceId()); } bool Eluna::OnSummoned(Creature* pCreature, Unit* pSummoner) { if (!CreatureEventBindings->HasEvents(CREATURE_EVENT_ON_SUMMONED, pCreature->GetEntry())) - return false; + if (!CreatureUniqueBindings->HasEvents(CREATURE_EVENT_ON_SUMMONED, pCreature->GET_GUID(), pCreature->GetInstanceId())) + return false; LOCK_ELUNA; Push(pCreature); Push(pSummoner); - return CallAllFunctionsBool(CreatureEventBindings, CREATURE_EVENT_ON_SUMMONED, pCreature->GetEntry()); + return CallAllFunctionsBool(CreatureEventBindings, CreatureUniqueBindings, CREATURE_EVENT_ON_SUMMONED, pCreature->GetEntry(), pCreature->GET_GUID(), pCreature->GetInstanceId()); } bool Eluna::UpdateAI(Creature* me, const uint32 diff) { if (!CreatureEventBindings->HasEvents(CREATURE_EVENT_ON_AIUPDATE, me->GetEntry())) - return false; + if (!CreatureUniqueBindings->HasEvents(CREATURE_EVENT_ON_AIUPDATE, me->GET_GUID(), me->GetInstanceId())) + return false; LOCK_ELUNA; Push(me); Push(diff); - return CallAllFunctionsBool(CreatureEventBindings, CREATURE_EVENT_ON_AIUPDATE, me->GetEntry()); + return CallAllFunctionsBool(CreatureEventBindings, CreatureUniqueBindings, CREATURE_EVENT_ON_AIUPDATE, me->GetEntry(), me->GET_GUID(), me->GetInstanceId()); } //Called for reaction at enter to combat if not in combat yet (enemy can be NULL) @@ -1869,19 +1880,21 @@ bool Eluna::UpdateAI(Creature* me, const uint32 diff) bool Eluna::EnterCombat(Creature* me, Unit* target) { if (!CreatureEventBindings->HasEvents(CREATURE_EVENT_ON_ENTER_COMBAT, me->GetEntry())) - return false; + if (!CreatureUniqueBindings->HasEvents(CREATURE_EVENT_ON_ENTER_COMBAT, me->GET_GUID(), me->GetInstanceId())) + return false; LOCK_ELUNA; Push(me); Push(target); - return CallAllFunctionsBool(CreatureEventBindings, CREATURE_EVENT_ON_ENTER_COMBAT, me->GetEntry()); + return CallAllFunctionsBool(CreatureEventBindings, CreatureUniqueBindings, CREATURE_EVENT_ON_ENTER_COMBAT, me->GetEntry(), me->GET_GUID(), me->GetInstanceId()); } // Called at any Damage from any attacker (before damage apply) bool Eluna::DamageTaken(Creature* me, Unit* attacker, uint32& damage) { if (!CreatureEventBindings->HasEvents(CREATURE_EVENT_ON_DAMAGE_TAKEN, me->GetEntry())) - return false; + if (!CreatureUniqueBindings->HasEvents(CREATURE_EVENT_ON_DAMAGE_TAKEN, me->GET_GUID(), me->GetInstanceId())) + return false; LOCK_ELUNA; bool result = false; @@ -1889,7 +1902,7 @@ bool Eluna::DamageTaken(Creature* me, Unit* attacker, uint32& damage) Push(attacker); Push(damage); int damageIndex = lua_gettop(L); - int n = SetupStack(CreatureEventBindings, CREATURE_EVENT_ON_DAMAGE_TAKEN, me->GetEntry(), 3); + int n = SetupStack(CreatureEventBindings, CreatureUniqueBindings, CREATURE_EVENT_ON_DAMAGE_TAKEN, me->GetEntry(), me->GET_GUID(), me->GetInstanceId(), 3); while (n > 0) { @@ -1918,73 +1931,79 @@ bool Eluna::JustDied(Creature* me, Unit* killer) On_Reset(me); if (!CreatureEventBindings->HasEvents(CREATURE_EVENT_ON_DIED, me->GetEntry())) - return false; + if (!CreatureUniqueBindings->HasEvents(CREATURE_EVENT_ON_DIED, me->GET_GUID(), me->GetInstanceId())) + return false; LOCK_ELUNA; Push(me); Push(killer); - return CallAllFunctionsBool(CreatureEventBindings, CREATURE_EVENT_ON_DIED, me->GetEntry()); + return CallAllFunctionsBool(CreatureEventBindings, CreatureUniqueBindings, CREATURE_EVENT_ON_DIED, me->GetEntry(), me->GET_GUID(), me->GetInstanceId()); } //Called at creature killing another unit bool Eluna::KilledUnit(Creature* me, Unit* victim) { if (!CreatureEventBindings->HasEvents(CREATURE_EVENT_ON_TARGET_DIED, me->GetEntry())) - return false; + if (!CreatureUniqueBindings->HasEvents(CREATURE_EVENT_ON_TARGET_DIED, me->GET_GUID(), me->GetInstanceId())) + return false; LOCK_ELUNA; Push(me); Push(victim); - return CallAllFunctionsBool(CreatureEventBindings, CREATURE_EVENT_ON_TARGET_DIED, me->GetEntry()); + return CallAllFunctionsBool(CreatureEventBindings, CreatureUniqueBindings, CREATURE_EVENT_ON_TARGET_DIED, me->GetEntry(), me->GET_GUID(), me->GetInstanceId()); } // Called when the creature summon successfully other creature bool Eluna::JustSummoned(Creature* me, Creature* summon) { if (!CreatureEventBindings->HasEvents(CREATURE_EVENT_ON_JUST_SUMMONED_CREATURE, me->GetEntry())) - return false; + if (!CreatureUniqueBindings->HasEvents(CREATURE_EVENT_ON_JUST_SUMMONED_CREATURE, me->GET_GUID(), me->GetInstanceId())) + return false; LOCK_ELUNA; Push(me); Push(summon); - return CallAllFunctionsBool(CreatureEventBindings, CREATURE_EVENT_ON_JUST_SUMMONED_CREATURE, me->GetEntry()); + return CallAllFunctionsBool(CreatureEventBindings, CreatureUniqueBindings, CREATURE_EVENT_ON_JUST_SUMMONED_CREATURE, me->GetEntry(), me->GET_GUID(), me->GetInstanceId()); } // Called when a summoned creature is despawned bool Eluna::SummonedCreatureDespawn(Creature* me, Creature* summon) { if (!CreatureEventBindings->HasEvents(CREATURE_EVENT_ON_SUMMONED_CREATURE_DESPAWN, me->GetEntry())) - return false; + if (!CreatureUniqueBindings->HasEvents(CREATURE_EVENT_ON_SUMMONED_CREATURE_DESPAWN, me->GET_GUID(), me->GetInstanceId())) + return false; LOCK_ELUNA; Push(me); Push(summon); - return CallAllFunctionsBool(CreatureEventBindings, CREATURE_EVENT_ON_SUMMONED_CREATURE_DESPAWN, me->GetEntry()); + return CallAllFunctionsBool(CreatureEventBindings, CreatureUniqueBindings, CREATURE_EVENT_ON_SUMMONED_CREATURE_DESPAWN, me->GetEntry(), me->GET_GUID(), me->GetInstanceId()); } //Called at waypoint reached or PointMovement end bool Eluna::MovementInform(Creature* me, uint32 type, uint32 id) { if (!CreatureEventBindings->HasEvents(CREATURE_EVENT_ON_REACH_WP, me->GetEntry())) - return false; + if (!CreatureUniqueBindings->HasEvents(CREATURE_EVENT_ON_REACH_WP, me->GET_GUID(), me->GetInstanceId())) + return false; LOCK_ELUNA; Push(me); Push(type); Push(id); - return CallAllFunctionsBool(CreatureEventBindings, CREATURE_EVENT_ON_REACH_WP, me->GetEntry()); + return CallAllFunctionsBool(CreatureEventBindings, CreatureUniqueBindings, CREATURE_EVENT_ON_REACH_WP, me->GetEntry(), me->GET_GUID(), me->GetInstanceId()); } // Called before EnterCombat even before the creature is in combat. bool Eluna::AttackStart(Creature* me, Unit* target) { if (!CreatureEventBindings->HasEvents(CREATURE_EVENT_ON_PRE_COMBAT, me->GetEntry())) - return false; + if (!CreatureUniqueBindings->HasEvents(CREATURE_EVENT_ON_PRE_COMBAT, me->GET_GUID(), me->GetInstanceId())) + return false; LOCK_ELUNA; Push(me); Push(target); - return CallAllFunctionsBool(CreatureEventBindings, CREATURE_EVENT_ON_PRE_COMBAT, me->GetEntry()); + return CallAllFunctionsBool(CreatureEventBindings, CreatureUniqueBindings, CREATURE_EVENT_ON_PRE_COMBAT, me->GetEntry(), me->GET_GUID(), me->GetInstanceId()); } // Called for reaction at stopping attack at no attackers or targets @@ -1993,23 +2012,25 @@ bool Eluna::EnterEvadeMode(Creature* me) On_Reset(me); if (!CreatureEventBindings->HasEvents(CREATURE_EVENT_ON_LEAVE_COMBAT, me->GetEntry())) - return false; + if (!CreatureUniqueBindings->HasEvents(CREATURE_EVENT_ON_LEAVE_COMBAT, me->GET_GUID(), me->GetInstanceId())) + return false; LOCK_ELUNA; Push(me); - return CallAllFunctionsBool(CreatureEventBindings, CREATURE_EVENT_ON_LEAVE_COMBAT, me->GetEntry()); + return CallAllFunctionsBool(CreatureEventBindings, CreatureUniqueBindings, CREATURE_EVENT_ON_LEAVE_COMBAT, me->GetEntry(), me->GET_GUID(), me->GetInstanceId()); } // Called when the creature is target of hostile action: swing, hostile spell landed, fear/etc) bool Eluna::AttackedBy(Creature* me, Unit* attacker) { if (!CreatureEventBindings->HasEvents(CREATURE_EVENT_ON_ATTACKED_AT, me->GetEntry())) - return false; + if (!CreatureUniqueBindings->HasEvents(CREATURE_EVENT_ON_ATTACKED_AT, me->GET_GUID(), me->GetInstanceId())) + return false; LOCK_ELUNA; Push(me); Push(attacker); - return CallAllFunctionsBool(CreatureEventBindings, CREATURE_EVENT_ON_ATTACKED_AT, me->GetEntry()); + return CallAllFunctionsBool(CreatureEventBindings, CreatureUniqueBindings, CREATURE_EVENT_ON_ATTACKED_AT, me->GetEntry(), me->GET_GUID(), me->GetInstanceId()); } // Called when creature is spawned or respawned (for reseting variables) @@ -2018,49 +2039,53 @@ bool Eluna::JustRespawned(Creature* me) On_Reset(me); if (!CreatureEventBindings->HasEvents(CREATURE_EVENT_ON_SPAWN, me->GetEntry())) - return false; + if (!CreatureUniqueBindings->HasEvents(CREATURE_EVENT_ON_SPAWN, me->GET_GUID(), me->GetInstanceId())) + return false; LOCK_ELUNA; Push(me); - return CallAllFunctionsBool(CreatureEventBindings, CREATURE_EVENT_ON_SPAWN, me->GetEntry()); + return CallAllFunctionsBool(CreatureEventBindings, CreatureUniqueBindings, CREATURE_EVENT_ON_SPAWN, me->GetEntry(), me->GET_GUID(), me->GetInstanceId()); } // Called at reaching home after evade bool Eluna::JustReachedHome(Creature* me) { if (!CreatureEventBindings->HasEvents(CREATURE_EVENT_ON_REACH_HOME, me->GetEntry())) - return false; + if (!CreatureUniqueBindings->HasEvents(CREATURE_EVENT_ON_REACH_HOME, me->GET_GUID(), me->GetInstanceId())) + return false; LOCK_ELUNA; Push(me); - return CallAllFunctionsBool(CreatureEventBindings, CREATURE_EVENT_ON_REACH_HOME, me->GetEntry()); + return CallAllFunctionsBool(CreatureEventBindings, CreatureUniqueBindings, CREATURE_EVENT_ON_REACH_HOME, me->GetEntry(), me->GET_GUID(), me->GetInstanceId()); } // Called at text emote receive from player bool Eluna::ReceiveEmote(Creature* me, Player* player, uint32 emoteId) { if (!CreatureEventBindings->HasEvents(CREATURE_EVENT_ON_RECEIVE_EMOTE, me->GetEntry())) - return false; + if (!CreatureUniqueBindings->HasEvents(CREATURE_EVENT_ON_RECEIVE_EMOTE, me->GET_GUID(), me->GetInstanceId())) + return false; LOCK_ELUNA; Push(me); Push(player); Push(emoteId); - return CallAllFunctionsBool(CreatureEventBindings, CREATURE_EVENT_ON_RECEIVE_EMOTE, me->GetEntry()); + return CallAllFunctionsBool(CreatureEventBindings, CreatureUniqueBindings, CREATURE_EVENT_ON_RECEIVE_EMOTE, me->GetEntry(), me->GET_GUID(), me->GetInstanceId()); } // called when the corpse of this creature gets removed bool Eluna::CorpseRemoved(Creature* me, uint32& respawnDelay) { if (!CreatureEventBindings->HasEvents(CREATURE_EVENT_ON_CORPSE_REMOVED, me->GetEntry())) - return false; + if (!CreatureUniqueBindings->HasEvents(CREATURE_EVENT_ON_CORPSE_REMOVED, me->GET_GUID(), me->GetInstanceId())) + return false; LOCK_ELUNA; bool result = false; Push(me); Push(respawnDelay); int respawnDelayIndex = lua_gettop(L); - int n = SetupStack(CreatureEventBindings, CREATURE_EVENT_ON_CORPSE_REMOVED, me->GetEntry(), 2); + int n = SetupStack(CreatureEventBindings, CreatureUniqueBindings, CREATURE_EVENT_ON_CORPSE_REMOVED, me->GetEntry(), me->GET_GUID(), me->GetInstanceId(), 2); while (n > 0) { @@ -2086,49 +2111,53 @@ bool Eluna::CorpseRemoved(Creature* me, uint32& respawnDelay) bool Eluna::MoveInLineOfSight(Creature* me, Unit* who) { if (!CreatureEventBindings->HasEvents(CREATURE_EVENT_ON_MOVE_IN_LOS, me->GetEntry())) - return false; + if (!CreatureUniqueBindings->HasEvents(CREATURE_EVENT_ON_MOVE_IN_LOS, me->GET_GUID(), me->GetInstanceId())) + return false; LOCK_ELUNA; Push(me); Push(who); - return CallAllFunctionsBool(CreatureEventBindings, CREATURE_EVENT_ON_MOVE_IN_LOS, me->GetEntry()); + return CallAllFunctionsBool(CreatureEventBindings, CreatureUniqueBindings, CREATURE_EVENT_ON_MOVE_IN_LOS, me->GetEntry(), me->GET_GUID(), me->GetInstanceId()); } // Called on creature initial spawn, respawn, death, evade (leave combat) void Eluna::On_Reset(Creature* me) // Not an override, custom { if (!CreatureEventBindings->HasEvents(CREATURE_EVENT_ON_RESET, me->GetEntry())) - return; + if (!CreatureUniqueBindings->HasEvents(CREATURE_EVENT_ON_RESET, me->GET_GUID(), me->GetInstanceId())) + return; LOCK_ELUNA; Push(me); - CallAllFunctions(CreatureEventBindings, CREATURE_EVENT_ON_RESET, me->GetEntry()); + CallAllFunctions(CreatureEventBindings, CreatureUniqueBindings, CREATURE_EVENT_ON_RESET, me->GetEntry(), me->GET_GUID(), me->GetInstanceId()); } // Called when hit by a spell bool Eluna::SpellHit(Creature* me, Unit* caster, SpellInfo const* spell) { if (!CreatureEventBindings->HasEvents(CREATURE_EVENT_ON_HIT_BY_SPELL, me->GetEntry())) - return false; + if (!CreatureUniqueBindings->HasEvents(CREATURE_EVENT_ON_HIT_BY_SPELL, me->GET_GUID(), me->GetInstanceId())) + return false; LOCK_ELUNA; Push(me); Push(caster); Push(spell->Id); // Pass spell object? - return CallAllFunctionsBool(CreatureEventBindings, CREATURE_EVENT_ON_HIT_BY_SPELL, me->GetEntry()); + return CallAllFunctionsBool(CreatureEventBindings, CreatureUniqueBindings, CREATURE_EVENT_ON_HIT_BY_SPELL, me->GetEntry(), me->GET_GUID(), me->GetInstanceId()); } // Called when spell hits a target bool Eluna::SpellHitTarget(Creature* me, Unit* target, SpellInfo const* spell) { if (!CreatureEventBindings->HasEvents(CREATURE_EVENT_ON_SPELL_HIT_TARGET, me->GetEntry())) - return false; + if (!CreatureUniqueBindings->HasEvents(CREATURE_EVENT_ON_SPELL_HIT_TARGET, me->GET_GUID(), me->GetInstanceId())) + return false; LOCK_ELUNA; Push(me); Push(target); Push(spell->Id); // Pass spell object? - return CallAllFunctionsBool(CreatureEventBindings, CREATURE_EVENT_ON_SPELL_HIT_TARGET, me->GetEntry()); + return CallAllFunctionsBool(CreatureEventBindings, CreatureUniqueBindings, CREATURE_EVENT_ON_SPELL_HIT_TARGET, me->GetEntry(), me->GET_GUID(), me->GetInstanceId()); } #ifdef TRINITY @@ -2136,37 +2165,40 @@ bool Eluna::SpellHitTarget(Creature* me, Unit* target, SpellInfo const* spell) bool Eluna::SummonedCreatureDies(Creature* me, Creature* summon, Unit* killer) { if (!CreatureEventBindings->HasEvents(CREATURE_EVENT_ON_SUMMONED_CREATURE_DIED, me->GetEntry())) - return false; + if (!CreatureUniqueBindings->HasEvents(CREATURE_EVENT_ON_SUMMONED_CREATURE_DIED, me->GET_GUID(), me->GetInstanceId())) + return false; LOCK_ELUNA; Push(me); Push(summon); Push(killer); - return CallAllFunctionsBool(CreatureEventBindings, CREATURE_EVENT_ON_SUMMONED_CREATURE_DIED, me->GetEntry()); + return CallAllFunctionsBool(CreatureEventBindings, CreatureUniqueBindings, CREATURE_EVENT_ON_SUMMONED_CREATURE_DIED, me->GetEntry(), me->GET_GUID(), me->GetInstanceId()); } // Called when owner takes damage bool Eluna::OwnerAttackedBy(Creature* me, Unit* attacker) { if (!CreatureEventBindings->HasEvents(CREATURE_EVENT_ON_OWNER_ATTACKED_AT, me->GetEntry())) - return false; + if (!CreatureUniqueBindings->HasEvents(CREATURE_EVENT_ON_OWNER_ATTACKED_AT, me->GET_GUID(), me->GetInstanceId())) + return false; LOCK_ELUNA; Push(me); Push(attacker); - return CallAllFunctionsBool(CreatureEventBindings, CREATURE_EVENT_ON_OWNER_ATTACKED_AT, me->GetEntry()); + return CallAllFunctionsBool(CreatureEventBindings, CreatureUniqueBindings, CREATURE_EVENT_ON_OWNER_ATTACKED_AT, me->GetEntry(), me->GET_GUID(), me->GetInstanceId()); } // Called when owner attacks something bool Eluna::OwnerAttacked(Creature* me, Unit* target) { if (!CreatureEventBindings->HasEvents(CREATURE_EVENT_ON_OWNER_ATTACKED, me->GetEntry())) - return false; + if (!CreatureUniqueBindings->HasEvents(CREATURE_EVENT_ON_OWNER_ATTACKED, me->GET_GUID(), me->GetInstanceId())) + return false; LOCK_ELUNA; Push(me); Push(target); - return CallAllFunctionsBool(CreatureEventBindings, CREATURE_EVENT_ON_OWNER_ATTACKED, me->GetEntry()); + return CallAllFunctionsBool(CreatureEventBindings, CreatureUniqueBindings, CREATURE_EVENT_ON_OWNER_ATTACKED, me->GetEntry(), me->GET_GUID(), me->GetInstanceId()); } #endif @@ -2547,7 +2579,7 @@ void Eluna::OnRemoveFromWorld(GameObject* gameobject) CreatureAI* Eluna::GetAI(Creature* creature) { - if (!CreatureEventBindings->HasEvents(creature->GetEntry())) + if (!CreatureEventBindings->HasEvents(creature->GetEntry()) && !CreatureUniqueBindings->HasEvents(creature->GET_GUID(), creature->GetInstanceId())) return NULL; return new ElunaCreatureAI(creature); } diff --git a/LuaEngine.cpp b/LuaEngine.cpp index 29a7f9b..dbf1c0c 100644 --- a/LuaEngine.cpp +++ b/LuaEngine.cpp @@ -137,7 +137,9 @@ GameObjectEventBindings(new EntryBind("GameObjectEven GameObjectGossipBindings(new EntryBind("GossipEvents (gameobject)", *this)), ItemEventBindings(new EntryBind("ItemEvents", *this)), ItemGossipBindings(new EntryBind("GossipEvents (item)", *this)), -playerGossipBindings(new EntryBind("GossipEvents (player)", *this)) +playerGossipBindings(new EntryBind("GossipEvents (player)", *this)), + +CreatureUniqueBindings(new UniqueBind("CreatureEvents", *this)) { // open base lua libraries luaL_openlibs(L); @@ -761,7 +763,7 @@ ElunaObject* Eluna::CHECKTYPE(lua_State* luastate, int narg, const char* tname, } // Saves the function reference ID given to the register type's store for given entry under the given event -void Eluna::Register(uint8 regtype, uint32 id, uint32 evt, int functionRef, uint32 shots) +void Eluna::Register(uint8 regtype, uint32 id, uint64 guid, uint32 instanceId, uint32 evt, int functionRef, uint32 shots) { switch (regtype) { @@ -831,14 +833,22 @@ void Eluna::Register(uint8 regtype, uint32 id, uint32 evt, int functionRef, uint case HookMgr::REGTYPE_CREATURE: if (evt < HookMgr::CREATURE_EVENT_COUNT) { - if (!eObjectMgr->GetCreatureTemplate(id)) + if (id != 0) { - luaL_unref(L, LUA_REGISTRYINDEX, functionRef); - luaL_error(L, "Couldn't find a creature with (ID: %d)!", id); - return; - } + if (!eObjectMgr->GetCreatureTemplate(id)) + { + luaL_unref(L, LUA_REGISTRYINDEX, functionRef); + luaL_error(L, "Couldn't find a creature with (ID: %d)!", id); + return; + } - CreatureEventBindings->Insert(id, evt, functionRef, shots); + CreatureEventBindings->Insert(id, evt, functionRef, shots); + } + else + { + ASSERT(guid != 0); + CreatureUniqueBindings->Insert(guid, instanceId, evt, functionRef, shots); + } return; } break; diff --git a/LuaEngine.h b/LuaEngine.h index 2b3ef7f..39b6139 100644 --- a/LuaEngine.h +++ b/LuaEngine.h @@ -91,6 +91,8 @@ template class EventBind; template class EntryBind; +template +class UniqueBind; struct LuaScript { @@ -110,41 +112,53 @@ private: Eluna& operator=(const Eluna&); // Some helpers for hooks to call event handlers. - template int SetupStack(EventBind* event_bindings, EntryBind* entry_bindings, T event_id, uint32 entry, int number_of_arguments); + template int SetupStack(EventBind* event_bindings, EntryBind* entry_bindings, UniqueBind* guid_bindings, T event_id, uint32 entry, uint64 guid, uint32 instanceId, int number_of_arguments); + int CallOneFunction(int number_of_functions, int number_of_arguments, int number_of_results); void CleanUpStack(int number_of_arguments); template void ReplaceArgument(T value, uint8 index); - int CallOneFunction(int number_of_functions, int number_of_arguments, int number_of_results); - template void CallAllFunctions(EventBind* event_bindings, EntryBind* entry_bindings, T event_id, uint32 entry); - template bool CallAllFunctionsBool(EventBind* event_bindings, EntryBind* entry_bindings, T event_id, uint32 entry, bool default_value); + template void CallAllFunctions(EventBind* event_bindings, EntryBind* entry_bindings, UniqueBind* guid_bindings, T event_id, uint32 entry, uint64 guid, uint32 instanceId); + template bool CallAllFunctionsBool(EventBind* event_bindings, EntryBind* entry_bindings, UniqueBind* guid_bindings, T event_id, uint32 entry, uint64 guid, uint32 instanceId, bool default_value); // Convenient overloads for Setup. Use these in hooks instead of original. template int SetupStack(EventBind* event_bindings, T event_id, int number_of_arguments) { - return SetupStack(event_bindings, (EntryBind*)NULL, event_id, 0, number_of_arguments); + return SetupStack(event_bindings, (EntryBind*)NULL, (UniqueBind*)NULL, event_id, 0, 0, 0, number_of_arguments); } template int SetupStack(EntryBind* entry_bindings, T event_id, uint32 entry, int number_of_arguments) { - return SetupStack((EventBind*)NULL, entry_bindings, event_id, entry, number_of_arguments); + return SetupStack((EventBind*)NULL, entry_bindings, (UniqueBind*)NULL, event_id, entry, 0, 0, number_of_arguments); + } + template int SetupStack(EntryBind* entry_bindings, UniqueBind* guid_bindings, T event_id, uint32 entry, uint64 guid, uint32 instanceId, int number_of_arguments) + { + return SetupStack((EventBind*)NULL, entry_bindings, guid_bindings, event_id, entry, guid, instanceId, number_of_arguments); } // Convenient overloads for CallAllFunctions. Use these in hooks instead of original. template void CallAllFunctions(EventBind* event_bindings, T event_id) { - CallAllFunctions(event_bindings, (EntryBind*)NULL, event_id, 0); + CallAllFunctions(event_bindings, (EntryBind*)NULL, (UniqueBind*)NULL, event_id, 0, 0, 0); } template void CallAllFunctions(EntryBind* entry_bindings, T event_id, uint32 entry) { - CallAllFunctions((EventBind*)NULL, entry_bindings, event_id, entry); + CallAllFunctions((EventBind*)NULL, entry_bindings, (UniqueBind*)NULL, event_id, entry, 0, 0); + } + template void CallAllFunctions(EntryBind* entry_bindings, UniqueBind* guid_bindings, T event_id, uint32 entry, uint64 guid, uint32 instanceId) + { + CallAllFunctions((EventBind*)NULL, entry_bindings, guid_bindings, event_id, entry, guid, instanceId); } // Convenient overloads for CallAllFunctionsBool. Use these in hooks instead of original. template bool CallAllFunctionsBool(EventBind* event_bindings, T event_id, bool default_value = false) { - return CallAllFunctionsBool(event_bindings, (EntryBind*)NULL, event_id, 0, default_value); + return CallAllFunctionsBool(event_bindings, (EntryBind*)NULL, (UniqueBind*)NULL, event_id, 0, 0, 0, default_value); } template bool CallAllFunctionsBool(EntryBind* entry_bindings, T event_id, uint32 entry, bool default_value = false) { - return CallAllFunctionsBool((EventBind*)NULL, entry_bindings, event_id, entry, default_value); + return CallAllFunctionsBool((EventBind*)NULL, entry_bindings, (UniqueBind*)NULL, event_id, entry, 0, 0, default_value); + } + template bool CallAllFunctionsBool(EntryBind* entry_bindings, UniqueBind* guid_bindings, T event_id, uint32 entry, uint64 guid, uint32 instanceId, bool default_value = false) + { + return CallAllFunctionsBool((EventBind*)NULL, entry_bindings, guid_bindings, event_id, entry, guid, instanceId, default_value); } public: @@ -185,6 +199,8 @@ public: EntryBind* ItemGossipBindings; EntryBind* playerGossipBindings; + UniqueBind* CreatureUniqueBindings; + Eluna(); ~Eluna(); @@ -202,7 +218,7 @@ public: static void report(lua_State* luastate); void ExecuteCall(int params, int res); - void Register(uint8 reg, uint32 id, uint32 evt, int func, uint32 shots); + void Register(uint8 reg, uint32 id, uint64 guid, uint32 instanceId, uint32 evt, int func, uint32 shots); void RunScripts(); void InvalidateObjects(); diff --git a/LuaFunctions.cpp b/LuaFunctions.cpp index 9278262..2c95a16 100644 --- a/LuaFunctions.cpp +++ b/LuaFunctions.cpp @@ -47,6 +47,7 @@ ElunaGlobal::ElunaRegister GlobalMethods[] = { "RegisterGuildEvent", &LuaGlobalFunctions::RegisterGuildEvent }, // RegisterGuildEvent(event, function) { "RegisterGroupEvent", &LuaGlobalFunctions::RegisterGroupEvent }, // RegisterGroupEvent(event, function) { "RegisterCreatureEvent", &LuaGlobalFunctions::RegisterCreatureEvent }, // RegisterCreatureEvent(entry, event, function) + { "RegisterUniqueCreatureEvent", &LuaGlobalFunctions::RegisterUniqueCreatureEvent }, // RegisterUniqueCreatureEvent(guid, instance, event, function) { "RegisterCreatureGossipEvent", &LuaGlobalFunctions::RegisterCreatureGossipEvent }, // RegisterCreatureGossipEvent(entry, event, function) { "RegisterGameObjectEvent", &LuaGlobalFunctions::RegisterGameObjectEvent }, // RegisterGameObjectEvent(entry, event, function) { "RegisterGameObjectGossipEvent", &LuaGlobalFunctions::RegisterGameObjectGossipEvent }, // RegisterGameObjectGossipEvent(entry, event, function) @@ -57,6 +58,7 @@ ElunaGlobal::ElunaRegister GlobalMethods[] = { "ClearBattleGroundEvents", &LuaGlobalFunctions::ClearBattleGroundEvents }, { "ClearCreatureEvents", &LuaGlobalFunctions::ClearCreatureEvents }, + { "ClearUniqueCreatureEvents", &LuaGlobalFunctions::ClearUniqueCreatureEvents }, { "ClearCreatureGossipEvents", &LuaGlobalFunctions::ClearCreatureGossipEvents }, { "ClearGameObjectEvents", &LuaGlobalFunctions::ClearGameObjectEvents }, { "ClearGameObjectGossipEvents", &LuaGlobalFunctions::ClearGameObjectGossipEvents },