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.
This commit is contained in:
Patman64
2015-01-11 18:48:38 -05:00
parent 882eb40acb
commit dd39592ddd
6 changed files with 367 additions and 89 deletions

View File

@@ -17,6 +17,11 @@ extern "C"
#include "lauxlib.h" #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 class ElunaBind : public ElunaUtil::RWLockable
{ {
public: public:
@@ -243,4 +248,126 @@ public:
EntryToEventsMap Bindings; // Binding store Bindings[entryId][eventId] = {(funcRef, counter)}; EntryToEventsMap Bindings; // Binding store Bindings[entryId][eventId] = {(funcRef, counter)};
}; };
template<typename T>
class UniqueBind : public ElunaBind
{
public:
typedef UNORDERED_MAP<uint32, EventToFunctionsMap> InstanceToEventsMap;
typedef UNORDERED_MAP<uint64, InstanceToEventsMap> 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 #endif

View File

@@ -494,7 +494,7 @@ namespace LuaGlobalFunctions
lua_pushvalue(L, 3); lua_pushvalue(L, 3);
int functionRef = luaL_ref(L, LUA_REGISTRYINDEX); int functionRef = luaL_ref(L, LUA_REGISTRYINDEX);
if (functionRef >= 0) if (functionRef >= 0)
E->Register(regtype, entry, ev, functionRef, shots); E->Register(regtype, entry, 0, 0, ev, functionRef, shots);
else else
luaL_argerror(L, 3, "unable to make a ref to function"); luaL_argerror(L, 3, "unable to make a ref to function");
} }
@@ -508,11 +508,27 @@ namespace LuaGlobalFunctions
lua_pushvalue(L, 2); lua_pushvalue(L, 2);
int functionRef = luaL_ref(L, LUA_REGISTRYINDEX); int functionRef = luaL_ref(L, LUA_REGISTRYINDEX);
if (functionRef >= 0) if (functionRef >= 0)
E->Register(regtype, 0, ev, functionRef, shots); E->Register(regtype, 0, 0, 0, ev, functionRef, shots);
else else
luaL_argerror(L, 2, "unable to make a ref to function"); 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<uint64>(L, 1);
uint32 instanceId = Eluna::CHECKVAL<uint32>(L, 2);
uint32 ev = Eluna::CHECKVAL<uint32>(L, 3);
luaL_checktype(L, 4, LUA_TFUNCTION);
uint32 shots = Eluna::CHECKVAL<uint32>(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. * Registers a server event handler.
* *
@@ -921,9 +937,9 @@ namespace LuaGlobalFunctions
* }; * };
* </pre> * </pre>
* *
* @param uint32 entry : [Creature] entry Id * @param uint32 entry : the ID of one or more [Creature]s
* @param uint32 event : [Creature] event Id, refer to CreatureEvents above * @param uint32 event : refer to CreatureEvents above
* @param function function : function to register * @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" * @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) int RegisterCreatureEvent(Eluna* E, lua_State* L)
@@ -932,6 +948,65 @@ namespace LuaGlobalFunctions
return 0; return 0;
} }
/**
* Registers a [Creature] event handler for a *single* [Creature].
*
* <pre>
* 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
* };
* </pre>
*
* @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. * Registers a [GameObject] event handler.
* *
@@ -2355,7 +2430,7 @@ namespace LuaGlobalFunctions
/** /**
* Unbinds all event handlers for a particular [Creature] event/entry combination. * 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] * @param uint32 event_type : the event whose handlers will be cleared, see [Global:RegisterCreatureEvent]
*/ */
int ClearCreatureEvents(Eluna* E, lua_State* L) int ClearCreatureEvents(Eluna* E, lua_State* L)
@@ -2366,6 +2441,22 @@ namespace LuaGlobalFunctions
return 0; 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<uint64>(L, 1);
uint32 instanceId = Eluna::CHECKVAL<uint32>(L, 2);
uint32 event_type = Eluna::CHECKVAL<uint32>(L, 3);
E->CreatureUniqueBindings->Clear(guid, instanceId, event_type);
return 0;
}
/** /**
* Unbinds all event handlers for a particular [Creature] gossip event/entry combination. * Unbinds all event handlers for a particular [Creature] gossip event/entry combination.
* *

View File

@@ -94,7 +94,7 @@ using namespace HookMgr;
* Use the simpler overloads for just EventBind or EntryBind instead of this overload in hooks. * Use the simpler overloads for just EventBind or EntryBind instead of this overload in hooks.
*/ */
template<typename T> template<typename T>
int Eluna::SetupStack(EventBind<T>* event_bindings, EntryBind<T>* entry_bindings, T event_id, uint32 entry, int number_of_arguments) int Eluna::SetupStack(EventBind<T>* event_bindings, EntryBind<T>* entry_bindings, UniqueBind<T>* 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. // Ensure that if `entry_bindings` is not NULL, a valid entry is supplied.
ASSERT(!entry_bindings || (entry_bindings && entry > 0)); ASSERT(!entry_bindings || (entry_bindings && entry > 0));
@@ -118,6 +118,9 @@ int Eluna::SetupStack(EventBind<T>* event_bindings, EntryBind<T>* entry_bindings
if (entry_bindings) if (entry_bindings)
entry_bindings->PushFuncRefs(L, (int)event_id, entry); 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] // Stack: event_id, [arguments], [functions]
int number_of_functions = lua_gettop(L) - arguments_top; 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. * Call all event handlers registered to the event ID/entry combination and ignore any results.
*/ */
template<typename T> template<typename T>
void Eluna::CallAllFunctions(EventBind<T>* event_bindings, EntryBind<T>* entry_bindings, T event_id, uint32 entry) void Eluna::CallAllFunctions(EventBind<T>* event_bindings, EntryBind<T>* entry_bindings, UniqueBind<T>* guid_bindings, T event_id, uint32 entry, uint64 guid, uint32 instanceId)
{ {
int number_of_arguments = this->push_counter; int number_of_arguments = this->push_counter;
// Stack: [arguments] // 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] // Stack: event_id, [arguments], [functions]
while (number_of_functions > 0) while (number_of_functions > 0)
@@ -214,14 +217,14 @@ void Eluna::CallAllFunctions(EventBind<T>* event_bindings, EntryBind<T>* entry_b
* otherwise returns the opposite of `default_value`. * otherwise returns the opposite of `default_value`.
*/ */
template<typename T> template<typename T>
bool Eluna::CallAllFunctionsBool(EventBind<T>* event_bindings, EntryBind<T>* entry_bindings, T event_id, uint32 entry, bool default_value) bool Eluna::CallAllFunctionsBool(EventBind<T>* event_bindings, EntryBind<T>* entry_bindings, UniqueBind<T>* guid_bindings, T event_id, uint32 entry, uint64 guid, uint32 instanceId, bool default_value)
{ {
bool result = default_value; bool result = default_value;
// Note: number_of_arguments here does not count in eventID, which is pushed in SetupStack // Note: number_of_arguments here does not count in eventID, which is pushed in SetupStack
int number_of_arguments = this->push_counter; int number_of_arguments = this->push_counter;
// Stack: [arguments] // 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] // Stack: event_id, [arguments], [functions]
while (number_of_functions > 0) while (number_of_functions > 0)
@@ -1734,6 +1737,7 @@ void Eluna::OnRemove(Creature* creature)
bool Eluna::OnDummyEffect(Unit* pCaster, uint32 spellId, SpellEffIndex effIndex, Creature* pTarget) bool Eluna::OnDummyEffect(Unit* pCaster, uint32 spellId, SpellEffIndex effIndex, Creature* pTarget)
{ {
if (!CreatureEventBindings->HasEvents(CREATURE_EVENT_ON_DUMMY_EFFECT, pTarget->GetEntry())) if (!CreatureEventBindings->HasEvents(CREATURE_EVENT_ON_DUMMY_EFFECT, pTarget->GetEntry()))
if (!CreatureUniqueBindings->HasEvents(CREATURE_EVENT_ON_DUMMY_EFFECT, pTarget->GET_GUID(), pTarget->GetInstanceId()))
return false; return false;
LOCK_ELUNA; LOCK_ELUNA;
@@ -1741,7 +1745,7 @@ bool Eluna::OnDummyEffect(Unit* pCaster, uint32 spellId, SpellEffIndex effIndex,
Push(spellId); Push(spellId);
Push(effIndex); Push(effIndex);
Push(pTarget); 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) bool Eluna::OnGossipHello(Player* pPlayer, Creature* pCreature)
@@ -1788,18 +1792,20 @@ bool Eluna::OnGossipSelectCode(Player* pPlayer, Creature* pCreature, uint32 send
bool Eluna::OnQuestAccept(Player* pPlayer, Creature* pCreature, Quest const* pQuest) bool Eluna::OnQuestAccept(Player* pPlayer, Creature* pCreature, Quest const* pQuest)
{ {
if (!CreatureEventBindings->HasEvents(CREATURE_EVENT_ON_QUEST_ACCEPT, pCreature->GetEntry())) if (!CreatureEventBindings->HasEvents(CREATURE_EVENT_ON_QUEST_ACCEPT, pCreature->GetEntry()))
if (!CreatureUniqueBindings->HasEvents(CREATURE_EVENT_ON_QUEST_ACCEPT, pCreature->GET_GUID(), pCreature->GetInstanceId()))
return false; return false;
LOCK_ELUNA; LOCK_ELUNA;
Push(pPlayer); Push(pPlayer);
Push(pCreature); Push(pCreature);
Push(pQuest); 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) bool Eluna::OnQuestReward(Player* pPlayer, Creature* pCreature, Quest const* pQuest, uint32 opt)
{ {
if (!CreatureEventBindings->HasEvents(CREATURE_EVENT_ON_QUEST_REWARD, pCreature->GetEntry())) if (!CreatureEventBindings->HasEvents(CREATURE_EVENT_ON_QUEST_REWARD, pCreature->GetEntry()))
if (!CreatureUniqueBindings->HasEvents(CREATURE_EVENT_ON_QUEST_REWARD, pCreature->GET_GUID(), pCreature->GetInstanceId()))
return false; return false;
LOCK_ELUNA; LOCK_ELUNA;
@@ -1807,61 +1813,66 @@ bool Eluna::OnQuestReward(Player* pPlayer, Creature* pCreature, Quest const* pQu
Push(pCreature); Push(pCreature);
Push(pQuest); Push(pQuest);
Push(opt); 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) uint32 Eluna::GetDialogStatus(Player* pPlayer, Creature* pCreature)
{ {
if (!CreatureEventBindings->HasEvents(CREATURE_EVENT_ON_DIALOG_STATUS, pCreature->GetEntry())) if (!CreatureEventBindings->HasEvents(CREATURE_EVENT_ON_DIALOG_STATUS, pCreature->GetEntry()))
if (!CreatureUniqueBindings->HasEvents(CREATURE_EVENT_ON_DIALOG_STATUS, pCreature->GET_GUID(), pCreature->GetInstanceId()))
return DIALOG_STATUS_SCRIPTED_NO_STATUS; return DIALOG_STATUS_SCRIPTED_NO_STATUS;
LOCK_ELUNA; LOCK_ELUNA;
Push(pPlayer); Push(pPlayer);
Push(pCreature); 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; return DIALOG_STATUS_SCRIPTED_NO_STATUS;
} }
void Eluna::OnAddToWorld(Creature* creature) void Eluna::OnAddToWorld(Creature* creature)
{ {
if (!CreatureEventBindings->HasEvents(CREATURE_EVENT_ON_ADD, creature->GetEntry())) if (!CreatureEventBindings->HasEvents(CREATURE_EVENT_ON_ADD, creature->GetEntry()))
if (!CreatureUniqueBindings->HasEvents(CREATURE_EVENT_ON_ADD, creature->GET_GUID(), creature->GetInstanceId()))
return; return;
LOCK_ELUNA; LOCK_ELUNA;
Push(creature); 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) void Eluna::OnRemoveFromWorld(Creature* creature)
{ {
if (!CreatureEventBindings->HasEvents(CREATURE_EVENT_ON_REMOVE, creature->GetEntry())) if (!CreatureEventBindings->HasEvents(CREATURE_EVENT_ON_REMOVE, creature->GetEntry()))
if (!CreatureUniqueBindings->HasEvents(CREATURE_EVENT_ON_REMOVE, creature->GET_GUID(), creature->GetInstanceId()))
return; return;
LOCK_ELUNA; LOCK_ELUNA;
Push(creature); 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) bool Eluna::OnSummoned(Creature* pCreature, Unit* pSummoner)
{ {
if (!CreatureEventBindings->HasEvents(CREATURE_EVENT_ON_SUMMONED, pCreature->GetEntry())) if (!CreatureEventBindings->HasEvents(CREATURE_EVENT_ON_SUMMONED, pCreature->GetEntry()))
if (!CreatureUniqueBindings->HasEvents(CREATURE_EVENT_ON_SUMMONED, pCreature->GET_GUID(), pCreature->GetInstanceId()))
return false; return false;
LOCK_ELUNA; LOCK_ELUNA;
Push(pCreature); Push(pCreature);
Push(pSummoner); 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) bool Eluna::UpdateAI(Creature* me, const uint32 diff)
{ {
if (!CreatureEventBindings->HasEvents(CREATURE_EVENT_ON_AIUPDATE, me->GetEntry())) if (!CreatureEventBindings->HasEvents(CREATURE_EVENT_ON_AIUPDATE, me->GetEntry()))
if (!CreatureUniqueBindings->HasEvents(CREATURE_EVENT_ON_AIUPDATE, me->GET_GUID(), me->GetInstanceId()))
return false; return false;
LOCK_ELUNA; LOCK_ELUNA;
Push(me); Push(me);
Push(diff); 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) //Called for reaction at enter to combat if not in combat yet (enemy can be NULL)
@@ -1869,18 +1880,20 @@ bool Eluna::UpdateAI(Creature* me, const uint32 diff)
bool Eluna::EnterCombat(Creature* me, Unit* target) bool Eluna::EnterCombat(Creature* me, Unit* target)
{ {
if (!CreatureEventBindings->HasEvents(CREATURE_EVENT_ON_ENTER_COMBAT, me->GetEntry())) if (!CreatureEventBindings->HasEvents(CREATURE_EVENT_ON_ENTER_COMBAT, me->GetEntry()))
if (!CreatureUniqueBindings->HasEvents(CREATURE_EVENT_ON_ENTER_COMBAT, me->GET_GUID(), me->GetInstanceId()))
return false; return false;
LOCK_ELUNA; LOCK_ELUNA;
Push(me); Push(me);
Push(target); 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) // Called at any Damage from any attacker (before damage apply)
bool Eluna::DamageTaken(Creature* me, Unit* attacker, uint32& damage) bool Eluna::DamageTaken(Creature* me, Unit* attacker, uint32& damage)
{ {
if (!CreatureEventBindings->HasEvents(CREATURE_EVENT_ON_DAMAGE_TAKEN, me->GetEntry())) if (!CreatureEventBindings->HasEvents(CREATURE_EVENT_ON_DAMAGE_TAKEN, me->GetEntry()))
if (!CreatureUniqueBindings->HasEvents(CREATURE_EVENT_ON_DAMAGE_TAKEN, me->GET_GUID(), me->GetInstanceId()))
return false; return false;
LOCK_ELUNA; LOCK_ELUNA;
@@ -1889,7 +1902,7 @@ bool Eluna::DamageTaken(Creature* me, Unit* attacker, uint32& damage)
Push(attacker); Push(attacker);
Push(damage); Push(damage);
int damageIndex = lua_gettop(L); 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) while (n > 0)
{ {
@@ -1918,73 +1931,79 @@ bool Eluna::JustDied(Creature* me, Unit* killer)
On_Reset(me); On_Reset(me);
if (!CreatureEventBindings->HasEvents(CREATURE_EVENT_ON_DIED, me->GetEntry())) if (!CreatureEventBindings->HasEvents(CREATURE_EVENT_ON_DIED, me->GetEntry()))
if (!CreatureUniqueBindings->HasEvents(CREATURE_EVENT_ON_DIED, me->GET_GUID(), me->GetInstanceId()))
return false; return false;
LOCK_ELUNA; LOCK_ELUNA;
Push(me); Push(me);
Push(killer); 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 //Called at creature killing another unit
bool Eluna::KilledUnit(Creature* me, Unit* victim) bool Eluna::KilledUnit(Creature* me, Unit* victim)
{ {
if (!CreatureEventBindings->HasEvents(CREATURE_EVENT_ON_TARGET_DIED, me->GetEntry())) if (!CreatureEventBindings->HasEvents(CREATURE_EVENT_ON_TARGET_DIED, me->GetEntry()))
if (!CreatureUniqueBindings->HasEvents(CREATURE_EVENT_ON_TARGET_DIED, me->GET_GUID(), me->GetInstanceId()))
return false; return false;
LOCK_ELUNA; LOCK_ELUNA;
Push(me); Push(me);
Push(victim); 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 // Called when the creature summon successfully other creature
bool Eluna::JustSummoned(Creature* me, Creature* summon) bool Eluna::JustSummoned(Creature* me, Creature* summon)
{ {
if (!CreatureEventBindings->HasEvents(CREATURE_EVENT_ON_JUST_SUMMONED_CREATURE, me->GetEntry())) if (!CreatureEventBindings->HasEvents(CREATURE_EVENT_ON_JUST_SUMMONED_CREATURE, me->GetEntry()))
if (!CreatureUniqueBindings->HasEvents(CREATURE_EVENT_ON_JUST_SUMMONED_CREATURE, me->GET_GUID(), me->GetInstanceId()))
return false; return false;
LOCK_ELUNA; LOCK_ELUNA;
Push(me); Push(me);
Push(summon); 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 // Called when a summoned creature is despawned
bool Eluna::SummonedCreatureDespawn(Creature* me, Creature* summon) bool Eluna::SummonedCreatureDespawn(Creature* me, Creature* summon)
{ {
if (!CreatureEventBindings->HasEvents(CREATURE_EVENT_ON_SUMMONED_CREATURE_DESPAWN, me->GetEntry())) if (!CreatureEventBindings->HasEvents(CREATURE_EVENT_ON_SUMMONED_CREATURE_DESPAWN, me->GetEntry()))
if (!CreatureUniqueBindings->HasEvents(CREATURE_EVENT_ON_SUMMONED_CREATURE_DESPAWN, me->GET_GUID(), me->GetInstanceId()))
return false; return false;
LOCK_ELUNA; LOCK_ELUNA;
Push(me); Push(me);
Push(summon); 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 //Called at waypoint reached or PointMovement end
bool Eluna::MovementInform(Creature* me, uint32 type, uint32 id) bool Eluna::MovementInform(Creature* me, uint32 type, uint32 id)
{ {
if (!CreatureEventBindings->HasEvents(CREATURE_EVENT_ON_REACH_WP, me->GetEntry())) if (!CreatureEventBindings->HasEvents(CREATURE_EVENT_ON_REACH_WP, me->GetEntry()))
if (!CreatureUniqueBindings->HasEvents(CREATURE_EVENT_ON_REACH_WP, me->GET_GUID(), me->GetInstanceId()))
return false; return false;
LOCK_ELUNA; LOCK_ELUNA;
Push(me); Push(me);
Push(type); Push(type);
Push(id); 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. // Called before EnterCombat even before the creature is in combat.
bool Eluna::AttackStart(Creature* me, Unit* target) bool Eluna::AttackStart(Creature* me, Unit* target)
{ {
if (!CreatureEventBindings->HasEvents(CREATURE_EVENT_ON_PRE_COMBAT, me->GetEntry())) if (!CreatureEventBindings->HasEvents(CREATURE_EVENT_ON_PRE_COMBAT, me->GetEntry()))
if (!CreatureUniqueBindings->HasEvents(CREATURE_EVENT_ON_PRE_COMBAT, me->GET_GUID(), me->GetInstanceId()))
return false; return false;
LOCK_ELUNA; LOCK_ELUNA;
Push(me); Push(me);
Push(target); 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 // Called for reaction at stopping attack at no attackers or targets
@@ -1993,23 +2012,25 @@ bool Eluna::EnterEvadeMode(Creature* me)
On_Reset(me); On_Reset(me);
if (!CreatureEventBindings->HasEvents(CREATURE_EVENT_ON_LEAVE_COMBAT, me->GetEntry())) if (!CreatureEventBindings->HasEvents(CREATURE_EVENT_ON_LEAVE_COMBAT, me->GetEntry()))
if (!CreatureUniqueBindings->HasEvents(CREATURE_EVENT_ON_LEAVE_COMBAT, me->GET_GUID(), me->GetInstanceId()))
return false; return false;
LOCK_ELUNA; LOCK_ELUNA;
Push(me); 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) // Called when the creature is target of hostile action: swing, hostile spell landed, fear/etc)
bool Eluna::AttackedBy(Creature* me, Unit* attacker) bool Eluna::AttackedBy(Creature* me, Unit* attacker)
{ {
if (!CreatureEventBindings->HasEvents(CREATURE_EVENT_ON_ATTACKED_AT, me->GetEntry())) if (!CreatureEventBindings->HasEvents(CREATURE_EVENT_ON_ATTACKED_AT, me->GetEntry()))
if (!CreatureUniqueBindings->HasEvents(CREATURE_EVENT_ON_ATTACKED_AT, me->GET_GUID(), me->GetInstanceId()))
return false; return false;
LOCK_ELUNA; LOCK_ELUNA;
Push(me); Push(me);
Push(attacker); 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) // Called when creature is spawned or respawned (for reseting variables)
@@ -2018,41 +2039,45 @@ bool Eluna::JustRespawned(Creature* me)
On_Reset(me); On_Reset(me);
if (!CreatureEventBindings->HasEvents(CREATURE_EVENT_ON_SPAWN, me->GetEntry())) if (!CreatureEventBindings->HasEvents(CREATURE_EVENT_ON_SPAWN, me->GetEntry()))
if (!CreatureUniqueBindings->HasEvents(CREATURE_EVENT_ON_SPAWN, me->GET_GUID(), me->GetInstanceId()))
return false; return false;
LOCK_ELUNA; LOCK_ELUNA;
Push(me); 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 // Called at reaching home after evade
bool Eluna::JustReachedHome(Creature* me) bool Eluna::JustReachedHome(Creature* me)
{ {
if (!CreatureEventBindings->HasEvents(CREATURE_EVENT_ON_REACH_HOME, me->GetEntry())) if (!CreatureEventBindings->HasEvents(CREATURE_EVENT_ON_REACH_HOME, me->GetEntry()))
if (!CreatureUniqueBindings->HasEvents(CREATURE_EVENT_ON_REACH_HOME, me->GET_GUID(), me->GetInstanceId()))
return false; return false;
LOCK_ELUNA; LOCK_ELUNA;
Push(me); 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 // Called at text emote receive from player
bool Eluna::ReceiveEmote(Creature* me, Player* player, uint32 emoteId) bool Eluna::ReceiveEmote(Creature* me, Player* player, uint32 emoteId)
{ {
if (!CreatureEventBindings->HasEvents(CREATURE_EVENT_ON_RECEIVE_EMOTE, me->GetEntry())) if (!CreatureEventBindings->HasEvents(CREATURE_EVENT_ON_RECEIVE_EMOTE, me->GetEntry()))
if (!CreatureUniqueBindings->HasEvents(CREATURE_EVENT_ON_RECEIVE_EMOTE, me->GET_GUID(), me->GetInstanceId()))
return false; return false;
LOCK_ELUNA; LOCK_ELUNA;
Push(me); Push(me);
Push(player); Push(player);
Push(emoteId); 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 // called when the corpse of this creature gets removed
bool Eluna::CorpseRemoved(Creature* me, uint32& respawnDelay) bool Eluna::CorpseRemoved(Creature* me, uint32& respawnDelay)
{ {
if (!CreatureEventBindings->HasEvents(CREATURE_EVENT_ON_CORPSE_REMOVED, me->GetEntry())) if (!CreatureEventBindings->HasEvents(CREATURE_EVENT_ON_CORPSE_REMOVED, me->GetEntry()))
if (!CreatureUniqueBindings->HasEvents(CREATURE_EVENT_ON_CORPSE_REMOVED, me->GET_GUID(), me->GetInstanceId()))
return false; return false;
LOCK_ELUNA; LOCK_ELUNA;
@@ -2060,7 +2085,7 @@ bool Eluna::CorpseRemoved(Creature* me, uint32& respawnDelay)
Push(me); Push(me);
Push(respawnDelay); Push(respawnDelay);
int respawnDelayIndex = lua_gettop(L); 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) while (n > 0)
{ {
@@ -2086,49 +2111,53 @@ bool Eluna::CorpseRemoved(Creature* me, uint32& respawnDelay)
bool Eluna::MoveInLineOfSight(Creature* me, Unit* who) bool Eluna::MoveInLineOfSight(Creature* me, Unit* who)
{ {
if (!CreatureEventBindings->HasEvents(CREATURE_EVENT_ON_MOVE_IN_LOS, me->GetEntry())) if (!CreatureEventBindings->HasEvents(CREATURE_EVENT_ON_MOVE_IN_LOS, me->GetEntry()))
if (!CreatureUniqueBindings->HasEvents(CREATURE_EVENT_ON_MOVE_IN_LOS, me->GET_GUID(), me->GetInstanceId()))
return false; return false;
LOCK_ELUNA; LOCK_ELUNA;
Push(me); Push(me);
Push(who); 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) // Called on creature initial spawn, respawn, death, evade (leave combat)
void Eluna::On_Reset(Creature* me) // Not an override, custom void Eluna::On_Reset(Creature* me) // Not an override, custom
{ {
if (!CreatureEventBindings->HasEvents(CREATURE_EVENT_ON_RESET, me->GetEntry())) if (!CreatureEventBindings->HasEvents(CREATURE_EVENT_ON_RESET, me->GetEntry()))
if (!CreatureUniqueBindings->HasEvents(CREATURE_EVENT_ON_RESET, me->GET_GUID(), me->GetInstanceId()))
return; return;
LOCK_ELUNA; LOCK_ELUNA;
Push(me); 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 // Called when hit by a spell
bool Eluna::SpellHit(Creature* me, Unit* caster, SpellInfo const* spell) bool Eluna::SpellHit(Creature* me, Unit* caster, SpellInfo const* spell)
{ {
if (!CreatureEventBindings->HasEvents(CREATURE_EVENT_ON_HIT_BY_SPELL, me->GetEntry())) if (!CreatureEventBindings->HasEvents(CREATURE_EVENT_ON_HIT_BY_SPELL, me->GetEntry()))
if (!CreatureUniqueBindings->HasEvents(CREATURE_EVENT_ON_HIT_BY_SPELL, me->GET_GUID(), me->GetInstanceId()))
return false; return false;
LOCK_ELUNA; LOCK_ELUNA;
Push(me); Push(me);
Push(caster); Push(caster);
Push(spell->Id); // Pass spell object? 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 // Called when spell hits a target
bool Eluna::SpellHitTarget(Creature* me, Unit* target, SpellInfo const* spell) bool Eluna::SpellHitTarget(Creature* me, Unit* target, SpellInfo const* spell)
{ {
if (!CreatureEventBindings->HasEvents(CREATURE_EVENT_ON_SPELL_HIT_TARGET, me->GetEntry())) if (!CreatureEventBindings->HasEvents(CREATURE_EVENT_ON_SPELL_HIT_TARGET, me->GetEntry()))
if (!CreatureUniqueBindings->HasEvents(CREATURE_EVENT_ON_SPELL_HIT_TARGET, me->GET_GUID(), me->GetInstanceId()))
return false; return false;
LOCK_ELUNA; LOCK_ELUNA;
Push(me); Push(me);
Push(target); Push(target);
Push(spell->Id); // Pass spell object? 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 #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) bool Eluna::SummonedCreatureDies(Creature* me, Creature* summon, Unit* killer)
{ {
if (!CreatureEventBindings->HasEvents(CREATURE_EVENT_ON_SUMMONED_CREATURE_DIED, me->GetEntry())) if (!CreatureEventBindings->HasEvents(CREATURE_EVENT_ON_SUMMONED_CREATURE_DIED, me->GetEntry()))
if (!CreatureUniqueBindings->HasEvents(CREATURE_EVENT_ON_SUMMONED_CREATURE_DIED, me->GET_GUID(), me->GetInstanceId()))
return false; return false;
LOCK_ELUNA; LOCK_ELUNA;
Push(me); Push(me);
Push(summon); Push(summon);
Push(killer); 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 // Called when owner takes damage
bool Eluna::OwnerAttackedBy(Creature* me, Unit* attacker) bool Eluna::OwnerAttackedBy(Creature* me, Unit* attacker)
{ {
if (!CreatureEventBindings->HasEvents(CREATURE_EVENT_ON_OWNER_ATTACKED_AT, me->GetEntry())) if (!CreatureEventBindings->HasEvents(CREATURE_EVENT_ON_OWNER_ATTACKED_AT, me->GetEntry()))
if (!CreatureUniqueBindings->HasEvents(CREATURE_EVENT_ON_OWNER_ATTACKED_AT, me->GET_GUID(), me->GetInstanceId()))
return false; return false;
LOCK_ELUNA; LOCK_ELUNA;
Push(me); Push(me);
Push(attacker); 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 // Called when owner attacks something
bool Eluna::OwnerAttacked(Creature* me, Unit* target) bool Eluna::OwnerAttacked(Creature* me, Unit* target)
{ {
if (!CreatureEventBindings->HasEvents(CREATURE_EVENT_ON_OWNER_ATTACKED, me->GetEntry())) if (!CreatureEventBindings->HasEvents(CREATURE_EVENT_ON_OWNER_ATTACKED, me->GetEntry()))
if (!CreatureUniqueBindings->HasEvents(CREATURE_EVENT_ON_OWNER_ATTACKED, me->GET_GUID(), me->GetInstanceId()))
return false; return false;
LOCK_ELUNA; LOCK_ELUNA;
Push(me); Push(me);
Push(target); 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 #endif
@@ -2547,7 +2579,7 @@ void Eluna::OnRemoveFromWorld(GameObject* gameobject)
CreatureAI* Eluna::GetAI(Creature* creature) 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 NULL;
return new ElunaCreatureAI(creature); return new ElunaCreatureAI(creature);
} }

View File

@@ -137,7 +137,9 @@ GameObjectEventBindings(new EntryBind<HookMgr::GameObjectEvents>("GameObjectEven
GameObjectGossipBindings(new EntryBind<HookMgr::GossipEvents>("GossipEvents (gameobject)", *this)), GameObjectGossipBindings(new EntryBind<HookMgr::GossipEvents>("GossipEvents (gameobject)", *this)),
ItemEventBindings(new EntryBind<HookMgr::ItemEvents>("ItemEvents", *this)), ItemEventBindings(new EntryBind<HookMgr::ItemEvents>("ItemEvents", *this)),
ItemGossipBindings(new EntryBind<HookMgr::GossipEvents>("GossipEvents (item)", *this)), ItemGossipBindings(new EntryBind<HookMgr::GossipEvents>("GossipEvents (item)", *this)),
playerGossipBindings(new EntryBind<HookMgr::GossipEvents>("GossipEvents (player)", *this)) playerGossipBindings(new EntryBind<HookMgr::GossipEvents>("GossipEvents (player)", *this)),
CreatureUniqueBindings(new UniqueBind<HookMgr::CreatureEvents>("CreatureEvents", *this))
{ {
// open base lua libraries // open base lua libraries
luaL_openlibs(L); 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 // 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) switch (regtype)
{ {
@@ -830,6 +832,8 @@ void Eluna::Register(uint8 regtype, uint32 id, uint32 evt, int functionRef, uint
case HookMgr::REGTYPE_CREATURE: case HookMgr::REGTYPE_CREATURE:
if (evt < HookMgr::CREATURE_EVENT_COUNT) if (evt < HookMgr::CREATURE_EVENT_COUNT)
{
if (id != 0)
{ {
if (!eObjectMgr->GetCreatureTemplate(id)) if (!eObjectMgr->GetCreatureTemplate(id))
{ {
@@ -839,6 +843,12 @@ void Eluna::Register(uint8 regtype, uint32 id, uint32 evt, int functionRef, uint
} }
CreatureEventBindings->Insert(id, evt, functionRef, shots); CreatureEventBindings->Insert(id, evt, functionRef, shots);
}
else
{
ASSERT(guid != 0);
CreatureUniqueBindings->Insert(guid, instanceId, evt, functionRef, shots);
}
return; return;
} }
break; break;

View File

@@ -91,6 +91,8 @@ template<typename T>
class EventBind; class EventBind;
template<typename T> template<typename T>
class EntryBind; class EntryBind;
template<typename T>
class UniqueBind;
struct LuaScript struct LuaScript
{ {
@@ -110,41 +112,53 @@ private:
Eluna& operator=(const Eluna&); Eluna& operator=(const Eluna&);
// Some helpers for hooks to call event handlers. // Some helpers for hooks to call event handlers.
template<typename T> int SetupStack(EventBind<T>* event_bindings, EntryBind<T>* entry_bindings, T event_id, uint32 entry, int number_of_arguments); template<typename T> int SetupStack(EventBind<T>* event_bindings, EntryBind<T>* entry_bindings, UniqueBind<T>* 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); void CleanUpStack(int number_of_arguments);
template<typename T> void ReplaceArgument(T value, uint8 index); template<typename T> void ReplaceArgument(T value, uint8 index);
int CallOneFunction(int number_of_functions, int number_of_arguments, int number_of_results); template<typename T> void CallAllFunctions(EventBind<T>* event_bindings, EntryBind<T>* entry_bindings, UniqueBind<T>* guid_bindings, T event_id, uint32 entry, uint64 guid, uint32 instanceId);
template<typename T> void CallAllFunctions(EventBind<T>* event_bindings, EntryBind<T>* entry_bindings, T event_id, uint32 entry); template<typename T> bool CallAllFunctionsBool(EventBind<T>* event_bindings, EntryBind<T>* entry_bindings, UniqueBind<T>* guid_bindings, T event_id, uint32 entry, uint64 guid, uint32 instanceId, bool default_value);
template<typename T> bool CallAllFunctionsBool(EventBind<T>* event_bindings, EntryBind<T>* entry_bindings, T event_id, uint32 entry, bool default_value);
// Convenient overloads for Setup. Use these in hooks instead of original. // Convenient overloads for Setup. Use these in hooks instead of original.
template<typename T> int SetupStack(EventBind<T>* event_bindings, T event_id, int number_of_arguments) template<typename T> int SetupStack(EventBind<T>* event_bindings, T event_id, int number_of_arguments)
{ {
return SetupStack(event_bindings, (EntryBind<T>*)NULL, event_id, 0, number_of_arguments); return SetupStack(event_bindings, (EntryBind<T>*)NULL, (UniqueBind<T>*)NULL, event_id, 0, 0, 0, number_of_arguments);
} }
template<typename T> int SetupStack(EntryBind<T>* entry_bindings, T event_id, uint32 entry, int number_of_arguments) template<typename T> int SetupStack(EntryBind<T>* entry_bindings, T event_id, uint32 entry, int number_of_arguments)
{ {
return SetupStack((EventBind<T>*)NULL, entry_bindings, event_id, entry, number_of_arguments); return SetupStack((EventBind<T>*)NULL, entry_bindings, (UniqueBind<T>*)NULL, event_id, entry, 0, 0, number_of_arguments);
}
template<typename T> int SetupStack(EntryBind<T>* entry_bindings, UniqueBind<T>* guid_bindings, T event_id, uint32 entry, uint64 guid, uint32 instanceId, int number_of_arguments)
{
return SetupStack((EventBind<T>*)NULL, entry_bindings, guid_bindings, event_id, entry, guid, instanceId, number_of_arguments);
} }
// Convenient overloads for CallAllFunctions. Use these in hooks instead of original. // Convenient overloads for CallAllFunctions. Use these in hooks instead of original.
template<typename T> void CallAllFunctions(EventBind<T>* event_bindings, T event_id) template<typename T> void CallAllFunctions(EventBind<T>* event_bindings, T event_id)
{ {
CallAllFunctions(event_bindings, (EntryBind<T>*)NULL, event_id, 0); CallAllFunctions(event_bindings, (EntryBind<T>*)NULL, (UniqueBind<T>*)NULL, event_id, 0, 0, 0);
} }
template<typename T> void CallAllFunctions(EntryBind<T>* entry_bindings, T event_id, uint32 entry) template<typename T> void CallAllFunctions(EntryBind<T>* entry_bindings, T event_id, uint32 entry)
{ {
CallAllFunctions((EventBind<T>*)NULL, entry_bindings, event_id, entry); CallAllFunctions((EventBind<T>*)NULL, entry_bindings, (UniqueBind<T>*)NULL, event_id, entry, 0, 0);
}
template<typename T> void CallAllFunctions(EntryBind<T>* entry_bindings, UniqueBind<T>* guid_bindings, T event_id, uint32 entry, uint64 guid, uint32 instanceId)
{
CallAllFunctions((EventBind<T>*)NULL, entry_bindings, guid_bindings, event_id, entry, guid, instanceId);
} }
// Convenient overloads for CallAllFunctionsBool. Use these in hooks instead of original. // Convenient overloads for CallAllFunctionsBool. Use these in hooks instead of original.
template<typename T> bool CallAllFunctionsBool(EventBind<T>* event_bindings, T event_id, bool default_value = false) template<typename T> bool CallAllFunctionsBool(EventBind<T>* event_bindings, T event_id, bool default_value = false)
{ {
return CallAllFunctionsBool(event_bindings, (EntryBind<T>*)NULL, event_id, 0, default_value); return CallAllFunctionsBool(event_bindings, (EntryBind<T>*)NULL, (UniqueBind<T>*)NULL, event_id, 0, 0, 0, default_value);
} }
template<typename T> bool CallAllFunctionsBool(EntryBind<T>* entry_bindings, T event_id, uint32 entry, bool default_value = false) template<typename T> bool CallAllFunctionsBool(EntryBind<T>* entry_bindings, T event_id, uint32 entry, bool default_value = false)
{ {
return CallAllFunctionsBool((EventBind<T>*)NULL, entry_bindings, event_id, entry, default_value); return CallAllFunctionsBool((EventBind<T>*)NULL, entry_bindings, (UniqueBind<T>*)NULL, event_id, entry, 0, 0, default_value);
}
template<typename T> bool CallAllFunctionsBool(EntryBind<T>* entry_bindings, UniqueBind<T>* guid_bindings, T event_id, uint32 entry, uint64 guid, uint32 instanceId, bool default_value = false)
{
return CallAllFunctionsBool((EventBind<T>*)NULL, entry_bindings, guid_bindings, event_id, entry, guid, instanceId, default_value);
} }
public: public:
@@ -185,6 +199,8 @@ public:
EntryBind<HookMgr::GossipEvents>* ItemGossipBindings; EntryBind<HookMgr::GossipEvents>* ItemGossipBindings;
EntryBind<HookMgr::GossipEvents>* playerGossipBindings; EntryBind<HookMgr::GossipEvents>* playerGossipBindings;
UniqueBind<HookMgr::CreatureEvents>* CreatureUniqueBindings;
Eluna(); Eluna();
~Eluna(); ~Eluna();
@@ -202,7 +218,7 @@ public:
static void report(lua_State* luastate); static void report(lua_State* luastate);
void ExecuteCall(int params, int res); 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 RunScripts();
void InvalidateObjects(); void InvalidateObjects();

View File

@@ -47,6 +47,7 @@ ElunaGlobal::ElunaRegister GlobalMethods[] =
{ "RegisterGuildEvent", &LuaGlobalFunctions::RegisterGuildEvent }, // RegisterGuildEvent(event, function) { "RegisterGuildEvent", &LuaGlobalFunctions::RegisterGuildEvent }, // RegisterGuildEvent(event, function)
{ "RegisterGroupEvent", &LuaGlobalFunctions::RegisterGroupEvent }, // RegisterGroupEvent(event, function) { "RegisterGroupEvent", &LuaGlobalFunctions::RegisterGroupEvent }, // RegisterGroupEvent(event, function)
{ "RegisterCreatureEvent", &LuaGlobalFunctions::RegisterCreatureEvent }, // RegisterCreatureEvent(entry, event, function) { "RegisterCreatureEvent", &LuaGlobalFunctions::RegisterCreatureEvent }, // RegisterCreatureEvent(entry, event, function)
{ "RegisterUniqueCreatureEvent", &LuaGlobalFunctions::RegisterUniqueCreatureEvent }, // RegisterUniqueCreatureEvent(guid, instance, event, function)
{ "RegisterCreatureGossipEvent", &LuaGlobalFunctions::RegisterCreatureGossipEvent }, // RegisterCreatureGossipEvent(entry, event, function) { "RegisterCreatureGossipEvent", &LuaGlobalFunctions::RegisterCreatureGossipEvent }, // RegisterCreatureGossipEvent(entry, event, function)
{ "RegisterGameObjectEvent", &LuaGlobalFunctions::RegisterGameObjectEvent }, // RegisterGameObjectEvent(entry, event, function) { "RegisterGameObjectEvent", &LuaGlobalFunctions::RegisterGameObjectEvent }, // RegisterGameObjectEvent(entry, event, function)
{ "RegisterGameObjectGossipEvent", &LuaGlobalFunctions::RegisterGameObjectGossipEvent }, // RegisterGameObjectGossipEvent(entry, event, function) { "RegisterGameObjectGossipEvent", &LuaGlobalFunctions::RegisterGameObjectGossipEvent }, // RegisterGameObjectGossipEvent(entry, event, function)
@@ -57,6 +58,7 @@ ElunaGlobal::ElunaRegister GlobalMethods[] =
{ "ClearBattleGroundEvents", &LuaGlobalFunctions::ClearBattleGroundEvents }, { "ClearBattleGroundEvents", &LuaGlobalFunctions::ClearBattleGroundEvents },
{ "ClearCreatureEvents", &LuaGlobalFunctions::ClearCreatureEvents }, { "ClearCreatureEvents", &LuaGlobalFunctions::ClearCreatureEvents },
{ "ClearUniqueCreatureEvents", &LuaGlobalFunctions::ClearUniqueCreatureEvents },
{ "ClearCreatureGossipEvents", &LuaGlobalFunctions::ClearCreatureGossipEvents }, { "ClearCreatureGossipEvents", &LuaGlobalFunctions::ClearCreatureGossipEvents },
{ "ClearGameObjectEvents", &LuaGlobalFunctions::ClearGameObjectEvents }, { "ClearGameObjectEvents", &LuaGlobalFunctions::ClearGameObjectEvents },
{ "ClearGameObjectGossipEvents", &LuaGlobalFunctions::ClearGameObjectGossipEvents }, { "ClearGameObjectGossipEvents", &LuaGlobalFunctions::ClearGameObjectGossipEvents },