/* * Copyright (C) 2010 - 2014 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 "Includes.h" using namespace HookMgr; /* 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; \ const char* _LuaBindType = sEluna->BINDMAP->groupName; \ uint32 _LuaEvent = EVENT; \ int _LuaStackTop = lua_gettop(L); \ for (size_t i = 0; i < sEluna->BINDMAP->Bindings[_LuaEvent].size(); ++i) \ lua_rawgeti(L, LUA_REGISTRYINDEX, (sEluna->BINDMAP->Bindings[_LuaEvent][i])); \ int _LuaFuncTop = lua_gettop(L); \ 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) - _LuaFuncTop; \ if (_LuaParams < 1) \ { \ ELUNA_LOG_ERROR("[Eluna]: Executing event %u for %s, params was %i. Report to devs", _LuaEvent, _LuaBindType, _LuaParams); \ } \ for (int j = _LuaFuncTop-_LuaStackTop; j > 0; --j) \ { \ for (int i = 0; i <= _LuaParams; ++i) \ lua_pushvalue(L, _LuaFuncTop+i); \ Eluna::ExecuteCall(L, _LuaParams, _LuaReturnValues); \ lua_remove(L, _LuaFuncTop--); \ } \ 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; \ const char* _LuaBindType = sEluna->BINDMAP->groupName; \ uint32 _LuaEvent = EVENT; \ int _LuaStackTop = lua_gettop(L); \ 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 for %s, stack top was %i and was supposed to be %i. Report to devs", _LuaEvent, _LuaBindType, lua_gettop(L), _LuaStackTop + _LuaReturnValues); \ } \ else if (_LuaReturnValues == LUA_MULTRET && lua_gettop(L) < _LuaStackTop) \ { \ ELUNA_LOG_ERROR("[Eluna]: Ending event %u for %s, stack top was %i and was supposed to be >= %i. Report to devs", _LuaEvent, _LuaBindType, 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(L, i, false)) packet = *data; if (!CHECKVAL(L, i, true)) { result = false; break; } } ENDCALL(); } void Eluna::OnPacketSendOne(Player* player, WorldPacket& packet, bool& result) { ENTRY_BEGIN(PacketEventBindings, OpcodesList(packet.GetOpcode()), PACKET_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(L, i, false)) packet = *data; if (!CHECKVAL(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(L, i, false)) packet = *data; if (!CHECKVAL(L, i, true)) { result = false; break; } } ENDCALL(); } void Eluna::OnPacketReceiveOne(Player* player, WorldPacket& packet, bool& result) { ENTRY_BEGIN(PacketEventBindings, OpcodesList(packet.GetOpcode()), PACKET_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(L, i, false)) packet = *data; if (!CHECKVAL(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) { if (reload) { ReloadEluna(); return; } 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(), ITEM_EVENT_ON_USE, 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(ItemGossipBindings, pItem->GetEntry(), GOSSIP_EVENT_ON_HELLO, return false); pPlayer->PlayerTalkClass->ClearMenus(); 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) { // 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; } } } } bool result = true; EVENT_BEGIN(PlayerEventBindings, 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(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(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(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(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(L, i, NULL)) msg = std::string(c_str); else if (!CHECKVAL(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(L, i, NULL)) msg = std::string(c_str); else if (!CHECKVAL(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(L, i, NULL)) msg = std::string(c_str); else if (!CHECKVAL(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(L, i, NULL)) msg = std::string(c_str); else if (!CHECKVAL(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(L, i, NULL)) msg = std::string(c_str); else if (!CHECKVAL(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(CreatureGossipBindings, pCreature->GetEntry(), GOSSIP_EVENT_ON_HELLO, return false); pPlayer->PlayerTalkClass->ClearMenus(); 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(CreatureGossipBindings, 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(CreatureGossipBindings, 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(1); FOR_RETS(i) { if (lua_isnoneornil(L, i)) continue; damage = Eluna::CHECKVAL(L, i, damage); } 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(1); FOR_RETS(i) { if (lua_isnoneornil(L, i)) continue; respawnDelay = Eluna::CHECKVAL(L, i, respawnDelay); } 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(GameObjectGossipBindings, 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(GameObjectGossipBindings, 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(GameObjectGossipBindings, 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); }