[Rel21] Stage 2 of updates for Rel21 Build System

This commit is contained in:
Antz 2015-07-28 11:07:13 +01:00 committed by Antz
parent fdefc0869a
commit 0bffcd62ad
79 changed files with 26890 additions and 0 deletions

5
src/modules/Eluna/.gitignore vendored Normal file
View file

@ -0,0 +1,5 @@
*.orig
*.rej
*.bak
*.patch
*.diff

View file

@ -0,0 +1,209 @@
/*
* 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
*/
#ifndef AURAMETHODS_H
#define AURAMETHODS_H
/***
* The persistent effect of a [Spell] that remains on a [Unit] after the [Spell]
* has been cast.
*
* As an example, if you cast a damage-over-time spell on a target, an [Aura] is
* put on the target that deals damage continuously.
*
* [Aura]s on your player are displayed in-game as a series of icons to the left
* of the mini-map.
*/
namespace LuaAura
{
/**
* Returns the [Unit] that casted the [Spell] that caused this [Aura] to be applied.
*
* @return [Unit] caster
*/
int GetCaster(Eluna* /*E*/, lua_State* L, Aura* aura)
{
Eluna::Push(L, aura->GetCaster());
return 1;
}
/**
* Returns the GUID of the [Unit] that casted the [Spell] that caused this [Aura] to be applied.
*
* @return string caster_guid : the GUID of the Unit as a decimal string
*/
int GetCasterGUID(Eluna* /*E*/, lua_State* L, Aura* aura)
{
#ifndef TRINITY
Eluna::Push(L, aura->GetCasterGuid());
#else
Eluna::Push(L, aura->GetCasterGUID());
#endif
return 1;
}
/**
* Returns the level of the [Unit] that casted the [Spell] that caused this [Aura] to be applied.
*
* @return uint32 caster_level
*/
int GetCasterLevel(Eluna* /*E*/, lua_State* L, Aura* aura)
{
Eluna::Push(L, aura->GetCaster()->getLevel());
return 1;
}
/**
* Returns the amount of time left until the [Aura] expires.
*
* @return int32 duration : amount of time left in milliseconds
*/
int GetDuration(Eluna* /*E*/, lua_State* L, Aura* aura)
{
#ifndef TRINITY
Eluna::Push(L, aura->GetAuraDuration());
#else
Eluna::Push(L, aura->GetDuration());
#endif
return 1;
}
/**
* Returns the ID of the [Spell] that caused this [Aura] to be applied.
*
* @return uint32 aura_id
*/
int GetAuraId(Eluna* /*E*/, lua_State* L, Aura* aura)
{
Eluna::Push(L, aura->GetId());
return 1;
}
/**
* Returns the amount of time this [Aura] lasts when applied.
*
* To determine how much time has passed since this Aura was applied,
* subtract the result of [Aura]:GetDuration from the result of this method.
*
* @return int32 max_duration : the maximum duration of the Aura, in milliseconds
*/
int GetMaxDuration(Eluna* /*E*/, lua_State* L, Aura* aura)
{
#ifndef TRINITY
Eluna::Push(L, aura->GetAuraMaxDuration());
#else
Eluna::Push(L, aura->GetMaxDuration());
#endif
return 1;
}
/**
* Returns the number of times the [Aura] has "stacked".
*
* This is the same as the number displayed on the [Aura]'s icon in-game.
*
* @return uint32 stack_amount
*/
int GetStackAmount(Eluna* /*E*/, lua_State* L, Aura* aura)
{
Eluna::Push(L, aura->GetStackAmount());
return 1;
}
/**
* Returns the [Unit] that the [Aura] has been applied to.
*
* @return [Unit] owner
*/
int GetOwner(Eluna* /*E*/, lua_State* L, Aura* aura)
{
#ifndef TRINITY
Eluna::Push(L, aura->GetTarget());
#else
Eluna::Push(L, aura->GetOwner());
#endif
return 1;
}
/**
* Change the amount of time before the [Aura] expires.
*
* @param int32 duration : the new duration of the Aura, in milliseconds
*/
int SetDuration(Eluna* /*E*/, lua_State* L, Aura* aura)
{
int32 duration = Eluna::CHECKVAL<int32>(L, 2);
#ifndef TRINITY
aura->GetHolder()->SetAuraDuration(duration);
#if (defined(TBC) || defined(CLASSIC))
aura->GetHolder()->UpdateAuraDuration();
#else
aura->GetHolder()->SendAuraUpdate(false);
#endif
#else
aura->SetDuration(duration);
#endif
return 0;
}
/**
* Change the maximum amount of time before the [Aura] expires.
*
* This does not affect the current duration of the [Aura], but if the [Aura]
* is reset to the maximum duration, it will instead change to `duration`.
*
* @param int32 duration : the new maximum duration of the Aura, in milliseconds
*/
int SetMaxDuration(Eluna* /*E*/, lua_State* L, Aura* aura)
{
int32 duration = Eluna::CHECKVAL<int32>(L, 2);
#ifndef TRINITY
aura->GetHolder()->SetAuraMaxDuration(duration);
#if (defined(TBC) || defined(CLASSIC))
aura->GetHolder()->UpdateAuraDuration();
#else
aura->GetHolder()->SendAuraUpdate(false);
#endif
#else
aura->SetMaxDuration(duration);
#endif
return 0;
}
/**
* Change the amount of times the [Aura] has "stacked" on the [Unit].
*
* If `amount` is greater than or equal to the current number of stacks,
* then the [Aura] has its duration reset to the maximum duration.
*
* @param uint32 amount
*/
int SetStackAmount(Eluna* /*E*/, lua_State* L, Aura* aura)
{
uint8 amount = Eluna::CHECKVAL<uint8>(L, 2);
#ifndef TRINITY
aura->GetHolder()->SetStackAmount(amount);
#else
aura->SetStackAmount(amount);
#endif
return 0;
}
/**
* Remove this [Aura] from the [Unit] it is applied to.
*/
int Remove(Eluna* /*E*/, lua_State* L, Aura* aura)
{
#ifndef TRINITY
aura->GetTarget()->RemoveSpellAuraHolder(aura->GetHolder(), AURA_REMOVE_BY_CANCEL);
#else
aura->Remove();
#endif
Eluna::CHECKOBJ<ElunaObject>(L, 1)->Invalidate();
return 0;
}
};
#endif

View file

@ -0,0 +1,67 @@
/*
* 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
*/
#ifndef _BATTLEGROUND_HOOKS_H
#define _BATTLEGROUND_HOOKS_H
#include "Hooks.h"
#include "HookHelpers.h"
#include "LuaEngine.h"
#include "ElunaBinding.h"
#include "ElunaTemplate.h"
using namespace Hooks;
void Eluna::OnBGStart(BattleGround* bg, BattleGroundTypeId bgId, uint32 instanceId)
{
if (!BGEventBindings->HasEvents(BG_EVENT_ON_START))
return;
LOCK_ELUNA;
Push(bg);
Push(bgId);
Push(instanceId);
CallAllFunctions(BGEventBindings, BG_EVENT_ON_START);
}
void Eluna::OnBGEnd(BattleGround* bg, BattleGroundTypeId bgId, uint32 instanceId, Team winner)
{
if (!BGEventBindings->HasEvents(BG_EVENT_ON_END))
return;
LOCK_ELUNA;
Push(bg);
Push(bgId);
Push(instanceId);
Push(winner);
CallAllFunctions(BGEventBindings, BG_EVENT_ON_END);
}
void Eluna::OnBGCreate(BattleGround* bg, BattleGroundTypeId bgId, uint32 instanceId)
{
if (!BGEventBindings->HasEvents(BG_EVENT_ON_CREATE))
return;
LOCK_ELUNA;
Push(bg);
Push(bgId);
Push(instanceId);
CallAllFunctions(BGEventBindings, BG_EVENT_ON_CREATE);
}
void Eluna::OnBGDestroy(BattleGround* bg, BattleGroundTypeId bgId, uint32 instanceId)
{
if (!BGEventBindings->HasEvents(BG_EVENT_ON_PRE_DESTROY))
return;
LOCK_ELUNA;
Push(bg);
Push(bgId);
Push(instanceId);
CallAllFunctions(BGEventBindings, BG_EVENT_ON_PRE_DESTROY);
}
#endif // _BATTLEGROUND_HOOKS_H

View file

@ -0,0 +1,226 @@
/*
* 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
*/
#ifndef BATTLEGROUNDMETHODS_H
#define BATTLEGROUNDMETHODS_H
/***
* Contains the state of a battleground, e.g. Warsong Gulch, Arathi Basin, etc.
*/
namespace LuaBattleGround
{
/**
* Returns the name of the [BattleGround].
*
* @return string name
*/
int GetName(Eluna* /*E*/, lua_State* L, BattleGround* bg)
{
Eluna::Push(L, bg->GetName());
return 1;
}
/**
* Returns the amount of alive players in the [BattleGround] by the team ID.
*
* @param [Team] team : team ID
* @return uint32 count
*/
int GetAlivePlayersCountByTeam(Eluna* /*E*/, lua_State* L, BattleGround* bg)
{
uint32 team = Eluna::CHECKVAL<uint32>(L, 2);
Eluna::Push(L, bg->GetAlivePlayersCountByTeam((Team)team));
return 1;
}
/**
* Returns the [Map] of the [BattleGround].
*
* @return [Map] map
*/
int GetMap(Eluna* /*E*/, lua_State* L, BattleGround* bg)
{
Eluna::Push(L, bg->GetBgMap());
return 1;
}
/**
* Returns the bonus honor given by amount of kills in the specific [BattleGround].
*
* @param uint32 kills : amount of kills
* @return uint32 bonusHonor
*/
int GetBonusHonorFromKillCount(Eluna* /*E*/, lua_State* L, BattleGround* bg)
{
uint32 kills = Eluna::CHECKVAL<uint32>(L, 2);
Eluna::Push(L, bg->GetBonusHonorFromKill(kills));
return 1;
}
/**
* Returns the bracket ID of the specific [BattleGround].
*
* @return [BattleGroundBracketId] bracketId
*/
int GetBracketId(Eluna* /*E*/, lua_State* L, BattleGround* bg)
{
Eluna::Push(L, bg->GetBracketId());
return 1;
}
/**
* Returns the end time of the [BattleGround].
*
* @return uint32 endTime
*/
int GetEndTime(Eluna* /*E*/, lua_State* L, BattleGround* bg)
{
#ifdef CATA
Eluna::Push(L, bg->GetRemainingTime());
#else
Eluna::Push(L, bg->GetEndTime());
#endif
return 1;
}
/**
* Returns the amount of free slots for the selected team in the specific [BattleGround].
*
* @param [Team] team : team ID
* @return uint32 freeSlots
*/
int GetFreeSlotsForTeam(Eluna* /*E*/, lua_State* L, BattleGround* bg)
{
uint32 team = Eluna::CHECKVAL<uint32>(L, 2);
Eluna::Push(L, bg->GetFreeSlotsForTeam((Team)team));
return 1;
}
/**
* Returns the instance ID of the [BattleGround].
*
* @return uint32 instanceId
*/
int GetInstanceId(Eluna* /*E*/, lua_State* L, BattleGround* bg)
{
Eluna::Push(L, bg->GetInstanceID());
return 1;
}
/**
* Returns the map ID of the [BattleGround].
*
* @return uint32 mapId
*/
int GetMapId(Eluna* /*E*/, lua_State* L, BattleGround* bg)
{
Eluna::Push(L, bg->GetMapId());
return 1;
}
/**
* Returns the type ID of the [BattleGround].
*
* @return [BattleGroundTypeId] typeId
*/
int GetTypeId(Eluna* /*E*/, lua_State* L, BattleGround* bg)
{
Eluna::Push(L, bg->GetTypeID());
return 1;
}
/**
* Returns the max allowed [Player] level of the specific [BattleGround].
*
* @return uint32 maxLevel
*/
int GetMaxLevel(Eluna* /*E*/, lua_State* L, BattleGround* bg)
{
Eluna::Push(L, bg->GetMaxLevel());
return 1;
}
/**
* Returns the minimum allowed [Player] level of the specific [BattleGround].
*
* @return uint32 minLevel
*/
int GetMinLevel(Eluna* /*E*/, lua_State* L, BattleGround* bg)
{
Eluna::Push(L, bg->GetMinLevel());
return 1;
}
/**
* Returns the maximum allowed [Player] count of the specific [BattleGround].
*
* @return uint32 maxPlayerCount
*/
int GetMaxPlayers(Eluna* /*E*/, lua_State* L, BattleGround* bg)
{
Eluna::Push(L, bg->GetMaxPlayers());
return 1;
}
/**
* Returns the minimum allowed [Player] count of the specific [BattleGround].
*
* @return uint32 minPlayerCount
*/
int GetMinPlayers(Eluna* /*E*/, lua_State* L, BattleGround* bg)
{
Eluna::Push(L, bg->GetMinPlayers());
return 1;
}
/**
* Returns the maximum allowed [Player] count per team of the specific [BattleGround].
*
* @return uint32 maxTeamPlayerCount
*/
int GetMaxPlayersPerTeam(Eluna* /*E*/, lua_State* L, BattleGround* bg)
{
Eluna::Push(L, bg->GetMaxPlayersPerTeam());
return 1;
}
/**
* Returns the minimum allowed [Player] count per team of the specific [BattleGround].
*
* @return uint32 minTeamPlayerCount
*/
int GetMinPlayersPerTeam(Eluna* /*E*/, lua_State* L, BattleGround* bg)
{
Eluna::Push(L, bg->GetMinPlayersPerTeam());
return 1;
}
/**
* Returns the winning team of the specific [BattleGround].
*
* @return [Team] team
*/
int GetWinner(Eluna* /*E*/, lua_State* L, BattleGround* bg)
{
Eluna::Push(L, bg->GetWinner());
return 1;
}
/**
* Returns the status of the specific [BattleGround].
*
* @return [BattleGroundStatus] status
*/
int GetStatus(Eluna* /*E*/, lua_State* L, BattleGround* bg)
{
Eluna::Push(L, bg->GetStatus());
return 1;
}
};
#endif

View file

@ -0,0 +1,215 @@
#
# 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
#
if ( USE_COREPCH )
include_directories(${CMAKE_CURRENT_BINARY_DIR})
include_directories(${CMAKE_SOURCE_DIR})
endif ()
# Iterates through all the source files and adds them to the solution
file(GLOB sources_localdir *.cpp *.h)
# Adds all the method headers to its own source group
file(GLOB method_headers *Methods.h)
source_group("Methods" FILES ${method_headers})
set(LuaEngine_STAT_SRCS
${LuaEngine_STAT_SRCS}
${sources_localdir}
)
include_directories(
${CMAKE_SOURCE_DIR}/dep/zlib
${CMAKE_SOURCE_DIR}/dep/lualib
${CMAKE_BINARY_DIR}
${ACE_INCLUDE_DIR}
${MYSQL_INCLUDE_DIR}
${OPENSSL_INCLUDE_DIR}
)
add_library(LuaEngine STATIC
${LuaEngine_STAT_SRCS}
${game_STAT_SRCS}
${game_STAT_PCH_SRC}
)
if( ${CMAKE_PROJECT_NAME} STREQUAL "TrinityCore" )
include_directories(
${CMAKE_SOURCE_DIR}/dep/recastnavigation/Detour
${CMAKE_SOURCE_DIR}/dep/recastnavigation/Detour/Include
${CMAKE_SOURCE_DIR}/dep/recastnavigation/Recast
${CMAKE_SOURCE_DIR}/dep/recastnavigation/Recast/Include
${CMAKE_SOURCE_DIR}/dep/g3dlite/include
${CMAKE_SOURCE_DIR}/dep/SFMT
${CMAKE_SOURCE_DIR}/dep/cppformat
${CMAKE_SOURCE_DIR}/dep/mersennetwister
${CMAKE_SOURCE_DIR}/src/server/shared
${CMAKE_SOURCE_DIR}/src/server/shared/Configuration
${CMAKE_SOURCE_DIR}/src/server/shared/Cryptography
${CMAKE_SOURCE_DIR}/src/server/shared/Cryptography/Authentication
${CMAKE_SOURCE_DIR}/src/server/shared/Database
${CMAKE_SOURCE_DIR}/src/server/shared/DataStores
${CMAKE_SOURCE_DIR}/src/server/shared/Debugging
${CMAKE_SOURCE_DIR}/src/server/shared/Dynamic/CountedReference
${CMAKE_SOURCE_DIR}/src/server/shared/Dynamic/LinkedReference
${CMAKE_SOURCE_DIR}/src/server/shared/Dynamic
${CMAKE_SOURCE_DIR}/src/server/shared/Logging
${CMAKE_SOURCE_DIR}/src/server/shared/Packets
${CMAKE_SOURCE_DIR}/src/server/shared/Policies
${CMAKE_SOURCE_DIR}/src/server/shared/Threading
${CMAKE_SOURCE_DIR}/src/server/shared/Utilities
${CMAKE_SOURCE_DIR}/src/server/ipc
${CMAKE_SOURCE_DIR}/src/server/collision
${CMAKE_SOURCE_DIR}/src/server/collision/Management
${CMAKE_SOURCE_DIR}/src/server/collision/Models
${CMAKE_SOURCE_DIR}/src/server/collision/Maps
${CMAKE_SOURCE_DIR}/src/server/shared
${CMAKE_SOURCE_DIR}/src/server/shared/Database
${CMAKE_SOURCE_DIR}/src/server/game/Accounts
${CMAKE_SOURCE_DIR}/src/server/game/Achievements
${CMAKE_SOURCE_DIR}/src/server/game/Addons
${CMAKE_SOURCE_DIR}/src/server/game/Handlers
${CMAKE_SOURCE_DIR}/src/server/game/AI
${CMAKE_SOURCE_DIR}/src/server/game/AI/CoreAI
${CMAKE_SOURCE_DIR}/src/server/game/AI/EventAI
${CMAKE_SOURCE_DIR}/src/server/game/AI/ScriptedAI
${CMAKE_SOURCE_DIR}/src/server/game/AI/SmartScripts
${CMAKE_SOURCE_DIR}/src/server/game/AuctionHouse
${CMAKE_SOURCE_DIR}/src/server/game/Battlegrounds
${CMAKE_SOURCE_DIR}/src/server/game/Battlegrounds/Zones
${CMAKE_SOURCE_DIR}/src/server/game/Calendar
${CMAKE_SOURCE_DIR}/src/server/game/Chat
${CMAKE_SOURCE_DIR}/src/server/game/Chat/Channels
${CMAKE_SOURCE_DIR}/src/server/game/Conditions
${CMAKE_SOURCE_DIR}/src/server/shared/Configuration
${CMAKE_SOURCE_DIR}/src/server/game/Combat
${CMAKE_SOURCE_DIR}/src/server/game/DataStores
${CMAKE_SOURCE_DIR}/src/server/game/DungeonFinding
${CMAKE_SOURCE_DIR}/src/server/game/Entities/AreaTrigger
${CMAKE_SOURCE_DIR}/src/server/game/Entities/Corpse
${CMAKE_SOURCE_DIR}/src/server/game/Entities/Creature
${CMAKE_SOURCE_DIR}/src/server/game/Entities/DynamicObject
${CMAKE_SOURCE_DIR}/src/server/game/Entities/Item
${CMAKE_SOURCE_DIR}/src/server/game/Entities/Item/Container
${CMAKE_SOURCE_DIR}/src/server/game/Entities/GameObject
${CMAKE_SOURCE_DIR}/src/server/game/Entities/Object
${CMAKE_SOURCE_DIR}/src/server/game/Entities/Object/Updates
${CMAKE_SOURCE_DIR}/src/server/game/Entities/Pet
${CMAKE_SOURCE_DIR}/src/server/game/Entities/Player
${CMAKE_SOURCE_DIR}/src/server/game/Entities/Transport
${CMAKE_SOURCE_DIR}/src/server/game/Entities/Unit
${CMAKE_SOURCE_DIR}/src/server/game/Entities/Vehicle
${CMAKE_SOURCE_DIR}/src/server/game/Events
${CMAKE_SOURCE_DIR}/src/server/game/Globals
${CMAKE_SOURCE_DIR}/src/server/game/Grids
${CMAKE_SOURCE_DIR}/src/server/game/Grids/Cells
${CMAKE_SOURCE_DIR}/src/server/game/Grids/Notifiers
${CMAKE_SOURCE_DIR}/src/server/game/Groups
${CMAKE_SOURCE_DIR}/src/server/game/Guilds
${CMAKE_SOURCE_DIR}/src/server/game/Instances
${CMAKE_SOURCE_DIR}/src/server/game/LookingForGroup
${CMAKE_SOURCE_DIR}/src/server/game/Loot
${CMAKE_SOURCE_DIR}/src/server/game/Mails
${CMAKE_SOURCE_DIR}/src/server/game/Miscellaneous
${CMAKE_SOURCE_DIR}/src/server/game/Maps
${CMAKE_SOURCE_DIR}/src/server/game/Movement
${CMAKE_SOURCE_DIR}/src/server/game/Movement/MovementGenerators
${CMAKE_SOURCE_DIR}/src/server/game/Movement/Waypoints
${CMAKE_SOURCE_DIR}/src/server/game/Movement/Spline
${CMAKE_SOURCE_DIR}/src/server/game/Opcodes
${CMAKE_SOURCE_DIR}/src/server/game/OutdoorPvP
${CMAKE_SOURCE_DIR}/src/server/game/Pools
${CMAKE_SOURCE_DIR}/src/server/game/PrecompiledHeaders
${CMAKE_SOURCE_DIR}/src/server/game/Quests
${CMAKE_SOURCE_DIR}/src/server/game/Reputation
${CMAKE_SOURCE_DIR}/src/server/game/Scripting
${CMAKE_SOURCE_DIR}/src/server/game/Server
${CMAKE_SOURCE_DIR}/src/server/game/Server/Protocol
${CMAKE_SOURCE_DIR}/src/server/game/Server/Protocol/Handlers
${CMAKE_SOURCE_DIR}/src/server/game/Skills
${CMAKE_SOURCE_DIR}/src/server/game/Spells
${CMAKE_SOURCE_DIR}/src/server/game/Spells/Auras
${CMAKE_SOURCE_DIR}/src/server/game/Texts
${CMAKE_SOURCE_DIR}/src/server/game/Tickets
${CMAKE_SOURCE_DIR}/src/server/game/Tools
${CMAKE_SOURCE_DIR}/src/server/game/Weather
${CMAKE_SOURCE_DIR}/src/server/game/World
${CMAKE_SOURCE_DIR}/src/server/scripts/PrecompiledHeaders
${Boost_LIBRARIES}
)
find_package(Boost COMPONENTS system filesystem REQUIRED)
target_link_libraries(LuaEngine
game
${Boost_LIBRARIES}
)
add_dependencies(LuaEngine game)
if( WIN32 )
if ( MSVC )
add_custom_command(TARGET LuaEngine
POST_BUILD
COMMAND ${CMAKE_COMMAND} -E make_directory ${CMAKE_BINARY_DIR}/bin/$(ConfigurationName)/lua_scripts/extensions/
COMMAND ${CMAKE_COMMAND} -E copy_directory ${CMAKE_CURRENT_SOURCE_DIR}/extensions ${CMAKE_BINARY_DIR}/bin/$(ConfigurationName)/lua_scripts/extensions/
)
elseif ( MINGW )
add_custom_command(TARGET LuaEngine
POST_BUILD
COMMAND ${CMAKE_COMMAND} -E make_directory ${CMAKE_BINARY_DIR}/bin/lua_scripts/extensions/
COMMAND ${CMAKE_COMMAND} -E copy_directory ${CMAKE_CURRENT_SOURCE_DIR}/extensions ${CMAKE_BINARY_DIR}/bin/lua_scripts/extensions/
)
endif()
endif()
if( UNIX )
install(DIRECTORY extensions DESTINATION bin/lua_scripts/)
elseif( WIN32 )
install(DIRECTORY extensions DESTINATION "${CMAKE_BINARY_DIR}/bin/$(ConfigurationName)/lua_scripts/")
endif()
elseif( ${CMAKE_PROJECT_NAME} STREQUAL "MaNGOS" )
include_directories(
${CMAKE_SOURCE_DIR}/dep/g3dlite
${CMAKE_SOURCE_DIR}/src/shared
${CMAKE_SOURCE_DIR}/src/shared/Common
${CMAKE_SOURCE_DIR}/src/shared/Utilities
${CMAKE_SOURCE_DIR}/src/shared/Log
${CMAKE_SOURCE_DIR}/src/shared/DataStores
${CMAKE_SOURCE_DIR}/src/shared/Threading
${CMAKE_SOURCE_DIR}/src/framework
${CMAKE_SOURCE_DIR}/src/framework/Platform
${CMAKE_SOURCE_DIR}/src/game/BattleGround
${CMAKE_SOURCE_DIR}/src/game/Server
${CMAKE_SOURCE_DIR}/src/game/vmap
${CMAKE_SOURCE_DIR}/src/game/Maps
${CMAKE_SOURCE_DIR}/src/game/MotionGenerators
${CMAKE_SOURCE_DIR}/src/game/Tools
${CMAKE_SOURCE_DIR}/src/game/References
${CMAKE_SOURCE_DIR}/src/game/WorldHandlers
${CMAKE_SOURCE_DIR}/src/game/Object
)
if( WIN32 )
if ( MSVC )
add_custom_command(TARGET LuaEngine
POST_BUILD
COMMAND ${CMAKE_COMMAND} -E make_directory "${CMAKE_BINARY_DIR}/bin/$(ConfigurationName)/lua_scripts/extensions/"
COMMAND ${CMAKE_COMMAND} -E copy_directory "${CMAKE_CURRENT_SOURCE_DIR}/extensions" "${CMAKE_BINARY_DIR}/bin/$(ConfigurationName)/lua_scripts/extensions/"
)
elseif ( MINGW )
add_custom_command(TARGET LuaEngine
POST_BUILD
COMMAND ${CMAKE_COMMAND} -E make_directory "${CMAKE_BINARY_DIR}/bin/lua_scripts/extensions/"
COMMAND ${CMAKE_COMMAND} -E copy_directory "${CMAKE_CURRENT_SOURCE_DIR}/extensions" "${CMAKE_BINARY_DIR}/bin/ua_scripts/extensions/"
)
endif()
endif()
install(DIRECTORY extensions DESTINATION "${BIN_DIR}/lua_scripts/")
endif()

View file

@ -0,0 +1,93 @@
/*
* 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
*/
#ifndef CORPSEMETHODS_H
#define CORPSEMETHODS_H
/***
* The remains of a [Player] that has died.
*/
namespace LuaCorpse
{
/**
* Returns the GUID of the [Player] that left the [Corpse] behind.
*
* @return uint64 ownerGUID
*/
int GetOwnerGUID(Eluna* /*E*/, lua_State* L, Corpse* corpse)
{
#ifndef TRINITY
Eluna::Push(L, corpse->GetOwnerGuid());
#else
Eluna::Push(L, corpse->GetOwnerGUID());
#endif
return 1;
}
/**
* Returns the time when the [Player] became a ghost and spawned this [Corpse].
*
* @return uint32 ghostTime
*/
int GetGhostTime(Eluna* /*E*/, lua_State* L, Corpse* corpse)
{
Eluna::Push(L, corpse->GetGhostTime());
return 1;
}
/**
* Returns the [CorpseType] of a [Corpse].
*
* enum CorpseType
* {
* CORPSE_BONES = 0,
* CORPSE_RESURRECTABLE_PVE = 1,
* CORPSE_RESURRECTABLE_PVP = 2
* };
*
* @return [CorpseType] corpseType
*/
int GetType(Eluna* /*E*/, lua_State* L, Corpse* corpse)
{
Eluna::Push(L, corpse->GetType());
return 1;
}
/**
* Sets the "ghost time" to the current time.
*
* See [Corpse:GetGhostTime].
*/
int ResetGhostTime(Eluna* /*E*/, lua_State* /*L*/, Corpse* corpse)
{
corpse->ResetGhostTime();
return 0;
}
/**
* Saves the [Corpse] to the database.
*/
int SaveToDB(Eluna* /*E*/, lua_State* /*L*/, Corpse* corpse)
{
corpse->SaveToDB();
return 0;
}
/**
* Deletes the [Corpse] from the world.
*
* If the [Corpse]'s type is not BONES then this does nothing.
*/
int DeleteBonesFromWorld(Eluna* /*E*/, lua_State* /*L*/, Corpse* corpse)
{
// Prevent a failed assertion.
if (corpse->GetType() != CORPSE_BONES)
return 0;
corpse->DeleteBonesFromWorld();
return 0;
}
};
#endif

View file

@ -0,0 +1,487 @@
/*
* 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
*/
#ifndef _CREATURE_HOOKS_H
#define _CREATURE_HOOKS_H
#include "Hooks.h"
#include "HookHelpers.h"
#include "LuaEngine.h"
#include "ElunaBinding.h"
#include "ElunaIncludes.h"
#include "ElunaTemplate.h"
using namespace Hooks;
bool Eluna::OnDummyEffect(Unit* pCaster, uint32 spellId, SpellEffIndex effIndex, Creature* pTarget)
{
if (!CreatureEventBindings->HasEvents(CREATURE_EVENT_ON_DUMMY_EFFECT, pTarget->GetEntry()))
if (!CreatureUniqueBindings->HasEvents(CREATURE_EVENT_ON_DUMMY_EFFECT, pTarget->GET_GUID(), pTarget->GetInstanceId()))
return false;
LOCK_ELUNA;
Push(pCaster);
Push(spellId);
Push(effIndex);
Push(pTarget);
return CallAllFunctionsBool(CreatureEventBindings, CreatureUniqueBindings, CREATURE_EVENT_ON_DUMMY_EFFECT, pTarget->GetEntry(), pTarget->GET_GUID(), pTarget->GetInstanceId());
}
bool Eluna::OnGossipHello(Player* pPlayer, Creature* pCreature)
{
if (!CreatureGossipBindings->HasEvents(GOSSIP_EVENT_ON_HELLO, pCreature->GetEntry()))
return false;
LOCK_ELUNA;
pPlayer->PlayerTalkClass->ClearMenus();
Push(pPlayer);
Push(pCreature);
return CallAllFunctionsBool(CreatureGossipBindings, GOSSIP_EVENT_ON_HELLO, pCreature->GetEntry(), true);
}
bool Eluna::OnGossipSelect(Player* pPlayer, Creature* pCreature, uint32 sender, uint32 action)
{
if (!CreatureGossipBindings->HasEvents(GOSSIP_EVENT_ON_SELECT, pCreature->GetEntry()))
return false;
LOCK_ELUNA;
pPlayer->PlayerTalkClass->ClearMenus();
Push(pPlayer);
Push(pCreature);
Push(sender);
Push(action);
return CallAllFunctionsBool(CreatureGossipBindings, GOSSIP_EVENT_ON_SELECT, pCreature->GetEntry(), true);
}
bool Eluna::OnGossipSelectCode(Player* pPlayer, Creature* pCreature, uint32 sender, uint32 action, const char* code)
{
if (!CreatureGossipBindings->HasEvents(GOSSIP_EVENT_ON_SELECT, pCreature->GetEntry()))
return false;
LOCK_ELUNA;
pPlayer->PlayerTalkClass->ClearMenus();
Push(pPlayer);
Push(pCreature);
Push(sender);
Push(action);
Push(code);
return CallAllFunctionsBool(CreatureGossipBindings, GOSSIP_EVENT_ON_SELECT, pCreature->GetEntry(), true);
}
bool Eluna::OnQuestAccept(Player* pPlayer, Creature* pCreature, Quest const* pQuest)
{
if (!CreatureEventBindings->HasEvents(CREATURE_EVENT_ON_QUEST_ACCEPT, pCreature->GetEntry()))
if (!CreatureUniqueBindings->HasEvents(CREATURE_EVENT_ON_QUEST_ACCEPT, pCreature->GET_GUID(), pCreature->GetInstanceId()))
return false;
LOCK_ELUNA;
Push(pPlayer);
Push(pCreature);
Push(pQuest);
return CallAllFunctionsBool(CreatureEventBindings, CreatureUniqueBindings, CREATURE_EVENT_ON_QUEST_ACCEPT, pCreature->GetEntry(), pCreature->GET_GUID(), pCreature->GetInstanceId());
}
bool Eluna::OnQuestReward(Player* pPlayer, Creature* pCreature, Quest const* pQuest, uint32 opt)
{
if (!CreatureEventBindings->HasEvents(CREATURE_EVENT_ON_QUEST_REWARD, pCreature->GetEntry()))
if (!CreatureUniqueBindings->HasEvents(CREATURE_EVENT_ON_QUEST_REWARD, pCreature->GET_GUID(), pCreature->GetInstanceId()))
return false;
LOCK_ELUNA;
Push(pPlayer);
Push(pCreature);
Push(pQuest);
Push(opt);
return CallAllFunctionsBool(CreatureEventBindings, CreatureUniqueBindings, CREATURE_EVENT_ON_QUEST_REWARD, pCreature->GetEntry(), pCreature->GET_GUID(), pCreature->GetInstanceId());
}
uint32 Eluna::GetDialogStatus(Player* pPlayer, Creature* pCreature)
{
if (!CreatureEventBindings->HasEvents(CREATURE_EVENT_ON_DIALOG_STATUS, pCreature->GetEntry()))
if (!CreatureUniqueBindings->HasEvents(CREATURE_EVENT_ON_DIALOG_STATUS, pCreature->GET_GUID(), pCreature->GetInstanceId()))
return DIALOG_STATUS_SCRIPTED_NO_STATUS;
LOCK_ELUNA;
Push(pPlayer);
Push(pCreature);
CallAllFunctions(CreatureEventBindings, CreatureUniqueBindings, CREATURE_EVENT_ON_DIALOG_STATUS, pCreature->GetEntry(), pCreature->GET_GUID(), pCreature->GetInstanceId());
return DIALOG_STATUS_SCRIPTED_NO_STATUS;
}
void Eluna::OnAddToWorld(Creature* creature)
{
if (!CreatureEventBindings->HasEvents(CREATURE_EVENT_ON_ADD, creature->GetEntry()))
if (!CreatureUniqueBindings->HasEvents(CREATURE_EVENT_ON_ADD, creature->GET_GUID(), creature->GetInstanceId()))
return;
LOCK_ELUNA;
Push(creature);
CallAllFunctions(CreatureEventBindings, CreatureUniqueBindings, CREATURE_EVENT_ON_ADD, creature->GetEntry(), creature->GET_GUID(), creature->GetInstanceId());
}
void Eluna::OnRemoveFromWorld(Creature* creature)
{
if (!CreatureEventBindings->HasEvents(CREATURE_EVENT_ON_REMOVE, creature->GetEntry()))
if (!CreatureUniqueBindings->HasEvents(CREATURE_EVENT_ON_REMOVE, creature->GET_GUID(), creature->GetInstanceId()))
return;
LOCK_ELUNA;
Push(creature);
CallAllFunctions(CreatureEventBindings, CreatureUniqueBindings, CREATURE_EVENT_ON_REMOVE, creature->GetEntry(), creature->GET_GUID(), creature->GetInstanceId());
}
bool Eluna::OnSummoned(Creature* pCreature, Unit* pSummoner)
{
if (!CreatureEventBindings->HasEvents(CREATURE_EVENT_ON_SUMMONED, pCreature->GetEntry()))
if (!CreatureUniqueBindings->HasEvents(CREATURE_EVENT_ON_SUMMONED, pCreature->GET_GUID(), pCreature->GetInstanceId()))
return false;
LOCK_ELUNA;
Push(pCreature);
Push(pSummoner);
return CallAllFunctionsBool(CreatureEventBindings, CreatureUniqueBindings, CREATURE_EVENT_ON_SUMMONED, pCreature->GetEntry(), pCreature->GET_GUID(), pCreature->GetInstanceId());
}
bool Eluna::UpdateAI(Creature* me, const uint32 diff)
{
if (!CreatureEventBindings->HasEvents(CREATURE_EVENT_ON_AIUPDATE, me->GetEntry()))
if (!CreatureUniqueBindings->HasEvents(CREATURE_EVENT_ON_AIUPDATE, me->GET_GUID(), me->GetInstanceId()))
return false;
LOCK_ELUNA;
Push(me);
Push(diff);
return CallAllFunctionsBool(CreatureEventBindings, CreatureUniqueBindings, CREATURE_EVENT_ON_AIUPDATE, me->GetEntry(), me->GET_GUID(), me->GetInstanceId());
}
//Called for reaction at enter to combat if not in combat yet (enemy can be NULL)
//Called at creature aggro either by MoveInLOS or Attack Start
bool Eluna::EnterCombat(Creature* me, Unit* target)
{
if (!CreatureEventBindings->HasEvents(CREATURE_EVENT_ON_ENTER_COMBAT, me->GetEntry()))
if (!CreatureUniqueBindings->HasEvents(CREATURE_EVENT_ON_ENTER_COMBAT, me->GET_GUID(), me->GetInstanceId()))
return false;
LOCK_ELUNA;
Push(me);
Push(target);
return CallAllFunctionsBool(CreatureEventBindings, CreatureUniqueBindings, CREATURE_EVENT_ON_ENTER_COMBAT, me->GetEntry(), me->GET_GUID(), me->GetInstanceId());
}
// Called at any Damage from any attacker (before damage apply)
bool Eluna::DamageTaken(Creature* me, Unit* attacker, uint32& damage)
{
if (!CreatureEventBindings->HasEvents(CREATURE_EVENT_ON_DAMAGE_TAKEN, me->GetEntry()))
if (!CreatureUniqueBindings->HasEvents(CREATURE_EVENT_ON_DAMAGE_TAKEN, me->GET_GUID(), me->GetInstanceId()))
return false;
LOCK_ELUNA;
bool result = false;
Push(me);
Push(attacker);
Push(damage);
int damageIndex = lua_gettop(L);
int n = SetupStack(CreatureEventBindings, CreatureUniqueBindings, CREATURE_EVENT_ON_DAMAGE_TAKEN, me->GetEntry(), me->GET_GUID(), me->GetInstanceId(), 3);
while (n > 0)
{
int r = CallOneFunction(n--, 3, 2);
if (lua_isboolean(L, r + 0) && lua_toboolean(L, r + 0))
result = true;
if (lua_isnumber(L, r + 1))
{
damage = Eluna::CHECKVAL<uint32>(L, r + 1);
// Update the stack for subsequent calls.
ReplaceArgument(damage, damageIndex);
}
lua_pop(L, 2);
}
CleanUpStack(3);
return result;
}
//Called at creature death
bool Eluna::JustDied(Creature* me, Unit* killer)
{
On_Reset(me);
if (!CreatureEventBindings->HasEvents(CREATURE_EVENT_ON_DIED, me->GetEntry()))
if (!CreatureUniqueBindings->HasEvents(CREATURE_EVENT_ON_DIED, me->GET_GUID(), me->GetInstanceId()))
return false;
LOCK_ELUNA;
Push(me);
Push(killer);
return CallAllFunctionsBool(CreatureEventBindings, CreatureUniqueBindings, CREATURE_EVENT_ON_DIED, me->GetEntry(), me->GET_GUID(), me->GetInstanceId());
}
//Called at creature killing another unit
bool Eluna::KilledUnit(Creature* me, Unit* victim)
{
if (!CreatureEventBindings->HasEvents(CREATURE_EVENT_ON_TARGET_DIED, me->GetEntry()))
if (!CreatureUniqueBindings->HasEvents(CREATURE_EVENT_ON_TARGET_DIED, me->GET_GUID(), me->GetInstanceId()))
return false;
LOCK_ELUNA;
Push(me);
Push(victim);
return CallAllFunctionsBool(CreatureEventBindings, CreatureUniqueBindings, CREATURE_EVENT_ON_TARGET_DIED, me->GetEntry(), me->GET_GUID(), me->GetInstanceId());
}
// Called when the creature summon successfully other creature
bool Eluna::JustSummoned(Creature* me, Creature* summon)
{
if (!CreatureEventBindings->HasEvents(CREATURE_EVENT_ON_JUST_SUMMONED_CREATURE, me->GetEntry()))
if (!CreatureUniqueBindings->HasEvents(CREATURE_EVENT_ON_JUST_SUMMONED_CREATURE, me->GET_GUID(), me->GetInstanceId()))
return false;
LOCK_ELUNA;
Push(me);
Push(summon);
return CallAllFunctionsBool(CreatureEventBindings, CreatureUniqueBindings, CREATURE_EVENT_ON_JUST_SUMMONED_CREATURE, me->GetEntry(), me->GET_GUID(), me->GetInstanceId());
}
// Called when a summoned creature is despawned
bool Eluna::SummonedCreatureDespawn(Creature* me, Creature* summon)
{
if (!CreatureEventBindings->HasEvents(CREATURE_EVENT_ON_SUMMONED_CREATURE_DESPAWN, me->GetEntry()))
if (!CreatureUniqueBindings->HasEvents(CREATURE_EVENT_ON_SUMMONED_CREATURE_DESPAWN, me->GET_GUID(), me->GetInstanceId()))
return false;
LOCK_ELUNA;
Push(me);
Push(summon);
return CallAllFunctionsBool(CreatureEventBindings, CreatureUniqueBindings, CREATURE_EVENT_ON_SUMMONED_CREATURE_DESPAWN, me->GetEntry(), me->GET_GUID(), me->GetInstanceId());
}
//Called at waypoint reached or PointMovement end
bool Eluna::MovementInform(Creature* me, uint32 type, uint32 id)
{
if (!CreatureEventBindings->HasEvents(CREATURE_EVENT_ON_REACH_WP, me->GetEntry()))
if (!CreatureUniqueBindings->HasEvents(CREATURE_EVENT_ON_REACH_WP, me->GET_GUID(), me->GetInstanceId()))
return false;
LOCK_ELUNA;
Push(me);
Push(type);
Push(id);
return CallAllFunctionsBool(CreatureEventBindings, CreatureUniqueBindings, CREATURE_EVENT_ON_REACH_WP, me->GetEntry(), me->GET_GUID(), me->GetInstanceId());
}
// Called before EnterCombat even before the creature is in combat.
bool Eluna::AttackStart(Creature* me, Unit* target)
{
if (!CreatureEventBindings->HasEvents(CREATURE_EVENT_ON_PRE_COMBAT, me->GetEntry()))
if (!CreatureUniqueBindings->HasEvents(CREATURE_EVENT_ON_PRE_COMBAT, me->GET_GUID(), me->GetInstanceId()))
return false;
LOCK_ELUNA;
Push(me);
Push(target);
return CallAllFunctionsBool(CreatureEventBindings, CreatureUniqueBindings, CREATURE_EVENT_ON_PRE_COMBAT, me->GetEntry(), me->GET_GUID(), me->GetInstanceId());
}
// Called for reaction at stopping attack at no attackers or targets
bool Eluna::EnterEvadeMode(Creature* me)
{
On_Reset(me);
if (!CreatureEventBindings->HasEvents(CREATURE_EVENT_ON_LEAVE_COMBAT, me->GetEntry()))
if (!CreatureUniqueBindings->HasEvents(CREATURE_EVENT_ON_LEAVE_COMBAT, me->GET_GUID(), me->GetInstanceId()))
return false;
LOCK_ELUNA;
Push(me);
return CallAllFunctionsBool(CreatureEventBindings, CreatureUniqueBindings, CREATURE_EVENT_ON_LEAVE_COMBAT, me->GetEntry(), me->GET_GUID(), me->GetInstanceId());
}
// Called when the creature is target of hostile action: swing, hostile spell landed, fear/etc)
bool Eluna::AttackedBy(Creature* me, Unit* attacker)
{
if (!CreatureEventBindings->HasEvents(CREATURE_EVENT_ON_ATTACKED_AT, me->GetEntry()))
if (!CreatureUniqueBindings->HasEvents(CREATURE_EVENT_ON_ATTACKED_AT, me->GET_GUID(), me->GetInstanceId()))
return false;
LOCK_ELUNA;
Push(me);
Push(attacker);
return CallAllFunctionsBool(CreatureEventBindings, CreatureUniqueBindings, CREATURE_EVENT_ON_ATTACKED_AT, me->GetEntry(), me->GET_GUID(), me->GetInstanceId());
}
// Called when creature is spawned or respawned (for reseting variables)
bool Eluna::JustRespawned(Creature* me)
{
On_Reset(me);
if (!CreatureEventBindings->HasEvents(CREATURE_EVENT_ON_SPAWN, me->GetEntry()))
if (!CreatureUniqueBindings->HasEvents(CREATURE_EVENT_ON_SPAWN, me->GET_GUID(), me->GetInstanceId()))
return false;
LOCK_ELUNA;
Push(me);
return CallAllFunctionsBool(CreatureEventBindings, CreatureUniqueBindings, CREATURE_EVENT_ON_SPAWN, me->GetEntry(), me->GET_GUID(), me->GetInstanceId());
}
// Called at reaching home after evade
bool Eluna::JustReachedHome(Creature* me)
{
if (!CreatureEventBindings->HasEvents(CREATURE_EVENT_ON_REACH_HOME, me->GetEntry()))
if (!CreatureUniqueBindings->HasEvents(CREATURE_EVENT_ON_REACH_HOME, me->GET_GUID(), me->GetInstanceId()))
return false;
LOCK_ELUNA;
Push(me);
return CallAllFunctionsBool(CreatureEventBindings, CreatureUniqueBindings, CREATURE_EVENT_ON_REACH_HOME, me->GetEntry(), me->GET_GUID(), me->GetInstanceId());
}
// Called at text emote receive from player
bool Eluna::ReceiveEmote(Creature* me, Player* player, uint32 emoteId)
{
if (!CreatureEventBindings->HasEvents(CREATURE_EVENT_ON_RECEIVE_EMOTE, me->GetEntry()))
if (!CreatureUniqueBindings->HasEvents(CREATURE_EVENT_ON_RECEIVE_EMOTE, me->GET_GUID(), me->GetInstanceId()))
return false;
LOCK_ELUNA;
Push(me);
Push(player);
Push(emoteId);
return CallAllFunctionsBool(CreatureEventBindings, CreatureUniqueBindings, CREATURE_EVENT_ON_RECEIVE_EMOTE, me->GetEntry(), me->GET_GUID(), me->GetInstanceId());
}
// called when the corpse of this creature gets removed
bool Eluna::CorpseRemoved(Creature* me, uint32& respawnDelay)
{
if (!CreatureEventBindings->HasEvents(CREATURE_EVENT_ON_CORPSE_REMOVED, me->GetEntry()))
if (!CreatureUniqueBindings->HasEvents(CREATURE_EVENT_ON_CORPSE_REMOVED, me->GET_GUID(), me->GetInstanceId()))
return false;
LOCK_ELUNA;
bool result = false;
Push(me);
Push(respawnDelay);
int respawnDelayIndex = lua_gettop(L);
int n = SetupStack(CreatureEventBindings, CreatureUniqueBindings, CREATURE_EVENT_ON_CORPSE_REMOVED, me->GetEntry(), me->GET_GUID(), me->GetInstanceId(), 2);
while (n > 0)
{
int r = CallOneFunction(n--, 2, 2);
if (lua_isboolean(L, r + 0) && lua_toboolean(L, r + 0))
result = true;
if (lua_isnumber(L, r + 1))
{
respawnDelay = Eluna::CHECKVAL<uint32>(L, r + 1);
// Update the stack for subsequent calls.
ReplaceArgument(respawnDelay, respawnDelayIndex);
}
lua_pop(L, 2);
}
CleanUpStack(2);
return result;
}
bool Eluna::MoveInLineOfSight(Creature* me, Unit* who)
{
if (!CreatureEventBindings->HasEvents(CREATURE_EVENT_ON_MOVE_IN_LOS, me->GetEntry()))
if (!CreatureUniqueBindings->HasEvents(CREATURE_EVENT_ON_MOVE_IN_LOS, me->GET_GUID(), me->GetInstanceId()))
return false;
LOCK_ELUNA;
Push(me);
Push(who);
return CallAllFunctionsBool(CreatureEventBindings, CreatureUniqueBindings, CREATURE_EVENT_ON_MOVE_IN_LOS, me->GetEntry(), me->GET_GUID(), me->GetInstanceId());
}
// Called on creature initial spawn, respawn, death, evade (leave combat)
void Eluna::On_Reset(Creature* me) // Not an override, custom
{
if (!CreatureEventBindings->HasEvents(CREATURE_EVENT_ON_RESET, me->GetEntry()))
if (!CreatureUniqueBindings->HasEvents(CREATURE_EVENT_ON_RESET, me->GET_GUID(), me->GetInstanceId()))
return;
LOCK_ELUNA;
Push(me);
CallAllFunctions(CreatureEventBindings, CreatureUniqueBindings, CREATURE_EVENT_ON_RESET, me->GetEntry(), me->GET_GUID(), me->GetInstanceId());
}
// Called when hit by a spell
bool Eluna::SpellHit(Creature* me, Unit* caster, SpellInfo const* spell)
{
if (!CreatureEventBindings->HasEvents(CREATURE_EVENT_ON_HIT_BY_SPELL, me->GetEntry()))
if (!CreatureUniqueBindings->HasEvents(CREATURE_EVENT_ON_HIT_BY_SPELL, me->GET_GUID(), me->GetInstanceId()))
return false;
LOCK_ELUNA;
Push(me);
Push(caster);
Push(spell->Id); // Pass spell object?
return CallAllFunctionsBool(CreatureEventBindings, CreatureUniqueBindings, CREATURE_EVENT_ON_HIT_BY_SPELL, me->GetEntry(), me->GET_GUID(), me->GetInstanceId());
}
// Called when spell hits a target
bool Eluna::SpellHitTarget(Creature* me, Unit* target, SpellInfo const* spell)
{
if (!CreatureEventBindings->HasEvents(CREATURE_EVENT_ON_SPELL_HIT_TARGET, me->GetEntry()))
if (!CreatureUniqueBindings->HasEvents(CREATURE_EVENT_ON_SPELL_HIT_TARGET, me->GET_GUID(), me->GetInstanceId()))
return false;
LOCK_ELUNA;
Push(me);
Push(target);
Push(spell->Id); // Pass spell object?
return CallAllFunctionsBool(CreatureEventBindings, CreatureUniqueBindings, CREATURE_EVENT_ON_SPELL_HIT_TARGET, me->GetEntry(), me->GET_GUID(), me->GetInstanceId());
}
#ifdef TRINITY
bool Eluna::SummonedCreatureDies(Creature* me, Creature* summon, Unit* killer)
{
if (!CreatureEventBindings->HasEvents(CREATURE_EVENT_ON_SUMMONED_CREATURE_DIED, me->GetEntry()))
if (!CreatureUniqueBindings->HasEvents(CREATURE_EVENT_ON_SUMMONED_CREATURE_DIED, me->GET_GUID(), me->GetInstanceId()))
return false;
LOCK_ELUNA;
Push(me);
Push(summon);
Push(killer);
return CallAllFunctionsBool(CreatureEventBindings, CreatureUniqueBindings, CREATURE_EVENT_ON_SUMMONED_CREATURE_DIED, me->GetEntry(), me->GET_GUID(), me->GetInstanceId());
}
// Called when owner takes damage
bool Eluna::OwnerAttackedBy(Creature* me, Unit* attacker)
{
if (!CreatureEventBindings->HasEvents(CREATURE_EVENT_ON_OWNER_ATTACKED_AT, me->GetEntry()))
if (!CreatureUniqueBindings->HasEvents(CREATURE_EVENT_ON_OWNER_ATTACKED_AT, me->GET_GUID(), me->GetInstanceId()))
return false;
LOCK_ELUNA;
Push(me);
Push(attacker);
return CallAllFunctionsBool(CreatureEventBindings, CreatureUniqueBindings, CREATURE_EVENT_ON_OWNER_ATTACKED_AT, me->GetEntry(), me->GET_GUID(), me->GetInstanceId());
}
// Called when owner attacks something
bool Eluna::OwnerAttacked(Creature* me, Unit* target)
{
if (!CreatureEventBindings->HasEvents(CREATURE_EVENT_ON_OWNER_ATTACKED, me->GetEntry()))
if (!CreatureUniqueBindings->HasEvents(CREATURE_EVENT_ON_OWNER_ATTACKED, me->GET_GUID(), me->GetInstanceId()))
return false;
LOCK_ELUNA;
Push(me);
Push(target);
return CallAllFunctionsBool(CreatureEventBindings, CreatureUniqueBindings, CREATURE_EVENT_ON_OWNER_ATTACKED, me->GetEntry(), me->GET_GUID(), me->GetInstanceId());
}
#endif // TRINITY
#endif // _CREATURE_HOOKS_H

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,573 @@
/*
* 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
*/
#ifndef _ELUNA_BINDING_H
#define _ELUNA_BINDING_H
#include "Common.h"
#include "LuaEngine.h"
#include "ElunaUtility.h"
extern "C"
{
#include "lua.h"
#include "lauxlib.h"
};
#ifdef WIN32
// VC++ complains about UniqueBind because one of its template types is really long.
#pragma warning(disable:4503)
#endif
class ElunaBind : public ElunaUtil::RWLockable
{
public:
struct Binding
{
int functionReference;
bool isTemporary;
uint32 remainingShots;
int cancelCallbackRef; // Reference to a callback that will cancel this binding, or 0.
Eluna& E;
Binding(Eluna& _E, int funcRef, uint32 shots, int cancelCallbackRef) :
functionReference(funcRef),
isTemporary(shots != 0 && cancelCallbackRef == 0),
remainingShots(shots),
cancelCallbackRef(cancelCallbackRef),
E(_E)
{
}
~Binding()
{
// Remove our function and cancel callback from the registry when the Binding is deleted.
if (cancelCallbackRef > 0)
luaL_unref(E.L, LUA_REGISTRYINDEX, cancelCallbackRef);
luaL_unref(E.L, LUA_REGISTRYINDEX, functionReference);
}
};
typedef std::vector<Binding*> FunctionRefVector;
typedef UNORDERED_MAP<int, FunctionRefVector> EventToFunctionsMap;
Eluna& E;
const char* groupName;
ElunaBind(const char* bindGroupName, Eluna& _E) : E(_E), groupName(bindGroupName)
{
}
virtual ~ElunaBind()
{
Clear();
}
// unregisters all registered functions and clears all registered events from the bindings
virtual void Clear() { };
virtual void ClearOne(int ref, uint32 event_id, uint32 entry, uint64 guid) = 0;
};
template<typename T>
class EventBind : public ElunaBind
{
public:
EventBind(const char* bindGroupName, Eluna& _E) : ElunaBind(bindGroupName, _E)
{
}
// unregisters all registered functions and clears all registered events from the bind std::maps (reset)
void Clear() override
{
WriteGuard guard(GetLock());
for (EventToFunctionsMap::iterator itr = Bindings.begin(); itr != Bindings.end(); ++itr)
{
FunctionRefVector& funcrefvec = itr->second;
std::vector<int> cancelRefVector;
for (FunctionRefVector::iterator it = funcrefvec.begin(); it != funcrefvec.end(); ++it)
{
Binding* binding = (*it);
// Can't call the callback now, since it might modify `v` and crash the server.
// Just add the ref to a list and call them all after this loop.
if (binding->cancelCallbackRef)
cancelRefVector.push_back(binding->cancelCallbackRef);
else
delete binding; // Don't bother removing from list, clear is called at end anyway.
}
// Call all of the cancel callbacks for bindings with cancel callbacks.
for (std::vector<int>::iterator i = cancelRefVector.begin(); i != cancelRefVector.end(); ++i)
{
lua_rawgeti(E.L, LUA_REGISTRYINDEX, (*i));
lua_call(E.L, 0, 0);
}
funcrefvec.clear();
}
Bindings.clear();
}
void Clear(uint32 event_id)
{
WriteGuard guard(GetLock());
FunctionRefVector& v = Bindings[event_id];
std::vector<int> cancelRefVector;
for (FunctionRefVector::iterator itr = v.begin(); itr != v.end(); ++itr)
{
Binding* binding = (*itr);
// Can't call the callback now, since it might modify `v` and crash the server.
// Just add the ref to a list and call them all after this loop.
if (binding->cancelCallbackRef)
cancelRefVector.push_back(binding->cancelCallbackRef);
else
delete binding; // Don't bother removing from list, clear is called at end anyway.
}
// Call all of the cancel callbacks for bindings with cancel callbacks.
for (std::vector<int>::iterator i = cancelRefVector.begin(); i != cancelRefVector.end(); ++i)
{
lua_rawgeti(E.L, LUA_REGISTRYINDEX, (*i));
lua_call(E.L, 0, 0);
}
v.clear();
}
void ClearOne(int ref, uint32 event_id, uint32 entry, uint64 guid) override
{
ASSERT(entry == 0 && guid == 0);
WriteGuard guard(GetLock());
FunctionRefVector& funcrefvec = Bindings[event_id];
for (FunctionRefVector::iterator i = funcrefvec.begin(); i != funcrefvec.end(); ++i)
{
Binding* binding = (*i);
if (binding->functionReference == ref)
{
i = funcrefvec.erase(i);
delete binding;
return;
}
}
ASSERT(false && "tried to clear function ref that doesn't exist");
}
// Pushes the function references and updates the counters on the binds and erases them if the counter would reach 0
void PushFuncRefs(lua_State* L, int event_id)
{
WriteGuard guard(GetLock());
for (FunctionRefVector::iterator it = Bindings[event_id].begin(); it != Bindings[event_id].end();)
{
FunctionRefVector::iterator it_old = it++;
Binding* binding = (*it_old);
lua_rawgeti(L, LUA_REGISTRYINDEX, binding->functionReference);
if (binding->isTemporary)
{
// Bad things will happen if there's a cancel callback (due to ref reuse).
ASSERT(binding->cancelCallbackRef == 0);
binding->remainingShots--;
if (binding->remainingShots == 0)
{
delete binding;
Bindings[event_id].erase(it_old);
}
}
}
if (Bindings[event_id].empty())
Bindings.erase(event_id);
};
void Insert(int eventId, int funcRef, uint32 shots, int callbackRef = 0) // Inserts a new registered event
{
WriteGuard guard(GetLock());
Bindings[eventId].push_back(new Binding(E, funcRef, shots, callbackRef));
}
// Checks if there are events for ID
bool HasEvents(T eventId)
{
ReadGuard guard(GetLock());
if (!E.IsEnabled())
return false;
if (Bindings.empty())
return false;
if (Bindings.find(eventId) == Bindings.end())
return false;
return true;
}
EventToFunctionsMap Bindings; // Binding store Bindings[eventId] = {(funcRef, counter)};
};
template<typename T>
class EntryBind : public ElunaBind
{
public:
typedef UNORDERED_MAP<uint32, EventToFunctionsMap> EntryToEventsMap;
EntryBind(const char* bindGroupName, Eluna& _E) : ElunaBind(bindGroupName, _E)
{
}
// unregisters all registered functions and clears all registered events from the bindmap
void Clear() override
{
WriteGuard guard(GetLock());
for (EntryToEventsMap::iterator itr = Bindings.begin(); itr != Bindings.end(); ++itr)
{
EventToFunctionsMap& funcmap = itr->second;
for (EventToFunctionsMap::iterator it = funcmap.begin(); it != funcmap.end(); ++it)
{
FunctionRefVector& funcrefvec = it->second;
std::vector<int> cancelRefVector;
for (FunctionRefVector::iterator i = funcrefvec.begin(); i != funcrefvec.end(); ++i)
{
Binding* binding = (*i);
// Can't call the callback now, since it might modify `v` and crash the server.
// Just add the ref to a list and call them all after this loop.
if (binding->cancelCallbackRef)
cancelRefVector.push_back(binding->cancelCallbackRef);
else
delete binding; // Don't bother removing from list, clear is called at end anyway.
}
// Call all of the cancel callbacks for bindings with cancel callbacks.
for (std::vector<int>::iterator i = cancelRefVector.begin(); i != cancelRefVector.end(); ++i)
{
lua_rawgeti(E.L, LUA_REGISTRYINDEX, (*i));
lua_call(E.L, 0, 0);
}
funcrefvec.clear();
}
funcmap.clear();
}
Bindings.clear();
}
void Clear(uint32 entry, uint32 event_id)
{
WriteGuard guard(GetLock());
FunctionRefVector& v = Bindings[entry][event_id];
std::vector<int> cancelRefVector;
for (FunctionRefVector::iterator itr = v.begin(); itr != v.end(); ++itr)
{
Binding* binding = (*itr);
// Can't call the callback now, since it might modify `v` and crash the server.
// Just add the ref to a list and call them all after this loop.
if (binding->cancelCallbackRef)
cancelRefVector.push_back(binding->cancelCallbackRef);
else
delete binding; // Don't bother removing from list, clear is called at end anyway.
}
// Call all of the cancel callbacks for bindings with cancel callbacks.
for (std::vector<int>::iterator i = cancelRefVector.begin(); i != cancelRefVector.end(); ++i)
{
lua_rawgeti(E.L, LUA_REGISTRYINDEX, (*i));
lua_call(E.L, 0, 0);
}
v.clear();
}
void ClearOne(int ref, uint32 event_id, uint32 entry, uint64 guid) override
{
ASSERT(entry != 0 && guid == 0);
WriteGuard guard(GetLock());
FunctionRefVector& funcrefvec = Bindings[entry][event_id];
for (FunctionRefVector::iterator i = funcrefvec.begin(); i != funcrefvec.end(); ++i)
{
Binding* binding = (*i);
if (binding->functionReference == ref)
{
i = funcrefvec.erase(i);
delete binding;
return;
}
}
ASSERT(false && "tried to clear function ref that doesn't exist");
}
// Pushes the function references and updates the counters on the binds and erases them if the counter would reach 0
void PushFuncRefs(lua_State* L, int event_id, uint32 entry)
{
WriteGuard guard(GetLock());
for (FunctionRefVector::iterator it = Bindings[entry][event_id].begin(); it != Bindings[entry][event_id].end();)
{
FunctionRefVector::iterator it_old = it++;
Binding* binding = (*it_old);
lua_rawgeti(L, LUA_REGISTRYINDEX, binding->functionReference);
if (binding->isTemporary)
{
// Bad things will happen if there's a cancel callback (due to ref reuse).
ASSERT(binding->cancelCallbackRef == 0);
binding->remainingShots--;
if (binding->remainingShots == 0)
{
delete binding;
Bindings[entry][event_id].erase(it_old);
}
}
}
if (Bindings[entry][event_id].empty())
Bindings[entry].erase(event_id);
if (Bindings[entry].empty())
Bindings.erase(entry);
};
void Insert(uint32 entryId, int eventId, int funcRef, uint32 shots, int callbackRef = 0) // Inserts a new registered event
{
WriteGuard guard(GetLock());
Bindings[entryId][eventId].push_back(new Binding(E, funcRef, shots, callbackRef));
}
// Returns true if the entry has registered binds
bool HasEvents(T eventId, uint32 entryId)
{
ReadGuard guard(GetLock());
if (Bindings.empty())
return false;
EntryToEventsMap::const_iterator itr = Bindings.find(entryId);
if (itr == Bindings.end())
return false;
return itr->second.find(eventId) != itr->second.end();
}
bool HasEvents(uint32 entryId)
{
ReadGuard guard(GetLock());
if (!E.IsEnabled())
return false;
if (Bindings.empty())
return false;
return Bindings.find(entryId) != Bindings.end();
}
EntryToEventsMap Bindings; // Binding store Bindings[entryId][eventId] = {(funcRef, counter)};
};
template<typename T>
class UniqueBind : public ElunaBind
{
public:
typedef UNORDERED_MAP<uint32, EventToFunctionsMap> InstanceToEventsMap;
typedef UNORDERED_MAP<uint64, InstanceToEventsMap> GUIDToInstancesMap;
UniqueBind(const char* bindGroupName, Eluna& _E) : ElunaBind(bindGroupName, _E)
{
}
// unregisters all registered functions and clears all registered events from the bindmap
void Clear() override
{
WriteGuard guard(GetLock());
for (GUIDToInstancesMap::iterator iter = Bindings.begin(); iter != Bindings.end(); ++iter)
{
InstanceToEventsMap& eventsMap = iter->second;
for (InstanceToEventsMap::iterator itr = eventsMap.begin(); itr != eventsMap.end(); ++itr)
{
EventToFunctionsMap& funcmap = itr->second;
for (EventToFunctionsMap::iterator it = funcmap.begin(); it != funcmap.end(); ++it)
{
FunctionRefVector& funcrefvec = it->second;
std::vector<int> cancelRefVector;
for (FunctionRefVector::iterator i = funcrefvec.begin(); i != funcrefvec.end(); ++i)
{
Binding* binding = (*i);
// Can't call the callback now, since it might modify `v` and crash the server.
// Just add the ref to a list and call them all after this loop.
if (binding->cancelCallbackRef)
cancelRefVector.push_back(binding->cancelCallbackRef);
else
delete binding; // Don't bother removing from list, clear is called at end anyway.
}
// Call all of the cancel callbacks for bindings with cancel callbacks.
for (std::vector<int>::iterator i = cancelRefVector.begin(); i != cancelRefVector.end(); ++i)
{
lua_rawgeti(E.L, LUA_REGISTRYINDEX, (*i));
lua_call(E.L, 0, 0);
}
funcrefvec.clear();
}
funcmap.clear();
}
eventsMap.clear();
}
Bindings.clear();
}
void Clear(uint64 guid, uint32 instanceId, uint32 event_id)
{
WriteGuard guard(GetLock());
FunctionRefVector& v = Bindings[guid][instanceId][event_id];
std::vector<int> cancelRefVector;
for (FunctionRefVector::iterator itr = v.begin(); itr != v.end(); ++itr)
{
Binding* binding = (*itr);
// Can't call the callback now, since it might modify `v` and crash the server.
// Just add the ref to a list and call them all after this loop.
if (binding->cancelCallbackRef)
cancelRefVector.push_back(binding->cancelCallbackRef);
else
delete binding; // Don't bother removing from list, clear is called at end anyway.
}
// Call all of the cancel callbacks for bindings with cancel callbacks.
for (std::vector<int>::iterator i = cancelRefVector.begin(); i != cancelRefVector.end(); ++i)
{
lua_rawgeti(E.L, LUA_REGISTRYINDEX, (*i));
lua_call(E.L, 0, 0);
}
v.clear();
}
void ClearOne(int ref, uint32 event_id, uint32 instance_id, uint64 guid) override
{
ASSERT(guid != 0);
WriteGuard guard(GetLock());
FunctionRefVector& funcrefvec = Bindings[guid][instance_id][event_id];
for (FunctionRefVector::iterator i = funcrefvec.begin(); i != funcrefvec.end(); ++i)
{
Binding* binding = (*i);
if (binding->functionReference == ref)
{
i = funcrefvec.erase(i);
delete binding;
return;
}
}
ASSERT(false && "tried to clear function ref that doesn't exist");
}
// Pushes the function references and updates the counters on the binds and erases them if the counter would reach 0
void PushFuncRefs(lua_State* L, int event_id, uint64 guid, uint32 instanceId)
{
WriteGuard guard(GetLock());
FunctionRefVector& v = Bindings[guid][instanceId][event_id];
for (FunctionRefVector::iterator it = v.begin(); it != v.end();)
{
FunctionRefVector::iterator it_old = it++;
Binding* binding = (*it_old);
lua_rawgeti(L, LUA_REGISTRYINDEX, binding->functionReference);
if (binding->isTemporary)
{
// Bad things will happen if there's a cancel callback (due to ref reuse).
ASSERT(binding->cancelCallbackRef == 0);
binding->remainingShots--;
if (binding->remainingShots == 0)
{
delete binding;
v.erase(it_old);
}
}
}
if (Bindings[guid][instanceId][event_id].empty())
Bindings[guid][instanceId].erase(event_id);
if (Bindings[guid][instanceId].empty())
Bindings[guid].erase(instanceId);
if (Bindings[guid].empty())
Bindings.erase(guid);
};
void Insert(uint64 guid, uint32 instanceId, int eventId, int funcRef, uint32 shots, int callbackRef = 0) // Inserts a new registered event
{
WriteGuard guard(GetLock());
Bindings[guid][instanceId][eventId].push_back(new Binding(E, funcRef, shots, callbackRef));
}
// Returns true if the entry has registered binds
bool HasEvents(T eventId, uint64 guid, uint32 instanceId)
{
ReadGuard guard(GetLock());
if (Bindings.empty())
return false;
GUIDToInstancesMap::const_iterator itr = Bindings.find(guid);
if (itr == Bindings.end())
return false;
InstanceToEventsMap::const_iterator it = itr->second.find(instanceId);
if (it == itr->second.end())
return false;
return it->second.find(eventId) != it->second.end();
}
bool HasEvents(uint64 guid, uint32 instanceId)
{
ReadGuard guard(GetLock());
if (Bindings.empty())
return false;
GUIDToInstancesMap::const_iterator itr = Bindings.find(guid);
if (itr == Bindings.end())
return false;
return itr->second.find(instanceId) != itr->second.end();
}
GUIDToInstancesMap Bindings; // Binding store Bindings[guid][instanceId][eventId] = {(funcRef, counter)};
};
#endif

View file

@ -0,0 +1,212 @@
/*
* 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
*/
#ifndef _ELUNA_CREATURE_AI_H
#define _ELUNA_CREATURE_AI_H
#include "LuaEngine.h"
#ifndef TRINITY
class AggressorAI;
typedef AggressorAI ScriptedAI;
#else
struct ScriptedAI;
#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
};
#endif

View file

@ -0,0 +1,153 @@
/*
* 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 "ElunaEventMgr.h"
#include "LuaEngine.h"
#include "Object.h"
extern "C"
{
#include "lua.h"
#include "lauxlib.h"
};
ElunaEventProcessor::ElunaEventProcessor(Eluna** _E, WorldObject* _obj) : m_time(0), obj(_obj), E(_E)
{
if (obj)
{
EventMgr::WriteGuard guard((*E)->eventMgr->GetLock());
(*E)->eventMgr->processors.insert(this);
}
}
ElunaEventProcessor::~ElunaEventProcessor()
{
RemoveEvents_internal();
if (obj && Eluna::IsInitialized())
{
EventMgr::WriteGuard guard((*E)->eventMgr->GetLock());
(*E)->eventMgr->processors.erase(this);
}
}
void ElunaEventProcessor::Update(uint32 diff)
{
m_time += diff;
for (EventList::iterator it = eventList.begin(); it != eventList.end() && it->first <= m_time; it = eventList.begin())
{
LuaEvent* luaEvent = it->second;
eventList.erase(it);
if (luaEvent->state != LUAEVENT_STATE_ERASE)
eventMap.erase(luaEvent->funcRef);
if (luaEvent->state == LUAEVENT_STATE_RUN)
{
bool remove = luaEvent->repeats == 1;
if (!remove)
AddEvent(luaEvent); // Reschedule before calling incase RemoveEvents used
// Call the timed event
(*E)->OnTimedEvent(luaEvent->funcRef, luaEvent->delay, luaEvent->repeats ? luaEvent->repeats-- : luaEvent->repeats, obj);
if (!remove)
continue;
}
// Event should be deleted (executed last time or set to be aborted)
RemoveEvent(luaEvent);
}
}
void ElunaEventProcessor::SetStates(LuaEventState state)
{
for (EventList::iterator it = eventList.begin(); it != eventList.end(); ++it)
it->second->SetState(state);
if (state == LUAEVENT_STATE_ERASE)
eventMap.clear();
}
void ElunaEventProcessor::RemoveEvents_internal()
{
//if (!final)
//{
// for (EventList::iterator it = eventList.begin(); it != eventList.end(); ++it)
// it->second->to_Abort = true;
// return;
//}
for (EventList::iterator it = eventList.begin(); it != eventList.end(); ++it)
RemoveEvent(it->second);
eventList.clear();
eventMap.clear();
}
void ElunaEventProcessor::SetState(int eventId, LuaEventState state)
{
if (eventMap.find(eventId) != eventMap.end())
eventMap[eventId]->SetState(state);
if (state == LUAEVENT_STATE_ERASE)
eventMap.erase(eventId);
}
void ElunaEventProcessor::AddEvent(LuaEvent* luaEvent)
{
eventList.insert(std::pair<uint64, LuaEvent*>(m_time + luaEvent->delay, luaEvent));
eventMap[luaEvent->funcRef] = luaEvent;
}
void ElunaEventProcessor::AddEvent(int funcRef, uint32 delay, uint32 repeats)
{
AddEvent(new LuaEvent(funcRef, delay, repeats));
}
void ElunaEventProcessor::RemoveEvent(LuaEvent* luaEvent)
{
// Unreference if should and if Eluna was not yet uninitialized and if the lua state still exists
if (luaEvent->state != LUAEVENT_STATE_ERASE && Eluna::IsInitialized() && (*E)->HasLuaState())
{
// Free lua function ref
luaL_unref((*E)->L, LUA_REGISTRYINDEX, luaEvent->funcRef);
}
delete luaEvent;
}
EventMgr::EventMgr(Eluna** _E) : globalProcessor(new ElunaEventProcessor(_E, NULL)), E(_E)
{
}
EventMgr::~EventMgr()
{
{
ReadGuard guard(GetLock());
if (!processors.empty())
for (ProcessorSet::const_iterator it = processors.begin(); it != processors.end(); ++it) // loop processors
(*it)->RemoveEvents_internal();
globalProcessor->RemoveEvents_internal();
}
delete globalProcessor;
globalProcessor = NULL;
}
void EventMgr::SetStates(LuaEventState state)
{
ReadGuard guard(GetLock());
if (!processors.empty())
for (ProcessorSet::const_iterator it = processors.begin(); it != processors.end(); ++it) // loop processors
(*it)->SetStates(state);
globalProcessor->SetStates(state);
}
void EventMgr::SetState(int eventId, LuaEventState state)
{
ReadGuard guard(GetLock());
if (!processors.empty())
for (ProcessorSet::const_iterator it = processors.begin(); it != processors.end(); ++it) // loop processors
(*it)->SetState(eventId, state);
globalProcessor->SetState(eventId, state);
}

View file

@ -0,0 +1,100 @@
/*
* 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
*/
#ifndef _ELUNA_EVENT_MGR_H
#define _ELUNA_EVENT_MGR_H
#include "ElunaUtility.h"
#include "Common.h"
#include <map>
#ifdef TRINITY
#include "Define.h"
#else
#include "Platform/Define.h"
#endif
class Eluna;
class EventMgr;
class ElunaEventProcessor;
class WorldObject;
enum LuaEventState
{
LUAEVENT_STATE_RUN, // On next call run the function normally
LUAEVENT_STATE_ABORT, // On next call unregisters reffed function and erases the data
LUAEVENT_STATE_ERASE, // On next call just erases the data
};
struct LuaEvent
{
LuaEvent(int _funcRef, uint32 _delay, uint32 _repeats) :
delay(_delay), repeats(_repeats), funcRef(_funcRef), state(LUAEVENT_STATE_RUN)
{
}
void SetState(LuaEventState _state)
{
if (state != LUAEVENT_STATE_ERASE)
state = _state;
}
uint32 delay; // Delay between event calls
uint32 repeats; // Amount of repeats to make, 0 for infinite
int funcRef; // Lua function reference ID, also used as event ID
LuaEventState state; // State for next call
};
class ElunaEventProcessor
{
friend class EventMgr;
public:
typedef std::multimap<uint64, LuaEvent*> EventList;
typedef UNORDERED_MAP<int, LuaEvent*> EventMap;
ElunaEventProcessor(Eluna** _E, WorldObject* _obj);
~ElunaEventProcessor();
void Update(uint32 diff);
// removes all timed events on next tick or at tick end
void SetStates(LuaEventState state);
// set the event to be removed when executing
void SetState(int eventId, LuaEventState state);
void AddEvent(int funcRef, uint32 delay, uint32 repeats);
EventMap eventMap;
private:
void RemoveEvents_internal();
void AddEvent(LuaEvent* luaEvent);
void RemoveEvent(LuaEvent* luaEvent);
EventList eventList;
uint64 m_time;
WorldObject* obj;
Eluna** E;
};
class EventMgr : public ElunaUtil::RWLockable
{
public:
typedef UNORDERED_SET<ElunaEventProcessor*> ProcessorSet;
ProcessorSet processors;
ElunaEventProcessor* globalProcessor;
Eluna** E;
EventMgr(Eluna** _E);
~EventMgr();
// Set the state of all timed events
// Execute only in safe env
void SetStates(LuaEventState state);
// Sets the eventId's state in all processors
// Execute only in safe env
void SetState(int eventId, LuaEventState state);
};
#endif

View file

@ -0,0 +1,142 @@
/*
* 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
*/
#ifndef _ELUNA_INCLUDES_H
#define _ELUNA_INCLUDES_H
// Required
#include "AccountMgr.h"
#include "AuctionHouseMgr.h"
#include "Cell.h"
#include "CellImpl.h"
#include "Chat.h"
#include "Channel.h"
#include "DBCStores.h"
#include "GossipDef.h"
#include "GridNotifiers.h"
#include "GridNotifiersImpl.h"
#include "Group.h"
#include "Guild.h"
#include "GuildMgr.h"
#include "Language.h"
#include "Mail.h"
#include "MapManager.h"
#include "ObjectAccessor.h"
#include "ObjectMgr.h"
#include "Opcodes.h"
#include "Player.h"
#include "Pet.h"
#include "ReputationMgr.h"
#include "ScriptMgr.h"
#include "Spell.h"
#include "SpellAuras.h"
#include "SpellMgr.h"
#include "TemporarySummon.h"
#include "WorldPacket.h"
#include "WorldSession.h"
#ifdef TRINITY
#include "Config.h"
#include "ScriptedCreature.h"
#include "SpellInfo.h"
#include "WeatherMgr.h"
#include "Battleground.h"
#include "revision.h"
#else
#include "Config/Config.h"
#include "AggressorAI.h"
#include "BattleGroundMgr.h"
#include "SQLStorages.h"
#endif
#ifdef MANGOS
#include "revision.h"
#elif defined(CMANGOS)
#include "revision_nr.h"
#endif
#if (!defined(TBC) && !defined(CLASSIC))
#include "Vehicle.h"
#endif
#ifndef CLASSIC
#include "ArenaTeam.h"
#endif
#ifndef CLASSIC
typedef Opcodes OpcodesList;
#endif
/*
* Note: if you add or change a CORE_NAME #define,
* please update LuaGlobalFunctions::GetCoreName docstring.
*/
#ifdef MANGOS
#define CORE_NAME "MaNGOS"
#define CORE_VERSION REVISION_NR
#endif
#ifdef CMANGOS
#define CORE_NAME "cMaNGOS"
#define CORE_VERSION REVISION_NR
#endif
#ifdef TRINITY
#define CORE_NAME "TrinityCore"
#define CORE_VERSION _DATE
#define eWorld (sWorld)
#define eMapMgr (sMapMgr)
#define eConfigMgr (sConfigMgr)
#define eGuildMgr (sGuildMgr)
#define eObjectMgr (sObjectMgr)
#define eAccountMgr (sAccountMgr)
#define eAuctionMgr (sAuctionMgr)
#define eObjectAccessor (sObjectAccessor)
#define REGEN_TIME_FULL
typedef ThreatContainer::StorageType ThreatList;
#ifdef CATA
#define NUM_MSG_TYPES NUM_OPCODE_HANDLERS
#endif
#endif
#ifndef TRINITY
#define eWorld (&sWorld)
#define eMapMgr (&sMapMgr)
#define eConfigMgr (&sConfig)
#define eGuildMgr (&sGuildMgr)
#define eObjectMgr (&sObjectMgr)
#define eAccountMgr (&sAccountMgr)
#define eAuctionMgr (&sAuctionMgr)
#define eObjectAccessor (&sObjectAccessor)
#define SERVER_MSG_STRING SERVER_MSG_CUSTOM
#define TOTAL_LOCALES MAX_LOCALE
#define DIALOG_STATUS_SCRIPTED_NO_STATUS DIALOG_STATUS_UNDEFINED
#define TARGETICONCOUNT TARGET_ICON_COUNT
#define MAX_TALENT_SPECS MAX_TALENT_SPEC_COUNT
#define TEAM_NEUTRAL TEAM_INDEX_NEUTRAL
#ifndef CLASSIC
#define PLAYER_FIELD_LIFETIME_HONORABLE_KILLS PLAYER_FIELD_LIFETIME_HONORBALE_KILLS
#endif
#ifdef TBC
#define SPELL_AURA_MOD_KILL_XP_PCT SPELL_AURA_MOD_XP_PCT
#endif
typedef TemporarySummon TempSummon;
typedef SpellEntry SpellInfo;
enum SelectAggroTarget
{
SELECT_TARGET_RANDOM = 0, // Just selects a random target
SELECT_TARGET_TOPAGGRO, // Selects targes from top aggro to bottom
SELECT_TARGET_BOTTOMAGGRO, // Selects targets from bottom aggro to top
SELECT_TARGET_NEAREST,
SELECT_TARGET_FARTHEST
};
#endif // TRINITY
#endif // _ELUNA_INCLUDES_H

View file

@ -0,0 +1,337 @@
/*
* 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
*/
#ifndef QUERYMETHODS_H
#define QUERYMETHODS_H
#ifndef TRINITY
#define RESULT result
#else
#define RESULT (*result)
#endif
/***
* The result of a database query.
*
* E.g. the return value of [Global:WorldDBQuery].
*/
namespace LuaQuery
{
static void CheckFields(lua_State* L, ElunaQuery* result)
{
if (Eluna::CHECKVAL<uint32>(L, 2) >= RESULT->GetFieldCount())
luaL_argerror(L, 2, "invalid field index");
}
/* BOOLEAN */
/**
* Returns `true` if the specified column of the current row is `NULL`, otherwise `false`.
*
* @param uint32 column
* @return bool isNull
*/
int IsNull(Eluna* /*E*/, lua_State* L, ElunaQuery* result)
{
uint32 col = Eluna::CHECKVAL<uint32>(L, 2);
CheckFields(L, result);
#ifndef TRINITY
Eluna::Push(L, RESULT->Fetch()[col].IsNULL());
#else
Eluna::Push(L, RESULT->Fetch()[col].IsNull());
#endif
return 1;
}
/* GETTERS */
/**
* Returns the number of columns in the result set.
*
* @return uint32 columnCount
*/
int GetColumnCount(Eluna* /*E*/, lua_State* L, ElunaQuery* result)
{
Eluna::Push(L, RESULT->GetFieldCount());
return 1;
}
/**
* Returns the number of rows in the result set.
*
* @return uint32 rowCount
*/
int GetRowCount(Eluna* /*E*/, lua_State* L, ElunaQuery* result)
{
if (RESULT->GetRowCount() > (uint32)-1)
Eluna::Push(L, (uint32)-1);
else
Eluna::Push(L, (uint32)(RESULT->GetRowCount()));
return 1;
}
/**
* Returns the data in the specified column of the current row, casted to a boolean.
*
* @param uint32 column
* @return bool data
*/
int GetBool(Eluna* /*E*/, lua_State* L, ElunaQuery* result)
{
uint32 col = Eluna::CHECKVAL<uint32>(L, 2);
CheckFields(L, result);
Eluna::Push(L, RESULT->Fetch()[col].GetBool());
return 1;
}
/**
* Returns the data in the specified column of the current row, casted to an unsigned 8-bit integer.
*
* @param uint32 column
* @return uint8 data
*/
int GetUInt8(Eluna* /*E*/, lua_State* L, ElunaQuery* result)
{
uint32 col = Eluna::CHECKVAL<uint32>(L, 2);
CheckFields(L, result);
Eluna::Push(L, RESULT->Fetch()[col].GetUInt8());
return 1;
}
/**
* Returns the data in the specified column of the current row, casted to an unsigned 16-bit integer.
*
* @param uint32 column
* @return uint16 data
*/
int GetUInt16(Eluna* /*E*/, lua_State* L, ElunaQuery* result)
{
uint32 col = Eluna::CHECKVAL<uint32>(L, 2);
CheckFields(L, result);
Eluna::Push(L, RESULT->Fetch()[col].GetUInt16());
return 1;
}
/**
* Returns the data in the specified column of the current row, casted to an unsigned 32-bit integer.
*
* @param uint32 column
* @return uint32 data
*/
int GetUInt32(Eluna* /*E*/, lua_State* L, ElunaQuery* result)
{
uint32 col = Eluna::CHECKVAL<uint32>(L, 2);
CheckFields(L, result);
Eluna::Push(L, RESULT->Fetch()[col].GetUInt32());
return 1;
}
/**
* Returns the data in the specified column of the current row, casted to an unsigned 64-bit integer.
*
* @param uint32 column
* @return uint64 data
*/
int GetUInt64(Eluna* /*E*/, lua_State* L, ElunaQuery* result)
{
uint32 col = Eluna::CHECKVAL<uint32>(L, 2);
CheckFields(L, result);
Eluna::Push(L, RESULT->Fetch()[col].GetUInt64());
return 1;
}
/**
* Returns the data in the specified column of the current row, casted to a signed 8-bit integer.
*
* @param uint32 column
* @return int8 data
*/
int GetInt8(Eluna* /*E*/, lua_State* L, ElunaQuery* result)
{
uint32 col = Eluna::CHECKVAL<uint32>(L, 2);
CheckFields(L, result);
Eluna::Push(L, RESULT->Fetch()[col].GetInt8());
return 1;
}
/**
* Returns the data in the specified column of the current row, casted to a signed 16-bit integer.
*
* @param uint32 column
* @return int16 data
*/
int GetInt16(Eluna* /*E*/, lua_State* L, ElunaQuery* result)
{
uint32 col = Eluna::CHECKVAL<uint32>(L, 2);
CheckFields(L, result);
Eluna::Push(L, RESULT->Fetch()[col].GetInt16());
return 1;
}
/**
* Returns the data in the specified column of the current row, casted to a signed 32-bit integer.
*
* @param uint32 column
* @return int32 data
*/
int GetInt32(Eluna* /*E*/, lua_State* L, ElunaQuery* result)
{
uint32 col = Eluna::CHECKVAL<uint32>(L, 2);
CheckFields(L, result);
Eluna::Push(L, RESULT->Fetch()[col].GetInt32());
return 1;
}
/**
* Returns the data in the specified column of the current row, casted to a signed 64-bit integer.
*
* @param uint32 column
* @return int64 data
*/
int GetInt64(Eluna* /*E*/, lua_State* L, ElunaQuery* result)
{
uint32 col = Eluna::CHECKVAL<uint32>(L, 2);
CheckFields(L, result);
Eluna::Push(L, RESULT->Fetch()[col].GetInt64());
return 1;
}
/**
* Returns the data in the specified column of the current row, casted to a 32-bit floating point value.
*
* @param uint32 column
* @return float data
*/
int GetFloat(Eluna* /*E*/, lua_State* L, ElunaQuery* result)
{
uint32 col = Eluna::CHECKVAL<uint32>(L, 2);
CheckFields(L, result);
Eluna::Push(L, RESULT->Fetch()[col].GetFloat());
return 1;
}
/**
* Returns the data in the specified column of the current row, casted to a 64-bit floating point value.
*
* @param uint32 column
* @return double data
*/
int GetDouble(Eluna* /*E*/, lua_State* L, ElunaQuery* result)
{
uint32 col = Eluna::CHECKVAL<uint32>(L, 2);
CheckFields(L, result);
Eluna::Push(L, RESULT->Fetch()[col].GetDouble());
return 1;
}
/**
* Returns the data in the specified column of the current row, casted to a string.
*
* @param uint32 column
* @return string data
*/
int GetString(Eluna* /*E*/, lua_State* L, ElunaQuery* result)
{
uint32 col = Eluna::CHECKVAL<uint32>(L, 2);
CheckFields(L, result);
#ifndef TRINITY
Eluna::Push(L, RESULT->Fetch()[col].GetString());
#else
Eluna::Push(L, RESULT->Fetch()[col].GetCString());
#endif
return 1;
}
/* OTHER */
/**
* Advances the [ElunaQuery] to the next row in the result set.
*
* *Do not* call this immediately after a query, or you'll skip the first row.
*
* Returns `false` if there was no new row, otherwise `true`.
*
* @return bool hadNextRow
*/
int NextRow(Eluna* /*E*/, lua_State* L, ElunaQuery* result)
{
Eluna::Push(L, RESULT->NextRow());
return 1;
}
/**
* Returns a table from the current row where keys are field names and values are the row's values.
*
* All numerical values will be numbers and everything else is returned as a string.
*
* **For example,** the query:
*
* SELECT entry, name FROM creature_template
*
* would result in a table like:
*
* { entry = 123, name = "some creature name" }
*
* To move to next row use [ElunaQuery:NextRow].
*
* @return table rowData : table filled with row columns and data where `T[column] = data`
*/
int GetRow(Eluna* /*E*/, lua_State* L, ElunaQuery* result)
{
lua_newtable(L);
int tbl = lua_gettop(L);
uint32 col = RESULT->GetFieldCount();
Field* row = RESULT->Fetch();
#ifndef TRINITY
const QueryFieldNames& names = RESULT->GetFieldNames();
#endif
for (uint32 i = 0; i < col; ++i)
{
#ifdef TRINITY
Eluna::Push(L, RESULT->GetFieldName(i));
const char* str = row[i].GetCString();
if (row[i].IsNull() || !str)
Eluna::Push(L);
#else
Eluna::Push(L, names[i]);
const char* str = row[i].GetString();
if (row[i].IsNULL() || !str)
Eluna::Push(L);
#endif
else
{
// MYSQL_TYPE_LONGLONG Interpreted as string for lua
switch (row[i].GetType())
{
case MYSQL_TYPE_TINY:
case MYSQL_TYPE_SHORT:
case MYSQL_TYPE_INT24:
case MYSQL_TYPE_LONG:
case MYSQL_TYPE_FLOAT:
case MYSQL_TYPE_DOUBLE:
Eluna::Push(L, strtod(str, NULL));
break;
default:
Eluna::Push(L, str);
break;
}
}
lua_settable(L, tbl);
}
lua_settop(L, tbl);
return 1;
}
};
#undef RESULT
#endif

View file

@ -0,0 +1,453 @@
/*
* 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
*/
#ifndef _ELUNA_TEMPLATE_H
#define _ELUNA_TEMPLATE_H
extern "C"
{
#include "lua.h"
#include "lualib.h"
#include "lauxlib.h"
};
#include "LuaEngine.h"
#include "ElunaUtility.h"
#include "SharedDefines.h"
class ElunaGlobal
{
public:
struct ElunaRegister
{
const char* name;
int(*mfunc)(Eluna*, lua_State*);
};
static int thunk(lua_State* L)
{
ElunaRegister* l = static_cast<ElunaRegister*>(lua_touserdata(L, lua_upvalueindex(1)));
Eluna* E = static_cast<Eluna*>(lua_touserdata(L, lua_upvalueindex(2)));
int args = lua_gettop(L);
int expected = l->mfunc(E, L);
args = lua_gettop(L) - args;
if (args < 0 || args > expected)
{
ELUNA_LOG_ERROR("[Eluna]: %s returned unexpected amount of arguments %i out of %i. Report to devs", l->name, args, expected);
ASSERT(false);
}
for (; args < expected; ++args)
lua_pushnil(L);
return expected;
}
static void SetMethods(Eluna* E, ElunaRegister* methodTable)
{
ASSERT(E);
ASSERT(methodTable);
lua_pushglobaltable(E->L);
for (; methodTable && methodTable->name && methodTable->mfunc; ++methodTable)
{
lua_pushstring(E->L, methodTable->name);
lua_pushlightuserdata(E->L, (void*)methodTable);
lua_pushlightuserdata(E->L, (void*)E);
lua_pushcclosure(E->L, thunk, 2);
lua_settable(E->L, -3);
}
lua_remove(E->L, -1);
}
};
class ElunaObject
{
public:
ElunaObject(void* obj, bool manageMemory) : _isvalid(false), _invalidate(!manageMemory), object(obj)
{
SetValid(true);
}
~ElunaObject()
{
}
// Get wrapped object pointer
void* GetObj() const { return object; }
// Returns whether the object is valid or not
bool IsValid() const { return _isvalid; }
// Returns whether the object can be invalidated or not
bool CanInvalidate() const { return _invalidate; }
// Sets the object pointer that is wrapped
void SetObj(void* obj)
{
ASSERT(obj);
object = obj;
SetValid(true);
}
// Sets the object pointer to valid or invalid
void SetValid(bool valid)
{
ASSERT(!valid || (valid && object));
_isvalid = valid;
}
// Sets whether the pointer will be invalidated at end of calls
void SetValidation(bool invalidate)
{
_invalidate = invalidate;
}
// Invalidates the pointer if it should be invalidated
void Invalidate()
{
if (CanInvalidate())
_isvalid = false;
}
private:
bool _isvalid;
bool _invalidate;
void* object;
};
template<typename T>
struct ElunaRegister
{
const char* name;
int(*mfunc)(Eluna*, lua_State*, T*);
};
template<typename T>
class ElunaTemplate
{
public:
static const char* tname;
static bool manageMemory;
// name will be used as type name
// If gc is true, lua will handle the memory management for object pushed
// gc should be used if pushing for example WorldPacket,
// that will only be needed on lua side and will not be managed by TC/mangos/<core>
static void Register(Eluna* E, const char* name, bool gc = false)
{
ASSERT(E);
ASSERT(name);
// check that metatable isn't already there
luaL_getmetatable(E->L, name);
ASSERT(lua_isnoneornil(E->L, -1));
// check that metatable isn't already there
lua_getglobal(E->L, name);
ASSERT(lua_isnoneornil(E->L, -1));
// pop metatable and methodtable values
lua_pop(E->L, 2);
tname = name;
manageMemory = gc;
// create methodtable for userdata of this type
lua_newtable(E->L);
int methods = lua_gettop(E->L);
// push methodtable to stack to be accessed and modified by users
lua_pushvalue(E->L, methods);
lua_setglobal(E->L, tname);
// create metatable for userdatas of this type
ASSERT(luaL_newmetatable(E->L, tname));
int metatable = lua_gettop(E->L);
// tostring
lua_pushcfunction(E->L, ToString);
lua_setfield(E->L, metatable, "__tostring");
// garbage collecting
lua_pushcfunction(E->L, CollectGarbage);
lua_setfield(E->L, metatable, "__gc");
// make methods accessible through metatable
lua_pushvalue(E->L, methods);
lua_setfield(E->L, metatable, "__index");
// make new indexes saved to methods
lua_pushvalue(E->L, methods);
lua_setfield(E->L, metatable, "__newindex");
// make new indexes saved to methods
lua_pushcfunction(E->L, Add);
lua_setfield(E->L, metatable, "__add");
// make new indexes saved to methods
lua_pushcfunction(E->L, Substract);
lua_setfield(E->L, metatable, "__sub");
// make new indexes saved to methods
lua_pushcfunction(E->L, Multiply);
lua_setfield(E->L, metatable, "__mul");
// make new indexes saved to methods
lua_pushcfunction(E->L, Divide);
lua_setfield(E->L, metatable, "__div");
// make new indexes saved to methods
lua_pushcfunction(E->L, Mod);
lua_setfield(E->L, metatable, "__mod");
// make new indexes saved to methods
lua_pushcfunction(E->L, Pow);
lua_setfield(E->L, metatable, "__pow");
// make new indexes saved to methods
lua_pushcfunction(E->L, UnaryMinus);
lua_setfield(E->L, metatable, "__unm");
// make new indexes saved to methods
lua_pushcfunction(E->L, Concat);
lua_setfield(E->L, metatable, "__concat");
// make new indexes saved to methods
lua_pushcfunction(E->L, Length);
lua_setfield(E->L, metatable, "__len");
// make new indexes saved to methods
lua_pushcfunction(E->L, Equal);
lua_setfield(E->L, metatable, "__eq");
// make new indexes saved to methods
lua_pushcfunction(E->L, Less);
lua_setfield(E->L, metatable, "__lt");
// make new indexes saved to methods
lua_pushcfunction(E->L, LessOrEqual);
lua_setfield(E->L, metatable, "__le");
// make new indexes saved to methods
lua_pushcfunction(E->L, Call);
lua_setfield(E->L, metatable, "__call");
// special method to get the object type
lua_pushcfunction(E->L, GetType);
lua_setfield(E->L, methods, "GetObjectType");
// special method to decide object invalidation at end of call
lua_pushcfunction(E->L, SetInvalidation);
lua_setfield(E->L, methods, "SetInvalidation");
// pop methods and metatable
lua_pop(E->L, 2);
}
template<typename C>
static void SetMethods(Eluna* E, ElunaRegister<C>* methodTable)
{
ASSERT(E);
ASSERT(tname);
ASSERT(methodTable);
// get metatable
luaL_getmetatable(E->L, tname);
ASSERT(lua_istable(E->L, -1));
// get method table
lua_getfield(E->L, -1, "__index");
lua_remove(E->L, -2);
ASSERT(lua_istable(E->L, -1));
for (; methodTable && methodTable->name && methodTable->mfunc; ++methodTable)
{
lua_pushstring(E->L, methodTable->name);
lua_pushlightuserdata(E->L, (void*)methodTable);
lua_pushlightuserdata(E->L, (void*)E);
lua_pushcclosure(E->L, CallMethod, 2);
lua_settable(E->L, -3);
}
lua_remove(E->L, -1);
}
static int Push(lua_State* L, T const* obj)
{
if (!obj)
{
lua_pushnil(L);
return 1;
}
//if (!manageMemory)
//{
lua_getglobal(L, ELUNA_OBJECT_STORE);
ASSERT(lua_istable(L, -1));
lua_pushfstring(L, "%p", obj);
lua_gettable(L, -2);
if (ElunaObject* elunaObj = Eluna::CHECKTYPE(L, -1, tname, false))
{
// set userdata valid
elunaObj->SetValid(true);
// remove userdata_table, leave userdata
lua_remove(L, -2);
return 1;
}
lua_remove(L, -1);
// left userdata_table in stack
//}
// Create new userdata
ElunaObject** ptrHold = static_cast<ElunaObject**>(lua_newuserdata(L, sizeof(ElunaObject*)));
if (!ptrHold)
{
ELUNA_LOG_ERROR("%s could not create new userdata", tname);
lua_pop(L, 2 /*manageMemory ? 1 : 2*/);
lua_pushnil(L);
return 1;
}
*ptrHold = new ElunaObject((void*)(obj), manageMemory);
// Set metatable for it
luaL_getmetatable(L, tname);
if (!lua_istable(L, -1))
{
ELUNA_LOG_ERROR("%s missing metatable", tname);
lua_pop(L, 3 /*manageMemory ? 2 : 3*/);
lua_pushnil(L);
return 1;
}
lua_setmetatable(L, -2);
//if (!manageMemory)
//{
lua_pushfstring(L, "%p", obj);
lua_pushvalue(L, -2);
lua_settable(L, -4);
lua_remove(L, -2);
//}
return 1;
}
static T* Check(lua_State* L, int narg, bool error = true)
{
ElunaObject* elunaObj = Eluna::CHECKTYPE(L, narg, tname, error);
if (!elunaObj)
return NULL;
//if (!manageMemory)
//{
// // Check pointer validity
// lua_rawgeti(L, LUA_REGISTRYINDEX, sEluna->userdata_table);
// lua_pushfstring(L, "%p", (*ptrHold)->GetObj());
// lua_gettable(L, -2);
// lua_remove(L, -2);
// bool valid = lua_isuserdata(L, -1) != 0;
// lua_remove(L, -1);
// if (!valid)
// {
// char buff[256];
// snprintf(buff, 256, "%s expected, got pointer to nonexisting object (%s). This should never happen", tname, luaL_typename(L, narg));
// if (error)
// {
// luaL_argerror(L, narg, buff);
// }
// else
// {
// ELUNA_LOG_ERROR("%s", buff);
// }
// return NULL;
// }
//}
if (!elunaObj->IsValid())
{
char buff[256];
snprintf(buff, 256, "%s expected, got pointer to nonexisting (invalidated) object (%s). Check your code.", tname, luaL_typename(L, narg));
if (error)
{
luaL_argerror(L, narg, buff);
}
else
{
ELUNA_LOG_ERROR("%s", buff);
}
return NULL;
}
return static_cast<T*>(elunaObj->GetObj());
}
static int GetType(lua_State* L)
{
lua_pushstring(L, tname);
return 1;
}
static int SetInvalidation(lua_State* L)
{
ElunaObject* elunaObj = Eluna::CHECKOBJ<ElunaObject>(L, 1);
bool invalidate = Eluna::CHECKVAL<bool>(L, 2);
elunaObj->SetValidation(invalidate);
return 0;
}
static int CallMethod(lua_State* L)
{
T* obj = Eluna::CHECKOBJ<T>(L, 1); // get self
if (!obj)
return 0;
ElunaRegister<T>* l = static_cast<ElunaRegister<T>*>(lua_touserdata(L, lua_upvalueindex(1)));
Eluna* E = static_cast<Eluna*>(lua_touserdata(L, lua_upvalueindex(2)));
int top = lua_gettop(L);
int expected = l->mfunc(E, L, obj);
int args = lua_gettop(L) - top;
if (args < 0 || args > expected)
{
ELUNA_LOG_ERROR("[Eluna]: %s returned unexpected amount of arguments %i out of %i. Report to devs", l->name, args, expected);
ASSERT(false);
}
if (args == expected)
return expected;
lua_settop(L, top);
return 0;
}
// Metamethods ("virtual")
// Remember special cases like ElunaTemplate<Vehicle>::CollectGarbage
static int CollectGarbage(lua_State* L)
{
// Get object pointer (and check type, no error)
ElunaObject* obj = Eluna::CHECKOBJ<ElunaObject>(L, 1, false);
if (obj && manageMemory)
delete static_cast<T*>(obj->GetObj());
delete obj;
return 0;
}
static int ToString(lua_State* L)
{
T* obj = Eluna::CHECKOBJ<T>(L, 1, true); // get self
lua_pushfstring(L, "%s: (%p)", tname, obj);
return 1;
}
static int ArithmeticError(lua_State* L) { return luaL_error(L, "attempt to perform arithmetic on a %s value", tname); }
static int CompareError(lua_State* L) { return luaL_error(L, "attempt to compare %s", tname); }
static int Add(lua_State* L) { return ArithmeticError(L); }
static int Substract(lua_State* L) { return ArithmeticError(L); }
static int Multiply(lua_State* L) { return ArithmeticError(L); }
static int Divide(lua_State* L) { return ArithmeticError(L); }
static int Mod(lua_State* L) { return ArithmeticError(L); }
static int Pow(lua_State* L) { return ArithmeticError(L); }
static int UnaryMinus(lua_State* L) { return ArithmeticError(L); }
static int Concat(lua_State* L) { return luaL_error(L, "attempt to concatenate a %s value", tname); }
static int Length(lua_State* L) { return luaL_error(L, "attempt to get length of a %s value", tname); }
static int Equal(lua_State* L) { Eluna::Push(L, Eluna::CHECKOBJ<T>(L, 1) == Eluna::CHECKOBJ<T>(L, 2)); return 1; }
static int Less(lua_State* L) { return CompareError(L); }
static int LessOrEqual(lua_State* L) { return CompareError(L); }
static int Call(lua_State* L) { return luaL_error(L, "attempt to call a %s value", tname); }
};
#endif

View file

@ -0,0 +1,87 @@
/*
* 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 "ElunaUtility.h"
#include "World.h"
#include "Object.h"
#include "Unit.h"
uint32 ElunaUtil::GetCurrTime()
{
#ifndef TRINITY
return WorldTimer::getMSTime();
#else
return getMSTime();
#endif
}
uint32 ElunaUtil::GetTimeDiff(uint32 oldMSTime)
{
#ifndef TRINITY
return WorldTimer::getMSTimeDiff(oldMSTime, GetCurrTime());
#else
return GetMSTimeDiffToNow(oldMSTime);
#endif
}
ElunaUtil::ObjectGUIDCheck::ObjectGUIDCheck(ObjectGuid guid) : _guid(guid)
{
}
bool ElunaUtil::ObjectGUIDCheck::operator()(WorldObject* object)
{
return object->GET_GUID() == _guid;
}
ElunaUtil::ObjectDistanceOrderPred::ObjectDistanceOrderPred(WorldObject const* pRefObj, bool ascending) : m_refObj(pRefObj), m_ascending(ascending)
{
}
bool ElunaUtil::ObjectDistanceOrderPred::operator()(WorldObject const* pLeft, WorldObject const* pRight) const
{
return m_ascending ? m_refObj->GetDistanceOrder(pLeft, pRight) : !m_refObj->GetDistanceOrder(pLeft, pRight);
}
ElunaUtil::WorldObjectInRangeCheck::WorldObjectInRangeCheck(bool nearest, WorldObject const* obj, float range,
uint16 typeMask, uint32 entry, uint32 hostile) :
i_obj(obj), i_hostile(hostile), i_entry(entry), i_range(range), i_typeMask(typeMask), i_nearest(nearest)
{
}
WorldObject const& ElunaUtil::WorldObjectInRangeCheck::GetFocusObject() const
{
return *i_obj;
}
bool ElunaUtil::WorldObjectInRangeCheck::operator()(WorldObject* u)
{
if (i_typeMask && !u->isType(TypeMask(i_typeMask)))
return false;
if (i_entry && u->GetEntry() != i_entry)
return false;
if (i_obj->GET_GUID() == u->GET_GUID())
return false;
if (!i_obj->IsWithinDistInMap(u, i_range))
return false;
if (Unit* unit = u->ToUnit())
{
#ifdef CMANGOS
if (!unit->isAlive())
return false;
#else
if (!unit->IsAlive())
return false;
#endif
if (i_hostile)
{
if (const Unit* obj = i_obj->ToUnit())
{
if ((i_hostile == 1) != obj->IsHostileTo(unit))
return false;
}
}
}
if (i_nearest)
i_range = i_obj->GetDistance(u);
return true;
}

View file

@ -0,0 +1,151 @@
/*
* 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
*/
#ifndef _ELUNA_UTIL_H
#define _ELUNA_UTIL_H
#include "Common.h"
#include "SharedDefines.h"
#include "ObjectGuid.h"
#ifdef TRINITY
#include "QueryResult.h"
#ifdef CATA
#include "Object.h"
#endif
#else
#include "Database/QueryResult.h"
#endif
// Some dummy includes containing BOOST_VERSION:
// ObjectAccessor.h Config.h Log.h
#ifdef BOOST_VERSION
#define USING_BOOST
#endif
#ifdef USING_BOOST
#include <boost/thread/locks.hpp>
#include <boost/thread/shared_mutex.hpp>
#else
#include <ace/Recursive_Thread_Mutex.h>
#endif
#ifdef TRINITY
typedef QueryResult ElunaQuery;
#define ELUNA_LOG_INFO(...) TC_LOG_INFO("eluna", __VA_ARGS__);
#define ELUNA_LOG_ERROR(...) TC_LOG_ERROR("eluna", __VA_ARGS__);
#define ELUNA_LOG_DEBUG(...) TC_LOG_DEBUG("eluna", __VA_ARGS__);
#define GET_GUID GetGUID
#else
typedef QueryNamedResult ElunaQuery;
#define ASSERT MANGOS_ASSERT
#define ELUNA_LOG_INFO(...) sLog.outString(__VA_ARGS__);
#define ELUNA_LOG_ERROR(...) sLog.outErrorEluna(__VA_ARGS__);
#define ELUNA_LOG_DEBUG(...) sLog.outDebug(__VA_ARGS__);
#define GET_GUID GetObjectGuid
#define GetGameObjectTemplate GetGameObjectInfo
#define GetItemTemplate GetItemPrototype
#define GetTemplate GetProto
#endif
#ifndef UNORDERED_MAP
#include <unordered_map>
#define UNORDERED_MAP std::unordered_map
#endif
#ifndef UNORDERED_SET
#include <unordered_set>
#define UNORDERED_SET std::unordered_set
#endif
#ifndef MAKE_NEW_GUID
#define MAKE_NEW_GUID(l, e, h) ObjectGuid(h, e, l)
#endif
#ifndef GUID_ENPART
#define GUID_ENPART(guid) ObjectGuid(guid).GetEntry()
#endif
#ifndef GUID_LOPART
#define GUID_LOPART(guid) ObjectGuid(guid).GetCounter()
#endif
#ifndef GUID_HIPART
#define GUID_HIPART(guid) ObjectGuid(guid).GetHigh()
#endif
class Unit;
class WorldObject;
namespace ElunaUtil
{
uint32 GetCurrTime();
uint32 GetTimeDiff(uint32 oldMSTime);
class ObjectGUIDCheck
{
public:
ObjectGUIDCheck(ObjectGuid guid);
bool operator()(WorldObject* object);
ObjectGuid _guid;
};
// Binary predicate to sort WorldObjects based on the distance to a reference WorldObject
class ObjectDistanceOrderPred
{
public:
ObjectDistanceOrderPred(WorldObject const* pRefObj, bool ascending = true);
bool operator()(WorldObject const* pLeft, WorldObject const* pRight) const;
WorldObject const* m_refObj;
const bool m_ascending;
};
// Doesn't get self
class WorldObjectInRangeCheck
{
public:
WorldObjectInRangeCheck(bool nearest, WorldObject const* obj, float range,
uint16 typeMask = 0, uint32 entry = 0, uint32 hostile = 0);
WorldObject const& GetFocusObject() const;
bool operator()(WorldObject* u);
WorldObject const* i_obj;
uint32 i_hostile;
uint32 i_entry;
float i_range;
uint16 i_typeMask;
bool i_nearest;
};
/*
* Usage:
* Inherit this class, then when needing lock, use
* ReadGuard guard(GetLock());
* or
* WriteGuard guard(GetLock());
*
* The lock is automatically released at end of scope
*/
class RWLockable
{
public:
#ifdef USING_BOOST
typedef boost::recursive_mutex LockType;
typedef boost::shared_lock<boost::shared_mutex> ReadGuard;
typedef boost::unique_lock<boost::shared_mutex> WriteGuard;
#else
typedef ACE_Recursive_Thread_Mutex LockType;
typedef ACE_Read_Guard<LockType> ReadGuard;
typedef ACE_Write_Guard<LockType> WriteGuard;
#endif
LockType& GetLock() { return _lock; }
private:
LockType _lock;
};
};
#endif

View file

@ -0,0 +1,212 @@
/*
* 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
*/
#ifndef _GAMEOBJECT_HOOKS_H
#define _GAMEOBJECT_HOOKS_H
#include "Hooks.h"
#include "HookHelpers.h"
#include "LuaEngine.h"
#include "ElunaBinding.h"
#include "ElunaIncludes.h"
#include "ElunaEventMgr.h"
#include "ElunaTemplate.h"
using namespace Hooks;
bool Eluna::OnDummyEffect(Unit* pCaster, uint32 spellId, SpellEffIndex effIndex, GameObject* pTarget)
{
if (!GameObjectEventBindings->HasEvents(GAMEOBJECT_EVENT_ON_DUMMY_EFFECT, pTarget->GetEntry()))
return false;
LOCK_ELUNA;
Push(pCaster);
Push(spellId);
Push(effIndex);
Push(pTarget);
return CallAllFunctionsBool(GameObjectEventBindings, GAMEOBJECT_EVENT_ON_DUMMY_EFFECT, pTarget->GetEntry());
}
bool Eluna::OnGossipHello(Player* pPlayer, GameObject* pGameObject)
{
if (!GameObjectGossipBindings->HasEvents(GOSSIP_EVENT_ON_HELLO, pGameObject->GetEntry()))
return false;
LOCK_ELUNA;
pPlayer->PlayerTalkClass->ClearMenus();
Push(pPlayer);
Push(pGameObject);
return CallAllFunctionsBool(GameObjectGossipBindings, GOSSIP_EVENT_ON_HELLO, pGameObject->GetEntry(), true);
}
bool Eluna::OnGossipSelect(Player* pPlayer, GameObject* pGameObject, uint32 sender, uint32 action)
{
if (!GameObjectGossipBindings->HasEvents(GOSSIP_EVENT_ON_SELECT, pGameObject->GetEntry()))
return false;
LOCK_ELUNA;
pPlayer->PlayerTalkClass->ClearMenus();
Push(pPlayer);
Push(pGameObject);
Push(sender);
Push(action);
return CallAllFunctionsBool(GameObjectGossipBindings, GOSSIP_EVENT_ON_SELECT, pGameObject->GetEntry(), true);
}
bool Eluna::OnGossipSelectCode(Player* pPlayer, GameObject* pGameObject, uint32 sender, uint32 action, const char* code)
{
if (!GameObjectGossipBindings->HasEvents(GOSSIP_EVENT_ON_SELECT, pGameObject->GetEntry()))
return false;
LOCK_ELUNA;
pPlayer->PlayerTalkClass->ClearMenus();
Push(pPlayer);
Push(pGameObject);
Push(sender);
Push(action);
Push(code);
return CallAllFunctionsBool(GameObjectGossipBindings, GOSSIP_EVENT_ON_SELECT, pGameObject->GetEntry(), true);
}
bool Eluna::OnQuestAccept(Player* pPlayer, GameObject* pGameObject, Quest const* pQuest)
{
if (!GameObjectEventBindings->HasEvents(GAMEOBJECT_EVENT_ON_QUEST_ACCEPT, pGameObject->GetEntry()))
return false;
LOCK_ELUNA;
Push(pPlayer);
Push(pGameObject);
Push(pQuest);
return CallAllFunctionsBool(GameObjectEventBindings, GAMEOBJECT_EVENT_ON_QUEST_ACCEPT, pGameObject->GetEntry());
}
void Eluna::UpdateAI(GameObject* pGameObject, uint32 diff)
{
if (!GameObjectEventBindings->HasEvents(GAMEOBJECT_EVENT_ON_AIUPDATE, pGameObject->GetEntry()))
return;
LOCK_ELUNA;
pGameObject->elunaEvents->Update(diff);
Push(pGameObject);
Push(diff);
CallAllFunctions(GameObjectEventBindings, GAMEOBJECT_EVENT_ON_AIUPDATE, pGameObject->GetEntry());
}
bool Eluna::OnQuestReward(Player* pPlayer, GameObject* pGameObject, Quest const* pQuest, uint32 opt)
{
if (!GameObjectEventBindings->HasEvents(GAMEOBJECT_EVENT_ON_QUEST_REWARD, pGameObject->GetEntry()))
return false;
LOCK_ELUNA;
Push(pPlayer);
Push(pGameObject);
Push(pQuest);
Push(opt);
return CallAllFunctionsBool(GameObjectEventBindings, GAMEOBJECT_EVENT_ON_QUEST_REWARD, pGameObject->GetEntry());
}
uint32 Eluna::GetDialogStatus(Player* pPlayer, GameObject* pGameObject)
{
if (!GameObjectEventBindings->HasEvents(GAMEOBJECT_EVENT_ON_DIALOG_STATUS, pGameObject->GetEntry()))
return DIALOG_STATUS_SCRIPTED_NO_STATUS;
LOCK_ELUNA;
Push(pPlayer);
Push(pGameObject);
CallAllFunctions(GameObjectEventBindings, GAMEOBJECT_EVENT_ON_DIALOG_STATUS, pGameObject->GetEntry());
return DIALOG_STATUS_SCRIPTED_NO_STATUS; // DIALOG_STATUS_UNDEFINED
}
#ifndef CLASSIC
#ifndef TBC
void Eluna::OnDestroyed(GameObject* pGameObject, Player* pPlayer)
{
if (!GameObjectEventBindings->HasEvents(GAMEOBJECT_EVENT_ON_DESTROYED, pGameObject->GetEntry()))
return;
LOCK_ELUNA;
Push(pGameObject);
Push(pPlayer);
CallAllFunctions(GameObjectEventBindings, GAMEOBJECT_EVENT_ON_DESTROYED, pGameObject->GetEntry());
}
void Eluna::OnDamaged(GameObject* pGameObject, Player* pPlayer)
{
if (!GameObjectEventBindings->HasEvents(GAMEOBJECT_EVENT_ON_DAMAGED, pGameObject->GetEntry()))
return;
LOCK_ELUNA;
Push(pGameObject);
Push(pPlayer);
CallAllFunctions(GameObjectEventBindings, GAMEOBJECT_EVENT_ON_DAMAGED, pGameObject->GetEntry());
}
#endif
#endif
void Eluna::OnLootStateChanged(GameObject* pGameObject, uint32 state)
{
if (!GameObjectEventBindings->HasEvents(GAMEOBJECT_EVENT_ON_LOOT_STATE_CHANGE, pGameObject->GetEntry()))
return;
LOCK_ELUNA;
Push(pGameObject);
Push(state);
CallAllFunctions(GameObjectEventBindings, GAMEOBJECT_EVENT_ON_LOOT_STATE_CHANGE, pGameObject->GetEntry());
}
void Eluna::OnGameObjectStateChanged(GameObject* pGameObject, uint32 state)
{
if (!GameObjectEventBindings->HasEvents(GAMEOBJECT_EVENT_ON_GO_STATE_CHANGED, pGameObject->GetEntry()))
return;
LOCK_ELUNA;
Push(pGameObject);
Push(state);
CallAllFunctions(GameObjectEventBindings, GAMEOBJECT_EVENT_ON_GO_STATE_CHANGED, pGameObject->GetEntry());
}
void Eluna::OnSpawn(GameObject* gameobject)
{
if (!GameObjectEventBindings->HasEvents(GAMEOBJECT_EVENT_ON_SPAWN, gameobject->GetEntry()))
return;
LOCK_ELUNA;
Push(gameobject);
CallAllFunctions(GameObjectEventBindings, GAMEOBJECT_EVENT_ON_SPAWN, gameobject->GetEntry());
}
void Eluna::OnAddToWorld(GameObject* gameobject)
{
if (!GameObjectEventBindings->HasEvents(GAMEOBJECT_EVENT_ON_ADD, gameobject->GetEntry()))
return;
LOCK_ELUNA;
Push(gameobject);
CallAllFunctions(GameObjectEventBindings, GAMEOBJECT_EVENT_ON_ADD, gameobject->GetEntry());
}
void Eluna::OnRemoveFromWorld(GameObject* gameobject)
{
if (!GameObjectEventBindings->HasEvents(GAMEOBJECT_EVENT_ON_REMOVE, gameobject->GetEntry()))
return;
LOCK_ELUNA;
Push(gameobject);
CallAllFunctions(GameObjectEventBindings, GAMEOBJECT_EVENT_ON_REMOVE, gameobject->GetEntry());
}
bool Eluna::OnGameObjectUse(Player* pPlayer, GameObject* pGameObject)
{
if (!GameObjectEventBindings->HasEvents(GAMEOBJECT_EVENT_ON_USE, pGameObject->GetEntry()))
return false;
LOCK_ELUNA;
Push(pGameObject);
Push(pPlayer);
return CallAllFunctionsBool(GameObjectEventBindings, GAMEOBJECT_EVENT_ON_USE, pGameObject->GetEntry());
}
#endif // _GAMEOBJECT_HOOKS_H

View file

@ -0,0 +1,278 @@
/*
* 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
*/
#ifndef GAMEOBJECTMETHODS_H
#define GAMEOBJECTMETHODS_H
namespace LuaGameObject
{
/**
* Returns 'true' if the [GameObject] can give the specified [Quest]
*
* @param uint32 questId : quest entry Id to check
* @return bool hasQuest
*/
int HasQuest(Eluna* /*E*/, lua_State* L, GameObject* go)
{
uint32 questId = Eluna::CHECKVAL<uint32>(L, 2);
#ifndef TRINITY
Eluna::Push(L, go->HasQuest(questId));
#else
Eluna::Push(L, go->hasQuest(questId));
#endif
return 1;
}
/**
* Returns 'true' if the [GameObject] is spawned
*
* @return bool isSpawned
*/
int IsSpawned(Eluna* /*E*/, lua_State* L, GameObject* go)
{
Eluna::Push(L, go->isSpawned());
return 1;
}
/**
* Returns 'true' if the [GameObject] is a transport
*
* @return bool isTransport
*/
int IsTransport(Eluna* /*E*/, lua_State* L, GameObject* go)
{
Eluna::Push(L, go->IsTransport());
return 1;
}
/**
* Returns 'true' if the [GameObject] is active
*
* @return bool isActive
*/
int IsActive(Eluna* /*E*/, lua_State* L, GameObject* go)
{
Eluna::Push(L, go->isActiveObject());
return 1;
}
/*int IsDestructible(Eluna* E, lua_State* L, GameObject* go) // TODO: Implementation core side
{
Eluna::Push(L, go->IsDestructibleBuilding());
return 1;
}*/
/**
* Returns display ID of the [GameObject]
*
* @return uint32 displayId
*/
int GetDisplayId(Eluna* /*E*/, lua_State* L, GameObject* go)
{
Eluna::Push(L, go->GetDisplayId());
return 1;
}
/**
* Returns the state of a [GameObject]
* Below are client side [GOState]s off of 3.3.5a
*
* <pre>
* enum GOState
* {
* GO_STATE_ACTIVE = 0, // show in world as used and not reset (closed door open)
* GO_STATE_READY = 1, // show in world as ready (closed door close)
* GO_STATE_ACTIVE_ALTERNATIVE = 2 // show in world as used in alt way and not reset (closed door open by cannon fire)
* };
* </pre>
*
* @return [GOState] goState
*/
int GetGoState(Eluna* /*E*/, lua_State* L, GameObject* go)
{
Eluna::Push(L, go->GetGoState());
return 1;
}
/**
* Returns the [LootState] of a [GameObject]
* Below are [LootState]s off of 3.3.5a
*
* <pre>
* enum LootState
* {
* GO_NOT_READY = 0,
* GO_READY, // can be ready but despawned, and then not possible activate until spawn
* GO_ACTIVATED,
* GO_JUST_DEACTIVATED
* };
* </pre>
*
* @return [LootState] lootState
*/
int GetLootState(Eluna* /*E*/, lua_State* L, GameObject* go)
{
Eluna::Push(L, go->getLootState());
return 1;
}
/**
* Returns the [Player] that can loot the [GameObject]
*
* @return [Player] player
*/
int GetLootRecipient(Eluna* /*E*/, lua_State* L, GameObject* go)
{
Eluna::Push(L, go->GetLootRecipient());
return 1;
}
/**
* Returns the [Group] that can loot the [GameObject]
*
* @return [Group] group
*/
int GetLootRecipientGroup(Eluna* /*E*/, lua_State* L, GameObject* go)
{
#ifdef TRINITY
Eluna::Push(L, go->GetLootRecipientGroup());
#else
Eluna::Push(L, go->GetGroupLootRecipient());
#endif
return 1;
}
/**
* Sets the state of a [GameObject]
*
* <pre>
* enum GOState
* {
* GO_STATE_ACTIVE = 0, // show in world as used and not reset (closed door open)
* GO_STATE_READY = 1, // show in world as ready (closed door close)
* GO_STATE_ACTIVE_ALTERNATIVE = 2 // show in world as used in alt way and not reset (closed door open by cannon fire)
* };
* </pre>
*
* @param [GOState] state : all available go states can be seen above
*/
int SetGoState(Eluna* /*E*/, lua_State* L, GameObject* go)
{
uint32 state = Eluna::CHECKVAL<uint32>(L, 2, 0);
if (state == 0)
go->SetGoState(GO_STATE_ACTIVE);
else if (state == 1)
go->SetGoState(GO_STATE_READY);
else if (state == 2)
go->SetGoState(GO_STATE_ACTIVE_ALTERNATIVE);
return 0;
}
/**
* Sets the [LootState] of a [GameObject]
* Below are [LootState]s off of 3.3.5a
*
* <pre>
* enum LootState
* {
* GO_NOT_READY = 0,
* GO_READY, // can be ready but despawned, and then not possible activate until spawn
* GO_ACTIVATED,
* GO_JUST_DEACTIVATED
* };
* </pre>
*
* @param [LootState] state : all available loot states can be seen above
*/
int SetLootState(Eluna* /*E*/, lua_State* L, GameObject* go)
{
uint32 state = Eluna::CHECKVAL<uint32>(L, 2, 0);
if (state == 0)
go->SetLootState(GO_NOT_READY);
else if (state == 1)
go->SetLootState(GO_READY);
else if (state == 2)
go->SetLootState(GO_ACTIVATED);
else if (state == 3)
go->SetLootState(GO_JUST_DEACTIVATED);
return 0;
}
/**
* Saves [GameObject] to the database
*
*/
int SaveToDB(Eluna* /*E*/, lua_State* /*L*/, GameObject* go)
{
go->SaveToDB();
return 0;
}
/**
* Removes [GameObject] from the world
*
* @param bool deleteFromDB : if true, it will delete the [GameObject] from the database
*/
int RemoveFromWorld(Eluna* /*E*/, lua_State* L, GameObject* go)
{
bool deldb = Eluna::CHECKVAL<bool>(L, 2, false);
if (deldb)
go->DeleteFromDB();
go->RemoveFromWorld();
return 0;
}
/**
* Changes uses a door or a button type [GameObject]
*
* @param uint32 delay : cooldown time in seconds to restore the [GameObject] back to normal
*/
int UseDoorOrButton(Eluna* /*E*/, lua_State* L, GameObject* go)
{
uint32 delay = Eluna::CHECKVAL<uint32>(L, 2, 0);
go->UseDoorOrButton(delay);
return 0;
}
/**
* Despawns a [GameObject]
*
* @param uint32 delay : time in seconds to despawn
*/
int Despawn(Eluna* /*E*/, lua_State* L, GameObject* go)
{
uint32 delay = Eluna::CHECKVAL<uint32>(L, 2, 1);
if (!delay)
delay = 1;
go->SetSpawnedByDefault(false);
go->SetRespawnTime(delay);
return 0;
}
/**
* Respawns a [GameObject]
*
* @param uint32 delay : time of respawn in seconds
*/
int Respawn(Eluna* /*E*/, lua_State* L, GameObject* go)
{
uint32 delay = Eluna::CHECKVAL<uint32>(L, 2, 1);
if (!delay)
delay = 1;
go->SetSpawnedByDefault(true);
go->SetRespawnTime(delay);
return 0;
}
};
#endif

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,86 @@
/*
* 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
*/
#ifndef _GROUP_HOOKS_H
#define _GROUP_HOOKS_H
#include "Hooks.h"
#include "HookHelpers.h"
#include "LuaEngine.h"
#include "ElunaBinding.h"
#include "ElunaTemplate.h"
using namespace Hooks;
void Eluna::OnAddMember(Group* group, uint64 guid)
{
if (!GroupEventBindings->HasEvents(GROUP_EVENT_ON_MEMBER_ADD))
return;
LOCK_ELUNA;
Push(group);
Push(guid);
CallAllFunctions(GroupEventBindings, GROUP_EVENT_ON_MEMBER_ADD);
}
void Eluna::OnInviteMember(Group* group, uint64 guid)
{
if (!GroupEventBindings->HasEvents(GROUP_EVENT_ON_MEMBER_INVITE))
return;
LOCK_ELUNA;
Push(group);
Push(guid);
CallAllFunctions(GroupEventBindings, GROUP_EVENT_ON_MEMBER_INVITE);
}
void Eluna::OnRemoveMember(Group* group, uint64 guid, uint8 method)
{
if (!GroupEventBindings->HasEvents(GROUP_EVENT_ON_MEMBER_REMOVE))
return;
LOCK_ELUNA;
Push(group);
Push(guid);
Push(method);
CallAllFunctions(GroupEventBindings, GROUP_EVENT_ON_MEMBER_REMOVE);
}
void Eluna::OnChangeLeader(Group* group, uint64 newLeaderGuid, uint64 oldLeaderGuid)
{
if (!GroupEventBindings->HasEvents(GROUP_EVENT_ON_LEADER_CHANGE))
return;
LOCK_ELUNA;
Push(group);
Push(newLeaderGuid);
Push(oldLeaderGuid);
CallAllFunctions(GroupEventBindings, GROUP_EVENT_ON_LEADER_CHANGE);
}
void Eluna::OnDisband(Group* group)
{
if (!GroupEventBindings->HasEvents(GROUP_EVENT_ON_DISBAND))
return;
LOCK_ELUNA;
Push(group);
CallAllFunctions(GroupEventBindings, GROUP_EVENT_ON_DISBAND);
}
void Eluna::OnCreate(Group* group, uint64 leaderGuid, GroupType groupType)
{
if (!GroupEventBindings->HasEvents(GROUP_EVENT_ON_CREATE))
return;
LOCK_ELUNA;
Push(group);
Push(leaderGuid);
Push(groupType);
CallAllFunctions(GroupEventBindings, GROUP_EVENT_ON_CREATE);
}
#endif // _GROUP_HOOKS_H

View file

@ -0,0 +1,383 @@
/*
* 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
*/
#ifndef GROUPMETHODS_H
#define GROUPMETHODS_H
namespace LuaGroup
{
/**
* Returns 'true' if the player is the [Group] leader
*
* @param uint64 guid : guid of a possible leader
* @return bool isLeader
*/
int IsLeader(Eluna* /*E*/, lua_State* L, Group* group)
{
uint64 guid = Eluna::CHECKVAL<uint64>(L, 2);
Eluna::Push(L, group->IsLeader(ObjectGuid(guid)));
return 1;
}
/**
* Returns 'true' if the [Group] is full
*
* @return bool isFull
*/
int IsFull(Eluna* /*E*/, lua_State* L, Group* group)
{
Eluna::Push(L, group->IsFull());
return 1;
}
/**
* Returns 'true' if the [Group] is a raid [Group]
*
* @return bool isRaid
*/
int IsRaidGroup(Eluna* /*E*/, lua_State* L, Group* group)
{
Eluna::Push(L, group->isRaidGroup());
return 1;
}
/**
* Returns 'true' if the [Group] is a battleground [Group]
*
* @return bool isBG
*/
int IsBGGroup(Eluna* /*E*/, lua_State* L, Group* group)
{
Eluna::Push(L, group->isBGGroup());
return 1;
}
/**
* Returns 'true' if the [Player] is a member of this [Group]
*
* @param [Player] player : [Player] to check
* @return bool isMember
*/
int IsMember(Eluna* /*E*/, lua_State* L, Group* group)
{
Player* player = Eluna::CHECKOBJ<Player>(L, 2);
Eluna::Push(L, group->IsMember(player->GET_GUID()));
return 1;
}
/**
* Returns 'true' if the [Player] is an assistant of this [Group]
*
* @param [Player] player : [Player] to check
* @return bool isAssistant
*/
int IsAssistant(Eluna* /*E*/, lua_State* L, Group* group)
{
Player* player = Eluna::CHECKOBJ<Player>(L, 2);
Eluna::Push(L, group->IsAssistant(player->GET_GUID()));
return 1;
}
/**
* Returns 'true' if the [Player]s are in the same subgroup in this [Group]
*
* @param [Player] player1 : first [Player] to check
* @param [Player] player2 : second [Player] to check
* @return bool sameSubGroup
*/
int SameSubGroup(Eluna* /*E*/, lua_State* L, Group* group)
{
Player* player1 = Eluna::CHECKOBJ<Player>(L, 2);
Player* player2 = Eluna::CHECKOBJ<Player>(L, 3);
Eluna::Push(L, group->SameSubGroup(player1, player2));
return 1;
}
/**
* Returns 'true' if the subgroup has free slots in this [Group]
*
* @param uint8 subGroup : subGroup ID to check
* @return bool hasFreeSlot
*/
int HasFreeSlotSubGroup(Eluna* /*E*/, lua_State* L, Group* group)
{
uint8 subGroup = Eluna::CHECKVAL<uint8>(L, 2);
Eluna::Push(L, group->HasFreeSlotSubGroup(subGroup));
return 1;
}
/**
* Returns 'true' if the [Group] invite was successful
*
* @param [Player] player : [Player] to invite
* @return bool invited
*/
int AddInvite(Eluna* /*E*/, lua_State* L, Group* group)
{
Player* player = Eluna::CHECKOBJ<Player>(L, 2);
Eluna::Push(L, group->AddInvite(player));
return 1;
}
/*int IsLFGGroup(Eluna* E, lua_State* L, Group* group) // TODO: Implementation
{
Eluna::Push(L, group->isLFGGroup());
return 1;
}*/
/*int IsBFGroup(Eluna* E, lua_State* L, Group* group) // TODO: Implementation
{
Eluna::Push(L, group->isBFGroup());
return 1;
}*/
/**
* Returns a table with the [Player]s in this [Group]
*
* @return table groupPlayers : table of [Player]s
*/
int GetMembers(Eluna* /*E*/, lua_State* L, Group* group)
{
lua_newtable(L);
int tbl = lua_gettop(L);
uint32 i = 0;
for (GroupReference* itr = group->GetFirstMember(); itr; itr = itr->next())
{
#ifndef TRINITY
Player* member = itr->getSource();
#else
Player* member = itr->GetSource();
#endif
if (!member || !member->GetSession())
continue;
++i;
Eluna::Push(L, i);
Eluna::Push(L, member);
lua_settable(L, tbl);
}
lua_settop(L, tbl); // push table to top of stack
return 1;
}
/**
* Returns [Group] leader GUID
*
* @return uint64 leaderGUID
*/
int GetLeaderGUID(Eluna* /*E*/, lua_State* L, Group* group)
{
#ifndef TRINITY
Eluna::Push(L, group->GetLeaderGuid());
#else
Eluna::Push(L, group->GetLeaderGUID());
#endif
return 1;
}
/**
* Finds and returns a [Group] leader by their GUID if logged in
*
* @return [Player] leader
*/
int GetLeader(Eluna* /*E*/, lua_State* L, Group* group)
{
#ifndef TRINITY
Eluna::Push(L, eObjectAccessor->FindPlayer(group->GetLeaderGuid()));
#else
Eluna::Push(L, eObjectAccessor->FindPlayer(group->GetLeaderGUID()));
#endif
return 1;
}
/**
* Returns the [Group]'s GUID
*
* @return uint64 groupGUID
*/
int GetGUID(Eluna* /*E*/, lua_State* L, Group* group)
{
#ifdef CLASSIC
Eluna::Push(L, group->GetId());
#else
Eluna::Push(L, group->GET_GUID());
#endif
return 1;
}
/**
* Returns a [Group] member's GUID by their name
*
* @param string name : the [Player]'s name
* @return uint64 memberGUID
*/
int GetMemberGUID(Eluna* /*E*/, lua_State* L, Group* group)
{
const char* name = Eluna::CHECKVAL<const char*>(L, 2);
#ifndef TRINITY
Eluna::Push(L, group->GetMemberGuid(name));
#else
Eluna::Push(L, group->GetMemberGUID(name));
#endif
return 1;
}
/**
* Returns the member count of this [Group]
*
* @return uint32 memberCount
*/
int GetMembersCount(Eluna* /*E*/, lua_State* L, Group* group)
{
Eluna::Push(L, group->GetMembersCount());
return 1;
}
/**
* Returns the [Player]'s subgroup ID of this [Group]
*
* @param [Player] player : the [Player] to check
* @return uint8 subGroupID
*/
int GetMemberGroup(Eluna* /*E*/, lua_State* L, Group* group)
{
Player* player = Eluna::CHECKOBJ<Player>(L, 2);
Eluna::Push(L, group->GetMemberGroup(player->GET_GUID()));
return 1;
}
/**
* Sets the leader of this [Group]
*
* @param [Player] leader : the [Player] leader to change
*/
int SetLeader(Eluna* /*E*/, lua_State* L, Group* group)
{
Player* leader = Eluna::CHECKOBJ<Player>(L, 2);
group->ChangeLeader(leader->GET_GUID());
return 0;
}
/**
* Sends a specified [WorldPacket] to this [Group]
*
* @param [WorldPacket] packet : the [WorldPacket] to send
* @param bool ignorePlayersInBg : ignores [Player]s in a battleground
* @param uint64 ignore : ignore a [Player] by their GUID
*/
int SendPacket(Eluna* /*E*/, lua_State* L, Group* group)
{
WorldPacket* data = Eluna::CHECKOBJ<WorldPacket>(L, 2);
bool ignorePlayersInBg = Eluna::CHECKVAL<bool>(L, 3);
uint64 ignore = Eluna::CHECKVAL<uint64>(L, 4);
group->BroadcastPacket(data, ignorePlayersInBg, -1, ObjectGuid(ignore));
return 0;
}
/**
* Removes a member from this [Group] and returns 'true' if successful
*
* <pre>
* enum RemoveMethod
* {
* GROUP_REMOVEMETHOD_DEFAULT = 0,
* GROUP_REMOVEMETHOD_KICK = 1,
* GROUP_REMOVEMETHOD_LEAVE = 2,
* GROUP_REMOVEMETHOD_KICK_LFG = 3
* };
* </pre>
*
* @param [Player] player : the [Player] to remove
* @param [RemoveMethod] method : method used to remove the player
* @return bool removed
*/
int RemoveMember(Eluna* /*E*/, lua_State* L, Group* group)
{
Player* player = Eluna::CHECKOBJ<Player>(L, 2);
uint32 method = Eluna::CHECKVAL<uint32>(L, 3, 0);
#ifndef TRINITY
Eluna::Push(L, group->RemoveMember(player->GET_GUID(), method));
#else
Eluna::Push(L, group->RemoveMember(player->GET_GUID(), (RemoveMethod)method));
#endif
return 1;
}
/**
* Disbands this [Group]
*
*/
int Disband(Eluna* /*E*/, lua_State* /*L*/, Group* group)
{
group->Disband();
return 0;
}
/**
* Converts this [Group] to a raid [Group]
*
*/
int ConvertToRaid(Eluna* /*E*/, lua_State* /*L*/, Group* group)
{
group->ConvertToRaid();
return 0;
}
/**
* Sets the member's subGroup
*
* @param [Player] player : [Player] to move
* @param uint8 groupID : the subGroup's ID
*/
int SetMembersGroup(Eluna* /*E*/, lua_State* L, Group* group)
{
Player* player = Eluna::CHECKOBJ<Player>(L, 2);
uint8 groupID = Eluna::CHECKVAL<uint8>(L, 3);
group->ChangeMembersGroup(player->GET_GUID(), groupID);
return 0;
}
/**
* Sets the target icon of an object for the [Group]
*
* @param uint8 icon : the icon (Skull, Square, etc)
* @param uint64 target : GUID of the icon target, 0 is to clear the icon
* @param uint64 setter : GUID of the icon setter
*/
int SetTargetIcon(Eluna* /*E*/, lua_State* L, Group* group)
{
uint8 icon = Eluna::CHECKVAL<uint8>(L, 2);
uint64 target = Eluna::CHECKVAL<uint64>(L, 3);
uint64 setter = Eluna::CHECKVAL<uint64>(L, 4, 0);
if (icon >= TARGETICONCOUNT)
return luaL_argerror(L, 2, "valid target icon expected");
#if (defined(CLASSIC) || defined(TBC))
group->SetTargetIcon(icon, ObjectGuid(target));
#else
group->SetTargetIcon(icon, ObjectGuid(setter), ObjectGuid(target));
#endif
return 0;
}
/*int ConvertToLFG(Eluna* E, lua_State* L, Group* group) // TODO: Implementation
{
group->ConvertToLFG();
return 0;
}*/
};
#endif

View file

@ -0,0 +1,194 @@
/*
* 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
*/
#ifndef _GUILD_HOOKS_H
#define _GUILD_HOOKS_H
#include "Hooks.h"
#include "HookHelpers.h"
#include "LuaEngine.h"
#include "ElunaBinding.h"
#include "ElunaTemplate.h"
using namespace Hooks;
void Eluna::OnAddMember(Guild* guild, Player* player, uint32 plRank)
{
if (!GuildEventBindings->HasEvents(GUILD_EVENT_ON_ADD_MEMBER))
return;
LOCK_ELUNA;
Push(guild);
Push(player);
Push(plRank);
CallAllFunctions(GuildEventBindings, GUILD_EVENT_ON_ADD_MEMBER);
}
void Eluna::OnRemoveMember(Guild* guild, Player* player, bool isDisbanding)
{
if (!GuildEventBindings->HasEvents(GUILD_EVENT_ON_REMOVE_MEMBER))
return;
LOCK_ELUNA;
Push(guild);
Push(player);
Push(isDisbanding);
CallAllFunctions(GuildEventBindings, GUILD_EVENT_ON_REMOVE_MEMBER);
}
void Eluna::OnMOTDChanged(Guild* guild, const std::string& newMotd)
{
if (!GuildEventBindings->HasEvents(GUILD_EVENT_ON_MOTD_CHANGE))
return;
LOCK_ELUNA;
Push(guild);
Push(newMotd);
CallAllFunctions(GuildEventBindings, GUILD_EVENT_ON_MOTD_CHANGE);
}
void Eluna::OnInfoChanged(Guild* guild, const std::string& newInfo)
{
if (!GuildEventBindings->HasEvents(GUILD_EVENT_ON_INFO_CHANGE))
return;
LOCK_ELUNA;
Push(guild);
Push(newInfo);
CallAllFunctions(GuildEventBindings, GUILD_EVENT_ON_INFO_CHANGE);
}
void Eluna::OnCreate(Guild* guild, Player* leader, const std::string& name)
{
if (!GuildEventBindings->HasEvents(GUILD_EVENT_ON_CREATE))
return;
LOCK_ELUNA;
Push(guild);
Push(leader);
Push(name);
CallAllFunctions(GuildEventBindings, GUILD_EVENT_ON_CREATE);
}
void Eluna::OnDisband(Guild* guild)
{
if (!GuildEventBindings->HasEvents(GUILD_EVENT_ON_DISBAND))
return;
LOCK_ELUNA;
Push(guild);
CallAllFunctions(GuildEventBindings, GUILD_EVENT_ON_DISBAND);
}
void Eluna::OnMemberWitdrawMoney(Guild* guild, Player* player, uint32& amount, bool isRepair) // isRepair not a part of Mangos, implement?
{
if (!GuildEventBindings->HasEvents(GUILD_EVENT_ON_MONEY_WITHDRAW))
return;
LOCK_ELUNA;
Push(guild);
Push(player);
Push(amount);
Push(isRepair); // isRepair not a part of Mangos, implement?
int amountIndex = lua_gettop(L) - 1;
int n = SetupStack(GuildEventBindings, GUILD_EVENT_ON_MONEY_WITHDRAW, 4);
while (n > 0)
{
int r = CallOneFunction(n--, 4, 1);
if (lua_isnumber(L, r))
{
amount = CHECKVAL<uint32>(L, r);
// Update the stack for subsequent calls.
ReplaceArgument(amount, amountIndex);
}
lua_pop(L, 1);
}
CleanUpStack(4);
}
void Eluna::OnMemberDepositMoney(Guild* guild, Player* player, uint32& amount)
{
if (!GuildEventBindings->HasEvents(GUILD_EVENT_ON_MONEY_DEPOSIT))
return;
LOCK_ELUNA;
Push(guild);
Push(player);
Push(amount);
int amountIndex = lua_gettop(L);
int n = SetupStack(GuildEventBindings, GUILD_EVENT_ON_MONEY_DEPOSIT, 3);
while (n > 0)
{
int r = CallOneFunction(n--, 3, 1);
if (lua_isnumber(L, r))
{
amount = CHECKVAL<uint32>(L, r);
// Update the stack for subsequent calls.
ReplaceArgument(amount, amountIndex);
}
lua_pop(L, 1);
}
CleanUpStack(3);
}
void Eluna::OnItemMove(Guild* guild, Player* player, Item* pItem, bool isSrcBank, uint8 srcContainer, uint8 srcSlotId,
bool isDestBank, uint8 destContainer, uint8 destSlotId)
{
if (!GuildEventBindings->HasEvents(GUILD_EVENT_ON_ITEM_MOVE))
return;
LOCK_ELUNA;
Push(guild);
Push(player);
Push(pItem);
Push(isSrcBank);
Push(srcContainer);
Push(srcSlotId);
Push(isDestBank);
Push(destContainer);
Push(destSlotId);
CallAllFunctions(GuildEventBindings, GUILD_EVENT_ON_ITEM_MOVE);
}
void Eluna::OnEvent(Guild* guild, uint8 eventType, uint32 playerGuid1, uint32 playerGuid2, uint8 newRank)
{
if (!GuildEventBindings->HasEvents(GUILD_EVENT_ON_EVENT))
return;
LOCK_ELUNA;
Push(guild);
Push(eventType);
Push(playerGuid1);
Push(playerGuid2);
Push(newRank);
CallAllFunctions(GuildEventBindings, GUILD_EVENT_ON_EVENT);
}
void Eluna::OnBankEvent(Guild* guild, uint8 eventType, uint8 tabId, uint32 playerGuid, uint32 itemOrMoney, uint16 itemStackCount, uint8 destTabId)
{
if (!GuildEventBindings->HasEvents(GUILD_EVENT_ON_BANK_EVENT))
return;
LOCK_ELUNA;
Push(guild);
Push(eventType);
Push(tabId);
Push(playerGuid);
Push(itemOrMoney);
Push(itemStackCount);
Push(destTabId);
CallAllFunctions(GuildEventBindings, GUILD_EVENT_ON_BANK_EVENT);
}
#endif // _GUILD_HOOKS_H

View file

@ -0,0 +1,301 @@
/*
* 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
*/
#ifndef GUILDMETHODS_H
#define GUILDMETHODS_H
namespace LuaGuild
{
/* GETTERS */
/**
* Returns a table with the [Player]s in this [Guild]
*
* @return table guildPlayers : table of [Player]s
*/
int GetMembers(Eluna* /*E*/, lua_State* L, Guild* guild)
{
lua_newtable(L);
int tbl = lua_gettop(L);
uint32 i = 0;
{
#ifdef TRINITY
boost::shared_lock<boost::shared_mutex> lock(*HashMapHolder<Player>::GetLock());
#else
HashMapHolder<Player>::ReadGuard g(HashMapHolder<Player>::GetLock());
#endif
const HashMapHolder<Player>::MapType& m = eObjectAccessor->GetPlayers();
for (HashMapHolder<Player>::MapType::const_iterator it = m.begin(); it != m.end(); ++it)
{
if (Player* player = it->second)
{
if (player->GetSession() && (player->GetGuildId() == guild->GetId()))
{
++i;
Eluna::Push(L, i);
Eluna::Push(L, player);
lua_settable(L, tbl);
}
}
}
}
lua_settop(L, tbl); // push table to top of stack
return 1;
}
/**
* Returns the member count of this [Guild]
*
* @return uint32 memberCount
*/
int GetMemberCount(Eluna* /*E*/, lua_State* L, Guild* guild)
{
Eluna::Push(L, guild->GetMemberSize());
return 1;
}
/**
* Finds and returns the [Guild] leader by their GUID if logged in
*
* @return [Player] leader
*/
int GetLeader(Eluna* /*E*/, lua_State* L, Guild* guild)
{
#ifndef TRINITY
Eluna::Push(L, eObjectAccessor->FindPlayer(guild->GetLeaderGuid()));
#else
Eluna::Push(L, eObjectAccessor->FindPlayer(guild->GetLeaderGUID()));
#endif
return 1;
}
/**
* Returns [Guild] leader GUID
*
* @return uint64 leaderGUID
*/
int GetLeaderGUID(Eluna* /*E*/, lua_State* L, Guild* guild)
{
#ifndef TRINITY
Eluna::Push(L, guild->GetLeaderGuid());
#else
Eluna::Push(L, guild->GetLeaderGUID());
#endif
return 1;
}
/**
* Returns the [Guild]s entry ID
*
* @return uint32 entryId
*/
int GetId(Eluna* /*E*/, lua_State* L, Guild* guild)
{
Eluna::Push(L, guild->GetId());
return 1;
}
/**
* Returns the [Guild]s name
*
* @return string guildName
*/
int GetName(Eluna* /*E*/, lua_State* L, Guild* guild)
{
Eluna::Push(L, guild->GetName());
return 1;
}
/**
* Returns the [Guild]s current Message Of The Day
*
* @return string guildMOTD
*/
int GetMOTD(Eluna* /*E*/, lua_State* L, Guild* guild)
{
Eluna::Push(L, guild->GetMOTD());
return 1;
}
/**
* Returns the [Guild]s current info
*
* @return string guildInfo
*/
int GetInfo(Eluna* /*E*/, lua_State* L, Guild* guild)
{
#ifndef TRINITY
Eluna::Push(L, guild->GetGINFO());
#else
Eluna::Push(L, guild->GetInfo());
#endif
return 1;
}
/* SETTERS */
#ifndef CATA
/**
* Sets the leader of this [Guild]
*
* @param [Player] leader : the [Player] leader to change
*/
int SetLeader(Eluna* /*E*/, lua_State* L, Guild* guild)
{
Player* player = Eluna::CHECKOBJ<Player>(L, 2);
#ifndef TRINITY
guild->SetLeader(player->GET_GUID());
#else
guild->HandleSetLeader(player->GetSession(), player->GetName());
#endif
return 0;
}
#endif
#ifndef CLASSIC
/**
* Sets the information of the bank tab specified
*
* @param uint8 tabId : the ID of the tab specified
* @param string info : the information to be set to the bank tab
*/
int SetBankTabText(Eluna* /*E*/, lua_State* L, Guild* guild)
{
uint8 tabId = Eluna::CHECKVAL<uint8>(L, 2);
const char* text = Eluna::CHECKVAL<const char*>(L, 3);
#ifndef TRINITY
guild->SetGuildBankTabText(tabId, text);
#else
guild->SetBankTabText(tabId, text);
#endif
return 0;
}
#endif
/* OTHER */
// SendPacketToGuild(packet)
/**
* Sends a [WorldPacket] to all the [Player]s in the [Guild]
*
* @param [WorldPacket] packet : the [WorldPacket] to be sent to the [Player]s
*/
int SendPacket(Eluna* /*E*/, lua_State* L, Guild* guild)
{
WorldPacket* data = Eluna::CHECKOBJ<WorldPacket>(L, 2);
guild->BroadcastPacket(data);
return 0;
}
// SendPacketToRankedInGuild(packet, rankId)
/**
* Sends a [WorldPacket] to all the [Player]s at the specified rank in the [Guild]
*
* @param [WorldPacket] packet : the [WorldPacket] to be sent to the [Player]s
* @param uint8 rankId : the rank ID
*/
int SendPacketToRanked(Eluna* /*E*/, lua_State* L, Guild* guild)
{
WorldPacket* data = Eluna::CHECKOBJ<WorldPacket>(L, 2);
uint8 ranked = Eluna::CHECKVAL<uint8>(L, 3);
guild->BroadcastPacketToRank(data, ranked);
return 0;
}
/**
* Disbands the [Guild]
*/
int Disband(Eluna* /*E*/, lua_State* /*L*/, Guild* guild)
{
guild->Disband();
return 0;
}
/**
* Adds the specified [Player] to the [Guild] at the specified rank.
*
* If no rank is specified, defaults to none.
*
* @param [Player] player : the [Player] to be added to the guild
* @param uint8 rankId : the rank ID
*/
int AddMember(Eluna* /*E*/, lua_State* L, Guild* guild)
{
Player* player = Eluna::CHECKOBJ<Player>(L, 2);
uint8 rankId = Eluna::CHECKVAL<uint8>(L, 3, GUILD_RANK_NONE);
guild->AddMember(player->GET_GUID(), rankId);
return 0;
}
/**
* Removes the specified [Player] from the [Guild].
*
* @param [Player] player : the [Player] to be removed from the guild
* @param bool isDisbanding : default 'false', should only be set to 'true' if the guild is triggered to disband
*/
int DeleteMember(Eluna* /*E*/, lua_State* L, Guild* guild)
{
Player* player = Eluna::CHECKOBJ<Player>(L, 2);
bool isDisbanding = Eluna::CHECKVAL<bool>(L, 3, false);
#ifndef TRINITY
guild->DelMember(player->GET_GUID(), isDisbanding);
#else
guild->DeleteMember(player->GET_GUID(), isDisbanding);
#endif
return 0;
}
/**
* Promotes/demotes the [Player] to the specified rank.
*
* @param [Player] player : the [Player] to be promoted/demoted
* @param uint8 rankId : the rank ID
*/
int SetMemberRank(Eluna* /*E*/, lua_State* L, Guild* guild)
{
Player* player = Eluna::CHECKOBJ<Player>(L, 2);
uint8 newRank = Eluna::CHECKVAL<uint8>(L, 3);
guild->ChangeMemberRank(player->GET_GUID(), newRank);
return 0;
}
#ifndef CLASSIC
// Move to Player methods
int WithdrawBankMoney(Eluna* /*E*/, lua_State* L, Guild* guild)
{
Player* player = Eluna::CHECKOBJ<Player>(L, 2);
uint32 money = Eluna::CHECKVAL<uint32>(L, 3);
#ifndef TRINITY
if (guild->GetGuildBankMoney() < money)
return 0;
guild->SetBankMoney(guild->GetGuildBankMoney() - money);
#else
guild->HandleMemberWithdrawMoney(player->GetSession(), money);
#endif
return 0;
}
// Move to Player methods
int DepositBankMoney(Eluna* /*E*/, lua_State* L, Guild* guild)
{
Player* player = Eluna::CHECKOBJ<Player>(L, 2);
uint32 money = Eluna::CHECKVAL<uint32>(L, 3);
#ifndef TRINITY
guild->SetBankMoney(guild->GetGuildBankMoney() + money);
#else
guild->HandleMemberDepositMoney(player->GetSession(), money);
#endif
return 0;
}
#endif
};
#endif

View file

@ -0,0 +1,129 @@
/*
* 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
*/
#ifndef _HOOK_HELPERS_H
#define _HOOK_HELPERS_H
#include "LuaEngine.h"
#include "ElunaUtility.h"
/*
* Sets up the stack so that event handlers can be called.
*
* Returns the number of functions that were pushed onto the stack.
*
* Use the simpler overloads for just EventBind or EntryBind instead of this overload in hooks.
*/
template<typename T>
int Eluna::SetupStack(EventBind<T>* event_bindings, EntryBind<T>* entry_bindings, UniqueBind<T>* guid_bindings, T event_id, uint32 entry, uint64 guid, uint32 instanceId, int number_of_arguments)
{
// Ensure that if `entry_bindings` is not NULL, a valid entry is supplied.
ASSERT(!entry_bindings || (entry_bindings && entry > 0));
ASSERT(number_of_arguments == this->push_counter);
// Stack: [arguments]
Push(event_id);
this->push_counter = 0;
++number_of_arguments;
// Stack: [arguments], event_id
int arguments_top = lua_gettop(L);
int first_argument_index = arguments_top - number_of_arguments + 1;
ASSERT(arguments_top >= number_of_arguments);
lua_insert(L, first_argument_index);
// Stack: event_id, [arguments]
if (event_bindings)
event_bindings->PushFuncRefs(L, (int)event_id);
if (entry_bindings)
entry_bindings->PushFuncRefs(L, (int)event_id, entry);
if (guid_bindings)
guid_bindings->PushFuncRefs(L, (int)event_id, guid, instanceId);
// Stack: event_id, [arguments], [functions]
int number_of_functions = lua_gettop(L) - arguments_top;
return number_of_functions;
}
/*
* Replace one of the arguments pushed before `SetupStack` with a new value.
*/
template<typename T>
void Eluna::ReplaceArgument(T value, uint8 index)
{
ASSERT(index < lua_gettop(L) && index > 0);
// Stack: event_id, [arguments], [functions], [results]
Eluna::Push(L, value);
// Stack: event_id, [arguments], [functions], [results], value
lua_replace(L, index + 1);
// Stack: event_id, [arguments and value], [functions], [results]
}
/*
* Call all event handlers registered to the event ID/entry combination and ignore any results.
*/
template<typename T>
void Eluna::CallAllFunctions(EventBind<T>* event_bindings, EntryBind<T>* entry_bindings, UniqueBind<T>* guid_bindings, T event_id, uint32 entry, uint64 guid, uint32 instanceId)
{
int number_of_arguments = this->push_counter;
// Stack: [arguments]
int number_of_functions = SetupStack(event_bindings, entry_bindings, guid_bindings, event_id, entry, guid, instanceId, number_of_arguments);
// Stack: event_id, [arguments], [functions]
while (number_of_functions > 0)
{
CallOneFunction(number_of_functions, number_of_arguments, 0);
--number_of_functions;
// Stack: event_id, [arguments], [functions - 1]
}
// Stack: event_id, [arguments]
CleanUpStack(number_of_arguments);
// Stack: (empty)
}
/*
* Call all event handlers registered to the event ID/entry combination,
* and returns `default_value` if ALL event handlers returned `default_value`,
* otherwise returns the opposite of `default_value`.
*/
template<typename T>
bool Eluna::CallAllFunctionsBool(EventBind<T>* event_bindings, EntryBind<T>* entry_bindings, UniqueBind<T>* guid_bindings, T event_id, uint32 entry, uint64 guid, uint32 instanceId, bool default_value)
{
bool result = default_value;
// Note: number_of_arguments here does not count in eventID, which is pushed in SetupStack
int number_of_arguments = this->push_counter;
// Stack: [arguments]
int number_of_functions = SetupStack(event_bindings, entry_bindings, guid_bindings, event_id, entry, guid, instanceId, number_of_arguments);
// Stack: event_id, [arguments], [functions]
while (number_of_functions > 0)
{
int r = CallOneFunction(number_of_functions, number_of_arguments, 1);
--number_of_functions;
// Stack: event_id, [arguments], [functions - 1], result
if (lua_isboolean(L, r) && (lua_toboolean(L, r) == 1) != default_value)
result = !default_value;
lua_pop(L, 1);
// Stack: event_id, [arguments], [functions - 1]
}
// Stack: event_id, [arguments]
CleanUpStack(number_of_arguments);
// Stack: (empty)
return result;
}
#endif // _HOOK_HELPERS_H

337
src/modules/Eluna/Hooks.h Normal file
View file

@ -0,0 +1,337 @@
/*
* 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
*/
#ifndef _HOOKS_H
#define _HOOKS_H
/*
* A hook should be written in one of the following forms:
*
* A. If results will be IGNORED:
*
* // Return early if there are no bindings.
* if (!WhateverBindings->HasEvents(SOME_EVENT_TYPE))
* return;
*
* // Lock out any other threads.
* LOCK_ELUNA;
*
* // Push extra arguments, if any.
* Push(a);
* Push(b);
* Push(c);
*
* // Call all event handlers.
* CallAllFunctions(WhateverBindings, SOME_EVENT_TYPE);
*
*
* B. If results will be USED:
*
* // Return early if there are no bindings.
* if (!WhateverBindings->HasEvents(SOME_EVENT_TYPE))
* return;
*
* // Lock out any other threads.
* LOCK_ELUNA;
*
* // Push extra arguments, if any.
* Push(a);
* Push(b);
* Push(c);
*
* // Setup the stack and get the number of functions pushed.
* // Last argument is 3 because we did 3 Pushes.
* int n = SetupStack(WhateverBindings, SOME_EVENT_TYPE, 3);
*
* // Call each event handler in order and check results.
* while (n > 0)
* {
* // Call an event handler and decrement the function counter afterward.
* // Second-last argument is 3 because we did 3 Pushes.
* // Last argument is 2 because we want 2 results.
* int r = CallOneFunction(n--, 3, 2);
*
* // Results can be popped using `r`.
* int first = CHECKVAL<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);
*/
namespace Hooks
{
enum RegisterTypes
{
REGTYPE_PACKET,
REGTYPE_SERVER,
REGTYPE_PLAYER,
REGTYPE_GUILD,
REGTYPE_GROUP,
REGTYPE_CREATURE,
REGTYPE_VEHICLE,
REGTYPE_CREATURE_GOSSIP,
REGTYPE_GAMEOBJECT,
REGTYPE_GAMEOBJECT_GOSSIP,
REGTYPE_ITEM,
REGTYPE_ITEM_GOSSIP,
REGTYPE_PLAYER_GOSSIP,
REGTYPE_BG,
REGTYPE_COUNT
};
enum PacketEvents
{
PACKET_EVENT_ON_PACKET_RECEIVE = 5, // (event, packet, player) - Player only if accessible. Can return false, newPacket
PACKET_EVENT_ON_PACKET_RECEIVE_UNKNOWN = 6, // Not Implemented
PACKET_EVENT_ON_PACKET_SEND = 7, // (event, packet, player) - Player only if accessible. Can return false, newPacket
PACKET_EVENT_COUNT
};
enum ServerEvents
{
// Server
SERVER_EVENT_ON_NETWORK_START = 1, // Not Implemented
SERVER_EVENT_ON_NETWORK_STOP = 2, // Not Implemented
SERVER_EVENT_ON_SOCKET_OPEN = 3, // Not Implemented
SERVER_EVENT_ON_SOCKET_CLOSE = 4, // Not Implemented
SERVER_EVENT_ON_PACKET_RECEIVE = 5, // (event, packet, player) - Player only if accessible. Can return false, newPacket
SERVER_EVENT_ON_PACKET_RECEIVE_UNKNOWN = 6, // Not Implemented
SERVER_EVENT_ON_PACKET_SEND = 7, // (event, packet, player) - Player only if accessible. Can return false, newPacket
// World
WORLD_EVENT_ON_OPEN_STATE_CHANGE = 8, // (event, open) - Needs core support on Mangos
WORLD_EVENT_ON_CONFIG_LOAD = 9, // (event, reload)
// UNUSED = 10,
WORLD_EVENT_ON_SHUTDOWN_INIT = 11, // (event, code, mask)
WORLD_EVENT_ON_SHUTDOWN_CANCEL = 12, // (event)
WORLD_EVENT_ON_UPDATE = 13, // (event, diff)
WORLD_EVENT_ON_STARTUP = 14, // (event)
WORLD_EVENT_ON_SHUTDOWN = 15, // (event)
// Eluna
ELUNA_EVENT_ON_LUA_STATE_CLOSE = 16, // (event) - triggers just before shutting down eluna (on shutdown and restart)
// Map
MAP_EVENT_ON_CREATE = 17, // (event, map)
MAP_EVENT_ON_DESTROY = 18, // (event, map)
MAP_EVENT_ON_GRID_LOAD = 19, // Not Implemented
MAP_EVENT_ON_GRID_UNLOAD = 20, // Not Implemented
MAP_EVENT_ON_PLAYER_ENTER = 21, // (event, map, player)
MAP_EVENT_ON_PLAYER_LEAVE = 22, // (event, map, player)
MAP_EVENT_ON_UPDATE = 23, // (event, map, diff)
// Area trigger
TRIGGER_EVENT_ON_TRIGGER = 24, // (event, player, triggerId) - Can return true
// Weather
WEATHER_EVENT_ON_CHANGE = 25, // (event, zoneId, state, grade)
// Auction house
AUCTION_EVENT_ON_ADD = 26, // (event, auctionId, owner, item, expireTime, buyout, startBid, currentBid, bidderGUIDLow)
AUCTION_EVENT_ON_REMOVE = 27, // (event, auctionId, owner, item, expireTime, buyout, startBid, currentBid, bidderGUIDLow)
AUCTION_EVENT_ON_SUCCESSFUL = 28, // (event, auctionId, owner, item, expireTime, buyout, startBid, currentBid, bidderGUIDLow)
AUCTION_EVENT_ON_EXPIRE = 29, // (event, auctionId, owner, item, expireTime, buyout, startBid, currentBid, bidderGUIDLow)
// AddOns
ADDON_EVENT_ON_MESSAGE = 30, // (event, sender, type, prefix, msg, target) - target can be nil/whisper_target/guild/group/channel. Can return false
WORLD_EVENT_ON_DELETE_CREATURE = 31, // (event, creature)
WORLD_EVENT_ON_DELETE_GAMEOBJECT = 32, // (event, gameobject)
// Eluna
ELUNA_EVENT_ON_LUA_STATE_OPEN = 33, // (event) - triggers after all scripts are loaded
SERVER_EVENT_COUNT
};
enum PlayerEvents
{
PLAYER_EVENT_ON_CHARACTER_CREATE = 1, // (event, player)
PLAYER_EVENT_ON_CHARACTER_DELETE = 2, // (event, guid)
PLAYER_EVENT_ON_LOGIN = 3, // (event, player)
PLAYER_EVENT_ON_LOGOUT = 4, // (event, player)
PLAYER_EVENT_ON_SPELL_CAST = 5, // (event, player, spell, skipCheck)
PLAYER_EVENT_ON_KILL_PLAYER = 6, // (event, killer, killed)
PLAYER_EVENT_ON_KILL_CREATURE = 7, // (event, killer, killed)
PLAYER_EVENT_ON_KILLED_BY_CREATURE = 8, // (event, killer, killed)
PLAYER_EVENT_ON_DUEL_REQUEST = 9, // (event, target, challenger)
PLAYER_EVENT_ON_DUEL_START = 10, // (event, player1, player2)
PLAYER_EVENT_ON_DUEL_END = 11, // (event, winner, loser, type)
PLAYER_EVENT_ON_GIVE_XP = 12, // (event, player, amount, victim) - Can return new XP amount
PLAYER_EVENT_ON_LEVEL_CHANGE = 13, // (event, player, oldLevel)
PLAYER_EVENT_ON_MONEY_CHANGE = 14, // (event, player, amount) - Can return new money amount
PLAYER_EVENT_ON_REPUTATION_CHANGE = 15, // (event, player, factionId, standing, incremental) - Can return new standing
PLAYER_EVENT_ON_TALENTS_CHANGE = 16, // (event, player, points)
PLAYER_EVENT_ON_TALENTS_RESET = 17, // (event, player, noCost)
PLAYER_EVENT_ON_CHAT = 18, // (event, player, msg, Type, lang) - Can return false, newMessage
PLAYER_EVENT_ON_WHISPER = 19, // (event, player, msg, Type, lang, receiver) - Can return false, newMessage
PLAYER_EVENT_ON_GROUP_CHAT = 20, // (event, player, msg, Type, lang, group) - Can return false, newMessage
PLAYER_EVENT_ON_GUILD_CHAT = 21, // (event, player, msg, Type, lang, guild) - Can return false, newMessage
PLAYER_EVENT_ON_CHANNEL_CHAT = 22, // (event, player, msg, Type, lang, channel) - Can return false, newMessage
PLAYER_EVENT_ON_EMOTE = 23, // (event, player, emote) - Not triggered on any known emote
PLAYER_EVENT_ON_TEXT_EMOTE = 24, // (event, player, textEmote, emoteNum, guid)
PLAYER_EVENT_ON_SAVE = 25, // (event, player)
PLAYER_EVENT_ON_BIND_TO_INSTANCE = 26, // (event, player, difficulty, mapid, permanent)
PLAYER_EVENT_ON_UPDATE_ZONE = 27, // (event, player, newZone, newArea)
PLAYER_EVENT_ON_MAP_CHANGE = 28, // (event, player)
// Custom
PLAYER_EVENT_ON_EQUIP = 29, // (event, player, item, bag, slot)
PLAYER_EVENT_ON_FIRST_LOGIN = 30, // (event, player)
PLAYER_EVENT_ON_CAN_USE_ITEM = 31, // (event, player, itemEntry) - Can return InventoryResult
PLAYER_EVENT_ON_LOOT_ITEM = 32, // (event, player, item, count)
PLAYER_EVENT_ON_ENTER_COMBAT = 33, // (event, player, enemy)
PLAYER_EVENT_ON_LEAVE_COMBAT = 34, // (event, player)
PLAYER_EVENT_ON_REPOP = 35, // (event, player)
PLAYER_EVENT_ON_RESURRECT = 36, // (event, player)
PLAYER_EVENT_ON_LOOT_MONEY = 37, // (event, player, amount)
PLAYER_EVENT_ON_QUEST_ABANDON = 38, // (event, player, questId)
PLAYER_EVENT_ON_LEARN_TALENTS = 39, // (event, player, talentId, talentRank, spellid)
// UNUSED = 40, // (event, player)
// UNUSED = 41, // (event, player)
PLAYER_EVENT_ON_COMMAND = 42, // (event, player, command) - player is nil if command used from console. Can return false
PLAYER_EVENT_COUNT
};
enum GuildEvents
{
// Guild
GUILD_EVENT_ON_ADD_MEMBER = 1, // (event, guild, player, rank)
GUILD_EVENT_ON_REMOVE_MEMBER = 2, // (event, guild, isDisbanding)
GUILD_EVENT_ON_MOTD_CHANGE = 3, // (event, guild, newMotd)
GUILD_EVENT_ON_INFO_CHANGE = 4, // (event, guild, newInfo)
GUILD_EVENT_ON_CREATE = 5, // (event, guild, leader, name) // Not on TC
GUILD_EVENT_ON_DISBAND = 6, // (event, guild)
GUILD_EVENT_ON_MONEY_WITHDRAW = 7, // (event, guild, player, amount, isRepair) - Can return new money amount
GUILD_EVENT_ON_MONEY_DEPOSIT = 8, // (event, guild, player, amount) - Can return new money amount
GUILD_EVENT_ON_ITEM_MOVE = 9, // (event, guild, player, item, isSrcBank, srcContainer, srcSlotId, isDestBank, destContainer, destSlotId) // TODO
GUILD_EVENT_ON_EVENT = 10, // (event, guild, eventType, plrGUIDLow1, plrGUIDLow2, newRank) // TODO
GUILD_EVENT_ON_BANK_EVENT = 11, // (event, guild, eventType, tabId, playerGUIDLow, itemOrMoney, itemStackCount, destTabId)
GUILD_EVENT_COUNT
};
enum GroupEvents
{
// Group
GROUP_EVENT_ON_MEMBER_ADD = 1, // (event, group, guid)
GROUP_EVENT_ON_MEMBER_INVITE = 2, // (event, group, guid)
GROUP_EVENT_ON_MEMBER_REMOVE = 3, // (event, group, guid, method, kicker, reason)
GROUP_EVENT_ON_LEADER_CHANGE = 4, // (event, group, newLeaderGuid, oldLeaderGuid)
GROUP_EVENT_ON_DISBAND = 5, // (event, group)
GROUP_EVENT_ON_CREATE = 6, // (event, group, leaderGuid, groupType)
GROUP_EVENT_COUNT
};
enum VehicleEvents
{
VEHICLE_EVENT_ON_INSTALL = 1, // (event, vehicle)
VEHICLE_EVENT_ON_UNINSTALL = 2, // (event, vehicle)
// UNUSED = 3, // (event, vehicle)
VEHICLE_EVENT_ON_INSTALL_ACCESSORY = 4, // (event, vehicle, creature)
VEHICLE_EVENT_ON_ADD_PASSENGER = 5, // (event, vehicle, unit, seatId)
VEHICLE_EVENT_ON_REMOVE_PASSENGER = 6, // (event, vehicle, unit)
VEHICLE_EVENT_COUNT
};
enum CreatureEvents
{
CREATURE_EVENT_ON_ENTER_COMBAT = 1, // (event, creature, target) - Can return true to stop normal action
CREATURE_EVENT_ON_LEAVE_COMBAT = 2, // (event, creature) - Can return true to stop normal action
CREATURE_EVENT_ON_TARGET_DIED = 3, // (event, creature, victim) - Can return true to stop normal action
CREATURE_EVENT_ON_DIED = 4, // (event, creature, killer) - Can return true to stop normal action
CREATURE_EVENT_ON_SPAWN = 5, // (event, creature) - Can return true to stop normal action
CREATURE_EVENT_ON_REACH_WP = 6, // (event, creature, type, id) - Can return true to stop normal action
CREATURE_EVENT_ON_AIUPDATE = 7, // (event, creature, diff) - Can return true to stop normal action
CREATURE_EVENT_ON_RECEIVE_EMOTE = 8, // (event, creature, player, emoteid) - Can return true to stop normal action
CREATURE_EVENT_ON_DAMAGE_TAKEN = 9, // (event, creature, attacker, damage) - Can return new damage
CREATURE_EVENT_ON_PRE_COMBAT = 10, // (event, creature, target) - Can return true to stop normal action
CREATURE_EVENT_ON_ATTACKED_AT = 11, // (event, creature, attacker) - Can return true to stop normal action
CREATURE_EVENT_ON_OWNER_ATTACKED = 12, // (event, creature, target) - Can return true to stop normal action // Not on mangos
CREATURE_EVENT_ON_OWNER_ATTACKED_AT = 13, // (event, creature, attacker) - Can return true to stop normal action // Not on mangos
CREATURE_EVENT_ON_HIT_BY_SPELL = 14, // (event, creature, caster, spellid) - Can return true to stop normal action
CREATURE_EVENT_ON_SPELL_HIT_TARGET = 15, // (event, creature, target, spellid) - Can return true to stop normal action
// UNUSED = 16, // (event, creature)
// UNUSED = 17, // (event, creature)
// UNUSED = 18, // (event, creature)
CREATURE_EVENT_ON_JUST_SUMMONED_CREATURE = 19, // (event, creature, summon) - Can return true to stop normal action
CREATURE_EVENT_ON_SUMMONED_CREATURE_DESPAWN = 20, // (event, creature, summon) - Can return true to stop normal action
CREATURE_EVENT_ON_SUMMONED_CREATURE_DIED = 21, // (event, creature, summon, killer) - Can return true to stop normal action // Not on mangos
CREATURE_EVENT_ON_SUMMONED = 22, // (event, creature, summoner) - Can return true to stop normal action
CREATURE_EVENT_ON_RESET = 23, // (event, creature)
CREATURE_EVENT_ON_REACH_HOME = 24, // (event, creature) - Can return true to stop normal action
// UNUSED = 25, // (event, creature)
CREATURE_EVENT_ON_CORPSE_REMOVED = 26, // (event, creature, respawndelay) - Can return true, newRespawnDelay
CREATURE_EVENT_ON_MOVE_IN_LOS = 27, // (event, creature, unit) - Can return true to stop normal action. Does not actually check LOS, just uses the sight range
// UNUSED = 28, // (event, creature)
// UNUSED = 29, // (event, creature)
CREATURE_EVENT_ON_DUMMY_EFFECT = 30, // (event, caster, spellid, effindex, creature) - Can return true
CREATURE_EVENT_ON_QUEST_ACCEPT = 31, // (event, player, creature, quest) - Can return true
// UNUSED = 32, // (event, creature)
// UNUSED = 33, // (event, creature)
CREATURE_EVENT_ON_QUEST_REWARD = 34, // (event, player, creature, quest, opt) - Can return true
CREATURE_EVENT_ON_DIALOG_STATUS = 35, // (event, player, creature)
CREATURE_EVENT_ON_ADD = 36, // (event, creature)
CREATURE_EVENT_ON_REMOVE = 37, // (event, creature)
CREATURE_EVENT_COUNT
};
enum GameObjectEvents
{
GAMEOBJECT_EVENT_ON_AIUPDATE = 1, // (event, go, diff)
GAMEOBJECT_EVENT_ON_SPAWN = 2, // (event, go)
GAMEOBJECT_EVENT_ON_DUMMY_EFFECT = 3, // (event, caster, spellid, effindex, go) - Can return true
GAMEOBJECT_EVENT_ON_QUEST_ACCEPT = 4, // (event, player, go, quest) - Can return true
GAMEOBJECT_EVENT_ON_QUEST_REWARD = 5, // (event, player, go, quest, opt) - Can return true
GAMEOBJECT_EVENT_ON_DIALOG_STATUS = 6, // (event, player, go)
GAMEOBJECT_EVENT_ON_DESTROYED = 7, // (event, go, player)
GAMEOBJECT_EVENT_ON_DAMAGED = 8, // (event, go, player)
GAMEOBJECT_EVENT_ON_LOOT_STATE_CHANGE = 9, // (event, go, state)
GAMEOBJECT_EVENT_ON_GO_STATE_CHANGED = 10, // (event, go, state)
// UNUSED = 11, // (event, gameobject)
GAMEOBJECT_EVENT_ON_ADD = 12, // (event, gameobject)
GAMEOBJECT_EVENT_ON_REMOVE = 13, // (event, gameobject)
GAMEOBJECT_EVENT_ON_USE = 14, // (event, go, player)
GAMEOBJECT_EVENT_COUNT
};
enum ItemEvents
{
ITEM_EVENT_ON_DUMMY_EFFECT = 1, // (event, caster, spellid, effindex, item) - Can return true
ITEM_EVENT_ON_USE = 2, // (event, player, item, target) - Can return false to stop the spell casting
ITEM_EVENT_ON_QUEST_ACCEPT = 3, // (event, player, item, quest) - Can return true
ITEM_EVENT_ON_EXPIRE = 4, // (event, player, itemid) - Can return true
ITEM_EVENT_ON_REMOVE = 5, // (event, player, item) - Can return true
ITEM_EVENT_COUNT
};
enum GossipEvents
{
GOSSIP_EVENT_ON_HELLO = 1, // (event, player, object) - Object is the Creature/GameObject/Item. Can return false to do default action. For item gossip can return false to stop spell casting.
GOSSIP_EVENT_ON_SELECT = 2, // (event, player, object, sender, intid, code, menu_id) - Object is the Creature/GameObject/Item/Player, menu_id is only for player gossip. Can return false to do default action.
GOSSIP_EVENT_COUNT
};
enum BGEvents
{
BG_EVENT_ON_START = 1, // (event, bg, bgId, instanceId) - Needs to be added to TC
BG_EVENT_ON_END = 2, // (event, bg, bgId, instanceId, winner) - Needs to be added to TC
BG_EVENT_ON_CREATE = 3, // (event, bg, bgId, instanceId) - Needs to be added to TC
BG_EVENT_ON_PRE_DESTROY = 4, // (event, bg, bgId, instanceId) - Needs to be added to TC
BG_EVENT_COUNT
};
};
#endif // _HOOKS_H

View file

@ -0,0 +1,145 @@
/*
* 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
*/
#ifndef _ITEM_HOOKS_H
#define _ITEM_HOOKS_H
#include "Hooks.h"
#include "HookHelpers.h"
#include "LuaEngine.h"
#include "ElunaBinding.h"
#include "ElunaIncludes.h"
#include "ElunaTemplate.h"
using namespace Hooks;
bool Eluna::OnDummyEffect(Unit* pCaster, uint32 spellId, SpellEffIndex effIndex, Item* pTarget)
{
if (!ItemEventBindings->HasEvents(ITEM_EVENT_ON_DUMMY_EFFECT, pTarget->GetEntry()))
return false;
LOCK_ELUNA;
Push(pCaster);
Push(spellId);
Push(effIndex);
Push(pTarget);
return CallAllFunctionsBool(ItemEventBindings, ITEM_EVENT_ON_DUMMY_EFFECT, pTarget->GetEntry());
}
bool Eluna::OnQuestAccept(Player* pPlayer, Item* pItem, Quest const* pQuest)
{
if (!ItemEventBindings->HasEvents(ITEM_EVENT_ON_QUEST_ACCEPT, pItem->GetEntry()))
return false;
LOCK_ELUNA;
Push(pPlayer);
Push(pItem);
Push(pQuest);
return CallAllFunctionsBool(ItemEventBindings, ITEM_EVENT_ON_QUEST_ACCEPT, pItem->GetEntry());
}
bool Eluna::OnUse(Player* pPlayer, Item* pItem, SpellCastTargets const& targets)
{
ObjectGuid guid = pItem->GET_GUID();
bool castSpell = true;
if (!OnItemUse(pPlayer, pItem, targets))
castSpell = false;
pItem = pPlayer->GetItemByGuid(guid);
if (pItem)
{
if (!OnItemGossip(pPlayer, pItem, targets))
castSpell = false;
pItem = pPlayer->GetItemByGuid(guid);
}
if (pItem && castSpell)
return true;
// Send equip error that shows no message
// This is a hack fix to stop spell casting visual bug when a spell is not cast on use
WorldPacket data(SMSG_INVENTORY_CHANGE_FAILURE, 18);
data << uint8(59); // EQUIP_ERR_NONE / EQUIP_ERR_CANT_BE_DISENCHANTED
data << ObjectGuid(guid);
data << ObjectGuid(uint64(0));
data << uint8(0);
pPlayer->GetSession()->SendPacket(&data);
return false;
}
bool Eluna::OnItemUse(Player* pPlayer, Item* pItem, SpellCastTargets const& targets)
{
if (!ItemEventBindings->HasEvents(ITEM_EVENT_ON_USE, pItem->GetEntry()))
return true;
LOCK_ELUNA;
Push(pPlayer);
Push(pItem);
#ifndef TRINITY
if (GameObject* target = targets.getGOTarget())
Push(target);
else if (Item* target = targets.getItemTarget())
Push(target);
else if (Corpse* target = pPlayer->GetMap()->GetCorpse(targets.getCorpseTargetGuid()))
Push(target);
else if (Unit* target = targets.getUnitTarget())
Push(target);
else
Push();
#else
if (GameObject* target = targets.GetGOTarget())
Push(target);
else if (Item* target = targets.GetItemTarget())
Push(target);
else if (Corpse* target = targets.GetCorpseTarget())
Push(target);
else if (Unit* target = targets.GetUnitTarget())
Push(target);
else if (WorldObject* target = targets.GetObjectTarget())
Push(target);
else
Push();
#endif
return CallAllFunctionsBool(ItemEventBindings, ITEM_EVENT_ON_USE, pItem->GetEntry(), true);
}
bool Eluna::OnItemGossip(Player* pPlayer, Item* pItem, SpellCastTargets const& /*targets*/)
{
if (!ItemGossipBindings->HasEvents(GOSSIP_EVENT_ON_HELLO, pItem->GetEntry()))
return true;
LOCK_ELUNA;
pPlayer->PlayerTalkClass->ClearMenus();
Push(pPlayer);
Push(pItem);
return CallAllFunctionsBool(ItemGossipBindings, GOSSIP_EVENT_ON_HELLO, pItem->GetEntry(), true);
}
bool Eluna::OnExpire(Player* pPlayer, ItemTemplate const* pProto)
{
if (!ItemEventBindings->HasEvents(ITEM_EVENT_ON_EXPIRE, pProto->ItemId))
return false;
LOCK_ELUNA;
Push(pPlayer);
Push(pProto->ItemId);
return CallAllFunctionsBool(ItemEventBindings, ITEM_EVENT_ON_EXPIRE, pProto->ItemId);
}
bool Eluna::OnRemove(Player* pPlayer, Item* item)
{
if (!ItemEventBindings->HasEvents(ITEM_EVENT_ON_REMOVE, item->GetEntry()))
return false;
LOCK_ELUNA;
Push(pPlayer);
Push(item);
return CallAllFunctionsBool(ItemEventBindings, ITEM_EVENT_ON_REMOVE, item->GetEntry());
}
#endif // _ITEM_HOOKS_H

View file

@ -0,0 +1,753 @@
/*
* 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
*/
#ifndef ITEMMETHODS_H
#define ITEMMETHODS_H
namespace LuaItem
{
/* BOOLEAN */
/**
* Returns 'true' if the [Item] is soulbound, 'false' otherwise
*
* @return bool isSoulBound
*/
int IsSoulBound(Eluna* /*E*/, lua_State* L, Item* item)
{
Eluna::Push(L, item->IsSoulBound());
return 1;
}
#if (!defined(TBC) && !defined(CLASSIC))
/**
* Returns 'true' if the [Item] is account bound, 'false' otherwise
*
* @return bool isAccountBound
*/
int IsBoundAccountWide(Eluna* /*E*/, lua_State* L, Item* item)
{
Eluna::Push(L, item->IsBoundAccountWide());
return 1;
}
#endif
/**
* Returns 'true' if the [Item] is bound to a [Player] by an enchant, 'false' otehrwise
*
* @return bool isBoundByEnchant
*/
int IsBoundByEnchant(Eluna* /*E*/, lua_State* L, Item* item)
{
Eluna::Push(L, item->IsBoundByEnchant());
return 1;
}
/**
* Returns 'true' if the [Item] is not bound to the [Player] specified, 'false' otherwise
*
* @param [Player] player : the [Player] object to check the item against
* @return bool isNotBound
*/
int IsNotBoundToPlayer(Eluna* /*E*/, lua_State* L, Item* item)
{
Player* player = Eluna::CHECKOBJ<Player>(L, 2);
Eluna::Push(L, item->IsBindedNotWith(player));
return 1;
}
/**
* Returns 'true' if the [Item] is locked, 'false' otherwise
*
* @return bool isLocked
*/
int IsLocked(Eluna* /*E*/, lua_State* L, Item* item)
{
Eluna::Push(L, item->IsLocked());
return 1;
}
/**
* Returns 'true' if the [Item] is a bag, 'false' otherwise
*
* @return bool isBag
*/
int IsBag(Eluna* /*E*/, lua_State* L, Item* item)
{
Eluna::Push(L, item->IsBag());
return 1;
}
#ifndef CLASSIC
/**
* Returns 'true' if the [Item] is a currency token, 'false' otherwise
*
* @return bool isCurrencyToken
*/
int IsCurrencyToken(Eluna* /*E*/, lua_State* L, Item* item)
{
Eluna::Push(L, item->IsCurrencyToken());
return 1;
}
#endif
/**
* Returns 'true' if the [Item] is a not an empty bag, 'false' otherwise
*
* @return bool isNotEmptyBag
*/
int IsNotEmptyBag(Eluna* /*E*/, lua_State* L, Item* item)
{
Eluna::Push(L, item->IsNotEmptyBag());
return 1;
}
/**
* Returns 'true' if the [Item] is broken, 'false' otherwise
*
* @return bool isBroken
*/
int IsBroken(Eluna* /*E*/, lua_State* L, Item* item)
{
Eluna::Push(L, item->IsBroken());
return 1;
}
/**
* Returns 'true' if the [Item] can be traded, 'false' otherwise
*
* @return bool isTradeable
*/
int CanBeTraded(Eluna* /*E*/, lua_State* L, Item* item)
{
#if (defined(TBC) || defined(CLASSIC))
Eluna::Push(L, item->CanBeTraded());
#else
bool mail = Eluna::CHECKVAL<bool>(L, 2, false);
Eluna::Push(L, item->CanBeTraded(mail));
#endif
return 1;
}
/**
* Returns 'true' if the [Item] is currently in a trade window, 'false' otherwise
*
* @return bool isInTrade
*/
int IsInTrade(Eluna* /*E*/, lua_State* L, Item* item)
{
Eluna::Push(L, item->IsInTrade());
return 1;
}
/**
* Returns 'true' if the [Item] is currently in a bag, 'false' otherwise
*
* @return bool isInBag
*/
int IsInBag(Eluna* /*E*/, lua_State* L, Item* item)
{
Eluna::Push(L, item->IsInBag());
return 1;
}
/**
* Returns 'true' if the [Item] is currently equipped, 'false' otherwise
*
* @return bool isEquipped
*/
int IsEquipped(Eluna* /*E*/, lua_State* L, Item* item)
{
Eluna::Push(L, item->IsEquipped());
return 1;
}
/**
* Returns 'true' if the [Item] has the [Quest] specified tied to it, 'false' otherwise
*
* @param uint32 questId : the [Quest] id to be checked
* @return bool hasQuest
*/
int HasQuest(Eluna* /*E*/, lua_State* L, Item* item)
{
uint32 quest = Eluna::CHECKVAL<uint32>(L, 2);
#ifndef TRINITY
Eluna::Push(L, item->HasQuest(quest));
#else
Eluna::Push(L, item->hasQuest(quest));
#endif
return 1;
}
/**
* Returns 'true' if the [Item] is a potion, 'false' otherwise
*
* @return bool isPotion
*/
int IsPotion(Eluna* /*E*/, lua_State* L, Item* item)
{
Eluna::Push(L, item->IsPotion());
return 1;
}
#ifndef CATA
/**
* Returns 'true' if the [Item] is a weapon vellum, 'false' otherwise
*
* @return bool isWeaponVellum
*/
int IsWeaponVellum(Eluna* /*E*/, lua_State* L, Item* item)
{
Eluna::Push(L, item->IsWeaponVellum());
return 1;
}
/**
* Returns 'true' if the [Item] is an armor vellum, 'false' otherwise
*
* @return bool isArmorVellum
*/
int IsArmorVellum(Eluna* /*E*/, lua_State* L, Item* item)
{
Eluna::Push(L, item->IsArmorVellum());
return 1;
}
#endif
/**
* Returns 'true' if the [Item] is a conjured consumable, 'false' otherwise
*
* @return bool isConjuredConsumable
*/
int IsConjuredConsumable(Eluna* /*E*/, lua_State* L, Item* item)
{
Eluna::Push(L, item->IsConjuredConsumable());
return 1;
}
/*
* int IsRefundExpired(Eluna* E, lua_State* L, Item* item)// TODO: Implement core support
* {
* Eluna::Push(L, item->IsRefundExpired());
* return 1;
* }
*/
/* GETTERS */
/**
* Returns the chat link of the [Item]
*
* <pre>
* enum LocaleConstant
* {
* LOCALE_enUS = 0,
* LOCALE_koKR = 1,
* LOCALE_frFR = 2,
* LOCALE_deDE = 3,
* LOCALE_zhCN = 4,
* LOCALE_zhTW = 5,
* LOCALE_esES = 6,
* LOCALE_esMX = 7,
* LOCALE_ruRU = 8
* };
* </pre>
*
* @param [LocaleConstant] locale = DEFAULT_LOCALE : locale to return the [Item]'s name in
* @return string itemLink
*/
int GetItemLink(Eluna* /*E*/, lua_State* L, Item* item)
{
uint8 locale = Eluna::CHECKVAL<uint8>(L, 2, DEFAULT_LOCALE);
if (locale >= TOTAL_LOCALES)
return luaL_argerror(L, 2, "valid LocaleConstant expected");
const ItemTemplate* temp = item->GetTemplate();
std::string name = temp->Name1;
if (ItemLocale const* il = eObjectMgr->GetItemLocale(temp->ItemId))
ObjectMgr::GetLocaleString(il->Name, locale, name);
#ifndef CLASSIC
if (int32 itemRandPropId = item->GetItemRandomPropertyId())
{
#ifdef CATA
char* suffix = NULL;
#else
char* const* suffix = NULL;
#endif
if (itemRandPropId < 0)
{
const ItemRandomSuffixEntry* itemRandEntry = sItemRandomSuffixStore.LookupEntry(-item->GetItemRandomPropertyId());
if (itemRandEntry)
suffix = itemRandEntry->nameSuffix;
}
else
{
const ItemRandomPropertiesEntry* itemRandEntry = sItemRandomPropertiesStore.LookupEntry(item->GetItemRandomPropertyId());
if (itemRandEntry)
suffix = itemRandEntry->nameSuffix;
}
if (suffix)
{
//std::string test(suffix[(name != temp->Name1) ? loc_idx : DEFAULT_LOCALE]);
//if (!test.empty())
//{
name += ' ';
name += suffix[(name != temp->Name1) ? locale : uint8(DEFAULT_LOCALE)];
/*}*/
}
}
#endif
std::ostringstream oss;
oss << "|c" << std::hex << ItemQualityColors[temp->Quality] << std::dec <<
"|Hitem:" << temp->ItemId << ":" <<
item->GetEnchantmentId(PERM_ENCHANTMENT_SLOT) << ":" <<
#ifndef CLASSIC
item->GetEnchantmentId(SOCK_ENCHANTMENT_SLOT) << ":" <<
item->GetEnchantmentId(SOCK_ENCHANTMENT_SLOT_2) << ":" <<
item->GetEnchantmentId(SOCK_ENCHANTMENT_SLOT_3) << ":" <<
item->GetEnchantmentId(BONUS_ENCHANTMENT_SLOT) << ":" <<
#endif
item->GetItemRandomPropertyId() << ":" << item->GetItemSuffixFactor() << ":" <<
(uint32)item->GetOwner()->getLevel() << "|h[" << name << "]|h|r";
Eluna::Push(L, oss.str());
return 1;
}
int GetOwnerGUID(Eluna* /*E*/, lua_State* L, Item* item)
{
#ifndef TRINITY
Eluna::Push(L, item->GetOwnerGuid());
#else
Eluna::Push(L, item->GetOwnerGUID());
#endif
return 1;
}
/**
* Returns the [Player] who currently owns the [Item]
*
* @return [Player] player : the [Player] who owns the [Item]
*/
int GetOwner(Eluna* /*E*/, lua_State* L, Item* item)
{
Eluna::Push(L, item->GetOwner());
return 1;
}
/**
* Returns the [Item]s stack count
*
* @return uint32 count
*/
int GetCount(Eluna* /*E*/, lua_State* L, Item* item)
{
Eluna::Push(L, item->GetCount());
return 1;
}
/**
* Returns the [Item]s max stack count
*
* @return uint32 maxCount
*/
int GetMaxStackCount(Eluna* /*E*/, lua_State* L, Item* item)
{
Eluna::Push(L, item->GetMaxStackCount());
return 1;
}
/**
* Returns the [Item]s current slot
*
* @return uint8 slot
*/
int GetSlot(Eluna* /*E*/, lua_State* L, Item* item)
{
Eluna::Push(L, item->GetSlot());
return 1;
}
/**
* Returns the [Item]s current bag slot
*
* @return uint8 bagSlot
*/
int GetBagSlot(Eluna* /*E*/, lua_State* L, Item* item)
{
Eluna::Push(L, item->GetBagSlot());
return 1;
}
/**
* Returns the [Item]s enchantment ID by enchant slot specified
*
* @param [EnchantmentSlot] enchantSlot : the enchant slot specified
* @return uint32 enchantId : the id of the enchant slot specified
*/
int GetEnchantmentId(Eluna* /*E*/, lua_State* L, Item* item)
{
uint32 enchant_slot = Eluna::CHECKVAL<uint32>(L, 2);
if (enchant_slot >= MAX_INSPECTED_ENCHANTMENT_SLOT)
return luaL_argerror(L, 2, "valid EnchantmentSlot expected");
Eluna::Push(L, item->GetEnchantmentId(EnchantmentSlot(enchant_slot)));
return 1;
}
/**
* Returns the spell ID tied to the [Item] by spell index
*
* @param uint32 spellIndex : the spell index specified
* @return uint32 spellId : the id of the spell
*/
int GetSpellId(Eluna* /*E*/, lua_State* L, Item* item)
{
uint32 index = Eluna::CHECKVAL<uint32>(L, 2);
if (index >= MAX_ITEM_PROTO_SPELLS)
return luaL_argerror(L, 2, "valid SpellIndex expected");
Eluna::Push(L, item->GetTemplate()->Spells[index].SpellId);
return 1;
}
/**
* Returns the spell trigger tied to the [Item] by spell index
*
* @param uint32 spellIndex : the spell index specified
* @return uint32 spellTrigger : the spell trigger of the specified index
*/
int GetSpellTrigger(Eluna* /*E*/, lua_State* L, Item* item)
{
uint32 index = Eluna::CHECKVAL<uint32>(L, 2);
if (index >= MAX_ITEM_PROTO_SPELLS)
return luaL_argerror(L, 2, "valid SpellIndex expected");
Eluna::Push(L, item->GetTemplate()->Spells[index].SpellTrigger);
return 1;
}
/**
* Returns class of the [Item]
*
* @return uint32 class
*/
int GetClass(Eluna* /*E*/, lua_State* L, Item* item)
{
Eluna::Push(L, item->GetTemplate()->Class);
return 1;
}
/**
* Returns subclass of the [Item]
*
* @return uint32 subClass
*/
int GetSubClass(Eluna* /*E*/, lua_State* L, Item* item)
{
Eluna::Push(L, item->GetTemplate()->SubClass);
return 1;
}
/**
* Returns the name of the [Item]
*
* @return string name
*/
int GetName(Eluna* /*E*/, lua_State* L, Item* item)
{
Eluna::Push(L, item->GetTemplate()->Name1);
return 1;
}
/**
* Returns the display ID of the [Item]
*
* @return uint32 displayId
*/
int GetDisplayId(Eluna* /*E*/, lua_State* L, Item* item)
{
Eluna::Push(L, item->GetTemplate()->DisplayInfoID);
return 1;
}
/**
* Returns the quality of the [Item]
*
* @return uint32 quality
*/
int GetQuality(Eluna* /*E*/, lua_State* L, Item* item)
{
Eluna::Push(L, item->GetTemplate()->Quality);
return 1;
}
/**
* Returns the default purchase count of the [Item]
*
* @return uint32 count
*/
int GetBuyCount(Eluna* /*E*/, lua_State* L, Item* item)
{
Eluna::Push(L, item->GetTemplate()->BuyCount);
return 1;
}
/**
* Returns the purchase price of the [Item]
*
* @return uint32 price
*/
int GetBuyPrice(Eluna* /*E*/, lua_State* L, Item* item)
{
Eluna::Push(L, item->GetTemplate()->BuyPrice);
return 1;
}
/**
* Returns the sell price of the [Item]
*
* @return uint32 price
*/
int GetSellPrice(Eluna* /*E*/, lua_State* L, Item* item)
{
Eluna::Push(L, item->GetTemplate()->SellPrice);
return 1;
}
/**
* Returns the inventory type of the [Item]
*
* @return uint32 inventoryType
*/
int GetInventoryType(Eluna* /*E*/, lua_State* L, Item* item)
{
Eluna::Push(L, item->GetTemplate()->InventoryType);
return 1;
}
/**
* Returns the [Player] classes allowed to use this [Item]
*
* @return uint32 allowableClass
*/
int GetAllowableClass(Eluna* /*E*/, lua_State* L, Item* item)
{
Eluna::Push(L, item->GetTemplate()->AllowableClass);
return 1;
}
/**
* Returns the [Player] races allowed to use this [Item]
*
* @return uint32 allowableRace
*/
int GetAllowableRace(Eluna* /*E*/, lua_State* L, Item* item)
{
Eluna::Push(L, item->GetTemplate()->AllowableRace);
return 1;
}
/**
* Returns the [Item]s level
*
* @return uint32 itemLevel
*/
int GetItemLevel(Eluna* /*E*/, lua_State* L, Item* item)
{
Eluna::Push(L, item->GetTemplate()->ItemLevel);
return 1;
}
/**
* Returns the minimum level required to use this [Item]
*
* @return uint32 requiredLevel
*/
int GetRequiredLevel(Eluna* /*E*/, lua_State* L, Item* item)
{
Eluna::Push(L, item->GetTemplate()->RequiredLevel);
return 1;
}
#ifdef WOTLK
int GetStatsCount(Eluna* /*E*/, lua_State* L, Item* item)
{
Eluna::Push(L, item->GetTemplate()->StatsCount);
return 1;
}
#endif
/**
* Returns the random property ID of this [Item]
*
* @return uint32 randomPropertyId
*/
int GetRandomProperty(Eluna* /*E*/, lua_State* L, Item* item)
{
Eluna::Push(L, item->GetTemplate()->RandomProperty);
return 1;
}
#ifndef CLASSIC
int GetRandomSuffix(Eluna* /*E*/, lua_State* L, Item* item)
{
Eluna::Push(L, item->GetTemplate()->RandomSuffix);
return 1;
}
#endif
/**
* Returns the item set ID of this [Item]
*
* @return uint32 itemSetId
*/
int GetItemSet(Eluna* /*E*/, lua_State* L, Item* item)
{
Eluna::Push(L, item->GetTemplate()->ItemSet);
return 1;
}
/**
* Returns the bag size of this [Item], 0 if [Item] is not a bag
*
* @return uint32 bagSize
*/
int GetBagSize(Eluna* /*E*/, lua_State* L, Item* item)
{
if (Bag* bag = item->ToBag())
Eluna::Push(L, bag->GetBagSize());
else
Eluna::Push(L, 0);
return 1;
}
/* SETTERS */
/**
* Sets the [Player] specified as the owner of the [Item]
*
* @param [Player] player : the [Player] specified
*/
int SetOwner(Eluna* /*E*/, lua_State* L, Item* item)
{
Player* player = Eluna::CHECKOBJ<Player>(L, 2);
#ifndef TRINITY
item->SetOwnerGuid(player->GET_GUID());
#else
item->SetOwnerGUID(player->GET_GUID());
#endif
return 0;
}
/**
* Sets the binding of the [Item] to 'true' or 'false'
*
* @param bool setBinding
*/
int SetBinding(Eluna* /*E*/, lua_State* L, Item* item)
{
bool soulbound = Eluna::CHECKVAL<bool>(L, 2);
item->SetBinding(soulbound);
return 0;
}
/**
* Sets the stack count of the [Item]
*
* @param uint32 count
*/
int SetCount(Eluna* /*E*/, lua_State* L, Item* item)
{
uint32 count = Eluna::CHECKVAL<uint32>(L, 2);
item->SetCount(count);
return 0;
}
/**
* Sets the specified enchantment of the [Item] to the specified slot
*
* @param uint32 enchantId : the ID of the enchant to be applied
* @param uint32 enchantSlot : the slot for the enchant to be applied to
* @return bool enchantmentSuccess : if enchantment is successfully set to specified slot, returns 'true', otherwise 'false'
*/
int SetEnchantment(Eluna* /*E*/, lua_State* L, Item* item)
{
Player* owner = item->GetOwner();
if (!owner)
{
Eluna::Push(L, false);
return 1;
}
uint32 enchant = Eluna::CHECKVAL<uint32>(L, 2);
if (!sSpellItemEnchantmentStore.LookupEntry(enchant))
{
Eluna::Push(L, false);
return 1;
}
EnchantmentSlot slot = (EnchantmentSlot)Eluna::CHECKVAL<uint32>(L, 3);
if (slot >= MAX_INSPECTED_ENCHANTMENT_SLOT)
return luaL_argerror(L, 2, "valid EnchantmentSlot expected");
owner->ApplyEnchantment(item, slot, false);
item->SetEnchantment(slot, enchant, 0, 0);
owner->ApplyEnchantment(item, slot, true);
Eluna::Push(L, true);
return 1;
}
/* OTHER */
/**
* Removes an enchant from the [Item] by the specified slot
*
* @param uint32 enchantSlot : the slot for the enchant to be removed from
* @return bool enchantmentRemoved : if enchantment is successfully removed from specified slot, returns 'true', otherwise 'false'
*/
int ClearEnchantment(Eluna* /*E*/, lua_State* L, Item* item)
{
Player* owner = item->GetOwner();
if (!owner)
{
Eluna::Push(L, false);
return 1;
}
EnchantmentSlot slot = (EnchantmentSlot)Eluna::CHECKVAL<uint32>(L, 2);
if (slot >= MAX_INSPECTED_ENCHANTMENT_SLOT)
return luaL_argerror(L, 2, "valid EnchantmentSlot expected");
if (!item->GetEnchantmentId(slot))
{
Eluna::Push(L, false);
return 1;
}
owner->ApplyEnchantment(item, slot, false);
item->ClearEnchantment(slot);
Eluna::Push(L, true);
return 1;
}
/**
* Saves the [Item] to the database
*/
int SaveToDB(Eluna* /*E*/, lua_State* /*L*/, Item* item)
{
#ifndef TRINITY
item->SaveToDB();
#else
SQLTransaction trans = SQLTransaction(NULL);
item->SaveToDB(trans);
#endif
return 0;
}
};
#endif

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,507 @@
/*
* 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
*/
#ifndef _LUA_ENGINE_H
#define _LUA_ENGINE_H
#include "Common.h"
#include "SharedDefines.h"
#include "DBCEnums.h"
#include "Group.h"
#include "Item.h"
#ifndef TRINITY
#include "Player.h"
#endif
#include "Weather.h"
#include "World.h"
#include "Hooks.h"
extern "C"
{
#include "lua.h"
};
#ifdef TRINITY
struct ItemTemplate;
typedef BattlegroundTypeId BattleGroundTypeId;
#else
struct ItemPrototype;
typedef ItemPrototype ItemTemplate;
typedef SpellEffectIndex SpellEffIndex;
struct SpellEntry;
typedef SpellEntry SpellInfo;
#ifdef CLASSIC
typedef int Difficulty;
#endif
#endif
struct AreaTriggerEntry;
class AuctionHouseObject;
struct AuctionEntry;
#ifdef TRINITY
class Battleground;
typedef Battleground BattleGround;
#endif
class Channel;
class Corpse;
class Creature;
class CreatureAI;
class GameObject;
#ifdef TRINITY
class GameObjectAI;
#endif
class Guild;
class Group;
class Item;
class Pet;
class Player;
class Quest;
class Spell;
class SpellCastTargets;
#ifdef TRINITY
class TempSummon;
#else
class TemporarySummon;
typedef TemporarySummon TempSummon;
#endif
// class Transport;
class Unit;
class Weather;
class WorldPacket;
#ifndef CLASSIC
#ifndef TBC
#ifdef TRINITY
class Vehicle;
#else
class VehicleInfo;
typedef VehicleInfo Vehicle;
#endif
#endif
#endif
struct lua_State;
class EventMgr;
class ElunaObject;
template<typename T>
class ElunaTemplate;
template<typename T>
class EventBind;
template<typename T>
class EntryBind;
template<typename T>
class UniqueBind;
struct LuaScript
{
std::string fileext;
std::string filename;
std::string filepath;
std::string modulepath;
};
#define ELUNA_OBJECT_STORE "Eluna Object Store"
#define LOCK_ELUNA Eluna::Guard __guard(Eluna::GetLock())
class Eluna
{
public:
typedef std::list<LuaScript> ScriptList;
#ifdef TRINITY
typedef std::recursive_mutex LockType;
typedef std::lock_guard<LockType> Guard;
#else
typedef ACE_Recursive_Thread_Mutex LockType;
typedef ACE_Guard<LockType> Guard;
#endif
private:
static bool reload;
static bool initialized;
static LockType lock;
// Lua script locations
static ScriptList lua_scripts;
static ScriptList lua_extensions;
// Lua script folder path
static std::string lua_folderpath;
// lua path variable for require() function
static std::string lua_requirepath;
uint32 event_level;
// When a hook pushes arguments to be passed to event handlers
// this is used to keep track of how many arguments were pushed.
uint8 push_counter;
bool enabled;
Eluna();
~Eluna();
// Prevent copy
Eluna(Eluna const&);
Eluna& operator=(const Eluna&);
void OpenLua();
void CloseLua();
void DestroyBindStores();
void CreateBindStores();
bool ExecuteCall(int params, int res);
void InvalidateObjects();
// Use ReloadEluna() to make eluna reload
// This is called on world update to reload eluna
static void _ReloadEluna();
static void LoadScriptPaths();
static void GetScripts(std::string path);
static void AddScriptPath(std::string filename, const std::string& fullpath);
static int StackTrace(lua_State *_L);
static void Report(lua_State* _L);
// Some helpers for hooks to call event handlers.
// The bodies of the templates are in HookHelpers.h, so if you want to use them you need to #include "HookHelpers.h".
template<typename T> int SetupStack(EventBind<T>* event_bindings, EntryBind<T>* entry_bindings, UniqueBind<T>* guid_bindings, T event_id, uint32 entry, uint64 guid, uint32 instanceId, int number_of_arguments);
int CallOneFunction(int number_of_functions, int number_of_arguments, int number_of_results);
void CleanUpStack(int number_of_arguments);
template<typename T> void ReplaceArgument(T value, uint8 index);
template<typename T> void CallAllFunctions(EventBind<T>* event_bindings, EntryBind<T>* entry_bindings, UniqueBind<T>* guid_bindings, T event_id, uint32 entry, uint64 guid, uint32 instanceId);
template<typename T> bool CallAllFunctionsBool(EventBind<T>* event_bindings, EntryBind<T>* entry_bindings, UniqueBind<T>* guid_bindings, T event_id, uint32 entry, uint64 guid, uint32 instanceId, bool default_value);
// Convenient overloads for Setup. Use these in hooks instead of original.
template<typename T> int SetupStack(EventBind<T>* event_bindings, T event_id, int number_of_arguments)
{
return SetupStack(event_bindings, (EntryBind<T>*)NULL, (UniqueBind<T>*)NULL, event_id, 0, 0, 0, number_of_arguments);
}
template<typename T> int SetupStack(EntryBind<T>* entry_bindings, T event_id, uint32 entry, int number_of_arguments)
{
return SetupStack((EventBind<T>*)NULL, entry_bindings, (UniqueBind<T>*)NULL, event_id, entry, 0, 0, number_of_arguments);
}
template<typename T> int SetupStack(EntryBind<T>* entry_bindings, UniqueBind<T>* guid_bindings, T event_id, uint32 entry, uint64 guid, uint32 instanceId, int number_of_arguments)
{
return SetupStack((EventBind<T>*)NULL, entry_bindings, guid_bindings, event_id, entry, guid, instanceId, number_of_arguments);
}
// Convenient overloads for CallAllFunctions. Use these in hooks instead of original.
template<typename T> void CallAllFunctions(EventBind<T>* event_bindings, T event_id)
{
CallAllFunctions(event_bindings, (EntryBind<T>*)NULL, (UniqueBind<T>*)NULL, event_id, 0, 0, 0);
}
template<typename T> void CallAllFunctions(EntryBind<T>* entry_bindings, T event_id, uint32 entry)
{
CallAllFunctions((EventBind<T>*)NULL, entry_bindings, (UniqueBind<T>*)NULL, event_id, entry, 0, 0);
}
template<typename T> void CallAllFunctions(EntryBind<T>* entry_bindings, UniqueBind<T>* guid_bindings, T event_id, uint32 entry, uint64 guid, uint32 instanceId)
{
CallAllFunctions((EventBind<T>*)NULL, entry_bindings, guid_bindings, event_id, entry, guid, instanceId);
}
// Convenient overloads for CallAllFunctionsBool. Use these in hooks instead of original.
template<typename T> bool CallAllFunctionsBool(EventBind<T>* event_bindings, T event_id, bool default_value = false)
{
return CallAllFunctionsBool(event_bindings, (EntryBind<T>*)NULL, (UniqueBind<T>*)NULL, event_id, 0, 0, 0, default_value);
}
template<typename T> bool CallAllFunctionsBool(EntryBind<T>* entry_bindings, T event_id, uint32 entry, bool default_value = false)
{
return CallAllFunctionsBool((EventBind<T>*)NULL, entry_bindings, (UniqueBind<T>*)NULL, event_id, entry, 0, 0, default_value);
}
template<typename T> bool CallAllFunctionsBool(EntryBind<T>* entry_bindings, UniqueBind<T>* guid_bindings, T event_id, uint32 entry, uint64 guid, uint32 instanceId, bool default_value = false)
{
return CallAllFunctionsBool((EventBind<T>*)NULL, entry_bindings, guid_bindings, event_id, entry, guid, instanceId, default_value);
}
public:
static Eluna* GEluna;
lua_State* L;
EventMgr* eventMgr;
EventBind<Hooks::ServerEvents>* ServerEventBindings;
EventBind<Hooks::PlayerEvents>* PlayerEventBindings;
EventBind<Hooks::GuildEvents>* GuildEventBindings;
EventBind<Hooks::GroupEvents>* GroupEventBindings;
EventBind<Hooks::VehicleEvents>* VehicleEventBindings;
EventBind<Hooks::BGEvents>* BGEventBindings;
EntryBind<Hooks::PacketEvents>* PacketEventBindings;
EntryBind<Hooks::CreatureEvents>* CreatureEventBindings;
EntryBind<Hooks::GossipEvents>* CreatureGossipBindings;
EntryBind<Hooks::GameObjectEvents>* GameObjectEventBindings;
EntryBind<Hooks::GossipEvents>* GameObjectGossipBindings;
EntryBind<Hooks::ItemEvents>* ItemEventBindings;
EntryBind<Hooks::GossipEvents>* ItemGossipBindings;
EntryBind<Hooks::GossipEvents>* playerGossipBindings;
UniqueBind<Hooks::CreatureEvents>* CreatureUniqueBindings;
static void Initialize();
static void Uninitialize();
// This function is used to make eluna reload
static void ReloadEluna() { LOCK_ELUNA; reload = true; }
static LockType& GetLock() { return lock; };
static bool IsInitialized() { return initialized; }
// Static pushes, can be used by anything, including methods.
static void Push(lua_State* luastate); // nil
static void Push(lua_State* luastate, const long long);
static void Push(lua_State* luastate, const unsigned long long);
static void Push(lua_State* luastate, const long);
static void Push(lua_State* luastate, const unsigned long);
static void Push(lua_State* luastate, const int);
static void Push(lua_State* luastate, const unsigned int);
static void Push(lua_State* luastate, const bool);
static void Push(lua_State* luastate, const float);
static void Push(lua_State* luastate, const double);
static void Push(lua_State* luastate, const std::string&);
static void Push(lua_State* luastate, const char*);
static void Push(lua_State* luastate, Object const* obj);
static void Push(lua_State* luastate, WorldObject const* obj);
static void Push(lua_State* luastate, Unit const* unit);
static void Push(lua_State* luastate, Pet const* pet);
static void Push(lua_State* luastate, TempSummon const* summon);
template<typename T>
static void Push(lua_State* luastate, T const* ptr)
{
ElunaTemplate<T>::Push(luastate, ptr);
}
void RunScripts();
bool ShouldReload() const { return reload; }
bool IsEnabled() const { return enabled && IsInitialized(); }
bool HasLuaState() const { return L != NULL; }
int Register(lua_State* L, uint8 reg, uint32 id, uint64 guid, uint32 instanceId, uint32 evt, int func, uint32 shots, bool returnCallback);
// Non-static pushes, to be used in hooks.
// These just call the correct static version with the main thread's Lua state.
void Push() { Push(L); ++push_counter; }
void Push(const long long value) { Push(L, value); ++push_counter; }
void Push(const unsigned long long value) { Push(L, value); ++push_counter; }
void Push(const long value) { Push(L, value); ++push_counter; }
void Push(const unsigned long value) { Push(L, value); ++push_counter; }
void Push(const int value) { Push(L, value); ++push_counter; }
void Push(const unsigned int value) { Push(L, value); ++push_counter; }
void Push(const bool value) { Push(L, value); ++push_counter; }
void Push(const float value) { Push(L, value); ++push_counter; }
void Push(const double value) { Push(L, value); ++push_counter; }
void Push(const std::string& value) { Push(L, value); ++push_counter; }
void Push(const char* value) { Push(L, value); ++push_counter; }
template<typename T>
void Push(T const* ptr) { Push(L, ptr); ++push_counter; }
// Checks
template<typename T> static T CHECKVAL(lua_State* luastate, int narg);
template<typename T> static T CHECKVAL(lua_State* luastate, int narg, T def)
{
return lua_isnoneornil(luastate, narg) ? def : CHECKVAL<T>(luastate, narg);
}
template<typename T> static T* CHECKOBJ(lua_State* luastate, int narg, bool error = true)
{
return ElunaTemplate<T>::Check(luastate, narg, error);
}
static ElunaObject* CHECKTYPE(lua_State* luastate, int narg, const char *tname, bool error = true);
CreatureAI* GetAI(Creature* creature);
/* Custom */
void OnTimedEvent(int funcRef, uint32 delay, uint32 calls, WorldObject* obj);
bool OnCommand(Player* player, const char* text);
void OnWorldUpdate(uint32 diff);
void OnLootItem(Player* pPlayer, Item* pItem, uint32 count, uint64 guid);
void OnLootMoney(Player* pPlayer, uint32 amount);
void OnFirstLogin(Player* pPlayer);
void OnEquip(Player* pPlayer, Item* pItem, uint8 bag, uint8 slot);
void OnRepop(Player* pPlayer);
void OnResurrect(Player* pPlayer);
void OnQuestAbandon(Player* pPlayer, uint32 questId);
void OnLearnTalents(Player* pPlayer, uint32 talentId, uint32 talentRank, uint32 spellid);
InventoryResult OnCanUseItem(const Player* pPlayer, uint32 itemEntry);
void OnLuaStateClose();
void OnLuaStateOpen();
bool OnAddonMessage(Player* sender, uint32 type, std::string& msg, Player* receiver, Guild* guild, Group* group, Channel* channel);
/* Item */
bool OnDummyEffect(Unit* pCaster, uint32 spellId, SpellEffIndex effIndex, Item* pTarget);
bool OnQuestAccept(Player* pPlayer, Item* pItem, Quest const* pQuest);
bool OnUse(Player* pPlayer, Item* pItem, SpellCastTargets const& targets);
bool OnItemUse(Player* pPlayer, Item* pItem, SpellCastTargets const& targets);
bool OnItemGossip(Player* pPlayer, Item* pItem, SpellCastTargets const& targets);
bool OnExpire(Player* pPlayer, ItemTemplate const* pProto);
bool OnRemove(Player* pPlayer, Item* item);
void HandleGossipSelectOption(Player* pPlayer, Item* item, uint32 sender, uint32 action, const std::string& code);
/* Creature */
bool OnDummyEffect(Unit* pCaster, uint32 spellId, SpellEffIndex effIndex, Creature* pTarget);
bool OnGossipHello(Player* pPlayer, Creature* pCreature);
bool OnGossipSelect(Player* pPlayer, Creature* pCreature, uint32 sender, uint32 action);
bool OnGossipSelectCode(Player* pPlayer, Creature* pCreature, uint32 sender, uint32 action, const char* code);
bool OnQuestAccept(Player* pPlayer, Creature* pCreature, Quest const* pQuest);
bool OnQuestReward(Player* pPlayer, Creature* pCreature, Quest const* pQuest, uint32 opt);
uint32 GetDialogStatus(Player* pPlayer, Creature* pCreature);
bool OnSummoned(Creature* creature, Unit* summoner);
bool UpdateAI(Creature* me, const uint32 diff);
bool EnterCombat(Creature* me, Unit* target);
bool DamageTaken(Creature* me, Unit* attacker, uint32& damage);
bool JustDied(Creature* me, Unit* killer);
bool KilledUnit(Creature* me, Unit* victim);
bool JustSummoned(Creature* me, Creature* summon);
bool SummonedCreatureDespawn(Creature* me, Creature* summon);
bool MovementInform(Creature* me, uint32 type, uint32 id);
bool AttackStart(Creature* me, Unit* target);
bool EnterEvadeMode(Creature* me);
bool AttackedBy(Creature* me, Unit* attacker);
bool JustRespawned(Creature* me);
bool JustReachedHome(Creature* me);
bool ReceiveEmote(Creature* me, Player* player, uint32 emoteId);
bool CorpseRemoved(Creature* me, uint32& respawnDelay);
bool MoveInLineOfSight(Creature* me, Unit* who);
bool SpellHit(Creature* me, Unit* caster, SpellInfo const* spell);
bool SpellHitTarget(Creature* me, Unit* target, SpellInfo const* spell);
bool SummonedCreatureDies(Creature* me, Creature* summon, Unit* killer);
bool OwnerAttackedBy(Creature* me, Unit* attacker);
bool OwnerAttacked(Creature* me, Unit* target);
void On_Reset(Creature* me);
/* GameObject */
bool OnDummyEffect(Unit* pCaster, uint32 spellId, SpellEffIndex effIndex, GameObject* pTarget);
bool OnGameObjectUse(Player* pPlayer, GameObject* pGameObject);
bool OnGossipHello(Player* pPlayer, GameObject* pGameObject);
bool OnGossipSelect(Player* pPlayer, GameObject* pGameObject, uint32 sender, uint32 action);
bool OnGossipSelectCode(Player* pPlayer, GameObject* pGameObject, uint32 sender, uint32 action, const char* code);
bool OnQuestAccept(Player* pPlayer, GameObject* pGameObject, Quest const* pQuest);
bool OnQuestReward(Player* pPlayer, GameObject* pGameObject, Quest const* pQuest, uint32 opt);
uint32 GetDialogStatus(Player* pPlayer, GameObject* pGameObject);
#ifndef CLASSIC
#ifndef TBC
void OnDestroyed(GameObject* pGameObject, Player* pPlayer);
void OnDamaged(GameObject* pGameObject, Player* pPlayer);
#endif
#endif
void OnLootStateChanged(GameObject* pGameObject, uint32 state);
void OnGameObjectStateChanged(GameObject* pGameObject, uint32 state);
void UpdateAI(GameObject* pGameObject, uint32 diff);
void OnSpawn(GameObject* gameobject);
/* Packet */
bool OnPacketSend(WorldSession* session, WorldPacket& packet);
void OnPacketSendAny(Player* player, WorldPacket& packet, bool& result);
void OnPacketSendOne(Player* player, WorldPacket& packet, bool& result);
bool OnPacketReceive(WorldSession* session, WorldPacket& packet);
void OnPacketReceiveAny(Player* player, WorldPacket& packet, bool& result);
void OnPacketReceiveOne(Player* player, WorldPacket& packet, bool& result);
/* Player */
void OnPlayerEnterCombat(Player* pPlayer, Unit* pEnemy);
void OnPlayerLeaveCombat(Player* pPlayer);
void OnPVPKill(Player* pKiller, Player* pKilled);
void OnCreatureKill(Player* pKiller, Creature* pKilled);
void OnPlayerKilledByCreature(Creature* pKiller, Player* pKilled);
void OnLevelChanged(Player* pPlayer, uint8 oldLevel);
void OnFreeTalentPointsChanged(Player* pPlayer, uint32 newPoints);
void OnTalentsReset(Player* pPlayer, bool noCost);
void OnMoneyChanged(Player* pPlayer, int32& amount);
void OnGiveXP(Player* pPlayer, uint32& amount, Unit* pVictim);
void OnReputationChange(Player* pPlayer, uint32 factionID, int32& standing, bool incremental);
void OnDuelRequest(Player* pTarget, Player* pChallenger);
void OnDuelStart(Player* pStarter, Player* pChallenger);
void OnDuelEnd(Player* pWinner, Player* pLoser, DuelCompleteType type);
bool OnChat(Player* pPlayer, uint32 type, uint32 lang, std::string& msg);
bool OnChat(Player* pPlayer, uint32 type, uint32 lang, std::string& msg, Group* pGroup);
bool OnChat(Player* pPlayer, uint32 type, uint32 lang, std::string& msg, Guild* pGuild);
bool OnChat(Player* pPlayer, uint32 type, uint32 lang, std::string& msg, Channel* pChannel);
bool OnChat(Player* pPlayer, uint32 type, uint32 lang, std::string& msg, Player* pReceiver);
void OnEmote(Player* pPlayer, uint32 emote);
void OnTextEmote(Player* pPlayer, uint32 textEmote, uint32 emoteNum, uint64 guid);
void OnSpellCast(Player* pPlayer, Spell* pSpell, bool skipCheck);
void OnLogin(Player* pPlayer);
void OnLogout(Player* pPlayer);
void OnCreate(Player* pPlayer);
void OnDelete(uint32 guid);
void OnSave(Player* pPlayer);
void OnBindToInstance(Player* pPlayer, Difficulty difficulty, uint32 mapid, bool permanent);
void OnUpdateZone(Player* pPlayer, uint32 newZone, uint32 newArea);
void OnMapChanged(Player* pPlayer);
void HandleGossipSelectOption(Player* pPlayer, uint32 menuId, uint32 sender, uint32 action, const std::string& code);
#ifndef CLASSIC
#ifndef TBC
/* Vehicle */
void OnInstall(Vehicle* vehicle);
void OnUninstall(Vehicle* vehicle);
void OnInstallAccessory(Vehicle* vehicle, Creature* accessory);
void OnAddPassenger(Vehicle* vehicle, Unit* passenger, int8 seatId);
void OnRemovePassenger(Vehicle* vehicle, Unit* passenger);
#endif
#endif
/* AreaTrigger */
bool OnAreaTrigger(Player* pPlayer, AreaTriggerEntry const* pTrigger);
/* Weather */
void OnChange(Weather* weather, uint32 zone, WeatherState state, float grade);
/* Auction House */
void OnAdd(AuctionHouseObject* ah, AuctionEntry* entry);
void OnRemove(AuctionHouseObject* ah, AuctionEntry* entry);
void OnSuccessful(AuctionHouseObject* ah, AuctionEntry* entry);
void OnExpire(AuctionHouseObject* ah, AuctionEntry* entry);
/* Guild */
void OnAddMember(Guild* guild, Player* player, uint32 plRank);
void OnRemoveMember(Guild* guild, Player* player, bool isDisbanding);
void OnMOTDChanged(Guild* guild, const std::string& newMotd);
void OnInfoChanged(Guild* guild, const std::string& newInfo);
void OnCreate(Guild* guild, Player* leader, const std::string& name);
void OnDisband(Guild* guild);
void OnMemberWitdrawMoney(Guild* guild, Player* player, uint32& amount, bool isRepair);
void OnMemberDepositMoney(Guild* guild, Player* player, uint32& amount);
void OnItemMove(Guild* guild, Player* player, Item* pItem, bool isSrcBank, uint8 srcContainer, uint8 srcSlotId, bool isDestBank, uint8 destContainer, uint8 destSlotId);
void OnEvent(Guild* guild, uint8 eventType, uint32 playerGuid1, uint32 playerGuid2, uint8 newRank);
void OnBankEvent(Guild* guild, uint8 eventType, uint8 tabId, uint32 playerGuid, uint32 itemOrMoney, uint16 itemStackCount, uint8 destTabId);
/* Group */
void OnAddMember(Group* group, uint64 guid);
void OnInviteMember(Group* group, uint64 guid);
void OnRemoveMember(Group* group, uint64 guid, uint8 method);
void OnChangeLeader(Group* group, uint64 newLeaderGuid, uint64 oldLeaderGuid);
void OnDisband(Group* group);
void OnCreate(Group* group, uint64 leaderGuid, GroupType groupType);
/* Map */
void OnCreate(Map* map);
void OnDestroy(Map* map);
void OnPlayerEnter(Map* map, Player* player);
void OnPlayerLeave(Map* map, Player* player);
void OnUpdate(Map* map, uint32 diff);
void OnAddToWorld(Creature* creature);
void OnRemoveFromWorld(Creature* creature);
void OnAddToWorld(GameObject* gameobject);
void OnRemoveFromWorld(GameObject* gameobject);
void OnRemove(Creature* creature);
void OnRemove(GameObject* gameobject);
/* World */
void OnOpenStateChange(bool open);
void OnConfigLoad(bool reload);
void OnShutdownInitiate(ShutdownExitCode code, ShutdownMask mask);
void OnShutdownCancel();
void OnUpdate(uint32 diff);
void OnStartup();
void OnShutdown();
/* Battle Ground */
void OnBGStart(BattleGround* bg, BattleGroundTypeId bgId, uint32 instanceId);
void OnBGEnd(BattleGround* bg, BattleGroundTypeId bgId, uint32 instanceId, Team winner);
void OnBGCreate(BattleGround* bg, BattleGroundTypeId bgId, uint32 instanceId);
void OnBGDestroy(BattleGround* bg, BattleGroundTypeId bgId, uint32 instanceId);
};
template<> Unit* Eluna::CHECKOBJ<Unit>(lua_State* L, int narg, bool error);
template<> Object* Eluna::CHECKOBJ<Object>(lua_State* L, int narg, bool error);
template<> WorldObject* Eluna::CHECKOBJ<WorldObject>(lua_State* L, int narg, bool error);
template<> ElunaObject* Eluna::CHECKOBJ<ElunaObject>(lua_State* L, int narg, bool error);
#define sEluna Eluna::GEluna
#endif

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,275 @@
/*
* 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
*/
#ifndef MAPMETHODS_H
#define MAPMETHODS_H
/***
* A game map, e.g. Azeroth, Eastern Kingdoms, the Molten Core, etc.
*/
namespace LuaMap
{
#ifndef CLASSIC
/**
* Returns `true` if the [Map] is an arena [BattleGround], `false` otherwise.
*
* @return bool isArena
*/
int IsArena(Eluna* /*E*/, lua_State* L, Map* map)
{
Eluna::Push(L, map->IsBattleArena());
return 1;
}
#endif
/**
* Returns `true` if the [Map] is a non-arena [BattleGround], `false` otherwise.
*
* @return bool isBattleGround
*/
int IsBattleground(Eluna* /*E*/, lua_State* L, Map* map)
{
#ifndef TRINITY
Eluna::Push(L, map->IsBattleGround());
#else
Eluna::Push(L, map->IsBattleground());
#endif
return 1;
}
/**
* Returns `true` if the [Map] is a dungeon, `false` otherwise.
*
* @return bool isDungeon
*/
int IsDungeon(Eluna* /*E*/, lua_State* L, Map* map)
{
Eluna::Push(L, map->IsDungeon());
return 1;
}
/**
* Returns `true` if the [Map] has no [Player]s, `false` otherwise.
*
* @return bool isEmpty
*/
int IsEmpty(Eluna* /*E*/, lua_State* L, Map* map)
{
Eluna::Push(L, map->isEmpty());
return 1;
}
#ifndef CLASSIC
/**
* Returns `true` if the [Map] is a heroic, `false` otherwise.
*
* @return bool isHeroic
*/
int IsHeroic(Eluna* /*E*/, lua_State* L, Map* map)
{
Eluna::Push(L, map->IsHeroic());
return 1;
}
#endif
/**
* Returns `true` if the [Map] is a raid, `false` otherwise.
*
* @return bool isRaid
*/
int IsRaid(Eluna* /*E*/, lua_State* L, Map* map)
{
Eluna::Push(L, map->IsRaid());
return 1;
}
/**
* Returns the name of the [Map].
*
* @return string mapName
*/
int GetName(Eluna* /*E*/, lua_State* L, Map* map)
{
Eluna::Push(L, map->GetMapName());
return 1;
}
/**
* Returns the height of the [Map] at the given X and Y coordinates.
*
* In case of no height found nil is returned
*
* @param float x
* @param float y
* @return float z
*/
int GetHeight(Eluna* /*E*/, lua_State* L, Map* map)
{
float x = Eluna::CHECKVAL<float>(L, 2);
float y = Eluna::CHECKVAL<float>(L, 3);
#if (defined(TBC) || defined(CLASSIC))
float z = map->GetHeight(x, y, MAX_HEIGHT);
#else
uint32 phasemask = Eluna::CHECKVAL<uint32>(L, 4, 1);
float z = map->GetHeight(phasemask, x, y, MAX_HEIGHT);
#endif
if (z != INVALID_HEIGHT)
Eluna::Push(L, z);
return 1;
}
/**
* Returns the difficulty of the [Map].
*
* Always returns 0 if the expansion is pre-TBC.
*
* @return int32 difficulty
*/
int GetDifficulty(Eluna* /*E*/, lua_State* L, Map* map)
{
#ifndef CLASSIC
Eluna::Push(L, map->GetDifficulty());
#else
Eluna::Push(L, (Difficulty)0);
#endif
return 1;
}
/**
* Returns the instance ID of the [Map].
*
* @return uint32 instanceId
*/
int GetInstanceId(Eluna* /*E*/, lua_State* L, Map* map)
{
Eluna::Push(L, map->GetInstanceId());
return 1;
}
/**
* Returns the player count currently on the [Map] (excluding GMs).
*
* @return uint32 playerCount
*/
int GetPlayerCount(Eluna* /*E*/, lua_State* L, Map* map)
{
Eluna::Push(L, map->GetPlayersCountExceptGMs());
return 1;
}
/**
* Returns the ID of the [Map].
*
* @return uint32 mapId
*/
int GetMapId(Eluna* /*E*/, lua_State* L, Map* map)
{
Eluna::Push(L, map->GetId());
return 1;
}
/**
* Returns the area ID of the [Map] at the specified X, Y, and Z coordinates.
*
* @param float x
* @param float y
* @param float z
* @return uint32 areaId
*/
int GetAreaId(Eluna* /*E*/, lua_State* L, Map* map)
{
float x = Eluna::CHECKVAL<float>(L, 2);
float y = Eluna::CHECKVAL<float>(L, 3);
float z = Eluna::CHECKVAL<float>(L, 4);
#ifndef TRINITY
Eluna::Push(L, map->GetTerrain()->GetAreaId(x, y, z));
#else
Eluna::Push(L, map->GetAreaId(x, y, z));
#endif
return 1;
}
/**
* Returns a [WorldObject] by its GUID from the map if it is spawned.
*
* @param uint64 guid
*/
int GetWorldObject(Eluna* /*E*/, lua_State* L, Map* map)
{
uint64 guid = Eluna::CHECKVAL<uint64>(L, 2);
#ifndef TRINITY
Eluna::Push(L, map->GetWorldObject(ObjectGuid(guid)));
#else
switch (GUID_HIPART(guid))
{
case HIGHGUID_PLAYER:
Eluna::Push(L, sObjectAccessor->GetObjectInMap(ObjectGuid(guid), map, (Player*)NULL));
break;
case HIGHGUID_TRANSPORT:
case HIGHGUID_MO_TRANSPORT:
case HIGHGUID_GAMEOBJECT:
Eluna::Push(L, sObjectAccessor->GetObjectInMap(ObjectGuid(guid), map, (GameObject*)NULL));
break;
case HIGHGUID_VEHICLE:
case HIGHGUID_UNIT:
Eluna::Push(L, sObjectAccessor->GetObjectInMap(ObjectGuid(guid), map, (Creature*)NULL));
break;
case HIGHGUID_PET:
Eluna::Push(L, sObjectAccessor->GetObjectInMap(ObjectGuid(guid), map, (Pet*)NULL));
break;
case HIGHGUID_DYNAMICOBJECT:
Eluna::Push(L, sObjectAccessor->GetObjectInMap(ObjectGuid(guid), map, (DynamicObject*)NULL));
break;
case HIGHGUID_CORPSE:
Eluna::Push(L, sObjectAccessor->GetObjectInMap(ObjectGuid(guid), map, (Corpse*)NULL));
break;
default:
break;
}
#endif
return 1;
}
/**
* Sets the [Weather] type based on [WeatherType] and grade supplied.
*
* enum WeatherType
* {
* WEATHER_TYPE_FINE = 0,
* WEATHER_TYPE_RAIN = 1,
* WEATHER_TYPE_SNOW = 2,
* WEATHER_TYPE_STORM = 3,
* WEATHER_TYPE_THUNDERS = 86,
* WEATHER_TYPE_BLACKRAIN = 90
* };
*
* @param uint32 zone : id of the zone to set the weather for
* @param [WeatherType] type : the [WeatherType], see above available weather types
* @param float grade : the intensity/grade of the [Weather], ranges from 0 to 1
*/
int SetWeather(Eluna* /*E*/, lua_State* L, Map* map)
{
uint32 zoneId = Eluna::CHECKVAL<uint32>(L, 2);
uint32 weatherType = Eluna::CHECKVAL<uint32>(L, 3);
float grade = Eluna::CHECKVAL<float>(L, 4);
#if defined(TRINITY)
Weather* weather = WeatherMgr::FindWeather(zoneId);
if (!weather)
weather = WeatherMgr::AddWeather(zoneId);
if (weather)
weather->SetWeather((WeatherType)weatherType, grade);
#else
if (Weather::IsValidWeatherType(weatherType))
map->SetWeather(zoneId, (WeatherType)weatherType, grade, false);
#endif
return 0;
}
};
#endif

View file

@ -0,0 +1,458 @@
/*
* 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
*/
#ifndef OBJECTMETHODS_H
#define OBJECTMETHODS_H
/***
* A basic game object (either an [Item] or a [WorldObject]).
*
* Objects in MaNGOS/Trinity are stored an a giant block of "values".
* Subclasses of Object, like [WorldObject], extend the block with more data specific to that subclass.
* Further subclasses, like [Player], extend it even further.
*
* A detailed map of all the fields in this data block can be found in the UpdateFields.h file of your emulator
* (it varies depending on the expansion supported).
*
* The GetValue methods in this class (e.g. [Object:GetInt32Value]) provide low-level access to the data block.
* Other methods, like [Object:HasFlag] and [Object:GetScale], merely wrap the GetValue methods and provide a simpler interface.
*/
namespace LuaObject
{
/* BOOLEAN */
/**
* Returns `true` if the specified flag is set, otherwise `false`.
*
* @param uint16 index : the index of the flags data in the [Object]
* @param uint32 flag : the flag to check for in the flags data
* @return bool hasFlag
*/
int HasFlag(Eluna* /*E*/, lua_State* L, Object* obj)
{
uint16 index = Eluna::CHECKVAL<uint16>(L, 2);
uint32 flag = Eluna::CHECKVAL<uint32>(L, 3);
Eluna::Push(L, obj->HasFlag(index, flag));
return 1;
}
/**
* Returns `true` if the [Object] has been added to its [Map], otherwise `false`.
*
* @return bool inWorld
*/
int IsInWorld(Eluna* /*E*/, lua_State* L, Object* obj)
{
Eluna::Push(L, obj->IsInWorld());
return 1;
}
/* GETTERS */
/**
* Returns the data at the specified index, casted to a signed 32-bit integer.
*
* @param uint16 index
* @return int32 value
*/
int GetInt32Value(Eluna* /*E*/, lua_State* L, Object* obj)
{
uint16 index = Eluna::CHECKVAL<uint16>(L, 2);
Eluna::Push(L, obj->GetInt32Value(index));
return 1;
}
/**
* Returns the data at the specified index, casted to a unsigned 32-bit integer.
*
* @param uint16 index
* @return uint32 value
*/
int GetUInt32Value(Eluna* /*E*/, lua_State* L, Object* obj)
{
uint16 index = Eluna::CHECKVAL<uint16>(L, 2);
Eluna::Push(L, obj->GetUInt32Value(index));
return 1;
}
/**
* Returns the data at the specified index, casted to a single-precision floating point value.
*
* @param uint16 index
* @return float value
*/
int GetFloatValue(Eluna* /*E*/, lua_State* L, Object* obj)
{
uint16 index = Eluna::CHECKVAL<uint16>(L, 2);
Eluna::Push(L, obj->GetFloatValue(index));
return 1;
}
/**
* Returns the data at the specified index and offset, casted to an unsigned 8-bit integer.
*
* E.g. if you want the second byte at index 10, you would pass in 1 as the offset.
*
* @param uint16 index
* @param uint8 offset : should be 0, 1, 2, or 3
* @return uint8 value
*/
int GetByteValue(Eluna* /*E*/, lua_State* L, Object* obj)
{
uint16 index = Eluna::CHECKVAL<uint16>(L, 2);
uint8 offset = Eluna::CHECKVAL<uint8>(L, 3);
Eluna::Push(L, obj->GetByteValue(index, offset));
return 1;
}
/**
* Returns the data at the specified index and offset, casted to a signed 16-bit integer.
*
* E.g. if you want the second half-word at index 10, you would pass in 1 as the offset.
*
* @param uint16 index
* @param uint8 offset : should be 0 or 1
* @return uint16 value
*/
int GetUInt16Value(Eluna* /*E*/, lua_State* L, Object* obj)
{
uint16 index = Eluna::CHECKVAL<uint16>(L, 2);
uint8 offset = Eluna::CHECKVAL<uint8>(L, 3);
Eluna::Push(L, obj->GetUInt16Value(index, offset));
return 1;
}
/**
* Returns the scale/size of the [Object].
*
* This affects the size of a [WorldObject] in-game, but [Item]s don't have a "scale".
*
* @return float scale
*/
int GetScale(Eluna* /*E*/, lua_State* L, Object* obj)
{
Eluna::Push(L, obj->GetObjectScale());
return 1;
}
/**
* Returns the entry of the [Object].
*
* [Player]s do not have an "entry".
*
* @return uint32 entry
*/
int GetEntry(Eluna* /*E*/, lua_State* L, Object* obj)
{
Eluna::Push(L, obj->GetEntry());
return 1;
}
/**
* Returns the GUID of the [Object].
*
* GUID is an unique identifier for the object.
*
* However on MaNGOS and cMangos creatures and gameobjects inside different maps can share
* the same GUID but not on the same map.
*
* On TrinityCore this value is unique across all maps
*
* @return uint64 guid
*/
int GetGUID(Eluna* /*E*/, lua_State* L, Object* obj)
{
Eluna::Push(L, obj->GET_GUID());
return 1;
}
/**
* Returns the low-part of the [Object]'s GUID.
*
* On TrinityCore all low GUIDs are different for all objects of the same type.
* For example creatures in instances are assigned new GUIDs when the Map is created.
*
* On MaNGOS and cMaNGOS low GUIDs are unique only on the same map.
* For example creatures in instances use the same low GUID assigned for that spawn in the database.
* This is why to identify a creature you have to know the instanceId and low GUID. See [Map:GetIntstanceId]
*
* @return uint32 guidLow
*/
int GetGUIDLow(Eluna* /*E*/, lua_State* L, Object* obj)
{
Eluna::Push(L, obj->GetGUIDLow());
return 1;
}
/**
* Returns the TypeId of the [Object].
*
* enum TypeID
* {
* TYPEID_OBJECT = 0,
* TYPEID_ITEM = 1,
* TYPEID_CONTAINER = 2,
* TYPEID_UNIT = 3,
* TYPEID_PLAYER = 4,
* TYPEID_GAMEOBJECT = 5,
* TYPEID_DYNAMICOBJECT = 6,
* TYPEID_CORPSE = 7
* };
*
* @return uint8 typeID
*/
int GetTypeId(Eluna* /*E*/, lua_State* L, Object* obj)
{
Eluna::Push(L, obj->GetTypeId());
return 1;
}
/**
* Returns the data at the specified index, casted to an unsigned 64-bit integer.
*
* @param uint16 index
* @return uint64 value
*/
int GetUInt64Value(Eluna* /*E*/, lua_State* L, Object* obj)
{
uint16 index = Eluna::CHECKVAL<uint16>(L, 2);
obj->GetUInt64Value(index);
return 0;
}
/* SETTERS */
/**
* Sets the specified flag in the data value at the specified index.
*
* If the flag was already set, it remains set.
*
* To remove a flag, use [Object:RemoveFlag].
*
* @param uint16 index
* @param uint32 value
*/
int SetFlag(Eluna* /*E*/, lua_State* L, Object* obj)
{
uint16 index = Eluna::CHECKVAL<uint16>(L, 2);
uint32 flag = Eluna::CHECKVAL<uint32>(L, 3);
obj->SetFlag(index, flag);
return 0;
}
/**
* Sets the data at the specified index to the given value, converted to a signed 32-bit integer.
*
* @param uint16 index
* @param int32 value
*/
int SetInt32Value(Eluna* /*E*/, lua_State* L, Object* obj)
{
uint16 index = Eluna::CHECKVAL<uint16>(L, 2);
int32 value = Eluna::CHECKVAL<int32>(L, 3);
obj->SetInt32Value(index, value);
return 0;
}
/**
* Sets the data at the specified index to the given value, converted to an unsigned 32-bit integer.
*
* @param uint16 index
* @param uint32 value
*/
int SetUInt32Value(Eluna* /*E*/, lua_State* L, Object* obj)
{
uint16 index = Eluna::CHECKVAL<uint16>(L, 2);
uint32 value = Eluna::CHECKVAL<uint32>(L, 3);
obj->SetUInt32Value(index, value);
return 0;
}
/**
* Sets the data at the specified index to the given value, converted to an unsigned 32-bit integer.
*
* @param uint16 index
* @param uint32 value
*/
int UpdateUInt32Value(Eluna* /*E*/, lua_State* L, Object* obj)
{
uint16 index = Eluna::CHECKVAL<uint16>(L, 2);
uint32 value = Eluna::CHECKVAL<uint32>(L, 3);
obj->UpdateUInt32Value(index, value);
return 0;
}
/**
* Sets the data at the specified index to the given value, converted to a single-precision floating point value.
*
* @param uint16 index
* @param float value
*/
int SetFloatValue(Eluna* /*E*/, lua_State* L, Object* obj)
{
uint16 index = Eluna::CHECKVAL<uint16>(L, 2);
float value = Eluna::CHECKVAL<float>(L, 3);
obj->SetFloatValue(index, value);
return 0;
}
/**
* Sets the data at the specified index and offset to the given value, converted to an unsigned 8-bit integer.
*
* @param uint16 index
* @param uint8 offset : should be 0, 1, 2, or 3
* @param uint8 value
*/
int SetByteValue(Eluna* /*E*/, lua_State* L, Object* obj)
{
uint16 index = Eluna::CHECKVAL<uint16>(L, 2);
uint8 offset = Eluna::CHECKVAL<uint8>(L, 3);
uint8 value = Eluna::CHECKVAL<uint8>(L, 4);
obj->SetByteValue(index, offset, value);
return 0;
}
/**
* Sets the data at the specified index to the given value, converted to an unsigned 16-bit integer.
*
* @param uint16 index
* @param uint8 offset : should be 0 or 1
* @param uint16 value
*/
int SetUInt16Value(Eluna* /*E*/, lua_State* L, Object* obj)
{
uint16 index = Eluna::CHECKVAL<uint16>(L, 2);
uint8 offset = Eluna::CHECKVAL<uint8>(L, 3);
uint16 value = Eluna::CHECKVAL<uint16>(L, 4);
obj->SetUInt16Value(index, offset, value);
return 0;
}
/**
* Sets the data at the specified index to the given value, converted to a signed 16-bit integer.
*
* @param uint16 index
* @param uint8 offset : should be 0 or 1
* @param int16 value
*/
int SetInt16Value(Eluna* /*E*/, lua_State* L, Object* obj)
{
uint16 index = Eluna::CHECKVAL<uint16>(L, 2);
uint8 offset = Eluna::CHECKVAL<uint8>(L, 3);
int16 value = Eluna::CHECKVAL<int16>(L, 4);
obj->SetInt16Value(index, offset, value);
return 0;
}
/**
* Sets the [Object]'s scale/size to the given value.
*
* @param float scale
*/
int SetScale(Eluna* /*E*/, lua_State* L, Object* obj)
{
float size = Eluna::CHECKVAL<float>(L, 2);
obj->SetObjectScale(size);
return 0;
}
/**
* Sets the data at the specified index to the given value, converted to an unsigned 64-bit integer.
*
* @param uint16 index
* @param uint64 value
*/
int SetUInt64Value(Eluna* /*E*/, lua_State* L, Object* obj)
{
uint16 index = Eluna::CHECKVAL<uint16>(L, 2);
uint64 value = Eluna::CHECKVAL<uint64>(L, 3);
obj->SetUInt64Value(index, value);
return 0;
}
/* OTHER */
/**
* Removes a flag from the value at the specified index.
*
* @param uint16 index
* @param uint32 flag
*/
int RemoveFlag(Eluna* /*E*/, lua_State* L, Object* obj)
{
uint16 index = Eluna::CHECKVAL<uint16>(L, 2);
uint32 flag = Eluna::CHECKVAL<uint32>(L, 3);
obj->RemoveFlag(index, flag);
return 0;
}
/**
* Attempts to convert the [Object] to a [Corpse].
*
* If the [Object] is not a [Corpse], returns `nil`.
*
* @return [Corpse] corpse : the [Object] as a [Corpse], or `nil`
*/
int ToCorpse(Eluna* /*E*/, lua_State* L, Object* obj)
{
Eluna::Push(L, obj->ToCorpse());
return 1;
}
/**
* Attempts to convert the [Object] to a [GameObject].
*
* If the [Object] is not a [GameObject], returns `nil`.
*
* @return [GameObject] gameObject : the [Object] as a [GameObject], or `nil`
*/
int ToGameObject(Eluna* /*E*/, lua_State* L, Object* obj)
{
Eluna::Push(L, obj->ToGameObject());
return 1;
}
/**
* Attempts to convert the [Object] to a [Unit].
*
* If the [Object] is not a [Unit], returns `nil`.
*
* @return [Unit] unit : the [Object] as a [Unit], or `nil`
*/
int ToUnit(Eluna* /*E*/, lua_State* L, Object* obj)
{
Eluna::Push(L, obj->ToUnit());
return 1;
}
/**
* Attempts to convert the [Object] to a [Creature].
*
* If the [Object] is not a [Creature], returns `nil`.
*
* @return [Creature] creature : the [Object] as a [Creature], or `nil`
*/
int ToCreature(Eluna* /*E*/, lua_State* L, Object* obj)
{
Eluna::Push(L, obj->ToCreature());
return 1;
}
/**
* Attempts to convert the [Object] to a [Player].
*
* If the [Object] is not a [Player], returns `nil`.
*
* @return [Player] player : the [Object] as a [Player], or `nil`
*/
int ToPlayer(Eluna* /*E*/, lua_State* L, Object* obj)
{
Eluna::Push(L, obj->ToPlayer());
return 1;
}
};
#endif

View file

@ -0,0 +1,733 @@
/*
* 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
*/
#ifndef _PLAYER_HOOKS_H
#define _PLAYER_HOOKS_H
#include "Hooks.h"
#include "HookHelpers.h"
#include "LuaEngine.h"
#include "ElunaBinding.h"
#include "ElunaIncludes.h"
#include "ElunaTemplate.h"
using namespace Hooks;
void Eluna::OnLearnTalents(Player* pPlayer, uint32 talentId, uint32 talentRank, uint32 spellid)
{
if (!PlayerEventBindings->HasEvents(PLAYER_EVENT_ON_LEARN_TALENTS))
return;
LOCK_ELUNA;
Push(pPlayer);
Push(talentId);
Push(talentRank);
Push(spellid);
CallAllFunctions(PlayerEventBindings, PLAYER_EVENT_ON_LEARN_TALENTS);
}
void Eluna::HandleGossipSelectOption(Player* pPlayer, Item* item, uint32 sender, uint32 action, const std::string& code)
{
if (!ItemGossipBindings->HasEvents(GOSSIP_EVENT_ON_SELECT, item->GetEntry()))
return;
LOCK_ELUNA;
pPlayer->PlayerTalkClass->ClearMenus();
Push(pPlayer);
Push(item);
Push(sender);
Push(action);
if (code.empty())
Push();
else
Push(code);
CallAllFunctions(ItemGossipBindings, GOSSIP_EVENT_ON_SELECT, item->GetEntry());
}
void Eluna::HandleGossipSelectOption(Player* pPlayer, uint32 menuId, uint32 sender, uint32 action, const std::string& code)
{
if (!playerGossipBindings->HasEvents(GOSSIP_EVENT_ON_SELECT, menuId))
return;
LOCK_ELUNA;
pPlayer->PlayerTalkClass->ClearMenus();
Push(pPlayer); // receiver
Push(pPlayer); // sender, just not to mess up the amount of args.
Push(sender);
Push(action);
if (code.empty())
Push();
else
Push(code);
CallAllFunctions(playerGossipBindings, GOSSIP_EVENT_ON_SELECT, menuId);
}
// Player
bool Eluna::OnCommand(Player* player, const char* text)
{
// If from console, player is NULL
std::string fullcmd(text);
if (!player || player->GetSession()->GetSecurity() >= SEC_ADMINISTRATOR)
{
char* creload = strtok((char*)text, " ");
char* celuna = strtok(NULL, "");
if (creload && celuna)
{
std::string reload(creload);
std::string eluna(celuna);
std::transform(reload.begin(), reload.end(), reload.begin(), ::tolower);
if (reload == "reload")
{
std::transform(eluna.begin(), eluna.end(), eluna.begin(), ::tolower);
if (std::string("eluna").find(eluna) == 0)
{
ReloadEluna();
return false;
}
}
}
}
if (!PlayerEventBindings->HasEvents(PLAYER_EVENT_ON_COMMAND))
return true;
LOCK_ELUNA;
Push(player);
Push(fullcmd);
return CallAllFunctionsBool(PlayerEventBindings, PLAYER_EVENT_ON_COMMAND, true);
}
void Eluna::OnLootItem(Player* pPlayer, Item* pItem, uint32 count, uint64 guid)
{
if (!PlayerEventBindings->HasEvents(PLAYER_EVENT_ON_LOOT_ITEM))
return;
LOCK_ELUNA;
Push(pPlayer);
Push(pItem);
Push(count);
Push(guid);
CallAllFunctions(PlayerEventBindings, PLAYER_EVENT_ON_LOOT_ITEM);
}
void Eluna::OnLootMoney(Player* pPlayer, uint32 amount)
{
if (!PlayerEventBindings->HasEvents(PLAYER_EVENT_ON_LOOT_MONEY))
return;
LOCK_ELUNA;
Push(pPlayer);
Push(amount);
CallAllFunctions(PlayerEventBindings, PLAYER_EVENT_ON_LOOT_MONEY);
}
void Eluna::OnFirstLogin(Player* pPlayer)
{
if (!PlayerEventBindings->HasEvents(PLAYER_EVENT_ON_FIRST_LOGIN))
return;
LOCK_ELUNA;
Push(pPlayer);
CallAllFunctions(PlayerEventBindings, PLAYER_EVENT_ON_FIRST_LOGIN);
}
void Eluna::OnRepop(Player* pPlayer)
{
if (!PlayerEventBindings->HasEvents(PLAYER_EVENT_ON_REPOP))
return;
LOCK_ELUNA;
Push(pPlayer);
CallAllFunctions(PlayerEventBindings, PLAYER_EVENT_ON_REPOP);
}
void Eluna::OnResurrect(Player* pPlayer)
{
if (!PlayerEventBindings->HasEvents(PLAYER_EVENT_ON_RESURRECT))
return;
LOCK_ELUNA;
Push(pPlayer);
CallAllFunctions(PlayerEventBindings, PLAYER_EVENT_ON_RESURRECT);
}
void Eluna::OnQuestAbandon(Player* pPlayer, uint32 questId)
{
if (!PlayerEventBindings->HasEvents(PLAYER_EVENT_ON_QUEST_ABANDON))
return;
LOCK_ELUNA;
Push(pPlayer);
Push(questId);
CallAllFunctions(PlayerEventBindings, PLAYER_EVENT_ON_QUEST_ABANDON);
}
void Eluna::OnEquip(Player* pPlayer, Item* pItem, uint8 bag, uint8 slot)
{
if (!PlayerEventBindings->HasEvents(PLAYER_EVENT_ON_EQUIP))
return;
LOCK_ELUNA;
Push(pPlayer);
Push(pItem);
Push(bag);
Push(slot);
CallAllFunctions(PlayerEventBindings, PLAYER_EVENT_ON_EQUIP);
}
InventoryResult Eluna::OnCanUseItem(const Player* pPlayer, uint32 itemEntry)
{
if (!PlayerEventBindings->HasEvents(PLAYER_EVENT_ON_CAN_USE_ITEM))
return EQUIP_ERR_OK;
LOCK_ELUNA;
InventoryResult result = EQUIP_ERR_OK;
Push(pPlayer);
Push(itemEntry);
int n = SetupStack(PlayerEventBindings, PLAYER_EVENT_ON_CAN_USE_ITEM, 2);
while (n > 0)
{
int r = CallOneFunction(n--, 2, 1);
if (lua_isnumber(L, r))
result = (InventoryResult)CHECKVAL<uint32>(L, r);
lua_pop(L, 1);
}
CleanUpStack(2);
return result;
}
void Eluna::OnPlayerEnterCombat(Player* pPlayer, Unit* pEnemy)
{
if (!PlayerEventBindings->HasEvents(PLAYER_EVENT_ON_ENTER_COMBAT))
return;
LOCK_ELUNA;
Push(pPlayer);
Push(pEnemy);
CallAllFunctions(PlayerEventBindings, PLAYER_EVENT_ON_ENTER_COMBAT);
}
void Eluna::OnPlayerLeaveCombat(Player* pPlayer)
{
if (!PlayerEventBindings->HasEvents(PLAYER_EVENT_ON_LEAVE_COMBAT))
return;
LOCK_ELUNA;
Push(pPlayer);
CallAllFunctions(PlayerEventBindings, PLAYER_EVENT_ON_LEAVE_COMBAT);
}
void Eluna::OnPVPKill(Player* pKiller, Player* pKilled)
{
if (!PlayerEventBindings->HasEvents(PLAYER_EVENT_ON_KILL_PLAYER))
return;
LOCK_ELUNA;
Push(pKiller);
Push(pKilled);
CallAllFunctions(PlayerEventBindings, PLAYER_EVENT_ON_KILL_PLAYER);
}
void Eluna::OnCreatureKill(Player* pKiller, Creature* pKilled)
{
if (!PlayerEventBindings->HasEvents(PLAYER_EVENT_ON_KILL_CREATURE))
return;
LOCK_ELUNA;
Push(pKiller);
Push(pKilled);
CallAllFunctions(PlayerEventBindings, PLAYER_EVENT_ON_KILL_CREATURE);
}
void Eluna::OnPlayerKilledByCreature(Creature* pKiller, Player* pKilled)
{
if (!PlayerEventBindings->HasEvents(PLAYER_EVENT_ON_KILLED_BY_CREATURE))
return;
LOCK_ELUNA;
Push(pKiller);
Push(pKilled);
CallAllFunctions(PlayerEventBindings, PLAYER_EVENT_ON_KILLED_BY_CREATURE);
}
void Eluna::OnLevelChanged(Player* pPlayer, uint8 oldLevel)
{
if (!PlayerEventBindings->HasEvents(PLAYER_EVENT_ON_LEVEL_CHANGE))
return;
LOCK_ELUNA;
Push(pPlayer);
Push(oldLevel);
CallAllFunctions(PlayerEventBindings, PLAYER_EVENT_ON_LEVEL_CHANGE);
}
void Eluna::OnFreeTalentPointsChanged(Player* pPlayer, uint32 newPoints)
{
if (!PlayerEventBindings->HasEvents(PLAYER_EVENT_ON_TALENTS_CHANGE))
return;
LOCK_ELUNA;
Push(pPlayer);
Push(newPoints);
CallAllFunctions(PlayerEventBindings, PLAYER_EVENT_ON_TALENTS_CHANGE);
}
void Eluna::OnTalentsReset(Player* pPlayer, bool noCost)
{
if (!PlayerEventBindings->HasEvents(PLAYER_EVENT_ON_TALENTS_RESET))
return;
LOCK_ELUNA;
Push(pPlayer);
Push(noCost);
CallAllFunctions(PlayerEventBindings, PLAYER_EVENT_ON_TALENTS_RESET);
}
void Eluna::OnMoneyChanged(Player* pPlayer, int32& amount)
{
if (!PlayerEventBindings->HasEvents(PLAYER_EVENT_ON_MONEY_CHANGE))
return;
LOCK_ELUNA;
Push(pPlayer);
Push(amount);
int amountIndex = lua_gettop(L);
int n = SetupStack(PlayerEventBindings, PLAYER_EVENT_ON_MONEY_CHANGE, 2);
while (n > 0)
{
int r = CallOneFunction(n--, 2, 1);
if (lua_isnumber(L, r))
{
amount = CHECKVAL<int32>(L, r);
// Update the stack for subsequent calls.
ReplaceArgument(amount, amountIndex);
}
lua_pop(L, 1);
}
CleanUpStack(2);
}
void Eluna::OnGiveXP(Player* pPlayer, uint32& amount, Unit* pVictim)
{
if (!PlayerEventBindings->HasEvents(PLAYER_EVENT_ON_GIVE_XP))
return;
LOCK_ELUNA;
Push(pPlayer);
Push(amount);
Push(pVictim);
int amountIndex = lua_gettop(L) - 1;
int n = SetupStack(PlayerEventBindings, PLAYER_EVENT_ON_GIVE_XP, 3);
while (n > 0)
{
int r = CallOneFunction(n--, 3, 1);
if (lua_isnumber(L, r))
{
amount = CHECKVAL<uint32>(L, r);
// Update the stack for subsequent calls.
ReplaceArgument(amount, amountIndex);
}
lua_pop(L, 1);
}
CleanUpStack(3);
}
void Eluna::OnReputationChange(Player* pPlayer, uint32 factionID, int32& standing, bool incremental)
{
if (!PlayerEventBindings->HasEvents(PLAYER_EVENT_ON_REPUTATION_CHANGE))
return;
LOCK_ELUNA;
Push(pPlayer);
Push(factionID);
Push(standing);
Push(incremental);
int standingIndex = lua_gettop(L) - 1;
int n = SetupStack(PlayerEventBindings, PLAYER_EVENT_ON_REPUTATION_CHANGE, 4);
while (n > 0)
{
int r = CallOneFunction(n--, 4, 1);
if (lua_isnumber(L, r))
{
standing = CHECKVAL<int32>(L, r);
// Update the stack for subsequent calls.
ReplaceArgument(standing, standingIndex);
}
lua_pop(L, 1);
}
CleanUpStack(4);
}
void Eluna::OnDuelRequest(Player* pTarget, Player* pChallenger)
{
if (!PlayerEventBindings->HasEvents(PLAYER_EVENT_ON_DUEL_REQUEST))
return;
LOCK_ELUNA;
Push(pTarget);
Push(pChallenger);
CallAllFunctions(PlayerEventBindings, PLAYER_EVENT_ON_DUEL_REQUEST);
}
void Eluna::OnDuelStart(Player* pStarter, Player* pChallenger)
{
if (!PlayerEventBindings->HasEvents(PLAYER_EVENT_ON_DUEL_START))
return;
LOCK_ELUNA;
Push(pStarter);
Push(pChallenger);
CallAllFunctions(PlayerEventBindings, PLAYER_EVENT_ON_DUEL_START);
}
void Eluna::OnDuelEnd(Player* pWinner, Player* pLoser, DuelCompleteType type)
{
if (!PlayerEventBindings->HasEvents(PLAYER_EVENT_ON_DUEL_END))
return;
LOCK_ELUNA;
Push(pWinner);
Push(pLoser);
Push(type);
CallAllFunctions(PlayerEventBindings, PLAYER_EVENT_ON_DUEL_END);
}
void Eluna::OnEmote(Player* pPlayer, uint32 emote)
{
if (!PlayerEventBindings->HasEvents(PLAYER_EVENT_ON_EMOTE))
return;
LOCK_ELUNA;
Push(pPlayer);
Push(emote);
CallAllFunctions(PlayerEventBindings, PLAYER_EVENT_ON_EMOTE);
}
void Eluna::OnTextEmote(Player* pPlayer, uint32 textEmote, uint32 emoteNum, uint64 guid)
{
if (!PlayerEventBindings->HasEvents(PLAYER_EVENT_ON_TEXT_EMOTE))
return;
LOCK_ELUNA;
Push(pPlayer);
Push(textEmote);
Push(emoteNum);
Push(guid);
CallAllFunctions(PlayerEventBindings, PLAYER_EVENT_ON_TEXT_EMOTE);
}
void Eluna::OnSpellCast(Player* pPlayer, Spell* pSpell, bool skipCheck)
{
if (!PlayerEventBindings->HasEvents(PLAYER_EVENT_ON_SPELL_CAST))
return;
LOCK_ELUNA;
Push(pPlayer);
Push(pSpell);
Push(skipCheck);
CallAllFunctions(PlayerEventBindings, PLAYER_EVENT_ON_SPELL_CAST);
}
void Eluna::OnLogin(Player* pPlayer)
{
if (!PlayerEventBindings->HasEvents(PLAYER_EVENT_ON_LOGIN))
return;
LOCK_ELUNA;
Push(pPlayer);
CallAllFunctions(PlayerEventBindings, PLAYER_EVENT_ON_LOGIN);
}
void Eluna::OnLogout(Player* pPlayer)
{
if (!PlayerEventBindings->HasEvents(PLAYER_EVENT_ON_LOGOUT))
return;
LOCK_ELUNA;
Push(pPlayer);
CallAllFunctions(PlayerEventBindings, PLAYER_EVENT_ON_LOGOUT);
}
void Eluna::OnCreate(Player* pPlayer)
{
if (!PlayerEventBindings->HasEvents(PLAYER_EVENT_ON_CHARACTER_CREATE))
return;
LOCK_ELUNA;
Push(pPlayer);
CallAllFunctions(PlayerEventBindings, PLAYER_EVENT_ON_CHARACTER_CREATE);
}
void Eluna::OnDelete(uint32 guidlow)
{
if (!PlayerEventBindings->HasEvents(PLAYER_EVENT_ON_CHARACTER_DELETE))
return;
LOCK_ELUNA;
Push(guidlow);
CallAllFunctions(PlayerEventBindings, PLAYER_EVENT_ON_CHARACTER_DELETE);
}
void Eluna::OnSave(Player* pPlayer)
{
if (!PlayerEventBindings->HasEvents(PLAYER_EVENT_ON_SAVE))
return;
LOCK_ELUNA;
Push(pPlayer);
CallAllFunctions(PlayerEventBindings, PLAYER_EVENT_ON_SAVE);
}
void Eluna::OnBindToInstance(Player* pPlayer, Difficulty difficulty, uint32 mapid, bool permanent)
{
if (!PlayerEventBindings->HasEvents(PLAYER_EVENT_ON_BIND_TO_INSTANCE))
return;
LOCK_ELUNA;
Push(pPlayer);
Push(difficulty);
Push(mapid);
Push(permanent);
CallAllFunctions(PlayerEventBindings, PLAYER_EVENT_ON_BIND_TO_INSTANCE);
}
void Eluna::OnUpdateZone(Player* pPlayer, uint32 newZone, uint32 newArea)
{
if (!PlayerEventBindings->HasEvents(PLAYER_EVENT_ON_UPDATE_ZONE))
return;
LOCK_ELUNA;
Push(pPlayer);
Push(newZone);
Push(newArea);
CallAllFunctions(PlayerEventBindings, PLAYER_EVENT_ON_UPDATE_ZONE);
}
void Eluna::OnMapChanged(Player* player)
{
if (!PlayerEventBindings->HasEvents(PLAYER_EVENT_ON_MAP_CHANGE))
return;
LOCK_ELUNA;
Push(player);
CallAllFunctions(PlayerEventBindings, PLAYER_EVENT_ON_MAP_CHANGE);
}
// AddOns
bool Eluna::OnAddonMessage(Player* sender, uint32 type, std::string& msg, Player* receiver, Guild* guild, Group* group, Channel* channel)
{
if (!ServerEventBindings->HasEvents(ADDON_EVENT_ON_MESSAGE))
return true;
LOCK_ELUNA;
Push(sender);
Push(type);
const char* c_msg = msg.c_str();
Push(strtok((char*)c_msg, "\t")); // prefix
Push(strtok(NULL, "")); // msg
if (receiver)
Push(receiver);
else if (guild)
Push(guild);
else if (group)
Push(group);
else if (channel)
Push(channel->GetChannelId());
else
Push();
return CallAllFunctionsBool(ServerEventBindings, ADDON_EVENT_ON_MESSAGE, true);
}
bool Eluna::OnChat(Player* pPlayer, uint32 type, uint32 lang, std::string& msg)
{
if (lang == LANG_ADDON)
return OnAddonMessage(pPlayer, type, msg, NULL, NULL, NULL, NULL);
if (!PlayerEventBindings->HasEvents(PLAYER_EVENT_ON_CHAT))
return true;
LOCK_ELUNA;
bool result = true;
Push(pPlayer);
Push(msg);
Push(type);
Push(lang);
int n = SetupStack(PlayerEventBindings, PLAYER_EVENT_ON_CHAT, 4);
while (n > 0)
{
int r = CallOneFunction(n--, 4, 2);
if (lua_isboolean(L, r + 0) && !lua_toboolean(L, r + 0))
result = false;
if (lua_isstring(L, r + 1))
msg = std::string(lua_tostring(L, r + 1));
lua_pop(L, 2);
}
CleanUpStack(4);
return result;
}
bool Eluna::OnChat(Player* pPlayer, uint32 type, uint32 lang, std::string& msg, Group* pGroup)
{
if (lang == LANG_ADDON)
return OnAddonMessage(pPlayer, type, msg, NULL, NULL, pGroup, NULL);
if (!PlayerEventBindings->HasEvents(PLAYER_EVENT_ON_GROUP_CHAT))
return true;
LOCK_ELUNA;
bool result = true;
Push(pPlayer);
Push(msg);
Push(type);
Push(lang);
Push(pGroup);
int n = SetupStack(PlayerEventBindings, PLAYER_EVENT_ON_GROUP_CHAT, 5);
while (n > 0)
{
int r = CallOneFunction(n--, 5, 2);
if (lua_isboolean(L, r + 0) && !lua_toboolean(L, r + 0))
result = false;
if (lua_isstring(L, r + 1))
msg = std::string(lua_tostring(L, r + 1));
lua_pop(L, 2);
}
CleanUpStack(5);
return result;
}
bool Eluna::OnChat(Player* pPlayer, uint32 type, uint32 lang, std::string& msg, Guild* pGuild)
{
if (lang == LANG_ADDON)
return OnAddonMessage(pPlayer, type, msg, NULL, pGuild, NULL, NULL);
if (!PlayerEventBindings->HasEvents(PLAYER_EVENT_ON_GUILD_CHAT))
return true;
LOCK_ELUNA;
bool result = true;
Push(pPlayer);
Push(msg);
Push(type);
Push(lang);
Push(pGuild);
int n = SetupStack(PlayerEventBindings, PLAYER_EVENT_ON_GUILD_CHAT, 5);
while (n > 0)
{
int r = CallOneFunction(n--, 5, 2);
if (lua_isboolean(L, r + 0) && !lua_toboolean(L, r + 0))
result = false;
if (lua_isstring(L, r + 1))
msg = std::string(lua_tostring(L, r + 1));
lua_pop(L, 2);
}
CleanUpStack(5);
return result;
}
bool Eluna::OnChat(Player* pPlayer, uint32 type, uint32 lang, std::string& msg, Channel* pChannel)
{
if (lang == LANG_ADDON)
return OnAddonMessage(pPlayer, type, msg, NULL, NULL, NULL, pChannel);
if (!PlayerEventBindings->HasEvents(PLAYER_EVENT_ON_CHANNEL_CHAT))
return true;
LOCK_ELUNA;
bool result = true;
Push(pPlayer);
Push(msg);
Push(type);
Push(lang);
Push(pChannel->GetChannelId());
int n = SetupStack(PlayerEventBindings, PLAYER_EVENT_ON_CHANNEL_CHAT, 5);
while (n > 0)
{
int r = CallOneFunction(n--, 5, 2);
if (lua_isboolean(L, r + 0) && !lua_toboolean(L, r + 0))
result = false;
if (lua_isstring(L, r + 1))
msg = std::string(lua_tostring(L, r + 1));
lua_pop(L, 2);
}
CleanUpStack(5);
return result;
}
bool Eluna::OnChat(Player* pPlayer, uint32 type, uint32 lang, std::string& msg, Player* pReceiver)
{
if (lang == LANG_ADDON)
return OnAddonMessage(pPlayer, type, msg, pReceiver, NULL, NULL, NULL);
if (!PlayerEventBindings->HasEvents(PLAYER_EVENT_ON_WHISPER))
return true;
LOCK_ELUNA;
bool result = true;
Push(pPlayer);
Push(msg);
Push(type);
Push(lang);
Push(pReceiver);
int n = SetupStack(PlayerEventBindings, PLAYER_EVENT_ON_WHISPER, 5);
while (n > 0)
{
int r = CallOneFunction(n--, 5, 2);
if (lua_isboolean(L, r + 0) && !lua_toboolean(L, r + 0))
result = false;
if (lua_isstring(L, r + 1))
msg = std::string(lua_tostring(L, r + 1));
lua_pop(L, 2);
}
CleanUpStack(5);
return result;
}
#endif // _PLAYER_HOOKS_H

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,184 @@
/*
* 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
*/
#ifndef QUESTMETHODS_H
#define QUESTMETHODS_H
namespace LuaQuest
{
/**
* Returns 'true' if the [Quest] has the specified flag, false otherwise.
* Below flags are based off of 3.3.5a. Subject to change.
*
* <pre>
* enum QuestFlags
* {
* // Flags used at server and sent to client
* QUEST_FLAGS_NONE = 0x0,
* QUEST_FLAGS_STAY_ALIVE = 0x1, // Not used currently
* QUEST_FLAGS_PARTY_ACCEPT = 0x2, // Not used currently. If player in party, all players that can accept this quest will receive confirmation box to accept quest CMSG_QUEST_CONFIRM_ACCEPT/SMSG_QUEST_CONFIRM_ACCEPT
* QUEST_FLAGS_EXPLORATION = 0x4, // Not used currently
* QUEST_FLAGS_SHARABLE = 0x8, // Can be shared: Player::CanShareQuest()
* QUEST_FLAGS_HAS_CONDITION = 0x10, // Not used currently
* QUEST_FLAGS_HIDE_REWARD_POI = 0x20, // Not used currently: Unsure of content
* QUEST_FLAGS_RAID = 0x40, // Not used currently
* QUEST_FLAGS_TBC = 0x80, // Not used currently: Available if TBC expansion enabled only
* QUEST_FLAGS_NO_MONEY_FROM_XP = 0x100, // Not used currently: Experience is not converted to gold at max level
* QUEST_FLAGS_HIDDEN_REWARDS = 0x200, // Items and money rewarded only sent in SMSG_QUESTGIVER_OFFER_REWARD (not in SMSG_QUESTGIVER_QUEST_DETAILS or in client quest log(SMSG_QUEST_QUERY_RESPONSE))
* QUEST_FLAGS_TRACKING = 0x400, // These quests are automatically rewarded on quest complete and they will never appear in quest log client side.
* QUEST_FLAGS_DEPRECATE_REPUTATION = 0x800, // Not used currently
* QUEST_FLAGS_DAILY = 0x1000, // Used to know quest is Daily one
* QUEST_FLAGS_FLAGS_PVP = 0x2000, // Having this quest in log forces PvP flag
* QUEST_FLAGS_UNAVAILABLE = 0x4000, // Used on quests that are not generically available
* QUEST_FLAGS_WEEKLY = 0x8000,
* QUEST_FLAGS_AUTOCOMPLETE = 0x10000, // auto complete
* QUEST_FLAGS_DISPLAY_ITEM_IN_TRACKER = 0x20000, // Displays usable item in quest tracker
* QUEST_FLAGS_OBJ_TEXT = 0x40000, // use Objective text as Complete text
* QUEST_FLAGS_AUTO_ACCEPT = 0x80000, // The client recognizes this flag as auto-accept. However, NONE of the current quests (3.3.5a) have this flag. Maybe blizz used to use it, or will use it in the future.
*
* // ... 4.x added flags up to 0x80000000 - all unknown for now
* };
* </pre>
*
* @param [QuestFlags] flag : all available flags can be seen above
* @return bool hasFlag
*/
int HasFlag(Eluna* /*E*/, lua_State* L, Quest* quest)
{
uint32 flag = Eluna::CHECKVAL<uint32>(L, 2);
#ifndef TRINITY
Eluna::Push(L, quest->HasQuestFlag((QuestFlags)flag));
#else
Eluna::Push(L, quest->HasFlag(flag));
#endif
return 1;
}
#ifndef CLASSIC
/**
* Returns 'true' if the [Quest] is a daily quest, false otherwise.
*
* @return bool isDaily
*/
int IsDaily(Eluna* /*E*/, lua_State* L, Quest* quest)
{
Eluna::Push(L, quest->IsDaily());
return 1;
}
#endif
/**
* Returns 'true' if the [Quest] is repeatable, false otherwise.
*
* @return bool isRepeatable
*/
int IsRepeatable(Eluna* /*E*/, lua_State* L, Quest* quest)
{
Eluna::Push(L, quest->IsRepeatable());
return 1;
}
/**
* Returns entry ID of the [Quest].
*
* @return uint32 entryId
*/
int GetId(Eluna* /*E*/, lua_State* L, Quest* quest)
{
Eluna::Push(L, quest->GetQuestId());
return 1;
}
/**
* Returns the [Quest]'s level.
*
* @return uint32 level
*/
int GetLevel(Eluna* /*E*/, lua_State* L, Quest* quest)
{
Eluna::Push(L, quest->GetQuestLevel());
return 1;
}
/**
* Returns the minimum level required to pick up the [Quest].
*
* @return uint32 minLevel
*/
int GetMinLevel(Eluna* /*E*/, lua_State* L, Quest* quest)
{
Eluna::Push(L, quest->GetMinLevel());
return 1;
}
/**
* Returns the next [Quest] entry ID.
*
* @return int32 entryId
*/
int GetNextQuestId(Eluna* /*E*/, lua_State* L, Quest* quest)
{
Eluna::Push(L, quest->GetNextQuestId());
return 1;
}
/**
* Returns the previous [Quest] entry ID.
*
* @return int32 entryId
*/
int GetPrevQuestId(Eluna* /*E*/, lua_State* L, Quest* quest)
{
Eluna::Push(L, quest->GetPrevQuestId());
return 1;
}
/**
* Returns the next [Quest] entry ID in the specific [Quest] chain.
*
* @return int32 entryId
*/
int GetNextQuestInChain(Eluna* /*E*/, lua_State* L, Quest* quest)
{
Eluna::Push(L, quest->GetNextQuestInChain());
return 1;
}
/**
* Returns the [Quest]'s flags.
*
* @return [QuestFlags] flags
*/
int GetFlags(Eluna* /*E*/, lua_State* L, Quest* quest)
{
#ifndef TRINITY
Eluna::Push(L, quest->GetQuestFlags());
#else
Eluna::Push(L, quest->GetFlags());
#endif
return 1;
}
/**
* Returns the [Quest]'s type.
*
* TODO: Document types available.
*
* @return uint32 type
*/
int GetType(Eluna* /*E*/, lua_State* L, Quest* quest)
{
Eluna::Push(L, quest->GetType());
return 1;
}
/*int GetMaxLevel(Eluna* E, lua_State* L, Quest* quest)
{
Eluna::Push(L, quest->GetMaxLevel());
return 1;
}*/
};
#endif

View file

@ -0,0 +1,54 @@
###[![Eluna](docs/Eluna.png)](https://github.com/ElunaLuaEngine/Eluna)
##About
Eluna Lua Engine &copy; is a lua engine embedded to World of Warcraft emulators. Eluna supports MaNGOS, CMaNGOS and TrinityCore.
We are currently working hard to make Eluna better from inside and outside.
Follow us on [EmuDevs Twitter](https://twitter.com/EmuDevs) page to view the latest news about EmuDevs and about what is going on with Eluna Lua Engine &copy;.
If you are having trouble with installation or scripts, post in [Eluna Support Forum](http://emudevs.com/forumdisplay.php/279-Eluna-Support)
For documentation and reference see [Eluna API](http://eluna.emudevs.com/) and [Lua reference manual](http://www.lua.org/manual/5.2/).
Special thanks to [MaNGOS](http://getmangos.eu/) for their continued support and use of Eluna. Please head over to their forums and show them some love!
##Documentation
* [Installation](https://github.com/ElunaLuaEngine/Eluna/blob/master/docs/INSTALL.md)
* [Function documentation](http://eluna.emudevs.com/)
* [Hook documentation](https://github.com/ElunaLuaEngine/Eluna/blob/master/Hooks.h)
* [Lua reference manual](http://www.lua.org/manual/5.2/)
* [Contributing](docs/CONTRIBUTING.md)
* [Support forum](http://emudevs.com/forumdisplay.php/279-Eluna-Support)
* [Example scripts](https://github.com/ElunaLuaEngine/Scripts)
* [Guides, releases and news](http://emudevs.com/forumdisplay.php/15-Eluna-Lua-Engine-%C2%A9)
##Source
Eluna source code: [Source](https://github.com/ElunaLuaEngine/Eluna)
Core forks with required modifications for Eluna:
[![Build Status](https://api.travis-ci.org/mangoszero/server.svg?branch=release20)](https://travis-ci.org/mangoszero/server) [Official MaNGOS Zero with Eluna](https://github.com/mangoszero/server)
[![Build Status](https://travis-ci.org/ElunaLuaEngine/ElunaTrinityWotlk.png?branch=master)](https://travis-ci.org/ElunaLuaEngine/ElunaTrinityWotlk) [Eluna TrinityCore WotLK](https://github.com/ElunaLuaEngine/ElunaTrinityWotlk)
[![Build Status](https://travis-ci.org/ElunaLuaEngine/ElunaTrinityCata.png?branch=master)](https://travis-ci.org/ElunaLuaEngine/ElunaTrinityCata) [Eluna TrinityCore Cataclysm](https://github.com/ElunaLuaEngine/ElunaTrinityCata)
[![Build Status](https://travis-ci.org/ElunaLuaEngine/ElunaMangosClassic.png?branch=master)](https://travis-ci.org/ElunaLuaEngine/ElunaMangosClassic) [Eluna cMaNGOS Classic](https://github.com/ElunaLuaEngine/ElunaMangosClassic)
[![Build Status](https://travis-ci.org/ElunaLuaEngine/ElunaMangosTbc.png?branch=master)](https://travis-ci.org/ElunaLuaEngine/ElunaMangosTbc) [Eluna cMaNGOS TBC](https://github.com/ElunaLuaEngine/ElunaMangosTbc)
[![Build Status](https://travis-ci.org/ElunaLuaEngine/ElunaMangosWotlk.png?branch=master)](https://travis-ci.org/ElunaLuaEngine/ElunaMangosWotlk) [Eluna cMaNGOS WotLK](https://github.com/ElunaLuaEngine/ElunaMangosWotlk)
##Links
* [MaNGOS](http://getmangos.eu/)
* [cMaNGOS](http://cmangos.net/)
* [TrinityCore](http://www.trinitycore.org/)
* [Lua.org](http://www.lua.org/)
* [License](https://github.com/ElunaLuaEngine/Eluna/blob/master/docs/LICENSE.md)
##Team
* [Tommy (Easelm)](https://github.com/Easelm)
* [Foereaper](https://github.com/Foereaper)
* [Rochet2](https://github.com/Rochet2)
* [Salja](https://github.com/Salja)
* [Patman64](https://github.com/Patman64)

View file

@ -0,0 +1,487 @@
/*
* 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
*/
#ifndef _SERVER_HOOKS_H
#define _SERVER_HOOKS_H
#include "Hooks.h"
#include "HookHelpers.h"
#include "LuaEngine.h"
#include "ElunaBinding.h"
#include "ElunaEventMgr.h"
#include "ElunaIncludes.h"
#include "ElunaTemplate.h"
using namespace Hooks;
void Eluna::OnTimedEvent(int funcRef, uint32 delay, uint32 calls, WorldObject* obj)
{
LOCK_ELUNA;
ASSERT(!event_level);
// Get function
lua_rawgeti(L, LUA_REGISTRYINDEX, funcRef);
// Push parameters
Push(L, funcRef);
Push(L, delay);
Push(L, calls);
Push(L, obj);
// Call function
ExecuteCall(4, 0);
ASSERT(!event_level);
InvalidateObjects();
}
void Eluna::OnLuaStateClose()
{
if (!ServerEventBindings->HasEvents(ELUNA_EVENT_ON_LUA_STATE_CLOSE))
return;
LOCK_ELUNA;
CallAllFunctions(ServerEventBindings, ELUNA_EVENT_ON_LUA_STATE_CLOSE);
}
void Eluna::OnLuaStateOpen()
{
if (!ServerEventBindings->HasEvents(ELUNA_EVENT_ON_LUA_STATE_OPEN))
return;
LOCK_ELUNA;
CallAllFunctions(ServerEventBindings, ELUNA_EVENT_ON_LUA_STATE_OPEN);
}
// areatrigger
bool Eluna::OnAreaTrigger(Player* pPlayer, AreaTriggerEntry const* pTrigger)
{
if (!ServerEventBindings->HasEvents(TRIGGER_EVENT_ON_TRIGGER))
return false;
LOCK_ELUNA;
Push(pPlayer);
Push(pTrigger->id);
return CallAllFunctionsBool(ServerEventBindings, TRIGGER_EVENT_ON_TRIGGER);
}
// weather
void Eluna::OnChange(Weather* weather, uint32 zone, WeatherState state, float grade)
{
if (!ServerEventBindings->HasEvents(WEATHER_EVENT_ON_CHANGE))
return;
LOCK_ELUNA;
Push(zone);
Push(state);
Push(grade);
CallAllFunctions(ServerEventBindings, WEATHER_EVENT_ON_CHANGE);
}
// Auction House
void Eluna::OnAdd(AuctionHouseObject* /*ah*/, AuctionEntry* entry)
{
if (!ServerEventBindings->HasEvents(AUCTION_EVENT_ON_ADD))
return;
Player* owner = eObjectAccessor->FindPlayer(MAKE_NEW_GUID(entry->owner, 0, HIGHGUID_PLAYER));
#ifdef TRINITY
Item* item = eAuctionMgr->GetAItem(entry->itemGUIDLow);
uint32 expiretime = entry->expire_time;
#else
Item* item = eAuctionMgr->GetAItem(entry->itemGuidLow);
uint32 expiretime = entry->expireTime;
#endif
if (!owner || !item)
return;
LOCK_ELUNA;
Push(entry->Id);
Push(owner);
Push(item);
Push(expiretime);
Push(entry->buyout);
Push(entry->startbid);
Push(entry->bid);
Push(entry->bidder);
CallAllFunctions(ServerEventBindings, AUCTION_EVENT_ON_ADD);
}
void Eluna::OnRemove(AuctionHouseObject* /*ah*/, AuctionEntry* entry)
{
if (!ServerEventBindings->HasEvents(AUCTION_EVENT_ON_REMOVE))
return;
Player* owner = eObjectAccessor->FindPlayer(MAKE_NEW_GUID(entry->owner, 0, HIGHGUID_PLAYER));
#ifdef TRINITY
Item* item = eAuctionMgr->GetAItem(entry->itemGUIDLow);
uint32 expiretime = entry->expire_time;
#else
Item* item = eAuctionMgr->GetAItem(entry->itemGuidLow);
uint32 expiretime = entry->expireTime;
#endif
if (!owner || !item)
return;
LOCK_ELUNA;
Push(entry->Id);
Push(owner);
Push(item);
Push(expiretime);
Push(entry->buyout);
Push(entry->startbid);
Push(entry->bid);
Push(entry->bidder);
CallAllFunctions(ServerEventBindings, AUCTION_EVENT_ON_REMOVE);
}
void Eluna::OnSuccessful(AuctionHouseObject* /*ah*/, AuctionEntry* entry)
{
if (!ServerEventBindings->HasEvents(AUCTION_EVENT_ON_SUCCESSFUL))
return;
Player* owner = eObjectAccessor->FindPlayer(MAKE_NEW_GUID(entry->owner, 0, HIGHGUID_PLAYER));
#ifdef TRINITY
Item* item = eAuctionMgr->GetAItem(entry->itemGUIDLow);
uint32 expiretime = entry->expire_time;
#else
Item* item = eAuctionMgr->GetAItem(entry->itemGuidLow);
uint32 expiretime = entry->expireTime;
#endif
if (!owner || !item)
return;
LOCK_ELUNA;
Push(entry->Id);
Push(owner);
Push(item);
Push(expiretime);
Push(entry->buyout);
Push(entry->startbid);
Push(entry->bid);
Push(entry->bidder);
CallAllFunctions(ServerEventBindings, AUCTION_EVENT_ON_SUCCESSFUL);
}
void Eluna::OnExpire(AuctionHouseObject* /*ah*/, AuctionEntry* entry)
{
if (!ServerEventBindings->HasEvents(AUCTION_EVENT_ON_EXPIRE))
return;
Player* owner = eObjectAccessor->FindPlayer(MAKE_NEW_GUID(entry->owner, 0, HIGHGUID_PLAYER));
#ifdef TRINITY
Item* item = eAuctionMgr->GetAItem(entry->itemGUIDLow);
uint32 expiretime = entry->expire_time;
#else
Item* item = eAuctionMgr->GetAItem(entry->itemGuidLow);
uint32 expiretime = entry->expireTime;
#endif
if (!owner || !item)
return;
LOCK_ELUNA;
Push(entry->Id);
Push(owner);
Push(item);
Push(expiretime);
Push(entry->buyout);
Push(entry->startbid);
Push(entry->bid);
Push(entry->bidder);
CallAllFunctions(ServerEventBindings, AUCTION_EVENT_ON_EXPIRE);
}
// Packet
bool Eluna::OnPacketSend(WorldSession* session, WorldPacket& packet)
{
bool result = true;
Player* player = NULL;
if (session)
player = session->GetPlayer();
OnPacketSendAny(player, packet, result);
OnPacketSendOne(player, packet, result);
return result;
}
void Eluna::OnPacketSendAny(Player* player, WorldPacket& packet, bool& result)
{
if (!ServerEventBindings->HasEvents(SERVER_EVENT_ON_PACKET_SEND))
return;
LOCK_ELUNA;
Push(new WorldPacket(packet));
Push(player);
int n = SetupStack(ServerEventBindings, SERVER_EVENT_ON_PACKET_SEND, 2);
while (n > 0)
{
int r = CallOneFunction(n--, 2, 2);
if (lua_isboolean(L, r + 0) && !lua_toboolean(L, r + 0))
result = false;
if (lua_isuserdata(L, r + 1))
if (WorldPacket* data = CHECKOBJ<WorldPacket>(L, r + 1, false))
packet = *data;
lua_pop(L, 2);
}
CleanUpStack(2);
}
void Eluna::OnPacketSendOne(Player* player, WorldPacket& packet, bool& result)
{
if (!PacketEventBindings->HasEvents(PACKET_EVENT_ON_PACKET_SEND, packet.GetOpcode()))
return;
LOCK_ELUNA;
Push(new WorldPacket(packet));
Push(player);
int n = SetupStack(PacketEventBindings, PACKET_EVENT_ON_PACKET_SEND, OpcodesList(packet.GetOpcode()), 2);
while (n > 0)
{
int r = CallOneFunction(n--, 2, 2);
if (lua_isboolean(L, r + 0) && !lua_toboolean(L, r + 0))
result = false;
if (lua_isuserdata(L, r + 1))
if (WorldPacket* data = CHECKOBJ<WorldPacket>(L, r + 1, false))
packet = *data;
lua_pop(L, 2);
}
CleanUpStack(2);
}
bool Eluna::OnPacketReceive(WorldSession* session, WorldPacket& packet)
{
bool result = true;
Player* player = NULL;
if (session)
player = session->GetPlayer();
OnPacketReceiveAny(player, packet, result);
OnPacketReceiveOne(player, packet, result);
return result;
}
void Eluna::OnPacketReceiveAny(Player* player, WorldPacket& packet, bool& result)
{
if (!ServerEventBindings->HasEvents(SERVER_EVENT_ON_PACKET_RECEIVE))
return;
LOCK_ELUNA;
Push(new WorldPacket(packet));
Push(player);
int n = SetupStack(ServerEventBindings, SERVER_EVENT_ON_PACKET_RECEIVE, 2);
while (n > 0)
{
int r = CallOneFunction(n--, 2, 2);
if (lua_isboolean(L, r + 0) && !lua_toboolean(L, r + 0))
result = false;
if (lua_isuserdata(L, r + 1))
if (WorldPacket* data = CHECKOBJ<WorldPacket>(L, r + 1, false))
packet = *data;
lua_pop(L, 2);
}
CleanUpStack(2);
}
void Eluna::OnPacketReceiveOne(Player* player, WorldPacket& packet, bool& result)
{
if (!PacketEventBindings->HasEvents(PACKET_EVENT_ON_PACKET_RECEIVE, packet.GetOpcode()))
return;
LOCK_ELUNA;
Push(new WorldPacket(packet));
Push(player);
int n = SetupStack(PacketEventBindings, PACKET_EVENT_ON_PACKET_RECEIVE, OpcodesList(), 2);
while (n > 0)
{
int r = CallOneFunction(n--, 2, 2);
if (lua_isboolean(L, r + 0) && !lua_toboolean(L, r + 0))
result = false;
if (lua_isuserdata(L, r + 1))
if (WorldPacket* data = CHECKOBJ<WorldPacket>(L, r + 1, false))
packet = *data;
lua_pop(L, 2);
}
CleanUpStack(2);
}
void Eluna::OnOpenStateChange(bool open)
{
if (!ServerEventBindings->HasEvents(WORLD_EVENT_ON_OPEN_STATE_CHANGE))
return;
LOCK_ELUNA;
Push(open);
CallAllFunctions(ServerEventBindings, WORLD_EVENT_ON_OPEN_STATE_CHANGE);
}
void Eluna::OnConfigLoad(bool reload)
{
if (!ServerEventBindings->HasEvents(WORLD_EVENT_ON_CONFIG_LOAD))
return;
LOCK_ELUNA;
Push(reload);
CallAllFunctions(ServerEventBindings, WORLD_EVENT_ON_CONFIG_LOAD);
}
void Eluna::OnShutdownInitiate(ShutdownExitCode code, ShutdownMask mask)
{
if (!ServerEventBindings->HasEvents(WORLD_EVENT_ON_SHUTDOWN_INIT))
return;
LOCK_ELUNA;
Push(code);
Push(mask);
CallAllFunctions(ServerEventBindings, WORLD_EVENT_ON_SHUTDOWN_INIT);
}
void Eluna::OnShutdownCancel()
{
if (!ServerEventBindings->HasEvents(WORLD_EVENT_ON_SHUTDOWN_CANCEL))
return;
LOCK_ELUNA;
CallAllFunctions(ServerEventBindings, WORLD_EVENT_ON_SHUTDOWN_CANCEL);
}
void Eluna::OnWorldUpdate(uint32 diff)
{
{
LOCK_ELUNA;
if (ShouldReload())
_ReloadEluna();
}
eventMgr->globalProcessor->Update(diff);
if (!ServerEventBindings->HasEvents(WORLD_EVENT_ON_UPDATE))
return;
LOCK_ELUNA;
Push(diff);
CallAllFunctions(ServerEventBindings, WORLD_EVENT_ON_UPDATE);
}
void Eluna::OnStartup()
{
if (!ServerEventBindings->HasEvents(WORLD_EVENT_ON_STARTUP))
return;
LOCK_ELUNA;
CallAllFunctions(ServerEventBindings, WORLD_EVENT_ON_STARTUP);
}
void Eluna::OnShutdown()
{
if (!ServerEventBindings->HasEvents(WORLD_EVENT_ON_SHUTDOWN))
return;
LOCK_ELUNA;
CallAllFunctions(ServerEventBindings, WORLD_EVENT_ON_SHUTDOWN);
}
/* Map */
void Eluna::OnCreate(Map* map)
{
if (!ServerEventBindings->HasEvents(MAP_EVENT_ON_CREATE))
return;
LOCK_ELUNA;
Push(map);
CallAllFunctions(ServerEventBindings, MAP_EVENT_ON_CREATE);
}
void Eluna::OnDestroy(Map* map)
{
if (!ServerEventBindings->HasEvents(MAP_EVENT_ON_DESTROY))
return;
LOCK_ELUNA;
Push(map);
CallAllFunctions(ServerEventBindings, MAP_EVENT_ON_DESTROY);
}
void Eluna::OnPlayerEnter(Map* map, Player* player)
{
if (!ServerEventBindings->HasEvents(MAP_EVENT_ON_PLAYER_ENTER))
return;
LOCK_ELUNA;
Push(map);
Push(player);
CallAllFunctions(ServerEventBindings, MAP_EVENT_ON_PLAYER_ENTER);
}
void Eluna::OnPlayerLeave(Map* map, Player* player)
{
if (!ServerEventBindings->HasEvents(MAP_EVENT_ON_PLAYER_LEAVE))
return;
LOCK_ELUNA;
Push(map);
Push(player);
CallAllFunctions(ServerEventBindings, MAP_EVENT_ON_PLAYER_LEAVE);
}
void Eluna::OnUpdate(Map* map, uint32 diff)
{
if (!ServerEventBindings->HasEvents(MAP_EVENT_ON_UPDATE))
return;
LOCK_ELUNA;
// enable this for multithread
// eventMgr->globalProcessor->Update(diff);
Push(map);
Push(diff);
CallAllFunctions(ServerEventBindings, MAP_EVENT_ON_UPDATE);
}
void Eluna::OnRemove(GameObject* gameobject)
{
if (!ServerEventBindings->HasEvents(WORLD_EVENT_ON_DELETE_GAMEOBJECT))
return;
LOCK_ELUNA;
Push(gameobject);
CallAllFunctions(ServerEventBindings, WORLD_EVENT_ON_DELETE_GAMEOBJECT);
}
void Eluna::OnRemove(Creature* creature)
{
if (!ServerEventBindings->HasEvents(WORLD_EVENT_ON_DELETE_CREATURE))
return;
LOCK_ELUNA;
Push(creature);
CallAllFunctions(ServerEventBindings, WORLD_EVENT_ON_DELETE_CREATURE);
}
#endif // _SERVER_HOOKS_H

View file

@ -0,0 +1,191 @@
/*
* 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
*/
#ifndef SPELLMETHODS_H
#define SPELLMETHODS_H
/***
* An instance of a spell, created when the spell is cast by a [Unit].
*/
namespace LuaSpell
{
/**
* Returns `true` if the [Spell] is automatically repeating, `false` otherwise.
*
* @return bool isAutoRepeating
*/
int IsAutoRepeat(Eluna* /*E*/, lua_State* L, Spell* spell)
{
Eluna::Push(L, spell->IsAutoRepeat());
return 1;
}
/**
* Returns the [Unit] that casted the [Spell].
*
* @return [Unit] caster
*/
int GetCaster(Eluna* /*E*/, lua_State* L, Spell* spell)
{
Eluna::Push(L, spell->GetCaster());
return 1;
}
/**
* Returns the cast time of the [Spell].
*
* @return int32 castTime
*/
int GetCastTime(Eluna* /*E*/, lua_State* L, Spell* spell)
{
Eluna::Push(L, spell->GetCastTime());
return 1;
}
/**
* Returns the entry ID of the [Spell].
*
* @return uint32 entryId
*/
int GetEntry(Eluna* /*E*/, lua_State* L, Spell* spell)
{
Eluna::Push(L, spell->m_spellInfo->Id);
return 1;
}
/**
* Returns the power cost of the [Spell].
*
* @return uint32 powerCost
*/
int GetPowerCost(Eluna* /*E*/, lua_State* L, Spell* spell)
{
Eluna::Push(L, spell->GetPowerCost());
return 1;
}
/**
* Returns the spell duration of the [Spell].
*
* @return int32 duration
*/
int GetDuration(Eluna* /*E*/, lua_State* L, Spell* spell)
{
#ifndef TRINITY
Eluna::Push(L, GetSpellDuration(spell->m_spellInfo));
#else
Eluna::Push(L, spell->GetSpellInfo()->GetDuration());
#endif
return 1;
}
/**
* Returns the target destination coordinates of the [Spell].
*
* @return float x : x coordinate of the [Spell]
* @return float y : y coordinate of the [Spell]
* @return float z : z coordinate of the [Spell]
*/
int GetTargetDest(Eluna* /*E*/, lua_State* L, Spell* spell)
{
#ifndef TRINITY
if (!(spell->m_targets.m_targetMask & TARGET_FLAG_DEST_LOCATION))
return 3;
float x, y, z;
spell->m_targets.getDestination(x, y, z);
#else
if (!spell->m_targets.HasDst())
return 3;
float x, y, z;
spell->m_targets.GetDstPos()->GetPosition(x, y, z);
#endif
Eluna::Push(L, x);
Eluna::Push(L, y);
Eluna::Push(L, z);
return 3;
}
/**
* Returns the target [Object] of the [Spell].
*
* The target can be any of the following [Object] types:
* - [Player]
* - [Creature]
* - [GameObject]
* - [Item]
* - [Corpse]
*
* @return [Object] target
*/
int GetTarget(Eluna* /*E*/, lua_State* L, Spell* spell)
{
#ifndef TRINITY
if (GameObject* target = spell->m_targets.getGOTarget())
Eluna::Push(L, target);
else if (Item* target = spell->m_targets.getItemTarget())
Eluna::Push(L, target);
else if (Corpse* target = spell->GetCaster()->GetMap()->GetCorpse(spell->m_targets.getCorpseTargetGuid()))
Eluna::Push(L, target);
else if (Unit* target = spell->m_targets.getUnitTarget())
Eluna::Push(L, target);
#else
if (GameObject* target = spell->m_targets.GetGOTarget())
Eluna::Push(L, target);
else if (Item* target = spell->m_targets.GetItemTarget())
Eluna::Push(L, target);
else if (Corpse* target = spell->m_targets.GetCorpseTarget())
Eluna::Push(L, target);
else if (Unit* target = spell->m_targets.GetUnitTarget())
Eluna::Push(L, target);
else if (WorldObject* target = spell->m_targets.GetObjectTarget())
Eluna::Push(L, target);
#endif
return 1;
}
/**
* Sets the [Spell] to automatically repeat.
*
* @param bool repeat : set variable to 'true' for spell to automatically repeat
*/
int SetAutoRepeat(Eluna* /*E*/, lua_State* L, Spell* spell)
{
bool repeat = Eluna::CHECKVAL<bool>(L, 2);
spell->SetAutoRepeat(repeat);
return 0;
}
/**
* Casts the [Spell].
*
* @param bool skipCheck = false : skips initial checks to see if the [Spell] can be casted or not, this is optional
*/
int Cast(Eluna* /*E*/, lua_State* L, Spell* spell)
{
bool skipCheck = Eluna::CHECKVAL<bool>(L, 2, false);
spell->cast(skipCheck);
return 0;
}
/**
* Cancels the [Spell].
*/
int Cancel(Eluna* /*E*/, lua_State* /*L*/, Spell* spell)
{
spell->cancel();
return 0;
}
/**
* Finishes the [Spell].
*/
int Finish(Eluna* /*E*/, lua_State* /*L*/, Spell* spell)
{
spell->finish();
return 0;
}
};
#endif

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,78 @@
/*
* 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
*/
#ifndef _VEHICLE_HOOKS_H
#define _VEHICLE_HOOKS_H
#include "Hooks.h"
#include "HookHelpers.h"
#include "LuaEngine.h"
#include "ElunaBinding.h"
#include "ElunaTemplate.h"
#ifndef CLASSIC
#ifndef TBC
using namespace Hooks;
// Vehicle
void Eluna::OnInstall(Vehicle* vehicle)
{
if (!VehicleEventBindings->HasEvents(VEHICLE_EVENT_ON_INSTALL))
return;
LOCK_ELUNA;
Push(vehicle);
CallAllFunctions(VehicleEventBindings, VEHICLE_EVENT_ON_INSTALL);
}
void Eluna::OnUninstall(Vehicle* vehicle)
{
if (!VehicleEventBindings->HasEvents(VEHICLE_EVENT_ON_UNINSTALL))
return;
LOCK_ELUNA;
Push(vehicle);
CallAllFunctions(VehicleEventBindings, VEHICLE_EVENT_ON_UNINSTALL);
}
void Eluna::OnInstallAccessory(Vehicle* vehicle, Creature* accessory)
{
if (!VehicleEventBindings->HasEvents(VEHICLE_EVENT_ON_INSTALL_ACCESSORY))
return;
LOCK_ELUNA;
Push(vehicle);
Push(accessory);
CallAllFunctions(VehicleEventBindings, VEHICLE_EVENT_ON_INSTALL_ACCESSORY);
}
void Eluna::OnAddPassenger(Vehicle* vehicle, Unit* passenger, int8 seatId)
{
if (!VehicleEventBindings->HasEvents(VEHICLE_EVENT_ON_ADD_PASSENGER))
return;
LOCK_ELUNA;
Push(vehicle);
Push(passenger);
Push(seatId);
CallAllFunctions(VehicleEventBindings, VEHICLE_EVENT_ON_ADD_PASSENGER);
}
void Eluna::OnRemovePassenger(Vehicle* vehicle, Unit* passenger)
{
if (!VehicleEventBindings->HasEvents(VEHICLE_EVENT_ON_REMOVE_PASSENGER))
return;
LOCK_ELUNA;
Push(vehicle);
Push(passenger);
CallAllFunctions(VehicleEventBindings, VEHICLE_EVENT_ON_REMOVE_PASSENGER);
}
#endif // CLASSIC
#endif // TBC
#endif // _VEHICLE_HOOKS_H

View file

@ -0,0 +1,82 @@
/*
* 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
*/
#ifndef VEHICLEMETHODS_H
#define VEHICLEMETHODS_H
#ifndef CLASSIC
#ifndef TBC
namespace LuaVehicle
{
/* BOOLEAN */
int IsOnBoard(Eluna* /*E*/, lua_State* L, Vehicle* vehicle)
{
Unit* passenger = Eluna::CHECKOBJ<Unit>(L, 2);
#ifndef TRINITY
Eluna::Push(L, vehicle->HasOnBoard(passenger));
#else
Eluna::Push(L, passenger->IsOnVehicle(vehicle->GetBase()));
#endif
return 1;
}
/* GETTERS */
int GetOwner(Eluna* /*E*/, lua_State* L, Vehicle* vehicle)
{
#ifndef TRINITY
Eluna::Push(L, vehicle->GetOwner());
#else
Eluna::Push(L, vehicle->GetBase());
#endif
return 1;
}
int GetEntry(Eluna* /*E*/, lua_State* L, Vehicle* vehicle)
{
#ifndef TRINITY
Eluna::Push(L, vehicle->GetVehicleEntry()->m_ID);
#else
Eluna::Push(L, vehicle->GetVehicleInfo()->m_ID);
#endif
return 1;
}
int GetPassenger(Eluna* /*E*/, lua_State* L, Vehicle* vehicle)
{
int8 seatId = Eluna::CHECKVAL<int8>(L, 2);
Eluna::Push(L, vehicle->GetPassenger(seatId));
return 1;
}
/* OTHER */
int AddPassenger(Eluna* /*E*/, lua_State* L, Vehicle* vehicle)
{
Unit* passenger = Eluna::CHECKOBJ<Unit>(L, 2);
int8 seatId = Eluna::CHECKVAL<int8>(L, 3);
#ifndef TRINITY
if (vehicle->CanBoard(passenger))
vehicle->Board(passenger, seatId);
#else
vehicle->AddPassenger(passenger, seatId);
#endif
return 0;
}
int RemovePassenger(Eluna* /*E*/, lua_State* L, Vehicle* vehicle)
{
Unit* passenger = Eluna::CHECKOBJ<Unit>(L, 2);
#ifndef TRINITY
vehicle->UnBoard(passenger, false);
#else
vehicle->RemovePassenger(passenger);
#endif
return 0;
}
}
#endif
#endif
#endif

View file

@ -0,0 +1,797 @@
/*
* 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
*/
#ifndef WORLDOBJECTMETHODS_H
#define WORLDOBJECTMETHODS_H
namespace LuaWorldObject
{
/**
* Returns the name of the [WorldObject]
*
* @return string name
*/
int GetName(Eluna* /*E*/, lua_State* L, WorldObject* obj)
{
Eluna::Push(L, obj->GetName());
return 1;
}
/**
* Returns the current [Map] object of the [WorldObject]
*
* @return [Map] mapObject
*/
int GetMap(Eluna* /*E*/, lua_State* L, WorldObject* obj)
{
Eluna::Push(L, obj->GetMap());
return 1;
}
#if (!defined(TBC) && !defined(CLASSIC))
/**
* Returns the current phase of the [WorldObject]
*
* @return uint32 phase
*/
int GetPhaseMask(Eluna* /*E*/, lua_State* L, WorldObject* obj)
{
Eluna::Push(L, obj->GetPhaseMask());
return 1;
}
#endif
/**
* Returns the current instance ID of the [WorldObject]
*
* @return uint32 instanceId
*/
int GetInstanceId(Eluna* /*E*/, lua_State* L, WorldObject* obj)
{
Eluna::Push(L, obj->GetInstanceId());
return 1;
}
/**
* Returns the current area ID of the [WorldObject]
*
* @return uint32 areaId
*/
int GetAreaId(Eluna* /*E*/, lua_State* L, WorldObject* obj)
{
Eluna::Push(L, obj->GetAreaId());
return 1;
}
/**
* Returns the current zone ID of the [WorldObject]
*
* @return uint32 zoneId
*/
int GetZoneId(Eluna* /*E*/, lua_State* L, WorldObject* obj)
{
Eluna::Push(L, obj->GetZoneId());
return 1;
}
/**
* Returns the current map ID of the [WorldObject]
*
* @return uint32 mapId
*/
int GetMapId(Eluna* /*E*/, lua_State* L, WorldObject* obj)
{
Eluna::Push(L, obj->GetMapId());
return 1;
}
/**
* Returns the current X coordinate of the [WorldObject]
*
* @return float x
*/
int GetX(Eluna* /*E*/, lua_State* L, WorldObject* obj)
{
Eluna::Push(L, obj->GetPositionX());
return 1;
}
/**
* Returns the current Y coordinate of the [WorldObject]
*
* @return float y
*/
int GetY(Eluna* /*E*/, lua_State* L, WorldObject* obj)
{
Eluna::Push(L, obj->GetPositionY());
return 1;
}
/**
* Returns the current Z coordinate of the [WorldObject]
*
* @return float z
*/
int GetZ(Eluna* /*E*/, lua_State* L, WorldObject* obj)
{
Eluna::Push(L, obj->GetPositionZ());
return 1;
}
/**
* Returns the current orientation of the [WorldObject]
*
* @return float orientation / facing
*/
int GetO(Eluna* /*E*/, lua_State* L, WorldObject* obj)
{
Eluna::Push(L, obj->GetOrientation());
return 1;
}
/**
* Returns the coordinates and orientation of the [WorldObject]
*
* @return float x : x coordinate of the [WorldObject]
* @return float y : y coordinate of the [WorldObject]
* @return float z : z coordinate (height) of the [WorldObject]
* @return float o : facing / orientation of the [WorldObject]
*/
int GetLocation(Eluna* /*E*/, lua_State* L, WorldObject* obj)
{
Eluna::Push(L, obj->GetPositionX());
Eluna::Push(L, obj->GetPositionY());
Eluna::Push(L, obj->GetPositionZ());
Eluna::Push(L, obj->GetOrientation());
return 4;
}
/**
* Returns the nearest [Player] object in sight of the [WorldObject] or within the given range
*
* @param float range = 533.33333 : optionally set range. Default range is grid size
*
* @return [Player] nearestPlayer
*/
int GetNearestPlayer(Eluna* /*E*/, lua_State* L, WorldObject* obj)
{
float range = Eluna::CHECKVAL<float>(L, 2, SIZE_OF_GRIDS);
Unit* target = NULL;
ElunaUtil::WorldObjectInRangeCheck checker(true, obj, range, TYPEMASK_PLAYER);
#ifndef TRINITY
MaNGOS::UnitLastSearcher<ElunaUtil::WorldObjectInRangeCheck> searcher(target, checker);
Cell::VisitWorldObjects(obj, searcher, range);
#else
Trinity::UnitLastSearcher<ElunaUtil::WorldObjectInRangeCheck> searcher(obj, target, checker);
obj->VisitNearbyObject(range, searcher);
#endif
Eluna::Push(L, target);
return 1;
}
/**
* Returns the nearest [GameObject] object in sight of the [WorldObject] or within the given range and/or with a specific entry ID
*
* @param float range = 533.33333 : optionally set range. Default range is grid size
* @param uint32 entryId = 0 : optionally set entry ID of game object to find
*
* @return [GameObject] nearestGameObject
*/
int GetNearestGameObject(Eluna* /*E*/, lua_State* L, WorldObject* obj)
{
float range = Eluna::CHECKVAL<float>(L, 2, SIZE_OF_GRIDS);
uint32 entry = Eluna::CHECKVAL<uint32>(L, 3, 0);
GameObject* target = NULL;
ElunaUtil::WorldObjectInRangeCheck checker(true, obj, range, TYPEMASK_GAMEOBJECT, entry);
#ifndef TRINITY
MaNGOS::GameObjectLastSearcher<ElunaUtil::WorldObjectInRangeCheck> searcher(target, checker);
Cell::VisitGridObjects(obj, searcher, range);
#else
Trinity::GameObjectLastSearcher<ElunaUtil::WorldObjectInRangeCheck> searcher(obj, target, checker);
obj->VisitNearbyObject(range, searcher);
#endif
Eluna::Push(L, target);
return 1;
}
/**
* Returns the nearest [Creature] object in sight of the [WorldObject] or within the given range and/or with a specific entry ID
*
* @param float range = 533.33333 : optionally set range. Default range is grid size
* @param uint32 entryId = 0 : optionally set entry ID of creature to find
*
* @return [Creature] nearestCreature
*/
int GetNearestCreature(Eluna* /*E*/, lua_State* L, WorldObject* obj)
{
float range = Eluna::CHECKVAL<float>(L, 2, SIZE_OF_GRIDS);
uint32 entry = Eluna::CHECKVAL<uint32>(L, 3, 0);
Creature* target = NULL;
ElunaUtil::WorldObjectInRangeCheck checker(true, obj, range, TYPEMASK_UNIT, entry);
#ifndef TRINITY
MaNGOS::CreatureLastSearcher<ElunaUtil::WorldObjectInRangeCheck> searcher(target, checker);
Cell::VisitGridObjects(obj, searcher, range);
#else
Trinity::CreatureLastSearcher<ElunaUtil::WorldObjectInRangeCheck> searcher(obj, target, checker);
obj->VisitNearbyObject(range, searcher);
#endif
Eluna::Push(L, target);
return 1;
}
/**
* Returns a table of [Player] objects in sight of the [WorldObject] or within the given range
*
* @param float range = 533.33333 : optionally set range. Default range is grid size
*
* @return table playersInRange : table of [Player]s
*/
int GetPlayersInRange(Eluna* /*E*/, lua_State* L, WorldObject* obj)
{
float range = Eluna::CHECKVAL<float>(L, 2, SIZE_OF_GRIDS);
std::list<Player*> list;
ElunaUtil::WorldObjectInRangeCheck checker(false, obj, range, TYPEMASK_PLAYER);
#ifndef TRINITY
MaNGOS::PlayerListSearcher<ElunaUtil::WorldObjectInRangeCheck> searcher(list, checker);
Cell::VisitWorldObjects(obj, searcher, range);
#else
Trinity::PlayerListSearcher<ElunaUtil::WorldObjectInRangeCheck> searcher(obj, list, checker);
obj->VisitNearbyObject(range, searcher);
#endif
lua_newtable(L);
int tbl = lua_gettop(L);
uint32 i = 0;
for (std::list<Player*>::const_iterator it = list.begin(); it != list.end(); ++it)
{
Eluna::Push(L, ++i);
Eluna::Push(L, *it);
lua_settable(L, tbl);
}
lua_settop(L, tbl);
return 1;
}
/**
* Returns a table of [Creature] objects in sight of the [WorldObject] or within the given range and/or with a specific entry ID
*
* @param float range = 533.33333 : optionally set range. Default range is grid size
* @param uint32 entryId = 0 : optionally set entry ID of creatures to find
*
* @return table creaturesInRange : table of [Creature]s
*/
int GetCreaturesInRange(Eluna* /*E*/, lua_State* L, WorldObject* obj)
{
float range = Eluna::CHECKVAL<float>(L, 2, SIZE_OF_GRIDS);
uint32 entry = Eluna::CHECKVAL<uint32>(L, 3, 0);
std::list<Creature*> list;
ElunaUtil::WorldObjectInRangeCheck checker(false, obj, range, TYPEMASK_UNIT, entry);
#ifndef TRINITY
MaNGOS::CreatureListSearcher<ElunaUtil::WorldObjectInRangeCheck> searcher(list, checker);
Cell::VisitGridObjects(obj, searcher, range);
#else
Trinity::CreatureListSearcher<ElunaUtil::WorldObjectInRangeCheck> searcher(obj, list, checker);
obj->VisitNearbyObject(range, searcher);
#endif
lua_newtable(L);
int tbl = lua_gettop(L);
uint32 i = 0;
for (std::list<Creature*>::const_iterator it = list.begin(); it != list.end(); ++it)
{
Eluna::Push(L, ++i);
Eluna::Push(L, *it);
lua_settable(L, tbl);
}
lua_settop(L, tbl);
return 1;
}
/**
* Returns a table of [GameObject] objects in sight of the [WorldObject] or within the given range and/or with a specific entry ID
*
* @param float range = 533.33333 : optionally set range. Default range is grid size
* @param uint32 entryId = 0 : optionally set entry ID of game objects to find
*
* @return table gameObjectsInRange : table of [GameObject]s
*/
int GetGameObjectsInRange(Eluna* /*E*/, lua_State* L, WorldObject* obj)
{
float range = Eluna::CHECKVAL<float>(L, 2, SIZE_OF_GRIDS);
uint32 entry = Eluna::CHECKVAL<uint32>(L, 3, 0);
std::list<GameObject*> list;
ElunaUtil::WorldObjectInRangeCheck checker(false, obj, range, TYPEMASK_GAMEOBJECT, entry);
#ifndef TRINITY
MaNGOS::GameObjectListSearcher<ElunaUtil::WorldObjectInRangeCheck> searcher(list, checker);
Cell::VisitGridObjects(obj, searcher, range);
#else
Trinity::GameObjectListSearcher<ElunaUtil::WorldObjectInRangeCheck> searcher(obj, list, checker);
obj->VisitNearbyObject(range, searcher);
#endif
lua_newtable(L);
int tbl = lua_gettop(L);
uint32 i = 0;
for (std::list<GameObject*>::const_iterator it = list.begin(); it != list.end(); ++it)
{
Eluna::Push(L, ++i);
Eluna::Push(L, *it);
lua_settable(L, tbl);
}
lua_settop(L, tbl);
return 1;
}
/**
* Returns nearest [WorldObject] in sight of the [WorldObject].
* The distance, type, entry and hostility requirements the [WorldObject] must match can be passed.
*
* @param float range = 533.33333 : optionally set range. Default range is grid size
* @param [TypeMask] type = 0 : the [TypeMask] that the [WorldObject] must be. This can contain multiple types. 0 will be ingored
* @param uint32 entry = 0 : the entry of the [WorldObject], 0 will be ingored
* @param uint32 hostile = 0 : specifies whether the [WorldObject] needs to be 1 hostile, 2 friendly or 0 either
*
* @return [WorldObject] worldObject
*/
int GetNearObject(Eluna* /*E*/, lua_State* L, WorldObject* obj)
{
float range = Eluna::CHECKVAL<float>(L, 2, SIZE_OF_GRIDS);
uint16 type = Eluna::CHECKVAL<uint16>(L, 3, 0); // TypeMask
uint32 entry = Eluna::CHECKVAL<uint32>(L, 4, 0);
uint32 hostile = Eluna::CHECKVAL<uint32>(L, 5, 0); // 0 none, 1 hostile, 2 friendly
float x, y, z;
obj->GetPosition(x, y, z);
ElunaUtil::WorldObjectInRangeCheck checker(true, obj, range, type, entry, hostile);
WorldObject* target = NULL;
#ifndef TRINITY
MaNGOS::WorldObjectLastSearcher<ElunaUtil::WorldObjectInRangeCheck> searcher(target, checker);
Cell::VisitAllObjects(obj, searcher, range);
#else
Trinity::WorldObjectLastSearcher<ElunaUtil::WorldObjectInRangeCheck> searcher(obj, target, checker);
obj->VisitNearbyObject(range, searcher);
#endif
Eluna::Push(L, target);
return 1;
}
/**
* Returns a table of [WorldObject]s in sight of the [WorldObject].
* The distance, type, entry and hostility requirements the [WorldObject] must match can be passed.
*
* @param float range = 533.33333 : optionally set range. Default range is grid size
* @param [TypeMask] type = 0 : the [TypeMask] that the [WorldObject] must be. This can contain multiple types. 0 will be ingored
* @param uint32 entry = 0 : the entry of the [WorldObject], 0 will be ingored
* @param uint32 hostile = 0 : specifies whether the [WorldObject] needs to be 1 hostile, 2 friendly or 0 either
*
* @return table worldObjectList : table of [WorldObject]s
*/
int GetNearObjects(Eluna* /*E*/, lua_State* L, WorldObject* obj)
{
float range = Eluna::CHECKVAL<float>(L, 2, SIZE_OF_GRIDS);
uint16 type = Eluna::CHECKVAL<uint16>(L, 3, 0); // TypeMask
uint32 entry = Eluna::CHECKVAL<uint32>(L, 4, 0);
uint32 hostile = Eluna::CHECKVAL<uint32>(L, 5, 0); // 0 none, 1 hostile, 2 friendly
float x, y, z;
obj->GetPosition(x, y, z);
ElunaUtil::WorldObjectInRangeCheck checker(false, obj, range, type, entry, hostile);
std::list<WorldObject*> list;
#ifndef TRINITY
MaNGOS::WorldObjectListSearcher<ElunaUtil::WorldObjectInRangeCheck> searcher(list, checker);
Cell::VisitAllObjects(obj, searcher, range);
#else
Trinity::WorldObjectListSearcher<ElunaUtil::WorldObjectInRangeCheck> searcher(obj, list, checker);
obj->VisitNearbyObject(range, searcher);
#endif
lua_newtable(L);
int tbl = lua_gettop(L);
uint32 i = 0;
for (std::list<WorldObject*>::const_iterator it = list.begin(); it != list.end(); ++it)
{
Eluna::Push(L, ++i);
Eluna::Push(L, *it);
lua_settable(L, tbl);
}
lua_settop(L, tbl);
return 1;
}
/**
* Returns the distance from this [WorldObject] to another [WorldObject], or from this [WorldObject] to a point in 3d space.
*
* The function takes into account the given object sizes. See also [WorldObject:GetExactDistance], [WorldObject:GetDistance2d]
*
* @proto dist = (obj)
* @proto dist = (x, y, z)
*
* @param [WorldObject] obj
* @param float x : the X-coordinate of the point
* @param float y : the Y-coordinate of the point
* @param float z : the Z-coordinate of the point
*
* @return float dist : the distance in yards
*/
int GetDistance(Eluna* /*E*/, lua_State* L, WorldObject* obj)
{
WorldObject* target = Eluna::CHECKOBJ<WorldObject>(L, 2, false);
if (target && target->IsInWorld())
Eluna::Push(L, obj->GetDistance(target));
else
{
float X = Eluna::CHECKVAL<float>(L, 2);
float Y = Eluna::CHECKVAL<float>(L, 3);
float Z = Eluna::CHECKVAL<float>(L, 4);
Eluna::Push(L, obj->GetDistance(X, Y, Z));
}
return 1;
}
/**
* Returns the distance from this [WorldObject] to another [WorldObject], or from this [WorldObject] to a point in 3d space.
*
* The function does not take into account the given object sizes, which means only the object coordinates are compared. See also [WorldObject:GetDistance], [WorldObject:GetDistance2d]
*
* @proto dist = (obj)
* @proto dist = (x, y, z)
*
* @param [WorldObject] obj
* @param float x : the X-coordinate of the point
* @param float y : the Y-coordinate of the point
* @param float z : the Z-coordinate of the point
*
* @return float dist : the distance in yards
*/
int GetExactDistance(Eluna* /*E*/, lua_State* L, WorldObject* obj)
{
float x, y, z;
obj->GetPosition(x, y, z);
WorldObject* target = Eluna::CHECKOBJ<WorldObject>(L, 2, false);
if (target && target->IsInWorld())
{
float x2, y2, z2;
target->GetPosition(x2, y2, z2);
x -= x2;
y -= y2;
z -= z2;
}
else
{
x -= Eluna::CHECKVAL<float>(L, 2);
y -= Eluna::CHECKVAL<float>(L, 3);
z -= Eluna::CHECKVAL<float>(L, 4);
}
Eluna::Push(L, std::sqrt(x*x + y*y + z*z));
return 1;
}
/**
* Returns the distance from this [WorldObject] to another [WorldObject], or from this [WorldObject] to a point in 2d space.
*
* The function takes into account the given object sizes. See also [WorldObject:GetDistance], [WorldObject:GetExactDistance2d]
*
* @proto dist = (obj)
* @proto dist = (x, y)
*
* @param [WorldObject] obj
* @param float x : the X-coordinate of the point
* @param float y : the Y-coordinate of the point
*
* @return float dist : the distance in yards
*/
int GetDistance2d(Eluna* /*E*/, lua_State* L, WorldObject* obj)
{
WorldObject* target = Eluna::CHECKOBJ<WorldObject>(L, 2, false);
if (target && target->IsInWorld())
Eluna::Push(L, obj->GetDistance2d(target));
else
{
float X = Eluna::CHECKVAL<float>(L, 2);
float Y = Eluna::CHECKVAL<float>(L, 3);
Eluna::Push(L, obj->GetDistance2d(X, Y));
}
return 1;
}
/**
* Returns the distance from this [WorldObject] to another [WorldObject], or from this [WorldObject] to a point in 2d space.
*
* The function does not take into account the given object sizes, which means only the object coordinates are compared. See also [WorldObject:GetDistance], [WorldObject:GetDistance2d]
*
* @proto dist = (obj)
* @proto dist = (x, y)
*
* @param [WorldObject] obj
* @param float x : the X-coordinate of the point
* @param float y : the Y-coordinate of the point
*
* @return float dist : the distance in yards
*/
int GetExactDistance2d(Eluna* /*E*/, lua_State* L, WorldObject* obj)
{
float x, y, z;
obj->GetPosition(x, y, z);
WorldObject* target = Eluna::CHECKOBJ<WorldObject>(L, 2, false);
if (target && target->IsInWorld())
{
float x2, y2, z2;
target->GetPosition(x2, y2, z2);
x -= x2;
y -= y2;
}
else
{
x -= Eluna::CHECKVAL<float>(L, 2);
y -= Eluna::CHECKVAL<float>(L, 3);
}
Eluna::Push(L, std::sqrt(x*x + y*y));
return 1;
}
/**
* Returns the x, y and z of a point dist away from the [WorldObject].
*
* @param float distance : specifies the distance of the point from the [WorldObject] in yards
* @param float angle : specifies the angle of the point relative to the orientation / facing of the [WorldObject] in radians
*
* @return float x
* @return float y
* @return float z
*/
int GetRelativePoint(Eluna* /*E*/, lua_State* L, WorldObject* obj)
{
float dist = Eluna::CHECKVAL<float>(L, 2);
float rad = Eluna::CHECKVAL<float>(L, 3);
float x, y, z;
obj->GetClosePoint(x, y, z, 0.0f, dist, rad);
Eluna::Push(L, x);
Eluna::Push(L, y);
Eluna::Push(L, z);
return 3;
}
/**
* Returns the angle between this [WorldObject] and another [WorldObject] or a point.
*
* The angle is the angle between two points and orientation will be ignored.
*
* @proto dist = (obj)
* @proto dist = (x, y)
*
* @param [WorldObject] object
* @param float x
* @param float y
*
* @return float angle : angle in radians in range 0..2*pi
*/
int GetAngle(Eluna* /*E*/, lua_State* L, WorldObject* obj)
{
WorldObject* target = Eluna::CHECKOBJ<WorldObject>(L, 2, false);
if (target && target->IsInWorld())
Eluna::Push(L, obj->GetAngle(target));
else
{
float x = Eluna::CHECKVAL<float>(L, 2);
float y = Eluna::CHECKVAL<float>(L, 3);
Eluna::Push(L, obj->GetAngle(x, y));
}
return 1;
}
/**
* Sends a [WorldPacket] to [Player]s in sight of the [WorldObject].
*
* @param [WorldPacket] packet
*/
int SendPacket(Eluna* /*E*/, lua_State* L, WorldObject* obj)
{
WorldPacket* data = Eluna::CHECKOBJ<WorldPacket>(L, 2);
obj->SendMessageToSet(data, true);
return 0;
}
/**
* Spawns a [GameObject] at specified location.
*
* @param uint32 entry : [GameObject] entry ID
* @param float x
* @param float y
* @param float z
* @param float o
* @param uint32 respawnDelay = 30 : respawn time in seconds
* @return [GameObject] gameObject
*/
int SummonGameObject(Eluna* /*E*/, lua_State* L, WorldObject* obj)
{
uint32 entry = Eluna::CHECKVAL<uint32>(L, 2);
float x = Eluna::CHECKVAL<float>(L, 3);
float y = Eluna::CHECKVAL<float>(L, 4);
float z = Eluna::CHECKVAL<float>(L, 5);
float o = Eluna::CHECKVAL<float>(L, 6);
uint32 respawnDelay = Eluna::CHECKVAL<uint32>(L, 7, 30);
#ifndef TRINITY
Eluna::Push(L, obj->SummonGameObject(entry, x, y, z, o, respawnDelay));
#else
Eluna::Push(L, obj->SummonGameObject(entry, x, y, z, o, 0, 0, 0, 0, respawnDelay));
#endif
return 1;
}
/**
* Spawns the creature at specified location.
*
* @param uint32 entry : [Creature]'s entry ID
* @param float x
* @param float y
* @param float z
* @param float o
* @param [TempSummonType] spawnType = MANUAL_DESPAWN : defines how and when the creature despawns
* @param uint32 despawnTimer = 0 : despawn time in milliseconds
* @return [Creature] spawnedCreature
*/
int SpawnCreature(Eluna* /*E*/, lua_State* L, WorldObject* obj)
{
uint32 entry = Eluna::CHECKVAL<uint32>(L, 2);
float x = Eluna::CHECKVAL<float>(L, 3);
float y = Eluna::CHECKVAL<float>(L, 4);
float z = Eluna::CHECKVAL<float>(L, 5);
float o = Eluna::CHECKVAL<float>(L, 6);
uint32 spawnType = Eluna::CHECKVAL<uint32>(L, 7, 8);
uint32 despawnTimer = Eluna::CHECKVAL<uint32>(L, 8, 0);
TempSummonType type;
switch (spawnType)
{
case 1:
type = TEMPSUMMON_TIMED_OR_DEAD_DESPAWN;
break;
case 2:
type = TEMPSUMMON_TIMED_OR_CORPSE_DESPAWN;
break;
case 3:
type = TEMPSUMMON_TIMED_DESPAWN;
break;
case 4:
#ifdef TRINITY
type = TEMPSUMMON_TIMED_DESPAWN_OUT_OF_COMBAT;
#else
type = TEMPSUMMON_TIMED_OOC_DESPAWN;
#endif
break;
case 5:
type = TEMPSUMMON_CORPSE_DESPAWN;
break;
case 6:
type = TEMPSUMMON_CORPSE_TIMED_DESPAWN;
break;
case 7:
type = TEMPSUMMON_DEAD_DESPAWN;
break;
case 8:
type = TEMPSUMMON_MANUAL_DESPAWN;
break;
#ifndef TRINITY
case 9:
type = TEMPSUMMON_TIMED_OOC_OR_CORPSE_DESPAWN;
break;
case 10:
type = TEMPSUMMON_TIMED_OOC_OR_DEAD_DESPAWN;
break;
#endif
default:
return luaL_argerror(L, 7, "valid SpawnType expected");
}
Eluna::Push(L, obj->SummonCreature(entry, x, y, z, o, type, despawnTimer));
return 1;
}
/**
* Registers a timed event to the [WorldObject]
* When the passed function is called, the parameters `(eventId, delay, repeats, worldobject)` are passed to it.
* Repeats will decrease on each call if the event does not repeat indefinitely
*
* Note that for [Creature] and [GameObject] the timed event timer ticks only if the creature is in sight of someone
* For all [WorldObject]s the timed events are removed when the object is destoryed. This means that for example a [Player]'s events are removed on logout.
*
* @param function function : function to trigger when the time has passed
* @param uint32 delay : set time in milliseconds for the event to trigger
* @param uint32 repeats : how many times for the event to repeat, 0 is infinite
* @return int eventId : unique ID for the timed event used to cancel it or nil
*/
int RegisterEvent(Eluna* /*E*/, lua_State* L, WorldObject* obj)
{
luaL_checktype(L, 2, LUA_TFUNCTION);
uint32 delay = Eluna::CHECKVAL<uint32>(L, 3);
uint32 repeats = Eluna::CHECKVAL<uint32>(L, 4);
lua_pushvalue(L, 2);
int functionRef = luaL_ref(L, LUA_REGISTRYINDEX);
if (functionRef != LUA_REFNIL && functionRef != LUA_NOREF)
{
obj->elunaEvents->AddEvent(functionRef, delay, repeats);
Eluna::Push(L, functionRef);
}
return 1;
}
/**
* Removes the timed event from a [WorldObject] by the specified event ID
*
* @param int eventId : event Id to remove
*/
int RemoveEventById(Eluna* /*E*/, lua_State* L, WorldObject* obj)
{
int eventId = Eluna::CHECKVAL<int>(L, 2);
obj->elunaEvents->SetState(eventId, LUAEVENT_STATE_ABORT);
return 0;
}
/**
* Removes all timed events from a [WorldObject]
*
*/
int RemoveEvents(Eluna* /*E*/, lua_State* /*L*/, WorldObject* obj)
{
obj->elunaEvents->SetStates(LUAEVENT_STATE_ABORT);
return 0;
}
/**
* Returns true if the given [WorldObject] or coordinates are in the [WorldObject]'s line of sight
*
* @proto isInLoS = (worldobject)
* @proto isInLoS = (x, y, z)
*
* @param [WorldObject] worldobject
* @param float x
* @param float y
* @param float z
* @return bool isInLoS
*/
int IsWithinLoS(Eluna* /*E*/, lua_State* L, WorldObject* obj)
{
WorldObject* target = Eluna::CHECKOBJ<WorldObject>(L, 2, false);
if (target)
Eluna::Push(L, obj->IsWithinLOSInMap(target));
else
{
float x = Eluna::CHECKVAL<float>(L, 2);
float y = Eluna::CHECKVAL<float>(L, 3);
float z = Eluna::CHECKVAL<float>(L, 4);
Eluna::Push(L, obj->IsWithinLOS(x, y, z));
}
return 1;
}
};
#endif

View file

@ -0,0 +1,308 @@
/*
* 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
*/
#ifndef WORLDPACKETMETHODS_H
#define WORLDPACKETMETHODS_H
/***
* A packet used to pass messages between the server and a client.
*
* Each packet has an opcode that determines the type of message being sent,
* e.g. if a CMSG_LOGOUT_REQUEST packet is sent to the server,
* the client has sent a message that its [Player] wants to logout.
*
* The packet can contain further data, the format of which depends on the opcode.
*/
namespace LuaPacket
{
/**
* Returns the opcode of the [WorldPacket].
*
* @return uint16 opcode
*/
int GetOpcode(Eluna* /*E*/, lua_State* L, WorldPacket* packet)
{
Eluna::Push(L, packet->GetOpcode());
return 1;
}
/**
* Returns the size of the [WorldPacket].
*
* @return uint32 size
*/
int GetSize(Eluna* /*E*/, lua_State* L, WorldPacket* packet)
{
Eluna::Push(L, packet->size());
return 1;
}
/**
* Sets the opcode of the [WorldPacket] to the specified opcode.
*
* @param [Opcodes] opcode : see Opcodes.h for all known opcodes
*/
int SetOpcode(Eluna* /*E*/, lua_State* L, WorldPacket* packet)
{
uint32 opcode = Eluna::CHECKVAL<uint32>(L, 2);
if (opcode >= NUM_MSG_TYPES)
return luaL_argerror(L, 2, "valid opcode expected");
packet->SetOpcode((OpcodesList)opcode);
return 0;
}
/**
* Reads and returns a signed 8-bit integer value from the [WorldPacket].
*
* @return int8 value
*/
int ReadByte(Eluna* /*E*/, lua_State* L, WorldPacket* packet)
{
int8 _byte;
(*packet) >> _byte;
Eluna::Push(L, _byte);
return 1;
}
/**
* Reads and returns an unsigned 8-bit integer value from the [WorldPacket].
*
* @return uint8 value
*/
int ReadUByte(Eluna* /*E*/, lua_State* L, WorldPacket* packet)
{
uint8 _ubyte;
(*packet) >> _ubyte;
Eluna::Push(L, _ubyte);
return 1;
}
/**
* Reads and returns a signed 16-bit integer value from the [WorldPacket].
*
* @return int16 value
*/
int ReadShort(Eluna* /*E*/, lua_State* L, WorldPacket* packet)
{
int16 _short;
(*packet) >> _short;
Eluna::Push(L, _short);
return 1;
}
/**
* Reads and returns an unsigned 16-bit integer value from the [WorldPacket].
*
* @return uint16 value
*/
int ReadUShort(Eluna* /*E*/, lua_State* L, WorldPacket* packet)
{
uint16 _ushort;
(*packet) >> _ushort;
Eluna::Push(L, _ushort);
return 1;
}
/**
* Reads and returns a signed 32-bit integer value from the [WorldPacket].
*
* @return int32 value
*/
int ReadLong(Eluna* /*E*/, lua_State* L, WorldPacket* packet)
{
int32 _long;
(*packet) >> _long;
Eluna::Push(L, _long);
return 1;
}
/**
* Reads and returns an unsigned 32-bit integer value from the [WorldPacket].
*
* @return uint32 value
*/
int ReadULong(Eluna* /*E*/, lua_State* L, WorldPacket* packet)
{
uint32 _ulong;
(*packet) >> _ulong;
Eluna::Push(L, _ulong);
return 1;
}
/**
* Reads and returns a single-precision floating-point value from the [WorldPacket].
*
* @return float value
*/
int ReadFloat(Eluna* /*E*/, lua_State* L, WorldPacket* packet)
{
float _val;
(*packet) >> _val;
Eluna::Push(L, _val);
return 1;
}
/**
* Reads and returns a double-precision floating-point value from the [WorldPacket].
*
* @return double value
*/
int ReadDouble(Eluna* /*E*/, lua_State* L, WorldPacket* packet)
{
double _val;
(*packet) >> _val;
Eluna::Push(L, _val);
return 1;
}
/**
* Reads and returns an unsigned 64-bit integer value from the [WorldPacket].
*
* @return uint64 value : value returned as string
*/
int ReadGUID(Eluna* /*E*/, lua_State* L, WorldPacket* packet)
{
uint64 guid;
(*packet) >> guid;
Eluna::Push(L, guid);
return 1;
}
/**
* Reads and returns a string value from the [WorldPacket].
*
* @return string value
*/
int ReadString(Eluna* /*E*/, lua_State* L, WorldPacket* packet)
{
std::string _val;
(*packet) >> _val;
Eluna::Push(L, _val);
return 1;
}
/**
* Writes an unsigned 64-bit integer value to the [WorldPacket].
*
* @param uint64 value : the value to be written to the [WorldPacket]
*/
int WriteGUID(Eluna* /*E*/, lua_State* L, WorldPacket* packet)
{
uint64 guid = Eluna::CHECKVAL<uint64>(L, 2);
(*packet) << guid;
return 0;
}
/**
* Writes a string to the [WorldPacket].
*
* @param string value : the string to be written to the [WorldPacket]
*/
int WriteString(Eluna* /*E*/, lua_State* L, WorldPacket* packet)
{
std::string _val = Eluna::CHECKVAL<std::string>(L, 2);
(*packet) << _val;
return 0;
}
/**
* Writes a signed 8-bit integer value to the [WorldPacket].
*
* @param int8 value : the int8 value to be written to the [WorldPacket]
*/
int WriteByte(Eluna* /*E*/, lua_State* L, WorldPacket* packet)
{
int8 byte = Eluna::CHECKVAL<int8>(L, 2);
(*packet) << byte;
return 0;
}
/**
* Writes an unsigned 8-bit integer value to the [WorldPacket].
*
* @param uint8 value : the uint8 value to be written to the [WorldPacket]
*/
int WriteUByte(Eluna* /*E*/, lua_State* L, WorldPacket* packet)
{
uint8 byte = Eluna::CHECKVAL<uint8>(L, 2);
(*packet) << byte;
return 0;
}
/**
* Writes a signed 16-bit integer value to the [WorldPacket].
*
* @param int16 value : the int16 value to be written to the [WorldPacket]
*/
int WriteShort(Eluna* /*E*/, lua_State* L, WorldPacket* packet)
{
int16 _short = Eluna::CHECKVAL<int16>(L, 2);
(*packet) << _short;
return 0;
}
/**
* Writes an unsigned 16-bit integer value to the [WorldPacket].
*
* @param uint16 value : the uint16 value to be written to the [WorldPacket]
*/
int WriteUShort(Eluna* /*E*/, lua_State* L, WorldPacket* packet)
{
uint16 _ushort = Eluna::CHECKVAL<uint16>(L, 2);
(*packet) << _ushort;
return 0;
}
/**
* Writes a signed 32-bit integer value to the [WorldPacket].
*
* @param int32 value : the int32 value to be written to the [WorldPacket]
*/
int WriteLong(Eluna* /*E*/, lua_State* L, WorldPacket* packet)
{
int32 _long = Eluna::CHECKVAL<int32>(L, 2);
(*packet) << _long;
return 0;
}
/**
* Writes an unsigned 32-bit integer value to the [WorldPacket].
*
* @param uint32 value : the uint32 value to be written to the [WorldPacket]
*/
int WriteULong(Eluna* /*E*/, lua_State* L, WorldPacket* packet)
{
uint32 _ulong = Eluna::CHECKVAL<uint32>(L, 2);
(*packet) << _ulong;
return 0;
}
/**
* Writes a 32-bit floating-point value to the [WorldPacket].
*
* @param float value : the float value to be written to the [WorldPacket]
*/
int WriteFloat(Eluna* /*E*/, lua_State* L, WorldPacket* packet)
{
float _val = Eluna::CHECKVAL<float>(L, 2);
(*packet) << _val;
return 0;
}
/**
* Writes a 64-bit floating-point value to the [WorldPacket].
*
* @param double value : the double value to be written to the [WorldPacket]
*/
int WriteDouble(Eluna* /*E*/, lua_State* L, WorldPacket* packet)
{
double _val = Eluna::CHECKVAL<double>(L, 2);
(*packet) << _val;
return 0;
}
};
#endif

2
src/modules/Eluna/docs/.gitignore vendored Normal file
View file

@ -0,0 +1,2 @@
# Ignore the temporary "build" folder.
build

View file

@ -0,0 +1,19 @@
#Contributing
Eluna uses C for the Lua engine, C++ for the server modifications and system code, Lua for scripting side code and scripts, python for the web documentation generation - but you do not have to be able to code to help.
You can contribute to Eluna in various ways:
* Improve our documentation: [Documentation generation](DOC_GEN.md)
* Create new features or enhance old features: [Eluna source](https://github.com/ElunaLuaEngine/Eluna)
* Notify us about your concerns, problems and needs regarding Eluna: [Issue tracker](https://github.com/ElunaLuaEngine/Eluna/issues)
* Create and improve Lua scripts, systems, releases and guides: [Eluna forum section](http://emudevs.com/forumdisplay.php/15-Eluna-Lua-Engine-%C2%A9)
###Features and documentation
To contribute to the source code and documentation within it, create a pull request for our github repository:
1. [Set up git](https://help.github.com/articles/set-up-git/)
2. [Fork](https://help.github.com/articles/fork-a-repo/) our repository: [Eluna repository](https://github.com/ElunaLuaEngine/Eluna)
3. Create a branch: `git checkout -b mybranch`
4. Make your contribution changes
5. Commit your changes `git commit -a -m "commit message"`
6. Push your commit to github: `git push`
7. Open a [pull request](https://help.github.com/articles/using-pull-requests/)

View file

@ -0,0 +1,165 @@
# Documentation generation
Eluna uses a custom made documentation generator to create it's [web documentation](http://eluna.emudevs.com/).
The generator is written in python by Patman. It works by parsing Eluna's source files for comments and then generates the HTML and javascript for the documentation based on them.
This page guides you through generating the web documentation locally and explains the standards of the documentation comments for you to help us improve our documentation. To contribute with your documentation changes, create a [pull request](https://help.github.com/articles/using-pull-requests/)
# Generating locally
- install [python](https://www.python.org/)(2)
- when installing, tick to install the path variable
- you may need restart afterwards for the installation to properly take effect
- install a package manager like [pip](https://pip.pypa.io/en/latest/)
- if you installed pip and it does not work, restart or try easy_install command
- install the dependencies with manager
- [Jinja2](https://pypi.python.org/pypi/Jinja2)
- [typedecorator](https://pypi.python.org/pypi/typedecorator)
- [markdown](https://pypi.python.org/pypi/Markdown)
- Run in cmd `python -m ElunaDoc` when at `\LuaEngine\docs\`
# Documenting
You can document functions in the Eluna source code. To find examples simply open a method header file like `PlayerMethods.h` and see the comments.
## Templates
Here are some basic templates for a function documentation. When defining a parameter or a return value the type and value name are mandatory, unless the parameter type is `...`, which is used for variable arguments; do not include a name in this case.
```c++
/**
* Short description (about 80 characters long).
*
* @param Type paramName
* @return Type returnName
*/
```
```c++
/**
* Short description (about 80 characters long).
*
* @param Type paramName = defaultValue : parameter description
* @return Type returnName : return value description
*/
```
This is a template for a function that takes in different parameters. When defining a parameter or a return value, the type and value name are mandatory.
```c++
/**
* Short description (about 80 characters long).
*
* @proto returnValue = (object)
* @proto returnValue = (x, y, z)
* @param [WorldObject] object = defaultValue : parameter description
* @param float x = defaultValue : parameter description
* @param float y = defaultValue : parameter description
* @param float z = defaultValue : parameter description
* @return Type returnName : return value description
*/
```
## Standard
A documentation comment block will always start with `/**` and end with `*/`.
All lines start with `*` character followed by one space before any content.
The first paragrph is used as a short description of the function/class, so it should be kept to about 80 characters. The other paragraphs can be as long as desired.
All paragraphs in the description (including the first) should start with a capital letter and end with a period.
**Paragraphs must be separated by an empty line**, e.g.:
```c++
/**
* This is a short description (about 80 characters).
*
* Here's another paragraph with more info. NOTE THE EMPTY LINE BETWEEN THE PARAGRAPHS.
* This does need to be short, and this line is still part of the same paragraph because
* there is no empty line.
*/
```
The parameter and return value descriptions should start with a lowercase letter and not end with a period. If more than one sentence is needed, start the *first* without a capital letter and end the *last* without a period.
Any class, enum or function can be referenced (made a link to) with square brackets.
`[Player]` will reference a player. `[WeatherType]` will reference an enum. `[Player:GetName]` will reference a function.
Use correct indentation with documentation comments.
```c++
/**
* Correct indentation.
*/
```
```c++
/**
* Invalid indentation.
*/
```
## Markdown
You can use [markdown](http://pythonhosted.org//Markdown/) in your descriptions.
For syntax see http://daringfireball.net/projects/markdown/syntax and http://pythonhosted.org//Markdown/#differences
```
/**
* Description.
*
* - list item
* - list item
* - list item
*
*
* // Codeblock
* // Code goes here.
* // Note the 4-space indent.
*
*
* `code line`
*
* *italic*
* **bold**
*/
```
**The above markdown code produces the output below:**
Description.
- list item
- list item
- list item
```
// Codeblock
// Code goes here.
// Note the 4-space indent.
```
`code line`
*italic*
**bold**
## Types
Here are some examples of possible types and most commonly used ones:
```
string
uint64
uint32
uint16
uint8
int64
int32
int16
int8
double
float
...
[EnumName]
[Player]
[Creature]
[GameObject]
[Item]
[Unit]
[WorldObject]
[Object]
```

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.5 KiB

View file

@ -0,0 +1,2 @@
*.pyc
.idea

View file

@ -0,0 +1,163 @@
import os
import shutil
from types import FileType
from jinja2 import Environment, FileSystemLoader
from typedecorator import params, returns
from parser import ClassParser, MethodDoc
import glob
import time
@returns([(str, FileType)])
@params(search_path=str)
def find_class_files(search_path):
"""Find and open all files containing Eluna class methods in `search_path`.
:param search_path: the path to search for Eluna methods in
:return: a list of all files containing Eluna methods, and the name of their respective classes
"""
# Get the current working dir and switch to the search path.
old_dir = os.getcwd()
os.chdir(search_path)
# Search for all files ending in "Methods.h".
method_file_names = glob.glob('*Methods.h')
# Open each file.
method_files = [open(file_name, 'r') for file_name in method_file_names]
# Go back to where we were before.
os.chdir(old_dir)
return method_files
def make_renderer(template_path, link_parser_factory):
"""Return a function that can be used to render Jinja2 templates from the `template_path` directory."""
# Set up jinja2 environment to load templates from the templates folder.
env = Environment(loader=FileSystemLoader(template_path), extensions=['jinja2.ext.with_'])
def inner(template_name, output_path, level, **kwargs):
env.filters['parse_links'], env.filters['parse_data_type'] = link_parser_factory(level)
template = env.get_template(template_name)
static = make_static(level)
root = make_root(level)
currdate = time.strftime("%d/%m/%Y")
with open('build/' + output_path, 'w') as out:
out.write(template.render(level=level, static=static, root=root, currdate=currdate, **kwargs))
return inner
def make_static(level):
return lambda file_name: ('../' * level) + 'static/' + file_name
def make_root(level):
return lambda file_name: ('../' * level) + file_name
if __name__ == '__main__':
# Recreate the build folder and copy static files over.
if os.path.exists('build'):
shutil.rmtree('build')
os.mkdir('build')
shutil.copytree('ElunaDoc/static', 'build/static')
# Load up all files with methods we need to parse.
print 'Finding Eluna method files...'
class_files = find_class_files('../')
# Parse all the method files.
classes = []
for f in class_files:
print 'Parsing file {}...'.format(f.name)
classes.append(ClassParser.parse_file(f))
f.close()
# Sort the classes so they are in the correct order in lists.
classes.sort(key=lambda c: c.name)
def make_parsers(level):
"""Returns a function that parses content for refs to other classes, methods, or enums,
and automatically inserts the correct link.
"""
# Make lists of all class names and method names.
class_names = []
method_names = []
for class_ in classes:
class_names.append('[' + class_.name + ']')
for method in class_.methods:
method_names.append('[' + class_.name + ':' + method.name + ']')
def link_parser(content):
# Replace all occurrencies of &Class:Function and then &Class with a link to given func or class
for name in method_names:
# Take the [] off the front of the method's name.
full_name = name[1:-1]
# Split "Class:Method" into "Class" and "Method".
class_name, method_name = full_name.split(':')
url = '{}{}/{}.html'.format(('../' * level), class_name, method_name)
# Replace occurrencies of &Class:Method with the url created
content = content.replace(name, '<a class="fn" href="{}">{}</a>'.format(url, full_name))
for name in class_names:
# Take the [] off the front of the class's name.
class_name = name[1:-1]
url = '{}{}/index.html'.format(('../' * level), class_name)
# Replace occurrencies of &Class:Method with the url created
content = content.replace(name, '<a class="mod" href="{}">{}</a>'.format(url, class_name))
return content
# Links to the "Programming in Lua" documentation for each Lua type.
lua_type_documentation = {
'nil': 'http://www.lua.org/pil/2.1.html',
'boolean': 'http://www.lua.org/pil/2.2.html',
'number': 'http://www.lua.org/pil/2.3.html',
'string': 'http://www.lua.org/pil/2.4.html',
'table': 'http://www.lua.org/pil/2.5.html',
'function': 'http://www.lua.org/pil/2.6.html',
'...': 'http://www.lua.org/pil/5.2.html',
}
def data_type_parser(content):
# If the type is a Lua type, return a link to Lua documentation.
if content in lua_type_documentation:
url = lua_type_documentation[content]
return '<strong><a href="{}">{}</a></strong>'.format(url, content)
# Otherwise try to build a link to the proper page.
if content in class_names:
class_name = content[1:-1]
url = '{}{}/index.html'.format(('../' * level), class_name)
return '<strong><a class="mod" href="{}">{}</a></strong>'.format(url, class_name)
return content[1:-1]
return link_parser, data_type_parser
# Create the render function with the template path and parser maker.
render = make_renderer('ElunaDoc/templates', make_parsers)
# Render the index.
render('index.html', 'index.html', level=0, classes=classes)
# Render the search index.
render('search-index.js', 'search-index.js', level=0, classes=classes)
for class_ in classes:
print 'Rending pages for class {}...'.format(class_.name)
# Make a folder for the class.
os.mkdir('build/' + class_.name)
index_path = '{}/index.html'.format(class_.name)
# Render the class's index page.
render('class.html', index_path, level=1, classes=classes, current_class=class_)
# Render each method's page.
for method in class_.methods:
method_path = '{}/{}.html'.format(class_.name, method.name)
render('method.html', method_path, level=1, current_class=class_, current_method=method)

View file

@ -0,0 +1,332 @@
import re
from types import FileType
import markdown
from typedecorator import params, returns, Nullable
class ParameterDoc(object):
"""The documentation data of a parameter or return value for an Eluna method."""
# The integer ranges that each C++ type is valid for. None means valid for all numbers.
valid_ranges = {
'float': None,
'double': None,
'int': ('-2,147,483,647', '2,147,483,647'), # This should be -32767..32767, but it's pretty safe to assume 32-bit.
'int8': ('-127', '127'),
'uint8': ('0', '255'),
'int16': ('-32,767', '32,767'),
'uint16': ('0', '65,535'),
'int32': ('-2,147,483,647', '2,147,483,647'),
'uint32': ('0', '4,294,967,295'),
'int64': ('-9,223,372,036,854,775,808', '9,223,372,036,854,775,807'),
'uint64': ('0', '18,446,744,073,709,551,615'),
}
@params(self=object, name=Nullable(unicode), data_type=str, description=unicode, default_value=Nullable(unicode))
def __init__(self, name, data_type, description, default_value=None):
"""If `name` is not provided, the Parameter is a returned value instead of a parameter."""
self.name = name
self.data_type = data_type
self.default_value = default_value
if self.data_type == '...':
self.name = '...'
else:
assert(self.name is not None)
if description:
# Capitalize the first letter, add a period, and parse as Markdown.
self.description = '{}{}. '.format(description[0].capitalize(), description[1:])
self.description = markdown.markdown(self.description)
else:
self.description = ''
# If the data type is a C++ number, convert to Lua number and add range info to description.
if self.data_type in ['float', 'double', 'int', 'int8', 'uint8', 'int16', 'uint16', 'int32', 'uint32']:
range = ParameterDoc.valid_ranges[self.data_type]
if range:
self.description += '<p><em>Valid numbers</em>: integers from {0} to {1}.</p>'.format(range[0], range[1])
else:
self.description += '<p><em>Valid numbers</em>: all decimal numbers.</p>'
self.data_type = 'number'
elif self.data_type == 'bool':
self.data_type = 'boolean'
elif self.data_type == 'int64' or self.data_type == 'uint64':
self.data_type = '[' + self.data_type + ']'
elif not self.data_type in ['nil', 'boolean', 'number', 'string', 'table', 'function', '...'] and self.data_type[:1] != '[':
print "Missing [] from data type `" + self.data_type + "`"
class MethodDoc(object):
"""The documentation data of an Eluna method."""
@params(self=object, name=unicode, description=unicode, prototypes=[unicode], parameters=[ParameterDoc], returned=[ParameterDoc])
def __init__(self, name, description, prototypes, parameters, returned):
self.name = name
self.prototypes = prototypes
self.parameters = parameters
self.returned = returned
# Parse the description as Markdown.
self.description = markdown.markdown(description)
# Pull the first paragraph out of the description as the short description.
self.short_description = self.description.split('</p>')[0][3:]
# If it has a description, it is "documented".
self.documented = self.description != ''
class MangosClassDoc(object):
"""The documentation of a MaNGOS class that has Lua methods."""
@params(self=object, name=unicode, description=unicode, methods=[MethodDoc])
def __init__(self, name, description, methods):
self.name = name
# Parse the description as Markdown.
self.description = markdown.markdown(description)
# Pull the first paragraph out of the description as the short description.
self.short_description = self.description.split('</p>')[0][3:]
# Sort the methods by their names.
self.methods = sorted(methods, key=lambda m: m.name)
# If any of our methods are not documented, we aren't fully documented.
for method in methods:
if not method.documented:
self.fully_documented = False
break
else:
self.fully_documented = True
# In the same vein, if any of our methods are documented, we aren't fully *un*documented.
for method in methods:
if method.documented:
self.fully_undocumented = False
break
else:
self.fully_undocumented = True
class ClassParser(object):
"""Parses a file line-by-line and returns methods when enough information is received to build them."""
# Various regular expressions to parse different parts of the doc string.
# There are used to parse the class's description.
class_start_regex = re.compile(r"\s*/\*\*\*") # The start of class documentation, i.e. /***
class_body_regex = re.compile(r"\s*\*\s*(.*)") # The "body", i.e. a * and optionally some descriptive text.
class_end_regex = re.compile(r"\s*\*/") # The end of the comment portion, i.e. */
# These are used to parse method documentation.
start_regex = re.compile(r"\s*/\*\*") # The start of documentation, i.e. /**
body_regex = re.compile(r"\s*\s?\*\s?(.*)") # The "body", i.e. a * and optionally some descriptive text.
# An extra optional space (\s?) was thrown in to make it different from `class_body_regex`.
param_regex = re.compile(r"""\s*\*\s@param\s # The @param tag starts with opt. whitespace followed by "* @param ".
([^\s]+)\s(\w+)? # The data type, a space, and the name of the param.
(?:\s=\s(\w+))? # The default value: a = surrounded by spaces, followed by text.
(?:\s:\s(.+))? # The description: a colon surrounded by spaces, followed by text.
""", re.X)
# This is the same as the @param tag, minus the default value part.
return_regex = re.compile(r"""\s*\*\s@return\s
([\[\]\w]+)\s(\w+)
(?:\s:\s(.+))?
""", re.X)
proto_regex = re.compile(r"""\s*\*\s@proto\s
([\w\s,]+)? # The list of arguments.
(?:=\s)? # An equals sign and a space separate the args and returns.
(?:\(([\w\s,]+)\))? # The list of return values, in parens.
""", re.X)
comment_end_regex = re.compile(r"\s*\*/") # The end of the comment portion, i.e. */
end_regex = re.compile(r"\s*int\s(\w+)\s*\(") # The end of the documentation, i.e. int MethodName(
def __init__(self, class_name):
assert ClassParser.class_body_regex is not ClassParser.body_regex
# The methods that have been parsed.
self.methods = []
# The name of the class being parsed.
self.class_name = class_name
# The description of the class being parsed.
self.class_description = ''
# Reset the parser's state machine.
self.reset()
def reset(self):
# What the last handled regex was, to determine what the next should be.
self.last_regex = None
# These are used to piece together the next `Method`.
self.description = ''
self.params = []
self.returned = []
self.method_name = None
self.prototypes = []
def handle_class_body(self, match):
text = match.group(1)
self.class_description += text + '\n'
def handle_body(self, match):
text = match.group(1)
self.description += text + '\n'
def handle_param(self, match):
data_type, name, default, description = match.group(1), match.group(2), match.group(3), match.group(4)
self.params.append(ParameterDoc(name, data_type, description, default))
def handle_return(self, match):
data_type, name, description = match.group(1), match.group(2), match.group(3)
self.returned.append(ParameterDoc(name, data_type, description))
def handle_proto(self, match):
return_values, parameters = match.group(1), match.group(2)
parameters = ' '+parameters+' ' if parameters else ''
return_values = return_values + '= ' if return_values else ''
if self.class_name == 'Global':
prototype = '{0}{{0}}({1})'.format(return_values, parameters)
else:
prototype = '{0}{1}:{{0}}({2})'.format(return_values, self.class_name, parameters)
self.prototypes.append(prototype)
def handle_end(self, match):
self.method_name = match.group(1)
def make_prototype(parameters):
if parameters != '':
parameters = ' ' + parameters + ' '
if self.class_name == 'Global':
if self.returned:
return_values = ', '.join([param.name for param in self.returned])
prototype = '{0} = {1}({2})'.format(return_values, self.method_name, parameters)
else:
prototype = '{0}({1})'.format(self.method_name, parameters)
else:
if self.returned:
return_values = ', '.join([param.name for param in self.returned])
prototype = '{0} = {1}:{2}({3})'.format(return_values, self.class_name, self.method_name, parameters)
else:
prototype = '{0}:{1}({2})'.format(self.class_name, self.method_name, parameters)
return prototype
# If there's no prototype, make one with all params and returns.
if not self.prototypes:
# A list of all parameters with default values.
params_with_default = []
# The index of the last non-default parameter.
last_non_default_i = 0
# If False, a parameter WITHOUT a default value follows one WITH a default value.
# In this case, don't bother generating prototypes.
simple_order = True
for i, param in enumerate(self.params):
if param.default_value:
params_with_default.append(param)
else:
last_non_default_i = i
if params_with_default:
simple_order = False
if not params_with_default or not simple_order:
# Just generate one prototype with all the parameters.
parameters = ', '.join([param.name for param in self.params])
self.prototypes.append(make_prototype(parameters))
else:
# Generate a prototype for all the non-default parameters,
# then one for each default parameter with all the previous parameters.
for i in range(last_non_default_i, len(self.params)):
parameters = ', '.join([param.name for param in self.params[:i+1]])
self.prototypes.append(make_prototype(parameters))
else:
# Format the method name into each prototype.
self.prototypes = [proto.format(self.method_name) for proto in self.prototypes]
self.methods.append(MethodDoc(self.method_name, self.description, self.prototypes, self.params, self.returned))
# Table of which handler is used to handle each regular expressions.
regex_handlers = {
class_start_regex: None,
class_body_regex: handle_class_body,
class_end_regex: None,
start_regex: None,
body_regex: handle_body,
param_regex: handle_param,
return_regex: handle_return,
proto_regex: handle_proto,
comment_end_regex: None,
end_regex: handle_end,
}
# Table of which regular expressions can follow the last handled regex.
# `body_regex` must always come LAST when used, since it also matches param, return, and comment_end.
next_regexes = {
None: [class_start_regex, start_regex, end_regex],
class_start_regex: [class_end_regex, class_body_regex],
class_body_regex: [class_end_regex, class_body_regex],
class_end_regex: [],
start_regex: [param_regex, return_regex, proto_regex, comment_end_regex, body_regex],
body_regex: [param_regex, return_regex, proto_regex, comment_end_regex, body_regex],
proto_regex: [param_regex, return_regex, proto_regex, comment_end_regex, body_regex],
param_regex: [param_regex, return_regex, comment_end_regex, body_regex],
return_regex: [return_regex, comment_end_regex],
comment_end_regex: [end_regex],
end_regex: [],
}
@returns(Nullable(MethodDoc))
@params(self=object, line=str)
def next_line(self, line):
"""Parse the next line of the file.
This method returns a `Method` when enough data to form a `Method` has been parsed.
Otherwise, it returns None.
"""
# Get the list of expected regular expressions using the last one handled.
valid_regexes = self.next_regexes[self.last_regex]
# Try to find a match.
for regex in valid_regexes:
match = regex.match(line)
if match:
handler = self.regex_handlers[regex]
if handler:
handler(self, match)
# Not every regex has a handler, but keep track of where we are anyway.
self.last_regex = regex
# Break at the first match.
break
else:
# No valid regex was found, reset everything.
self.reset()
@returns(MangosClassDoc)
def to_class_doc(self):
"""Create an instance of `MangosClassDoc` from the parser's data.
Is called by `parse_file` once parsing is finished.
"""
return MangosClassDoc(self.class_name, self.class_description, self.methods)
@staticmethod
@returns(MangosClassDoc)
@params(file=FileType)
def parse_file(file):
"""Parse the file `file` into a documented class."""
# Get the class name from "ClassMethods.h" by stripping off "Methods.h".
class_name = file.name[:-len('Methods.h')]
parser = ClassParser(class_name)
line = file.readline()
while line:
parser.next_line(line)
line = file.readline()
return parser.to_class_doc()

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2 KiB

File diff suppressed because one or more lines are too long

View file

@ -0,0 +1,520 @@
/**
* Copyright 2013 The Rust Project Developers. See the COPYRIGHT
* file at the top-level directory of this distribution and at
* http://rust-lang.org/COPYRIGHT.
*
* Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
* http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
* <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
* option. This file may not be copied, modified, or distributed
* except according to those terms.
*/
@font-face {
font-family: 'Fira Sans';
font-style: normal;
font-weight: 400;
src: local('Fira Sans'), url("FiraSans-Regular.woff") format('woff');
}
@font-face {
font-family: 'Fira Sans';
font-style: normal;
font-weight: 500;
src: local('Fira Sans Medium'), url("FiraSans-Medium.woff") format('woff');
}
@font-face {
font-family: 'Source Serif Pro';
font-style: normal;
font-weight: 400;
src: local('Source Serif Pro'), url("SourceSerifPro-Regular.woff") format('woff');
}
@font-face {
font-family: 'Source Serif Pro';
font-style: italic;
font-weight: 400;
src: url("Heuristica-Italic.woff") format('woff');
}
@font-face {
font-family: 'Source Serif Pro';
font-style: normal;
font-weight: 700;
src: local('Source Serif Pro Bold'), url("SourceSerifPro-Bold.woff") format('woff');
}
@font-face {
font-family: 'Source Code Pro';
font-style: normal;
font-weight: 400;
src: local('Source Code Pro'), url("SourceCodePro-Regular.woff") format('woff');
}
@font-face {
font-family: 'Source Code Pro';
font-style: normal;
font-weight: 600;
src: local('Source Code Pro Semibold'), url("SourceCodePro-Semibold.woff") format('woff');
}
@import "normalize.css";
* {
-webkit-box-sizing: border-box;
-moz-box-sizing: border-box;
box-sizing: border-box;
}
/* General structure and fonts */
body {
color: #333;
min-width: 500px;
font: 16px/1.4 "Source Serif Pro", "Helvetica Neue", Helvetica, Arial, sans-serif;
margin: 0;
position: relative;
padding: 10px 15px 20px 15px;
}
h1 {
font-size: 1.5em;
}
h2 {
font-size: 1.4em;
}
h3 {
font-size: 1.3em;
}
h1, h2, h3:not(.impl):not(.method), h4:not(.method) {
color: black;
font-weight: 500;
margin: 20px 0 15px 0;
padding-bottom: 6px;
}
h1.fqn {
border-bottom: 1px dashed #D5D5D5;
margin-top: 0;
}
h2, h3:not(.impl):not(.method), h4:not(.method) {
border-bottom: 1px solid #DDDDDD;
}
h3.impl, h3.method, h4.method {
font-weight: 600;
margin-top: 10px;
margin-bottom: 10px;
}
h3.impl, h3.method {
margin-top: 15px;
}
h1, h2, h3, h4, section.sidebar, a.source, .search-input, .content table a, .collapse-toggle {
font-family: "Fira Sans", "Helvetica Neue", Helvetica, Arial, sans-serif;
}
ol, ul {
padding-left: 25px;
}
ul ul, ol ul, ul ol, ol ol {
margin-bottom: 0;
}
p {
margin: 0 0 .6em 0;
}
code, pre {
font-family: "Source Code Pro", Menlo, Monaco, Consolas, "DejaVu Sans Mono", Inconsolata, monospace;
white-space: pre-wrap;
}
.docblock code {
background-color: #F5F5F5;
border-radius: 3px;
padding: 0 0.2em;
}
pre {
background-color: #F5F5F5;
padding: 14px;
}
.source pre {
padding: 20px;
}
.content.source {
margin-top: 50px;
max-width: none;
overflow: visible;
margin-left: 0px;
min-width: 70em;
}
nav.sub {
font-size: 16px;
text-transform: uppercase;
}
.sidebar {
width: 200px;
position: absolute;
left: 0;
top: 0;
min-height: 100%;
}
.content, nav { max-width: 960px; }
/* Everything else */
.js-only, .hidden { display: none; }
.sidebar {
padding: 10px;
}
.sidebar img {
margin: 20px auto;
display: block;
}
.sidebar .location {
font-size: 17px;
margin: 30px 0 20px 0;
background: #e1e1e1;
text-align: center;
color: #333;
}
.block {
padding: 0 10px;
margin-bottom: 14px;
}
.block h2 {
margin-top: 0;
margin-bottom: 8px;
text-align: center;
}
.block a {
display: block;
text-overflow: ellipsis;
overflow: hidden;
line-height: 15px;
padding: 7px 5px;
font-size: 14px;
font-weight: 300;
transition: border 500ms ease-out;
}
.block a:hover {
background: #F5F5F5;
}
.content {
padding: 15px 0;
}
.content.source pre.rust {
white-space: pre;
overflow: auto;
padding-left: 0;
}
.content pre.line-numbers { float: left; border: none; }
.line-numbers span { color: #c67e2d; }
.line-numbers .line-highlighted {
background-color: #f6fdb0;
}
.content .highlighted {
cursor: pointer;
color: #000 !important;
background-color: #ccc;
}
.content .highlighted a { color: #000 !important; }
.content .highlighted.trait { background-color: #fece7e; }
.content .highlighted.mod { background-color: #afc6e4; }
.content .highlighted.enum { background-color: #b4d1b9; }
.content .highlighted.struct { background-color: #e7b1a0; }
.content .highlighted.fn { background-color: #c6afb3; }
.docblock.short.nowrap {
display: block;
overflow: hidden;
white-space: nowrap;
text-overflow: ellipsis;
}
.docblock.short p {
overflow: hidden;
text-overflow: ellipsis;
margin: 0;
}
.docblock.short code { white-space: nowrap; }
.docblock h1, .docblock h2, .docblock h3, .docblock h4, .docblock h5 {
border-bottom: 1px solid #DDD;
}
.docblock h1 { font-size: 1.3em; }
.docblock h2 { font-size: 1.15em; }
.docblock h3, .docblock h4, .docblock h5 { font-size: 1em; }
.content .out-of-band {
float: right;
font-size: 23px;
}
.content table {
border-spacing: 0 5px;
border-collapse: separate;
}
.content td { vertical-align: top; }
.content td:first-child { padding-right: 20px; }
.content td p:first-child { margin-top: 0; }
.content td h1, .content td h2 { margin-left: 0; font-size: 1.1em; }
.content .item-list {
list-style-type: none;
padding: 0;
}
.content .item-list li { margin-bottom: 3px; }
.content .multi-column {
-moz-column-count: 5;
-moz-column-gap: 2.5em;
-webkit-column-count: 5;
-webkit-column-gap: 2.5em;
column-count: 5;
column-gap: 2.5em;
}
.content .multi-column li { width: 100%; display: inline-block; }
.content .method {
font-size: 1em;
position: relative;
}
.content .methods .docblock { margin-left: 40px; }
.content .impl-methods .docblock { margin-left: 40px; }
nav {
border-bottom: 1px solid #e0e0e0;
padding-bottom: 10px;
margin-bottom: 10px;
}
nav.main {
padding: 20px 0;
text-align: center;
}
nav.main .current {
border-top: 1px solid #000;
border-bottom: 1px solid #000;
}
nav.main .separator {
border: 1px solid #000;
display: inline-block;
height: 23px;
margin: 0 20px;
}
nav.sum { text-align: right; }
nav.sub form { display: inline; }
nav, .content {
margin-left: 230px;
}
a {
text-decoration: none;
color: #000;
background: transparent;
}
p a { color: #4e8bca; }
p a:hover { text-decoration: underline; }
.content a.trait, .block a.current.trait { color: #ed9603; }
.content a.mod, .block a.current.mod { color: #4d76ae; }
.content a.enum, .block a.current.enum { color: #5e9766; }
.content a.struct, .block a.current.struct { color: #e53700; }
.content a.fn, .block a.current.fn { color: #8c6067; }
.content .fnname { color: #8c6067; }
.search-input {
width: 100%;
/* Override Normalize.css: we have margins and do
not want to overflow - the `moz` attribute is necessary
until Firefox 29, too early to drop at this point */
-moz-box-sizing: border-box !important;
box-sizing: border-box !important;
outline: none;
border: none;
border-radius: 1px;
color: #555;
margin-top: 5px;
padding: 10px 16px;
font-size: 17px;
box-shadow: 0 0 0 1px #e0e0e0, 0 0 0 2px transparent;
transition: border-color 300ms ease;
transition: border-radius 300ms ease-in-out;
transition: box-shadow 300ms ease-in-out;
}
.search-input:focus {
border-color: #66afe9;
border-radius: 2px;
border: 0;
outline: 0;
box-shadow: 0 0 8px #078dd8;
}
.search-results .desc {
white-space: nowrap;
text-overflow: ellipsis;
overflow: hidden;
display: block;
}
#help {
background: #e9e9e9;
border-radius: 4px;
box-shadow: 0 0 6px rgba(0,0,0,.2);
position: absolute;
top: 300px;
left: 50%;
margin-top: -125px;
margin-left: -275px;
width: 550px;
height: 300px;
border: 1px solid #bfbfbf;
}
#help dt {
float: left;
border-radius: 3px;
border: 1px solid #bfbfbf;
background: #fff;
width: 23px;
text-align: center;
clear: left;
display: block;
margin-top: -1px;
}
#help dd { margin: 5px 33px; }
#help .infos { padding-left: 0; }
#help h1 { margin-top: 0; }
#help div {
width: 50%;
float: left;
padding: 20px;
}
.stability {
border-left: 6px solid;
padding: 3px 6px;
border-radius: 3px;
}
h1 .stability {
text-transform: lowercase;
font-weight: 400;
margin-left: 14px;
padding: 4px 10px;
}
.impl-methods .stability, .methods .stability {
margin-right: 20px;
}
.stability.Deprecated { border-color: #A071A8; color: #82478C; }
.stability.Experimental { border-color: #D46D6A; color: #AA3C39; }
.stability.Unstable { border-color: #D4B16A; color: #AA8439; }
.stability.Stable { border-color: #54A759; color: #2D8632; }
.stability.Frozen { border-color: #009431; color: #007726; }
.stability.Locked { border-color: #0084B6; color: #00668c; }
.stability.Unmarked { border-color: #BBBBBB; }
.summary {
padding-right: 0px;
}
.summary.Deprecated { background-color: #A071A8; }
.summary.Experimental { background-color: #D46D6A; }
.summary.Unstable { background-color: #D4B16A; }
.summary.Stable { background-color: #54A759; }
.summary.Unmarked { background-color: #BBBBBB; }
:target { background: #FDFFD3; }
/* Code highlighting */
pre.rust .kw { color: #8959A8; }
pre.rust .kw-2, pre.rust .prelude-ty { color: #4271AE; }
pre.rust .number, pre.rust .string { color: #718C00; }
pre.rust .self, pre.rust .boolval, pre.rust .prelude-val,
pre.rust .attribute, pre.rust .attribute .ident { color: #C82829; }
pre.rust .comment { color: #8E908C; }
pre.rust .doccomment { color: #4D4D4C; }
pre.rust .macro, pre.rust .macro-nonterminal { color: #3E999F; }
pre.rust .lifetime { color: #B76514; }
.rusttest { display: none; }
pre.rust { position: relative; }
.test-arrow {
display: inline-block;
position: absolute;
top: 0;
right: 10px;
font-size: 150%;
-webkit-transform: scaleX(-1);
transform: scaleX(-1);
}
.methods .section-header {
/* Override parent class attributes. */
border-bottom: none !important;
font-size: 1.1em !important;
margin: 0 0 -5px;
padding: 0;
}
.section-header:hover a:after {
content: '\2002\00a7\2002';
}
/* Media Queries */
@media (max-width: 700px) {
.sidebar {
display: none;
}
.content {
margin-left: 0px;
}
nav.sub {
margin: 0 auto;
}
}
.collapse-toggle {
font-weight: 100;
position: absolute;
left: 13px;
color: #999;
margin-top: 2px;
}
.toggle-wrapper > .collapse-toggle {
left: -24px;
margin-top: 0px;
}
.toggle-wrapper {
position: relative;
}
.toggle-wrapper.collapsed {
height: 1em;
transition: height .2s;
}
.collapse-toggle > .inner {
display: inline-block;
width: 1ch;
text-align: center;
}
.toggle-label {
color: #999;
font-style: italic;
}

View file

@ -0,0 +1,782 @@
// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.
/*jslint browser: true, es5: true */
/*globals $: true, rootPath: true */
(function() {
"use strict";
var resizeTimeout, interval;
$('.js-only').removeClass('js-only');
function getQueryStringParams() {
var params = {};
window.location.search.substring(1).split("&").
map(function(s) {
var pair = s.split("=");
params[decodeURIComponent(pair[0])] =
typeof pair[1] === "undefined" ?
null : decodeURIComponent(pair[1]);
});
return params;
}
function browserSupportsHistoryApi() {
return window.history && typeof window.history.pushState === "function";
}
function resizeShortBlocks() {
if (resizeTimeout) {
clearTimeout(resizeTimeout);
}
resizeTimeout = setTimeout(function() {
var contentWidth = $('.content').width();
$('.docblock.short').width(function() {
return contentWidth - 40 - $(this).prev().width();
}).addClass('nowrap');
$('.summary-column').width(function() {
return contentWidth - 40 - $(this).prev().width();
})
}, 150);
}
resizeShortBlocks();
$(window).on('resize', resizeShortBlocks);
function highlightSourceLines() {
var i, from, to, match = window.location.hash.match(/^#?(\d+)(?:-(\d+))?$/);
if (match) {
from = parseInt(match[1], 10);
to = Math.min(50000, parseInt(match[2] || match[1], 10));
from = Math.min(from, to);
if ($('#' + from).length === 0) {
return;
}
$('#' + from)[0].scrollIntoView();
$('.line-numbers span').removeClass('line-highlighted');
for (i = from; i <= to; ++i) {
$('#' + i).addClass('line-highlighted');
}
}
}
highlightSourceLines();
$(window).on('hashchange', highlightSourceLines);
$(document).on('keyup', function(e) {
if (document.activeElement.tagName === 'INPUT') {
return;
}
if (e.which === 191 && $('#help').hasClass('hidden')) { // question mark
e.preventDefault();
$('#help').removeClass('hidden');
} else if (e.which === 27) { // esc
if (!$('#help').hasClass('hidden')) {
e.preventDefault();
$('#help').addClass('hidden');
} else if (!$('#search').hasClass('hidden')) {
e.preventDefault();
$('#search').addClass('hidden');
$('#main').removeClass('hidden');
}
} else if (e.which === 83) { // S
e.preventDefault();
$('.search-input').focus();
}
}).on('click', function(e) {
if (!$(e.target).closest('#help').length) {
$('#help').addClass('hidden');
}
});
$('.version-selector').on('change', function() {
var i, match,
url = document.location.href,
stripped = '',
len = rootPath.match(/\.\.\//g).length + 1;
for (i = 0; i < len; ++i) {
match = url.match(/\/[^\/]*$/);
if (i < len - 1) {
stripped = match[0] + stripped;
}
url = url.substring(0, url.length - match[0].length);
}
url += '/' + $('.version-selector').val() + stripped;
document.location.href = url;
});
/**
* A function to compute the Levenshtein distance between two strings
* Licensed under the Creative Commons Attribution-ShareAlike 3.0 Unported
* Full License can be found at http://creativecommons.org/licenses/by-sa/3.0/legalcode
* This code is an unmodified version of the code written by Marco de Wit
* and was found at http://stackoverflow.com/a/18514751/745719
*/
var levenshtein = (function() {
var row2 = [];
return function(s1, s2) {
if (s1 === s2) {
return 0;
} else {
var s1_len = s1.length, s2_len = s2.length;
if (s1_len && s2_len) {
var i1 = 0, i2 = 0, a, b, c, c2, row = row2;
while (i1 < s1_len)
row[i1] = ++i1;
while (i2 < s2_len) {
c2 = s2.charCodeAt(i2);
a = i2;
++i2;
b = i2;
for (i1 = 0; i1 < s1_len; ++i1) {
c = a + (s1.charCodeAt(i1) !== c2 ? 1 : 0);
a = row[i1];
b = b < a ? (b < c ? b + 1 : c) : (a < c ? a + 1 : c);
row[i1] = b;
}
}
return b;
} else {
return s1_len + s2_len;
}
}
};
})();
function initSearch(rawSearchIndex) {
var currentResults, index, searchIndex;
var MAX_LEV_DISTANCE = 3;
var params = getQueryStringParams();
// Populate search bar with query string search term when provided,
// but only if the input bar is empty. This avoid the obnoxious issue
// where you start trying to do a search, and the index loads, and
// suddenly your search is gone!
if ($(".search-input")[0].value === "") {
$(".search-input")[0].value = params.search || '';
}
/**
* Executes the query and builds an index of results
* @param {[Object]} query [The user query]
* @param {[type]} max [The maximum results returned]
* @param {[type]} searchWords [The list of search words to query
* against]
* @return {[type]} [A search index of results]
*/
function execQuery(query, max, searchWords) {
var valLower = query.query.toLowerCase(),
val = valLower,
typeFilter = itemTypeFromName(query.type),
results = [],
split = valLower.split("::");
//remove empty keywords
for (var j = 0; j < split.length; ++j) {
split[j].toLowerCase();
if (split[j] === "") {
split.splice(j, 1);
}
}
// quoted values mean literal search
var nSearchWords = searchWords.length;
if ((val.charAt(0) === "\"" || val.charAt(0) === "'") &&
val.charAt(val.length - 1) === val.charAt(0))
{
val = val.substr(1, val.length - 2);
for (var i = 0; i < nSearchWords; ++i) {
if (searchWords[i] === val) {
// filter type: ... queries
if (typeFilter < 0 || typeFilter === searchIndex[i].ty) {
results.push({id: i, index: -1});
}
}
if (results.length === max) {
break;
}
}
} else {
// gather matching search results up to a certain maximum
val = val.replace(/\_/g, "");
for (var i = 0; i < split.length; ++i) {
for (var j = 0; j < nSearchWords; ++j) {
var lev_distance;
if (searchWords[j].indexOf(split[i]) > -1 ||
searchWords[j].indexOf(val) > -1 ||
searchWords[j].replace(/_/g, "").indexOf(val) > -1)
{
// filter type: ... queries
if (typeFilter < 0 || typeFilter === searchIndex[j].ty) {
results.push({
id: j,
index: searchWords[j].replace(/_/g, "").indexOf(val),
lev: 0,
});
}
} else if (
(lev_distance = levenshtein(searchWords[j], val)) <=
MAX_LEV_DISTANCE) {
if (typeFilter < 0 || typeFilter === searchIndex[j].ty) {
results.push({
id: j,
index: 0,
// we want lev results to go lower than others
lev: lev_distance,
});
}
}
if (results.length === max) {
break;
}
}
}
}
var nresults = results.length;
for (var i = 0; i < nresults; ++i) {
results[i].word = searchWords[results[i].id];
results[i].item = searchIndex[results[i].id] || {};
}
// if there are no results then return to default and fail
if (results.length === 0) {
return [];
}
results.sort(function(aaa, bbb) {
var a, b;
// Sort by non levenshtein results and then levenshtein results by the distance
// (less changes required to match means higher rankings)
a = (aaa.lev);
b = (bbb.lev);
if (a !== b) return a - b;
// sort by crate (non-current crate goes later)
a = (aaa.item.crate !== window.currentCrate);
b = (bbb.item.crate !== window.currentCrate);
if (a !== b) return a - b;
// sort by exact match (mismatch goes later)
a = (aaa.word !== valLower);
b = (bbb.word !== valLower);
if (a !== b) return a - b;
// sort by item name length (longer goes later)
a = aaa.word.length;
b = bbb.word.length;
if (a !== b) return a - b;
// sort by item name (lexicographically larger goes later)
a = aaa.word;
b = bbb.word;
if (a !== b) return (a > b ? +1 : -1);
// sort by index of keyword in item name (no literal occurrence goes later)
a = (aaa.index < 0);
b = (bbb.index < 0);
if (a !== b) return a - b;
// (later literal occurrence, if any, goes later)
a = aaa.index;
b = bbb.index;
if (a !== b) return a - b;
// sort by description (no description goes later)
a = (aaa.item.desc === '');
b = (bbb.item.desc === '');
if (a !== b) return a - b;
// sort by type (later occurrence in `itemTypes` goes later)
a = aaa.item.ty;
b = bbb.item.ty;
if (a !== b) return a - b;
// sort by path (lexicographically larger goes later)
a = aaa.item.path;
b = bbb.item.path;
if (a !== b) return (a > b ? +1 : -1);
// que sera, sera
return 0;
});
// remove duplicates, according to the data provided
for (var i = results.length - 1; i > 0; i -= 1) {
if (results[i].word === results[i - 1].word &&
results[i].item.ty === results[i - 1].item.ty &&
results[i].item.path === results[i - 1].item.path)
{
results[i].id = -1;
}
}
for (var i = 0; i < results.length; ++i) {
var result = results[i],
name = result.item.name.toLowerCase(),
path = result.item.path.toLowerCase(),
parent = result.item.parent;
var valid = validateResult(name, path, split, parent);
if (!valid) {
result.id = -1;
}
}
return results;
}
/**
* Validate performs the following boolean logic. For example:
* "File::open" will give IF A PARENT EXISTS => ("file" && "open")
* exists in (name || path || parent) OR => ("file" && "open") exists in
* (name || path )
*
* This could be written functionally, but I wanted to minimise
* functions on stack.
*
* @param {[string]} name [The name of the result]
* @param {[string]} path [The path of the result]
* @param {[string]} keys [The keys to be used (["file", "open"])]
* @param {[object]} parent [The parent of the result]
* @return {[boolean]} [Whether the result is valid or not]
*/
function validateResult(name, path, keys, parent) {
for (var i=0; i < keys.length; ++i) {
// each check is for validation so we negate the conditions and invalidate
if (!(
// check for an exact name match
name.toLowerCase().indexOf(keys[i]) > -1 ||
// then an exact path match
path.toLowerCase().indexOf(keys[i]) > -1 ||
// next if there is a parent, check for exact parent match
(parent !== undefined &&
parent.name.toLowerCase().indexOf(keys[i]) > -1) ||
// lastly check to see if the name was a levenshtein match
levenshtein(name.toLowerCase(), keys[i]) <=
MAX_LEV_DISTANCE)) {
return false;
}
}
return true;
}
function getQuery() {
var matches, type, query = $('.search-input').val();
matches = query.match(/^(fn|mod|str(uct)?|enum|trait|t(ype)?d(ef)?)\s*:\s*/i);
if (matches) {
type = matches[1].replace(/^td$/, 'typedef')
.replace(/^str$/, 'struct')
.replace(/^tdef$/, 'typedef')
.replace(/^typed$/, 'typedef');
query = query.substring(matches[0].length);
}
return {
query: query,
type: type,
id: query + type,
};
}
function initSearchNav() {
var hoverTimeout, $results = $('.search-results .result');
$results.on('click', function() {
var dst = $(this).find('a')[0];
if (window.location.pathname == dst.pathname) {
$('#search').addClass('hidden');
$('#main').removeClass('hidden');
}
document.location.href = dst.href;
}).on('mouseover', function() {
var $el = $(this);
clearTimeout(hoverTimeout);
hoverTimeout = setTimeout(function() {
$results.removeClass('highlighted');
$el.addClass('highlighted');
}, 20);
});
$(document).off('keydown.searchnav');
$(document).on('keydown.searchnav', function(e) {
var $active = $results.filter('.highlighted');
if (e.which === 38) { // up
e.preventDefault();
if (!$active.length || !$active.prev()) {
return;
}
$active.prev().addClass('highlighted');
$active.removeClass('highlighted');
} else if (e.which === 40) { // down
e.preventDefault();
if (!$active.length) {
$results.first().addClass('highlighted');
} else if ($active.next().length) {
$active.next().addClass('highlighted');
$active.removeClass('highlighted');
}
} else if (e.which === 13) { // return
e.preventDefault();
if ($active.length) {
document.location.href = $active.find('a').prop('href');
}
}
});
}
function escape(content) {
return $('<h1/>').text(content).html();
}
function showResults(results) {
var output, shown, query = getQuery();
currentResults = query.id;
output = '<h1>Results for ' + escape(query.query) +
(query.type ? ' (type: ' + escape(query.type) + ')' : '') + '</h1>';
output += '<table class="search-results">';
if (results.length > 0) {
shown = [];
results.forEach(function(item) {
var name, type;
if (shown.indexOf(item) !== -1) {
return;
}
shown.push(item);
name = item.name;
type = itemTypes[item.ty];
output += '<tr class="' + type + ' result"><td>';
if (type === 'mod') {
output += item.path +
'::<a href="' + rootPath +
item.path.replace(/::/g, '/') + // '/' +
name + '/index.html" class="' +
type + '">' + name + '</a>';
} else if (type === 'static' || type === 'reexport') {
output += item.path +
'::<a href="' + rootPath +
item.path.replace(/::/g, '/') +
'/index.html" class="' + type +
'">' + name + '</a>';
} else if (item.parent !== undefined) {
var myparent = item.parent;
var anchor = '#' + type + '.' + name;
output += item.path + '::' + myparent.name +
'::<a href="' + rootPath +
item.path.replace(/::/g, '/') +
'/' + myparent.name +
'.html' + anchor +
'" class="' + type +
'">' + name + '</a>';
} else {
output += item.path +
'::<a href="' + rootPath +
item.path.replace(/::/g, '/') +
'/' + name +
'.html" class="' + type +
'">' + name + '</a>';
}
output += '</td><td><span class="desc">' + item.desc +
'</span></td></tr>';
});
} else {
output += 'No results :( <a href="https://duckduckgo.com/?q=' +
encodeURIComponent('eluna ' + query.query) +
'">Try on DuckDuckGo?</a>';
}
output += "</p>";
$('#main.content').addClass('hidden');
$('#search.content').removeClass('hidden').html(output);
$('#search .desc').width($('#search').width() - 40 -
$('#search td:first-child').first().width());
initSearchNav();
}
function search(e) {
var query,
filterdata = [],
obj, i, len,
results = [],
maxResults = 200,
resultIndex;
var params = getQueryStringParams();
query = getQuery();
if (e) {
e.preventDefault();
}
if (!query.query || query.id === currentResults) {
return;
}
// Because searching is incremental by character, only the most
// recent search query is added to the browser history.
if (browserSupportsHistoryApi()) {
if (!history.state && !params.search) {
history.pushState(query, "", "?search=" +
encodeURIComponent(query.query));
} else {
history.replaceState(query, "", "?search=" +
encodeURIComponent(query.query));
}
}
resultIndex = execQuery(query, 20000, index);
len = resultIndex.length;
for (i = 0; i < len; ++i) {
if (resultIndex[i].id > -1) {
obj = searchIndex[resultIndex[i].id];
filterdata.push([obj.name, obj.ty, obj.path, obj.desc]);
results.push(obj);
}
if (results.length >= maxResults) {
break;
}
}
showResults(results);
}
// This mapping table should match the discriminants of
// `rustdoc::html::item_type::ItemType` type in Rust.
var itemTypes = ["mod",
"struct",
"type",
"fn",
"type",
"static",
"trait",
"impl",
"viewitem",
"tymethod",
"method",
"structfield",
"variant",
"ffi",
"ffs",
"macro",
"primitive"];
function itemTypeFromName(typename) {
for (var i = 0; i < itemTypes.length; ++i) {
if (itemTypes[i] === typename) return i;
}
return -1;
}
function buildIndex(rawSearchIndex) {
searchIndex = [];
var searchWords = [];
for (var crate in rawSearchIndex) {
if (!rawSearchIndex.hasOwnProperty(crate)) { continue }
// an array of [(Number) item type,
// (String) name,
// (String) full path or empty string for previous path,
// (String) description,
// (optional Number) the parent path index to `paths`]
var items = rawSearchIndex[crate].items;
// an array of [(Number) item type,
// (String) name]
var paths = rawSearchIndex[crate].paths;
// convert `paths` into an object form
var len = paths.length;
for (var i = 0; i < len; ++i) {
paths[i] = {ty: paths[i][0], name: paths[i][1]};
}
// convert `items` into an object form, and construct word indices.
//
// before any analysis is performed lets gather the search terms to
// search against apart from the rest of the data. This is a quick
// operation that is cached for the life of the page state so that
// all other search operations have access to this cached data for
// faster analysis operations
var len = items.length;
var lastPath = "";
for (var i = 0; i < len; ++i) {
var rawRow = items[i];
var row = {crate: crate, ty: rawRow[0], name: rawRow[1],
path: rawRow[2] || lastPath, desc: rawRow[3],
parent: paths[rawRow[4]]};
searchIndex.push(row);
if (typeof row.name === "string") {
var word = row.name.toLowerCase();
searchWords.push(word);
} else {
searchWords.push("");
}
lastPath = row.path;
}
}
return searchWords;
}
function startSearch() {
var keyUpTimeout;
$('.do-search').on('click', search);
$('.search-input').on('keyup', function() {
clearTimeout(keyUpTimeout);
keyUpTimeout = setTimeout(search, 100);
});
// Push and pop states are used to add search results to the browser
// history.
if (browserSupportsHistoryApi()) {
$(window).on('popstate', function(e) {
var params = getQueryStringParams();
// When browsing back from search results the main page
// visibility must be reset.
if (!params.search) {
$('#main.content').removeClass('hidden');
$('#search.content').addClass('hidden');
}
// When browsing forward to search results the previous
// search will be repeated, so the currentResults are
// cleared to ensure the search is successful.
currentResults = null;
// Synchronize search bar with query string state and
// perform the search. This will empty the bar if there's
// nothing there, which lets you really go back to a
// previous state with nothing in the bar.
$('.search-input').val(params.search);
// Some browsers fire 'onpopstate' for every page load
// (Chrome), while others fire the event only when actually
// popping a state (Firefox), which is why search() is
// called both here and at the end of the startSearch()
// function.
search();
});
}
search();
}
index = buildIndex(rawSearchIndex);
startSearch();
// Draw a convenient sidebar of known crates if we have a listing
if (rootPath == '../') {
var sidebar = $('.sidebar');
var div = $('<div>').attr('class', 'block crate');
div.append($('<h2>').text('All Classes'));
var crates = [];
for (var crate in rawSearchIndex) {
if (!rawSearchIndex.hasOwnProperty(crate)) { continue }
crates.push(crate);
}
crates.sort();
for (var i = 0; i < crates.length; ++i) {
var klass = 'crate';
if (crates[i] == window.currentCrate) {
klass += ' current';
}
div.append($('<a>', {'href': '../' + crates[i] + '/index.html',
'class': klass}).text(crates[i]));
}
sidebar.append(div);
}
}
window.initSearch = initSearch;
window.register_implementors = function(imp) {
var list = $('#implementors-list');
var libs = Object.getOwnPropertyNames(imp);
for (var i = 0; i < libs.length; ++i) {
if (libs[i] == currentCrate) continue;
var structs = imp[libs[i]];
for (var j = 0; j < structs.length; ++j) {
var code = $('<code>').append(structs[j]);
$.each(code.find('a'), function(idx, a) {
var href = $(a).attr('href');
if (!href.startsWith('http')) {
$(a).attr('href', rootPath + $(a).attr('href'));
}
});
var li = $('<li>').append(code);
list.append(li);
}
}
};
if (window.pending_implementors) {
window.register_implementors(window.pending_implementors);
}
// See documentation in html/render.rs for what this is doing.
var query = getQueryStringParams();
if (query['gotosrc']) {
window.location = $('#src-' + query['gotosrc']).attr('href');
}
$("#expand-all").on("click", function() {
$(".docblock").show();
$(".toggle-label").hide();
$(".toggle-wrapper").removeClass("collapsed");
$(".collapse-toggle").children(".inner").html("-");
});
$("#collapse-all").on("click", function() {
$(".docblock").hide();
$(".toggle-label").show();
$(".toggle-wrapper").addClass("collapsed");
$(".collapse-toggle").children(".inner").html("+");
});
$(document).on("click", ".collapse-toggle", function() {
var toggle = $(this);
var relatedDoc = toggle.parent().next();
if (relatedDoc.is(".docblock")) {
if (relatedDoc.is(":visible")) {
relatedDoc.slideUp({duration:'fast', easing:'linear'});
toggle.parent(".toggle-wrapper").addClass("collapsed");
toggle.children(".inner").html("+");
toggle.children(".toggle-label").fadeIn();
} else {
relatedDoc.slideDown({duration:'fast', easing:'linear'});
toggle.parent(".toggle-wrapper").removeClass("collapsed");
toggle.children(".inner").html("-");
toggle.children(".toggle-label").hide();
}
}
});
$(function() {
var toggle = "<a href='javascript:void(0)'"
+ "class='collapse-toggle'>[<span class='inner'>-</span>]</a>";
$(".method").each(function() {
if ($(this).next().is(".docblock")) {
$(this).children().first().after(toggle);
}
});
var mainToggle = $(toggle);
mainToggle.append("<span class='toggle-label' style='display:none'>"
+ "&nbsp;Expand&nbsp;description</span></a>")
var wrapper = $("<div class='toggle-wrapper'>");
wrapper.append(mainToggle);
$("#main > .docblock").before(wrapper);
});
}());

View file

@ -0,0 +1 @@
/*! normalize.css v3.0.0 | MIT License | git.io/normalize */html{font-family:sans-serif;-ms-text-size-adjust:100%;-webkit-text-size-adjust:100%}body{margin:0}article,aside,details,figcaption,figure,footer,header,hgroup,main,nav,section,summary{display:block}audio,canvas,progress,video{display:inline-block;vertical-align:baseline}audio:not([controls]){display:none;height:0}[hidden],template{display:none}a{background:transparent}a:active,a:hover{outline:0}abbr[title]{border-bottom:1px dotted}b,strong{font-weight:bold}dfn{font-style:italic}h1{font-size:2em;margin:.67em 0}mark{background:#ff0;color:#000}small{font-size:80%}sub,sup{font-size:75%;line-height:0;position:relative;vertical-align:baseline}sup{top:-0.5em}sub{bottom:-0.25em}img{border:0}svg:not(:root){overflow:hidden}figure{margin:1em 40px}hr{-moz-box-sizing:content-box;box-sizing:content-box;height:0}pre{overflow:auto}code,kbd,pre,samp{font-family:monospace,monospace;font-size:1em}button,input,optgroup,select,textarea{color:inherit;font:inherit;margin:0}button{overflow:visible}button,select{text-transform:none}button,html input[type="button"],input[type="reset"],input[type="submit"]{-webkit-appearance:button;cursor:pointer}button[disabled],html input[disabled]{cursor:default}button::-moz-focus-inner,input::-moz-focus-inner{border:0;padding:0}input{line-height:normal}input[type="checkbox"],input[type="radio"]{box-sizing:border-box;padding:0}input[type="number"]::-webkit-inner-spin-button,input[type="number"]::-webkit-outer-spin-button{height:auto}input[type="search"]{-webkit-appearance:textfield;-moz-box-sizing:content-box;-webkit-box-sizing:content-box;box-sizing:content-box}input[type="search"]::-webkit-search-cancel-button,input[type="search"]::-webkit-search-decoration{-webkit-appearance:none}fieldset{border:1px solid silver;margin:0 2px;padding:.35em .625em .75em}legend{border:0;padding:0}textarea{overflow:auto}optgroup{font-weight:bold}table{border-collapse:collapse;border-spacing:0}td,th{padding:0}

View file

@ -0,0 +1,105 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta name="description" content="{% block description %}API documentation for the Eluna engine.{% endblock %}">
<meta name="keywords" content="eluna, lua, lua engine, trinitycore, trinity, mangos, cmangos, script, scripting, doc, docs, documentation">
<title>{% block title %}Eluna API{% endblock %}</title>
<link rel="stylesheet" type="text/css" href="{{ static('main.css') }}">
<link rel="shortcut icon" href="{{ static('favicon.ico') }}">
</head>
<body class="rustdoc">
<!--[if lte IE 8]>
<div class="warning">
This old browser is unsupported and will most likely display funky
things.
</div>
<![endif]-->
<section class="sidebar">
<a href='{{ root('index.html') }}'><img src='{{ static('eluna-logo.png') }}' alt='Eluna Logo' width='100'></a>
<div class="block">
{% block sidebar %}
<h2>All Classes</h2>
{% for class in classes -%}
<a class="mod {{ 'current' if class == current_class }}" href="{{ root(class.name + '/index.html') }}">{{ class.name }}</a>
{%- endfor %}
{% endblock %}
</div>
</section>
<nav class="sub">
<form class="search-form js-only">
<div class="search-container">
<input class="search-input" name="search"
autocomplete="off"
placeholder="Click or press 'S' to search, '?' for more options..."
type="search">
</div>
</form>
</nav>
<section id='main' class="content mod">
<h1 class='fqn'>
{% block document_title %}Title Missing{% endblock %}
<span class='out-of-band'>
<span id='render-detail'>
<a id="collapse-all" href="#">[-]</a>
<a id="expand-all" href="#">[+]</a>
</span>
</span>
</h1>
{% block content %}<h2>Content missing.</h2>{% endblock %}
</section>
<section id='search' class="content hidden"></section>
<section class="footer"></section>
<div id="help" class="hidden">
<div class="shortcuts">
<h1>Keyboard shortcuts</h1>
<dl>
<dt>?</dt>
<dd>Show this help dialog</dd>
<dt>S</dt>
<dd>Focus the search field</dd>
<dt>&larrb;</dt>
<dd>Move up in search results</dd>
<dt>&rarrb;</dt>
<dd>Move down in search results</dd>
<dt>&#9166;</dt>
<dd>Go to active search result</dd>
</dl>
</div>
<div class="infos">
<h1>Search tricks</h1>
<p>
Prefix searches with a type followed by a colon (e.g.
<code>fn:</code>) to restrict the search to a given type.
</p>
<p>
Accepted types are: <code>fn</code>, <code>mod</code>,
<code>struct</code> (or <code>str</code>), <code>enum</code>,
<code>trait</code>, <code>typedef</code> (or
<code>tdef</code>).
</p>
</div>
</div>
<script>
window.rootPath = "{{ ('../' * level) if level }}";
</script>
<script src="{{ static('jquery.js') }}"></script>
<script src="{{ static('main.js') }}"></script>
<script async src="{{ root('search-index.js') }}"></script>
<center>Generated on {{ currdate }}</center>
<center>&copy;2015 - Eluna Lua Engine</center>
</body>
</html>

View file

@ -0,0 +1,40 @@
{% extends '_base.html' %}
{% block title -%}
{{ current_class.name }} - {{ super() }}
{%- endblock %}
{% block description -%}
API documentation for the {{ current_class.name }} class in the Eluna engine.
{%- endblock %}
{% block document_title -%}
Class <a class="mod" href="">{{ current_class.name }}</a>
{%- endblock %}
{% block sidebar %}
{% endblock %}
{% block content %}
{{ current_class.description|parse_links }}
<h2 id='methods' class='section-header'><a href="#methods">Methods</a></h2>
<table>
{%- for method in current_class.methods %}
<tr>
<td>
<a class='stability {{ 'Stable' if method.documented else 'Experimental' }}' title='{{ 'Documented' if method.documented else 'Undocumented' }}'></a>
<a class='fn' href='{{ method.name }}.html'>{{ method.name }}</a>
</td>
<td class='docblock short'>
<p>{{ method.short_description|parse_links }}</p>
</td>
</tr>
{%- endfor %}
</table>
{% endblock %}

View file

@ -0,0 +1 @@
{% extends '_base.html' %}

View file

@ -0,0 +1,77 @@
{% extends '_base.html' %}
{% block document_title -%}
Eluna API Documentation
{%- endblock %}
{% block content %}
<div class='docblock'>
<h1 id="the-eluna-engine-api" class='section-header'>
<a href="#the-eluna-engine-api">The Eluna Lua Engine&copy; API</a>
</h1>
<p>
The Eluna Lua Engine&copy; API allows you to add your own Lua code to be executed when certain events (called "hooks") occur.
</p>
<p>
Add a new in-game command, give life to creatures with new AI, or even light players who try to duel on fire!
If the hook exists, you can script it.
</p>
<h2 id="about-eluna" class='section-header'>
<a href="#about-eluna">About Eluna</a>
</h2>
<p>
Eluna is a <a href="http://www.lua.org/">Lua</a> engine for World of Warcraft emulators.
Eluna supports <a href="http://cmangos.net/">CMaNGOS</a>/<a href="https://www.getmangos.eu/home.php">MaNGOS</a>
and <a href="http://www.trinitycore.org/">TrinityCore</a>.
</p>
<p>
To get Eluna, simply clone your favorite version of MaNGOS or Trinity from
<a href="https://github.com/ElunaLuaEngine">our Github account</a>.
Each fork there has Eluna already integrated, so you just need to compile and go!
</p>
<p>
Follow us on <a href="https://twitter.com/EmuDevs">our Twitter page</a> to view the latest news about what's going on with Eluna.
</p>
<h2 id="tutorials-and-guides" class='section-header'>
<a href="#tutorials-and-guides">Tutorials & Guides</a>
</h2>
<p>
We haven't written tutorials yet, but when we do, we'll put the links here.
</p>
<h2 id="about-this-documentation" class='section-header'>
<a href="#about-this-documentation">About this documentation</a>
</h2>
<p>
The layout, CSS, and Javascript code for this documentation was borrowed from <a href="http://doc.rust-lang.org/">doc.rust-lang.org</a>.
</p>
<p>
The documentation generator was originally written by <a href="https://github.com/Patman64">Patman64</a> and is maintained by the Eluna team.
</p>
</div>
<h2 id='modules' class='section-header'><a href="#modules">Classes</a></h2>
<table>
{%- for class in classes %}
<tr>
<td>
{%- if class.fully_documented %}
<a class='stability Stable' title='Fully Documented'></a>
{%- elif class.fully_undocumented %}
<a class='stability Experimental' title='Fully Undocumented'></a>
{%- else %}
<a class='stability Unstable' title='Partially Documented'></a>
{%- endif %}
<a class='mod' href='{{ root(class.name + '/index.html') }}'>{{ class.name }}</a>
</td>
<td class='docblock short'>
<p>{{ class.short_description|parse_links }}</p>
</td>
</tr>
{%- endfor %}
</table>
{% endblock %}

View file

@ -0,0 +1,86 @@
{% extends '_base.html' %}
{% block title -%}
{{ current_class.name }}:{{ current_method.name }} - Eluna
{%- endblock %}
{% block description -%}
API documentation for the {{ current_class.name }}:{{ current_method.name }} method in the Eluna engine.
{%- endblock %}
{% block document_title -%}
Method
<a class="mod" href="{{ root(current_class.name + '/index.html') }}">
{{- current_class.name -}}
</a>:<a class="fn" href="{{ root(current_class.name + '/' + current_method.name + '.html') }}">
{{- current_method.name -}}
</a>
{%- endblock %}
{% block sidebar %}
<h2>{{ current_class.name }} Methods</h2>
{%- for method in current_class.methods %}
<a class="fn {{ 'current' if method == current_method }}" href="{{ root(current_class.name + '/' + method.name + '.html') }}">{{ method.name }}</a>
{%- endfor %}
{% endblock %}
{% block content %}
<div class='docblock'>
{%- if current_method.documented %}
{{ current_method.description|parse_links }}
{%- else %}
<p>This method is <em>undocumented</em>. <strong>Use at your own risk.</strong></p>
<p>For temporary documentation, please check the <a href="https://github.com/ElunaLuaEngine/Eluna/blob/master/LuaFunctions.cpp">LuaFunctions</a> source file.</p>
{%- endif %}
<h2 id="synopsis" class='section-header'>
<a href="#synopsis">Synopsis</a>
</h2>
{%- for prototype in current_method.prototypes %}
<p>
<code>{{ prototype }}</code>
</p>
{%- endfor %}
<h2 id="arguments" class='section-header'>
<a href="#arguments">Arguments</a>
</h2>
<p>
{%- if current_method.parameters|length > 0 %}
{%- for param in current_method.parameters %}
<dl>
<dt><code>{{ param.data_type|escape|parse_data_type }} {{ param.name if param.data_type != '...' }} {{- ' (' + param.default_value + ')' if param.default_value }}</code></dt>
<dd class="docblock">{{ param.description|parse_links if param.description else '<em>See method description.</em>' }}</dd>
</dl>
{%- endfor %}
{%- elif not current_method.documented %}
Unknown.
{%- else %}
None.
{%- endif %}
</p>
<h2 id="returns" class='section-header'>
<a href="#returns">Returns</a>
</h2>
<p>
{%- if current_method.returned|length > 0 %}
{%- for returned in current_method.returned %}
<dl>
<dt><code>{{ returned.data_type|escape|parse_data_type }} {{ returned.name }}</code></dt>
<dd class="docblock">{{ returned.description|parse_links if returned.description else '<em>See method description.</em>' }}</dd>
</dl>
{%- endfor %}
{%- elif not current_method.documented %}
Unknown.
{%- else %}
Nothing.
{%- endif %}
</p>
</div>
{% endblock %}

View file

@ -0,0 +1,15 @@
var searchIndex = {};
{% for class in classes -%}
searchIndex["{{ class.name }}"] = {
"items": [
[0, "", "{{ class.name }}", "{{ class.short_description|replace('\n', ' ')|replace('\"', '&#34;')|parse_links|replace('"', '\\"') }}"],
{%- for method in class.methods %}
[3, "{{ method.name }}", "", "{{ method.short_description|replace('\n', ' ')|replace('\"', '&#34;')|parse_links|replace('"', '\\"') }}"],
{%- endfor %}
],
"paths": []
};
{%- endfor %}
initSearch(searchIndex);

View file

@ -0,0 +1,35 @@
#Installing and updating
This page will help you get a cMaNGOS and a TrinityCore source with Eluna.
To get a MaNGOS source with Eluna head over to [their forum](http://getmangos.eu/) for the core installation and updating instructions.
If you are having trouble with the installation or updating the core source, head over to our [support forum](../README.md#documentation).
If you are looking for a way to merge eluna with a fork of the official repositories see [merging](MERGING.md).
###Requirements and dependencies:
Currently there are no additional requirements apart from the normal core requirements.
See you desired core's documentation and installation instructions for it's requirements and dependencies.
###Installation
1. Open [git bash](http://git-scm.com/) and navigate to where you want the core source
2. Choose the git address of your desired core and patch below and clone the core with `git clone <address>`.
For example `git clone https://github.com/ElunaLuaEngine/ElunaTrinityWotlk.git`
* TrinityCore WoTLK: `https://github.com/ElunaLuaEngine/ElunaTrinityWotlk.git`
* TrinityCore Cataclysm: `https://github.com/ElunaLuaEngine/ElunaTrinityCata.git`
* cMaNGOS Classic: `https://github.com/ElunaLuaEngine/ElunaMangosClassic.git`
* cMaNGOS TBC: `https://github.com/ElunaLuaEngine/ElunaMangosTbc.git`
* cMaNGOS WoTLK: `https://github.com/ElunaLuaEngine/ElunaMangosWotlk.git`
3. Navigate to the newly created source folder with `git bash`
4. Use the git command `git submodule init` followed by `git submodule update`
* If you really do not get how to use git bash (and do try!) you can navigate to the `LuaEngine` folder and clone the [eluna repository](https://github.com/ElunaLuaEngine/Eluna) there. This is not recommended though.
4. Continue compiling the core normally using the official instructions
* [TrinityCore](http://collab.kpsn.org/display/tc/Installation+Guide)
* [cMaNGOS](https://github.com/cmangos/issues/wiki/Installation-Instructions)
###Updating
Updating is essentially handled in the same manner as you would normally update the core and database.
To get the newest core sourcecode open `git bash` and navigate to your local source folder.
Then execute use `git pull` followed by `git submodule init` and `git submodule update`.
After updating the source you need to recompile the core normally. Simply use `CMake` if needed and compile.
To update the databases refer to the core's or database's official updating documents:
* [TrinityCore](http://collab.kpsn.org/display/tc/Databases+Installation)
* [cMaNGOS](https://github.com/cmangos/issues/wiki/Installation-Instructions)

View file

@ -0,0 +1,220 @@
GNU GENERAL PUBLIC LICENSE
Version 3, 29 June 2007
Copyright (C) 2007 Free Software Foundation, Inc. <http://fsf.org/>
Everyone is permitted to copy and distribute verbatim copies of this license document, but changing it is not allowed.
Preamble
The GNU General Public License is a free, copyleft license for software and other kinds of works.
The licenses for most software and other practical works are designed to take away your freedom to share and change the works. By contrast, the GNU General Public License is intended to guarantee your freedom to share and change all versions of a program--to make sure it remains free software for all its users. We, the Free Software Foundation, use the GNU General Public License for most of our software; it applies also to any other work released this way by its authors. You can apply it to your programs, too.
When we speak of free software, we are referring to freedom, not price. Our General Public Licenses are designed to make sure that you have the freedom to distribute copies of free software (and charge for them if you wish), that you receive source code or can get it if you want it, that you can change the software or use pieces of it in new free programs, and that you know you can do these things.
To protect your rights, we need to prevent others from denying you these rights or asking you to surrender the rights. Therefore, you have certain responsibilities if you distribute copies of the software, or if you modify it: responsibilities to respect the freedom of others.
For example, if you distribute copies of such a program, whether gratis or for a fee, you must pass on to the recipients the same freedoms that you received. You must make sure that they, too, receive or can get the source code. And you must show them these terms so they know their rights.
Developers that use the GNU GPL protect your rights with two steps: (1) assert copyright on the software, and (2) offer you this License giving you legal permission to copy, distribute and/or modify it.
For the developers' and authors' protection, the GPL clearly explains that there is no warranty for this free software. For both users' and authors' sake, the GPL requires that modified versions be marked as changed, so that their problems will not be attributed erroneously to authors of previous versions.
Some devices are designed to deny users access to install or run modified versions of the software inside them, although the manufacturer can do so. This is fundamentally incompatible with the aim of protecting users' freedom to change the software. The systematic pattern of such abuse occurs in the area of products for individuals to use, which is precisely where it is most unacceptable. Therefore, we have designed this version of the GPL to prohibit the practice for those products. If such problems arise substantially in other domains, we stand ready to extend this provision to those domains in future versions of the GPL, as needed to protect the freedom of users.
Finally, every program is threatened constantly by software patents. States should not allow patents to restrict development and use of software on general-purpose computers, but in those that do, we wish to avoid the special danger that patents applied to a free program could make it effectively proprietary. To prevent this, the GPL assures that patents cannot be used to render the program non-free.
The precise terms and conditions for copying, distribution and modification follow.
TERMS AND CONDITIONS
0. Definitions.
“This License” refers to version 3 of the GNU General Public License.
“Copyright” also means copyright-like laws that apply to other kinds of works, such as semiconductor masks.
“The Program” refers to any copyrightable work licensed under this License. Each licensee is addressed as “you”. “Licensees” and “recipients” may be individuals or organizations.
To “modify” a work means to copy from or adapt all or part of the work in a fashion requiring copyright permission, other than the making of an exact copy. The resulting work is called a “modified version” of the earlier work or a work “based on” the earlier work.
A “covered work” means either the unmodified Program or a work based on the Program.
To “propagate” a work means to do anything with it that, without permission, would make you directly or secondarily liable for infringement under applicable copyright law, except executing it on a computer or modifying a private copy. Propagation includes copying, distribution (with or without modification), making available to the public, and in some countries other activities as well.
To “convey” a work means any kind of propagation that enables other parties to make or receive copies. Mere interaction with a user through a computer network, with no transfer of a copy, is not conveying.
An interactive user interface displays “Appropriate Legal Notices” to the extent that it includes a convenient and prominently visible feature that (1) displays an appropriate copyright notice, and (2) tells the user that there is no warranty for the work (except to the extent that warranties are provided), that licensees may convey the work under this License, and how to view a copy of this License. If the interface presents a list of user commands or options, such as a menu, a prominent item in the list meets this criterion.
1. Source Code.
The “source code” for a work means the preferred form of the work for making modifications to it. “Object code” means any non-source form of a work.
A “Standard Interface” means an interface that either is an official standard defined by a recognized standards body, or, in the case of interfaces specified for a particular programming language, one that is widely used among developers working in that language.
The “System Libraries” of an executable work include anything, other than the work as a whole, that (a) is included in the normal form of packaging a Major Component, but which is not part of that Major Component, and (b) serves only to enable use of the work with that Major Component, or to implement a Standard Interface for which an implementation is available to the public in source code form. A “Major Component”, in this context, means a major essential component (kernel, window system, and so on) of the specific operating system (if any) on which the executable work runs, or a compiler used to produce the work, or an object code interpreter used to run it.
The “Corresponding Source” for a work in object code form means all the source code needed to generate, install, and (for an executable work) run the object code and to modify the work, including scripts to control those activities. However, it does not include the work's System Libraries, or general-purpose tools or generally available free programs which are used unmodified in performing those activities but which are not part of the work. For example, Corresponding Source includes interface definition files associated with source files for the work, and the source code for shared libraries and dynamically linked subprograms that the work is specifically designed to require, such as by intimate data communication or control flow between those subprograms and other parts of the work.
The Corresponding Source need not include anything that users can regenerate automatically from other parts of the Corresponding Source.
The Corresponding Source for a work in source code form is that same work.
2. Basic Permissions.
All rights granted under this License are granted for the term of copyright on the Program, and are irrevocable provided the stated conditions are met. This License explicitly affirms your unlimited permission to run the unmodified Program. The output from running a covered work is covered by this License only if the output, given its content, constitutes a covered work. This License acknowledges your rights of fair use or other equivalent, as provided by copyright law.
You may make, run and propagate covered works that you do not convey, without conditions so long as your license otherwise remains in force. You may convey covered works to others for the sole purpose of having them make modifications exclusively for you, or provide you with facilities for running those works, provided that you comply with the terms of this License in conveying all material for which you do not control copyright. Those thus making or running the covered works for you must do so exclusively on your behalf, under your direction and control, on terms that prohibit them from making any copies of your copyrighted material outside their relationship with you.
Conveying under any other circumstances is permitted solely under the conditions stated below. Sublicensing is not allowed; section 10 makes it unnecessary.
3. Protecting Users' Legal Rights From Anti-Circumvention Law.
No covered work shall be deemed part of an effective technological measure under any applicable law fulfilling obligations under article 11 of the WIPO copyright treaty adopted on 20 December 1996, or similar laws prohibiting or restricting circumvention of such measures.
When you convey a covered work, you waive any legal power to forbid circumvention of technological measures to the extent such circumvention is effected by exercising rights under this License with respect to the covered work, and you disclaim any intention to limit operation or modification of the work as a means of enforcing, against the work's users, your or third parties' legal rights to forbid circumvention of technological measures.
4. Conveying Verbatim Copies.
You may convey verbatim copies of the Program's source code as you receive it, in any medium, provided that you conspicuously and appropriately publish on each copy an appropriate copyright notice; keep intact all notices stating that this License and any non-permissive terms added in accord with section 7 apply to the code; keep intact all notices of the absence of any warranty; and give all recipients a copy of this License along with the Program.
You may charge any price or no price for each copy that you convey, and you may offer support or warranty protection for a fee.
5. Conveying Modified Source Versions.
You may convey a work based on the Program, or the modifications to produce it from the Program, in the form of source code under the terms of section 4, provided that you also meet all of these conditions:
a) The work must carry prominent notices stating that you modified it, and giving a relevant date.
b) The work must carry prominent notices stating that it is released under this License and any conditions added under section 7. This requirement modifies the requirement in section 4 to “keep intact all notices”.
c) You must license the entire work, as a whole, under this License to anyone who comes into possession of a copy. This License will therefore apply, along with any applicable section 7 additional terms, to the whole of the work, and all its parts, regardless of how they are packaged. This License gives no permission to license the work in any other way, but it does not invalidate such permission if you have separately received it.
d) If the work has interactive user interfaces, each must display Appropriate Legal Notices; however, if the Program has interactive interfaces that do not display Appropriate Legal Notices, your work need not make them do so.
A compilation of a covered work with other separate and independent works, which are not by their nature extensions of the covered work, and which are not combined with it such as to form a larger program, in or on a volume of a storage or distribution medium, is called an “aggregate” if the compilation and its resulting copyright are not used to limit the access or legal rights of the compilation's users beyond what the individual works permit. Inclusion of a covered work in an aggregate does not cause this License to apply to the other parts of the aggregate.
6. Conveying Non-Source Forms.
You may convey a covered work in object code form under the terms of sections 4 and 5, provided that you also convey the machine-readable Corresponding Source under the terms of this License, in one of these ways:
a) Convey the object code in, or embodied in, a physical product (including a physical distribution medium), accompanied by the Corresponding Source fixed on a durable physical medium customarily used for software interchange.
b) Convey the object code in, or embodied in, a physical product (including a physical distribution medium), accompanied by a written offer, valid for at least three years and valid for as long as you offer spare parts or customer support for that product model, to give anyone who possesses the object code either (1) a copy of the Corresponding Source for all the software in the product that is covered by this License, on a durable physical medium customarily used for software interchange, for a price no more than your reasonable cost of physically performing this conveying of source, or (2) access to copy the Corresponding Source from a network server at no charge.
c) Convey individual copies of the object code with a copy of the written offer to provide the Corresponding Source. This alternative is allowed only occasionally and noncommercially, and only if you received the object code with such an offer, in accord with subsection 6b.
d) Convey the object code by offering access from a designated place (gratis or for a charge), and offer equivalent access to the Corresponding Source in the same way through the same place at no further charge. You need not require recipients to copy the Corresponding Source along with the object code. If the place to copy the object code is a network server, the Corresponding Source may be on a different server (operated by you or a third party) that supports equivalent copying facilities, provided you maintain clear directions next to the object code saying where to find the Corresponding Source. Regardless of what server hosts the Corresponding Source, you remain obligated to ensure that it is available for as long as needed to satisfy these requirements.
e) Convey the object code using peer-to-peer transmission, provided you inform other peers where the object code and Corresponding Source of the work are being offered to the general public at no charge under subsection 6d.
A separable portion of the object code, whose source code is excluded from the Corresponding Source as a System Library, need not be included in conveying the object code work.
A “User Product” is either (1) a “consumer product”, which means any tangible personal property which is normally used for personal, family, or household purposes, or (2) anything designed or sold for incorporation into a dwelling. In determining whether a product is a consumer product, doubtful cases shall be resolved in favor of coverage. For a particular product received by a particular user, “normally used” refers to a typical or common use of that class of product, regardless of the status of the particular user or of the way in which the particular user actually uses, or expects or is expected to use, the product. A product is a consumer product regardless of whether the product has substantial commercial, industrial or non-consumer uses, unless such uses represent the only significant mode of use of the product.
“Installation Information” for a User Product means any methods, procedures, authorization keys, or other information required to install and execute modified versions of a covered work in that User Product from a modified version of its Corresponding Source. The information must suffice to ensure that the continued functioning of the modified object code is in no case prevented or interfered with solely because modification has been made.
If you convey an object code work under this section in, or with, or specifically for use in, a User Product, and the conveying occurs as part of a transaction in which the right of possession and use of the User Product is transferred to the recipient in perpetuity or for a fixed term (regardless of how the transaction is characterized), the Corresponding Source conveyed under this section must be accompanied by the Installation Information. But this requirement does not apply if neither you nor any third party retains the ability to install modified object code on the User Product (for example, the work has been installed in ROM).
The requirement to provide Installation Information does not include a requirement to continue to provide support service, warranty, or updates for a work that has been modified or installed by the recipient, or for the User Product in which it has been modified or installed. Access to a network may be denied when the modification itself materially and adversely affects the operation of the network or violates the rules and protocols for communication across the network.
Corresponding Source conveyed, and Installation Information provided, in accord with this section must be in a format that is publicly documented (and with an implementation available to the public in source code form), and must require no special password or key for unpacking, reading or copying.
7. Additional Terms.
“Additional permissions” are terms that supplement the terms of this License by making exceptions from one or more of its conditions. Additional permissions that are applicable to the entire Program shall be treated as though they were included in this License, to the extent that they are valid under applicable law. If additional permissions apply only to part of the Program, that part may be used separately under those permissions, but the entire Program remains governed by this License without regard to the additional permissions.
When you convey a copy of a covered work, you may at your option remove any additional permissions from that copy, or from any part of it. (Additional permissions may be written to require their own removal in certain cases when you modify the work.) You may place additional permissions on material, added by you to a covered work, for which you have or can give appropriate copyright permission.
Notwithstanding any other provision of this License, for material you add to a covered work, you may (if authorized by the copyright holders of that material) supplement the terms of this License with terms:
a) Disclaiming warranty or limiting liability differently from the terms of sections 15 and 16 of this License; or
b) Requiring preservation of specified reasonable legal notices or author attributions in that material or in the Appropriate Legal Notices displayed by works containing it; or
c) Prohibiting misrepresentation of the origin of that material, or requiring that modified versions of such material be marked in reasonable ways as different from the original version; or
d) Limiting the use for publicity purposes of names of licensors or authors of the material; or
e) Declining to grant rights under trademark law for use of some trade names, trademarks, or service marks; or
f) Requiring indemnification of licensors and authors of that material by anyone who conveys the material (or modified versions of it) with contractual assumptions of liability to the recipient, for any liability that these contractual assumptions directly impose on those licensors and authors.
All other non-permissive additional terms are considered “further restrictions” within the meaning of section 10. If the Program as you received it, or any part of it, contains a notice stating that it is governed by this License along with a term that is a further restriction, you may remove that term. If a license document contains a further restriction but permits relicensing or conveying under this License, you may add to a covered work material governed by the terms of that license document, provided that the further restriction does not survive such relicensing or conveying.
If you add terms to a covered work in accord with this section, you must place, in the relevant source files, a statement of the additional terms that apply to those files, or a notice indicating where to find the applicable terms.
Additional terms, permissive or non-permissive, may be stated in the form of a separately written license, or stated as exceptions; the above requirements apply either way.
8. Termination.
You may not propagate or modify a covered work except as expressly provided under this License. Any attempt otherwise to propagate or modify it is void, and will automatically terminate your rights under this License (including any patent licenses granted under the third paragraph of section 11).
However, if you cease all violation of this License, then your license from a particular copyright holder is reinstated (a) provisionally, unless and until the copyright holder explicitly and finally terminates your license, and (b) permanently, if the copyright holder fails to notify you of the violation by some reasonable means prior to 60 days after the cessation.
Moreover, your license from a particular copyright holder is reinstated permanently if the copyright holder notifies you of the violation by some reasonable means, this is the first time you have received notice of violation of this License (for any work) from that copyright holder, and you cure the violation prior to 30 days after your receipt of the notice.
Termination of your rights under this section does not terminate the licenses of parties who have received copies or rights from you under this License. If your rights have been terminated and not permanently reinstated, you do not qualify to receive new licenses for the same material under section 10.
9. Acceptance Not Required for Having Copies.
You are not required to accept this License in order to receive or run a copy of the Program. Ancillary propagation of a covered work occurring solely as a consequence of using peer-to-peer transmission to receive a copy likewise does not require acceptance. However, nothing other than this License grants you permission to propagate or modify any covered work. These actions infringe copyright if you do not accept this License. Therefore, by modifying or propagating a covered work, you indicate your acceptance of this License to do so.
10. Automatic Licensing of Downstream Recipients.
Each time you convey a covered work, the recipient automatically receives a license from the original licensors, to run, modify and propagate that work, subject to this License. You are not responsible for enforcing compliance by third parties with this License.
An “entity transaction” is a transaction transferring control of an organization, or substantially all assets of one, or subdividing an organization, or merging organizations. If propagation of a covered work results from an entity transaction, each party to that transaction who receives a copy of the work also receives whatever licenses to the work the party's predecessor in interest had or could give under the previous paragraph, plus a right to possession of the Corresponding Source of the work from the predecessor in interest, if the predecessor has it or can get it with reasonable efforts.
You may not impose any further restrictions on the exercise of the rights granted or affirmed under this License. For example, you may not impose a license fee, royalty, or other charge for exercise of rights granted under this License, and you may not initiate litigation (including a cross-claim or counterclaim in a lawsuit) alleging that any patent claim is infringed by making, using, selling, offering for sale, or importing the Program or any portion of it.
11. Patents.
A “contributor” is a copyright holder who authorizes use under this License of the Program or a work on which the Program is based. The work thus licensed is called the contributor's “contributor version”.
A contributor's “essential patent claims” are all patent claims owned or controlled by the contributor, whether already acquired or hereafter acquired, that would be infringed by some manner, permitted by this License, of making, using, or selling its contributor version, but do not include claims that would be infringed only as a consequence of further modification of the contributor version. For purposes of this definition, “control” includes the right to grant patent sublicenses in a manner consistent with the requirements of this License.
Each contributor grants you a non-exclusive, worldwide, royalty-free patent license under the contributor's essential patent claims, to make, use, sell, offer for sale, import and otherwise run, modify and propagate the contents of its contributor version.
In the following three paragraphs, a “patent license” is any express agreement or commitment, however denominated, not to enforce a patent (such as an express permission to practice a patent or covenant not to sue for patent infringement). To “grant” such a patent license to a party means to make such an agreement or commitment not to enforce a patent against the party.
If you convey a covered work, knowingly relying on a patent license, and the Corresponding Source of the work is not available for anyone to copy, free of charge and under the terms of this License, through a publicly available network server or other readily accessible means, then you must either (1) cause the Corresponding Source to be so available, or (2) arrange to deprive yourself of the benefit of the patent license for this particular work, or (3) arrange, in a manner consistent with the requirements of this License, to extend the patent license to downstream recipients. “Knowingly relying” means you have actual knowledge that, but for the patent license, your conveying the covered work in a country, or your recipient's use of the covered work in a country, would infringe one or more identifiable patents in that country that you have reason to believe are valid.
If, pursuant to or in connection with a single transaction or arrangement, you convey, or propagate by procuring conveyance of, a covered work, and grant a patent license to some of the parties receiving the covered work authorizing them to use, propagate, modify or convey a specific copy of the covered work, then the patent license you grant is automatically extended to all recipients of the covered work and works based on it.
A patent license is “discriminatory” if it does not include within the scope of its coverage, prohibits the exercise of, or is conditioned on the non-exercise of one or more of the rights that are specifically granted under this License. You may not convey a covered work if you are a party to an arrangement with a third party that is in the business of distributing software, under which you make payment to the third party based on the extent of your activity of conveying the work, and under which the third party grants, to any of the parties who would receive the covered work from you, a discriminatory patent license (a) in connection with copies of the covered work conveyed by you (or copies made from those copies), or (b) primarily for and in connection with specific products or compilations that contain the covered work, unless you entered into that arrangement, or that patent license was granted, prior to 28 March 2007.
Nothing in this License shall be construed as excluding or limiting any implied license or other defenses to infringement that may otherwise be available to you under applicable patent law.
12. No Surrender of Others' Freedom.
If conditions are imposed on you (whether by court order, agreement or otherwise) that contradict the conditions of this License, they do not excuse you from the conditions of this License. If you cannot convey a covered work so as to satisfy simultaneously your obligations under this License and any other pertinent obligations, then as a consequence you may not convey it at all. For example, if you agree to terms that obligate you to collect a royalty for further conveying from those to whom you convey the Program, the only way you could satisfy both those terms and this License would be to refrain entirely from conveying the Program.
13. Use with the GNU Affero General Public License.
Notwithstanding any other provision of this License, you have permission to link or combine any covered work with a work licensed under version 3 of the GNU Affero General Public License into a single combined work, and to convey the resulting work. The terms of this License will continue to apply to the part which is the covered work, but the special requirements of the GNU Affero General Public License, section 13, concerning interaction through a network will apply to the combination as such.
14. Revised Versions of this License.
The Free Software Foundation may publish revised and/or new versions of the GNU General Public License from time to time. Such new versions will be similar in spirit to the present version, but may differ in detail to address new problems or concerns.
Each version is given a distinguishing version number. If the Program specifies that a certain numbered version of the GNU General Public License “or any later version” applies to it, you have the option of following the terms and conditions either of that numbered version or of any later version published by the Free Software Foundation. If the Program does not specify a version number of the GNU General Public License, you may choose any version ever published by the Free Software Foundation.
If the Program specifies that a proxy can decide which future versions of the GNU General Public License can be used, that proxy's public statement of acceptance of a version permanently authorizes you to choose that version for the Program.
Later license versions may give you additional or different permissions. However, no additional obligations are imposed on any author or copyright holder as a result of your choosing to follow a later version.
15. Disclaimer of Warranty.
THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM “AS IS” WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
16. Limitation of Liability.
IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES.
17. Interpretation of Sections 15 and 16.
If the disclaimer of warranty and limitation of liability provided above cannot be given local legal effect according to their terms, reviewing courts shall apply local law that most closely approximates an absolute waiver of all civil liability in connection with the Program, unless a warranty or assumption of liability accompanies a copy of the Program in return for a fee.
END OF TERMS AND CONDITIONS
How to Apply These Terms to Your New Programs
If you develop a new program, and you want it to be of the greatest possible use to the public, the best way to achieve this is to make it free software which everyone can redistribute and change under these terms.
To do so, attach the following notices to the program. It is safest to attach them to the start of each source file to most effectively state the exclusion of warranty; and each file should have at least the “copyright” line and a pointer to where the full notice is found.
<one line to give the program's name and a brief idea of what it does.>
Copyright (C) <year> <name of author>
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
Also add information on how to contact you by electronic and paper mail.
If the program does terminal interaction, make it output a short notice like this when it starts in an interactive mode:
<program> Copyright (C) <year> <name of author>
This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
This is free software, and you are welcome to redistribute it
under certain conditions; type `show c' for details.
The hypothetical commands 'show w' and 'show c' should show the appropriate parts of the General Public License. Of course, your program's commands might be different; for a GUI interface, you would use an “about box”.
You should also get your employer (if you work as a programmer) or school, if any, to sign a “copyright disclaimer” for the program, if necessary. For more information on this, and how to apply and follow the GNU GPL, see <http://www.gnu.org/licenses/>.
The GNU General Public License does not permit incorporating your program into proprietary programs. If your program is a subroutine library, you may consider it more useful to permit linking proprietary applications with the library. If this is what you want to do, use the GNU Lesser General Public License instead of this License. But first, please read <http://www.gnu.org/philosophy/why-not-lgpl.html>.

View file

@ -0,0 +1,42 @@
#Merging Eluna
Eluna can be added to various sources by applying the core changes required for Eluna to function.
Below you find the guides for merging Eluna with each core or a fork of it.
If you choose to merge you should be able to maintain and update yourself - we do not maintain your core.
We also do not fix any merging errors you may have, but you are free to ask about them on the [support forum](../README.md#documentation) and we may assist.
We recommend using the [installation guide](INSTALL.md) especially if you are not familiar with git and updating the code.
It allows you to simply use `git pull` followed by `git submodule update` to update your source and we will handle the merging and maintenance with the official core source. Naturally you still need to handle updating the database as instructed by the core's wiki or instructions.
###Merging Eluna with MaNGOS
Eluna is merged with [official MaNGOS](http://getmangos.eu/) by default.
###Merging Eluna with cMaNGOS
```
git clone https://github.com/cmangos/mangos-wotlk.git
cd mangos-wotlk
git pull --recurse-submodules https://github.com/ElunaLuaEngine/ElunaMangosWotlk.git
```
Steps explained:
1. clone the core or fork source or get the it by other means
2. navigate to the source folder
3. pull the Eluna fork. This will fetch the repository and merge it with your source.
* `--recurse-submodules` will automatically pull the submodules (Eluna repository). You may need to use `git submodule init` followed by `git submodule update` if your Eluna folder is empty
* it is important that you choose the correct Eluna fork for your core andpatch:
* [Eluna cMaNGOS Classic](https://github.com/ElunaLuaEngine/ElunaMangosClassic)
* [Eluna cMaNGOS TBC](https://github.com/ElunaLuaEngine/ElunaMangosTbc)
* [Eluna cMaNGOS WotLK](https://github.com/ElunaLuaEngine/ElunaMangosWotlk)
###Merging Eluna with TrinityCore
```
git clone https://github.com/TrinityCore/TrinityCore.git -b3.3.5
cd TrinityCore
git pull --recurse-submodules https://github.com/ElunaLuaEngine/ElunaTrinityWotlk.git
```
Steps explained:
1. clone the core or fork source or get the it by other means
2. navigate to the source folder
3. pull the Eluna fork. This will fetch the repository and merge it with your source.
* `--recurse-submodules` will automatically pull the submodules (Eluna repository). You may need to use `git submodule init` followed by `git submodule update` if your Eluna folder is empty
* it is important that you choose the correct Eluna fork for your core and patch:
* [Eluna TrinityCore WotLK](https://github.com/ElunaLuaEngine/ElunaTrinityWotlk)
* [Eluna TrinityCore Cataclysm](https://github.com/ElunaLuaEngine/ElunaTrinityCata)

View file

@ -0,0 +1,88 @@
--
-- 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
--
-- filename.ext files are loaded before normal .lua files
local variableStores = {
Map = {},
Player = {},
Creature = {},
GameObject = {},
}
local function DestroyData(event, obj)
if (event == 18) then
local mapid = obj:GetMapId()
local instid = obj:GetInstanceId()
if (variableStores.Map[mapid]) then
variableStores.Map[mapid][instid] = nil
end
else
variableStores[obj:GetObjectType()][obj:GetGUIDLow()] = nil
end
end
local function GetData(self, field)
local Type = self:GetObjectType()
local varStore = variableStores[Type]
local id
if (Type == "Map") then
local mapid = self:GetMapId()
varStore = varStore[mapid]
if (not varStore) then
return nil
end
id = self:GetInstanceId()
else
id = self:GetGUIDLow()
end
if (not varStore[id]) then
return nil
end
if (field == nil) then
return varStore[id]
else
return varStore[id][field]
end
end
local function SetData(self, field, val)
assert(field ~= nil, "field was nil", 2)
local Type = self:GetObjectType()
local varStore = variableStores[Type]
local id
if (Type == "Map") then
local mapid = self:GetMapId()
if (not varStore[mapid]) then
varStore[mapid] = {}
end
varStore = varStore[mapid]
id = self:GetInstanceId()
else
id = self:GetGUIDLow()
end
if (not varStore[id]) then
varStore[id] = {}
end
varStore[id][field] = val
end
for k,v in pairs(variableStores) do
_G[k].GetData = GetData
_G[k].SetData = SetData
end
RegisterPlayerEvent(4, DestroyData)
RegisterServerEvent(31, DestroyData)
RegisterServerEvent(32, DestroyData)
RegisterServerEvent(18, DestroyData)

View file

@ -0,0 +1,21 @@
The MIT License
Copyright (c) 2010 Ignacio Burgueño
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.

View file

@ -0,0 +1,128 @@
# StackTracePlus #
[![Build Status](https://travis-ci.org/ignacio/StackTracePlus.png?branch=master)](https://travis-ci.org/ignacio/StackTracePlus)
[StackTracePlus](https://github.com/ignacio/StackTracePlus) provides enhanced stack traces for [Lua 5.1, Lua 5.2][1] and [LuaJIT][2].
StackTracePlus can be used as a replacement for debug.traceback. It gives detailed information about locals, tries to guess
function names when they're not available, etc, so, instead of
lua5.1.exe: D:\trunk_git\sources\stacktraceplus\test\test.lua:10: attempt to concatenate a nil value
stack traceback:
D:\trunk_git\sources\stacktraceplus\test\test.lua:10: in function <D:\trunk_git\sources\stacktraceplus\test\test.lua:7>
(tail call): ?
D:\trunk_git\sources\stacktraceplus\test\test.lua:15: in main chunk
[C]: ?
you'll get
lua5.1.exe: D:\trunk_git\sources\stacktraceplus\test\test.lua:10: attempt to concatenate a nil value
Stack Traceback
===============
(2) C function 'function: 00A8F418'
(3) Lua function 'g' at file 'D:\trunk_git\sources\stacktraceplus\test\test.lua:10' (best guess)
Local variables:
fun = table module
str = string: "hey"
tb = table: 027DCBE0 {dummy:1, blah:true, foo:bar}
(*temporary) = nil
(*temporary) = string: "text"
(*temporary) = string: "attempt to concatenate a nil value"
(4) tail call
(5) main chunk of file 'D:\trunk_git\sources\stacktraceplus\test\test.lua' at line 15
(6) C function 'function: 002CA480'
## Usage #
StackTracePlus can be used as a replacement for `debug.traceback`, as an `xpcall` error handler or even from C code. Note that
only the Lua 5.1 interpreter allows the traceback function to be replaced "on the fly". LuaJIT and Lua 5.2 always calls luaL_traceback internally so there is no easy way to override that.
```lua
local STP = require "StackTracePlus"
debug.traceback = STP.stacktrace
function test()
local s = "this is a string"
local n = 42
local t = { foo = "bar" }
local co = coroutine
local cr = coroutine.create
error("an error")
end
test()
```
That script will output (only with Lua 5.1):
lua5.1: example.lua:11: an error
Stack Traceback
===============
(2) C function 'function: 006B5758'
(3) global C function 'error'
(4) Lua global 'test' at file 'example.lua:11'
Local variables:
s = string: "this is a string"
n = number: 42
t = table: 006E5220 {foo:bar}
co = coroutine table
cr = C function: 003C7080
(5) main chunk of file 'example.lua' at line 14
(6) C function 'function: 00637B30'
**StackTracePlus** is aware of the usual Lua libraries, like *coroutine*, *table*, *string*, *io*, etc and functions like
*print*, *pcall*, *assert*, and so on.
You can also make STP aware of your own tables and functions by calling *add_known_function* and *add_known_table*.
```lua
local STP = require "StackTracePlus"
debug.traceback = STP.stacktrace
local my_table = {
f = function() end
}
function my_function()
end
function test(data, func)
local s = "this is a string"
error("an error")
end
STP.add_known_table(my_table, "A description for my_table")
STP.add_known_function(my_function, "A description for my_function")
test( my_table, my_function )
```
Will output:
lua5.1: ..\test\example2.lua:13: an error
Stack Traceback
===============
(2) C function 'function: 0073AAA8'
(3) global C function 'error'
(4) Lua global 'test' at file '..\test\example2.lua:13'
Local variables:
data = A description for my_table
func = Lua function 'A description for my_function' (defined at line 7 of chunk ..\test\example2.lua)
s = string: "this is a string"
(5) main chunk of file '..\test\example2.lua' at line 19
(6) C function 'function: 00317B30'
## Installation #
The easiest way to install is with [LuaRocks][3].
- luarocks install stacktraceplus
If you don't want to use LuaRocks, just copy StackTracePlus.lua to Lua's path.
## License #
**StackTracePlus** is available under the MIT license.
[1]: http://www.lua.org/
[2]: http://luajit.org/
[3]: http://luarocks.org/

View file

@ -0,0 +1,411 @@
-- tables
local _G = _G
local string, io, debug, coroutine = string, io, debug, coroutine
-- functions
local tostring, print, require = tostring, print, require
local next, assert = next, assert
local pcall, type, pairs, ipairs = pcall, type, pairs, ipairs
local error = error
assert(debug, "debug table must be available at this point")
local io_open = io.open
local string_gmatch = string.gmatch
local string_sub = string.sub
local table_concat = table.concat
local _M = {
max_tb_output_len = 70 -- controls the maximum length of the 'stringified' table before cutting with ' (more...)'
}
-- this tables should be weak so the elements in them won't become uncollectable
local m_known_tables = { [_G] = "_G (global table)" }
local function add_known_module(name, desc)
local ok, mod = pcall(require, name)
if ok then
m_known_tables[mod] = desc
end
end
add_known_module("string", "string module")
add_known_module("io", "io module")
add_known_module("os", "os module")
add_known_module("table", "table module")
add_known_module("math", "math module")
add_known_module("package", "package module")
add_known_module("debug", "debug module")
add_known_module("coroutine", "coroutine module")
-- lua5.2
add_known_module("bit32", "bit32 module")
-- luajit
add_known_module("bit", "bit module")
add_known_module("jit", "jit module")
local m_user_known_tables = {}
local m_known_functions = {}
for _, name in ipairs{
-- Lua 5.2, 5.1
"assert",
"collectgarbage",
"dofile",
"error",
"getmetatable",
"ipairs",
"load",
"loadfile",
"next",
"pairs",
"pcall",
"print",
"rawequal",
"rawget",
"rawlen",
"rawset",
"require",
"select",
"setmetatable",
"tonumber",
"tostring",
"type",
"xpcall",
-- Lua 5.1
"gcinfo",
"getfenv",
"loadstring",
"module",
"newproxy",
"setfenv",
"unpack",
-- TODO: add table.* etc functions
} do
if _G[name] then
m_known_functions[_G[name]] = name
end
end
local m_user_known_functions = {}
local function safe_tostring (value)
local ok, err = pcall(tostring, value)
if ok then return err else return ("<failed to get printable value>: '%s'"):format(err) end
end
-- Private:
-- Parses a line, looking for possible function definitions (in a very na?ve way)
-- Returns '(anonymous)' if no function name was found in the line
local function ParseLine(line)
assert(type(line) == "string")
--print(line)
local match = line:match("^%s*function%s+(%w+)")
if match then
--print("+++++++++++++function", match)
return match
end
match = line:match("^%s*local%s+function%s+(%w+)")
if match then
--print("++++++++++++local", match)
return match
end
match = line:match("^%s*local%s+(%w+)%s+=%s+function")
if match then
--print("++++++++++++local func", match)
return match
end
match = line:match("%s*function%s*%(") -- this is an anonymous function
if match then
--print("+++++++++++++function2", match)
return "(anonymous)"
end
return "(anonymous)"
end
-- Private:
-- Tries to guess a function's name when the debug info structure does not have it.
-- It parses either the file or the string where the function is defined.
-- Returns '?' if the line where the function is defined is not found
local function GuessFunctionName(info)
--print("guessing function name")
if type(info.source) == "string" and info.source:sub(1,1) == "@" then
local file, err = io_open(info.source:sub(2), "r")
if not file then
print("file not found: "..tostring(err)) -- whoops!
return "?"
end
local line
for i = 1, info.linedefined do
line = file:read("*l")
end
if not line then
print("line not found") -- whoops!
return "?"
end
return ParseLine(line)
else
local line
local lineNumber = 0
for l in string_gmatch(info.source, "([^\n]+)\n-") do
lineNumber = lineNumber + 1
if lineNumber == info.linedefined then
line = l
break
end
end
if not line then
print("line not found") -- whoops!
return "?"
end
return ParseLine(line)
end
end
---
-- Dumper instances are used to analyze stacks and collect its information.
--
local Dumper = {}
Dumper.new = function(thread)
local t = { lines = {} }
for k,v in pairs(Dumper) do t[k] = v end
t.dumping_same_thread = (thread == coroutine.running())
-- if a thread was supplied, bind it to debug.info and debug.get
-- we also need to skip this additional level we are introducing in the callstack (only if we are running
-- in the same thread we're inspecting)
if type(thread) == "thread" then
t.getinfo = function(level, what)
if t.dumping_same_thread and type(level) == "number" then
level = level + 1
end
return debug.getinfo(thread, level, what)
end
t.getlocal = function(level, loc)
if t.dumping_same_thread then
level = level + 1
end
return debug.getlocal(thread, level, loc)
end
else
t.getinfo = debug.getinfo
t.getlocal = debug.getlocal
end
return t
end
-- helpers for collecting strings to be used when assembling the final trace
function Dumper:add (text)
self.lines[#self.lines + 1] = text
end
function Dumper:add_f (fmt, ...)
self:add(fmt:format(...))
end
function Dumper:concat_lines ()
return table_concat(self.lines)
end
---
-- Private:
-- Iterates over the local variables of a given function.
--
-- @param level The stack level where the function is.
--
function Dumper:DumpLocals (level)
local prefix = "\t "
local i = 1
if self.dumping_same_thread then
level = level + 1
end
local name, value = self.getlocal(level, i)
if not name then
return
end
self:add("\tLocal variables:\r\n")
while name do
if type(value) == "number" then
self:add_f("%s%s = number: %g\r\n", prefix, name, value)
elseif type(value) == "boolean" then
self:add_f("%s%s = boolean: %s\r\n", prefix, name, tostring(value))
elseif type(value) == "string" then
self:add_f("%s%s = string: %q\r\n", prefix, name, value)
elseif type(value) == "userdata" then
self:add_f("%s%s = %s\r\n", prefix, name, safe_tostring(value))
elseif type(value) == "nil" then
self:add_f("%s%s = nil\r\n", prefix, name)
elseif type(value) == "table" then
if m_known_tables[value] then
self:add_f("%s%s = %s\r\n", prefix, name, m_known_tables[value])
elseif m_user_known_tables[value] then
self:add_f("%s%s = %s\r\n", prefix, name, m_user_known_tables[value])
else
local txt = "{"
for k,v in pairs(value) do
txt = txt..safe_tostring(k)..":"..safe_tostring(v)
if #txt > _M.max_tb_output_len then
txt = txt.." (more...)"
break
end
if next(value, k) then txt = txt..", " end
end
self:add_f("%s%s = %s %s\r\n", prefix, name, safe_tostring(value), txt.."}")
end
elseif type(value) == "function" then
local info = self.getinfo(value, "nS")
local fun_name = info.name or m_known_functions[value] or m_user_known_functions[value]
if info.what == "C" then
self:add_f("%s%s = C %s\r\n", prefix, name, (fun_name and ("function: " .. fun_name) or tostring(value)))
else
local source = info.short_src
if source:sub(2,7) == "string" then
source = source:sub(9) -- uno m?s, por el espacio que viene (string "Baragent.Main", por ejemplo)
end
--for k,v in pairs(info) do print(k,v) end
fun_name = fun_name or GuessFunctionName(info)
self:add_f("%s%s = Lua function '%s' (defined at line %d of chunk %s)\r\n", prefix, name, fun_name, info.linedefined, source)
end
elseif type(value) == "thread" then
self:add_f("%sthread %q = %s\r\n", prefix, name, tostring(value))
end
i = i + 1
name, value = self.getlocal(level, i)
end
end
---
-- Public:
-- Collects a detailed stack trace, dumping locals, resolving function names when they're not available, etc.
-- This function is suitable to be used as an error handler with pcall or xpcall
--
-- @param thread An optional thread whose stack is to be inspected (defaul is the current thread)
-- @param message An optional error string or object.
-- @param level An optional number telling at which level to start the traceback (default is 1)
--
-- Returns a string with the stack trace and a string with the original error.
--
function _M.stacktrace(thread, message, level)
if type(thread) ~= "thread" then
-- shift parameters left
thread, message, level = nil, thread, message
end
thread = thread or coroutine.running()
level = level or 1
local dumper = Dumper.new(thread)
local original_error
if type(message) == "table" then
dumper:add("an error object {\r\n")
local first = true
for k,v in pairs(message) do
if first then
dumper:add(" ")
first = false
else
dumper:add(",\r\n ")
end
dumper:add(safe_tostring(k))
dumper:add(": ")
dumper:add(safe_tostring(v))
end
dumper:add("\r\n}")
original_error = dumper:concat_lines()
elseif type(message) == "string" then
dumper:add(message)
original_error = message
end
dumper:add("\r\n")
dumper:add[[
Stack Traceback
===============
]]
--print(error_message)
local level_to_show = level
if dumper.dumping_same_thread then level = level + 1 end
local info = dumper.getinfo(level, "nSlf")
while info do
if info.what == "main" then
if string_sub(info.source, 1, 1) == "@" then
dumper:add_f("(%d) main chunk of file '%s' at line %d\r\n", level_to_show, string_sub(info.source, 2), info.currentline)
else
dumper:add_f("(%d) main chunk of %s at line %d\r\n", level_to_show, info.short_src, info.currentline)
end
elseif info.what == "C" then
--print(info.namewhat, info.name)
--for k,v in pairs(info) do print(k,v, type(v)) end
local function_name = m_user_known_functions[info.func] or m_known_functions[info.func] or info.name or tostring(info.func)
dumper:add_f("(%d) %s C function '%s'\r\n", level_to_show, info.namewhat, function_name)
--dumper:add_f("%s%s = C %s\r\n", prefix, name, (m_known_functions[value] and ("function: " .. m_known_functions[value]) or tostring(value)))
elseif info.what == "tail" then
--print("tail")
--for k,v in pairs(info) do print(k,v, type(v)) end--print(info.namewhat, info.name)
dumper:add_f("(%d) tail call\r\n", level_to_show)
dumper:DumpLocals(level)
elseif info.what == "Lua" then
local source = info.short_src
local function_name = m_user_known_functions[info.func] or m_known_functions[info.func] or info.name
if source:sub(2, 7) == "string" then
source = source:sub(9)
end
local was_guessed = false
if not function_name or function_name == "?" then
--for k,v in pairs(info) do print(k,v, type(v)) end
function_name = GuessFunctionName(info)
was_guessed = true
end
-- test if we have a file name
local function_type = (info.namewhat == "") and "function" or info.namewhat
if info.source and info.source:sub(1, 1) == "@" then
dumper:add_f("(%d) Lua %s '%s' at file '%s:%d'%s\r\n", level_to_show, function_type, function_name, info.source:sub(2), info.currentline, was_guessed and " (best guess)" or "")
elseif info.source and info.source:sub(1,1) == '#' then
dumper:add_f("(%d) Lua %s '%s' at template '%s:%d'%s\r\n", level_to_show, function_type, function_name, info.source:sub(2), info.currentline, was_guessed and " (best guess)" or "")
else
dumper:add_f("(%d) Lua %s '%s' at line %d of chunk '%s'\r\n", level_to_show, function_type, function_name, info.currentline, source)
end
dumper:DumpLocals(level)
else
dumper:add_f("(%d) unknown frame %s\r\n", level_to_show, info.what)
end
level = level + 1
level_to_show = level_to_show + 1
info = dumper.getinfo(level, "nSlf")
end
return dumper:concat_lines(), original_error
end
--
-- Adds a table to the list of known tables
function _M.add_known_table(tab, description)
if m_known_tables[tab] then
error("Cannot override an already known table")
end
m_user_known_tables[tab] = description
end
--
-- Adds a function to the list of known functions
function _M.add_known_function(fun, description)
if m_known_functions[fun] then
error("Cannot override an already known function")
end
m_user_known_functions[fun] = description
end
return _M

View file

@ -0,0 +1,14 @@
--
-- 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
--
-- filename.ext files are loaded before normal .lua files
-- Randomize random
math.randomseed(tonumber(tostring(os.time()):reverse():sub(1,6)))
-- Set debug.traceback to use StackTracePlus to print full stack trace
local trace = require("StackTracePlus")
debug.traceback = trace.stacktrace