mirror of
https://github.com/azerothcore/mod-ale
synced 2025-11-29 15:38:17 +08:00
2145 lines
57 KiB
C++
2145 lines
57 KiB
C++
/*
|
|
* Copyright (C) 2010 - 2015 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 "ElunaBinding.h"
|
|
#include "ElunaEventMgr.h"
|
|
#include "ElunaIncludes.h"
|
|
#include "ElunaTemplate.h"
|
|
|
|
extern "C"
|
|
{
|
|
#include "lua.h"
|
|
#include "lualib.h"
|
|
#include "lauxlib.h"
|
|
};
|
|
|
|
#ifndef TRINITY
|
|
class AggressorAI;
|
|
typedef AggressorAI ScriptedAI;
|
|
#else
|
|
struct ScriptedAI;
|
|
#endif
|
|
|
|
using namespace HookMgr;
|
|
|
|
/*
|
|
* A hook should be written in one of the following forms:
|
|
*
|
|
* A. If results will be IGNORED:
|
|
*
|
|
* // Lock out any other threads.
|
|
* ELUNA_LOCK(this);
|
|
*
|
|
* // 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:
|
|
*
|
|
* // Lock out any other threads.
|
|
* ELUNA_LOCK(this);
|
|
*
|
|
* // 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<int>(L, r + 0);
|
|
* int second = CHECKVAL<int>(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<typename T>
|
|
int Eluna::SetupStack(EventBind<T>* event_bindings, EntryBind<T>* entry_bindings, T event_id, uint32 entry, 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((int)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);
|
|
// 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<typename T>
|
|
void Eluna::ReplaceArgument(T value, uint8 index, uint8 number_of_arguments, uint8 number_of_results, uint8 remaining_functions)
|
|
{
|
|
ASSERT(index <= number_of_arguments && index > 0);
|
|
// Stack: event_id, [arguments], [functions], [results]
|
|
|
|
int first_argument_index = lua_gettop(L) - number_of_results - remaining_functions - number_of_arguments + 1;
|
|
int argument_index = first_argument_index + index - 1;
|
|
|
|
Eluna::Push(L, value);
|
|
// Stack: event_id, [arguments], [functions], [results], value
|
|
|
|
lua_replace(L, argument_index);
|
|
// 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_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)
|
|
}
|
|
|
|
/*
|
|
* Call all event handlers registered to the event ID/entry combination and ignore any results.
|
|
*/
|
|
template<typename T>
|
|
void Eluna::CallAllFunctions(EventBind<T>* event_bindings, EntryBind<T>* entry_bindings, T event_id, uint32 entry)
|
|
{
|
|
int number_of_arguments = this->push_counter;
|
|
// Stack: [arguments]
|
|
|
|
int number_of_functions = SetupStack(event_bindings, entry_bindings, event_id, entry, 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<typename T>
|
|
bool Eluna::CallAllFunctionsBool(EventBind<T>* event_bindings, EntryBind<T>* entry_bindings, T event_id, uint32 entry, bool default_value)
|
|
{
|
|
bool result = default_value;
|
|
int number_of_arguments = this->push_counter;
|
|
// Stack: [arguments]
|
|
|
|
int number_of_functions = SetupStack(event_bindings, entry_bindings, event_id, entry, 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) && (bool)lua_toboolean(L, r) != 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()
|
|
{
|
|
ELUNA_LOCK(this);
|
|
CallAllFunctions(ServerEventBindings, ELUNA_EVENT_ON_LUA_STATE_CLOSE);
|
|
}
|
|
|
|
void Eluna::OnLuaStateOpen()
|
|
{
|
|
ELUNA_LOCK(this);
|
|
CallAllFunctions(ServerEventBindings, ELUNA_EVENT_ON_LUA_STATE_OPEN);
|
|
}
|
|
|
|
// areatrigger
|
|
bool Eluna::OnAreaTrigger(Player* pPlayer, AreaTriggerEntry const* pTrigger)
|
|
{
|
|
ELUNA_LOCK(this);
|
|
Push(pPlayer);
|
|
Push(pTrigger->id);
|
|
return CallAllFunctionsBool(ServerEventBindings, TRIGGER_EVENT_ON_TRIGGER);
|
|
}
|
|
// weather
|
|
void Eluna::OnChange(Weather* weather, WeatherState state, float grade)
|
|
{
|
|
ELUNA_LOCK(this);
|
|
Push(weather->GetZone());
|
|
Push(state);
|
|
Push(grade);
|
|
CallAllFunctions(ServerEventBindings, WEATHER_EVENT_ON_CHANGE);
|
|
}
|
|
// Auction House
|
|
void Eluna::OnAdd(AuctionHouseObject* ah)
|
|
{
|
|
ELUNA_LOCK(this);
|
|
Push(ah);
|
|
CallAllFunctions(ServerEventBindings, AUCTION_EVENT_ON_ADD);
|
|
}
|
|
|
|
void Eluna::OnRemove(AuctionHouseObject* ah)
|
|
{
|
|
ELUNA_LOCK(this);
|
|
Push(ah);
|
|
CallAllFunctions(ServerEventBindings, AUCTION_EVENT_ON_REMOVE);
|
|
}
|
|
|
|
void Eluna::OnSuccessful(AuctionHouseObject* ah)
|
|
{
|
|
ELUNA_LOCK(this);
|
|
Push(ah);
|
|
CallAllFunctions(ServerEventBindings, AUCTION_EVENT_ON_SUCCESSFUL);
|
|
}
|
|
|
|
void Eluna::OnExpire(AuctionHouseObject* ah)
|
|
{
|
|
ELUNA_LOCK(this);
|
|
Push(ah);
|
|
CallAllFunctions(ServerEventBindings, AUCTION_EVENT_ON_EXPIRE);
|
|
}
|
|
|
|
// Packet
|
|
bool Eluna::OnPacketSend(WorldSession* session, WorldPacket& packet)
|
|
{
|
|
ELUNA_LOCK(this);
|
|
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)
|
|
{
|
|
ELUNA_LOCK(this);
|
|
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<WorldPacket>(L, r + 1, true))
|
|
packet = *data;
|
|
|
|
lua_pop(L, 2);
|
|
}
|
|
|
|
CleanUpStack(2);
|
|
}
|
|
void Eluna::OnPacketSendOne(Player* player, WorldPacket& packet, bool& result)
|
|
{
|
|
ELUNA_LOCK(this);
|
|
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<WorldPacket>(L, r + 1, true))
|
|
packet = *data;
|
|
|
|
lua_pop(L, 2);
|
|
}
|
|
|
|
CleanUpStack(2);
|
|
}
|
|
|
|
bool Eluna::OnPacketReceive(WorldSession* session, WorldPacket& packet)
|
|
{
|
|
ELUNA_LOCK(this);
|
|
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)
|
|
{
|
|
ELUNA_LOCK(this);
|
|
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<WorldPacket>(L, r + 1, true))
|
|
packet = *data;
|
|
|
|
lua_pop(L, 2);
|
|
}
|
|
|
|
CleanUpStack(2);
|
|
}
|
|
void Eluna::OnPacketReceiveOne(Player* player, WorldPacket& packet, bool& result)
|
|
{
|
|
ELUNA_LOCK(this);
|
|
Push(new WorldPacket(packet));
|
|
Push(player);
|
|
int n = SetupStack(PacketEventBindings, PACKET_EVENT_ON_PACKET_RECEIVE, 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<WorldPacket>(L, r + 1, true))
|
|
packet = *data;
|
|
|
|
lua_pop(L, 2);
|
|
}
|
|
|
|
CleanUpStack(2);
|
|
}
|
|
|
|
// AddOns
|
|
bool Eluna::OnAddonMessage(Player* sender, uint32 type, std::string& msg, Player* receiver, Guild* guild, Group* group, Channel* channel)
|
|
{
|
|
ELUNA_LOCK(this);
|
|
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);
|
|
}
|
|
|
|
void Eluna::OnOpenStateChange(bool open)
|
|
{
|
|
ELUNA_LOCK(this);
|
|
Push(open);
|
|
CallAllFunctions(ServerEventBindings, WORLD_EVENT_ON_OPEN_STATE_CHANGE);
|
|
}
|
|
|
|
void Eluna::OnConfigLoad(bool reload)
|
|
{
|
|
ELUNA_LOCK(this);
|
|
Push(reload);
|
|
CallAllFunctions(ServerEventBindings, WORLD_EVENT_ON_CONFIG_LOAD);
|
|
}
|
|
|
|
void Eluna::OnShutdownInitiate(ShutdownExitCode code, ShutdownMask mask)
|
|
{
|
|
ELUNA_LOCK(this);
|
|
Push(code);
|
|
Push(mask);
|
|
CallAllFunctions(ServerEventBindings, WORLD_EVENT_ON_SHUTDOWN_INIT);
|
|
}
|
|
|
|
void Eluna::OnShutdownCancel()
|
|
{
|
|
ELUNA_LOCK(this);
|
|
CallAllFunctions(ServerEventBindings, WORLD_EVENT_ON_SHUTDOWN_CANCEL);
|
|
}
|
|
|
|
void Eluna::OnWorldUpdate(uint32 diff)
|
|
{
|
|
ELUNA_LOCK(this);
|
|
if (reload)
|
|
{
|
|
ReloadEluna();
|
|
return;
|
|
}
|
|
|
|
eventMgr->globalProcessor->Update(diff);
|
|
|
|
Push(diff);
|
|
CallAllFunctions(ServerEventBindings, WORLD_EVENT_ON_UPDATE);
|
|
}
|
|
|
|
void Eluna::OnStartup()
|
|
{
|
|
ELUNA_LOCK(this);
|
|
CallAllFunctions(ServerEventBindings, WORLD_EVENT_ON_STARTUP);
|
|
}
|
|
|
|
void Eluna::OnShutdown()
|
|
{
|
|
ELUNA_LOCK(this);
|
|
CallAllFunctions(ServerEventBindings, WORLD_EVENT_ON_SHUTDOWN);
|
|
}
|
|
|
|
void Eluna::HandleGossipSelectOption(Player* pPlayer, Item* item, uint32 sender, uint32 action, const std::string& code)
|
|
{
|
|
ELUNA_LOCK(this);
|
|
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)
|
|
{
|
|
ELUNA_LOCK(this);
|
|
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)
|
|
{
|
|
ELUNA_LOCK(this);
|
|
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)
|
|
{
|
|
ELUNA_LOCK(this);
|
|
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)
|
|
{
|
|
ELUNA_LOCK(this);
|
|
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)
|
|
{
|
|
ELUNA_LOCK(this);
|
|
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());
|
|
}
|
|
|
|
bool Eluna::OnItemGossip(Player* pPlayer, Item* pItem, SpellCastTargets const& /*targets*/)
|
|
{
|
|
ELUNA_LOCK(this);
|
|
pPlayer->PlayerTalkClass->ClearMenus();
|
|
Push(pPlayer);
|
|
Push(pItem);
|
|
return CallAllFunctionsBool(ItemGossipBindings, GOSSIP_EVENT_ON_HELLO, pItem->GetEntry());
|
|
}
|
|
|
|
bool Eluna::OnExpire(Player* pPlayer, ItemTemplate const* pProto)
|
|
{
|
|
ELUNA_LOCK(this);
|
|
Push(pPlayer);
|
|
Push(pProto->ItemId);
|
|
return CallAllFunctionsBool(ItemEventBindings, ITEM_EVENT_ON_EXPIRE, pProto->ItemId);
|
|
}
|
|
|
|
bool Eluna::OnRemove(Player* pPlayer, Item* item)
|
|
{
|
|
ELUNA_LOCK(this);
|
|
Push(pPlayer);
|
|
Push(item);
|
|
return CallAllFunctionsBool(ItemEventBindings, ITEM_EVENT_ON_REMOVE, item->GetEntry());
|
|
}
|
|
|
|
// Player
|
|
bool Eluna::OnCommand(Player* player, const char* text)
|
|
{
|
|
ELUNA_LOCK(this);
|
|
// 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;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
Push(player);
|
|
Push(fullcmd);
|
|
return CallAllFunctionsBool(PlayerEventBindings, PLAYER_EVENT_ON_COMMAND, true);
|
|
}
|
|
|
|
void Eluna::OnLootItem(Player* pPlayer, Item* pItem, uint32 count, uint64 guid)
|
|
{
|
|
ELUNA_LOCK(this);
|
|
Push(pPlayer);
|
|
Push(pItem);
|
|
Push(count);
|
|
Push(guid);
|
|
CallAllFunctions(PlayerEventBindings, PLAYER_EVENT_ON_LOOT_ITEM);
|
|
}
|
|
|
|
void Eluna::OnLootMoney(Player* pPlayer, uint32 amount)
|
|
{
|
|
ELUNA_LOCK(this);
|
|
Push(pPlayer);
|
|
Push(amount);
|
|
CallAllFunctions(PlayerEventBindings, PLAYER_EVENT_ON_LOOT_MONEY);
|
|
}
|
|
|
|
void Eluna::OnFirstLogin(Player* pPlayer)
|
|
{
|
|
ELUNA_LOCK(this);
|
|
Push(pPlayer);
|
|
CallAllFunctions(PlayerEventBindings, PLAYER_EVENT_ON_FIRST_LOGIN);
|
|
}
|
|
|
|
void Eluna::OnRepop(Player* pPlayer)
|
|
{
|
|
ELUNA_LOCK(this);
|
|
Push(pPlayer);
|
|
CallAllFunctions(PlayerEventBindings, PLAYER_EVENT_ON_REPOP);
|
|
}
|
|
|
|
void Eluna::OnResurrect(Player* pPlayer)
|
|
{
|
|
ELUNA_LOCK(this);
|
|
Push(pPlayer);
|
|
CallAllFunctions(PlayerEventBindings, PLAYER_EVENT_ON_RESURRECT);
|
|
}
|
|
|
|
void Eluna::OnQuestAbandon(Player* pPlayer, uint32 questId)
|
|
{
|
|
ELUNA_LOCK(this);
|
|
Push(pPlayer);
|
|
Push(questId);
|
|
CallAllFunctions(PlayerEventBindings, PLAYER_EVENT_ON_QUEST_ABANDON);
|
|
}
|
|
|
|
void Eluna::OnEquip(Player* pPlayer, Item* pItem, uint8 bag, uint8 slot)
|
|
{
|
|
ELUNA_LOCK(this);
|
|
Push(pPlayer);
|
|
Push(pItem);
|
|
Push(bag);
|
|
Push(slot);
|
|
CallAllFunctions(PlayerEventBindings, PLAYER_EVENT_ON_EQUIP);
|
|
}
|
|
|
|
InventoryResult Eluna::OnCanUseItem(const Player* pPlayer, uint32 itemEntry)
|
|
{
|
|
ELUNA_LOCK(this);
|
|
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<uint32>(L, r);
|
|
|
|
lua_pop(L, 1);
|
|
}
|
|
|
|
CleanUpStack(2);
|
|
return result;
|
|
}
|
|
void Eluna::OnPlayerEnterCombat(Player* pPlayer, Unit* pEnemy)
|
|
{
|
|
ELUNA_LOCK(this);
|
|
Push(pPlayer);
|
|
Push(pEnemy);
|
|
CallAllFunctions(PlayerEventBindings, PLAYER_EVENT_ON_ENTER_COMBAT);
|
|
}
|
|
|
|
void Eluna::OnPlayerLeaveCombat(Player* pPlayer)
|
|
{
|
|
ELUNA_LOCK(this);
|
|
Push(pPlayer);
|
|
CallAllFunctions(PlayerEventBindings, PLAYER_EVENT_ON_LEAVE_COMBAT);
|
|
}
|
|
|
|
void Eluna::OnPVPKill(Player* pKiller, Player* pKilled)
|
|
{
|
|
ELUNA_LOCK(this);
|
|
Push(pKiller);
|
|
Push(pKilled);
|
|
CallAllFunctions(PlayerEventBindings, PLAYER_EVENT_ON_KILL_PLAYER);
|
|
}
|
|
|
|
void Eluna::OnCreatureKill(Player* pKiller, Creature* pKilled)
|
|
{
|
|
ELUNA_LOCK(this);
|
|
Push(pKiller);
|
|
Push(pKilled);
|
|
CallAllFunctions(PlayerEventBindings, PLAYER_EVENT_ON_KILL_CREATURE);
|
|
}
|
|
|
|
void Eluna::OnPlayerKilledByCreature(Creature* pKiller, Player* pKilled)
|
|
{
|
|
ELUNA_LOCK(this);
|
|
Push(pKiller);
|
|
Push(pKilled);
|
|
CallAllFunctions(PlayerEventBindings, PLAYER_EVENT_ON_KILLED_BY_CREATURE);
|
|
}
|
|
|
|
void Eluna::OnLevelChanged(Player* pPlayer, uint8 oldLevel)
|
|
{
|
|
ELUNA_LOCK(this);
|
|
Push(pPlayer);
|
|
Push(oldLevel);
|
|
CallAllFunctions(PlayerEventBindings, PLAYER_EVENT_ON_LEVEL_CHANGE);
|
|
}
|
|
|
|
void Eluna::OnFreeTalentPointsChanged(Player* pPlayer, uint32 newPoints)
|
|
{
|
|
ELUNA_LOCK(this);
|
|
Push(pPlayer);
|
|
Push(newPoints);
|
|
CallAllFunctions(PlayerEventBindings, PLAYER_EVENT_ON_TALENTS_CHANGE);
|
|
}
|
|
|
|
void Eluna::OnTalentsReset(Player* pPlayer, bool noCost)
|
|
{
|
|
ELUNA_LOCK(this);
|
|
Push(pPlayer);
|
|
Push(noCost);
|
|
CallAllFunctions(PlayerEventBindings, PLAYER_EVENT_ON_TALENTS_RESET);
|
|
}
|
|
|
|
void Eluna::OnMoneyChanged(Player* pPlayer, int32& amount)
|
|
{
|
|
ELUNA_LOCK(this);
|
|
Push(pPlayer);
|
|
Push(amount);
|
|
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<int32>(L, r);
|
|
// Update the stack for subsequent calls.
|
|
ReplaceArgument(amount, 2, 2, 1, n);
|
|
}
|
|
|
|
lua_pop(L, 1);
|
|
}
|
|
|
|
CleanUpStack(2);
|
|
}
|
|
|
|
void Eluna::OnGiveXP(Player* pPlayer, uint32& amount, Unit* pVictim)
|
|
{
|
|
ELUNA_LOCK(this);
|
|
Push(pPlayer);
|
|
Push(amount);
|
|
Push(pVictim);
|
|
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<int32>(L, r);
|
|
// Update the stack for subsequent calls.
|
|
ReplaceArgument(amount, 2, 3, 1, n);
|
|
}
|
|
|
|
lua_pop(L, 1);
|
|
}
|
|
|
|
CleanUpStack(3);
|
|
}
|
|
|
|
void Eluna::OnReputationChange(Player* pPlayer, uint32 factionID, int32& standing, bool incremental)
|
|
{
|
|
ELUNA_LOCK(this);
|
|
Push(pPlayer);
|
|
Push(factionID);
|
|
Push(standing);
|
|
Push(incremental);
|
|
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<int32>(L, r);
|
|
// Update the stack for subsequent calls.
|
|
ReplaceArgument(standing, 3, 4, 1, n);
|
|
}
|
|
|
|
lua_pop(L, 1);
|
|
}
|
|
|
|
CleanUpStack(4);
|
|
}
|
|
|
|
void Eluna::OnDuelRequest(Player* pTarget, Player* pChallenger)
|
|
{
|
|
ELUNA_LOCK(this);
|
|
Push(pTarget);
|
|
Push(pChallenger);
|
|
CallAllFunctions(PlayerEventBindings, PLAYER_EVENT_ON_DUEL_REQUEST);
|
|
}
|
|
|
|
void Eluna::OnDuelStart(Player* pStarter, Player* pChallenger)
|
|
{
|
|
ELUNA_LOCK(this);
|
|
Push(pStarter);
|
|
Push(pChallenger);
|
|
CallAllFunctions(PlayerEventBindings, PLAYER_EVENT_ON_DUEL_START);
|
|
}
|
|
|
|
void Eluna::OnDuelEnd(Player* pWinner, Player* pLoser, DuelCompleteType type)
|
|
{
|
|
ELUNA_LOCK(this);
|
|
Push(pWinner);
|
|
Push(pLoser);
|
|
Push(type);
|
|
CallAllFunctions(PlayerEventBindings, PLAYER_EVENT_ON_DUEL_END);
|
|
}
|
|
|
|
void Eluna::OnEmote(Player* pPlayer, uint32 emote)
|
|
{
|
|
ELUNA_LOCK(this);
|
|
Push(pPlayer);
|
|
Push(emote);
|
|
CallAllFunctions(PlayerEventBindings, PLAYER_EVENT_ON_EMOTE);
|
|
}
|
|
|
|
void Eluna::OnTextEmote(Player* pPlayer, uint32 textEmote, uint32 emoteNum, uint64 guid)
|
|
{
|
|
ELUNA_LOCK(this);
|
|
Push(pPlayer);
|
|
Push(textEmote);
|
|
Push(emoteNum);
|
|
Push(guid);
|
|
CallAllFunctions(PlayerEventBindings, PLAYER_EVENT_ON_TEXT_EMOTE);
|
|
}
|
|
|
|
void Eluna::OnSpellCast(Player* pPlayer, Spell* pSpell, bool skipCheck)
|
|
{
|
|
ELUNA_LOCK(this);
|
|
Push(pPlayer);
|
|
Push(pSpell);
|
|
Push(skipCheck);
|
|
CallAllFunctions(PlayerEventBindings, PLAYER_EVENT_ON_SPELL_CAST);
|
|
}
|
|
|
|
void Eluna::OnLogin(Player* pPlayer)
|
|
{
|
|
ELUNA_LOCK(this);
|
|
Push(pPlayer);
|
|
CallAllFunctions(PlayerEventBindings, PLAYER_EVENT_ON_LOGIN);
|
|
}
|
|
|
|
void Eluna::OnLogout(Player* pPlayer)
|
|
{
|
|
ELUNA_LOCK(this);
|
|
Push(pPlayer);
|
|
CallAllFunctions(PlayerEventBindings, PLAYER_EVENT_ON_LOGOUT);
|
|
}
|
|
|
|
void Eluna::OnCreate(Player* pPlayer)
|
|
{
|
|
ELUNA_LOCK(this);
|
|
Push(pPlayer);
|
|
CallAllFunctions(PlayerEventBindings, PLAYER_EVENT_ON_CHARACTER_CREATE);
|
|
}
|
|
|
|
void Eluna::OnDelete(uint32 guidlow)
|
|
{
|
|
ELUNA_LOCK(this);
|
|
Push(guidlow);
|
|
CallAllFunctions(PlayerEventBindings, PLAYER_EVENT_ON_CHARACTER_DELETE);
|
|
}
|
|
|
|
void Eluna::OnSave(Player* pPlayer)
|
|
{
|
|
ELUNA_LOCK(this);
|
|
Push(pPlayer);
|
|
CallAllFunctions(PlayerEventBindings, PLAYER_EVENT_ON_SAVE);
|
|
}
|
|
|
|
void Eluna::OnBindToInstance(Player* pPlayer, Difficulty difficulty, uint32 mapid, bool permanent)
|
|
{
|
|
ELUNA_LOCK(this);
|
|
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)
|
|
{
|
|
ELUNA_LOCK(this);
|
|
Push(pPlayer);
|
|
Push(newZone);
|
|
Push(newArea);
|
|
CallAllFunctions(PlayerEventBindings, PLAYER_EVENT_ON_UPDATE_ZONE);
|
|
}
|
|
|
|
void Eluna::OnMapChanged(Player* player)
|
|
{
|
|
ELUNA_LOCK(this);
|
|
Push(player);
|
|
CallAllFunctions(PlayerEventBindings, PLAYER_EVENT_ON_MAP_CHANGE);
|
|
}
|
|
|
|
bool Eluna::OnChat(Player* pPlayer, uint32 type, uint32 lang, std::string& msg)
|
|
{
|
|
ELUNA_LOCK(this);
|
|
if (lang == LANG_ADDON)
|
|
return OnAddonMessage(pPlayer, type, msg, NULL, NULL, NULL, NULL);
|
|
|
|
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)
|
|
{
|
|
ELUNA_LOCK(this);
|
|
if (lang == LANG_ADDON)
|
|
return OnAddonMessage(pPlayer, type, msg, NULL, NULL, pGroup, NULL);
|
|
|
|
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)
|
|
{
|
|
ELUNA_LOCK(this);
|
|
if (lang == LANG_ADDON)
|
|
return OnAddonMessage(pPlayer, type, msg, NULL, pGuild, NULL, NULL);
|
|
|
|
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)
|
|
{
|
|
ELUNA_LOCK(this);
|
|
if (lang == LANG_ADDON)
|
|
return OnAddonMessage(pPlayer, type, msg, NULL, NULL, NULL, pChannel);
|
|
|
|
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)
|
|
{
|
|
ELUNA_LOCK(this);
|
|
if (lang == LANG_ADDON)
|
|
return OnAddonMessage(pPlayer, type, msg, pReceiver, NULL, NULL, NULL);
|
|
|
|
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)
|
|
{
|
|
ELUNA_LOCK(this);
|
|
Push(vehicle);
|
|
CallAllFunctions(VehicleEventBindings, VEHICLE_EVENT_ON_INSTALL);
|
|
}
|
|
|
|
void Eluna::OnUninstall(Vehicle* vehicle)
|
|
{
|
|
ELUNA_LOCK(this);
|
|
Push(vehicle);
|
|
CallAllFunctions(VehicleEventBindings, VEHICLE_EVENT_ON_UNINSTALL);
|
|
}
|
|
|
|
void Eluna::OnInstallAccessory(Vehicle* vehicle, Creature* accessory)
|
|
{
|
|
ELUNA_LOCK(this);
|
|
Push(vehicle);
|
|
Push(accessory);
|
|
CallAllFunctions(VehicleEventBindings, VEHICLE_EVENT_ON_INSTALL_ACCESSORY);
|
|
}
|
|
|
|
void Eluna::OnAddPassenger(Vehicle* vehicle, Unit* passenger, int8 seatId)
|
|
{
|
|
ELUNA_LOCK(this);
|
|
Push(vehicle);
|
|
Push(passenger);
|
|
Push(seatId);
|
|
CallAllFunctions(VehicleEventBindings, VEHICLE_EVENT_ON_ADD_PASSENGER);
|
|
}
|
|
|
|
void Eluna::OnRemovePassenger(Vehicle* vehicle, Unit* passenger)
|
|
{
|
|
ELUNA_LOCK(this);
|
|
Push(vehicle);
|
|
Push(passenger);
|
|
CallAllFunctions(VehicleEventBindings, VEHICLE_EVENT_ON_REMOVE_PASSENGER);
|
|
}
|
|
#endif
|
|
#endif
|
|
|
|
void Eluna::OnAddMember(Guild* guild, Player* player, uint32 plRank)
|
|
{
|
|
ELUNA_LOCK(this);
|
|
Push(guild);
|
|
Push(player);
|
|
Push(plRank);
|
|
CallAllFunctions(GuildEventBindings, GUILD_EVENT_ON_ADD_MEMBER);
|
|
}
|
|
|
|
void Eluna::OnRemoveMember(Guild* guild, Player* player, bool isDisbanding)
|
|
{
|
|
ELUNA_LOCK(this);
|
|
Push(guild);
|
|
Push(player);
|
|
Push(isDisbanding);
|
|
CallAllFunctions(GuildEventBindings, GUILD_EVENT_ON_REMOVE_MEMBER);
|
|
}
|
|
|
|
void Eluna::OnMOTDChanged(Guild* guild, const std::string& newMotd)
|
|
{
|
|
ELUNA_LOCK(this);
|
|
Push(guild);
|
|
Push(newMotd);
|
|
CallAllFunctions(GuildEventBindings, GUILD_EVENT_ON_MOTD_CHANGE);
|
|
}
|
|
|
|
void Eluna::OnInfoChanged(Guild* guild, const std::string& newInfo)
|
|
{
|
|
ELUNA_LOCK(this);
|
|
Push(guild);
|
|
Push(newInfo);
|
|
CallAllFunctions(GuildEventBindings, GUILD_EVENT_ON_INFO_CHANGE);
|
|
}
|
|
|
|
void Eluna::OnCreate(Guild* guild, Player* leader, const std::string& name)
|
|
{
|
|
ELUNA_LOCK(this);
|
|
Push(guild);
|
|
Push(leader);
|
|
Push(name);
|
|
CallAllFunctions(GuildEventBindings, GUILD_EVENT_ON_CREATE);
|
|
}
|
|
|
|
void Eluna::OnDisband(Guild* guild)
|
|
{
|
|
ELUNA_LOCK(this);
|
|
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?
|
|
{
|
|
ELUNA_LOCK(this);
|
|
Push(guild);
|
|
Push(player);
|
|
Push(amount);
|
|
Push(isRepair); // isRepair not a part of Mangos, implement?
|
|
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<uint32>(L, r);
|
|
// Update the stack for subsequent calls.
|
|
ReplaceArgument(amount, 3, 4, 1, n);
|
|
}
|
|
|
|
lua_pop(L, 1);
|
|
}
|
|
|
|
CleanUpStack(4);
|
|
}
|
|
|
|
void Eluna::OnMemberDepositMoney(Guild* guild, Player* player, uint32& amount)
|
|
{
|
|
ELUNA_LOCK(this);
|
|
Push(guild);
|
|
Push(player);
|
|
Push(amount);
|
|
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<uint32>(L, r);
|
|
// Update the stack for subsequent calls.
|
|
ReplaceArgument(amount, 3, 3, 1, n);
|
|
}
|
|
|
|
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)
|
|
{
|
|
ELUNA_LOCK(this);
|
|
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)
|
|
{
|
|
ELUNA_LOCK(this);
|
|
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)
|
|
{
|
|
ELUNA_LOCK(this);
|
|
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)
|
|
{
|
|
ELUNA_LOCK(this);
|
|
Push(group);
|
|
Push(guid);
|
|
CallAllFunctions(GroupEventBindings, GROUP_EVENT_ON_MEMBER_ADD);
|
|
}
|
|
|
|
void Eluna::OnInviteMember(Group* group, uint64 guid)
|
|
{
|
|
ELUNA_LOCK(this);
|
|
Push(group);
|
|
Push(guid);
|
|
CallAllFunctions(GroupEventBindings, GROUP_EVENT_ON_MEMBER_INVITE);
|
|
}
|
|
|
|
void Eluna::OnRemoveMember(Group* group, uint64 guid, uint8 method)
|
|
{
|
|
ELUNA_LOCK(this);
|
|
Push(group);
|
|
Push(guid);
|
|
Push(method);
|
|
CallAllFunctions(GroupEventBindings, GROUP_EVENT_ON_MEMBER_REMOVE);
|
|
}
|
|
|
|
void Eluna::OnChangeLeader(Group* group, uint64 newLeaderGuid, uint64 oldLeaderGuid)
|
|
{
|
|
ELUNA_LOCK(this);
|
|
Push(group);
|
|
Push(newLeaderGuid);
|
|
Push(oldLeaderGuid);
|
|
CallAllFunctions(GroupEventBindings, GROUP_EVENT_ON_LEADER_CHANGE);
|
|
}
|
|
|
|
void Eluna::OnDisband(Group* group)
|
|
{
|
|
ELUNA_LOCK(this);
|
|
Push(group);
|
|
CallAllFunctions(GroupEventBindings, GROUP_EVENT_ON_DISBAND);
|
|
}
|
|
|
|
void Eluna::OnCreate(Group* group, uint64 leaderGuid, GroupType groupType)
|
|
{
|
|
ELUNA_LOCK(this);
|
|
Push(group);
|
|
Push(leaderGuid);
|
|
Push(groupType);
|
|
CallAllFunctions(GroupEventBindings, GROUP_EVENT_ON_CREATE);
|
|
}
|
|
|
|
/* Map */
|
|
void Eluna::OnCreate(Map* map)
|
|
{
|
|
ELUNA_LOCK(this);
|
|
Push(map);
|
|
CallAllFunctions(ServerEventBindings, MAP_EVENT_ON_CREATE);
|
|
}
|
|
void Eluna::OnDestroy(Map* map)
|
|
{
|
|
ELUNA_LOCK(this);
|
|
Push(map);
|
|
CallAllFunctions(ServerEventBindings, MAP_EVENT_ON_DESTROY);
|
|
}
|
|
void Eluna::OnPlayerEnter(Map* map, Player* player)
|
|
{
|
|
ELUNA_LOCK(this);
|
|
Push(map);
|
|
Push(player);
|
|
CallAllFunctions(ServerEventBindings, MAP_EVENT_ON_PLAYER_ENTER);
|
|
}
|
|
void Eluna::OnPlayerLeave(Map* map, Player* player)
|
|
{
|
|
ELUNA_LOCK(this);
|
|
Push(map);
|
|
Push(player);
|
|
CallAllFunctions(ServerEventBindings, MAP_EVENT_ON_PLAYER_LEAVE);
|
|
}
|
|
void Eluna::OnUpdate(Map* map, uint32 diff)
|
|
{
|
|
ELUNA_LOCK(this);
|
|
// enable this for multithread
|
|
// eventMgr->globalProcessor->Update(diff);
|
|
Push(map);
|
|
Push(diff);
|
|
CallAllFunctions(ServerEventBindings, MAP_EVENT_ON_UPDATE);
|
|
}
|
|
void Eluna::OnRemove(GameObject* gameobject)
|
|
{
|
|
ELUNA_LOCK(this);
|
|
Push(gameobject);
|
|
CallAllFunctions(ServerEventBindings, WORLD_EVENT_ON_DELETE_GAMEOBJECT);
|
|
}
|
|
void Eluna::OnRemove(Creature* creature)
|
|
{
|
|
ELUNA_LOCK(this);
|
|
Push(creature);
|
|
CallAllFunctions(ServerEventBindings, WORLD_EVENT_ON_DELETE_CREATURE);
|
|
}
|
|
|
|
// creature
|
|
bool Eluna::OnDummyEffect(Unit* pCaster, uint32 spellId, SpellEffIndex effIndex, Creature* pTarget)
|
|
{
|
|
ELUNA_LOCK(this);
|
|
Push(pCaster);
|
|
Push(spellId);
|
|
Push(effIndex);
|
|
Push(pTarget);
|
|
return CallAllFunctionsBool(CreatureEventBindings, CREATURE_EVENT_ON_DUMMY_EFFECT, pTarget->GetEntry());
|
|
}
|
|
|
|
bool Eluna::OnGossipHello(Player* pPlayer, Creature* pCreature)
|
|
{
|
|
ELUNA_LOCK(this);
|
|
pPlayer->PlayerTalkClass->ClearMenus();
|
|
Push(pPlayer);
|
|
Push(pCreature);
|
|
return CallAllFunctionsBool(CreatureGossipBindings, GOSSIP_EVENT_ON_HELLO, pCreature->GetEntry());
|
|
}
|
|
|
|
bool Eluna::OnGossipSelect(Player* pPlayer, Creature* pCreature, uint32 sender, uint32 action)
|
|
{
|
|
ELUNA_LOCK(this);
|
|
pPlayer->PlayerTalkClass->ClearMenus();
|
|
Push(pPlayer);
|
|
Push(pCreature);
|
|
Push(sender);
|
|
Push(action);
|
|
return CallAllFunctionsBool(CreatureGossipBindings, GOSSIP_EVENT_ON_SELECT, pCreature->GetEntry());
|
|
}
|
|
|
|
bool Eluna::OnGossipSelectCode(Player* pPlayer, Creature* pCreature, uint32 sender, uint32 action, const char* code)
|
|
{
|
|
ELUNA_LOCK(this);
|
|
pPlayer->PlayerTalkClass->ClearMenus();
|
|
Push(pPlayer);
|
|
Push(pCreature);
|
|
Push(sender);
|
|
Push(action);
|
|
Push(code);
|
|
return CallAllFunctionsBool(CreatureGossipBindings, GOSSIP_EVENT_ON_SELECT, pCreature->GetEntry());
|
|
}
|
|
|
|
bool Eluna::OnQuestAccept(Player* pPlayer, Creature* pCreature, Quest const* pQuest)
|
|
{
|
|
ELUNA_LOCK(this);
|
|
Push(pPlayer);
|
|
Push(pCreature);
|
|
Push(pQuest);
|
|
return CallAllFunctionsBool(CreatureEventBindings, CREATURE_EVENT_ON_QUEST_ACCEPT, pCreature->GetEntry());
|
|
}
|
|
|
|
bool Eluna::OnQuestReward(Player* pPlayer, Creature* pCreature, Quest const* pQuest, uint32 opt)
|
|
{
|
|
ELUNA_LOCK(this);
|
|
Push(pPlayer);
|
|
Push(pCreature);
|
|
Push(pQuest);
|
|
Push(opt);
|
|
return CallAllFunctionsBool(CreatureEventBindings, CREATURE_EVENT_ON_QUEST_REWARD, pCreature->GetEntry());
|
|
}
|
|
|
|
uint32 Eluna::GetDialogStatus(Player* pPlayer, Creature* pCreature)
|
|
{
|
|
ELUNA_LOCK(this);
|
|
Push(pPlayer);
|
|
Push(pCreature);
|
|
CallAllFunctions(CreatureEventBindings, CREATURE_EVENT_ON_DIALOG_STATUS, pCreature->GetEntry());
|
|
return DIALOG_STATUS_SCRIPTED_NO_STATUS;
|
|
}
|
|
|
|
void Eluna::OnAddToWorld(Creature* creature)
|
|
{
|
|
ELUNA_LOCK(this);
|
|
Push(creature);
|
|
CallAllFunctions(CreatureEventBindings, CREATURE_EVENT_ON_ADD, creature->GetEntry());
|
|
}
|
|
|
|
void Eluna::OnRemoveFromWorld(Creature* creature)
|
|
{
|
|
ELUNA_LOCK(this);
|
|
Push(creature);
|
|
CallAllFunctions(CreatureEventBindings, CREATURE_EVENT_ON_REMOVE, creature->GetEntry());
|
|
}
|
|
|
|
bool Eluna::OnSummoned(Creature* pCreature, Unit* pSummoner)
|
|
{
|
|
ELUNA_LOCK(this);
|
|
Push(pCreature);
|
|
Push(pSummoner);
|
|
return CallAllFunctionsBool(CreatureEventBindings, CREATURE_EVENT_ON_SUMMONED, pCreature->GetEntry());
|
|
}
|
|
|
|
bool Eluna::UpdateAI(Creature* me, const uint32 diff)
|
|
{
|
|
ELUNA_LOCK(this);
|
|
Push(me);
|
|
Push(diff);
|
|
return CallAllFunctionsBool(CreatureEventBindings, CREATURE_EVENT_ON_AIUPDATE, me->GetEntry());
|
|
}
|
|
|
|
//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)
|
|
{
|
|
ELUNA_LOCK(this);
|
|
Push(me);
|
|
Push(target);
|
|
return CallAllFunctionsBool(CreatureEventBindings, CREATURE_EVENT_ON_ENTER_COMBAT, me->GetEntry());
|
|
}
|
|
|
|
// Called at any Damage from any attacker (before damage apply)
|
|
bool Eluna::DamageTaken(Creature* me, Unit* attacker, uint32& damage)
|
|
{
|
|
ELUNA_LOCK(this);
|
|
bool result = false;
|
|
Push(me);
|
|
Push(attacker);
|
|
Push(damage);
|
|
int n = SetupStack(CreatureEventBindings, CREATURE_EVENT_ON_DAMAGE_TAKEN, me->GetEntry(), 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<uint32>(L, r + 1);
|
|
// Update the stack for subsequent calls.
|
|
ReplaceArgument(damage, 3, 3, 2, n);
|
|
}
|
|
|
|
lua_pop(L, 2);
|
|
}
|
|
|
|
CleanUpStack(3);
|
|
return result;
|
|
}
|
|
|
|
//Called at creature death
|
|
bool Eluna::JustDied(Creature* me, Unit* killer)
|
|
{
|
|
ELUNA_LOCK(this);
|
|
On_Reset(me);
|
|
Push(me);
|
|
Push(killer);
|
|
return CallAllFunctionsBool(CreatureEventBindings, CREATURE_EVENT_ON_DIED, me->GetEntry());
|
|
}
|
|
|
|
//Called at creature killing another unit
|
|
bool Eluna::KilledUnit(Creature* me, Unit* victim)
|
|
{
|
|
ELUNA_LOCK(this);
|
|
Push(me);
|
|
Push(victim);
|
|
return CallAllFunctionsBool(CreatureEventBindings, CREATURE_EVENT_ON_TARGET_DIED, me->GetEntry());
|
|
}
|
|
|
|
// Called when the creature summon successfully other creature
|
|
bool Eluna::JustSummoned(Creature* me, Creature* summon)
|
|
{
|
|
ELUNA_LOCK(this);
|
|
Push(me);
|
|
Push(summon);
|
|
return CallAllFunctionsBool(CreatureEventBindings, CREATURE_EVENT_ON_JUST_SUMMONED_CREATURE, me->GetEntry());
|
|
}
|
|
|
|
// Called when a summoned creature is despawned
|
|
bool Eluna::SummonedCreatureDespawn(Creature* me, Creature* summon)
|
|
{
|
|
ELUNA_LOCK(this);
|
|
Push(me);
|
|
Push(summon);
|
|
return CallAllFunctionsBool(CreatureEventBindings, CREATURE_EVENT_ON_SUMMONED_CREATURE_DESPAWN, me->GetEntry());
|
|
}
|
|
|
|
//Called at waypoint reached or PointMovement end
|
|
bool Eluna::MovementInform(Creature* me, uint32 type, uint32 id)
|
|
{
|
|
ELUNA_LOCK(this);
|
|
Push(me);
|
|
Push(type);
|
|
Push(id);
|
|
return CallAllFunctionsBool(CreatureEventBindings, CREATURE_EVENT_ON_REACH_WP, me->GetEntry());
|
|
}
|
|
|
|
// Called before EnterCombat even before the creature is in combat.
|
|
bool Eluna::AttackStart(Creature* me, Unit* target)
|
|
{
|
|
ELUNA_LOCK(this);
|
|
Push(me);
|
|
Push(target);
|
|
return CallAllFunctionsBool(CreatureEventBindings, CREATURE_EVENT_ON_PRE_COMBAT, me->GetEntry());
|
|
}
|
|
|
|
// Called for reaction at stopping attack at no attackers or targets
|
|
bool Eluna::EnterEvadeMode(Creature* me)
|
|
{
|
|
ELUNA_LOCK(this);
|
|
On_Reset(me);
|
|
Push(me);
|
|
return CallAllFunctionsBool(CreatureEventBindings, CREATURE_EVENT_ON_LEAVE_COMBAT, me->GetEntry());
|
|
}
|
|
|
|
// Called when the creature is target of hostile action: swing, hostile spell landed, fear/etc)
|
|
bool Eluna::AttackedBy(Creature* me, Unit* attacker)
|
|
{
|
|
ELUNA_LOCK(this);
|
|
Push(me);
|
|
Push(attacker);
|
|
return CallAllFunctionsBool(CreatureEventBindings, CREATURE_EVENT_ON_ATTACKED_AT, me->GetEntry());
|
|
}
|
|
|
|
// Called when creature is spawned or respawned (for reseting variables)
|
|
bool Eluna::JustRespawned(Creature* me)
|
|
{
|
|
ELUNA_LOCK(this);
|
|
On_Reset(me);
|
|
Push(me);
|
|
return CallAllFunctionsBool(CreatureEventBindings, CREATURE_EVENT_ON_SPAWN, me->GetEntry());
|
|
}
|
|
|
|
// Called at reaching home after evade
|
|
bool Eluna::JustReachedHome(Creature* me)
|
|
{
|
|
ELUNA_LOCK(this);
|
|
Push(me);
|
|
return CallAllFunctionsBool(CreatureEventBindings, CREATURE_EVENT_ON_REACH_HOME, me->GetEntry());
|
|
}
|
|
|
|
// Called at text emote receive from player
|
|
bool Eluna::ReceiveEmote(Creature* me, Player* player, uint32 emoteId)
|
|
{
|
|
ELUNA_LOCK(this);
|
|
Push(me);
|
|
Push(player);
|
|
Push(emoteId);
|
|
return CallAllFunctionsBool(CreatureEventBindings, CREATURE_EVENT_ON_RECEIVE_EMOTE, me->GetEntry());
|
|
}
|
|
|
|
// called when the corpse of this creature gets removed
|
|
bool Eluna::CorpseRemoved(Creature* me, uint32& respawnDelay)
|
|
{
|
|
ELUNA_LOCK(this);
|
|
bool result = false;
|
|
Push(me);
|
|
Push(respawnDelay);
|
|
int n = SetupStack(CreatureEventBindings, CREATURE_EVENT_ON_CORPSE_REMOVED, me->GetEntry(), 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<uint32>(L, r + 1);
|
|
// Update the stack for subsequent calls.
|
|
ReplaceArgument(respawnDelay, 2, 2, 2, n);
|
|
}
|
|
|
|
lua_pop(L, 2);
|
|
}
|
|
|
|
CleanUpStack(2);
|
|
return result;
|
|
}
|
|
|
|
bool Eluna::MoveInLineOfSight(Creature* me, Unit* who)
|
|
{
|
|
ELUNA_LOCK(this);
|
|
Push(me);
|
|
Push(who);
|
|
return CallAllFunctionsBool(CreatureEventBindings, CREATURE_EVENT_ON_MOVE_IN_LOS, me->GetEntry());
|
|
}
|
|
|
|
// Called on creature initial spawn, respawn, death, evade (leave combat)
|
|
void Eluna::On_Reset(Creature* me) // Not an override, custom
|
|
{
|
|
ELUNA_LOCK(this);
|
|
Push(me);
|
|
CallAllFunctions(CreatureEventBindings, CREATURE_EVENT_ON_RESET, me->GetEntry());
|
|
}
|
|
|
|
// Called when hit by a spell
|
|
bool Eluna::SpellHit(Creature* me, Unit* caster, SpellInfo const* spell)
|
|
{
|
|
ELUNA_LOCK(this);
|
|
Push(me);
|
|
Push(caster);
|
|
Push(spell->Id); // Pass spell object?
|
|
return CallAllFunctionsBool(CreatureEventBindings, CREATURE_EVENT_ON_HIT_BY_SPELL, me->GetEntry());
|
|
}
|
|
|
|
// Called when spell hits a target
|
|
bool Eluna::SpellHitTarget(Creature* me, Unit* target, SpellInfo const* spell)
|
|
{
|
|
ELUNA_LOCK(this);
|
|
Push(me);
|
|
Push(target);
|
|
Push(spell->Id); // Pass spell object?
|
|
return CallAllFunctionsBool(CreatureEventBindings, CREATURE_EVENT_ON_SPELL_HIT_TARGET, me->GetEntry());
|
|
}
|
|
|
|
#ifdef TRINITY
|
|
|
|
bool Eluna::SummonedCreatureDies(Creature* me, Creature* summon, Unit* killer)
|
|
{
|
|
ELUNA_LOCK(this);
|
|
Push(me);
|
|
Push(summon);
|
|
Push(killer);
|
|
return CallAllFunctionsBool(CreatureEventBindings, CREATURE_EVENT_ON_SUMMONED_CREATURE_DIED, me->GetEntry());
|
|
}
|
|
|
|
// Called when owner takes damage
|
|
bool Eluna::OwnerAttackedBy(Creature* me, Unit* attacker)
|
|
{
|
|
ELUNA_LOCK(this);
|
|
Push(me);
|
|
Push(attacker);
|
|
return CallAllFunctionsBool(CreatureEventBindings, CREATURE_EVENT_ON_OWNER_ATTACKED_AT, me->GetEntry());
|
|
}
|
|
|
|
// Called when owner attacks something
|
|
bool Eluna::OwnerAttacked(Creature* me, Unit* target)
|
|
{
|
|
ELUNA_LOCK(this);
|
|
Push(me);
|
|
Push(target);
|
|
return CallAllFunctionsBool(CreatureEventBindings, CREATURE_EVENT_ON_OWNER_ATTACKED, me->GetEntry());
|
|
}
|
|
#endif
|
|
|
|
struct ElunaCreatureAI : ScriptedAI
|
|
{
|
|
#ifndef TRINITY
|
|
#define me m_creature
|
|
#endif
|
|
|
|
ElunaCreatureAI(Creature* creature) : ScriptedAI(creature)
|
|
{
|
|
JustRespawned();
|
|
}
|
|
~ElunaCreatureAI() { }
|
|
|
|
//Called at World update tick
|
|
#ifndef TRINITY
|
|
void UpdateAI(const uint32 diff) override
|
|
#else
|
|
void UpdateAI(uint32 diff) override
|
|
#endif
|
|
{
|
|
if (!sEluna->UpdateAI(me, diff))
|
|
{
|
|
#ifdef TRINITY
|
|
if (!me->HasFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_IMMUNE_TO_NPC))
|
|
ScriptedAI::UpdateAI(diff);
|
|
#else
|
|
if (!me->HasFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_PASSIVE))
|
|
ScriptedAI::UpdateAI(diff);
|
|
#endif
|
|
}
|
|
}
|
|
|
|
//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
|
|
{
|
|
if (!sEluna->EnterCombat(me, target))
|
|
ScriptedAI::EnterCombat(target);
|
|
}
|
|
|
|
// Called at any Damage from any attacker (before damage apply)
|
|
void DamageTaken(Unit* attacker, uint32& damage) override
|
|
{
|
|
if (!sEluna->DamageTaken(me, attacker, damage))
|
|
ScriptedAI::DamageTaken(attacker, damage);
|
|
}
|
|
|
|
//Called at creature death
|
|
void JustDied(Unit* killer) override
|
|
{
|
|
if (!sEluna->JustDied(me, killer))
|
|
ScriptedAI::JustDied(killer);
|
|
}
|
|
|
|
//Called at creature killing another unit
|
|
void KilledUnit(Unit* victim) override
|
|
{
|
|
if (!sEluna->KilledUnit(me, victim))
|
|
ScriptedAI::KilledUnit(victim);
|
|
}
|
|
|
|
// Called when the creature summon successfully other creature
|
|
void JustSummoned(Creature* summon) override
|
|
{
|
|
if (!sEluna->JustSummoned(me, summon))
|
|
ScriptedAI::JustSummoned(summon);
|
|
}
|
|
|
|
// Called when a summoned creature is despawned
|
|
void SummonedCreatureDespawn(Creature* summon) override
|
|
{
|
|
if (!sEluna->SummonedCreatureDespawn(me, summon))
|
|
ScriptedAI::SummonedCreatureDespawn(summon);
|
|
}
|
|
|
|
//Called at waypoint reached or PointMovement end
|
|
void MovementInform(uint32 type, uint32 id) override
|
|
{
|
|
if (!sEluna->MovementInform(me, type, id))
|
|
ScriptedAI::MovementInform(type, id);
|
|
}
|
|
|
|
// Called before EnterCombat even before the creature is in combat.
|
|
void AttackStart(Unit* target) override
|
|
{
|
|
if (!sEluna->AttackStart(me, target))
|
|
ScriptedAI::AttackStart(target);
|
|
}
|
|
|
|
// Called for reaction at stopping attack at no attackers or targets
|
|
void EnterEvadeMode() override
|
|
{
|
|
if (!sEluna->EnterEvadeMode(me))
|
|
ScriptedAI::EnterEvadeMode();
|
|
}
|
|
|
|
// Called when the creature is target of hostile action: swing, hostile spell landed, fear/etc)
|
|
void AttackedBy(Unit* attacker) override
|
|
{
|
|
if (!sEluna->AttackedBy(me, attacker))
|
|
ScriptedAI::AttackedBy(attacker);
|
|
}
|
|
|
|
// Called when creature is spawned or respawned (for reseting variables)
|
|
void JustRespawned() override
|
|
{
|
|
if (!sEluna->JustRespawned(me))
|
|
ScriptedAI::JustRespawned();
|
|
}
|
|
|
|
// Called at reaching home after evade
|
|
void JustReachedHome() override
|
|
{
|
|
if (!sEluna->JustReachedHome(me))
|
|
ScriptedAI::JustReachedHome();
|
|
}
|
|
|
|
// Called at text emote receive from player
|
|
void ReceiveEmote(Player* player, uint32 emoteId) override
|
|
{
|
|
if (!sEluna->ReceiveEmote(me, player, emoteId))
|
|
ScriptedAI::ReceiveEmote(player, emoteId);
|
|
}
|
|
|
|
// called when the corpse of this creature gets removed
|
|
void CorpseRemoved(uint32& respawnDelay) override
|
|
{
|
|
if (!sEluna->CorpseRemoved(me, respawnDelay))
|
|
ScriptedAI::CorpseRemoved(respawnDelay);
|
|
}
|
|
|
|
#ifndef TRINITY
|
|
// Enables use of MoveInLineOfSight
|
|
bool IsVisible(Unit* who) const override
|
|
{
|
|
return true;
|
|
}
|
|
#endif
|
|
|
|
void MoveInLineOfSight(Unit* who) override
|
|
{
|
|
if (!sEluna->MoveInLineOfSight(me, who))
|
|
ScriptedAI::MoveInLineOfSight(who);
|
|
}
|
|
|
|
// Called when hit by a spell
|
|
void SpellHit(Unit* caster, SpellInfo const* spell) override
|
|
{
|
|
if (!sEluna->SpellHit(me, caster, spell))
|
|
ScriptedAI::SpellHit(caster, spell);
|
|
}
|
|
|
|
// Called when spell hits a target
|
|
void SpellHitTarget(Unit* target, SpellInfo const* spell) override
|
|
{
|
|
if (!sEluna->SpellHitTarget(me, target, spell))
|
|
ScriptedAI::SpellHitTarget(target, spell);
|
|
}
|
|
|
|
#ifdef TRINITY
|
|
|
|
// Called when the creature is summoned successfully by other creature
|
|
void IsSummonedBy(Unit* summoner) override
|
|
{
|
|
if (!sEluna->OnSummoned(me, summoner))
|
|
ScriptedAI::IsSummonedBy(summoner);
|
|
}
|
|
|
|
void SummonedCreatureDies(Creature* summon, Unit* killer) override
|
|
{
|
|
if (!sEluna->SummonedCreatureDies(me, summon, killer))
|
|
ScriptedAI::SummonedCreatureDies(summon, killer);
|
|
}
|
|
|
|
// Called when owner takes damage
|
|
void OwnerAttackedBy(Unit* attacker) override
|
|
{
|
|
if (!sEluna->OwnerAttackedBy(me, attacker))
|
|
ScriptedAI::OwnerAttackedBy(attacker);
|
|
}
|
|
|
|
// Called when owner attacks something
|
|
void OwnerAttacked(Unit* target) override
|
|
{
|
|
if (!sEluna->OwnerAttacked(me, target))
|
|
ScriptedAI::OwnerAttacked(target);
|
|
}
|
|
#endif
|
|
|
|
#ifndef TRINITY
|
|
#undef me
|
|
#endif
|
|
};
|
|
|
|
// gameobject
|
|
bool Eluna::OnDummyEffect(Unit* pCaster, uint32 spellId, SpellEffIndex effIndex, GameObject* pTarget)
|
|
{
|
|
ELUNA_LOCK(this);
|
|
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)
|
|
{
|
|
ELUNA_LOCK(this);
|
|
pPlayer->PlayerTalkClass->ClearMenus();
|
|
Push(pPlayer);
|
|
Push(pGameObject);
|
|
return CallAllFunctionsBool(GameObjectGossipBindings, GOSSIP_EVENT_ON_HELLO, pGameObject->GetEntry());
|
|
}
|
|
|
|
bool Eluna::OnGossipSelect(Player* pPlayer, GameObject* pGameObject, uint32 sender, uint32 action)
|
|
{
|
|
ELUNA_LOCK(this);
|
|
pPlayer->PlayerTalkClass->ClearMenus();
|
|
Push(pPlayer);
|
|
Push(pGameObject);
|
|
Push(sender);
|
|
Push(action);
|
|
return CallAllFunctionsBool(GameObjectGossipBindings, GOSSIP_EVENT_ON_SELECT, pGameObject->GetEntry());
|
|
}
|
|
|
|
bool Eluna::OnGossipSelectCode(Player* pPlayer, GameObject* pGameObject, uint32 sender, uint32 action, const char* code)
|
|
{
|
|
ELUNA_LOCK(this);
|
|
pPlayer->PlayerTalkClass->ClearMenus();
|
|
Push(pPlayer);
|
|
Push(pGameObject);
|
|
Push(sender);
|
|
Push(action);
|
|
Push(code);
|
|
return CallAllFunctionsBool(GameObjectGossipBindings, GOSSIP_EVENT_ON_SELECT, pGameObject->GetEntry());
|
|
}
|
|
|
|
bool Eluna::OnQuestAccept(Player* pPlayer, GameObject* pGameObject, Quest const* pQuest)
|
|
{
|
|
ELUNA_LOCK(this);
|
|
Push(pPlayer);
|
|
Push(pGameObject);
|
|
Push(pQuest);
|
|
return CallAllFunctionsBool(GameObjectEventBindings, GAMEOBJECT_EVENT_ON_QUEST_ACCEPT, pGameObject->GetEntry());
|
|
}
|
|
|
|
void Eluna::UpdateAI(GameObject* pGameObject, uint32 diff)
|
|
{
|
|
ELUNA_LOCK(this);
|
|
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)
|
|
{
|
|
ELUNA_LOCK(this);
|
|
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)
|
|
{
|
|
ELUNA_LOCK(this);
|
|
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)
|
|
{
|
|
ELUNA_LOCK(this);
|
|
Push(pGameObject);
|
|
Push(pPlayer);
|
|
CallAllFunctions(GameObjectEventBindings, GAMEOBJECT_EVENT_ON_DESTROYED, pGameObject->GetEntry());
|
|
}
|
|
|
|
void Eluna::OnDamaged(GameObject* pGameObject, Player* pPlayer)
|
|
{
|
|
ELUNA_LOCK(this);
|
|
Push(pGameObject);
|
|
Push(pPlayer);
|
|
CallAllFunctions(GameObjectEventBindings, GAMEOBJECT_EVENT_ON_DAMAGED, pGameObject->GetEntry());
|
|
}
|
|
#endif
|
|
#endif
|
|
|
|
void Eluna::OnLootStateChanged(GameObject* pGameObject, uint32 state)
|
|
{
|
|
ELUNA_LOCK(this);
|
|
Push(pGameObject);
|
|
Push(state);
|
|
CallAllFunctions(GameObjectEventBindings, GAMEOBJECT_EVENT_ON_LOOT_STATE_CHANGE, pGameObject->GetEntry());
|
|
}
|
|
|
|
void Eluna::OnGameObjectStateChanged(GameObject* pGameObject, uint32 state)
|
|
{
|
|
ELUNA_LOCK(this);
|
|
Push(pGameObject);
|
|
Push(state);
|
|
CallAllFunctions(GameObjectEventBindings, GAMEOBJECT_EVENT_ON_GO_STATE_CHANGED, pGameObject->GetEntry());
|
|
}
|
|
|
|
void Eluna::OnSpawn(GameObject* gameobject)
|
|
{
|
|
ELUNA_LOCK(this);
|
|
Push(gameobject);
|
|
CallAllFunctions(GameObjectEventBindings, GAMEOBJECT_EVENT_ON_SPAWN, gameobject->GetEntry());
|
|
}
|
|
|
|
void Eluna::OnAddToWorld(GameObject* gameobject)
|
|
{
|
|
ELUNA_LOCK(this);
|
|
Push(gameobject);
|
|
CallAllFunctions(GameObjectEventBindings, GAMEOBJECT_EVENT_ON_ADD, gameobject->GetEntry());
|
|
}
|
|
|
|
void Eluna::OnRemoveFromWorld(GameObject* gameobject)
|
|
{
|
|
ELUNA_LOCK(this);
|
|
Push(gameobject);
|
|
CallAllFunctions(GameObjectEventBindings, GAMEOBJECT_EVENT_ON_REMOVE, gameobject->GetEntry());
|
|
}
|
|
|
|
CreatureAI* Eluna::GetAI(Creature* creature)
|
|
{
|
|
ELUNA_LOCK(this);
|
|
if (!CreatureEventBindings->HasEvents(creature->GetEntry()))
|
|
return NULL;
|
|
return new ElunaCreatureAI(creature);
|
|
}
|
|
|
|
void Eluna::OnBGStart(BattleGround* bg, BattleGroundTypeId bgId, uint32 instanceId)
|
|
{
|
|
ELUNA_LOCK(this);
|
|
Push(bg);
|
|
Push(bgId);
|
|
Push(instanceId);
|
|
CallAllFunctions(BGEventBindings, BG_EVENT_ON_START);
|
|
}
|
|
|
|
void Eluna::OnBGEnd(BattleGround* bg, BattleGroundTypeId bgId, uint32 instanceId, Team winner)
|
|
{
|
|
ELUNA_LOCK(this);
|
|
Push(bg);
|
|
Push(bgId);
|
|
Push(instanceId);
|
|
Push(winner);
|
|
CallAllFunctions(BGEventBindings, BG_EVENT_ON_END);
|
|
}
|
|
|
|
void Eluna::OnBGCreate(BattleGround* bg, BattleGroundTypeId bgId, uint32 instanceId)
|
|
{
|
|
ELUNA_LOCK(this);
|
|
Push(bg);
|
|
Push(bgId);
|
|
Push(instanceId);
|
|
CallAllFunctions(BGEventBindings, BG_EVENT_ON_CREATE);
|
|
}
|
|
|
|
void Eluna::OnBGDestroy(BattleGround* bg, BattleGroundTypeId bgId, uint32 instanceId)
|
|
{
|
|
ELUNA_LOCK(this);
|
|
Push(bg);
|
|
Push(bgId);
|
|
Push(instanceId);
|
|
CallAllFunctions(BGEventBindings, BG_EVENT_ON_PRE_DESTROY);
|
|
}
|