Files
mod-ale/HookMgr.cpp
Rochet2 b1f85bfc21 Eluna
Improved pushing so that a single userdata is used per object pushed.
Made everything use the singleton less, allowing more free code and easier to implement multithreading later.
Made macros for hookmgr and fixed the issue with hooks called inside hooks.
2014-06-29 21:28:49 +02:00

1766 lines
48 KiB
C++

/*
* Copyright (C) 2010 - 2014 Eluna Lua Engine <http://emudevs.com/>
* 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 "Includes.h"
/*
Call model for EventBind:
// Begin the call if should
EVENT_BEGIN(bindmap, eventid, return returnvalue);
// push arguments
Push(L, pPlayer);
EVENT_EXECUTE(returnedargs);
FOR_RET(iter)
{
// process returned arguments
}
ENDCALL();
*/
// RET is a return statement
#define EVENT_BEGIN(BINDMAP, EVENT, RET) \
if (!BINDMAP->HasEvents(EVENT)) \
RET; \
lua_State* L = sEluna->L; \
uint32 _LuaEvent = EVENT; \
int _LuaStackTop = lua_gettop(L); \
EventBind* _LuaBindMap = sEluna->BINDMAP; \
Eluna::Push(L, _LuaEvent);
// use LUA_MULTRET for multiple return values
// return values will be at top of stack if any
#define EVENT_EXECUTE(RETVALS) \
int _LuaReturnValues = RETVALS; \
int _LuaParams = lua_gettop(L) - _LuaStackTop; \
if (_LuaParams < 1) \
{ \
ELUNA_LOG_ERROR("[Eluna]: Executing event %u, params was %i. Report to devs", _LuaEvent, _LuaParams); \
} \
for (EventBind::ElunaBindingMap::const_iterator it = _LuaBindMap->Bindings[_LuaEvent].begin(); it != _LuaBindMap->Bindings[_LuaEvent].end(); ++it) \
{ \
lua_rawgeti(L, LUA_REGISTRYINDEX, (*it)); \
int stacktop = lua_gettop(L); \
for (int i = stacktop - _LuaParams; i < stacktop; ++i) \
lua_pushvalue(L, i); \
Eluna::ExecuteCall(L, _LuaParams, _LuaReturnValues); \
} \
for (int i = _LuaParams; i > 0; --i) \
if (!lua_isnone(L, i)) \
lua_remove(L, i);
// RET is a return statement
#define ENTRY_BEGIN(BINDMAP, ENTRY, EVENT, RET) \
int _Luabind = sEluna->BINDMAP->GetBind(ENTRY, EVENT); \
if (!_Luabind) \
RET; \
lua_State* L = sEluna->L; \
uint32 _LuaEvent = EVENT; \
int _LuaStackTop = lua_gettop(L); \
EntryBind* _LuaBindMap = sEluna->BINDMAP; \
lua_rawgeti(L, LUA_REGISTRYINDEX, _Luabind); \
Eluna::Push(L, _LuaEvent);
#define ENTRY_EXECUTE(RETVALS) \
int _LuaReturnValues = RETVALS; \
int _LuaParams = lua_gettop(L) - _LuaStackTop - 1; \
Eluna::ExecuteCall(L, _LuaParams, _LuaReturnValues);
#define FOR_RETS(IT) \
for (int IT = _LuaStackTop + 1; IT <= lua_gettop(L); ++IT)
#define ENDCALL() \
if (_LuaReturnValues != LUA_MULTRET && lua_gettop(L) != _LuaStackTop + _LuaReturnValues) \
{ \
ELUNA_LOG_ERROR("[Eluna]: Ending event %u, stack top was %i and was supposed to be %i. Report to devs", _LuaEvent, lua_gettop(L), _LuaStackTop); \
} \
lua_settop(L, _LuaStackTop);
void Eluna::OnLuaStateClose()
{
EVENT_BEGIN(ServerEventBindings, ELUNA_EVENT_ON_LUA_STATE_CLOSE, return);
EVENT_EXECUTE(0);
ENDCALL();
}
// areatrigger
bool Eluna::OnAreaTrigger(Player* pPlayer, AreaTriggerEntry const* pTrigger)
{
EVENT_BEGIN(ServerEventBindings, TRIGGER_EVENT_ON_TRIGGER, return false);
Push(L, pPlayer);
Push(L, pTrigger->id);
EVENT_EXECUTE(0);
ENDCALL();
return false;
}
// weather
void Eluna::OnChange(Weather* weather, WeatherState state, float grade)
{
EVENT_BEGIN(ServerEventBindings, WEATHER_EVENT_ON_CHANGE, return);
Push(L, weather->GetZone());
Push(L, state);
Push(L, grade);
EVENT_EXECUTE(0);
ENDCALL();
}
// Auction House
void Eluna::OnAdd(AuctionHouseObject* ah)
{
EVENT_BEGIN(ServerEventBindings, AUCTION_EVENT_ON_ADD, return);
Push(L, (ah));
EVENT_EXECUTE(0);
ENDCALL();
}
void Eluna::OnRemove(AuctionHouseObject* ah)
{
EVENT_BEGIN(ServerEventBindings, AUCTION_EVENT_ON_REMOVE, return);
Push(L, (ah));
EVENT_EXECUTE(0);
ENDCALL();
}
void Eluna::OnSuccessful(AuctionHouseObject* ah)
{
EVENT_BEGIN(ServerEventBindings, AUCTION_EVENT_ON_SUCCESSFUL, return);
Push(L, (ah));
EVENT_EXECUTE(0);
ENDCALL();
}
void Eluna::OnExpire(AuctionHouseObject* ah)
{
EVENT_BEGIN(ServerEventBindings, AUCTION_EVENT_ON_EXPIRE, return);
Push(L, (ah));
EVENT_EXECUTE(0);
ENDCALL();
}
// Packet
bool Eluna::OnPacketSend(WorldSession* session, WorldPacket& packet)
{
bool result = true;
Player* player = NULL;
if (session)
player = session->GetPlayer();
OnPacketSendOne(player, packet, result);
OnPacketSendOne(player, packet, result);
return result;
}
void Eluna::OnPacketSendAny(Player* player, WorldPacket& packet, bool& result)
{
EVENT_BEGIN(ServerEventBindings, SERVER_EVENT_ON_PACKET_SEND, return);
Push(L, new WorldPacket(packet));
Push(L, player);
EVENT_EXECUTE(2);
FOR_RETS(i)
{
if (lua_isnoneornil(L, i))
continue;
if (WorldPacket* data = CHECKOBJ<WorldPacket>(L, i, false))
packet = *data;
if (!CHECKVAL<bool>(L, i, true))
{
result = false;
break;
}
}
ENDCALL();
}
void Eluna::OnPacketSendOne(Player* player, WorldPacket& packet, bool& result)
{
ENTRY_BEGIN(PacketEventBindings, Opcodes(packet.GetOpcode()), SERVER_EVENT_ON_PACKET_SEND, return);
Push(L, new WorldPacket(packet));
Push(L, player);
ENTRY_EXECUTE(2);
FOR_RETS(i)
{
if (lua_isnoneornil(L, i))
continue;
if (WorldPacket* data = CHECKOBJ<WorldPacket>(L, i, false))
packet = *data;
if (!CHECKVAL<bool>(L, i, true))
{
result = false;
break;
}
}
ENDCALL();
}
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)
{
EVENT_BEGIN(ServerEventBindings, SERVER_EVENT_ON_PACKET_RECEIVE, return);
Push(L, new WorldPacket(packet));
Push(L, player);
EVENT_EXECUTE(2);
FOR_RETS(i)
{
if (lua_isnoneornil(L, i))
continue;
if (WorldPacket* data = CHECKOBJ<WorldPacket>(L, i, false))
packet = *data;
if (!CHECKVAL<bool>(L, i, true))
{
result = false;
break;
}
}
ENDCALL();
}
void Eluna::OnPacketReceiveOne(Player* player, WorldPacket& packet, bool& result)
{
ENTRY_BEGIN(PacketEventBindings, Opcodes(packet.GetOpcode()), SERVER_EVENT_ON_PACKET_RECEIVE, return);
Push(L, new WorldPacket(packet));
Push(L, player);
ENTRY_EXECUTE(2);
FOR_RETS(i)
{
if (lua_isnoneornil(L, i))
continue;
if (WorldPacket* data = CHECKOBJ<WorldPacket>(L, i, false))
packet = *data;
if (!CHECKVAL<bool>(L, i, true))
{
result = false;
break;
}
}
ENDCALL();
}
// AddOns
bool Eluna::OnAddonMessage(Player* sender, uint32 type, std::string& msg, Player* receiver, Guild* guild, Group* group, Channel* channel)
{
EVENT_BEGIN(ServerEventBindings, ADDON_EVENT_ON_MESSAGE, return false);
Push(L, sender);
Push(L, type);
const char* c_msg = msg.c_str();
Push(L, strtok((char*)c_msg, "\t")); // prefix
Push(L, strtok(NULL, "")); // msg
if (receiver)
Push(L, receiver);
else if (guild)
Push(L, guild);
else if (group)
Push(L, group);
else if (channel)
Push(L, channel->GetChannelId());
else
Push(L);
EVENT_EXECUTE(0);
ENDCALL();
return true;
}
void Eluna::OnOpenStateChange(bool open)
{
EVENT_BEGIN(ServerEventBindings, WORLD_EVENT_ON_OPEN_STATE_CHANGE, return);
Push(L, open);
EVENT_EXECUTE(0);
ENDCALL();
}
void Eluna::OnConfigLoad(bool reload)
{
EVENT_BEGIN(ServerEventBindings, WORLD_EVENT_ON_CONFIG_LOAD, return);
Push(L, reload);
EVENT_EXECUTE(0);
ENDCALL();
}
void Eluna::OnShutdownInitiate(ShutdownExitCode code, ShutdownMask mask)
{
EVENT_BEGIN(ServerEventBindings, WORLD_EVENT_ON_SHUTDOWN_INIT, return);
Push(L, code);
Push(L, mask);
EVENT_EXECUTE(0);
ENDCALL();
}
void Eluna::OnShutdownCancel()
{
EVENT_BEGIN(ServerEventBindings, WORLD_EVENT_ON_SHUTDOWN_CANCEL, return);
EVENT_EXECUTE(0);
ENDCALL();
}
void Eluna::OnWorldUpdate(uint32 diff)
{
m_EventMgr->Update(diff);
EVENT_BEGIN(ServerEventBindings, WORLD_EVENT_ON_UPDATE, return);
Push(L, diff);
EVENT_EXECUTE(0);
ENDCALL();
}
void Eluna::OnStartup()
{
EVENT_BEGIN(ServerEventBindings, WORLD_EVENT_ON_STARTUP, return);
EVENT_EXECUTE(0);
ENDCALL();
}
void Eluna::OnShutdown()
{
EVENT_BEGIN(ServerEventBindings, WORLD_EVENT_ON_SHUTDOWN, return);
EVENT_EXECUTE(0);
ENDCALL();
}
void Eluna::HandleGossipSelectOption(Player* pPlayer, Item* item, uint32 sender, uint32 action, std::string code)
{
ENTRY_BEGIN(ItemGossipBindings, item->GetEntry(), GOSSIP_EVENT_ON_SELECT, return);
pPlayer->PlayerTalkClass->ClearMenus();
Push(L, pPlayer);
Push(L, item);
Push(L, sender);
Push(L, action);
if (code.empty())
Push(L);
else
Push(L, code);
ENTRY_EXECUTE(0);
ENDCALL();
}
void Eluna::HandleGossipSelectOption(Player* pPlayer, uint32 menuId, uint32 sender, uint32 action, std::string code)
{
ENTRY_BEGIN(playerGossipBindings, menuId, GOSSIP_EVENT_ON_SELECT, return);
pPlayer->PlayerTalkClass->ClearMenus();
Push(L, pPlayer); // receiver
Push(L, pPlayer); // sender, just not to mess up the amount of args.
Push(L, sender);
Push(L, action);
if (code.empty())
Push(L);
else
Push(L, code);
ENTRY_EXECUTE(0);
ENDCALL();
}
// item
bool Eluna::OnDummyEffect(Unit* pCaster, uint32 spellId, SpellEffIndex effIndex, Item* pTarget)
{
ENTRY_BEGIN(ItemEventBindings, pTarget->GetEntry(), ITEM_EVENT_ON_DUMMY_EFFECT, return false);
Push(L, pCaster);
Push(L, spellId);
Push(L, effIndex);
Push(L, pTarget);
ENTRY_EXECUTE(0);
ENDCALL();
return true;
}
bool Eluna::OnQuestAccept(Player* pPlayer, Item* pItem, Quest const* pQuest)
{
ENTRY_BEGIN(ItemEventBindings, pItem->GetEntry(), ITEM_EVENT_ON_QUEST_ACCEPT, return false);
Push(L, pPlayer);
Push(L, pItem);
Push(L, pQuest);
ENTRY_EXECUTE(0);
ENDCALL();
return true;
}
bool Eluna::OnUse(Player* pPlayer, Item* pItem, SpellCastTargets const& targets)
{
OnItemUse(pPlayer, pItem, targets);
OnItemGossip(pPlayer, pItem, targets);
// pPlayer->SendEquipError((InventoryResult)83, pItem, NULL);
// return true;
return false;
}
bool Eluna::OnItemUse(Player* pPlayer, Item* pItem, SpellCastTargets const& targets)
{
ENTRY_BEGIN(ItemEventBindings, pItem->GetEntry(), GOSSIP_EVENT_ON_HELLO, return false);
Push(L, pPlayer);
Push(L, pItem);
#ifdef MANGOS
if (GameObject* target = targets.getGOTarget())
Push(L, target);
else if (Item* target = targets.getItemTarget())
Push(L, target);
else if (Corpse* target = pPlayer->GetMap()->GetCorpse(targets.getCorpseTargetGuid()))
Push(L, target);
else if (Unit* target = targets.getUnitTarget())
Push(L, target);
else
Push(L);
#else
if (GameObject* target = targets.GetGOTarget())
Push(L, target);
else if (Item* target = targets.GetItemTarget())
Push(L, target);
else if (Corpse* target = targets.GetCorpseTarget())
Push(L, target);
else if (Unit* target = targets.GetUnitTarget())
Push(L, target);
else if (WorldObject* target = targets.GetObjectTarget())
Push(L, target);
else
Push(L);
#endif
ENTRY_EXECUTE(0);
ENDCALL();
return true;
}
bool Eluna::OnItemGossip(Player* pPlayer, Item* pItem, SpellCastTargets const& targets)
{
ENTRY_BEGIN(ItemEventBindings, pItem->GetEntry(), ITEM_EVENT_ON_USE, return false);
Push(L, pPlayer);
Push(L, pItem);
ENTRY_EXECUTE(0);
ENDCALL();
return true;
}
bool Eluna::OnExpire(Player* pPlayer, ItemTemplate const* pProto)
{
ENTRY_BEGIN(ItemEventBindings, pProto->ItemId, ITEM_EVENT_ON_EXPIRE, return false);
Push(L, pPlayer);
Push(L, pProto->ItemId);
ENTRY_EXECUTE(0);
ENDCALL();
return true;
}
bool Eluna::OnRemove(Player* pPlayer, Item* item)
{
ENTRY_BEGIN(ItemEventBindings, item->GetEntry(), ITEM_EVENT_ON_REMOVE, return false);
Push(L, pPlayer);
Push(L, item);
ENTRY_EXECUTE(0);
ENDCALL();
return true;
}
// Player
bool Eluna::OnCommand(Player* player, const char* text)
{
std::string fullcmd(text);
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)
{
sWorld->SendServerMessage(SERVER_MSG_STRING, "Reloading Eluna...");
ReloadEluna();
return false;
}
}
}
bool result = true;
EVENT_BEGIN(ServerEventBindings, PLAYER_EVENT_ON_COMMAND, return result);
Push(L, player);
Push(L, fullcmd);
EVENT_EXECUTE(1);
FOR_RETS(i)
{
if (lua_isnoneornil(L, i))
continue;
result = CHECKVAL<bool>(L, i, result);
}
ENDCALL();
return result;
}
void Eluna::OnLootItem(Player* pPlayer, Item* pItem, uint32 count, uint64 guid)
{
EVENT_BEGIN(PlayerEventBindings, PLAYER_EVENT_ON_LOOT_ITEM, return);
Push(L, pPlayer);
Push(L, pItem);
Push(L, count);
Push(L, guid);
EVENT_EXECUTE(0);
ENDCALL();
}
void Eluna::OnLootMoney(Player* pPlayer, uint32 amount)
{
EVENT_BEGIN(PlayerEventBindings, PLAYER_EVENT_ON_LOOT_MONEY, return);
Push(L, pPlayer);
Push(L, amount);
EVENT_EXECUTE(0);
ENDCALL();
}
void Eluna::OnFirstLogin(Player* pPlayer)
{
EVENT_BEGIN(PlayerEventBindings, PLAYER_EVENT_ON_FIRST_LOGIN, return);
Push(L, pPlayer);
EVENT_EXECUTE(0);
ENDCALL();
}
void Eluna::OnRepop(Player* pPlayer)
{
EVENT_BEGIN(PlayerEventBindings, PLAYER_EVENT_ON_REPOP, return);
Push(L, pPlayer);
EVENT_EXECUTE(0);
ENDCALL();
}
void Eluna::OnResurrect(Player* pPlayer)
{
EVENT_BEGIN(PlayerEventBindings, PLAYER_EVENT_ON_RESURRECT, return);
Push(L, pPlayer);
EVENT_EXECUTE(0);
ENDCALL();
}
void Eluna::OnQuestAbandon(Player* pPlayer, uint32 questId)
{
EVENT_BEGIN(PlayerEventBindings, PLAYER_EVENT_ON_QUEST_ABANDON, return);
Push(L, pPlayer);
Push(L, questId);
EVENT_EXECUTE(0);
ENDCALL();
}
void Eluna::OnEquip(Player* pPlayer, Item* pItem, uint8 bag, uint8 slot)
{
EVENT_BEGIN(PlayerEventBindings, PLAYER_EVENT_ON_EQUIP, return);
Push(L, pPlayer);
Push(L, pItem);
Push(L, bag);
Push(L, slot);
EVENT_EXECUTE(0);
ENDCALL();
}
InventoryResult Eluna::OnCanUseItem(const Player* pPlayer, uint32 itemEntry)
{
InventoryResult result = EQUIP_ERR_OK;
EVENT_BEGIN(PlayerEventBindings, PLAYER_EVENT_ON_CAN_USE_ITEM, return result);
Push(L, pPlayer);
Push(L, itemEntry);
EVENT_EXECUTE(1);
FOR_RETS(i)
{
if (lua_isnoneornil(L, i))
continue;
uint32 res = CHECKVAL<uint32>(L, i, EQUIP_ERR_OK);
if (res != EQUIP_ERR_OK)
result = (InventoryResult)res;
}
ENDCALL();
return result;
}
void Eluna::OnPlayerEnterCombat(Player* pPlayer, Unit* pEnemy)
{
EVENT_BEGIN(PlayerEventBindings, PLAYER_EVENT_ON_ENTER_COMBAT, return);
Push(L, pPlayer);
Push(L, pEnemy);
EVENT_EXECUTE(0);
ENDCALL();
}
void Eluna::OnPlayerLeaveCombat(Player* pPlayer)
{
EVENT_BEGIN(PlayerEventBindings, PLAYER_EVENT_ON_LEAVE_COMBAT, return);
Push(L, pPlayer);
EVENT_EXECUTE(0);
ENDCALL();
}
void Eluna::OnPVPKill(Player* pKiller, Player* pKilled)
{
EVENT_BEGIN(PlayerEventBindings, PLAYER_EVENT_ON_KILL_PLAYER, return);
Push(L, pKiller);
Push(L, pKilled);
EVENT_EXECUTE(0);
ENDCALL();
}
void Eluna::OnCreatureKill(Player* pKiller, Creature* pKilled)
{
EVENT_BEGIN(PlayerEventBindings, PLAYER_EVENT_ON_KILL_CREATURE, return);
Push(L, pKiller);
Push(L, pKilled);
EVENT_EXECUTE(0);
ENDCALL();
}
void Eluna::OnPlayerKilledByCreature(Creature* pKiller, Player* pKilled)
{
EVENT_BEGIN(PlayerEventBindings, PLAYER_EVENT_ON_KILLED_BY_CREATURE, return);
Push(L, pKiller);
Push(L, pKilled);
EVENT_EXECUTE(0);
ENDCALL();
}
void Eluna::OnLevelChanged(Player* pPlayer, uint8 oldLevel)
{
EVENT_BEGIN(PlayerEventBindings, PLAYER_EVENT_ON_LEVEL_CHANGE, return);
Push(L, pPlayer);
Push(L, oldLevel);
EVENT_EXECUTE(0);
ENDCALL();
}
void Eluna::OnFreeTalentPointsChanged(Player* pPlayer, uint32 newPoints)
{
EVENT_BEGIN(PlayerEventBindings, PLAYER_EVENT_ON_TALENTS_CHANGE, return);
Push(L, pPlayer);
Push(L, newPoints);
EVENT_EXECUTE(0);
ENDCALL();
}
void Eluna::OnTalentsReset(Player* pPlayer, bool noCost)
{
EVENT_BEGIN(PlayerEventBindings, PLAYER_EVENT_ON_TALENTS_RESET, return);
Push(L, pPlayer);
Push(L, noCost);
EVENT_EXECUTE(0);
ENDCALL();
}
void Eluna::OnMoneyChanged(Player* pPlayer, int32& amount)
{
EVENT_BEGIN(PlayerEventBindings, PLAYER_EVENT_ON_MONEY_CHANGE, return);
Push(L, pPlayer);
Push(L, amount);
EVENT_EXECUTE(0);
ENDCALL();
}
void Eluna::OnGiveXP(Player* pPlayer, uint32& amount, Unit* pVictim)
{
EVENT_BEGIN(PlayerEventBindings, PLAYER_EVENT_ON_GIVE_XP, return);
Push(L, pPlayer);
Push(L, amount);
Push(L, pVictim);
EVENT_EXECUTE(1);
FOR_RETS(i)
{
if (lua_isnoneornil(L, i))
continue;
amount = CHECKVAL<uint32>(L, i, amount);
}
ENDCALL();
}
void Eluna::OnReputationChange(Player* pPlayer, uint32 factionID, int32& standing, bool incremental)
{
EVENT_BEGIN(PlayerEventBindings, PLAYER_EVENT_ON_REPUTATION_CHANGE, return);
Push(L, pPlayer);
Push(L, factionID);
Push(L, standing);
Push(L, incremental);
EVENT_EXECUTE(1);
FOR_RETS(i)
{
if (lua_isnoneornil(L, i))
continue;
standing = CHECKVAL<uint32>(L, i, standing);
}
ENDCALL();
}
void Eluna::OnDuelRequest(Player* pTarget, Player* pChallenger)
{
EVENT_BEGIN(PlayerEventBindings, PLAYER_EVENT_ON_DUEL_REQUEST, return);
Push(L, pTarget);
Push(L, pChallenger);
EVENT_EXECUTE(0);
ENDCALL();
}
void Eluna::OnDuelStart(Player* pStarter, Player* pChallenger)
{
EVENT_BEGIN(PlayerEventBindings, PLAYER_EVENT_ON_DUEL_START, return);
Push(L, pStarter);
Push(L, pChallenger);
EVENT_EXECUTE(0);
ENDCALL();
}
void Eluna::OnDuelEnd(Player* pWinner, Player* pLoser, DuelCompleteType type)
{
EVENT_BEGIN(PlayerEventBindings, PLAYER_EVENT_ON_DUEL_END, return);
Push(L, pWinner);
Push(L, pLoser);
Push(L, type);
EVENT_EXECUTE(0);
ENDCALL();
}
void Eluna::OnEmote(Player* pPlayer, uint32 emote)
{
EVENT_BEGIN(PlayerEventBindings, PLAYER_EVENT_ON_EMOTE, return);
Push(L, pPlayer);
Push(L, emote);
EVENT_EXECUTE(0);
ENDCALL();
}
void Eluna::OnTextEmote(Player* pPlayer, uint32 textEmote, uint32 emoteNum, uint64 guid)
{
EVENT_BEGIN(PlayerEventBindings, PLAYER_EVENT_ON_TEXT_EMOTE, return);
Push(L, pPlayer);
Push(L, textEmote);
Push(L, emoteNum);
Push(L, guid);
EVENT_EXECUTE(0);
ENDCALL();
}
void Eluna::OnSpellCast(Player* pPlayer, Spell* pSpell, bool skipCheck)
{
EVENT_BEGIN(PlayerEventBindings, PLAYER_EVENT_ON_SPELL_CAST, return);
Push(L, pPlayer);
Push(L, pSpell);
Push(L, skipCheck);
EVENT_EXECUTE(0);
ENDCALL();
}
void Eluna::OnLogin(Player* pPlayer)
{
EVENT_BEGIN(PlayerEventBindings, PLAYER_EVENT_ON_LOGIN, return);
Push(L, pPlayer);
EVENT_EXECUTE(0);
ENDCALL();
}
void Eluna::OnLogout(Player* pPlayer)
{
EVENT_BEGIN(PlayerEventBindings, PLAYER_EVENT_ON_LOGOUT, return);
Push(L, pPlayer);
EVENT_EXECUTE(0);
ENDCALL();
}
void Eluna::OnCreate(Player* pPlayer)
{
EVENT_BEGIN(PlayerEventBindings, PLAYER_EVENT_ON_CHARACTER_CREATE, return);
Push(L, pPlayer);
EVENT_EXECUTE(0);
ENDCALL();
}
void Eluna::OnDelete(uint32 guidlow)
{
EVENT_BEGIN(PlayerEventBindings, PLAYER_EVENT_ON_CHARACTER_DELETE, return);
Push(L, guidlow);
EVENT_EXECUTE(0);
ENDCALL();
}
void Eluna::OnSave(Player* pPlayer)
{
EVENT_BEGIN(PlayerEventBindings, PLAYER_EVENT_ON_SAVE, return);
Push(L, pPlayer);
EVENT_EXECUTE(0);
ENDCALL();
}
void Eluna::OnBindToInstance(Player* pPlayer, Difficulty difficulty, uint32 mapid, bool permanent)
{
EVENT_BEGIN(PlayerEventBindings, PLAYER_EVENT_ON_BIND_TO_INSTANCE, return);
Push(L, pPlayer);
Push(L, difficulty);
Push(L, mapid);
Push(L, permanent);
EVENT_EXECUTE(0);
ENDCALL();
}
void Eluna::OnUpdateZone(Player* pPlayer, uint32 newZone, uint32 newArea)
{
EVENT_BEGIN(PlayerEventBindings, PLAYER_EVENT_ON_UPDATE_ZONE, return);
Push(L, pPlayer);
Push(L, newZone);
Push(L, newArea);
EVENT_EXECUTE(0);
ENDCALL();
}
void Eluna::OnMapChanged(Player* player)
{
EVENT_BEGIN(PlayerEventBindings, PLAYER_EVENT_ON_MAP_CHANGE, return);
Push(L, player);
EVENT_EXECUTE(0);
ENDCALL();
}
bool Eluna::OnChat(Player* pPlayer, uint32 type, uint32 lang, std::string& msg)
{
if (lang == LANG_ADDON && OnAddonMessage(pPlayer, type, msg, NULL, NULL, NULL, NULL))
return true;
bool result = true;
EVENT_BEGIN(PlayerEventBindings, PLAYER_EVENT_ON_CHAT, return result);
Push(L, pPlayer);
Push(L, msg);
Push(L, type);
Push(L, lang);
EVENT_EXECUTE(2);
FOR_RETS(i)
{
if (lua_isnoneornil(L, i))
continue;
if (const char* c_str = CHECKVAL<const char*>(L, i, NULL))
msg = std::string(c_str);
else if (!CHECKVAL<bool>(L, i, true))
{
result = false;
break;
}
}
ENDCALL();
return result;
}
bool Eluna::OnChat(Player* pPlayer, uint32 type, uint32 lang, std::string& msg, Group* pGroup)
{
if (lang == LANG_ADDON && OnAddonMessage(pPlayer, type, msg, NULL, NULL, pGroup, NULL))
return true;
bool result = true;
EVENT_BEGIN(PlayerEventBindings, PLAYER_EVENT_ON_GROUP_CHAT, return result);
Push(L, pPlayer);
Push(L, msg);
Push(L, type);
Push(L, lang);
Push(L, pGroup);
EVENT_EXECUTE(2);
FOR_RETS(i)
{
if (lua_isnoneornil(L, i))
continue;
if (const char* c_str = CHECKVAL<const char*>(L, i, NULL))
msg = std::string(c_str);
else if (!CHECKVAL<bool>(L, i, true))
{
result = false;
break;
}
}
ENDCALL();
return result;
}
bool Eluna::OnChat(Player* pPlayer, uint32 type, uint32 lang, std::string& msg, Guild* pGuild)
{
if (lang == LANG_ADDON && OnAddonMessage(pPlayer, type, msg, NULL, pGuild, NULL, NULL))
return true;
bool result = true;
EVENT_BEGIN(PlayerEventBindings, PLAYER_EVENT_ON_GUILD_CHAT, return result);
Push(L, pPlayer);
Push(L, msg);
Push(L, type);
Push(L, lang);
Push(L, pGuild);
EVENT_EXECUTE(2);
FOR_RETS(i)
{
if (lua_isnoneornil(L, i))
continue;
if (const char* c_str = CHECKVAL<const char*>(L, i, NULL))
msg = std::string(c_str);
else if (!CHECKVAL<bool>(L, i, true))
{
result = false;
break;
}
}
ENDCALL();
return result;
}
bool Eluna::OnChat(Player* pPlayer, uint32 type, uint32 lang, std::string& msg, Channel* pChannel)
{
if (lang == LANG_ADDON && OnAddonMessage(pPlayer, type, msg, NULL, NULL, NULL, pChannel))
return true;
bool result = true;
EVENT_BEGIN(PlayerEventBindings, PLAYER_EVENT_ON_CHANNEL_CHAT, return result);
Push(L, pPlayer);
Push(L, msg);
Push(L, type);
Push(L, lang);
Push(L, pChannel->GetChannelId());
EVENT_EXECUTE(2);
FOR_RETS(i)
{
if (lua_isnoneornil(L, i))
continue;
if (const char* c_str = CHECKVAL<const char*>(L, i, NULL))
msg = std::string(c_str);
else if (!CHECKVAL<bool>(L, i, true))
{
result = false;
break;
}
}
ENDCALL();
return result;
}
bool Eluna::OnChat(Player* pPlayer, uint32 type, uint32 lang, std::string& msg, Player* pReceiver)
{
if (lang == LANG_ADDON && OnAddonMessage(pPlayer, type, msg, pReceiver, NULL, NULL, NULL))
return true;
bool result = true;
EVENT_BEGIN(PlayerEventBindings, PLAYER_EVENT_ON_WHISPER, return result);
Push(L, pPlayer);
Push(L, msg);
Push(L, type);
Push(L, lang);
Push(L, pReceiver);
EVENT_EXECUTE(2);
FOR_RETS(i)
{
if (lua_isnoneornil(L, i))
continue;
if (const char* c_str = CHECKVAL<const char*>(L, i, NULL))
msg = std::string(c_str);
else if (!CHECKVAL<bool>(L, i, true))
{
result = false;
break;
}
}
ENDCALL();
return result;
}
#ifndef CLASSIC
#ifndef TBC
// Vehicle
void Eluna::OnInstall(Vehicle* vehicle)
{
EVENT_BEGIN(VehicleEventBindings, VEHICLE_EVENT_ON_INSTALL, return);
Push(L, vehicle);
EVENT_EXECUTE(0);
ENDCALL();
}
void Eluna::OnUninstall(Vehicle* vehicle)
{
EVENT_BEGIN(VehicleEventBindings, VEHICLE_EVENT_ON_UNINSTALL, return);
Push(L, vehicle);
EVENT_EXECUTE(0);
ENDCALL();
}
void Eluna::OnInstallAccessory(Vehicle* vehicle, Creature* accessory)
{
EVENT_BEGIN(VehicleEventBindings, VEHICLE_EVENT_ON_INSTALL_ACCESSORY, return);
Push(L, vehicle);
Push(L, accessory);
EVENT_EXECUTE(0);
ENDCALL();
}
void Eluna::OnAddPassenger(Vehicle* vehicle, Unit* passenger, int8 seatId)
{
EVENT_BEGIN(VehicleEventBindings, VEHICLE_EVENT_ON_ADD_PASSENGER, return);
Push(L, vehicle);
Push(L, passenger);
Push(L, seatId);
EVENT_EXECUTE(0);
ENDCALL();
}
void Eluna::OnRemovePassenger(Vehicle* vehicle, Unit* passenger)
{
EVENT_BEGIN(VehicleEventBindings, VEHICLE_EVENT_ON_REMOVE_PASSENGER, return);
Push(L, vehicle);
Push(L, passenger);
EVENT_EXECUTE(0);
ENDCALL();
}
#endif
#endif
void Eluna::OnAddMember(Guild* guild, Player* player, uint32 plRank)
{
EVENT_BEGIN(GuildEventBindings, GUILD_EVENT_ON_ADD_MEMBER, return);
Push(L, guild);
Push(L, player);
Push(L, plRank);
EVENT_EXECUTE(0);
ENDCALL();
}
void Eluna::OnRemoveMember(Guild* guild, Player* player, bool isDisbanding)
{
EVENT_BEGIN(GuildEventBindings, GUILD_EVENT_ON_REMOVE_MEMBER, return);
Push(L, guild);
Push(L, player);
Push(L, isDisbanding);
EVENT_EXECUTE(0);
ENDCALL();
}
void Eluna::OnMOTDChanged(Guild* guild, const std::string& newMotd)
{
EVENT_BEGIN(GuildEventBindings, GUILD_EVENT_ON_MOTD_CHANGE, return);
Push(L, guild);
Push(L, newMotd);
EVENT_EXECUTE(0);
ENDCALL();
}
void Eluna::OnInfoChanged(Guild* guild, const std::string& newInfo)
{
EVENT_BEGIN(GuildEventBindings, GUILD_EVENT_ON_INFO_CHANGE, return);
Push(L, guild);
Push(L, newInfo);
EVENT_EXECUTE(0);
ENDCALL();
}
void Eluna::OnCreate(Guild* guild, Player* leader, const std::string& name)
{
EVENT_BEGIN(GuildEventBindings, GUILD_EVENT_ON_CREATE, return);
Push(L, guild);
Push(L, leader);
Push(L, name);
EVENT_EXECUTE(0);
ENDCALL();
}
void Eluna::OnDisband(Guild* guild)
{
EVENT_BEGIN(GuildEventBindings, GUILD_EVENT_ON_DISBAND, return);
Push(L, guild);
EVENT_EXECUTE(0);
ENDCALL();
}
void Eluna::OnMemberWitdrawMoney(Guild* guild, Player* player, uint32 &amount, bool isRepair) // isRepair not a part of Mangos, implement?
{
EVENT_BEGIN(GuildEventBindings, GUILD_EVENT_ON_MONEY_WITHDRAW, return);
Push(L, guild);
Push(L, player);
Push(L, amount);
Push(L, isRepair); // isRepair not a part of Mangos, implement?
EVENT_EXECUTE(0);
ENDCALL();
}
void Eluna::OnMemberDepositMoney(Guild* guild, Player* player, uint32 &amount)
{
EVENT_BEGIN(GuildEventBindings, GUILD_EVENT_ON_MONEY_DEPOSIT, return);
Push(L, guild);
Push(L, player);
Push(L, amount);
EVENT_EXECUTE(0);
ENDCALL();
}
void Eluna::OnItemMove(Guild* guild, Player* player, Item* pItem, bool isSrcBank, uint8 srcContainer, uint8 srcSlotId,
bool isDestBank, uint8 destContainer, uint8 destSlotId)
{
EVENT_BEGIN(GuildEventBindings, GUILD_EVENT_ON_ITEM_MOVE, return);
Push(L, guild);
Push(L, player);
Push(L, pItem);
Push(L, isSrcBank);
Push(L, srcContainer);
Push(L, srcSlotId);
Push(L, isDestBank);
Push(L, destContainer);
Push(L, destSlotId);
EVENT_EXECUTE(0);
ENDCALL();
}
void Eluna::OnEvent(Guild* guild, uint8 eventType, uint32 playerGuid1, uint32 playerGuid2, uint8 newRank)
{
EVENT_BEGIN(GuildEventBindings, GUILD_EVENT_ON_EVENT, return);
Push(L, guild);
Push(L, eventType);
Push(L, playerGuid1);
Push(L, playerGuid2);
Push(L, newRank);
EVENT_EXECUTE(0);
ENDCALL();
}
void Eluna::OnBankEvent(Guild* guild, uint8 eventType, uint8 tabId, uint32 playerGuid, uint32 itemOrMoney, uint16 itemStackCount, uint8 destTabId)
{
EVENT_BEGIN(GuildEventBindings, GUILD_EVENT_ON_BANK_EVENT, return);
Push(L, guild);
Push(L, eventType);
Push(L, tabId);
Push(L, playerGuid);
Push(L, itemOrMoney);
Push(L, itemStackCount);
Push(L, destTabId);
EVENT_EXECUTE(0);
ENDCALL();
}
// Group
void Eluna::OnAddMember(Group* group, uint64 guid)
{
EVENT_BEGIN(GroupEventBindings, GROUP_EVENT_ON_MEMBER_ADD, return);
Push(L, group);
Push(L, guid);
EVENT_EXECUTE(0);
ENDCALL();
}
void Eluna::OnInviteMember(Group* group, uint64 guid)
{
EVENT_BEGIN(GroupEventBindings, GROUP_EVENT_ON_MEMBER_INVITE, return);
Push(L, group);
Push(L, guid);
EVENT_EXECUTE(0);
ENDCALL();
}
void Eluna::OnRemoveMember(Group* group, uint64 guid, uint8 method)
{
EVENT_BEGIN(GroupEventBindings, GROUP_EVENT_ON_MEMBER_REMOVE, return);
Push(L, group);
Push(L, guid);
Push(L, method);
EVENT_EXECUTE(0);
ENDCALL();
}
void Eluna::OnChangeLeader(Group* group, uint64 newLeaderGuid, uint64 oldLeaderGuid)
{
EVENT_BEGIN(GroupEventBindings, GROUP_EVENT_ON_LEADER_CHANGE, return);
Push(L, group);
Push(L, newLeaderGuid);
Push(L, oldLeaderGuid);
EVENT_EXECUTE(0);
ENDCALL();
}
void Eluna::OnDisband(Group* group)
{
EVENT_BEGIN(GroupEventBindings, GROUP_EVENT_ON_DISBAND, return);
Push(L, group);
EVENT_EXECUTE(0);
ENDCALL();
}
void Eluna::OnCreate(Group* group, uint64 leaderGuid, GroupType groupType)
{
EVENT_BEGIN(GroupEventBindings, GROUP_EVENT_ON_CREATE, return);
Push(L, group);
Push(L, leaderGuid);
Push(L, groupType);
EVENT_EXECUTE(0);
ENDCALL();
}
/* Map */
void Eluna::OnCreate(Map* map)
{
EVENT_BEGIN(ServerEventBindings, MAP_EVENT_ON_CREATE, return);
Push(L, map);
EVENT_EXECUTE(0);
ENDCALL();
}
void Eluna::OnDestroy(Map* map)
{
EVENT_BEGIN(ServerEventBindings, MAP_EVENT_ON_DESTROY, return);
Push(L, map);
EVENT_EXECUTE(0);
ENDCALL();
}
void Eluna::OnPlayerEnter(Map* map, Player* player)
{
EVENT_BEGIN(ServerEventBindings, MAP_EVENT_ON_PLAYER_ENTER, return);
Push(L, map);
Push(L, player);
EVENT_EXECUTE(0);
ENDCALL();
}
void Eluna::OnPlayerLeave(Map* map, Player* player)
{
EVENT_BEGIN(ServerEventBindings, MAP_EVENT_ON_PLAYER_LEAVE, return);
Push(L, map);
Push(L, player);
EVENT_EXECUTE(0);
ENDCALL();
}
void Eluna::OnUpdate(Map* map, uint32 diff)
{
EVENT_BEGIN(ServerEventBindings, MAP_EVENT_ON_UPDATE, return);
Push(L, map);
Push(L, diff);
EVENT_EXECUTE(0);
ENDCALL();
}
// creature
bool Eluna::OnDummyEffect(Unit* pCaster, uint32 spellId, SpellEffIndex effIndex, Creature* pTarget)
{
ENTRY_BEGIN(CreatureEventBindings, pTarget->GetEntry(), CREATURE_EVENT_ON_DUMMY_EFFECT, return false);
Push(L, pCaster);
Push(L, spellId);
Push(L, effIndex);
Push(L, pTarget);
ENTRY_EXECUTE(0);
ENDCALL();
return true;
}
bool Eluna::OnGossipHello(Player* pPlayer, Creature* pCreature)
{
ENTRY_BEGIN(CreatureEventBindings, pCreature->GetEntry(), GOSSIP_EVENT_ON_HELLO, return false);
Push(L, pPlayer);
Push(L, pCreature);
ENTRY_EXECUTE(0);
ENDCALL();
return true;
}
bool Eluna::OnGossipSelect(Player* pPlayer, Creature* pCreature, uint32 sender, uint32 action)
{
ENTRY_BEGIN(CreatureEventBindings, pCreature->GetEntry(), GOSSIP_EVENT_ON_SELECT, return false);
pPlayer->PlayerTalkClass->ClearMenus();
Push(L, pPlayer);
Push(L, pCreature);
Push(L, sender);
Push(L, action);
ENTRY_EXECUTE(0);
ENDCALL();
return true;
}
bool Eluna::OnGossipSelectCode(Player* pPlayer, Creature* pCreature, uint32 sender, uint32 action, const char* code)
{
ENTRY_BEGIN(CreatureEventBindings, pCreature->GetEntry(), GOSSIP_EVENT_ON_SELECT, return false);
pPlayer->PlayerTalkClass->ClearMenus();
Push(L, pPlayer);
Push(L, pCreature);
Push(L, sender);
Push(L, action);
Push(L, code);
ENTRY_EXECUTE(0);
ENDCALL();
return true;
}
bool Eluna::OnQuestAccept(Player* pPlayer, Creature* pCreature, Quest const* pQuest)
{
ENTRY_BEGIN(CreatureEventBindings, pCreature->GetEntry(), CREATURE_EVENT_ON_QUEST_ACCEPT, return false);
Push(L, pPlayer);
Push(L, pCreature);
Push(L, pQuest);
ENTRY_EXECUTE(0);
ENDCALL();
return true;
}
bool Eluna::OnQuestComplete(Player* pPlayer, Creature* pCreature, Quest const* pQuest)
{
ENTRY_BEGIN(CreatureEventBindings, pCreature->GetEntry(), CREATURE_EVENT_ON_QUEST_COMPLETE, return false);
Push(L, pPlayer);
Push(L, pCreature);
Push(L, pQuest);
ENTRY_EXECUTE(0);
ENDCALL();
return true;
}
bool Eluna::OnQuestReward(Player* pPlayer, Creature* pCreature, Quest const* pQuest)
{
ENTRY_BEGIN(CreatureEventBindings, pCreature->GetEntry(), CREATURE_EVENT_ON_QUEST_REWARD, return false);
Push(L, pPlayer);
Push(L, pCreature);
Push(L, pQuest);
ENTRY_EXECUTE(0);
ENDCALL();
return true;
}
uint32 Eluna::GetDialogStatus(Player* pPlayer, Creature* pCreature)
{
ENTRY_BEGIN(CreatureEventBindings, pCreature->GetEntry(), CREATURE_EVENT_ON_DIALOG_STATUS, return 0);
Push(L, pPlayer);
Push(L, pCreature);
ENTRY_EXECUTE(0);
ENDCALL();
return DIALOG_STATUS_SCRIPTED_NO_STATUS;
}
void Eluna::OnSummoned(Creature* pCreature, Unit* pSummoner)
{
ENTRY_BEGIN(CreatureEventBindings, pCreature->GetEntry(), CREATURE_EVENT_ON_SUMMONED, return);
Push(L, pCreature);
Push(L, pSummoner);
ENTRY_EXECUTE(0);
ENDCALL();
}
struct ElunaCreatureAI : ScriptedAI
{
#ifdef MANGOS
#define me m_creature
#endif
ElunaCreatureAI(Creature* creature): ScriptedAI(creature)
{
JustRespawned();
}
~ElunaCreatureAI() {}
//Called at World update tick
#ifdef MANGOS
void UpdateAI(const uint32 diff) override
#else
void UpdateAI(uint32 diff) override
#endif
{
#ifdef MANGOS
if (IsCombatMovement())
ScriptedAI::UpdateAI(diff);
#else
if (!me->HasReactState(REACT_PASSIVE))
ScriptedAI::UpdateAI(diff);
#endif
ENTRY_BEGIN(CreatureEventBindings, me->GetEntry(), CREATURE_EVENT_ON_AIUPDATE, return);
Eluna::Push(L, me);
Eluna::Push(L, diff);
ENTRY_EXECUTE(0);
ENDCALL();
}
//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
void EnterCombat(Unit* target) override
{
ScriptedAI::EnterCombat(target);
ENTRY_BEGIN(CreatureEventBindings, me->GetEntry(), CREATURE_EVENT_ON_ENTER_COMBAT, return);
Eluna::Push(L, me);
Eluna::Push(L, target);
ENTRY_EXECUTE(0);
ENDCALL();
}
// Called at any Damage from any attacker (before damage apply)
void DamageTaken(Unit* attacker, uint32& damage) override
{
ScriptedAI::DamageTaken(attacker, damage);
ENTRY_BEGIN(CreatureEventBindings, me->GetEntry(), CREATURE_EVENT_ON_DAMAGE_TAKEN, return);
Eluna::Push(L, me);
Eluna::Push(L, attacker);
Eluna::Push(L, damage);
ENTRY_EXECUTE(0);
ENDCALL();
}
//Called at creature death
void JustDied(Unit* killer) override
{
ScriptedAI::JustDied(killer);
On_Reset();
ENTRY_BEGIN(CreatureEventBindings, me->GetEntry(), CREATURE_EVENT_ON_DIED, return);
Eluna::Push(L, me);
Eluna::Push(L, killer);
ENTRY_EXECUTE(0);
ENDCALL();
}
//Called at creature killing another unit
void KilledUnit(Unit* victim) override
{
ScriptedAI::KilledUnit(victim);
ENTRY_BEGIN(CreatureEventBindings, me->GetEntry(), CREATURE_EVENT_ON_TARGET_DIED, return);
Eluna::Push(L, me);
Eluna::Push(L, victim);
ENTRY_EXECUTE(0);
ENDCALL();
}
// Called when the creature summon successfully other creature
void JustSummoned(Creature* summon) override
{
ScriptedAI::JustSummoned(summon);
ENTRY_BEGIN(CreatureEventBindings, me->GetEntry(), CREATURE_EVENT_ON_JUST_SUMMONED_CREATURE, return);
Eluna::Push(L, me);
Eluna::Push(L, summon);
ENTRY_EXECUTE(0);
ENDCALL();
}
// Called when a summoned creature is despawned
void SummonedCreatureDespawn(Creature* summon) override
{
ScriptedAI::SummonedCreatureDespawn(summon);
ENTRY_BEGIN(CreatureEventBindings, me->GetEntry(), CREATURE_EVENT_ON_SUMMONED_CREATURE_DESPAWN, return);
Eluna::Push(L, me);
Eluna::Push(L, summon);
ENTRY_EXECUTE(0);
ENDCALL();
}
//Called at waypoint reached or PointMovement end
void MovementInform(uint32 type, uint32 id) override
{
ScriptedAI::MovementInform(type, id);
ENTRY_BEGIN(CreatureEventBindings, me->GetEntry(), CREATURE_EVENT_ON_REACH_WP, return);
Eluna::Push(L, me);
Eluna::Push(L, type);
Eluna::Push(L, id);
ENTRY_EXECUTE(0);
ENDCALL();
}
// Called before EnterCombat even before the creature is in combat.
void AttackStart(Unit* target) override
{
ScriptedAI::AttackStart(target);
ENTRY_BEGIN(CreatureEventBindings, me->GetEntry(), CREATURE_EVENT_ON_PRE_COMBAT, return);
Eluna::Push(L, me);
Eluna::Push(L, target);
ENTRY_EXECUTE(0);
ENDCALL();
}
// Called for reaction at stopping attack at no attackers or targets
void EnterEvadeMode() override
{
ScriptedAI::EnterEvadeMode();
On_Reset();
ENTRY_BEGIN(CreatureEventBindings, me->GetEntry(), CREATURE_EVENT_ON_LEAVE_COMBAT, return);
Eluna::Push(L, me);
ENTRY_EXECUTE(0);
ENDCALL();
}
// Called when the creature is target of hostile action: swing, hostile spell landed, fear/etc)
void AttackedBy(Unit* attacker) override
{
ScriptedAI::AttackedBy(attacker);
ENTRY_BEGIN(CreatureEventBindings, me->GetEntry(), CREATURE_EVENT_ON_ATTACKED_AT, return);
Eluna::Push(L, me);
Eluna::Push(L, attacker);
ENTRY_EXECUTE(0);
ENDCALL();
}
// Called when creature is spawned or respawned (for reseting variables)
void JustRespawned() override
{
ScriptedAI::JustRespawned();
On_Reset();
ENTRY_BEGIN(CreatureEventBindings, me->GetEntry(), CREATURE_EVENT_ON_SPAWN, return);
Eluna::Push(L, me);
ENTRY_EXECUTE(0);
ENDCALL();
}
// Called at reaching home after evade
void JustReachedHome() override
{
ScriptedAI::JustReachedHome();
ENTRY_BEGIN(CreatureEventBindings, me->GetEntry(), CREATURE_EVENT_ON_REACH_HOME, return);
Eluna::Push(L, me);
ENTRY_EXECUTE(0);
ENDCALL();
}
// Called at text emote receive from player
void ReceiveEmote(Player* player, uint32 emoteId) override
{
ScriptedAI::ReceiveEmote(player, emoteId);
ENTRY_BEGIN(CreatureEventBindings, me->GetEntry(), CREATURE_EVENT_ON_RECEIVE_EMOTE, return);
Eluna::Push(L, me);
Eluna::Push(L, player);
Eluna::Push(L, emoteId);
ENTRY_EXECUTE(0);
ENDCALL();
}
// called when the corpse of this creature gets removed
void CorpseRemoved(uint32& respawnDelay) override
{
ScriptedAI::CorpseRemoved(respawnDelay);
ENTRY_BEGIN(CreatureEventBindings, me->GetEntry(), CREATURE_EVENT_ON_CORPSE_REMOVED, return);
Eluna::Push(L, me);
Eluna::Push(L, respawnDelay);
ENTRY_EXECUTE(0);
ENDCALL();
}
#ifdef MANGOS
// Enables use of MoveInLineOfSight
bool IsVisible(Unit* who) const override
{
return true;
}
#endif
void MoveInLineOfSight(Unit* who) override
{
ScriptedAI::MoveInLineOfSight(who);
ENTRY_BEGIN(CreatureEventBindings, me->GetEntry(), CREATURE_EVENT_ON_MOVE_IN_LOS, return);
Eluna::Push(L, me);
Eluna::Push(L, who);
ENTRY_EXECUTE(0);
ENDCALL();
}
// Called on creature initial spawn, respawn, death, evade (leave combat)
void On_Reset() // Not an override, custom
{
ENTRY_BEGIN(CreatureEventBindings, me->GetEntry(), CREATURE_EVENT_ON_RESET, return);
Eluna::Push(L, me);
ENTRY_EXECUTE(0);
ENDCALL();
}
// Called when hit by a spell
void SpellHit(Unit* caster, SpellInfo const* spell) override
{
ScriptedAI::SpellHit(caster, spell);
ENTRY_BEGIN(CreatureEventBindings, me->GetEntry(), CREATURE_EVENT_ON_HIT_BY_SPELL, return);
Eluna::Push(L, me);
Eluna::Push(L, caster);
Eluna::Push(L, spell->Id); // Pass spell object?
ENTRY_EXECUTE(0);
ENDCALL();
}
// Called when spell hits a target
void SpellHitTarget(Unit* target, SpellInfo const* spell) override
{
ScriptedAI::SpellHitTarget(target, spell);
ENTRY_BEGIN(CreatureEventBindings, me->GetEntry(), CREATURE_EVENT_ON_SPELL_HIT_TARGET, return);
Eluna::Push(L, me);
Eluna::Push(L, target);
Eluna::Push(L, spell->Id); // Pass spell object?
ENTRY_EXECUTE(0);
ENDCALL();
}
#ifndef MANGOS
// Called when the creature is summoned successfully by other creature
void IsSummonedBy(Unit* summoner) override
{
ScriptedAI::IsSummonedBy(summoner);
sEluna->OnSummoned(me, summoner);
}
void SummonedCreatureDies(Creature* summon, Unit* killer) override
{
ScriptedAI::SummonedCreatureDies(summon, killer);
ENTRY_BEGIN(CreatureEventBindings, me->GetEntry(), CREATURE_EVENT_ON_SUMMONED_CREATURE_DIED, return);
Eluna::Push(L, me);
Eluna::Push(L, summon);
Eluna::Push(L, killer);
ENTRY_EXECUTE(0);
ENDCALL();
}
// Called when owner takes damage
void OwnerAttackedBy(Unit* attacker) override
{
ScriptedAI::OwnerAttackedBy(attacker);
ENTRY_BEGIN(CreatureEventBindings, me->GetEntry(), CREATURE_EVENT_ON_OWNER_ATTACKED_AT, return);
Eluna::Push(L, me);
Eluna::Push(L, attacker);
ENTRY_EXECUTE(0);
ENDCALL();
}
// Called when owner attacks something
void OwnerAttacked(Unit* target) override
{
ScriptedAI::OwnerAttacked(target);
ENTRY_BEGIN(CreatureEventBindings, me->GetEntry(), CREATURE_EVENT_ON_OWNER_ATTACKED, return);
Eluna::Push(L, me);
Eluna::Push(L, target);
ENTRY_EXECUTE(0);
ENDCALL();
}
#endif
#ifdef MANGOS
#undef me
#endif
};
// gameobject
bool Eluna::OnDummyEffect(Unit* pCaster, uint32 spellId, SpellEffIndex effIndex, GameObject* pTarget)
{
ENTRY_BEGIN(GameObjectEventBindings, pTarget->GetEntry(), GAMEOBJECT_EVENT_ON_DUMMY_EFFECT, return false);
Push(L, pCaster);
Push(L, spellId);
Push(L, effIndex);
Push(L, pTarget);
ENTRY_EXECUTE(0);
ENDCALL();
return true;
}
bool Eluna::OnGossipHello(Player* pPlayer, GameObject* pGameObject)
{
ENTRY_BEGIN(GameObjectEventBindings, pGameObject->GetEntry(), GOSSIP_EVENT_ON_HELLO, return false);
pPlayer->PlayerTalkClass->ClearMenus();
Push(L, pPlayer);
Push(L, pGameObject);
ENTRY_EXECUTE(0);
ENDCALL();
return true;
}
bool Eluna::OnGossipSelect(Player* pPlayer, GameObject* pGameObject, uint32 sender, uint32 action)
{
ENTRY_BEGIN(GameObjectEventBindings, pGameObject->GetEntry(), GOSSIP_EVENT_ON_SELECT, return false);
pPlayer->PlayerTalkClass->ClearMenus();
Push(L, pPlayer);
Push(L, pGameObject);
Push(L, sender);
Push(L, action);
ENTRY_EXECUTE(0);
ENDCALL();
return true;
}
bool Eluna::OnGossipSelectCode(Player* pPlayer, GameObject* pGameObject, uint32 sender, uint32 action, const char* code)
{
ENTRY_BEGIN(GameObjectEventBindings, pGameObject->GetEntry(), GOSSIP_EVENT_ON_SELECT, return false);
pPlayer->PlayerTalkClass->ClearMenus();
Push(L, pPlayer);
Push(L, pGameObject);
Push(L, sender);
Push(L, action);
Push(L, code);
ENTRY_EXECUTE(0);
ENDCALL();
return true;
}
bool Eluna::OnQuestAccept(Player* pPlayer, GameObject* pGameObject, Quest const* pQuest)
{
ENTRY_BEGIN(GameObjectEventBindings, pGameObject->GetEntry(), GAMEOBJECT_EVENT_ON_QUEST_ACCEPT, return false);
Push(L, pPlayer);
Push(L, pGameObject);
Push(L, pQuest);
ENTRY_EXECUTE(0);
ENDCALL();
return true;
}
bool Eluna::OnQuestComplete(Player* pPlayer, GameObject* pGameObject, Quest const* pQuest)
{
ENTRY_BEGIN(GameObjectEventBindings, pGameObject->GetEntry(), GAMEOBJECT_EVENT_ON_QUEST_COMPLETE, return false);
Push(L, pPlayer);
Push(L, pGameObject);
Push(L, pQuest);
ENTRY_EXECUTE(0);
ENDCALL();
return true;
}
void Eluna::UpdateAI(GameObject* pGameObject, uint32 diff)
{
ENTRY_BEGIN(GameObjectEventBindings, pGameObject->GetEntry(), GAMEOBJECT_EVENT_ON_AIUPDATE, return);
Push(L, pGameObject);
Push(L, diff);
ENTRY_EXECUTE(0);
ENDCALL();
}
bool Eluna::OnQuestReward(Player* pPlayer, GameObject* pGameObject, Quest const* pQuest)
{
ENTRY_BEGIN(GameObjectEventBindings, pGameObject->GetEntry(), GAMEOBJECT_EVENT_ON_QUEST_REWARD, return false);
Push(L, pPlayer);
Push(L, pGameObject);
Push(L, pQuest);
ENTRY_EXECUTE(0);
ENDCALL();
return true;
}
uint32 Eluna::GetDialogStatus(Player* pPlayer, GameObject* pGameObject)
{
ENTRY_BEGIN(GameObjectEventBindings, pGameObject->GetEntry(), GAMEOBJECT_EVENT_ON_DIALOG_STATUS, return 0);
Push(L, pPlayer);
Push(L, pGameObject);
ENTRY_EXECUTE(0);
ENDCALL();
return DIALOG_STATUS_SCRIPTED_NO_STATUS; // DIALOG_STATUS_UNDEFINED
}
#ifndef CLASSIC
#ifndef TBC
void Eluna::OnDestroyed(GameObject* pGameObject, Player* pPlayer)
{
ENTRY_BEGIN(GameObjectEventBindings, pGameObject->GetEntry(), GAMEOBJECT_EVENT_ON_DESTROYED, return);
Push(L, pGameObject);
Push(L, pPlayer);
ENTRY_EXECUTE(0);
ENDCALL();
}
void Eluna::OnDamaged(GameObject* pGameObject, Player* pPlayer)
{
ENTRY_BEGIN(GameObjectEventBindings, pGameObject->GetEntry(), GAMEOBJECT_EVENT_ON_DAMAGED, return);
Push(L, pGameObject);
Push(L, pPlayer);
ENTRY_EXECUTE(0);
ENDCALL();
}
#endif
#endif
void Eluna::OnLootStateChanged(GameObject* pGameObject, uint32 state)
{
ENTRY_BEGIN(GameObjectEventBindings, pGameObject->GetEntry(), GAMEOBJECT_EVENT_ON_LOOT_STATE_CHANGE, return);
Push(L, pGameObject);
Push(L, state);
ENTRY_EXECUTE(0);
ENDCALL();
}
void Eluna::OnGameObjectStateChanged(GameObject* pGameObject, uint32 state)
{
ENTRY_BEGIN(GameObjectEventBindings, pGameObject->GetEntry(), GAMEOBJECT_EVENT_ON_GO_STATE_CHANGED, return);
Push(L, pGameObject);
Push(L, state);
ENTRY_EXECUTE(0);
ENDCALL();
}
void Eluna::OnSpawn(GameObject* gameobject)
{
ENTRY_BEGIN(GameObjectEventBindings, gameobject->GetEntry(), GAMEOBJECT_EVENT_ON_SPAWN, return);
Push(L, gameobject);
ENTRY_EXECUTE(0);
ENDCALL();
}
CreatureAI* Eluna::GetAI(Creature* creature)
{
if (!CreatureEventBindings->GetBindMap(creature->GetEntry()))
return NULL;
return new ElunaCreatureAI(creature);
}