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 },