diff --git a/BattleGroundHooks.cpp b/BattleGroundHooks.cpp new file mode 100644 index 0000000..17baa02 --- /dev/null +++ b/BattleGroundHooks.cpp @@ -0,0 +1,67 @@ +/* + * Copyright (C) 2010 - 2015 Eluna Lua Engine + * This program is free software licensed under GPL version 3 + * Please see the included DOCS/LICENSE.md for more information + */ + +#ifndef _BATTLEGROUND_HOOKS_H +#define _BATTLEGROUND_HOOKS_H + +#include "Hooks.h" +#include "HookHelpers.h" +#include "LuaEngine.h" +#include "ElunaTemplate.h" // Needed to be able to push BattleGround objects. +#include "ElunaBinding.h" + +using namespace Hooks; + +void Eluna::OnBGStart(BattleGround* bg, BattleGroundTypeId bgId, uint32 instanceId) +{ + if (!BGEventBindings->HasEvents(BG_EVENT_ON_START)) + return; + + LOCK_ELUNA; + Push(bg); + Push(bgId); + Push(instanceId); + CallAllFunctions(BGEventBindings, BG_EVENT_ON_START); +} + +void Eluna::OnBGEnd(BattleGround* bg, BattleGroundTypeId bgId, uint32 instanceId, Team winner) +{ + if (!BGEventBindings->HasEvents(BG_EVENT_ON_END)) + return; + + LOCK_ELUNA; + Push(bg); + Push(bgId); + Push(instanceId); + Push(winner); + CallAllFunctions(BGEventBindings, BG_EVENT_ON_END); +} + +void Eluna::OnBGCreate(BattleGround* bg, BattleGroundTypeId bgId, uint32 instanceId) +{ + if (!BGEventBindings->HasEvents(BG_EVENT_ON_CREATE)) + return; + + LOCK_ELUNA; + Push(bg); + Push(bgId); + Push(instanceId); + CallAllFunctions(BGEventBindings, BG_EVENT_ON_CREATE); +} + +void Eluna::OnBGDestroy(BattleGround* bg, BattleGroundTypeId bgId, uint32 instanceId) +{ + if (!BGEventBindings->HasEvents(BG_EVENT_ON_PRE_DESTROY)) + return; + + LOCK_ELUNA; + Push(bg); + Push(bgId); + Push(instanceId); + CallAllFunctions(BGEventBindings, BG_EVENT_ON_PRE_DESTROY); +} + +#endif // _BATTLEGROUND_HOOKS_H \ No newline at end of file diff --git a/CreatureHooks.cpp b/CreatureHooks.cpp new file mode 100644 index 0000000..5431e96 --- /dev/null +++ b/CreatureHooks.cpp @@ -0,0 +1,486 @@ +/* + * Copyright (C) 2010 - 2015 Eluna Lua Engine + * This program is free software licensed under GPL version 3 + * Please see the included DOCS/LICENSE.md for more information + */ + +#ifndef _CREATURE_HOOKS_H +#define _CREATURE_HOOKS_H + +#include "Hooks.h" +#include "HookHelpers.h" +#include "LuaEngine.h" +#include "ElunaBinding.h" +#include "ElunaIncludes.h" + +using namespace Hooks; + +bool Eluna::OnDummyEffect(Unit* pCaster, uint32 spellId, SpellEffIndex effIndex, Creature* pTarget) +{ + 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; + + LOCK_ELUNA; + Push(pCaster); + Push(spellId); + Push(effIndex); + Push(pTarget); + return CallAllFunctionsBool(CreatureEventBindings, CreatureUniqueBindings, CREATURE_EVENT_ON_DUMMY_EFFECT, pTarget->GetEntry(), pTarget->GET_GUID(), pTarget->GetInstanceId()); +} + +bool Eluna::OnGossipHello(Player* pPlayer, Creature* pCreature) +{ + if (!CreatureGossipBindings->HasEvents(GOSSIP_EVENT_ON_HELLO, pCreature->GetEntry())) + return false; + + LOCK_ELUNA; + pPlayer->PlayerTalkClass->ClearMenus(); + Push(pPlayer); + Push(pCreature); + return CallAllFunctionsBool(CreatureGossipBindings, GOSSIP_EVENT_ON_HELLO, pCreature->GetEntry(), true); +} + +bool Eluna::OnGossipSelect(Player* pPlayer, Creature* pCreature, uint32 sender, uint32 action) +{ + if (!CreatureGossipBindings->HasEvents(GOSSIP_EVENT_ON_SELECT, pCreature->GetEntry())) + return false; + + LOCK_ELUNA; + pPlayer->PlayerTalkClass->ClearMenus(); + Push(pPlayer); + Push(pCreature); + Push(sender); + Push(action); + return CallAllFunctionsBool(CreatureGossipBindings, GOSSIP_EVENT_ON_SELECT, pCreature->GetEntry(), true); +} + +bool Eluna::OnGossipSelectCode(Player* pPlayer, Creature* pCreature, uint32 sender, uint32 action, const char* code) +{ + if (!CreatureGossipBindings->HasEvents(GOSSIP_EVENT_ON_SELECT, pCreature->GetEntry())) + return false; + + LOCK_ELUNA; + pPlayer->PlayerTalkClass->ClearMenus(); + Push(pPlayer); + Push(pCreature); + Push(sender); + Push(action); + Push(code); + return CallAllFunctionsBool(CreatureGossipBindings, GOSSIP_EVENT_ON_SELECT, pCreature->GetEntry(), true); +} + +bool Eluna::OnQuestAccept(Player* pPlayer, Creature* pCreature, Quest const* pQuest) +{ + 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; + + LOCK_ELUNA; + Push(pPlayer); + Push(pCreature); + Push(pQuest); + 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())) + 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, 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())) + 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, 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())) + if (!CreatureUniqueBindings->HasEvents(CREATURE_EVENT_ON_ADD, creature->GET_GUID(), creature->GetInstanceId())) + return; + + LOCK_ELUNA; + Push(creature); + 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())) + if (!CreatureUniqueBindings->HasEvents(CREATURE_EVENT_ON_REMOVE, creature->GET_GUID(), creature->GetInstanceId())) + return; + + LOCK_ELUNA; + Push(creature); + 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())) + if (!CreatureUniqueBindings->HasEvents(CREATURE_EVENT_ON_SUMMONED, pCreature->GET_GUID(), pCreature->GetInstanceId())) + return false; + + LOCK_ELUNA; + Push(pCreature); + Push(pSummoner); + 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())) + if (!CreatureUniqueBindings->HasEvents(CREATURE_EVENT_ON_AIUPDATE, me->GET_GUID(), me->GetInstanceId())) + return false; + + LOCK_ELUNA; + Push(me); + Push(diff); + 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 at creature aggro either by MoveInLOS or Attack Start +bool Eluna::EnterCombat(Creature* me, Unit* target) +{ + 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; + + LOCK_ELUNA; + Push(me); + Push(target); + 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())) + if (!CreatureUniqueBindings->HasEvents(CREATURE_EVENT_ON_DAMAGE_TAKEN, me->GET_GUID(), me->GetInstanceId())) + return false; + + LOCK_ELUNA; + bool result = false; + Push(me); + Push(attacker); + Push(damage); + int damageIndex = lua_gettop(L); + int n = SetupStack(CreatureEventBindings, CreatureUniqueBindings, CREATURE_EVENT_ON_DAMAGE_TAKEN, me->GetEntry(), me->GET_GUID(), me->GetInstanceId(), 3); + + while (n > 0) + { + int r = CallOneFunction(n--, 3, 2); + + if (lua_isboolean(L, r + 0) && lua_toboolean(L, r + 0)) + result = true; + + if (lua_isnumber(L, r + 1)) + { + damage = Eluna::CHECKVAL(L, r + 1); + // Update the stack for subsequent calls. + ReplaceArgument(damage, damageIndex); + } + + lua_pop(L, 2); + } + + CleanUpStack(3); + return result; +} + +//Called at creature death +bool Eluna::JustDied(Creature* me, Unit* killer) +{ + On_Reset(me); + + if (!CreatureEventBindings->HasEvents(CREATURE_EVENT_ON_DIED, me->GetEntry())) + if (!CreatureUniqueBindings->HasEvents(CREATURE_EVENT_ON_DIED, me->GET_GUID(), me->GetInstanceId())) + return false; + + LOCK_ELUNA; + Push(me); + Push(killer); + 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())) + if (!CreatureUniqueBindings->HasEvents(CREATURE_EVENT_ON_TARGET_DIED, me->GET_GUID(), me->GetInstanceId())) + return false; + + LOCK_ELUNA; + Push(me); + Push(victim); + 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())) + 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, 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())) + 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, 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())) + 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, 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())) + if (!CreatureUniqueBindings->HasEvents(CREATURE_EVENT_ON_PRE_COMBAT, me->GET_GUID(), me->GetInstanceId())) + return false; + + LOCK_ELUNA; + Push(me); + Push(target); + 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 +bool Eluna::EnterEvadeMode(Creature* me) +{ + On_Reset(me); + + 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; + + LOCK_ELUNA; + Push(me); + 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())) + if (!CreatureUniqueBindings->HasEvents(CREATURE_EVENT_ON_ATTACKED_AT, me->GET_GUID(), me->GetInstanceId())) + return false; + + LOCK_ELUNA; + Push(me); + Push(attacker); + 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) +bool Eluna::JustRespawned(Creature* me) +{ + On_Reset(me); + + if (!CreatureEventBindings->HasEvents(CREATURE_EVENT_ON_SPAWN, me->GetEntry())) + if (!CreatureUniqueBindings->HasEvents(CREATURE_EVENT_ON_SPAWN, me->GET_GUID(), me->GetInstanceId())) + return false; + + LOCK_ELUNA; + Push(me); + 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())) + if (!CreatureUniqueBindings->HasEvents(CREATURE_EVENT_ON_REACH_HOME, me->GET_GUID(), me->GetInstanceId())) + return false; + + LOCK_ELUNA; + Push(me); + 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())) + 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, 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())) + 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, CreatureUniqueBindings, CREATURE_EVENT_ON_CORPSE_REMOVED, me->GetEntry(), me->GET_GUID(), me->GetInstanceId(), 2); + + while (n > 0) + { + int r = CallOneFunction(n--, 2, 2); + + if (lua_isboolean(L, r + 0) && lua_toboolean(L, r + 0)) + result = true; + + if (lua_isnumber(L, r + 1)) + { + respawnDelay = Eluna::CHECKVAL(L, r + 1); + // Update the stack for subsequent calls. + ReplaceArgument(respawnDelay, respawnDelayIndex); + } + + lua_pop(L, 2); + } + + CleanUpStack(2); + return result; +} + +bool Eluna::MoveInLineOfSight(Creature* me, Unit* who) +{ + 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; + + LOCK_ELUNA; + Push(me); + Push(who); + 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())) + if (!CreatureUniqueBindings->HasEvents(CREATURE_EVENT_ON_RESET, me->GET_GUID(), me->GetInstanceId())) + return; + + LOCK_ELUNA; + Push(me); + 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())) + 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, 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())) + 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, CreatureUniqueBindings, CREATURE_EVENT_ON_SPELL_HIT_TARGET, me->GetEntry(), me->GET_GUID(), me->GetInstanceId()); +} + +#ifdef TRINITY + +bool Eluna::SummonedCreatureDies(Creature* me, Creature* summon, Unit* killer) +{ + 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; + + LOCK_ELUNA; + Push(me); + Push(summon); + Push(killer); + 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())) + 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, 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())) + if (!CreatureUniqueBindings->HasEvents(CREATURE_EVENT_ON_OWNER_ATTACKED, me->GET_GUID(), me->GetInstanceId())) + return false; + + LOCK_ELUNA; + Push(me); + Push(target); + return CallAllFunctionsBool(CreatureEventBindings, CreatureUniqueBindings, CREATURE_EVENT_ON_OWNER_ATTACKED, me->GetEntry(), me->GET_GUID(), me->GetInstanceId()); +} + +#endif // TRINITY +#endif // _CREATURE_HOOKS_H \ No newline at end of file diff --git a/GameObjectHooks.cpp b/GameObjectHooks.cpp new file mode 100644 index 0000000..b62f6ab --- /dev/null +++ b/GameObjectHooks.cpp @@ -0,0 +1,211 @@ +/* + * Copyright (C) 2010 - 2015 Eluna Lua Engine + * This program is free software licensed under GPL version 3 + * Please see the included DOCS/LICENSE.md for more information + */ + +#ifndef _GAMEOBJECT_HOOKS_H +#define _GAMEOBJECT_HOOKS_H + +#include "Hooks.h" +#include "HookHelpers.h" +#include "LuaEngine.h" +#include "ElunaBinding.h" +#include "ElunaIncludes.h" +#include "ElunaEventMgr.h" + +using namespace Hooks; + +bool Eluna::OnDummyEffect(Unit* pCaster, uint32 spellId, SpellEffIndex effIndex, GameObject* pTarget) +{ + if (!GameObjectEventBindings->HasEvents(GAMEOBJECT_EVENT_ON_DUMMY_EFFECT, pTarget->GetEntry())) + return false; + + LOCK_ELUNA; + Push(pCaster); + Push(spellId); + Push(effIndex); + Push(pTarget); + return CallAllFunctionsBool(GameObjectEventBindings, GAMEOBJECT_EVENT_ON_DUMMY_EFFECT, pTarget->GetEntry()); +} + +bool Eluna::OnGossipHello(Player* pPlayer, GameObject* pGameObject) +{ + if (!GameObjectGossipBindings->HasEvents(GOSSIP_EVENT_ON_HELLO, pGameObject->GetEntry())) + return false; + + LOCK_ELUNA; + pPlayer->PlayerTalkClass->ClearMenus(); + Push(pPlayer); + Push(pGameObject); + return CallAllFunctionsBool(GameObjectGossipBindings, GOSSIP_EVENT_ON_HELLO, pGameObject->GetEntry(), true); +} + +bool Eluna::OnGossipSelect(Player* pPlayer, GameObject* pGameObject, uint32 sender, uint32 action) +{ + if (!GameObjectGossipBindings->HasEvents(GOSSIP_EVENT_ON_SELECT, pGameObject->GetEntry())) + return false; + + LOCK_ELUNA; + pPlayer->PlayerTalkClass->ClearMenus(); + Push(pPlayer); + Push(pGameObject); + Push(sender); + Push(action); + return CallAllFunctionsBool(GameObjectGossipBindings, GOSSIP_EVENT_ON_SELECT, pGameObject->GetEntry(), true); +} + +bool Eluna::OnGossipSelectCode(Player* pPlayer, GameObject* pGameObject, uint32 sender, uint32 action, const char* code) +{ + if (!GameObjectGossipBindings->HasEvents(GOSSIP_EVENT_ON_SELECT, pGameObject->GetEntry())) + return false; + + LOCK_ELUNA; + pPlayer->PlayerTalkClass->ClearMenus(); + Push(pPlayer); + Push(pGameObject); + Push(sender); + Push(action); + Push(code); + return CallAllFunctionsBool(GameObjectGossipBindings, GOSSIP_EVENT_ON_SELECT, pGameObject->GetEntry(), true); +} + +bool Eluna::OnQuestAccept(Player* pPlayer, GameObject* pGameObject, Quest const* pQuest) +{ + if (!GameObjectEventBindings->HasEvents(GAMEOBJECT_EVENT_ON_QUEST_ACCEPT, pGameObject->GetEntry())) + return false; + + LOCK_ELUNA; + Push(pPlayer); + Push(pGameObject); + Push(pQuest); + return CallAllFunctionsBool(GameObjectEventBindings, GAMEOBJECT_EVENT_ON_QUEST_ACCEPT, pGameObject->GetEntry()); +} + +void Eluna::UpdateAI(GameObject* pGameObject, uint32 diff) +{ + if (!GameObjectEventBindings->HasEvents(GAMEOBJECT_EVENT_ON_AIUPDATE, pGameObject->GetEntry())) + return; + + LOCK_ELUNA; + pGameObject->elunaEvents->Update(diff); + Push(pGameObject); + Push(diff); + CallAllFunctions(GameObjectEventBindings, GAMEOBJECT_EVENT_ON_AIUPDATE, pGameObject->GetEntry()); +} + +bool Eluna::OnQuestReward(Player* pPlayer, GameObject* pGameObject, Quest const* pQuest, uint32 opt) +{ + if (!GameObjectEventBindings->HasEvents(GAMEOBJECT_EVENT_ON_QUEST_REWARD, pGameObject->GetEntry())) + return false; + + LOCK_ELUNA; + Push(pPlayer); + Push(pGameObject); + Push(pQuest); + Push(opt); + return CallAllFunctionsBool(GameObjectEventBindings, GAMEOBJECT_EVENT_ON_QUEST_REWARD, pGameObject->GetEntry()); +} + +uint32 Eluna::GetDialogStatus(Player* pPlayer, GameObject* pGameObject) +{ + if (!GameObjectEventBindings->HasEvents(GAMEOBJECT_EVENT_ON_DIALOG_STATUS, pGameObject->GetEntry())) + return DIALOG_STATUS_SCRIPTED_NO_STATUS; + + LOCK_ELUNA; + Push(pPlayer); + Push(pGameObject); + CallAllFunctions(GameObjectEventBindings, GAMEOBJECT_EVENT_ON_DIALOG_STATUS, pGameObject->GetEntry()); + return DIALOG_STATUS_SCRIPTED_NO_STATUS; // DIALOG_STATUS_UNDEFINED +} + +#ifndef CLASSIC +#ifndef TBC +void Eluna::OnDestroyed(GameObject* pGameObject, Player* pPlayer) +{ + if (!GameObjectEventBindings->HasEvents(GAMEOBJECT_EVENT_ON_DESTROYED, pGameObject->GetEntry())) + return; + + LOCK_ELUNA; + Push(pGameObject); + Push(pPlayer); + CallAllFunctions(GameObjectEventBindings, GAMEOBJECT_EVENT_ON_DESTROYED, pGameObject->GetEntry()); +} + +void Eluna::OnDamaged(GameObject* pGameObject, Player* pPlayer) +{ + if (!GameObjectEventBindings->HasEvents(GAMEOBJECT_EVENT_ON_DAMAGED, pGameObject->GetEntry())) + return; + + LOCK_ELUNA; + Push(pGameObject); + Push(pPlayer); + CallAllFunctions(GameObjectEventBindings, GAMEOBJECT_EVENT_ON_DAMAGED, pGameObject->GetEntry()); +} +#endif +#endif + +void Eluna::OnLootStateChanged(GameObject* pGameObject, uint32 state) +{ + if (!GameObjectEventBindings->HasEvents(GAMEOBJECT_EVENT_ON_LOOT_STATE_CHANGE, pGameObject->GetEntry())) + return; + + LOCK_ELUNA; + Push(pGameObject); + Push(state); + CallAllFunctions(GameObjectEventBindings, GAMEOBJECT_EVENT_ON_LOOT_STATE_CHANGE, pGameObject->GetEntry()); +} + +void Eluna::OnGameObjectStateChanged(GameObject* pGameObject, uint32 state) +{ + if (!GameObjectEventBindings->HasEvents(GAMEOBJECT_EVENT_ON_GO_STATE_CHANGED, pGameObject->GetEntry())) + return; + + LOCK_ELUNA; + Push(pGameObject); + Push(state); + CallAllFunctions(GameObjectEventBindings, GAMEOBJECT_EVENT_ON_GO_STATE_CHANGED, pGameObject->GetEntry()); +} + +void Eluna::OnSpawn(GameObject* gameobject) +{ + if (!GameObjectEventBindings->HasEvents(GAMEOBJECT_EVENT_ON_SPAWN, gameobject->GetEntry())) + return; + + LOCK_ELUNA; + Push(gameobject); + CallAllFunctions(GameObjectEventBindings, GAMEOBJECT_EVENT_ON_SPAWN, gameobject->GetEntry()); +} + +void Eluna::OnAddToWorld(GameObject* gameobject) +{ + if (!GameObjectEventBindings->HasEvents(GAMEOBJECT_EVENT_ON_ADD, gameobject->GetEntry())) + return; + + LOCK_ELUNA; + Push(gameobject); + CallAllFunctions(GameObjectEventBindings, GAMEOBJECT_EVENT_ON_ADD, gameobject->GetEntry()); +} + +void Eluna::OnRemoveFromWorld(GameObject* gameobject) +{ + if (!GameObjectEventBindings->HasEvents(GAMEOBJECT_EVENT_ON_REMOVE, gameobject->GetEntry())) + return; + + LOCK_ELUNA; + Push(gameobject); + CallAllFunctions(GameObjectEventBindings, GAMEOBJECT_EVENT_ON_REMOVE, gameobject->GetEntry()); +} + +bool Eluna::OnGameObjectUse(Player* pPlayer, GameObject* pGameObject) +{ + if (!GameObjectEventBindings->HasEvents(GAMEOBJECT_EVENT_ON_USE, pGameObject->GetEntry())) + return false; + + LOCK_ELUNA; + Push(pGameObject); + Push(pPlayer); + return CallAllFunctionsBool(GameObjectEventBindings, GAMEOBJECT_EVENT_ON_USE, pGameObject->GetEntry()); +} + +#endif // _GAMEOBJECT_HOOKS_H \ No newline at end of file diff --git a/GlobalMethods.h b/GlobalMethods.h index 8f30903..f6b940e 100644 --- a/GlobalMethods.h +++ b/GlobalMethods.h @@ -593,7 +593,7 @@ namespace LuaGlobalFunctions */ int RegisterServerEvent(Eluna* E, lua_State* L) { - RegisterEventHelper(E, L, HookMgr::REGTYPE_SERVER); + RegisterEventHelper(E, L, Hooks::REGTYPE_SERVER); return 0; } @@ -658,7 +658,7 @@ namespace LuaGlobalFunctions */ int RegisterPlayerEvent(Eluna* E, lua_State* L) { - RegisterEventHelper(E, L, HookMgr::REGTYPE_PLAYER); + RegisterEventHelper(E, L, Hooks::REGTYPE_PLAYER); return 0; } @@ -691,7 +691,7 @@ namespace LuaGlobalFunctions */ int RegisterGuildEvent(Eluna* E, lua_State* L) { - RegisterEventHelper(E, L, HookMgr::REGTYPE_GUILD); + RegisterEventHelper(E, L, Hooks::REGTYPE_GUILD); return 0; } @@ -719,7 +719,7 @@ namespace LuaGlobalFunctions */ int RegisterGroupEvent(Eluna* E, lua_State* L) { - RegisterEventHelper(E, L, HookMgr::REGTYPE_GROUP); + RegisterEventHelper(E, L, Hooks::REGTYPE_GROUP); return 0; } @@ -743,7 +743,7 @@ namespace LuaGlobalFunctions */ int RegisterBGEvent(Eluna* E, lua_State* L) { - RegisterEventHelper(E, L, HookMgr::REGTYPE_BG); + RegisterEventHelper(E, L, Hooks::REGTYPE_BG); return 0; } @@ -768,7 +768,7 @@ namespace LuaGlobalFunctions */ int RegisterPacketEvent(Eluna* E, lua_State* L) { - RegisterEntryHelper(E, L, HookMgr::REGTYPE_PACKET); + RegisterEntryHelper(E, L, Hooks::REGTYPE_PACKET); return 0; } @@ -791,7 +791,7 @@ namespace LuaGlobalFunctions */ int RegisterCreatureGossipEvent(Eluna* E, lua_State* L) { - RegisterEntryHelper(E, L, HookMgr::REGTYPE_CREATURE_GOSSIP); + RegisterEntryHelper(E, L, Hooks::REGTYPE_CREATURE_GOSSIP); return 0; } @@ -814,7 +814,7 @@ namespace LuaGlobalFunctions */ int RegisterGameObjectGossipEvent(Eluna* E, lua_State* L) { - RegisterEntryHelper(E, L, HookMgr::REGTYPE_GAMEOBJECT_GOSSIP); + RegisterEntryHelper(E, L, Hooks::REGTYPE_GAMEOBJECT_GOSSIP); return 0; } @@ -840,7 +840,7 @@ namespace LuaGlobalFunctions */ int RegisterItemEvent(Eluna* E, lua_State* L) { - RegisterEntryHelper(E, L, HookMgr::REGTYPE_ITEM); + RegisterEntryHelper(E, L, Hooks::REGTYPE_ITEM); return 0; } @@ -863,7 +863,7 @@ namespace LuaGlobalFunctions */ int RegisterItemGossipEvent(Eluna* E, lua_State* L) { - RegisterEntryHelper(E, L, HookMgr::REGTYPE_ITEM_GOSSIP); + RegisterEntryHelper(E, L, Hooks::REGTYPE_ITEM_GOSSIP); return 0; } @@ -886,7 +886,7 @@ namespace LuaGlobalFunctions */ int RegisterPlayerGossipEvent(Eluna* E, lua_State* L) { - RegisterEntryHelper(E, L, HookMgr::REGTYPE_PLAYER_GOSSIP); + RegisterEntryHelper(E, L, Hooks::REGTYPE_PLAYER_GOSSIP); return 0; } @@ -944,7 +944,7 @@ namespace LuaGlobalFunctions */ int RegisterCreatureEvent(Eluna* E, lua_State* L) { - RegisterEntryHelper(E, L, HookMgr::REGTYPE_CREATURE); + RegisterEntryHelper(E, L, Hooks::REGTYPE_CREATURE); return 0; } @@ -1003,7 +1003,7 @@ namespace LuaGlobalFunctions */ int RegisterUniqueCreatureEvent(Eluna* E, lua_State* L) { - RegisterUniqueHelper(E, L, HookMgr::REGTYPE_CREATURE); + RegisterUniqueHelper(E, L, Hooks::REGTYPE_CREATURE); return 0; } @@ -1037,7 +1037,7 @@ namespace LuaGlobalFunctions */ int RegisterGameObjectEvent(Eluna* E, lua_State* L) { - RegisterEntryHelper(E, L, HookMgr::REGTYPE_GAMEOBJECT); + RegisterEntryHelper(E, L, Hooks::REGTYPE_GAMEOBJECT); return 0; } diff --git a/GroupHooks.cpp b/GroupHooks.cpp new file mode 100644 index 0000000..6d26f9c --- /dev/null +++ b/GroupHooks.cpp @@ -0,0 +1,85 @@ +/* + * Copyright (C) 2010 - 2015 Eluna Lua Engine + * This program is free software licensed under GPL version 3 + * Please see the included DOCS/LICENSE.md for more information + */ + +#ifndef _GROUP_HOOKS_H +#define _GROUP_HOOKS_H + +#include "Hooks.h" +#include "HookHelpers.h" +#include "LuaEngine.h" +#include "ElunaBinding.h" + +using namespace Hooks; + +void Eluna::OnAddMember(Group* group, uint64 guid) +{ + if (!GroupEventBindings->HasEvents(GROUP_EVENT_ON_MEMBER_ADD)) + return; + + LOCK_ELUNA; + Push(group); + Push(guid); + CallAllFunctions(GroupEventBindings, GROUP_EVENT_ON_MEMBER_ADD); +} + +void Eluna::OnInviteMember(Group* group, uint64 guid) +{ + if (!GroupEventBindings->HasEvents(GROUP_EVENT_ON_MEMBER_INVITE)) + return; + + LOCK_ELUNA; + Push(group); + Push(guid); + CallAllFunctions(GroupEventBindings, GROUP_EVENT_ON_MEMBER_INVITE); +} + +void Eluna::OnRemoveMember(Group* group, uint64 guid, uint8 method) +{ + if (!GroupEventBindings->HasEvents(GROUP_EVENT_ON_MEMBER_REMOVE)) + return; + + LOCK_ELUNA; + Push(group); + Push(guid); + Push(method); + CallAllFunctions(GroupEventBindings, GROUP_EVENT_ON_MEMBER_REMOVE); +} + +void Eluna::OnChangeLeader(Group* group, uint64 newLeaderGuid, uint64 oldLeaderGuid) +{ + if (!GroupEventBindings->HasEvents(GROUP_EVENT_ON_LEADER_CHANGE)) + return; + + LOCK_ELUNA; + Push(group); + Push(newLeaderGuid); + Push(oldLeaderGuid); + CallAllFunctions(GroupEventBindings, GROUP_EVENT_ON_LEADER_CHANGE); +} + +void Eluna::OnDisband(Group* group) +{ + if (!GroupEventBindings->HasEvents(GROUP_EVENT_ON_DISBAND)) + return; + + LOCK_ELUNA; + Push(group); + CallAllFunctions(GroupEventBindings, GROUP_EVENT_ON_DISBAND); +} + +void Eluna::OnCreate(Group* group, uint64 leaderGuid, GroupType groupType) +{ + if (!GroupEventBindings->HasEvents(GROUP_EVENT_ON_CREATE)) + return; + + LOCK_ELUNA; + Push(group); + Push(leaderGuid); + Push(groupType); + CallAllFunctions(GroupEventBindings, GROUP_EVENT_ON_CREATE); +} + +#endif // _GROUP_HOOKS_H \ No newline at end of file diff --git a/GuildHooks.cpp b/GuildHooks.cpp new file mode 100644 index 0000000..b34f78c --- /dev/null +++ b/GuildHooks.cpp @@ -0,0 +1,193 @@ +/* + * Copyright (C) 2010 - 2015 Eluna Lua Engine + * This program is free software licensed under GPL version 3 + * Please see the included DOCS/LICENSE.md for more information + */ + +#ifndef _GUILD_HOOKS_H +#define _GUILD_HOOKS_H + +#include "Hooks.h" +#include "HookHelpers.h" +#include "LuaEngine.h" +#include "ElunaBinding.h" + +using namespace Hooks; + +void Eluna::OnAddMember(Guild* guild, Player* player, uint32 plRank) +{ + if (!GuildEventBindings->HasEvents(GUILD_EVENT_ON_ADD_MEMBER)) + return; + + LOCK_ELUNA; + Push(guild); + Push(player); + Push(plRank); + CallAllFunctions(GuildEventBindings, GUILD_EVENT_ON_ADD_MEMBER); +} + +void Eluna::OnRemoveMember(Guild* guild, Player* player, bool isDisbanding) +{ + if (!GuildEventBindings->HasEvents(GUILD_EVENT_ON_REMOVE_MEMBER)) + return; + + LOCK_ELUNA; + Push(guild); + Push(player); + Push(isDisbanding); + CallAllFunctions(GuildEventBindings, GUILD_EVENT_ON_REMOVE_MEMBER); +} + +void Eluna::OnMOTDChanged(Guild* guild, const std::string& newMotd) +{ + if (!GuildEventBindings->HasEvents(GUILD_EVENT_ON_MOTD_CHANGE)) + return; + + LOCK_ELUNA; + Push(guild); + Push(newMotd); + CallAllFunctions(GuildEventBindings, GUILD_EVENT_ON_MOTD_CHANGE); +} + +void Eluna::OnInfoChanged(Guild* guild, const std::string& newInfo) +{ + if (!GuildEventBindings->HasEvents(GUILD_EVENT_ON_INFO_CHANGE)) + return; + + LOCK_ELUNA; + Push(guild); + Push(newInfo); + CallAllFunctions(GuildEventBindings, GUILD_EVENT_ON_INFO_CHANGE); +} + +void Eluna::OnCreate(Guild* guild, Player* leader, const std::string& name) +{ + if (!GuildEventBindings->HasEvents(GUILD_EVENT_ON_CREATE)) + return; + + LOCK_ELUNA; + Push(guild); + Push(leader); + Push(name); + CallAllFunctions(GuildEventBindings, GUILD_EVENT_ON_CREATE); +} + +void Eluna::OnDisband(Guild* guild) +{ + if (!GuildEventBindings->HasEvents(GUILD_EVENT_ON_DISBAND)) + return; + + LOCK_ELUNA; + Push(guild); + CallAllFunctions(GuildEventBindings, GUILD_EVENT_ON_DISBAND); +} + +void Eluna::OnMemberWitdrawMoney(Guild* guild, Player* player, uint32& amount, bool isRepair) // isRepair not a part of Mangos, implement? +{ + if (!GuildEventBindings->HasEvents(GUILD_EVENT_ON_MONEY_WITHDRAW)) + return; + + LOCK_ELUNA; + Push(guild); + Push(player); + Push(amount); + Push(isRepair); // isRepair not a part of Mangos, implement? + int amountIndex = lua_gettop(L) - 1; + int n = SetupStack(GuildEventBindings, GUILD_EVENT_ON_MONEY_WITHDRAW, 4); + + while (n > 0) + { + int r = CallOneFunction(n--, 4, 1); + + if (lua_isnumber(L, r)) + { + amount = CHECKVAL(L, r); + // Update the stack for subsequent calls. + ReplaceArgument(amount, amountIndex); + } + + lua_pop(L, 1); + } + + CleanUpStack(4); +} + +void Eluna::OnMemberDepositMoney(Guild* guild, Player* player, uint32& amount) +{ + if (!GuildEventBindings->HasEvents(GUILD_EVENT_ON_MONEY_DEPOSIT)) + return; + + LOCK_ELUNA; + Push(guild); + Push(player); + Push(amount); + int amountIndex = lua_gettop(L); + int n = SetupStack(GuildEventBindings, GUILD_EVENT_ON_MONEY_DEPOSIT, 3); + + while (n > 0) + { + int r = CallOneFunction(n--, 3, 1); + + if (lua_isnumber(L, r)) + { + amount = CHECKVAL(L, r); + // Update the stack for subsequent calls. + ReplaceArgument(amount, amountIndex); + } + + lua_pop(L, 1); + } + + CleanUpStack(3); +} + +void Eluna::OnItemMove(Guild* guild, Player* player, Item* pItem, bool isSrcBank, uint8 srcContainer, uint8 srcSlotId, + bool isDestBank, uint8 destContainer, uint8 destSlotId) +{ + if (!GuildEventBindings->HasEvents(GUILD_EVENT_ON_ITEM_MOVE)) + return; + + LOCK_ELUNA; + Push(guild); + Push(player); + Push(pItem); + Push(isSrcBank); + Push(srcContainer); + Push(srcSlotId); + Push(isDestBank); + Push(destContainer); + Push(destSlotId); + CallAllFunctions(GuildEventBindings, GUILD_EVENT_ON_ITEM_MOVE); +} + +void Eluna::OnEvent(Guild* guild, uint8 eventType, uint32 playerGuid1, uint32 playerGuid2, uint8 newRank) +{ + if (!GuildEventBindings->HasEvents(GUILD_EVENT_ON_EVENT)) + return; + + LOCK_ELUNA; + Push(guild); + Push(eventType); + Push(playerGuid1); + Push(playerGuid2); + Push(newRank); + CallAllFunctions(GuildEventBindings, GUILD_EVENT_ON_EVENT); +} + +void Eluna::OnBankEvent(Guild* guild, uint8 eventType, uint8 tabId, uint32 playerGuid, uint32 itemOrMoney, uint16 itemStackCount, uint8 destTabId) +{ + if (!GuildEventBindings->HasEvents(GUILD_EVENT_ON_BANK_EVENT)) + return; + + LOCK_ELUNA; + Push(guild); + Push(eventType); + Push(tabId); + Push(playerGuid); + Push(itemOrMoney); + Push(itemStackCount); + Push(destTabId); + CallAllFunctions(GuildEventBindings, GUILD_EVENT_ON_BANK_EVENT); +} + +#endif // _GUILD_HOOKS_H \ No newline at end of file diff --git a/HookHelpers.h b/HookHelpers.h new file mode 100644 index 0000000..6ff54a9 --- /dev/null +++ b/HookHelpers.h @@ -0,0 +1,129 @@ +/* + * Copyright (C) 2010 - 2015 Eluna Lua Engine + * This program is free software licensed under GPL version 3 + * Please see the included DOCS/LICENSE.md for more information + */ + +#ifndef _HOOK_HELPERS_H +#define _HOOK_HELPERS_H + +#include "LuaEngine.h" +#include "ElunaUtility.h" + +/* + * Sets up the stack so that event handlers can be called. + * + * Returns the number of functions that were pushed onto the stack. + * + * 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, 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)); + ASSERT(number_of_arguments == this->push_counter); + // Stack: [arguments] + + Push(event_id); + this->push_counter = 0; + ++number_of_arguments; + // Stack: [arguments], event_id + + int arguments_top = lua_gettop(L); + int first_argument_index = arguments_top - number_of_arguments + 1; + ASSERT(arguments_top >= number_of_arguments); + + lua_insert(L, first_argument_index); + // Stack: event_id, [arguments] + + if (event_bindings) + event_bindings->PushFuncRefs(L, (int)event_id); + + 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; + return number_of_functions; +} + +/* + * Replace one of the arguments pushed before `SetupStack` with a new value. + */ +template +void Eluna::ReplaceArgument(T value, uint8 index) +{ + ASSERT(index < lua_gettop(L) && index > 0); + // Stack: event_id, [arguments], [functions], [results] + + Eluna::Push(L, value); + // Stack: event_id, [arguments], [functions], [results], value + + lua_replace(L, index + 1); + // Stack: event_id, [arguments and value], [functions], [results] +} + +/* + * 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, 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, guid_bindings, event_id, entry, guid, instanceId, number_of_arguments); + // Stack: event_id, [arguments], [functions] + + while (number_of_functions > 0) + { + CallOneFunction(number_of_functions, number_of_arguments, 0); + --number_of_functions; + // Stack: event_id, [arguments], [functions - 1] + } + // Stack: event_id, [arguments] + + CleanUpStack(number_of_arguments); + // Stack: (empty) +} + +/* + * Call all event handlers registered to the event ID/entry combination, + * and returns `default_value` if ALL event handlers returned `default_value`, + * otherwise returns the opposite of `default_value`. + */ +template +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, guid_bindings, event_id, entry, guid, instanceId, number_of_arguments); + // Stack: event_id, [arguments], [functions] + + while (number_of_functions > 0) + { + int r = CallOneFunction(number_of_functions, number_of_arguments, 1); + --number_of_functions; + // Stack: event_id, [arguments], [functions - 1], result + + if (lua_isboolean(L, r) && (lua_toboolean(L, r) == 1) != default_value) + result = !default_value; + + lua_pop(L, 1); + // Stack: event_id, [arguments], [functions - 1] + } + // Stack: event_id, [arguments] + + CleanUpStack(number_of_arguments); + // Stack: (empty) + return result; +} + +#endif // _HOOK_HELPERS_H \ No newline at end of file diff --git a/HookMgr.cpp b/HookMgr.cpp deleted file mode 100644 index 4d0cfc0..0000000 --- a/HookMgr.cpp +++ /dev/null @@ -1,2446 +0,0 @@ -/* - * Copyright (C) 2010 - 2015 Eluna Lua Engine - * This program is free software licensed under GPL version 3 - * Please see the included DOCS/LICENSE.md for more information - */ - -#include "HookMgr.h" -#include "LuaEngine.h" -#include "ElunaBinding.h" -#include "ElunaEventMgr.h" -#include "ElunaIncludes.h" -#include "ElunaTemplate.h" -#include "ElunaCreatureAI.h" - -extern "C" -{ -#include "lua.h" -#include "lualib.h" -#include "lauxlib.h" -}; - -using namespace HookMgr; - -/* - * A hook should be written in one of the following forms: - * - * A. If results will be IGNORED: - * - * // Return early if there are no bindings. - * if (!WhateverBindings->HasEvents(SOME_EVENT_TYPE)) - * return; - * - * // Lock out any other threads. - * LOCK_ELUNA; - * - * // Push extra arguments, if any. - * Push(a); - * Push(b); - * Push(c); - * - * // Call all event handlers. - * CallAllFunctions(WhateverBindings, SOME_EVENT_TYPE); - * - * - * B. If results will be USED: - * - * // Return early if there are no bindings. - * if (!WhateverBindings->HasEvents(SOME_EVENT_TYPE)) - * return; - * - * // Lock out any other threads. - * LOCK_ELUNA; - * - * // Push extra arguments, if any. - * Push(a); - * Push(b); - * Push(c); - * - * // Setup the stack and get the number of functions pushed. - * // Last argument is 3 because we did 3 Pushes. - * int n = SetupStack(WhateverBindings, SOME_EVENT_TYPE, 3); - * - * // Call each event handler in order and check results. - * while (n > 0) - * { - * // Call an event handler and decrement the function counter afterward. - * // Second-last argument is 3 because we did 3 Pushes. - * // Last argument is 2 because we want 2 results. - * int r = CallOneFunction(n--, 3, 2); - * - * // Results can be popped using `r`. - * int first = CHECKVAL(L, r + 0); - * int second = CHECKVAL(L, r + 1); - * - * // Pop the results off the stack. - * lua_pop(L, 2); - * } - * - * // Clean-up the stack. Argument is 3 because we did 3 Pushes. - * CleanUpStack(3); - */ - -/* - * Sets up the stack so that event handlers can be called. - * - * Returns the number of functions that were pushed onto the stack. - * - * 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, 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)); - ASSERT(number_of_arguments == this->push_counter); - // Stack: [arguments] - - Push(event_id); - this->push_counter = 0; - ++number_of_arguments; - // Stack: [arguments], event_id - - int arguments_top = lua_gettop(L); - int first_argument_index = arguments_top - number_of_arguments + 1; - ASSERT(arguments_top >= number_of_arguments); - - lua_insert(L, first_argument_index); - // Stack: event_id, [arguments] - - if (event_bindings) - event_bindings->PushFuncRefs(L, (int)event_id); - - 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; - return number_of_functions; -} - -/* - * Replace one of the arguments pushed before `SetupStack` with a new value. - */ -template -void Eluna::ReplaceArgument(T value, uint8 index) -{ - ASSERT(index < lua_gettop(L) && index > 0); - // Stack: event_id, [arguments], [functions], [results] - - Eluna::Push(L, value); - // Stack: event_id, [arguments], [functions], [results], value - - lua_replace(L, index + 1); - // Stack: event_id, [arguments and value], [functions], [results] -} - -/* - * Call a single event handler that was put on the stack with `Setup` and removes it from the stack. - * - * The caller is responsible for keeping track of how many times this should be called. - */ -int Eluna::CallOneFunction(int number_of_functions, int number_of_arguments, int number_of_results) -{ - ++number_of_arguments; // Caller doesn't know about `event_id`. - ASSERT(number_of_functions > 0 && number_of_arguments > 0 && number_of_results >= 0); - // Stack: event_id, [arguments], [functions] - - int functions_top = lua_gettop(L); - int first_function_index = functions_top - number_of_functions + 1; - int arguments_top = first_function_index - 1; - int first_argument_index = arguments_top - number_of_arguments + 1; - - // Copy the arguments from the bottom of the stack to the top. - for (int argument_index = first_argument_index; argument_index <= arguments_top; ++argument_index) - { - lua_pushvalue(L, argument_index); - } - // Stack: event_id, [arguments], [functions], event_id, [arguments] - - ExecuteCall(number_of_arguments, number_of_results); - --functions_top; - // Stack: event_id, [arguments], [functions - 1], [results] - - return functions_top + 1; // Return the location of the first result (if any exist). -} - -/* - * Cleans up the stack, effectively undoing all Push calls and the Setup call. - */ -void Eluna::CleanUpStack(int number_of_arguments) -{ - // Stack: event_id, [arguments] - - lua_pop(L, number_of_arguments + 1); // Add 1 because the caller doesn't know about `event_id`. - // Stack: (empty) - - if (event_level == 0) - InvalidateObjects(); -} - -/* - * 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, 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, guid_bindings, event_id, entry, guid, instanceId, number_of_arguments); - // Stack: event_id, [arguments], [functions] - - while (number_of_functions > 0) - { - CallOneFunction(number_of_functions, number_of_arguments, 0); - --number_of_functions; - // Stack: event_id, [arguments], [functions - 1] - } - // Stack: event_id, [arguments] - - CleanUpStack(number_of_arguments); - // Stack: (empty) -} - -/* - * Call all event handlers registered to the event ID/entry combination, - * and returns `default_value` if ALL event handlers returned `default_value`, - * otherwise returns the opposite of `default_value`. - */ -template -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, guid_bindings, event_id, entry, guid, instanceId, number_of_arguments); - // Stack: event_id, [arguments], [functions] - - while (number_of_functions > 0) - { - int r = CallOneFunction(number_of_functions, number_of_arguments, 1); - --number_of_functions; - // Stack: event_id, [arguments], [functions - 1], result - - if (lua_isboolean(L, r) && (lua_toboolean(L, r) == 1) != default_value) - result = !default_value; - - lua_pop(L, 1); - // Stack: event_id, [arguments], [functions - 1] - } - // Stack: event_id, [arguments] - - CleanUpStack(number_of_arguments); - // Stack: (empty) - return result; -} - -void Eluna::OnLuaStateClose() -{ - if (!ServerEventBindings->HasEvents(ELUNA_EVENT_ON_LUA_STATE_CLOSE)) - return; - - LOCK_ELUNA; - CallAllFunctions(ServerEventBindings, ELUNA_EVENT_ON_LUA_STATE_CLOSE); -} - -void Eluna::OnLuaStateOpen() -{ - if (!ServerEventBindings->HasEvents(ELUNA_EVENT_ON_LUA_STATE_OPEN)) - return; - - LOCK_ELUNA; - CallAllFunctions(ServerEventBindings, ELUNA_EVENT_ON_LUA_STATE_OPEN); -} - -// areatrigger -bool Eluna::OnAreaTrigger(Player* pPlayer, AreaTriggerEntry const* pTrigger) -{ - if (!ServerEventBindings->HasEvents(TRIGGER_EVENT_ON_TRIGGER)) - return false; - - LOCK_ELUNA; - Push(pPlayer); - Push(pTrigger->id); - return CallAllFunctionsBool(ServerEventBindings, TRIGGER_EVENT_ON_TRIGGER); -} -// weather -void Eluna::OnChange(Weather* weather, uint32 zone, WeatherState state, float grade) -{ - if (!ServerEventBindings->HasEvents(WEATHER_EVENT_ON_CHANGE)) - return; - - LOCK_ELUNA; - Push(zone); - Push(state); - Push(grade); - CallAllFunctions(ServerEventBindings, WEATHER_EVENT_ON_CHANGE); -} -// Auction House -void Eluna::OnAdd(AuctionHouseObject* ah) -{ - if (!ServerEventBindings->HasEvents(AUCTION_EVENT_ON_ADD)) - return; - - LOCK_ELUNA; - Push(ah); - CallAllFunctions(ServerEventBindings, AUCTION_EVENT_ON_ADD); -} - -void Eluna::OnRemove(AuctionHouseObject* ah) -{ - if (!ServerEventBindings->HasEvents(AUCTION_EVENT_ON_REMOVE)) - return; - - LOCK_ELUNA; - Push(ah); - CallAllFunctions(ServerEventBindings, AUCTION_EVENT_ON_REMOVE); -} - -void Eluna::OnSuccessful(AuctionHouseObject* ah) -{ - if (!ServerEventBindings->HasEvents(AUCTION_EVENT_ON_SUCCESSFUL)) - return; - - LOCK_ELUNA; - Push(ah); - CallAllFunctions(ServerEventBindings, AUCTION_EVENT_ON_SUCCESSFUL); -} - -void Eluna::OnExpire(AuctionHouseObject* ah) -{ - if (!ServerEventBindings->HasEvents(AUCTION_EVENT_ON_EXPIRE)) - return; - - LOCK_ELUNA; - Push(ah); - CallAllFunctions(ServerEventBindings, AUCTION_EVENT_ON_EXPIRE); -} - -// Packet -bool Eluna::OnPacketSend(WorldSession* session, WorldPacket& packet) -{ - bool result = true; - Player* player = NULL; - if (session) - player = session->GetPlayer(); - OnPacketSendAny(player, packet, result); - OnPacketSendOne(player, packet, result); - return result; -} -void Eluna::OnPacketSendAny(Player* player, WorldPacket& packet, bool& result) -{ - if (!ServerEventBindings->HasEvents(SERVER_EVENT_ON_PACKET_SEND)) - return; - - LOCK_ELUNA; - Push(new WorldPacket(packet)); - Push(player); - int n = SetupStack(ServerEventBindings, SERVER_EVENT_ON_PACKET_SEND, 2); - - while (n > 0) - { - int r = CallOneFunction(n--, 2, 2); - - if (lua_isboolean(L, r + 0) && !lua_toboolean(L, r + 0)) - result = false; - - if (lua_isuserdata(L, r + 1)) - if (WorldPacket* data = CHECKOBJ(L, r + 1, false)) - packet = *data; - - lua_pop(L, 2); - } - - CleanUpStack(2); -} -void Eluna::OnPacketSendOne(Player* player, WorldPacket& packet, bool& result) -{ - if (!PacketEventBindings->HasEvents(PACKET_EVENT_ON_PACKET_SEND, packet.GetOpcode())) - return; - - LOCK_ELUNA; - Push(new WorldPacket(packet)); - Push(player); - int n = SetupStack(PacketEventBindings, PACKET_EVENT_ON_PACKET_SEND, OpcodesList(packet.GetOpcode()), 2); - - while (n > 0) - { - int r = CallOneFunction(n--, 2, 2); - - if (lua_isboolean(L, r + 0) && !lua_toboolean(L, r + 0)) - result = false; - - if (lua_isuserdata(L, r + 1)) - if (WorldPacket* data = CHECKOBJ(L, r + 1, false)) - packet = *data; - - lua_pop(L, 2); - } - - CleanUpStack(2); -} - -bool Eluna::OnPacketReceive(WorldSession* session, WorldPacket& packet) -{ - bool result = true; - Player* player = NULL; - if (session) - player = session->GetPlayer(); - OnPacketReceiveAny(player, packet, result); - OnPacketReceiveOne(player, packet, result); - return result; -} -void Eluna::OnPacketReceiveAny(Player* player, WorldPacket& packet, bool& result) -{ - if (!ServerEventBindings->HasEvents(SERVER_EVENT_ON_PACKET_RECEIVE)) - return; - - LOCK_ELUNA; - Push(new WorldPacket(packet)); - Push(player); - int n = SetupStack(ServerEventBindings, SERVER_EVENT_ON_PACKET_RECEIVE, 2); - - while (n > 0) - { - int r = CallOneFunction(n--, 2, 2); - - if (lua_isboolean(L, r + 0) && !lua_toboolean(L, r + 0)) - result = false; - - if (lua_isuserdata(L, r + 1)) - if (WorldPacket* data = CHECKOBJ(L, r + 1, false)) - packet = *data; - - lua_pop(L, 2); - } - - CleanUpStack(2); -} -void Eluna::OnPacketReceiveOne(Player* player, WorldPacket& packet, bool& result) -{ - if (!PacketEventBindings->HasEvents(PACKET_EVENT_ON_PACKET_RECEIVE, packet.GetOpcode())) - return; - - LOCK_ELUNA; - Push(new WorldPacket(packet)); - Push(player); - int n = SetupStack(PacketEventBindings, PACKET_EVENT_ON_PACKET_RECEIVE, OpcodesList(), 2); - - while (n > 0) - { - int r = CallOneFunction(n--, 2, 2); - - if (lua_isboolean(L, r + 0) && !lua_toboolean(L, r + 0)) - result = false; - - if (lua_isuserdata(L, r + 1)) - if (WorldPacket* data = CHECKOBJ(L, r + 1, false)) - packet = *data; - - lua_pop(L, 2); - } - - CleanUpStack(2); -} - -void Eluna::OnOpenStateChange(bool open) -{ - if (!ServerEventBindings->HasEvents(WORLD_EVENT_ON_OPEN_STATE_CHANGE)) - return; - - LOCK_ELUNA; - Push(open); - CallAllFunctions(ServerEventBindings, WORLD_EVENT_ON_OPEN_STATE_CHANGE); -} - -void Eluna::OnConfigLoad(bool reload) -{ - if (!ServerEventBindings->HasEvents(WORLD_EVENT_ON_CONFIG_LOAD)) - return; - - LOCK_ELUNA; - Push(reload); - CallAllFunctions(ServerEventBindings, WORLD_EVENT_ON_CONFIG_LOAD); -} - -void Eluna::OnShutdownInitiate(ShutdownExitCode code, ShutdownMask mask) -{ - if (!ServerEventBindings->HasEvents(WORLD_EVENT_ON_SHUTDOWN_INIT)) - return; - - LOCK_ELUNA; - Push(code); - Push(mask); - CallAllFunctions(ServerEventBindings, WORLD_EVENT_ON_SHUTDOWN_INIT); -} - -void Eluna::OnShutdownCancel() -{ - if (!ServerEventBindings->HasEvents(WORLD_EVENT_ON_SHUTDOWN_CANCEL)) - return; - - LOCK_ELUNA; - CallAllFunctions(ServerEventBindings, WORLD_EVENT_ON_SHUTDOWN_CANCEL); -} - -void Eluna::OnWorldUpdate(uint32 diff) -{ - LOCK_ELUNA; - - if (reload) - { - ReloadEluna(); - return; - } - - eventMgr->globalProcessor->Update(diff); - - if (!ServerEventBindings->HasEvents(WORLD_EVENT_ON_UPDATE)) - return; - - Push(diff); - CallAllFunctions(ServerEventBindings, WORLD_EVENT_ON_UPDATE); -} - -void Eluna::OnStartup() -{ - if (!ServerEventBindings->HasEvents(WORLD_EVENT_ON_STARTUP)) - return; - - LOCK_ELUNA; - CallAllFunctions(ServerEventBindings, WORLD_EVENT_ON_STARTUP); -} - -void Eluna::OnShutdown() -{ - if (!ServerEventBindings->HasEvents(WORLD_EVENT_ON_SHUTDOWN)) - return; - - LOCK_ELUNA; - CallAllFunctions(ServerEventBindings, WORLD_EVENT_ON_SHUTDOWN); -} - -void Eluna::HandleGossipSelectOption(Player* pPlayer, Item* item, uint32 sender, uint32 action, const std::string& code) -{ - if (!ItemGossipBindings->HasEvents(GOSSIP_EVENT_ON_SELECT, item->GetEntry())) - return; - - LOCK_ELUNA; - pPlayer->PlayerTalkClass->ClearMenus(); - - Push(pPlayer); - Push(item); - Push(sender); - Push(action); - if (code.empty()) - Push(); - else - Push(code); - - CallAllFunctions(ItemGossipBindings, GOSSIP_EVENT_ON_SELECT, item->GetEntry()); -} - -void Eluna::HandleGossipSelectOption(Player* pPlayer, uint32 menuId, uint32 sender, uint32 action, const std::string& code) -{ - if (!playerGossipBindings->HasEvents(GOSSIP_EVENT_ON_SELECT, menuId)) - return; - - LOCK_ELUNA; - pPlayer->PlayerTalkClass->ClearMenus(); - - Push(pPlayer); // receiver - Push(pPlayer); // sender, just not to mess up the amount of args. - Push(sender); - Push(action); - if (code.empty()) - Push(); - else - Push(code); - - CallAllFunctions(playerGossipBindings, GOSSIP_EVENT_ON_SELECT, menuId); -} - -// item -bool Eluna::OnDummyEffect(Unit* pCaster, uint32 spellId, SpellEffIndex effIndex, Item* pTarget) -{ - if (!ItemEventBindings->HasEvents(ITEM_EVENT_ON_DUMMY_EFFECT, pTarget->GetEntry())) - return false; - - LOCK_ELUNA; - Push(pCaster); - Push(spellId); - Push(effIndex); - Push(pTarget); - return CallAllFunctionsBool(ItemEventBindings, ITEM_EVENT_ON_DUMMY_EFFECT, pTarget->GetEntry()); -} - -bool Eluna::OnQuestAccept(Player* pPlayer, Item* pItem, Quest const* pQuest) -{ - if (!ItemEventBindings->HasEvents(ITEM_EVENT_ON_QUEST_ACCEPT, pItem->GetEntry())) - return false; - - LOCK_ELUNA; - Push(pPlayer); - Push(pItem); - Push(pQuest); - return CallAllFunctionsBool(ItemEventBindings, ITEM_EVENT_ON_QUEST_ACCEPT, pItem->GetEntry()); -} - -bool Eluna::OnUse(Player* pPlayer, Item* pItem, SpellCastTargets const& targets) -{ - ObjectGuid guid = pItem->GET_GUID(); - bool castSpell = true; - - if (!OnItemUse(pPlayer, pItem, targets)) - castSpell = false; - - pItem = pPlayer->GetItemByGuid(guid); - if (pItem) - { - if (!OnItemGossip(pPlayer, pItem, targets)) - castSpell = false; - pItem = pPlayer->GetItemByGuid(guid); - } - - if (pItem && castSpell) - return true; - - // Send equip error that shows no message - // This is a hack fix to stop spell casting visual bug when a spell is not cast on use - WorldPacket data(SMSG_INVENTORY_CHANGE_FAILURE, 18); - data << uint8(59); // EQUIP_ERR_NONE / EQUIP_ERR_CANT_BE_DISENCHANTED - data << ObjectGuid(guid); - data << ObjectGuid(uint64(0)); - data << uint8(0); - pPlayer->GetSession()->SendPacket(&data); - return false; -} - -bool Eluna::OnItemUse(Player* pPlayer, Item* pItem, SpellCastTargets const& targets) -{ - if (!ItemEventBindings->HasEvents(ITEM_EVENT_ON_USE, pItem->GetEntry())) - return true; - - LOCK_ELUNA; - Push(pPlayer); - Push(pItem); -#ifndef TRINITY - if (GameObject* target = targets.getGOTarget()) - Push(target); - else if (Item* target = targets.getItemTarget()) - Push(target); - else if (Corpse* target = pPlayer->GetMap()->GetCorpse(targets.getCorpseTargetGuid())) - Push(target); - else if (Unit* target = targets.getUnitTarget()) - Push(target); - else - Push(); -#else - if (GameObject* target = targets.GetGOTarget()) - Push(target); - else if (Item* target = targets.GetItemTarget()) - Push(target); - else if (Corpse* target = targets.GetCorpseTarget()) - Push(target); - else if (Unit* target = targets.GetUnitTarget()) - Push(target); - else if (WorldObject* target = targets.GetObjectTarget()) - Push(target); - else - Push(); -#endif - - return CallAllFunctionsBool(ItemEventBindings, ITEM_EVENT_ON_USE, pItem->GetEntry(), true); -} - -bool Eluna::OnItemGossip(Player* pPlayer, Item* pItem, SpellCastTargets const& /*targets*/) -{ - if (!ItemGossipBindings->HasEvents(GOSSIP_EVENT_ON_HELLO, pItem->GetEntry())) - return true; - - LOCK_ELUNA; - pPlayer->PlayerTalkClass->ClearMenus(); - Push(pPlayer); - Push(pItem); - return CallAllFunctionsBool(ItemGossipBindings, GOSSIP_EVENT_ON_HELLO, pItem->GetEntry(), true); -} - -bool Eluna::OnExpire(Player* pPlayer, ItemTemplate const* pProto) -{ - if (!ItemEventBindings->HasEvents(ITEM_EVENT_ON_EXPIRE, pProto->ItemId)) - return false; - - LOCK_ELUNA; - Push(pPlayer); - Push(pProto->ItemId); - return CallAllFunctionsBool(ItemEventBindings, ITEM_EVENT_ON_EXPIRE, pProto->ItemId); -} - -bool Eluna::OnRemove(Player* pPlayer, Item* item) -{ - if (!ItemEventBindings->HasEvents(ITEM_EVENT_ON_REMOVE, item->GetEntry())) - return false; - - LOCK_ELUNA; - Push(pPlayer); - Push(item); - return CallAllFunctionsBool(ItemEventBindings, ITEM_EVENT_ON_REMOVE, item->GetEntry()); -} - -// Player -bool Eluna::OnCommand(Player* player, const char* text) -{ - // If from console, player is NULL - std::string fullcmd(text); - if (!player || player->GetSession()->GetSecurity() >= SEC_ADMINISTRATOR) - { - char* creload = strtok((char*)text, " "); - char* celuna = strtok(NULL, ""); - if (creload && celuna) - { - std::string reload(creload); - std::string eluna(celuna); - std::transform(reload.begin(), reload.end(), reload.begin(), ::tolower); - if (reload == "reload") - { - std::transform(eluna.begin(), eluna.end(), eluna.begin(), ::tolower); - if (std::string("eluna").find(eluna) == 0) - { - Eluna::reload = true; - return false; - } - } - } - } - - if (!PlayerEventBindings->HasEvents(PLAYER_EVENT_ON_COMMAND)) - return true; - - LOCK_ELUNA; - Push(player); - Push(fullcmd); - return CallAllFunctionsBool(PlayerEventBindings, PLAYER_EVENT_ON_COMMAND, true); -} - -void Eluna::OnLootItem(Player* pPlayer, Item* pItem, uint32 count, uint64 guid) -{ - if (!PlayerEventBindings->HasEvents(PLAYER_EVENT_ON_LOOT_ITEM)) - return; - - LOCK_ELUNA; - Push(pPlayer); - Push(pItem); - Push(count); - Push(guid); - CallAllFunctions(PlayerEventBindings, PLAYER_EVENT_ON_LOOT_ITEM); -} - -void Eluna::OnLootMoney(Player* pPlayer, uint32 amount) -{ - if (!PlayerEventBindings->HasEvents(PLAYER_EVENT_ON_LOOT_MONEY)) - return; - - LOCK_ELUNA; - Push(pPlayer); - Push(amount); - CallAllFunctions(PlayerEventBindings, PLAYER_EVENT_ON_LOOT_MONEY); -} - -void Eluna::OnFirstLogin(Player* pPlayer) -{ - if (!PlayerEventBindings->HasEvents(PLAYER_EVENT_ON_FIRST_LOGIN)) - return; - - LOCK_ELUNA; - Push(pPlayer); - CallAllFunctions(PlayerEventBindings, PLAYER_EVENT_ON_FIRST_LOGIN); -} - -void Eluna::OnRepop(Player* pPlayer) -{ - if (!PlayerEventBindings->HasEvents(PLAYER_EVENT_ON_REPOP)) - return; - - LOCK_ELUNA; - Push(pPlayer); - CallAllFunctions(PlayerEventBindings, PLAYER_EVENT_ON_REPOP); -} - -void Eluna::OnResurrect(Player* pPlayer) -{ - if (!PlayerEventBindings->HasEvents(PLAYER_EVENT_ON_RESURRECT)) - return; - - LOCK_ELUNA; - Push(pPlayer); - CallAllFunctions(PlayerEventBindings, PLAYER_EVENT_ON_RESURRECT); -} - -void Eluna::OnQuestAbandon(Player* pPlayer, uint32 questId) -{ - if (!PlayerEventBindings->HasEvents(PLAYER_EVENT_ON_QUEST_ABANDON)) - return; - - LOCK_ELUNA; - Push(pPlayer); - Push(questId); - CallAllFunctions(PlayerEventBindings, PLAYER_EVENT_ON_QUEST_ABANDON); -} - -void Eluna::OnEquip(Player* pPlayer, Item* pItem, uint8 bag, uint8 slot) -{ - if (!PlayerEventBindings->HasEvents(PLAYER_EVENT_ON_EQUIP)) - return; - - LOCK_ELUNA; - Push(pPlayer); - Push(pItem); - Push(bag); - Push(slot); - CallAllFunctions(PlayerEventBindings, PLAYER_EVENT_ON_EQUIP); -} - -InventoryResult Eluna::OnCanUseItem(const Player* pPlayer, uint32 itemEntry) -{ - if (!PlayerEventBindings->HasEvents(PLAYER_EVENT_ON_CAN_USE_ITEM)) - return EQUIP_ERR_OK; - - LOCK_ELUNA; - InventoryResult result = EQUIP_ERR_OK; - Push(pPlayer); - Push(itemEntry); - int n = SetupStack(PlayerEventBindings, PLAYER_EVENT_ON_CAN_USE_ITEM, 2); - - while (n > 0) - { - int r = CallOneFunction(n--, 2, 1); - - if (lua_isnumber(L, r)) - result = (InventoryResult)CHECKVAL(L, r); - - lua_pop(L, 1); - } - - CleanUpStack(2); - return result; -} -void Eluna::OnPlayerEnterCombat(Player* pPlayer, Unit* pEnemy) -{ - if (!PlayerEventBindings->HasEvents(PLAYER_EVENT_ON_ENTER_COMBAT)) - return; - - LOCK_ELUNA; - Push(pPlayer); - Push(pEnemy); - CallAllFunctions(PlayerEventBindings, PLAYER_EVENT_ON_ENTER_COMBAT); -} - -void Eluna::OnPlayerLeaveCombat(Player* pPlayer) -{ - if (!PlayerEventBindings->HasEvents(PLAYER_EVENT_ON_LEAVE_COMBAT)) - return; - - LOCK_ELUNA; - Push(pPlayer); - CallAllFunctions(PlayerEventBindings, PLAYER_EVENT_ON_LEAVE_COMBAT); -} - -void Eluna::OnPVPKill(Player* pKiller, Player* pKilled) -{ - if (!PlayerEventBindings->HasEvents(PLAYER_EVENT_ON_KILL_PLAYER)) - return; - - LOCK_ELUNA; - Push(pKiller); - Push(pKilled); - CallAllFunctions(PlayerEventBindings, PLAYER_EVENT_ON_KILL_PLAYER); -} - -void Eluna::OnCreatureKill(Player* pKiller, Creature* pKilled) -{ - if (!PlayerEventBindings->HasEvents(PLAYER_EVENT_ON_KILL_CREATURE)) - return; - - LOCK_ELUNA; - Push(pKiller); - Push(pKilled); - CallAllFunctions(PlayerEventBindings, PLAYER_EVENT_ON_KILL_CREATURE); -} - -void Eluna::OnPlayerKilledByCreature(Creature* pKiller, Player* pKilled) -{ - if (!PlayerEventBindings->HasEvents(PLAYER_EVENT_ON_KILLED_BY_CREATURE)) - return; - - LOCK_ELUNA; - Push(pKiller); - Push(pKilled); - CallAllFunctions(PlayerEventBindings, PLAYER_EVENT_ON_KILLED_BY_CREATURE); -} - -void Eluna::OnLevelChanged(Player* pPlayer, uint8 oldLevel) -{ - if (!PlayerEventBindings->HasEvents(PLAYER_EVENT_ON_LEVEL_CHANGE)) - return; - - LOCK_ELUNA; - Push(pPlayer); - Push(oldLevel); - CallAllFunctions(PlayerEventBindings, PLAYER_EVENT_ON_LEVEL_CHANGE); -} - -void Eluna::OnFreeTalentPointsChanged(Player* pPlayer, uint32 newPoints) -{ - if (!PlayerEventBindings->HasEvents(PLAYER_EVENT_ON_TALENTS_CHANGE)) - return; - - LOCK_ELUNA; - Push(pPlayer); - Push(newPoints); - CallAllFunctions(PlayerEventBindings, PLAYER_EVENT_ON_TALENTS_CHANGE); -} - -void Eluna::OnTalentsReset(Player* pPlayer, bool noCost) -{ - if (!PlayerEventBindings->HasEvents(PLAYER_EVENT_ON_TALENTS_RESET)) - return; - - LOCK_ELUNA; - Push(pPlayer); - Push(noCost); - CallAllFunctions(PlayerEventBindings, PLAYER_EVENT_ON_TALENTS_RESET); -} - -void Eluna::OnMoneyChanged(Player* pPlayer, int32& amount) -{ - if (!PlayerEventBindings->HasEvents(PLAYER_EVENT_ON_MONEY_CHANGE)) - return; - - LOCK_ELUNA; - Push(pPlayer); - Push(amount); - int amountIndex = lua_gettop(L); - int n = SetupStack(PlayerEventBindings, PLAYER_EVENT_ON_MONEY_CHANGE, 2); - - while (n > 0) - { - int r = CallOneFunction(n--, 2, 1); - - if (lua_isnumber(L, r)) - { - amount = CHECKVAL(L, r); - // Update the stack for subsequent calls. - ReplaceArgument(amount, amountIndex); - } - - lua_pop(L, 1); - } - - CleanUpStack(2); -} - -void Eluna::OnGiveXP(Player* pPlayer, uint32& amount, Unit* pVictim) -{ - if (!PlayerEventBindings->HasEvents(PLAYER_EVENT_ON_GIVE_XP)) - return; - - LOCK_ELUNA; - Push(pPlayer); - Push(amount); - Push(pVictim); - int amountIndex = lua_gettop(L) - 1; - int n = SetupStack(PlayerEventBindings, PLAYER_EVENT_ON_GIVE_XP, 3); - - while (n > 0) - { - int r = CallOneFunction(n--, 3, 1); - - if (lua_isnumber(L, r)) - { - amount = CHECKVAL(L, r); - // Update the stack for subsequent calls. - ReplaceArgument(amount, amountIndex); - } - - lua_pop(L, 1); - } - - CleanUpStack(3); -} - -void Eluna::OnReputationChange(Player* pPlayer, uint32 factionID, int32& standing, bool incremental) -{ - if (!PlayerEventBindings->HasEvents(PLAYER_EVENT_ON_REPUTATION_CHANGE)) - return; - - LOCK_ELUNA; - Push(pPlayer); - Push(factionID); - Push(standing); - Push(incremental); - int standingIndex = lua_gettop(L) - 1; - int n = SetupStack(PlayerEventBindings, PLAYER_EVENT_ON_REPUTATION_CHANGE, 4); - - while (n > 0) - { - int r = CallOneFunction(n--, 4, 1); - - if (lua_isnumber(L, r)) - { - standing = CHECKVAL(L, r); - // Update the stack for subsequent calls. - ReplaceArgument(standing, standingIndex); - } - - lua_pop(L, 1); - } - - CleanUpStack(4); -} - -void Eluna::OnDuelRequest(Player* pTarget, Player* pChallenger) -{ - if (!PlayerEventBindings->HasEvents(PLAYER_EVENT_ON_DUEL_REQUEST)) - return; - - LOCK_ELUNA; - Push(pTarget); - Push(pChallenger); - CallAllFunctions(PlayerEventBindings, PLAYER_EVENT_ON_DUEL_REQUEST); -} - -void Eluna::OnDuelStart(Player* pStarter, Player* pChallenger) -{ - if (!PlayerEventBindings->HasEvents(PLAYER_EVENT_ON_DUEL_START)) - return; - - LOCK_ELUNA; - Push(pStarter); - Push(pChallenger); - CallAllFunctions(PlayerEventBindings, PLAYER_EVENT_ON_DUEL_START); -} - -void Eluna::OnDuelEnd(Player* pWinner, Player* pLoser, DuelCompleteType type) -{ - if (!PlayerEventBindings->HasEvents(PLAYER_EVENT_ON_DUEL_END)) - return; - - LOCK_ELUNA; - Push(pWinner); - Push(pLoser); - Push(type); - CallAllFunctions(PlayerEventBindings, PLAYER_EVENT_ON_DUEL_END); -} - -void Eluna::OnEmote(Player* pPlayer, uint32 emote) -{ - if (!PlayerEventBindings->HasEvents(PLAYER_EVENT_ON_EMOTE)) - return; - - LOCK_ELUNA; - Push(pPlayer); - Push(emote); - CallAllFunctions(PlayerEventBindings, PLAYER_EVENT_ON_EMOTE); -} - -void Eluna::OnTextEmote(Player* pPlayer, uint32 textEmote, uint32 emoteNum, uint64 guid) -{ - if (!PlayerEventBindings->HasEvents(PLAYER_EVENT_ON_TEXT_EMOTE)) - return; - - LOCK_ELUNA; - Push(pPlayer); - Push(textEmote); - Push(emoteNum); - Push(guid); - CallAllFunctions(PlayerEventBindings, PLAYER_EVENT_ON_TEXT_EMOTE); -} - -void Eluna::OnSpellCast(Player* pPlayer, Spell* pSpell, bool skipCheck) -{ - if (!PlayerEventBindings->HasEvents(PLAYER_EVENT_ON_SPELL_CAST)) - return; - - LOCK_ELUNA; - Push(pPlayer); - Push(pSpell); - Push(skipCheck); - CallAllFunctions(PlayerEventBindings, PLAYER_EVENT_ON_SPELL_CAST); -} - -void Eluna::OnLogin(Player* pPlayer) -{ - if (!PlayerEventBindings->HasEvents(PLAYER_EVENT_ON_LOGIN)) - return; - - LOCK_ELUNA; - Push(pPlayer); - CallAllFunctions(PlayerEventBindings, PLAYER_EVENT_ON_LOGIN); -} - -void Eluna::OnLogout(Player* pPlayer) -{ - if (!PlayerEventBindings->HasEvents(PLAYER_EVENT_ON_LOGOUT)) - return; - - LOCK_ELUNA; - Push(pPlayer); - CallAllFunctions(PlayerEventBindings, PLAYER_EVENT_ON_LOGOUT); -} - -void Eluna::OnCreate(Player* pPlayer) -{ - if (!PlayerEventBindings->HasEvents(PLAYER_EVENT_ON_CHARACTER_CREATE)) - return; - - LOCK_ELUNA; - Push(pPlayer); - CallAllFunctions(PlayerEventBindings, PLAYER_EVENT_ON_CHARACTER_CREATE); -} - -void Eluna::OnDelete(uint32 guidlow) -{ - if (!PlayerEventBindings->HasEvents(PLAYER_EVENT_ON_CHARACTER_DELETE)) - return; - - LOCK_ELUNA; - Push(guidlow); - CallAllFunctions(PlayerEventBindings, PLAYER_EVENT_ON_CHARACTER_DELETE); -} - -void Eluna::OnSave(Player* pPlayer) -{ - if (!PlayerEventBindings->HasEvents(PLAYER_EVENT_ON_SAVE)) - return; - - LOCK_ELUNA; - Push(pPlayer); - CallAllFunctions(PlayerEventBindings, PLAYER_EVENT_ON_SAVE); -} - -void Eluna::OnBindToInstance(Player* pPlayer, Difficulty difficulty, uint32 mapid, bool permanent) -{ - if (!PlayerEventBindings->HasEvents(PLAYER_EVENT_ON_BIND_TO_INSTANCE)) - return; - - LOCK_ELUNA; - Push(pPlayer); - Push(difficulty); - Push(mapid); - Push(permanent); - CallAllFunctions(PlayerEventBindings, PLAYER_EVENT_ON_BIND_TO_INSTANCE); -} - -void Eluna::OnUpdateZone(Player* pPlayer, uint32 newZone, uint32 newArea) -{ - if (!PlayerEventBindings->HasEvents(PLAYER_EVENT_ON_UPDATE_ZONE)) - return; - - LOCK_ELUNA; - Push(pPlayer); - Push(newZone); - Push(newArea); - CallAllFunctions(PlayerEventBindings, PLAYER_EVENT_ON_UPDATE_ZONE); -} - -void Eluna::OnMapChanged(Player* player) -{ - if (!PlayerEventBindings->HasEvents(PLAYER_EVENT_ON_MAP_CHANGE)) - return; - - LOCK_ELUNA; - Push(player); - CallAllFunctions(PlayerEventBindings, PLAYER_EVENT_ON_MAP_CHANGE); -} - -// AddOns -bool Eluna::OnAddonMessage(Player* sender, uint32 type, std::string& msg, Player* receiver, Guild* guild, Group* group, Channel* channel) -{ - if (!ServerEventBindings->HasEvents(ADDON_EVENT_ON_MESSAGE)) - return true; - - LOCK_ELUNA; - Push(sender); - Push(type); - const char* c_msg = msg.c_str(); - Push(strtok((char*)c_msg, "\t")); // prefix - Push(strtok(NULL, "")); // msg - if (receiver) - Push(receiver); - else if (guild) - Push(guild); - else if (group) - Push(group); - else if (channel) - Push(channel->GetChannelId()); - else - Push(); - - return CallAllFunctionsBool(ServerEventBindings, ADDON_EVENT_ON_MESSAGE, true); -} - -bool Eluna::OnChat(Player* pPlayer, uint32 type, uint32 lang, std::string& msg) -{ - if (lang == LANG_ADDON) - return OnAddonMessage(pPlayer, type, msg, NULL, NULL, NULL, NULL); - - if (!PlayerEventBindings->HasEvents(PLAYER_EVENT_ON_CHAT)) - return true; - - LOCK_ELUNA; - bool result = true; - Push(pPlayer); - Push(msg); - Push(type); - Push(lang); - int n = SetupStack(PlayerEventBindings, PLAYER_EVENT_ON_CHAT, 4); - - while (n > 0) - { - int r = CallOneFunction(n--, 4, 2); - - if (lua_isboolean(L, r + 0) && !lua_toboolean(L, r + 0)) - result = false; - - if (lua_isstring(L, r + 1)) - msg = std::string(lua_tostring(L, r + 1)); - - lua_pop(L, 2); - } - - CleanUpStack(4); - return result; -} - -bool Eluna::OnChat(Player* pPlayer, uint32 type, uint32 lang, std::string& msg, Group* pGroup) -{ - if (lang == LANG_ADDON) - return OnAddonMessage(pPlayer, type, msg, NULL, NULL, pGroup, NULL); - - if (!PlayerEventBindings->HasEvents(PLAYER_EVENT_ON_GROUP_CHAT)) - return true; - - LOCK_ELUNA; - bool result = true; - Push(pPlayer); - Push(msg); - Push(type); - Push(lang); - Push(pGroup); - int n = SetupStack(PlayerEventBindings, PLAYER_EVENT_ON_GROUP_CHAT, 5); - - while (n > 0) - { - int r = CallOneFunction(n--, 5, 2); - - if (lua_isboolean(L, r + 0) && !lua_toboolean(L, r + 0)) - result = false; - - if (lua_isstring(L, r + 1)) - msg = std::string(lua_tostring(L, r + 1)); - - lua_pop(L, 2); - } - - CleanUpStack(5); - return result; -} - -bool Eluna::OnChat(Player* pPlayer, uint32 type, uint32 lang, std::string& msg, Guild* pGuild) -{ - if (lang == LANG_ADDON) - return OnAddonMessage(pPlayer, type, msg, NULL, pGuild, NULL, NULL); - - if (!PlayerEventBindings->HasEvents(PLAYER_EVENT_ON_GUILD_CHAT)) - return true; - - LOCK_ELUNA; - bool result = true; - Push(pPlayer); - Push(msg); - Push(type); - Push(lang); - Push(pGuild); - int n = SetupStack(PlayerEventBindings, PLAYER_EVENT_ON_GUILD_CHAT, 5); - - while (n > 0) - { - int r = CallOneFunction(n--, 5, 2); - - if (lua_isboolean(L, r + 0) && !lua_toboolean(L, r + 0)) - result = false; - - if (lua_isstring(L, r + 1)) - msg = std::string(lua_tostring(L, r + 1)); - - lua_pop(L, 2); - } - - CleanUpStack(5); - return result; -} - -bool Eluna::OnChat(Player* pPlayer, uint32 type, uint32 lang, std::string& msg, Channel* pChannel) -{ - if (lang == LANG_ADDON) - return OnAddonMessage(pPlayer, type, msg, NULL, NULL, NULL, pChannel); - - if (!PlayerEventBindings->HasEvents(PLAYER_EVENT_ON_CHANNEL_CHAT)) - return true; - - LOCK_ELUNA; - bool result = true; - Push(pPlayer); - Push(msg); - Push(type); - Push(lang); - Push(pChannel->GetChannelId()); - int n = SetupStack(PlayerEventBindings, PLAYER_EVENT_ON_CHANNEL_CHAT, 5); - - while (n > 0) - { - int r = CallOneFunction(n--, 5, 2); - - if (lua_isboolean(L, r + 0) && !lua_toboolean(L, r + 0)) - result = false; - - if (lua_isstring(L, r + 1)) - msg = std::string(lua_tostring(L, r + 1)); - - lua_pop(L, 2); - } - - CleanUpStack(5); - return result; -} - -bool Eluna::OnChat(Player* pPlayer, uint32 type, uint32 lang, std::string& msg, Player* pReceiver) -{ - if (lang == LANG_ADDON) - return OnAddonMessage(pPlayer, type, msg, pReceiver, NULL, NULL, NULL); - - if (!PlayerEventBindings->HasEvents(PLAYER_EVENT_ON_WHISPER)) - return true; - - LOCK_ELUNA; - bool result = true; - Push(pPlayer); - Push(msg); - Push(type); - Push(lang); - Push(pReceiver); - int n = SetupStack(PlayerEventBindings, PLAYER_EVENT_ON_WHISPER, 5); - - while (n > 0) - { - int r = CallOneFunction(n--, 5, 2); - - if (lua_isboolean(L, r + 0) && !lua_toboolean(L, r + 0)) - result = false; - - if (lua_isstring(L, r + 1)) - msg = std::string(lua_tostring(L, r + 1)); - - lua_pop(L, 2); - } - - CleanUpStack(5); - return result; -} - -#ifndef CLASSIC -#ifndef TBC -// Vehicle -void Eluna::OnInstall(Vehicle* vehicle) -{ - if (!VehicleEventBindings->HasEvents(VEHICLE_EVENT_ON_INSTALL)) - return; - - LOCK_ELUNA; - Push(vehicle); - CallAllFunctions(VehicleEventBindings, VEHICLE_EVENT_ON_INSTALL); -} - -void Eluna::OnUninstall(Vehicle* vehicle) -{ - if (!VehicleEventBindings->HasEvents(VEHICLE_EVENT_ON_UNINSTALL)) - return; - - LOCK_ELUNA; - Push(vehicle); - CallAllFunctions(VehicleEventBindings, VEHICLE_EVENT_ON_UNINSTALL); -} - -void Eluna::OnInstallAccessory(Vehicle* vehicle, Creature* accessory) -{ - if (!VehicleEventBindings->HasEvents(VEHICLE_EVENT_ON_INSTALL_ACCESSORY)) - return; - - LOCK_ELUNA; - Push(vehicle); - Push(accessory); - CallAllFunctions(VehicleEventBindings, VEHICLE_EVENT_ON_INSTALL_ACCESSORY); -} - -void Eluna::OnAddPassenger(Vehicle* vehicle, Unit* passenger, int8 seatId) -{ - if (!VehicleEventBindings->HasEvents(VEHICLE_EVENT_ON_ADD_PASSENGER)) - return; - - LOCK_ELUNA; - Push(vehicle); - Push(passenger); - Push(seatId); - CallAllFunctions(VehicleEventBindings, VEHICLE_EVENT_ON_ADD_PASSENGER); -} - -void Eluna::OnRemovePassenger(Vehicle* vehicle, Unit* passenger) -{ - if (!VehicleEventBindings->HasEvents(VEHICLE_EVENT_ON_REMOVE_PASSENGER)) - return; - - LOCK_ELUNA; - Push(vehicle); - Push(passenger); - CallAllFunctions(VehicleEventBindings, VEHICLE_EVENT_ON_REMOVE_PASSENGER); -} -#endif -#endif - -void Eluna::OnAddMember(Guild* guild, Player* player, uint32 plRank) -{ - if (!GuildEventBindings->HasEvents(GUILD_EVENT_ON_ADD_MEMBER)) - return; - - LOCK_ELUNA; - Push(guild); - Push(player); - Push(plRank); - CallAllFunctions(GuildEventBindings, GUILD_EVENT_ON_ADD_MEMBER); -} - -void Eluna::OnRemoveMember(Guild* guild, Player* player, bool isDisbanding) -{ - if (!GuildEventBindings->HasEvents(GUILD_EVENT_ON_REMOVE_MEMBER)) - return; - - LOCK_ELUNA; - Push(guild); - Push(player); - Push(isDisbanding); - CallAllFunctions(GuildEventBindings, GUILD_EVENT_ON_REMOVE_MEMBER); -} - -void Eluna::OnMOTDChanged(Guild* guild, const std::string& newMotd) -{ - if (!GuildEventBindings->HasEvents(GUILD_EVENT_ON_MOTD_CHANGE)) - return; - - LOCK_ELUNA; - Push(guild); - Push(newMotd); - CallAllFunctions(GuildEventBindings, GUILD_EVENT_ON_MOTD_CHANGE); -} - -void Eluna::OnInfoChanged(Guild* guild, const std::string& newInfo) -{ - if (!GuildEventBindings->HasEvents(GUILD_EVENT_ON_INFO_CHANGE)) - return; - - LOCK_ELUNA; - Push(guild); - Push(newInfo); - CallAllFunctions(GuildEventBindings, GUILD_EVENT_ON_INFO_CHANGE); -} - -void Eluna::OnCreate(Guild* guild, Player* leader, const std::string& name) -{ - if (!GuildEventBindings->HasEvents(GUILD_EVENT_ON_CREATE)) - return; - - LOCK_ELUNA; - Push(guild); - Push(leader); - Push(name); - CallAllFunctions(GuildEventBindings, GUILD_EVENT_ON_CREATE); -} - -void Eluna::OnDisband(Guild* guild) -{ - if (!GuildEventBindings->HasEvents(GUILD_EVENT_ON_DISBAND)) - return; - - LOCK_ELUNA; - Push(guild); - CallAllFunctions(GuildEventBindings, GUILD_EVENT_ON_DISBAND); -} - -void Eluna::OnMemberWitdrawMoney(Guild* guild, Player* player, uint32& amount, bool isRepair) // isRepair not a part of Mangos, implement? -{ - if (!GuildEventBindings->HasEvents(GUILD_EVENT_ON_MONEY_WITHDRAW)) - return; - - LOCK_ELUNA; - Push(guild); - Push(player); - Push(amount); - Push(isRepair); // isRepair not a part of Mangos, implement? - int amountIndex = lua_gettop(L) - 1; - int n = SetupStack(GuildEventBindings, GUILD_EVENT_ON_MONEY_WITHDRAW, 4); - - while (n > 0) - { - int r = CallOneFunction(n--, 4, 1); - - if (lua_isnumber(L, r)) - { - amount = CHECKVAL(L, r); - // Update the stack for subsequent calls. - ReplaceArgument(amount, amountIndex); - } - - lua_pop(L, 1); - } - - CleanUpStack(4); -} - -void Eluna::OnMemberDepositMoney(Guild* guild, Player* player, uint32& amount) -{ - if (!GuildEventBindings->HasEvents(GUILD_EVENT_ON_MONEY_DEPOSIT)) - return; - - LOCK_ELUNA; - Push(guild); - Push(player); - Push(amount); - int amountIndex = lua_gettop(L); - int n = SetupStack(GuildEventBindings, GUILD_EVENT_ON_MONEY_DEPOSIT, 3); - - while (n > 0) - { - int r = CallOneFunction(n--, 3, 1); - - if (lua_isnumber(L, r)) - { - amount = CHECKVAL(L, r); - // Update the stack for subsequent calls. - ReplaceArgument(amount, amountIndex); - } - - lua_pop(L, 1); - } - - CleanUpStack(3); -} - -void Eluna::OnItemMove(Guild* guild, Player* player, Item* pItem, bool isSrcBank, uint8 srcContainer, uint8 srcSlotId, - bool isDestBank, uint8 destContainer, uint8 destSlotId) -{ - if (!GuildEventBindings->HasEvents(GUILD_EVENT_ON_ITEM_MOVE)) - return; - - LOCK_ELUNA; - Push(guild); - Push(player); - Push(pItem); - Push(isSrcBank); - Push(srcContainer); - Push(srcSlotId); - Push(isDestBank); - Push(destContainer); - Push(destSlotId); - CallAllFunctions(GuildEventBindings, GUILD_EVENT_ON_ITEM_MOVE); -} - -void Eluna::OnEvent(Guild* guild, uint8 eventType, uint32 playerGuid1, uint32 playerGuid2, uint8 newRank) -{ - if (!GuildEventBindings->HasEvents(GUILD_EVENT_ON_EVENT)) - return; - - LOCK_ELUNA; - Push(guild); - Push(eventType); - Push(playerGuid1); - Push(playerGuid2); - Push(newRank); - CallAllFunctions(GuildEventBindings, GUILD_EVENT_ON_EVENT); -} - -void Eluna::OnBankEvent(Guild* guild, uint8 eventType, uint8 tabId, uint32 playerGuid, uint32 itemOrMoney, uint16 itemStackCount, uint8 destTabId) -{ - if (!GuildEventBindings->HasEvents(GUILD_EVENT_ON_BANK_EVENT)) - return; - - LOCK_ELUNA; - Push(guild); - Push(eventType); - Push(tabId); - Push(playerGuid); - Push(itemOrMoney); - Push(itemStackCount); - Push(destTabId); - CallAllFunctions(GuildEventBindings, GUILD_EVENT_ON_BANK_EVENT); -} -// Group -void Eluna::OnAddMember(Group* group, uint64 guid) -{ - if (!GroupEventBindings->HasEvents(GROUP_EVENT_ON_MEMBER_ADD)) - return; - - LOCK_ELUNA; - Push(group); - Push(guid); - CallAllFunctions(GroupEventBindings, GROUP_EVENT_ON_MEMBER_ADD); -} - -void Eluna::OnInviteMember(Group* group, uint64 guid) -{ - if (!GroupEventBindings->HasEvents(GROUP_EVENT_ON_MEMBER_INVITE)) - return; - - LOCK_ELUNA; - Push(group); - Push(guid); - CallAllFunctions(GroupEventBindings, GROUP_EVENT_ON_MEMBER_INVITE); -} - -void Eluna::OnRemoveMember(Group* group, uint64 guid, uint8 method) -{ - if (!GroupEventBindings->HasEvents(GROUP_EVENT_ON_MEMBER_REMOVE)) - return; - - LOCK_ELUNA; - Push(group); - Push(guid); - Push(method); - CallAllFunctions(GroupEventBindings, GROUP_EVENT_ON_MEMBER_REMOVE); -} - -void Eluna::OnChangeLeader(Group* group, uint64 newLeaderGuid, uint64 oldLeaderGuid) -{ - if (!GroupEventBindings->HasEvents(GROUP_EVENT_ON_LEADER_CHANGE)) - return; - - LOCK_ELUNA; - Push(group); - Push(newLeaderGuid); - Push(oldLeaderGuid); - CallAllFunctions(GroupEventBindings, GROUP_EVENT_ON_LEADER_CHANGE); -} - -void Eluna::OnDisband(Group* group) -{ - if (!GroupEventBindings->HasEvents(GROUP_EVENT_ON_DISBAND)) - return; - - LOCK_ELUNA; - Push(group); - CallAllFunctions(GroupEventBindings, GROUP_EVENT_ON_DISBAND); -} - -void Eluna::OnCreate(Group* group, uint64 leaderGuid, GroupType groupType) -{ - if (!GroupEventBindings->HasEvents(GROUP_EVENT_ON_CREATE)) - return; - - LOCK_ELUNA; - Push(group); - Push(leaderGuid); - Push(groupType); - CallAllFunctions(GroupEventBindings, GROUP_EVENT_ON_CREATE); -} - -/* Map */ -void Eluna::OnCreate(Map* map) -{ - if (!ServerEventBindings->HasEvents(MAP_EVENT_ON_CREATE)) - return; - - LOCK_ELUNA; - Push(map); - CallAllFunctions(ServerEventBindings, MAP_EVENT_ON_CREATE); -} -void Eluna::OnDestroy(Map* map) -{ - if (!ServerEventBindings->HasEvents(MAP_EVENT_ON_DESTROY)) - return; - - LOCK_ELUNA; - Push(map); - CallAllFunctions(ServerEventBindings, MAP_EVENT_ON_DESTROY); -} -void Eluna::OnPlayerEnter(Map* map, Player* player) -{ - if (!ServerEventBindings->HasEvents(MAP_EVENT_ON_PLAYER_ENTER)) - return; - - LOCK_ELUNA; - Push(map); - Push(player); - CallAllFunctions(ServerEventBindings, MAP_EVENT_ON_PLAYER_ENTER); -} -void Eluna::OnPlayerLeave(Map* map, Player* player) -{ - if (!ServerEventBindings->HasEvents(MAP_EVENT_ON_PLAYER_LEAVE)) - return; - - LOCK_ELUNA; - Push(map); - Push(player); - CallAllFunctions(ServerEventBindings, MAP_EVENT_ON_PLAYER_LEAVE); -} -void Eluna::OnUpdate(Map* map, uint32 diff) -{ - if (!ServerEventBindings->HasEvents(MAP_EVENT_ON_UPDATE)) - return; - - LOCK_ELUNA; - // enable this for multithread - // eventMgr->globalProcessor->Update(diff); - Push(map); - Push(diff); - CallAllFunctions(ServerEventBindings, MAP_EVENT_ON_UPDATE); -} -void Eluna::OnRemove(GameObject* gameobject) -{ - if (!ServerEventBindings->HasEvents(WORLD_EVENT_ON_DELETE_GAMEOBJECT)) - return; - - LOCK_ELUNA; - Push(gameobject); - CallAllFunctions(ServerEventBindings, WORLD_EVENT_ON_DELETE_GAMEOBJECT); -} -void Eluna::OnRemove(Creature* creature) -{ - if (!ServerEventBindings->HasEvents(WORLD_EVENT_ON_DELETE_CREATURE)) - return; - - LOCK_ELUNA; - Push(creature); - CallAllFunctions(ServerEventBindings, WORLD_EVENT_ON_DELETE_CREATURE); -} - -// creature -bool Eluna::OnDummyEffect(Unit* pCaster, uint32 spellId, SpellEffIndex effIndex, Creature* pTarget) -{ - 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; - - LOCK_ELUNA; - Push(pCaster); - Push(spellId); - Push(effIndex); - Push(pTarget); - return CallAllFunctionsBool(CreatureEventBindings, CreatureUniqueBindings, CREATURE_EVENT_ON_DUMMY_EFFECT, pTarget->GetEntry(), pTarget->GET_GUID(), pTarget->GetInstanceId()); -} - -bool Eluna::OnGossipHello(Player* pPlayer, Creature* pCreature) -{ - if (!CreatureGossipBindings->HasEvents(GOSSIP_EVENT_ON_HELLO, pCreature->GetEntry())) - return false; - - LOCK_ELUNA; - pPlayer->PlayerTalkClass->ClearMenus(); - Push(pPlayer); - Push(pCreature); - return CallAllFunctionsBool(CreatureGossipBindings, GOSSIP_EVENT_ON_HELLO, pCreature->GetEntry(), true); -} - -bool Eluna::OnGossipSelect(Player* pPlayer, Creature* pCreature, uint32 sender, uint32 action) -{ - if (!CreatureGossipBindings->HasEvents(GOSSIP_EVENT_ON_SELECT, pCreature->GetEntry())) - return false; - - LOCK_ELUNA; - pPlayer->PlayerTalkClass->ClearMenus(); - Push(pPlayer); - Push(pCreature); - Push(sender); - Push(action); - return CallAllFunctionsBool(CreatureGossipBindings, GOSSIP_EVENT_ON_SELECT, pCreature->GetEntry(), true); -} - -bool Eluna::OnGossipSelectCode(Player* pPlayer, Creature* pCreature, uint32 sender, uint32 action, const char* code) -{ - if (!CreatureGossipBindings->HasEvents(GOSSIP_EVENT_ON_SELECT, pCreature->GetEntry())) - return false; - - LOCK_ELUNA; - pPlayer->PlayerTalkClass->ClearMenus(); - Push(pPlayer); - Push(pCreature); - Push(sender); - Push(action); - Push(code); - return CallAllFunctionsBool(CreatureGossipBindings, GOSSIP_EVENT_ON_SELECT, pCreature->GetEntry(), true); -} - -bool Eluna::OnQuestAccept(Player* pPlayer, Creature* pCreature, Quest const* pQuest) -{ - 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; - - LOCK_ELUNA; - Push(pPlayer); - Push(pCreature); - Push(pQuest); - 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())) - 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, 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())) - 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, 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())) - if (!CreatureUniqueBindings->HasEvents(CREATURE_EVENT_ON_ADD, creature->GET_GUID(), creature->GetInstanceId())) - return; - - LOCK_ELUNA; - Push(creature); - 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())) - if (!CreatureUniqueBindings->HasEvents(CREATURE_EVENT_ON_REMOVE, creature->GET_GUID(), creature->GetInstanceId())) - return; - - LOCK_ELUNA; - Push(creature); - 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())) - if (!CreatureUniqueBindings->HasEvents(CREATURE_EVENT_ON_SUMMONED, pCreature->GET_GUID(), pCreature->GetInstanceId())) - return false; - - LOCK_ELUNA; - Push(pCreature); - Push(pSummoner); - 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())) - if (!CreatureUniqueBindings->HasEvents(CREATURE_EVENT_ON_AIUPDATE, me->GET_GUID(), me->GetInstanceId())) - return false; - - LOCK_ELUNA; - Push(me); - Push(diff); - 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 at creature aggro either by MoveInLOS or Attack Start -bool Eluna::EnterCombat(Creature* me, Unit* target) -{ - 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; - - LOCK_ELUNA; - Push(me); - Push(target); - 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())) - if (!CreatureUniqueBindings->HasEvents(CREATURE_EVENT_ON_DAMAGE_TAKEN, me->GET_GUID(), me->GetInstanceId())) - return false; - - LOCK_ELUNA; - bool result = false; - Push(me); - Push(attacker); - Push(damage); - int damageIndex = lua_gettop(L); - int n = SetupStack(CreatureEventBindings, CreatureUniqueBindings, CREATURE_EVENT_ON_DAMAGE_TAKEN, me->GetEntry(), me->GET_GUID(), me->GetInstanceId(), 3); - - while (n > 0) - { - int r = CallOneFunction(n--, 3, 2); - - if (lua_isboolean(L, r + 0) && lua_toboolean(L, r + 0)) - result = true; - - if (lua_isnumber(L, r + 1)) - { - damage = Eluna::CHECKVAL(L, r + 1); - // Update the stack for subsequent calls. - ReplaceArgument(damage, damageIndex); - } - - lua_pop(L, 2); - } - - CleanUpStack(3); - return result; -} - -//Called at creature death -bool Eluna::JustDied(Creature* me, Unit* killer) -{ - On_Reset(me); - - if (!CreatureEventBindings->HasEvents(CREATURE_EVENT_ON_DIED, me->GetEntry())) - if (!CreatureUniqueBindings->HasEvents(CREATURE_EVENT_ON_DIED, me->GET_GUID(), me->GetInstanceId())) - return false; - - LOCK_ELUNA; - Push(me); - Push(killer); - 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())) - if (!CreatureUniqueBindings->HasEvents(CREATURE_EVENT_ON_TARGET_DIED, me->GET_GUID(), me->GetInstanceId())) - return false; - - LOCK_ELUNA; - Push(me); - Push(victim); - 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())) - 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, 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())) - 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, 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())) - 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, 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())) - if (!CreatureUniqueBindings->HasEvents(CREATURE_EVENT_ON_PRE_COMBAT, me->GET_GUID(), me->GetInstanceId())) - return false; - - LOCK_ELUNA; - Push(me); - Push(target); - 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 -bool Eluna::EnterEvadeMode(Creature* me) -{ - On_Reset(me); - - 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; - - LOCK_ELUNA; - Push(me); - 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())) - if (!CreatureUniqueBindings->HasEvents(CREATURE_EVENT_ON_ATTACKED_AT, me->GET_GUID(), me->GetInstanceId())) - return false; - - LOCK_ELUNA; - Push(me); - Push(attacker); - 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) -bool Eluna::JustRespawned(Creature* me) -{ - On_Reset(me); - - if (!CreatureEventBindings->HasEvents(CREATURE_EVENT_ON_SPAWN, me->GetEntry())) - if (!CreatureUniqueBindings->HasEvents(CREATURE_EVENT_ON_SPAWN, me->GET_GUID(), me->GetInstanceId())) - return false; - - LOCK_ELUNA; - Push(me); - 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())) - if (!CreatureUniqueBindings->HasEvents(CREATURE_EVENT_ON_REACH_HOME, me->GET_GUID(), me->GetInstanceId())) - return false; - - LOCK_ELUNA; - Push(me); - 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())) - 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, 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())) - 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, CreatureUniqueBindings, CREATURE_EVENT_ON_CORPSE_REMOVED, me->GetEntry(), me->GET_GUID(), me->GetInstanceId(), 2); - - while (n > 0) - { - int r = CallOneFunction(n--, 2, 2); - - if (lua_isboolean(L, r + 0) && lua_toboolean(L, r + 0)) - result = true; - - if (lua_isnumber(L, r + 1)) - { - respawnDelay = Eluna::CHECKVAL(L, r + 1); - // Update the stack for subsequent calls. - ReplaceArgument(respawnDelay, respawnDelayIndex); - } - - lua_pop(L, 2); - } - - CleanUpStack(2); - return result; -} - -bool Eluna::MoveInLineOfSight(Creature* me, Unit* who) -{ - 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; - - LOCK_ELUNA; - Push(me); - Push(who); - 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())) - if (!CreatureUniqueBindings->HasEvents(CREATURE_EVENT_ON_RESET, me->GET_GUID(), me->GetInstanceId())) - return; - - LOCK_ELUNA; - Push(me); - 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())) - 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, 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())) - 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, CreatureUniqueBindings, CREATURE_EVENT_ON_SPELL_HIT_TARGET, me->GetEntry(), me->GET_GUID(), me->GetInstanceId()); -} - -#ifdef TRINITY - -bool Eluna::SummonedCreatureDies(Creature* me, Creature* summon, Unit* killer) -{ - 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; - - LOCK_ELUNA; - Push(me); - Push(summon); - Push(killer); - 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())) - 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, 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())) - if (!CreatureUniqueBindings->HasEvents(CREATURE_EVENT_ON_OWNER_ATTACKED, me->GET_GUID(), me->GetInstanceId())) - return false; - - LOCK_ELUNA; - Push(me); - Push(target); - return CallAllFunctionsBool(CreatureEventBindings, CreatureUniqueBindings, CREATURE_EVENT_ON_OWNER_ATTACKED, me->GetEntry(), me->GET_GUID(), me->GetInstanceId()); -} -#endif - -// gameobject -bool Eluna::OnDummyEffect(Unit* pCaster, uint32 spellId, SpellEffIndex effIndex, GameObject* pTarget) -{ - if (!GameObjectEventBindings->HasEvents(GAMEOBJECT_EVENT_ON_DUMMY_EFFECT, pTarget->GetEntry())) - return false; - - LOCK_ELUNA; - Push(pCaster); - Push(spellId); - Push(effIndex); - Push(pTarget); - return CallAllFunctionsBool(GameObjectEventBindings, GAMEOBJECT_EVENT_ON_DUMMY_EFFECT, pTarget->GetEntry()); -} - -bool Eluna::OnGossipHello(Player* pPlayer, GameObject* pGameObject) -{ - if (!GameObjectGossipBindings->HasEvents(GOSSIP_EVENT_ON_HELLO, pGameObject->GetEntry())) - return false; - - LOCK_ELUNA; - pPlayer->PlayerTalkClass->ClearMenus(); - Push(pPlayer); - Push(pGameObject); - return CallAllFunctionsBool(GameObjectGossipBindings, GOSSIP_EVENT_ON_HELLO, pGameObject->GetEntry(), true); -} - -bool Eluna::OnGossipSelect(Player* pPlayer, GameObject* pGameObject, uint32 sender, uint32 action) -{ - if (!GameObjectGossipBindings->HasEvents(GOSSIP_EVENT_ON_SELECT, pGameObject->GetEntry())) - return false; - - LOCK_ELUNA; - pPlayer->PlayerTalkClass->ClearMenus(); - Push(pPlayer); - Push(pGameObject); - Push(sender); - Push(action); - return CallAllFunctionsBool(GameObjectGossipBindings, GOSSIP_EVENT_ON_SELECT, pGameObject->GetEntry(), true); -} - -bool Eluna::OnGossipSelectCode(Player* pPlayer, GameObject* pGameObject, uint32 sender, uint32 action, const char* code) -{ - if (!GameObjectGossipBindings->HasEvents(GOSSIP_EVENT_ON_SELECT, pGameObject->GetEntry())) - return false; - - LOCK_ELUNA; - pPlayer->PlayerTalkClass->ClearMenus(); - Push(pPlayer); - Push(pGameObject); - Push(sender); - Push(action); - Push(code); - return CallAllFunctionsBool(GameObjectGossipBindings, GOSSIP_EVENT_ON_SELECT, pGameObject->GetEntry(), true); -} - -bool Eluna::OnQuestAccept(Player* pPlayer, GameObject* pGameObject, Quest const* pQuest) -{ - if (!GameObjectEventBindings->HasEvents(GAMEOBJECT_EVENT_ON_QUEST_ACCEPT, pGameObject->GetEntry())) - return false; - - LOCK_ELUNA; - Push(pPlayer); - Push(pGameObject); - Push(pQuest); - return CallAllFunctionsBool(GameObjectEventBindings, GAMEOBJECT_EVENT_ON_QUEST_ACCEPT, pGameObject->GetEntry()); -} - -void Eluna::UpdateAI(GameObject* pGameObject, uint32 diff) -{ - if (!GameObjectEventBindings->HasEvents(GAMEOBJECT_EVENT_ON_AIUPDATE, pGameObject->GetEntry())) - return; - - LOCK_ELUNA; - pGameObject->elunaEvents->Update(diff); - Push(pGameObject); - Push(diff); - CallAllFunctions(GameObjectEventBindings, GAMEOBJECT_EVENT_ON_AIUPDATE, pGameObject->GetEntry()); -} - -bool Eluna::OnQuestReward(Player* pPlayer, GameObject* pGameObject, Quest const* pQuest, uint32 opt) -{ - if (!GameObjectEventBindings->HasEvents(GAMEOBJECT_EVENT_ON_QUEST_REWARD, pGameObject->GetEntry())) - return false; - - LOCK_ELUNA; - Push(pPlayer); - Push(pGameObject); - Push(pQuest); - Push(opt); - return CallAllFunctionsBool(GameObjectEventBindings, GAMEOBJECT_EVENT_ON_QUEST_REWARD, pGameObject->GetEntry()); -} - -uint32 Eluna::GetDialogStatus(Player* pPlayer, GameObject* pGameObject) -{ - if (!GameObjectEventBindings->HasEvents(GAMEOBJECT_EVENT_ON_DIALOG_STATUS, pGameObject->GetEntry())) - return DIALOG_STATUS_SCRIPTED_NO_STATUS; - - LOCK_ELUNA; - Push(pPlayer); - Push(pGameObject); - CallAllFunctions(GameObjectEventBindings, GAMEOBJECT_EVENT_ON_DIALOG_STATUS, pGameObject->GetEntry()); - return DIALOG_STATUS_SCRIPTED_NO_STATUS; // DIALOG_STATUS_UNDEFINED -} - -#ifndef CLASSIC -#ifndef TBC -void Eluna::OnDestroyed(GameObject* pGameObject, Player* pPlayer) -{ - if (!GameObjectEventBindings->HasEvents(GAMEOBJECT_EVENT_ON_DESTROYED, pGameObject->GetEntry())) - return; - - LOCK_ELUNA; - Push(pGameObject); - Push(pPlayer); - CallAllFunctions(GameObjectEventBindings, GAMEOBJECT_EVENT_ON_DESTROYED, pGameObject->GetEntry()); -} - -void Eluna::OnDamaged(GameObject* pGameObject, Player* pPlayer) -{ - if (!GameObjectEventBindings->HasEvents(GAMEOBJECT_EVENT_ON_DAMAGED, pGameObject->GetEntry())) - return; - - LOCK_ELUNA; - Push(pGameObject); - Push(pPlayer); - CallAllFunctions(GameObjectEventBindings, GAMEOBJECT_EVENT_ON_DAMAGED, pGameObject->GetEntry()); -} -#endif -#endif - -void Eluna::OnLootStateChanged(GameObject* pGameObject, uint32 state) -{ - if (!GameObjectEventBindings->HasEvents(GAMEOBJECT_EVENT_ON_LOOT_STATE_CHANGE, pGameObject->GetEntry())) - return; - - LOCK_ELUNA; - Push(pGameObject); - Push(state); - CallAllFunctions(GameObjectEventBindings, GAMEOBJECT_EVENT_ON_LOOT_STATE_CHANGE, pGameObject->GetEntry()); -} - -void Eluna::OnGameObjectStateChanged(GameObject* pGameObject, uint32 state) -{ - if (!GameObjectEventBindings->HasEvents(GAMEOBJECT_EVENT_ON_GO_STATE_CHANGED, pGameObject->GetEntry())) - return; - - LOCK_ELUNA; - Push(pGameObject); - Push(state); - CallAllFunctions(GameObjectEventBindings, GAMEOBJECT_EVENT_ON_GO_STATE_CHANGED, pGameObject->GetEntry()); -} - -void Eluna::OnSpawn(GameObject* gameobject) -{ - if (!GameObjectEventBindings->HasEvents(GAMEOBJECT_EVENT_ON_SPAWN, gameobject->GetEntry())) - return; - - LOCK_ELUNA; - Push(gameobject); - CallAllFunctions(GameObjectEventBindings, GAMEOBJECT_EVENT_ON_SPAWN, gameobject->GetEntry()); -} - -void Eluna::OnAddToWorld(GameObject* gameobject) -{ - if (!GameObjectEventBindings->HasEvents(GAMEOBJECT_EVENT_ON_ADD, gameobject->GetEntry())) - return; - - LOCK_ELUNA; - Push(gameobject); - CallAllFunctions(GameObjectEventBindings, GAMEOBJECT_EVENT_ON_ADD, gameobject->GetEntry()); -} - -void Eluna::OnRemoveFromWorld(GameObject* gameobject) -{ - if (!GameObjectEventBindings->HasEvents(GAMEOBJECT_EVENT_ON_REMOVE, gameobject->GetEntry())) - return; - - LOCK_ELUNA; - Push(gameobject); - CallAllFunctions(GameObjectEventBindings, GAMEOBJECT_EVENT_ON_REMOVE, gameobject->GetEntry()); -} - -bool Eluna::OnGameObjectUse(Player* pPlayer, GameObject* pGameObject) -{ - if (!GameObjectEventBindings->HasEvents(GAMEOBJECT_EVENT_ON_USE, pGameObject->GetEntry())) - return false; - - LOCK_ELUNA; - Push(pGameObject); - Push(pPlayer); - return CallAllFunctionsBool(GameObjectEventBindings, GAMEOBJECT_EVENT_ON_USE, pGameObject->GetEntry()); -} - -CreatureAI* Eluna::GetAI(Creature* creature) -{ - if (!CreatureEventBindings->HasEvents(creature->GetEntry()) && !CreatureUniqueBindings->HasEvents(creature->GET_GUID(), creature->GetInstanceId())) - return NULL; - return new ElunaCreatureAI(creature); -} - -void Eluna::OnBGStart(BattleGround* bg, BattleGroundTypeId bgId, uint32 instanceId) -{ - if (!BGEventBindings->HasEvents(BG_EVENT_ON_START)) - return; - - LOCK_ELUNA; - Push(bg); - Push(bgId); - Push(instanceId); - CallAllFunctions(BGEventBindings, BG_EVENT_ON_START); -} - -void Eluna::OnBGEnd(BattleGround* bg, BattleGroundTypeId bgId, uint32 instanceId, Team winner) -{ - if (!BGEventBindings->HasEvents(BG_EVENT_ON_END)) - return; - - LOCK_ELUNA; - Push(bg); - Push(bgId); - Push(instanceId); - Push(winner); - CallAllFunctions(BGEventBindings, BG_EVENT_ON_END); -} - -void Eluna::OnBGCreate(BattleGround* bg, BattleGroundTypeId bgId, uint32 instanceId) -{ - if (!BGEventBindings->HasEvents(BG_EVENT_ON_CREATE)) - return; - - LOCK_ELUNA; - Push(bg); - Push(bgId); - Push(instanceId); - CallAllFunctions(BGEventBindings, BG_EVENT_ON_CREATE); -} - -void Eluna::OnBGDestroy(BattleGround* bg, BattleGroundTypeId bgId, uint32 instanceId) -{ - if (!BGEventBindings->HasEvents(BG_EVENT_ON_PRE_DESTROY)) - return; - - LOCK_ELUNA; - Push(bg); - Push(bgId); - Push(instanceId); - CallAllFunctions(BGEventBindings, BG_EVENT_ON_PRE_DESTROY); -} diff --git a/Hooks.cpp b/Hooks.cpp new file mode 100644 index 0000000..5fd8be4 --- /dev/null +++ b/Hooks.cpp @@ -0,0 +1,19 @@ +/* + * Copyright (C) 2010 - 2015 Eluna Lua Engine + * This program is free software licensed under GPL version 3 + * Please see the included DOCS/LICENSE.md for more information + */ + +#include "Hooks.h" +#include "LuaEngine.h" +#include "ElunaBinding.h" +#include "ElunaEventMgr.h" +#include "ElunaIncludes.h" +#include "ElunaTemplate.h" +#include "ElunaCreatureAI.h" + +extern "C" +{ +#include "lua.h" +}; + diff --git a/HookMgr.h b/Hooks.h similarity index 90% rename from HookMgr.h rename to Hooks.h index f5d45fb..2c8531a 100644 --- a/HookMgr.h +++ b/Hooks.h @@ -1,13 +1,72 @@ /* -* Copyright (C) 2010 - 2015 Eluna Lua Engine -* This program is free software licensed under GPL version 3 -* Please see the included DOCS/LICENSE.md for more information -*/ + * Copyright (C) 2010 - 2015 Eluna Lua Engine + * This program is free software licensed under GPL version 3 + * Please see the included DOCS/LICENSE.md for more information + */ -#ifndef LUAHOOKS_H -#define LUAHOOKS_H +#ifndef _HOOKS_H +#define _HOOKS_H -namespace HookMgr +/* + * A hook should be written in one of the following forms: + * + * A. If results will be IGNORED: + * + * // Return early if there are no bindings. + * if (!WhateverBindings->HasEvents(SOME_EVENT_TYPE)) + * return; + * + * // Lock out any other threads. + * LOCK_ELUNA; + * + * // Push extra arguments, if any. + * Push(a); + * Push(b); + * Push(c); + * + * // Call all event handlers. + * CallAllFunctions(WhateverBindings, SOME_EVENT_TYPE); + * + * + * B. If results will be USED: + * + * // Return early if there are no bindings. + * if (!WhateverBindings->HasEvents(SOME_EVENT_TYPE)) + * return; + * + * // Lock out any other threads. + * LOCK_ELUNA; + * + * // Push extra arguments, if any. + * Push(a); + * Push(b); + * Push(c); + * + * // Setup the stack and get the number of functions pushed. + * // Last argument is 3 because we did 3 Pushes. + * int n = SetupStack(WhateverBindings, SOME_EVENT_TYPE, 3); + * + * // Call each event handler in order and check results. + * while (n > 0) + * { + * // Call an event handler and decrement the function counter afterward. + * // Second-last argument is 3 because we did 3 Pushes. + * // Last argument is 2 because we want 2 results. + * int r = CallOneFunction(n--, 3, 2); + * + * // Results can be popped using `r`. + * int first = CHECKVAL(L, r + 0); + * int second = CHECKVAL(L, r + 1); + * + * // Pop the results off the stack. + * lua_pop(L, 2); + * } + * + * // Clean-up the stack. Argument is 3 because we did 3 Pushes. + * CleanUpStack(3); + */ + +namespace Hooks { enum RegisterTypes { @@ -28,7 +87,6 @@ namespace HookMgr REGTYPE_COUNT }; - // RegisterPacketEvent(Opcode, event, function) enum PacketEvents { PACKET_EVENT_ON_PACKET_RECEIVE = 5, // (event, packet, player) - Player only if accessible. Can return false, newPacket @@ -38,7 +96,6 @@ namespace HookMgr PACKET_EVENT_COUNT }; - // RegisterServerEvent(EventId, function) enum ServerEvents { // Server @@ -96,7 +153,6 @@ namespace HookMgr SERVER_EVENT_COUNT }; - // RegisterPlayerEvent(eventId, function) enum PlayerEvents { PLAYER_EVENT_ON_CHARACTER_CREATE = 1, // (event, player) @@ -147,7 +203,6 @@ namespace HookMgr PLAYER_EVENT_COUNT }; - // RegisterGuildEvent(eventId, function) enum GuildEvents { // Guild @@ -166,7 +221,6 @@ namespace HookMgr GUILD_EVENT_COUNT }; - // RegisterGroupEvent(eventId, function) enum GroupEvents { // Group @@ -180,7 +234,6 @@ namespace HookMgr GROUP_EVENT_COUNT }; - // RegisterVehicleEvent(eventId, function) enum VehicleEvents { VEHICLE_EVENT_ON_INSTALL = 1, // (event, vehicle) @@ -193,7 +246,6 @@ namespace HookMgr VEHICLE_EVENT_COUNT }; - // RegisterCreatureEvent(entry, EventId, function) enum CreatureEvents { CREATURE_EVENT_ON_ENTER_COMBAT = 1, // (event, creature, target) - Can return true to stop normal action @@ -236,7 +288,6 @@ namespace HookMgr CREATURE_EVENT_COUNT }; - // RegisterGameObjectEvent(entry, EventId, function) enum GameObjectEvents { GAMEOBJECT_EVENT_ON_AIUPDATE = 1, // (event, go, diff) @@ -256,7 +307,6 @@ namespace HookMgr GAMEOBJECT_EVENT_COUNT }; - // RegisterItemEvent(entry, EventId, function) enum ItemEvents { ITEM_EVENT_ON_DUMMY_EFFECT = 1, // (event, caster, spellid, effindex, item) - Can return true @@ -267,10 +317,6 @@ namespace HookMgr ITEM_EVENT_COUNT }; - // RegisterCreatureGossipEvent(entry, EventId, function) - // RegisterGameObjectGossipEvent(entry, EventId, function) - // RegisterItemGossipEvent(entry, EventId, function) - // RegisterPlayerGossipEvent(menu_id, EventId, function) enum GossipEvents { GOSSIP_EVENT_ON_HELLO = 1, // (event, player, object) - Object is the Creature/GameObject/Item. Can return false to do default action. For item gossip can return false to stop spell casting. @@ -278,7 +324,6 @@ namespace HookMgr GOSSIP_EVENT_COUNT }; - // RegisterBGEvent(EventId, function) enum BGEvents { BG_EVENT_ON_START = 1, // (event, bg, bgId, instanceId) - Needs to be added to TC @@ -288,4 +333,5 @@ namespace HookMgr BG_EVENT_COUNT }; }; -#endif + +#endif // _HOOKS_H \ No newline at end of file diff --git a/ItemHooks.cpp b/ItemHooks.cpp new file mode 100644 index 0000000..e357be6 --- /dev/null +++ b/ItemHooks.cpp @@ -0,0 +1,144 @@ +/* + * Copyright (C) 2010 - 2015 Eluna Lua Engine + * This program is free software licensed under GPL version 3 + * Please see the included DOCS/LICENSE.md for more information + */ + +#ifndef _ITEM_HOOKS_H +#define _ITEM_HOOKS_H + +#include "Hooks.h" +#include "HookHelpers.h" +#include "LuaEngine.h" +#include "ElunaBinding.h" +#include "ElunaIncludes.h" + +using namespace Hooks; + +bool Eluna::OnDummyEffect(Unit* pCaster, uint32 spellId, SpellEffIndex effIndex, Item* pTarget) +{ + if (!ItemEventBindings->HasEvents(ITEM_EVENT_ON_DUMMY_EFFECT, pTarget->GetEntry())) + return false; + + LOCK_ELUNA; + Push(pCaster); + Push(spellId); + Push(effIndex); + Push(pTarget); + return CallAllFunctionsBool(ItemEventBindings, ITEM_EVENT_ON_DUMMY_EFFECT, pTarget->GetEntry()); +} + +bool Eluna::OnQuestAccept(Player* pPlayer, Item* pItem, Quest const* pQuest) +{ + if (!ItemEventBindings->HasEvents(ITEM_EVENT_ON_QUEST_ACCEPT, pItem->GetEntry())) + return false; + + LOCK_ELUNA; + Push(pPlayer); + Push(pItem); + Push(pQuest); + return CallAllFunctionsBool(ItemEventBindings, ITEM_EVENT_ON_QUEST_ACCEPT, pItem->GetEntry()); +} + +bool Eluna::OnUse(Player* pPlayer, Item* pItem, SpellCastTargets const& targets) +{ + ObjectGuid guid = pItem->GET_GUID(); + bool castSpell = true; + + if (!OnItemUse(pPlayer, pItem, targets)) + castSpell = false; + + pItem = pPlayer->GetItemByGuid(guid); + if (pItem) + { + if (!OnItemGossip(pPlayer, pItem, targets)) + castSpell = false; + pItem = pPlayer->GetItemByGuid(guid); + } + + if (pItem && castSpell) + return true; + + // Send equip error that shows no message + // This is a hack fix to stop spell casting visual bug when a spell is not cast on use + WorldPacket data(SMSG_INVENTORY_CHANGE_FAILURE, 18); + data << uint8(59); // EQUIP_ERR_NONE / EQUIP_ERR_CANT_BE_DISENCHANTED + data << ObjectGuid(guid); + data << ObjectGuid(uint64(0)); + data << uint8(0); + pPlayer->GetSession()->SendPacket(&data); + return false; +} + +bool Eluna::OnItemUse(Player* pPlayer, Item* pItem, SpellCastTargets const& targets) +{ + if (!ItemEventBindings->HasEvents(ITEM_EVENT_ON_USE, pItem->GetEntry())) + return true; + + LOCK_ELUNA; + Push(pPlayer); + Push(pItem); +#ifndef TRINITY + if (GameObject* target = targets.getGOTarget()) + Push(target); + else if (Item* target = targets.getItemTarget()) + Push(target); + else if (Corpse* target = pPlayer->GetMap()->GetCorpse(targets.getCorpseTargetGuid())) + Push(target); + else if (Unit* target = targets.getUnitTarget()) + Push(target); + else + Push(); +#else + if (GameObject* target = targets.GetGOTarget()) + Push(target); + else if (Item* target = targets.GetItemTarget()) + Push(target); + else if (Corpse* target = targets.GetCorpseTarget()) + Push(target); + else if (Unit* target = targets.GetUnitTarget()) + Push(target); + else if (WorldObject* target = targets.GetObjectTarget()) + Push(target); + else + Push(); +#endif + + return CallAllFunctionsBool(ItemEventBindings, ITEM_EVENT_ON_USE, pItem->GetEntry(), true); +} + +bool Eluna::OnItemGossip(Player* pPlayer, Item* pItem, SpellCastTargets const& /*targets*/) +{ + if (!ItemGossipBindings->HasEvents(GOSSIP_EVENT_ON_HELLO, pItem->GetEntry())) + return true; + + LOCK_ELUNA; + pPlayer->PlayerTalkClass->ClearMenus(); + Push(pPlayer); + Push(pItem); + return CallAllFunctionsBool(ItemGossipBindings, GOSSIP_EVENT_ON_HELLO, pItem->GetEntry(), true); +} + +bool Eluna::OnExpire(Player* pPlayer, ItemTemplate const* pProto) +{ + if (!ItemEventBindings->HasEvents(ITEM_EVENT_ON_EXPIRE, pProto->ItemId)) + return false; + + LOCK_ELUNA; + Push(pPlayer); + Push(pProto->ItemId); + return CallAllFunctionsBool(ItemEventBindings, ITEM_EVENT_ON_EXPIRE, pProto->ItemId); +} + +bool Eluna::OnRemove(Player* pPlayer, Item* item) +{ + if (!ItemEventBindings->HasEvents(ITEM_EVENT_ON_REMOVE, item->GetEntry())) + return false; + + LOCK_ELUNA; + Push(pPlayer); + Push(item); + return CallAllFunctionsBool(ItemEventBindings, ITEM_EVENT_ON_REMOVE, item->GetEntry()); +} + +#endif // _ITEM_HOOKS_H \ No newline at end of file diff --git a/LuaEngine.cpp b/LuaEngine.cpp index dbf1c0c..60399d5 100644 --- a/LuaEngine.cpp +++ b/LuaEngine.cpp @@ -4,13 +4,14 @@ * Please see the included DOCS/LICENSE.md for more information */ -#include "HookMgr.h" +#include "Hooks.h" #include "LuaEngine.h" #include "ElunaBinding.h" #include "ElunaEventMgr.h" #include "ElunaIncludes.h" #include "ElunaTemplate.h" #include "ElunaUtility.h" +#include "ElunaCreatureAI.h" #ifdef USING_BOOST #include @@ -123,23 +124,23 @@ push_counter(0), eventMgr(NULL), -ServerEventBindings(new EventBind("ServerEvents", *this)), -PlayerEventBindings(new EventBind("PlayerEvents", *this)), -GuildEventBindings(new EventBind("GuildEvents", *this)), -GroupEventBindings(new EventBind("GroupEvents", *this)), -VehicleEventBindings(new EventBind("VehicleEvents", *this)), -BGEventBindings(new EventBind("BGEvents", *this)), +ServerEventBindings(new EventBind("ServerEvents", *this)), +PlayerEventBindings(new EventBind("PlayerEvents", *this)), +GuildEventBindings(new EventBind("GuildEvents", *this)), +GroupEventBindings(new EventBind("GroupEvents", *this)), +VehicleEventBindings(new EventBind("VehicleEvents", *this)), +BGEventBindings(new EventBind("BGEvents", *this)), -PacketEventBindings(new EntryBind("PacketEvents", *this)), -CreatureEventBindings(new EntryBind("CreatureEvents", *this)), -CreatureGossipBindings(new EntryBind("GossipEvents (creature)", *this)), -GameObjectEventBindings(new EntryBind("GameObjectEvents", *this)), -GameObjectGossipBindings(new EntryBind("GossipEvents (gameobject)", *this)), -ItemEventBindings(new EntryBind("ItemEvents", *this)), -ItemGossipBindings(new EntryBind("GossipEvents (item)", *this)), -playerGossipBindings(new EntryBind("GossipEvents (player)", *this)), +PacketEventBindings(new EntryBind("PacketEvents", *this)), +CreatureEventBindings(new EntryBind("CreatureEvents", *this)), +CreatureGossipBindings(new EntryBind("GossipEvents (creature)", *this)), +GameObjectEventBindings(new EntryBind("GameObjectEvents", *this)), +GameObjectGossipBindings(new EntryBind("GossipEvents (gameobject)", *this)), +ItemEventBindings(new EntryBind("ItemEvents", *this)), +ItemGossipBindings(new EntryBind("GossipEvents (item)", *this)), +playerGossipBindings(new EntryBind("GossipEvents (player)", *this)), -CreatureUniqueBindings(new UniqueBind("CreatureEvents", *this)) +CreatureUniqueBindings(new UniqueBind("CreatureEvents", *this)) { // open base lua libraries luaL_openlibs(L); @@ -767,56 +768,56 @@ void Eluna::Register(uint8 regtype, uint32 id, uint64 guid, uint32 instanceId, u { switch (regtype) { - case HookMgr::REGTYPE_SERVER: - if (evt < HookMgr::SERVER_EVENT_COUNT) + case Hooks::REGTYPE_SERVER: + if (evt < Hooks::SERVER_EVENT_COUNT) { ServerEventBindings->Insert(evt, functionRef, shots); return; } break; - case HookMgr::REGTYPE_PLAYER: - if (evt < HookMgr::PLAYER_EVENT_COUNT) + case Hooks::REGTYPE_PLAYER: + if (evt < Hooks::PLAYER_EVENT_COUNT) { PlayerEventBindings->Insert(evt, functionRef, shots); return; } break; - case HookMgr::REGTYPE_GUILD: - if (evt < HookMgr::GUILD_EVENT_COUNT) + case Hooks::REGTYPE_GUILD: + if (evt < Hooks::GUILD_EVENT_COUNT) { GuildEventBindings->Insert(evt, functionRef, shots); return; } break; - case HookMgr::REGTYPE_GROUP: - if (evt < HookMgr::GROUP_EVENT_COUNT) + case Hooks::REGTYPE_GROUP: + if (evt < Hooks::GROUP_EVENT_COUNT) { GroupEventBindings->Insert(evt, functionRef, shots); return; } break; - case HookMgr::REGTYPE_VEHICLE: - if (evt < HookMgr::VEHICLE_EVENT_COUNT) + case Hooks::REGTYPE_VEHICLE: + if (evt < Hooks::VEHICLE_EVENT_COUNT) { VehicleEventBindings->Insert(evt, functionRef, shots); return; } break; - case HookMgr::REGTYPE_BG: - if (evt < HookMgr::BG_EVENT_COUNT) + case Hooks::REGTYPE_BG: + if (evt < Hooks::BG_EVENT_COUNT) { BGEventBindings->Insert(evt, functionRef, shots); return; } break; - case HookMgr::REGTYPE_PACKET: - if (evt < HookMgr::PACKET_EVENT_COUNT) + case Hooks::REGTYPE_PACKET: + if (evt < Hooks::PACKET_EVENT_COUNT) { if (id >= NUM_MSG_TYPES) { @@ -830,8 +831,8 @@ void Eluna::Register(uint8 regtype, uint32 id, uint64 guid, uint32 instanceId, u } break; - case HookMgr::REGTYPE_CREATURE: - if (evt < HookMgr::CREATURE_EVENT_COUNT) + case Hooks::REGTYPE_CREATURE: + if (evt < Hooks::CREATURE_EVENT_COUNT) { if (id != 0) { @@ -853,8 +854,8 @@ void Eluna::Register(uint8 regtype, uint32 id, uint64 guid, uint32 instanceId, u } break; - case HookMgr::REGTYPE_CREATURE_GOSSIP: - if (evt < HookMgr::GOSSIP_EVENT_COUNT) + case Hooks::REGTYPE_CREATURE_GOSSIP: + if (evt < Hooks::GOSSIP_EVENT_COUNT) { if (!eObjectMgr->GetCreatureTemplate(id)) { @@ -868,8 +869,8 @@ void Eluna::Register(uint8 regtype, uint32 id, uint64 guid, uint32 instanceId, u } break; - case HookMgr::REGTYPE_GAMEOBJECT: - if (evt < HookMgr::GAMEOBJECT_EVENT_COUNT) + case Hooks::REGTYPE_GAMEOBJECT: + if (evt < Hooks::GAMEOBJECT_EVENT_COUNT) { if (!eObjectMgr->GetGameObjectTemplate(id)) { @@ -883,8 +884,8 @@ void Eluna::Register(uint8 regtype, uint32 id, uint64 guid, uint32 instanceId, u } break; - case HookMgr::REGTYPE_GAMEOBJECT_GOSSIP: - if (evt < HookMgr::GOSSIP_EVENT_COUNT) + case Hooks::REGTYPE_GAMEOBJECT_GOSSIP: + if (evt < Hooks::GOSSIP_EVENT_COUNT) { if (!eObjectMgr->GetGameObjectTemplate(id)) { @@ -898,8 +899,8 @@ void Eluna::Register(uint8 regtype, uint32 id, uint64 guid, uint32 instanceId, u } break; - case HookMgr::REGTYPE_ITEM: - if (evt < HookMgr::ITEM_EVENT_COUNT) + case Hooks::REGTYPE_ITEM: + if (evt < Hooks::ITEM_EVENT_COUNT) { if (!eObjectMgr->GetItemTemplate(id)) { @@ -913,8 +914,8 @@ void Eluna::Register(uint8 regtype, uint32 id, uint64 guid, uint32 instanceId, u } break; - case HookMgr::REGTYPE_ITEM_GOSSIP: - if (evt < HookMgr::GOSSIP_EVENT_COUNT) + case Hooks::REGTYPE_ITEM_GOSSIP: + if (evt < Hooks::GOSSIP_EVENT_COUNT) { if (!eObjectMgr->GetItemTemplate(id)) { @@ -928,8 +929,8 @@ void Eluna::Register(uint8 regtype, uint32 id, uint64 guid, uint32 instanceId, u } break; - case HookMgr::REGTYPE_PLAYER_GOSSIP: - if (evt < HookMgr::GOSSIP_EVENT_COUNT) + case Hooks::REGTYPE_PLAYER_GOSSIP: + if (evt < Hooks::GOSSIP_EVENT_COUNT) { playerGossipBindings->Insert(id, evt, functionRef, shots); return; @@ -939,3 +940,56 @@ void Eluna::Register(uint8 regtype, uint32 id, uint64 guid, uint32 instanceId, u luaL_unref(L, LUA_REGISTRYINDEX, functionRef); luaL_error(L, "Unknown event type (regtype %d, id %d, event %d)", regtype, id, evt); } + +/* + * Cleans up the stack, effectively undoing all Push calls and the Setup call. + */ +void Eluna::CleanUpStack(int number_of_arguments) +{ + // Stack: event_id, [arguments] + + lua_pop(L, number_of_arguments + 1); // Add 1 because the caller doesn't know about `event_id`. + // Stack: (empty) + + if (event_level == 0) + InvalidateObjects(); +} + +/* + * Call a single event handler that was put on the stack with `Setup` and removes it from the stack. + * + * The caller is responsible for keeping track of how many times this should be called. + */ +int Eluna::CallOneFunction(int number_of_functions, int number_of_arguments, int number_of_results) +{ + ++number_of_arguments; // Caller doesn't know about `event_id`. + ASSERT(number_of_functions > 0 && number_of_arguments > 0 && number_of_results >= 0); + // Stack: event_id, [arguments], [functions] + + int functions_top = lua_gettop(L); + int first_function_index = functions_top - number_of_functions + 1; + int arguments_top = first_function_index - 1; + int first_argument_index = arguments_top - number_of_arguments + 1; + + // Copy the arguments from the bottom of the stack to the top. + for (int argument_index = first_argument_index; argument_index <= arguments_top; ++argument_index) + { + lua_pushvalue(L, argument_index); + } + // Stack: event_id, [arguments], [functions], event_id, [arguments] + + ExecuteCall(number_of_arguments, number_of_results); + --functions_top; + // Stack: event_id, [arguments], [functions - 1], [results] + + return functions_top + 1; // Return the location of the first result (if any exist). +} + +CreatureAI* Eluna::GetAI(Creature* creature) +{ + if (CreatureEventBindings->HasEvents(creature->GetEntry()) || + CreatureUniqueBindings->HasEvents(creature->GET_GUID(), creature->GetInstanceId())) + return new ElunaCreatureAI(creature); + + return NULL; +} diff --git a/LuaEngine.h b/LuaEngine.h index c51c7ce..d0c5cd7 100644 --- a/LuaEngine.h +++ b/LuaEngine.h @@ -18,7 +18,7 @@ #endif #include "Weather.h" #include "World.h" -#include "HookMgr.h" +#include "Hooks.h" extern "C" { @@ -112,6 +112,7 @@ private: Eluna& operator=(const Eluna&); // Some helpers for hooks to call event handlers. + // The bodies of the templates are in HookHelpers.h, so if you want to use them you need to #include "HookHelpers.h". 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); @@ -183,23 +184,23 @@ public: EventMgr* eventMgr; - EventBind* ServerEventBindings; - EventBind* PlayerEventBindings; - EventBind* GuildEventBindings; - EventBind* GroupEventBindings; - EventBind* VehicleEventBindings; - EventBind* BGEventBindings; + EventBind* ServerEventBindings; + EventBind* PlayerEventBindings; + EventBind* GuildEventBindings; + EventBind* GroupEventBindings; + EventBind* VehicleEventBindings; + EventBind* BGEventBindings; - EntryBind* PacketEventBindings; - EntryBind* CreatureEventBindings; - EntryBind* CreatureGossipBindings; - EntryBind* GameObjectEventBindings; - EntryBind* GameObjectGossipBindings; - EntryBind* ItemEventBindings; - EntryBind* ItemGossipBindings; - EntryBind* playerGossipBindings; + EntryBind* PacketEventBindings; + EntryBind* CreatureEventBindings; + EntryBind* CreatureGossipBindings; + EntryBind* GameObjectEventBindings; + EntryBind* GameObjectGossipBindings; + EntryBind* ItemEventBindings; + EntryBind* ItemGossipBindings; + EntryBind* playerGossipBindings; - UniqueBind* CreatureUniqueBindings; + UniqueBind* CreatureUniqueBindings; Eluna(); ~Eluna(); @@ -235,16 +236,18 @@ public: static void Push(lua_State* luastate, const double); static void Push(lua_State* luastate, const std::string&); static void Push(lua_State* luastate, const char*); - template static void Push(lua_State* luastate, T const* ptr) - { - ElunaTemplate::Push(luastate, ptr); - } static void Push(lua_State* luastate, Object const* obj); static void Push(lua_State* luastate, WorldObject const* obj); static void Push(lua_State* luastate, Unit const* unit); static void Push(lua_State* luastate, Pet const* pet); static void Push(lua_State* luastate, TempSummon const* summon); + template + static void Push(lua_State* luastate, T const* ptr) + { + ElunaTemplate::Push(luastate, ptr); + } + // When a hook pushes arguments to be passed to event handlers // this is used to keep track of how many arguments were pushed. uint8 push_counter; @@ -263,7 +266,8 @@ public: void Push(const double value) { Push(L, value); ++push_counter; } void Push(const std::string& value) { Push(L, value); ++push_counter; } void Push(const char* value) { Push(L, value); ++push_counter; } - template void Push(T const* ptr){ Push(L, ptr); ++push_counter; } + template + void Push(T const* ptr) { Push(L, ptr); ++push_counter; } // Checks template static T CHECKVAL(lua_State* luastate, int narg); diff --git a/PlayerHooks.cpp b/PlayerHooks.cpp new file mode 100644 index 0000000..f80b73f --- /dev/null +++ b/PlayerHooks.cpp @@ -0,0 +1,719 @@ +/* + * Copyright (C) 2010 - 2015 Eluna Lua Engine + * This program is free software licensed under GPL version 3 + * Please see the included DOCS/LICENSE.md for more information + */ + +#ifndef _PLAYER_HOOKS_H +#define _PLAYER_HOOKS_H + +#include "Hooks.h" +#include "HookHelpers.h" +#include "LuaEngine.h" +#include "ElunaBinding.h" +#include "ElunaIncludes.h" + +using namespace Hooks; + +void Eluna::HandleGossipSelectOption(Player* pPlayer, Item* item, uint32 sender, uint32 action, const std::string& code) +{ + if (!ItemGossipBindings->HasEvents(GOSSIP_EVENT_ON_SELECT, item->GetEntry())) + return; + + LOCK_ELUNA; + pPlayer->PlayerTalkClass->ClearMenus(); + + Push(pPlayer); + Push(item); + Push(sender); + Push(action); + if (code.empty()) + Push(); + else + Push(code); + + CallAllFunctions(ItemGossipBindings, GOSSIP_EVENT_ON_SELECT, item->GetEntry()); +} + +void Eluna::HandleGossipSelectOption(Player* pPlayer, uint32 menuId, uint32 sender, uint32 action, const std::string& code) +{ + if (!playerGossipBindings->HasEvents(GOSSIP_EVENT_ON_SELECT, menuId)) + return; + + LOCK_ELUNA; + pPlayer->PlayerTalkClass->ClearMenus(); + + Push(pPlayer); // receiver + Push(pPlayer); // sender, just not to mess up the amount of args. + Push(sender); + Push(action); + if (code.empty()) + Push(); + else + Push(code); + + CallAllFunctions(playerGossipBindings, GOSSIP_EVENT_ON_SELECT, menuId); +} + +// Player +bool Eluna::OnCommand(Player* player, const char* text) +{ + // If from console, player is NULL + std::string fullcmd(text); + if (!player || player->GetSession()->GetSecurity() >= SEC_ADMINISTRATOR) + { + char* creload = strtok((char*)text, " "); + char* celuna = strtok(NULL, ""); + if (creload && celuna) + { + std::string reload(creload); + std::string eluna(celuna); + std::transform(reload.begin(), reload.end(), reload.begin(), ::tolower); + if (reload == "reload") + { + std::transform(eluna.begin(), eluna.end(), eluna.begin(), ::tolower); + if (std::string("eluna").find(eluna) == 0) + { + Eluna::reload = true; + return false; + } + } + } + } + + if (!PlayerEventBindings->HasEvents(PLAYER_EVENT_ON_COMMAND)) + return true; + + LOCK_ELUNA; + Push(player); + Push(fullcmd); + return CallAllFunctionsBool(PlayerEventBindings, PLAYER_EVENT_ON_COMMAND, true); +} + +void Eluna::OnLootItem(Player* pPlayer, Item* pItem, uint32 count, uint64 guid) +{ + if (!PlayerEventBindings->HasEvents(PLAYER_EVENT_ON_LOOT_ITEM)) + return; + + LOCK_ELUNA; + Push(pPlayer); + Push(pItem); + Push(count); + Push(guid); + CallAllFunctions(PlayerEventBindings, PLAYER_EVENT_ON_LOOT_ITEM); +} + +void Eluna::OnLootMoney(Player* pPlayer, uint32 amount) +{ + if (!PlayerEventBindings->HasEvents(PLAYER_EVENT_ON_LOOT_MONEY)) + return; + + LOCK_ELUNA; + Push(pPlayer); + Push(amount); + CallAllFunctions(PlayerEventBindings, PLAYER_EVENT_ON_LOOT_MONEY); +} + +void Eluna::OnFirstLogin(Player* pPlayer) +{ + if (!PlayerEventBindings->HasEvents(PLAYER_EVENT_ON_FIRST_LOGIN)) + return; + + LOCK_ELUNA; + Push(pPlayer); + CallAllFunctions(PlayerEventBindings, PLAYER_EVENT_ON_FIRST_LOGIN); +} + +void Eluna::OnRepop(Player* pPlayer) +{ + if (!PlayerEventBindings->HasEvents(PLAYER_EVENT_ON_REPOP)) + return; + + LOCK_ELUNA; + Push(pPlayer); + CallAllFunctions(PlayerEventBindings, PLAYER_EVENT_ON_REPOP); +} + +void Eluna::OnResurrect(Player* pPlayer) +{ + if (!PlayerEventBindings->HasEvents(PLAYER_EVENT_ON_RESURRECT)) + return; + + LOCK_ELUNA; + Push(pPlayer); + CallAllFunctions(PlayerEventBindings, PLAYER_EVENT_ON_RESURRECT); +} + +void Eluna::OnQuestAbandon(Player* pPlayer, uint32 questId) +{ + if (!PlayerEventBindings->HasEvents(PLAYER_EVENT_ON_QUEST_ABANDON)) + return; + + LOCK_ELUNA; + Push(pPlayer); + Push(questId); + CallAllFunctions(PlayerEventBindings, PLAYER_EVENT_ON_QUEST_ABANDON); +} + +void Eluna::OnEquip(Player* pPlayer, Item* pItem, uint8 bag, uint8 slot) +{ + if (!PlayerEventBindings->HasEvents(PLAYER_EVENT_ON_EQUIP)) + return; + + LOCK_ELUNA; + Push(pPlayer); + Push(pItem); + Push(bag); + Push(slot); + CallAllFunctions(PlayerEventBindings, PLAYER_EVENT_ON_EQUIP); +} + +InventoryResult Eluna::OnCanUseItem(const Player* pPlayer, uint32 itemEntry) +{ + if (!PlayerEventBindings->HasEvents(PLAYER_EVENT_ON_CAN_USE_ITEM)) + return EQUIP_ERR_OK; + + LOCK_ELUNA; + InventoryResult result = EQUIP_ERR_OK; + Push(pPlayer); + Push(itemEntry); + int n = SetupStack(PlayerEventBindings, PLAYER_EVENT_ON_CAN_USE_ITEM, 2); + + while (n > 0) + { + int r = CallOneFunction(n--, 2, 1); + + if (lua_isnumber(L, r)) + result = (InventoryResult)CHECKVAL(L, r); + + lua_pop(L, 1); + } + + CleanUpStack(2); + return result; +} +void Eluna::OnPlayerEnterCombat(Player* pPlayer, Unit* pEnemy) +{ + if (!PlayerEventBindings->HasEvents(PLAYER_EVENT_ON_ENTER_COMBAT)) + return; + + LOCK_ELUNA; + Push(pPlayer); + Push(pEnemy); + CallAllFunctions(PlayerEventBindings, PLAYER_EVENT_ON_ENTER_COMBAT); +} + +void Eluna::OnPlayerLeaveCombat(Player* pPlayer) +{ + if (!PlayerEventBindings->HasEvents(PLAYER_EVENT_ON_LEAVE_COMBAT)) + return; + + LOCK_ELUNA; + Push(pPlayer); + CallAllFunctions(PlayerEventBindings, PLAYER_EVENT_ON_LEAVE_COMBAT); +} + +void Eluna::OnPVPKill(Player* pKiller, Player* pKilled) +{ + if (!PlayerEventBindings->HasEvents(PLAYER_EVENT_ON_KILL_PLAYER)) + return; + + LOCK_ELUNA; + Push(pKiller); + Push(pKilled); + CallAllFunctions(PlayerEventBindings, PLAYER_EVENT_ON_KILL_PLAYER); +} + +void Eluna::OnCreatureKill(Player* pKiller, Creature* pKilled) +{ + if (!PlayerEventBindings->HasEvents(PLAYER_EVENT_ON_KILL_CREATURE)) + return; + + LOCK_ELUNA; + Push(pKiller); + Push(pKilled); + CallAllFunctions(PlayerEventBindings, PLAYER_EVENT_ON_KILL_CREATURE); +} + +void Eluna::OnPlayerKilledByCreature(Creature* pKiller, Player* pKilled) +{ + if (!PlayerEventBindings->HasEvents(PLAYER_EVENT_ON_KILLED_BY_CREATURE)) + return; + + LOCK_ELUNA; + Push(pKiller); + Push(pKilled); + CallAllFunctions(PlayerEventBindings, PLAYER_EVENT_ON_KILLED_BY_CREATURE); +} + +void Eluna::OnLevelChanged(Player* pPlayer, uint8 oldLevel) +{ + if (!PlayerEventBindings->HasEvents(PLAYER_EVENT_ON_LEVEL_CHANGE)) + return; + + LOCK_ELUNA; + Push(pPlayer); + Push(oldLevel); + CallAllFunctions(PlayerEventBindings, PLAYER_EVENT_ON_LEVEL_CHANGE); +} + +void Eluna::OnFreeTalentPointsChanged(Player* pPlayer, uint32 newPoints) +{ + if (!PlayerEventBindings->HasEvents(PLAYER_EVENT_ON_TALENTS_CHANGE)) + return; + + LOCK_ELUNA; + Push(pPlayer); + Push(newPoints); + CallAllFunctions(PlayerEventBindings, PLAYER_EVENT_ON_TALENTS_CHANGE); +} + +void Eluna::OnTalentsReset(Player* pPlayer, bool noCost) +{ + if (!PlayerEventBindings->HasEvents(PLAYER_EVENT_ON_TALENTS_RESET)) + return; + + LOCK_ELUNA; + Push(pPlayer); + Push(noCost); + CallAllFunctions(PlayerEventBindings, PLAYER_EVENT_ON_TALENTS_RESET); +} + +void Eluna::OnMoneyChanged(Player* pPlayer, int32& amount) +{ + if (!PlayerEventBindings->HasEvents(PLAYER_EVENT_ON_MONEY_CHANGE)) + return; + + LOCK_ELUNA; + Push(pPlayer); + Push(amount); + int amountIndex = lua_gettop(L); + int n = SetupStack(PlayerEventBindings, PLAYER_EVENT_ON_MONEY_CHANGE, 2); + + while (n > 0) + { + int r = CallOneFunction(n--, 2, 1); + + if (lua_isnumber(L, r)) + { + amount = CHECKVAL(L, r); + // Update the stack for subsequent calls. + ReplaceArgument(amount, amountIndex); + } + + lua_pop(L, 1); + } + + CleanUpStack(2); +} + +void Eluna::OnGiveXP(Player* pPlayer, uint32& amount, Unit* pVictim) +{ + if (!PlayerEventBindings->HasEvents(PLAYER_EVENT_ON_GIVE_XP)) + return; + + LOCK_ELUNA; + Push(pPlayer); + Push(amount); + Push(pVictim); + int amountIndex = lua_gettop(L) - 1; + int n = SetupStack(PlayerEventBindings, PLAYER_EVENT_ON_GIVE_XP, 3); + + while (n > 0) + { + int r = CallOneFunction(n--, 3, 1); + + if (lua_isnumber(L, r)) + { + amount = CHECKVAL(L, r); + // Update the stack for subsequent calls. + ReplaceArgument(amount, amountIndex); + } + + lua_pop(L, 1); + } + + CleanUpStack(3); +} + +void Eluna::OnReputationChange(Player* pPlayer, uint32 factionID, int32& standing, bool incremental) +{ + if (!PlayerEventBindings->HasEvents(PLAYER_EVENT_ON_REPUTATION_CHANGE)) + return; + + LOCK_ELUNA; + Push(pPlayer); + Push(factionID); + Push(standing); + Push(incremental); + int standingIndex = lua_gettop(L) - 1; + int n = SetupStack(PlayerEventBindings, PLAYER_EVENT_ON_REPUTATION_CHANGE, 4); + + while (n > 0) + { + int r = CallOneFunction(n--, 4, 1); + + if (lua_isnumber(L, r)) + { + standing = CHECKVAL(L, r); + // Update the stack for subsequent calls. + ReplaceArgument(standing, standingIndex); + } + + lua_pop(L, 1); + } + + CleanUpStack(4); +} + +void Eluna::OnDuelRequest(Player* pTarget, Player* pChallenger) +{ + if (!PlayerEventBindings->HasEvents(PLAYER_EVENT_ON_DUEL_REQUEST)) + return; + + LOCK_ELUNA; + Push(pTarget); + Push(pChallenger); + CallAllFunctions(PlayerEventBindings, PLAYER_EVENT_ON_DUEL_REQUEST); +} + +void Eluna::OnDuelStart(Player* pStarter, Player* pChallenger) +{ + if (!PlayerEventBindings->HasEvents(PLAYER_EVENT_ON_DUEL_START)) + return; + + LOCK_ELUNA; + Push(pStarter); + Push(pChallenger); + CallAllFunctions(PlayerEventBindings, PLAYER_EVENT_ON_DUEL_START); +} + +void Eluna::OnDuelEnd(Player* pWinner, Player* pLoser, DuelCompleteType type) +{ + if (!PlayerEventBindings->HasEvents(PLAYER_EVENT_ON_DUEL_END)) + return; + + LOCK_ELUNA; + Push(pWinner); + Push(pLoser); + Push(type); + CallAllFunctions(PlayerEventBindings, PLAYER_EVENT_ON_DUEL_END); +} + +void Eluna::OnEmote(Player* pPlayer, uint32 emote) +{ + if (!PlayerEventBindings->HasEvents(PLAYER_EVENT_ON_EMOTE)) + return; + + LOCK_ELUNA; + Push(pPlayer); + Push(emote); + CallAllFunctions(PlayerEventBindings, PLAYER_EVENT_ON_EMOTE); +} + +void Eluna::OnTextEmote(Player* pPlayer, uint32 textEmote, uint32 emoteNum, uint64 guid) +{ + if (!PlayerEventBindings->HasEvents(PLAYER_EVENT_ON_TEXT_EMOTE)) + return; + + LOCK_ELUNA; + Push(pPlayer); + Push(textEmote); + Push(emoteNum); + Push(guid); + CallAllFunctions(PlayerEventBindings, PLAYER_EVENT_ON_TEXT_EMOTE); +} + +void Eluna::OnSpellCast(Player* pPlayer, Spell* pSpell, bool skipCheck) +{ + if (!PlayerEventBindings->HasEvents(PLAYER_EVENT_ON_SPELL_CAST)) + return; + + LOCK_ELUNA; + Push(pPlayer); + Push(pSpell); + Push(skipCheck); + CallAllFunctions(PlayerEventBindings, PLAYER_EVENT_ON_SPELL_CAST); +} + +void Eluna::OnLogin(Player* pPlayer) +{ + if (!PlayerEventBindings->HasEvents(PLAYER_EVENT_ON_LOGIN)) + return; + + LOCK_ELUNA; + Push(pPlayer); + CallAllFunctions(PlayerEventBindings, PLAYER_EVENT_ON_LOGIN); +} + +void Eluna::OnLogout(Player* pPlayer) +{ + if (!PlayerEventBindings->HasEvents(PLAYER_EVENT_ON_LOGOUT)) + return; + + LOCK_ELUNA; + Push(pPlayer); + CallAllFunctions(PlayerEventBindings, PLAYER_EVENT_ON_LOGOUT); +} + +void Eluna::OnCreate(Player* pPlayer) +{ + if (!PlayerEventBindings->HasEvents(PLAYER_EVENT_ON_CHARACTER_CREATE)) + return; + + LOCK_ELUNA; + Push(pPlayer); + CallAllFunctions(PlayerEventBindings, PLAYER_EVENT_ON_CHARACTER_CREATE); +} + +void Eluna::OnDelete(uint32 guidlow) +{ + if (!PlayerEventBindings->HasEvents(PLAYER_EVENT_ON_CHARACTER_DELETE)) + return; + + LOCK_ELUNA; + Push(guidlow); + CallAllFunctions(PlayerEventBindings, PLAYER_EVENT_ON_CHARACTER_DELETE); +} + +void Eluna::OnSave(Player* pPlayer) +{ + if (!PlayerEventBindings->HasEvents(PLAYER_EVENT_ON_SAVE)) + return; + + LOCK_ELUNA; + Push(pPlayer); + CallAllFunctions(PlayerEventBindings, PLAYER_EVENT_ON_SAVE); +} + +void Eluna::OnBindToInstance(Player* pPlayer, Difficulty difficulty, uint32 mapid, bool permanent) +{ + if (!PlayerEventBindings->HasEvents(PLAYER_EVENT_ON_BIND_TO_INSTANCE)) + return; + + LOCK_ELUNA; + Push(pPlayer); + Push(difficulty); + Push(mapid); + Push(permanent); + CallAllFunctions(PlayerEventBindings, PLAYER_EVENT_ON_BIND_TO_INSTANCE); +} + +void Eluna::OnUpdateZone(Player* pPlayer, uint32 newZone, uint32 newArea) +{ + if (!PlayerEventBindings->HasEvents(PLAYER_EVENT_ON_UPDATE_ZONE)) + return; + + LOCK_ELUNA; + Push(pPlayer); + Push(newZone); + Push(newArea); + CallAllFunctions(PlayerEventBindings, PLAYER_EVENT_ON_UPDATE_ZONE); +} + +void Eluna::OnMapChanged(Player* player) +{ + if (!PlayerEventBindings->HasEvents(PLAYER_EVENT_ON_MAP_CHANGE)) + return; + + LOCK_ELUNA; + Push(player); + CallAllFunctions(PlayerEventBindings, PLAYER_EVENT_ON_MAP_CHANGE); +} + +// AddOns +bool Eluna::OnAddonMessage(Player* sender, uint32 type, std::string& msg, Player* receiver, Guild* guild, Group* group, Channel* channel) +{ + if (!ServerEventBindings->HasEvents(ADDON_EVENT_ON_MESSAGE)) + return true; + + LOCK_ELUNA; + Push(sender); + Push(type); + const char* c_msg = msg.c_str(); + Push(strtok((char*)c_msg, "\t")); // prefix + Push(strtok(NULL, "")); // msg + if (receiver) + Push(receiver); + else if (guild) + Push(guild); + else if (group) + Push(group); + else if (channel) + Push(channel->GetChannelId()); + else + Push(); + + return CallAllFunctionsBool(ServerEventBindings, ADDON_EVENT_ON_MESSAGE, true); +} + +bool Eluna::OnChat(Player* pPlayer, uint32 type, uint32 lang, std::string& msg) +{ + if (lang == LANG_ADDON) + return OnAddonMessage(pPlayer, type, msg, NULL, NULL, NULL, NULL); + + if (!PlayerEventBindings->HasEvents(PLAYER_EVENT_ON_CHAT)) + return true; + + LOCK_ELUNA; + bool result = true; + Push(pPlayer); + Push(msg); + Push(type); + Push(lang); + int n = SetupStack(PlayerEventBindings, PLAYER_EVENT_ON_CHAT, 4); + + while (n > 0) + { + int r = CallOneFunction(n--, 4, 2); + + if (lua_isboolean(L, r + 0) && !lua_toboolean(L, r + 0)) + result = false; + + if (lua_isstring(L, r + 1)) + msg = std::string(lua_tostring(L, r + 1)); + + lua_pop(L, 2); + } + + CleanUpStack(4); + return result; +} + +bool Eluna::OnChat(Player* pPlayer, uint32 type, uint32 lang, std::string& msg, Group* pGroup) +{ + if (lang == LANG_ADDON) + return OnAddonMessage(pPlayer, type, msg, NULL, NULL, pGroup, NULL); + + if (!PlayerEventBindings->HasEvents(PLAYER_EVENT_ON_GROUP_CHAT)) + return true; + + LOCK_ELUNA; + bool result = true; + Push(pPlayer); + Push(msg); + Push(type); + Push(lang); + Push(pGroup); + int n = SetupStack(PlayerEventBindings, PLAYER_EVENT_ON_GROUP_CHAT, 5); + + while (n > 0) + { + int r = CallOneFunction(n--, 5, 2); + + if (lua_isboolean(L, r + 0) && !lua_toboolean(L, r + 0)) + result = false; + + if (lua_isstring(L, r + 1)) + msg = std::string(lua_tostring(L, r + 1)); + + lua_pop(L, 2); + } + + CleanUpStack(5); + return result; +} + +bool Eluna::OnChat(Player* pPlayer, uint32 type, uint32 lang, std::string& msg, Guild* pGuild) +{ + if (lang == LANG_ADDON) + return OnAddonMessage(pPlayer, type, msg, NULL, pGuild, NULL, NULL); + + if (!PlayerEventBindings->HasEvents(PLAYER_EVENT_ON_GUILD_CHAT)) + return true; + + LOCK_ELUNA; + bool result = true; + Push(pPlayer); + Push(msg); + Push(type); + Push(lang); + Push(pGuild); + int n = SetupStack(PlayerEventBindings, PLAYER_EVENT_ON_GUILD_CHAT, 5); + + while (n > 0) + { + int r = CallOneFunction(n--, 5, 2); + + if (lua_isboolean(L, r + 0) && !lua_toboolean(L, r + 0)) + result = false; + + if (lua_isstring(L, r + 1)) + msg = std::string(lua_tostring(L, r + 1)); + + lua_pop(L, 2); + } + + CleanUpStack(5); + return result; +} + +bool Eluna::OnChat(Player* pPlayer, uint32 type, uint32 lang, std::string& msg, Channel* pChannel) +{ + if (lang == LANG_ADDON) + return OnAddonMessage(pPlayer, type, msg, NULL, NULL, NULL, pChannel); + + if (!PlayerEventBindings->HasEvents(PLAYER_EVENT_ON_CHANNEL_CHAT)) + return true; + + LOCK_ELUNA; + bool result = true; + Push(pPlayer); + Push(msg); + Push(type); + Push(lang); + Push(pChannel->GetChannelId()); + int n = SetupStack(PlayerEventBindings, PLAYER_EVENT_ON_CHANNEL_CHAT, 5); + + while (n > 0) + { + int r = CallOneFunction(n--, 5, 2); + + if (lua_isboolean(L, r + 0) && !lua_toboolean(L, r + 0)) + result = false; + + if (lua_isstring(L, r + 1)) + msg = std::string(lua_tostring(L, r + 1)); + + lua_pop(L, 2); + } + + CleanUpStack(5); + return result; +} + +bool Eluna::OnChat(Player* pPlayer, uint32 type, uint32 lang, std::string& msg, Player* pReceiver) +{ + if (lang == LANG_ADDON) + return OnAddonMessage(pPlayer, type, msg, pReceiver, NULL, NULL, NULL); + + if (!PlayerEventBindings->HasEvents(PLAYER_EVENT_ON_WHISPER)) + return true; + + LOCK_ELUNA; + bool result = true; + Push(pPlayer); + Push(msg); + Push(type); + Push(lang); + Push(pReceiver); + int n = SetupStack(PlayerEventBindings, PLAYER_EVENT_ON_WHISPER, 5); + + while (n > 0) + { + int r = CallOneFunction(n--, 5, 2); + + if (lua_isboolean(L, r + 0) && !lua_toboolean(L, r + 0)) + result = false; + + if (lua_isstring(L, r + 1)) + msg = std::string(lua_tostring(L, r + 1)); + + lua_pop(L, 2); + } + + CleanUpStack(5); + return result; +} + +#endif // _PLAYER_HOOKS_H \ No newline at end of file diff --git a/ServerHooks.cpp b/ServerHooks.cpp new file mode 100644 index 0000000..d041247 --- /dev/null +++ b/ServerHooks.cpp @@ -0,0 +1,386 @@ +/* + * Copyright (C) 2010 - 2015 Eluna Lua Engine + * This program is free software licensed under GPL version 3 + * Please see the included DOCS/LICENSE.md for more information + */ + +#ifndef _SERVER_HOOKS_H +#define _SERVER_HOOKS_H + +#include "Hooks.h" +#include "HookHelpers.h" +#include "LuaEngine.h" +#include "ElunaBinding.h" +#include "ElunaTemplate.h" // Needed to be able to push AuctionHouseObjects. +#include "ElunaEventMgr.h" + +using namespace Hooks; + +void Eluna::OnLuaStateClose() +{ + if (!ServerEventBindings->HasEvents(ELUNA_EVENT_ON_LUA_STATE_CLOSE)) + return; + + LOCK_ELUNA; + CallAllFunctions(ServerEventBindings, ELUNA_EVENT_ON_LUA_STATE_CLOSE); +} + +void Eluna::OnLuaStateOpen() +{ + if (!ServerEventBindings->HasEvents(ELUNA_EVENT_ON_LUA_STATE_OPEN)) + return; + + LOCK_ELUNA; + CallAllFunctions(ServerEventBindings, ELUNA_EVENT_ON_LUA_STATE_OPEN); +} + +// areatrigger +bool Eluna::OnAreaTrigger(Player* pPlayer, AreaTriggerEntry const* pTrigger) +{ + if (!ServerEventBindings->HasEvents(TRIGGER_EVENT_ON_TRIGGER)) + return false; + + LOCK_ELUNA; + Push(pPlayer); + Push(pTrigger->id); + return CallAllFunctionsBool(ServerEventBindings, TRIGGER_EVENT_ON_TRIGGER); +} + +// weather +void Eluna::OnChange(Weather* weather, uint32 zone, WeatherState state, float grade) +{ + if (!ServerEventBindings->HasEvents(WEATHER_EVENT_ON_CHANGE)) + return; + + LOCK_ELUNA; + Push(zone); + Push(state); + Push(grade); + CallAllFunctions(ServerEventBindings, WEATHER_EVENT_ON_CHANGE); +} + +// Auction House +void Eluna::OnAdd(AuctionHouseObject* ah) +{ + if (!ServerEventBindings->HasEvents(AUCTION_EVENT_ON_ADD)) + return; + + LOCK_ELUNA; + Push(ah); + CallAllFunctions(ServerEventBindings, AUCTION_EVENT_ON_ADD); +} + +void Eluna::OnRemove(AuctionHouseObject* ah) +{ + if (!ServerEventBindings->HasEvents(AUCTION_EVENT_ON_REMOVE)) + return; + + LOCK_ELUNA; + Push(ah); + CallAllFunctions(ServerEventBindings, AUCTION_EVENT_ON_REMOVE); +} + +void Eluna::OnSuccessful(AuctionHouseObject* ah) +{ + if (!ServerEventBindings->HasEvents(AUCTION_EVENT_ON_SUCCESSFUL)) + return; + + LOCK_ELUNA; + Push(ah); + CallAllFunctions(ServerEventBindings, AUCTION_EVENT_ON_SUCCESSFUL); +} + +void Eluna::OnExpire(AuctionHouseObject* ah) +{ + if (!ServerEventBindings->HasEvents(AUCTION_EVENT_ON_EXPIRE)) + return; + + LOCK_ELUNA; + Push(ah); + CallAllFunctions(ServerEventBindings, AUCTION_EVENT_ON_EXPIRE); +} + +// Packet +bool Eluna::OnPacketSend(WorldSession* session, WorldPacket& packet) +{ + bool result = true; + Player* player = NULL; + if (session) + player = session->GetPlayer(); + OnPacketSendAny(player, packet, result); + OnPacketSendOne(player, packet, result); + return result; +} +void Eluna::OnPacketSendAny(Player* player, WorldPacket& packet, bool& result) +{ + if (!ServerEventBindings->HasEvents(SERVER_EVENT_ON_PACKET_SEND)) + return; + + LOCK_ELUNA; + Push(new WorldPacket(packet)); + Push(player); + int n = SetupStack(ServerEventBindings, SERVER_EVENT_ON_PACKET_SEND, 2); + + while (n > 0) + { + int r = CallOneFunction(n--, 2, 2); + + if (lua_isboolean(L, r + 0) && !lua_toboolean(L, r + 0)) + result = false; + + if (lua_isuserdata(L, r + 1)) + if (WorldPacket* data = CHECKOBJ(L, r + 1, false)) + packet = *data; + + lua_pop(L, 2); + } + + CleanUpStack(2); +} + +void Eluna::OnPacketSendOne(Player* player, WorldPacket& packet, bool& result) +{ + if (!PacketEventBindings->HasEvents(PACKET_EVENT_ON_PACKET_SEND, packet.GetOpcode())) + return; + + LOCK_ELUNA; + Push(new WorldPacket(packet)); + Push(player); + int n = SetupStack(PacketEventBindings, PACKET_EVENT_ON_PACKET_SEND, OpcodesList(packet.GetOpcode()), 2); + + while (n > 0) + { + int r = CallOneFunction(n--, 2, 2); + + if (lua_isboolean(L, r + 0) && !lua_toboolean(L, r + 0)) + result = false; + + if (lua_isuserdata(L, r + 1)) + if (WorldPacket* data = CHECKOBJ(L, r + 1, false)) + packet = *data; + + lua_pop(L, 2); + } + + CleanUpStack(2); +} + +bool Eluna::OnPacketReceive(WorldSession* session, WorldPacket& packet) +{ + bool result = true; + Player* player = NULL; + if (session) + player = session->GetPlayer(); + OnPacketReceiveAny(player, packet, result); + OnPacketReceiveOne(player, packet, result); + return result; +} + +void Eluna::OnPacketReceiveAny(Player* player, WorldPacket& packet, bool& result) +{ + if (!ServerEventBindings->HasEvents(SERVER_EVENT_ON_PACKET_RECEIVE)) + return; + + LOCK_ELUNA; + Push(new WorldPacket(packet)); + Push(player); + int n = SetupStack(ServerEventBindings, SERVER_EVENT_ON_PACKET_RECEIVE, 2); + + while (n > 0) + { + int r = CallOneFunction(n--, 2, 2); + + if (lua_isboolean(L, r + 0) && !lua_toboolean(L, r + 0)) + result = false; + + if (lua_isuserdata(L, r + 1)) + if (WorldPacket* data = CHECKOBJ(L, r + 1, false)) + packet = *data; + + lua_pop(L, 2); + } + + CleanUpStack(2); +} + +void Eluna::OnPacketReceiveOne(Player* player, WorldPacket& packet, bool& result) +{ + if (!PacketEventBindings->HasEvents(PACKET_EVENT_ON_PACKET_RECEIVE, packet.GetOpcode())) + return; + + LOCK_ELUNA; + Push(new WorldPacket(packet)); + Push(player); + int n = SetupStack(PacketEventBindings, PACKET_EVENT_ON_PACKET_RECEIVE, OpcodesList(), 2); + + while (n > 0) + { + int r = CallOneFunction(n--, 2, 2); + + if (lua_isboolean(L, r + 0) && !lua_toboolean(L, r + 0)) + result = false; + + if (lua_isuserdata(L, r + 1)) + if (WorldPacket* data = CHECKOBJ(L, r + 1, false)) + packet = *data; + + lua_pop(L, 2); + } + + CleanUpStack(2); +} + +void Eluna::OnOpenStateChange(bool open) +{ + if (!ServerEventBindings->HasEvents(WORLD_EVENT_ON_OPEN_STATE_CHANGE)) + return; + + LOCK_ELUNA; + Push(open); + CallAllFunctions(ServerEventBindings, WORLD_EVENT_ON_OPEN_STATE_CHANGE); +} + +void Eluna::OnConfigLoad(bool reload) +{ + if (!ServerEventBindings->HasEvents(WORLD_EVENT_ON_CONFIG_LOAD)) + return; + + LOCK_ELUNA; + Push(reload); + CallAllFunctions(ServerEventBindings, WORLD_EVENT_ON_CONFIG_LOAD); +} + +void Eluna::OnShutdownInitiate(ShutdownExitCode code, ShutdownMask mask) +{ + if (!ServerEventBindings->HasEvents(WORLD_EVENT_ON_SHUTDOWN_INIT)) + return; + + LOCK_ELUNA; + Push(code); + Push(mask); + CallAllFunctions(ServerEventBindings, WORLD_EVENT_ON_SHUTDOWN_INIT); +} + +void Eluna::OnShutdownCancel() +{ + if (!ServerEventBindings->HasEvents(WORLD_EVENT_ON_SHUTDOWN_CANCEL)) + return; + + LOCK_ELUNA; + CallAllFunctions(ServerEventBindings, WORLD_EVENT_ON_SHUTDOWN_CANCEL); +} + +void Eluna::OnWorldUpdate(uint32 diff) +{ + LOCK_ELUNA; + + if (reload) + { + ReloadEluna(); + return; + } + + eventMgr->globalProcessor->Update(diff); + + if (!ServerEventBindings->HasEvents(WORLD_EVENT_ON_UPDATE)) + return; + + Push(diff); + CallAllFunctions(ServerEventBindings, WORLD_EVENT_ON_UPDATE); +} + +void Eluna::OnStartup() +{ + if (!ServerEventBindings->HasEvents(WORLD_EVENT_ON_STARTUP)) + return; + + LOCK_ELUNA; + CallAllFunctions(ServerEventBindings, WORLD_EVENT_ON_STARTUP); +} + +void Eluna::OnShutdown() +{ + if (!ServerEventBindings->HasEvents(WORLD_EVENT_ON_SHUTDOWN)) + return; + + LOCK_ELUNA; + CallAllFunctions(ServerEventBindings, WORLD_EVENT_ON_SHUTDOWN); +} + +/* Map */ +void Eluna::OnCreate(Map* map) +{ + if (!ServerEventBindings->HasEvents(MAP_EVENT_ON_CREATE)) + return; + + LOCK_ELUNA; + Push(map); + CallAllFunctions(ServerEventBindings, MAP_EVENT_ON_CREATE); +} + +void Eluna::OnDestroy(Map* map) +{ + if (!ServerEventBindings->HasEvents(MAP_EVENT_ON_DESTROY)) + return; + + LOCK_ELUNA; + Push(map); + CallAllFunctions(ServerEventBindings, MAP_EVENT_ON_DESTROY); +} + +void Eluna::OnPlayerEnter(Map* map, Player* player) +{ + if (!ServerEventBindings->HasEvents(MAP_EVENT_ON_PLAYER_ENTER)) + return; + + LOCK_ELUNA; + Push(map); + Push(player); + CallAllFunctions(ServerEventBindings, MAP_EVENT_ON_PLAYER_ENTER); +} + +void Eluna::OnPlayerLeave(Map* map, Player* player) +{ + if (!ServerEventBindings->HasEvents(MAP_EVENT_ON_PLAYER_LEAVE)) + return; + + LOCK_ELUNA; + Push(map); + Push(player); + CallAllFunctions(ServerEventBindings, MAP_EVENT_ON_PLAYER_LEAVE); +} + +void Eluna::OnUpdate(Map* map, uint32 diff) +{ + if (!ServerEventBindings->HasEvents(MAP_EVENT_ON_UPDATE)) + return; + + LOCK_ELUNA; + // enable this for multithread + // eventMgr->globalProcessor->Update(diff); + Push(map); + Push(diff); + CallAllFunctions(ServerEventBindings, MAP_EVENT_ON_UPDATE); +} + +void Eluna::OnRemove(GameObject* gameobject) +{ + if (!ServerEventBindings->HasEvents(WORLD_EVENT_ON_DELETE_GAMEOBJECT)) + return; + + LOCK_ELUNA; + Push(gameobject); + CallAllFunctions(ServerEventBindings, WORLD_EVENT_ON_DELETE_GAMEOBJECT); +} + +void Eluna::OnRemove(Creature* creature) +{ + if (!ServerEventBindings->HasEvents(WORLD_EVENT_ON_DELETE_CREATURE)) + return; + + LOCK_ELUNA; + Push(creature); + CallAllFunctions(ServerEventBindings, WORLD_EVENT_ON_DELETE_CREATURE); +} + +#endif // _SERVER_HOOKS_H \ No newline at end of file diff --git a/VehicleHooks.cpp b/VehicleHooks.cpp new file mode 100644 index 0000000..a5db54d --- /dev/null +++ b/VehicleHooks.cpp @@ -0,0 +1,77 @@ +/* + * Copyright (C) 2010 - 2015 Eluna Lua Engine + * This program is free software licensed under GPL version 3 + * Please see the included DOCS/LICENSE.md for more information + */ + +#ifndef _VEHICLE_HOOKS_H +#define _VEHICLE_HOOKS_H + +#ifndef CLASSIC +#ifndef TBC + +#include "Hooks.h" +#include "HookHelpers.h" +#include "LuaEngine.h" +#include "ElunaBinding.h" + +using namespace Hooks; + +// Vehicle +void Eluna::OnInstall(Vehicle* vehicle) +{ + if (!VehicleEventBindings->HasEvents(VEHICLE_EVENT_ON_INSTALL)) + return; + + LOCK_ELUNA; + Push(vehicle); + CallAllFunctions(VehicleEventBindings, VEHICLE_EVENT_ON_INSTALL); +} + +void Eluna::OnUninstall(Vehicle* vehicle) +{ + if (!VehicleEventBindings->HasEvents(VEHICLE_EVENT_ON_UNINSTALL)) + return; + + LOCK_ELUNA; + Push(vehicle); + CallAllFunctions(VehicleEventBindings, VEHICLE_EVENT_ON_UNINSTALL); +} + +void Eluna::OnInstallAccessory(Vehicle* vehicle, Creature* accessory) +{ + if (!VehicleEventBindings->HasEvents(VEHICLE_EVENT_ON_INSTALL_ACCESSORY)) + return; + + LOCK_ELUNA; + Push(vehicle); + Push(accessory); + CallAllFunctions(VehicleEventBindings, VEHICLE_EVENT_ON_INSTALL_ACCESSORY); +} + +void Eluna::OnAddPassenger(Vehicle* vehicle, Unit* passenger, int8 seatId) +{ + if (!VehicleEventBindings->HasEvents(VEHICLE_EVENT_ON_ADD_PASSENGER)) + return; + + LOCK_ELUNA; + Push(vehicle); + Push(passenger); + Push(seatId); + CallAllFunctions(VehicleEventBindings, VEHICLE_EVENT_ON_ADD_PASSENGER); +} + +void Eluna::OnRemovePassenger(Vehicle* vehicle, Unit* passenger) +{ + if (!VehicleEventBindings->HasEvents(VEHICLE_EVENT_ON_REMOVE_PASSENGER)) + return; + + LOCK_ELUNA; + Push(vehicle); + Push(passenger); + CallAllFunctions(VehicleEventBindings, VEHICLE_EVENT_ON_REMOVE_PASSENGER); +} + +#endif // CLASSIC +#endif // TBC +#endif // _VEHICLE_HOOKS_H \ No newline at end of file