From 9575a970f388da6ab969fab2666585deccaf1d94 Mon Sep 17 00:00:00 2001 From: Patman64 Date: Mon, 19 Jan 2015 00:29:43 -0500 Subject: [PATCH] Move hooks to separate files. --- BattleGroundHooks.cpp | 67 ++ CreatureHooks.cpp | 486 ++++++++ GameObjectHooks.cpp | 211 ++++ GlobalMethods.h | 28 +- GroupHooks.cpp | 85 ++ GuildHooks.cpp | 193 ++++ HookHelpers.h | 129 +++ HookMgr.cpp | 2446 ----------------------------------------- Hooks.cpp | 19 + HookMgr.h => Hooks.h | 90 +- ItemHooks.cpp | 144 +++ LuaEngine.cpp | 142 ++- LuaEngine.h | 46 +- PlayerHooks.cpp | 719 ++++++++++++ ServerHooks.cpp | 386 +++++++ VehicleHooks.cpp | 77 ++ 16 files changed, 2721 insertions(+), 2547 deletions(-) create mode 100644 BattleGroundHooks.cpp create mode 100644 CreatureHooks.cpp create mode 100644 GameObjectHooks.cpp create mode 100644 GroupHooks.cpp create mode 100644 GuildHooks.cpp create mode 100644 HookHelpers.h delete mode 100644 HookMgr.cpp create mode 100644 Hooks.cpp rename HookMgr.h => Hooks.h (90%) create mode 100644 ItemHooks.cpp create mode 100644 PlayerHooks.cpp create mode 100644 ServerHooks.cpp create mode 100644 VehicleHooks.cpp 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