diff options
Diffstat (limited to 'src/server')
806 files changed, 25686 insertions, 15200 deletions
diff --git a/src/server/CMakeLists.txt b/src/server/CMakeLists.txt index 7d85cdb6e21..02fca56340f 100644 --- a/src/server/CMakeLists.txt +++ b/src/server/CMakeLists.txt @@ -12,7 +12,7 @@ # This to stop a few silly crashes that could have been avoided IF people # weren't doing some -O3 psychooptimizations etc. -if(CMAKE_COMPILER_IS_GNUCXX) +if(CMAKE_COMPILER_IS_GNUCXX AND NOT MINGW) add_definitions(-fno-delete-null-pointer-checks) endif() @@ -30,5 +30,6 @@ if( SERVERS ) else() if( TOOLS ) add_subdirectory(collision) + add_subdirectory(shared) endif() endif() diff --git a/src/server/authserver/Authentication/AuthCodes.h b/src/server/authserver/Authentication/AuthCodes.h index 492ac53f8cd..416d14ba5a0 100644 --- a/src/server/authserver/Authentication/AuthCodes.h +++ b/src/server/authserver/Authentication/AuthCodes.h @@ -41,7 +41,7 @@ enum AuthResult WOW_FAIL_GAME_ACCOUNT_LOCKED = 0x18, WOW_FAIL_INTERNET_GAME_ROOM_WITHOUT_BNET = 0x19, WOW_FAIL_UNLOCKABLE_LOCK = 0x20, - WOW_FAIL_DISCONNECTED = 0xFF, + WOW_FAIL_DISCONNECTED = 0xFF }; enum LoginResult @@ -62,7 +62,7 @@ enum LoginResult LOGIN_FAILED4 = 0x0D, LOGIN_CONNECTED = 0x0E, LOGIN_PARENTALCONTROL = 0x0F, - LOGIN_LOCKED_ENFORCED = 0x10, + LOGIN_LOCKED_ENFORCED = 0x10 }; enum ExpansionFlags diff --git a/src/server/authserver/CMakeLists.txt b/src/server/authserver/CMakeLists.txt index 328369cb908..f7c4b9cb8ca 100644 --- a/src/server/authserver/CMakeLists.txt +++ b/src/server/authserver/CMakeLists.txt @@ -29,11 +29,18 @@ set(authserver_SRCS ) if( WIN32 ) -set(authserver_SRCS - ${authserver_SRCS} - ${sources_Debugging} + if ( MSVC ) + set(authserver_SRCS + ${authserver_SRCS} + ${sources_Debugging} authserver.rc -) + ) + else ( ) + set(authserver_SRCS + ${authserver_SRCS} + ${sources_Debugging} + ) + endif () endif() include_directories( @@ -76,10 +83,17 @@ target_link_libraries(authserver ) if( WIN32 ) - add_custom_command(TARGET authserver - POST_BUILD - COMMAND ${CMAKE_COMMAND} -E copy ${CMAKE_CURRENT_SOURCE_DIR}/authserver.conf.dist ${CMAKE_BINARY_DIR}/bin/$(ConfigurationName)/ - ) + if ( MSVC ) + add_custom_command(TARGET authserver + POST_BUILD + COMMAND ${CMAKE_COMMAND} -E copy ${CMAKE_CURRENT_SOURCE_DIR}/authserver.conf.dist ${CMAKE_BINARY_DIR}/bin/$(ConfigurationName)/ + ) + elseif ( MINGW ) + add_custom_command(TARGET authserver + POST_BUILD + COMMAND ${CMAKE_COMMAND} -E copy ${CMAKE_CURRENT_SOURCE_DIR}/authserver.conf.dist ${CMAKE_BINARY_DIR}/bin/ + ) + endif() endif() if( UNIX ) diff --git a/src/server/authserver/Main.cpp b/src/server/authserver/Main.cpp index f4f73e2c33d..c87df4ef7ab 100644 --- a/src/server/authserver/Main.cpp +++ b/src/server/authserver/Main.cpp @@ -134,8 +134,6 @@ extern int main(int argc, char **argv) if (!StartDB()) return 1; - sLog->SetRealmID(0); // ensure we've set realm to 0 (authserver realmid) - // Get the list of realms for the server sRealmList->Initialize(ConfigMgr::GetIntDefault("RealmsStateUpdateDelay", 20)); if (sRealmList->size() == 0) @@ -272,7 +270,7 @@ bool StartDB() } sLog->outInfo(LOG_FILTER_AUTHSERVER, "Started auth database connection pool."); - sLog->EnableDBAppenders(); + sLog->SetRealmId(0); // Enables DB appenders when realm is set. return true; } diff --git a/src/server/authserver/Realms/RealmList.cpp b/src/server/authserver/Realms/RealmList.cpp index 72873e40ce5..b4becc96451 100644 --- a/src/server/authserver/Realms/RealmList.cpp +++ b/src/server/authserver/Realms/RealmList.cpp @@ -31,12 +31,12 @@ void RealmList::Initialize(uint32 updateInterval) UpdateRealms(true); } -void RealmList::UpdateRealm(uint32 ID, const std::string& name, ACE_INET_Addr const& address, uint8 icon, RealmFlags flag, uint8 timezone, AccountTypes allowedSecurityLevel, float popu, uint32 build) +void RealmList::UpdateRealm(uint32 id, const std::string& name, ACE_INET_Addr const& address, ACE_INET_Addr const& localAddr, ACE_INET_Addr const& localSubmask, uint8 icon, RealmFlags flag, uint8 timezone, AccountTypes allowedSecurityLevel, float popu, uint32 build) { // Create new if not exist or update existed Realm& realm = m_realms[name]; - realm.m_ID = ID; + realm.m_ID = id; realm.name = name; realm.icon = icon; realm.flag = flag; @@ -45,7 +45,9 @@ void RealmList::UpdateRealm(uint32 ID, const std::string& name, ACE_INET_Addr co realm.populationLevel = popu; // Append port to IP address. - address.addr_to_string(realm.address, ACE_MAX_FULLY_QUALIFIED_NAME_LEN + 16); + realm.ExternalAddress = address; + realm.LocalAddress = localAddr; + realm.LocalSubnetMask = localSubmask; realm.gamebuild = build; } @@ -77,23 +79,27 @@ void RealmList::UpdateRealms(bool init) do { Field* fields = result->Fetch(); - uint32 realmId = fields[0].GetUInt32(); - std::string name = fields[1].GetString(); - std::string address = fields[2].GetString(); - uint16 port = fields[3].GetUInt16(); - uint8 icon = fields[4].GetUInt8(); - RealmFlags flag = RealmFlags(fields[5].GetUInt8()); - uint8 timezone = fields[6].GetUInt8(); - uint8 allowedSecurityLevel = fields[7].GetUInt8(); - float pop = fields[8].GetFloat(); - uint32 build = fields[9].GetUInt32(); - - ACE_INET_Addr addr(port, address.c_str(), AF_INET); - - UpdateRealm(realmId, name, addr, icon, flag, timezone, (allowedSecurityLevel <= SEC_ADMINISTRATOR ? AccountTypes(allowedSecurityLevel) : SEC_ADMINISTRATOR), pop, build); + uint32 realmId = fields[0].GetUInt32(); + std::string name = fields[1].GetString(); + std::string externalAddress = fields[2].GetString(); + std::string localAddress = fields[3].GetString(); + std::string localSubmask = fields[4].GetString(); + uint16 port = fields[5].GetUInt16(); + uint8 icon = fields[6].GetUInt8(); + RealmFlags flag = RealmFlags(fields[7].GetUInt8()); + uint8 timezone = fields[8].GetUInt8(); + uint8 allowedSecurityLevel = fields[9].GetUInt8(); + float pop = fields[10].GetFloat(); + uint32 build = fields[11].GetUInt32(); + + ACE_INET_Addr externalAddr(port, externalAddress.c_str(), AF_INET); + ACE_INET_Addr localAddr(port, localAddress.c_str(), AF_INET); + ACE_INET_Addr submask(0, localSubmask.c_str(), AF_INET); + + UpdateRealm(realmId, name, externalAddr, localAddr, submask, icon, flag, timezone, (allowedSecurityLevel <= SEC_ADMINISTRATOR ? AccountTypes(allowedSecurityLevel) : SEC_ADMINISTRATOR), pop, build); if (init) - sLog->outInfo(LOG_FILTER_AUTHSERVER, "Added realm \"%s\" at %s.", name.c_str(), m_realms[name].address); + sLog->outInfo(LOG_FILTER_AUTHSERVER, "Added realm \"%s\" at %s:%u.", name.c_str(), m_realms[name].ExternalAddress.get_host_addr(), port); } while (result->NextRow()); } diff --git a/src/server/authserver/Realms/RealmList.h b/src/server/authserver/Realms/RealmList.h index 1949c34df9a..68e6524c334 100644 --- a/src/server/authserver/Realms/RealmList.h +++ b/src/server/authserver/Realms/RealmList.h @@ -40,7 +40,9 @@ enum RealmFlags // Storage object for a realm struct Realm { - char address[ACE_MAX_FULLY_QUALIFIED_NAME_LEN + 16]; + ACE_INET_Addr ExternalAddress; + ACE_INET_Addr LocalAddress; + ACE_INET_Addr LocalSubnetMask; std::string name; uint8 icon; RealmFlags flag; @@ -72,7 +74,7 @@ public: private: void UpdateRealms(bool init=false); - void UpdateRealm(uint32 ID, const std::string& name, ACE_INET_Addr const& address, uint8 icon, RealmFlags flag, uint8 timezone, AccountTypes allowedSecurityLevel, float popu, uint32 build); + void UpdateRealm(uint32 id, const std::string& name, ACE_INET_Addr const& address, ACE_INET_Addr const& localAddr, ACE_INET_Addr const& localSubmask, uint8 icon, RealmFlags flag, uint8 timezone, AccountTypes allowedSecurityLevel, float popu, uint32 build); RealmMap m_realms; uint32 m_UpdateInterval; diff --git a/src/server/authserver/Server/AuthSocket.cpp b/src/server/authserver/Server/AuthSocket.cpp index 9145c8413ff..32ddf029f1c 100644 --- a/src/server/authserver/Server/AuthSocket.cpp +++ b/src/server/authserver/Server/AuthSocket.cpp @@ -207,7 +207,7 @@ AuthSocket::AuthSocket(RealmSocket& socket) : pPatch(NULL), socket_(socket) // Close patch file descriptor before leaving AuthSocket::~AuthSocket(void) {} -// Accept the connection and set the s random value for SRP6 +// Accept the connection void AuthSocket::OnAccept(void) { sLog->outDebug(LOG_FILTER_AUTHSERVER, "'%s:%d' Accepting connection", socket().getRemoteAddress().c_str(), socket().getRemotePort()); @@ -365,7 +365,7 @@ bool AuthSocket::_HandleLogonChallenge() if (result) { pkt << uint8(WOW_FAIL_BANNED); - sLog->outDebug(LOG_FILTER_AUTHSERVER, "'%s:%d' [AuthChallenge] Banned ip tries to login!",socket().getRemoteAddress().c_str(), socket().getRemotePort()); + sLog->outDebug(LOG_FILTER_AUTHSERVER, "'%s:%d' [AuthChallenge] Banned ip tries to login!", socket().getRemoteAddress().c_str(), socket().getRemotePort()); } else { @@ -818,6 +818,28 @@ bool AuthSocket::_HandleReconnectProof() } } +ACE_INET_Addr const& AuthSocket::GetAddressForClient(Realm const& realm, ACE_INET_Addr const& clientAddr) +{ + // Attempt to send best address for client + if (clientAddr.is_loopback()) + { + // Try guessing if realm is also connected locally + if (realm.LocalAddress.is_loopback() || realm.ExternalAddress.is_loopback()) + return clientAddr; + + // Assume that user connecting from the machine that authserver is located on + // has all realms available in his local network + return realm.LocalAddress; + } + + // Check if connecting client is in the same network + if (IsIPAddrInNetwork(realm.LocalAddress, clientAddr, realm.LocalSubnetMask)) + return realm.LocalAddress; + + // Return external IP + return realm.ExternalAddress; +} + // Realm List command handler bool AuthSocket::_HandleRealmList() { @@ -845,6 +867,9 @@ bool AuthSocket::_HandleRealmList() // Update realm list if need sRealmList->UpdateIfNeed(); + ACE_INET_Addr clientAddr; + socket().peer().get_remote_addr(clientAddr); + // Circle through realms in the RealmList and construct the return packet (including # of user characters in each realm) ByteBuffer pkt; @@ -876,6 +901,9 @@ bool AuthSocket::_HandleRealmList() name = ss.str(); } + // We don't need the port number from which client connects with but the realm's port + clientAddr.set_port_number(i->second.ExternalAddress.get_port_number()); + uint8 lock = (i->second.allowedSecurityLevel > _accountSecurityLevel) ? 1 : 0; uint8 AmountOfCharacters = 0; @@ -891,7 +919,7 @@ bool AuthSocket::_HandleRealmList() pkt << lock; // if 1, then realm locked pkt << uint8(flag); // RealmFlags pkt << name; - pkt << i->second.address; + pkt << GetAddressString(GetAddressForClient(i->second, clientAddr)); pkt << i->second.populationLevel; pkt << AmountOfCharacters; pkt << i->second.timezone; // realm category diff --git a/src/server/authserver/Server/AuthSocket.h b/src/server/authserver/Server/AuthSocket.h index 87fd092381e..6c13f85a022 100644 --- a/src/server/authserver/Server/AuthSocket.h +++ b/src/server/authserver/Server/AuthSocket.h @@ -23,6 +23,9 @@ #include "BigNumber.h" #include "RealmSocket.h" +class ACE_INET_Addr; +struct Realm; + // Handle login commands class AuthSocket: public RealmSocket::Session { @@ -36,6 +39,8 @@ public: virtual void OnAccept(void); virtual void OnClose(void); + static ACE_INET_Addr const& GetAddressForClient(Realm const& realm, ACE_INET_Addr const& clientAddr); + bool _HandleLogonChallenge(); bool _HandleLogonProof(); bool _HandleReconnectChallenge(); diff --git a/src/server/authserver/Server/RealmSocket.cpp b/src/server/authserver/Server/RealmSocket.cpp index e67af783d5f..565a8c9a600 100644 --- a/src/server/authserver/Server/RealmSocket.cpp +++ b/src/server/authserver/Server/RealmSocket.cpp @@ -23,10 +23,6 @@ #include "RealmSocket.h" #include "Log.h" -#ifndef MSG_NOSIGNAL -#define MSG_NOSIGNAL 0 -#endif - RealmSocket::Session::Session(void) {} RealmSocket::Session::~Session(void) { } @@ -138,7 +134,11 @@ ssize_t RealmSocket::noblk_send(ACE_Message_Block &message_block) return -1; // Try to send the message directly. +#ifdef MSG_NOSIGNAL ssize_t n = peer().send(message_block.rd_ptr(), len, MSG_NOSIGNAL); +#else + ssize_t n = peer().send(message_block.rd_ptr(), len); +#endif // MSG_NOSIGNAL if (n < 0) { diff --git a/src/server/authserver/authserver.conf.dist b/src/server/authserver/authserver.conf.dist index 67d22c49da1..dda19c3b849 100644 --- a/src/server/authserver/authserver.conf.dist +++ b/src/server/authserver/authserver.conf.dist @@ -154,7 +154,7 @@ LoginDatabase.WorkerThreads = 1 # Appender config values: Given a appender "name" # Appender.name # Description: Defines 'where to log' -# Format: Type,LogLevel,Flags,optional1,optional2 +# Format: Type,LogLevel,Flags,optional1,optional2,optional3 # # Type # 0 - (None) @@ -205,6 +205,13 @@ LoginDatabase.WorkerThreads = 1 # a - (Append) # w - (Overwrite) # +# MaxFileSize: Maximum file size of the log file before creating a new log file +# (read as optional3 if Type = File) +# Size is measured in bytes expressed in a 64-bit unsigned integer. +# Maximum value is 4294967295 (4 gb). Leave blank for no limit. +# NOTE: Does not work with dynamic filenames. +# Example: 536870912 (512 mb) +# Appender.Console=1,2,0 Appender.Auth=2,2,0,Auth.log,w @@ -250,4 +257,4 @@ Logger.Root=0,3,Console Auth Loggers=Root # -###################################################################################################
\ No newline at end of file +################################################################################################### diff --git a/src/server/collision/BoundingIntervalHierarchy.cpp b/src/server/collision/BoundingIntervalHierarchy.cpp index ad3753ea3c9..340d66ddaf0 100644 --- a/src/server/collision/BoundingIntervalHierarchy.cpp +++ b/src/server/collision/BoundingIntervalHierarchy.cpp @@ -18,6 +18,12 @@ #include "BoundingIntervalHierarchy.h" +#ifdef _MSC_VER + #define isnan _isnan +#else + #define isnan std::isnan +#endif + void BIH::buildHierarchy(std::vector<uint32> &tempTree, buildData &dat, BuildStats &stats) { // create space for the first node @@ -51,7 +57,7 @@ void BIH::subdivide(int left, int right, std::vector<uint32> &tempTree, buildDat prevAxis = axis; prevSplit = split; // perform quick consistency checks - Vector3 d( gridBox.hi - gridBox.lo ); + G3D::Vector3 d( gridBox.hi - gridBox.lo ); if (d.x < 0 || d.y < 0 || d.z < 0) throw std::logic_error("negative node extents"); for (int i = 0; i < 3; i++) @@ -255,11 +261,11 @@ bool BIH::writeToFile(FILE* wf) const bool BIH::readFromFile(FILE* rf) { uint32 treeSize; - Vector3 lo, hi; + G3D::Vector3 lo, hi; uint32 check=0, count=0; check += fread(&lo, sizeof(float), 3, rf); check += fread(&hi, sizeof(float), 3, rf); - bounds = AABox(lo, hi); + bounds = G3D::AABox(lo, hi); check += fread(&treeSize, sizeof(uint32), 1, rf); tree.resize(treeSize); check += fread(&tree[0], sizeof(uint32), treeSize, rf); diff --git a/src/server/collision/BoundingIntervalHierarchy.h b/src/server/collision/BoundingIntervalHierarchy.h index 7cbaedbfba6..997f9c99e5f 100644 --- a/src/server/collision/BoundingIntervalHierarchy.h +++ b/src/server/collision/BoundingIntervalHierarchy.h @@ -31,20 +31,8 @@ #include <limits> #include <cmath> -#ifdef __APPLE__ - #define isnan(x) ( std::isnan(x) ) -#endif - #define MAX_STACK_SIZE 64 -#ifdef _MSC_VER - #define isnan(x) _isnan(x) -#endif - -using G3D::Vector3; -using G3D::AABox; -using G3D::Ray; - static inline uint32 floatToRawIntBits(float f) { union @@ -69,7 +57,7 @@ static inline float intBitsToFloat(uint32 i) struct AABound { - Vector3 lo, hi; + G3D::Vector3 lo, hi; }; /** Bounding Interval Hierarchy Class. @@ -105,12 +93,11 @@ class BIH dat.maxPrims = leafSize; dat.numPrims = primitives.size(); dat.indices = new uint32[dat.numPrims]; - dat.primBound = new AABox[dat.numPrims]; + dat.primBound = new G3D::AABox[dat.numPrims]; getBounds(primitives[0], bounds); for (uint32 i=0; i<dat.numPrims; ++i) { dat.indices[i] = i; - AABox tb; getBounds(primitives[i], dat.primBound[i]); bounds.merge(dat.primBound[i]); } @@ -131,13 +118,13 @@ class BIH uint32 primCount() const { return objects.size(); } template<typename RayCallback> - void intersectRay(const Ray &r, RayCallback& intersectCallback, float &maxDist, bool stopAtFirst=false) const + void intersectRay(const G3D::Ray &r, RayCallback& intersectCallback, float &maxDist, bool stopAtFirst=false) const { float intervalMin = -1.f; float intervalMax = -1.f; - Vector3 org = r.origin(); - Vector3 dir = r.direction(); - Vector3 invDir; + G3D::Vector3 org = r.origin(); + G3D::Vector3 dir = r.direction(); + G3D::Vector3 invDir; for (int i=0; i<3; ++i) { invDir[i] = 1.f / dir[i]; @@ -270,7 +257,7 @@ class BIH } template<typename IsectCallback> - void intersectPoint(const Vector3 &p, IsectCallback& intersectCallback) const + void intersectPoint(const G3D::Vector3 &p, IsectCallback& intersectCallback) const { if (!bounds.contains(p)) return; @@ -353,12 +340,12 @@ class BIH protected: std::vector<uint32> tree; std::vector<uint32> objects; - AABox bounds; + G3D::AABox bounds; struct buildData { uint32 *indices; - AABox *primBound; + G3D::AABox *primBound; uint32 numPrims; int maxPrims; }; @@ -410,4 +397,4 @@ class BIH void subdivide(int left, int right, std::vector<uint32> &tempTree, buildData &dat, AABound &gridBox, AABound &nodeBox, int nodeIndex, int depth, BuildStats &stats); }; -#endif // _BIH_H
\ No newline at end of file +#endif // _BIH_H diff --git a/src/server/collision/BoundingIntervalHierarchyWrapper.h b/src/server/collision/BoundingIntervalHierarchyWrapper.h index 8a99078caab..305d57b0075 100644 --- a/src/server/collision/BoundingIntervalHierarchyWrapper.h +++ b/src/server/collision/BoundingIntervalHierarchyWrapper.h @@ -33,18 +33,23 @@ class BIHWrap { const T* const* objects; RayCallback& _callback; + uint32 objects_size; - MDLCallback(RayCallback& callback, const T* const* objects_array ) : objects(objects_array), _callback(callback) {} + MDLCallback(RayCallback& callback, const T* const* objects_array, uint32 objects_size ) : objects(objects_array), _callback(callback), objects_size(objects_size) {} - bool operator() (const Ray& ray, uint32 Idx, float& MaxDist, bool /*stopAtFirst*/) + bool operator() (const G3D::Ray& ray, uint32 Idx, float& MaxDist, bool /*stopAtFirst*/) { + if (Idx >= objects_size) + return false; if (const T* obj = objects[Idx]) return _callback(ray, *obj, MaxDist/*, stopAtFirst*/); return false; } - void operator() (const Vector3& p, uint32 Idx) + void operator() (const G3D::Vector3& p, uint32 Idx) { + if (Idx >= objects_size) + return false; if (const T* obj = objects[Idx]) _callback(p, *obj); } @@ -87,21 +92,24 @@ public: m_objects.fastClear(); m_obj2Idx.getKeys(m_objects); m_objects_to_push.getMembers(m_objects); + //assert that m_obj2Idx has all the keys m_tree.build(m_objects, BoundsFunc::getBounds2); } template<typename RayCallback> - void intersectRay(const Ray& ray, RayCallback& intersectCallback, float& maxDist) const + void intersectRay(const G3D::Ray& ray, RayCallback& intersectCallback, float& maxDist) { - MDLCallback<RayCallback> temp_cb(intersectCallback, m_objects.getCArray()); + balance(); + MDLCallback<RayCallback> temp_cb(intersectCallback, m_objects.getCArray(), m_objects.size()); m_tree.intersectRay(ray, temp_cb, maxDist, true); } template<typename IsectCallback> - void intersectPoint(const Vector3& point, IsectCallback& intersectCallback) const + void intersectPoint(const G3D::Vector3& point, IsectCallback& intersectCallback) { - MDLCallback<IsectCallback> callback(intersectCallback, m_objects.getCArray()); + balance(); + MDLCallback<IsectCallback> callback(intersectCallback, m_objects.getCArray(), m_objects.size()); m_tree.intersectPoint(point, callback); } }; diff --git a/src/server/collision/CMakeLists.txt b/src/server/collision/CMakeLists.txt index 62af7dd081e..b4012b63812 100644 --- a/src/server/collision/CMakeLists.txt +++ b/src/server/collision/CMakeLists.txt @@ -33,7 +33,9 @@ set(collision_STAT_SRCS include_directories( ${CMAKE_BINARY_DIR} ${CMAKE_SOURCE_DIR}/dep/g3dlite/include + ${CMAKE_SOURCE_DIR}/dep/recastnavigation/Detour ${CMAKE_SOURCE_DIR}/src/server/shared + ${CMAKE_SOURCE_DIR}/src/server/shared/Configuration ${CMAKE_SOURCE_DIR}/src/server/shared/Debugging ${CMAKE_SOURCE_DIR}/src/server/shared/Database ${CMAKE_SOURCE_DIR}/src/server/shared/Debugging diff --git a/src/server/collision/DynamicTree.cpp b/src/server/collision/DynamicTree.cpp index 1a2f721a69f..c70a4b78a03 100644 --- a/src/server/collision/DynamicTree.cpp +++ b/src/server/collision/DynamicTree.cpp @@ -27,15 +27,24 @@ #include "GameObjectModel.h" #include "ModelInstance.h" +#include <G3D/AABox.h> +#include <G3D/Ray.h> +#include <G3D/Vector3.h> + using VMAP::ModelInstance; -using G3D::Ray; + +namespace { + +int CHECK_TREE_PERIOD = 200; + +} // namespace template<> struct HashTrait< GameObjectModel>{ static size_t hashCode(const GameObjectModel& g) { return (size_t)(void*)&g; } }; template<> struct PositionTrait< GameObjectModel> { - static void getPosition(const GameObjectModel& g, Vector3& p) { p = g.getPosition(); } + static void getPosition(const GameObjectModel& g, G3D::Vector3& p) { p = g.getPosition(); } }; template<> struct BoundsTrait< GameObjectModel> { @@ -49,11 +58,6 @@ static bool operator == (const GameObjectModel& mdl, const GameObjectModel& mdl2 } */ -int valuesPerNode = 5, numMeanSplits = 3; - -int UNBALANCED_TIMES_LIMIT = 5; -int CHECK_TREE_PERIOD = 200; - typedef RegularGrid2D<GameObjectModel, BIHWrap<GameObjectModel> > ParentTree; struct DynTreeImpl : public ParentTree/*, public Intersectable*/ @@ -103,43 +107,43 @@ struct DynTreeImpl : public ParentTree/*, public Intersectable*/ int unbalanced_times; }; -DynamicMapTree::DynamicMapTree() : impl(*new DynTreeImpl()) +DynamicMapTree::DynamicMapTree() : impl(new DynTreeImpl()) { } DynamicMapTree::~DynamicMapTree() { - delete &impl; + delete impl; } void DynamicMapTree::insert(const GameObjectModel& mdl) { - impl.insert(mdl); + impl->insert(mdl); } void DynamicMapTree::remove(const GameObjectModel& mdl) { - impl.remove(mdl); + impl->remove(mdl); } bool DynamicMapTree::contains(const GameObjectModel& mdl) const { - return impl.contains(mdl); + return impl->contains(mdl); } void DynamicMapTree::balance() { - impl.balance(); + impl->balance(); } int DynamicMapTree::size() const { - return impl.size(); + return impl->size(); } void DynamicMapTree::update(uint32 t_diff) { - impl.update(t_diff); + impl->update(t_diff); } struct DynamicTreeIntersectionCallback @@ -147,7 +151,7 @@ struct DynamicTreeIntersectionCallback bool did_hit; uint32 phase_mask; DynamicTreeIntersectionCallback(uint32 phasemask) : did_hit(false), phase_mask(phasemask) {} - bool operator()(const Ray& r, const GameObjectModel& obj, float& distance) + bool operator()(const G3D::Ray& r, const GameObjectModel& obj, float& distance) { did_hit = obj.intersectRay(r, distance, true, phase_mask); return did_hit; @@ -163,7 +167,7 @@ struct DynamicTreeIntersectionCallback_WithLogger { sLog->outDebug(LOG_FILTER_MAPS, "Dynamic Intersection log"); } - bool operator()(const Ray& r, const GameObjectModel& obj, float& distance) + bool operator()(const G3D::Ray& r, const GameObjectModel& obj, float& distance) { sLog->outDebug(LOG_FILTER_MAPS, "testing intersection with %s", obj.name.c_str()); bool hit = obj.intersectRay(r, distance, true, phase_mask); @@ -177,17 +181,20 @@ struct DynamicTreeIntersectionCallback_WithLogger bool didHit() const { return did_hit;} }; -bool DynamicMapTree::getIntersectionTime(const uint32 phasemask, const G3D::Ray& ray, const Vector3& endPos, float& maxDist) const +bool DynamicMapTree::getIntersectionTime(const uint32 phasemask, const G3D::Ray& ray, + const G3D::Vector3& endPos, float& maxDist) const { float distance = maxDist; DynamicTreeIntersectionCallback callback(phasemask); - impl.intersectRay(ray, callback, distance, endPos); + impl->intersectRay(ray, callback, distance, endPos); if (callback.didHit()) maxDist = distance; return callback.didHit(); } -bool DynamicMapTree::getObjectHitPos(const uint32 phasemask, const Vector3& startPos, const Vector3& endPos, Vector3& resultHit, float modifyDist) const +bool DynamicMapTree::getObjectHitPos(const uint32 phasemask, const G3D::Vector3& startPos, + const G3D::Vector3& endPos, G3D::Vector3& resultHit, + float modifyDist) const { bool result = false; float maxDist = (endPos - startPos).magnitude(); @@ -199,7 +206,7 @@ bool DynamicMapTree::getObjectHitPos(const uint32 phasemask, const Vector3& star resultHit = endPos; return false; } - Vector3 dir = (endPos - startPos)/maxDist; // direction with length of 1 + G3D::Vector3 dir = (endPos - startPos)/maxDist; // direction with length of 1 G3D::Ray ray(startPos, dir); float dist = maxDist; if (getIntersectionTime(phasemask, ray, endPos, dist)) @@ -227,26 +234,26 @@ bool DynamicMapTree::getObjectHitPos(const uint32 phasemask, const Vector3& star bool DynamicMapTree::isInLineOfSight(float x1, float y1, float z1, float x2, float y2, float z2, uint32 phasemask) const { - Vector3 v1(x1,y1,z1), v2(x2,y2,z2); + G3D::Vector3 v1(x1, y1, z1), v2(x2, y2, z2); float maxDist = (v2 - v1).magnitude(); if (!G3D::fuzzyGt(maxDist, 0) ) return true; - Ray r(v1, (v2-v1) / maxDist); + G3D::Ray r(v1, (v2-v1) / maxDist); DynamicTreeIntersectionCallback callback(phasemask); - impl.intersectRay(r, callback, maxDist, v2); + impl->intersectRay(r, callback, maxDist, v2); return !callback.did_hit; } float DynamicMapTree::getHeight(float x, float y, float z, float maxSearchDist, uint32 phasemask) const { - Vector3 v(x,y,z); - Ray r(v, Vector3(0,0,-1)); + G3D::Vector3 v(x, y, z); + G3D::Ray r(v, G3D::Vector3(0, 0, -1)); DynamicTreeIntersectionCallback callback(phasemask); - impl.intersectZAllignedRay(r, callback, maxSearchDist); + impl->intersectZAllignedRay(r, callback, maxSearchDist); if (callback.didHit()) return v.z - maxSearchDist; diff --git a/src/server/collision/DynamicTree.h b/src/server/collision/DynamicTree.h index ca199a9cd70..8e541fd453a 100644 --- a/src/server/collision/DynamicTree.h +++ b/src/server/collision/DynamicTree.h @@ -20,34 +20,36 @@ #ifndef _DYNTREE_H #define _DYNTREE_H -#include <G3D/Matrix3.h> -#include <G3D/Vector3.h> -#include <G3D/AABox.h> -#include <G3D/Ray.h> - -//#include "ModelInstance.h" #include "Define.h" -//#include "GameObjectModel.h" namespace G3D { + class Ray; class Vector3; } -using G3D::Vector3; class GameObjectModel; +struct DynTreeImpl; class DynamicMapTree { - struct DynTreeImpl& impl; + DynTreeImpl *impl; + public: DynamicMapTree(); ~DynamicMapTree(); - bool isInLineOfSight(float x1, float y1, float z1, float x2, float y2, float z2, uint32 phasemask) const; - bool getIntersectionTime(uint32 phasemask, const G3D::Ray& ray, const Vector3& endPos, float& maxDist) const; - bool getObjectHitPos(uint32 phasemask, const Vector3& pPos1, const Vector3& pPos2, Vector3& pResultHitPos, float pModifyDist) const; + bool isInLineOfSight(float x1, float y1, float z1, float x2, float y2, + float z2, uint32 phasemask) const; + + bool getIntersectionTime(uint32 phasemask, const G3D::Ray& ray, + const G3D::Vector3& endPos, float& maxDist) const; + + bool getObjectHitPos(uint32 phasemask, const G3D::Vector3& pPos1, + const G3D::Vector3& pPos2, G3D::Vector3& pResultHitPos, + float pModifyDist) const; + float getHeight(float x, float y, float z, float maxSearchDist, uint32 phasemask) const; void insert(const GameObjectModel&); diff --git a/src/server/collision/Management/MMapFactory.cpp b/src/server/collision/Management/MMapFactory.cpp new file mode 100644 index 00000000000..7adf7fbfa66 --- /dev/null +++ b/src/server/collision/Management/MMapFactory.cpp @@ -0,0 +1,52 @@ +/* + * Copyright (C) 2008-2013 TrinityCore <http://www.trinitycore.org/> + * Copyright (C) 2005-2010 MaNGOS <http://getmangos.com/> + * + * 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 2 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/>. + */ + +#include "MMapFactory.h" +#include "World.h" +#include "Config.h" +#include "DisableMgr.h" + +namespace MMAP +{ + // ######################## MMapFactory ######################## + // our global singleton copy + MMapManager *g_MMapManager = NULL; + + MMapManager* MMapFactory::createOrGetMMapManager() + { + if (g_MMapManager == NULL) + g_MMapManager = new MMapManager(); + + return g_MMapManager; + } + + bool MMapFactory::IsPathfindingEnabled(uint32 mapId) + { + return sWorld->getBoolConfig(CONFIG_ENABLE_MMAPS) + && !DisableMgr::IsDisabledFor(DISABLE_TYPE_MMAP, mapId, NULL, MMAP_DISABLE_PATHFINDING); + } + + void MMapFactory::clear() + { + if (g_MMapManager) + { + delete g_MMapManager; + g_MMapManager = NULL; + } + } +}
\ No newline at end of file diff --git a/src/server/collision/Management/MMapFactory.h b/src/server/collision/Management/MMapFactory.h new file mode 100644 index 00000000000..038d44a941c --- /dev/null +++ b/src/server/collision/Management/MMapFactory.h @@ -0,0 +1,50 @@ +/* + * Copyright (C) 2008-2013 TrinityCore <http://www.trinitycore.org/> + * Copyright (C) 2005-2010 MaNGOS <http://getmangos.com/> + * + * 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 2 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/>. + */ + +#ifndef _MMAP_FACTORY_H +#define _MMAP_FACTORY_H + +#include "MMapManager.h" +#include "UnorderedMap.h" +#include "DetourAlloc.h" +#include "DetourNavMesh.h" +#include "DetourNavMeshQuery.h" + +namespace MMAP +{ + enum MMAP_LOAD_RESULT + { + MMAP_LOAD_RESULT_ERROR, + MMAP_LOAD_RESULT_OK, + MMAP_LOAD_RESULT_IGNORED + }; + + // static class + // holds all mmap global data + // access point to MMapManager singleton + class MMapFactory + { + public: + static MMapManager* createOrGetMMapManager(); + static void clear(); + static bool IsPathfindingEnabled(uint32 mapId); + }; +} + +#endif + diff --git a/src/server/collision/Management/MMapManager.cpp b/src/server/collision/Management/MMapManager.cpp new file mode 100644 index 00000000000..e3ed8f3310a --- /dev/null +++ b/src/server/collision/Management/MMapManager.cpp @@ -0,0 +1,302 @@ +/* + * Copyright (C) 2008-2013 TrinityCore <http://www.trinitycore.org/> + * Copyright (C) 2005-2010 MaNGOS <http://getmangos.com/> + * + * 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 2 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/>. + */ + +#include "MMapManager.h" +#include "Log.h" +#include "World.h" + +namespace MMAP +{ + // ######################## MMapManager ######################## + MMapManager::~MMapManager() + { + for (MMapDataSet::iterator i = loadedMMaps.begin(); i != loadedMMaps.end(); ++i) + delete i->second; + + // by now we should not have maps loaded + // if we had, tiles in MMapData->mmapLoadedTiles, their actual data is lost! + } + + bool MMapManager::loadMapData(uint32 mapId) + { + // we already have this map loaded? + if (loadedMMaps.find(mapId) != loadedMMaps.end()) + return true; + + // load and init dtNavMesh - read parameters from file + uint32 pathLen = sWorld->GetDataPath().length() + strlen("mmaps/%03i.mmap")+1; + char *fileName = new char[pathLen]; + snprintf(fileName, pathLen, (sWorld->GetDataPath()+"mmaps/%03i.mmap").c_str(), mapId); + + FILE* file = fopen(fileName, "rb"); + if (!file) + { + sLog->outDebug(LOG_FILTER_MAPS, "MMAP:loadMapData: Error: Could not open mmap file '%s'", fileName); + delete [] fileName; + return false; + } + + dtNavMeshParams params; + int count = fread(¶ms, sizeof(dtNavMeshParams), 1, file); + fclose(file); + if (count != 1) + { + sLog->outDebug(LOG_FILTER_MAPS, "MMAP:loadMapData: Error: Could not read params from file '%s'", fileName); + delete [] fileName; + return false; + } + + dtNavMesh* mesh = dtAllocNavMesh(); + ASSERT(mesh); + if (DT_SUCCESS != mesh->init(¶ms)) + { + dtFreeNavMesh(mesh); + sLog->outError(LOG_FILTER_MAPS, "MMAP:loadMapData: Failed to initialize dtNavMesh for mmap %03u from file %s", mapId, fileName); + delete [] fileName; + return false; + } + + delete [] fileName; + + sLog->outInfo(LOG_FILTER_MAPS, "MMAP:loadMapData: Loaded %03i.mmap", mapId); + + // store inside our map list + MMapData* mmap_data = new MMapData(mesh); + mmap_data->mmapLoadedTiles.clear(); + + loadedMMaps.insert(std::pair<uint32, MMapData*>(mapId, mmap_data)); + return true; + } + + uint32 MMapManager::packTileID(int32 x, int32 y) + { + return uint32(x << 16 | y); + } + + bool MMapManager::loadMap(const std::string& /*basePath*/, uint32 mapId, int32 x, int32 y) + { + // make sure the mmap is loaded and ready to load tiles + if (!loadMapData(mapId)) + return false; + + // get this mmap data + MMapData* mmap = loadedMMaps[mapId]; + ASSERT(mmap->navMesh); + + // check if we already have this tile loaded + uint32 packedGridPos = packTileID(x, y); + if (mmap->mmapLoadedTiles.find(packedGridPos) != mmap->mmapLoadedTiles.end()) + return false; + + // load this tile :: mmaps/MMMXXYY.mmtile + uint32 pathLen = sWorld->GetDataPath().length() + strlen("mmaps/%03i%02i%02i.mmtile")+1; + char *fileName = new char[pathLen]; + + snprintf(fileName, pathLen, (sWorld->GetDataPath()+"mmaps/%03i%02i%02i.mmtile").c_str(), mapId, x, y); + + FILE *file = fopen(fileName, "rb"); + if (!file) + { + sLog->outDebug(LOG_FILTER_MAPS, "MMAP:loadMap: Could not open mmtile file '%s'", fileName); + delete [] fileName; + return false; + } + delete [] fileName; + + // read header + MmapTileHeader fileHeader; + if (fread(&fileHeader, sizeof(MmapTileHeader), 1, file) != 1 || fileHeader.mmapMagic != MMAP_MAGIC) + { + sLog->outError(LOG_FILTER_MAPS, "MMAP:loadMap: Bad header in mmap %03u%02i%02i.mmtile", mapId, x, y); + return false; + } + + if (fileHeader.mmapVersion != MMAP_VERSION) + { + sLog->outError(LOG_FILTER_MAPS, "MMAP:loadMap: %03u%02i%02i.mmtile was built with generator v%i, expected v%i", + mapId, x, y, fileHeader.mmapVersion, MMAP_VERSION); + return false; + } + + unsigned char* data = (unsigned char*)dtAlloc(fileHeader.size, DT_ALLOC_PERM); + ASSERT(data); + + size_t result = fread(data, fileHeader.size, 1, file); + if (!result) + { + sLog->outError(LOG_FILTER_MAPS, "MMAP:loadMap: Bad header or data in mmap %03u%02i%02i.mmtile", mapId, x, y); + fclose(file); + return false; + } + + fclose(file); + + dtMeshHeader* header = (dtMeshHeader*)data; + dtTileRef tileRef = 0; + + // memory allocated for data is now managed by detour, and will be deallocated when the tile is removed + if (DT_SUCCESS == mmap->navMesh->addTile(data, fileHeader.size, DT_TILE_FREE_DATA, 0, &tileRef)) + { + mmap->mmapLoadedTiles.insert(std::pair<uint32, dtTileRef>(packedGridPos, tileRef)); + ++loadedTiles; + sLog->outInfo(LOG_FILTER_MAPS, "MMAP:loadMap: Loaded mmtile %03i[%02i,%02i] into %03i[%02i,%02i]", mapId, x, y, mapId, header->x, header->y); + return true; + } + else + { + sLog->outError(LOG_FILTER_MAPS, "MMAP:loadMap: Could not load %03u%02i%02i.mmtile into navmesh", mapId, x, y); + dtFree(data); + return false; + } + + return false; + } + + bool MMapManager::unloadMap(uint32 mapId, int32 x, int32 y) + { + // check if we have this map loaded + if (loadedMMaps.find(mapId) == loadedMMaps.end()) + { + // file may not exist, therefore not loaded + sLog->outDebug(LOG_FILTER_MAPS, "MMAP:unloadMap: Asked to unload not loaded navmesh map. %03u%02i%02i.mmtile", mapId, x, y); + return false; + } + + MMapData* mmap = loadedMMaps[mapId]; + + // check if we have this tile loaded + uint32 packedGridPos = packTileID(x, y); + if (mmap->mmapLoadedTiles.find(packedGridPos) == mmap->mmapLoadedTiles.end()) + { + // file may not exist, therefore not loaded + sLog->outDebug(LOG_FILTER_MAPS, "MMAP:unloadMap: Asked to unload not loaded navmesh tile. %03u%02i%02i.mmtile", mapId, x, y); + return false; + } + + dtTileRef tileRef = mmap->mmapLoadedTiles[packedGridPos]; + + // unload, and mark as non loaded + if (DT_SUCCESS != mmap->navMesh->removeTile(tileRef, NULL, NULL)) + { + // this is technically a memory leak + // if the grid is later reloaded, dtNavMesh::addTile will return error but no extra memory is used + // we cannot recover from this error - assert out + sLog->outError(LOG_FILTER_MAPS, "MMAP:unloadMap: Could not unload %03u%02i%02i.mmtile from navmesh", mapId, x, y); + ASSERT(false); + } + else + { + mmap->mmapLoadedTiles.erase(packedGridPos); + --loadedTiles; + sLog->outInfo(LOG_FILTER_MAPS, "MMAP:unloadMap: Unloaded mmtile %03i[%02i,%02i] from %03i", mapId, x, y, mapId); + return true; + } + + return false; + } + + bool MMapManager::unloadMap(uint32 mapId) + { + if (loadedMMaps.find(mapId) == loadedMMaps.end()) + { + // file may not exist, therefore not loaded + sLog->outDebug(LOG_FILTER_MAPS, "MMAP:unloadMap: Asked to unload not loaded navmesh map %03u", mapId); + return false; + } + + // unload all tiles from given map + MMapData* mmap = loadedMMaps[mapId]; + for (MMapTileSet::iterator i = mmap->mmapLoadedTiles.begin(); i != mmap->mmapLoadedTiles.end(); ++i) + { + uint32 x = (i->first >> 16); + uint32 y = (i->first & 0x0000FFFF); + if (DT_SUCCESS != mmap->navMesh->removeTile(i->second, NULL, NULL)) + sLog->outError(LOG_FILTER_MAPS, "MMAP:unloadMap: Could not unload %03u%02i%02i.mmtile from navmesh", mapId, x, y); + else + { + --loadedTiles; + sLog->outInfo(LOG_FILTER_MAPS, "MMAP:unloadMap: Unloaded mmtile %03i[%02i,%02i] from %03i", mapId, x, y, mapId); + } + } + + delete mmap; + loadedMMaps.erase(mapId); + sLog->outInfo(LOG_FILTER_MAPS, "MMAP:unloadMap: Unloaded %03i.mmap", mapId); + + return true; + } + + bool MMapManager::unloadMapInstance(uint32 mapId, uint32 instanceId) + { + // check if we have this map loaded + if (loadedMMaps.find(mapId) == loadedMMaps.end()) + { + // file may not exist, therefore not loaded + sLog->outDebug(LOG_FILTER_MAPS, "MMAP:unloadMapInstance: Asked to unload not loaded navmesh map %03u", mapId); + return false; + } + + MMapData* mmap = loadedMMaps[mapId]; + if (mmap->navMeshQueries.find(instanceId) == mmap->navMeshQueries.end()) + { + sLog->outDebug(LOG_FILTER_MAPS, "MMAP:unloadMapInstance: Asked to unload not loaded dtNavMeshQuery mapId %03u instanceId %u", mapId, instanceId); + return false; + } + + dtNavMeshQuery* query = mmap->navMeshQueries[instanceId]; + + dtFreeNavMeshQuery(query); + mmap->navMeshQueries.erase(instanceId); + sLog->outInfo(LOG_FILTER_MAPS, "MMAP:unloadMapInstance: Unloaded mapId %03u instanceId %u", mapId, instanceId); + + return true; + } + + dtNavMesh const* MMapManager::GetNavMesh(uint32 mapId) + { + if (loadedMMaps.find(mapId) == loadedMMaps.end()) + return NULL; + + return loadedMMaps[mapId]->navMesh; + } + + dtNavMeshQuery const* MMapManager::GetNavMeshQuery(uint32 mapId, uint32 instanceId) + { + if (loadedMMaps.find(mapId) == loadedMMaps.end()) + return NULL; + + MMapData* mmap = loadedMMaps[mapId]; + if (mmap->navMeshQueries.find(instanceId) == mmap->navMeshQueries.end()) + { + // allocate mesh query + dtNavMeshQuery* query = dtAllocNavMeshQuery(); + ASSERT(query); + if (DT_SUCCESS != query->init(mmap->navMesh, 1024)) + { + dtFreeNavMeshQuery(query); + sLog->outError(LOG_FILTER_MAPS, "MMAP:GetNavMeshQuery: Failed to initialize dtNavMeshQuery for mapId %03u instanceId %u", mapId, instanceId); + return NULL; + } + + sLog->outInfo(LOG_FILTER_MAPS, "MMAP:GetNavMeshQuery: created dtNavMeshQuery for mapId %03u instanceId %u", mapId, instanceId); + mmap->navMeshQueries.insert(std::pair<uint32, dtNavMeshQuery*>(instanceId, query)); + } + + return mmap->navMeshQueries[instanceId]; + } +} diff --git a/src/server/collision/Management/MMapManager.h b/src/server/collision/Management/MMapManager.h new file mode 100644 index 00000000000..56b1b856d65 --- /dev/null +++ b/src/server/collision/Management/MMapManager.h @@ -0,0 +1,84 @@ +/* + * Copyright (C) 2008-2013 TrinityCore <http://www.trinitycore.org/> + * Copyright (C) 2005-2010 MaNGOS <http://getmangos.com/> + * + * 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 2 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/>. + */ + +#ifndef _MMAP_MANAGER_H +#define _MMAP_MANAGER_H + +#include "UnorderedMap.h" +#include "DetourAlloc.h" +#include "DetourNavMesh.h" +#include "DetourNavMeshQuery.h" + +// move map related classes +namespace MMAP +{ + typedef UNORDERED_MAP<uint32, dtTileRef> MMapTileSet; + typedef UNORDERED_MAP<uint32, dtNavMeshQuery*> NavMeshQuerySet; + + // dummy struct to hold map's mmap data + struct MMapData + { + MMapData(dtNavMesh* mesh) : navMesh(mesh) {} + ~MMapData() + { + for (NavMeshQuerySet::iterator i = navMeshQueries.begin(); i != navMeshQueries.end(); ++i) + dtFreeNavMeshQuery(i->second); + + if (navMesh) + dtFreeNavMesh(navMesh); + } + + dtNavMesh* navMesh; + + // we have to use single dtNavMeshQuery for every instance, since those are not thread safe + NavMeshQuerySet navMeshQueries; // instanceId to query + MMapTileSet mmapLoadedTiles; // maps [map grid coords] to [dtTile] + }; + + + typedef UNORDERED_MAP<uint32, MMapData*> MMapDataSet; + + // singleton class + // holds all all access to mmap loading unloading and meshes + class MMapManager + { + public: + MMapManager() : loadedTiles(0) {} + ~MMapManager(); + + bool loadMap(const std::string& basePath, uint32 mapId, int32 x, int32 y); + bool unloadMap(uint32 mapId, int32 x, int32 y); + bool unloadMap(uint32 mapId); + bool unloadMapInstance(uint32 mapId, uint32 instanceId); + + // the returned [dtNavMeshQuery const*] is NOT threadsafe + dtNavMeshQuery const* GetNavMeshQuery(uint32 mapId, uint32 instanceId); + dtNavMesh const* GetNavMesh(uint32 mapId); + + uint32 getLoadedTilesCount() const { return loadedTiles; } + uint32 getLoadedMapsCount() const { return loadedMMaps.size(); } + private: + bool loadMapData(uint32 mapId); + uint32 packTileID(int32 x, int32 y); + + MMapDataSet loadedMMaps; + uint32 loadedTiles; + }; +} + +#endif
\ No newline at end of file diff --git a/src/server/collision/Management/VMapManager2.cpp b/src/server/collision/Management/VMapManager2.cpp index 5e3741ca753..8a1bd346957 100644 --- a/src/server/collision/Management/VMapManager2.cpp +++ b/src/server/collision/Management/VMapManager2.cpp @@ -24,13 +24,13 @@ #include "MapTree.h" #include "ModelInstance.h" #include "WorldModel.h" -#include "VMapDefinitions.h" -#include "Log.h" #include <G3D/Vector3.h> #include <ace/Null_Mutex.h> #include <ace/Singleton.h> #include "DisableMgr.h" #include "DBCStores.h" +#include "Log.h" +#include "VMapDefinitions.h" using G3D::Vector3; @@ -257,11 +257,11 @@ namespace VMAP WorldModel* worldmodel = new WorldModel(); if (!worldmodel->readFile(basepath + filename + ".vmo")) { - sLog->outError(LOG_FILTER_GENERAL, "VMapManager2: could not load '%s%s.vmo'", basepath.c_str(), filename.c_str()); + VMAP_ERROR_LOG(LOG_FILTER_GENERAL, "VMapManager2: could not load '%s%s.vmo'", basepath.c_str(), filename.c_str()); delete worldmodel; return NULL; } - sLog->outDebug(LOG_FILTER_MAPS, "VMapManager2: loading file '%s%s'", basepath.c_str(), filename.c_str()); + VMAP_DEBUG_LOG(LOG_FILTER_MAPS, "VMapManager2: loading file '%s%s'", basepath.c_str(), filename.c_str()); model = iLoadedModelFiles.insert(std::pair<std::string, ManagedModel>(filename, ManagedModel())).first; model->second.setModel(worldmodel); } @@ -277,12 +277,12 @@ namespace VMAP ModelFileMap::iterator model = iLoadedModelFiles.find(filename); if (model == iLoadedModelFiles.end()) { - sLog->outError(LOG_FILTER_GENERAL, "VMapManager2: trying to unload non-loaded file '%s'", filename.c_str()); + VMAP_ERROR_LOG(LOG_FILTER_GENERAL, "VMapManager2: trying to unload non-loaded file '%s'", filename.c_str()); return; } if (model->second.decRefCount() == 0) { - sLog->outDebug(LOG_FILTER_MAPS, "VMapManager2: unloading file '%s'", filename.c_str()); + VMAP_DEBUG_LOG(LOG_FILTER_MAPS, "VMapManager2: unloading file '%s'", filename.c_str()); delete model->second.getModel(); iLoadedModelFiles.erase(model); } diff --git a/src/server/collision/Management/VMapManager2.h b/src/server/collision/Management/VMapManager2.h index e2e9965dbfc..51f15f0fda4 100644 --- a/src/server/collision/Management/VMapManager2.h +++ b/src/server/collision/Management/VMapManager2.h @@ -112,6 +112,8 @@ namespace VMAP return getMapFileName(mapId); } virtual bool existsMap(const char* basePath, unsigned int mapId, int x, int y); + public: + void getInstanceMapTree(InstanceTreeMap &instanceMapTree); }; } diff --git a/src/server/collision/Maps/MapTree.cpp b/src/server/collision/Maps/MapTree.cpp index 5f4e2b6aa8b..bd925d5a0c4 100644 --- a/src/server/collision/Maps/MapTree.cpp +++ b/src/server/collision/Maps/MapTree.cpp @@ -21,18 +21,13 @@ #include "VMapManager2.h" #include "VMapDefinitions.h" #include "Log.h" +#include "Errors.h" #include <string> #include <sstream> #include <iomanip> #include <limits> -#ifndef NO_CORE_FUNCS - #include "Errors.h" -#else - #define ASSERT(x) -#endif - using G3D::Vector3; namespace VMAP @@ -248,7 +243,7 @@ namespace VMAP FILE* rf = fopen(fullname.c_str(), "rb"); if (!rf) return false; - // TODO: check magic number when implemented... + /// @todo check magic number when implemented... char tiled; char chunk[8]; if (!readChunk(rf, chunk, VMAP_MAGIC, 8) || fread(&tiled, sizeof(char), 1, rf) != 1) @@ -277,7 +272,7 @@ namespace VMAP bool StaticMapTree::InitMap(const std::string &fname, VMapManager2* vm) { - sLog->outDebug(LOG_FILTER_MAPS, "StaticMapTree::InitMap() : initializing StaticMapTree '%s'", fname.c_str()); + VMAP_DEBUG_LOG(LOG_FILTER_MAPS, "StaticMapTree::InitMap() : initializing StaticMapTree '%s'", fname.c_str()); bool success = true; std::string fullname = iBasePath + fname; FILE* rf = fopen(fullname.c_str(), "rb"); @@ -310,7 +305,7 @@ namespace VMAP if (!iIsTiled && ModelSpawn::readFromFile(rf, spawn)) { WorldModel* model = vm->acquireModelInstance(iBasePath, spawn.name); - sLog->outDebug(LOG_FILTER_MAPS, "StaticMapTree::InitMap() : loading %s", spawn.name.c_str()); + VMAP_DEBUG_LOG(LOG_FILTER_MAPS, "StaticMapTree::InitMap() : loading %s", spawn.name.c_str()); if (model) { // assume that global model always is the first and only tree value (could be improved...) @@ -320,7 +315,7 @@ namespace VMAP else { success = false; - sLog->outError(LOG_FILTER_GENERAL, "StaticMapTree::InitMap() : could not acquire WorldModel pointer for '%s'", spawn.name.c_str()); + VMAP_ERROR_LOG(LOG_FILTER_GENERAL, "StaticMapTree::InitMap() : could not acquire WorldModel pointer for '%s'", spawn.name.c_str()); } } @@ -356,7 +351,7 @@ namespace VMAP } if (!iTreeValues) { - sLog->outError(LOG_FILTER_GENERAL, "StaticMapTree::LoadMapTile() : tree has not been initialized [%u, %u]", tileX, tileY); + VMAP_ERROR_LOG(LOG_FILTER_GENERAL, "StaticMapTree::LoadMapTile() : tree has not been initialized [%u, %u]", tileX, tileY); return false; } bool result = true; @@ -382,7 +377,7 @@ namespace VMAP // acquire model instance WorldModel* model = vm->acquireModelInstance(iBasePath, spawn.name); if (!model) - sLog->outError(LOG_FILTER_GENERAL, "StaticMapTree::LoadMapTile() : could not acquire WorldModel pointer [%u, %u]", tileX, tileY); + VMAP_ERROR_LOG(LOG_FILTER_GENERAL, "StaticMapTree::LoadMapTile() : could not acquire WorldModel pointer [%u, %u]", tileX, tileY); // update tree uint32 referencedVal; @@ -432,7 +427,7 @@ namespace VMAP loadedTileMap::iterator tile = iLoadedTiles.find(tileID); if (tile == iLoadedTiles.end()) { - sLog->outError(LOG_FILTER_GENERAL, "StaticMapTree::UnloadMapTile() : trying to unload non-loaded tile - Map:%u X:%u Y:%u", iMapID, tileX, tileY); + VMAP_ERROR_LOG(LOG_FILTER_GENERAL, "StaticMapTree::UnloadMapTile() : trying to unload non-loaded tile - Map:%u X:%u Y:%u", iMapID, tileX, tileY); return; } if (tile->second) // file associated with tile @@ -466,7 +461,7 @@ namespace VMAP else { if (!iLoadedSpawns.count(referencedNode)) - sLog->outError(LOG_FILTER_GENERAL, "StaticMapTree::UnloadMapTile() : trying to unload non-referenced model '%s' (ID:%u)", spawn.name.c_str(), spawn.ID); + VMAP_ERROR_LOG(LOG_FILTER_GENERAL, "StaticMapTree::UnloadMapTile() : trying to unload non-referenced model '%s' (ID:%u)", spawn.name.c_str(), spawn.ID); else if (--iLoadedSpawns[referencedNode] == 0) { iTreeValues[referencedNode].setUnloaded(); @@ -480,5 +475,4 @@ namespace VMAP } iLoadedTiles.erase(tile); } - } diff --git a/src/server/collision/Maps/MapTree.h b/src/server/collision/Maps/MapTree.h index bd928d85c5a..e97c44d089e 100644 --- a/src/server/collision/Maps/MapTree.h +++ b/src/server/collision/Maps/MapTree.h @@ -31,7 +31,7 @@ namespace VMAP struct LocationInfo { - LocationInfo(): hitInstance(0), hitModel(0), ground_Z(-G3D::inf()) {}; + LocationInfo(): hitInstance(0), hitModel(0), ground_Z(-G3D::inf()) {} const ModelInstance* hitInstance; const GroupModel* hitModel; float ground_Z; @@ -72,7 +72,7 @@ namespace VMAP bool getObjectHitPos(const G3D::Vector3& pos1, const G3D::Vector3& pos2, G3D::Vector3& pResultHitPos, float pModifyDist) const; float getHeight(const G3D::Vector3& pPos, float maxSearchDist) const; bool getAreaInfo(G3D::Vector3 &pos, uint32 &flags, int32 &adtId, int32 &rootId, int32 &groupId) const; - bool GetLocationInfo(const Vector3 &pos, LocationInfo &info) const; + bool GetLocationInfo(const G3D::Vector3 &pos, LocationInfo &info) const; bool InitMap(const std::string &fname, VMapManager2* vm); void UnloadMap(VMapManager2* vm); @@ -80,11 +80,12 @@ namespace VMAP void UnloadMapTile(uint32 tileX, uint32 tileY, VMapManager2* vm); bool isTiled() const { return iIsTiled; } uint32 numLoadedTiles() const { return iLoadedTiles.size(); } + void getModelInstances(ModelInstance* &models, uint32 &count); }; struct AreaInfo { - AreaInfo(): result(false), ground_Z(-G3D::inf()) {}; + AreaInfo(): result(false), ground_Z(-G3D::inf()) {} bool result; float ground_Z; uint32 flags; diff --git a/src/server/collision/Maps/TileAssembler.cpp b/src/server/collision/Maps/TileAssembler.cpp index 380d6b5df21..ba1ae275c9a 100644 --- a/src/server/collision/Maps/TileAssembler.cpp +++ b/src/server/collision/Maps/TileAssembler.cpp @@ -88,7 +88,7 @@ namespace VMAP } else if (entry->second.flags & MOD_WORLDSPAWN) // WMO maps and terrain maps use different origin, so we need to adapt :/ { - // TODO: remove extractor hack and uncomment below line: + /// @todo remove extractor hack and uncomment below line: //entry->second.iPos += Vector3(533.33333f*32, 533.33333f*32, 0.f); entry->second.iBound = entry->second.iBound + Vector3(533.33333f*32, 533.33333f*32, 0.f); } @@ -380,11 +380,11 @@ namespace VMAP } } - fwrite(&displayId,sizeof(uint32),1,model_list_copy); - fwrite(&name_length,sizeof(uint32),1,model_list_copy); - fwrite(&buff,sizeof(char),name_length,model_list_copy); - fwrite(&bounds.low(),sizeof(Vector3),1,model_list_copy); - fwrite(&bounds.high(),sizeof(Vector3),1,model_list_copy); + fwrite(&displayId, sizeof(uint32), 1, model_list_copy); + fwrite(&name_length, sizeof(uint32), 1, model_list_copy); + fwrite(&buff, sizeof(char), name_length, model_list_copy); + fwrite(&bounds.low(), sizeof(Vector3), 1, model_list_copy); + fwrite(&bounds.high(), sizeof(Vector3), 1, model_list_copy); } fclose(model_list); diff --git a/src/server/collision/Maps/TileAssembler.h b/src/server/collision/Maps/TileAssembler.h index 087c2021b50..a11ce272d62 100644 --- a/src/server/collision/Maps/TileAssembler.h +++ b/src/server/collision/Maps/TileAssembler.h @@ -72,12 +72,12 @@ namespace VMAP uint32 liquidflags; std::vector<MeshTriangle> triangles; std::vector<G3D::Vector3> vertexArray; - class WmoLiquid *liquid; + class WmoLiquid* liquid; GroupModel_Raw() : liquid(0) {} ~GroupModel_Raw(); - bool Read(FILE * f); + bool Read(FILE* f); }; struct WorldModel_Raw diff --git a/src/server/collision/Models/GameObjectModel.cpp b/src/server/collision/Models/GameObjectModel.cpp index 237a5b33621..e166a860cd2 100644 --- a/src/server/collision/Models/GameObjectModel.cpp +++ b/src/server/collision/Models/GameObjectModel.cpp @@ -34,8 +34,6 @@ using G3D::Vector3; using G3D::Ray; using G3D::AABox; -#ifndef NO_CORE_FUNCS - struct GameobjectModelData { GameobjectModelData(const std::string& name_, const AABox& box) : @@ -50,11 +48,14 @@ ModelList model_list; void LoadGameObjectModelList() { +#ifndef NO_CORE_FUNCS uint32 oldMSTime = getMSTime(); +#endif + FILE* model_list_file = fopen((sWorld->GetDataPath() + "vmaps/" + VMAP::GAMEOBJECT_MODELS).c_str(), "rb"); if (!model_list_file) { - sLog->outError(LOG_FILTER_GENERAL, "Unable to open '%s' file.", VMAP::GAMEOBJECT_MODELS); + VMAP_ERROR_LOG(LOG_FILTER_GENERAL, "Unable to open '%s' file.", VMAP::GAMEOBJECT_MODELS); return; } @@ -73,19 +74,18 @@ void LoadGameObjectModelList() || fread(&v1, sizeof(Vector3), 1, model_list_file) != 1 || fread(&v2, sizeof(Vector3), 1, model_list_file) != 1) { - sLog->outError(LOG_FILTER_GENERAL, "File '%s' seems to be corrupted!", VMAP::GAMEOBJECT_MODELS); + VMAP_ERROR_LOG(LOG_FILTER_GENERAL, "File '%s' seems to be corrupted!", VMAP::GAMEOBJECT_MODELS); break; } model_list.insert ( - ModelList::value_type( displayId, GameobjectModelData(std::string(buff,name_length),AABox(v1,v2)) ) + ModelList::value_type( displayId, GameobjectModelData(std::string(buff, name_length), AABox(v1, v2)) ) ); } fclose(model_list_file); - sLog->outInfo(LOG_FILTER_SERVER_LOADING, ">> Loaded %u GameObject models in %u ms", uint32(model_list.size()), GetMSTimeDiffToNow(oldMSTime)); - + VMAP_INFO_LOG(LOG_FILTER_SERVER_LOADING, ">> Loaded %u GameObject models in %u ms", uint32(model_list.size()), GetMSTimeDiffToNow(oldMSTime)); } GameObjectModel::~GameObjectModel() @@ -104,7 +104,7 @@ bool GameObjectModel::initialize(const GameObject& go, const GameObjectDisplayIn // ignore models with no bounds if (mdl_box == G3D::AABox::zero()) { - sLog->outError(LOG_FILTER_GENERAL, "GameObject model %s has zero bounds, loading skipped", it->second.name.c_str()); + VMAP_ERROR_LOG(LOG_FILTER_GENERAL, "GameObject model %s has zero bounds, loading skipped", it->second.name.c_str()); return false; } @@ -184,5 +184,3 @@ bool GameObjectModel::intersectRay(const G3D::Ray& ray, float& MaxDist, bool Sto } return hit; } - -#endif diff --git a/src/server/collision/Models/ModelInstance.h b/src/server/collision/Models/ModelInstance.h index 5af02a1d1b1..f26089bb46c 100644 --- a/src/server/collision/Models/ModelInstance.h +++ b/src/server/collision/Models/ModelInstance.h @@ -74,6 +74,8 @@ namespace VMAP G3D::Matrix3 iInvRot; float iInvScale; WorldModel* iModel; + public: + WorldModel* getWorldModel(); }; } // namespace VMAP diff --git a/src/server/collision/Models/WorldModel.h b/src/server/collision/Models/WorldModel.h index 8e046e561f7..9d588316cce 100644 --- a/src/server/collision/Models/WorldModel.h +++ b/src/server/collision/Models/WorldModel.h @@ -36,8 +36,8 @@ namespace VMAP class MeshTriangle { public: - MeshTriangle(){}; - MeshTriangle(uint32 na, uint32 nb, uint32 nc): idx0(na), idx1(nb), idx2(nc) {}; + MeshTriangle(){} + MeshTriangle(uint32 na, uint32 nb, uint32 nc): idx0(na), idx1(nb), idx2(nc) {} uint32 idx0; uint32 idx1; @@ -47,11 +47,11 @@ namespace VMAP class WmoLiquid { public: - WmoLiquid(uint32 width, uint32 height, const Vector3 &corner, uint32 type); + WmoLiquid(uint32 width, uint32 height, const G3D::Vector3 &corner, uint32 type); WmoLiquid(const WmoLiquid &other); ~WmoLiquid(); WmoLiquid& operator=(const WmoLiquid &other); - bool GetLiquidHeight(const Vector3 &pos, float &liqHeight) const; + bool GetLiquidHeight(const G3D::Vector3 &pos, float &liqHeight) const; uint32 GetType() const { return iType; } float *GetHeightStorage() { return iHeight; } uint8 *GetFlagsStorage() { return iFlags; } @@ -59,13 +59,15 @@ namespace VMAP bool writeToFile(FILE* wf); static bool readFromFile(FILE* rf, WmoLiquid* &liquid); private: - WmoLiquid(): iHeight(0), iFlags(0) {}; - uint32 iTilesX; //!< number of tiles in x direction, each + WmoLiquid(): iHeight(0), iFlags(0) {} + uint32 iTilesX; //!< number of tiles in x direction, each uint32 iTilesY; - Vector3 iCorner; //!< the lower corner - uint32 iType; //!< liquid type - float *iHeight; //!< (tilesX + 1)*(tilesY + 1) height values - uint8 *iFlags; //!< info if liquid tile is used + G3D::Vector3 iCorner; //!< the lower corner + uint32 iType; //!< liquid type + float *iHeight; //!< (tilesX + 1)*(tilesY + 1) height values + uint8 *iFlags; //!< info if liquid tile is used + public: + void getPosInfo(uint32 &tilesX, uint32 &tilesY, G3D::Vector3 &corner) const; }; /*! holding additional info for WMO group files */ @@ -74,16 +76,16 @@ namespace VMAP public: GroupModel(): iLiquid(0) {} GroupModel(const GroupModel &other); - GroupModel(uint32 mogpFlags, uint32 groupWMOID, const AABox &bound): + GroupModel(uint32 mogpFlags, uint32 groupWMOID, const G3D::AABox &bound): iBound(bound), iMogpFlags(mogpFlags), iGroupWMOID(groupWMOID), iLiquid(0) {} ~GroupModel() { delete iLiquid; } //! pass mesh data to object and create BIH. Passed vectors get get swapped with old geometry! - void setMeshData(std::vector<Vector3> &vert, std::vector<MeshTriangle> &tri); + void setMeshData(std::vector<G3D::Vector3> &vert, std::vector<MeshTriangle> &tri); void setLiquidData(WmoLiquid*& liquid) { iLiquid = liquid; liquid = NULL; } bool IntersectRay(const G3D::Ray &ray, float &distance, bool stopAtFirstHit) const; - bool IsInsideObject(const Vector3 &pos, const Vector3 &down, float &z_dist) const; - bool GetLiquidLevel(const Vector3 &pos, float &liqHeight) const; + bool IsInsideObject(const G3D::Vector3 &pos, const G3D::Vector3 &down, float &z_dist) const; + bool GetLiquidLevel(const G3D::Vector3 &pos, float &liqHeight) const; uint32 GetLiquidType() const; bool writeToFile(FILE* wf); bool readFromFile(FILE* rf); @@ -94,10 +96,12 @@ namespace VMAP G3D::AABox iBound; uint32 iMogpFlags;// 0x8 outdor; 0x2000 indoor uint32 iGroupWMOID; - std::vector<Vector3> vertices; + std::vector<G3D::Vector3> vertices; std::vector<MeshTriangle> triangles; BIH meshTree; WmoLiquid* iLiquid; + public: + void getMeshData(std::vector<G3D::Vector3> &vertices, std::vector<MeshTriangle> &triangles, WmoLiquid* &liquid); }; /*! Holds a model (converted M2 or WMO) in its original coordinate space */ class WorldModel @@ -117,6 +121,8 @@ namespace VMAP uint32 RootWMOID; std::vector<GroupModel> groupModels; BIH groupTree; + public: + void getGroupModels(std::vector<GroupModel> &groupModels); }; } // namespace VMAP diff --git a/src/server/collision/RegularGrid.h b/src/server/collision/RegularGrid.h index 5b7d1d74987..d1832c1ea06 100644 --- a/src/server/collision/RegularGrid.h +++ b/src/server/collision/RegularGrid.h @@ -3,18 +3,12 @@ #include <G3D/Ray.h> -#include <G3D/AABox.h> #include <G3D/Table.h> #include <G3D/BoundsTrait.h> #include <G3D/PositionTrait.h> #include "Errors.h" -using G3D::Vector2; -using G3D::Vector3; -using G3D::AABox; -using G3D::Ray; - template<class Node> struct NodeCreator{ static Node * makeNode(int /*x*/, int /*y*/) { return new Node();} @@ -54,7 +48,7 @@ public: void insert(const T& value) { - Vector3 pos; + G3D::Vector3 pos; PositionFunc::getPosition(value, pos); Node& node = getGridFor(pos.x, pos.y); node.insert(value); @@ -104,18 +98,18 @@ public: { ASSERT(x < CELL_NUMBER && y < CELL_NUMBER); if (!nodes[x][y]) - nodes[x][y] = NodeCreatorFunc::makeNode(x,y); + nodes[x][y] = NodeCreatorFunc::makeNode(x, y); return *nodes[x][y]; } template<typename RayCallback> - void intersectRay(const Ray& ray, RayCallback& intersectCallback, float max_dist) + void intersectRay(const G3D::Ray& ray, RayCallback& intersectCallback, float max_dist) { intersectRay(ray, intersectCallback, max_dist, ray.origin() + ray.direction() * max_dist); } template<typename RayCallback> - void intersectRay(const Ray& ray, RayCallback& intersectCallback, float& max_dist, const Vector3& end) + void intersectRay(const G3D::Ray& ray, RayCallback& intersectCallback, float& max_dist, const G3D::Vector3& end) { Cell cell = Cell::ComputeCell(ray.origin().x, ray.origin().y); if (!cell.isValid()) @@ -191,7 +185,7 @@ public: } template<typename IsectCallback> - void intersectPoint(const Vector3& point, IsectCallback& intersectCallback) + void intersectPoint(const G3D::Vector3& point, IsectCallback& intersectCallback) { Cell cell = Cell::ComputeCell(point.x, point.y); if (!cell.isValid()) @@ -202,7 +196,7 @@ public: // Optimized verson of intersectRay function for rays with vertical directions template<typename RayCallback> - void intersectZAllignedRay(const Ray& ray, RayCallback& intersectCallback, float& max_dist) + void intersectZAllignedRay(const G3D::Ray& ray, RayCallback& intersectCallback, float& max_dist) { Cell cell = Cell::ComputeCell(ray.origin().x, ray.origin().y); if (!cell.isValid()) diff --git a/src/server/collision/VMapDefinitions.h b/src/server/collision/VMapDefinitions.h index 609d00cd00f..bb0766dc8ff 100644 --- a/src/server/collision/VMapDefinitions.h +++ b/src/server/collision/VMapDefinitions.h @@ -31,4 +31,16 @@ namespace VMAP // defined in TileAssembler.cpp currently... bool readChunk(FILE* rf, char *dest, const char *compare, uint32 len); } + +// Set of helper macros for extractors (VMAP and MMAP) +#ifndef NO_CORE_FUNCS +#define VMAP_ERROR_LOG(FILTER, ...) sLog->outError(FILTER, __VA_ARGS__) +#define VMAP_DEBUG_LOG(FILTER, ...) sLog->outDebug(FILTER, __VA_ARGS__) +#define VMAP_INFO_LOG(FILTER, ...) sLog->outInfo(FILTER, __VA_ARGS__) +#else +#define VMAP_ERROR_LOG(FILTER, ...) (void)sizeof(FILTER) +#define VMAP_DEBUG_LOG(FILTER, ...) (void)sizeof(FILTER) +#define VMAP_INFO_LOG(FILTER, ...) (void)sizeof(FILTER) +#endif + #endif diff --git a/src/server/game/AI/CoreAI/CombatAI.cpp b/src/server/game/AI/CoreAI/CombatAI.cpp index 95a5a9a5116..34a0e522796 100644 --- a/src/server/game/AI/CoreAI/CombatAI.cpp +++ b/src/server/game/AI/CoreAI/CombatAI.cpp @@ -32,7 +32,7 @@ int AggressorAI::Permissible(const Creature* creature) return PERMIT_BASE_NO; } -void AggressorAI::UpdateAI(const uint32 /*diff*/) +void AggressorAI::UpdateAI(uint32 /*diff*/) { if (!UpdateVictim()) return; @@ -93,7 +93,7 @@ void CombatAI::EnterCombat(Unit* who) } } -void CombatAI::UpdateAI(const uint32 diff) +void CombatAI::UpdateAI(uint32 diff) { if (!UpdateVictim()) return; @@ -157,7 +157,7 @@ void CasterAI::EnterCombat(Unit* who) } } -void CasterAI::UpdateAI(const uint32 diff) +void CasterAI::UpdateAI(uint32 diff) { if (!UpdateVictim()) return; @@ -219,7 +219,7 @@ void ArcherAI::AttackStart(Unit* who) me->GetMotionMaster()->MoveIdle(); } -void ArcherAI::UpdateAI(const uint32 /*diff*/) +void ArcherAI::UpdateAI(uint32 /*diff*/) { if (!UpdateVictim()) return; @@ -247,7 +247,7 @@ TurretAI::TurretAI(Creature* c) : CreatureAI(c) bool TurretAI::CanAIAttack(const Unit* /*who*/) const { - // TODO: use one function to replace it + /// @todo use one function to replace it if (!me->IsWithinCombatRange(me->getVictim(), me->m_CombatDistance) || (m_minRange && me->IsWithinCombatRange(me->getVictim(), m_minRange))) return false; @@ -260,7 +260,7 @@ void TurretAI::AttackStart(Unit* who) me->Attack(who, false); } -void TurretAI::UpdateAI(const uint32 /*diff*/) +void TurretAI::UpdateAI(uint32 /*diff*/) { if (!UpdateVictim()) return; @@ -280,7 +280,7 @@ VehicleAI::VehicleAI(Creature* c) : CreatureAI(c), m_vehicle(c->GetVehicleKit()) } //NOTE: VehicleAI::UpdateAI runs even while the vehicle is mounted -void VehicleAI::UpdateAI(const uint32 diff) +void VehicleAI::UpdateAI(uint32 diff) { CheckConditions(diff); diff --git a/src/server/game/AI/CoreAI/CombatAI.h b/src/server/game/AI/CoreAI/CombatAI.h index 8b10a8d6190..315ff861da9 100644 --- a/src/server/game/AI/CoreAI/CombatAI.h +++ b/src/server/game/AI/CoreAI/CombatAI.h @@ -30,7 +30,7 @@ class AggressorAI : public CreatureAI public: explicit AggressorAI(Creature* c) : CreatureAI(c) {} - void UpdateAI(const uint32); + void UpdateAI(uint32); static int Permissible(const Creature*); }; @@ -45,7 +45,7 @@ class CombatAI : public CreatureAI void Reset(); void EnterCombat(Unit* who); void JustDied(Unit* killer); - void UpdateAI(const uint32 diff); + void UpdateAI(uint32 diff); void SpellInterrupted(uint32 spellId, uint32 unTimeMs); static int Permissible(const Creature*); protected: @@ -59,7 +59,7 @@ class CasterAI : public CombatAI explicit CasterAI(Creature* c) : CombatAI(c) { m_attackDist = MELEE_RANGE; } void InitializeAI(); void AttackStart(Unit* victim) { AttackStartCaster(victim, m_attackDist); } - void UpdateAI(const uint32 diff); + void UpdateAI(uint32 diff); void EnterCombat(Unit* /*who*/); private: float m_attackDist; @@ -70,7 +70,7 @@ struct ArcherAI : public CreatureAI public: explicit ArcherAI(Creature* c); void AttackStart(Unit* who); - void UpdateAI(const uint32 diff); + void UpdateAI(uint32 diff); static int Permissible(const Creature*); protected: @@ -83,7 +83,7 @@ struct TurretAI : public CreatureAI explicit TurretAI(Creature* c); bool CanAIAttack(const Unit* who) const; void AttackStart(Unit* who); - void UpdateAI(const uint32 diff); + void UpdateAI(uint32 diff); static int Permissible(const Creature*); protected: @@ -97,7 +97,7 @@ struct VehicleAI : public CreatureAI public: explicit VehicleAI(Creature* c); - void UpdateAI(const uint32 diff); + void UpdateAI(uint32 diff); static int Permissible(const Creature*); void Reset(); void MoveInLineOfSight(Unit*) {} diff --git a/src/server/game/AI/CoreAI/GameObjectAI.h b/src/server/game/AI/CoreAI/GameObjectAI.h index feb3bbefcb8..32a6e9a670c 100644 --- a/src/server/game/AI/CoreAI/GameObjectAI.h +++ b/src/server/game/AI/CoreAI/GameObjectAI.h @@ -40,7 +40,7 @@ class GameObjectAI virtual void Reset() { } // Pass parameters between AI - virtual void DoAction(const int32 /*param = 0 */) {} + virtual void DoAction(int32 /*param = 0 */) {} virtual void SetGUID(uint64 /*guid*/, int32 /*id = 0 */) {} virtual uint64 GetGUID(int32 /*id = 0 */) const { return 0; } diff --git a/src/server/game/AI/CoreAI/PassiveAI.cpp b/src/server/game/AI/CoreAI/PassiveAI.cpp index 2407b1f71e6..187a72bae92 100644 --- a/src/server/game/AI/CoreAI/PassiveAI.cpp +++ b/src/server/game/AI/CoreAI/PassiveAI.cpp @@ -24,7 +24,7 @@ PassiveAI::PassiveAI(Creature* c) : CreatureAI(c) { me->SetReactState(REACT_PASS PossessedAI::PossessedAI(Creature* c) : CreatureAI(c) { me->SetReactState(REACT_PASSIVE); } NullCreatureAI::NullCreatureAI(Creature* c) : CreatureAI(c) { me->SetReactState(REACT_PASSIVE); } -void PassiveAI::UpdateAI(const uint32) +void PassiveAI::UpdateAI(uint32) { if (me->isInCombat() && me->getAttackers().empty()) EnterEvadeMode(); @@ -35,7 +35,7 @@ void PossessedAI::AttackStart(Unit* target) me->Attack(target, true); } -void PossessedAI::UpdateAI(const uint32 /*diff*/) +void PossessedAI::UpdateAI(uint32 /*diff*/) { if (me->getVictim()) { diff --git a/src/server/game/AI/CoreAI/PassiveAI.h b/src/server/game/AI/CoreAI/PassiveAI.h index cb513234be3..cb047ff364b 100644 --- a/src/server/game/AI/CoreAI/PassiveAI.h +++ b/src/server/game/AI/CoreAI/PassiveAI.h @@ -28,7 +28,7 @@ class PassiveAI : public CreatureAI void MoveInLineOfSight(Unit*) {} void AttackStart(Unit*) {} - void UpdateAI(const uint32); + void UpdateAI(uint32); static int Permissible(const Creature*) { return PERMIT_BASE_IDLE; } }; @@ -40,7 +40,7 @@ class PossessedAI : public CreatureAI void MoveInLineOfSight(Unit*) {} void AttackStart(Unit* target); - void UpdateAI(const uint32); + void UpdateAI(uint32); void EnterEvadeMode() {} void JustDied(Unit*); @@ -56,7 +56,7 @@ class NullCreatureAI : public CreatureAI void MoveInLineOfSight(Unit*) {} void AttackStart(Unit*) {} - void UpdateAI(const uint32) {} + void UpdateAI(uint32) {} void EnterEvadeMode() {} void OnCharmed(bool /*apply*/) {} diff --git a/src/server/game/AI/CoreAI/PetAI.cpp b/src/server/game/AI/CoreAI/PetAI.cpp index a8d2a2248ad..85864cab493 100644 --- a/src/server/game/AI/CoreAI/PetAI.cpp +++ b/src/server/game/AI/CoreAI/PetAI.cpp @@ -40,7 +40,6 @@ int PetAI::Permissible(const Creature* creature) PetAI::PetAI(Creature* c) : CreatureAI(c), i_tracker(TIME_INTERVAL_LOOK) { - m_AllySet.clear(); UpdateAllies(); } @@ -74,7 +73,7 @@ void PetAI::_stopAttack() HandleReturnMovement(); } -void PetAI::UpdateAI(const uint32 diff) +void PetAI::UpdateAI(uint32 diff) { if (!me->isAlive() || !me->GetCharmInfo()) return; @@ -432,29 +431,23 @@ void PetAI::HandleReturnMovement() if (!me->GetCharmInfo()->IsAtStay() && !me->GetCharmInfo()->IsReturning()) { // Return to previous position where stay was clicked - if (!me->GetCharmInfo()->IsCommandAttack()) - { - float x, y, z; + float x, y, z; - me->GetCharmInfo()->GetStayPosition(x, y, z); - ClearCharmInfoFlags(); - me->GetCharmInfo()->SetIsReturning(true); - me->GetMotionMaster()->Clear(); - me->GetMotionMaster()->MovePoint(me->GetGUIDLow(), x, y, z); - } + me->GetCharmInfo()->GetStayPosition(x, y, z); + ClearCharmInfoFlags(); + me->GetCharmInfo()->SetIsReturning(true); + me->GetMotionMaster()->Clear(); + me->GetMotionMaster()->MovePoint(me->GetGUIDLow(), x, y, z); } } else // COMMAND_FOLLOW { if (!me->GetCharmInfo()->IsFollowing() && !me->GetCharmInfo()->IsReturning()) { - if (!me->GetCharmInfo()->IsCommandAttack()) - { - ClearCharmInfoFlags(); - me->GetCharmInfo()->SetIsReturning(true); - me->GetMotionMaster()->Clear(); - me->GetMotionMaster()->MoveFollow(me->GetCharmerOrOwner(), PET_FOLLOW_DIST, me->GetFollowAngle()); - } + ClearCharmInfoFlags(); + me->GetCharmInfo()->SetIsReturning(true); + me->GetMotionMaster()->Clear(); + me->GetMotionMaster()->MoveFollow(me->GetCharmerOrOwner(), PET_FOLLOW_DIST, me->GetFollowAngle()); } } } @@ -473,12 +466,13 @@ void PetAI::DoAttack(Unit* target, bool chase) if (me->HasReactState(REACT_AGGRESSIVE) && !me->GetCharmInfo()->IsCommandAttack()) me->SendPetAIReaction(me->GetGUID()); - if (chase) { - ClearCharmInfoFlags(); - me->GetMotionMaster()->Clear(); - me->GetMotionMaster()->MoveChase(target); + bool oldCmdAttack = me->GetCharmInfo()->IsCommandAttack(); // This needs to be reset after other flags are cleared + ClearCharmInfoFlags(); + me->GetCharmInfo()->SetIsCommandAttack(oldCmdAttack); // For passive pets commanded to attack so they will use spells + me->GetMotionMaster()->Clear(); + me->GetMotionMaster()->MoveChase(target); } else // (Stay && ((Aggressive || Defensive) && In Melee Range))) { diff --git a/src/server/game/AI/CoreAI/PetAI.h b/src/server/game/AI/CoreAI/PetAI.h index 674c3dc1748..efb088160f3 100644 --- a/src/server/game/AI/CoreAI/PetAI.h +++ b/src/server/game/AI/CoreAI/PetAI.h @@ -31,7 +31,7 @@ class PetAI : public CreatureAI explicit PetAI(Creature* c); - void UpdateAI(const uint32); + void UpdateAI(uint32); static int Permissible(const Creature*); void KilledUnit(Unit* /*victim*/); diff --git a/src/server/game/AI/CoreAI/ReactorAI.cpp b/src/server/game/AI/CoreAI/ReactorAI.cpp index 31b9a82c534..b99885088d4 100644 --- a/src/server/game/AI/CoreAI/ReactorAI.cpp +++ b/src/server/game/AI/CoreAI/ReactorAI.cpp @@ -23,10 +23,7 @@ #include "ObjectAccessor.h" #include "CreatureAIImpl.h" -#define REACTOR_VISIBLE_RANGE (26.46f) - -int -ReactorAI::Permissible(const Creature* creature) +int ReactorAI::Permissible(const Creature* creature) { if (creature->isCivilian() || creature->IsNeutralToAll()) return PERMIT_BASE_REACTIVE; @@ -34,24 +31,10 @@ ReactorAI::Permissible(const Creature* creature) return PERMIT_BASE_NO; } -void -ReactorAI::MoveInLineOfSight(Unit*) -{ -} - -void -ReactorAI::UpdateAI(const uint32 /*time_diff*/) +void ReactorAI::UpdateAI(uint32 /*diff*/) { - // update i_victimGuid if me->getVictim() !=0 and changed if (!UpdateVictim()) return; - if (me->isAttackReady()) - { - if (me->IsWithinMeleeRange(me->getVictim())) - { - me->AttackerStateUpdate(me->getVictim()); - me->resetAttackTimer(); - } - } + DoMeleeAttackIfReady(); } diff --git a/src/server/game/AI/CoreAI/ReactorAI.h b/src/server/game/AI/CoreAI/ReactorAI.h index 39af09c4a9d..449458f39be 100644 --- a/src/server/game/AI/CoreAI/ReactorAI.h +++ b/src/server/game/AI/CoreAI/ReactorAI.h @@ -29,9 +29,9 @@ class ReactorAI : public CreatureAI explicit ReactorAI(Creature* c) : CreatureAI(c) {} - void MoveInLineOfSight(Unit*); + void MoveInLineOfSight(Unit*) {} + void UpdateAI(uint32 diff); - void UpdateAI(const uint32); static int Permissible(const Creature*); }; #endif diff --git a/src/server/game/AI/CoreAI/TotemAI.cpp b/src/server/game/AI/CoreAI/TotemAI.cpp index 8846066fee4..45865c5dbc2 100644 --- a/src/server/game/AI/CoreAI/TotemAI.cpp +++ b/src/server/game/AI/CoreAI/TotemAI.cpp @@ -49,7 +49,7 @@ void TotemAI::EnterEvadeMode() me->CombatStop(true); } -void TotemAI::UpdateAI(uint32 const /*diff*/) +void TotemAI::UpdateAI(uint32 /*diff*/) { if (me->ToTotem()->GetTotemType() != TOTEM_ACTIVE) return; diff --git a/src/server/game/AI/CoreAI/TotemAI.h b/src/server/game/AI/CoreAI/TotemAI.h index f9a6acc7fce..897cfea1c44 100644 --- a/src/server/game/AI/CoreAI/TotemAI.h +++ b/src/server/game/AI/CoreAI/TotemAI.h @@ -35,7 +35,7 @@ class TotemAI : public CreatureAI void AttackStart(Unit* victim); void EnterEvadeMode(); - void UpdateAI(uint32 const diff); + void UpdateAI(uint32 diff); static int Permissible(Creature const* creature); private: diff --git a/src/server/game/AI/CoreAI/UnitAI.cpp b/src/server/game/AI/CoreAI/UnitAI.cpp index a3cb57b3332..e0e9e68315d 100644 --- a/src/server/game/AI/CoreAI/UnitAI.cpp +++ b/src/server/game/AI/CoreAI/UnitAI.cpp @@ -103,8 +103,7 @@ void UnitAI::DoAddAuraToAllHostilePlayers(uint32 spellid) if (unit->GetTypeId() == TYPEID_PLAYER) me->AddAura(spellid, unit); } - }else - return; + } } void UnitAI::DoCastToAllHostilePlayers(uint32 spellid, bool triggered) @@ -118,8 +117,7 @@ void UnitAI::DoCastToAllHostilePlayers(uint32 spellid, bool triggered) if (unit->GetTypeId() == TYPEID_PLAYER) me->CastSpell(unit, spellid, triggered); } - }else - return; + } } void UnitAI::DoCast(uint32 spellId) @@ -148,8 +146,7 @@ void UnitAI::DoCast(uint32 spellId) float range = spellInfo->GetMaxRange(false); DefaultTargetSelector targetSelector(me, range, playerOnly, -(int32)spellId); - if (!(spellInfo->Attributes & SPELL_ATTR0_BREAKABLE_BY_DAMAGE) - && !(spellInfo->AuraInterruptFlags & AURA_INTERRUPT_FLAG_NOT_VICTIM) + if (!(spellInfo->AuraInterruptFlags & AURA_INTERRUPT_FLAG_NOT_VICTIM) && targetSelector(me->getVictim())) target = me->getVictim(); else @@ -172,7 +169,9 @@ void UnitAI::DoCast(Unit* victim, uint32 spellId, bool triggered) void UnitAI::DoCastVictim(uint32 spellId, bool triggered) { - // Why don't we check for casting unit_state and existing target as we do in DoCast(.. ? + if (!me->getVictim() || (me->HasUnitState(UNIT_STATE_CASTING) && !triggered)) + return; + me->CastSpell(me->getVictim(), spellId, triggered); } @@ -238,7 +237,10 @@ void UnitAI::FillAISpellInfo() } //Enable PlayerAI when charmed -void PlayerAI::OnCharmed(bool apply) { me->IsAIEnabled = apply; } +void PlayerAI::OnCharmed(bool apply) +{ + me->IsAIEnabled = apply; +} void SimpleCharmedAI::UpdateAI(const uint32 /*diff*/) { diff --git a/src/server/game/AI/CoreAI/UnitAI.h b/src/server/game/AI/CoreAI/UnitAI.h index 3cb7c15dce4..f048c049b34 100644 --- a/src/server/game/AI/CoreAI/UnitAI.h +++ b/src/server/game/AI/CoreAI/UnitAI.h @@ -89,7 +89,7 @@ struct DefaultTargetSelector : public std::unary_function<Unit*, bool> }; // Target selector for spell casts checking range, auras and attributes -// TODO: Add more checks from Spell::CheckCast +/// @todo Add more checks from Spell::CheckCast struct SpellTargetSelector : public std::unary_function<Unit*, bool> { public: @@ -125,7 +125,7 @@ class UnitAI virtual bool CanAIAttack(Unit const* /*target*/) const { return true; } virtual void AttackStart(Unit* /*target*/); - virtual void UpdateAI(uint32 const diff) = 0; + virtual void UpdateAI(uint32 diff) = 0; virtual void InitializeAI() { if (!me->isDead()) Reset(); } @@ -135,7 +135,7 @@ class UnitAI virtual void OnCharmed(bool apply) = 0; // Pass parameters between AI - virtual void DoAction(int32 const /*param*/) {} + virtual void DoAction(int32 /*param*/) {} virtual uint32 GetData(uint32 /*id = 0*/) const { return 0; } virtual void SetData(uint32 /*id*/, uint32 /*value*/) {} virtual void SetGUID(uint64 /*guid*/, int32 /*id*/ = 0) {} @@ -278,7 +278,7 @@ class PlayerAI : public UnitAI class SimpleCharmedAI : public PlayerAI { public: - void UpdateAI(uint32 const diff); + void UpdateAI(uint32 diff); SimpleCharmedAI(Player* player): PlayerAI(player) {} }; diff --git a/src/server/game/AI/CreatureAI.cpp b/src/server/game/AI/CreatureAI.cpp index 427818fe571..e8df19630c4 100644 --- a/src/server/game/AI/CreatureAI.cpp +++ b/src/server/game/AI/CreatureAI.cpp @@ -134,7 +134,7 @@ void CreatureAI::MoveInLineOfSight(Unit* who) AttackStart(who); //else if (who->getVictim() && me->IsFriendlyTo(who) // && me->IsWithinDistInMap(who, sWorld->getIntConfig(CONFIG_CREATURE_FAMILY_ASSISTANCE_RADIUS)) - // && me->canStartAttack(who->getVictim(), true)) // TODO: if we use true, it will not attack it when it arrives + // && me->canStartAttack(who->getVictim(), true)) /// @todo if we use true, it will not attack it when it arrives // me->GetMotionMaster()->MoveChase(who->getVictim()); } diff --git a/src/server/game/AI/CreatureAIImpl.h b/src/server/game/AI/CreatureAIImpl.h index 559240c4a3f..6c5cb5622b3 100644 --- a/src/server/game/AI/CreatureAIImpl.h +++ b/src/server/game/AI/CreatureAIImpl.h @@ -313,96 +313,177 @@ const T& RAND(const T& v1, const T& v2, const T& v3, const T& v4, const T& v5, c class EventMap { - typedef std::map<uint32, uint32> StorageType; + /** + * Internal storage type. + * Key: Time as uint32 when the event should occur. + * Value: The event data as uint32. + * + * Structure of event data: + * - Bit 0 - 15: Event Id. + * - Bit 16 - 23: Group + * - Bit 24 - 31: Phase + * - Pattern: 0xPPGGEEEE + */ + typedef std::multimap<uint32, uint32> EventStore; public: EventMap() : _time(0), _phase(0) {} - // Returns current timer value, does not represent real dates/times - uint32 GetTimer() const { return _time; } - - // Removes all events and clears phase + /** + * @name Reset + * @brief Removes all scheduled events and resets time and phase. + */ void Reset() { - _eventMap.clear(); _time = 0; _phase = 0; + _eventMap.clear(); + _time = 0; + _phase = 0; + } + + /** + * @name Update + * @brief Updates the timer of the event map. + * @param time Value to be added to time. + */ + void Update(uint32 time) + { + _time += time; } - void Update(uint32 time) { _time += time; } + /** + * @name GetTimer + * @return Current timer value. + */ + uint32 GetTimer() const + { + return _time; + } - uint32 GetPhaseMask() const { return (_phase >> 24) & 0xFF; } + /** + * @name GetPhaseMask + * @return Active phases as mask. + */ + uint8 GetPhaseMask() const + { + return _phase; + } - bool Empty() const { return _eventMap.empty(); } + /** + * @name Empty + * @return True, if there are no events scheduled. + */ + bool Empty() const + { + return _eventMap.empty(); + } - // Sets event phase, must be in range 1 - 8 - void SetPhase(uint32 phase) + /** + * @name SetPhase + * @brief Sets the phase of the map (absolute). + * @param phase Phase which should be set. Values: 1 - 8. 0 resets phase. + */ + void SetPhase(uint8 phase) { - if (phase && phase < 8) - _phase = (1 << (phase + 24)); - else if (!phase) + if (!phase) _phase = 0; + else if (phase <= 8) + _phase = (1 << (phase - 1)); } - // Creates new event entry in map with given id, time, group if given (1 - 8) and phase if given (1 - 8) - // 0 for group/phase means it belongs to no group or runs in all phases - void ScheduleEvent(uint32 eventId, uint32 time, uint32 groupId = 0, uint32 phase = 0) + /** + * @name AddPhase + * @brief Activates the given phase (bitwise). + * @param phase Phase which should be activated. Values: 1 - 8 + */ + void AddPhase(uint8 phase) { - time += _time; - if (groupId && groupId < 9) - eventId |= (1 << (groupId + 16)); - if (phase && phase < 8) - eventId |= (1 << (phase + 24)); - StorageType::const_iterator itr = _eventMap.find(time); - while (itr != _eventMap.end()) - { - ++time; - itr = _eventMap.find(time); - } + if (phase && phase <= 8) + _phase |= (1 << (phase - 1)); + } - _eventMap.insert(StorageType::value_type(time, eventId)); + /** + * @name RemovePhase + * @brief Deactivates the given phase (bitwise). + * @param phase Phase which should be deactivated. Values: 1 - 8. + */ + void RemovePhase(uint8 phase) + { + if (phase && phase <= 8) + _phase &= ~(1 << (phase - 1)); } - // Removes event with specified id and creates new entry for it - void RescheduleEvent(uint32 eventId, uint32 time, uint32 groupId = 0, uint32 phase = 0) + /** + * @name ScheduleEvent + * @brief Creates new event entry in map. + * @param eventId The id of the new event. + * @param time The time in milliseconds until the event occurs. + * @param group The group which the event is associated to. Has to be between 1 and 8. 0 means it has no group. + * @param phase The phase in which the event can occur. Has to be between 1 and 8. 0 means it can occur in all phases. + */ + void ScheduleEvent(uint32 eventId, uint32 time, uint32 group = 0, uint8 phase = 0) + { + if (group && group <= 8) + eventId |= (1 << (group + 15)); + + if (phase && phase <= 8) + eventId |= (1 << (phase + 23)); + + _eventMap.insert(EventStore::value_type(_time + time, eventId)); + } + + /** + * @name RescheduleEvent + * @brief Cancels the given event and reschedules it. + * @param eventId The id of the event. + * @param time The time in milliseconds until the event occurs. + * @param group The group which the event is associated to. Has to be between 1 and 8. 0 means it has no group. + * @param phase The phase in which the event can occur. Has to be between 1 and 8. 0 means it can occur in all phases. + */ + void RescheduleEvent(uint32 eventId, uint32 time, uint32 group = 0, uint8 phase = 0) { CancelEvent(eventId); - ScheduleEvent(eventId, time, groupId, phase); + ScheduleEvent(eventId, time, group, phase); } - // Reschedules closest event + /** + * @name RepeatEvent + * @brief Cancels the closest event and reschedules it. + * @param time Time until the event occurs. + */ void RepeatEvent(uint32 time) { - if (_eventMap.empty()) + if (Empty()) return; uint32 eventId = _eventMap.begin()->second; _eventMap.erase(_eventMap.begin()); - time += _time; - StorageType::const_iterator itr = _eventMap.find(time); - while (itr != _eventMap.end()) - { - ++time; - itr = _eventMap.find(time); - } - - _eventMap.insert(StorageType::value_type(time, eventId)); + ScheduleEvent(eventId, time); } - // Removes first event + /** + * @name PopEvent + * @brief Remove the first event in the map. + */ void PopEvent() { - if (!_eventMap.empty()) + if (!Empty()) _eventMap.erase(_eventMap.begin()); } - // Gets next event id to execute and removes it from map + /** + * @name ExecuteEvent + * @brief Returns the next event to execute and removes it from map. + * @return Id of the event to execute. + */ uint32 ExecuteEvent() { - while (!_eventMap.empty()) + while (!Empty()) { - StorageType::iterator itr = _eventMap.begin(); + EventStore::iterator itr = _eventMap.begin(); + if (itr->first > _time) return 0; - else if (_phase && (itr->second & 0xFF000000) && !(itr->second & _phase)) + else if (_phase && (itr->second & 0xFF000000) && !((itr->second >> 24) & _phase)) _eventMap.erase(itr); else { @@ -411,18 +492,24 @@ class EventMap return eventId; } } + return 0; } - // Gets next event id to execute + /** + * @name GetEvent + * @brief Returns the next event to execute. + * @return Id of the event to execute. + */ uint32 GetEvent() { - while (!_eventMap.empty()) + while (!Empty()) { - StorageType::iterator itr = _eventMap.begin(); + EventStore::iterator itr = _eventMap.begin(); + if (itr->first > _time) return 0; - else if (_phase && (itr->second & 0xFF000000) && !(itr->second & _phase)) + else if (_phase && (itr->second & 0xFF000000) && !(itr->second & (_phase << 24))) _eventMap.erase(itr); else return (itr->second & 0x0000FFFF); @@ -431,81 +518,150 @@ class EventMap return 0; } - // Delay all events + /** + * @name DelayEvents + * @brief Delays all events in the map. If delay is greater than or equal internal timer, delay will be 0. + * @param delay Amount of delay. + */ void DelayEvents(uint32 delay) { - if (delay < _time) - _time -= delay; - else - _time = 0; + _time = delay < _time ? _time - delay : 0; } - // Delay all events having the specified Group - void DelayEvents(uint32 delay, uint32 groupId) + /** + * @name DelayEvents + * @brief Delay all events of the same group. + * @param delay Amount of delay. + * @param group Group of the events. + */ + void DelayEvents(uint32 delay, uint32 group) { - uint32 nextTime = _time + delay; - uint32 groupMask = (1 << (groupId + 16)); - for (StorageType::iterator itr = _eventMap.begin(); itr != _eventMap.end() && itr->first < nextTime;) + if (!group || group > 8 || Empty()) + return; + + EventStore delayed; + + for (EventStore::iterator itr = _eventMap.begin(); itr != _eventMap.end();) { - if (itr->second & groupMask) + if (itr->second & (1 << (group + 15))) { - ScheduleEvent(itr->second, itr->first - _time + delay); - _eventMap.erase(itr); - itr = _eventMap.begin(); + delayed.insert(EventStore::value_type(itr->first + delay, itr->second)); + _eventMap.erase(itr++); } else ++itr; } + + _eventMap.insert(delayed.begin(), delayed.end()); } - // Cancel events with specified id + /** + * @name CancelEvent + * @brief Cancels all events of the specified id. + * @param eventId Event id to cancel. + */ void CancelEvent(uint32 eventId) { - for (StorageType::iterator itr = _eventMap.begin(); itr != _eventMap.end();) + if (Empty()) + return; + + for (EventStore::iterator itr = _eventMap.begin(); itr != _eventMap.end();) { if (eventId == (itr->second & 0x0000FFFF)) - { - _eventMap.erase(itr); - itr = _eventMap.begin(); - } + _eventMap.erase(itr++); else ++itr; } } - // Cancel events belonging to specified group - void CancelEventGroup(uint32 groupId) + /** + * @name CancelEventGroup + * @brief Cancel events belonging to specified group. + * @param group Group to cancel. + */ + void CancelEventGroup(uint32 group) { - uint32 groupMask = (1 << (groupId + 16)); + if (!group || group > 8 || Empty()) + return; - for (StorageType::iterator itr = _eventMap.begin(); itr != _eventMap.end();) + for (EventStore::iterator itr = _eventMap.begin(); itr != _eventMap.end();) { - if (itr->second & groupMask) - { - _eventMap.erase(itr); - itr = _eventMap.begin(); - } + if (itr->second & (1 << (group + 15))) + _eventMap.erase(itr++); else ++itr; } } - // Returns time of next event to execute - // To get how much time remains substract _time + /** + * @name GetNextEventTime + * @brief Returns closest occurence of specified event. + * @param eventId Wanted event id. + * @return Time of found event. + */ uint32 GetNextEventTime(uint32 eventId) const { - for (StorageType::const_iterator itr = _eventMap.begin(); itr != _eventMap.end(); ++itr) + if (Empty()) + return 0; + + for (EventStore::const_iterator itr = _eventMap.begin(); itr != _eventMap.end(); ++itr) if (eventId == (itr->second & 0x0000FFFF)) return itr->first; return 0; } + /** + * @name GetNextEventTime + * @return Time of next event. + */ + uint32 GetNextEventTime() const + { + return Empty() ? 0 : _eventMap.begin()->first; + } + + /** + * @name IsInPhase + * @brief Returns wether event map is in specified phase or not. + * @param phase Wanted phase. + * @return True, if phase of event map contains specified phase. + */ + bool IsInPhase(uint8 phase) + { + return phase <= 8 && (!phase || _phase & (1 << (phase - 1))); + } + private: + /** + * @name _time + * @brief Internal timer. + * + * This does not represent the real date/time value. + * It's more like a stopwatch: It can run, it can be stopped, + * it can be resetted and so on. Events occur when this timer + * has reached their time value. Its value is changed in the + * Update method. + */ uint32 _time; - uint32 _phase; - StorageType _eventMap; + /** + * @name _phase + * @brief Phase mask of the event map. + * + * Contains the phases the event map is in. Multiple + * phases from 1 to 8 can be set with SetPhase or + * AddPhase. RemovePhase deactives a phase. + */ + uint8 _phase; + + /** + * @name _eventMap + * @brief Internal event storage map. Contains the scheduled events. + * + * See typedef at the beginning of the class for more + * details. + */ + EventStore _eventMap; }; enum AITarget diff --git a/src/server/game/AI/CreatureAISelector.cpp b/src/server/game/AI/CreatureAISelector.cpp index 920c1c25533..a09feb6e00f 100644 --- a/src/server/game/AI/CreatureAISelector.cpp +++ b/src/server/game/AI/CreatureAISelector.cpp @@ -132,16 +132,12 @@ namespace FactorySelector const GameObjectAICreator* ai_factory = NULL; GameObjectAIRegistry& ai_registry(*GameObjectAIRepository::instance()); + // scriptname in db if (GameObjectAI* scriptedAI = sScriptMgr->GetGameObjectAI(go)) return scriptedAI; ai_factory = ai_registry.GetRegistryItem(go->GetAIName()); - // scriptname in db - if (!ai_factory) - if (GameObjectAI* scriptedAI = sScriptMgr->GetGameObjectAI(go)) - return scriptedAI; - //future goAI types go here std::string ainame = (ai_factory == NULL || go->GetScriptId()) ? "NullGameObjectAI" : ai_factory->key(); diff --git a/src/server/game/AI/EventAI/CreatureEventAI.cpp b/src/server/game/AI/EventAI/CreatureEventAI.cpp index 7172a187504..9a4a85b72d8 100644 --- a/src/server/game/AI/EventAI/CreatureEventAI.cpp +++ b/src/server/game/AI/EventAI/CreatureEventAI.cpp @@ -406,10 +406,7 @@ void CreatureEventAI::ProcessAction(CreatureEventAI_Action const& action, uint32 if (action.morph.creatureId) { if (CreatureTemplate const* ci = sObjectMgr->GetCreatureTemplate(action.morph.creatureId)) - { - uint32 display_id = sObjectMgr->ChooseDisplayId(0, ci); - me->SetDisplayId(display_id); - } + me->SetDisplayId(ObjectMgr::ChooseDisplayId(ci)); } //if no param1, then use value from param2 (modelId) else @@ -780,10 +777,7 @@ void CreatureEventAI::ProcessAction(CreatureEventAI_Action const& action, uint32 if (action.mount.creatureId) { if (CreatureTemplate const* cInfo = sObjectMgr->GetCreatureTemplate(action.mount.creatureId)) - { - uint32 display_id = sObjectMgr->ChooseDisplayId(0, cInfo); - me->Mount(display_id); - } + me->Mount(ObjectMgr::ChooseDisplayId(cInfo)); } //if no param1, then use value from param2 (modelId) else @@ -840,7 +834,7 @@ void CreatureEventAI::Reset() break; } default: - //TODO: enable below code line / verify this is correct to enable events previously disabled (ex. aggro yell), instead of enable this in void EnterCombat() + /// @todo enable below code line / verify this is correct to enable events previously disabled (ex. aggro yell), instead of enable this in void EnterCombat() //(*i).Enabled = true; //(*i).Time = 0; break; @@ -1012,7 +1006,7 @@ void CreatureEventAI::SpellHit(Unit* unit, const SpellInfo* spell) ProcessEvent(*i, unit); } -void CreatureEventAI::UpdateAI(const uint32 diff) +void CreatureEventAI::UpdateAI(uint32 diff) { //Check if we are in combat (also updates calls threat update code) bool Combat = UpdateVictim(); diff --git a/src/server/game/AI/EventAI/CreatureEventAI.h b/src/server/game/AI/EventAI/CreatureEventAI.h index fa4b2a709a6..d67fef64b95 100644 --- a/src/server/game/AI/EventAI/CreatureEventAI.h +++ b/src/server/game/AI/EventAI/CreatureEventAI.h @@ -591,10 +591,8 @@ class CreatureEventAI : public CreatureAI { public: explicit CreatureEventAI(Creature* c); - ~CreatureEventAI() - { - m_CreatureEventAIList.clear(); - } + ~CreatureEventAI() { } + void JustRespawned(); void Reset(); void JustReachedHome(); @@ -608,7 +606,7 @@ class CreatureEventAI : public CreatureAI void SpellHit(Unit* unit, const SpellInfo* spell); void DamageTaken(Unit* done_by, uint32& damage); void HealReceived(Unit* /*done_by*/, uint32& /*addhealth*/) {} - void UpdateAI(const uint32 diff); + void UpdateAI(uint32 diff); void ReceiveEmote(Player* player, uint32 textEmote); static int Permissible(const Creature*); diff --git a/src/server/game/AI/EventAI/CreatureEventAIMgr.cpp b/src/server/game/AI/EventAI/CreatureEventAIMgr.cpp index 8fc8debc38a..c2698b01e19 100644 --- a/src/server/game/AI/EventAI/CreatureEventAIMgr.cpp +++ b/src/server/game/AI/EventAI/CreatureEventAIMgr.cpp @@ -211,7 +211,10 @@ void CreatureEventAIMgr::LoadCreatureEventAI_Scripts() } if ((temp.spell_hit.schoolMask & spell->SchoolMask) != spell->SchoolMask) - sLog->outError(LOG_FILTER_SQL, "CreatureEventAI: Creature %u has param1(spellId %u) but param2 is not -1 and not equal to spell's school mask. Event %u can never trigger.", temp.creature_id, temp.spell_hit.schoolMask, i); + { + sLog->outError(LOG_FILTER_SQL, "CreatureEventAI: Creature %u has param1(spellId %u) but param2 is not -1 and not equal to spell's school mask. Event %u can never trigger.", + temp.creature_id, temp.spell_hit.schoolMask, i); + } } if (!temp.spell_hit.schoolMask) @@ -237,11 +240,17 @@ void CreatureEventAIMgr::LoadCreatureEventAI_Scripts() break; case SPAWNED_EVENT_MAP: if (!sMapStore.LookupEntry(temp.spawned.conditionValue1)) - sLog->outError(LOG_FILTER_SQL, "CreatureEventAI: Creature %u are using spawned event(%u) with param1 = %u 'map specific' but with not existed map (%u) in param2. Event will never repeat.", temp.creature_id, i, temp.spawned.condition, temp.spawned.conditionValue1); + { + sLog->outError(LOG_FILTER_SQL, "CreatureEventAI: Creature %u are using spawned event(%u) with param1 = %u 'map specific' but with not existed map (%u) in param2. Event will never repeat.", + temp.creature_id, i, temp.spawned.condition, temp.spawned.conditionValue1); + } break; case SPAWNED_EVENT_ZONE: if (!GetAreaEntryByAreaID(temp.spawned.conditionValue1)) - sLog->outError(LOG_FILTER_SQL, "CreatureEventAI: Creature %u are using spawned event(%u) with param1 = %u 'area specific' but with not existed area (%u) in param2. Event will never repeat.", temp.creature_id, i, temp.spawned.condition, temp.spawned.conditionValue1); + { + sLog->outError(LOG_FILTER_SQL, "CreatureEventAI: Creature %u are using spawned event(%u) with param1 = %u 'area specific' but with not existed area (%u) in param2. Event will never repeat.", + temp.creature_id, i, temp.spawned.condition, temp.spawned.conditionValue1); + } default: sLog->outError(LOG_FILTER_SQL, "CreatureEventAI: Creature %u are using invalid spawned event %u mode (%u) in param1", temp.creature_id, i, temp.spawned.condition); break; diff --git a/src/server/game/AI/EventAI/CreatureEventAIMgr.h b/src/server/game/AI/EventAI/CreatureEventAIMgr.h index 1ec08682563..8e862a9279b 100644 --- a/src/server/game/AI/EventAI/CreatureEventAIMgr.h +++ b/src/server/game/AI/EventAI/CreatureEventAIMgr.h @@ -27,8 +27,8 @@ class CreatureEventAIMgr friend class ACE_Singleton<CreatureEventAIMgr, ACE_Null_Mutex>; private: - CreatureEventAIMgr(){}; - ~CreatureEventAIMgr(){}; + CreatureEventAIMgr(){} + ~CreatureEventAIMgr(){} public: void LoadCreatureEventAI_Texts(); diff --git a/src/server/game/AI/ScriptedAI/ScriptedCreature.cpp b/src/server/game/AI/ScriptedAI/ScriptedCreature.cpp index 9709cb0ecc2..e36916decae 100644 --- a/src/server/game/AI/ScriptedAI/ScriptedCreature.cpp +++ b/src/server/game/AI/ScriptedAI/ScriptedCreature.cpp @@ -104,11 +104,19 @@ void ScriptedAI::AttackStartNoMove(Unit* who) if (!who) return; - if (me->Attack(who, false)) + if (me->Attack(who, true)) DoStartNoMovement(who); } -void ScriptedAI::UpdateAI(uint32 const /*diff*/) +void ScriptedAI::AttackStart(Unit* who) +{ + if (IsCombatMovementAllowed()) + CreatureAI::AttackStart(who); + else + AttackStartNoMove(who); +} + +void ScriptedAI::UpdateAI(uint32 /*diff*/) { //Check if we have a current target if (!UpdateVictim()) @@ -362,9 +370,7 @@ void ScriptedAI::SetEquipmentSlots(bool loadDefault, int32 mainHand /*= EQUIP_NO { if (loadDefault) { - if (CreatureTemplate const* creatureInfo = sObjectMgr->GetCreatureTemplate(me->GetEntry())) - me->LoadEquipment(creatureInfo->equipmentId, true); - + me->LoadEquipment(me->GetOriginalEquipmentId(), true); return; } @@ -439,15 +445,6 @@ bool ScriptedAI::EnterEvadeIfOutOfCombatArea(uint32 const diff) return true; } -void Scripted_NoMovementAI::AttackStart(Unit* target) -{ - if (!target) - return; - - if (me->Attack(target, true)) - DoStartNoMovement(target); -} - // BossAI - for instanced bosses BossAI::BossAI(Creature* creature, uint32 bossId) : ScriptedAI(creature), instance(creature->GetInstanceScript()), @@ -518,35 +515,35 @@ bool BossAI::CheckBoundary(Unit* who) switch (itr->first) { case BOUNDARY_N: - if (me->GetPositionX() > itr->second) + if (who->GetPositionX() > itr->second) return false; break; case BOUNDARY_S: - if (me->GetPositionX() < itr->second) + if (who->GetPositionX() < itr->second) return false; break; case BOUNDARY_E: - if (me->GetPositionY() < itr->second) + if (who->GetPositionY() < itr->second) return false; break; case BOUNDARY_W: - if (me->GetPositionY() > itr->second) + if (who->GetPositionY() > itr->second) return false; break; case BOUNDARY_NW: - if (me->GetPositionX() + me->GetPositionY() > itr->second) + if (who->GetPositionX() + who->GetPositionY() > itr->second) return false; break; case BOUNDARY_SE: - if (me->GetPositionX() + me->GetPositionY() < itr->second) + if (who->GetPositionX() + who->GetPositionY() < itr->second) return false; break; case BOUNDARY_NE: - if (me->GetPositionX() - me->GetPositionY() > itr->second) + if (who->GetPositionX() - who->GetPositionY() > itr->second) return false; break; case BOUNDARY_SW: - if (me->GetPositionX() - me->GetPositionY() < itr->second) + if (who->GetPositionX() - who->GetPositionY() < itr->second) return false; break; default: @@ -569,7 +566,7 @@ void BossAI::SummonedCreatureDespawn(Creature* summon) summons.Despawn(summon); } -void BossAI::UpdateAI(uint32 const diff) +void BossAI::UpdateAI(uint32 diff) { if (!UpdateVictim()) return; @@ -628,7 +625,7 @@ void WorldBossAI::SummonedCreatureDespawn(Creature* summon) summons.Despawn(summon); } -void WorldBossAI::UpdateAI(uint32 const diff) +void WorldBossAI::UpdateAI(uint32 diff) { if (!UpdateVictim()) return; diff --git a/src/server/game/AI/ScriptedAI/ScriptedCreature.h b/src/server/game/AI/ScriptedAI/ScriptedCreature.h index 50363f20ed5..8d7a28d4e6f 100644 --- a/src/server/game/AI/ScriptedAI/ScriptedCreature.h +++ b/src/server/game/AI/ScriptedAI/ScriptedCreature.h @@ -90,7 +90,7 @@ struct ScriptedAI : public CreatureAI void DamageTaken(Unit* /*attacker*/, uint32& /*damage*/) {} //Called at World update tick - virtual void UpdateAI(uint32 const diff); + virtual void UpdateAI(uint32 diff); //Called at creature death void JustDied(Unit* /*killer*/) {} @@ -136,6 +136,9 @@ struct ScriptedAI : public CreatureAI //Called at creature aggro either by MoveInLOS or Attack Start void EnterCombat(Unit* /*victim*/) {} + // Called before EnterCombat even before the creature is in combat. + void AttackStart(Unit* /*target*/); + // ************* //AI Helper Functions // ************* @@ -191,7 +194,11 @@ struct ScriptedAI : public CreatureAI void SetEquipmentSlots(bool loadDefault, int32 mainHand = EQUIP_NO_CHANGE, int32 offHand = EQUIP_NO_CHANGE, int32 ranged = EQUIP_NO_CHANGE); - //Generally used to control if MoveChase() is to be used or not in AttackStart(). Some creatures does not chase victims + // Used to control if MoveChase() is to be used or not in AttackStart(). Some creatures does not chase victims + // NOTE: If you use SetCombatMovement while the creature is in combat, it will do NOTHING - This only affects AttackStart + // You should make the necessary to make it happen so. + // Remember that if you modified _isCombatMovementAllowed (e.g: using SetCombatMovement) it will not be reset at Reset(). + // It will keep the last value you set. void SetCombatMovement(bool allowMovement); bool IsCombatMovementAllowed() const { return _isCombatMovementAllowed; } @@ -269,15 +276,6 @@ struct ScriptedAI : public CreatureAI bool _isHeroic; }; -struct Scripted_NoMovementAI : public ScriptedAI -{ - Scripted_NoMovementAI(Creature* creature) : ScriptedAI(creature) {} - virtual ~Scripted_NoMovementAI() {} - - //Called at each attack of me by any victim - void AttackStart(Unit* target); -}; - class BossAI : public ScriptedAI { public: @@ -290,13 +288,13 @@ class BossAI : public ScriptedAI void JustSummoned(Creature* summon); void SummonedCreatureDespawn(Creature* summon); - virtual void UpdateAI(uint32 const diff); + virtual void UpdateAI(uint32 diff); // Hook used to execute events scheduled into EventMap without the need // to override UpdateAI // note: You must re-schedule the event within this method if the event // is supposed to run more than once - virtual void ExecuteEvent(uint32 const /*eventId*/) { } + virtual void ExecuteEvent(uint32 /*eventId*/) { } void Reset() { _Reset(); } void EnterCombat(Unit* /*who*/) { _EnterCombat(); } @@ -338,13 +336,13 @@ class WorldBossAI : public ScriptedAI void JustSummoned(Creature* summon); void SummonedCreatureDespawn(Creature* summon); - virtual void UpdateAI(uint32 const diff); + virtual void UpdateAI(uint32 diff); // Hook used to execute events scheduled into EventMap without the need // to override UpdateAI // note: You must re-schedule the event within this method if the event // is supposed to run more than once - virtual void ExecuteEvent(uint32 const /*eventId*/) { } + virtual void ExecuteEvent(uint32 /*eventId*/) { } void Reset() { _Reset(); } void EnterCombat(Unit* /*who*/) { _EnterCombat(); } diff --git a/src/server/game/AI/ScriptedAI/ScriptedEscortAI.cpp b/src/server/game/AI/ScriptedAI/ScriptedEscortAI.cpp index 3f5952a210d..0f0e461e4cf 100644 --- a/src/server/game/AI/ScriptedAI/ScriptedEscortAI.cpp +++ b/src/server/game/AI/ScriptedAI/ScriptedEscortAI.cpp @@ -205,7 +205,7 @@ bool npc_escortAI::IsPlayerOrGroupInRange() return false; } -void npc_escortAI::UpdateAI(uint32 const diff) +void npc_escortAI::UpdateAI(uint32 diff) { //Waypoint Updating if (HasEscortState(STATE_ESCORT_ESCORTING) && !me->getVictim() && m_uiWPWaitTimer && !HasEscortState(STATE_ESCORT_RETURNING)) @@ -293,7 +293,7 @@ void npc_escortAI::UpdateAI(uint32 const diff) UpdateEscortAI(diff); } -void npc_escortAI::UpdateEscortAI(uint32 const /*diff*/) +void npc_escortAI::UpdateEscortAI(uint32 /*diff*/) { if (!UpdateVictim()) return; @@ -415,7 +415,7 @@ void npc_escortAI::SetRun(bool on) m_bIsRunning = on; } -//TODO: get rid of this many variables passed in function. +/// @todo get rid of this many variables passed in function. void npc_escortAI::Start(bool isActiveAttacker /* = true*/, bool run /* = false */, uint64 playerGUID /* = 0 */, Quest const* quest /* = NULL */, bool instantRespawn /* = false */, bool canLoopPath /* = false */, bool resetWaypoints /* = true */) { if (me->getVictim()) diff --git a/src/server/game/AI/ScriptedAI/ScriptedEscortAI.h b/src/server/game/AI/ScriptedAI/ScriptedEscortAI.h index 4b4f3656a8d..4a350acab2c 100644 --- a/src/server/game/AI/ScriptedAI/ScriptedEscortAI.h +++ b/src/server/game/AI/ScriptedAI/ScriptedEscortAI.h @@ -54,7 +54,7 @@ struct npc_escortAI : public ScriptedAI void EnterEvadeMode(); - void UpdateAI(uint32 const diff); //the "internal" update, calls UpdateEscortAI() + void UpdateAI(uint32 diff); //the "internal" update, calls UpdateEscortAI() virtual void UpdateEscortAI(uint32 const diff); //used when it's needed to add code in update (abilities, scripted events, etc) void MovementInform(uint32, uint32); diff --git a/src/server/game/AI/ScriptedAI/ScriptedFollowerAI.cpp b/src/server/game/AI/ScriptedAI/ScriptedFollowerAI.cpp index 96209084240..887714a6ce2 100644 --- a/src/server/game/AI/ScriptedAI/ScriptedFollowerAI.cpp +++ b/src/server/game/AI/ScriptedAI/ScriptedFollowerAI.cpp @@ -122,7 +122,7 @@ void FollowerAI::JustDied(Unit* /*killer*/) if (!HasFollowState(STATE_FOLLOW_INPROGRESS) || !m_uiLeaderGUID || !m_pQuestForFollow) return; - //TODO: need a better check for quests with time limit. + /// @todo need a better check for quests with time limit. if (Player* player = GetLeaderForFollower()) { if (Group* group = player->GetGroup()) @@ -184,7 +184,7 @@ void FollowerAI::EnterEvadeMode() Reset(); } -void FollowerAI::UpdateAI(const uint32 uiDiff) +void FollowerAI::UpdateAI(uint32 uiDiff) { if (HasFollowState(STATE_FOLLOW_INPROGRESS) && !me->getVictim()) { @@ -246,7 +246,7 @@ void FollowerAI::UpdateAI(const uint32 uiDiff) UpdateFollowerAI(uiDiff); } -void FollowerAI::UpdateFollowerAI(const uint32 /*uiDiff*/) +void FollowerAI::UpdateFollowerAI(uint32 /*uiDiff*/) { if (!UpdateVictim()) return; diff --git a/src/server/game/AI/ScriptedAI/ScriptedFollowerAI.h b/src/server/game/AI/ScriptedAI/ScriptedFollowerAI.h index 1c81b5f73fc..ccc8af6197a 100644 --- a/src/server/game/AI/ScriptedAI/ScriptedFollowerAI.h +++ b/src/server/game/AI/ScriptedAI/ScriptedFollowerAI.h @@ -38,8 +38,8 @@ class FollowerAI : public ScriptedAI void JustRespawned(); - void UpdateAI(const uint32); //the "internal" update, calls UpdateFollowerAI() - virtual void UpdateFollowerAI(const uint32); //used when it's needed to add code in update (abilities, scripted events, etc) + void UpdateAI(uint32); //the "internal" update, calls UpdateFollowerAI() + virtual void UpdateFollowerAI(uint32); //used when it's needed to add code in update (abilities, scripted events, etc) void StartFollow(Player* player, uint32 factionForFollower = 0, const Quest* quest = NULL); diff --git a/src/server/game/AI/SmartScripts/SmartAI.cpp b/src/server/game/AI/SmartScripts/SmartAI.cpp index e568a36abc4..f1328bbd259 100644 --- a/src/server/game/AI/SmartScripts/SmartAI.cpp +++ b/src/server/game/AI/SmartScripts/SmartAI.cpp @@ -330,13 +330,13 @@ void SmartAI::UpdatePath(const uint32 diff) } } -void SmartAI::UpdateAI(const uint32 diff) +void SmartAI::UpdateAI(uint32 diff) { GetScript()->OnUpdate(diff); UpdatePath(diff); UpdateDespawn(diff); - //TODO move to void + /// @todo move to void if (mFollowGuid) { if (mFollowArrivedTimer < diff) @@ -422,6 +422,9 @@ void SmartAI::MovepointReached(uint32 id) void SmartAI::MovementInform(uint32 MovementType, uint32 Data) { + if ((MovementType == POINT_MOTION_TYPE && Data == SMART_ESCORT_LAST_OOC_POINT) || MovementType == FOLLOW_MOTION_TYPE) + me->ClearUnitState(UNIT_STATE_EVADE); + GetScript()->ProcessEventsFor(SMART_EVENT_MOVEMENTINFORM, NULL, MovementType, Data); if (MovementType != POINT_MOTION_TYPE || !HasEscortState(SMART_ESCORT_ESCORTING)) return; @@ -430,23 +433,25 @@ void SmartAI::MovementInform(uint32 MovementType, uint32 Data) void SmartAI::RemoveAuras() { - // Only loop throught the applied auras, because here is where all auras on the current unit are stored - Unit::AuraApplicationMap appliedAuras = me->GetAppliedAuras(); - for (Unit::AuraApplicationMap::iterator iter = appliedAuras.begin(); iter != appliedAuras.end(); ++iter) + Unit::AuraApplicationMap& appliedAuras = me->GetAppliedAuras(); + for (Unit::AuraApplicationMap::iterator iter = appliedAuras.begin(); iter != appliedAuras.end();) { Aura const* aura = iter->second->GetBase(); - if (!aura->GetSpellInfo()->IsPassive() && !aura->GetSpellInfo()->HasAura(SPELL_AURA_CONTROL_VEHICLE) && aura->GetCaster() != me) - me->RemoveAurasDueToSpell(aura->GetId()); + if (!aura->IsPassive() && !aura->HasEffectType(SPELL_AURA_CONTROL_VEHICLE) && aura->GetCasterGUID() != me->GetGUID()) + me->RemoveAura(iter); + else + ++iter; } } void SmartAI::EnterEvadeMode() { - if (!me->isAlive()) + if (!me->isAlive() || me->IsInEvadeMode()) return; RemoveAuras(); + me->AddUnitState(UNIT_STATE_EVADE); me->DeleteThreatList(); me->CombatStop(true); me->LoadCreaturesAddon(); @@ -693,7 +698,7 @@ void SmartAI::OnCharmed(bool apply) GetScript()->ProcessEventsFor(SMART_EVENT_CHARMED, NULL, 0, 0, apply); } -void SmartAI::DoAction(const int32 param) +void SmartAI::DoAction(int32 param) { GetScript()->ProcessEventsFor(SMART_EVENT_ACTION_DONE, NULL, param); } diff --git a/src/server/game/AI/SmartScripts/SmartAI.h b/src/server/game/AI/SmartScripts/SmartAI.h index ab2ffb7229d..dee6bec905c 100644 --- a/src/server/game/AI/SmartScripts/SmartAI.h +++ b/src/server/game/AI/SmartScripts/SmartAI.h @@ -45,7 +45,7 @@ enum SmartEscortVars class SmartAI : public CreatureAI { public: - ~SmartAI(){}; + ~SmartAI(){} explicit SmartAI(Creature* c); // Start moving to the desired MovePoint @@ -111,7 +111,7 @@ class SmartAI : public CreatureAI void HealReceived(Unit* doneBy, uint32& addhealth); // Called at World update tick - void UpdateAI(const uint32 diff); + void UpdateAI(uint32 diff); // Called at text emote receive from player void ReceiveEmote(Player* player, uint32 textEmote); @@ -147,7 +147,7 @@ class SmartAI : public CreatureAI bool CanAIAttack(const Unit* who) const; // Used in scripts to share variables - void DoAction(const int32 param = 0); + void DoAction(int32 param = 0); // Used in scripts to share variables uint32 GetData(uint32 id = 0) const; diff --git a/src/server/game/AI/SmartScripts/SmartScript.cpp b/src/server/game/AI/SmartScripts/SmartScript.cpp index c08e085e816..9c476ea55fc 100644 --- a/src/server/game/AI/SmartScripts/SmartScript.cpp +++ b/src/server/game/AI/SmartScripts/SmartScript.cpp @@ -83,7 +83,6 @@ SmartScript::SmartScript() mEventPhase = 0; mPathId = 0; mTargetStorage = new ObjectListMap(); - mStoredEvents.clear(); mTextTimer = 0; mLastTextID = 0; mTextGUID = 0; @@ -313,10 +312,10 @@ void SmartScript::ProcessAction(SmartScriptHolder& e, Unit* unit, uint32 var0, u { if (CreatureTemplate const* ci = sObjectMgr->GetCreatureTemplate(e.action.morphOrMount.creature)) { - uint32 display_id = sObjectMgr->ChooseDisplayId(0, ci); - (*itr)->ToCreature()->SetDisplayId(display_id); + uint32 displayId = ObjectMgr::ChooseDisplayId(ci); + (*itr)->ToCreature()->SetDisplayId(displayId); sLog->outDebug(LOG_FILTER_DATABASE_AI, "SmartScript::ProcessAction:: SMART_ACTION_MORPH_TO_ENTRY_OR_MODEL: Creature entry %u, GuidLow %u set displayid to %u", - (*itr)->GetEntry(), (*itr)->GetGUIDLow(), display_id); + (*itr)->GetEntry(), (*itr)->GetGUIDLow(), displayId); } } //if no param1, then use value from param2 (modelId) @@ -1050,10 +1049,7 @@ void SmartScript::ProcessAction(SmartScriptHolder& e, Unit* unit, uint32 var0, u if (e.action.morphOrMount.creature > 0) { if (CreatureTemplate const* cInfo = sObjectMgr->GetCreatureTemplate(e.action.morphOrMount.creature)) - { - uint32 display_id = sObjectMgr->ChooseDisplayId(0, cInfo); - (*itr)->ToUnit()->Mount(display_id); - } + (*itr)->ToUnit()->Mount(ObjectMgr::ChooseDisplayId(cInfo)); } else (*itr)->ToUnit()->Mount(e.action.morphOrMount.model); @@ -1459,15 +1455,16 @@ void SmartScript::ProcessAction(SmartScriptHolder& e, Unit* unit, uint32 var0, u if (Creature* npc = (*itr)->ToCreature()) { uint32 slot[3]; - if (e.action.equip.entry) + int8 equipId = (int8)e.action.equip.entry; + if (equipId) { - EquipmentInfo const* einfo = sObjectMgr->GetEquipmentInfo(e.action.equip.entry); + EquipmentInfo const* einfo = sObjectMgr->GetEquipmentInfo(npc->GetEntry(), equipId); if (!einfo) { - sLog->outError(LOG_FILTER_SQL, "SmartScript: SMART_ACTION_EQUIP uses non-existent equipment info entry %u", e.action.equip.entry); + sLog->outError(LOG_FILTER_SQL, "SmartScript: SMART_ACTION_EQUIP uses non-existent equipment info id %u for creature %u", equipId, npc->GetEntry()); return; } - npc->SetCurrentEquipmentId(e.action.equip.entry); + npc->SetCurrentEquipmentId(equipId); slot[0] = einfo->ItemEntry[0]; slot[1] = einfo->ItemEntry[1]; slot[2] = einfo->ItemEntry[2]; @@ -1478,11 +1475,11 @@ void SmartScript::ProcessAction(SmartScriptHolder& e, Unit* unit, uint32 var0, u slot[1] = e.action.equip.slot2; slot[2] = e.action.equip.slot3; } - if (!e.action.equip.mask || e.action.equip.mask & 1) + if (!e.action.equip.mask || (e.action.equip.mask & 1)) npc->SetUInt32Value(UNIT_VIRTUAL_ITEM_SLOT_ID + 0, slot[0]); - if (!e.action.equip.mask || e.action.equip.mask & 2) + if (!e.action.equip.mask || (e.action.equip.mask & 2)) npc->SetUInt32Value(UNIT_VIRTUAL_ITEM_SLOT_ID + 1, slot[1]); - if (!e.action.equip.mask || e.action.equip.mask & 4) + if (!e.action.equip.mask || (e.action.equip.mask & 4)) npc->SetUInt32Value(UNIT_VIRTUAL_ITEM_SLOT_ID + 2, slot[2]); } } @@ -1893,12 +1890,19 @@ void SmartScript::ProcessAction(SmartScriptHolder& e, Unit* unit, uint32 var0, u } case SMART_ACTION_JUMP_TO_POS: { - if (!me) + ObjectList* targets = GetTargets(e, unit); + if (!targets) break; - me->GetMotionMaster()->Clear(); - me->GetMotionMaster()->MoveJump(e.target.x, e.target.y, e.target.z, (float)e.action.jump.speedxy, (float)e.action.jump.speedz); - // TODO: Resume path when reached jump location + for (ObjectList::const_iterator itr = targets->begin(); itr != targets->end(); ++itr) + if (Creature* creature = (*itr)->ToCreature()) + { + creature->GetMotionMaster()->Clear(); + creature->GetMotionMaster()->MoveJump(e.target.x, e.target.y, e.target.z, (float)e.action.jump.speedxy, (float)e.action.jump.speedz); + } + /// @todo Resume path when reached jump location + + delete targets; break; } case SMART_ACTION_GO_SET_LOOT_STATE: @@ -1977,23 +1981,100 @@ void SmartScript::ProcessAction(SmartScriptHolder& e, Unit* unit, uint32 var0, u } case SMART_ACTION_SET_HOME_POS: { - if (!me) + ObjectList* targets = GetTargets(e, unit); + if (!targets) break; - if (e.GetTargetType() == SMART_TARGET_SELF) - me->SetHomePosition(me->GetPositionX(), me->GetPositionY(), me->GetPositionZ(), me->GetOrientation()); - else if (e.GetTargetType() == SMART_TARGET_POSITION) - me->SetHomePosition(e.target.x, e.target.y, e.target.z, e.target.o); - else - sLog->outError(LOG_FILTER_SQL, "SmartScript: Action target for SMART_ACTION_SET_HOME_POS is not using SMART_TARGET_SELF or SMART_TARGET_POSITION, skipping"); + for (ObjectList::const_iterator itr = targets->begin(); itr != targets->end(); ++itr) + if (IsCreature(*itr)) + { + if (e.GetTargetType() == SMART_TARGET_SELF) + (*itr)->ToCreature()->SetHomePosition(me->GetPositionX(), me->GetPositionY(), me->GetPositionZ(), me->GetOrientation()); + else if (e.GetTargetType() == SMART_TARGET_POSITION) + (*itr)->ToCreature()->SetHomePosition(e.target.x, e.target.y, e.target.z, e.target.o); + else + sLog->outError(LOG_FILTER_SQL, "SmartScript: Action target for SMART_ACTION_SET_HOME_POS is not using SMART_TARGET_SELF or SMART_TARGET_POSITION, skipping"); + } - break; + delete targets; + break; } case SMART_ACTION_SET_HEALTH_REGEN: { - if (!me || me->GetTypeId() != TYPEID_UNIT) + ObjectList* targets = GetTargets(e, unit); + if (!targets) + break; + + for (ObjectList::const_iterator itr = targets->begin(); itr != targets->end(); ++itr) + if (IsCreature(*itr)) + (*itr)->ToCreature()->setRegeneratingHealth(e.action.setHealthRegen.regenHealth ? true : false); + + delete targets; + break; + } + case SMART_ACTION_SET_ROOT: + { + ObjectList* targets = GetTargets(e, unit); + if (!targets) + break; + + for (ObjectList::const_iterator itr = targets->begin(); itr != targets->end(); ++itr) + if (IsCreature(*itr)) + (*itr)->ToCreature()->SetControlled(e.action.setRoot.root ? true : false, UNIT_STATE_ROOT); + + delete targets; + break; + } + case SMART_ACTION_SET_GO_FLAG: + { + ObjectList* targets = GetTargets(e, unit); + if (!targets) + break; + + for (ObjectList::const_iterator itr = targets->begin(); itr != targets->end(); ++itr) + if (IsGameObject(*itr)) + (*itr)->ToGameObject()->SetUInt32Value(GAMEOBJECT_FLAGS, e.action.goFlag.flag); + + delete targets; + break; + } + case SMART_ACTION_ADD_GO_FLAG: + { + ObjectList* targets = GetTargets(e, unit); + if (!targets) + break; + + for (ObjectList::const_iterator itr = targets->begin(); itr != targets->end(); ++itr) + if (IsGameObject(*itr)) + (*itr)->ToGameObject()->SetFlag(GAMEOBJECT_FLAGS, e.action.goFlag.flag); + + delete targets; + break; + } + case SMART_ACTION_REMOVE_GO_FLAG: + { + ObjectList* targets = GetTargets(e, unit); + if (!targets) break; - me->setRegeneratingHealth(e.action.setHealthRegen.regenHealth ? true : false); + + for (ObjectList::const_iterator itr = targets->begin(); itr != targets->end(); ++itr) + if (IsGameObject(*itr)) + (*itr)->ToGameObject()->RemoveFlag(GAMEOBJECT_FLAGS, e.action.goFlag.flag); + + delete targets; + break; + } + case SMART_ACTION_SUMMON_CREATURE_GROUP: + { + std::list<TempSummon*> summonList; + GetBaseObject()->SummonCreatureGroup(e.action.creatureGroup.group, &summonList); + + for (std::list<TempSummon*>::const_iterator itr = summonList.begin(); itr != summonList.end(); ++itr) + { + if (unit && e.action.creatureGroup.attackInvoker) + (*itr)->AI()->AttackStart(unit); + } + break; } default: @@ -2011,6 +2092,17 @@ void SmartScript::ProcessAction(SmartScriptHolder& e, Unit* unit, uint32 var0, u } } +void SmartScript::ProcessTimedAction(SmartScriptHolder& e, uint32 const& min, uint32 const& max, Unit* unit, uint32 var0, uint32 var1, bool bvar, const SpellInfo* spell, GameObject* gob) +{ + ConditionList const conds = sConditionMgr->GetConditionsForSmartEvent(e.entryOrGuid, e.event_id, e.source_type); + ConditionSourceInfo info = ConditionSourceInfo(unit, GetBaseObject()); + + if (sConditionMgr->IsObjectMeetToConditions(info, conds)) + ProcessAction(e, unit, var0, var1, bvar, spell, gob); + + RecalcTimer(e, min, max); +} + void SmartScript::InstallTemplate(SmartScriptHolder const& e) { if (!GetBaseObject()) @@ -2121,18 +2213,20 @@ SmartScriptHolder SmartScript::CreateEvent(SMART_EVENT e, uint32 event_flags, ui ObjectList* SmartScript::GetTargets(SmartScriptHolder const& e, Unit* invoker /*= NULL*/) { - Unit* trigger = NULL; + Unit* scriptTrigger = NULL; if (invoker) - trigger = invoker; + scriptTrigger = invoker; else if (Unit* tempLastInvoker = GetLastInvoker()) - trigger = tempLastInvoker; + scriptTrigger = tempLastInvoker; + + WorldObject* baseObject = GetBaseObject(); ObjectList* l = new ObjectList(); switch (e.GetTargetType()) { case SMART_TARGET_SELF: - if (GetBaseObject()) - l->push_back(GetBaseObject()); + if (baseObject) + l->push_back(baseObject); break; case SMART_TARGET_VICTIM: if (me && me->getVictim()) @@ -2160,17 +2254,17 @@ ObjectList* SmartScript::GetTargets(SmartScriptHolder const& e, Unit* invoker /* break; case SMART_TARGET_NONE: case SMART_TARGET_ACTION_INVOKER: - if (trigger) - l->push_back(trigger); + if (scriptTrigger) + l->push_back(scriptTrigger); break; case SMART_TARGET_ACTION_INVOKER_VEHICLE: - if (trigger && trigger->GetVehicle() && trigger->GetVehicle()->GetBase()) - l->push_back(trigger->GetVehicle()->GetBase()); + if (scriptTrigger && scriptTrigger->GetVehicle() && scriptTrigger->GetVehicle()->GetBase()) + l->push_back(scriptTrigger->GetVehicle()->GetBase()); break; case SMART_TARGET_INVOKER_PARTY: - if (trigger) + if (scriptTrigger) { - if (Player* player = trigger->ToPlayer()) + if (Player* player = scriptTrigger->ToPlayer()) { if (Group* group = player->GetGroup()) { @@ -2182,7 +2276,7 @@ ObjectList* SmartScript::GetTargets(SmartScriptHolder const& e, Unit* invoker /* // this even if there is a group (thus the else-check), it will add the // same player to the list twice. We don't want that to happen. else - l->push_back(trigger); + l->push_back(scriptTrigger); } } break; @@ -2198,7 +2292,7 @@ ObjectList* SmartScript::GetTargets(SmartScriptHolder const& e, Unit* invoker /* if (me && me == *itr) continue; - if (((e.target.unitRange.creature && (*itr)->ToCreature()->GetEntry() == e.target.unitRange.creature) || !e.target.unitRange.creature) && GetBaseObject()->IsInRange(*itr, (float)e.target.unitRange.minDist, (float)e.target.unitRange.maxDist)) + if (((e.target.unitRange.creature && (*itr)->ToCreature()->GetEntry() == e.target.unitRange.creature) || !e.target.unitRange.creature) && baseObject->IsInRange(*itr, (float)e.target.unitRange.minDist, (float)e.target.unitRange.maxDist)) l->push_back(*itr); } @@ -2255,7 +2349,7 @@ ObjectList* SmartScript::GetTargets(SmartScriptHolder const& e, Unit* invoker /* if (go && go == *itr) continue; - if (((e.target.goRange.entry && IsGameObject(*itr) && (*itr)->ToGameObject()->GetEntry() == e.target.goRange.entry) || !e.target.goRange.entry) && GetBaseObject()->IsInRange((*itr), (float)e.target.goRange.minDist, (float)e.target.goRange.maxDist)) + if (((e.target.goRange.entry && IsGameObject(*itr) && (*itr)->ToGameObject()->GetEntry() == e.target.goRange.entry) || !e.target.goRange.entry) && baseObject->IsInRange((*itr), (float)e.target.goRange.minDist, (float)e.target.goRange.maxDist)) l->push_back(*itr); } @@ -2265,13 +2359,13 @@ ObjectList* SmartScript::GetTargets(SmartScriptHolder const& e, Unit* invoker /* case SMART_TARGET_CREATURE_GUID: { Creature* target = NULL; - if (!trigger && !GetBaseObject()) + if (!scriptTrigger && !baseObject) { sLog->outError(LOG_FILTER_SQL, "SMART_TARGET_CREATURE_GUID can not be used without invoker"); break; } - target = FindCreatureNear(trigger ? trigger : GetBaseObject(), e.target.unitGUID.dbGuid); + target = FindCreatureNear(scriptTrigger ? scriptTrigger : baseObject, e.target.unitGUID.dbGuid); if (target && (!e.target.unitGUID.entry || target->GetEntry() == e.target.unitGUID.entry)) l->push_back(target); @@ -2280,13 +2374,13 @@ ObjectList* SmartScript::GetTargets(SmartScriptHolder const& e, Unit* invoker /* case SMART_TARGET_GAMEOBJECT_GUID: { GameObject* target = NULL; - if (!trigger && !GetBaseObject()) + if (!scriptTrigger && !baseObject) { sLog->outError(LOG_FILTER_SQL, "SMART_TARGET_GAMEOBJECT_GUID can not be used without invoker"); break; } - target = FindGameObjectNear(trigger ? trigger : GetBaseObject(), e.target.goGUID.dbGuid); + target = FindGameObjectNear(scriptTrigger ? scriptTrigger : baseObject, e.target.goGUID.dbGuid); if (target && (!e.target.goGUID.entry || target->GetEntry() == e.target.goGUID.entry)) l->push_back(target); @@ -2296,9 +2390,9 @@ ObjectList* SmartScript::GetTargets(SmartScriptHolder const& e, Unit* invoker /* { // will always return a valid pointer, even if empty list ObjectList* units = GetWorldObjectsInDist((float)e.target.playerRange.maxDist); - if (!units->empty() && GetBaseObject()) + if (!units->empty() && baseObject) for (ObjectList::const_iterator itr = units->begin(); itr != units->end(); ++itr) - if (IsPlayer(*itr) && GetBaseObject()->IsInRange(*itr, (float)e.target.playerRange.minDist, (float)e.target.playerRange.maxDist)) + if (IsPlayer(*itr) && baseObject->IsInRange(*itr, (float)e.target.playerRange.minDist, (float)e.target.playerRange.maxDist)) l->push_back(*itr); delete units; @@ -2325,14 +2419,14 @@ ObjectList* SmartScript::GetTargets(SmartScriptHolder const& e, Unit* invoker /* } case SMART_TARGET_CLOSEST_CREATURE: { - Creature* target = GetClosestCreatureWithEntry(GetBaseObject(), e.target.closest.entry, (float)(e.target.closest.dist ? e.target.closest.dist : 100), e.target.closest.dead ? false : true); + Creature* target = GetClosestCreatureWithEntry(baseObject, e.target.closest.entry, (float)(e.target.closest.dist ? e.target.closest.dist : 100), e.target.closest.dead ? false : true); if (target) l->push_back(target); break; } case SMART_TARGET_CLOSEST_GAMEOBJECT: { - GameObject* target = GetClosestGameObjectWithEntry(GetBaseObject(), e.target.closest.entry, (float)(e.target.closest.dist ? e.target.closest.dist : 100)); + GameObject* target = GetClosestGameObjectWithEntry(baseObject, e.target.closest.entry, (float)(e.target.closest.dist ? e.target.closest.dist : 100)); if (target) l->push_back(target); break; @@ -2407,20 +2501,17 @@ void SmartScript::ProcessEvent(SmartScriptHolder& e, Unit* unit, uint32 var0, ui break; //called from Update tick case SMART_EVENT_UPDATE: - RecalcTimer(e, e.event.minMaxRepeat.repeatMin, e.event.minMaxRepeat.repeatMax); - ProcessAction(e); + ProcessTimedAction(e, e.event.minMaxRepeat.repeatMin, e.event.minMaxRepeat.repeatMax); break; case SMART_EVENT_UPDATE_OOC: if (me && me->isInCombat()) return; - RecalcTimer(e, e.event.minMaxRepeat.repeatMin, e.event.minMaxRepeat.repeatMax); - ProcessAction(e); + ProcessTimedAction(e, e.event.minMaxRepeat.repeatMin, e.event.minMaxRepeat.repeatMax); break; case SMART_EVENT_UPDATE_IC: if (!me || !me->isInCombat()) return; - RecalcTimer(e, e.event.minMaxRepeat.repeatMin, e.event.minMaxRepeat.repeatMax); - ProcessAction(e); + ProcessTimedAction(e, e.event.minMaxRepeat.repeatMin, e.event.minMaxRepeat.repeatMax); break; case SMART_EVENT_HEALT_PCT: { @@ -2429,8 +2520,7 @@ void SmartScript::ProcessEvent(SmartScriptHolder& e, Unit* unit, uint32 var0, ui uint32 perc = (uint32)me->GetHealthPct(); if (perc > e.event.minMaxRepeat.max || perc < e.event.minMaxRepeat.min) return; - RecalcTimer(e, e.event.minMaxRepeat.repeatMin, e.event.minMaxRepeat.repeatMax); - ProcessAction(e); + ProcessTimedAction(e, e.event.minMaxRepeat.repeatMin, e.event.minMaxRepeat.repeatMax); break; } case SMART_EVENT_TARGET_HEALTH_PCT: @@ -2440,8 +2530,7 @@ void SmartScript::ProcessEvent(SmartScriptHolder& e, Unit* unit, uint32 var0, ui uint32 perc = (uint32)me->getVictim()->GetHealthPct(); if (perc > e.event.minMaxRepeat.max || perc < e.event.minMaxRepeat.min) return; - RecalcTimer(e, e.event.minMaxRepeat.repeatMin, e.event.minMaxRepeat.repeatMax); - ProcessAction(e, me->getVictim()); + ProcessTimedAction(e, e.event.minMaxRepeat.repeatMin, e.event.minMaxRepeat.repeatMax, me->getVictim()); break; } case SMART_EVENT_MANA_PCT: @@ -2451,8 +2540,7 @@ void SmartScript::ProcessEvent(SmartScriptHolder& e, Unit* unit, uint32 var0, ui uint32 perc = uint32(100.0f * me->GetPower(POWER_MANA) / me->GetMaxPower(POWER_MANA)); if (perc > e.event.minMaxRepeat.max || perc < e.event.minMaxRepeat.min) return; - RecalcTimer(e, e.event.minMaxRepeat.repeatMin, e.event.minMaxRepeat.repeatMax); - ProcessAction(e); + ProcessTimedAction(e, e.event.minMaxRepeat.repeatMin, e.event.minMaxRepeat.repeatMax); break; } case SMART_EVENT_TARGET_MANA_PCT: @@ -2462,8 +2550,7 @@ void SmartScript::ProcessEvent(SmartScriptHolder& e, Unit* unit, uint32 var0, ui uint32 perc = uint32(100.0f * me->getVictim()->GetPower(POWER_MANA) / me->getVictim()->GetMaxPower(POWER_MANA)); if (perc > e.event.minMaxRepeat.max || perc < e.event.minMaxRepeat.min) return; - RecalcTimer(e, e.event.minMaxRepeat.repeatMin, e.event.minMaxRepeat.repeatMax); - ProcessAction(e, me->getVictim()); + ProcessTimedAction(e, e.event.minMaxRepeat.repeatMin, e.event.minMaxRepeat.repeatMax, me->getVictim()); break; } case SMART_EVENT_RANGE: @@ -2472,18 +2559,15 @@ void SmartScript::ProcessEvent(SmartScriptHolder& e, Unit* unit, uint32 var0, ui return; if (me->IsInRange(me->getVictim(), (float)e.event.minMaxRepeat.min, (float)e.event.minMaxRepeat.max)) - { - ProcessAction(e, me->getVictim()); - RecalcTimer(e, e.event.minMaxRepeat.repeatMin, e.event.minMaxRepeat.repeatMax); - } + ProcessTimedAction(e, e.event.minMaxRepeat.repeatMin, e.event.minMaxRepeat.repeatMax, me->getVictim()); break; } case SMART_EVENT_TARGET_CASTING: { if (!me || !me->isInCombat() || !me->getVictim() || !me->getVictim()->IsNonMeleeSpellCasted(false, false, true)) return; - ProcessAction(e, me->getVictim()); - RecalcTimer(e, e.event.minMax.repeatMin, e.event.minMax.repeatMax); + + ProcessTimedAction(e, e.event.minMaxRepeat.repeatMin, e.event.minMaxRepeat.repeatMax, me->getVictim()); } case SMART_EVENT_FRIENDLY_HEALTH: { @@ -2493,8 +2577,7 @@ void SmartScript::ProcessEvent(SmartScriptHolder& e, Unit* unit, uint32 var0, ui Unit* target = DoSelectLowestHpFriendly((float)e.event.friendlyHealt.radius, e.event.friendlyHealt.hpDeficit); if (!target) return; - ProcessAction(e, target); - RecalcTimer(e, e.event.friendlyHealt.repeatMin, e.event.friendlyHealt.repeatMax); + ProcessTimedAction(e, e.event.friendlyHealt.repeatMin, e.event.friendlyHealt.repeatMax, target); break; } case SMART_EVENT_FRIENDLY_IS_CC: @@ -2506,8 +2589,7 @@ void SmartScript::ProcessEvent(SmartScriptHolder& e, Unit* unit, uint32 var0, ui DoFindFriendlyCC(pList, (float)e.event.friendlyCC.radius); if (pList.empty()) return; - ProcessAction(e, *(pList.begin())); - RecalcTimer(e, e.event.friendlyCC.repeatMin, e.event.friendlyCC.repeatMax); + ProcessTimedAction(e, e.event.friendlyCC.repeatMin, e.event.friendlyCC.repeatMax, *pList.begin()); break; } case SMART_EVENT_FRIENDLY_MISSING_BUFF: @@ -2517,8 +2599,8 @@ void SmartScript::ProcessEvent(SmartScriptHolder& e, Unit* unit, uint32 var0, ui if (pList.empty()) return; - ProcessAction(e, *(pList.begin())); - RecalcTimer(e, e.event.missingBuff.repeatMin, e.event.missingBuff.repeatMax); + + ProcessTimedAction(e, e.event.missingBuff.repeatMin, e.event.missingBuff.repeatMax, *pList.begin()); break; } case SMART_EVENT_HAS_AURA: @@ -2527,10 +2609,7 @@ void SmartScript::ProcessEvent(SmartScriptHolder& e, Unit* unit, uint32 var0, ui return; uint32 count = me->GetAuraCount(e.event.aura.spell); if ((!e.event.aura.count && !count) || (e.event.aura.count && count >= e.event.aura.count)) - { - ProcessAction(e); - RecalcTimer(e, e.event.aura.repeatMin, e.event.aura.repeatMax); - } + ProcessTimedAction(e, e.event.aura.repeatMin, e.event.aura.repeatMax); break; } case SMART_EVENT_TARGET_BUFFED: @@ -2540,8 +2619,7 @@ void SmartScript::ProcessEvent(SmartScriptHolder& e, Unit* unit, uint32 var0, ui uint32 count = me->getVictim()->GetAuraCount(e.event.aura.spell); if (count < e.event.aura.count) return; - ProcessAction(e); - RecalcTimer(e, e.event.aura.repeatMin, e.event.aura.repeatMax); + ProcessTimedAction(e, e.event.aura.repeatMin, e.event.aura.repeatMax); break; } //no params @@ -2576,10 +2654,7 @@ void SmartScript::ProcessEvent(SmartScriptHolder& e, Unit* unit, uint32 var0, ui if (Unit* victim = me->getVictim()) { if (!victim->HasInArc(static_cast<float>(M_PI), me)) - { - ProcessAction(e, victim); - RecalcTimer(e, e.event.behindTarget.cooldownMin, e.event.behindTarget.cooldownMax); - } + ProcessTimedAction(e, e.event.behindTarget.cooldownMin, e.event.behindTarget.cooldownMax, victim); } break; } diff --git a/src/server/game/AI/SmartScripts/SmartScript.h b/src/server/game/AI/SmartScripts/SmartScript.h index d0d0221493f..28b328a2947 100644 --- a/src/server/game/AI/SmartScripts/SmartScript.h +++ b/src/server/game/AI/SmartScripts/SmartScript.h @@ -45,6 +45,7 @@ class SmartScript void UpdateTimer(SmartScriptHolder& e, uint32 const diff); void InitTimer(SmartScriptHolder& e); void ProcessAction(SmartScriptHolder& e, Unit* unit = NULL, uint32 var0 = 0, uint32 var1 = 0, bool bvar = false, const SpellInfo* spell = NULL, GameObject* gob = NULL); + void ProcessTimedAction(SmartScriptHolder& e, uint32 const& min, uint32 const& max, Unit* unit = NULL, uint32 var0 = 0, uint32 var1 = 0, bool bvar = false, const SpellInfo* spell = NULL, GameObject* gob = NULL); ObjectList* GetTargets(SmartScriptHolder const& e, Unit* invoker = NULL); ObjectList* GetWorldObjectsInDist(float dist); void InstallTemplate(SmartScriptHolder const& e); diff --git a/src/server/game/AI/SmartScripts/SmartScriptMgr.cpp b/src/server/game/AI/SmartScripts/SmartScriptMgr.cpp index a49ae031e63..a862670e826 100644 --- a/src/server/game/AI/SmartScripts/SmartScriptMgr.cpp +++ b/src/server/game/AI/SmartScripts/SmartScriptMgr.cpp @@ -101,8 +101,6 @@ SmartWaypointMgr::~SmartWaypointMgr() delete itr->second; } - - waypoint_map.clear(); } void SmartAIMgr::LoadSmartAIFromDB() @@ -906,6 +904,11 @@ bool SmartAIMgr::IsEventValid(SmartScriptHolder& e) case SMART_ACTION_SEND_TARGET_TO_TARGET: case SMART_ACTION_SET_HOME_POS: case SMART_ACTION_SET_HEALTH_REGEN: + case SMART_ACTION_SET_ROOT: + case SMART_ACTION_SET_GO_FLAG: + case SMART_ACTION_ADD_GO_FLAG: + case SMART_ACTION_REMOVE_GO_FLAG: + case SMART_ACTION_SUMMON_CREATURE_GROUP: break; default: sLog->outError(LOG_FILTER_SQL, "SmartAIMgr: Not handled action_type(%u), event_type(%u), Entry %d SourceType %u Event %u, skipped.", e.GetActionType(), e.GetEventType(), e.entryOrGuid, e.GetScriptType(), e.event_id); diff --git a/src/server/game/AI/SmartScripts/SmartScriptMgr.h b/src/server/game/AI/SmartScripts/SmartScriptMgr.h index c88ef206b00..3b9109a8f38 100644 --- a/src/server/game/AI/SmartScripts/SmartScriptMgr.h +++ b/src/server/game/AI/SmartScripts/SmartScriptMgr.h @@ -104,8 +104,8 @@ enum SMART_EVENT SMART_EVENT_REWARD_QUEST = 20, // QuestID(0any) SMART_EVENT_REACHED_HOME = 21, // NONE SMART_EVENT_RECEIVE_EMOTE = 22, // EmoteId, CooldownMin, CooldownMax, condition, val1, val2, val3 - SMART_EVENT_HAS_AURA = 23, // Param1 = SpellID, Param2 = Number of Time STacked, Param3/4 RepeatMin, RepeatMax - SMART_EVENT_TARGET_BUFFED = 24, // Param1 = SpellID, Param2 = Number of Time STacked, Param3/4 RepeatMin, RepeatMax + SMART_EVENT_HAS_AURA = 23, // Param1 = SpellID, Param2 = Stack amount, Param3/4 RepeatMin, RepeatMax + SMART_EVENT_TARGET_BUFFED = 24, // Param1 = SpellID, Param2 = Stack amount, Param3/4 RepeatMin, RepeatMax SMART_EVENT_RESET = 25, // Called after combat, when the creature respawn and spawn. SMART_EVENT_IC_LOS = 26, // NoHostile, MaxRnage, CooldownMin, CooldownMax SMART_EVENT_PASSENGER_BOARDED = 27, // CooldownMin, CooldownMax @@ -426,8 +426,7 @@ enum SMART_ACTION SMART_ACTION_SET_INVINCIBILITY_HP_LEVEL = 42, // MinHpValue(+pct, -flat) SMART_ACTION_MOUNT_TO_ENTRY_OR_MODEL = 43, // Creature_template entry(param1) OR ModelId (param2) (or 0 for both to dismount) SMART_ACTION_SET_INGAME_PHASE_MASK = 44, // mask - - SMART_ACTION_SET_DATA = 45, // Field, Data (only creature TODO) + SMART_ACTION_SET_DATA = 45, // Field, Data (only creature @todo) SMART_ACTION_MOVE_FORWARD = 46, // distance SMART_ACTION_SET_VISIBILITY = 47, // on/off SMART_ACTION_SET_ACTIVE = 48, // No Params @@ -449,7 +448,6 @@ enum SMART_ACTION SMART_ACTION_STORE_TARGET_LIST = 64, // varID, SMART_ACTION_WP_RESUME = 65, // none SMART_ACTION_SET_ORIENTATION = 66, // - SMART_ACTION_CREATE_TIMED_EVENT = 67, // id, InitialMin, InitialMax, RepeatMin(only if it repeats), RepeatMax(only if it repeats), chance SMART_ACTION_PLAYMOVIE = 68, // entry SMART_ACTION_MOVE_TO_POS = 69, // PointId, xyz @@ -486,8 +484,13 @@ enum SMART_ACTION SMART_ACTION_SEND_TARGET_TO_TARGET = 100, // id SMART_ACTION_SET_HOME_POS = 101, // none SMART_ACTION_SET_HEALTH_REGEN = 102, // 0/1 + SMART_ACTION_SET_ROOT = 103, // off/on + SMART_ACTION_SET_GO_FLAG = 104, // Flags + SMART_ACTION_ADD_GO_FLAG = 105, // Flags + SMART_ACTION_REMOVE_GO_FLAG = 106, // Flags + SMART_ACTION_SUMMON_CREATURE_GROUP = 107, // Group, attackInvoker - SMART_ACTION_END = 103 + SMART_ACTION_END = 108 }; struct SmartAction @@ -919,6 +922,22 @@ struct SmartAction uint32 regenHealth; } setHealthRegen; + struct + { + uint32 root; + } setRoot; + + struct + { + uint32 flag; + } goFlag; + + struct + { + uint32 group; + uint32 attackInvoker; + } creatureGroup; + //! Note for any new future actions //! All parameters must have type uint32 @@ -1282,9 +1301,9 @@ typedef UNORDERED_MAP<int32, SmartAIEventList> SmartAIEventMap; class SmartAIMgr { friend class ACE_Singleton<SmartAIMgr, ACE_Null_Mutex>; - SmartAIMgr(){}; + SmartAIMgr(){} public: - ~SmartAIMgr(){}; + ~SmartAIMgr(){} void LoadSmartAIFromDB(); diff --git a/src/server/game/Accounts/AccountMgr.cpp b/src/server/game/Accounts/AccountMgr.cpp index 01ba222d93b..716aabd9a98 100644 --- a/src/server/game/Accounts/AccountMgr.cpp +++ b/src/server/game/Accounts/AccountMgr.cpp @@ -17,6 +17,7 @@ */ #include "AccountMgr.h" +#include "Config.h" #include "DatabaseEnv.h" #include "ObjectAccessor.h" #include "Player.h" @@ -24,10 +25,16 @@ #include "SHA1.h" #include "WorldSession.h" -namespace AccountMgr +AccountMgr::AccountMgr() { +} + +AccountMgr::~AccountMgr() +{ + ClearRBAC(); +} -AccountOpResult CreateAccount(std::string username, std::string password) +AccountOpResult AccountMgr::CreateAccount(std::string username, std::string password) { if (utf8length(username) > MAX_ACCOUNT_STR) return AOR_NAME_TOO_LONG; // username's too long @@ -43,16 +50,26 @@ AccountOpResult CreateAccount(std::string username, std::string password) stmt->setString(0, username); stmt->setString(1, CalculateShaPassHash(username, password)); - LoginDatabase.Execute(stmt); + LoginDatabase.DirectExecute(stmt); // Enforce saving, otherwise AddGroup can fail stmt = LoginDatabase.GetPreparedStatement(LOGIN_INS_REALM_CHARACTERS_INIT); LoginDatabase.Execute(stmt); + // Add default rbac groups for that security level + RBACData* rbac = new RBACData(GetId(username), username, -1); + // No need to Load From DB, as it's new data + + RBACGroupContainer const& groupsToAdd = _defaultSecGroups[0]; // 0: Default sec level + for (RBACGroupContainer::const_iterator it = groupsToAdd.begin(); it != groupsToAdd.end(); ++it) + rbac->AddGroup(*it, -1); + + delete rbac; + return AOR_OK; // everything's fine } -AccountOpResult DeleteAccount(uint32 accountId) +AccountOpResult AccountMgr::DeleteAccount(uint32 accountId) { // Check if accounts exists PreparedStatement* stmt = LoginDatabase.GetPreparedStatement(LOGIN_SEL_ACCOUNT_BY_ID); @@ -124,7 +141,7 @@ AccountOpResult DeleteAccount(uint32 accountId) return AOR_OK; } -AccountOpResult ChangeUsername(uint32 accountId, std::string newUsername, std::string newPassword) +AccountOpResult AccountMgr::ChangeUsername(uint32 accountId, std::string newUsername, std::string newPassword) { // Check if accounts exists PreparedStatement* stmt = LoginDatabase.GetPreparedStatement(LOGIN_SEL_ACCOUNT_BY_ID); @@ -154,7 +171,7 @@ AccountOpResult ChangeUsername(uint32 accountId, std::string newUsername, std::s return AOR_OK; } -AccountOpResult ChangePassword(uint32 accountId, std::string newPassword) +AccountOpResult AccountMgr::ChangePassword(uint32 accountId, std::string newPassword) { std::string username; @@ -174,10 +191,18 @@ AccountOpResult ChangePassword(uint32 accountId, std::string newPassword) LoginDatabase.Execute(stmt); + stmt = LoginDatabase.GetPreparedStatement(LOGIN_UPD_VS); + + stmt->setString(0, ""); + stmt->setString(1, ""); + stmt->setString(2, username); + + LoginDatabase.Execute(stmt); + return AOR_OK; } -uint32 GetId(std::string const& username) +uint32 AccountMgr::GetId(std::string const& username) { PreparedStatement* stmt = LoginDatabase.GetPreparedStatement(LOGIN_GET_ACCOUNT_ID_BY_USERNAME); stmt->setString(0, username); @@ -186,7 +211,7 @@ uint32 GetId(std::string const& username) return (result) ? (*result)[0].GetUInt32() : 0; } -uint32 GetSecurity(uint32 accountId) +uint32 AccountMgr::GetSecurity(uint32 accountId) { PreparedStatement* stmt = LoginDatabase.GetPreparedStatement(LOGIN_GET_ACCOUNT_ACCESS_GMLEVEL); stmt->setUInt32(0, accountId); @@ -195,7 +220,7 @@ uint32 GetSecurity(uint32 accountId) return (result) ? (*result)[0].GetUInt8() : uint32(SEC_PLAYER); } -uint32 GetSecurity(uint32 accountId, int32 realmId) +uint32 AccountMgr::GetSecurity(uint32 accountId, int32 realmId) { PreparedStatement* stmt = LoginDatabase.GetPreparedStatement(LOGIN_GET_GMLEVEL_BY_REALMID); stmt->setUInt32(0, accountId); @@ -205,7 +230,7 @@ uint32 GetSecurity(uint32 accountId, int32 realmId) return (result) ? (*result)[0].GetUInt8() : uint32(SEC_PLAYER); } -bool GetName(uint32 accountId, std::string& name) +bool AccountMgr::GetName(uint32 accountId, std::string& name) { PreparedStatement* stmt = LoginDatabase.GetPreparedStatement(LOGIN_GET_USERNAME_BY_ID); stmt->setUInt32(0, accountId); @@ -220,7 +245,7 @@ bool GetName(uint32 accountId, std::string& name) return false; } -bool CheckPassword(uint32 accountId, std::string password) +bool AccountMgr::CheckPassword(uint32 accountId, std::string password) { std::string username; @@ -238,7 +263,7 @@ bool CheckPassword(uint32 accountId, std::string password) return (result) ? true : false; } -uint32 GetCharactersCount(uint32 accountId) +uint32 AccountMgr::GetCharactersCount(uint32 accountId) { // check character count PreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_SEL_SUM_CHARS); @@ -248,7 +273,7 @@ uint32 GetCharactersCount(uint32 accountId) return (result) ? (*result)[0].GetUInt64() : 0; } -bool normalizeString(std::string& utf8String) +bool AccountMgr::normalizeString(std::string& utf8String) { wchar_t buffer[MAX_ACCOUNT_STR+1]; @@ -266,7 +291,7 @@ bool normalizeString(std::string& utf8String) return WStrToUtf8(buffer, maxLength, utf8String); } -std::string CalculateShaPassHash(std::string const& name, std::string const& password) +std::string AccountMgr::CalculateShaPassHash(std::string const& name, std::string const& password) { SHA1Hash sha; sha.Initialize(); @@ -278,29 +303,276 @@ std::string CalculateShaPassHash(std::string const& name, std::string const& pas return ByteArrayToHexStr(sha.GetDigest(), sha.GetLength()); } -bool IsPlayerAccount(uint32 gmlevel) +bool AccountMgr::IsPlayerAccount(uint32 gmlevel) { return gmlevel == SEC_PLAYER; } -bool IsModeratorAccount(uint32 gmlevel) +bool AccountMgr::IsAdminAccount(uint32 gmlevel) { - return gmlevel >= SEC_MODERATOR && gmlevel <= SEC_CONSOLE; + return gmlevel >= SEC_ADMINISTRATOR && gmlevel <= SEC_CONSOLE; } -bool IsGMAccount(uint32 gmlevel) +bool AccountMgr::IsConsoleAccount(uint32 gmlevel) { - return gmlevel >= SEC_GAMEMASTER && gmlevel <= SEC_CONSOLE; + return gmlevel == SEC_CONSOLE; } -bool IsAdminAccount(uint32 gmlevel) +void AccountMgr::LoadRBAC() { - return gmlevel >= SEC_ADMINISTRATOR && gmlevel <= SEC_CONSOLE; + ClearRBAC(); + + sLog->outInfo(LOG_FILTER_RBAC, "AccountMgr::LoadRBAC"); + uint32 oldMSTime = getMSTime(); + uint32 count1 = 0; + uint32 count2 = 0; + uint32 count3 = 0; + + sLog->outDebug(LOG_FILTER_RBAC, "AccountMgr::LoadRBAC: Loading permissions"); + QueryResult result = LoginDatabase.Query("SELECT id, name FROM rbac_permissions"); + if (!result) + { + sLog->outInfo(LOG_FILTER_SQL, ">> Loaded 0 account permission definitions. DB table `rbac_permissions` is empty."); + return; + } + + do + { + Field* field = result->Fetch(); + uint32 id = field[0].GetUInt32(); + _permissions[id] = new RBACPermission(id, field[1].GetString()); + ++count1; + } + while (result->NextRow()); + + sLog->outDebug(LOG_FILTER_RBAC, "AccountMgr::LoadRBAC: Loading roles"); + result = LoginDatabase.Query("SELECT id, name FROM rbac_roles"); + if (!result) + { + sLog->outInfo(LOG_FILTER_SQL, ">> Loaded 0 account role definitions. DB table `rbac_roles` is empty."); + return; + } + + do + { + Field* field = result->Fetch(); + uint32 id = field[0].GetUInt32(); + _roles[id] = new RBACRole(id, field[1].GetString()); + ++count2; + } + while (result->NextRow()); + + sLog->outDebug(LOG_FILTER_RBAC, "AccountMgr::LoadRBAC: Loading role permissions"); + result = LoginDatabase.Query("SELECT roleId, permissionId FROM rbac_role_permissions"); + if (!result) + { + sLog->outInfo(LOG_FILTER_SQL, ">> Loaded 0 account role-permission definitions. DB table `rbac_role_permissions` is empty."); + return; + } + + do + { + Field* field = result->Fetch(); + uint32 id = field[0].GetUInt32(); + RBACRole* role = _roles[id]; + role->GrantPermission(field[1].GetUInt32()); + } + while (result->NextRow()); + + sLog->outDebug(LOG_FILTER_RBAC, "AccountMgr::LoadRBAC: Loading groups"); + result = LoginDatabase.Query("SELECT id, name FROM rbac_groups"); + if (!result) + { + sLog->outInfo(LOG_FILTER_SQL, ">> Loaded 0 account group definitions. DB table `rbac_groups` is empty."); + return; + } + + do + { + Field* field = result->Fetch(); + uint32 id = field[0].GetUInt32(); + _groups[id] = new RBACGroup(id, field[1].GetString()); + ++count3; + } + while (result->NextRow()); + + sLog->outDebug(LOG_FILTER_RBAC, "AccountMgr::LoadRBAC: Loading group roles"); + result = LoginDatabase.Query("SELECT groupId, roleId FROM rbac_group_roles"); + if (!result) + { + sLog->outInfo(LOG_FILTER_SQL, ">> Loaded 0 account group-role definitions. DB table `rbac_group_roles` is empty."); + return; + } + + do + { + Field* field = result->Fetch(); + uint32 id = field[0].GetUInt32(); + RBACGroup* group = _groups[id]; + group->GrantRole(field[1].GetUInt32()); + } + while (result->NextRow()); + + sLog->outDebug(LOG_FILTER_RBAC, "AccountMgr::LoadRBAC: Loading security level groups"); + result = LoginDatabase.Query("SELECT secId, groupId FROM rbac_security_level_groups ORDER by secId ASC"); + if (!result) + { + sLog->outInfo(LOG_FILTER_SQL, ">> Loaded 0 account default groups for security levels definitions. DB table `rbac_security_level_groups` is empty."); + return; + } + + uint8 lastSecId = 255; + RBACGroupContainer* groups = NULL; + do + { + Field* field = result->Fetch(); + uint8 secId = field[0].GetUInt8(); + + if (lastSecId != secId) + groups = &_defaultSecGroups[secId]; + + groups->insert(field[1].GetUInt32()); + } + while (result->NextRow()); + + sLog->outInfo(LOG_FILTER_SERVER_LOADING, ">> Loaded %u permission definitions, %u role definitions and %u group definitions in %u ms", count1, count2, count3, GetMSTimeDiffToNow(oldMSTime)); + + sLog->outDebug(LOG_FILTER_RBAC, "AccountMgr::LoadRBAC: Loading default groups"); + // Load default groups to be added to any RBAC Object. + std::string defaultGroups = ConfigMgr::GetStringDefault("RBAC.DefaultGroups", ""); + Tokenizer tokens(defaultGroups, ','); + for (Tokenizer::const_iterator itr = tokens.begin(); itr != tokens.end(); ++itr) + if (uint32 groupId = atoi(*itr)) + _defaultGroups.insert(groupId); } -bool IsConsoleAccount(uint32 gmlevel) +void AccountMgr::UpdateAccountAccess(RBACData* rbac, uint32 accountId, uint8 securityLevel, int32 realmId) { - return gmlevel == SEC_CONSOLE; + int32 serverRealmId = realmId != -1 ? realmId : ConfigMgr::GetIntDefault("RealmID", 0); + bool needDelete = false; + if (!rbac) + { + needDelete = true; + rbac = new RBACData(accountId, "", serverRealmId); + rbac->LoadFromDB(); + } + + // Get max security level and realm (checking current realm and -1) + PreparedStatement* stmt = LoginDatabase.GetPreparedStatement(LOGIN_SEL_ACCOUNT_ACCESS_BY_ID); + stmt->setUInt32(0, accountId); + stmt->setInt32(1, serverRealmId); + PreparedQueryResult result = LoginDatabase.Query(stmt); + if (result) + { + do + { + Field* field = result->Fetch(); + uint8 secLevel = field[0].GetUInt8(); + int32 realmId = field[1].GetUInt32(); + + RBACGroupContainer const& groupsToRemove = _defaultSecGroups[secLevel]; + for (RBACGroupContainer::const_iterator it = groupsToRemove.begin(); it != groupsToRemove.end(); ++it) + rbac->RemoveGroup(*it, realmId); + } + while (result->NextRow()); + } + + // Add new groups depending on the new security Level + RBACGroupContainer const& groupsToAdd = _defaultSecGroups[securityLevel]; + for (RBACGroupContainer::const_iterator it = groupsToAdd.begin(); it != groupsToAdd.end(); ++it) + rbac->AddGroup(*it, realmId); + + if (needDelete) + delete rbac; + + // Delete old security level from DB + if (realmId == -1) + { + PreparedStatement* stmt = LoginDatabase.GetPreparedStatement(LOGIN_DEL_ACCOUNT_ACCESS); + stmt->setUInt32(0, accountId); + LoginDatabase.Execute(stmt); + } + else + { + PreparedStatement* stmt = LoginDatabase.GetPreparedStatement(LOGIN_DEL_ACCOUNT_ACCESS_BY_REALM); + stmt->setUInt32(0, accountId); + stmt->setUInt32(1, realmId); + LoginDatabase.Execute(stmt); + } + + // Add new security level + if (securityLevel) + { + PreparedStatement* stmt = LoginDatabase.GetPreparedStatement(LOGIN_INS_ACCOUNT_ACCESS); + stmt->setUInt32(0, accountId); + stmt->setUInt8(1, securityLevel); + stmt->setInt32(2, realmId); + LoginDatabase.Execute(stmt); + } +} + +RBACGroup const* AccountMgr::GetRBACGroup(uint32 groupId) const +{ + sLog->outTrace(LOG_FILTER_RBAC, "AccountMgr::GetRBACGroup: groupId: %u", groupId); + RBACGroupsContainer::const_iterator it = _groups.find(groupId); + if (it != _groups.end()) + return it->second; + + return NULL; +} + +RBACRole const* AccountMgr::GetRBACRole(uint32 roleId) const +{ + sLog->outTrace(LOG_FILTER_RBAC, "AccountMgr::GetRBACRole: roleId: %u", roleId); + RBACRolesContainer::const_iterator it = _roles.find(roleId); + if (it != _roles.end()) + return it->second; + + return NULL; +} + +RBACPermission const* AccountMgr::GetRBACPermission(uint32 permissionId) const +{ + sLog->outTrace(LOG_FILTER_RBAC, "AccountMgr::GetRBACPermission: roleId: %u", permissionId); + RBACPermissionsContainer::const_iterator it = _permissions.find(permissionId); + if (it != _permissions.end()) + return it->second; + + return NULL; } -} // Namespace AccountMgr +bool AccountMgr::HasPermission(uint32 accountId, uint32 permissionId, uint32 realmId) +{ + if (!accountId) + { + sLog->outError(LOG_FILTER_RBAC, "AccountMgr::HasPermission: Wrong accountId 0"); + return false; + } + + RBACData* rbac = new RBACData(accountId, "", realmId); + rbac->LoadFromDB(); + bool hasPermission = rbac->HasPermission(permissionId); + delete rbac; + + sLog->outDebug(LOG_FILTER_RBAC, "AccountMgr::HasPermission [AccountId: %u, PermissionId: %u, realmId: %d]: %u", + accountId, permissionId, realmId, hasPermission); + return hasPermission; +} + +void AccountMgr::ClearRBAC() +{ + for (RBACPermissionsContainer::iterator itr = _permissions.begin(); itr != _permissions.end(); ++itr) + delete itr->second; + + for (RBACRolesContainer::iterator itr = _roles.begin(); itr != _roles.end(); ++itr) + delete itr->second; + + for (RBACGroupsContainer::iterator itr = _groups.begin(); itr != _groups.end(); ++itr) + delete itr->second; + + _permissions.clear(); + _roles.clear(); + _groups.clear(); + _defaultGroups.clear(); + _defaultSecGroups.clear(); +} diff --git a/src/server/game/Accounts/AccountMgr.h b/src/server/game/Accounts/AccountMgr.h index 7154cf0e867..878ecde24f9 100644 --- a/src/server/game/Accounts/AccountMgr.h +++ b/src/server/game/Accounts/AccountMgr.h @@ -19,8 +19,8 @@ #ifndef _ACCMGR_H #define _ACCMGR_H -#include "Define.h" -#include <string> +#include "RBAC.h" +#include <ace/Singleton.h> enum AccountOpResult { @@ -34,27 +34,59 @@ enum AccountOpResult #define MAX_ACCOUNT_STR 16 -namespace AccountMgr +typedef std::map<uint32, RBACPermission*> RBACPermissionsContainer; +typedef std::map<uint32, RBACRole*> RBACRolesContainer; +typedef std::map<uint32, RBACGroup*> RBACGroupsContainer; +typedef std::map<uint32, RBACGroupContainer> RBACDefaultSecurityGroupContainer; + +class AccountMgr { - AccountOpResult CreateAccount(std::string username, std::string password); - AccountOpResult DeleteAccount(uint32 accountId); - AccountOpResult ChangeUsername(uint32 accountId, std::string newUsername, std::string newPassword); - AccountOpResult ChangePassword(uint32 accountId, std::string newPassword); - bool CheckPassword(uint32 accountId, std::string password); - - uint32 GetId(std::string const& username); - uint32 GetSecurity(uint32 accountId); - uint32 GetSecurity(uint32 accountId, int32 realmId); - bool GetName(uint32 accountId, std::string& name); - uint32 GetCharactersCount(uint32 accountId); - std::string CalculateShaPassHash(std::string const& name, std::string const& password); - - bool normalizeString(std::string& utf8String); - bool IsPlayerAccount(uint32 gmlevel); - bool IsModeratorAccount(uint32 gmlevel); - bool IsGMAccount(uint32 gmlevel); - bool IsAdminAccount(uint32 gmlevel); - bool IsConsoleAccount(uint32 gmlevel); -} + friend class ACE_Singleton<AccountMgr, ACE_Null_Mutex>; + + private: + AccountMgr(); + ~AccountMgr(); + + public: + AccountOpResult CreateAccount(std::string username, std::string password); + static AccountOpResult DeleteAccount(uint32 accountId); + static AccountOpResult ChangeUsername(uint32 accountId, std::string newUsername, std::string newPassword); + static AccountOpResult ChangePassword(uint32 accountId, std::string newPassword); + static bool CheckPassword(uint32 accountId, std::string password); + + static uint32 GetId(std::string const& username); + static uint32 GetSecurity(uint32 accountId); + static uint32 GetSecurity(uint32 accountId, int32 realmId); + static bool GetName(uint32 accountId, std::string& name); + static uint32 GetCharactersCount(uint32 accountId); + + static std::string CalculateShaPassHash(std::string const& name, std::string const& password); + static bool normalizeString(std::string& utf8String); + static bool IsPlayerAccount(uint32 gmlevel); + static bool IsAdminAccount(uint32 gmlevel); + static bool IsConsoleAccount(uint32 gmlevel); + static bool HasPermission(uint32 accountId, uint32 permission, uint32 realmId); + + void UpdateAccountAccess(RBACData* rbac, uint32 accountId, uint8 securityLevel, int32 realmId); + + void LoadRBAC(); + RBACGroup const* GetRBACGroup(uint32 group) const; + RBACRole const* GetRBACRole(uint32 role) const; + RBACPermission const* GetRBACPermission(uint32 permission) const; + + RBACGroupsContainer const& GetRBACGroupList() const { return _groups; } + RBACRolesContainer const& GetRBACRoleList() const { return _roles; } + RBACPermissionsContainer const& GetRBACPermissionList() const { return _permissions; } + RBACGroupContainer const& GetRBACDefaultGroups() const { return _defaultGroups; } + + private: + void ClearRBAC(); + RBACPermissionsContainer _permissions; + RBACRolesContainer _roles; + RBACGroupsContainer _groups; + RBACDefaultSecurityGroupContainer _defaultSecGroups; + RBACGroupContainer _defaultGroups; +}; +#define sAccountMgr ACE_Singleton<AccountMgr, ACE_Null_Mutex>::instance() #endif diff --git a/src/server/game/Accounts/RBAC.cpp b/src/server/game/Accounts/RBAC.cpp new file mode 100644 index 00000000000..d26d557e2f4 --- /dev/null +++ b/src/server/game/Accounts/RBAC.cpp @@ -0,0 +1,493 @@ +/*
+ * Copyright (C) 2008-2013 TrinityCore <http://www.trinitycore.org/>
+ *
+ * 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 2 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/>.
+ */
+
+#include "RBAC.h"
+#include "AccountMgr.h"
+#include "DatabaseEnv.h"
+
+void RBACRole::GrantPermission(uint32 permissionId)
+{
+ if (permissionId < RBAC_PERM_MAX)
+ {
+ sLog->outTrace(LOG_FILTER_RBAC, "RBACRole::GrantPermission (Role %u, Permission %u). Ok", GetId(), permissionId);
+ _perms.set(permissionId);
+ }
+ else
+ sLog->outError(LOG_FILTER_RBAC, "RBACRole::GrantPermission (Role %u, Permission %u). Permission not lower than %u",
+ GetId(), permissionId, RBAC_PERM_MAX);
+}
+
+void RBACRole::RevokePermission(uint32 permissionId)
+{
+ if (permissionId < RBAC_PERM_MAX)
+ {
+ sLog->outTrace(LOG_FILTER_RBAC, "RBACRole::RevokePermission (Role %u, Permission %u). Ok", GetId(), permissionId);
+ _perms.reset(permissionId);
+ }
+ else
+ sLog->outError(LOG_FILTER_RBAC, "RBACRole::RevokePermission (Role %u, Permission %u). Permission not lower than %u",
+ GetId(), permissionId, RBAC_PERM_MAX);
+}
+
+void RBACGroup::GrantRole(uint32 roleId)
+{
+ sLog->outTrace(LOG_FILTER_RBAC, "RBACRole::GrantPermission (Role %u, Permission %u). Ok", GetId(), roleId);
+ _roles.insert(roleId);
+}
+
+void RBACGroup::RevokeRole(uint32 roleId)
+{
+ sLog->outTrace(LOG_FILTER_RBAC, "RBACRole::GrantPermission (Role %u, Permission %u). Ok", GetId(), roleId);
+ _roles.erase(roleId);
+}
+
+RBACCommandResult RBACData::AddGroup(uint32 groupId, int32 realmId /* = 0 */)
+{
+ // Check if group Id exists
+ RBACGroup const* group = sAccountMgr->GetRBACGroup(groupId);
+ if (!group)
+ {
+ sLog->outTrace(LOG_FILTER_RBAC, "RBACData::AddGroup [Id: %u Name: %s] (Group %u, RealmId %d). Group does not exists",
+ GetId(), GetName().c_str(), groupId, realmId);
+ return RBAC_ID_DOES_NOT_EXISTS;
+ }
+
+ // Already added?
+ std::pair<std::set<uint32>::iterator, bool> ret = _groups.insert(groupId);
+ if (!ret.second)
+ {
+ sLog->outTrace(LOG_FILTER_RBAC, "RBACData::AddGroup [Id: %u Name: %s] (Group %u, RealmId %d). Group Already added",
+ GetId(), GetName().c_str(), groupId, realmId);
+ return RBAC_CANT_ADD_ALREADY_ADDED;
+ }
+
+ // Do not save to db when loading data from DB (realmId = 0)
+ if (realmId)
+ {
+ sLog->outTrace(LOG_FILTER_RBAC, "RBACData::AddGroup [Id: %u Name: %s] (Group %u, RealmId %d). Added and DB updated",
+ GetId(), GetName().c_str(), groupId, realmId);
+ PreparedStatement* stmt = LoginDatabase.GetPreparedStatement(LOGIN_INS_RBAC_ACCOUNT_GROUP);
+ stmt->setUInt32(0, GetId());
+ stmt->setUInt32(1, groupId);
+ stmt->setInt32(2, realmId);
+ LoginDatabase.Execute(stmt);
+
+ CalculateNewPermissions();
+ }
+ else
+ sLog->outTrace(LOG_FILTER_RBAC, "RBACData::AddGroup [Id: %u Name: %s] (Group %u, RealmId %d). Added",
+ GetId(), GetName().c_str(), groupId, realmId);
+
+ return RBAC_OK;
+}
+
+RBACCommandResult RBACData::RemoveGroup(uint32 groupId, int32 realmId /* = 0 */)
+{
+ // could remove it?
+ if (!_groups.erase(groupId))
+ {
+ sLog->outTrace(LOG_FILTER_RBAC, "RBACData::RemoveGroup [Id: %u Name: %s] (Group %u, RealmId %d). Group not in list",
+ GetId(), GetName().c_str(), groupId, realmId);
+ return RBAC_CANT_REVOKE_NOT_IN_LIST;
+ }
+
+ // Do not save to db when loading data from DB (realmId = 0)
+ if (realmId)
+ {
+ sLog->outTrace(LOG_FILTER_RBAC, "RBACData::RemoveGroup [Id: %u Name: %s] (Group %u, RealmId %d). Removed and DB updated",
+ GetId(), GetName().c_str(), groupId, realmId);
+ PreparedStatement* stmt = LoginDatabase.GetPreparedStatement(LOGIN_DEL_RBAC_ACCOUNT_GROUP);
+ stmt->setUInt32(0, GetId());
+ stmt->setUInt32(1, groupId);
+ stmt->setInt32(2, realmId);
+ LoginDatabase.Execute(stmt);
+
+ CalculateNewPermissions();
+ }
+ else
+ sLog->outTrace(LOG_FILTER_RBAC, "RBACData::RemoveGroup [Id: %u Name: %s] (Group %u, RealmId %d). Removed",
+ GetId(), GetName().c_str(), groupId, realmId);
+
+ return RBAC_OK;
+}
+
+RBACCommandResult RBACData::GrantRole(uint32 roleId, int32 realmId /* = 0*/)
+{
+ // Check if role Id exists
+ RBACRole const* role = sAccountMgr->GetRBACRole(roleId);
+ if (!role)
+ {
+ sLog->outTrace(LOG_FILTER_RBAC, "RBACData::GrantRole [Id: %u Name: %s] (Role %u, RealmId %d). Role does not exists",
+ GetId(), GetName().c_str(), roleId, realmId);
+ return RBAC_ID_DOES_NOT_EXISTS;
+ }
+
+ // Check if already added in denied list
+ if (_deniedRoles.find(roleId) != _deniedRoles.end())
+ {
+ sLog->outTrace(LOG_FILTER_RBAC, "RBACData::GrantRole [Id: %u Name: %s] (Role %u, RealmId %d). Role in deny list",
+ GetId(), GetName().c_str(), roleId, realmId);
+ return RBAC_IN_DENIED_LIST;
+ }
+
+ // Already added?
+ std::pair<std::set<uint32>::iterator, bool> ret = _grantedRoles.insert(roleId);
+ if (!ret.second)
+ {
+ sLog->outTrace(LOG_FILTER_RBAC, "RBACData::GrantRole [Id: %u Name: %s] (Role %u, RealmId %d). Role already granted",
+ GetId(), GetName().c_str(), roleId, realmId);
+ return RBAC_CANT_ADD_ALREADY_ADDED;
+ }
+
+ // Do not save to db when loading data from DB (realmId = 0)
+ if (realmId)
+ {
+ sLog->outTrace(LOG_FILTER_RBAC, "RBACData::GrantRole [Id: %u Name: %s] (Role %u, RealmId %d). Ok and DB updated",
+ GetId(), GetName().c_str(), roleId, realmId);
+ SaveRole(roleId, true, realmId);
+ CalculateNewPermissions();
+ }
+ else
+ sLog->outTrace(LOG_FILTER_RBAC, "RBACData::GrantRole [Id: %u Name: %s] (Role %u, RealmId %d). Ok",
+ GetId(), GetName().c_str(), roleId, realmId);
+
+ return RBAC_OK;
+}
+
+RBACCommandResult RBACData::DenyRole(uint32 roleId, int32 realmId /* = 0*/)
+{
+ // Check if role Id exists
+ RBACRole const* role = sAccountMgr->GetRBACRole(roleId);
+ if (!role)
+ {
+ sLog->outTrace(LOG_FILTER_RBAC, "RBACData::DenyRole [Id: %u Name: %s] (Role %u, RealmId %d). Role does not exists",
+ GetId(), GetName().c_str(), roleId, realmId);
+ return RBAC_ID_DOES_NOT_EXISTS;
+ }
+
+ // Check if already added in granted list
+ if (_grantedRoles.find(roleId) != _grantedRoles.end())
+ {
+ sLog->outTrace(LOG_FILTER_RBAC, "RBACData::DenyRole [Id: %u Name: %s] (Role %u, RealmId %d). Role in grant list",
+ GetId(), GetName().c_str(), roleId, realmId);
+ return RBAC_IN_GRANTED_LIST;
+ }
+
+ // Already added?
+ std::pair<std::set<uint32>::iterator, bool> ret = _deniedRoles.insert(roleId);
+ if (!ret.second)
+ {
+ sLog->outTrace(LOG_FILTER_RBAC, "RBACData::DenyRole [Id: %u Name: %s] (Role %u, RealmId %d). Role already denied",
+ GetId(), GetName().c_str(), roleId, realmId);
+ return RBAC_CANT_ADD_ALREADY_ADDED;
+ }
+
+ // Do not save to db when loading data from DB (realmId = 0)
+ if (realmId)
+ {
+ sLog->outTrace(LOG_FILTER_RBAC, "RBACData::DenyRole [Id: %u Name: %s] (Role %u, RealmId %d). Ok and DB updated",
+ GetId(), GetName().c_str(), roleId, realmId);
+ SaveRole(roleId, false, realmId);
+ CalculateNewPermissions();
+ }
+ else
+ sLog->outTrace(LOG_FILTER_RBAC, "RBACData::DenyRole [Id: %u Name: %s] (Role %u, RealmId %d). Ok",
+ GetId(), GetName().c_str(), roleId, realmId);
+
+ return RBAC_OK;
+}
+
+void RBACData::SaveRole(uint32 roleId, bool granted, int32 realmId)
+{
+ PreparedStatement* stmt = LoginDatabase.GetPreparedStatement(LOGIN_INS_RBAC_ACCOUNT_ROLE);
+ stmt->setUInt32(0, GetId());
+ stmt->setUInt32(1, roleId);
+ stmt->setBool(2, granted);
+ stmt->setInt32(3, realmId);
+ LoginDatabase.Execute(stmt);
+}
+
+RBACCommandResult RBACData::RevokeRole(uint32 roleId, int32 realmId /* = 0*/)
+{
+ uint8 revoked = _grantedRoles.erase(roleId) + _deniedRoles.erase(roleId);
+
+ // could remove it?
+ if (!revoked)
+ {
+ sLog->outTrace(LOG_FILTER_RBAC, "RBACData::RevokeRole [Id: %u Name: %s] (Role %u, RealmId %d). Not granted or revoked",
+ GetId(), GetName().c_str(), roleId, realmId);
+ return RBAC_CANT_REVOKE_NOT_IN_LIST;
+ }
+
+ // Do not save to db when loading data from DB (realmId = 0)
+ if (realmId)
+ {
+ sLog->outTrace(LOG_FILTER_RBAC, "RBACData::RevokeRole [Id: %u Name: %s] (Role %u, RealmId %d). Ok and DB updated",
+ GetId(), GetName().c_str(), roleId, realmId);
+ PreparedStatement* stmt = LoginDatabase.GetPreparedStatement(LOGIN_DEL_RBAC_ACCOUNT_ROLE);
+ stmt->setUInt32(0, GetId());
+ stmt->setUInt32(1, roleId);
+ stmt->setInt32(2, realmId);
+ LoginDatabase.Execute(stmt);
+
+ CalculateNewPermissions();
+ }
+ else
+ sLog->outTrace(LOG_FILTER_RBAC, "RBACData::RevokeRole [Id: %u Name: %s] (Role %u, RealmId %d). Ok",
+ GetId(), GetName().c_str(), roleId, realmId);
+
+ return RBAC_OK;
+}
+
+RBACCommandResult RBACData::GrantPermission(uint32 permissionId, int32 realmId /* = 0*/)
+{
+ // Check if permission Id exists
+ RBACPermission const* perm = sAccountMgr->GetRBACPermission(permissionId);
+ if (!perm)
+ {
+ sLog->outTrace(LOG_FILTER_RBAC, "RBACData::GrantPermission [Id: %u Name: %s] (Permission %u, RealmId %d). Permission does not exists",
+ GetId(), GetName().c_str(), permissionId, realmId);
+ return RBAC_ID_DOES_NOT_EXISTS;
+ }
+
+ // Check if already added in denied list
+ if (_deniedPerms.test(permissionId))
+ {
+ sLog->outTrace(LOG_FILTER_RBAC, "RBACData::GrantPermission [Id: %u Name: %s] (Permission %u, RealmId %d). Permission in deny list",
+ GetId(), GetName().c_str(), permissionId, realmId);
+ return RBAC_IN_DENIED_LIST;
+ }
+
+ // Already added?
+ if (_grantedPerms.test(permissionId))
+ {
+ sLog->outTrace(LOG_FILTER_RBAC, "RBACData::GrantPermission [Id: %u Name: %s] (Permission %u, RealmId %d). Permission already granted",
+ GetId(), GetName().c_str(), permissionId, realmId);
+ return RBAC_CANT_ADD_ALREADY_ADDED;
+ }
+
+ _grantedPerms.set(permissionId);
+
+ // Do not save to db when loading data from DB (realmId = 0)
+ if (realmId)
+ {
+ sLog->outTrace(LOG_FILTER_RBAC, "RBACData::GrantPermission [Id: %u Name: %s] (Permission %u, RealmId %d). Ok and DB updated",
+ GetId(), GetName().c_str(), permissionId, realmId);
+ SavePermission(permissionId, true, realmId);
+ CalculateNewPermissions();
+ }
+ else
+ sLog->outTrace(LOG_FILTER_RBAC, "RBACData::GrantPermission [Id: %u Name: %s] (Permission %u, RealmId %d). Ok",
+ GetId(), GetName().c_str(), permissionId, realmId);
+
+ return RBAC_OK;
+}
+
+RBACCommandResult RBACData::DenyPermission(uint32 permissionId, int32 realmId /* = 0*/)
+{
+ // Check if permission Id exists
+ RBACPermission const* perm = sAccountMgr->GetRBACPermission(permissionId);
+ if (!perm)
+ {
+ sLog->outTrace(LOG_FILTER_RBAC, "RBACData::DenyPermission [Id: %u Name: %s] (Permission %u, RealmId %d). Permission does not exists",
+ GetId(), GetName().c_str(), permissionId, realmId);
+ return RBAC_ID_DOES_NOT_EXISTS;
+ }
+
+ // Check if already added in granted list
+ if (_grantedPerms.test(permissionId))
+ {
+ sLog->outTrace(LOG_FILTER_RBAC, "RBACData::DenyPermission [Id: %u Name: %s] (Permission %u, RealmId %d). Permission in grant list",
+ GetId(), GetName().c_str(), permissionId, realmId);
+ return RBAC_IN_GRANTED_LIST;
+ }
+
+ // Already added?
+ if (_deniedPerms.test(permissionId))
+ {
+ sLog->outTrace(LOG_FILTER_RBAC, "RBACData::DenyPermission [Id: %u Name: %s] (Permission %u, RealmId %d). Permission already denied",
+ GetId(), GetName().c_str(), permissionId, realmId);
+ return RBAC_CANT_ADD_ALREADY_ADDED;
+ }
+
+ _deniedPerms.set(permissionId);
+
+ // Do not save to db when loading data from DB (realmId = 0)
+ if (realmId)
+ {
+ sLog->outTrace(LOG_FILTER_RBAC, "RBACData::DenyPermission [Id: %u Name: %s] (Permission %u, RealmId %d). Ok and DB updated",
+ GetId(), GetName().c_str(), permissionId, realmId);
+ SavePermission(permissionId, false, realmId);
+ CalculateNewPermissions();
+ }
+ else
+ sLog->outTrace(LOG_FILTER_RBAC, "RBACData::DenyPermission [Id: %u Name: %s] (Permission %u, RealmId %d). Ok",
+ GetId(), GetName().c_str(), permissionId, realmId);
+
+ return RBAC_OK;
+}
+
+void RBACData::SavePermission(uint32 permission, bool granted, int32 realmId)
+{
+ PreparedStatement* stmt = LoginDatabase.GetPreparedStatement(LOGIN_INS_RBAC_ACCOUNT_PERMISSION);
+ stmt->setUInt32(0, GetId());
+ stmt->setUInt32(1, permission);
+ stmt->setBool(2, granted);
+ stmt->setInt32(3, realmId);
+ LoginDatabase.Execute(stmt);
+}
+
+RBACCommandResult RBACData::RevokePermission(uint32 permissionId, int32 realmId /* = 0*/)
+{
+ // Check if it's present in any list
+ if (!_grantedPerms.test(permissionId) && !_deniedPerms.test(permissionId))
+ {
+ sLog->outTrace(LOG_FILTER_RBAC, "RBACData::RevokePermission [Id: %u Name: %s] (Permission %u, RealmId %d). Not granted or revoked",
+ GetId(), GetName().c_str(), permissionId, realmId);
+ return RBAC_CANT_REVOKE_NOT_IN_LIST;
+ }
+
+ _grantedPerms.reset(permissionId);
+ _deniedPerms.reset(permissionId);
+
+ // Do not save to db when loading data from DB (realmId = 0)
+ if (realmId)
+ {
+ sLog->outTrace(LOG_FILTER_RBAC, "RBACData::RevokePermission [Id: %u Name: %s] (Permission %u, RealmId %d). Ok and DB updated",
+ GetId(), GetName().c_str(), permissionId, realmId);
+ PreparedStatement* stmt = LoginDatabase.GetPreparedStatement(LOGIN_DEL_RBAC_ACCOUNT_PERMISSION);
+ stmt->setUInt32(0, GetId());
+ stmt->setUInt32(1, permissionId);
+ stmt->setInt32(2, realmId);
+ LoginDatabase.Execute(stmt);
+
+ CalculateNewPermissions();
+ }
+ else
+ sLog->outTrace(LOG_FILTER_RBAC, "RBACData::RevokePermission [Id: %u Name: %s] (Permission %u, RealmId %d). Ok",
+ GetId(), GetName().c_str(), permissionId, realmId);
+
+ return RBAC_OK;
+}
+
+void RBACData::LoadFromDB()
+{
+ sLog->outInfo(LOG_FILTER_RBAC, "RBACData::LoadFromDB [Id: %u Name: %s]", GetId(), GetName().c_str());
+ sLog->outDebug(LOG_FILTER_RBAC, "RBACData::LoadFromDB [Id: %u Name: %s]: Loading groups", GetId(), GetName().c_str());
+
+ // Load account group that affect current realm
+ PreparedStatement* stmt = LoginDatabase.GetPreparedStatement(LOGIN_SEL_RBAC_ACCOUNT_GROUPS);
+ stmt->setUInt32(0, GetId());
+ stmt->setInt32(1, GetRealmId());
+ PreparedQueryResult result = LoginDatabase.Query(stmt);
+
+ if (result)
+ {
+ do
+ {
+ Field* fields = result->Fetch();
+ AddGroup(fields[0].GetUInt32());
+ }
+ while (result->NextRow());
+ }
+
+ sLog->outDebug(LOG_FILTER_RBAC, "RBACData::LoadFromDB [Id: %u Name: %s]: Loading roles", GetId(), GetName().c_str());
+ // Load account roles (granted and denied) that affect current realm
+ stmt = LoginDatabase.GetPreparedStatement(LOGIN_SEL_RBAC_ACCOUNT_ROLES);
+ stmt->setUInt32(0, GetId());
+ stmt->setInt32(1, GetRealmId());
+ result = LoginDatabase.Query(stmt);
+
+ if (result)
+ {
+ do
+ {
+ Field* fields = result->Fetch();
+ if (fields[1].GetBool())
+ GrantRole(fields[0].GetUInt32());
+ else
+ DenyRole(fields[0].GetUInt32());
+ }
+ while (result->NextRow());
+ }
+
+ sLog->outDebug(LOG_FILTER_RBAC, "RBACData::LoadFromDB [Id: %u Name: %s]: Loading permissions", GetId(), GetName().c_str());
+ // Load account permissions (granted and denied) that affect current realm
+ stmt = LoginDatabase.GetPreparedStatement(LOGIN_SEL_RBAC_ACCOUNT_PERMISSIONS);
+ stmt->setUInt32(0, GetId());
+ stmt->setInt32(1, GetRealmId());
+
+ result = LoginDatabase.Query(stmt);
+ if (result)
+ {
+ do
+ {
+ Field* fields = result->Fetch();
+ if (fields[1].GetBool())
+ GrantPermission(fields[0].GetUInt32());
+ else
+ DenyPermission(fields[0].GetUInt32());
+ }
+ while (result->NextRow());
+ }
+
+ sLog->outDebug(LOG_FILTER_RBAC, "RBACData::LoadFromDB [Id: %u Name: %s]: Adding default groups", GetId(), GetName().c_str());
+ // Add default groups
+ RBACGroupContainer const& groups = sAccountMgr->GetRBACDefaultGroups();
+ for (RBACGroupContainer::const_iterator itr = groups.begin(); itr != groups.end(); ++itr)
+ AddGroup(*itr);
+
+ sLog->outDebug(LOG_FILTER_RBAC, "RBACData::LoadFromDB [Id: %u Name: %s]: Calculating global permissions", GetId(), GetName().c_str());
+ // Force calculation of permissions, it wasn't performed at load time
+ // while adding groups, roles and permissions
+ CalculateNewPermissions();
+}
+
+void RBACData::CalculateNewPermissions()
+{
+ sLog->outTrace(LOG_FILTER_RBAC, "RBACData::LoadFromDB [Id: %u Name: %s]: Calculating global permissions", GetId(), GetName().c_str());
+ // Get the list of directly granted roles
+ RBACRoleContainer tempGrantedRoles = GetGrantedRoles();
+
+ // Add those roles inherited from groups
+ for (RBACGroupContainer::const_iterator itGroup = _groups.begin(); itGroup != _groups.end(); ++itGroup)
+ {
+ RBACGroup const* group = sAccountMgr->GetRBACGroup(*itGroup);
+ if (!group) // Should never happen due to foreign keys in DB
+ continue;
+
+ RBACRoleContainer const& roles = group->GetRoles();
+ for (RBACRoleContainer::const_iterator it = roles.begin(); it != roles.end(); ++it)
+ tempGrantedRoles.insert(*it);
+ }
+
+ // Get the list of granted permissions
+ _globalPerms = GetGrantedPermissions();
+
+ // Add those permissions inherited from roles granted
+ for (RBACRoleContainer::const_iterator it = tempGrantedRoles.begin(); it != tempGrantedRoles.end(); ++it)
+ if (RBACRole const* role = sAccountMgr->GetRBACRole(*it))
+ _globalPerms |= role->GetPermissions();
+
+ // Remove denied permissions from the list
+ _globalPerms &= ~GetDeniedPermissions();
+
+ // Remove those permissions inherited from denied roles
+ for (RBACRoleContainer::const_iterator it = _deniedRoles.begin(); it != _deniedRoles.end(); ++it)
+ if (RBACRole const* role = sAccountMgr->GetRBACRole(*it))
+ _globalPerms &= ~role->GetPermissions();
+}
diff --git a/src/server/game/Accounts/RBAC.h b/src/server/game/Accounts/RBAC.h new file mode 100644 index 00000000000..779b0ece021 --- /dev/null +++ b/src/server/game/Accounts/RBAC.h @@ -0,0 +1,447 @@ +/*
+ * Copyright (C) 2008-2013 TrinityCore <http://www.trinitycore.org/>
+ *
+ * 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 2 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/>.
+ */
+
+/**
+* @file RBAC.h
+* @brief Role Based Access Control related classes definition
+*
+* This file contains all the classes and enums used to implement
+* Role Based Access Control
+*
+* RBAC Rules:
+* - Pemission: Defines an autorization to perform certain operation.
+* - Role: Set of permissions.
+* - Group: Set of roles.
+* - An Account can have multiple groups, roles and permissions.
+* - Account Groups can only be granted or revoked
+* - Account Roles and Permissions can be granted, denied or revoked
+* - Grant: Assignment of the object (role/permission) and allow it
+* - Deny: Assignment of the object (role/permission) and deny it
+* - Revoke: Removal of the object (role/permission) no matter if it was granted or denied
+* - Global Permissions are computed as:
+* Group Grants + Role Grants + User Grans - Role Grants - User Grants
+* - Groups, Roles and Permissions can be assigned by realm
+*/
+
+#ifndef _RBAC_H
+#define _RBAC_H
+
+#include "Define.h"
+#include <string>
+#include <bitset>
+#include <set>
+#include <map>
+
+enum RBACPermissions
+{
+ RBAC_PERM_INSTANT_LOGOUT = 1,
+ RBAC_PERM_SKIP_QUEUE = 2,
+ RBAC_PERM_JOIN_NORMAL_BG = 3,
+ RBAC_PERM_JOIN_RANDOM_BG = 4,
+ RBAC_PERM_JOIN_ARENAS = 5,
+ RBAC_PERM_JOIN_DUNGEON_FINDER = 6,
+ RBAC_PERM_PLAYER_COMMANDS = 7,
+ RBAC_PERM_MODERATOR_COMMANDS = 8,
+ RBAC_PERM_GAMEMASTER_COMMANDS = 9,
+ RBAC_PERM_ADMINISTRATOR_COMMANDS = 10,
+ RBAC_PERM_LOG_GM_TRADE = 11,
+ // Free = 12
+ RBAC_PERM_SKIP_CHECK_INSTANCE_REQUIRED_BOSSES = 13,
+ RBAC_PERM_SKIP_CHECK_CHARACTER_CREATION_TEAMMASK = 14,
+ RBAC_PERM_SKIP_CHECK_CHARACTER_CREATION_CLASSMASK = 15,
+ RBAC_PERM_SKIP_CHECK_CHARACTER_CREATION_RACEMASK = 16,
+ RBAC_PERM_SKIP_CHECK_CHARACTER_CREATION_RESERVEDNAME = 17,
+ RBAC_PERM_SKIP_CHECK_CHARACTER_CREATION_HEROIC_CHARACTER = 18,
+ RBAC_PERM_SKIP_CHECK_CHAT_CHANNEL_REQ = 19,
+ RBAC_PERM_SKIP_CHECK_DISABLE_MAP = 20,
+ RBAC_PERM_SKIP_CHECK_MORE_TALENTS_THAN_ALLOWED = 21,
+ RBAC_PERM_SKIP_CHECK_CHAT_SPAM = 22,
+ RBAC_PERM_SKIP_CHECK_OVERSPEED_PING = 23,
+ RBAC_PERM_TWO_SIDE_CHARACTER_CREATION = 24,
+ RBAC_PERM_TWO_SIDE_INTERACTION_CHAT = 25,
+ RBAC_PERM_TWO_SIDE_INTERACTION_CHANNEL = 26,
+ RBAC_PERM_TWO_SIDE_INTERACTION_MAIL = 27,
+ RBAC_PERM_TWO_SIDE_WHO_LIST = 28,
+ RBAC_PERM_TWO_SIDE_ADD_FRIEND = 29,
+ RBAC_PERM_COMMANDS_SAVE_WITHOUT_DELAY = 30,
+ RBAC_PERM_COMMANDS_USE_UNSTUCK_WITH_ARGS = 31,
+ RBAC_PERM_COMMANDS_BE_ASSIGNED_TICKET = 32,
+ RBAC_PERM_COMMANDS_NOTIFY_COMMAND_NOT_FOUND_ERROR = 33,
+ RBAC_PERM_COMMANDS_APPEAR_IN_GM_LIST = 34,
+ RBAC_PERM_WHO_SEE_ALL_SEC_LEVELS = 35,
+ RBAC_PERM_CAN_FILTER_WHISPERS = 36,
+ RBAC_PERM_CHAT_USE_STAFF_BADGE = 37,
+ RBAC_PERM_RESURRECT_WITH_FULL_HPS = 38,
+ RBAC_PERM_RESTORE_SAVED_GM_STATE = 39,
+ RBAC_PERM_ALLOW_GM_FRIEND = 40,
+ RBAC_PERM_USE_START_GM_LEVEL = 41,
+ RBAC_PERM_OPCODE_WORLD_TELEPORT = 42,
+ RBAC_PERM_OPCODE_WHOIS = 43,
+ RBAC_PERM_RECEIVE_GLOBAL_GM_TEXTMESSAGE = 44,
+ RBAC_PERM_SILENTLY_JOIN_CHANNEL = 45,
+ RBAC_PERM_CHANGE_CHANNEL_NOT_MODERATOR = 46,
+ RBAC_PERM_CHECK_FOR_LOWER_SECURITY = 47,
+ RBAC_PERM_MAX
+};
+
+enum RBACCommandResult
+{
+ RBAC_OK,
+ RBAC_CANT_ADD_ALREADY_ADDED,
+ RBAC_CANT_REVOKE_NOT_IN_LIST,
+ RBAC_IN_GRANTED_LIST,
+ RBAC_IN_DENIED_LIST,
+ RBAC_ID_DOES_NOT_EXISTS
+};
+
+typedef std::bitset<RBAC_PERM_MAX> RBACPermissionContainer;
+typedef std::set<uint32> RBACRoleContainer;
+typedef std::set<uint32> RBACGroupContainer;
+
+class RBACObject
+{
+ public:
+ RBACObject(uint32 id = 0, std::string const& name = ""):
+ _id(id), _name(name) { }
+
+ /// Gets the Name of the Object
+ std::string const& GetName() const { return _name; }
+ /// Gets the Id of the Object
+ uint32 GetId() const { return _id; }
+
+ private:
+ uint32 _id; ///> id of the object
+ std::string _name; ///> name of the object
+};
+
+/// Permission: Defines an autorization to perform certain operation
+class RBACPermission: public RBACObject
+{
+ public:
+ RBACPermission(uint32 id = 0, std::string const& name = ""):
+ RBACObject(id, name) { }
+};
+
+/// Set of Permissions
+class RBACRole: public RBACObject
+{
+ public:
+ RBACRole(uint32 id = 0, std::string const& name = ""):
+ RBACObject(id, name) { }
+
+ /// Gets the Permissions assigned to this role
+ RBACPermissionContainer const& GetPermissions() const { return _perms; }
+ /// Grants a Permission (Adds)
+ void GrantPermission(uint32 id);
+ /// Revokes a Permission (Removes)
+ void RevokePermission(uint32 id);
+
+ private:
+ RBACPermissionContainer _perms; ///> Set of permissions
+};
+
+/// Set of Roles
+class RBACGroup: public RBACObject
+{
+ public:
+ RBACGroup(uint32 id = 0, std::string const& name = ""):
+ RBACObject(id, name) { }
+
+ /// Gets the Roles assigned to this group
+ RBACRoleContainer const& GetRoles() const { return _roles; }
+ /// Grants a Role (Adds)
+ void GrantRole(uint32 role);
+ /// Revokes a Role (Removes)
+ void RevokeRole(uint32 role);
+
+ private:
+ RBACRoleContainer _roles; ///> Set of Roles
+};
+
+/**
+ * @name RBACData
+ * @brief Contains all needed information about the acccount
+ *
+ * This class contains all the data needed to calculate the account permissions.
+ * RBACDAta is formed by group permissions and user permissions through:
+ * - Granted Groups, which contains roles, which contains permissions: Set of granted permissions
+ * - Granted Roles, which contains permissions: Set of granted permissions
+ * - Denied Roles, which contains permissions: Set of denied permissions
+ * - Granted Permissions
+ * - Denied Permissions
+ *
+ * Calculation of current Permissions: Granted permissions - Denied permissions
+ * - Granted permissions: through groups, through roles and directly assigned
+ * - Denied permissions: through roles and directly assigned
+ */
+class RBACData: public RBACObject
+{
+ public:
+ RBACData(uint32 id, std::string const& name, int32 realmId):
+ RBACObject(id, name), _realmId(realmId) { }
+
+ /**
+ * @name HasPermission
+ * @brief Checks if certain action is allowed
+ *
+ * Checks if certain action can be performed.
+ *
+ * @return grant or deny action
+ *
+ * Example Usage:
+ * @code
+ * bool Player::CanJoinArena(Battleground* bg)
+ * {
+ * return bg->isArena() && HasPermission(RBAC_PERM_JOIN_ARENA);
+ * }
+ * @endcode
+ */
+ bool HasPermission(uint32 permission) { return _globalPerms.test(permission); }
+
+ // Functions enabled to be used by command system
+ /// Returns all the granted permissions (after computation)
+ RBACPermissionContainer const& GetPermissions() const { return _globalPerms; }
+ /// Returns all the granted permissions
+ RBACPermissionContainer const& GetGrantedPermissions() const { return _grantedPerms; }
+ /// Returns all the denied permissions
+ RBACPermissionContainer const& GetDeniedPermissions() const { return _deniedPerms; }
+ /// Returns all the granted roles
+ RBACRoleContainer const& GetGrantedRoles() const { return _grantedRoles; }
+ /// Returns all the denied roles
+ RBACRoleContainer const& GetDeniedRoles() const { return _deniedRoles; }
+ /// Returns all the granted groups
+ RBACGroupContainer const& GetGroups() const { return _groups; }
+
+ /**
+ * @name AddGroup
+ * @brief Adds new group
+ *
+ * Add a new group to the account. If realm is 0 or the group can not be added
+ * No save to db action will be performed.
+ *
+ * Fails if group Id does not exists or group already present
+ *
+ * @param groupId group to be added
+ * @param realmId realm affected
+ *
+ * @return Success or failure (with reason) to add the group
+ *
+ * Example Usage:
+ * @code
+ * // previously defined "RBACData* rbac" with proper initialization
+ * uint32 groupId = 2;
+ * if (rbac->AddGroup(groupId) == RBAC_OK)
+ * sLog->outDebug(LOG_FILTER_PLAYER, "Group %u succesfully added", groupId);
+ * @endcode
+ */
+ RBACCommandResult AddGroup(uint32 groupId, int32 realmId = 0);
+
+ /**
+ * @name RemoveGroup
+ * @brief Removes a group
+ *
+ * Removes a group from the account. If realm is 0 or the group can not be removed
+ * No save to db action will be performed. Any delete operation will always affect
+ * "all realms (-1)" in addition to the realm specified
+ *
+ * Fails if group not present
+ *
+ * @param groupId group to be removed
+ * @param realmId realm affected
+ *
+ * @return Success or failure (with reason) to remove the group
+ *
+ * Example Usage:
+ * // previously defined "RBACData* rbac" with proper initialization
+ * uint32 groupId = 2;
+ * if (rbac->RemoveGroup(groupId) == RBAC_OK)
+ * sLog->outDebug(LOG_FILTER_PLAYER, "Group %u succesfully removed", groupId);
+ * @endcode
+ */
+ RBACCommandResult RemoveGroup(uint32 groupId, int32 realmId = 0);
+
+ /**
+ * @name GrantRole
+ * @brief Grants a role
+ *
+ * Grants a role to the account. If realm is 0 or the role can not be added
+ * No save to db action will be performed.
+ *
+ * Fails if role Id does not exists or role already granted or denied
+ *
+ * @param roleId role to be granted
+ * @param realmId realm affected
+ *
+ * @return Success or failure (with reason) to grant the role
+ *
+ * Example Usage:
+ * // previously defined "RBACData* rbac" with proper initialization
+ * uint32 roleId = 2;
+ * if (rbac->GrantRole(roleId) == RBAC_IN_DENIED_LIST)
+ * sLog->outDebug(LOG_FILTER_PLAYER, "Failed to grant role %u, already denied", roleId);
+ * @endcode
+ */
+ RBACCommandResult GrantRole(uint32 roleId, int32 realmId = 0);
+
+ /**
+ * @name DenyRole
+ * @brief Denies a role
+ *
+ * Denied a role to the account. If realm is 0 or the role can not be added
+ * No save to db action will be performed.
+ *
+ * Fails if role Id does not exists or role already granted or denied
+ *
+ * @param roleId role to be denied
+ * @param realmId realm affected
+ *
+ * @return Success or failure (with reason) to deny the role
+ *
+ * Example Usage:
+ * // previously defined "RBACData* rbac" with proper initialization
+ * uint32 roleId = 2;
+ * if (rbac->DenyRole(roleId) == RBAC_ID_DOES_NOT_EXISTS)
+ * sLog->outDebug(LOG_FILTER_PLAYER, "Role Id %u does not exists", roleId);
+ * @endcode
+ */
+ RBACCommandResult DenyRole(uint32 roleId, int32 realmId = 0);
+
+ /**
+ * @name RevokeRole
+ * @brief Removes a role
+ *
+ * Removes a role from the account. If realm is 0 or the role can not be removed
+ * No save to db action will be performed. Any delete operation will always affect
+ * "all realms (-1)" in addition to the realm specified
+ *
+ * Fails if role not present
+ *
+ * @param roleId role to be removed
+ * @param realmId realm affected
+ *
+ * @return Success or failure (with reason) to remove the role
+ *
+ * Example Usage:
+ * // previously defined "RBACData* rbac" with proper initialization
+ * uint32 roleId = 2;
+ * if (rbac->RevokeRole(roleId) == RBAC_OK)
+ * sLog->outDebug(LOG_FILTER_PLAYER, "Role %u succesfully removed", roleId);
+ * @endcode
+ */
+ RBACCommandResult RevokeRole(uint32 roleId, int32 realmId = 0);
+
+ /**
+ * @name GrantRole
+ * @brief Grants a permission
+ *
+ * Grants a permission to the account. If realm is 0 or the permission can not be added
+ * No save to db action will be performed.
+ *
+ * Fails if permission Id does not exists or permission already granted or denied
+ *
+ * @param permissionId permission to be granted
+ * @param realmId realm affected
+ *
+ * @return Success or failure (with reason) to grant the permission
+ *
+ * Example Usage:
+ * // previously defined "RBACData* rbac" with proper initialization
+ * uint32 permissionId = 2;
+ * if (rbac->GrantRole(permissionId) == RBAC_IN_DENIED_LIST)
+ * sLog->outDebug(LOG_FILTER_PLAYER, "Failed to grant permission %u, already denied", permissionId);
+ * @endcode
+ */
+ RBACCommandResult GrantPermission(uint32 permissionId, int32 realmId = 0);
+
+ /**
+ * @name DenyPermission
+ * @brief Denies a permission
+ *
+ * Denied a permission to the account. If realm is 0 or the permission can not be added
+ * No save to db action will be performed.
+ *
+ * Fails if permission Id does not exists or permission already granted or denied
+ *
+ * @param permissionId permission to be denied
+ * @param realmId realm affected
+ *
+ * @return Success or failure (with reason) to deny the permission
+ *
+ * Example Usage:
+ * // previously defined "RBACData* rbac" with proper initialization
+ * uint32 permissionId = 2;
+ * if (rbac->DenyRole(permissionId) == RBAC_ID_DOES_NOT_EXISTS)
+ * sLog->outDebug(LOG_FILTER_PLAYER, "Role Id %u does not exists", permissionId);
+ * @endcode
+ */
+ RBACCommandResult DenyPermission(uint32 permissionId, int32 realmId = 0);
+
+ /**
+ * @name RevokePermission
+ * @brief Removes a permission
+ *
+ * Removes a permission from the account. If realm is 0 or the permission can not be removed
+ * No save to db action will be performed. Any delete operation will always affect
+ * "all realms (-1)" in addition to the realm specified
+ *
+ * Fails if permission not present
+ *
+ * @param permissionId permission to be removed
+ * @param realmId realm affected
+ *
+ * @return Success or failure (with reason) to remove the permission
+ *
+ * Example Usage:
+ * // previously defined "RBACData* rbac" with proper initialization
+ * uint32 permissionId = 2;
+ * if (rbac->RevokeRole(permissionId) == RBAC_OK)
+ * sLog->outDebug(LOG_FILTER_PLAYER, "Permission %u succesfully removed", permissionId);
+ * @endcode
+ */
+ RBACCommandResult RevokePermission(uint32 permissionId, int32 realmId = 0);
+
+ /// Loads all permissions, groups and roles assigned to current account
+ void LoadFromDB();
+ private:
+ /// Saves a role to DB, Granted or Denied
+ void SaveRole(uint32 role, bool granted, int32 realm);
+ /// Saves a permission to DB, Granted or Denied
+ void SavePermission(uint32 role, bool granted, int32 realm);
+
+ /**
+ * @name CalculateNewPermissions
+ * @brief Calculates new permissions
+ *
+ * Calculates new permissions after some change in groups, roles or permissions.
+ * The calculation is done Granted - Denied:
+ * - Granted permissions: through groups, through roles and directly assigned
+ * - Denied permissions: through roles and directly assigned
+ */
+ void CalculateNewPermissions();
+
+ int32 GetRealmId() { return _realmId; }
+
+ int32 _realmId; ///> RealmId Affected
+ RBACGroupContainer _groups; ///> Granted groups
+ RBACRoleContainer _grantedRoles; ///> Granted roles
+ RBACRoleContainer _deniedRoles; ///> Denied roles
+ RBACPermissionContainer _grantedPerms; ///> Granted permissions
+ RBACPermissionContainer _deniedPerms; ///> Denied permissions
+ RBACPermissionContainer _globalPerms; ///> Calculated permissions
+};
+
+#endif
diff --git a/src/server/game/Achievements/AchievementMgr.cpp b/src/server/game/Achievements/AchievementMgr.cpp index 2fd55ac29ef..41748248025 100644 --- a/src/server/game/Achievements/AchievementMgr.cpp +++ b/src/server/game/Achievements/AchievementMgr.cpp @@ -2048,7 +2048,7 @@ void AchievementMgr::CompletedAchievement(AchievementEntry const* achievement) ca.changed = true; // don't insert for ACHIEVEMENT_FLAG_REALM_FIRST_KILL since otherwise only the first group member would reach that achievement - // TODO: where do set this instead? + /// @todo where do set this instead? if (!(achievement->flags & ACHIEVEMENT_FLAG_REALM_FIRST_KILL)) sAchievementMgr->SetRealmCompleted(achievement); @@ -2209,6 +2209,7 @@ void AchievementGlobalMgr::LoadAchievementCriteriaList() return; } + uint32 loaded = 0; for (uint32 entryId = 0; entryId < sAchievementCriteriaStore.GetNumRows(); ++entryId) { AchievementCriteriaEntry const* criteria = sAchievementMgr->GetAchievementCriteria(entryId); @@ -2220,9 +2221,11 @@ void AchievementGlobalMgr::LoadAchievementCriteriaList() if (criteria->timeLimit) m_AchievementCriteriasByTimedType[criteria->timedType].push_back(criteria); + + ++loaded; } - sLog->outInfo(LOG_FILTER_SERVER_LOADING, ">> Loaded %lu achievement criteria in %u ms", (unsigned long)m_AchievementCriteriasByType->size(), GetMSTimeDiffToNow(oldMSTime)); + sLog->outInfo(LOG_FILTER_SERVER_LOADING, ">> Loaded %u achievement criteria in %u ms", loaded, GetMSTimeDiffToNow(oldMSTime)); } void AchievementGlobalMgr::LoadAchievementReferenceList() @@ -2284,14 +2287,14 @@ void AchievementGlobalMgr::LoadAchievementCriteriaData() } uint32 dataType = fields[1].GetUInt8(); - const char* scriptName = fields[4].GetCString(); + std::string scriptName = fields[4].GetString(); uint32 scriptId = 0; - if (strcmp(scriptName, "")) // not empty + if (scriptName.length()) // not empty { if (dataType != ACHIEVEMENT_CRITERIA_DATA_TYPE_SCRIPT) sLog->outError(LOG_FILTER_SQL, "Table `achievement_criteria_data` has ScriptName set for non-scripted data type (Entry: %u, type %u), useless data.", criteria_id, dataType); else - scriptId = sObjectMgr->GetScriptId(scriptName); + scriptId = sObjectMgr->GetScriptId(scriptName.c_str()); } AchievementCriteriaData data(dataType, fields[2].GetUInt32(), fields[3].GetUInt32(), scriptId); diff --git a/src/server/game/AuctionHouse/AuctionHouseMgr.cpp b/src/server/game/AuctionHouse/AuctionHouseMgr.cpp index 71c44408f72..4c80d268c12 100644 --- a/src/server/game/AuctionHouse/AuctionHouseMgr.cpp +++ b/src/server/game/AuctionHouse/AuctionHouseMgr.cpp @@ -52,13 +52,13 @@ AuctionHouseObject* AuctionHouseMgr::GetAuctionsMap(uint32 factionTemplateId) if (sWorld->getBoolConfig(CONFIG_ALLOW_TWO_SIDE_INTERACTION_AUCTION)) return &mNeutralAuctions; - // team have linked auction houses - FactionTemplateEntry const* u_entry = sFactionTemplateStore.LookupEntry(factionTemplateId); - if (!u_entry) + // teams have linked auction houses + FactionTemplateEntry const* uEntry = sFactionTemplateStore.LookupEntry(factionTemplateId); + if (!uEntry) return &mNeutralAuctions; - else if (u_entry->ourMask & FACTION_MASK_ALLIANCE) + else if (uEntry->ourMask & FACTION_MASK_ALLIANCE) return &mAllianceAuctions; - else if (u_entry->ourMask & FACTION_MASK_HORDE) + else if (uEntry->ourMask & FACTION_MASK_HORDE) return &mHordeAuctions; else return &mNeutralAuctions; @@ -93,46 +93,42 @@ void AuctionHouseMgr::SendAuctionWonMail(AuctionEntry* auction, SQLTransaction& if (!pItem) return; - uint32 bidder_accId = 0; - uint64 bidder_guid = MAKE_NEW_GUID(auction->bidder, 0, HIGHGUID_PLAYER); - Player* bidder = ObjectAccessor::FindPlayer(bidder_guid); + uint32 bidderAccId = 0; + uint64 bidderGuid = MAKE_NEW_GUID(auction->bidder, 0, HIGHGUID_PLAYER); + Player* bidder = ObjectAccessor::FindPlayer(bidderGuid); // data for gm.log - if (sWorld->getBoolConfig(CONFIG_GM_LOG_TRADE)) + std::string bidderName; + bool logGmTrade = false; + + if (bidder) { - uint32 bidder_security = 0; - std::string bidder_name; - if (bidder) - { - bidder_accId = bidder->GetSession()->GetAccountId(); - bidder_security = bidder->GetSession()->GetSecurity(); - bidder_name = bidder->GetName(); - } - else - { - bidder_accId = sObjectMgr->GetPlayerAccountIdByGUID(bidder_guid); - bidder_security = AccountMgr::GetSecurity(bidder_accId, realmID); + bidderAccId = bidder->GetSession()->GetAccountId(); + bidderName = bidder->GetName(); + logGmTrade = bidder->GetSession()->HasPermission(RBAC_PERM_LOG_GM_TRADE); + } + else + { + bidderAccId = sObjectMgr->GetPlayerAccountIdByGUID(bidderGuid); + logGmTrade = AccountMgr::HasPermission(bidderAccId, RBAC_PERM_LOG_GM_TRADE, realmID); - if (!AccountMgr::IsPlayerAccount(bidder_security)) // not do redundant DB requests - { - if (!sObjectMgr->GetPlayerNameByGUID(bidder_guid, bidder_name)) - bidder_name = sObjectMgr->GetTrinityStringForDBCLocale(LANG_UNKNOWN); - } - } - if (!AccountMgr::IsPlayerAccount(bidder_security)) - { - std::string owner_name; - if (!sObjectMgr->GetPlayerNameByGUID(auction->owner, owner_name)) - owner_name = sObjectMgr->GetTrinityStringForDBCLocale(LANG_UNKNOWN); + if (logGmTrade && !sObjectMgr->GetPlayerNameByGUID(bidderGuid, bidderName)) + bidderName = sObjectMgr->GetTrinityStringForDBCLocale(LANG_UNKNOWN); + } - uint32 owner_accid = sObjectMgr->GetPlayerAccountIdByGUID(auction->owner); + if (logGmTrade) + { + std::string ownerName; + if (!sObjectMgr->GetPlayerNameByGUID(auction->owner, ownerName)) + ownerName = sObjectMgr->GetTrinityStringForDBCLocale(LANG_UNKNOWN); - sLog->outCommand(bidder_accId, "GM %s (Account: %u) won item in auction: %s (Entry: %u Count: %u) and pay money: %u. Original owner %s (Account: %u)", - bidder_name.c_str(), bidder_accId, pItem->GetTemplate()->Name1.c_str(), pItem->GetEntry(), pItem->GetCount(), auction->bid, owner_name.c_str(), owner_accid); - } + uint32 ownerAccId = sObjectMgr->GetPlayerAccountIdByGUID(auction->owner); + + sLog->outCommand(bidderAccId, "GM %s (Account: %u) won item in auction: %s (Entry: %u Count: %u) and pay money: %u. Original owner %s (Account: %u)", + bidderName.c_str(), bidderAccId, pItem->GetTemplate()->Name1.c_str(), pItem->GetEntry(), pItem->GetCount(), auction->bid, ownerName.c_str(), ownerAccId); } // receiver exist - if (bidder || bidder_accId) + if (bidder || bidderAccId) { // set owner to bidder (to prevent delete item with sender char deleting) // owner in `data` will set at mail receive and item extracting @@ -143,7 +139,7 @@ void AuctionHouseMgr::SendAuctionWonMail(AuctionEntry* auction, SQLTransaction& if (bidder) { - bidder->GetSession()->SendAuctionBidderNotification(auction->GetHouseId(), auction->Id, bidder_guid, 0, 0, auction->itemEntry); + bidder->GetSession()->SendAuctionBidderNotification(auction->GetHouseId(), auction->Id, bidderGuid, 0, 0, auction->itemEntry); // FIXME: for offline player need also bidder->UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_WON_AUCTIONS, 1); } @@ -330,7 +326,7 @@ void AuctionHouseMgr::LoadAuctions() } GetAuctionsMap(aItem->factionTemplateId)->AddAuction(aItem); - count++; + ++count; } while (result->NextRow()); CharacterDatabase.CommitTransaction(trans); @@ -369,7 +365,7 @@ AuctionHouseEntry const* AuctionHouseMgr::GetAuctionHouseEntry(uint32 factionTem if (!sWorld->getBoolConfig(CONFIG_ALLOW_TWO_SIDE_INTERACTION_AUCTION)) { - //FIXME: found way for proper auctionhouse selection by another way + // FIXME: found way for proper auctionhouse selection by another way // AuctionHouse.dbc have faction field with _player_ factions associated with auction house races. // but no easy way convert creature faction to player race faction for specific city switch (factionTemplateId) @@ -781,7 +777,8 @@ void AuctionHouseMgr::DeleteExpiredAuctionsAtStartup() delete auction; ++expirecount; - } while (expAuctions->NextRow()); + } + while (expAuctions->NextRow()); sLog->outInfo(LOG_FILTER_SERVER_LOADING, ">> Deleted %u expired auctions in %u ms", expirecount, GetMSTimeDiffToNow(oldMSTime)); diff --git a/src/server/game/AuctionHouse/AuctionHouseMgr.h b/src/server/game/AuctionHouse/AuctionHouseMgr.h index eb35dc494ee..e0e972c5d40 100644 --- a/src/server/game/AuctionHouse/AuctionHouseMgr.h +++ b/src/server/game/AuctionHouse/AuctionHouseMgr.h @@ -95,8 +95,6 @@ struct AuctionEntry class AuctionHouseObject { public: - // Initialize storage - AuctionHouseObject() { next = AuctionsMap.begin(); } ~AuctionHouseObject() { for (AuctionEntryMap::iterator itr = AuctionsMap.begin(); itr != AuctionsMap.end(); ++itr) @@ -131,9 +129,6 @@ class AuctionHouseObject private: AuctionEntryMap AuctionsMap; - - // storage for "next" auction item for next Update() - AuctionEntryMap::const_iterator next; }; class AuctionHouseMgr diff --git a/src/server/game/Battlefield/Battlefield.cpp b/src/server/game/Battlefield/Battlefield.cpp index 32f71822737..685cb4937a7 100644 --- a/src/server/game/Battlefield/Battlefield.cpp +++ b/src/server/game/Battlefield/Battlefield.cpp @@ -65,8 +65,6 @@ Battlefield::~Battlefield() for (GraveyardVect::const_iterator itr = m_GraveyardList.begin(); itr != m_GraveyardList.end(); ++itr) delete *itr; - - m_capturePoints.clear(); } // Called when a player enters the zone @@ -81,7 +79,7 @@ void Battlefield::HandlePlayerEnterZone(Player* player, uint32 /*zone*/) InvitePlayerToWar(player); else // No more vacant places { - // TODO: Send a packet to announce it to player + /// @todo Send a packet to announce it to player m_PlayersWillBeKick[player->GetTeamId()][player->GetGUID()] = time(NULL) + 10; InvitePlayerToQueue(player); } @@ -161,16 +159,17 @@ bool Battlefield::Update(uint32 diff) // Kick players who chose not to accept invitation to the battle if (m_uiKickDontAcceptTimer <= diff) { + time_t now = time(NULL); for (int team = 0; team < 2; team++) for (PlayerTimerMap::iterator itr = m_InvitedPlayers[team].begin(); itr != m_InvitedPlayers[team].end(); ++itr) - if ((*itr).second <= time(NULL)) - KickPlayerFromBattlefield((*itr).first); + if (itr->second <= now) + KickPlayerFromBattlefield(itr->first); InvitePlayersInZoneToWar(); for (int team = 0; team < 2; team++) for (PlayerTimerMap::iterator itr = m_PlayersWillBeKick[team].begin(); itr != m_PlayersWillBeKick[team].end(); ++itr) - if ((*itr).second <= time(NULL)) - KickPlayerFromBattlefield((*itr).first); + if (itr->second <= now) + KickPlayerFromBattlefield(itr->first); m_uiKickDontAcceptTimer = 1000; } @@ -255,7 +254,7 @@ void Battlefield::InvitePlayerToWar(Player* player) if (!player) return; - // TODO : needed ? + /// @todo needed ? if (player->isInFlight()) return; @@ -469,13 +468,13 @@ void Battlefield::SendWarningToAllInZone(uint32 entry) sCreatureTextMgr->SendChat(stalker, (uint8) entry, 0, CHAT_MSG_BG_SYSTEM_NEUTRAL, LANG_ADDON, TEXT_RANGE_ZONE); } -/*void Battlefield::SendWarningToAllInWar(int32 entry,...) +/*void Battlefield::SendWarningToAllInWar(int32 entry, ...) { const char *format = sObjectMgr->GetTrinityStringForDBCLocale(entry); va_list ap; char str [1024]; va_start(ap, entry); - vsnprintf(str,1024,format, ap); + vsnprintf(str, 1024, format, ap); va_end(ap); std::string msg = (std::string)str; @@ -604,7 +603,7 @@ BfGraveyard* Battlefield::GetGraveyardById(uint32 id) const return NULL; } -WorldSafeLocsEntry const * Battlefield::GetClosestGraveYard(Player* player) +WorldSafeLocsEntry const* Battlefield::GetClosestGraveYard(Player* player) { BfGraveyard* closestGY = NULL; float maxdist = -1; @@ -680,7 +679,6 @@ BfGraveyard::BfGraveyard(Battlefield* battlefield) m_ControlTeam = TEAM_NEUTRAL; m_SpiritGuide[0] = 0; m_SpiritGuide[1] = 0; - m_ResurrectQueue.clear(); } void BfGraveyard::Initialize(TeamId startControl, uint32 graveyardId) @@ -816,7 +814,7 @@ Creature* Battlefield::SpawnCreature(uint32 entry, Position pos, TeamId team) Creature* Battlefield::SpawnCreature(uint32 entry, float x, float y, float z, float o, TeamId team) { //Get map object - Map* map = const_cast < Map * >(sMapMgr->CreateBaseMap(m_MapId)); + Map* map = sMapMgr->CreateBaseMap(m_MapId); if (!map) { sLog->outError(LOG_FILTER_BATTLEFIELD, "Battlefield::SpawnCreature: Can't create creature entry: %u map not found", entry); @@ -854,7 +852,7 @@ Creature* Battlefield::SpawnCreature(uint32 entry, float x, float y, float z, fl GameObject* Battlefield::SpawnGameObject(uint32 entry, float x, float y, float z, float o) { // Get map object - Map* map = const_cast<Map*>(sMapMgr->CreateBaseMap(571)); // *vomits* + Map* map = sMapMgr->CreateBaseMap(571); // *vomits* if (!map) return 0; diff --git a/src/server/game/Battlefield/Battlefield.h b/src/server/game/Battlefield/Battlefield.h index 0da776b9624..534bfd620f0 100644 --- a/src/server/game/Battlefield/Battlefield.h +++ b/src/server/game/Battlefield/Battlefield.h @@ -71,7 +71,7 @@ class BfGraveyard; typedef std::set<uint64> GuidSet; typedef std::vector<BfGraveyard*> GraveyardVect; -typedef std::map<uint64, uint32> PlayerTimerMap; +typedef std::map<uint64, time_t> PlayerTimerMap; class BfCapturePoint { @@ -277,7 +277,7 @@ class Battlefield : public ZoneScript // Graveyard methods // Find which graveyard the player must be teleported to to be resurrected by spiritguide - WorldSafeLocsEntry const * GetClosestGraveYard(Player* player); + WorldSafeLocsEntry const* GetClosestGraveYard(Player* player); virtual void AddPlayerToResurrectQueue(uint64 npc_guid, uint64 player_guid); void RemovePlayerFromResurrectQueue(uint64 player_guid); diff --git a/src/server/game/Battlefield/BattlefieldMgr.cpp b/src/server/game/Battlefield/BattlefieldMgr.cpp index 5aec0458b19..d30a0b17fd7 100644 --- a/src/server/game/Battlefield/BattlefieldMgr.cpp +++ b/src/server/game/Battlefield/BattlefieldMgr.cpp @@ -51,7 +51,7 @@ void BattlefieldMgr::InitBattlefield() /* For Cataclysm: Tol Barad pBf = new BattlefieldTB; // respawn, init variables - if(!pBf->SetupBattlefield()) + if (!pBf->SetupBattlefield()) { sLog->outDebug(LOG_FILTER_BATTLEFIELD, "Battlefield : Tol Barad init failed."); delete pBf; @@ -68,7 +68,7 @@ void BattlefieldMgr::AddZone(uint32 zoneid, Battlefield *handle) m_BattlefieldMap[zoneid] = handle; } -void BattlefieldMgr::HandlePlayerEnterZone(Player * player, uint32 zoneid) +void BattlefieldMgr::HandlePlayerEnterZone(Player* player, uint32 zoneid) { BattlefieldMap::iterator itr = m_BattlefieldMap.find(zoneid); if (itr == m_BattlefieldMap.end()) @@ -81,7 +81,7 @@ void BattlefieldMgr::HandlePlayerEnterZone(Player * player, uint32 zoneid) sLog->outDebug(LOG_FILTER_BATTLEFIELD, "Player %u entered outdoorpvp id %u", player->GetGUIDLow(), itr->second->GetTypeId()); } -void BattlefieldMgr::HandlePlayerLeaveZone(Player * player, uint32 zoneid) +void BattlefieldMgr::HandlePlayerLeaveZone(Player* player, uint32 zoneid) { BattlefieldMap::iterator itr = m_BattlefieldMap.find(zoneid); if (itr == m_BattlefieldMap.end()) @@ -129,7 +129,7 @@ void BattlefieldMgr::Update(uint32 diff) } } -ZoneScript *BattlefieldMgr::GetZoneScript(uint32 zoneId) +ZoneScript* BattlefieldMgr::GetZoneScript(uint32 zoneId) { BattlefieldMap::iterator itr = m_BattlefieldMap.find(zoneId); if (itr != m_BattlefieldMap.end()) diff --git a/src/server/game/Battlefield/BattlefieldMgr.h b/src/server/game/Battlefield/BattlefieldMgr.h index 28b2a3c148a..af1cea763df 100644 --- a/src/server/game/Battlefield/BattlefieldMgr.h +++ b/src/server/game/Battlefield/BattlefieldMgr.h @@ -39,11 +39,11 @@ class BattlefieldMgr // create battlefield events void InitBattlefield(); // called when a player enters an battlefield area - void HandlePlayerEnterZone(Player * player, uint32 areaflag); + void HandlePlayerEnterZone(Player* player, uint32 areaflag); // called when player leaves an battlefield area - void HandlePlayerLeaveZone(Player * player, uint32 areaflag); + void HandlePlayerLeaveZone(Player* player, uint32 areaflag); // called when player resurrects - void HandlePlayerResurrects(Player * player, uint32 areaflag); + void HandlePlayerResurrects(Player* player, uint32 areaflag); // return assigned battlefield Battlefield* GetBattlefieldToZoneId(uint32 zoneid); Battlefield* GetBattlefieldByBattleId(uint32 battleid); @@ -54,14 +54,14 @@ class BattlefieldMgr void Update(uint32 diff); - void HandleGossipOption(Player * player, uint64 guid, uint32 gossipid); + void HandleGossipOption(Player* player, uint64 guid, uint32 gossipid); - bool CanTalkTo(Player * player, Creature * creature, GossipMenuItems gso); + bool CanTalkTo(Player* player, Creature* creature, GossipMenuItems gso); - void HandleDropFlag(Player * player, uint32 spellId); + void HandleDropFlag(Player* player, uint32 spellId); typedef std::vector < Battlefield * >BattlefieldSet; - typedef std::map < uint32 /* zoneid */ , Battlefield * >BattlefieldMap; + typedef std::map < uint32 /* zoneid */, Battlefield * >BattlefieldMap; private: // contains all initiated battlefield events // used when initing / cleaning up diff --git a/src/server/game/Battlefield/Zones/BattlefieldWG.cpp b/src/server/game/Battlefield/Zones/BattlefieldWG.cpp index a36d204a4b7..4f481f36716 100644 --- a/src/server/game/Battlefield/Zones/BattlefieldWG.cpp +++ b/src/server/game/Battlefield/Zones/BattlefieldWG.cpp @@ -15,9 +15,9 @@ * with this program. If not, see <http://www.gnu.org/licenses/>. */ -// TODO: Implement proper support for vehicle+player teleportation -// TODO: Use spell victory/defeat in wg instead of RewardMarkOfHonor() && RewardHonor -// TODO: Add proper implement of achievement +/// @todo Implement proper support for vehicle+player teleportation +/// @todo Use spell victory/defeat in wg instead of RewardMarkOfHonor() && RewardHonor +/// @todo Add proper implement of achievement #include "BattlefieldWG.h" #include "AchievementMgr.h" @@ -397,7 +397,7 @@ void BattlefieldWG::OnBattleEnd(bool endByTimer) for (GuidSet::const_iterator itr = m_vehicles[team].begin(); itr != m_vehicles[team].end(); ++itr) if (Creature* creature = GetCreature(*itr)) if (creature->IsVehicle()) - creature->GetVehicleKit()->Dismiss(); + creature->DespawnOrUnsummon(); m_vehicles[team].clear(); } @@ -658,7 +658,7 @@ void BattlefieldWG::HandleKill(Player* killer, Unit* victim) } } } - // TODO:Recent PvP activity worldstate + /// @todoRecent PvP activity worldstate } bool BattlefieldWG::FindAndRemoveVehicleFromList(Unit* vehicle) @@ -764,11 +764,12 @@ void BattlefieldWG::OnPlayerJoinWar(Player* player) void BattlefieldWG::OnPlayerLeaveWar(Player* player) { - // Remove all aura from WG // TODO: false we can go out of this zone on retail and keep Rank buff, remove on end of WG + // Remove all aura from WG /// @todo false we can go out of this zone on retail and keep Rank buff, remove on end of WG if (!player->GetSession()->PlayerLogout()) { - if (player->GetVehicle()) // Remove vehicle of player if he go out. - player->GetVehicle()->Dismiss(); + if (Creature* vehicle = player->GetVehicleCreatureBase()) // Remove vehicle of player if he go out. + vehicle->DespawnOrUnsummon(); + RemoveAurasFromPlayer(player); } @@ -916,7 +917,7 @@ void BattlefieldWG::UpdatedDestroyedTowerCount(TeamId team) } } -void BattlefieldWG::ProcessEvent(WorldObject *obj, uint32 eventId) +void BattlefieldWG::ProcessEvent(WorldObject* obj, uint32 eventId) { if (!obj || !IsWarTime()) return; diff --git a/src/server/game/Battlefield/Zones/BattlefieldWG.h b/src/server/game/Battlefield/Zones/BattlefieldWG.h index f313357e323..fcd000e75af 100644 --- a/src/server/game/Battlefield/Zones/BattlefieldWG.h +++ b/src/server/game/Battlefield/Zones/BattlefieldWG.h @@ -102,21 +102,21 @@ enum WintergraspData enum WintergraspAchievements { ACHIEVEMENTS_WIN_WG = 1717, - ACHIEVEMENTS_WIN_WG_100 = 1718, // todo - ACHIEVEMENTS_WG_GNOMESLAUGHTER = 1723, // todo + ACHIEVEMENTS_WIN_WG_100 = 1718, /// @todo: Has to be implemented + ACHIEVEMENTS_WG_GNOMESLAUGHTER = 1723, /// @todo: Has to be implemented ACHIEVEMENTS_WG_TOWER_DESTROY = 1727, - ACHIEVEMENTS_DESTRUCTION_DERBY_A = 1737, // todo - ACHIEVEMENTS_WG_TOWER_CANNON_KILL = 1751, // todo - ACHIEVEMENTS_WG_MASTER_A = 1752, // todo + ACHIEVEMENTS_DESTRUCTION_DERBY_A = 1737, /// @todo: Has to be implemented + ACHIEVEMENTS_WG_TOWER_CANNON_KILL = 1751, /// @todo: Has to be implemented + ACHIEVEMENTS_WG_MASTER_A = 1752, /// @todo: Has to be implemented ACHIEVEMENTS_WIN_WG_TIMER_10 = 1755, - ACHIEVEMENTS_STONE_KEEPER_50 = 2085, // todo - ACHIEVEMENTS_STONE_KEEPER_100 = 2086, // todo - ACHIEVEMENTS_STONE_KEEPER_250 = 2087, // todo - ACHIEVEMENTS_STONE_KEEPER_500 = 2088, // todo - ACHIEVEMENTS_STONE_KEEPER_1000 = 2089, // todo - ACHIEVEMENTS_WG_RANGER = 2199, // todo - ACHIEVEMENTS_DESTRUCTION_DERBY_H = 2476, // todo - ACHIEVEMENTS_WG_MASTER_H = 2776 // todo + ACHIEVEMENTS_STONE_KEEPER_50 = 2085, /// @todo: Has to be implemented + ACHIEVEMENTS_STONE_KEEPER_100 = 2086, /// @todo: Has to be implemented + ACHIEVEMENTS_STONE_KEEPER_250 = 2087, /// @todo: Has to be implemented + ACHIEVEMENTS_STONE_KEEPER_500 = 2088, /// @todo: Has to be implemented + ACHIEVEMENTS_STONE_KEEPER_1000 = 2089, /// @todo: Has to be implemented + ACHIEVEMENTS_WG_RANGER = 2199, /// @todo: Has to be implemented + ACHIEVEMENTS_DESTRUCTION_DERBY_H = 2476, /// @todo: Has to be implemented + ACHIEVEMENTS_WG_MASTER_H = 2776 /// @todo: Has to be implemented }; enum WintergraspWorldStates @@ -405,7 +405,7 @@ class BattlefieldWG : public Battlefield void PromotePlayer(Player* killer); void UpdateTenacity(); - void ProcessEvent(WorldObject *obj, uint32 eventId); + void ProcessEvent(WorldObject* obj, uint32 eventId); bool FindAndRemoveVehicleFromList(Unit* vehicle); @@ -499,7 +499,7 @@ enum WintergraspTeamControl BATTLEFIELD_WG_TEAM_NEUTRAL }; -// TODO: Handle this with creature_text ? +/// @todo: Can this be handled with creature_text or SmartAI ? enum WintergraspText { BATTLEFIELD_WG_TEXT_WORKSHOP_NAME_NE = 12055, @@ -562,7 +562,7 @@ struct WintergraspObjectPositionData }; // ***************************************************** -// ************ Destructible (Wall,Tower..) ************ +// ************ Destructible (Wall, Tower..) *********** // ***************************************************** struct WintergraspBuildingSpawnData @@ -755,7 +755,7 @@ const WintergraspTeleporterData WGPortalDefenderData[WG_MAX_TELEPORTER] = }; // ********************************************************* -// **********Tower Element(GameObject,Creature)************* +// **********Tower Element(GameObject, Creature)************ // ********************************************************* struct WintergraspTowerData @@ -764,7 +764,7 @@ struct WintergraspTowerData uint8 nbObject; // Number of gameobjects spawned on this point WintergraspObjectPositionData GameObject[6]; // Gameobject position and entry (Horde/Alliance) - // Creature : Turrets and Guard, TODO: check if killed on tower destruction? tower damage? + // Creature: Turrets and Guard /// @todo: Killed on Tower destruction ? Tower damage ? Requires confirming uint8 nbCreatureBottom; WintergraspObjectPositionData CreatureBottom[9]; uint8 nbCreatureTop; @@ -1055,7 +1055,7 @@ const WGWorkshopData WorkshopsData[WG_MAX_WORKSHOP] = }; // ******************************************************************** -// * Structs using for Building,Graveyard,Workshop * +// * Structs using for Building, Graveyard, Workshop * // ******************************************************************** // Structure for different buildings that can be destroyed during battle struct BfWGGameObjectBuilding diff --git a/src/server/game/Battlegrounds/ArenaTeam.cpp b/src/server/game/Battlegrounds/ArenaTeam.cpp index 1b0955fb670..f8de9c58232 100644 --- a/src/server/game/Battlegrounds/ArenaTeam.cpp +++ b/src/server/game/Battlegrounds/ArenaTeam.cpp @@ -652,7 +652,7 @@ int32 ArenaTeam::GetRatingMod(uint32 ownRating, uint32 opponentRating, bool won // Calculate the rating modification float mod; - // TODO: Replace this hack with using the confidence factor (limiting the factor to 2.0f) + /// @todo Replace this hack with using the confidence factor (limiting the factor to 2.0f) if (won && ownRating < 1300) { if (ownRating < 1000) diff --git a/src/server/game/Battlegrounds/Battleground.cpp b/src/server/game/Battlegrounds/Battleground.cpp index 52183b9509d..5828789e77b 100644 --- a/src/server/game/Battlegrounds/Battleground.cpp +++ b/src/server/game/Battlegrounds/Battleground.cpp @@ -270,7 +270,7 @@ void Battleground::Update(uint32 diff) // after 47 minutes without one team losing, the arena closes with no winner and no rating change if (isArena()) { - if (GetStartTime() >= 47*MINUTE*IN_MILLISECONDS) + if (GetStartTime() >= 47 * MINUTE*IN_MILLISECONDS) { UpdateArenaWorldState(); CheckArenaAfterTimerConditions(); @@ -515,7 +515,7 @@ inline void Battleground::_ProcessJoin(uint32 diff) // Remove preparation if (isArena()) { - // TODO : add arena sound PlaySoundToAll(SOUND_ARENA_START); + /// @todo add arena sound PlaySoundToAll(SOUND_ARENA_START); for (BattlegroundPlayerMap::const_iterator itr = GetPlayers().begin(); itr != GetPlayers().end(); ++itr) if (Player* player = ObjectAccessor::FindPlayer(itr->first)) { @@ -523,7 +523,7 @@ inline void Battleground::_ProcessJoin(uint32 diff) WorldPacket status; BattlegroundQueueTypeId bgQueueTypeId = sBattlegroundMgr->BGQueueTypeId(m_TypeID, GetArenaType()); uint32 queueSlot = player->GetBattlegroundQueueIndex(bgQueueTypeId); - sBattlegroundMgr->BuildBattlegroundStatusPacket(&status, this, queueSlot, STATUS_IN_PROGRESS, 0, GetStartTime(), GetArenaType()); + sBattlegroundMgr->BuildBattlegroundStatusPacket(&status, this, queueSlot, STATUS_IN_PROGRESS, 0, GetStartTime(), GetArenaType(), player->GetBGTeam()); player->GetSession()->SendPacket(&status); player->RemoveAurasDueToSpell(SPELL_ARENA_PREPARATION); @@ -919,7 +919,7 @@ void Battleground::EndBattleground(uint32 winner) player->GetSession()->SendPacket(&pvpLogData); WorldPacket data; - sBattlegroundMgr->BuildBattlegroundStatusPacket(&data, this, player->GetBattlegroundQueueIndex(bgQueueTypeId), STATUS_IN_PROGRESS, TIME_TO_AUTOREMOVE, GetStartTime(), GetArenaType()); + sBattlegroundMgr->BuildBattlegroundStatusPacket(&data, this, player->GetBattlegroundQueueIndex(bgQueueTypeId), STATUS_IN_PROGRESS, TIME_TO_AUTOREMOVE, GetStartTime(), GetArenaType(), player->GetBGTeam()); player->GetSession()->SendPacket(&data); player->UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_COMPLETE_BATTLEGROUND, 1); } @@ -1022,7 +1022,7 @@ void Battleground::RemovePlayerAtLeave(uint64 guid, bool Transport, bool SendPac if (SendPacket) { WorldPacket data; - sBattlegroundMgr->BuildBattlegroundStatusPacket(&data, this, player->GetBattlegroundQueueIndex(bgQueueTypeId), STATUS_NONE, 0, 0, 0); + sBattlegroundMgr->BuildBattlegroundStatusPacket(&data, this, player->GetBattlegroundQueueIndex(bgQueueTypeId), STATUS_NONE, 0, 0, 0, 0); player->GetSession()->SendPacket(&data); } @@ -1147,13 +1147,6 @@ void Battleground::AddPlayer(Player* player) sBattlegroundMgr->BuildPlayerJoinedBattlegroundPacket(&data, player); SendPacketToTeam(team, &data, player, false); - // BG Status packet - WorldPacket status; - BattlegroundQueueTypeId bgQueueTypeId = sBattlegroundMgr->BGQueueTypeId(m_TypeID, GetArenaType()); - uint32 queueSlot = player->GetBattlegroundQueueIndex(bgQueueTypeId); - sBattlegroundMgr->BuildBattlegroundStatusPacket(&status, this, queueSlot, STATUS_IN_PROGRESS, 0, GetStartTime(), GetArenaType(), isArena() ? 0 : 1); - player->GetSession()->SendPacket(&status); - player->RemoveAurasByType(SPELL_AURA_MOUNTED); // add arena specific auras @@ -1643,7 +1636,7 @@ bool Battleground::AddSpiritGuide(uint32 type, float x, float y, float z, float creature->setDeathState(DEAD); creature->SetUInt64Value(UNIT_FIELD_CHANNEL_OBJECT, creature->GetGUID()); // aura - // TODO: Fix display here + /// @todo Fix display here // creature->SetVisibleAura(0, SPELL_SPIRIT_HEAL_CHANNEL); // casting visual effect creature->SetUInt32Value(UNIT_CHANNEL_SPELL, SPELL_SPIRIT_HEAL_CHANNEL); @@ -1688,7 +1681,7 @@ void Battleground::SendWarningToAll(int32 entry, ...) if (!entry) return; - char const *format = sObjectMgr->GetTrinityStringForDBCLocale(entry); + char const* format = sObjectMgr->GetTrinityStringForDBCLocale(entry); char str[1024]; va_list ap; @@ -1846,7 +1839,7 @@ void Battleground::PlayerAddedToBGCheckIfBGIsRunning(Player* player) sBattlegroundMgr->BuildPvpLogDataPacket(&data, this); player->GetSession()->SendPacket(&data); - sBattlegroundMgr->BuildBattlegroundStatusPacket(&data, this, player->GetBattlegroundQueueIndex(bgQueueTypeId), STATUS_IN_PROGRESS, GetEndTime(), GetStartTime(), GetArenaType()); + sBattlegroundMgr->BuildBattlegroundStatusPacket(&data, this, player->GetBattlegroundQueueIndex(bgQueueTypeId), STATUS_IN_PROGRESS, GetEndTime(), GetStartTime(), GetArenaType(), player->GetBGTeam()); player->GetSession()->SendPacket(&data); } diff --git a/src/server/game/Battlegrounds/Battleground.h b/src/server/game/Battlegrounds/Battleground.h index 8aba0ae7e4d..dd8fbb6710c 100644 --- a/src/server/game/Battlegrounds/Battleground.h +++ b/src/server/game/Battlegrounds/Battleground.h @@ -494,7 +494,7 @@ class Battleground void HandleTriggerBuff(uint64 go_guid); void SetHoliday(bool is_holiday); - // TODO: make this protected: + /// @todo make this protected: typedef std::vector<uint64> BGObjects; typedef std::vector<uint64> BGCreatures; BGObjects BgObjects; diff --git a/src/server/game/Battlegrounds/BattlegroundMgr.cpp b/src/server/game/Battlegrounds/BattlegroundMgr.cpp index 71ac8cf8180..dfa1a5dd609 100644 --- a/src/server/game/Battlegrounds/BattlegroundMgr.cpp +++ b/src/server/game/Battlegrounds/BattlegroundMgr.cpp @@ -162,7 +162,7 @@ void BattlegroundMgr::Update(uint32 diff) } } -void BattlegroundMgr::BuildBattlegroundStatusPacket(WorldPacket* data, Battleground* bg, uint8 QueueSlot, uint8 StatusID, uint32 Time1, uint32 Time2, uint8 arenatype, uint8 uiFrame) +void BattlegroundMgr::BuildBattlegroundStatusPacket(WorldPacket* data, Battleground* bg, uint8 QueueSlot, uint8 StatusID, uint32 Time1, uint32 Time2, uint8 arenatype, uint32 arenaFaction) { // we can be in 2 queues in same time... @@ -179,35 +179,35 @@ void BattlegroundMgr::BuildBattlegroundStatusPacket(WorldPacket* data, Battlegro // The following segment is read as uint64 in client but can be appended as their original type. *data << uint8(arenatype); sLog->outDebug(LOG_FILTER_NETWORKIO, "BattlegroundMgr::BuildBattlegroundStatusPacket: arenatype = %u for bg instanceID %u, TypeID %u.", arenatype, bg->GetClientInstanceID(), bg->GetTypeID()); - *data << uint8(bg->isArena() ? 0xC : 0x2); + *data << uint8(bg->isArena() ? 0xE : 0x0); *data << uint32(bg->GetTypeID()); *data << uint16(0x1F90); // End of uint64 segment, decomposed this way for simplicity - *data << uint8(0); // 3.3.0, some level, only saw 80... - *data << uint8(0); // 3.3.0, some level, only saw 80... + *data << uint8(bg->GetMinLevel()); + *data << uint8(bg->GetMaxLevel()); *data << uint32(bg->GetClientInstanceID()); // alliance/horde for BG and skirmish/rated for Arenas // following displays the minimap-icon 0 = faction icon 1 = arenaicon - *data << uint8(bg->isRated()); // 1 for rated match, 0 for bg or non rated match + *data << uint8(bg->isRated()); // 1 for rated match, 0 for bg or non rated match - *data << uint32(StatusID); // status + *data << uint32(StatusID); // status switch (StatusID) { - case STATUS_WAIT_QUEUE: // status_in_queue - *data << uint32(Time1); // average wait time, milliseconds - *data << uint32(Time2); // time in queue, updated every minute!, milliseconds + case STATUS_WAIT_QUEUE: // status_in_queue + *data << uint32(Time1); // average wait time, milliseconds + *data << uint32(Time2); // time in queue, updated every minute!, milliseconds break; - case STATUS_WAIT_JOIN: // status_invite - *data << uint32(bg->GetMapId()); // map id - *data << uint64(0); // 3.3.5, unknown - *data << uint32(Time1); // time to remove from queue, milliseconds + case STATUS_WAIT_JOIN: // status_invite + *data << uint32(bg->GetMapId()); // map id + *data << uint64(0); // 3.3.5, unknown + *data << uint32(Time1); // time to remove from queue, milliseconds break; - case STATUS_IN_PROGRESS: // status_in_progress - *data << uint32(bg->GetMapId()); // map id - *data << uint64(0); // 3.3.5, unknown - *data << uint32(Time1); // time to bg auto leave, 0 at bg start, 120000 after bg end, milliseconds - *data << uint32(Time2); // time from bg start, milliseconds - *data << uint8(uiFrame); + case STATUS_IN_PROGRESS: // status_in_progress + *data << uint32(bg->GetMapId()); // map id + *data << uint64(0); // 3.3.5, unknown + *data << uint32(Time1); // time to bg auto leave, 0 at bg start, 120000 after bg end, milliseconds + *data << uint32(Time2); // time from bg start, milliseconds + *data << uint8(arenaFaction == ALLIANCE ? 1 : 0); // arenafaction (0 for horde, 1 for alliance) break; default: sLog->outError(LOG_FILTER_BATTLEGROUND, "Unknown BG status!"); @@ -589,6 +589,27 @@ Battleground* BattlegroundMgr::CreateNewBattleground(BattlegroundTypeId original bg->SetRated(isRated); bg->SetRandom(isRandom); + // Set up correct min/max player counts for scoreboards + if (bg->isArena()) + { + uint32 maxPlayersPerTeam = 0; + switch (arenaType) + { + case ARENA_TYPE_2v2: + maxPlayersPerTeam = 2; + break; + case ARENA_TYPE_3v3: + maxPlayersPerTeam = 3; + break; + case ARENA_TYPE_5v5: + maxPlayersPerTeam = 5; + break; + } + + bg->SetMaxPlayersPerTeam(maxPlayersPerTeam); + bg->SetMaxPlayers(maxPlayersPerTeam * 2); + } + return bg; } @@ -649,8 +670,8 @@ bool BattlegroundMgr::CreateBattleground(CreateBattlegroundData& data) bg->SetArenaorBGType(data.IsArena); bg->SetMinPlayersPerTeam(data.MinPlayersPerTeam); bg->SetMaxPlayersPerTeam(data.MaxPlayersPerTeam); - bg->SetMinPlayers(data.MinPlayersPerTeam* 2); - bg->SetMaxPlayers(data.MaxPlayersPerTeam* 2); + bg->SetMinPlayers(data.MinPlayersPerTeam * 2); + bg->SetMaxPlayers(data.MaxPlayersPerTeam * 2); bg->SetName(data.BattlegroundName); bg->SetTeamStartLoc(ALLIANCE, data.Team1StartLocX, data.Team1StartLocY, data.Team1StartLocZ, data.Team1StartLocO); bg->SetTeamStartLoc(HORDE, data.Team2StartLocX, data.Team2StartLocY, data.Team2StartLocZ, data.Team2StartLocO); @@ -1008,7 +1029,7 @@ void BattlegroundMgr::SetHolidayWeekends(uint32 mask) void BattlegroundMgr::ScheduleQueueUpdate(uint32 arenaMatchmakerRating, uint8 arenaType, BattlegroundQueueTypeId bgQueueTypeId, BattlegroundTypeId bgTypeId, BattlegroundBracketId bracket_id) { - //This method must be atomic, TODO add mutex + //This method must be atomic, @todo add mutex //we will use only 1 number created of bgTypeId and bracket_id uint64 const scheduleId = ((uint64)arenaMatchmakerRating << 32) | (arenaType << 24) | (bgQueueTypeId << 16) | (bgTypeId << 8) | bracket_id; if (std::find(m_QueueUpdateScheduler.begin(), m_QueueUpdateScheduler.end(), scheduleId) == m_QueueUpdateScheduler.end()) diff --git a/src/server/game/Battlegrounds/BattlegroundMgr.h b/src/server/game/Battlegrounds/BattlegroundMgr.h index 236494792d4..c66d9d64ab8 100644 --- a/src/server/game/Battlegrounds/BattlegroundMgr.h +++ b/src/server/game/Battlegrounds/BattlegroundMgr.h @@ -80,7 +80,7 @@ class BattlegroundMgr void BuildGroupJoinedBattlegroundPacket(WorldPacket* data, GroupJoinBattlegroundResult result); void BuildUpdateWorldStatePacket(WorldPacket* data, uint32 field, uint32 value); void BuildPvpLogDataPacket(WorldPacket* data, Battleground* bg); - void BuildBattlegroundStatusPacket(WorldPacket* data, Battleground* bg, uint8 queueSlot, uint8 statusId, uint32 time1, uint32 time2, uint8 arenaType, uint8 uiFrame = 1); + void BuildBattlegroundStatusPacket(WorldPacket* data, Battleground* bg, uint8 queueSlot, uint8 statusId, uint32 time1, uint32 time2, uint8 arenaType, uint32 arenaFaction); void BuildPlaySoundPacket(WorldPacket* data, uint32 soundId); void SendAreaSpiritHealerQueryOpcode(Player* player, Battleground* bg, uint64 guid); diff --git a/src/server/game/Battlegrounds/BattlegroundQueue.cpp b/src/server/game/Battlegrounds/BattlegroundQueue.cpp index 150cec08e3c..65d3b9dc0b8 100644 --- a/src/server/game/Battlegrounds/BattlegroundQueue.cpp +++ b/src/server/game/Battlegrounds/BattlegroundQueue.cpp @@ -49,14 +49,12 @@ BattlegroundQueue::~BattlegroundQueue() { m_events.KillAllEvents(false); - m_QueuedPlayers.clear(); for (int i = 0; i < MAX_BATTLEGROUND_BRACKETS; ++i) { for (uint32 j = 0; j < BG_QUEUE_GROUP_TYPES_COUNT; ++j) { for (GroupsQueueType::iterator itr = m_QueuedGroups[i][j].begin(); itr!= m_QueuedGroups[i][j].end(); ++itr) delete (*itr); - m_QueuedGroups[i][j].clear(); } } } @@ -396,7 +394,7 @@ void BattlegroundQueue::RemovePlayer(uint64 guid, bool decreaseInvitedCount) plr2->RemoveBattlegroundQueueId(bgQueueTypeId); // must be called this way, because if you move this call to // queue->removeplayer, it causes bugs WorldPacket data; - sBattlegroundMgr->BuildBattlegroundStatusPacket(&data, bg, queueSlot, STATUS_NONE, 0, 0, 0); + sBattlegroundMgr->BuildBattlegroundStatusPacket(&data, bg, queueSlot, STATUS_NONE, 0, 0, 0, 0); plr2->GetSession()->SendPacket(&data); } // then actually delete, this may delete the group as well! @@ -481,7 +479,7 @@ bool BattlegroundQueue::InviteGroupToBG(GroupQueueInfo* ginfo, Battleground* bg, player->GetName().c_str(), player->GetGUIDLow(), bg->GetInstanceID(), queueSlot, bg->GetTypeID()); // send status packet - sBattlegroundMgr->BuildBattlegroundStatusPacket(&data, bg, queueSlot, STATUS_WAIT_JOIN, INVITE_ACCEPT_WAIT_TIME, 0, ginfo->ArenaType); + sBattlegroundMgr->BuildBattlegroundStatusPacket(&data, bg, queueSlot, STATUS_WAIT_JOIN, INVITE_ACCEPT_WAIT_TIME, 0, ginfo->ArenaType, 0); player->GetSession()->SendPacket(&data); } return true; @@ -1003,7 +1001,7 @@ bool BGQueueInviteEvent::Execute(uint64 /*e_time*/, uint32 /*p_time*/) { WorldPacket data; //we must send remaining time in queue - sBattlegroundMgr->BuildBattlegroundStatusPacket(&data, bg, queueSlot, STATUS_WAIT_JOIN, INVITE_ACCEPT_WAIT_TIME - INVITATION_REMIND_TIME, 0, m_ArenaType); + sBattlegroundMgr->BuildBattlegroundStatusPacket(&data, bg, queueSlot, STATUS_WAIT_JOIN, INVITE_ACCEPT_WAIT_TIME - INVITATION_REMIND_TIME, 0, m_ArenaType, 0); player->GetSession()->SendPacket(&data); } } @@ -1051,7 +1049,7 @@ bool BGQueueRemoveEvent::Execute(uint64 /*e_time*/, uint32 /*p_time*/) sBattlegroundMgr->ScheduleQueueUpdate(0, 0, m_BgQueueTypeId, m_BgTypeId, bg->GetBracketId()); WorldPacket data; - sBattlegroundMgr->BuildBattlegroundStatusPacket(&data, bg, queueSlot, STATUS_NONE, 0, 0, 0); + sBattlegroundMgr->BuildBattlegroundStatusPacket(&data, bg, queueSlot, STATUS_NONE, 0, 0, 0, 0); player->GetSession()->SendPacket(&data); } } diff --git a/src/server/game/Battlegrounds/Zones/BattlegroundAB.h b/src/server/game/Battlegrounds/Zones/BattlegroundAB.h index 87e27a990ed..3467cf56ba6 100644 --- a/src/server/game/Battlegrounds/Zones/BattlegroundAB.h +++ b/src/server/game/Battlegrounds/Zones/BattlegroundAB.h @@ -282,7 +282,7 @@ class BattlegroundAB : public Battleground void _SendNodeUpdate(uint8 node); /* Creature spawning/despawning */ - // TODO: working, scripted peons spawning + /// @todo working, scripted peons spawning void _NodeOccupied(uint8 node, Team team); void _NodeDeOccupied(uint8 node); diff --git a/src/server/game/Battlegrounds/Zones/BattlegroundAV.cpp b/src/server/game/Battlegrounds/Zones/BattlegroundAV.cpp index e0c62f9ca56..e89d80efc1f 100644 --- a/src/server/game/Battlegrounds/Zones/BattlegroundAV.cpp +++ b/src/server/game/Battlegrounds/Zones/BattlegroundAV.cpp @@ -43,7 +43,7 @@ BattlegroundAV::~BattlegroundAV() { } -uint16 BattlegroundAV::GetBonusHonor(uint8 kills) //TODO: move this function to Battleground.cpp (needs to find a way to get m_MaxLevel) +uint16 BattlegroundAV::GetBonusHonor(uint8 kills) /// @todo move this function to Battleground.cpp (needs to find a way to get m_MaxLevel) { return Trinity::Honor::hk_honor_at_level(m_MaxLevel, kills); } @@ -139,7 +139,7 @@ void BattlegroundAV::HandleQuestComplete(uint32 questid, Player* player) if (GetStatus() != STATUS_IN_PROGRESS) return;//maybe we should log this, cause this must be a cheater or a big bug uint8 team = GetTeamIndexByTeamId(player->GetTeam()); - //TODO add reputation, events (including quest not available anymore, next quest availabe, go/npc de/spawning)and maybe honor + /// @todo add reputation, events (including quest not available anymore, next quest availabe, go/npc de/spawning)and maybe honor sLog->outDebug(LOG_FILTER_BATTLEGROUND, "BG_AV Quest %i completed", questid); switch (questid) { @@ -298,7 +298,7 @@ Creature* BattlegroundAV::AddAVCreature(uint16 cinfoid, uint16 type) if (!creature) return NULL; if (creature->GetEntry() == BG_AV_CreatureInfo[AV_NPC_A_CAPTAIN][0] || creature->GetEntry() == BG_AV_CreatureInfo[AV_NPC_H_CAPTAIN][0]) - creature->SetRespawnDelay(RESPAWN_ONE_DAY); // TODO: look if this can be done by database + also add this for the wingcommanders + creature->SetRespawnDelay(RESPAWN_ONE_DAY); /// @todo look if this can be done by database + also add this for the wingcommanders if ((isStatic && cinfoid >= 10 && cinfoid <= 14) || (!isStatic && ((cinfoid >= AV_NPC_A_GRAVEDEFENSE0 && cinfoid <= AV_NPC_A_GRAVEDEFENSE3) || (cinfoid >= AV_NPC_H_GRAVEDEFENSE0 && cinfoid <= AV_NPC_H_GRAVEDEFENSE3)))) @@ -314,7 +314,7 @@ Creature* BattlegroundAV::AddAVCreature(uint16 cinfoid, uint16 type) creature->GetMotionMaster()->Initialize(); creature->setDeathState(JUST_DIED); creature->Respawn(); - //TODO: find a way to add a motionmaster without killing the creature (i + /// @todo find a way to add a motionmaster without killing the creature (i //just copied this code from a gm-command } @@ -384,11 +384,11 @@ void BattlegroundAV::PostUpdateImpl(uint32 diff) else { CastSpellOnTeam(AV_BUFF_H_CAPTAIN, HORDE); - Creature* creature = GetBGCreature(AV_CPLACE_MAX + 59); //TODO: make the captains a dynamic creature + Creature* creature = GetBGCreature(AV_CPLACE_MAX + 59); /// @todo make the captains a dynamic creature if (creature) YellToAll(creature, LANG_BG_AV_H_CAPTAIN_BUFF, LANG_ORCISH); } - m_CaptainBuffTimer[i] = 120000 + urand(0, 4)* 60000; //as far as i could see, the buff is randomly so i make 2minutes (thats the duration of the buff itself) + 0-4minutes TODO get the right times + m_CaptainBuffTimer[i] = 120000 + urand(0, 4)* 60000; //as far as i could see, the buff is randomly so i make 2minutes (thats the duration of the buff itself) + 0-4minutes @todo get the right times } } //add points from mine owning, and look if he neutral team wanrts to reclaim the mine @@ -455,7 +455,7 @@ void BattlegroundAV::AddPlayer(Player* player) BattlegroundAVScore* sc = new BattlegroundAVScore; PlayerScores[player->GetGUID()] = sc; if (m_MaxLevel == 0) - m_MaxLevel=(player->getLevel()%10 == 0)? player->getLevel() : (player->getLevel()-(player->getLevel()%10))+10; //TODO: just look at the code \^_^/ --but queue-info should provide this information.. + m_MaxLevel=(player->getLevel()%10 == 0)? player->getLevel() : (player->getLevel()-(player->getLevel()%10))+10; /// @todo just look at the code \^_^/ --but queue-info should provide this information.. } void BattlegroundAV::EndBattleground(uint32 winner) @@ -494,7 +494,7 @@ void BattlegroundAV::EndBattleground(uint32 winner) RewardHonorToTeam(GetBonusHonor(kills[i]), i == 0 ? ALLIANCE : HORDE); } - //TODO add enterevademode for all attacking creatures + /// @todo add enterevademode for all attacking creatures Battleground::EndBattleground(winner); } @@ -505,7 +505,7 @@ void BattlegroundAV::RemovePlayer(Player* player, uint64 /*guid*/, uint32 /*team sLog->outError(LOG_FILTER_BATTLEGROUND, "bg_AV no player at remove"); return; } - //TODO search more buffs + /// @todo search more buffs player->RemoveAurasDueToSpell(AV_BUFF_ARMOR); player->RemoveAurasDueToSpell(AV_BUFF_A_CAPTAIN); player->RemoveAurasDueToSpell(AV_BUFF_H_CAPTAIN); @@ -666,10 +666,10 @@ void BattlegroundAV::ChangeMineOwner(uint8 mine, uint32 team, bool initial) if (mine == AV_SOUTH_MINE) for (uint16 i=AV_CPLACE_MINE_S_S_MIN; i <= AV_CPLACE_MINE_S_S_MAX; i++) if (BgCreatures[i]) - DelCreature(i); //TODO just set the respawntime to 999999 + DelCreature(i); /// @todo just set the respawntime to 999999 for (uint16 i=((mine == AV_NORTH_MINE)?AV_CPLACE_MINE_N_1_MIN:AV_CPLACE_MINE_S_1_MIN); i <= ((mine == AV_NORTH_MINE)?AV_CPLACE_MINE_N_3:AV_CPLACE_MINE_S_3); i++) if (BgCreatures[i]) - DelCreature(i); //TODO here also + DelCreature(i); /// @todo here also } SendMineWorldStates(mine); @@ -1617,7 +1617,7 @@ void BattlegroundAV::ResetBGSubclass() m_Team_Scores[i]=BG_AV_SCORE_INITIAL_POINTS; m_IsInformedNearVictory[i]=false; m_CaptainAlive[i] = true; - m_CaptainBuffTimer[i] = 120000 + urand(0, 4)* 60; //as far as i could see, the buff is randomly so i make 2minutes (thats the duration of the buff itself) + 0-4minutes TODO get the right times + m_CaptainBuffTimer[i] = 120000 + urand(0, 4)* 60; //as far as i could see, the buff is randomly so i make 2minutes (thats the duration of the buff itself) + 0-4minutes @todo get the right times m_Mine_Owner[i] = AV_NEUTRAL_TEAM; m_Mine_PrevOwner[i] = m_Mine_Owner[i]; } diff --git a/src/server/game/Battlegrounds/Zones/BattlegroundAV.h b/src/server/game/Battlegrounds/Zones/BattlegroundAV.h index 7cd4d571cad..7a0af0b06d7 100644 --- a/src/server/game/Battlegrounds/Zones/BattlegroundAV.h +++ b/src/server/game/Battlegrounds/Zones/BattlegroundAV.h @@ -53,7 +53,7 @@ #define AV_EVENT_START_BATTLE 9166 // Achievement: The Alterac Blitz enum BG_AV_Sounds -{ //TODO: get out if there comes a sound when neutral team captures mine +{ /// @todo: get out if there comes a sound when neutral team captures mine /* 8212: @@ -86,7 +86,7 @@ horde: horde wins */ - AV_SOUND_NEAR_VICTORY = 8456, //not confirmed yet + AV_SOUND_NEAR_VICTORY = 8456, /// @todo: Not confirmed yet AV_SOUND_ALLIANCE_ASSAULTS = 8212, //tower, grave + enemy boss if someone tries to attack him AV_SOUND_HORDE_ASSAULTS = 8174, @@ -104,7 +104,7 @@ enum BG_AV_OTHER_VALUES AV_NORTH_MINE = 0, AV_SOUTH_MINE = 1, AV_MINE_TICK_TIMER = 45000, - AV_MINE_RECLAIM_TIMER = 1200000, //TODO: get the right value.. this is currently 20 minutes + AV_MINE_RECLAIM_TIMER = 1200000, /// @todo: get the right value.. this is currently 20 minutes AV_NEUTRAL_TEAM = 0 //this is the neutral owner of snowfall }; enum BG_AV_ObjectIds @@ -547,7 +547,7 @@ enum BG_AV_CreaturePlace AV_CPLACE_SPIRIT_FROST_HUT = 6, AV_CPLACE_SPIRIT_MAIN_ALLIANCE = 7, AV_CPLACE_SPIRIT_MAIN_HORDE = 8, -//i don't will add for all 4 positions a variable.. i think one is enough to compute the rest +//I don't add a variable for all 4 positions... I think one is enough to compute the rest AV_CPLACE_DEFENSE_STORM_AID = 9, AV_CPLACE_DEFEMSE_STORM_GRAVE = 13, AV_CPLACE_DEFENSE_STONE_GRAVE = 17, @@ -680,7 +680,7 @@ const float BG_AV_CreaturePos[AV_CPLACE_MAX][4] = {575.411f, -83.597f, 52.3626f, 6.26573f}, {571.352f, -75.6582f, 52.479f, 0.523599f}, //dun north - OK - {668.60f, -122.53f, 64.12f, 2.34f}, //not 100% ok + {668.60f, -122.53f, 64.12f, 2.34f}, /// @todo: To be confirm - Not completely okay {662.253f, -129.105f, 64.1794f, 2.77507f}, {661.209f, -138.877f, 64.2251f, 3.38594f}, {665.481f, -146.857f, 64.1271f, 3.75246f}, @@ -720,7 +720,7 @@ const float BG_AV_CreaturePos[AV_CPLACE_MAX][4] = {723.058f, -14.1548f, 50.7046f, 3.40339f}, // north {715.691f, -4.72233f, 50.2187f, 3.47321f}, // icewing {720.046f, -19.9413f, 50.2187f, 3.36849f}, // stone -//horde (coords not 100% ok) +/// horde @todo: Confirm positions {-1363.99f, -221.99f, 98.4053f, 4.93012f}, {-1370.96f, -223.532f, 98.4266f, 4.93012f}, {-1378.37f, -228.614f, 99.3546f, 5.38565f}, @@ -1039,14 +1039,14 @@ enum BG_AV_CreatureIds }; //entry, team, minlevel, maxlevel -//TODO this array should be removed, the only needed things are the entrys (for spawning(?) and handlekillunit) +/// @todo: this array should be removed, the only needed things are the entrys (for spawning(?) and handlekillunit) const uint32 BG_AV_CreatureInfo[AV_NPC_INFO_MAX][4] = { { 12050, 1216, 58, 58 }, //Stormpike Defender { 13326, 1216, 59, 59 }, //Seasoned Defender { 13331, 1216, 60, 60 }, //Veteran Defender { 13422, 1216, 61, 61 }, //Champion Defender - { 13358, 1216, 59, 60 }, //Stormpike Bowman //i think its 60, 61 and 69, 70.. but this is until now not possible TODO look if this is ok + { 13358, 1216, 59, 60 }, //Stormpike Bowman /// @todo: Confirm if this is correct. Author assumpted 60,61 & 69,70, but wouldn't work here { 11949, 469, 0, 0}, //not spawned with this data, but used for handlekillunit { 11948, 469, 0, 0}, //not spawned with this data, but used for handlekillunit { 12053, 1214, 58, 58 }, //Frostwolf Guardian @@ -1071,7 +1071,7 @@ const uint32 BG_AV_CreatureInfo[AV_NPC_INFO_MAX][4] = { 11602, 59, 54, 55 }, //Irondeep Skullthumper { 11657, 59, 58, 58 }, //Morloch - {13396, 469, 52, 53}, //irondeep alliance TODO: get the right ids + {13396, 469, 52, 53}, // irondeep alliance /// @todo: Correct and give correct ids {13080, 469, 53, 54}, {13098, 469, 54, 55}, {13078, 469, 58, 58}, @@ -1246,7 +1246,7 @@ const uint32 BG_AV_StaticCreatureInfo[51][4] = { 11675, 514, 53, 53 }, //Snowblind Windcaller { 11678, 14, 52, 53 }, //Snowblind Ambusher { 11839, 39, 56, 56 }, //Wildpaw Brute - { 11947, 1214, 61, 61 }, //Captain Galvangar --TODO: doubled + { 11947, 1214, 61, 61 }, // Captain Galvangar /// @todo: Duplicate ? Check and confirm { 11948, 1216, 63, 63 }, //Vanndar Stormpike { 11949, 1216, 61, 61 }, //Captain Balinda Stonehearth { 11997, 1334, 60, 60 }, //Stormpike Herald @@ -1277,7 +1277,7 @@ const uint32 BG_AV_StaticCreatureInfo[51][4] = { 14282, 1214, 53, 54 }, //Frostwolf Bloodhound { 14283, 1216, 53, 54 }, //Stormpike Owl { 14284, 1216, 61, 61 }, //Stormpike Battleguard - { 11946, 1214, 63, 63 }, //Drek'Thar //TODO: make the levels right (boss=0 maybe) + { 11946, 1214, 63, 63 }, //Drek'Thar /// @todo: Correct the level (Level 80 for boss ?) { 11948, 1216, 63, 63 }, //Vanndar Stormpike { 11947, 1214, 61, 61 }, //Captain Galvangar { 11949, 1216, 61, 61 } //Captain Balinda Stonehearth @@ -1310,7 +1310,7 @@ const uint32 BG_AV_GraveyardIds[9]= }; enum BG_AV_BUFF -{ //TODO add all other buffs here +{ /// @todo: Add all other buffs here AV_BUFF_ARMOR = 21163, AV_BUFF_A_CAPTAIN = 23693, //the buff which the alliance captain does AV_BUFF_H_CAPTAIN = 22751 //the buff which the horde captain does @@ -1607,7 +1607,7 @@ class BattlegroundAV : public Battleground /*general */ Creature* AddAVCreature(uint16 cinfoid, uint16 type); - uint16 GetBonusHonor(uint8 kills); //TODO remove this when the core handles this right + uint16 GetBonusHonor(uint8 kills); /// @todo: Remove this when the core handles this properly /*variables */ int32 m_Team_Scores[2]; @@ -1622,7 +1622,7 @@ class BattlegroundAV : public Battleground uint32 m_CaptainBuffTimer[2]; bool m_CaptainAlive[2]; - uint8 m_MaxLevel; //TODO remove this when battleground-getmaxlevel() returns something usefull + uint8 m_MaxLevel; /// @todo: Remove this once battleground->getmaxlevel() returns something usefull/is reworked (?) bool m_IsInformedNearVictory[2]; }; diff --git a/src/server/game/Battlegrounds/Zones/BattlegroundBE.cpp b/src/server/game/Battlegrounds/Zones/BattlegroundBE.cpp index b0ffc7855dd..9d1c12a8903 100644 --- a/src/server/game/Battlegrounds/Zones/BattlegroundBE.cpp +++ b/src/server/game/Battlegrounds/Zones/BattlegroundBE.cpp @@ -157,18 +157,3 @@ void BattlegroundBE::UpdatePlayerScore(Player* Source, uint32 type, uint32 value Battleground::UpdatePlayerScore(Source, type, value, doAddHonor); } - -/* -21:45:46 id:231310 [S2C] SMSG_INIT_WORLD_STATES (706 = 0x02C2) len: 86 -0000: 32 02 00 00 76 0e 00 00 00 00 00 00 09 00 f3 09 | 2...v........... -0010: 00 00 01 00 00 00 f1 09 00 00 01 00 00 00 f0 09 | ................ -0020: 00 00 02 00 00 00 d4 08 00 00 00 00 00 00 d8 08 | ................ -0030: 00 00 00 00 00 00 d7 08 00 00 00 00 00 00 d6 08 | ................ -0040: 00 00 00 00 00 00 d5 08 00 00 00 00 00 00 d3 08 | ................ -0050: 00 00 00 00 00 00 | ...... - -spell 32724 - Gold Team -spell 32725 - Green Team -35774 Gold Team -35775 Green Team -*/ diff --git a/src/server/game/Battlegrounds/Zones/BattlegroundDS.h b/src/server/game/Battlegrounds/Zones/BattlegroundDS.h index c9fe5e43c33..43437595220 100644 --- a/src/server/game/Battlegrounds/Zones/BattlegroundDS.h +++ b/src/server/game/Battlegrounds/Zones/BattlegroundDS.h @@ -106,15 +106,15 @@ class BattlegroundDS : public Battleground void PostUpdateImpl(uint32 diff); protected: - uint32 getWaterFallStatus() { return _waterfallStatus; }; - void setWaterFallStatus(uint8 status) { _waterfallStatus = status; }; - uint32 getWaterFallTimer() { return _waterfallTimer; }; - void setWaterFallTimer(uint32 timer) { _waterfallTimer = timer; }; - uint32 getWaterFallKnockbackTimer() { return _waterfallKnockbackTimer; }; - void setWaterFallKnockbackTimer(uint32 timer) { _waterfallKnockbackTimer = timer; }; - uint8 getPipeKnockBackCount() { return _pipeKnockBackCount; }; - void setPipeKnockBackCount(uint8 count) { _pipeKnockBackCount = count; }; - uint32 getPipeKnockBackTimer() { return _pipeKnockBackTimer; }; - void setPipeKnockBackTimer(uint32 timer) { _pipeKnockBackTimer = timer; }; + uint32 getWaterFallStatus() { return _waterfallStatus; } + void setWaterFallStatus(uint8 status) { _waterfallStatus = status; } + uint32 getWaterFallTimer() { return _waterfallTimer; } + void setWaterFallTimer(uint32 timer) { _waterfallTimer = timer; } + uint32 getWaterFallKnockbackTimer() { return _waterfallKnockbackTimer; } + void setWaterFallKnockbackTimer(uint32 timer) { _waterfallKnockbackTimer = timer; } + uint8 getPipeKnockBackCount() { return _pipeKnockBackCount; } + void setPipeKnockBackCount(uint8 count) { _pipeKnockBackCount = count; } + uint32 getPipeKnockBackTimer() { return _pipeKnockBackTimer; } + void setPipeKnockBackTimer(uint32 timer) { _pipeKnockBackTimer = timer; } }; #endif diff --git a/src/server/game/Battlegrounds/Zones/BattlegroundEY.cpp b/src/server/game/Battlegrounds/Zones/BattlegroundEY.cpp index 4ddf7a8b052..3d1c8844230 100644 --- a/src/server/game/Battlegrounds/Zones/BattlegroundEY.cpp +++ b/src/server/game/Battlegrounds/Zones/BattlegroundEY.cpp @@ -247,7 +247,7 @@ void BattlegroundEY::UpdatePointStatuses() if (player) { this->UpdateWorldStateForPlayer(PROGRESS_BAR_STATUS, m_PointBarStatus[point], player); - //if point owner changed we must evoke event! + //if point owner changed we must evoke event! if (pointOwnerTeamId != m_PointOwnedByTeam[point]) { //point was uncontrolled and player is from team which captured point @@ -258,6 +258,12 @@ void BattlegroundEY::UpdatePointStatuses() if (m_PointState[point] == EY_POINT_UNDER_CONTROL && player->GetTeam() != m_PointOwnedByTeam[point]) this->EventTeamLostPoint(player, point); } + + /// @workaround The original AreaTrigger is covered by a bigger one and not triggered on client side. + if (point == FEL_REAVER && m_PointOwnedByTeam[point] == player->GetTeam()) + if (m_FlagState && GetFlagPickerGUID() == player->GetGUID()) + if (player->GetDistance(2044.0f, 1729.729f, 1190.03f) < 3.0f) + EventPlayerCapturedFlag(player, BG_EY_OBJECT_FLAG_FEL_REAVER); } } } @@ -266,7 +272,7 @@ void BattlegroundEY::UpdatePointStatuses() void BattlegroundEY::UpdateTeamScore(uint32 Team) { uint32 score = GetTeamScore(Team); - //TODO there should be some sound played when one team is near victory!! - and define variables + /// @todo there should be some sound played when one team is near victory!! - and define variables /*if (!m_IsInformedNearVictory && score >= BG_EY_WARNING_NEAR_VICTORY_SCORE) { if (Team == ALLIANCE) diff --git a/src/server/game/Battlegrounds/Zones/BattlegroundRV.h b/src/server/game/Battlegrounds/Zones/BattlegroundRV.h index af6b5996edd..b6dc3775df8 100644 --- a/src/server/game/Battlegrounds/Zones/BattlegroundRV.h +++ b/src/server/game/Battlegrounds/Zones/BattlegroundRV.h @@ -118,11 +118,11 @@ class BattlegroundRV : public Battleground void PostUpdateImpl(uint32 diff); protected: - uint32 getTimer() { return Timer; }; - void setTimer(uint32 timer) { Timer = timer; }; + uint32 getTimer() { return Timer; } + void setTimer(uint32 timer) { Timer = timer; } - uint32 getState() { return State; }; - void setState(uint32 state) { State = state; }; + uint32 getState() { return State; } + void setState(uint32 state) { State = state; } void TogglePillarCollision(); bool GetPillarCollision() { return PillarCollision; } void SetPillarCollision(bool apply) { PillarCollision = apply; } diff --git a/src/server/game/CMakeLists.txt b/src/server/game/CMakeLists.txt index 368407e7924..f455610666e 100644 --- a/src/server/game/CMakeLists.txt +++ b/src/server/game/CMakeLists.txt @@ -102,6 +102,8 @@ set(game_STAT_SRCS include_directories( ${CMAKE_BINARY_DIR} + ${CMAKE_SOURCE_DIR}/dep/recastnavigation/Detour + ${CMAKE_SOURCE_DIR}/dep/recastnavigation/Recast ${CMAKE_SOURCE_DIR}/dep/g3dlite/include ${CMAKE_SOURCE_DIR}/dep/SFMT ${CMAKE_SOURCE_DIR}/dep/zlib diff --git a/src/server/game/Calendar/CalendarMgr.cpp b/src/server/game/Calendar/CalendarMgr.cpp index f4dd059846e..5f73ee48380 100644 --- a/src/server/game/Calendar/CalendarMgr.cpp +++ b/src/server/game/Calendar/CalendarMgr.cpp @@ -40,6 +40,12 @@ CalendarMgr::CalendarMgr() CalendarMgr::~CalendarMgr() { + for (CalendarEventStore::iterator itr = _events.begin(); itr != _events.end(); ++itr) + delete *itr; + + for (CalendarEventInviteStore::iterator itr = _invites.begin(); itr != _invites.end(); ++itr) + for (CalendarInviteStore::iterator itr2 = itr->second.begin(); itr2 != itr->second.end(); ++itr2) + delete *itr2; } void CalendarMgr::LoadFromDB() @@ -68,7 +74,7 @@ void CalendarMgr::LoadFromDB() if (flags & CALENDAR_FLAG_GUILD_EVENT || flags & CALENDAR_FLAG_WITHOUT_INVITES) guildId = Player::GetGuildIdFromDB(creatorGUID); - CalendarEvent* calendarEvent = new CalendarEvent(eventId, creatorGUID , guildId, type, dungeonId, time_t(eventTime), flags, time_t(timezoneTime), title, description); + CalendarEvent* calendarEvent = new CalendarEvent(eventId, creatorGUID, guildId, type, dungeonId, time_t(eventTime), flags, time_t(timezoneTime), title, description); _events.insert(calendarEvent); _maxEventId = std::max(_maxEventId, eventId); @@ -153,7 +159,7 @@ void CalendarMgr::RemoveEvent(uint64 eventId, uint64 remover) PreparedStatement* stmt; MailDraft mail(calendarEvent->BuildCalendarMailSubject(remover), calendarEvent->BuildCalendarMailBody()); - std::vector<CalendarInvite*>::iterator itr = _invites[eventId].begin(); + CalendarInviteStore::iterator itr = _invites[eventId].begin(); while (itr != _invites[eventId].end()) { stmt = CharacterDatabase.GetPreparedStatement(CHAR_DEL_CALENDAR_INVITE); @@ -187,7 +193,7 @@ void CalendarMgr::RemoveInvite(uint64 inviteId, uint64 eventId, uint64 /*remover if (!calendarEvent) return; - std::vector<CalendarInvite*>::iterator itr = _invites[eventId].begin(); + CalendarInviteStore::iterator itr = _invites[eventId].begin(); for (; itr != _invites[eventId].end(); ++itr) if ((*itr)->GetInviteId() == inviteId) break; @@ -254,8 +260,8 @@ void CalendarMgr::RemoveAllPlayerEventsAndInvites(uint64 guid) if ((*itr)->GetCreatorGUID() == guid) RemoveEvent((*itr)->GetEventId(), 0); // don't send mail if removing a character - std::vector<CalendarInvite*> playerInvites = GetPlayerInvites(guid); - for (std::vector<CalendarInvite*>::const_iterator itr = playerInvites.begin(); itr != playerInvites.end(); ++itr) + CalendarInviteStore playerInvites = GetPlayerInvites(guid); + for (CalendarInviteStore::const_iterator itr = playerInvites.begin(); itr != playerInvites.end(); ++itr) RemoveInvite((*itr)->GetInviteId(), (*itr)->GetEventId(), guid); } @@ -265,14 +271,14 @@ void CalendarMgr::RemovePlayerGuildEventsAndSignups(uint64 guid, uint32 guildId) if ((*itr)->GetCreatorGUID() == guid && ((*itr)->IsGuildEvent() || (*itr)->IsGuildAnnouncement())) RemoveEvent((*itr)->GetEventId(), guid); - std::vector<CalendarInvite*> playerInvites = GetPlayerInvites(guid); - for (std::vector<CalendarInvite*>::const_iterator itr = playerInvites.begin(); itr != playerInvites.end(); ++itr) + CalendarInviteStore playerInvites = GetPlayerInvites(guid); + for (CalendarInviteStore::const_iterator itr = playerInvites.begin(); itr != playerInvites.end(); ++itr) if (CalendarEvent* calendarEvent = GetEvent((*itr)->GetEventId())) if (calendarEvent->IsGuildEvent() && calendarEvent->GetGuildId() == guildId) RemoveInvite((*itr)->GetInviteId(), (*itr)->GetEventId(), guid); } -CalendarEvent* CalendarMgr::GetEvent(uint64 eventId) +CalendarEvent* CalendarMgr::GetEvent(uint64 eventId) const { for (CalendarEventStore::const_iterator itr = _events.begin(); itr != _events.end(); ++itr) if ((*itr)->GetEventId() == eventId) @@ -282,10 +288,10 @@ CalendarEvent* CalendarMgr::GetEvent(uint64 eventId) return NULL; } -CalendarInvite* CalendarMgr::GetInvite(uint64 inviteId) +CalendarInvite* CalendarMgr::GetInvite(uint64 inviteId) const { - for (CalendarInviteStore::const_iterator itr = _invites.begin(); itr != _invites.end(); ++itr) - for (std::vector<CalendarInvite*>::const_iterator itr2 = itr->second.begin(); itr2 != itr->second.end(); ++itr2) + for (CalendarEventInviteStore::const_iterator itr = _invites.begin(); itr != _invites.end(); ++itr) + for (CalendarInviteStore::const_iterator itr2 = itr->second.begin(); itr2 != itr->second.end(); ++itr2) if ((*itr2)->GetInviteId() == inviteId) return *itr2; @@ -305,12 +311,10 @@ uint64 CalendarMgr::GetFreeEventId() { if (_freeEventIds.empty()) return ++_maxEventId; - else - { - uint64 eventId = _freeEventIds.front(); - _freeEventIds.pop_front(); - return eventId; - } + + uint64 eventId = _freeEventIds.front(); + _freeEventIds.pop_front(); + return eventId; } void CalendarMgr::FreeInviteId(uint64 id) @@ -325,20 +329,18 @@ uint64 CalendarMgr::GetFreeInviteId() { if (_freeInviteIds.empty()) return ++_maxInviteId; - else - { - uint64 inviteId = _freeInviteIds.front(); - _freeInviteIds.pop_front(); - return inviteId; - } + + uint64 inviteId = _freeInviteIds.front(); + _freeInviteIds.pop_front(); + return inviteId; } CalendarEventStore CalendarMgr::GetPlayerEvents(uint64 guid) { CalendarEventStore events; - for (CalendarInviteStore::const_iterator itr = _invites.begin(); itr != _invites.end(); ++itr) - for (std::vector<CalendarInvite*>::const_iterator itr2 = itr->second.begin(); itr2 != itr->second.end(); ++itr2) + for (CalendarEventInviteStore::const_iterator itr = _invites.begin(); itr != _invites.end(); ++itr) + for (CalendarInviteStore::const_iterator itr2 = itr->second.begin(); itr2 != itr->second.end(); ++itr2) if ((*itr2)->GetInviteeGUID() == guid) events.insert(GetEvent(itr->first)); @@ -350,17 +352,17 @@ CalendarEventStore CalendarMgr::GetPlayerEvents(uint64 guid) return events; } -std::vector<CalendarInvite*> CalendarMgr::GetEventInvites(uint64 eventId) +CalendarInviteStore const& CalendarMgr::GetEventInvites(uint64 eventId) { return _invites[eventId]; } -std::vector<CalendarInvite*> CalendarMgr::GetPlayerInvites(uint64 guid) +CalendarInviteStore CalendarMgr::GetPlayerInvites(uint64 guid) { - std::vector<CalendarInvite*> invites; + CalendarInviteStore invites; - for (CalendarInviteStore::const_iterator itr = _invites.begin(); itr != _invites.end(); ++itr) - for (std::vector<CalendarInvite*>::const_iterator itr2 = itr->second.begin(); itr2 != itr->second.end(); ++itr2) + for (CalendarEventInviteStore::const_iterator itr = _invites.begin(); itr != _invites.end(); ++itr) + for (CalendarInviteStore::const_iterator itr2 = itr->second.begin(); itr2 != itr->second.end(); ++itr2) if ((*itr2)->GetInviteeGUID() == guid) invites.push_back(*itr2); @@ -369,13 +371,22 @@ std::vector<CalendarInvite*> CalendarMgr::GetPlayerInvites(uint64 guid) uint32 CalendarMgr::GetPlayerNumPending(uint64 guid) { - std::vector<CalendarInvite*> const& invites = GetPlayerInvites(guid); + CalendarInviteStore const& invites = GetPlayerInvites(guid); uint32 pendingNum = 0; - for (std::vector<CalendarInvite*>::const_iterator itr = invites.begin(); itr != invites.end(); ++itr) - // correct? - if ((*itr)->GetStatus() == CALENDAR_STATUS_INVITED || (*itr)->GetStatus() == CALENDAR_STATUS_TENTATIVE || (*itr)->GetStatus() == CALENDAR_STATUS_NOT_SIGNED_UP) - ++pendingNum; + for (CalendarInviteStore::const_iterator itr = invites.begin(); itr != invites.end(); ++itr) + { + switch ((*itr)->GetStatus()) + { + case CALENDAR_STATUS_INVITED: + case CALENDAR_STATUS_TENTATIVE: + case CALENDAR_STATUS_NOT_SIGNED_UP: + ++pendingNum; + break; + default: + break; + } + } return pendingNum; } @@ -531,7 +542,7 @@ void CalendarMgr::SendCalendarEvent(uint64 guid, CalendarEvent const& calendarEv if (!player) return; - std::vector<CalendarInvite*> const& eventInviteeList = _invites[calendarEvent.GetEventId()]; + CalendarInviteStore const& eventInviteeList = _invites[calendarEvent.GetEventId()]; WorldPacket data(SMSG_CALENDAR_SEND_EVENT, 60 + eventInviteeList.size() * 32); data << uint8(sendType); @@ -549,7 +560,7 @@ void CalendarMgr::SendCalendarEvent(uint64 guid, CalendarEvent const& calendarEv data << uint32(calendarEvent.GetGuildId()); data << uint32(eventInviteeList.size()); - for (std::vector<CalendarInvite*>::const_iterator itr = eventInviteeList.begin(); itr != eventInviteeList.end(); ++itr) + for (CalendarInviteStore::const_iterator itr = eventInviteeList.begin(); itr != eventInviteeList.end(); ++itr) { CalendarInvite const* calendarInvite = (*itr); uint64 inviteeGuid = calendarInvite->GetInviteeGUID(); @@ -627,8 +638,8 @@ void CalendarMgr::SendPacketToAllEventRelatives(WorldPacket packet, CalendarEven guild->BroadcastPacket(&packet); // Send packet to all invitees if event is non-guild, in other case only to non-guild invitees (packet was broadcasted for them) - std::vector<CalendarInvite*> invites = _invites[calendarEvent.GetEventId()]; - for (std::vector<CalendarInvite*>::iterator itr = invites.begin(); itr != invites.end(); ++itr) + CalendarInviteStore invites = _invites[calendarEvent.GetEventId()]; + for (CalendarInviteStore::iterator itr = invites.begin(); itr != invites.end(); ++itr) if (Player* player = ObjectAccessor::FindPlayer((*itr)->GetInviteeGUID())) if (!calendarEvent.IsGuildEvent() || (calendarEvent.IsGuildEvent() && player->GetGuildId() != calendarEvent.GetGuildId())) player->SendDirectMessage(&packet); diff --git a/src/server/game/Calendar/CalendarMgr.h b/src/server/game/Calendar/CalendarMgr.h index 3674e707399..d1b3d0a9dd6 100644 --- a/src/server/game/Calendar/CalendarMgr.h +++ b/src/server/game/Calendar/CalendarMgr.h @@ -261,9 +261,9 @@ struct CalendarEvent std::string _title; std::string _description; }; - +typedef std::vector<CalendarInvite*> CalendarInviteStore; typedef std::set<CalendarEvent*> CalendarEventStore; -typedef std::map<uint64 /* eventId */, std::vector<CalendarInvite*> > CalendarInviteStore; +typedef std::map<uint64 /* eventId */, CalendarInviteStore > CalendarEventInviteStore; class CalendarMgr { @@ -274,7 +274,7 @@ class CalendarMgr ~CalendarMgr(); CalendarEventStore _events; - CalendarInviteStore _invites; + CalendarEventInviteStore _invites; std::deque<uint64> _freeEventIds; std::deque<uint64> _freeInviteIds; @@ -284,14 +284,14 @@ class CalendarMgr public: void LoadFromDB(); - CalendarEvent* GetEvent(uint64 eventId); + CalendarEvent* GetEvent(uint64 eventId) const; CalendarEventStore const& GetEvents() const { return _events; } CalendarEventStore GetPlayerEvents(uint64 guid); - CalendarInvite* GetInvite(uint64 inviteId); - CalendarInviteStore const& GetInvites() const { return _invites; } - std::vector<CalendarInvite*> GetEventInvites(uint64 eventId); - std::vector<CalendarInvite*> GetPlayerInvites(uint64 guid); + CalendarInvite* GetInvite(uint64 inviteId) const; + CalendarEventInviteStore const& GetInvites() const { return _invites; } + CalendarInviteStore const& GetEventInvites(uint64 eventId); + CalendarInviteStore GetPlayerInvites(uint64 guid); void FreeEventId(uint64 id); uint64 GetFreeEventId(); diff --git a/src/server/game/Chat/Channels/Channel.cpp b/src/server/game/Chat/Channels/Channel.cpp index 9e7a63c9093..d6b00fb108a 100644 --- a/src/server/game/Chat/Channels/Channel.cpp +++ b/src/server/game/Chat/Channels/Channel.cpp @@ -180,7 +180,7 @@ void Channel::JoinChannel(Player* player, std::string const& pass) if (HasFlag(CHANNEL_FLAG_LFG) && sWorld->getBoolConfig(CONFIG_RESTRICTED_LFG_CHANNEL) && - AccountMgr::IsPlayerAccount(player->GetSession()->GetSecurity()) && + AccountMgr::IsPlayerAccount(player->GetSession()->GetSecurity()) && //FIXME: Move to RBAC player->GetGroup()) { WorldPacket data; @@ -191,8 +191,7 @@ void Channel::JoinChannel(Player* player, std::string const& pass) player->JoinedChannel(this); - if (_announce && (!AccountMgr::IsGMAccount(player->GetSession()->GetSecurity()) || - !sWorld->getBoolConfig(CONFIG_SILENTLY_GM_JOIN_TO_CHANNEL))) + if (_announce && !player->GetSession()->HasPermission(RBAC_PERM_SILENTLY_JOIN_CHANNEL)) { WorldPacket data; MakeJoined(&data, guid); @@ -252,8 +251,8 @@ void Channel::LeaveChannel(Player* player, bool send) bool changeowner = playersStore[guid].IsOwner(); playersStore.erase(guid); - if (_announce && (!AccountMgr::IsGMAccount(player->GetSession()->GetSecurity()) || - !sWorld->getBoolConfig(CONFIG_SILENTLY_GM_JOIN_TO_CHANNEL))) + + if (_announce && !player->GetSession()->HasPermission(RBAC_PERM_SILENTLY_JOIN_CHANNEL)) { WorldPacket data; MakeLeft(&data, guid); @@ -279,7 +278,6 @@ void Channel::LeaveChannel(Player* player, bool send) void Channel::KickOrBan(Player const* player, std::string const& badname, bool ban) { - AccountTypes sec = player->GetSession()->GetSecurity(); uint64 good = player->GetGUID(); if (!IsOn(good)) @@ -290,7 +288,7 @@ void Channel::KickOrBan(Player const* player, std::string const& badname, bool b return; } - if (!playersStore[good].IsModerator() && !AccountMgr::IsGMAccount(sec)) + if (!playersStore[good].IsModerator() && !player->GetSession()->HasPermission(RBAC_PERM_CHANGE_CHANNEL_NOT_MODERATOR)) { WorldPacket data; MakeNotModerator(&data); @@ -310,7 +308,7 @@ void Channel::KickOrBan(Player const* player, std::string const& badname, bool b bool changeowner = _ownerGUID == victim; - if (!AccountMgr::IsGMAccount(sec) && changeowner && good != _ownerGUID) + if (!player->GetSession()->HasPermission(RBAC_PERM_CHANGE_CHANNEL_NOT_MODERATOR) && changeowner && good != _ownerGUID) { WorldPacket data; MakeNotOwner(&data); @@ -318,21 +316,19 @@ void Channel::KickOrBan(Player const* player, std::string const& badname, bool b return; } - bool notify = !(AccountMgr::IsGMAccount(sec) && sWorld->getBoolConfig(CONFIG_SILENTLY_GM_JOIN_TO_CHANNEL)); - if (ban && !IsBanned(victim)) { bannedStore.insert(victim); UpdateChannelInDB(); - if (notify) + if (!player->GetSession()->HasPermission(RBAC_PERM_SILENTLY_JOIN_CHANNEL)) { WorldPacket data; MakePlayerBanned(&data, victim, good); SendToAll(&data); } } - else if (notify) + else if (!player->GetSession()->HasPermission(RBAC_PERM_SILENTLY_JOIN_CHANNEL)) { WorldPacket data; MakePlayerKicked(&data, victim, good); @@ -352,7 +348,6 @@ void Channel::KickOrBan(Player const* player, std::string const& badname, bool b void Channel::UnBan(Player const* player, std::string const& badname) { - uint32 sec = player->GetSession()->GetSecurity(); uint64 good = player->GetGUID(); if (!IsOn(good)) @@ -363,7 +358,7 @@ void Channel::UnBan(Player const* player, std::string const& badname) return; } - if (!playersStore[good].IsModerator() && !AccountMgr::IsGMAccount(sec)) + if (!playersStore[good].IsModerator() && !player->GetSession()->HasPermission(RBAC_PERM_CHANGE_CHANNEL_NOT_MODERATOR)) { WorldPacket data; MakeNotModerator(&data); @@ -404,7 +399,7 @@ void Channel::Password(Player const* player, std::string const& pass) return; } - if (!playersStore[guid].IsModerator() && !AccountMgr::IsGMAccount(player->GetSession()->GetSecurity())) + if (!playersStore[guid].IsModerator() && !player->GetSession()->HasPermission(RBAC_PERM_CHANGE_CHANNEL_NOT_MODERATOR)) { WorldPacket data; MakeNotModerator(&data); @@ -424,7 +419,6 @@ void Channel::Password(Player const* player, std::string const& pass) void Channel::SetMode(Player const* player, std::string const& p2n, bool mod, bool set) { uint64 guid = player->GetGUID(); - uint32 sec = player->GetSession()->GetSecurity(); if (!IsOn(guid)) { @@ -434,7 +428,7 @@ void Channel::SetMode(Player const* player, std::string const& p2n, bool mod, bo return; } - if (!playersStore[guid].IsModerator() && !AccountMgr::IsGMAccount(sec)) + if (!playersStore[guid].IsModerator() && !player->GetSession()->HasPermission(RBAC_PERM_CHANGE_CHANNEL_NOT_MODERATOR)) { WorldPacket data; MakeNotModerator(&data); @@ -449,10 +443,9 @@ void Channel::SetMode(Player const* player, std::string const& p2n, bool mod, bo uint64 victim = newp ? newp->GetGUID() : 0; if (!victim || !IsOn(victim) || - // allow make moderator from another team only if both is GMs - // at this moment this only way to show channel post for GM from another team - ((!AccountMgr::IsGMAccount(sec) || !AccountMgr::IsGMAccount(newp->GetSession()->GetSecurity())) && - player->GetTeam() != newp->GetTeam() && !sWorld->getBoolConfig(CONFIG_ALLOW_TWO_SIDE_INTERACTION_CHANNEL))) + (player->GetTeam() != newp->GetTeam() && + (!player->GetSession()->HasPermission(RBAC_PERM_TWO_SIDE_INTERACTION_CHANNEL) || + !newp->GetSession()->HasPermission(RBAC_PERM_TWO_SIDE_INTERACTION_CHANNEL)))) { WorldPacket data; MakePlayerNotFound(&data, p2n); @@ -477,7 +470,6 @@ void Channel::SetMode(Player const* player, std::string const& p2n, bool mod, bo void Channel::SetOwner(Player const* player, std::string const& newname) { uint64 guid = player->GetGUID(); - uint32 sec = player->GetSession()->GetSecurity(); if (!IsOn(guid)) { @@ -487,7 +479,7 @@ void Channel::SetOwner(Player const* player, std::string const& newname) return; } - if (!AccountMgr::IsGMAccount(sec) && guid != _ownerGUID) + if (!player->GetSession()->HasPermission(RBAC_PERM_CHANGE_CHANNEL_NOT_MODERATOR) && guid != _ownerGUID) { WorldPacket data; MakeNotOwner(&data); @@ -499,7 +491,9 @@ void Channel::SetOwner(Player const* player, std::string const& newname) uint64 victim = newp ? newp->GetGUID() : 0; if (!victim || !IsOn(victim) || - (newp->GetTeam() != player->GetTeam() && !sWorld->getBoolConfig(CONFIG_ALLOW_TWO_SIDE_INTERACTION_CHANNEL))) + (player->GetTeam() != newp->GetTeam() && + (!player->GetSession()->HasPermission(RBAC_PERM_TWO_SIDE_INTERACTION_CHANNEL) || + !newp->GetSession()->HasPermission(RBAC_PERM_TWO_SIDE_INTERACTION_CHANNEL)))) { WorldPacket data; MakePlayerNotFound(&data, newname); @@ -553,7 +547,9 @@ void Channel::List(Player const* player) // PLAYER can't see MODERATOR, GAME MASTER, ADMINISTRATOR characters // MODERATOR, GAME MASTER, ADMINISTRATOR can see all - if (member && (!AccountMgr::IsPlayerAccount(player->GetSession()->GetSecurity()) || member->GetSession()->GetSecurity() <= AccountTypes(gmLevelInWhoList)) && + if (member && + (player->GetSession()->HasPermission(RBAC_PERM_WHO_SEE_ALL_SEC_LEVELS) || + member->GetSession()->GetSecurity() <= AccountTypes(gmLevelInWhoList)) && member->IsVisibleGloballyFor(player)) { data << uint64(i->first); @@ -570,7 +566,6 @@ void Channel::List(Player const* player) void Channel::Announce(Player const* player) { uint64 guid = player->GetGUID(); - uint32 sec = player->GetSession()->GetSecurity(); if (!IsOn(guid)) { @@ -580,7 +575,7 @@ void Channel::Announce(Player const* player) return; } - if (!playersStore[guid].IsModerator() && !AccountMgr::IsGMAccount(sec)) + if (!playersStore[guid].IsModerator() && !player->GetSession()->HasPermission(RBAC_PERM_CHANGE_CHANNEL_NOT_MODERATOR)) { WorldPacket data; MakeNotModerator(&data); @@ -605,6 +600,11 @@ void Channel::Say(uint64 guid, std::string const& what, uint32 lang) if (what.empty()) return; + uint8 chatTag = 0; + if (Player* player = ObjectAccessor::FindPlayer(guid)) + chatTag = player->GetChatTag(); + + // TODO: Add proper RBAC check if (sWorld->getBoolConfig(CONFIG_ALLOW_TWO_SIDE_INTERACTION_CHANNEL)) lang = LANG_UNIVERSAL; @@ -633,8 +633,7 @@ void Channel::Say(uint64 guid, std::string const& what, uint32 lang) data << uint64(guid); data << uint32(what.size() + 1); data << what; - Player* player = ObjectAccessor::FindPlayer(guid); - data << uint8(player ? player->GetChatTag() : 0); + data << uint8(chatTag); SendToAll(&data, !playersStore[guid].IsModerator() ? guid : false); } @@ -668,7 +667,9 @@ void Channel::Invite(Player const* player, std::string const& newname) return; } - if (newp->GetTeam() != player->GetTeam() && !sWorld->getBoolConfig(CONFIG_ALLOW_TWO_SIDE_INTERACTION_CHANNEL)) + if (newp->GetTeam() != player->GetTeam() && + (!player->GetSession()->HasPermission(RBAC_PERM_TWO_SIDE_INTERACTION_CHANNEL) || + !newp->GetSession()->HasPermission(RBAC_PERM_TWO_SIDE_INTERACTION_CHANNEL))) { WorldPacket data; MakeInviteWrongFaction(&data); diff --git a/src/server/game/Chat/Channels/Channel.h b/src/server/game/Chat/Channels/Channel.h index 0b3b84088a5..295c8d5394d 100644 --- a/src/server/game/Chat/Channels/Channel.h +++ b/src/server/game/Chat/Channels/Channel.h @@ -49,8 +49,8 @@ enum ChatNotify CHAT_MODE_CHANGE_NOTICE = 0x0C, //? CHAT_ANNOUNCEMENTS_ON_NOTICE = 0x0D, //+ "[%s] Channel announcements enabled by %s."; CHAT_ANNOUNCEMENTS_OFF_NOTICE = 0x0E, //+ "[%s] Channel announcements disabled by %s."; - // CHAT_MODERATION_ON_NOTICE = 0x0F, //+ "[%s] Channel moderation enabled by %s."; - // CHAT_MODERATION_OFF_NOTICE = 0x10, //+ "[%s] Channel moderation disabled by %s."; + CHAT_MODERATION_ON_NOTICE = 0x0F, //+ "[%s] Channel moderation enabled by %s."; + CHAT_MODERATION_OFF_NOTICE = 0x10, //+ "[%s] Channel moderation disabled by %s."; CHAT_MUTED_NOTICE = 0x11, //+ "[%s] You do not have permission to speak."; CHAT_PLAYER_KICKED_NOTICE = 0x12, //? "[%s] Player %s kicked by %s."; CHAT_BANNED_NOTICE = 0x13, //+ "[%s] You are bannedStore from that channel."; diff --git a/src/server/game/Chat/Channels/ChannelMgr.cpp b/src/server/game/Chat/Channels/ChannelMgr.cpp index bb2a7e08b0f..62b3416f72e 100644 --- a/src/server/game/Chat/Channels/ChannelMgr.cpp +++ b/src/server/game/Chat/Channels/ChannelMgr.cpp @@ -24,8 +24,6 @@ ChannelMgr::~ChannelMgr() { for (ChannelMap::iterator itr = channels.begin(); itr != channels.end(); ++itr) delete itr->second; - - channels.clear(); } ChannelMgr* ChannelMgr::forTeam(uint32 team) diff --git a/src/server/game/Chat/Chat.cpp b/src/server/game/Chat/Chat.cpp index 0bf7c8591e3..7c92af2d67f 100644 --- a/src/server/game/Chat/Chat.cpp +++ b/src/server/game/Chat/Chat.cpp @@ -122,8 +122,28 @@ const char *ChatHandler::GetTrinityString(int32 entry) const bool ChatHandler::isAvailable(ChatCommand const& cmd) const { - // check security level only for simple command (without child commands) - return m_session->GetSecurity() >= AccountTypes(cmd.SecurityLevel); + uint32 permission = 0; + + ///@Workaround:: Fast adaptation to RBAC system till all commands are moved to permissions + switch (AccountTypes(cmd.SecurityLevel)) + { + case SEC_ADMINISTRATOR: + permission = RBAC_PERM_ADMINISTRATOR_COMMANDS; + break; + case SEC_GAMEMASTER: + permission = RBAC_PERM_GAMEMASTER_COMMANDS; + break; + case SEC_MODERATOR: + permission = RBAC_PERM_MODERATOR_COMMANDS; + break; + case SEC_PLAYER: + permission = RBAC_PERM_PLAYER_COMMANDS; + break; + default: // Allow custom security levels for commands + return m_session->GetSecurity() >= AccountTypes(cmd.SecurityLevel); + } + + return m_session->HasPermission(permission); } bool ChatHandler::HasLowerSecurity(Player* target, uint64 guid, bool strong) @@ -155,7 +175,7 @@ bool ChatHandler::HasLowerSecurityAccount(WorldSession* target, uint32 target_ac return false; // ignore only for non-players for non strong checks (when allow apply command at least to same sec level) - if (!AccountMgr::IsPlayerAccount(m_session->GetSecurity()) && !strong && !sWorld->getBoolConfig(CONFIG_GM_LOWER_SECURITY)) + if (m_session->HasPermission(RBAC_PERM_CHECK_FOR_LOWER_SECURITY) && !strong && !sWorld->getBoolConfig(CONFIG_GM_LOWER_SECURITY)) return false; if (target) @@ -341,6 +361,7 @@ bool ChatHandler::ExecuteCommandInTable(ChatCommand* table, const char* text, co // table[i].Name == "" is special case: send original command to handler if ((table[i].Handler)(this, table[i].Name[0] != '\0' ? text : oldtext)) { + // FIXME: When Command system is moved to RBAC this check must be changed if (!AccountMgr::IsPlayerAccount(table[i].SecurityLevel)) { // chat case @@ -431,7 +452,7 @@ bool ChatHandler::ParseCommands(char const* text) std::string fullcmd = text; - if (m_session && AccountMgr::IsPlayerAccount(m_session->GetSecurity()) && !sWorld->getBoolConfig(CONFIG_ALLOW_PLAYER_COMMANDS)) + if (m_session && !m_session->HasPermission(RBAC_PERM_PLAYER_COMMANDS)) return false; /// chat case (.command or !command format) @@ -456,7 +477,7 @@ bool ChatHandler::ParseCommands(char const* text) if (!ExecuteCommandInTable(getCommandTable(), text, fullcmd)) { - if (m_session && AccountMgr::IsPlayerAccount(m_session->GetSecurity())) + if (m_session && !m_session->HasPermission(RBAC_PERM_COMMANDS_NOTIFY_COMMAND_NOT_FOUND_ERROR)) return false; SendSysMessage(LANG_NO_CMD); diff --git a/src/server/game/Combat/ThreatManager.cpp b/src/server/game/Combat/ThreatManager.cpp index 0e13019c8a2..249c1696348 100644 --- a/src/server/game/Combat/ThreatManager.cpp +++ b/src/server/game/Combat/ThreatManager.cpp @@ -272,7 +272,7 @@ HostileReference* ThreatContainer::getReferenceByTarget(Unit* victim) const uint64 const guid = victim->GetGUID(); for (ThreatContainer::StorageType::const_iterator i = iThreatList.begin(); i != iThreatList.end(); ++i) { - HostileReference *ref = (*i); + HostileReference* ref = (*i); if (ref && ref->getUnitGuid() == guid) return ref; } @@ -416,20 +416,17 @@ void ThreatManager::addThreat(Unit* victim, float threat, SpellSchoolMask school void ThreatManager::doAddThreat(Unit* victim, float threat) { - uint32 reducedThreadPercent = victim->GetReducedThreatPercent(); + uint32 redirectThreadPct = victim->GetRedirectThreatPercent(); // must check > 0.0f, otherwise dead loop - if (threat > 0.0f && reducedThreadPercent) + if (threat > 0.0f && redirectThreadPct) { - Unit* redirectTarget = victim->GetMisdirectionTarget(); - if (redirectTarget) - if (Aura* glyphAura = redirectTarget->GetAura(63326)) // Glyph of Vigilance - reducedThreadPercent += glyphAura->GetSpellInfo()->Effects[0].CalcValue(); - - float reducedThreat = threat * reducedThreadPercent / 100.0f; - threat -= reducedThreat; - if (redirectTarget) - _addThreat(redirectTarget, reducedThreat); + if (Unit* redirectTarget = victim->GetRedirectThreatTarget()) + { + float redirectThreat = CalculatePct(threat, redirectThreadPct); + threat -= redirectThreat; + _addThreat(redirectTarget, redirectThreat); + } } _addThreat(victim, threat); diff --git a/src/server/game/Conditions/ConditionMgr.cpp b/src/server/game/Conditions/ConditionMgr.cpp index 0526c9276f9..96cb8b7ee25 100644 --- a/src/server/game/Conditions/ConditionMgr.cpp +++ b/src/server/game/Conditions/ConditionMgr.cpp @@ -311,6 +311,12 @@ bool Condition::Meets(ConditionSourceInfo& sourceInfo) condMeets = ((1 << object->GetMap()->GetSpawnMode()) & ConditionValue1); break; } + case CONDITION_UNIT_STATE: + { + if (Unit* unit = object->ToUnit()) + condMeets = unit->HasUnitState(ConditionValue1); + break; + } default: condMeets = false; break; @@ -425,6 +431,7 @@ uint32 Condition::GetSearcherTypeMaskForCondition() default: break; } + break; case CONDITION_TYPE_MASK: if (ConditionValue1 & TYPEMASK_UNIT) mask |= GRID_MAP_TYPE_MASK_CREATURE | GRID_MAP_TYPE_MASK_PLAYER; @@ -468,6 +475,9 @@ uint32 Condition::GetSearcherTypeMaskForCondition() case CONDITION_GENDER: mask |= GRID_MAP_TYPE_MASK_PLAYER; break; + case CONDITION_UNIT_STATE: + mask |= GRID_MAP_TYPE_MASK_CREATURE | GRID_MAP_TYPE_MASK_PLAYER; + break; default: ASSERT(false && "Condition::GetSearcherTypeMaskForCondition - missing condition handling!"); break; @@ -768,7 +778,7 @@ void ConditionMgr::LoadConditions(bool isReload) if (!result) { - sLog->outError(LOG_FILTER_SQL, ">> Loaded 0 conditions. DB table `conditions` is empty!"); + sLog->outError(LOG_FILTER_SERVER_LOADING, ">> Loaded 0 conditions. DB table `conditions` is empty!"); return; } @@ -1355,7 +1365,7 @@ bool ConditionMgr::isSourceTypeValid(Condition* cond) if ((cond->SourceGroup > MAX_EFFECT_MASK) || !cond->SourceGroup) { - sLog->outError(LOG_FILTER_SQL, "SourceEntry %u in `condition` table, has incorrect SourceGroup %u (spell effectMask) set , ignoring.", cond->SourceEntry, cond->SourceGroup); + sLog->outError(LOG_FILTER_SQL, "SourceEntry %u in `condition` table, has incorrect SourceGroup %u (spell effectMask) set, ignoring.", cond->SourceEntry, cond->SourceGroup); return false; } @@ -1957,9 +1967,15 @@ bool ConditionMgr::isConditionTypeValid(Condition* cond) } break; } - case CONDITION_UNUSED_21: - sLog->outError(LOG_FILTER_SQL, "Found ConditionTypeOrReference = CONDITION_UNUSED_21 in `conditions` table - ignoring"); - return false; + case CONDITION_UNIT_STATE: + { + if (cond->ConditionValue1 > uint32(UNIT_STATE_ALL_STATE)) + { + sLog->outError(LOG_FILTER_SQL, "UnitState condition has non existing UnitState in value1 (%u), skipped", cond->ConditionValue1); + return false; + } + break; + } case CONDITION_UNUSED_24: sLog->outError(LOG_FILTER_SQL, "Found ConditionTypeOrReference = CONDITION_UNUSED_24 in `conditions` table - ignoring"); return false; diff --git a/src/server/game/Conditions/ConditionMgr.h b/src/server/game/Conditions/ConditionMgr.h index fec5cd6fc95..b49626747a6 100644 --- a/src/server/game/Conditions/ConditionMgr.h +++ b/src/server/game/Conditions/ConditionMgr.h @@ -54,7 +54,7 @@ enum ConditionTypes CONDITION_TITLE = 18, // title id 0 0 true if player has title CONDITION_SPAWNMASK = 19, // spawnMask 0 0 true if in spawnMask CONDITION_GENDER = 20, // gender 0 0 true if player's gender is equal to gender - CONDITION_UNUSED_21 = 21, // + CONDITION_UNIT_STATE = 21, // unitState 0 0 true if unit has unitState CONDITION_MAPID = 22, // map_id 0 0 true if in map_id CONDITION_AREAID = 23, // area_id 0 0 true if in area_id CONDITION_UNUSED_24 = 24, // diff --git a/src/server/game/Conditions/DisableMgr.cpp b/src/server/game/Conditions/DisableMgr.cpp index fefb51323c4..7e379fdaded 100644 --- a/src/server/game/Conditions/DisableMgr.cpp +++ b/src/server/game/Conditions/DisableMgr.cpp @@ -42,7 +42,7 @@ namespace DisableMap m_DisableMap; - uint8 MAX_DISABLE_TYPES = 7; + uint8 MAX_DISABLE_TYPES = 8; } void LoadDisables() @@ -222,6 +222,34 @@ void LoadDisables() } break; } + case DISABLE_TYPE_MMAP: + { + MapEntry const* mapEntry = sMapStore.LookupEntry(entry); + if (!mapEntry) + { + sLog->outError(LOG_FILTER_SQL, "Map entry %u from `disables` doesn't exist in dbc, skipped.", entry); + continue; + } + switch (mapEntry->map_type) + { + case MAP_COMMON: + sLog->outInfo(LOG_FILTER_GENERAL, "Pathfinding disabled for world map %u.", entry); + break; + case MAP_INSTANCE: + case MAP_RAID: + sLog->outInfo(LOG_FILTER_GENERAL, "Pathfinding disabled for instance map %u.", entry); + break; + case MAP_BATTLEGROUND: + sLog->outInfo(LOG_FILTER_GENERAL, "Pathfinding disabled for battleground map %u.", entry); + break; + case MAP_ARENA: + sLog->outInfo(LOG_FILTER_GENERAL, "Pathfinding disabled for arena map %u.", entry); + break; + default: + break; + } + break; + } default: break; } @@ -350,6 +378,7 @@ bool IsDisabledFor(DisableType type, uint32 entry, Unit const* unit, uint8 flags case DISABLE_TYPE_BATTLEGROUND: case DISABLE_TYPE_OUTDOORPVP: case DISABLE_TYPE_ACHIEVEMENT_CRITERIA: + case DISABLE_TYPE_MMAP: return true; case DISABLE_TYPE_VMAP: return flags & itr->second.flags; diff --git a/src/server/game/Conditions/DisableMgr.h b/src/server/game/Conditions/DisableMgr.h index 89761931048..38751b8a89f 100644 --- a/src/server/game/Conditions/DisableMgr.h +++ b/src/server/game/Conditions/DisableMgr.h @@ -31,7 +31,8 @@ enum DisableType DISABLE_TYPE_BATTLEGROUND = 3, DISABLE_TYPE_ACHIEVEMENT_CRITERIA = 4, DISABLE_TYPE_OUTDOORPVP = 5, - DISABLE_TYPE_VMAP = 6 + DISABLE_TYPE_VMAP = 6, + DISABLE_TYPE_MMAP = 7 }; enum SpellDisableTypes @@ -56,6 +57,11 @@ enum VmapDisableTypes VMAP_DISABLE_LIQUIDSTATUS = 0x8 }; +enum MMapDisableTypes +{ + MMAP_DISABLE_PATHFINDING = 0x0 +}; + namespace DisableMgr { void LoadDisables(); diff --git a/src/server/game/DataStores/DBCEnums.h b/src/server/game/DataStores/DBCEnums.h index 70af15da6e9..c4283bbca8a 100644 --- a/src/server/game/DataStores/DBCEnums.h +++ b/src/server/game/DataStores/DBCEnums.h @@ -153,13 +153,13 @@ enum AchievementCriteriaTypes ACHIEVEMENT_CRITERIA_TYPE_GAIN_EXALTED_REPUTATION = 47, ACHIEVEMENT_CRITERIA_TYPE_VISIT_BARBER_SHOP = 48, ACHIEVEMENT_CRITERIA_TYPE_EQUIP_EPIC_ITEM = 49, - ACHIEVEMENT_CRITERIA_TYPE_ROLL_NEED_ON_LOOT = 50, // TODO: itemlevel is mentioned in text but not present in dbc + ACHIEVEMENT_CRITERIA_TYPE_ROLL_NEED_ON_LOOT = 50, /// @todo itemlevel is mentioned in text but not present in dbc ACHIEVEMENT_CRITERIA_TYPE_ROLL_GREED_ON_LOOT = 51, ACHIEVEMENT_CRITERIA_TYPE_HK_CLASS = 52, ACHIEVEMENT_CRITERIA_TYPE_HK_RACE = 53, ACHIEVEMENT_CRITERIA_TYPE_DO_EMOTE = 54, ACHIEVEMENT_CRITERIA_TYPE_HEALING_DONE = 55, - ACHIEVEMENT_CRITERIA_TYPE_GET_KILLING_BLOWS = 56, // TODO: in some cases map not present, and in some cases need do without die + ACHIEVEMENT_CRITERIA_TYPE_GET_KILLING_BLOWS = 56, /// @todo in some cases map not present, and in some cases need do without die ACHIEVEMENT_CRITERIA_TYPE_EQUIP_ITEM = 57, ACHIEVEMENT_CRITERIA_TYPE_MONEY_FROM_VENDORS = 59, ACHIEVEMENT_CRITERIA_TYPE_GOLD_SPENT_FOR_TALENTS = 60, @@ -173,8 +173,8 @@ enum AchievementCriteriaTypes ACHIEVEMENT_CRITERIA_TYPE_BE_SPELL_TARGET2 = 69, ACHIEVEMENT_CRITERIA_TYPE_SPECIAL_PVP_KILL = 70, ACHIEVEMENT_CRITERIA_TYPE_FISH_IN_GAMEOBJECT = 72, - // TODO 73: Achievements 1515, 1241, 1103 (Name: Mal'Ganis) - ACHIEVEMENT_CRITERIA_TYPE_EARNED_PVP_TITLE = 74, // TODO: title id is not mentioned in dbc + /// @todo 73: Achievements 1515, 1241, 1103 (Name: Mal'Ganis) + ACHIEVEMENT_CRITERIA_TYPE_EARNED_PVP_TITLE = 74, /// @todo title id is not mentioned in dbc ACHIEVEMENT_CRITERIA_TYPE_LEARN_SKILLLINE_SPELLS = 75, ACHIEVEMENT_CRITERIA_TYPE_WIN_DUEL = 76, ACHIEVEMENT_CRITERIA_TYPE_LOSE_DUEL = 77, @@ -207,7 +207,7 @@ enum AchievementCriteriaTypes ACHIEVEMENT_CRITERIA_TYPE_QUEST_ABANDONED = 107, ACHIEVEMENT_CRITERIA_TYPE_FLIGHT_PATHS_TAKEN = 108, ACHIEVEMENT_CRITERIA_TYPE_LOOT_TYPE = 109, - ACHIEVEMENT_CRITERIA_TYPE_CAST_SPELL2 = 110, // TODO: target entry is missing + ACHIEVEMENT_CRITERIA_TYPE_CAST_SPELL2 = 110, /// @todo target entry is missing ACHIEVEMENT_CRITERIA_TYPE_LEARN_SKILL_LINE = 112, ACHIEVEMENT_CRITERIA_TYPE_EARN_HONORABLE_KILL = 113, ACHIEVEMENT_CRITERIA_TYPE_ACCEPTED_SUMMONINGS = 114, @@ -389,27 +389,38 @@ enum SummonPropFlags enum VehicleSeatFlags { - VEHICLE_SEAT_FLAG_HAS_LOWER_ANIM_FOR_ENTER = 0x00000001, - VEHICLE_SEAT_FLAG_HAS_LOWER_ANIM_FOR_RIDE = 0x00000002, - VEHICLE_SEAT_FLAG_SHOULD_USE_VEH_SEAT_EXIT_ANIM_ON_VOLUNTARY_EXIT = 0x00000008, - VEHICLE_SEAT_FLAG_HIDE_PASSENGER = 0x00000200, // Passenger is hidden - VEHICLE_SEAT_FLAG_ALLOW_TURNING = 0x00000400, // needed for CGCamera__SyncFreeLookFacing - VEHICLE_SEAT_FLAG_CAN_CONTROL = 0x00000800, // Lua_UnitInVehicleControlSeat - VEHICLE_SEAT_FLAG_CAN_CAST_MOUNT_SPELL = 0x00001000, // Can cast spells with SPELL_AURA_MOUNTED from seat (possibly 4.x only, 0 seats on 3.3.5a) - VEHICLE_SEAT_FLAG_UNCONTROLLED = 0x00002000, // can override !& VEHICLE_SEAT_FLAG_CAN_ENTER_OR_EXIT - VEHICLE_SEAT_FLAG_CAN_ATTACK = 0x00004000, // Can attack, cast spells and use items from vehicle - VEHICLE_SEAT_FLAG_SHOULD_USE_VEH_SEAT_EXIT_ANIMN_ON_FORCED_EXIT = 0x00008000, - VEHICLE_SEAT_FLAG_HAS_VEH_EXIT_ANIM_VOLUNTARY_EXIT = 0x00040000, - VEHICLE_SEAT_FLAG_HAS_VEH_EXIT_ANIM_FORCED_EXIT = 0x00080000, - VEHICLE_SEAT_FLAG_REC_HAS_VEHICLE_ENTER_ANIM = 0x00400000, - VEHICLE_SEAT_FLAG_ENABLE_VEHICLE_ZOOM = 0x01000000, - VEHICLE_SEAT_FLAG_CAN_ENTER_OR_EXIT = 0x02000000, // Lua_CanExitVehicle - can enter and exit at free will - VEHICLE_SEAT_FLAG_CAN_SWITCH = 0x04000000, // Lua_CanSwitchVehicleSeats + VEHICLE_SEAT_FLAG_HAS_LOWER_ANIM_FOR_ENTER = 0x00000001, + VEHICLE_SEAT_FLAG_HAS_LOWER_ANIM_FOR_RIDE = 0x00000002, + VEHICLE_SEAT_FLAG_UNK3 = 0x00000004, + VEHICLE_SEAT_FLAG_SHOULD_USE_VEH_SEAT_EXIT_ANIM_ON_VOLUNTARY_EXIT = 0x00000008, + VEHICLE_SEAT_FLAG_UNK5 = 0x00000010, + VEHICLE_SEAT_FLAG_UNK6 = 0x00000020, + VEHICLE_SEAT_FLAG_UNK7 = 0x00000040, + VEHICLE_SEAT_FLAG_UNK8 = 0x00000080, + VEHICLE_SEAT_FLAG_UNK9 = 0x00000100, + VEHICLE_SEAT_FLAG_HIDE_PASSENGER = 0x00000200, // Passenger is hidden + VEHICLE_SEAT_FLAG_ALLOW_TURNING = 0x00000400, // needed for CGCamera__SyncFreeLookFacing + VEHICLE_SEAT_FLAG_CAN_CONTROL = 0x00000800, // Lua_UnitInVehicleControlSeat + VEHICLE_SEAT_FLAG_CAN_CAST_MOUNT_SPELL = 0x00001000, // Can cast spells with SPELL_AURA_MOUNTED from seat (possibly 4.x only, 0 seats on 3.3.5a) + VEHICLE_SEAT_FLAG_UNCONTROLLED = 0x00002000, // can override !& VEHICLE_SEAT_FLAG_CAN_ENTER_OR_EXIT + VEHICLE_SEAT_FLAG_CAN_ATTACK = 0x00004000, // Can attack, cast spells and use items from vehicle + VEHICLE_SEAT_FLAG_SHOULD_USE_VEH_SEAT_EXIT_ANIM_ON_FORCED_EXIT = 0x00008000, + VEHICLE_SEAT_FLAG_UNK17 = 0x00010000, + VEHICLE_SEAT_FLAG_UNK18 = 0x00020000, // Needs research and support (28 vehicles): Allow entering vehicles while keeping specific permanent(?) auras that impose visuals (states like beeing under freeze/stun mechanic, emote state animations). + VEHICLE_SEAT_FLAG_HAS_VEH_EXIT_ANIM_VOLUNTARY_EXIT = 0x00040000, + VEHICLE_SEAT_FLAG_HAS_VEH_EXIT_ANIM_FORCED_EXIT = 0x00080000, + VEHICLE_SEAT_FLAG_UNK21 = 0x00100000, + VEHICLE_SEAT_FLAG_UNK22 = 0x00200000, + VEHICLE_SEAT_FLAG_REC_HAS_VEHICLE_ENTER_ANIM = 0x00400000, + VEHICLE_SEAT_FLAG_IS_USING_VEHICLE_CONTROLS = 0x00800000, // Lua_IsUsingVehicleControls + VEHICLE_SEAT_FLAG_ENABLE_VEHICLE_ZOOM = 0x01000000, + VEHICLE_SEAT_FLAG_CAN_ENTER_OR_EXIT = 0x02000000, // Lua_CanExitVehicle - can enter and exit at free will + VEHICLE_SEAT_FLAG_CAN_SWITCH = 0x04000000, // Lua_CanSwitchVehicleSeats VEHICLE_SEAT_FLAG_HAS_START_WARITING_FOR_VEH_TRANSITION_ANIM_ENTER = 0x08000000, - VEHICLE_SEAT_FLAG_HAS_START_WARITING_FOR_VEH_TRANSITION_ANIM_EXIT = 0x10000000, - VEHICLE_SEAT_FLAG_CAN_CAST = 0x20000000, // Lua_UnitHasVehicleUI - VEHICLE_SEAT_FLAG_UNK2 = 0x40000000, // checked in conjunction with 0x800 in CastSpell2 - VEHICLE_SEAT_FLAG_ALLOWS_INTERACTION = 0x80000000 + VEHICLE_SEAT_FLAG_HAS_START_WARITING_FOR_VEH_TRANSITION_ANIM_EXIT = 0x10000000, + VEHICLE_SEAT_FLAG_CAN_CAST = 0x20000000, // Lua_UnitHasVehicleUI + VEHICLE_SEAT_FLAG_UNK2 = 0x40000000, // checked in conjunction with 0x800 in CastSpell2 + VEHICLE_SEAT_FLAG_ALLOWS_INTERACTION = 0x80000000 }; enum VehicleSeatFlagsB diff --git a/src/server/game/DataStores/DBCStores.cpp b/src/server/game/DataStores/DBCStores.cpp index 3fdff8e11d6..f382082761a 100644 --- a/src/server/game/DataStores/DBCStores.cpp +++ b/src/server/game/DataStores/DBCStores.cpp @@ -21,6 +21,8 @@ #include "SharedDefines.h" #include "SpellMgr.h" #include "DBCfmt.h" +#include "Timer.h" +#include "ObjectDefines.h" #include <map> @@ -62,6 +64,7 @@ DBCStorage <BankBagSlotPricesEntry> sBankBagSlotPricesStore(BankBagSlotPricesEnt DBCStorage <BattlemasterListEntry> sBattlemasterListStore(BattlemasterListEntryfmt); DBCStorage <BarberShopStyleEntry> sBarberShopStyleStore(BarberShopStyleEntryfmt); DBCStorage <CharStartOutfitEntry> sCharStartOutfitStore(CharStartOutfitEntryfmt); +std::map<uint32, CharStartOutfitEntry const*> sCharStartOutfitMap; DBCStorage <CharTitlesEntry> sCharTitlesStore(CharTitlesEntryfmt); DBCStorage <ChatChannelsEntry> sChatChannelsStore(ChatChannelsEntryfmt); DBCStorage <ChrClassesEntry> sChrClassesStore(ChrClassesEntryfmt); @@ -237,9 +240,10 @@ inline void LoadDBC(uint32& availableDbcLocales, StoreProblemList& errors, DBCSt // sort problematic dbc to (1) non compatible and (2) non-existed if (FILE* f = fopen(dbcFilename.c_str(), "rb")) { - char buf[100]; - snprintf(buf, 100, " exists, and has %u field(s) (expected " SIZEFMTD "). Extracted file might be from wrong client version or a database-update has been forgotten.", storage.GetFieldCount(), strlen(storage.GetFormat())); - errors.push_back(dbcFilename + buf); + std::ostringstream stream; + stream << dbcFilename << " exists, and has " << storage.GetFieldCount() << " field(s) (expected " << strlen(storage.GetFormat()) << "). Extracted file might be from wrong client version or a database-update has been forgotten."; + std::string buf = stream.str(); + errors.push_back(buf); fclose(f); } else @@ -284,6 +288,10 @@ void LoadDBCStores(const std::string& dataPath) LoadDBC(availableDbcLocales, bad_dbc_files, sBattlemasterListStore, dbcPath, "BattlemasterList.dbc"); LoadDBC(availableDbcLocales, bad_dbc_files, sBarberShopStyleStore, dbcPath, "BarberShopStyle.dbc"); LoadDBC(availableDbcLocales, bad_dbc_files, sCharStartOutfitStore, dbcPath, "CharStartOutfit.dbc"); + for (uint32 i = 0; i < sCharStartOutfitStore.GetNumRows(); ++i) + if (CharStartOutfitEntry const* outfit = sCharStartOutfitStore.LookupEntry(i)) + sCharStartOutfitMap[outfit->Race | (outfit->Class << 8) | (outfit->Gender << 16)] = outfit; + LoadDBC(availableDbcLocales, bad_dbc_files, sCharTitlesStore, dbcPath, "CharTitles.dbc"); LoadDBC(availableDbcLocales, bad_dbc_files, sChatChannelsStore, dbcPath, "ChatChannels.dbc"); LoadDBC(availableDbcLocales, bad_dbc_files, sChrClassesStore, dbcPath, "ChrClasses.dbc"); @@ -872,3 +880,11 @@ uint32 GetLiquidFlags(uint32 liquidType) return 0; } +CharStartOutfitEntry const* GetCharStartOutfitEntry(uint8 race, uint8 class_, uint8 gender) +{ + std::map<uint32, CharStartOutfitEntry const*>::const_iterator itr = sCharStartOutfitMap.find(race | (class_ << 8) | (gender << 16)); + if (itr == sCharStartOutfitMap.end()) + return NULL; + + return itr->second; +} diff --git a/src/server/game/DataStores/DBCStores.h b/src/server/game/DataStores/DBCStores.h index c77d0ee32f1..48a2cb3fe4e 100644 --- a/src/server/game/DataStores/DBCStores.h +++ b/src/server/game/DataStores/DBCStores.h @@ -65,6 +65,8 @@ uint32 GetLiquidFlags(uint32 liquidType); PvPDifficultyEntry const* GetBattlegroundBracketByLevel(uint32 mapid, uint32 level); PvPDifficultyEntry const* GetBattlegroundBracketById(uint32 mapid, BattlegroundBracketId id); +CharStartOutfitEntry const* GetCharStartOutfitEntry(uint8 race, uint8 class_, uint8 gender); + extern DBCStorage <AchievementEntry> sAchievementStore; extern DBCStorage <AchievementCriteriaEntry> sAchievementCriteriaStore; extern DBCStorage <AreaTableEntry> sAreaStore;// recommend access using functions diff --git a/src/server/game/DataStores/DBCStructure.h b/src/server/game/DataStores/DBCStructure.h index aa19863ec29..9636d5e0f35 100644 --- a/src/server/game/DataStores/DBCStructure.h +++ b/src/server/game/DataStores/DBCStructure.h @@ -76,7 +76,7 @@ struct AchievementCriteriaEntry union { // ACHIEVEMENT_CRITERIA_TYPE_KILL_CREATURE = 0 - // TODO: also used for player deaths.. + /// @todo also used for player deaths.. struct { uint32 creatureID; // 3 @@ -288,14 +288,14 @@ struct AchievementCriteriaEntry // ACHIEVEMENT_CRITERIA_TYPE_EXPLORE_AREA = 43 struct { - // TODO: This rank is _NOT_ the index from AreaTable.dbc + /// @todo This rank is _NOT_ the index from AreaTable.dbc uint32 areaReference; // 3 } explore_area; // ACHIEVEMENT_CRITERIA_TYPE_OWN_RANK = 44 struct { - // TODO: This rank is _NOT_ the index from CharTitles.dbc + /// @todo This rank is _NOT_ the index from CharTitles.dbc uint32 rank; // 3 } own_rank; @@ -328,7 +328,7 @@ struct AchievementCriteriaEntry } visit_barber; // ACHIEVEMENT_CRITERIA_TYPE_EQUIP_EPIC_ITEM = 49 - // TODO: where is the required itemlevel stored? + /// @todo where is the required itemlevel stored? struct { uint32 itemSlot; // 3 @@ -363,7 +363,7 @@ struct AchievementCriteriaEntry } hk_race; // ACHIEVEMENT_CRITERIA_TYPE_DO_EMOTE = 54 - // TODO: where is the information about the target stored? + /// @todo where is the information about the target stored? struct { uint32 emoteID; // 3 enum TextEmotes @@ -413,7 +413,7 @@ struct AchievementCriteriaEntry } use_gameobject; // ACHIEVEMENT_CRITERIA_TYPE_SPECIAL_PVP_KILL = 70 - // TODO: are those special criteria stored in the dbc or do we have to add another sql table? + /// @todo are those special criteria stored in the dbc or do we have to add another sql table? struct { uint32 unused; // 3 @@ -629,13 +629,13 @@ struct BattlemasterListEntry struct CharStartOutfitEntry { //uint32 Id; // 0 - uint32 RaceClassGender; // 1 (UNIT_FIELD_BYTES_0 & 0x00FFFFFF) comparable (0 byte = race, 1 byte = class, 2 byte = gender) - int32 ItemId[MAX_OUTFIT_ITEMS]; // 2-13 - //int32 ItemDisplayId[MAX_OUTFIT_ITEMS]; // 14-25 not required at server side - //int32 ItemInventorySlot[MAX_OUTFIT_ITEMS]; // 26-37 not required at server side - //uint32 Unknown1; // 38, unique values (index-like with gaps ordered in other way as ids) - //uint32 Unknown2; // 39 - //uint32 Unknown3; // 40 + uint8 Race; // 1 + uint8 Class; // 2 + uint8 Gender; // 3 + //uint8 Unused; // 4 + int32 ItemId[MAX_OUTFIT_ITEMS]; // 5-28 + //int32 ItemDisplayId[MAX_OUTFIT_ITEMS]; // 29-52 not required at server side + //int32 ItemInventorySlot[MAX_OUTFIT_ITEMS]; // 53-76 not required at server side }; struct CharTitlesEntry diff --git a/src/server/game/DataStores/DBCfmt.h b/src/server/game/DataStores/DBCfmt.h index 1395440fb6d..c82fdf868b3 100644 --- a/src/server/game/DataStores/DBCfmt.h +++ b/src/server/game/DataStores/DBCfmt.h @@ -19,111 +19,110 @@ #ifndef TRINITY_DBCSFRM_H #define TRINITY_DBCSFRM_H -char const Achievementfmt[]="niixssssssssssssssssxxxxxxxxxxxxxxxxxxiixixxxxxxxxxxxxxxxxxxii"; -const std::string CustomAchievementfmt="pppaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaapapaaaaaaaaaaaaaaaaaapp"; +char const Achievementfmt[] = "niixssssssssssssssssxxxxxxxxxxxxxxxxxxiixixxxxxxxxxxxxxxxxxxii"; +const std::string CustomAchievementfmt = "pppaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaapapaaaaaaaaaaaaaaaaaapp"; const std::string CustomAchievementIndex = "ID"; -char const AchievementCriteriafmt[]="niiiiiiiixxxxxxxxxxxxxxxxxiiiix"; -char const AreaTableEntryfmt[]="iiinixxxxxissssssssssssssssxiiiiixxx"; -char const AreaGroupEntryfmt[]="niiiiiii"; -char const AreaPOIEntryfmt[]="niiiiiiiiiiifffixixxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxix"; -char const AreaTriggerEntryfmt[]="niffffffff"; -char const AuctionHouseEntryfmt[]="niiixxxxxxxxxxxxxxxxx"; -char const BankBagSlotPricesEntryfmt[]="ni"; -char const BarberShopStyleEntryfmt[]="nixxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxiii"; -char const BattlemasterListEntryfmt[]="niiiiiiiiixssssssssssssssssxiixx"; -char const CharStartOutfitEntryfmt[]="diiiiiiiiiiiiiiiiiiiiiiiiixxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"; -char const CharTitlesEntryfmt[]="nxssssssssssssssssxxxxxxxxxxxxxxxxxxi"; -char const ChatChannelsEntryfmt[]="nixssssssssssssssssxxxxxxxxxxxxxxxxxx"; - // ChatChannelsEntryfmt, index not used (more compact store) -char const ChrClassesEntryfmt[]="nxixxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxixii"; -char const ChrRacesEntryfmt[]="nxixiixixxxxixssssssssssssssssxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxi"; -char const CinematicSequencesEntryfmt[]="nxxxxxxxxx"; -char const CreatureDisplayInfofmt[]="nixxfxxxxxxxxxxx"; -char const CreatureFamilyfmt[]="nfifiiiiixssssssssssssssssxx"; -char const CreatureModelDatafmt[]="nxxxfxxxxxxxxxxffxxxxxxxxxxx"; -char const CreatureSpellDatafmt[]="niiiixxxx"; -char const CreatureTypefmt[]="nxxxxxxxxxxxxxxxxxx"; -char const CurrencyTypesfmt[]="xnxi"; -char const DestructibleModelDatafmt[]="nxxixxxixxxixxxixxx"; -char const DungeonEncounterfmt[]="niixissssssssssssssssxx"; -char const DurabilityCostsfmt[]="niiiiiiiiiiiiiiiiiiiiiiiiiiiii"; -char const DurabilityQualityfmt[]="nf"; -char const EmotesEntryfmt[]="nxxiiix"; -char const EmotesTextEntryfmt[]="nxixxxxxxxxxxxxxxxx"; -char const FactionEntryfmt[]="niiiiiiiiiiiiiiiiiiffixssssssssssssssssxxxxxxxxxxxxxxxxxx"; -char const FactionTemplateEntryfmt[]="niiiiiiiiiiiii"; -char const GameObjectDisplayInfofmt[]="nsxxxxxxxxxxffffffx"; -char const GemPropertiesEntryfmt[]="nixxi"; -char const GlyphPropertiesfmt[]="niii"; -char const GlyphSlotfmt[]="nii"; -char const GtBarberShopCostBasefmt[]="f"; -char const GtCombatRatingsfmt[]="f"; -char const GtChanceToMeleeCritBasefmt[]="f"; -char const GtChanceToMeleeCritfmt[]="f"; -char const GtChanceToSpellCritBasefmt[]="f"; -char const GtChanceToSpellCritfmt[]="f"; -char const GtOCTClassCombatRatingScalarfmt[]="df"; -char const GtOCTRegenHPfmt[]="f"; -//char const GtOCTRegenMPfmt[]="f"; -char const GtRegenHPPerSptfmt[]="f"; -char const GtRegenMPPerSptfmt[]="f"; -char const Holidaysfmt[]="niiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiixxsiix"; -char const Itemfmt[]="niiiiiii"; -char const ItemBagFamilyfmt[]="nxxxxxxxxxxxxxxxxx"; -//char const ItemDisplayTemplateEntryfmt[]="nxxxxxxxxxxixxxxxxxxxxx"; -//char const ItemCondExtCostsEntryfmt[]="xiii"; -char const ItemExtendedCostEntryfmt[]="niiiiiiiiiiiiiix"; -char const ItemLimitCategoryEntryfmt[]="nxxxxxxxxxxxxxxxxxii"; -char const ItemRandomPropertiesfmt[]="nxiiixxssssssssssssssssx"; -char const ItemRandomSuffixfmt[]="nssssssssssssssssxxiiixxiiixx"; -char const ItemSetEntryfmt[]="dssssssssssssssssxiiiiiiiiiixxxxxxxiiiiiiiiiiiiiiiiii"; -char const LFGDungeonEntryfmt[]="nssssssssssssssssxiiiiiiiiixxixixxxxxxxxxxxxxxxxx"; -char const LiquidTypefmt[]="nxxixixxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"; -char const LockEntryfmt[]="niiiiiiiiiiiiiiiiiiiiiiiixxxxxxxx"; -char const MailTemplateEntryfmt[]="nxxxxxxxxxxxxxxxxxssssssssssssssssx"; -char const MapEntryfmt[]="nxixxssssssssssssssssxixxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxixiffxiix"; -char const MapDifficultyEntryfmt[]="diisxxxxxxxxxxxxxxxxiix"; -char const MovieEntryfmt[]="nxx"; -char const OverrideSpellDatafmt[]="niiiiiiiiiix"; -char const QuestSortEntryfmt[]="nxxxxxxxxxxxxxxxxx"; -char const QuestXPfmt[]="niiiiiiiiii"; -char const QuestFactionRewardfmt[]="niiiiiiiiii"; -char const PvPDifficultyfmt[]="diiiii"; -char const RandomPropertiesPointsfmt[]="niiiiiiiiiiiiiii"; -char const ScalingStatDistributionfmt[]="niiiiiiiiiiiiiiiiiiiii"; -char const ScalingStatValuesfmt[]="iniiiiiiiiiiiiiiiiiiiiii"; -char const SkillLinefmt[]="nixssssssssssssssssxxxxxxxxxxxxxxxxxxixxxxxxxxxxxxxxxxxi"; -char const SkillLineAbilityfmt[]="niiiixxiiiiixx"; -char const SoundEntriesfmt[]="nxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"; -char const SpellCastTimefmt[]="nixx"; -char const SpellDifficultyfmt[]="niiii"; -const std::string CustomSpellDifficultyfmt="ppppp"; -const std::string CustomSpellDifficultyIndex="id"; -char const SpellDurationfmt[]="niii"; -char const SpellEntryfmt[]="niiiiiiiiiiiixixiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiifxiiiiiiiiiiiiiiiiiiiiiiiiiiiifffiiiiiiiiiiiiiiiiiiiiifffiiiiiiiiiiiiiiifffiiiiiiiiiiiiixssssssssssssssssxssssssssssssssssxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxiiiiiiiiiiixfffxxxiiiiixxfffxx"; -const std::string CustomSpellEntryfmt="papppppppppppapapaaaaaaaaaaapaaapapppppppaaaaapaapaaaaaaaaaaaaaaaaaappppppppppppppppppppppppppppppppppppaaaaaapppppppppaaapppppppppaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaappppppppapppaaaaappaaaaaaa"; +char const AchievementCriteriafmt[] = "niiiiiiiixxxxxxxxxxxxxxxxxiiiix"; +char const AreaTableEntryfmt[] = "iiinixxxxxissssssssssssssssxiiiiixxx"; +char const AreaGroupEntryfmt[] = "niiiiiii"; +char const AreaPOIEntryfmt[] = "niiiiiiiiiiifffixixxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxix"; +char const AreaTriggerEntryfmt[] = "niffffffff"; +char const AuctionHouseEntryfmt[] = "niiixxxxxxxxxxxxxxxxx"; +char const BankBagSlotPricesEntryfmt[] = "ni"; +char const BarberShopStyleEntryfmt[] = "nixxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxiii"; +char const BattlemasterListEntryfmt[] = "niiiiiiiiixssssssssssssssssxiixx"; +char const CharStartOutfitEntryfmt[] = "dbbbXiiiiiiiiiiiiiiiiiiiiiiiixxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"; +char const CharTitlesEntryfmt[] = "nxssssssssssssssssxxxxxxxxxxxxxxxxxxi"; +char const ChatChannelsEntryfmt[] = "nixssssssssssssssssxxxxxxxxxxxxxxxxxx"; +char const ChrClassesEntryfmt[] = "nxixxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxixii"; +char const ChrRacesEntryfmt[] = "nxixiixixxxxixssssssssssssssssxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxi"; +char const CinematicSequencesEntryfmt[] = "nxxxxxxxxx"; +char const CreatureDisplayInfofmt[] = "nixxfxxxxxxxxxxx"; +char const CreatureFamilyfmt[] = "nfifiiiiixssssssssssssssssxx"; +char const CreatureModelDatafmt[] = "nxxxfxxxxxxxxxxffxxxxxxxxxxx"; +char const CreatureSpellDatafmt[] = "niiiixxxx"; +char const CreatureTypefmt[] = "nxxxxxxxxxxxxxxxxxx"; +char const CurrencyTypesfmt[] = "xnxi"; +char const DestructibleModelDatafmt[] = "nxxixxxixxxixxxixxx"; +char const DungeonEncounterfmt[] = "niixissssssssssssssssxx"; +char const DurabilityCostsfmt[] = "niiiiiiiiiiiiiiiiiiiiiiiiiiiii"; +char const DurabilityQualityfmt[] = "nf"; +char const EmotesEntryfmt[] = "nxxiiix"; +char const EmotesTextEntryfmt[] = "nxixxxxxxxxxxxxxxxx"; +char const FactionEntryfmt[] = "niiiiiiiiiiiiiiiiiiffixssssssssssssssssxxxxxxxxxxxxxxxxxx"; +char const FactionTemplateEntryfmt[] = "niiiiiiiiiiiii"; +char const GameObjectDisplayInfofmt[] = "nsxxxxxxxxxxffffffx"; +char const GemPropertiesEntryfmt[] = "nixxi"; +char const GlyphPropertiesfmt[] = "niii"; +char const GlyphSlotfmt[] = "nii"; +char const GtBarberShopCostBasefmt[] = "f"; +char const GtCombatRatingsfmt[] = "f"; +char const GtChanceToMeleeCritBasefmt[] = "f"; +char const GtChanceToMeleeCritfmt[] = "f"; +char const GtChanceToSpellCritBasefmt[] = "f"; +char const GtChanceToSpellCritfmt[] = "f"; +char const GtOCTClassCombatRatingScalarfmt[] = "df"; +char const GtOCTRegenHPfmt[] = "f"; +//char const GtOCTRegenMPfmt[] = "f"; +char const GtRegenHPPerSptfmt[] = "f"; +char const GtRegenMPPerSptfmt[] = "f"; +char const Holidaysfmt[] = "niiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiixxsiix"; +char const Itemfmt[] = "niiiiiii"; +char const ItemBagFamilyfmt[] = "nxxxxxxxxxxxxxxxxx"; +//char const ItemDisplayTemplateEntryfmt[] = "nxxxxxxxxxxixxxxxxxxxxx"; +//char const ItemCondExtCostsEntryfmt[] = "xiii"; +char const ItemExtendedCostEntryfmt[] = "niiiiiiiiiiiiiix"; +char const ItemLimitCategoryEntryfmt[] = "nxxxxxxxxxxxxxxxxxii"; +char const ItemRandomPropertiesfmt[] = "nxiiixxssssssssssssssssx"; +char const ItemRandomSuffixfmt[] = "nssssssssssssssssxxiiixxiiixx"; +char const ItemSetEntryfmt[] = "dssssssssssssssssxiiiiiiiiiixxxxxxxiiiiiiiiiiiiiiiiii"; +char const LFGDungeonEntryfmt[] = "nssssssssssssssssxiiiiiiiiixxixixxxxxxxxxxxxxxxxx"; +char const LiquidTypefmt[] = "nxxixixxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"; +char const LockEntryfmt[] = "niiiiiiiiiiiiiiiiiiiiiiiixxxxxxxx"; +char const MailTemplateEntryfmt[] = "nxxxxxxxxxxxxxxxxxssssssssssssssssx"; +char const MapEntryfmt[] = "nxixxssssssssssssssssxixxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxixiffxiix"; +char const MapDifficultyEntryfmt[] = "diisxxxxxxxxxxxxxxxxiix"; +char const MovieEntryfmt[] = "nxx"; +char const OverrideSpellDatafmt[] = "niiiiiiiiiix"; +char const QuestFactionRewardfmt[] = "niiiiiiiiii"; +char const QuestSortEntryfmt[] = "nxxxxxxxxxxxxxxxxx"; +char const QuestXPfmt[] = "niiiiiiiiii"; +char const PvPDifficultyfmt[] = "diiiii"; +char const RandomPropertiesPointsfmt[] = "niiiiiiiiiiiiiii"; +char const ScalingStatDistributionfmt[] = "niiiiiiiiiiiiiiiiiiiii"; +char const ScalingStatValuesfmt[] = "iniiiiiiiiiiiiiiiiiiiiii"; +char const SkillLinefmt[] = "nixssssssssssssssssxxxxxxxxxxxxxxxxxxixxxxxxxxxxxxxxxxxi"; +char const SkillLineAbilityfmt[] = "niiiixxiiiiixx"; +char const SoundEntriesfmt[] = "nxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"; +char const SpellCastTimefmt[] = "nixx"; +char const SpellDifficultyfmt[] = "niiii"; +const std::string CustomSpellDifficultyfmt = "ppppp"; +const std::string CustomSpellDifficultyIndex = "id"; +char const SpellDurationfmt[] = "niii"; +char const SpellEntryfmt[] = "niiiiiiiiiiiixixiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiifxiiiiiiiiiiiiiiiiiiiiiiiiiiiifffiiiiiiiiiiiiiiiiiiiiifffiiiiiiiiiiiiiiifffiiiiiiiiiiiiixssssssssssssssssxssssssssssssssssxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxiiiiiiiiiiixfffxxxiiiiixxfffxx"; +const std::string CustomSpellEntryfmt = "papppppppppppapapaaaaaaaaaaapaaapapppppppaaaaapaapaaaaaaaaaaaaaaaaaappppppppppppppppppppppppppppppppppppaaaaaapppppppppaaapppppppppaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaappppppppapppaaaaappaaaaaaa"; const std::string CustomSpellEntryIndex = "Id"; -char const SpellFocusObjectfmt[]="nxxxxxxxxxxxxxxxxx"; -char const SpellItemEnchantmentfmt[]="nxiiiiiixxxiiissssssssssssssssxiiiiiii"; -char const SpellItemEnchantmentConditionfmt[]="nbbbbbxxxxxbbbbbbbbbbiiiiiXXXXX"; -char const SpellRadiusfmt[]="nfff"; -char const SpellRangefmt[]="nffffixxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"; -char const SpellRuneCostfmt[]="niiii"; -char const SpellShapeshiftfmt[]="nxxxxxxxxxxxxxxxxxxiixiiixxiiiiiiii"; +char const SpellFocusObjectfmt[] = "nxxxxxxxxxxxxxxxxx"; +char const SpellItemEnchantmentfmt[] = "nxiiiiiixxxiiissssssssssssssssxiiiiiii"; +char const SpellItemEnchantmentConditionfmt[] = "nbbbbbxxxxxbbbbbbbbbbiiiiiXXXXX"; +char const SpellRadiusfmt[] = "nfff"; +char const SpellRangefmt[] = "nffffixxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"; +char const SpellRuneCostfmt[] = "niiii"; +char const SpellShapeshiftfmt[] = "nxxxxxxxxxxxxxxxxxxiixiiixxiiiiiiii"; char const StableSlotPricesfmt[] = "ni"; char const SummonPropertiesfmt[] = "niiiii"; -char const TalentEntryfmt[]="niiiiiiiixxxxixxixxxxxx"; -char const TalentTabEntryfmt[]="nxxxxxxxxxxxxxxxxxxxiiix"; -char const TaxiNodesEntryfmt[]="nifffssssssssssssssssxii"; -char const TaxiPathEntryfmt[]="niii"; -char const TaxiPathNodeEntryfmt[]="diiifffiiii"; -char const TeamContributionPointsfmt[]="df"; -char const TotemCategoryEntryfmt[]="nxxxxxxxxxxxxxxxxxii"; -char const VehicleEntryfmt[]="niffffiiiiiiiifffffffffffffffssssfifiixx"; -char const VehicleSeatEntryfmt[]="niiffffffffffiiiiiifffffffiiifffiiiiiiiffiiiiixxxxxxxxxxxx"; -char const WMOAreaTableEntryfmt[]="niiixxxxxiixxxxxxxxxxxxxxxxx"; -char const WorldMapAreaEntryfmt[]="xinxffffixx"; -char const WorldMapOverlayEntryfmt[]="nxiiiixxxxxxxxxxx"; -char const WorldSafeLocsEntryfmt[]="nifffxxxxxxxxxxxxxxxxx"; +char const TalentEntryfmt[] = "niiiiiiiixxxxixxixxxxxx"; +char const TalentTabEntryfmt[] = "nxxxxxxxxxxxxxxxxxxxiiix"; +char const TaxiNodesEntryfmt[] = "nifffssssssssssssssssxii"; +char const TaxiPathEntryfmt[] = "niii"; +char const TaxiPathNodeEntryfmt[] = "diiifffiiii"; +char const TeamContributionPointsfmt[] = "df"; +char const TotemCategoryEntryfmt[] = "nxxxxxxxxxxxxxxxxxii"; +char const VehicleEntryfmt[] = "niffffiiiiiiiifffffffffffffffssssfifiixx"; +char const VehicleSeatEntryfmt[] = "niiffffffffffiiiiiifffffffiiifffiiiiiiiffiiiiixxxxxxxxxxxx"; +char const WMOAreaTableEntryfmt[] = "niiixxxxxiixxxxxxxxxxxxxxxxx"; +char const WorldMapAreaEntryfmt[] = "xinxffffixx"; +char const WorldMapOverlayEntryfmt[] = "nxiiiixxxxxxxxxxx"; +char const WorldSafeLocsEntryfmt[] = "nifffxxxxxxxxxxxxxxxxx"; #endif diff --git a/src/server/game/DungeonFinding/LFG.cpp b/src/server/game/DungeonFinding/LFG.cpp new file mode 100644 index 00000000000..ce16ad5533e --- /dev/null +++ b/src/server/game/DungeonFinding/LFG.cpp @@ -0,0 +1,108 @@ +/* + * Copyright (C) 2008-2013 TrinityCore <http://www.trinitycore.org/> + * + * 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 2 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/>. + */ + +#include "LFG.h" +#include "Language.h" +#include "ObjectMgr.h" + +namespace lfg +{ + +std::string ConcatenateDungeons(LfgDungeonSet const& dungeons) +{ + std::string dungeonstr = ""; + if (!dungeons.empty()) + { + std::ostringstream o; + LfgDungeonSet::const_iterator it = dungeons.begin(); + o << (*it); + for (++it; it != dungeons.end(); ++it) + o << ", " << uint32(*it); + dungeonstr = o.str(); + } + return dungeonstr; +} + +std::string GetRolesString(uint8 roles) +{ + std::string rolesstr = ""; + + if (roles & PLAYER_ROLE_TANK) + rolesstr.append(sObjectMgr->GetTrinityStringForDBCLocale(LANG_LFG_ROLE_TANK)); + + if (roles & PLAYER_ROLE_HEALER) + { + if (!rolesstr.empty()) + rolesstr.append(", "); + rolesstr.append(sObjectMgr->GetTrinityStringForDBCLocale(LANG_LFG_ROLE_HEALER)); + } + + if (roles & PLAYER_ROLE_DAMAGE) + { + if (!rolesstr.empty()) + rolesstr.append(", "); + rolesstr.append(sObjectMgr->GetTrinityStringForDBCLocale(LANG_LFG_ROLE_DAMAGE)); + } + + if (roles & PLAYER_ROLE_LEADER) + { + if (!rolesstr.empty()) + rolesstr.append(", "); + rolesstr.append(sObjectMgr->GetTrinityStringForDBCLocale(LANG_LFG_ROLE_LEADER)); + } + + if (rolesstr.empty()) + rolesstr.append(sObjectMgr->GetTrinityStringForDBCLocale(LANG_LFG_ROLE_NONE)); + + return rolesstr; +} + +std::string GetStateString(LfgState state) +{ + int32 entry = LANG_LFG_ERROR; + switch (state) + { + case LFG_STATE_NONE: + entry = LANG_LFG_STATE_NONE; + break; + case LFG_STATE_ROLECHECK: + entry = LANG_LFG_STATE_ROLECHECK; + break; + case LFG_STATE_QUEUED: + entry = LANG_LFG_STATE_QUEUED; + break; + case LFG_STATE_PROPOSAL: + entry = LANG_LFG_STATE_PROPOSAL; + break; + case LFG_STATE_DUNGEON: + entry = LANG_LFG_STATE_DUNGEON; + break; + case LFG_STATE_BOOT: + entry = LANG_LFG_STATE_BOOT; + break; + case LFG_STATE_FINISHED_DUNGEON: + entry = LANG_LFG_STATE_FINISHED_DUNGEON; + break; + case LFG_STATE_RAIDBROWSER: + entry = LANG_LFG_STATE_RAIDBROWSER; + break; + } + + return std::string(sObjectMgr->GetTrinityStringForDBCLocale(entry)); +} + +} // namespace lfg diff --git a/src/server/game/DungeonFinding/LFG.h b/src/server/game/DungeonFinding/LFG.h index ebbcfb1d71a..541e4d6bd43 100644 --- a/src/server/game/DungeonFinding/LFG.h +++ b/src/server/game/DungeonFinding/LFG.h @@ -20,6 +20,9 @@ #include "Common.h" +namespace lfg +{ + enum LFGEnum { LFG_TANKS_NEEDED = 1, @@ -99,4 +102,10 @@ typedef std::list<uint64> LfgGuidList; typedef std::map<uint64, uint8> LfgRolesMap; typedef std::map<uint64, uint64> LfgGroupsMap; +std::string ConcatenateDungeons(LfgDungeonSet const& dungeons); +std::string GetRolesString(uint8 roles); +std::string GetStateString(LfgState state); + +} // namespace lfg + #endif diff --git a/src/server/game/DungeonFinding/LFGGroupData.cpp b/src/server/game/DungeonFinding/LFGGroupData.cpp index 427225bf323..f711514e26d 100644 --- a/src/server/game/DungeonFinding/LFGGroupData.cpp +++ b/src/server/game/DungeonFinding/LFGGroupData.cpp @@ -18,6 +18,9 @@ #include "LFG.h" #include "LFGGroupData.h" +namespace lfg +{ + LfgGroupData::LfgGroupData(): m_State(LFG_STATE_NONE), m_OldState(LFG_STATE_NONE), m_Leader(0), m_Dungeon(0), m_KicksLeft(LFG_GROUP_MAX_KICKS) { } @@ -122,3 +125,5 @@ uint8 LfgGroupData::GetKicksLeft() const { return m_KicksLeft; } + +} // namespace lfg diff --git a/src/server/game/DungeonFinding/LFGGroupData.h b/src/server/game/DungeonFinding/LFGGroupData.h index 2ad020d3bc1..47e562c37aa 100644 --- a/src/server/game/DungeonFinding/LFGGroupData.h +++ b/src/server/game/DungeonFinding/LFGGroupData.h @@ -20,6 +20,9 @@ #include "LFG.h" +namespace lfg +{ + enum LfgGroupEnum { LFG_GROUP_MAX_KICKS = 3, @@ -75,4 +78,6 @@ class LfgGroupData uint8 m_KicksLeft; ///< Number of kicks left }; +} // namespace lfg + #endif diff --git a/src/server/game/DungeonFinding/LFGMgr.cpp b/src/server/game/DungeonFinding/LFGMgr.cpp index 9d5d8e40b54..9fc880c3f4a 100644 --- a/src/server/game/DungeonFinding/LFGMgr.cpp +++ b/src/server/game/DungeonFinding/LFGMgr.cpp @@ -29,10 +29,14 @@ #include "LFGQueue.h" #include "Group.h" #include "Player.h" +#include "RBAC.h" #include "GroupMgr.h" #include "GameEventMgr.h" #include "WorldSession.h" +namespace lfg +{ + LFGMgr::LFGMgr(): m_QueueTimer(0), m_lfgProposalId(1), m_options(sWorld->getIntConfig(CONFIG_LFG_OPTIONSMASK)) { @@ -95,89 +99,6 @@ void LFGMgr::_SaveToDB(uint64 guid, uint32 db_guid) CharacterDatabase.Execute(stmt); } -std::string LFGMgr::ConcatenateDungeons(LfgDungeonSet const& dungeons) -{ - std::string dungeonstr = ""; - if (!dungeons.empty()) - { - std::ostringstream o; - LfgDungeonSet::const_iterator it = dungeons.begin(); - o << (*it); - for (++it; it != dungeons.end(); ++it) - o << ", " << uint32(*it); - dungeonstr = o.str(); - } - return dungeonstr; -} - -std::string LFGMgr::GetRolesString(uint8 roles) -{ - std::string rolesstr = ""; - - if (roles & PLAYER_ROLE_TANK) - rolesstr.append(sObjectMgr->GetTrinityStringForDBCLocale(LANG_LFG_ROLE_TANK)); - - if (roles & PLAYER_ROLE_HEALER) - { - if (!rolesstr.empty()) - rolesstr.append(", "); - rolesstr.append(sObjectMgr->GetTrinityStringForDBCLocale(LANG_LFG_ROLE_HEALER)); - } - - if (roles & PLAYER_ROLE_DAMAGE) - { - if (!rolesstr.empty()) - rolesstr.append(", "); - rolesstr.append(sObjectMgr->GetTrinityStringForDBCLocale(LANG_LFG_ROLE_DAMAGE)); - } - - if (roles & PLAYER_ROLE_LEADER) - { - if (!rolesstr.empty()) - rolesstr.append(", "); - rolesstr.append(sObjectMgr->GetTrinityStringForDBCLocale(LANG_LFG_ROLE_LEADER)); - } - - if (rolesstr.empty()) - rolesstr.append(sObjectMgr->GetTrinityStringForDBCLocale(LANG_LFG_ROLE_NONE)); - - return rolesstr; -} - -std::string LFGMgr::GetStateString(LfgState state) -{ - int32 entry = LANG_LFG_ERROR; - switch (state) - { - case LFG_STATE_NONE: - entry = LANG_LFG_STATE_NONE; - break; - case LFG_STATE_ROLECHECK: - entry = LANG_LFG_STATE_ROLECHECK; - break; - case LFG_STATE_QUEUED: - entry = LANG_LFG_STATE_QUEUED; - break; - case LFG_STATE_PROPOSAL: - entry = LANG_LFG_STATE_PROPOSAL; - break; - case LFG_STATE_DUNGEON: - entry = LANG_LFG_STATE_DUNGEON; - break; - case LFG_STATE_BOOT: - entry = LANG_LFG_STATE_BOOT; - break; - case LFG_STATE_FINISHED_DUNGEON: - entry = LANG_LFG_STATE_FINISHED_DUNGEON; - break; - case LFG_STATE_RAIDBROWSER: - entry = LANG_LFG_STATE_RAIDBROWSER; - break; - } - - return std::string(sObjectMgr->GetTrinityStringForDBCLocale(entry)); -} - /// Load rewards for completing dungeons void LFGMgr::LoadRewards() { @@ -207,7 +128,7 @@ void LFGMgr::LoadRewards() uint32 firstQuestId = fields[2].GetUInt32(); uint32 otherQuestId = fields[3].GetUInt32(); - if (!GetLFGDungeon(dungeonId)) + if (!GetLFGDungeonEntry(dungeonId)) { sLog->outError(LOG_FILTER_SQL, "Dungeon %u specified in table `lfg_dungeon_rewards` does not exist!", dungeonId); continue; @@ -248,11 +169,6 @@ LFGDungeonData const* LFGMgr::GetLFGDungeon(uint32 id) return NULL; } -LFGDungeonContainer & LFGMgr::GetLFGDungeonMap() -{ - return LfgDungeonStore; -} - void LFGMgr::LoadLFGDungeons(bool reload /* = false */) { uint32 oldMSTime = getMSTime(); @@ -282,7 +198,7 @@ void LFGMgr::LoadLFGDungeons(bool reload /* = false */) if (!result) { - sLog->outError(LOG_FILTER_SQL, ">> Loaded 0 lfg entrance positions. DB table `lfg_entrances` is empty!"); + sLog->outError(LOG_FILTER_SERVER_LOADING, ">> Loaded 0 lfg entrance positions. DB table `lfg_entrances` is empty!"); return; } @@ -464,6 +380,7 @@ void LFGMgr::InitializeLockedDungeons(Player* player, uint8 level /* = 0 */) uint8 expansion = player->GetSession()->Expansion(); LfgDungeonSet const& dungeons = GetDungeonsByRandom(0); LfgLockMap lock; + bool denyJoin = !player->GetSession()->HasPermission(RBAC_PERM_JOIN_DUNGEON_FINDER); for (LfgDungeonSet::const_iterator it = dungeons.begin(); it != dungeons.end(); ++it) { @@ -472,7 +389,9 @@ void LFGMgr::InitializeLockedDungeons(Player* player, uint8 level /* = 0 */) continue; uint32 lockData = 0; - if (dungeon->expansion > expansion) + if (denyJoin) + lockData = LFG_LOCKSTATUS_RAID_LOCKED; + else if (dungeon->expansion > expansion) lockData = LFG_LOCKSTATUS_INSUFFICIENT_EXPANSION; else if (DisableMgr::IsDisabledFor(DISABLE_TYPE_MAP, dungeon->map, player)) lockData = LFG_LOCKSTATUS_RAID_LOCKED; @@ -502,7 +421,7 @@ void LFGMgr::InitializeLockedDungeons(Player* player, uint8 level /* = 0 */) lockData = LFG_LOCKSTATUS_MISSING_ITEM; } - /* TODO VoA closed if WG is not under team control (LFG_LOCKSTATUS_RAID_LOCKED) + /* @todo VoA closed if WG is not under team control (LFG_LOCKSTATUS_RAID_LOCKED) lockData = LFG_LOCKSTATUS_TOO_LOW_GEAR_SCORE; lockData = LFG_LOCKSTATUS_TOO_HIGH_GEAR_SCORE; lockData = LFG_LOCKSTATUS_ATTUNEMENT_TOO_LOW_LEVEL; @@ -554,7 +473,9 @@ void LFGMgr::JoinLfg(Player* player, uint8 roles, LfgDungeonSet& dungeons, const } // Check player or group member restrictions - if (player->InBattleground() || player->InArena() || player->InBattlegroundQueue()) + if (!player->GetSession()->HasPermission(RBAC_PERM_JOIN_DUNGEON_FINDER)) + joinData.result = LFG_JOIN_NOT_MEET_REQS; + else if (player->InBattleground() || player->InArena() || player->InBattlegroundQueue()) joinData.result = LFG_JOIN_USING_BG_SYSTEM; else if (player->HasAura(LFG_SPELL_DUNGEON_DESERTER)) joinData.result = LFG_JOIN_DESERTER; @@ -573,6 +494,8 @@ void LFGMgr::JoinLfg(Player* player, uint8 roles, LfgDungeonSet& dungeons, const { if (Player* plrg = itr->getSource()) { + if (!plrg->GetSession()->HasPermission(RBAC_PERM_JOIN_DUNGEON_FINDER)) + joinData.result = LFG_JOIN_PARTY_NOT_MEET_REQS; if (plrg->HasAura(LFG_SPELL_DUNGEON_DESERTER)) joinData.result = LFG_JOIN_PARTY_DESERTER; else if (plrg->HasAura(LFG_SPELL_DUNGEON_COOLDOWN)) @@ -1163,7 +1086,6 @@ void LFGMgr::UpdateProposal(uint32 proposalId, uint64 guid, bool accept) break; } - teleportStore.push_back(pguid); SetState(pguid, LFG_STATE_DUNGEON); } @@ -1398,10 +1320,7 @@ void LFGMgr::TeleportPlayer(Player* player, bool out, bool fromOpcode /*= false* sLog->outDebug(LOG_FILTER_LFG, "TeleportPlayer: Player %s is being teleported out. Current Map %u - Expected Map %u", player->GetName().c_str(), player->GetMapId(), uint32(dungeon->map)); if (player->GetMapId() == uint32(dungeon->map)) - { - player->RemoveAurasDueToSpell(LFG_SPELL_LUCK_OF_THE_DRAW); player->TeleportToBGEntryPoint(); - } return; } @@ -1563,7 +1482,6 @@ void LFGMgr::FinishDungeon(uint64 gguid, const uint32 dungeonId) LfgPlayerRewardData data = LfgPlayerRewardData(dungeon->Entry(), GetDungeon(gguid, false), done, quest); player->GetSession()->SendLfgPlayerReward(data); } - SetDungeon(gguid, 0); } // --------------------------------------------------------------------------// @@ -1632,6 +1550,18 @@ LfgState LFGMgr::GetState(uint64 guid) return state; } +LfgState LFGMgr::GetOldState(uint64 guid) +{ + LfgState state; + if (IS_GROUP_GUID(guid)) + state = GroupsStore[guid].GetOldState(); + else + state = PlayersStore[guid].GetOldState(); + + sLog->outTrace(LOG_FILTER_LFG, "LFGMgr::GetOldState: [" UI64FMTD "] = %u", guid, state); + return state; +} + uint32 LFGMgr::GetDungeon(uint64 guid, bool asId /*= true */) { uint32 dungeon = GroupsStore[guid].GetDungeon(asId); @@ -1664,16 +1594,6 @@ const std::string& LFGMgr::GetComment(uint64 guid) return PlayersStore[guid].GetComment(); } -bool LFGMgr::IsTeleported(uint64 pguid) -{ - if (std::find(teleportStore.begin(), teleportStore.end(), pguid) != teleportStore.end()) - { - teleportStore.remove(pguid); - return true; - } - return false; -} - LfgDungeonSet const& LFGMgr::GetSelectedDungeons(uint64 guid) { sLog->outTrace(LOG_FILTER_LFG, "LFGMgr::GetSelectedDungeons: [" UI64FMTD "]", guid); @@ -1693,7 +1613,7 @@ uint8 LFGMgr::GetKicksLeft(uint64 guid) return kicks; } -void LFGMgr::RestoreState(uint64 guid, char const *debugMsg) +void LFGMgr::RestoreState(uint64 guid, char const* debugMsg) { if (IS_GROUP_GUID(guid)) { @@ -2028,3 +1948,56 @@ void LFGMgr::SetupGroupMember(uint64 guid, uint64 gguid) SetGroup(guid, gguid); AddPlayerToGroup(gguid, guid); } + +bool LFGMgr::selectedRandomLfgDungeon(uint64 guid) +{ + if (GetState(guid) != LFG_STATE_NONE) + { + LfgDungeonSet const& dungeons = GetSelectedDungeons(guid); + if (!dungeons.empty()) + { + LFGDungeonData const* dungeon = GetLFGDungeon(*dungeons.begin()); + if (dungeon && (dungeon->type == LFG_TYPE_RANDOM || dungeon->seasonal)) + return true; + } + } + + return false; +} + +bool LFGMgr::inLfgDungeonMap(uint64 guid, uint32 map, Difficulty difficulty) +{ + if (!IS_GROUP_GUID(guid)) + guid = GetGroup(guid); + + if (uint32 dungeonId = GetDungeon(guid, true)) + if (LFGDungeonData const* dungeon = GetLFGDungeon(dungeonId)) + if (uint32(dungeon->map) == map && dungeon->difficulty == difficulty) + return true; + + return false; +} + +uint32 LFGMgr::GetLFGDungeonEntry(uint32 id) +{ + if (id) + if (LFGDungeonData const* dungeon = GetLFGDungeon(id)) + return dungeon->Entry(); + + return 0; +} + +LfgDungeonSet LFGMgr::GetRandomAndSeasonalDungeons(uint8 level, uint8 expansion) +{ + LfgDungeonSet randomDungeons; + for (lfg::LFGDungeonContainer::const_iterator itr = LfgDungeonStore.begin(); itr != LfgDungeonStore.end(); ++itr) + { + lfg::LFGDungeonData const& dungeon = itr->second; + if ((dungeon.type == lfg::LFG_TYPE_RANDOM || (dungeon.seasonal && sLFGMgr->IsSeasonActive(dungeon.id))) + && dungeon.expansion <= expansion && dungeon.minlevel <= level && level <= dungeon.maxlevel) + randomDungeons.insert(dungeon.Entry()); + } + return randomDungeons; +} + +} // namespace lfg diff --git a/src/server/game/DungeonFinding/LFGMgr.h b/src/server/game/DungeonFinding/LFGMgr.h index 0a1b90ee04d..96fedb65547 100644 --- a/src/server/game/DungeonFinding/LFGMgr.h +++ b/src/server/game/DungeonFinding/LFGMgr.h @@ -30,6 +30,9 @@ class Group; class Player; class Quest; +namespace lfg +{ + enum LfgOptions { LFG_OPTION_ENABLE_DUNGEON_FINDER = 0x01, @@ -296,98 +299,136 @@ class LFGMgr ~LFGMgr(); public: + // Functions used outside lfg namespace void Update(uint32 diff); - // Reward - void LoadRewards(); + // World.cpp + /// Finish the dungeon for the given group. All check are performed using internal lfg data void FinishDungeon(uint64 gguid, uint32 dungeonId); - LfgReward const* GetRandomDungeonReward(uint32 dungeon, uint8 level); - - // Queue - void JoinLfg(Player* player, uint8 roles, LfgDungeonSet& dungeons, std::string const& comment); - void LeaveLfg(uint64 guid); - - // Role Check - void UpdateRoleCheck(uint64 gguid, uint64 guid = 0, uint8 roles = PLAYER_ROLE_NONE); - - // Group Matching - static bool CheckGroupRoles(LfgRolesMap &groles, bool removeLeaderFlag = true); - void GetCompatibleDungeons(LfgDungeonSet& dungeons, LfgGuidSet const& players, LfgLockPartyMap& lockMap); - - // Proposals - uint32 AddProposal(LfgProposal& proposal); - void UpdateProposal(uint32 proposalId, uint64 guid, bool accept); + /// Loads rewards for random dungeons + void LoadRewards(); + /// Loads dungeons from dbc and adds teleport coords + void LoadLFGDungeons(bool reload = false); - // Teleportation - void TeleportPlayer(Player* player, bool out, bool fromOpcode = false); + // Multiple files + /// Check if given guid applied for random dungeon + bool selectedRandomLfgDungeon(uint64 guid); + /// Check if given guid applied for given map and difficulty. Used to know + bool inLfgDungeonMap(uint64 guid, uint32 map, Difficulty difficulty); + /// Get selected dungeons + LfgDungeonSet const& GetSelectedDungeons(uint64 guid); + /// Get current lfg state + LfgState GetState(uint64 guid); + /// Get current dungeon + uint32 GetDungeon(uint64 guid, bool asId = true); + /// Get the map id of the current dungeon + uint32 GetDungeonMapId(uint64 guid); + /// Get kicks left in current group + uint8 GetKicksLeft(uint64 gguid); + /// Load Lfg group info from DB + void _LoadFromDB(Field* fields, uint64 guid); + /// Initializes player data after loading group data from DB + void SetupGroupMember(uint64 guid, uint64 gguid); + /// Return Lfg dungeon entry for given dungeon id + uint32 GetLFGDungeonEntry(uint32 id); - // Vote kick - void InitBoot(uint64 gguid, uint64 kguid, uint64 vguid, std::string const& reason); - void UpdateBoot(uint64 guid, bool accept); + // cs_lfg + /// Get current player roles + uint8 GetRoles(uint64 guid); + /// Get current player comment (used for LFR) + std::string const& GetComment(uint64 gguid); + /// Gets current lfg options + uint32 GetOptions(); + /// Sets new lfg options + void SetOptions(uint32 options); + /// Checks if given lfg option is enabled + bool isOptionEnabled(uint32 option); + /// Clears queue - Only for internal testing + void Clean(); + /// Dumps the state of the queue - Only for internal testing + std::string DumpQueueInfo(bool full = false); + // LFGScripts + /// Get leader of the group (using internal data) + uint64 GetLeader(uint64 guid); + /// Initializes locked dungeons for given player (called at login or level change) void InitializeLockedDungeons(Player* player, uint8 level = 0); - - void SetRoles(uint64 guid, uint8 roles); - void SetComment(uint64 guid, std::string const& comment); + /// Sets player team void SetTeam(uint64 guid, uint8 team); + /// Sets player group void SetGroup(uint64 guid, uint64 group); + /// Gets player group + uint64 GetGroup(uint64 guid); + /// Sets the leader of the group void SetLeader(uint64 gguid, uint64 leader); - void SetState(uint64 guid, LfgState state); - - void _LoadFromDB(Field* fields, uint64 guid); - void _SaveToDB(uint64 guid, uint32 db_guid); - - void RemovePlayerData(uint64 guid); + /// Removes saved group data void RemoveGroupData(uint64 guid); + /// Removes a player from a group uint8 RemovePlayerFromGroup(uint64 gguid, uint64 guid); + /// Adds player to group void AddPlayerToGroup(uint64 gguid, uint64 guid); + // LFGHandler + /// Get locked dungeons LfgLockMap const& GetLockedDungeons(uint64 guid); - LfgDungeonSet const& GetSelectedDungeons(uint64 guid); - uint32 GetDungeon(uint64 guid, bool asId = true); - uint32 GetDungeonMapId(uint64 guid); - LfgState GetState(uint64 guid); - uint8 GetKicksLeft(uint64 gguid); - uint64 GetLeader(uint64 guid); + /// Returns current lfg status + LfgUpdateData GetLfgStatus(uint64 guid); + /// Checks if Seasonal dungeon is active + bool IsSeasonActive(uint32 dungeonId); + /// Gets the random dungeon reward corresponding to given dungeon and player level + LfgReward const* GetRandomDungeonReward(uint32 dungeon, uint8 level); + /// Returns all random and seasonal dungeons for given level and expansion + LfgDungeonSet GetRandomAndSeasonalDungeons(uint8 level, uint8 expansion); + /// Teleport a player to/from selected dungeon + void TeleportPlayer(Player* player, bool out, bool fromOpcode = false); + /// Inits new proposal to boot a player + void InitBoot(uint64 gguid, uint64 kguid, uint64 vguid, std::string const& reason); + /// Updates player boot proposal with new player answer + void UpdateBoot(uint64 guid, bool accept); + /// Updates proposal to join dungeon with player answer + void UpdateProposal(uint32 proposalId, uint64 guid, bool accept); + /// Updates the role check with player answer + void UpdateRoleCheck(uint64 gguid, uint64 guid = 0, uint8 roles = PLAYER_ROLE_NONE); + /// Sets player lfg roles + void SetRoles(uint64 guid, uint8 roles); + /// Sets player lfr comment + void SetComment(uint64 guid, std::string const& comment); + /// Join Lfg with selected roles, dungeons and comment + void JoinLfg(Player* player, uint8 roles, LfgDungeonSet& dungeons, std::string const& comment); + /// Leaves lfg + void LeaveLfg(uint64 guid); + + // LfgQueue + /// Get last lfg state (NONE, DUNGEON or FINISHED_DUNGEON) + LfgState GetOldState(uint64 guid); + /// Check if given group guid is lfg bool IsLfgGroup(uint64 guid); - uint8 GetRoles(uint64 guid); - std::string const& GetComment(uint64 gguid); - LfgGuidSet const& GetPlayers(uint64 guid); + /// Gets the player count of given group uint8 GetPlayerCount(uint64 guid); - - bool IsTeleported(uint64 guid); - + /// Add a new Proposal + uint32 AddProposal(LfgProposal& proposal); + /// Checks if all players are queued bool AllQueued(LfgGuidList const& check); - void Clean(); - + /// Checks if given roles match, modifies given roles map with new roles + static bool CheckGroupRoles(LfgRolesMap &groles, bool removeLeaderFlag = true); + /// Checks if given players are ignoring each other static bool HasIgnore(uint64 guid1, uint64 guid2); + /// Sends queue status to player static void SendLfgQueueStatus(uint64 guid, LfgQueueStatusData const& data); - bool isOptionEnabled(uint32 option); - uint32 GetOptions(); - void SetOptions(uint32 options); - LfgUpdateData GetLfgStatus(uint64 guid); - bool IsSeasonActive(uint32 dungeonId); - - std::string DumpQueueInfo(bool full = false); - static std::string ConcatenateDungeons(LfgDungeonSet const& dungeons); - static std::string GetRolesString(uint8 roles); - static std::string GetStateString(LfgState state); - - void LoadLFGDungeons(bool reload = false); - LFGDungeonData const* GetLFGDungeon(uint32 id); - LFGDungeonContainer& GetLFGDungeonMap(); - void SetupGroupMember(uint64 guid, uint64 gguid); - uint64 GetGroup(uint64 guid); - private: uint8 GetTeam(uint64 guid); - void RestoreState(uint64 guid, char const *debugMsg); - void ClearState(uint64 guid, char const *debugMsg); + void RestoreState(uint64 guid, char const* debugMsg); + void ClearState(uint64 guid, char const* debugMsg); void SetDungeon(uint64 guid, uint32 dungeon); void SetSelectedDungeons(uint64 guid, LfgDungeonSet const& dungeons); void SetLockedDungeons(uint64 guid, LfgLockMap const& lock); void DecreaseKicksLeft(uint64 guid); + void SetState(uint64 guid, LfgState state); + void RemovePlayerData(uint64 guid); + void GetCompatibleDungeons(LfgDungeonSet& dungeons, LfgGuidSet const& players, LfgLockPartyMap& lockMap); + void _SaveToDB(uint64 guid, uint32 db_guid); + LFGDungeonData const* GetLFGDungeon(uint32 id); // Proposals void RemoveProposal(LfgProposalContainer::iterator itProposal, LfgUpdateType type); @@ -406,6 +447,8 @@ class LFGMgr void SendLfgUpdatePlayer(uint64 guid, LfgUpdateData const& data); void SendLfgUpdateProposal(uint64 guid, LfgProposal const& proposal); + LfgGuidSet const& GetPlayers(uint64 guid); + // General variables uint32 m_QueueTimer; ///< used to check interval of update uint32 m_lfgProposalId; ///< used as internal counter for proposals @@ -422,8 +465,9 @@ class LFGMgr LfgPlayerBootContainer BootsStore; ///< Current player kicks LfgPlayerDataContainer PlayersStore; ///< Player data LfgGroupDataContainer GroupsStore; ///< Group data - LfgGuidList teleportStore; ///< Players being teleported }; -#define sLFGMgr ACE_Singleton<LFGMgr, ACE_Null_Mutex>::instance() +} // namespace lfg + +#define sLFGMgr ACE_Singleton<lfg::LFGMgr, ACE_Null_Mutex>::instance() #endif diff --git a/src/server/game/DungeonFinding/LFGPlayerData.cpp b/src/server/game/DungeonFinding/LFGPlayerData.cpp index 410076f7e75..e8ef430bc1f 100644 --- a/src/server/game/DungeonFinding/LFGPlayerData.cpp +++ b/src/server/game/DungeonFinding/LFGPlayerData.cpp @@ -17,6 +17,9 @@ #include "LFGPlayerData.h" +namespace lfg +{ + LfgPlayerData::LfgPlayerData(): m_State(LFG_STATE_NONE), m_OldState(LFG_STATE_NONE), m_Team(0), m_Group(0), m_Roles(0), m_Comment("") {} @@ -122,3 +125,5 @@ LfgDungeonSet const& LfgPlayerData::GetSelectedDungeons() const { return m_SelectedDungeons; } + +} // namespace lfg diff --git a/src/server/game/DungeonFinding/LFGPlayerData.h b/src/server/game/DungeonFinding/LFGPlayerData.h index 055924fd364..a425ce77bad 100644 --- a/src/server/game/DungeonFinding/LFGPlayerData.h +++ b/src/server/game/DungeonFinding/LFGPlayerData.h @@ -20,6 +20,9 @@ #include "LFG.h" +namespace lfg +{ + /** Stores all lfg data needed about the player. */ @@ -68,4 +71,6 @@ class LfgPlayerData LfgDungeonSet m_SelectedDungeons; ///< Selected Dungeons when joined LFG }; +} // namespace lfg + #endif diff --git a/src/server/game/DungeonFinding/LFGQueue.cpp b/src/server/game/DungeonFinding/LFGQueue.cpp index e75a1bdc4b3..6a98fccecdc 100644 --- a/src/server/game/DungeonFinding/LFGQueue.cpp +++ b/src/server/game/DungeonFinding/LFGQueue.cpp @@ -27,6 +27,9 @@ #include "World.h" #include "GroupMgr.h" +namespace lfg +{ + /** Given a list of guids returns the concatenation using | as delimiter @@ -431,7 +434,7 @@ LfgCompatibility LFGQueue::CheckCompatibility(LfgGuidList check) { std::ostringstream o; for (LfgRolesMap::const_iterator it = debugRoles.begin(); it != debugRoles.end(); ++it) - o << ", " << it->first << ": " << sLFGMgr->GetRolesString(it->second); + o << ", " << it->first << ": " << GetRolesString(it->second); sLog->outDebug(LOG_FILTER_LFG, "LFGQueue::CheckCompatibility: (%s) Roles not compatible%s", strGuids.c_str(), o.str().c_str()); SetCompatibles(strGuids, LFG_INCOMPATIBLES_NO_ROLES); @@ -441,12 +444,12 @@ LfgCompatibility LFGQueue::CheckCompatibility(LfgGuidList check) LfgGuidList::iterator itguid = check.begin(); proposalDungeons = QueueDataStore[*itguid].dungeons; std::ostringstream o; - o << ", " << *itguid << ": (" << sLFGMgr->ConcatenateDungeons(proposalDungeons) << ")"; + o << ", " << *itguid << ": (" << ConcatenateDungeons(proposalDungeons) << ")"; for (++itguid; itguid != check.end(); ++itguid) { LfgDungeonSet temporal; LfgDungeonSet &dungeons = QueueDataStore[*itguid].dungeons; - o << ", " << *itguid << ": (" << sLFGMgr->ConcatenateDungeons(dungeons) << ")"; + o << ", " << *itguid << ": (" << ConcatenateDungeons(dungeons) << ")"; std::set_intersection(proposalDungeons.begin(), proposalDungeons.end(), dungeons.begin(), dungeons.end(), std::inserter(temporal, temporal.begin())); proposalDungeons = temporal; } @@ -483,7 +486,7 @@ LfgCompatibility LFGQueue::CheckCompatibility(LfgGuidList check) uint64 gguid = *check.begin(); proposal.queues = check; - proposal.isNew = numLfgGroups != 1 || !sLFGMgr->GetDungeon(gguid); + proposal.isNew = numLfgGroups != 1 || sLFGMgr->GetOldState(gguid) != LFG_STATE_DUNGEON; if (!sLFGMgr->AllQueued(check)) { @@ -671,3 +674,5 @@ void LFGQueue::UpdateBestCompatibleInQueue(LfgQueueDataContainer::iterator itrQu --queueData.dps; } } + +} // namespace lfg diff --git a/src/server/game/DungeonFinding/LFGQueue.h b/src/server/game/DungeonFinding/LFGQueue.h index acb78d2c0f2..db7e7bbf318 100644 --- a/src/server/game/DungeonFinding/LFGQueue.h +++ b/src/server/game/DungeonFinding/LFGQueue.h @@ -20,6 +20,9 @@ #include "LFG.h" +namespace lfg +{ + enum LfgCompatibility { LFG_COMPATIBILITY_PENDING, @@ -140,4 +143,6 @@ class LFGQueue LfgGuidList newToQueueStore; ///< New groups to add to queue }; +} // namespace lfg + #endif diff --git a/src/server/game/DungeonFinding/LFGScripts.cpp b/src/server/game/DungeonFinding/LFGScripts.cpp index 568b61eef2f..3a70dc59e66 100644 --- a/src/server/game/DungeonFinding/LFGScripts.cpp +++ b/src/server/game/DungeonFinding/LFGScripts.cpp @@ -29,6 +29,9 @@ #include "ObjectAccessor.h" #include "WorldSession.h" +namespace lfg +{ + LFGPlayerScript::LFGPlayerScript() : PlayerScript("LFGPlayerScript") { } @@ -75,7 +78,7 @@ void LFGPlayerScript::OnLogin(Player* player) sLFGMgr->InitializeLockedDungeons(player); sLFGMgr->SetTeam(player->GetGUID(), player->GetTeam()); - // TODO - Restore LfgPlayerData and send proper status to player if it was in a group + /// @todo - Restore LfgPlayerData and send proper status to player if it was in a group } void LFGPlayerScript::OnBindToInstance(Player* player, Difficulty difficulty, uint32 mapId, bool /*permanent*/) @@ -85,6 +88,38 @@ void LFGPlayerScript::OnBindToInstance(Player* player, Difficulty difficulty, ui sLFGMgr->InitializeLockedDungeons(player); } +void LFGPlayerScript::OnMapChanged(Player* player) +{ + Map const* map = player->GetMap(); + + if (sLFGMgr->inLfgDungeonMap(player->GetGUID(), map->GetId(), map->GetDifficulty())) + { + Group* group = player->GetGroup(); + // This function is also called when players log in + // if for some reason the LFG system recognises the player as being in a LFG dungeon, + // but the player was loaded without a valid group, we'll teleport to homebind to prevent + // crashes or other undefined behaviour + if (!group) + { + sLFGMgr->LeaveLfg(player->GetGUID()); + player->RemoveAurasDueToSpell(LFG_SPELL_LUCK_OF_THE_DRAW); + player->TeleportTo(player->m_homebindMapId, player->m_homebindX, player->m_homebindY, player->m_homebindZ, 0.0f); + sLog->outError(LOG_FILTER_LFG, "LFGPlayerScript::OnMapChanged, Player %s (%u) is in LFG dungeon map but does not have a valid group! " + "Teleporting to homebind.", player->GetName().c_str(), player->GetGUIDLow()); + return; + } + + for (GroupReference* itr = group->GetFirstMember(); itr != NULL; itr = itr->next()) + if (Player* member = itr->getSource()) + player->GetSession()->SendNameQueryOpcode(member->GetGUID()); + + if (sLFGMgr->selectedRandomLfgDungeon(player->GetGUID())) + player->CastSpell(player, LFG_SPELL_LUCK_OF_THE_DRAW, true); + } + else + player->RemoveAurasDueToSpell(LFG_SPELL_LUCK_OF_THE_DRAW); +} + LFGGroupScript::LFGGroupScript() : GroupScript("LFGGroupScript") { } @@ -131,7 +166,7 @@ void LFGGroupScript::OnRemoveMember(Group* group, uint64 guid, RemoveMethod meth if (isLFG && method == GROUP_REMOVEMETHOD_KICK) // Player have been kicked { - // TODO - Update internal kick cooldown of kicker + /// @todo - Update internal kick cooldown of kicker std::string str_reason = ""; if (reason) str_reason = std::string(reason); @@ -208,3 +243,5 @@ void LFGGroupScript::OnInviteMember(Group* group, uint64 guid) if (leader && !gguid) sLFGMgr->LeaveLfg(leader); } + +} // namespace lfg diff --git a/src/server/game/DungeonFinding/LFGScripts.h b/src/server/game/DungeonFinding/LFGScripts.h index 227543e1899..bb1900cad93 100644 --- a/src/server/game/DungeonFinding/LFGScripts.h +++ b/src/server/game/DungeonFinding/LFGScripts.h @@ -26,6 +26,9 @@ class Player; class Group; +namespace lfg +{ + class LFGPlayerScript : public PlayerScript { public: @@ -36,6 +39,7 @@ class LFGPlayerScript : public PlayerScript void OnLogout(Player* player); void OnLogin(Player* player); void OnBindToInstance(Player* player, Difficulty difficulty, uint32 mapId, bool permanent); + void OnMapChanged(Player* player); }; class LFGGroupScript : public GroupScript @@ -50,3 +54,5 @@ class LFGGroupScript : public GroupScript void OnChangeLeader(Group* group, uint64 newLeaderGuid, uint64 oldLeaderGuid); void OnInviteMember(Group* group, uint64 guid); }; + +} // namespace lfg diff --git a/src/server/game/Entities/Creature/Creature.cpp b/src/server/game/Entities/Creature/Creature.cpp index 5b3969c9b9d..52ca60a4d1e 100644 --- a/src/server/game/Entities/Creature/Creature.cpp +++ b/src/server/game/Entities/Creature/Creature.cpp @@ -16,13 +16,13 @@ * with this program. If not, see <http://www.gnu.org/licenses/>. */ +#include "Creature.h" #include "BattlegroundMgr.h" #include "CellImpl.h" #include "Common.h" #include "CreatureAI.h" #include "CreatureAISelector.h" #include "CreatureGroups.h" -#include "Creature.h" #include "DatabaseEnv.h" #include "Formulas.h" #include "GameEventMgr.h" @@ -145,7 +145,7 @@ Creature::Creature(bool isWorldObject): Unit(isWorldObject), MapCreature(), lootForPickPocketed(false), lootForBody(false), m_groupLootTimer(0), lootingGroupLowGUID(0), m_PlayerDamageReq(0), m_lootRecipient(0), m_lootRecipientGroup(0), m_corpseRemoveTime(0), m_respawnTime(0), m_respawnDelay(300), m_corpseDelay(60), m_respawnradius(0.0f), m_reactState(REACT_AGGRESSIVE), -m_defaultMovementType(IDLE_MOTION_TYPE), m_DBTableGuid(0), m_equipmentId(0), m_AlreadyCallAssistance(false), +m_defaultMovementType(IDLE_MOTION_TYPE), m_DBTableGuid(0), m_equipmentId(0), m_originalEquipmentId(0), m_AlreadyCallAssistance(false), m_AlreadySearchedAssistance(false), m_regenHealth(true), m_AI_locked(false), m_meleeDamageSchoolMask(SPELL_SCHOOL_MASK_NORMAL), m_creatureInfo(NULL), m_creatureData(NULL), m_path_id(0), m_formation(NULL) { @@ -169,8 +169,6 @@ m_creatureInfo(NULL), m_creatureData(NULL), m_path_id(0), m_formation(NULL) Creature::~Creature() { - m_vendorItemCounts.clear(); - delete i_AI; i_AI = NULL; @@ -258,12 +256,12 @@ void Creature::RemoveCorpse(bool setSpawnTime) /** * change the entry of creature until respawn */ -bool Creature::InitEntry(uint32 Entry, uint32 /*team*/, const CreatureData* data) +bool Creature::InitEntry(uint32 entry, uint32 /*team*/, const CreatureData* data) { - CreatureTemplate const* normalInfo = sObjectMgr->GetCreatureTemplate(Entry); + CreatureTemplate const* normalInfo = sObjectMgr->GetCreatureTemplate(entry); if (!normalInfo) { - sLog->outError(LOG_FILTER_SQL, "Creature::InitEntry creature entry %u does not exist.", Entry); + sLog->outError(LOG_FILTER_SQL, "Creature::InitEntry creature entry %u does not exist.", entry); return false; } @@ -289,7 +287,11 @@ bool Creature::InitEntry(uint32 Entry, uint32 /*team*/, const CreatureData* data --diff; } - SetEntry(Entry); // normal entry always + // Initialize loot duplicate count depending on raid difficulty + if (GetMap()->Is25ManRaid()) + loot.maxDuplicates = 3; + + SetEntry(entry); // normal entry always m_creatureInfo = cinfo; // map mode related always // equal to player Race field, but creature does not have race @@ -301,15 +303,15 @@ bool Creature::InitEntry(uint32 Entry, uint32 /*team*/, const CreatureData* data // Cancel load if no model defined if (!(cinfo->GetFirstValidModelId())) { - sLog->outError(LOG_FILTER_SQL, "Creature (Entry: %u) has no model defined in table `creature_template`, can't load. ", Entry); + sLog->outError(LOG_FILTER_SQL, "Creature (Entry: %u) has no model defined in table `creature_template`, can't load. ", entry); return false; } - uint32 displayID = sObjectMgr->ChooseDisplayId(0, GetCreatureTemplate(), data); + uint32 displayID = ObjectMgr::ChooseDisplayId(GetCreatureTemplate(), data); CreatureModelInfo const* minfo = sObjectMgr->GetCreatureModelRandomGender(&displayID); if (!minfo) // Cancel load if no model defined { - sLog->outError(LOG_FILTER_SQL, "Creature (Entry: %u) has no model defined in table `creature_template`, can't load. ", Entry); + sLog->outError(LOG_FILTER_SQL, "Creature (Entry: %u) has no model defined in table `creature_template`, can't load. ", entry); return false; } @@ -318,10 +320,13 @@ bool Creature::InitEntry(uint32 Entry, uint32 /*team*/, const CreatureData* data SetByteValue(UNIT_FIELD_BYTES_0, 2, minfo->gender); // Load creature equipment - if (!data || data->equipmentId == 0) // use default from the template - LoadEquipment(cinfo->equipmentId); - else if (data && data->equipmentId != -1) // override, -1 means no equipment + if (!data || data->equipmentId == 0) + LoadEquipment(); // use default equipment (if available) + else if (data && data->equipmentId != 0) // override, 0 means no equipment + { + m_originalEquipmentId = data->equipmentId; LoadEquipment(data->equipmentId); + } SetName(normalInfo->Name); // at normal entry always @@ -390,7 +395,7 @@ bool Creature::UpdateEntry(uint32 Entry, uint32 team, const CreatureData* data) SetMeleeDamageSchool(SpellSchools(cInfo->dmgschool)); CreatureBaseStats const* stats = sObjectMgr->GetCreatureBaseStats(getLevel(), cInfo->unit_class); - float armor = (float)stats->GenerateArmor(cInfo); // TODO: Why is this treated as uint32 when it's a float? + float armor = (float)stats->GenerateArmor(cInfo); /// @todo Why is this treated as uint32 when it's a float? SetModifierValue(UNIT_MOD_ARMOR, BASE_VALUE, armor); SetModifierValue(UNIT_MOD_RESISTANCE_HOLY, BASE_VALUE, float(cInfo->resistance[SPELL_SCHOOL_HOLY])); SetModifierValue(UNIT_MOD_RESISTANCE_FIRE, BASE_VALUE, float(cInfo->resistance[SPELL_SCHOOL_FIRE])); @@ -730,7 +735,7 @@ void Creature::DoFleeToGetAssistance() if (!creature) //SetFeared(true, getVictim()->GetGUID(), 0, sWorld->getIntConfig(CONFIG_CREATURE_FAMILY_FLEE_DELAY)); - //TODO: use 31365 + /// @todo use 31365 SetControlled(true, UNIT_STATE_FLEEING); else GetMotionMaster()->MoveSeekAssistance(creature->GetPositionX(), creature->GetPositionY(), creature->GetPositionZ()); @@ -843,7 +848,7 @@ bool Creature::Create(uint32 guidlow, Map* map, uint32 phaseMask, uint32 Entry, LastUsedScriptID = GetCreatureTemplate()->ScriptID; - // TODO: Replace with spell, handle from DB + /// @todo Replace with spell, handle from DB if (isSpiritHealer() || isSpiritGuide()) { m_serverSideVisibility.SetValue(SERVERSIDE_VISIBILITY_GHOST, GHOST_VISIBILITY_GHOST); @@ -856,6 +861,16 @@ bool Creature::Create(uint32 guidlow, Map* map, uint32 phaseMask, uint32 Entry, return true; } +void Creature::InitializeReactState() +{ + if (isTotem() || isTrigger() || GetCreatureType() == CREATURE_TYPE_CRITTER || isSpiritService()) + SetReactState(REACT_PASSIVE); + else + SetReactState(REACT_AGGRESSIVE); + /*else if (isCivilian()) + SetReactState(REACT_DEFENSIVE);*/; +} + bool Creature::isCanTrainingOf(Player* player, bool msg) const { if (!isTrainer()) @@ -1085,7 +1100,7 @@ void Creature::SaveToDB(uint32 mapid, uint8 spawnMask, uint32 phaseMask) data.mapid = mapid; data.phaseMask = phaseMask; data.displayid = displayId; - data.equipmentId = GetEquipmentId(); + data.equipmentId = GetCurrentEquipmentId(); data.posX = GetPositionX(); data.posY = GetPositionY(); data.posZ = GetPositionZMinusOffset(); @@ -1120,7 +1135,7 @@ void Creature::SaveToDB(uint32 mapid, uint8 spawnMask, uint32 phaseMask) stmt->setUInt8(index++, spawnMask); stmt->setUInt16(index++, uint16(GetPhaseMask())); stmt->setUInt32(index++, displayId); - stmt->setInt32(index++, int32(GetEquipmentId())); + stmt->setInt32(index++, int32(GetCurrentEquipmentId())); stmt->setFloat(index++, GetPositionX()); stmt->setFloat(index++, GetPositionY()); stmt->setFloat(index++, GetPositionZ()); @@ -1169,7 +1184,7 @@ void Creature::SelectLevel(const CreatureTemplate* cinfo) SetMaxPower(POWER_MANA, mana); //MAX Mana SetPower(POWER_MANA, mana); - // TODO: set UNIT_FIELD_POWER*, for some creature class case (energy, etc) + /// @todo set UNIT_FIELD_POWER*, for some creature class case (energy, etc) SetModifierValue(UNIT_MOD_HEALTH, BASE_VALUE, (float)health); SetModifierValue(UNIT_MOD_MANA, BASE_VALUE, (float)mana); @@ -1206,6 +1221,12 @@ float Creature::_GetHealthMod(int32 Rank) } } +void Creature::LowerPlayerDamageReq(uint32 unDamage) +{ + if (m_PlayerDamageReq) + m_PlayerDamageReq > unDamage ? m_PlayerDamageReq -= unDamage : m_PlayerDamageReq = 0; +} + float Creature::_GetDamageMod(int32 Rank) { switch (Rank) // define rates for each elite rank @@ -1225,7 +1246,7 @@ float Creature::_GetDamageMod(int32 Rank) } } -float Creature::GetSpellDamageMod(int32 Rank) +float Creature::GetSpellDamageMod(int32 Rank) const { switch (Rank) // define rates for each elite rank { @@ -1266,14 +1287,14 @@ bool Creature::CreateFromProto(uint32 guidlow, uint32 Entry, uint32 vehId, uint3 if (!vehId) vehId = cinfo->VehicleId; - if (vehId && !CreateVehicleKit(vehId, Entry)) - vehId = 0; - Object::_Create(guidlow, Entry, vehId ? HIGHGUID_VEHICLE : HIGHGUID_UNIT); if (!UpdateEntry(Entry, team, data)) return false; + if (vehId) + CreateVehicleKit(vehId, Entry); + return true; } @@ -1351,24 +1372,24 @@ bool Creature::LoadCreatureFromDB(uint32 guid, Map* map, bool addToMap) return true; } -void Creature::LoadEquipment(uint32 equip_entry, bool force) +void Creature::LoadEquipment(int8 id, bool force /*= true*/) { - if (equip_entry == 0) + if (id == 0) { if (force) { - for (uint8 i = 0; i < 3; ++i) + for (uint8 i = 0; i < MAX_EQUIPMENT_ITEMS; ++i) SetUInt32Value(UNIT_VIRTUAL_ITEM_SLOT_ID + i, 0); m_equipmentId = 0; } return; } - EquipmentInfo const* einfo = sObjectMgr->GetEquipmentInfo(equip_entry); + EquipmentInfo const* einfo = sObjectMgr->GetEquipmentInfo(GetEntry(), id); if (!einfo) return; - m_equipmentId = equip_entry; + m_equipmentId = id; for (uint8 i = 0; i < 3; ++i) SetUInt32Value(UNIT_VIRTUAL_ITEM_SLOT_ID + i, einfo->ItemEntry[i]); } @@ -1461,7 +1482,7 @@ bool Creature::canStartAttack(Unit const* who, bool force) const if (!CanFly() && (GetDistanceZ(who) > CREATURE_Z_ATTACK_RANGE + m_CombatDistance)) //|| who->IsControlledByPlayer() && who->IsFlying())) // we cannot check flying for other creatures, too much map/vmap calculation - // TODO: should switch to range attack + /// @todo should switch to range attack return false; if (!force) @@ -1685,7 +1706,7 @@ void Creature::DespawnOrUnsummon(uint32 msTimeToDespawn /*= 0*/) ForcedDespawn(msTimeToDespawn); } -bool Creature::IsImmunedToSpell(SpellInfo const* spellInfo) +bool Creature::IsImmunedToSpell(SpellInfo const* spellInfo) const { if (!spellInfo) return false; @@ -1724,6 +1745,23 @@ bool Creature::IsImmunedToSpellEffect(SpellInfo const* spellInfo, uint32 index) return Unit::IsImmunedToSpellEffect(spellInfo, index); } +bool Creature::isElite() const +{ + if (isPet()) + return false; + + uint32 rank = GetCreatureTemplate()->rank; + return rank != CREATURE_ELITE_NORMAL && rank != CREATURE_ELITE_RARE; +} + +bool Creature::isWorldBoss() const +{ + if (isPet()) + return false; + + return GetCreatureTemplate()->type_flags & CREATURE_TYPEFLAGS_BOSS; +} + SpellInfo const* Creature::reachWithSpellAttack(Unit* victim) { if (!victim) @@ -2105,9 +2143,11 @@ bool Creature::LoadCreaturesAddon(bool reload) SetByteValue(UNIT_FIELD_BYTES_1, 3, uint8((cainfo->bytes1 >> 24) & 0xFF)); //! Suspected correlation between UNIT_FIELD_BYTES_1, offset 3, value 0x2: - //! If no inhabittype_fly (if no MovementFlag_DisableGravity flag found in sniffs) + //! If no inhabittype_fly (if no MovementFlag_DisableGravity or MovementFlag_CanFly flag found in sniffs) + //! Check using InhabitType as movement flags are assigned dynamically + //! basing on whether the creature is in air or not //! Set MovementFlag_Hover. Otherwise do nothing. - if (GetByteValue(UNIT_FIELD_BYTES_1, 3) & UNIT_BYTE1_FLAG_HOVER && !IsLevitating()) + if (GetByteValue(UNIT_FIELD_BYTES_1, 3) & UNIT_BYTE1_FLAG_HOVER && !(GetCreatureTemplate()->InhabitType & INHABIT_AIR)) AddUnitMovementFlag(MOVEMENTFLAG_HOVER); } @@ -2148,7 +2188,7 @@ bool Creature::LoadCreaturesAddon(bool reload) if (HasAura(*itr)) { if (!reload) - sLog->outError(LOG_FILTER_SQL, "Creature (GUID: %u Entry: %u) has duplicate aura (spell %u) in `auras` field.", GetGUIDLow(), GetEntry(), *itr); + sLog->outError(LOG_FILTER_SQL, "Creature (GUID: %u Entry: %u) has duplicate aura (spell %u) in `auras` field.", GetDBTableGUIDLow(), GetEntry(), *itr); continue; } @@ -2209,6 +2249,11 @@ void Creature::SetInCombatWithZone() } } +uint32 Creature::GetShieldBlockValue() const //dunno mob block value +{ + return (getLevel()/2 + uint32(GetStat(STAT_STRENGTH)/20)); +} + void Creature::_AddCreatureSpellCooldown(uint32 spell_id, time_t end_time) { m_CreatureSpellCooldowns[spell_id] = end_time; @@ -2246,6 +2291,13 @@ bool Creature::HasCategoryCooldown(uint32 spell_id) const return(itr != m_CreatureCategoryCooldowns.end() && time_t(itr->second + (spellInfo->CategoryRecoveryTime / IN_MILLISECONDS)) > time(NULL)); } +uint32 Creature::GetCreatureSpellCooldownDelay(uint32 spellId) const +{ + CreatureSpellCooldowns::const_iterator itr = m_CreatureSpellCooldowns.find(spellId); + time_t t = time(NULL); + return uint32(itr != m_CreatureSpellCooldowns.end() && itr->second > t ? itr->second - t : 0); +} + bool Creature::HasSpellCooldown(uint32 spell_id) const { CreatureSpellCooldowns::const_iterator itr = m_CreatureSpellCooldowns.find(spell_id); @@ -2490,6 +2542,14 @@ void Creature::FarTeleportTo(Map* map, float X, float Y, float Z, float O) GetMap()->AddToMap(this); } +uint32 Creature::GetPetAutoSpellOnPos(uint8 pos) const +{ + if (pos >= MAX_SPELL_CHARM || m_charmInfo->GetCharmSpell(pos)->GetType() != ACT_ENABLED) + return 0; + else + return m_charmInfo->GetCharmSpell(pos)->GetAction(); +} + void Creature::SetPosition(float x, float y, float z, float o) { // prevent crash when a bad coord is sent by the client diff --git a/src/server/game/Entities/Creature/Creature.h b/src/server/game/Entities/Creature/Creature.h index efc4e44798f..6e771d2761b 100644 --- a/src/server/game/Entities/Creature/Creature.h +++ b/src/server/game/Entities/Creature/Creature.h @@ -136,7 +136,6 @@ struct CreatureTemplate uint32 questItems[MAX_CREATURE_QUEST_ITEMS]; uint32 movementId; bool RegenHealth; - uint32 equipmentId; uint32 MechanicImmuneMask; uint32 flags_extra; uint32 ScriptID; @@ -156,13 +155,18 @@ struct CreatureTemplate return SKILL_SKINNING; // normal case } - bool isTameable(bool exotic) const + bool isExotic() const + { + return (type_flags & CREATURE_TYPEFLAGS_EXOTIC) != 0; + } + + bool isTameable(bool canTameExotic) const { if (type != CREATURE_TYPE_BEAST || family == 0 || (type_flags & CREATURE_TYPEFLAGS_TAMEABLE) == 0) return false; - // if can tame exotic then can tame any temable - return exotic || (type_flags & CREATURE_TYPEFLAGS_EXOTIC) == 0; + // if can tame exotic then can tame any tameable + return canTameExotic || !isExotic(); } }; @@ -170,7 +174,7 @@ struct CreatureTemplate typedef UNORDERED_MAP<uint32, CreatureTemplate> CreatureTemplateContainer; // Represents max amount of expansions. -// TODO: Add MAX_EXPANSION constant. +/// @todo: Add MAX_EXPANSION constant. #define MAX_CREATURE_BASE_HP 3 // GCC have alternative #pragma pack(N) syntax and old gcc version not support pack(push, N), also any gcc version not support it at some platform @@ -236,7 +240,8 @@ struct EquipmentInfo }; // Benchmarked: Faster than std::map (insert/find) -typedef UNORDERED_MAP<uint16, EquipmentInfo> EquipmentInfoContainer; +typedef UNORDERED_MAP<uint8, EquipmentInfo> EquipmentInfoContainerInternal; +typedef UNORDERED_MAP<uint32, EquipmentInfoContainerInternal> EquipmentInfoContainer; // from `creature` table struct CreatureData @@ -246,7 +251,7 @@ struct CreatureData uint16 mapid; uint16 phaseMask; uint32 displayid; - int32 equipmentId; + int8 equipmentId; float posX; float posY; float posZ; @@ -454,13 +459,12 @@ class Creature : public Unit, public GridObject<Creature>, public MapCreature bool Create(uint32 guidlow, Map* map, uint32 phaseMask, uint32 Entry, uint32 vehId, uint32 team, float x, float y, float z, float ang, const CreatureData* data = NULL); bool LoadCreaturesAddon(bool reload = false); void SelectLevel(const CreatureTemplate* cinfo); - void LoadEquipment(uint32 equip_entry, bool force=false); + void LoadEquipment(int8 id = 1, bool force = false); uint32 GetDBTableGUIDLow() const { return m_DBTableGuid; } void Update(uint32 time); // overwrited Unit::Update void GetRespawnPosition(float &x, float &y, float &z, float* ori = NULL, float* dist =NULL) const; - uint32 GetEquipmentId() const { return GetCreatureTemplate()->equipmentId; } void SetCorpseDelay(uint32 delay) { m_corpseDelay = delay; } uint32 GetCorpseDelay() const { return m_corpseDelay; } @@ -475,41 +479,17 @@ class Creature : public Unit, public GridObject<Creature>, public MapCreature void SetReactState(ReactStates st) { m_reactState = st; } ReactStates GetReactState() { return m_reactState; } bool HasReactState(ReactStates state) const { return (m_reactState == state); } - void InitializeReactState() - { - if (isTotem() || isTrigger() || GetCreatureType() == CREATURE_TYPE_CRITTER || isSpiritService()) - SetReactState(REACT_PASSIVE); - else - SetReactState(REACT_AGGRESSIVE); - /*else if (isCivilian()) - SetReactState(REACT_DEFENSIVE);*/; - } - - ///// TODO RENAME THIS!!!!! + void InitializeReactState(); + + /// @todo Rename these properly bool isCanTrainingOf(Player* player, bool msg) const; bool isCanInteractWithBattleMaster(Player* player, bool msg) const; bool isCanTrainingAndResetTalentsOf(Player* player) const; bool canCreatureAttack(Unit const* victim, bool force = true) const; - bool IsImmunedToSpell(SpellInfo const* spellInfo); - // redefine Unit::IsImmunedToSpell - bool IsImmunedToSpellEffect(SpellInfo const* spellInfo, uint32 index) const; - // redefine Unit::IsImmunedToSpellEffect - bool isElite() const - { - if (isPet()) - return false; - - uint32 rank = GetCreatureTemplate()->rank; - return rank != CREATURE_ELITE_NORMAL && rank != CREATURE_ELITE_RARE; - } - - bool isWorldBoss() const - { - if (isPet()) - return false; - - return GetCreatureTemplate()->type_flags & CREATURE_TYPEFLAGS_BOSS; - } + bool IsImmunedToSpell(SpellInfo const* spellInfo) const; // override Unit::IsImmunedToSpell + bool IsImmunedToSpellEffect(SpellInfo const* spellInfo, uint32 index) const; // override Unit::IsImmunedToSpellEffect + bool isElite() const; + bool isWorldBoss() const; bool IsDungeonBoss() const; @@ -526,10 +506,7 @@ class Creature : public Unit, public GridObject<Creature>, public MapCreature bool SetDisableGravity(bool disable, bool packetOnly = false); bool SetHover(bool enable); - uint32 GetShieldBlockValue() const //dunno mob block value - { - return (getLevel()/2 + uint32(GetStat(STAT_STRENGTH)/20)); - } + uint32 GetShieldBlockValue() const; SpellSchoolMask GetMeleeDamageSchoolMask() const { return m_meleeDamageSchoolMask; } void SetMeleeDamageSchool(SpellSchools school) { m_meleeDamageSchoolMask = SpellSchoolMask(1 << school); } @@ -539,12 +516,7 @@ class Creature : public Unit, public GridObject<Creature>, public MapCreature void AddCreatureSpellCooldown(uint32 spellid); bool HasSpellCooldown(uint32 spell_id) const; bool HasCategoryCooldown(uint32 spell_id) const; - uint32 GetCreatureSpellCooldownDelay(uint32 spellId) const - { - CreatureSpellCooldowns::const_iterator itr = m_CreatureSpellCooldowns.find(spellId); - time_t t = time(NULL); - return uint32(itr != m_CreatureSpellCooldowns.end() && itr->second > t ? itr->second - t : 0); - } + uint32 GetCreatureSpellCooldownDelay(uint32 spellId) const; virtual void ProhibitSpellSchool(SpellSchoolMask idSchoolMask, uint32 unTimeMs); bool HasSpell(uint32 spellID) const; @@ -558,9 +530,12 @@ class Creature : public Unit, public GridObject<Creature>, public MapCreature void UpdateMaxPower(Powers power); void UpdateAttackPowerAndDamage(bool ranged = false); void UpdateDamagePhysical(WeaponAttackType attType); - uint32 GetCurrentEquipmentId() { return m_equipmentId; } - void SetCurrentEquipmentId(uint32 entry) { m_equipmentId = entry; } - float GetSpellDamageMod(int32 Rank); + + int8 GetOriginalEquipmentId() const { return m_originalEquipmentId; } + uint8 GetCurrentEquipmentId() { return m_equipmentId; } + void SetCurrentEquipmentId(uint8 id) { m_equipmentId = id; } + + float GetSpellDamageMod(int32 Rank) const; VendorItemData const* GetVendorItems() const; uint32 GetVendorItemCurrentCount(VendorItem const* vItem); @@ -671,13 +646,7 @@ class Creature : public Unit, public GridObject<Creature>, public MapCreature bool isRegeneratingHealth() { return m_regenHealth; } void setRegeneratingHealth(bool regenHealth) { m_regenHealth = regenHealth; } virtual uint8 GetPetAutoSpellSize() const { return MAX_SPELL_CHARM; } - virtual uint32 GetPetAutoSpellOnPos(uint8 pos) const - { - if (pos >= MAX_SPELL_CHARM || m_charmInfo->GetCharmSpell(pos)->GetType() != ACT_ENABLED) - return 0; - else - return m_charmInfo->GetCharmSpell(pos)->GetAction(); - } + virtual uint32 GetPetAutoSpellOnPos(uint8 pos) const; void SetPosition(float x, float y, float z, float o); void SetPosition(const Position &pos) { SetPosition(pos.GetPositionX(), pos.GetPositionY(), pos.GetPositionZ(), pos.GetOrientation()); } @@ -695,8 +664,8 @@ class Creature : public Unit, public GridObject<Creature>, public MapCreature uint32 GetWaypointPath(){return m_path_id;} void LoadPath(uint32 pathid) { m_path_id = pathid; } - uint32 GetCurrentWaypointID(){return m_waypointID;} - void UpdateWaypointID(uint32 wpID){m_waypointID = wpID;} + uint32 GetCurrentWaypointID() const { return m_waypointID; } + void UpdateWaypointID(uint32 wpID) { m_waypointID = wpID; } void SearchFormation(); CreatureGroup* GetFormation() {return m_formation;} @@ -707,11 +676,7 @@ class Creature : public Unit, public GridObject<Creature>, public MapCreature void SetDisableReputationGain(bool disable) { DisableReputationGain = disable; } bool IsReputationGainDisabled() { return DisableReputationGain; } bool IsDamageEnoughForLootingAndReward() const { return m_PlayerDamageReq == 0; } - void LowerPlayerDamageReq(uint32 unDamage) - { - if (m_PlayerDamageReq) - m_PlayerDamageReq > unDamage ? m_PlayerDamageReq -= unDamage : m_PlayerDamageReq = 0; - } + void LowerPlayerDamageReq(uint32 unDamage); void ResetPlayerDamageReq() { m_PlayerDamageReq = GetHealth() / 2; } uint32 m_PlayerDamageReq; @@ -754,7 +719,8 @@ class Creature : public Unit, public GridObject<Creature>, public MapCreature void Regenerate(Powers power); MovementGeneratorType m_defaultMovementType; uint32 m_DBTableGuid; ///< For new or temporary creatures is 0 for saved it is lowguid - uint32 m_equipmentId; + uint8 m_equipmentId; + int8 m_originalEquipmentId; // can be -1 bool m_AlreadyCallAssistance; bool m_AlreadySearchedAssistance; @@ -769,10 +735,10 @@ class Creature : public Unit, public GridObject<Creature>, public MapCreature bool DisableReputationGain; - CreatureTemplate const* m_creatureInfo; // in difficulty mode > 0 can different from sObjectMgr->GetCreatureTemplate(GetEntry()) + CreatureTemplate const* m_creatureInfo; // Can differ from sObjectMgr->GetCreatureTemplate(GetEntry()) in difficulty mode > 0 CreatureData const* m_creatureData; - uint16 m_LootMode; // bitmask, default LOOT_MODE_DEFAULT, determines what loot will be lootable + uint16 m_LootMode; // Bitmask (default: LOOT_MODE_DEFAULT) that determines what loot will be lootable uint32 guid_transport; bool IsInvisibleDueToDespawn() const; diff --git a/src/server/game/Entities/Creature/GossipDef.cpp b/src/server/game/Entities/Creature/GossipDef.cpp index f5877a3b927..a2305a8a56d 100644 --- a/src/server/game/Entities/Creature/GossipDef.cpp +++ b/src/server/game/Entities/Creature/GossipDef.cpp @@ -142,6 +142,9 @@ void PlayerMenu::SendGossipMenu(uint32 titleTextId, uint64 objectGUID) const data << uint32(_questMenu.GetMenuItemCount()); // max count 0x20 + // Store this instead of checking the Singleton every loop iteration + bool questLevelInTitle = sWorld->getBoolConfig(CONFIG_UI_QUESTLEVELS_IN_DIALOGS); + for (uint8 i = 0; i < _questMenu.GetMenuItemCount(); ++i) { QuestMenuItem const& item = _questMenu.GetItem(i); @@ -160,6 +163,9 @@ void PlayerMenu::SendGossipMenu(uint32 titleTextId, uint64 objectGUID) const if (QuestLocale const* localeData = sObjectMgr->GetQuestLocale(questID)) ObjectMgr::GetLocaleString(localeData->Title, locale, title); + if (questLevelInTitle) + AddQuestLevelToTitle(title, quest->GetQuestLevel()); + data << title; // max 0x200 } @@ -252,6 +258,10 @@ void PlayerMenu::SendQuestGiverQuestList(QEmote eEmote, const std::string& Title size_t count_pos = data.wpos(); data << uint8 (_questMenu.GetMenuItemCount()); uint32 count = 0; + + // Store this instead of checking the Singleton every loop iteration + bool questLevelInTitle = sWorld->getBoolConfig(CONFIG_UI_QUESTLEVELS_IN_DIALOGS); + for (; count < _questMenu.GetMenuItemCount(); ++count) { QuestMenuItem const& qmi = _questMenu.GetItem(count); @@ -267,6 +277,9 @@ void PlayerMenu::SendQuestGiverQuestList(QEmote eEmote, const std::string& Title if (QuestLocale const* localeData = sObjectMgr->GetQuestLocale(questID)) ObjectMgr::GetLocaleString(localeData->Title, locale, title); + if (questLevelInTitle) + AddQuestLevelToTitle(title, quest->GetQuestLevel()); + data << uint32(questID); data << uint32(qmi.QuestIcon); data << int32(quest->GetQuestLevel()); @@ -310,6 +323,9 @@ void PlayerMenu::SendQuestGiverQuestDetails(Quest const* quest, uint64 npcGUID, } } + if (sWorld->getBoolConfig(CONFIG_UI_QUESTLEVELS_IN_DIALOGS)) + AddQuestLevelToTitle(questTitle, quest->GetQuestLevel()); + WorldPacket data(SMSG_QUESTGIVER_QUEST_DETAILS, 100); // guess size data << uint64(npcGUID); data << uint64(0); // wotlk, something todo with quest sharing? @@ -499,6 +515,9 @@ void PlayerMenu::SendQuestQueryResponse(Quest const* quest) const data << float(quest->GetPointY()); data << uint32(quest->GetPointOpt()); + if (sWorld->getBoolConfig(CONFIG_UI_QUESTLEVELS_IN_DIALOGS)) + AddQuestLevelToTitle(questTitle, quest->GetQuestLevel()); + data << questTitle; data << questObjectives; data << questDetails; @@ -545,6 +564,9 @@ void PlayerMenu::SendQuestGiverOfferReward(Quest const* quest, uint64 npcGUID, b } } + if (sWorld->getBoolConfig(CONFIG_UI_QUESTLEVELS_IN_DIALOGS)) + AddQuestLevelToTitle(questTitle, quest->GetQuestLevel()); + WorldPacket data(SMSG_QUESTGIVER_OFFER_REWARD, 50); // guess size data << uint64(npcGUID); data << uint32(quest->GetQuestId()); @@ -645,6 +667,9 @@ void PlayerMenu::SendQuestGiverRequestItems(Quest const* quest, uint64 npcGUID, return; } + if (sWorld->getBoolConfig(CONFIG_UI_QUESTLEVELS_IN_DIALOGS)) + AddQuestLevelToTitle(questTitle, quest->GetQuestLevel()); + WorldPacket data(SMSG_QUESTGIVER_REQUEST_ITEMS, 50); // guess size data << uint64(npcGUID); data << uint32(quest->GetQuestId()); @@ -694,3 +719,13 @@ void PlayerMenu::SendQuestGiverRequestItems(Quest const* quest, uint64 npcGUID, _session->SendPacket(&data); sLog->outDebug(LOG_FILTER_NETWORKIO, "WORLD: Sent SMSG_QUESTGIVER_REQUEST_ITEMS NPCGuid=%u, questid=%u", GUID_LOPART(npcGUID), quest->GetQuestId()); } + +void PlayerMenu::AddQuestLevelToTitle(std::string &title, int32 level) +{ + // Adds the quest level to the front of the quest title + // example: [13] Westfall Stew + + std::stringstream questTitlePretty; + questTitlePretty << "[" << level << "] " << title; + title = questTitlePretty.str(); +} diff --git a/src/server/game/Entities/Creature/GossipDef.h b/src/server/game/Entities/Creature/GossipDef.h index 6c5f465bbf0..f13f19bba55 100644 --- a/src/server/game/Entities/Creature/GossipDef.h +++ b/src/server/game/Entities/Creature/GossipDef.h @@ -277,6 +277,8 @@ class PlayerMenu void SendQuestGiverOfferReward(Quest const* quest, uint64 npcGUID, bool enableNext) const; void SendQuestGiverRequestItems(Quest const* quest, uint64 npcGUID, bool canComplete, bool closeOnCancel) const; + static void AddQuestLevelToTitle(std::string &title, int32 level); + private: GossipMenu _gossipMenu; QuestMenu _questMenu; diff --git a/src/server/game/Entities/Creature/TemporarySummon.cpp b/src/server/game/Entities/Creature/TemporarySummon.cpp index 2f691f68c99..eb7c0e7da6c 100644 --- a/src/server/game/Entities/Creature/TemporarySummon.cpp +++ b/src/server/game/Entities/Creature/TemporarySummon.cpp @@ -372,7 +372,7 @@ void Puppet::Update(uint32 time) if (!isAlive()) { UnSummon(); - // TODO: why long distance .die does not remove it + /// @todo why long distance .die does not remove it } } } diff --git a/src/server/game/Entities/Creature/TemporarySummon.h b/src/server/game/Entities/Creature/TemporarySummon.h index a96d9ab33d0..a28874c51e7 100644 --- a/src/server/game/Entities/Creature/TemporarySummon.h +++ b/src/server/game/Entities/Creature/TemporarySummon.h @@ -21,6 +21,22 @@ #include "Creature.h" +enum SummonerType +{ + SUMMONER_TYPE_CREATURE = 0, + SUMMONER_TYPE_GAMEOBJECT = 1, + SUMMONER_TYPE_MAP = 2 +}; + +/// Stores data for temp summons +struct TempSummonData +{ + uint32 entry; ///< Entry of summoned creature + Position pos; ///< Position, where should be creature spawned + TempSummonType type; ///< Summon type, see TempSummonType for available types + uint32 time; ///< Despawn time, usable only with certain temp summon types +}; + class TempSummon : public Creature { public: @@ -56,6 +72,7 @@ class Minion : public TempSummon float GetFollowAngle() const { return m_followAngle; } void SetFollowAngle(float angle) { m_followAngle = angle; } bool IsPetGhoul() const {return GetEntry() == 26125;} // Ghoul may be guardian or pet + bool IsSpiritWolf() const {return GetEntry() == 29264;} // Spirit wolf from feral spirits bool IsGuardianPet() const; protected: Unit* const m_owner; diff --git a/src/server/game/Entities/GameObject/GameObject.cpp b/src/server/game/Entities/GameObject/GameObject.cpp index bf0fbb4199d..db51d88653a 100644 --- a/src/server/game/Entities/GameObject/GameObject.cpp +++ b/src/server/game/Entities/GameObject/GameObject.cpp @@ -224,6 +224,10 @@ bool GameObject::Create(uint32 guidlow, uint32 name_id, Map* map, uint32 phaseMa switch (goinfo->type) { + case GAMEOBJECT_TYPE_FISHINGHOLE: + SetGoAnimProgress(animprogress); + m_goValue.FishingHole.MaxOpens = urand(GetGOInfo()->fishinghole.minSuccessOpens, GetGOInfo()->fishinghole.maxSuccessOpens); + break; case GAMEOBJECT_TYPE_DESTRUCTIBLE_BUILDING: m_goValue.Building.Health = goinfo->building.intactNumHits + goinfo->building.damagedNumHits; m_goValue.Building.MaxHealth = m_goValue.Building.Health; @@ -258,6 +262,10 @@ bool GameObject::Create(uint32 guidlow, uint32 name_id, Map* map, uint32 phaseMa LastUsedScriptID = GetGOInfo()->ScriptId; AIM_Initialize(); + // Initialize loot duplicate count depending on raid difficulty + if (map->Is25ManRaid()) + loot.maxDuplicates = 3; + return true; } @@ -373,22 +381,27 @@ void GameObject::Update(uint32 diff) //we need to open doors if they are closed (add there another condition if this code breaks some usage, but it need to be here for battlegrounds) if (GetGoState() != GO_STATE_READY) ResetDoorOrButton(); - //flags in AB are type_button and we need to add them here so no break! + break; + case GAMEOBJECT_TYPE_FISHINGHOLE: + // Initialize a new max fish count on respawn + m_goValue.FishingHole.MaxOpens = urand(GetGOInfo()->fishinghole.minSuccessOpens, GetGOInfo()->fishinghole.maxSuccessOpens); + break; default: - if (!m_spawnedByDefault) // despawn timer - { - // can be despawned or destroyed - SetLootState(GO_JUST_DEACTIVATED); - return; - } - // respawn timer - uint32 poolid = GetDBTableGUIDLow() ? sPoolMgr->IsPartOfAPool<GameObject>(GetDBTableGUIDLow()) : 0; - if (poolid) - sPoolMgr->UpdatePool<GameObject>(poolid, GetDBTableGUIDLow()); - else - GetMap()->AddToMap(this); break; } + + if (!m_spawnedByDefault) // despawn timer + { + // can be despawned or destroyed + SetLootState(GO_JUST_DEACTIVATED); + return; + } + // respawn timer + uint32 poolid = GetDBTableGUIDLow() ? sPoolMgr->IsPartOfAPool<GameObject>(GetDBTableGUIDLow()) : 0; + if (poolid) + sPoolMgr->UpdatePool<GameObject>(poolid, GetDBTableGUIDLow()); + else + GetMap()->AddToMap(this); } } @@ -415,8 +428,8 @@ void GameObject::Update(uint32 diff) bool IsBattlegroundTrap = false; //FIXME: this is activation radius (in different casting radius that must be selected from spell data) - //TODO: move activated state code (cast itself) to GO_ACTIVATED, in this place only check activating and set state - float radius = (float)(goInfo->trap.radius)/3*2; // TODO rename radius to diameter (goInfo->trap.radius) should be (goInfo->trap.diameter) + /// @todo move activated state code (cast itself) to GO_ACTIVATED, in this place only check activating and set state + float radius = (float)(goInfo->trap.radius)/3*2; /// @todo rename radius to diameter (goInfo->trap.radius) should be (goInfo->trap.diameter) if (!radius) { if (goInfo->trap.cooldown != 3) // cast in other case (at some triggering/linked go/etc explicit call) @@ -932,7 +945,7 @@ bool GameObject::ActivateToQuest(Player* target) const { if (LootTemplates_Gameobject.HaveQuestLootForPlayer(GetGOInfo()->GetLootId(), target)) { - //TODO: fix this hack + /// @todo fix this hack //look for battlegroundAV for some objects which are only activated after mine gots captured by own team if (GetEntry() == BG_AV_OBJECTID_MINE_N || GetEntry() == BG_AV_OBJECTID_MINE_S) if (Battleground* bg = target->GetBattleground()) @@ -1340,12 +1353,12 @@ void GameObject::Use(Unit* user) { player->UpdateFishingSkill(); - //TODO: I do not understand this hack. Need some explanation. + /// @todo I do not understand this hack. Need some explanation. // prevent removing GO at spell cancel RemoveFromOwner(); SetOwnerGUID(player->GetGUID()); - //TODO: find reasonable value for fishing hole search + /// @todo find reasonable value for fishing hole search GameObject* ok = LookupFishingHoleAround(20.0f + CONTACT_DISTANCE); if (ok) { @@ -1355,7 +1368,7 @@ void GameObject::Use(Unit* user) else player->SendLoot(GetGUID(), LOOT_FISHING); } - // TODO: else: junk + /// @todo else: junk else m_respawnTime = time(NULL); @@ -1818,7 +1831,7 @@ void GameObject::ModifyHealth(int32 change, Unit* attackerOrHealer /*= NULL*/, u Player* player = attackerOrHealer->GetCharmerOrOwnerPlayerOrPlayerItself(); // dealing damage, send packet - // TODO: is there any packet for healing? + /// @todo is there any packet for healing? if (change < 0 && player) { WorldPacket data(SMSG_DESTRUCTIBLE_BUILDING_DAMAGE, 8 + 8 + 8 + 4 + 4); diff --git a/src/server/game/Entities/GameObject/GameObject.h b/src/server/game/Entities/GameObject/GameObject.h index 7b1ccbc9015..3f16ea5f273 100644 --- a/src/server/game/Entities/GameObject/GameObject.h +++ b/src/server/game/Entities/GameObject/GameObject.h @@ -81,7 +81,7 @@ struct GameObjectTemplate uint32 noDamageImmune; //5 uint32 openTextID; //6 can be used to replace castBarCaption? uint32 losOK; //7 - uint32 allowMounted; //8 + uint32 allowMounted; //8 Is usable while on mount/vehicle. (0/1) uint32 large; //9 } questgiver; //3 GAMEOBJECT_TYPE_CHEST @@ -91,8 +91,8 @@ struct GameObjectTemplate uint32 lootId; //1 uint32 chestRestockTime; //2 uint32 consumable; //3 - uint32 minSuccessOpens; //4 - uint32 maxSuccessOpens; //5 + uint32 minSuccessOpens; //4 Deprecated, pre 3.0 was used for mining nodes but since WotLK all mining nodes are usable once and grant all loot with a single use + uint32 maxSuccessOpens; //5 Deprecated, pre 3.0 was used for mining nodes but since WotLK all mining nodes are usable once and grant all loot with a single use uint32 eventId; //6 lootedEvent uint32 linkedTrapId; //7 uint32 questId; //8 not used currently but store quest required for GO activation for player @@ -160,7 +160,7 @@ struct GameObjectTemplate uint32 pageID; //0 uint32 language; //1 uint32 pageMaterial; //2 - uint32 allowMounted; //3 + uint32 allowMounted; //3 Is usable while on mount/vehicle. (0/1) } text; //10 GAMEOBJECT_TYPE_GOOBER struct @@ -182,7 +182,7 @@ struct GameObjectTemplate uint32 openTextID; //14 can be used to replace castBarCaption? uint32 closeTextID; //15 uint32 losOK; //16 isBattlegroundObject - uint32 allowMounted; //17 + uint32 allowMounted; //17 Is usable while on mount/vehicle. (0/1) uint32 floatingTooltip; //18 uint32 gossipID; //19 uint32 WorldStateSetsState; //20 @@ -257,7 +257,7 @@ struct GameObjectTemplate uint32 spellId; //0 uint32 charges; //1 uint32 partyOnly; //2 - uint32 allowMounted; //3 + uint32 allowMounted; //3 Is usable while on mount/vehicle. (0/1) uint32 large; //4 } spellcaster; //23 GAMEOBJECT_TYPE_MEETINGSTONE @@ -409,6 +409,18 @@ struct GameObjectTemplate } } + bool IsUsableMounted() const + { + switch (type) + { + case GAMEOBJECT_TYPE_QUESTGIVER: return questgiver.allowMounted; + case GAMEOBJECT_TYPE_TEXT: return text.allowMounted; + case GAMEOBJECT_TYPE_GOOBER: return goober.allowMounted; + case GAMEOBJECT_TYPE_SPELLCASTER: return spellcaster.allowMounted; + default: return false; + } + } + uint32 GetLockId() const { switch (type) @@ -529,6 +541,11 @@ class OPvPCapturePoint; union GameObjectValue { + //25 GAMEOBJECT_TYPE_FISHINGHOLE + struct + { + uint32 MaxOpens; + } FishingHole; //29 GAMEOBJECT_TYPE_CAPTURE_POINT struct { @@ -790,7 +807,7 @@ class GameObject : public WorldObject, public GridObject<GameObject> void SetDisplayId(uint32 displayid); uint32 GetDisplayId() const { return GetUInt32Value(GAMEOBJECT_DISPLAYID); } - GameObjectModel * m_model; + GameObjectModel* m_model; protected: bool AIM_Initialize(); uint32 m_spellId; diff --git a/src/server/game/Entities/Item/Item.cpp b/src/server/game/Entities/Item/Item.cpp index 5dd726044ee..a88fdac2349 100644 --- a/src/server/game/Entities/Item/Item.cpp +++ b/src/server/game/Entities/Item/Item.cpp @@ -737,7 +737,7 @@ void Item::RemoveFromUpdateQueueOf(Player* player) if (!IsInUpdateQueue()) return; - ASSERT(player != NULL) + ASSERT(player != NULL); if (player->GetGUID() != GetOwnerGUID()) { @@ -1018,27 +1018,27 @@ void Item::SendTimeUpdate(Player* owner) owner->GetSession()->SendPacket(&data); } -Item* Item::CreateItem(uint32 item, uint32 count, Player const* player) +Item* Item::CreateItem(uint32 itemEntry, uint32 count, Player const* player) { if (count < 1) return NULL; //don't create item at zero count - ItemTemplate const* pProto = sObjectMgr->GetItemTemplate(item); - if (pProto) + ItemTemplate const* proto = sObjectMgr->GetItemTemplate(itemEntry); + if (proto) { - if (count > pProto->GetMaxStackSize()) - count = pProto->GetMaxStackSize(); + if (count > proto->GetMaxStackSize()) + count = proto->GetMaxStackSize(); ASSERT(count != 0 && "pProto->Stackable == 0 but checked at loading already"); - Item* pItem = NewItemOrBag(pProto); - if (pItem->Create(sObjectMgr->GenerateLowGuid(HIGHGUID_ITEM), item, player)) + Item* item = NewItemOrBag(proto); + if (item->Create(sObjectMgr->GenerateLowGuid(HIGHGUID_ITEM), itemEntry, player)) { - pItem->SetCount(count); - return pItem; + item->SetCount(count); + return item; } else - delete pItem; + delete item; } else ASSERT(false); @@ -1176,7 +1176,7 @@ bool Item::IsRefundExpired() return (GetPlayedTime() > 2*HOUR); } -void Item::SetSoulboundTradeable(AllowedLooterSet& allowedLooters) +void Item::SetSoulboundTradeable(AllowedLooterSet const& allowedLooters) { SetFlag(ITEM_FIELD_FLAGS, ITEM_FLAG_BOP_TRADEABLE); allowedGUIDs = allowedLooters; diff --git a/src/server/game/Entities/Item/Item.h b/src/server/game/Entities/Item/Item.h index 2f5ba02739d..0d34305d15c 100644 --- a/src/server/game/Entities/Item/Item.h +++ b/src/server/game/Entities/Item/Item.h @@ -208,7 +208,7 @@ bool ItemCanGoIntoBag(ItemTemplate const* proto, ItemTemplate const* pBagProto); class Item : public Object { public: - static Item* CreateItem(uint32 item, uint32 count, Player const* player = NULL); + static Item* CreateItem(uint32 itemEntry, uint32 count, Player const* player = NULL); Item* CloneItem(uint32 count, Player const* player = NULL) const; Item(); @@ -334,16 +334,17 @@ class Item : public Object void SetRefundRecipient(uint32 pGuidLow) { m_refundRecipient = pGuidLow; } void SetPaidMoney(uint32 money) { m_paidMoney = money; } void SetPaidExtendedCost(uint32 iece) { m_paidExtendedCost = iece; } - uint32 GetRefundRecipient() { return m_refundRecipient; } - uint32 GetPaidMoney() { return m_paidMoney; } - uint32 GetPaidExtendedCost() { return m_paidExtendedCost; } + + uint32 GetRefundRecipient() const { return m_refundRecipient; } + uint32 GetPaidMoney() const { return m_paidMoney; } + uint32 GetPaidExtendedCost() const { return m_paidExtendedCost; } void UpdatePlayedTime(Player* owner); uint32 GetPlayedTime(); bool IsRefundExpired(); // Soulbound trade system - void SetSoulboundTradeable(AllowedLooterSet& allowedLooters); + void SetSoulboundTradeable(AllowedLooterSet const& allowedLooters); void ClearSoulboundTradeable(Player* currentOwner); bool CheckSoulboundTradeExpire(); diff --git a/src/server/game/Entities/Item/ItemEnchantmentMgr.cpp b/src/server/game/Entities/Item/ItemEnchantmentMgr.cpp index 2b887672ec4..6a530a771f6 100644 --- a/src/server/game/Entities/Item/ItemEnchantmentMgr.cpp +++ b/src/server/game/Entities/Item/ItemEnchantmentMgr.cpp @@ -74,7 +74,7 @@ void LoadRandomEnchantmentsTable() sLog->outInfo(LOG_FILTER_SERVER_LOADING, ">> Loaded %u Item Enchantment definitions in %u ms", count, GetMSTimeDiffToNow(oldMSTime)); } else - sLog->outError(LOG_FILTER_SQL, ">> Loaded 0 Item Enchantment definitions. DB table `item_enchantment_template` is empty."); + sLog->outError(LOG_FILTER_SERVER_LOADING, ">> Loaded 0 Item Enchantment definitions. DB table `item_enchantment_template` is empty."); } uint32 GetItemEnchantMod(int32 entry) diff --git a/src/server/game/Entities/Item/ItemPrototype.h b/src/server/game/Entities/Item/ItemPrototype.h index f68923706ff..5fc49c99f0a 100644 --- a/src/server/game/Entities/Item/ItemPrototype.h +++ b/src/server/game/Entities/Item/ItemPrototype.h @@ -102,10 +102,8 @@ enum ItemBondingType #define MAX_BIND_TYPE 6 -/* TODO - // need to know cases when using item is not allowed in shapeshift - ITEM_PROTO_FLAG_USABLE_WHEN_SHAPESHIFTED = 0x00800000, // Item can be used in shapeshift forms -*/ +/* /// @todo: Requiring actual cases in which using (an) item isn't allowed while shapeshifted. Else, this flag would need an implementation. + ITEM_PROTO_FLAG_USABLE_WHEN_SHAPESHIFTED = 0x00800000, // Item can be used in shapeshift forms */ enum ItemProtoFlags { @@ -143,9 +141,6 @@ enum ItemProtoFlags ITEM_PROTO_FLAG_UNK12 = 0x80000000 // ? }; -/* TODO -*/ - enum ItemFieldFlags { ITEM_FLAG_SOULBOUND = 0x00000001, // Item is soulbound and cannot be traded <<-- diff --git a/src/server/game/Entities/Object/Object.cpp b/src/server/game/Entities/Object/Object.cpp index 1cd36aec78f..5b6bf87057f 100644 --- a/src/server/game/Entities/Object/Object.cpp +++ b/src/server/game/Entities/Object/Object.cpp @@ -75,7 +75,6 @@ Object::Object() : m_PackGUID(sizeof(uint64)+1) m_objectType = TYPEMASK_OBJECT; m_uint32Values = NULL; - _changedFields = NULL; m_valuesCount = 0; _fieldNotifyFlags = UF_FLAG_DYNAMIC; @@ -119,8 +118,7 @@ Object::~Object() } delete [] m_uint32Values; - delete [] _changedFields; - + m_uint32Values = 0; } void Object::_InitValues() @@ -128,8 +126,7 @@ void Object::_InitValues() m_uint32Values = new uint32[m_valuesCount]; memset(m_uint32Values, 0, m_valuesCount*sizeof(uint32)); - _changedFields = new bool[m_valuesCount]; - memset(_changedFields, 0, m_valuesCount*sizeof(bool)); + _changesMask.SetCount(m_valuesCount); m_objectUpdated = false; } @@ -323,6 +320,44 @@ void Object::DestroyForPlayer(Player* target, bool onDeath) const target->GetSession()->SendPacket(&data); } +int32 Object::GetInt32Value(uint16 index) const +{ + ASSERT(index < m_valuesCount || PrintIndexError(index, false)); + return m_int32Values[index]; +} + +uint32 Object::GetUInt32Value(uint16 index) const +{ + ASSERT(index < m_valuesCount || PrintIndexError(index, false)); + return m_uint32Values[index]; +} + +uint64 Object::GetUInt64Value(uint16 index) const +{ + ASSERT(index + 1 < m_valuesCount || PrintIndexError(index, false)); + return *((uint64*)&(m_uint32Values[index])); +} + +float Object::GetFloatValue(uint16 index) const +{ + ASSERT(index < m_valuesCount || PrintIndexError(index, false)); + return m_floatValues[index]; +} + +uint8 Object::GetByteValue(uint16 index, uint8 offset) const +{ + ASSERT(index < m_valuesCount || PrintIndexError(index, false)); + ASSERT(offset < 4); + return *(((uint8*)&m_uint32Values[index])+offset); +} + +uint16 Object::GetUInt16Value(uint16 index, uint8 offset) const +{ + ASSERT(index < m_valuesCount || PrintIndexError(index, false)); + ASSERT(offset < 2); + return *(((uint16*)&m_uint32Values[index])+offset); +} + void Object::_BuildMovementUpdate(ByteBuffer* data, uint16 flags) const { *data << uint16(flags); // update flags @@ -422,7 +457,7 @@ void Object::_BuildMovementUpdate(ByteBuffer* data, uint16 flags) const *data << uint32(GetGUIDLow()); // GetGUIDLow() break; //! Unit, Player and default here are sending wrong values. - //! TODO: Research the proper formula + /// @todo Research the proper formula case TYPEID_UNIT: *data << uint32(0x0000000B); // unk break; @@ -456,7 +491,7 @@ void Object::_BuildMovementUpdate(ByteBuffer* data, uint16 flags) const // 0x80 if (flags & UPDATEFLAG_VEHICLE) { - // TODO: Allow players to aquire this updateflag. + /// @todo Allow players to aquire this updateflag. *data << uint32(((Unit*)this)->GetVehicleKit()->GetVehicleInfo()->m_ID); *data << float(((Creature*)this)->GetOrientation()); } @@ -513,7 +548,7 @@ void Object::_BuildValuesUpdate(uint8 updatetype, ByteBuffer * data, UpdateMask* WPAssert(updateMask && updateMask->GetCount() == m_valuesCount); *data << (uint8)updateMask->GetBlockCount(); - data->append(updateMask->GetMask(), updateMask->GetLength()); + updateMask->AppendToPacket(data); // 2 specialized loops for speed optimization in non-unit case if (isType(TYPEMASK_UNIT)) // unit (creature/player) case @@ -757,7 +792,7 @@ void Object::_BuildValuesUpdate(uint8 updatetype, ByteBuffer * data, UpdateMask* void Object::ClearUpdateMask(bool remove) { - memset(_changedFields, 0, m_valuesCount*sizeof(bool)); + _changesMask.Clear(); if (m_objectUpdated) { @@ -781,64 +816,57 @@ void Object::BuildFieldsUpdate(Player* player, UpdateDataMapType& data_map) cons BuildValuesUpdateBlockForPlayer(&iter->second, iter->first); } -void Object::GetUpdateFieldData(Player const* target, uint32*& flags, bool& isOwner, bool& isItemOwner, bool& hasSpecialInfo, bool& isPartyMember) const +uint32 Object::GetUpdateFieldData(Player const* target, uint32*& flags) const { - // This function assumes updatefield index is always valid + uint32 visibleFlag = UF_FLAG_PUBLIC; + + if (target == this) + visibleFlag |= UF_FLAG_PRIVATE; + switch (GetTypeId()) { case TYPEID_ITEM: case TYPEID_CONTAINER: flags = ItemUpdateFieldFlags; - isOwner = isItemOwner = ((Item*)this)->GetOwnerGUID() == target->GetGUID(); + if (((Item*)this)->GetOwnerGUID() == target->GetGUID()) + visibleFlag |= UF_FLAG_OWNER | UF_FLAG_ITEM_OWNER; break; case TYPEID_UNIT: case TYPEID_PLAYER: { Player* plr = ToUnit()->GetCharmerOrOwnerPlayerOrPlayerItself(); flags = UnitUpdateFieldFlags; - isOwner = ToUnit()->GetOwnerGUID() == target->GetGUID(); - hasSpecialInfo = ToUnit()->HasAuraTypeWithCaster(SPELL_AURA_EMPATHY, target->GetGUID()); - isPartyMember = plr && plr->IsInSameGroupWith(target); + if (ToUnit()->GetOwnerGUID() == target->GetGUID()) + visibleFlag |= UF_FLAG_OWNER; + + if (HasFlag(UNIT_DYNAMIC_FLAGS, UNIT_DYNFLAG_SPECIALINFO)) + if (ToUnit()->HasAuraTypeWithCaster(SPELL_AURA_EMPATHY, target->GetGUID())) + visibleFlag |= UF_FLAG_SPECIAL_INFO; + + if (plr && plr->IsInSameRaidWith(target)) + visibleFlag |= UF_FLAG_PARTY_MEMBER; break; } case TYPEID_GAMEOBJECT: flags = GameObjectUpdateFieldFlags; - isOwner = ToGameObject()->GetOwnerGUID() == target->GetGUID(); + if (ToGameObject()->GetOwnerGUID() == target->GetGUID()) + visibleFlag |= UF_FLAG_OWNER; break; case TYPEID_DYNAMICOBJECT: flags = DynamicObjectUpdateFieldFlags; - isOwner = ((DynamicObject*)this)->GetCasterGUID() == target->GetGUID(); + if (((DynamicObject*)this)->GetCasterGUID() == target->GetGUID()) + visibleFlag |= UF_FLAG_OWNER; break; case TYPEID_CORPSE: flags = CorpseUpdateFieldFlags; - isOwner = ToCorpse()->GetOwnerGUID() == target->GetGUID(); + if (ToCorpse()->GetOwnerGUID() == target->GetGUID()) + visibleFlag |= UF_FLAG_OWNER; break; case TYPEID_OBJECT: break; } -} - -bool Object::IsUpdateFieldVisible(uint32 flags, bool isSelf, bool isOwner, bool isItemOwner, bool isPartyMember) const -{ - if (flags == UF_FLAG_NONE) - return false; - - if (flags & UF_FLAG_PUBLIC) - return true; - - if (flags & UF_FLAG_PRIVATE && isSelf) - return true; - - if (flags & UF_FLAG_OWNER && isOwner) - return true; - if (flags & UF_FLAG_ITEM_OWNER && isItemOwner) - return true; - - if (flags & UF_FLAG_PARTY_MEMBER && isPartyMember) - return true; - - return false; + return visibleFlag; } void Object::_LoadIntoDataField(std::string const& data, uint32 startOffset, uint32 count) @@ -854,24 +882,17 @@ void Object::_LoadIntoDataField(std::string const& data, uint32 startOffset, uin for (uint32 index = 0; index < count; ++index) { m_uint32Values[startOffset + index] = atol(tokens[index]); - _changedFields[startOffset + index] = true; + _changesMask.SetBit(startOffset + index); } } void Object::_SetUpdateBits(UpdateMask* updateMask, Player* target) const { - bool* indexes = _changedFields; uint32* flags = NULL; - bool isSelf = target == this; - bool isOwner = false; - bool isItemOwner = false; - bool hasSpecialInfo = false; - bool isPartyMember = false; - - GetUpdateFieldData(target, flags, isOwner, isItemOwner, hasSpecialInfo, isPartyMember); + uint32 visibleFlag = GetUpdateFieldData(target, flags); - for (uint16 index = 0; index < m_valuesCount; ++index, ++indexes) - if (_fieldNotifyFlags & flags[index] || (flags[index] & UF_FLAG_SPECIAL_INFO && hasSpecialInfo) || (*indexes && IsUpdateFieldVisible(flags[index], isSelf, isOwner, isItemOwner, isPartyMember))) + for (uint16 index = 0; index < m_valuesCount; ++index) + if (_fieldNotifyFlags & flags[index] || ((flags[index] & visibleFlag) & UF_FLAG_SPECIAL_INFO) || (_changesMask.GetBit(index) && (flags[index] & visibleFlag))) updateMask->SetBit(index); } @@ -879,16 +900,10 @@ void Object::_SetCreateBits(UpdateMask* updateMask, Player* target) const { uint32* value = m_uint32Values; uint32* flags = NULL; - bool isSelf = target == this; - bool isOwner = false; - bool isItemOwner = false; - bool hasSpecialInfo = false; - bool isPartyMember = false; - - GetUpdateFieldData(target, flags, isOwner, isItemOwner, hasSpecialInfo, isPartyMember); + uint32 visibleFlag = GetUpdateFieldData(target, flags); for (uint16 index = 0; index < m_valuesCount; ++index, ++value) - if (_fieldNotifyFlags & flags[index] || (flags[index] & UF_FLAG_SPECIAL_INFO && hasSpecialInfo) || (*value && IsUpdateFieldVisible(flags[index], isSelf, isOwner, isItemOwner, isPartyMember))) + if (_fieldNotifyFlags & flags[index] || ((flags[index] & visibleFlag) & UF_FLAG_SPECIAL_INFO) || (*value && (flags[index] & visibleFlag))) updateMask->SetBit(index); } @@ -899,7 +914,7 @@ void Object::SetInt32Value(uint16 index, int32 value) if (m_int32Values[index] != value) { m_int32Values[index] = value; - _changedFields[index] = true; + _changesMask.SetBit(index); if (m_inWorld && !m_objectUpdated) { @@ -916,7 +931,7 @@ void Object::SetUInt32Value(uint16 index, uint32 value) if (m_uint32Values[index] != value) { m_uint32Values[index] = value; - _changedFields[index] = true; + _changesMask.SetBit(index); if (m_inWorld && !m_objectUpdated) { @@ -931,7 +946,7 @@ void Object::UpdateUInt32Value(uint16 index, uint32 value) ASSERT(index < m_valuesCount || PrintIndexError(index, true)); m_uint32Values[index] = value; - _changedFields[index] = true; + _changesMask.SetBit(index); } void Object::SetUInt64Value(uint16 index, uint64 value) @@ -941,8 +956,8 @@ void Object::SetUInt64Value(uint16 index, uint64 value) { m_uint32Values[index] = PAIR64_LOPART(value); m_uint32Values[index + 1] = PAIR64_HIPART(value); - _changedFields[index] = true; - _changedFields[index + 1] = true; + _changesMask.SetBit(index); + _changesMask.SetBit(index + 1); if (m_inWorld && !m_objectUpdated) { @@ -959,8 +974,8 @@ bool Object::AddUInt64Value(uint16 index, uint64 value) { m_uint32Values[index] = PAIR64_LOPART(value); m_uint32Values[index + 1] = PAIR64_HIPART(value); - _changedFields[index] = true; - _changedFields[index + 1] = true; + _changesMask.SetBit(index); + _changesMask.SetBit(index + 1); if (m_inWorld && !m_objectUpdated) { @@ -981,8 +996,8 @@ bool Object::RemoveUInt64Value(uint16 index, uint64 value) { m_uint32Values[index] = 0; m_uint32Values[index + 1] = 0; - _changedFields[index] = true; - _changedFields[index + 1] = true; + _changesMask.SetBit(index); + _changesMask.SetBit(index + 1); if (m_inWorld && !m_objectUpdated) { @@ -1003,7 +1018,7 @@ void Object::SetFloatValue(uint16 index, float value) if (m_floatValues[index] != value) { m_floatValues[index] = value; - _changedFields[index] = true; + _changesMask.SetBit(index); if (m_inWorld && !m_objectUpdated) { @@ -1027,7 +1042,7 @@ void Object::SetByteValue(uint16 index, uint8 offset, uint8 value) { m_uint32Values[index] &= ~uint32(uint32(0xFF) << (offset * 8)); m_uint32Values[index] |= uint32(uint32(value) << (offset * 8)); - _changedFields[index] = true; + _changesMask.SetBit(index); if (m_inWorld && !m_objectUpdated) { @@ -1051,7 +1066,7 @@ void Object::SetUInt16Value(uint16 index, uint8 offset, uint16 value) { m_uint32Values[index] &= ~uint32(uint32(0xFFFF) << (offset * 16)); m_uint32Values[index] |= uint32(uint32(value) << (offset * 16)); - _changedFields[index] = true; + _changesMask.SetBit(index); if (m_inWorld && !m_objectUpdated) { @@ -1100,6 +1115,13 @@ void Object::ApplyModSignedFloatValue(uint16 index, float val, bool apply) SetFloatValue(index, cur); } +void Object::ApplyPercentModFloatValue(uint16 index, float val, bool apply) +{ + float value = GetFloatValue(index); + ApplyPercentModFloatVar(value, val, apply); + SetFloatValue(index, value); +} + void Object::ApplyModPositiveFloatValue(uint16 index, float val, bool apply) { float cur = GetFloatValue(index); @@ -1118,7 +1140,7 @@ void Object::SetFlag(uint16 index, uint32 newFlag) if (oldval != newval) { m_uint32Values[index] = newval; - _changedFields[index] = true; + _changesMask.SetBit(index); if (m_inWorld && !m_objectUpdated) { @@ -1139,7 +1161,7 @@ void Object::RemoveFlag(uint16 index, uint32 oldFlag) if (oldval != newval) { m_uint32Values[index] = newval; - _changedFields[index] = true; + _changesMask.SetBit(index); if (m_inWorld && !m_objectUpdated) { @@ -1149,6 +1171,27 @@ void Object::RemoveFlag(uint16 index, uint32 oldFlag) } } +void Object::ToggleFlag(uint16 index, uint32 flag) +{ + if (HasFlag(index, flag)) + RemoveFlag(index, flag); + else + SetFlag(index, flag); +} + +bool Object::HasFlag(uint16 index, uint32 flag) const +{ + if (index >= m_valuesCount && !PrintIndexError(index, false)) + return false; + + return (m_uint32Values[index] & flag) != 0; +} + +void Object::ApplyModFlag(uint16 index, uint32 flag, bool apply) +{ + if (apply) SetFlag(index, flag); else RemoveFlag(index, flag); +} + void Object::SetByteFlag(uint16 index, uint8 offset, uint8 newFlag) { ASSERT(index < m_valuesCount || PrintIndexError(index, true)); @@ -1162,7 +1205,7 @@ void Object::SetByteFlag(uint16 index, uint8 offset, uint8 newFlag) if (!(uint8(m_uint32Values[index] >> (offset * 8)) & newFlag)) { m_uint32Values[index] |= uint32(uint32(newFlag) << (offset * 8)); - _changedFields[index] = true; + _changesMask.SetBit(index); if (m_inWorld && !m_objectUpdated) { @@ -1185,7 +1228,7 @@ void Object::RemoveByteFlag(uint16 index, uint8 offset, uint8 oldFlag) if (uint8(m_uint32Values[index] >> (offset * 8)) & oldFlag) { m_uint32Values[index] &= ~uint32(uint32(oldFlag) << (offset * 8)); - _changedFields[index] = true; + _changesMask.SetBit(index); if (m_inWorld && !m_objectUpdated) { @@ -1195,6 +1238,54 @@ void Object::RemoveByteFlag(uint16 index, uint8 offset, uint8 oldFlag) } } +void Object::ToggleByteFlag(uint16 index, uint8 offset, uint8 flag) +{ + if (HasByteFlag(index, offset, flag)) + RemoveByteFlag(index, offset, flag); + else + SetByteFlag(index, offset, flag); +} + +bool Object::HasByteFlag(uint16 index, uint8 offset, uint8 flag) const +{ + ASSERT(index < m_valuesCount || PrintIndexError(index, false)); + ASSERT(offset < 4); + return (((uint8*)&m_uint32Values[index])[offset] & flag) != 0; +} + +void Object::SetFlag64(uint16 index, uint64 newFlag) +{ + uint64 oldval = GetUInt64Value(index); + uint64 newval = oldval | newFlag; + SetUInt64Value(index, newval); +} + +void Object::RemoveFlag64(uint16 index, uint64 oldFlag) +{ + uint64 oldval = GetUInt64Value(index); + uint64 newval = oldval & ~oldFlag; + SetUInt64Value(index, newval); +} + +void Object::ToggleFlag64(uint16 index, uint64 flag) +{ + if (HasFlag64(index, flag)) + RemoveFlag64(index, flag); + else + SetFlag64(index, flag); +} + +bool Object::HasFlag64(uint16 index, uint64 flag) const +{ + ASSERT(index < m_valuesCount || PrintIndexError(index, false)); + return (GetUInt64Value(index) & flag) != 0; +} + +void Object::ApplyModFlag64(uint16 index, uint64 flag, bool apply) +{ + if (apply) SetFlag64(index, flag); else RemoveFlag64(index, flag); +} + bool Object::PrintIndexError(uint32 index, bool set) const { sLog->outError(LOG_FILTER_GENERAL, "Attempt %s non-existed value field: %u (count: %u) for object typeid: %u type mask: %u", (set ? "set value to" : "get value from"), index, m_valuesCount, GetTypeId(), m_objectType); @@ -1353,6 +1444,16 @@ void WorldObject::_Create(uint32 guidlow, HighGuid guidhigh, uint32 phaseMask) m_phaseMask = phaseMask; } +void WorldObject::RemoveFromWorld() +{ + if (!IsInWorld()) + return; + + DestroyForNearbyPlayers(); + + Object::RemoveFromWorld(); +} + uint32 WorldObject::GetZoneId() const { return GetBaseMap()->GetZoneId(m_positionX, m_positionY, m_positionZ); @@ -1422,6 +1523,80 @@ bool WorldObject::IsWithinLOSInMap(const WorldObject* obj) const return IsWithinLOS(ox, oy, oz); } +float WorldObject::GetDistance(const WorldObject* obj) const +{ + float d = GetExactDist(obj) - GetObjectSize() - obj->GetObjectSize(); + return d > 0.0f ? d : 0.0f; +} + +float WorldObject::GetDistance(const Position &pos) const +{ + float d = GetExactDist(&pos) - GetObjectSize(); + return d > 0.0f ? d : 0.0f; +} + +float WorldObject::GetDistance(float x, float y, float z) const +{ + float d = GetExactDist(x, y, z) - GetObjectSize(); + return d > 0.0f ? d : 0.0f; +} + +float WorldObject::GetDistance2d(const WorldObject* obj) const +{ + float d = GetExactDist2d(obj) - GetObjectSize() - obj->GetObjectSize(); + return d > 0.0f ? d : 0.0f; +} + +float WorldObject::GetDistance2d(float x, float y) const +{ + float d = GetExactDist2d(x, y) - GetObjectSize(); + return d > 0.0f ? d : 0.0f; +} + +bool WorldObject::IsSelfOrInSameMap(const WorldObject* obj) const +{ + if (this == obj) + return true; + return IsInMap(obj); +} + +bool WorldObject::IsInMap(const WorldObject* obj) const +{ + if (obj) + return IsInWorld() && obj->IsInWorld() && (GetMap() == obj->GetMap()); + return false; +} + +bool WorldObject::IsWithinDist3d(float x, float y, float z, float dist) const +{ + return IsInDist(x, y, z, dist + GetObjectSize()); +} + +bool WorldObject::IsWithinDist3d(const Position* pos, float dist) const +{ + return IsInDist(pos, dist + GetObjectSize()); +} + +bool WorldObject::IsWithinDist2d(float x, float y, float dist) const +{ + return IsInDist2d(x, y, dist + GetObjectSize()); +} + +bool WorldObject::IsWithinDist2d(const Position* pos, float dist) const +{ + return IsInDist2d(pos, dist + GetObjectSize()); +} + +bool WorldObject::IsWithinDist(WorldObject const* obj, float dist2compare, bool is3D /*= true*/) const +{ + return obj && _IsWithinDist(obj, dist2compare, is3D); +} + +bool WorldObject::IsWithinDistInMap(WorldObject const* obj, float dist2compare, bool is3D /*= true*/) const +{ + return obj && IsInMap(obj) && InSamePhase(obj) && _IsWithinDist(obj, dist2compare, is3D); +} + bool WorldObject::IsWithinLOS(float ox, float oy, float oz) const { /*float x, y, z; @@ -1653,6 +1828,13 @@ void WorldObject::GetRandomPoint(const Position &pos, float distance, float &ran UpdateGroundPositionZ(rand_x, rand_y, rand_z); // update to LOS height if available } +void WorldObject::GetRandomPoint(const Position &srcPos, float distance, Position &pos) const +{ + float x, y, z; + GetRandomPoint(srcPos, distance, x, y, z); + pos.Relocate(x, y, z, GetOrientation()); +} + void WorldObject::UpdateGroundPositionZ(float x, float y, float &z) const { float new_z = GetBaseMap()->GetHeight(GetPhaseMask(), x, y, z, true); @@ -1845,6 +2027,11 @@ bool WorldObject::canSeeOrDetect(WorldObject const* obj, bool ignoreStealth, boo return true; } +bool WorldObject::CanNeverSee(WorldObject const* obj) const +{ + return GetMap() != obj->GetMap() || !InSamePhase(obj); +} + bool WorldObject::CanDetect(WorldObject const* obj, bool ignoreStealth) const { const WorldObject* seer = this; @@ -1968,7 +2155,7 @@ void WorldObject::SendPlaySound(uint32 Sound, bool OnlySelf) void Object::ForceValuesUpdateAtIndex(uint32 i) { - _changedFields[i] = true; + _changesMask.SetBit(i); if (m_inWorld && !m_objectUpdated) { sObjectAccessor->AddUpdateObject(this); @@ -1987,7 +2174,7 @@ namespace Trinity { char const* text = sObjectMgr->GetTrinityString(i_textId, loc_idx); - // TODO: i_object.GetName() also must be localized? + /// @todo i_object.GetName() also must be localized? i_object.BuildMonsterChat(&data, i_msgtype, text, i_language, i_object.GetNameForLocaleIdx(loc_idx), i_targetGUID); } @@ -2006,7 +2193,7 @@ namespace Trinity : i_object(obj), i_msgtype(msgtype), i_text(text), i_language(language), i_targetGUID(targetGUID) {} void operator()(WorldPacket& data, LocaleConstant loc_idx) { - // TODO: i_object.GetName() also must be localized? + /// @todo i_object.GetName() also must be localized? i_object.BuildMonsterChat(&data, i_msgtype, i_text, i_language, i_object.GetNameForLocaleIdx(loc_idx), i_targetGUID); } @@ -2339,6 +2526,25 @@ TempSummon* Map::SummonCreature(uint32 entry, Position const& pos, SummonPropert return summon; } +/** +* Summons group of creatures. +* +* @param group Id of group to summon. +* @param list List to store pointers to summoned creatures. +*/ + +void Map::SummonCreatureGroup(uint8 group, std::list<TempSummon*>* list /*= NULL*/) +{ + std::vector<TempSummonData> const* data = sObjectMgr->GetSummonGroup(GetId(), SUMMONER_TYPE_MAP, group); + if (!data) + return; + + for (std::vector<TempSummonData>::const_iterator itr = data->begin(); itr != data->end(); ++itr) + if (TempSummon* summon = SummonCreature(itr->entry, itr->pos, NULL, itr->time)) + if (list) + list->push_back(summon); +} + void WorldObject::SetZoneScript() { if (Map* map = FindMap()) @@ -2369,6 +2575,18 @@ TempSummon* WorldObject::SummonCreature(uint32 entry, const Position &pos, TempS return NULL; } +TempSummon* WorldObject::SummonCreature(uint32 id, float x, float y, float z, float ang /*= 0*/, TempSummonType spwtype /*= TEMPSUMMON_MANUAL_DESPAWN*/, uint32 despwtime /*= 0*/) const +{ + if (!x && !y && !z) + { + GetClosePoint(x, y, z, GetObjectSize()); + ang = GetOrientation(); + } + Position pos; + pos.Relocate(x, y, z, ang); + return SummonCreature(id, pos, spwtype, despwtime, 0); +} + GameObject* WorldObject::SummonGameObject(uint32 entry, float x, float y, float z, float ang, float rotation0, float rotation1, float rotation2, float rotation3, uint32 respawnTime) { if (!IsInWorld()) @@ -2418,6 +2636,26 @@ Creature* WorldObject::SummonTrigger(float x, float y, float z, float ang, uint3 return summon; } +/** +* Summons group of creatures. Should be called only by instances of Creature and GameObject classes. +* +* @param group Id of group to summon. +* @param list List to store pointers to summoned creatures. +*/ +void WorldObject::SummonCreatureGroup(uint8 group, std::list<TempSummon*>* list /*= NULL*/) +{ + ASSERT((GetTypeId() == TYPEID_GAMEOBJECT || GetTypeId() == TYPEID_UNIT) && "Only GOs and creatures can summon npc groups!"); + + std::vector<TempSummonData> const* data = sObjectMgr->GetSummonGroup(GetEntry(), GetTypeId() == TYPEID_GAMEOBJECT ? SUMMONER_TYPE_GAMEOBJECT : SUMMONER_TYPE_CREATURE, group); + if (!data) + return; + + for (std::vector<TempSummonData>::const_iterator itr = data->begin(); itr != data->end(); ++itr) + if (TempSummon* summon = SummonCreature(itr->entry, itr->pos, itr->type, itr->time)) + if (list) + list->push_back(summon); +} + Creature* WorldObject::FindNearestCreature(uint32 entry, float range, bool alive) const { Creature* creature = NULL; @@ -2680,6 +2918,41 @@ void WorldObject::GetNearPoint(WorldObject const* /*searcher*/, float &x, float */ } +void WorldObject::GetClosePoint(float &x, float &y, float &z, float size, float distance2d /*= 0*/, float angle /*= 0*/) const +{ + // angle calculated from current orientation + GetNearPoint(NULL, x, y, z, size, distance2d, GetOrientation() + angle); +} + +void WorldObject::GetNearPosition(Position &pos, float dist, float angle) +{ + GetPosition(&pos); + MovePosition(pos, dist, angle); +} + +void WorldObject::GetFirstCollisionPosition(Position &pos, float dist, float angle) +{ + GetPosition(&pos); + MovePositionToFirstCollision(pos, dist, angle); +} + +void WorldObject::GetRandomNearPosition(Position &pos, float radius) +{ + GetPosition(&pos); + MovePosition(pos, radius * (float)rand_norm(), (float)rand_norm() * static_cast<float>(2 * M_PI)); +} + +void WorldObject::GetContactPoint(const WorldObject* obj, float &x, float &y, float &z, float distance2d /*= CONTACT_DISTANCE*/) const +{ + // angle to face `obj` to `this` using distance includes size of `obj` + GetNearPoint(obj, x, y, z, obj->GetObjectSize(), distance2d, GetAngle(obj)); +} + +float WorldObject::GetObjectSize() const +{ + return (m_valuesCount > UNIT_FIELD_COMBATREACH) ? m_floatValues[UNIT_FIELD_COMBATREACH] : DEFAULT_WORLD_OBJECT_SIZE; +} + void WorldObject::MovePosition(Position &pos, float dist, float angle) { angle += m_orientation; @@ -2688,7 +2961,7 @@ void WorldObject::MovePosition(Position &pos, float dist, float angle) desty = pos.m_positionY + dist * std::sin(angle); // Prevent invalid coordinates here, position is unchanged - if (!Trinity::IsValidMapCoord(destx, desty)) + if (!Trinity::IsValidMapCoord(destx, desty, pos.m_positionZ)) { sLog->outFatal(LOG_FILTER_GENERAL, "WorldObject::MovePosition invalid coordinates X: %f and Y: %f were passed!", destx, desty); return; @@ -2801,6 +3074,11 @@ void WorldObject::SetPhaseMask(uint32 newPhaseMask, bool update) UpdateObjectVisibility(); } +bool WorldObject::InSamePhase(WorldObject const* obj) const +{ + return InSamePhase(obj->GetPhaseMask()); +} + void WorldObject::PlayDistanceSound(uint32 sound_id, Player* target /*= NULL*/) { WorldPacket data(SMSG_PLAY_OBJECT_SOUND, 4+8); @@ -2841,7 +3119,7 @@ void WorldObject::DestroyForNearbyPlayers() if (!player->HaveAtClient(this)) continue; - if (isType(TYPEMASK_UNIT) && ((Unit*)this)->GetCharmerGUID() == player->GetGUID()) // TODO: this is for puppet + if (isType(TYPEMASK_UNIT) && ((Unit*)this)->GetCharmerGUID() == player->GetGUID()) /// @todo this is for puppet continue; DestroyForPlayer(player); diff --git a/src/server/game/Entities/Object/Object.h b/src/server/game/Entities/Object/Object.h index a9afd074c67..6c54ccfbdf7 100644 --- a/src/server/game/Entities/Object/Object.h +++ b/src/server/game/Entities/Object/Object.h @@ -20,7 +20,7 @@ #define _OBJECT_H #include "Common.h" -#include "UpdateFields.h" +#include "UpdateMask.h" #include "UpdateData.h" #include "GridReference.h" #include "ObjectDefines.h" @@ -107,7 +107,6 @@ class ByteBuffer; class WorldSession; class Creature; class Player; -class UpdateMask; class InstanceScript; class GameObject; class TempSummon; @@ -151,43 +150,12 @@ class Object virtual void DestroyForPlayer(Player* target, bool onDeath = false) const; - int32 GetInt32Value(uint16 index) const - { - ASSERT(index < m_valuesCount || PrintIndexError(index, false)); - return m_int32Values[index]; - } - - uint32 GetUInt32Value(uint16 index) const - { - ASSERT(index < m_valuesCount || PrintIndexError(index, false)); - return m_uint32Values[index]; - } - - uint64 GetUInt64Value(uint16 index) const - { - ASSERT(index + 1 < m_valuesCount || PrintIndexError(index, false)); - return *((uint64*)&(m_uint32Values[index])); - } - - float GetFloatValue(uint16 index) const - { - ASSERT(index < m_valuesCount || PrintIndexError(index, false)); - return m_floatValues[index]; - } - - uint8 GetByteValue(uint16 index, uint8 offset) const - { - ASSERT(index < m_valuesCount || PrintIndexError(index, false)); - ASSERT(offset < 4); - return *(((uint8*)&m_uint32Values[index])+offset); - } - - uint16 GetUInt16Value(uint16 index, uint8 offset) const - { - ASSERT(index < m_valuesCount || PrintIndexError(index, false)); - ASSERT(offset < 2); - return *(((uint16*)&m_uint32Values[index])+offset); - } + int32 GetInt32Value(uint16 index) const; + uint32 GetUInt32Value(uint16 index) const; + uint64 GetUInt64Value(uint16 index) const; + float GetFloatValue(uint16 index) const; + uint8 GetByteValue(uint16 index, uint8 offset) const; + uint16 GetUInt16Value(uint16 index, uint8 offset) const; void SetInt32Value(uint16 index, int32 value); void SetUInt32Value(uint16 index, uint32 value); @@ -208,88 +176,24 @@ class Object void ApplyModUInt64Value(uint16 index, int32 val, bool apply); void ApplyModPositiveFloatValue(uint16 index, float val, bool apply); void ApplyModSignedFloatValue(uint16 index, float val, bool apply); - - void ApplyPercentModFloatValue(uint16 index, float val, bool apply) - { - float value = GetFloatValue(index); - ApplyPercentModFloatVar(value, val, apply); - SetFloatValue(index, value); - } + void ApplyPercentModFloatValue(uint16 index, float val, bool apply); void SetFlag(uint16 index, uint32 newFlag); void RemoveFlag(uint16 index, uint32 oldFlag); - - void ToggleFlag(uint16 index, uint32 flag) - { - if (HasFlag(index, flag)) - RemoveFlag(index, flag); - else - SetFlag(index, flag); - } - - bool HasFlag(uint16 index, uint32 flag) const - { - if (index >= m_valuesCount && !PrintIndexError(index, false)) - return false; - - return (m_uint32Values[index] & flag) != 0; - } + void ToggleFlag(uint16 index, uint32 flag); + bool HasFlag(uint16 index, uint32 flag) const; + void ApplyModFlag(uint16 index, uint32 flag, bool apply); void SetByteFlag(uint16 index, uint8 offset, uint8 newFlag); void RemoveByteFlag(uint16 index, uint8 offset, uint8 newFlag); + void ToggleByteFlag(uint16 index, uint8 offset, uint8 flag); + bool HasByteFlag(uint16 index, uint8 offset, uint8 flag) const; - void ToggleFlag(uint16 index, uint8 offset, uint8 flag) - { - if (HasByteFlag(index, offset, flag)) - RemoveByteFlag(index, offset, flag); - else - SetByteFlag(index, offset, flag); - } - - bool HasByteFlag(uint16 index, uint8 offset, uint8 flag) const - { - ASSERT(index < m_valuesCount || PrintIndexError(index, false)); - ASSERT(offset < 4); - return (((uint8*)&m_uint32Values[index])[offset] & flag) != 0; - } - - void ApplyModFlag(uint16 index, uint32 flag, bool apply) - { - if (apply) SetFlag(index, flag); else RemoveFlag(index, flag); - } - - void SetFlag64(uint16 index, uint64 newFlag) - { - uint64 oldval = GetUInt64Value(index); - uint64 newval = oldval | newFlag; - SetUInt64Value(index, newval); - } - - void RemoveFlag64(uint16 index, uint64 oldFlag) - { - uint64 oldval = GetUInt64Value(index); - uint64 newval = oldval & ~oldFlag; - SetUInt64Value(index, newval); - } - - void ToggleFlag64(uint16 index, uint64 flag) - { - if (HasFlag64(index, flag)) - RemoveFlag64(index, flag); - else - SetFlag64(index, flag); - } - - bool HasFlag64(uint16 index, uint64 flag) const - { - ASSERT(index < m_valuesCount || PrintIndexError(index, false)); - return (GetUInt64Value(index) & flag) != 0; - } - - void ApplyModFlag64(uint16 index, uint64 flag, bool apply) - { - if (apply) SetFlag64(index, flag); else RemoveFlag64(index, flag); - } + void SetFlag64(uint16 index, uint64 newFlag); + void RemoveFlag64(uint16 index, uint64 oldFlag); + void ToggleFlag64(uint16 index, uint64 flag); + bool HasFlag64(uint16 index, uint64 flag) const; + void ApplyModFlag64(uint16 index, uint64 flag, bool apply); void ClearUpdateMask(bool remove); @@ -307,19 +211,21 @@ class Object void ForceValuesUpdateAtIndex(uint32); Player* ToPlayer() { if (GetTypeId() == TYPEID_PLAYER) return reinterpret_cast<Player*>(this); else return NULL; } - Player const* ToPlayer() const { if (GetTypeId() == TYPEID_PLAYER) return (Player const*)((Player*)this); else return NULL; } + Player const* ToPlayer() const { if (GetTypeId() == TYPEID_PLAYER) return reinterpret_cast<Player const*>(this); else return NULL; } + Creature* ToCreature() { if (GetTypeId() == TYPEID_UNIT) return reinterpret_cast<Creature*>(this); else return NULL; } - Creature const* ToCreature() const { if (GetTypeId() == TYPEID_UNIT) return (Creature const*)((Creature*)this); else return NULL; } + Creature const* ToCreature() const { if (GetTypeId() == TYPEID_UNIT) return reinterpret_cast<Creature const*>(this); else return NULL; } + + Unit* ToUnit() { if (isType(TYPEMASK_UNIT)) return reinterpret_cast<Unit*>(this); else return NULL; } + Unit const* ToUnit() const { if (isType(TYPEMASK_UNIT)) return reinterpret_cast<Unit const*>(this); else return NULL; } - Unit* ToUnit() { if (GetTypeId() == TYPEID_UNIT || GetTypeId() == TYPEID_PLAYER) return reinterpret_cast<Unit*>(this); else return NULL; } - Unit const* ToUnit() const { if (GetTypeId() == TYPEID_UNIT || GetTypeId() == TYPEID_PLAYER) return (const Unit*)((Unit*)this); else return NULL; } GameObject* ToGameObject() { if (GetTypeId() == TYPEID_GAMEOBJECT) return reinterpret_cast<GameObject*>(this); else return NULL; } - GameObject const* ToGameObject() const { if (GetTypeId() == TYPEID_GAMEOBJECT) return (const GameObject*)((GameObject*)this); else return NULL; } + GameObject const* ToGameObject() const { if (GetTypeId() == TYPEID_GAMEOBJECT) return reinterpret_cast<GameObject const*>(this); else return NULL; } Corpse* ToCorpse() { if (GetTypeId() == TYPEID_CORPSE) return reinterpret_cast<Corpse*>(this); else return NULL; } - Corpse const* ToCorpse() const { if (GetTypeId() == TYPEID_CORPSE) return (const Corpse*)((Corpse*)this); else return NULL; } - protected: + Corpse const* ToCorpse() const { if (GetTypeId() == TYPEID_CORPSE) return reinterpret_cast<Corpse const*>(this); else return NULL; } + protected: Object(); void _InitValues(); @@ -327,9 +233,7 @@ class Object std::string _ConcatFields(uint16 startIndex, uint16 size) const; void _LoadIntoDataField(std::string const& data, uint32 startOffset, uint32 count); - void GetUpdateFieldData(Player const* target, uint32*& flags, bool& isOwner, bool& isItemOwner, bool& hasSpecialInfo, bool& isPartyMember) const; - - bool IsUpdateFieldVisible(uint32 flags, bool isSelf, bool isOwner, bool isItemOwner, bool isPartyMember) const; + uint32 GetUpdateFieldData(Player const* target, uint32*& flags) const; void _SetUpdateBits(UpdateMask* updateMask, Player* target) const; void _SetCreateBits(UpdateMask* updateMask, Player* target) const; @@ -348,7 +252,7 @@ class Object float *m_floatValues; }; - bool* _changedFields; + UpdateMask _changesMask; uint16 m_valuesCount; @@ -584,68 +488,30 @@ class WorldObject : public Object, public WorldLocation virtual void Update (uint32 /*time_diff*/) { } void _Create(uint32 guidlow, HighGuid guidhigh, uint32 phaseMask); - - virtual void RemoveFromWorld() - { - if (!IsInWorld()) - return; - - DestroyForNearbyPlayers(); - - Object::RemoveFromWorld(); - } + virtual void RemoveFromWorld(); void GetNearPoint2D(float &x, float &y, float distance, float absAngle) const; void GetNearPoint(WorldObject const* searcher, float &x, float &y, float &z, float searcher_size, float distance2d, float absAngle) const; - void GetClosePoint(float &x, float &y, float &z, float size, float distance2d = 0, float angle = 0) const - { - // angle calculated from current orientation - GetNearPoint(NULL, x, y, z, size, distance2d, GetOrientation() + angle); - } + void GetClosePoint(float &x, float &y, float &z, float size, float distance2d = 0, float angle = 0) const; void MovePosition(Position &pos, float dist, float angle); - void GetNearPosition(Position &pos, float dist, float angle) - { - GetPosition(&pos); - MovePosition(pos, dist, angle); - } + void GetNearPosition(Position &pos, float dist, float angle); void MovePositionToFirstCollision(Position &pos, float dist, float angle); - void GetFirstCollisionPosition(Position &pos, float dist, float angle) - { - GetPosition(&pos); - MovePositionToFirstCollision(pos, dist, angle); - } - void GetRandomNearPosition(Position &pos, float radius) - { - GetPosition(&pos); - MovePosition(pos, radius * (float)rand_norm(), (float)rand_norm() * static_cast<float>(2 * M_PI)); - } - - void GetContactPoint(const WorldObject* obj, float &x, float &y, float &z, float distance2d = CONTACT_DISTANCE) const - { - // angle to face `obj` to `this` using distance includes size of `obj` - GetNearPoint(obj, x, y, z, obj->GetObjectSize(), distance2d, GetAngle(obj)); - } + void GetFirstCollisionPosition(Position &pos, float dist, float angle); + void GetRandomNearPosition(Position &pos, float radius); + void GetContactPoint(const WorldObject* obj, float &x, float &y, float &z, float distance2d = CONTACT_DISTANCE) const; - float GetObjectSize() const - { - return (m_valuesCount > UNIT_FIELD_COMBATREACH) ? m_floatValues[UNIT_FIELD_COMBATREACH] : DEFAULT_WORLD_OBJECT_SIZE; - } + float GetObjectSize() const; void UpdateGroundPositionZ(float x, float y, float &z) const; void UpdateAllowedPositionZ(float x, float y, float &z) const; void GetRandomPoint(const Position &srcPos, float distance, float &rand_x, float &rand_y, float &rand_z) const; - void GetRandomPoint(const Position &srcPos, float distance, Position &pos) const - { - float x, y, z; - GetRandomPoint(srcPos, distance, x, y, z); - pos.Relocate(x, y, z, GetOrientation()); - } + void GetRandomPoint(const Position &srcPos, float distance, Position &pos) const; uint32 GetInstanceId() const { return m_InstanceId; } virtual void SetPhaseMask(uint32 newPhaseMask, bool update); uint32 GetPhaseMask() const { return m_phaseMask; } - bool InSamePhase(WorldObject const* obj) const { return InSamePhase(obj->GetPhaseMask()); } + bool InSamePhase(WorldObject const* obj) const; bool InSamePhase(uint32 phasemask) const { return (GetPhaseMask() & phasemask); } uint32 GetZoneId() const; @@ -659,62 +525,22 @@ class WorldObject : public Object, public WorldLocation virtual std::string const& GetNameForLocaleIdx(LocaleConstant /*locale_idx*/) const { return m_name; } - float GetDistance(const WorldObject* obj) const - { - float d = GetExactDist(obj) - GetObjectSize() - obj->GetObjectSize(); - return d > 0.0f ? d : 0.0f; - } - float GetDistance(const Position &pos) const - { - float d = GetExactDist(&pos) - GetObjectSize(); - return d > 0.0f ? d : 0.0f; - } - float GetDistance(float x, float y, float z) const - { - float d = GetExactDist(x, y, z) - GetObjectSize(); - return d > 0.0f ? d : 0.0f; - } - float GetDistance2d(const WorldObject* obj) const - { - float d = GetExactDist2d(obj) - GetObjectSize() - obj->GetObjectSize(); - return d > 0.0f ? d : 0.0f; - } - float GetDistance2d(float x, float y) const - { - float d = GetExactDist2d(x, y) - GetObjectSize(); - return d > 0.0f ? d : 0.0f; - } + float GetDistance(const WorldObject* obj) const; + float GetDistance(const Position &pos) const; + float GetDistance(float x, float y, float z) const; + float GetDistance2d(const WorldObject* obj) const; + float GetDistance2d(float x, float y) const; float GetDistanceZ(const WorldObject* obj) const; - bool IsSelfOrInSameMap(const WorldObject* obj) const - { - if (this == obj) - return true; - return IsInMap(obj); - } - bool IsInMap(const WorldObject* obj) const - { - if (obj) - return IsInWorld() && obj->IsInWorld() && (GetMap() == obj->GetMap()); - return false; - } - bool IsWithinDist3d(float x, float y, float z, float dist) const - { return IsInDist(x, y, z, dist + GetObjectSize()); } - bool IsWithinDist3d(const Position* pos, float dist) const - { return IsInDist(pos, dist + GetObjectSize()); } - bool IsWithinDist2d(float x, float y, float dist) const - { return IsInDist2d(x, y, dist + GetObjectSize()); } - bool IsWithinDist2d(const Position* pos, float dist) const - { return IsInDist2d(pos, dist + GetObjectSize()); } + bool IsSelfOrInSameMap(const WorldObject* obj) const; + bool IsInMap(const WorldObject* obj) const; + bool IsWithinDist3d(float x, float y, float z, float dist) const; + bool IsWithinDist3d(const Position* pos, float dist) const; + bool IsWithinDist2d(float x, float y, float dist) const; + bool IsWithinDist2d(const Position* pos, float dist) const; // use only if you will sure about placing both object at same map - bool IsWithinDist(WorldObject const* obj, float dist2compare, bool is3D = true) const - { - return obj && _IsWithinDist(obj, dist2compare, is3D); - } - bool IsWithinDistInMap(WorldObject const* obj, float dist2compare, bool is3D = true) const - { - return obj && IsInMap(obj) && InSamePhase(obj) && _IsWithinDist(obj, dist2compare, is3D); - } + bool IsWithinDist(WorldObject const* obj, float dist2compare, bool is3D = true) const; + bool IsWithinDistInMap(WorldObject const* obj, float dist2compare, bool is3D = true) const; bool IsWithinLOS(float x, float y, float z) const; bool IsWithinLOSInMap(const WorldObject* obj) const; bool GetDistanceOrder(WorldObject const* obj1, WorldObject const* obj2, bool is3D = true) const; @@ -783,19 +609,10 @@ class WorldObject : public Object, public WorldLocation ZoneScript* GetZoneScript() const { return m_zoneScript; } TempSummon* SummonCreature(uint32 id, const Position &pos, TempSummonType spwtype = TEMPSUMMON_MANUAL_DESPAWN, uint32 despwtime = 0, uint32 vehId = 0) const; - TempSummon* SummonCreature(uint32 id, float x, float y, float z, float ang = 0, TempSummonType spwtype = TEMPSUMMON_MANUAL_DESPAWN, uint32 despwtime = 0) - { - if (!x && !y && !z) - { - GetClosePoint(x, y, z, GetObjectSize()); - ang = GetOrientation(); - } - Position pos; - pos.Relocate(x, y, z, ang); - return SummonCreature(id, pos, spwtype, despwtime, 0); - } + TempSummon* SummonCreature(uint32 id, float x, float y, float z, float ang = 0, TempSummonType spwtype = TEMPSUMMON_MANUAL_DESPAWN, uint32 despwtime = 0) const; GameObject* SummonGameObject(uint32 entry, float x, float y, float z, float ang, float rotation0, float rotation1, float rotation2, float rotation3, uint32 respawnTime); Creature* SummonTrigger(float x, float y, float z, float ang, uint32 dur, CreatureAI* (*GetAI)(Creature*) = NULL); + void SummonCreatureGroup(uint8 group, std::list<TempSummon*>* list = NULL); Creature* FindNearestCreature(uint32 entry, float range, bool alive = true) const; GameObject* FindNearestGameObject(uint32 entry, float range) const; @@ -880,7 +697,7 @@ class WorldObject : public Object, public WorldLocation virtual bool _IsWithinDist(WorldObject const* obj, float dist2compare, bool is3D) const; - bool CanNeverSee(WorldObject const* obj) const { return GetMap() != obj->GetMap() || !InSamePhase(obj); } + bool CanNeverSee(WorldObject const* obj) const; virtual bool CanAlwaysSee(WorldObject const* /*obj*/) const { return false; } bool CanDetect(WorldObject const* obj, bool ignoreStealth) const; bool CanDetectInvisibilityOf(WorldObject const* obj) const; diff --git a/src/server/game/Entities/Object/Updates/UpdateMask.h b/src/server/game/Entities/Object/Updates/UpdateMask.h index 784c4eba96f..8be8dfecdaf 100644 --- a/src/server/game/Entities/Object/Updates/UpdateMask.h +++ b/src/server/game/Entities/Object/Updates/UpdateMask.h @@ -21,106 +21,106 @@ #include "UpdateFields.h" #include "Errors.h" +#include "ByteBuffer.h" class UpdateMask { public: - UpdateMask() : mCount(0), mBlocks(0), mUpdateMask(0) { } - UpdateMask(UpdateMask const& mask) : mUpdateMask(0) { *this = mask; } + /// Type representing how client reads update mask + typedef uint32 ClientUpdateMaskType; - ~UpdateMask() + enum UpdateMaskCount { - delete[] mUpdateMask; - } + CLIENT_UPDATE_MASK_BITS = sizeof(ClientUpdateMaskType) * 8, + }; - void SetBit(uint32 index) - { - ((uint8*)mUpdateMask)[index >> 3] |= 1 << (index & 0x7); - } + UpdateMask() : _fieldCount(0), _blockCount(0), _bits(NULL) { } - void UnsetBit(uint32 index) + UpdateMask(UpdateMask const& right) { - ((uint8*)mUpdateMask)[index >> 3] &= (0xff ^ (1 << (index & 0x7))); + SetCount(right.GetCount()); + memcpy(_bits, right._bits, sizeof(uint8) * _blockCount * 32); } - bool GetBit(uint32 index) const + ~UpdateMask() { delete[] _bits; } + + void SetBit(uint32 index) { _bits[index] = 1; } + void UnsetBit(uint32 index) { _bits[index] = 0; } + bool GetBit(uint32 index) const { return _bits[index] != 0; } + + void AppendToPacket(ByteBuffer* data) { - return (((uint8*)mUpdateMask)[index >> 3] & (1 << (index & 0x7))) != 0; + for (uint32 i = 0; i < GetBlockCount(); ++i) + { + ClientUpdateMaskType maskPart = 0; + for (uint32 j = 0; j < CLIENT_UPDATE_MASK_BITS; ++j) + if (_bits[CLIENT_UPDATE_MASK_BITS * i + j]) + maskPart |= 1 << j; + + *data << maskPart; + } } - uint32 GetBlockCount() const { return mBlocks; } - uint32 GetLength() const { return mBlocks << 2; } - uint32 GetCount() const { return mCount; } - uint8* GetMask() { return (uint8*)mUpdateMask; } + uint32 GetBlockCount() const { return _blockCount; } + uint32 GetCount() const { return _fieldCount; } - void SetCount (uint32 valuesCount) + void SetCount(uint32 valuesCount) { - delete [] mUpdateMask; + delete[] _bits; - mCount = valuesCount; - mBlocks = (valuesCount + 31) / 32; + _fieldCount = valuesCount; + _blockCount = (valuesCount + CLIENT_UPDATE_MASK_BITS - 1) / CLIENT_UPDATE_MASK_BITS; - mUpdateMask = new uint32[mBlocks]; - memset(mUpdateMask, 0, mBlocks << 2); + _bits = new uint8[_blockCount * CLIENT_UPDATE_MASK_BITS]; + memset(_bits, 0, sizeof(uint8) * _blockCount * CLIENT_UPDATE_MASK_BITS); } void Clear() { - if (mUpdateMask) - memset(mUpdateMask, 0, mBlocks << 2); + if (_bits) + memset(_bits, 0, sizeof(uint8) * _blockCount * CLIENT_UPDATE_MASK_BITS); } - UpdateMask& operator=(UpdateMask const& mask) + UpdateMask& operator=(UpdateMask const& right) { - if (this == &mask) + if (this == &right) return *this; - SetCount(mask.mCount); - memcpy(mUpdateMask, mask.mUpdateMask, mBlocks << 2); - + SetCount(right.GetCount()); + memcpy(_bits, right._bits, sizeof(uint8) * _blockCount * CLIENT_UPDATE_MASK_BITS); return *this; } - void operator&=(UpdateMask const& mask) + UpdateMask& operator&=(UpdateMask const& right) { - ASSERT(mask.mCount <= mCount); - for (uint32 i = 0; i < mBlocks; ++i) - mUpdateMask[i] &= mask.mUpdateMask[i]; - } + ASSERT(right.GetCount() <= GetCount()); + for (uint32 i = 0; i < _fieldCount; ++i) + _bits[i] &= right._bits[i]; - void operator|=(UpdateMask const& mask) - { - ASSERT(mask.mCount <= mCount); - for (uint32 i = 0; i < mBlocks; ++i) - mUpdateMask[i] |= mask.mUpdateMask[i]; + return *this; } - UpdateMask operator&(UpdateMask const& mask) const + UpdateMask& operator|=(UpdateMask const& right) { - ASSERT(mask.mCount <= mCount); + ASSERT(right.GetCount() <= GetCount()); + for (uint32 i = 0; i < _fieldCount; ++i) + _bits[i] |= right._bits[i]; - UpdateMask newmask; - newmask = *this; - newmask &= mask; - - return newmask; + return *this; } - UpdateMask operator|(UpdateMask const& mask) const + UpdateMask operator|(UpdateMask const& right) { - ASSERT(mask.mCount <= mCount); - - UpdateMask newmask; - newmask = *this; - newmask |= mask; - - return newmask; + UpdateMask ret(*this); + ret |= right; + return ret; } private: - uint32 mCount; - uint32 mBlocks; - uint32 *mUpdateMask; + uint32 _fieldCount; + uint32 _blockCount; + uint8* _bits; }; + #endif diff --git a/src/server/game/Entities/Pet/Pet.cpp b/src/server/game/Entities/Pet/Pet.cpp index d11f6d94734..e10ca7b64c2 100644 --- a/src/server/game/Entities/Pet/Pet.cpp +++ b/src/server/game/Entities/Pet/Pet.cpp @@ -286,7 +286,7 @@ bool Pet::LoadPetFromDB(Player* owner, uint32 petentry, uint32 petnumber, bool c // Send fake summon spell cast - this is needed for correct cooldown application for spells // Example: 46584 - without this cooldown (which should be set always when pet is loaded) isn't set clientside - // TODO: pets should be summoned from real cast instead of just faking it? + /// @todo pets should be summoned from real cast instead of just faking it? if (summon_spell_id) { WorldPacket data(SMSG_SPELL_GO, (8+8+4+4+2)); @@ -822,7 +822,7 @@ bool Pet::CreateBaseAtTamed(CreatureTemplate const* cinfo, Map* map, uint32 phas return true; } -// TODO: Move stat mods code to pet passive auras +/// @todo Move stat mods code to pet passive auras bool Guardian::InitStatsForLevel(uint8 petlevel) { CreatureTemplate const* cinfo = GetCreatureTemplate(); @@ -1003,15 +1003,11 @@ bool Guardian::InitStatsForLevel(uint8 petlevel) if (!pInfo) SetCreateHealth(30*petlevel); - float dmg_multiplier = 0.3f; - if (m_owner->GetAuraEffect(63271, 0)) // Glyph of Feral Spirit - dmg_multiplier = 0.6f; + // wolf attack speed is 1.5s + SetAttackTime(BASE_ATTACK, cinfo->baseattacktime); - SetBonusDamage(int32(m_owner->GetTotalAttackPowerValue(BASE_ATTACK) * dmg_multiplier)); - - // 14AP == 1dps, wolf's strike speed == 2s so dmg = basedmg + AP / 14 * 2 - SetBaseWeaponDamage(BASE_ATTACK, MINDAMAGE, float((petlevel * 4 - petlevel) + (m_owner->GetTotalAttackPowerValue(BASE_ATTACK) * dmg_multiplier * 2 / 14))); - SetBaseWeaponDamage(BASE_ATTACK, MAXDAMAGE, float((petlevel * 4 + petlevel) + (m_owner->GetTotalAttackPowerValue(BASE_ATTACK) * dmg_multiplier * 2 / 14))); + SetBaseWeaponDamage(BASE_ATTACK, MINDAMAGE, float((petlevel * 4 - petlevel))); + SetBaseWeaponDamage(BASE_ATTACK, MAXDAMAGE, float((petlevel * 4 + petlevel))); SetModifierValue(UNIT_MOD_ARMOR, BASE_VALUE, float(m_owner->GetArmor()) * 0.35f); // Bonus Armor (35% of player armor) SetModifierValue(UNIT_MOD_STAT_STAMINA, BASE_VALUE, float(m_owner->GetStat(STAT_STAMINA)) * 0.3f); // Bonus Stamina (30% of player stamina) diff --git a/src/server/game/Entities/Player/Player.cpp b/src/server/game/Entities/Player/Player.cpp index e501471b688..4b3adf6fba7 100644 --- a/src/server/game/Entities/Player/Player.cpp +++ b/src/server/game/Entities/Player/Player.cpp @@ -668,7 +668,7 @@ Player::Player(WorldSession* session): Unit(true) //m_pad = 0; // players always accept - if (AccountMgr::IsPlayerAccount(GetSession()->GetSecurity())) + if (!GetSession()->HasPermission(RBAC_PERM_CAN_FILTER_WHISPERS)) SetAcceptWhispers(true); m_curSelection = 0; @@ -932,7 +932,7 @@ void Player::CleanupsBeforeDelete(bool finalCleanup) bool Player::Create(uint32 guidlow, CharacterCreateInfo* createInfo) { //FIXME: outfitId not used in player creating - // TODO: need more checks against packet modifications + /// @todo need more checks against packet modifications // should check that skin, face, hair* are valid via DBC per race/class // also do it in Player::BuildEnumData, Player::LoadFromDB @@ -1018,7 +1018,7 @@ bool Player::Create(uint32 guidlow, CharacterCreateInfo* createInfo) ? sWorld->getIntConfig(CONFIG_START_PLAYER_LEVEL) : sWorld->getIntConfig(CONFIG_START_HEROIC_PLAYER_LEVEL); - if (!AccountMgr::IsPlayerAccount(GetSession()->GetSecurity())) + if (m_session->HasPermission(RBAC_PERM_USE_START_GM_LEVEL)) { uint32 gm_level = sWorld->getIntConfig(CONFIG_START_GM_LEVEL); if (gm_level > start_level) @@ -1040,7 +1040,7 @@ bool Player::Create(uint32 guidlow, CharacterCreateInfo* createInfo) SetFlag(PLAYER_EXPLORED_ZONES_1+i, 0xFFFFFFFF); } - //Reputations if "StartAllReputation" is enabled, -- TODO: Fix this in a better way + //Reputations if "StartAllReputation" is enabled, -- @todo Fix this in a better way if (sWorld->getBoolConfig(CONFIG_START_ALL_REP)) { GetReputationMgr().SetReputation(sFactionStore.LookupEntry(942), 42999); @@ -1120,20 +1120,7 @@ bool Player::Create(uint32 guidlow, CharacterCreateInfo* createInfo) addActionButton(action_itr->button, action_itr->action, action_itr->type); // original items - CharStartOutfitEntry const* oEntry = NULL; - for (uint32 i = 1; i < sCharStartOutfitStore.GetNumRows(); ++i) - { - if (CharStartOutfitEntry const* entry = sCharStartOutfitStore.LookupEntry(i)) - { - if (entry->RaceClassGender == RaceClassGender) - { - oEntry = entry; - break; - } - } - } - - if (oEntry) + if (CharStartOutfitEntry const* oEntry = GetCharStartOutfitEntry(createInfo->Race, createInfo->Class, createInfo->Gender)) { for (int j = 0; j < MAX_OUTFIT_ITEMS; ++j) { @@ -1355,6 +1342,18 @@ void Player::UpdateMirrorTimers() m_MirrorTimerFlagsLast = ~m_MirrorTimerFlags; } +void Player::StopMirrorTimers() +{ + StopMirrorTimer(FATIGUE_TIMER); + StopMirrorTimer(BREATH_TIMER); + StopMirrorTimer(FIRE_TIMER); +} + +bool Player::IsMirrorTimerActive(MirrorTimerType type) +{ + return m_MirrorTimer[type] == getMaxTimer(type); +} + void Player::HandleDrowning(uint32 time_diff) { if (!m_MirrorTimerFlags) @@ -1377,7 +1376,7 @@ void Player::HandleDrowning(uint32 time_diff) { m_MirrorTimer[BREATH_TIMER]+= 1*IN_MILLISECONDS; // Calculate and deal damage - // TODO: Check this formula + /// @todo Check this formula uint32 damage = GetMaxHealth() / 5 + urand(0, getLevel()-1); EnvironmentalDamage(DAMAGE_DROWNING, damage); } @@ -1446,7 +1445,7 @@ void Player::HandleDrowning(uint32 time_diff) { m_MirrorTimer[FIRE_TIMER]+= 1*IN_MILLISECONDS; // Calculate and deal damage - // TODO: Check this formula + /// @todo Check this formula uint32 damage = urand(600, 700); if (m_MirrorTimerFlags & UNDERWATER_INLAVA) EnvironmentalDamage(DAMAGE_LAVA, damage); @@ -1588,7 +1587,9 @@ void Player::Update(uint32 p_time) GetSession()->m_muteTime = 0; PreparedStatement* stmt = LoginDatabase.GetPreparedStatement(LOGIN_UPD_MUTE_TIME); stmt->setInt64(0, 0); // Set the mute time to 0 - stmt->setUInt32(1, GetSession()->GetAccountId()); + stmt->setString(1, ""); + stmt->setString(2, ""); + stmt->setUInt32(3, GetSession()->GetAccountId()); LoginDatabase.Execute(stmt); } @@ -1620,7 +1621,7 @@ void Player::Update(uint32 p_time) if (Unit* victim = getVictim()) { // default combat reach 10 - // TODO add weapon, skill check + /// @todo add weapon, skill check if (isAttackReady(BASE_ATTACK)) { @@ -1884,6 +1885,15 @@ void Player::setDeathState(DeathState s) SetUInt32Value(PLAYER_SELF_RES_SPELL, 0); } +void Player::InnEnter(time_t time, uint32 mapid, float x, float y, float z) +{ + inn_pos_mapid = mapid; + inn_pos_x = x; + inn_pos_y = y; + inn_pos_z = z; + time_inn_enter = time; +} + bool Player::BuildEnumData(PreparedQueryResult result, WorldPacket* data) { // 0 1 2 3 4 5 6 7 @@ -2080,7 +2090,7 @@ bool Player::TeleportTo(uint32 mapid, float x, float y, float z, float orientati return false; } - if (AccountMgr::IsPlayerAccount(GetSession()->GetSecurity()) && DisableMgr::IsDisabledFor(DISABLE_TYPE_MAP, mapid, this)) + if (!GetSession()->HasPermission(RBAC_PERM_SKIP_CHECK_DISABLE_MAP) && DisableMgr::IsDisabledFor(DISABLE_TYPE_MAP, mapid, this)) { sLog->outError(LOG_FILTER_MAPS, "Player (GUID: %u, name: %s) tried to enter a forbidden map %u", GetGUIDLow(), GetName().c_str(), mapid); SendTransferAborted(mapid, TRANSFER_ABORT_MAP_NOT_ALLOWED); @@ -2323,6 +2333,11 @@ bool Player::TeleportTo(uint32 mapid, float x, float y, float z, float orientati return true; } +bool Player::TeleportTo(WorldLocation const &loc, uint32 options /*= 0*/) +{ + return TeleportTo(loc.GetMapId(), loc.GetPositionX(), loc.GetPositionY(), loc.GetPositionZ(), loc.GetOrientation(), options); +} + bool Player::TeleportToBGEntryPoint() { if (m_bgData.joinPos.m_mapId == MAPID_INVALID) @@ -2388,7 +2403,7 @@ void Player::ProcessDelayedOperations() if (m_DelayedOperations & DELAYED_BG_GROUP_RESTORE) { - if (Group *g = GetGroup()) + if (Group* g = GetGroup()) g->SendUpdateToPlayer(GetGUID()); } @@ -2491,7 +2506,7 @@ void Player::Regenerate(Powers power) uint32 curValue = GetPower(power); - // TODO: possible use of miscvalueb instead of amount + /// @todo possible use of miscvalueb instead of amount if (HasAuraTypeWithValue(SPELL_AURA_PREVENT_REGENERATE_POWER, power)) return; @@ -2747,7 +2762,7 @@ GameObject* Player::GetGameObjectIfCanInteractWith(uint64 guid, GameobjectTypes float maxdist; switch (type) { - // TODO: find out how the client calculates the maximal usage distance to spellless working + /// @todo find out how the client calculates the maximal usage distance to spellless working // gameobjects like guildbanks and mailboxes - 10.0 is a just an abitrary choosen number case GAMEOBJECT_TYPE_GUILD_BANK: case GAMEOBJECT_TYPE_MAILBOX: @@ -2786,7 +2801,7 @@ void Player::SetInWater(bool apply) //move player's guid into HateOfflineList of those mobs //which can't swim and move guid back into ThreatList when //on surface. - //TODO: exist also swimming mobs, and function must be symmetric to enter/leave water + /// @todo exist also swimming mobs, and function must be symmetric to enter/leave water m_isInWater = apply; // remove auras that need water/land @@ -2893,8 +2908,13 @@ bool Player::IsInSameGroupWith(Player const* p) const GetGroup()->SameSubGroup(this, p)); } +bool Player::IsInSameRaidWith(Player const* p) const +{ + return p == this || (GetGroup() != NULL && GetGroup() == p->GetGroup()); +} + ///- If the player is invited, remove him. If the group if then only 1 person, disband the group. -/// \todo Shouldn't we also check if there is no other invitees before disbanding the group? +/// @todo Shouldn't we also check if there is no other invitees before disbanding the group? void Player::UninviteFromGroup() { Group* group = GetGroupInvite(); @@ -3083,7 +3103,7 @@ void Player::GiveLevel(uint8 level) if (MailLevelReward const* mailReward = sObjectMgr->GetMailLevelReward(level, getRaceMask())) { - //- TODO: Poor design of mail system + /// @todo Poor design of mail system SQLTransaction trans = CharacterDatabase.BeginTransaction(); MailDraft(mailReward->mailTemplateId).SendMailTo(trans, this, MailSender(MAIL_CREATURE, mailReward->senderEntry)); CharacterDatabase.CommitTransaction(trans); @@ -3114,7 +3134,7 @@ void Player::InitTalentForLevel() // Remove all talent points if (m_usedTalentCount > 0) // Free any used talents { - resetTalents(true); + resetTalents(true); /// @todo: Has to (collectively) be renamed to ResetTalents SetFreeTalentPoints(0); } } @@ -3131,7 +3151,7 @@ void Player::InitTalentForLevel() // if used more that have then reset if (m_usedTalentCount > talentPointsForLevel) { - if (!AccountMgr::IsAdminAccount(GetSession()->GetSecurity())) + if (!GetSession()->HasPermission(RBAC_PERM_SKIP_CHECK_MORE_TALENTS_THAN_ALLOWED)) resetTalents(true); else SetFreeTalentPoints(0); @@ -3445,6 +3465,19 @@ void Player::AddNewMailDeliverTime(time_t deliver_time) } } +void DeleteSpellFromAllPlayers(uint32 spellId) +{ + CharacterDatabaseStatements stmts[2] = {CHAR_DEL_INVALID_SPELL_SPELLS, CHAR_DEL_INVALID_SPELL_TALENTS}; + for (uint8 i = 0; i < 2; i++) + { + PreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(stmts[i]); + + stmt->setUInt32(0, spellId); + + CharacterDatabase.Execute(stmt); + } +} + bool Player::AddTalent(uint32 spellId, uint8 spec, bool learning) { SpellInfo const* spellInfo = sSpellMgr->GetSpellInfo(spellId); @@ -3455,11 +3488,7 @@ bool Player::AddTalent(uint32 spellId, uint8 spec, bool learning) { sLog->outError(LOG_FILTER_SPELLS_AURAS, "Player::addSpell: Non-existed in SpellStore spell #%u request, deleting for all characters in `character_spell`.", spellId); - PreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_DEL_INVALID_SPELL); - - stmt->setUInt32(0, spellId); - - CharacterDatabase.Execute(stmt); + DeleteSpellFromAllPlayers(spellId); } else sLog->outError(LOG_FILTER_SPELLS_AURAS, "Player::addSpell: Non-existed in SpellStore spell #%u request.", spellId); @@ -3474,11 +3503,7 @@ bool Player::AddTalent(uint32 spellId, uint8 spec, bool learning) { sLog->outError(LOG_FILTER_SPELLS_AURAS, "Player::addTalent: Broken spell #%u learning not allowed, deleting for all characters in `character_talent`.", spellId); - PreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_DEL_INVALID_SPELL); - - stmt->setUInt32(0, spellId); - - CharacterDatabase.Execute(stmt); + DeleteSpellFromAllPlayers(spellId); } else sLog->outError(LOG_FILTER_SPELLS_AURAS, "Player::addTalent: Broken spell #%u learning not allowed.", spellId); @@ -3528,11 +3553,7 @@ bool Player::addSpell(uint32 spellId, bool active, bool learning, bool dependent { sLog->outError(LOG_FILTER_SPELLS_AURAS, "Player::addSpell: Non-existed in SpellStore spell #%u request, deleting for all characters in `character_spell`.", spellId); - PreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_DEL_INVALID_SPELL); - - stmt->setUInt32(0, spellId); - - CharacterDatabase.Execute(stmt); + DeleteSpellFromAllPlayers(spellId); } else sLog->outError(LOG_FILTER_SPELLS_AURAS, "Player::addSpell: Non-existed in SpellStore spell #%u request.", spellId); @@ -3547,11 +3568,7 @@ bool Player::addSpell(uint32 spellId, bool active, bool learning, bool dependent { sLog->outError(LOG_FILTER_SPELLS_AURAS, "Player::addSpell: Broken spell #%u learning not allowed, deleting for all characters in `character_spell`.", spellId); - PreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_DEL_INVALID_SPELL); - - stmt->setUInt32(0, spellId); - - CharacterDatabase.Execute(stmt); + DeleteSpellFromAllPlayers(spellId); } else sLog->outError(LOG_FILTER_SPELLS_AURAS, "Player::addSpell: Broken spell #%u learning not allowed.", spellId); @@ -4899,7 +4916,7 @@ void Player::DeleteFromDB(uint64 playerguid, uint32 accountId, bool updateRealmC stmt->setUInt32(0, guid); trans->Append(stmt); - stmt = CharacterDatabase.GetPreparedStatement(CHAR_DEL_ITEM_INSTANCE); + stmt = CharacterDatabase.GetPreparedStatement(CHAR_DEL_ITEM_INSTANCE_BY_OWNER); stmt->setUInt32(0, guid); trans->Append(stmt); @@ -5807,7 +5824,7 @@ void Player::GetDodgeFromAgility(float &diminishing, float &nondiminishing) if (dodgeRatio == NULL || pclass > MAX_CLASSES) return; - // TODO: research if talents/effects that increase total agility by x% should increase non-diminishing part + /// @todo research if talents/effects that increase total agility by x% should increase non-diminishing part float base_agility = GetCreateStat(STAT_AGILITY) * m_auraModifiersGroup[UNIT_MOD_STAT_START + STAT_AGILITY][BASE_PCT]; float bonus_agility = GetStat(STAT_AGILITY) - base_agility; @@ -7349,6 +7366,16 @@ uint8 Player::GetRankFromDB(uint64 guid) return 0; } +void Player::SetInArenaTeam(uint32 ArenaTeamId, uint8 slot, uint8 type) +{ + SetArenaTeamInfoField(slot, ARENA_TEAM_ID, ArenaTeamId); + SetArenaTeamInfoField(slot, ARENA_TEAM_TYPE, type); +} +void Player::SetArenaTeamInfoField(uint8 slot, ArenaTeamInfoType type, uint32 value) +{ + SetUInt32Value(PLAYER_FIELD_ARENA_TEAM_INFO_1_1 + (slot * ARENA_TEAM_END) + type, value); +} + uint32 Player::GetArenaTeamIdFromDB(uint64 guid, uint8 type) { PreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_SEL_ARENA_TEAM_ID_BY_PLAYER_GUID); @@ -7390,6 +7417,9 @@ uint32 Player::GetZoneIdFromDB(uint64 guid) float posy = fields[2].GetFloat(); float posz = fields[3].GetFloat(); + if (!sMapStore.LookupEntry(map)) + return 0; + zone = sMapMgr->GetZoneId(map, posx, posy, posz); if (zone > 0) @@ -7428,17 +7458,17 @@ void Player::UpdateArea(uint32 newArea) m_areaUpdateId = newArea; AreaTableEntry const* area = GetAreaEntryByAreaID(newArea); - pvpInfo.inFFAPvPArea = area && (area->flags & AREA_FLAG_ARENA); + pvpInfo.IsInFFAPvPArea = area && (area->flags & AREA_FLAG_ARENA); UpdatePvPState(true); UpdateAreaDependentAuras(newArea); // previously this was in UpdateZone (but after UpdateArea) so nothing will break - pvpInfo.inNoPvPArea = false; + pvpInfo.IsInNoPvPArea = false; if (area && area->IsSanctuary()) // in sanctuary { SetByteFlag(UNIT_FIELD_BYTES_2, 1, UNIT_BYTE2_FLAG_SANCTUARY); - pvpInfo.inNoPvPArea = true; + pvpInfo.IsInNoPvPArea = true; CombatStopWithPets(); } else @@ -7459,18 +7489,8 @@ void Player::UpdateZone(uint32 newZone, uint32 newArea) } // group update - if (Group* group = GetGroup()) - { + if (GetGroup()) SetGroupUpdateFlag(GROUP_UPDATE_FULL); - if (GetSession() && group->isLFGGroup() && sLFGMgr->IsTeleported(GetGUID())) - { - for (GroupReference* itr = group->GetFirstMember(); itr != NULL; itr = itr->next()) - { - if (Player* member = itr->getSource()) - GetSession()->SendNameQueryOpcode(member->GetGUID()); - } - } - } m_zoneUpdateId = newZone; m_zoneUpdateTimer = ZONE_UPDATE_INTERVAL; @@ -7503,29 +7523,32 @@ void Player::UpdateZone(uint32 newZone, uint32 newArea) switch (zone->team) { case AREATEAM_ALLY: - pvpInfo.inHostileArea = GetTeam() != ALLIANCE && (sWorld->IsPvPRealm() || zone->flags & AREA_FLAG_CAPITAL); + pvpInfo.IsInHostileArea = GetTeam() != ALLIANCE && (sWorld->IsPvPRealm() || zone->flags & AREA_FLAG_CAPITAL); break; case AREATEAM_HORDE: - pvpInfo.inHostileArea = GetTeam() != HORDE && (sWorld->IsPvPRealm() || zone->flags & AREA_FLAG_CAPITAL); + pvpInfo.IsInHostileArea = GetTeam() != HORDE && (sWorld->IsPvPRealm() || zone->flags & AREA_FLAG_CAPITAL); break; case AREATEAM_NONE: // overwrite for battlegrounds, maybe batter some zone flags but current known not 100% fit to this - pvpInfo.inHostileArea = sWorld->IsPvPRealm() || InBattleground() || zone->flags & AREA_FLAG_WINTERGRASP; + pvpInfo.IsInHostileArea = sWorld->IsPvPRealm() || InBattleground() || zone->flags & AREA_FLAG_WINTERGRASP; break; default: // 6 in fact - pvpInfo.inHostileArea = false; + pvpInfo.IsInHostileArea = false; break; } + // Treat players having a quest flagging for PvP as always in hostile area + pvpInfo.IsHostile = pvpInfo.IsInHostileArea || HasPvPForcingQuest(); + if (zone->flags & AREA_FLAG_CAPITAL) // Is in a capital city { - if (!pvpInfo.inHostileArea || zone->IsSanctuary()) + if (!pvpInfo.IsHostile || zone->IsSanctuary()) { SetFlag(PLAYER_FLAGS, PLAYER_FLAGS_RESTING); SetRestType(REST_TYPE_IN_CITY); InnEnter(time(0), GetMapId(), 0, 0, 0); } - pvpInfo.inNoPvPArea = true; + pvpInfo.IsInNoPvPArea = true; } else { @@ -8746,7 +8769,7 @@ void Player::SendLoot(uint64 guid, LootType loot_type) { uint32 lootid = go->GetGOInfo()->GetLootId(); - //TODO: fix this big hack + /// @todo fix this big hack if ((go->GetEntry() == BG_AV_OBJECTID_MINE_N || go->GetEntry() == BG_AV_OBJECTID_MINE_S)) if (Battleground* bg = GetBattleground()) if (bg->GetTypeID(true) == BATTLEGROUND_AV) @@ -10150,6 +10173,14 @@ Item* Player::GetItemByPos(uint8 bag, uint8 slot) const return NULL; } +//Does additional check for disarmed weapons +Item* Player::GetUseableItemByPos(uint8 bag, uint8 slot) const +{ + if (!CanUseAttackType(GetAttackBySlot(slot))) + return NULL; + return GetItemByPos(bag, slot); +} + Bag* Player::GetBagByPos(uint8 bag) const { if ((bag >= INVENTORY_SLOT_BAG_START && bag < INVENTORY_SLOT_BAG_END) @@ -10514,6 +10545,19 @@ InventoryResult Player::CanTakeMoreSimilarItems(uint32 entry, uint32 count, Item return EQUIP_ERR_OK; } +InventoryResult Player::CanStoreNewItem(uint8 bag, uint8 slot, ItemPosCountVec& dest, uint32 item, uint32 count, uint32* no_space_count /*= NULL*/) const +{ + return CanStoreItem(bag, slot, dest, item, count, NULL, false, no_space_count); +} + +InventoryResult Player::CanStoreItem(uint8 bag, uint8 slot, ItemPosCountVec& dest, Item* pItem, bool swap /*= false*/) const +{ + if (!pItem) + return EQUIP_ERR_ITEM_NOT_FOUND; + uint32 count = pItem->GetCount(); + return CanStoreItem(bag, slot, dest, pItem->GetEntry(), count, pItem, swap, NULL); +} + bool Player::HasItemTotemCategory(uint32 TotemCategory) const { Item* pItem; @@ -10748,7 +10792,7 @@ InventoryResult Player::CanStoreItem(uint8 bag, uint8 slot, ItemPosCountVec &des { if (no_space_count) *no_space_count = count; - return swap ? EQUIP_ERR_ITEMS_CANT_BE_SWAPPED :EQUIP_ERR_ITEM_NOT_FOUND; + return swap ? EQUIP_ERR_ITEMS_CANT_BE_SWAPPED : EQUIP_ERR_ITEM_NOT_FOUND; } if (pItem) @@ -11503,8 +11547,37 @@ InventoryResult Player::CanEquipItem(uint8 slot, uint16 &dest, Item* pItem, bool if (!swap && GetItemByPos(INVENTORY_SLOT_BAG_0, eslot)) return EQUIP_ERR_NO_EQUIPMENT_SLOT_AVAILABLE; - // if swap ignore item (equipped also) - InventoryResult res2 = CanEquipUniqueItem(pItem, swap ? eslot : uint8(NULL_SLOT)); + // if we are swapping 2 equiped items, CanEquipUniqueItem check + // should ignore the item we are trying to swap, and not the + // destination item. CanEquipUniqueItem should ignore destination + // item only when we are swapping weapon from bag + uint8 ignore = uint8(NULL_SLOT); + switch (eslot) + { + case EQUIPMENT_SLOT_MAINHAND: + ignore = EQUIPMENT_SLOT_OFFHAND; + break; + case EQUIPMENT_SLOT_OFFHAND: + ignore = EQUIPMENT_SLOT_MAINHAND; + break; + case EQUIPMENT_SLOT_FINGER1: + ignore = EQUIPMENT_SLOT_FINGER2; + break; + case EQUIPMENT_SLOT_FINGER2: + ignore = EQUIPMENT_SLOT_FINGER1; + break; + case EQUIPMENT_SLOT_TRINKET1: + ignore = EQUIPMENT_SLOT_TRINKET2; + break; + case EQUIPMENT_SLOT_TRINKET2: + ignore = EQUIPMENT_SLOT_TRINKET1; + break; + } + + if (ignore == uint8(NULL_SLOT) || pItem != GetItemByPos(INVENTORY_SLOT_BAG_0, ignore)) + ignore = eslot; + + InventoryResult res2 = CanEquipUniqueItem(pItem, swap ? ignore : uint8(NULL_SLOT)); if (res2 != EQUIP_ERR_OK) return res2; @@ -11829,7 +11902,7 @@ InventoryResult Player::CanUseItem(Item* pItem, bool not_loading) const // Armor that is binded to account can "morph" from plate to mail, etc. if skill is not learned yet. if (pProto->Quality == ITEM_QUALITY_HEIRLOOM && pProto->Class == ITEM_CLASS_ARMOR && !HasSkill(itemSkill)) { - // TODO: when you right-click already equipped item it throws EQUIP_ERR_NO_REQUIRED_PROFICIENCY. + /// @todo when you right-click already equipped item it throws EQUIP_ERR_NO_REQUIRED_PROFICIENCY. // In fact it's a visual bug, everything works properly... I need sniffs of operations with // binded to account items from off server. @@ -11900,22 +11973,12 @@ InventoryResult Player::CanUseItem(ItemTemplate const* proto) const InventoryResult Player::CanRollForItemInLFG(ItemTemplate const* proto, WorldObject const* lootedObject) const { - LfgDungeonSet const& dungeons = sLFGMgr->GetSelectedDungeons(GetGUID()); - if (dungeons.empty()) - return EQUIP_ERR_OK; // not using LFG - if (!GetGroup() || !GetGroup()->isLFGGroup()) return EQUIP_ERR_OK; // not in LFG group // check if looted object is inside the lfg dungeon - bool lootedObjectInDungeon = false; Map const* map = lootedObject->GetMap(); - if (uint32 dungeonId = sLFGMgr->GetDungeon(GetGroup()->GetGUID(), true)) - if (LFGDungeonData const* dungeon = sLFGMgr->GetLFGDungeon(dungeonId)) - if (uint32(dungeon->map) == map->GetId() && dungeon->difficulty == map->GetDifficulty()) - lootedObjectInDungeon = true; - - if (!lootedObjectInDungeon) + if (!sLFGMgr->inLfgDungeonMap(GetGroup()->GetGUID(), map->GetId(), map->GetDifficulty())) return EQUIP_ERR_OK; if (!proto) @@ -12414,6 +12477,11 @@ void Player::VisualizeItem(uint8 slot, Item* pItem) pItem->SetState(ITEM_CHANGED, this); } +Item* Player::BankItem(ItemPosCountVec const& dest, Item* pItem, bool update) +{ + return StoreItem(dest, pItem, update); +} + void Player::RemoveItem(uint8 bag, uint8 slot, bool update) { // note: removeitem does not actually change the item @@ -13564,6 +13632,18 @@ void Player::SendSellError(SellResult msg, Creature* creature, uint64 guid, uint GetSession()->SendPacket(&data); } +bool Player::IsUseEquipedWeapon(bool mainhand) const +{ + // disarm applied only to mainhand weapon + return !IsInFeralForm() && (!mainhand || !HasFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_DISARMED)); +} + +bool Player::IsTwoHandUsed() const +{ + Item* mainItem = GetItemByPos(INVENTORY_SLOT_BAG_0, EQUIPMENT_SLOT_MAINHAND); + return mainItem && mainItem->GetTemplate()->InventoryType == INVTYPE_2HWEAPON && !CanTitanGrip(); +} + void Player::TradeCancel(bool sendback) { if (m_trade) @@ -13612,7 +13692,7 @@ void Player::AddTradeableItem(Item* item) m_itemSoulboundTradeable.push_back(item); } -//TODO: should never allow an item to be added to m_itemSoulboundTradeable twice +/// @todo should never allow an item to be added to m_itemSoulboundTradeable twice void Player::RemoveTradeableItem(Item* item) { m_itemSoulboundTradeable.remove(item); @@ -14278,7 +14358,7 @@ void Player::PrepareGossipMenu(WorldObject* source, uint32 menuId /*= 0*/, bool VendorItemData const* vendorItems = creature->GetVendorItems(); if (!vendorItems || vendorItems->Empty()) { - sLog->outError(LOG_FILTER_SQL, "Creature %u (Entry: %u) have UNIT_NPC_FLAG_VENDOR but have empty trading item list.", creature->GetGUIDLow(), creature->GetEntry()); + sLog->outError(LOG_FILTER_SQL, "Creature (GUID: %u, Entry: %u) have UNIT_NPC_FLAG_VENDOR but have empty trading item list.", creature->GetGUIDLow(), creature->GetEntry()); canTalk = false; } break; @@ -14667,7 +14747,7 @@ void Player::SendPreparedQuest(uint64 guid) else if (icon == 4) PlayerTalkClass->SendQuestGiverRequestItems(quest, guid, CanRewardQuest(quest, false), true); // Send completable on repeatable and autoCompletable quest if player don't have quest - // TODO: verify if check for !quest->IsDaily() is really correct (possibly not) + /// @todo verify if check for !quest->IsDaily() is really correct (possibly not) else { Object* object = ObjectAccessor::GetObjectByTypeMask(*this, guid, TYPEMASK_UNIT | TYPEMASK_GAMEOBJECT | TYPEMASK_ITEM); @@ -15048,6 +15128,12 @@ void Player::AddQuest(Quest const* quest, Object* questGiver) else questStatusData.Timer = 0; + if (quest->HasFlag(QUEST_FLAGS_FLAGS_PVP)) + { + pvpInfo.IsHostile = true; + UpdatePvPState(); + } + SetQuestSlot(log_slot, quest_id, qtime); m_QuestStatusSave[quest_id] = true; @@ -15069,7 +15155,7 @@ void Player::CompleteQuest(uint32 quest_id) if (Quest const* qInfo = sObjectMgr->GetQuestTemplate(quest_id)) { - if (qInfo->HasFlag(QUEST_FLAGS_AUTO_REWARDED)) + if (qInfo->HasFlag(QUEST_FLAGS_TRACKING)) RewardQuest(qInfo, 0, this, false); else SendQuestComplete(quest_id); @@ -15198,7 +15284,7 @@ void Player::RewardQuest(Quest const* quest, uint32 reward, Object* questGiver, // Send reward mail if (uint32 mail_template_id = quest->GetRewMailTemplateId()) { - //- TODO: Poor design of mail system + /// @todo Poor design of mail system SQLTransaction trans = CharacterDatabase.BeginTransaction(); MailDraft(mail_template_id).SendMailTo(trans, this, questGiver, MAIL_CHECK_MASK_HAS_BODY, quest->GetRewMailDelaySecs()); CharacterDatabase.CommitTransaction(trans); @@ -15244,6 +15330,12 @@ void Player::RewardQuest(Quest const* quest, uint32 reward, Object* questGiver, UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_COMPLETE_QUEST_COUNT); UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_COMPLETE_QUEST, quest->GetQuestId()); + if (quest->HasFlag(QUEST_FLAGS_FLAGS_PVP)) + { + pvpInfo.IsHostile = pvpInfo.IsInHostileArea || HasPvPForcingQuest(); + UpdatePvPState(); + } + //lets remove flag for delayed teleports SetCanDelayTeleport(false); } @@ -15884,6 +15976,70 @@ uint16 Player::FindQuestSlot(uint32 quest_id) const return MAX_QUEST_LOG_SIZE; } +uint32 Player::GetQuestSlotQuestId(uint16 slot) const +{ + return GetUInt32Value(PLAYER_QUEST_LOG_1_1 + slot * MAX_QUEST_OFFSET + QUEST_ID_OFFSET); +} + +uint32 Player::GetQuestSlotState(uint16 slot) const +{ + return GetUInt32Value(PLAYER_QUEST_LOG_1_1 + slot * MAX_QUEST_OFFSET + QUEST_STATE_OFFSET); +} + +uint16 Player::GetQuestSlotCounter(uint16 slot, uint8 counter) const +{ + return (uint16)(GetUInt64Value(PLAYER_QUEST_LOG_1_1 + slot * MAX_QUEST_OFFSET + QUEST_COUNTS_OFFSET) >> (counter * 16)); +} + +uint32 Player::GetQuestSlotTime(uint16 slot) const +{ + return GetUInt32Value(PLAYER_QUEST_LOG_1_1 + slot * MAX_QUEST_OFFSET + QUEST_TIME_OFFSET); +} + +void Player::SetQuestSlot(uint16 slot, uint32 quest_id, uint32 timer /*= 0*/) +{ + SetUInt32Value(PLAYER_QUEST_LOG_1_1 + slot * MAX_QUEST_OFFSET + QUEST_ID_OFFSET, quest_id); + SetUInt32Value(PLAYER_QUEST_LOG_1_1 + slot * MAX_QUEST_OFFSET + QUEST_STATE_OFFSET, 0); + SetUInt32Value(PLAYER_QUEST_LOG_1_1 + slot * MAX_QUEST_OFFSET + QUEST_COUNTS_OFFSET, 0); + SetUInt32Value(PLAYER_QUEST_LOG_1_1 + slot * MAX_QUEST_OFFSET + QUEST_COUNTS_OFFSET + 1, 0); + SetUInt32Value(PLAYER_QUEST_LOG_1_1 + slot * MAX_QUEST_OFFSET + QUEST_TIME_OFFSET, timer); +} + +void Player::SetQuestSlotCounter(uint16 slot, uint8 counter, uint16 count) +{ + uint64 val = GetUInt64Value(PLAYER_QUEST_LOG_1_1 + slot * MAX_QUEST_OFFSET + QUEST_COUNTS_OFFSET); + val &= ~((uint64)0xFFFF << (counter * 16)); + val |= ((uint64)count << (counter * 16)); + SetUInt64Value(PLAYER_QUEST_LOG_1_1 + slot * MAX_QUEST_OFFSET + QUEST_COUNTS_OFFSET, val); +} + +void Player::SetQuestSlotState(uint16 slot, uint32 state) +{ + SetFlag(PLAYER_QUEST_LOG_1_1 + slot * MAX_QUEST_OFFSET + QUEST_STATE_OFFSET, state); +} + +void Player::RemoveQuestSlotState(uint16 slot, uint32 state) +{ + RemoveFlag(PLAYER_QUEST_LOG_1_1 + slot * MAX_QUEST_OFFSET + QUEST_STATE_OFFSET, state); +} + +void Player::SetQuestSlotTimer(uint16 slot, uint32 timer) +{ + SetUInt32Value(PLAYER_QUEST_LOG_1_1 + slot * MAX_QUEST_OFFSET + QUEST_TIME_OFFSET, timer); +} + +void Player::SwapQuestSlot(uint16 slot1, uint16 slot2) +{ + for (int i = 0; i < MAX_QUEST_OFFSET; ++i) + { + uint32 temp1 = GetUInt32Value(PLAYER_QUEST_LOG_1_1 + MAX_QUEST_OFFSET * slot1 + i); + uint32 temp2 = GetUInt32Value(PLAYER_QUEST_LOG_1_1 + MAX_QUEST_OFFSET * slot2 + i); + + SetUInt32Value(PLAYER_QUEST_LOG_1_1 + MAX_QUEST_OFFSET * slot1 + i, temp2); + SetUInt32Value(PLAYER_QUEST_LOG_1_1 + MAX_QUEST_OFFSET * slot2 + i, temp1); + } +} + void Player::AreaExploredOrEventHappens(uint32 questId) { if (questId) @@ -16557,6 +16713,25 @@ void Player::SendQuestUpdateAddPlayer(Quest const* quest, uint16 old_count, uint SetQuestSlotCounter(log_slot, QUEST_PVP_KILL_SLOT, GetQuestSlotCounter(log_slot, QUEST_PVP_KILL_SLOT) + add_count); } +bool Player::HasPvPForcingQuest() const +{ + for (uint8 i = 0; i < MAX_QUEST_LOG_SIZE; ++i) + { + uint32 questId = GetQuestSlotQuestId(i); + if (questId == 0) + continue; + + Quest const* quest = sObjectMgr->GetQuestTemplate(questId); + if (!quest) + continue; + + if (quest->HasFlag(QUEST_FLAGS_FLAGS_PVP)) + return true; + } + + return false; +} + /*********************************************************/ /*** LOAD SYSTEM ***/ /*********************************************************/ @@ -16776,7 +16951,8 @@ bool Player::LoadFromDB(uint32 guid, SQLQueryHolder *holder) // check name limitations if (ObjectMgr::CheckPlayerName(m_name) != CHAR_NAME_SUCCESS || - (AccountMgr::IsPlayerAccount(GetSession()->GetSecurity()) && sObjectMgr->IsReservedName(m_name))) + (!GetSession()->HasPermission(RBAC_PERM_SKIP_CHECK_CHARACTER_CREATION_RESERVEDNAME) && + sObjectMgr->IsReservedName(m_name))) { PreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_UPD_ADD_AT_LOGIN_FLAG); stmt->setUInt16(0, uint16(AT_LOGIN_RENAME)); @@ -17311,7 +17487,7 @@ bool Player::LoadFromDB(uint32 guid, SQLQueryHolder *holder) outDebugValues(); // GM state - if (!AccountMgr::IsPlayerAccount(GetSession()->GetSecurity())) + if (GetSession()->HasPermission(RBAC_PERM_RESTORE_SAVED_GM_STATE)) { switch (sWorld->getIntConfig(CONFIG_GM_LOGIN_STATE)) { @@ -17574,7 +17750,7 @@ void Player::_LoadInventory(PreparedQueryResult result, uint32 timeDiff) //NOTE: the "order by `bag`" is important because it makes sure //the bagMap is filled before items in the bags are loaded //NOTE2: the "order by `slot`" is needed because mainhand weapons are (wrongly?) - //expected to be equipped before offhand items (TODO: fixme) + //expected to be equipped before offhand items (@todo fixme) if (result) { @@ -18429,6 +18605,12 @@ void Player::BindToInstance() GetSession()->SendCalendarRaidLockout(mapSave, true); } +void Player::SetPendingBind(uint32 instanceId, uint32 bindTimer) +{ + _pendingBindId = instanceId; + _pendingBindTimer = bindTimer; +} + void Player::SendRaidInfo() { uint32 counter = 0; @@ -18630,6 +18812,11 @@ bool Player::CheckInstanceCount(uint32 instanceId) const return _instanceResetTimes.find(instanceId) != _instanceResetTimes.end(); } +void Player::AddInstanceEnterTime(uint32 instanceId, time_t enterTime) +{ + if (_instanceResetTimes.find(instanceId) == _instanceResetTimes.end()) + _instanceResetTimes.insert(InstanceTimeMap::value_type(instanceId, enterTime + HOUR)); +} bool Player::_LoadHomeBind(PreparedQueryResult result) { @@ -18718,7 +18905,7 @@ void Player::SaveToDB(bool create /*=false*/) if (create) { //! Insert query - //! TO DO: Filter out more redundant fields that can take their default value at player create + /// @todo: Filter out more redundant fields that can take their default value at player create stmt = CharacterDatabase.GetPreparedStatement(CHAR_INS_CHARACTER); stmt->setUInt32(index++, GetGUIDLow()); stmt->setUInt32(index++, GetSession()->GetAccountId()); @@ -18926,7 +19113,7 @@ void Player::SaveToDB(bool create /*=false*/) stmt->setUInt8(index++, GetByteValue(PLAYER_FIELD_BYTES, 2)); stmt->setUInt32(index++, m_grantableLevels); - stmt->setUInt8(index++, IsInWorld() ? 1 : 0); + stmt->setUInt8(index++, IsInWorld() && !GetSession()->PlayerLogout() ? 1 : 0); // Index stmt->setUInt32(index++, GetGUIDLow()); } @@ -19335,7 +19522,7 @@ void Player::_SaveQuestStatus(SQLTransaction& trans) { if (saveItr->second) { - stmt = CharacterDatabase.GetPreparedStatement(CHAR_INS_CHAR_QUESTSTATUS); + stmt = CharacterDatabase.GetPreparedStatement(CHAR_INS_CHAR_QUESTSTATUS_REWARDED); stmt->setUInt32(0, GetGUIDLow()); stmt->setUInt32(1, saveItr->first); trans->Append(stmt); @@ -19630,7 +19817,7 @@ void Player::outDebugValues() const void Player::UpdateSpeakTime() { // ignore chat spam protection for GMs in any mode - if (!AccountMgr::IsPlayerAccount(GetSession()->GetSecurity())) + if (GetSession()->HasPermission(RBAC_PERM_SKIP_CHECK_CHAT_SPAM)) return; time_t current = time (NULL); @@ -19884,11 +20071,19 @@ void Player::UpdateContestedPvP(uint32 diff) m_contestedPvPTimer -= diff; } +void Player::ResetContestedPvP() +{ + ClearUnitState(UNIT_STATE_ATTACK_PLAYER); + RemoveFlag(PLAYER_FLAGS, PLAYER_FLAGS_CONTESTED_PVP); + m_contestedPvPTimer = 0; +} + void Player::UpdatePvPFlag(time_t currTime) { if (!IsPvP()) return; - if (pvpInfo.endTimer == 0 || currTime < (pvpInfo.endTimer + 300) || pvpInfo.inHostileArea) + + if (!pvpInfo.EndTimer || currTime < (pvpInfo.EndTimer + 300) || pvpInfo.IsHostile) return; UpdatePvP(false); @@ -20078,7 +20273,7 @@ void Player::TextEmote(const std::string& text) WorldPacket data(SMSG_MESSAGECHAT, 200); BuildPlayerChat(&data, CHAT_MSG_EMOTE, _text, LANG_UNIVERSAL); - SendMessageToSetInRange(&data, sWorld->getFloatConfig(CONFIG_LISTEN_RANGE_TEXTEMOTE), true, !sWorld->getBoolConfig(CONFIG_ALLOW_TWO_SIDE_INTERACTION_CHAT)); + SendMessageToSetInRange(&data, sWorld->getFloatConfig(CONFIG_LISTEN_RANGE_TEXTEMOTE), true, !GetSession()->HasPermission(RBAC_PERM_TWO_SIDE_INTERACTION_CHAT)); } void Player::Whisper(const std::string& text, uint32 language, uint64 receiver) @@ -20118,6 +20313,30 @@ void Player::Whisper(const std::string& text, uint32 language, uint64 receiver) ChatHandler(GetSession()).PSendSysMessage(LANG_PLAYER_DND, rPlayer->GetName().c_str(), rPlayer->autoReplyMsg.c_str()); } +Item* Player::GetMItem(uint32 id) +{ + ItemMap::const_iterator itr = mMitems.find(id); + return itr != mMitems.end() ? itr->second : NULL; +} + +void Player::AddMItem(Item* it) +{ + ASSERT(it); + //ASSERT deleted, because items can be added before loading + mMitems[it->GetGUIDLow()] = it; +} + +bool Player::RemoveMItem(uint32 id) +{ + return mMitems.erase(id) ? true : false; +} + +void Player::SendOnCancelExpectedVehicleRideAura() +{ + WorldPacket data(SMSG_ON_CANCEL_EXPECTED_RIDE_VEHICLE_AURA, 0); + GetSession()->SendPacket(&data); +} + void Player::PetSpellInitialize() { Pet* pet = GetPet(); @@ -20477,7 +20696,7 @@ void Player::RestoreSpellMods(Spell* spell, uint32 ownerAuraId, Aura* aura) mod->charges = mod->ownerAura->GetCharges(); // Skip this check for now - aura charges may change due to various reason - // TODO: trac these changes correctly + /// @todo trac these changes correctly //ASSERT (mod->ownerAura->GetCharges() <= mod->charges); } } @@ -21332,10 +21551,10 @@ void Player::UpdateHomebindTime(uint32 time) void Player::UpdatePvPState(bool onlyFFA) { - // TODO: should we always synchronize UNIT_FIELD_BYTES_2, 1 of controller and controlled? + /// @todo should we always synchronize UNIT_FIELD_BYTES_2, 1 of controller and controlled? // no, we shouldn't, those are checked for affecting player by client - if (!pvpInfo.inNoPvPArea && !isGameMaster() - && (pvpInfo.inFFAPvPArea || sWorld->IsFFAPvPRealm())) + if (!pvpInfo.IsInNoPvPArea && !isGameMaster() + && (pvpInfo.IsInFFAPvPArea || sWorld->IsFFAPvPRealm())) { if (!HasByteFlag(UNIT_FIELD_BYTES_2, 1, UNIT_BYTE2_FLAG_FFA_PVP)) { @@ -21354,32 +21573,52 @@ void Player::UpdatePvPState(bool onlyFFA) if (onlyFFA) return; - if (pvpInfo.inHostileArea) // in hostile area + if (pvpInfo.IsHostile) // in hostile area { - if (!IsPvP() || pvpInfo.endTimer != 0) + if (!IsPvP() || pvpInfo.EndTimer) UpdatePvP(true, true); } else // in friendly area { - if (IsPvP() && !HasFlag(PLAYER_FLAGS, PLAYER_FLAGS_IN_PVP) && pvpInfo.endTimer == 0) - pvpInfo.endTimer = time(0); // start toggle-off + if (IsPvP() && !HasFlag(PLAYER_FLAGS, PLAYER_FLAGS_IN_PVP) && !pvpInfo.EndTimer) + pvpInfo.EndTimer = time(NULL); // start toggle-off } } +void Player::SetPvP(bool state) +{ + Unit::SetPvP(state); + for (ControlList::iterator itr = m_Controlled.begin(); itr != m_Controlled.end(); ++itr) + (*itr)->SetPvP(state); +} + void Player::UpdatePvP(bool state, bool override) { if (!state || override) { SetPvP(state); - pvpInfo.endTimer = 0; + pvpInfo.EndTimer = 0; } else { - pvpInfo.endTimer = time(NULL); + pvpInfo.EndTimer = time(NULL); SetPvP(state); } } +bool Player::HasSpellCooldown(uint32 spell_id) const +{ + SpellCooldowns::const_iterator itr = m_spellCooldowns.find(spell_id); + return itr != m_spellCooldowns.end() && itr->second.end > time(NULL); +} + +uint32 Player::GetSpellCooldownDelay(uint32 spell_id) const +{ + SpellCooldowns::const_iterator itr = m_spellCooldowns.find(spell_id); + time_t t = time(NULL); + return uint32(itr != m_spellCooldowns.end() && itr->second.end > t ? itr->second.end - t : 0); +} + void Player::AddSpellAndCategoryCooldowns(SpellInfo const* spellInfo, uint32 itemId, Spell* spell, bool infinityCooldown) { // init cooldown values @@ -21440,7 +21679,7 @@ void Player::AddSpellAndCategoryCooldowns(SpellInfo const* spellInfo, uint32 ite if (rec > 0) ApplySpellMod(spellInfo->Id, SPELLMOD_COOLDOWN, rec, spell); - if (catrec > 0) + if (catrec > 0 && !(spellInfo->AttributesEx6 & SPELL_ATTR6_IGNORE_CATEGORY_COOLDOWN_MODS)) ApplySpellMod(spellInfo->Id, SPELLMOD_COOLDOWN, catrec, spell); // replace negative cooldowns by 0 @@ -21520,6 +21759,16 @@ void Player::UpdatePotionCooldown(Spell* spell) m_lastPotionId = 0; } +void Player::setResurrectRequestData(uint64 guid, uint32 mapId, float X, float Y, float Z, uint32 health, uint32 mana) +{ + m_resurrectGUID = guid; + m_resurrectMap = mapId; + m_resurrectX = X; + m_resurrectY = Y; + m_resurrectZ = Z; + m_resurrectHealth = health; + m_resurrectMana = mana; +} //slot to be excluded while counting bool Player::EnchantmentFitsRequirements(uint32 enchantmentcondition, int8 slot) { @@ -21723,6 +21972,17 @@ void Player::SetBattlegroundEntryPoint() m_bgData.joinPos = WorldLocation(m_homebindMapId, m_homebindX, m_homebindY, m_homebindZ, 0.0f); } +void Player::SetBGTeam(uint32 team) +{ + m_bgData.bgTeam = team; + SetByteValue(PLAYER_BYTES_3, 3, uint8(team == ALLIANCE ? 1 : 0)); +} + +uint32 Player::GetBGTeam() const +{ + return m_bgData.bgTeam ? m_bgData.bgTeam : GetTeam(); +} + void Player::LeaveBattleground(bool teleportToEntryPoint) { if (Battleground* bg = GetBattleground()) @@ -21747,12 +22007,21 @@ void Player::LeaveBattleground(bool teleportToEntryPoint) } } -bool Player::CanJoinToBattleground() const +bool Player::CanJoinToBattleground(Battleground const* bg) const { // check Deserter debuff if (HasAura(26013)) return false; + if (bg->isArena() && !GetSession()->HasPermission(RBAC_PERM_JOIN_ARENAS)) + return false; + + if (bg->IsRandom() && !GetSession()->HasPermission(RBAC_PERM_JOIN_RANDOM_BG)) + return false; + + if (!GetSession()->HasPermission(RBAC_PERM_JOIN_NORMAL_BG)) + return false; + return true; } @@ -21796,6 +22065,11 @@ WorldLocation Player::GetStartPosition() const return WorldLocation(mapId, info->positionX, info->positionY, info->positionZ, 0); } +bool Player::HaveAtClient(WorldObject const* u) const +{ + return u == this || m_clientGUIDs.find(u->GetGUID()) != m_clientGUIDs.end(); +} + bool Player::IsNeverVisible() const { if (Unit::IsNeverVisible()) @@ -22036,26 +22310,47 @@ void Player::InitPrimaryProfessions() SetFreePrimaryProfessions(sWorld->getIntConfig(CONFIG_MAX_PRIMARY_TRADE_SKILL)); } -void Player::ModifyMoney(int32 d) +bool Player::ModifyMoney(int32 amount, bool sendError /*= true*/) { - sScriptMgr->OnPlayerMoneyChanged(this, d); + if (!amount) + return true; - if (d < 0) - SetMoney (GetMoney() > uint32(-d) ? GetMoney() + d : 0); + sScriptMgr->OnPlayerMoneyChanged(this, amount); + + if (amount < 0) + SetMoney (GetMoney() > uint32(-amount) ? GetMoney() + amount : 0); else { - uint32 newAmount = 0; - if (GetMoney() < uint32(MAX_MONEY_AMOUNT - d)) - newAmount = GetMoney() + d; + if (GetMoney() < uint32(MAX_MONEY_AMOUNT - amount)) + SetMoney(GetMoney() + amount); else { - // "At Gold Limit" - newAmount = MAX_MONEY_AMOUNT; - if (d) + if (sendError) SendEquipError(EQUIP_ERR_TOO_MUCH_GOLD, NULL, NULL); + return false; } - SetMoney (newAmount); } + + return true; +} + +bool Player::HasEnoughMoney(int32 amount) const +{ + if (amount > 0) + return (GetMoney() >= (uint32) amount); + return true; +} + +void Player::SetMoney(uint32 value) +{ + SetUInt32Value(PLAYER_FIELD_COINAGE, value); + MoneyChanged(value); + UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_HIGHEST_GOLD_VALUE_OWNED); +} + +bool Player::IsQuestRewarded(uint32 quest_id) const +{ + return m_RewardedQuests.find(quest_id) != m_RewardedQuests.end(); } Unit* Player::GetSelectedUnit() const @@ -22692,6 +22987,96 @@ Battleground* Player::GetBattleground() const return sBattlegroundMgr->GetBattleground(GetBattlegroundId(), m_bgData.bgTypeID); } +bool Player::InBattlegroundQueue() const +{ + for (uint8 i = 0; i < PLAYER_MAX_BATTLEGROUND_QUEUES; ++i) + if (m_bgBattlegroundQueueID[i].bgQueueTypeId != BATTLEGROUND_QUEUE_NONE) + return true; + return false; +} + +BattlegroundQueueTypeId Player::GetBattlegroundQueueTypeId(uint32 index) const +{ + return m_bgBattlegroundQueueID[index].bgQueueTypeId; +} + +uint32 Player::GetBattlegroundQueueIndex(BattlegroundQueueTypeId bgQueueTypeId) const +{ + for (uint8 i = 0; i < PLAYER_MAX_BATTLEGROUND_QUEUES; ++i) + if (m_bgBattlegroundQueueID[i].bgQueueTypeId == bgQueueTypeId) + return i; + return PLAYER_MAX_BATTLEGROUND_QUEUES; +} + +bool Player::IsInvitedForBattlegroundQueueType(BattlegroundQueueTypeId bgQueueTypeId) const +{ + for (uint8 i = 0; i < PLAYER_MAX_BATTLEGROUND_QUEUES; ++i) + if (m_bgBattlegroundQueueID[i].bgQueueTypeId == bgQueueTypeId) + return m_bgBattlegroundQueueID[i].invitedToInstance != 0; + return false; +} + +bool Player::InBattlegroundQueueForBattlegroundQueueType(BattlegroundQueueTypeId bgQueueTypeId) const +{ + return GetBattlegroundQueueIndex(bgQueueTypeId) < PLAYER_MAX_BATTLEGROUND_QUEUES; +} + +void Player::SetBattlegroundId(uint32 val, BattlegroundTypeId bgTypeId) +{ + m_bgData.bgInstanceID = val; + m_bgData.bgTypeID = bgTypeId; +} + +uint32 Player::AddBattlegroundQueueId(BattlegroundQueueTypeId val) +{ + for (uint8 i=0; i < PLAYER_MAX_BATTLEGROUND_QUEUES; ++i) + { + if (m_bgBattlegroundQueueID[i].bgQueueTypeId == BATTLEGROUND_QUEUE_NONE || m_bgBattlegroundQueueID[i].bgQueueTypeId == val) + { + m_bgBattlegroundQueueID[i].bgQueueTypeId = val; + m_bgBattlegroundQueueID[i].invitedToInstance = 0; + return i; + } + } + return PLAYER_MAX_BATTLEGROUND_QUEUES; +} + +bool Player::HasFreeBattlegroundQueueId() +{ + for (uint8 i=0; i < PLAYER_MAX_BATTLEGROUND_QUEUES; ++i) + if (m_bgBattlegroundQueueID[i].bgQueueTypeId == BATTLEGROUND_QUEUE_NONE) + return true; + return false; +} + +void Player::RemoveBattlegroundQueueId(BattlegroundQueueTypeId val) +{ + for (uint8 i=0; i < PLAYER_MAX_BATTLEGROUND_QUEUES; ++i) + { + if (m_bgBattlegroundQueueID[i].bgQueueTypeId == val) + { + m_bgBattlegroundQueueID[i].bgQueueTypeId = BATTLEGROUND_QUEUE_NONE; + m_bgBattlegroundQueueID[i].invitedToInstance = 0; + return; + } + } +} + +void Player::SetInviteForBattlegroundQueueType(BattlegroundQueueTypeId bgQueueTypeId, uint32 instanceId) +{ + for (uint8 i=0; i < PLAYER_MAX_BATTLEGROUND_QUEUES; ++i) + if (m_bgBattlegroundQueueID[i].bgQueueTypeId == bgQueueTypeId) + m_bgBattlegroundQueueID[i].invitedToInstance = instanceId; +} + +bool Player::IsInvitedForBattlegroundInstance(uint32 instanceId) const +{ + for (uint8 i=0; i < PLAYER_MAX_BATTLEGROUND_QUEUES; ++i) + if (m_bgBattlegroundQueueID[i].invitedToInstance == instanceId) + return true; + return false; +} + bool Player::InArena() const { Battleground* bg = GetBattleground(); @@ -22840,6 +23225,15 @@ void Player::UpdateForQuestWorldObjects() GetSession()->SendPacket(&packet); } +void Player::SetSummonPoint(uint32 mapid, float x, float y, float z) +{ + m_summon_expire = time(NULL) + MAX_PLAYER_SUMMON_DELAY; + m_summon_mapid = mapid; + m_summon_x = x; + m_summon_y = y; + m_summon_z = z; +} + void Player::SummonIfPossible(bool agree) { if (!agree) @@ -22932,7 +23326,7 @@ OutdoorPvP* Player::GetOutdoorPvP() const return sOutdoorPvPMgr->GetOutdoorPvPToZoneId(GetZoneId()); } -bool Player::HasItemFitToSpellRequirements(SpellInfo const* spellInfo, Item const* ignoreItem) +bool Player::HasItemFitToSpellRequirements(SpellInfo const* spellInfo, Item const* ignoreItem) const { if (spellInfo->EquippedItemClass < 0) return true; @@ -22943,7 +23337,7 @@ bool Player::HasItemFitToSpellRequirements(SpellInfo const* spellInfo, Item cons { case ITEM_CLASS_WEAPON: { - for (uint8 i= EQUIPMENT_SLOT_MAINHAND; i < EQUIPMENT_SLOT_TABARD; ++i) + for (uint8 i = EQUIPMENT_SLOT_MAINHAND; i < EQUIPMENT_SLOT_TABARD; ++i) if (Item* item = GetUseableItemByPos(INVENTORY_SLOT_BAG_0, i)) if (item != ignoreItem && item->IsFitToSpellRequirements(spellInfo)) return true; @@ -22952,7 +23346,7 @@ bool Player::HasItemFitToSpellRequirements(SpellInfo const* spellInfo, Item cons case ITEM_CLASS_ARMOR: { // tabard not have dependent spells - for (uint8 i= EQUIPMENT_SLOT_START; i< EQUIPMENT_SLOT_MAINHAND; ++i) + for (uint8 i = EQUIPMENT_SLOT_START; i < EQUIPMENT_SLOT_MAINHAND; ++i) if (Item* item = GetUseableItemByPos(INVENTORY_SLOT_BAG_0, i)) if (item != ignoreItem && item->IsFitToSpellRequirements(spellInfo)) return true; @@ -23243,6 +23637,13 @@ void Player::SetClientControl(Unit* target, uint8 allowMove) SetMover(this); } +void Player::SetMover(Unit* target) +{ + m_mover->m_movedPlayer = NULL; + m_mover = target; + m_mover->m_movedPlayer = this; +} + void Player::UpdateZoneDependentAuras(uint32 newZone) { // Some spells applied at enter into zone (with subzones), aura removed in UpdateAreaDependentAuras that called always at zone->area update @@ -23272,14 +23673,14 @@ void Player::UpdateAreaDependentAuras(uint32 newArea) if (!HasAura(itr->second->spellId)) CastSpell(this, itr->second->spellId, true); - if (newArea == 4273 && GetVehicle() && GetPositionX() > 400) // Ulduar + if (newArea == 4273 && GetVehicleCreatureBase() && GetPositionX() > 400) // Ulduar { switch (GetVehicleBase()->GetEntry()) { case 33062: case 33109: case 33060: - GetVehicle()->Dismiss(); + GetVehicleCreatureBase()->DespawnOrUnsummon(); break; } } @@ -23411,20 +23812,20 @@ PartyResult Player::CanUninviteFromGroup() const if (!sLFGMgr->GetKicksLeft(gguid)) return ERR_PARTY_LFG_BOOT_LIMIT; - LfgState state = sLFGMgr->GetState(gguid); - if (state == LFG_STATE_BOOT) + lfg::LfgState state = sLFGMgr->GetState(gguid); + if (state == lfg::LFG_STATE_BOOT) return ERR_PARTY_LFG_BOOT_IN_PROGRESS; - if (grp->GetMembersCount() <= LFG_GROUP_KICK_VOTES_NEEDED) + if (grp->GetMembersCount() <= lfg::LFG_GROUP_KICK_VOTES_NEEDED) return ERR_PARTY_LFG_BOOT_TOO_FEW_PLAYERS; - if (state == LFG_STATE_FINISHED_DUNGEON) + if (state == lfg::LFG_STATE_FINISHED_DUNGEON) return ERR_PARTY_LFG_BOOT_DUNGEON_COMPLETE; if (grp->isRollLootActive()) return ERR_PARTY_LFG_BOOT_LOOT_ROLLS; - // TODO: Should also be sent when anyone has recently left combat, with an aprox ~5 seconds timer. + /// @todo Should also be sent when anyone has recently left combat, with an aprox ~5 seconds timer. for (GroupReference const* itr = grp->GetFirstMember(); itr != NULL; itr = itr->next()) if (itr->getSource() && itr->getSource()->isInCombat()) return ERR_PARTY_LFG_BOOT_IN_COMBAT; @@ -23448,21 +23849,17 @@ PartyResult Player::CanUninviteFromGroup() const bool Player::isUsingLfg() { - return sLFGMgr->GetState(GetGUID()) != LFG_STATE_NONE; + return sLFGMgr->GetState(GetGUID()) != lfg::LFG_STATE_NONE; } bool Player::inRandomLfgDungeon() { - if (isUsingLfg()) + if (sLFGMgr->selectedRandomLfgDungeon(GetGUID())) { - const LfgDungeonSet& dungeons = sLFGMgr->GetSelectedDungeons(GetGUID()); - if (!dungeons.empty()) - { - LFGDungeonData const* dungeon = sLFGMgr->GetLFGDungeon(*dungeons.begin()); - if (dungeon && (dungeon->type == LFG_TYPE_RANDOM || dungeon->seasonal)) - return true; - } + Map const* map = GetMap(); + return sLFGMgr->inLfgDungeonMap(GetGUID(), map->GetId(), map->GetDifficulty()); } + return false; } @@ -23747,6 +24144,12 @@ void Player::InitGlyphsForLevel() SetUInt32Value(PLAYER_GLYPHS_ENABLED, value); } +void Player::SetGlyph(uint8 slot, uint32 glyph) +{ + m_Glyphs[m_activeSpec][slot] = glyph; + SetUInt32Value(PLAYER_FIELD_GLYPHS_1 + slot, glyph); +} + bool Player::isTotalImmune() { AuraEffectList const& immune = GetAuraEffectsByType(SPELL_AURA_SCHOOL_IMMUNITY); @@ -23868,6 +24271,22 @@ uint32 Player::GetRuneBaseCooldown(uint8 index) return cooldown; } +void Player::SetRuneCooldown(uint8 index, uint32 cooldown) +{ + m_runes->runes[index].Cooldown = cooldown; + m_runes->SetRuneState(index, (cooldown == 0) ? true : false); +} + +void Player::SetRuneConvertAura(uint8 index, AuraEffect const* aura) +{ + m_runes->runes[index].ConvertAura = aura; +} + +void Player::AddRuneByAuraEffect(uint8 index, RuneType newType, AuraEffect const* aura) +{ + SetRuneConvertAura(index, aura); ConvertRune(index, newType); +} + void Player::RemoveRunesByAuraEffect(AuraEffect const* aura) { for (uint8 i = 0; i < MAX_RUNES; ++i) @@ -24292,6 +24711,12 @@ InventoryResult Player::CanEquipUniqueItem(ItemTemplate const* itemProto, uint8 return EQUIP_ERR_OK; } +void Player::SetFallInformation(uint32 time, float z) +{ + m_lastFallTime = time; + m_lastFallZ = z; +} + void Player::HandleFall(MovementInfo const& movementInfo) { // calculate total z distance of the fall @@ -24678,6 +25103,11 @@ void Player::ResummonPetTemporaryUnSummonedIfAny() m_temporaryUnsummonedPetNumber = 0; } +bool Player::IsPetNeedBeTemporaryUnsummoned() const +{ + return !IsInWorld() || !isAlive() || IsMounted() /*+in flight*/; +} + bool Player::canSeeSpellClickOn(Creature const* c) const { if (!c->HasFlag(UNIT_NPC_FLAGS, UNIT_NPC_FLAG_SPELLCLICK)) @@ -25259,6 +25689,7 @@ void Player::ActivateSpec(uint8 spec) ClearComboPointHolders(); ClearAllReactives(); UnsummonAllTotems(); + ExitVehicle(); RemoveAllControlled(); /*RemoveAllAurasOnDeath(); if (GetPet()) @@ -25479,11 +25910,11 @@ bool Player::AddItem(uint32 itemId, uint32 count) ItemPosCountVec dest; InventoryResult msg = CanStoreNewItem(NULL_BAG, NULL_SLOT, dest, itemId, count, &noSpaceForCount); if (msg != EQUIP_ERR_OK) - count = noSpaceForCount; + count -= noSpaceForCount; if (count == 0 || dest.empty()) { - // -- TODO: Send to mailbox if no space + /// @todo Send to mailbox if no space ChatHandler(GetSession()).PSendSysMessage("You don't have any space in your bags."); return false; } @@ -25735,6 +26166,39 @@ void Player::SendMovementSetFeatherFall(bool apply) SendDirectMessage(&data); } +float Player::GetCollisionHeight(bool mounted) const +{ + if (mounted) + { + CreatureDisplayInfoEntry const* mountDisplayInfo = sCreatureDisplayInfoStore.LookupEntry(GetUInt32Value(UNIT_FIELD_MOUNTDISPLAYID)); + if (!mountDisplayInfo) + return GetCollisionHeight(false); + + CreatureModelDataEntry const* mountModelData = sCreatureModelDataStore.LookupEntry(mountDisplayInfo->ModelId); + if (!mountModelData) + return GetCollisionHeight(false); + + CreatureDisplayInfoEntry const* displayInfo = sCreatureDisplayInfoStore.LookupEntry(GetNativeDisplayId()); + ASSERT(displayInfo); + CreatureModelDataEntry const* modelData = sCreatureModelDataStore.LookupEntry(displayInfo->ModelId); + ASSERT(modelData); + + float scaleMod = GetFloatValue(OBJECT_FIELD_SCALE_X); // 99% sure about this + + return scaleMod * mountModelData->MountHeight + modelData->CollisionHeight * 0.5f; + } + else + { + //! Dismounting case - use basic default model data + CreatureDisplayInfoEntry const* displayInfo = sCreatureDisplayInfoStore.LookupEntry(GetNativeDisplayId()); + ASSERT(displayInfo); + CreatureModelDataEntry const* modelData = sCreatureModelDataStore.LookupEntry(displayInfo->ModelId); + ASSERT(modelData); + + return modelData->CollisionHeight; + } +} + Guild* Player::GetGuild() { uint32 guildId = GetGuildId(); diff --git a/src/server/game/Entities/Player/Player.h b/src/server/game/Entities/Player/Player.h index fa82ac6f8c6..6458de47378 100644 --- a/src/server/game/Entities/Player/Player.h +++ b/src/server/game/Entities/Player/Player.h @@ -269,12 +269,13 @@ struct PlayerInfo struct PvPInfo { - PvPInfo() : inHostileArea(false), inNoPvPArea(false), inFFAPvPArea(false), endTimer(0) {} + PvPInfo() : IsHostile(false), IsInHostileArea(false), IsInNoPvPArea(false), IsInFFAPvPArea(false), EndTimer(0) {} - bool inHostileArea; - bool inNoPvPArea; - bool inFFAPvPArea; - time_t endTimer; + bool IsHostile; + bool IsInHostileArea; ///> Marks if player is in an area which forces PvP flag + bool IsInNoPvPArea; ///> Marks if player is in a sanctuary or friendly capital city + bool IsInFFAPvPArea; ///> Marks if player is in an FFAPvP area (such as Gurubashi Arena) + time_t EndTimer; ///> Time when player unflags himself for PvP (flag removed after 5 minutes) }; struct DuelInfo @@ -392,7 +393,7 @@ enum PlayerFlags PLAYER_FLAGS_UNK16 = 0x00010000, // pre-3.0.3 PLAYER_FLAGS_SANCTUARY flag for player entered sanctuary PLAYER_FLAGS_TAXI_BENCHMARK = 0x00020000, // taxi benchmark mode (on/off) (2.0.1) PLAYER_FLAGS_PVP_TIMER = 0x00040000, // 3.0.2, pvp timer active (after you disable pvp manually) - PLAYER_FLAGS_UNK19 = 0x00080000, + PLAYER_FLAGS_UBER = 0x00080000, PLAYER_FLAGS_UNK20 = 0x00100000, PLAYER_FLAGS_UNK21 = 0x00200000, PLAYER_FLAGS_COMMENTATOR2 = 0x00400000, @@ -1071,20 +1072,10 @@ class Player : public Unit, public GridObject<Player> void RemoveFromWorld(); bool TeleportTo(uint32 mapid, float x, float y, float z, float orientation, uint32 options = 0); - bool TeleportTo(WorldLocation const &loc, uint32 options = 0) - { - return TeleportTo(loc.GetMapId(), loc.GetPositionX(), loc.GetPositionY(), loc.GetPositionZ(), loc.GetOrientation(), options); - } + bool TeleportTo(WorldLocation const &loc, uint32 options = 0); bool TeleportToBGEntryPoint(); - void SetSummonPoint(uint32 mapid, float x, float y, float z) - { - m_summon_expire = time(NULL) + MAX_PLAYER_SUMMON_DELAY; - m_summon_mapid = mapid; - m_summon_x = x; - m_summon_y = y; - m_summon_z = z; - } + void SetSummonPoint(uint32 mapid, float x, float y, float z); void SummonIfPossible(bool agree); bool Create(uint32 guidlow, CharacterCreateInfo* createInfo); @@ -1159,14 +1150,7 @@ class Player : public Unit, public GridObject<Player> void setDeathState(DeathState s); // overwrite Unit::setDeathState - void InnEnter (time_t time, uint32 mapid, float x, float y, float z) - { - inn_pos_mapid = mapid; - inn_pos_x = x; - inn_pos_y = y; - inn_pos_z = z; - time_inn_enter = time; - } + void InnEnter(time_t time, uint32 mapid, float x, float y, float z); float GetRestBonus() const { return m_rest_bonus; } void SetRestBonus(float rest_bonus_new); @@ -1187,10 +1171,15 @@ class Player : public Unit, public GridObject<Player> void RemovePet(Pet* pet, PetSaveMode mode, bool returnreagent = false); uint32 GetPhaseMaskForSpawn() const; // used for proper set phase for DB at GM-mode creature/GO spawn + /// Handles said message in regular chat based on declared language and in config pre-defined Range. void Say(std::string const& text, const uint32 language); + /// Handles yelled message in regular chat based on declared language and in config pre-defined Range. void Yell(std::string const& text, const uint32 language); + /// Outputs an universal text which is supposed to be an action. void TextEmote(std::string const& text); + /// Handles whispers from Addons and players based on sender, receiver's guid and language. void Whisper(std::string const& text, const uint32 language, uint64 receiver); + /// Constructs the player Chat data for the specific functions to use void BuildPlayerChat(WorldPacket* data, uint8 msgtype, std::string const& text, uint32 language) const; /*********************************************************/ @@ -1206,13 +1195,8 @@ class Player : public Unit, public GridObject<Player> Item* GetItemByEntry(uint32 entry) const; Item* GetItemByPos(uint16 pos) const; Item* GetItemByPos(uint8 bag, uint8 slot) const; + Item* GetUseableItemByPos(uint8 bag, uint8 slot) const; Bag* GetBagByPos(uint8 slot) const; - inline Item* GetUseableItemByPos(uint8 bag, uint8 slot) const //Does additional check for disarmed weapons - { - if (!CanUseAttackType(GetAttackBySlot(slot))) - return NULL; - return GetItemByPos(bag, slot); - } Item* GetWeaponForAttack(WeaponAttackType attackType, bool useable = false) const; Item* GetShield(bool useable = false) const; static uint8 GetAttackBySlot(uint8 slot); // MAX_ATTACK if not weapon slot @@ -1229,23 +1213,14 @@ class Player : public Unit, public GridObject<Player> uint8 GetBankBagSlotCount() const { return GetByteValue(PLAYER_BYTES_2, 2); } void SetBankBagSlotCount(uint8 count) { SetByteValue(PLAYER_BYTES_2, 2, count); } bool HasItemCount(uint32 item, uint32 count = 1, bool inBankAlso = false) const; - bool HasItemFitToSpellRequirements(SpellInfo const* spellInfo, Item const* ignoreItem = NULL); + bool HasItemFitToSpellRequirements(SpellInfo const* spellInfo, Item const* ignoreItem = NULL) const; bool CanNoReagentCast(SpellInfo const* spellInfo) const; bool HasItemOrGemWithIdEquipped(uint32 item, uint32 count, uint8 except_slot = NULL_SLOT) const; bool HasItemOrGemWithLimitCategoryEquipped(uint32 limitCategory, uint32 count, uint8 except_slot = NULL_SLOT) const; InventoryResult CanTakeMoreSimilarItems(Item* pItem) const { return CanTakeMoreSimilarItems(pItem->GetEntry(), pItem->GetCount(), pItem); } InventoryResult CanTakeMoreSimilarItems(uint32 entry, uint32 count) const { return CanTakeMoreSimilarItems(entry, count, NULL); } - InventoryResult CanStoreNewItem(uint8 bag, uint8 slot, ItemPosCountVec& dest, uint32 item, uint32 count, uint32* no_space_count = NULL) const - { - return CanStoreItem(bag, slot, dest, item, count, NULL, false, no_space_count); - } - InventoryResult CanStoreItem(uint8 bag, uint8 slot, ItemPosCountVec& dest, Item* pItem, bool swap = false) const - { - if (!pItem) - return EQUIP_ERR_ITEM_NOT_FOUND; - uint32 count = pItem->GetCount(); - return CanStoreItem(bag, slot, dest, pItem->GetEntry(), count, pItem, swap, NULL); - } + InventoryResult CanStoreNewItem(uint8 bag, uint8 slot, ItemPosCountVec& dest, uint32 item, uint32 count, uint32* no_space_count = NULL) const; + InventoryResult CanStoreItem(uint8 bag, uint8 slot, ItemPosCountVec& dest, Item* pItem, bool swap = false) const; InventoryResult CanStoreItems(Item** pItem, int count) const; InventoryResult CanEquipNewItem(uint8 slot, uint16& dest, uint32 item, bool swap) const; InventoryResult CanEquipItem(uint8 slot, uint16& dest, Item* pItem, bool swap, bool not_loading = true) const; @@ -1285,11 +1260,7 @@ class Player : public Unit, public GridObject<Player> void QuickEquipItem(uint16 pos, Item* pItem); void VisualizeItem(uint8 slot, Item* pItem); void SetVisibleItemSlot(uint8 slot, Item* pItem); - Item* BankItem(ItemPosCountVec const& dest, Item* pItem, bool update) - { - return StoreItem(dest, pItem, update); - } - Item* BankItem(uint16 pos, Item* pItem, bool update); + Item* BankItem(ItemPosCountVec const& dest, Item* pItem, bool update); void RemoveItem(uint8 bag, uint8 slot, bool update); void MoveItemFromInventory(uint8 bag, uint8 slot, bool update); // in trade, auction, guild bank, mail.... @@ -1314,16 +1285,8 @@ class Player : public Unit, public GridObject<Player> void AddArmorProficiency(uint32 newflag) { m_ArmorProficiency |= newflag; } uint32 GetWeaponProficiency() const { return m_WeaponProficiency; } uint32 GetArmorProficiency() const { return m_ArmorProficiency; } - bool IsUseEquipedWeapon(bool mainhand) const - { - // disarm applied only to mainhand weapon - return !IsInFeralForm() && (!mainhand || !HasFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_DISARMED)); - } - bool IsTwoHandUsed() const - { - Item* mainItem = GetItemByPos(INVENTORY_SLOT_BAG_0, EQUIPMENT_SLOT_MAINHAND); - return mainItem && mainItem->GetTemplate()->InventoryType == INVTYPE_2HWEAPON && !CanTitanGrip(); - } + bool IsUseEquipedWeapon(bool mainhand) const; + bool IsTwoHandUsed() const; void SendNewItem(Item* item, uint32 count, bool received, bool created, bool broadcast = false); bool BuyItemFromVendorSlot(uint64 vendorguid, uint32 vendorslot, uint32 item, uint8 count, uint8 bag, uint8 slot); bool _StoreOrEquipNewItem(uint32 vendorslot, uint32 item, uint8 count, uint8 bag, uint8 slot, int32 price, ItemTemplate const* pProto, Creature* pVendor, VendorItem const* crItem, bool bStore); @@ -1427,39 +1390,17 @@ class Player : public Unit, public GridObject<Player> void ResetSeasonalQuestStatus(uint16 event_id); uint16 FindQuestSlot(uint32 quest_id) const; - uint32 GetQuestSlotQuestId(uint16 slot) const { return GetUInt32Value(PLAYER_QUEST_LOG_1_1 + slot * MAX_QUEST_OFFSET + QUEST_ID_OFFSET); } - uint32 GetQuestSlotState(uint16 slot) const { return GetUInt32Value(PLAYER_QUEST_LOG_1_1 + slot * MAX_QUEST_OFFSET + QUEST_STATE_OFFSET); } - uint16 GetQuestSlotCounter(uint16 slot, uint8 counter) const { return (uint16)(GetUInt64Value(PLAYER_QUEST_LOG_1_1 + slot * MAX_QUEST_OFFSET + QUEST_COUNTS_OFFSET) >> (counter * 16)); } - uint32 GetQuestSlotTime(uint16 slot) const { return GetUInt32Value(PLAYER_QUEST_LOG_1_1 + slot * MAX_QUEST_OFFSET + QUEST_TIME_OFFSET); } - void SetQuestSlot(uint16 slot, uint32 quest_id, uint32 timer = 0) - { - SetUInt32Value(PLAYER_QUEST_LOG_1_1 + slot * MAX_QUEST_OFFSET + QUEST_ID_OFFSET, quest_id); - SetUInt32Value(PLAYER_QUEST_LOG_1_1 + slot * MAX_QUEST_OFFSET + QUEST_STATE_OFFSET, 0); - SetUInt32Value(PLAYER_QUEST_LOG_1_1 + slot * MAX_QUEST_OFFSET + QUEST_COUNTS_OFFSET, 0); - SetUInt32Value(PLAYER_QUEST_LOG_1_1 + slot * MAX_QUEST_OFFSET + QUEST_COUNTS_OFFSET + 1, 0); - SetUInt32Value(PLAYER_QUEST_LOG_1_1 + slot * MAX_QUEST_OFFSET + QUEST_TIME_OFFSET, timer); - } - void SetQuestSlotCounter(uint16 slot, uint8 counter, uint16 count) - { - uint64 val = GetUInt64Value(PLAYER_QUEST_LOG_1_1 + slot * MAX_QUEST_OFFSET + QUEST_COUNTS_OFFSET); - val &= ~((uint64)0xFFFF << (counter * 16)); - val |= ((uint64)count << (counter * 16)); - SetUInt64Value(PLAYER_QUEST_LOG_1_1 + slot * MAX_QUEST_OFFSET + QUEST_COUNTS_OFFSET, val); - } - void SetQuestSlotState(uint16 slot, uint32 state) { SetFlag(PLAYER_QUEST_LOG_1_1 + slot * MAX_QUEST_OFFSET + QUEST_STATE_OFFSET, state); } - void RemoveQuestSlotState(uint16 slot, uint32 state) { RemoveFlag(PLAYER_QUEST_LOG_1_1 + slot * MAX_QUEST_OFFSET + QUEST_STATE_OFFSET, state); } - void SetQuestSlotTimer(uint16 slot, uint32 timer) { SetUInt32Value(PLAYER_QUEST_LOG_1_1 + slot * MAX_QUEST_OFFSET + QUEST_TIME_OFFSET, timer); } - void SwapQuestSlot(uint16 slot1, uint16 slot2) - { - for (int i = 0; i < MAX_QUEST_OFFSET; ++i) - { - uint32 temp1 = GetUInt32Value(PLAYER_QUEST_LOG_1_1 + MAX_QUEST_OFFSET * slot1 + i); - uint32 temp2 = GetUInt32Value(PLAYER_QUEST_LOG_1_1 + MAX_QUEST_OFFSET * slot2 + i); + uint32 GetQuestSlotQuestId(uint16 slot) const; + uint32 GetQuestSlotState(uint16 slot) const; + uint16 GetQuestSlotCounter(uint16 slot, uint8 counter) const; + uint32 GetQuestSlotTime(uint16 slot) const; + void SetQuestSlot(uint16 slot, uint32 quest_id, uint32 timer = 0); + void SetQuestSlotCounter(uint16 slot, uint8 counter, uint16 count); + void SetQuestSlotState(uint16 slot, uint32 state); + void RemoveQuestSlotState(uint16 slot, uint32 state); + void SetQuestSlotTimer(uint16 slot, uint32 timer); + void SwapQuestSlot(uint16 slot1, uint16 slot2); - SetUInt32Value(PLAYER_QUEST_LOG_1_1 + MAX_QUEST_OFFSET * slot1 + i, temp2); - SetUInt32Value(PLAYER_QUEST_LOG_1_1 + MAX_QUEST_OFFSET * slot2 + i, temp1); - } - } uint16 GetReqKillOrCastCurrentCount(uint32 quest_id, int32 entry); void AreaExploredOrEventHappens(uint32 questId); void GroupEventHappens(uint32 questId, WorldObject const* pEventObject); @@ -1499,6 +1440,8 @@ class Player : public Unit, public GridObject<Player> void AddTimedQuest(uint32 quest_id) { m_timedquests.insert(quest_id); } void RemoveTimedQuest(uint32 quest_id) { m_timedquests.erase(quest_id); } + bool HasPvPForcingQuest() const; + /*********************************************************/ /*** LOAD SYSTEM ***/ /*********************************************************/ @@ -1546,30 +1489,16 @@ class Player : public Unit, public GridObject<Player> void setWeaponChangeTimer(uint32 time) {m_weaponChangeTimer = time;} uint32 GetMoney() const { return GetUInt32Value(PLAYER_FIELD_COINAGE); } - void ModifyMoney(int32 d); + bool ModifyMoney(int32 amount, bool sendError = true); bool HasEnoughMoney(uint32 amount) const { return (GetMoney() >= amount); } - bool HasEnoughMoney(int32 amount) const - { - if (amount > 0) - return (GetMoney() >= (uint32) amount); - return true; - } - - void SetMoney(uint32 value) - { - SetUInt32Value(PLAYER_FIELD_COINAGE, value); - MoneyChanged(value); - UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_HIGHEST_GOLD_VALUE_OWNED); - } + bool HasEnoughMoney(int32 amount) const; + void SetMoney(uint32 value); RewardedQuestSet const& getRewardedQuests() const { return m_RewardedQuests; } QuestStatusMap& getQuestStatusMap() { return m_QuestStatus; } size_t GetRewardedQuestCount() const { return m_RewardedQuests.size(); } - bool IsQuestRewarded(uint32 quest_id) const - { - return m_RewardedQuests.find(quest_id) != m_RewardedQuests.end(); - } + bool IsQuestRewarded(uint32 quest_id) const; uint64 GetSelection() const { return m_curSelection; } Unit* GetSelectedUnit() const; @@ -1610,24 +1539,11 @@ class Player : public Unit, public GridObject<Player> ItemMap mMitems; //template defined in objectmgr.cpp - Item* GetMItem(uint32 id) - { - ItemMap::const_iterator itr = mMitems.find(id); - return itr != mMitems.end() ? itr->second : NULL; - } - - void AddMItem(Item* it) - { - ASSERT(it); - //ASSERT deleted, because items can be added before loading - mMitems[it->GetGUIDLow()] = it; - } - - bool RemoveMItem(uint32 id) - { - return mMitems.erase(id) ? true : false; - } + Item* GetMItem(uint32 id); + void AddMItem(Item* it); + bool RemoveMItem(uint32 id); + void SendOnCancelExpectedVehicleRideAura(); void PetSpellInitialize(); void CharmSpellInitialize(); void PossessSpellInitialize(); @@ -1681,11 +1597,7 @@ class Player : public Unit, public GridObject<Player> void InitGlyphsForLevel(); void SetGlyphSlot(uint8 slot, uint32 slottype) { SetUInt32Value(PLAYER_FIELD_GLYPH_SLOTS_1 + slot, slottype); } uint32 GetGlyphSlot(uint8 slot) { return GetUInt32Value(PLAYER_FIELD_GLYPH_SLOTS_1 + slot); } - void SetGlyph(uint8 slot, uint32 glyph) - { - m_Glyphs[m_activeSpec][slot] = glyph; - SetUInt32Value(PLAYER_FIELD_GLYPHS_1 + slot, glyph); - } + void SetGlyph(uint8 slot, uint32 glyph); uint32 GetGlyph(uint8 slot) { return m_Glyphs[m_activeSpec][slot]; } uint32 GetFreePrimaryProfessionPoints() const { return GetUInt32Value(PLAYER_CHARACTER_POINTS2); } @@ -1708,17 +1620,8 @@ class Player : public Unit, public GridObject<Player> static uint32 const infinityCooldownDelay = MONTH; // used for set "infinity cooldowns" for spells and check static uint32 const infinityCooldownDelayCheck = MONTH/2; - bool HasSpellCooldown(uint32 spell_id) const - { - SpellCooldowns::const_iterator itr = m_spellCooldowns.find(spell_id); - return itr != m_spellCooldowns.end() && itr->second.end > time(NULL); - } - uint32 GetSpellCooldownDelay(uint32 spell_id) const - { - SpellCooldowns::const_iterator itr = m_spellCooldowns.find(spell_id); - time_t t = time(NULL); - return uint32(itr != m_spellCooldowns.end() && itr->second.end > t ? itr->second.end - t : 0); - } + bool HasSpellCooldown(uint32 spell_id) const; + uint32 GetSpellCooldownDelay(uint32 spell_id) const; void AddSpellAndCategoryCooldowns(SpellInfo const* spellInfo, uint32 itemId, Spell* spell = NULL, bool infinityCooldown = false); void AddSpellCooldown(uint32 spell_id, uint32 itemid, time_t end_time); void SendCooldownEvent(SpellInfo const* spellInfo, uint32 itemId = 0, Spell* spell = NULL, bool setCooldown = true); @@ -1737,29 +1640,14 @@ class Player : public Unit, public GridObject<Player> void SetLastPotionId(uint32 item_id) { m_lastPotionId = item_id; } void UpdatePotionCooldown(Spell* spell = NULL); - void setResurrectRequestData(uint64 guid, uint32 mapId, float X, float Y, float Z, uint32 health, uint32 mana) - { - m_resurrectGUID = guid; - m_resurrectMap = mapId; - m_resurrectX = X; - m_resurrectY = Y; - m_resurrectZ = Z; - m_resurrectHealth = health; - m_resurrectMana = mana; - } + void setResurrectRequestData(uint64 guid, uint32 mapId, float X, float Y, float Z, uint32 health, uint32 mana); void clearResurrectRequestData() { setResurrectRequestData(0, 0, 0.0f, 0.0f, 0.0f, 0, 0); } bool isRessurectRequestedBy(uint64 guid) const { return m_resurrectGUID == guid; } bool isRessurectRequested() const { return m_resurrectGUID != 0; } void ResurectUsingRequestData(); - uint8 getCinematic() - { - return m_cinematic; - } - void setCinematic(uint8 cine) - { - m_cinematic = cine; - } + uint8 getCinematic() { return m_cinematic; } + void setCinematic(uint8 cine) { m_cinematic = cine; } ActionButton* addActionButton(uint8 button, uint32 action, uint8 type); void removeActionButton(uint8 button); @@ -1770,12 +1658,7 @@ class Player : public Unit, public GridObject<Player> PvPInfo pvpInfo; void UpdatePvPState(bool onlyFFA = false); - void SetPvP(bool state) - { - Unit::SetPvP(state); - for (ControlList::iterator itr = m_Controlled.begin(); itr != m_Controlled.end(); ++itr) - (*itr)->SetPvP(state); - } + void SetPvP(bool state); void UpdatePvP(bool state, bool override=false); void UpdateZone(uint32 newZone, uint32 newArea); void UpdateArea(uint32 newArea); @@ -1787,12 +1670,7 @@ class Player : public Unit, public GridObject<Player> void UpdatePvPFlag(time_t currTime); void UpdateContestedPvP(uint32 currTime); void SetContestedPvPTimer(uint32 newTime) {m_contestedPvPTimer = newTime;} - void ResetContestedPvP() - { - ClearUnitState(UNIT_STATE_ATTACK_PLAYER); - RemoveFlag(PLAYER_FLAGS, PLAYER_FLAGS_CONTESTED_PVP); - m_contestedPvPTimer = 0; - } + void ResetContestedPvP(); /** todo: -maybe move UpdateDuelFlag+DuelComplete to independent DuelHandler.. **/ DuelInfo* duel; @@ -1803,7 +1681,7 @@ class Player : public Unit, public GridObject<Player> bool IsGroupVisibleFor(Player const* p) const; bool IsInSameGroupWith(Player const* p) const; - bool IsInSameRaidWith(Player const* p) const { return p == this || (GetGroup() != NULL && GetGroup() == p->GetGroup()); } + bool IsInSameRaidWith(Player const* p) const; void UninviteFromGroup(); static void RemoveFromGroup(Group* group, uint64 guid, RemoveMethod method = GROUP_REMOVEMETHOD_DEFAULT, uint64 kicker = 0, const char* reason = NULL); void RemoveFromGroup(RemoveMethod method = GROUP_REMOVEMETHOD_DEFAULT) { RemoveFromGroup(GetGroup(), GetGUID(), method); } @@ -1821,15 +1699,8 @@ class Player : public Unit, public GridObject<Player> static void RemovePetitionsAndSigns(uint64 guid, uint32 type); // Arena Team - void SetInArenaTeam(uint32 ArenaTeamId, uint8 slot, uint8 type) - { - SetArenaTeamInfoField(slot, ARENA_TEAM_ID, ArenaTeamId); - SetArenaTeamInfoField(slot, ARENA_TEAM_TYPE, type); - } - void SetArenaTeamInfoField(uint8 slot, ArenaTeamInfoType type, uint32 value) - { - SetUInt32Value(PLAYER_FIELD_ARENA_TEAM_INFO_1_1 + (slot * ARENA_TEAM_END) + type, value); - } + void SetInArenaTeam(uint32 ArenaTeamId, uint8 slot, uint8 type); + void SetArenaTeamInfoField(uint8 slot, ArenaTeamInfoType type, uint32 value); static uint32 GetArenaTeamIdFromDB(uint64 guid, uint8 slot); static void LeaveAllArenaTeams(uint64 guid); uint32 GetArenaTeamId(uint8 slot) const { return GetUInt32Value(PLAYER_FIELD_ARENA_TEAM_INFO_1_1 + (slot * ARENA_TEAM_END) + ARENA_TEAM_ID); } @@ -1888,7 +1759,7 @@ class Player : public Unit, public GridObject<Player> float OCTRegenMPPerSpirit(); float GetRatingMultiplier(CombatRating cr) const; float GetRatingBonusValue(CombatRating cr) const; - uint32 GetBaseSpellPowerBonus() { return m_baseSpellPower; } + uint32 GetBaseSpellPowerBonus() const { return m_baseSpellPower; } int32 GetSpellPenetrationItemMod() const { return m_spellPenetrationItemMod; } float GetExpertiseDodgeOrParryReduction(WeaponAttackType attType) const; @@ -1966,13 +1837,8 @@ class Player : public Unit, public GridObject<Player> uint32 DurabilityRepair(uint16 pos, bool cost, float discountMod, bool guildBank); void UpdateMirrorTimers(); - void StopMirrorTimers() - { - StopMirrorTimer(FATIGUE_TIMER); - StopMirrorTimer(BREATH_TIMER); - StopMirrorTimer(FIRE_TIMER); - } - bool IsMirrorTimerActive(MirrorTimerType type) { return m_MirrorTimer[type] == getMaxTimer(type); } + void StopMirrorTimers(); + bool IsMirrorTimerActive(MirrorTimerType type); void SetMovement(PlayerMovementType pType); @@ -2138,92 +2004,27 @@ class Player : public Unit, public GridObject<Player> BattlegroundTypeId GetBattlegroundTypeId() const { return m_bgData.bgTypeID; } Battleground* GetBattleground() const; - bool InBattlegroundQueue() const - { - for (uint8 i = 0; i < PLAYER_MAX_BATTLEGROUND_QUEUES; ++i) - if (m_bgBattlegroundQueueID[i].bgQueueTypeId != BATTLEGROUND_QUEUE_NONE) - return true; - return false; - } + bool InBattlegroundQueue() const; - BattlegroundQueueTypeId GetBattlegroundQueueTypeId(uint32 index) const { return m_bgBattlegroundQueueID[index].bgQueueTypeId; } - uint32 GetBattlegroundQueueIndex(BattlegroundQueueTypeId bgQueueTypeId) const - { - for (uint8 i = 0; i < PLAYER_MAX_BATTLEGROUND_QUEUES; ++i) - if (m_bgBattlegroundQueueID[i].bgQueueTypeId == bgQueueTypeId) - return i; - return PLAYER_MAX_BATTLEGROUND_QUEUES; - } - bool IsInvitedForBattlegroundQueueType(BattlegroundQueueTypeId bgQueueTypeId) const - { - for (uint8 i = 0; i < PLAYER_MAX_BATTLEGROUND_QUEUES; ++i) - if (m_bgBattlegroundQueueID[i].bgQueueTypeId == bgQueueTypeId) - return m_bgBattlegroundQueueID[i].invitedToInstance != 0; - return false; - } - bool InBattlegroundQueueForBattlegroundQueueType(BattlegroundQueueTypeId bgQueueTypeId) const - { - return GetBattlegroundQueueIndex(bgQueueTypeId) < PLAYER_MAX_BATTLEGROUND_QUEUES; - } + BattlegroundQueueTypeId GetBattlegroundQueueTypeId(uint32 index) const; + uint32 GetBattlegroundQueueIndex(BattlegroundQueueTypeId bgQueueTypeId) const; + bool IsInvitedForBattlegroundQueueType(BattlegroundQueueTypeId bgQueueTypeId) const; + bool InBattlegroundQueueForBattlegroundQueueType(BattlegroundQueueTypeId bgQueueTypeId) const; - void SetBattlegroundId(uint32 val, BattlegroundTypeId bgTypeId) - { - m_bgData.bgInstanceID = val; - m_bgData.bgTypeID = bgTypeId; - } - uint32 AddBattlegroundQueueId(BattlegroundQueueTypeId val) - { - for (uint8 i=0; i < PLAYER_MAX_BATTLEGROUND_QUEUES; ++i) - { - if (m_bgBattlegroundQueueID[i].bgQueueTypeId == BATTLEGROUND_QUEUE_NONE || m_bgBattlegroundQueueID[i].bgQueueTypeId == val) - { - m_bgBattlegroundQueueID[i].bgQueueTypeId = val; - m_bgBattlegroundQueueID[i].invitedToInstance = 0; - return i; - } - } - return PLAYER_MAX_BATTLEGROUND_QUEUES; - } - bool HasFreeBattlegroundQueueId() - { - for (uint8 i=0; i < PLAYER_MAX_BATTLEGROUND_QUEUES; ++i) - if (m_bgBattlegroundQueueID[i].bgQueueTypeId == BATTLEGROUND_QUEUE_NONE) - return true; - return false; - } - void RemoveBattlegroundQueueId(BattlegroundQueueTypeId val) - { - for (uint8 i=0; i < PLAYER_MAX_BATTLEGROUND_QUEUES; ++i) - { - if (m_bgBattlegroundQueueID[i].bgQueueTypeId == val) - { - m_bgBattlegroundQueueID[i].bgQueueTypeId = BATTLEGROUND_QUEUE_NONE; - m_bgBattlegroundQueueID[i].invitedToInstance = 0; - return; - } - } - } - void SetInviteForBattlegroundQueueType(BattlegroundQueueTypeId bgQueueTypeId, uint32 instanceId) - { - for (uint8 i=0; i < PLAYER_MAX_BATTLEGROUND_QUEUES; ++i) - if (m_bgBattlegroundQueueID[i].bgQueueTypeId == bgQueueTypeId) - m_bgBattlegroundQueueID[i].invitedToInstance = instanceId; - } - bool IsInvitedForBattlegroundInstance(uint32 instanceId) const - { - for (uint8 i=0; i < PLAYER_MAX_BATTLEGROUND_QUEUES; ++i) - if (m_bgBattlegroundQueueID[i].invitedToInstance == instanceId) - return true; - return false; - } + void SetBattlegroundId(uint32 val, BattlegroundTypeId bgTypeId); + uint32 AddBattlegroundQueueId(BattlegroundQueueTypeId val); + bool HasFreeBattlegroundQueueId(); + void RemoveBattlegroundQueueId(BattlegroundQueueTypeId val); + void SetInviteForBattlegroundQueueType(BattlegroundQueueTypeId bgQueueTypeId, uint32 instanceId); + bool IsInvitedForBattlegroundInstance(uint32 instanceId) const; WorldLocation const& GetBattlegroundEntryPoint() const { return m_bgData.joinPos; } void SetBattlegroundEntryPoint(); - void SetBGTeam(uint32 team) { m_bgData.bgTeam = team; } - uint32 GetBGTeam() const { return m_bgData.bgTeam ? m_bgData.bgTeam : GetTeam(); } + void SetBGTeam(uint32 team); + uint32 GetBGTeam() const; void LeaveBattleground(bool teleportToEntryPoint = true); - bool CanJoinToBattleground() const; + bool CanJoinToBattleground(Battleground const* bg) const; bool CanReportAfkDueToLimit(); void ReportedAfkBy(Player* reporter); void ClearAfkReports() { m_bgData.bgAfkReporter.clear(); } @@ -2275,23 +2076,14 @@ class Player : public Unit, public GridObject<Player> void UpdateFallInformationIfNeed(MovementInfo const& minfo, uint16 opcode); Unit* m_mover; WorldObject* m_seer; - void SetFallInformation(uint32 time, float z) - { - m_lastFallTime = time; - m_lastFallZ = z; - } + void SetFallInformation(uint32 time, float z); void HandleFall(MovementInfo const& movementInfo); bool IsKnowHowFlyIn(uint32 mapid, uint32 zone) const; void SetClientControl(Unit* target, uint8 allowMove); - void SetMover(Unit* target) - { - m_mover->m_movedPlayer = NULL; - m_mover = target; - m_mover->m_movedPlayer = this; - } + void SetMover(Unit* target); void SetSeer(WorldObject* target) { m_seer = target; } void SetViewpoint(WorldObject* target, bool apply); @@ -2325,7 +2117,7 @@ class Player : public Unit, public GridObject<Player> typedef std::set<uint64> ClientGUIDs; ClientGUIDs m_clientGUIDs; - bool HaveAtClient(WorldObject const* u) const { return u == this || m_clientGUIDs.find(u->GetGUID()) != m_clientGUIDs.end(); } + bool HaveAtClient(WorldObject const* u) const; bool IsNeverVisible() const; @@ -2357,7 +2149,7 @@ class Player : public Unit, public GridObject<Player> void SetTemporaryUnsummonedPetNumber(uint32 petnumber) { m_temporaryUnsummonedPetNumber = petnumber; } void UnsummonPetTemporaryIfAny(); void ResummonPetTemporaryUnSummonedIfAny(); - bool IsPetNeedBeTemporaryUnsummoned() const { return !IsInWorld() || !isAlive() || IsMounted() /*+in flight*/; } + bool IsPetNeedBeTemporaryUnsummoned() const; void SendCinematicStart(uint32 CinematicSequenceId); void SendMovieStart(uint32 MovieId); @@ -2381,7 +2173,7 @@ class Player : public Unit, public GridObject<Player> void UnbindInstance(BoundInstancesMap::iterator &itr, Difficulty difficulty, bool unload = false); InstancePlayerBind* BindToInstance(InstanceSave* save, bool permanent, bool load = false); void BindToInstance(); - void SetPendingBind(uint32 instanceId, uint32 bindTimer) { _pendingBindId = instanceId; _pendingBindTimer = bindTimer; } + void SetPendingBind(uint32 instanceId, uint32 bindTimer); bool HasPendingBind() const { return _pendingBindId > 0; } void SendRaidInfo(); void SendSavedInstances(); @@ -2389,12 +2181,7 @@ class Player : public Unit, public GridObject<Player> bool Satisfy(AccessRequirement const* ar, uint32 target_map, bool report = false); bool CheckInstanceLoginValid(); bool CheckInstanceCount(uint32 instanceId) const; - - void AddInstanceEnterTime(uint32 instanceId, time_t enterTime) - { - if (_instanceResetTimes.find(instanceId) == _instanceResetTimes.end()) - _instanceResetTimes.insert(InstanceTimeMap::value_type(instanceId, enterTime + HOUR)); - } + void AddInstanceEnterTime(uint32 instanceId, time_t enterTime); // last used pet number (for BG's) uint32 GetLastPetNumber() const { return m_lastpetnumber; } @@ -2448,9 +2235,9 @@ class Player : public Unit, public GridObject<Player> void SetLastUsedRune(RuneType type) { m_runes->lastUsedRune = type; } void SetBaseRune(uint8 index, RuneType baseRune) { m_runes->runes[index].BaseRune = baseRune; } void SetCurrentRune(uint8 index, RuneType currentRune) { m_runes->runes[index].CurrentRune = currentRune; } - void SetRuneCooldown(uint8 index, uint32 cooldown) { m_runes->runes[index].Cooldown = cooldown; m_runes->SetRuneState(index, (cooldown == 0) ? true : false); } - void SetRuneConvertAura(uint8 index, AuraEffect const* aura) { m_runes->runes[index].ConvertAura = aura; } - void AddRuneByAuraEffect(uint8 index, RuneType newType, AuraEffect const* aura) { SetRuneConvertAura(index, aura); ConvertRune(index, newType); } + void SetRuneCooldown(uint8 index, uint32 cooldown); + void SetRuneConvertAura(uint8 index, AuraEffect const* aura); + void AddRuneByAuraEffect(uint8 index, RuneType newType, AuraEffect const* aura); void RemoveRunesByAuraEffect(AuraEffect const* aura); void RestoreBaseRune(uint8 index); void ConvertRune(uint8 index, RuneType newType); @@ -2485,6 +2272,7 @@ class Player : public Unit, public GridObject<Player> void ClearWhisperWhiteList() { WhisperList.clear(); } void AddWhisperWhiteList(uint64 guid) { WhisperList.push_back(guid); } bool IsInWhisperWhiteList(uint64 guid); + void RemoveFromWhisperWhiteList(uint64 guid) { WhisperList.remove(guid); } /*! These methods send different packets to the client in apply and unapply case. These methods are only sent to the current unit. @@ -2498,38 +2286,7 @@ class Player : public Unit, public GridObject<Player> bool CanFly() const { return m_movementInfo.HasMovementFlag(MOVEMENTFLAG_CAN_FLY); } //! Return collision height sent to client - float GetCollisionHeight(bool mounted) - { - if (mounted) - { - CreatureDisplayInfoEntry const* mountDisplayInfo = sCreatureDisplayInfoStore.LookupEntry(GetUInt32Value(UNIT_FIELD_MOUNTDISPLAYID)); - if (!mountDisplayInfo) - return GetCollisionHeight(false); - - CreatureModelDataEntry const* mountModelData = sCreatureModelDataStore.LookupEntry(mountDisplayInfo->ModelId); - if (!mountModelData) - return GetCollisionHeight(false); - - CreatureDisplayInfoEntry const* displayInfo = sCreatureDisplayInfoStore.LookupEntry(GetNativeDisplayId()); - ASSERT(displayInfo); - CreatureModelDataEntry const* modelData = sCreatureModelDataStore.LookupEntry(displayInfo->ModelId); - ASSERT(modelData); - - float scaleMod = GetFloatValue(OBJECT_FIELD_SCALE_X); // 99% sure about this - - return scaleMod * mountModelData->MountHeight + modelData->CollisionHeight * 0.5f; - } - else - { - //! Dismounting case - use basic default model data - CreatureDisplayInfoEntry const* displayInfo = sCreatureDisplayInfoStore.LookupEntry(GetNativeDisplayId()); - ASSERT(displayInfo); - CreatureModelDataEntry const* modelData = sCreatureModelDataStore.LookupEntry(displayInfo->ModelId); - ASSERT(modelData); - - return modelData->CollisionHeight; - } - } + float GetCollisionHeight(bool mounted) const; protected: // Gamemaster whisper whitelist @@ -2563,7 +2320,7 @@ class Player : public Unit, public GridObject<Player> //We allow only one timed quest active at the same time. Below can then be simple value instead of set. typedef std::set<uint32> QuestSet; typedef std::set<uint32> SeasonalQuestSet; - typedef UNORDERED_MAP<uint32,SeasonalQuestSet> SeasonalEventQuestMap; + typedef UNORDERED_MAP<uint32, SeasonalQuestSet> SeasonalEventQuestMap; QuestSet m_timedquests; QuestSet m_weeklyquests; QuestSet m_monthlyquests; @@ -2699,8 +2456,6 @@ class Player : public Unit, public GridObject<Player> int32 m_spellPenetrationItemMod; SpellModList m_spellMods[MAX_SPELLMOD]; - //uint32 m_pad; -// Spell* m_spellModTakingSpell; // Spell for which charges are dropped in spell::finish EnchantDurationList m_enchantDuration; ItemDurationList m_itemDuration; @@ -2815,12 +2570,7 @@ class Player : public Unit, public GridObject<Player> void SetCanDelayTeleport(bool setting) { m_bCanDelayTeleport = setting; } bool IsHasDelayedTeleport() const { return m_bHasDelayedTeleport; } void SetDelayedTeleportFlag(bool setting) { m_bHasDelayedTeleport = setting; } - - void ScheduleDelayedOperation(uint32 operation) - { - if (operation < DELAYED_END) - m_DelayedOperations |= operation; - } + void ScheduleDelayedOperation(uint32 operation) { if (operation < DELAYED_END) m_DelayedOperations |= operation; } MapReference m_mapRef; diff --git a/src/server/game/Entities/Player/SocialMgr.cpp b/src/server/game/Entities/Player/SocialMgr.cpp index e5bbac59e00..6f5927492bf 100644 --- a/src/server/game/Entities/Player/SocialMgr.cpp +++ b/src/server/game/Entities/Player/SocialMgr.cpp @@ -216,34 +216,37 @@ void SocialMgr::GetFriendInfo(Player* player, uint32 friendGUID, FriendInfo &fri friendInfo.Level = 0; friendInfo.Class = 0; - Player* pFriend = ObjectAccessor::FindPlayer(friendGUID); - if (!pFriend) + Player* target = ObjectAccessor::FindPlayer(friendGUID); + if (!target) return; - uint32 team = player->GetTeam(); - AccountTypes security = player->GetSession()->GetSecurity(); - bool allowTwoSideWhoList = sWorld->getBoolConfig(CONFIG_ALLOW_TWO_SIDE_WHO_LIST); - AccountTypes gmLevelInWhoList = AccountTypes(sWorld->getIntConfig(CONFIG_GM_LEVEL_IN_WHO_LIST)); - PlayerSocialMap::iterator itr = player->GetSocial()->m_playerSocialMap.find(friendGUID); if (itr != player->GetSocial()->m_playerSocialMap.end()) friendInfo.Note = itr->second.Note; // PLAYER see his team only and PLAYER can't see MODERATOR, GAME MASTER, ADMINISTRATOR characters // MODERATOR, GAME MASTER, ADMINISTRATOR can see all - if (pFriend && - (!AccountMgr::IsPlayerAccount(security) || - ((pFriend->GetTeam() == team || allowTwoSideWhoList) && (pFriend->GetSession()->GetSecurity() <= gmLevelInWhoList))) && - pFriend->IsVisibleGloballyFor(player)) + + if (!player->GetSession()->HasPermission(RBAC_PERM_WHO_SEE_ALL_SEC_LEVELS) && + target->GetSession()->GetSecurity() > AccountTypes(sWorld->getIntConfig(CONFIG_GM_LEVEL_IN_WHO_LIST))) + return; + + // player can see member of other team only if CONFIG_ALLOW_TWO_SIDE_WHO_LIST + if (target->GetTeam() != player->GetTeam() && !player->GetSession()->HasPermission(RBAC_PERM_TWO_SIDE_WHO_LIST)) + return; + + if (target->IsVisibleGloballyFor(player)) { - friendInfo.Status = FRIEND_STATUS_ONLINE; - if (pFriend->isAFK()) - friendInfo.Status = FRIEND_STATUS_AFK; - if (pFriend->isDND()) + if (target->isDND()) friendInfo.Status = FRIEND_STATUS_DND; - friendInfo.Area = pFriend->GetZoneId(); - friendInfo.Level = pFriend->getLevel(); - friendInfo.Class = pFriend->getClass(); + else if (target->isAFK()) + friendInfo.Status = FRIEND_STATUS_AFK; + else + friendInfo.Status = FRIEND_STATUS_ONLINE; + + friendInfo.Area = target->GetZoneId(); + friendInfo.Level = target->getLevel(); + friendInfo.Class = target->getClass(); } } @@ -295,28 +298,25 @@ void SocialMgr::BroadcastToFriendListers(Player* player, WorldPacket* packet) if (!player) return; - uint32 team = player->GetTeam(); - AccountTypes security = player->GetSession()->GetSecurity(); - uint32 guid = player->GetGUIDLow(); - AccountTypes gmLevelInWhoList = AccountTypes(sWorld->getIntConfig(CONFIG_GM_LEVEL_IN_WHO_LIST)); - bool allowTwoSideWhoList = sWorld->getBoolConfig(CONFIG_ALLOW_TWO_SIDE_WHO_LIST); - + AccountTypes gmSecLevel = AccountTypes(sWorld->getIntConfig(CONFIG_GM_LEVEL_IN_WHO_LIST)); for (SocialMap::const_iterator itr = m_socialMap.begin(); itr != m_socialMap.end(); ++itr) { - PlayerSocialMap::const_iterator itr2 = itr->second.m_playerSocialMap.find(guid); + PlayerSocialMap::const_iterator itr2 = itr->second.m_playerSocialMap.find(player->GetGUID()); if (itr2 != itr->second.m_playerSocialMap.end() && (itr2->second.Flags & SOCIAL_FLAG_FRIEND)) { - Player* pFriend = ObjectAccessor::FindPlayer(MAKE_NEW_GUID(itr->first, 0, HIGHGUID_PLAYER)); - - // PLAYER see his team only and PLAYER can't see MODERATOR, GAME MASTER, ADMINISTRATOR characters - // MODERATOR, GAME MASTER, ADMINISTRATOR can see all - if (pFriend && pFriend->IsInWorld() && - (!AccountMgr::IsPlayerAccount(pFriend->GetSession()->GetSecurity()) || - ((pFriend->GetTeam() == team || allowTwoSideWhoList) && security <= gmLevelInWhoList)) && - player->IsVisibleGloballyFor(pFriend)) - { - pFriend->GetSession()->SendPacket(packet); - } + Player* target = ObjectAccessor::FindPlayer(MAKE_NEW_GUID(itr->first, 0, HIGHGUID_PLAYER)); + if (!target || !target->IsInWorld()) + continue; + + WorldSession* session = target->GetSession(); + if (!session->HasPermission(RBAC_PERM_WHO_SEE_ALL_SEC_LEVELS) && player->GetSession()->GetSecurity() > gmSecLevel) + continue; + + if (target->GetTeam() != player->GetTeam() && !session->HasPermission(RBAC_PERM_TWO_SIDE_WHO_LIST)) + continue; + + if (player->IsVisibleGloballyFor(target)) + session->SendPacket(packet); } } } diff --git a/src/server/game/Entities/Totem/Totem.cpp b/src/server/game/Entities/Totem/Totem.cpp index c2dec9086ca..07aa28ecee0 100644 --- a/src/server/game/Entities/Totem/Totem.cpp +++ b/src/server/game/Entities/Totem/Totem.cpp @@ -148,7 +148,7 @@ void Totem::UnSummon(uint32 msTime) bool Totem::IsImmunedToSpellEffect(SpellInfo const* spellInfo, uint32 index) const { - // TODO: possibly all negative auras immune? + /// @todo possibly all negative auras immune? if (GetEntry() == 5925) return false; diff --git a/src/server/game/Entities/Transport/Transport.cpp b/src/server/game/Entities/Transport/Transport.cpp index 3ce23a973ca..c2c01331b4d 100644 --- a/src/server/game/Entities/Transport/Transport.cpp +++ b/src/server/game/Entities/Transport/Transport.cpp @@ -680,9 +680,9 @@ uint32 Transport::AddNPCPassenger(uint32 tguid, uint32 entry, float x, float y, void Transport::UpdatePosition(MovementInfo* mi) { - float transport_o = mi->pos.m_orientation - mi->t_pos.m_orientation; - float transport_x = mi->pos.m_positionX - (mi->t_pos.m_positionX * std::cos(transport_o) - mi->t_pos.m_positionY* std::sin(transport_o)); - float transport_y = mi->pos.m_positionY - (mi->t_pos.m_positionY * std::cos(transport_o) + mi->t_pos.m_positionX* std::sin(transport_o)); + float transport_o = mi->pos.GetOrientation() - mi->t_pos.GetOrientation(); + float transport_x = mi->pos.m_positionX - (mi->t_pos.m_positionX * std::cos(transport_o) - mi->t_pos.m_positionY * std::sin(transport_o)); + float transport_y = mi->pos.m_positionY - (mi->t_pos.m_positionY * std::cos(transport_o) + mi->t_pos.m_positionX * std::sin(transport_o)); float transport_z = mi->pos.m_positionZ - mi->t_pos.m_positionZ; Relocate(transport_x, transport_y, transport_z, transport_o); diff --git a/src/server/game/Entities/Unit/StatSystem.cpp b/src/server/game/Entities/Unit/StatSystem.cpp index 5cf0550905c..c30fa910f76 100644 --- a/src/server/game/Entities/Unit/StatSystem.cpp +++ b/src/server/game/Entities/Unit/StatSystem.cpp @@ -229,8 +229,7 @@ void Player::UpdateArmor() float Player::GetHealthBonusFromStamina() { float stamina = GetStat(STAT_STAMINA); - - float baseStam = stamina < 20 ? stamina : 20; + float baseStam = std::min(20.0f, stamina); float moreStam = stamina - baseStam; return baseStam + (moreStam*10.0f); @@ -240,10 +239,10 @@ float Player::GetManaBonusFromIntellect() { float intellect = GetStat(STAT_INTELLECT); - float baseInt = intellect < 20 ? intellect : 20; + float baseInt = std::min(20.0f, intellect); float moreInt = intellect - baseInt; - return baseInt + (moreInt*15.0f); + return baseInt + (moreInt * 15.0f); } void Player::UpdateMaxHealth() @@ -442,6 +441,7 @@ void Player::UpdateAttackPowerAndDamage(bool ranged) SetFloatValue(index_mult, attPowerMultiplier); //UNIT_FIELD_(RANGED)_ATTACK_POWER_MULTIPLIER field Pet* pet = GetPet(); //update pet's AP + Guardian* guardian = GetGuardianPet(); //automatically update weapon damage after attack power modification if (ranged) { @@ -457,8 +457,11 @@ void Player::UpdateAttackPowerAndDamage(bool ranged) if (getClass() == CLASS_SHAMAN || getClass() == CLASS_PALADIN) // mental quickness UpdateSpellDamageAndHealingBonus(); - if (pet && pet->IsPetGhoul()) // At ranged attack change for hunter pet + if (pet && pet->IsPetGhoul()) // At melee attack power change for DK pet pet->UpdateAttackPowerAndDamage(); + + if (guardian && guardian->IsSpiritWolf()) // At melee attack power change for Shaman feral spirit + guardian->UpdateAttackPowerAndDamage(); } } @@ -1306,6 +1309,14 @@ void Guardian::UpdateAttackPowerAndDamage(bool ranged) bonusAP = owner->GetTotalAttackPowerValue(BASE_ATTACK) * 0.22f; SetBonusDamage(int32(owner->GetTotalAttackPowerValue(BASE_ATTACK) * 0.1287f)); } + else if (IsSpiritWolf()) //wolf benefit from shaman's attack power + { + float dmg_multiplier = 0.31f; + if (m_owner->GetAuraEffect(63271, 0)) // Glyph of Feral Spirit + dmg_multiplier = 0.61f; + bonusAP = owner->GetTotalAttackPowerValue(BASE_ATTACK) * dmg_multiplier; + SetBonusDamage(int32(owner->GetTotalAttackPowerValue(BASE_ATTACK) * dmg_multiplier)); + } //demons benefit from warlocks shadow or fire damage else if (isPet()) { diff --git a/src/server/game/Entities/Unit/Unit.cpp b/src/server/game/Entities/Unit/Unit.cpp index d383b92c5ff..87ca7a6c62b 100644 --- a/src/server/game/Entities/Unit/Unit.cpp +++ b/src/server/game/Entities/Unit/Unit.cpp @@ -256,8 +256,8 @@ Unit::Unit(bool isWorldObject): WorldObject(isWorldObject) m_speed_rate[i] = 1.0f; m_charmInfo = NULL; - m_reducedThreatPercent = 0; - m_misdirectionTargetGUID = 0; + + _redirectThreadInfo = RedirectThreatInfo(); // remove aurastates allowing special moves for (uint8 i = 0; i < MAX_REACTIVE; ++i) @@ -385,10 +385,10 @@ bool Unit::haveOffhandWeapon() const return m_canDualWield; } -void Unit::MonsterMoveWithSpeed(float x, float y, float z, float speed) +void Unit::MonsterMoveWithSpeed(float x, float y, float z, float speed, bool generatePath, bool forceDestination) { - Movement::MoveSplineInit init(*this); - init.MoveTo(x,y,z); + Movement::MoveSplineInit init(this); + init.MoveTo(x, y, z, generatePath, forceDestination); init.SetVelocity(speed); init.Launch(); } @@ -442,6 +442,12 @@ void Unit::resetAttackTimer(WeaponAttackType type) m_attackTimer[type] = uint32(GetAttackTime(type) * m_modAttackSpeedPct[type]); } +float Unit::GetMeleeReach() const +{ + float reach = m_floatValues[UNIT_FIELD_COMBATREACH]; + return reach > MIN_MELEE_REACH ? reach : MIN_MELEE_REACH; +} + bool Unit::IsWithinCombatRange(const Unit* obj, float dist2compare) const { if (!obj || !IsInMap(obj) || !InSamePhase(obj)) @@ -487,6 +493,26 @@ void Unit::GetRandomContactPoint(const Unit* obj, float &x, float &y, float &z, , GetAngle(obj) + (attacker_number ? (static_cast<float>(M_PI/2) - static_cast<float>(M_PI) * (float)rand_norm()) * float(attacker_number) / combat_reach * 0.3f : 0)); } +AuraApplication * Unit::GetVisibleAura(uint8 slot) const +{ + VisibleAuraMap::const_iterator itr = m_visibleAuras.find(slot); + if (itr != m_visibleAuras.end()) + return itr->second; + return 0; +} + +void Unit::SetVisibleAura(uint8 slot, AuraApplication * aur) +{ + m_visibleAuras[slot]=aur; + UpdateAuraForGroup(slot); +} + +void Unit::RemoveVisibleAura(uint8 slot) +{ + m_visibleAuras.erase(slot); + UpdateAuraForGroup(slot); +} + void Unit::UpdateInterruptMask() { m_interruptMask = 0; @@ -515,7 +541,7 @@ bool Unit::HasBreakableByDamageAuraType(AuraType type, uint32 excludeAura) const AuraEffectList const& auras = GetAuraEffectsByType(type); for (AuraEffectList::const_iterator itr = auras.begin(); itr != auras.end(); ++itr) if ((!excludeAura || excludeAura != (*itr)->GetSpellInfo()->Id) && //Avoid self interrupt of channeled Crowd Control spells like Seduction - ((*itr)->GetSpellInfo()->Attributes & SPELL_ATTR0_BREAKABLE_BY_DAMAGE || (*itr)->GetSpellInfo()->AuraInterruptFlags & AURA_INTERRUPT_FLAG_TAKE_DAMAGE)) + ((*itr)->GetSpellInfo()->AuraInterruptFlags & AURA_INTERRUPT_FLAG_TAKE_DAMAGE)) return true; return false; } @@ -598,7 +624,7 @@ uint32 Unit::DealDamage(Unit* victim, uint32 damage, CleanDamage const* cleanDam uint32 share = CalculatePct(damage, (*i)->GetAmount()); - // TODO: check packets if damage is done by victim, or by attacker of victim + /// @todo check packets if damage is done by victim, or by attacker of victim DealDamageMods(shareDamageTarget, share, NULL); DealDamage(shareDamageTarget, share, NULL, NODAMAGE, spell->GetSchoolMask(), spell, false); } @@ -818,7 +844,7 @@ void Unit::CastSpell(SpellCastTargets const& targets, SpellInfo const* spellInfo return; } - // TODO: this is a workaround - not needed anymore, but required for some scripts :( + /// @todo this is a workaround - not needed anymore, but required for some scripts :( if (!originalCaster && triggeredByAura) originalCaster = triggeredByAura->GetCasterGUID(); @@ -1078,7 +1104,7 @@ void Unit::DealSpellDamage(SpellNonMeleeDamage* damageInfo, bool durabilityLoss) DealDamage(victim, damageInfo->damage, &cleanDamage, SPELL_DIRECT_DAMAGE, SpellSchoolMask(damageInfo->schoolMask), spellProto, durabilityLoss); } -// TODO for melee need create structure as in +/// @todo for melee need create structure as in void Unit::CalculateMeleeDamage(Unit* victim, uint32 damage, CalcDamageInfo* damageInfo, WeaponAttackType attackType) { damageInfo->attacker = this; @@ -1401,7 +1427,7 @@ void Unit::DealMeleeDamage(CalcDamageInfo* damageInfo, bool durabilityLoss) // No Unit::CalcAbsorbResist here - opcode doesn't send that data - this damage is probably not affected by that victim->DealDamageMods(this, damage, NULL); - // TODO: Move this to a packet handler + /// @todo Move this to a packet handler WorldPacket data(SMSG_SPELLDAMAGESHIELD, (8+8+4+4+4+4)); data << uint64(victim->GetGUID()); data << uint64(GetGUID()); @@ -2242,6 +2268,17 @@ int32 Unit::GetMechanicResistChance(const SpellInfo* spell) return resist_mech; } +bool Unit::CanUseAttackType(uint8 attacktype) const +{ + switch (attacktype) + { + case BASE_ATTACK: return !HasFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_DISARMED); + case OFF_ATTACK: return !HasFlag(UNIT_FIELD_FLAGS_2, UNIT_FLAG2_DISARM_OFFHAND); + case RANGED_ATTACK: return !HasFlag(UNIT_FIELD_FLAGS_2, UNIT_FLAG2_DISARM_RANGED); + } + return true; +} + // Melee based spells hit result calculations SpellMissInfo Unit::MeleeSpellHitResult(Unit* victim, SpellInfo const* spell) { @@ -2419,7 +2456,7 @@ SpellMissInfo Unit::MeleeSpellHitResult(Unit* victim, SpellInfo const* spell) return SPELL_MISS_NONE; } -// TODO need use unit spell resistances in calculations +/// @todo need use unit spell resistances in calculations SpellMissInfo Unit::MagicSpellHitResult(Unit* victim, SpellInfo const* spell) { // Can`t miss on dead target (on skinning for example) @@ -2538,7 +2575,7 @@ SpellMissInfo Unit::SpellHitResult(Unit* victim, SpellInfo const* spell, bool Ca return SPELL_MISS_IMMUNE; // All positive spells can`t miss - // TODO: client not show miss log for this spells - so need find info for this in dbc and use it! + /// @todo client not show miss log for this spells - so need find info for this in dbc and use it! if (spell->IsPositive() &&(!IsHostileTo(victim))) // prevent from affecting enemy by "positive" spell return SPELL_MISS_NONE; @@ -2582,6 +2619,26 @@ SpellMissInfo Unit::SpellHitResult(Unit* victim, SpellInfo const* spell, bool Ca return SPELL_MISS_NONE; } +uint32 Unit::GetShieldBlockValue(uint32 soft_cap, uint32 hard_cap) const +{ + uint32 value = GetShieldBlockValue(); + if (value >= hard_cap) + { + value = (soft_cap + hard_cap) / 2; + } + else if (value > soft_cap) + { + value = soft_cap + ((value - soft_cap) / 2); + } + + return value; +} + +uint32 Unit::GetUnitMeleeSkill(Unit const* target) const +{ + return (target ? getLevelForTarget(target) : getLevel()) * 5; +} + uint32 Unit::GetDefenseSkillValue(Unit const* target) const { if (GetTypeId() == TYPEID_PLAYER) @@ -3147,7 +3204,9 @@ void Unit::DeMorph() Aura* Unit::_TryStackingOrRefreshingExistingAura(SpellInfo const* newAura, uint8 effMask, Unit* caster, int32* baseAmount /*= NULL*/, Item* castItem /*= NULL*/, uint64 casterGUID /*= 0*/) { ASSERT(casterGUID || caster); - if (!casterGUID) + + // Check if these can stack anyway + if (!casterGUID && !newAura->IsStackableOnOneSlotWithDifferentCasters()) casterGUID = caster->GetGUID(); // passive and Incanter's Absorption and auras with different type can stack with themselves any number of times @@ -4092,7 +4151,7 @@ AuraEffect* Unit::GetAuraEffect(AuraType type, SpellFamilyNames name, uint32 ico return NULL; } -AuraEffect* Unit::GetAuraEffect(AuraType type, SpellFamilyNames family, uint32 familyFlag1, uint32 familyFlag2, uint32 familyFlag3, uint64 casterGUID) +AuraEffect* Unit::GetAuraEffect(AuraType type, SpellFamilyNames family, uint32 familyFlag1, uint32 familyFlag2, uint32 familyFlag3, uint64 casterGUID) const { AuraEffectList const& auras = GetAuraEffectsByType(type); for (AuraEffectList::const_iterator i = auras.begin(); i != auras.end(); ++i) @@ -4108,6 +4167,11 @@ AuraEffect* Unit::GetAuraEffect(AuraType type, SpellFamilyNames family, uint32 f return NULL; } +AuraEffect* Unit::GetDummyAuraEffect(SpellFamilyNames name, uint32 iconId, uint8 effIndex) const +{ + return GetAuraEffect(SPELL_AURA_DUMMY, name, iconId, effIndex); +} + AuraApplication * Unit::GetAuraApplication(uint32 spellId, uint64 casterGUID, uint64 itemCasterGUID, uint8 reqEffMask, AuraApplication * except) const { AuraApplicationMapBounds range = m_appliedAuras.equal_range(spellId); @@ -4403,7 +4467,7 @@ float Unit::GetTotalAuraMultiplier(AuraType auratype) const return multiplier; } -int32 Unit::GetMaxPositiveAuraModifier(AuraType auratype) +int32 Unit::GetMaxPositiveAuraModifier(AuraType auratype) const { int32 modifier = 0; @@ -4429,7 +4493,7 @@ int32 Unit::GetMaxNegativeAuraModifier(AuraType auratype) const return modifier; } -int32 Unit::GetTotalAuraModifierByMiscMask(AuraType auratype, uint32 misc_mask) const +int32 Unit::GetTotalAuraModifierByMiscMask(AuraType auratype, uint32 miscMask) const { std::map<SpellGroup, int32> SameEffectSpellGroup; int32 modifier = 0; @@ -4437,7 +4501,7 @@ int32 Unit::GetTotalAuraModifierByMiscMask(AuraType auratype, uint32 misc_mask) AuraEffectList const& mTotalAuraList = GetAuraEffectsByType(auratype); for (AuraEffectList::const_iterator i = mTotalAuraList.begin(); i != mTotalAuraList.end(); ++i) - if ((*i)->GetMiscValue() & misc_mask) + if ((*i)->GetMiscValue() & miscMask) if (!sSpellMgr->AddSameEffectStackRuleSpellGroups((*i)->GetSpellInfo(), (*i)->GetAmount(), SameEffectSpellGroup)) modifier += (*i)->GetAmount(); @@ -4447,7 +4511,7 @@ int32 Unit::GetTotalAuraModifierByMiscMask(AuraType auratype, uint32 misc_mask) return modifier; } -float Unit::GetTotalAuraMultiplierByMiscMask(AuraType auratype, uint32 misc_mask) const +float Unit::GetTotalAuraMultiplierByMiscMask(AuraType auratype, uint32 miscMask) const { std::map<SpellGroup, int32> SameEffectSpellGroup; float multiplier = 1.0f; @@ -4455,7 +4519,7 @@ float Unit::GetTotalAuraMultiplierByMiscMask(AuraType auratype, uint32 misc_mask AuraEffectList const& mTotalAuraList = GetAuraEffectsByType(auratype); for (AuraEffectList::const_iterator i = mTotalAuraList.begin(); i != mTotalAuraList.end(); ++i) { - if (((*i)->GetMiscValue() & misc_mask)) + if (((*i)->GetMiscValue() & miscMask)) { // Check if the Aura Effect has a the Same Effect Stack Rule and if so, use the highest amount of that SpellGroup // If the Aura Effect does not have this Stack Rule, it returns false so we can add to the multiplier as usual @@ -4470,35 +4534,35 @@ float Unit::GetTotalAuraMultiplierByMiscMask(AuraType auratype, uint32 misc_mask return multiplier; } -int32 Unit::GetMaxPositiveAuraModifierByMiscMask(AuraType auratype, uint32 misc_mask, const AuraEffect* except) const +int32 Unit::GetMaxPositiveAuraModifierByMiscMask(AuraType auratype, uint32 miscMask, const AuraEffect* except) const { int32 modifier = 0; AuraEffectList const& mTotalAuraList = GetAuraEffectsByType(auratype); for (AuraEffectList::const_iterator i = mTotalAuraList.begin(); i != mTotalAuraList.end(); ++i) { - if (except != (*i) && (*i)->GetMiscValue()& misc_mask && (*i)->GetAmount() > modifier) + if (except != (*i) && (*i)->GetMiscValue()& miscMask && (*i)->GetAmount() > modifier) modifier = (*i)->GetAmount(); } return modifier; } -int32 Unit::GetMaxNegativeAuraModifierByMiscMask(AuraType auratype, uint32 misc_mask) const +int32 Unit::GetMaxNegativeAuraModifierByMiscMask(AuraType auratype, uint32 miscMask) const { int32 modifier = 0; AuraEffectList const& mTotalAuraList = GetAuraEffectsByType(auratype); for (AuraEffectList::const_iterator i = mTotalAuraList.begin(); i != mTotalAuraList.end(); ++i) { - if ((*i)->GetMiscValue()& misc_mask && (*i)->GetAmount() < modifier) + if ((*i)->GetMiscValue()& miscMask && (*i)->GetAmount() < modifier) modifier = (*i)->GetAmount(); } return modifier; } -int32 Unit::GetTotalAuraModifierByMiscValue(AuraType auratype, int32 misc_value) const +int32 Unit::GetTotalAuraModifierByMiscValue(AuraType auratype, int32 miscValue) const { std::map<SpellGroup, int32> SameEffectSpellGroup; int32 modifier = 0; @@ -4506,7 +4570,7 @@ int32 Unit::GetTotalAuraModifierByMiscValue(AuraType auratype, int32 misc_value) AuraEffectList const& mTotalAuraList = GetAuraEffectsByType(auratype); for (AuraEffectList::const_iterator i = mTotalAuraList.begin(); i != mTotalAuraList.end(); ++i) { - if ((*i)->GetMiscValue() == misc_value) + if ((*i)->GetMiscValue() == miscValue) if (!sSpellMgr->AddSameEffectStackRuleSpellGroups((*i)->GetSpellInfo(), (*i)->GetAmount(), SameEffectSpellGroup)) modifier += (*i)->GetAmount(); } @@ -4517,7 +4581,7 @@ int32 Unit::GetTotalAuraModifierByMiscValue(AuraType auratype, int32 misc_value) return modifier; } -float Unit::GetTotalAuraMultiplierByMiscValue(AuraType auratype, int32 misc_value) const +float Unit::GetTotalAuraMultiplierByMiscValue(AuraType auratype, int32 miscValue) const { std::map<SpellGroup, int32> SameEffectSpellGroup; float multiplier = 1.0f; @@ -4525,7 +4589,7 @@ float Unit::GetTotalAuraMultiplierByMiscValue(AuraType auratype, int32 misc_valu AuraEffectList const& mTotalAuraList = GetAuraEffectsByType(auratype); for (AuraEffectList::const_iterator i = mTotalAuraList.begin(); i != mTotalAuraList.end(); ++i) { - if ((*i)->GetMiscValue() == misc_value) + if ((*i)->GetMiscValue() == miscValue) if (!sSpellMgr->AddSameEffectStackRuleSpellGroups((*i)->GetSpellInfo(), (*i)->GetAmount(), SameEffectSpellGroup)) AddPct(multiplier, (*i)->GetAmount()); } @@ -4536,28 +4600,28 @@ float Unit::GetTotalAuraMultiplierByMiscValue(AuraType auratype, int32 misc_valu return multiplier; } -int32 Unit::GetMaxPositiveAuraModifierByMiscValue(AuraType auratype, int32 misc_value) const +int32 Unit::GetMaxPositiveAuraModifierByMiscValue(AuraType auratype, int32 miscValue) const { int32 modifier = 0; AuraEffectList const& mTotalAuraList = GetAuraEffectsByType(auratype); for (AuraEffectList::const_iterator i = mTotalAuraList.begin(); i != mTotalAuraList.end(); ++i) { - if ((*i)->GetMiscValue() == misc_value && (*i)->GetAmount() > modifier) + if ((*i)->GetMiscValue() == miscValue && (*i)->GetAmount() > modifier) modifier = (*i)->GetAmount(); } return modifier; } -int32 Unit::GetMaxNegativeAuraModifierByMiscValue(AuraType auratype, int32 misc_value) const +int32 Unit::GetMaxNegativeAuraModifierByMiscValue(AuraType auratype, int32 miscValue) const { int32 modifier = 0; AuraEffectList const& mTotalAuraList = GetAuraEffectsByType(auratype); for (AuraEffectList::const_iterator i = mTotalAuraList.begin(); i != mTotalAuraList.end(); ++i) { - if ((*i)->GetMiscValue() == misc_value && (*i)->GetAmount() < modifier) + if ((*i)->GetMiscValue() == miscValue && (*i)->GetAmount() < modifier) modifier = (*i)->GetAmount(); } @@ -4630,6 +4694,45 @@ int32 Unit::GetMaxNegativeAuraModifierByAffectMask(AuraType auratype, SpellInfo return modifier; } +float Unit::GetResistanceBuffMods(SpellSchools school, bool positive) const +{ + return GetFloatValue(positive ? UNIT_FIELD_RESISTANCEBUFFMODSPOSITIVE+school : UNIT_FIELD_RESISTANCEBUFFMODSNEGATIVE+school); +} + +void Unit::SetResistanceBuffMods(SpellSchools school, bool positive, float val) +{ + SetFloatValue(positive ? UNIT_FIELD_RESISTANCEBUFFMODSPOSITIVE+school : UNIT_FIELD_RESISTANCEBUFFMODSNEGATIVE+school, val); +} + +void Unit::ApplyResistanceBuffModsMod(SpellSchools school, bool positive, float val, bool apply) +{ + ApplyModSignedFloatValue(positive ? UNIT_FIELD_RESISTANCEBUFFMODSPOSITIVE+school : UNIT_FIELD_RESISTANCEBUFFMODSNEGATIVE+school, val, apply); +} + +void Unit::ApplyResistanceBuffModsPercentMod(SpellSchools school, bool positive, float val, bool apply) +{ + ApplyPercentModFloatValue(positive ? UNIT_FIELD_RESISTANCEBUFFMODSPOSITIVE+school : UNIT_FIELD_RESISTANCEBUFFMODSNEGATIVE+school, val, apply); +} + +void Unit::InitStatBuffMods() +{ + for (uint8 i = STAT_STRENGTH; i < MAX_STATS; ++i) + SetFloatValue(UNIT_FIELD_POSSTAT0+i, 0); + for (uint8 i = STAT_STRENGTH; i < MAX_STATS; ++i) + SetFloatValue(UNIT_FIELD_NEGSTAT0+i, 0); +} + +void Unit::ApplyStatBuffMod(Stats stat, float val, bool apply) +{ + ApplyModSignedFloatValue((val > 0 ? UNIT_FIELD_POSSTAT0+stat : UNIT_FIELD_NEGSTAT0+stat), val, apply); +} + +void Unit::ApplyStatPercentBuffMod(Stats stat, float val, bool apply) +{ + ApplyPercentModFloatValue(UNIT_FIELD_POSSTAT0+stat, val, apply); + ApplyPercentModFloatValue(UNIT_FIELD_NEGSTAT0+stat, val, apply); +} + void Unit::_RegisterDynObject(DynamicObject* dynObj) { m_dynObj.push_back(dynObj); @@ -4984,127 +5087,6 @@ void Unit::SendAttackStateUpdate(uint32 HitInfo, Unit* target, uint8 /*SwingType SendAttackStateUpdate(&dmgInfo); } -bool Unit::HandleHasteAuraProc(Unit* victim, uint32 damage, AuraEffect* triggeredByAura, SpellInfo const* /*procSpell*/, uint32 /*procFlag*/, uint32 /*procEx*/, uint32 cooldown) -{ - SpellInfo const* hasteSpell = triggeredByAura->GetSpellInfo(); - - Item* castItem = triggeredByAura->GetBase()->GetCastItemGUID() && GetTypeId() == TYPEID_PLAYER - ? ToPlayer()->GetItemByGuid(triggeredByAura->GetBase()->GetCastItemGUID()) : NULL; - - uint32 triggered_spell_id = 0; - Unit* target = victim; - int32 basepoints0 = 0; - - switch (hasteSpell->SpellFamilyName) - { - case SPELLFAMILY_ROGUE: - { - switch (hasteSpell->Id) - { - // Blade Flurry - case 13877: - case 33735: - { - target = SelectNearbyTarget(victim); - if (!target) - return false; - basepoints0 = damage; - triggered_spell_id = 22482; - break; - } - } - break; - } - } - - // processed charge only counting case - if (!triggered_spell_id) - return true; - - SpellInfo const* triggerEntry = sSpellMgr->GetSpellInfo(triggered_spell_id); - - if (!triggerEntry) - { - sLog->outError(LOG_FILTER_UNITS, "Unit::HandleHasteAuraProc: Spell %u has non-existing triggered spell %u", hasteSpell->Id, triggered_spell_id); - return false; - } - - if (cooldown && GetTypeId() == TYPEID_PLAYER && ToPlayer()->HasSpellCooldown(triggered_spell_id)) - return false; - - if (basepoints0) - CastCustomSpell(target, triggered_spell_id, &basepoints0, NULL, NULL, true, castItem, triggeredByAura); - else - CastSpell(target, triggered_spell_id, true, castItem, triggeredByAura); - - if (cooldown && GetTypeId() == TYPEID_PLAYER) - ToPlayer()->AddSpellCooldown(triggered_spell_id, 0, time(NULL) + cooldown); - - return true; -} - -bool Unit::HandleSpellCritChanceAuraProc(Unit* victim, uint32 /*damage*/, AuraEffect* triggeredByAura, SpellInfo const* /*procSpell*/, uint32 /*procFlag*/, uint32 /*procEx*/, uint32 cooldown) -{ - SpellInfo const* triggeredByAuraSpell = triggeredByAura->GetSpellInfo(); - - Item* castItem = triggeredByAura->GetBase()->GetCastItemGUID() && GetTypeId() == TYPEID_PLAYER - ? ToPlayer()->GetItemByGuid(triggeredByAura->GetBase()->GetCastItemGUID()) : NULL; - - uint32 triggered_spell_id = 0; - Unit* target = victim; - int32 basepoints0 = 0; - - switch (triggeredByAuraSpell->SpellFamilyName) - { - case SPELLFAMILY_MAGE: - { - switch (triggeredByAuraSpell->Id) - { - // Focus Magic - case 54646: - { - Unit* caster = triggeredByAura->GetCaster(); - if (!caster) - return false; - - triggered_spell_id = 54648; - target = caster; - break; - } - } - } - } - - // processed charge only counting case - if (!triggered_spell_id) - return true; - - SpellInfo const* triggerEntry = sSpellMgr->GetSpellInfo(triggered_spell_id); - - if (!triggerEntry) - { - sLog->outError(LOG_FILTER_UNITS, "Unit::HandleHasteAuraProc: Spell %u has non-existing triggered spell %u", triggeredByAuraSpell->Id, triggered_spell_id); - return false; - } - - // default case - if (!target || (target != this && !target->isAlive())) - return false; - - if (cooldown && GetTypeId() == TYPEID_PLAYER && ToPlayer()->HasSpellCooldown(triggered_spell_id)) - return false; - - if (basepoints0) - CastCustomSpell(target, triggered_spell_id, &basepoints0, NULL, NULL, true, castItem, triggeredByAura); - else - CastSpell(target, triggered_spell_id, true, castItem, triggeredByAura); - - if (cooldown && GetTypeId() == TYPEID_PLAYER) - ToPlayer()->AddSpellCooldown(triggered_spell_id, 0, time(NULL) + cooldown); - - return true; -} - //victim may be NULL bool Unit::HandleDummyAuraProc(Unit* victim, uint32 damage, AuraEffect* triggeredByAura, SpellInfo const* procSpell, uint32 procFlag, uint32 procEx, uint32 cooldown) { @@ -5128,38 +5110,6 @@ bool Unit::HandleDummyAuraProc(Unit* victim, uint32 damage, AuraEffect* triggere { switch (dummySpell->Id) { - // Bloodworms Health Leech - case 50453: - { - if (Unit* owner = GetOwner()) - { - basepoints0 = int32(damage * 1.50f); - target = owner; - triggered_spell_id = 50454; - break; - } - return false; - } - // Eye for an Eye - case 9799: - case 25988: - { - // return damage % to attacker but < 50% own total health - basepoints0 = int32(std::min(CalculatePct(damage, triggerAmount), CountPctFromMaxHealth(50))); - triggered_spell_id = 25997; - break; - } - // Sweeping Strikes - case 18765: - case 35429: - { - target = SelectNearbyTarget(victim); - if (!target) - return false; - - triggered_spell_id = 26654; - break; - } // Unstable Power case 24658: { @@ -5176,67 +5126,6 @@ bool Unit::HandleDummyAuraProc(Unit* victim, uint32 damage, AuraEffect* triggere RemoveAuraFromStack(24662); return true; } - // Adaptive Warding (Frostfire Regalia set) - case 28764: - { - if (!procSpell) - return false; - - // find Mage Armor - if (!GetAuraEffect(SPELL_AURA_MOD_MANA_REGEN_INTERRUPT, SPELLFAMILY_MAGE, 0x10000000, 0, 0)) - return false; - - switch (GetFirstSchoolInMask(procSpell->GetSchoolMask())) - { - case SPELL_SCHOOL_NORMAL: - case SPELL_SCHOOL_HOLY: - return false; // ignored - case SPELL_SCHOOL_FIRE: triggered_spell_id = 28765; break; - case SPELL_SCHOOL_NATURE: triggered_spell_id = 28768; break; - case SPELL_SCHOOL_FROST: triggered_spell_id = 28766; break; - case SPELL_SCHOOL_SHADOW: triggered_spell_id = 28769; break; - case SPELL_SCHOOL_ARCANE: triggered_spell_id = 28770; break; - default: - return false; - } - - target = this; - break; - } - // Obsidian Armor (Justice Bearer`s Pauldrons shoulder) - case 27539: - { - if (!procSpell) - return false; - - switch (GetFirstSchoolInMask(procSpell->GetSchoolMask())) - { - case SPELL_SCHOOL_NORMAL: - return false; // ignore - case SPELL_SCHOOL_HOLY: triggered_spell_id = 27536; break; - case SPELL_SCHOOL_FIRE: triggered_spell_id = 27533; break; - case SPELL_SCHOOL_NATURE: triggered_spell_id = 27538; break; - case SPELL_SCHOOL_FROST: triggered_spell_id = 27534; break; - case SPELL_SCHOOL_SHADOW: triggered_spell_id = 27535; break; - case SPELL_SCHOOL_ARCANE: triggered_spell_id = 27540; break; - default: - return false; - } - - target = this; - break; - } - // Mana Leech (Passive) (Priest Pet Aura) - case 28305: - { - // Cast on owner - target = GetOwner(); - if (!target) - return false; - - triggered_spell_id = 34650; - break; - } // Mark of Malice case 33493: { @@ -5311,7 +5200,7 @@ bool Unit::HandleDummyAuraProc(Unit* victim, uint32 damage, AuraEffect* triggere target = this; if (roll_chance_i(10)) - ToPlayer()->Say("This is Madness!", LANG_UNIVERSAL); // TODO: It should be moved to database, shouldn't it? + ToPlayer()->Say("This is Madness!", LANG_UNIVERSAL); /// @todo It should be moved to database, shouldn't it? break; } // Sunwell Exalted Caster Neck (??? neck) @@ -5427,14 +5316,6 @@ bool Unit::HandleDummyAuraProc(Unit* victim, uint32 damage, AuraEffect* triggere } return false; } - // Living Seed - case 48504: - { - triggered_spell_id = 48503; - basepoints0 = triggerAmount; - target = this; - break; - } // Kill command case 58914: { @@ -5594,50 +5475,6 @@ bool Unit::HandleDummyAuraProc(Unit* victim, uint32 damage, AuraEffect* triggere } break; } - case 71875: // Item - Black Bruise: Necrotic Touch Proc - case 71877: - { - basepoints0 = CalculatePct(int32(damage), triggerAmount); - triggered_spell_id = 71879; - break; - } - // Item - Shadowmourne Legendary - case 71903: - { - if (!victim || !victim->isAlive() || HasAura(73422)) // cant collect shards while under effect of Chaos Bane buff - return false; - - CastSpell(this, 71905, true, NULL, triggeredByAura); - - // this can't be handled in AuraScript because we need to know victim - Aura const* dummy = GetAura(71905); - if (!dummy || dummy->GetStackAmount() < 10) - return false; - - RemoveAurasDueToSpell(71905); - triggered_spell_id = 71904; - target = victim; - break; - } - // Shadow's Fate (Shadowmourne questline) - case 71169: - { - Unit* caster = triggeredByAura->GetCaster(); - if (caster && caster->GetTypeId() == TYPEID_PLAYER && caster->ToPlayer()->GetQuestStatus(24547) == QUEST_STATUS_INCOMPLETE) - { - CastSpell(caster, 71203, true); - return true; - } - else - return false; - } - // Essence of the Blood Queen - case 70871: - { - basepoints0 = CalculatePct(int32(damage), triggerAmount); - CastCustomSpell(70872, SPELLVALUE_BASE_POINT0, basepoints0, this); - return true; - } case 65032: // Boom aura (321 Boombot) { if (victim->GetEntry() != 33343) // Scrapbot @@ -5650,13 +5487,6 @@ bool Unit::HandleDummyAuraProc(Unit* victim, uint32 damage, AuraEffect* triggere instance->DoCastSpellOnPlayers(65037); // Achievement criteria marker break; } - // Dark Hunger (The Lich King encounter) - case 69383: - { - basepoints0 = CalculatePct(int32(damage), 50); - triggered_spell_id = 69384; - break; - } } break; } @@ -5674,22 +5504,6 @@ bool Unit::HandleDummyAuraProc(Unit* victim, uint32 damage, AuraEffect* triggere triggered_spell_id = 29442; break; } - // Master of Elements - if (dummySpell->SpellIconID == 1920) - { - if (!procSpell) - return false; - - // mana cost save - int32 cost = int32(procSpell->ManaCost + CalculatePct(GetCreateMana(), procSpell->ManaCostPercentage)); - basepoints0 = CalculatePct(cost, triggerAmount); - if (basepoints0 <= 0) - return false; - - target = this; - triggered_spell_id = 29077; - break; - } // Arcane Potency if (dummySpell->SpellIconID == 2120) { @@ -5707,7 +5521,6 @@ bool Unit::HandleDummyAuraProc(Unit* victim, uint32 damage, AuraEffect* triggere } break; } - // Hot Streak if (dummySpell->SpellIconID == 2999) { @@ -5730,20 +5543,6 @@ bool Unit::HandleDummyAuraProc(Unit* victim, uint32 damage, AuraEffect* triggere counter->SetAmount(25); return true; } - // Burnout - if (dummySpell->SpellIconID == 2998) - { - if (!procSpell) - return false; - - int32 cost = int32(procSpell->ManaCost + CalculatePct(GetCreateMana(), procSpell->ManaCostPercentage)); - basepoints0 = CalculatePct(cost, triggerAmount); - if (basepoints0 <= 0) - return false; - triggered_spell_id = 44450; - target = this; - break; - } // Incanter's Regalia set (add trigger chance to Mana Shield) if (dummySpell->SpellFamilyFlags[0] & 0x8000) { @@ -5773,29 +5572,6 @@ bool Unit::HandleDummyAuraProc(Unit* victim, uint32 damage, AuraEffect* triggere RemoveAurasByType(SPELL_AURA_MOD_DECREASE_SPEED); return true; } - // Ignite - case 11119: - case 11120: - case 12846: - case 12847: - case 12848: - { - switch (dummySpell->Id) - { - case 11119: basepoints0 = int32(0.04f * damage); break; - case 11120: basepoints0 = int32(0.08f * damage); break; - case 12846: basepoints0 = int32(0.12f * damage); break; - case 12847: basepoints0 = int32(0.16f * damage); break; - case 12848: basepoints0 = int32(0.20f * damage); break; - default: - sLog->outError(LOG_FILTER_UNITS, "Unit::HandleDummyAuraProc: non handled spell id: %u (IG)", dummySpell->Id); - return false; - } - - triggered_spell_id = 12654; - basepoints0 += victim->GetRemainingPeriodicAmount(GetGUID(), triggered_spell_id, SPELL_AURA_PERIODIC_DAMAGE); - break; - } // Glyph of Ice Block case 56372: { @@ -5815,25 +5591,6 @@ bool Unit::HandleDummyAuraProc(Unit* victim, uint32 damage, AuraEffect* triggere } break; } - // Blessing of Ancient Kings (Val'anyr, Hammer of Ancient Kings) - case 64411: - { - if (!victim) - return false; - basepoints0 = int32(CalculatePct(damage, 15)); - if (AuraEffect* aurEff = victim->GetAuraEffect(64413, 0, GetGUID())) - { - // The shield can grow to a maximum size of 20, 000 damage absorbtion - aurEff->SetAmount(std::min<int32>(aurEff->GetAmount() + basepoints0, 20000)); - - // Refresh and return to prevent replacing the aura - aurEff->GetBase()->RefreshDuration(); - return true; - } - target = victim; - triggered_spell_id = 64413; - break; - } case 47020: // Enter vehicle XT-002 (Scrapbot) { if (GetTypeId() != TYPEID_UNIT) @@ -5843,7 +5600,7 @@ bool Unit::HandleDummyAuraProc(Unit* victim, uint32 damage, AuraEffect* triggere if (!vehicleBase) return false; - // Todo: Check if this amount is blizzlike + /// @todo Check if this amount is blizzlike vehicleBase->ModifyHealth(int32(vehicleBase->CountPctFromMaxHealth(1))); break; } @@ -5854,16 +5611,6 @@ bool Unit::HandleDummyAuraProc(Unit* victim, uint32 damage, AuraEffect* triggere { switch (dummySpell->Id) { - // Sweeping Strikes - case 12328: - { - target = SelectNearbyTarget(victim); - if (!target) - return false; - - triggered_spell_id = 26654; - break; - } // Victorious case 32216: { @@ -5913,14 +5660,6 @@ bool Unit::HandleDummyAuraProc(Unit* victim, uint32 damage, AuraEffect* triggere target = this; break; } - // Damage Shield - if (dummySpell->SpellIconID == 3214) - { - triggered_spell_id = 59653; - // % of amount blocked - basepoints0 = CalculatePct(int32(GetShieldBlockValue()), triggerAmount); - break; - } // Glyph of Blocking if (dummySpell->Id == 58375) { @@ -5991,31 +5730,8 @@ bool Unit::HandleDummyAuraProc(Unit* victim, uint32 damage, AuraEffect* triggere triggeredByAura->SetAmount(triggeredByAura->GetAmount() - damage); return true; } - // Fel Synergy - if (dummySpell->SpellIconID == 3222) - { - target = GetGuardianPet(); - if (!target) - return false; - basepoints0 = CalculatePct(int32(damage), triggerAmount); - triggered_spell_id = 54181; - break; - } switch (dummySpell->Id) { - // Siphon Life - case 63108: - { - if (!damage) - break; - // Glyph of Siphon Life - if (HasAura(56216)) - triggerAmount += triggerAmount / 4; - triggered_spell_id = 63106; - target = this; - basepoints0 = CalculatePct(int32(damage), triggerAmount); - break; - } // Glyph of Shadowflame case 63310: { @@ -6126,24 +5842,6 @@ bool Unit::HandleDummyAuraProc(Unit* victim, uint32 damage, AuraEffect* triggere victim->CastSpell(victim, 57669, true, castItem, triggeredByAura); return true; // no hidden cooldown } - // Divine Aegis - if (dummySpell->SpellIconID == 2820) - { - if (!target) - return false; - - // Multiple effects stack, so let's try to find this aura. - int32 bonus = 0; - if (AuraEffect const* aurEff = target->GetAuraEffect(47753, 0)) - bonus = aurEff->GetAmount(); - - basepoints0 = CalculatePct(int32(damage), triggerAmount) + bonus; - if (basepoints0 > target->getLevel() * 125) - basepoints0 = target->getLevel() * 125; - - triggered_spell_id = 47753; - break; - } // Body and Soul if (dummySpell->SpellIconID == 2218) { @@ -6184,31 +5882,6 @@ bool Unit::HandleDummyAuraProc(Unit* victim, uint32 damage, AuraEffect* triggere target = this; break; } - // Glyph of Prayer of Healing - case 55680: - { - triggered_spell_id = 56161; - - SpellInfo const* GoPoH = sSpellMgr->GetSpellInfo(triggered_spell_id); - if (!GoPoH) - return false; - - int EffIndex = 0; - for (uint8 i = 0; i < MAX_SPELL_EFFECTS; i++) - { - if (GoPoH->Effects[i].Effect == SPELL_EFFECT_APPLY_AURA) - { - EffIndex = i; - break; - } - } - int32 tickcount = GoPoH->GetMaxDuration() / GoPoH->Effects[EffIndex].Amplitude; - if (!tickcount) - return false; - - basepoints0 = CalculatePct(int32(damage), triggerAmount) / tickcount; - break; - } // Improved Shadowform case 47570: case 47569: @@ -6481,13 +6154,6 @@ bool Unit::HandleDummyAuraProc(Unit* victim, uint32 damage, AuraEffect* triggere triggered_spell_id = isWrathSpell ? 48518 : 48517; break; } - // Living Seed - else if (dummySpell->SpellIconID == 2860) - { - triggered_spell_id = 48504; - basepoints0 = CalculatePct(int32(damage), triggerAmount); - break; - } break; } case SPELLFAMILY_ROGUE: @@ -6508,16 +6174,6 @@ bool Unit::HandleDummyAuraProc(Unit* victim, uint32 damage, AuraEffect* triggere triggered_spell_id = 32747; break; } - case 57934: // Tricks of the Trade - { - Unit* redirectTarget = GetMisdirectionTarget(); - RemoveAura(57934); - if (!redirectTarget) - break; - CastSpell(this,59628,true); - CastSpell(redirectTarget,57933,true); - break; - } } switch (dummySpell->SpellIconID) @@ -6636,14 +6292,6 @@ bool Unit::HandleDummyAuraProc(Unit* victim, uint32 damage, AuraEffect* triggere switch (dummySpell->Id) { - case 34477: // Misdirection - { - if (!GetMisdirectionTarget()) - return false; - triggered_spell_id = 35079; // 4 sec buff on self - target = this; - break; - } case 57870: // Glyph of Mend Pet { victim->CastSpell(victim, 57894, true, NULL, NULL, GetGUID()); @@ -6654,18 +6302,6 @@ bool Unit::HandleDummyAuraProc(Unit* victim, uint32 damage, AuraEffect* triggere } case SPELLFAMILY_PALADIN: { - // Seal of Righteousness - melee proc dummy (addition ${$MWS*(0.022*$AP+0.044*$SPH)} damage) - if (dummySpell->SpellFamilyFlags[0] & 0x8000000) - { - if (effIndex != 0) - return false; - triggered_spell_id = 25742; - float ap = GetTotalAttackPowerValue(BASE_ATTACK); - int32 holy = SpellBaseDamageBonusDone(SPELL_SCHOOL_MASK_HOLY) + - victim->SpellBaseDamageBonusTaken(SPELL_SCHOOL_MASK_HOLY); - basepoints0 = (int32)GetAttackTime(BASE_ATTACK) * int32(ap * 0.022f + 0.044f * holy) / 1000; - break; - } // Light's Beacon - Beacon of Light if (dummySpell->Id == 53651) { @@ -6708,7 +6344,7 @@ bool Unit::HandleDummyAuraProc(Unit* victim, uint32 damage, AuraEffect* triggere if (triggered_spell_id && beaconTarget) { - victim->CastCustomSpell(beaconTarget, triggered_spell_id, &basepoints0, NULL, NULL, true, 0, triggeredByAura); + victim->CastCustomSpell(beaconTarget, triggered_spell_id, &basepoints0, NULL, NULL, true); return true; } @@ -6832,20 +6468,6 @@ bool Unit::HandleDummyAuraProc(Unit* victim, uint32 damage, AuraEffect* triggere } break; } - case 25899: // Greater Blessing of Sanctuary - case 20911: // Blessing of Sanctuary - { - target = this; - switch (target->getPowerType()) - { - case POWER_MANA: - triggered_spell_id = 57319; - break; - default: - return false; - } - break; - } // Seal of Vengeance (damage calc on apply aura) case 31801: { @@ -7348,20 +6970,6 @@ bool Unit::HandleDummyAuraProc(Unit* victim, uint32 damage, AuraEffect* triggere target = this; break; } - // Earth Shield - if (dummySpell->SpellFamilyFlags[1] & 0x00000400) - { - // 3.0.8: Now correctly uses the Shaman's own spell critical strike chance to determine the chance of a critical heal. - originalCaster = triggeredByAura->GetCasterGUID(); - target = this; - basepoints0 = triggerAmount; - - // Glyph of Earth Shield - if (AuraEffect* aur = GetAuraEffect(63279, 0)) - AddPct(basepoints0, aur->GetAmount()); - triggered_spell_id = 379; - break; - } // Flametongue Weapon (Passive) if (dummySpell->SpellFamilyFlags[0] & 0x200000) { @@ -7573,7 +7181,7 @@ bool Unit::HandleDummyAuraProc(Unit* victim, uint32 damage, AuraEffect* triggere // Mark of Blood if (dummySpell->Id == 49005) { - // TODO: need more info (cooldowns/PPM) + /// @todo need more info (cooldowns/PPM) triggered_spell_id = 61607; break; } @@ -7813,114 +7421,6 @@ bool Unit::HandleDummyAuraProc(Unit* victim, uint32 damage, AuraEffect* triggere return true; } -bool Unit::HandleObsModEnergyAuraProc(Unit* victim, uint32 /*damage*/, AuraEffect* triggeredByAura, SpellInfo const* /*procSpell*/, uint32 /*procFlag*/, uint32 /*procEx*/, uint32 cooldown) -{ - SpellInfo const* dummySpell = triggeredByAura->GetSpellInfo(); - //uint32 effIndex = triggeredByAura->GetEffIndex(); - //int32 triggerAmount = triggeredByAura->GetAmount(); - - Item* castItem = triggeredByAura->GetBase()->GetCastItemGUID() && GetTypeId() == TYPEID_PLAYER - ? ToPlayer()->GetItemByGuid(triggeredByAura->GetBase()->GetCastItemGUID()) : NULL; - - uint32 triggered_spell_id = 0; - Unit* target = victim; - int32 basepoints0 = 0; - - switch (dummySpell->SpellFamilyName) - { - case SPELLFAMILY_HUNTER: - { - // Aspect of the Viper - if (dummySpell->SpellFamilyFlags[1] & 0x40000) - { - uint32 maxmana = GetMaxPower(POWER_MANA); - basepoints0 = CalculatePct(maxmana, GetAttackTime(RANGED_ATTACK) / 1000.0f); - target = this; - triggered_spell_id = 34075; - break; - } - break; - } - } - // processed charge only counting case - if (!triggered_spell_id) - return true; - - SpellInfo const* triggerEntry = sSpellMgr->GetSpellInfo(triggered_spell_id); - - // Try handle unknown trigger spells - if (!triggerEntry) - { - sLog->outError(LOG_FILTER_UNITS, "Unit::HandleObsModEnergyAuraProc: Spell %u has non-existing triggered spell %u", dummySpell->Id, triggered_spell_id); - return false; - } - - if (cooldown && GetTypeId() == TYPEID_PLAYER && ToPlayer()->HasSpellCooldown(triggered_spell_id)) - return false; - if (basepoints0) - CastCustomSpell(target, triggered_spell_id, &basepoints0, NULL, NULL, true, castItem, triggeredByAura); - else - CastSpell(target, triggered_spell_id, true, castItem, triggeredByAura); - - if (cooldown && GetTypeId() == TYPEID_PLAYER) - ToPlayer()->AddSpellCooldown(triggered_spell_id, 0, time(NULL) + cooldown); - return true; -} -bool Unit::HandleModDamagePctTakenAuraProc(Unit* victim, uint32 /*damage*/, AuraEffect* triggeredByAura, SpellInfo const* /*procSpell*/, uint32 /*procFlag*/, uint32 /*procEx*/, uint32 cooldown) -{ - SpellInfo const* dummySpell = triggeredByAura->GetSpellInfo(); - //uint32 effIndex = triggeredByAura->GetEffIndex(); - //int32 triggerAmount = triggeredByAura->GetAmount(); - - Item* castItem = triggeredByAura->GetBase()->GetCastItemGUID() && GetTypeId() == TYPEID_PLAYER - ? ToPlayer()->GetItemByGuid(triggeredByAura->GetBase()->GetCastItemGUID()) : NULL; - - uint32 triggered_spell_id = 0; - Unit* target = victim; - int32 basepoints0 = 0; - - switch (dummySpell->SpellFamilyName) - { - case SPELLFAMILY_PALADIN: - { - // Blessing of Sanctuary - if (dummySpell->SpellFamilyFlags[0] & 0x10000000) - { - switch (getPowerType()) - { - case POWER_MANA: triggered_spell_id = 57319; break; - default: - return false; - } - } - break; - } - } - // processed charge only counting case - if (!triggered_spell_id) - return true; - - SpellInfo const* triggerEntry = sSpellMgr->GetSpellInfo(triggered_spell_id); - - if (!triggerEntry) - { - sLog->outError(LOG_FILTER_UNITS, "Unit::HandleModDamagePctTakenAuraProc: Spell %u has non-existing triggered spell %u", dummySpell->Id, triggered_spell_id); - return false; - } - - if (cooldown && GetTypeId() == TYPEID_PLAYER && ToPlayer()->HasSpellCooldown(triggered_spell_id)) - return false; - - if (basepoints0) - CastCustomSpell(target, triggered_spell_id, &basepoints0, NULL, NULL, true, castItem, triggeredByAura); - else - CastSpell(target, triggered_spell_id, true, castItem, triggeredByAura); - - if (cooldown && GetTypeId() == TYPEID_PLAYER) - ToPlayer()->AddSpellCooldown(triggered_spell_id, 0, time(NULL) + cooldown); - - return true; -} // Used in case when access to whole aura is needed // All procs should be handled like this... @@ -8303,12 +7803,6 @@ bool Unit::HandleProcTriggerSpell(Unit* victim, uint32 damage, AuraEffect* trigg RemoveAuraFromStack(auraSpellInfo->Id); return false; } - if (auraSpellInfo->Id == 50720) - { - target = triggeredByAura->GetCaster(); - if (!target) - return false; - } break; case SPELLFAMILY_WARLOCK: { @@ -8598,7 +8092,7 @@ bool Unit::HandleProcTriggerSpell(Unit* victim, uint32 damage, AuraEffect* trigg basepoints0 = int32(auraSpellInfo->Effects[EFFECT_0].CalcValue() * GetMaxHealth() / 100.0f); target = this; trigger_spell_id = 31616; - // TODO: Threat part + /// @todo Threat part } else return false; @@ -8955,7 +8449,7 @@ bool Unit::HandleProcTriggerSpell(Unit* victim, uint32 damage, AuraEffect* trigg { if (AuraEffect* aurEff = owner->GetDummyAuraEffect(SPELLFAMILY_WARLOCK, 3220, 0)) { - basepoints0 = int32((aurEff->GetAmount() * owner->SpellBaseDamageBonusDone(SpellSchoolMask(SPELL_SCHOOL_MASK_MAGIC)) + 100.0f) / 100.0f); // TODO: Is it right? + basepoints0 = int32((aurEff->GetAmount() * owner->SpellBaseDamageBonusDone(SpellSchoolMask(SPELL_SCHOOL_MASK_MAGIC)) + 100.0f) / 100.0f); /// @todo Is it right? CastCustomSpell(this, trigger_spell_id, &basepoints0, &basepoints0, NULL, true, castItem, triggeredByAura); return true; } @@ -9071,48 +8565,6 @@ bool Unit::HandleProcTriggerSpell(Unit* victim, uint32 damage, AuraEffect* trigg return false; break; } - // Shadow's Fate (Shadowmourne questline) - case 71169: - { - // Victim needs more checks so bugs, rats or summons can not be affected by the proc. - if (GetTypeId() != TYPEID_PLAYER || !victim || victim->GetTypeId() != TYPEID_UNIT || victim->GetCreatureType() == CREATURE_TYPE_CRITTER) - return false; - - Player* player = ToPlayer(); - if (player->GetQuestStatus(24547) == QUEST_STATUS_INCOMPLETE) - { - break; - } - else if (player->GetDifficulty(true) == RAID_DIFFICULTY_25MAN_NORMAL || player->GetDifficulty(true) == RAID_DIFFICULTY_25MAN_HEROIC) - { - uint32 spellId = 0; - uint32 questId = 0; - switch (victim->GetEntry()) - { - case 36678: // NPC: Professor Putricide - questId = 24749; // Quest: Unholy Infusion - spellId = 71516; // Spell: Shadow Infusion - break; - case 37955: // NPC: Blood-Queen Lana'thel - questId = 24756; // Quest: Blood Infusion - spellId = 72154; // Spell: Thirst Quenched - break; - case 36853: // NPC: Sindragosa - questId = 24757; // Quest: Frost Infusion - spellId = 72290; // Spell: Frost-Imbued Blade - break; - default: - return false; - } - - if (player->GetQuestStatus(questId) != QUEST_STATUS_INCOMPLETE || !player->HasAura(spellId)) - return false; - - break; - } - else - return false; - } } if (cooldown && GetTypeId() == TYPEID_PLAYER && ToPlayer()->HasSpellCooldown(trigger_spell_id)) @@ -9454,6 +8906,27 @@ bool Unit::IsNeutralToAll() const return my_faction->IsNeutralToAll(); } +void Unit::_addAttacker(Unit* pAttacker) +{ + m_attackers.insert(pAttacker); +} + +void Unit::_removeAttacker(Unit* pAttacker) +{ + m_attackers.erase(pAttacker); +} + +Unit* Unit::getAttackerForHelper() const // If someone wants to help, who to give them +{ + if (getVictim() != NULL) + return getVictim(); + + if (!m_attackers.empty()) + return *(m_attackers.begin()); + + return NULL; +} + bool Unit::Attack(Unit* victim, bool meleeAttack) { if (!victim || victim == this) @@ -9844,6 +9317,19 @@ Unit* Unit::GetCharm() const return NULL; } +Unit* Unit::GetCharmerOrOwner() const +{ + return GetCharmerGUID() ? GetCharmer() : GetOwner(); +} + +Unit* Unit::GetCharmerOrOwnerOrSelf() const +{ + if (Unit* u = GetCharmerOrOwner()) + return u; + + return (Unit*)this; +} + void Unit::SetMinion(Minion *minion, bool apply) { sLog->outDebug(LOG_FILTER_UNITS, "SetMinion %u for %u, apply %u", minion->GetEntry(), GetEntry(), apply); @@ -10041,7 +9527,7 @@ void Unit::SetCharm(Unit* charm, bool apply) sLog->outFatal(LOG_FILTER_UNITS, "Player %s is trying to charm unit %u, but it already has a charmed unit " UI64FMTD "", GetName().c_str(), charm->GetEntry(), GetCharmGUID()); charm->m_ControlledByPlayer = true; - // TODO: maybe we can use this flag to check if controlled by player + /// @todo maybe we can use this flag to check if controlled by player charm->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_PVP_ATTACKABLE); } else @@ -10158,7 +9644,7 @@ Unit* Unit::GetMagicHitRedirectTarget(Unit* victim, SpellInfo const* spellInfo) && spellInfo->CheckTarget(this, magnet, false) == SPELL_CAST_OK && _IsValidAttackTarget(magnet, spellInfo)) { - // TODO: handle this charge drop by proc in cast phase on explicit target + /// @todo handle this charge drop by proc in cast phase on explicit target (*itr)->GetBase()->DropCharge(AURA_REMOVE_BY_EXPIRE); return magnet; } @@ -10220,6 +9706,24 @@ void Unit::RemoveAllControlled() sLog->outFatal(LOG_FILTER_UNITS, "Unit %u is not able to release its charm " UI64FMTD, GetEntry(), GetCharmGUID()); } +bool Unit::isPossessedByPlayer() const +{ + return HasUnitState(UNIT_STATE_POSSESSED) && IS_PLAYER_GUID(GetCharmerGUID()); +} + +bool Unit::isPossessing(Unit* u) const +{ + return u->isPossessed() && GetCharmGUID() == u->GetGUID(); +} + +bool Unit::isPossessing() const +{ + if (Unit* u = GetCharm()) + return u->isPossessed(); + else + return false; +} + Unit* Unit::GetNextRandomRaidMemberOrPet(float radius) { Player* player = NULL; @@ -10322,7 +9826,7 @@ void Unit::UnsummonAllTotems() void Unit::SendHealSpellLog(Unit* victim, uint32 SpellID, uint32 Damage, uint32 OverHeal, uint32 Absorb, bool critical) { // we guess size - WorldPacket data(SMSG_SPELLHEALLOG, (8+8+4+4+4+4+1+1)); + WorldPacket data(SMSG_SPELLHEALLOG, 8 + 8 + 4 + 4 + 4 + 4 + 1 + 1); data.append(victim->GetPackGUID()); data.append(GetPackGUID()); data << uint32(SpellID); @@ -10345,28 +9849,28 @@ int32 Unit::HealBySpell(Unit* victim, SpellInfo const* spellInfo, uint32 addHeal return gain; } -void Unit::SendEnergizeSpellLog(Unit* victim, uint32 spellID, uint32 damage, Powers powerType) +void Unit::SendEnergizeSpellLog(Unit* victim, uint32 spellId, int32 damage, Powers powerType) { WorldPacket data(SMSG_SPELLENERGIZELOG, (8+8+4+4+4+1)); data.append(victim->GetPackGUID()); data.append(GetPackGUID()); - data << uint32(spellID); + data << uint32(spellId); data << uint32(powerType); - data << uint32(damage); + data << int32(damage); SendMessageToSet(&data, true); } -void Unit::EnergizeBySpell(Unit* victim, uint32 spellID, uint32 damage, Powers powerType) +void Unit::EnergizeBySpell(Unit* victim, uint32 spellId, int32 damage, Powers powerType) { - SendEnergizeSpellLog(victim, spellID, damage, powerType); + SendEnergizeSpellLog(victim, spellId, damage, powerType); // needs to be called after sending spell log victim->ModifyPower(powerType, damage); - SpellInfo const* spellInfo = sSpellMgr->GetSpellInfo(spellID); + SpellInfo const* spellInfo = sSpellMgr->GetSpellInfo(spellId); victim->getHostileRefManager().threatAssist(this, float(damage) * 0.5f, spellInfo); } -uint32 Unit::SpellDamageBonusDone(Unit* victim, SpellInfo const* spellProto, uint32 pdamage, DamageEffectType damagetype, uint32 stack) +uint32 Unit::SpellDamageBonusDone(Unit* victim, SpellInfo const* spellProto, uint32 pdamage, DamageEffectType damagetype, uint32 stack) const { if (!spellProto || !victim || damagetype == DIRECT_DAMAGE) return pdamage; @@ -10430,7 +9934,7 @@ uint32 Unit::SpellDamageBonusDone(Unit* victim, SpellInfo const* spellProto, uin AddPct(DoneTotalMod, (*i)->GetAmount()); // done scripted mod (take it from owner) - Unit* owner = GetOwner() ? GetOwner() : this; + Unit const * const owner = GetOwner() ? GetOwner() : this; AuraEffectList const& mOverrideClassScript= owner->GetAuraEffectsByType(SPELL_AURA_OVERRIDE_CLASS_SCRIPTS); for (AuraEffectList::const_iterator i = mOverrideClassScript.begin(); i != mOverrideClassScript.end(); ++i) { @@ -10463,8 +9967,8 @@ uint32 Unit::SpellDamageBonusDone(Unit* victim, SpellInfo const* spellProto, uin for (AuraApplicationMap::const_iterator itr = victimAuras.begin(); itr != victimAuras.end(); ++itr) { Aura const* aura = itr->second->GetBase(); - SpellInfo const* m_spell = aura->GetSpellInfo(); - if (m_spell->SpellFamilyName != SPELLFAMILY_WARLOCK || !(m_spell->SpellFamilyFlags[1] & 0x0004071B || m_spell->SpellFamilyFlags[0] & 0x8044C402)) + SpellInfo const* spell = aura->GetSpellInfo(); + if (spell->SpellFamilyName != SPELLFAMILY_WARLOCK || !(spell->SpellFamilyFlags[1] & 0x0004071B || spell->SpellFamilyFlags[0] & 0x8044C402)) continue; modPercent += stepPercent * aura->GetStackAmount(); if (modPercent >= maxPercent) @@ -10784,7 +10288,7 @@ uint32 Unit::SpellDamageBonusDone(Unit* victim, SpellInfo const* spellProto, uin return uint32(std::max(tmpDamage, 0.0f)); } -uint32 Unit::SpellDamageBonusTaken(Unit* caster, SpellInfo const* spellProto, uint32 pdamage, DamageEffectType damagetype, uint32 stack) +uint32 Unit::SpellDamageBonusTaken(Unit* caster, SpellInfo const* spellProto, uint32 pdamage, DamageEffectType damagetype, uint32 stack) const { if (!spellProto || damagetype == DIRECT_DAMAGE) return pdamage; @@ -10884,7 +10388,7 @@ uint32 Unit::SpellDamageBonusTaken(Unit* caster, SpellInfo const* spellProto, ui return uint32(std::max(tmpDamage, 0.0f)); } -int32 Unit::SpellBaseDamageBonusDone(SpellSchoolMask schoolMask) +int32 Unit::SpellBaseDamageBonusDone(SpellSchoolMask schoolMask) const { int32 DoneAdvertisedBenefit = 0; @@ -10923,7 +10427,7 @@ int32 Unit::SpellBaseDamageBonusDone(SpellSchoolMask schoolMask) return DoneAdvertisedBenefit; } -int32 Unit::SpellBaseDamageBonusTaken(SpellSchoolMask schoolMask) +int32 Unit::SpellBaseDamageBonusTaken(SpellSchoolMask schoolMask) const { int32 TakenAdvertisedBenefit = 0; @@ -11141,7 +10645,7 @@ uint32 Unit::SpellCriticalDamageBonus(SpellInfo const* spellProto, uint32 damage { case SPELL_DAMAGE_CLASS_MELEE: // for melee based spells is 100% case SPELL_DAMAGE_CLASS_RANGED: - // TODO: write here full calculation for melee/ranged spells + /// @todo write here full calculation for melee/ranged spells crit_bonus += damage; break; default: @@ -11179,7 +10683,7 @@ uint32 Unit::SpellCriticalHealingBonus(SpellInfo const* spellProto, uint32 damag { case SPELL_DAMAGE_CLASS_MELEE: // for melee based spells is 100% case SPELL_DAMAGE_CLASS_RANGED: - // TODO: write here full calculation for melee/ranged spells + /// @todo write here full calculation for melee/ranged spells crit_bonus = damage; break; default: @@ -11201,7 +10705,7 @@ uint32 Unit::SpellCriticalHealingBonus(SpellInfo const* spellProto, uint32 damag return damage; } -uint32 Unit::SpellHealingBonusDone(Unit* victim, SpellInfo const* spellProto, uint32 healamount, DamageEffectType damagetype, uint32 stack) +uint32 Unit::SpellHealingBonusDone(Unit* victim, SpellInfo const* spellProto, uint32 healamount, DamageEffectType damagetype, uint32 stack) const { // For totems get healing bonus from owner (statue isn't totem in fact) if (GetTypeId() == TYPEID_UNIT && isTotem()) @@ -11221,7 +10725,7 @@ uint32 Unit::SpellHealingBonusDone(Unit* victim, SpellInfo const* spellProto, ui AddPct(DoneTotalMod, (*i)->GetAmount()); // done scripted mod (take it from owner) - Unit* owner = GetOwner() ? GetOwner() : this; + Unit const* owner = GetOwner() ? GetOwner() : this; AuraEffectList const& mOverrideClassScript= owner->GetAuraEffectsByType(SPELL_AURA_OVERRIDE_CLASS_SCRIPTS); for (AuraEffectList::const_iterator i = mOverrideClassScript.begin(); i != mOverrideClassScript.end(); ++i) { @@ -11352,7 +10856,7 @@ uint32 Unit::SpellHealingBonusDone(Unit* victim, SpellInfo const* spellProto, ui return uint32(std::max(heal, 0.0f)); } -uint32 Unit::SpellHealingBonusTaken(Unit* caster, SpellInfo const* spellProto, uint32 healamount, DamageEffectType damagetype, uint32 stack) +uint32 Unit::SpellHealingBonusTaken(Unit* caster, SpellInfo const* spellProto, uint32 healamount, DamageEffectType damagetype, uint32 stack) const { float TakenTotalMod = 1.0f; @@ -11457,20 +10961,20 @@ uint32 Unit::SpellHealingBonusTaken(Unit* caster, SpellInfo const* spellProto, u return uint32(std::max(heal, 0.0f)); } -int32 Unit::SpellBaseHealingBonusDone(SpellSchoolMask schoolMask) +int32 Unit::SpellBaseHealingBonusDone(SpellSchoolMask schoolMask) const { - int32 AdvertisedBenefit = 0; + int32 advertisedBenefit = 0; AuraEffectList const& mHealingDone = GetAuraEffectsByType(SPELL_AURA_MOD_HEALING_DONE); for (AuraEffectList::const_iterator i = mHealingDone.begin(); i != mHealingDone.end(); ++i) if (!(*i)->GetMiscValue() || ((*i)->GetMiscValue() & schoolMask) != 0) - AdvertisedBenefit += (*i)->GetAmount(); + advertisedBenefit += (*i)->GetAmount(); // Healing bonus of spirit, intellect and strength if (GetTypeId() == TYPEID_PLAYER) { // Base value - AdvertisedBenefit += ToPlayer()->GetBaseSpellPowerBonus(); + advertisedBenefit += ToPlayer()->GetBaseSpellPowerBonus(); // Healing bonus from stats AuraEffectList const& mHealingDoneOfStatPercent = GetAuraEffectsByType(SPELL_AURA_MOD_SPELL_HEALING_OF_STAT_PERCENT); @@ -11478,31 +10982,31 @@ int32 Unit::SpellBaseHealingBonusDone(SpellSchoolMask schoolMask) { // stat used dependent from misc value (stat index) Stats usedStat = Stats((*i)->GetSpellInfo()->Effects[(*i)->GetEffIndex()].MiscValue); - AdvertisedBenefit += int32(CalculatePct(GetStat(usedStat), (*i)->GetAmount())); + advertisedBenefit += int32(CalculatePct(GetStat(usedStat), (*i)->GetAmount())); } // ... and attack power AuraEffectList const& mHealingDonebyAP = GetAuraEffectsByType(SPELL_AURA_MOD_SPELL_HEALING_OF_ATTACK_POWER); for (AuraEffectList::const_iterator i = mHealingDonebyAP.begin(); i != mHealingDonebyAP.end(); ++i) if ((*i)->GetMiscValue() & schoolMask) - AdvertisedBenefit += int32(CalculatePct(GetTotalAttackPowerValue(BASE_ATTACK), (*i)->GetAmount())); + advertisedBenefit += int32(CalculatePct(GetTotalAttackPowerValue(BASE_ATTACK), (*i)->GetAmount())); } - return AdvertisedBenefit; + return advertisedBenefit; } -int32 Unit::SpellBaseHealingBonusTaken(SpellSchoolMask schoolMask) +int32 Unit::SpellBaseHealingBonusTaken(SpellSchoolMask schoolMask) const { - int32 AdvertisedBenefit = 0; + int32 advertisedBenefit = 0; AuraEffectList const& mDamageTaken = GetAuraEffectsByType(SPELL_AURA_MOD_HEALING); for (AuraEffectList::const_iterator i = mDamageTaken.begin(); i != mDamageTaken.end(); ++i) if (((*i)->GetMiscValue() & schoolMask) != 0) - AdvertisedBenefit += (*i)->GetAmount(); + advertisedBenefit += (*i)->GetAmount(); - return AdvertisedBenefit; + return advertisedBenefit; } -bool Unit::IsImmunedToDamage(SpellSchoolMask shoolMask) +bool Unit::IsImmunedToDamage(SpellSchoolMask shoolMask) const { // If m_immuneToSchool type contain this school type, IMMUNE damage. SpellImmuneList const& schoolList = m_spellImmune[IMMUNITY_SCHOOL]; @@ -11519,7 +11023,7 @@ bool Unit::IsImmunedToDamage(SpellSchoolMask shoolMask) return false; } -bool Unit::IsImmunedToDamage(SpellInfo const* spellInfo) +bool Unit::IsImmunedToDamage(SpellInfo const* spellInfo) const { if (spellInfo->Attributes & SPELL_ATTR0_UNAFFECTED_BY_INVULNERABILITY) return false; @@ -11543,7 +11047,7 @@ bool Unit::IsImmunedToDamage(SpellInfo const* spellInfo) return false; } -bool Unit::IsImmunedToSpell(SpellInfo const* spellInfo) +bool Unit::IsImmunedToSpell(SpellInfo const* spellInfo) const { if (!spellInfo) return false; @@ -11842,7 +11346,7 @@ uint32 Unit::MeleeDamageBonusTaken(Unit* attacker, uint32 pdamage, WeaponAttackT // ..taken AuraEffectList const& mDamageTaken = GetAuraEffectsByType(SPELL_AURA_MOD_DAMAGE_TAKEN); for (AuraEffectList::const_iterator i = mDamageTaken.begin(); i != mDamageTaken.end(); ++i) - if ((*i)->GetMiscValue() & GetMeleeDamageSchoolMask()) + if ((*i)->GetMiscValue() & attacker->GetMeleeDamageSchoolMask()) TakenFlatBenefit += (*i)->GetAmount(); if (attType != RANGED_ATTACK) @@ -11854,7 +11358,7 @@ uint32 Unit::MeleeDamageBonusTaken(Unit* attacker, uint32 pdamage, WeaponAttackT float TakenTotalMod = 1.0f; // ..taken - TakenTotalMod *= GetTotalAuraMultiplierByMiscMask(SPELL_AURA_MOD_DAMAGE_PERCENT_TAKEN, GetMeleeDamageSchoolMask()); + TakenTotalMod *= GetTotalAuraMultiplierByMiscMask(SPELL_AURA_MOD_DAMAGE_PERCENT_TAKEN, attacker->GetMeleeDamageSchoolMask()); // .. taken pct (special attacks) if (spellProto) @@ -12037,8 +11541,6 @@ void Unit::Mount(uint32 mount, uint32 VehicleId, uint32 creatureEntry) { if (CreateVehicleKit(VehicleId, creatureEntry)) { - GetVehicleKit()->Reset(); - // Send others that we now have a vehicle WorldPacket data(SMSG_PLAYER_VEHICLE_DATA, GetPackGUID().size()+4); data.appendPackGUID(GetGUID()); @@ -12125,6 +11627,15 @@ void Unit::Dismount() } } +bool Unit::isServiceProvider() const +{ + return HasFlag(UNIT_NPC_FLAGS, + UNIT_NPC_FLAG_VENDOR | UNIT_NPC_FLAG_TRAINER | UNIT_NPC_FLAG_FLIGHTMASTER | + UNIT_NPC_FLAG_PETITIONER | UNIT_NPC_FLAG_BATTLEMASTER | UNIT_NPC_FLAG_BANKER | + UNIT_NPC_FLAG_INNKEEPER | UNIT_NPC_FLAG_SPIRITHEALER | + UNIT_NPC_FLAG_SPIRITGUIDE | UNIT_NPC_FLAG_TABARDDESIGNER | UNIT_NPC_FLAG_AUCTIONEER); +} + void Unit::SetInCombatWith(Unit* enemy) { Unit* eOwner = enemy->GetCharmerOrOwnerOrSelf(); @@ -12316,7 +11827,7 @@ bool Unit::_IsValidAttackTarget(Unit const* target, SpellInfo const* bySpell, Wo if (Player const* playerAttacker = ToPlayer()) { - if (playerAttacker->HasFlag(PLAYER_FLAGS, PLAYER_FLAGS_UNK19)) + if (playerAttacker->HasFlag(PLAYER_FLAGS, PLAYER_FLAGS_UBER)) return false; } // check flags @@ -12431,7 +11942,7 @@ bool Unit::_IsValidAssistTarget(Unit const* target, SpellInfo const* bySpell) co && target->HasFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE)) return false; - if (!bySpell || !(bySpell->AttributesEx6 & SPELL_ATTR6_UNK3)) + if (!bySpell || !(bySpell->AttributesEx6 & SPELL_ATTR6_ASSIST_IGNORE_IMMUNE_FLAG)) { if (HasFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_PVP_ATTACKABLE)) { @@ -12478,7 +11989,7 @@ bool Unit::_IsValidAssistTarget(Unit const* target, SpellInfo const* bySpell) co // PvC case - player can assist creature only if has specific type flags // !target->HasFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_PVP_ATTACKABLE) && else if (HasFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_PVP_ATTACKABLE) - && (!bySpell || !(bySpell->AttributesEx6 & SPELL_ATTR6_UNK3)) + && (!bySpell || !(bySpell->AttributesEx6 & SPELL_ATTR6_ASSIST_IGNORE_IMMUNE_FLAG)) && !((target->GetByteValue(UNIT_FIELD_BYTES_2, 1) & UNIT_BYTE2_FLAG_PVP))) { if (Creature const* creatureTarget = target->ToCreature()) @@ -12590,6 +12101,12 @@ int32 Unit::ModifyPowerPct(Powers power, float pct, bool apply) return ModifyPower(power, (int32)amount - (int32)GetMaxPower(power)); } +uint32 Unit::GetAttackTime(WeaponAttackType att) const +{ + float f_BaseAttackTime = GetFloatValue(UNIT_FIELD_BASEATTACKTIME+att) / m_modAttackSpeedPct[att]; + return (uint32)f_BaseAttackTime; +} + bool Unit::IsAlwaysVisibleFor(WorldObject const* seer) const { if (WorldObject::IsAlwaysVisibleFor(seer)) @@ -12620,6 +12137,11 @@ bool Unit::IsAlwaysDetectableFor(WorldObject const* seer) const return false; } +bool Unit::IsVisible() const +{ + return (m_serverSideVisibility.GetValue(SERVERSIDE_VISIBILITY_GM) > SEC_PLAYER) ? false : true; +} + void Unit::SetVisible(bool x) { if (!x) @@ -12735,7 +12257,7 @@ void Unit::UpdateSpeed(UnitMoveType mtype, bool forced) } // Normalize speed by 191 aura SPELL_AURA_USE_NORMAL_MOVEMENT_SPEED if need - // TODO: possible affect only on MOVE_RUN + /// @todo possible affect only on MOVE_RUN if (int32 normalization = GetMaxPositiveAuraModifier(SPELL_AURA_USE_NORMAL_MOVEMENT_SPEED)) { // Use speed from aura @@ -12897,6 +12419,9 @@ void Unit::setDeathState(DeathState s) if (IsNonMeleeSpellCasted(false)) InterruptNonMeleeSpells(false); + ExitVehicle(); // Exit vehicle before calling RemoveAllControlled + // vehicles use special type of charm that is not removed by the next function + // triggering an assert UnsummonAllTotems(); RemoveAllControlled(); RemoveAllAurasOnDeath(); @@ -13161,7 +12686,7 @@ Unit* Creature::SelectVictim() return NULL; } - // TODO: a vehicle may eat some mob, so mob should not evade + /// @todo a vehicle may eat some mob, so mob should not evade if (GetVehicle()) return NULL; @@ -13529,6 +13054,30 @@ uint32 Unit::GetCreatureType() const return ToCreature()->GetCreatureTemplate()->type; } +uint32 Unit::GetCreatureTypeMask() const +{ + uint32 creatureType = GetCreatureType(); + return (creatureType >= 1) ? (1 << (creatureType - 1)) : 0; +} + +void Unit::SetShapeshiftForm(ShapeshiftForm form) +{ + SetByteValue(UNIT_FIELD_BYTES_2, 3, form); +} + +bool Unit::IsInFeralForm() const +{ + ShapeshiftForm form = GetShapeshiftForm(); + return form == FORM_CAT || form == FORM_BEAR || form == FORM_DIREBEAR; +} + +bool Unit::IsInDisallowedMountForm() const +{ + ShapeshiftForm form = GetShapeshiftForm(); + return form != FORM_NONE && form != FORM_BATTLESTANCE && form != FORM_BERSERKERSTANCE && form != FORM_DEFENSIVESTANCE && + form != FORM_SHADOW && form != FORM_STEALTH && form != FORM_UNDEAD; +} + /*####################################### ######## ######## ######## STAT SYSTEM ######## @@ -13729,6 +13278,12 @@ float Unit::GetWeaponDamageRange(WeaponAttackType attType, WeaponDamageRange typ return m_weaponDamage[attType][type]; } +bool Unit::CanFreeMove() const +{ + return !HasUnitState(UNIT_STATE_CONFUSED | UNIT_STATE_FLEEING | UNIT_STATE_IN_FLIGHT | + UNIT_STATE_ROOT | UNIT_STATE_STUNNED | UNIT_STATE_DISTRACTED) && GetOwnerGUID() == 0; +} + void Unit::SetLevel(uint8 lvl) { SetUInt32Value(UNIT_FIELD_LEVEL, lvl); @@ -14452,7 +14007,8 @@ void Unit::ProcDamageAndSpellFor(bool isVictim, Unit* target, uint32 procFlag, u Unit* actionTarget = !isVictim ? target : this; DamageInfo damageInfo = DamageInfo(actor, actionTarget, damage, procSpell, procSpell ? SpellSchoolMask(procSpell->SchoolMask) : SPELL_SCHOOL_MASK_NORMAL, SPELL_DIRECT_DAMAGE); - ProcEventInfo eventInfo = ProcEventInfo(actor, actionTarget, target, procFlag, 0, 0, procExtra, NULL, &damageInfo, NULL /*HealInfo*/); + HealInfo healInfo = HealInfo(actor, actionTarget, damage, procSpell, procSpell ? SpellSchoolMask(procSpell->SchoolMask) : SPELL_SCHOOL_MASK_NORMAL); + ProcEventInfo eventInfo = ProcEventInfo(actor, actionTarget, target, procFlag, 0, 0, procExtra, NULL, &damageInfo, &healInfo); ProcTriggeredList procTriggered; // Fill procTriggered list @@ -14483,6 +14039,10 @@ void Unit::ProcDamageAndSpellFor(bool isVictim, Unit* target, uint32 procFlag, u if (!sConditionMgr->IsObjectMeetToConditions(condInfo, conditions)) continue; + // AuraScript Hook + if (!triggerData.aura->CallScriptCheckProcHandlers(itr->second, eventInfo)) + continue; + // Triggered spells not triggering additional spells bool triggered = !(spellProto->AttributesEx3 & SPELL_ATTR3_CAN_PROC_WITH_TRIGGERED) ? (procExtra & PROC_EX_INTERNAL_TRIGGERED && !(procFlag & PROC_FLAG_DONE_TRAP_ACTIVATION)) : false; @@ -14531,15 +14091,21 @@ void Unit::ProcDamageAndSpellFor(bool isVictim, Unit* target, uint32 procFlag, u SpellInfo const* spellInfo = i->aura->GetSpellInfo(); uint32 Id = i->aura->GetId(); + AuraApplication* aurApp = i->aura->GetApplicationOfTarget(GetGUID()); + + bool prepare = i->aura->CallScriptPrepareProcHandlers(aurApp, eventInfo); + // For players set spell cooldown if need uint32 cooldown = 0; - if (GetTypeId() == TYPEID_PLAYER && i->spellProcEvent && i->spellProcEvent->cooldown) + if (prepare && GetTypeId() == TYPEID_PLAYER && i->spellProcEvent && i->spellProcEvent->cooldown) cooldown = i->spellProcEvent->cooldown; // Note: must SetCantProc(false) before return if (spellInfo->AttributesEx3 & SPELL_ATTR3_DISABLE_PROC) SetCantProc(true); + i->aura->CallScriptProcHandlers(aurApp, eventInfo); + // This bool is needed till separate aura effect procs are still here bool handled = false; if (HandleAuraProc(target, damage, i->aura, procSpell, procFlag, procExtra, cooldown, &handled)) @@ -14558,6 +14124,13 @@ void Unit::ProcDamageAndSpellFor(bool isVictim, Unit* target, uint32 procFlag, u AuraEffect* triggeredByAura = i->aura->GetEffect(effIndex); ASSERT(triggeredByAura); + bool prevented = i->aura->CallScriptEffectProcHandlers(triggeredByAura, aurApp, eventInfo); + if (prevented) + { + takeCharges = true; + continue; + } + switch (triggeredByAura->GetAuraType()) { case SPELL_AURA_PROC_TRIGGER_SPELL: @@ -14571,17 +14144,10 @@ void Unit::ProcDamageAndSpellFor(bool isVictim, Unit* target, uint32 procFlag, u case SPELL_AURA_PROC_TRIGGER_DAMAGE: { // target has to be valid - if (!target) + if (!eventInfo.GetProcTarget()) break; - sLog->outDebug(LOG_FILTER_SPELLS_AURAS, "ProcDamageAndSpell: doing %u damage from spell id %u (triggered by %s aura of spell %u)", triggeredByAura->GetAmount(), spellInfo->Id, (isVictim?"a victim's":"an attacker's"), triggeredByAura->GetId()); - SpellNonMeleeDamage damageInfo(this, target, spellInfo->Id, spellInfo->SchoolMask); - uint32 newDamage = SpellDamageBonusDone(target, spellInfo, triggeredByAura->GetAmount(), SPELL_DIRECT_DAMAGE); - newDamage = target->SpellDamageBonusTaken(this, spellInfo, newDamage, SPELL_DIRECT_DAMAGE); - CalculateSpellDamageTaken(&damageInfo, newDamage, spellInfo); - DealDamageMods(damageInfo.target, damageInfo.damage, &damageInfo.absorb); - SendSpellNonMeleeDamageLog(&damageInfo); - DealSpellDamage(&damageInfo, true); + triggeredByAura->HandleProcTriggerDamageAuraProc(aurApp, eventInfo); // this function is part of the new proc system takeCharges = true; break; } @@ -14594,22 +14160,12 @@ void Unit::ProcDamageAndSpellFor(bool isVictim, Unit* target, uint32 procFlag, u break; } case SPELL_AURA_OBS_MOD_POWER: - sLog->outDebug(LOG_FILTER_SPELLS_AURAS, "ProcDamageAndSpell: casting spell id %u (triggered by %s aura of spell %u)", spellInfo->Id, (isVictim?"a victim's":"an attacker's"), triggeredByAura->GetId()); - if (HandleObsModEnergyAuraProc(target, damage, triggeredByAura, procSpell, procFlag, procExtra, cooldown)) - takeCharges = true; - break; + case SPELL_AURA_MOD_SPELL_CRIT_CHANCE: case SPELL_AURA_MOD_DAMAGE_PERCENT_TAKEN: - sLog->outDebug(LOG_FILTER_SPELLS_AURAS, "ProcDamageAndSpell: casting spell id %u (triggered by %s aura of spell %u)", spellInfo->Id, (isVictim?"a victim's":"an attacker's"), triggeredByAura->GetId()); - if (HandleModDamagePctTakenAuraProc(target, damage, triggeredByAura, procSpell, procFlag, procExtra, cooldown)) - takeCharges = true; - break; case SPELL_AURA_MOD_MELEE_HASTE: - { - sLog->outDebug(LOG_FILTER_SPELLS_AURAS, "ProcDamageAndSpell: casting spell id %u (triggered by %s haste aura of spell %u)", spellInfo->Id, (isVictim?"a victim's":"an attacker's"), triggeredByAura->GetId()); - if (HandleHasteAuraProc(target, damage, triggeredByAura, procSpell, procFlag, procExtra, cooldown)) - takeCharges = true; + sLog->outDebug(LOG_FILTER_SPELLS_AURAS, "ProcDamageAndSpell: casting spell id %u (triggered by %s aura of spell %u)", spellInfo->Id, isVictim ? "a victim's" : "an attacker's", triggeredByAura->GetId()); + takeCharges = true; break; - } case SPELL_AURA_OVERRIDE_CLASS_SCRIPTS: { sLog->outDebug(LOG_FILTER_SPELLS_AURAS, "ProcDamageAndSpell: casting spell id %u (triggered by %s aura of spell %u)", spellInfo->Id, (isVictim?"a victim's":"an attacker's"), triggeredByAura->GetId()); @@ -14681,11 +14237,6 @@ void Unit::ProcDamageAndSpellFor(bool isVictim, Unit* target, uint32 procFlag, u if (triggeredByAura->GetCasterGUID() == target->GetGUID()) takeCharges = true; break; - case SPELL_AURA_MOD_SPELL_CRIT_CHANCE: - sLog->outDebug(LOG_FILTER_SPELLS_AURAS, "ProcDamageAndSpell: casting spell id %u (triggered by %s spell crit chance aura of spell %u)", spellInfo->Id, (isVictim?"a victim's":"an attacker's"), triggeredByAura->GetId()); - if (procSpell && HandleSpellCritChanceAuraProc(target, damage, triggeredByAura, procSpell, procFlag, procExtra, cooldown)) - takeCharges = true; - break; // CC Auras which use their amount amount to drop // Are there any more auras which need this? case SPELL_AURA_MOD_CONFUSE: @@ -14725,13 +14276,16 @@ void Unit::ProcDamageAndSpellFor(bool isVictim, Unit* target, uint32 procFlag, u takeCharges = true; break; } // switch (triggeredByAura->GetAuraType()) + i->aura->CallScriptAfterEffectProcHandlers(triggeredByAura, aurApp, eventInfo); } // for (uint8 effIndex = 0; effIndex < MAX_SPELL_EFFECTS; ++effIndex) } // if (!handled) // Remove charge (aura can be removed by triggers) - if (useCharges && takeCharges) + if (prepare && useCharges && takeCharges) i->aura->DropCharge(); + i->aura->CallScriptAfterProcHandlers(aurApp, eventInfo); + if (spellInfo->AttributesEx3 & SPELL_ATTR3_DISABLE_PROC) SetCantProc(false); } @@ -14752,7 +14306,7 @@ void Unit::GetProcAurasTriggeredOnEvent(std::list<AuraApplication*>& aurasTrigge if (!(*itr)->GetRemoveMode()) if ((*itr)->GetBase()->IsProcTriggeredOnEvent(*itr, eventInfo)) { - (*itr)->GetBase()->PrepareProcToTrigger(); + (*itr)->GetBase()->PrepareProcToTrigger(*itr, eventInfo); aurasTriggeringProc.push_back(*itr); } } @@ -14764,7 +14318,7 @@ void Unit::GetProcAurasTriggeredOnEvent(std::list<AuraApplication*>& aurasTrigge { if (itr->second->GetBase()->IsProcTriggeredOnEvent(itr->second, eventInfo)) { - itr->second->GetBase()->PrepareProcToTrigger(); + itr->second->GetBase()->PrepareProcToTrigger(itr->second, eventInfo); aurasTriggeringProc.push_back(itr->second); } } @@ -14810,6 +14364,18 @@ SpellSchoolMask Unit::GetMeleeDamageSchoolMask() const return SPELL_SCHOOL_MASK_NORMAL; } +uint64 Unit::GetCharmerOrOwnerGUID() const +{ + return GetCharmerGUID() ? GetCharmerGUID() : GetOwnerGUID(); +} + +uint64 Unit::GetCharmerOrOwnerOrOwnGUID() const +{ + if (uint64 guid = GetCharmerOrOwnerGUID()) + return guid; + return GetGUID(); +} + Player* Unit::GetSpellModOwner() const { if (GetTypeId() == TYPEID_PLAYER) @@ -14885,8 +14451,8 @@ void Unit::StopMoving() if (!IsInWorld()) return; - Movement::MoveSplineInit init(*this); - init.MoveTo(GetPositionX(), GetPositionY(), GetPositionZMinusOffset()); + Movement::MoveSplineInit init(this); + init.MoveTo(GetPositionX(), GetPositionY(), GetPositionZMinusOffset(), false); init.SetFacing(GetOrientation()); init.Launch(); } @@ -15228,7 +14794,18 @@ void Unit::UpdateAuraForGroup(uint8 slot) } } -float Unit::CalculateDefaultCoefficient(SpellInfo const *spellInfo, DamageEffectType damagetype) const +void Unit::SetCantProc(bool apply) +{ + if (apply) + ++m_procDeep; + else + { + ASSERT(m_procDeep); + --m_procDeep; + } +} + +float Unit::CalculateDefaultCoefficient(SpellInfo const* spellInfo, DamageEffectType damagetype) const { // Damage over Time spells bonus calculation float DotFactor = 1.0f; @@ -15788,7 +15365,7 @@ void Unit::Kill(Unit* victim, bool durabilityLoss) { Map* instanceMap = creature->GetMap(); Player* creditedPlayer = GetCharmerOrOwnerPlayerOrPlayerItself(); - // TODO: do instance binding anyway if the charmer/owner is offline + /// @todo do instance binding anyway if the charmer/owner is offline if (instanceMap->IsDungeon() && creditedPlayer) { @@ -15860,6 +15437,15 @@ void Unit::Kill(Unit* victim, bool durabilityLoss) } } +float Unit::GetPositionZMinusOffset() const +{ + float offset = 0.0f; + if (HasUnitMovementFlag(MOVEMENTFLAG_HOVER)) + offset = GetFloatValue(UNIT_FIELD_HOVERHEIGHT); + + return GetPositionZ() - offset; +} + void Unit::SetControlled(bool apply, UnitState state) { if (apply) @@ -15906,15 +15492,32 @@ void Unit::SetControlled(bool apply, UnitState state) { switch (state) { - case UNIT_STATE_STUNNED: if (HasAuraType(SPELL_AURA_MOD_STUN)) return; - else SetStunned(false); break; - case UNIT_STATE_ROOT: if (HasAuraType(SPELL_AURA_MOD_ROOT) || GetVehicle()) return; - else SetRooted(false); break; - case UNIT_STATE_CONFUSED:if (HasAuraType(SPELL_AURA_MOD_CONFUSE)) return; - else SetConfused(false); break; - case UNIT_STATE_FLEEING: if (HasAuraType(SPELL_AURA_MOD_FEAR)) return; - else SetFeared(false); break; - default: return; + case UNIT_STATE_STUNNED: + if (HasAuraType(SPELL_AURA_MOD_STUN)) + return; + + SetStunned(false); + break; + case UNIT_STATE_ROOT: + if (HasAuraType(SPELL_AURA_MOD_ROOT) || GetVehicle()) + return; + + SetRooted(false); + break; + case UNIT_STATE_CONFUSED: + if (HasAuraType(SPELL_AURA_MOD_CONFUSE)) + return; + + SetConfused(false); + break; + case UNIT_STATE_FLEEING: + if (HasAuraType(SPELL_AURA_MOD_FEAR)) + return; + + SetFeared(false); + break; + default: + return; } ClearUnitState(state); @@ -16091,7 +15694,10 @@ bool Unit::SetCharmedBy(Unit* charmer, CharmType type, AuraApplication const* au // dismount players when charmed if (GetTypeId() == TYPEID_PLAYER) - Dismount(); + RemoveAurasByType(SPELL_AURA_MOUNTED); + + if (charmer->GetTypeId() == TYPEID_PLAYER) + charmer->RemoveAurasByType(SPELL_AURA_MOUNTED); ASSERT(type != CHARM_TYPE_POSSESS || charmer->GetTypeId() == TYPEID_PLAYER); ASSERT((type == CHARM_TYPE_VEHICLE) == IsVehicle()); @@ -16121,7 +15727,7 @@ bool Unit::SetCharmedBy(Unit* charmer, CharmType type, AuraApplication const* au } CastStop(); - CombatStop(); // TODO: CombatStop(true) may cause crash (interrupt spells) + CombatStop(); /// @todo CombatStop(true) may cause crash (interrupt spells) DeleteThreatList(); // Charmer stop charming @@ -16256,7 +15862,7 @@ void Unit::RemoveCharmedBy(Unit* charmer) type = CHARM_TYPE_CHARM; CastStop(); - CombatStop(); // TODO: CombatStop(true) may cause crash (interrupt spells) + CombatStop(); /// @todo CombatStop(true) may cause crash (interrupt spells) getHostileRefManager().deleteReferences(); DeleteThreatList(); Map* map = GetMap(); @@ -16364,6 +15970,11 @@ void Unit::RestoreFaction() } } +Unit* Unit::GetRedirectThreatTarget() +{ + return _redirectThreadInfo.GetTargetGUID() ? GetUnit(*this, _redirectThreadInfo.GetTargetGUID()) : NULL; +} + bool Unit::CreateVehicleKit(uint32 id, uint32 creatureEntry) { VehicleEntry const* vehInfo = sVehicleStore.LookupEntry(id); @@ -16392,6 +16003,11 @@ void Unit::RemoveVehicleKit() RemoveFlag(UNIT_NPC_FLAGS, UNIT_NPC_FLAG_PLAYER_VEHICLE); } +bool Unit::IsOnVehicle(const Unit* vehicle) const +{ + return m_vehicle && m_vehicle == vehicle->GetVehicleKit(); +} + Unit* Unit::GetVehicleBase() const { return m_vehicle ? m_vehicle->GetBase() : NULL; @@ -16498,6 +16114,22 @@ void Unit::GetPartyMembers(std::list<Unit*> &TagUnitMap) } } +bool Unit::IsContestedGuard() const +{ + if (FactionTemplateEntry const* entry = getFactionTemplateEntry()) + return entry->IsContestedGuardFaction(); + + return false; +} + +void Unit::SetPvP(bool state) +{ + if (state) + SetByteFlag(UNIT_FIELD_BYTES_2, 1, UNIT_BYTE2_FLAG_PVP); + else + RemoveByteFlag(UNIT_FIELD_BYTES_2, 1, UNIT_BYTE2_FLAG_PVP); +} + Aura* Unit::AddAura(uint32 spellId, Unit* target) { if (!target) @@ -17213,32 +16845,14 @@ void Unit::_EnterVehicle(Vehicle* vehicle, int8 seatId, AuraApplication const* a if (Player* player = ToPlayer()) { if (vehicle->GetBase()->GetTypeId() == TYPEID_PLAYER && player->isInCombat()) + { + vehicle->GetBase()->RemoveAura(const_cast<AuraApplication*>(aurApp)); return; - - InterruptNonMeleeSpells(false); - player->StopCastingCharm(); - player->StopCastingBindSight(); - Dismount(); - RemoveAurasByType(SPELL_AURA_MOUNTED); - - // drop flag at invisible in bg - if (Battleground* bg = player->GetBattleground()) - bg->EventPlayerDroppedFlag(player); - - WorldPacket data(SMSG_ON_CANCEL_EXPECTED_RIDE_VEHICLE_AURA, 0); - player->GetSession()->SendPacket(&data); - - player->UnsummonPetTemporaryIfAny(); + } } ASSERT(!m_vehicle); - m_vehicle = vehicle; - - if (!m_vehicle->AddPassenger(this, seatId)) - { - m_vehicle = NULL; - return; - } + (void)vehicle->AddPassenger(this, seatId); } void Unit::ChangeSeat(int8 seatId, bool next) @@ -17246,17 +16860,24 @@ void Unit::ChangeSeat(int8 seatId, bool next) if (!m_vehicle) return; - if (seatId < 0) - { - seatId = m_vehicle->GetNextEmptySeat(GetTransSeat(), next); - if (seatId < 0) - return; - } - else if (seatId == GetTransSeat() || !m_vehicle->HasEmptySeat(seatId)) + // Don't change if current and new seat are identical + if (seatId == GetTransSeat()) + return; + + SeatMap::const_iterator seat = (seatId < 0 ? m_vehicle->GetNextEmptySeat(GetTransSeat(), next) : m_vehicle->Seats.find(seatId)); + // The second part of the check will only return true if seatId >= 0. @Vehicle::GetNextEmptySeat makes sure of that. + if (seat == m_vehicle->Seats.end() || seat->second.Passenger) return; + // Todo: the functions below could be consolidated and refactored to take + // SeatMap::const_iterator as parameter, to save redundant map lookups. m_vehicle->RemovePassenger(this); - if (!m_vehicle->AddPassenger(this, seatId)) + + // Set m_vehicle to NULL before adding passenger as adding new passengers is handled asynchronously + // and someone may call ExitVehicle again before passenger is added to new seat + Vehicle* veh = m_vehicle; + m_vehicle = NULL; + if (!veh->AddPassenger(this, seatId)) ASSERT(false); } @@ -17281,6 +16902,9 @@ void Unit::ExitVehicle(Position const* /*exitPosition*/) void Unit::_ExitVehicle(Position const* exitPosition) { + /// It's possible m_vehicle is NULL, when this function is called indirectly from @VehicleJoinEvent::Abort. + /// In that case it was not possible to add the passenger to the vehicle. The vehicle aura has already been removed + /// from the target in the aforementioned function and we don't need to do anything else at this point. if (!m_vehicle) return; @@ -17288,7 +16912,7 @@ void Unit::_ExitVehicle(Position const* exitPosition) Player* player = ToPlayer(); - // If player is on mouted duel and exits the mount should immediatly lose the duel + // If the player is on mounted duel and exits the mount, he should immediatly lose the duel if (player && player->duel && player->duel->isMounted) player->DuelComplete(DUEL_FLED); @@ -17316,20 +16940,25 @@ void Unit::_ExitVehicle(Position const* exitPosition) SendMessageToSet(&data, false); } - Movement::MoveSplineInit init(*this); - init.MoveTo(pos.GetPositionX(), pos.GetPositionY(), pos.GetPositionZ()); + float height = pos.GetPositionZ(); + + Movement::MoveSplineInit init(this); + + // Creatures without inhabit type air should begin falling after exiting the vehicle + if (GetTypeId() == TYPEID_UNIT && !CanFly() && height > GetMap()->GetWaterOrGroundLevel(pos.GetPositionX(), pos.GetPositionY(), pos.GetPositionZ(), &height) + 0.1f) + init.SetFall(); + + init.MoveTo(pos.GetPositionX(), pos.GetPositionY(), height, false); init.SetFacing(GetOrientation()); init.SetTransportExit(); init.Launch(); - //GetMotionMaster()->MoveFall(); // Enable this once passenger positions are calculater properly (see above) - if (player) player->ResummonPetTemporaryUnSummonedIfAny(); - if (vehicle->GetBase()->HasUnitTypeMask(UNIT_MASK_MINION)) + if (vehicle->GetBase()->HasUnitTypeMask(UNIT_MASK_MINION) && vehicle->GetBase()->GetTypeId() == TYPEID_UNIT) if (((Minion*)vehicle->GetBase())->GetOwner() == this) - vehicle->Dismiss(); + vehicle->GetBase()->ToCreature()->DespawnOrUnsummon(); if (HasUnitTypeMask(UNIT_MASK_ACCESSORY)) { @@ -17466,6 +17095,11 @@ bool Unit::UpdatePosition(float x, float y, float z, float orientation, bool tel return (relocated || turn); } +bool Unit::UpdatePosition(const Position &pos, bool teleport) +{ + return UpdatePosition(pos.GetPositionX(), pos.GetPositionY(), pos.GetPositionZ(), pos.GetOrientation(), teleport); +} + //! Only server-side orientation update, does not broadcast to client void Unit::UpdateOrientation(float orientation) { @@ -17746,7 +17380,7 @@ bool CharmInfo::IsReturning() return _isReturning; } -void Unit::SetInFront(Unit const* target) +void Unit::SetInFront(WorldObject const* target) { if (!HasUnitState(UNIT_STATE_CANNOT_TURN)) SetOrientation(GetAngle(target)); @@ -17754,8 +17388,8 @@ void Unit::SetInFront(Unit const* target) void Unit::SetFacingTo(float ori) { - Movement::MoveSplineInit init(*this); - init.MoveTo(GetPositionX(), GetPositionY(), GetPositionZMinusOffset()); + Movement::MoveSplineInit init(this); + init.MoveTo(GetPositionX(), GetPositionY(), GetPositionZMinusOffset(), false); init.SetFacing(ori); init.Launch(); } @@ -17766,7 +17400,7 @@ void Unit::SetFacingToObject(WorldObject* object) if (!IsStopped()) return; - // TODO: figure out under what conditions creature will move towards object instead of facing it where it currently is. + /// @todo figure out under what conditions creature will move towards object instead of facing it where it currently is. SetFacingTo(GetAngle(object)); } @@ -17888,16 +17522,25 @@ void Unit::SendMovementCanFlyChange() SendMessageToSet(&data, false); } -void Unit::FocusTarget(Spell const* focusSpell, uint64 target) +void Unit::SetTarget(uint64 guid) +{ + if (!_focusSpell) + SetUInt64Value(UNIT_FIELD_TARGET, guid); +} + +void Unit::FocusTarget(Spell const* focusSpell, WorldObject const* target) { // already focused if (_focusSpell) return; _focusSpell = focusSpell; - SetUInt64Value(UNIT_FIELD_TARGET, target); + SetUInt64Value(UNIT_FIELD_TARGET, target->GetGUID()); if (focusSpell->GetSpellInfo()->AttributesEx5 & SPELL_ATTR5_DONT_TURN_DURING_CAST) AddUnitState(UNIT_STATE_ROTATING); + + // Set serverside orientation if needed (needs to be after attribute check) + SetInFront(target); } void Unit::ReleaseFocus(Spell const* focusSpell) diff --git a/src/server/game/Entities/Unit/Unit.h b/src/server/game/Entities/Unit/Unit.h index c714303e8c7..49df2659433 100644 --- a/src/server/game/Entities/Unit/Unit.h +++ b/src/server/game/Entities/Unit/Unit.h @@ -332,6 +332,7 @@ class UnitAI; class Totem; class Transport; class Vehicle; +class VehicleJoinEvent; class TransportBase; class SpellCastTargets; @@ -397,6 +398,7 @@ enum TriggerCastFlags TRIGGERED_IGNORE_CASTER_AURAS = 0x00010000, //! Will ignore caster aura restrictions or requirements TRIGGERED_DISALLOW_PROC_EVENTS = 0x00020000, //! Disallows proc events from triggered spell (default) TRIGGERED_DONT_REPORT_CAST_ERROR = 0x00040000, //! Will return SPELL_FAILED_DONT_REPORT in CheckCast functions + TRIGGERED_IGNORE_EQUIPPED_ITEM_REQUIREMENT = 0x00080000, //! Will ignore equipped item requirements TRIGGERED_FULL_MASK = 0xFFFFFFFF }; @@ -493,9 +495,10 @@ enum UnitState UNIT_STATE_FLEEING_MOVE = 0x02000000, UNIT_STATE_CHASE_MOVE = 0x04000000, UNIT_STATE_FOLLOW_MOVE = 0x08000000, + UNIT_STATE_IGNORE_PATHFINDING = 0x10000000, // do not use pathfinding in any MovementGenerator UNIT_STATE_UNATTACKABLE = (UNIT_STATE_IN_FLIGHT | UNIT_STATE_ONVEHICLE), // for real move using movegen check and stop (except unstoppable flight) - UNIT_STATE_MOVING = UNIT_STATE_ROAMING_MOVE | UNIT_STATE_CONFUSED_MOVE | UNIT_STATE_FLEEING_MOVE | UNIT_STATE_CHASE_MOVE | UNIT_STATE_FOLLOW_MOVE , + UNIT_STATE_MOVING = UNIT_STATE_ROAMING_MOVE | UNIT_STATE_CONFUSED_MOVE | UNIT_STATE_FLEEING_MOVE | UNIT_STATE_CHASE_MOVE | UNIT_STATE_FOLLOW_MOVE, UNIT_STATE_CONTROLLED = (UNIT_STATE_CONFUSED | UNIT_STATE_STUNNED | UNIT_STATE_FLEEING), UNIT_STATE_LOST_CONTROL = (UNIT_STATE_CONTROLLED | UNIT_STATE_JUMPING | UNIT_STATE_CHARGING), UNIT_STATE_SIGHTLESS = (UNIT_STATE_LOST_CONTROL | UNIT_STATE_EVADE), @@ -700,7 +703,7 @@ enum MovementFlags MOVEMENTFLAG_FALLING_SLOW = 0x20000000, // active rogue safe fall spell (passive) MOVEMENTFLAG_HOVER = 0x40000000, // hover, cannot jump - // TODO: Check if PITCH_UP and PITCH_DOWN really belong here.. + /// @todo Check if PITCH_UP and PITCH_DOWN really belong here.. MOVEMENTFLAG_MASK_MOVING = MOVEMENTFLAG_FORWARD | MOVEMENTFLAG_BACKWARD | MOVEMENTFLAG_STRAFE_LEFT | MOVEMENTFLAG_STRAFE_RIGHT | MOVEMENTFLAG_PITCH_UP | MOVEMENTFLAG_PITCH_DOWN | MOVEMENTFLAG_FALLING | MOVEMENTFLAG_FALLING_FAR | MOVEMENTFLAG_ASCENDING | MOVEMENTFLAG_DESCENDING | @@ -712,7 +715,7 @@ enum MovementFlags MOVEMENTFLAG_MASK_MOVING_FLY = MOVEMENTFLAG_FLYING | MOVEMENTFLAG_ASCENDING | MOVEMENTFLAG_DESCENDING, - //! TODO if needed: add more flags to this masks that are exclusive to players + /// @todo if needed: add more flags to this masks that are exclusive to players MOVEMENTFLAG_MASK_PLAYER_ONLY = MOVEMENTFLAG_FLYING }; @@ -756,16 +759,6 @@ namespace Movement{ class MoveSpline; } -enum DiminishingLevels -{ - DIMINISHING_LEVEL_1 = 0, - DIMINISHING_LEVEL_2 = 1, - DIMINISHING_LEVEL_3 = 2, - DIMINISHING_LEVEL_IMMUNE = 3, - DIMINISHING_LEVEL_4 = 3, - DIMINISHING_LEVEL_TAUNT_IMMUNE = 4 -}; - struct DiminishingReturn { DiminishingReturn(DiminishingGroup group, uint32 t, uint32 count) @@ -839,16 +832,16 @@ public: void ResistDamage(uint32 amount); void BlockDamage(uint32 amount); - Unit* GetAttacker() const { return m_attacker; }; - Unit* GetVictim() const { return m_victim; }; - SpellInfo const* GetSpellInfo() const { return m_spellInfo; }; - SpellSchoolMask GetSchoolMask() const { return m_schoolMask; }; - DamageEffectType GetDamageType() const { return m_damageType; }; - WeaponAttackType GetAttackType() const { return m_attackType; }; - uint32 GetDamage() const { return m_damage; }; - uint32 GetAbsorb() const { return m_absorb; }; - uint32 GetResist() const { return m_resist; }; - uint32 GetBlock() const { return m_block; }; + Unit* GetAttacker() const { return m_attacker; } + Unit* GetVictim() const { return m_victim; } + SpellInfo const* GetSpellInfo() const { return m_spellInfo; } + SpellSchoolMask GetSchoolMask() const { return m_schoolMask; } + DamageEffectType GetDamageType() const { return m_damageType; } + WeaponAttackType GetAttackType() const { return m_attackType; } + uint32 GetDamage() const { return m_damage; } + uint32 GetAbsorb() const { return m_absorb; } + uint32 GetResist() const { return m_resist; } + uint32 GetBlock() const { return m_block; } }; class HealInfo @@ -873,35 +866,42 @@ public: m_heal -= amount; } - uint32 GetHeal() const { return m_heal; }; + uint32 GetHeal() const { return m_heal; } }; class ProcEventInfo { -private: - Unit* const _actor; - Unit* const _actionTarget; - Unit* const _procTarget; - uint32 _typeMask; - uint32 _spellTypeMask; - uint32 _spellPhaseMask; - uint32 _hitMask; - Spell* _spell; - DamageInfo* _damageInfo; - HealInfo* _healInfo; public: - explicit ProcEventInfo(Unit* actor, Unit* actionTarget, Unit* procTarget, uint32 typeMask, uint32 spellTypeMask, uint32 spellPhaseMask, uint32 hitMask, Spell* spell, DamageInfo* damageInfo, HealInfo* healInfo); - Unit* GetActor() { return _actor; }; + ProcEventInfo(Unit* actor, Unit* actionTarget, Unit* procTarget, uint32 typeMask, + uint32 spellTypeMask, uint32 spellPhaseMask, uint32 hitMask, + Spell* spell, DamageInfo* damageInfo, HealInfo* healInfo); + + Unit* GetActor() { return _actor; } Unit* GetActionTarget() const { return _actionTarget; } Unit* GetProcTarget() const { return _procTarget; } + uint32 GetTypeMask() const { return _typeMask; } uint32 GetSpellTypeMask() const { return _spellTypeMask; } uint32 GetSpellPhaseMask() const { return _spellPhaseMask; } uint32 GetHitMask() const { return _hitMask; } + SpellInfo const* GetSpellInfo() const { return NULL; } SpellSchoolMask GetSchoolMask() const { return SPELL_SCHOOL_MASK_NONE; } + DamageInfo* GetDamageInfo() const { return _damageInfo; } HealInfo* GetHealInfo() const { return _healInfo; } + +private: + Unit* const _actor; + Unit* const _actionTarget; + Unit* const _procTarget; + uint32 _typeMask; + uint32 _spellTypeMask; + uint32 _spellPhaseMask; + uint32 _hitMask; + Spell* _spell; + DamageInfo* _damageInfo; + HealInfo* _healInfo; }; // Struct for use in Unit::CalculateMeleeDamage @@ -923,7 +923,7 @@ struct CalcDamageInfo uint32 procVictim; uint32 procEx; uint32 cleanDamage; // Used only for rage calculation - MeleeHitOutcome hitOutCome; // TODO: remove this field (need use TargetState) + MeleeHitOutcome hitOutCome; /// @todo remove this field (need use TargetState) }; // Spell damage info structure based on structure sending in SMSG_SPELLNONMELEEDAMAGELOG opcode @@ -965,6 +965,28 @@ struct SpellPeriodicAuraLogInfo uint32 createProcExtendMask(SpellNonMeleeDamage* damageInfo, SpellMissInfo missCondition); +struct RedirectThreatInfo +{ + RedirectThreatInfo() : _targetGUID(0), _threatPct(0) { } + uint64 _targetGUID; + uint32 _threatPct; + + uint64 GetTargetGUID() const { return _targetGUID; } + uint32 GetThreatPct() const { return _threatPct; } + + void Set(uint64 guid, uint32 pct) + { + _targetGUID = guid; + _threatPct = pct; + } + + void ModifyThreatPct(int32 amount) + { + amount += _threatPct; + _threatPct = uint32(std::max(0, amount)); + } +}; + #define MAX_DECLINED_NAME_CASES 5 struct DeclinedName @@ -1252,31 +1274,16 @@ class Unit : public WorldObject bool CanDualWield() const { return m_canDualWield; } void SetCanDualWield(bool value) { m_canDualWield = value; } float GetCombatReach() const { return m_floatValues[UNIT_FIELD_COMBATREACH]; } - float GetMeleeReach() const { float reach = m_floatValues[UNIT_FIELD_COMBATREACH]; return reach > MIN_MELEE_REACH ? reach : MIN_MELEE_REACH; } + float GetMeleeReach() const; bool IsWithinCombatRange(const Unit* obj, float dist2compare) const; bool IsWithinMeleeRange(const Unit* obj, float dist = MELEE_RANGE) const; void GetRandomContactPoint(const Unit* target, float &x, float &y, float &z, float distance2dMin, float distance2dMax) const; uint32 m_extraAttacks; bool m_canDualWield; - void _addAttacker(Unit* pAttacker) // must be called only from Unit::Attack(Unit*) - { - m_attackers.insert(pAttacker); - } - void _removeAttacker(Unit* pAttacker) // must be called only from Unit::AttackStop() - { - m_attackers.erase(pAttacker); - } - Unit* getAttackerForHelper() const // If someone wants to help, who to give them - { - if (getVictim() != NULL) - return getVictim(); - - if (!m_attackers.empty()) - return *(m_attackers.begin()); - - return NULL; - } + void _addAttacker(Unit* pAttacker); // must be called only from Unit::Attack(Unit*) + void _removeAttacker(Unit* pAttacker); // must be called only from Unit::AttackStop() + Unit* getAttackerForHelper() const; // If someone wants to help, who to give them bool Attack(Unit* victim, bool meleeAttack); void CastStop(uint32 except_spellid = 0); bool AttackStop(); @@ -1295,11 +1302,7 @@ class Unit : public WorldObject void AddUnitState(uint32 f) { m_state |= f; } bool HasUnitState(const uint32 f) const { return (m_state & f); } void ClearUnitState(uint32 f) { m_state &= ~f; } - bool CanFreeMove() const - { - return !HasUnitState(UNIT_STATE_CONFUSED | UNIT_STATE_FLEEING | UNIT_STATE_IN_FLIGHT | - UNIT_STATE_ROOT | UNIT_STATE_STUNNED | UNIT_STATE_DISTRACTED) && GetOwnerGUID() == 0; - } + bool CanFreeMove() const; uint32 HasUnitTypeMask(uint32 mask) const { return mask & m_unitTypeMask; } void AddUnitTypeMask(uint32 mask) { m_unitTypeMask |= mask; } @@ -1356,12 +1359,7 @@ class Unit : public WorldObject int32 ModifyPower(Powers power, int32 val); int32 ModifyPowerPct(Powers power, float pct, bool apply = true); - uint32 GetAttackTime(WeaponAttackType att) const - { - float f_BaseAttackTime = GetFloatValue(UNIT_FIELD_BASEATTACKTIME+att) / m_modAttackSpeedPct[att]; - return (uint32)f_BaseAttackTime; - } - + uint32 GetAttackTime(WeaponAttackType att) const; void SetAttackTime(WeaponAttackType att, uint32 val) { SetFloatValue(UNIT_FIELD_BASEATTACKTIME+att, val*m_modAttackSpeedPct[att]); } void ApplyAttackTimePercentMod(WeaponAttackType att, float val, bool apply); void ApplyCastTimePercentMod(float val, bool apply); @@ -1384,27 +1382,11 @@ class Unit : public WorldObject bool IsInPartyWith(Unit const* unit) const; bool IsInRaidWith(Unit const* unit) const; void GetPartyMembers(std::list<Unit*> &units); - bool IsContestedGuard() const - { - if (FactionTemplateEntry const* entry = getFactionTemplateEntry()) - return entry->IsContestedGuardFaction(); - - return false; - } + bool IsContestedGuard() const; bool IsPvP() const { return HasByteFlag(UNIT_FIELD_BYTES_2, 1, UNIT_BYTE2_FLAG_PVP); } - void SetPvP(bool state) - { - if (state) - SetByteFlag(UNIT_FIELD_BYTES_2, 1, UNIT_BYTE2_FLAG_PVP); - else - RemoveByteFlag(UNIT_FIELD_BYTES_2, 1, UNIT_BYTE2_FLAG_PVP); - } + void SetPvP(bool state); uint32 GetCreatureType() const; - uint32 GetCreatureTypeMask() const - { - uint32 creatureType = GetCreatureType(); - return (creatureType >= 1) ? (1 << (creatureType - 1)) : 0; - } + uint32 GetCreatureTypeMask() const; uint8 getStandState() const { return GetByteValue(UNIT_FIELD_BYTES_1, 0); } bool IsSitState() const; @@ -1471,33 +1453,11 @@ class Unit : public WorldObject float GetUnitMissChance(WeaponAttackType attType) const; float GetUnitCriticalChance(WeaponAttackType attackType, const Unit* victim) const; int32 GetMechanicResistChance(const SpellInfo* spell); - bool CanUseAttackType(uint8 attacktype) const - { - switch (attacktype) - { - case BASE_ATTACK: return !HasFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_DISARMED); - case OFF_ATTACK: return !HasFlag(UNIT_FIELD_FLAGS_2, UNIT_FLAG2_DISARM_OFFHAND); - case RANGED_ATTACK: return !HasFlag(UNIT_FIELD_FLAGS_2, UNIT_FLAG2_DISARM_RANGED); - } - return true; - } + bool CanUseAttackType(uint8 attacktype) const; virtual uint32 GetShieldBlockValue() const =0; - uint32 GetShieldBlockValue(uint32 soft_cap, uint32 hard_cap) const - { - uint32 value = GetShieldBlockValue(); - if (value >= hard_cap) - { - value = (soft_cap + hard_cap) / 2; - } - else if (value > soft_cap) - { - value = soft_cap + ((value - soft_cap) / 2); - } - - return value; - } - uint32 GetUnitMeleeSkill(Unit const* target = NULL) const { return (target ? getLevelForTarget(target) : getLevel()) * 5; } + uint32 GetShieldBlockValue(uint32 soft_cap, uint32 hard_cap) const; + uint32 GetUnitMeleeSkill(Unit const* target = NULL) const; uint32 GetDefenseSkillValue(Unit const* target = NULL) const; uint32 GetWeaponSkillValue(WeaponAttackType attType, Unit const* target = NULL) const; float GetWeaponProcChance() const; @@ -1520,14 +1480,7 @@ class Unit : public WorldObject bool isTabardDesigner()const { return HasFlag(UNIT_NPC_FLAGS, UNIT_NPC_FLAG_TABARDDESIGNER); } bool isAuctioner() const { return HasFlag(UNIT_NPC_FLAGS, UNIT_NPC_FLAG_AUCTIONEER); } bool isArmorer() const { return HasFlag(UNIT_NPC_FLAGS, UNIT_NPC_FLAG_REPAIR); } - bool isServiceProvider() const - { - return HasFlag(UNIT_NPC_FLAGS, - UNIT_NPC_FLAG_VENDOR | UNIT_NPC_FLAG_TRAINER | UNIT_NPC_FLAG_FLIGHTMASTER | - UNIT_NPC_FLAG_PETITIONER | UNIT_NPC_FLAG_BATTLEMASTER | UNIT_NPC_FLAG_BANKER | - UNIT_NPC_FLAG_INNKEEPER | UNIT_NPC_FLAG_SPIRITHEALER | - UNIT_NPC_FLAG_SPIRITGUIDE | UNIT_NPC_FLAG_TABARDDESIGNER | UNIT_NPC_FLAG_AUCTIONEER); - } + bool isServiceProvider() const; bool isSpiritService() const { return HasFlag(UNIT_NPC_FLAGS, UNIT_NPC_FLAG_SPIRITHEALER | UNIT_NPC_FLAG_SPIRITGUIDE); } bool isInFlight() const { return HasUnitState(UNIT_STATE_IN_FLIGHT); } @@ -1567,8 +1520,8 @@ class Unit : public WorldObject void SendHealSpellLog(Unit* victim, uint32 SpellID, uint32 Damage, uint32 OverHeal, uint32 Absorb, bool critical = false); int32 HealBySpell(Unit* victim, SpellInfo const* spellInfo, uint32 addHealth, bool critical = false); - void SendEnergizeSpellLog(Unit* victim, uint32 SpellID, uint32 Damage, Powers powertype); - void EnergizeBySpell(Unit* victim, uint32 SpellID, uint32 Damage, Powers powertype); + void SendEnergizeSpellLog(Unit* victim, uint32 spellID, int32 damage, Powers powerType); + void EnergizeBySpell(Unit* victim, uint32 SpellID, int32 Damage, Powers powertype); uint32 SpellNonMeleeDamageLog(Unit* victim, uint32 spellID, uint32 damage); void CastSpell(SpellCastTargets const& targets, SpellInfo const* spellInfo, CustomSpellValues const* value, TriggerCastFlags triggerFlags = TRIGGERED_NONE, Item* castItem = NULL, AuraEffect const* triggeredByAura = NULL, uint64 originalCaster = 0); @@ -1603,7 +1556,7 @@ class Unit : public WorldObject void SendTeleportPacket(Position& pos); virtual bool UpdatePosition(float x, float y, float z, float ang, bool teleport = false); // returns true if unit's position really changed - bool UpdatePosition(const Position &pos, bool teleport = false) { return UpdatePosition(pos.GetPositionX(), pos.GetPositionY(), pos.GetPositionZ(), pos.GetOrientation(), teleport); } + bool UpdatePosition(const Position &pos, bool teleport = false); void UpdateOrientation(float orientation); void UpdateHeight(float newZ); @@ -1611,7 +1564,7 @@ class Unit : public WorldObject void JumpTo(float speedXY, float speedZ, bool forward = true); void JumpTo(WorldObject* obj, float speedZ); - void MonsterMoveWithSpeed(float x, float y, float z, float speed); + void MonsterMoveWithSpeed(float x, float y, float z, float speed, bool generatePath = false, bool forceDestination = false); //void SetFacing(float ori, WorldObject* obj = NULL); //void SendMonsterMove(float NewPosX, float NewPosY, float NewPosZ, uint8 type, uint32 MovementFlags, uint32 Time, Player* player = NULL); void SendMovementFlagUpdate(bool self = false); @@ -1633,7 +1586,7 @@ class Unit : public WorldObject virtual bool SetDisableGravity(bool disable, bool packetOnly = false); virtual bool SetHover(bool enable); - void SetInFront(Unit const* target); + void SetInFront(WorldObject const* target); void SetFacingTo(float ori); void SetFacingToObject(WorldObject* object); @@ -1646,10 +1599,10 @@ class Unit : public WorldObject void BuildHeartBeatMsg(WorldPacket* data) const; - bool isAlive() const { return (m_deathState == ALIVE); }; - bool isDying() const { return (m_deathState == JUST_DIED); }; - bool isDead() const { return (m_deathState == DEAD || m_deathState == CORPSE); }; - DeathState getDeathState() { return m_deathState; }; + bool isAlive() const { return (m_deathState == ALIVE); } + bool isDying() const { return (m_deathState == JUST_DIED); } + bool isDead() const { return (m_deathState == DEAD || m_deathState == CORPSE); } + DeathState getDeathState() const { return m_deathState; } virtual void setDeathState(DeathState s); // overwrited in Creature/Player/Pet uint64 GetOwnerGUID() const { return GetUInt64Value(UNIT_FIELD_SUMMONEDBY); } @@ -1667,13 +1620,8 @@ class Unit : public WorldObject uint64 GetCritterGUID() const { return GetUInt64Value(UNIT_FIELD_CRITTER); } bool IsControlledByPlayer() const { return m_ControlledByPlayer; } - uint64 GetCharmerOrOwnerGUID() const { return GetCharmerGUID() ? GetCharmerGUID() : GetOwnerGUID(); } - uint64 GetCharmerOrOwnerOrOwnGUID() const - { - if (uint64 guid = GetCharmerOrOwnerGUID()) - return guid; - return GetGUID(); - } + uint64 GetCharmerOrOwnerGUID() const; + uint64 GetCharmerOrOwnerOrOwnGUID() const; bool isCharmedOwnedByPlayerOrPlayer() const { return IS_PLAYER_GUID(GetCharmerOrOwnerOrOwnGUID()); } Player* GetSpellModOwner() const; @@ -1683,14 +1631,8 @@ class Unit : public WorldObject Minion *GetFirstMinion() const; Unit* GetCharmer() const; Unit* GetCharm() const; - Unit* GetCharmerOrOwner() const { return GetCharmerGUID() ? GetCharmer() : GetOwner(); } - Unit* GetCharmerOrOwnerOrSelf() const - { - if (Unit* u = GetCharmerOrOwner()) - return u; - - return (Unit*)this; - } + Unit* GetCharmerOrOwner() const; + Unit* GetCharmerOrOwnerOrSelf() const; Player* GetCharmerOrOwnerPlayerOrPlayerItself() const; Player* GetAffectingPlayer() const; @@ -1709,15 +1651,9 @@ class Unit : public WorldObject bool isCharmed() const { return GetCharmerGUID() != 0; } bool isPossessed() const { return HasUnitState(UNIT_STATE_POSSESSED); } - bool isPossessedByPlayer() const { return HasUnitState(UNIT_STATE_POSSESSED) && IS_PLAYER_GUID(GetCharmerGUID()); } - bool isPossessing() const - { - if (Unit* u = GetCharm()) - return u->isPossessed(); - else - return false; - } - bool isPossessing(Unit* u) const { return u->isPossessed() && GetCharmGUID() == u->GetGUID(); } + bool isPossessedByPlayer() const; + bool isPossessing() const; + bool isPossessing(Unit* u) const; CharmInfo* GetCharmInfo() { return m_charmInfo; } CharmInfo* InitCharmInfo(); @@ -1799,8 +1735,8 @@ class Unit : public WorldObject AuraEffect* GetAuraEffect(uint32 spellId, uint8 effIndex, uint64 casterGUID = 0) const; AuraEffect* GetAuraEffectOfRankedSpell(uint32 spellId, uint8 effIndex, uint64 casterGUID = 0) const; AuraEffect* GetAuraEffect(AuraType type, SpellFamilyNames name, uint32 iconId, uint8 effIndex) const; // spell mustn't have familyflags - AuraEffect* GetAuraEffect(AuraType type, SpellFamilyNames family, uint32 familyFlag1, uint32 familyFlag2, uint32 familyFlag3, uint64 casterGUID =0); - inline AuraEffect* GetDummyAuraEffect(SpellFamilyNames name, uint32 iconId, uint8 effIndex) const { return GetAuraEffect(SPELL_AURA_DUMMY, name, iconId, effIndex);} + AuraEffect* GetAuraEffect(AuraType type, SpellFamilyNames family, uint32 familyFlag1, uint32 familyFlag2, uint32 familyFlag3, uint64 casterGUID =0) const; + AuraEffect* GetDummyAuraEffect(SpellFamilyNames name, uint32 iconId, uint8 effIndex) const; AuraApplication * GetAuraApplication(uint32 spellId, uint64 casterGUID = 0, uint64 itemCasterGUID = 0, uint8 reqEffMask = 0, AuraApplication * except = NULL) const; Aura* GetAura(uint32 spellId, uint64 casterGUID = 0, uint64 itemCasterGUID = 0, uint8 reqEffMask = 0) const; @@ -1828,7 +1764,7 @@ class Unit : public WorldObject int32 GetTotalAuraModifier(AuraType auratype) const; float GetTotalAuraMultiplier(AuraType auratype) const; - int32 GetMaxPositiveAuraModifier(AuraType auratype); + int32 GetMaxPositiveAuraModifier(AuraType auratype) const; int32 GetMaxNegativeAuraModifier(AuraType auratype) const; int32 GetTotalAuraModifierByMiscMask(AuraType auratype, uint32 misc_mask) const; @@ -1846,21 +1782,13 @@ class Unit : public WorldObject int32 GetMaxPositiveAuraModifierByAffectMask(AuraType auratype, SpellInfo const* affectedSpell) const; int32 GetMaxNegativeAuraModifierByAffectMask(AuraType auratype, SpellInfo const* affectedSpell) const; - float GetResistanceBuffMods(SpellSchools school, bool positive) const { return GetFloatValue(positive ? UNIT_FIELD_RESISTANCEBUFFMODSPOSITIVE+school : UNIT_FIELD_RESISTANCEBUFFMODSNEGATIVE+school); } - void SetResistanceBuffMods(SpellSchools school, bool positive, float val) { SetFloatValue(positive ? UNIT_FIELD_RESISTANCEBUFFMODSPOSITIVE+school : UNIT_FIELD_RESISTANCEBUFFMODSNEGATIVE+school, val); } - void ApplyResistanceBuffModsMod(SpellSchools school, bool positive, float val, bool apply) { ApplyModSignedFloatValue(positive ? UNIT_FIELD_RESISTANCEBUFFMODSPOSITIVE+school : UNIT_FIELD_RESISTANCEBUFFMODSNEGATIVE+school, val, apply); } - void ApplyResistanceBuffModsPercentMod(SpellSchools school, bool positive, float val, bool apply) { ApplyPercentModFloatValue(positive ? UNIT_FIELD_RESISTANCEBUFFMODSPOSITIVE+school : UNIT_FIELD_RESISTANCEBUFFMODSNEGATIVE+school, val, apply); } - void InitStatBuffMods() - { - for (uint8 i = STAT_STRENGTH; i < MAX_STATS; ++i) SetFloatValue(UNIT_FIELD_POSSTAT0+i, 0); - for (uint8 i = STAT_STRENGTH; i < MAX_STATS; ++i) SetFloatValue(UNIT_FIELD_NEGSTAT0+i, 0); - } - void ApplyStatBuffMod(Stats stat, float val, bool apply) { ApplyModSignedFloatValue((val > 0 ? UNIT_FIELD_POSSTAT0+stat : UNIT_FIELD_NEGSTAT0+stat), val, apply); } - void ApplyStatPercentBuffMod(Stats stat, float val, bool apply) - { - ApplyPercentModFloatValue(UNIT_FIELD_POSSTAT0+stat, val, apply); - ApplyPercentModFloatValue(UNIT_FIELD_NEGSTAT0+stat, val, apply); - } + float GetResistanceBuffMods(SpellSchools school, bool positive) const; + void SetResistanceBuffMods(SpellSchools school, bool positive, float val); + void ApplyResistanceBuffModsMod(SpellSchools school, bool positive, float val, bool apply); + void ApplyResistanceBuffModsPercentMod(SpellSchools school, bool positive, float val, bool apply); + void InitStatBuffMods(); + void ApplyStatBuffMod(Stats stat, float val, bool apply); + void ApplyStatPercentBuffMod(Stats stat, float val, bool apply); void SetCreateStat(Stats stat, float val) { m_createStats[stat] = val; } void SetCreateHealth(uint32 val) { SetUInt32Value(UNIT_FIELD_BASE_HEALTH, val); } uint32 GetCreateHealth() const { return GetUInt32Value(UNIT_FIELD_BASE_HEALTH); } @@ -1895,23 +1823,11 @@ class Unit : public WorldObject uint64 m_ObjectSlot[MAX_GAMEOBJECT_SLOT]; ShapeshiftForm GetShapeshiftForm() const { return ShapeshiftForm(GetByteValue(UNIT_FIELD_BYTES_2, 3)); } - void SetShapeshiftForm(ShapeshiftForm form) - { - SetByteValue(UNIT_FIELD_BYTES_2, 3, form); - } + void SetShapeshiftForm(ShapeshiftForm form); - inline bool IsInFeralForm() const - { - ShapeshiftForm form = GetShapeshiftForm(); - return form == FORM_CAT || form == FORM_BEAR || form == FORM_DIREBEAR; - } + bool IsInFeralForm() const; - inline bool IsInDisallowedMountForm() const - { - ShapeshiftForm form = GetShapeshiftForm(); - return form != FORM_NONE && form != FORM_BATTLESTANCE && form != FORM_BERSERKERSTANCE && form != FORM_DEFENSIVESTANCE && - form != FORM_SHADOW && form != FORM_STEALTH && form != FORM_UNDEAD; - } + bool IsInDisallowedMountForm() const; float m_modMeleeHitChance; float m_modRangedHitChance; @@ -1951,7 +1867,7 @@ class Unit : public WorldObject bool isInBackInMap(Unit const* target, float distance, float arc = M_PI) const; // Visibility system - bool IsVisible() const { return (m_serverSideVisibility.GetValue(SERVERSIDE_VISIBILITY_GM) > SEC_PLAYER) ? false : true; } + bool IsVisible() const; void SetVisible(bool x); // common function for visibility checks for player/creatures with detection code @@ -1974,23 +1890,17 @@ class Unit : public WorldObject HostileRefManager& getHostileRefManager() { return m_HostileRefManager; } VisibleAuraMap const* GetVisibleAuras() { return &m_visibleAuras; } - AuraApplication * GetVisibleAura(uint8 slot) - { - VisibleAuraMap::iterator itr = m_visibleAuras.find(slot); - if (itr != m_visibleAuras.end()) - return itr->second; - return 0; - } - void SetVisibleAura(uint8 slot, AuraApplication * aur){ m_visibleAuras[slot]=aur; UpdateAuraForGroup(slot);} - void RemoveVisibleAura(uint8 slot){ m_visibleAuras.erase(slot); UpdateAuraForGroup(slot);} + AuraApplication * GetVisibleAura(uint8 slot) const; + void SetVisibleAura(uint8 slot, AuraApplication * aur); + void RemoveVisibleAura(uint8 slot); uint32 GetInterruptMask() const { return m_interruptMask; } void AddInterruptMask(uint32 mask) { m_interruptMask |= mask; } void UpdateInterruptMask(); - uint32 GetDisplayId() { return GetUInt32Value(UNIT_FIELD_DISPLAYID); } + uint32 GetDisplayId() const { return GetUInt32Value(UNIT_FIELD_DISPLAYID); } void SetDisplayId(uint32 modelId); - uint32 GetNativeDisplayId() { return GetUInt32Value(UNIT_FIELD_NATIVEDISPLAYID); } + uint32 GetNativeDisplayId() const { return GetUInt32Value(UNIT_FIELD_NATIVEDISPLAYID); } void RestoreDisplayId(); void SetNativeDisplayId(uint32 modelId) { SetUInt32Value(UNIT_FIELD_NATIVEDISPLAYID, modelId); } void setTransForm(uint32 spellid) { m_transform = spellid;} @@ -2018,17 +1928,17 @@ class Unit : public WorldObject Unit* GetMagicHitRedirectTarget(Unit* victim, SpellInfo const* spellInfo); Unit* GetMeleeHitRedirectTarget(Unit* victim, SpellInfo const* spellInfo = NULL); - int32 SpellBaseDamageBonusDone(SpellSchoolMask schoolMask); - int32 SpellBaseDamageBonusTaken(SpellSchoolMask schoolMask); - uint32 SpellDamageBonusDone(Unit* victim, SpellInfo const *spellProto, uint32 pdamage, DamageEffectType damagetype, uint32 stack = 1); - uint32 SpellDamageBonusTaken(Unit* caster, SpellInfo const *spellProto, uint32 pdamage, DamageEffectType damagetype, uint32 stack = 1); - int32 SpellBaseHealingBonusDone(SpellSchoolMask schoolMask); - int32 SpellBaseHealingBonusTaken(SpellSchoolMask schoolMask); - uint32 SpellHealingBonusDone(Unit* victim, SpellInfo const *spellProto, uint32 healamount, DamageEffectType damagetype, uint32 stack = 1); - uint32 SpellHealingBonusTaken(Unit* caster, SpellInfo const *spellProto, uint32 healamount, DamageEffectType damagetype, uint32 stack = 1); + int32 SpellBaseDamageBonusDone(SpellSchoolMask schoolMask) const; + int32 SpellBaseDamageBonusTaken(SpellSchoolMask schoolMask) const; + uint32 SpellDamageBonusDone(Unit* victim, SpellInfo const* spellProto, uint32 pdamage, DamageEffectType damagetype, uint32 stack = 1) const; + uint32 SpellDamageBonusTaken(Unit* caster, SpellInfo const* spellProto, uint32 pdamage, DamageEffectType damagetype, uint32 stack = 1) const; + int32 SpellBaseHealingBonusDone(SpellSchoolMask schoolMask) const; + int32 SpellBaseHealingBonusTaken(SpellSchoolMask schoolMask) const; + uint32 SpellHealingBonusDone(Unit* victim, SpellInfo const* spellProto, uint32 healamount, DamageEffectType damagetype, uint32 stack = 1) const; + uint32 SpellHealingBonusTaken(Unit* caster, SpellInfo const* spellProto, uint32 healamount, DamageEffectType damagetype, uint32 stack = 1) const; - uint32 MeleeDamageBonusDone(Unit *pVictim, uint32 damage, WeaponAttackType attType, SpellInfo const *spellProto = NULL); - uint32 MeleeDamageBonusTaken(Unit* attacker, uint32 pdamage,WeaponAttackType attType, SpellInfo const *spellProto = NULL); + uint32 MeleeDamageBonusDone(Unit* pVictim, uint32 damage, WeaponAttackType attType, SpellInfo const* spellProto = NULL); + uint32 MeleeDamageBonusTaken(Unit* attacker, uint32 pdamage, WeaponAttackType attType, SpellInfo const* spellProto = NULL); bool isSpellBlocked(Unit* victim, SpellInfo const* spellProto, WeaponAttackType attackType = BASE_ATTACK); @@ -2043,16 +1953,16 @@ class Unit : public WorldObject void SetContestedPvP(Player* attackedPlayer = NULL); uint32 GetCastingTimeForBonus(SpellInfo const* spellProto, DamageEffectType damagetype, uint32 CastingTime) const; - float CalculateDefaultCoefficient(SpellInfo const *spellInfo, DamageEffectType damagetype) const; + float CalculateDefaultCoefficient(SpellInfo const* spellInfo, DamageEffectType damagetype) const; uint32 GetRemainingPeriodicAmount(uint64 caster, uint32 spellId, AuraType auraType, uint8 effectIndex = 0) const; void ApplySpellImmune(uint32 spellId, uint32 op, uint32 type, bool apply); void ApplySpellDispelImmunity(const SpellInfo* spellProto, DispelType type, bool apply); - virtual bool IsImmunedToSpell(SpellInfo const* spellInfo); + virtual bool IsImmunedToSpell(SpellInfo const* spellInfo) const; // redefined in Creature - bool IsImmunedToDamage(SpellSchoolMask meleeSchoolMask); - bool IsImmunedToDamage(SpellInfo const* spellInfo); + bool IsImmunedToDamage(SpellSchoolMask meleeSchoolMask) const; + bool IsImmunedToDamage(SpellInfo const* spellInfo) const; virtual bool IsImmunedToSpellEffect(SpellInfo const* spellInfo, uint32 index) const; // redefined in Creature static bool IsDamageReducedByArmor(SpellSchoolMask damageSchoolMask, SpellInfo const* spellInfo = NULL, uint8 effIndex = MAX_SPELL_EFFECTS); @@ -2099,14 +2009,7 @@ class Unit : public WorldObject uint16 GetExtraUnitMovementFlags() const { return m_movementInfo.flags2; } void SetExtraUnitMovementFlags(uint16 f) { m_movementInfo.flags2 = f; } - float GetPositionZMinusOffset() const - { - float offset = 0.0f; - if (HasUnitMovementFlag(MOVEMENTFLAG_HOVER)) - offset = GetFloatValue(UNIT_FIELD_HOVERHEIGHT); - - return GetPositionZ() - offset; - } + float GetPositionZMinusOffset() const; void SetControlled(bool apply, UnitState state); @@ -2132,17 +2035,8 @@ class Unit : public WorldObject void UpdateAuraForGroup(uint8 slot); // proc trigger system - bool CanProc(){return !m_procDeep;} - void SetCantProc(bool apply) - { - if (apply) - ++m_procDeep; - else - { - ASSERT(m_procDeep); - --m_procDeep; - } - } + bool CanProc() const {return !m_procDeep;} + void SetCantProc(bool apply); // pet auras typedef std::set<PetAura const*> PetAuraSet; @@ -2153,20 +2047,20 @@ class Unit : public WorldObject uint32 GetModelForForm(ShapeshiftForm form) const; uint32 GetModelForTotem(PlayerTotemType totemType); - void SetReducedThreatPercent(uint32 pct, uint64 guid) - { - m_reducedThreatPercent = pct; - m_misdirectionTargetGUID = guid; - } - uint32 GetReducedThreatPercent() { return m_reducedThreatPercent; } - Unit* GetMisdirectionTarget() { return m_misdirectionTargetGUID ? GetUnit(*this, m_misdirectionTargetGUID) : NULL; } + // Redirect Threat + void SetRedirectThreat(uint64 guid, uint32 pct) { _redirectThreadInfo.Set(guid, pct); } + void ResetRedirectThreat() { SetRedirectThreat(0, 0); } + void ModifyRedirectThreat(int32 amount) { _redirectThreadInfo.ModifyThreatPct(amount); } + uint32 GetRedirectThreatPercent() const { return _redirectThreadInfo.GetThreatPct(); } + Unit* GetRedirectThreatTarget(); + friend class VehicleJoinEvent; bool IsAIEnabled, NeedChangeAI; bool CreateVehicleKit(uint32 id, uint32 creatureEntry); void RemoveVehicleKit(); Vehicle* GetVehicleKit()const { return m_vehicleKit; } Vehicle* GetVehicle() const { return m_vehicle; } - bool IsOnVehicle(const Unit* vehicle) const { return m_vehicle && m_vehicle == vehicle->GetVehicleKit(); } + bool IsOnVehicle(const Unit* vehicle) const; Unit* GetVehicleBase() const; Creature* GetVehicleCreatureBase() const; float GetTransOffsetX() const { return m_movementInfo.t_pos.GetPositionX(); } @@ -2206,19 +2100,19 @@ class Unit : public WorldObject virtual bool isBeingLoaded() const { return false;} bool IsDuringRemoveFromWorld() const {return m_duringRemoveFromWorld;} - Pet* ToPet(){ if (isPet()) return reinterpret_cast<Pet*>(this); else return NULL; } - Totem* ToTotem(){ if (isTotem()) return reinterpret_cast<Totem*>(this); else return NULL; } + Pet* ToPet() { if (isPet()) return reinterpret_cast<Pet*>(this); else return NULL; } + Pet const* ToPet() const { if (isPet()) return reinterpret_cast<Pet const*>(this); else return NULL; } + + Totem* ToTotem() { if (isTotem()) return reinterpret_cast<Totem*>(this); else return NULL; } + Totem const* ToTotem() const { if (isTotem()) return reinterpret_cast<Totem const*>(this); else return NULL; } + TempSummon* ToTempSummon() { if (isSummon()) return reinterpret_cast<TempSummon*>(this); else return NULL; } - const TempSummon* ToTempSummon() const { if (isSummon()) return reinterpret_cast<const TempSummon*>(this); else return NULL; } + TempSummon const* ToTempSummon() const { if (isSummon()) return reinterpret_cast<TempSummon const*>(this); else return NULL; } - void SetTarget(uint64 guid) - { - if (!_focusSpell) - SetUInt64Value(UNIT_FIELD_TARGET, guid); - } + void SetTarget(uint64 guid); // Handling caster facing during spellcast - void FocusTarget(Spell const* focusSpell, uint64 target); + void FocusTarget(Spell const* focusSpell, WorldObject const* target); void ReleaseFocus(Spell const* focusSpell); // Movement info @@ -2305,10 +2199,6 @@ class Unit : public WorldObject private: bool IsTriggeredAtSpellProcEvent(Unit* victim, Aura* aura, SpellInfo const* procSpell, uint32 procFlag, uint32 procExtra, WeaponAttackType attType, bool isVictim, bool active, SpellProcEventEntry const* & spellProcEvent); bool HandleDummyAuraProc(Unit* victim, uint32 damage, AuraEffect* triggeredByAura, SpellInfo const* procSpell, uint32 procFlag, uint32 procEx, uint32 cooldown); - bool HandleHasteAuraProc(Unit* victim, uint32 damage, AuraEffect* triggeredByAura, SpellInfo const* procSpell, uint32 procFlag, uint32 procEx, uint32 cooldown); - bool HandleSpellCritChanceAuraProc(Unit* victim, uint32 damage, AuraEffect* triggredByAura, SpellInfo const* procSpell, uint32 procFlag, uint32 procEx, uint32 cooldown); - bool HandleObsModEnergyAuraProc(Unit* victim, uint32 damage, AuraEffect* triggeredByAura, SpellInfo const* procSpell, uint32 procFlag, uint32 procEx, uint32 cooldown); - bool HandleModDamagePctTakenAuraProc(Unit* victim, uint32 damage, AuraEffect* triggeredByAura, SpellInfo const* procSpell, uint32 procFlag, uint32 procEx, uint32 cooldown); bool HandleAuraProc(Unit* victim, uint32 damage, Aura* triggeredByAura, SpellInfo const* procSpell, uint32 procFlag, uint32 procEx, uint32 cooldown, bool * handled); bool HandleProcTriggerSpell(Unit* victim, uint32 damage, AuraEffect* triggeredByAura, SpellInfo const* procSpell, uint32 procFlag, uint32 procEx, uint32 cooldown); bool HandleOverrideClassScriptAuraProc(Unit* victim, uint32 damage, AuraEffect* triggeredByAura, SpellInfo const* procSpell, uint32 cooldown); @@ -2341,8 +2231,7 @@ class Unit : public WorldObject ComboPointHolderSet m_ComboPointHolders; - uint32 m_reducedThreatPercent; - uint64 m_misdirectionTargetGUID; + RedirectThreatInfo _redirectThreadInfo; bool m_cleanupDone; // lock made to not add stuff after cleanup before delete bool m_duringRemoveFromWorld; // lock made to not add stuff after begining removing from world diff --git a/src/server/game/Entities/Vehicle/Vehicle.cpp b/src/server/game/Entities/Vehicle/Vehicle.cpp index a3be443d014..fad9115ee3d 100644..100755 --- a/src/server/game/Entities/Vehicle/Vehicle.cpp +++ b/src/server/game/Entities/Vehicle/Vehicle.cpp @@ -30,9 +30,12 @@ #include "SpellInfo.h" #include "MoveSplineInit.h" #include "TemporarySummon.h" +#include "EventProcessor.h" +#include "Player.h" +#include "Battleground.h" Vehicle::Vehicle(Unit* unit, VehicleEntry const* vehInfo, uint32 creatureEntry) : -_me(unit), _vehicleInfo(vehInfo), _usableSeatNum(0), _creatureEntry(creatureEntry), _status(STATUS_NONE) +UsableSeatNum(0), _me(unit), _vehicleInfo(vehInfo), _creatureEntry(creatureEntry), _status(STATUS_NONE) { for (uint32 i = 0; i < MAX_VEHICLE_SEATS; ++i) { @@ -41,10 +44,16 @@ _me(unit), _vehicleInfo(vehInfo), _usableSeatNum(0), _creatureEntry(creatureEntr { Seats.insert(std::make_pair(i, VehicleSeat(veSeat))); if (veSeat->CanEnterOrExit()) - ++_usableSeatNum; + ++UsableSeatNum; } } + // Set or remove correct flags based on available seats. Will overwrite db data (if wrong). + if (UsableSeatNum) + _me->SetFlag(UNIT_NPC_FLAGS, (_me->GetTypeId() == TYPEID_PLAYER ? UNIT_NPC_FLAG_PLAYER_VEHICLE : UNIT_NPC_FLAG_SPELLCLICK)); + else + _me->RemoveFlag(UNIT_NPC_FLAGS, (_me->GetTypeId() == TYPEID_PLAYER ? UNIT_NPC_FLAG_PLAYER_VEHICLE : UNIT_NPC_FLAG_SPELLCLICK)); + InitMovementInfoForBase(); } @@ -56,6 +65,15 @@ Vehicle::~Vehicle() ASSERT(!itr->second.Passenger); } +/** + * @fn void Vehicle::Install() + * + * @brief Initializes power type for vehicle. Nothing more. + * + * @author Machiavelli + * @date 17-2-2013 + */ + void Vehicle::Install() { if (Creature* creature = _me->ToCreature()) @@ -114,15 +132,26 @@ void Vehicle::InstallAllAccessories(bool evading) InstallAccessory(itr->AccessoryEntry, itr->SeatId, itr->IsMinion, itr->SummonedType, itr->SummonTime); } +/** + * @fn void Vehicle::Uninstall() + * + * @brief Removes all passengers and sets status to STATUS_UNINSTALLING. + * No new passengers can be added to the vehicle after this call. + * + * @author Machiavelli + * @date 17-2-2013 + */ + void Vehicle::Uninstall() { /// @Prevent recursive uninstall call. (Bad script in OnUninstall/OnRemovePassenger/PassengerBoarded hook.) - if (_status == STATUS_UNINSTALLING) + if (_status == STATUS_UNINSTALLING && !GetBase()->HasUnitTypeMask(UNIT_MASK_MINION)) { sLog->outError(LOG_FILTER_VEHICLES, "Vehicle GuidLow: %u, Entry: %u attempts to uninstall, but already has STATUS_UNINSTALLING! " "Check Uninstall/PassengerBoarded script hooks for errors.", _me->GetGUIDLow(), _me->GetEntry()); return; } + _status = STATUS_UNINSTALLING; sLog->outDebug(LOG_FILTER_VEHICLES, "Vehicle::Uninstall Entry: %u, GuidLow: %u", _creatureEntry, _me->GetGUIDLow()); RemoveAllPassengers(); @@ -131,26 +160,39 @@ void Vehicle::Uninstall() sScriptMgr->OnUninstall(this); } +/** + * @fn void Vehicle::Reset(bool evading ) + * + * @brief Reapplies immunities and reinstalls accessories. Only has effect for creatures. + * + * @author Machiavelli + * @date 17-2-2013 + * + * @param evading true if called from CreatureAI::EnterEvadeMode + */ + void Vehicle::Reset(bool evading /*= false*/) { - sLog->outDebug(LOG_FILTER_VEHICLES, "Vehicle::Reset Entry: %u, GuidLow: %u", _creatureEntry, _me->GetGUIDLow()); - if (_me->GetTypeId() == TYPEID_PLAYER) - { - if (_usableSeatNum) - _me->SetFlag(UNIT_NPC_FLAGS, UNIT_NPC_FLAG_PLAYER_VEHICLE); - } - else - { - ApplyAllImmunities(); - InstallAllAccessories(evading); - if (_usableSeatNum) - _me->SetFlag(UNIT_NPC_FLAGS, UNIT_NPC_FLAG_SPELLCLICK); - } + if (GetBase()->GetTypeId() != TYPEID_UNIT) + return; - if (GetBase()->GetTypeId() == TYPEID_UNIT) - sScriptMgr->OnReset(this); + sLog->outDebug(LOG_FILTER_VEHICLES, "Vehicle::Reset (Entry: %u, GuidLow: %u, DBGuid: %u)", GetCreatureEntry(), _me->GetGUIDLow(), _me->ToCreature()->GetDBTableGUIDLow()); + + ApplyAllImmunities(); + InstallAllAccessories(evading); + + sScriptMgr->OnReset(this); } +/** + * @fn void Vehicle::ApplyAllImmunities() + * + * @brief Applies specific immunities that cannot be set in DB. + * + * @author Machiavelli + * @date 17-2-2013 + */ + void Vehicle::ApplyAllImmunities() { // This couldn't be done in DB, because some spells have MECHANIC_NONE @@ -199,10 +241,34 @@ void Vehicle::ApplyAllImmunities() } } +/** + * @fn void Vehicle::RemoveAllPassengers() + * + * @brief Removes all current and pending passengers from the vehicle. + * + * @author Machiavelli + * @date 17-2-2013 + */ + void Vehicle::RemoveAllPassengers() { sLog->outDebug(LOG_FILTER_VEHICLES, "Vehicle::RemoveAllPassengers. Entry: %u, GuidLow: %u", _creatureEntry, _me->GetGUIDLow()); + /// Setting to_Abort to true will cause @VehicleJoinEvent::Abort to be executed on next @Unit::UpdateEvents call + /// This will properly "reset" the pending join process for the passenger. + { + /// Update vehicle pointer in every pending join event - Abort may be called after vehicle is deleted + Vehicle* eventVehicle = _status != STATUS_UNINSTALLING ? this : NULL; + + while (!_pendingJoinEvents.empty()) + { + VehicleJoinEvent* e = _pendingJoinEvents.front(); + e->to_Abort = true; + e->Target = eventVehicle; + _pendingJoinEvents.pop_front(); + } + } + // Passengers always cast an aura with SPELL_AURA_CONTROL_VEHICLE on the vehicle // We just remove the aura and the unapply handler will make the target leave the vehicle. // We don't need to iterate over Seats @@ -215,6 +281,19 @@ void Vehicle::RemoveAllPassengers() // ASSERT(!itr->second.passenger); } +/** + * @fn bool Vehicle::HasEmptySeat(int8 seatId) const + * + * @brief Checks if vehicle's seat specified by 'seatId' is empty. + * + * @author Machiavelli + * @date 17-2-2013 + * + * @param seatId Identifier for the seat. + * + * @return true if empty seat, false if not. + */ + bool Vehicle::HasEmptySeat(int8 seatId) const { SeatMap::const_iterator seat = Seats.find(seatId); @@ -223,6 +302,19 @@ bool Vehicle::HasEmptySeat(int8 seatId) const return !seat->second.Passenger; } +/** + * @fn Unit* Vehicle::GetPassenger(int8 seatId) const + * + * @brief Gets a passenger on specified seat. + * + * @author Machiavelli + * @date 17-2-2013 + * + * @param seatId Seat to look on. + * + * @return null if it not found, else pointer to passenger if in world + */ + Unit* Vehicle::GetPassenger(int8 seatId) const { SeatMap::const_iterator seat = Seats.find(seatId); @@ -232,92 +324,127 @@ Unit* Vehicle::GetPassenger(int8 seatId) const return ObjectAccessor::GetUnit(*GetBase(), seat->second.Passenger); } -int8 Vehicle::GetNextEmptySeat(int8 seatId, bool next) const +/** + * @fn SeatMap::const_iterator Vehicle::GetNextEmptySeat(int8 seatId, bool next) const + * + * @brief Gets the next empty seat based on current seat. + * + * @author Machiavelli + * @date 17-2-2013 + * + * @param seatId Identifier for the current seat. + * @param next true if iterating forward, false means iterating backwards. + * + * @return The next empty seat. + */ + +SeatMap::const_iterator Vehicle::GetNextEmptySeat(int8 seatId, bool next) const { SeatMap::const_iterator seat = Seats.find(seatId); if (seat == Seats.end()) - return -1; + return seat; while (seat->second.Passenger || (!seat->second.SeatInfo->CanEnterOrExit() && !seat->second.SeatInfo->IsUsableByOverride())) { if (next) { - ++seat; - if (seat == Seats.end()) + if (++seat == Seats.end()) seat = Seats.begin(); } else { - if (seat == Seats.begin()) + if (seat-- == Seats.begin()) seat = Seats.end(); - --seat; } + // Make sure we don't loop indefinetly if (seat->first == seatId) - return -1; // no available seat + return Seats.end(); } - return seat->first; + return seat; } +/** + * @fn void Vehicle::InstallAccessory(uint32 entry, int8 seatId, bool minion, uint8 type, + * uint32 summonTime) + * + * @brief Installs an accessory. + * + * @author Machiavelli + * @date 17-2-2013 + * + * @param entry The NPC entry of accessory. + * @param seatId Identifier for the seat to add the accessory to. + * @param minion true if accessory considered a 'minion'. Implies that the accessory will despawn when the vehicle despawns. + * Essentially that it has no life without the vehicle. Their fates are bound. + * @param type See enum @SummonType. + * @param summonTime Time after which the minion is despawned in case of a timed despawn @type specified. + */ + void Vehicle::InstallAccessory(uint32 entry, int8 seatId, bool minion, uint8 type, uint32 summonTime) { /// @Prevent adding accessories when vehicle is uninstalling. (Bad script in OnUninstall/OnRemovePassenger/PassengerBoarded hook.) if (_status == STATUS_UNINSTALLING) { - sLog->outError(LOG_FILTER_VEHICLES, "Vehicle GuidLow: %u, Entry: %u attempts to install accessory Entry: %u on seat %d with STATUS_UNINSTALLING! " - "Check Uninstall/PassengerBoarded script hooks for errors.", _me->GetGUIDLow(), _me->GetEntry(), entry, (int32)seatId); + sLog->outError(LOG_FILTER_VEHICLES, "Vehicle (GuidLow: %u, DB GUID: %u, Entry: %u) attempts to install accessory (Entry: %u) on seat %d with STATUS_UNINSTALLING! " + "Check Uninstall/PassengerBoarded script hooks for errors.", _me->GetGUIDLow(), + (_me->GetTypeId() == TYPEID_UNIT ? _me->ToCreature()->GetDBTableGUIDLow() : _me->GetGUIDLow()), GetCreatureEntry(), entry, (int32)seatId); return; } - sLog->outDebug(LOG_FILTER_VEHICLES, "Vehicle: Installing accessory entry %u on vehicle entry %u (seat:%i)", entry, GetCreatureEntry(), seatId); - if (Unit* passenger = GetPassenger(seatId)) - { - // already installed - if (passenger->GetEntry() == entry) - { - ASSERT(passenger->GetTypeId() == TYPEID_UNIT); - if (_me->GetTypeId() == TYPEID_UNIT) - { - if (_me->ToCreature()->IsInEvadeMode() && passenger->ToCreature()->IsAIEnabled) - passenger->ToCreature()->AI()->EnterEvadeMode(); - return; - } - } - else - passenger->ExitVehicle(); // this should not happen - } + sLog->outDebug(LOG_FILTER_VEHICLES, "Vehicle (GuidLow: %u, DB Guid: %u, Entry %u): installing accessory (Entry: %u) on seat: %d", + _me->GetGUIDLow(), (_me->GetTypeId() == TYPEID_UNIT ? _me->ToCreature()->GetDBTableGUIDLow() : _me->GetGUIDLow()), GetCreatureEntry(), + entry, (int32)seatId); - if (TempSummon* accessory = _me->SummonCreature(entry, *_me, TempSummonType(type), summonTime)) - { - if (minion) - accessory->AddUnitTypeMask(UNIT_MASK_ACCESSORY); + TempSummon* accessory = _me->SummonCreature(entry, *_me, TempSummonType(type), summonTime); + ASSERT(accessory); - if (!_me->HandleSpellClick(accessory, seatId)) - { - accessory->UnSummon(); - return; - } + if (minion) + accessory->AddUnitTypeMask(UNIT_MASK_ACCESSORY); - if (GetBase()->GetTypeId() == TYPEID_UNIT) - sScriptMgr->OnInstallAccessory(this, accessory); - } + (void)_me->HandleSpellClick(accessory, seatId); + + /// If for some reason adding accessory to vehicle fails it will unsummon in + /// @VehicleJoinEvent::Abort } +/** + * @fn bool Vehicle::AddPassenger(Unit* unit, int8 seatId) + * + * @brief Attempts to add a passenger to the vehicle on 'seatId'. + * + * @author Machiavelli + * @date 17-2-2013 + * + * @param [in,out] The prospective passenger. + * @param seatId Identifier for the seat. Value of -1 indicates the next available seat. + * + * @return true if it succeeds, false if it fails. + */ + bool Vehicle::AddPassenger(Unit* unit, int8 seatId) { /// @Prevent adding passengers when vehicle is uninstalling. (Bad script in OnUninstall/OnRemovePassenger/PassengerBoarded hook.) if (_status == STATUS_UNINSTALLING) { - sLog->outError(LOG_FILTER_VEHICLES, "Passenger GuidLow: %u, Entry: %u, attempting to board vehicle GuidLow: %u, Entry: %u during uninstall! SeatId: %i", + sLog->outError(LOG_FILTER_VEHICLES, "Passenger GuidLow: %u, Entry: %u, attempting to board vehicle GuidLow: %u, Entry: %u during uninstall! SeatId: %d", unit->GetGUIDLow(), unit->GetEntry(), _me->GetGUIDLow(), _me->GetEntry(), (int32)seatId); return false; } - if (unit->GetVehicle() != this) - return false; + sLog->outDebug(LOG_FILTER_VEHICLES, "Unit %s scheduling enter vehicle (entry: %u, vehicleId: %u, guid: %u (dbguid: %u) on seat %d", + unit->GetName().c_str(), _me->GetEntry(), _vehicleInfo->m_ID, _me->GetGUIDLow(), + (_me->GetTypeId() == TYPEID_UNIT ? _me->ToCreature()->GetDBTableGUIDLow() : 0), (int32)seatId); + // The seat selection code may kick other passengers off the vehicle. + // While the validity of the following may be arguable, it is possible that when such a passenger + // exits the vehicle will dismiss. That's why the actual adding the passenger to the vehicle is scheduled + // asynchronously, so it can be cancelled easily in case the vehicle is uninstalled meanwhile. SeatMap::iterator seat; + VehicleJoinEvent* e = new VehicleJoinEvent(this, unit); + unit->m_Events.AddEvent(e, unit->m_Events.CalculateTime(0)); + if (seatId < 0) // no specific seat requirement { for (seat = Seats.begin(); seat != Seats.end(); ++seat) @@ -325,87 +452,49 @@ bool Vehicle::AddPassenger(Unit* unit, int8 seatId) break; if (seat == Seats.end()) // no available seat + { + e->to_Abort = true; return false; + } + + e->Seat = seat; + _pendingJoinEvents.push_back(e); } else { seat = Seats.find(seatId); if (seat == Seats.end()) + { + e->to_Abort = true; return false; + } + e->Seat = seat; + _pendingJoinEvents.push_back(e); if (seat->second.Passenger) { - if (Unit* passenger = ObjectAccessor::GetUnit(*GetBase(), seat->second.Passenger)) - passenger->ExitVehicle(); - else - seat->second.Passenger = 0; + Unit* passenger = ObjectAccessor::GetUnit(*GetBase(), seat->second.Passenger); + ASSERT(passenger); + passenger->ExitVehicle(); } ASSERT(!seat->second.Passenger); } - sLog->outDebug(LOG_FILTER_VEHICLES, "Unit %s enter vehicle entry %u id %u dbguid %u seat %d", unit->GetName().c_str(), _me->GetEntry(), _vehicleInfo->m_ID, _me->GetGUIDLow(), (int32)seat->first); - - seat->second.Passenger = unit->GetGUID(); - if (seat->second.SeatInfo->CanEnterOrExit()) - { - ASSERT(_usableSeatNum); - --_usableSeatNum; - if (!_usableSeatNum) - { - if (_me->GetTypeId() == TYPEID_PLAYER) - _me->RemoveFlag(UNIT_NPC_FLAGS, UNIT_NPC_FLAG_PLAYER_VEHICLE); - else - _me->RemoveFlag(UNIT_NPC_FLAGS, UNIT_NPC_FLAG_SPELLCLICK); - } - } - - if (seat->second.SeatInfo->m_flags && !(seat->second.SeatInfo->m_flags & VEHICLE_SEAT_FLAG_ALLOW_TURNING)) - unit->AddUnitState(UNIT_STATE_ONVEHICLE); - - unit->AddUnitMovementFlag(MOVEMENTFLAG_ONTRANSPORT); - VehicleSeatEntry const* veSeat = seat->second.SeatInfo; - unit->m_movementInfo.t_pos.m_positionX = veSeat->m_attachmentOffsetX; - unit->m_movementInfo.t_pos.m_positionY = veSeat->m_attachmentOffsetY; - unit->m_movementInfo.t_pos.m_positionZ = veSeat->m_attachmentOffsetZ; - unit->m_movementInfo.t_pos.SetOrientation(0); - unit->m_movementInfo.t_time = 0; // 1 for player - unit->m_movementInfo.t_seat = seat->first; - unit->m_movementInfo.t_guid = _me->GetGUID(); - - if (_me->GetTypeId() == TYPEID_UNIT && unit->GetTypeId() == TYPEID_PLAYER && - seat->second.SeatInfo->m_flags & VEHICLE_SEAT_FLAG_CAN_CONTROL) - ASSERT(_me->SetCharmedBy(unit, CHARM_TYPE_VEHICLE)) - - if (_me->IsInWorld()) - { - unit->SendClearTarget(); // SMSG_BREAK_TARGET - unit->SetControlled(true, UNIT_STATE_ROOT); // SMSG_FORCE_ROOT - In some cases we send SMSG_SPLINE_MOVE_ROOT here (for creatures) - // also adds MOVEMENTFLAG_ROOT - Movement::MoveSplineInit init(*unit); - init.DisableTransportPathTransformations(); - init.MoveTo(veSeat->m_attachmentOffsetX, veSeat->m_attachmentOffsetY, veSeat->m_attachmentOffsetZ); - init.SetFacing(0.0f); - init.SetTransportEnter(); - init.Launch(); - - if (_me->GetTypeId() == TYPEID_UNIT) - { - if (_me->ToCreature()->IsAIEnabled) - _me->ToCreature()->AI()->PassengerBoarded(unit, seat->first, true); - - // update all passenger's positions - //Passenger's spline OR vehicle movement will update positions - //RelocatePassengers(_me->GetPositionX(), _me->GetPositionY(), _me->GetPositionZ(), _me->GetOrientation()); - } - } - - if (GetBase()->GetTypeId() == TYPEID_UNIT) - sScriptMgr->OnAddPassenger(this, unit, seatId); - return true; } +/** + * @fn void Vehicle::RemovePassenger(Unit* unit) + * + * @brief Removes the passenger from the vehicle. + * + * @author Machiavelli + * @date 17-2-2013 + * + * @param [in,out] unit The passenger to remove. + */ + void Vehicle::RemovePassenger(Unit* unit) { if (unit->GetVehicle() != this) @@ -414,20 +503,12 @@ void Vehicle::RemovePassenger(Unit* unit) SeatMap::iterator seat = GetSeatIteratorForPassenger(unit); ASSERT(seat != Seats.end()); - sLog->outDebug(LOG_FILTER_VEHICLES, "Unit %s exit vehicle entry %u id %u dbguid %u seat %d", unit->GetName().c_str(), _me->GetEntry(), _vehicleInfo->m_ID, _me->GetGUIDLow(), (int32)seat->first); + sLog->outDebug(LOG_FILTER_VEHICLES, "Unit %s exit vehicle entry %u id %u dbguid %u seat %d", + unit->GetName().c_str(), _me->GetEntry(), _vehicleInfo->m_ID, _me->GetGUIDLow(), (int32)seat->first); seat->second.Passenger = 0; - if (seat->second.SeatInfo->CanEnterOrExit()) - { - if (!_usableSeatNum) - { - if (_me->GetTypeId() == TYPEID_PLAYER) - _me->SetFlag(UNIT_NPC_FLAGS, UNIT_NPC_FLAG_PLAYER_VEHICLE); - else - _me->SetFlag(UNIT_NPC_FLAGS, UNIT_NPC_FLAG_SPELLCLICK); - } - ++_usableSeatNum; - } + if (seat->second.SeatInfo->CanEnterOrExit() && ++UsableSeatNum) + _me->SetFlag(UNIT_NPC_FLAGS, (_me->GetTypeId() == TYPEID_PLAYER ? UNIT_NPC_FLAG_PLAYER_VEHICLE : UNIT_NPC_FLAG_SPELLCLICK)); unit->ClearUnitState(UNIT_STATE_ONVEHICLE); @@ -437,7 +518,7 @@ void Vehicle::RemovePassenger(Unit* unit) if (_me->IsInWorld()) { unit->RemoveUnitMovementFlag(MOVEMENTFLAG_ONTRANSPORT); - unit->m_movementInfo.t_pos.Relocate(0, 0, 0, 0); + unit->m_movementInfo.t_pos.Relocate(0.0f, 0.0f, 0.0f, 0.0f); unit->m_movementInfo.t_time = 0; unit->m_movementInfo.t_seat = 0; } @@ -453,7 +534,15 @@ void Vehicle::RemovePassenger(Unit* unit) sScriptMgr->OnRemovePassenger(this, unit); } -//! Must be called after m_base::Relocate +/** + * @fn void Vehicle::RelocatePassengers() + * + * @brief Relocate passengers. Must be called after m_base::Relocate + * + * @author Machiavelli + * @date 17-2-2013 + */ + void Vehicle::RelocatePassengers() { ASSERT(_me->GetMap()); @@ -473,16 +562,35 @@ void Vehicle::RelocatePassengers() } } -void Vehicle::Dismiss() +/** + * @fn bool Vehicle::IsVehicleInUse() const + * + * @brief Returns information whether the vehicle is currently used by any unit + * + * @author Shauren + * @date 26-2-2013 + * + * @return true if any passenger is boarded on vehicle, false otherwise. + */ + +bool Vehicle::IsVehicleInUse() const { - if (GetBase()->GetTypeId() != TYPEID_UNIT) - return; + for (SeatMap::const_iterator itr = Seats.begin(); itr != Seats.end(); ++itr) + if (itr->second.Passenger) + return true; - sLog->outDebug(LOG_FILTER_VEHICLES, "Vehicle::Dismiss Entry: %u, GuidLow %u", _creatureEntry, _me->GetGUIDLow()); - Uninstall(); - GetBase()->ToCreature()->DespawnOrUnsummon(); + return false; } +/** + * @fn void Vehicle::InitMovementInfoForBase() + * + * @brief Sets correct MovementFlags2 based on VehicleFlags from DBC. + * + * @author Machiavelli + * @date 17-2-2013 + */ + void Vehicle::InitMovementInfoForBase() { uint32 vehicleFlags = GetVehicleInfo()->m_flags; @@ -499,16 +607,41 @@ void Vehicle::InitMovementInfoForBase() _me->AddExtraUnitMovementFlag(MOVEMENTFLAG2_FULL_SPEED_PITCHING); } -VehicleSeatEntry const* Vehicle::GetSeatForPassenger(Unit* passenger) +/** + * @fn VehicleSeatEntry const* Vehicle::GetSeatForPassenger(Unit* passenger) + * + * @brief Returns information on the seat of specified passenger, represented by the format in VehicleSeat.dbc + * + * @author Machiavelli + * @date 17-2-2013 + * + * @param [in,out] The passenger for which we check the seat info. + * + * @return null if passenger not found on vehicle, else the DBC record for the seat. + */ + +VehicleSeatEntry const* Vehicle::GetSeatForPassenger(Unit const* passenger) const { - SeatMap::iterator itr; - for (itr = Seats.begin(); itr != Seats.end(); ++itr) + for (SeatMap::const_iterator itr = Seats.begin(); itr != Seats.end(); ++itr) if (itr->second.Passenger == passenger->GetGUID()) return itr->second.SeatInfo; return NULL; } +/** + * @fn SeatMap::iterator Vehicle::GetSeatIteratorForPassenger(Unit* passenger) + * + * @brief Gets seat iterator for specified passenger. + * + * @author Machiavelli + * @date 17-2-2013 + * + * @param [in,out] passenger Passenger to look up. + * + * @return The seat iterator for specified passenger if it's found on the vehicle. Otherwise Seats.end() (invalid iterator). + */ + SeatMap::iterator Vehicle::GetSeatIteratorForPassenger(Unit* passenger) { SeatMap::iterator itr; @@ -519,6 +652,17 @@ SeatMap::iterator Vehicle::GetSeatIteratorForPassenger(Unit* passenger) return Seats.end(); } +/** + * @fn uint8 Vehicle::GetAvailableSeatCount() const + * + * @brief Gets the available seat count. + * + * @author Machiavelli + * @date 17-2-2013 + * + * @return The available seat count. + */ + uint8 Vehicle::GetAvailableSeatCount() const { uint8 ret = 0; @@ -549,3 +693,210 @@ void Vehicle::CalculatePassengerOffset(float& x, float& y, float& z, float& o) y = (iny - inx * tan(GetBase()->GetOrientation())) / (cos(GetBase()->GetOrientation()) + std::sin(GetBase()->GetOrientation()) * tan(GetBase()->GetOrientation())); x = (inx + iny * tan(GetBase()->GetOrientation())) / (cos(GetBase()->GetOrientation()) + std::sin(GetBase()->GetOrientation()) * tan(GetBase()->GetOrientation())); } + +/** + * @fn void Vehicle::RemovePendingEvent(VehicleJoinEvent* e) + * + * @brief Removes @VehicleJoinEvent objects from pending join event store. + * This method only removes it after it's executed or aborted to prevent leaving + * pointers to deleted events. + * + * @author Shauren + * @date 22-2-2013 + * + * @param [in] e The VehicleJoinEvent* to remove from pending event store. + */ + +void Vehicle::RemovePendingEvent(VehicleJoinEvent* e) +{ + for (PendingJoinEventContainer::iterator itr = _pendingJoinEvents.begin(); itr != _pendingJoinEvents.end(); ++itr) + { + if (*itr == e) + { + _pendingJoinEvents.erase(itr); + break; + } + } +} + +/** + * @fn void Vehicle::RemovePendingEventsForSeat(uint8 seatId) + * + * @brief Removes any pending events for given seatId. Executed when a @VehicleJoinEvent::Execute is called + * + * @author Machiavelli + * @date 23-2-2013 + * + * @param seatId Identifier for the seat. + */ + +void Vehicle::RemovePendingEventsForSeat(int8 seatId) +{ + for (PendingJoinEventContainer::iterator itr = _pendingJoinEvents.begin(); itr != _pendingJoinEvents.end();) + { + if ((*itr)->Seat->first == seatId) + { + (*itr)->to_Abort = true; + _pendingJoinEvents.erase(itr++); + } + else + ++itr; + } +} + +/** + * @fn void Vehicle::RemovePendingEventsForSeat(uint8 seatId) + * + * @brief Removes any pending events for given passenger. Executed when vehicle control aura is removed while adding passenger is in progress + * + * @author Shauren + * @date 13-2-2013 + * + * @param passenger Unit that is supposed to enter the vehicle. + */ + +void Vehicle::RemovePendingEventsForPassenger(Unit* passenger) +{ + for (PendingJoinEventContainer::iterator itr = _pendingJoinEvents.begin(); itr != _pendingJoinEvents.end();) + { + if ((*itr)->Passenger == passenger) + { + (*itr)->to_Abort = true; + _pendingJoinEvents.erase(itr++); + } + else + ++itr; + } +} + +VehicleJoinEvent::~VehicleJoinEvent() +{ + if (Target) + Target->RemovePendingEvent(this); +} + +/** + * @fn bool VehicleJoinEvent::Execute(uint64, uint32) + * + * @brief Actually adds the passenger @Passenger to vehicle @Target. + * + * @author Machiavelli + * @date 17-2-2013 + * + * @param parameter1 Unused + * @param parameter2 Unused. + * + * @return true, cannot fail. + * + */ + +bool VehicleJoinEvent::Execute(uint64, uint32) +{ + ASSERT(Passenger->IsInWorld()); + ASSERT(Target && Target->GetBase()->IsInWorld()); + ASSERT(Target->GetBase()->HasAuraTypeWithCaster(SPELL_AURA_CONTROL_VEHICLE, Passenger->GetGUID())); + + Target->RemovePendingEventsForSeat(Seat->first); + + Passenger->m_vehicle = Target; + Seat->second.Passenger = Passenger->GetGUID(); + if (Seat->second.SeatInfo->CanEnterOrExit()) + { + ASSERT(Target->UsableSeatNum); + --(Target->UsableSeatNum); + if (!Target->UsableSeatNum) + { + if (Target->GetBase()->GetTypeId() == TYPEID_PLAYER) + Target->GetBase()->RemoveFlag(UNIT_NPC_FLAGS, UNIT_NPC_FLAG_PLAYER_VEHICLE); + else + Target->GetBase()->RemoveFlag(UNIT_NPC_FLAGS, UNIT_NPC_FLAG_SPELLCLICK); + } + } + + Passenger->InterruptNonMeleeSpells(false); + Passenger->RemoveAurasByType(SPELL_AURA_MOUNTED); + + Player* player = Passenger->ToPlayer(); + if (player) + { + // drop flag + if (Battleground* bg = player->GetBattleground()) + bg->EventPlayerDroppedFlag(player); + + player->StopCastingCharm(); + player->StopCastingBindSight(); + player->SendOnCancelExpectedVehicleRideAura(); + player->UnsummonPetTemporaryIfAny(); + } + + if (Seat->second.SeatInfo->m_flags && !(Seat->second.SeatInfo->m_flags & VEHICLE_SEAT_FLAG_ALLOW_TURNING)) + Passenger->AddUnitState(UNIT_STATE_ONVEHICLE); + + Passenger->AddUnitMovementFlag(MOVEMENTFLAG_ONTRANSPORT); + VehicleSeatEntry const* veSeat = Seat->second.SeatInfo; + Passenger->m_movementInfo.t_pos.Relocate(veSeat->m_attachmentOffsetX, veSeat->m_attachmentOffsetY, veSeat->m_attachmentOffsetZ); + Passenger->m_movementInfo.t_time = 0; // 1 for player + Passenger->m_movementInfo.t_seat = Seat->first; + Passenger->m_movementInfo.t_guid = Target->GetBase()->GetGUID(); + + if (Target->GetBase()->GetTypeId() == TYPEID_UNIT && Passenger->GetTypeId() == TYPEID_PLAYER && + Seat->second.SeatInfo->m_flags & VEHICLE_SEAT_FLAG_CAN_CONTROL) + ASSERT(Target->GetBase()->SetCharmedBy(Passenger, CHARM_TYPE_VEHICLE)) // SMSG_CLIENT_CONTROL + + Passenger->SendClearTarget(); // SMSG_BREAK_TARGET + Passenger->SetControlled(true, UNIT_STATE_ROOT); // SMSG_FORCE_ROOT - In some cases we send SMSG_SPLINE_MOVE_ROOT here (for creatures) + // also adds MOVEMENTFLAG_ROOT + + Movement::MoveSplineInit init(Passenger); + init.DisableTransportPathTransformations(); + init.MoveTo(veSeat->m_attachmentOffsetX, veSeat->m_attachmentOffsetY, veSeat->m_attachmentOffsetZ, false, true); + init.SetFacing(0.0f); + init.SetTransportEnter(); + init.Launch(); + + if (Target->GetBase()->GetTypeId() == TYPEID_UNIT) + { + if (Target->GetBase()->ToCreature()->IsAIEnabled) + Target->GetBase()->ToCreature()->AI()->PassengerBoarded(Passenger, Seat->first, true); + + sScriptMgr->OnAddPassenger(Target, Passenger, Seat->first); + + // Actually quite a redundant hook. Could just use OnAddPassenger and check for unit typemask inside script. + if (Passenger->HasUnitTypeMask(UNIT_MASK_ACCESSORY)) + sScriptMgr->OnInstallAccessory(Target, Passenger->ToCreature()); + } + + return true; +} + +/** + * @fn void VehicleJoinEvent::Abort(uint64) + * + * @brief Aborts the event. Implies that unit @Passenger will not be boarding vehicle @Target after all. + * + * @author Machiavelli + * @date 17-2-2013 + * + * @param parameter1 Unused + */ + +void VehicleJoinEvent::Abort(uint64) +{ + /// Check if the Vehicle was already uninstalled, in which case all auras were removed already + if (Target) + { + sLog->outDebug(LOG_FILTER_VEHICLES, "Passenger GuidLow: %u, Entry: %u, board on vehicle GuidLow: %u, Entry: %u SeatId: %d cancelled", + Passenger->GetGUIDLow(), Passenger->GetEntry(), Target->GetBase()->GetGUIDLow(), Target->GetBase()->GetEntry(), (int32)Seat->first); + + /// @SPELL_AURA_CONTROL_VEHICLE auras can be applied even when the passenger is not (yet) on the vehicle. + /// When this code is triggered it means that something went wrong in @Vehicle::AddPassenger, and we should remove + /// the aura manually. + Target->GetBase()->RemoveAurasByType(SPELL_AURA_CONTROL_VEHICLE, Passenger->GetGUID()); + } + else + sLog->outDebug(LOG_FILTER_VEHICLES, "Passenger GuidLow: %u, Entry: %u, board on uninstalled vehicle SeatId: %d cancelled", + Passenger->GetGUIDLow(), Passenger->GetEntry(), (int32)Seat->first); + + if (Passenger->IsInWorld() && Passenger->HasUnitTypeMask(UNIT_MASK_ACCESSORY)) + Passenger->ToCreature()->DespawnOrUnsummon(); +} diff --git a/src/server/game/Entities/Vehicle/Vehicle.h b/src/server/game/Entities/Vehicle/Vehicle.h index 823fb72b8a8..67975490ecc 100644 --- a/src/server/game/Entities/Vehicle/Vehicle.h +++ b/src/server/game/Entities/Vehicle/Vehicle.h @@ -23,15 +23,23 @@ #include "Object.h" #include "VehicleDefines.h" #include "Unit.h" +#include <list> struct VehicleEntry; - class Unit; +class VehicleJoinEvent; typedef std::set<uint64> GuidSet; class Vehicle : public TransportBase { + protected: + friend bool Unit::CreateVehicleKit(uint32 id, uint32 creatureEntry); + Vehicle(Unit* unit, VehicleEntry const* vehInfo, uint32 creatureEntry); + + friend void Unit::RemoveVehicleKit(); + ~Vehicle(); + public: void Install(); void Uninstall(); @@ -46,7 +54,7 @@ class Vehicle : public TransportBase bool HasEmptySeat(int8 seatId) const; Unit* GetPassenger(int8 seatId) const; - int8 GetNextEmptySeat(int8 seatId, bool next) const; + SeatMap::const_iterator GetNextEmptySeat(int8 seatId, bool next) const; uint8 GetAvailableSeatCount() const; bool AddPassenger(Unit* passenger, int8 seatId = -1); @@ -54,22 +62,20 @@ class Vehicle : public TransportBase void RemovePassenger(Unit* passenger); void RelocatePassengers(); void RemoveAllPassengers(); - void Dismiss(); - void TeleportVehicle(float x, float y, float z, float ang); - bool IsVehicleInUse() { return Seats.begin() != Seats.end(); } + bool IsVehicleInUse() const; + + void SetLastShootPos(Position const& pos) { _lastShootPos.Relocate(pos); } + Position const& GetLastShootPos() const { return _lastShootPos; } - void SetLastShootPos(Position const& pos) { m_lastShootPos.Relocate(pos); } - Position GetLastShootPos() { return m_lastShootPos; } + SeatMap Seats; ///< The collection of all seats on the vehicle. Including vacant ones. - SeatMap Seats; + VehicleSeatEntry const* GetSeatForPassenger(Unit const* passenger) const; - VehicleSeatEntry const* GetSeatForPassenger(Unit* passenger); + void RemovePendingEventsForPassenger(Unit* passenger); protected: - friend bool Unit::CreateVehicleKit(uint32 id, uint32 creatureEntry); - Vehicle(Unit* unit, VehicleEntry const* vehInfo, uint32 creatureEntry); - friend void Unit::RemoveVehicleKit(); - ~Vehicle(); + friend class VehicleJoinEvent; + uint32 UsableSeatNum; ///< Number of seats that match VehicleSeatEntry::UsableByPlayer, used for proper display flags private: enum Status @@ -88,12 +94,34 @@ class Vehicle : public TransportBase /// This method transforms supplied global coordinates into local offsets void CalculatePassengerOffset(float& x, float& y, float& z, float& o); - Unit* _me; - VehicleEntry const* _vehicleInfo; + void RemovePendingEvent(VehicleJoinEvent* e); + void RemovePendingEventsForSeat(int8 seatId); + + private: + Unit* _me; ///< The underlying unit with the vehicle kit. Can be player or creature. + VehicleEntry const* _vehicleInfo; ///< DBC data for vehicle GuidSet vehiclePlayers; - uint32 _usableSeatNum; // Number of seats that match VehicleSeatEntry::UsableByPlayer, used for proper display flags - uint32 _creatureEntry; // Can be different than me->GetBase()->GetEntry() in case of players - Status _status; - Position m_lastShootPos; + + uint32 _creatureEntry; ///< Can be different than the entry of _me in case of players + Status _status; ///< Internal variable for sanity checks + Position _lastShootPos; + + typedef std::list<VehicleJoinEvent*> PendingJoinEventContainer; + PendingJoinEventContainer _pendingJoinEvents; ///< Collection of delayed join events for prospective passengers }; + +class VehicleJoinEvent : public BasicEvent +{ + friend class Vehicle; + protected: + VehicleJoinEvent(Vehicle* v, Unit* u) : Target(v), Passenger(u), Seat(Target->Seats.end()) {} + ~VehicleJoinEvent(); + bool Execute(uint64, uint32); + void Abort(uint64); + + Vehicle* Target; + Unit* Passenger; + SeatMap::iterator Seat; +}; + #endif diff --git a/src/server/game/Entities/Vehicle/VehicleDefines.h b/src/server/game/Entities/Vehicle/VehicleDefines.h index 3d3b43e832c..4210a663aab 100644 --- a/src/server/game/Entities/Vehicle/VehicleDefines.h +++ b/src/server/game/Entities/Vehicle/VehicleDefines.h @@ -78,6 +78,8 @@ typedef std::map<int8, VehicleSeat> SeatMap; class TransportBase { public: + virtual ~TransportBase() { } + /// This method transforms supplied transport offsets into global coordinates virtual void CalculatePassengerPosition(float& x, float& y, float& z, float& o) = 0; diff --git a/src/server/game/Events/GameEventMgr.cpp b/src/server/game/Events/GameEventMgr.cpp index a499347356b..685ac9029ed 100644 --- a/src/server/game/Events/GameEventMgr.cpp +++ b/src/server/game/Events/GameEventMgr.cpp @@ -210,8 +210,7 @@ void GameEventMgr::LoadFromDB() if (!result) { mGameEvent.clear(); - sLog->outError(LOG_FILTER_SQL, ">> Loaded 0 game events. DB table `game_event` is empty."); - + sLog->outError(LOG_FILTER_SERVER_LOADING, ">> Loaded 0 game events. DB table `game_event` is empty."); return; } @@ -451,8 +450,8 @@ void GameEventMgr::LoadFromDB() { uint32 oldMSTime = getMSTime(); - // 0 1 2 3 - QueryResult result = WorldDatabase.Query("SELECT creature.guid, game_event_model_equip.eventEntry, game_event_model_equip.modelid, game_event_model_equip.equipment_id " + // 0 1 2 3 4 + QueryResult result = WorldDatabase.Query("SELECT creature.guid, creature.id, game_event_model_equip.eventEntry, game_event_model_equip.modelid, game_event_model_equip.equipment_id " "FROM creature JOIN game_event_model_equip ON creature.guid=game_event_model_equip.guid"); if (!result) @@ -467,7 +466,8 @@ void GameEventMgr::LoadFromDB() Field* fields = result->Fetch(); uint32 guid = fields[0].GetUInt32(); - uint16 event_id = fields[1].GetUInt8(); + uint32 entry = fields[1].GetUInt32(); + uint16 event_id = fields[2].GetUInt8(); if (event_id >= mGameEventModelEquip.size()) { @@ -477,17 +477,18 @@ void GameEventMgr::LoadFromDB() ModelEquipList& equiplist = mGameEventModelEquip[event_id]; ModelEquip newModelEquipSet; - newModelEquipSet.modelid = fields[2].GetUInt32(); - newModelEquipSet.equipment_id = fields[3].GetUInt32(); + newModelEquipSet.modelid = fields[3].GetUInt32(); + newModelEquipSet.equipment_id = fields[4].GetUInt8(); newModelEquipSet.equipement_id_prev = 0; newModelEquipSet.modelid_prev = 0; if (newModelEquipSet.equipment_id > 0) { - if (!sObjectMgr->GetEquipmentInfo(newModelEquipSet.equipment_id)) + int8 equipId = static_cast<int8>(newModelEquipSet.equipment_id); + if (!sObjectMgr->GetEquipmentInfo(entry, equipId)) { - sLog->outError(LOG_FILTER_SQL, "Table `game_event_model_equip` have creature (Guid: %u) with equipment_id %u not found in table `creature_equip_template`, set to no equipment.", - guid, newModelEquipSet.equipment_id); + sLog->outError(LOG_FILTER_SQL, "Table `game_event_model_equip` have creature (Guid: %u, entry: %u) with equipment_id %u not found in table `creature_equip_template`, set to no equipment.", + guid, entry, newModelEquipSet.equipment_id); continue; } } @@ -764,7 +765,7 @@ void GameEventMgr::LoadFromDB() Field* fields = result->Fetch(); uint32 questId = fields[0].GetUInt32(); - uint32 eventEntry = fields[1].GetUInt32(); // TODO: Change to uint8 + uint32 eventEntry = fields[1].GetUInt32(); /// @todo Change to uint8 if (!sObjectMgr->GetQuestTemplate(questId)) { @@ -1103,14 +1104,8 @@ void GameEventMgr::UnApplyEvent(uint16 event_id) void GameEventMgr::ApplyNewEvent(uint16 event_id) { - switch (sWorld->getIntConfig(CONFIG_EVENT_ANNOUNCE)) - { - case 0: // disable - break; - case 1: // announce events - sWorld->SendWorldText(LANG_EVENTMESSAGE, mGameEvent[event_id].description.c_str()); - break; - } + if (sWorld->getBoolConfig(CONFIG_EVENT_ANNOUNCE)) + sWorld->SendWorldText(LANG_EVENTMESSAGE, mGameEvent[event_id].description.c_str()); sLog->outInfo(LOG_FILTER_GAMEEVENTS, "GameEvent %u \"%s\" started.", event_id, mGameEvent[event_id].description.c_str()); @@ -1232,7 +1227,7 @@ void GameEventMgr::GameEventSpawn(int16 event_id) { GameObject* pGameobject = new GameObject; //sLog->outDebug(LOG_FILTER_GENERAL, "Spawning gameobject %u", *itr); - //TODO: find out when it is add to map + /// @todo find out when it is add to map if (!pGameobject->LoadGameObjectFromDB(*itr, map, false)) delete pGameobject; else @@ -1332,7 +1327,7 @@ void GameEventMgr::ChangeEquipOrModel(int16 event_id, bool activate) itr->second.equipement_id_prev = creature->GetCurrentEquipmentId(); itr->second.modelid_prev = creature->GetDisplayId(); creature->LoadEquipment(itr->second.equipment_id, true); - if (itr->second.modelid >0 && itr->second.modelid_prev != itr->second.modelid) + if (itr->second.modelid > 0 && itr->second.modelid_prev != itr->second.modelid) { CreatureModelInfo const* minfo = sObjectMgr->GetCreatureModelInfo(itr->second.modelid); if (minfo) @@ -1347,7 +1342,7 @@ void GameEventMgr::ChangeEquipOrModel(int16 event_id, bool activate) else { creature->LoadEquipment(itr->second.equipement_id_prev, true); - if (itr->second.modelid_prev >0 && itr->second.modelid_prev != itr->second.modelid) + if (itr->second.modelid_prev > 0 && itr->second.modelid_prev != itr->second.modelid) { CreatureModelInfo const* minfo = sObjectMgr->GetCreatureModelInfo(itr->second.modelid_prev); if (minfo) @@ -1366,11 +1361,11 @@ void GameEventMgr::ChangeEquipOrModel(int16 event_id, bool activate) if (data2 && activate) { CreatureTemplate const* cinfo = sObjectMgr->GetCreatureTemplate(data2->id); - uint32 displayID = sObjectMgr->ChooseDisplayId(0, cinfo, data2); + uint32 displayID = ObjectMgr::ChooseDisplayId(cinfo, data2); sObjectMgr->GetCreatureModelRandomGender(&displayID); if (data2->equipmentId == 0) - itr->second.equipement_id_prev = cinfo->equipmentId; + itr->second.equipement_id_prev = 0; ///@todo: verify this line else if (data2->equipmentId != -1) itr->second.equipement_id_prev = data->equipmentId; itr->second.modelid_prev = displayID; diff --git a/src/server/game/Events/GameEventMgr.h b/src/server/game/Events/GameEventMgr.h index d15b3e48dc9..4175e57f28a 100644 --- a/src/server/game/Events/GameEventMgr.h +++ b/src/server/game/Events/GameEventMgr.h @@ -73,9 +73,9 @@ struct GameEventData struct ModelEquip { uint32 modelid; - uint32 equipment_id; uint32 modelid_prev; - uint32 equipement_id_prev; + uint8 equipment_id; + uint8 equipement_id_prev; }; struct NPCVendorEntry diff --git a/src/server/game/Globals/ObjectAccessor.cpp b/src/server/game/Globals/ObjectAccessor.cpp index 75b8413c934..0ea66a056fb 100644 --- a/src/server/game/Globals/ObjectAccessor.cpp +++ b/src/server/game/Globals/ObjectAccessor.cpp @@ -213,7 +213,7 @@ void ObjectAccessor::RemoveCorpse(Corpse* corpse) { ASSERT(corpse && corpse->GetType() != CORPSE_BONES); - //TODO: more works need to be done for corpse and other world object + /// @todo more works need to be done for corpse and other world object if (Map* map = corpse->FindMap()) { corpse->DestroyForNearbyPlayers(); @@ -234,7 +234,7 @@ void ObjectAccessor::RemoveCorpse(Corpse* corpse) TRINITY_WRITE_GUARD(ACE_RW_Thread_Mutex, i_corpseLock); Player2CorpsesMapType::iterator iter = i_player2corpse.find(corpse->GetOwnerGUID()); - if (iter == i_player2corpse.end()) // TODO: Fix this + if (iter == i_player2corpse.end()) /// @todo Fix this return; // build mapid*cellid -> guid_set map diff --git a/src/server/game/Globals/ObjectAccessor.h b/src/server/game/Globals/ObjectAccessor.h index 113ef1dec83..6a53d58c57f 100644 --- a/src/server/game/Globals/ObjectAccessor.h +++ b/src/server/game/Globals/ObjectAccessor.h @@ -90,7 +90,7 @@ class ObjectAccessor ObjectAccessor& operator=(const ObjectAccessor&); public: - // TODO: override these template functions for each holder type and add assertions + /// @todo: Override these template functions for each holder type and add assertions template<class T> static T* GetObjectInOrOutOfWorld(uint64 guid, T* /*typeSpecifier*/) { diff --git a/src/server/game/Globals/ObjectMgr.cpp b/src/server/game/Globals/ObjectMgr.cpp index b41b61904e6..b04d259c5d0 100644 --- a/src/server/game/Globals/ObjectMgr.cpp +++ b/src/server/game/Globals/ObjectMgr.cpp @@ -404,8 +404,8 @@ void ObjectMgr::LoadCreatureTemplates() "spell2, spell3, spell4, spell5, spell6, spell7, spell8, PetSpellDataId, VehicleId, mingold, maxgold, AIName, MovementType, " // 68 69 70 71 72 73 74 75 76 77 78 "InhabitType, HoverHeight, Health_mod, Mana_mod, Armor_mod, RacialLeader, questItem1, questItem2, questItem3, questItem4, questItem5, " - // 79 80 81 82 83 84 - " questItem6, movementId, RegenHealth, equipment_id, mechanic_immune_mask, flags_extra, ScriptName " + // 79 80 81 82 83 84 + " questItem6, movementId, RegenHealth, mechanic_immune_mask, flags_extra, ScriptName " "FROM creature_template;"); if (!result) @@ -500,10 +500,9 @@ void ObjectMgr::LoadCreatureTemplates() creatureTemplate.movementId = fields[80].GetUInt32(); creatureTemplate.RegenHealth = fields[81].GetBool(); - creatureTemplate.equipmentId = fields[82].GetUInt32(); - creatureTemplate.MechanicImmuneMask = fields[83].GetUInt32(); - creatureTemplate.flags_extra = fields[84].GetUInt32(); - creatureTemplate.ScriptID = GetScriptId(fields[85].GetCString()); + creatureTemplate.MechanicImmuneMask = fields[82].GetUInt32(); + creatureTemplate.flags_extra = fields[83].GetUInt32(); + creatureTemplate.ScriptID = GetScriptId(fields[84].GetCString()); ++count; } @@ -858,15 +857,6 @@ void ObjectMgr::CheckCreatureTemplate(CreatureTemplate const* cInfo) const_cast<CreatureTemplate*>(cInfo)->MovementType = IDLE_MOTION_TYPE; } - if (cInfo->equipmentId > 0) // 0 no equipment - { - if (!GetEquipmentInfo(cInfo->equipmentId)) - { - sLog->outError(LOG_FILTER_SQL, "Table `creature_template` lists creature (Entry: %u) with `equipment_id` %u not found in table `creature_equip_template`, set to no equipment.", cInfo->Entry, cInfo->equipmentId); - const_cast<CreatureTemplate*>(cInfo)->equipmentId = 0; - } - } - /// if not set custom creature scale then load scale from CreatureDisplayInfo.dbc if (cInfo->scale <= 0.0f) { @@ -986,11 +976,28 @@ CreatureAddon const* ObjectMgr::GetCreatureTemplateAddon(uint32 entry) return NULL; } -EquipmentInfo const* ObjectMgr::GetEquipmentInfo(uint32 entry) +EquipmentInfo const* ObjectMgr::GetEquipmentInfo(uint32 entry, int8& id) { EquipmentInfoContainer::const_iterator itr = _equipmentInfoStore.find(entry); - if (itr != _equipmentInfoStore.end()) - return &(itr->second); + if (itr == _equipmentInfoStore.end()) + return NULL; + + if (itr->second.empty()) + return NULL; + + if (id == -1) // select a random element + { + EquipmentInfoContainerInternal::const_iterator ritr = itr->second.begin(); + std::advance(ritr, urand(0u, itr->second.size() - 1)); + id = std::distance(itr->second.begin(), ritr) + 1; + return &ritr->second; + } + else + { + EquipmentInfoContainerInternal::const_iterator itr2 = itr->second.find(id); + if (itr2 != itr->second.end()) + return &itr2->second; + } return NULL; } @@ -999,7 +1006,8 @@ void ObjectMgr::LoadEquipmentTemplates() { uint32 oldMSTime = getMSTime(); - QueryResult result = WorldDatabase.Query("SELECT entry, itemEntry1, itemEntry2, itemEntry3 FROM creature_equip_template"); + // 0 1 2 3 4 + QueryResult result = WorldDatabase.Query("SELECT entry, id, itemEntry1, itemEntry2, itemEntry3 FROM creature_equip_template"); if (!result) { @@ -1012,13 +1020,21 @@ void ObjectMgr::LoadEquipmentTemplates() { Field* fields = result->Fetch(); - uint16 entry = fields[0].GetUInt16(); + uint32 entry = fields[0].GetUInt32(); + + if (!sObjectMgr->GetCreatureTemplate(entry)) + { + sLog->outError(LOG_FILTER_SQL, "Creature template (Entry: %u) does not exist but has a record in `creature_equip_template`", entry); + continue; + } + + uint8 id = fields[1].GetUInt8(); - EquipmentInfo& equipmentInfo = _equipmentInfoStore[entry]; + EquipmentInfo& equipmentInfo = _equipmentInfoStore[entry][id]; - equipmentInfo.ItemEntry[0] = fields[1].GetUInt32(); - equipmentInfo.ItemEntry[1] = fields[2].GetUInt32(); - equipmentInfo.ItemEntry[2] = fields[3].GetUInt32(); + equipmentInfo.ItemEntry[0] = fields[2].GetUInt32(); + equipmentInfo.ItemEntry[1] = fields[3].GetUInt32(); + equipmentInfo.ItemEntry[2] = fields[4].GetUInt32(); for (uint8 i = 0; i < MAX_EQUIPMENT_ITEMS; ++i) { @@ -1029,8 +1045,8 @@ void ObjectMgr::LoadEquipmentTemplates() if (!dbcItem) { - sLog->outError(LOG_FILTER_SQL, "Unknown item (entry=%u) in creature_equip_template.itemEntry%u for entry = %u, forced to 0.", - equipmentInfo.ItemEntry[i], i+1, entry); + sLog->outError(LOG_FILTER_SQL, "Unknown item (entry=%u) in creature_equip_template.itemEntry%u for entry = %u and id=%u, forced to 0.", + equipmentInfo.ItemEntry[i], i+1, entry, id); equipmentInfo.ItemEntry[i] = 0; continue; } @@ -1045,8 +1061,8 @@ void ObjectMgr::LoadEquipmentTemplates() dbcItem->InventoryType != INVTYPE_THROWN && dbcItem->InventoryType != INVTYPE_RANGEDRIGHT) { - sLog->outError(LOG_FILTER_SQL, "Item (entry=%u) in creature_equip_template.itemEntry%u for entry = %u is not equipable in a hand, forced to 0.", - equipmentInfo.ItemEntry[i], i+1, entry); + sLog->outError(LOG_FILTER_SQL, "Item (entry=%u) in creature_equip_template.itemEntry%u for entry = %u and id = %u is not equipable in a hand, forced to 0.", + equipmentInfo.ItemEntry[i], i+1, entry, id); equipmentInfo.ItemEntry[i] = 0; } } @@ -1067,19 +1083,13 @@ CreatureModelInfo const* ObjectMgr::GetCreatureModelInfo(uint32 modelId) return NULL; } -uint32 ObjectMgr::ChooseDisplayId(uint32 /*team*/, const CreatureTemplate* cinfo, const CreatureData* data /*= NULL*/) +uint32 ObjectMgr::ChooseDisplayId(CreatureTemplate const* cinfo, CreatureData const* data /*= NULL*/) { // Load creature model (display id) - uint32 display_id = 0; - - if (!data || data->displayid == 0) - { - display_id = cinfo->GetRandomValidModelId(); - } - else + if (data && data->displayid) return data->displayid; - return display_id; + return cinfo->GetRandomValidModelId(); } void ObjectMgr::ChooseCreatureFlags(const CreatureTemplate* cinfo, uint32& npcflag, uint32& unit_flags, uint32& dynamicflags, const CreatureData* data /*= NULL*/) @@ -1189,8 +1199,7 @@ void ObjectMgr::LoadLinkedRespawn() if (!result) { - sLog->outError(LOG_FILTER_SQL, ">> Loaded 0 linked respawns. DB table `linked_respawn` is empty."); - + sLog->outError(LOG_FILTER_SERVER_LOADING, ">> Loaded 0 linked respawns. DB table `linked_respawn` is empty."); return; } @@ -1406,6 +1415,94 @@ bool ObjectMgr::SetCreatureLinkedRespawn(uint32 guidLow, uint32 linkedGuidLow) return true; } +void ObjectMgr::LoadTempSummons() +{ + uint32 oldMSTime = getMSTime(); + + _tempSummonDataStore.clear(); // needed for reload case + + // 0 1 2 3 4 5 6 7 8 9 + QueryResult result = WorldDatabase.Query("SELECT summonerId, summonerType, groupId, entry, position_x, position_y, position_z, orientation, summonType, summonTime FROM creature_summon_groups"); + + if (!result) + { + sLog->outInfo(LOG_FILTER_SERVER_LOADING, ">> Loaded 0 temp summons. DB table `creature_summon_groups` is empty."); + return; + } + + uint32 count = 0; + do + { + Field* fields = result->Fetch(); + + uint32 summonerId = fields[0].GetUInt32(); + SummonerType summonerType = SummonerType(fields[1].GetUInt8()); + uint8 group = fields[2].GetUInt8(); + + switch (summonerType) + { + case SUMMONER_TYPE_CREATURE: + if (!GetCreatureTemplate(summonerId)) + { + sLog->outError(LOG_FILTER_SQL, "Table `creature_summon_groups` has summoner with non existing entry %u for creature summoner type, skipped.", summonerId); + continue; + } + break; + case SUMMONER_TYPE_GAMEOBJECT: + if (!GetGameObjectTemplate(summonerId)) + { + sLog->outError(LOG_FILTER_SQL, "Table `creature_summon_groups` has summoner with non existing entry %u for gameobject summoner type, skipped.", summonerId); + continue; + } + break; + case SUMMONER_TYPE_MAP: + if (!sMapStore.LookupEntry(summonerId)) + { + sLog->outError(LOG_FILTER_SQL, "Table `creature_summon_groups` has summoner with non existing entry %u for map summoner type, skipped.", summonerId); + continue; + } + break; + default: + sLog->outError(LOG_FILTER_SQL, "Table `creature_summon_groups` has unhandled summoner type %u for summoner %u, skipped.", summonerType, summonerId); + continue; + } + + TempSummonData data; + data.entry = fields[3].GetUInt32(); + + if (!GetCreatureTemplate(data.entry)) + { + sLog->outError(LOG_FILTER_SQL, "Table `creature_summon_groups` has creature in group [Summoner ID: %u, Summoner Type: %u, Group ID: %u] with non existing creature entry %u, skipped.", summonerId, summonerType, group, data.entry); + continue; + } + + float posX = fields[4].GetFloat(); + float posY = fields[5].GetFloat(); + float posZ = fields[6].GetFloat(); + float orientation = fields[7].GetFloat(); + + data.pos.Relocate(posX, posY, posZ, orientation); + + data.type = TempSummonType(fields[8].GetUInt8()); + + if (data.type > TEMPSUMMON_MANUAL_DESPAWN) + { + sLog->outError(LOG_FILTER_SQL, "Table `creature_summon_groups` has unhandled temp summon type %u in group [Summoner ID: %u, Summoner Type: %u, Group ID: %u] for creature entry %u, skipped.", data.type, summonerId, summonerType, group, data.entry); + continue; + } + + data.time = fields[9].GetUInt32(); + + TempSummonGroupKey key(summonerId, summonerType, group); + _tempSummonDataStore[key].push_back(data); + + ++count; + + } while (result->NextRow()); + + sLog->outInfo(LOG_FILTER_SERVER_LOADING, ">> Loaded %u temp summons in %u ms", count, GetMSTimeDiffToNow(oldMSTime)); +} + void ObjectMgr::LoadCreatures() { uint32 oldMSTime = getMSTime(); @@ -1420,8 +1517,7 @@ void ObjectMgr::LoadCreatures() if (!result) { - sLog->outError(LOG_FILTER_SQL, ">> Loaded 0 creatures. DB table `creature` is empty."); - + sLog->outError(LOG_FILTER_SERVER_LOADING, ">> Loaded 0 creatures. DB table `creature` is empty."); return; } @@ -1453,7 +1549,7 @@ void ObjectMgr::LoadCreatures() data.id = entry; data.mapid = fields[2].GetUInt16(); data.displayid = fields[3].GetUInt32(); - data.equipmentId = fields[4].GetInt32(); + data.equipmentId = fields[4].GetInt8(); data.posX = fields[5].GetFloat(); data.posY = fields[6].GetFloat(); data.posZ = fields[7].GetFloat(); @@ -1495,13 +1591,13 @@ void ObjectMgr::LoadCreatures() if (!ok) continue; - // -1 no equipment, 0 use default - if (data.equipmentId > 0) + // -1 random, 0 no equipment, + if (data.equipmentId != 0) { - if (!GetEquipmentInfo(data.equipmentId)) + if (!GetEquipmentInfo(data.id, data.equipmentId)) { sLog->outError(LOG_FILTER_SQL, "Table `creature` have creature (Entry: %u) with equipment_id %u not found in table `creature_equip_template`, set to no equipment.", data.id, data.equipmentId); - data.equipmentId = -1; + data.equipmentId = 0; } } @@ -1675,7 +1771,7 @@ uint32 ObjectMgr::AddCreData(uint32 entry, uint32 /*team*/, uint32 mapId, float data.id = entry; data.mapid = mapId; data.displayid = 0; - data.equipmentId = cInfo->equipmentId; + data.equipmentId = 0; data.posX = x; data.posY = y; data.posZ = z; @@ -1729,7 +1825,7 @@ void ObjectMgr::LoadGameobjects() if (!result) { - sLog->outError(LOG_FILTER_SQL, ">> Loaded 0 gameobjects. DB table `gameobject` is empty."); + sLog->outError(LOG_FILTER_SERVER_LOADING, ">> Loaded 0 gameobjects. DB table `gameobject` is empty."); return; } @@ -2754,8 +2850,7 @@ void ObjectMgr::LoadVehicleTemplateAccessories() if (!result) { - sLog->outError(LOG_FILTER_SQL, ">> Loaded 0 vehicle template accessories. DB table `vehicle_template_accessory` is empty."); - + sLog->outError(LOG_FILTER_SERVER_LOADING, ">> Loaded 0 vehicle template accessories. DB table `vehicle_template_accessory` is empty."); return; } @@ -2849,8 +2944,7 @@ void ObjectMgr::LoadPetLevelInfo() if (!result) { - sLog->outError(LOG_FILTER_SQL, ">> Loaded 0 level pet stats definitions. DB table `pet_levelstats` is empty."); - + sLog->outError(LOG_FILTER_SERVER_LOADING, ">> Loaded 0 level pet stats definitions. DB table `pet_levelstats` is empty."); return; } @@ -2956,33 +3050,23 @@ void ObjectMgr::PlayerCreateInfoAddItemHelper(uint32 race_, uint32 class_, uint3 if (count < -1) sLog->outError(LOG_FILTER_SQL, "Invalid count %i specified on item %u be removed from original player create info (use -1)!", count, itemId); - uint32 RaceClass = (race_) | (class_ << 8); - bool doneOne = false; - for (uint32 i = 1; i < sCharStartOutfitStore.GetNumRows(); ++i) + for (uint32 gender = 0; gender < GENDER_NONE; ++gender) { - if (CharStartOutfitEntry const* entry = sCharStartOutfitStore.LookupEntry(i)) + if (CharStartOutfitEntry const* entry = GetCharStartOutfitEntry(race_, class_, gender)) { - if (entry->RaceClassGender == RaceClass || entry->RaceClassGender == (RaceClass | (1 << 16))) + bool found = false; + for (uint8 x = 0; x < MAX_OUTFIT_ITEMS; ++x) { - bool found = false; - for (uint8 x = 0; x < MAX_OUTFIT_ITEMS; ++x) + if (entry->ItemId[x] > 0 && uint32(entry->ItemId[x]) == itemId) { - if (entry->ItemId[x] > 0 && uint32(entry->ItemId[x]) == itemId) - { - found = true; - const_cast<CharStartOutfitEntry*>(entry)->ItemId[x] = 0; - break; - } - } - - if (!found) - sLog->outError(LOG_FILTER_SQL, "Item %u specified to be removed from original create info not found in dbc!", itemId); - - if (!doneOne) - doneOne = true; - else + found = true; + const_cast<CharStartOutfitEntry*>(entry)->ItemId[x] = 0; break; + } } + + if (!found) + sLog->outError(LOG_FILTER_SQL, "Item %u specified to be removed from original create info not found in dbc!", itemId); } } } @@ -2998,8 +3082,7 @@ void ObjectMgr::LoadPlayerInfo() if (!result) { - - sLog->outError(LOG_FILTER_SQL, ">> Loaded 0 player create definitions. DB table `playercreateinfo` is empty."); + sLog->outError(LOG_FILTER_SERVER_LOADING, ">> Loaded 0 player create definitions. DB table `playercreateinfo` is empty."); exit(1); } else @@ -3152,12 +3235,11 @@ void ObjectMgr::LoadPlayerInfo() uint32 oldMSTime = getMSTime(); std::string tableName = sWorld->getBoolConfig(CONFIG_START_ALL_SPELLS) ? "playercreateinfo_spell_custom" : "playercreateinfo_spell"; - QueryResult result = WorldDatabase.PQuery("SELECT race, class, Spell FROM %s", tableName.c_str()); + QueryResult result = WorldDatabase.PQuery("SELECT racemask, classmask, Spell FROM %s", tableName.c_str()); if (!result) { - sLog->outError(LOG_FILTER_SQL, ">> Loaded 0 player create spells. DB table `%s` is empty.", sWorld->getBoolConfig(CONFIG_START_ALL_SPELLS) ? "playercreateinfo_spell_custom" : "playercreateinfo_spell"); - + sLog->outError(LOG_FILTER_SERVER_LOADING, ">> Loaded 0 player create spells. DB table `%s` is empty.", sWorld->getBoolConfig(CONFIG_START_ALL_SPELLS) ? "playercreateinfo_spell_custom" : "playercreateinfo_spell"); } else { @@ -3166,41 +3248,43 @@ void ObjectMgr::LoadPlayerInfo() do { Field* fields = result->Fetch(); + uint32 raceMask = fields[0].GetUInt32(); + uint32 classMask = fields[1].GetUInt32(); + uint32 spellId = fields[2].GetUInt32(); - uint32 current_race = fields[0].GetUInt8(); - if (current_race >= MAX_RACES) + if (raceMask != 0 && !(raceMask & RACEMASK_ALL_PLAYABLE)) { - sLog->outError(LOG_FILTER_SQL, "Wrong race %u in `playercreateinfo_spell` table, ignoring.", current_race); + sLog->outError(LOG_FILTER_SQL, "Wrong race mask %u in `playercreateinfo_spell` table, ignoring.", raceMask); continue; } - uint32 current_class = fields[1].GetUInt8(); - if (current_class >= MAX_CLASSES) + if (classMask != 0 && !(classMask & CLASSMASK_ALL_PLAYABLE)) { - sLog->outError(LOG_FILTER_SQL, "Wrong class %u in `playercreateinfo_spell` table, ignoring.", current_class); + sLog->outError(LOG_FILTER_SQL, "Wrong class mask %u in `playercreateinfo_spell` table, ignoring.", classMask); continue; } - if (!current_race || !current_class) + for (uint32 raceIndex = RACE_HUMAN; raceIndex < MAX_RACES; ++raceIndex) { - uint32 min_race = current_race ? current_race : 1; - uint32 max_race = current_race ? current_race + 1 : MAX_RACES; - uint32 min_class = current_class ? current_class : 1; - uint32 max_class = current_class ? current_class + 1 : MAX_CLASSES; - for (uint32 r = min_race; r < max_race; ++r) - for (uint32 c = min_class; c < max_class; ++c) - if (PlayerInfo * info = _playerInfo[r][c]) - info->spell.push_back(fields[2].GetUInt32()); - } - else if (PlayerInfo * info = _playerInfo[current_race][current_class]) - info->spell.push_back(fields[2].GetUInt32()); - else - { - sLog->outError(LOG_FILTER_SQL, "Wrong race: %u, class: %u combination in `playercreateinfo_spell` table, ignoring.", current_race, current_class); - continue; + if (raceMask == 0 || ((1 << (raceIndex - 1)) & raceMask)) + { + for (uint32 classIndex = CLASS_WARRIOR; classIndex < MAX_CLASSES; ++classIndex) + { + if (classMask == 0 || ((1 << (classIndex - 1)) & classMask)) + { + if (PlayerInfo* info = _playerInfo[raceIndex][classIndex]) + { + info->spell.push_back(spellId); + ++count; + } + // We need something better here, the check is not accounting for spells used by multiple races/classes but not all of them. + // Either split the masks per class, or per race, which kind of kills the point yet. + // else if (raceMask != 0 && classMask != 0) + // sLog->outError(LOG_FILTER_SQL, "Racemask/classmask (%u/%u) combination was found containing an invalid race/class combination (%u/%u) in `playercreateinfo_spell` (Spell %u), ignoring.", raceMask, classMask, raceIndex, classIndex, spellId); + } + } + } } - - ++count; } while (result->NextRow()); @@ -3218,8 +3302,7 @@ void ObjectMgr::LoadPlayerInfo() if (!result) { - sLog->outError(LOG_FILTER_SQL, ">> Loaded 0 player create actions. DB table `playercreateinfo_action` is empty."); - + sLog->outError(LOG_FILTER_SERVER_LOADING, ">> Loaded 0 player create actions. DB table `playercreateinfo_action` is empty."); } else { @@ -3264,7 +3347,7 @@ void ObjectMgr::LoadPlayerInfo() if (!result) { - sLog->outError(LOG_FILTER_SQL, ">> Loaded 0 level health/mana definitions. DB table `game_event_condition` is empty."); + sLog->outError(LOG_FILTER_SERVER_LOADING, ">> Loaded 0 level health/mana definitions. DB table `game_event_condition` is empty."); exit(1); } @@ -3346,8 +3429,7 @@ void ObjectMgr::LoadPlayerInfo() if (!result) { - sLog->outError(LOG_FILTER_SQL, ">> Loaded 0 level stats definitions. DB table `player_levelstats` is empty."); - + sLog->outError(LOG_FILTER_SERVER_LOADING, ">> Loaded 0 level stats definitions. DB table `player_levelstats` is empty."); exit(1); } @@ -3459,8 +3541,7 @@ void ObjectMgr::LoadPlayerInfo() if (!result) { - sLog->outError(LOG_FILTER_SQL, ">> Loaded 0 xp for level definitions. DB table `player_xp_for_level` is empty."); - + sLog->outError(LOG_FILTER_SERVER_LOADING, ">> Loaded 0 xp for level definitions. DB table `player_xp_for_level` is empty."); exit(1); } @@ -3657,7 +3738,7 @@ void ObjectMgr::LoadQuests() " FROM quest_template"); if (!result) { - sLog->outError(LOG_FILTER_SQL, ">> Loaded 0 quests definitions. DB table `quest_template` is empty."); + sLog->outError(LOG_FILTER_SERVER_LOADING, ">> Loaded 0 quests definitions. DB table `quest_template` is empty."); return; } @@ -3728,14 +3809,14 @@ void ObjectMgr::LoadQuests() } } - if (qinfo->Flags & QUEST_FLAGS_AUTO_REWARDED) + if (qinfo->Flags & QUEST_FLAGS_TRACKING) { // at auto-reward can be rewarded only RewardChoiceItemId[0] for (int j = 1; j < QUEST_REWARD_CHOICES_COUNT; ++j ) { if (uint32 id = qinfo->RewardChoiceItemId[j]) { - sLog->outError(LOG_FILTER_SQL, "Quest %u has `RewardChoiceItemId%d` = %u but item from `RewardChoiceItemId%d` can't be rewarded with quest flag QUEST_FLAGS_AUTO_REWARDED.", + sLog->outError(LOG_FILTER_SQL, "Quest %u has `RewardChoiceItemId%d` = %u but item from `RewardChoiceItemId%d` can't be rewarded with quest flag QUEST_FLAGS_TRACKING.", qinfo->GetQuestId(), j+1, id, j+1); // no changes, quest ignore this data } @@ -4740,7 +4821,7 @@ void ObjectMgr::LoadWaypointScripts() for (ScriptMapMap::const_iterator itr = sWaypointScripts.begin(); itr != sWaypointScripts.end(); ++itr) actionSet.insert(itr->first); - PreparedStatement* stmt = WorldDatabase.GetPreparedStatement(WOLRD_SEL_WAYPOINT_DATA_ACTION); + PreparedStatement* stmt = WorldDatabase.GetPreparedStatement(WORLD_SEL_WAYPOINT_DATA_ACTION); PreparedQueryResult result = WorldDatabase.Query(stmt); if (result) @@ -5009,8 +5090,7 @@ void ObjectMgr::LoadInstanceEncounters() QueryResult result = WorldDatabase.Query("SELECT entry, creditType, creditEntry, lastEncounterDungeon FROM instance_encounters"); if (!result) { - sLog->outError(LOG_FILTER_SQL, ">> Loaded 0 instance encounters, table is empty!"); - + sLog->outError(LOG_FILTER_SERVER_LOADING, ">> Loaded 0 instance encounters, table is empty!"); return; } @@ -5030,7 +5110,7 @@ void ObjectMgr::LoadInstanceEncounters() continue; } - if (lastEncounterDungeon && !sLFGMgr->GetLFGDungeon(lastEncounterDungeon)) + if (lastEncounterDungeon && !sLFGMgr->GetLFGDungeonEntry(lastEncounterDungeon)) { sLog->outError(LOG_FILTER_SQL, "Table `instance_encounters` has an encounter %u (%s) marked as final for invalid dungeon id %u, skipped!", entry, dungeonEncounter->encounterName[0], lastEncounterDungeon); continue; @@ -6463,8 +6543,7 @@ void ObjectMgr::LoadExplorationBaseXP() if (!result) { - sLog->outError(LOG_FILTER_SQL, ">> Loaded 0 BaseXP definitions. DB table `exploration_basexp` is empty."); - + sLog->outError(LOG_FILTER_SERVER_LOADING, ">> Loaded 0 BaseXP definitions. DB table `exploration_basexp` is empty."); return; } @@ -6611,7 +6690,7 @@ void ObjectMgr::LoadReputationRewardRate() QueryResult result = WorldDatabase.Query("SELECT faction, quest_rate, quest_daily_rate, quest_weekly_rate, quest_monthly_rate, creature_rate, spell_rate FROM reputation_reward_rate"); if (!result) { - sLog->outError(LOG_FILTER_SQL, ">> Loaded `reputation_reward_rate`, table is empty!"); + sLog->outError(LOG_FILTER_SERVER_LOADING, ">> Loaded `reputation_reward_rate`, table is empty!"); return; } @@ -6699,8 +6778,7 @@ void ObjectMgr::LoadReputationOnKill() if (!result) { - sLog->outError(LOG_FILTER_SQL, ">> Loaded 0 creature award reputation definitions. DB table `creature_onkill_reputation` is empty."); - + sLog->outError(LOG_FILTER_SERVER_LOADING, ">> Loaded 0 creature award reputation definitions. DB table `creature_onkill_reputation` is empty."); return; } @@ -6878,8 +6956,7 @@ void ObjectMgr::LoadPointsOfInterest() if (!result) { - sLog->outError(LOG_FILTER_SQL, ">> Loaded 0 Points of Interest definitions. DB table `points_of_interest` is empty."); - + sLog->outError(LOG_FILTER_SERVER_LOADING, ">> Loaded 0 Points of Interest definitions. DB table `points_of_interest` is empty."); return; } @@ -6924,8 +7001,7 @@ void ObjectMgr::LoadQuestPOI() if (!result) { - sLog->outError(LOG_FILTER_SQL, ">> Loaded 0 quest POI definitions. DB table `quest_poi` is empty."); - + sLog->outError(LOG_FILTER_SERVER_LOADING, ">> Loaded 0 quest POI definitions. DB table `quest_poi` is empty."); return; } @@ -6992,8 +7068,7 @@ void ObjectMgr::LoadNPCSpellClickSpells() if (!result) { - sLog->outError(LOG_FILTER_SQL, ">> Loaded 0 spellclick spells. DB table `npc_spellclick_spells` is empty."); - + sLog->outError(LOG_FILTER_SERVER_LOADING, ">> Loaded 0 spellclick spells. DB table `npc_spellclick_spells` is empty."); return; } @@ -7095,7 +7170,7 @@ void ObjectMgr::LoadQuestRelationsHelper(QuestRelations& map, std::string const& if (!result) { - sLog->outError(LOG_FILTER_SQL, ">> Loaded 0 quest relations from `%s`, table is empty.", table.c_str()); + sLog->outError(LOG_FILTER_SERVER_LOADING, ">> Loaded 0 quest relations from `%s`, table is empty.", table.c_str()); return; } @@ -7470,7 +7545,7 @@ bool ObjectMgr::LoadTrinityStrings(const char* table, int32 min_value, int32 max if (!result) { if (min_value == MIN_TRINITY_STRING_ID) // error only in case internal strings - sLog->outError(LOG_FILTER_SQL, ">> Loaded 0 trinity strings. DB table `%s` is empty. Cannot continue.", table); + sLog->outError(LOG_FILTER_SERVER_LOADING, ">> Loaded 0 trinity strings. DB table `%s` is empty. Cannot continue.", table); else sLog->outInfo(LOG_FILTER_SERVER_LOADING, ">> Loaded 0 string templates. DB table `%s` is empty.", table); @@ -7546,8 +7621,7 @@ void ObjectMgr::LoadFishingBaseSkillLevel() if (!result) { - sLog->outError(LOG_FILTER_SQL, ">> Loaded 0 areas for fishing base skill level. DB table `skill_fishing_base_level` is empty."); - + sLog->outError(LOG_FILTER_SERVER_LOADING, ">> Loaded 0 areas for fishing base skill level. DB table `skill_fishing_base_level` is empty."); return; } @@ -7606,13 +7680,13 @@ uint32 ObjectMgr::GetAreaTriggerScriptId(uint32 trigger_id) return 0; } -SpellScriptsBounds ObjectMgr::GetSpellScriptsBounds(uint32 spell_id) +SpellScriptsBounds ObjectMgr::GetSpellScriptsBounds(uint32 spellId) { - return SpellScriptsBounds(_spellScriptsStore.lower_bound(spell_id), _spellScriptsStore.upper_bound(spell_id)); + return SpellScriptsBounds(_spellScriptsStore.equal_range(spellId)); } // this allows calculating base reputations to offline players, just by race and class -int32 ObjectMgr::GetBaseReputationOff(FactionEntry const* factionEntry, uint8 race, uint8 playerClass) +int32 ObjectMgr::GetBaseReputationOf(FactionEntry const* factionEntry, uint8 race, uint8 playerClass) { if (!factionEntry) return 0; @@ -7675,8 +7749,7 @@ void ObjectMgr::LoadGameTele() if (!result) { - sLog->outError(LOG_FILTER_SQL, ">> Loaded 0 GameTeleports. DB table `game_tele` is empty!"); - + sLog->outError(LOG_FILTER_SERVER_LOADING, ">> Loaded 0 GameTeleports. DB table `game_tele` is empty!"); return; } @@ -7815,8 +7888,7 @@ void ObjectMgr::LoadMailLevelRewards() if (!result) { - sLog->outError(LOG_FILTER_SQL, ">> Loaded 0 level dependent mail rewards. DB table `mail_level_reward` is empty."); - + sLog->outError(LOG_FILTER_SERVER_LOADING, ">> Loaded 0 level dependent mail rewards. DB table `mail_level_reward` is empty."); return; } @@ -8082,8 +8154,7 @@ void ObjectMgr::LoadGossipMenu() if (!result) { - sLog->outError(LOG_FILTER_SQL, ">> Loaded 0 gossip_menu entries. DB table `gossip_menu` is empty!"); - + sLog->outError(LOG_FILTER_SERVER_LOADING, ">> Loaded 0 gossip_menu entries. DB table `gossip_menu` is empty!"); return; } @@ -8128,8 +8199,7 @@ void ObjectMgr::LoadGossipMenuItems() if (!result) { - sLog->outError(LOG_FILTER_SQL, ">> Loaded 0 gossip_menu_option entries. DB table `gossip_menu_option` is empty!"); - + sLog->outError(LOG_FILTER_SERVER_LOADING, ">> Loaded 0 gossip_menu_option entries. DB table `gossip_menu_option` is empty!"); return; } @@ -8336,8 +8406,7 @@ void ObjectMgr::LoadScriptNames() if (!result) { - - sLog->outError(LOG_FILTER_SQL, ">> Loaded empty set of Script Names!"); + sLog->outError(LOG_FILTER_SERVER_LOADING, ">> Loaded empty set of Script Names!"); return; } @@ -8513,8 +8582,7 @@ void ObjectMgr::LoadFactionChangeAchievements() if (!result) { - sLog->outError(LOG_FILTER_SQL, ">> Loaded 0 faction change achievement pairs. DB table `player_factionchange_achievement` is empty."); - + sLog->outError(LOG_FILTER_SERVER_LOADING, ">> Loaded 0 faction change achievement pairs. DB table `player_factionchange_achievement` is empty."); return; } @@ -8528,11 +8596,11 @@ void ObjectMgr::LoadFactionChangeAchievements() uint32 horde = fields[1].GetUInt32(); if (!sAchievementMgr->GetAchievement(alliance)) - sLog->outError(LOG_FILTER_SQL, "Achievement %u referenced in `player_factionchange_achievement` does not exist, pair skipped!", alliance); + sLog->outError(LOG_FILTER_SQL, "Achievement %u (alliance_id) referenced in `player_factionchange_achievement` does not exist, pair skipped!", alliance); else if (!sAchievementMgr->GetAchievement(horde)) - sLog->outError(LOG_FILTER_SQL, "Achievement %u referenced in `player_factionchange_achievement` does not exist, pair skipped!", horde); + sLog->outError(LOG_FILTER_SQL, "Achievement %u (horde_id) referenced in `player_factionchange_achievement` does not exist, pair skipped!", horde); else - FactionChange_Achievements[alliance] = horde; + FactionChangeAchievements[alliance] = horde; ++count; } @@ -8563,11 +8631,11 @@ void ObjectMgr::LoadFactionChangeItems() uint32 horde = fields[1].GetUInt32(); if (!GetItemTemplate(alliance)) - sLog->outError(LOG_FILTER_SQL, "Item %u referenced in `player_factionchange_items` does not exist, pair skipped!", alliance); + sLog->outError(LOG_FILTER_SQL, "Item %u (alliance_id) referenced in `player_factionchange_items` does not exist, pair skipped!", alliance); else if (!GetItemTemplate(horde)) - sLog->outError(LOG_FILTER_SQL, "Item %u referenced in `player_factionchange_items` does not exist, pair skipped!", horde); + sLog->outError(LOG_FILTER_SQL, "Item %u (horde_id) referenced in `player_factionchange_items` does not exist, pair skipped!", horde); else - FactionChange_Items[alliance] = horde; + FactionChangeItems[alliance] = horde; ++count; } @@ -8576,16 +8644,15 @@ void ObjectMgr::LoadFactionChangeItems() sLog->outInfo(LOG_FILTER_SERVER_LOADING, ">> Loaded %u faction change item pairs in %u ms", count, GetMSTimeDiffToNow(oldMSTime)); } -void ObjectMgr::LoadFactionChangeSpells() +void ObjectMgr::LoadFactionChangeQuests() { uint32 oldMSTime = getMSTime(); - QueryResult result = WorldDatabase.Query("SELECT alliance_id, horde_id FROM player_factionchange_spells"); + QueryResult result = WorldDatabase.Query("SELECT alliance_id, horde_id FROM player_factionchange_quests"); if (!result) { - sLog->outError(LOG_FILTER_SQL, ">> Loaded 0 faction change spell pairs. DB table `player_factionchange_spells` is empty."); - + sLog->outError(LOG_FILTER_SERVER_LOADING, ">> Loaded 0 faction change quest pairs. DB table `player_factionchange_quests` is empty."); return; } @@ -8598,18 +8665,18 @@ void ObjectMgr::LoadFactionChangeSpells() uint32 alliance = fields[0].GetUInt32(); uint32 horde = fields[1].GetUInt32(); - if (!sSpellMgr->GetSpellInfo(alliance)) - sLog->outError(LOG_FILTER_SQL, "Spell %u referenced in `player_factionchange_spells` does not exist, pair skipped!", alliance); - else if (!sSpellMgr->GetSpellInfo(horde)) - sLog->outError(LOG_FILTER_SQL, "Spell %u referenced in `player_factionchange_spells` does not exist, pair skipped!", horde); + if (!sObjectMgr->GetQuestTemplate(alliance)) + sLog->outError(LOG_FILTER_SQL, "Quest %u (alliance_id) referenced in `player_factionchange_quests` does not exist, pair skipped!", alliance); + else if (!sObjectMgr->GetQuestTemplate(horde)) + sLog->outError(LOG_FILTER_SQL, "Quest %u (horde_id) referenced in `player_factionchange_quests` does not exist, pair skipped!", horde); else - FactionChange_Spells[alliance] = horde; + FactionChangeQuests[alliance] = horde; ++count; } while (result->NextRow()); - sLog->outInfo(LOG_FILTER_SERVER_LOADING, ">> Loaded %u faction change spell pairs in %u ms", count, GetMSTimeDiffToNow(oldMSTime)); + sLog->outInfo(LOG_FILTER_SERVER_LOADING, ">> Loaded %u faction change quest pairs in %u ms", count, GetMSTimeDiffToNow(oldMSTime)); } void ObjectMgr::LoadFactionChangeReputations() @@ -8634,11 +8701,11 @@ void ObjectMgr::LoadFactionChangeReputations() uint32 horde = fields[1].GetUInt32(); if (!sFactionStore.LookupEntry(alliance)) - sLog->outError(LOG_FILTER_SQL, "Reputation %u referenced in `player_factionchange_reputations` does not exist, pair skipped!", alliance); + sLog->outError(LOG_FILTER_SQL, "Reputation %u (alliance_id) referenced in `player_factionchange_reputations` does not exist, pair skipped!", alliance); else if (!sFactionStore.LookupEntry(horde)) - sLog->outError(LOG_FILTER_SQL, "Reputation %u referenced in `player_factionchange_reputations` does not exist, pair skipped!", horde); + sLog->outError(LOG_FILTER_SQL, "Reputation %u (horde_id) referenced in `player_factionchange_reputations` does not exist, pair skipped!", horde); else - FactionChange_Reputation[alliance] = horde; + FactionChangeReputation[alliance] = horde; ++count; } @@ -8647,6 +8714,41 @@ void ObjectMgr::LoadFactionChangeReputations() sLog->outInfo(LOG_FILTER_SERVER_LOADING, ">> Loaded %u faction change reputation pairs in %u ms", count, GetMSTimeDiffToNow(oldMSTime)); } +void ObjectMgr::LoadFactionChangeSpells() +{ + uint32 oldMSTime = getMSTime(); + + QueryResult result = WorldDatabase.Query("SELECT alliance_id, horde_id FROM player_factionchange_spells"); + + if (!result) + { + sLog->outError(LOG_FILTER_SERVER_LOADING, ">> Loaded 0 faction change spell pairs. DB table `player_factionchange_spells` is empty."); + return; + } + + uint32 count = 0; + + do + { + Field* fields = result->Fetch(); + + uint32 alliance = fields[0].GetUInt32(); + uint32 horde = fields[1].GetUInt32(); + + if (!sSpellMgr->GetSpellInfo(alliance)) + sLog->outError(LOG_FILTER_SQL, "Spell %u (alliance_id) referenced in `player_factionchange_spells` does not exist, pair skipped!", alliance); + else if (!sSpellMgr->GetSpellInfo(horde)) + sLog->outError(LOG_FILTER_SQL, "Spell %u (horde_id) referenced in `player_factionchange_spells` does not exist, pair skipped!", horde); + else + FactionChangeSpells[alliance] = horde; + + ++count; + } + while (result->NextRow()); + + sLog->outInfo(LOG_FILTER_SERVER_LOADING, ">> Loaded %u faction change spell pairs in %u ms", count, GetMSTimeDiffToNow(oldMSTime)); +} + void ObjectMgr::LoadFactionChangeTitles() { uint32 oldMSTime = getMSTime(); @@ -8669,11 +8771,11 @@ void ObjectMgr::LoadFactionChangeTitles() uint32 horde = fields[1].GetUInt32(); if (!sCharTitlesStore.LookupEntry(alliance)) - sLog->outError(LOG_FILTER_SQL, "Title %u referenced in `player_factionchange_title` does not exist, pair skipped!", alliance); + sLog->outError(LOG_FILTER_SQL, "Title %u (alliance_id) referenced in `player_factionchange_title` does not exist, pair skipped!", alliance); else if (!sCharTitlesStore.LookupEntry(horde)) - sLog->outError(LOG_FILTER_SQL, "Title %u referenced in `player_factionchange_title` does not exist, pair skipped!", horde); + sLog->outError(LOG_FILTER_SQL, "Title %u (horde_id) referenced in `player_factionchange_title` does not exist, pair skipped!", horde); else - FactionChange_Titles[alliance] = horde; + FactionChangeTitles[alliance] = horde; ++count; } diff --git a/src/server/game/Globals/ObjectMgr.h b/src/server/game/Globals/ObjectMgr.h index 9339684964c..88836e050aa 100644 --- a/src/server/game/Globals/ObjectMgr.h +++ b/src/server/game/Globals/ObjectMgr.h @@ -25,6 +25,7 @@ #include "Creature.h" #include "DynamicObject.h" #include "GameObject.h" +#include "TemporarySummon.h" #include "Corpse.h" #include "QuestDef.h" #include "ItemPrototype.h" @@ -62,6 +63,26 @@ struct PageText uint16 NextPage; }; +/// Key for storing temp summon data in TempSummonDataContainer +struct TempSummonGroupKey +{ + TempSummonGroupKey(uint32 summonerEntry, SummonerType summonerType, uint8 group) + : _summonerEntry(summonerEntry), _summonerType(summonerType), _summonGroup(group) + { + } + + bool operator<(TempSummonGroupKey const& rhs) const + { + // memcmp is only reliable if struct doesn't have any padding (packed) + return memcmp(this, &rhs, sizeof(TempSummonGroupKey)) < 0; + } + +private: + uint32 _summonerEntry; ///< Summoner's entry + SummonerType _summonerType; ///< Summoner's type, see SummonerType for available types + uint8 _summonGroup; ///< Summon's group id +}; + // GCC have alternative #pragma pack() syntax and old gcc version not support pack(pop), also any gcc version not support it at some platform #if defined(__GNUC__) #pragma pack() @@ -419,6 +440,7 @@ struct TrinityStringLocale typedef std::map<uint64, uint64> LinkedRespawnContainer; typedef UNORDERED_MAP<uint32, CreatureData> CreatureDataContainer; typedef UNORDERED_MAP<uint32, GameObjectData> GameObjectDataContainer; +typedef std::map<TempSummonGroupKey, std::vector<TempSummonData> > TempSummonDataContainer; typedef UNORDERED_MAP<uint32, CreatureLocale> CreatureLocaleContainer; typedef UNORDERED_MAP<uint32, GameObjectLocale> GameObjectLocaleContainer; typedef UNORDERED_MAP<uint32, ItemLocale> ItemLocaleContainer; @@ -661,9 +683,9 @@ class ObjectMgr CreatureTemplateContainer const* GetCreatureTemplates() const { return &_creatureTemplateStore; } CreatureModelInfo const* GetCreatureModelInfo(uint32 modelId); CreatureModelInfo const* GetCreatureModelRandomGender(uint32* displayID); - static uint32 ChooseDisplayId(uint32 team, const CreatureTemplate* cinfo, const CreatureData* data = NULL); - static void ChooseCreatureFlags(const CreatureTemplate* cinfo, uint32& npcflag, uint32& unit_flags, uint32& dynamicflags, const CreatureData* data = NULL); - EquipmentInfo const* GetEquipmentInfo(uint32 entry); + static uint32 ChooseDisplayId(CreatureTemplate const* cinfo, CreatureData const* data = NULL); + static void ChooseCreatureFlags(CreatureTemplate const* cinfo, uint32& npcflag, uint32& unit_flags, uint32& dynamicflags, CreatureData const* data = NULL); + EquipmentInfo const* GetEquipmentInfo(uint32 entry, int8& id); CreatureAddon const* GetCreatureAddon(uint32 lowguid); CreatureAddon const* GetCreatureTemplateAddon(uint32 entry); ItemTemplate const* GetItemTemplate(uint32 entry); @@ -758,7 +780,7 @@ class ObjectMgr AreaTrigger const* GetMapEntranceTrigger(uint32 Map) const; uint32 GetAreaTriggerScriptId(uint32 trigger_id); - SpellScriptsBounds GetSpellScriptsBounds(uint32 spell_id); + SpellScriptsBounds GetSpellScriptsBounds(uint32 spellId); RepRewardRate const* GetRepRewardRate(uint32 factionId) const { @@ -777,7 +799,7 @@ class ObjectMgr return NULL; } - int32 GetBaseReputationOff(FactionEntry const* factionEntry, uint8 race, uint8 playerClass); + int32 GetBaseReputationOf(FactionEntry const* factionEntry, uint8 race, uint8 playerClass); RepSpilloverTemplate const* GetRepSpilloverTemplate(uint32 factionId) const { @@ -876,6 +898,7 @@ class ObjectMgr void LoadCreatureTemplates(); void LoadCreatureTemplateAddons(); void CheckCreatureTemplate(CreatureTemplate const* cInfo); + void LoadTempSummons(); void LoadCreatures(); void LoadLinkedRespawn(); bool SetCreatureLinkedRespawn(uint32 guid, uint32 linkedGuid); @@ -981,6 +1004,24 @@ class ObjectMgr return _mapObjectGuidsStore[MAKE_PAIR32(mapid, spawnMode)][cell_id]; } + /** + * Gets temp summon data for all creatures of specified group. + * + * @param summonerId Summoner's entry. + * @param summonerType Summoner's type, see SummonerType for available types. + * @param group Id of required group. + * + * @return null if group was not found, otherwise reference to the creature group data + */ + std::vector<TempSummonData> const* GetSummonGroup(uint32 summonerId, SummonerType summonerType, uint8 group) const + { + TempSummonDataContainer::const_iterator itr = _tempSummonDataStore.find(TempSummonGroupKey(summonerId, summonerType, group)); + if (itr != _tempSummonDataStore.end()) + return &itr->second; + + return NULL; + } + CreatureData const* GetCreatureData(uint32 guid) const { CreatureDataContainer::const_iterator itr = _creatureDataStore.find(guid); @@ -1164,16 +1205,18 @@ class ObjectMgr value = data[loc_idx]; } - CharacterConversionMap FactionChange_Achievements; - CharacterConversionMap FactionChange_Items; - CharacterConversionMap FactionChange_Spells; - CharacterConversionMap FactionChange_Reputation; - CharacterConversionMap FactionChange_Titles; + CharacterConversionMap FactionChangeAchievements; + CharacterConversionMap FactionChangeItems; + CharacterConversionMap FactionChangeQuests; + CharacterConversionMap FactionChangeReputation; + CharacterConversionMap FactionChangeSpells; + CharacterConversionMap FactionChangeTitles; void LoadFactionChangeAchievements(); void LoadFactionChangeItems(); - void LoadFactionChangeSpells(); + void LoadFactionChangeQuests(); void LoadFactionChangeReputations(); + void LoadFactionChangeSpells(); void LoadFactionChangeTitles(); private: @@ -1294,6 +1337,8 @@ class ObjectMgr GameObjectDataContainer _gameObjectDataStore; GameObjectLocaleContainer _gameObjectLocaleStore; GameObjectTemplateContainer _gameObjectTemplateStore; + /// Stores temp summon data grouped by summoner's entry, summoner's type and group id + TempSummonDataContainer _tempSummonDataStore; ItemTemplateContainer _itemTemplateStore; ItemLocaleContainer _itemLocaleStore; diff --git a/src/server/game/Grids/Notifiers/GridNotifiers.h b/src/server/game/Grids/Notifiers/GridNotifiers.h index d2069a7f5f4..f52b6443872 100644 --- a/src/server/game/Grids/Notifiers/GridNotifiers.h +++ b/src/server/game/Grids/Notifiers/GridNotifiers.h @@ -968,7 +968,7 @@ namespace Trinity if (u->GetTypeId() == TYPEID_UNIT && ((Creature*)u)->isTotem()) return false; - if (i_funit->_IsValidAttackTarget(u, _spellInfo,i_obj->GetTypeId() == TYPEID_DYNAMICOBJECT ? i_obj : NULL) && i_obj->IsWithinDistInMap(u, i_range)) + if (i_funit->_IsValidAttackTarget(u, _spellInfo, i_obj->GetTypeId() == TYPEID_DYNAMICOBJECT ? i_obj : NULL) && i_obj->IsWithinDistInMap(u, i_range)) return true; return false; diff --git a/src/server/game/Grids/ObjectGridLoader.cpp b/src/server/game/Grids/ObjectGridLoader.cpp index 3fb74b6fdcc..5de63d91649 100644 --- a/src/server/game/Grids/ObjectGridLoader.cpp +++ b/src/server/game/Grids/ObjectGridLoader.cpp @@ -44,7 +44,7 @@ void ObjectGridEvacuator::Visit(CreatureMapType &m) } // for loading world object at grid loading (Corpses) -//TODO: to implement npc on transport, also need to load npcs at grid loading +/// @todo to implement npc on transport, also need to load npcs at grid loading class ObjectWorldLoader { public: @@ -121,7 +121,7 @@ void LoadHelper(CellCorpseSet const& cell_corpses, CellCoord &cell, CorpseMapTyp if (!obj) continue; - // TODO: this is a hack + /// @todo this is a hack // corpse's map should be reset when the map is unloaded // but it may still exist when the grid is unloaded but map is not // in that case map == currMap @@ -200,7 +200,7 @@ void ObjectGridUnloader::Visit(GridRefManager<T> &m) //Some creatures may summon other temp summons in CleanupsBeforeDelete() //So we need this even after cleaner (maybe we can remove cleaner) //Example: Flame Leviathan Turret 33139 is summoned when a creature is deleted - //TODO: Check if that script has the correct logic. Do we really need to summons something before deleting? + /// @todo Check if that script has the correct logic. Do we really need to summons something before deleting? obj->CleanupsBeforeDelete(); ///- object will get delinked from the manager when deleted delete obj; @@ -210,14 +210,15 @@ void ObjectGridUnloader::Visit(GridRefManager<T> &m) void ObjectGridStoper::Visit(CreatureMapType &m) { // stop any fights at grid de-activation and remove dynobjects created at cast by creatures - for (CreatureMapType::iterator iter=m.begin(); iter != m.end(); ++iter) + for (CreatureMapType::iterator iter = m.begin(); iter != m.end(); ++iter) { iter->getSource()->RemoveAllDynObjects(); if (iter->getSource()->isInCombat()) { iter->getSource()->CombatStop(); iter->getSource()->DeleteThreatList(); - iter->getSource()->AI()->EnterEvadeMode(); + if (iter->getSource()->IsAIEnabled) + iter->getSource()->AI()->EnterEvadeMode(); } } } diff --git a/src/server/game/Groups/Group.cpp b/src/server/game/Groups/Group.cpp index 734a1bfbaad..fe06c172e3f 100644 --- a/src/server/game/Groups/Group.cpp +++ b/src/server/game/Groups/Group.cpp @@ -634,7 +634,7 @@ void Group::ChangeLeader(uint64 guid) if (!player) return; - sScriptMgr->OnGroupChangeLeader(this, m_leaderGuid, guid); + sScriptMgr->OnGroupChangeLeader(this, guid, m_leaderGuid); if (!isBGGroup() && !isBFGroup()) { @@ -1496,7 +1496,7 @@ void Group::SendUpdateToPlayer(uint64 playerGUID, MemberSlot* slot) data << uint8(slot->roles); if (isLFGGroup()) { - data << uint8(sLFGMgr->GetState(m_guid) == LFG_STATE_FINISHED_DUNGEON ? 2 : 0); // FIXME - Dungeon save status? 2 = done + data << uint8(sLFGMgr->GetState(m_guid) == lfg::LFG_STATE_FINISHED_DUNGEON ? 2 : 0); // FIXME - Dungeon save status? 2 = done data << uint32(sLFGMgr->GetDungeon(m_guid)); } @@ -1818,7 +1818,7 @@ GroupJoinBattlegroundResult Group::CanJoinBattlegroundQueue(Battleground const* if (bgOrTemplate->GetTypeID() == BATTLEGROUND_RB && member->InBattlegroundQueue()) return ERR_IN_NON_RANDOM_BG; // check for deserter debuff in case not arena queue - if (bgOrTemplate->GetTypeID() != BATTLEGROUND_AA && !member->CanJoinToBattleground()) + if (bgOrTemplate->GetTypeID() != BATTLEGROUND_AA && !member->CanJoinToBattleground(bgOrTemplate)) return ERR_GROUP_JOIN_BATTLEGROUND_DESERTERS; // check if member can join any more battleground queues if (!member->HasFreeBattlegroundQueueId()) diff --git a/src/server/game/Groups/Group.h b/src/server/game/Groups/Group.h index e81afe78513..356a1a59663 100644 --- a/src/server/game/Groups/Group.h +++ b/src/server/game/Groups/Group.h @@ -156,7 +156,7 @@ struct InstanceGroupBind }; /** request member stats checken **/ -/** todo: uninvite people that not accepted invite **/ +/// @todo uninvite people that not accepted invite class Group { public: diff --git a/src/server/game/Guilds/Guild.cpp b/src/server/game/Guilds/Guild.cpp index fc80a7d7635..158a20d67d1 100644 --- a/src/server/game/Guilds/Guild.cpp +++ b/src/server/game/Guilds/Guild.cpp @@ -235,7 +235,7 @@ void Guild::BankEventLogEntry::WritePacket(WorldPacket& data) const data << uint8(m_eventType); data << uint64(MAKE_NEW_GUID(m_playerGuid, 0, HIGHGUID_PLAYER)); - switch(m_eventType) + switch (m_eventType) { case GUILD_BANK_LOG_DEPOSIT_ITEM: case GUILD_BANK_LOG_WITHDRAW_ITEM: @@ -983,12 +983,14 @@ void Guild::BankMoveItemData::LogBankEvent(SQLTransaction& trans, MoveItemData* void Guild::BankMoveItemData::LogAction(MoveItemData* pFrom) const { MoveItemData::LogAction(pFrom); - if (!pFrom->IsBank() && sWorld->getBoolConfig(CONFIG_GM_LOG_TRADE) && !AccountMgr::IsPlayerAccount(m_pPlayer->GetSession()->GetSecurity())) // TODO: move to scripts + if (!pFrom->IsBank() && m_pPlayer->GetSession()->HasPermission(RBAC_PERM_LOG_GM_TRADE)) /// @todo Move this to scripts + { sLog->outCommand(m_pPlayer->GetSession()->GetAccountId(), "GM %s (Account: %u) deposit item: %s (Entry: %d Count: %u) to guild bank (Guild ID: %u)", m_pPlayer->GetName().c_str(), m_pPlayer->GetSession()->GetAccountId(), pFrom->GetItem()->GetTemplate()->Name1.c_str(), pFrom->GetItem()->GetEntry(), pFrom->GetItem()->GetCount(), m_pGuild->GetId()); + } } Item* Guild::BankMoveItemData::_StoreItem(SQLTransaction& trans, BankTab* pTab, Item* pItem, ItemPosCount& pos, bool clone) const @@ -1729,7 +1731,7 @@ void Guild::HandleMemberDepositMoney(WorldSession* session, uint32 amount) std::string aux = ByteArrayToHexStr(reinterpret_cast<uint8*>(&amount), 8, true); _BroadcastEvent(GE_BANK_MONEY_CHANGED, 0, aux.c_str()); - if (!AccountMgr::IsPlayerAccount(player->GetSession()->GetSecurity()) && sWorld->getBoolConfig(CONFIG_GM_LOG_TRADE)) + if (player->GetSession()->HasPermission(RBAC_PERM_LOG_GM_TRADE)) { sLog->outCommand(player->GetSession()->GetAccountId(), "GM %s (Account: %u) deposit money (Amount: %u) to guild bank (Guild ID %u)", @@ -1755,16 +1757,20 @@ bool Guild::HandleMemberWithdrawMoney(WorldSession* session, uint32 amount, bool sScriptMgr->OnGuildMemberWitdrawMoney(this, player, amount, repair); SQLTransaction trans = CharacterDatabase.BeginTransaction(); - // Update remaining money amount - member->UpdateBankWithdrawValue(trans, GUILD_BANK_MAX_TABS, amount); - // Remove money from bank - _ModifyBankMoney(trans, amount, false); // Add money to player (if required) if (!repair) { - player->ModifyMoney(amount); + if (!player->ModifyMoney(amount)) + return false; + player->SaveGoldToDB(trans); } + + // Update remaining money amount + member->UpdateBankWithdrawValue(trans, GUILD_BANK_MAX_TABS, amount); + // Remove money from bank + _ModifyBankMoney(trans, amount, false); + // Log guild bank event _LogBankEvent(trans, repair ? GUILD_BANK_LOG_REPAIR_MONEY : GUILD_BANK_LOG_WITHDRAW_MONEY, uint8(0), player->GetGUIDLow(), amount); CharacterDatabase.CommitTransaction(trans); @@ -2724,7 +2730,7 @@ bool Guild::_DoItemsMove(MoveItemData* pSrc, MoveItemData* pDest, bool sendError if (!pSrc->CanStore(pDestItem, true, true)) return false; - // GM LOG (TODO: move to scripts) + // GM LOG (@todo move to scripts) pDest->LogAction(pSrc); if (swap) pSrc->LogAction(pDest); @@ -2868,7 +2874,7 @@ void Guild::_SendBankList(WorldSession* session /* = NULL*/, uint8 tabId /*= 0*/ sLog->outDebug(LOG_FILTER_GUILD, "SMSG_GUILD_BANK_LIST [%s]: TabId: %u, FullSlots: %u, slots: %d", session->GetPlayerInfo().c_str(), tabId, sendAllSlots, numSlots); } - else // TODO - Probably this is just sent to session + those that have sent CMSG_GUILD_BANKER_ACTIVATE + else /// @todo - Probably this is just sent to session + those that have sent CMSG_GUILD_BANKER_ACTIVATE { for (Members::const_iterator itr = m_members.begin(); itr != m_members.end(); ++itr) { diff --git a/src/server/game/Handlers/AddonHandler.cpp b/src/server/game/Handlers/AddonHandler.cpp index 7e62280f17c..68c93259fcb 100644 --- a/src/server/game/Handlers/AddonHandler.cpp +++ b/src/server/game/Handlers/AddonHandler.cpp @@ -30,7 +30,7 @@ AddonHandler::~AddonHandler() { } -bool AddonHandler::BuildAddonPacket(WorldPacket* Source, WorldPacket* Target) +bool AddonHandler::BuildAddonPacket(WorldPacket* source, WorldPacket* target) { ByteBuffer AddOnPacked; uLongf AddonRealSize; @@ -38,10 +38,10 @@ bool AddonHandler::BuildAddonPacket(WorldPacket* Source, WorldPacket* Target) uint32 TempValue; // broken addon packet, can't be received from real client - if (Source->rpos() + 4 > Source->size()) + if (source->rpos() + 4 > source->size()) return false; - *Source >> TempValue; // get real size of the packed structure + *source >> TempValue; // get real size of the packed structure // empty addon packet, nothing process, can't be received from real client if (!TempValue) @@ -49,13 +49,13 @@ bool AddonHandler::BuildAddonPacket(WorldPacket* Source, WorldPacket* Target) AddonRealSize = TempValue; // temp value because ZLIB only excepts uLongf - CurrentPosition = Source->rpos(); // get the position of the pointer in the structure + CurrentPosition = source->rpos(); // get the position of the pointer in the structure AddOnPacked.resize(AddonRealSize); // resize target for zlib action - if (!uncompress(const_cast<uint8*>(AddOnPacked.contents()), &AddonRealSize, const_cast<uint8*>((*Source).contents() + CurrentPosition), (*Source).size() - CurrentPosition)!= Z_OK) + if (!uncompress(AddOnPacked.contents(), &AddonRealSize, source->contents() + CurrentPosition, source->size() - CurrentPosition)!= Z_OK) { - Target->Initialize(SMSG_ADDON_INFO); + target->Initialize(SMSG_ADDON_INFO); uint32 addonsCount; AddOnPacked >> addonsCount; // addons count? @@ -81,14 +81,14 @@ bool AddonHandler::BuildAddonPacket(WorldPacket* Source, WorldPacket* Target) sLog->outDebug(LOG_FILTER_NETWORKIO, "ADDON: Name: %s, Enabled: 0x%x, CRC: 0x%x, Unknown2: 0x%x", addonName.c_str(), enabled, crc, unk2); uint8 state = (enabled ? 2 : 1); - *Target << uint8(state); + *target << uint8(state); uint8 unk1 = (enabled ? 1 : 0); - *Target << uint8(unk1); + *target << uint8(unk1); if (unk1) { uint8 unk = (crc != 0x4c1c776d); // If addon is Standard addon CRC - *Target << uint8(unk); + *target << uint8(unk); if (unk) { unsigned char tdata[256] = @@ -110,18 +110,18 @@ bool AddonHandler::BuildAddonPacket(WorldPacket* Source, WorldPacket* Target) 0xC3, 0xFB, 0x1B, 0x8C, 0x29, 0xEF, 0x8E, 0xE5, 0x34, 0xCB, 0xD1, 0x2A, 0xCE, 0x79, 0xC3, 0x9A, 0x0D, 0x36, 0xEA, 0x01, 0xE0, 0xAA, 0x91, 0x20, 0x54, 0xF0, 0x72, 0xD8, 0x1E, 0xC7, 0x89, 0xD2 }; - Target->append(tdata, sizeof(tdata)); + target->append(tdata, sizeof(tdata)); } - *Target << uint32(0); + *target << uint32(0); } uint8 unk3 = (enabled ? 0 : 1); - *Target << uint8(unk3); + *target << uint8(unk3); if (unk3) { // String, 256 (null terminated?) - *Target << uint8(0); + *target << uint8(0); } } @@ -129,7 +129,7 @@ bool AddonHandler::BuildAddonPacket(WorldPacket* Source, WorldPacket* Target) AddOnPacked >> unk4; uint32 count = 0; - *Target << uint32(count); + *target << uint32(count); if (AddOnPacked.rpos() != AddOnPacked.size()) sLog->outDebug(LOG_FILTER_NETWORKIO, "packet under read!"); diff --git a/src/server/game/Handlers/AuctionHouseHandler.cpp b/src/server/game/Handlers/AuctionHouseHandler.cpp index 6fc88f441bb..47ad7ffa568 100644 --- a/src/server/game/Handlers/AuctionHouseHandler.cpp +++ b/src/server/game/Handlers/AuctionHouseHandler.cpp @@ -245,7 +245,7 @@ void WorldSession::HandleAuctionSellItem(WorldPacket& recvData) // Required stack size of auction matches to current item stack size, just move item to auctionhouse if (itemsCount == 1 && item->GetCount() == count[i]) { - if (GetSecurity() > SEC_PLAYER && sWorld->getBoolConfig(CONFIG_GM_LOG_TRADE)) + if (HasPermission(RBAC_PERM_LOG_GM_TRADE)) { sLog->outCommand(GetAccountId(), "GM %s (Account: %u) create auction: %s (Entry: %u Count: %u)", GetPlayerName().c_str(), GetAccountId(), item->GetTemplate()->Name1.c_str(), item->GetEntry(), item->GetCount()); @@ -291,7 +291,7 @@ void WorldSession::HandleAuctionSellItem(WorldPacket& recvData) return; } - if (GetSecurity() > SEC_PLAYER && sWorld->getBoolConfig(CONFIG_GM_LOG_TRADE)) + if (HasPermission(RBAC_PERM_LOG_GM_TRADE)) { sLog->outCommand(GetAccountId(), "GM %s (Account: %u) create auction: %s (Entry: %u Count: %u)", GetPlayerName().c_str(), GetAccountId(), newItem->GetTemplate()->Name1.c_str(), newItem->GetEntry(), newItem->GetCount()); diff --git a/src/server/game/Handlers/BattleGroundHandler.cpp b/src/server/game/Handlers/BattleGroundHandler.cpp index a7df171b1c5..0213df31630 100644 --- a/src/server/game/Handlers/BattleGroundHandler.cpp +++ b/src/server/game/Handlers/BattleGroundHandler.cpp @@ -138,7 +138,7 @@ void WorldSession::HandleBattlemasterJoinOpcode(WorldPacket& recvData) } // check Deserter debuff - if (!_player->CanJoinToBattleground()) + if (!_player->CanJoinToBattleground(bg)) { WorldPacket data; sBattlegroundMgr->BuildGroupJoinedBattlegroundPacket(&data, ERR_GROUP_JOIN_BATTLEGROUND_DESERTERS); @@ -187,7 +187,7 @@ void WorldSession::HandleBattlemasterJoinOpcode(WorldPacket& recvData) WorldPacket data; // send status packet (in queue) - sBattlegroundMgr->BuildBattlegroundStatusPacket(&data, bg, queueSlot, STATUS_WAIT_QUEUE, avgTime, 0, ginfo->ArenaType); + sBattlegroundMgr->BuildBattlegroundStatusPacket(&data, bg, queueSlot, STATUS_WAIT_QUEUE, avgTime, 0, ginfo->ArenaType, 0); SendPacket(&data); sLog->outDebug(LOG_FILTER_BATTLEGROUND, "Battleground: player joined queue for bg queue type %u bg type %u: GUID %u, NAME %s", bgQueueTypeId, bgTypeId, _player->GetGUIDLow(), _player->GetName().c_str()); @@ -233,7 +233,7 @@ void WorldSession::HandleBattlemasterJoinOpcode(WorldPacket& recvData) uint32 queueSlot = member->AddBattlegroundQueueId(bgQueueTypeId); // send status packet (in queue) - sBattlegroundMgr->BuildBattlegroundStatusPacket(&data, bg, queueSlot, STATUS_WAIT_QUEUE, avgTime, 0, ginfo->ArenaType); + sBattlegroundMgr->BuildBattlegroundStatusPacket(&data, bg, queueSlot, STATUS_WAIT_QUEUE, avgTime, 0, ginfo->ArenaType, 0); member->GetSession()->SendPacket(&data); sBattlegroundMgr->BuildGroupJoinedBattlegroundPacket(&data, err); member->GetSession()->SendPacket(&data); @@ -413,7 +413,7 @@ void WorldSession::HandleBattleFieldPortOpcode(WorldPacket &recvData) if (action == 1 && ginfo.ArenaType == 0) { //if player is trying to enter battleground (not arena!) and he has deserter debuff, we must just remove him from queue - if (!_player->CanJoinToBattleground()) + if (!_player->CanJoinToBattleground(bg)) { //send bg command result to show nice message WorldPacket data2; @@ -453,8 +453,9 @@ void WorldSession::HandleBattleFieldPortOpcode(WorldPacket &recvData) _player->CleanupAfterTaxiFlight(); } - sBattlegroundMgr->BuildBattlegroundStatusPacket(&data, bg, queueSlot, STATUS_IN_PROGRESS, 0, bg->GetStartTime(), bg->GetArenaType()); + sBattlegroundMgr->BuildBattlegroundStatusPacket(&data, bg, queueSlot, STATUS_IN_PROGRESS, 0, bg->GetStartTime(), bg->GetArenaType(), ginfo.Team); _player->GetSession()->SendPacket(&data); + // remove battleground queue status from BGmgr bgQueue.RemovePlayer(_player->GetGUID(), false); // this is still needed here if battleground "jumping" shouldn't add deserter debuff @@ -466,6 +467,7 @@ void WorldSession::HandleBattleFieldPortOpcode(WorldPacket &recvData) _player->SetBattlegroundId(bg->GetInstanceID(), bgTypeId); // set the destination team _player->SetBGTeam(ginfo.Team); + // bg->HandleBeforeTeleportToBattleground(_player); sBattlegroundMgr->SendToBattleground(_player, ginfo.IsInvitedToBGInstanceGUID, bgTypeId); // add only in HandleMoveWorldPortAck() @@ -489,7 +491,7 @@ void WorldSession::HandleBattleFieldPortOpcode(WorldPacket &recvData) } } _player->RemoveBattlegroundQueueId(bgQueueTypeId); // must be called this way, because if you move this call to queue->removeplayer, it causes bugs - sBattlegroundMgr->BuildBattlegroundStatusPacket(&data, bg, queueSlot, STATUS_NONE, 0, 0, 0); + sBattlegroundMgr->BuildBattlegroundStatusPacket(&data, bg, queueSlot, STATUS_NONE, 0, 0, 0, 0); bgQueue.RemovePlayer(_player->GetGUID(), true); // player left queue, we should update it - do not update Arena Queue if (!ginfo.ArenaType) @@ -541,7 +543,7 @@ void WorldSession::HandleBattlefieldStatusOpcode(WorldPacket & /*recvData*/) { // this line is checked, i only don't know if GetStartTime is changing itself after bg end! // send status in Battleground - sBattlegroundMgr->BuildBattlegroundStatusPacket(&data, bg, i, STATUS_IN_PROGRESS, bg->GetEndTime(), bg->GetStartTime(), arenaType); + sBattlegroundMgr->BuildBattlegroundStatusPacket(&data, bg, i, STATUS_IN_PROGRESS, bg->GetEndTime(), bg->GetStartTime(), arenaType, _player->GetBGTeam()); SendPacket(&data); continue; } @@ -559,7 +561,7 @@ void WorldSession::HandleBattlefieldStatusOpcode(WorldPacket & /*recvData*/) continue; uint32 remainingTime = getMSTimeDiff(getMSTime(), ginfo.RemoveInviteTime); // send status invited to Battleground - sBattlegroundMgr->BuildBattlegroundStatusPacket(&data, bg, i, STATUS_WAIT_JOIN, remainingTime, 0, arenaType); + sBattlegroundMgr->BuildBattlegroundStatusPacket(&data, bg, i, STATUS_WAIT_JOIN, remainingTime, 0, arenaType, 0); SendPacket(&data); } else @@ -575,7 +577,7 @@ void WorldSession::HandleBattlefieldStatusOpcode(WorldPacket & /*recvData*/) uint32 avgTime = bgQueue.GetAverageQueueWaitTime(&ginfo, bracketEntry->GetBracketId()); // send status in Battleground Queue - sBattlegroundMgr->BuildBattlegroundStatusPacket(&data, bg, i, STATUS_WAIT_QUEUE, avgTime, getMSTimeDiff(ginfo.JoinTime, getMSTime()), arenaType); + sBattlegroundMgr->BuildBattlegroundStatusPacket(&data, bg, i, STATUS_WAIT_QUEUE, avgTime, getMSTimeDiff(ginfo.JoinTime, getMSTime()), arenaType, 0); SendPacket(&data); } } @@ -727,7 +729,7 @@ void WorldSession::HandleBattlemasterJoinArena(WorldPacket& recvData) uint32 queueSlot = member->AddBattlegroundQueueId(bgQueueTypeId); // send status packet (in queue) - sBattlegroundMgr->BuildBattlegroundStatusPacket(&data, bg, queueSlot, STATUS_WAIT_QUEUE, avgTime, 0, arenatype); + sBattlegroundMgr->BuildBattlegroundStatusPacket(&data, bg, queueSlot, STATUS_WAIT_QUEUE, avgTime, 0, arenatype, 0); member->GetSession()->SendPacket(&data); sBattlegroundMgr->BuildGroupJoinedBattlegroundPacket(&data, err); member->GetSession()->SendPacket(&data); @@ -742,7 +744,7 @@ void WorldSession::HandleBattlemasterJoinArena(WorldPacket& recvData) WorldPacket data; // send status packet (in queue) - sBattlegroundMgr->BuildBattlegroundStatusPacket(&data, bg, queueSlot, STATUS_WAIT_QUEUE, avgTime, 0, arenatype); + sBattlegroundMgr->BuildBattlegroundStatusPacket(&data, bg, queueSlot, STATUS_WAIT_QUEUE, avgTime, 0, arenatype, 0); SendPacket(&data); sLog->outDebug(LOG_FILTER_BATTLEGROUND, "Battleground: player joined queue for arena, skirmish, bg queue type %u bg type %u: GUID %u, NAME %s", bgQueueTypeId, bgTypeId, _player->GetGUIDLow(), _player->GetName().c_str()); } diff --git a/src/server/game/Handlers/BattlefieldHandler.cpp b/src/server/game/Handlers/BattlefieldHandler.cpp index 0263b64456f..4a29dee4fb0 100644 --- a/src/server/game/Handlers/BattlefieldHandler.cpp +++ b/src/server/game/Handlers/BattlefieldHandler.cpp @@ -60,7 +60,7 @@ void WorldSession::SendBfInvitePlayerToQueue(uint32 BattleId) //Param2:(ZoneId) the zone where the battle is (4197 for wg) //Param3:(CanQueue) if able to queue //Param4:(Full) on log in is full -void WorldSession::SendBfQueueInviteResponse(uint32 BattleId,uint32 ZoneId, bool CanQueue, bool Full) +void WorldSession::SendBfQueueInviteResponse(uint32 BattleId, uint32 ZoneId, bool CanQueue, bool Full) { WorldPacket data(SMSG_BATTLEFIELD_MGR_QUEUE_REQUEST_RESPONSE, 11); data << uint32(BattleId); diff --git a/src/server/game/Handlers/CalendarHandler.cpp b/src/server/game/Handlers/CalendarHandler.cpp index 9dbc4bec199..fd8b5f08460 100644 --- a/src/server/game/Handlers/CalendarHandler.cpp +++ b/src/server/game/Handlers/CalendarHandler.cpp @@ -25,7 +25,7 @@ SMSG_CALENDAR_EVENT_INVITE_NOTES_ALERT [ uint64(inviteId), string(Text) ] SMSG_CALENDAR_EVENT_INVITE_STATUS_ALERT [ uint64(eventId), uint32(eventTime), uint32(unkFlag), uint8(deletePending) ] SMSG_CALENDAR_RAID_LOCKOUT_UPDATED SendCalendarRaidLockoutUpdated(InstanceSave const* save) ------ TODO ----- +@todo Finish complains' handling - what to do with received complains and how to respond? Find out what to do with all "not used yet" opcodes @@ -57,9 +57,9 @@ void WorldSession::HandleCalendarGetCalendar(WorldPacket& /*recvData*/) WorldPacket data(SMSG_CALENDAR_SEND_CALENDAR, 1000); // Average size if no instance - std::vector<CalendarInvite*> invites = sCalendarMgr->GetPlayerInvites(guid); + CalendarInviteStore invites = sCalendarMgr->GetPlayerInvites(guid); data << uint32(invites.size()); - for (std::vector<CalendarInvite*>::const_iterator itr = invites.begin(); itr != invites.end(); ++itr) + for (CalendarInviteStore::const_iterator itr = invites.begin(); itr != invites.end(); ++itr) { data << uint64((*itr)->GetEventId()); data << uint64((*itr)->GetInviteId()); @@ -147,7 +147,7 @@ void WorldSession::HandleCalendarGetCalendar(WorldPacket& /*recvData*/) data << uint32(boundCounter); data.append(dataBuffer); - // TODO: Fix this, how we do know how many and what holidays to send? + /// @todo Fix this, how we do know how many and what holidays to send? uint32 holidayCount = 0; data << uint32(holidayCount); for (uint32 i = 0; i < holidayCount; ++i) @@ -347,9 +347,9 @@ void WorldSession::HandleCalendarCopyEvent(WorldPacket& recvData) newEvent->SetEventTime(time_t(time)); sCalendarMgr->AddEvent(newEvent, CALENDAR_SENDTYPE_COPY); - std::vector<CalendarInvite*> invites = sCalendarMgr->GetEventInvites(eventId); + CalendarInviteStore invites = sCalendarMgr->GetEventInvites(eventId); - for (std::vector<CalendarInvite*>::const_iterator itr = invites.begin(); itr != invites.end(); ++itr) + for (CalendarInviteStore::const_iterator itr = invites.begin(); itr != invites.end(); ++itr) sCalendarMgr->AddInvite(newEvent, new CalendarInvite(**itr, sCalendarMgr->GetFreeInviteId(), newEvent->GetEventId())); // should we change owner when somebody makes a copy of event owned by another person? diff --git a/src/server/game/Handlers/CharacterHandler.cpp b/src/server/game/Handlers/CharacterHandler.cpp index d8e50be11f0..f1ec017962e 100644 --- a/src/server/game/Handlers/CharacterHandler.cpp +++ b/src/server/game/Handlers/CharacterHandler.cpp @@ -215,7 +215,7 @@ void WorldSession::HandleCharEnum(PreparedQueryResult result) data << num; - _allowedCharsToLogin.clear(); + _legitCharacters.clear(); if (result) { do @@ -224,7 +224,9 @@ void WorldSession::HandleCharEnum(PreparedQueryResult result) sLog->outInfo(LOG_FILTER_NETWORKIO, "Loading char guid %u from account %u.", guidlow, GetAccountId()); if (Player::BuildEnumData(result, &data)) { - _allowedCharsToLogin.insert(guidlow); + _legitCharacters.insert(guidlow); + if (!sWorld->HasCharacterNameData(guidlow)) // This can happen if characters are inserted into the database manually. Core hasn't loaded name data yet. + sWorld->AddCharacterNameData(guidlow, (*result)[1].GetString(), (*result)[4].GetUInt8(), (*result)[2].GetUInt8(), (*result)[3].GetUInt8(), (*result)[7].GetUInt8()); ++num; } } @@ -272,7 +274,7 @@ void WorldSession::HandleCharCreateOpcode(WorldPacket& recvData) WorldPacket data(SMSG_CHAR_CREATE, 1); // returned with diff.values in all cases - if (AccountMgr::IsPlayerAccount(GetSecurity())) + if (!HasPermission(RBAC_PERM_SKIP_CHECK_CHARACTER_CREATION_TEAMMASK)) { if (uint32 mask = sWorld->getIntConfig(CONFIG_CHARACTER_CREATING_DISABLED)) { @@ -281,13 +283,17 @@ void WorldSession::HandleCharCreateOpcode(WorldPacket& recvData) uint32 team = Player::TeamForRace(race_); switch (team) { - case ALLIANCE: disabled = mask & (1 << 0); break; - case HORDE: disabled = mask & (1 << 1); break; + case ALLIANCE: + disabled = mask & (1 << 0); + break; + case HORDE: + disabled = mask & (1 << 1); + break; } if (disabled) { - data << (uint8)CHAR_CREATE_DISABLED; + data << uint8(CHAR_CREATE_DISABLED); SendPacket(&data); return; } @@ -297,7 +303,7 @@ void WorldSession::HandleCharCreateOpcode(WorldPacket& recvData) ChrClassesEntry const* classEntry = sChrClassesStore.LookupEntry(class_); if (!classEntry) { - data << (uint8)CHAR_CREATE_FAILED; + data << uint8(CHAR_CREATE_FAILED); SendPacket(&data); sLog->outError(LOG_FILTER_NETWORKIO, "Class (%u) not found in DBC while creating new char for account (ID: %u): wrong DBC files or cheater?", class_, GetAccountId()); return; @@ -306,7 +312,7 @@ void WorldSession::HandleCharCreateOpcode(WorldPacket& recvData) ChrRacesEntry const* raceEntry = sChrRacesStore.LookupEntry(race_); if (!raceEntry) { - data << (uint8)CHAR_CREATE_FAILED; + data << uint8(CHAR_CREATE_FAILED); SendPacket(&data); sLog->outError(LOG_FILTER_NETWORKIO, "Race (%u) not found in DBC while creating new char for account (ID: %u): wrong DBC files or cheater?", race_, GetAccountId()); return; @@ -315,7 +321,7 @@ void WorldSession::HandleCharCreateOpcode(WorldPacket& recvData) // prevent character creating Expansion race without Expansion account if (raceEntry->expansion > Expansion()) { - data << (uint8)CHAR_CREATE_EXPANSION; + data << uint8(CHAR_CREATE_EXPANSION); sLog->outError(LOG_FILTER_NETWORKIO, "Expansion %u account:[%d] tried to Create character with expansion %u race (%u)", Expansion(), GetAccountId(), raceEntry->expansion, race_); SendPacket(&data); return; @@ -324,13 +330,13 @@ void WorldSession::HandleCharCreateOpcode(WorldPacket& recvData) // prevent character creating Expansion class without Expansion account if (classEntry->expansion > Expansion()) { - data << (uint8)CHAR_CREATE_EXPANSION_CLASS; + data << uint8(CHAR_CREATE_EXPANSION_CLASS); sLog->outError(LOG_FILTER_NETWORKIO, "Expansion %u account:[%d] tried to Create character with expansion %u class (%u)", Expansion(), GetAccountId(), classEntry->expansion, class_); SendPacket(&data); return; } - if (AccountMgr::IsPlayerAccount(GetSecurity())) + if (!HasPermission(RBAC_PERM_SKIP_CHECK_CHARACTER_CREATION_RACEMASK)) { uint32 raceMaskDisabled = sWorld->getIntConfig(CONFIG_CHARACTER_CREATING_DISABLED_RACEMASK); if ((1 << (race_ - 1)) & raceMaskDisabled) @@ -339,7 +345,10 @@ void WorldSession::HandleCharCreateOpcode(WorldPacket& recvData) SendPacket(&data); return; } + } + if (!HasPermission(RBAC_PERM_SKIP_CHECK_CHARACTER_CREATION_CLASSMASK)) + { uint32 classMaskDisabled = sWorld->getIntConfig(CONFIG_CHARACTER_CREATING_DISABLED_CLASSMASK); if ((1 << (class_ - 1)) & classMaskDisabled) { @@ -352,7 +361,7 @@ void WorldSession::HandleCharCreateOpcode(WorldPacket& recvData) // prevent character creating with invalid name if (!normalizePlayerName(name)) { - data << (uint8)CHAR_NAME_NO_NAME; + data << uint8(CHAR_NAME_NO_NAME); SendPacket(&data); sLog->outError(LOG_FILTER_NETWORKIO, "Account:[%d] but tried to Create character with empty [name] ", GetAccountId()); return; @@ -367,29 +376,32 @@ void WorldSession::HandleCharCreateOpcode(WorldPacket& recvData) return; } - if (AccountMgr::IsPlayerAccount(GetSecurity()) && sObjectMgr->IsReservedName(name)) + if (!HasPermission(RBAC_PERM_SKIP_CHECK_CHARACTER_CREATION_RESERVEDNAME) && sObjectMgr->IsReservedName(name)) { - data << (uint8)CHAR_NAME_RESERVED; + data << uint8(CHAR_NAME_RESERVED); SendPacket(&data); return; } - // speedup check for heroic class disabled case - uint32 heroic_free_slots = sWorld->getIntConfig(CONFIG_HEROIC_CHARACTERS_PER_REALM); - if (heroic_free_slots == 0 && AccountMgr::IsPlayerAccount(GetSecurity()) && class_ == CLASS_DEATH_KNIGHT) + if (class_ == CLASS_DEATH_KNIGHT && !HasPermission(RBAC_PERM_SKIP_CHECK_CHARACTER_CREATION_HEROIC_CHARACTER)) { - data << (uint8)CHAR_CREATE_UNIQUE_CLASS_LIMIT; - SendPacket(&data); - return; - } + // speedup check for heroic class disabled case + uint32 heroic_free_slots = sWorld->getIntConfig(CONFIG_HEROIC_CHARACTERS_PER_REALM); + if (heroic_free_slots == 0) + { + data << uint8(CHAR_CREATE_UNIQUE_CLASS_LIMIT); + SendPacket(&data); + return; + } - // speedup check for heroic class disabled case - uint32 req_level_for_heroic = sWorld->getIntConfig(CONFIG_CHARACTER_CREATING_MIN_LEVEL_FOR_HEROIC_CHARACTER); - if (AccountMgr::IsPlayerAccount(GetSecurity()) && class_ == CLASS_DEATH_KNIGHT && req_level_for_heroic > sWorld->getIntConfig(CONFIG_MAX_PLAYER_LEVEL)) - { - data << (uint8)CHAR_CREATE_LEVEL_REQUIREMENT; - SendPacket(&data); - return; + // speedup check for heroic class disabled case + uint32 req_level_for_heroic = sWorld->getIntConfig(CONFIG_CHARACTER_CREATING_MIN_LEVEL_FOR_HEROIC_CHARACTER); + if (req_level_for_heroic > sWorld->getIntConfig(CONFIG_MAX_PLAYER_LEVEL)) + { + data << uint8(CHAR_CREATE_LEVEL_REQUIREMENT); + SendPacket(&data); + return; + } } delete _charCreateCallback.GetParam(); // Delete existing if any, to make the callback chain reset to stage 0 @@ -480,7 +492,7 @@ void WorldSession::HandleCharCreateCallback(PreparedQueryResult result, Characte } } - bool allowTwoSideAccounts = !sWorld->IsPvPRealm() || sWorld->getBoolConfig(CONFIG_ALLOW_TWO_SIDE_ACCOUNTS) || !AccountMgr::IsPlayerAccount(GetSecurity()); + bool allowTwoSideAccounts = !sWorld->IsPvPRealm() || HasPermission(RBAC_PERM_TWO_SIDE_CHARACTER_CREATION); uint32 skipCinematics = sWorld->getIntConfig(CONFIG_SKIP_CINEMATICS); _charCreateCallback.FreeResult(); @@ -504,8 +516,9 @@ void WorldSession::HandleCharCreateCallback(PreparedQueryResult result, Characte bool haveSameRace = false; uint32 heroicReqLevel = sWorld->getIntConfig(CONFIG_CHARACTER_CREATING_MIN_LEVEL_FOR_HEROIC_CHARACTER); bool hasHeroicReqLevel = (heroicReqLevel == 0); - bool allowTwoSideAccounts = !sWorld->IsPvPRealm() || sWorld->getBoolConfig(CONFIG_ALLOW_TWO_SIDE_ACCOUNTS) || !AccountMgr::IsPlayerAccount(GetSecurity()); + bool allowTwoSideAccounts = !sWorld->IsPvPRealm() || HasPermission(RBAC_PERM_TWO_SIDE_CHARACTER_CREATION); uint32 skipCinematics = sWorld->getIntConfig(CONFIG_SKIP_CINEMATICS); + bool checkHeroicReqs = createInfo->Class == CLASS_DEATH_KNIGHT && !HasPermission(RBAC_PERM_SKIP_CHECK_CHARACTER_CREATION_HEROIC_CHARACTER); if (result) { @@ -515,7 +528,7 @@ void WorldSession::HandleCharCreateCallback(PreparedQueryResult result, Characte Field* field = result->Fetch(); uint8 accRace = field[1].GetUInt8(); - if (AccountMgr::IsPlayerAccount(GetSecurity()) && createInfo->Class == CLASS_DEATH_KNIGHT) + if (checkHeroicReqs) { uint8 accClass = field[2].GetUInt8(); if (accClass == CLASS_DEATH_KNIGHT) @@ -543,7 +556,7 @@ void WorldSession::HandleCharCreateCallback(PreparedQueryResult result, Characte } // need to check team only for first character - // TODO: what to if account already has characters of both races? + /// @todo what to if account already has characters of both races? if (!allowTwoSideAccounts) { uint32 accTeam = 0; @@ -562,7 +575,7 @@ void WorldSession::HandleCharCreateCallback(PreparedQueryResult result, Characte } // search same race for cinematic or same class if need - // TODO: check if cinematic already shown? (already logged in?; cinematic field) + /// @todo check if cinematic already shown? (already logged in?; cinematic field) while ((skipCinematics == 1 && !haveSameRace) || createInfo->Class == CLASS_DEATH_KNIGHT) { if (!result->NextRow()) @@ -574,7 +587,7 @@ void WorldSession::HandleCharCreateCallback(PreparedQueryResult result, Characte if (!haveSameRace) haveSameRace = createInfo->Race == accRace; - if (AccountMgr::IsPlayerAccount(GetSecurity()) && createInfo->Class == CLASS_DEATH_KNIGHT) + if (checkHeroicReqs) { uint8 acc_class = field[2].GetUInt8(); if (acc_class == CLASS_DEATH_KNIGHT) @@ -603,7 +616,7 @@ void WorldSession::HandleCharCreateCallback(PreparedQueryResult result, Characte } } - if (AccountMgr::IsPlayerAccount(GetSecurity()) && createInfo->Class == CLASS_DEATH_KNIGHT && !hasHeroicReqLevel) + if (checkHeroicReqs && !hasHeroicReqLevel) { WorldPacket data(SMSG_CHAR_CREATE, 1); data << uint8(CHAR_CREATE_LEVEL_REQUIREMENT); @@ -725,7 +738,7 @@ void WorldSession::HandleCharDeleteOpcode(WorldPacket& recvData) std::string IP_str = GetRemoteAddress(); sLog->outInfo(LOG_FILTER_CHARACTER, "Account: %d, IP: %s deleted character: %s, GUID: %u, Level: %u", accountId, IP_str.c_str(), name.c_str(), GUID_LOPART(guid), level); sScriptMgr->OnPlayerDelete(guid); - sWorld->DeleteCharaceterNameData(GUID_LOPART(guid)); + sWorld->DeleteCharacterNameData(GUID_LOPART(guid)); if (sLog->ShouldLog(LOG_FILTER_PLAYER_DUMP, LOG_LEVEL_INFO)) // optimize GetPlayerDump call { @@ -757,7 +770,7 @@ void WorldSession::HandlePlayerLoginOpcode(WorldPacket& recvData) recvData >> playerGuid; - if (!CharCanLogin(GUID_LOPART(playerGuid))) + if (!IsLegitCharacterForAccount(GUID_LOPART(playerGuid))) { sLog->outError(LOG_FILTER_NETWORKIO, "Account (%u) can't login with that character (%u).", GetAccountId(), GUID_LOPART(playerGuid)); KickPlayer(); @@ -1120,7 +1133,7 @@ void WorldSession::HandleCharRenameOpcode(WorldPacket& recvData) } // check name limitations - if (AccountMgr::IsPlayerAccount(GetSecurity()) && sObjectMgr->IsReservedName(newName)) + if (!HasPermission(RBAC_PERM_SKIP_CHECK_CHARACTER_CREATION_RESERVEDNAME) && sObjectMgr->IsReservedName(newName)) { WorldPacket data(SMSG_CHAR_RENAME, 1); data << uint8(CHAR_NAME_RESERVED); @@ -1384,6 +1397,15 @@ void WorldSession::HandleCharCustomize(WorldPacket& recvData) std::string newName; recvData >> guid; + if (!IsLegitCharacterForAccount(GUID_LOPART(guid))) + { + sLog->outError(LOG_FILTER_NETWORKIO, "Account %u, IP: %s tried to customise character %u, but it does not belong to their account!", + GetAccountId(), GetRemoteAddress().c_str(), GUID_LOPART(guid)); + recvData.rfinish(); + KickPlayer(); + return; + } + recvData >> newName; uint8 gender, skin, face, hairStyle, hairColor, facialHair; @@ -1392,7 +1414,7 @@ void WorldSession::HandleCharCustomize(WorldPacket& recvData) PreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_SEL_CHARACTER_AT_LOGIN); stmt->setUInt32(0, GUID_LOPART(guid)); - + // TODO: Make async with callback PreparedQueryResult result = CharacterDatabase.Query(stmt); if (!result) @@ -1433,7 +1455,7 @@ void WorldSession::HandleCharCustomize(WorldPacket& recvData) } // check name limitations - if (AccountMgr::IsPlayerAccount(GetSecurity()) && sObjectMgr->IsReservedName(newName)) + if (!HasPermission(RBAC_PERM_SKIP_CHECK_CHARACTER_CREATION_RESERVEDNAME) && sObjectMgr->IsReservedName(newName)) { WorldPacket data(SMSG_CHAR_CUSTOMIZE, 1); data << uint8(CHAR_NAME_RESERVED); @@ -1617,6 +1639,16 @@ void WorldSession::HandleCharFactionOrRaceChange(WorldPacket& recvData) std::string newname; uint8 gender, skin, face, hairStyle, hairColor, facialHair, race; recvData >> guid; + + if (!IsLegitCharacterForAccount(GUID_LOPART(guid))) + { + sLog->outError(LOG_FILTER_NETWORKIO, "Account %u, IP: %s tried to factionchange character %u, but it does not belong to their account!", + GetAccountId(), GetRemoteAddress().c_str(), GUID_LOPART(guid)); + recvData.rfinish(); + KickPlayer(); + return; + } + recvData >> newname; recvData >> gender >> skin >> hairColor >> hairStyle >> facialHair >> face >> race; @@ -1624,6 +1656,14 @@ void WorldSession::HandleCharFactionOrRaceChange(WorldPacket& recvData) // get the players old (at this moment current) race CharacterNameData const* nameData = sWorld->GetCharacterNameData(lowGuid); + if (!nameData) + { + WorldPacket data(SMSG_CHAR_FACTION_CHANGE, 1); + data << uint8(CHAR_CREATE_ERROR); + SendPacket(&data); + return; + } + uint8 oldRace = nameData->m_race; uint8 playerClass = nameData->m_class; uint8 level = nameData->m_level; @@ -1661,7 +1701,7 @@ void WorldSession::HandleCharFactionOrRaceChange(WorldPacket& recvData) return; } - if (AccountMgr::IsPlayerAccount(GetSecurity())) + if (!HasPermission(RBAC_PERM_SKIP_CHECK_CHARACTER_CREATION_RACEMASK)) { uint32 raceMaskDisabled = sWorld->getIntConfig(CONFIG_CHARACTER_CREATING_DISABLED_RACEMASK); if ((1 << (race - 1)) & raceMaskDisabled) @@ -1692,7 +1732,7 @@ void WorldSession::HandleCharFactionOrRaceChange(WorldPacket& recvData) } // check name limitations - if (AccountMgr::IsPlayerAccount(GetSecurity()) && sObjectMgr->IsReservedName(newname)) + if (!HasPermission(RBAC_PERM_SKIP_CHECK_CHARACTER_CREATION_RESERVEDNAME) && sObjectMgr->IsReservedName(newname)) { WorldPacket data(SMSG_CHAR_FACTION_CHANGE, 1); data << uint8(CHAR_NAME_RESERVED); @@ -1856,44 +1896,6 @@ void WorldSession::HandleCharFactionOrRaceChange(WorldPacket& recvData) trans->Append(stmt); } - // Delete all current quests - stmt = CharacterDatabase.GetPreparedStatement(CHAR_DEL_CHAR_QUESTSTATUS); - stmt->setUInt32(0, GUID_LOPART(guid)); - trans->Append(stmt); - - // Delete record of the faction old completed quests - { - std::ostringstream quests; - ObjectMgr::QuestMap const& qTemplates = sObjectMgr->GetQuestTemplates(); - for (ObjectMgr::QuestMap::const_iterator iter = qTemplates.begin(); iter != qTemplates.end(); ++iter) - { - Quest *qinfo = iter->second; - uint32 requiredRaces = qinfo->GetRequiredRaces(); - if (team == TEAM_ALLIANCE) - { - if (requiredRaces & RACEMASK_ALLIANCE) - { - quests << uint32(qinfo->GetQuestId()); - quests << ','; - } - } - else // if (team == TEAM_HORDE) - { - if (requiredRaces & RACEMASK_HORDE) - { - quests << uint32(qinfo->GetQuestId()); - quests << ','; - } - } - } - - std::string questsStr = quests.str(); - questsStr = questsStr.substr(0, questsStr.length() - 1); - - if (!questsStr.empty()) - trans->PAppend("DELETE FROM `character_queststatus_rewarded` WHERE guid='%u' AND quest IN (%s)", lowGuid, questsStr.c_str()); - } - if (!sWorld->getBoolConfig(CONFIG_ALLOW_TWO_SIDE_INTERACTION_GUILD)) { // Reset guild @@ -1907,7 +1909,7 @@ void WorldSession::HandleCharFactionOrRaceChange(WorldPacket& recvData) guild->DeleteMember(MAKE_NEW_GUID(lowGuid, 0, HIGHGUID_PLAYER)); } - if (!sWorld->getBoolConfig(CONFIG_ALLOW_TWO_SIDE_ADD_FRIEND)) + if (!HasPermission(RBAC_PERM_TWO_SIDE_ADD_FRIEND)) { // Delete Friend List stmt = CharacterDatabase.GetPreparedStatement(CHAR_DEL_CHAR_SOCIAL_BY_GUID); @@ -1951,7 +1953,7 @@ void WorldSession::HandleCharFactionOrRaceChange(WorldPacket& recvData) trans->Append(stmt); // Achievement conversion - for (std::map<uint32, uint32>::const_iterator it = sObjectMgr->FactionChange_Achievements.begin(); it != sObjectMgr->FactionChange_Achievements.end(); ++it) + for (std::map<uint32, uint32>::const_iterator it = sObjectMgr->FactionChangeAchievements.begin(); it != sObjectMgr->FactionChangeAchievements.end(); ++it) { uint32 achiev_alliance = it->first; uint32 achiev_horde = it->second; @@ -1969,7 +1971,7 @@ void WorldSession::HandleCharFactionOrRaceChange(WorldPacket& recvData) } // Item conversion - for (std::map<uint32, uint32>::const_iterator it = sObjectMgr->FactionChange_Items.begin(); it != sObjectMgr->FactionChange_Items.end(); ++it) + for (std::map<uint32, uint32>::const_iterator it = sObjectMgr->FactionChangeItems.begin(); it != sObjectMgr->FactionChangeItems.end(); ++it) { uint32 item_alliance = it->first; uint32 item_horde = it->second; @@ -1981,8 +1983,53 @@ void WorldSession::HandleCharFactionOrRaceChange(WorldPacket& recvData) trans->Append(stmt); } + // Delete all current quests + stmt = CharacterDatabase.GetPreparedStatement(CHAR_DEL_CHAR_QUESTSTATUS); + stmt->setUInt32(0, GUID_LOPART(guid)); + trans->Append(stmt); + + // Quest conversion + for (std::map<uint32, uint32>::const_iterator it = sObjectMgr->FactionChangeQuests.begin(); it != sObjectMgr->FactionChangeQuests.end(); ++it) + { + uint32 quest_alliance = it->first; + uint32 quest_horde = it->second; + + stmt = CharacterDatabase.GetPreparedStatement(CHAR_DEL_CHAR_QUESTSTATUS_REWARDED_BY_QUEST); + stmt->setUInt32(0, lowGuid); + stmt->setUInt32(1, (team == TEAM_ALLIANCE ? quest_alliance : quest_horde)); + trans->Append(stmt); + + stmt = CharacterDatabase.GetPreparedStatement(CHAR_UPD_CHAR_QUESTSTATUS_REWARDED_FACTION_CHANGE); + stmt->setUInt32(0, (team == TEAM_ALLIANCE ? quest_alliance : quest_horde)); + stmt->setUInt32(1, (team == TEAM_ALLIANCE ? quest_horde : quest_alliance)); + stmt->setUInt32(2, lowGuid); + trans->Append(stmt); + } + + // Mark all rewarded quests as "active" (will count for completed quests achievements) + stmt = CharacterDatabase.GetPreparedStatement(CHAR_UPD_CHAR_QUESTSTATUS_REWARDED_ACTIVE); + stmt->setUInt32(0, lowGuid); + trans->Append(stmt); + + // Disable all old-faction specific quests + { + ObjectMgr::QuestMap const& questTemplates = sObjectMgr->GetQuestTemplates(); + for (ObjectMgr::QuestMap::const_iterator iter = questTemplates.begin(); iter != questTemplates.end(); ++iter) + { + Quest const* quest = iter->second; + uint32 newRaceMask = (team == TEAM_ALLIANCE) ? RACEMASK_ALLIANCE : RACEMASK_HORDE; + if (!(quest->GetRequiredRaces() & newRaceMask)) + { + stmt = CharacterDatabase.GetPreparedStatement(CHAR_UPD_CHAR_QUESTSTATUS_REWARDED_ACTIVE_BY_QUEST); + stmt->setUInt32(0, lowGuid); + stmt->setUInt32(1, quest->GetQuestId()); + trans->Append(stmt); + } + } + } + // Spell conversion - for (std::map<uint32, uint32>::const_iterator it = sObjectMgr->FactionChange_Spells.begin(); it != sObjectMgr->FactionChange_Spells.end(); ++it) + for (std::map<uint32, uint32>::const_iterator it = sObjectMgr->FactionChangeSpells.begin(); it != sObjectMgr->FactionChangeSpells.end(); ++it) { uint32 spell_alliance = it->first; uint32 spell_horde = it->second; @@ -2000,7 +2047,7 @@ void WorldSession::HandleCharFactionOrRaceChange(WorldPacket& recvData) } // Reputation conversion - for (std::map<uint32, uint32>::const_iterator it = sObjectMgr->FactionChange_Reputation.begin(); it != sObjectMgr->FactionChange_Reputation.end(); ++it) + for (std::map<uint32, uint32>::const_iterator it = sObjectMgr->FactionChangeReputation.begin(); it != sObjectMgr->FactionChangeReputation.end(); ++it) { uint32 reputation_alliance = it->first; uint32 reputation_horde = it->second; @@ -2026,10 +2073,10 @@ void WorldSession::HandleCharFactionOrRaceChange(WorldPacket& recvData) FactionEntry const* factionEntry = sFactionStore.LookupEntry(oldReputation); // old base reputation - int32 oldBaseRep = sObjectMgr->GetBaseReputationOff(factionEntry, oldRace, playerClass); + int32 oldBaseRep = sObjectMgr->GetBaseReputationOf(factionEntry, oldRace, playerClass); // new base reputation - int32 newBaseRep = sObjectMgr->GetBaseReputationOff(sFactionStore.LookupEntry(newReputation), race, playerClass); + int32 newBaseRep = sObjectMgr->GetBaseReputationOf(sFactionStore.LookupEntry(newReputation), race, playerClass); // final reputation shouldnt change int32 FinalRep = oldDBRep + oldBaseRep; @@ -2061,7 +2108,7 @@ void WorldSession::HandleCharFactionOrRaceChange(WorldPacket& recvData) for (uint32 index = 0; index < ktcount; ++index) knownTitles[index] = atol(tokens[index]); - for (std::map<uint32, uint32>::const_iterator it = sObjectMgr->FactionChange_Titles.begin(); it != sObjectMgr->FactionChange_Titles.end(); ++it) + for (std::map<uint32, uint32>::const_iterator it = sObjectMgr->FactionChangeTitles.begin(); it != sObjectMgr->FactionChangeTitles.end(); ++it) { uint32 title_alliance = it->first; uint32 title_horde = it->second; diff --git a/src/server/game/Handlers/ChatHandler.cpp b/src/server/game/Handlers/ChatHandler.cpp index d04d365504d..b14e9eebf02 100644 --- a/src/server/game/Handlers/ChatHandler.cpp +++ b/src/server/game/Handlers/ChatHandler.cpp @@ -129,8 +129,10 @@ void WorldSession::HandleMessagechatOpcode(WorldPacket& recvData) lang = LANG_UNIVERSAL; else { - // send in universal language in two side iteration allowed mode - if (sWorld->getBoolConfig(CONFIG_ALLOW_TWO_SIDE_INTERACTION_CHAT)) + Unit::AuraEffectList const& ModLangAuras = sender->GetAuraEffectsByType(SPELL_AURA_MOD_LANGUAGE); + if (!ModLangAuras.empty()) + lang = ModLangAuras.front()->GetMiscValue(); + else if (HasPermission(RBAC_PERM_TWO_SIDE_INTERACTION_CHAT)) lang = LANG_UNIVERSAL; else { @@ -153,11 +155,6 @@ void WorldSession::HandleMessagechatOpcode(WorldPacket& recvData) break; } } - - // but overwrite it by SPELL_AURA_MOD_LANGUAGE auras (only single case used) - Unit::AuraEffectList const& ModLangAuras = sender->GetAuraEffectsByType(SPELL_AURA_MOD_LANGUAGE); - if (!ModLangAuras.empty()) - lang = ModLangAuras.front()->GetMiscValue(); } if (!sender->CanSpeak()) @@ -260,12 +257,6 @@ void WorldSession::HandleMessagechatOpcode(WorldPacket& recvData) } break; case CHAT_MSG_WHISPER: { - if (sender->getLevel() < sWorld->getIntConfig(CONFIG_CHAT_WHISPER_LEVEL_REQ)) - { - SendNotification(GetTrinityString(LANG_WHISPER_REQ), sWorld->getIntConfig(CONFIG_CHAT_WHISPER_LEVEL_REQ)); - return; - } - if (!normalizePlayerName(to)) { SendPlayerNotFoundNotice(to); @@ -273,20 +264,22 @@ void WorldSession::HandleMessagechatOpcode(WorldPacket& recvData) } Player* receiver = sObjectAccessor->FindPlayerByName(to); - bool senderIsPlayer = AccountMgr::IsPlayerAccount(GetSecurity()); - bool receiverIsPlayer = AccountMgr::IsPlayerAccount(receiver ? receiver->GetSession()->GetSecurity() : SEC_PLAYER); - if (!receiver || (senderIsPlayer && !receiverIsPlayer && !receiver->isAcceptWhispers() && !receiver->IsInWhisperWhiteList(sender->GetGUID()))) + if (!receiver || (!receiver->isAcceptWhispers() && receiver->GetSession()->HasPermission(RBAC_PERM_CAN_FILTER_WHISPERS) && !receiver->IsInWhisperWhiteList(sender->GetGUID()))) { SendPlayerNotFoundNotice(to); return; } + if (!sender->isGameMaster() && sender->getLevel() < sWorld->getIntConfig(CONFIG_CHAT_WHISPER_LEVEL_REQ) && !receiver->IsInWhisperWhiteList(sender->GetGUID())) + { + SendNotification(GetTrinityString(LANG_WHISPER_REQ), sWorld->getIntConfig(CONFIG_CHAT_WHISPER_LEVEL_REQ)); + return; + } - if (!sWorld->getBoolConfig(CONFIG_ALLOW_TWO_SIDE_INTERACTION_CHAT) && senderIsPlayer && receiverIsPlayer) - if (GetPlayer()->GetTeam() != receiver->GetTeam()) - { - SendWrongFactionNotice(); - return; - } + if (GetPlayer()->GetTeam() != receiver->GetTeam() && !HasPermission(RBAC_PERM_TWO_SIDE_INTERACTION_CHAT) && !receiver->IsInWhisperWhiteList(sender->GetGUID())) + { + SendWrongFactionNotice(); + return; + } if (GetPlayer()->HasAura(1852) && !receiver->isGameMaster()) { @@ -295,7 +288,9 @@ void WorldSession::HandleMessagechatOpcode(WorldPacket& recvData) } // If player is a Gamemaster and doesn't accept whisper, we auto-whitelist every player that the Gamemaster is talking to - if (!senderIsPlayer && !sender->isAcceptWhispers() && !sender->IsInWhisperWhiteList(receiver->GetGUID())) + // We also do that if a player is under the required level for whispers. + if (receiver->getLevel() < sWorld->getIntConfig(CONFIG_CHAT_WHISPER_LEVEL_REQ) || + (HasPermission(RBAC_PERM_CAN_FILTER_WHISPERS) && !sender->isAcceptWhispers() && !sender->IsInWhisperWhiteList(receiver->GetGUID()))) sender->AddWhisperWhiteList(receiver->GetGUID()); GetPlayer()->Whisper(msg, lang, receiver->GetGUID()); @@ -420,7 +415,7 @@ void WorldSession::HandleMessagechatOpcode(WorldPacket& recvData) } break; case CHAT_MSG_CHANNEL: { - if (AccountMgr::IsPlayerAccount(GetSecurity())) + if (!HasPermission(RBAC_PERM_SKIP_CHECK_CHAT_CHANNEL_REQ)) { if (_player->getLevel() < sWorld->getIntConfig(CONFIG_CHAT_CHANNEL_LEVEL_REQ)) { diff --git a/src/server/game/Handlers/GuildHandler.cpp b/src/server/game/Handlers/GuildHandler.cpp index f57a5ce020f..60749932637 100644 --- a/src/server/game/Handlers/GuildHandler.cpp +++ b/src/server/game/Handlers/GuildHandler.cpp @@ -339,7 +339,7 @@ void WorldSession::HandleGuildBankerActivate(WorldPacket& recvData) sLog->outDebug(LOG_FILTER_GUILD, "CMSG_GUILD_BANKER_ACTIVATE [%s]: Go: [" UI64FMTD "] AllSlots: %u" , GetPlayerInfo().c_str(), guid, sendAllSlots); - Guild * const guild = GetPlayer()->GetGuild(); + Guild* const guild = GetPlayer()->GetGuild(); if (!guild) { Guild::SendCommandResult(this, GUILD_COMMAND_VIEW_TAB, ERR_GUILD_PLAYER_NOT_IN_GUILD); diff --git a/src/server/game/Handlers/ItemHandler.cpp b/src/server/game/Handlers/ItemHandler.cpp index 77d44dffd1b..5aedc08a063 100644 --- a/src/server/game/Handlers/ItemHandler.cpp +++ b/src/server/game/Handlers/ItemHandler.cpp @@ -970,8 +970,8 @@ void WorldSession::HandleAutoStoreBankItemOpcode(WorldPacket& recvPacket) } _player->RemoveItem(srcbag, srcslot, true); - _player->StoreItem(dest, pItem, true); - _player->ItemAddedQuestCheck(pItem->GetEntry(), pItem->GetCount()); + if (Item const* storedItem = _player->StoreItem(dest, pItem, true)) + _player->ItemAddedQuestCheck(storedItem->GetEntry(), storedItem->GetCount()); } else // moving from inventory to bank { diff --git a/src/server/game/Handlers/LFGHandler.cpp b/src/server/game/Handlers/LFGHandler.cpp index 0654ae326f9..619e9b68b51 100644 --- a/src/server/game/Handlers/LFGHandler.cpp +++ b/src/server/game/Handlers/LFGHandler.cpp @@ -23,20 +23,20 @@ #include "WorldPacket.h" #include "WorldSession.h" -void BuildPlayerLockDungeonBlock(WorldPacket& data, LfgLockMap const& lock) +void BuildPlayerLockDungeonBlock(WorldPacket& data, lfg::LfgLockMap const& lock) { data << uint32(lock.size()); // Size of lock dungeons - for (LfgLockMap::const_iterator it = lock.begin(); it != lock.end(); ++it) + for (lfg::LfgLockMap::const_iterator it = lock.begin(); it != lock.end(); ++it) { data << uint32(it->first); // Dungeon entry (id + type) data << uint32(it->second); // Lock status } } -void BuildPartyLockDungeonBlock(WorldPacket& data, const LfgLockPartyMap& lockMap) +void BuildPartyLockDungeonBlock(WorldPacket& data, lfg::LfgLockPartyMap const& lockMap) { data << uint8(lockMap.size()); - for (LfgLockPartyMap::const_iterator it = lockMap.begin(); it != lockMap.end(); ++it) + for (lfg::LfgLockPartyMap::const_iterator it = lockMap.begin(); it != lockMap.end(); ++it) { data << uint64(it->first); // Player guid BuildPlayerLockDungeonBlock(data, it->second); @@ -45,7 +45,7 @@ void BuildPartyLockDungeonBlock(WorldPacket& data, const LfgLockPartyMap& lockMa void WorldSession::HandleLfgJoinOpcode(WorldPacket& recvData) { - if (!sLFGMgr->isOptionEnabled(LFG_OPTION_ENABLE_DUNGEON_FINDER | LFG_OPTION_ENABLE_RAID_BROWSER) || + if (!sLFGMgr->isOptionEnabled(lfg::LFG_OPTION_ENABLE_DUNGEON_FINDER | lfg::LFG_OPTION_ENABLE_RAID_BROWSER) || (GetPlayer()->GetGroup() && GetPlayer()->GetGroup()->GetLeaderGUID() != GetPlayer()->GetGUID() && (GetPlayer()->GetGroup()->GetMembersCount() == MAXGROUPSIZE || !GetPlayer()->GetGroup()->isLFGGroup()))) { @@ -66,7 +66,7 @@ void WorldSession::HandleLfgJoinOpcode(WorldPacket& recvData) return; } - LfgDungeonSet newDungeons; + lfg::LfgDungeonSet newDungeons; for (int8 i = 0; i < numDungeons; ++i) { uint32 dungeon; @@ -167,21 +167,12 @@ void WorldSession::HandleLfgPlayerLockInfoRequestOpcode(WorldPacket& /*recvData* GetPlayerInfo().c_str()); // Get Random dungeons that can be done at a certain level and expansion - LfgDungeonSet randomDungeons; uint8 level = GetPlayer()->getLevel(); - uint8 expansion = GetPlayer()->GetSession()->Expansion(); - - LFGDungeonContainer& LfgDungeons = sLFGMgr->GetLFGDungeonMap(); - for (LFGDungeonContainer::const_iterator itr = LfgDungeons.begin(); itr != LfgDungeons.end(); ++itr) - { - LFGDungeonData const& dungeon = itr->second; - if ((dungeon.type == LFG_TYPE_RANDOM || (dungeon.seasonal && sLFGMgr->IsSeasonActive(dungeon.id))) - && dungeon.expansion <= expansion && dungeon.minlevel <= level && level <= dungeon.maxlevel) - randomDungeons.insert(dungeon.Entry()); - } + lfg::LfgDungeonSet const& randomDungeons = + sLFGMgr->GetRandomAndSeasonalDungeons(level, GetPlayer()->GetSession()->Expansion()); // Get player locked Dungeons - LfgLockMap const& lock = sLFGMgr->GetLockedDungeons(guid); + lfg::LfgLockMap const& lock = sLFGMgr->GetLockedDungeons(guid); uint32 rsize = uint32(randomDungeons.size()); uint32 lsize = uint32(lock.size()); @@ -189,10 +180,10 @@ void WorldSession::HandleLfgPlayerLockInfoRequestOpcode(WorldPacket& /*recvData* WorldPacket data(SMSG_LFG_PLAYER_INFO, 1 + rsize * (4 + 1 + 4 + 4 + 4 + 4 + 1 + 4 + 4 + 4) + 4 + lsize * (1 + 4 + 4 + 4 + 4 + 1 + 4 + 4 + 4)); data << uint8(randomDungeons.size()); // Random Dungeon count - for (LfgDungeonSet::const_iterator it = randomDungeons.begin(); it != randomDungeons.end(); ++it) + for (lfg::LfgDungeonSet::const_iterator it = randomDungeons.begin(); it != randomDungeons.end(); ++it) { data << uint32(*it); // Dungeon Entry (id + type) - LfgReward const* reward = sLFGMgr->GetRandomDungeonReward(*it, level); + lfg::LfgReward const* reward = sLFGMgr->GetRandomDungeonReward(*it, level); Quest const* quest = NULL; bool done = false; if (reward) @@ -250,7 +241,7 @@ void WorldSession::HandleLfgPartyLockInfoRequestOpcode(WorldPacket& /*recvData* return; // Get the locked dungeons of the other party members - LfgLockPartyMap lockMap; + lfg::LfgLockPartyMap lockMap; for (GroupReference* itr = group->GetFirstMember(); itr != NULL; itr = itr->next()) { Player* plrg = itr->getSource(); @@ -265,7 +256,7 @@ void WorldSession::HandleLfgPartyLockInfoRequestOpcode(WorldPacket& /*recvData* } uint32 size = 0; - for (LfgLockPartyMap::const_iterator it = lockMap.begin(); it != lockMap.end(); ++it) + for (lfg::LfgLockPartyMap::const_iterator it = lockMap.begin(); it != lockMap.end(); ++it) size += 8 + 4 + uint32(it->second.size()) * (4 + 4); sLog->outDebug(LOG_FILTER_LFG, "SMSG_LFG_PARTY_INFO %s", GetPlayerInfo().c_str()); @@ -297,7 +288,7 @@ void WorldSession::HandleLfgGetStatus(WorldPacket& /*recvData*/) sLog->outDebug(LOG_FILTER_LFG, "CMSG_LFG_GET_STATUS %s", GetPlayerInfo().c_str()); uint64 guid = GetPlayer()->GetGUID(); - LfgUpdateData updateData = sLFGMgr->GetLfgStatus(guid); + lfg::LfgUpdateData updateData = sLFGMgr->GetLfgStatus(guid); if (GetPlayer()->GetGroup()) { @@ -313,19 +304,19 @@ void WorldSession::HandleLfgGetStatus(WorldPacket& /*recvData*/) } } -void WorldSession::SendLfgUpdatePlayer(LfgUpdateData const& updateData) +void WorldSession::SendLfgUpdatePlayer(lfg::LfgUpdateData const& updateData) { bool queued = false; uint8 size = uint8(updateData.dungeons.size()); switch (updateData.updateType) { - case LFG_UPDATETYPE_JOIN_QUEUE: - case LFG_UPDATETYPE_ADDED_TO_QUEUE: + case lfg::LFG_UPDATETYPE_JOIN_QUEUE: + case lfg::LFG_UPDATETYPE_ADDED_TO_QUEUE: queued = true; break; - case LFG_UPDATETYPE_UPDATE_STATUS: - queued = updateData.state == LFG_STATE_QUEUED; + case lfg::LFG_UPDATETYPE_UPDATE_STATUS: + queued = updateData.state == lfg::LFG_STATE_QUEUED; break; default: break; @@ -343,14 +334,14 @@ void WorldSession::SendLfgUpdatePlayer(LfgUpdateData const& updateData) data << uint8(0); // unk - Always 0 data << uint8(size); - for (LfgDungeonSet::const_iterator it = updateData.dungeons.begin(); it != updateData.dungeons.end(); ++it) + for (lfg::LfgDungeonSet::const_iterator it = updateData.dungeons.begin(); it != updateData.dungeons.end(); ++it) data << uint32(*it); data << updateData.comment; } SendPacket(&data); } -void WorldSession::SendLfgUpdateParty(const LfgUpdateData& updateData) +void WorldSession::SendLfgUpdateParty(const lfg::LfgUpdateData& updateData) { bool join = false; bool queued = false; @@ -358,15 +349,15 @@ void WorldSession::SendLfgUpdateParty(const LfgUpdateData& updateData) switch (updateData.updateType) { - case LFG_UPDATETYPE_ADDED_TO_QUEUE: // Rolecheck Success + case lfg::LFG_UPDATETYPE_ADDED_TO_QUEUE: // Rolecheck Success queued = true; // no break on purpose - case LFG_UPDATETYPE_PROPOSAL_BEGIN: + case lfg::LFG_UPDATETYPE_PROPOSAL_BEGIN: join = true; break; - case LFG_UPDATETYPE_UPDATE_STATUS: - join = updateData.state != LFG_STATE_ROLECHECK && updateData.state != LFG_STATE_NONE; - queued = updateData.state == LFG_STATE_QUEUED; + case lfg::LFG_UPDATETYPE_UPDATE_STATUS: + join = updateData.state != lfg::LFG_STATE_ROLECHECK && updateData.state != lfg::LFG_STATE_NONE; + queued = updateData.state == lfg::LFG_STATE_QUEUED; break; default: break; @@ -387,7 +378,7 @@ void WorldSession::SendLfgUpdateParty(const LfgUpdateData& updateData) data << uint8(0); // unk - Always 0 data << uint8(size); - for (LfgDungeonSet::const_iterator it = updateData.dungeons.begin(); it != updateData.dungeons.end(); ++it) + for (lfg::LfgDungeonSet::const_iterator it = updateData.dungeons.begin(); it != updateData.dungeons.end(); ++it) data << uint32(*it); data << updateData.comment; } @@ -406,9 +397,9 @@ void WorldSession::SendLfgRoleChosen(uint64 guid, uint8 roles) SendPacket(&data); } -void WorldSession::SendLfgRoleCheckUpdate(const LfgRoleCheck& roleCheck) +void WorldSession::SendLfgRoleCheckUpdate(lfg::LfgRoleCheck const& roleCheck) { - LfgDungeonSet dungeons; + lfg::LfgDungeonSet dungeons; if (roleCheck.rDungeonId) dungeons.insert(roleCheck.rDungeonId); else @@ -418,16 +409,11 @@ void WorldSession::SendLfgRoleCheckUpdate(const LfgRoleCheck& roleCheck) WorldPacket data(SMSG_LFG_ROLE_CHECK_UPDATE, 4 + 1 + 1 + dungeons.size() * 4 + 1 + roleCheck.roles.size() * (8 + 1 + 4 + 1)); data << uint32(roleCheck.state); // Check result - data << uint8(roleCheck.state == LFG_ROLECHECK_INITIALITING); + data << uint8(roleCheck.state == lfg::LFG_ROLECHECK_INITIALITING); data << uint8(dungeons.size()); // Number of dungeons if (!dungeons.empty()) - { - for (LfgDungeonSet::iterator it = dungeons.begin(); it != dungeons.end(); ++it) - { - LFGDungeonData const* dungeon = sLFGMgr->GetLFGDungeon(*it); - data << uint32(dungeon ? dungeon->Entry() : 0); // Dungeon - } - } + for (lfg::LfgDungeonSet::iterator it = dungeons.begin(); it != dungeons.end(); ++it) + data << uint32(sLFGMgr->GetLFGDungeonEntry(*it)); // Dungeon data << uint8(roleCheck.roles.size()); // Players in group if (!roleCheck.roles.empty()) @@ -441,7 +427,7 @@ void WorldSession::SendLfgRoleCheckUpdate(const LfgRoleCheck& roleCheck) Player* player = ObjectAccessor::FindPlayer(guid); data << uint8(player ? player->getLevel() : 0); // Level - for (LfgRolesMap::const_iterator it = roleCheck.roles.begin(); it != roleCheck.roles.end(); ++it) + for (lfg::LfgRolesMap::const_iterator it = roleCheck.roles.begin(); it != roleCheck.roles.end(); ++it) { if (it->first == roleCheck.leader) continue; @@ -458,10 +444,10 @@ void WorldSession::SendLfgRoleCheckUpdate(const LfgRoleCheck& roleCheck) SendPacket(&data); } -void WorldSession::SendLfgJoinResult(LfgJoinResultData const& joinData) +void WorldSession::SendLfgJoinResult(lfg::LfgJoinResultData const& joinData) { uint32 size = 0; - for (LfgLockPartyMap::const_iterator it = joinData.lockmap.begin(); it != joinData.lockmap.end(); ++it) + for (lfg::LfgLockPartyMap::const_iterator it = joinData.lockmap.begin(); it != joinData.lockmap.end(); ++it) size += 8 + 4 + uint32(it->second.size()) * (4 + 4); sLog->outDebug(LOG_FILTER_LFG, "SMSG_LFG_JOIN_RESULT %s checkResult: %u checkValue: %u", @@ -475,7 +461,7 @@ void WorldSession::SendLfgJoinResult(LfgJoinResultData const& joinData) SendPacket(&data); } -void WorldSession::SendLfgQueueStatus(LfgQueueStatusData const& queueData) +void WorldSession::SendLfgQueueStatus(lfg::LfgQueueStatusData const& queueData) { sLog->outDebug(LOG_FILTER_LFG, "SMSG_LFG_QUEUE_STATUS %s dungeon: %u, waitTime: %d, " "avgWaitTime: %d, waitTimeTanks: %d, waitTimeHealer: %d, waitTimeDps: %d, " @@ -498,7 +484,7 @@ void WorldSession::SendLfgQueueStatus(LfgQueueStatusData const& queueData) SendPacket(&data); } -void WorldSession::SendLfgPlayerReward(LfgPlayerRewardData const& rewardData) +void WorldSession::SendLfgPlayerReward(lfg::LfgPlayerRewardData const& rewardData) { if (!rewardData.rdungeonEntry || !rewardData.sdungeonEntry || !rewardData.quest) return; @@ -532,42 +518,42 @@ void WorldSession::SendLfgPlayerReward(LfgPlayerRewardData const& rewardData) SendPacket(&data); } -void WorldSession::SendLfgBootProposalUpdate(LfgPlayerBoot const& boot) +void WorldSession::SendLfgBootProposalUpdate(lfg::LfgPlayerBoot const& boot) { uint64 guid = GetPlayer()->GetGUID(); - LfgAnswer playerVote = boot.votes.find(guid)->second; + lfg::LfgAnswer playerVote = boot.votes.find(guid)->second; uint8 votesNum = 0; uint8 agreeNum = 0; uint32 secsleft = uint8((boot.cancelTime - time(NULL)) / 1000); - for (LfgAnswerContainer::const_iterator it = boot.votes.begin(); it != boot.votes.end(); ++it) + for (lfg::LfgAnswerContainer::const_iterator it = boot.votes.begin(); it != boot.votes.end(); ++it) { - if (it->second != LFG_ANSWER_PENDING) + if (it->second != lfg::LFG_ANSWER_PENDING) { ++votesNum; - if (it->second == LFG_ANSWER_AGREE) + if (it->second == lfg::LFG_ANSWER_AGREE) ++agreeNum; } } sLog->outDebug(LOG_FILTER_LFG, "SMSG_LFG_BOOT_PROPOSAL_UPDATE %s inProgress: %u - " "didVote: %u - agree: %u - victim: %u votes: %u - agrees: %u - left: %u - " "needed: %u - reason %s", - GetPlayerInfo().c_str(), uint8(boot.inProgress), uint8(playerVote != LFG_ANSWER_PENDING), - uint8(playerVote == LFG_ANSWER_AGREE), GUID_LOPART(boot.victim), votesNum, agreeNum, - secsleft, LFG_GROUP_KICK_VOTES_NEEDED, boot.reason.c_str()); + GetPlayerInfo().c_str(), uint8(boot.inProgress), uint8(playerVote != lfg::LFG_ANSWER_PENDING), + uint8(playerVote == lfg::LFG_ANSWER_AGREE), GUID_LOPART(boot.victim), votesNum, agreeNum, + secsleft, lfg::LFG_GROUP_KICK_VOTES_NEEDED, boot.reason.c_str()); WorldPacket data(SMSG_LFG_BOOT_PROPOSAL_UPDATE, 1 + 1 + 1 + 8 + 4 + 4 + 4 + 4 + boot.reason.length()); data << uint8(boot.inProgress); // Vote in progress - data << uint8(playerVote != LFG_ANSWER_PENDING); // Did Vote - data << uint8(playerVote == LFG_ANSWER_AGREE); // Agree + data << uint8(playerVote != lfg::LFG_ANSWER_PENDING); // Did Vote + data << uint8(playerVote == lfg::LFG_ANSWER_AGREE); // Agree data << uint64(boot.victim); // Victim GUID data << uint32(votesNum); // Total Votes data << uint32(agreeNum); // Agree Count data << uint32(secsleft); // Time Left - data << uint32(LFG_GROUP_KICK_VOTES_NEEDED); // Needed Votes + data << uint32(lfg::LFG_GROUP_KICK_VOTES_NEEDED); // Needed Votes data << boot.reason.c_str(); // Kick reason SendPacket(&data); } -void WorldSession::SendLfgUpdateProposal(LfgProposal const& proposal) +void WorldSession::SendLfgUpdateProposal(lfg::LfgProposal const& proposal) { uint64 guid = GetPlayer()->GetGUID(); uint64 gguid = proposal.players.find(guid)->second.group; @@ -580,13 +566,12 @@ void WorldSession::SendLfgUpdateProposal(LfgProposal const& proposal) // show random dungeon if player selected random dungeon and it's not lfg group if (!silent) { - LfgDungeonSet const& playerDungeons = sLFGMgr->GetSelectedDungeons(guid); + lfg::LfgDungeonSet const& playerDungeons = sLFGMgr->GetSelectedDungeons(guid); if (playerDungeons.find(proposal.dungeonId) == playerDungeons.end()) dungeonEntry = (*playerDungeons.begin()); } - if (LFGDungeonData const* dungeon = sLFGMgr->GetLFGDungeon(dungeonEntry)) - dungeonEntry = dungeon->Entry(); + dungeonEntry = sLFGMgr->GetLFGDungeonEntry(dungeonEntry); WorldPacket data(SMSG_LFG_PROPOSAL_UPDATE, 4 + 1 + 4 + 4 + 1 + 1 + proposal.players.size() * (4 + 1 + 1 + 1 + 1 +1)); data << uint32(dungeonEntry); // Dungeon @@ -596,9 +581,9 @@ void WorldSession::SendLfgUpdateProposal(LfgProposal const& proposal) data << uint8(silent); // Show proposal window data << uint8(proposal.players.size()); // Group size - for (LfgProposalPlayerContainer::const_iterator it = proposal.players.begin(); it != proposal.players.end(); ++it) + for (lfg::LfgProposalPlayerContainer::const_iterator it = proposal.players.begin(); it != proposal.players.end(); ++it) { - LfgProposalPlayer const& player = it->second; + lfg::LfgProposalPlayer const& player = it->second; data << uint32(player.role); // Role data << uint8(it->first == guid); // Self player if (!player.group) // Player not it a group @@ -611,8 +596,8 @@ void WorldSession::SendLfgUpdateProposal(LfgProposal const& proposal) data << uint8(player.group == proposal.group); // In dungeon (silent) data << uint8(player.group == gguid); // Same Group than player } - data << uint8(player.accept != LFG_ANSWER_PENDING);// Answered - data << uint8(player.accept == LFG_ANSWER_AGREE); // Accepted + data << uint8(player.accept != lfg::LFG_ANSWER_PENDING);// Answered + data << uint8(player.accept == lfg::LFG_ANSWER_AGREE); // Accepted } SendPacket(&data); } diff --git a/src/server/game/Handlers/LootHandler.cpp b/src/server/game/Handlers/LootHandler.cpp index 74fd18b31ed..2129b386d8c 100644 --- a/src/server/game/Handlers/LootHandler.cpp +++ b/src/server/game/Handlers/LootHandler.cpp @@ -99,7 +99,7 @@ void WorldSession::HandleAutostoreLootItemOpcode(WorldPacket& recvData) player->GetSession()->DoLootRelease(lguid); } -void WorldSession::HandleLootMoneyOpcode(WorldPacket & /*recvData*/) +void WorldSession::HandleLootMoneyOpcode(WorldPacket& /*recvData*/) { sLog->outDebug(LOG_FILTER_NETWORKIO, "WORLD: CMSG_LOOT_MONEY"); @@ -188,7 +188,7 @@ void WorldSession::HandleLootMoneyOpcode(WorldPacket & /*recvData*/) WorldPacket data(SMSG_LOOT_MONEY_NOTIFY, 4 + 1); data << uint32(goldPerPlayer); - data << uint8(playersNear.size() > 1 ? 0 : 1); // Controls the text displayed in chat. 0 is "Your share is..." and 1 is "You loot..." + data << uint8(playersNear.size() <= 1); // Controls the text displayed in chat. 0 is "Your share is..." and 1 is "You loot..." (*i)->GetSession()->SendPacket(&data); } } @@ -277,61 +277,15 @@ void WorldSession::DoLootRelease(uint64 lguid) } else if (loot->isLooted() || go->GetGoType() == GAMEOBJECT_TYPE_FISHINGNODE) { - // GO is mineral vein? so it is not removed after its looted - if (go->GetGoType() == GAMEOBJECT_TYPE_CHEST) - { - uint32 go_min = go->GetGOInfo()->chest.minSuccessOpens; - uint32 go_max = go->GetGOInfo()->chest.maxSuccessOpens; - - // only vein pass this check - if (go_min != 0 && go_max > go_min) - { - float amount_rate = sWorld->getRate(RATE_MINING_AMOUNT); - float min_amount = go_min*amount_rate; - float max_amount = go_max*amount_rate; - - go->AddUse(); - float uses = float(go->GetUseCount()); - - if (uses < max_amount) - { - if (uses >= min_amount) - { - float chance_rate = sWorld->getRate(RATE_MINING_NEXT); - - int32 ReqValue = 175; - LockEntry const* lockInfo = sLockStore.LookupEntry(go->GetGOInfo()->chest.lockId); - if (lockInfo) - ReqValue = lockInfo->Skill[0]; - float skill = float(player->GetSkillValue(SKILL_MINING))/(ReqValue+25); - double chance = pow(0.8*chance_rate, 4*(1/double(max_amount))*double(uses)); - if (roll_chance_f((float)(100*chance+skill))) - { - go->SetLootState(GO_READY); - } - else // not have more uses - go->SetLootState(GO_JUST_DEACTIVATED); - } - else // 100% chance until min uses - go->SetLootState(GO_READY); - } - else // max uses already - go->SetLootState(GO_JUST_DEACTIVATED); - } - else // not vein - go->SetLootState(GO_JUST_DEACTIVATED); - } - else if (go->GetGoType() == GAMEOBJECT_TYPE_FISHINGHOLE) + if (go->GetGoType() == GAMEOBJECT_TYPE_FISHINGHOLE) { // The fishing hole used once more go->AddUse(); // if the max usage is reached, will be despawned in next tick - if (go->GetUseCount() >= urand(go->GetGOInfo()->fishinghole.minSuccessOpens, go->GetGOInfo()->fishinghole.maxSuccessOpens)) - { + if (go->GetUseCount() >= go->GetGOValue()->FishingHole.MaxOpens) go->SetLootState(GO_JUST_DEACTIVATED); - } else go->SetLootState(GO_READY); } - else // not chest (or vein/herb/etc) + else go->SetLootState(GO_JUST_DEACTIVATED); loot->clear(); diff --git a/src/server/game/Handlers/MailHandler.cpp b/src/server/game/Handlers/MailHandler.cpp index 5aeb59e7383..d137e034302 100644 --- a/src/server/game/Handlers/MailHandler.cpp +++ b/src/server/game/Handlers/MailHandler.cpp @@ -32,23 +32,16 @@ void WorldSession::HandleSendMail(WorldPacket& recvData) { uint64 mailbox, unk3; - std::string receiver, subject, body; + std::string receiverName, subject, body; uint32 unk1, unk2, money, COD; uint8 unk4; - recvData >> mailbox; - recvData >> receiver; - - recvData >> subject; - - recvData >> body; - - recvData >> unk1; // stationery? - recvData >> unk2; // 0x00000000 - uint8 items_count; - recvData >> items_count; // attached items count + recvData >> mailbox >> receiverName >> subject >> body + >> unk1 // stationery? + >> unk2 // 0x00000000 + >> items_count; // attached items count - if (items_count > MAX_MAIL_ITEMS) // client limit + if (items_count > MAX_MAIL_ITEMS) // client limit { GetPlayer()->SendMailResult(0, MAIL_SEND, MAIL_ERR_TOO_MANY_ATTACHMENTS); recvData.rfinish(); // set to end to avoid warnings spam @@ -72,7 +65,7 @@ void WorldSession::HandleSendMail(WorldPacket& recvData) if (!GetPlayer()->GetGameObjectIfCanInteractWith(mailbox, GAMEOBJECT_TYPE_MAILBOX)) return; - if (receiver.empty()) + if (receiverName.empty()) return; Player* player = _player; @@ -83,21 +76,26 @@ void WorldSession::HandleSendMail(WorldPacket& recvData) return; } - uint64 rc = 0; - if (normalizePlayerName(receiver)) - rc = sObjectMgr->GetPlayerGUIDByName(receiver); + uint64 receiverGuid = 0; + if (normalizePlayerName(receiverName)) + receiverGuid = sObjectMgr->GetPlayerGUIDByName(receiverName); - if (!rc) + if (!receiverGuid) { - sLog->outInfo(LOG_FILTER_NETWORKIO, "Player %u is sending mail to %s (GUID: not existed!) with subject %s and body %s includes %u items, %u copper and %u COD copper with unk1 = %u, unk2 = %u", - player->GetGUIDLow(), receiver.c_str(), subject.c_str(), body.c_str(), items_count, money, COD, unk1, unk2); + sLog->outInfo(LOG_FILTER_NETWORKIO, "Player %u is sending mail to %s (GUID: not existed!) with subject %s " + "and body %s includes %u items, %u copper and %u COD copper with unk1 = %u, unk2 = %u", + player->GetGUIDLow(), receiverName.c_str(), subject.c_str(), body.c_str(), + items_count, money, COD, unk1, unk2); player->SendMailResult(0, MAIL_SEND, MAIL_ERR_RECIPIENT_NOT_FOUND); return; } - sLog->outInfo(LOG_FILTER_NETWORKIO, "Player %u is sending mail to %s (GUID: %u) with subject %s and body %s includes %u items, %u copper and %u COD copper with unk1 = %u, unk2 = %u", player->GetGUIDLow(), receiver.c_str(), GUID_LOPART(rc), subject.c_str(), body.c_str(), items_count, money, COD, unk1, unk2); + sLog->outInfo(LOG_FILTER_NETWORKIO, "Player %u is sending mail to %s (GUID: %u) with subject %s and body %s " + "includes %u items, %u copper and %u COD copper with unk1 = %u, unk2 = %u", + player->GetGUIDLow(), receiverName.c_str(), GUID_LOPART(receiverGuid), subject.c_str(), + body.c_str(), items_count, money, COD, unk1, unk2); - if (player->GetGUID() == rc) + if (player->GetGUID() == receiverGuid) { player->SendMailResult(0, MAIL_SEND, MAIL_ERR_CANNOT_SEND_TO_SELF); return; @@ -113,58 +111,59 @@ void WorldSession::HandleSendMail(WorldPacket& recvData) return; } - Player* receive = ObjectAccessor::FindPlayer(rc); + Player* receiver = ObjectAccessor::FindPlayer(receiverGuid); - uint32 rc_team = 0; - uint8 mails_count = 0; //do not allow to send to one player more than 100 mails - uint8 receiveLevel = 0; + uint32 receiverTeam = 0; + uint8 mailsCount = 0; //do not allow to send to one player more than 100 mails + uint8 receiverLevel = 0; + uint32 receiverAccountId = 0; - if (receive) + if (receiver) { - rc_team = receive->GetTeam(); - mails_count = receive->GetMailSize(); - receiveLevel = receive->getLevel(); + receiverTeam = receiver->GetTeam(); + mailsCount = receiver->GetMailSize(); + receiverLevel = receiver->getLevel(); + receiverAccountId = receiver->GetSession()->GetAccountId(); } else { - rc_team = sObjectMgr->GetPlayerTeamByGUID(rc); + receiverTeam = sObjectMgr->GetPlayerTeamByGUID(receiverGuid); PreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_SEL_MAIL_COUNT); - - stmt->setUInt32(0, GUID_LOPART(rc)); + stmt->setUInt32(0, GUID_LOPART(receiverGuid)); PreparedQueryResult result = CharacterDatabase.Query(stmt); - if (result) { Field* fields = result->Fetch(); - mails_count = fields[0].GetUInt64(); + mailsCount = fields[0].GetUInt64(); } stmt = CharacterDatabase.GetPreparedStatement(CHAR_SEL_CHAR_LEVEL); - - stmt->setUInt32(0, GUID_LOPART(rc)); + stmt->setUInt32(0, GUID_LOPART(receiverGuid)); result = CharacterDatabase.Query(stmt); - if (result) { Field* fields = result->Fetch(); - receiveLevel = fields[0].GetUInt8(); + receiverLevel = fields[0].GetUInt8(); } + + receiverAccountId = sObjectMgr->GetPlayerAccountIdByGUID(receiverGuid); } - //do not allow to have more than 100 mails in mailbox.. mails count is in opcode uint8!!! - so max can be 255.. - if (mails_count > 100) + + // do not allow to have more than 100 mails in mailbox.. mails count is in opcode uint8!!! - so max can be 255.. + if (mailsCount > 100) { player->SendMailResult(0, MAIL_SEND, MAIL_ERR_RECIPIENT_CAP_REACHED); return; } + // test the receiver's Faction... or all items are account bound bool accountBound = items_count ? true : false; for (uint8 i = 0; i < items_count; ++i) { - Item* item = player->GetItemByGuid(itemGUIDs[i]); - if (item) + if (Item* item = player->GetItemByGuid(itemGUIDs[i])) { ItemTemplate const* itemProto = item->GetTemplate(); if (!itemProto || !(itemProto->Flags & ITEM_PROTO_FLAG_BIND_TO_ACCOUNT)) @@ -175,22 +174,18 @@ void WorldSession::HandleSendMail(WorldPacket& recvData) } } - if (!accountBound && !sWorld->getBoolConfig(CONFIG_ALLOW_TWO_SIDE_INTERACTION_MAIL) && player->GetTeam() != rc_team && AccountMgr::IsPlayerAccount(GetSecurity())) + if (!accountBound && player->GetTeam() != receiverTeam && !HasPermission(RBAC_PERM_TWO_SIDE_INTERACTION_MAIL)) { player->SendMailResult(0, MAIL_SEND, MAIL_ERR_NOT_YOUR_TEAM); return; } - if (receiveLevel < sWorld->getIntConfig(CONFIG_MAIL_LEVEL_REQ)) + if (receiverLevel < sWorld->getIntConfig(CONFIG_MAIL_LEVEL_REQ)) { SendNotification(GetTrinityString(LANG_MAIL_RECEIVER_REQ), sWorld->getIntConfig(CONFIG_MAIL_LEVEL_REQ)); return; } - uint32 rc_account = receive - ? receive->GetSession()->GetAccountId() - : sObjectMgr->GetPlayerAccountIdByGUID(rc); - Item* items[MAX_MAIL_ITEMS]; for (uint8 i = 0; i < items_count; ++i) @@ -216,7 +211,7 @@ void WorldSession::HandleSendMail(WorldPacket& recvData) return; } - if (item->IsBoundAccountWide() && item->IsSoulBound() && player->GetSession()->GetAccountId() != rc_account) + if (item->IsBoundAccountWide() && item->IsSoulBound() && player->GetSession()->GetAccountId() != receiverAccountId) { player->SendMailResult(0, MAIL_SEND, MAIL_ERR_EQUIP_ERROR, EQUIP_ERR_ARTEFACTS_ONLY_FOR_OWN_CHARACTERS); return; @@ -256,35 +251,38 @@ void WorldSession::HandleSendMail(WorldPacket& recvData) if (items_count > 0 || money > 0) { + bool log = HasPermission(RBAC_PERM_LOG_GM_TRADE); if (items_count > 0) { for (uint8 i = 0; i < items_count; ++i) { Item* item = items[i]; - if (!AccountMgr::IsPlayerAccount(GetSecurity()) && sWorld->getBoolConfig(CONFIG_GM_LOG_TRADE)) + if (log) { - sLog->outCommand(GetAccountId(), "GM %s (Account: %u) mail item: %s (Entry: %u Count: %u) to player: %s (Account: %u)", - GetPlayerName().c_str(), GetAccountId(), item->GetTemplate()->Name1.c_str(), item->GetEntry(), item->GetCount(), receiver.c_str(), rc_account); + sLog->outCommand(GetAccountId(), "GM %s (Account: %u) mail item: %s (Entry: %u Count: %u) " + "to player: %s (Account: %u)", GetPlayerName().c_str(), GetAccountId(), + item->GetTemplate()->Name1.c_str(), item->GetEntry(), item->GetCount(), + receiverName.c_str(), receiverAccountId); } item->SetNotRefundable(GetPlayer()); // makes the item no longer refundable player->MoveItemFromInventory(items[i]->GetBagSlot(), item->GetSlot(), true); item->DeleteFromInventoryDB(trans); // deletes item from character's inventory - item->SetOwnerGUID(rc); + item->SetOwnerGUID(receiverGuid); item->SaveToDB(trans); // recursive and not have transaction guard into self, item not in inventory and can be save standalone draft.AddItem(item); } // if item send to character at another account, then apply item delivery delay - needItemDelay = player->GetSession()->GetAccountId() != rc_account; + needItemDelay = player->GetSession()->GetAccountId() != receiverAccountId; } - if (money > 0 && !AccountMgr::IsPlayerAccount(GetSecurity()) && sWorld->getBoolConfig(CONFIG_GM_LOG_TRADE)) + if (log && money > 0) { sLog->outCommand(GetAccountId(), "GM %s (Account: %u) mail money: %u to player: %s (Account: %u)", - GetPlayerName().c_str(), GetAccountId(), money, receiver.c_str(), rc_account); + GetPlayerName().c_str(), GetAccountId(), money, receiverName.c_str(), receiverAccountId); } } @@ -295,7 +293,7 @@ void WorldSession::HandleSendMail(WorldPacket& recvData) draft .AddMoney(money) .AddCOD(COD) - .SendMailTo(trans, MailReceiver(receive, GUID_LOPART(rc)), MailSender(player), body.empty() ? MAIL_CHECK_MASK_COPIED : MAIL_CHECK_MASK_HAS_BODY, deliver_delay); + .SendMailTo(trans, MailReceiver(receiver, GUID_LOPART(receiverGuid)), MailSender(player), body.empty() ? MAIL_CHECK_MASK_COPIED : MAIL_CHECK_MASK_HAS_BODY, deliver_delay); player->SaveInventoryAndGoldToDB(trans); CharacterDatabase.CommitTransaction(trans); @@ -458,17 +456,17 @@ void WorldSession::HandleMailTakeItem(WorldPacket& recvData) if (m->COD > 0) //if there is COD, take COD money from player and send them to sender by mail { uint64 sender_guid = MAKE_NEW_GUID(m->sender, 0, HIGHGUID_PLAYER); - Player* receive = ObjectAccessor::FindPlayer(sender_guid); + Player* receiver = ObjectAccessor::FindPlayer(sender_guid); uint32 sender_accId = 0; - if (!AccountMgr::IsPlayerAccount(GetSecurity()) && sWorld->getBoolConfig(CONFIG_GM_LOG_TRADE)) + if (HasPermission(RBAC_PERM_LOG_GM_TRADE)) { std::string sender_name; - if (receive) + if (receiver) { - sender_accId = receive->GetSession()->GetAccountId(); - sender_name = receive->GetName(); + sender_accId = receiver->GetSession()->GetAccountId(); + sender_name = receiver->GetName(); } else { @@ -478,18 +476,18 @@ void WorldSession::HandleMailTakeItem(WorldPacket& recvData) if (!sObjectMgr->GetPlayerNameByGUID(sender_guid, sender_name)) sender_name = sObjectMgr->GetTrinityStringForDBCLocale(LANG_UNKNOWN); } - sLog->outCommand(GetAccountId(), "GM %s (Account: %u) receive mail item: %s (Entry: %u Count: %u) and send COD money: %u to player: %s (Account: %u)", + sLog->outCommand(GetAccountId(), "GM %s (Account: %u) receiver mail item: %s (Entry: %u Count: %u) and send COD money: %u to player: %s (Account: %u)", GetPlayerName().c_str(), GetAccountId(), it->GetTemplate()->Name1.c_str(), it->GetEntry(), it->GetCount(), m->COD, sender_name.c_str(), sender_accId); } - else if (!receive) + else if (!receiver) sender_accId = sObjectMgr->GetPlayerAccountIdByGUID(sender_guid); // check player existence - if (receive || sender_accId) + if (receiver || sender_accId) { MailDraft(m->subject, "") .AddMoney(m->COD) - .SendMailTo(trans, MailReceiver(receive, m->sender), MailSender(MAIL_NORMAL, m->receiver), MAIL_CHECK_MASK_COD_PAYMENT); + .SendMailTo(trans, MailReceiver(receiver, m->sender), MailSender(MAIL_NORMAL, m->receiver), MAIL_CHECK_MASK_COD_PAYMENT); } player->ModifyMoney(-int32(m->COD)); @@ -532,13 +530,18 @@ void WorldSession::HandleMailTakeMoney(WorldPacket& recvData) return; } - player->SendMailResult(mailId, MAIL_MONEY_TAKEN, MAIL_OK); + if (!player->ModifyMoney(m->money, false)) + { + player->SendMailResult(mailId, MAIL_MONEY_TAKEN, MAIL_ERR_EQUIP_ERROR, EQUIP_ERR_TOO_MUCH_GOLD); + return; + } - player->ModifyMoney(m->money); m->money = 0; m->state = MAIL_STATE_CHANGED; player->m_mailsUpdated = true; + player->SendMailResult(mailId, MAIL_MONEY_TAKEN, MAIL_OK); + // save money and mail to prevent cheating SQLTransaction trans = CharacterDatabase.BeginTransaction(); player->SaveGoldToDB(trans); @@ -732,7 +735,7 @@ void WorldSession::HandleMailCreateTextItem(WorldPacket& recvData) } } -//TODO Fix me! ... this void has probably bad condition, but good data are sent +/// @todo Fix me! ... this void has probably bad condition, but good data are sent void WorldSession::HandleQueryNextMailTime(WorldPacket & /*recvData*/) { WorldPacket data(MSG_QUERY_NEXT_MAIL_TIME, 8); diff --git a/src/server/game/Handlers/MiscHandler.cpp b/src/server/game/Handlers/MiscHandler.cpp index 3ee14ed429a..5a9289904f5 100644 --- a/src/server/game/Handlers/MiscHandler.cpp +++ b/src/server/game/Handlers/MiscHandler.cpp @@ -241,8 +241,7 @@ void WorldSession::HandleWhoOpcode(WorldPacket& recvData) level_max = STRONG_MAX_LEVEL; uint32 team = _player->GetTeam(); - uint32 security = GetSecurity(); - bool allowTwoSideWhoList = sWorld->getBoolConfig(CONFIG_ALLOW_TWO_SIDE_WHO_LIST); + uint32 gmLevelInWhoList = sWorld->getIntConfig(CONFIG_GM_LEVEL_IN_WHO_LIST); uint32 displaycount = 0; @@ -254,42 +253,40 @@ void WorldSession::HandleWhoOpcode(WorldPacket& recvData) HashMapHolder<Player>::MapType const& m = sObjectAccessor->GetPlayers(); for (HashMapHolder<Player>::MapType::const_iterator itr = m.begin(); itr != m.end(); ++itr) { - if (AccountMgr::IsPlayerAccount(security)) - { - // player can see member of other team only if CONFIG_ALLOW_TWO_SIDE_WHO_LIST - if (itr->second->GetTeam() != team && !allowTwoSideWhoList) - continue; + Player* target = itr->second; + // player can see member of other team only if CONFIG_ALLOW_TWO_SIDE_WHO_LIST + if (target->GetTeam() != team && !HasPermission(RBAC_PERM_TWO_SIDE_WHO_LIST)) + continue; - // player can see MODERATOR, GAME MASTER, ADMINISTRATOR only if CONFIG_GM_IN_WHO_LIST - if ((itr->second->GetSession()->GetSecurity() > AccountTypes(gmLevelInWhoList))) - continue; - } + // player can see MODERATOR, GAME MASTER, ADMINISTRATOR only if CONFIG_GM_IN_WHO_LIST + if (!HasPermission(RBAC_PERM_WHO_SEE_ALL_SEC_LEVELS) && target->GetSession()->GetSecurity() > AccountTypes(gmLevelInWhoList)) + continue; - //do not process players which are not in world - if (!(itr->second->IsInWorld())) + // do not process players which are not in world + if (!target->IsInWorld()) continue; // check if target is globally visible for player - if (!(itr->second->IsVisibleGloballyFor(_player))) + if (!target->IsVisibleGloballyFor(_player)) continue; // check if target's level is in level range - uint8 lvl = itr->second->getLevel(); + uint8 lvl = target->getLevel(); if (lvl < level_min || lvl > level_max) continue; // check if class matches classmask - uint32 class_ = itr->second->getClass(); + uint8 class_ = target->getClass(); if (!(classmask & (1 << class_))) continue; // check if race matches racemask - uint32 race = itr->second->getRace(); + uint32 race = target->getRace(); if (!(racemask & (1 << race))) continue; - uint32 pzoneid = itr->second->GetZoneId(); - uint8 gender = itr->second->getGender(); + uint32 pzoneid = target->GetZoneId(); + uint8 gender = target->getGender(); bool z_show = true; for (uint32 i = 0; i < zones_count; ++i) @@ -305,7 +302,7 @@ void WorldSession::HandleWhoOpcode(WorldPacket& recvData) if (!z_show) continue; - std::string pname = itr->second->GetName(); + std::string pname = target->GetName(); std::wstring wpname; if (!Utf8toWStr(pname, wpname)) continue; @@ -314,7 +311,7 @@ void WorldSession::HandleWhoOpcode(WorldPacket& recvData) if (!(wplayer_name.empty() || wpname.find(wplayer_name) != std::wstring::npos)) continue; - std::string gname = sGuildMgr->GetGuildNameById(itr->second->GetGuildId()); + std::string gname = sGuildMgr->GetGuildNameById(target->GetGuildId()); std::wstring wgname; if (!Utf8toWStr(gname, wgname)) continue; @@ -324,7 +321,7 @@ void WorldSession::HandleWhoOpcode(WorldPacket& recvData) continue; std::string aname; - if (AreaTableEntry const* areaEntry = GetAreaEntryByAreaID(itr->second->GetZoneId())) + if (AreaTableEntry const* areaEntry = GetAreaEntryByAreaID(pzoneid)) aname = areaEntry->area_name[GetSessionDbcLocale()]; bool s_show = true; @@ -375,33 +372,34 @@ void WorldSession::HandleLogoutRequestOpcode(WorldPacket& /*recvData*/) if (uint64 lguid = GetPlayer()->GetLootGUID()) DoLootRelease(lguid); - uint8 reason = 0; + bool instantLogout = (GetPlayer()->HasFlag(PLAYER_FLAGS, PLAYER_FLAGS_RESTING) && !GetPlayer()->isInCombat()) || + GetPlayer()->isInFlight() || HasPermission(RBAC_PERM_INSTANT_LOGOUT); + + /// TODO: Possibly add RBAC permission to log out in combat + bool canLogoutInCombat = GetPlayer()->HasFlag(PLAYER_FLAGS, PLAYER_FLAGS_RESTING); - if (GetPlayer()->isInCombat()) + uint32 reason = 0; + if (GetPlayer()->isInCombat() && !canLogoutInCombat) reason = 1; else if (GetPlayer()->m_movementInfo.HasMovementFlag(MOVEMENTFLAG_FALLING | MOVEMENTFLAG_FALLING_FAR)) reason = 3; // is jumping or falling else if (GetPlayer()->duel || GetPlayer()->HasAura(9454)) // is dueling or frozen by GM via freeze command reason = 2; // FIXME - Need the correct value + WorldPacket data(SMSG_LOGOUT_RESPONSE, 1+4); + data << uint32(reason); + data << uint8(instantLogout); + SendPacket(&data); + if (reason) { - WorldPacket data(SMSG_LOGOUT_RESPONSE, 1+4); - data << uint8(reason); - data << uint32(0); - SendPacket(&data); LogoutRequest(0); return; } //instant logout in taverns/cities or on taxi or for admins, gm's, mod's if its enabled in worldserver.conf - if (GetPlayer()->HasFlag(PLAYER_FLAGS, PLAYER_FLAGS_RESTING) || GetPlayer()->isInFlight() || - GetSecurity() >= AccountTypes(sWorld->getIntConfig(CONFIG_INSTANT_LOGOUT))) + if (instantLogout) { - WorldPacket data(SMSG_LOGOUT_RESPONSE, 1+4); - data << uint8(0); - data << uint32(16777216); - SendPacket(&data); LogoutPlayer(true); return; } @@ -418,10 +416,6 @@ void WorldSession::HandleLogoutRequestOpcode(WorldPacket& /*recvData*/) GetPlayer()->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_STUNNED); } - WorldPacket data(SMSG_LOGOUT_RESPONSE, 1+4); - data << uint8(0); - data << uint32(0); - SendPacket(&data); LogoutRequest(time(NULL)); } @@ -480,13 +474,13 @@ void WorldSession::HandleTogglePvP(WorldPacket& recvData) if (GetPlayer()->HasFlag(PLAYER_FLAGS, PLAYER_FLAGS_IN_PVP)) { - if (!GetPlayer()->IsPvP() || GetPlayer()->pvpInfo.endTimer != 0) + if (!GetPlayer()->IsPvP() || GetPlayer()->pvpInfo.EndTimer) GetPlayer()->UpdatePvP(true, true); } else { - if (!GetPlayer()->pvpInfo.inHostileArea && GetPlayer()->IsPvP()) - GetPlayer()->pvpInfo.endTimer = time(NULL); // start toggle-off + if (!GetPlayer()->pvpInfo.IsHostile && GetPlayer()->IsPvP()) + GetPlayer()->pvpInfo.EndTimer = time(NULL); // start toggle-off } //if (OutdoorPvP* pvp = _player->GetOutdoorPvP()) @@ -578,13 +572,13 @@ void WorldSession::HandleAddFriendOpcodeCallBack(PreparedQueryResult result, std team = Player::TeamForRace(fields[1].GetUInt8()); friendAccountId = fields[2].GetUInt32(); - if (!AccountMgr::IsPlayerAccount(GetSecurity()) || sWorld->getBoolConfig(CONFIG_ALLOW_GM_FRIEND) || AccountMgr::IsPlayerAccount(AccountMgr::GetSecurity(friendAccountId, realmID))) + if (HasPermission(RBAC_PERM_ALLOW_GM_FRIEND) || AccountMgr::IsPlayerAccount(AccountMgr::GetSecurity(friendAccountId, realmID))) { if (friendGuid) { if (friendGuid == GetPlayer()->GetGUID()) friendResult = FRIEND_SELF; - else if (GetPlayer()->GetTeam() != team && !sWorld->getBoolConfig(CONFIG_ALLOW_TWO_SIDE_ADD_FRIEND) && AccountMgr::IsPlayerAccount(GetSecurity())) + else if (GetPlayer()->GetTeam() != team && !HasPermission(RBAC_PERM_TWO_SIDE_ADD_FRIEND)) friendResult = FRIEND_ENEMY; else if (GetPlayer()->GetSocial()->HasFriend(GUID_LOPART(friendGuid))) friendResult = FRIEND_ALREADY; @@ -976,7 +970,7 @@ void WorldSession::HandleUpdateAccountData(WorldPacket& recvData) dest.resize(decompressedSize); uLongf realSize = decompressedSize; - if (uncompress(const_cast<uint8*>(dest.contents()), &realSize, const_cast<uint8*>(recvData.contents() + recvData.rpos()), recvData.size() - recvData.rpos()) != Z_OK) + if (uncompress(dest.contents(), &realSize, recvData.contents() + recvData.rpos(), recvData.size() - recvData.rpos()) != Z_OK) { recvData.rfinish(); // unnneded warning spam in this case sLog->outError(LOG_FILTER_NETWORKIO, "UAD: Failed to decompress account data"); @@ -1017,7 +1011,7 @@ void WorldSession::HandleRequestAccountData(WorldPacket& recvData) ByteBuffer dest; dest.resize(destSize); - if (size && compress(const_cast<uint8*>(dest.contents()), &destSize, (uint8*)adata->Data.c_str(), size) != Z_OK) + if (size && compress(dest.contents(), &destSize, (uint8 const*)adata->Data.c_str(), size) != Z_OK) { sLog->outDebug(LOG_FILTER_NETWORKIO, "RAD: Failed to compress account data"); return; @@ -1072,7 +1066,7 @@ void WorldSession::HandleMoveTimeSkippedOpcode(WorldPacket& recvData) recvData >> time_skipped; sLog->outDebug(LOG_FILTER_PACKETIO, "WORLD: CMSG_MOVE_TIME_SKIPPED"); - /// TODO + //// @todo must be need use in Trinity We substract server Lags to move time (AntiLags) for exmaple @@ -1251,7 +1245,7 @@ void WorldSession::HandleWorldTeleportOpcode(WorldPacket& recvData) sLog->outDebug(LOG_FILTER_NETWORKIO, "CMSG_WORLD_TELEPORT: Player = %s, Time = %u, map = %u, x = %f, y = %f, z = %f, o = %f", GetPlayer()->GetName().c_str(), time, mapid, PositionX, PositionY, PositionZ, Orientation); - if (AccountMgr::IsAdminAccount(GetSecurity())) + if (HasPermission(RBAC_PERM_OPCODE_WORLD_TELEPORT)) GetPlayer()->TeleportTo(mapid, PositionX, PositionY, PositionZ, Orientation); else SendNotification(LANG_YOU_NOT_HAVE_PERMISSION); @@ -1263,7 +1257,7 @@ void WorldSession::HandleWhoisOpcode(WorldPacket& recvData) std::string charname; recvData >> charname; - if (!AccountMgr::IsAdminAccount(GetSecurity())) + if (!HasPermission(RBAC_PERM_OPCODE_WHOIS)) { SendNotification(LANG_YOU_NOT_HAVE_PERMISSION); return; @@ -1342,7 +1336,7 @@ void WorldSession::HandleComplainOpcode(WorldPacket& recvData) recvData >> unk1; // probably language recvData >> unk2; // message type? recvData >> unk3; // probably channel id - recvData >> unk4; // unk random value + recvData >> unk4; // time recvData >> description; // spam description string (messagetype, channel name, player name, message) break; } @@ -1587,8 +1581,7 @@ void WorldSession::HandleCancelMountAuraOpcode(WorldPacket& /*recvData*/) return; } - _player->Dismount(); - _player->RemoveAurasByType(SPELL_AURA_MOUNTED); + _player->RemoveAurasByType(SPELL_AURA_MOUNTED); // Calls Dismount() } void WorldSession::HandleMoveSetCanFlyAckOpcode(WorldPacket& recvData) @@ -1684,7 +1677,7 @@ void WorldSession::HandleAreaSpiritHealerQueryOpcode(WorldPacket& recvData) sBattlegroundMgr->SendAreaSpiritHealerQueryOpcode(_player, bg, guid); if (Battlefield* bf = sBattlefieldMgr->GetBattlefieldToZoneId(_player->GetZoneId())) - bf->SendAreaSpiritHealerQueryOpcode(_player,guid); + bf->SendAreaSpiritHealerQueryOpcode(_player, guid); } void WorldSession::HandleAreaSpiritHealerQueueOpcode(WorldPacket& recvData) diff --git a/src/server/game/Handlers/MovementHandler.cpp b/src/server/game/Handlers/MovementHandler.cpp index ee0d4f2a1f2..6f1c2a30d5e 100644 --- a/src/server/game/Handlers/MovementHandler.cpp +++ b/src/server/game/Handlers/MovementHandler.cpp @@ -126,7 +126,7 @@ void WorldSession::HandleMoveWorldportAckOpcode() { // short preparations to continue flight FlightPathMovementGenerator* flight = (FlightPathMovementGenerator*)(GetPlayer()->GetMotionMaster()->top()); - flight->Initialize(*GetPlayer()); + flight->Initialize(GetPlayer()); return; } @@ -174,7 +174,7 @@ void WorldSession::HandleMoveWorldportAckOpcode() GetPlayer()->UpdateZone(newzone, newarea); // honorless target - if (GetPlayer()->pvpInfo.inHostileArea) + if (GetPlayer()->pvpInfo.IsHostile) GetPlayer()->CastSpell(GetPlayer(), 2479, true); // in friendly area @@ -224,7 +224,7 @@ void WorldSession::HandleMoveTeleportAck(WorldPacket& recvData) if (old_zone != newzone) { // honorless target - if (plMover->pvpInfo.inHostileArea) + if (plMover->pvpInfo.IsHostile) plMover->CastSpell(plMover, 2479, true); // in friendly area @@ -392,7 +392,7 @@ void WorldSession::HandleMovementOpcodes(WorldPacket& recvData) { // NOTE: this is actually called many times while falling // even after the player has been teleported away - // TODO: discard movement packets after the player is rooted + /// @todo discard movement packets after the player is rooted if (plrMover->isAlive()) { plrMover->EnvironmentalDamage(DAMAGE_FALL_TO_VOID, GetPlayer()->GetMaxHealth()); diff --git a/src/server/game/Handlers/PetHandler.cpp b/src/server/game/Handlers/PetHandler.cpp index 98bcab81763..fc5f6fbd513 100644 --- a/src/server/game/Handlers/PetHandler.cpp +++ b/src/server/game/Handlers/PetHandler.cpp @@ -93,7 +93,7 @@ void WorldSession::HandlePetAction(WorldPacket& recvData) return; } - //TODO: allow control charmed player? + /// @todo allow control charmed player? if (pet->GetTypeId() == TYPEID_PLAYER && !(flag == ACT_COMMAND && spellid == COMMAND_ATTACK)) return; @@ -185,7 +185,7 @@ void WorldSession::HandlePetActionHelper(Unit* pet, uint64 guid1, uint32 spellid if (_player->HasAuraType(SPELL_AURA_MOD_PACIFY)) { //pet->SendPetCastFail(spellid, SPELL_FAILED_PACIFIED); - //TODO: Send proper error message to client + /// @todo Send proper error message to client return; } @@ -198,13 +198,6 @@ void WorldSession::HandlePetActionHelper(Unit* pet, uint64 guid1, uint32 spellid if (!owner->IsValidAttackTarget(TargetUnit)) return; - // Not let attack through obstructions - if (sWorld->getBoolConfig(CONFIG_PET_LOS)) - { - if (!pet->IsWithinLOSInMap(TargetUnit)) - return; - } - pet->ClearUnitState(UNIT_STATE_FOLLOW); // This is true if pet has no target or has target but targets differs. if (pet->getVictim() != TargetUnit || (pet->getVictim() == TargetUnit && !pet->GetCharmInfo()->IsCommandAttack())) @@ -799,7 +792,7 @@ void WorldSession::HandlePetCastSpellOpcode(WorldPacket& recvPacket) spell->m_cast_count = castCount; // probably pending spell cast spell->m_targets = targets; - // TODO: need to check victim? + /// @todo need to check victim? SpellCastResult result; if (caster->m_movedPlayer) result = spell->CheckPetCast(caster->m_movedPlayer->GetSelectedUnit()); diff --git a/src/server/game/Handlers/PetitionsHandler.cpp b/src/server/game/Handlers/PetitionsHandler.cpp index b4510545def..83cf793519f 100644 --- a/src/server/game/Handlers/PetitionsHandler.cpp +++ b/src/server/game/Handlers/PetitionsHandler.cpp @@ -111,7 +111,7 @@ void WorldSession::HandlePetitionBuyOpcode(WorldPacket& recvData) } else { - // TODO: find correct opcode + /// @todo find correct opcode if (_player->getLevel() < sWorld->getIntConfig(CONFIG_MAX_PLAYER_LEVEL)) { SendNotification(LANG_ARENA_ONE_TOOLOW, sWorld->getIntConfig(CONFIG_MAX_PLAYER_LEVEL)); diff --git a/src/server/game/Handlers/QuestHandler.cpp b/src/server/game/Handlers/QuestHandler.cpp index 4e5dbb306fa..97e13d52913 100644 --- a/src/server/game/Handlers/QuestHandler.cpp +++ b/src/server/game/Handlers/QuestHandler.cpp @@ -425,10 +425,16 @@ void WorldSession::HandleQuestLogRemoveQuest(WorldPacket& recvData) if (!_player->TakeQuestSourceItem(questId, true)) return; // can't un-equip some items, reject quest cancel - if (const Quest *quest = sObjectMgr->GetQuestTemplate(questId)) + if (Quest const* quest = sObjectMgr->GetQuestTemplate(questId)) { if (quest->HasFlag(QUEST_TRINITY_FLAGS_TIMED)) _player->RemoveTimedQuest(questId); + + if (quest->HasFlag(QUEST_FLAGS_FLAGS_PVP)) + { + _player->pvpInfo.IsHostile = _player->pvpInfo.IsInHostileArea || _player->HasPvPForcingQuest(); + _player->UpdatePvPState(); + } } _player->TakeQuestSourceItem(questId, true); // remove quest src item from player @@ -496,7 +502,7 @@ void WorldSession::HandleQuestgiverCompleteQuest(WorldPacket& recvData) _player->GetName().c_str(), _player->GetGUIDLow(), questId); return; } - // TODO: need a virtual function + /// @todo need a virtual function if (_player->InBattleground()) if (Battleground* bg = _player->GetBattleground()) if (bg->GetTypeID() == BATTLEGROUND_AV) diff --git a/src/server/game/Handlers/ReferAFriendHandler.cpp b/src/server/game/Handlers/ReferAFriendHandler.cpp index a40e763b030..8a1793af557 100644 --- a/src/server/game/Handlers/ReferAFriendHandler.cpp +++ b/src/server/game/Handlers/ReferAFriendHandler.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2013 TrinityCore <http://www.trinitycore.org/> + * Copyright (C) 2008-2013 TrinityCore <http://www.trinitycore.org/> * * 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 diff --git a/src/server/game/Handlers/SpellHandler.cpp b/src/server/game/Handlers/SpellHandler.cpp index 45cb8164775..c0b72f1b80c 100644 --- a/src/server/game/Handlers/SpellHandler.cpp +++ b/src/server/game/Handlers/SpellHandler.cpp @@ -59,7 +59,7 @@ void WorldSession::HandleClientCastFlags(WorldPacket& recvPacket, uint8 castFlag void WorldSession::HandleUseItemOpcode(WorldPacket& recvPacket) { - // TODO: add targets.read() check + /// @todo add targets.read() check Player* pUser = _player; // ignore for remote control state @@ -271,12 +271,15 @@ void WorldSession::HandleGameObjectUseOpcode(WorldPacket& recvData) sLog->outDebug(LOG_FILTER_NETWORKIO, "WORLD: Recvd CMSG_GAMEOBJ_USE Message [guid=%u]", GUID_LOPART(guid)); - // ignore for remote control state - if (_player->m_mover != _player) - return; - if (GameObject* obj = GetPlayer()->GetMap()->GetGameObject(guid)) + { + // ignore for remote control state + if (_player->m_mover != _player) + if (!(_player->IsOnVehicle(_player->m_mover) || _player->IsMounted()) && !obj->GetGOInfo()->IsUsableMounted()) + return; + obj->Use(_player); + } } void WorldSession::HandleGameobjectReportUse(WorldPacket& recvPacket) @@ -320,7 +323,6 @@ void WorldSession::HandleCastSpellOpcode(WorldPacket& recvPacket) } SpellInfo const* spellInfo = sSpellMgr->GetSpellInfo(spellId); - if (!spellInfo) { sLog->outError(LOG_FILTER_NETWORKIO, "WORLD: unknown spell id %u", spellId); @@ -328,31 +330,37 @@ void WorldSession::HandleCastSpellOpcode(WorldPacket& recvPacket) return; } - if (mover->GetTypeId() == TYPEID_PLAYER) + if (spellInfo->IsPassive()) { - // not have spell in spellbook or spell passive and not casted by client - if (!mover->ToPlayer()->HasActiveSpell (spellId) || spellInfo->IsPassive()) - { - //cheater? kick? ban? - recvPacket.rfinish(); // prevent spam at ignore packet - return; - } + recvPacket.rfinish(); // prevent spam at ignore packet + return; } - else + + Unit* caster = mover; + if (caster->GetTypeId() == TYPEID_UNIT && !caster->ToCreature()->HasSpell(spellId)) { - // not have spell in spellbook or spell passive and not casted by client - if ((mover->GetTypeId() == TYPEID_UNIT && !mover->ToCreature()->HasSpell(spellId)) || spellInfo->IsPassive()) + // If the vehicle creature does not have the spell but it allows the passenger to cast own spells + // change caster to player and let him cast + if (!_player->IsOnVehicle(caster) || spellInfo->CheckVehicle(_player) != SPELL_CAST_OK) { - //cheater? kick? ban? recvPacket.rfinish(); // prevent spam at ignore packet return; } + + caster = _player; + } + + if (caster->GetTypeId() == TYPEID_PLAYER && !caster->ToPlayer()->HasActiveSpell(spellId)) + { + // not have spell in spellbook + recvPacket.rfinish(); // prevent spam at ignore packet + return; } // Client is resending autoshot cast opcode when other spell is casted during shoot rotation // Skip it to prevent "interrupt" message - if (spellInfo->IsAutoRepeatRangedSpell() && _player->GetCurrentSpell(CURRENT_AUTOREPEAT_SPELL) - && _player->GetCurrentSpell(CURRENT_AUTOREPEAT_SPELL)->m_spellInfo == spellInfo) + if (spellInfo->IsAutoRepeatRangedSpell() && caster->GetCurrentSpell(CURRENT_AUTOREPEAT_SPELL) + && caster->GetCurrentSpell(CURRENT_AUTOREPEAT_SPELL)->m_spellInfo == spellInfo) { recvPacket.rfinish(); return; @@ -367,7 +375,7 @@ void WorldSession::HandleCastSpellOpcode(WorldPacket& recvPacket) // client provided targets SpellCastTargets targets; - targets.Read(recvPacket, mover); + targets.Read(recvPacket, caster); HandleClientCastFlags(recvPacket, castFlags, targets); // auto-selection buff level base at target level (in spellInfo) @@ -380,7 +388,7 @@ void WorldSession::HandleCastSpellOpcode(WorldPacket& recvPacket) spellInfo = actualSpellInfo; } - Spell* spell = new Spell(mover, spellInfo, TRIGGERED_NONE, 0, false); + Spell* spell = new Spell(caster, spellInfo, TRIGGERED_NONE, 0, false); spell->m_cast_count = castCount; // set count of casts spell->prepare(&targets); } @@ -542,7 +550,7 @@ void WorldSession::HandleSpellClick(WorldPacket& recvData) if (!unit) return; - // TODO: Unit::SetCharmedBy: 28782 is not in world but 0 is trying to charm it! -> crash + /// @todo Unit::SetCharmedBy: 28782 is not in world but 0 is trying to charm it! -> crash if (!unit->IsInWorld()) return; diff --git a/src/server/game/Handlers/TaxiHandler.cpp b/src/server/game/Handlers/TaxiHandler.cpp index b7155e552c7..53334cffd18 100644 --- a/src/server/game/Handlers/TaxiHandler.cpp +++ b/src/server/game/Handlers/TaxiHandler.cpp @@ -269,7 +269,7 @@ void WorldSession::HandleMoveSplineDoneOpcode(WorldPacket& recvData) GetPlayer()->CleanupAfterTaxiFlight(); GetPlayer()->SetFallInformation(0, GetPlayer()->GetPositionZ()); - if (GetPlayer()->pvpInfo.inHostileArea) + if (GetPlayer()->pvpInfo.IsHostile) GetPlayer()->CastSpell(GetPlayer(), 2479, true); } diff --git a/src/server/game/Handlers/TicketHandler.cpp b/src/server/game/Handlers/TicketHandler.cpp index 4463613a97b..2da2735a3f9 100644 --- a/src/server/game/Handlers/TicketHandler.cpp +++ b/src/server/game/Handlers/TicketHandler.cpp @@ -69,7 +69,7 @@ void WorldSession::HandleGMTicketCreateOpcode(WorldPacket& recvData) dest.resize(decompressedSize); uLongf realSize = decompressedSize; - if (uncompress(const_cast<uint8*>(dest.contents()), &realSize, const_cast<uint8*>(recvData.contents() + pos), recvData.size() - pos) == Z_OK) + if (uncompress(dest.contents(), &realSize, recvData.contents() + pos, recvData.size() - pos) == Z_OK) { dest >> chatLog; ticket->SetChatLog(times, chatLog); diff --git a/src/server/game/Handlers/TradeHandler.cpp b/src/server/game/Handlers/TradeHandler.cpp index 2f9db8687c3..8155dacf1d8 100644 --- a/src/server/game/Handlers/TradeHandler.cpp +++ b/src/server/game/Handlers/TradeHandler.cpp @@ -152,7 +152,7 @@ void WorldSession::moveItems(Item* myItems[], Item* hisItems[]) { // logging sLog->outDebug(LOG_FILTER_NETWORKIO, "partner storing: %u", myItems[i]->GetGUIDLow()); - if (!AccountMgr::IsPlayerAccount(_player->GetSession()->GetSecurity()) && sWorld->getBoolConfig(CONFIG_GM_LOG_TRADE)) + if (HasPermission(RBAC_PERM_LOG_GM_TRADE)) { sLog->outCommand(_player->GetSession()->GetAccountId(), "GM %s (Account: %u) trade: %s (Entry: %d Count: %u) to player: %s (Account: %u)", _player->GetName().c_str(), _player->GetSession()->GetAccountId(), @@ -170,7 +170,7 @@ void WorldSession::moveItems(Item* myItems[], Item* hisItems[]) { // logging sLog->outDebug(LOG_FILTER_NETWORKIO, "player storing: %u", hisItems[i]->GetGUIDLow()); - if (!AccountMgr::IsPlayerAccount(trader->GetSession()->GetSecurity()) && sWorld->getBoolConfig(CONFIG_GM_LOG_TRADE)) + if (HasPermission(RBAC_PERM_LOG_GM_TRADE)) { sLog->outCommand(trader->GetSession()->GetAccountId(), "GM %s (Account: %u) trade: %s (Entry: %d Count: %u) to player: %s (Account: %u)", trader->GetName().c_str(), trader->GetSession()->GetAccountId(), @@ -292,6 +292,20 @@ void WorldSession::HandleAcceptTradeOpcode(WorldPacket& /*recvPacket*/) return; } + if (_player->GetMoney() >= uint32(MAX_MONEY_AMOUNT) - his_trade->GetMoney()) + { + _player->SendEquipError(EQUIP_ERR_TOO_MUCH_GOLD, NULL, NULL); + my_trade->SetAccepted(false, true); + return; + } + + if (trader->GetMoney() >= uint32(MAX_MONEY_AMOUNT) - my_trade->GetMoney()) + { + trader->SendEquipError(EQUIP_ERR_TOO_MUCH_GOLD, NULL, NULL); + his_trade->SetAccepted(false, true); + return; + } + // not accept if some items now can't be trade (cheating) for (uint8 i = 0; i < TRADE_SLOT_TRADED_COUNT; ++i) { @@ -302,6 +316,7 @@ void WorldSession::HandleAcceptTradeOpcode(WorldPacket& /*recvPacket*/) SendTradeStatus(TRADE_STATUS_TRADE_CANCELED); return; } + if (item->IsBindedNotWith(trader)) { SendTradeStatus(TRADE_STATUS_NOT_ELIGIBLE); @@ -458,16 +473,17 @@ void WorldSession::HandleAcceptTradeOpcode(WorldPacket& /*recvPacket*/) moveItems(myItems, hisItems); // logging money - if (sWorld->getBoolConfig(CONFIG_GM_LOG_TRADE)) + if (HasPermission(RBAC_PERM_LOG_GM_TRADE)) { - if (!AccountMgr::IsPlayerAccount(_player->GetSession()->GetSecurity()) && my_trade->GetMoney() > 0) + if (my_trade->GetMoney() > 0) { sLog->outCommand(_player->GetSession()->GetAccountId(), "GM %s (Account: %u) give money (Amount: %u) to player: %s (Account: %u)", _player->GetName().c_str(), _player->GetSession()->GetAccountId(), my_trade->GetMoney(), trader->GetName().c_str(), trader->GetSession()->GetAccountId()); } - if (!AccountMgr::IsPlayerAccount(trader->GetSession()->GetSecurity()) && his_trade->GetMoney() > 0) + + if (his_trade->GetMoney() > 0) { sLog->outCommand(trader->GetSession()->GetAccountId(), "GM %s (Account: %u) give money (Amount: %u) to player: %s (Account: %u)", trader->GetName().c_str(), trader->GetSession()->GetAccountId(), diff --git a/src/server/game/Instances/InstanceSaveMgr.cpp b/src/server/game/Instances/InstanceSaveMgr.cpp index 81b148d8eaf..c4967e46623 100644 --- a/src/server/game/Instances/InstanceSaveMgr.cpp +++ b/src/server/game/Instances/InstanceSaveMgr.cpp @@ -646,7 +646,7 @@ void InstanceSaveManager::_ResetOrWarnAll(uint32 mapid, Difficulty difficulty, b ((InstanceMap*)map2)->Reset(INSTANCE_RESET_GLOBAL); } - // TODO: delete creature/gameobject respawn times even if the maps are not loaded + /// @todo delete creature/gameobject respawn times even if the maps are not loaded } uint32 InstanceSaveManager::GetNumBoundPlayersTotal() diff --git a/src/server/game/Instances/InstanceSaveMgr.h b/src/server/game/Instances/InstanceSaveMgr.h index a99b4c66b27..c5dcaf32463 100644 --- a/src/server/game/Instances/InstanceSaveMgr.h +++ b/src/server/game/Instances/InstanceSaveMgr.h @@ -101,8 +101,8 @@ class InstanceSave private: bool UnloadIfEmpty(); /* the only reason the instSave-object links are kept is because - the object-instSave links need to be broken at reset time - TODO: maybe it's enough to just store the number of players/groups */ + the object-instSave links need to be broken at reset time */ + /// @todo: Check if maybe it's enough to just store the number of players/groups PlayerListType m_playerList; GroupListType m_groupList; time_t m_resetTime; diff --git a/src/server/game/Loot/LootMgr.cpp b/src/server/game/Loot/LootMgr.cpp index a64e8117ce9..da219c66b9b 100644 --- a/src/server/game/Loot/LootMgr.cpp +++ b/src/server/game/Loot/LootMgr.cpp @@ -26,6 +26,7 @@ #include "SpellInfo.h" #include "Group.h" #include "Player.h" +#include "Containers.h" static Rates const qualityToRate[MAX_ITEM_QUALITY] = { @@ -51,10 +52,37 @@ LootStore LootTemplates_Reference("reference_loot_template", "reference LootStore LootTemplates_Skinning("skinning_loot_template", "creature skinning id", true); LootStore LootTemplates_Spell("spell_loot_template", "spell id (random item creating)", false); +// Selects invalid loot items to be removed from group possible entries (before rolling) +struct LootGroupInvalidSelector : public std::unary_function<LootStoreItem*, bool> +{ + explicit LootGroupInvalidSelector(Loot const& loot, uint16 lootMode) : _loot(loot), _lootMode(lootMode) { } + + bool operator()(LootStoreItem* item) const + { + if (!(item->lootmode & _lootMode)) + return true; + + uint8 foundDuplicates = 0; + for (std::vector<LootItem>::const_iterator itr = _loot.items.begin(); itr != _loot.items.end(); ++itr) + if (itr->itemid == item->itemid) + if (++foundDuplicates == _loot.maxDuplicates) + return true; + + return false; + } + +private: + Loot const& _loot; + uint16 _lootMode; +}; + class LootTemplate::LootGroup // A set of loot definitions for items (refs are not allowed) { public: - void AddEntry(LootStoreItem& item); // Adds an entry to the group (at loading stage) + LootGroup() { } + ~LootGroup(); + + void AddEntry(LootStoreItem* item); // Adds an entry to the group (at loading stage) bool HasQuestDrop() const; // True if group includes at least 1 quest drop entry bool HasQuestDropForPlayer(Player const* player) const; // The same for active quests of the player @@ -72,7 +100,11 @@ class LootTemplate::LootGroup // A set of loot def LootStoreItemList ExplicitlyChanced; // Entries with chances defined in DB LootStoreItemList EqualChanced; // Zero chances - every entry takes the same chance - LootStoreItem const* Roll() const; // Rolls an item from the group, returns NULL if all miss their chances + LootStoreItem const* Roll(Loot& loot, uint16 lootMode) const; // Rolls an item from the group, returns NULL if all miss their chances + + // This class must never be copied - storing pointers + LootGroup(LootGroup const&); + LootGroup& operator=(LootGroup const&); }; //Remove all data and free all memory @@ -126,10 +158,13 @@ uint32 LootStore::LoadLootTable() continue; // error already printed to log/console. } - LootStoreItem storeitem = LootStoreItem(item, chanceOrQuestChance, lootmode, group, mincountOrRef, maxcount); + LootStoreItem* storeitem = new LootStoreItem(item, chanceOrQuestChance, lootmode, group, mincountOrRef, maxcount); - if (!storeitem.IsValid(*this, entry)) // Validity checks + if (!storeitem->IsValid(*this, entry)) // Validity checks + { + delete storeitem; continue; + } // Looking for the template of the entry // often entries are put together @@ -139,7 +174,7 @@ uint32 LootStore::LoadLootTable() tab = m_LootTemplates.find(entry); if (tab == m_LootTemplates.end()) { - std::pair< LootTemplateMap::iterator, bool > pr = m_LootTemplates.insert(LootTemplateMap::value_type(entry, new LootTemplate)); + std::pair< LootTemplateMap::iterator, bool > pr = m_LootTemplates.insert(LootTemplateMap::value_type(entry, new LootTemplate())); tab = pr.first; } } @@ -182,7 +217,7 @@ void LootStore::ResetConditions() for (LootTemplateMap::iterator itr = m_LootTemplates.begin(); itr != m_LootTemplates.end(); ++itr) { ConditionList empty; - (*itr).second->CopyConditions(empty); + itr->second->CopyConditions(empty); } } @@ -327,7 +362,6 @@ LootItem::LootItem(LootStoreItem const& li) needs_quest = li.needs_quest; - count = urand(li.mincountOrRef, li.maxcount); // constructor called for mincountOrRef > 0 only randomSuffix = GenerateEnchSuffixFactor(itemid); randomPropertyId = Item::GenerateItemRandomPropertyId(itemid); is_looted = 0; @@ -376,26 +410,30 @@ void LootItem::AddAllowedLooter(const Player* player) // // Inserts the item into the loot (called by LootTemplate processors) -void Loot::AddItem(LootStoreItem const & item) +void Loot::AddItem(LootStoreItem const& item) { - if (item.needs_quest) // Quest drop - { - if (quest_items.size() < MAX_NR_QUEST_ITEMS) - quest_items.push_back(LootItem(item)); - } - else if (items.size() < MAX_NR_LOOT_ITEMS) // Non-quest drop + ItemTemplate const* proto = sObjectMgr->GetItemTemplate(item.itemid); + if (!proto) + return; + + uint32 count = urand(item.mincountOrRef, item.maxcount); + uint32 stacks = count / proto->GetMaxStackSize() + (count % proto->GetMaxStackSize() ? 1 : 0); + + std::vector<LootItem>& lootItems = item.needs_quest ? quest_items : items; + uint32 limit = item.needs_quest ? MAX_NR_QUEST_ITEMS : MAX_NR_LOOT_ITEMS; + + for (uint32 i = 0; i < stacks && lootItems.size() < limit; ++i) { - items.push_back(LootItem(item)); + LootItem generatedLoot(item); + generatedLoot.count = std::min(count, proto->GetMaxStackSize()); + lootItems.push_back(generatedLoot); + count -= proto->GetMaxStackSize(); // non-conditional one-player only items are counted here, // free for all items are counted in FillFFALoot(), // non-ffa conditionals are counted in FillNonQuestNonFFAConditionalLoot() - if (item.conditions.empty()) - { - ItemTemplate const* proto = sObjectMgr->GetItemTemplate(item.itemid); - if (!proto || (proto->Flags & ITEM_PROTO_FLAG_PARTY_LOOT) == 0) - ++unlootedCount; - } + if (!item.needs_quest && item.conditions.empty() && !(proto->Flags & ITEM_PROTO_FLAG_PARTY_LOOT)) + ++unlootedCount; } } @@ -1024,34 +1062,56 @@ ByteBuffer& operator<<(ByteBuffer& b, LootView const& lv) // --------- LootTemplate::LootGroup --------- // +LootTemplate::LootGroup::~LootGroup() +{ + while (!ExplicitlyChanced.empty()) + { + delete ExplicitlyChanced.back(); + ExplicitlyChanced.pop_back(); + } + + while (!EqualChanced.empty()) + { + delete EqualChanced.back(); + EqualChanced.pop_back(); + } +} + // Adds an entry to the group (at loading stage) -void LootTemplate::LootGroup::AddEntry(LootStoreItem& item) +void LootTemplate::LootGroup::AddEntry(LootStoreItem* item) { - if (item.chance != 0) + if (item->chance != 0) ExplicitlyChanced.push_back(item); else EqualChanced.push_back(item); } // Rolls an item from the group, returns NULL if all miss their chances -LootStoreItem const* LootTemplate::LootGroup::Roll() const +LootStoreItem const* LootTemplate::LootGroup::Roll(Loot& loot, uint16 lootMode) const { - if (!ExplicitlyChanced.empty()) // First explicitly chanced entries are checked + LootStoreItemList possibleLoot = ExplicitlyChanced; + possibleLoot.remove_if(LootGroupInvalidSelector(loot, lootMode)); + + if (!possibleLoot.empty()) // First explicitly chanced entries are checked { - float Roll = (float)rand_chance(); + float roll = (float)rand_chance(); - for (uint32 i = 0; i < ExplicitlyChanced.size(); ++i) // check each explicitly chanced entry in the template and modify its chance based on quality. + for (LootStoreItemList::const_iterator itr = possibleLoot.begin(); itr != possibleLoot.end(); ++itr) // check each explicitly chanced entry in the template and modify its chance based on quality. { - if (ExplicitlyChanced[i].chance >= 100.0f) - return &ExplicitlyChanced[i]; + LootStoreItem* item = *itr; + if (item->chance >= 100.0f) + return item; - Roll -= ExplicitlyChanced[i].chance; - if (Roll < 0) - return &ExplicitlyChanced[i]; + roll -= item->chance; + if (roll < 0) + return item; } } - if (!EqualChanced.empty()) // If nothing selected yet - an item is taken from equal-chanced part - return &EqualChanced[irand(0, EqualChanced.size()-1)]; + + possibleLoot = EqualChanced; + possibleLoot.remove_if(LootGroupInvalidSelector(loot, lootMode)); + if (!possibleLoot.empty()) // If nothing selected yet - an item is taken from equal-chanced part + return Trinity::Containers::SelectRandomContainerElement(possibleLoot); return NULL; // Empty drop from the group } @@ -1059,12 +1119,14 @@ LootStoreItem const* LootTemplate::LootGroup::Roll() const // True if group includes at least 1 quest drop entry bool LootTemplate::LootGroup::HasQuestDrop() const { - for (LootStoreItemList::const_iterator i=ExplicitlyChanced.begin(); i != ExplicitlyChanced.end(); ++i) - if (i->needs_quest) + for (LootStoreItemList::const_iterator i = ExplicitlyChanced.begin(); i != ExplicitlyChanced.end(); ++i) + if ((*i)->needs_quest) return true; - for (LootStoreItemList::const_iterator i=EqualChanced.begin(); i != EqualChanced.end(); ++i) - if (i->needs_quest) + + for (LootStoreItemList::const_iterator i = EqualChanced.begin(); i != EqualChanced.end(); ++i) + if ((*i)->needs_quest) return true; + return false; } @@ -1072,111 +1134,30 @@ bool LootTemplate::LootGroup::HasQuestDrop() const bool LootTemplate::LootGroup::HasQuestDropForPlayer(Player const* player) const { for (LootStoreItemList::const_iterator i = ExplicitlyChanced.begin(); i != ExplicitlyChanced.end(); ++i) - if (player->HasQuestForItem(i->itemid)) + if (player->HasQuestForItem((*i)->itemid)) return true; + for (LootStoreItemList::const_iterator i = EqualChanced.begin(); i != EqualChanced.end(); ++i) - if (player->HasQuestForItem(i->itemid)) + if (player->HasQuestForItem((*i)->itemid)) return true; + return false; } void LootTemplate::LootGroup::CopyConditions(ConditionList /*conditions*/) { for (LootStoreItemList::iterator i = ExplicitlyChanced.begin(); i != ExplicitlyChanced.end(); ++i) - { - i->conditions.clear(); - } + (*i)->conditions.clear(); + for (LootStoreItemList::iterator i = EqualChanced.begin(); i != EqualChanced.end(); ++i) - { - i->conditions.clear(); - } + (*i)->conditions.clear(); } // Rolls an item from the group (if any takes its chance) and adds the item to the loot void LootTemplate::LootGroup::Process(Loot& loot, uint16 lootMode) const { - // build up list of possible drops - LootStoreItemList EqualPossibleDrops = EqualChanced; - LootStoreItemList ExplicitPossibleDrops = ExplicitlyChanced; - - uint8 uiAttemptCount = 0; - const uint8 uiMaxAttempts = ExplicitlyChanced.size() + EqualChanced.size(); - - while (!ExplicitPossibleDrops.empty() || !EqualPossibleDrops.empty()) - { - if (uiAttemptCount == uiMaxAttempts) // already tried rolling too many times, just abort - return; - - LootStoreItem* item = NULL; - - // begin rolling (normally called via Roll()) - LootStoreItemList::iterator itr; - uint8 itemSource = 0; - if (!ExplicitPossibleDrops.empty()) // First explicitly chanced entries are checked - { - itemSource = 1; - float Roll = (float)rand_chance(); - // check each explicitly chanced entry in the template and modify its chance based on quality - for (itr = ExplicitPossibleDrops.begin(); itr != ExplicitPossibleDrops.end(); itr = ExplicitPossibleDrops.erase(itr)) - { - if (itr->chance >= 100.0f) - { - item = &*itr; - break; - } - - Roll -= itr->chance; - if (Roll < 0) - { - item = &*itr; - break; - } - } - } - if (item == NULL && !EqualPossibleDrops.empty()) // If nothing selected yet - an item is taken from equal-chanced part - { - itemSource = 2; - itr = EqualPossibleDrops.begin(); - std::advance(itr, irand(0, EqualPossibleDrops.size()-1)); - item = &*itr; - } - // finish rolling - - ++uiAttemptCount; - - if (item != NULL && item->lootmode & lootMode) // only add this item if roll succeeds and the mode matches - { - bool duplicate = false; - if (ItemTemplate const* _proto = sObjectMgr->GetItemTemplate(item->itemid)) - { - uint8 _item_counter = 0; - for (LootItemList::const_iterator _item = loot.items.begin(); _item != loot.items.end(); ++_item) - if (_item->itemid == item->itemid) // search through the items that have already dropped - { - ++_item_counter; - if (_proto->InventoryType == 0 && _item_counter == 3) // Non-equippable items are limited to 3 drops - duplicate = true; - else if (_proto->InventoryType != 0 && _item_counter == 1) // Equippable item are limited to 1 drop - duplicate = true; - } - } - if (duplicate) // if item->itemid is a duplicate, remove it - switch (itemSource) - { - case 1: // item came from ExplicitPossibleDrops - ExplicitPossibleDrops.erase(itr); - break; - case 2: // item came from EqualPossibleDrops - EqualPossibleDrops.erase(itr); - break; - } - else // otherwise, add the item and exit the function - { - loot.AddItem(*item); - return; - } - } - } + if (LootStoreItem const* item = Roll(loot, lootMode)) + loot.AddItem(*item); } // Overall chance for the group without equal chanced items @@ -1185,8 +1166,8 @@ float LootTemplate::LootGroup::RawTotalChance() const float result = 0; for (LootStoreItemList::const_iterator i=ExplicitlyChanced.begin(); i != ExplicitlyChanced.end(); ++i) - if (!i->needs_quest) - result += i->chance; + if (!(*i)->needs_quest) + result += (*i)->chance; return result; } @@ -1205,38 +1186,36 @@ float LootTemplate::LootGroup::TotalChance() const void LootTemplate::LootGroup::Verify(LootStore const& lootstore, uint32 id, uint8 group_id) const { float chance = RawTotalChance(); - if (chance > 101.0f) // TODO: replace with 100% when DBs will be ready - { + if (chance > 101.0f) /// @todo replace with 100% when DBs will be ready sLog->outError(LOG_FILTER_SQL, "Table '%s' entry %u group %d has total chance > 100%% (%f)", lootstore.GetName(), id, group_id, chance); - } if (chance >= 100.0f && !EqualChanced.empty()) - { sLog->outError(LOG_FILTER_SQL, "Table '%s' entry %u group %d has items with chance=0%% but group total chance >= 100%% (%f)", lootstore.GetName(), id, group_id, chance); - } } void LootTemplate::LootGroup::CheckLootRefs(LootTemplateMap const& /*store*/, LootIdSet* ref_set) const { - for (LootStoreItemList::const_iterator ieItr=ExplicitlyChanced.begin(); ieItr != ExplicitlyChanced.end(); ++ieItr) + for (LootStoreItemList::const_iterator ieItr = ExplicitlyChanced.begin(); ieItr != ExplicitlyChanced.end(); ++ieItr) { - if (ieItr->mincountOrRef < 0) + LootStoreItem* item = *ieItr; + if (item->mincountOrRef < 0) { - if (!LootTemplates_Reference.GetLootFor(-ieItr->mincountOrRef)) - LootTemplates_Reference.ReportNotExistedId(-ieItr->mincountOrRef); + if (!LootTemplates_Reference.GetLootFor(-item->mincountOrRef)) + LootTemplates_Reference.ReportNotExistedId(-item->mincountOrRef); else if (ref_set) - ref_set->erase(-ieItr->mincountOrRef); + ref_set->erase(-item->mincountOrRef); } } - for (LootStoreItemList::const_iterator ieItr=EqualChanced.begin(); ieItr != EqualChanced.end(); ++ieItr) + for (LootStoreItemList::const_iterator ieItr = EqualChanced.begin(); ieItr != EqualChanced.end(); ++ieItr) { - if (ieItr->mincountOrRef < 0) + LootStoreItem* item = *ieItr; + if (item->mincountOrRef < 0) { - if (!LootTemplates_Reference.GetLootFor(-ieItr->mincountOrRef)) - LootTemplates_Reference.ReportNotExistedId(-ieItr->mincountOrRef); + if (!LootTemplates_Reference.GetLootFor(-item->mincountOrRef)) + LootTemplates_Reference.ReportNotExistedId(-item->mincountOrRef); else if (ref_set) - ref_set->erase(-ieItr->mincountOrRef); + ref_set->erase(-item->mincountOrRef); } } } @@ -1245,14 +1224,30 @@ void LootTemplate::LootGroup::CheckLootRefs(LootTemplateMap const& /*store*/, Lo // --------- LootTemplate --------- // +LootTemplate::~LootTemplate() +{ + while (!Entries.empty()) + { + delete Entries.back(); + Entries.pop_back(); + } + + for (size_t i = 0; i < Groups.size(); ++i) + delete Groups[i]; + Groups.clear(); +} + // Adds an entry to the group (at loading stage) -void LootTemplate::AddEntry(LootStoreItem& item) +void LootTemplate::AddEntry(LootStoreItem* item) { - if (item.group > 0 && item.mincountOrRef > 0) // Group + if (item->group > 0 && item->mincountOrRef > 0) // Group { - if (item.group >= Groups.size()) - Groups.resize(item.group); // Adds new group the the loot template if needed - Groups[item.group-1].AddEntry(item); // Adds new entry to the group + if (item->group >= Groups.size()) + Groups.resize(item->group, NULL); // Adds new group the the loot template if needed + if (!Groups[item->group - 1]) + Groups[item->group - 1] = new LootGroup(); + + Groups[item->group-1]->AddEntry(item); // Adds new entry to the group } else // Non-grouped entries and references are stored together Entries.push_back(item); @@ -1261,10 +1256,11 @@ void LootTemplate::AddEntry(LootStoreItem& item) void LootTemplate::CopyConditions(ConditionList conditions) { for (LootStoreItemList::iterator i = Entries.begin(); i != Entries.end(); ++i) - i->conditions.clear(); + (*i)->conditions.clear(); for (LootGroups::iterator i = Groups.begin(); i != Groups.end(); ++i) - i->CopyConditions(conditions); + if (LootGroup* group = *i) + group->CopyConditions(conditions); } void LootTemplate::CopyConditions(LootItem* li) const @@ -1272,10 +1268,11 @@ void LootTemplate::CopyConditions(LootItem* li) const // Copies the conditions list from a template item to a LootItem for (LootStoreItemList::const_iterator _iter = Entries.begin(); _iter != Entries.end(); ++_iter) { - if (_iter->itemid != li->itemid) + LootStoreItem* item = *_iter; + if (item->itemid != li->itemid) continue; - li->conditions = _iter->conditions; + li->conditions = item->conditions; break; } } @@ -1288,54 +1285,41 @@ void LootTemplate::Process(Loot& loot, bool rate, uint16 lootMode, uint8 groupId if (groupId > Groups.size()) return; // Error message already printed at loading stage - Groups[groupId-1].Process(loot, lootMode); + if (!Groups[groupId - 1]) + return; + + Groups[groupId-1]->Process(loot, lootMode); return; } // Rolling non-grouped items for (LootStoreItemList::const_iterator i = Entries.begin(); i != Entries.end(); ++i) { - if (i->lootmode &~ lootMode) // Do not add if mode mismatch + LootStoreItem* item = *i; + if (!(item->lootmode & lootMode)) // Do not add if mode mismatch continue; - if (!i->Roll(rate)) - continue; // Bad luck for the entry + if (!item->Roll(rate)) + continue; // Bad luck for the entry - if (ItemTemplate const* _proto = sObjectMgr->GetItemTemplate(i->itemid)) + if (item->mincountOrRef < 0) // References processing { - uint8 _item_counter = 0; - LootItemList::const_iterator _item = loot.items.begin(); - for (; _item != loot.items.end(); ++_item) - if (_item->itemid == i->itemid) // search through the items that have already dropped - { - ++_item_counter; - if (_proto->InventoryType == 0 && _item_counter == 3) // Non-equippable items are limited to 3 drops - continue; - else if (_proto->InventoryType != 0 && _item_counter == 1) // Equippable item are limited to 1 drop - continue; - } - if (_item != loot.items.end()) - continue; - } - - if (i->mincountOrRef < 0) // References processing - { - LootTemplate const* Referenced = LootTemplates_Reference.GetLootFor(-i->mincountOrRef); - + LootTemplate const* Referenced = LootTemplates_Reference.GetLootFor(-item->mincountOrRef); if (!Referenced) - continue; // Error message already printed at loading stage + continue; // Error message already printed at loading stage - uint32 maxcount = uint32(float(i->maxcount) * sWorld->getRate(RATE_DROP_ITEM_REFERENCED_AMOUNT)); - for (uint32 loop = 0; loop < maxcount; ++loop) // Ref multiplicator - Referenced->Process(loot, rate, lootMode, i->group); + uint32 maxcount = uint32(float(item->maxcount) * sWorld->getRate(RATE_DROP_ITEM_REFERENCED_AMOUNT)); + for (uint32 loop = 0; loop < maxcount; ++loop) // Ref multiplicator + Referenced->Process(loot, rate, lootMode, item->group); } - else // Plain entries (not a reference, not grouped) - loot.AddItem(*i); // Chance is already checked, just add + else // Plain entries (not a reference, not grouped) + loot.AddItem(*item); // Chance is already checked, just add } // Now processing groups for (LootGroups::const_iterator i = Groups.begin(); i != Groups.end(); ++i) - i->Process(loot, lootMode); + if (LootGroup* group = *i) + group->Process(loot, lootMode); } // True if template includes at least 1 quest drop entry @@ -1345,27 +1329,33 @@ bool LootTemplate::HasQuestDrop(LootTemplateMap const& store, uint8 groupId) con { if (groupId > Groups.size()) return false; // Error message [should be] already printed at loading stage - return Groups[groupId-1].HasQuestDrop(); + + if (!Groups[groupId - 1]) + return false; + + return Groups[groupId-1]->HasQuestDrop(); } for (LootStoreItemList::const_iterator i = Entries.begin(); i != Entries.end(); ++i) { - if (i->mincountOrRef < 0) // References + LootStoreItem* item = *i; + if (item->mincountOrRef < 0) // References { - LootTemplateMap::const_iterator Referenced = store.find(-i->mincountOrRef); + LootTemplateMap::const_iterator Referenced = store.find(-item->mincountOrRef); if (Referenced == store.end()) continue; // Error message [should be] already printed at loading stage - if (Referenced->second->HasQuestDrop(store, i->group)) + if (Referenced->second->HasQuestDrop(store, item->group)) return true; } - else if (i->needs_quest) + else if (item->needs_quest) return true; // quest drop found } // Now processing groups for (LootGroups::const_iterator i = Groups.begin(); i != Groups.end(); ++i) - if (i->HasQuestDrop()) - return true; + if (LootGroup* group = *i) + if (group->HasQuestDrop()) + return true; return false; } @@ -1377,28 +1367,34 @@ bool LootTemplate::HasQuestDropForPlayer(LootTemplateMap const& store, Player co { if (groupId > Groups.size()) return false; // Error message already printed at loading stage - return Groups[groupId-1].HasQuestDropForPlayer(player); + + if (!Groups[groupId - 1]) + return false; + + return Groups[groupId-1]->HasQuestDropForPlayer(player); } // Checking non-grouped entries for (LootStoreItemList::const_iterator i = Entries.begin(); i != Entries.end(); ++i) { - if (i->mincountOrRef < 0) // References processing + LootStoreItem* item = *i; + if (item->mincountOrRef < 0) // References processing { - LootTemplateMap::const_iterator Referenced = store.find(-i->mincountOrRef); + LootTemplateMap::const_iterator Referenced = store.find(-item->mincountOrRef); if (Referenced == store.end()) continue; // Error message already printed at loading stage - if (Referenced->second->HasQuestDropForPlayer(store, player, i->group)) + if (Referenced->second->HasQuestDropForPlayer(store, player, item->group)) return true; } - else if (player->HasQuestForItem(i->itemid)) + else if (player->HasQuestForItem(item->itemid)) return true; // active quest drop found } // Now checking groups for (LootGroups::const_iterator i = Groups.begin(); i != Groups.end(); ++i) - if (i->HasQuestDropForPlayer(player)) - return true; + if (LootGroup* group = *i) + if (group->HasQuestDropForPlayer(player)) + return true; return false; } @@ -1407,28 +1403,32 @@ bool LootTemplate::HasQuestDropForPlayer(LootTemplateMap const& store, Player co void LootTemplate::Verify(LootStore const& lootstore, uint32 id) const { // Checking group chances - for (uint32 i=0; i < Groups.size(); ++i) - Groups[i].Verify(lootstore, id, i+1); + for (uint32 i = 0; i < Groups.size(); ++i) + if (Groups[i]) + Groups[i]->Verify(lootstore, id, i + 1); - // TODO: References validity checks + /// @todo References validity checks } void LootTemplate::CheckLootRefs(LootTemplateMap const& store, LootIdSet* ref_set) const { for (LootStoreItemList::const_iterator ieItr = Entries.begin(); ieItr != Entries.end(); ++ieItr) { - if (ieItr->mincountOrRef < 0) + LootStoreItem* item = *ieItr; + if (item->mincountOrRef < 0) { - if (!LootTemplates_Reference.GetLootFor(-ieItr->mincountOrRef)) - LootTemplates_Reference.ReportNotExistedId(-ieItr->mincountOrRef); + if (!LootTemplates_Reference.GetLootFor(-item->mincountOrRef)) + LootTemplates_Reference.ReportNotExistedId(-item->mincountOrRef); else if (ref_set) - ref_set->erase(-ieItr->mincountOrRef); + ref_set->erase(-item->mincountOrRef); } } for (LootGroups::const_iterator grItr = Groups.begin(); grItr != Groups.end(); ++grItr) - grItr->CheckLootRefs(store, ref_set); + if (LootGroup* group = *grItr) + group->CheckLootRefs(store, ref_set); } + bool LootTemplate::addConditionItem(Condition* cond) { if (!cond || !cond->isLoaded())//should never happen, checked at loading @@ -1436,41 +1436,48 @@ bool LootTemplate::addConditionItem(Condition* cond) sLog->outError(LOG_FILTER_LOOT, "LootTemplate::addConditionItem: condition is null"); return false; } + if (!Entries.empty()) { for (LootStoreItemList::iterator i = Entries.begin(); i != Entries.end(); ++i) { - if (i->itemid == uint32(cond->SourceEntry)) + if ((*i)->itemid == uint32(cond->SourceEntry)) { - i->conditions.push_back(cond); + (*i)->conditions.push_back(cond); return true; } } } + if (!Groups.empty()) { for (LootGroups::iterator groupItr = Groups.begin(); groupItr != Groups.end(); ++groupItr) { - LootStoreItemList* itemList = (*groupItr).GetExplicitlyChancedItemList(); + LootGroup* group = *groupItr; + if (!group) + continue; + + LootStoreItemList* itemList = group->GetExplicitlyChancedItemList(); if (!itemList->empty()) { for (LootStoreItemList::iterator i = itemList->begin(); i != itemList->end(); ++i) { - if ((*i).itemid == uint32(cond->SourceEntry)) + if ((*i)->itemid == uint32(cond->SourceEntry)) { - (*i).conditions.push_back(cond); + (*i)->conditions.push_back(cond); return true; } } } - itemList = (*groupItr).GetEqualChancedItemList(); + + itemList = group->GetEqualChancedItemList(); if (!itemList->empty()) { for (LootStoreItemList::iterator i = itemList->begin(); i != itemList->end(); ++i) { - if ((*i).itemid == uint32(cond->SourceEntry)) + if ((*i)->itemid == uint32(cond->SourceEntry)) { - (*i).conditions.push_back(cond); + (*i)->conditions.push_back(cond); return true; } } @@ -1483,10 +1490,9 @@ bool LootTemplate::addConditionItem(Condition* cond) bool LootTemplate::isReference(uint32 id) { for (LootStoreItemList::const_iterator ieItr = Entries.begin(); ieItr != Entries.end(); ++ieItr) - { - if (ieItr->itemid == id && ieItr->mincountOrRef < 0) + if ((*ieItr)->itemid == id && (*ieItr)->mincountOrRef < 0) return true; - } + return false;//not found or not reference } @@ -1521,7 +1527,7 @@ void LoadLootTemplates_Creature() if (count) sLog->outInfo(LOG_FILTER_SERVER_LOADING, ">> Loaded %u creature loot templates in %u ms", count, GetMSTimeDiffToNow(oldMSTime)); else - sLog->outError(LOG_FILTER_SQL, ">> Loaded 0 creature loot templates. DB table `creature_loot_template` is empty"); + sLog->outError(LOG_FILTER_SERVER_LOADING, ">> Loaded 0 creature loot templates. DB table `creature_loot_template` is empty"); } void LoadLootTemplates_Disenchant() @@ -1554,7 +1560,7 @@ void LoadLootTemplates_Disenchant() if (count) sLog->outInfo(LOG_FILTER_SERVER_LOADING, ">> Loaded %u disenchanting loot templates in %u ms", count, GetMSTimeDiffToNow(oldMSTime)); else - sLog->outError(LOG_FILTER_SQL, ">> Loaded 0 disenchanting loot templates. DB table `disenchant_loot_template` is empty"); + sLog->outError(LOG_FILTER_SERVER_LOADING, ">> Loaded 0 disenchanting loot templates. DB table `disenchant_loot_template` is empty"); } void LoadLootTemplates_Fishing() @@ -1578,7 +1584,7 @@ void LoadLootTemplates_Fishing() if (count) sLog->outInfo(LOG_FILTER_SERVER_LOADING, ">> Loaded %u fishing loot templates in %u ms", count, GetMSTimeDiffToNow(oldMSTime)); else - sLog->outError(LOG_FILTER_SQL, ">> Loaded 0 fishing loot templates. DB table `fishing_loot_template` is empty"); + sLog->outError(LOG_FILTER_SERVER_LOADING, ">> Loaded 0 fishing loot templates. DB table `fishing_loot_template` is empty"); } void LoadLootTemplates_Gameobject() @@ -1612,7 +1618,7 @@ void LoadLootTemplates_Gameobject() if (count) sLog->outInfo(LOG_FILTER_SERVER_LOADING, ">> Loaded %u gameobject loot templates in %u ms", count, GetMSTimeDiffToNow(oldMSTime)); else - sLog->outError(LOG_FILTER_SQL, ">> Loaded 0 gameobject loot templates. DB table `gameobject_loot_template` is empty"); + sLog->outError(LOG_FILTER_SERVER_LOADING, ">> Loaded 0 gameobject loot templates. DB table `gameobject_loot_template` is empty"); } void LoadLootTemplates_Item() @@ -1636,7 +1642,7 @@ void LoadLootTemplates_Item() if (count) sLog->outInfo(LOG_FILTER_SERVER_LOADING, ">> Loaded %u item loot templates in %u ms", count, GetMSTimeDiffToNow(oldMSTime)); else - sLog->outError(LOG_FILTER_SQL, ">> Loaded 0 item loot templates. DB table `item_loot_template` is empty"); + sLog->outError(LOG_FILTER_SERVER_LOADING, ">> Loaded 0 item loot templates. DB table `item_loot_template` is empty"); } void LoadLootTemplates_Milling() @@ -1665,7 +1671,7 @@ void LoadLootTemplates_Milling() if (count) sLog->outInfo(LOG_FILTER_SERVER_LOADING, ">> Loaded %u milling loot templates in %u ms", count, GetMSTimeDiffToNow(oldMSTime)); else - sLog->outError(LOG_FILTER_SQL, ">> Loaded 0 milling loot templates. DB table `milling_loot_template` is empty"); + sLog->outError(LOG_FILTER_SERVER_LOADING, ">> Loaded 0 milling loot templates. DB table `milling_loot_template` is empty"); } void LoadLootTemplates_Pickpocketing() @@ -1699,7 +1705,7 @@ void LoadLootTemplates_Pickpocketing() if (count) sLog->outInfo(LOG_FILTER_SERVER_LOADING, ">> Loaded %u pickpocketing loot templates in %u ms", count, GetMSTimeDiffToNow(oldMSTime)); else - sLog->outError(LOG_FILTER_SQL, ">> Loaded 0 pickpocketing loot templates. DB table `pickpocketing_loot_template` is empty"); + sLog->outError(LOG_FILTER_SERVER_LOADING, ">> Loaded 0 pickpocketing loot templates. DB table `pickpocketing_loot_template` is empty"); } void LoadLootTemplates_Prospecting() @@ -1728,7 +1734,7 @@ void LoadLootTemplates_Prospecting() if (count) sLog->outInfo(LOG_FILTER_SERVER_LOADING, ">> Loaded %u prospecting loot templates in %u ms", count, GetMSTimeDiffToNow(oldMSTime)); else - sLog->outError(LOG_FILTER_SQL, ">> Loaded 0 prospecting loot templates. DB table `prospecting_loot_template` is empty"); + sLog->outError(LOG_FILTER_SERVER_LOADING, ">> Loaded 0 prospecting loot templates. DB table `prospecting_loot_template` is empty"); } void LoadLootTemplates_Mail() @@ -1752,7 +1758,7 @@ void LoadLootTemplates_Mail() if (count) sLog->outInfo(LOG_FILTER_SERVER_LOADING, ">> Loaded %u mail loot templates in %u ms", count, GetMSTimeDiffToNow(oldMSTime)); else - sLog->outError(LOG_FILTER_SQL, ">> Loaded 0 mail loot templates. DB table `mail_loot_template` is empty"); + sLog->outError(LOG_FILTER_SERVER_LOADING, ">> Loaded 0 mail loot templates. DB table `mail_loot_template` is empty"); } void LoadLootTemplates_Skinning() @@ -1786,7 +1792,7 @@ void LoadLootTemplates_Skinning() if (count) sLog->outInfo(LOG_FILTER_SERVER_LOADING, ">> Loaded %u skinning loot templates in %u ms", count, GetMSTimeDiffToNow(oldMSTime)); else - sLog->outError(LOG_FILTER_SQL, ">> Loaded 0 skinning loot templates. DB table `skinning_loot_template` is empty"); + sLog->outError(LOG_FILTER_SERVER_LOADING, ">> Loaded 0 skinning loot templates. DB table `skinning_loot_template` is empty"); } void LoadLootTemplates_Spell() @@ -1828,7 +1834,7 @@ void LoadLootTemplates_Spell() if (count) sLog->outInfo(LOG_FILTER_SERVER_LOADING, ">> Loaded %u spell loot templates in %u ms", count, GetMSTimeDiffToNow(oldMSTime)); else - sLog->outError(LOG_FILTER_SQL, ">> Loaded 0 spell loot templates. DB table `spell_loot_template` is empty"); + sLog->outError(LOG_FILTER_SERVER_LOADING, ">> Loaded 0 spell loot templates. DB table `spell_loot_template` is empty"); } void LoadLootTemplates_Reference() diff --git a/src/server/game/Loot/LootMgr.h b/src/server/game/Loot/LootMgr.h index 759064385a5..5c858a35242 100644 --- a/src/server/game/Loot/LootMgr.h +++ b/src/server/game/Loot/LootMgr.h @@ -27,6 +27,7 @@ #include <map> #include <vector> +#include <list> enum RollType { @@ -174,7 +175,7 @@ class LootTemplate; typedef std::vector<QuestItem> QuestItemList; typedef std::vector<LootItem> LootItemList; typedef std::map<uint32, QuestItemList*> QuestItemMap; -typedef std::vector<LootStoreItem> LootStoreItemList; +typedef std::list<LootStoreItem*> LootStoreItemList; typedef UNORDERED_MAP<uint32, LootTemplate*> LootTemplateMap; typedef std::set<uint32> LootIdSet; @@ -218,11 +219,14 @@ class LootStore class LootTemplate { class LootGroup; // A set of loot definitions for items (refs are not allowed inside) - typedef std::vector<LootGroup> LootGroups; + typedef std::vector<LootGroup*> LootGroups; public: + LootTemplate() { } + ~LootTemplate(); + // Adds an entry to the group (at loading stage) - void AddEntry(LootStoreItem& item); + void AddEntry(LootStoreItem* item); // Rolls for every item in the template and adds the rolled items the the loot void Process(Loot& loot, bool rate, uint16 lootMode, uint8 groupId = 0) const; void CopyConditions(ConditionList conditions); @@ -242,6 +246,10 @@ class LootTemplate private: LootStoreItemList Entries; // not grouped only LootGroups Groups; // groups have own (optimised) processing, grouped entries go there + + // Objects of this class must never be copied, we are storing pointers in container + LootTemplate(LootTemplate const&); + LootTemplate& operator=(LootTemplate const&); }; //===================================================== @@ -290,12 +298,13 @@ struct Loot uint8 unlootedCount; uint64 roundRobinPlayer; // GUID of the player having the Round-Robin ownership for the loot. If 0, round robin owner has released. LootType loot_type; // required for achievement system + uint8 maxDuplicates; // Max amount of items with the same entry that can drop (default is 1; on 25 man raid mode 3) // GUIDLow of container that holds this loot (item_instance.entry) // Only set for inventory items that can be right-click looted uint32 containerID; - Loot(uint32 _gold = 0) : gold(_gold), unlootedCount(0), loot_type(LOOT_CORPSE), containerID(0) {} + Loot(uint32 _gold = 0) : gold(_gold), unlootedCount(0), loot_type(LOOT_CORPSE), maxDuplicates(1), containerID(0) {} ~Loot() { clear(); } // For deleting items at loot removal since there is no backward interface to the Item() diff --git a/src/server/game/Maps/Map.cpp b/src/server/game/Maps/Map.cpp index 286604c10ac..70942b8ffc0 100644 --- a/src/server/game/Maps/Map.cpp +++ b/src/server/game/Maps/Map.cpp @@ -18,6 +18,7 @@ #include "Map.h" #include "Battleground.h" +#include "MMapFactory.h" #include "CellImpl.h" #include "DynamicTree.h" #include "GridNotifiers.h" @@ -25,7 +26,6 @@ #include "GridStates.h" #include "Group.h" #include "InstanceScript.h" -#include "LFGMgr.h" #include "MapInstanced.h" #include "MapManager.h" #include "ObjectAccessor.h" @@ -36,14 +36,8 @@ #include "Vehicle.h" #include "VMapFactory.h" -union u_map_magic -{ - char asChar[4]; - uint32 asUInt; -}; - u_map_magic MapMagic = { {'M','A','P','S'} }; -u_map_magic MapVersionMagic = { {'v','1','.','2'} }; +u_map_magic MapVersionMagic = { {'v','1','.','3'} }; u_map_magic MapAreaMagic = { {'A','R','E','A'} }; u_map_magic MapHeightMagic = { {'M','H','G','T'} }; u_map_magic MapLiquidMagic = { {'M','L','I','Q'} }; @@ -71,32 +65,36 @@ Map::~Map() if (!m_scriptSchedule.empty()) sScriptMgr->DecreaseScheduledScriptCount(m_scriptSchedule.size()); + + MMAP::MMapFactory::createOrGetMMapManager()->unloadMapInstance(GetId(), i_InstanceId); } bool Map::ExistMap(uint32 mapid, int gx, int gy) { - int len = sWorld->GetDataPath().length()+strlen("maps/%03u%02u%02u.map")+1; - char* tmp = new char[len]; - snprintf(tmp, len, (char *)(sWorld->GetDataPath()+"maps/%03u%02u%02u.map").c_str(), mapid, gx, gy); + int len = sWorld->GetDataPath().length() + strlen("maps/%03u%02u%02u.map") + 1; + char* fileName = new char[len]; + snprintf(fileName, len, (char *)(sWorld->GetDataPath() + "maps/%03u%02u%02u.map").c_str(), mapid, gx, gy); bool ret = false; - FILE* pf=fopen(tmp, "rb"); + FILE* pf = fopen(fileName, "rb"); if (!pf) - sLog->outError(LOG_FILTER_MAPS, "Map file '%s': does not exist!", tmp); + sLog->outError(LOG_FILTER_MAPS, "Map file '%s': does not exist!", fileName); else { map_fileheader header; if (fread(&header, sizeof(header), 1, pf) == 1) { - if (header.mapMagic != MapMagic.asUInt || header.versionMagic != MapVersionMagic.asUInt) - sLog->outError(LOG_FILTER_MAPS, "Map file '%s' is from an incompatible clientversion. Please recreate using the mapextractor.", tmp); + if (header.mapMagic.asUInt != MapMagic.asUInt || header.versionMagic.asUInt != MapVersionMagic.asUInt) + sLog->outError(LOG_FILTER_MAPS, "Map file '%s' is from an incompatible map version (%.*s %.*s), %.*s %.*s is expected. Please recreate using the mapextractor.", + fileName, 4, header.mapMagic.asChar, 4, header.versionMagic.asChar, 4, MapMagic.asChar, 4, MapVersionMagic.asChar); else ret = true; } fclose(pf); } - delete [] tmp; + + delete[] fileName; return ret; } @@ -119,6 +117,16 @@ bool Map::ExistVMap(uint32 mapid, int gx, int gy) return true; } +void Map::LoadMMap(int gx, int gy) +{ + bool mmapLoadResult = MMAP::MMapFactory::createOrGetMMapManager()->loadMap((sWorld->GetDataPath() + "mmaps").c_str(), GetId(), gx, gy); + + if (mmapLoadResult) + sLog->outInfo(LOG_FILTER_MAPS, "MMAP loaded name:%s, id:%d, x:%d, y:%d (mmap rep.: x:%d, y:%d)", GetMapName(), GetId(), gx, gy, gx, gy); + else + sLog->outInfo(LOG_FILTER_MAPS, "Could not load MMAP name:%s, id:%d, x:%d, y:%d (mmap rep.: x:%d, y:%d)", GetMapName(), GetId(), gx, gy, gx, gy); +} + void Map::LoadVMap(int gx, int gy) { // x and y are swapped !! @@ -167,18 +175,16 @@ void Map::LoadMap(int gx, int gy, bool reload) } // map file name - char *tmp=NULL; - int len = sWorld->GetDataPath().length()+strlen("maps/%03u%02u%02u.map")+1; + char* tmp = NULL; + int len = sWorld->GetDataPath().length() + strlen("maps/%03u%02u%02u.map") + 1; tmp = new char[len]; - snprintf(tmp, len, (char *)(sWorld->GetDataPath()+"maps/%03u%02u%02u.map").c_str(), GetId(), gx, gy); + snprintf(tmp, len, (char *)(sWorld->GetDataPath() + "maps/%03u%02u%02u.map").c_str(), GetId(), gx, gy); sLog->outInfo(LOG_FILTER_MAPS, "Loading map %s", tmp); // loading data GridMaps[gx][gy] = new GridMap(); if (!GridMaps[gx][gy]->loadData(tmp)) - { sLog->outError(LOG_FILTER_MAPS, "Error loading map file: \n %s\n", tmp); - } - delete [] tmp; + delete[] tmp; sScriptMgr->OnLoadGridMap(this, GridMaps[gx][gy], gx, gy); } @@ -186,8 +192,12 @@ void Map::LoadMap(int gx, int gy, bool reload) void Map::LoadMapAndVMap(int gx, int gy) { LoadMap(gx, gy); + // Only load the data for the base map if (i_InstanceId == 0) - LoadVMap(gx, gy); // Only load the data for the base map + { + LoadVMap(gx, gy); + LoadMMap(gx, gy); + } } void Map::InitStateMachine() @@ -305,13 +315,13 @@ template<> void Map::DeleteFromWorld(Player* player) { sObjectAccessor->RemoveObject(player); - sObjectAccessor->RemoveUpdateObject(player); //TODO: I do not know why we need this, it should be removed in ~Object anyway + sObjectAccessor->RemoveUpdateObject(player); /// @todo I do not know why we need this, it should be removed in ~Object anyway delete player; } void Map::EnsureGridCreated(const GridCoord &p) { - TRINITY_GUARD(ACE_Thread_Mutex, Lock); + TRINITY_GUARD(ACE_Thread_Mutex, GridLock); EnsureGridCreated_i(p); } @@ -428,7 +438,7 @@ void Map::InitializeObject(Creature* obj) template<class T> bool Map::AddToMap(T *obj) { - //TODO: Needs clean up. An object should not be added to map twice. + /// @todo Needs clean up. An object should not be added to map twice. if (obj->IsInWorld()) { ASSERT(obj->IsInGrid()); @@ -829,7 +839,7 @@ void Map::MoveAllCreaturesInMoveList() //This may happen when a player just logs in and a pet moves to a nearby unloaded cell //To avoid this, we can load nearby cells when player log in //But this check is always needed to ensure safety - //TODO: pets will disappear if this is outside CreatureRespawnRelocation + /// @todo pets will disappear if this is outside CreatureRespawnRelocation //need to check why pet is frequently relocated to an unloaded cell if (c->isPet()) ((Pet*)c)->Remove(PET_SAVE_NOT_IN_SLOT, true); @@ -998,8 +1008,8 @@ bool Map::UnloadGrid(NGridType& ngrid, bool unloadAll) GridMaps[gx][gy]->unloadData(); delete GridMaps[gx][gy]; } - // x and y are swapped VMAP::VMapFactory::createOrGetVMapManager()->unloadMap(GetId(), gx, gy); + MMAP::MMapFactory::createOrGetMMapManager()->unloadMap(GetId(), gx, gy); } else ((MapInstanced*)m_parentMap)->RemoveGridMapReference(GridCoord(gx, gy)); @@ -1071,7 +1081,7 @@ GridMap::~GridMap() unloadData(); } -bool GridMap::loadData(char *filename) +bool GridMap::loadData(char* filename) { // Unload old data if exist unloadData(); @@ -1088,23 +1098,23 @@ bool GridMap::loadData(char *filename) return false; } - if (header.mapMagic == MapMagic.asUInt && header.versionMagic == MapVersionMagic.asUInt) + if (header.mapMagic.asUInt == MapMagic.asUInt && header.versionMagic.asUInt == MapVersionMagic.asUInt) { - // loadup area data + // load up area data if (header.areaMapOffset && !loadAreaData(in, header.areaMapOffset, header.areaMapSize)) { sLog->outError(LOG_FILTER_MAPS, "Error loading map area data\n"); fclose(in); return false; } - // loadup height data + // load up height data if (header.heightMapOffset && !loadHeightData(in, header.heightMapOffset, header.heightMapSize)) { sLog->outError(LOG_FILTER_MAPS, "Error loading map height data\n"); fclose(in); return false; } - // loadup liquid data + // load up liquid data if (header.liquidMapOffset && !loadLiquidData(in, header.liquidMapOffset, header.liquidMapSize)) { sLog->outError(LOG_FILTER_MAPS, "Error loading map liquids data\n"); @@ -1114,7 +1124,9 @@ bool GridMap::loadData(char *filename) fclose(in); return true; } - sLog->outError(LOG_FILTER_MAPS, "Map file '%s' is from an incompatible clientversion. Please recreate using the mapextractor.", filename); + + sLog->outError(LOG_FILTER_MAPS, "Map file '%s' is from an incompatible map version (%.*s %.*s), %.*s %.*s is expected. Please recreate using the mapextractor.", + filename, 4, header.mapMagic.asChar, 4, header.versionMagic.asChar, 4, MapMagic.asChar, 4, MapVersionMagic.asChar); fclose(in); return false; } @@ -1905,10 +1917,10 @@ bool Map::isInLineOfSight(float x1, float y1, float z1, float x2, float y2, floa bool Map::getObjectHitPos(uint32 phasemask, float x1, float y1, float z1, float x2, float y2, float z2, float& rx, float& ry, float& rz, float modifyDist) { - Vector3 startPos = Vector3(x1, y1, z1); - Vector3 dstPos = Vector3(x2, y2, z2); + G3D::Vector3 startPos(x1, y1, z1); + G3D::Vector3 dstPos(x2, y2, z2); - Vector3 resultPos; + G3D::Vector3 resultPos; bool result = _dynamicTree.getObjectHitPos(phasemask, startPos, dstPos, resultPos, modifyDist); rx = resultPos.x; @@ -2375,7 +2387,7 @@ bool InstanceMap::CanEnter(Player* player) */ bool InstanceMap::AddPlayerToMap(Player* player) { - // TODO: Not sure about checking player level: already done in HandleAreaTriggerOpcode + /// @todo Not sure about checking player level: already done in HandleAreaTriggerOpcode // GMs still can teleport player in instance. // Is it needed? @@ -2469,13 +2481,6 @@ bool InstanceMap::AddPlayerToMap(Player* player) ASSERT(playerBind->save == mapSave); } } - - if (group && group->isLFGGroup()) - if (uint32 dungeonId = sLFGMgr->GetDungeon(group->GetGUID(), true)) - if (LFGDungeonData const* dungeon = sLFGMgr->GetLFGDungeon(dungeonId)) - if (LFGDungeonData const* randomDungeon = sLFGMgr->GetLFGDungeon(*(sLFGMgr->GetSelectedDungeons(player->GetGUID()).begin()))) - if (uint32(dungeon->map) == GetId() && dungeon->difficulty == GetDifficulty() && randomDungeon->type == LFG_TYPE_RANDOM) - player->CastSpell(player, LFG_SPELL_LUCK_OF_THE_DRAW, true); } // for normal instances cancel the reset schedule when the @@ -2536,7 +2541,7 @@ void InstanceMap::CreateInstanceData(bool load) if (load) { - // TODO: make a global storage for this + /// @todo make a global storage for this PreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_SEL_INSTANCE); stmt->setUInt16(0, uint16(GetId())); stmt->setUInt32(1, i_InstanceId); diff --git a/src/server/game/Maps/Map.h b/src/server/game/Maps/Map.h index 47a26fa49e7..3deeb4e04b1 100644 --- a/src/server/game/Maps/Map.h +++ b/src/server/game/Maps/Map.h @@ -58,8 +58,15 @@ struct ScriptAction { uint64 sourceGUID; uint64 targetGUID; - uint64 ownerGUID; // owner of source if source is item - ScriptInfo const* script; // pointer to static script data + uint64 ownerGUID; ///> owner of source if source is item + ScriptInfo const* script; ///> pointer to static script data +}; + +/// Represents a map magic value of 4 bytes (used in versions) +union u_map_magic +{ + char asChar[4]; ///> Non-null terminated string + uint32 asUInt; ///> uint32 representation }; // ****************************************** @@ -67,15 +74,17 @@ struct ScriptAction // ****************************************** struct map_fileheader { - uint32 mapMagic; - uint32 versionMagic; - uint32 buildMagic; + u_map_magic mapMagic; + u_map_magic versionMagic; + u_map_magic buildMagic; uint32 areaMapOffset; uint32 areaMapSize; uint32 heightMapOffset; uint32 heightMapSize; uint32 liquidMapOffset; uint32 liquidMapSize; + uint32 holesOffset; + uint32 holesSize; }; #define MAP_AREA_NO_AREA 0x0001 @@ -426,6 +435,7 @@ class Map : public GridRefManager<NGridType> void UpdateIteratorBack(Player* player); TempSummon* SummonCreature(uint32 entry, Position const& pos, SummonPropertiesEntry const* properties = NULL, uint32 duration = 0, Unit* summoner = NULL, uint32 spellId = 0, uint32 vehId = 0); + void SummonCreatureGroup(uint8 group, std::list<TempSummon*>* list = NULL); Creature* GetCreature(uint64 guid); GameObject* GetGameObject(uint64 guid); DynamicObject* GetDynamicObject(uint64 guid); @@ -479,6 +489,7 @@ class Map : public GridRefManager<NGridType> void LoadMapAndVMap(int gx, int gy); void LoadVMap(int gx, int gy); void LoadMap(int gx, int gy, bool reload = false); + void LoadMMap(int gx, int gy); GridMap* GetGrid(float x, float y); void SetTimer(uint32 t) { i_gridExpiry = t < MIN_GRID_DELAY ? MIN_GRID_DELAY : t; } @@ -526,6 +537,7 @@ class Map : public GridRefManager<NGridType> void SetUnloadReferenceLock(const GridCoord &p, bool on) { getNGrid(p.x_coord, p.y_coord)->setUnloadReferenceLock(on); } ACE_Thread_Mutex Lock; + ACE_Thread_Mutex GridLock; MapEntry const* i_mapEntry; uint8 i_spawnMode; diff --git a/src/server/game/Maps/MapInstanced.cpp b/src/server/game/Maps/MapInstanced.cpp index 27a1e0cc432..c2079c22e76 100644 --- a/src/server/game/Maps/MapInstanced.cpp +++ b/src/server/game/Maps/MapInstanced.cpp @@ -21,6 +21,7 @@ #include "MapManager.h" #include "Battleground.h" #include "VMapFactory.h" +#include "MMapFactory.h" #include "InstanceSaveMgr.h" #include "World.h" #include "Group.h" @@ -261,6 +262,7 @@ bool MapInstanced::DestroyInstance(InstancedMaps::iterator &itr) if (m_InstancedMaps.size() <= 1 && sWorld->getBoolConfig(CONFIG_GRID_UNLOAD)) { VMAP::VMapFactory::createOrGetVMapManager()->unloadMap(itr->second->GetId()); + MMAP::MMapFactory::createOrGetMMapManager()->unloadMap(itr->second->GetId()); // in that case, unload grids of the base map, too // so in the next map creation, (EnsureGridCreated actually) VMaps will be reloaded Map::UnloadAll(); diff --git a/src/server/game/Maps/MapManager.cpp b/src/server/game/Maps/MapManager.cpp index 755d443091a..4c09db16bd5 100644 --- a/src/server/game/Maps/MapManager.cpp +++ b/src/server/game/Maps/MapManager.cpp @@ -105,16 +105,17 @@ Map* MapManager::CreateBaseMap(uint32 id) { TRINITY_GUARD(ACE_Thread_Mutex, Lock); - const MapEntry* entry = sMapStore.LookupEntry(id); - if (entry && entry->Instanceable()) - { + MapEntry const* entry = sMapStore.LookupEntry(id); + ASSERT(entry); + + if (entry->Instanceable()) map = new MapInstanced(id, i_gridCleanUpDelay); - } else { map = new Map(id, i_gridCleanUpDelay, 0, REGULAR_DIFFICULTY); map->LoadRespawnTimes(); } + i_maps[id] = map; } @@ -194,7 +195,7 @@ bool MapManager::CanPlayerEnter(uint32 mapid, Player* player, bool loginCheck) if ((!group || !group->isRaidGroup()) && !sWorld->getBoolConfig(CONFIG_INSTANCE_IGNORE_RAID)) { // probably there must be special opcode, because client has this string constant in GlobalStrings.lua - // TODO: this is not a good place to send the message + /// @todo this is not a good place to send the message player->GetSession()->SendAreaTriggerMessage(player->GetSession()->GetTrinityString(LANG_INSTANCE_RAID_GROUP_ONLY), mapName); sLog->outDebug(LOG_FILTER_MAPS, "MAP: Player '%s' must be in a raid group to enter instance '%s'", player->GetName().c_str(), mapName); return false; @@ -246,7 +247,7 @@ bool MapManager::CanPlayerEnter(uint32 mapid, Player* player, bool loginCheck) if (playerBoundedInstance && playerBoundedInstance->perm && playerBoundedInstance->save && boundedInstance->save->GetInstanceId() != playerBoundedInstance->save->GetInstanceId()) { - //TODO: send some kind of error message to the player + /// @todo send some kind of error message to the player return false; }*/ } @@ -320,7 +321,7 @@ bool MapManager::IsValidMAP(uint32 mapid, bool startUp) else return mEntry && (!mEntry->IsDungeon() || sObjectMgr->GetInstanceTemplate(mapid)); - // TODO: add check for battleground template + /// @todo add check for battleground template } void MapManager::UnloadAll() diff --git a/src/server/game/Maps/ZoneScript.h b/src/server/game/Maps/ZoneScript.h index 9cea5fec518..ce7168a4040 100644 --- a/src/server/game/Maps/ZoneScript.h +++ b/src/server/game/Maps/ZoneScript.h @@ -32,11 +32,11 @@ class ZoneScript virtual uint32 GetCreatureEntry(uint32 /*guidlow*/, CreatureData const* data) { return data->id; } virtual uint32 GetGameObjectEntry(uint32 /*guidlow*/, uint32 entry) { return entry; } - virtual void OnCreatureCreate(Creature *) { } - virtual void OnCreatureRemove(Creature *) { } + virtual void OnCreatureCreate(Creature* ) { } + virtual void OnCreatureRemove(Creature* ) { } - virtual void OnGameObjectCreate(GameObject *) { } - virtual void OnGameObjectRemove(GameObject *) { } + virtual void OnGameObjectCreate(GameObject* ) { } + virtual void OnGameObjectRemove(GameObject* ) { } virtual void OnUnitDeath(Unit*) { } diff --git a/src/server/game/Miscellaneous/Formulas.h b/src/server/game/Miscellaneous/Formulas.h index b0a461d7760..6579485a56f 100644 --- a/src/server/game/Miscellaneous/Formulas.h +++ b/src/server/game/Miscellaneous/Formulas.h @@ -39,7 +39,8 @@ namespace Trinity { return uint32(ceil(hk_honor_at_level_f(level, multiplier))); } - } + } // namespace Trinity::Honor + namespace XP { inline uint8 GetGrayLevel(uint8 pl_level) @@ -219,7 +220,7 @@ namespace Trinity sScriptMgr->OnGroupRateCalculation(rate, count, isRaid); return rate; } - } -} + } // namespace Trinity::XP +} // namespace Trinity #endif diff --git a/src/server/game/Miscellaneous/Language.h b/src/server/game/Miscellaneous/Language.h index f116d695e17..f4379e59f19 100644 --- a/src/server/game/Miscellaneous/Language.h +++ b/src/server/game/Miscellaneous/Language.h @@ -86,7 +86,40 @@ enum TrinityStrings LANG_CONNECTED_PLAYERS = 60, LANG_ACCOUNT_ADDON = 61, LANG_IMPROPER_VALUE = 62, - // Room for more level 0 63-99 not used + LANG_RBAC_WRONG_PARAMETER_ID = 63, + LANG_RBAC_WRONG_PARAMETER_REALM = 64, + LANG_RBAC_GROUP_IN_LIST = 65, + LANG_RBAC_GROUP_NOT_IN_LIST = 66, + LANG_RBAC_GROUP_ADDED = 67, + LANG_RBAC_GROUP_REMOVED = 68, + LANG_RBAC_GROUP_LIST_HEADER = 69, + LANG_RBAC_LIST_EMPTY = 70, + LANG_RBAC_LIST_ELEMENT = 71, + LANG_RBAC_ROLE_GRANTED_IN_LIST = 72, + LANG_RBAC_ROLE_GRANTED_IN_DENIED_LIST = 73, + LANG_RBAC_ROLE_GRANTED = 74, + LANG_RBAC_ROLE_DENIED_IN_LIST = 75, + LANG_RBAC_ROLE_DENIED_IN_GRANTED_LIST = 76, + LANG_RBAC_ROLE_DENIED = 77, + LANG_RBAC_ROLE_REVOKED = 78, + LANG_RBAC_ROLE_REVOKED_NOT_IN_LIST = 79, + LANG_RBAC_ROLE_LIST_HEADER_GRANTED = 80, + LANG_RBAC_ROLE_LIST_HEADER_DENIED = 81, + LANG_RBAC_PERM_GRANTED_IN_LIST = 82, + LANG_RBAC_PERM_GRANTED_IN_DENIED_LIST = 83, + LANG_RBAC_PERM_GRANTED = 84, + LANG_RBAC_PERM_DENIED_IN_LIST = 85, + LANG_RBAC_PERM_DENIED_IN_GRANTED_LIST = 86, + LANG_RBAC_PERM_DENIED = 87, + LANG_RBAC_PERM_REVOKED = 88, + LANG_RBAC_PERM_REVOKED_NOT_IN_LIST = 89, + LANG_RBAC_PERM_LIST_HEADER_GRANTED = 90, + LANG_RBAC_PERM_LIST_HEADER_DENIED = 91, + LANG_RBAC_PERM_LIST_GLOBAL = 92, + LANG_RBAC_LIST_GROUPS_HEADER = 93, + LANG_RBAC_LIST_ROLES_HEADER = 94, + LANG_RBAC_LIST_PERMISSIONS_HEADER = 95, + // Room for more level 0 96-99 not used // level 1 chat LANG_GLOBAL_NOTIFY = 100, @@ -343,7 +376,8 @@ enum TrinityStrings LANG_COMMAND_CHEAT_CD = 360, LANG_COMMAND_CHEAT_POWER = 361, LANG_COMMAND_CHEAT_WW = 362, - // Room for more level 2 363-399 not used + LANG_COMMAND_WHISPEROFFPLAYER = 363, + // Room for more level 2 364-399 not used // level 3 chat LANG_SCRIPTS_RELOADED = 400, @@ -522,6 +556,7 @@ enum TrinityStrings LANG_PINFO_BAN = 453, LANG_PINFO_MAP_ONLINE = 714, LANG_PINFO_MAP_OFFLINE = 716, + LANG_PINFO_GUILD_INFO = 749, LANG_YOU_SET_EXPLORE_ALL = 551, LANG_YOU_SET_EXPLORE_NOTHING = 552, @@ -742,7 +777,32 @@ enum TrinityStrings LANG_COMMAND_CREATURESTORAGE_NOTFOUND = 818, LANG_CHANNEL_CITY = 819, - // Room for in-game strings 820-999 not used + + LANG_NPCINFO_GOSSIP = 820, + LANG_NPCINFO_QUESTGIVER = 821, + LANG_NPCINFO_TRAINER_CLASS = 822, + LANG_NPCINFO_TRAINER_PROFESSION = 823, + LANG_NPCINFO_VENDOR_AMMO = 824, + LANG_NPCINFO_VENDOR_FOOD = 825, + LANG_NPCINFO_VENDOR_POISON = 826, + LANG_NPCINFO_VENDOR_REAGENT = 827, + LANG_NPCINFO_REPAIR = 828, + LANG_NPCINFO_FLIGHTMASTER = 829, + LANG_NPCINFO_SPIRITHEALER = 830, + LANG_NPCINFO_SPIRITGUIDE = 831, + LANG_NPCINFO_INNKEEPER = 832, + LANG_NPCINFO_BANKER = 833, + LANG_NPCINFO_PETITIONER = 834, + LANG_NPCINFO_TABARDDESIGNER = 835, + LANG_NPCINFO_BATTLEMASTER = 836, + LANG_NPCINFO_AUCTIONEER = 837, + LANG_NPCINFO_STABLEMASTER = 838, + LANG_NPCINFO_GUILD_BANKER = 839, + LANG_NPCINFO_SPELLCLICK = 840, + LANG_NPCINFO_MAILBOX = 841, + LANG_NPCINFO_PLAYER_VEHICLE = 842, + + // Room for in-game strings 843-999 not used // Level 4 (CLI only commands) LANG_COMMAND_EXIT = 1000, @@ -822,7 +882,19 @@ enum TrinityStrings LANG_MOVEGENS_EFFECT = 1142, LANG_MOVEFLAGS_GET = 1143, LANG_MOVEFLAGS_SET = 1144, - // Room for more level 3 1144-1199 not used + LANG_GROUP_ALREADY_IN_GROUP = 1145, + LANG_GROUP_PLAYER_JOINED = 1146, + LANG_GROUP_NOT_IN_GROUP = 1147, + LANG_GROUP_FULL = 1148, + LANG_GROUP_TYPE = 1149, + LANG_GROUP_PLAYER_NAME_GUID = 1150, + LANG_LIST_MAIL_HEADER = 1151, + LANG_LIST_MAIL_INFO_1 = 1152, + LANG_LIST_MAIL_INFO_2 = 1153, + LANG_LIST_MAIL_INFO_3 = 1154, + LANG_LIST_MAIL_INFO_ITEM = 1155, + LANG_LIST_MAIL_NOT_FOUND = 1156, + // Room for more level 3 1157-1199 not used // Debug commands LANG_CINEMATIC_NOT_EXIST = 1200, @@ -928,6 +1000,7 @@ enum TrinityStrings LANG_COMMAND_TICKETSHOWESCALATEDLIST = 2026, LANG_COMMAND_TICKETPENDING = 2027, LANG_COMMAND_TICKETRESET = 2028, + LANG_COMMAND_TICKETLISTRESPONSE = 2029, // Trinity strings 5000-9999 LANG_COMMAND_FREEZE = 5000, @@ -967,7 +1040,8 @@ enum TrinityStrings LANG_COMMAND_NO_ACHIEVEMENT_CRITERIA_FOUND = 5033, LANG_COMMAND_NO_OUTDOOR_PVP_FORUND = 5034, LANG_CALL_FOR_HELP = 5035, - // Room for more Trinity strings 5036-9999 + LANG_NPCINFO_EQUIPMENT = 5036, + // Room for more Trinity strings 5037-9999 // Level requirement notifications LANG_SAY_REQ = 6604, diff --git a/src/server/game/Miscellaneous/SharedDefines.h b/src/server/game/Miscellaneous/SharedDefines.h index 05696694033..caf504944c6 100644 --- a/src/server/game/Miscellaneous/SharedDefines.h +++ b/src/server/game/Miscellaneous/SharedDefines.h @@ -19,6 +19,7 @@ #ifndef TRINITY_SHAREDDEFINES_H #define TRINITY_SHAREDDEFINES_H +#include "DetourNavMesh.h" #include "Define.h" #include <cassert> @@ -296,7 +297,7 @@ enum SpellAttr0 SPELL_ATTR0_CASTABLE_WHILE_SITTING = 0x08000000, // 27 castable while sitting SPELL_ATTR0_CANT_USED_IN_COMBAT = 0x10000000, // 28 Cannot be used in combat SPELL_ATTR0_UNAFFECTED_BY_INVULNERABILITY = 0x20000000, // 29 unaffected by invulnerability (hmm possible not...) - SPELL_ATTR0_BREAKABLE_BY_DAMAGE = 0x40000000, // 30 + SPELL_ATTR0_HEARTBEAT_RESIST_CHECK = 0x40000000, // 30 random chance the effect will end TODO: implement core support SPELL_ATTR0_CANT_CANCEL = 0x80000000 // 31 positive aura can't be canceled }; @@ -432,7 +433,7 @@ enum SpellAttr4 SPELL_ATTR4_UNK19 = 0x00080000, // 19 proc dalayed, after damage or don't proc on absorb? SPELL_ATTR4_NOT_CHECK_SELFCAST_POWER = 0x00100000, // 20 supersedes message "More powerful spell applied" for self casts. SPELL_ATTR4_UNK21 = 0x00200000, // 21 Pally aura, dk presence, dudu form, warrior stance, shadowform, hunter track - SPELL_ATTR4_UNK22 = 0x00400000, // 22 Seal of Command (42058,57770) and Gymer's Smash 55426 + SPELL_ATTR4_UNK22 = 0x00400000, // 22 Seal of Command (42058, 57770) and Gymer's Smash 55426 SPELL_ATTR4_UNK23 = 0x00800000, // 23 SPELL_ATTR4_UNK24 = 0x01000000, // 24 some shoot spell SPELL_ATTR4_IS_PET_SCALING = 0x02000000, // 25 pet scaling auras @@ -441,7 +442,7 @@ enum SpellAttr4 SPELL_ATTR4_UNK28 = 0x10000000, // 28 Aimed Shot SPELL_ATTR4_UNK29 = 0x20000000, // 29 SPELL_ATTR4_UNK30 = 0x40000000, // 30 - SPELL_ATTR4_UNK31 = 0x80000000 // 31 Polymorph (chicken) 228 and Sonic Boom (38052,38488) + SPELL_ATTR4_UNK31 = 0x80000000 // 31 Polymorph (chicken) 228 and Sonic Boom (38052, 38488) }; enum SpellAttr5 @@ -473,8 +474,8 @@ enum SpellAttr5 SPELL_ATTR5_UNK24 = 0x01000000, // 24 SPELL_ATTR5_UNK25 = 0x02000000, // 25 SPELL_ATTR5_UNK26 = 0x04000000, // 26 aoe related - Boulder, Cannon, Corpse Explosion, Fire Nova, Flames, Frost Bomb, Living Bomb, Seed of Corruption, Starfall, Thunder Clap, Volley - SPELL_ATTR5_UNK27 = 0x08000000, // 27 - SPELL_ATTR5_UNK28 = 0x10000000, // 28 + SPELL_ATTR5_DONT_SHOW_AURA_IF_SELF_CAST = 0x08000000, // 27 Auras with this attribute are not visible on units that are the caster + SPELL_ATTR5_DONT_SHOW_AURA_IF_NOT_SELF_CAST = 0x10000000, // 28 Auras with this attribute are not visible on units that are not the caster SPELL_ATTR5_UNK29 = 0x20000000, // 29 SPELL_ATTR5_UNK30 = 0x40000000, // 30 SPELL_ATTR5_UNK31 = 0x80000000 // 31 Forces all nearby enemies to focus attacks caster @@ -485,10 +486,10 @@ enum SpellAttr6 SPELL_ATTR6_DONT_DISPLAY_COOLDOWN = 0x00000001, // 0 client doesn't display cooldown in tooltip for these spells SPELL_ATTR6_ONLY_IN_ARENA = 0x00000002, // 1 only usable in arena SPELL_ATTR6_IGNORE_CASTER_AURAS = 0x00000004, // 2 - SPELL_ATTR6_UNK3 = 0x00000008, // 3 + SPELL_ATTR6_ASSIST_IGNORE_IMMUNE_FLAG = 0x00000008, // 3 skips checking UNIT_FLAG_IMMUNE_TO_PC and UNIT_FLAG_IMMUNE_TO_NPC flags on assist SPELL_ATTR6_UNK4 = 0x00000010, // 4 SPELL_ATTR6_UNK5 = 0x00000020, // 5 - SPELL_ATTR6_UNK6 = 0x00000040, // 6 + SPELL_ATTR6_USE_SPELL_CAST_EVENT = 0x00000040, // 6 Auras with this attribute trigger SPELL_CAST combat log event instead of SPELL_AURA_START (clientside attribute) SPELL_ATTR6_UNK7 = 0x00000080, // 7 SPELL_ATTR6_CANT_TARGET_CROWD_CONTROLLED = 0x00000100, // 8 SPELL_ATTR6_UNK9 = 0x00000200, // 9 @@ -502,7 +503,7 @@ enum SpellAttr6 SPELL_ATTR6_UNK17 = 0x00020000, // 17 Mount spell SPELL_ATTR6_CAST_BY_CHARMER = 0x00040000, // 18 client won't allow to cast these spells when unit is not possessed && charmer of caster will be original caster SPELL_ATTR6_UNK19 = 0x00080000, // 19 only 47488, 50782 - SPELL_ATTR6_UNK20 = 0x00100000, // 20 only 58371, 62218 + SPELL_ATTR6_ONLY_VISIBLE_TO_CASTER = 0x00100000, // 20 Auras with this attribute are only visible to their caster (or pet's owner) SPELL_ATTR6_CLIENT_UI_TARGET_EFFECTS = 0x00200000, // 21 it's only client-side attribute SPELL_ATTR6_UNK22 = 0x00400000, // 22 only 72054 SPELL_ATTR6_UNK23 = 0x00800000, // 23 @@ -513,7 +514,7 @@ enum SpellAttr6 SPELL_ATTR6_UNK28 = 0x10000000, // 28 Death Grip SPELL_ATTR6_NO_DONE_PCT_DAMAGE_MODS = 0x20000000, // 29 ignores done percent damage mods? SPELL_ATTR6_UNK30 = 0x40000000, // 30 - SPELL_ATTR6_UNK31 = 0x80000000 // 31 some special cooldown calc? only 2894 + SPELL_ATTR6_IGNORE_CATEGORY_COOLDOWN_MODS = 0x80000000 // 31 Spells with this attribute skip applying modifiers to category cooldowns }; enum SpellAttr7 @@ -546,7 +547,7 @@ enum SpellAttr7 SPELL_ATTR7_UNK25 = 0x02000000, // 25 SPELL_ATTR7_UNK26 = 0x04000000, // 26 SPELL_ATTR7_UNK27 = 0x08000000, // 27 Not set - SPELL_ATTR7_BENEFIT_FROM_SPELLMOD = 0x10000000, // 28 Non-permanent, non-passive buffs that may benefit from spellmods + SPELL_ATTR7_CONSOLIDATED_RAID_BUFF = 0x10000000, // 28 May be collapsed in raid buff frame (clientside attribute) SPELL_ATTR7_UNK29 = 0x20000000, // 29 only 69028, 71237 SPELL_ATTR7_UNK30 = 0x40000000, // 30 Burning Determination, Divine Sacrifice, Earth Shield, Prayer of Mending SPELL_ATTR7_CLIENT_INDICATOR = 0x80000000 @@ -3156,124 +3157,129 @@ enum SummonType enum EventId { EVENT_CHARGE = 1003, - EVENT_JUMP = 1004 + EVENT_JUMP = 1004, + + /// Special charge event which is used for charge spells that have explicit targets + /// and had a path already generated - using it in PointMovementGenerator will not + /// create a new spline and launch it + EVENT_CHARGE_PREPATH = 1005 }; enum ResponseCodes { - RESPONSE_SUCCESS = 0x00, - RESPONSE_FAILURE = 0x01, - RESPONSE_CANCELLED = 0x02, - RESPONSE_DISCONNECTED = 0x03, - RESPONSE_FAILED_TO_CONNECT = 0x04, - RESPONSE_CONNECTED = 0x05, - RESPONSE_VERSION_MISMATCH = 0x06, - - CSTATUS_CONNECTING = 0x07, - CSTATUS_NEGOTIATING_SECURITY = 0x08, - CSTATUS_NEGOTIATION_COMPLETE = 0x09, - CSTATUS_NEGOTIATION_FAILED = 0x0A, - CSTATUS_AUTHENTICATING = 0x0B, - - AUTH_OK = 0x0C, - AUTH_FAILED = 0x0D, - AUTH_REJECT = 0x0E, - AUTH_BAD_SERVER_PROOF = 0x0F, - AUTH_UNAVAILABLE = 0x10, - AUTH_SYSTEM_ERROR = 0x11, - AUTH_BILLING_ERROR = 0x12, - AUTH_BILLING_EXPIRED = 0x13, - AUTH_VERSION_MISMATCH = 0x14, - AUTH_UNKNOWN_ACCOUNT = 0x15, - AUTH_INCORRECT_PASSWORD = 0x16, - AUTH_SESSION_EXPIRED = 0x17, - AUTH_SERVER_SHUTTING_DOWN = 0x18, - AUTH_ALREADY_LOGGING_IN = 0x19, - AUTH_LOGIN_SERVER_NOT_FOUND = 0x1A, - AUTH_WAIT_QUEUE = 0x1B, - AUTH_BANNED = 0x1C, - AUTH_ALREADY_ONLINE = 0x1D, - AUTH_NO_TIME = 0x1E, - AUTH_DB_BUSY = 0x1F, - AUTH_SUSPENDED = 0x20, - AUTH_PARENTAL_CONTROL = 0x21, - AUTH_LOCKED_ENFORCED = 0x22, - - REALM_LIST_IN_PROGRESS = 0x23, - REALM_LIST_SUCCESS = 0x24, - REALM_LIST_FAILED = 0x25, - REALM_LIST_INVALID = 0x26, - REALM_LIST_REALM_NOT_FOUND = 0x27, - - ACCOUNT_CREATE_IN_PROGRESS = 0x28, - ACCOUNT_CREATE_SUCCESS = 0x29, - ACCOUNT_CREATE_FAILED = 0x2A, - - CHAR_LIST_RETRIEVING = 0x2B, - CHAR_LIST_RETRIEVED = 0x2C, - CHAR_LIST_FAILED = 0x2D, - - CHAR_CREATE_IN_PROGRESS = 0x2E, - CHAR_CREATE_SUCCESS = 0x2F, - CHAR_CREATE_ERROR = 0x30, - CHAR_CREATE_FAILED = 0x31, - CHAR_CREATE_NAME_IN_USE = 0x32, - CHAR_CREATE_DISABLED = 0x33, - CHAR_CREATE_PVP_TEAMS_VIOLATION = 0x34, - CHAR_CREATE_SERVER_LIMIT = 0x35, - CHAR_CREATE_ACCOUNT_LIMIT = 0x36, - CHAR_CREATE_SERVER_QUEUE = 0x37, - CHAR_CREATE_ONLY_EXISTING = 0x38, - CHAR_CREATE_EXPANSION = 0x39, - CHAR_CREATE_EXPANSION_CLASS = 0x3A, - CHAR_CREATE_LEVEL_REQUIREMENT = 0x3B, - CHAR_CREATE_UNIQUE_CLASS_LIMIT = 0x3C, - CHAR_CREATE_CHARACTER_IN_GUILD = 0x3D, - CHAR_CREATE_RESTRICTED_RACECLASS = 0x3E, - CHAR_CREATE_CHARACTER_CHOOSE_RACE = 0x3F, - CHAR_CREATE_CHARACTER_ARENA_LEADER = 0x40, - CHAR_CREATE_CHARACTER_DELETE_MAIL = 0x41, - CHAR_CREATE_CHARACTER_SWAP_FACTION = 0x42, - CHAR_CREATE_CHARACTER_RACE_ONLY = 0x43, - CHAR_CREATE_CHARACTER_GOLD_LIMIT = 0x44, - CHAR_CREATE_FORCE_LOGIN = 0x45, - - CHAR_DELETE_IN_PROGRESS = 0x46, - CHAR_DELETE_SUCCESS = 0x47, - CHAR_DELETE_FAILED = 0x48, - CHAR_DELETE_FAILED_LOCKED_FOR_TRANSFER = 0x49, - CHAR_DELETE_FAILED_GUILD_LEADER = 0x4A, - CHAR_DELETE_FAILED_ARENA_CAPTAIN = 0x4B, - - CHAR_LOGIN_IN_PROGRESS = 0x4C, - CHAR_LOGIN_SUCCESS = 0x4D, - CHAR_LOGIN_NO_WORLD = 0x4E, - CHAR_LOGIN_DUPLICATE_CHARACTER = 0x4F, - CHAR_LOGIN_NO_INSTANCES = 0x50, - CHAR_LOGIN_FAILED = 0x51, - CHAR_LOGIN_DISABLED = 0x52, - CHAR_LOGIN_NO_CHARACTER = 0x53, - CHAR_LOGIN_LOCKED_FOR_TRANSFER = 0x54, - CHAR_LOGIN_LOCKED_BY_BILLING = 0x55, - CHAR_LOGIN_LOCKED_BY_MOBILE_AH = 0x56, - - CHAR_NAME_SUCCESS = 0x57, - CHAR_NAME_FAILURE = 0x58, - CHAR_NAME_NO_NAME = 0x59, - CHAR_NAME_TOO_SHORT = 0x5A, - CHAR_NAME_TOO_LONG = 0x5B, - CHAR_NAME_INVALID_CHARACTER = 0x5C, - CHAR_NAME_MIXED_LANGUAGES = 0x5D, - CHAR_NAME_PROFANE = 0x5E, - CHAR_NAME_RESERVED = 0x5F, - CHAR_NAME_INVALID_APOSTROPHE = 0x60, - CHAR_NAME_MULTIPLE_APOSTROPHES = 0x61, - CHAR_NAME_THREE_CONSECUTIVE = 0x62, - CHAR_NAME_INVALID_SPACE = 0x63, - CHAR_NAME_CONSECUTIVE_SPACES = 0x64, - CHAR_NAME_RUSSIAN_CONSECUTIVE_SILENT_CHARACTERS = 0x65, - CHAR_NAME_RUSSIAN_SILENT_CHARACTER_AT_BEGINNING_OR_END = 0x66, - CHAR_NAME_DECLENSION_DOESNT_MATCH_BASE_NAME = 0x67 + RESPONSE_SUCCESS = 0, + RESPONSE_FAILURE = 1, + RESPONSE_CANCELLED = 2, + RESPONSE_DISCONNECTED = 3, + RESPONSE_FAILED_TO_CONNECT = 4, + RESPONSE_CONNECTED = 5, + RESPONSE_VERSION_MISMATCH = 6, + + CSTATUS_CONNECTING = 7, + CSTATUS_NEGOTIATING_SECURITY = 8, + CSTATUS_NEGOTIATION_COMPLETE = 9, + CSTATUS_NEGOTIATION_FAILED = 10, + CSTATUS_AUTHENTICATING = 11, + + AUTH_OK = 12, + AUTH_FAILED = 13, + AUTH_REJECT = 14, + AUTH_BAD_SERVER_PROOF = 15, + AUTH_UNAVAILABLE = 16, + AUTH_SYSTEM_ERROR = 17, + AUTH_BILLING_ERROR = 18, + AUTH_BILLING_EXPIRED = 19, + AUTH_VERSION_MISMATCH = 20, + AUTH_UNKNOWN_ACCOUNT = 21, + AUTH_INCORRECT_PASSWORD = 22, + AUTH_SESSION_EXPIRED = 23, + AUTH_SERVER_SHUTTING_DOWN = 24, + AUTH_ALREADY_LOGGING_IN = 25, + AUTH_LOGIN_SERVER_NOT_FOUND = 26, + AUTH_WAIT_QUEUE = 27, + AUTH_BANNED = 28, + AUTH_ALREADY_ONLINE = 29, + AUTH_NO_TIME = 30, + AUTH_DB_BUSY = 31, + AUTH_SUSPENDED = 32, + AUTH_PARENTAL_CONTROL = 33, + AUTH_LOCKED_ENFORCED = 34, + + REALM_LIST_IN_PROGRESS = 35, + REALM_LIST_SUCCESS = 36, + REALM_LIST_FAILED = 37, + REALM_LIST_INVALID = 38, + REALM_LIST_REALM_NOT_FOUND = 39, + + ACCOUNT_CREATE_IN_PROGRESS = 40, + ACCOUNT_CREATE_SUCCESS = 41, + ACCOUNT_CREATE_FAILED = 42, + + CHAR_LIST_RETRIEVING = 43, + CHAR_LIST_RETRIEVED = 44, + CHAR_LIST_FAILED = 45, + + CHAR_CREATE_IN_PROGRESS = 46, + CHAR_CREATE_SUCCESS = 47, + CHAR_CREATE_ERROR = 48, + CHAR_CREATE_FAILED = 49, + CHAR_CREATE_NAME_IN_USE = 50, + CHAR_CREATE_DISABLED = 51, + CHAR_CREATE_PVP_TEAMS_VIOLATION = 52, + CHAR_CREATE_SERVER_LIMIT = 53, + CHAR_CREATE_ACCOUNT_LIMIT = 54, + CHAR_CREATE_SERVER_QUEUE = 55, + CHAR_CREATE_ONLY_EXISTING = 56, + CHAR_CREATE_EXPANSION = 57, + CHAR_CREATE_EXPANSION_CLASS = 58, + CHAR_CREATE_LEVEL_REQUIREMENT = 59, + CHAR_CREATE_UNIQUE_CLASS_LIMIT = 60, + CHAR_CREATE_CHARACTER_IN_GUILD = 61, + CHAR_CREATE_RESTRICTED_RACECLASS = 62, + CHAR_CREATE_CHARACTER_CHOOSE_RACE = 63, + CHAR_CREATE_CHARACTER_ARENA_LEADER = 64, + CHAR_CREATE_CHARACTER_DELETE_MAIL = 65, + CHAR_CREATE_CHARACTER_SWAP_FACTION = 66, + CHAR_CREATE_CHARACTER_RACE_ONLY = 67, + CHAR_CREATE_CHARACTER_GOLD_LIMIT = 68, + CHAR_CREATE_FORCE_LOGIN = 69, + + CHAR_DELETE_IN_PROGRESS = 70, + CHAR_DELETE_SUCCESS = 71, + CHAR_DELETE_FAILED = 72, + CHAR_DELETE_FAILED_LOCKED_FOR_TRANSFER = 73, + CHAR_DELETE_FAILED_GUILD_LEADER = 74, + CHAR_DELETE_FAILED_ARENA_CAPTAIN = 75, + + CHAR_LOGIN_IN_PROGRESS = 76, + CHAR_LOGIN_SUCCESS = 77, + CHAR_LOGIN_NO_WORLD = 78, + CHAR_LOGIN_DUPLICATE_CHARACTER = 79, + CHAR_LOGIN_NO_INSTANCES = 80, + CHAR_LOGIN_FAILED = 81, + CHAR_LOGIN_DISABLED = 82, + CHAR_LOGIN_NO_CHARACTER = 83, + CHAR_LOGIN_LOCKED_FOR_TRANSFER = 84, + CHAR_LOGIN_LOCKED_BY_BILLING = 85, + CHAR_LOGIN_LOCKED_BY_MOBILE_AH = 86, + + CHAR_NAME_SUCCESS = 87, + CHAR_NAME_FAILURE = 88, + CHAR_NAME_NO_NAME = 89, + CHAR_NAME_TOO_SHORT = 90, + CHAR_NAME_TOO_LONG = 91, + CHAR_NAME_INVALID_CHARACTER = 92, + CHAR_NAME_MIXED_LANGUAGES = 93, + CHAR_NAME_PROFANE = 94, + CHAR_NAME_RESERVED = 95, + CHAR_NAME_INVALID_APOSTROPHE = 96, + CHAR_NAME_MULTIPLE_APOSTROPHES = 97, + CHAR_NAME_THREE_CONSECUTIVE = 98, + CHAR_NAME_INVALID_SPACE = 99, + CHAR_NAME_CONSECUTIVE_SPACES = 100, + CHAR_NAME_RUSSIAN_CONSECUTIVE_SILENT_CHARACTERS = 101, + CHAR_NAME_RUSSIAN_SILENT_CHARACTER_AT_BEGINNING_OR_END = 102, + CHAR_NAME_DECLENSION_DOESNT_MATCH_BASE_NAME = 103 }; /// Ban function modes @@ -3533,4 +3539,43 @@ enum PartyResult ERR_PARTY_LFG_TELEPORT_IN_COMBAT = 30 }; +const uint32 MMAP_MAGIC = 0x4d4d4150; // 'MMAP' +#define MMAP_VERSION 3 + +struct MmapTileHeader +{ + uint32 mmapMagic; + uint32 dtVersion; + uint32 mmapVersion; + uint32 size; + bool usesLiquids : 1; + + MmapTileHeader() : mmapMagic(MMAP_MAGIC), dtVersion(DT_NAVMESH_VERSION), + mmapVersion(MMAP_VERSION), size(0), usesLiquids(true) {} +}; + +enum NavTerrain +{ + NAV_EMPTY = 0x00, + NAV_GROUND = 0x01, + NAV_MAGMA = 0x02, + NAV_SLIME = 0x04, + NAV_WATER = 0x08, + NAV_UNUSED1 = 0x10, + NAV_UNUSED2 = 0x20, + NAV_UNUSED3 = 0x40, + NAV_UNUSED4 = 0x80 + // we only have 8 bits +}; + +enum DiminishingLevels +{ + DIMINISHING_LEVEL_1 = 0, + DIMINISHING_LEVEL_2 = 1, + DIMINISHING_LEVEL_3 = 2, + DIMINISHING_LEVEL_IMMUNE = 3, + DIMINISHING_LEVEL_4 = 3, + DIMINISHING_LEVEL_TAUNT_IMMUNE = 4 +}; + #endif diff --git a/src/server/game/Movement/FollowerRefManager.h b/src/server/game/Movement/FollowerRefManager.h index 2bb31d27227..92904f8e4af 100644 --- a/src/server/game/Movement/FollowerRefManager.h +++ b/src/server/game/Movement/FollowerRefManager.h @@ -29,4 +29,3 @@ class FollowerRefManager : public RefManager<Unit, TargetedMovementGeneratorBase }; #endif - diff --git a/src/server/game/Movement/FollowerReference.cpp b/src/server/game/Movement/FollowerReference.cpp index 2ce23e214d1..30797bbaaca 100644 --- a/src/server/game/Movement/FollowerReference.cpp +++ b/src/server/game/Movement/FollowerReference.cpp @@ -34,4 +34,3 @@ void FollowerReference::sourceObjectDestroyLink() { getSource()->stopFollowing(); } - diff --git a/src/server/game/Movement/FollowerReference.h b/src/server/game/Movement/FollowerReference.h index 9e373d2527e..43ad7e7fa58 100644 --- a/src/server/game/Movement/FollowerReference.h +++ b/src/server/game/Movement/FollowerReference.h @@ -32,4 +32,3 @@ class FollowerReference : public Reference<Unit, TargetedMovementGeneratorBase> void sourceObjectDestroyLink(); }; #endif - diff --git a/src/server/game/Movement/MotionMaster.cpp b/src/server/game/Movement/MotionMaster.cpp index ba648c72e26..8e045b98dbb 100644 --- a/src/server/game/Movement/MotionMaster.cpp +++ b/src/server/game/Movement/MotionMaster.cpp @@ -87,7 +87,7 @@ void MotionMaster::UpdateMotion(uint32 diff) ASSERT(!empty()); _cleanFlag |= MMCF_UPDATE; - if (!top()->Update(*_owner, diff)) + if (!top()->Update(_owner, diff)) { _cleanFlag &= ~MMCF_UPDATE; MovementExpired(); @@ -111,7 +111,7 @@ void MotionMaster::UpdateMotion(uint32 diff) else if (needInitTop()) InitTop(); else if (_cleanFlag & MMCF_RESET) - top()->Reset(*_owner); + top()->Reset(_owner); _cleanFlag &= ~MMCF_RESET; } @@ -132,7 +132,7 @@ void MotionMaster::DirectClean(bool reset) if (needInitTop()) InitTop(); else if (reset) - top()->Reset(*_owner); + top()->Reset(_owner); } void MotionMaster::DelayedClean() @@ -163,7 +163,7 @@ void MotionMaster::DirectExpire(bool reset) else if (needInitTop()) InitTop(); else if (reset) - top()->Reset(*_owner); + top()->Reset(_owner); } void MotionMaster::DelayedExpire() @@ -199,19 +199,19 @@ void MotionMaster::MoveTargetedHome() { Clear(false); - if (_owner->GetTypeId()==TYPEID_UNIT && !((Creature*)_owner)->GetCharmerOrOwnerGUID()) + if (_owner->GetTypeId() == TYPEID_UNIT && !_owner->ToCreature()->GetCharmerOrOwnerGUID()) { sLog->outDebug(LOG_FILTER_GENERAL, "Creature (Entry: %u GUID: %u) targeted home", _owner->GetEntry(), _owner->GetGUIDLow()); Mutate(new HomeMovementGenerator<Creature>(), MOTION_SLOT_ACTIVE); } - else if (_owner->GetTypeId()==TYPEID_UNIT && ((Creature*)_owner)->GetCharmerOrOwnerGUID()) + else if (_owner->GetTypeId() == TYPEID_UNIT && _owner->ToCreature()->GetCharmerOrOwnerGUID()) { sLog->outDebug(LOG_FILTER_GENERAL, "Pet or controlled creature (Entry: %u GUID: %u) targeting home", _owner->GetEntry(), _owner->GetGUIDLow()); - Unit *target = ((Creature*)_owner)->GetCharmerOrOwner(); + Unit* target = _owner->ToCreature()->GetCharmerOrOwner(); if (target) { sLog->outDebug(LOG_FILTER_GENERAL, "Following %s (GUID: %u)", target->GetTypeId() == TYPEID_PLAYER ? "player" : "creature", target->GetTypeId() == TYPEID_PLAYER ? target->GetGUIDLow() : ((Creature*)target)->GetDBTableGUIDLow()); - Mutate(new FollowMovementGenerator<Creature>(*target,PET_FOLLOW_DIST,PET_FOLLOW_ANGLE), MOTION_SLOT_ACTIVE); + Mutate(new FollowMovementGenerator<Creature>(target, PET_FOLLOW_DIST, PET_FOLLOW_ANGLE), MOTION_SLOT_ACTIVE); } } else @@ -248,7 +248,7 @@ void MotionMaster::MoveChase(Unit* target, float dist, float angle) _owner->GetGUIDLow(), target->GetTypeId() == TYPEID_PLAYER ? "player" : "creature", target->GetTypeId() == TYPEID_PLAYER ? target->GetGUIDLow() : target->ToCreature()->GetDBTableGUIDLow()); - Mutate(new ChaseMovementGenerator<Player>(*target,dist,angle), MOTION_SLOT_ACTIVE); + Mutate(new ChaseMovementGenerator<Player>(target, dist, angle), MOTION_SLOT_ACTIVE); } else { @@ -256,7 +256,7 @@ void MotionMaster::MoveChase(Unit* target, float dist, float angle) _owner->GetEntry(), _owner->GetGUIDLow(), target->GetTypeId() == TYPEID_PLAYER ? "player" : "creature", target->GetTypeId() == TYPEID_PLAYER ? target->GetGUIDLow() : target->ToCreature()->GetDBTableGUIDLow()); - Mutate(new ChaseMovementGenerator<Creature>(*target,dist,angle), MOTION_SLOT_ACTIVE); + Mutate(new ChaseMovementGenerator<Creature>(target, dist, angle), MOTION_SLOT_ACTIVE); } } @@ -272,7 +272,7 @@ void MotionMaster::MoveFollow(Unit* target, float dist, float angle, MovementSlo sLog->outDebug(LOG_FILTER_GENERAL, "Player (GUID: %u) follow to %s (GUID: %u)", _owner->GetGUIDLow(), target->GetTypeId() == TYPEID_PLAYER ? "player" : "creature", target->GetTypeId() == TYPEID_PLAYER ? target->GetGUIDLow() : target->ToCreature()->GetDBTableGUIDLow()); - Mutate(new FollowMovementGenerator<Player>(*target,dist,angle), slot); + Mutate(new FollowMovementGenerator<Player>(target, dist, angle), slot); } else { @@ -280,22 +280,22 @@ void MotionMaster::MoveFollow(Unit* target, float dist, float angle, MovementSlo _owner->GetEntry(), _owner->GetGUIDLow(), target->GetTypeId() == TYPEID_PLAYER ? "player" : "creature", target->GetTypeId() == TYPEID_PLAYER ? target->GetGUIDLow() : target->ToCreature()->GetDBTableGUIDLow()); - Mutate(new FollowMovementGenerator<Creature>(*target,dist,angle), slot); + Mutate(new FollowMovementGenerator<Creature>(target, dist, angle), slot); } } -void MotionMaster::MovePoint(uint32 id, float x, float y, float z) +void MotionMaster::MovePoint(uint32 id, float x, float y, float z, bool generatePath) { if (_owner->GetTypeId() == TYPEID_PLAYER) { sLog->outDebug(LOG_FILTER_GENERAL, "Player (GUID: %u) targeted point (Id: %u X: %f Y: %f Z: %f)", _owner->GetGUIDLow(), id, x, y, z); - Mutate(new PointMovementGenerator<Player>(id, x, y, z), MOTION_SLOT_ACTIVE); + Mutate(new PointMovementGenerator<Player>(id, x, y, z, generatePath), MOTION_SLOT_ACTIVE); } else { sLog->outDebug(LOG_FILTER_GENERAL, "Creature (Entry: %u GUID: %u) targeted point (ID: %u X: %f Y: %f Z: %f)", _owner->GetEntry(), _owner->GetGUIDLow(), id, x, y, z); - Mutate(new PointMovementGenerator<Creature>(id, x, y, z), MOTION_SLOT_ACTIVE); + Mutate(new PointMovementGenerator<Creature>(id, x, y, z, generatePath), MOTION_SLOT_ACTIVE); } } @@ -306,8 +306,8 @@ void MotionMaster::MoveLand(uint32 id, Position const& pos) sLog->outDebug(LOG_FILTER_GENERAL, "Creature (Entry: %u) landing point (ID: %u X: %f Y: %f Z: %f)", _owner->GetEntry(), id, x, y, z); - Movement::MoveSplineInit init(*_owner); - init.MoveTo(x,y,z); + Movement::MoveSplineInit init(_owner); + init.MoveTo(x, y, z); init.SetAnimation(Movement::ToGround); init.Launch(); Mutate(new EffectMovementGenerator(id), MOTION_SLOT_ACTIVE); @@ -320,8 +320,8 @@ void MotionMaster::MoveTakeoff(uint32 id, Position const& pos) sLog->outDebug(LOG_FILTER_GENERAL, "Creature (Entry: %u) landing point (ID: %u X: %f Y: %f Z: %f)", _owner->GetEntry(), id, x, y, z); - Movement::MoveSplineInit init(*_owner); - init.MoveTo(x,y,z); + Movement::MoveSplineInit init(_owner); + init.MoveTo(x, y, z); init.SetAnimation(Movement::ToFly); init.Launch(); Mutate(new EffectMovementGenerator(id), MOTION_SLOT_ACTIVE); @@ -336,13 +336,13 @@ void MotionMaster::MoveKnockbackFrom(float srcX, float srcY, float speedXY, floa float x, y, z; float moveTimeHalf = speedZ / Movement::gravity; float dist = 2 * moveTimeHalf * speedXY; - float max_height = -Movement::computeFallElevation(moveTimeHalf,false,-speedZ); + float max_height = -Movement::computeFallElevation(moveTimeHalf, false, -speedZ); _owner->GetNearPoint(_owner, x, y, z, _owner->GetObjectSize(), dist, _owner->GetAngle(srcX, srcY) + M_PI); - Movement::MoveSplineInit init(*_owner); - init.MoveTo(x,y,z); - init.SetParabolic(max_height,0); + Movement::MoveSplineInit init(_owner); + init.MoveTo(x, y, z); + init.SetParabolic(max_height, 0); init.SetOrientationFixed(true); init.SetVelocity(speedXY); init.Launch(); @@ -368,11 +368,11 @@ void MotionMaster::MoveJump(float x, float y, float z, float speedXY, float spee sLog->outDebug(LOG_FILTER_GENERAL, "Unit (GUID: %u) jump to point (X: %f Y: %f Z: %f)", _owner->GetGUIDLow(), x, y, z); float moveTimeHalf = speedZ / Movement::gravity; - float max_height = -Movement::computeFallElevation(moveTimeHalf,false,-speedZ); + float max_height = -Movement::computeFallElevation(moveTimeHalf, false, -speedZ); - Movement::MoveSplineInit init(*_owner); - init.MoveTo(x,y,z); - init.SetParabolic(max_height,0); + Movement::MoveSplineInit init(_owner); + init.MoveTo(x, y, z, false); + init.SetParabolic(max_height, 0); init.SetVelocity(speedXY); init.Launch(); Mutate(new EffectMovementGenerator(id), MOTION_SLOT_CONTROLLED); @@ -399,14 +399,14 @@ void MotionMaster::MoveFall(uint32 id /*=0*/) _owner->m_movementInfo.SetFallTime(0); } - Movement::MoveSplineInit init(*_owner); - init.MoveTo(_owner->GetPositionX(), _owner->GetPositionY(), tz); + Movement::MoveSplineInit init(_owner); + init.MoveTo(_owner->GetPositionX(), _owner->GetPositionY(), tz, false); init.SetFall(); init.Launch(); Mutate(new EffectMovementGenerator(id), MOTION_SLOT_CONTROLLED); } -void MotionMaster::MoveCharge(float x, float y, float z, float speed, uint32 id) +void MotionMaster::MoveCharge(float x, float y, float z, float speed, uint32 id, bool generatePath) { if (Impl[MOTION_SLOT_CONTROLLED] && Impl[MOTION_SLOT_CONTROLLED]->GetMovementGeneratorType() != DISTRACT_MOTION_TYPE) return; @@ -414,16 +414,29 @@ void MotionMaster::MoveCharge(float x, float y, float z, float speed, uint32 id) if (_owner->GetTypeId() == TYPEID_PLAYER) { sLog->outDebug(LOG_FILTER_GENERAL, "Player (GUID: %u) charge point (X: %f Y: %f Z: %f)", _owner->GetGUIDLow(), x, y, z); - Mutate(new PointMovementGenerator<Player>(id, x, y, z, speed), MOTION_SLOT_CONTROLLED); + Mutate(new PointMovementGenerator<Player>(id, x, y, z, generatePath, speed), MOTION_SLOT_CONTROLLED); } else { sLog->outDebug(LOG_FILTER_GENERAL, "Creature (Entry: %u GUID: %u) charge point (X: %f Y: %f Z: %f)", _owner->GetEntry(), _owner->GetGUIDLow(), x, y, z); - Mutate(new PointMovementGenerator<Creature>(id, x, y, z, speed), MOTION_SLOT_CONTROLLED); + Mutate(new PointMovementGenerator<Creature>(id, x, y, z, generatePath, speed), MOTION_SLOT_CONTROLLED); } } +void MotionMaster::MoveCharge(PathGenerator const& path) +{ + Vector3 dest = path.GetActualEndPosition(); + + MoveCharge(dest.x, dest.y, dest.z, SPEED_CHARGE, EVENT_CHARGE_PREPATH); + + // Charge movement is not started when using EVENT_CHARGE_PREPATH + Movement::MoveSplineInit init(_owner); + init.MovebyPath(path.GetPath()); + init.SetVelocity(SPEED_CHARGE); + init.Launch(); +} + void MotionMaster::MoveSeekAssistance(float x, float y, float z) { if (_owner->GetTypeId() == TYPEID_PLAYER) @@ -546,7 +559,7 @@ void MotionMaster::Mutate(MovementGenerator *m, MovementSlot slot) else { _needInit[slot] = false; - m->Initialize(*_owner); + m->Initialize(_owner); } } @@ -614,7 +627,7 @@ MovementGeneratorType MotionMaster::GetMotionSlotType(int slot) const void MotionMaster::InitTop() { - top()->Initialize(*_owner); + top()->Initialize(_owner); _needInit[_top] = false; } @@ -622,7 +635,7 @@ void MotionMaster::DirectDelete(_Ty curr) { if (isStatic(curr)) return; - curr->Finalize(*_owner); + curr->Finalize(_owner); delete curr; } @@ -639,9 +652,9 @@ void MotionMaster::DelayedDelete(_Ty curr) bool MotionMaster::GetDestination(float &x, float &y, float &z) { if (_owner->movespline->Finalized()) - return false; + return false; - const G3D::Vector3& dest = _owner->movespline->FinalDestination(); + G3D::Vector3 const& dest = _owner->movespline->FinalDestination(); x = dest.x; y = dest.y; z = dest.z; diff --git a/src/server/game/Movement/MotionMaster.h b/src/server/game/Movement/MotionMaster.h index f6f58afef22..f2f3959dba5 100644 --- a/src/server/game/Movement/MotionMaster.h +++ b/src/server/game/Movement/MotionMaster.h @@ -26,6 +26,7 @@ class MovementGenerator; class Unit; +class PathGenerator; // Creature Entry ID used for waypoints show, visible only for GMs #define VISUAL_WAYPOINT 1 @@ -154,13 +155,14 @@ class MotionMaster //: private std::stack<MovementGenerator *> void MoveFleeing(Unit* enemy, uint32 time = 0); void MovePoint(uint32 id, const Position &pos) { MovePoint(id, pos.m_positionX, pos.m_positionY, pos.m_positionZ); } - void MovePoint(uint32 id, float x, float y, float z); + void MovePoint(uint32 id, float x, float y, float z, bool generatePath = true); // These two movement types should only be used with creatures having landing/takeoff animations void MoveLand(uint32 id, Position const& pos); void MoveTakeoff(uint32 id, Position const& pos); - void MoveCharge(float x, float y, float z, float speed = SPEED_CHARGE, uint32 id = EVENT_CHARGE); + void MoveCharge(float x, float y, float z, float speed = SPEED_CHARGE, uint32 id = EVENT_CHARGE, bool generatePath = false); + void MoveCharge(PathGenerator const& path); void MoveKnockbackFrom(float srcX, float srcY, float speedXY, float speedZ); void MoveJumpTo(float angle, float speedXY, float speedZ); void MoveJump(Position const& pos, float speedXY, float speedZ, uint32 id = EVENT_JUMP) @@ -199,4 +201,3 @@ class MotionMaster //: private std::stack<MovementGenerator *> uint8 _cleanFlag; }; #endif - diff --git a/src/server/game/Movement/MovementGenerator.h b/src/server/game/Movement/MovementGenerator.h index 1c1c38bc72f..39394a75513 100644..100755 --- a/src/server/game/Movement/MovementGenerator.h +++ b/src/server/game/Movement/MovementGenerator.h @@ -33,41 +33,47 @@ class MovementGenerator public: virtual ~MovementGenerator(); - virtual void Initialize(Unit &) = 0; - virtual void Finalize(Unit &) = 0; + virtual void Initialize(Unit*) = 0; + virtual void Finalize(Unit*) = 0; - virtual void Reset(Unit &) = 0; + virtual void Reset(Unit*) = 0; - virtual bool Update(Unit &, uint32 time_diff) = 0; + virtual bool Update(Unit*, uint32 time_diff) = 0; virtual MovementGeneratorType GetMovementGeneratorType() = 0; virtual void unitSpeedChanged() { } + + // used by Evade code for select point to evade with expected restart default movement + virtual bool GetResetPosition(Unit*, float& /*x*/, float& /*y*/, float& /*z*/) { return false; } }; template<class T, class D> class MovementGeneratorMedium : public MovementGenerator { public: - void Initialize(Unit &u) + void Initialize(Unit* u) { //u->AssertIsType<T>(); - (static_cast<D*>(this))->DoInitialize(*((T*)&u)); + (static_cast<D*>(this))->DoInitialize(static_cast<T*>(u)); } - void Finalize(Unit &u) + + void Finalize(Unit* u) { //u->AssertIsType<T>(); - (static_cast<D*>(this))->DoFinalize(*((T*)&u)); + (static_cast<D*>(this))->DoFinalize(static_cast<T*>(u)); } - void Reset(Unit &u) + + void Reset(Unit* u) { //u->AssertIsType<T>(); - (static_cast<D*>(this))->DoReset(*((T*)&u)); + (static_cast<D*>(this))->DoReset(static_cast<T*>(u)); } - bool Update(Unit &u, uint32 time_diff) + + bool Update(Unit* u, uint32 time_diff) { //u->AssertIsType<T>(); - return (static_cast<D*>(this))->DoUpdate(*((T*)&u), time_diff); + return (static_cast<D*>(this))->DoUpdate(static_cast<T*>(u), time_diff); } }; @@ -88,4 +94,3 @@ typedef FactoryHolder<MovementGenerator, MovementGeneratorType> MovementGenerato typedef FactoryHolder<MovementGenerator, MovementGeneratorType>::FactoryHolderRegistry MovementGeneratorRegistry; typedef FactoryHolder<MovementGenerator, MovementGeneratorType>::FactoryHolderRepository MovementGeneratorRepository; #endif - diff --git a/src/server/game/Movement/MovementGeneratorImpl.h b/src/server/game/Movement/MovementGeneratorImpl.h index 2618cadc14f..b77db7b5b9d 100644 --- a/src/server/game/Movement/MovementGeneratorImpl.h +++ b/src/server/game/Movement/MovementGeneratorImpl.h @@ -28,4 +28,3 @@ MovementGeneratorFactory<MOVEMENT_GEN>::Create(void * /*data*/) const return (new MOVEMENT_GEN()); } #endif - diff --git a/src/server/game/Movement/MovementGenerators/ConfusedMovementGenerator.cpp b/src/server/game/Movement/MovementGenerators/ConfusedMovementGenerator.cpp index 482c16997a0..72537f0898c 100755 --- a/src/server/game/Movement/MovementGenerators/ConfusedMovementGenerator.cpp +++ b/src/server/game/Movement/MovementGenerators/ConfusedMovementGenerator.cpp @@ -19,6 +19,7 @@ #include "Creature.h" #include "MapManager.h" #include "ConfusedMovementGenerator.h" +#include "PathGenerator.h" #include "VMapFactory.h" #include "MoveSplineInit.h" #include "MoveSpline.h" @@ -30,100 +31,44 @@ #endif template<class T> -void ConfusedMovementGenerator<T>::DoInitialize(T &unit) +void ConfusedMovementGenerator<T>::DoInitialize(T* unit) { - unit.StopMoving(); - float const wander_distance = 4; - float x = unit.GetPositionX(); - float y = unit.GetPositionY(); - float z = unit.GetPositionZ(); + unit->AddUnitState(UNIT_STATE_CONFUSED); + unit->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_CONFUSED); + unit->GetPosition(i_x, i_y, i_z); - Map const* map = unit.GetBaseMap(); + if (!unit->isAlive() || unit->IsStopped()) + return; - i_nextMove = 1; - - bool is_water_ok, is_land_ok; - _InitSpecific(unit, is_water_ok, is_land_ok); - - for (uint8 idx = 0; idx < MAX_CONF_WAYPOINTS + 1; ++idx) - { - float wanderX = x + (wander_distance * (float)rand_norm() - wander_distance/2); - float wanderY = y + (wander_distance * (float)rand_norm() - wander_distance/2); - - // prevent invalid coordinates generation - Trinity::NormalizeMapCoord(wanderX); - Trinity::NormalizeMapCoord(wanderY); - - if (unit.IsWithinLOS(wanderX, wanderY, z)) - { - bool is_water = map->IsInWater(wanderX, wanderY, z); - - if ((is_water && !is_water_ok) || (!is_water && !is_land_ok)) - { - //! Cannot use coordinates outside our InhabitType. Use the current or previous position. - wanderX = idx > 0 ? i_waypoints[idx-1][0] : x; - wanderY = idx > 0 ? i_waypoints[idx-1][1] : y; - } - } - else - { - //! Trying to access path outside line of sight. Skip this by using the current or previous position. - wanderX = idx > 0 ? i_waypoints[idx-1][0] : x; - wanderY = idx > 0 ? i_waypoints[idx-1][1] : y; - } - - unit.UpdateAllowedPositionZ(wanderX, wanderY, z); - - //! Positions are fine - apply them to this waypoint - i_waypoints[idx][0] = wanderX; - i_waypoints[idx][1] = wanderY; - i_waypoints[idx][2] = z; - } - - unit.StopMoving(); - unit.SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_CONFUSED); - unit.AddUnitState(UNIT_STATE_CONFUSED | UNIT_STATE_CONFUSED_MOVE); -} - -template<> -void ConfusedMovementGenerator<Creature>::_InitSpecific(Creature &creature, bool &is_water_ok, bool &is_land_ok) -{ - is_water_ok = creature.canSwim(); - is_land_ok = creature.canWalk(); -} - -template<> -void ConfusedMovementGenerator<Player>::_InitSpecific(Player &, bool &is_water_ok, bool &is_land_ok) -{ - is_water_ok = true; - is_land_ok = true; + unit->StopMoving(); + unit->AddUnitState(UNIT_STATE_CONFUSED_MOVE); } template<class T> -void ConfusedMovementGenerator<T>::DoReset(T &unit) +void ConfusedMovementGenerator<T>::DoReset(T* unit) { - i_nextMove = 1; i_nextMoveTime.Reset(0); - unit.StopMoving(); - unit.AddUnitState(UNIT_STATE_CONFUSED | UNIT_STATE_CONFUSED_MOVE); + + if (!unit->isAlive() || unit->IsStopped()) + return; + + unit->StopMoving(); + unit->AddUnitState(UNIT_STATE_CONFUSED | UNIT_STATE_CONFUSED_MOVE); } template<class T> -bool ConfusedMovementGenerator<T>::DoUpdate(T &unit, uint32 diff) +bool ConfusedMovementGenerator<T>::DoUpdate(T* unit, uint32 diff) { - if (unit.HasUnitState(UNIT_STATE_ROOT | UNIT_STATE_STUNNED | UNIT_STATE_DISTRACTED)) + if (unit->HasUnitState(UNIT_STATE_ROOT | UNIT_STATE_STUNNED | UNIT_STATE_DISTRACTED)) return true; if (i_nextMoveTime.Passed()) { // currently moving, update location - unit.AddUnitState(UNIT_STATE_CONFUSED_MOVE); + unit->AddUnitState(UNIT_STATE_CONFUSED_MOVE); - if (unit.movespline->Finalized()) - { - i_nextMove = urand(1, MAX_CONF_WAYPOINTS); - i_nextMoveTime.Reset(urand(500, 1200)); // Guessed - } + if (unit->movespline->Finalized()) + i_nextMoveTime.Reset(urand(800, 1500)); } else { @@ -132,14 +77,25 @@ bool ConfusedMovementGenerator<T>::DoUpdate(T &unit, uint32 diff) if (i_nextMoveTime.Passed()) { // start moving - unit.AddUnitState(UNIT_STATE_CONFUSED_MOVE); + unit->AddUnitState(UNIT_STATE_CONFUSED_MOVE); + + float dest = 4.0f * (float)rand_norm() - 2.0f; + + Position pos; + pos.Relocate(i_x, i_y, i_z); + unit->MovePositionToFirstCollision(pos, dest, 0.0f); + + PathGenerator path(unit); + path.SetPathLengthLimit(30.0f); + bool result = path.CalculatePath(pos.m_positionX, pos.m_positionY, pos.m_positionZ); + if (!result || (path.GetPathType() & PATHFIND_NOPATH)) + { + i_nextMoveTime.Reset(100); + return true; + } - ASSERT(i_nextMove <= MAX_CONF_WAYPOINTS); - float x = i_waypoints[i_nextMove][0]; - float y = i_waypoints[i_nextMove][1]; - float z = i_waypoints[i_nextMove][2]; Movement::MoveSplineInit init(unit); - init.MoveTo(x, y, z); + init.MovebyPath(path.GetPath()); init.SetWalk(true); init.Launch(); } @@ -149,25 +105,25 @@ bool ConfusedMovementGenerator<T>::DoUpdate(T &unit, uint32 diff) } template<> -void ConfusedMovementGenerator<Player>::DoFinalize(Player &unit) +void ConfusedMovementGenerator<Player>::DoFinalize(Player* unit) { - unit.RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_CONFUSED); - unit.ClearUnitState(UNIT_STATE_CONFUSED | UNIT_STATE_CONFUSED_MOVE); + unit->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_CONFUSED); + unit->ClearUnitState(UNIT_STATE_CONFUSED | UNIT_STATE_CONFUSED_MOVE); + unit->StopMoving(); } template<> -void ConfusedMovementGenerator<Creature>::DoFinalize(Creature &unit) +void ConfusedMovementGenerator<Creature>::DoFinalize(Creature* unit) { - unit.RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_CONFUSED); - unit.ClearUnitState(UNIT_STATE_CONFUSED | UNIT_STATE_CONFUSED_MOVE); - if (unit.getVictim()) - unit.SetTarget(unit.getVictim()->GetGUID()); + unit->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_CONFUSED); + unit->ClearUnitState(UNIT_STATE_CONFUSED | UNIT_STATE_CONFUSED_MOVE); + if (unit->getVictim()) + unit->SetTarget(unit->getVictim()->GetGUID()); } -template void ConfusedMovementGenerator<Player>::DoInitialize(Player &player); -template void ConfusedMovementGenerator<Creature>::DoInitialize(Creature &creature); -template void ConfusedMovementGenerator<Player>::DoReset(Player &player); -template void ConfusedMovementGenerator<Creature>::DoReset(Creature &creature); -template bool ConfusedMovementGenerator<Player>::DoUpdate(Player &player, uint32 diff); -template bool ConfusedMovementGenerator<Creature>::DoUpdate(Creature &creature, uint32 diff); - +template void ConfusedMovementGenerator<Player>::DoInitialize(Player*); +template void ConfusedMovementGenerator<Creature>::DoInitialize(Creature*); +template void ConfusedMovementGenerator<Player>::DoReset(Player*); +template void ConfusedMovementGenerator<Creature>::DoReset(Creature*); +template bool ConfusedMovementGenerator<Player>::DoUpdate(Player*, uint32 diff); +template bool ConfusedMovementGenerator<Creature>::DoUpdate(Creature*, uint32 diff); diff --git a/src/server/game/Movement/MovementGenerators/ConfusedMovementGenerator.h b/src/server/game/Movement/MovementGenerators/ConfusedMovementGenerator.h index 20e84f3a97f..da29b8aa12e 100755 --- a/src/server/game/Movement/MovementGenerators/ConfusedMovementGenerator.h +++ b/src/server/game/Movement/MovementGenerators/ConfusedMovementGenerator.h @@ -22,25 +22,20 @@ #include "MovementGenerator.h" #include "Timer.h" -#define MAX_CONF_WAYPOINTS 24 //! Allows a twelve second confusion if i_nextMove always is the absolute minimum timer. - template<class T> class ConfusedMovementGenerator : public MovementGeneratorMedium< T, ConfusedMovementGenerator<T> > { public: explicit ConfusedMovementGenerator() : i_nextMoveTime(0) {} - void DoInitialize(T &); - void DoFinalize(T &); - void DoReset(T &); - bool DoUpdate(T &, uint32); + void DoInitialize(T*); + void DoFinalize(T*); + void DoReset(T*); + bool DoUpdate(T*, uint32); MovementGeneratorType GetMovementGeneratorType() { return CONFUSED_MOTION_TYPE; } private: - void _InitSpecific(T &, bool &, bool &); TimeTracker i_nextMoveTime; - float i_waypoints[MAX_CONF_WAYPOINTS+1][3]; - uint32 i_nextMove; + float i_x, i_y, i_z; }; #endif - diff --git a/src/server/game/Movement/MovementGenerators/FleeingMovementGenerator.cpp b/src/server/game/Movement/MovementGenerators/FleeingMovementGenerator.cpp index e89d30c56f4..216fffbfee1 100755..100644 --- a/src/server/game/Movement/MovementGenerators/FleeingMovementGenerator.cpp +++ b/src/server/game/Movement/MovementGenerators/FleeingMovementGenerator.cpp @@ -20,6 +20,7 @@ #include "CreatureAI.h" #include "MapManager.h" #include "FleeingMovementGenerator.h" +#include "PathGenerator.h" #include "ObjectAccessor.h" #include "MoveSplineInit.h" #include "MoveSpline.h" @@ -29,384 +30,163 @@ #define MAX_QUIET_DISTANCE 43.0f template<class T> -void FleeingMovementGenerator<T>::_setTargetLocation(T &owner) +void FleeingMovementGenerator<T>::_setTargetLocation(T* owner) { - if (!&owner) + if (!owner) return; - if (owner.HasUnitState(UNIT_STATE_ROOT | UNIT_STATE_STUNNED)) + if (owner->HasUnitState(UNIT_STATE_ROOT | UNIT_STATE_STUNNED)) return; - if (!_setMoveData(owner)) - return; + owner->AddUnitState(UNIT_STATE_FLEEING_MOVE); float x, y, z; - if (!_getPoint(owner, x, y, z)) - return; + _getPoint(owner, x, y, z); - owner.AddUnitState(UNIT_STATE_FLEEING_MOVE); + PathGenerator path(owner); + path.SetPathLengthLimit(30.0f); + bool result = path.CalculatePath(x, y, z); + if (!result || (path.GetPathType() & PATHFIND_NOPATH)) + { + i_nextCheckTime.Reset(100); + return; + } Movement::MoveSplineInit init(owner); - init.MoveTo(x,y,z); + init.MovebyPath(path.GetPath()); init.SetWalk(false); - init.Launch(); + int32 traveltime = init.Launch(); + i_nextCheckTime.Reset(traveltime + urand(800, 1500)); } template<class T> -bool FleeingMovementGenerator<T>::_getPoint(T &owner, float &x, float &y, float &z) +void FleeingMovementGenerator<T>::_getPoint(T* owner, float &x, float &y, float &z) { - if (!&owner) - return false; - - x = owner.GetPositionX(); - y = owner.GetPositionY(); - z = owner.GetPositionZ(); - - float temp_x, temp_y, angle; - const Map* _map = owner.GetBaseMap(); - // primitive path-finding - for (uint8 i = 0; i < 18; ++i) + float dist_from_caster, angle_to_caster; + if (Unit* fright = ObjectAccessor::GetUnit(*owner, i_frightGUID)) { - if (i_only_forward && i > 2) - break; - - float distance = 5.0f; - - switch (i) - { - case 0: - angle = i_cur_angle; - break; - case 1: - angle = i_cur_angle; - distance /= 2; - break; - case 2: - angle = i_cur_angle; - distance /= 4; - break; - case 3: - angle = i_cur_angle + static_cast<float>(M_PI/4); - break; - case 4: - angle = i_cur_angle - static_cast<float>(M_PI/4); - break; - case 5: - angle = i_cur_angle + static_cast<float>(M_PI/4); - distance /= 2; - break; - case 6: - angle = i_cur_angle - static_cast<float>(M_PI/4); - distance /= 2; - break; - case 7: - angle = i_cur_angle + static_cast<float>(M_PI/2); - break; - case 8: - angle = i_cur_angle - static_cast<float>(M_PI/2); - break; - case 9: - angle = i_cur_angle + static_cast<float>(M_PI/2); - distance /= 2; - break; - case 10: - angle = i_cur_angle - static_cast<float>(M_PI/2); - distance /= 2; - break; - case 11: - angle = i_cur_angle + static_cast<float>(M_PI/4); - distance /= 4; - break; - case 12: - angle = i_cur_angle - static_cast<float>(M_PI/4); - distance /= 4; - break; - case 13: - angle = i_cur_angle + static_cast<float>(M_PI/2); - distance /= 4; - break; - case 14: - angle = i_cur_angle - static_cast<float>(M_PI/2); - distance /= 4; - break; - case 15: - angle = i_cur_angle + static_cast<float>(3*M_PI/4); - distance /= 2; - break; - case 16: - angle = i_cur_angle - static_cast<float>(3*M_PI/4); - distance /= 2; - break; - case 17: - angle = i_cur_angle + static_cast<float>(M_PI); - distance /= 2; - break; - default: - angle = 0.0f; - distance = 0.0f; - break; - } - - temp_x = x + distance * std::cos(angle); - temp_y = y + distance * std::sin(angle); - Trinity::NormalizeMapCoord(temp_x); - Trinity::NormalizeMapCoord(temp_y); - if (owner.IsWithinLOS(temp_x, temp_y, z)) - { - bool is_water_now = _map->IsInWater(x,y,z); - - if (is_water_now && _map->IsInWater(temp_x,temp_y,z)) - { - x = temp_x; - y = temp_y; - return true; - } - float new_z = _map->GetHeight(owner.GetPhaseMask(), temp_x, temp_y, z, true); - - if (new_z <= INVALID_HEIGHT) - continue; - - bool is_water_next = _map->IsInWater(temp_x, temp_y, new_z); - - if ((is_water_now && !is_water_next && !is_land_ok) || (!is_water_now && is_water_next && !is_water_ok)) - continue; - - if (!(new_z - z) || distance / fabs(new_z - z) > 1.0f) - { - float new_z_left = _map->GetHeight(owner.GetPhaseMask(), temp_x + 1.0f* std::cos(angle+static_cast<float>(M_PI/2)),temp_y + 1.0f* std::sin(angle+static_cast<float>(M_PI/2)),z,true); - float new_z_right = _map->GetHeight(owner.GetPhaseMask(), temp_x + 1.0f* std::cos(angle-static_cast<float>(M_PI/2)),temp_y + 1.0f* std::sin(angle-static_cast<float>(M_PI/2)),z,true); - if (fabs(new_z_left - new_z) < 1.2f && fabs(new_z_right - new_z) < 1.2f) - { - x = temp_x; - y = temp_y; - z = new_z; - return true; - } - } - } - } - i_to_distance_from_caster = 0.0f; - i_nextCheckTime.Reset(urand(500,1000)); - return false; -} - -template<class T> -bool FleeingMovementGenerator<T>::_setMoveData(T &owner) -{ - float cur_dist_xyz = owner.GetDistance(i_caster_x, i_caster_y, i_caster_z); - - if (i_to_distance_from_caster > 0.0f) - { - if ((i_last_distance_from_caster > i_to_distance_from_caster && cur_dist_xyz < i_to_distance_from_caster) || - // if we reach lower distance - (i_last_distance_from_caster > i_to_distance_from_caster && cur_dist_xyz > i_last_distance_from_caster) || - // if we can't be close - (i_last_distance_from_caster < i_to_distance_from_caster && cur_dist_xyz > i_to_distance_from_caster) || - // if we reach bigger distance - (cur_dist_xyz > MAX_QUIET_DISTANCE) || // if we are too far - (i_last_distance_from_caster > MIN_QUIET_DISTANCE && cur_dist_xyz < MIN_QUIET_DISTANCE)) - // if we leave 'quiet zone' - { - // we are very far or too close, stopping - i_to_distance_from_caster = 0.0f; - i_nextCheckTime.Reset(urand(500,1000)); - return false; - } + dist_from_caster = fright->GetDistance(owner); + if (dist_from_caster > 0.2f) + angle_to_caster = fright->GetAngle(owner); else - { - // now we are running, continue - i_last_distance_from_caster = cur_dist_xyz; - return true; - } - } - - float cur_dist; - float angle_to_caster; - - if (Unit* fright = ObjectAccessor::GetUnit(owner, i_frightGUID)) - { - cur_dist = fright->GetDistance(&owner); - if (cur_dist < cur_dist_xyz) - { - i_caster_x = fright->GetPositionX(); - i_caster_y = fright->GetPositionY(); - i_caster_z = fright->GetPositionZ(); - angle_to_caster = fright->GetAngle(&owner); - } - else - { - cur_dist = cur_dist_xyz; - angle_to_caster = owner.GetAngle(i_caster_x, i_caster_y) + static_cast<float>(M_PI); - } + angle_to_caster = frand(0, 2 * static_cast<float>(M_PI)); } else { - cur_dist = cur_dist_xyz; - angle_to_caster = owner.GetAngle(i_caster_x, i_caster_y) + static_cast<float>(M_PI); + dist_from_caster = 0.0f; + angle_to_caster = frand(0, 2 * static_cast<float>(M_PI)); } - // if we too close may use 'path-finding' else just stop - i_only_forward = cur_dist >= MIN_QUIET_DISTANCE/3; - - //get angle and 'distance from caster' to run - float angle; - - if (i_cur_angle == 0.0f && i_last_distance_from_caster == 0.0f) //just started, first time + float dist, angle; + if (dist_from_caster < MIN_QUIET_DISTANCE) { - angle = (float)rand_norm()*(1.0f - cur_dist/MIN_QUIET_DISTANCE) * static_cast<float>(M_PI/3) + (float)rand_norm()*static_cast<float>(M_PI*2/3); - i_to_distance_from_caster = MIN_QUIET_DISTANCE; - i_only_forward = true; + dist = frand(0.4f, 1.3f)*(MIN_QUIET_DISTANCE - dist_from_caster); + angle = angle_to_caster + frand(-static_cast<float>(M_PI)/8, static_cast<float>(M_PI)/8); } - else if (cur_dist < MIN_QUIET_DISTANCE) + else if (dist_from_caster > MAX_QUIET_DISTANCE) { - angle = static_cast<float>(M_PI/6) + (float)rand_norm()*static_cast<float>(M_PI*2/3); - i_to_distance_from_caster = cur_dist*2/3 + (float)rand_norm()*(MIN_QUIET_DISTANCE - cur_dist*2/3); + dist = frand(0.4f, 1.0f)*(MAX_QUIET_DISTANCE - MIN_QUIET_DISTANCE); + angle = -angle_to_caster + frand(-static_cast<float>(M_PI)/4, static_cast<float>(M_PI)/4); } - else if (cur_dist > MAX_QUIET_DISTANCE) + else // we are inside quiet range { - angle = (float)rand_norm()*static_cast<float>(M_PI/3) + static_cast<float>(M_PI*2/3); - i_to_distance_from_caster = MIN_QUIET_DISTANCE + 2.5f + (float)rand_norm()*(MAX_QUIET_DISTANCE - MIN_QUIET_DISTANCE - 2.5f); + dist = frand(0.6f, 1.2f)*(MAX_QUIET_DISTANCE - MIN_QUIET_DISTANCE); + angle = frand(0, 2*static_cast<float>(M_PI)); } - else - { - angle = (float)rand_norm()*static_cast<float>(M_PI); - i_to_distance_from_caster = MIN_QUIET_DISTANCE + 2.5f + (float)rand_norm()*(MAX_QUIET_DISTANCE - MIN_QUIET_DISTANCE - 2.5f); - } - - int8 sign = (float)rand_norm() > 0.5f ? 1 : -1; - i_cur_angle = sign*angle + angle_to_caster; - // current distance - i_last_distance_from_caster = cur_dist; - - return true; + Position pos; + owner->GetFirstCollisionPosition(pos, dist, angle); + x = pos.m_positionX; + y = pos.m_positionY; + z = pos.m_positionZ; } template<class T> -void FleeingMovementGenerator<T>::DoInitialize(T &owner) +void FleeingMovementGenerator<T>::DoInitialize(T* owner) { - if (!&owner) + if (!owner) return; - owner.SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_FLEEING); - owner.AddUnitState(UNIT_STATE_FLEEING|UNIT_STATE_FLEEING_MOVE); - - _Init(owner); - - if (Unit *fright = ObjectAccessor::GetUnit(owner, i_frightGUID)) - { - i_caster_x = fright->GetPositionX(); - i_caster_y = fright->GetPositionY(); - i_caster_z = fright->GetPositionZ(); - } - else - { - i_caster_x = owner.GetPositionX(); - i_caster_y = owner.GetPositionY(); - i_caster_z = owner.GetPositionZ(); - } - - i_only_forward = true; - i_cur_angle = 0.0f; - i_last_distance_from_caster = 0.0f; - i_to_distance_from_caster = 0.0f; + owner->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_FLEEING); + owner->AddUnitState(UNIT_STATE_FLEEING | UNIT_STATE_FLEEING_MOVE); _setTargetLocation(owner); } template<> -void FleeingMovementGenerator<Creature>::_Init(Creature &owner) +void FleeingMovementGenerator<Player>::DoFinalize(Player* owner) { - if (!&owner) - return; - - //owner.SetTargetGuid(ObjectGuid()); - is_water_ok = owner.canSwim(); - is_land_ok = owner.canWalk(); + owner->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_FLEEING); + owner->ClearUnitState(UNIT_STATE_FLEEING | UNIT_STATE_FLEEING_MOVE); + owner->StopMoving(); } template<> -void FleeingMovementGenerator<Player>::_Init(Player &) +void FleeingMovementGenerator<Creature>::DoFinalize(Creature* owner) { - is_water_ok = true; - is_land_ok = true; -} - -template<> -void FleeingMovementGenerator<Player>::DoFinalize(Player &owner) -{ - owner.RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_FLEEING); - owner.ClearUnitState(UNIT_STATE_FLEEING|UNIT_STATE_FLEEING_MOVE); - owner.StopMoving(); -} - -template<> -void FleeingMovementGenerator<Creature>::DoFinalize(Creature &owner) -{ - owner.RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_FLEEING); - owner.ClearUnitState(UNIT_STATE_FLEEING|UNIT_STATE_FLEEING_MOVE); - if (owner.getVictim()) - owner.SetTarget(owner.getVictim()->GetGUID()); + owner->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_FLEEING); + owner->ClearUnitState(UNIT_STATE_FLEEING|UNIT_STATE_FLEEING_MOVE); + if (owner->getVictim()) + owner->SetTarget(owner->getVictim()->GetGUID()); } template<class T> -void FleeingMovementGenerator<T>::DoReset(T &owner) +void FleeingMovementGenerator<T>::DoReset(T* owner) { DoInitialize(owner); } template<class T> -bool FleeingMovementGenerator<T>::DoUpdate(T &owner, uint32 time_diff) +bool FleeingMovementGenerator<T>::DoUpdate(T* owner, uint32 time_diff) { - if (!&owner || !owner.isAlive()) + if (!owner || !owner->isAlive()) return false; - if (owner.HasUnitState(UNIT_STATE_ROOT | UNIT_STATE_STUNNED)) + + if (owner->HasUnitState(UNIT_STATE_ROOT | UNIT_STATE_STUNNED)) { - owner.ClearUnitState(UNIT_STATE_FLEEING_MOVE); + owner->ClearUnitState(UNIT_STATE_FLEEING_MOVE); return true; } i_nextCheckTime.Update(time_diff); - if (i_nextCheckTime.Passed() && owner.movespline->Finalized()) + if (i_nextCheckTime.Passed() && owner->movespline->Finalized()) _setTargetLocation(owner); return true; } -template void FleeingMovementGenerator<Player>::DoInitialize(Player &); -template void FleeingMovementGenerator<Creature>::DoInitialize(Creature &); -template bool FleeingMovementGenerator<Player>::_setMoveData(Player &); -template bool FleeingMovementGenerator<Creature>::_setMoveData(Creature &); -template bool FleeingMovementGenerator<Player>::_getPoint(Player &, float &, float &, float &); -template bool FleeingMovementGenerator<Creature>::_getPoint(Creature &, float &, float &, float &); -template void FleeingMovementGenerator<Player>::_setTargetLocation(Player &); -template void FleeingMovementGenerator<Creature>::_setTargetLocation(Creature &); -template void FleeingMovementGenerator<Player>::DoReset(Player &); -template void FleeingMovementGenerator<Creature>::DoReset(Creature &); -template bool FleeingMovementGenerator<Player>::DoUpdate(Player &, uint32); -template bool FleeingMovementGenerator<Creature>::DoUpdate(Creature &, uint32); - -void TimedFleeingMovementGenerator::Finalize(Unit &owner) +template void FleeingMovementGenerator<Player>::DoInitialize(Player*); +template void FleeingMovementGenerator<Creature>::DoInitialize(Creature*); +template void FleeingMovementGenerator<Player>::_getPoint(Player*, float&, float&, float&); +template void FleeingMovementGenerator<Creature>::_getPoint(Creature*, float&, float&, float&); +template void FleeingMovementGenerator<Player>::_setTargetLocation(Player*); +template void FleeingMovementGenerator<Creature>::_setTargetLocation(Creature*); +template void FleeingMovementGenerator<Player>::DoReset(Player*); +template void FleeingMovementGenerator<Creature>::DoReset(Creature*); +template bool FleeingMovementGenerator<Player>::DoUpdate(Player*, uint32); +template bool FleeingMovementGenerator<Creature>::DoUpdate(Creature*, uint32); + +void TimedFleeingMovementGenerator::Finalize(Unit* owner) { - owner.RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_FLEEING); - owner.ClearUnitState(UNIT_STATE_FLEEING|UNIT_STATE_FLEEING_MOVE); - if (Unit* victim = owner.getVictim()) + owner->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_FLEEING); + owner->ClearUnitState(UNIT_STATE_FLEEING|UNIT_STATE_FLEEING_MOVE); + if (Unit* victim = owner->getVictim()) { - if (owner.isAlive()) + if (owner->isAlive()) { - owner.AttackStop(); - owner.ToCreature()->AI()->AttackStart(victim); + owner->AttackStop(); + owner->ToCreature()->AI()->AttackStart(victim); } } } -bool TimedFleeingMovementGenerator::Update(Unit & owner, uint32 time_diff) +bool TimedFleeingMovementGenerator::Update(Unit* owner, uint32 time_diff) { - if (!owner.isAlive()) + if (!owner->isAlive()) return false; - if (owner.HasUnitState(UNIT_STATE_ROOT | UNIT_STATE_STUNNED)) + if (owner->HasUnitState(UNIT_STATE_ROOT | UNIT_STATE_STUNNED)) { - owner.ClearUnitState(UNIT_STATE_FLEEING_MOVE); + owner->ClearUnitState(UNIT_STATE_FLEEING_MOVE); return true; } @@ -418,4 +198,3 @@ bool TimedFleeingMovementGenerator::Update(Unit & owner, uint32 time_diff) // This is done instead of casting Unit& to Creature& and call parent method, then we can use Unit directly return MovementGeneratorMedium< Creature, FleeingMovementGenerator<Creature> >::Update(owner, time_diff); } - diff --git a/src/server/game/Movement/MovementGenerators/FleeingMovementGenerator.h b/src/server/game/Movement/MovementGenerators/FleeingMovementGenerator.h index 8ad165c8206..33a7c705564 100755 --- a/src/server/game/Movement/MovementGenerators/FleeingMovementGenerator.h +++ b/src/server/game/Movement/MovementGenerators/FleeingMovementGenerator.h @@ -27,29 +27,17 @@ class FleeingMovementGenerator : public MovementGeneratorMedium< T, FleeingMovem public: FleeingMovementGenerator(uint64 fright) : i_frightGUID(fright), i_nextCheckTime(0) {} - void DoInitialize(T &); - void DoFinalize(T &); - void DoReset(T &); - bool DoUpdate(T &, uint32); + void DoInitialize(T*); + void DoFinalize(T*); + void DoReset(T*); + bool DoUpdate(T*, uint32); MovementGeneratorType GetMovementGeneratorType() { return FLEEING_MOTION_TYPE; } private: - void _setTargetLocation(T &owner); - bool _getPoint(T &owner, float &x, float &y, float &z); - bool _setMoveData(T &owner); - void _Init(T &); + void _setTargetLocation(T*); + void _getPoint(T*, float &x, float &y, float &z); - bool is_water_ok :1; - bool is_land_ok :1; - bool i_only_forward:1; - - float i_caster_x; - float i_caster_y; - float i_caster_z; - float i_last_distance_from_caster; - float i_to_distance_from_caster; - float i_cur_angle; uint64 i_frightGUID; TimeTracker i_nextCheckTime; }; @@ -62,12 +50,11 @@ class TimedFleeingMovementGenerator : public FleeingMovementGenerator<Creature> i_totalFleeTime(time) {} MovementGeneratorType GetMovementGeneratorType() { return TIMED_FLEEING_MOTION_TYPE; } - bool Update(Unit &, uint32); - void Finalize(Unit &); + bool Update(Unit*, uint32); + void Finalize(Unit*); private: TimeTracker i_totalFleeTime; }; #endif - diff --git a/src/server/game/Movement/MovementGenerators/HomeMovementGenerator.cpp b/src/server/game/Movement/MovementGenerators/HomeMovementGenerator.cpp index 358362c9c15..a94ef5d4f87 100644 --- a/src/server/game/Movement/MovementGenerators/HomeMovementGenerator.cpp +++ b/src/server/game/Movement/MovementGenerators/HomeMovementGenerator.cpp @@ -23,49 +23,50 @@ #include "MoveSplineInit.h" #include "MoveSpline.h" -void HomeMovementGenerator<Creature>::DoInitialize(Creature & owner) +void HomeMovementGenerator<Creature>::DoInitialize(Creature* owner) { _setTargetLocation(owner); } -void HomeMovementGenerator<Creature>::DoReset(Creature &) +void HomeMovementGenerator<Creature>::DoFinalize(Creature* owner) +{ + if (arrived) + { + owner->ClearUnitState(UNIT_STATE_EVADE); + owner->SetWalk(true); + owner->LoadCreaturesAddon(true); + owner->AI()->JustReachedHome(); + } +} + +void HomeMovementGenerator<Creature>::DoReset(Creature*) { } -void HomeMovementGenerator<Creature>::_setTargetLocation(Creature & owner) +void HomeMovementGenerator<Creature>::_setTargetLocation(Creature* owner) { - if (owner.HasUnitState(UNIT_STATE_ROOT | UNIT_STATE_STUNNED | UNIT_STATE_DISTRACTED)) + if (owner->HasUnitState(UNIT_STATE_ROOT | UNIT_STATE_STUNNED | UNIT_STATE_DISTRACTED)) return; Movement::MoveSplineInit init(owner); float x, y, z, o; // at apply we can select more nice return points base at current movegen - //if (owner.GetMotionMaster()->empty() || !owner.GetMotionMaster()->top()->GetResetPosition(owner,x,y,z)) - //{ - owner.GetHomePosition(x, y, z, o); - init.SetFacing(o); - //} - init.MoveTo(x,y,z); + if (owner->GetMotionMaster()->empty() || !owner->GetMotionMaster()->top()->GetResetPosition(owner, x, y, z)) + { + owner->GetHomePosition(x, y, z, o); + init.SetFacing(o); + } + init.MoveTo(x, y, z); init.SetWalk(false); init.Launch(); arrived = false; - owner.ClearUnitState(uint32(UNIT_STATE_ALL_STATE & ~UNIT_STATE_EVADE)); -} -bool HomeMovementGenerator<Creature>::DoUpdate(Creature &owner, const uint32 /*time_diff*/) -{ - arrived = owner.movespline->Finalized(); - return !arrived; + owner->ClearUnitState(uint32(UNIT_STATE_ALL_STATE & ~UNIT_STATE_EVADE)); } -void HomeMovementGenerator<Creature>::DoFinalize(Creature& owner) +bool HomeMovementGenerator<Creature>::DoUpdate(Creature* owner, const uint32 /*time_diff*/) { - if (arrived) - { - owner.ClearUnitState(UNIT_STATE_EVADE); - owner.SetWalk(true); - owner.LoadCreaturesAddon(true); - owner.AI()->JustReachedHome(); - } + arrived = owner->movespline->Finalized(); + return !arrived; } diff --git a/src/server/game/Movement/MovementGenerators/HomeMovementGenerator.h b/src/server/game/Movement/MovementGenerators/HomeMovementGenerator.h index c93241b82db..3d6c6ab18c9 100644 --- a/src/server/game/Movement/MovementGenerators/HomeMovementGenerator.h +++ b/src/server/game/Movement/MovementGenerators/HomeMovementGenerator.h @@ -34,15 +34,14 @@ class HomeMovementGenerator<Creature> : public MovementGeneratorMedium< Creature HomeMovementGenerator() : arrived(false) {} ~HomeMovementGenerator() {} - void DoInitialize(Creature &); - void DoFinalize(Creature &); - void DoReset(Creature &); - bool DoUpdate(Creature &, const uint32); + void DoInitialize(Creature*); + void DoFinalize(Creature*); + void DoReset(Creature*); + bool DoUpdate(Creature*, const uint32); MovementGeneratorType GetMovementGeneratorType() { return HOME_MOTION_TYPE; } private: - void _setTargetLocation(Creature &); + void _setTargetLocation(Creature*); bool arrived; }; #endif - diff --git a/src/server/game/Movement/MovementGenerators/IdleMovementGenerator.cpp b/src/server/game/Movement/MovementGenerators/IdleMovementGenerator.cpp index c952ad9ba94..81442570940 100755 --- a/src/server/game/Movement/MovementGenerators/IdleMovementGenerator.cpp +++ b/src/server/game/Movement/MovementGenerators/IdleMovementGenerator.cpp @@ -24,33 +24,33 @@ IdleMovementGenerator si_idleMovement; // StopMoving is needed to make unit stop if its last movement generator expires // But it should not be sent otherwise there are many redundent packets -void IdleMovementGenerator::Initialize(Unit &owner) +void IdleMovementGenerator::Initialize(Unit* owner) { Reset(owner); } -void IdleMovementGenerator::Reset(Unit& owner) +void IdleMovementGenerator::Reset(Unit* owner) { - if (!owner.IsStopped()) - owner.StopMoving(); + if (!owner->IsStopped()) + owner->StopMoving(); } -void RotateMovementGenerator::Initialize(Unit& owner) +void RotateMovementGenerator::Initialize(Unit* owner) { - if (!owner.IsStopped()) - owner.StopMoving(); + if (!owner->IsStopped()) + owner->StopMoving(); - if (owner.getVictim()) - owner.SetInFront(owner.getVictim()); + if (owner->getVictim()) + owner->SetInFront(owner->getVictim()); - owner.AddUnitState(UNIT_STATE_ROTATING); + owner->AddUnitState(UNIT_STATE_ROTATING); - owner.AttackStop(); + owner->AttackStop(); } -bool RotateMovementGenerator::Update(Unit& owner, uint32 diff) +bool RotateMovementGenerator::Update(Unit* owner, uint32 diff) { - float angle = owner.GetOrientation(); + float angle = owner->GetOrientation(); if (m_direction == ROTATE_DIRECTION_LEFT) { angle += (float)diff * static_cast<float>(M_PI * 2) / m_maxDuration; @@ -61,8 +61,8 @@ bool RotateMovementGenerator::Update(Unit& owner, uint32 diff) angle -= (float)diff * static_cast<float>(M_PI * 2) / m_maxDuration; while (angle < 0) angle += static_cast<float>(M_PI * 2); } - owner.SetOrientation(angle); - owner.SendMovementFlagUpdate(); // this is a hack. we do not have anything correct to send in the beginning + owner->SetOrientation(angle); + owner->SendMovementFlagUpdate(); // this is a hack. we do not have anything correct to send in the beginning if (m_duration > diff) m_duration -= diff; @@ -72,24 +72,24 @@ bool RotateMovementGenerator::Update(Unit& owner, uint32 diff) return true; } -void RotateMovementGenerator::Finalize(Unit &unit) +void RotateMovementGenerator::Finalize(Unit* unit) { - unit.ClearUnitState(UNIT_STATE_ROTATING); - if (unit.GetTypeId() == TYPEID_UNIT) - unit.ToCreature()->AI()->MovementInform(ROTATE_MOTION_TYPE, 0); + unit->ClearUnitState(UNIT_STATE_ROTATING); + if (unit->GetTypeId() == TYPEID_UNIT) + unit->ToCreature()->AI()->MovementInform(ROTATE_MOTION_TYPE, 0); } -void DistractMovementGenerator::Initialize(Unit& owner) +void DistractMovementGenerator::Initialize(Unit* owner) { - owner.AddUnitState(UNIT_STATE_DISTRACTED); + owner->AddUnitState(UNIT_STATE_DISTRACTED); } -void DistractMovementGenerator::Finalize(Unit& owner) +void DistractMovementGenerator::Finalize(Unit* owner) { - owner.ClearUnitState(UNIT_STATE_DISTRACTED); + owner->ClearUnitState(UNIT_STATE_DISTRACTED); } -bool DistractMovementGenerator::Update(Unit& /*owner*/, uint32 time_diff) +bool DistractMovementGenerator::Update(Unit* /*owner*/, uint32 time_diff) { if (time_diff > m_timer) return false; @@ -98,9 +98,8 @@ bool DistractMovementGenerator::Update(Unit& /*owner*/, uint32 time_diff) return true; } -void AssistanceDistractMovementGenerator::Finalize(Unit &unit) +void AssistanceDistractMovementGenerator::Finalize(Unit* unit) { - unit.ClearUnitState(UNIT_STATE_DISTRACTED); - unit.ToCreature()->SetReactState(REACT_AGGRESSIVE); + unit->ClearUnitState(UNIT_STATE_DISTRACTED); + unit->ToCreature()->SetReactState(REACT_AGGRESSIVE); } - diff --git a/src/server/game/Movement/MovementGenerators/IdleMovementGenerator.h b/src/server/game/Movement/MovementGenerators/IdleMovementGenerator.h index bbcc2413cae..0043891db2c 100644..100755 --- a/src/server/game/Movement/MovementGenerators/IdleMovementGenerator.h +++ b/src/server/game/Movement/MovementGenerators/IdleMovementGenerator.h @@ -25,10 +25,10 @@ class IdleMovementGenerator : public MovementGenerator { public: - void Initialize(Unit &); - void Finalize(Unit &) { } - void Reset(Unit &); - bool Update(Unit &, uint32) { return true; } + void Initialize(Unit*); + void Finalize(Unit*) { } + void Reset(Unit*); + bool Update(Unit*, uint32) { return true; } MovementGeneratorType GetMovementGeneratorType() { return IDLE_MOTION_TYPE; } }; @@ -39,10 +39,10 @@ class RotateMovementGenerator : public MovementGenerator public: explicit RotateMovementGenerator(uint32 time, RotateDirection direction) : m_duration(time), m_maxDuration(time), m_direction(direction) {} - void Initialize(Unit& owner); - void Finalize(Unit& owner); - void Reset(Unit& owner) { Initialize(owner); } - bool Update(Unit& owner, uint32 time_diff); + void Initialize(Unit*); + void Finalize(Unit*); + void Reset(Unit* owner) { Initialize(owner); } + bool Update(Unit*, uint32); MovementGeneratorType GetMovementGeneratorType() { return ROTATE_MOTION_TYPE; } private: @@ -55,10 +55,10 @@ class DistractMovementGenerator : public MovementGenerator public: explicit DistractMovementGenerator(uint32 timer) : m_timer(timer) {} - void Initialize(Unit& owner); - void Finalize(Unit& owner); - void Reset(Unit& owner) { Initialize(owner); } - bool Update(Unit& owner, uint32 time_diff); + void Initialize(Unit*); + void Finalize(Unit*); + void Reset(Unit* owner) { Initialize(owner); } + bool Update(Unit*, uint32); MovementGeneratorType GetMovementGeneratorType() { return DISTRACT_MOTION_TYPE; } private: @@ -72,8 +72,7 @@ class AssistanceDistractMovementGenerator : public DistractMovementGenerator DistractMovementGenerator(timer) {} MovementGeneratorType GetMovementGeneratorType() { return ASSISTANCE_DISTRACT_MOTION_TYPE; } - void Finalize(Unit& unit); + void Finalize(Unit*); }; #endif - diff --git a/src/server/game/Movement/MovementGenerators/PointMovementGenerator.cpp b/src/server/game/Movement/MovementGenerators/PointMovementGenerator.cpp index 59c41d841f2..ea7a8c4c710 100644..100755 --- a/src/server/game/Movement/MovementGenerators/PointMovementGenerator.cpp +++ b/src/server/game/Movement/MovementGenerators/PointMovementGenerator.cpp @@ -27,111 +27,116 @@ //----- Point Movement Generator template<class T> -void PointMovementGenerator<T>::DoInitialize(T &unit) +void PointMovementGenerator<T>::DoInitialize(T* unit) { - if (!unit.IsStopped()) - unit.StopMoving(); + if (!unit->IsStopped()) + unit->StopMoving(); + + unit->AddUnitState(UNIT_STATE_ROAMING|UNIT_STATE_ROAMING_MOVE); + + if (id == EVENT_CHARGE_PREPATH) + return; - unit.AddUnitState(UNIT_STATE_ROAMING|UNIT_STATE_ROAMING_MOVE); - i_recalculateSpeed = false; Movement::MoveSplineInit init(unit); - init.MoveTo(i_x, i_y, i_z); + init.MoveTo(i_x, i_y, i_z, m_generatePath); if (speed > 0.0f) init.SetVelocity(speed); init.Launch(); } template<class T> -bool PointMovementGenerator<T>::DoUpdate(T &unit, uint32 /*diff*/) +bool PointMovementGenerator<T>::DoUpdate(T* unit, uint32 /*diff*/) { - if (!&unit) + if (!unit) return false; - if (unit.HasUnitState(UNIT_STATE_ROOT | UNIT_STATE_STUNNED)) + if (unit->HasUnitState(UNIT_STATE_ROOT | UNIT_STATE_STUNNED)) { - unit.ClearUnitState(UNIT_STATE_ROAMING_MOVE); + unit->ClearUnitState(UNIT_STATE_ROAMING_MOVE); return true; } - unit.AddUnitState(UNIT_STATE_ROAMING_MOVE); + unit->AddUnitState(UNIT_STATE_ROAMING_MOVE); - if (i_recalculateSpeed && !unit.movespline->Finalized()) + if (id != EVENT_CHARGE_PREPATH && i_recalculateSpeed && !unit->movespline->Finalized()) { i_recalculateSpeed = false; Movement::MoveSplineInit init(unit); - init.MoveTo(i_x, i_y, i_z); + init.MoveTo(i_x, i_y, i_z, m_generatePath); if (speed > 0.0f) // Default value for point motion type is 0.0, if 0.0 spline will use GetSpeed on unit init.SetVelocity(speed); init.Launch(); } - return !unit.movespline->Finalized(); + return !unit->movespline->Finalized(); } template<class T> -void PointMovementGenerator<T>::DoFinalize(T &unit) +void PointMovementGenerator<T>::DoFinalize(T* unit) { - unit.ClearUnitState(UNIT_STATE_ROAMING|UNIT_STATE_ROAMING_MOVE); + if (unit->HasUnitState(UNIT_STATE_CHARGING)) + unit->ClearUnitState(UNIT_STATE_ROAMING | UNIT_STATE_ROAMING_MOVE); - if (unit.movespline->Finalized()) + if (unit->movespline->Finalized()) MovementInform(unit); } template<class T> -void PointMovementGenerator<T>::DoReset(T &unit) +void PointMovementGenerator<T>::DoReset(T* unit) { - if (!unit.IsStopped()) - unit.StopMoving(); + if (!unit->IsStopped()) + unit->StopMoving(); - unit.AddUnitState(UNIT_STATE_ROAMING|UNIT_STATE_ROAMING_MOVE); + unit->AddUnitState(UNIT_STATE_ROAMING|UNIT_STATE_ROAMING_MOVE); } template<class T> -void PointMovementGenerator<T>::MovementInform(T & /*unit*/) +void PointMovementGenerator<T>::MovementInform(T* /*unit*/) { } -template <> void PointMovementGenerator<Creature>::MovementInform(Creature &unit) +template <> void PointMovementGenerator<Creature>::MovementInform(Creature* unit) { - if (unit.AI()) - unit.AI()->MovementInform(POINT_MOTION_TYPE, id); + if (unit->AI()) + unit->AI()->MovementInform(POINT_MOTION_TYPE, id); } -template void PointMovementGenerator<Player>::DoInitialize(Player&); -template void PointMovementGenerator<Creature>::DoInitialize(Creature&); -template void PointMovementGenerator<Player>::DoFinalize(Player&); -template void PointMovementGenerator<Creature>::DoFinalize(Creature&); -template void PointMovementGenerator<Player>::DoReset(Player&); -template void PointMovementGenerator<Creature>::DoReset(Creature&); -template bool PointMovementGenerator<Player>::DoUpdate(Player &, uint32); -template bool PointMovementGenerator<Creature>::DoUpdate(Creature&, uint32); +template void PointMovementGenerator<Player>::DoInitialize(Player*); +template void PointMovementGenerator<Creature>::DoInitialize(Creature*); +template void PointMovementGenerator<Player>::DoFinalize(Player*); +template void PointMovementGenerator<Creature>::DoFinalize(Creature*); +template void PointMovementGenerator<Player>::DoReset(Player*); +template void PointMovementGenerator<Creature>::DoReset(Creature*); +template bool PointMovementGenerator<Player>::DoUpdate(Player*, uint32); +template bool PointMovementGenerator<Creature>::DoUpdate(Creature*, uint32); -void AssistanceMovementGenerator::Finalize(Unit &unit) +void AssistanceMovementGenerator::Finalize(Unit* unit) { - unit.ToCreature()->SetNoCallAssistance(false); - unit.ToCreature()->CallAssistance(); - if (unit.isAlive()) - unit.GetMotionMaster()->MoveSeekAssistanceDistract(sWorld->getIntConfig(CONFIG_CREATURE_FAMILY_ASSISTANCE_DELAY)); + unit->ToCreature()->SetNoCallAssistance(false); + unit->ToCreature()->CallAssistance(); + if (unit->isAlive()) + unit->GetMotionMaster()->MoveSeekAssistanceDistract(sWorld->getIntConfig(CONFIG_CREATURE_FAMILY_ASSISTANCE_DELAY)); } -bool EffectMovementGenerator::Update(Unit &unit, uint32) +bool EffectMovementGenerator::Update(Unit* unit, uint32) { - return !unit.movespline->Finalized(); + return !unit->movespline->Finalized(); } -void EffectMovementGenerator::Finalize(Unit &unit) +void EffectMovementGenerator::Finalize(Unit* unit) { - if (unit.GetTypeId() != TYPEID_UNIT) + if (unit->GetTypeId() != TYPEID_UNIT) return; - if (((Creature&)unit).AI()) - ((Creature&)unit).AI()->MovementInform(EFFECT_MOTION_TYPE, m_Id); // Need restore previous movement since we have no proper states system - //if (unit.isAlive() && !unit.HasUnitState(UNIT_STATE_CONFUSED|UNIT_STATE_FLEEING)) - //{ - // if (Unit * victim = unit.getVictim()) - // unit.GetMotionMaster()->MoveChase(victim); - // else - // unit.GetMotionMaster()->Initialize(); - //} + if (unit->isAlive() && !unit->HasUnitState(UNIT_STATE_CONFUSED | UNIT_STATE_FLEEING)) + { + if (Unit* victim = unit->getVictim()) + unit->GetMotionMaster()->MoveChase(victim); + else + unit->GetMotionMaster()->Initialize(); + } + + if (unit->ToCreature()->AI()) + unit->ToCreature()->AI()->MovementInform(EFFECT_MOTION_TYPE, m_Id); } diff --git a/src/server/game/Movement/MovementGenerators/PointMovementGenerator.h b/src/server/game/Movement/MovementGenerators/PointMovementGenerator.h index f9a51d0c5f3..421736ca4ec 100644 --- a/src/server/game/Movement/MovementGenerators/PointMovementGenerator.h +++ b/src/server/game/Movement/MovementGenerators/PointMovementGenerator.h @@ -26,25 +26,26 @@ template<class T> class PointMovementGenerator : public MovementGeneratorMedium< T, PointMovementGenerator<T> > { public: - PointMovementGenerator(uint32 _id, float _x, float _y, float _z, float _speed = 0.0f) : id(_id), - i_x(_x), i_y(_y), i_z(_z), speed(_speed) {} + PointMovementGenerator(uint32 _id, float _x, float _y, float _z, bool _generatePath, float _speed = 0.0f) : id(_id), + i_x(_x), i_y(_y), i_z(_z), speed(_speed), m_generatePath(_generatePath), i_recalculateSpeed(false) {} - void DoInitialize(T &); - void DoFinalize(T &); - void DoReset(T &); - bool DoUpdate(T &, uint32); + void DoInitialize(T*); + void DoFinalize(T*); + void DoReset(T*); + bool DoUpdate(T*, uint32); - void MovementInform(T &); + void MovementInform(T*); void unitSpeedChanged() { i_recalculateSpeed = true; } MovementGeneratorType GetMovementGeneratorType() { return POINT_MOTION_TYPE; } - bool GetDestination(float& x, float& y, float& z) const { x=i_x; y=i_y; z=i_z; return true; } + void GetDestination(float& x, float& y, float& z) const { x = i_x; y = i_y; z = i_z; } private: uint32 id; float i_x, i_y, i_z; float speed; + bool m_generatePath; bool i_recalculateSpeed; }; @@ -52,10 +53,10 @@ class AssistanceMovementGenerator : public PointMovementGenerator<Creature> { public: AssistanceMovementGenerator(float _x, float _y, float _z) : - PointMovementGenerator<Creature>(0, _x, _y, _z) {} + PointMovementGenerator<Creature>(0, _x, _y, _z, true) {} MovementGeneratorType GetMovementGeneratorType() { return ASSISTANCE_MOTION_TYPE; } - void Finalize(Unit &); + void Finalize(Unit*); }; // Does almost nothing - just doesn't allows previous movegen interrupt current effect. @@ -63,14 +64,13 @@ class EffectMovementGenerator : public MovementGenerator { public: explicit EffectMovementGenerator(uint32 Id) : m_Id(Id) {} - void Initialize(Unit &) {} - void Finalize(Unit &unit); - void Reset(Unit &) {} - bool Update(Unit &u, uint32); + void Initialize(Unit*) {} + void Finalize(Unit*); + void Reset(Unit*) {} + bool Update(Unit*, uint32); MovementGeneratorType GetMovementGeneratorType() { return EFFECT_MOTION_TYPE; } private: uint32 m_Id; }; #endif - diff --git a/src/server/game/Movement/MovementGenerators/RandomMovementGenerator.cpp b/src/server/game/Movement/MovementGenerators/RandomMovementGenerator.cpp index f733fa3331c..723b0748494 100644 --- a/src/server/game/Movement/MovementGenerators/RandomMovementGenerator.cpp +++ b/src/server/game/Movement/MovementGenerators/RandomMovementGenerator.cpp @@ -33,16 +33,16 @@ #endif template<> -void RandomMovementGenerator<Creature>::_setRandomLocation(Creature& creature) +void RandomMovementGenerator<Creature>::_setRandomLocation(Creature* creature) { float respX, respY, respZ, respO, destX, destY, destZ, travelDistZ; - creature.GetHomePosition(respX, respY, respZ, respO); - Map const* map = creature.GetBaseMap(); + creature->GetHomePosition(respX, respY, respZ, respO); + Map const* map = creature->GetBaseMap(); // For 2D/3D system selection //bool is_land_ok = creature.CanWalk(); // not used? //bool is_water_ok = creature.CanSwim(); // not used? - bool is_air_ok = creature.CanFly(); + bool is_air_ok = creature->CanFly(); const float angle = float(rand_norm()) * static_cast<float>(M_PI*2.0f); const float range = float(rand_norm()) * wander_distance; @@ -77,17 +77,17 @@ void RandomMovementGenerator<Creature>::_setRandomLocation(Creature& creature) // The fastest way to get an accurate result 90% of the time. // Better result can be obtained like 99% accuracy with a ray light, but the cost is too high and the code is too long. - destZ = map->GetHeight(creature.GetPhaseMask(), destX, destY, respZ+travelDistZ-2.0f, false); + destZ = map->GetHeight(creature->GetPhaseMask(), destX, destY, respZ+travelDistZ-2.0f, false); if (fabs(destZ - respZ) > travelDistZ) // Map check { // Vmap Horizontal or above - destZ = map->GetHeight(creature.GetPhaseMask(), destX, destY, respZ - 2.0f, true); + destZ = map->GetHeight(creature->GetPhaseMask(), destX, destY, respZ - 2.0f, true); if (fabs(destZ - respZ) > travelDistZ) { // Vmap Higher - destZ = map->GetHeight(creature.GetPhaseMask(), destX, destY, respZ+travelDistZ-2.0f, true); + destZ = map->GetHeight(creature->GetPhaseMask(), destX, destY, respZ+travelDistZ-2.0f, true); // let's forget this bad coords where a z cannot be find and retry at next tick if (fabs(destZ - respZ) > travelDistZ) @@ -101,7 +101,7 @@ void RandomMovementGenerator<Creature>::_setRandomLocation(Creature& creature) else i_nextMoveTime.Reset(urand(500, 10000)); - creature.AddUnitState(UNIT_STATE_ROAMING_MOVE); + creature->AddUnitState(UNIT_STATE_ROAMING_MOVE); Movement::MoveSplineInit init(creature); init.MoveTo(destX, destY, destZ); @@ -109,47 +109,47 @@ void RandomMovementGenerator<Creature>::_setRandomLocation(Creature& creature) init.Launch(); //Call for creature group update - if (creature.GetFormation() && creature.GetFormation()->getLeader() == &creature) - creature.GetFormation()->LeaderMoveTo(destX, destY, destZ); + if (creature->GetFormation() && creature->GetFormation()->getLeader() == creature) + creature->GetFormation()->LeaderMoveTo(destX, destY, destZ); } template<> -void RandomMovementGenerator<Creature>::DoInitialize(Creature &creature) +void RandomMovementGenerator<Creature>::DoInitialize(Creature* creature) { - if (!creature.isAlive()) + if (!creature->isAlive()) return; if (!wander_distance) - wander_distance = creature.GetRespawnRadius(); + wander_distance = creature->GetRespawnRadius(); - creature.AddUnitState(UNIT_STATE_ROAMING|UNIT_STATE_ROAMING_MOVE); + creature->AddUnitState(UNIT_STATE_ROAMING | UNIT_STATE_ROAMING_MOVE); _setRandomLocation(creature); } template<> -void RandomMovementGenerator<Creature>::DoReset(Creature &creature) +void RandomMovementGenerator<Creature>::DoReset(Creature* creature) { DoInitialize(creature); } template<> -void RandomMovementGenerator<Creature>::DoFinalize(Creature &creature) +void RandomMovementGenerator<Creature>::DoFinalize(Creature* creature) { - creature.ClearUnitState(UNIT_STATE_ROAMING|UNIT_STATE_ROAMING_MOVE); - creature.SetWalk(false); + creature->ClearUnitState(UNIT_STATE_ROAMING|UNIT_STATE_ROAMING_MOVE); + creature->SetWalk(false); } template<> -bool RandomMovementGenerator<Creature>::DoUpdate(Creature &creature, const uint32 diff) +bool RandomMovementGenerator<Creature>::DoUpdate(Creature* creature, const uint32 diff) { - if (creature.HasUnitState(UNIT_STATE_ROOT | UNIT_STATE_STUNNED | UNIT_STATE_DISTRACTED)) + if (creature->HasUnitState(UNIT_STATE_ROOT | UNIT_STATE_STUNNED | UNIT_STATE_DISTRACTED)) { i_nextMoveTime.Reset(0); // Expire the timer - creature.ClearUnitState(UNIT_STATE_ROAMING_MOVE); + creature->ClearUnitState(UNIT_STATE_ROAMING_MOVE); return true; } - if (creature.movespline->Finalized()) + if (creature->movespline->Finalized()) { i_nextMoveTime.Update(diff); if (i_nextMoveTime.Passed()) @@ -159,14 +159,14 @@ bool RandomMovementGenerator<Creature>::DoUpdate(Creature &creature, const uint3 } template<> -bool RandomMovementGenerator<Creature>::GetResetPosition(Creature &creature, float& x, float& y, float& z) +bool RandomMovementGenerator<Creature>::GetResetPos(Creature* creature, float& x, float& y, float& z) { float radius; - creature.GetRespawnPosition(x, y, z, NULL, &radius); + creature->GetRespawnPosition(x, y, z, NULL, &radius); // use current if in range - if (creature.IsWithinDist2d(x,y,radius)) - creature.GetPosition(x,y,z); + if (creature->IsWithinDist2d(x, y, radius)) + creature->GetPosition(x, y, z); return true; } diff --git a/src/server/game/Movement/MovementGenerators/RandomMovementGenerator.h b/src/server/game/Movement/MovementGenerators/RandomMovementGenerator.h index 3e74753bc91..a6159e995fe 100644 --- a/src/server/game/Movement/MovementGenerators/RandomMovementGenerator.h +++ b/src/server/game/Movement/MovementGenerators/RandomMovementGenerator.h @@ -27,12 +27,12 @@ class RandomMovementGenerator : public MovementGeneratorMedium< T, RandomMovemen public: RandomMovementGenerator(float spawn_dist = 0.0f) : i_nextMoveTime(0), wander_distance(spawn_dist) {} - void _setRandomLocation(T &); - void DoInitialize(T &); - void DoFinalize(T &); - void DoReset(T &); - bool DoUpdate(T &, const uint32); - bool GetResetPosition(T&, float& x, float& y, float& z); + void _setRandomLocation(T*); + void DoInitialize(T*); + void DoFinalize(T*); + void DoReset(T*); + bool DoUpdate(T*, const uint32); + bool GetResetPos(T*, float& x, float& y, float& z); MovementGeneratorType GetMovementGeneratorType() { return RANDOM_MOTION_TYPE; } private: TimeTrackerSmall i_nextMoveTime; @@ -41,4 +41,3 @@ class RandomMovementGenerator : public MovementGeneratorMedium< T, RandomMovemen float wander_distance; }; #endif - diff --git a/src/server/game/Movement/MovementGenerators/TargetedMovementGenerator.cpp b/src/server/game/Movement/MovementGenerators/TargetedMovementGenerator.cpp index ebcb830cf61..abb4ac9964b 100755..100644 --- a/src/server/game/Movement/MovementGenerators/TargetedMovementGenerator.cpp +++ b/src/server/game/Movement/MovementGenerators/TargetedMovementGenerator.cpp @@ -26,140 +26,116 @@ #include "MoveSpline.h" #include "Player.h" -#include <cmath> - template<class T, typename D> -void TargetedMovementGeneratorMedium<T,D>::_setTargetLocation(T &owner) +void TargetedMovementGeneratorMedium<T,D>::_setTargetLocation(T* owner, bool updateDestination) { if (!i_target.isValid() || !i_target->IsInWorld()) return; - if (owner.HasUnitState(UNIT_STATE_NOT_MOVE)) + if (owner->HasUnitState(UNIT_STATE_NOT_MOVE)) + return; + + if (owner->GetTypeId() == TYPEID_UNIT && !i_target->isInAccessiblePlaceFor(owner->ToCreature())) return; float x, y, z; - //! Following block of code deleted by MrSmite in issue 4891 - //! Code kept for learning and diagnostical purposes -// -// if (i_offset && i_target->IsWithinDistInMap(&owner,2*i_offset)) -// { -// if (!owner.movespline->Finalized()) -// return; -// -// owner.GetPosition(x, y, z); -// } -// else - if (!i_offset) - { - if (i_target->IsWithinMeleeRange(&owner)) - return; - // to nearest random contact position - i_target->GetRandomContactPoint(&owner, x, y, z, 0, MELEE_RANGE - 0.5f); - } - else + if (updateDestination || !i_path) { - float dist; - float size; - - // Pets need special handling. - // We need to subtract GetObjectSize() because it gets added back further down the chain - // and that makes pets too far away. Subtracting it allows pets to properly - // be (GetCombatReach() + i_offset) away. - // Only applies when i_target is pet's owner otherwise pets and mobs end up - // doing a "dance" while fighting - if (owner.isPet() && i_target->GetTypeId() == TYPEID_PLAYER) + if (!i_offset) { - dist = i_target->GetCombatReach(); - size = i_target->GetCombatReach() - i_target->GetObjectSize(); + // to nearest contact position + i_target->GetContactPoint(owner, x, y, z); } else { - dist = i_offset + 1.0f; - size = owner.GetObjectSize(); + float dist; + float size; + + // Pets need special handling. + // We need to subtract GetObjectSize() because it gets added back further down the chain + // and that makes pets too far away. Subtracting it allows pets to properly + // be (GetCombatReach() + i_offset) away. + // Only applies when i_target is pet's owner otherwise pets and mobs end up + // doing a "dance" while fighting + if (owner->isPet() && i_target->GetTypeId() == TYPEID_PLAYER) + { + dist = i_target->GetCombatReach(); + size = i_target->GetCombatReach() - i_target->GetObjectSize(); + } + else + { + dist = i_offset + 1.0f; + size = owner->GetObjectSize(); + } + + if (i_target->IsWithinDistInMap(owner, dist)) + return; + + // to at i_offset distance from target and i_angle from target facing + i_target->GetClosePoint(x, y, z, size, i_offset, i_angle); } - - if (i_target->IsWithinDistInMap(&owner, dist)) - return; - - // to at i_offset distance from target and i_angle from target facing - i_target->GetClosePoint(x, y, z, size, i_offset, i_angle); + } + else + { + // the destination has not changed, we just need to refresh the path (usually speed change) + G3D::Vector3 end = i_path->GetEndPosition(); + x = end.x; + y = end.y; + z = end.z; } - /* - We MUST not check the distance difference and avoid setting the new location for smaller distances. - By that we risk having far too many GetContactPoint() calls freezing the whole system. - In TargetedMovementGenerator<T>::Update() we check the distance to the target and at - some range we calculate a new position. The calculation takes some processor cycles due to vmaps. - If the distance to the target it too large to ignore, - but the distance to the new contact point is short enough to be ignored, - we will calculate a new contact point each update loop, but will never move to it. - The system will freeze. - ralf + if (!i_path) + i_path = new PathGenerator(owner); - //We don't update Mob Movement, if the difference between New destination and last destination is < BothObjectSize - float bothObjectSize = i_target->GetObjectBoundingRadius() + owner.GetObjectBoundingRadius() + CONTACT_DISTANCE; - if ( i_destinationHolder.HasDestination() && i_destinationHolder.GetDestinationDiff(x,y,z) < bothObjectSize ) - return; - */ + // allow pets to use shortcut if no path found when following their master + bool forceDest = (owner->GetTypeId() == TYPEID_UNIT && owner->ToCreature()->isPet() + && owner->HasUnitState(UNIT_STATE_FOLLOW)); + bool result = i_path->CalculatePath(x, y, z, forceDest); + if (!result || (i_path->GetPathType() & PATHFIND_NOPATH)) + { + // Cant reach target + i_recalculateTravel = true; + return; + } D::_addUnitStateMove(owner); i_targetReached = false; i_recalculateTravel = false; + owner->AddUnitState(UNIT_STATE_CHASE); Movement::MoveSplineInit init(owner); - init.MoveTo(x,y,z); + init.MovebyPath(i_path->GetPath()); init.SetWalk(((D*)this)->EnableWalking()); - init.Launch(); -} - -template<> -void TargetedMovementGeneratorMedium<Player,ChaseMovementGenerator<Player> >::UpdateFinalDistance(float /*fDistance*/) -{ - // nothing to do for Player -} + // Using the same condition for facing target as the one that is used for SetInFront on movement end + // - applies to ChaseMovementGenerator mostly + if (i_angle == 0.f) + init.SetFacing(i_target.getTarget()); -template<> -void TargetedMovementGeneratorMedium<Player,FollowMovementGenerator<Player> >::UpdateFinalDistance(float /*fDistance*/) -{ - // nothing to do for Player -} - -template<> -void TargetedMovementGeneratorMedium<Creature,ChaseMovementGenerator<Creature> >::UpdateFinalDistance(float fDistance) -{ - i_offset = fDistance; - i_recalculateTravel = true; -} - -template<> -void TargetedMovementGeneratorMedium<Creature,FollowMovementGenerator<Creature> >::UpdateFinalDistance(float fDistance) -{ - i_offset = fDistance; - i_recalculateTravel = true; + init.Launch(); } template<class T, typename D> -bool TargetedMovementGeneratorMedium<T,D>::DoUpdate(T &owner, uint32 time_diff) +bool TargetedMovementGeneratorMedium<T,D>::DoUpdate(T* owner, uint32 time_diff) { if (!i_target.isValid() || !i_target->IsInWorld()) return false; - if (!owner.isAlive()) - return true; + if (!owner || !owner->isAlive()) + return false; - if (owner.HasUnitState(UNIT_STATE_NOT_MOVE)) + if (owner->HasUnitState(UNIT_STATE_NOT_MOVE)) { D::_clearUnitStateMove(owner); return true; } // prevent movement while casting spells with cast time or channel time - if (owner.HasUnitState(UNIT_STATE_CASTING)) + if (owner->HasUnitState(UNIT_STATE_CASTING)) { - if (!owner.IsStopped()) - owner.StopMoving(); + if (!owner->IsStopped()) + owner->StopMoving(); return true; } @@ -170,22 +146,29 @@ bool TargetedMovementGeneratorMedium<T,D>::DoUpdate(T &owner, uint32 time_diff) return true; } + bool targetMoved = false; i_recheckDistance.Update(time_diff); if (i_recheckDistance.Passed()) { - i_recheckDistance.Reset(50); + i_recheckDistance.Reset(100); //More distance let have better performance, less distance let have more sensitive reaction at target move. - float allowed_dist = i_target->GetObjectSize() + owner.GetObjectSize() + MELEE_RANGE - 0.5f; - float dist = (owner.movespline->FinalDestination() - G3D::Vector3(i_target->GetPositionX(),i_target->GetPositionY(),i_target->GetPositionZ())).squaredLength(); - if (dist >= allowed_dist * allowed_dist) - _setTargetLocation(owner); + float allowed_dist = owner->GetCombatReach() + sWorld->getRate(RATE_TARGET_POS_RECALCULATION_RANGE); + G3D::Vector3 dest = owner->movespline->FinalDestination(); + + if (owner->GetTypeId() == TYPEID_UNIT && owner->ToCreature()->CanFly()) + targetMoved = !i_target->IsWithinDist3d(dest.x, dest.y, dest.z, allowed_dist); + else + targetMoved = !i_target->IsWithinDist2d(dest.x, dest.y, allowed_dist); } - if (owner.movespline->Finalized()) + if (i_recalculateTravel || targetMoved) + _setTargetLocation(owner, targetMoved); + + if (owner->movespline->Finalized()) { static_cast<D*>(this)->MovementInform(owner); - if (i_angle == 0.f && !owner.HasInArc(0.01f, i_target.getTarget())) - owner.SetInFront(i_target.getTarget()); + if (i_angle == 0.f && !owner->HasInArc(0.01f, i_target.getTarget())) + owner->SetInFront(i_target.getTarget()); if (!i_targetReached) { @@ -193,60 +176,56 @@ bool TargetedMovementGeneratorMedium<T,D>::DoUpdate(T &owner, uint32 time_diff) static_cast<D*>(this)->_reachTarget(owner); } } - else - { - if (i_recalculateTravel) - _setTargetLocation(owner); - } + return true; } //-----------------------------------------------// template<class T> -void ChaseMovementGenerator<T>::_reachTarget(T &owner) +void ChaseMovementGenerator<T>::_reachTarget(T* owner) { - if (owner.IsWithinMeleeRange(this->i_target.getTarget())) - owner.Attack(this->i_target.getTarget(),true); + if (owner->IsWithinMeleeRange(this->i_target.getTarget())) + owner->Attack(this->i_target.getTarget(),true); } template<> -void ChaseMovementGenerator<Player>::DoInitialize(Player &owner) +void ChaseMovementGenerator<Player>::DoInitialize(Player* owner) { - owner.AddUnitState(UNIT_STATE_CHASE|UNIT_STATE_CHASE_MOVE); - _setTargetLocation(owner); + owner->AddUnitState(UNIT_STATE_CHASE | UNIT_STATE_CHASE_MOVE); + _setTargetLocation(owner, true); } template<> -void ChaseMovementGenerator<Creature>::DoInitialize(Creature &owner) +void ChaseMovementGenerator<Creature>::DoInitialize(Creature* owner) { - owner.SetWalk(false); - owner.AddUnitState(UNIT_STATE_CHASE|UNIT_STATE_CHASE_MOVE); - _setTargetLocation(owner); + owner->SetWalk(false); + owner->AddUnitState(UNIT_STATE_CHASE | UNIT_STATE_CHASE_MOVE); + _setTargetLocation(owner, true); } template<class T> -void ChaseMovementGenerator<T>::DoFinalize(T &owner) +void ChaseMovementGenerator<T>::DoFinalize(T* owner) { - owner.ClearUnitState(UNIT_STATE_CHASE|UNIT_STATE_CHASE_MOVE); + owner->ClearUnitState(UNIT_STATE_CHASE | UNIT_STATE_CHASE_MOVE); } template<class T> -void ChaseMovementGenerator<T>::DoReset(T &owner) +void ChaseMovementGenerator<T>::DoReset(T* owner) { DoInitialize(owner); } template<class T> -void ChaseMovementGenerator<T>::MovementInform(T & /*unit*/) +void ChaseMovementGenerator<T>::MovementInform(T* /*unit*/) { } template<> -void ChaseMovementGenerator<Creature>::MovementInform(Creature &unit) +void ChaseMovementGenerator<Creature>::MovementInform(Creature* unit) { // Pass back the GUIDLow of the target. If it is pet's owner then PetAI will handle - if (unit.AI()) - unit.AI()->MovementInform(CHASE_MOTION_TYPE, i_target.getTarget()->GetGUIDLow()); + if (unit->AI()) + unit->AI()->MovementInform(CHASE_MOTION_TYPE, i_target.getTarget()->GetGUIDLow()); } //-----------------------------------------------// @@ -263,85 +242,86 @@ bool FollowMovementGenerator<Player>::EnableWalking() const } template<> -void FollowMovementGenerator<Player>::_updateSpeed(Player &/*u*/) +void FollowMovementGenerator<Player>::_updateSpeed(Player* /*owner*/) { // nothing to do for Player } template<> -void FollowMovementGenerator<Creature>::_updateSpeed(Creature &u) +void FollowMovementGenerator<Creature>::_updateSpeed(Creature* owner) { // pet only sync speed with owner - if (!((Creature&)u).isPet() || !i_target.isValid() || i_target->GetGUID() != u.GetOwnerGUID()) + /// Make sure we are not in the process of a map change (IsInWorld) + if (!owner->isPet() || !owner->IsInWorld() || !i_target.isValid() || i_target->GetGUID() != owner->GetOwnerGUID()) return; - u.UpdateSpeed(MOVE_RUN,true); - u.UpdateSpeed(MOVE_WALK,true); - u.UpdateSpeed(MOVE_SWIM,true); + owner->UpdateSpeed(MOVE_RUN, true); + owner->UpdateSpeed(MOVE_WALK, true); + owner->UpdateSpeed(MOVE_SWIM, true); } template<> -void FollowMovementGenerator<Player>::DoInitialize(Player &owner) +void FollowMovementGenerator<Player>::DoInitialize(Player* owner) { - owner.AddUnitState(UNIT_STATE_FOLLOW|UNIT_STATE_FOLLOW_MOVE); + owner->AddUnitState(UNIT_STATE_FOLLOW | UNIT_STATE_FOLLOW_MOVE); _updateSpeed(owner); - _setTargetLocation(owner); + _setTargetLocation(owner, true); } template<> -void FollowMovementGenerator<Creature>::DoInitialize(Creature &owner) +void FollowMovementGenerator<Creature>::DoInitialize(Creature* owner) { - owner.AddUnitState(UNIT_STATE_FOLLOW|UNIT_STATE_FOLLOW_MOVE); + owner->AddUnitState(UNIT_STATE_FOLLOW | UNIT_STATE_FOLLOW_MOVE); _updateSpeed(owner); - _setTargetLocation(owner); + _setTargetLocation(owner, true); } template<class T> -void FollowMovementGenerator<T>::DoFinalize(T &owner) +void FollowMovementGenerator<T>::DoFinalize(T* owner) { - owner.ClearUnitState(UNIT_STATE_FOLLOW|UNIT_STATE_FOLLOW_MOVE); + owner->ClearUnitState(UNIT_STATE_FOLLOW | UNIT_STATE_FOLLOW_MOVE); _updateSpeed(owner); } template<class T> -void FollowMovementGenerator<T>::DoReset(T &owner) +void FollowMovementGenerator<T>::DoReset(T* owner) { DoInitialize(owner); } template<class T> -void FollowMovementGenerator<T>::MovementInform(T & /*unit*/) +void FollowMovementGenerator<T>::MovementInform(T* /*unit*/) { } template<> -void FollowMovementGenerator<Creature>::MovementInform(Creature &unit) +void FollowMovementGenerator<Creature>::MovementInform(Creature* unit) { // Pass back the GUIDLow of the target. If it is pet's owner then PetAI will handle - if (unit.AI()) - unit.AI()->MovementInform(FOLLOW_MOTION_TYPE, i_target.getTarget()->GetGUIDLow()); + if (unit->AI()) + unit->AI()->MovementInform(FOLLOW_MOTION_TYPE, i_target.getTarget()->GetGUIDLow()); } //-----------------------------------------------// -template void TargetedMovementGeneratorMedium<Player,ChaseMovementGenerator<Player> >::_setTargetLocation(Player &); -template void TargetedMovementGeneratorMedium<Player,FollowMovementGenerator<Player> >::_setTargetLocation(Player &); -template void TargetedMovementGeneratorMedium<Creature,ChaseMovementGenerator<Creature> >::_setTargetLocation(Creature &); -template void TargetedMovementGeneratorMedium<Creature,FollowMovementGenerator<Creature> >::_setTargetLocation(Creature &); -template bool TargetedMovementGeneratorMedium<Player,ChaseMovementGenerator<Player> >::DoUpdate(Player &, uint32); -template bool TargetedMovementGeneratorMedium<Player,FollowMovementGenerator<Player> >::DoUpdate(Player &, uint32); -template bool TargetedMovementGeneratorMedium<Creature,ChaseMovementGenerator<Creature> >::DoUpdate(Creature &, uint32); -template bool TargetedMovementGeneratorMedium<Creature,FollowMovementGenerator<Creature> >::DoUpdate(Creature &, uint32); - -template void ChaseMovementGenerator<Player>::_reachTarget(Player &); -template void ChaseMovementGenerator<Creature>::_reachTarget(Creature &); -template void ChaseMovementGenerator<Player>::DoFinalize(Player &); -template void ChaseMovementGenerator<Creature>::DoFinalize(Creature &); -template void ChaseMovementGenerator<Player>::DoReset(Player &); -template void ChaseMovementGenerator<Creature>::DoReset(Creature &); -template void ChaseMovementGenerator<Player>::MovementInform(Player &unit); - -template void FollowMovementGenerator<Player>::DoFinalize(Player &); -template void FollowMovementGenerator<Creature>::DoFinalize(Creature &); -template void FollowMovementGenerator<Player>::DoReset(Player &); -template void FollowMovementGenerator<Creature>::DoReset(Creature &); -template void FollowMovementGenerator<Player>::MovementInform(Player &unit); +template void TargetedMovementGeneratorMedium<Player,ChaseMovementGenerator<Player> >::_setTargetLocation(Player*, bool); +template void TargetedMovementGeneratorMedium<Player,FollowMovementGenerator<Player> >::_setTargetLocation(Player*, bool); +template void TargetedMovementGeneratorMedium<Creature,ChaseMovementGenerator<Creature> >::_setTargetLocation(Creature*, bool); +template void TargetedMovementGeneratorMedium<Creature,FollowMovementGenerator<Creature> >::_setTargetLocation(Creature*, bool); +template bool TargetedMovementGeneratorMedium<Player,ChaseMovementGenerator<Player> >::DoUpdate(Player*, uint32); +template bool TargetedMovementGeneratorMedium<Player,FollowMovementGenerator<Player> >::DoUpdate(Player*, uint32); +template bool TargetedMovementGeneratorMedium<Creature,ChaseMovementGenerator<Creature> >::DoUpdate(Creature*, uint32); +template bool TargetedMovementGeneratorMedium<Creature,FollowMovementGenerator<Creature> >::DoUpdate(Creature*, uint32); + +template void ChaseMovementGenerator<Player>::_reachTarget(Player*); +template void ChaseMovementGenerator<Creature>::_reachTarget(Creature*); +template void ChaseMovementGenerator<Player>::DoFinalize(Player*); +template void ChaseMovementGenerator<Creature>::DoFinalize(Creature*); +template void ChaseMovementGenerator<Player>::DoReset(Player*); +template void ChaseMovementGenerator<Creature>::DoReset(Creature*); +template void ChaseMovementGenerator<Player>::MovementInform(Player*); + +template void FollowMovementGenerator<Player>::DoFinalize(Player*); +template void FollowMovementGenerator<Creature>::DoFinalize(Creature*); +template void FollowMovementGenerator<Player>::DoReset(Player*); +template void FollowMovementGenerator<Creature>::DoReset(Creature*); +template void FollowMovementGenerator<Player>::MovementInform(Player*); diff --git a/src/server/game/Movement/MovementGenerators/TargetedMovementGenerator.h b/src/server/game/Movement/MovementGenerators/TargetedMovementGenerator.h index 4105668838d..3edeb348d54 100755 --- a/src/server/game/Movement/MovementGenerators/TargetedMovementGenerator.h +++ b/src/server/game/Movement/MovementGenerators/TargetedMovementGenerator.h @@ -23,11 +23,12 @@ #include "FollowerReference.h" #include "Timer.h" #include "Unit.h" +#include "PathGenerator.h" class TargetedMovementGeneratorBase { public: - TargetedMovementGeneratorBase(Unit &target) { i_target.link(&target, this); } + TargetedMovementGeneratorBase(Unit* target) { i_target.link(target, this); } void stopFollowing() { } protected: FollowerReference i_target; @@ -37,24 +38,24 @@ template<class T, typename D> class TargetedMovementGeneratorMedium : public MovementGeneratorMedium< T, D >, public TargetedMovementGeneratorBase { protected: - TargetedMovementGeneratorMedium(Unit &target, float offset, float angle) : - TargetedMovementGeneratorBase(target), i_recheckDistance(0), - i_offset(offset), i_angle(angle), + TargetedMovementGeneratorMedium(Unit* target, float offset, float angle) : + TargetedMovementGeneratorBase(target), i_path(NULL), + i_recheckDistance(0), i_offset(offset), i_angle(angle), i_recalculateTravel(false), i_targetReached(false) { } - ~TargetedMovementGeneratorMedium() {} + ~TargetedMovementGeneratorMedium() { delete i_path; } public: - bool DoUpdate(T &, uint32); + bool DoUpdate(T*, uint32); Unit* GetTarget() const { return i_target.getTarget(); } - void unitSpeedChanged() { i_recalculateTravel=true; } - void UpdateFinalDistance(float fDistance); - + void unitSpeedChanged() { i_recalculateTravel = true; } + bool IsReachable() const { return (i_path) ? (i_path->GetPathType() & PATHFIND_NORMAL) : true; } protected: - void _setTargetLocation(T &); + void _setTargetLocation(T* owner, bool updateDestination); + PathGenerator* i_path; TimeTrackerSmall i_recheckDistance; float i_offset; float i_angle; @@ -66,50 +67,50 @@ template<class T> class ChaseMovementGenerator : public TargetedMovementGeneratorMedium<T, ChaseMovementGenerator<T> > { public: - ChaseMovementGenerator(Unit &target) + ChaseMovementGenerator(Unit* target) : TargetedMovementGeneratorMedium<T, ChaseMovementGenerator<T> >(target) {} - ChaseMovementGenerator(Unit &target, float offset, float angle) + ChaseMovementGenerator(Unit* target, float offset, float angle) : TargetedMovementGeneratorMedium<T, ChaseMovementGenerator<T> >(target, offset, angle) {} ~ChaseMovementGenerator() {} MovementGeneratorType GetMovementGeneratorType() { return CHASE_MOTION_TYPE; } - void DoInitialize(T &); - void DoFinalize(T &); - void DoReset(T &); - void MovementInform(T &); + void DoInitialize(T*); + void DoFinalize(T*); + void DoReset(T*); + void MovementInform(T*); - static void _clearUnitStateMove(T &u) { u.ClearUnitState(UNIT_STATE_CHASE_MOVE); } - static void _addUnitStateMove(T &u) { u.AddUnitState(UNIT_STATE_CHASE_MOVE); } + static void _clearUnitStateMove(T* u) { u->ClearUnitState(UNIT_STATE_CHASE_MOVE); } + static void _addUnitStateMove(T* u) { u->AddUnitState(UNIT_STATE_CHASE_MOVE); } bool EnableWalking() const { return false;} - bool _lostTarget(T &u) const { return u.getVictim() != this->GetTarget(); } - void _reachTarget(T &); + bool _lostTarget(T* u) const { return u->getVictim() != this->GetTarget(); } + void _reachTarget(T*); }; template<class T> class FollowMovementGenerator : public TargetedMovementGeneratorMedium<T, FollowMovementGenerator<T> > { public: - FollowMovementGenerator(Unit &target) + FollowMovementGenerator(Unit* target) : TargetedMovementGeneratorMedium<T, FollowMovementGenerator<T> >(target){} - FollowMovementGenerator(Unit &target, float offset, float angle) + FollowMovementGenerator(Unit* target, float offset, float angle) : TargetedMovementGeneratorMedium<T, FollowMovementGenerator<T> >(target, offset, angle) {} ~FollowMovementGenerator() {} MovementGeneratorType GetMovementGeneratorType() { return FOLLOW_MOTION_TYPE; } - void DoInitialize(T &); - void DoFinalize(T &); - void DoReset(T &); - void MovementInform(T &); + void DoInitialize(T*); + void DoFinalize(T*); + void DoReset(T*); + void MovementInform(T*); - static void _clearUnitStateMove(T &u) { u.ClearUnitState(UNIT_STATE_FOLLOW_MOVE); } - static void _addUnitStateMove(T &u) { u.AddUnitState(UNIT_STATE_FOLLOW_MOVE); } + static void _clearUnitStateMove(T* u) { u->ClearUnitState(UNIT_STATE_FOLLOW_MOVE); } + static void _addUnitStateMove(T* u) { u->AddUnitState(UNIT_STATE_FOLLOW_MOVE); } bool EnableWalking() const; - bool _lostTarget(T &) const { return false; } - void _reachTarget(T &) {} + bool _lostTarget(T*) const { return false; } + void _reachTarget(T*) {} private: - void _updateSpeed(T &u); + void _updateSpeed(T* owner); }; #endif diff --git a/src/server/game/Movement/MovementGenerators/WaypointMovementGenerator.cpp b/src/server/game/Movement/MovementGenerators/WaypointMovementGenerator.cpp index 4b825544bdf..98f4c9581c6 100644..100755 --- a/src/server/game/Movement/MovementGenerators/WaypointMovementGenerator.cpp +++ b/src/server/game/Movement/MovementGenerators/WaypointMovementGenerator.cpp @@ -31,64 +31,64 @@ #include "MoveSplineInit.h" #include "MoveSpline.h" -void WaypointMovementGenerator<Creature>::LoadPath(Creature &creature) +void WaypointMovementGenerator<Creature>::LoadPath(Creature* creature) { if (!path_id) - path_id = creature.GetWaypointPath(); + path_id = creature->GetWaypointPath(); i_path = sWaypointMgr->GetPath(path_id); if (!i_path) { // No movement found for entry - sLog->outError(LOG_FILTER_SQL, "WaypointMovementGenerator::LoadPath: creature %s (Entry: %u GUID: %u) doesn't have waypoint path id: %u", creature.GetName().c_str(), creature.GetEntry(), creature.GetGUIDLow(), path_id); + sLog->outError(LOG_FILTER_SQL, "WaypointMovementGenerator::LoadPath: creature %s (Entry: %u GUID: %u) doesn't have waypoint path id: %u", creature->GetName().c_str(), creature->GetEntry(), creature->GetGUIDLow(), path_id); return; } StartMoveNow(creature); } -void WaypointMovementGenerator<Creature>::DoInitialize(Creature &creature) +void WaypointMovementGenerator<Creature>::DoInitialize(Creature* creature) { LoadPath(creature); - creature.AddUnitState(UNIT_STATE_ROAMING|UNIT_STATE_ROAMING_MOVE); + creature->AddUnitState(UNIT_STATE_ROAMING|UNIT_STATE_ROAMING_MOVE); } -void WaypointMovementGenerator<Creature>::DoFinalize(Creature &creature) +void WaypointMovementGenerator<Creature>::DoFinalize(Creature* creature) { - creature.ClearUnitState(UNIT_STATE_ROAMING|UNIT_STATE_ROAMING_MOVE); - creature.SetWalk(false); + creature->ClearUnitState(UNIT_STATE_ROAMING|UNIT_STATE_ROAMING_MOVE); + creature->SetWalk(false); } -void WaypointMovementGenerator<Creature>::DoReset(Creature &creature) +void WaypointMovementGenerator<Creature>::DoReset(Creature* creature) { - creature.AddUnitState(UNIT_STATE_ROAMING|UNIT_STATE_ROAMING_MOVE); + creature->AddUnitState(UNIT_STATE_ROAMING|UNIT_STATE_ROAMING_MOVE); StartMoveNow(creature); } -void WaypointMovementGenerator<Creature>::OnArrived(Creature& creature) +void WaypointMovementGenerator<Creature>::OnArrived(Creature* creature) { if (!i_path || i_path->empty()) return; if (m_isArrivalDone) return; - creature.ClearUnitState(UNIT_STATE_ROAMING_MOVE); + creature->ClearUnitState(UNIT_STATE_ROAMING_MOVE); m_isArrivalDone = true; if (i_path->at(i_currentNode)->event_id && urand(0, 99) < i_path->at(i_currentNode)->event_chance) { - sLog->outDebug(LOG_FILTER_MAPSCRIPTS, "Creature movement start script %u at point %u for "UI64FMTD".", i_path->at(i_currentNode)->event_id, i_currentNode, creature.GetGUID()); - creature.GetMap()->ScriptsStart(sWaypointScripts, i_path->at(i_currentNode)->event_id, &creature, NULL); + sLog->outDebug(LOG_FILTER_MAPSCRIPTS, "Creature movement start script %u at point %u for "UI64FMTD".", i_path->at(i_currentNode)->event_id, i_currentNode, creature->GetGUID()); + creature->GetMap()->ScriptsStart(sWaypointScripts, i_path->at(i_currentNode)->event_id, creature, NULL); } // Inform script MovementInform(creature); - creature.UpdateWaypointID(i_currentNode); + creature->UpdateWaypointID(i_currentNode); Stop(i_path->at(i_currentNode)->delay); } -bool WaypointMovementGenerator<Creature>::StartMove(Creature &creature) +bool WaypointMovementGenerator<Creature>::StartMove(Creature* creature) { if (!i_path || i_path->empty()) return false; @@ -99,8 +99,8 @@ bool WaypointMovementGenerator<Creature>::StartMove(Creature &creature) { if ((i_currentNode == i_path->size() - 1) && !repeating) // If that's our last waypoint { - creature.SetHomePosition(i_path->at(i_currentNode)->x, i_path->at(i_currentNode)->y, i_path->at(i_currentNode)->z, creature.GetOrientation()); - creature.GetMotionMaster()->Initialize(); + creature->SetHomePosition(i_path->at(i_currentNode)->x, i_path->at(i_currentNode)->y, i_path->at(i_currentNode)->z, creature->GetOrientation()); + creature->GetMotionMaster()->Initialize(); return false; } @@ -111,7 +111,7 @@ bool WaypointMovementGenerator<Creature>::StartMove(Creature &creature) m_isArrivalDone = false; - creature.AddUnitState(UNIT_STATE_ROAMING_MOVE); + creature->AddUnitState(UNIT_STATE_ROAMING_MOVE); Movement::MoveSplineInit init(creature); init.MoveTo(node->x, node->y, node->z); @@ -124,19 +124,19 @@ bool WaypointMovementGenerator<Creature>::StartMove(Creature &creature) init.Launch(); //Call for creature group update - if (creature.GetFormation() && creature.GetFormation()->getLeader() == &creature) - creature.GetFormation()->LeaderMoveTo(node->x, node->y, node->z); + if (creature->GetFormation() && creature->GetFormation()->getLeader() == creature) + creature->GetFormation()->LeaderMoveTo(node->x, node->y, node->z); return true; } -bool WaypointMovementGenerator<Creature>::DoUpdate(Creature &creature, uint32 diff) +bool WaypointMovementGenerator<Creature>::DoUpdate(Creature* creature, uint32 diff) { // Waypoint movement can be switched on/off // This is quite handy for escort quests and other stuff - if (creature.HasUnitState(UNIT_STATE_NOT_MOVE)) + if (creature->HasUnitState(UNIT_STATE_NOT_MOVE)) { - creature.ClearUnitState(UNIT_STATE_ROAMING_MOVE); + creature->ClearUnitState(UNIT_STATE_ROAMING_MOVE); return true; } // prevent a crash at empty waypoint path. @@ -150,9 +150,9 @@ bool WaypointMovementGenerator<Creature>::DoUpdate(Creature &creature, uint32 di } else { - if (creature.IsStopped()) + if (creature->IsStopped()) Stop(STOP_TIME_FOR_PLAYER); - else if (creature.movespline->Finalized()) + else if (creature->movespline->Finalized()) { OnArrived(creature); return StartMove(creature); @@ -161,13 +161,13 @@ bool WaypointMovementGenerator<Creature>::DoUpdate(Creature &creature, uint32 di return true; } -void WaypointMovementGenerator<Creature>::MovementInform(Creature &creature) +void WaypointMovementGenerator<Creature>::MovementInform(Creature* creature) { - if (creature.AI()) - creature.AI()->MovementInform(WAYPOINT_MOTION_TYPE, i_currentNode); + if (creature->AI()) + creature->AI()->MovementInform(WAYPOINT_MOTION_TYPE, i_currentNode); } -bool WaypointMovementGenerator<Creature>::GetResetPosition(Creature&, float& x, float& y, float& z) +bool WaypointMovementGenerator<Creature>::GetResetPos(Creature*, float& x, float& y, float& z) { // prevent a crash at empty waypoint path. if (!i_path || i_path->empty()) @@ -196,37 +196,37 @@ uint32 FlightPathMovementGenerator::GetPathAtMapEnd() const return i_path->size(); } -void FlightPathMovementGenerator::DoInitialize(Player &player) +void FlightPathMovementGenerator::DoInitialize(Player* player) { - DoReset(player); + Reset(player); InitEndGridInfo(); } -void FlightPathMovementGenerator::DoFinalize(Player& player) +void FlightPathMovementGenerator::DoFinalize(Player* player) { // remove flag to prevent send object build movement packets for flight state and crash (movement generator already not at top of stack) - player.ClearUnitState(UNIT_STATE_IN_FLIGHT); + player->ClearUnitState(UNIT_STATE_IN_FLIGHT); - player.Dismount(); - player.RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_DISABLE_MOVE | UNIT_FLAG_TAXI_FLIGHT); + player->Dismount(); + player->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_DISABLE_MOVE | UNIT_FLAG_TAXI_FLIGHT); - if (player.m_taxi.empty()) + if (player->m_taxi.empty()) { - player.getHostileRefManager().setOnlineOfflineState(true); + player->getHostileRefManager().setOnlineOfflineState(true); // update z position to ground and orientation for landing point // this prevent cheating with landing point at lags // when client side flight end early in comparison server side - player.StopMoving(); + player->StopMoving(); } } #define PLAYER_FLIGHT_SPEED 32.0f -void FlightPathMovementGenerator::DoReset(Player & player) +void FlightPathMovementGenerator::DoReset(Player* player) { - player.getHostileRefManager().setOnlineOfflineState(false); - player.AddUnitState(UNIT_STATE_IN_FLIGHT); - player.SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_DISABLE_MOVE | UNIT_FLAG_TAXI_FLIGHT); + player->getHostileRefManager().setOnlineOfflineState(false); + player->AddUnitState(UNIT_STATE_IN_FLIGHT); + player->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_DISABLE_MOVE | UNIT_FLAG_TAXI_FLIGHT); Movement::MoveSplineInit init(player); uint32 end = GetPathAtMapEnd(); @@ -241,9 +241,9 @@ void FlightPathMovementGenerator::DoReset(Player & player) init.Launch(); } -bool FlightPathMovementGenerator::DoUpdate(Player &player, uint32 /*diff*/) +bool FlightPathMovementGenerator::DoUpdate(Player* player, uint32 /*diff*/) { - uint32 pointId = (uint32)player.movespline->currentPathIdx(); + uint32 pointId = (uint32)player->movespline->currentPathIdx(); if (pointId > i_currentNode) { bool departureEvent = true; @@ -279,16 +279,16 @@ void FlightPathMovementGenerator::SetCurrentNodeAfterTeleport() } } -void FlightPathMovementGenerator::DoEventIfAny(Player& player, TaxiPathNodeEntry const& node, bool departure) +void FlightPathMovementGenerator::DoEventIfAny(Player* player, TaxiPathNodeEntry const& node, bool departure) { if (uint32 eventid = departure ? node.departureEventID : node.arrivalEventID) { - sLog->outDebug(LOG_FILTER_MAPSCRIPTS, "Taxi %s event %u of node %u of path %u for player %s", departure ? "departure" : "arrival", eventid, node.index, node.path, player.GetName().c_str()); - player.GetMap()->ScriptsStart(sEventScripts, eventid, &player, &player); + sLog->outDebug(LOG_FILTER_MAPSCRIPTS, "Taxi %s event %u of node %u of path %u for player %s", departure ? "departure" : "arrival", eventid, node.index, node.path, player->GetName().c_str()); + player->GetMap()->ScriptsStart(sEventScripts, eventid, player, player); } } -bool FlightPathMovementGenerator::GetResetPosition(Player&, float& x, float& y, float& z) +bool FlightPathMovementGenerator::GetResetPos(Player*, float& x, float& y, float& z) { const TaxiPathNodeEntry& node = (*i_path)[i_currentNode]; x = node.x; y = node.y; z = node.z; @@ -320,331 +320,3 @@ void FlightPathMovementGenerator::PreloadEndGrid() else sLog->outInfo(LOG_FILTER_GENERAL, "Unable to determine map to preload flightmaster grid"); } - - -// -// Unique1's ASTAR Pathfinding Code... For future use & reference... -// - -#ifdef __PATHFINDING__ - -int GetFCost(int to, int num, int parentNum, float *gcost); // Below... - -int ShortenASTARRoute(short int *pathlist, int number) -{ // Wrote this to make the routes a little smarter (shorter)... No point looping back to the same places... Unique1 - short int temppathlist[MAX_PATHLIST_NODES]; - int count = 0; - // int count2 = 0; - int temp, temp2; - int link; - int upto = 0; - - for (temp = number; temp >= 0; temp--) - { - qboolean shortened = qfalse; - - for (temp2 = 0; temp2 < temp; temp2++) - { - for (link = 0; link < nodes[pathlist[temp]].enodenum; link++) - { - if (nodes[pathlist[temp]].links[link].flags & PATH_BLOCKED) - continue; - - //if ((bot->client->ps.eFlags & EF_TANK) && nodes[bot->current_node].links[link].flags & PATH_NOTANKS) //if this path is blocked, skip it - // continue; - - //if (nodes[nodes[pathlist[temp]].links[link].targetNode].origin[2] > nodes[pathlist[temp]].origin[2] + 32) - // continue; - - if (nodes[pathlist[temp]].links[link].targetNode == pathlist[temp2]) - { // Found a shorter route... - //if (OrgVisible(nodes[pathlist[temp2]].origin, nodes[pathlist[temp]].origin, -1)) - { - temppathlist[count] = pathlist[temp2]; - temp = temp2; - ++count; - shortened = qtrue; - } - } - } - } - - if (!shortened) - { - temppathlist[count] = pathlist[temp]; - ++count; - } - } - - upto = count; - - for (temp = 0; temp < count; temp++) - { - pathlist[temp] = temppathlist[upto]; - --upto; - } - - G_Printf("ShortenASTARRoute: Path size reduced from %i to %i nodes...n", number, count); - return count; -} - -/* -=========================================================================== -CreatePathAStar -This function uses the A* pathfinding algorithm to determine the -shortest path between any two nodes. -It's fairly complex, so I'm not really going to explain it much. -Look up A* and binary heaps for more info. -pathlist stores the ideal path between the nodes, in reverse order, -and the return value is the number of nodes in that path -=========================================================================== -*/ -int CreatePathAStar(gentity_t *bot, int from, int to, short int *pathlist) -{ - //all the data we have to hold...since we can't do dynamic allocation, has to be MAX_NODES - //we can probably lower this later - eg, the open list should never have more than at most a few dozen items on it - short int openlist[MAX_NODES+1]; //add 1 because it's a binary heap, and they don't use 0 - 1 is the first used index - float gcost[MAX_NODES]; - int fcost[MAX_NODES]; - char list[MAX_NODES]; //0 is neither, 1 is open, 2 is closed - char because it's the smallest data type - short int parent[MAX_NODES]; - - short int numOpen = 0; - short int atNode, temp, newnode=-1; - qboolean found = qfalse; - int count = -1; - float gc; - int i, u, v, m; - vec3_t vec; - - //clear out all the arrays - memset(openlist, 0, sizeof(short int)*(MAX_NODES+1)); - memset(fcost, 0, sizeof(int)*MAX_NODES); - memset(list, 0, sizeof(char)*MAX_NODES); - memset(parent, 0, sizeof(short int)*MAX_NODES); - memset(gcost, -1, sizeof(float)*MAX_NODES); - - //make sure we have valid data before calculating everything - if ((from == NODE_INVALID) || (to == NODE_INVALID) || (from >= MAX_NODES) || (to >= MAX_NODES) || (from == to)) - return -1; - - openlist[1] = from; //add the starting node to the open list - ++numOpen; - gcost[from] = 0; //its f and g costs are obviously 0 - fcost[from] = 0; - - while (1) - { - if (numOpen != 0) //if there are still items in the open list - { - //pop the top item off of the list - atNode = openlist[1]; - list[atNode] = 2; //put the node on the closed list so we don't check it again - --numOpen; - - openlist[1] = openlist[numOpen+1]; //move the last item in the list to the top position - v = 1; - - //this while loop reorders the list so that the new lowest fcost is at the top again - while (1) - { - u = v; - if ((2*u+1) < numOpen) //if both children exist - { - if (fcost[openlist[u]] >= fcost[openlist[2*u]]) - v = 2*u; - if (fcost[openlist[v]] >= fcost[openlist[2*u+1]]) - v = 2*u+1; - } - else - { - if ((2*u) < numOpen) //if only one child exists - { - if (fcost[openlist[u]] >= fcost[openlist[2*u]]) - v = 2*u; - } - } - - if (u != v) //if they're out of order, swap this item with its parent - { - temp = openlist[u]; - openlist[u] = openlist[v]; - openlist[v] = temp; - } - else - break; - } - - for (i = 0; i < nodes[atNode].enodenum; ++i) //loop through all the links for this node - { - newnode = nodes[atNode].links[i].targetNode; - - //if this path is blocked, skip it - if (nodes[atNode].links[i].flags & PATH_BLOCKED) - continue; - //if this path is blocked, skip it - if (bot->client && (bot->client->ps.eFlags & EF_TANK) && nodes[atNode].links[i].flags & PATH_NOTANKS) - continue; - //skip any unreachable nodes - if (bot->client && (nodes[newnode].type & NODE_ALLY_UNREACHABLE) && (bot->client->sess.sessionTeam == TEAM_ALLIES)) - continue; - if (bot->client && (nodes[newnode].type & NODE_AXIS_UNREACHABLE) && (bot->client->sess.sessionTeam == TEAM_AXIS)) - continue; - - if (list[newnode] == 2) //if this node is on the closed list, skip it - continue; - - if (list[newnode] != 1) //if this node is not already on the open list - { - openlist[++numOpen] = newnode; //add the new node to the open list - list[newnode] = 1; - parent[newnode] = atNode; //record the node's parent - - if (newnode == to) //if we've found the goal, don't keep computing paths! - break; //this will break the 'for' and go all the way to 'if (list[to] == 1)' - - //store it's f cost value - fcost[newnode] = GetFCost(to, newnode, parent[newnode], gcost); - - //this loop re-orders the heap so that the lowest fcost is at the top - m = numOpen; - while (m != 1) //while this item isn't at the top of the heap already - { - //if it has a lower fcost than its parent - if (fcost[openlist[m]] <= fcost[openlist[m/2]]) - { - temp = openlist[m/2]; - openlist[m/2] = openlist[m]; - openlist[m] = temp; //swap them - m /= 2; - } - else - break; - } - } - else //if this node is already on the open list - { - gc = gcost[atNode]; - VectorSubtract(nodes[newnode].origin, nodes[atNode].origin, vec); - gc += VectorLength(vec); //calculate what the gcost would be if we reached this node along the current path - - if (gc < gcost[newnode]) //if the new gcost is less (ie, this path is shorter than what we had before) - { - parent[newnode] = atNode; //set the new parent for this node - gcost[newnode] = gc; //and the new g cost - - for (i = 1; i < numOpen; ++i) //loop through all the items on the open list - { - if (openlist[i] == newnode) //find this node in the list - { - //calculate the new fcost and store it - fcost[newnode] = GetFCost(to, newnode, parent[newnode], gcost); - - //reorder the list again, with the lowest fcost item on top - m = i; - while (m != 1) - { - //if the item has a lower fcost than it's parent - if (fcost[openlist[m]] < fcost[openlist[m/2]]) - { - temp = openlist[m/2]; - openlist[m/2] = openlist[m]; - openlist[m] = temp; //swap them - m /= 2; - } - else - break; - } - break; //exit the 'for' loop because we already changed this node - } //if - } //for - } //if (gc < gcost[newnode]) - } //if (list[newnode] != 1) --> else - } //for (loop through links) - } //if (numOpen != 0) - else - { - found = qfalse; //there is no path between these nodes - break; - } - - if (list[to] == 1) //if the destination node is on the open list, we're done - { - found = qtrue; - break; - } - } //while (1) - - if (found == qtrue) //if we found a path - { - //G_Printf("%s - path found!n", bot->client->pers.netname); - count = 0; - - temp = to; //start at the end point - while (temp != from) //travel along the path (backwards) until we reach the starting point - { - pathlist[count++] = temp; //add the node to the pathlist and increment the count - temp = parent[temp]; //move to the parent of this node to continue the path - } - - pathlist[count++] = from; //add the beginning node to the end of the pathlist - - #ifdef __BOT_SHORTEN_ROUTING__ - count = ShortenASTARRoute(pathlist, count); // This isn't working... Dunno why.. Unique1 - #endif //__BOT_SHORTEN_ROUTING__ - } - else - { - //G_Printf("^1*** ^4BOT DEBUG^5: (CreatePathAStar) There is no route between node ^7%i^5 and node ^7%i^5.n", from, to); - count = CreateDumbRoute(from, to, pathlist); - - if (count > 0) - { - #ifdef __BOT_SHORTEN_ROUTING__ - count = ShortenASTARRoute(pathlist, count); // This isn't working... Dunno why.. Unique1 - #endif //__BOT_SHORTEN_ROUTING__ - return count; - } - } - - return count; //return the number of nodes in the path, -1 if not found -} - -/* -=========================================================================== -GetFCost -Utility function used by A* pathfinding to calculate the -cost to move between nodes towards a goal. Using the A* -algorithm F = G + H, G here is the distance along the node -paths the bot must travel, and H is the straight-line distance -to the goal node. -Returned as an int because more precision is unnecessary and it -will slightly speed up heap access -=========================================================================== -*/ -int GetFCost(int to, int num, int parentNum, float *gcost) -{ - float gc = 0; - float hc = 0; - vec3_t v; - - if (gcost[num] == -1) - { - if (parentNum != -1) - { - gc = gcost[parentNum]; - VectorSubtract(nodes[num].origin, nodes[parentNum].origin, v); - gc += VectorLength(v); - } - gcost[num] = gc; - } - else - gc = gcost[num]; - - VectorSubtract(nodes[to].origin, nodes[num].origin, v); - hc = VectorLength(v); - - return (int)(gc + hc); -} -#endif //__PATHFINDING__ - diff --git a/src/server/game/Movement/MovementGenerators/WaypointMovementGenerator.h b/src/server/game/Movement/MovementGenerators/WaypointMovementGenerator.h index 319a5c66a03..72650570e12 100644..100755 --- a/src/server/game/Movement/MovementGenerators/WaypointMovementGenerator.h +++ b/src/server/game/Movement/MovementGenerators/WaypointMovementGenerator.h @@ -65,19 +65,19 @@ class WaypointMovementGenerator<Creature> : public MovementGeneratorMedium< Crea WaypointMovementGenerator(uint32 _path_id = 0, bool _repeating = true) : i_nextMoveTime(0), m_isArrivalDone(false), path_id(_path_id), repeating(_repeating) {} ~WaypointMovementGenerator() { i_path = NULL; } - void DoInitialize(Creature &); - void DoFinalize(Creature &); - void DoReset(Creature &); - bool DoUpdate(Creature &, uint32 diff); + void DoInitialize(Creature*); + void DoFinalize(Creature*); + void DoReset(Creature*); + bool DoUpdate(Creature*, uint32 diff); - void MovementInform(Creature &); + void MovementInform(Creature*); MovementGeneratorType GetMovementGeneratorType() { return WAYPOINT_MOTION_TYPE; } // now path movement implmementation - void LoadPath(Creature &c); + void LoadPath(Creature*); - bool GetResetPosition(Creature&, float& x, float& y, float& z); + bool GetResetPos(Creature*, float& x, float& y, float& z); private: @@ -91,10 +91,10 @@ class WaypointMovementGenerator<Creature> : public MovementGeneratorMedium< Crea return i_nextMoveTime.Passed(); } - void OnArrived(Creature&); - bool StartMove(Creature&); + void OnArrived(Creature*); + bool StartMove(Creature*); - void StartMoveNow(Creature& creature) + void StartMoveNow(Creature* creature) { i_nextMoveTime.Reset(0); StartMove(creature); @@ -118,10 +118,10 @@ class FlightPathMovementGenerator : public MovementGeneratorMedium< Player, Flig i_path = &pathnodes; i_currentNode = startNode; } - void DoInitialize(Player &); - void DoReset(Player &); - void DoFinalize(Player &); - bool DoUpdate(Player &, uint32); + void DoInitialize(Player*); + void DoReset(Player*); + void DoFinalize(Player*); + bool DoUpdate(Player*, uint32); MovementGeneratorType GetMovementGeneratorType() { return FLIGHT_MOTION_TYPE; } TaxiPathNodeList const& GetPath() { return *i_path; } @@ -129,9 +129,9 @@ class FlightPathMovementGenerator : public MovementGeneratorMedium< Player, Flig bool HasArrived() const { return (i_currentNode >= i_path->size()); } void SetCurrentNodeAfterTeleport(); void SkipCurrentNode() { ++i_currentNode; } - void DoEventIfAny(Player& player, TaxiPathNodeEntry const& node, bool departure); + void DoEventIfAny(Player* player, TaxiPathNodeEntry const& node, bool departure); - bool GetResetPosition(Player&, float& x, float& y, float& z); + bool GetResetPos(Player*, float& x, float& y, float& z); void InitEndGridInfo(); void PreloadEndGrid(); @@ -143,4 +143,3 @@ class FlightPathMovementGenerator : public MovementGeneratorMedium< Player, Flig uint32 _preloadTargetNode; //! node index where preloading starts }; #endif - diff --git a/src/server/game/Movement/PathGenerator.cpp b/src/server/game/Movement/PathGenerator.cpp new file mode 100644 index 00000000000..07e33f353c7 --- /dev/null +++ b/src/server/game/Movement/PathGenerator.cpp @@ -0,0 +1,803 @@ +/* + * Copyright (C) 2005-2011 MaNGOS <http://getmangos.com/> + * + * 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 2 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, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include "PathGenerator.h" +#include "Map.h" +#include "Creature.h" +#include "MMapFactory.h" +#include "MMapManager.h" +#include "Log.h" + +#include "DetourCommon.h" +#include "DetourNavMeshQuery.h" + +////////////////// PathGenerator ////////////////// +PathGenerator::PathGenerator(const Unit* owner) : + _polyLength(0), _type(PATHFIND_BLANK), + _useStraightPath(false), _forceDestination(false), _pointPathLimit(MAX_POINT_PATH_LENGTH), + _endPosition(Vector3::zero()), _sourceUnit(owner), _navMesh(NULL), _navMeshQuery(NULL) +{ + sLog->outDebug(LOG_FILTER_MAPS, "++ PathGenerator::PathGenerator for %u \n", _sourceUnit->GetGUIDLow()); + + uint32 mapId = _sourceUnit->GetMapId(); + if (MMAP::MMapFactory::IsPathfindingEnabled(mapId)) + { + MMAP::MMapManager* mmap = MMAP::MMapFactory::createOrGetMMapManager(); + _navMesh = mmap->GetNavMesh(mapId); + _navMeshQuery = mmap->GetNavMeshQuery(mapId, _sourceUnit->GetInstanceId()); + } + + CreateFilter(); +} + +PathGenerator::~PathGenerator() +{ + sLog->outDebug(LOG_FILTER_MAPS, "++ PathGenerator::~PathGenerator() for %u \n", _sourceUnit->GetGUIDLow()); +} + +bool PathGenerator::CalculatePath(float destX, float destY, float destZ, bool forceDest) +{ + float x, y, z; + _sourceUnit->GetPosition(x, y, z); + + if (!Trinity::IsValidMapCoord(destX, destY, destZ) || !Trinity::IsValidMapCoord(x, y, z)) + return false; + + Vector3 dest(destX, destY, destZ); + SetEndPosition(dest); + + Vector3 start(x, y, z); + SetStartPosition(start); + + _forceDestination = forceDest; + + sLog->outDebug(LOG_FILTER_MAPS, "++ PathGenerator::CalculatePath() for %u \n", _sourceUnit->GetGUIDLow()); + + // make sure navMesh works - we can run on map w/o mmap + // check if the start and end point have a .mmtile loaded (can we pass via not loaded tile on the way?) + if (!_navMesh || !_navMeshQuery || _sourceUnit->HasUnitState(UNIT_STATE_IGNORE_PATHFINDING) || + !HaveTile(start) || !HaveTile(dest)) + { + BuildShortcut(); + _type = PathType(PATHFIND_NORMAL | PATHFIND_NOT_USING_PATH); + return true; + } + + UpdateFilter(); + + BuildPolyPath(start, dest); + return true; +} + +dtPolyRef PathGenerator::GetPathPolyByPosition(dtPolyRef const* polyPath, uint32 polyPathSize, float const* point, float* distance) const +{ + if (!polyPath || !polyPathSize) + return INVALID_POLYREF; + + dtPolyRef nearestPoly = INVALID_POLYREF; + float minDist2d = FLT_MAX; + float minDist3d = 0.0f; + + for (uint32 i = 0; i < polyPathSize; ++i) + { + float closestPoint[VERTEX_SIZE]; + if (DT_SUCCESS != _navMeshQuery->closestPointOnPoly(polyPath[i], point, closestPoint)) + continue; + + float d = dtVdist2DSqr(point, closestPoint); + if (d < minDist2d) + { + minDist2d = d; + nearestPoly = polyPath[i]; + minDist3d = dtVdistSqr(point, closestPoint); + } + + if (minDist2d < 1.0f) // shortcut out - close enough for us + break; + } + + if (distance) + *distance = dtSqrt(minDist3d); + + return (minDist2d < 3.0f) ? nearestPoly : INVALID_POLYREF; +} + +dtPolyRef PathGenerator::GetPolyByLocation(float const* point, float* distance) const +{ + // first we check the current path + // if the current path doesn't contain the current poly, + // we need to use the expensive navMesh.findNearestPoly + dtPolyRef polyRef = GetPathPolyByPosition(_pathPolyRefs, _polyLength, point, distance); + if (polyRef != INVALID_POLYREF) + return polyRef; + + // we don't have it in our old path + // try to get it by findNearestPoly() + // first try with low search box + float extents[VERTEX_SIZE] = {3.0f, 5.0f, 3.0f}; // bounds of poly search area + float closestPoint[VERTEX_SIZE] = {0.0f, 0.0f, 0.0f}; + dtStatus result = _navMeshQuery->findNearestPoly(point, extents, &_filter, &polyRef, closestPoint); + if (DT_SUCCESS == result && polyRef != INVALID_POLYREF) + { + *distance = dtVdist(closestPoint, point); + return polyRef; + } + + // still nothing .. + // try with bigger search box + extents[1] = 200.0f; + result = _navMeshQuery->findNearestPoly(point, extents, &_filter, &polyRef, closestPoint); + if (DT_SUCCESS == result && polyRef != INVALID_POLYREF) + { + *distance = dtVdist(closestPoint, point); + return polyRef; + } + + return INVALID_POLYREF; +} + +void PathGenerator::BuildPolyPath(Vector3 const& startPos, Vector3 const& endPos) +{ + // *** getting start/end poly logic *** + + float distToStartPoly, distToEndPoly; + float startPoint[VERTEX_SIZE] = {startPos.y, startPos.z, startPos.x}; + float endPoint[VERTEX_SIZE] = {endPos.y, endPos.z, endPos.x}; + + dtPolyRef startPoly = GetPolyByLocation(startPoint, &distToStartPoly); + dtPolyRef endPoly = GetPolyByLocation(endPoint, &distToEndPoly); + + // we have a hole in our mesh + // make shortcut path and mark it as NOPATH ( with flying and swimming exception ) + // its up to caller how he will use this info + if (startPoly == INVALID_POLYREF || endPoly == INVALID_POLYREF) + { + sLog->outDebug(LOG_FILTER_MAPS, "++ BuildPolyPath :: (startPoly == 0 || endPoly == 0)\n"); + BuildShortcut(); + bool path = _sourceUnit->GetTypeId() == TYPEID_UNIT && _sourceUnit->ToCreature()->CanFly(); + + bool waterPath = _sourceUnit->GetTypeId() == TYPEID_UNIT && _sourceUnit->ToCreature()->canSwim(); + if (waterPath) + { + // Check both start and end points, if they're both in water, then we can *safely* let the creature move + for (uint32 i = 0; i < _pathPoints.size(); ++i) + { + ZLiquidStatus status = _sourceUnit->GetBaseMap()->getLiquidStatus(_pathPoints[i].x, _pathPoints[i].y, _pathPoints[i].z, MAP_ALL_LIQUIDS, NULL); + // One of the points is not in the water, cancel movement. + if (status == LIQUID_MAP_NO_WATER) + { + waterPath = false; + break; + } + } + } + + _type = (path || waterPath) ? PathType(PATHFIND_NORMAL | PATHFIND_NOT_USING_PATH) : PATHFIND_NOPATH; + return; + } + + // we may need a better number here + bool farFromPoly = (distToStartPoly > 7.0f || distToEndPoly > 7.0f); + if (farFromPoly) + { + sLog->outDebug(LOG_FILTER_MAPS, "++ BuildPolyPath :: farFromPoly distToStartPoly=%.3f distToEndPoly=%.3f\n", distToStartPoly, distToEndPoly); + + bool buildShotrcut = false; + if (_sourceUnit->GetTypeId() == TYPEID_UNIT) + { + Creature* owner = (Creature*)_sourceUnit; + + Vector3 p = (distToStartPoly > 7.0f) ? startPos : endPos; + if (_sourceUnit->GetBaseMap()->IsUnderWater(p.x, p.y, p.z)) + { + sLog->outDebug(LOG_FILTER_MAPS, "++ BuildPolyPath :: underWater case\n"); + if (owner->canSwim()) + buildShotrcut = true; + } + else + { + sLog->outDebug(LOG_FILTER_MAPS, "++ BuildPolyPath :: flying case\n"); + if (owner->CanFly()) + buildShotrcut = true; + } + } + + if (buildShotrcut) + { + BuildShortcut(); + _type = PathType(PATHFIND_NORMAL | PATHFIND_NOT_USING_PATH); + return; + } + else + { + float closestPoint[VERTEX_SIZE]; + // we may want to use closestPointOnPolyBoundary instead + if (DT_SUCCESS == _navMeshQuery->closestPointOnPoly(endPoly, endPoint, closestPoint)) + { + dtVcopy(endPoint, closestPoint); + SetActualEndPosition(Vector3(endPoint[2], endPoint[0], endPoint[1])); + } + + _type = PATHFIND_INCOMPLETE; + } + } + + // *** poly path generating logic *** + + // start and end are on same polygon + // just need to move in straight line + if (startPoly == endPoly) + { + sLog->outDebug(LOG_FILTER_MAPS, "++ BuildPolyPath :: (startPoly == endPoly)\n"); + + BuildShortcut(); + + _pathPolyRefs[0] = startPoly; + _polyLength = 1; + + _type = farFromPoly ? PATHFIND_INCOMPLETE : PATHFIND_NORMAL; + sLog->outDebug(LOG_FILTER_MAPS, "++ BuildPolyPath :: path type %d\n", _type); + return; + } + + // look for startPoly/endPoly in current path + /// @todo we can merge it with getPathPolyByPosition() loop + bool startPolyFound = false; + bool endPolyFound = false; + uint32 pathStartIndex = 0; + uint32 pathEndIndex = 0; + + if (_polyLength) + { + for (; pathStartIndex < _polyLength; ++pathStartIndex) + { + // here to carch few bugs + ASSERT(_pathPolyRefs[pathStartIndex] != INVALID_POLYREF); + + if (_pathPolyRefs[pathStartIndex] == startPoly) + { + startPolyFound = true; + break; + } + } + + for (pathEndIndex = _polyLength-1; pathEndIndex > pathStartIndex; --pathEndIndex) + if (_pathPolyRefs[pathEndIndex] == endPoly) + { + endPolyFound = true; + break; + } + } + + if (startPolyFound && endPolyFound) + { + sLog->outDebug(LOG_FILTER_MAPS, "++ BuildPolyPath :: (startPolyFound && endPolyFound)\n"); + + // we moved along the path and the target did not move out of our old poly-path + // our path is a simple subpath case, we have all the data we need + // just "cut" it out + + _polyLength = pathEndIndex - pathStartIndex + 1; + memmove(_pathPolyRefs, _pathPolyRefs + pathStartIndex, _polyLength * sizeof(dtPolyRef)); + } + else if (startPolyFound && !endPolyFound) + { + sLog->outDebug(LOG_FILTER_MAPS, "++ BuildPolyPath :: (startPolyFound && !endPolyFound)\n"); + + // we are moving on the old path but target moved out + // so we have atleast part of poly-path ready + + _polyLength -= pathStartIndex; + + // try to adjust the suffix of the path instead of recalculating entire length + // at given interval the target cannot get too far from its last location + // thus we have less poly to cover + // sub-path of optimal path is optimal + + // take ~80% of the original length + /// @todo play with the values here + uint32 prefixPolyLength = uint32(_polyLength * 0.8f + 0.5f); + memmove(_pathPolyRefs, _pathPolyRefs+pathStartIndex, prefixPolyLength * sizeof(dtPolyRef)); + + dtPolyRef suffixStartPoly = _pathPolyRefs[prefixPolyLength-1]; + + // we need any point on our suffix start poly to generate poly-path, so we need last poly in prefix data + float suffixEndPoint[VERTEX_SIZE]; + if (DT_SUCCESS != _navMeshQuery->closestPointOnPoly(suffixStartPoly, endPoint, suffixEndPoint)) + { + // we can hit offmesh connection as last poly - closestPointOnPoly() don't like that + // try to recover by using prev polyref + --prefixPolyLength; + suffixStartPoly = _pathPolyRefs[prefixPolyLength-1]; + if (DT_SUCCESS != _navMeshQuery->closestPointOnPoly(suffixStartPoly, endPoint, suffixEndPoint)) + { + // suffixStartPoly is still invalid, error state + BuildShortcut(); + _type = PATHFIND_NOPATH; + return; + } + } + + // generate suffix + uint32 suffixPolyLength = 0; + dtStatus dtResult = _navMeshQuery->findPath( + suffixStartPoly, // start polygon + endPoly, // end polygon + suffixEndPoint, // start position + endPoint, // end position + &_filter, // polygon search filter + _pathPolyRefs + prefixPolyLength - 1, // [out] path + (int*)&suffixPolyLength, + MAX_PATH_LENGTH-prefixPolyLength); // max number of polygons in output path + + if (!suffixPolyLength || dtResult != DT_SUCCESS) + { + // this is probably an error state, but we'll leave it + // and hopefully recover on the next Update + // we still need to copy our preffix + sLog->outError(LOG_FILTER_MAPS, "%u's Path Build failed: 0 length path", _sourceUnit->GetGUIDLow()); + } + + sLog->outDebug(LOG_FILTER_MAPS, "++ m_polyLength=%u prefixPolyLength=%u suffixPolyLength=%u \n", _polyLength, prefixPolyLength, suffixPolyLength); + + // new path = prefix + suffix - overlap + _polyLength = prefixPolyLength + suffixPolyLength - 1; + } + else + { + sLog->outDebug(LOG_FILTER_MAPS, "++ BuildPolyPath :: (!startPolyFound && !endPolyFound)\n"); + + // either we have no path at all -> first run + // or something went really wrong -> we aren't moving along the path to the target + // just generate new path + + // free and invalidate old path data + Clear(); + + dtStatus dtResult = _navMeshQuery->findPath( + startPoly, // start polygon + endPoly, // end polygon + startPoint, // start position + endPoint, // end position + &_filter, // polygon search filter + _pathPolyRefs, // [out] path + (int*)&_polyLength, + MAX_PATH_LENGTH); // max number of polygons in output path + + if (!_polyLength || dtResult != DT_SUCCESS) + { + // only happens if we passed bad data to findPath(), or navmesh is messed up + sLog->outError(LOG_FILTER_MAPS, "%u's Path Build failed: 0 length path", _sourceUnit->GetGUIDLow()); + BuildShortcut(); + _type = PATHFIND_NOPATH; + return; + } + } + + // by now we know what type of path we can get + if (_pathPolyRefs[_polyLength - 1] == endPoly && !(_type & PATHFIND_INCOMPLETE)) + _type = PATHFIND_NORMAL; + else + _type = PATHFIND_INCOMPLETE; + + // generate the point-path out of our up-to-date poly-path + BuildPointPath(startPoint, endPoint); +} + +void PathGenerator::BuildPointPath(const float *startPoint, const float *endPoint) +{ + float pathPoints[MAX_POINT_PATH_LENGTH*VERTEX_SIZE]; + uint32 pointCount = 0; + dtStatus dtResult = DT_FAILURE; + if (_useStraightPath) + { + dtResult = _navMeshQuery->findStraightPath( + startPoint, // start position + endPoint, // end position + _pathPolyRefs, // current path + _polyLength, // lenth of current path + pathPoints, // [out] path corner points + NULL, // [out] flags + NULL, // [out] shortened path + (int*)&pointCount, + _pointPathLimit); // maximum number of points/polygons to use + } + else + { + dtResult = FindSmoothPath( + startPoint, // start position + endPoint, // end position + _pathPolyRefs, // current path + _polyLength, // length of current path + pathPoints, // [out] path corner points + (int*)&pointCount, + _pointPathLimit); // maximum number of points + } + + if (pointCount < 2 || dtResult != DT_SUCCESS) + { + // only happens if pass bad data to findStraightPath or navmesh is broken + // single point paths can be generated here + /// @todo check the exact cases + sLog->outDebug(LOG_FILTER_MAPS, "++ PathGenerator::BuildPointPath FAILED! path sized %d returned\n", pointCount); + BuildShortcut(); + _type = PATHFIND_NOPATH; + return; + } + else if (pointCount == _pointPathLimit) + { + sLog->outDebug(LOG_FILTER_MAPS, "++ PathGenerator::BuildPointPath FAILED! path sized %d returned, lower than limit set to %d\n", pointCount, _pointPathLimit); + BuildShortcut(); + _type = PATHFIND_SHORT; + return; + } + + _pathPoints.resize(pointCount); + for (uint32 i = 0; i < pointCount; ++i) + _pathPoints[i] = Vector3(pathPoints[i*VERTEX_SIZE+2], pathPoints[i*VERTEX_SIZE], pathPoints[i*VERTEX_SIZE+1]); + + NormalizePath(); + + // first point is always our current location - we need the next one + SetActualEndPosition(_pathPoints[pointCount-1]); + + // force the given destination, if needed + if (_forceDestination && + (!(_type & PATHFIND_NORMAL) || !InRange(GetEndPosition(), GetActualEndPosition(), 1.0f, 1.0f))) + { + // we may want to keep partial subpath + if (Dist3DSqr(GetActualEndPosition(), GetEndPosition()) < 0.3f * Dist3DSqr(GetStartPosition(), GetEndPosition())) + { + SetActualEndPosition(GetEndPosition()); + _pathPoints[_pathPoints.size()-1] = GetEndPosition(); + } + else + { + SetActualEndPosition(GetEndPosition()); + BuildShortcut(); + } + + _type = PathType(PATHFIND_NORMAL | PATHFIND_NOT_USING_PATH); + } + + sLog->outDebug(LOG_FILTER_MAPS, "++ PathGenerator::BuildPointPath path type %d size %d poly-size %d\n", _type, pointCount, _polyLength); +} + +void PathGenerator::NormalizePath() +{ + for (uint32 i = 0; i < _pathPoints.size(); ++i) + _sourceUnit->UpdateAllowedPositionZ(_pathPoints[i].x, _pathPoints[i].y, _pathPoints[i].z); +} + +void PathGenerator::BuildShortcut() +{ + sLog->outDebug(LOG_FILTER_MAPS, "++ BuildShortcut :: making shortcut\n"); + + Clear(); + + // make two point path, our curr pos is the start, and dest is the end + _pathPoints.resize(2); + + // set start and a default next position + _pathPoints[0] = GetStartPosition(); + _pathPoints[1] = GetActualEndPosition(); + + NormalizePath(); + + _type = PATHFIND_SHORTCUT; +} + +void PathGenerator::CreateFilter() +{ + uint16 includeFlags = 0; + uint16 excludeFlags = 0; + + if (_sourceUnit->GetTypeId() == TYPEID_UNIT) + { + Creature* creature = (Creature*)_sourceUnit; + if (creature->canWalk()) + includeFlags |= NAV_GROUND; // walk + + // creatures don't take environmental damage + if (creature->canSwim()) + includeFlags |= (NAV_WATER | NAV_MAGMA | NAV_SLIME); // swim + } + else // assume Player + { + // perfect support not possible, just stay 'safe' + includeFlags |= (NAV_GROUND | NAV_WATER | NAV_MAGMA | NAV_SLIME); + } + + _filter.setIncludeFlags(includeFlags); + _filter.setExcludeFlags(excludeFlags); + + UpdateFilter(); +} + +void PathGenerator::UpdateFilter() +{ + // allow creatures to cheat and use different movement types if they are moved + // forcefully into terrain they can't normally move in + if (_sourceUnit->IsInWater() || _sourceUnit->IsUnderWater()) + { + uint16 includedFlags = _filter.getIncludeFlags(); + includedFlags |= GetNavTerrain(_sourceUnit->GetPositionX(), + _sourceUnit->GetPositionY(), + _sourceUnit->GetPositionZ()); + + _filter.setIncludeFlags(includedFlags); + } +} + +NavTerrain PathGenerator::GetNavTerrain(float x, float y, float z) +{ + LiquidData data; + _sourceUnit->GetBaseMap()->getLiquidStatus(x, y, z, MAP_ALL_LIQUIDS, &data); + + switch (data.type_flags) + { + case MAP_LIQUID_TYPE_WATER: + case MAP_LIQUID_TYPE_OCEAN: + return NAV_WATER; + case MAP_LIQUID_TYPE_MAGMA: + return NAV_MAGMA; + case MAP_LIQUID_TYPE_SLIME: + return NAV_SLIME; + default: + return NAV_GROUND; + } +} + +bool PathGenerator::HaveTile(const Vector3& p) const +{ + int tx = -1, ty = -1; + float point[VERTEX_SIZE] = {p.y, p.z, p.x}; + + _navMesh->calcTileLoc(point, &tx, &ty); + + /// Workaround + /// For some reason, often the tx and ty variables wont get a valid value + /// Use this check to prevent getting negative tile coords and crashing on getTileAt + if (tx < 0 || ty < 0) + return false; + + return (_navMesh->getTileAt(tx, ty) != NULL); +} + +uint32 PathGenerator::FixupCorridor(dtPolyRef* path, uint32 npath, uint32 maxPath, dtPolyRef const* visited, uint32 nvisited) +{ + int32 furthestPath = -1; + int32 furthestVisited = -1; + + // Find furthest common polygon. + for (int32 i = npath-1; i >= 0; --i) + { + bool found = false; + for (int32 j = nvisited-1; j >= 0; --j) + { + if (path[i] == visited[j]) + { + furthestPath = i; + furthestVisited = j; + found = true; + } + } + if (found) + break; + } + + // If no intersection found just return current path. + if (furthestPath == -1 || furthestVisited == -1) + return npath; + + // Concatenate paths. + + // Adjust beginning of the buffer to include the visited. + uint32 req = nvisited - furthestVisited; + uint32 orig = uint32(furthestPath + 1) < npath ? furthestPath + 1 : npath; + uint32 size = npath > orig ? npath - orig : 0; + if (req + size > maxPath) + size = maxPath-req; + + if (size) + memmove(path + req, path + orig, size * sizeof(dtPolyRef)); + + // Store visited + for (uint32 i = 0; i < req; ++i) + path[i] = visited[(nvisited - 1) - i]; + + return req+size; +} + +bool PathGenerator::GetSteerTarget(float const* startPos, float const* endPos, + float minTargetDist, dtPolyRef const* path, uint32 pathSize, + float* steerPos, unsigned char& steerPosFlag, dtPolyRef& steerPosRef) +{ + // Find steer target. + static const uint32 MAX_STEER_POINTS = 3; + float steerPath[MAX_STEER_POINTS*VERTEX_SIZE]; + unsigned char steerPathFlags[MAX_STEER_POINTS]; + dtPolyRef steerPathPolys[MAX_STEER_POINTS]; + uint32 nsteerPath = 0; + dtStatus dtResult = _navMeshQuery->findStraightPath(startPos, endPos, path, pathSize, + steerPath, steerPathFlags, steerPathPolys, (int*)&nsteerPath, MAX_STEER_POINTS); + if (!nsteerPath || DT_SUCCESS != dtResult) + return false; + + // Find vertex far enough to steer to. + uint32 ns = 0; + while (ns < nsteerPath) + { + // Stop at Off-Mesh link or when point is further than slop away. + if ((steerPathFlags[ns] & DT_STRAIGHTPATH_OFFMESH_CONNECTION) || + !InRangeYZX(&steerPath[ns*VERTEX_SIZE], startPos, minTargetDist, 1000.0f)) + break; + ns++; + } + // Failed to find good point to steer to. + if (ns >= nsteerPath) + return false; + + dtVcopy(steerPos, &steerPath[ns*VERTEX_SIZE]); + steerPos[1] = startPos[1]; // keep Z value + steerPosFlag = steerPathFlags[ns]; + steerPosRef = steerPathPolys[ns]; + + return true; +} + +dtStatus PathGenerator::FindSmoothPath(float const* startPos, float const* endPos, + dtPolyRef const* polyPath, uint32 polyPathSize, + float* smoothPath, int* smoothPathSize, uint32 maxSmoothPathSize) +{ + *smoothPathSize = 0; + uint32 nsmoothPath = 0; + + dtPolyRef polys[MAX_PATH_LENGTH]; + memcpy(polys, polyPath, sizeof(dtPolyRef)*polyPathSize); + uint32 npolys = polyPathSize; + + float iterPos[VERTEX_SIZE], targetPos[VERTEX_SIZE]; + if (DT_SUCCESS != _navMeshQuery->closestPointOnPolyBoundary(polys[0], startPos, iterPos)) + return DT_FAILURE; + + if (DT_SUCCESS != _navMeshQuery->closestPointOnPolyBoundary(polys[npolys-1], endPos, targetPos)) + return DT_FAILURE; + + dtVcopy(&smoothPath[nsmoothPath*VERTEX_SIZE], iterPos); + nsmoothPath++; + + // Move towards target a small advancement at a time until target reached or + // when ran out of memory to store the path. + while (npolys && nsmoothPath < maxSmoothPathSize) + { + // Find location to steer towards. + float steerPos[VERTEX_SIZE]; + unsigned char steerPosFlag; + dtPolyRef steerPosRef = INVALID_POLYREF; + + if (!GetSteerTarget(iterPos, targetPos, SMOOTH_PATH_SLOP, polys, npolys, steerPos, steerPosFlag, steerPosRef)) + break; + + bool endOfPath = (steerPosFlag & DT_STRAIGHTPATH_END); + bool offMeshConnection = (steerPosFlag & DT_STRAIGHTPATH_OFFMESH_CONNECTION); + + // Find movement delta. + float delta[VERTEX_SIZE]; + dtVsub(delta, steerPos, iterPos); + float len = dtSqrt(dtVdot(delta,delta)); + // If the steer target is end of path or off-mesh link, do not move past the location. + if ((endOfPath || offMeshConnection) && len < SMOOTH_PATH_STEP_SIZE) + len = 1.0f; + else + len = SMOOTH_PATH_STEP_SIZE / len; + + float moveTgt[VERTEX_SIZE]; + dtVmad(moveTgt, iterPos, delta, len); + + // Move + float result[VERTEX_SIZE]; + const static uint32 MAX_VISIT_POLY = 16; + dtPolyRef visited[MAX_VISIT_POLY]; + + uint32 nvisited = 0; + _navMeshQuery->moveAlongSurface(polys[0], iterPos, moveTgt, &_filter, result, visited, (int*)&nvisited, MAX_VISIT_POLY); + npolys = FixupCorridor(polys, npolys, MAX_PATH_LENGTH, visited, nvisited); + + _navMeshQuery->getPolyHeight(polys[0], result, &result[1]); + result[1] += 0.5f; + dtVcopy(iterPos, result); + + // Handle end of path and off-mesh links when close enough. + if (endOfPath && InRangeYZX(iterPos, steerPos, SMOOTH_PATH_SLOP, 1.0f)) + { + // Reached end of path. + dtVcopy(iterPos, targetPos); + if (nsmoothPath < maxSmoothPathSize) + { + dtVcopy(&smoothPath[nsmoothPath*VERTEX_SIZE], iterPos); + nsmoothPath++; + } + break; + } + else if (offMeshConnection && InRangeYZX(iterPos, steerPos, SMOOTH_PATH_SLOP, 1.0f)) + { + // Advance the path up to and over the off-mesh connection. + dtPolyRef prevRef = INVALID_POLYREF; + dtPolyRef polyRef = polys[0]; + uint32 npos = 0; + while (npos < npolys && polyRef != steerPosRef) + { + prevRef = polyRef; + polyRef = polys[npos]; + npos++; + } + + for (uint32 i = npos; i < npolys; ++i) + polys[i-npos] = polys[i]; + + npolys -= npos; + + // Handle the connection. + float startPos[VERTEX_SIZE], endPos[VERTEX_SIZE]; + if (DT_SUCCESS == _navMesh->getOffMeshConnectionPolyEndPoints(prevRef, polyRef, startPos, endPos)) + { + if (nsmoothPath < maxSmoothPathSize) + { + dtVcopy(&smoothPath[nsmoothPath*VERTEX_SIZE], startPos); + nsmoothPath++; + } + // Move position at the other side of the off-mesh link. + dtVcopy(iterPos, endPos); + _navMeshQuery->getPolyHeight(polys[0], iterPos, &iterPos[1]); + iterPos[1] += 0.5f; + } + } + + // Store results. + if (nsmoothPath < maxSmoothPathSize) + { + dtVcopy(&smoothPath[nsmoothPath*VERTEX_SIZE], iterPos); + nsmoothPath++; + } + } + + *smoothPathSize = nsmoothPath; + + // this is most likely a loop + return nsmoothPath < MAX_POINT_PATH_LENGTH ? DT_SUCCESS : DT_FAILURE; +} + +bool PathGenerator::InRangeYZX(const float* v1, const float* v2, float r, float h) const +{ + const float dx = v2[0] - v1[0]; + const float dy = v2[1] - v1[1]; // elevation + const float dz = v2[2] - v1[2]; + return (dx * dx + dz * dz) < r * r && fabsf(dy) < h; +} + +bool PathGenerator::InRange(Vector3 const& p1, Vector3 const& p2, float r, float h) const +{ + Vector3 d = p1 - p2; + return (d.x * d.x + d.y * d.y) < r * r && fabsf(d.z) < h; +} + +float PathGenerator::Dist3DSqr(Vector3 const& p1, Vector3 const& p2) const +{ + return (p1 - p2).squaredLength(); +} diff --git a/src/server/game/Movement/PathGenerator.h b/src/server/game/Movement/PathGenerator.h new file mode 100644 index 00000000000..d41d3160db5 --- /dev/null +++ b/src/server/game/Movement/PathGenerator.h @@ -0,0 +1,135 @@ +/* + * Copyright (C) 2005-2011 MaNGOS <http://getmangos.com/> + * + * 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 2 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, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#ifndef _PATH_GENERATOR_H +#define _PATH_GENERATOR_H + +#include "SharedDefines.h" +#include "DetourNavMesh.h" +#include "DetourNavMeshQuery.h" +#include "MoveSplineInitArgs.h" + +using Movement::Vector3; +using Movement::PointsArray; + +class Unit; + +// 74*4.0f=296y number_of_points*interval = max_path_len +// this is way more than actual evade range +// I think we can safely cut those down even more +#define MAX_PATH_LENGTH 74 +#define MAX_POINT_PATH_LENGTH 74 + +#define SMOOTH_PATH_STEP_SIZE 4.0f +#define SMOOTH_PATH_SLOP 0.3f + +#define VERTEX_SIZE 3 +#define INVALID_POLYREF 0 + +enum PathType +{ + PATHFIND_BLANK = 0x00, // path not built yet + PATHFIND_NORMAL = 0x01, // normal path + PATHFIND_SHORTCUT = 0x02, // travel through obstacles, terrain, air, etc (old behavior) + PATHFIND_INCOMPLETE = 0x04, // we have partial path to follow - getting closer to target + PATHFIND_NOPATH = 0x08, // no valid path at all or error in generating one + PATHFIND_NOT_USING_PATH = 0x10, // used when we are either flying/swiming or on map w/o mmaps + PATHFIND_SHORT = 0x20, // path is longer or equal to its limited path length +}; + +class PathGenerator +{ + public: + explicit PathGenerator(Unit const* owner); + ~PathGenerator(); + + // Calculate the path from owner to given destination + // return: true if new path was calculated, false otherwise (no change needed) + bool CalculatePath(float destX, float destY, float destZ, bool forceDest = false); + + // option setters - use optional + void SetUseStraightPath(bool useStraightPath) { _useStraightPath = useStraightPath; }; + void SetPathLengthLimit(float distance) { _pointPathLimit = std::min<uint32>(uint32(distance/SMOOTH_PATH_STEP_SIZE), MAX_POINT_PATH_LENGTH); }; + + // result getters + Vector3 const& GetStartPosition() const { return _startPosition; } + Vector3 const& GetEndPosition() const { return _endPosition; } + Vector3 const& GetActualEndPosition() const { return _actualEndPosition; } + + PointsArray const& GetPath() const { return _pathPoints; } + PathType GetPathType() const { return _type; } + + private: + + dtPolyRef _pathPolyRefs[MAX_PATH_LENGTH]; // array of detour polygon references + uint32 _polyLength; // number of polygons in the path + + PointsArray _pathPoints; // our actual (x,y,z) path to the target + PathType _type; // tells what kind of path this is + + bool _useStraightPath; // type of path will be generated + bool _forceDestination; // when set, we will always arrive at given point + uint32 _pointPathLimit; // limit point path size; min(this, MAX_POINT_PATH_LENGTH) + + Vector3 _startPosition; // {x, y, z} of current location + Vector3 _endPosition; // {x, y, z} of the destination + Vector3 _actualEndPosition;// {x, y, z} of the closest possible point to given destination + + Unit const* const _sourceUnit; // the unit that is moving + dtNavMesh const* _navMesh; // the nav mesh + dtNavMeshQuery const* _navMeshQuery; // the nav mesh query used to find the path + + dtQueryFilter _filter; // use single filter for all movements, update it when needed + + void SetStartPosition(Vector3 Point) { _startPosition = Point; } + void SetEndPosition(Vector3 Point) { _actualEndPosition = Point; _endPosition = Point; } + void SetActualEndPosition(Vector3 Point) { _actualEndPosition = Point; } + void NormalizePath(); + + void Clear() + { + _polyLength = 0; + _pathPoints.clear(); + } + + bool InRange(Vector3 const& p1, Vector3 const& p2, float r, float h) const; + float Dist3DSqr(Vector3 const& p1, Vector3 const& p2) const; + bool InRangeYZX(float const* v1, float const* v2, float r, float h) const; + + dtPolyRef GetPathPolyByPosition(dtPolyRef const* polyPath, uint32 polyPathSize, float const* Point, float* Distance = NULL) const; + dtPolyRef GetPolyByLocation(float const* Point, float* Distance) const; + bool HaveTile(Vector3 const& p) const; + + void BuildPolyPath(Vector3 const& startPos, Vector3 const& endPos); + void BuildPointPath(float const* startPoint, float const* endPoint); + void BuildShortcut(); + + NavTerrain GetNavTerrain(float x, float y, float z); + void CreateFilter(); + void UpdateFilter(); + + // smooth path aux functions + uint32 FixupCorridor(dtPolyRef* path, uint32 npath, uint32 maxPath, dtPolyRef const* visited, uint32 nvisited); + bool GetSteerTarget(float const* startPos, float const* endPos, float minTargetDist, dtPolyRef const* path, uint32 pathSize, float* steerPos, + unsigned char& steerPosFlag, dtPolyRef& steerPosRef); + dtStatus FindSmoothPath(float const* startPos, float const* endPos, + dtPolyRef const* polyPath, uint32 polyPathSize, + float* smoothPath, int* smoothPathSize, uint32 smoothPathMaxSize); +}; + +#endif diff --git a/src/server/game/Movement/Spline/MoveSpline.cpp b/src/server/game/Movement/Spline/MoveSpline.cpp index 1e96cd00fd3..e19e4e175bd 100644 --- a/src/server/game/Movement/Spline/MoveSpline.cpp +++ b/src/server/game/Movement/Spline/MoveSpline.cpp @@ -32,7 +32,7 @@ Location MoveSpline::ComputePosition() const ASSERT(Initialized()); float u = 1.f; - int32 seg_time = spline.length(point_Idx,point_Idx+1); + int32 seg_time = spline.length(point_Idx, point_Idx+1); if (seg_time > 0) u = (time_passed - spline.length(point_Idx)) / (float)seg_time; Location c; @@ -103,7 +103,7 @@ struct FallInitializer float start_elevation; inline int32 operator()(Spline<int32>& s, int32 i) { - return Movement::computeFallTime(start_elevation - s.getPoint(i+1).z,false) * 1000.f; + return Movement::computeFallTime(start_elevation - s.getPoint(i+1).z, false) * 1000.f; } }; @@ -125,7 +125,7 @@ struct CommonInitializer void MoveSpline::init_spline(const MoveSplineInitArgs& args) { - const SplineBase::EvaluationMode modes[2] = {SplineBase::ModeLinear,SplineBase::ModeCatmullrom}; + const SplineBase::EvaluationMode modes[2] = {SplineBase::ModeLinear, SplineBase::ModeCatmullrom}; if (args.flags.cyclic) { uint32 cyclic_point = 0; @@ -151,7 +151,7 @@ void MoveSpline::init_spline(const MoveSplineInitArgs& args) spline.initLengths(init); } - // TODO: what to do in such cases? problem is in input data (all points are at same coords) + /// @todo what to do in such cases? problem is in input data (all points are at same coords) if (spline.length() < minimal_duration) { sLog->outError(LOG_FILTER_GENERAL, "MoveSpline::init_spline: zero length spline, wrong input data?"); diff --git a/src/server/game/Movement/Spline/MoveSpline.h b/src/server/game/Movement/Spline/MoveSpline.h index 46611e58447..b18166ea615 100644 --- a/src/server/game/Movement/Spline/MoveSpline.h +++ b/src/server/game/Movement/Spline/MoveSpline.h @@ -27,7 +27,7 @@ namespace Movement struct Location : public Vector3 { Location() : orientation(0) {} - Location(float x, float y, float z, float o) : Vector3(x,y,z), orientation(o) {} + Location(float x, float y, float z, float o) : Vector3(x, y, z), orientation(o) {} Location(const Vector3& v) : Vector3(v), orientation(0) {} Location(const Vector3& v, float o) : Vector3(v), orientation(o) {} @@ -78,18 +78,17 @@ namespace Movement UpdateResult _updateState(int32& ms_time_diff); int32 next_timestamp() const { return spline.length(point_Idx+1); } int32 segment_time_elapsed() const { return next_timestamp()-time_passed; } - int32 Duration() const { return spline.length(); } int32 timeElapsed() const { return Duration() - time_passed; } int32 timePassed() const { return time_passed; } public: + int32 Duration() const { return spline.length(); } const MySpline& _Spline() const { return spline; } int32 _currentSplineIdx() const { return point_Idx; } void _Finalize(); void _Interrupt() { splineflags.done = true;} public: - void Initialize(const MoveSplineInitArgs&); bool Initialized() const { return !spline.empty(); } @@ -101,14 +100,14 @@ namespace Movement ASSERT(Initialized()); do handler(_updateState(difftime)); - while(difftime > 0); + while (difftime > 0); } void updateState(int32 difftime) { ASSERT(Initialized()); do _updateState(difftime); - while(difftime > 0); + while (difftime > 0); } Location ComputePosition() const; diff --git a/src/server/game/Movement/Spline/MoveSplineFlag.h b/src/server/game/Movement/Spline/MoveSplineFlag.h index f3f436c9d00..ec7eaf7e763 100644 --- a/src/server/game/Movement/Spline/MoveSplineFlag.h +++ b/src/server/game/Movement/Spline/MoveSplineFlag.h @@ -27,7 +27,7 @@ namespace Movement #if defined( __GNUC__ ) #pragma pack(1) #else -#pragma pack(push,1) +#pragma pack(push, 1) #endif class MoveSplineFlag diff --git a/src/server/game/Movement/Spline/MoveSplineInit.cpp b/src/server/game/Movement/Spline/MoveSplineInit.cpp index b327d0d0cd6..e661cf877e3 100644 --- a/src/server/game/Movement/Spline/MoveSplineInit.cpp +++ b/src/server/game/Movement/Spline/MoveSplineInit.cpp @@ -58,38 +58,38 @@ namespace Movement return MOVE_RUN; } - void MoveSplineInit::Launch() + int32 MoveSplineInit::Launch() { - MoveSpline& move_spline = *unit.movespline; + MoveSpline& move_spline = *unit->movespline; bool transport = false; - Location real_position(unit.GetPositionX(), unit.GetPositionY(), unit.GetPositionZMinusOffset(), unit.GetOrientation()); + Location real_position(unit->GetPositionX(), unit->GetPositionY(), unit->GetPositionZMinusOffset(), unit->GetOrientation()); // Elevators also use MOVEMENTFLAG_ONTRANSPORT but we do not keep track of their position changes - if (unit.HasUnitMovementFlag(MOVEMENTFLAG_ONTRANSPORT) && unit.GetTransGUID()) + if (unit->HasUnitMovementFlag(MOVEMENTFLAG_ONTRANSPORT) && unit->GetTransGUID()) { transport = true; - real_position.x = unit.GetTransOffsetX(); - real_position.y = unit.GetTransOffsetY(); - real_position.z = unit.GetTransOffsetZ(); - real_position.orientation = unit.GetTransOffsetO(); + real_position.x = unit->GetTransOffsetX(); + real_position.y = unit->GetTransOffsetY(); + real_position.z = unit->GetTransOffsetZ(); + real_position.orientation = unit->GetTransOffsetO(); } // there is a big chance that current position is unknown if current state is not finalized, need compute it - // this also allows calculate spline position and update map position in much greater intervals + // this also allows CalculatePath spline position and update map position in much greater intervals // Don't compute for transport movement if the unit is in a motion between two transports if (!move_spline.Finalized() && move_spline.onTransport == transport) real_position = move_spline.ComputePosition(); // should i do the things that user should do? - no. if (args.path.empty()) - return; + return 0; // corrent first vertex args.path[0] = real_position; args.initialOrientation = real_position.orientation; move_spline.onTransport = transport; - uint32 moveFlags = unit.m_movementInfo.GetMovementFlags(); + uint32 moveFlags = unit->m_movementInfo.GetMovementFlags(); if (args.flags.walkmode) moveFlags |= MOVEMENTFLAG_WALKING; else @@ -98,39 +98,41 @@ namespace Movement moveFlags |= (MOVEMENTFLAG_SPLINE_ENABLED|MOVEMENTFLAG_FORWARD); if (!args.HasVelocity) - args.velocity = unit.GetSpeed(SelectSpeedType(moveFlags)); + args.velocity = unit->GetSpeed(SelectSpeedType(moveFlags)); - if (!args.Validate(&unit)) - return; + if (!args.Validate(unit)) + return 0; if (moveFlags & MOVEMENTFLAG_ROOT) moveFlags &= ~MOVEMENTFLAG_MASK_MOVING; - unit.m_movementInfo.SetMovementFlags((MovementFlags)moveFlags); + unit->m_movementInfo.SetMovementFlags((MovementFlags)moveFlags); move_spline.Initialize(args); WorldPacket data(!transport ? SMSG_MONSTER_MOVE : SMSG_MONSTER_MOVE_TRANSPORT, 64); - data.append(unit.GetPackGUID()); + data.append(unit->GetPackGUID()); if (transport) { - data.appendPackGUID(unit.GetTransGUID()); - data << int8(unit.GetTransSeat()); + data.appendPackGUID(unit->GetTransGUID()); + data << int8(unit->GetTransSeat()); } PacketBuilder::WriteMonsterMove(move_spline, data); - unit.SendMessageToSet(&data,true); + unit->SendMessageToSet(&data,true); + + return move_spline.Duration(); } - MoveSplineInit::MoveSplineInit(Unit& m) : unit(m) + MoveSplineInit::MoveSplineInit(Unit* m) : unit(m) { // Elevators also use MOVEMENTFLAG_ONTRANSPORT but we do not keep track of their position changes - args.TransformForTransport = unit.HasUnitMovementFlag(MOVEMENTFLAG_ONTRANSPORT) && unit.GetTransGUID(); + args.TransformForTransport = unit->HasUnitMovementFlag(MOVEMENTFLAG_ONTRANSPORT) && unit->GetTransGUID(); // mix existing state into new - args.flags.walkmode = unit.m_movementInfo.HasMovementFlag(MOVEMENTFLAG_WALKING); - args.flags.flying = unit.m_movementInfo.HasMovementFlag((MovementFlags)(MOVEMENTFLAG_CAN_FLY|MOVEMENTFLAG_DISABLE_GRAVITY)); + args.flags.walkmode = unit->m_movementInfo.HasMovementFlag(MOVEMENTFLAG_WALKING); + args.flags.flying = unit->m_movementInfo.HasMovementFlag((MovementFlags)(MOVEMENTFLAG_CAN_FLY | MOVEMENTFLAG_DISABLE_GRAVITY)); } - void MoveSplineInit::SetFacing(const Unit * target) + void MoveSplineInit::SetFacing(const Unit* target) { args.flags.EnableFacingTarget(); args.facing.target = target->GetGUID(); @@ -140,9 +142,9 @@ namespace Movement { if (args.TransformForTransport) { - if (Unit* vehicle = unit.GetVehicleBase()) + if (Unit* vehicle = unit->GetVehicleBase()) angle -= vehicle->GetOrientation(); - else if (Transport* transport = unit.GetTransport()) + else if (Transport* transport = unit->GetTransport()) angle -= transport->GetOrientation(); } @@ -150,8 +152,19 @@ namespace Movement args.flags.EnableFacingAngle(); } - void MoveSplineInit::MoveTo(Vector3 const& dest) + void MoveSplineInit::MoveTo(const Vector3& dest, bool generatePath, bool forceDestination) { + if (generatePath) + { + PathGenerator path(unit); + bool result = path.CalculatePath(dest.x, dest.y, dest.z, forceDestination); + if (result && !(path.GetPathType() & PATHFIND_NOPATH)) + { + MovebyPath(path.GetPath()); + return; + } + } + args.path_Idx_offset = 0; args.path.resize(2); TransportPathTransform transform(unit, args.TransformForTransport); @@ -162,7 +175,7 @@ namespace Movement { if (_transformForTransport) { - if (TransportBase* transport = _owner.GetDirectTransport()) + if (TransportBase* transport = _owner->GetDirectTransport()) { float unused = 0.0f; // need reference transport->CalculatePassengerOffset(input.x, input.y, input.z, unused); diff --git a/src/server/game/Movement/Spline/MoveSplineInit.h b/src/server/game/Movement/Spline/MoveSplineInit.h index 8ebac4aec06..441bad66142 100644 --- a/src/server/game/Movement/Spline/MoveSplineInit.h +++ b/src/server/game/Movement/Spline/MoveSplineInit.h @@ -20,6 +20,7 @@ #define TRINITYSERVER_MOVESPLINEINIT_H #include "MoveSplineInitArgs.h" +#include "PathGenerator.h" class Unit; @@ -37,12 +38,12 @@ namespace Movement class TransportPathTransform { public: - TransportPathTransform(Unit& owner, bool transformForTransport) + TransportPathTransform(Unit* owner, bool transformForTransport) : _owner(owner), _transformForTransport(transformForTransport) { } Vector3 operator()(Vector3 input); private: - Unit& _owner; + Unit* _owner; bool _transformForTransport; }; @@ -52,11 +53,11 @@ namespace Movement { public: - explicit MoveSplineInit(Unit& m); + explicit MoveSplineInit(Unit* m); /* Final pass of initialization that launches spline movement. */ - void Launch(); + int32 Launch(); /* Adds movement by parabolic trajectory * @param amplitude - the maximum height of parabola, value could be negative and positive @@ -75,7 +76,7 @@ namespace Movement */ void SetFacing(float angle); void SetFacing(Vector3 const& point); - void SetFacing(const Unit * target); + void SetFacing(const Unit* target); /* Initializes movement by path * @param path - array of points, shouldn't be empty @@ -83,10 +84,10 @@ namespace Movement */ void MovebyPath(const PointsArray& path, int32 pointId = 0); - /* Initializes simple A to B mition, A is current unit's position, B is destination + /* Initializes simple A to B motion, A is current unit's position, B is destination */ - void MoveTo(const Vector3& destination); - void MoveTo(float x, float y, float z); + void MoveTo(const Vector3& destination, bool generatePath = true, bool forceDestination = false); + void MoveTo(float x, float y, float z, bool generatePath = true, bool forceDestination = false); /* Sets Id of fisrt point of the path. When N-th path point will be done ILisener will notify that pointId + N done * Needed for waypoint movement where path splitten into parts @@ -137,7 +138,7 @@ namespace Movement protected: MoveSplineInitArgs args; - Unit& unit; + Unit* unit; }; inline void MoveSplineInit::SetFly() { args.flags.EnableFlying(); } @@ -158,9 +159,9 @@ namespace Movement std::transform(controls.begin(), controls.end(), args.path.begin(), TransportPathTransform(unit, args.TransformForTransport)); } - inline void MoveSplineInit::MoveTo(float x, float y, float z) + inline void MoveSplineInit::MoveTo(float x, float y, float z, bool generatePath, bool forceDestination) { - MoveTo(G3D::Vector3(x, y, z)); + MoveTo(G3D::Vector3(x, y, z), generatePath, forceDestination); } inline void MoveSplineInit::SetParabolic(float amplitude, float time_shift) diff --git a/src/server/game/Movement/Spline/MoveSplineInitArgs.h b/src/server/game/Movement/Spline/MoveSplineInitArgs.h index 32045629c9f..4a086094c3f 100644 --- a/src/server/game/Movement/Spline/MoveSplineInitArgs.h +++ b/src/server/game/Movement/Spline/MoveSplineInitArgs.h @@ -31,7 +31,7 @@ namespace Movement union FacingInfo { struct{ - float x,y,z; + float x, y, z; }f; uint64 target; float angle; diff --git a/src/server/game/Movement/Spline/MovementPacketBuilder.cpp b/src/server/game/Movement/Spline/MovementPacketBuilder.cpp index d747d6f69a6..29d1bb50a8f 100644 --- a/src/server/game/Movement/Spline/MovementPacketBuilder.cpp +++ b/src/server/game/Movement/Spline/MovementPacketBuilder.cpp @@ -1,4 +1,5 @@ /* + * Copyright (C) 2008-2013 TrinityCore <http://www.trinitycore.org/> * Copyright (C) 2005-2011 MaNGOS <http://getmangos.com/> * * This program is free software; you can redistribute it and/or modify @@ -141,11 +142,11 @@ namespace Movement void PacketBuilder::WriteCreate(const MoveSpline& move_spline, ByteBuffer& data) { - //WriteClientStatus(mov,data); + //WriteClientStatus(mov, data); //data.append<float>(&mov.m_float_values[SpeedWalk], SpeedMaxCount); //if (mov.SplineEnabled()) { - MoveSplineFlag splineFlags = move_spline.splineflags; + MoveSplineFlag const& splineFlags = move_spline.splineflags; data << splineFlags.raw(); diff --git a/src/server/game/Movement/Spline/MovementPacketBuilder.h b/src/server/game/Movement/Spline/MovementPacketBuilder.h index 92a414e9b3b..b502e203656 100644 --- a/src/server/game/Movement/Spline/MovementPacketBuilder.h +++ b/src/server/game/Movement/Spline/MovementPacketBuilder.h @@ -1,4 +1,5 @@ /* + * Copyright (C) 2008-2013 TrinityCore <http://www.trinitycore.org/> * Copyright (C) 2005-2011 MaNGOS <http://getmangos.com/> * * This program is free software; you can redistribute it and/or modify diff --git a/src/server/game/Movement/Spline/MovementUtil.cpp b/src/server/game/Movement/Spline/MovementUtil.cpp index b69d4b39e19..99413384dd8 100644 --- a/src/server/game/Movement/Spline/MovementUtil.cpp +++ b/src/server/game/Movement/Spline/MovementUtil.cpp @@ -103,39 +103,39 @@ namespace Movement char const* g_MovementFlag_names[] = { - STR(Forward ),// 0x00000001, - STR(Backward ),// 0x00000002, - STR(Strafe_Left ),// 0x00000004, - STR(Strafe_Right ),// 0x00000008, - STR(Turn_Left ),// 0x00000010, - STR(Turn_Right ),// 0x00000020, - STR(Pitch_Up ),// 0x00000040, - STR(Pitch_Down ),// 0x00000080, - - STR(Walk ),// 0x00000100, // Walking - STR(Ontransport ),// 0x00000200, - STR(Levitation ),// 0x00000400, - STR(Root ),// 0x00000800, - STR(Falling ),// 0x00001000, - STR(Fallingfar ),// 0x00002000, - STR(Pendingstop ),// 0x00004000, - STR(PendingSTRafestop ),// 0x00008000, - STR(Pendingforward ),// 0x00010000, - STR(Pendingbackward ),// 0x00020000, - STR(PendingSTRafeleft ),// 0x00040000, - STR(PendingSTRaferight ),// 0x00080000, - STR(Pendingroot ),// 0x00100000, - STR(Swimming ),// 0x00200000, // Appears With Fly Flag Also - STR(Ascending ),// 0x00400000, // Swim Up Also - STR(Descending ),// 0x00800000, // Swim Down Also - STR(Can_Fly ),// 0x01000000, // Can Fly In 3.3? - STR(Flying ),// 0x02000000, // Actual Flying Mode - STR(Spline_Elevation ),// 0x04000000, // Used For Flight Paths - STR(Spline_Enabled ),// 0x08000000, // Used For Flight Paths - STR(Waterwalking ),// 0x10000000, // Prevent Unit From Falling Through Water - STR(Safe_Fall ),// 0x20000000, // Active Rogue Safe Fall Spell (Passive) - STR(Hover ),// 0x40000000 - STR(Unknown13 ),// 0x80000000 + STR(Forward ), // 0x00000001, + STR(Backward ), // 0x00000002, + STR(Strafe_Left ), // 0x00000004, + STR(Strafe_Right ), // 0x00000008, + STR(Turn_Left ), // 0x00000010, + STR(Turn_Right ), // 0x00000020, + STR(Pitch_Up ), // 0x00000040, + STR(Pitch_Down ), // 0x00000080, + + STR(Walk ), // 0x00000100, // Walking + STR(Ontransport ), // 0x00000200, + STR(Levitation ), // 0x00000400, + STR(Root ), // 0x00000800, + STR(Falling ), // 0x00001000, + STR(Fallingfar ), // 0x00002000, + STR(Pendingstop ), // 0x00004000, + STR(PendingSTRafestop ), // 0x00008000, + STR(Pendingforward ), // 0x00010000, + STR(Pendingbackward ), // 0x00020000, + STR(PendingSTRafeleft ), // 0x00040000, + STR(PendingSTRaferight ), // 0x00080000, + STR(Pendingroot ), // 0x00100000, + STR(Swimming ), // 0x00200000, // Appears With Fly Flag Also + STR(Ascending ), // 0x00400000, // Swim Up Also + STR(Descending ), // 0x00800000, // Swim Down Also + STR(Can_Fly ), // 0x01000000, // Can Fly In 3.3? + STR(Flying ), // 0x02000000, // Actual Flying Mode + STR(Spline_Elevation ), // 0x04000000, // Used For Flight Paths + STR(Spline_Enabled ), // 0x08000000, // Used For Flight Paths + STR(Waterwalking ), // 0x10000000, // Prevent Unit From Falling Through Water + STR(Safe_Fall ), // 0x20000000, // Active Rogue Safe Fall Spell (Passive) + STR(Hover ), // 0x40000000 + STR(Unknown13 ), // 0x80000000 STR(Unk1 ), STR(Unk2 ), STR(Unk3 ), @@ -156,38 +156,38 @@ namespace Movement char const* g_SplineFlag_names[32] = { - STR(AnimBit1 ),// 0x00000001, - STR(AnimBit2 ),// 0x00000002, - STR(AnimBit3 ),// 0x00000004, - STR(AnimBit4 ),// 0x00000008, - STR(AnimBit5 ),// 0x00000010, - STR(AnimBit6 ),// 0x00000020, - STR(AnimBit7 ),// 0x00000040, - STR(AnimBit8 ),// 0x00000080, - STR(Done ),// 0x00000100, - STR(Falling ),// 0x00000200, // Not Compartible With Trajectory Movement - STR(No_Spline ),// 0x00000400, - STR(Trajectory ),// 0x00000800, // Not Compartible With Fall Movement - STR(Walkmode ),// 0x00001000, - STR(Flying ),// 0x00002000, // Smooth Movement(Catmullrom Interpolation Mode), Flying Animation - STR(Knockback ),// 0x00004000, // Model Orientation Fixed - STR(Final_Point ),// 0x00008000, - STR(Final_Target ),// 0x00010000, - STR(Final_Angle ),// 0x00020000, - STR(Catmullrom ),// 0x00040000, // Used Catmullrom Interpolation Mode - STR(Cyclic ),// 0x00080000, // Movement By Cycled Spline - STR(Enter_Cycle ),// 0x00100000, // Everytime Appears With Cyclic Flag In Monster Move Packet - STR(Animation ),// 0x00200000, // Animationid (0...3), Uint32 Time, Not Compartible With Trajectory And Fall Movement - STR(Unknown4 ),// 0x00400000, // Disables Movement By Path - STR(Unknown5 ),// 0x00800000, - STR(Unknown6 ),// 0x01000000, - STR(Unknown7 ),// 0x02000000, - STR(Unknown8 ),// 0x04000000, - STR(OrientationInversed ),// 0x08000000, // Appears With Runmode Flag, Nodes ),// 1, Handles Orientation - STR(Unknown10 ),// 0x10000000, - STR(Unknown11 ),// 0x20000000, - STR(Unknown12 ),// 0x40000000, - STR(Unknown13 ),// 0x80000000, + STR(AnimBit1 ), // 0x00000001, + STR(AnimBit2 ), // 0x00000002, + STR(AnimBit3 ), // 0x00000004, + STR(AnimBit4 ), // 0x00000008, + STR(AnimBit5 ), // 0x00000010, + STR(AnimBit6 ), // 0x00000020, + STR(AnimBit7 ), // 0x00000040, + STR(AnimBit8 ), // 0x00000080, + STR(Done ), // 0x00000100, + STR(Falling ), // 0x00000200, // Not Compartible With Trajectory Movement + STR(No_Spline ), // 0x00000400, + STR(Trajectory ), // 0x00000800, // Not Compartible With Fall Movement + STR(Walkmode ), // 0x00001000, + STR(Flying ), // 0x00002000, // Smooth Movement(Catmullrom Interpolation Mode), Flying Animation + STR(Knockback ), // 0x00004000, // Model Orientation Fixed + STR(Final_Point ), // 0x00008000, + STR(Final_Target ), // 0x00010000, + STR(Final_Angle ), // 0x00020000, + STR(Catmullrom ), // 0x00040000, // Used Catmullrom Interpolation Mode + STR(Cyclic ), // 0x00080000, // Movement By Cycled Spline + STR(Enter_Cycle ), // 0x00100000, // Everytime Appears With Cyclic Flag In Monster Move Packet + STR(Animation ), // 0x00200000, // Animationid (0...3), Uint32 Time, Not Compartible With Trajectory And Fall Movement + STR(Unknown4 ), // 0x00400000, // Disables Movement By Path + STR(Unknown5 ), // 0x00800000, + STR(Unknown6 ), // 0x01000000, + STR(Unknown7 ), // 0x02000000, + STR(Unknown8 ), // 0x04000000, + STR(OrientationInversed ), // 0x08000000, // Appears With Runmode Flag, Nodes ), // 1, Handles Orientation + STR(Unknown10 ), // 0x10000000, + STR(Unknown11 ), // 0x20000000, + STR(Unknown12 ), // 0x40000000, + STR(Unknown13 ), // 0x80000000, }; template<class Flags, int N> diff --git a/src/server/game/Movement/Spline/Spline.cpp b/src/server/game/Movement/Spline/Spline.cpp index 6970acf5415..887541e2289 100644 --- a/src/server/game/Movement/Spline/Spline.cpp +++ b/src/server/game/Movement/Spline/Spline.cpp @@ -59,7 +59,7 @@ SplineBase::InitMethtod SplineBase::initializers[SplineBase::ModesEnd] = using G3D::Matrix4; static const Matrix4 s_catmullRomCoeffs( - -0.5f, 1.5f,-1.5f, 0.5f, + -0.5f, 1.5f, -1.5f, 0.5f, 1.f, -2.5f, 2.f, -0.5f, -0.5f, 0.f, 0.5f, 0.f, 0.f, 1.f, 0.f, 0.f); @@ -222,7 +222,7 @@ void SplineBase::InitLinear(const Vector3* controls, index_type count, bool cycl points.resize(real_size); - memcpy(&points[0],controls, sizeof(Vector3) * count); + memcpy(&points[0], controls, sizeof(Vector3) * count); // first and last two indexes are space for special 'virtual points' // these points are required for proper C_Evaluate and C_Evaluate_Derivative methtod work @@ -244,7 +244,7 @@ void SplineBase::InitCatmullRom(const Vector3* controls, index_type count, bool int lo_index = 1; int high_index = lo_index + count - 1; - memcpy(&points[lo_index],controls, sizeof(Vector3) * count); + memcpy(&points[lo_index], controls, sizeof(Vector3) * count); // first and last two indexes are space for special 'virtual points' // these points are required for proper C_Evaluate and C_Evaluate_Derivative methtod work @@ -274,7 +274,7 @@ void SplineBase::InitBezier3(const Vector3* controls, index_type count, bool /*c index_type t = c / 3u; points.resize(c); - memcpy(&points[0],controls, sizeof(Vector3) * c); + memcpy(&points[0], controls, sizeof(Vector3) * c); index_lo = 0; index_hi = t-1; diff --git a/src/server/game/Movement/Spline/Spline.h b/src/server/game/Movement/Spline/Spline.h index 63e61b84579..2a2f3fa8f43 100644 --- a/src/server/game/Movement/Spline/Spline.h +++ b/src/server/game/Movement/Spline/Spline.h @@ -61,7 +61,7 @@ protected: void EvaluateLinear(index_type, float, Vector3&) const; void EvaluateCatmullRom(index_type, float, Vector3&) const; void EvaluateBezier3(index_type, float, Vector3&) const; - typedef void (SplineBase::*EvaluationMethtod)(index_type,float,Vector3&) const; + typedef void (SplineBase::*EvaluationMethtod)(index_type, float, Vector3&) const; static EvaluationMethtod evaluators[ModesEnd]; void EvaluateDerivativeLinear(index_type, float, Vector3&) const; @@ -91,13 +91,13 @@ public: @param t - percent of segment length, assumes that t in range [0, 1] @param Idx - spline segment index, should be in range [first, last) */ - void evaluate_percent(index_type Idx, float u, Vector3& c) const {(this->*evaluators[m_mode])(Idx,u,c);} + void evaluate_percent(index_type Idx, float u, Vector3& c) const {(this->*evaluators[m_mode])(Idx, u,c);} /** Caclulates derivation in index Idx, and percent of segment length t @param Idx - spline segment index, should be in range [first, last) @param t - percent of spline segment length, assumes that t in range [0, 1] */ - void evaluate_derivative(index_type Idx, float u, Vector3& hermite) const {(this->*derivative_evaluators[m_mode])(Idx,u,hermite);} + void evaluate_derivative(index_type Idx, float u, Vector3& hermite) const {(this->*derivative_evaluators[m_mode])(Idx, u,hermite);} /** Bounds for spline indexes. All indexes should be in range [first, last). */ index_type first() const { return index_lo;} @@ -119,7 +119,7 @@ public: would be no harm to have some custom initializers. */ template<class Init> inline void init_spline(Init& initializer) { - initializer(m_mode,cyclic,points,index_lo,index_hi); + initializer(m_mode, cyclic, points, index_lo, index_hi); } void clear(); @@ -156,20 +156,20 @@ public: /** Calculates the position for given segment Idx, and percent of segment length t @param t = partial_segment_length / whole_segment_length @param Idx - spline segment index, should be in range [first, last). */ - void evaluate_percent(index_type Idx, float u, Vector3& c) const { SplineBase::evaluate_percent(Idx,u,c);} + void evaluate_percent(index_type Idx, float u, Vector3& c) const { SplineBase::evaluate_percent(Idx, u,c);} /** Caclulates derivation for index Idx, and percent of segment length t @param Idx - spline segment index, should be in range [first, last) @param t - percent of spline segment length, assumes that t in range [0, 1]. */ - void evaluate_derivative(index_type Idx, float u, Vector3& c) const { SplineBase::evaluate_derivative(Idx,u,c);} + void evaluate_derivative(index_type Idx, float u, Vector3& c) const { SplineBase::evaluate_derivative(Idx, u,c);} // Assumes that t in range [0, 1] index_type computeIndexInBounds(float t) const; void computeIndex(float t, index_type& out_idx, float& out_u) const; /** Initializes spline. Don't call other methods while spline not initialized. */ - void init_spline(const Vector3 * controls, index_type count, EvaluationMode m) { SplineBase::init_spline(controls,count,m);} - void init_cyclic_spline(const Vector3 * controls, index_type count, EvaluationMode m, index_type cyclic_point) { SplineBase::init_cyclic_spline(controls,count,m,cyclic_point);} + void init_spline(const Vector3 * controls, index_type count, EvaluationMode m) { SplineBase::init_spline(controls, count, m);} + void init_cyclic_spline(const Vector3 * controls, index_type count, EvaluationMode m, index_type cyclic_point) { SplineBase::init_cyclic_spline(controls, count, m,cyclic_point);} /** Initializes lengths with SplineBase::SegLength method. */ void initLengths(); @@ -181,7 +181,7 @@ public: index_type i = index_lo; lengths.resize(index_hi+1); length_type prev_length = 0, new_length = 0; - while(i < index_hi) + while (i < index_hi) { new_length = cacher(*this, i); lengths[++i] = new_length; diff --git a/src/server/game/Movement/Spline/SplineImpl.h b/src/server/game/Movement/Spline/SplineImpl.h index eded2d8c903..98f3f5fe079 100644 --- a/src/server/game/Movement/Spline/SplineImpl.h +++ b/src/server/game/Movement/Spline/SplineImpl.h @@ -81,7 +81,7 @@ template<typename length_type> void Spline<length_type>::initLengths() index_type i = index_lo; length_type length = 0; lengths.resize(index_hi+1); - while(i < index_hi ) + while (i < index_hi) { length += SegLength(i); lengths[++i] = length; diff --git a/src/server/game/Movement/Waypoints/Path.h b/src/server/game/Movement/Waypoints/Path.h index 3f78a640384..39f05184cf6 100644 --- a/src/server/game/Movement/Waypoints/Path.h +++ b/src/server/game/Movement/Waypoints/Path.h @@ -20,10 +20,12 @@ #define TRINITYCORE_PATH_H #include "Common.h" -#include <vector> +#include <deque> -struct SimplePathNode +struct PathNode { + PathNode(): x(0.0f), y(0.0f), z(0.0f) { } + PathNode(float _x, float _y, float _z): x(_x), y(_y), z(_z) { } float x, y, z; }; template<typename PathElem, typename PathNode = PathElem> @@ -36,6 +38,20 @@ class Path void resize(unsigned int sz) { i_nodes.resize(sz); } void clear() { i_nodes.clear(); } void erase(uint32 idx) { i_nodes.erase(i_nodes.begin()+idx); } + void crop(unsigned int start, unsigned int end) + { + while(start && !i_nodes.empty()) + { + i_nodes.pop_front(); + --start; + } + + while(end && !i_nodes.empty()) + { + i_nodes.pop_back(); + --end; + } + } float GetTotalLength(uint32 start, uint32 end) const { @@ -76,10 +92,9 @@ class Path void set(size_t idx, PathElem elem) { i_nodes[idx] = elem; } protected: - std::vector<PathElem> i_nodes; + std::deque<PathElem> i_nodes; }; -typedef Path<SimplePathNode> SimplePath; +typedef Path<PathNode> SimplePath; #endif - diff --git a/src/server/game/Movement/Waypoints/WaypointManager.cpp b/src/server/game/Movement/Waypoints/WaypointManager.cpp index 6f9da3931af..6fba8308077 100644 --- a/src/server/game/Movement/Waypoints/WaypointManager.cpp +++ b/src/server/game/Movement/Waypoints/WaypointManager.cpp @@ -48,8 +48,7 @@ void WaypointMgr::Load() if (!result) { - sLog->outError(LOG_FILTER_SQL, ">> Loaded 0 waypoints. DB table `waypoint_data` is empty!"); - + sLog->outError(LOG_FILTER_SERVER_LOADING, ">> Loaded 0 waypoints. DB table `waypoint_data` is empty!"); return; } @@ -87,7 +86,6 @@ void WaypointMgr::Load() while (result->NextRow()); sLog->outInfo(LOG_FILTER_SERVER_LOADING, ">> Loaded %u waypoints in %u ms", count, GetMSTimeDiffToNow(oldMSTime)); - } void WaypointMgr::ReloadPath(uint32 id) diff --git a/src/server/game/Movement/Waypoints/WaypointManager.h b/src/server/game/Movement/Waypoints/WaypointManager.h index 07f855380f9..b17714f1a51 100644 --- a/src/server/game/Movement/Waypoints/WaypointManager.h +++ b/src/server/game/Movement/Waypoints/WaypointManager.h @@ -68,4 +68,3 @@ class WaypointMgr #define sWaypointMgr ACE_Singleton<WaypointMgr, ACE_Null_Mutex>::instance() #endif - diff --git a/src/server/game/OutdoorPvP/OutdoorPvP.cpp b/src/server/game/OutdoorPvP/OutdoorPvP.cpp index bb7dea76461..93bf7edc7d5 100644 --- a/src/server/game/OutdoorPvP/OutdoorPvP.cpp +++ b/src/server/game/OutdoorPvP/OutdoorPvP.cpp @@ -392,7 +392,7 @@ void OutdoorPvP::SendUpdateWorldState(uint32 field, uint32 value) if (m_sendUpdate) for (int i = 0; i < 2; ++i) for (PlayerSet::iterator itr = m_players[i].begin(); itr != m_players[i].end(); ++itr) - if (Player * const player = ObjectAccessor::FindPlayer(*itr)) + if (Player* const player = ObjectAccessor::FindPlayer(*itr)) player->SendUpdateWorldState(field, value); } @@ -402,7 +402,7 @@ void OPvPCapturePoint::SendUpdateWorldState(uint32 field, uint32 value) { // send to all players present in the area for (PlayerSet::iterator itr = m_activePlayers[team].begin(); itr != m_activePlayers[team].end(); ++itr) - if (Player * const player = ObjectAccessor::FindPlayer(*itr)) + if (Player* const player = ObjectAccessor::FindPlayer(*itr)) player->SendUpdateWorldState(field, value); } } @@ -424,7 +424,7 @@ void OPvPCapturePoint::SendObjectiveComplete(uint32 id, uint64 guid) // send to all players present in the area for (PlayerSet::iterator itr = m_activePlayers[team].begin(); itr != m_activePlayers[team].end(); ++itr) - if (Player * const player = ObjectAccessor::FindPlayer(*itr)) + if (Player* const player = ObjectAccessor::FindPlayer(*itr)) player->KilledMonsterCredit(id, guid); } @@ -563,7 +563,7 @@ void OutdoorPvP::BroadcastPacket(WorldPacket &data) const // This is faster than sWorld->SendZoneMessage for (uint32 team = 0; team < 2; ++team) for (PlayerSet::const_iterator itr = m_players[team].begin(); itr != m_players[team].end(); ++itr) - if (Player * const player = ObjectAccessor::FindPlayer(*itr)) + if (Player* const player = ObjectAccessor::FindPlayer(*itr)) player->GetSession()->SendPacket(&data); } @@ -583,13 +583,13 @@ void OutdoorPvP::TeamCastSpell(TeamId team, int32 spellId) if (spellId > 0) { for (PlayerSet::iterator itr = m_players[team].begin(); itr != m_players[team].end(); ++itr) - if (Player * const player = ObjectAccessor::FindPlayer(*itr)) + if (Player* const player = ObjectAccessor::FindPlayer(*itr)) player->CastSpell(player, (uint32)spellId, true); } else { for (PlayerSet::iterator itr = m_players[team].begin(); itr != m_players[team].end(); ++itr) - if (Player * const player = ObjectAccessor::FindPlayer(*itr)) + if (Player* const player = ObjectAccessor::FindPlayer(*itr)) player->RemoveAura((uint32)-spellId); // by stack? } } diff --git a/src/server/game/OutdoorPvP/OutdoorPvP.h b/src/server/game/OutdoorPvP/OutdoorPvP.h index 5f1607843fb..1e23f87a52e 100644 --- a/src/server/game/OutdoorPvP/OutdoorPvP.h +++ b/src/server/game/OutdoorPvP/OutdoorPvP.h @@ -285,7 +285,7 @@ class OutdoorPvP : public ZoneScript void RegisterZone(uint32 zoneid); - bool HasPlayer(Player const * player) const; + bool HasPlayer(Player const* player) const; void TeamCastSpell(TeamId team, int32 spellId); }; diff --git a/src/server/game/Quests/QuestDef.cpp b/src/server/game/Quests/QuestDef.cpp index 8bc628b853d..3fefa812489 100644 --- a/src/server/game/Quests/QuestDef.cpp +++ b/src/server/game/Quests/QuestDef.cpp @@ -207,6 +207,14 @@ int32 Quest::GetRewOrReqMoney() const return int32(RewardOrRequiredMoney * sWorld->getRate(RATE_DROP_MONEY)); } +uint32 Quest::GetRewMoneyMaxLevel() const +{ + if (HasFlag(QUEST_FLAGS_NO_MONEY_FROM_XP)) + return 0; + + return RewardMoneyMaxLevel; +} + bool Quest::IsAutoAccept() const { return sWorld->getBoolConfig(CONFIG_QUEST_IGNORE_AUTO_ACCEPT) ? false : (Flags & QUEST_FLAGS_AUTO_ACCEPT); diff --git a/src/server/game/Quests/QuestDef.h b/src/server/game/Quests/QuestDef.h index 9073c5d1441..a447f4a8f52 100644 --- a/src/server/game/Quests/QuestDef.h +++ b/src/server/game/Quests/QuestDef.h @@ -124,27 +124,27 @@ enum __QuestGiverStatus enum QuestFlags { // Flags used at server and sent to client - QUEST_FLAGS_NONE = 0x00000000, - QUEST_FLAGS_STAY_ALIVE = 0x00000001, // Not used currently - QUEST_FLAGS_PARTY_ACCEPT = 0x00000002, // 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 = 0x00000004, // Not used currently - QUEST_FLAGS_SHARABLE = 0x00000008, // Can be shared: Player::CanShareQuest() - //QUEST_FLAGS_NONE2 = 0x00000010, // Not used currently - QUEST_FLAGS_EPIC = 0x00000020, // Not used currently: Unsure of content - QUEST_FLAGS_RAID = 0x00000040, // Not used currently - QUEST_FLAGS_TBC = 0x00000080, // Not used currently: Available if TBC expansion enabled only - QUEST_FLAGS_DELIVER_MORE = 0x00000100, // Not used currently: _DELIVER_MORE Quest needs more than normal _q-item_ drops from mobs - QUEST_FLAGS_HIDDEN_REWARDS = 0x00000200, // 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_AUTO_REWARDED = 0x00000400, // These quests are automatically rewarded on quest complete and they will never appear in quest log client side. - QUEST_FLAGS_TBC_RACES = 0x00000800, // Not used currently: Blood elf/Draenei starting zone quests - QUEST_FLAGS_DAILY = 0x00001000, // Used to know quest is Daily one - QUEST_FLAGS_REPEATABLE = 0x00002000, // Used on repeatable quests (3.0.0+) - QUEST_FLAGS_UNAVAILABLE = 0x00004000, // Used on quests that are not generically available - QUEST_FLAGS_WEEKLY = 0x00008000, - QUEST_FLAGS_AUTOCOMPLETE = 0x00010000, // auto complete - QUEST_FLAGS_SPECIAL_ITEM = 0x00020000, // has something to do with RequiredItemId and SourceItemId - QUEST_FLAGS_OBJ_TEXT = 0x00040000, // use Objective text as Complete text - QUEST_FLAGS_AUTO_ACCEPT = 0x00080000, // 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. + QUEST_FLAGS_NONE = 0x00000000, + QUEST_FLAGS_STAY_ALIVE = 0x00000001, // Not used currently + QUEST_FLAGS_PARTY_ACCEPT = 0x00000002, // 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 = 0x00000004, // Not used currently + QUEST_FLAGS_SHARABLE = 0x00000008, // Can be shared: Player::CanShareQuest() + QUEST_FLAGS_HAS_CONDITION = 0x00000010, // Not used currently + QUEST_FLAGS_HIDE_REWARD_POI = 0x00000020, // Not used currently: Unsure of content + QUEST_FLAGS_RAID = 0x00000040, // Not used currently + QUEST_FLAGS_TBC = 0x00000080, // Not used currently: Available if TBC expansion enabled only + QUEST_FLAGS_NO_MONEY_FROM_XP = 0x00000100, // Not used currently: Experience is not converted to gold at max level + QUEST_FLAGS_HIDDEN_REWARDS = 0x00000200, // 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 = 0x00000400, // These quests are automatically rewarded on quest complete and they will never appear in quest log client side. + QUEST_FLAGS_DEPRECATE_REPUTATION = 0x00000800, // Not used currently + QUEST_FLAGS_DAILY = 0x00001000, // Used to know quest is Daily one + QUEST_FLAGS_FLAGS_PVP = 0x00002000, // Having this quest in log forces PvP flag + QUEST_FLAGS_UNAVAILABLE = 0x00004000, // Used on quests that are not generically available + QUEST_FLAGS_WEEKLY = 0x00008000, + QUEST_FLAGS_AUTOCOMPLETE = 0x00010000, // auto complete + QUEST_FLAGS_DISPLAY_ITEM_IN_TRACKER = 0x00020000, // Displays usable item in quest tracker + QUEST_FLAGS_OBJ_TEXT = 0x00040000, // use Objective text as Complete text + QUEST_FLAGS_AUTO_ACCEPT = 0x00080000, // 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. // Trinity flags for set SpecialFlags in DB if required but used only at server QUEST_TRINITY_FLAGS_REPEATABLE = 0x00100000, // Set by 1 in SpecialFlags from DB @@ -234,7 +234,7 @@ class Quest int32 GetRewOrReqMoney() const; uint32 GetRewHonorAddition() const { return RewardHonor; } float GetRewHonorMultiplier() const { return RewardHonorMultiplier; } - uint32 GetRewMoneyMaxLevel() const { return RewardMoneyMaxLevel; } // use in XP calculation at client + uint32 GetRewMoneyMaxLevel() const; // use in XP calculation at client uint32 GetRewSpell() const { return RewardSpell; } int32 GetRewSpellCast() const { return RewardSpellCast; } uint32 GetRewMailTemplateId() const { return RewardMailTemplateId; } diff --git a/src/server/game/Scripting/MapScripts.cpp b/src/server/game/Scripting/MapScripts.cpp index 6cd6a72a06a..d36e351ba9d 100644 --- a/src/server/game/Scripting/MapScripts.cpp +++ b/src/server/game/Scripting/MapScripts.cpp @@ -476,7 +476,7 @@ void Map::ScriptsProcess() // Source or target must be Creature. if (Creature* cSource = _GetScriptCreatureSourceOrTarget(source, target, step.script)) { - Unit * unit = (Unit*)cSource; + Unit* unit = (Unit*)cSource; if (step.script->MoveTo.TravelTime != 0) { float speed = unit->GetDistance(step.script->MoveTo.DestX, step.script->MoveTo.DestY, step.script->MoveTo.DestZ) / ((float)step.script->MoveTo.TravelTime * 0.001f); @@ -698,7 +698,7 @@ void Map::ScriptsProcess() case SCRIPT_COMMAND_CAST_SPELL: { - // TODO: Allow gameobjects to be targets and casters + /// @todo Allow gameobjects to be targets and casters if (!source && !target) { sLog->outError(LOG_FILTER_TSCR, "%s source and target objects are NULL.", step.script->GetDebugInfo().c_str()); diff --git a/src/server/game/Scripting/ScriptLoader.cpp b/src/server/game/Scripting/ScriptLoader.cpp index 479979f177f..845c3fa704d 100644 --- a/src/server/game/Scripting/ScriptLoader.cpp +++ b/src/server/game/Scripting/ScriptLoader.cpp @@ -52,6 +52,7 @@ void AddSC_cast_commandscript(); void AddSC_character_commandscript(); void AddSC_cheat_commandscript(); void AddSC_debug_commandscript(); +void AddSC_deserter_commandscript(); void AddSC_disable_commandscript(); void AddSC_event_commandscript(); void AddSC_gm_commandscript(); @@ -66,9 +67,11 @@ void AddSC_list_commandscript(); void AddSC_lookup_commandscript(); void AddSC_message_commandscript(); void AddSC_misc_commandscript(); +void AddSC_mmaps_commandscript(); void AddSC_modify_commandscript(); void AddSC_npc_commandscript(); void AddSC_quest_commandscript(); +void AddSC_rbac_commandscript(); void AddSC_reload_commandscript(); void AddSC_reset_commandscript(); void AddSC_server_commandscript(); @@ -590,6 +593,7 @@ void AddSC_boss_high_astromancer_solarian(); void AddSC_instance_the_eye(); void AddSC_the_eye(); void AddSC_boss_gatewatcher_iron_hand(); //TK The Mechanar +void AddSC_boss_gatewatcher_gyrokill(); void AddSC_boss_nethermancer_sepethrea(); void AddSC_boss_pathaleon_the_calculator(); void AddSC_boss_mechano_lord_capacitus(); @@ -680,6 +684,7 @@ void AddCommandScripts() AddSC_character_commandscript(); AddSC_cheat_commandscript(); AddSC_debug_commandscript(); + AddSC_deserter_commandscript(); AddSC_disable_commandscript(); AddSC_event_commandscript(); AddSC_gm_commandscript(); @@ -694,9 +699,11 @@ void AddCommandScripts() AddSC_list_commandscript(); AddSC_message_commandscript(); AddSC_misc_commandscript(); + AddSC_mmaps_commandscript(); AddSC_modify_commandscript(); AddSC_npc_commandscript(); AddSC_quest_commandscript(); + AddSC_rbac_commandscript(); AddSC_reload_commandscript(); AddSC_reset_commandscript(); AddSC_server_commandscript(); @@ -1073,6 +1080,7 @@ void AddOutlandScripts() AddSC_instance_the_eye(); AddSC_the_eye(); AddSC_boss_gatewatcher_iron_hand(); //TK The Mechanar + AddSC_boss_gatewatcher_gyrokill(); AddSC_boss_nethermancer_sepethrea(); AddSC_boss_pathaleon_the_calculator(); AddSC_boss_mechano_lord_capacitus(); diff --git a/src/server/game/Scripting/ScriptMgr.cpp b/src/server/game/Scripting/ScriptMgr.cpp index cae8ea9d2d5..21eb6f74221 100644 --- a/src/server/game/Scripting/ScriptMgr.cpp +++ b/src/server/game/Scripting/ScriptMgr.cpp @@ -489,14 +489,14 @@ void ScriptMgr::OnGroupRateCalculation(float& rate, uint32 count, bool isRaid) } #define SCR_MAP_BGN(M, V, I, E, C, T) \ - if (V->GetEntry()->T()) \ + if (V->GetEntry() && V->GetEntry()->T()) \ { \ FOR_SCRIPTS(M, I, E) \ { \ MapEntry const* C = I->second->GetEntry(); \ if (!C) \ continue; \ - if (entry->MapID == V->GetId()) \ + if (C->MapID == V->GetId()) \ { #define SCR_MAP_END \ @@ -580,6 +580,8 @@ void ScriptMgr::OnPlayerEnterMap(Map* map, Player* player) ASSERT(map); ASSERT(player); + FOREACH_SCRIPT(PlayerScript)->OnMapChanged(player); + SCR_MAP_BGN(WorldMapScript, map, itr, end, entry, IsWorldMap); itr->second->OnPlayerEnter(map, player); SCR_MAP_END; @@ -764,7 +766,7 @@ uint32 ScriptMgr::GetDialogStatus(Player* player, Creature* creature) ASSERT(player); ASSERT(creature); - // TODO: 100 is a funny magic number to have hanging around here... + /// @todo 100 is a funny magic number to have hanging around here... GET_SCRIPT_RET(CreatureScript, creature->GetScriptId(), tmpscript, 100); player->PlayerTalkClass->ClearMenus(); return tmpscript->GetDialogStatus(player, creature); @@ -850,7 +852,7 @@ uint32 ScriptMgr::GetDialogStatus(Player* player, GameObject* go) ASSERT(player); ASSERT(go); - // TODO: 100 is a funny magic number to have hanging around here... + /// @todo 100 is a funny magic number to have hanging around here... GET_SCRIPT_RET(GameObjectScript, go->GetScriptId(), tmpscript, 100); player->PlayerTalkClass->ClearMenus(); return tmpscript->GetDialogStatus(player, go); @@ -916,7 +918,7 @@ bool ScriptMgr::OnAreaTrigger(Player* player, AreaTriggerEntry const* trigger) Battleground* ScriptMgr::CreateBattleground(BattlegroundTypeId /*typeId*/) { - // TODO: Implement script-side battlegrounds. + /// @todo Implement script-side battlegrounds. ASSERT(false); return NULL; } diff --git a/src/server/game/Scripting/ScriptMgr.h b/src/server/game/Scripting/ScriptMgr.h index 7f140cfffe0..480a7f6cea1 100644 --- a/src/server/game/Scripting/ScriptMgr.h +++ b/src/server/game/Scripting/ScriptMgr.h @@ -71,7 +71,7 @@ struct OutdoorPvPData; /* - TODO: Add more script type classes. + @todo Add more script type classes. MailScript SessionScript @@ -754,6 +754,9 @@ class PlayerScript : public UnitScript // Called when a player switches to a new zone virtual void OnUpdateZone(Player* /*player*/, uint32 /*newZone*/, uint32 /*newArea*/) { } + + // Called when a player changes to a new map (after moving to new map) + virtual void OnMapChanged(Player* /*player*/) { } }; class GuildScript : public ScriptObject diff --git a/src/server/game/Scripting/ScriptSystem.h b/src/server/game/Scripting/ScriptSystem.h index cc65d493f3e..0641cebd18f 100644 --- a/src/server/game/Scripting/ScriptSystem.h +++ b/src/server/game/Scripting/ScriptSystem.h @@ -10,7 +10,7 @@ #define TEXT_SOURCE_RANGE -1000000 //the amount of entries each text source has available -//TODO: find better namings and definitions. +/// @todo find better namings and definitions. //N=Neutral, A=Alliance, H=Horde. //NEUTRAL or FRIEND = Hostility to player surroundings (not a good definition) //ACTIVE or PASSIVE = Hostility to environment surroundings. diff --git a/src/server/game/Server/Protocol/PacketLog.cpp b/src/server/game/Server/Protocol/PacketLog.cpp index 649f4130c06..fe8b6804020 100644 --- a/src/server/game/Server/Protocol/PacketLog.cpp +++ b/src/server/game/Server/Protocol/PacketLog.cpp @@ -55,7 +55,7 @@ void PacketLog::LogPacket(WorldPacket const& packet, Direction direction) data << uint8(direction); for (uint32 i = 0; i < packet.size(); i++) - data << const_cast<WorldPacket&>(packet)[i]; + data << packet[i]; fwrite(data.contents(), 1, data.size(), _file); fflush(_file); diff --git a/src/server/game/Server/WorldSession.cpp b/src/server/game/Server/WorldSession.cpp index 484a382c988..5e91f0f2464 100644 --- a/src/server/game/Server/WorldSession.cpp +++ b/src/server/game/Server/WorldSession.cpp @@ -21,8 +21,10 @@ */ #include "WorldSocket.h" // must be first to make ACE happy with ACE includes in it +#include "Config.h" #include "Common.h" #include "DatabaseEnv.h" +#include "AccountMgr.h" #include "Log.h" #include "Opcodes.h" #include "WorldPacket.h" @@ -95,17 +97,29 @@ bool WorldSessionFilter::Process(WorldPacket* packet) /// WorldSession constructor WorldSession::WorldSession(uint32 id, WorldSocket* sock, AccountTypes sec, uint8 expansion, time_t mute_time, LocaleConstant locale, uint32 recruiter, bool isARecruiter): -m_muteTime(mute_time), m_timeOutTime(0), _player(NULL), m_Socket(sock), -_security(sec), _accountId(id), m_expansion(expansion), _logoutTime(0), -m_inQueue(false), m_playerLoading(false), m_playerLogout(false), -m_playerRecentlyLogout(false), m_playerSave(false), -m_sessionDbcLocale(sWorld->GetAvailableDbcLocale(locale)), -m_sessionDbLocaleIndex(locale), -m_latency(0), m_TutorialsChanged(false), recruiterId(recruiter), -isRecruiter(isARecruiter), timeLastWhoCommand(0) + m_muteTime(mute_time), + m_timeOutTime(0), + _player(NULL), + m_Socket(sock), + _security(sec), + _accountId(id), + m_expansion(expansion), + _warden(NULL), + _logoutTime(0), + m_inQueue(false), + m_playerLoading(false), + m_playerLogout(false), + m_playerRecentlyLogout(false), + m_playerSave(false), + m_sessionDbcLocale(sWorld->GetAvailableDbcLocale(locale)), + m_sessionDbLocaleIndex(locale), + m_latency(0), + m_TutorialsChanged(false), + recruiterId(recruiter), + isRecruiter(isARecruiter), + timeLastWhoCommand(0), + _RBACData(NULL) { - _warden = NULL; - if (sock) { m_Address = sock->GetRemoteAddress(); @@ -132,8 +146,8 @@ WorldSession::~WorldSession() m_Socket = NULL; } - if (_warden) - delete _warden; + delete _warden; + delete _RBACData; ///- empty incoming packet queue WorldPacket* packet = NULL; @@ -395,14 +409,14 @@ bool WorldSession::Update(uint32 diff, PacketFilter& updater) } /// %Log the player out -void WorldSession::LogoutPlayer(bool Save) +void WorldSession::LogoutPlayer(bool save) { // finish pending transfers before starting the logout while (_player && _player->IsBeingTeleportedFar()) HandleMoveWorldportAckOpcode(); m_playerLogout = true; - m_playerSave = Save; + m_playerSave = save; if (_player) { @@ -417,39 +431,6 @@ void WorldSession::LogoutPlayer(bool Save) _player->BuildPlayerRepop(); _player->RepopAtGraveyard(); } - else if (!_player->getAttackers().empty()) - { - // build set of player who attack _player or who have pet attacking of _player - std::set<Player*> aset; - for (Unit::AttackerSet::const_iterator itr = _player->getAttackers().begin(); itr != _player->getAttackers().end(); ++itr) - { - Unit* owner = (*itr)->GetOwner(); // including player controlled case - if (owner && owner->GetTypeId() == TYPEID_PLAYER) - aset.insert(owner->ToPlayer()); - else if ((*itr)->GetTypeId() == TYPEID_PLAYER) - aset.insert((Player*)(*itr)); - } - - // CombatStop() method is removing all attackers from the AttackerSet - // That is why it must be AFTER building current set of attackers - _player->CombatStop(); - _player->getHostileRefManager().setOnlineOfflineState(false); - _player->RemoveAllAurasOnDeath(); - _player->SetPvPDeath(!aset.empty()); - _player->KillPlayer(); - _player->BuildPlayerRepop(); - _player->RepopAtGraveyard(); - - // give honor to all attackers from set like group case - for (std::set<Player*>::const_iterator itr = aset.begin(); itr != aset.end(); ++itr) - (*itr)->RewardHonor(_player, aset.size()); - - // give bg rewards and update counters like kill by first from attackers - // this can't be called for all attackers. - if (!aset.empty()) - if (Battleground* bg = _player->GetBattleground()) - bg->HandleKillPlayer(_player, *aset.begin()); - } else if (_player->HasAuraType(SPELL_AURA_SPIRIT_OF_REDEMPTION)) { // this will kill character by SPELL_AURA_SPIRIT_OF_REDEMPTION @@ -496,9 +477,12 @@ void WorldSession::LogoutPlayer(bool Save) ///- Remove pet _player->RemovePet(NULL, PET_SAVE_AS_CURRENT, true); + ///- Clear whisper whitelist + _player->ClearWhisperWhiteList(); + ///- empty buyback items and save the player in the database // some save parts only correctly work in case player present in map/player_lists (pets, etc) - if (Save) + if (save) { uint32 eslot; for (int j = BUYBACK_SLOT_START; j < BUYBACK_SLOT_END; ++j) @@ -727,8 +711,8 @@ void WorldSession::SetAccountData(AccountDataType type, time_t tm, std::string c void WorldSession::SendAccountDataTimes(uint32 mask) { - WorldPacket data(SMSG_ACCOUNT_DATA_TIMES, 4 + 1 + 4 + 8 * 4); // changed in WotLK - data << uint32(time(NULL)); // unix time of something + WorldPacket data(SMSG_ACCOUNT_DATA_TIMES, 4 + 1 + 4 + NUM_ACCOUNT_DATA_TYPES * 4); + data << uint32(time(NULL)); // Server time data << uint8(1); data << uint32(mask); // type mask for (uint32 i = 0; i < NUM_ACCOUNT_DATA_TYPES; ++i) @@ -815,7 +799,7 @@ void WorldSession::ReadMovementInfo(WorldPacket &data, MovementInfo* mi) if (mi->HasMovementFlag(MOVEMENTFLAG_SPLINE_ELEVATION)) data >> mi->splineElevation; - //! Anti-cheat checks. Please keep them in seperate if() blocks to maintain a clear overview. + //! Anti-cheat checks. Please keep them in seperate if () blocks to maintain a clear overview. //! Might be subject to latency, so just remove improper flags. #ifdef TRINITY_DEBUG #define REMOVE_VIOLATING_FLAGS(check, maskToRemove) \ @@ -950,7 +934,7 @@ void WorldSession::ReadAddonsInfo(WorldPacket &data) ByteBuffer addonInfo; addonInfo.resize(size); - if (uncompress(const_cast<uint8*>(addonInfo.contents()), &uSize, const_cast<uint8*>(data.contents() + pos), data.size() - pos) == Z_OK) + if (uncompress(addonInfo.contents(), &uSize, data.contents() + pos, data.size() - pos) == Z_OK) { uint32 addonsCount; addonInfo >> addonsCount; // addons count @@ -993,7 +977,7 @@ void WorldSession::ReadAddonsInfo(WorldPacket &data) sLog->outInfo(LOG_FILTER_GENERAL, "ADDON: %s (0x%x) was not known, saving...", addon.Name.c_str(), addon.CRC); } - // TODO: Find out when to not use CRC/pubkey, and other possible states. + /// @todo Find out when to not use CRC/pubkey, and other possible states. m_addonsList.push_back(addon); } @@ -1050,7 +1034,7 @@ void WorldSession::SendAddonsInfo() data.append(addonPublicKey, sizeof(addonPublicKey)); } - data << uint32(0); // TODO: Find out the meaning of this. + data << uint32(0); /// @todo Find out the meaning of this. } uint8 unk3 = 0; // 0 is sent here @@ -1189,3 +1173,41 @@ void WorldSession::InitWarden(BigNumber* k, std::string const& os) // _warden->Init(this, k); } } + +void WorldSession::LoadPermissions() +{ + uint32 id = GetAccountId(); + std::string name; + AccountMgr::GetName(id, name); + + _RBACData = new RBACData(id, name, realmID); + _RBACData->LoadFromDB(); + + sLog->outDebug(LOG_FILTER_RBAC, "WorldSession::LoadPermissions [AccountId: %u, Name: %s, realmId: %d]", + id, name.c_str(), realmID); +} + +RBACData* WorldSession::GetRBACData() +{ + return _RBACData; +} + +bool WorldSession::HasPermission(uint32 permission) +{ + if (!_RBACData) + LoadPermissions(); + + bool hasPermission = _RBACData->HasPermission(permission); + sLog->outDebug(LOG_FILTER_RBAC, "WorldSession::HasPermission [AccountId: %u, Name: %s, realmId: %d]", + _RBACData->GetId(), _RBACData->GetName().c_str(), realmID); + + return hasPermission; +} + +void WorldSession::InvalidateRBACData() +{ + sLog->outDebug(LOG_FILTER_RBAC, "WorldSession::InvalidateRBACData [AccountId: %u, Name: %s, realmId: %d]", + _RBACData->GetId(), _RBACData->GetName().c_str(), realmID); + delete _RBACData; + _RBACData = NULL; +} diff --git a/src/server/game/Server/WorldSession.h b/src/server/game/Server/WorldSession.h index 39f5425d9df..b714cd71e6d 100644 --- a/src/server/game/Server/WorldSession.h +++ b/src/server/game/Server/WorldSession.h @@ -39,6 +39,7 @@ class LoginQueryHolder; class Object; class Player; class Quest; +class RBACData; class SpellCastTargets; class Unit; class Warden; @@ -48,15 +49,18 @@ struct AreaTableEntry; struct AuctionEntry; struct DeclinedName; struct ItemTemplate; +struct MovementInfo; + +namespace lfg +{ struct LfgJoinResultData; -struct LfgLockStatus; struct LfgPlayerBoot; struct LfgProposal; struct LfgQueueStatusData; struct LfgPlayerRewardData; struct LfgRoleCheck; struct LfgUpdateData; -struct MovementInfo; +} enum AccountDataType { @@ -181,9 +185,6 @@ class CharacterCreateInfo /// Server side data uint8 CharCount; - - private: - virtual ~CharacterCreateInfo(){}; }; /// Player session in the World @@ -216,6 +217,11 @@ class WorldSession void SendAuthResponse(uint8 code, bool shortForm, uint32 queuePos = 0); void SendClientCacheVersion(uint32 version); + RBACData* GetRBACData(); + bool HasPermission(uint32 permissionId); + void LoadPermissions(); + void InvalidateRBACData(); // Used to force LoadPermissions at next HasPermission check + AccountTypes GetSecurity() const { return _security; } uint32 GetAccountId() const { return _accountId; } Player* GetPlayer() const { return _player; } @@ -248,7 +254,7 @@ class WorldSession return (_logoutTime > 0 && currTime >= _logoutTime + 20); } - void LogoutPlayer(bool Save); + void LogoutPlayer(bool save); void KickPlayer(); void QueuePacket(WorldPacket* new_packet); @@ -785,16 +791,16 @@ class WorldSession void HandleLfrLeaveOpcode(WorldPacket& recvData); void HandleLfgGetStatus(WorldPacket& recvData); - void SendLfgUpdatePlayer(LfgUpdateData const& updateData); - void SendLfgUpdateParty(LfgUpdateData const& updateData); + void SendLfgUpdatePlayer(lfg::LfgUpdateData const& updateData); + void SendLfgUpdateParty(lfg::LfgUpdateData const& updateData); void SendLfgRoleChosen(uint64 guid, uint8 roles); - void SendLfgRoleCheckUpdate(LfgRoleCheck const& pRoleCheck); + void SendLfgRoleCheckUpdate(lfg::LfgRoleCheck const& pRoleCheck); void SendLfgLfrList(bool update); - void SendLfgJoinResult(LfgJoinResultData const& joinData); - void SendLfgQueueStatus(LfgQueueStatusData const& queueData); - void SendLfgPlayerReward(LfgPlayerRewardData const& lfgPlayerRewardData); - void SendLfgBootProposalUpdate(LfgPlayerBoot const& boot); - void SendLfgUpdateProposal(LfgProposal const& proposal); + void SendLfgJoinResult(lfg::LfgJoinResultData const& joinData); + void SendLfgQueueStatus(lfg::LfgQueueStatusData const& queueData); + void SendLfgPlayerReward(lfg::LfgPlayerRewardData const& lfgPlayerRewardData); + void SendLfgBootProposalUpdate(lfg::LfgPlayerBoot const& boot); + void SendLfgUpdateProposal(lfg::LfgProposal const& proposal); void SendLfgDisabled(); void SendLfgOfferContinue(uint32 dungeonEntry); void SendLfgTeleportError(uint8 err); @@ -914,14 +920,14 @@ class WorldSession void LogUnprocessedTail(WorldPacket* packet); // EnumData helpers - bool CharCanLogin(uint32 lowGUID) + bool IsLegitCharacterForAccount(uint32 lowGUID) { - return _allowedCharsToLogin.find(lowGUID) != _allowedCharsToLogin.end(); + return _legitCharacters.find(lowGUID) != _legitCharacters.end(); } // this stores the GUIDs of the characters who can login // characters who failed on Player::BuildEnumData shouldn't login - std::set<uint32> _allowedCharsToLogin; + std::set<uint32> _legitCharacters; uint32 m_GUIDLow; // set loggined or recently logout player (while m_playerRecentlyLogout set) Player* _player; @@ -954,6 +960,7 @@ class WorldSession bool isRecruiter; ACE_Based::LockedQueue<WorldPacket*, ACE_Thread_Mutex> _recvQueue; time_t timeLastWhoCommand; + RBACData* _RBACData; }; #endif /// @} diff --git a/src/server/game/Server/WorldSocket.cpp b/src/server/game/Server/WorldSocket.cpp index b47f801ab29..128175d785b 100644 --- a/src/server/game/Server/WorldSocket.cpp +++ b/src/server/game/Server/WorldSocket.cpp @@ -159,27 +159,29 @@ int WorldSocket::SendPacket(WorldPacket const& pct) if (closing_) return -1; - // Dump outgoing packet. + // Dump outgoing packet if (sPacketLog->CanLogPacket()) sPacketLog->LogPacket(pct, SERVER_TO_CLIENT); + WorldPacket const* pkt = &pct; + + if (m_Session) - sLog->outTrace(LOG_FILTER_OPCODES, "S->C %s %s", m_Session->GetPlayerInfo().c_str(), GetOpcodeNameForLogging(pct.GetOpcode()).c_str()); + sLog->outTrace(LOG_FILTER_OPCODES, "S->C: %s %s", m_Session->GetPlayerInfo().c_str(), GetOpcodeNameForLogging(pkt->GetOpcode()).c_str()); - // Create a copy of the original packet; this is to avoid issues if a hook modifies it. - sScriptMgr->OnPacketSend(this, WorldPacket(pct)); + sScriptMgr->OnPacketSend(this, *pkt); - ServerPktHeader header(pct.size()+2, pct.GetOpcode()); + ServerPktHeader header(pkt->size()+2, pkt->GetOpcode()); m_Crypt.EncryptSend ((uint8*)header.header, header.getHeaderLength()); - if (m_OutBuffer->space() >= pct.size() + header.getHeaderLength() && msg_queue()->is_empty()) + if (m_OutBuffer->space() >= pkt->size() + header.getHeaderLength() && msg_queue()->is_empty()) { // Put the packet on the buffer. if (m_OutBuffer->copy((char*) header.header, header.getHeaderLength()) == -1) ACE_ASSERT (false); - if (!pct.empty()) - if (m_OutBuffer->copy((char*) pct.contents(), pct.size()) == -1) + if (!pkt->empty()) + if (m_OutBuffer->copy((char*) pkt->contents(), pkt->size()) == -1) ACE_ASSERT (false); } else @@ -187,12 +189,12 @@ int WorldSocket::SendPacket(WorldPacket const& pct) // Enqueue the packet. ACE_Message_Block* mb; - ACE_NEW_RETURN(mb, ACE_Message_Block(pct.size() + header.getHeaderLength()), -1); + ACE_NEW_RETURN(mb, ACE_Message_Block(pkt->size() + header.getHeaderLength()), -1); mb->copy((char*) header.header, header.getHeaderLength()); - if (!pct.empty()) - mb->copy((const char*)pct.contents(), pct.size()); + if (!pkt->empty()) + mb->copy((const char*)pkt->contents(), pkt->size()); if (msg_queue()->enqueue_tail(mb, (ACE_Time_Value*)&ACE_Time_Value::zero) == -1) { @@ -245,20 +247,7 @@ int WorldSocket::open (void *a) m_Address = remote_addr.get_host_addr(); - // Send startup packet. - WorldPacket packet (SMSG_AUTH_CHALLENGE, 24); - packet << uint32(1); // 1...31 - packet << m_Seed; - - BigNumber seed1; - seed1.SetRand(16 * 8); - packet.append(seed1.AsByteArray(16), 16); // new encryption seeds - - BigNumber seed2; - seed2.SetRand(16 * 8); - packet.append(seed2.AsByteArray(16), 16); // new encryption seeds - - if (SendPacket(packet) == -1) + if (HandleSendAuthSession() == -1) return -1; // Register with ACE Reactor @@ -383,9 +372,9 @@ int WorldSocket::handle_output_queue (GuardType& g) const size_t send_len = mblk->length(); #ifdef MSG_NOSIGNAL - ssize_t n = peer().send (mblk->rd_ptr(), send_len, MSG_NOSIGNAL); + ssize_t n = peer().send(mblk->rd_ptr(), send_len, MSG_NOSIGNAL); #else - ssize_t n = peer().send (mblk->rd_ptr(), send_len); + ssize_t n = peer().send(mblk->rd_ptr(), send_len); #endif // MSG_NOSIGNAL if (n == 0) @@ -461,7 +450,7 @@ int WorldSocket::Update (void) int ret; do - ret = handle_output (get_handle()); + ret = handle_output(get_handle()); while (ret > 0); return ret; @@ -469,18 +458,18 @@ int WorldSocket::Update (void) int WorldSocket::handle_input_header (void) { - ACE_ASSERT (m_RecvWPct == NULL); + ACE_ASSERT(m_RecvWPct == NULL); - ACE_ASSERT (m_Header.length() == sizeof(ClientPktHeader)); + ACE_ASSERT(m_Header.length() == sizeof(ClientPktHeader)); - m_Crypt.DecryptRecv ((uint8*) m_Header.rd_ptr(), sizeof(ClientPktHeader)); + m_Crypt.DecryptRecv ((uint8*)m_Header.rd_ptr(), sizeof(ClientPktHeader)); - ClientPktHeader& header = *((ClientPktHeader*) m_Header.rd_ptr()); + ClientPktHeader& header = *((ClientPktHeader*)m_Header.rd_ptr()); EndianConvertReverse(header.size); EndianConvert(header.cmd); - if ((header.size < 4) || (header.size > 10240) || (header.cmd > 10240)) + if ((header.size < 4) || (header.size > 10240) || (header.cmd > 10240)) { Player* _player = m_Session ? m_Session->GetPlayer() : NULL; sLog->outError(LOG_FILTER_NETWORKIO, "WorldSocket::handle_input_header(): client (account: %u, char [GUID: %u, name: %s]) sent malformed packet (size: %d, cmd: %d)", @@ -495,11 +484,11 @@ int WorldSocket::handle_input_header (void) header.size -= 4; - ACE_NEW_RETURN (m_RecvWPct, WorldPacket ((uint16) header.cmd, header.size), -1); + ACE_NEW_RETURN(m_RecvWPct, WorldPacket ((uint16)header.cmd, header.size), -1); if (header.size > 0) { - m_RecvWPct->resize (header.size); + m_RecvWPct->resize(header.size); m_RecvPct.base ((char*) m_RecvWPct->contents(), m_RecvWPct->size()); } else @@ -666,7 +655,7 @@ int WorldSocket::ProcessIncoming(WorldPacket* new_pct) ACE_ASSERT (new_pct); // manage memory ;) - ACE_Auto_Ptr<WorldPacket> aptr (new_pct); + ACE_Auto_Ptr<WorldPacket> aptr(new_pct); const ACE_UINT16 opcode = new_pct->GetOpcode(); @@ -677,15 +666,16 @@ int WorldSocket::ProcessIncoming(WorldPacket* new_pct) if (sPacketLog->CanLogPacket()) sPacketLog->LogPacket(*new_pct, CLIENT_TO_SERVER); + std::string opcodeName = GetOpcodeNameForLogging(opcode); if (m_Session) - sLog->outTrace(LOG_FILTER_OPCODES, "C->S %s %s", m_Session->GetPlayerInfo().c_str(), GetOpcodeNameForLogging(new_pct->GetOpcode()).c_str()); + sLog->outTrace(LOG_FILTER_OPCODES, "C->S: %s %s", m_Session->GetPlayerInfo().c_str(), opcodeName.c_str()); try { switch (opcode) { case CMSG_PING: - return HandlePing (*new_pct); + return HandlePing(*new_pct); case CMSG_AUTH_SESSION: if (m_Session) { @@ -694,18 +684,17 @@ int WorldSocket::ProcessIncoming(WorldPacket* new_pct) } sScriptMgr->OnPacketReceive(this, WorldPacket(*new_pct)); - return HandleAuthSession (*new_pct); + return HandleAuthSession(*new_pct); case CMSG_KEEP_ALIVE: - sLog->outDebug(LOG_FILTER_NETWORKIO, "%s", GetOpcodeNameForLogging(opcode).c_str()); + sLog->outDebug(LOG_FILTER_NETWORKIO, "%s", opcodeName.c_str()); sScriptMgr->OnPacketReceive(this, WorldPacket(*new_pct)); return 0; default: { - ACE_GUARD_RETURN (LockType, Guard, m_SessionLock, -1); - + ACE_GUARD_RETURN(LockType, Guard, m_SessionLock, -1); if (!m_Session) { - sLog->outError(LOG_FILTER_NETWORKIO, "ProcessIncoming: Client not authed opcode = %u", uint32(opcode)); + sLog->outError(LOG_FILTER_OPCODES, "ProcessIncoming: Client not authed opcode = %u", uint32(opcode)); return -1; } @@ -715,7 +704,7 @@ int WorldSocket::ProcessIncoming(WorldPacket* new_pct) // OK, give the packet to WorldSession aptr.release(); - // WARNINIG here we call it with locks held. + // WARNING here we call it with locks held. // Its possible to cause deadlock if QueuePacket calls back m_Session->QueuePacket(new_pct); return 0; @@ -724,8 +713,8 @@ int WorldSocket::ProcessIncoming(WorldPacket* new_pct) } catch (ByteBufferException &) { - sLog->outError(LOG_FILTER_NETWORKIO, "WorldSocket::ProcessIncoming ByteBufferException occured while parsing an instant handled packet (opcode: %u) from client %s, accountid=%i. Disconnected client.", - opcode, GetRemoteAddress().c_str(), m_Session ? int32(m_Session->GetAccountId()) : -1); + sLog->outError(LOG_FILTER_NETWORKIO, "WorldSocket::ProcessIncoming ByteBufferException occured while parsing an instant handled packet %s from client %s, accountid=%i. Disconnected client.", + opcodeName.c_str(), GetRemoteAddress().c_str(), m_Session ? int32(m_Session->GetAccountId()) : -1); new_pct->hexlike(); return -1; } @@ -733,36 +722,46 @@ int WorldSocket::ProcessIncoming(WorldPacket* new_pct) ACE_NOTREACHED (return 0); } +int WorldSocket::HandleSendAuthSession() +{ + WorldPacket packet(SMSG_AUTH_CHALLENGE, 37); + packet << uint32(1); // 1...31 + packet << uint32(m_Seed); + + BigNumber seed1; + seed1.SetRand(16 * 8); + packet.append(seed1.AsByteArray(16), 16); // new encryption seeds + + BigNumber seed2; + seed2.SetRand(16 * 8); + packet.append(seed2.AsByteArray(16), 16); // new encryption seeds + return SendPacket(packet); +} + int WorldSocket::HandleAuthSession(WorldPacket& recvPacket) { - // NOTE: ATM the socket is singlethread, have this in mind ... uint8 digest[20]; uint32 clientSeed; - uint32 unk2, unk3, unk5, unk6, unk7; - uint64 unk4; - uint32 BuiltNumberClient; - uint32 id, security; - //uint8 expansion = 0; + uint8 security; + uint32 id; LocaleConstant locale; std::string account; SHA1Hash sha; - BigNumber v, s, g, N; + uint32 clientBuild; + uint32 unk2, unk3, unk5, unk6, unk7; + uint64 unk4; WorldPacket packet, SendAddonPacked; - BigNumber k; if (sWorld->IsClosed()) { - packet.Initialize(SMSG_AUTH_RESPONSE, 1); - packet << uint8(AUTH_REJECT); - SendPacket(packet); - + SendAuthResponseError(AUTH_REJECT); sLog->outError(LOG_FILTER_NETWORKIO, "WorldSocket::HandleAuthSession: World closed, denying client (%s).", GetRemoteAddress().c_str()); return -1; } // Read the content of the packet - recvPacket >> BuiltNumberClient; // for now no use + recvPacket >> clientBuild; recvPacket >> unk2; recvPacket >> account; recvPacket >> unk3; @@ -772,13 +771,15 @@ int WorldSocket::HandleAuthSession(WorldPacket& recvPacket) recvPacket.read(digest, 20); sLog->outDebug(LOG_FILTER_NETWORKIO, "WorldSocket::HandleAuthSession: client %u, unk2 %u, account %s, unk3 %u, clientseed %u", - BuiltNumberClient, + clientBuild, unk2, account.c_str(), unk3, clientSeed); // Get the account information from the realmd database + // 0 1 2 3 4 5 6 7 8 + // SELECT id, sessionkey, last_ip, locked, expansion, mutetime, locale, recruiter, os FROM account WHERE username = ? PreparedStatement* stmt = LoginDatabase.GetPreparedStatement(LOGIN_SEL_ACCOUNT_INFO_BY_NAME); stmt->setString(0, account); @@ -788,67 +789,40 @@ int WorldSocket::HandleAuthSession(WorldPacket& recvPacket) // Stop if the account is not found if (!result) { - packet.Initialize (SMSG_AUTH_RESPONSE, 1); - packet << uint8 (AUTH_UNKNOWN_ACCOUNT); - - SendPacket(packet); - + SendAuthResponseError(AUTH_UNKNOWN_ACCOUNT); sLog->outError(LOG_FILTER_NETWORKIO, "WorldSocket::HandleAuthSession: Sent Auth Response (unknown account)."); return -1; } Field* fields = result->Fetch(); - uint8 expansion = fields[6].GetUInt8(); + uint8 expansion = fields[4].GetUInt8(); uint32 world_expansion = sWorld->getIntConfig(CONFIG_EXPANSION); if (expansion > world_expansion) expansion = world_expansion; - N.SetHexStr ("894B645E89E1535BBDAD5B8B290650530801B18EBFBF5E8FAB3C82872A3E9BB7"); - g.SetDword (7); - - v.SetHexStr(fields[4].GetCString()); - s.SetHexStr (fields[5].GetCString()); - - const char* sStr = s.AsHexStr(); //Must be freed by OPENSSL_free() - const char* vStr = v.AsHexStr(); //Must be freed by OPENSSL_free() - - sLog->outDebug(LOG_FILTER_NETWORKIO, "WorldSocket::HandleAuthSession: (s, v) check s: %s v: %s", - sStr, - vStr); - - OPENSSL_free ((void*) sStr); - OPENSSL_free ((void*) vStr); - ///- Re-check ip locking (same check as in realmd). if (fields[3].GetUInt8() == 1) // if ip is locked { if (strcmp (fields[2].GetCString(), GetRemoteAddress().c_str())) { - packet.Initialize (SMSG_AUTH_RESPONSE, 1); - packet << uint8 (AUTH_FAILED); - SendPacket(packet); - + SendAuthResponseError(AUTH_FAILED); sLog->outDebug(LOG_FILTER_NETWORKIO, "WorldSocket::HandleAuthSession: Sent Auth Response (Account IP differs)."); return -1; } } id = fields[0].GetUInt32(); - /* - if (security > SEC_ADMINISTRATOR) // prevent invalid security settings in DB - security = SEC_ADMINISTRATOR; - */ - k.SetHexStr (fields[1].GetCString()); + k.SetHexStr(fields[1].GetCString()); - int64 mutetime = fields[7].GetInt64(); + int64 mutetime = fields[5].GetInt64(); //! Negative mutetime indicates amount of seconds to be muted effective on next login - which is now. if (mutetime < 0) { mutetime = time(NULL) + llabs(mutetime); - PreparedStatement* stmt = LoginDatabase.GetPreparedStatement(LOGIN_UPD_MUTE_TIME); + PreparedStatement* stmt = LoginDatabase.GetPreparedStatement(LOGIN_UPD_MUTE_TIME_LOGIN); stmt->setInt64(0, mutetime); stmt->setUInt32(1, id); @@ -856,20 +830,17 @@ int WorldSocket::HandleAuthSession(WorldPacket& recvPacket) LoginDatabase.Execute(stmt); } - locale = LocaleConstant (fields[8].GetUInt8()); + locale = LocaleConstant (fields[6].GetUInt8()); if (locale >= TOTAL_LOCALES) locale = LOCALE_enUS; - uint32 recruiter = fields[9].GetUInt32(); - std::string os = fields[10].GetString(); + uint32 recruiter = fields[7].GetUInt32(); + std::string os = fields[8].GetString(); // Must be done before WorldSession is created if (sWorld->getBoolConfig(CONFIG_WARDEN_ENABLED) && os != "Win" && os != "OSX") { - packet.Initialize(SMSG_AUTH_RESPONSE, 1); - packet << uint8(AUTH_REJECT); - SendPacket(packet); - + SendAuthResponseError(AUTH_REJECT); sLog->outError(LOG_FILTER_NETWORKIO, "WorldSocket::HandleAuthSession: Client %s attempted to log in using invalid client OS (%s).", GetRemoteAddress().c_str(), os.c_str()); return -1; } @@ -900,10 +871,7 @@ int WorldSocket::HandleAuthSession(WorldPacket& recvPacket) if (banresult) // if account banned { - packet.Initialize (SMSG_AUTH_RESPONSE, 1); - packet << uint8 (AUTH_BANNED); - SendPacket(packet); - + SendAuthResponseError(AUTH_BANNED); sLog->outError(LOG_FILTER_NETWORKIO, "WorldSocket::HandleAuthSession: Sent Auth Response (Account banned)."); return -1; } @@ -911,13 +879,9 @@ int WorldSocket::HandleAuthSession(WorldPacket& recvPacket) // Check locked state for server AccountTypes allowedAccountType = sWorld->GetPlayerSecurityLimit(); sLog->outDebug(LOG_FILTER_NETWORKIO, "Allowed Level: %u Player Level %u", allowedAccountType, AccountTypes(security)); - if (AccountTypes(security) < allowedAccountType) + if (allowedAccountType > SEC_PLAYER && AccountTypes(security) < allowedAccountType) { - WorldPacket Packet (SMSG_AUTH_RESPONSE, 1); - Packet << uint8 (AUTH_UNAVAILABLE); - - SendPacket(packet); - + SendAuthResponseError(AUTH_UNAVAILABLE); sLog->outInfo(LOG_FILTER_NETWORKIO, "WorldSocket::HandleAuthSession: User tries to login but his security level is not enough"); return -1; } @@ -926,29 +890,25 @@ int WorldSocket::HandleAuthSession(WorldPacket& recvPacket) uint32 t = 0; uint32 seed = m_Seed; - sha.UpdateData (account); - sha.UpdateData ((uint8 *) & t, 4); - sha.UpdateData ((uint8 *) & clientSeed, 4); - sha.UpdateData ((uint8 *) & seed, 4); - sha.UpdateBigNumbers (&k, NULL); + sha.UpdateData(account); + sha.UpdateData((uint8*)&t, 4); + sha.UpdateData((uint8*)&clientSeed, 4); + sha.UpdateData((uint8*)&seed, 4); + sha.UpdateBigNumbers(&k, NULL); sha.Finalize(); std::string address = GetRemoteAddress(); - if (memcmp (sha.GetDigest(), digest, 20)) + if (memcmp(sha.GetDigest(), digest, 20)) { - packet.Initialize (SMSG_AUTH_RESPONSE, 1); - packet << uint8 (AUTH_FAILED); - - SendPacket(packet); - + SendAuthResponseError(AUTH_FAILED); sLog->outError(LOG_FILTER_NETWORKIO, "WorldSocket::HandleAuthSession: Authentication failed for account: %u ('%s') address: %s", id, account.c_str(), address.c_str()); return -1; } sLog->outDebug(LOG_FILTER_NETWORKIO, "WorldSocket::HandleAuthSession: Client '%s' authenticated successfully from %s.", - account.c_str(), - address.c_str()); + account.c_str(), + address.c_str()); // Check if this user is by any chance a recruiter stmt = LoginDatabase.GetPreparedStatement(LOGIN_SEL_ACCOUNT_RECRUITER); @@ -971,13 +931,14 @@ int WorldSocket::HandleAuthSession(WorldPacket& recvPacket) LoginDatabase.Execute(stmt); // NOTE ATM the socket is single-threaded, have this in mind ... - ACE_NEW_RETURN (m_Session, WorldSession (id, this, AccountTypes(security), expansion, mutetime, locale, recruiter, isRecruiter), -1); + ACE_NEW_RETURN(m_Session, WorldSession(id, this, AccountTypes(security), expansion, mutetime, locale, recruiter, isRecruiter), -1); m_Crypt.Init(&k); m_Session->LoadGlobalAccountData(); m_Session->LoadTutorialsData(); m_Session->ReadAddonsInfo(recvPacket); + m_Session->LoadPermissions(); // Initialize Warden system only if it is enabled by config if (sWorld->getBoolConfig(CONFIG_WARDEN_ENABLED)) @@ -985,10 +946,9 @@ int WorldSocket::HandleAuthSession(WorldPacket& recvPacket) // Sleep this Network thread for uint32 sleepTime = sWorld->getIntConfig(CONFIG_SESSION_ADD_DELAY); - ACE_OS::sleep (ACE_Time_Value (0, sleepTime)); - - sWorld->AddSession (m_Session); + ACE_OS::sleep(ACE_Time_Value(0, sleepTime)); + sWorld->AddSession(m_Session); return 0; } @@ -1020,7 +980,7 @@ int WorldSocket::HandlePing (WorldPacket& recvPacket) { ACE_GUARD_RETURN (LockType, Guard, m_SessionLock, -1); - if (m_Session && AccountMgr::IsPlayerAccount(m_Session->GetSecurity())) + if (m_Session && !m_Session->HasPermission(RBAC_PERM_SKIP_CHECK_OVERSPEED_PING)) { sLog->outError(LOG_FILTER_NETWORKIO, "WorldSocket::HandlePing: %s kicked for over-speed pings (address: %s)", m_Session->GetPlayerInfo().c_str(), GetRemoteAddress().c_str()); @@ -1049,7 +1009,14 @@ int WorldSocket::HandlePing (WorldPacket& recvPacket) } } - WorldPacket packet (SMSG_PONG, 4); + WorldPacket packet(SMSG_PONG, 4); packet << ping; return SendPacket(packet); } + +void WorldSocket::SendAuthResponseError(uint8 code) +{ + WorldPacket packet(SMSG_AUTH_RESPONSE, 1); + packet << uint8(code); + SendPacket(packet); +} diff --git a/src/server/game/Server/WorldSocket.h b/src/server/game/Server/WorldSocket.h index 6b59647bb6c..2d5762ef60e 100644 --- a/src/server/game/Server/WorldSocket.h +++ b/src/server/game/Server/WorldSocket.h @@ -97,13 +97,13 @@ class WorldSocket : public WorldHandler typedef ACE_Guard<LockType> GuardType; /// Check if socket is closed. - bool IsClosed (void) const; + bool IsClosed(void) const; /// Close the socket. - void CloseSocket (void); + void CloseSocket(void); /// Get address of connected peer. - const std::string& GetRemoteAddress (void) const; + const std::string& GetRemoteAddress(void) const; /// Send A packet on the socket, this function is reentrant. /// @param pct packet to send @@ -111,57 +111,60 @@ class WorldSocket : public WorldHandler int SendPacket(const WorldPacket& pct); /// Add reference to this object. - long AddReference (void); + long AddReference(void); /// Remove reference to this object. - long RemoveReference (void); + long RemoveReference(void); /// things called by ACE framework. /// Called on open, the void* is the acceptor. - virtual int open (void *); + virtual int open(void *); /// Called on failures inside of the acceptor, don't call from your code. - virtual int close (u_long); + virtual int close(u_long); /// Called when we can read from the socket. - virtual int handle_input (ACE_HANDLE = ACE_INVALID_HANDLE); + virtual int handle_input(ACE_HANDLE = ACE_INVALID_HANDLE); /// Called when the socket can write. - virtual int handle_output (ACE_HANDLE = ACE_INVALID_HANDLE); + virtual int handle_output(ACE_HANDLE = ACE_INVALID_HANDLE); /// Called when connection is closed or error happens. - virtual int handle_close (ACE_HANDLE = ACE_INVALID_HANDLE, + virtual int handle_close(ACE_HANDLE = ACE_INVALID_HANDLE, ACE_Reactor_Mask = ACE_Event_Handler::ALL_EVENTS_MASK); /// Called by WorldSocketMgr/ReactorRunnable. - int Update (void); + int Update(void); private: /// Helper functions for processing incoming data. - int handle_input_header (void); - int handle_input_payload (void); - int handle_input_missing_data (void); + int handle_input_header(void); + int handle_input_payload(void); + int handle_input_missing_data(void); /// Help functions to mark/unmark the socket for output. /// @param g the guard is for m_OutBufferLock, the function will release it - int cancel_wakeup_output (GuardType& g); - int schedule_wakeup_output (GuardType& g); + int cancel_wakeup_output(GuardType& g); + int schedule_wakeup_output(GuardType& g); /// Drain the queue if its not empty. - int handle_output_queue (GuardType& g); + int handle_output_queue(GuardType& g); /// process one incoming packet. /// @param new_pct received packet, note that you need to delete it. - int ProcessIncoming (WorldPacket* new_pct); + int ProcessIncoming(WorldPacket* new_pct); /// Called by ProcessIncoming() on CMSG_AUTH_SESSION. - int HandleAuthSession (WorldPacket& recvPacket); + int HandleAuthSession(WorldPacket& recvPacket); /// Called by ProcessIncoming() on CMSG_PING. - int HandlePing (WorldPacket& recvPacket); + int HandlePing(WorldPacket& recvPacket); + + int HandleSendAuthSession(); private: + void SendAuthResponseError(uint8); /// Time in which the last ping was received ACE_Time_Value m_LastPingTime; diff --git a/src/server/game/Skills/SkillDiscovery.cpp b/src/server/game/Skills/SkillDiscovery.cpp index 8b5ae4863d0..e6ba28d5f1c 100644 --- a/src/server/game/Skills/SkillDiscovery.cpp +++ b/src/server/game/Skills/SkillDiscovery.cpp @@ -55,8 +55,7 @@ void LoadSkillDiscoveryTable() if (!result) { - sLog->outError(LOG_FILTER_SQL, ">> Loaded 0 skill discovery definitions. DB table `skill_discovery_template` is empty."); - + sLog->outError(LOG_FILTER_SERVER_LOADING, ">> Loaded 0 skill discovery definitions. DB table `skill_discovery_template` is empty."); return; } @@ -154,7 +153,6 @@ void LoadSkillDiscoveryTable() } sLog->outInfo(LOG_FILTER_SERVER_LOADING, ">> Loaded %u skill discovery definitions in %u ms", count, GetMSTimeDiffToNow(oldMSTime)); - } uint32 GetExplicitDiscoverySpell(uint32 spellId, Player* player) diff --git a/src/server/game/Skills/SkillExtraItems.cpp b/src/server/game/Skills/SkillExtraItems.cpp index 090e2e8205a..5c3b69e48d2 100644 --- a/src/server/game/Skills/SkillExtraItems.cpp +++ b/src/server/game/Skills/SkillExtraItems.cpp @@ -60,8 +60,7 @@ void LoadSkillExtraItemTable() if (!result) { - sLog->outError(LOG_FILTER_SQL, ">> Loaded 0 spell specialization definitions. DB table `skill_extra_item_template` is empty."); - + sLog->outError(LOG_FILTER_SERVER_LOADING, ">> Loaded 0 spell specialization definitions. DB table `skill_extra_item_template` is empty."); return; } @@ -75,28 +74,28 @@ void LoadSkillExtraItemTable() if (!sSpellMgr->GetSpellInfo(spellId)) { - sLog->outError(LOG_FILTER_GENERAL, "Skill specialization %u has non-existent spell id in `skill_extra_item_template`!", spellId); + sLog->outError(LOG_FILTER_SQL, "Skill specialization %u has non-existent spell id in `skill_extra_item_template`!", spellId); continue; } uint32 requiredSpecialization = fields[1].GetUInt32(); if (!sSpellMgr->GetSpellInfo(requiredSpecialization)) { - sLog->outError(LOG_FILTER_GENERAL, "Skill specialization %u have not existed required specialization spell id %u in `skill_extra_item_template`!", spellId, requiredSpecialization); + sLog->outError(LOG_FILTER_SQL, "Skill specialization %u have not existed required specialization spell id %u in `skill_extra_item_template`!", spellId, requiredSpecialization); continue; } float additionalCreateChance = fields[2].GetFloat(); if (additionalCreateChance <= 0.0f) { - sLog->outError(LOG_FILTER_GENERAL, "Skill specialization %u has too low additional create chance in `skill_extra_item_template`!", spellId); + sLog->outError(LOG_FILTER_SQL, "Skill specialization %u has too low additional create chance in `skill_extra_item_template`!", spellId); continue; } uint8 additionalMaxNum = fields[3].GetUInt8(); if (!additionalMaxNum) { - sLog->outError(LOG_FILTER_GENERAL, "Skill specialization %u has 0 max number of extra items in `skill_extra_item_template`!", spellId); + sLog->outError(LOG_FILTER_SQL, "Skill specialization %u has 0 max number of extra items in `skill_extra_item_template`!", spellId); continue; } @@ -111,7 +110,6 @@ void LoadSkillExtraItemTable() while (result->NextRow()); sLog->outInfo(LOG_FILTER_SERVER_LOADING, ">> Loaded %u spell specialization definitions in %u ms", count, GetMSTimeDiffToNow(oldMSTime)); - } bool canCreateExtraItems(Player* player, uint32 spellId, float &additionalChance, uint8 &additionalMax) diff --git a/src/server/game/Spells/Auras/SpellAuraEffects.cpp b/src/server/game/Spells/Auras/SpellAuraEffects.cpp index 12551c93346..71c74db7ba2 100644 --- a/src/server/game/Spells/Auras/SpellAuraEffects.cpp +++ b/src/server/game/Spells/Auras/SpellAuraEffects.cpp @@ -449,8 +449,6 @@ int32 AuraEffect::CalculateAmount(Unit* caster) } } - float DoneActualBenefit = 0.0f; - // custom amount calculations go here switch (GetAuraType()) { @@ -483,280 +481,14 @@ int32 AuraEffect::CalculateAmount(Unit* caster) } break; case SPELL_AURA_SCHOOL_ABSORB: - m_canBeRecalculated = false; - if (!caster) - break; - switch (GetSpellInfo()->SpellFamilyName) - { - case SPELLFAMILY_MAGE: - // Ice Barrier - if (GetSpellInfo()->SpellFamilyFlags[1] & 0x1 && GetSpellInfo()->SpellFamilyFlags[2] & 0x8) - { - // +80.68% from sp bonus - DoneActualBenefit += caster->SpellBaseDamageBonusDone(m_spellInfo->GetSchoolMask()) * 0.8068f; - // Glyph of Ice Barrier: its weird having a SPELLMOD_ALL_EFFECTS here but its blizzards doing :) - // Glyph of Ice Barrier is only applied at the spell damage bonus because it was already applied to the base value in CalculateSpellDamage - DoneActualBenefit = caster->ApplyEffectModifiers(GetSpellInfo(), m_effIndex, DoneActualBenefit); - } - // Fire Ward - else if (GetSpellInfo()->SpellFamilyFlags[0] & 0x8 && GetSpellInfo()->SpellFamilyFlags[2] & 0x8) - { - // +80.68% from sp bonus - DoneActualBenefit += caster->SpellBaseDamageBonusDone(m_spellInfo->GetSchoolMask()) * 0.8068f; - } - // Frost Ward - else if (GetSpellInfo()->SpellFamilyFlags[0] & 0x100 && GetSpellInfo()->SpellFamilyFlags[2] & 0x8) - { - // +80.68% from sp bonus - DoneActualBenefit += caster->SpellBaseDamageBonusDone(m_spellInfo->GetSchoolMask()) * 0.8068f; - } - break; - case SPELLFAMILY_WARLOCK: - // Shadow Ward - if (m_spellInfo->SpellFamilyFlags[2] & 0x40) - { - // +80.68% from sp bonus - DoneActualBenefit += caster->SpellBaseDamageBonusDone(m_spellInfo->GetSchoolMask()) * 0.8068f; - } - break; - case SPELLFAMILY_PRIEST: - // Power Word: Shield - if (GetSpellInfo()->SpellFamilyFlags[0] & 0x1 && GetSpellInfo()->SpellFamilyFlags[2] & 0x400) - { - // +80.68% from sp bonus - float bonus = 0.8068f; - - // Borrowed Time - if (AuraEffect const* pAurEff = caster->GetDummyAuraEffect(SPELLFAMILY_PRIEST, 2899, 1)) - bonus += CalculatePct(1.0f, pAurEff->GetAmount()); - - DoneActualBenefit += caster->SpellBaseHealingBonusDone(m_spellInfo->GetSchoolMask()) * bonus; - // Improved PW: Shield: its weird having a SPELLMOD_ALL_EFFECTS here but its blizzards doing :) - // Improved PW: Shield is only applied at the spell healing bonus because it was already applied to the base value in CalculateSpellDamage - DoneActualBenefit = caster->ApplyEffectModifiers(GetSpellInfo(), m_effIndex, DoneActualBenefit); - DoneActualBenefit *= caster->CalculateLevelPenalty(GetSpellInfo()); - - amount += int32(DoneActualBenefit); - - // Twin Disciplines - if (AuraEffect const* pAurEff = caster->GetAuraEffect(SPELL_AURA_ADD_PCT_MODIFIER, SPELLFAMILY_PRIEST, 0x400000, 0, 0, caster->GetGUID())) - AddPct(amount, pAurEff->GetAmount()); - - // Focused Power - // Reuse variable, not sure if this code below can be moved before Twin Disciplines - DoneActualBenefit = float(amount); - DoneActualBenefit *= caster->GetTotalAuraMultiplier(SPELL_AURA_MOD_HEALING_DONE_PERCENT); - amount = int32(DoneActualBenefit); - - return amount; - } - break; - case SPELLFAMILY_PALADIN: - // Sacred Shield - if (m_spellInfo->SpellFamilyFlags[1] & 0x80000) - { - //+75.00% from sp bonus - float bonus = 0.75f; - - DoneActualBenefit += caster->SpellBaseHealingBonusDone(m_spellInfo->GetSchoolMask()) * bonus; - // Divine Guardian is only applied at the spell healing bonus because it was already applied to the base value in CalculateSpellDamage - DoneActualBenefit = caster->ApplyEffectModifiers(GetSpellInfo(), m_effIndex, DoneActualBenefit); - DoneActualBenefit *= caster->CalculateLevelPenalty(GetSpellInfo()); - - amount += (int32)DoneActualBenefit; - - // Arena - Dampening - AuraEffect const* pAurEff = caster->GetAuraEffect(74410, 0); - if (!pAurEff) - pAurEff = caster->GetAuraEffect(74411, 0); // Battleground - Dampening - if (pAurEff) - AddPct(amount, pAurEff->GetAmount()); - - return amount; - } - break; - default: - break; - } - break; case SPELL_AURA_MANA_SHIELD: m_canBeRecalculated = false; - if (!caster) - break; - // Mana Shield - if (GetSpellInfo()->SpellFamilyName == SPELLFAMILY_MAGE && GetSpellInfo()->SpellFamilyFlags[0] & 0x8000 && m_spellInfo->SpellFamilyFlags[2] & 0x8) - { - // +80.53% from +spd bonus - DoneActualBenefit += caster->SpellBaseDamageBonusDone(m_spellInfo->GetSchoolMask()) * 0.8053f; - } - break; - case SPELL_AURA_DUMMY: - if (!caster) - break; - // Earth Shield - if (GetSpellInfo()->SpellFamilyName == SPELLFAMILY_SHAMAN && m_spellInfo->SpellFamilyFlags[1] & 0x400) - { - amount = caster->SpellHealingBonusDone(GetBase()->GetUnitOwner(), GetSpellInfo(), amount, SPELL_DIRECT_DAMAGE); - amount = GetBase()->GetUnitOwner()->SpellHealingBonusTaken(caster, GetSpellInfo(), amount, SPELL_DIRECT_DAMAGE); - } - break; - case SPELL_AURA_PERIODIC_DAMAGE: - if (!caster) - break; - // Rupture - if (GetSpellInfo()->SpellFamilyName == SPELLFAMILY_ROGUE && m_spellInfo->SpellFamilyFlags[0] & 0x100000) - { - m_canBeRecalculated = false; - if (caster->GetTypeId() != TYPEID_PLAYER) - break; - //1 point : ${($m1+$b1*1+0.015*$AP)*4} damage over 8 secs - //2 points: ${($m1+$b1*2+0.024*$AP)*5} damage over 10 secs - //3 points: ${($m1+$b1*3+0.03*$AP)*6} damage over 12 secs - //4 points: ${($m1+$b1*4+0.03428571*$AP)*7} damage over 14 secs - //5 points: ${($m1+$b1*5+0.0375*$AP)*8} damage over 16 secs - float AP_per_combo[6] = {0.0f, 0.015f, 0.024f, 0.03f, 0.03428571f, 0.0375f}; - uint8 cp = caster->ToPlayer()->GetComboPoints(); - if (cp > 5) cp = 5; - amount += int32(caster->GetTotalAttackPowerValue(BASE_ATTACK) * AP_per_combo[cp]); - } - // Rip - else if (GetSpellInfo()->SpellFamilyName == SPELLFAMILY_DRUID && m_spellInfo->SpellFamilyFlags[0] & 0x00800000 && GetAuraType() == SPELL_AURA_PERIODIC_DAMAGE) - { - m_canBeRecalculated = false; - // 0.01*$AP*cp - if (caster->GetTypeId() != TYPEID_PLAYER) - break; - - uint8 cp = caster->ToPlayer()->GetComboPoints(); - - // Idol of Feral Shadows. Cant be handled as SpellMod in SpellAura:Dummy due its dependency from CPs - if (AuraEffect const* aurEff = caster->GetAuraEffect(34241, EFFECT_0)) - amount += cp * aurEff->GetAmount(); - // Idol of Worship. Cant be handled as SpellMod in SpellAura:Dummy due its dependency from CPs - else if (AuraEffect const* aurEff = caster->GetAuraEffect(60774, EFFECT_0)) - amount += cp * aurEff->GetAmount(); - - amount += uint32(CalculatePct(caster->GetTotalAttackPowerValue(BASE_ATTACK), cp)); - } - // Rend - else if (GetSpellInfo()->SpellFamilyName == SPELLFAMILY_WARRIOR && GetSpellInfo()->SpellFamilyFlags[0] & 0x20) - { - m_canBeRecalculated = false; - // $0.2 * (($MWB + $mwb) / 2 + $AP / 14 * $MWS) bonus per tick - float ap = caster->GetTotalAttackPowerValue(BASE_ATTACK); - int32 mws = caster->GetAttackTime(BASE_ATTACK); - float mwb_min = caster->GetWeaponDamageRange(BASE_ATTACK, MINDAMAGE); - float mwb_max = caster->GetWeaponDamageRange(BASE_ATTACK, MAXDAMAGE); - float mwb = ((mwb_min + mwb_max) / 2 + ap * mws / 14000) * 0.2f; - amount += int32(caster->ApplyEffectModifiers(m_spellInfo, m_effIndex, mwb)); - // "If used while your target is above 75% health, Rend does 35% more damage." - // as for 3.1.3 only ranks above 9 (wrong tooltip?) - if (m_spellInfo->GetRank() >= 9) - { - if (GetBase()->GetUnitOwner()->HasAuraState(AURA_STATE_HEALTH_ABOVE_75_PERCENT, m_spellInfo, caster)) - AddPct(amount, m_spellInfo->Effects[EFFECT_2].CalcValue(caster)); - } - } - break; - case SPELL_AURA_PERIODIC_ENERGIZE: - switch (m_spellInfo->Id) - { - case 29166: // Innervate - ApplyPct(amount, float(GetBase()->GetUnitOwner()->GetCreatePowers(POWER_MANA)) / GetTotalTicks()); - break; - case 48391: // Owlkin Frenzy - ApplyPct(amount, GetBase()->GetUnitOwner()->GetCreatePowers(POWER_MANA)); - break; - default: - break; - } - break; - case SPELL_AURA_PERIODIC_HEAL: - if (!caster) - break; - // Lightwell Renew - if (GetSpellInfo()->SpellFamilyName == SPELLFAMILY_PRIEST && m_spellInfo->SpellFamilyFlags[2] & 0x4000) - { - if (caster->GetTypeId() == TYPEID_PLAYER) - // Bonus from Glyph of Lightwell - if (AuraEffect* modHealing = caster->GetAuraEffect(55673, 0)) - AddPct(amount, modHealing->GetAmount()); - } - break; - case SPELL_AURA_MOD_DAMAGE_PERCENT_TAKEN: - if (!caster) - break; - // Icebound Fortitude - if (GetSpellInfo()->SpellFamilyName == SPELLFAMILY_DEATHKNIGHT && m_spellInfo->SpellFamilyFlags[0] & 0x00100000) - { - if (caster->GetTypeId() == TYPEID_PLAYER) - { - int32 value = (-1 * amount) - 10; - uint32 defva = uint32(caster->ToPlayer()->GetSkillValue(SKILL_DEFENSE) + caster->ToPlayer()->GetRatingBonusValue(CR_DEFENSE_SKILL)); - - if (defva > 400) - value += int32((defva - 400) * 0.15); - - // Glyph of Icebound Fortitude - if (AuraEffect const* aurEff = caster->GetAuraEffect(58625, 0)) - { - int32 valMax = aurEff->GetAmount(); - if (value < valMax) - value = valMax; - } - amount = -value; - } - } - // Hand of Salvation - else if (GetSpellInfo()->SpellFamilyName == SPELLFAMILY_PALADIN && GetSpellInfo()->SpellFamilyFlags[0] & 0x00000100) - { - //Glyph of Salvation - if (caster->GetGUID() == GetBase()->GetUnitOwner()->GetGUID()) - if (AuraEffect const* aurEff = caster->GetAuraEffect(63225, 0)) - amount = -aurEff->GetAmount(); - } - break; - case SPELL_AURA_MOD_THREAT: - { - uint8 level_diff = 0; - float multiplier = 0.0f; - switch (GetId()) - { - // Arcane Shroud - case 26400: - level_diff = GetBase()->GetUnitOwner()->getLevel() - 60; - multiplier = 2; - break; - // The Eye of Diminution - case 28862: - level_diff = GetBase()->GetUnitOwner()->getLevel() - 60; - multiplier = 1; - break; - } - if (level_diff > 0) - amount += int32(multiplier * level_diff); - break; - } - case SPELL_AURA_MOD_INCREASE_HEALTH: - // Vampiric Blood - if (GetId() == 55233) - amount = GetBase()->GetUnitOwner()->CountPctFromMaxHealth(amount); - break; - case SPELL_AURA_MOD_INCREASE_SPEED: - // Dash - do not set speed if not in cat form - if (GetSpellInfo()->SpellFamilyName == SPELLFAMILY_DRUID && GetSpellInfo()->SpellFamilyFlags[2] & 0x00000008) - amount = GetBase()->GetUnitOwner()->GetShapeshiftForm() == FORM_CAT ? amount : 0; break; default: break; } - if (DoneActualBenefit != 0.0f) - { - DoneActualBenefit *= caster->CalculateLevelPenalty(GetSpellInfo()); - amount += (int32)DoneActualBenefit; - } - GetBase()->CallScriptEffectCalcAmountHandlers(const_cast<AuraEffect const*>(this), amount, m_canBeRecalculated); + GetBase()->CallScriptEffectCalcAmountHandlers(this, amount, m_canBeRecalculated); amount *= GetBase()->GetStackAmount(); return amount; } @@ -790,7 +522,7 @@ void AuraEffect::CalculatePeriodic(Unit* caster, bool create, bool load) break; } - GetBase()->CallScriptEffectCalcPeriodicHandlers(const_cast<AuraEffect const*>(this), m_isPeriodic, m_amplitude); + GetBase()->CallScriptEffectCalcPeriodicHandlers(this, m_isPeriodic, m_amplitude); if (!m_isPeriodic) return; @@ -848,32 +580,6 @@ void AuraEffect::CalculateSpellMod() { switch (GetAuraType()) { - case SPELL_AURA_DUMMY: - switch (GetSpellInfo()->SpellFamilyName) - { - case SPELLFAMILY_DRUID: - switch (GetId()) - { - case 34246: // Idol of the Emerald Queen - case 60779: // Idol of Lush Moss - { - if (!m_spellmod) - { - m_spellmod = new SpellModifier(GetBase()); - m_spellmod->op = SPELLMOD_DOT; - m_spellmod->type = SPELLMOD_FLAT; - m_spellmod->spellId = GetId(); - m_spellmod->mask[1] = 0x0010; - } - m_spellmod->value = GetAmount()/7; - } - break; - } - break; - default: - break; - } - break; case SPELL_AURA_ADD_FLAT_MODIFIER: case SPELL_AURA_ADD_PCT_MODIFIER: if (!m_spellmod) @@ -882,7 +588,7 @@ void AuraEffect::CalculateSpellMod() m_spellmod->op = SpellModOp(GetMiscValue()); ASSERT(m_spellmod->op < MAX_SPELLMOD); - m_spellmod->type = SpellModType(GetAuraType()); // SpellModType value == spell aura types + m_spellmod->type = SpellModType(GetAuraType()); // SpellModType value == spell aura types m_spellmod->spellId = GetId(); m_spellmod->mask = GetSpellInfo()->Effects[GetEffIndex()].SpellClassMask; m_spellmod->charges = GetBase()->GetCharges(); @@ -892,7 +598,7 @@ void AuraEffect::CalculateSpellMod() default: break; } - GetBase()->CallScriptEffectCalcSpellModHandlers(const_cast<AuraEffect const*>(this), m_spellmod); + GetBase()->CallScriptEffectCalcSpellModHandlers(this, m_spellmod); } void AuraEffect::ChangeAmount(int32 newAmount, bool mark, bool onStackOrReapply) @@ -951,15 +657,15 @@ void AuraEffect::HandleEffect(AuraApplication * aurApp, uint8 mode, bool apply) // call scripts helping/replacing effect handlers bool prevented = false; if (apply) - prevented = GetBase()->CallScriptEffectApplyHandlers(const_cast<AuraEffect const*>(this), const_cast<AuraApplication const*>(aurApp), (AuraEffectHandleModes)mode); + prevented = GetBase()->CallScriptEffectApplyHandlers(this, aurApp, (AuraEffectHandleModes)mode); else - prevented = GetBase()->CallScriptEffectRemoveHandlers(const_cast<AuraEffect const*>(this), const_cast<AuraApplication const*>(aurApp), (AuraEffectHandleModes)mode); + prevented = GetBase()->CallScriptEffectRemoveHandlers(this, aurApp, (AuraEffectHandleModes)mode); // check if script events have removed the aura or if default effect prevention was requested if ((apply && aurApp->GetRemoveMode()) || prevented) return; - (*this.*AuraEffectHandler [GetAuraType()])(const_cast<AuraApplication const*>(aurApp), mode, apply); + (*this.*AuraEffectHandler[GetAuraType()])(aurApp, mode, apply); // check if script events have removed the aura or if default effect prevention was requested if (apply && aurApp->GetRemoveMode()) @@ -967,9 +673,9 @@ void AuraEffect::HandleEffect(AuraApplication * aurApp, uint8 mode, bool apply) // call scripts triggering additional events after apply/remove if (apply) - GetBase()->CallScriptAfterEffectApplyHandlers(const_cast<AuraEffect const*>(this), const_cast<AuraApplication const*>(aurApp), (AuraEffectHandleModes)mode); + GetBase()->CallScriptAfterEffectApplyHandlers(this, aurApp, (AuraEffectHandleModes)mode); else - GetBase()->CallScriptAfterEffectRemoveHandlers(const_cast<AuraEffect const*>(this), const_cast<AuraApplication const*>(aurApp), (AuraEffectHandleModes)mode); + GetBase()->CallScriptAfterEffectRemoveHandlers(this, aurApp, (AuraEffectHandleModes)mode); } void AuraEffect::HandleEffect(Unit* target, uint8 mode, bool apply) @@ -1274,7 +980,10 @@ void AuraEffect::PeriodicTick(AuraApplication * aurApp, Unit* caster) const void AuraEffect::HandleProc(AuraApplication* aurApp, ProcEventInfo& eventInfo) { - // TODO: effect script handlers here + bool prevented = GetBase()->CallScriptEffectProcHandlers(this, aurApp, eventInfo); + if (prevented) + return; + switch (GetAuraType()) { case SPELL_AURA_PROC_TRIGGER_SPELL: @@ -1295,6 +1004,8 @@ void AuraEffect::HandleProc(AuraApplication* aurApp, ProcEventInfo& eventInfo) default: break; } + + GetBase()->CallScriptAfterEffectProcHandlers(this, aurApp, eventInfo); } void AuraEffect::CleanupTriggeredSpells(Unit* target) @@ -1311,7 +1022,7 @@ void AuraEffect::CleanupTriggeredSpells(Unit* target) return; // needed for spell 43680, maybe others - // TODO: is there a spell flag, which can solve this in a more sophisticated way? + /// @todo is there a spell flag, which can solve this in a more sophisticated way? if (m_spellInfo->Effects[GetEffIndex()].ApplyAuraName == SPELL_AURA_PERIODIC_TRIGGER_SPELL && uint32(m_spellInfo->GetDuration()) == m_spellInfo->Effects[GetEffIndex()].Amplitude) return; @@ -1854,7 +1565,7 @@ void AuraEffect::HandlePhase(AuraApplication const* aurApp, uint8 mode, bool app // call functions which may have additional effects after chainging state of unit // phase auras normally not expected at BG but anyway better check - if (apply && (mode & AURA_EFFECT_HANDLE_REAL)) + if (apply) { // drop flag at invisibiliy in bg target->RemoveAurasWithInterruptFlags(AURA_INTERRUPT_FLAG_IMMUNE_OR_LOST_SELECTION); @@ -2340,11 +2051,7 @@ void AuraEffect::HandleAuraTransform(AuraApplication const* aurApp, uint8 mode, uint32 cr_id = target->GetAuraEffectsByType(SPELL_AURA_MOUNTED).front()->GetMiscValue(); if (CreatureTemplate const* ci = sObjectMgr->GetCreatureTemplate(cr_id)) { - uint32 team = 0; - if (target->GetTypeId() == TYPEID_PLAYER) - team = target->ToPlayer()->GetTeam(); - - uint32 displayID = sObjectMgr->ChooseDisplayId(team, ci); + uint32 displayID = ObjectMgr::ChooseDisplayId(ci); sObjectMgr->GetCreatureModelRandomGender(&displayID); target->SetUInt32Value(UNIT_FIELD_MOUNTDISPLAYID, displayID); @@ -2611,7 +2318,8 @@ void AuraEffect::HandleAuraModPacifyAndSilence(AuraApplication const* aurApp, ui Unit* target = aurApp->GetTarget(); - // Vengeance of the Blue Flight (TODO: REMOVE THIS!) + // Vengeance of the Blue Flight (@todo REMOVE THIS!) + /// @workaround if (m_spellInfo->Id == 45839) { if (apply) @@ -2664,7 +2372,10 @@ void AuraEffect::HandleAuraTrackCreatures(AuraApplication const* aurApp, uint8 m if (target->GetTypeId() != TYPEID_PLAYER) return; - target->SetUInt32Value(PLAYER_TRACK_CREATURES, (apply) ? ((uint32)1)<<(GetMiscValue()-1) : 0); + if (apply) + target->SetFlag(PLAYER_TRACK_CREATURES, uint32(1) << (GetMiscValue() - 1)); + else + target->RemoveFlag(PLAYER_TRACK_CREATURES, uint32(1) << (GetMiscValue() - 1)); } void AuraEffect::HandleAuraTrackResources(AuraApplication const* aurApp, uint8 mode, bool apply) const @@ -2677,7 +2388,10 @@ void AuraEffect::HandleAuraTrackResources(AuraApplication const* aurApp, uint8 m if (target->GetTypeId() != TYPEID_PLAYER) return; - target->SetUInt32Value(PLAYER_TRACK_RESOURCES, (apply) ? ((uint32)1)<<(GetMiscValue()-1): 0); + if (apply) + target->SetFlag(PLAYER_TRACK_RESOURCES, uint32(1) << (GetMiscValue() - 1)); + else + target->RemoveFlag(PLAYER_TRACK_RESOURCES, uint32(1) << (GetMiscValue() - 1)); } void AuraEffect::HandleAuraTrackStealthed(AuraApplication const* aurApp, uint8 mode, bool apply) const @@ -2805,11 +2519,7 @@ void AuraEffect::HandleAuraMounted(AuraApplication const* aurApp, uint8 mode, bo return; } - uint32 team = 0; - if (target->GetTypeId() == TYPEID_PLAYER) - team = target->ToPlayer()->GetTeam(); - - uint32 displayID = sObjectMgr->ChooseDisplayId(team, ci); + uint32 displayID = ObjectMgr::ChooseDisplayId(ci); sObjectMgr->GetCreatureModelRandomGender(&displayID); //some spell has one aura of mount and one of vehicle @@ -3208,6 +2918,9 @@ void AuraEffect::HandleAuraControlVehicle(AuraApplication const* aurApp, uint8 m } else { + // Remove pending passengers before exiting vehicle - might cause an Uninstall + target->GetVehicleKit()->RemovePendingEventsForPassenger(caster); + if (GetId() == 53111) // Devour Humanoid { target->Kill(caster); @@ -3628,22 +3341,19 @@ void AuraEffect::HandleAuraModEffectImmunity(AuraApplication const* aurApp, uint Unit* target = aurApp->GetTarget(); - target->ApplySpellImmune(GetId(), IMMUNITY_EFFECT, GetMiscValue(), apply); + target->ApplySpellImmune(GetId(), IMMUNITY_EFFECT, GetMiscValue(), apply); // when removing flag aura, handle flag drop - if (!apply && target->GetTypeId() == TYPEID_PLAYER - && (GetSpellInfo()->AuraInterruptFlags & AURA_INTERRUPT_FLAG_IMMUNE_OR_LOST_SELECTION)) + Player* player = target->ToPlayer(); + if (!apply && player && (GetSpellInfo()->AuraInterruptFlags & AURA_INTERRUPT_FLAG_IMMUNE_OR_LOST_SELECTION)) { - if (target->GetTypeId() == TYPEID_PLAYER) + if (player->InBattleground()) { - if (target->ToPlayer()->InBattleground()) - { - if (Battleground* bg = target->ToPlayer()->GetBattleground()) - bg->EventPlayerDroppedFlag(target->ToPlayer()); - } - else - sOutdoorPvPMgr->HandleDropFlag((Player*)target, GetSpellInfo()->Id); + if (Battleground* bg = player->GetBattleground()) + bg->EventPlayerDroppedFlag(player); } + else + sOutdoorPvPMgr->HandleDropFlag(player, GetSpellInfo()->Id); } } @@ -3696,7 +3406,7 @@ void AuraEffect::HandleAuraModSchoolImmunity(AuraApplication const* aurApp, uint && GetSpellInfo()->AttributesEx2 & SPELL_ATTR2_DAMAGE_REDUCED_SHIELD) target->RemoveAurasWithInterruptFlags(AURA_INTERRUPT_FLAG_IMMUNE_OR_LOST_SELECTION); - // TODO: optimalize this cycle - use RemoveAurasWithInterruptFlags call or something else + /// @todo optimalize this cycle - use RemoveAurasWithInterruptFlags call or something else if ((apply) && GetSpellInfo()->AttributesEx & SPELL_ATTR1_DISPEL_AURAS_ON_IMMUNITY && GetSpellInfo()->IsPositive()) //Only positive immunity removes auras @@ -4927,7 +4637,7 @@ void AuraEffect::HandleAuraDummy(AuraApplication const* aurApp, uint8 mode, bool if (owner_aura) { // This aura lasts 2 sec, need this hack to properly proc spells - // TODO: drop aura charges for ApplySpellMod in ProcDamageAndSpell + /// @todo drop aura charges for ApplySpellMod in ProcDamageAndSpell GetBase()->SetDuration(owner_aura->GetDuration()); // Make aura be not charged-this prevents removing charge on not crit spells owner_aura->SetCharges(0); @@ -4973,10 +4683,6 @@ void AuraEffect::HandleAuraDummy(AuraApplication const* aurApp, uint8 mode, bool if (Aura* newAura = target->AddAura(71564, target)) newAura->SetStackAmount(newAura->GetSpellInfo()->StackAmount); break; - case 59628: // Tricks of the Trade - if (caster && caster->GetMisdirectionTarget()) - target->SetReducedThreatPercent(100, caster->GetMisdirectionTarget()->GetGUID()); - break; } } // AT REMOVE @@ -5072,20 +4778,6 @@ void AuraEffect::HandleAuraDummy(AuraApplication const* aurApp, uint8 mode, bool if (GetId() == 61777) target->CastSpell(target, GetAmount(), true); break; - case SPELLFAMILY_ROGUE: - // Tricks of the trade - switch (GetId()) - { - case 59628: //Tricks of the trade buff on rogue (6sec duration) - target->SetReducedThreatPercent(0,0); - break; - case 57934: //Tricks of the trade buff on rogue (30sec duration) - if (aurApp->GetRemoveMode() == AURA_REMOVE_BY_EXPIRE || !caster->GetMisdirectionTarget()) - target->SetReducedThreatPercent(0,0); - else - target->SetReducedThreatPercent(0,caster->GetMisdirectionTarget()->GetGUID()); - break; - } default: break; } @@ -5205,11 +4897,7 @@ void AuraEffect::HandleAuraDummy(AuraApplication const* aurApp, uint8 mode, bool if (CreatureTemplate const* creatureInfo = sObjectMgr->GetCreatureTemplate(creatureEntry)) { - uint32 team = 0; - if (target->GetTypeId() == TYPEID_PLAYER) - team = target->ToPlayer()->GetTeam(); - - uint32 displayID = sObjectMgr->ChooseDisplayId(team, creatureInfo); + uint32 displayID = ObjectMgr::ChooseDisplayId(creatureInfo); sObjectMgr->GetCreatureModelRandomGender(&displayID); target->SetUInt32Value(UNIT_FIELD_MOUNTDISPLAYID, displayID); @@ -5365,10 +5053,6 @@ void AuraEffect::HandleAuraEmpathy(AuraApplication const* aurApp, uint8 mode, bo return; Unit* target = aurApp->GetTarget(); - - if (target->GetTypeId() != TYPEID_UNIT) - return; - if (!apply) { // do not remove unit flag if there are more than this auraEffect of that kind on unit on unit @@ -5376,8 +5060,7 @@ void AuraEffect::HandleAuraEmpathy(AuraApplication const* aurApp, uint8 mode, bo return; } - CreatureTemplate const* ci = sObjectMgr->GetCreatureTemplate(target->GetEntry()); - if (ci && ci->type == CREATURE_TYPE_BEAST) + if (target->GetCreatureType() == CREATURE_TYPE_BEAST) target->ApplyModUInt32Value(UNIT_DYNAMIC_FLAGS, UNIT_DYNFLAG_SPECIALINFO, apply); } @@ -5605,10 +5288,7 @@ void AuraEffect::HandleAuraSetVehicle(AuraApplication const* aurApp, uint8 mode, target->SendMessageToSet(&data, true); if (apply) - { - data.Initialize(SMSG_ON_CANCEL_EXPECTED_RIDE_VEHICLE_AURA, 0); - target->ToPlayer()->GetSession()->SendPacket(&data); - } + target->ToPlayer()->SendOnCancelExpectedVehicleRideAura(); } void AuraEffect::HandlePreventResurrection(AuraApplication const* aurApp, uint8 mode, bool apply) const @@ -5708,7 +5388,7 @@ void AuraEffect::HandlePeriodicDummyAuraTick(Unit* target, Unit* caster) const // Killing Spree case 51690: { - // TODO: this should use effect[1] of 51690 + /// @todo this should use effect[1] of 51690 UnitList targets; { // eff_radius == 0 @@ -5905,7 +5585,7 @@ void AuraEffect::HandlePeriodicTriggerSpellAuraTick(Unit* target, Unit* caster) triggerSpellId = 30571; break; // Doom - // TODO: effect trigger spell may be independant on spell targets, and executed in spell finish phase + /// @todo effect trigger spell may be independant on spell targets, and executed in spell finish phase // so instakill will be naturally done before trigger spell case 31347: { diff --git a/src/server/game/Spells/Auras/SpellAuras.cpp b/src/server/game/Spells/Auras/SpellAuras.cpp index b33546ee988..51149df1265 100644 --- a/src/server/game/Spells/Auras/SpellAuras.cpp +++ b/src/server/game/Spells/Auras/SpellAuras.cpp @@ -421,7 +421,7 @@ void Aura::_UnapplyForTarget(Unit* target, Unit* caster, AuraApplication * auraA ApplicationMap::iterator itr = m_applications.find(target->GetGUID()); - // TODO: Figure out why this happens + /// @todo Figure out why this happens if (itr == m_applications.end()) { sLog->outError(LOG_FILTER_SPELLS_AURAS, "Aura::_UnapplyForTarget, target:%u, caster:%u, spell:%u was not found in owners application map!", @@ -565,7 +565,7 @@ void Aura::UpdateTargetMap(Unit* caster, bool apply) // owner has to be in world, or effect has to be applied to self if (!GetOwner()->IsSelfOrInSameMap(itr->first)) { - //TODO: There is a crash caused by shadowfiend load addon + /// @todo There is a crash caused by shadowfiend load addon sLog->outFatal(LOG_FILTER_SPELLS_AURAS, "Aura %u: Owner %s (map %u) is not in the same map as target %s (map %u).", GetSpellInfo()->Id, GetOwner()->GetName().c_str(), GetOwner()->IsInWorld() ? GetOwner()->GetMap()->GetId() : uint32(-1), itr->first->GetName().c_str(), itr->first->IsInWorld() ? itr->first->GetMap()->GetId() : uint32(-1)); @@ -908,6 +908,10 @@ bool Aura::CanBeSaved() const if (HasEffectType(SPELL_AURA_OPEN_STABLE)) return false; + // Can't save vehicle auras, it requires both caster & target to be in world + if (HasEffectType(SPELL_AURA_CONTROL_VEHICLE)) + return false; + // Incanter's Absorbtion - considering the minimal duration and problems with aura stacking // we skip saving this aura // Also for some reason other auras put as MultiSlot crash core on keeping them after restart, @@ -937,7 +941,7 @@ void Aura::UnregisterSingleTarget() { ASSERT(m_isSingleTarget); Unit* caster = GetCaster(); - // TODO: find a better way to do this. + /// @todo find a better way to do this. if (!caster) caster = ObjectAccessor::GetObjectInOrOutOfWorld(GetCasterGUID(), (Unit*)NULL); ASSERT(caster); @@ -1162,7 +1166,7 @@ void Aura::HandleAuraSpecificMods(AuraApplication const* aurApp, Unit* caster, b if (caster->HasAura(56370)) SetDuration(0); } - // Todo: This should be moved to similar function in spell::hit + /// @todo This should be moved to similar function in spell::hit else if (GetSpellInfo()->SpellFamilyFlags[0] & 0x01000000) { // Polymorph Sound - Sheep && Penguin @@ -1350,7 +1354,7 @@ void Aura::HandleAuraSpecificMods(AuraApplication const* aurApp, Unit* caster, b if (removeMode == AURA_REMOVE_BY_ENEMY_SPELL && GetSpellInfo()->SpellFamilyFlags[1] & 0x1) { // Shattered Barrier - if (AuraEffect * dummy = caster->GetDummyAuraEffect(SPELLFAMILY_MAGE, 2945, 0)) + if (AuraEffect* dummy = caster->GetDummyAuraEffect(SPELLFAMILY_MAGE, 2945, 0)) if (roll_chance_i(dummy->GetSpellInfo()->ProcChance)) caster->CastSpell(target, 55080, true, NULL, GetEffect(0)); } @@ -1537,17 +1541,6 @@ void Aura::HandleAuraSpecificMods(AuraApplication const* aurApp, Unit* caster, b // mods at aura apply or remove switch (GetSpellInfo()->SpellFamilyName) { - case SPELLFAMILY_GENERIC: - switch (GetId()) - { - case 50720: // Vigilance - if (apply) - target->CastSpell(caster, 59665, true, 0, 0, caster->GetGUID()); - else - target->SetReducedThreatPercent(0, 0); - break; - } - break; case SPELLFAMILY_DRUID: // Enrage if ((GetSpellInfo()->SpellFamilyFlags[0] & 0x80000) && GetSpellInfo()->SpellIconID == 961) @@ -1940,9 +1933,12 @@ void Aura::AddProcCooldown(uint32 /*msec*/) //m_procCooldown = time(NULL) + msec; } -void Aura::PrepareProcToTrigger() +void Aura::PrepareProcToTrigger(AuraApplication* aurApp, ProcEventInfo& eventInfo) { - // TODO: allow scripts to prevent charge drop/cooldown + bool prepare = CallScriptPrepareProcHandlers(aurApp, eventInfo); + if (!prepare) + return; + // take one charge, aura expiration will be handled in Aura::TriggerProcOnEvent (if needed) if (IsUsingCharges()) { @@ -1973,7 +1969,7 @@ bool Aura::IsProcTriggeredOnEvent(AuraApplication* aurApp, ProcEventInfo& eventI if (IsProcOnCooldown()) return false; - // TODO: + /// @todo // something about triggered spells triggering, and add extra attack effect // do checks against db data @@ -1981,20 +1977,24 @@ bool Aura::IsProcTriggeredOnEvent(AuraApplication* aurApp, ProcEventInfo& eventI return false; // do checks using conditions table - ConditionList conditions = sConditionMgr->GetConditionsForNotGroupedEntry(CONDITION_SOURCE_TYPE_SPELL_PROC, GetSpellInfo()->Id); + ConditionList conditions = sConditionMgr->GetConditionsForNotGroupedEntry(CONDITION_SOURCE_TYPE_SPELL_PROC, GetId()); ConditionSourceInfo condInfo = ConditionSourceInfo(eventInfo.GetActor(), eventInfo.GetActionTarget()); if (!sConditionMgr->IsObjectMeetToConditions(condInfo, conditions)) return false; - // TODO: - // - add DoCheckProc() AuraScript hook - // to allow additional requirements for procs + // AuraScript Hook + bool check = const_cast<Aura*>(this)->CallScriptCheckProcHandlers(aurApp, eventInfo); + if (!check) + return false; + + /// @todo + // do allow additional requirements for procs // this is needed because this is the last moment in which you can prevent aura charge drop on proc // and possibly a way to prevent default checks (if there're going to be any) // Check if current equipment meets aura requirements // do that only for passive spells - // TODO: this needs to be unified for all kinds of auras + /// @todo this needs to be unified for all kinds of auras Unit* target = aurApp->GetTarget(); if (IsPassive() && target->GetTypeId() == TYPEID_PLAYER) { @@ -2052,14 +2052,14 @@ float Aura::CalcProcChance(SpellProcEntry const& procEntry, ProcEventInfo& event void Aura::TriggerProcOnEvent(AuraApplication* aurApp, ProcEventInfo& eventInfo) { - // TODO: OnProc hook here + CallScriptProcHandlers(aurApp, eventInfo); + for (uint8 i = 0; i < MAX_SPELL_EFFECTS; ++i) if (aurApp->HasEffect(i)) - // TODO: OnEffectProc hook here (allowing prevention of selected effects) + // OnEffectProc / AfterEffectProc hooks handled in AuraEffect::HandleProc() GetEffect(i)->HandleProc(aurApp, eventInfo); - // TODO: AfterEffectProc hook here - // TODO: AfterProc hook here + CallScriptAfterProcHandlers(aurApp, eventInfo); // Remove aura if we've used last charge to proc if (IsUsingCharges() && !GetCharges()) @@ -2096,16 +2096,17 @@ void Aura::LoadScripts() bool Aura::CallScriptCheckAreaTargetHandlers(Unit* target) { + bool result = true; for (std::list<AuraScript*>::iterator scritr = m_loadedScripts.begin(); scritr != m_loadedScripts.end(); ++scritr) { (*scritr)->_PrepareScriptCall(AURA_SCRIPT_HOOK_CHECK_AREA_TARGET); std::list<AuraScript::CheckAreaTargetHandler>::iterator hookItrEnd = (*scritr)->DoCheckAreaTarget.end(), hookItr = (*scritr)->DoCheckAreaTarget.begin(); for (; hookItr != hookItrEnd; ++hookItr) - if (!(*hookItr).Call(*scritr, target)) - return false; + result &= hookItr->Call(*scritr, target); + (*scritr)->_FinishScriptCall(); } - return true; + return result; } void Aura::CallScriptDispel(DispelInfo* dispelInfo) @@ -2115,7 +2116,8 @@ void Aura::CallScriptDispel(DispelInfo* dispelInfo) (*scritr)->_PrepareScriptCall(AURA_SCRIPT_HOOK_DISPEL); std::list<AuraScript::AuraDispelHandler>::iterator hookItrEnd = (*scritr)->OnDispel.end(), hookItr = (*scritr)->OnDispel.begin(); for (; hookItr != hookItrEnd; ++hookItr) - (*hookItr).Call(*scritr, dispelInfo); + hookItr->Call(*scritr, dispelInfo); + (*scritr)->_FinishScriptCall(); } } @@ -2127,7 +2129,8 @@ void Aura::CallScriptAfterDispel(DispelInfo* dispelInfo) (*scritr)->_PrepareScriptCall(AURA_SCRIPT_HOOK_AFTER_DISPEL); std::list<AuraScript::AuraDispelHandler>::iterator hookItrEnd = (*scritr)->AfterDispel.end(), hookItr = (*scritr)->AfterDispel.begin(); for (; hookItr != hookItrEnd; ++hookItr) - (*hookItr).Call(*scritr, dispelInfo); + hookItr->Call(*scritr, dispelInfo); + (*scritr)->_FinishScriptCall(); } } @@ -2140,14 +2143,15 @@ bool Aura::CallScriptEffectApplyHandlers(AuraEffect const* aurEff, AuraApplicati (*scritr)->_PrepareScriptCall(AURA_SCRIPT_HOOK_EFFECT_APPLY, aurApp); std::list<AuraScript::EffectApplyHandler>::iterator effEndItr = (*scritr)->OnEffectApply.end(), effItr = (*scritr)->OnEffectApply.begin(); for (; effItr != effEndItr; ++effItr) - { - if ((*effItr).IsEffectAffected(m_spellInfo, aurEff->GetEffIndex())) - (*effItr).Call(*scritr, aurEff, mode); - } + if (effItr->IsEffectAffected(m_spellInfo, aurEff->GetEffIndex())) + effItr->Call(*scritr, aurEff, mode); + if (!preventDefault) preventDefault = (*scritr)->_IsDefaultActionPrevented(); + (*scritr)->_FinishScriptCall(); } + return preventDefault; } @@ -2159,12 +2163,12 @@ bool Aura::CallScriptEffectRemoveHandlers(AuraEffect const* aurEff, AuraApplicat (*scritr)->_PrepareScriptCall(AURA_SCRIPT_HOOK_EFFECT_REMOVE, aurApp); std::list<AuraScript::EffectApplyHandler>::iterator effEndItr = (*scritr)->OnEffectRemove.end(), effItr = (*scritr)->OnEffectRemove.begin(); for (; effItr != effEndItr; ++effItr) - { - if ((*effItr).IsEffectAffected(m_spellInfo, aurEff->GetEffIndex())) - (*effItr).Call(*scritr, aurEff, mode); - } + if (effItr->IsEffectAffected(m_spellInfo, aurEff->GetEffIndex())) + effItr->Call(*scritr, aurEff, mode); + if (!preventDefault) preventDefault = (*scritr)->_IsDefaultActionPrevented(); + (*scritr)->_FinishScriptCall(); } return preventDefault; @@ -2177,10 +2181,9 @@ void Aura::CallScriptAfterEffectApplyHandlers(AuraEffect const* aurEff, AuraAppl (*scritr)->_PrepareScriptCall(AURA_SCRIPT_HOOK_EFFECT_AFTER_APPLY, aurApp); std::list<AuraScript::EffectApplyHandler>::iterator effEndItr = (*scritr)->AfterEffectApply.end(), effItr = (*scritr)->AfterEffectApply.begin(); for (; effItr != effEndItr; ++effItr) - { - if ((*effItr).IsEffectAffected(m_spellInfo, aurEff->GetEffIndex())) - (*effItr).Call(*scritr, aurEff, mode); - } + if (effItr->IsEffectAffected(m_spellInfo, aurEff->GetEffIndex())) + effItr->Call(*scritr, aurEff, mode); + (*scritr)->_FinishScriptCall(); } } @@ -2192,10 +2195,9 @@ void Aura::CallScriptAfterEffectRemoveHandlers(AuraEffect const* aurEff, AuraApp (*scritr)->_PrepareScriptCall(AURA_SCRIPT_HOOK_EFFECT_AFTER_REMOVE, aurApp); std::list<AuraScript::EffectApplyHandler>::iterator effEndItr = (*scritr)->AfterEffectRemove.end(), effItr = (*scritr)->AfterEffectRemove.begin(); for (; effItr != effEndItr; ++effItr) - { - if ((*effItr).IsEffectAffected(m_spellInfo, aurEff->GetEffIndex())) - (*effItr).Call(*scritr, aurEff, mode); - } + if (effItr->IsEffectAffected(m_spellInfo, aurEff->GetEffIndex())) + effItr->Call(*scritr, aurEff, mode); + (*scritr)->_FinishScriptCall(); } } @@ -2208,14 +2210,15 @@ bool Aura::CallScriptEffectPeriodicHandlers(AuraEffect const* aurEff, AuraApplic (*scritr)->_PrepareScriptCall(AURA_SCRIPT_HOOK_EFFECT_PERIODIC, aurApp); std::list<AuraScript::EffectPeriodicHandler>::iterator effEndItr = (*scritr)->OnEffectPeriodic.end(), effItr = (*scritr)->OnEffectPeriodic.begin(); for (; effItr != effEndItr; ++effItr) - { - if ((*effItr).IsEffectAffected(m_spellInfo, aurEff->GetEffIndex())) - (*effItr).Call(*scritr, aurEff); - } + if (effItr->IsEffectAffected(m_spellInfo, aurEff->GetEffIndex())) + effItr->Call(*scritr, aurEff); + if (!preventDefault) preventDefault = (*scritr)->_IsDefaultActionPrevented(); + (*scritr)->_FinishScriptCall(); } + return preventDefault; } @@ -2226,10 +2229,9 @@ void Aura::CallScriptEffectUpdatePeriodicHandlers(AuraEffect* aurEff) (*scritr)->_PrepareScriptCall(AURA_SCRIPT_HOOK_EFFECT_UPDATE_PERIODIC); std::list<AuraScript::EffectUpdatePeriodicHandler>::iterator effEndItr = (*scritr)->OnEffectUpdatePeriodic.end(), effItr = (*scritr)->OnEffectUpdatePeriodic.begin(); for (; effItr != effEndItr; ++effItr) - { - if ((*effItr).IsEffectAffected(m_spellInfo, aurEff->GetEffIndex())) - (*effItr).Call(*scritr, aurEff); - } + if (effItr->IsEffectAffected(m_spellInfo, aurEff->GetEffIndex())) + effItr->Call(*scritr, aurEff); + (*scritr)->_FinishScriptCall(); } } @@ -2241,10 +2243,9 @@ void Aura::CallScriptEffectCalcAmountHandlers(AuraEffect const* aurEff, int32 & (*scritr)->_PrepareScriptCall(AURA_SCRIPT_HOOK_EFFECT_CALC_AMOUNT); std::list<AuraScript::EffectCalcAmountHandler>::iterator effEndItr = (*scritr)->DoEffectCalcAmount.end(), effItr = (*scritr)->DoEffectCalcAmount.begin(); for (; effItr != effEndItr; ++effItr) - { - if ((*effItr).IsEffectAffected(m_spellInfo, aurEff->GetEffIndex())) - (*effItr).Call(*scritr, aurEff, amount, canBeRecalculated); - } + if (effItr->IsEffectAffected(m_spellInfo, aurEff->GetEffIndex())) + effItr->Call(*scritr, aurEff, amount, canBeRecalculated); + (*scritr)->_FinishScriptCall(); } } @@ -2256,10 +2257,9 @@ void Aura::CallScriptEffectCalcPeriodicHandlers(AuraEffect const* aurEff, bool & (*scritr)->_PrepareScriptCall(AURA_SCRIPT_HOOK_EFFECT_CALC_PERIODIC); std::list<AuraScript::EffectCalcPeriodicHandler>::iterator effEndItr = (*scritr)->DoEffectCalcPeriodic.end(), effItr = (*scritr)->DoEffectCalcPeriodic.begin(); for (; effItr != effEndItr; ++effItr) - { - if ((*effItr).IsEffectAffected(m_spellInfo, aurEff->GetEffIndex())) - (*effItr).Call(*scritr, aurEff, isPeriodic, amplitude); - } + if (effItr->IsEffectAffected(m_spellInfo, aurEff->GetEffIndex())) + effItr->Call(*scritr, aurEff, isPeriodic, amplitude); + (*scritr)->_FinishScriptCall(); } } @@ -2271,10 +2271,9 @@ void Aura::CallScriptEffectCalcSpellModHandlers(AuraEffect const* aurEff, SpellM (*scritr)->_PrepareScriptCall(AURA_SCRIPT_HOOK_EFFECT_CALC_SPELLMOD); std::list<AuraScript::EffectCalcSpellModHandler>::iterator effEndItr = (*scritr)->DoEffectCalcSpellMod.end(), effItr = (*scritr)->DoEffectCalcSpellMod.begin(); for (; effItr != effEndItr; ++effItr) - { - if ((*effItr).IsEffectAffected(m_spellInfo, aurEff->GetEffIndex())) - (*effItr).Call(*scritr, aurEff, spellMod); - } + if (effItr->IsEffectAffected(m_spellInfo, aurEff->GetEffIndex())) + effItr->Call(*scritr, aurEff, spellMod); + (*scritr)->_FinishScriptCall(); } } @@ -2286,11 +2285,13 @@ void Aura::CallScriptEffectAbsorbHandlers(AuraEffect* aurEff, AuraApplication co (*scritr)->_PrepareScriptCall(AURA_SCRIPT_HOOK_EFFECT_ABSORB, aurApp); std::list<AuraScript::EffectAbsorbHandler>::iterator effEndItr = (*scritr)->OnEffectAbsorb.end(), effItr = (*scritr)->OnEffectAbsorb.begin(); for (; effItr != effEndItr; ++effItr) - { - if ((*effItr).IsEffectAffected(m_spellInfo, aurEff->GetEffIndex())) - (*effItr).Call(*scritr, aurEff, dmgInfo, absorbAmount); - } - defaultPrevented = (*scritr)->_IsDefaultActionPrevented(); + + if (effItr->IsEffectAffected(m_spellInfo, aurEff->GetEffIndex())) + effItr->Call(*scritr, aurEff, dmgInfo, absorbAmount); + + if (!defaultPrevented) + defaultPrevented = (*scritr)->_IsDefaultActionPrevented(); + (*scritr)->_FinishScriptCall(); } } @@ -2302,10 +2303,9 @@ void Aura::CallScriptEffectAfterAbsorbHandlers(AuraEffect* aurEff, AuraApplicati (*scritr)->_PrepareScriptCall(AURA_SCRIPT_HOOK_EFFECT_AFTER_ABSORB, aurApp); std::list<AuraScript::EffectAbsorbHandler>::iterator effEndItr = (*scritr)->AfterEffectAbsorb.end(), effItr = (*scritr)->AfterEffectAbsorb.begin(); for (; effItr != effEndItr; ++effItr) - { - if ((*effItr).IsEffectAffected(m_spellInfo, aurEff->GetEffIndex())) - (*effItr).Call(*scritr, aurEff, dmgInfo, absorbAmount); - } + if (effItr->IsEffectAffected(m_spellInfo, aurEff->GetEffIndex())) + effItr->Call(*scritr, aurEff, dmgInfo, absorbAmount); + (*scritr)->_FinishScriptCall(); } } @@ -2317,10 +2317,9 @@ void Aura::CallScriptEffectManaShieldHandlers(AuraEffect* aurEff, AuraApplicatio (*scritr)->_PrepareScriptCall(AURA_SCRIPT_HOOK_EFFECT_MANASHIELD, aurApp); std::list<AuraScript::EffectManaShieldHandler>::iterator effEndItr = (*scritr)->OnEffectManaShield.end(), effItr = (*scritr)->OnEffectManaShield.begin(); for (; effItr != effEndItr; ++effItr) - { - if ((*effItr).IsEffectAffected(m_spellInfo, aurEff->GetEffIndex())) - (*effItr).Call(*scritr, aurEff, dmgInfo, absorbAmount); - } + if (effItr->IsEffectAffected(m_spellInfo, aurEff->GetEffIndex())) + effItr->Call(*scritr, aurEff, dmgInfo, absorbAmount); + (*scritr)->_FinishScriptCall(); } } @@ -2332,10 +2331,9 @@ void Aura::CallScriptEffectAfterManaShieldHandlers(AuraEffect* aurEff, AuraAppli (*scritr)->_PrepareScriptCall(AURA_SCRIPT_HOOK_EFFECT_AFTER_MANASHIELD, aurApp); std::list<AuraScript::EffectManaShieldHandler>::iterator effEndItr = (*scritr)->AfterEffectManaShield.end(), effItr = (*scritr)->AfterEffectManaShield.begin(); for (; effItr != effEndItr; ++effItr) - { - if ((*effItr).IsEffectAffected(m_spellInfo, aurEff->GetEffIndex())) - (*effItr).Call(*scritr, aurEff, dmgInfo, absorbAmount); - } + if (effItr->IsEffectAffected(m_spellInfo, aurEff->GetEffIndex())) + effItr->Call(*scritr, aurEff, dmgInfo, absorbAmount); + (*scritr)->_FinishScriptCall(); } } @@ -2347,10 +2345,103 @@ void Aura::CallScriptEffectSplitHandlers(AuraEffect* aurEff, AuraApplication con (*scritr)->_PrepareScriptCall(AURA_SCRIPT_HOOK_EFFECT_SPLIT, aurApp); std::list<AuraScript::EffectSplitHandler>::iterator effEndItr = (*scritr)->OnEffectSplit.end(), effItr = (*scritr)->OnEffectSplit.begin(); for (; effItr != effEndItr; ++effItr) - { - if ((*effItr).IsEffectAffected(m_spellInfo, aurEff->GetEffIndex())) - (*effItr).Call(*scritr, aurEff, dmgInfo, splitAmount); - } + if (effItr->IsEffectAffected(m_spellInfo, aurEff->GetEffIndex())) + effItr->Call(*scritr, aurEff, dmgInfo, splitAmount); + + (*scritr)->_FinishScriptCall(); + } +} + +bool Aura::CallScriptCheckProcHandlers(AuraApplication const* aurApp, ProcEventInfo& eventInfo) +{ + bool result = true; + for (std::list<AuraScript*>::iterator scritr = m_loadedScripts.begin(); scritr != m_loadedScripts.end(); ++scritr) + { + (*scritr)->_PrepareScriptCall(AURA_SCRIPT_HOOK_CHECK_PROC, aurApp); + std::list<AuraScript::CheckProcHandler>::iterator hookItrEnd = (*scritr)->DoCheckProc.end(), hookItr = (*scritr)->DoCheckProc.begin(); + for (; hookItr != hookItrEnd; ++hookItr) + result &= hookItr->Call(*scritr, eventInfo); + + (*scritr)->_FinishScriptCall(); + } + + return result; +} + +bool Aura::CallScriptPrepareProcHandlers(AuraApplication const* aurApp, ProcEventInfo& eventInfo) +{ + bool prepare = true; + for (std::list<AuraScript*>::iterator scritr = m_loadedScripts.begin(); scritr != m_loadedScripts.end(); ++scritr) + { + (*scritr)->_PrepareScriptCall(AURA_SCRIPT_HOOK_PREPARE_PROC, aurApp); + std::list<AuraScript::AuraProcHandler>::iterator effEndItr = (*scritr)->DoPrepareProc.end(), effItr = (*scritr)->DoPrepareProc.begin(); + for (; effItr != effEndItr; ++effItr) + effItr->Call(*scritr, eventInfo); + + if (prepare) + prepare = !(*scritr)->_IsDefaultActionPrevented(); + + (*scritr)->_FinishScriptCall(); + } + + return prepare; +} + +void Aura::CallScriptProcHandlers(AuraApplication const* aurApp, ProcEventInfo& eventInfo) +{ + for (std::list<AuraScript*>::iterator scritr = m_loadedScripts.begin(); scritr != m_loadedScripts.end(); ++scritr) + { + (*scritr)->_PrepareScriptCall(AURA_SCRIPT_HOOK_PROC, aurApp); + std::list<AuraScript::AuraProcHandler>::iterator hookItrEnd = (*scritr)->OnProc.end(), hookItr = (*scritr)->OnProc.begin(); + for (; hookItr != hookItrEnd; ++hookItr) + hookItr->Call(*scritr, eventInfo); + + (*scritr)->_FinishScriptCall(); + } +} + +void Aura::CallScriptAfterProcHandlers(AuraApplication const* aurApp, ProcEventInfo& eventInfo) +{ + for (std::list<AuraScript*>::iterator scritr = m_loadedScripts.begin(); scritr != m_loadedScripts.end(); ++scritr) + { + (*scritr)->_PrepareScriptCall(AURA_SCRIPT_HOOK_AFTER_PROC, aurApp); + std::list<AuraScript::AuraProcHandler>::iterator hookItrEnd = (*scritr)->AfterProc.end(), hookItr = (*scritr)->AfterProc.begin(); + for (; hookItr != hookItrEnd; ++hookItr) + hookItr->Call(*scritr, eventInfo); + + (*scritr)->_FinishScriptCall(); + } +} + +bool Aura::CallScriptEffectProcHandlers(AuraEffect const* aurEff, AuraApplication const* aurApp, ProcEventInfo& eventInfo) +{ + bool preventDefault = false; + for (std::list<AuraScript*>::iterator scritr = m_loadedScripts.begin(); scritr != m_loadedScripts.end(); ++scritr) + { + (*scritr)->_PrepareScriptCall(AURA_SCRIPT_HOOK_EFFECT_PROC, aurApp); + std::list<AuraScript::EffectProcHandler>::iterator effEndItr = (*scritr)->OnEffectProc.end(), effItr = (*scritr)->OnEffectProc.begin(); + for (; effItr != effEndItr; ++effItr) + if (effItr->IsEffectAffected(m_spellInfo, aurEff->GetEffIndex())) + effItr->Call(*scritr, aurEff, eventInfo); + + if (!preventDefault) + preventDefault = (*scritr)->_IsDefaultActionPrevented(); + + (*scritr)->_FinishScriptCall(); + } + return preventDefault; +} + +void Aura::CallScriptAfterEffectProcHandlers(AuraEffect const* aurEff, AuraApplication const* aurApp, ProcEventInfo& eventInfo) +{ + for (std::list<AuraScript*>::iterator scritr = m_loadedScripts.begin(); scritr != m_loadedScripts.end(); ++scritr) + { + (*scritr)->_PrepareScriptCall(AURA_SCRIPT_HOOK_EFFECT_AFTER_PROC, aurApp); + std::list<AuraScript::EffectProcHandler>::iterator effEndItr = (*scritr)->AfterEffectProc.end(), effItr = (*scritr)->AfterEffectProc.begin(); + for (; effItr != effEndItr; ++effItr) + if (effItr->IsEffectAffected(m_spellInfo, aurEff->GetEffIndex())) + effItr->Call(*scritr, aurEff, eventInfo); + (*scritr)->_FinishScriptCall(); } } diff --git a/src/server/game/Spells/Auras/SpellAuras.h b/src/server/game/Spells/Auras/SpellAuras.h index 88ebee18981..bd351548255 100644 --- a/src/server/game/Spells/Auras/SpellAuras.h +++ b/src/server/game/Spells/Auras/SpellAuras.h @@ -194,7 +194,7 @@ class Aura void AddProcCooldown(uint32 msec); bool IsUsingCharges() const { return m_isUsingCharges; } void SetUsingCharges(bool val) { m_isUsingCharges = val; } - void PrepareProcToTrigger(); + void PrepareProcToTrigger(AuraApplication* aurApp, ProcEventInfo& eventInfo); bool IsProcTriggeredOnEvent(AuraApplication* aurApp, ProcEventInfo& eventInfo) const; float CalcProcChance(SpellProcEntry const& procEntry, ProcEventInfo& eventInfo) const; void TriggerProcOnEvent(AuraApplication* aurApp, ProcEventInfo& eventInfo); @@ -218,6 +218,13 @@ class Aura void CallScriptEffectManaShieldHandlers(AuraEffect* aurEff, AuraApplication const* aurApp, DamageInfo & dmgInfo, uint32 & absorbAmount, bool & defaultPrevented); void CallScriptEffectAfterManaShieldHandlers(AuraEffect* aurEff, AuraApplication const* aurApp, DamageInfo & dmgInfo, uint32 & absorbAmount); void CallScriptEffectSplitHandlers(AuraEffect* aurEff, AuraApplication const* aurApp, DamageInfo & dmgInfo, uint32 & splitAmount); + // Spell Proc Hooks + bool CallScriptCheckProcHandlers(AuraApplication const* aurApp, ProcEventInfo& eventInfo); + bool CallScriptPrepareProcHandlers(AuraApplication const* aurApp, ProcEventInfo& eventInfo); + void CallScriptProcHandlers(AuraApplication const* aurApp, ProcEventInfo& eventInfo); + void CallScriptAfterProcHandlers(AuraApplication const* aurApp, ProcEventInfo& eventInfo); + bool CallScriptEffectProcHandlers(AuraEffect const* aurEff, AuraApplication const* aurApp, ProcEventInfo& eventInfo); + void CallScriptAfterEffectProcHandlers(AuraEffect const* aurEff, AuraApplication const* aurApp, ProcEventInfo& eventInfo); std::list<AuraScript*> m_loadedScripts; private: diff --git a/src/server/game/Spells/Spell.cpp b/src/server/game/Spells/Spell.cpp index af6ed55ed58..93e14154302 100644 --- a/src/server/game/Spells/Spell.cpp +++ b/src/server/game/Spells/Spell.cpp @@ -490,7 +490,7 @@ SpellValue::SpellValue(SpellInfo const* proto) Spell::Spell(Unit* caster, SpellInfo const* info, TriggerCastFlags triggerFlags, uint64 originalCasterGUID, bool skipCheck) : m_spellInfo(sSpellMgr->GetSpellForDifficultyFromSpell(info, caster)), m_caster((info->AttributesEx6 & SPELL_ATTR6_CAST_BY_CHARMER && caster->GetCharmerOrOwner()) ? caster->GetCharmerOrOwner() : caster) -, m_spellValue(new SpellValue(m_spellInfo)) +, m_spellValue(new SpellValue(m_spellInfo)), m_preGeneratedPath(PathGenerator(m_caster)) { m_customError = SPELL_CUSTOM_ERROR_NONE; m_skipCheck = skipCheck; @@ -610,6 +610,7 @@ Spell::~Spell() if (m_caster && m_caster->GetTypeId() == TYPEID_PLAYER) ASSERT(m_caster->ToPlayer()->m_spellModTakingSpell != this); + delete m_spellValue; CheckEffectExecuteData(); @@ -822,7 +823,8 @@ void Spell::SelectEffectImplicitTargets(SpellEffIndex effIndex, SpellImplicitTar if (effects[effIndex].TargetA.GetTarget() == effects[j].TargetA.GetTarget() && effects[effIndex].TargetB.GetTarget() == effects[j].TargetB.GetTarget() && effects[effIndex].ImplicitTargetConditions == effects[j].ImplicitTargetConditions && - effects[effIndex].CalcRadius(m_caster) == effects[j].CalcRadius(m_caster)) + effects[effIndex].CalcRadius(m_caster) == effects[j].CalcRadius(m_caster) && + CheckScriptEffectImplicitTargets(effIndex, j)) { effectMask |= 1 << j; } @@ -1075,7 +1077,7 @@ void Spell::SelectImplicitConeTargets(SpellEffIndex effIndex, SpellImplicitTarge } // for compability with older code - add only unit and go targets - // TODO: remove this + /// @todo remove this std::list<Unit*> unitTargets; std::list<GameObject*> gObjTargets; @@ -1152,7 +1154,7 @@ void Spell::SelectImplicitAreaTargets(SpellEffIndex effIndex, SpellImplicitTarge SearchAreaTargets(targets, radius, center, referer, targetType.GetObjectType(), targetType.GetCheckType(), m_spellInfo->Effects[effIndex].ImplicitTargetConditions); // Custom entries - // TODO: remove those + /// @todo remove those switch (m_spellInfo->Id) { case 46584: // Raise Dead @@ -1227,7 +1229,7 @@ void Spell::SelectImplicitAreaTargets(SpellEffIndex effIndex, SpellImplicitTarge std::list<Unit*> unitTargets; std::list<GameObject*> gObjTargets; // for compability with older code - add only unit and go targets - // TODO: remove this + /// @todo remove this for (std::list<WorldObject*>::iterator itr = targets.begin(); itr != targets.end(); ++itr) { if (Unit* unitTarget = (*itr)->ToUnit()) @@ -1345,11 +1347,6 @@ void Spell::SelectImplicitAreaTargets(SpellEffIndex effIndex, SpellImplicitTarge } } - // todo: move to scripts, but we must call it before resize list by MaxAffectedTargets - // Intimidating Shout - if (m_spellInfo->Id == 5246 && effIndex != EFFECT_0) - unitTargets.remove(m_targets.GetUnitTarget()); - // Other special target selection goes here if (uint32 maxTargets = m_spellValue->MaxAffectedTargets) { @@ -1396,7 +1393,7 @@ void Spell::SelectImplicitCasterDestTargets(SpellEffIndex effIndex, SpellImplici case TARGET_DEST_DB: if (SpellTargetPosition const* st = sSpellMgr->GetSpellTargetPosition(m_spellInfo->Id)) { - // TODO: fix this check + /// @todo fix this check if (m_spellInfo->HasEffect(SPELL_EFFECT_TELEPORT_UNITS) || m_spellInfo->HasEffect(SPELL_EFFECT_BIND)) m_targets.SetDst(st->target_X, st->target_Y, st->target_Z, st->target_Orientation, (int32)st->target_mapId); else if (st->target_mapId == m_caster->GetMapId()) @@ -1655,7 +1652,7 @@ void Spell::SelectImplicitTrajTargets() continue; const float size = std::max((*itr)->GetObjectSize() * 0.7f, 1.0f); // 1/sqrt(3) - // TODO: all calculation should be based on src instead of m_caster + /// @todo all calculation should be based on src instead of m_caster const float objDist2d = m_targets.GetSrcPos()->GetExactDist2d(*itr) * std::cos(m_targets.GetSrcPos()->GetRelativeAngle(*itr)); const float dz = (*itr)->GetPositionZ() - m_targets.GetSrcPos()->m_positionZ; @@ -1755,7 +1752,7 @@ void Spell::SelectImplicitTrajTargets() void Spell::SelectEffectTypeImplicitTargets(uint8 effIndex) { // special case for SPELL_EFFECT_SUMMON_RAF_FRIEND and SPELL_EFFECT_SUMMON_PLAYER - // TODO: this is a workaround - target shouldn't be stored in target map for those spells + /// @todo this is a workaround - target shouldn't be stored in target map for those spells switch (m_spellInfo->Effects[effIndex].Effect) { case SPELL_EFFECT_SUMMON_RAF_FRIEND: @@ -1798,7 +1795,7 @@ void Spell::SelectEffectTypeImplicitTargets(uint8 effIndex) { if (Corpse* corpseTarget = m_targets.GetCorpseTarget()) { - // TODO: this is a workaround - corpses should be added to spell target map too, but we can't do that so we add owner instead + /// @todo this is a workaround - corpses should be added to spell target map too, but we can't do that so we add owner instead if (Player* owner = ObjectAccessor::FindPlayer(corpseTarget->GetOwnerGUID())) target = owner; } @@ -1880,7 +1877,7 @@ void Spell::SearchTargets(SEARCHER& searcher, uint32 containerMask, Unit* refere bool searchInWorld = containerMask & (GRID_MAP_TYPE_MASK_CREATURE | GRID_MAP_TYPE_MASK_PLAYER | GRID_MAP_TYPE_MASK_CORPSE); if (searchInGrid || searchInWorld) { - float x,y; + float x, y; x = pos->GetPositionX(); y = pos->GetPositionY(); @@ -1898,7 +1895,7 @@ void Spell::SearchTargets(SEARCHER& searcher, uint32 containerMask, Unit* refere if (searchInGrid) { TypeContainerVisitor<SEARCHER, GridTypeMapContainer > grid_object_notifier(searcher); - cell.Visit(p, grid_object_notifier, map, radius, x , y); + cell.Visit(p, grid_object_notifier, map, radius, x, y); } } } @@ -2179,7 +2176,7 @@ void Spell::AddUnitTarget(Unit* target, uint32 effectMask, bool checkIfValid /*= if (m_spellInfo->Speed > 0.0f && m_caster != target) { // calculate spell incoming interval - // TODO: this is a hack + /// @todo this is a hack float dist = m_caster->GetDistance(target->GetPositionX(), target->GetPositionY(), target->GetPositionZ()); if (dist < 5.0f) @@ -2407,7 +2404,7 @@ void Spell::DoAllEffectOnTarget(TargetInfo* target) { m_needComboPoints = false; // Restore spell mods for a miss/dodge/parry Cold Blood - // TODO: check how broad this rule should be + /// @todo check how broad this rule should be if (m_caster->GetTypeId() == TYPEID_PLAYER && (missInfo == SPELL_MISS_MISS || missInfo == SPELL_MISS_DODGE || missInfo == SPELL_MISS_PARRY)) m_caster->ToPlayer()->RestoreSpellMods(this, 14177); @@ -2591,7 +2588,7 @@ SpellMissInfo Spell::DoSpellHitOnUnit(Unit* unit, uint32 effectMask, bool scaleA debuff_resist_chance += unit->GetMaxNegativeAuraModifierByMiscValue(SPELL_AURA_MOD_DEBUFF_RESISTANCE, int32(m_spellInfo->Dispel)); if (debuff_resist_chance > 0) - if (irand(0,10000) <= (debuff_resist_chance * 100)) + if (irand(0, 10000) <= (debuff_resist_chance * 100)) { effectMask &= ~(1 << effectNumber); returnVal = SPELL_MISS_RESIST; @@ -2628,14 +2625,14 @@ SpellMissInfo Spell::DoSpellHitOnUnit(Unit* unit, uint32 effectMask, bool scaleA if (m_caster->_IsValidAttackTarget(unit, m_spellInfo)) { unit->RemoveAurasWithInterruptFlags(AURA_INTERRUPT_FLAG_HITBYSPELL); - //TODO: This is a hack. But we do not know what types of stealth should be interrupted by CC + /// @todo This is a hack. But we do not know what types of stealth should be interrupted by CC if ((m_spellInfo->AttributesCu & SPELL_ATTR0_CU_AURA_CC) && unit->IsControlledByPlayer()) unit->RemoveAurasByType(SPELL_AURA_MOD_STEALTH); } else if (m_caster->IsFriendlyTo(unit)) { // for delayed spells ignore negative spells (after duel end) for friendly targets - // TODO: this cause soul transfer bugged + /// @todo this cause soul transfer bugged if (m_spellInfo->Speed > 0.0f && unit->GetTypeId() == TYPEID_PLAYER && !m_spellInfo->IsPositive()) return SPELL_MISS_EVADE; @@ -2764,7 +2761,7 @@ SpellMissInfo Spell::DoSpellHitOnUnit(Unit* unit, uint32 effectMask, bool scaleA void Spell::DoTriggersOnSpellHit(Unit* unit, uint8 effMask) { // Apply additional spell effects to target - // TODO: move this code to scripts + /// @todo move this code to scripts if (m_preCastSpell) { // Paladin immunity shields @@ -2820,7 +2817,7 @@ void Spell::DoTriggersOnSpellHit(Unit* unit, uint8 effMask) } // trigger linked auras remove/apply - // TODO: remove/cleanup this, as this table is not documented and people are doing stupid things with it + /// @todo remove/cleanup this, as this table is not documented and people are doing stupid things with it if (std::vector<int32> const* spellTriggered = sSpellMgr->GetSpellLinked(m_spellInfo->Id + SPELL_LINK_HIT)) for (std::vector<int32>::const_iterator i = spellTriggered->begin(); i != spellTriggered->end(); ++i) if (*i < 0) @@ -3051,7 +3048,7 @@ void Spell::prepare(SpellCastTargets const* targets, AuraEffect const* triggered sLog->outDebug(LOG_FILTER_SPELLS_AURAS, "Spell::prepare: spell id %u source %u caster %d customCastFlags %u mask %u", m_spellInfo->Id, m_caster->GetEntry(), m_originalCaster ? m_originalCaster->GetEntry() : -1, _triggeredCastFlags, m_targets.GetTargetMask()); //Containers for channeled spells have to be set - //TODO:Apply this to all casted spells if needed + /// @todoApply this to all casted spells if needed // Why check duration? 29350: channelled triggers channelled if ((_triggeredCastFlags & TRIGGERED_CAST_DIRECTLY) && (!m_spellInfo->IsChanneled() || !m_spellInfo->GetMaxDuration())) cast(true); @@ -3075,8 +3072,8 @@ void Spell::prepare(SpellCastTargets const* targets, AuraEffect const* triggered // set target for proper facing if ((m_casttime || m_spellInfo->IsChanneled()) && !(_triggeredCastFlags & TRIGGERED_IGNORE_SET_FACING)) - if (m_caster->GetGUID() != m_targets.GetObjectTargetGUID() && m_caster->GetTypeId() == TYPEID_UNIT) - m_caster->FocusTarget(this, m_targets.GetObjectTargetGUID()); + if (m_caster->GetTypeId() == TYPEID_UNIT && m_targets.GetObjectTarget() && m_caster != m_targets.GetObjectTarget()) + m_caster->FocusTarget(this, m_targets.GetObjectTarget()); if (!(_triggeredCastFlags & TRIGGERED_IGNORE_GCD)) TriggerGlobalCooldown(); @@ -3168,10 +3165,12 @@ void Spell::cast(bool skipCheck) if (playerPet->isAlive() && playerPet->isControlled() && (m_targets.GetTargetMask() & TARGET_FLAG_UNIT)) playerPet->AI()->OwnerAttacked(m_targets.GetObjectTarget()->ToUnit()); } + SetExecutedCurrently(true); - if (m_caster->GetTypeId() != TYPEID_PLAYER && m_targets.GetUnitTarget() && m_targets.GetUnitTarget() != m_caster) - m_caster->SetInFront(m_targets.GetUnitTarget()); + if (!(_triggeredCastFlags & TRIGGERED_IGNORE_SET_FACING)) + if (m_caster->GetTypeId() == TYPEID_UNIT && m_targets.GetObjectTarget() && m_caster != m_targets.GetObjectTarget()) + m_caster->SetInFront(m_targets.GetObjectTarget()); // Should this be done for original caster? if (m_caster->GetTypeId() == TYPEID_PLAYER) @@ -3490,7 +3489,7 @@ void Spell::_handle_immediate_phase() if (!m_originalCaster) return; // Handle procs on cast - // TODO: finish new proc system:P + /// @todo finish new proc system:P if (m_UniqueTargetInfo.empty() && m_targets.HasDst()) { uint32 procAttacker = m_procAttacker; @@ -3518,7 +3517,7 @@ void Spell::_handle_finish_phase() if (m_caster->m_extraAttacks && GetSpellInfo()->HasEffect(SPELL_EFFECT_ADD_EXTRA_ATTACKS)) m_caster->HandleProcExtraAttackFor(m_caster->getVictim()); - // TODO: trigger proc phase finish here + /// @todo trigger proc phase finish here } void Spell::SendSpellCooldown() @@ -3972,7 +3971,7 @@ void Spell::SendSpellGo() if (castFlags & CAST_FLAG_RUNE_LIST) // rune cooldowns list { - //TODO: There is a crash caused by a spell with CAST_FLAG_RUNE_LIST casted by a creature + /// @todo There is a crash caused by a spell with CAST_FLAG_RUNE_LIST casted by a creature //The creature is the mover of a player, so HandleCastSpellOpcode uses it as the caster if (Player* player = m_caster->ToPlayer()) { @@ -4835,34 +4834,12 @@ SpellCastResult Spell::CheckCast(bool strict) return SPELL_FAILED_MOVING; } - - Vehicle* vehicle = m_caster->GetVehicle(); - if (vehicle && !(_triggeredCastFlags & TRIGGERED_IGNORE_CASTER_MOUNTED_OR_ON_VEHICLE)) + // Check vehicle flags + if (!(_triggeredCastFlags & TRIGGERED_IGNORE_CASTER_MOUNTED_OR_ON_VEHICLE)) { - uint16 checkMask = 0; - for (uint8 effIndex = EFFECT_0; effIndex < MAX_SPELL_EFFECTS; ++effIndex) - { - SpellEffectInfo const* effInfo = &m_spellInfo->Effects[effIndex]; - if (effInfo->ApplyAuraName == SPELL_AURA_MOD_SHAPESHIFT) - { - SpellShapeshiftEntry const* shapeShiftEntry = sSpellShapeshiftStore.LookupEntry(effInfo->MiscValue); - if (shapeShiftEntry && (shapeShiftEntry->flags1 & 1) == 0) // unk flag - checkMask |= VEHICLE_SEAT_FLAG_UNCONTROLLED; - break; - } - } - - if (m_spellInfo->HasAura(SPELL_AURA_MOUNTED)) - checkMask |= VEHICLE_SEAT_FLAG_CAN_CAST_MOUNT_SPELL; - - if (!checkMask) - checkMask = VEHICLE_SEAT_FLAG_CAN_ATTACK; - - // All creatures should be able to cast as passengers freely, restriction and attribute are only for players - VehicleSeatEntry const* vehicleSeat = vehicle->GetSeatForPassenger(m_caster); - if (!(m_spellInfo->AttributesEx6 & SPELL_ATTR6_CASTABLE_WHILE_ON_VEHICLE) && !(m_spellInfo->Attributes & SPELL_ATTR0_CASTABLE_WHILE_MOUNTED) - && (vehicleSeat->m_flags & checkMask) != checkMask && m_caster->GetTypeId() == TYPEID_PLAYER) - return SPELL_FAILED_DONT_REPORT; + SpellCastResult vehicleCheck = m_spellInfo->CheckVehicle(m_caster); + if (vehicleCheck != SPELL_CAST_OK) + return vehicleCheck; } // check spell cast conditions from database @@ -4992,7 +4969,7 @@ SpellCastResult Spell::CheckCast(bool strict) } // Triggered spells also have range check - // TODO: determine if there is some flag to enable/disable the check + /// @todo determine if there is some flag to enable/disable the check castResult = CheckRange(strict); if (castResult != SPELL_CAST_OK) return castResult; @@ -5148,12 +5125,27 @@ SpellCastResult Spell::CheckCast(bool strict) if (strict && m_caster->IsScriptOverriden(m_spellInfo, 6953)) m_caster->RemoveMovementImpairingAuras(); } + if (m_caster->HasUnitState(UNIT_STATE_ROOT)) return SPELL_FAILED_ROOTED; - if (m_caster->GetTypeId() == TYPEID_PLAYER) - if (Unit* target = m_targets.GetUnitTarget()) - if (!target->isAlive()) - return SPELL_FAILED_BAD_TARGETS; + + if (GetSpellInfo()->NeedsExplicitUnitTarget()) + { + Unit* target = m_targets.GetUnitTarget(); + if (!target) + return SPELL_FAILED_DONT_REPORT; + + Position pos; + target->GetContactPoint(m_caster, pos.m_positionX, pos.m_positionY, pos.m_positionZ); + target->GetFirstCollisionPosition(pos, CONTACT_DISTANCE, target->GetRelativeAngle(m_caster)); + + m_preGeneratedPath.SetPathLengthLimit(m_spellInfo->GetMaxRange(true) * 1.5f); + bool result = m_preGeneratedPath.CalculatePath(pos.m_positionX, pos.m_positionY, pos.m_positionZ + target->GetObjectSize()); + if (m_preGeneratedPath.GetPathType() & PATHFIND_SHORT) + return SPELL_FAILED_OUT_OF_RANGE; + else if (!result || m_preGeneratedPath.GetPathType() & PATHFIND_NOPATH) + return SPELL_FAILED_NOPATH; + } break; } case SPELL_EFFECT_SKINNING: @@ -5931,8 +5923,9 @@ SpellCastResult Spell::CheckItems() // if not item target then required item must be equipped else { - if (m_caster->GetTypeId() == TYPEID_PLAYER && !m_caster->ToPlayer()->HasItemFitToSpellRequirements(m_spellInfo)) - return SPELL_FAILED_EQUIPPED_ITEM_CLASS; + if (!(_triggeredCastFlags & TRIGGERED_IGNORE_EQUIPPED_ITEM_REQUIREMENT)) + if (m_caster->GetTypeId() == TYPEID_PLAYER && !m_caster->ToPlayer()->HasItemFitToSpellRequirements(m_spellInfo)) + return SPELL_FAILED_EQUIPPED_ITEM_CLASS; } // check spell focus object @@ -6049,7 +6042,7 @@ SpellCastResult Spell::CheckItems() if (msg != EQUIP_ERR_OK) { ItemTemplate const* pProto = sObjectMgr->GetItemTemplate(m_spellInfo->Effects[i].ItemType); - // TODO: Needs review + /// @todo Needs review if (pProto && !(pProto->ItemLimitCategory)) { p_caster->SendEquipError(msg, NULL, NULL, m_spellInfo->Effects[i].ItemType); @@ -6314,7 +6307,7 @@ SpellCastResult Spell::CheckItems() } // check weapon presence in slots for main/offhand weapons - if (m_spellInfo->EquippedItemClass >=0) + if (!(_triggeredCastFlags & TRIGGERED_IGNORE_EQUIPPED_ITEM_REQUIREMENT) && m_spellInfo->EquippedItemClass >=0) { // main hand weapon required if (m_spellInfo->AttributesEx3 & SPELL_ATTR3_MAIN_HAND) @@ -6505,10 +6498,10 @@ bool Spell::CheckEffectTarget(Unit const* target, uint32 eff) const break; } - if (IsTriggered() || m_spellInfo->AttributesEx2 & SPELL_ATTR2_CAN_TARGET_NOT_IN_LOS) + if (IsTriggered() || m_spellInfo->AttributesEx2 & SPELL_ATTR2_CAN_TARGET_NOT_IN_LOS || DisableMgr::IsDisabledFor(DISABLE_TYPE_SPELL, m_spellInfo->Id, NULL, SPELL_DISABLE_LOS)) return true; - // todo: shit below shouldn't be here, but it's temporary + /// @todo shit below shouldn't be here, but it's temporary //Check targets for LOS visibility (except spells without range limitations) switch (m_spellInfo->Effects[eff].Effect) { @@ -6554,7 +6547,7 @@ bool Spell::IsNextMeleeSwingSpell() const bool Spell::IsAutoActionResetSpell() const { - // TODO: changed SPELL_INTERRUPT_FLAG_AUTOATTACK -> SPELL_INTERRUPT_FLAG_INTERRUPT to fix compile - is this check correct at all? + /// @todo changed SPELL_INTERRUPT_FLAG_AUTOATTACK -> SPELL_INTERRUPT_FLAG_INTERRUPT to fix compile - is this check correct at all? return !IsTriggered() && (m_spellInfo->InterruptFlags & SPELL_INTERRUPT_FLAG_INTERRUPT); } @@ -7141,6 +7134,29 @@ void Spell::CallScriptObjectTargetSelectHandlers(WorldObject*& target, SpellEffI } } +bool Spell::CheckScriptEffectImplicitTargets(uint32 effIndex, uint32 effIndexToCheck) +{ + // Skip if there are not any script + if (!m_loadedScripts.size()) + return true; + + for (std::list<SpellScript*>::iterator itr = m_loadedScripts.begin(); itr != m_loadedScripts.end(); ++itr) + { + std::list<SpellScript::ObjectTargetSelectHandler>::iterator targetSelectHookEnd = (*itr)->OnObjectTargetSelect.end(), targetSelectHookItr = (*itr)->OnObjectTargetSelect.begin(); + for (; targetSelectHookItr != targetSelectHookEnd; ++targetSelectHookItr) + if (((*targetSelectHookItr).IsEffectAffected(m_spellInfo, effIndex) && !(*targetSelectHookItr).IsEffectAffected(m_spellInfo, effIndexToCheck)) || + (!(*targetSelectHookItr).IsEffectAffected(m_spellInfo, effIndex) && (*targetSelectHookItr).IsEffectAffected(m_spellInfo, effIndexToCheck))) + return false; + + std::list<SpellScript::ObjectAreaTargetSelectHandler>::iterator areaTargetSelectHookEnd = (*itr)->OnObjectAreaTargetSelect.end(), areaTargetSelectHookItr = (*itr)->OnObjectAreaTargetSelect.begin(); + for (; areaTargetSelectHookItr != areaTargetSelectHookEnd; ++areaTargetSelectHookItr) + if (((*areaTargetSelectHookItr).IsEffectAffected(m_spellInfo, effIndex) && !(*areaTargetSelectHookItr).IsEffectAffected(m_spellInfo, effIndexToCheck)) || + (!(*areaTargetSelectHookItr).IsEffectAffected(m_spellInfo, effIndex) && (*areaTargetSelectHookItr).IsEffectAffected(m_spellInfo, effIndexToCheck))) + return false; + } + return true; +} + bool Spell::CanExecuteTriggersOnHit(uint8 effMask, SpellInfo const* triggeredByAura) const { bool only_on_caster = (triggeredByAura && (triggeredByAura->AttributesEx4 & SPELL_ATTR4_PROC_ONLY_ON_CASTER)); @@ -7155,7 +7171,7 @@ bool Spell::CanExecuteTriggersOnHit(uint8 effMask, SpellInfo const* triggeredByA void Spell::PrepareTriggersExecutedOnHit() { - // todo: move this to scripts + /// @todo move this to scripts if (m_spellInfo->SpellFamilyName) { SpellInfo const* excludeCasterSpellInfo = sSpellMgr->GetSpellInfo(m_spellInfo->ExcludeCasterAuraSpell); @@ -7166,7 +7182,7 @@ void Spell::PrepareTriggersExecutedOnHit() m_preCastSpell = m_spellInfo->ExcludeTargetAuraSpell; } - // todo: move this to scripts + /// @todo move this to scripts switch (m_spellInfo->SpellFamilyName) { case SPELLFAMILY_MAGE: diff --git a/src/server/game/Spells/Spell.h b/src/server/game/Spells/Spell.h index 1fe8affc407..47ce299c05d 100644 --- a/src/server/game/Spells/Spell.h +++ b/src/server/game/Spells/Spell.h @@ -23,6 +23,7 @@ #include "SharedDefines.h" #include "ObjectMgr.h" #include "SpellInfo.h" +#include "PathGenerator.h" class Unit; class Player; @@ -631,6 +632,7 @@ class Spell void CallScriptAfterHitHandlers(); void CallScriptObjectAreaTargetSelectHandlers(std::list<WorldObject*>& targets, SpellEffIndex effIndex); void CallScriptObjectTargetSelectHandlers(WorldObject*& target, SpellEffIndex effIndex); + bool CheckScriptEffectImplicitTargets(uint32 effIndex, uint32 effIndexToCheck); std::list<SpellScript*> m_loadedScripts; struct HitTriggerSpell @@ -665,6 +667,7 @@ class Spell bool m_skipCheck; uint8 m_auraScaleMask; + PathGenerator m_preGeneratedPath; ByteBuffer * m_effectExecuteData[MAX_SPELL_EFFECTS]; diff --git a/src/server/game/Spells/SpellEffects.cpp b/src/server/game/Spells/SpellEffects.cpp index 8913cf2ac20..4cb40a05e3d 100644 --- a/src/server/game/Spells/SpellEffects.cpp +++ b/src/server/game/Spells/SpellEffects.cpp @@ -63,6 +63,7 @@ #include "GameObjectAI.h" #include "AccountMgr.h" #include "InstanceScript.h" +#include "PathGenerator.h" #include "ReputationMgr.h" pEffect SpellEffects[TOTAL_SPELL_EFFECTS]= @@ -599,7 +600,7 @@ void Spell::EffectSchoolDMG(SpellEffIndex effIndex) } } - // TODO: should this be put on taken but not done? + /// @todo should this be put on taken but not done? if (found) damage += m_spellInfo->Effects[EFFECT_1].CalcValue(); @@ -807,7 +808,7 @@ void Spell::EffectTriggerSpell(SpellEffIndex effIndex) uint32 triggered_spell_id = m_spellInfo->Effects[effIndex].TriggerSpell; - // todo: move those to spell scripts + /// @todo move those to spell scripts if (m_spellInfo->Effects[effIndex].Effect == SPELL_EFFECT_TRIGGER_SPELL && effectHandleMode == SPELL_EFFECT_HANDLE_LAUNCH_TARGET) { @@ -883,12 +884,6 @@ void Spell::EffectTriggerSpell(SpellEffIndex effIndex) m_caster->CastSpell(unitTarget, spell->Id, true); return; } - // Righteous Defense - case 31980: - { - m_caster->CastSpell(unitTarget, 31790, true); - return; - } // Cloak of Shadows case 35729: { @@ -1139,32 +1134,8 @@ void Spell::EffectTeleportUnits(SpellEffIndex /*effIndex*/) return; // Pre effects - uint8 uiMaxSafeLevel = 0; switch (m_spellInfo->Id) { - case 48129: // Scroll of Recall - uiMaxSafeLevel = 40; - case 60320: // Scroll of Recall II - if (!uiMaxSafeLevel) - uiMaxSafeLevel = 70; - case 60321: // Scroll of Recal III - if (!uiMaxSafeLevel) - uiMaxSafeLevel = 80; - - if (unitTarget->getLevel() > uiMaxSafeLevel) - { - unitTarget->AddAura(60444, unitTarget); //Apply Lost! Aura - - // ALLIANCE from 60323 to 60330 - HORDE from 60328 to 60335 - uint32 spellId = 60323; - if (m_caster->ToPlayer()->GetTeam() == HORDE) - spellId += 5; - - spellId += urand(0, 7); - m_caster->CastSpell(m_caster, spellId, true); - return; - } - break; case 66550: // teleports outside (Isle of Conquest) if (Player* target = unitTarget->ToPlayer()) { @@ -1188,7 +1159,7 @@ void Spell::EffectTeleportUnits(SpellEffIndex /*effIndex*/) // If not exist data for dest location - return if (!m_targets.HasDst()) { - sLog->outError(LOG_FILTER_SPELLS_AURAS, "Spell::EffectTeleportUnits - does not have destination for spell ID %u\n", m_spellInfo->Id); + sLog->outError(LOG_FILTER_SPELLS_AURAS, "Spell::EffectTeleportUnits - does not have destination for spellId %u.", m_spellInfo->Id); return; } @@ -1408,7 +1379,7 @@ void Spell::EffectSendEvent(SpellEffIndex effIndex) // some spells have no target entries in dbc and they use focus target if (focusObject) target = focusObject; - // TODO: there should be a possibility to pass dest target to event script + /// @todo there should be a possibility to pass dest target to event script } sLog->outDebug(LOG_FILTER_SPELLS_AURAS, "Spell ScriptStart %u for spellid %u in EffectSendEvent ", m_spellInfo->Effects[effIndex].MiscValue, m_spellInfo->Id); @@ -1585,10 +1556,6 @@ void Spell::EffectHealPct(SpellEffIndex /*effIndex*/) if (!m_originalCaster) return; - // Rune Tap - Party - if (m_spellInfo->Id == 59754 && unitTarget == m_caster) - return; - uint32 heal = m_originalCaster->SpellHealingBonusDone(unitTarget, m_spellInfo, unitTarget->CountPctFromMaxHealth(damage), HEAL); heal = unitTarget->SpellHealingBonusTaken(m_originalCaster, m_spellInfo, heal, HEAL); @@ -1792,7 +1759,7 @@ void Spell::EffectCreateItem2(SpellEffIndex effIndex) else player->AutoStoreLoot(m_spellInfo->Id, LootTemplates_Spell); // create some random items } - // TODO: ExecuteLogEffectCreateItem(i, m_spellInfo->Effects[i].ItemType); + /// @todo ExecuteLogEffectCreateItem(i, m_spellInfo->Effects[i].ItemType); } void Spell::EffectCreateRandomItem(SpellEffIndex /*effIndex*/) @@ -1806,7 +1773,7 @@ void Spell::EffectCreateRandomItem(SpellEffIndex /*effIndex*/) // create some random items player->AutoStoreLoot(m_spellInfo->Id, LootTemplates_Spell); - // TODO: ExecuteLogEffectCreateItem(i, m_spellInfo->Effects[i].ItemType); + /// @todo ExecuteLogEffectCreateItem(i, m_spellInfo->Effects[i].ItemType); } void Spell::EffectPersistentAA(SpellEffIndex effIndex) @@ -2024,7 +1991,7 @@ void Spell::SendLoot(uint64 guid, LootType loottype) return; case GAMEOBJECT_TYPE_CHEST: - // TODO: possible must be moved to loot release (in different from linked triggering) + /// @todo possible must be moved to loot release (in different from linked triggering) if (gameObjTarget->GetGOInfo()->chest.eventId) { sLog->outDebug(LOG_FILTER_SPELLS_AURAS, "Chest ScriptStart id %u for GO %u", gameObjTarget->GetGOInfo()->chest.eventId, gameObjTarget->GetDBTableGUIDLow()); @@ -2065,7 +2032,7 @@ void Spell::EffectOpenLock(SpellEffIndex effIndex) if (gameObjTarget) { GameObjectTemplate const* goInfo = gameObjTarget->GetGOInfo(); - // Arathi Basin banner opening. // TODO: Verify correctness of this check + // Arathi Basin banner opening. /// @todo Verify correctness of this check if ((goInfo->type == GAMEOBJECT_TYPE_BUTTON && goInfo->button.noDamageImmune) || (goInfo->type == GAMEOBJECT_TYPE_GOOBER && goInfo->goober.losOK)) { @@ -2093,7 +2060,7 @@ void Spell::EffectOpenLock(SpellEffIndex effIndex) gameObjTarget->SetLootState(GO_JUST_DEACTIVATED); return; } - // TODO: Add script for spell 41920 - Filling, becouse server it freze when use this spell + /// @todo Add script for spell 41920 - Filling, becouse server it freze when use this spell // handle outdoor pvp object opening, return true if go was registered for handling // these objects must have been spawned by outdoorpvp! else if (gameObjTarget->GetGOInfo()->type == GAMEOBJECT_TYPE_GOOBER && sOutdoorPvPMgr->HandleOpenGo(player, gameObjTarget->GetGUID())) @@ -2597,7 +2564,7 @@ void Spell::EffectDualWield(SpellEffIndex /*effIndex*/) void Spell::EffectPull(SpellEffIndex effIndex) { - // TODO: create a proper pull towards distract spell center for distract + /// @todo create a proper pull towards distract spell center for distract EffectNULL(effIndex); } @@ -2796,7 +2763,7 @@ void Spell::EffectEnchantItemPerm(SpellEffIndex effIndex) if (!item_owner) return; - if (item_owner != p_caster && !AccountMgr::IsPlayerAccount(p_caster->GetSession()->GetSecurity()) && sWorld->getBoolConfig(CONFIG_GM_LOG_TRADE)) + if (item_owner != p_caster && p_caster->GetSession()->HasPermission(RBAC_PERM_LOG_GM_TRADE)) { sLog->outCommand(p_caster->GetSession()->GetAccountId(), "GM %s (Account: %u) enchanting(perm): %s (Entry: %d) for player: %s (Account: %u)", p_caster->GetName().c_str(), p_caster->GetSession()->GetAccountId(), @@ -2861,7 +2828,7 @@ void Spell::EffectEnchantItemPrismatic(SpellEffIndex effIndex) if (!item_owner) return; - if (item_owner != p_caster && !AccountMgr::IsPlayerAccount(p_caster->GetSession()->GetSecurity()) && sWorld->getBoolConfig(CONFIG_GM_LOG_TRADE)) + if (item_owner != p_caster && p_caster->GetSession()->HasPermission(RBAC_PERM_LOG_GM_TRADE)) { sLog->outCommand(p_caster->GetSession()->GetAccountId(), "GM %s (Account: %u) enchanting(perm): %s (Entry: %d) for player: %s (Account: %u)", p_caster->GetName().c_str(), p_caster->GetSession()->GetAccountId(), @@ -2995,7 +2962,7 @@ void Spell::EffectEnchantItemTmp(SpellEffIndex effIndex) if (!item_owner) return; - if (item_owner != p_caster && !AccountMgr::IsPlayerAccount(p_caster->GetSession()->GetSecurity()) && sWorld->getBoolConfig(CONFIG_GM_LOG_TRADE)) + if (item_owner != p_caster && p_caster->GetSession()->HasPermission(RBAC_PERM_LOG_GM_TRADE)) { sLog->outCommand(p_caster->GetSession()->GetAccountId(), "GM %s (Account: %u) enchanting(temp): %s (Entry: %d) for player: %s (Account: %u)", p_caster->GetName().c_str(), p_caster->GetSession()->GetAccountId(), @@ -3245,24 +3212,6 @@ void Spell::EffectWeaponDmg(SpellEffIndex effIndex) switch (m_spellInfo->SpellFamilyName) { - case SPELLFAMILY_GENERIC: - { - switch (m_spellInfo->Id) - { - case 69055: // Saber Lash - case 70814: // Saber Lash - { - uint32 count = 0; - for (std::list<TargetInfo>::iterator ihit = m_UniqueTargetInfo.begin(); ihit != m_UniqueTargetInfo.end(); ++ihit) - if (ihit->effectMask & (1 << effIndex)) - ++count; - - totalDamagePercentMod /= count; - break; - } - } - break; - } case SPELLFAMILY_WARRIOR: { // Devastate (player ones) @@ -3283,7 +3232,7 @@ void Spell::EffectWeaponDmg(SpellEffIndex effIndex) } if (m_spellInfo->SpellFamilyFlags[0] & 0x8000000) // Mocking Blow { - if (unitTarget->IsImmunedToSpellEffect(m_spellInfo,EFFECT_1) || unitTarget->GetTypeId() == TYPEID_PLAYER) + if (unitTarget->IsImmunedToSpellEffect(m_spellInfo, EFFECT_1) || unitTarget->GetTypeId() == TYPEID_PLAYER) { m_damage = 0; return; @@ -3569,7 +3518,7 @@ void Spell::EffectInterruptCast(SpellEffIndex effIndex) if (!unitTarget || !unitTarget->isAlive()) return; - // TODO: not all spells that used this effect apply cooldown at school spells + /// @todo not all spells that used this effect apply cooldown at school spells // also exist case: apply cooldown to interrupted cast only and to all spells // there is no CURRENT_AUTOREPEAT_SPELL spells that can be interrupted for (uint32 i = CURRENT_FIRST_NON_MELEE_SPELL; i < CURRENT_AUTOREPEAT_SPELL; ++i) @@ -3667,7 +3616,7 @@ void Spell::EffectScriptEffect(SpellEffIndex effIndex) if (effectHandleMode != SPELL_EFFECT_HANDLE_HIT_TARGET) return; - // TODO: we must implement hunter pet summon at login there (spell 6962) + /// @todo we must implement hunter pet summon at login there (spell 6962) switch (m_spellInfo->SpellFamilyName) { @@ -3732,23 +3681,6 @@ void Spell::EffectScriptEffect(SpellEffIndex effIndex) return; unitTarget->RemoveAurasDueToSpell(m_spellInfo->Effects[effIndex].CalcValue()); break; - // PX-238 Winter Wondervolt TRAP - case 26275: - { - uint32 spells[4] = { 26272, 26157, 26273, 26274 }; - - // check presence - for (uint8 j = 0; j < 4; ++j) - if (unitTarget->HasAuraEffect(spells[j], 0)) - return; - - // select spell - uint32 iTmpSpellId = spells[urand(0, 3)]; - - // cast - unitTarget->CastSpell(unitTarget, iTmpSpellId, true); - return; - } // Bending Shinbone case 8856: { @@ -3794,14 +3726,6 @@ void Spell::EffectScriptEffect(SpellEffIndex effIndex) m_caster->CastSpell(unitTarget, 22682, true); return; } - // Piccolo of the Flaming Fire - case 17512: - { - if (!unitTarget || unitTarget->GetTypeId() != TYPEID_PLAYER) - return; - unitTarget->HandleEmoteCommand(EMOTE_STATE_DANCE); - return; - } // Decimate case 28374: case 54426: @@ -3944,17 +3868,6 @@ void Spell::EffectScriptEffect(SpellEffIndex effIndex) m_caster->MonsterTextEmote(buf, 0); break; } - // Vigilance - case 50725: - { - if (!unitTarget || unitTarget->GetTypeId() != TYPEID_PLAYER) - return; - - // Remove Taunt cooldown - unitTarget->ToPlayer()->RemoveSpellCooldown(355, true); - - return; - } // Death Knight Initiate Visual case 51519: { @@ -3989,7 +3902,7 @@ void Spell::EffectScriptEffect(SpellEffIndex effIndex) unitTarget->CastSpell(unitTarget, iTmpSpellId, true); Creature* npc = unitTarget->ToCreature(); - npc->LoadEquipment(npc->GetEquipmentId()); + npc->LoadEquipment(); return; } // Emblazon Runeblade @@ -4113,17 +4026,6 @@ void Spell::EffectScriptEffect(SpellEffIndex effIndex) } return; } - case 63845: // Create Lance - { - if (m_caster->GetTypeId() != TYPEID_PLAYER) - return; - - if (m_caster->ToPlayer()->GetTeam() == ALLIANCE) - m_caster->CastSpell(m_caster, 63914, true); - else - m_caster->CastSpell(m_caster, 63919, true); - return; - } case 59317: // Teleporting { @@ -4147,7 +4049,7 @@ void Spell::EffectScriptEffect(SpellEffIndex effIndex) { if (Unit* parent = seat->GetVehicleBase()) { - // TODO: a hack, range = 11, should after some time cast, otherwise too far + /// @todo a hack, range = 11, should after some time cast, otherwise too far m_caster->CastSpell(parent, 62496, true); unitTarget->CastSpell(parent, m_spellInfo->Effects[EFFECT_0].CalcValue()); } @@ -4317,46 +4219,6 @@ void Spell::EffectScriptEffect(SpellEffIndex effIndex) return; } } - case SPELLFAMILY_POTION: - { - switch (m_spellInfo->Id) - { - // Netherbloom - case 28702: - { - if (!unitTarget) - return; - // 25% chance of casting a random buff - if (roll_chance_i(75)) - return; - - // triggered spells are 28703 to 28707 - // Note: some sources say, that there was the possibility of - // receiving a debuff. However, this seems to be removed by a patch. - const uint32 spellid = 28703; - - // don't overwrite an existing aura - for (uint8 i = 0; i < 5; ++i) - if (unitTarget->HasAura(spellid + i)) - return; - unitTarget->CastSpell(unitTarget, spellid+urand(0, 4), true); - break; - } - - // Nightmare Vine - case 28720: - { - if (!unitTarget) - return; - // 25% chance of casting Nightmare Pollen - if (roll_chance_i(75)) - return; - unitTarget->CastSpell(unitTarget, 28721, true); - break; - } - } - break; - } case SPELLFAMILY_DEATHKNIGHT: { // Pestilence @@ -4377,19 +4239,6 @@ void Spell::EffectScriptEffect(SpellEffIndex effIndex) } break; } - case SPELLFAMILY_WARRIOR: - { - // Shattering Throw - if (m_spellInfo->SpellFamilyFlags[1] & 0x00400000) - { - if (!unitTarget) - return; - // remove shields, will still display immune to damage part - unitTarget->RemoveAurasWithMechanic(1<<MECHANIC_IMMUNE_SHIELD, AURA_REMOVE_BY_ENEMY_SPELL); - return; - } - break; - } } // normal DB scripted effect @@ -4779,7 +4628,7 @@ void Spell::EffectFeedPet(SpellEffIndex effIndex) uint32 count = 1; player->DestroyItemCount(foodItem, count, true); - // TODO: fix crash when a spell has two effects, both pointed at the same item target + /// @todo fix crash when a spell has two effects, both pointed at the same item target m_caster->CastCustomSpell(pet, m_spellInfo->Effects[effIndex].TriggerSpell, &benefit, NULL, NULL, true); } @@ -4868,45 +4717,12 @@ void Spell::EffectResurrect(SpellEffIndex effIndex) if (effectHandleMode != SPELL_EFFECT_HANDLE_HIT_TARGET) return; - if (!unitTarget) - return; - if (unitTarget->GetTypeId() != TYPEID_PLAYER) + if (!unitTarget || unitTarget->GetTypeId() != TYPEID_PLAYER) return; - if (unitTarget->isAlive()) - return; - if (!unitTarget->IsInWorld()) + if (unitTarget->isAlive() || !unitTarget->IsInWorld()) return; - switch (m_spellInfo->Id) - { - // Defibrillate (Goblin Jumper Cables) have 33% chance on success - case 8342: - if (roll_chance_i(67)) - { - m_caster->CastSpell(m_caster, 8338, true, m_CastItem); - return; - } - break; - // Defibrillate (Goblin Jumper Cables XL) have 50% chance on success - case 22999: - if (roll_chance_i(50)) - { - m_caster->CastSpell(m_caster, 23055, true, m_CastItem); - return; - } - break; - // Defibrillate (Gnomish Army Knife) have 67% chance on success_list - case 54732: - if (roll_chance_i(33)) - { - return; - } - break; - default: - break; - } - Player* target = unitTarget->ToPlayer(); if (target->isRessurectRequested()) // already have one active request @@ -5097,25 +4913,25 @@ void Spell::EffectSkinning(SpellEffIndex /*effIndex*/) void Spell::EffectCharge(SpellEffIndex /*effIndex*/) { + if (!unitTarget) + return; + if (effectHandleMode == SPELL_EFFECT_HANDLE_LAUNCH_TARGET) { - if (!unitTarget) - return; - - float angle = unitTarget->GetRelativeAngle(m_caster); - Position pos; - - unitTarget->GetContactPoint(m_caster, pos.m_positionX, pos.m_positionY, pos.m_positionZ); - unitTarget->GetFirstCollisionPosition(pos, unitTarget->GetObjectSize(), angle); - - m_caster->GetMotionMaster()->MoveCharge(pos.m_positionX, pos.m_positionY, pos.m_positionZ + unitTarget->GetObjectSize()); + // Spell is not using explicit target - no generated path + if (m_preGeneratedPath.GetPathType() == PATHFIND_BLANK) + { + Position pos; + unitTarget->GetContactPoint(m_caster, pos.m_positionX, pos.m_positionY, pos.m_positionZ); + unitTarget->GetFirstCollisionPosition(pos, unitTarget->GetObjectSize(), unitTarget->GetRelativeAngle(m_caster)); + m_caster->GetMotionMaster()->MoveCharge(pos.m_positionX, pos.m_positionY, pos.m_positionZ); + } + else + m_caster->GetMotionMaster()->MoveCharge(m_preGeneratedPath); } if (effectHandleMode == SPELL_EFFECT_HANDLE_HIT_TARGET) { - if (!unitTarget) - return; - // not all charge effects used in negative spells if (!m_spellInfo->IsPositive() && m_caster->GetTypeId() == TYPEID_PLAYER) m_caster->Attack(unitTarget, true); @@ -5151,26 +4967,10 @@ void Spell::EffectKnockBack(SpellEffIndex effIndex) if (creatureTarget->isWorldBoss() || creatureTarget->IsDungeonBoss()) return; - // Spells with SPELL_EFFECT_KNOCK_BACK(like Thunderstorm) can't knoback target if target has ROOT/STUN + // Spells with SPELL_EFFECT_KNOCK_BACK (like Thunderstorm) can't knockback target if target has ROOT/STUN if (unitTarget->HasUnitState(UNIT_STATE_ROOT | UNIT_STATE_STUNNED)) return; - // Typhoon - if (m_spellInfo->SpellFamilyName == SPELLFAMILY_DRUID && m_spellInfo->SpellFamilyFlags[1] & 0x01000000) - { - // Glyph of Typhoon - if (m_caster->HasAura(62135)) - return; - } - - // Thunderstorm - if (m_spellInfo->SpellFamilyName == SPELLFAMILY_SHAMAN && m_spellInfo->SpellFamilyFlags[1] & 0x00002000) - { - // Glyph of Thunderstorm - if (m_caster->HasAura(62132)) - return; - } - // Instantly interrupt non melee spells being casted if (unitTarget->IsNonMeleeSpellCasted(true)) unitTarget->InterruptNonMeleeSpells(true); @@ -5241,6 +5041,12 @@ void Spell::EffectQuestClear(SpellEffIndex effIndex) // we ignore unequippable quest items in this case, it's still be equipped player->TakeQuestSourceItem(logQuest, false); + + if (quest->HasFlag(QUEST_FLAGS_FLAGS_PVP)) + { + player->pvpInfo.IsHostile = player->pvpInfo.IsInHostileArea || player->HasPvPForcingQuest(); + player->UpdatePvPState(); + } } } @@ -5974,7 +5780,7 @@ void Spell::EffectRedirectThreat(SpellEffIndex /*effIndex*/) return; if (unitTarget) - m_caster->SetReducedThreatPercent((uint32)damage, unitTarget->GetGUID()); + m_caster->SetRedirectThreat(unitTarget->GetGUID(), uint32(damage)); } void Spell::EffectGameObjectDamage(SpellEffIndex /*effIndex*/) @@ -6162,7 +5968,7 @@ void Spell::EffectPlaySound(SpellEffIndex effIndex) if (!sSoundEntriesStore.LookupEntry(soundId)) { - sLog->outError(LOG_FILTER_SPELLS_AURAS, "EffectPlayerSound: Sound (Id: %u) not exist in spell %u.", soundId, m_spellInfo->Id); + sLog->outError(LOG_FILTER_SPELLS_AURAS, "EffectPlaySound: Sound (Id: %u) not exist in spell %u.", soundId, m_spellInfo->Id); return; } diff --git a/src/server/game/Spells/SpellInfo.cpp b/src/server/game/Spells/SpellInfo.cpp index afbf85a0a13..8635270bb84 100644 --- a/src/server/game/Spells/SpellInfo.cpp +++ b/src/server/game/Spells/SpellInfo.cpp @@ -23,6 +23,7 @@ #include "ConditionMgr.h" #include "Player.h" #include "Battleground.h" +#include "Vehicle.h" uint32 GetTargetFlagMask(SpellTargetObjectTypes objType) { @@ -232,7 +233,7 @@ SpellImplicitTargetInfo::StaticData SpellImplicitTargetInfo::_data[TOTAL_SPELL_ {TARGET_OBJECT_TYPE_GOBJ, TARGET_REFERENCE_TYPE_TARGET, TARGET_SELECT_CATEGORY_DEFAULT, TARGET_CHECK_DEFAULT, TARGET_DIR_NONE}, // 23 TARGET_GAMEOBJECT_TARGET {TARGET_OBJECT_TYPE_UNIT, TARGET_REFERENCE_TYPE_CASTER, TARGET_SELECT_CATEGORY_CONE, TARGET_CHECK_ENEMY, TARGET_DIR_FRONT}, // 24 TARGET_UNIT_CONE_ENEMY_24 {TARGET_OBJECT_TYPE_UNIT, TARGET_REFERENCE_TYPE_TARGET, TARGET_SELECT_CATEGORY_DEFAULT, TARGET_CHECK_DEFAULT, TARGET_DIR_NONE}, // 25 TARGET_UNIT_TARGET_ANY - {TARGET_OBJECT_TYPE_GOBJ_ITEM, TARGET_REFERENCE_TYPE_TARGET, TARGET_SELECT_CATEGORY_DEFAULT, TARGET_CHECK_DEFAULT, TARGET_DIR_NONE}, // 26 TARGET_GAMEOBJECT_ITEM_TARGET + {TARGET_OBJECT_TYPE_GOBJ_ITEM, TARGET_REFERENCE_TYPE_TARGET, TARGET_SELECT_CATEGORY_DEFAULT, TARGET_CHECK_DEFAULT, TARGET_DIR_NONE}, // 26 TARGET_GAMEOBJECT_ITEM_TARGET {TARGET_OBJECT_TYPE_UNIT, TARGET_REFERENCE_TYPE_CASTER, TARGET_SELECT_CATEGORY_DEFAULT, TARGET_CHECK_DEFAULT, TARGET_DIR_NONE}, // 27 TARGET_UNIT_MASTER {TARGET_OBJECT_TYPE_DEST, TARGET_REFERENCE_TYPE_DEST, TARGET_SELECT_CATEGORY_DEFAULT, TARGET_CHECK_ENEMY, TARGET_DIR_NONE}, // 28 TARGET_DEST_DYNOBJ_ENEMY {TARGET_OBJECT_TYPE_DEST, TARGET_REFERENCE_TYPE_DEST, TARGET_SELECT_CATEGORY_DEFAULT, TARGET_CHECK_ALLY, TARGET_DIR_NONE}, // 29 TARGET_DEST_DYNOBJ_ALLY @@ -267,7 +268,7 @@ SpellImplicitTargetInfo::StaticData SpellImplicitTargetInfo::_data[TOTAL_SPELL_ {TARGET_OBJECT_TYPE_UNIT, TARGET_REFERENCE_TYPE_CASTER, TARGET_SELECT_CATEGORY_NEARBY, TARGET_CHECK_RAID, TARGET_DIR_NONE}, // 58 TARGET_UNIT_NEARBY_RAID {TARGET_OBJECT_TYPE_UNIT, TARGET_REFERENCE_TYPE_CASTER, TARGET_SELECT_CATEGORY_CONE, TARGET_CHECK_ALLY, TARGET_DIR_FRONT}, // 59 TARGET_UNIT_CONE_ALLY {TARGET_OBJECT_TYPE_UNIT, TARGET_REFERENCE_TYPE_CASTER, TARGET_SELECT_CATEGORY_CONE, TARGET_CHECK_ENTRY, TARGET_DIR_FRONT}, // 60 TARGET_UNIT_CONE_ENTRY - {TARGET_OBJECT_TYPE_UNIT, TARGET_REFERENCE_TYPE_TARGET, TARGET_SELECT_CATEGORY_AREA, TARGET_CHECK_RAID_CLASS,TARGET_DIR_NONE}, // 61 TARGET_UNIT_TARGET_AREA_RAID_CLASS + {TARGET_OBJECT_TYPE_UNIT, TARGET_REFERENCE_TYPE_TARGET, TARGET_SELECT_CATEGORY_AREA, TARGET_CHECK_RAID_CLASS, TARGET_DIR_NONE}, // 61 TARGET_UNIT_TARGET_AREA_RAID_CLASS {TARGET_OBJECT_TYPE_NONE, TARGET_REFERENCE_TYPE_NONE, TARGET_SELECT_CATEGORY_NYI, TARGET_CHECK_DEFAULT, TARGET_DIR_NONE}, // 62 TARGET_UNK_62 {TARGET_OBJECT_TYPE_DEST, TARGET_REFERENCE_TYPE_TARGET, TARGET_SELECT_CATEGORY_DEFAULT, TARGET_CHECK_DEFAULT, TARGET_DIR_NONE}, // 63 TARGET_DEST_TARGET_ANY {TARGET_OBJECT_TYPE_DEST, TARGET_REFERENCE_TYPE_TARGET, TARGET_SELECT_CATEGORY_DEFAULT, TARGET_CHECK_DEFAULT, TARGET_DIR_FRONT}, // 64 TARGET_DEST_TARGET_FRONT @@ -299,9 +300,9 @@ SpellImplicitTargetInfo::StaticData SpellImplicitTargetInfo::_data[TOTAL_SPELL_ {TARGET_OBJECT_TYPE_UNIT, TARGET_REFERENCE_TYPE_TARGET, TARGET_SELECT_CATEGORY_DEFAULT, TARGET_CHECK_DEFAULT, TARGET_DIR_NONE}, // 90 TARGET_UNIT_TARGET_MINIPET {TARGET_OBJECT_TYPE_DEST, TARGET_REFERENCE_TYPE_DEST, TARGET_SELECT_CATEGORY_DEFAULT, TARGET_CHECK_DEFAULT, TARGET_DIR_RANDOM}, // 91 TARGET_DEST_DEST_RADIUS {TARGET_OBJECT_TYPE_UNIT, TARGET_REFERENCE_TYPE_CASTER, TARGET_SELECT_CATEGORY_DEFAULT, TARGET_CHECK_DEFAULT, TARGET_DIR_NONE}, // 92 TARGET_UNIT_SUMMONER - {TARGET_OBJECT_TYPE_CORPSE, TARGET_REFERENCE_TYPE_SRC, TARGET_SELECT_CATEGORY_NYI, TARGET_CHECK_ENEMY, TARGET_DIR_NONE}, // 93 TARGET_CORPSE_SRC_AREA_ENEMY + {TARGET_OBJECT_TYPE_CORPSE, TARGET_REFERENCE_TYPE_SRC, TARGET_SELECT_CATEGORY_NYI, TARGET_CHECK_ENEMY, TARGET_DIR_NONE}, // 93 TARGET_CORPSE_SRC_AREA_ENEMY {TARGET_OBJECT_TYPE_UNIT, TARGET_REFERENCE_TYPE_CASTER, TARGET_SELECT_CATEGORY_DEFAULT, TARGET_CHECK_DEFAULT, TARGET_DIR_NONE}, // 94 TARGET_UNIT_VEHICLE - {TARGET_OBJECT_TYPE_UNIT, TARGET_REFERENCE_TYPE_TARGET, TARGET_SELECT_CATEGORY_DEFAULT, TARGET_CHECK_PASSENGER, TARGET_DIR_NONE}, // 95 TARGET_UNIT_TARGET_PASSENGER + {TARGET_OBJECT_TYPE_UNIT, TARGET_REFERENCE_TYPE_TARGET, TARGET_SELECT_CATEGORY_DEFAULT, TARGET_CHECK_PASSENGER, TARGET_DIR_NONE}, // 95 TARGET_UNIT_TARGET_PASSENGER {TARGET_OBJECT_TYPE_UNIT, TARGET_REFERENCE_TYPE_CASTER, TARGET_SELECT_CATEGORY_DEFAULT, TARGET_CHECK_DEFAULT, TARGET_DIR_NONE}, // 96 TARGET_UNIT_PASSENGER_0 {TARGET_OBJECT_TYPE_UNIT, TARGET_REFERENCE_TYPE_CASTER, TARGET_SELECT_CATEGORY_DEFAULT, TARGET_CHECK_DEFAULT, TARGET_DIR_NONE}, // 97 TARGET_UNIT_PASSENGER_1 {TARGET_OBJECT_TYPE_UNIT, TARGET_REFERENCE_TYPE_CASTER, TARGET_SELECT_CATEGORY_DEFAULT, TARGET_CHECK_DEFAULT, TARGET_DIR_NONE}, // 98 TARGET_UNIT_PASSENGER_2 @@ -849,7 +850,7 @@ bool SpellInfo::IsLootCrafting() const return (Effects[0].Effect == SPELL_EFFECT_CREATE_RANDOM_ITEM || // different random cards from Inscription (121==Virtuoso Inking Set category) r without explicit item (Effects[0].Effect == SPELL_EFFECT_CREATE_ITEM_2 && - (TotemCategory[0] != 0 || Effects[0].ItemType == 0))); + ((TotemCategory[0] != 0 || (Totem[0] != 0 && SpellIconID == 1)) || Effects[0].ItemType == 0))); } bool SpellInfo::IsQuestTame() const @@ -1030,6 +1031,12 @@ bool SpellInfo::IsMultiSlotAura() const return IsPassive() || Id == 55849 || Id == 40075 || Id == 44413; // Power Spark, Fel Flak Fire, Incanter's Absorption } +bool SpellInfo::IsStackableOnOneSlotWithDifferentCasters() const +{ + /// TODO: Re-verify meaning of SPELL_ATTR3_STACK_FOR_DIFF_CASTERS and update conditions here + return StackAmount > 1 && !IsChanneled() && !(AttributesEx3 & SPELL_ATTR3_STACK_FOR_DIFF_CASTERS); +} + bool SpellInfo::IsDeathPersistent() const { return AttributesEx3 & SPELL_ATTR3_DEATH_PERSISTENT; @@ -1168,10 +1175,8 @@ bool SpellInfo::IsSingleTarget() const bool SpellInfo::IsSingleTargetWith(SpellInfo const* spellInfo) const { - // TODO - need better check - // Equal icon and spellfamily - if (SpellFamilyName == spellInfo->SpellFamilyName && - SpellIconID == spellInfo->SpellIconID) + // Same spell? + if (IsRankOf(spellInfo)) return true; SpellSpecificType spec = GetSpellSpecific(); @@ -1287,7 +1292,7 @@ SpellCastResult SpellInfo::CheckShapeshift(uint32 form) const // Check if stance disables cast of not-stance spells // Example: cannot cast any other spells in zombie or ghoul form - // TODO: Find a way to disable use of these spells clientside + /// @todo Find a way to disable use of these spells clientside if (shapeInfo && shapeInfo->flags1 & 0x400) { if (!(stanceMask & Stances)) @@ -1610,6 +1615,56 @@ SpellCastResult SpellInfo::CheckExplicitTarget(Unit const* caster, WorldObject c return SPELL_CAST_OK; } +SpellCastResult SpellInfo::CheckVehicle(Unit const* caster) const +{ + // All creatures should be able to cast as passengers freely, restriction and attribute are only for players + if (caster->GetTypeId() != TYPEID_PLAYER) + return SPELL_CAST_OK; + + Vehicle* vehicle = caster->GetVehicle(); + if (vehicle) + { + uint16 checkMask = 0; + for (uint8 effIndex = EFFECT_0; effIndex < MAX_SPELL_EFFECTS; ++effIndex) + { + if (Effects[effIndex].ApplyAuraName == SPELL_AURA_MOD_SHAPESHIFT) + { + SpellShapeshiftEntry const* shapeShiftEntry = sSpellShapeshiftStore.LookupEntry(Effects[effIndex].MiscValue); + if (shapeShiftEntry && (shapeShiftEntry->flags1 & 1) == 0) // unk flag + checkMask |= VEHICLE_SEAT_FLAG_UNCONTROLLED; + break; + } + } + + if (HasAura(SPELL_AURA_MOUNTED)) + checkMask |= VEHICLE_SEAT_FLAG_CAN_CAST_MOUNT_SPELL; + + if (!checkMask) + checkMask = VEHICLE_SEAT_FLAG_CAN_ATTACK; + + VehicleSeatEntry const* vehicleSeat = vehicle->GetSeatForPassenger(caster); + if (!(AttributesEx6 & SPELL_ATTR6_CASTABLE_WHILE_ON_VEHICLE) && !(Attributes & SPELL_ATTR0_CASTABLE_WHILE_MOUNTED) + && (vehicleSeat->m_flags & checkMask) != checkMask) + return SPELL_FAILED_CANT_DO_THAT_RIGHT_NOW; + + // Can only summon uncontrolled minions/guardians when on controlled vehicle + if (vehicleSeat->m_flags & (VEHICLE_SEAT_FLAG_CAN_CONTROL | VEHICLE_SEAT_FLAG_UNK2)) + { + for (uint32 i = EFFECT_0; i < MAX_SPELL_EFFECTS; ++i) + { + if (Effects[i].Effect != SPELL_EFFECT_SUMMON) + continue; + + SummonPropertiesEntry const* props = sSummonPropertiesStore.LookupEntry(Effects[i].MiscValueB); + if (props && props->Category != SUMMON_CATEGORY_WILD) + return SPELL_FAILED_CANT_DO_THAT_RIGHT_NOW; + } + } + } + + return SPELL_CAST_OK; +} + bool SpellInfo::CheckTargetCreatureType(Unit const* target) const { // Curse of Doom & Exorcism: not find another way to fix spell target check :/ @@ -1922,6 +1977,9 @@ SpellSpecificType SpellInfo::GetSpellSpecific() const case SPELL_AURA_AOE_CHARM: return SPELL_SPECIFIC_CHARM; case SPELL_AURA_TRACK_CREATURES: + /// @workaround For non-stacking tracking spells (We need generic solution) + if (Id == 30645) // Gas Cloud Tracking + return SPELL_SPECIFIC_NORMAL; case SPELL_AURA_TRACK_RESOURCES: case SPELL_AURA_TRACK_STEALTHED: return SPELL_SPECIFIC_TRACKER; diff --git a/src/server/game/Spells/SpellInfo.h b/src/server/game/Spells/SpellInfo.h index 23682c3d48f..3e6ba0023b1 100644 --- a/src/server/game/Spells/SpellInfo.h +++ b/src/server/game/Spells/SpellInfo.h @@ -22,6 +22,7 @@ #include "Util.h" #include "DBCStructure.h" #include "Object.h" +#include "SpellAuraDefines.h" class Unit; class Player; @@ -392,6 +393,7 @@ public: bool IsStackableWithRanks() const; bool IsPassiveStackableWithRanks() const; bool IsMultiSlotAura() const; + bool IsStackableOnOneSlotWithDifferentCasters() const; bool IsDeathPersistent() const; bool IsRequiringDeadTarget() const; bool IsAllowingDeadTarget() const; @@ -419,6 +421,7 @@ public: SpellCastResult CheckLocation(uint32 map_id, uint32 zone_id, uint32 area_id, Player const* player = NULL) const; SpellCastResult CheckTarget(Unit const* caster, WorldObject const* target, bool implicit = true) const; SpellCastResult CheckExplicitTarget(Unit const* caster, WorldObject const* target, Item const* itemTarget = NULL) const; + SpellCastResult CheckVehicle(Unit const* caster) const; bool CheckTargetCreatureType(Unit const* target) const; SpellSchoolMask GetSchoolMask() const; diff --git a/src/server/game/Spells/SpellMgr.cpp b/src/server/game/Spells/SpellMgr.cpp index 582f13284bb..31d433367ac 100644 --- a/src/server/game/Spells/SpellMgr.cpp +++ b/src/server/game/Spells/SpellMgr.cpp @@ -592,21 +592,6 @@ bool SpellMgr::IsSpellRequiringSpell(uint32 spellid, uint32 req_spellid) const return false; } -const SpellsRequiringSpellMap SpellMgr::GetSpellsRequiringSpell() -{ - return this->mSpellsReqSpell; -} - -uint32 SpellMgr::GetSpellRequired(uint32 spell_id) const -{ - SpellRequiredMap::const_iterator itr = mSpellReq.find(spell_id); - - if (itr == mSpellReq.end()) - return 0; - - return itr->second; -} - SpellLearnSkillNode const* SpellMgr::GetSpellLearnSkill(uint32 spell_id) const { SpellLearnSkillMap::const_iterator itr = mSpellLearnSkills.find(spell_id); @@ -777,7 +762,7 @@ SpellProcEventEntry const* SpellMgr::GetSpellProcEvent(uint32 spellId) const return NULL; } -bool SpellMgr::IsSpellProcEventCanTriggeredBy(SpellProcEventEntry const* spellProcEvent, uint32 EventProcFlag, SpellInfo const* procSpell, uint32 procFlags, uint32 procExtra, bool active) +bool SpellMgr::IsSpellProcEventCanTriggeredBy(SpellProcEventEntry const* spellProcEvent, uint32 EventProcFlag, SpellInfo const* procSpell, uint32 procFlags, uint32 procExtra, bool active) const { // No extra req need uint32 procEvent_procEx = PROC_EX_NONE; @@ -914,7 +899,7 @@ SpellProcEntry const* SpellMgr::GetSpellProcEntry(uint32 spellId) const return NULL; } -bool SpellMgr::CanSpellTriggerProcOnEvent(SpellProcEntry const& procEntry, ProcEventInfo& eventInfo) +bool SpellMgr::CanSpellTriggerProcOnEvent(SpellProcEntry const& procEntry, ProcEventInfo& eventInfo) const { // proc type doesn't match if (!(eventInfo.GetTypeMask() & procEntry.typeMask)) @@ -1015,7 +1000,7 @@ SkillLineAbilityMapBounds SpellMgr::GetSkillLineAbilityMapBounds(uint32 spell_id return mSkillLineAbilityMap.equal_range(spell_id); } -PetAura const* SpellMgr::GetPetAura(uint32 spell_id, uint8 eff) +PetAura const* SpellMgr::GetPetAura(uint32 spell_id, uint8 eff) const { SpellPetAuraMap::const_iterator itr = mSpellPetAuraMap.find((spell_id<<8) + eff); if (itr != mSpellPetAuraMap.end()) @@ -2128,7 +2113,7 @@ void SpellMgr::LoadEnchantCustomAttr() if (!spellInfo) continue; - // TODO: find a better check + /// @todo find a better check if (!(spellInfo->AttributesEx2 & SPELL_ATTR2_PRESERVE_ENCHANT_IN_ARENA) || !(spellInfo->Attributes & SPELL_ATTR0_NOT_SHAPESHIFT)) continue; @@ -3371,6 +3356,17 @@ void SpellMgr::LoadDbcDataCorrections() case 64596: // Cosmic Smash (Algalon the Observer) spellInfo->rangeIndex = 6; // 100yd break; + case 64014: // Expedition Base Camp Teleport + case 64024: // Conservatory Teleport + case 64025: // Halls of Invention Teleport + case 64028: // Colossal Forge Teleport + case 64029: // Shattered Walkway Teleport + case 64030: // Antechamber Teleport + case 64031: // Scrapyard Teleport + case 64032: // Formation Grounds Teleport + case 65042: // Prison of Yogg-Saron Teleport + spellInfo->EffectImplicitTargetA[0] = TARGET_DEST_DB; + break; // ENDOF ULDUAR SPELLS // // TRIAL OF THE CRUSADER SPELLS @@ -3397,9 +3393,9 @@ void SpellMgr::LoadDbcDataCorrections() case 70861: // Sindragosa's Lair Teleport spellInfo->EffectImplicitTargetA[0] = TARGET_DEST_DB; break; - case 69055: // Saber Lash (Lord Marrowgar) - case 70814: // Saber Lash (Lord Marrowgar) - spellInfo->EffectRadiusIndex[0] = EFFECT_RADIUS_5_YARDS; // 5yd + case 69055: // Bone Slice (Lord Marrowgar) + case 70814: // Bone Slice (Lord Marrowgar) + spellInfo->EffectRadiusIndex[0] = EFFECT_RADIUS_8_YARDS; // 5yd break; case 69075: // Bone Storm (Lord Marrowgar) case 70834: // Bone Storm (Lord Marrowgar) @@ -3464,7 +3460,7 @@ void SpellMgr::LoadDbcDataCorrections() case 71518: // Unholy Infusion Quest Credit (Professor Putricide) case 72934: // Blood Infusion Quest Credit (Blood-Queen Lana'thel) case 72289: // Frost Infusion Quest Credit (Sindragosa) - spellInfo->EffectRadiusIndex[0] = EFFECT_RADIUS_50000_YARDS; // another missing radius + spellInfo->EffectRadiusIndex[0] = EFFECT_RADIUS_200_YARDS; // another missing radius break; case 71708: // Empowered Flare (Blood Prince Council) case 72785: // Empowered Flare (Blood Prince Council) @@ -3613,6 +3609,35 @@ void SpellMgr::LoadDbcDataCorrections() break; // ENDOF RUBY SANCTUM SPELLS // + // EYE OF ETERNITY SPELLS + // All spells below work even without these changes. The LOS attribute is due to problem + // from collision between maps & gos with active destroyed state. + case 57473: // Arcane Storm bonus explicit visual spell + case 57431: // Summon Static Field + case 56091: // Flame Spike (Wyrmrest Skytalon) + case 56092: // Engulf in Flames (Wyrmrest Skytalon) + case 57090: // Revivify (Wyrmrest Skytalon) + case 57143: // Life Burst (Wyrmrest Skytalon) + spellInfo->AttributesEx2 |= SPELL_ATTR2_CAN_TARGET_NOT_IN_LOS; + break; + // This would never crit on retail and it has attribute for SPELL_ATTR3_NO_DONE_BONUS because is handled from player, + // until someone figures how to make scions not critting without hack and without making them main casters this should stay here. + case 63934: // Arcane Barrage (casted by players and NONMELEEDAMAGELOG with caster Scion of Eternity (original caster)). + spellInfo->AttributesEx2 |= SPELL_ATTR2_CANT_CRIT; + break; + // ENDOF EYE OF ETERNITY SPELLS + // + // OCULUS SPELLS + // The spells below are here because their effect 1 is giving warning due to + // triggered spell not found in any dbc and is missing from encounter source* of data. + // Even judged as clientside these spells can't be guessed for* now. + case 49462: // Call Ruby Drake + case 49461: // Call Amber Drake + case 49345: // Call Emerald Drake + spellInfo->Effect[1] = 0; + break; + // ENDOF OCULUS SPELLS + // case 40055: // Introspection case 40165: // Introspection case 40166: // Introspection @@ -3626,13 +3651,8 @@ void SpellMgr::LoadDbcDataCorrections() spellInfo->manaCost = 0; spellInfo->manaPerSecond = 0; break; - // OCULUS SPELLS - // The spells below are here, because their effect 1 is giving warning, because the triggered spell is not found in dbc and is missing from encounter sniff. - case 49462: // Call Ruby Drake - case 49461: // Call Amber Drake - case 49345: // Call Emerald Drake - spellInfo->Effect[1] = 0; - break; + case 24314: // Threatening Gaze + spellInfo->AuraInterruptFlags |= AURA_INTERRUPT_FLAG_CAST | AURA_INTERRUPT_FLAG_MOVE | AURA_INTERRUPT_FLAG_JUMP; default: break; } diff --git a/src/server/game/Spells/SpellMgr.h b/src/server/game/Spells/SpellMgr.h index 0cdb9601370..c1b64e76a41 100644 --- a/src/server/game/Spells/SpellMgr.h +++ b/src/server/game/Spells/SpellMgr.h @@ -22,9 +22,15 @@ // For static or at-server-startup loaded spell data #include <ace/Singleton.h> -#include "Common.h" + +#include "DBCStructure.h" #include "SharedDefines.h" -#include "Unit.h" +#include "UnorderedMap.h" +#include "Util.h" + +#include <map> +#include <set> +#include <vector> class SpellInfo; class Player; @@ -84,7 +90,7 @@ enum SpellFamilyFlag SPELLFAMILYFLAG_DK_DEATH_STRIKE = 0x00000010, SPELLFAMILYFLAG_DK_DEATH_COIL = 0x00002000, - // TODO: Figure out a more accurate name for the following familyflag(s) + /// @todo Figure out a more accurate name for the following familyflag(s) SPELLFAMILYFLAG_SHAMAN_TOTEM_EFFECTS = 0x04000000 // Seems to be linked to most totems and some totem effects }; @@ -442,10 +448,7 @@ class PetAura typedef UNORDERED_MAP<uint32, uint32> PetAuraMap; public: - PetAura() : removeOnChangePet(false), damage(0) - { - auras.clear(); - } + PetAura() : removeOnChangePet(false), damage(0) { } PetAura(uint32 petEntry, uint32 aura, bool _removeOnChangePet, int _damage) : removeOnChangePet(_removeOnChangePet), damage(_damage) @@ -630,8 +633,6 @@ class SpellMgr SpellRequiredMapBounds GetSpellsRequiredForSpellBounds(uint32 spell_id) const; SpellsRequiringSpellMapBounds GetSpellsRequiringSpellBounds(uint32 spell_id) const; bool IsSpellRequiringSpell(uint32 spellid, uint32 req_spellid) const; - const SpellsRequiringSpellMap GetSpellsRequiringSpell(); - uint32 GetSpellRequired(uint32 spell_id) const; // Spell learning SpellLearnSkillNode const* GetSpellLearnSkill(uint32 spell_id) const; @@ -656,11 +657,11 @@ class SpellMgr // Spell proc event table SpellProcEventEntry const* GetSpellProcEvent(uint32 spellId) const; - bool IsSpellProcEventCanTriggeredBy(SpellProcEventEntry const* spellProcEvent, uint32 EventProcFlag, SpellInfo const* procSpell, uint32 procFlags, uint32 procExtra, bool active); + bool IsSpellProcEventCanTriggeredBy(SpellProcEventEntry const* spellProcEvent, uint32 EventProcFlag, SpellInfo const* procSpell, uint32 procFlags, uint32 procExtra, bool active) const; // Spell proc table SpellProcEntry const* GetSpellProcEntry(uint32 spellId) const; - bool CanSpellTriggerProcOnEvent(SpellProcEntry const& procEntry, ProcEventInfo& eventInfo); + bool CanSpellTriggerProcOnEvent(SpellProcEntry const& procEntry, ProcEventInfo& eventInfo) const; // Spell bonus data table SpellBonusEntry const* GetSpellBonusData(uint32 spellId) const; @@ -670,7 +671,7 @@ class SpellMgr SkillLineAbilityMapBounds GetSkillLineAbilityMapBounds(uint32 spell_id) const; - PetAura const* GetPetAura(uint32 spell_id, uint8 eff); + PetAura const* GetPetAura(uint32 spell_id, uint8 eff) const; SpellEnchantProcEntry const* GetSpellEnchantProcEvent(uint32 enchId) const; bool IsArenaAllowedEnchancment(uint32 ench_id) const; diff --git a/src/server/game/Spells/SpellScript.cpp b/src/server/game/Spells/SpellScript.cpp index c29b08242a0..6229a30a5f0 100644 --- a/src/server/game/Spells/SpellScript.cpp +++ b/src/server/game/Spells/SpellScript.cpp @@ -470,7 +470,7 @@ WorldLocation* SpellScript::GetHitDest() { if (!IsInEffectHook()) { - sLog->outError(LOG_FILTER_TSCR, "Script: `%s` Spell: `%u`: function SpellScript::GetHitGObj was called, but function has no effect in current hook!", m_scriptName->c_str(), m_scriptSpellId); + sLog->outError(LOG_FILTER_TSCR, "Script: `%s` Spell: `%u`: function SpellScript::GetHitDest was called, but function has no effect in current hook!", m_scriptName->c_str(), m_scriptSpellId); return NULL; } return m_spell->destTarget; @@ -612,7 +612,7 @@ SpellValue const* SpellScript::GetSpellValue() bool AuraScript::_Validate(SpellInfo const* entry) { for (std::list<CheckAreaTargetHandler>::iterator itr = DoCheckAreaTarget.begin(); itr != DoCheckAreaTarget.end(); ++itr) - if (!entry->HasAreaAuraEffect()) + if (!entry->HasAreaAuraEffect() && !entry->HasEffect(SPELL_EFFECT_PERSISTENT_AREA_AURA)) sLog->outError(LOG_FILTER_TSCR, "Spell `%u` of script `%s` does not have area aura effect - handler bound to hook `DoCheckAreaTarget` of AuraScript won't be executed", entry->Id, m_scriptName->c_str()); for (std::list<AuraDispelHandler>::iterator itr = OnDispel.begin(); itr != OnDispel.end(); ++itr) @@ -679,6 +679,30 @@ bool AuraScript::_Validate(SpellInfo const* entry) if (!(*itr).GetAffectedEffectsMask(entry)) sLog->outError(LOG_FILTER_TSCR, "Spell `%u` Effect `%s` of script `%s` did not match dbc effect data - handler bound to hook `OnEffectSplit` of AuraScript won't be executed", entry->Id, (*itr).ToString().c_str(), m_scriptName->c_str()); + for (std::list<CheckProcHandler>::iterator itr = DoCheckProc.begin(); itr != DoCheckProc.end(); ++itr) + if (!entry->HasEffect(SPELL_EFFECT_APPLY_AURA) && !entry->HasAreaAuraEffect()) + sLog->outError(LOG_FILTER_TSCR, "Spell `%u` of script `%s` does not have apply aura effect - handler bound to hook `DoCheckProc` of AuraScript won't be executed", entry->Id, m_scriptName->c_str()); + + for (std::list<AuraProcHandler>::iterator itr = DoPrepareProc.begin(); itr != DoPrepareProc.end(); ++itr) + if (!entry->HasEffect(SPELL_EFFECT_APPLY_AURA) && !entry->HasAreaAuraEffect()) + sLog->outError(LOG_FILTER_TSCR, "Spell `%u` of script `%s` does not have apply aura effect - handler bound to hook `DoPrepareProc` of AuraScript won't be executed", entry->Id, m_scriptName->c_str()); + + for (std::list<AuraProcHandler>::iterator itr = OnProc.begin(); itr != OnProc.end(); ++itr) + if (!entry->HasEffect(SPELL_EFFECT_APPLY_AURA) && !entry->HasAreaAuraEffect()) + sLog->outError(LOG_FILTER_TSCR, "Spell `%u` of script `%s` does not have apply aura effect - handler bound to hook `OnProc` of AuraScript won't be executed", entry->Id, m_scriptName->c_str()); + + for (std::list<AuraProcHandler>::iterator itr = AfterProc.begin(); itr != AfterProc.end(); ++itr) + if (!entry->HasEffect(SPELL_EFFECT_APPLY_AURA) && !entry->HasAreaAuraEffect()) + sLog->outError(LOG_FILTER_TSCR, "Spell `%u` of script `%s` does not have apply aura effect - handler bound to hook `AfterProc` of AuraScript won't be executed", entry->Id, m_scriptName->c_str()); + + for (std::list<EffectProcHandler>::iterator itr = OnEffectProc.begin(); itr != OnEffectProc.end(); ++itr) + if (!(*itr).GetAffectedEffectsMask(entry)) + sLog->outError(LOG_FILTER_TSCR, "Spell `%u` Effect `%s` of script `%s` did not match dbc effect data - handler bound to hook `OnEffectProc` of AuraScript won't be executed", entry->Id, (*itr).ToString().c_str(), m_scriptName->c_str()); + + for (std::list<EffectProcHandler>::iterator itr = AfterEffectProc.begin(); itr != AfterEffectProc.end(); ++itr) + if (!(*itr).GetAffectedEffectsMask(entry)) + sLog->outError(LOG_FILTER_TSCR, "Spell `%u` Effect `%s` of script `%s` did not match dbc effect data - handler bound to hook `AfterEffectProc` of AuraScript won't be executed", entry->Id, (*itr).ToString().c_str(), m_scriptName->c_str()); + return _SpellScript::_Validate(entry); } @@ -818,6 +842,37 @@ void AuraScript::EffectSplitHandler::Call(AuraScript* auraScript, AuraEffect* au (auraScript->*pEffectHandlerScript)(aurEff, dmgInfo, splitAmount); } +AuraScript::CheckProcHandler::CheckProcHandler(AuraCheckProcFnType handlerScript) +{ + _HandlerScript = handlerScript; +} + +bool AuraScript::CheckProcHandler::Call(AuraScript* auraScript, ProcEventInfo& eventInfo) +{ + return (auraScript->*_HandlerScript)(eventInfo); +} + +AuraScript::AuraProcHandler::AuraProcHandler(AuraProcFnType handlerScript) +{ + _HandlerScript = handlerScript; +} + +void AuraScript::AuraProcHandler::Call(AuraScript* auraScript, ProcEventInfo& eventInfo) +{ + (auraScript->*_HandlerScript)(eventInfo); +} + +AuraScript::EffectProcHandler::EffectProcHandler(AuraEffectProcFnType effectHandlerScript, uint8 effIndex, uint16 effName) + : AuraScript::EffectBase(effIndex, effName) +{ + _EffectHandlerScript = effectHandlerScript; +} + +void AuraScript::EffectProcHandler::Call(AuraScript* auraScript, AuraEffect const* aurEff, ProcEventInfo& eventInfo) +{ + (auraScript->*_EffectHandlerScript)(aurEff, eventInfo); +} + bool AuraScript::_Load(Aura* aura) { m_aura = aura; @@ -853,6 +908,8 @@ bool AuraScript::_IsDefaultActionPrevented() case AURA_SCRIPT_HOOK_EFFECT_PERIODIC: case AURA_SCRIPT_HOOK_EFFECT_ABSORB: case AURA_SCRIPT_HOOK_EFFECT_SPLIT: + case AURA_SCRIPT_HOOK_PREPARE_PROC: + case AURA_SCRIPT_HOOK_EFFECT_PROC: return m_defaultActionPrevented; default: ASSERT(false && "AuraScript::_IsDefaultActionPrevented is called in a wrong place"); @@ -869,6 +926,8 @@ void AuraScript::PreventDefaultAction() case AURA_SCRIPT_HOOK_EFFECT_PERIODIC: case AURA_SCRIPT_HOOK_EFFECT_ABSORB: case AURA_SCRIPT_HOOK_EFFECT_SPLIT: + case AURA_SCRIPT_HOOK_PREPARE_PROC: + case AURA_SCRIPT_HOOK_EFFECT_PROC: m_defaultActionPrevented = true; break; default: @@ -1051,6 +1110,12 @@ Unit* AuraScript::GetTarget() const case AURA_SCRIPT_HOOK_EFFECT_MANASHIELD: case AURA_SCRIPT_HOOK_EFFECT_AFTER_MANASHIELD: case AURA_SCRIPT_HOOK_EFFECT_SPLIT: + case AURA_SCRIPT_HOOK_CHECK_PROC: + case AURA_SCRIPT_HOOK_PREPARE_PROC: + case AURA_SCRIPT_HOOK_PROC: + case AURA_SCRIPT_HOOK_AFTER_PROC: + case AURA_SCRIPT_HOOK_EFFECT_PROC: + case AURA_SCRIPT_HOOK_EFFECT_AFTER_PROC: return m_auraApplication->GetTarget(); default: sLog->outError(LOG_FILTER_TSCR, "Script: `%s` Spell: `%u` AuraScript::GetTarget called in a hook in which the call won't have effect!", m_scriptName->c_str(), m_scriptSpellId); diff --git a/src/server/game/Spells/SpellScript.h b/src/server/game/Spells/SpellScript.h index 5791c701c07..6f1df2560dc 100644 --- a/src/server/game/Spells/SpellScript.h +++ b/src/server/game/Spells/SpellScript.h @@ -428,14 +428,22 @@ enum AuraScriptHookType AURA_SCRIPT_HOOK_EFFECT_SPLIT, AURA_SCRIPT_HOOK_CHECK_AREA_TARGET, AURA_SCRIPT_HOOK_DISPEL, - AURA_SCRIPT_HOOK_AFTER_DISPEL + AURA_SCRIPT_HOOK_AFTER_DISPEL, + // Spell Proc Hooks + AURA_SCRIPT_HOOK_CHECK_PROC, + AURA_SCRIPT_HOOK_PREPARE_PROC, + AURA_SCRIPT_HOOK_PROC, + AURA_SCRIPT_HOOK_EFFECT_PROC, + AURA_SCRIPT_HOOK_EFFECT_AFTER_PROC, + AURA_SCRIPT_HOOK_AFTER_PROC, /*AURA_SCRIPT_HOOK_APPLY, AURA_SCRIPT_HOOK_REMOVE, */ }; +/* #define HOOK_AURA_EFFECT_START HOOK_AURA_EFFECT_APPLY #define HOOK_AURA_EFFECT_END HOOK_AURA_EFFECT_CALC_SPELLMOD + 1 #define HOOK_AURA_EFFECT_COUNT HOOK_AURA_EFFECT_END - HOOK_AURA_EFFECT_START - +*/ class AuraScript : public _SpellScript { // internal use classes & functions @@ -453,6 +461,9 @@ class AuraScript : public _SpellScript typedef void(CLASSNAME::*AuraEffectCalcSpellModFnType)(AuraEffect const*, SpellModifier* &); \ typedef void(CLASSNAME::*AuraEffectAbsorbFnType)(AuraEffect*, DamageInfo &, uint32 &); \ typedef void(CLASSNAME::*AuraEffectSplitFnType)(AuraEffect*, DamageInfo &, uint32 &); \ + typedef bool(CLASSNAME::*AuraCheckProcFnType)(ProcEventInfo&); \ + typedef void(CLASSNAME::*AuraProcFnType)(ProcEventInfo&); \ + typedef void(CLASSNAME::*AuraEffectProcFnType)(AuraEffect const*, ProcEventInfo&); \ AURASCRIPT_FUNCTION_TYPE_DEFINES(AuraScript) @@ -552,6 +563,30 @@ class AuraScript : public _SpellScript private: AuraEffectSplitFnType pEffectHandlerScript; }; + class CheckProcHandler + { + public: + CheckProcHandler(AuraCheckProcFnType handlerScript); + bool Call(AuraScript* auraScript, ProcEventInfo& eventInfo); + private: + AuraCheckProcFnType _HandlerScript; + }; + class AuraProcHandler + { + public: + AuraProcHandler(AuraProcFnType handlerScript); + void Call(AuraScript* auraScript, ProcEventInfo& eventInfo); + private: + AuraProcFnType _HandlerScript; + }; + class EffectProcHandler : public EffectBase + { + public: + EffectProcHandler(AuraEffectProcFnType effectHandlerScript, uint8 effIndex, uint16 effName); + void Call(AuraScript* auraScript, AuraEffect const* aurEff, ProcEventInfo& eventInfo); + private: + AuraEffectProcFnType _EffectHandlerScript; + }; #define AURASCRIPT_FUNCTION_CAST_DEFINES(CLASSNAME) \ class CheckAreaTargetFunction : public AuraScript::CheckAreaTargetHandler { public: CheckAreaTargetFunction(AuraCheckAreaTargetFnType _pHandlerScript) : AuraScript::CheckAreaTargetHandler((AuraScript::AuraCheckAreaTargetFnType)_pHandlerScript) {} }; \ @@ -565,6 +600,9 @@ class AuraScript : public _SpellScript class EffectAbsorbFunction : public AuraScript::EffectAbsorbHandler { public: EffectAbsorbFunction(AuraEffectAbsorbFnType _pEffectHandlerScript, uint8 _effIndex) : AuraScript::EffectAbsorbHandler((AuraScript::AuraEffectAbsorbFnType)_pEffectHandlerScript, _effIndex) {} }; \ class EffectManaShieldFunction : public AuraScript::EffectManaShieldHandler { public: EffectManaShieldFunction(AuraEffectAbsorbFnType _pEffectHandlerScript, uint8 _effIndex) : AuraScript::EffectManaShieldHandler((AuraScript::AuraEffectAbsorbFnType)_pEffectHandlerScript, _effIndex) {} }; \ class EffectSplitFunction : public AuraScript::EffectSplitHandler { public: EffectSplitFunction(AuraEffectSplitFnType _pEffectHandlerScript, uint8 _effIndex) : AuraScript::EffectSplitHandler((AuraScript::AuraEffectSplitFnType)_pEffectHandlerScript, _effIndex) {} }; \ + class CheckProcHandlerFunction : public AuraScript::CheckProcHandler { public: CheckProcHandlerFunction(AuraCheckProcFnType handlerScript) : AuraScript::CheckProcHandler((AuraScript::AuraCheckProcFnType)handlerScript) {} }; \ + class AuraProcHandlerFunction : public AuraScript::AuraProcHandler { public: AuraProcHandlerFunction(AuraProcFnType handlerScript) : AuraScript::AuraProcHandler((AuraScript::AuraProcFnType)handlerScript) {} }; \ + class EffectProcHandlerFunction : public AuraScript::EffectProcHandler { public: EffectProcHandlerFunction(AuraEffectProcFnType effectHandlerScript, uint8 effIndex, uint16 effName) : AuraScript::EffectProcHandler((AuraScript::AuraEffectProcFnType)effectHandlerScript, effIndex, effName) {} }; \ #define PrepareAuraScript(CLASSNAME) AURASCRIPT_FUNCTION_TYPE_DEFINES(CLASSNAME) AURASCRIPT_FUNCTION_CAST_DEFINES(CLASSNAME) @@ -695,6 +733,36 @@ class AuraScript : public _SpellScript HookList<EffectSplitHandler> OnEffectSplit; #define AuraEffectSplitFn(F, I) EffectSplitFunction(&F, I) + // executed when aura checks if it can proc + // example: DoCheckProc += AuraCheckProcFn(class::function); + // where function is: bool function (ProcEventInfo& eventInfo); + HookList<CheckProcHandler> DoCheckProc; + #define AuraCheckProcFn(F) CheckProcHandlerFunction(&F) + + // executed before aura procs (possibility to prevent charge drop/cooldown) + // example: DoPrepareProc += AuraProcFn(class::function); + // where function is: void function (ProcEventInfo& eventInfo); + HookList<AuraProcHandler> DoPrepareProc; + // executed when aura procs + // example: OnProc += AuraProcFn(class::function); + // where function is: void function (ProcEventInfo& eventInfo); + HookList<AuraProcHandler> OnProc; + // executed after aura proced + // example: AfterProc += AuraProcFn(class::function); + // where function is: void function (ProcEventInfo& eventInfo); + HookList<AuraProcHandler> AfterProc; + #define AuraProcFn(F) AuraProcHandlerFunction(&F) + + // executed when aura effect procs + // example: OnEffectProc += AuraEffectProcFn(class::function, EffectIndexSpecifier, EffectAuraNameSpecifier); + // where function is: void function (AuraEffect const* aurEff, ProcEventInfo& procInfo); + HookList<EffectProcHandler> OnEffectProc; + // executed after aura effect proced + // example: AfterEffectProc += AuraEffectProcFn(class::function, EffectIndexSpecifier, EffectAuraNameSpecifier); + // where function is: void function (AuraEffect const* aurEff, ProcEventInfo& procInfo); + HookList<EffectProcHandler> AfterEffectProc; + #define AuraEffectProcFn(F, I, N) EffectProcHandlerFunction(&F, I, N) + // AuraScript interface - hook/effect execution manipulators // prevents default action of a hook from being executed (works only while called in a hook which default action can be prevented) diff --git a/src/server/game/Tickets/TicketMgr.cpp b/src/server/game/Tickets/TicketMgr.cpp index 1b7ecd34051..fe10b81b09d 100644 --- a/src/server/game/Tickets/TicketMgr.cpp +++ b/src/server/game/Tickets/TicketMgr.cpp @@ -182,6 +182,8 @@ std::string GmTicket::FormatMessageString(ChatHandler& handler, bool detailed) c ss << handler.PGetParseString(LANG_COMMAND_TICKETLISTMESSAGE, _message.c_str()); if (!_comment.empty()) ss << handler.PGetParseString(LANG_COMMAND_TICKETLISTCOMMENT, _comment.c_str()); + if (!_response.empty()) + ss << handler.PGetParseString(LANG_COMMAND_TICKETLISTRESPONSE, _response.c_str()); } return ss.str(); } diff --git a/src/server/game/Tickets/TicketMgr.h b/src/server/game/Tickets/TicketMgr.h index 22315ab1926..0fe45f81360 100644 --- a/src/server/game/Tickets/TicketMgr.h +++ b/src/server/game/Tickets/TicketMgr.h @@ -162,7 +162,7 @@ private: bool _completed; GMTicketEscalationStatus _escalatedStatus; bool _viewed; - bool _needResponse; // TODO: find out the use of this, and then store it in DB + bool _needResponse; /// @todo find out the use of this, and then store it in DB bool _haveTicket; std::string _response; std::string _chatLog; // No need to store in db, will be refreshed every session client side diff --git a/src/server/game/Tools/PlayerDump.cpp b/src/server/game/Tools/PlayerDump.cpp index 558fe8e2910..de54c358dae 100644 --- a/src/server/game/Tools/PlayerDump.cpp +++ b/src/server/game/Tools/PlayerDump.cpp @@ -351,8 +351,8 @@ bool PlayerDumpWriter::GetDump(uint32 guid, std::string &dump) if (!DumpTable(dump, guid, dumpTables[i].name, dumpTables[i].name, dumpTables[i].type)) return false; - // TODO: Add instance/group.. - // TODO: Add a dump level option to skip some non-important tables + /// @todo Add instance/group.. + /// @todo Add a dump level option to skip some non-important tables return true; } diff --git a/src/server/game/Warden/Warden.cpp b/src/server/game/Warden/Warden.cpp index a99688c8844..af695c482cf 100644 --- a/src/server/game/Warden/Warden.cpp +++ b/src/server/game/Warden/Warden.cpp @@ -219,7 +219,7 @@ std::string Warden::Penalty(WardenCheck* check /*= NULL*/) void WorldSession::HandleWardenDataOpcode(WorldPacket& recvData) { - _warden->DecryptData(const_cast<uint8*>(recvData.contents()), recvData.size()); + _warden->DecryptData(recvData.contents(), recvData.size()); uint8 opcode; recvData >> opcode; sLog->outDebug(LOG_FILTER_WARDEN, "Got packet, opcode %02X, size %u", opcode, uint32(recvData.size())); diff --git a/src/server/game/Warden/Warden.h b/src/server/game/Warden/Warden.h index 7a61f3d5723..b9470b0c8a7 100644 --- a/src/server/game/Warden/Warden.h +++ b/src/server/game/Warden/Warden.h @@ -40,7 +40,7 @@ enum WardenOpcodes WARDEN_SMSG_MODULE_CACHE = 1, WARDEN_SMSG_CHEAT_CHECKS_REQUEST = 2, WARDEN_SMSG_MODULE_INITIALIZE = 3, - WARDEN_SMSG_MEM_CHECKS_REQUEST = 4, // byte len; while(!EOF) { byte unk(1); byte index(++); string module(can be 0); int offset; byte len; byte[] bytes_to_compare[len]; } + WARDEN_SMSG_MEM_CHECKS_REQUEST = 4, // byte len; while (!EOF) { byte unk(1); byte index(++); string module(can be 0); int offset; byte len; byte[] bytes_to_compare[len]; } WARDEN_SMSG_HASH_REQUEST = 5 }; @@ -60,7 +60,7 @@ enum WardenCheckType #if defined(__GNUC__) #pragma pack(1) #else -#pragma pack(push,1) +#pragma pack(push, 1) #endif struct WardenModuleUse diff --git a/src/server/game/Warden/WardenCheckMgr.cpp b/src/server/game/Warden/WardenCheckMgr.cpp index b96cb1156c2..ec271192450 100644 --- a/src/server/game/Warden/WardenCheckMgr.cpp +++ b/src/server/game/Warden/WardenCheckMgr.cpp @@ -44,7 +44,6 @@ void WardenCheckMgr::LoadWardenChecks() if (!sWorld->getBoolConfig(CONFIG_WARDEN_ENABLED)) { sLog->outInfo(LOG_FILTER_WARDEN, ">> Warden disabled, loading checks skipped."); - return; } @@ -52,8 +51,7 @@ void WardenCheckMgr::LoadWardenChecks() if (!result) { - sLog->outInfo(LOG_FILTER_WARDEN, ">> Loaded 0 Warden checks. DB table `warden_checks` is empty!"); - + sLog->outInfo(LOG_FILTER_SERVER_LOADING, ">> Loaded 0 Warden checks. DB table `warden_checks` is empty!"); return; } @@ -145,8 +143,7 @@ void WardenCheckMgr::LoadWardenChecks() } while (result->NextRow()); - sLog->outInfo(LOG_FILTER_WARDEN, ">> Loaded %u warden checks.", count); - + sLog->outInfo(LOG_FILTER_SERVER_LOADING, ">> Loaded %u warden checks.", count); } void WardenCheckMgr::LoadWardenOverrides() @@ -155,7 +152,6 @@ void WardenCheckMgr::LoadWardenOverrides() if (!sWorld->getBoolConfig(CONFIG_WARDEN_ENABLED)) { sLog->outInfo(LOG_FILTER_WARDEN, ">> Warden disabled, loading check overrides skipped."); - return; } @@ -164,8 +160,7 @@ void WardenCheckMgr::LoadWardenOverrides() if (!result) { - sLog->outInfo(LOG_FILTER_WARDEN, ">> Loaded 0 Warden action overrides. DB table `warden_action` is empty!"); - + sLog->outInfo(LOG_FILTER_SERVER_LOADING, ">> Loaded 0 Warden action overrides. DB table `warden_action` is empty!"); return; } @@ -194,8 +189,7 @@ void WardenCheckMgr::LoadWardenOverrides() } while (result->NextRow()); - sLog->outInfo(LOG_FILTER_WARDEN, ">> Loaded %u warden action overrides.", count); - + sLog->outInfo(LOG_FILTER_SERVER_LOADING, ">> Loaded %u warden action overrides.", count); } WardenCheck* WardenCheckMgr::GetWardenDataById(uint16 Id) diff --git a/src/server/game/Warden/WardenMac.cpp b/src/server/game/Warden/WardenMac.cpp index d1df94d7f07..fa84cd216b6 100644 --- a/src/server/game/Warden/WardenMac.cpp +++ b/src/server/game/Warden/WardenMac.cpp @@ -38,7 +38,7 @@ WardenMac::~WardenMac() { } -void WardenMac::Init(WorldSession *pClient, BigNumber *K) +void WardenMac::Init(WorldSession* pClient, BigNumber* K) { _session = pClient; // Generate Warden Key @@ -206,7 +206,7 @@ void WardenMac::RequestData() buff.hexlike(); // Encrypt with warden RC4 key. - EncryptData(const_cast<uint8*>(buff.contents()), buff.size()); + EncryptData(buff.contents(), buff.size()); WorldPacket pkt(SMSG_WARDEN_DATA, buff.size()); pkt.append(buff); diff --git a/src/server/game/Warden/WardenWin.cpp b/src/server/game/Warden/WardenWin.cpp index bff12280d89..21bf3527a9a 100644 --- a/src/server/game/Warden/WardenWin.cpp +++ b/src/server/game/Warden/WardenWin.cpp @@ -42,7 +42,7 @@ WardenWin::~WardenWin() { } -void WardenWin::Init(WorldSession* session, BigNumber *k) +void WardenWin::Init(WorldSession* session, BigNumber* k) { _session = session; // Generate Warden Key @@ -310,7 +310,7 @@ void WardenWin::RequestData() buff.hexlike(); // Encrypt with warden RC4 key - EncryptData(const_cast<uint8*>(buff.contents()), buff.size()); + EncryptData(buff.contents(), buff.size()); WorldPacket pkt(SMSG_WARDEN_DATA, buff.size()); pkt.append(buff); @@ -349,7 +349,7 @@ void WardenWin::HandleData(ByteBuffer &buff) { uint8 result; buff >> result; - // TODO: test it. + /// @todo test it. if (result == 0x00) { sLog->outWarn(LOG_FILTER_WARDEN, "%s failed timing check. Action: %s", _session->GetPlayerInfo().c_str(), Penalty().c_str()); @@ -368,7 +368,7 @@ void WardenWin::HandleData(ByteBuffer &buff) sLog->outDebug(LOG_FILTER_WARDEN, "Ticks diff %u", ourTicks - newClientTicks); } - WardenCheckResult *rs; + WardenCheckResult* rs; WardenCheck *rd; uint8 type; uint16 checkFailed = 0; diff --git a/src/server/game/Warden/WardenWin.h b/src/server/game/Warden/WardenWin.h index 102a64c6895..1b1cc6746f4 100644 --- a/src/server/game/Warden/WardenWin.h +++ b/src/server/game/Warden/WardenWin.h @@ -28,7 +28,7 @@ #if defined(__GNUC__) #pragma pack(1) #else -#pragma pack(push,1) +#pragma pack(push, 1) #endif struct WardenInitModuleRequest diff --git a/src/server/game/Weather/Weather.cpp b/src/server/game/Weather/Weather.cpp index cd148712b55..64ee188a0d2 100644 --- a/src/server/game/Weather/Weather.cpp +++ b/src/server/game/Weather/Weather.cpp @@ -221,6 +221,9 @@ bool Weather::UpdateWeather() char const* wthstr; switch (state) { + case WEATHER_STATE_FOG: + wthstr = "fog"; + break; case WEATHER_STATE_LIGHT_RAIN: wthstr = "light rain"; break; diff --git a/src/server/game/Weather/Weather.h b/src/server/game/Weather/Weather.h index 1fcd822d580..2645d3f2067 100644 --- a/src/server/game/Weather/Weather.h +++ b/src/server/game/Weather/Weather.h @@ -46,6 +46,7 @@ struct WeatherData enum WeatherState { WEATHER_STATE_FINE = 0, + WEATHER_STATE_FOG = 1, WEATHER_STATE_LIGHT_RAIN = 3, WEATHER_STATE_MEDIUM_RAIN = 4, WEATHER_STATE_HEAVY_RAIN = 5, diff --git a/src/server/game/Weather/WeatherMgr.cpp b/src/server/game/Weather/WeatherMgr.cpp index 802cdb8209f..769e40b4dff 100644 --- a/src/server/game/Weather/WeatherMgr.cpp +++ b/src/server/game/Weather/WeatherMgr.cpp @@ -96,8 +96,7 @@ void LoadWeatherData() if (!result) { - sLog->outError(LOG_FILTER_SQL, ">> Loaded 0 weather definitions. DB table `game_weather` is empty."); - + sLog->outError(LOG_FILTER_SERVER_LOADING, ">> Loaded 0 weather definitions. DB table `game_weather` is empty."); return; } @@ -141,7 +140,6 @@ void LoadWeatherData() while (result->NextRow()); sLog->outInfo(LOG_FILTER_SERVER_LOADING, ">> Loaded %u weather definitions in %u ms", count, GetMSTimeDiffToNow(oldMSTime)); - } void SendFineWeatherUpdateToPlayer(Player* player) diff --git a/src/server/game/World/World.cpp b/src/server/game/World/World.cpp index d232920418d..ec11a29b5c1 100644 --- a/src/server/game/World/World.cpp +++ b/src/server/game/World/World.cpp @@ -21,6 +21,7 @@ */ #include "Common.h" +#include "Memory.h" #include "DatabaseEnv.h" #include "Config.h" #include "SystemConfig.h" @@ -54,6 +55,7 @@ #include "TemporarySummon.h" #include "WaypointMovementGenerator.h" #include "VMapFactory.h" +#include "MMapFactory.h" #include "GameEventMgr.h" #include "PoolMgr.h" #include "GridNotifiersImpl.h" @@ -135,8 +137,9 @@ World::~World() delete command; VMAP::VMapFactory::clear(); + MMAP::MMapFactory::clear(); - //TODO free addSessQueue + /// @todo free addSessQueue } /// Find a player in a specified zone @@ -222,7 +225,7 @@ void World::AddSession(WorldSession* s) void World::AddSession_(WorldSession* s) { - ASSERT (s); + ASSERT(s); //NOTE - Still there is race condition in WorldSession* being used in the Sockets @@ -257,16 +260,16 @@ void World::AddSession_(WorldSession* s) uint32 Sessions = GetActiveAndQueuedSessionCount(); uint32 pLimit = GetPlayerAmountLimit(); - uint32 QueueSize = GetQueuedSessionCount(); //number of players in the queue + uint32 QueueSize = GetQueuedSessionCount(); //number of players in the queue //so we don't count the user trying to //login as a session and queue the socket that we are using if (decrease_session) --Sessions; - if (pLimit > 0 && Sessions >= pLimit && AccountMgr::IsPlayerAccount(s->GetSecurity()) && !HasRecentlyDisconnected(s)) + if (pLimit > 0 && Sessions >= pLimit && !s->HasPermission(RBAC_PERM_SKIP_QUEUE) && !HasRecentlyDisconnected(s)) { - AddQueuedPlayer (s); + AddQueuedPlayer(s); UpdateMaxSessionCounters(); sLog->outInfo(LOG_FILTER_GENERAL, "PlayerQueue: Account id %u is in Queue Position (%u).", s->GetAccountId(), ++QueueSize); return; @@ -494,8 +497,6 @@ void World::LoadConfigSettings(bool reload) rate_values[RATE_AUCTION_DEPOSIT] = ConfigMgr::GetFloatDefault("Rate.Auction.Deposit", 1.0f); rate_values[RATE_AUCTION_CUT] = ConfigMgr::GetFloatDefault("Rate.Auction.Cut", 1.0f); rate_values[RATE_HONOR] = ConfigMgr::GetFloatDefault("Rate.Honor", 1.0f); - rate_values[RATE_MINING_AMOUNT] = ConfigMgr::GetFloatDefault("Rate.Mining.Amount", 1.0f); - rate_values[RATE_MINING_NEXT] = ConfigMgr::GetFloatDefault("Rate.Mining.Next", 1.0f); rate_values[RATE_INSTANCE_RESET_TIME] = ConfigMgr::GetFloatDefault("Rate.InstanceResetTime", 1.0f); rate_values[RATE_TALENT] = ConfigMgr::GetFloatDefault("Rate.Talent", 1.0f); if (rate_values[RATE_TALENT] < 0.0f) @@ -582,7 +583,6 @@ void World::LoadConfigSettings(bool reload) m_int_configs[CONFIG_TICKET_LEVEL_REQ] = ConfigMgr::GetIntDefault("LevelReq.Ticket", 1); m_int_configs[CONFIG_AUCTION_LEVEL_REQ] = ConfigMgr::GetIntDefault("LevelReq.Auction", 1); m_int_configs[CONFIG_MAIL_LEVEL_REQ] = ConfigMgr::GetIntDefault("LevelReq.Mail", 1); - m_bool_configs[CONFIG_ALLOW_PLAYER_COMMANDS] = ConfigMgr::GetBoolDefault("AllowPlayerCommands", 1); m_bool_configs[CONFIG_PRESERVE_CUSTOM_CHANNELS] = ConfigMgr::GetBoolDefault("PreserveCustomChannels", false); m_int_configs[CONFIG_PRESERVE_CUSTOM_CHANNEL_DURATION] = ConfigMgr::GetIntDefault("PreserveCustomChannelDuration", 14); m_bool_configs[CONFIG_GRID_UNLOAD] = ConfigMgr::GetBoolDefault("GridUnload", true); @@ -632,7 +632,7 @@ void World::LoadConfigSettings(bool reload) m_float_configs[CONFIG_GROUP_XP_DISTANCE] = ConfigMgr::GetFloatDefault("MaxGroupXPDistance", 74.0f); m_float_configs[CONFIG_MAX_RECRUIT_A_FRIEND_DISTANCE] = ConfigMgr::GetFloatDefault("MaxRecruitAFriendBonusDistance", 100.0f); - /// \todo Add MonsterSight and GuarderSight (with meaning) in worldserver.conf or put them as define + /// @todo Add MonsterSight and GuarderSight (with meaning) in worldserver.conf or put them as define m_float_configs[CONFIG_SIGHT_MONSTER] = ConfigMgr::GetFloatDefault("MonsterSight", 50); m_float_configs[CONFIG_SIGHT_GUARDER] = ConfigMgr::GetFloatDefault("GuarderSight", 50); @@ -654,16 +654,11 @@ void World::LoadConfigSettings(bool reload) else m_int_configs[CONFIG_REALM_ZONE] = ConfigMgr::GetIntDefault("RealmZone", REALM_ZONE_DEVELOPMENT); - m_bool_configs[CONFIG_ALLOW_TWO_SIDE_ACCOUNTS] = ConfigMgr::GetBoolDefault("AllowTwoSide.Accounts", true); m_bool_configs[CONFIG_ALLOW_TWO_SIDE_INTERACTION_CALENDAR]= ConfigMgr::GetBoolDefault("AllowTwoSide.Interaction.Calendar", false); - m_bool_configs[CONFIG_ALLOW_TWO_SIDE_INTERACTION_CHAT] = ConfigMgr::GetBoolDefault("AllowTwoSide.Interaction.Chat", false); m_bool_configs[CONFIG_ALLOW_TWO_SIDE_INTERACTION_CHANNEL] = ConfigMgr::GetBoolDefault("AllowTwoSide.Interaction.Channel", false); m_bool_configs[CONFIG_ALLOW_TWO_SIDE_INTERACTION_GROUP] = ConfigMgr::GetBoolDefault("AllowTwoSide.Interaction.Group", false); m_bool_configs[CONFIG_ALLOW_TWO_SIDE_INTERACTION_GUILD] = ConfigMgr::GetBoolDefault("AllowTwoSide.Interaction.Guild", false); m_bool_configs[CONFIG_ALLOW_TWO_SIDE_INTERACTION_AUCTION] = ConfigMgr::GetBoolDefault("AllowTwoSide.Interaction.Auction", false); - m_bool_configs[CONFIG_ALLOW_TWO_SIDE_INTERACTION_MAIL] = ConfigMgr::GetBoolDefault("AllowTwoSide.Interaction.Mail", false); - m_bool_configs[CONFIG_ALLOW_TWO_SIDE_WHO_LIST] = ConfigMgr::GetBoolDefault("AllowTwoSide.WhoList", false); - m_bool_configs[CONFIG_ALLOW_TWO_SIDE_ADD_FRIEND] = ConfigMgr::GetBoolDefault("AllowTwoSide.AddFriend", false); m_bool_configs[CONFIG_ALLOW_TWO_SIDE_TRADE] = ConfigMgr::GetBoolDefault("AllowTwoSide.trade", false); m_int_configs[CONFIG_STRICT_PLAYER_NAMES] = ConfigMgr::GetIntDefault ("StrictPlayerNames", 0); m_int_configs[CONFIG_STRICT_CHARTER_NAMES] = ConfigMgr::GetIntDefault ("StrictCharterNames", 0); @@ -772,7 +767,7 @@ void World::LoadConfigSettings(bool reload) if (int32(m_int_configs[CONFIG_START_PLAYER_MONEY]) < 0) { sLog->outError(LOG_FILTER_SERVER_LOADING, "StartPlayerMoney (%i) must be in range 0..%u. Set to %u.", m_int_configs[CONFIG_START_PLAYER_MONEY], MAX_MONEY_AMOUNT, 0); - m_int_configs[CONFIG_START_PLAYER_MONEY] = 0; + m_int_configs[CONFIG_START_PLAYER_MONEY] = 0; } else if (m_int_configs[CONFIG_START_PLAYER_MONEY] > MAX_MONEY_AMOUNT) { @@ -857,7 +852,6 @@ void World::LoadConfigSettings(bool reload) m_int_configs[CONFIG_GM_LEVEL_IN_GM_LIST] = ConfigMgr::GetIntDefault("GM.InGMList.Level", SEC_ADMINISTRATOR); m_int_configs[CONFIG_GM_LEVEL_IN_WHO_LIST] = ConfigMgr::GetIntDefault("GM.InWhoList.Level", SEC_ADMINISTRATOR); - m_bool_configs[CONFIG_GM_LOG_TRADE] = ConfigMgr::GetBoolDefault("GM.LogTrade", false); m_int_configs[CONFIG_START_GM_LEVEL] = ConfigMgr::GetIntDefault("GM.StartLevel", 1); if (m_int_configs[CONFIG_START_GM_LEVEL] < m_int_configs[CONFIG_START_PLAYER_LEVEL]) { @@ -871,7 +865,6 @@ void World::LoadConfigSettings(bool reload) m_int_configs[CONFIG_START_GM_LEVEL] = MAX_LEVEL; } m_bool_configs[CONFIG_ALLOW_GM_GROUP] = ConfigMgr::GetBoolDefault("GM.AllowInvite", false); - m_bool_configs[CONFIG_ALLOW_GM_FRIEND] = ConfigMgr::GetBoolDefault("GM.AllowFriend", false); m_bool_configs[CONFIG_GM_LOWER_SECURITY] = ConfigMgr::GetBoolDefault("GM.LowerSecurity", false); m_float_configs[CONFIG_CHANCE_OF_GM_SURVEY] = ConfigMgr::GetFloatDefault("GM.TicketSystem.ChanceOfGMSurvey", 50.0f); @@ -953,7 +946,7 @@ void World::LoadConfigSettings(bool reload) m_int_configs[CONFIG_CHATFLOOD_MESSAGE_DELAY] = ConfigMgr::GetIntDefault("ChatFlood.MessageDelay", 1); m_int_configs[CONFIG_CHATFLOOD_MUTE_TIME] = ConfigMgr::GetIntDefault("ChatFlood.MuteTime", 10); - m_int_configs[CONFIG_EVENT_ANNOUNCE] = ConfigMgr::GetIntDefault("Event.Announce", 0); + m_bool_configs[CONFIG_EVENT_ANNOUNCE] = ConfigMgr::GetIntDefault("Event.Announce", false); m_float_configs[CONFIG_CREATURE_FAMILY_FLEE_ASSISTANCE_RADIUS] = ConfigMgr::GetFloatDefault("CreatureFamilyFleeAssistanceRadius", 30.0f); m_float_configs[CONFIG_CREATURE_FAMILY_ASSISTANCE_RADIUS] = ConfigMgr::GetFloatDefault("CreatureFamilyAssistanceRadius", 10.0f); @@ -990,8 +983,6 @@ void World::LoadConfigSettings(bool reload) m_bool_configs[CONFIG_DETECT_POS_COLLISION] = ConfigMgr::GetBoolDefault("DetectPosCollision", true); m_bool_configs[CONFIG_RESTRICTED_LFG_CHANNEL] = ConfigMgr::GetBoolDefault("Channel.RestrictedLfg", true); - m_bool_configs[CONFIG_SILENTLY_GM_JOIN_TO_CHANNEL] = ConfigMgr::GetBoolDefault("Channel.SilentlyGMJoin", false); - m_bool_configs[CONFIG_TALENTS_INSPECTING] = ConfigMgr::GetBoolDefault("TalentsInspecting", true); m_bool_configs[CONFIG_CHAT_FAKE_MESSAGE_PREVENTING] = ConfigMgr::GetBoolDefault("ChatFakeMessagePreventing", false); m_int_configs[CONFIG_CHAT_STRICT_LINK_CHECKING_SEVERITY] = ConfigMgr::GetIntDefault("ChatStrictLinkChecking.Severity", 0); @@ -1056,8 +1047,6 @@ void World::LoadConfigSettings(bool reload) sLog->outError(LOG_FILTER_SERVER_LOADING, "ClientCacheVersion can't be negative %d, ignored.", clientCacheId); } - m_int_configs[CONFIG_INSTANT_LOGOUT] = ConfigMgr::GetIntDefault("InstantLogout", SEC_MODERATOR); - m_int_configs[CONFIG_GUILD_EVENT_LOG_COUNT] = ConfigMgr::GetIntDefault("Guild.EventLogRecordsCount", GUILD_EVENTLOG_MAX_RECORDS); if (m_int_configs[CONFIG_GUILD_EVENT_LOG_COUNT] > GUILD_EVENTLOG_MAX_RECORDS) m_int_configs[CONFIG_GUILD_EVENT_LOG_COUNT] = GUILD_EVENTLOG_MAX_RECORDS; @@ -1118,6 +1107,15 @@ void World::LoadConfigSettings(bool reload) if (dataPath.at(dataPath.length()-1) != '/' && dataPath.at(dataPath.length()-1) != '\\') dataPath.push_back('/'); +#if PLATFORM == PLATFORM_UNIX || PLATFORM == PLATFORM_APPLE + if (dataPath[0] == '~') + { + const char* home = getenv("HOME"); + if (home) + dataPath.replace(0, 1, home); + } +#endif + if (reload) { if (dataPath != m_dataPath) @@ -1129,22 +1127,23 @@ void World::LoadConfigSettings(bool reload) sLog->outInfo(LOG_FILTER_SERVER_LOADING, "Using DataDir %s", m_dataPath.c_str()); } + m_bool_configs[CONFIG_ENABLE_MMAPS] = ConfigMgr::GetBoolDefault("mmap.enablePathFinding", false); + sLog->outInfo(LOG_FILTER_SERVER_LOADING, "WORLD: MMap data directory is: %smmaps", m_dataPath.c_str()); + m_bool_configs[CONFIG_VMAP_INDOOR_CHECK] = ConfigMgr::GetBoolDefault("vmap.enableIndoorCheck", 0); bool enableIndoor = ConfigMgr::GetBoolDefault("vmap.enableIndoorCheck", true); bool enableLOS = ConfigMgr::GetBoolDefault("vmap.enableLOS", true); bool enableHeight = ConfigMgr::GetBoolDefault("vmap.enableHeight", true); - bool enablePetLOS = ConfigMgr::GetBoolDefault("vmap.petLOS", true); if (!enableHeight) sLog->outError(LOG_FILTER_SERVER_LOADING, "VMap height checking disabled! Creatures movements and other various things WILL be broken! Expect no support."); VMAP::VMapFactory::createOrGetVMapManager()->setEnableLineOfSightCalc(enableLOS); VMAP::VMapFactory::createOrGetVMapManager()->setEnableHeightCalc(enableHeight); - sLog->outInfo(LOG_FILTER_SERVER_LOADING, "VMap support included. LineOfSight: %i, getHeight: %i, indoorCheck: %i PetLOS: %i", enableLOS, enableHeight, enableIndoor, enablePetLOS); + sLog->outInfo(LOG_FILTER_SERVER_LOADING, "VMap support included. LineOfSight: %i, getHeight: %i, indoorCheck: %i", enableLOS, enableHeight, enableIndoor); sLog->outInfo(LOG_FILTER_SERVER_LOADING, "VMap data directory is: %svmaps", m_dataPath.c_str()); m_int_configs[CONFIG_MAX_WHO] = ConfigMgr::GetIntDefault("MaxWhoListReturns", 49); - m_bool_configs[CONFIG_PET_LOS] = ConfigMgr::GetBoolDefault("vmap.petLOS", true); m_bool_configs[CONFIG_START_ALL_SPELLS] = ConfigMgr::GetBoolDefault("PlayerStart.AllSpells", false); if (m_bool_configs[CONFIG_START_ALL_SPELLS]) sLog->outWarn(LOG_FILTER_SERVER_LOADING, "PlayerStart.AllSpells enabled - may not function as intended!"); @@ -1211,8 +1210,9 @@ void World::LoadConfigSettings(bool reload) // misc m_bool_configs[CONFIG_PDUMP_NO_PATHS] = ConfigMgr::GetBoolDefault("PlayerDump.DisallowPaths", true); m_bool_configs[CONFIG_PDUMP_NO_OVERWRITE] = ConfigMgr::GetBoolDefault("PlayerDump.DisallowOverwrite", true); + m_bool_configs[CONFIG_UI_QUESTLEVELS_IN_DIALOGS] = ConfigMgr::GetBoolDefault("UI.ShowQuestLevelsInDialogs", false); - // call ScriptMgr if we're reloading the configuration + // Wintergrasp battlefield m_bool_configs[CONFIG_WINTERGRASP_ENABLE] = ConfigMgr::GetBoolDefault("Wintergrasp.Enable", false); m_int_configs[CONFIG_WINTERGRASP_PLR_MAX] = ConfigMgr::GetIntDefault("Wintergrasp.PlayerMax", 100); m_int_configs[CONFIG_WINTERGRASP_PLR_MIN] = ConfigMgr::GetIntDefault("Wintergrasp.PlayerMin", 0); @@ -1221,6 +1221,7 @@ void World::LoadConfigSettings(bool reload) m_int_configs[CONFIG_WINTERGRASP_NOBATTLETIME] = ConfigMgr::GetIntDefault("Wintergrasp.NoBattleTimer", 150); m_int_configs[CONFIG_WINTERGRASP_RESTART_AFTER_CRASH] = ConfigMgr::GetIntDefault("Wintergrasp.CrashRestartTimer", 10); + // call ScriptMgr if we're reloading the configuration if (reload) sScriptMgr->OnConfigLoad(reload); } @@ -1236,6 +1237,9 @@ void World::SetInitialWorldSettings() ///- Initialize the random number generator srand((unsigned int)time(NULL)); + ///- Initialize detour memory management + dtAllocSetCustom(dtCustomAlloc, dtCustomFree); + ///- Initialize config settings LoadConfigSettings(); @@ -1276,12 +1280,7 @@ void World::SetInitialWorldSettings() //No SQL injection as values are treated as integers // not send custom type REALM_FFA_PVP to realm list - uint32 server_type; - if (IsFFAPvPRealm()) - server_type = REALM_TYPE_PVP; - else - server_type = getIntConfig(CONFIG_GAME_TYPE); - + uint32 server_type = IsFFAPvPRealm() ? uint32(REALM_TYPE_PVP) : getIntConfig(CONFIG_GAME_TYPE); uint32 realm_zone = getIntConfig(CONFIG_REALM_ZONE); LoginDatabase.PExecute("UPDATE realmlist SET icon = %u, timezone = %u WHERE id = '%d'", server_type, realm_zone, realmID); // One-time query @@ -1336,6 +1335,8 @@ void World::SetInitialWorldSettings() sObjectMgr->SetDBCLocaleIndex(GetDefaultDbcLocale()); // Get once for all the locale index of DBC language (console/broadcasts) sLog->outInfo(LOG_FILTER_SERVER_LOADING, ">> Localization strings loaded in %u ms", GetMSTimeDiffToNow(oldMSTime)); + sLog->outInfo(LOG_FILTER_SERVER_LOADING, "Loading Account Roles and Permissions..."); + sAccountMgr->LoadRBAC(); sLog->outInfo(LOG_FILTER_SERVER_LOADING, "Loading Page Texts..."); sObjectMgr->LoadPageTexts(); @@ -1382,8 +1383,8 @@ void World::SetInitialWorldSettings() sLog->outInfo(LOG_FILTER_SERVER_LOADING, "Loading Item Random Enchantments Table..."); LoadRandomEnchantmentsTable(); - sLog->outInfo(LOG_FILTER_SERVER_LOADING, "Loading Disables"); - DisableMgr::LoadDisables(); // must be before loading quests and items + sLog->outInfo(LOG_FILTER_SERVER_LOADING, "Loading Disables"); // must be before loading quests and items + DisableMgr::LoadDisables(); sLog->outInfo(LOG_FILTER_SERVER_LOADING, "Loading Items..."); // must be after LoadRandomEnchantmentsTable and LoadPageTexts sObjectMgr->LoadItemTemplates(); @@ -1394,12 +1395,12 @@ void World::SetInitialWorldSettings() sLog->outInfo(LOG_FILTER_SERVER_LOADING, "Loading Creature Model Based Info Data..."); sObjectMgr->LoadCreatureModelInfo(); - sLog->outInfo(LOG_FILTER_SERVER_LOADING, "Loading Equipment templates..."); - sObjectMgr->LoadEquipmentTemplates(); - sLog->outInfo(LOG_FILTER_SERVER_LOADING, "Loading Creature templates..."); sObjectMgr->LoadCreatureTemplates(); + sLog->outInfo(LOG_FILTER_SERVER_LOADING, "Loading Equipment templates..."); // must be after LoadCreatureTemplates + sObjectMgr->LoadEquipmentTemplates(); + sLog->outInfo(LOG_FILTER_SERVER_LOADING, "Loading Creature template addons..."); sObjectMgr->LoadCreatureTemplateAddons(); @@ -1421,6 +1422,9 @@ void World::SetInitialWorldSettings() sLog->outInfo(LOG_FILTER_SERVER_LOADING, "Loading Creature Data..."); sObjectMgr->LoadCreatures(); + sLog->outInfo(LOG_FILTER_SERVER_LOADING, "Loading Temporary Summon Data..."); + sObjectMgr->LoadTempSummons(); // must be after LoadCreatureTemplates() and LoadGameObjectTemplates() + sLog->outInfo(LOG_FILTER_SERVER_LOADING, "Loading pet levelup spells..."); sSpellMgr->LoadPetLevelupSpellMap(); @@ -1563,9 +1567,11 @@ void World::SetInitialWorldSettings() ///- Load dynamic data tables from the database sLog->outInfo(LOG_FILTER_SERVER_LOADING, "Loading Item Auctions..."); sAuctionMgr->LoadAuctionItems(); + sLog->outInfo(LOG_FILTER_SERVER_LOADING, "Loading Auctions..."); sAuctionMgr->LoadAuctions(); + sLog->outInfo(LOG_FILTER_SERVER_LOADING, "Loading Guilds..."); sGuildMgr->LoadGuilds(); sLog->outInfo(LOG_FILTER_SERVER_LOADING, "Loading ArenaTeams..."); @@ -1704,7 +1710,7 @@ void World::SetInitialWorldSettings() //to set mailtimer to return mails every day between 4 and 5 am //mailtimer is increased when updating auctions //one second is 1000 -(tested on win system) - //TODO: Get rid of magic numbers + /// @todo Get rid of magic numbers mail_timer = ((((localtime(&m_gameTime)->tm_hour + 20) % 24)* HOUR * IN_MILLISECONDS) / m_timers[WUPDATE_AUCTIONS].GetInterval()); //1440 mail_timer_expires = ((DAY * IN_MILLISECONDS) / (m_timers[WUPDATE_AUCTIONS].GetInterval())); @@ -1781,7 +1787,9 @@ void World::SetInitialWorldSettings() uint32 startupDuration = GetMSTimeDiffToNow(startupBegin); sLog->outInfo(LOG_FILTER_WORLDSERVER, "World initialized in %u minutes %u seconds", (startupDuration / 60000), ((startupDuration % 60000) / 1000)); - sLog->EnableDBAppenders(); + + if (uint32 realmId = ConfigMgr::GetIntDefault("RealmID", 0)) // 0 reserved for auth + sLog->SetRealmId(realmId); } void World::DetectDBCLang() @@ -1825,7 +1833,6 @@ void World::DetectDBCLang() m_defaultDbcLocale = LocaleConstant(default_locale); sLog->outInfo(LOG_FILTER_SERVER_LOADING, "Using %s DBC Locale as default. All available DBC locales: %s", localeNames[m_defaultDbcLocale], availableLocalsStr.empty() ? "<none>" : availableLocalsStr.c_str()); - } void World::RecordTimeDiff(const char *text, ...) @@ -1865,7 +1872,6 @@ void World::LoadAutobroadcasts() if (!result) { sLog->outInfo(LOG_FILTER_SERVER_LOADING, ">> Loaded 0 autobroadcasts definitions. DB table `autobroadcast` is empty!"); - return; } @@ -1873,7 +1879,6 @@ void World::LoadAutobroadcasts() do { - Field* fields = result->Fetch(); std::string message = fields[0].GetString(); @@ -1882,8 +1887,7 @@ void World::LoadAutobroadcasts() ++count; } while (result->NextRow()); - sLog->outInfo(LOG_FILTER_SERVER_LOADING, ">> Loaded %u autobroadcasts definitions in %u ms", count, GetMSTimeDiffToNow(oldMSTime)); - + sLog->outInfo(LOG_FILTER_SERVER_LOADING, ">> Loaded %u autobroadcast definitions in %u ms", count, GetMSTimeDiffToNow(oldMSTime)); } /// Update the World ! @@ -2103,18 +2107,21 @@ void World::SendGlobalMessage(WorldPacket* packet, WorldSession* self, uint32 te /// Send a packet to all GMs (except self if mentioned) void World::SendGlobalGMMessage(WorldPacket* packet, WorldSession* self, uint32 team) { - SessionMap::iterator itr; - for (itr = m_sessions.begin(); itr != m_sessions.end(); ++itr) + for (SessionMap::const_iterator itr = m_sessions.begin(); itr != m_sessions.end(); ++itr) { - if (itr->second && - itr->second->GetPlayer() && - itr->second->GetPlayer()->IsInWorld() && - itr->second != self && - !AccountMgr::IsPlayerAccount(itr->second->GetSecurity()) && - (team == 0 || itr->second->GetPlayer()->GetTeam() == team)) - { - itr->second->SendPacket(packet); - } + // check if session and can receive global GM Messages and its not self + WorldSession* session = itr->second; + if (!session || session == self || !session->HasPermission(RBAC_PERM_RECEIVE_GLOBAL_GM_TEXTMESSAGE)) + continue; + + // Player should be in world + Player* player = session->GetPlayer(); + if (!player || !player->IsInWorld()) + continue; + + // Send only to same team, if team is given + if (!team || player->GetTeam() == team) + session->SendPacket(packet); } } @@ -2202,15 +2209,19 @@ void World::SendGMText(int32 string_id, ...) Trinity::WorldWorldTextBuilder wt_builder(string_id, &ap); Trinity::LocalizedPacketListDo<Trinity::WorldWorldTextBuilder> wt_do(wt_builder); - for (SessionMap::iterator itr = m_sessions.begin(); itr != m_sessions.end(); ++itr) + for (SessionMap::const_iterator itr = m_sessions.begin(); itr != m_sessions.end(); ++itr) { - if (!itr->second || !itr->second->GetPlayer() || !itr->second->GetPlayer()->IsInWorld()) + // Session should have permissions to receive global gm messages + WorldSession* session = itr->second; + if (!session || !session->HasPermission(RBAC_PERM_RECEIVE_GLOBAL_GM_TEXTMESSAGE)) continue; - if (AccountMgr::IsPlayerAccount(itr->second->GetSecurity())) + // Player should be in world + Player* player = session->GetPlayer(); + if (!player || !player->IsInWorld()) continue; - wt_do(itr->second->GetPlayer()); + wt_do(player); } va_end(ap); @@ -2846,8 +2857,6 @@ void World::ResetMonthlyQuests() if (itr->second->GetPlayer()) itr->second->GetPlayer()->ResetMonthlyQuestStatus(); - time_t mostRecentQuestTime = 0; - // generate time time_t curTime = time(NULL); tm localTm = *localtime(&curTime); @@ -2874,14 +2883,8 @@ void World::ResetMonthlyQuests() time_t nextMonthResetTime = mktime(&localTm); - // last reset time before current moment - time_t resetTime = (curTime < nextMonthResetTime) ? nextMonthResetTime - MONTH : nextMonthResetTime; - - // need reset (if we have quest time before last reset time (not processed by some reason) - if (mostRecentQuestTime && mostRecentQuestTime <= resetTime) - m_NextMonthlyQuestReset = mostRecentQuestTime; - else // plan next reset time - m_NextMonthlyQuestReset = (curTime >= nextMonthResetTime) ? nextMonthResetTime + MONTH : nextMonthResetTime; + // plan next reset time + m_NextMonthlyQuestReset = (curTime >= nextMonthResetTime) ? nextMonthResetTime + MONTH : nextMonthResetTime; sWorld->setWorldState(WS_MONTHLY_QUEST_RESET_TIME, uint64(m_NextMonthlyQuestReset)); } @@ -2889,7 +2892,7 @@ void World::ResetMonthlyQuests() void World::ResetEventSeasonalQuests(uint16 event_id) { PreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_DEL_QUEST_STATUS_SEASONAL); - stmt->setUInt16(0,event_id); + stmt->setUInt16(0, event_id); CharacterDatabase.Execute(stmt); for (SessionMap::const_iterator itr = m_sessions.begin(); itr != m_sessions.end(); ++itr) @@ -2933,8 +2936,8 @@ void World::LoadDBVersion() if (result) { Field* fields = result->Fetch(); - m_DBVersion = fields[0].GetString(); + m_DBVersion = fields[0].GetString(); // will be overwrite by config values if different and non-0 m_int_configs[CONFIG_CLIENTCACHE_VERSION] = fields[1].GetUInt32(); } @@ -3108,3 +3111,12 @@ CharacterNameData const* World::GetCharacterNameData(uint32 guid) const else return NULL; } + +void World::ReloadRBAC() +{ + // Pasive reload, we mark the data as invalidated and next time a permission is checked it will be reloaded + sLog->outInfo(LOG_FILTER_RBAC, "World::ReloadRBAC()"); + for (SessionMap::const_iterator itr = m_sessions.begin(); itr != m_sessions.end(); ++itr) + if (WorldSession* session = itr->second) + session->InvalidateRBACData(); +} diff --git a/src/server/game/World/World.h b/src/server/game/World/World.h index 768f1d327b8..00bb9e7ffb2 100644 --- a/src/server/game/World/World.h +++ b/src/server/game/World/World.h @@ -90,25 +90,18 @@ enum WorldBoolConfigs CONFIG_CLEAN_CHARACTER_DB, CONFIG_GRID_UNLOAD, CONFIG_STATS_SAVE_ONLY_ON_LOGOUT, - CONFIG_ALLOW_TWO_SIDE_ACCOUNTS, CONFIG_ALLOW_TWO_SIDE_INTERACTION_CALENDAR, - CONFIG_ALLOW_TWO_SIDE_INTERACTION_CHAT, CONFIG_ALLOW_TWO_SIDE_INTERACTION_CHANNEL, CONFIG_ALLOW_TWO_SIDE_INTERACTION_GROUP, CONFIG_ALLOW_TWO_SIDE_INTERACTION_GUILD, CONFIG_ALLOW_TWO_SIDE_INTERACTION_AUCTION, - CONFIG_ALLOW_TWO_SIDE_INTERACTION_MAIL, - CONFIG_ALLOW_TWO_SIDE_WHO_LIST, - CONFIG_ALLOW_TWO_SIDE_ADD_FRIEND, CONFIG_ALLOW_TWO_SIDE_TRADE, CONFIG_ALL_TAXI_PATHS, CONFIG_INSTANT_TAXI, CONFIG_INSTANCE_IGNORE_LEVEL, CONFIG_INSTANCE_IGNORE_RAID, CONFIG_CAST_UNSTUCK, - CONFIG_GM_LOG_TRADE, CONFIG_ALLOW_GM_GROUP, - CONFIG_ALLOW_GM_FRIEND, CONFIG_GM_LOWER_SECURITY, CONFIG_SKILL_PROSPECTING, CONFIG_SKILL_MILLING, @@ -118,7 +111,6 @@ enum WorldBoolConfigs CONFIG_QUEST_IGNORE_RAID, CONFIG_DETECT_POS_COLLISION, CONFIG_RESTRICTED_LFG_CHANNEL, - CONFIG_SILENTLY_GM_JOIN_TO_CHANNEL, CONFIG_TALENTS_INSPECTING, CONFIG_CHAT_FAKE_MESSAGE_PREVENTING, CONFIG_DEATH_CORPSE_RECLAIM_DELAY_PVP, @@ -138,7 +130,6 @@ enum WorldBoolConfigs CONFIG_ARENA_LOG_EXTENDED_INFO, CONFIG_OFFHAND_CHECK_AT_SPELL_UNLEARN, CONFIG_VMAP_INDOOR_CHECK, - CONFIG_PET_LOS, CONFIG_START_ALL_SPELLS, CONFIG_START_ALL_EXPLORED, CONFIG_START_ALL_REP, @@ -164,7 +155,10 @@ enum WorldBoolConfigs CONFIG_QUEST_IGNORE_AUTO_ACCEPT, CONFIG_QUEST_IGNORE_AUTO_COMPLETE, CONFIG_WARDEN_ENABLED, + CONFIG_ENABLE_MMAPS, CONFIG_WINTERGRASP_ENABLE, + CONFIG_UI_QUESTLEVELS_IN_DIALOGS, // Should we add quest levels to the title in the NPC dialogs? + CONFIG_EVENT_ANNOUNCE, BOOL_CONFIG_VALUE_COUNT }; @@ -252,7 +246,6 @@ enum WorldIntConfigs CONFIG_CHATFLOOD_MESSAGE_COUNT, CONFIG_CHATFLOOD_MESSAGE_DELAY, CONFIG_CHATFLOOD_MUTE_TIME, - CONFIG_EVENT_ANNOUNCE, CONFIG_CREATURE_FAMILY_ASSISTANCE_DELAY, CONFIG_CREATURE_FAMILY_FLEE_DELAY, CONFIG_WORLD_BOSS_LEVEL_DIFF, @@ -384,8 +377,6 @@ enum Rates RATE_AUCTION_DEPOSIT, RATE_AUCTION_CUT, RATE_HONOR, - RATE_MINING_AMOUNT, - RATE_MINING_NEXT, RATE_TALENT, RATE_CORPSE_DECAY_LOOTED, RATE_INSTANCE_RESET_TIME, @@ -567,7 +558,7 @@ class World int32 GetQueuePos(WorldSession*); bool HasRecentlyDisconnected(WorldSession*); - /// \todo Actions on m_allowMovement still to be implemented + /// @todo Actions on m_allowMovement still to be implemented /// Is movement allowed? bool getAllowMovement() const { return m_allowMovement; } /// Allow/Disallow object movements @@ -732,11 +723,15 @@ class World void AddCharacterNameData(uint32 guid, std::string const& name, uint8 gender, uint8 race, uint8 playerClass, uint8 level); void UpdateCharacterNameData(uint32 guid, std::string const& name, uint8 gender = GENDER_NONE, uint8 race = RACE_NONE); void UpdateCharacterNameDataLevel(uint32 guid, uint8 level); - void DeleteCharaceterNameData(uint32 guid) { _characterNameDataMap.erase(guid); } + void DeleteCharacterNameData(uint32 guid) { _characterNameDataMap.erase(guid); } + bool HasCharacterNameData(uint32 guid) { return _characterNameDataMap.find(guid) != _characterNameDataMap.end(); } uint32 GetCleaningFlags() const { return m_CleaningFlags; } void SetCleaningFlags(uint32 flags) { m_CleaningFlags = flags; } void ResetEventSeasonalQuests(uint16 event_id); + + void ReloadRBAC(); + protected: void _UpdateGameTime(); // callback for UpdateRealmCharacters diff --git a/src/server/scripts/CMakeLists.txt b/src/server/scripts/CMakeLists.txt index 9726cc1a937..cf4618022b3 100644 --- a/src/server/scripts/CMakeLists.txt +++ b/src/server/scripts/CMakeLists.txt @@ -45,6 +45,8 @@ message("") include_directories( ${CMAKE_BINARY_DIR} + ${CMAKE_SOURCE_DIR}/dep/recastnavigation/Detour + ${CMAKE_SOURCE_DIR}/dep/recastnavigation/Recast ${CMAKE_SOURCE_DIR}/dep/g3dlite/include ${CMAKE_SOURCE_DIR}/dep/SFMT ${CMAKE_SOURCE_DIR}/dep/zlib diff --git a/src/server/scripts/Commands/CMakeLists.txt b/src/server/scripts/Commands/CMakeLists.txt index 97e9b35e6cd..15e16c2caf1 100644 --- a/src/server/scripts/Commands/CMakeLists.txt +++ b/src/server/scripts/Commands/CMakeLists.txt @@ -18,6 +18,7 @@ set(scripts_STAT_SRCS Commands/cs_character.cpp Commands/cs_cheat.cpp Commands/cs_debug.cpp + Commands/cs_deserter.cpp Commands/cs_disable.cpp Commands/cs_event.cpp Commands/cs_gm.cpp @@ -35,6 +36,7 @@ set(scripts_STAT_SRCS Commands/cs_modify.cpp Commands/cs_npc.cpp Commands/cs_quest.cpp + Commands/cs_rbac.cpp Commands/cs_reload.cpp Commands/cs_reset.cpp Commands/cs_tele.cpp @@ -42,6 +44,7 @@ set(scripts_STAT_SRCS Commands/cs_server.cpp Commands/cs_titles.cpp Commands/cs_wp.cpp + Commands/cs_mmaps.cpp # Commands/cs_pdump.cpp # Commands/cs_channel.cpp # Commands/cs_pet.cpp diff --git a/src/server/scripts/Commands/cs_account.cpp b/src/server/scripts/Commands/cs_account.cpp index 3a20a03bb4a..3953beab3da 100644 --- a/src/server/scripts/Commands/cs_account.cpp +++ b/src/server/scripts/Commands/cs_account.cpp @@ -106,7 +106,7 @@ public: if (!accountName || !password) return false; - AccountOpResult result = AccountMgr::CreateAccount(std::string(accountName), std::string(password)); + AccountOpResult result = sAccountMgr->CreateAccount(std::string(accountName), std::string(password)); switch (result) { case AOR_OK: @@ -140,7 +140,7 @@ public: } /// Delete a user account and all associated characters in this realm - /// \todo This function has to be enhanced to respect the login/realm split (delete char, delete account chars in realm then delete account) + /// @todo This function has to be enhanced to respect the login/realm split (delete char, delete account chars in realm then delete account) static bool HandleAccountDeleteCommand(ChatHandler* handler, char const* args) { if (!*args) @@ -503,36 +503,8 @@ public: return false; } - // If gmRealmID is -1, delete all values for the account id, else, insert values for the specific realmID - PreparedStatement* stmt; - - if (gmRealmID == -1) - { - stmt = LoginDatabase.GetPreparedStatement(LOGIN_DEL_ACCOUNT_ACCESS); - - stmt->setUInt32(0, targetAccountId); - } - else - { - stmt = LoginDatabase.GetPreparedStatement(LOGIN_DEL_ACCOUNT_ACCESS_BY_REALM); - - stmt->setUInt32(0, targetAccountId); - stmt->setUInt32(1, realmID); - } - - LoginDatabase.Execute(stmt); - - if (gm != 0) - { - stmt = LoginDatabase.GetPreparedStatement(LOGIN_INS_ACCOUNT_ACCESS); - - stmt->setUInt32(0, targetAccountId); - stmt->setUInt8(1, uint8(gm)); - stmt->setInt32(2, gmRealmID); - - LoginDatabase.Execute(stmt); - } - + RBACData* rbac = isAccountNameGiven ? NULL : handler->getSelectedPlayer()->GetSession()->GetRBACData(); + sAccountMgr->UpdateAccountAccess(rbac, targetAccountId, uint8(gm), gmRealmID); handler->PSendSysMessage(LANG_YOU_CHANGE_SECURITY, targetAccountName.c_str(), gm); return true; diff --git a/src/server/scripts/Commands/cs_character.cpp b/src/server/scripts/Commands/cs_character.cpp index 5ec40bcd0fc..c29b62975ab 100644 --- a/src/server/scripts/Commands/cs_character.cpp +++ b/src/server/scripts/Commands/cs_character.cpp @@ -443,7 +443,7 @@ public: stmt->setUInt16(0, uint16(AT_LOGIN_CHANGE_RACE)); if (target) { - // TODO : add text into database + /// @todo add text into database handler->PSendSysMessage(LANG_CUSTOMIZE_PLAYER, handler->GetNameLink(target).c_str()); target->SetAtLoginFlag(AT_LOGIN_CHANGE_RACE); stmt->setUInt32(1, target->GetGUIDLow()); @@ -451,7 +451,7 @@ public: else { std::string oldNameLink = handler->playerLink(targetName); - // TODO : add text into database + /// @todo add text into database handler->PSendSysMessage(LANG_CUSTOMIZE_PLAYER_GUID, oldNameLink.c_str(), GUID_LOPART(targetGuid)); stmt->setUInt32(1, GUID_LOPART(targetGuid)); } diff --git a/src/server/scripts/Commands/cs_debug.cpp b/src/server/scripts/Commands/cs_debug.cpp index 030bc136333..400e35b705b 100644 --- a/src/server/scripts/Commands/cs_debug.cpp +++ b/src/server/scripts/Commands/cs_debug.cpp @@ -1120,13 +1120,13 @@ public: if (isInt32) { uint32 value = (uint32)atoi(y); - target->SetUInt32Value(opcode , value); + target->SetUInt32Value(opcode, value); handler->PSendSysMessage(LANG_SET_UINT_FIELD, GUID_LOPART(guid), opcode, value); } else { float value = (float)atof(y); - target->SetFloatValue(opcode , value); + target->SetFloatValue(opcode, value); handler->PSendSysMessage(LANG_SET_FLOAT_FIELD, GUID_LOPART(guid), opcode, value); } @@ -1328,7 +1328,7 @@ public: { Player* player = handler->GetSession()->GetPlayer(); - sLog->outInfo(LOG_FILTER_SQL_DEV, "(@PATH, XX, %.3f, %.3f, %.5f, 0,0, 0,100, 0),", player->GetPositionX(), player->GetPositionY(), player->GetPositionZ()); + sLog->outInfo(LOG_FILTER_SQL_DEV, "(@PATH, XX, %.3f, %.3f, %.5f, 0, 0, 0, 100, 0),", player->GetPositionX(), player->GetPositionY(), player->GetPositionZ()); handler->PSendSysMessage("Waypoint SQL written to SQL Developer log"); return true; diff --git a/src/server/scripts/Commands/cs_deserter.cpp b/src/server/scripts/Commands/cs_deserter.cpp new file mode 100644 index 00000000000..3850456fcb3 --- /dev/null +++ b/src/server/scripts/Commands/cs_deserter.cpp @@ -0,0 +1,199 @@ +/* + * Copyright (C) 2008-2013 TrinityCore <http://www.trinitycore.org/> + * + * 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 2 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/>. + */ + +/** +* @file cs_deserter.cpp +* @brief .deserter related commands +* +* This file contains the CommandScripts for all deserter sub-commands +*/ + +#include "Chat.h" +#include "Player.h" +#include "Language.h" +#include "ScriptMgr.h" +#include "SpellAuras.h" + +enum Spells +{ + LFG_SPELL_DUNGEON_DESERTER = 71041, + BG_SPELL_DESERTER = 26013 +}; + +class deserter_commandscript : public CommandScript +{ +public: + deserter_commandscript() : CommandScript("deserter_commandscript") { } + + /** + * @brief Returns the command structure for the system. + */ + + ChatCommand* GetCommands() const + { + static ChatCommand deserterInstanceCommandTable[] = + { + { "add", SEC_ADMINISTRATOR, false, &HandleDeserterInstanceAdd, "", NULL }, + { "remove", SEC_ADMINISTRATOR, false, &HandleDeserterInstanceRemove, "", NULL }, + { NULL, SEC_PLAYER, false, NULL, "", NULL } + }; + static ChatCommand deserterBGCommandTable[] = + { + { "add", SEC_ADMINISTRATOR, false, &HandleDeserterBGAdd, "", NULL }, + { "remove", SEC_ADMINISTRATOR, false, &HandleDeserterBGRemove, "", NULL }, + { NULL, SEC_PLAYER, false, NULL, "", NULL } + }; + + static ChatCommand deserterCommandTable[] = + { + { "instance", SEC_ADMINISTRATOR, false, NULL, "", deserterInstanceCommandTable }, + { "bg", SEC_ADMINISTRATOR, false, NULL, "", deserterBGCommandTable }, + { NULL, SEC_PLAYER, false, NULL, "", NULL } + }; + static ChatCommand commandTable[] = + { + { "deserter", SEC_ADMINISTRATOR, false, NULL, "", deserterCommandTable }, + { NULL, SEC_PLAYER, false, NULL, "", NULL } + }; + return commandTable; + } + + /** + * @brief Applies the Deserter Debuff to a player + * + * This function applies a Deserter Debuff of the given type (Instance or BG) to the + * selected player, with the provided duration in seconds. + * + * @param handler The ChatHandler, passed by the system. + * @param args The provided duration in seconds. + * @param isInstance provided by the relaying functions, so we don't have + * to write that much code :) + * + * @return true if everything was correct, false if an error occured. + * + * Example Usage: + * @code + * .deserter instance add 3600 (one hour) + * -or- + * .deserter bg add 3600 (one hour) + * @endcode + */ + static bool HandleDeserterAdd(ChatHandler* handler, char const* args, bool isInstance) + { + if (!*args) + return false; + + Player* player = handler->getSelectedPlayer(); + if (!player) + { + handler->SendSysMessage(LANG_NO_CHAR_SELECTED); + handler->SetSentErrorMessage(true); + return false; + } + char* timeStr = strtok((char*)args, " "); + if (!timeStr) + { + handler->SendSysMessage(LANG_BAD_VALUE); + handler->SetSentErrorMessage(true); + return false; + } + uint32 time = atoi(timeStr); + + if (!time) + { + handler->SendSysMessage(LANG_BAD_VALUE); + handler->SetSentErrorMessage(true); + return false; + } + + Aura* aura = player->AddAura(isInstance ? LFG_SPELL_DUNGEON_DESERTER : BG_SPELL_DESERTER, player); + + if (!aura) + { + handler->SendSysMessage(LANG_BAD_VALUE); + handler->SetSentErrorMessage(true); + return false; + } + aura->SetDuration(time * IN_MILLISECONDS); + + return true; + } + + /** + * @brief Removes the Deserter Debuff from a player + * + * This function removes a Deserter Debuff of the given type (Instance or BG) from the + * selected player. + * + * @param handler The ChatHandler, passed by the system. + * @param args Should be nothing. + * @param isInstance provided by the relaying functions, so we don't have + * to write that much code :) + * + * @return true if everything was correct, false if an error occured. + * + * Example Usage: + * @code + * .deserter instance remove + * -or- + * .deserter bg remove + * @endcode + */ + static bool HandleDeserterRemove(ChatHandler* handler, char const* /*args*/, bool isInstance) + { + Player* player = handler->getSelectedPlayer(); + if (!player) + { + handler->SendSysMessage(LANG_NO_CHAR_SELECTED); + handler->SetSentErrorMessage(true); + return false; + } + + player->RemoveAura(isInstance ? LFG_SPELL_DUNGEON_DESERTER : BG_SPELL_DESERTER); + + return true; + } + + /// @sa HandleDeserterAdd() + static bool HandleDeserterInstanceAdd(ChatHandler* handler, char const* args) + { + return HandleDeserterAdd(handler, args, true); + } + + /// @sa HandleDeserterAdd() + static bool HandleDeserterBGAdd(ChatHandler* handler, char const* args) + { + return HandleDeserterAdd(handler, args, false); + } + + /// @sa HandleDeserterRemove() + static bool HandleDeserterInstanceRemove(ChatHandler* handler, char const* args) + { + return HandleDeserterRemove(handler, args, true); + } + + /// @sa HandleDeserterRemove() + static bool HandleDeserterBGRemove(ChatHandler* handler, char const* args) + { + return HandleDeserterRemove(handler, args, false); + } +}; + +void AddSC_deserter_commandscript() +{ + new deserter_commandscript(); +} diff --git a/src/server/scripts/Commands/cs_disable.cpp b/src/server/scripts/Commands/cs_disable.cpp index 37e282cac8e..34738777c85 100644 --- a/src/server/scripts/Commands/cs_disable.cpp +++ b/src/server/scripts/Commands/cs_disable.cpp @@ -48,6 +48,7 @@ public: { "achievement_criteria", SEC_ADMINISTRATOR, true, &HandleRemoveDisableAchievementCriteriaCommand, "", NULL }, { "outdoorpvp", SEC_ADMINISTRATOR, true, &HandleRemoveDisableOutdoorPvPCommand, "", NULL }, { "vmap", SEC_ADMINISTRATOR, true, &HandleRemoveDisableVmapCommand, "", NULL }, + { "mmap", SEC_ADMINISTRATOR, true, &HandleRemoveDisableMMapCommand, "", NULL }, { NULL, 0, false, NULL, "", NULL } }; static ChatCommand addDisableCommandTable[] = @@ -59,6 +60,7 @@ public: { "achievement_criteria", SEC_ADMINISTRATOR, true, &HandleAddDisableAchievementCriteriaCommand, "", NULL }, { "outdoorpvp", SEC_ADMINISTRATOR, true, &HandleAddDisableOutdoorPvPCommand, "", NULL }, { "vmap", SEC_ADMINISTRATOR, true, &HandleAddDisableVmapCommand, "", NULL }, + { "mmap", SEC_ADMINISTRATOR, true, &HandleAddDisableMMapCommand, "", NULL }, { NULL, 0, false, NULL, "", NULL } }; static ChatCommand disableCommandTable[] = @@ -172,6 +174,17 @@ public: disableTypeStr = "vmap"; break; } + case DISABLE_TYPE_MMAP: + { + if (!sMapStore.LookupEntry(entry)) + { + handler->PSendSysMessage(LANG_COMMAND_NOMAPFOUND); + handler->SetSentErrorMessage(true); + return false; + } + disableTypeStr = "mmap"; + break; + } default: break; } @@ -256,6 +269,14 @@ public: return HandleAddDisables(handler, args, DISABLE_TYPE_VMAP); } + static bool HandleAddDisableMMapCommand(ChatHandler* handler, char const* args) + { + if (!*args) + return false; + + return HandleAddDisables(handler, args, DISABLE_TYPE_MMAP); + } + static bool HandleRemoveDisables(ChatHandler* handler, char const* args, uint8 disableType) { char* entryStr = strtok((char*)args, " "); @@ -289,6 +310,9 @@ public: case DISABLE_TYPE_VMAP: disableTypeStr = "vmap"; break; + case DISABLE_TYPE_MMAP: + disableTypeStr = "mmap"; + break; } PreparedStatement* stmt = NULL; @@ -367,6 +391,14 @@ public: return HandleRemoveDisables(handler, args, DISABLE_TYPE_VMAP); } + + static bool HandleRemoveDisableMMapCommand(ChatHandler* handler, char const* args) + { + if (!*args) + return false; + + return HandleRemoveDisables(handler, args, DISABLE_TYPE_MMAP); + } }; void AddSC_disable_commandscript() diff --git a/src/server/scripts/Commands/cs_gm.cpp b/src/server/scripts/Commands/cs_gm.cpp index 932bb562f11..168a5ec60b8 100644 --- a/src/server/scripts/Commands/cs_gm.cpp +++ b/src/server/scripts/Commands/cs_gm.cpp @@ -59,30 +59,32 @@ public: // Enables or disables hiding of the staff badge static bool HandleGMChatCommand(ChatHandler* handler, char const* args) { - if (!*args) + if (WorldSession* session = handler->GetSession()) { - WorldSession* session = handler->GetSession(); - if (!AccountMgr::IsPlayerAccount(session->GetSecurity()) && session->GetPlayer()->isGMChat()) - session->SendNotification(LANG_GM_CHAT_ON); - else - session->SendNotification(LANG_GM_CHAT_OFF); - return true; - } + if (!*args) + { + if (session->HasPermission(RBAC_PERM_CHAT_USE_STAFF_BADGE) && session->GetPlayer()->isGMChat()) + session->SendNotification(LANG_GM_CHAT_ON); + else + session->SendNotification(LANG_GM_CHAT_OFF); + return true; + } - std::string param = (char*)args; + std::string param = (char*)args; - if (param == "on") - { - handler->GetSession()->GetPlayer()->SetGMChat(true); - handler->GetSession()->SendNotification(LANG_GM_CHAT_ON); - return true; - } + if (param == "on") + { + session->GetPlayer()->SetGMChat(true); + session->SendNotification(LANG_GM_CHAT_ON); + return true; + } - if (param == "off") - { - handler->GetSession()->GetPlayer()->SetGMChat(false); - handler->GetSession()->SendNotification(LANG_GM_CHAT_OFF); - return true; + if (param == "off") + { + session->GetPlayer()->SetGMChat(false); + session->SendNotification(LANG_GM_CHAT_OFF); + return true; + } } handler->SendSysMessage(LANG_USE_BOL); @@ -126,7 +128,9 @@ public: for (HashMapHolder<Player>::MapType::const_iterator itr = m.begin(); itr != m.end(); ++itr) { AccountTypes itrSec = itr->second->GetSession()->GetSecurity(); - if ((itr->second->isGameMaster() || (!AccountMgr::IsPlayerAccount(itrSec) && itrSec <= AccountTypes(sWorld->getIntConfig(CONFIG_GM_LEVEL_IN_GM_LIST)))) && + if ((itr->second->isGameMaster() || + (itr->second->GetSession()->HasPermission(RBAC_PERM_COMMANDS_APPEAR_IN_GM_LIST) && + itrSec <= AccountTypes(sWorld->getIntConfig(CONFIG_GM_LEVEL_IN_GM_LIST)))) && (!handler->GetSession() || itr->second->IsVisibleGloballyFor(handler->GetSession()->GetPlayer()))) { if (first) diff --git a/src/server/scripts/Commands/cs_gobject.cpp b/src/server/scripts/Commands/cs_gobject.cpp index 4093861ae9a..f99e51fb260 100644 --- a/src/server/scripts/Commands/cs_gobject.cpp +++ b/src/server/scripts/Commands/cs_gobject.cpp @@ -174,7 +174,7 @@ public: return false; } - // TODO: is it really necessary to add both the real and DB table guid here ? + /// @todo is it really necessary to add both the real and DB table guid here ? sObjectMgr->AddGameobjectToGrid(guidLow, sObjectMgr->GetGOData(guidLow)); handler->PSendSysMessage(LANG_GAMEOBJECT_ADD, objectId, objectInfo->name.c_str(), guidLow, x, y, z); diff --git a/src/server/scripts/Commands/cs_lfg.cpp b/src/server/scripts/Commands/cs_lfg.cpp index 7f39a8fc024..aa9d9308bcd 100644 --- a/src/server/scripts/Commands/cs_lfg.cpp +++ b/src/server/scripts/Commands/cs_lfg.cpp @@ -28,12 +28,12 @@ void GetPlayerInfo(ChatHandler* handler, Player* player) return; uint64 guid = player->GetGUID(); - LfgDungeonSet dungeons = sLFGMgr->GetSelectedDungeons(guid); + lfg::LfgDungeonSet dungeons = sLFGMgr->GetSelectedDungeons(guid); - std::string const& state = sLFGMgr->GetStateString(sLFGMgr->GetState(guid)); + std::string const& state = lfg::GetStateString(sLFGMgr->GetState(guid)); handler->PSendSysMessage(LANG_LFG_PLAYER_INFO, player->GetName().c_str(), - state.c_str(), uint8(dungeons.size()), sLFGMgr->ConcatenateDungeons(dungeons).c_str(), - sLFGMgr->GetRolesString(sLFGMgr->GetRoles(guid)).c_str(), sLFGMgr->GetComment(guid).c_str()); + state.c_str(), uint8(dungeons.size()), lfg::ConcatenateDungeons(dungeons).c_str(), + lfg::GetRolesString(sLFGMgr->GetRoles(guid)).c_str(), sLFGMgr->GetComment(guid).c_str()); } class lfg_commandscript : public CommandScript @@ -87,7 +87,7 @@ public: } uint64 guid = grp->GetGUID(); - std::string const& state = sLFGMgr->GetStateString(sLFGMgr->GetState(guid)); + std::string const& state = lfg::GetStateString(sLFGMgr->GetState(guid)); handler->PSendSysMessage(LANG_LFG_GROUP_INFO, grp->isLFGGroup(), state.c_str(), sLFGMgr->GetDungeon(guid)); diff --git a/src/server/scripts/Commands/cs_list.cpp b/src/server/scripts/Commands/cs_list.cpp index fce1f77c2cf..81608ebd458 100644 --- a/src/server/scripts/Commands/cs_list.cpp +++ b/src/server/scripts/Commands/cs_list.cpp @@ -29,6 +29,7 @@ EndScriptData */ #include "ObjectAccessor.h" #include "ObjectMgr.h" #include "Player.h" +#include <iostream> class list_commandscript : public CommandScript { @@ -43,6 +44,7 @@ public: { "item", SEC_ADMINISTRATOR, true, &HandleListItemCommand, "", NULL }, { "object", SEC_ADMINISTRATOR, true, &HandleListObjectCommand, "", NULL }, { "auras", SEC_ADMINISTRATOR, false, &HandleListAurasCommand, "", NULL }, + { "mail", SEC_ADMINISTRATOR, true, &HandleListMailCommand, "", NULL }, { NULL, 0, false, NULL, "", NULL } }; static ChatCommand commandTable[] = @@ -463,6 +465,114 @@ public: return true; } + // handle list mail command + static bool HandleListMailCommand(ChatHandler* handler, char const* args) + { + Player* target; + uint64 targetGuid; + std::string targetName; + + if (!*args) + return false; + + uint32 parseGUID = MAKE_NEW_GUID(atol((char*)args), 0, HIGHGUID_PLAYER); + + if (sObjectMgr->GetPlayerNameByGUID(parseGUID, targetName)) + { + target = sObjectMgr->GetPlayerByLowGUID(parseGUID); + targetGuid = parseGUID; + } + else if (!handler->extractPlayerTarget((char*)args, &target, &targetGuid, &targetName)) + return false; + + PreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_SEL_MAIL_LIST_COUNT); + stmt->setUInt32(0, targetGuid); + PreparedQueryResult result = CharacterDatabase.Query(stmt); + if (result) + { + Field* fields = result->Fetch(); + uint32 countMail = fields[0].GetUInt64(); + std::string nameLink = handler->playerLink(targetName); + handler->PSendSysMessage(LANG_LIST_MAIL_HEADER, countMail, nameLink.c_str(), targetGuid); + handler->PSendSysMessage(LANG_ACCOUNT_LIST_BAR); + PreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_SEL_MAIL_LIST_INFO); + stmt->setUInt32(0, targetGuid); + PreparedQueryResult result = CharacterDatabase.Query(stmt); + if (result) + { + do + { + Field* fields = result->Fetch(); + uint32 messageId = fields[0].GetUInt32(); + uint32 senderId = fields[1].GetUInt32(); + std::string sender = fields[2].GetString(); + uint32 receiverId = fields[3].GetUInt32(); + std::string receiver = fields[4].GetString(); + std::string subject = fields[5].GetString(); + uint64 deliverTime = fields[6].GetUInt32(); + uint64 expireTime = fields[7].GetUInt32(); + uint32 money = fields[8].GetUInt32(); + int hasItem = fields[9].GetUInt8(); + uint32 gold = money /GOLD; + uint32 silv = (money % GOLD) / SILVER; + uint32 copp = (money % GOLD) % SILVER; + std::string receiverStr = handler->playerLink(receiver); + std::string senderStr = handler->playerLink(sender); + handler->PSendSysMessage(LANG_LIST_MAIL_INFO_1 , messageId, subject.c_str(),gold, silv, copp); + handler->PSendSysMessage(LANG_LIST_MAIL_INFO_2, senderStr.c_str(), senderId, receiverStr.c_str(), receiverId); + handler->PSendSysMessage(LANG_LIST_MAIL_INFO_3, TimeToTimestampStr(deliverTime).c_str(), TimeToTimestampStr(expireTime).c_str()); + if (hasItem == 1) + { + QueryResult result2; + result2 = CharacterDatabase.PQuery("SELECT item_guid FROM mail_items WHERE mail_id = '%u'", messageId); + if (result2) + { + do + { + uint32 item_guid = (*result2)[0].GetUInt32(); + PreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_SEL_MAIL_LIST_ITEMS); + stmt->setUInt32(0, item_guid); + PreparedQueryResult result3 = CharacterDatabase.Query(stmt); + if (result3) + { + do + { + Field* fields = result3->Fetch(); + uint32 item_entry = fields[0].GetUInt32(); + uint32 item_count = fields[1].GetUInt32(); + QueryResult result4; + result4 = WorldDatabase.PQuery("SELECT name,quality FROM item_template WHERE entry = '%u'", item_entry); + Field* fields1 = result4->Fetch(); + std::string item_name = fields1[0].GetString(); + int item_quality = fields1[1].GetUInt8(); + if (handler->GetSession()) + { + uint32 color = ItemQualityColors[item_quality]; + std::ostringstream itemStr; + itemStr << "|c" << std::hex << color << "|Hitem:" << item_entry << ":0:0:0:0:0:0:0:0:0|h[" << item_name << "]|h|r"; + handler->PSendSysMessage(LANG_LIST_MAIL_INFO_ITEM, itemStr.str().c_str(), item_entry, item_guid, item_count); + } + else + handler->PSendSysMessage(LANG_LIST_MAIL_INFO_ITEM, item_name.c_str(), item_entry, item_guid, item_count); + } + while (result3->NextRow()); + } + } + while (result2->NextRow()); + } + } + handler->PSendSysMessage(LANG_ACCOUNT_LIST_BAR); + } + while (result->NextRow()); + } + else + handler->PSendSysMessage(LANG_LIST_MAIL_NOT_FOUND); + return true; + } + else + handler->PSendSysMessage(LANG_LIST_MAIL_NOT_FOUND); + return true; + } }; void AddSC_list_commandscript() diff --git a/src/server/scripts/Commands/cs_message.cpp b/src/server/scripts/Commands/cs_message.cpp index e2c53492e9d..cc50490e831 100644 --- a/src/server/scripts/Commands/cs_message.cpp +++ b/src/server/scripts/Commands/cs_message.cpp @@ -27,6 +27,7 @@ EndScriptData */ #include "ChannelMgr.h" #include "Language.h" #include "Player.h" +#include "ObjectMgr.h" class message_commandscript : public CommandScript { @@ -186,7 +187,7 @@ public: return true; } - std::string argStr = (char*)args; + std::string argStr = strtok((char*)args, " "); // whisper on if (argStr == "on") { @@ -205,6 +206,25 @@ public: return true; } + if (argStr == "remove") + { + std::string name = strtok(NULL, " "); + if (normalizePlayerName(name)) + { + if (Player* player = sObjectAccessor->FindPlayerByName(name)) + { + handler->GetSession()->GetPlayer()->RemoveFromWhisperWhiteList(player->GetGUID()); + handler->PSendSysMessage(LANG_COMMAND_WHISPEROFFPLAYER, name.c_str()); + return true; + } + else + { + handler->PSendSysMessage(LANG_PLAYER_NOT_FOUND, name.c_str()); + handler->SetSentErrorMessage(true); + return false; + } + } + } handler->SendSysMessage(LANG_USE_BOL); handler->SetSentErrorMessage(true); return false; diff --git a/src/server/scripts/Commands/cs_misc.cpp b/src/server/scripts/Commands/cs_misc.cpp index 59315e1a813..c6d80cea3a5 100644 --- a/src/server/scripts/Commands/cs_misc.cpp +++ b/src/server/scripts/Commands/cs_misc.cpp @@ -33,6 +33,9 @@ #include "ace/INET_Addr.h" #include "Player.h" #include "Pet.h" +#include "LFG.h" +#include "GroupMgr.h" +#include "MMapFactory.h" class misc_commandscript : public CommandScript { @@ -46,6 +49,8 @@ public: { "leader", SEC_ADMINISTRATOR, false, &HandleGroupLeaderCommand, "", NULL }, { "disband", SEC_ADMINISTRATOR, false, &HandleGroupDisbandCommand, "", NULL }, { "remove", SEC_ADMINISTRATOR, false, &HandleGroupRemoveCommand, "", NULL }, + { "join", SEC_ADMINISTRATOR, false, &HandleGroupJoinCommand, "", NULL }, + { "list", SEC_ADMINISTRATOR, false, &HandleGroupListCommand, "", NULL }, { NULL, 0, false, NULL, "", NULL } }; static ChatCommand petCommandTable[] = @@ -187,8 +192,9 @@ public: uint32 zoneId, areaId; object->GetZoneAndAreaId(zoneId, areaId); + uint32 mapId = object->GetMapId(); - MapEntry const* mapEntry = sMapStore.LookupEntry(object->GetMapId()); + MapEntry const* mapEntry = sMapStore.LookupEntry(mapId); AreaTableEntry const* zoneEntry = GetAreaEntryByAreaID(zoneId); AreaTableEntry const* areaEntry = GetAreaEntryByAreaID(areaId); @@ -207,8 +213,9 @@ public: int gridX = 63 - gridCoord.x_coord; int gridY = 63 - gridCoord.y_coord; - uint32 haveMap = Map::ExistMap(object->GetMapId(), gridX, gridY) ? 1 : 0; - uint32 haveVMap = Map::ExistVMap(object->GetMapId(), gridX, gridY) ? 1 : 0; + uint32 haveMap = Map::ExistMap(mapId, gridX, gridY) ? 1 : 0; + uint32 haveVMap = Map::ExistVMap(mapId, gridX, gridY) ? 1 : 0; + uint32 haveMMap = (MMAP::MMapFactory::IsPathfindingEnabled(mapId) && MMAP::MMapFactory::createOrGetMMapManager()->GetNavMesh(handler->GetSession()->GetPlayer()->GetMapId())) ? 1 : 0; if (haveVMap) { @@ -221,13 +228,13 @@ public: handler->PSendSysMessage("no VMAP available for area info"); handler->PSendSysMessage(LANG_MAP_POSITION, - object->GetMapId(), (mapEntry ? mapEntry->name[handler->GetSessionDbcLocale()] : "<unknown>"), + mapId, (mapEntry ? mapEntry->name[handler->GetSessionDbcLocale()] : "<unknown>"), zoneId, (zoneEntry ? zoneEntry->area_name[handler->GetSessionDbcLocale()] : "<unknown>"), areaId, (areaEntry ? areaEntry->area_name[handler->GetSessionDbcLocale()] : "<unknown>"), object->GetPhaseMask(), object->GetPositionX(), object->GetPositionY(), object->GetPositionZ(), object->GetOrientation(), cell.GridX(), cell.GridY(), cell.CellX(), cell.CellY(), object->GetInstanceId(), - zoneX, zoneY, groundZ, floorZ, haveMap, haveVMap); + zoneX, zoneY, groundZ, floorZ, haveMap, haveVMap, haveMMap); LiquidData liquidStatus; ZLiquidStatus status = map->getLiquidStatus(object->GetPositionX(), object->GetPositionY(), object->GetPositionZ(), MAP_ALL_LIQUIDS, &liquidStatus); @@ -674,7 +681,7 @@ public: if (target) { - target->ResurrectPlayer(!AccountMgr::IsPlayerAccount(target->GetSession()->GetSecurity()) ? 1.0f : 0.5f); + target->ResurrectPlayer(target->GetSession()->HasPermission(RBAC_PERM_RESURRECT_WITH_FULL_HPS) ? 1.0f : 0.5f); target->SpawnCorpseBones(); target->SaveToDB(); } @@ -877,7 +884,7 @@ public: Player* player = handler->GetSession()->GetPlayer(); // save GM account without delay and output message - if (!AccountMgr::IsPlayerAccount(handler->GetSession()->GetSecurity())) + if (handler->GetSession()->HasPermission(RBAC_PERM_COMMANDS_SAVE_WITHOUT_DELAY)) { if (Player* target = handler->getSelectedPlayer()) target->SaveToDB(); @@ -934,8 +941,8 @@ public: static bool HandleUnstuckCommand(ChatHandler* handler, char const* args) { - //No args required for players - if (handler->GetSession() && AccountMgr::IsPlayerAccount(handler->GetSession()->GetSecurity())) + // No args required for players + if (handler->GetSession() && !handler->GetSession()->HasPermission(RBAC_PERM_COMMANDS_USE_UNSTUCK_WITH_ARGS)) { // 7355: "Stuck" if (Player* player = handler->GetSession()->GetPlayer()) @@ -1534,7 +1541,7 @@ public: return false; Field* fields = result->Fetch(); - totalPlayerTime = fields[0].GetUInt32(); + totalPlayerTime = fields[0].GetUInt32(); level = fields[1].GetUInt8(); money = fields[2].GetUInt32(); accId = fields[3].GetUInt32(); @@ -1546,6 +1553,8 @@ public: std::string userName = handler->GetTrinityString(LANG_ERROR); std::string eMail = handler->GetTrinityString(LANG_ERROR); + std::string muteReason = ""; + std::string muteBy = ""; std::string lastIp = handler->GetTrinityString(LANG_ERROR); uint32 security = 0; std::string lastLogin = handler->GetTrinityString(LANG_ERROR); @@ -1562,6 +1571,8 @@ public: security = fields[1].GetUInt8(); eMail = fields[2].GetString(); muteTime = fields[5].GetUInt64(); + muteReason = fields[6].GetString(); + muteBy = fields[7].GetString(); if (eMail.empty()) eMail = "-"; @@ -1617,13 +1628,13 @@ public: if (result2) { Field* fields = result2->Fetch(); - banTime = int64(fields[1].GetBool() ? 0 : fields[0].GetUInt32()); + banTime = int64(fields[1].GetUInt64() ? 0 : fields[0].GetUInt32()); bannedby = fields[2].GetString(); banreason = fields[3].GetString(); } if (muteTime > 0) - handler->PSendSysMessage(LANG_PINFO_MUTE, secsToTimeString(muteTime - time(NULL), true).c_str()); + handler->PSendSysMessage(LANG_PINFO_MUTE, secsToTimeString(muteTime - time(NULL), true).c_str(), muteBy.c_str(), muteReason.c_str()); if (banTime >= 0) handler->PSendSysMessage(LANG_PINFO_BAN, banTime > 0 ? secsToTimeString(banTime - time(NULL), true).c_str() : "permanently", bannedby.c_str(), banreason.c_str()); @@ -1730,6 +1741,23 @@ public: else handler->PSendSysMessage(LANG_PINFO_MAP_OFFLINE, map->name[locale], areaName.c_str()); + stmt = CharacterDatabase.GetPreparedStatement(CHAR_SEL_GUILD_MEMBER_EXTENDED); + stmt->setUInt32(0, GUID_LOPART(targetGuid)); + + result = CharacterDatabase.Query(stmt); + if (result) + { + Field* fields = result->Fetch(); + + uint32 guildId = fields[0].GetUInt32(); + std::string guildName = fields[1].GetString(); + std::string guildRank = fields[2].GetString(); + std::string note = fields[3].GetString(); + std::string officeNote = fields[4].GetString(); + + handler->PSendSysMessage(LANG_PINFO_GUILD_INFO, guildName.c_str(), guildId, guildRank.c_str(), note.c_str(), officeNote.c_str()); + } + return true; } @@ -1799,6 +1827,11 @@ public: return false; PreparedStatement* stmt = LoginDatabase.GetPreparedStatement(LOGIN_UPD_MUTE_TIME); + std::string muteBy = ""; + if (handler->GetSession()) + muteBy = handler->GetSession()->GetPlayerName(); + else + muteBy = "Console"; if (target) { @@ -1806,7 +1839,7 @@ public: int64 muteTime = time(NULL) + notSpeakTime * MINUTE; target->GetSession()->m_muteTime = muteTime; stmt->setInt64(0, muteTime); - ChatHandler(target->GetSession()).PSendSysMessage(LANG_YOUR_CHAT_DISABLED, notSpeakTime, muteReasonStr.c_str()); + ChatHandler(target->GetSession()).PSendSysMessage(LANG_YOUR_CHAT_DISABLED, notSpeakTime, muteBy.c_str(), muteReasonStr.c_str()); } else { @@ -1815,7 +1848,9 @@ public: stmt->setInt64(0, muteTime); } - stmt->setUInt32(1, accountId); + stmt->setString(1, muteReasonStr.c_str()); + stmt->setString(2, muteBy.c_str()); + stmt->setUInt32(3, accountId); LoginDatabase.Execute(stmt); std::string nameLink = handler->playerLink(targetName); @@ -1858,7 +1893,9 @@ public: PreparedStatement* stmt = LoginDatabase.GetPreparedStatement(LOGIN_UPD_MUTE_TIME); stmt->setInt64(0, 0); - stmt->setUInt32(1, accountId); + stmt->setString(1, ""); + stmt->setString(2, ""); + stmt->setUInt32(3, accountId); LoginDatabase.Execute(stmt); if (target) @@ -2177,7 +2214,7 @@ public: // from console show not existed sender MailSender sender(MAIL_NORMAL, handler->GetSession() ? handler->GetSession()->GetPlayer()->GetGUIDLow() : 0, MAIL_STATIONERY_GM); - //- TODO: Fix poor design + /// @todo Fix poor design SQLTransaction trans = CharacterDatabase.BeginTransaction(); MailDraft(subject, text) .SendMailTo(trans, MailReceiver(target, GUID_LOPART(targetGuid)), sender); @@ -2725,6 +2762,132 @@ public: return true; } + static bool HandleGroupJoinCommand(ChatHandler* handler, char const* args) + { + if (!*args) + return false; + + Player* playerSource = NULL; + Player* playerTarget = NULL; + Group* groupSource = NULL; + Group* groupTarget = NULL; + uint64 guidSource = 0; + uint64 guidTarget = 0; + char* nameplgrStr = strtok((char*)args, " "); + char* nameplStr = strtok(NULL, " "); + + if (handler->GetPlayerGroupAndGUIDByName(nameplgrStr, playerSource, groupSource, guidSource, true)) + { + if (groupSource) + { + if (handler->GetPlayerGroupAndGUIDByName(nameplStr, playerTarget, groupTarget, guidTarget, true)) + { + if (!groupTarget && playerTarget->GetGroup() != groupSource) + { + if (!groupSource->IsFull()) + { + groupSource->AddMember(playerTarget); + groupSource->BroadcastGroupUpdate(); + handler->PSendSysMessage(LANG_GROUP_PLAYER_JOINED, playerTarget->GetName().c_str(), playerSource->GetName().c_str()); + return true; + } + else + { + // group is full + handler->PSendSysMessage(LANG_GROUP_FULL); + return true; + } + } + else + { + // group is full or target player already in a group + handler->PSendSysMessage(LANG_GROUP_ALREADY_IN_GROUP, playerTarget->GetName().c_str()); + return true; + } + } + } + else + { + // specified source player is not in a group + handler->PSendSysMessage(LANG_GROUP_NOT_IN_GROUP, playerSource->GetName().c_str()); + return true; + } + } + + return true; + } + + static bool HandleGroupListCommand(ChatHandler* handler, char const* args) + { + Player* playerTarget; + uint64 guidTarget; + std::string nameTarget; + + uint32 parseGUID = MAKE_NEW_GUID(atol((char*)args), 0, HIGHGUID_PLAYER); + + if (sObjectMgr->GetPlayerNameByGUID(parseGUID, nameTarget)) + { + playerTarget = sObjectMgr->GetPlayerByLowGUID(parseGUID); + guidTarget = parseGUID; + } + else if (!handler->extractPlayerTarget((char*)args, &playerTarget, &guidTarget, &nameTarget)) + return false; + + Group* groupTarget = NULL; + if (playerTarget) + groupTarget = playerTarget->GetGroup(); + + if (!groupTarget) + { + PreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_SEL_GROUP_MEMBER); + stmt->setUInt32(0, guidTarget); + PreparedQueryResult resultGroup = CharacterDatabase.Query(stmt); + if (resultGroup) + groupTarget = sGroupMgr->GetGroupByDbStoreId((*resultGroup)[0].GetUInt32()); + } + + if (groupTarget) + { + handler->PSendSysMessage(LANG_GROUP_TYPE, (groupTarget->isRaidGroup() ? "raid" : "party")); + Group::MemberSlotList const& members = groupTarget->GetMemberSlots(); + for (Group::MemberSlotList::const_iterator itr = members.begin(); itr != members.end(); ++itr) + { + Group::MemberSlot const& slot = *itr; + + std::string flags; + if (slot.flags & MEMBER_FLAG_ASSISTANT) + flags = "Assistant"; + + if (slot.flags & MEMBER_FLAG_MAINTANK) + { + if (!flags.empty()) + flags.append(", "); + flags.append("MainTank"); + } + + if (slot.flags & MEMBER_FLAG_MAINASSIST) + { + if (!flags.empty()) + flags.append(", "); + flags.append("MainAssist"); + } + + if (flags.empty()) + flags = "None"; + + Player* p = ObjectAccessor::FindPlayer((*itr).guid); + const char* onlineState = (p && p->IsInWorld()) ? "online" : "offline"; + + handler->PSendSysMessage(LANG_GROUP_PLAYER_NAME_GUID, slot.name.c_str(), onlineState, + GUID_LOPART(slot.guid), flags.c_str(), lfg::GetRolesString(slot.roles).c_str()); + } + } + else + handler->PSendSysMessage(LANG_GROUP_NOT_IN_GROUP, nameTarget.c_str()); + + return true; + } + static bool HandlePlayAllCommand(ChatHandler* handler, char const* args) { if (!*args) diff --git a/src/server/scripts/Commands/cs_mmaps.cpp b/src/server/scripts/Commands/cs_mmaps.cpp new file mode 100644 index 00000000000..79cd0deb75e --- /dev/null +++ b/src/server/scripts/Commands/cs_mmaps.cpp @@ -0,0 +1,294 @@ +/* + * Copyright (C) 2008-2013 TrinityCore <http://www.trinitycore.org/> + * + * 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 2 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/>. + */ + +/** +* @file cs_mmaps.cpp +* @brief .mmap related commands +* +* This file contains the CommandScripts for all +* mmap sub-commands +*/ + +#include "ScriptMgr.h" +#include "Chat.h" +#include "ObjectMgr.h" +#include "Player.h" +#include "PointMovementGenerator.h" +#include "PathGenerator.h" +#include "MMapFactory.h" +#include "Map.h" +#include "TargetedMovementGenerator.h" +#include "GridNotifiers.h" +#include "GridNotifiersImpl.h" +#include "CellImpl.h" + +class mmaps_commandscript : public CommandScript +{ +public: + mmaps_commandscript() : CommandScript("mmaps_commandscript") { } + + ChatCommand* GetCommands() const + { + static ChatCommand mmapCommandTable[] = + { + { "path", SEC_ADMINISTRATOR, false, &HandleMmapPathCommand, "", NULL }, + { "loc", SEC_ADMINISTRATOR, false, &HandleMmapLocCommand, "", NULL }, + { "loadedtiles", SEC_ADMINISTRATOR, false, &HandleMmapLoadedTilesCommand, "", NULL }, + { "stats", SEC_ADMINISTRATOR, false, &HandleMmapStatsCommand, "", NULL }, + { "testarea", SEC_ADMINISTRATOR, false, &HandleMmapTestArea, "", NULL }, + { NULL, 0, false, NULL, "", NULL } + }; + + static ChatCommand commandTable[] = + { + { "mmap", SEC_ADMINISTRATOR, true, NULL, "", mmapCommandTable }, + { NULL, 0, false, NULL, "", NULL } + }; + return commandTable; + } + + static bool HandleMmapPathCommand(ChatHandler* handler, char const* args) + { + if (!MMAP::MMapFactory::createOrGetMMapManager()->GetNavMesh(handler->GetSession()->GetPlayer()->GetMapId())) + { + handler->PSendSysMessage("NavMesh not loaded for current map."); + return true; + } + + handler->PSendSysMessage("mmap path:"); + + // units + Player* player = handler->GetSession()->GetPlayer(); + Unit* target = handler->getSelectedUnit(); + if (!player || !target) + { + handler->PSendSysMessage("Invalid target/source selection."); + return true; + } + + char* para = strtok((char*)args, " "); + + bool useStraightPath = false; + if (para && strcmp(para, "true") == 0) + useStraightPath = true; + + // unit locations + float x, y, z; + player->GetPosition(x, y, z); + + // path + PathGenerator path(target); + path.SetUseStraightPath(useStraightPath); + bool result = path.CalculatePath(x, y, z); + + PointsArray const& pointPath = path.GetPath(); + handler->PSendSysMessage("%s's path to %s:", target->GetName().c_str(), player->GetName().c_str()); + handler->PSendSysMessage("Building: %s", useStraightPath ? "StraightPath" : "SmoothPath"); + handler->PSendSysMessage("Result: %s - Length: "SIZEFMTD" - Type: %u", (result ? "true" : "false"), pointPath.size(), path.GetPathType()); + + Vector3 start = path.GetStartPosition(); + Vector3 end = path.GetEndPosition(); + Vector3 actualEnd = path.GetActualEndPosition(); + + handler->PSendSysMessage("StartPosition (%.3f, %.3f, %.3f)", start.x, start.y, start.z); + handler->PSendSysMessage("EndPosition (%.3f, %.3f, %.3f)", end.x, end.y, end.z); + handler->PSendSysMessage("ActualEndPosition (%.3f, %.3f, %.3f)", actualEnd.x, actualEnd.y, actualEnd.z); + + if (!player->isGameMaster()) + handler->PSendSysMessage("Enable GM mode to see the path points."); + + for (uint32 i = 0; i < pointPath.size(); ++i) + player->SummonCreature(VISUAL_WAYPOINT, pointPath[i].x, pointPath[i].y, pointPath[i].z, 0, TEMPSUMMON_TIMED_DESPAWN, 9000); + + return true; + } + + static bool HandleMmapLocCommand(ChatHandler* handler, char const* /*args*/) + { + handler->PSendSysMessage("mmap tileloc:"); + + // grid tile location + Player* player = handler->GetSession()->GetPlayer(); + + int32 gx = 32 - player->GetPositionX() / SIZE_OF_GRIDS; + int32 gy = 32 - player->GetPositionY() / SIZE_OF_GRIDS; + + handler->PSendSysMessage("%03u%02i%02i.mmtile", player->GetMapId(), gy, gx); + handler->PSendSysMessage("gridloc [%i,%i]", gx, gy); + + // calculate navmesh tile location + dtNavMesh const* navmesh = MMAP::MMapFactory::createOrGetMMapManager()->GetNavMesh(handler->GetSession()->GetPlayer()->GetMapId()); + dtNavMeshQuery const* navmeshquery = MMAP::MMapFactory::createOrGetMMapManager()->GetNavMeshQuery(handler->GetSession()->GetPlayer()->GetMapId(), player->GetInstanceId()); + if (!navmesh || !navmeshquery) + { + handler->PSendSysMessage("NavMesh not loaded for current map."); + return true; + } + + float const* min = navmesh->getParams()->orig; + float x, y, z; + player->GetPosition(x, y, z); + float location[VERTEX_SIZE] = {y, z, x}; + float extents[VERTEX_SIZE] = {3.0f, 5.0f, 3.0f}; + + int32 tilex = int32((y - min[0]) / SIZE_OF_GRIDS); + int32 tiley = int32((x - min[2]) / SIZE_OF_GRIDS); + + handler->PSendSysMessage("Calc [%02i,%02i]", tilex, tiley); + + // navmesh poly -> navmesh tile location + dtQueryFilter filter = dtQueryFilter(); + dtPolyRef polyRef = INVALID_POLYREF; + navmeshquery->findNearestPoly(location, extents, &filter, &polyRef, NULL); + + if (polyRef == INVALID_POLYREF) + handler->PSendSysMessage("Dt [??,??] (invalid poly, probably no tile loaded)"); + else + { + dtMeshTile const* tile; + dtPoly const* poly; + navmesh->getTileAndPolyByRef(polyRef, &tile, &poly); + if (tile) + handler->PSendSysMessage("Dt [%02i,%02i]", tile->header->x, tile->header->y); + else + handler->PSendSysMessage("Dt [??,??] (no tile loaded)"); + } + + return true; + } + + static bool HandleMmapLoadedTilesCommand(ChatHandler* handler, char const* /*args*/) + { + uint32 mapid = handler->GetSession()->GetPlayer()->GetMapId(); + dtNavMesh const* navmesh = MMAP::MMapFactory::createOrGetMMapManager()->GetNavMesh(mapid); + dtNavMeshQuery const* navmeshquery = MMAP::MMapFactory::createOrGetMMapManager()->GetNavMeshQuery(mapid, handler->GetSession()->GetPlayer()->GetInstanceId()); + if (!navmesh || !navmeshquery) + { + handler->PSendSysMessage("NavMesh not loaded for current map."); + return true; + } + + handler->PSendSysMessage("mmap loadedtiles:"); + + for (int32 i = 0; i < navmesh->getMaxTiles(); ++i) + { + dtMeshTile const* tile = navmesh->getTile(i); + if (!tile || !tile->header) + continue; + + handler->PSendSysMessage("[%02i,%02i]", tile->header->x, tile->header->y); + } + + return true; + } + + static bool HandleMmapStatsCommand(ChatHandler* handler, char const* /*args*/) + { + uint32 mapId = handler->GetSession()->GetPlayer()->GetMapId(); + handler->PSendSysMessage("mmap stats:"); + handler->PSendSysMessage(" global mmap pathfinding is %sabled", MMAP::MMapFactory::IsPathfindingEnabled(mapId) ? "en" : "dis"); + + MMAP::MMapManager* manager = MMAP::MMapFactory::createOrGetMMapManager(); + handler->PSendSysMessage(" %u maps loaded with %u tiles overall", manager->getLoadedMapsCount(), manager->getLoadedTilesCount()); + + dtNavMesh const* navmesh = manager->GetNavMesh(handler->GetSession()->GetPlayer()->GetMapId()); + if (!navmesh) + { + handler->PSendSysMessage("NavMesh not loaded for current map."); + return true; + } + + uint32 tileCount = 0; + uint32 nodeCount = 0; + uint32 polyCount = 0; + uint32 vertCount = 0; + uint32 triCount = 0; + uint32 triVertCount = 0; + uint32 dataSize = 0; + for (int32 i = 0; i < navmesh->getMaxTiles(); ++i) + { + dtMeshTile const* tile = navmesh->getTile(i); + if (!tile || !tile->header) + continue; + + tileCount++; + nodeCount += tile->header->bvNodeCount; + polyCount += tile->header->polyCount; + vertCount += tile->header->vertCount; + triCount += tile->header->detailTriCount; + triVertCount += tile->header->detailVertCount; + dataSize += tile->dataSize; + } + + handler->PSendSysMessage("Navmesh stats:"); + handler->PSendSysMessage(" %u tiles loaded", tileCount); + handler->PSendSysMessage(" %u BVTree nodes", nodeCount); + handler->PSendSysMessage(" %u polygons (%u vertices)", polyCount, vertCount); + handler->PSendSysMessage(" %u triangles (%u vertices)", triCount, triVertCount); + handler->PSendSysMessage(" %.2f MB of data (not including pointers)", ((float)dataSize / sizeof(unsigned char)) / 1048576); + + return true; + } + + static bool HandleMmapTestArea(ChatHandler* handler, char const* /*args*/) + { + float radius = 40.0f; + WorldObject* object = handler->GetSession()->GetPlayer(); + + CellCoord pair(Trinity::ComputeCellCoord(object->GetPositionX(), object->GetPositionY())); + Cell cell(pair); + cell.SetNoCreate(); + + std::list<Creature*> creatureList; + + Trinity::AnyUnitInObjectRangeCheck go_check(object, radius); + Trinity::CreatureListSearcher<Trinity::AnyUnitInObjectRangeCheck> go_search(object, creatureList, go_check); + TypeContainerVisitor<Trinity::CreatureListSearcher<Trinity::AnyUnitInObjectRangeCheck>, GridTypeMapContainer> go_visit(go_search); + + // Get Creatures + cell.Visit(pair, go_visit, *(object->GetMap()), *object, radius); + + if (!creatureList.empty()) + { + handler->PSendSysMessage("Found "SIZEFMTD" Creatures.", creatureList.size()); + + uint32 paths = 0; + uint32 uStartTime = getMSTime(); + + float gx, gy, gz; + object->GetPosition(gx, gy, gz); + for (std::list<Creature*>::iterator itr = creatureList.begin(); itr != creatureList.end(); ++itr) + { + PathGenerator path(*itr); + path.CalculatePath(gx, gy, gz); + ++paths; + } + + uint32 uPathLoadTime = getMSTimeDiff(uStartTime, getMSTime()); + handler->PSendSysMessage("Generated %i paths in %i ms", paths, uPathLoadTime); + } + else + handler->PSendSysMessage("No creatures in %f yard range.", radius); + + return true; + } +}; + +void AddSC_mmaps_commandscript() +{ + new mmaps_commandscript(); +} diff --git a/src/server/scripts/Commands/cs_modify.cpp b/src/server/scripts/Commands/cs_modify.cpp index 01648f25cff..7219615736e 100644 --- a/src/server/scripts/Commands/cs_modify.cpp +++ b/src/server/scripts/Commands/cs_modify.cpp @@ -1046,9 +1046,12 @@ public: ChatHandler(target->GetSession()).PSendSysMessage(LANG_YOURS_MONEY_GIVEN, handler->GetNameLink().c_str(), moneyToAdd); if (moneyToAdd >= MAX_MONEY_AMOUNT) - target->SetMoney(MAX_MONEY_AMOUNT); - else - target->ModifyMoney(moneyToAdd); + moneyToAdd = MAX_MONEY_AMOUNT; + + if (targetMoney >= uint32(MAX_MONEY_AMOUNT) - moneyToAdd) + moneyToAdd -= targetMoney; + + target->ModifyMoney(moneyToAdd); } sLog->outDebug(LOG_FILTER_GENERAL, handler->GetTrinityString(LANG_NEW_MONEY), targetMoney, moneyToAdd, target->GetMoney()); @@ -1246,6 +1249,7 @@ public: } target->GetReputationMgr().SetOneFactionReputation(factionEntry, amount, false); + target->GetReputationMgr().SendState(target->GetReputationMgr().GetState(factionEntry)); handler->PSendSysMessage(LANG_COMMAND_MODIFY_REP, factionEntry->name[handler->GetSessionDbcLocale()], factionId, handler->GetNameLink(target).c_str(), target->GetReputationMgr().GetReputation(factionEntry)); return true; diff --git a/src/server/scripts/Commands/cs_npc.cpp b/src/server/scripts/Commands/cs_npc.cpp index 8679e288282..79a74b0823d 100644 --- a/src/server/scripts/Commands/cs_npc.cpp +++ b/src/server/scripts/Commands/cs_npc.cpp @@ -33,6 +33,42 @@ EndScriptData */ #include "Player.h" #include "Pet.h" +struct NpcFlagText +{ + uint32 flag; + int32 text; +}; + +#define NPCFLAG_COUNT 24 + +const NpcFlagText npcFlagTexts[NPCFLAG_COUNT] = +{ + { UNIT_NPC_FLAG_AUCTIONEER, LANG_NPCINFO_AUCTIONEER }, + { UNIT_NPC_FLAG_BANKER, LANG_NPCINFO_BANKER }, + { UNIT_NPC_FLAG_BATTLEMASTER, LANG_NPCINFO_BATTLEMASTER }, + { UNIT_NPC_FLAG_FLIGHTMASTER, LANG_NPCINFO_FLIGHTMASTER }, + { UNIT_NPC_FLAG_GOSSIP, LANG_NPCINFO_GOSSIP }, + { UNIT_NPC_FLAG_GUILD_BANKER, LANG_NPCINFO_GUILD_BANKER }, + { UNIT_NPC_FLAG_INNKEEPER, LANG_NPCINFO_INNKEEPER }, + { UNIT_NPC_FLAG_PETITIONER, LANG_NPCINFO_PETITIONER }, + { UNIT_NPC_FLAG_PLAYER_VEHICLE, LANG_NPCINFO_PLAYER_VEHICLE }, + { UNIT_NPC_FLAG_QUESTGIVER, LANG_NPCINFO_QUESTGIVER }, + { UNIT_NPC_FLAG_REPAIR, LANG_NPCINFO_REPAIR }, + { UNIT_NPC_FLAG_SPELLCLICK, LANG_NPCINFO_SPELLCLICK }, + { UNIT_NPC_FLAG_SPIRITGUIDE, LANG_NPCINFO_SPIRITGUIDE }, + { UNIT_NPC_FLAG_SPIRITHEALER, LANG_NPCINFO_SPIRITHEALER }, + { UNIT_NPC_FLAG_STABLEMASTER, LANG_NPCINFO_STABLEMASTER }, + { UNIT_NPC_FLAG_TABARDDESIGNER, LANG_NPCINFO_TABARDDESIGNER }, + { UNIT_NPC_FLAG_TRAINER, LANG_NPCINFO_TRAINER }, + { UNIT_NPC_FLAG_TRAINER_CLASS, LANG_NPCINFO_TRAINER_CLASS }, + { UNIT_NPC_FLAG_TRAINER_PROFESSION, LANG_NPCINFO_TRAINER_PROFESSION }, + { UNIT_NPC_FLAG_VENDOR, LANG_NPCINFO_VENDOR }, + { UNIT_NPC_FLAG_VENDOR_AMMO, LANG_NPCINFO_VENDOR_AMMO }, + { UNIT_NPC_FLAG_VENDOR_FOOD, LANG_NPCINFO_VENDOR_FOOD }, + { UNIT_NPC_FLAG_VENDOR_POISON, LANG_NPCINFO_VENDOR_POISON }, + { UNIT_NPC_FLAG_VENDOR_REAGENT, LANG_NPCINFO_VENDOR_REAGENT } +}; + class npc_commandscript : public CommandScript { public: @@ -46,7 +82,7 @@ public: { "item", SEC_GAMEMASTER, false, &HandleNpcAddVendorItemCommand, "", NULL }, { "move", SEC_GAMEMASTER, false, &HandleNpcAddMoveCommand, "", NULL }, { "temp", SEC_GAMEMASTER, false, &HandleNpcAddTempSpawnCommand, "", NULL }, - //{ TODO: fix or remove this command + //{@todo fix or remove this command { "weapon", SEC_ADMINISTRATOR, false, &HandleNpcAddWeaponCommand, "", NULL }, //} { "", SEC_GAMEMASTER, false, &HandleNpcAddCommand, "", NULL }, @@ -78,7 +114,7 @@ public: { "spawndist", SEC_GAMEMASTER, false, &HandleNpcSetSpawnDistCommand, "", NULL }, { "spawntime", SEC_GAMEMASTER, false, &HandleNpcSetSpawnTimeCommand, "", NULL }, { "data", SEC_ADMINISTRATOR, false, &HandleNpcSetDataCommand, "", NULL }, - //{ TODO: fix or remove these commands + //{ @todo fix or remove these commands { "name", SEC_GAMEMASTER, false, &HandleNpcSetNameCommand, "", NULL }, { "subname", SEC_GAMEMASTER, false, &HandleNpcSetSubNameCommand, "", NULL }, //} @@ -609,21 +645,20 @@ public: handler->PSendSysMessage(LANG_NPCINFO_CHAR, target->GetDBTableGUIDLow(), target->GetGUIDLow(), faction, npcflags, Entry, displayid, nativeid); handler->PSendSysMessage(LANG_NPCINFO_LEVEL, target->getLevel()); + handler->PSendSysMessage(LANG_NPCINFO_EQUIPMENT, target->GetCurrentEquipmentId(), target->GetOriginalEquipmentId()); handler->PSendSysMessage(LANG_NPCINFO_HEALTH, target->GetCreateHealth(), target->GetMaxHealth(), target->GetHealth()); - handler->PSendSysMessage(LANG_NPCINFO_FLAGS, target->GetUInt32Value(UNIT_FIELD_FLAGS), target->GetUInt32Value(UNIT_DYNAMIC_FLAGS), target->getFaction()); + handler->PSendSysMessage(LANG_NPCINFO_FLAGS, target->GetUInt32Value(UNIT_FIELD_FLAGS), target->GetUInt32Value(UNIT_FIELD_FLAGS_2), target->GetUInt32Value(UNIT_DYNAMIC_FLAGS), target->getFaction()); handler->PSendSysMessage(LANG_COMMAND_RAWPAWNTIMES, defRespawnDelayStr.c_str(), curRespawnDelayStr.c_str()); handler->PSendSysMessage(LANG_NPCINFO_LOOT, cInfo->lootid, cInfo->pickpocketLootId, cInfo->SkinLootId); handler->PSendSysMessage(LANG_NPCINFO_DUNGEON_ID, target->GetInstanceId()); handler->PSendSysMessage(LANG_NPCINFO_PHASEMASK, target->GetPhaseMask()); handler->PSendSysMessage(LANG_NPCINFO_ARMOR, target->GetArmor()); - handler->PSendSysMessage(LANG_NPCINFO_POSITION, float(target->GetPositionX()), float(target->GetPositionY()), float(target->GetPositionZ())); + handler->PSendSysMessage(LANG_NPCINFO_POSITION, target->GetPositionX(), target->GetPositionY(), target->GetPositionZ()); handler->PSendSysMessage(LANG_NPCINFO_AIINFO, target->GetAIName().c_str(), target->GetScriptName().c_str()); - if (npcflags & UNIT_NPC_FLAG_VENDOR) - handler->SendSysMessage(LANG_NPCINFO_VENDOR); - - if (npcflags & UNIT_NPC_FLAG_TRAINER) - handler->SendSysMessage(LANG_NPCINFO_TRAINER); + for (uint8 i = 0; i < NPCFLAG_COUNT; i++) + if (npcflags & npcFlagTexts[i].flag) + handler->PSendSysMessage(npcFlagTexts[i].text, npcFlagTexts[i].flag); return true; } @@ -1386,7 +1421,7 @@ public: return true; } - //TODO: NpcCommands that need to be fixed : + /// @todo NpcCommands that need to be fixed : static bool HandleNpcAddWeaponCommand(ChatHandler* /*handler*/, char const* /*args*/) { /*if (!*args) diff --git a/src/server/scripts/Commands/cs_quest.cpp b/src/server/scripts/Commands/cs_quest.cpp index a8748bc1adf..e0d67b55989 100644 --- a/src/server/scripts/Commands/cs_quest.cpp +++ b/src/server/scripts/Commands/cs_quest.cpp @@ -80,7 +80,7 @@ public: // check item starting quest (it can work incorrectly if added without item in inventory) ItemTemplateContainer const* itc = sObjectMgr->GetItemTemplateStore(); - ItemTemplateContainer::const_iterator result = find_if(itc->begin(), itc->end(), Finder<uint32, ItemTemplate>(entry, &ItemTemplate::StartQuest)); + ItemTemplateContainer::const_iterator result = find_if (itc->begin(), itc->end(), Finder<uint32, ItemTemplate>(entry, &ItemTemplate::StartQuest)); if (result != itc->end()) { @@ -138,6 +138,12 @@ public: // we ignore unequippable quest items in this case, its' still be equipped player->TakeQuestSourceItem(logQuest, false); + + if (quest->HasFlag(QUEST_FLAGS_FLAGS_PVP)) + { + player->pvpInfo.IsHostile = player->pvpInfo.IsInHostileArea || player->HasPvPForcingQuest(); + player->UpdatePvPState(); + } } } diff --git a/src/server/scripts/Commands/cs_rbac.cpp b/src/server/scripts/Commands/cs_rbac.cpp new file mode 100644 index 00000000000..604218c2e68 --- /dev/null +++ b/src/server/scripts/Commands/cs_rbac.cpp @@ -0,0 +1,780 @@ +/*
+ * Copyright (C) 2008-2013 TrinityCore <http://www.trinitycore.org/>
+ *
+ * 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 2 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/>.
+ */
+
+/* ScriptData
+Name: rbac_commandscript
+%Complete: 100
+Comment: All role based access control related commands (including account related)
+Category: commandscripts
+EndScriptData */
+
+#include "AccountMgr.h"
+#include "Config.h"
+#include "Chat.h"
+#include "Language.h"
+#include "Player.h"
+#include "ScriptMgr.h"
+
+struct RBACCommandData
+{
+ RBACCommandData(): id(0), realmId(0), rbac(NULL), needDelete(false) { }
+ uint32 id;
+ int32 realmId;
+ RBACData* rbac;
+ bool needDelete;
+};
+
+class rbac_commandscript : public CommandScript
+{
+public:
+ rbac_commandscript() : CommandScript("rbac_commandscript") { }
+
+ ChatCommand* GetCommands() const
+ {
+ static ChatCommand rbacGroupsCommandTable[] =
+ {
+ { "add", SEC_ADMINISTRATOR, true, &HandleRBACGroupAddCommand, "", NULL },
+ { "remove", SEC_ADMINISTRATOR, true, &HandleRBACGroupRemoveCommand, "", NULL },
+ { "", SEC_ADMINISTRATOR, true, &HandleRBACGroupListCommand, "", NULL },
+ { NULL, SEC_ADMINISTRATOR, false, NULL, "", NULL }
+ };
+
+ static ChatCommand rbacRolesCommandTable[] =
+ {
+ { "grant", SEC_ADMINISTRATOR, true, &HandleRBACRoleGrantCommand, "", NULL },
+ { "deny", SEC_ADMINISTRATOR, true, &HandleRBACRoleDenyCommand, "", NULL },
+ { "revoke", SEC_ADMINISTRATOR, true, &HandleRBACRoleRevokeCommand, "", NULL },
+ { "", SEC_ADMINISTRATOR, true, &HandleRBACRoleListCommand, "", NULL },
+ { NULL, SEC_ADMINISTRATOR, false, NULL, "", NULL }
+ };
+
+ static ChatCommand rbacPermsCommandTable[] =
+ {
+ { "grant", SEC_ADMINISTRATOR, true, &HandleRBACPermGrantCommand, "", NULL },
+ { "deny", SEC_ADMINISTRATOR, true, &HandleRBACPermDenyCommand, "", NULL },
+ { "revoke", SEC_ADMINISTRATOR, true, &HandleRBACPermRevokeCommand, "", NULL },
+ { "", SEC_ADMINISTRATOR, true, &HandleRBACPermListCommand, "", NULL },
+ { NULL, SEC_ADMINISTRATOR, false, NULL, "", NULL }
+ };
+
+ static ChatCommand rbacListCommandTable[] =
+ {
+ { "groups", SEC_ADMINISTRATOR, true, &HandleRBACListGroupsCommand, "", NULL },
+ { "roles", SEC_ADMINISTRATOR, true, &HandleRBACListRolesCommand, "", NULL },
+ { "permissions", SEC_ADMINISTRATOR, true, &HandleRBACListPermissionsCommand, "", NULL },
+ { NULL, SEC_ADMINISTRATOR, false, NULL, "", NULL }
+ };
+
+ static ChatCommand rbacAccountCommandTable[] =
+ {
+ { "group", SEC_ADMINISTRATOR, true, NULL, "", rbacGroupsCommandTable },
+ { "role", SEC_ADMINISTRATOR, true, NULL, "", rbacRolesCommandTable },
+ { "permission", SEC_ADMINISTRATOR, true, NULL, "", rbacPermsCommandTable },
+ { "", SEC_ADMINISTRATOR, true, &HandleRBACAccountPermissionCommand, "", NULL },
+ { NULL, SEC_ADMINISTRATOR, false, NULL, "", NULL }
+ };
+
+ static ChatCommand rbacCommandTable[] =
+ {
+ { "account", SEC_ADMINISTRATOR, true, NULL, "", rbacAccountCommandTable },
+ { "list", SEC_ADMINISTRATOR, true, NULL, "", rbacListCommandTable },
+ { NULL, SEC_ADMINISTRATOR, false, NULL, "", NULL }
+ };
+
+ static ChatCommand commandTable[] =
+ {
+ { "rbac", SEC_ADMINISTRATOR, true, NULL, "", rbacCommandTable },
+ { NULL, SEC_ADMINISTRATOR, false, NULL, "", NULL }
+ };
+
+ return commandTable;
+ }
+
+ static RBACCommandData* ReadParams(ChatHandler* handler, char const* args, bool checkParams = true)
+ {
+ if (!args)
+ return NULL;
+
+ char* param1 = strtok((char*)args, " ");
+ char* param2 = strtok(NULL, " ");
+ char* param3 = strtok(NULL, " ");
+
+ int32 realmId = -1;
+ uint32 accountId = 0;
+ std::string accountName;
+ uint32 id = 0;
+ RBACCommandData* data = NULL;
+ RBACData* rdata = NULL;
+ bool useSelectedPlayer = false;
+
+ if (checkParams)
+ {
+ if (!param3)
+ {
+ if (param2)
+ realmId = atoi(param2);
+
+ if (param1)
+ id = atoi(param1);
+
+ useSelectedPlayer = true;
+ }
+ else
+ {
+ id = atoi(param2);
+ realmId = atoi(param3);
+ }
+
+ if (!id)
+ {
+ handler->PSendSysMessage(LANG_RBAC_WRONG_PARAMETER_ID, id);
+ handler->SetSentErrorMessage(true);
+ return NULL;
+ }
+
+ if (realmId < -1 || !realmId)
+ {
+ handler->PSendSysMessage(LANG_RBAC_WRONG_PARAMETER_REALM, realmId);
+ handler->SetSentErrorMessage(true);
+ return NULL;
+ }
+ }
+ else if (!param1)
+ useSelectedPlayer = true;
+
+ if (useSelectedPlayer)
+ {
+ Player* player = handler->getSelectedPlayer();
+ if (!player)
+ return NULL;
+
+ rdata = player->GetSession()->GetRBACData();
+ accountId = rdata->GetId();
+ AccountMgr::GetName(accountId, accountName);
+ }
+ else
+ {
+ accountName = param1;
+
+ if (AccountMgr::normalizeString(accountName))
+ accountId = AccountMgr::GetId(accountName);
+
+ if (!accountId)
+ {
+ handler->PSendSysMessage(LANG_ACCOUNT_NOT_EXIST, accountName.c_str());
+ handler->SetSentErrorMessage(true);
+ return NULL;
+ }
+ }
+
+ if (checkParams && handler->HasLowerSecurityAccount(NULL, accountId, true))
+ return NULL;
+
+ data = new RBACCommandData();
+
+ if (!rdata)
+ {
+ data->rbac = new RBACData(accountId, accountName, realmID);
+ data->rbac->LoadFromDB();
+ data->needDelete = true;
+ }
+ else
+ data->rbac = rdata;
+
+ data->id = id;
+ data->realmId = realmId;
+ return data;
+ }
+
+ static bool HandleRBACGroupAddCommand(ChatHandler* handler, char const* args)
+ {
+ RBACCommandData* command = ReadParams(handler, args);
+
+ if (!command)
+ {
+ handler->SetSentErrorMessage(true);
+ return false;
+ }
+
+ RBACCommandResult result = command->rbac->AddGroup(command->id, command->realmId);
+ RBACGroup const* group = sAccountMgr->GetRBACGroup(command->id);
+
+ switch (result)
+ {
+ case RBAC_CANT_ADD_ALREADY_ADDED:
+ handler->PSendSysMessage(LANG_RBAC_GROUP_IN_LIST, command->id, group->GetName().c_str(),
+ command->realmId, command->rbac->GetId(), command->rbac->GetName().c_str());
+ break;
+ case RBAC_OK:
+ handler->PSendSysMessage(LANG_RBAC_GROUP_ADDED, command->id, group->GetName().c_str(),
+ command->realmId, command->rbac->GetId(), command->rbac->GetName().c_str());
+ break;
+ case RBAC_ID_DOES_NOT_EXISTS:
+ handler->PSendSysMessage(LANG_RBAC_WRONG_PARAMETER_ID, command->id);
+ break;
+ default:
+ break;
+ }
+
+ if (command->needDelete)
+ delete command;
+
+ return true;
+ }
+
+ static bool HandleRBACGroupRemoveCommand(ChatHandler* handler, char const* args)
+ {
+ RBACCommandData* command = ReadParams(handler, args);
+
+ if (!command)
+ {
+ handler->SetSentErrorMessage(true);
+ return false;
+ }
+
+ RBACCommandResult result = command->rbac->RemoveGroup(command->id, command->realmId);
+ RBACGroup const* group = sAccountMgr->GetRBACGroup(command->id);
+
+ switch (result)
+ {
+ case RBAC_CANT_REVOKE_NOT_IN_LIST:
+ handler->PSendSysMessage(LANG_RBAC_GROUP_NOT_IN_LIST, command->id, group->GetName().c_str(),
+ command->realmId, command->rbac->GetId(), command->rbac->GetName().c_str());
+ break;
+ case RBAC_OK:
+ handler->PSendSysMessage(LANG_RBAC_GROUP_REMOVED, command->id, group->GetName().c_str(),
+ command->realmId, command->rbac->GetId(), command->rbac->GetName().c_str());
+ break;
+ case RBAC_ID_DOES_NOT_EXISTS:
+ handler->PSendSysMessage(LANG_RBAC_WRONG_PARAMETER_ID, command->id);
+ break;
+ default:
+ break;
+ }
+
+ if (command->needDelete)
+ delete command;
+
+ return true;
+ }
+
+ static bool HandleRBACGroupListCommand(ChatHandler* handler, char const* args)
+ {
+ RBACCommandData* command = ReadParams(handler, args, false);
+
+ if (!command)
+ {
+ handler->SetSentErrorMessage(true);
+ return false;
+ }
+
+ handler->PSendSysMessage(LANG_RBAC_GROUP_LIST_HEADER, command->rbac->GetId(), command->rbac->GetName().c_str());
+ RBACGroupContainer const& groups = command->rbac->GetGroups();
+ if (groups.empty())
+ handler->PSendSysMessage("%s", handler->GetTrinityString(LANG_RBAC_LIST_EMPTY));
+ else
+ {
+ for (RBACGroupContainer::const_iterator it = groups.begin(); it != groups.end(); ++it)
+ {
+ RBACGroup const* group = sAccountMgr->GetRBACGroup(*it);
+ handler->PSendSysMessage(LANG_RBAC_LIST_ELEMENT, group->GetId(), group->GetName().c_str());
+ }
+ }
+
+ if (command->needDelete)
+ delete command;
+
+ return true;
+ }
+
+ static bool HandleRBACRoleGrantCommand(ChatHandler* handler, char const* args)
+ {
+ RBACCommandData* command = ReadParams(handler, args);
+
+ if (!command)
+ {
+ handler->SetSentErrorMessage(true);
+ return false;
+ }
+
+ RBACCommandResult result = command->rbac->GrantRole(command->id, command->realmId);
+ RBACRole const* role = sAccountMgr->GetRBACRole(command->id);
+
+ switch (result)
+ {
+ case RBAC_CANT_ADD_ALREADY_ADDED:
+ handler->PSendSysMessage(LANG_RBAC_ROLE_GRANTED_IN_LIST, command->id, role->GetName().c_str(),
+ command->realmId, command->rbac->GetId(), command->rbac->GetName().c_str());
+ break;
+ case RBAC_IN_DENIED_LIST:
+ handler->PSendSysMessage(LANG_RBAC_ROLE_GRANTED_IN_DENIED_LIST, command->id, role->GetName().c_str(),
+ command->realmId, command->rbac->GetId(), command->rbac->GetName().c_str());
+ break;
+ case RBAC_OK:
+ handler->PSendSysMessage(LANG_RBAC_ROLE_GRANTED, command->id, role->GetName().c_str(),
+ command->realmId, command->rbac->GetId(), command->rbac->GetName().c_str());
+ break;
+ case RBAC_ID_DOES_NOT_EXISTS:
+ handler->PSendSysMessage(LANG_RBAC_WRONG_PARAMETER_ID, command->id);
+ break;
+ default:
+ break;
+ }
+
+ if (command->needDelete)
+ delete command;
+
+ return true;
+ }
+
+ static bool HandleRBACRoleDenyCommand(ChatHandler* handler, char const* args)
+ {
+ RBACCommandData* command = ReadParams(handler, args);
+
+ if (!command)
+ {
+ handler->SetSentErrorMessage(true);
+ return false;
+ }
+
+ RBACCommandResult result = command->rbac->DenyRole(command->id, command->realmId);
+ RBACRole const* role = sAccountMgr->GetRBACRole(command->id);
+
+ switch (result)
+ {
+ case RBAC_CANT_ADD_ALREADY_ADDED:
+ handler->PSendSysMessage(LANG_RBAC_ROLE_DENIED_IN_LIST, command->id, role->GetName().c_str(),
+ command->realmId, command->rbac->GetId(), command->rbac->GetName().c_str());
+ break;
+ case RBAC_IN_GRANTED_LIST:
+ handler->PSendSysMessage(LANG_RBAC_ROLE_DENIED_IN_GRANTED_LIST, command->id, role->GetName().c_str(),
+ command->realmId, command->rbac->GetId(), command->rbac->GetName().c_str());
+ break;
+ case RBAC_OK:
+ handler->PSendSysMessage(LANG_RBAC_ROLE_DENIED, command->id, role->GetName().c_str(),
+ command->realmId, command->rbac->GetId(), command->rbac->GetName().c_str());
+ break;
+ case RBAC_ID_DOES_NOT_EXISTS:
+ handler->PSendSysMessage(LANG_RBAC_WRONG_PARAMETER_ID, command->id);
+ break;
+ default:
+ break;
+ }
+
+ if (command->needDelete)
+ delete command;
+
+ return true;
+ }
+
+ static bool HandleRBACRoleRevokeCommand(ChatHandler* handler, char const* args)
+ {
+ RBACCommandData* command = ReadParams(handler, args);
+
+ if (!command)
+ {
+ handler->SetSentErrorMessage(true);
+ return false;
+ }
+
+ RBACCommandResult result = command->rbac->RevokeRole(command->id, command->realmId);
+ RBACRole const* role = sAccountMgr->GetRBACRole(command->id);
+
+ switch (result)
+ {
+ case RBAC_CANT_REVOKE_NOT_IN_LIST:
+ handler->PSendSysMessage(LANG_RBAC_ROLE_REVOKED_NOT_IN_LIST, command->id, role->GetName().c_str(),
+ command->realmId, command->rbac->GetId(), command->rbac->GetName().c_str());
+ break;
+ case RBAC_OK:
+ handler->PSendSysMessage(LANG_RBAC_ROLE_REVOKED, command->id, role->GetName().c_str(),
+ command->realmId, command->rbac->GetId(), command->rbac->GetName().c_str());
+ break;
+ case RBAC_ID_DOES_NOT_EXISTS:
+ handler->PSendSysMessage(LANG_RBAC_WRONG_PARAMETER_ID, command->id);
+ break;
+ default:
+ break;
+ }
+
+ if (command->needDelete)
+ delete command;
+
+ return true;
+ }
+
+ static bool HandleRBACRoleListCommand(ChatHandler* handler, char const* args)
+ {
+ RBACCommandData* command = ReadParams(handler, args, false);
+
+ if (!command)
+ {
+ handler->SetSentErrorMessage(true);
+ return false;
+ }
+
+ handler->PSendSysMessage(LANG_RBAC_ROLE_LIST_HEADER_GRANTED, command->rbac->GetId(), command->rbac->GetName().c_str());
+ RBACGroupContainer const& granted = command->rbac->GetGrantedRoles();
+ if (granted.empty())
+ handler->PSendSysMessage("%s", handler->GetTrinityString(LANG_RBAC_LIST_EMPTY));
+ else
+ {
+ for (RBACRoleContainer::const_iterator it = granted.begin(); it != granted.end(); ++it)
+ {
+ RBACRole const* role = sAccountMgr->GetRBACRole(*it);
+ handler->PSendSysMessage(LANG_RBAC_LIST_ELEMENT, role->GetId(), role->GetName().c_str());
+ }
+ }
+
+ handler->PSendSysMessage(LANG_RBAC_ROLE_LIST_HEADER_DENIED, command->rbac->GetId(), command->rbac->GetName().c_str());
+ RBACGroupContainer const& denied = command->rbac->GetDeniedRoles();
+ if (denied.empty())
+ handler->PSendSysMessage("%s", handler->GetTrinityString(LANG_RBAC_LIST_EMPTY));
+ else
+ {
+ for (RBACRoleContainer::const_iterator it = denied.begin(); it != denied.end(); ++it)
+ {
+ RBACRole const* role = sAccountMgr->GetRBACRole(*it);
+ handler->PSendSysMessage(LANG_RBAC_LIST_ELEMENT, role->GetId(), role->GetName().c_str());
+ }
+ }
+
+ if (command->needDelete)
+ delete command;
+
+ return true;
+ }
+
+ static bool HandleRBACPermGrantCommand(ChatHandler* handler, char const* args)
+ {
+ RBACCommandData* command = ReadParams(handler, args);
+
+ if (!command)
+ {
+ handler->SetSentErrorMessage(true);
+ return false;
+ }
+
+ RBACCommandResult result = command->rbac->GrantPermission(command->id, command->realmId);
+ RBACPermission const* permission = sAccountMgr->GetRBACPermission(command->id);
+
+ switch (result)
+ {
+ case RBAC_CANT_ADD_ALREADY_ADDED:
+ handler->PSendSysMessage(LANG_RBAC_PERM_GRANTED_IN_LIST, command->id, permission->GetName().c_str(),
+ command->realmId, command->rbac->GetId(), command->rbac->GetName().c_str());
+ break;
+ case RBAC_IN_DENIED_LIST:
+ handler->PSendSysMessage(LANG_RBAC_PERM_GRANTED_IN_DENIED_LIST, command->id, permission->GetName().c_str(),
+ command->realmId, command->rbac->GetId(), command->rbac->GetName().c_str());
+ break;
+ case RBAC_OK:
+ handler->PSendSysMessage(LANG_RBAC_PERM_GRANTED, command->id, permission->GetName().c_str(),
+ command->realmId, command->rbac->GetId(), command->rbac->GetName().c_str());
+ break;
+ case RBAC_ID_DOES_NOT_EXISTS:
+ handler->PSendSysMessage(LANG_RBAC_WRONG_PARAMETER_ID, command->id);
+ break;
+ default:
+ break;
+ }
+
+ if (command->needDelete)
+ delete command;
+
+ return true;
+ }
+
+ static bool HandleRBACPermDenyCommand(ChatHandler* handler, char const* args)
+ {
+ RBACCommandData* command = ReadParams(handler, args);
+
+ if (!command)
+ {
+ handler->SetSentErrorMessage(true);
+ return false;
+ }
+
+ RBACCommandResult result = command->rbac->DenyPermission(command->id, command->realmId);
+ RBACPermission const* permission = sAccountMgr->GetRBACPermission(command->id);
+
+ switch (result)
+ {
+ case RBAC_CANT_ADD_ALREADY_ADDED:
+ handler->PSendSysMessage(LANG_RBAC_PERM_DENIED_IN_LIST, command->id, permission->GetName().c_str(),
+ command->realmId, command->rbac->GetId(), command->rbac->GetName().c_str());
+ break;
+ case RBAC_IN_GRANTED_LIST:
+ handler->PSendSysMessage(LANG_RBAC_PERM_DENIED_IN_GRANTED_LIST, command->id, permission->GetName().c_str(),
+ command->realmId, command->rbac->GetId(), command->rbac->GetName().c_str());
+ break;
+ case RBAC_OK:
+ handler->PSendSysMessage(LANG_RBAC_PERM_DENIED, command->id, permission->GetName().c_str(),
+ command->realmId, command->rbac->GetId(), command->rbac->GetName().c_str());
+ break;
+ case RBAC_ID_DOES_NOT_EXISTS:
+ handler->PSendSysMessage(LANG_RBAC_WRONG_PARAMETER_ID, command->id);
+ break;
+ default:
+ break;
+ }
+
+ if (command->needDelete)
+ delete command;
+
+ return true;
+ }
+
+ static bool HandleRBACPermRevokeCommand(ChatHandler* handler, char const* args)
+ {
+ RBACCommandData* command = ReadParams(handler, args);
+
+ if (!command)
+ {
+ handler->SetSentErrorMessage(true);
+ return false;
+ }
+
+ RBACCommandResult result = command->rbac->RevokePermission(command->id, command->realmId);
+ RBACPermission const* permission = sAccountMgr->GetRBACPermission(command->id);
+
+ switch (result)
+ {
+ case RBAC_CANT_REVOKE_NOT_IN_LIST:
+ handler->PSendSysMessage(LANG_RBAC_PERM_REVOKED_NOT_IN_LIST, command->id, permission->GetName().c_str(),
+ command->realmId, command->rbac->GetId(), command->rbac->GetName().c_str());
+ break;
+ case RBAC_OK:
+ handler->PSendSysMessage(LANG_RBAC_PERM_REVOKED, command->id, permission->GetName().c_str(),
+ command->realmId, command->rbac->GetId(), command->rbac->GetName().c_str());
+ break;
+ case RBAC_ID_DOES_NOT_EXISTS:
+ handler->PSendSysMessage(LANG_RBAC_WRONG_PARAMETER_ID, command->id);
+ break;
+ default:
+ break;
+ }
+
+ if (command->needDelete)
+ delete command;
+
+ return true;
+ }
+
+ static bool HandleRBACPermListCommand(ChatHandler* handler, char const* args)
+ {
+ RBACCommandData* command = ReadParams(handler, args, false);
+
+ if (!command)
+ {
+ handler->SetSentErrorMessage(true);
+ return false;
+ }
+
+ handler->PSendSysMessage(LANG_RBAC_PERM_LIST_HEADER_GRANTED, command->rbac->GetId(), command->rbac->GetName().c_str());
+ RBACPermissionContainer const& granted = command->rbac->GetGrantedPermissions();
+ if (!granted.any())
+ handler->PSendSysMessage("%s", handler->GetTrinityString(LANG_RBAC_LIST_EMPTY));
+ else
+ {
+ for (uint32 i = 0; i < RBAC_PERM_MAX; ++i)
+ if (granted.test(i))
+ {
+ RBACPermission const* permission = sAccountMgr->GetRBACPermission(i);
+ handler->PSendSysMessage(LANG_RBAC_LIST_ELEMENT, permission->GetId(), permission->GetName().c_str());
+ }
+ }
+
+ handler->PSendSysMessage(LANG_RBAC_PERM_LIST_HEADER_DENIED, command->rbac->GetId(), command->rbac->GetName().c_str());
+ RBACPermissionContainer const& denied = command->rbac->GetDeniedPermissions();
+ if (!denied.any())
+ handler->PSendSysMessage("%s", handler->GetTrinityString(LANG_RBAC_LIST_EMPTY));
+ else
+ {
+ for (uint32 i = 0; i < RBAC_PERM_MAX; ++i)
+ if (denied.test(i))
+ {
+ RBACPermission const* permission = sAccountMgr->GetRBACPermission(i);
+ handler->PSendSysMessage(LANG_RBAC_LIST_ELEMENT, permission->GetId(), permission->GetName().c_str());
+ }
+ }
+
+ if (command->needDelete)
+ delete command;
+
+ return true;
+ }
+
+ static bool HandleRBACAccountPermissionCommand(ChatHandler* handler, char const* args)
+ {
+ RBACCommandData* command = ReadParams(handler, args, false);
+
+ if (!command)
+ {
+ handler->SetSentErrorMessage(true);
+ return false;
+ }
+
+ handler->PSendSysMessage(LANG_RBAC_PERM_LIST_GLOBAL, command->rbac->GetId(), command->rbac->GetName().c_str());
+ RBACPermissionContainer const& permissions = command->rbac->GetPermissions();
+ if (!permissions.any())
+ handler->PSendSysMessage("%s", handler->GetTrinityString(LANG_RBAC_LIST_EMPTY));
+ else
+ {
+ for (uint32 i = 0; i < RBAC_PERM_MAX; ++i)
+ if (permissions.test(i))
+ {
+ RBACPermission const* permission = sAccountMgr->GetRBACPermission(i);
+ handler->PSendSysMessage(LANG_RBAC_LIST_ELEMENT, permission->GetId(), permission->GetName().c_str());
+ }
+ }
+
+ if (command->needDelete)
+ delete command;
+
+ return true;
+ }
+
+ static bool HandleRBACListGroupsCommand(ChatHandler* handler, char const* args)
+ {
+ uint32 id = 0;
+ if (char* param1 = strtok((char*)args, " "))
+ id = atoi(param1);
+
+ if (!id)
+ {
+ RBACGroupsContainer const& groups = sAccountMgr->GetRBACGroupList();
+ handler->PSendSysMessage("%s", handler->GetTrinityString(LANG_RBAC_LIST_GROUPS_HEADER));
+ for (RBACGroupsContainer::const_iterator it = groups.begin(); it != groups.end(); ++it)
+ {
+ RBACGroup const* group = it->second;
+ handler->PSendSysMessage(LANG_RBAC_LIST_ELEMENT, group->GetId(), group->GetName().c_str());
+ }
+ }
+ else
+ {
+ RBACGroup const* group = sAccountMgr->GetRBACGroup(id);
+ if (!group)
+ {
+ handler->PSendSysMessage(LANG_RBAC_WRONG_PARAMETER_ID, id);
+ handler->SetSentErrorMessage(true);
+ return false;
+ }
+
+ handler->PSendSysMessage("%s", handler->GetTrinityString(LANG_RBAC_LIST_GROUPS_HEADER));
+ handler->PSendSysMessage(LANG_RBAC_LIST_ELEMENT, group->GetId(), group->GetName().c_str());
+ handler->PSendSysMessage("%s", handler->GetTrinityString(LANG_RBAC_LIST_ROLES_HEADER));
+ RBACRoleContainer const& roles = group->GetRoles();
+ if (roles.empty())
+ handler->PSendSysMessage("%s", handler->GetTrinityString(LANG_RBAC_LIST_EMPTY));
+ else
+ {
+ for (RBACRoleContainer::const_iterator it = roles.begin(); it != roles.end(); ++it)
+ {
+ RBACRole const* role = sAccountMgr->GetRBACRole(*it);
+ handler->PSendSysMessage(LANG_RBAC_LIST_ELEMENT, role->GetId(), role->GetName().c_str());
+ }
+ }
+ }
+
+ return true;
+ }
+
+ static bool HandleRBACListRolesCommand(ChatHandler* handler, char const* args)
+ {
+ uint32 id = 0;
+ if (char* param1 = strtok((char*)args, " "))
+ id = atoi(param1);
+
+ if (!id)
+ {
+ RBACRolesContainer const& roles = sAccountMgr->GetRBACRoleList();
+ handler->PSendSysMessage("%s", handler->GetTrinityString(LANG_RBAC_LIST_ROLES_HEADER));
+ for (RBACRolesContainer::const_iterator it = roles.begin(); it != roles.end(); ++it)
+ {
+ RBACRole const* role = it->second;
+ handler->PSendSysMessage(LANG_RBAC_LIST_ELEMENT, role->GetId(), role->GetName().c_str());
+ }
+ }
+ else
+ {
+ RBACRole const* role = sAccountMgr->GetRBACRole(id);
+ if (!role)
+ {
+ handler->PSendSysMessage(LANG_RBAC_WRONG_PARAMETER_ID, id);
+ handler->SetSentErrorMessage(true);
+ return false;
+ }
+
+ handler->PSendSysMessage("%s", handler->GetTrinityString(LANG_RBAC_LIST_ROLES_HEADER));
+ handler->PSendSysMessage(LANG_RBAC_LIST_ELEMENT, role->GetId(), role->GetName().c_str());
+ handler->PSendSysMessage("%s", handler->GetTrinityString(LANG_RBAC_LIST_PERMISSIONS_HEADER));
+ RBACPermissionContainer const& permissions = role->GetPermissions();
+ if (!permissions.any())
+ handler->PSendSysMessage("%s", handler->GetTrinityString(LANG_RBAC_LIST_EMPTY));
+ else
+ {
+ for (uint32 i = 0; i < RBAC_PERM_MAX; ++i)
+ if (permissions.test(i))
+ {
+ RBACPermission const* permission = sAccountMgr->GetRBACPermission(i);
+ handler->PSendSysMessage(LANG_RBAC_LIST_ELEMENT, permission->GetId(), permission->GetName().c_str());
+ }
+ }
+ }
+
+ return true;
+ }
+
+ static bool HandleRBACListPermissionsCommand(ChatHandler* handler, char const* args)
+ {
+ uint32 id = 0;
+ if (char* param1 = strtok((char*)args, " "))
+ id = atoi(param1);
+
+ if (!id)
+ {
+ RBACPermissionsContainer const& permissions = sAccountMgr->GetRBACPermissionList();
+ handler->PSendSysMessage("%s", handler->GetTrinityString(LANG_RBAC_LIST_PERMISSIONS_HEADER));
+ for (RBACPermissionsContainer::const_iterator it = permissions.begin(); it != permissions.end(); ++it)
+ {
+ RBACPermission const* permission = it->second;
+ handler->PSendSysMessage(LANG_RBAC_LIST_ELEMENT, permission->GetId(), permission->GetName().c_str());
+ }
+ }
+ else
+ {
+ RBACPermission const* permission = sAccountMgr->GetRBACPermission(id);
+ if (!permission)
+ {
+ handler->PSendSysMessage(LANG_RBAC_WRONG_PARAMETER_ID, id);
+ handler->SetSentErrorMessage(true);
+ return false;
+ }
+
+ handler->PSendSysMessage("%s", handler->GetTrinityString(LANG_RBAC_LIST_PERMISSIONS_HEADER));
+ handler->PSendSysMessage(LANG_RBAC_LIST_ELEMENT, permission->GetId(), permission->GetName().c_str());
+ }
+
+ return true;
+ }
+};
+
+void AddSC_rbac_commandscript()
+{
+ new rbac_commandscript();
+}
diff --git a/src/server/scripts/Commands/cs_reload.cpp b/src/server/scripts/Commands/cs_reload.cpp index 43c2001fbf7..7aee1139868 100644 --- a/src/server/scripts/Commands/cs_reload.cpp +++ b/src/server/scripts/Commands/cs_reload.cpp @@ -22,6 +22,7 @@ Comment: All reload related commands Category: commandscripts EndScriptData */ +#include "AccountMgr.h" #include "AchievementMgr.h" #include "AuctionHouseMgr.h" #include "Chat.h" @@ -86,6 +87,7 @@ public: { "creature_loot_template", SEC_ADMINISTRATOR, true, &HandleReloadLootTemplatesCreatureCommand, "", NULL }, { "creature_onkill_reputation", SEC_ADMINISTRATOR, true, &HandleReloadOnKillReputationCommand, "", NULL }, { "creature_questrelation", SEC_ADMINISTRATOR, true, &HandleReloadCreatureQuestRelationsCommand, "", NULL }, + { "creature_summon_groups", SEC_ADMINISTRATOR, true, &HandleReloadCreatureSummonGroupsCommand, "", NULL }, { "creature_template", SEC_ADMINISTRATOR, true, &HandleReloadCreatureTemplateCommand, "", NULL }, //{ "db_script_string", SEC_ADMINISTRATOR, true, &HandleReloadDbScriptStringCommand, "", NULL }, { "disables", SEC_ADMINISTRATOR, true, &HandleReloadDisablesCommand, "", NULL }, @@ -127,6 +129,7 @@ public: { "prospecting_loot_template", SEC_ADMINISTRATOR, true, &HandleReloadLootTemplatesProspectingCommand, "", NULL }, { "quest_poi", SEC_ADMINISTRATOR, true, &HandleReloadQuestPOICommand, "", NULL }, { "quest_template", SEC_ADMINISTRATOR, true, &HandleReloadQuestTemplateCommand, "", NULL }, + { "rbac", SEC_ADMINISTRATOR, true, &HandleReloadRBACCommand, "", NULL }, { "reference_loot_template", SEC_ADMINISTRATOR, true, &HandleReloadLootTemplatesReferenceCommand, "", NULL }, { "reserved_name", SEC_ADMINISTRATOR, true, &HandleReloadReservedNameCommand, "", NULL }, { "reputation_reward_rate", SEC_ADMINISTRATOR, true, &HandleReloadReputationRewardRateCommand, "", NULL }, @@ -195,6 +198,8 @@ public: HandleReloadTrinityStringCommand(handler, ""); HandleReloadGameTeleCommand(handler, ""); + HandleReloadCreatureSummonGroupsCommand(handler, ""); + HandleReloadVehicleAccessoryCommand(handler, ""); HandleReloadVehicleTemplateAccessoryCommand(handler, ""); @@ -397,6 +402,14 @@ public: return true; } + static bool HandleReloadCreatureSummonGroupsCommand(ChatHandler* handler, const char* /*args*/) + { + sLog->outInfo(LOG_FILTER_GENERAL, "Reloading creature summon groups..."); + sObjectMgr->LoadTempSummons(); + handler->SendGlobalGMSysMessage("DB table `creature_summon_groups` reloaded."); + return true; + } + static bool HandleReloadCreatureTemplateCommand(ChatHandler* handler, const char* args) { if (!*args) @@ -508,10 +521,9 @@ public: cInfo->questItems[5] = fields[78].GetUInt32(); cInfo->movementId = fields[79].GetUInt32(); cInfo->RegenHealth = fields[80].GetBool(); - cInfo->equipmentId = fields[81].GetUInt32(); - cInfo->MechanicImmuneMask = fields[82].GetUInt32(); - cInfo->flags_extra = fields[83].GetUInt32(); - cInfo->ScriptID = sObjectMgr->GetScriptId(fields[84].GetCString()); + cInfo->MechanicImmuneMask = fields[81].GetUInt32(); + cInfo->flags_extra = fields[82].GetUInt32(); + cInfo->ScriptID = sObjectMgr->GetScriptId(fields[83].GetCString()); sObjectMgr->CheckCreatureTemplate(cInfo); } @@ -1232,6 +1244,15 @@ public: handler->SendGlobalGMSysMessage("Vehicle template accessories reloaded."); return true; } + + static bool HandleReloadRBACCommand(ChatHandler* handler, const char* /*args*/) + { + sLog->outInfo(LOG_FILTER_GENERAL, "Reloading RBAC tables..."); + sAccountMgr->LoadRBAC(); + sWorld->ReloadRBAC(); + handler->SendGlobalGMSysMessage("RBAC data reloaded."); + return true; + } }; void AddSC_reload_commandscript() diff --git a/src/server/scripts/Commands/cs_ticket.cpp b/src/server/scripts/Commands/cs_ticket.cpp index 3215b533bce..95cbf70e1f8 100644 --- a/src/server/scripts/Commands/cs_ticket.cpp +++ b/src/server/scripts/Commands/cs_ticket.cpp @@ -95,13 +95,10 @@ public: return true; } - // Get target information - uint64 targetGuid = sObjectMgr->GetPlayerGUIDByName(target.c_str()); - uint64 targetAccountId = sObjectMgr->GetPlayerAccountIdByGUID(targetGuid); - uint32 targetGmLevel = AccountMgr::GetSecurity(targetAccountId, realmID); - + uint64 targetGuid = sObjectMgr->GetPlayerGUIDByName(target); + uint32 accountId = sObjectMgr->GetPlayerAccountIdByGUID(targetGuid); // Target must exist and have administrative rights - if (!targetGuid || AccountMgr::IsPlayerAccount(targetGmLevel)) + if (!AccountMgr::HasPermission(accountId, RBAC_PERM_COMMANDS_BE_ASSIGNED_TICKET, realmID)) { handler->SendSysMessage(LANG_COMMAND_TICKETASSIGNERROR_A); return true; @@ -125,7 +122,7 @@ public: // Assign ticket SQLTransaction trans = SQLTransaction(NULL); - ticket->SetAssignedTo(targetGuid, AccountMgr::IsAdminAccount(targetGmLevel)); + ticket->SetAssignedTo(targetGuid, AccountMgr::IsAdminAccount(AccountMgr::GetSecurity(accountId, realmID))); ticket->SaveToDB(trans); sTicketMgr->UpdateLastChange(); @@ -386,12 +383,13 @@ public: return true; } + std::string assignedTo = ticket->GetAssignedToName(); // copy assignedto name because we need it after the ticket has been unnassigned SQLTransaction trans = SQLTransaction(NULL); ticket->SetUnassigned(); ticket->SaveToDB(trans); sTicketMgr->UpdateLastChange(); - std::string msg = ticket->FormatMessageString(*handler, NULL, ticket->GetAssignedToName().c_str(), + std::string msg = ticket->FormatMessageString(*handler, NULL, assignedTo.c_str(), handler->GetSession() ? handler->GetSession()->GetPlayer()->GetName().c_str() : "Console", NULL); handler->SendGlobalGMSysMessage(msg.c_str()); diff --git a/src/server/scripts/Commands/cs_wp.cpp b/src/server/scripts/Commands/cs_wp.cpp index 87b12021212..bb48e94f744 100644 --- a/src/server/scripts/Commands/cs_wp.cpp +++ b/src/server/scripts/Commands/cs_wp.cpp @@ -700,7 +700,7 @@ public: wpCreature2->SaveToDB(map->GetId(), (1 << map->GetSpawnMode()), chr->GetPhaseMaskForSpawn()); // To call _LoadGoods(); _LoadQuests(); CreateTrainerSpells(); - //TODO: Should we first use "Create" then use "LoadFromDB"? + /// @todo Should we first use "Create" then use "LoadFromDB"? if (!wpCreature2->LoadCreatureFromDB(wpCreature2->GetDBTableGUIDLow(), map)) { handler->PSendSysMessage(LANG_WAYPOINT_VP_NOTCREATED, VISUAL_WAYPOINT); diff --git a/src/server/scripts/EasternKingdoms/AlteracValley/alterac_valley.cpp b/src/server/scripts/EasternKingdoms/AlteracValley/alterac_valley.cpp index 809bd2440d7..d301e702174 100644 --- a/src/server/scripts/EasternKingdoms/AlteracValley/alterac_valley.cpp +++ b/src/server/scripts/EasternKingdoms/AlteracValley/alterac_valley.cpp @@ -104,7 +104,7 @@ class mob_av_marshal_or_warmaster : public CreatureScript Reset(); } - void UpdateAI(uint32 const diff) + void UpdateAI(uint32 diff) { // I have a feeling this isn't blizzlike, but owell, I'm only passing by and cleaning up. if (!_hasAura) diff --git a/src/server/scripts/EasternKingdoms/AlteracValley/boss_balinda.cpp b/src/server/scripts/EasternKingdoms/AlteracValley/boss_balinda.cpp index 5622e91cd73..6dec1796500 100644 --- a/src/server/scripts/EasternKingdoms/AlteracValley/boss_balinda.cpp +++ b/src/server/scripts/EasternKingdoms/AlteracValley/boss_balinda.cpp @@ -62,7 +62,7 @@ public: resetTimer = 5 * IN_MILLISECONDS; } - void UpdateAI(const uint32 diff) + void UpdateAI(uint32 diff) { if (!UpdateVictim()) return; @@ -145,7 +145,7 @@ public: summons.DespawnAll(); } - void UpdateAI(const uint32 diff) + void UpdateAI(uint32 diff) { if (!UpdateVictim()) return; diff --git a/src/server/scripts/EasternKingdoms/AlteracValley/boss_drekthar.cpp b/src/server/scripts/EasternKingdoms/AlteracValley/boss_drekthar.cpp index 6e2738d79ca..745c310d35c 100644 --- a/src/server/scripts/EasternKingdoms/AlteracValley/boss_drekthar.cpp +++ b/src/server/scripts/EasternKingdoms/AlteracValley/boss_drekthar.cpp @@ -75,7 +75,7 @@ public: Talk(YELL_RESPAWN); } - void UpdateAI(const uint32 diff) + void UpdateAI(uint32 diff) { if (!UpdateVictim()) return; diff --git a/src/server/scripts/EasternKingdoms/AlteracValley/boss_galvangar.cpp b/src/server/scripts/EasternKingdoms/AlteracValley/boss_galvangar.cpp index fea8573d6f8..2cf7d7cafef 100644 --- a/src/server/scripts/EasternKingdoms/AlteracValley/boss_galvangar.cpp +++ b/src/server/scripts/EasternKingdoms/AlteracValley/boss_galvangar.cpp @@ -69,7 +69,7 @@ public: Reset(); } - void UpdateAI(const uint32 diff) + void UpdateAI(uint32 diff) { if (!UpdateVictim()) return; diff --git a/src/server/scripts/EasternKingdoms/AlteracValley/boss_vanndar.cpp b/src/server/scripts/EasternKingdoms/AlteracValley/boss_vanndar.cpp index 732bbc6f1ba..6939890a702 100644 --- a/src/server/scripts/EasternKingdoms/AlteracValley/boss_vanndar.cpp +++ b/src/server/scripts/EasternKingdoms/AlteracValley/boss_vanndar.cpp @@ -64,7 +64,7 @@ public: Talk(YELL_AGGRO); } - void UpdateAI(const uint32 diff) + void UpdateAI(uint32 diff) { if (!UpdateVictim()) return; diff --git a/src/server/scripts/EasternKingdoms/BlackrockDepths/blackrock_depths.cpp b/src/server/scripts/EasternKingdoms/BlackrockDepths/blackrock_depths.cpp index 071e0c4dd19..0cbeec50f98 100644 --- a/src/server/scripts/EasternKingdoms/BlackrockDepths/blackrock_depths.cpp +++ b/src/server/scripts/EasternKingdoms/BlackrockDepths/blackrock_depths.cpp @@ -109,7 +109,7 @@ enum GrimstoneTexts SAY_TEXT6 = 5 }; -//TODO: implement quest part of event (different end boss) +/// @todo implement quest part of event (different end boss) class npc_grimstone : public CreatureScript { public: @@ -160,7 +160,7 @@ public: CanWalk = false; } - //TODO: move them to center + /// @todo move them to center void SummonRingMob() { if (Creature* tmp = me->SummonCreature(RingMob[MobSpawnId], 608.960f, -235.322f, -53.907f, 1.857f, TEMPSUMMON_DEAD_DESPAWN, 0)) @@ -172,7 +172,7 @@ public: MobDeath_Timer = 2500; } - //TODO: move them to center + /// @todo move them to center void SummonRingBoss() { if (Creature* tmp = me->SummonCreature(RingBoss[rand()%6], 644.300f, -175.989f, -53.739f, 3.418f, TEMPSUMMON_DEAD_DESPAWN, 0)) @@ -222,7 +222,7 @@ public: instance->HandleGameObject(instance->GetData64(id), open); } - void UpdateAI(const uint32 diff) + void UpdateAI(uint32 diff) { if (!instance) return; @@ -372,7 +372,7 @@ public: MightyBlow_Timer = 15000; } - void UpdateAI(const uint32 diff) + void UpdateAI(uint32 diff) { //Return since we have no target if (!UpdateVictim()) @@ -648,7 +648,7 @@ public: } } - void UpdateAI(const uint32 diff) + void UpdateAI(uint32 diff) { if (instance->GetData(DATA_QUEST_JAIL_BREAK) == ENCOUNTER_STATE_NOT_STARTED) return; if ((instance->GetData(DATA_QUEST_JAIL_BREAK) == ENCOUNTER_STATE_IN_PROGRESS || instance->GetData(DATA_QUEST_JAIL_BREAK) == ENCOUNTER_STATE_FAILED || instance->GetData(DATA_QUEST_JAIL_BREAK) == ENCOUNTER_STATE_ENDED)&& instance->GetData(DATA_DUGHAL) == ENCOUNTER_STATE_ENDED) @@ -807,7 +807,7 @@ public: instance->SetData(DATA_QUEST_JAIL_BREAK, ENCOUNTER_STATE_FAILED); } - void UpdateAI(const uint32 diff) + void UpdateAI(uint32 diff) { if (instance->GetData(DATA_QUEST_JAIL_BREAK) == ENCOUNTER_STATE_NOT_STARTED) return; @@ -1017,7 +1017,7 @@ public: instance->SetData(DATA_QUEST_JAIL_BREAK, ENCOUNTER_STATE_FAILED); } - void UpdateAI(const uint32 diff) + void UpdateAI(uint32 diff) { if (instance->GetData(DATA_QUEST_JAIL_BREAK) == ENCOUNTER_STATE_NOT_STARTED) return; @@ -1151,7 +1151,7 @@ public: } } - void UpdateAI(const uint32 diff) + void UpdateAI(uint32 diff) { if (instance->GetData(DATA_QUEST_JAIL_BREAK) == ENCOUNTER_STATE_NOT_STARTED) return; @@ -1284,7 +1284,7 @@ public: } } - void UpdateAI(const uint32 diff) + void UpdateAI(uint32 diff) { if (!instance) return; diff --git a/src/server/scripts/EasternKingdoms/BlackrockDepths/boss_ambassador_flamelash.cpp b/src/server/scripts/EasternKingdoms/BlackrockDepths/boss_ambassador_flamelash.cpp index 99619a89bf3..c5d93ad0c85 100644 --- a/src/server/scripts/EasternKingdoms/BlackrockDepths/boss_ambassador_flamelash.cpp +++ b/src/server/scripts/EasternKingdoms/BlackrockDepths/boss_ambassador_flamelash.cpp @@ -55,7 +55,7 @@ public: Spirit->AI()->AttackStart(victim); } - void UpdateAI(const uint32 diff) + void UpdateAI(uint32 diff) { //Return since we have no target if (!UpdateVictim()) diff --git a/src/server/scripts/EasternKingdoms/BlackrockDepths/boss_anubshiah.cpp b/src/server/scripts/EasternKingdoms/BlackrockDepths/boss_anubshiah.cpp index 424489fc703..bb4de5b347a 100644 --- a/src/server/scripts/EasternKingdoms/BlackrockDepths/boss_anubshiah.cpp +++ b/src/server/scripts/EasternKingdoms/BlackrockDepths/boss_anubshiah.cpp @@ -59,7 +59,7 @@ public: void EnterCombat(Unit* /*who*/) {} - void UpdateAI(const uint32 diff) + void UpdateAI(uint32 diff) { //Return since we have no target if (!UpdateVictim()) diff --git a/src/server/scripts/EasternKingdoms/BlackrockDepths/boss_emperor_dagran_thaurissan.cpp b/src/server/scripts/EasternKingdoms/BlackrockDepths/boss_emperor_dagran_thaurissan.cpp index 3a7baff0196..aaf0adc57c4 100644 --- a/src/server/scripts/EasternKingdoms/BlackrockDepths/boss_emperor_dagran_thaurissan.cpp +++ b/src/server/scripts/EasternKingdoms/BlackrockDepths/boss_emperor_dagran_thaurissan.cpp @@ -81,7 +81,7 @@ public: } } - void UpdateAI(const uint32 diff) + void UpdateAI(uint32 diff) { //Return since we have no target if (!UpdateVictim()) diff --git a/src/server/scripts/EasternKingdoms/BlackrockDepths/boss_general_angerforge.cpp b/src/server/scripts/EasternKingdoms/BlackrockDepths/boss_general_angerforge.cpp index 8c2c590e3e5..bd5a06bf46c 100644 --- a/src/server/scripts/EasternKingdoms/BlackrockDepths/boss_general_angerforge.cpp +++ b/src/server/scripts/EasternKingdoms/BlackrockDepths/boss_general_angerforge.cpp @@ -69,7 +69,7 @@ public: SummonedMedic->AI()->AttackStart(victim); } - void UpdateAI(const uint32 diff) + void UpdateAI(uint32 diff) { //Return since we have no target if (!UpdateVictim()) diff --git a/src/server/scripts/EasternKingdoms/BlackrockDepths/boss_gorosh_the_dervish.cpp b/src/server/scripts/EasternKingdoms/BlackrockDepths/boss_gorosh_the_dervish.cpp index 4f876f41907..02c00b4958c 100644 --- a/src/server/scripts/EasternKingdoms/BlackrockDepths/boss_gorosh_the_dervish.cpp +++ b/src/server/scripts/EasternKingdoms/BlackrockDepths/boss_gorosh_the_dervish.cpp @@ -52,7 +52,7 @@ public: { } - void UpdateAI(const uint32 diff) + void UpdateAI(uint32 diff) { //Return since we have no target if (!UpdateVictim()) diff --git a/src/server/scripts/EasternKingdoms/BlackrockDepths/boss_grizzle.cpp b/src/server/scripts/EasternKingdoms/BlackrockDepths/boss_grizzle.cpp index 51fddc0f71f..a0ab6f9939c 100644 --- a/src/server/scripts/EasternKingdoms/BlackrockDepths/boss_grizzle.cpp +++ b/src/server/scripts/EasternKingdoms/BlackrockDepths/boss_grizzle.cpp @@ -51,7 +51,7 @@ public: void EnterCombat(Unit* /*who*/) {} - void UpdateAI(const uint32 diff) + void UpdateAI(uint32 diff) { //Return since we have no target if (!UpdateVictim()) diff --git a/src/server/scripts/EasternKingdoms/BlackrockDepths/boss_high_interrogator_gerstahn.cpp b/src/server/scripts/EasternKingdoms/BlackrockDepths/boss_high_interrogator_gerstahn.cpp index 0631a4308df..a901bc3d5e3 100644 --- a/src/server/scripts/EasternKingdoms/BlackrockDepths/boss_high_interrogator_gerstahn.cpp +++ b/src/server/scripts/EasternKingdoms/BlackrockDepths/boss_high_interrogator_gerstahn.cpp @@ -56,7 +56,7 @@ public: void EnterCombat(Unit* /*who*/) {} - void UpdateAI(const uint32 diff) + void UpdateAI(uint32 diff) { //Return since we have no target if (!UpdateVictim()) diff --git a/src/server/scripts/EasternKingdoms/BlackrockDepths/boss_magmus.cpp b/src/server/scripts/EasternKingdoms/BlackrockDepths/boss_magmus.cpp index fa8a13f1bfd..5c496ed597b 100644 --- a/src/server/scripts/EasternKingdoms/BlackrockDepths/boss_magmus.cpp +++ b/src/server/scripts/EasternKingdoms/BlackrockDepths/boss_magmus.cpp @@ -55,7 +55,7 @@ public: void EnterCombat(Unit* /*who*/) {} - void UpdateAI(const uint32 diff) + void UpdateAI(uint32 diff) { //Return since we have no target if (!UpdateVictim()) diff --git a/src/server/scripts/EasternKingdoms/BlackrockDepths/boss_moira_bronzebeard.cpp b/src/server/scripts/EasternKingdoms/BlackrockDepths/boss_moira_bronzebeard.cpp index 3142610b346..bb528de9dca 100644 --- a/src/server/scripts/EasternKingdoms/BlackrockDepths/boss_moira_bronzebeard.cpp +++ b/src/server/scripts/EasternKingdoms/BlackrockDepths/boss_moira_bronzebeard.cpp @@ -58,7 +58,7 @@ public: void EnterCombat(Unit* /*who*/) {} - void UpdateAI(const uint32 diff) + void UpdateAI(uint32 diff) { //Return since we have no target if (!UpdateVictim()) diff --git a/src/server/scripts/EasternKingdoms/BlackrockDepths/boss_tomb_of_seven.cpp b/src/server/scripts/EasternKingdoms/BlackrockDepths/boss_tomb_of_seven.cpp index f4e9d561b5e..2767c76a69e 100644 --- a/src/server/scripts/EasternKingdoms/BlackrockDepths/boss_tomb_of_seven.cpp +++ b/src/server/scripts/EasternKingdoms/BlackrockDepths/boss_tomb_of_seven.cpp @@ -202,7 +202,7 @@ public: instance->SetData(DATA_GHOSTKILL, 1); } - void UpdateAI(const uint32 diff) + void UpdateAI(uint32 diff) { if (!UpdateVictim()) return; diff --git a/src/server/scripts/EasternKingdoms/BlackrockSpire/boss_drakkisath.cpp b/src/server/scripts/EasternKingdoms/BlackrockSpire/boss_drakkisath.cpp index fa1f79d82e7..7081974195f 100644 --- a/src/server/scripts/EasternKingdoms/BlackrockSpire/boss_drakkisath.cpp +++ b/src/server/scripts/EasternKingdoms/BlackrockSpire/boss_drakkisath.cpp @@ -69,7 +69,7 @@ public: _JustDied(); } - void UpdateAI(const uint32 diff) + void UpdateAI(uint32 diff) { if (!UpdateVictim()) return; diff --git a/src/server/scripts/EasternKingdoms/BlackrockSpire/boss_gyth.cpp b/src/server/scripts/EasternKingdoms/BlackrockSpire/boss_gyth.cpp index cef633ac2d8..667265cdba0 100644 --- a/src/server/scripts/EasternKingdoms/BlackrockSpire/boss_gyth.cpp +++ b/src/server/scripts/EasternKingdoms/BlackrockSpire/boss_gyth.cpp @@ -30,7 +30,7 @@ enum Spells enum Adds { - MODEL_REND_ON_DRAKE = 9723, // TODO: use creature_template 10459 instead of its modelid + MODEL_REND_ON_DRAKE = 9723, /// @todo use creature_template 10459 instead of its modelid NPC_RAGE_TALON_FIRE_TONG = 10372, NPC_CHROMATIC_WHELP = 10442, NPC_CHROMATIC_DRAGONSPAWN = 10447, @@ -92,7 +92,7 @@ public: Summoned->AddThreat(target, 250.0f); } - void UpdateAI(uint32 const diff) + void UpdateAI(uint32 diff) { if (!UpdateVictim()) return; diff --git a/src/server/scripts/EasternKingdoms/BlackrockSpire/boss_halycon.cpp b/src/server/scripts/EasternKingdoms/BlackrockSpire/boss_halycon.cpp index 2f9d39152e3..af0e5110523 100644 --- a/src/server/scripts/EasternKingdoms/BlackrockSpire/boss_halycon.cpp +++ b/src/server/scripts/EasternKingdoms/BlackrockSpire/boss_halycon.cpp @@ -68,7 +68,7 @@ public: _JustDied(); } - void UpdateAI(uint32 const diff) + void UpdateAI(uint32 diff) { if (!UpdateVictim()) return; diff --git a/src/server/scripts/EasternKingdoms/BlackrockSpire/boss_highlord_omokk.cpp b/src/server/scripts/EasternKingdoms/BlackrockSpire/boss_highlord_omokk.cpp index afb6ab75649..082e1f8e79b 100644 --- a/src/server/scripts/EasternKingdoms/BlackrockSpire/boss_highlord_omokk.cpp +++ b/src/server/scripts/EasternKingdoms/BlackrockSpire/boss_highlord_omokk.cpp @@ -78,7 +78,7 @@ public: _JustDied(); } - void UpdateAI(uint32 const diff) + void UpdateAI(uint32 diff) { if (!UpdateVictim()) return; diff --git a/src/server/scripts/EasternKingdoms/BlackrockSpire/boss_mother_smolderweb.cpp b/src/server/scripts/EasternKingdoms/BlackrockSpire/boss_mother_smolderweb.cpp index d67fa7c5caa..fc6d3f7d4db 100644 --- a/src/server/scripts/EasternKingdoms/BlackrockSpire/boss_mother_smolderweb.cpp +++ b/src/server/scripts/EasternKingdoms/BlackrockSpire/boss_mother_smolderweb.cpp @@ -70,7 +70,7 @@ public: DoCast(me, SPELL_SUMMON_SPIRE_SPIDERLING, true); } - void UpdateAI(uint32 const diff) + void UpdateAI(uint32 diff) { if (!UpdateVictim()) return; diff --git a/src/server/scripts/EasternKingdoms/BlackrockSpire/boss_overlord_wyrmthalak.cpp b/src/server/scripts/EasternKingdoms/BlackrockSpire/boss_overlord_wyrmthalak.cpp index ff68462ffb5..09d85a680b8 100644 --- a/src/server/scripts/EasternKingdoms/BlackrockSpire/boss_overlord_wyrmthalak.cpp +++ b/src/server/scripts/EasternKingdoms/BlackrockSpire/boss_overlord_wyrmthalak.cpp @@ -81,7 +81,7 @@ public: _JustDied(); } - void UpdateAI(uint32 const diff) + void UpdateAI(uint32 diff) { if (!UpdateVictim()) return; diff --git a/src/server/scripts/EasternKingdoms/BlackrockSpire/boss_pyroguard_emberseer.cpp b/src/server/scripts/EasternKingdoms/BlackrockSpire/boss_pyroguard_emberseer.cpp index 047ad3f7096..44a27e6938f 100644 --- a/src/server/scripts/EasternKingdoms/BlackrockSpire/boss_pyroguard_emberseer.cpp +++ b/src/server/scripts/EasternKingdoms/BlackrockSpire/boss_pyroguard_emberseer.cpp @@ -66,7 +66,6 @@ public: { if (instance->GetBossState(DATA_PYROGAURD_EMBERSEER) == IN_PROGRESS) OpenDoors(false); - instance->SetBossState(DATA_PYROGAURD_EMBERSEER,NOT_STARTED); // respawn any dead Blackhand Incarcerators DoCast(me, SPELL_ENCAGED_EMBERSEER); //DoCast(me, SPELL_FIRE_SHIELD_TRIGGER); @@ -83,7 +82,6 @@ public: void JustDied(Unit* /*killer*/) { - instance->SetBossState(DATA_PYROGAURD_EMBERSEER,DONE); OpenDoors(true); _JustDied(); } @@ -99,10 +97,9 @@ public: door3->SetGoState(GO_STATE_ACTIVE); } - void UpdateAI(uint32 const diff) + void UpdateAI(uint32 diff) { if (!UpdateVictim()) - return; events.Update(diff); @@ -115,11 +112,11 @@ public: switch (eventId) { case EVENT_FIRENOVA: - DoCast(me->getVictim(), SPELL_FIRENOVA); + DoCastVictim(SPELL_FIRENOVA); events.ScheduleEvent(EVENT_FIRENOVA, 6 * IN_MILLISECONDS); break; case EVENT_FLAMEBUFFET: - DoCast(me->getVictim(), SPELL_FLAMEBUFFET); + DoCastVictim(SPELL_FLAMEBUFFET); events.ScheduleEvent(EVENT_FLAMEBUFFET, 14 * IN_MILLISECONDS); break; case EVENT_PYROBLAST: @@ -129,6 +126,7 @@ public: break; } } + DoMeleeAttackIfReady(); } }; diff --git a/src/server/scripts/EasternKingdoms/BlackrockSpire/boss_quartermaster_zigris.cpp b/src/server/scripts/EasternKingdoms/BlackrockSpire/boss_quartermaster_zigris.cpp index 2f86c009d56..8828fcfe753 100644 --- a/src/server/scripts/EasternKingdoms/BlackrockSpire/boss_quartermaster_zigris.cpp +++ b/src/server/scripts/EasternKingdoms/BlackrockSpire/boss_quartermaster_zigris.cpp @@ -65,7 +65,7 @@ public: _JustDied(); } - void UpdateAI(uint32 const diff) + void UpdateAI(uint32 diff) { if (!UpdateVictim()) return; diff --git a/src/server/scripts/EasternKingdoms/BlackrockSpire/boss_rend_blackhand.cpp b/src/server/scripts/EasternKingdoms/BlackrockSpire/boss_rend_blackhand.cpp index b881f94dda9..b8d9377d7c4 100644 --- a/src/server/scripts/EasternKingdoms/BlackrockSpire/boss_rend_blackhand.cpp +++ b/src/server/scripts/EasternKingdoms/BlackrockSpire/boss_rend_blackhand.cpp @@ -66,7 +66,7 @@ public: _JustDied(); } - void UpdateAI(uint32 const diff) + void UpdateAI(uint32 diff) { if (!UpdateVictim()) return; diff --git a/src/server/scripts/EasternKingdoms/BlackrockSpire/boss_shadow_hunter_voshgajin.cpp b/src/server/scripts/EasternKingdoms/BlackrockSpire/boss_shadow_hunter_voshgajin.cpp index 69ebf33248f..c429931d42b 100644 --- a/src/server/scripts/EasternKingdoms/BlackrockSpire/boss_shadow_hunter_voshgajin.cpp +++ b/src/server/scripts/EasternKingdoms/BlackrockSpire/boss_shadow_hunter_voshgajin.cpp @@ -67,7 +67,7 @@ public: _JustDied(); } - void UpdateAI(uint32 const diff) + void UpdateAI(uint32 diff) { if (!UpdateVictim()) return; diff --git a/src/server/scripts/EasternKingdoms/BlackrockSpire/boss_the_beast.cpp b/src/server/scripts/EasternKingdoms/BlackrockSpire/boss_the_beast.cpp index f8f4f64b618..a32fefeca40 100644 --- a/src/server/scripts/EasternKingdoms/BlackrockSpire/boss_the_beast.cpp +++ b/src/server/scripts/EasternKingdoms/BlackrockSpire/boss_the_beast.cpp @@ -66,7 +66,7 @@ public: _JustDied(); } - void UpdateAI(uint32 const diff) + void UpdateAI(uint32 diff) { if (!UpdateVictim()) return; diff --git a/src/server/scripts/EasternKingdoms/BlackrockSpire/boss_warmaster_voone.cpp b/src/server/scripts/EasternKingdoms/BlackrockSpire/boss_warmaster_voone.cpp index 7d4c7a40d61..056448854dc 100644 --- a/src/server/scripts/EasternKingdoms/BlackrockSpire/boss_warmaster_voone.cpp +++ b/src/server/scripts/EasternKingdoms/BlackrockSpire/boss_warmaster_voone.cpp @@ -75,7 +75,7 @@ public: _JustDied(); } - void UpdateAI(const uint32 diff) + void UpdateAI(uint32 diff) { if (!UpdateVictim()) return; diff --git a/src/server/scripts/EasternKingdoms/BlackrockSpire/instance_blackrock_spire.cpp b/src/server/scripts/EasternKingdoms/BlackrockSpire/instance_blackrock_spire.cpp index 72a5712181e..06ba0036ef3 100644 --- a/src/server/scripts/EasternKingdoms/BlackrockSpire/instance_blackrock_spire.cpp +++ b/src/server/scripts/EasternKingdoms/BlackrockSpire/instance_blackrock_spire.cpp @@ -215,7 +215,8 @@ public: switch (eventId) { case EVENT_PYROGUARD_EMBERSEER: - SetBossState(DATA_PYROGAURD_EMBERSEER,IN_PROGRESS); + if (GetBossState(DATA_PYROGAURD_EMBERSEER) == NOT_STARTED) + SetBossState(DATA_PYROGAURD_EMBERSEER, IN_PROGRESS); break; default: break; diff --git a/src/server/scripts/EasternKingdoms/BlackwingLair/boss_broodlord_lashlayer.cpp b/src/server/scripts/EasternKingdoms/BlackwingLair/boss_broodlord_lashlayer.cpp index 0aeba151385..73afebfa9f3 100644 --- a/src/server/scripts/EasternKingdoms/BlackwingLair/boss_broodlord_lashlayer.cpp +++ b/src/server/scripts/EasternKingdoms/BlackwingLair/boss_broodlord_lashlayer.cpp @@ -32,12 +32,20 @@ enum Say SAY_LEASH = 1, }; +enum Events +{ + EVENT_CLEAVE = 1, + EVENT_MORTAL_STRIKE = 2, + EVENT_BLAST_WAVE = 3, + EVENT_KNOCK_BACK = 4, +}; + enum Spells { SPELL_CLEAVE = 26350, - SPELL_BLASTWAVE = 23331, - SPELL_MORTALSTRIKE = 24573, - SPELL_KNOCKBACK = 25778 + SPELL_BLAST_WAVE = 23331, + SPELL_MORTAL_STRIKE = 24573, + SPELL_KNOCK_BACK = 25778 }; class boss_broodlord : public CreatureScript @@ -54,17 +62,13 @@ public: { boss_broodlordAI(Creature* creature) : ScriptedAI(creature) {} - uint32 Cleave_Timer; - uint32 BlastWave_Timer; - uint32 MortalStrike_Timer; - uint32 KnockBack_Timer; - void Reset() { - Cleave_Timer = 8000; // These times are probably wrong - BlastWave_Timer = 12000; - MortalStrike_Timer = 20000; - KnockBack_Timer = 30000; + // These timers are probably wrong + events.ScheduleEvent(EVENT_CLEAVE, 8000); + events.ScheduleEvent(EVENT_BLAST_WAVE, 12000); + events.ScheduleEvent(EVENT_MORTAL_STRIKE, 20000); + events.ScheduleEvent(EVENT_KNOCK_BACK, 30000); } void EnterCombat(Unit* /*who*/) @@ -73,47 +77,56 @@ public: DoZoneInCombat(); } - void UpdateAI(const uint32 diff) + void UpdateAI(uint32 diff) { if (!UpdateVictim()) return; - //Cleave_Timer - if (Cleave_Timer <= diff) - { - DoCast(me->getVictim(), SPELL_CLEAVE); - Cleave_Timer = 7000; - } else Cleave_Timer -= diff; - - // BlastWave - if (BlastWave_Timer <= diff) - { - DoCast(me->getVictim(), SPELL_BLASTWAVE); - BlastWave_Timer = urand(8000, 16000); - } else BlastWave_Timer -= diff; + if (EnterEvadeIfOutOfCombatArea(diff)) + Talk(SAY_LEASH); - //MortalStrike_Timer - if (MortalStrike_Timer <= diff) - { - DoCast(me->getVictim(), SPELL_MORTALSTRIKE); - MortalStrike_Timer = urand(25000, 35000); - } else MortalStrike_Timer -= diff; + if (me->HasUnitState(UNIT_STATE_CASTING)) + return; - if (KnockBack_Timer <= diff) + while (uint32 eventId = events.ExecuteEvent()) { - DoCast(me->getVictim(), SPELL_KNOCKBACK); - //Drop 50% aggro - if (DoGetThreat(me->getVictim())) - DoModifyThreatPercent(me->getVictim(), -50); - - KnockBack_Timer = urand(15000, 30000); - } else KnockBack_Timer -= diff; + switch (eventId) + { + case EVENT_CLEAVE: + DoCastVictim(SPELL_CLEAVE); + events.ScheduleEvent(EVENT_CLEAVE, 8000); + break; + case EVENT_MORTAL_STRIKE: + DoCastVictim(SPELL_MORTAL_STRIKE); + events.ScheduleEvent(EVENT_MORTAL_STRIKE, 20000); + break; + case EVENT_BLAST_WAVE: + DoCastVictim(SPELL_BLAST_WAVE); + events.ScheduleEvent(EVENT_BLAST_WAVE, 12000); + break; + case EVENT_KNOCK_BACK: + if (Unit* target = me->getVictim()) + { + DoCast(target, SPELL_BLAST_WAVE); + // Drop 50% of threat + if (DoGetThreat(target)) + DoModifyThreatPercent(target, -50); + } + events.ScheduleEvent(EVENT_KNOCK_BACK, 30000); + break; + default: + break; + } + } if (EnterEvadeIfOutOfCombatArea(diff)) Talk(SAY_LEASH); DoMeleeAttackIfReady(); } + + private: + EventMap events; /// @todo: change BWL to instance script and bosses to BossAI }; }; diff --git a/src/server/scripts/EasternKingdoms/BlackwingLair/boss_chromaggus.cpp b/src/server/scripts/EasternKingdoms/BlackwingLair/boss_chromaggus.cpp index 14e4e90337c..c7459ed2f7d 100644 --- a/src/server/scripts/EasternKingdoms/BlackwingLair/boss_chromaggus.cpp +++ b/src/server/scripts/EasternKingdoms/BlackwingLair/boss_chromaggus.cpp @@ -200,7 +200,7 @@ public: void EnterCombat(Unit* /*who*/) {} - void UpdateAI(const uint32 diff) + void UpdateAI(uint32 diff) { if (!UpdateVictim()) return; diff --git a/src/server/scripts/EasternKingdoms/BlackwingLair/boss_ebonroc.cpp b/src/server/scripts/EasternKingdoms/BlackwingLair/boss_ebonroc.cpp index 54c1ba99e8d..d1670171d67 100644 --- a/src/server/scripts/EasternKingdoms/BlackwingLair/boss_ebonroc.cpp +++ b/src/server/scripts/EasternKingdoms/BlackwingLair/boss_ebonroc.cpp @@ -27,9 +27,10 @@ EndScriptData */ #include "ScriptedCreature.h" #define SPELL_SHADOWFLAME 22539 -#define SPELL_WINGBUFFET 18500 +#define SPELL_WINGBUFFET 23339 #define SPELL_SHADOWOFEBONROC 23340 -#define SPELL_HEAL 41386 //Thea Heal spell of his Shadow +#define SPELL_HEAL 41386 //The Heal spell of his Shadow +#define SPELL_THRASH 3391 class boss_ebonroc : public CreatureScript { @@ -49,6 +50,7 @@ public: uint32 WingBuffet_Timer; uint32 ShadowOfEbonroc_Timer; uint32 Heal_Timer; + uint32 Thrash_Timer; void Reset() { @@ -56,6 +58,7 @@ public: WingBuffet_Timer = 30000; ShadowOfEbonroc_Timer = 45000; Heal_Timer = 1000; + Thrash_Timer = 10000; } void EnterCombat(Unit* /*who*/) @@ -63,7 +66,7 @@ public: DoZoneInCombat(); } - void UpdateAI(const uint32 diff) + void UpdateAI(uint32 diff) { if (!UpdateVictim()) return; @@ -71,25 +74,32 @@ public: //Shadowflame Timer if (ShadowFlame_Timer <= diff) { - DoCast(me->getVictim(), SPELL_SHADOWFLAME); + DoCastVictim(SPELL_SHADOWFLAME); ShadowFlame_Timer = urand(12000, 15000); } else ShadowFlame_Timer -= diff; + //Thrash Timer + if (Thrash_Timer <= diff) + { + DoCastVictim(SPELL_THRASH); + Thrash_Timer = urand(10000, 15000); + } else Thrash_Timer -= diff; + //Wing Buffet Timer if (WingBuffet_Timer <= diff) { - DoCast(me->getVictim(), SPELL_WINGBUFFET); + DoCastVictim(SPELL_WINGBUFFET); WingBuffet_Timer = 25000; } else WingBuffet_Timer -= diff; //Shadow of Ebonroc Timer if (ShadowOfEbonroc_Timer <= diff) { - DoCast(me->getVictim(), SPELL_SHADOWOFEBONROC); + DoCastVictim(SPELL_SHADOWOFEBONROC); ShadowOfEbonroc_Timer = urand(25000, 350000); } else ShadowOfEbonroc_Timer -= diff; - if (me->getVictim()->HasAura(SPELL_SHADOWOFEBONROC)) + if (me->getVictim() && me->getVictim()->HasAura(SPELL_SHADOWOFEBONROC)) { if (Heal_Timer <= diff) { diff --git a/src/server/scripts/EasternKingdoms/BlackwingLair/boss_firemaw.cpp b/src/server/scripts/EasternKingdoms/BlackwingLair/boss_firemaw.cpp index 7ca74f4ed4f..3b63d67814e 100644 --- a/src/server/scripts/EasternKingdoms/BlackwingLair/boss_firemaw.cpp +++ b/src/server/scripts/EasternKingdoms/BlackwingLair/boss_firemaw.cpp @@ -60,7 +60,7 @@ public: DoZoneInCombat(); } - void UpdateAI(const uint32 diff) + void UpdateAI(uint32 diff) { if (!UpdateVictim()) return; @@ -68,24 +68,26 @@ public: //ShadowFlame_Timer if (ShadowFlame_Timer <= diff) { - DoCast(me->getVictim(), SPELL_SHADOWFLAME); + DoCastVictim(SPELL_SHADOWFLAME); ShadowFlame_Timer = urand(15000, 18000); } else ShadowFlame_Timer -= diff; //WingBuffet_Timer if (WingBuffet_Timer <= diff) { - DoCast(me->getVictim(), SPELL_WINGBUFFET); - if (DoGetThreat(me->getVictim())) - DoModifyThreatPercent(me->getVictim(), -75); - + if (Unit* target = me->getVictim()) + { + DoCast(target, SPELL_WINGBUFFET); + if (DoGetThreat(target)) + DoModifyThreatPercent(target, -75); + } WingBuffet_Timer = 25000; } else WingBuffet_Timer -= diff; //FlameBuffet_Timer if (FlameBuffet_Timer <= diff) { - DoCast(me->getVictim(), SPELL_FLAMEBUFFET); + DoCastVictim(SPELL_FLAMEBUFFET); FlameBuffet_Timer = 5000; } else FlameBuffet_Timer -= diff; diff --git a/src/server/scripts/EasternKingdoms/BlackwingLair/boss_flamegor.cpp b/src/server/scripts/EasternKingdoms/BlackwingLair/boss_flamegor.cpp index a1659330a6f..f90389bc4eb 100644 --- a/src/server/scripts/EasternKingdoms/BlackwingLair/boss_flamegor.cpp +++ b/src/server/scripts/EasternKingdoms/BlackwingLair/boss_flamegor.cpp @@ -68,7 +68,7 @@ public: DoZoneInCombat(); } - void UpdateAI(const uint32 diff) + void UpdateAI(uint32 diff) { if (!UpdateVictim()) return; @@ -76,17 +76,19 @@ public: //ShadowFlame_Timer if (ShadowFlame_Timer <= diff) { - DoCast(me->getVictim(), SPELL_SHADOWFLAME); + DoCastVictim(SPELL_SHADOWFLAME); ShadowFlame_Timer = urand(15000, 22000); } else ShadowFlame_Timer -= diff; //WingBuffet_Timer if (WingBuffet_Timer <= diff) { - DoCast(me->getVictim(), SPELL_WINGBUFFET); - if (DoGetThreat(me->getVictim())) - DoModifyThreatPercent(me->getVictim(), -75); - + if (Unit* target = me->getVictim()) + { + DoCast(target, SPELL_WINGBUFFET); + if (DoGetThreat(target)) + DoModifyThreatPercent(target, -75); + } WingBuffet_Timer = 25000; } else WingBuffet_Timer -= diff; diff --git a/src/server/scripts/EasternKingdoms/BlackwingLair/boss_nefarian.cpp b/src/server/scripts/EasternKingdoms/BlackwingLair/boss_nefarian.cpp index 5594d826fdf..f96d6c4a562 100644 --- a/src/server/scripts/EasternKingdoms/BlackwingLair/boss_nefarian.cpp +++ b/src/server/scripts/EasternKingdoms/BlackwingLair/boss_nefarian.cpp @@ -123,7 +123,7 @@ public: DoZoneInCombat(); } - void UpdateAI(const uint32 diff) + void UpdateAI(uint32 diff) { if (DespawnTimer <= diff) { diff --git a/src/server/scripts/EasternKingdoms/BlackwingLair/boss_razorgore.cpp b/src/server/scripts/EasternKingdoms/BlackwingLair/boss_razorgore.cpp index b8361da5eb8..ebf6298b79d 100644 --- a/src/server/scripts/EasternKingdoms/BlackwingLair/boss_razorgore.cpp +++ b/src/server/scripts/EasternKingdoms/BlackwingLair/boss_razorgore.cpp @@ -81,7 +81,7 @@ public: Talk(SAY_DEATH); } - void UpdateAI(const uint32 diff) + void UpdateAI(uint32 diff) { if (!UpdateVictim()) return; diff --git a/src/server/scripts/EasternKingdoms/BlackwingLair/boss_vaelastrasz.cpp b/src/server/scripts/EasternKingdoms/BlackwingLair/boss_vaelastrasz.cpp index 45a9eb397eb..e07da353e90 100644 --- a/src/server/scripts/EasternKingdoms/BlackwingLair/boss_vaelastrasz.cpp +++ b/src/server/scripts/EasternKingdoms/BlackwingLair/boss_vaelastrasz.cpp @@ -156,7 +156,7 @@ public: me->ResetPlayerDamageReq(); } - void UpdateAI(const uint32 diff) + void UpdateAI(uint32 diff) { //Speech if (DoingSpeech) diff --git a/src/server/scripts/EasternKingdoms/BlackwingLair/boss_victor_nefarius.cpp b/src/server/scripts/EasternKingdoms/BlackwingLair/boss_victor_nefarius.cpp index 86709e5e6b5..8a781b48e90 100644 --- a/src/server/scripts/EasternKingdoms/BlackwingLair/boss_victor_nefarius.cpp +++ b/src/server/scripts/EasternKingdoms/BlackwingLair/boss_victor_nefarius.cpp @@ -270,7 +270,7 @@ public: } } - void UpdateAI(const uint32 diff) + void UpdateAI(uint32 diff) { if (!UpdateVictim()) return; diff --git a/src/server/scripts/EasternKingdoms/Deadmines/boss_mr_smite.cpp b/src/server/scripts/EasternKingdoms/Deadmines/boss_mr_smite.cpp index eb8fc77717c..060c2e0506f 100644 --- a/src/server/scripts/EasternKingdoms/Deadmines/boss_mr_smite.cpp +++ b/src/server/scripts/EasternKingdoms/Deadmines/boss_mr_smite.cpp @@ -94,7 +94,7 @@ public: return true; } - void UpdateAI(const uint32 uiDiff) + void UpdateAI(uint32 uiDiff) { if (!UpdateVictim()) return; diff --git a/src/server/scripts/EasternKingdoms/Gnomeregan/gnomeregan.cpp b/src/server/scripts/EasternKingdoms/Gnomeregan/gnomeregan.cpp index 6b0d39d7223..558ffaf7135 100644 --- a/src/server/scripts/EasternKingdoms/Gnomeregan/gnomeregan.cpp +++ b/src/server/scripts/EasternKingdoms/Gnomeregan/gnomeregan.cpp @@ -572,7 +572,7 @@ public: CAST_CRE(summon)->AI()->SetData(2, 1); } - void UpdateAI(const uint32 /*diff*/) + void UpdateAI(uint32 /*diff*/) { if (!UpdateVictim()) return; diff --git a/src/server/scripts/EasternKingdoms/Karazhan/boss_curator.cpp b/src/server/scripts/EasternKingdoms/Karazhan/boss_curator.cpp index bcdd1a9671a..9dab7439136 100644 --- a/src/server/scripts/EasternKingdoms/Karazhan/boss_curator.cpp +++ b/src/server/scripts/EasternKingdoms/Karazhan/boss_curator.cpp @@ -95,7 +95,7 @@ public: Talk(SAY_AGGRO); } - void UpdateAI(const uint32 diff) + void UpdateAI(uint32 diff) { if (!UpdateVictim()) return; diff --git a/src/server/scripts/EasternKingdoms/Karazhan/boss_maiden_of_virtue.cpp b/src/server/scripts/EasternKingdoms/Karazhan/boss_maiden_of_virtue.cpp index a431a3e10e7..52d9c697452 100644 --- a/src/server/scripts/EasternKingdoms/Karazhan/boss_maiden_of_virtue.cpp +++ b/src/server/scripts/EasternKingdoms/Karazhan/boss_maiden_of_virtue.cpp @@ -89,7 +89,7 @@ public: Talk(SAY_AGGRO); } - void UpdateAI(const uint32 diff) + void UpdateAI(uint32 diff) { if (!UpdateVictim()) return; diff --git a/src/server/scripts/EasternKingdoms/Karazhan/boss_midnight.cpp b/src/server/scripts/EasternKingdoms/Karazhan/boss_midnight.cpp index 8347e1c114d..19023f70c80 100644 --- a/src/server/scripts/EasternKingdoms/Karazhan/boss_midnight.cpp +++ b/src/server/scripts/EasternKingdoms/Karazhan/boss_midnight.cpp @@ -44,7 +44,7 @@ enum Midnight MOUNTED_DISPLAYID = 16040, - //Attumen (TODO: Use the summoning spell instead of Creature id. It works, but is not convenient for us) + //Attumen (@todo Use the summoning spell instead of Creature id. It works, but is not convenient for us) SUMMON_ATTUMEN = 15550, }; @@ -104,7 +104,7 @@ public: midnight->Kill(midnight); } - void UpdateAI(const uint32 diff); + void UpdateAI(uint32 diff); void SpellHit(Unit* /*source*/, const SpellInfo* spell) { @@ -153,7 +153,7 @@ public: } } - void UpdateAI(const uint32 diff) + void UpdateAI(uint32 diff) { if (!UpdateVictim()) return; @@ -234,7 +234,7 @@ public: }; }; -void boss_attumen::boss_attumenAI::UpdateAI(const uint32 diff) +void boss_attumen::boss_attumenAI::UpdateAI(uint32 diff) { if (ResetTimer) { diff --git a/src/server/scripts/EasternKingdoms/Karazhan/boss_moroes.cpp b/src/server/scripts/EasternKingdoms/Karazhan/boss_moroes.cpp index 5c7c39e3725..f3bc733e722 100644 --- a/src/server/scripts/EasternKingdoms/Karazhan/boss_moroes.cpp +++ b/src/server/scripts/EasternKingdoms/Karazhan/boss_moroes.cpp @@ -228,7 +228,7 @@ public: } } - void UpdateAI(const uint32 diff) + void UpdateAI(uint32 diff) { if (!UpdateVictim()) return; @@ -354,7 +354,7 @@ struct boss_moroes_guestAI : public ScriptedAI return me; } - void UpdateAI(const uint32 /*diff*/) + void UpdateAI(uint32 /*diff*/) { if (instance && !instance->GetData(TYPE_MOROES)) EnterEvadeMode(); @@ -421,7 +421,7 @@ public: boss_moroes_guestAI::Reset(); } - void UpdateAI(const uint32 diff) + void UpdateAI(uint32 diff) { if (!UpdateVictim()) return; @@ -482,7 +482,7 @@ public: boss_moroes_guestAI::Reset(); } - void UpdateAI(const uint32 diff) + void UpdateAI(uint32 diff) { if (!UpdateVictim()) return; @@ -543,7 +543,7 @@ public: boss_moroes_guestAI::Reset(); } - void UpdateAI(const uint32 diff) + void UpdateAI(uint32 diff) { if (!UpdateVictim()) return; @@ -613,7 +613,7 @@ public: boss_moroes_guestAI::Reset(); } - void UpdateAI(const uint32 diff) + void UpdateAI(uint32 diff) { if (!UpdateVictim()) return; @@ -683,7 +683,7 @@ public: boss_moroes_guestAI::Reset(); } - void UpdateAI(const uint32 diff) + void UpdateAI(uint32 diff) { if (!UpdateVictim()) return; @@ -741,7 +741,7 @@ public: boss_moroes_guestAI::Reset(); } - void UpdateAI(const uint32 diff) + void UpdateAI(uint32 diff) { if (!UpdateVictim()) return; diff --git a/src/server/scripts/EasternKingdoms/Karazhan/boss_netherspite.cpp b/src/server/scripts/EasternKingdoms/Karazhan/boss_netherspite.cpp index dd9b97386b4..305e37a72d3 100644 --- a/src/server/scripts/EasternKingdoms/Karazhan/boss_netherspite.cpp +++ b/src/server/scripts/EasternKingdoms/Karazhan/boss_netherspite.cpp @@ -269,7 +269,7 @@ public: DestroyPortals(); } - void UpdateAI(const uint32 diff) + void UpdateAI(uint32 diff) { if (!UpdateVictim()) return; diff --git a/src/server/scripts/EasternKingdoms/Karazhan/boss_nightbane.cpp b/src/server/scripts/EasternKingdoms/Karazhan/boss_nightbane.cpp index 6d9a1f98e93..8165ba5c53b 100644 --- a/src/server/scripts/EasternKingdoms/Karazhan/boss_nightbane.cpp +++ b/src/server/scripts/EasternKingdoms/Karazhan/boss_nightbane.cpp @@ -260,7 +260,7 @@ public: Skeletons = false; } - void UpdateAI(const uint32 diff) + void UpdateAI(uint32 diff) { /* The timer for this was never setup apparently, not sure if the code works properly: if (WaitTimer <= diff) diff --git a/src/server/scripts/EasternKingdoms/Karazhan/boss_prince_malchezaar.cpp b/src/server/scripts/EasternKingdoms/Karazhan/boss_prince_malchezaar.cpp index 3a026d23faa..4ef91b93b43 100644 --- a/src/server/scripts/EasternKingdoms/Karazhan/boss_prince_malchezaar.cpp +++ b/src/server/scripts/EasternKingdoms/Karazhan/boss_prince_malchezaar.cpp @@ -121,7 +121,7 @@ public: void EnterCombat(Unit* /*who*/) {} void MoveInLineOfSight(Unit* /*who*/) {} - void UpdateAI(const uint32 diff) + void UpdateAI(uint32 diff) { if (HellfireTimer) { @@ -386,7 +386,7 @@ public: Talk(SAY_SUMMON); } - void UpdateAI(const uint32 diff) + void UpdateAI(uint32 diff) { if (!UpdateVictim()) return; @@ -603,7 +603,7 @@ public: void netherspite_infernal::netherspite_infernalAI::Cleanup() { - Creature *pMalchezaar = Unit::GetCreature(*me, malchezaar); + Creature* pMalchezaar = Unit::GetCreature(*me, malchezaar); if (pMalchezaar && pMalchezaar->isAlive()) CAST_AI(boss_malchezaar::boss_malchezaarAI, pMalchezaar->AI())->Cleanup(me, point); diff --git a/src/server/scripts/EasternKingdoms/Karazhan/boss_shade_of_aran.cpp b/src/server/scripts/EasternKingdoms/Karazhan/boss_shade_of_aran.cpp index 5bd9e8a0bae..2a349297860 100644 --- a/src/server/scripts/EasternKingdoms/Karazhan/boss_shade_of_aran.cpp +++ b/src/server/scripts/EasternKingdoms/Karazhan/boss_shade_of_aran.cpp @@ -217,7 +217,7 @@ public: } } - void UpdateAI(const uint32 diff) + void UpdateAI(uint32 diff) { if (!UpdateVictim()) return; @@ -531,7 +531,7 @@ public: void EnterCombat(Unit* /*who*/) {} - void UpdateAI(const uint32 diff) + void UpdateAI(uint32 diff) { if (!UpdateVictim()) return; diff --git a/src/server/scripts/EasternKingdoms/Karazhan/boss_terestian_illhoof.cpp b/src/server/scripts/EasternKingdoms/Karazhan/boss_terestian_illhoof.cpp index 75a8c8cf662..fe773a1e3a2 100644 --- a/src/server/scripts/EasternKingdoms/Karazhan/boss_terestian_illhoof.cpp +++ b/src/server/scripts/EasternKingdoms/Karazhan/boss_terestian_illhoof.cpp @@ -111,7 +111,7 @@ public: } else ERROR_INST_DATA(me); } - void UpdateAI(const uint32 diff) + void UpdateAI(uint32 diff) { //Return since we have no target if (!UpdateVictim()) @@ -228,7 +228,7 @@ public: void EnterCombat(Unit* /*who*/) {} - void UpdateAI(const uint32 diff) + void UpdateAI(uint32 diff) { //Return since we have no target if (!UpdateVictim()) @@ -362,7 +362,7 @@ public: instance->SetData(TYPE_TERESTIAN, DONE); } - void UpdateAI(const uint32 diff) + void UpdateAI(uint32 diff) { if (!UpdateVictim()) return; diff --git a/src/server/scripts/EasternKingdoms/Karazhan/bosses_opera.cpp b/src/server/scripts/EasternKingdoms/Karazhan/bosses_opera.cpp index 6cb4e70ee7a..06389fbbf25 100644 --- a/src/server/scripts/EasternKingdoms/Karazhan/bosses_opera.cpp +++ b/src/server/scripts/EasternKingdoms/Karazhan/bosses_opera.cpp @@ -187,7 +187,7 @@ public: ScriptedAI::MoveInLineOfSight(who); } - void UpdateAI(const uint32 diff) + void UpdateAI(uint32 diff) { if (AggroTimer) { @@ -263,7 +263,7 @@ public: } } - void UpdateAI(const uint32 diff) + void UpdateAI(uint32 diff) { if (!UpdateVictim()) return; @@ -373,7 +373,7 @@ public: Talk(SAY_STRAWMAN_SLAY); } - void UpdateAI(const uint32 diff) + void UpdateAI(uint32 diff) { if (AggroTimer) { @@ -478,7 +478,7 @@ public: Talk(SAY_TINHEAD_SLAY); } - void UpdateAI(const uint32 diff) + void UpdateAI(uint32 diff) { if (AggroTimer) { @@ -585,7 +585,7 @@ public: Talk(SAY_ROAR_SLAY); } - void UpdateAI(const uint32 diff) + void UpdateAI(uint32 diff) { if (AggroTimer) { @@ -682,7 +682,7 @@ public: } } - void UpdateAI(const uint32 diff) + void UpdateAI(uint32 diff) { if (!UpdateVictim()) return; @@ -735,7 +735,7 @@ public: { } - void UpdateAI(const uint32 diff) + void UpdateAI(uint32 diff) { if (!me->HasAura(SPELL_KNOCKBACK)) DoCast(me, SPELL_KNOCKBACK, true); @@ -871,7 +871,7 @@ public: } } - void UpdateAI(const uint32 diff) + void UpdateAI(uint32 diff) { if (!UpdateVictim()) return; @@ -1121,7 +1121,7 @@ public: Talk(SAY_JULIANNE_SLAY); } - void UpdateAI(const uint32 diff); + void UpdateAI(uint32 diff); }; }; @@ -1276,7 +1276,7 @@ public: Talk(SAY_ROMULO_SLAY); } - void UpdateAI(const uint32 diff) + void UpdateAI(uint32 diff) { if (!UpdateVictim() || IsFakingDeath) return; @@ -1331,7 +1331,7 @@ public: }; }; -void boss_julianne::boss_julianneAI::UpdateAI(const uint32 diff) +void boss_julianne::boss_julianneAI::UpdateAI(uint32 diff) { if (EntryYellTimer) { diff --git a/src/server/scripts/EasternKingdoms/Karazhan/instance_karazhan.cpp b/src/server/scripts/EasternKingdoms/Karazhan/instance_karazhan.cpp index 28bb17055f9..412fcae76b1 100644 --- a/src/server/scripts/EasternKingdoms/Karazhan/instance_karazhan.cpp +++ b/src/server/scripts/EasternKingdoms/Karazhan/instance_karazhan.cpp @@ -19,7 +19,7 @@ /* ScriptData SDName: Instance_Karazhan SD%Complete: 70 -SDComment: Instance Script for Karazhan to help in various encounters. TODO: GameObject visibility for Opera event. +SDComment: Instance Script for Karazhan to help in various encounters. @todo GameObject visibility for Opera event. SDCategory: Karazhan EndScriptData */ @@ -224,7 +224,7 @@ public: switch (m_uiOperaEvent) { - //TODO: Set Object visibilities for Opera based on performance + /// @todo Set Object visibilities for Opera based on performance case EVENT_OZ: break; diff --git a/src/server/scripts/EasternKingdoms/Karazhan/karazhan.cpp b/src/server/scripts/EasternKingdoms/Karazhan/karazhan.cpp index 7d3b63acb6a..b8525dd0181 100644 --- a/src/server/scripts/EasternKingdoms/Karazhan/karazhan.cpp +++ b/src/server/scripts/EasternKingdoms/Karazhan/karazhan.cpp @@ -266,7 +266,7 @@ public: RaidWiped = false; } - void UpdateAI(const uint32 diff) + void UpdateAI(uint32 diff) { npc_escortAI::UpdateAI(diff); @@ -613,7 +613,7 @@ public: } } - void UpdateAI(const uint32 diff) + void UpdateAI(uint32 diff) { if (YellTimer <= diff) { diff --git a/src/server/scripts/EasternKingdoms/MagistersTerrace/boss_felblood_kaelthas.cpp b/src/server/scripts/EasternKingdoms/MagistersTerrace/boss_felblood_kaelthas.cpp index 5d132cbd34e..308ff45fac5 100644 --- a/src/server/scripts/EasternKingdoms/MagistersTerrace/boss_felblood_kaelthas.cpp +++ b/src/server/scripts/EasternKingdoms/MagistersTerrace/boss_felblood_kaelthas.cpp @@ -134,7 +134,7 @@ public: void Reset() { - // TODO: Timers + /// @todo Timers FireballTimer = 0; PhoenixTimer = 10000; FlameStrikeTimer = 25000; @@ -280,7 +280,7 @@ public: } } - void UpdateAI(const uint32 diff) + void UpdateAI(uint32 diff) { //Return since we have no target if (!UpdateVictim()) @@ -462,7 +462,7 @@ public: void EnterCombat(Unit* /*who*/) {} void MoveInLineOfSight(Unit* /*who*/) {} - void UpdateAI(const uint32 diff) + void UpdateAI(uint32 diff) { if (FlameStrikeTimer <= diff) { @@ -548,7 +548,7 @@ public: me->SummonCreature(CREATURE_PHOENIX_EGG, 0.0f, 0.0f, 0.0f, 0.0f, TEMPSUMMON_TIMED_OR_CORPSE_DESPAWN, 45000); } - void UpdateAI(const uint32 diff) + void UpdateAI(uint32 diff) { //If we are fake death, we cast revbirth and after that we kill the phoenix to spawn the egg. if (FakeDeath) @@ -610,7 +610,7 @@ public: void EnterCombat(Unit* /*who*/) {} void MoveInLineOfSight(Unit* /*who*/) {} - void UpdateAI(const uint32 diff) + void UpdateAI(uint32 diff) { if (HatchTimer <= diff) { @@ -651,7 +651,7 @@ public: void EnterCombat(Unit* /*who*/) {} - void UpdateAI(const uint32 diff) + void UpdateAI(uint32 diff) { if (DespawnTimer <= diff) me->Kill(me); diff --git a/src/server/scripts/EasternKingdoms/MagistersTerrace/boss_priestess_delrissa.cpp b/src/server/scripts/EasternKingdoms/MagistersTerrace/boss_priestess_delrissa.cpp index 3ed4c50fab4..36324e6b042 100644 --- a/src/server/scripts/EasternKingdoms/MagistersTerrace/boss_priestess_delrissa.cpp +++ b/src/server/scripts/EasternKingdoms/MagistersTerrace/boss_priestess_delrissa.cpp @@ -238,7 +238,7 @@ public: } } - void UpdateAI(const uint32 diff) + void UpdateAI(uint32 diff) { if (!UpdateVictim()) return; @@ -456,7 +456,7 @@ struct boss_priestess_lackey_commonAI : public ScriptedAI } } - void UpdateAI(const uint32 diff) + void UpdateAI(uint32 diff) { if (!UsedPotion && HealthBelowPct(25)) { @@ -517,7 +517,7 @@ public: boss_priestess_lackey_commonAI::Reset(); } - void UpdateAI(const uint32 diff) + void UpdateAI(uint32 diff) { if (!UpdateVictim()) return; @@ -623,7 +623,7 @@ public: DoCast(me, SPELL_SUMMON_IMP); } - void UpdateAI(const uint32 diff) + void UpdateAI(uint32 diff) { if (!UpdateVictim()) return; @@ -703,7 +703,7 @@ public: boss_priestess_lackey_commonAI::Reset(); } - void UpdateAI(const uint32 diff) + void UpdateAI(uint32 diff) { if (!UpdateVictim()) return; @@ -780,7 +780,7 @@ public: boss_priestess_lackey_commonAI::Reset(); } - void UpdateAI(const uint32 diff) + void UpdateAI(uint32 diff) { if (!UpdateVictim()) return; @@ -907,7 +907,7 @@ public: DoCast(me, SPELL_BATTLE_SHOUT); } - void UpdateAI(const uint32 diff) + void UpdateAI(uint32 diff) { if (!UpdateVictim()) return; @@ -1036,7 +1036,7 @@ public: m_uiPetGUID = summoned->GetGUID(); } - void UpdateAI(const uint32 diff) + void UpdateAI(uint32 diff) { if (!UpdateVictim()) return; @@ -1144,7 +1144,7 @@ public: boss_priestess_lackey_commonAI::Reset(); } - void UpdateAI(const uint32 diff) + void UpdateAI(uint32 diff) { if (!UpdateVictim()) return; @@ -1240,7 +1240,7 @@ public: boss_priestess_lackey_commonAI::Reset(); } - void UpdateAI(const uint32 diff) + void UpdateAI(uint32 diff) { if (!UpdateVictim()) return; diff --git a/src/server/scripts/EasternKingdoms/MagistersTerrace/boss_selin_fireheart.cpp b/src/server/scripts/EasternKingdoms/MagistersTerrace/boss_selin_fireheart.cpp index a18dbe79d40..bd5f57f8af0 100644 --- a/src/server/scripts/EasternKingdoms/MagistersTerrace/boss_selin_fireheart.cpp +++ b/src/server/scripts/EasternKingdoms/MagistersTerrace/boss_selin_fireheart.cpp @@ -242,7 +242,7 @@ public: ShatterRemainingCrystals(); } - void UpdateAI(const uint32 diff) + void UpdateAI(uint32 diff) { if (!UpdateVictim()) return; @@ -338,7 +338,7 @@ public: void EnterCombat(Unit* /*who*/) {} void AttackStart(Unit* /*who*/) {} void MoveInLineOfSight(Unit* /*who*/) {} - void UpdateAI(const uint32 /*diff*/) {} + void UpdateAI(uint32 /*diff*/) {} void JustDied(Unit* /*killer*/) { diff --git a/src/server/scripts/EasternKingdoms/MagistersTerrace/boss_vexallus.cpp b/src/server/scripts/EasternKingdoms/MagistersTerrace/boss_vexallus.cpp index 85a113ec495..8958246f1cf 100644 --- a/src/server/scripts/EasternKingdoms/MagistersTerrace/boss_vexallus.cpp +++ b/src/server/scripts/EasternKingdoms/MagistersTerrace/boss_vexallus.cpp @@ -127,7 +127,7 @@ public: summoned->CastSpell(summoned, SPELL_ENERGY_BOLT, false, 0, 0, me->GetGUID()); } - void UpdateAI(const uint32 diff) + void UpdateAI(uint32 diff) { if (!UpdateVictim()) return; diff --git a/src/server/scripts/EasternKingdoms/MagistersTerrace/magisters_terrace.cpp b/src/server/scripts/EasternKingdoms/MagistersTerrace/magisters_terrace.cpp index da1423ed0e9..daaa7d94d18 100644 --- a/src/server/scripts/EasternKingdoms/MagistersTerrace/magisters_terrace.cpp +++ b/src/server/scripts/EasternKingdoms/MagistersTerrace/magisters_terrace.cpp @@ -154,7 +154,7 @@ public: } } - void UpdateAI(const uint32 uiDiff) + void UpdateAI(uint32 uiDiff) { if (m_uiTransformTimer) { diff --git a/src/server/scripts/EasternKingdoms/MoltenCore/boss_baron_geddon.cpp b/src/server/scripts/EasternKingdoms/MoltenCore/boss_baron_geddon.cpp index cc8f2b41fbb..645322768e3 100644 --- a/src/server/scripts/EasternKingdoms/MoltenCore/boss_baron_geddon.cpp +++ b/src/server/scripts/EasternKingdoms/MoltenCore/boss_baron_geddon.cpp @@ -67,7 +67,7 @@ class boss_baron_geddon : public CreatureScript events.ScheduleEvent(EVENT_LIVING_BOMB, 35000); } - void UpdateAI(const uint32 diff) + void UpdateAI(uint32 diff) { if (!UpdateVictim()) return; diff --git a/src/server/scripts/EasternKingdoms/MoltenCore/boss_garr.cpp b/src/server/scripts/EasternKingdoms/MoltenCore/boss_garr.cpp index 824fcca4714..aa563bf3180 100644 --- a/src/server/scripts/EasternKingdoms/MoltenCore/boss_garr.cpp +++ b/src/server/scripts/EasternKingdoms/MoltenCore/boss_garr.cpp @@ -64,7 +64,7 @@ class boss_garr : public CreatureScript events.ScheduleEvent(EVENT_MAGMA_SHACKLES, 15000); } - void UpdateAI(const uint32 diff) + void UpdateAI(uint32 diff) { if (!UpdateVictim()) return; @@ -129,7 +129,7 @@ class mob_firesworn : public CreatureScript } } - void UpdateAI(const uint32 diff) + void UpdateAI(uint32 diff) { if (!UpdateVictim()) return; diff --git a/src/server/scripts/EasternKingdoms/MoltenCore/boss_gehennas.cpp b/src/server/scripts/EasternKingdoms/MoltenCore/boss_gehennas.cpp index 6e9d9b00523..9007d16d2f9 100644 --- a/src/server/scripts/EasternKingdoms/MoltenCore/boss_gehennas.cpp +++ b/src/server/scripts/EasternKingdoms/MoltenCore/boss_gehennas.cpp @@ -61,7 +61,7 @@ class boss_gehennas : public CreatureScript events.ScheduleEvent(EVENT_SHADOW_BOLT, 6000); } - void UpdateAI(const uint32 diff) + void UpdateAI(uint32 diff) { if (!UpdateVictim()) return; diff --git a/src/server/scripts/EasternKingdoms/MoltenCore/boss_golemagg.cpp b/src/server/scripts/EasternKingdoms/MoltenCore/boss_golemagg.cpp index 65c82610cc2..a21ca66543e 100644 --- a/src/server/scripts/EasternKingdoms/MoltenCore/boss_golemagg.cpp +++ b/src/server/scripts/EasternKingdoms/MoltenCore/boss_golemagg.cpp @@ -84,7 +84,7 @@ class boss_golemagg : public CreatureScript events.ScheduleEvent(EVENT_EARTHQUAKE, 3000); } - void UpdateAI(const uint32 diff) + void UpdateAI(uint32 diff) { if (!UpdateVictim()) return; @@ -155,7 +155,7 @@ class mob_core_rager : public CreatureScript } } - void UpdateAI(const uint32 diff) + void UpdateAI(uint32 diff) { if (!UpdateVictim()) return; diff --git a/src/server/scripts/EasternKingdoms/MoltenCore/boss_lucifron.cpp b/src/server/scripts/EasternKingdoms/MoltenCore/boss_lucifron.cpp index 1bb93b2e038..cb91cfc3cae 100644 --- a/src/server/scripts/EasternKingdoms/MoltenCore/boss_lucifron.cpp +++ b/src/server/scripts/EasternKingdoms/MoltenCore/boss_lucifron.cpp @@ -61,7 +61,7 @@ class boss_lucifron : public CreatureScript events.ScheduleEvent(EVENT_SHADOW_SHOCK, 6000); } - void UpdateAI(const uint32 diff) + void UpdateAI(uint32 diff) { if (!UpdateVictim()) return; diff --git a/src/server/scripts/EasternKingdoms/MoltenCore/boss_magmadar.cpp b/src/server/scripts/EasternKingdoms/MoltenCore/boss_magmadar.cpp index c18e9db1ab7..c4b338d635d 100644 --- a/src/server/scripts/EasternKingdoms/MoltenCore/boss_magmadar.cpp +++ b/src/server/scripts/EasternKingdoms/MoltenCore/boss_magmadar.cpp @@ -73,7 +73,7 @@ class boss_magmadar : public CreatureScript events.ScheduleEvent(EVENT_LAVA_BOMB, 12000); } - void UpdateAI(const uint32 diff) + void UpdateAI(uint32 diff) { if (!UpdateVictim()) return; diff --git a/src/server/scripts/EasternKingdoms/MoltenCore/boss_majordomo_executus.cpp b/src/server/scripts/EasternKingdoms/MoltenCore/boss_majordomo_executus.cpp index 26788e10302..a221e2829dd 100644 --- a/src/server/scripts/EasternKingdoms/MoltenCore/boss_majordomo_executus.cpp +++ b/src/server/scripts/EasternKingdoms/MoltenCore/boss_majordomo_executus.cpp @@ -94,7 +94,7 @@ class boss_majordomo : public CreatureScript events.ScheduleEvent(EVENT_TELEPORT, 20000); } - void UpdateAI(const uint32 diff) + void UpdateAI(uint32 diff) { if (instance && instance->GetBossState(BOSS_MAJORDOMO_EXECUTUS) != DONE) { @@ -174,7 +174,7 @@ class boss_majordomo : public CreatureScript } } - void DoAction(const int32 action) + void DoAction(int32 action) { if (action == ACTION_START_RAGNAROS) { diff --git a/src/server/scripts/EasternKingdoms/MoltenCore/boss_ragnaros.cpp b/src/server/scripts/EasternKingdoms/MoltenCore/boss_ragnaros.cpp index eecd9ae65f4..63764b5de01 100644 --- a/src/server/scripts/EasternKingdoms/MoltenCore/boss_ragnaros.cpp +++ b/src/server/scripts/EasternKingdoms/MoltenCore/boss_ragnaros.cpp @@ -115,7 +115,7 @@ class boss_ragnaros : public CreatureScript Talk(SAY_KILL); } - void UpdateAI(const uint32 diff) + void UpdateAI(uint32 diff) { if (_introState != 2) { @@ -328,7 +328,7 @@ class mob_son_of_flame : public CreatureScript instance->SetData(DATA_RAGNAROS_ADDS, 1); } - void UpdateAI(const uint32 /*diff*/) + void UpdateAI(uint32 /*diff*/) { if (!UpdateVictim()) return; diff --git a/src/server/scripts/EasternKingdoms/MoltenCore/boss_shazzrah.cpp b/src/server/scripts/EasternKingdoms/MoltenCore/boss_shazzrah.cpp index 778a8012269..435082b5a98 100644 --- a/src/server/scripts/EasternKingdoms/MoltenCore/boss_shazzrah.cpp +++ b/src/server/scripts/EasternKingdoms/MoltenCore/boss_shazzrah.cpp @@ -66,7 +66,7 @@ class boss_shazzrah : public CreatureScript events.ScheduleEvent(EVENT_BLINK, 30000); } - void UpdateAI(const uint32 diff) + void UpdateAI(uint32 diff) { if (!UpdateVictim()) return; diff --git a/src/server/scripts/EasternKingdoms/MoltenCore/boss_sulfuron_harbinger.cpp b/src/server/scripts/EasternKingdoms/MoltenCore/boss_sulfuron_harbinger.cpp index 1ad0c5dfa2d..b4c2372a015 100644 --- a/src/server/scripts/EasternKingdoms/MoltenCore/boss_sulfuron_harbinger.cpp +++ b/src/server/scripts/EasternKingdoms/MoltenCore/boss_sulfuron_harbinger.cpp @@ -77,7 +77,7 @@ class boss_sulfuron : public CreatureScript events.ScheduleEvent(EVENT_FLAMESPEAR, 2000); } - void UpdateAI(const uint32 diff) + void UpdateAI(uint32 diff) { if (!UpdateVictim()) return; @@ -162,7 +162,7 @@ class mob_flamewaker_priest : public CreatureScript events.ScheduleEvent(EVENT_IMMOLATE, 8000); } - void UpdateAI(const uint32 diff) + void UpdateAI(uint32 diff) { if (!UpdateVictim()) return; diff --git a/src/server/scripts/EasternKingdoms/ScarletEnclave/chapter1.cpp b/src/server/scripts/EasternKingdoms/ScarletEnclave/chapter1.cpp index 97fe57c5434..d3cb21c75f0 100644 --- a/src/server/scripts/EasternKingdoms/ScarletEnclave/chapter1.cpp +++ b/src/server/scripts/EasternKingdoms/ScarletEnclave/chapter1.cpp @@ -102,10 +102,8 @@ public: npc_unworthy_initiateAI(Creature* creature) : ScriptedAI(creature) { me->SetReactState(REACT_PASSIVE); - if (!me->GetEquipmentId()) - if (const CreatureTemplate* info = sObjectMgr->GetCreatureTemplate(28406)) - if (info->equipmentId) - const_cast<CreatureTemplate*>(me->GetCreatureTemplate())->equipmentId = info->equipmentId; + if (!me->GetCurrentEquipmentId()) + me->SetCurrentEquipmentId(me->GetOriginalEquipmentId()); } uint64 playerGUID; @@ -146,7 +144,7 @@ public: me->CastSpell(me, SPELL_DK_INITIATE_VISUAL, true); if (Player* starter = Unit::GetPlayer(*me, playerGUID)) - Talk(SAY_EVENT_ATTACK); + sCreatureTextMgr->SendChat(me, SAY_EVENT_ATTACK, 0, CHAT_MSG_ADDON, LANG_ADDON, TEXT_RANGE_NORMAL, 0, TEAM_OTHER, false, starter); phase = PHASE_TO_ATTACK; } @@ -168,7 +166,7 @@ public: Talk(SAY_EVENT_START); } - void UpdateAI(const uint32 diff) + void UpdateAI(uint32 diff) { switch (phase) { @@ -459,7 +457,7 @@ public: } } - void UpdateAI(const uint32 uiDiff) + void UpdateAI(uint32 uiDiff) { if (!UpdateVictim()) { @@ -495,7 +493,7 @@ public: } } - // TODO: spells + /// @todo spells CombatAI::UpdateAI(uiDiff); } @@ -544,7 +542,7 @@ public: TargetGUID = 0; } - void UpdateAI(const uint32 diff) + void UpdateAI(uint32 diff) { if (!Intro || !TargetGUID) return; @@ -760,7 +758,7 @@ public: if (CAST_PLR(owner)->GetQuestStatus(12698) == QUEST_STATUS_INCOMPLETE) CAST_CRE(who)->CastSpell(owner, 52517, true); - //Todo: Creatures must not be removed, but, must instead + /// @todo Creatures must not be removed, but, must instead // stand next to Gothik and be commanded into the pit // and dig into the ground. CAST_CRE(who)->DespawnOrUnsummon(); @@ -816,7 +814,7 @@ public: } } - void UpdateAI(const uint32 /*diff*/) + void UpdateAI(uint32 /*diff*/) { if (!me->isInCombat()) { @@ -890,7 +888,7 @@ public: minerGUID = guid; } - void DoAction(const int32 /*param*/) + void DoAction(int32 /*param*/) { if (Creature* miner = Unit::GetCreature(*me, minerGUID)) { @@ -1024,7 +1022,7 @@ public: } } - void UpdateAI(const uint32 diff) + void UpdateAI(uint32 diff) { if (IntroPhase) { diff --git a/src/server/scripts/EasternKingdoms/ScarletEnclave/chapter2.cpp b/src/server/scripts/EasternKingdoms/ScarletEnclave/chapter2.cpp index 6985ad2c4ad..1f87d6f65cc 100644 --- a/src/server/scripts/EasternKingdoms/ScarletEnclave/chapter2.cpp +++ b/src/server/scripts/EasternKingdoms/ScarletEnclave/chapter2.cpp @@ -90,7 +90,7 @@ public: } } - void UpdateAI(const uint32 diff) + void UpdateAI(uint32 diff) { if (speechCounter) { @@ -160,7 +160,7 @@ public: ## npc_koltira_deathweaver ######*/ -enum eKoltira +enum Koltira { SAY_BREAKOUT1 = 0, SAY_BREAKOUT2 = 1, @@ -180,10 +180,9 @@ enum eKoltira NPC_CRIMSON_ACOLYTE = 29007, NPC_HIGH_INQUISITOR_VALROTH = 29001, - NPC_KOLTIRA_ALT = 28447, //not sure about this id - //NPC_DEATH_KNIGHT_MOUNT = 29201, + //NPC_DEATH_KNIGHT_MOUNT = 29201, MODEL_DEATH_KNIGHT_MOUNT = 25278 }; @@ -198,17 +197,12 @@ public: { creature->SetStandState(UNIT_STAND_STATE_STAND); - if (npc_escortAI* pEscortAI = CAST_AI(npc_koltira_deathweaver::npc_koltira_deathweaverAI, creature->AI())) - pEscortAI->Start(false, false, player->GetGUID()); + if (npc_escortAI* escortAI = CAST_AI(npc_koltira_deathweaver::npc_koltira_deathweaverAI, creature->AI())) + escortAI->Start(false, false, player->GetGUID()); } return true; } - CreatureAI* GetAI(Creature* creature) const - { - return new npc_koltira_deathweaverAI(creature); - } - struct npc_koltira_deathweaverAI : public npc_escortAI { npc_koltira_deathweaverAI(Creature* creature) : npc_escortAI(creature) @@ -216,20 +210,17 @@ public: me->SetReactState(REACT_DEFENSIVE); } - uint32 m_uiWave; - uint32 m_uiWave_Timer; - uint64 m_uiValrothGUID; - void Reset() { if (!HasEscortState(STATE_ESCORT_ESCORTING)) { - m_uiWave = 0; - m_uiWave_Timer = 3000; - m_uiValrothGUID = 0; - me->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE); + wave = 0; + waveTimer = 3000; + valrothGUID = 0; me->LoadEquipment(0, true); - me->RemoveAura(SPELL_ANTI_MAGIC_ZONE); + me->RemoveAurasDueToSpell(SPELL_ANTI_MAGIC_ZONE); + me->RemoveAurasDueToSpell(SPELL_KOLTIRA_TRANSFORM); + me->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE); } } @@ -239,22 +230,21 @@ public: { case 0: Talk(SAY_BREAKOUT1); - me->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE); break; case 1: me->SetStandState(UNIT_STAND_STATE_KNEEL); break; case 2: me->SetStandState(UNIT_STAND_STATE_STAND); - //me->UpdateEntry(NPC_KOLTIRA_ALT); //unclear if we must update or not DoCast(me, SPELL_KOLTIRA_TRANSFORM); - me->LoadEquipment(me->GetEquipmentId()); + me->LoadEquipment(); break; case 3: SetEscortPaused(true); + me->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE); me->SetStandState(UNIT_STAND_STATE_KNEEL); Talk(SAY_BREAKOUT2); - DoCast(me, SPELL_ANTI_MAGIC_ZONE); // cast again that makes bubble up + DoCast(me, SPELL_ANTI_MAGIC_ZONE); break; case 4: SetRun(true); @@ -274,9 +264,8 @@ public: summoned->AI()->AttackStart(player); if (summoned->GetEntry() == NPC_HIGH_INQUISITOR_VALROTH) - m_uiValrothGUID = summoned->GetGUID(); + valrothGUID = summoned->GetGUID(); - summoned->AddThreat(me, 0.0f); summoned->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_IMMUNE_TO_PC); } @@ -286,57 +275,57 @@ public: me->SummonCreature(NPC_CRIMSON_ACOLYTE, 1642.329f, -6045.818f, 127.583f, 0.0f, TEMPSUMMON_TIMED_DESPAWN_OUT_OF_COMBAT, 5000); } - void UpdateAI(const uint32 uiDiff) + void UpdateAI(uint32 uiDiff) { npc_escortAI::UpdateAI(uiDiff); if (HasEscortState(STATE_ESCORT_PAUSED)) { - if (m_uiWave_Timer <= uiDiff) + if (waveTimer <= uiDiff) { - switch (m_uiWave) + switch (wave) { case 0: Talk(SAY_BREAKOUT3); SummonAcolyte(3); - m_uiWave_Timer = 20000; + waveTimer = 20000; break; case 1: Talk(SAY_BREAKOUT4); SummonAcolyte(3); - m_uiWave_Timer = 20000; + waveTimer = 20000; break; case 2: Talk(SAY_BREAKOUT5); SummonAcolyte(4); - m_uiWave_Timer = 20000; + waveTimer = 20000; break; case 3: Talk(SAY_BREAKOUT6); me->SummonCreature(NPC_HIGH_INQUISITOR_VALROTH, 1642.329f, -6045.818f, 127.583f, 0.0f, TEMPSUMMON_TIMED_DESPAWN_OUT_OF_COMBAT, 1000); - m_uiWave_Timer = 1000; + waveTimer = 1000; break; case 4: { - Creature* temp = Unit::GetCreature(*me, m_uiValrothGUID); + Creature* temp = Unit::GetCreature(*me, valrothGUID); if (!temp || !temp->isAlive()) { Talk(SAY_BREAKOUT8); - m_uiWave_Timer = 5000; + waveTimer = 5000; } else { - m_uiWave_Timer = 2500; - return; //return, we don't want m_uiWave to increment now + waveTimer = 2500; + return; } break; } case 5: Talk(SAY_BREAKOUT9); me->RemoveAurasDueToSpell(SPELL_ANTI_MAGIC_ZONE); - // i do not know why the armor will also be removed - m_uiWave_Timer = 2500; + me->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE); + waveTimer = 2500; break; case 6: Talk(SAY_BREAKOUT10); @@ -344,14 +333,24 @@ public: break; } - ++m_uiWave; + ++wave; } else - m_uiWave_Timer -= uiDiff; + waveTimer -= uiDiff; } } + + private: + uint8 wave; + uint32 waveTimer; + uint64 valrothGUID; + }; + CreatureAI* GetAI(Creature* creature) const + { + return new npc_koltira_deathweaverAI(creature); + } }; //Scarlet courier @@ -404,7 +403,7 @@ public: uiStage = 2; } - void UpdateAI(const uint32 diff) + void UpdateAI(uint32 diff) { if (uiStage && !me->isInCombat()) { @@ -487,7 +486,7 @@ public: DoCast(who, SPELL_VALROTH_SMITE); } - void UpdateAI(const uint32 diff) + void UpdateAI(uint32 diff) { if (uiRenew_timer <= diff) { @@ -677,7 +676,7 @@ public: PlayerGUID = who->GetGUID(); } - void UpdateAI(const uint32 diff) + void UpdateAI(uint32 diff) { if (PlayerGUID && !me->getVictim() && me->isAlive()) { @@ -691,7 +690,7 @@ public: return; } - //TODO: simplify text's selection + /// @todo simplify text's selection switch (player->getRace()) { diff --git a/src/server/scripts/EasternKingdoms/ScarletEnclave/chapter5.cpp b/src/server/scripts/EasternKingdoms/ScarletEnclave/chapter5.cpp index ff92710d5b2..3d91e81644e 100644 --- a/src/server/scripts/EasternKingdoms/ScarletEnclave/chapter5.cpp +++ b/src/server/scripts/EasternKingdoms/ScarletEnclave/chapter5.cpp @@ -606,7 +606,7 @@ public: npc_escortAI::EnterEvadeMode(); } - void UpdateAI(const uint32 diff) + void UpdateAI(uint32 diff) { npc_escortAI::UpdateAI(diff); @@ -1662,7 +1662,7 @@ public: npc_the_lich_king_tirion_dawnAI(Creature* creature) : ScriptedAI(creature) { Reset(); } void Reset() {} void AttackStart(Unit* /*who*/) {} // very sample, just don't make them aggreesive - void UpdateAI(const uint32 /*diff*/) {} + void UpdateAI(uint32 /*diff*/) {} void JustDied(Unit* /*killer*/) {} }; diff --git a/src/server/scripts/EasternKingdoms/ScarletEnclave/zone_the_scarlet_enclave.cpp b/src/server/scripts/EasternKingdoms/ScarletEnclave/zone_the_scarlet_enclave.cpp index 32ce484f715..16e6554d1f4 100644 --- a/src/server/scripts/EasternKingdoms/ScarletEnclave/zone_the_scarlet_enclave.cpp +++ b/src/server/scripts/EasternKingdoms/ScarletEnclave/zone_the_scarlet_enclave.cpp @@ -69,7 +69,7 @@ public: me->SetPosition(x, y, z, 0.0f); } - void UpdateAI(const uint32 diff) + void UpdateAI(uint32 diff) { if (FlyBackTimer <= diff) { @@ -104,7 +104,7 @@ public: { me->HandleEmoteCommand(EMOTE_ONESHOT_CUSTOM_SPELL_01); DoCast(player, SPELL_REVIVE, true); - Talk(WHISPER_REVIVE,player->GetGUID()); + Talk(WHISPER_REVIVE, player->GetGUID()); } FlyBackTimer = 5000; break; diff --git a/src/server/scripts/EasternKingdoms/ScarletMonastery/boss_arcanist_doan.cpp b/src/server/scripts/EasternKingdoms/ScarletMonastery/boss_arcanist_doan.cpp index 1ede8a871d9..db08df50148 100644 --- a/src/server/scripts/EasternKingdoms/ScarletMonastery/boss_arcanist_doan.cpp +++ b/src/server/scripts/EasternKingdoms/ScarletMonastery/boss_arcanist_doan.cpp @@ -72,7 +72,7 @@ public: Talk(SAY_AGGRO); } - void UpdateAI(const uint32 diff) + void UpdateAI(uint32 diff) { if (!UpdateVictim()) return; diff --git a/src/server/scripts/EasternKingdoms/ScarletMonastery/boss_azshir_the_sleepless.cpp b/src/server/scripts/EasternKingdoms/ScarletMonastery/boss_azshir_the_sleepless.cpp index 23480154c22..384ffeb6bf3 100644 --- a/src/server/scripts/EasternKingdoms/ScarletMonastery/boss_azshir_the_sleepless.cpp +++ b/src/server/scripts/EasternKingdoms/ScarletMonastery/boss_azshir_the_sleepless.cpp @@ -60,7 +60,7 @@ public: void EnterCombat(Unit* /*who*/) {} - void UpdateAI(const uint32 diff) + void UpdateAI(uint32 diff) { if (!UpdateVictim()) return; diff --git a/src/server/scripts/EasternKingdoms/ScarletMonastery/boss_bloodmage_thalnos.cpp b/src/server/scripts/EasternKingdoms/ScarletMonastery/boss_bloodmage_thalnos.cpp index 7540a1eefb3..cae033f2a30 100644 --- a/src/server/scripts/EasternKingdoms/ScarletMonastery/boss_bloodmage_thalnos.cpp +++ b/src/server/scripts/EasternKingdoms/ScarletMonastery/boss_bloodmage_thalnos.cpp @@ -77,7 +77,7 @@ public: Talk(SAY_KILL); } - void UpdateAI(const uint32 diff) + void UpdateAI(uint32 diff) { if (!UpdateVictim()) return; diff --git a/src/server/scripts/EasternKingdoms/ScarletMonastery/boss_headless_horseman.cpp b/src/server/scripts/EasternKingdoms/ScarletMonastery/boss_headless_horseman.cpp index 4927666073b..32e8af3821b 100644 --- a/src/server/scripts/EasternKingdoms/ScarletMonastery/boss_headless_horseman.cpp +++ b/src/server/scripts/EasternKingdoms/ScarletMonastery/boss_headless_horseman.cpp @@ -204,7 +204,7 @@ public: DoCast(who, SPELL_SQUASH_SOUL); } - void UpdateAI(const uint32 diff) + void UpdateAI(uint32 diff) { if (delay) { @@ -325,7 +325,7 @@ public: } void Disappear(); - void UpdateAI(const uint32 diff) + void UpdateAI(uint32 diff) { if (!withbody) { @@ -639,7 +639,7 @@ public: } } - void UpdateAI(const uint32 diff) + void UpdateAI(uint32 diff) { if (withhead) { @@ -858,7 +858,7 @@ public: DoStartMovement(who); } - void UpdateAI(const uint32 /*diff*/) + void UpdateAI(uint32 /*diff*/) { if (sprouted && UpdateVictim()) DoMeleeAttackIfReady(); diff --git a/src/server/scripts/EasternKingdoms/ScarletMonastery/boss_herod.cpp b/src/server/scripts/EasternKingdoms/ScarletMonastery/boss_herod.cpp index 6e24dd81bbe..4929e0fbb3d 100644 --- a/src/server/scripts/EasternKingdoms/ScarletMonastery/boss_herod.cpp +++ b/src/server/scripts/EasternKingdoms/ScarletMonastery/boss_herod.cpp @@ -93,7 +93,7 @@ public: me->SummonCreature(ENTRY_SCARLET_TRAINEE, 1939.18f, -431.58f, 17.09f, 6.22f, TEMPSUMMON_TIMED_OR_DEAD_DESPAWN, 600000); } - void UpdateAI(const uint32 diff) + void UpdateAI(uint32 diff) { if (!UpdateVictim()) return; @@ -152,7 +152,7 @@ public: void WaypointReached(uint32 /*waypointId*/) {} void EnterCombat(Unit* /*who*/) {} - void UpdateAI(const uint32 diff) + void UpdateAI(uint32 diff) { if (Start_Timer) { diff --git a/src/server/scripts/EasternKingdoms/ScarletMonastery/boss_high_inquisitor_fairbanks.cpp b/src/server/scripts/EasternKingdoms/ScarletMonastery/boss_high_inquisitor_fairbanks.cpp index 2c64ba693d0..235add380de 100644 --- a/src/server/scripts/EasternKingdoms/ScarletMonastery/boss_high_inquisitor_fairbanks.cpp +++ b/src/server/scripts/EasternKingdoms/ScarletMonastery/boss_high_inquisitor_fairbanks.cpp @@ -19,7 +19,7 @@ /* ScriptData SDName: Boss_High_Inquisitor_Fairbanks SD%Complete: 100 -SDComment: TODO: if this guy not involved in some special event, remove (and let ACID script) +SDComment: @todo if this guy not involved in some special event, remove (and let ACID script) SDCategory: Scarlet Monastery EndScriptData */ @@ -77,7 +77,7 @@ public: me->SetUInt32Value(UNIT_FIELD_BYTES_1, 0); } - void UpdateAI(const uint32 diff) + void UpdateAI(uint32 diff) { if (!UpdateVictim()) return; diff --git a/src/server/scripts/EasternKingdoms/ScarletMonastery/boss_houndmaster_loksey.cpp b/src/server/scripts/EasternKingdoms/ScarletMonastery/boss_houndmaster_loksey.cpp index 1b2679538b0..6bdf1a16b03 100644 --- a/src/server/scripts/EasternKingdoms/ScarletMonastery/boss_houndmaster_loksey.cpp +++ b/src/server/scripts/EasternKingdoms/ScarletMonastery/boss_houndmaster_loksey.cpp @@ -59,7 +59,7 @@ public: Talk(SAY_AGGRO); } - void UpdateAI(const uint32 diff) + void UpdateAI(uint32 diff) { if (!UpdateVictim()) return; diff --git a/src/server/scripts/EasternKingdoms/ScarletMonastery/boss_interrogator_vishas.cpp b/src/server/scripts/EasternKingdoms/ScarletMonastery/boss_interrogator_vishas.cpp index 76673b7a632..4206e958f3c 100644 --- a/src/server/scripts/EasternKingdoms/ScarletMonastery/boss_interrogator_vishas.cpp +++ b/src/server/scripts/EasternKingdoms/ScarletMonastery/boss_interrogator_vishas.cpp @@ -89,7 +89,7 @@ public: vorrel->AI()->Talk(SAY_TRIGGER_VORREL); } - void UpdateAI(const uint32 diff) + void UpdateAI(uint32 diff) { if (!UpdateVictim()) return; diff --git a/src/server/scripts/EasternKingdoms/ScarletMonastery/boss_mograine_and_whitemane.cpp b/src/server/scripts/EasternKingdoms/ScarletMonastery/boss_mograine_and_whitemane.cpp index 70af355a4c7..c6fdc6e651b 100644 --- a/src/server/scripts/EasternKingdoms/ScarletMonastery/boss_mograine_and_whitemane.cpp +++ b/src/server/scripts/EasternKingdoms/ScarletMonastery/boss_mograine_and_whitemane.cpp @@ -175,7 +175,7 @@ public: } } - void UpdateAI(const uint32 diff) + void UpdateAI(uint32 diff) { if (!UpdateVictim()) return; @@ -290,7 +290,7 @@ public: damage = me->GetHealth() - 1; } - void UpdateAI(const uint32 diff) + void UpdateAI(uint32 diff) { if (!UpdateVictim()) return; diff --git a/src/server/scripts/EasternKingdoms/ScarletMonastery/boss_scorn.cpp b/src/server/scripts/EasternKingdoms/ScarletMonastery/boss_scorn.cpp index f6b6118f701..639db4571cb 100644 --- a/src/server/scripts/EasternKingdoms/ScarletMonastery/boss_scorn.cpp +++ b/src/server/scripts/EasternKingdoms/ScarletMonastery/boss_scorn.cpp @@ -63,7 +63,7 @@ public: void EnterCombat(Unit* /*who*/) {} - void UpdateAI(const uint32 diff) + void UpdateAI(uint32 diff) { if (!UpdateVictim()) return; diff --git a/src/server/scripts/EasternKingdoms/Scholomance/boss_darkmaster_gandling.cpp b/src/server/scripts/EasternKingdoms/Scholomance/boss_darkmaster_gandling.cpp index 471f28835cd..dccb7ccbaa0 100644 --- a/src/server/scripts/EasternKingdoms/Scholomance/boss_darkmaster_gandling.cpp +++ b/src/server/scripts/EasternKingdoms/Scholomance/boss_darkmaster_gandling.cpp @@ -1,6 +1,5 @@ /* * Copyright (C) 2008-2013 TrinityCore <http://www.trinitycore.org/> - * Copyright (C) 2006-2009 ScriptDev2 <https://scriptdev2.svn.sourceforge.net/> * * 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 @@ -16,216 +15,347 @@ * with this program. If not, see <http://www.gnu.org/licenses/>. */ -/* ScriptData -SDName: Boss_Darkmaster_Gandling -SD%Complete: 75 -SDComment: Doors missing in instance script. -SDCategory: Scholomance -EndScriptData */ +/* +Name: Boss_Darkmaster_Gandling +%Complete: 90 +Comment: Doors Not yet reopening. +Category: Scholomance +*/ #include "ScriptMgr.h" #include "ScriptedCreature.h" #include "scholomance.h" +#include "SpellScript.h" -#define SPELL_ARCANEMISSILES 22272 -#define SPELL_SHADOWSHIELD 22417 //Not right ID. But 12040 is wrong either. -#define SPELL_CURSE 18702 - -#define ADD_1X 170.205f -#define ADD_1Y 99.413f -#define ADD_1Z 104.733f -#define ADD_1O 3.16f - -#define ADD_2X 170.813f -#define ADD_2Y 97.857f -#define ADD_2Z 104.713f -#define ADD_2O 3.16f +enum Says +{ + YELL_SUMMONED = 0 +}; -#define ADD_3X 170.720f -#define ADD_3Y 100.900f -#define ADD_3Z 104.739f -#define ADD_3O 3.16f +enum Spells +{ + SPELL_ARCANEMISSILES = 15790, + SPELL_SHADOWSHIELD = 12040, + SPELL_CURSE = 18702, + SPELL_SHADOW_PORTAL = 17950 +}; -#define ADD_4X 171.866f -#define ADD_4Y 99.373f -#define ADD_4Z 104.732f -#define ADD_4O 3.16f +enum Events +{ + EVENT_ARCANEMISSILES = 1, + EVENT_SHADOWSHIELD = 2, + EVENT_CURSE = 3, + EVENT_SHADOW_PORTAL = 4 +}; class boss_darkmaster_gandling : public CreatureScript { -public: - boss_darkmaster_gandling() : CreatureScript("boss_darkmaster_gandling") { } + public: boss_darkmaster_gandling() : CreatureScript("boss_darkmaster_gandling") { } - CreatureAI* GetAI(Creature* creature) const - { - return new boss_darkmaster_gandlingAI (creature); - } - - struct boss_darkmaster_gandlingAI : public ScriptedAI - { - boss_darkmaster_gandlingAI(Creature* creature) : ScriptedAI(creature) + struct boss_darkmaster_gandlingAI : public BossAI { - instance = me->GetInstanceScript(); - } + boss_darkmaster_gandlingAI(Creature* creature) : BossAI(creature, DATA_DARKMASTERGANDLING) {} + + void Reset() + { + _Reset(); + if (GameObject* gate = me->GetMap()->GetGameObject(instance->GetData64(GO_GATE_GANDLING))) + gate->SetGoState(GO_STATE_ACTIVE); + } + + void JustDied(Unit* /*killer*/) + { + _JustDied(); + if (GameObject* gate = me->GetMap()->GetGameObject(instance->GetData64(GO_GATE_GANDLING))) + gate->SetGoState(GO_STATE_ACTIVE); + } + + void EnterCombat(Unit* /*who*/) + { + _EnterCombat(); + events.ScheduleEvent(EVENT_ARCANEMISSILES, 4500); + events.ScheduleEvent(EVENT_SHADOWSHIELD, 12000); + events.ScheduleEvent(EVENT_CURSE, 2000); + events.ScheduleEvent(EVENT_SHADOW_PORTAL, 16000); + + if (GameObject* gate = me->GetMap()->GetGameObject(instance->GetData64(GO_GATE_GANDLING))) + gate->SetGoState(GO_STATE_READY); + } - InstanceScript* instance; + void IsSummonedBy(Unit* /*summoner*/) + { + Talk(YELL_SUMMONED); + me->GetMotionMaster()->MoveRandom(5); + } + + void UpdateAI(uint32 diff) + { + if (!UpdateVictim()) + return; + + events.Update(diff); - uint32 ArcaneMissiles_Timer; - uint32 ShadowShield_Timer; - uint32 Curse_Timer; - uint32 Teleport_Timer; + if (me->HasUnitState(UNIT_STATE_CASTING)) + return; - void Reset() + while (uint32 eventId = events.ExecuteEvent()) + { + switch (eventId) + { + case EVENT_ARCANEMISSILES: + DoCastVictim(SPELL_ARCANEMISSILES, true); + events.ScheduleEvent(EVENT_ARCANEMISSILES, 8000); + break; + case EVENT_SHADOWSHIELD: + DoCast(me, SPELL_SHADOWSHIELD); + events.ScheduleEvent(EVENT_SHADOWSHIELD, urand(14000, 28000)); + break; + case EVENT_CURSE: + DoCastVictim(SPELL_CURSE, true); + events.ScheduleEvent(EVENT_CURSE, urand(15000, 27000)); + break; + case EVENT_SHADOW_PORTAL: + if (HealthAbovePct(3)) + { + DoCast(SelectTarget(SELECT_TARGET_RANDOM, 0, 100, true), SPELL_SHADOW_PORTAL, true); + events.ScheduleEvent(EVENT_SHADOW_PORTAL, urand(17000, 27000)); + } + } + } + DoMeleeAttackIfReady(); + } + }; + + CreatureAI* GetAI(Creature* creature) const { - ArcaneMissiles_Timer = 4500; - ShadowShield_Timer = 12000; - Curse_Timer = 2000; - Teleport_Timer = 16000; + return new boss_darkmaster_gandlingAI (creature); } +}; - void EnterCombat(Unit* /*who*/) +// Script for Shadow Portal spell 17950 +enum Rooms +{ + ROOM_HALL_OF_SECRETS = 0, + ROOM_HALL_OF_THE_DAMNED = 1, + ROOM_THE_COVEN = 2, + ROOM_THE_SHADOW_VAULT = 3, + ROOM_BAROV_FAMILY_VAULT = 4, + ROOM_VAULT_OF_THE_RAVENIAN = 5 +}; + +enum SPSpells +{ + SPELL_SHADOW_PORTAL_HALLOFSECRETS = 17863, + SPELL_SHADOW_PORTAL_HALLOFTHEDAMNED = 17939, + SPELL_SHADOW_PORTAL_THECOVEN = 17943, + SPELL_SHADOW_PORTAL_THESHADOWVAULT = 17944, + SPELL_SHADOW_PORTAL_BAROVFAMILYVAULT = 17946, + SPELL_SHADOW_PORTAL_VAULTOFTHERAVENIAN = 17948 +}; + +class spell_shadow_portal : public SpellScriptLoader +{ + public: + spell_shadow_portal() : SpellScriptLoader("spell_shadow_portal") { } + + class spell_shadow_portal_SpellScript : public SpellScript { - } + PrepareSpellScript(spell_shadow_portal_SpellScript); - void JustDied(Unit* /*killer*/) + void HandleCast(SpellEffIndex /*effIndex*/) + { + Creature* caster = GetCaster()->ToCreature(); + int8 attempts = 0; + int32 spell_to_cast =0; + + while (!spell_to_cast) + { + if (attempts++ >= 6) break; + + switch (urand(0, 5)) + { + case ROOM_HALL_OF_SECRETS: + if (InstanceScript* instance = GetCaster()->GetInstanceScript()) + if (GameObject::GetGameObject(*caster, instance->GetData64(GO_GATE_RAVENIAN))->GetGoState() == GO_STATE_ACTIVE) + spell_to_cast = SPELL_SHADOW_PORTAL_HALLOFSECRETS; + break; + case ROOM_HALL_OF_THE_DAMNED: + if (InstanceScript* instance = GetCaster()->GetInstanceScript()) + if (GameObject::GetGameObject(*caster, instance->GetData64(GO_GATE_THEOLEN))->GetGoState() == GO_STATE_ACTIVE) + spell_to_cast = SPELL_SHADOW_PORTAL_HALLOFTHEDAMNED; + break; + case ROOM_THE_COVEN: + if (InstanceScript* instance = GetCaster()->GetInstanceScript()) + if (GameObject::GetGameObject(*caster, instance->GetData64(GO_GATE_MALICIA))->GetGoState() == GO_STATE_ACTIVE) + spell_to_cast = SPELL_SHADOW_PORTAL_THECOVEN; + break; + case ROOM_THE_SHADOW_VAULT: + if (InstanceScript* instance = GetCaster()->GetInstanceScript()) + if (GameObject::GetGameObject(*caster, instance->GetData64(GO_GATE_ILLUCIA))->GetGoState() == GO_STATE_ACTIVE) + spell_to_cast = SPELL_SHADOW_PORTAL_THESHADOWVAULT; + break; + case ROOM_BAROV_FAMILY_VAULT: + if (InstanceScript* instance = GetCaster()->GetInstanceScript()) + if (GameObject::GetGameObject(*caster, instance->GetData64(GO_GATE_BAROV))->GetGoState() == GO_STATE_ACTIVE) + spell_to_cast = SPELL_SHADOW_PORTAL_BAROVFAMILYVAULT; + break; + case ROOM_VAULT_OF_THE_RAVENIAN: + if (InstanceScript* instance = GetCaster()->GetInstanceScript()) + if (GameObject::GetGameObject(*caster, instance->GetData64(GO_GATE_POLKELT))->GetGoState() == GO_STATE_ACTIVE) + spell_to_cast = SPELL_SHADOW_PORTAL_VAULTOFTHERAVENIAN; + break; + } + + if (spell_to_cast) + GetHitUnit()->CastSpell(GetHitUnit(), spell_to_cast); + } + } + + void Register() + { + OnEffectHitTarget += SpellEffectFn(spell_shadow_portal_SpellScript::HandleCast, EFFECT_0, SPELL_EFFECT_DUMMY); + } + }; + + SpellScript* GetSpellScript() const { - if (instance) - instance->SetData(TYPE_GANDLING, DONE); + return new spell_shadow_portal_SpellScript(); } +}; + +// Script for Shadow Portal spells 17863, 17939, 17943, 17944, 17946, 17948 +Position const SummonPos[18] = +{ + // Hall of Secrects + + + + // The Hall of the damned + { 177.9624f, -68.23893f, 84.95197f, 3.228859f }, + { 183.7705f, -61.43489f, 84.92424f, 5.148721f }, + { 184.7035f, -77.74805f, 84.92424f, 4.660029f }, + // The Coven + { 111.7203f, -1.105035f, 85.45985f, 3.961897f }, + { 118.0079f, 6.430664f, 85.31169f, 2.408554f }, + { 120.0276f, -7.496636f, 85.31169f, 2.984513f }, + // The Shadow Vault + { 245.3716f, 0.628038f, 72.73877f, 0.01745329f }, + { 240.9920f, 3.405653f, 72.73877f, 6.143559f }, + { 240.9543f, -3.182943f, 72.73877f, 0.2268928f }, + // Barov Family Vault + { 181.8245f, -42.58117f, 75.4812f, 4.660029f }, + { 177.7456f, -42.74745f, 75.4812f, 4.886922f }, + { 185.6157f, -42.91200f, 75.4812f, 4.45059f }, + // Vault of the Ravenian + + + +}; - void UpdateAI(const uint32 diff) +enum Creatures +{ + NPC_RISEN_GUARDIAN = 11598 +}; + +enum ScriptEventId +{ + SPELL_EVENT_HALLOFSECRETS = 5618, + SPELL_EVENT_HALLOFTHEDAMNED = 5619, + SPELL_EVENT_THECOVEN = 5620, + SPELL_EVENT_THESHADOWVAULT = 5621, + SPELL_EVENT_BAROVFAMILYVAULT = 5622, + SPELL_EVENT_VAULTOFTHERAVENIAN = 5623 +}; + +class spell_shadow_portal_rooms : public SpellScriptLoader +{ + public: + spell_shadow_portal_rooms() : SpellScriptLoader("spell_shadow_portal_rooms") { } + + class spell_shadow_portal_rooms_SpellScript : public SpellScript { - if (!UpdateVictim()) - return; + PrepareSpellScript(spell_shadow_portal_rooms_SpellScript); - //ArcaneMissiles_Timer - if (ArcaneMissiles_Timer <= diff) + void HandleSendEvent(SpellEffIndex effIndex) { - DoCast(me->getVictim(), SPELL_ARCANEMISSILES); - ArcaneMissiles_Timer = 8000; - } else ArcaneMissiles_Timer -= diff; + // If only one player in threat list fail spell - //ShadowShield_Timer - if (ShadowShield_Timer <= diff) - { - DoCast(me, SPELL_SHADOWSHIELD); - ShadowShield_Timer = urand(14000, 28000); - } else ShadowShield_Timer -= diff; + Creature* Summoned = NULL; + Creature* caster = GetCaster()->ToCreature(); - //Curse_Timer - if (Curse_Timer <= diff) - { - DoCast(me->getVictim(), SPELL_CURSE); - Curse_Timer = urand(15000, 27000); - } else Curse_Timer -= diff; + int8 pos_to_summon = 0; + int8 phase_to_set = 0; + int32 gate_to_close = 0; - //Teleporting Random Target to one of the six pre boss rooms and spawn 3-4 skeletons near the gamer. - //We will only telport if gandling has more than 3% of hp so teleported gamers can always loot. - if (HealthAbovePct(3)) - { - if (Teleport_Timer <= diff) + switch (GetSpellInfo()->Effects[effIndex].MiscValue) { - Unit* target = NULL; - target = SelectTarget(SELECT_TARGET_RANDOM, 0); - if (target && target->GetTypeId() == TYPEID_PLAYER) - { - if (DoGetThreat(target)) - DoModifyThreatPercent(target, -100); + case SPELL_EVENT_HALLOFSECRETS: + pos_to_summon = 0; // Not yet spawned + phase_to_set = 1; + gate_to_close = GO_GATE_RAVENIAN; + break; + case SPELL_EVENT_HALLOFTHEDAMNED: + pos_to_summon = 0; + phase_to_set = 2; + gate_to_close = GO_GATE_THEOLEN; + break; + case SPELL_EVENT_THECOVEN: + pos_to_summon = 3; + phase_to_set = 3; + gate_to_close = GO_GATE_MALICIA; + break; + case SPELL_EVENT_THESHADOWVAULT: + pos_to_summon = 6; + phase_to_set = 4; + gate_to_close = GO_GATE_ILLUCIA; + break; + case SPELL_EVENT_BAROVFAMILYVAULT: + pos_to_summon = 9; + phase_to_set = 5; + gate_to_close = GO_GATE_BAROV; + break; + case SPELL_EVENT_VAULTOFTHERAVENIAN: + pos_to_summon = 0; // Not yet spawned + phase_to_set = 6; + gate_to_close = GO_GATE_POLKELT; + break; + default: + break; + } - Creature* Summoned = NULL; - switch (rand()%6) + if (gate_to_close && (GetCaster()->GetMap()->GetId() == 289)) + { + for (uint8 i = 0; i < 3; ++i) + { + Summoned = GetCaster()->SummonCreature(NPC_RISEN_GUARDIAN, SummonPos[pos_to_summon++], TEMPSUMMON_TIMED_DESPAWN_OUT_OF_COMBAT, 120000); + if (Summoned) { - case 0: - DoTeleportPlayer(target, 250.0696f, 0.3921f, 84.8408f, 3.149f); - Summoned = me->SummonCreature(16119, 254.2325f, 0.3417f, 84.8407f, 0, TEMPSUMMON_TIMED_DESPAWN_OUT_OF_COMBAT, 10000); - if (Summoned) - Summoned->AI()->AttackStart(target); - Summoned = me->SummonCreature(16119, 257.7133f, 4.0226f, 84.8407f, 0, TEMPSUMMON_TIMED_DESPAWN_OUT_OF_COMBAT, 10000); - if (Summoned) - Summoned->AI()->AttackStart(target); - Summoned = me->SummonCreature(16119, 258.6702f, -2.60656f, 84.8407f, 0, TEMPSUMMON_TIMED_DESPAWN_OUT_OF_COMBAT, 10000); - if (Summoned) - Summoned->AI()->AttackStart(target); - break; - case 1: - DoTeleportPlayer(target, 181.4220f, -91.9481f, 84.8410f, 1.608f); - Summoned = me->SummonCreature(16119, 184.0519f, -73.5649f, 84.8407f, 0, TEMPSUMMON_TIMED_DESPAWN_OUT_OF_COMBAT, 10000); - if (Summoned) - Summoned->AI()->AttackStart(target); - Summoned = me->SummonCreature(16119, 179.5951f, -73.7045f, 84.8407f, 0, TEMPSUMMON_TIMED_DESPAWN_OUT_OF_COMBAT, 10000); - if (Summoned) - Summoned->AI()->AttackStart(target); - Summoned = me->SummonCreature(16119, 180.6452f, -78.2143f, 84.8407f, 0, TEMPSUMMON_TIMED_DESPAWN_OUT_OF_COMBAT, 10000); - if (Summoned) - Summoned->AI()->AttackStart(target); - Summoned = me->SummonCreature(16119, 283.2274f, -78.1518f, 84.8407f, 0, TEMPSUMMON_TIMED_DESPAWN_OUT_OF_COMBAT, 10000); - if (Summoned) - Summoned->AI()->AttackStart(target); - break; - case 2: - DoTeleportPlayer(target, 95.1547f, -1.8173f, 85.2289f, 0.043f); - Summoned = me->SummonCreature(16119, 100.9404f, -1.8016f, 85.2289f, 0, TEMPSUMMON_TIMED_DESPAWN_OUT_OF_COMBAT, 10000); - if (Summoned) - Summoned->AI()->AttackStart(target); - Summoned = me->SummonCreature(16119, 101.3729f, 0.4882f, 85.2289f, 0, TEMPSUMMON_TIMED_DESPAWN_OUT_OF_COMBAT, 10000); - if (Summoned) - Summoned->AI()->AttackStart(target); - Summoned = me->SummonCreature(16119, 101.4596f, -4.4740f, 85.2289f, 0, TEMPSUMMON_TIMED_DESPAWN_OUT_OF_COMBAT, 10000); - if (Summoned) - Summoned->AI()->AttackStart(target); - break; - case 3: - DoTeleportPlayer(target, 250.0696f, 0.3921f, 72.6722f, 3.149f); - Summoned = me->SummonCreature(16119, 240.34481f, 0.7368f, 72.6722f, 0, TEMPSUMMON_TIMED_DESPAWN_OUT_OF_COMBAT, 10000); - if (Summoned) - Summoned->AI()->AttackStart(target); - Summoned = me->SummonCreature(16119, 240.3633f, -2.9520f, 72.6722f, 0, TEMPSUMMON_TIMED_DESPAWN_OUT_OF_COMBAT, 10000); - if (Summoned) - Summoned->AI()->AttackStart(target); - Summoned = me->SummonCreature(16119, 240.6702f, 3.34949f, 72.6722f, 0, TEMPSUMMON_TIMED_DESPAWN_OUT_OF_COMBAT, 10000); - if (Summoned) - Summoned->AI()->AttackStart(target); - break; - case 4: - DoTeleportPlayer(target, 181.4220f, -91.9481f, 70.7734f, 1.608f); - Summoned = me->SummonCreature(16119, 184.0519f, -73.5649f, 70.7734f, 0, TEMPSUMMON_TIMED_DESPAWN_OUT_OF_COMBAT, 10000); - if (Summoned) - Summoned->AI()->AttackStart(target); - Summoned = me->SummonCreature(16119, 179.5951f, -73.7045f, 70.7734f, 0, TEMPSUMMON_TIMED_DESPAWN_OUT_OF_COMBAT, 10000); - if (Summoned) - Summoned->AI()->AttackStart(target); - Summoned = me->SummonCreature(16119, 180.6452f, -78.2143f, 70.7734f, 0, TEMPSUMMON_TIMED_DESPAWN_OUT_OF_COMBAT, 10000); - if (Summoned) - Summoned->AI()->AttackStart(target); - Summoned = me->SummonCreature(16119, 283.2274f, -78.1518f, 70.7734f, 0, TEMPSUMMON_TIMED_DESPAWN_OUT_OF_COMBAT, 10000); - if (Summoned) - Summoned->AI()->AttackStart(target); - break; - case 5: - DoTeleportPlayer(target, 106.1541f, -1.8994f, 75.3663f, 0.043f); - Summoned = me->SummonCreature(16119, 115.3945f, -1.5555f, 75.3663f, 0, TEMPSUMMON_TIMED_DESPAWN_OUT_OF_COMBAT, 10000); - if (Summoned) - Summoned->AI()->AttackStart(target); - Summoned = me->SummonCreature(16119, 257.7133f, 1.8066f, 75.3663f, 0, TEMPSUMMON_TIMED_DESPAWN_OUT_OF_COMBAT, 10000); - if (Summoned) - Summoned->AI()->AttackStart(target); - Summoned = me->SummonCreature(16119, 258.6702f, -5.1001f, 75.3663f, 0, TEMPSUMMON_TIMED_DESPAWN_OUT_OF_COMBAT, 10000); - if (Summoned) - Summoned->AI()->AttackStart(target); - break; + Summoned->GetMotionMaster()->MoveRandom(5); + Summoned->AI()->SetData(0, phase_to_set); } } - Teleport_Timer = urand(20000, 35000); - } else Teleport_Timer -= diff; + + if (InstanceScript* instance = GetCaster()->GetInstanceScript()) + if (GameObject* gate = GameObject::GetGameObject(*caster, instance->GetData64(gate_to_close))) + gate->SetGoState(GO_STATE_READY); + } } - DoMeleeAttackIfReady(); - } - }; + void Register() + { + OnEffectHit += SpellEffectFn(spell_shadow_portal_rooms_SpellScript::HandleSendEvent, EFFECT_1, SPELL_EFFECT_SEND_EVENT); + } + }; + SpellScript* GetSpellScript() const + { + return new spell_shadow_portal_rooms_SpellScript(); + } }; void AddSC_boss_darkmaster_gandling() { new boss_darkmaster_gandling(); + new spell_shadow_portal(); + new spell_shadow_portal_rooms(); } diff --git a/src/server/scripts/EasternKingdoms/Scholomance/boss_doctor_theolen_krastinov.cpp b/src/server/scripts/EasternKingdoms/Scholomance/boss_doctor_theolen_krastinov.cpp index ea60b0ce333..0f1999b112f 100644 --- a/src/server/scripts/EasternKingdoms/Scholomance/boss_doctor_theolen_krastinov.cpp +++ b/src/server/scripts/EasternKingdoms/Scholomance/boss_doctor_theolen_krastinov.cpp @@ -1,6 +1,5 @@ /* * Copyright (C) 2008-2013 TrinityCore <http://www.trinitycore.org/> - * Copyright (C) 2006-2009 ScriptDev2 <https://scriptdev2.svn.sourceforge.net/> * * 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 @@ -16,12 +15,12 @@ * with this program. If not, see <http://www.gnu.org/licenses/>. */ -/* ScriptData -SDName: Boss_Doctor_Theolen_Krastinov -SD%Complete: 100 -SDComment: -SDCategory: Scholomance -EndScriptData */ +/* +Name: Boss_Doctor_Theolen_Krastinov +%Complete: 100 +Comment: +Category: Scholomance +*/ #include "ScriptMgr.h" #include "ScriptedCreature.h" @@ -54,31 +53,15 @@ class boss_doctor_theolen_krastinov : public CreatureScript { boss_theolenkrastinovAI(Creature* creature) : BossAI(creature, DATA_DOCTORTHEOLENKRASTINOV) {} - void Reset() {} - - void JustDied(Unit* /*killer*/) - { - InstanceScript* instance = me->GetInstanceScript(); - if (instance) - { - instance->SetData(DATA_DOCTORTHEOLENKRASTINOV, DONE); - - if (instance->GetData(TYPE_GANDLING) == IN_PROGRESS) - { - instance->SetData(TYPE_GANDLING, IN_PROGRESS); - me->SummonCreature(1853, 180.73f, -9.43856f, 75.507f, 1.61399f, TEMPSUMMON_DEAD_DESPAWN, 0); - } - } - } - void EnterCombat(Unit* /*who*/) { + _EnterCombat(); events.ScheduleEvent(EVENT_REND, 8000); events.ScheduleEvent(EVENT_BACKHAND, 9000); events.ScheduleEvent(EVENT_FRENZY, 1000); } - void UpdateAI(uint32 const diff) + void UpdateAI(uint32 diff) { if (!UpdateVictim()) return; diff --git a/src/server/scripts/EasternKingdoms/Scholomance/boss_illucia_barov.cpp b/src/server/scripts/EasternKingdoms/Scholomance/boss_illucia_barov.cpp index 54fc9e4a17e..5ea6c86d23e 100644 --- a/src/server/scripts/EasternKingdoms/Scholomance/boss_illucia_barov.cpp +++ b/src/server/scripts/EasternKingdoms/Scholomance/boss_illucia_barov.cpp @@ -1,6 +1,5 @@ /* * Copyright (C) 2008-2013 TrinityCore <http://www.trinitycore.org/> - * Copyright (C) 2006-2009 ScriptDev2 <https://scriptdev2.svn.sourceforge.net/> * * 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 @@ -16,12 +15,12 @@ * with this program. If not, see <http://www.gnu.org/licenses/>. */ -/* ScriptData -SDName: Boss_Illucia_Barov -SD%Complete: 100 -SDComment: -SDCategory: Scholomance -EndScriptData */ +/* +Name: Boss_Illucia_Barov +%Complete: 100 +Comment: +Category: Scholomance +*/ #include "ScriptMgr.h" #include "ScriptedCreature.h" @@ -49,34 +48,18 @@ class boss_illucia_barov : public CreatureScript struct boss_illuciabarovAI : public BossAI { - boss_illuciabarovAI(Creature* creature) : BossAI(creature,DATA_LADYILLUCIABAROV) {} - - void Reset() {} - - void JustDied(Unit* /*killer*/) - { - InstanceScript* instance = me->GetInstanceScript(); - if (instance) - { - instance->SetData(DATA_LADYILLUCIABAROV, DONE); - - if (instance->GetData(TYPE_GANDLING) == IN_PROGRESS) - { - instance->SetData(TYPE_GANDLING, IN_PROGRESS); - me->SummonCreature(1853, 180.73f, -9.43856f, 75.507f, 1.61399f, TEMPSUMMON_DEAD_DESPAWN, 0); - } - } - } + boss_illuciabarovAI(Creature* creature) : BossAI(creature, DATA_LADYILLUCIABAROV) {} void EnterCombat(Unit* /*who*/) { + _EnterCombat(); events.ScheduleEvent(EVENT_CURSEOFAGONY, 18000); events.ScheduleEvent(EVENT_SHADOWSHOCK, 9000); events.ScheduleEvent(EVENT_SILENCE, 5000); events.ScheduleEvent(EVENT_FEAR, 30000); } - void UpdateAI(uint32 const diff) + void UpdateAI(uint32 diff) { if (!UpdateVictim()) return; @@ -95,7 +78,7 @@ class boss_illucia_barov : public CreatureScript events.ScheduleEvent(EVENT_CURSEOFAGONY, 30000); break; case EVENT_SHADOWSHOCK: - DoCast(SelectTarget(SELECT_TARGET_RANDOM,0, 100, true),SPELL_SHADOWSHOCK,true); + DoCast(SelectTarget(SELECT_TARGET_RANDOM, 0, 100, true), SPELL_SHADOWSHOCK, true); events.ScheduleEvent(EVENT_SHADOWSHOCK, 12000); break; case EVENT_SILENCE: diff --git a/src/server/scripts/EasternKingdoms/Scholomance/boss_instructor_malicia.cpp b/src/server/scripts/EasternKingdoms/Scholomance/boss_instructor_malicia.cpp index daf03f41db5..1d311a7bd2c 100644 --- a/src/server/scripts/EasternKingdoms/Scholomance/boss_instructor_malicia.cpp +++ b/src/server/scripts/EasternKingdoms/Scholomance/boss_instructor_malicia.cpp @@ -1,6 +1,5 @@ /* * Copyright (C) 2008-2013 TrinityCore <http://www.trinitycore.org/> - * Copyright (C) 2006-2009 ScriptDev2 <https://scriptdev2.svn.sourceforge.net/> * * 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 @@ -58,27 +57,14 @@ class boss_instructor_malicia : public CreatureScript void Reset() { + _Reset(); FlashCounter = 0; TouchCounter = 0; } - void JustDied(Unit* /*killer*/) - { - InstanceScript* instance = me->GetInstanceScript(); - if (instance) - { - instance->SetData(DATA_INSTRUCTORMALICIA, DONE); - - if (instance->GetData(TYPE_GANDLING) == IN_PROGRESS) - { - instance->SetData(TYPE_GANDLING, IN_PROGRESS); - me->SummonCreature(1853, 180.73f, -9.43856f, 75.507f, 1.61399f, TEMPSUMMON_DEAD_DESPAWN, 0); - } - } - } - void EnterCombat(Unit* /*who*/) { + _EnterCombat(); events.ScheduleEvent(EVENT_CALLOFGRAVES, 4000); events.ScheduleEvent(EVENT_CORRUPTION, 8000); events.ScheduleEvent(EVENT_RENEW, 32000); @@ -86,7 +72,7 @@ class boss_instructor_malicia : public CreatureScript events.ScheduleEvent(EVENT_HEALINGTOUCH, 45000); } - void UpdateAI(uint32 const diff) + void UpdateAI(uint32 diff) { if (!UpdateVictim()) return; @@ -105,7 +91,7 @@ class boss_instructor_malicia : public CreatureScript events.ScheduleEvent(EVENT_CALLOFGRAVES, 65000); break; case EVENT_CORRUPTION: - DoCast(SelectTarget(SELECT_TARGET_RANDOM,0, 100, true),SPELL_CORRUPTION,true); + DoCast(SelectTarget(SELECT_TARGET_RANDOM, 0, 100, true), SPELL_CORRUPTION, true); events.ScheduleEvent(EVENT_CORRUPTION, 24000); break; case EVENT_RENEW: diff --git a/src/server/scripts/EasternKingdoms/Scholomance/boss_jandice_barov.cpp b/src/server/scripts/EasternKingdoms/Scholomance/boss_jandice_barov.cpp index c9cf4aa9020..3f083a30987 100644 --- a/src/server/scripts/EasternKingdoms/Scholomance/boss_jandice_barov.cpp +++ b/src/server/scripts/EasternKingdoms/Scholomance/boss_jandice_barov.cpp @@ -70,7 +70,7 @@ public: Illusion->AI()->AttackStart(victim); } - void UpdateAI(const uint32 diff) + void UpdateAI(uint32 diff) { if (Invisible && Invisible_Timer <= diff) { @@ -180,7 +180,7 @@ public: { } - void UpdateAI(const uint32 diff) + void UpdateAI(uint32 diff) { //Return since we have no target if (!UpdateVictim()) diff --git a/src/server/scripts/EasternKingdoms/Scholomance/boss_kirtonos_the_herald.cpp b/src/server/scripts/EasternKingdoms/Scholomance/boss_kirtonos_the_herald.cpp index 68d7dcdebe8..97b8e0334ee 100644 --- a/src/server/scripts/EasternKingdoms/Scholomance/boss_kirtonos_the_herald.cpp +++ b/src/server/scripts/EasternKingdoms/Scholomance/boss_kirtonos_the_herald.cpp @@ -57,32 +57,34 @@ enum Events EVENT_KIRTONOS_TRANSFORM = 14 }; -enum Misc +enum eMisc { WEAPON_KIRTONOS_STAFF = 11365, POINT_KIRTONOS_LAND = 13, KIRTONOS_PATH = 105061 }; +Position const PosMove[2] = +{ + { 299.4884f, 92.76137f, 105.6335f, 0.0f }, + { 314.8673f, 90.30210f, 101.6459f, 0.0f } +}; + class boss_kirtonos_the_herald : public CreatureScript { public: boss_kirtonos_the_herald() : CreatureScript("boss_kirtonos_the_herald") { } struct boss_kirtonos_the_heraldAI : public BossAI { - boss_kirtonos_the_heraldAI(Creature* creature) : BossAI(creature, TYPE_KIRTONOS) { } + boss_kirtonos_the_heraldAI(Creature* creature) : BossAI(creature, DATA_KIRTONOS) { } void Reset() { - _introEvent = 0; - _introTimer = 0; _Reset(); } void EnterCombat(Unit* /*who*/) { - _introTimer = 0; - _introEvent = 0; events.ScheduleEvent(EVENT_SWOOP, urand(8000, 8000)); events.ScheduleEvent(EVENT_WING_FLAP, urand(15000, 15000)); events.ScheduleEvent(EVENT_PIERCE_ARMOR, urand(18000, 18000)); @@ -103,8 +105,7 @@ class boss_kirtonos_the_herald : public CreatureScript brazier->ResetDoorOrButton(); brazier->SetGoState(GO_STATE_READY); } - if (instance) - instance->SetData(TYPE_KIRTONOS, DONE); + _JustDied(); } void EnterEvadeMode() @@ -121,12 +122,10 @@ class boss_kirtonos_the_herald : public CreatureScript void IsSummonedBy(Unit* /*summoner*/) { + events.ScheduleEvent(INTRO_1, 500); me->SetDisableGravity(true); me->SetReactState(REACT_PASSIVE); me->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE|UNIT_FLAG_NOT_SELECTABLE); - _introEvent = INTRO_1; - _introTimer = 1; - _currentPoint = 0; Talk(EMOTE_SUMMONED); } @@ -139,68 +138,58 @@ class boss_kirtonos_the_herald : public CreatureScript { if (type == WAYPOINT_MOTION_TYPE && id == POINT_KIRTONOS_LAND) { - _introTimer = 1500; - _introEvent = INTRO_2; + events.ScheduleEvent(INTRO_2, 1500); } } - void UpdateAI(uint32 const diff) + void UpdateAI(uint32 diff) { - if (_introEvent) + events.Update(diff); + + while (uint32 eventId = events.ExecuteEvent() && !UpdateVictim()) { - if (_introTimer <= diff) + switch (eventId) { - switch (_introEvent) - { - case INTRO_1: - me->GetMotionMaster()->MovePath(KIRTONOS_PATH,false); - _introEvent = 0; - break; - case INTRO_2: - me->GetMotionMaster()->MovePoint(0, 299.4884f, 92.76137f, 105.6335f); - _introTimer = 1000; - _introEvent = INTRO_3; - break; - case INTRO_3: - if (GameObject* gate = me->GetMap()->GetGameObject(instance->GetData64(GO_GATE_KIRTONOS))) - gate->SetGoState(GO_STATE_READY); - me->SetFacingTo(0.01745329f); - _introTimer = 3000; - _introEvent = INTRO_4; - break; - case INTRO_4: - if (GameObject* brazier = me->GetMap()->GetGameObject(instance->GetData64(GO_BRAZIER_OF_THE_HERALD))) - brazier->SetGoState(GO_STATE_READY); - me->SetWalk(true); - me->SetDisableGravity(false); - DoCast(me, SPELL_KIRTONOS_TRANSFORM); - me->SetCanFly(false); - _introTimer = 1000; - _introEvent = INTRO_5; - break; - case INTRO_5: - me->HandleEmoteCommand(EMOTE_ONESHOT_ROAR); - me->SetUInt32Value(UNIT_VIRTUAL_ITEM_SLOT_ID + 0, uint32(WEAPON_KIRTONOS_STAFF)); - me->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE|UNIT_FLAG_NOT_SELECTABLE); - me->SetReactState(REACT_AGGRESSIVE); - _introTimer = 5000; - _introEvent = INTRO_6; - case INTRO_6: - me->GetMotionMaster()->MovePoint(0, 314.8673f, 90.3021f, 101.6459f); - _introTimer = 0; - _introEvent = 0; + case INTRO_1: + me->GetMotionMaster()->MovePath(KIRTONOS_PATH, false); + break; + case INTRO_2: + me->GetMotionMaster()->MovePoint(0, PosMove[0]); + events.ScheduleEvent(INTRO_3, 1000); + break; + case INTRO_3: + if (GameObject* gate = me->GetMap()->GetGameObject(instance->GetData64(GO_GATE_KIRTONOS))) + gate->SetGoState(GO_STATE_READY); + me->SetFacingTo(0.01745329f); + events.ScheduleEvent(INTRO_4, 3000); + break; + case INTRO_4: + if (GameObject* brazier = me->GetMap()->GetGameObject(instance->GetData64(GO_BRAZIER_OF_THE_HERALD))) + brazier->SetGoState(GO_STATE_READY); + me->SetWalk(true); + me->SetDisableGravity(false); + DoCast(me, SPELL_KIRTONOS_TRANSFORM); + me->SetCanFly(false); + events.ScheduleEvent(INTRO_5, 1000); + break; + case INTRO_5: + me->HandleEmoteCommand(EMOTE_ONESHOT_ROAR); + me->SetUInt32Value(UNIT_VIRTUAL_ITEM_SLOT_ID + 0, uint32(WEAPON_KIRTONOS_STAFF)); + me->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE|UNIT_FLAG_NOT_SELECTABLE); + me->SetReactState(REACT_AGGRESSIVE); + events.ScheduleEvent(INTRO_6, 5000); + break; + case INTRO_6: + me->GetMotionMaster()->MovePoint(0, PosMove[1]); + break; + default: break; - } } - else - _introTimer -= diff; } if (!UpdateVictim()) return; - events.Update(diff); - if (me->HasUnitState(UNIT_STATE_CASTING)) return; @@ -258,11 +247,6 @@ class boss_kirtonos_the_herald : public CreatureScript DoMeleeAttackIfReady(); } - - private: - uint8 _introEvent; - uint32 _introTimer; - uint32 _currentPoint; }; CreatureAI* GetAI(Creature* creature) const @@ -281,6 +265,11 @@ enum Brazier_Of_The_Herald SOUND_SCREECH = 557 }; +Position const PosSummon[1] = +{ + { 315.028f, 70.53845f, 102.1496f, 0.3859715f } +}; + class go_brazier_of_the_herald : public GameObjectScript { public: @@ -290,7 +279,7 @@ class go_brazier_of_the_herald : public GameObjectScript { go->UseDoorOrButton(); go->PlayDirectSound(SOUND_SCREECH, 0); - player->SummonCreature(NPC_KIRTONOS, 315.028f, 70.53845f, 102.1496f, 0.3859715f, TEMPSUMMON_DEAD_DESPAWN, 900000); + player->SummonCreature(NPC_KIRTONOS, PosSummon[0], TEMPSUMMON_DEAD_DESPAWN, 900000); return true; } }; diff --git a/src/server/scripts/EasternKingdoms/Scholomance/boss_kormok.cpp b/src/server/scripts/EasternKingdoms/Scholomance/boss_kormok.cpp index a0dc31c4dff..1167a945992 100644 --- a/src/server/scripts/EasternKingdoms/Scholomance/boss_kormok.cpp +++ b/src/server/scripts/EasternKingdoms/Scholomance/boss_kormok.cpp @@ -74,7 +74,7 @@ public: SummonedMage->AI()->AttackStart(victim); } - void UpdateAI(const uint32 diff) + void UpdateAI(uint32 diff) { if (!UpdateVictim()) return; diff --git a/src/server/scripts/EasternKingdoms/Scholomance/boss_lord_alexei_barov.cpp b/src/server/scripts/EasternKingdoms/Scholomance/boss_lord_alexei_barov.cpp index 55ef0605c31..d0028894067 100644 --- a/src/server/scripts/EasternKingdoms/Scholomance/boss_lord_alexei_barov.cpp +++ b/src/server/scripts/EasternKingdoms/Scholomance/boss_lord_alexei_barov.cpp @@ -1,6 +1,5 @@ /* * Copyright (C) 2008-2013 TrinityCore <http://www.trinitycore.org/> - * Copyright (C) 2006-2009 ScriptDev2 <https://scriptdev2.svn.sourceforge.net/> * * 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 @@ -49,31 +48,18 @@ class boss_lord_alexei_barov : public CreatureScript void Reset() { + _Reset(); me->LoadCreaturesAddon(); } - void JustDied(Unit* /*killer*/) - { - InstanceScript* instance = me->GetInstanceScript(); - if (instance) - { - instance->SetData(DATA_LORDALEXEIBAROV, DONE); - - if (instance->GetData(TYPE_GANDLING) == IN_PROGRESS) - { - instance->SetData(TYPE_GANDLING, IN_PROGRESS); - me->SummonCreature(1853, 180.73f, -9.43856f, 75.507f, 1.61399f, TEMPSUMMON_DEAD_DESPAWN, 0); - } - } - } - void EnterCombat(Unit* /*who*/) { + _EnterCombat(); events.ScheduleEvent(EVENT_IMMOLATE, 7000); events.ScheduleEvent(EVENT_VEILOFSHADOW, 15000); } - void UpdateAI(uint32 const diff) + void UpdateAI(uint32 diff) { if (!UpdateVictim()) return; @@ -88,7 +74,7 @@ class boss_lord_alexei_barov : public CreatureScript switch (eventId) { case EVENT_IMMOLATE: - DoCast(SelectTarget(SELECT_TARGET_RANDOM,0, 100, true),SPELL_IMMOLATE,true); + DoCast(SelectTarget(SELECT_TARGET_RANDOM, 0, 100, true), SPELL_IMMOLATE, true); events.ScheduleEvent(EVENT_IMMOLATE, 12000); break; case EVENT_VEILOFSHADOW: diff --git a/src/server/scripts/EasternKingdoms/Scholomance/boss_lorekeeper_polkelt.cpp b/src/server/scripts/EasternKingdoms/Scholomance/boss_lorekeeper_polkelt.cpp index cc9180ded76..f7170a0618f 100644 --- a/src/server/scripts/EasternKingdoms/Scholomance/boss_lorekeeper_polkelt.cpp +++ b/src/server/scripts/EasternKingdoms/Scholomance/boss_lorekeeper_polkelt.cpp @@ -1,6 +1,5 @@ /* * Copyright (C) 2008-2013 TrinityCore <http://www.trinitycore.org/> - * Copyright (C) 2006-2009 ScriptDev2 <https://scriptdev2.svn.sourceforge.net/> * * 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 @@ -16,12 +15,12 @@ * with this program. If not, see <http://www.gnu.org/licenses/>. */ -/* ScriptData -SDName: Boss_Lorekeeper_Polkelt -SD%Complete: 100 -SDComment: -SDCategory: Scholomance -EndScriptData */ +/* +Name: Boss_Lorekeeper_Polkelt +%Complete: 100 +Comment: +Category: Scholomance +*/ #include "ScriptMgr.h" #include "ScriptedCreature.h" @@ -51,32 +50,16 @@ class boss_lorekeeper_polkelt : public CreatureScript { boss_lorekeeperpolkeltAI(Creature* creature) : BossAI(creature, DATA_LOREKEEPERPOLKELT) {} - void Reset() {} - - void JustDied(Unit* /*killer*/) - { - InstanceScript* instance = me->GetInstanceScript(); - if (instance) - { - instance->SetData(DATA_LOREKEEPERPOLKELT, DONE); - - if (instance->GetData(TYPE_GANDLING) == IN_PROGRESS) - { - instance->SetData(TYPE_GANDLING, IN_PROGRESS); - me->SummonCreature(1853, 180.73f, -9.43856f, 75.507f, 1.61399f, TEMPSUMMON_DEAD_DESPAWN, 0); - } - } - } - void EnterCombat(Unit* /*who*/) { + _EnterCombat(); events.ScheduleEvent(EVENT_VOLATILEINFECTION, 38000); events.ScheduleEvent(EVENT_DARKPLAGUE, 8000); events.ScheduleEvent(EVENT_CORROSIVEACID, 45000); events.ScheduleEvent(EVENT_NOXIOUSCATALYST, 35000); } - void UpdateAI(uint32 const diff) + void UpdateAI(uint32 diff) { if (!UpdateVictim()) return; diff --git a/src/server/scripts/EasternKingdoms/Scholomance/boss_ras_frostwhisper.cpp b/src/server/scripts/EasternKingdoms/Scholomance/boss_ras_frostwhisper.cpp index 99f01ee96c3..4483d5332d7 100644 --- a/src/server/scripts/EasternKingdoms/Scholomance/boss_ras_frostwhisper.cpp +++ b/src/server/scripts/EasternKingdoms/Scholomance/boss_ras_frostwhisper.cpp @@ -71,7 +71,7 @@ public: void EnterCombat(Unit* /*who*/){} - void UpdateAI(const uint32 diff) + void UpdateAI(uint32 diff) { if (!UpdateVictim()) return; diff --git a/src/server/scripts/EasternKingdoms/Scholomance/boss_the_ravenian.cpp b/src/server/scripts/EasternKingdoms/Scholomance/boss_the_ravenian.cpp index 5a6f5d436c4..14caccb8b00 100644 --- a/src/server/scripts/EasternKingdoms/Scholomance/boss_the_ravenian.cpp +++ b/src/server/scripts/EasternKingdoms/Scholomance/boss_the_ravenian.cpp @@ -1,6 +1,5 @@ /* * Copyright (C) 2008-2013 TrinityCore <http://www.trinitycore.org/> - * Copyright (C) 2006-2009 ScriptDev2 <https://scriptdev2.svn.sourceforge.net/> * * 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 @@ -16,12 +15,12 @@ * with this program. If not, see <http://www.gnu.org/licenses/>. */ -/* ScriptData -SDName: Boss_the_ravenian -SD%Complete: 100 -SDComment: -SDCategory: Scholomance -EndScriptData */ +/* +Name: Boss_the_ravenian +%Complete: 100 +Comment: +Category: Scholomance +*/ #include "ScriptMgr.h" #include "ScriptedCreature.h" @@ -43,7 +42,6 @@ enum Events EVENT_KNOCKAWAY = 4 }; - class boss_the_ravenian : public CreatureScript { public: boss_the_ravenian() : CreatureScript("boss_the_ravenian") { } @@ -52,32 +50,16 @@ class boss_the_ravenian : public CreatureScript { boss_theravenianAI(Creature* creature) : BossAI(creature, DATA_THERAVENIAN) {} - void Reset() {} - - void JustDied(Unit* /*killer*/) - { - InstanceScript* instance = me->GetInstanceScript(); - if (instance) - { - instance->SetData(DATA_THERAVENIAN, DONE); - - if (instance->GetData(TYPE_GANDLING) == IN_PROGRESS) - { - instance->SetData(TYPE_GANDLING, IN_PROGRESS); - me->SummonCreature(1853, 180.73f, -9.43856f, 75.507f, 1.61399f, TEMPSUMMON_DEAD_DESPAWN, 0); - } - } - } - void EnterCombat(Unit* /*who*/) { + _EnterCombat(); events.ScheduleEvent(EVENT_TRAMPLE, 24000); events.ScheduleEvent(EVENT_CLEAVE, 15000); events.ScheduleEvent(EVENT_SUNDERINCLEAVE, 40000); events.ScheduleEvent(EVENT_KNOCKAWAY, 32000); } - void UpdateAI(uint32 const diff) + void UpdateAI(uint32 diff) { if (!UpdateVictim()) return; diff --git a/src/server/scripts/EasternKingdoms/Scholomance/boss_vectus.cpp b/src/server/scripts/EasternKingdoms/Scholomance/boss_vectus.cpp index 054760981d2..85ae16499cf 100644 --- a/src/server/scripts/EasternKingdoms/Scholomance/boss_vectus.cpp +++ b/src/server/scripts/EasternKingdoms/Scholomance/boss_vectus.cpp @@ -60,7 +60,7 @@ public: m_uiFrenzy_Timer = 0; } - void UpdateAI(const uint32 uiDiff) + void UpdateAI(uint32 uiDiff) { if (!UpdateVictim()) return; diff --git a/src/server/scripts/EasternKingdoms/Scholomance/instance_scholomance.cpp b/src/server/scripts/EasternKingdoms/Scholomance/instance_scholomance.cpp index 04a12ae2bd2..0da31fbe428 100644 --- a/src/server/scripts/EasternKingdoms/Scholomance/instance_scholomance.cpp +++ b/src/server/scripts/EasternKingdoms/Scholomance/instance_scholomance.cpp @@ -1,6 +1,5 @@ /* * Copyright (C) 2008-2013 TrinityCore <http://www.trinitycore.org/> - * Copyright (C) 2006-2009 ScriptDev2 <https://scriptdev2.svn.sourceforge.net/> * * 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 @@ -16,131 +15,215 @@ * with this program. If not, see <http://www.gnu.org/licenses/>. */ -/* ScriptData -SDName: Instance_Scholomance -SD%Complete: 100 -SDComment: -SDCategory: Scholomance -EndScriptData */ - #include "ScriptMgr.h" #include "InstanceScript.h" +#include "Player.h" #include "scholomance.h" +Position const GandlingLoc = { 180.7712f, -5.428603f, 75.57024f, 1.291544f }; + class instance_scholomance : public InstanceMapScript { -public: - instance_scholomance() : InstanceMapScript("instance_scholomance", 289) { } - - InstanceScript* GetInstanceScript(InstanceMap* map) const - { - return new instance_scholomance_InstanceMapScript(map); - } - - struct instance_scholomance_InstanceMapScript : public InstanceScript - { - instance_scholomance_InstanceMapScript(Map* map) : InstanceScript(map) {} - - //Lord Alexei Barov, Doctor Theolen Krastinov, The Ravenian, Lorekeeper Polkelt, Instructor Malicia and the Lady Illucia Barov. - bool IsBossDied[6]; - uint32 m_auiEncounter[MAX_ENCOUNTER]; - - uint64 GateKirtonosGUID; - uint64 GateGandlingGUID; - uint64 GateMiliciaGUID; - uint64 GateTheolenGUID; - uint64 GatePolkeltGUID; - uint64 GateRavenianGUID; - uint64 GateBarovGUID; - uint64 GateIlluciaGUID; - uint64 BrazierOfTheHeraldGUID; - - void Initialize() + public: + instance_scholomance() : InstanceMapScript("instance_scholomance", 289) { } + + InstanceScript* GetInstanceScript(InstanceMap* map) const { - memset(&m_auiEncounter, 0, sizeof(m_auiEncounter)); - - GateKirtonosGUID = 0; - GateGandlingGUID = 0; - GateMiliciaGUID = 0; - GateTheolenGUID = 0; - GatePolkeltGUID = 0; - GateRavenianGUID = 0; - GateBarovGUID = 0; - GateIlluciaGUID = 0; - BrazierOfTheHeraldGUID = 0; - - for (uint8 i = 0; i < 6; ++i) - IsBossDied[i] = false; + return new instance_scholomance_InstanceMapScript(map); } - void OnGameObjectCreate(GameObject* go) + struct instance_scholomance_InstanceMapScript : public InstanceScript { - switch (go->GetEntry()) + instance_scholomance_InstanceMapScript(Map* map) : InstanceScript(map) { - case GO_GATE_KIRTONOS: GateKirtonosGUID = go->GetGUID(); break; - case GO_GATE_GANDLING: GateGandlingGUID = go->GetGUID(); break; - case GO_GATE_MALICIA: GateMiliciaGUID = go->GetGUID(); break; - case GO_GATE_THEOLEN: GateTheolenGUID = go->GetGUID(); break; - case GO_GATE_POLKELT: GatePolkeltGUID = go->GetGUID(); break; - case GO_GATE_RAVENIAN: GateRavenianGUID = go->GetGUID(); break; - case GO_GATE_BAROV: GateBarovGUID = go->GetGUID(); break; - case GO_GATE_ILLUCIA: GateIlluciaGUID = go->GetGUID(); break; - case GO_BRAZIER_OF_THE_HERALD: BrazierOfTheHeraldGUID = go->GetGUID(); break; + SetBossNumber(EncounterCount); + GateKirtonosGUID = 0; + GateGandlingGUID = 0; + GateMiliciaGUID = 0; + GateTheolenGUID = 0; + GatePolkeltGUID = 0; + GateRavenianGUID = 0; + GateBarovGUID = 0; + GateIlluciaGUID = 0; + BrazierOfTheHeraldGUID = 0; } - } - void SetData(uint32 type, uint32 data) - { - switch (type) + void OnGameObjectCreate(GameObject* go) { - case DATA_LORDALEXEIBAROV: - IsBossDied[0] = true; - break; - case DATA_DOCTORTHEOLENKRASTINOV: - IsBossDied[1] = true; - break; - case DATA_THERAVENIAN: - IsBossDied[2] = true; - break; - case DATA_LOREKEEPERPOLKELT: - IsBossDied[3] = true; - break; - case DATA_INSTRUCTORMALICIA: - IsBossDied[4] = true; - break; - case DATA_LADYILLUCIABAROV: - IsBossDied[5] = true; - break; - case TYPE_GANDLING: - m_auiEncounter[0] = data; - break; - case TYPE_KIRTONOS: - m_auiEncounter[1] = data; - break; + switch (go->GetEntry()) + { + case GO_GATE_KIRTONOS: + GateKirtonosGUID = go->GetGUID(); + break; + case GO_GATE_GANDLING: + GateGandlingGUID = go->GetGUID(); + break; + case GO_GATE_MALICIA: + GateMiliciaGUID = go->GetGUID(); + break; + case GO_GATE_THEOLEN: + GateTheolenGUID = go->GetGUID(); + break; + case GO_GATE_POLKELT: + GatePolkeltGUID = go->GetGUID(); + break; + case GO_GATE_RAVENIAN: + GateRavenianGUID = go->GetGUID(); + break; + case GO_GATE_BAROV: + GateBarovGUID = go->GetGUID(); + break; + case GO_GATE_ILLUCIA: + GateIlluciaGUID = go->GetGUID(); + break; + case GO_BRAZIER_OF_THE_HERALD: + BrazierOfTheHeraldGUID = go->GetGUID(); + break; + default: + break; + } } - } - uint32 GetData(uint32 type) const - { - return (type == TYPE_GANDLING && - IsBossDied[0] && IsBossDied[1] && IsBossDied[2] && - IsBossDied[3] && IsBossDied[4] && IsBossDied[5]) - ? IN_PROGRESS : 0; - } + bool SetBossState(uint32 type, EncounterState state) + { + if (!InstanceScript::SetBossState(type, state)) + return false; + + switch (type) + { + case DATA_LORDALEXEIBAROV: + case DATA_DOCTORTHEOLENKRASTINOV: + case DATA_THERAVENIAN: + case DATA_LOREKEEPERPOLKELT: + case DATA_INSTRUCTORMALICIA: + case DATA_LADYILLUCIABAROV: + CheckToSpawnGandling(); + break; + default: + break; + } + + return true; + } - uint64 GetData64(uint32 type) const - { - switch (type) + uint64 GetData64(uint32 type) const { - case GO_GATE_KIRTONOS: - return GateKirtonosGUID; - case GO_BRAZIER_OF_THE_HERALD: - return BrazierOfTheHeraldGUID; + switch (type) + { + case GO_GATE_KIRTONOS: + return GateKirtonosGUID; + case GO_GATE_GANDLING: + return GateGandlingGUID; + case GO_GATE_MALICIA: + return GateMiliciaGUID; + case GO_GATE_THEOLEN: + return GateTheolenGUID; + case GO_GATE_POLKELT: + return GatePolkeltGUID; + case GO_GATE_RAVENIAN: + return GateRavenianGUID; + case GO_GATE_BAROV: + return GateBarovGUID; + case GO_GATE_ILLUCIA: + return GateIlluciaGUID; + case GO_BRAZIER_OF_THE_HERALD: + return BrazierOfTheHeraldGUID; + default: + break; + } + + return 0; } - return 0; - } - }; + bool CheckPreBosses(uint32 bossId) const + { + switch (bossId) + { + case DATA_DARKMASTERGANDLING: + if (GetBossState(DATA_LORDALEXEIBAROV) != DONE) + return false; + if (GetBossState(DATA_DOCTORTHEOLENKRASTINOV) != DONE) + return false; + if (GetBossState(DATA_THERAVENIAN) != DONE) + return false; + if (GetBossState(DATA_LOREKEEPERPOLKELT) != DONE) + return false; + if (GetBossState(DATA_INSTRUCTORMALICIA) != DONE) + return false; + if (GetBossState(DATA_LADYILLUCIABAROV) != DONE) + return false; + if (GetBossState(DATA_DARKMASTERGANDLING) == DONE) + return false; + break; + default: + break; + } + + return true; + } + + void CheckToSpawnGandling() + { + if (CheckPreBosses(DATA_DARKMASTERGANDLING)) + instance->SummonCreature(NPC_DARKMASTER_GANDLING, GandlingLoc); + } + + std::string GetSaveData() + { + OUT_SAVE_INST_DATA; + + std::ostringstream saveStream; + saveStream << "S O " << GetBossSaveData(); + + OUT_SAVE_INST_DATA_COMPLETE; + return saveStream.str(); + } + + void Load(const char* str) + { + if (!str) + { + OUT_LOAD_INST_DATA_FAIL; + return; + } + + OUT_LOAD_INST_DATA(str); + + char dataHead1, dataHead2; + + std::istringstream loadStream(str); + loadStream >> dataHead1 >> dataHead2; + + if (dataHead1 == 'S' && dataHead2 == 'O') + { + for (uint32 i = 0; i < EncounterCount; ++i) + { + uint32 tmpState; + loadStream >> tmpState; + if (tmpState == IN_PROGRESS || tmpState > SPECIAL) + tmpState = NOT_STARTED; + SetBossState(i, EncounterState(tmpState)); + } + + CheckToSpawnGandling(); + } + else + OUT_LOAD_INST_DATA_FAIL; + + OUT_LOAD_INST_DATA_COMPLETE; + } + + protected: + uint64 GateKirtonosGUID; + uint64 GateGandlingGUID; + uint64 GateMiliciaGUID; + uint64 GateTheolenGUID; + uint64 GatePolkeltGUID; + uint64 GateRavenianGUID; + uint64 GateBarovGUID; + uint64 GateIlluciaGUID; + uint64 BrazierOfTheHeraldGUID; + }; }; void AddSC_instance_scholomance() diff --git a/src/server/scripts/EasternKingdoms/Scholomance/scholomance.h b/src/server/scripts/EasternKingdoms/Scholomance/scholomance.h index f89f36d91e5..5c38cc39e3d 100644 --- a/src/server/scripts/EasternKingdoms/Scholomance/scholomance.h +++ b/src/server/scripts/EasternKingdoms/Scholomance/scholomance.h @@ -1,6 +1,5 @@ /* * Copyright (C) 2008-2013 TrinityCore <http://www.trinitycore.org/> - * Copyright (C) 2006-2009 ScriptDev2 <https://scriptdev2.svn.sourceforge.net/> * * 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 @@ -19,30 +18,35 @@ #ifndef DEF_SCHOLOMANCE_H #define DEF_SCHOLOMANCE_H -uint32 const MAX_ENCOUNTER = 2; +uint32 const EncounterCount = 8; enum DataTypes { - TYPE_GANDLING = 1, - DATA_DOCTORTHEOLENKRASTINOV = 2, - DATA_INSTRUCTORMALICIA = 3, - DATA_LADYILLUCIABAROV = 4, - DATA_LORDALEXEIBAROV = 5, - DATA_LOREKEEPERPOLKELT = 6, - DATA_THERAVENIAN = 7, - TYPE_KIRTONOS = 8 + DATA_DOCTORTHEOLENKRASTINOV = 0, + DATA_INSTRUCTORMALICIA = 1, + DATA_LADYILLUCIABAROV = 2, + DATA_LORDALEXEIBAROV = 3, + DATA_LOREKEEPERPOLKELT = 4, + DATA_THERAVENIAN = 5, + DATA_DARKMASTERGANDLING = 6, + DATA_KIRTONOS = 7 +}; + +enum CreatureIds +{ + NPC_DARKMASTER_GANDLING = 1853 }; enum GameobjectIds { GO_GATE_KIRTONOS = 175570, GO_GATE_GANDLING = 177374, - GO_GATE_MALICIA = 177375, - GO_GATE_THEOLEN = 177377, - GO_GATE_POLKELT = 177376, GO_GATE_RAVENIAN = 177372, - GO_GATE_BAROV = 177373, + GO_GATE_THEOLEN = 177377, GO_GATE_ILLUCIA = 177371, + GO_GATE_MALICIA = 177375, + GO_GATE_BAROV = 177373, + GO_GATE_POLKELT = 177376, GO_BRAZIER_OF_THE_HERALD = 175564 }; diff --git a/src/server/scripts/EasternKingdoms/ShadowfangKeep/shadowfang_keep.cpp b/src/server/scripts/EasternKingdoms/ShadowfangKeep/shadowfang_keep.cpp index f9bd7d89216..7af7e1e78bc 100644 --- a/src/server/scripts/EasternKingdoms/ShadowfangKeep/shadowfang_keep.cpp +++ b/src/server/scripts/EasternKingdoms/ShadowfangKeep/shadowfang_keep.cpp @@ -172,7 +172,7 @@ public: uiDarkOffering = urand(200, 1000); } - void UpdateAI(uint32 const uiDiff) + void UpdateAI(uint32 uiDiff) { if (!UpdateVictim()) return; diff --git a/src/server/scripts/EasternKingdoms/Stratholme/boss_baron_rivendare.cpp b/src/server/scripts/EasternKingdoms/Stratholme/boss_baron_rivendare.cpp index 2357f59b65d..8b49df5ca84 100644 --- a/src/server/scripts/EasternKingdoms/Stratholme/boss_baron_rivendare.cpp +++ b/src/server/scripts/EasternKingdoms/Stratholme/boss_baron_rivendare.cpp @@ -116,7 +116,7 @@ public: instance->SetData(TYPE_BARON, DONE); } - void UpdateAI(const uint32 diff) + void UpdateAI(uint32 diff) { if (!UpdateVictim()) return; diff --git a/src/server/scripts/EasternKingdoms/Stratholme/boss_baroness_anastari.cpp b/src/server/scripts/EasternKingdoms/Stratholme/boss_baroness_anastari.cpp index d72e226d2e2..b2adbecbe63 100644 --- a/src/server/scripts/EasternKingdoms/Stratholme/boss_baroness_anastari.cpp +++ b/src/server/scripts/EasternKingdoms/Stratholme/boss_baroness_anastari.cpp @@ -74,7 +74,7 @@ public: instance->SetData(TYPE_BARONESS, IN_PROGRESS); } - void UpdateAI(const uint32 diff) + void UpdateAI(uint32 diff) { if (!UpdateVictim()) return; diff --git a/src/server/scripts/EasternKingdoms/Stratholme/boss_cannon_master_willey.cpp b/src/server/scripts/EasternKingdoms/Stratholme/boss_cannon_master_willey.cpp index 909609baecc..74819269415 100644 --- a/src/server/scripts/EasternKingdoms/Stratholme/boss_cannon_master_willey.cpp +++ b/src/server/scripts/EasternKingdoms/Stratholme/boss_cannon_master_willey.cpp @@ -119,7 +119,7 @@ public: { } - void UpdateAI(const uint32 diff) + void UpdateAI(uint32 diff) { //Return since we have no target if (!UpdateVictim()) diff --git a/src/server/scripts/EasternKingdoms/Stratholme/boss_dathrohan_balnazzar.cpp b/src/server/scripts/EasternKingdoms/Stratholme/boss_dathrohan_balnazzar.cpp index 2cb00df38db..f75a0c4a3dc 100644 --- a/src/server/scripts/EasternKingdoms/Stratholme/boss_dathrohan_balnazzar.cpp +++ b/src/server/scripts/EasternKingdoms/Stratholme/boss_dathrohan_balnazzar.cpp @@ -120,7 +120,7 @@ public: { } - void UpdateAI(const uint32 uiDiff) + void UpdateAI(uint32 uiDiff) { if (!UpdateVictim()) return; diff --git a/src/server/scripts/EasternKingdoms/Stratholme/boss_magistrate_barthilas.cpp b/src/server/scripts/EasternKingdoms/Stratholme/boss_magistrate_barthilas.cpp index 5d75ce4fa16..5f4d1cbc0b9 100644 --- a/src/server/scripts/EasternKingdoms/Stratholme/boss_magistrate_barthilas.cpp +++ b/src/server/scripts/EasternKingdoms/Stratholme/boss_magistrate_barthilas.cpp @@ -85,7 +85,7 @@ public: { } - void UpdateAI(const uint32 diff) + void UpdateAI(uint32 diff) { //Return since we have no target if (!UpdateVictim()) diff --git a/src/server/scripts/EasternKingdoms/Stratholme/boss_maleki_the_pallid.cpp b/src/server/scripts/EasternKingdoms/Stratholme/boss_maleki_the_pallid.cpp index 0a7bdfad583..2812c1dd39b 100644 --- a/src/server/scripts/EasternKingdoms/Stratholme/boss_maleki_the_pallid.cpp +++ b/src/server/scripts/EasternKingdoms/Stratholme/boss_maleki_the_pallid.cpp @@ -72,7 +72,7 @@ public: instance->SetData(TYPE_PALLID, IN_PROGRESS); } - void UpdateAI(const uint32 diff) + void UpdateAI(uint32 diff) { //Return since we have no target if (!UpdateVictim()) diff --git a/src/server/scripts/EasternKingdoms/Stratholme/boss_nerubenkan.cpp b/src/server/scripts/EasternKingdoms/Stratholme/boss_nerubenkan.cpp index 75bdd2b06de..2cc16bc2972 100644 --- a/src/server/scripts/EasternKingdoms/Stratholme/boss_nerubenkan.cpp +++ b/src/server/scripts/EasternKingdoms/Stratholme/boss_nerubenkan.cpp @@ -84,7 +84,7 @@ public: pUndeadScarab->AI()->AttackStart(victim); } - void UpdateAI(const uint32 diff) + void UpdateAI(uint32 diff) { if (!UpdateVictim()) return; diff --git a/src/server/scripts/EasternKingdoms/Stratholme/boss_order_of_silver_hand.cpp b/src/server/scripts/EasternKingdoms/Stratholme/boss_order_of_silver_hand.cpp index e52fd3402e7..7c6ea86dfa5 100644 --- a/src/server/scripts/EasternKingdoms/Stratholme/boss_order_of_silver_hand.cpp +++ b/src/server/scripts/EasternKingdoms/Stratholme/boss_order_of_silver_hand.cpp @@ -136,7 +136,7 @@ public: } } - void UpdateAI(const uint32 diff) + void UpdateAI(uint32 diff) { //Return since we have no target if (!UpdateVictim()) diff --git a/src/server/scripts/EasternKingdoms/Stratholme/boss_postmaster_malown.cpp b/src/server/scripts/EasternKingdoms/Stratholme/boss_postmaster_malown.cpp index 5b0b39c1de2..3d0eaba9022 100644 --- a/src/server/scripts/EasternKingdoms/Stratholme/boss_postmaster_malown.cpp +++ b/src/server/scripts/EasternKingdoms/Stratholme/boss_postmaster_malown.cpp @@ -77,7 +77,7 @@ class boss_postmaster_malown : public CreatureScript Talk(SAY_KILL); } - void UpdateAI(uint32 const diff) + void UpdateAI(uint32 diff) { if (!UpdateVictim()) return; diff --git a/src/server/scripts/EasternKingdoms/Stratholme/boss_ramstein_the_gorger.cpp b/src/server/scripts/EasternKingdoms/Stratholme/boss_ramstein_the_gorger.cpp index 6d83093d13c..5cd69f561d6 100644 --- a/src/server/scripts/EasternKingdoms/Stratholme/boss_ramstein_the_gorger.cpp +++ b/src/server/scripts/EasternKingdoms/Stratholme/boss_ramstein_the_gorger.cpp @@ -82,7 +82,7 @@ public: instance->SetData(TYPE_RAMSTEIN, DONE); } - void UpdateAI(const uint32 diff) + void UpdateAI(uint32 diff) { //Return since we have no target if (!UpdateVictim()) diff --git a/src/server/scripts/EasternKingdoms/Stratholme/boss_timmy_the_cruel.cpp b/src/server/scripts/EasternKingdoms/Stratholme/boss_timmy_the_cruel.cpp index bd7c3519926..27249e84892 100644 --- a/src/server/scripts/EasternKingdoms/Stratholme/boss_timmy_the_cruel.cpp +++ b/src/server/scripts/EasternKingdoms/Stratholme/boss_timmy_the_cruel.cpp @@ -68,7 +68,7 @@ public: } } - void UpdateAI(const uint32 diff) + void UpdateAI(uint32 diff) { //Return since we have no target if (!UpdateVictim()) diff --git a/src/server/scripts/EasternKingdoms/Stratholme/stratholme.cpp b/src/server/scripts/EasternKingdoms/Stratholme/stratholme.cpp index 0798fe2e3b0..7208bbbee03 100644 --- a/src/server/scripts/EasternKingdoms/Stratholme/stratholme.cpp +++ b/src/server/scripts/EasternKingdoms/Stratholme/stratholme.cpp @@ -172,7 +172,7 @@ public: me->SummonCreature(ENTRY_FREED, me->GetPositionX(), me->GetPositionY(), me->GetPositionZ(), me->GetOrientation(), TEMPSUMMON_TIMED_DESPAWN, 300000); } - void UpdateAI(const uint32 diff) + void UpdateAI(uint32 diff) { if (Tagged) { @@ -244,7 +244,7 @@ public: } } - void UpdateAI(const uint32 diff) + void UpdateAI(uint32 diff) { if (Tagged) { diff --git a/src/server/scripts/EasternKingdoms/SunwellPlateau/boss_brutallus.cpp b/src/server/scripts/EasternKingdoms/SunwellPlateau/boss_brutallus.cpp index dab612828f8..d81c001889a 100644 --- a/src/server/scripts/EasternKingdoms/SunwellPlateau/boss_brutallus.cpp +++ b/src/server/scripts/EasternKingdoms/SunwellPlateau/boss_brutallus.cpp @@ -277,7 +277,7 @@ public: ScriptedAI::MoveInLineOfSight(who); } - void UpdateAI(const uint32 diff) + void UpdateAI(uint32 diff) { if (IsIntro) { diff --git a/src/server/scripts/EasternKingdoms/SunwellPlateau/boss_eredar_twins.cpp b/src/server/scripts/EasternKingdoms/SunwellPlateau/boss_eredar_twins.cpp index 6e3f024ac1d..eb2e4f1ae8b 100644 --- a/src/server/scripts/EasternKingdoms/SunwellPlateau/boss_eredar_twins.cpp +++ b/src/server/scripts/EasternKingdoms/SunwellPlateau/boss_eredar_twins.cpp @@ -114,7 +114,7 @@ public: if (instance) { - if (Creature *temp = Unit::GetCreature(*me, instance->GetData64(DATA_ALYTHESS))) + if (Creature* temp = Unit::GetCreature(*me, instance->GetData64(DATA_ALYTHESS))) { if (temp->isDead()) temp->Respawn(); @@ -145,7 +145,7 @@ public: if (instance) { - Creature *temp = Unit::GetCreature(*me, instance->GetData64(DATA_ALYTHESS)); + Creature* temp = Unit::GetCreature(*me, instance->GetData64(DATA_ALYTHESS)); if (temp && temp->isAlive() && !temp->getVictim()) temp->AI()->AttackStart(who); } @@ -217,7 +217,7 @@ public: } } - void UpdateAI(const uint32 diff) + void UpdateAI(uint32 diff) { if (!SisterDeath) { @@ -345,10 +345,12 @@ public: return new boss_alythessAI (creature); }; - struct boss_alythessAI : public Scripted_NoMovementAI + struct boss_alythessAI : public ScriptedAI { - boss_alythessAI(Creature* creature) : Scripted_NoMovementAI(creature) + boss_alythessAI(Creature* creature) : ScriptedAI(creature) { + SetCombatMovement(false); + instance = creature->GetInstanceScript(); IntroStepCounter = 10; } @@ -374,7 +376,7 @@ public: if (instance) { - if (Creature *temp = Unit::GetCreature((*me), instance->GetData64(DATA_SACROLASH))) + if (Creature* temp = Unit::GetCreature((*me), instance->GetData64(DATA_SACROLASH))) { if (temp->isDead()) temp->Respawn(); @@ -406,7 +408,7 @@ public: if (instance) { - Creature *temp = Unit::GetCreature(*me, instance->GetData64(DATA_SACROLASH)); + Creature* temp = Unit::GetCreature(*me, instance->GetData64(DATA_SACROLASH)); if (temp && temp->isAlive() && !temp->getVictim()) temp->AI()->AttackStart(who); } @@ -418,9 +420,7 @@ public: void AttackStart(Unit* who) { if (!me->isInCombat()) - { - Scripted_NoMovementAI::AttackStart(who); - } + ScriptedAI::AttackStart(who); } void MoveInLineOfSight(Unit* who) @@ -542,7 +542,7 @@ public: return 10000; } - void UpdateAI(const uint32 diff) + void UpdateAI(uint32 diff) { if (IntroStepCounter < 9) { @@ -707,7 +707,7 @@ public: } } - void UpdateAI(const uint32 diff) + void UpdateAI(uint32 diff) { if (!me->HasAura(SPELL_IMAGE_VISUAL)) DoCast(me, SPELL_IMAGE_VISUAL); diff --git a/src/server/scripts/EasternKingdoms/SunwellPlateau/boss_felmyst.cpp b/src/server/scripts/EasternKingdoms/SunwellPlateau/boss_felmyst.cpp index 7f72da805ce..6ac6b9a4812 100644 --- a/src/server/scripts/EasternKingdoms/SunwellPlateau/boss_felmyst.cpp +++ b/src/server/scripts/EasternKingdoms/SunwellPlateau/boss_felmyst.cpp @@ -404,7 +404,7 @@ public: ++uiFlightCount; } - void UpdateAI(const uint32 diff) + void UpdateAI(uint32 diff) { if (!UpdateVictim()) { @@ -536,7 +536,7 @@ public: DoZoneInCombat(); //DoCast(me, SPELL_VAPOR_FORCE, true); core bug } - void UpdateAI(const uint32 /*diff*/) + void UpdateAI(uint32 /*diff*/) { if (!me->getVictim()) if (Unit* target = SelectTarget(SELECT_TARGET_RANDOM, 0, 100, true)) @@ -568,7 +568,7 @@ public: void EnterCombat(Unit* /*who*/) {} void AttackStart(Unit* /*who*/) {} void MoveInLineOfSight(Unit* /*who*/) {} - void UpdateAI(const uint32 /*diff*/) {} + void UpdateAI(uint32 /*diff*/) {} }; }; diff --git a/src/server/scripts/EasternKingdoms/SunwellPlateau/boss_kalecgos.cpp b/src/server/scripts/EasternKingdoms/SunwellPlateau/boss_kalecgos.cpp index a8755c16418..f6c9b79bbc1 100644 --- a/src/server/scripts/EasternKingdoms/SunwellPlateau/boss_kalecgos.cpp +++ b/src/server/scripts/EasternKingdoms/SunwellPlateau/boss_kalecgos.cpp @@ -182,7 +182,7 @@ public: ScriptedAI::EnterEvadeMode(); } - void DoAction(const int32 param) + void DoAction(int32 param) { switch (param) { @@ -197,7 +197,7 @@ public: } } - void UpdateAI(const uint32 diff) + void UpdateAI(uint32 diff) { if (TalkTimer) { @@ -485,7 +485,7 @@ public: damage *= 3; } - void UpdateAI(const uint32 diff) + void UpdateAI(uint32 diff) { if (!me->HasAura(AURA_SPECTRAL_INVISIBILITY)) me->CastSpell(me, AURA_SPECTRAL_INVISIBILITY, true); @@ -691,7 +691,7 @@ public: } } - void DoAction(const int32 param) + void DoAction(int32 param) { switch (param) { @@ -706,7 +706,7 @@ public: } } - void UpdateAI(const uint32 diff) + void UpdateAI(uint32 diff) { if (!me->HasAura(AURA_SPECTRAL_INVISIBILITY)) me->CastSpell(me, AURA_SPECTRAL_INVISIBILITY, true); @@ -780,8 +780,9 @@ public: if (AgonyCurseTimer <= diff) { - Unit* target = SelectTarget(SELECT_TARGET_RANDOM, 0); - if (!target) target = me->getVictim(); + Unit* target = SelectTarget(SELECT_TARGET_RANDOM, 1); + if (!target) + target = me->getVictim(); DoCast(target, SPELL_AGONY_CURSE); AgonyCurseTimer = 20000; } else AgonyCurseTimer -= diff; diff --git a/src/server/scripts/EasternKingdoms/SunwellPlateau/boss_kiljaeden.cpp b/src/server/scripts/EasternKingdoms/SunwellPlateau/boss_kiljaeden.cpp index 59face32389..9b95f4bb7c5 100644 --- a/src/server/scripts/EasternKingdoms/SunwellPlateau/boss_kiljaeden.cpp +++ b/src/server/scripts/EasternKingdoms/SunwellPlateau/boss_kiljaeden.cpp @@ -22,7 +22,7 @@ SDComment: Sinister Reflection Model, Armageddon Visual, SAY_KJ_SHADOWSPIKE3, Em SDCategory: Sunwell_Plateau EndScriptData */ -//TODO rewrite Armageddon +/// @todo rewrite Armageddon #include "ScriptMgr.h" #include "ScriptedCreature.h" @@ -105,7 +105,7 @@ enum Spells SPELL_ARMAGEDDON_DAMAGE = 45915, // This does the area damage /* Shield Orb Spells*/ - SPELL_SHADOW_BOLT = 45680, //45679 would be correct but triggers to often //TODO fix console error + SPELL_SHADOW_BOLT = 45680, //45679 would be correct but triggers to often /// @todo fix console error /* Anveena's spells and cosmetics (Or, generally, everything that has "Anveena" in name) */ SPELL_ANVEENA_PRISON = 46367, // She hovers locked within a bubble @@ -335,7 +335,7 @@ public: } } - void UpdateAI(const uint32 /*diff*/) + void UpdateAI(uint32 /*diff*/) { } @@ -392,11 +392,13 @@ public: return new mob_kiljaeden_controllerAI (creature); } - struct mob_kiljaeden_controllerAI : public Scripted_NoMovementAI + struct mob_kiljaeden_controllerAI : public ScriptedAI { - mob_kiljaeden_controllerAI(Creature* creature) : Scripted_NoMovementAI(creature), summons(me) + mob_kiljaeden_controllerAI(Creature* creature) : ScriptedAI(creature), summons(me) { instance = creature->GetInstanceScript(); + + SetCombatMovement(false); } InstanceScript* instance; @@ -452,7 +454,7 @@ public: summons.Summon(summoned); } - void UpdateAI(const uint32 diff) + void UpdateAI(uint32 diff) { if (uiRandomSayTimer < diff) { @@ -492,11 +494,13 @@ public: return new boss_kiljaedenAI (creature); } - struct boss_kiljaedenAI : public Scripted_NoMovementAI + struct boss_kiljaedenAI : public ScriptedAI { - boss_kiljaedenAI(Creature* creature) : Scripted_NoMovementAI(creature), summons(me) + boss_kiljaedenAI(Creature* creature) : ScriptedAI(creature), summons(me) { instance = creature->GetInstanceScript(); + + SetCombatMovement(false); } InstanceScript* instance; @@ -520,7 +524,7 @@ public: void InitializeAI() { - Scripted_NoMovementAI::InitializeAI(); + // Scripted_NoMovementAI::InitializeAI(); } void Reset() @@ -615,7 +619,8 @@ public: void EnterEvadeMode() { - Scripted_NoMovementAI::EnterEvadeMode(); + ScriptedAI::EnterEvadeMode(); + summons.DespawnAll(); // Reset the controller @@ -661,7 +666,7 @@ public: } } - void UpdateAI(const uint32 diff) + void UpdateAI(uint32 diff) { if (!UpdateVictim() || Phase < PHASE_NORMAL) return; @@ -779,7 +784,7 @@ public: break; case TIMER_FLAME_DART: //Phase 3 DoCastAOE(SPELL_FLAME_DART, false); - Timer[TIMER_FLAME_DART] = 3000; //TODO Timer + Timer[TIMER_FLAME_DART] = 3000; /// @todo Timer break; case TIMER_DARKNESS: //Phase 3 if (!me->IsNonMeleeSpellCasted(false)) @@ -913,7 +918,7 @@ public: void Reset() { - // TODO: Timers! + /// @todo Timers! ShadowBoltVolleyTimer = urand(8000, 14000); // So they don't all cast it in the same moment. FelfirePortalTimer = 20000; if (instance) @@ -946,7 +951,7 @@ public: ++(CAST_AI(mob_kiljaeden_controller::mob_kiljaeden_controllerAI, pControl->AI())->deceiverDeathCount); } - void UpdateAI(const uint32 diff) + void UpdateAI(uint32 diff) { if (!me->isInCombat()) DoCast(me, SPELL_SHADOW_CHANNELING); @@ -999,9 +1004,12 @@ public: return new mob_felfire_portalAI (creature); } - struct mob_felfire_portalAI : public Scripted_NoMovementAI + struct mob_felfire_portalAI : public ScriptedAI { - mob_felfire_portalAI(Creature* creature) : Scripted_NoMovementAI(creature) {} + mob_felfire_portalAI(Creature* creature) : ScriptedAI(creature) + { + SetCombatMovement(false); + } uint32 uiSpawnFiendTimer; @@ -1017,7 +1025,7 @@ public: summoned->SetLevel(me->getLevel()); } - void UpdateAI(const uint32 diff) + void UpdateAI(uint32 diff) { if (!UpdateVictim()) return; @@ -1063,7 +1071,7 @@ public: DoCast(me, SPELL_FELFIRE_FISSION, true); } - void UpdateAI(const uint32 diff) + void UpdateAI(uint32 diff) { if (!UpdateVictim()) return; @@ -1100,9 +1108,12 @@ public: return new mob_armageddonAI (creature); } - struct mob_armageddonAI : public Scripted_NoMovementAI + struct mob_armageddonAI : public ScriptedAI { - mob_armageddonAI(Creature* creature) : Scripted_NoMovementAI(creature) {} + mob_armageddonAI(Creature* creature) : ScriptedAI(creature) + { + SetCombatMovement(false); + } uint8 spell; uint32 uiTimer; @@ -1113,7 +1124,7 @@ public: uiTimer = 0; } - void UpdateAI(const uint32 diff) + void UpdateAI(uint32 diff) { if (uiTimer <= diff) { @@ -1182,7 +1193,7 @@ public: bClockwise = urand(0, 1); } - void UpdateAI(const uint32 diff) + void UpdateAI(uint32 diff) { if (bPointReached) { @@ -1256,7 +1267,7 @@ public: victimClass = 0; } - void UpdateAI(const uint32 diff) + void UpdateAI(uint32 diff) { if (!UpdateVictim()) return; diff --git a/src/server/scripts/EasternKingdoms/SunwellPlateau/boss_muru.cpp b/src/server/scripts/EasternKingdoms/SunwellPlateau/boss_muru.cpp index 5eb79258005..aa4acc24bfd 100644 --- a/src/server/scripts/EasternKingdoms/SunwellPlateau/boss_muru.cpp +++ b/src/server/scripts/EasternKingdoms/SunwellPlateau/boss_muru.cpp @@ -172,7 +172,7 @@ public: instance->SetData(DATA_MURU_EVENT, DONE); } - void UpdateAI(const uint32 diff) + void UpdateAI(uint32 diff) { if (!UpdateVictim()) return; @@ -213,10 +213,11 @@ public: return new boss_muruAI (creature); } - struct boss_muruAI : public Scripted_NoMovementAI + struct boss_muruAI : public ScriptedAI { - boss_muruAI(Creature* creature) : Scripted_NoMovementAI(creature), Summons(me) + boss_muruAI(Creature* creature) : ScriptedAI(creature), Summons(creature) { + SetCombatMovement(false); instance = creature->GetInstanceScript(); } @@ -285,7 +286,7 @@ public: Summons.Summon(summoned); } - void UpdateAI(const uint32 diff) + void UpdateAI(uint32 diff) { if (!UpdateVictim()) return; @@ -377,10 +378,11 @@ public: return new npc_muru_portalAI (creature); } - struct npc_muru_portalAI : public Scripted_NoMovementAI + struct npc_muru_portalAI : public ScriptedAI { - npc_muru_portalAI(Creature* creature) : Scripted_NoMovementAI(creature), Summons(me) + npc_muru_portalAI(Creature* creature) : ScriptedAI(creature), Summons(creature) { + SetCombatMovement(false); instance = creature->GetInstanceScript(); } @@ -432,7 +434,7 @@ public: } } - void UpdateAI(const uint32 diff) + void UpdateAI(uint32 diff) { if (!SummonSentinel) { @@ -482,7 +484,7 @@ public: me->DisappearAndDie(); } - void UpdateAI(const uint32 diff) + void UpdateAI(uint32 diff) { if (!UpdateVictim()) return; @@ -544,7 +546,7 @@ public: me->SummonCreature(CREATURE_VOID_SPAWN, me->GetPositionX(), me->GetPositionY(), me->GetPositionZ(), float(rand()%6), TEMPSUMMON_TIMED_OR_CORPSE_DESPAWN, 180000); } - void UpdateAI(const uint32 diff) + void UpdateAI(uint32 diff) { if (!UpdateVictim()) return; @@ -600,7 +602,7 @@ public: DoCastAOE(SPELL_BLACKHOLE_SPAWN, true); } - void UpdateAI(const uint32 diff) + void UpdateAI(uint32 diff) { if (SpellTimer <= diff) { diff --git a/src/server/scripts/EasternKingdoms/SunwellPlateau/instance_sunwell_plateau.cpp b/src/server/scripts/EasternKingdoms/SunwellPlateau/instance_sunwell_plateau.cpp index d575b7633cb..57699a34e17 100644 --- a/src/server/scripts/EasternKingdoms/SunwellPlateau/instance_sunwell_plateau.cpp +++ b/src/server/scripts/EasternKingdoms/SunwellPlateau/instance_sunwell_plateau.cpp @@ -122,7 +122,7 @@ public: return false; } - Player const * GetPlayerInMap() const + Player const* GetPlayerInMap() const { Map::PlayerList const& players = instance->GetPlayers(); diff --git a/src/server/scripts/EasternKingdoms/Uldaman/boss_archaedas.cpp b/src/server/scripts/EasternKingdoms/Uldaman/boss_archaedas.cpp index 87301f43745..ec9409af69f 100644 --- a/src/server/scripts/EasternKingdoms/Uldaman/boss_archaedas.cpp +++ b/src/server/scripts/EasternKingdoms/Uldaman/boss_archaedas.cpp @@ -102,7 +102,7 @@ class boss_archaedas : public CreatureScript DoCast(minion, SPELL_AWAKEN_VAULT_WALKER, flag); minion->CastSpell(minion, SPELL_ARCHAEDAS_AWAKEN, true); minion->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE); - minion->RemoveFlag(UNIT_FIELD_FLAGS,UNIT_FLAG_DISABLE_MOVE); + minion->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_DISABLE_MOVE); minion->setFaction(14); } } @@ -130,7 +130,7 @@ class boss_archaedas : public CreatureScript Talk(SAY_KILL); } - void UpdateAI(const uint32 uiDiff) + void UpdateAI(uint32 uiDiff) { if (!instance) return; @@ -278,7 +278,7 @@ class mob_archaedas_minions : public CreatureScript ScriptedAI::MoveInLineOfSight(who); } - void UpdateAI(const uint32 uiDiff) + void UpdateAI(uint32 uiDiff) { // we're still in the awaken animation if (bWakingUp && iAwakenTimer >= 0) @@ -347,7 +347,7 @@ class mob_stonekeepers : public CreatureScript me->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_DISABLE_MOVE); } - void UpdateAI(const uint32 /*diff*/) + void UpdateAI(uint32 /*diff*/) { //Return since we have no target if (!UpdateVictim()) @@ -399,35 +399,6 @@ class go_altar_of_archaedas : public GameObjectScript } }; -/* ScriptData -SDName: go_altar_of_the_keepers -SD%Complete: 100 -SDComment: Need 1 person to activate to open the altar. One by one the StoneKeepers will activate. After all four are dead than the door will open. -SDCategory: Uldaman -EndScriptData */ - -class go_altar_of_the_keepers : public GameObjectScript -{ - public: - - go_altar_of_the_keepers() - : GameObjectScript("go_altar_of_the_keepers") - { - } - - bool OnGossipHello(Player* player, GameObject* /*go*/) - { - InstanceScript* instance = player->GetInstanceScript(); - if (!instance) - return false; - - player->CastSpell (player, SPELL_BOSS_OBJECT_VISUAL, false); - - instance->SetData(DATA_STONE_KEEPERS, IN_PROGRESS); // activate the Stone Keepers - return false; - } -}; - //This is the actual function called only once durring InitScripts() //It must define all handled functions that are to be run in this script void AddSC_boss_archaedas() @@ -436,6 +407,5 @@ void AddSC_boss_archaedas() new mob_archaedas_minions(); new mob_stonekeepers(); new go_altar_of_archaedas(); - new go_altar_of_the_keepers(); } diff --git a/src/server/scripts/EasternKingdoms/Uldaman/boss_ironaya.cpp b/src/server/scripts/EasternKingdoms/Uldaman/boss_ironaya.cpp index 6f521060541..f40570d4130 100644 --- a/src/server/scripts/EasternKingdoms/Uldaman/boss_ironaya.cpp +++ b/src/server/scripts/EasternKingdoms/Uldaman/boss_ironaya.cpp @@ -63,7 +63,7 @@ class boss_ironaya : public CreatureScript Talk(SAY_AGGRO); } - void UpdateAI(const uint32 uiDiff) + void UpdateAI(uint32 uiDiff) { //Return since we have no target if (!UpdateVictim()) diff --git a/src/server/scripts/EasternKingdoms/Uldaman/instance_uldaman.cpp b/src/server/scripts/EasternKingdoms/Uldaman/instance_uldaman.cpp index 138243a9ce2..df87eaca5a8 100644 --- a/src/server/scripts/EasternKingdoms/Uldaman/instance_uldaman.cpp +++ b/src/server/scripts/EasternKingdoms/Uldaman/instance_uldaman.cpp @@ -33,38 +33,38 @@ enum eSpells SPELL_AWAKEN_VAULT_WALKER = 10258, }; +enum Events +{ + EVENT_SUB_BOSS_AGGRO = 2228 +}; + class instance_uldaman : public InstanceMapScript { public: - instance_uldaman() - : InstanceMapScript("instance_uldaman", 70) - { - } + instance_uldaman() : InstanceMapScript("instance_uldaman", 70) {} struct instance_uldaman_InstanceMapScript : public InstanceScript { - instance_uldaman_InstanceMapScript(Map* map) : InstanceScript(map) - { - } + instance_uldaman_InstanceMapScript(Map* map) : InstanceScript(map) {} void Initialize() { memset(&m_auiEncounter, 0, sizeof(m_auiEncounter)); - uiArchaedasGUID = 0; - uiIronayaGUID = 0; - uiWhoWokeuiArchaedasGUID = 0; + archaedasGUID = 0; + ironayaGUID = 0; + whoWokeuiArchaedasGUID = 0; - uiAltarOfTheKeeperTempleDoor = 0; - uiArchaedasTempleDoor = 0; - uiAncientVaultDoor = 0; + altarOfTheKeeperTempleDoor = 0; + archaedasTempleDoor = 0; + ancientVaultDoor = 0; - uiIronayaSealDoor = 0; + ironayaSealDoor = 0; - uiKeystoneGUID = 0; + keystoneGUID = 0; - uiIronayaSealDoorTimer = 27000; //animation time - bKeystoneCheck = false; + ironayaSealDoorTimer = 27000; //animation time + keystoneCheck = false; } bool IsEncounterInProgress() const @@ -76,25 +76,25 @@ class instance_uldaman : public InstanceMapScript return false; } - uint64 uiArchaedasGUID; - uint64 uiIronayaGUID; - uint64 uiWhoWokeuiArchaedasGUID; + uint64 archaedasGUID; + uint64 ironayaGUID; + uint64 whoWokeuiArchaedasGUID; - uint64 uiAltarOfTheKeeperTempleDoor; - uint64 uiArchaedasTempleDoor; - uint64 uiAncientVaultDoor; - uint64 uiIronayaSealDoor; + uint64 altarOfTheKeeperTempleDoor; + uint64 archaedasTempleDoor; + uint64 ancientVaultDoor; + uint64 ironayaSealDoor; - uint64 uiKeystoneGUID; + uint64 keystoneGUID; - uint32 uiIronayaSealDoorTimer; - bool bKeystoneCheck; + uint32 ironayaSealDoorTimer; + bool keystoneCheck; - std::vector<uint64> vStoneKeeper; - std::vector<uint64> vAltarOfTheKeeperCount; - std::vector<uint64> vVaultWalker; - std::vector<uint64> vEarthenGuardian; - std::vector<uint64> vArchaedasWallMinions; // minions lined up around the wall + std::vector<uint64> stoneKeepers; + std::vector<uint64> altarOfTheKeeperCounts; + std::vector<uint64> vaultWalkers; + std::vector<uint64> earthenGuardians; + std::vector<uint64> archaedasWallMinions; // minions lined up around the wall uint32 m_auiEncounter[MAX_ENCOUNTER]; std::string str_data; @@ -104,14 +104,14 @@ class instance_uldaman : public InstanceMapScript switch (go->GetEntry()) { case GO_ALTAR_OF_THE_KEEPER_TEMPLE_DOOR: // lock the door - uiAltarOfTheKeeperTempleDoor = go->GetGUID(); + altarOfTheKeeperTempleDoor = go->GetGUID(); if (m_auiEncounter[0] == DONE) HandleGameObject(0, true, go); break; case GO_ARCHAEDAS_TEMPLE_DOOR: - uiArchaedasTempleDoor = go->GetGUID(); + archaedasTempleDoor = go->GetGUID(); if (m_auiEncounter[0] == DONE) HandleGameObject(0, true, go); @@ -120,21 +120,21 @@ class instance_uldaman : public InstanceMapScript case GO_ANCIENT_VAULT_DOOR: go->SetGoState(GO_STATE_READY); go->SetUInt32Value(GAMEOBJECT_FLAGS, 33); - uiAncientVaultDoor = go->GetGUID(); + ancientVaultDoor = go->GetGUID(); if (m_auiEncounter[1] == DONE) HandleGameObject(0, true, go); break; case GO_IRONAYA_SEAL_DOOR: - uiIronayaSealDoor = go->GetGUID(); + ironayaSealDoor = go->GetGUID(); if (m_auiEncounter[2] == DONE) HandleGameObject(0, true, go); break; case GO_KEYSTONE: - uiKeystoneGUID = go->GetGUID(); + keystoneGUID = go->GetGUID(); if (m_auiEncounter[2] == DONE) { @@ -174,35 +174,38 @@ class instance_uldaman : public InstanceMapScript void ActivateStoneKeepers() { - for (std::vector<uint64>::const_iterator i = vStoneKeeper.begin(); i != vStoneKeeper.end(); ++i) + if (GetData(DATA_ALTAR_DOORS) != DONE) { - Creature* target = instance->GetCreature(*i); - if (!target || !target->isAlive() || target->getFaction() == 14) - continue; - target->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_DISABLE_MOVE); - target->setFaction(14); - target->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE); - return; // only want the first one we find + for (std::vector<uint64>::const_iterator i = stoneKeepers.begin(); i != stoneKeepers.end(); ++i) + { + Creature* target = instance->GetCreature(*i); + if (!target || !target->isAlive()) + continue; + target->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_DISABLE_MOVE); + target->setFaction(14); + target->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE); + return; // only want the first one we find + } + // if we get this far than all four are dead so open the door + SetData(DATA_ALTAR_DOORS, DONE); + SetDoor(archaedasTempleDoor, true); //open next the door too } - // if we get this far than all four are dead so open the door - SetData(DATA_ALTAR_DOORS, DONE); - SetDoor(uiArchaedasTempleDoor, true); //open next the door too } void ActivateWallMinions() { - Creature* archaedas = instance->GetCreature(uiArchaedasGUID); + Creature* archaedas = instance->GetCreature(archaedasGUID); if (!archaedas) return; - for (std::vector<uint64>::const_iterator i = vArchaedasWallMinions.begin(); i != vArchaedasWallMinions.end(); ++i) + for (std::vector<uint64>::const_iterator i = archaedasWallMinions.begin(); i != archaedasWallMinions.end(); ++i) { Creature* target = instance->GetCreature(*i); if (!target || !target->isAlive() || target->getFaction() == 14) continue; archaedas->CastSpell(target, SPELL_AWAKEN_VAULT_WALKER, true); target->CastSpell(target, SPELL_ARCHAEDAS_AWAKEN, true); - target->RemoveFlag(UNIT_FIELD_FLAGS,UNIT_FLAG_DISABLE_MOVE); + target->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_DISABLE_MOVE); target->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE); target->setFaction(14); return; // only want the first one we find @@ -213,7 +216,7 @@ class instance_uldaman : public InstanceMapScript void DeActivateMinions() { // first despawn any aggroed wall minions - for (std::vector<uint64>::const_iterator i = vArchaedasWallMinions.begin(); i != vArchaedasWallMinions.end(); ++i) + for (std::vector<uint64>::const_iterator i = archaedasWallMinions.begin(); i != archaedasWallMinions.end(); ++i) { Creature* target = instance->GetCreature(*i); if (!target || target->isDead() || target->getFaction() != 14) @@ -223,7 +226,7 @@ class instance_uldaman : public InstanceMapScript } // Vault Walkers - for (std::vector<uint64>::const_iterator i = vVaultWalker.begin(); i != vVaultWalker.end(); ++i) + for (std::vector<uint64>::const_iterator i = vaultWalkers.begin(); i != vaultWalkers.end(); ++i) { Creature* target = instance->GetCreature(*i); if (!target || target->isDead() || target->getFaction() != 14) @@ -233,7 +236,7 @@ class instance_uldaman : public InstanceMapScript } // Earthen Guardians - for (std::vector<uint64>::const_iterator i = vEarthenGuardian.begin(); i != vEarthenGuardian.end(); ++i) + for (std::vector<uint64>::const_iterator i = earthenGuardians.begin(); i != earthenGuardians.end(); ++i) { Creature* target = instance->GetCreature(*i); if (!target || target->isDead() || target->getFaction() != 14) @@ -245,20 +248,20 @@ class instance_uldaman : public InstanceMapScript void ActivateArchaedas(uint64 target) { - Creature* archaedas = instance->GetCreature(uiArchaedasGUID); + Creature* archaedas = instance->GetCreature(archaedasGUID); if (!archaedas) return; if (Unit::GetUnit(*archaedas, target)) { archaedas->CastSpell(archaedas, SPELL_ARCHAEDAS_AWAKEN, false); - uiWhoWokeuiArchaedasGUID = target; + whoWokeuiArchaedasGUID = target; } } void ActivateIronaya() { - Creature* ironaya = instance->GetCreature(uiIronayaGUID); + Creature* ironaya = instance->GetCreature(ironayaGUID); if (!ironaya) return; @@ -270,7 +273,7 @@ class instance_uldaman : public InstanceMapScript void RespawnMinions() { // first respawn any aggroed wall minions - for (std::vector<uint64>::const_iterator i = vArchaedasWallMinions.begin(); i != vArchaedasWallMinions.end(); ++i) + for (std::vector<uint64>::const_iterator i = archaedasWallMinions.begin(); i != archaedasWallMinions.end(); ++i) { Creature* target = instance->GetCreature(*i); if (target && target->isDead()) @@ -282,7 +285,7 @@ class instance_uldaman : public InstanceMapScript } // Vault Walkers - for (std::vector<uint64>::const_iterator i = vVaultWalker.begin(); i != vVaultWalker.end(); ++i) + for (std::vector<uint64>::const_iterator i = vaultWalkers.begin(); i != vaultWalkers.end(); ++i) { Creature* target = instance->GetCreature(*i); if (target && target->isDead()) @@ -294,7 +297,7 @@ class instance_uldaman : public InstanceMapScript } // Earthen Guardians - for (std::vector<uint64>::const_iterator i = vEarthenGuardian.begin(); i != vEarthenGuardian.end(); ++i) + for (std::vector<uint64>::const_iterator i = earthenGuardians.begin(); i != earthenGuardians.end(); ++i) { Creature* target = instance->GetCreature(*i); if (target && target->isDead()) @@ -307,21 +310,21 @@ class instance_uldaman : public InstanceMapScript } void Update(uint32 diff) { - if (!bKeystoneCheck) + if (!keystoneCheck) return; - if (uiIronayaSealDoorTimer <= diff) + if (ironayaSealDoorTimer <= diff) { ActivateIronaya(); - SetDoor(uiIronayaSealDoor, true); - BlockGO(uiKeystoneGUID); + SetDoor(ironayaSealDoor, true); + BlockGO(keystoneGUID); SetData(DATA_IRONAYA_DOOR, DONE); //save state - bKeystoneCheck = false; + keystoneCheck = false; } else - uiIronayaSealDoorTimer -= diff; + ironayaSealDoorTimer -= diff; } void SetData(uint32 type, uint32 data) @@ -331,15 +334,15 @@ class instance_uldaman : public InstanceMapScript case DATA_ALTAR_DOORS: m_auiEncounter[0] = data; if (data == DONE) - SetDoor(uiAltarOfTheKeeperTempleDoor, true); + SetDoor(altarOfTheKeeperTempleDoor, true); break; case DATA_ANCIENT_DOOR: m_auiEncounter[1] = data; if (data == DONE) //archeadas defeat { - SetDoor(uiArchaedasTempleDoor, true); //re open enter door - SetDoor(uiAncientVaultDoor, true); + SetDoor(archaedasTempleDoor, true); //re open enter door + SetDoor(ancientVaultDoor, true); } break; @@ -356,7 +359,7 @@ class instance_uldaman : public InstanceMapScript { case NOT_STARTED: if (m_auiEncounter[0] == DONE) //if players opened the doors - SetDoor(uiArchaedasTempleDoor, true); + SetDoor(archaedasTempleDoor, true); RespawnMinions(); break; @@ -372,7 +375,7 @@ class instance_uldaman : public InstanceMapScript break; case DATA_IRONAYA_SEAL: - bKeystoneCheck = true; + keystoneCheck = true; break; } @@ -396,7 +399,7 @@ class instance_uldaman : public InstanceMapScript if (type == 0) { ActivateArchaedas (data); - SetDoor(uiArchaedasTempleDoor, false); //close when event is started + SetDoor(archaedasTempleDoor, false); //close when event is started } } @@ -433,34 +436,34 @@ class instance_uldaman : public InstanceMapScript { case 4857: // Stone Keeper SetFrozenState (creature); - vStoneKeeper.push_back(creature->GetGUID()); + stoneKeepers.push_back(creature->GetGUID()); break; case 7309: // Earthen Custodian - vArchaedasWallMinions.push_back(creature->GetGUID()); + archaedasWallMinions.push_back(creature->GetGUID()); break; case 7077: // Earthen Hallshaper - vArchaedasWallMinions.push_back(creature->GetGUID()); + archaedasWallMinions.push_back(creature->GetGUID()); break; case 7076: // Earthen Guardian - vEarthenGuardian.push_back(creature->GetGUID()); + earthenGuardians.push_back(creature->GetGUID()); break; case 7228: // Ironaya - uiIronayaGUID = creature->GetGUID(); + ironayaGUID = creature->GetGUID(); if (m_auiEncounter[2] != DONE) SetFrozenState (creature); break; case 10120: // Vault Walker - vVaultWalker.push_back(creature->GetGUID()); + vaultWalkers.push_back(creature->GetGUID()); break; case 2748: // Archaedas - uiArchaedasGUID = creature->GetGUID(); + archaedasGUID = creature->GetGUID(); break; } @@ -471,25 +474,37 @@ class instance_uldaman : public InstanceMapScript switch (identifier) { case 0: - return uiWhoWokeuiArchaedasGUID; + return whoWokeuiArchaedasGUID; case 1: case 2: case 3: case 4: - return vVaultWalker.at(identifier - 1); + return vaultWalkers.at(identifier - 1); case 5: case 6: case 7: case 8: case 9: case 10: - return vEarthenGuardian.at(identifier - 5); + return earthenGuardians.at(identifier - 5); default: break; } return 0; } // end GetData64 + + void ProcessEvent(WorldObject* /*gameObject*/, uint32 eventId) + { + switch (eventId) + { + case EVENT_SUB_BOSS_AGGRO: + SetData(DATA_STONE_KEEPERS, IN_PROGRESS); // activate the Stone Keepers + break; + default: + break; + } + } }; InstanceScript* GetInstanceScript(InstanceMap* map) const diff --git a/src/server/scripts/EasternKingdoms/Uldaman/uldaman.cpp b/src/server/scripts/EasternKingdoms/Uldaman/uldaman.cpp index 0cd59951590..9fdc2f26d9f 100644 --- a/src/server/scripts/EasternKingdoms/Uldaman/uldaman.cpp +++ b/src/server/scripts/EasternKingdoms/Uldaman/uldaman.cpp @@ -68,7 +68,7 @@ class mob_jadespine_basilisk : public CreatureScript { } - void UpdateAI(const uint32 uiDiff) + void UpdateAI(uint32 uiDiff) { //Return since we have no target if (!UpdateVictim()) diff --git a/src/server/scripts/EasternKingdoms/ZulAman/boss_akilzon.cpp b/src/server/scripts/EasternKingdoms/ZulAman/boss_akilzon.cpp index 1b2512ccf63..ce526fb0ddc 100644 --- a/src/server/scripts/EasternKingdoms/ZulAman/boss_akilzon.cpp +++ b/src/server/scripts/EasternKingdoms/ZulAman/boss_akilzon.cpp @@ -201,8 +201,11 @@ class boss_akilzon : public CreatureScript //dealdamege for (std::list<Unit*>::const_iterator i = tempUnitMap.begin(); i != tempUnitMap.end(); ++i) { - if (!Cloud->IsWithinDist(*i, 6, false)) - Cloud->CastCustomSpell(*i, 43137, &bp0, NULL, NULL, true, 0, 0, me->GetGUID()); + if (Unit* target = (*i)) + { + if (!Cloud->IsWithinDist(target, 6, false)) + Cloud->CastCustomSpell(target, 43137, &bp0, NULL, NULL, true, 0, 0, me->GetGUID()); + } } // visual float x, y, z; @@ -237,7 +240,7 @@ class boss_akilzon : public CreatureScript StormSequenceTimer = 1000; } - void UpdateAI(const uint32 diff) + void UpdateAI(uint32 diff) { if (!UpdateVictim()) return; @@ -418,7 +421,7 @@ class mob_akilzon_eagle : public CreatureScript } } - void UpdateAI(const uint32 diff) + void UpdateAI(uint32 diff) { if (EagleSwoop_Timer <= diff) EagleSwoop_Timer = 0; diff --git a/src/server/scripts/EasternKingdoms/ZulAman/boss_halazzi.cpp b/src/server/scripts/EasternKingdoms/ZulAman/boss_halazzi.cpp index 935e54eae0c..21392fda660 100644 --- a/src/server/scripts/EasternKingdoms/ZulAman/boss_halazzi.cpp +++ b/src/server/scripts/EasternKingdoms/ZulAman/boss_halazzi.cpp @@ -45,32 +45,37 @@ EndScriptData */ #define YELL_BERSERK "Whatch you be doing? Pissin' yourselves..." #define SOUND_BERSERK 12025 -#define SPELL_DUAL_WIELD 29651 -#define SPELL_SABER_LASH 43267 -#define SPELL_FRENZY 43139 -#define SPELL_FLAMESHOCK 43303 -#define SPELL_EARTHSHOCK 43305 -#define SPELL_TRANSFORM_SPLIT 43142 -#define SPELL_TRANSFORM_SPLIT2 43573 -#define SPELL_TRANSFORM_MERGE 43271 -#define SPELL_SUMMON_LYNX 43143 -#define SPELL_SUMMON_TOTEM 43302 -#define SPELL_BERSERK 45078 - -#define MOB_SPIRIT_LYNX 24143 -#define SPELL_LYNX_FRENZY 43290 -#define SPELL_SHRED_ARMOR 43243 - -#define MOB_TOTEM 24224 +enum Spells +{ + SPELL_DUAL_WIELD = 29651, + SPELL_SABER_LASH = 43267, + SPELL_FRENZY = 43139, + SPELL_FLAMESHOCK = 43303, + SPELL_EARTHSHOCK = 43305, + SPELL_TRANSFORM_SPLIT = 43142, + SPELL_TRANSFORM_SPLIT2 = 43573, + SPELL_TRANSFORM_MERGE = 43271, + SPELL_SUMMON_LYNX = 43143, + SPELL_SUMMON_TOTEM = 43302, + SPELL_BERSERK = 45078, + SPELL_LYNX_FRENZY = 43290, // Used by Spirit Lynx + SPELL_SHRED_ARMOR = 43243 // Used by Spirit Lynx +}; + +enum Hal_CreatureIds +{ + NPC_SPIRIT_LYNX = 24143, + NPC_TOTEM = 24224 +}; enum PhaseHalazzi { - PHASE_NONE = 0, - PHASE_LYNX = 1, - PHASE_SPLIT = 2, - PHASE_HUMAN = 3, - PHASE_MERGE = 4, - PHASE_ENRAGE = 5 + PHASE_NONE = 0, + PHASE_LYNX = 1, + PHASE_SPLIT = 2, + PHASE_HUMAN = 3, + PHASE_MERGE = 4, + PHASE_ENRAGE = 5 }; class boss_halazzi : public CreatureScript @@ -134,7 +139,7 @@ class boss_halazzi : public CreatureScript void JustSummoned(Creature* summon) { summon->AI()->AttackStart(me->getVictim()); - if (summon->GetEntry() == MOB_SPIRIT_LYNX) + if (summon->GetEntry() == NPC_SPIRIT_LYNX) LynxGUID = summon->GetGUID(); } @@ -183,7 +188,7 @@ class boss_halazzi : public CreatureScript break; case PHASE_HUMAN: //DoCast(me, SPELL_SUMMON_LYNX, true); - DoSpawnCreature(MOB_SPIRIT_LYNX, 5, 5, 0, 0, TEMPSUMMON_CORPSE_DESPAWN, 0); + DoSpawnCreature(NPC_SPIRIT_LYNX, 5, 5, 0, 0, TEMPSUMMON_CORPSE_DESPAWN, 0); me->SetMaxHealth(400000); me->SetHealth(400000); ShockTimer = 10000; @@ -208,7 +213,7 @@ class boss_halazzi : public CreatureScript Phase = NextPhase; } - void UpdateAI(const uint32 diff) + void UpdateAI(uint32 diff) { if (!UpdateVictim()) return; @@ -379,7 +384,7 @@ class mob_halazzi_lynx : public CreatureScript void EnterCombat(Unit* /*who*/) {/*DoZoneInCombat();*/} - void UpdateAI(const uint32 diff) + void UpdateAI(uint32 diff) { if (!UpdateVictim()) return; @@ -413,3 +418,4 @@ void AddSC_boss_halazzi() new mob_halazzi_lynx(); } + diff --git a/src/server/scripts/EasternKingdoms/ZulAman/boss_hexlord.cpp b/src/server/scripts/EasternKingdoms/ZulAman/boss_hexlord.cpp index d3d7bd390ca..332baa29b51 100644 --- a/src/server/scripts/EasternKingdoms/ZulAman/boss_hexlord.cpp +++ b/src/server/scripts/EasternKingdoms/ZulAman/boss_hexlord.cpp @@ -198,7 +198,7 @@ struct boss_hexlord_addAI : public ScriptedAI DoZoneInCombat(); } - void UpdateAI(const uint32 /*diff*/) + void UpdateAI(uint32 /*diff*/) { if (instance && instance->GetData(DATA_HEXLORDEVENT) != IN_PROGRESS) { @@ -351,7 +351,7 @@ class boss_hexlord_malacrass : public CreatureScript } } - void UpdateAI(const uint32 diff) + void UpdateAI(uint32 diff) { if (!UpdateVictim()) return; @@ -511,7 +511,7 @@ class boss_thurg : public CreatureScript boss_hexlord_addAI::Reset(); } - void UpdateAI(const uint32 diff) + void UpdateAI(uint32 diff) { if (!UpdateVictim()) return; @@ -588,7 +588,7 @@ class boss_alyson_antille : public CreatureScript } } - void UpdateAI(const uint32 diff) + void UpdateAI(uint32 diff) { if (!UpdateVictim()) return; @@ -672,7 +672,7 @@ struct boss_gazakrothAI : public boss_hexlord_addAI } } - void UpdateAI(const uint32 diff) + void UpdateAI(uint32 diff) { if (!UpdateVictim()) return; @@ -714,7 +714,7 @@ class boss_lord_raadan : public CreatureScript boss_hexlord_addAI::Reset(); } - void UpdateAI(const uint32 diff) + void UpdateAI(uint32 diff) { if (!UpdateVictim()) return; @@ -763,7 +763,7 @@ class boss_darkheart : public CreatureScript psychicwail_timer = 8000; boss_hexlord_addAI::Reset(); } - void UpdateAI(const uint32 diff) + void UpdateAI(uint32 diff) { if (!UpdateVictim()) return; @@ -822,7 +822,7 @@ class boss_slither : public CreatureScript } } - void UpdateAI(const uint32 diff) + void UpdateAI(uint32 diff) { if (!UpdateVictim()) return; @@ -867,7 +867,7 @@ class boss_fenstalker : public CreatureScript boss_hexlord_addAI::Reset(); } - void UpdateAI(const uint32 diff) + void UpdateAI(uint32 diff) { if (!UpdateVictim()) return; @@ -916,7 +916,7 @@ class boss_koragg : public CreatureScript boss_hexlord_addAI::Reset(); } - void UpdateAI(const uint32 diff) + void UpdateAI(uint32 diff) { if (!UpdateVictim()) return; diff --git a/src/server/scripts/EasternKingdoms/ZulAman/boss_janalai.cpp b/src/server/scripts/EasternKingdoms/ZulAman/boss_janalai.cpp index eced8dd6830..75e044a3c5e 100644 --- a/src/server/scripts/EasternKingdoms/ZulAman/boss_janalai.cpp +++ b/src/server/scripts/EasternKingdoms/ZulAman/boss_janalai.cpp @@ -315,7 +315,7 @@ class boss_janalai : public CreatureScript } } - void UpdateAI(const uint32 diff) + void UpdateAI(uint32 diff) { if (isFlameBreathing) { @@ -468,7 +468,7 @@ class mob_janalai_firebomb : public CreatureScript void MoveInLineOfSight(Unit* /*who*/) {} - void UpdateAI(const uint32 /*diff*/) {} + void UpdateAI(uint32 /*diff*/) {} }; CreatureAI* GetAI(Creature* creature) const @@ -560,7 +560,7 @@ class mob_janalai_hatcher : public CreatureScript WaitTimer = 1; } - void UpdateAI(const uint32 diff) + void UpdateAI(uint32 diff) { if (!instance || !(instance->GetData(DATA_JANALAIEVENT) == IN_PROGRESS)) { @@ -641,7 +641,7 @@ class mob_janalai_hatchling : public CreatureScript void EnterCombat(Unit* /*who*/) {/*DoZoneInCombat();*/} - void UpdateAI(const uint32 diff) + void UpdateAI(uint32 diff) { if (!instance || !(instance->GetData(DATA_JANALAIEVENT) == IN_PROGRESS)) { @@ -684,7 +684,7 @@ public: void Reset() {} - void UpdateAI(uint32 const /*diff*/) {} + void UpdateAI(uint32 /*diff*/) {} void SpellHit(Unit* /*caster*/, const SpellInfo* spell) { diff --git a/src/server/scripts/EasternKingdoms/ZulAman/boss_nalorakk.cpp b/src/server/scripts/EasternKingdoms/ZulAman/boss_nalorakk.cpp index 8fd9da930ae..6c8b1cd8aba 100644 --- a/src/server/scripts/EasternKingdoms/ZulAman/boss_nalorakk.cpp +++ b/src/server/scripts/EasternKingdoms/ZulAman/boss_nalorakk.cpp @@ -155,7 +155,7 @@ class boss_nalorakk : public CreatureScript Berserk_Timer = 600000; inBearForm = false; - // me->SetUInt32Value(UNIT_VIRTUAL_ITEM_SLOT_ID + 1, 5122); // TODO: find the correct equipment id + // me->SetUInt32Value(UNIT_VIRTUAL_ITEM_SLOT_ID + 1, 5122); /// @todo find the correct equipment id } void SendAttacker(Unit* target) @@ -343,7 +343,7 @@ class boss_nalorakk : public CreatureScript } } - void UpdateAI(const uint32 diff) + void UpdateAI(uint32 diff) { if (waitTimer && inMove) { diff --git a/src/server/scripts/EasternKingdoms/ZulAman/boss_zuljin.cpp b/src/server/scripts/EasternKingdoms/ZulAman/boss_zuljin.cpp index 2305c360fd2..be88e67386b 100644 --- a/src/server/scripts/EasternKingdoms/ZulAman/boss_zuljin.cpp +++ b/src/server/scripts/EasternKingdoms/ZulAman/boss_zuljin.cpp @@ -363,7 +363,7 @@ class boss_zuljin : public CreatureScript Phase = NextPhase; } - void UpdateAI(const uint32 diff) + void UpdateAI(uint32 diff) { if (!TankGUID) { @@ -582,7 +582,7 @@ class mob_zuljin_vortex : public CreatureScript DoCast(caster, SPELL_ZAP_DAMAGE, true); } - void UpdateAI(const uint32 /*diff*/) + void UpdateAI(uint32 /*diff*/) { //if the vortex reach the target, it change his target to another player if (me->IsWithinMeleeRange(me->getVictim())) diff --git a/src/server/scripts/EasternKingdoms/ZulAman/zulaman.cpp b/src/server/scripts/EasternKingdoms/ZulAman/zulaman.cpp index 59997ebaa31..ff6d434fa40 100644 --- a/src/server/scripts/EasternKingdoms/ZulAman/zulaman.cpp +++ b/src/server/scripts/EasternKingdoms/ZulAman/zulaman.cpp @@ -148,7 +148,7 @@ class npc_zulaman_hostage : public CreatureScript player->SendLoot(me->GetGUID(), LOOT_CORPSE); } - void UpdateAI(const uint32 /*diff*/) + void UpdateAI(uint32 /*diff*/) { if (IsLoot) DoCast(me, 7, false); @@ -314,14 +314,14 @@ class npc_harrison_jones : public CreatureScript me->SetEntry(NPC_HARRISON_JONES_2); me->SetDisplayId(MODEL_HARRISON_JONES_2); me->SetTarget(0); - me->SetByteValue(UNIT_FIELD_BYTES_1,0,UNIT_STAND_STATE_DEAD); + me->SetByteValue(UNIT_FIELD_BYTES_1, 0, UNIT_STAND_STATE_DEAD); me->SetFlag(UNIT_DYNAMIC_FLAGS, UNIT_DYNFLAG_DEAD); if (instance) instance->SetData(DATA_GONGEVENT, DONE); } } - void UpdateAI(uint32 const diff) + void UpdateAI(uint32 diff) { if (_gongEvent) { @@ -330,7 +330,7 @@ class npc_harrison_jones : public CreatureScript switch (_gongEvent) { case GONG_EVENT_1: - me->GetMotionMaster()->MovePath(HARRISON_MOVE_1,false); + me->GetMotionMaster()->MovePath(HARRISON_MOVE_1, false); _gongEvent = GONG_EVENT_2; _gongTimer = 12000; break; @@ -345,14 +345,14 @@ class npc_harrison_jones : public CreatureScript break; case GONG_EVENT_3: if (GameObject* gong = me->GetMap()->GetGameObject(instance->GetData64(GO_STRANGE_GONG))) - gong->RemoveFlag(GAMEOBJECT_FLAGS,GO_FLAG_NOT_SELECTABLE); + gong->RemoveFlag(GAMEOBJECT_FLAGS, GO_FLAG_NOT_SELECTABLE); _gongEvent = GONG_EVENT_4; _gongTimer = 105000; break; case GONG_EVENT_4: me->RemoveAura(SPELL_BANGING_THE_GONG); if (GameObject* gong = me->GetMap()->GetGameObject(instance->GetData64(GO_STRANGE_GONG))) - gong->SetFlag(GAMEOBJECT_FLAGS,GO_FLAG_NOT_SELECTABLE); + gong->SetFlag(GAMEOBJECT_FLAGS, GO_FLAG_NOT_SELECTABLE); // trigger or gong will need to be scripted to set IN_PROGRESS after enough hits. // This is temp workaround. @@ -362,7 +362,7 @@ class npc_harrison_jones : public CreatureScript if (instance->GetData(DATA_GONGEVENT) == IN_PROGRESS) { // Players are Now Saved to instance at SPECIAL (Player should be notified?) - me->GetMotionMaster()->MovePath(HARRISON_MOVE_2,false); + me->GetMotionMaster()->MovePath(HARRISON_MOVE_2, false); _gongEvent = GONG_EVENT_5; _gongTimer = 5000; } @@ -401,12 +401,12 @@ class npc_harrison_jones : public CreatureScript ptarget->SetUInt32Value(UNIT_VIRTUAL_ITEM_SLOT_ID + 0, uint32(WEAPON_SPEAR)); ptarget->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_IMMUNE_TO_PC); ptarget->SetReactState(REACT_PASSIVE); - ptarget->AI()->SetData(0,1); + ptarget->AI()->SetData(0, 1); } else ptarget->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_IMMUNE_TO_PC); ptarget->SetReactState(REACT_PASSIVE); - ptarget->AI()->SetData(0,2); + ptarget->AI()->SetData(0, 2); } } } @@ -421,7 +421,7 @@ class npc_harrison_jones : public CreatureScript DoCast(me, SPELL_STEALTH); me->SetUInt32Value(UNIT_VIRTUAL_ITEM_SLOT_ID + 0, uint32(0)); me->SetUInt32Value(UNIT_NPC_EMOTESTATE, EMOTE_ONESHOT_NONE); - me->GetMotionMaster()->MovePath(HARRISON_MOVE_3,false); + me->GetMotionMaster()->MovePath(HARRISON_MOVE_3, false); _gongTimer = 1000; _gongEvent = 0; break; diff --git a/src/server/scripts/EasternKingdoms/ZulGurub/boss_arlokk.cpp b/src/server/scripts/EasternKingdoms/ZulGurub/boss_arlokk.cpp index 54a5f5c706c..97eeb385e15 100644 --- a/src/server/scripts/EasternKingdoms/ZulGurub/boss_arlokk.cpp +++ b/src/server/scripts/EasternKingdoms/ZulGurub/boss_arlokk.cpp @@ -1,6 +1,5 @@ /* * Copyright (C) 2008-2013 TrinityCore <http://www.trinitycore.org/> - * Copyright (C) 2006-2009 ScriptDev2 <https://scriptdev2.svn.sourceforge.net/> * * 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 @@ -17,270 +16,433 @@ */ /* ScriptData -SDName: Boss_Arlokk -SD%Complete: 95 -SDComment: Wrong cleave and red aura is missing. -SDCategory: Zul'Gurub +TCName: Boss_Arlokk +TC%Complete: 95 +TCComment: Wrong cleave and red aura is missing not yet added. +TCComment: Prowlers moving through wall hopefully mmaps will fix. +TCComment: Can't test LOS until mmaps. +TCCategory: Zul'Gurub EndScriptData */ #include "ScriptMgr.h" #include "ScriptedCreature.h" +#include "SpellInfo.h" #include "zulgurub.h" -enum eYells +enum Says { SAY_AGGRO = 0, - SAY_FEAST_PANTHER = 1, - SAY_DEATH = 2, + SAY_FEAST_PROWLER = 1, + SAY_DEATH = 2 }; -enum eSpells +enum Spells { - SPELL_SHADOWWORDPAIN = 23952, - SPELL_GOUGE = 24698, - SPELL_MARK = 24210, - SPELL_CLEAVE = 26350, //Perhaps not right. Not a red aura... - SPELL_PANTHER_TRANSFORM = 24190, - - MODEL_ID_NORMAL = 15218, - MODEL_ID_PANTHER = 15215, - MODEL_ID_BLANK = 11686, - - NPC_ZULIAN_PROWLER = 15101 + SPELL_SHADOW_WORD_PAIN = 24212, // Corrected + SPELL_GOUGE = 12540, // Corrected + SPELL_MARK_OF_ARLOKK = 24210, // triggered spell 24211 Added to spell_dbc + SPELL_RAVAGE = 24213, // Corrected + SPELL_CLEAVE = 25174, // Searching for right spell + SPELL_PANTHER_TRANSFORM = 24190, // Transform to panther now used + SPELL_SUMMON_PROWLER = 24246, // Added to Spell_dbc + SPELL_VANISH_VISUAL = 24222, // Added + SPELL_VANISH = 24223, // Added + SPELL_SUPER_INVIS = 24235 // Added to Spell_dbc }; -class boss_arlokk : public CreatureScript +enum Events { - public: - - boss_arlokk() - : CreatureScript("boss_arlokk") - { - } + EVENT_SHADOW_WORD_PAIN = 1, + EVENT_GOUGE = 2, + EVENT_MARK_OF_ARLOKK = 3, + EVENT_RAVAGE = 4, + EVENT_TRANSFORM = 5, + EVENT_VANISH = 6, + EVENT_VANISH_2 = 7, + EVENT_TRANSFORM_BACK = 8, + EVENT_VISIBLE = 9, + EVENT_SUMMON_PROWLERS = 10 +}; - struct boss_arlokkAI : public ScriptedAI - { - boss_arlokkAI(Creature* creature) : ScriptedAI(creature) - { - instance = creature->GetInstanceScript(); - } +enum Phases +{ + PHASE_ALL = 0, + PHASE_ONE = 1, + PHASE_TWO = 2 +}; - InstanceScript* instance; +enum Weapon +{ + WEAPON_DAGGER = 10616 +}; - uint32 m_uiShadowWordPain_Timer; - uint32 m_uiGouge_Timer; - uint32 m_uiMark_Timer; - uint32 m_uiCleave_Timer; - uint32 m_uiVanish_Timer; - uint32 m_uiVisible_Timer; +enum Misc +{ + MAX_PROWLERS_PER_SIDE = 15 +}; - uint32 m_uiSummon_Timer; - uint32 m_uiSummonCount; +Position const PosMoveOnSpawn[1] = +{ + { -11561.9f, -1627.868f, 41.29941f, 0.0f } +}; - Unit* m_pMarkedTarget; - uint64 MarkedTargetGUID; +class boss_arlokk : public CreatureScript +{ + public: boss_arlokk() : CreatureScript("boss_arlokk") {} - bool m_bIsPhaseTwo; - bool m_bIsVanished; + struct boss_arlokkAI : public BossAI + { + boss_arlokkAI(Creature* creature) : BossAI(creature, DATA_ARLOKK) { } void Reset() { - m_uiShadowWordPain_Timer = 8000; - m_uiGouge_Timer = 14000; - m_uiMark_Timer = 35000; - m_uiCleave_Timer = 4000; - m_uiVanish_Timer = 60000; - m_uiVisible_Timer = 6000; - - m_uiSummon_Timer = 5000; - m_uiSummonCount = 0; - - m_bIsPhaseTwo = false; - m_bIsVanished = false; - - MarkedTargetGUID = 0; - - me->SetDisplayId(MODEL_ID_NORMAL); - me->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE); + _summonCountA = 0; + _summonCountB = 0; + me->RemoveAllAuras(); + me->SetUInt32Value(UNIT_VIRTUAL_ITEM_SLOT_ID + 0, uint32(WEAPON_DAGGER)); + me->SetUInt32Value(UNIT_VIRTUAL_ITEM_SLOT_ID + 1, uint32(WEAPON_DAGGER)); + if (instance) + { + if (GameObject* gate = me->GetMap()->GetGameObject(instance->GetData64(GO_FORCEFIELD))) + gate->SetGoState(GO_STATE_READY); + me->SetWalk(false); + me->GetMotionMaster()->MovePoint(0, PosMoveOnSpawn[0]); + } } - void EnterCombat(Unit* /*who*/) + void JustDied(Unit* /*killer*/) { - Talk(SAY_AGGRO); + Talk(SAY_DEATH); + me->RemoveAllAuras(); + if (instance) + { + if (GameObject* gate = me->GetMap()->GetGameObject(instance->GetData64(GO_FORCEFIELD))) + gate->SetGoState(GO_STATE_ACTIVE); + instance->SetBossState(DATA_ARLOKK, DONE); + } } - void JustReachedHome() + void EnterCombat(Unit* /*who*/) { + _EnterCombat(); + events.ScheduleEvent(EVENT_SHADOW_WORD_PAIN, urand(7000, 9000), 0, PHASE_ONE); + events.ScheduleEvent(EVENT_GOUGE, urand(12000, 15000), 0, PHASE_ONE); if (instance) - instance->SetData(DATA_ARLOKK, NOT_STARTED); + events.ScheduleEvent(EVENT_SUMMON_PROWLERS, 6000, 0, PHASE_ALL); + events.ScheduleEvent(EVENT_MARK_OF_ARLOKK, urand(9000, 11000), 0, PHASE_ALL); + events.ScheduleEvent(EVENT_TRANSFORM, urand(15000, 20000), 0, PHASE_ONE); + Talk(SAY_AGGRO); - //we should be summoned, so despawn - me->DespawnOrUnsummon(); + // Sets up list of Panther spawners to cast on + std::list<Creature*> triggerList; + GetCreatureListWithEntryInGrid(triggerList, me, NPC_PANTHER_TRIGGER, 100.0f); + if (!triggerList.empty()) + { + uint8 sideA = 0; + uint8 sideB = 0; + for (std::list<Creature*>::const_iterator itr = triggerList.begin(); itr != triggerList.end(); ++itr) + { + if (Creature* trigger = *itr) + { + if (trigger->GetPositionY() < -1625.0f) + { + _triggersSideAGUID[sideA] = trigger->GetGUID(); + ++sideA; + } + else + { + _triggersSideBGUID[sideB] = trigger->GetGUID(); + ++sideB; + } + } + } + } } - void JustDied(Unit* /*killer*/) + void EnterEvadeMode() { - Talk(SAY_DEATH); - - me->SetDisplayId(MODEL_ID_NORMAL); - me->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE); - if (instance) - instance->SetData(DATA_ARLOKK, DONE); + { + if (GameObject* object = me->GetMap()->GetGameObject(instance->GetData64(GO_FORCEFIELD))) + object->SetGoState(GO_STATE_ACTIVE); + if (GameObject* object = me->GetMap()->GetGameObject(instance->GetData64(GO_GONG_OF_BETHEKK))) + object->RemoveFlag(GAMEOBJECT_FLAGS, GO_FLAG_NOT_SELECTABLE); + instance->SetBossState(DATA_ARLOKK, NOT_STARTED); + } + me->DespawnOrUnsummon(4000); } - void DoSummonPhanters() + void SetData(uint32 id, uint32 /*value*/) { - if (MarkedTargetGUID) - Talk(SAY_FEAST_PANTHER, MarkedTargetGUID); - - me->SummonCreature(NPC_ZULIAN_PROWLER, -11532.7998f, -1649.6734f, 41.4800f, 0.0f, TEMPSUMMON_TIMED_DESPAWN_OUT_OF_COMBAT, 15000); - me->SummonCreature(NPC_ZULIAN_PROWLER, -11532.9970f, -1606.4840f, 41.2979f, 0.0f, TEMPSUMMON_TIMED_DESPAWN_OUT_OF_COMBAT, 15000); + if (id == 1) + --_summonCountA; + else if (id == 2) + --_summonCountB; } - void JustSummoned(Creature* summoned) + void UpdateAI(uint32 diff) { - if (Unit* pMarkedTarget = Unit::GetUnit(*me, MarkedTargetGUID)) - summoned->AI()->AttackStart(pMarkedTarget); + if (!UpdateVictim()) + return; - ++m_uiSummonCount; - } + events.Update(diff); - void UpdateAI(const uint32 uiDiff) - { - if (!UpdateVictim()) + if (me->HasUnitState(UNIT_STATE_CASTING)) return; - if (!m_bIsPhaseTwo) + while (uint32 eventId = events.ExecuteEvent()) { - if (m_uiShadowWordPain_Timer <= uiDiff) - { - DoCast(me->getVictim(), SPELL_SHADOWWORDPAIN); - m_uiShadowWordPain_Timer = 15000; - } - else - m_uiShadowWordPain_Timer -= uiDiff; - - if (m_uiMark_Timer <= uiDiff) + switch (eventId) { - Unit* pMarkedTarget = SelectTarget(SELECT_TARGET_RANDOM, 0); - - if (pMarkedTarget) + case EVENT_SHADOW_WORD_PAIN: + DoCastVictim(SPELL_SHADOW_WORD_PAIN, true); + events.ScheduleEvent(EVENT_SHADOW_WORD_PAIN, urand(5000, 7000), 0, PHASE_ONE); + break; + case EVENT_GOUGE: + DoCastVictim(SPELL_GOUGE, true); + break; + case EVENT_SUMMON_PROWLERS: + if (_summonCountA < MAX_PROWLERS_PER_SIDE) + { + if (Unit* trigger = me->GetUnit(*me, _triggersSideAGUID[urand(0, 4)])) + { + trigger->CastSpell(trigger, SPELL_SUMMON_PROWLER); + ++_summonCountA; + } + } + if (_summonCountB < MAX_PROWLERS_PER_SIDE) + { + if (Unit* trigger = me->GetUnit(*me, _triggersSideBGUID[urand(0, 4)])) + { + trigger->CastSpell(trigger, SPELL_SUMMON_PROWLER); + ++_summonCountB; + } + } + events.ScheduleEvent(EVENT_SUMMON_PROWLERS, 6000, 0, PHASE_ALL); + break; + case EVENT_MARK_OF_ARLOKK: { - DoCast(pMarkedTarget, SPELL_MARK); - MarkedTargetGUID = pMarkedTarget->GetGUID(); + Unit* target = SelectTarget(SELECT_TARGET_TOPAGGRO, urand(1,3), 0.0f, false, -SPELL_MARK_OF_ARLOKK); + if (!target) + target = me->getVictim(); + if (target) + { + DoCast(target, SPELL_MARK_OF_ARLOKK, true); + Talk(SAY_FEAST_PROWLER, target->GetGUID()); + } + events.ScheduleEvent(EVENT_MARK_OF_ARLOKK, urand(120000, 130000)); + break; } - else - sLog->outError(LOG_FILTER_TSCR, "boss_arlokk could not accuire pMarkedTarget."); - - m_uiMark_Timer = 15000; + case EVENT_TRANSFORM: + { + DoCast(me, SPELL_PANTHER_TRANSFORM); + me->SetUInt32Value(UNIT_VIRTUAL_ITEM_SLOT_ID + 0, uint32(EQUIP_UNEQUIP)); + me->SetUInt32Value(UNIT_VIRTUAL_ITEM_SLOT_ID + 1, uint32(EQUIP_UNEQUIP)); + const CreatureTemplate* cinfo = me->GetCreatureTemplate(); + me->SetBaseWeaponDamage(BASE_ATTACK, MINDAMAGE, (cinfo->mindmg +((cinfo->mindmg/100) * 35))); + me->SetBaseWeaponDamage(BASE_ATTACK, MAXDAMAGE, (cinfo->maxdmg +((cinfo->maxdmg/100) * 35))); + me->UpdateDamagePhysical(BASE_ATTACK); + me->AttackStop(); + DoResetThreat(); + me->SetReactState(REACT_PASSIVE); + me->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE|UNIT_FLAG_NOT_SELECTABLE); + DoCast(me, SPELL_VANISH_VISUAL); + DoCast(me, SPELL_VANISH); + events.ScheduleEvent(EVENT_VANISH, 1000, 0, PHASE_ONE); + break; + } + case EVENT_VANISH: + DoCast(me, SPELL_SUPER_INVIS); + me->SetWalk(false); + if (instance) + me->GetMotionMaster()->MovePoint(0, frand(-11551.0f, -11508.0f), frand(-1638.0f, -1617.0f), me->GetPositionZ()); + events.ScheduleEvent(EVENT_VANISH_2, 9000, 0, PHASE_ONE); + break; + case EVENT_VANISH_2: + DoCast(me, SPELL_VANISH); + DoCast(me, SPELL_SUPER_INVIS); + events.ScheduleEvent(EVENT_VISIBLE, urand(7000, 10000), 0, PHASE_ONE); + break; + case EVENT_VISIBLE: + me->SetReactState(REACT_AGGRESSIVE); + me->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE|UNIT_FLAG_NOT_SELECTABLE); + if (Unit* target = SelectTarget(SELECT_TARGET_RANDOM, 0)) + AttackStart(target); + me->RemoveAura(SPELL_SUPER_INVIS); + me->RemoveAura(SPELL_VANISH); + events.ScheduleEvent(EVENT_RAVAGE, urand(10000, 14000), 0, PHASE_TWO); + events.ScheduleEvent(EVENT_TRANSFORM_BACK, urand(15000, 18000), 0, PHASE_TWO); + events.SetPhase(PHASE_TWO); + break; + case EVENT_RAVAGE: + DoCastVictim(SPELL_RAVAGE, true); + events.ScheduleEvent(EVENT_RAVAGE, urand(10000, 14000), 0, PHASE_TWO); + break; + case EVENT_TRANSFORM_BACK: + { + me->RemoveAura(SPELL_PANTHER_TRANSFORM); + DoCast(me, SPELL_VANISH_VISUAL); + me->SetUInt32Value(UNIT_VIRTUAL_ITEM_SLOT_ID + 0, uint32(WEAPON_DAGGER)); + me->SetUInt32Value(UNIT_VIRTUAL_ITEM_SLOT_ID + 1, uint32(WEAPON_DAGGER)); + const CreatureTemplate* cinfo = me->GetCreatureTemplate(); + me->SetBaseWeaponDamage(BASE_ATTACK, MINDAMAGE, (cinfo->mindmg)); + me->SetBaseWeaponDamage(BASE_ATTACK, MAXDAMAGE, (cinfo->maxdmg)); + me->UpdateDamagePhysical(BASE_ATTACK); + events.ScheduleEvent(EVENT_SHADOW_WORD_PAIN, urand(4000, 7000), 0, PHASE_ONE); + events.ScheduleEvent(EVENT_GOUGE, urand(12000, 15000), 0, PHASE_ONE); + events.ScheduleEvent(EVENT_TRANSFORM, urand(16000, 20000), 0, PHASE_ONE); + events.SetPhase(PHASE_ONE); + break; + } + default: + break; } - else - m_uiMark_Timer -= uiDiff; } - else - { - //Cleave_Timer - if (m_uiCleave_Timer <= uiDiff) - { - DoCast(me->getVictim(), SPELL_CLEAVE); - m_uiCleave_Timer = 16000; - } - else - m_uiCleave_Timer -= uiDiff; - //Gouge_Timer - if (m_uiGouge_Timer <= uiDiff) - { - DoCast(me->getVictim(), SPELL_GOUGE); + DoMeleeAttackIfReady(); + } - DoModifyThreatPercent(me->getVictim(), -80); + private: + uint8 _summonCountA; + uint8 _summonCountB; + uint64 _triggersSideAGUID[5]; + uint64 _triggersSideBGUID[5]; + }; - m_uiGouge_Timer = 17000+rand()%10000; - } - else - m_uiGouge_Timer -= uiDiff; - } + CreatureAI* GetAI(Creature* creature) const + { + return GetZulGurubAI<boss_arlokkAI>(creature); + } +}; - if (m_uiSummonCount <= 30) - { - if (m_uiSummon_Timer <= uiDiff) - { - DoSummonPhanters(); - m_uiSummon_Timer = 5000; - } - else - m_uiSummon_Timer -= uiDiff; - } +/*###### +## npc_zulian_prowler +######*/ - if (m_uiVanish_Timer <= uiDiff) - { - //Invisble Model - me->SetDisplayId(MODEL_ID_BLANK); - me->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE); +enum ZulianProwlerSpells +{ + SPELL_SNEAK_RANK_1_1 = 22766, + SPELL_SNEAK_RANK_1_2 = 7939, // Added to Spell_dbc + SPELL_MARK_OF_ARLOKK_TRIGGER = 24211 // Added to Spell_dbc +}; - me->AttackStop(); - DoResetThreat(); +enum ZulianProwlerEvents +{ + EVENT_ATTACK = 1 +}; - m_bIsVanished = true; +Position const PosProwlerCenter[1] = +{ + { -11556.7f, -1631.344f, 41.2994f, 0.0f } +}; - m_uiVanish_Timer = 45000; - m_uiVisible_Timer = 6000; - } +class npc_zulian_prowler : public CreatureScript +{ + public: npc_zulian_prowler() : CreatureScript("npc_zulian_prowler") {} + + struct npc_zulian_prowlerAI : public ScriptedAI + { + npc_zulian_prowlerAI(Creature* creature) : ScriptedAI(creature), _instance(creature->GetInstanceScript()) { } + + void Reset() + { + if (me->GetPositionY() < -1625.0f) + _sideData = 1; else - m_uiVanish_Timer -= uiDiff; + _sideData = 2; + + DoCast(me, SPELL_SNEAK_RANK_1_1); + DoCast(me, SPELL_SNEAK_RANK_1_2); + + if (_instance) + if (Unit* arlokk = me->GetUnit(*me, _instance->GetData64(NPC_ARLOKK))) + me->GetMotionMaster()->MovePoint(0, arlokk->GetPositionX(), arlokk->GetPositionY(), arlokk->GetPositionZ()); + _events.ScheduleEvent(EVENT_ATTACK, 6000); + } + + void EnterCombat(Unit* /*who*/) + { + me->GetMotionMaster()->Clear(false); + me->RemoveAura(SPELL_SNEAK_RANK_1_1); + me->RemoveAura(SPELL_SNEAK_RANK_1_2); + } + + void SpellHit(Unit* caster, SpellInfo const* spell) + { + if (spell->Id == SPELL_MARK_OF_ARLOKK_TRIGGER) // Should only hit if line of sight + me->Attack(caster, true); + } - if (m_bIsVanished) + void JustDied(Unit* /*killer*/) + { + if (_instance) { - if (m_uiVisible_Timer <= uiDiff) + if (Unit* arlokk = me->GetUnit(*me, _instance->GetData64(NPC_ARLOKK))) { - //The Panther Model - me->SetDisplayId(MODEL_ID_PANTHER); - me->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE); + if (arlokk->isAlive()) + arlokk->GetAI()->SetData(_sideData, 0); + } + } + me->DespawnOrUnsummon(4000); + } - const CreatureTemplate* cinfo = me->GetCreatureTemplate(); - me->SetBaseWeaponDamage(BASE_ATTACK, MINDAMAGE, (cinfo->mindmg +((cinfo->mindmg/100) * 35))); - me->SetBaseWeaponDamage(BASE_ATTACK, MAXDAMAGE, (cinfo->maxdmg +((cinfo->maxdmg/100) * 35))); - me->UpdateDamagePhysical(BASE_ATTACK); + void UpdateAI(uint32 diff) + { + if (UpdateVictim()) + { + DoMeleeAttackIfReady(); + return; + } - if (Unit* target = SelectTarget(SELECT_TARGET_RANDOM, 0)) - AttackStart(target); + _events.Update(diff); - m_bIsPhaseTwo = true; - m_bIsVanished = false; + while (uint32 eventId = _events.ExecuteEvent()) + { + switch (eventId) + { + case EVENT_ATTACK: + if (Unit* target = SelectTarget(SELECT_TARGET_RANDOM, 0.0f, 100, false)) + me->Attack(target, true); + break; + default: + break; } - else - m_uiVisible_Timer -= uiDiff; } - else - DoMeleeAttackIfReady(); } + + private: + int32 _sideData; + EventMap _events; + InstanceScript* _instance; }; CreatureAI* GetAI(Creature* creature) const { - return new boss_arlokkAI(creature); + return GetZulGurubAI<npc_zulian_prowlerAI>(creature); } }; +/*###### +## go_gong_of_bethekk +######*/ + +Position const PosSummonArlokk[1] = +{ + { -11507.22f, -1628.062f, 41.38264f, 3.159046f } +}; + class go_gong_of_bethekk : public GameObjectScript { - public: - go_gong_of_bethekk() : GameObjectScript("go_gong_of_bethekk") - { - } + public: go_gong_of_bethekk() : GameObjectScript("go_gong_of_bethekk") {} bool OnGossipHello(Player* /*player*/, GameObject* go) { - if (InstanceScript* instance = go->GetInstanceScript()) + if (go->GetInstanceScript()) { - if (instance->GetData(DATA_ARLOKK) == DONE || instance->GetData(DATA_ARLOKK) == IN_PROGRESS) - return true; - - instance->SetData(DATA_ARLOKK, IN_PROGRESS); - return true; + go->SetFlag(GAMEOBJECT_FLAGS, GO_FLAG_NOT_SELECTABLE); + go->SendCustomAnim(0); + go->SummonCreature(NPC_ARLOKK, PosSummonArlokk[0], TEMPSUMMON_TIMED_DESPAWN_OUT_OF_COMBAT, 600000); } - return true; } }; @@ -288,6 +450,6 @@ class go_gong_of_bethekk : public GameObjectScript void AddSC_boss_arlokk() { new boss_arlokk(); + new npc_zulian_prowler(); new go_gong_of_bethekk(); } - diff --git a/src/server/scripts/EasternKingdoms/ZulGurub/boss_gahzranka.cpp b/src/server/scripts/EasternKingdoms/ZulGurub/boss_gahzranka.cpp index e7d54aecb31..e930d864940 100644 --- a/src/server/scripts/EasternKingdoms/ZulGurub/boss_gahzranka.cpp +++ b/src/server/scripts/EasternKingdoms/ZulGurub/boss_gahzranka.cpp @@ -25,62 +25,78 @@ EndScriptData */ #include "ScriptMgr.h" #include "ScriptedCreature.h" +#include "zulgurub.h" -#define SPELL_FROSTBREATH 16099 -#define SPELL_MASSIVEGEYSER 22421 //Not working. Cause its a summon... -#define SPELL_SLAM 24326 +enum Spells +{ + SPELL_FROSTBREATH = 16099, + SPELL_MASSIVEGEYSER = 22421, // Not working. (summon) + SPELL_SLAM = 24326 +}; -class boss_gahzranka : public CreatureScript +enum Events { - public: - boss_gahzranka() : CreatureScript("boss_gahzranka") { } + EVENT_FROSTBREATH = 0, + EVENT_MASSIVEGEYSER = 1, + EVENT_SLAM = 2 +}; - struct boss_gahzrankaAI : public ScriptedAI +class boss_gahzranka : public CreatureScript // gahzranka +{ + public: boss_gahzranka() : CreatureScript("boss_gahzranka") {} + + struct boss_gahzrankaAI : public BossAI { - boss_gahzrankaAI(Creature* creature) : ScriptedAI(creature) { } - uint32 Frostbreath_Timer; - uint32 MassiveGeyser_Timer; - uint32 Slam_Timer; + boss_gahzrankaAI(Creature* creature) : BossAI(creature, DATA_GAHZRANKA) {} void Reset() { - Frostbreath_Timer = 8000; - MassiveGeyser_Timer = 25000; - Slam_Timer = 17000; + _Reset(); + } + + void JustDied(Unit* /*killer*/) + { + _JustDied(); } void EnterCombat(Unit* /*who*/) { + _EnterCombat(); + events.ScheduleEvent(EVENT_FROSTBREATH, 8000); + events.ScheduleEvent(EVENT_MASSIVEGEYSER, 25000); + events.ScheduleEvent(EVENT_SLAM, 17000); } - void UpdateAI(const uint32 diff) + void UpdateAI(uint32 diff) { - //Return since we have no target if (!UpdateVictim()) return; - //Frostbreath_Timer - if (Frostbreath_Timer <= diff) - { - DoCast(me->getVictim(), SPELL_FROSTBREATH); - Frostbreath_Timer = urand(7000, 11000); - } else Frostbreath_Timer -= diff; - - //MassiveGeyser_Timer - if (MassiveGeyser_Timer <= diff) - { - DoCast(me->getVictim(), SPELL_MASSIVEGEYSER); - DoResetThreat(); + events.Update(diff); - MassiveGeyser_Timer = urand(22000, 32000); - } else MassiveGeyser_Timer -= diff; + if (me->HasUnitState(UNIT_STATE_CASTING)) + return; - //Slam_Timer - if (Slam_Timer <= diff) + while (uint32 eventId = events.ExecuteEvent()) { - DoCast(me->getVictim(), SPELL_SLAM); - Slam_Timer = urand(12000, 20000); - } else Slam_Timer -= diff; + switch (eventId) + { + case EVENT_FROSTBREATH: + DoCastVictim(SPELL_FROSTBREATH, true); + events.ScheduleEvent(EVENT_FROSTBREATH, urand(7000, 11000)); + break; + case EVENT_MASSIVEGEYSER: + DoCastVictim(SPELL_MASSIVEGEYSER, true); + events.ScheduleEvent(EVENT_MASSIVEGEYSER, urand(22000, 32000)); + break; + case EVENT_SLAM: + DoCastVictim(SPELL_SLAM, true); + events.ScheduleEvent(EVENT_SLAM, urand(12000, 20000)); + break; + default: + break; + } + } DoMeleeAttackIfReady(); } @@ -96,4 +112,3 @@ void AddSC_boss_gahzranka() { new boss_gahzranka(); } - diff --git a/src/server/scripts/EasternKingdoms/ZulGurub/boss_grilek.cpp b/src/server/scripts/EasternKingdoms/ZulGurub/boss_grilek.cpp index 4ccdbceb466..af8303e63e4 100644 --- a/src/server/scripts/EasternKingdoms/ZulGurub/boss_grilek.cpp +++ b/src/server/scripts/EasternKingdoms/ZulGurub/boss_grilek.cpp @@ -27,60 +27,77 @@ EndScriptData */ #include "ScriptedCreature.h" #include "zulgurub.h" -#define SPELL_AVARTAR 24646 //The Enrage Spell -#define SPELL_GROUNDTREMOR 6524 +enum Spells +{ + SPELL_AVATAR = 24646, // Enrage Spell + SPELL_GROUND_TREMOR = 6524 +}; -class boss_grilek : public CreatureScript +enum Events { - public: - boss_grilek() : CreatureScript("boss_grilek") { } + EVENT_AVATAR = 0, + EVENT_GROUND_TREMOR = 1 +}; - struct boss_grilekAI : public ScriptedAI - { - boss_grilekAI(Creature* creature) : ScriptedAI(creature) { } +class boss_grilek : public CreatureScript // grilek +{ + public: boss_grilek() : CreatureScript("boss_grilek") {} - uint32 Avartar_Timer; - uint32 GroundTremor_Timer; + struct boss_grilekAI : public BossAI + { + boss_grilekAI(Creature* creature) : BossAI(creature, DATA_EDGE_OF_MADNESS) {} void Reset() { - Avartar_Timer = urand(15000, 25000); - GroundTremor_Timer = urand(8000, 16000); + _Reset(); + } + + void JustDied(Unit* /*killer*/) + { + _JustDied(); } void EnterCombat(Unit* /*who*/) { + _EnterCombat(); + events.ScheduleEvent(EVENT_AVATAR, urand(15000, 25000)); + events.ScheduleEvent(EVENT_GROUND_TREMOR, urand(15000, 25000)); } - void UpdateAI(const uint32 diff) + void UpdateAI(uint32 diff) { - //Return since we have no target if (!UpdateVictim()) return; - //Avartar_Timer - if (Avartar_Timer <= diff) - { - - DoCast(me, SPELL_AVARTAR); - Unit* target = NULL; + events.Update(diff); - target = SelectTarget(SELECT_TARGET_RANDOM, 1); - - if (DoGetThreat(me->getVictim())) - DoModifyThreatPercent(me->getVictim(), -50); - if (target) - AttackStart(target); - - Avartar_Timer = urand(25000, 35000); - } else Avartar_Timer -= diff; + if (me->HasUnitState(UNIT_STATE_CASTING)) + return; - //GroundTremor_Timer - if (GroundTremor_Timer <= diff) + while (uint32 eventId = events.ExecuteEvent()) { - DoCast(me->getVictim(), SPELL_GROUNDTREMOR); - GroundTremor_Timer = urand(12000, 16000); - } else GroundTremor_Timer -= diff; + switch (eventId) + { + case EVENT_AVATAR: + DoCast(me, SPELL_AVATAR); + if (Unit* victim = me->getVictim()) + { + if (DoGetThreat(victim)) + DoModifyThreatPercent(victim, -50); + } + + if (Unit* target = SelectTarget(SELECT_TARGET_RANDOM, 1)) + AttackStart(target); + events.ScheduleEvent(EVENT_AVATAR, urand(25000, 35000)); + break; + case EVENT_GROUND_TREMOR: + DoCastVictim(SPELL_GROUND_TREMOR, true); + events.ScheduleEvent(EVENT_GROUND_TREMOR, urand(12000, 16000)); + break; + default: + break; + } + } DoMeleeAttackIfReady(); } diff --git a/src/server/scripts/EasternKingdoms/ZulGurub/boss_hakkar.cpp b/src/server/scripts/EasternKingdoms/ZulGurub/boss_hakkar.cpp index 781b68bfcb0..f9fe338d918 100644 --- a/src/server/scripts/EasternKingdoms/ZulGurub/boss_hakkar.cpp +++ b/src/server/scripts/EasternKingdoms/ZulGurub/boss_hakkar.cpp @@ -1,6 +1,5 @@ /* * Copyright (C) 2008-2013 TrinityCore <http://www.trinitycore.org/> - * Copyright (C) 2006-2009 ScriptDev2 <https://scriptdev2.svn.sourceforge.net/> * * 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 @@ -16,31 +15,33 @@ * with this program. If not, see <http://www.gnu.org/licenses/>. */ -/* ScriptData -SDName: Boss_Hakkar -SD%Complete: 95 -SDComment: Blood siphon spell buggy cause of Core Issue. -SDCategory: Zul'Gurub -EndScriptData */ +/* +Name: Boss_Hakkar +%Complete: 95 +Comment: Blood siphon spell buggy cause of Core Issue. +Category: Zul'Gurub +*/ #include "ScriptMgr.h" #include "ScriptedCreature.h" #include "zulgurub.h" -enum Hakkar +enum Says { SAY_AGGRO = 0, SAY_FLEEING = 1, - SAY_MINION_DESTROY = 2, //where does it belong? - SAY_PROTECT_ALTAR = 3, //where does it belong? + SAY_MINION_DESTROY = 2, // Where does it belong? + SAY_PROTECT_ALTAR = 3 // Where does it belong? +}; - SPELL_BLOODSIPHON = 24322, - SPELL_CORRUPTEDBLOOD = 24328, - SPELL_CAUSEINSANITY = 24327, //Not working disabled. - SPELL_WILLOFHAKKAR = 24178, +enum Spells +{ + SPELL_BLOOD_SIPHON = 24322, // Buggy ? + SPELL_CORRUPTED_BLOOD = 24328, + SPELL_CAUSE_INSANITY = 24327, // Spell needs scripting. + SPELL_WILL_OF_HAKKAR = 24178, SPELL_ENRAGE = 24318, - -// The Aspects of all High Priests + // The Aspects of all High Priests spells SPELL_ASPECT_OF_JEKLIK = 24687, SPELL_ASPECT_OF_VENOXIS = 24688, SPELL_ASPECT_OF_MARLI = 24686, @@ -48,202 +49,119 @@ enum Hakkar SPELL_ASPECT_OF_ARLOKK = 24690 }; +enum Events +{ + EVENT_BLOOD_SIPHON = 0, + EVENT_CORRUPTED_BLOOD = 1, + EVENT_CAUSE_INSANITY = 2, // Spell needs scripting. Event disabled + EVENT_WILL_OF_HAKKAR = 3, + EVENT_ENRAGE = 4, + // The Aspects of all High Priests events + EVENT_ASPECT_OF_JEKLIK = 5, + EVENT_ASPECT_OF_VENOXIS = 6, + EVENT_ASPECT_OF_MARLI = 7, + EVENT_ASPECT_OF_THEKAL = 8, + EVENT_ASPECT_OF_ARLOKK = 9 +}; + class boss_hakkar : public CreatureScript { - public: + public: boss_hakkar() : CreatureScript("boss_hakkar") {} - boss_hakkar() - : CreatureScript("boss_hakkar") + struct boss_hakkarAI : public BossAI { - } + boss_hakkarAI(Creature* creature) : BossAI(creature, DATA_HAKKAR) {} - struct boss_hakkarAI : public ScriptedAI - { - boss_hakkarAI(Creature* creature) : ScriptedAI(creature) + void Reset() { - instance = creature->GetInstanceScript(); + _Reset(); } - InstanceScript* instance; - - uint32 BloodSiphon_Timer; - uint32 CorruptedBlood_Timer; - uint32 CauseInsanity_Timer; - uint32 WillOfHakkar_Timer; - uint32 Enrage_Timer; - - uint32 CheckJeklik_Timer; - uint32 CheckVenoxis_Timer; - uint32 CheckMarli_Timer; - uint32 CheckThekal_Timer; - uint32 CheckArlokk_Timer; - - uint32 AspectOfJeklik_Timer; - uint32 AspectOfVenoxis_Timer; - uint32 AspectOfMarli_Timer; - uint32 AspectOfThekal_Timer; - uint32 AspectOfArlokk_Timer; - - bool Enraged; - - void Reset() + void JustDied(Unit* /*killer*/) { - BloodSiphon_Timer = 90000; - CorruptedBlood_Timer = 25000; - CauseInsanity_Timer = 17000; - WillOfHakkar_Timer = 17000; - Enrage_Timer = 600000; - - CheckJeklik_Timer = 1000; - CheckVenoxis_Timer = 2000; - CheckMarli_Timer = 3000; - CheckThekal_Timer = 4000; - CheckArlokk_Timer = 5000; - - AspectOfJeklik_Timer = 4000; - AspectOfVenoxis_Timer = 7000; - AspectOfMarli_Timer = 12000; - AspectOfThekal_Timer = 8000; - AspectOfArlokk_Timer = 18000; - - Enraged = false; + _JustDied(); } void EnterCombat(Unit* /*who*/) { + _EnterCombat(); + events.ScheduleEvent(EVENT_BLOOD_SIPHON, 90000); + events.ScheduleEvent(EVENT_CORRUPTED_BLOOD, 25000); + events.ScheduleEvent(EVENT_CAUSE_INSANITY, 17000); + events.ScheduleEvent(EVENT_WILL_OF_HAKKAR, 17000); + events.ScheduleEvent(EVENT_ENRAGE, 600000); + if (instance->GetBossState(DATA_JEKLIK) != DONE) + events.ScheduleEvent(EVENT_ASPECT_OF_JEKLIK, 4000); + if (instance->GetBossState(DATA_VENOXIS) != DONE) + events.ScheduleEvent(EVENT_ASPECT_OF_VENOXIS, 7000); + if (instance->GetBossState(DATA_MARLI) != DONE) + events.ScheduleEvent(EVENT_ASPECT_OF_MARLI, 12000); + if (instance->GetBossState(DATA_THEKAL) != DONE) + events.ScheduleEvent(EVENT_ASPECT_OF_THEKAL, 8000); + if (instance->GetBossState(DATA_ARLOKK) != DONE) + events.ScheduleEvent(EVENT_ASPECT_OF_ARLOKK, 18000); Talk(SAY_AGGRO); } - void UpdateAI(const uint32 diff) + void UpdateAI(uint32 diff) { if (!UpdateVictim()) return; - //BloodSiphon_Timer - if (BloodSiphon_Timer <= diff) - { - DoCast(me->getVictim(), SPELL_BLOODSIPHON); - BloodSiphon_Timer = 90000; - } else BloodSiphon_Timer -= diff; - - //CorruptedBlood_Timer - if (CorruptedBlood_Timer <= diff) - { - DoCast(me->getVictim(), SPELL_CORRUPTEDBLOOD); - CorruptedBlood_Timer = urand(30000, 45000); - } else CorruptedBlood_Timer -= diff; - - //CauseInsanity_Timer - /*if (CauseInsanity_Timer <= diff) - { - if (Unit* target = SelectUnit(SELECT_TARGET_RANDOM, 0)) - DoCast(target, SPELL_CAUSEINSANITY); - - CauseInsanity_Timer = urand(35000, 43000); - } else CauseInsanity_Timer -= diff;*/ - - //WillOfHakkar_Timer - if (WillOfHakkar_Timer <= diff) - { - if (Unit* target = SelectTarget(SELECT_TARGET_RANDOM, 0)) - DoCast(target, SPELL_WILLOFHAKKAR); - - WillOfHakkar_Timer = urand(25000, 35000); - } else WillOfHakkar_Timer -= diff; - - if (!Enraged && Enrage_Timer <= diff) - { - DoCast(me, SPELL_ENRAGE); - Enraged = true; - } else Enrage_Timer -= diff; - - //Checking if Jeklik is dead. If not we cast her Aspect - if (CheckJeklik_Timer <= diff) - { - if (instance) - { - if (instance->GetData(DATA_JEKLIK) != DONE) - { - if (AspectOfJeklik_Timer <= diff) - { - DoCast(me->getVictim(), SPELL_ASPECT_OF_JEKLIK); - AspectOfJeklik_Timer = urand(10000, 14000); - } else AspectOfJeklik_Timer -= diff; - } - } - CheckJeklik_Timer = 1000; - } else CheckJeklik_Timer -= diff; - - //Checking if Venoxis is dead. If not we cast his Aspect - if (CheckVenoxis_Timer <= diff) - { - if (instance) - { - if (instance->GetData(DATA_VENOXIS) != DONE) - { - if (AspectOfVenoxis_Timer <= diff) - { - DoCast(me->getVictim(), SPELL_ASPECT_OF_VENOXIS); - AspectOfVenoxis_Timer = 8000; - } else AspectOfVenoxis_Timer -= diff; - } - } - CheckVenoxis_Timer = 1000; - } else CheckVenoxis_Timer -= diff; - - //Checking if Marli is dead. If not we cast her Aspect - if (CheckMarli_Timer <= diff) - { - if (instance) - { - if (instance->GetData(DATA_MARLI) != DONE) - { - if (AspectOfMarli_Timer <= diff) - { - DoCast(me->getVictim(), SPELL_ASPECT_OF_MARLI); - AspectOfMarli_Timer = 10000; - } else AspectOfMarli_Timer -= diff; - - } - } - CheckMarli_Timer = 1000; - } else CheckMarli_Timer -= diff; + events.Update(diff); - //Checking if Thekal is dead. If not we cast his Aspect - if (CheckThekal_Timer <= diff) - { - if (instance) - { - if (instance->GetData(DATA_THEKAL) != DONE) - { - if (AspectOfThekal_Timer <= diff) - { - DoCast(me, SPELL_ASPECT_OF_THEKAL); - AspectOfThekal_Timer = 15000; - } else AspectOfThekal_Timer -= diff; - } - } - CheckThekal_Timer = 1000; - } else CheckThekal_Timer -= diff; + if (me->HasUnitState(UNIT_STATE_CASTING)) + return; - //Checking if Arlokk is dead. If yes we cast her Aspect - if (CheckArlokk_Timer <= diff) + while (uint32 eventId = events.ExecuteEvent()) { - if (instance) + switch (eventId) { - if (instance->GetData(DATA_ARLOKK) != DONE) - { - if (AspectOfArlokk_Timer <= diff) - { - DoCast(me, SPELL_ASPECT_OF_ARLOKK); - DoResetThreat(); - - AspectOfArlokk_Timer = urand(10000, 15000); - } else AspectOfArlokk_Timer -= diff; - } + case EVENT_BLOOD_SIPHON: + DoCastVictim(SPELL_BLOOD_SIPHON, true); + events.ScheduleEvent(EVENT_BLOOD_SIPHON, 90000); + break; + case EVENT_CORRUPTED_BLOOD: + DoCastVictim(SPELL_CORRUPTED_BLOOD, true); + events.ScheduleEvent(EVENT_CORRUPTED_BLOOD, urand(30000, 45000)); + break; + case EVENT_CAUSE_INSANITY: + // DoCast(SelectTarget(SELECT_TARGET_RANDOM, 0, 100, true), SPELL_CAUSE_INSANITY); + // events.ScheduleEvent(EVENT_CAUSE_INSANITY, urand(35000, 45000)); + break; + case EVENT_WILL_OF_HAKKAR: + DoCast(SelectTarget(SELECT_TARGET_RANDOM, 0, 100, true), SPELL_WILL_OF_HAKKAR); + events.ScheduleEvent(EVENT_WILL_OF_HAKKAR, urand(25000, 35000)); + break; + case EVENT_ENRAGE: + if (!me->HasAura(SPELL_ENRAGE)) + DoCast(me, SPELL_ENRAGE); + events.ScheduleEvent(EVENT_ENRAGE, 90000); + break; + case EVENT_ASPECT_OF_JEKLIK: + DoCastVictim(SPELL_ASPECT_OF_JEKLIK, true); + events.ScheduleEvent(EVENT_ASPECT_OF_JEKLIK, urand(10000, 14000)); + break; + case EVENT_ASPECT_OF_VENOXIS: + DoCastVictim(SPELL_ASPECT_OF_VENOXIS, true); + events.ScheduleEvent(EVENT_ASPECT_OF_VENOXIS, 8000); + break; + case EVENT_ASPECT_OF_MARLI: + DoCastVictim(SPELL_ASPECT_OF_MARLI, true); + events.ScheduleEvent(EVENT_ASPECT_OF_MARLI, 10000); + break; + case EVENT_ASPECT_OF_THEKAL: + DoCastVictim(SPELL_ASPECT_OF_THEKAL, true); + events.ScheduleEvent(EVENT_ASPECT_OF_THEKAL, 15000); + break; + case EVENT_ASPECT_OF_ARLOKK: + DoCastVictim(SPELL_ASPECT_OF_ARLOKK, true); + events.ScheduleEvent(EVENT_ASPECT_OF_ARLOKK, urand(10000, 15000)); + break; + default: + break; } - CheckArlokk_Timer = 1000; - } else CheckArlokk_Timer -= diff; + } DoMeleeAttackIfReady(); } diff --git a/src/server/scripts/EasternKingdoms/ZulGurub/boss_hazzarah.cpp b/src/server/scripts/EasternKingdoms/ZulGurub/boss_hazzarah.cpp index bbdc2905874..b2282ba85da 100644 --- a/src/server/scripts/EasternKingdoms/ZulGurub/boss_hazzarah.cpp +++ b/src/server/scripts/EasternKingdoms/ZulGurub/boss_hazzarah.cpp @@ -27,75 +27,85 @@ EndScriptData */ #include "ScriptedCreature.h" #include "zulgurub.h" -#define SPELL_MANABURN 26046 -#define SPELL_SLEEP 24664 +enum Spells +{ + SPELL_MANABURN = 26046, + SPELL_SLEEP = 24664 +}; -class boss_hazzarah : public CreatureScript +enum Events { - public: + EVENT_MANABURN = 0, + EVENT_SLEEP = 1, + EVENT_ILLUSIONS = 2 +}; - boss_hazzarah() - : CreatureScript("boss_hazzarah") - { - } +class boss_hazzarah : public CreatureScript +{ + public: boss_hazzarah() : CreatureScript("boss_hazzarah") {} - struct boss_hazzarahAI : public ScriptedAI + struct boss_hazzarahAI : public BossAI { - boss_hazzarahAI(Creature* creature) : ScriptedAI(creature) {} - - uint32 ManaBurn_Timer; - uint32 Sleep_Timer; - uint32 Illusions_Timer; + boss_hazzarahAI(Creature* creature) : BossAI(creature, DATA_EDGE_OF_MADNESS) {} void Reset() { - ManaBurn_Timer = urand(4000, 10000); - Sleep_Timer = urand(10000, 18000); - Illusions_Timer = urand(10000, 18000); + _Reset(); + } + + void JustDied(Unit* /*killer*/) + { + _JustDied(); } void EnterCombat(Unit* /*who*/) { + _EnterCombat(); + events.ScheduleEvent(EVENT_MANABURN, urand(4000, 10000)); + events.ScheduleEvent(EVENT_SLEEP, urand(10000, 18000)); + events.ScheduleEvent(EVENT_ILLUSIONS, urand(10000, 18000)); } - void UpdateAI(const uint32 diff) + void UpdateAI(uint32 diff) { if (!UpdateVictim()) return; - //ManaBurn_Timer - if (ManaBurn_Timer <= diff) - { - DoCast(me->getVictim(), SPELL_MANABURN); - ManaBurn_Timer = urand(8000, 16000); - } else ManaBurn_Timer -= diff; + events.Update(diff); - //Sleep_Timer - if (Sleep_Timer <= diff) - { - DoCast(me->getVictim(), SPELL_SLEEP); - Sleep_Timer = urand(12000, 20000); - } else Sleep_Timer -= diff; + if (me->HasUnitState(UNIT_STATE_CASTING)) + return; - //Illusions_Timer - if (Illusions_Timer <= diff) + while (uint32 eventId = events.ExecuteEvent()) { - //We will summon 3 illusions that will spawn on a random gamer and attack this gamer - //We will just use one model for the beginning - Unit* target = NULL; - for (uint8 i = 0; i < 3; ++i) + switch (eventId) { - target = SelectTarget(SELECT_TARGET_RANDOM, 0); - if (!target) - return; - - Creature* Illusion = me->SummonCreature(15163, target->GetPositionX(), target->GetPositionY(), target->GetPositionZ(), 0, TEMPSUMMON_TIMED_OR_CORPSE_DESPAWN, 30000); - if (Illusion) - Illusion->AI()->AttackStart(target); + case EVENT_MANABURN: + DoCastVictim(SPELL_MANABURN, true); + events.ScheduleEvent(EVENT_MANABURN, urand(8000, 16000)); + break; + case EVENT_SLEEP: + DoCastVictim(SPELL_SLEEP, true); + events.ScheduleEvent(EVENT_SLEEP, urand(12000, 20000)); + break; + case EVENT_ILLUSIONS: + // We will summon 3 illusions that will spawn on a random gamer and attack this gamer + // We will just use one model for the beginning + for (uint8 i = 0; i < 3; ++i) + { + if (Unit* target = SelectTarget(SELECT_TARGET_RANDOM, 0)) + { + Creature* Illusion = me->SummonCreature(NPC_NIGHTMARE_ILLUSION, target->GetPositionX(), target->GetPositionY(), target->GetPositionZ(), 0, TEMPSUMMON_TIMED_OR_CORPSE_DESPAWN, 30000); + if (Illusion) + Illusion->AI()->AttackStart(target); + } + } + events.ScheduleEvent(EVENT_ILLUSIONS, urand(15000, 25000)); + break; + default: + break; } - - Illusions_Timer = urand(15000, 25000); - } else Illusions_Timer -= diff; + } DoMeleeAttackIfReady(); } @@ -111,4 +121,3 @@ void AddSC_boss_hazzarah() { new boss_hazzarah(); } - diff --git a/src/server/scripts/EasternKingdoms/ZulGurub/boss_jeklik.cpp b/src/server/scripts/EasternKingdoms/ZulGurub/boss_jeklik.cpp index 10431ec84bd..73d2982aee6 100644 --- a/src/server/scripts/EasternKingdoms/ZulGurub/boss_jeklik.cpp +++ b/src/server/scripts/EasternKingdoms/ZulGurub/boss_jeklik.cpp @@ -27,42 +27,34 @@ EndScriptData */ #include "ScriptedCreature.h" #include "zulgurub.h" -enum Jeklik +enum Says { SAY_AGGRO = 0, SAY_RAIN_FIRE = 1, - SAY_DEATH = 2, + SAY_DEATH = 2 +}; +enum Spells +{ SPELL_CHARGE = 22911, SPELL_SONICBURST = 23918, SPELL_SCREECH = 6605, SPELL_SHADOW_WORD_PAIN = 23952, SPELL_MIND_FLAY = 23953, - SPELL_CHAIN_MIND_FLAY = 26044, //Right ID unknown. So disabled + SPELL_CHAIN_MIND_FLAY = 26044, // Right ID unknown. So disabled SPELL_GREATERHEAL = 23954, SPELL_BAT_FORM = 23966, - // Batriders Spell - SPELL_BOMB = 40332 //Wrong ID but Magmadars bomb is not working... + SPELL_BOMB = 40332 // Wrong ID but Magmadars bomb is not working... }; -class boss_jeklik : public CreatureScript +class boss_jeklik : public CreatureScript //jeklik { - public: - - boss_jeklik() - : CreatureScript("boss_jeklik") - { - } + public: boss_jeklik() : CreatureScript("boss_jeklik") {} - struct boss_jeklikAI : public ScriptedAI + struct boss_jeklikAI : public BossAI { - boss_jeklikAI(Creature* creature) : ScriptedAI(creature) - { - instance = creature->GetInstanceScript(); - } - - InstanceScript* instance; + boss_jeklikAI(Creature* creature) : BossAI(creature, DATA_JEKLIK) {} uint32 Charge_Timer; uint32 SonicBurst_Timer; @@ -78,6 +70,7 @@ class boss_jeklik : public CreatureScript void Reset() { + _Reset(); Charge_Timer = 20000; SonicBurst_Timer = 8000; Screech_Timer = 13000; @@ -91,21 +84,20 @@ class boss_jeklik : public CreatureScript PhaseTwo = false; } - void EnterCombat(Unit* /*who*/) - { - Talk(SAY_AGGRO); - DoCast(me, SPELL_BAT_FORM); - } - void JustDied(Unit* /*killer*/) { + _JustDied(); Talk(SAY_DEATH); + } - if (instance) - instance->SetData(DATA_JEKLIK, DONE); + void EnterCombat(Unit* /*who*/) + { + _EnterCombat(); + Talk(SAY_AGGRO); + DoCast(me, SPELL_BAT_FORM); } - void UpdateAI(const uint32 diff) + void UpdateAI(uint32 diff) { if (!UpdateVictim()) return; @@ -166,7 +158,7 @@ class boss_jeklik : public CreatureScript { if (PhaseTwo) { - if (PhaseTwo && ShadowWordPain_Timer <= diff) + if (ShadowWordPain_Timer <= diff) { if (Unit* target = SelectTarget(SELECT_TARGET_RANDOM, 0)) { @@ -197,13 +189,11 @@ class boss_jeklik : public CreatureScript if (SpawnFlyingBats_Timer <= diff) { - Unit* target = SelectTarget(SELECT_TARGET_RANDOM, 0); - if (!target) - return; - - Creature* FlyingBat = me->SummonCreature(14965, target->GetPositionX(), target->GetPositionY(), target->GetPositionZ()+15, 0, TEMPSUMMON_TIMED_DESPAWN_OUT_OF_COMBAT, 15000); - if (FlyingBat) - FlyingBat->AI()->AttackStart(target); + if (Unit* target = SelectTarget(SELECT_TARGET_RANDOM, 0)) + { + if (Creature* FlyingBat = me->SummonCreature(14965, target->GetPositionX(), target->GetPositionY(), target->GetPositionZ()+15, 0, TEMPSUMMON_TIMED_DESPAWN_OUT_OF_COMBAT, 15000)) + FlyingBat->AI()->AttackStart(target); + } SpawnFlyingBats_Timer = urand(10000, 15000); } else SpawnFlyingBats_Timer -=diff; @@ -259,7 +249,7 @@ class mob_batrider : public CreatureScript void EnterCombat(Unit* /*who*/) {} - void UpdateAI (const uint32 diff) + void UpdateAI(uint32 diff) { if (!UpdateVictim()) return; @@ -279,7 +269,7 @@ class mob_batrider : public CreatureScript { if (instance) { - if (instance->GetData(DATA_JEKLIK) == DONE) + if (instance->GetBossState(DATA_JEKLIK) == DONE) { me->setDeathState(JUST_DIED); me->RemoveCorpse(); diff --git a/src/server/scripts/EasternKingdoms/ZulGurub/boss_jindo.cpp b/src/server/scripts/EasternKingdoms/ZulGurub/boss_jindo.cpp index 7c4c9626f9a..166acc13f58 100644 --- a/src/server/scripts/EasternKingdoms/ZulGurub/boss_jindo.cpp +++ b/src/server/scripts/EasternKingdoms/ZulGurub/boss_jindo.cpp @@ -27,147 +27,150 @@ EndScriptData */ #include "ScriptedCreature.h" #include "zulgurub.h" -enum Jindo +enum Say { - SAY_AGGRO = 1, + SAY_AGGRO = 1 +}; +enum Spells +{ SPELL_BRAINWASHTOTEM = 24262, - SPELL_POWERFULLHEALINGWARD = 24309, //We will not use this spell. We will summon a totem by script cause the spell totems will not cast. + SPELL_POWERFULLHEALINGWARD = 24309, // HACKED Totem summoned by script because the spell totems will not cast. SPELL_HEX = 24053, SPELL_DELUSIONSOFJINDO = 24306, - SPELL_SHADEOFJINDO = 24308, //We will not use this spell. We will summon a shade by script. - + SPELL_SHADEOFJINDO = 24308, // HACKED //Healing Ward Spell - SPELL_HEAL = 38588, //Totems are not working right. Right heal spell ID is 24311 but this spell is not casting... - + SPELL_HEAL = 38588, // HACKED Totems are not working right. Right heal spell ID is 24311 but this spell is not casting... //Shade of Jindo Spell SPELL_SHADOWSHOCK = 19460, SPELL_INVISIBLE = 24699 }; -class boss_jindo : public CreatureScript +enum Events { - public: + EVENT_BRAINWASHTOTEM = 0, + EVENT_POWERFULLHEALINGWARD = 1, + EVENT_HEX = 2, + EVENT_DELUSIONSOFJINDO = 3, + EVENT_TELEPORT = 4 +}; - boss_jindo() - : CreatureScript("boss_jindo") - { - } +Position const TeleportLoc = {-11583.7783f, -1249.4278f, 77.5471f, 4.745f}; - struct boss_jindoAI : public ScriptedAI - { - boss_jindoAI(Creature* creature) : ScriptedAI(creature) {} +class boss_jindo : public CreatureScript +{ + public: boss_jindo() : CreatureScript("boss_jindo") {} - uint32 BrainWashTotem_Timer; - uint32 HealingWard_Timer; - uint32 Hex_Timer; - uint32 Delusions_Timer; - uint32 Teleport_Timer; + struct boss_jindoAI : public BossAI + { + boss_jindoAI(Creature* creature) : BossAI(creature, DATA_JINDO) {} void Reset() { - BrainWashTotem_Timer = 20000; - HealingWard_Timer = 16000; - Hex_Timer = 8000; - Delusions_Timer = 10000; - Teleport_Timer = 5000; + _Reset(); + } + + void JustDied(Unit* /*killer*/) + { + _JustDied(); } void EnterCombat(Unit* /*who*/) { + _EnterCombat(); + events.ScheduleEvent(EVENT_BRAINWASHTOTEM, 20000); + events.ScheduleEvent(EVENT_POWERFULLHEALINGWARD, 16000); + events.ScheduleEvent(EVENT_HEX, 8000); + events.ScheduleEvent(EVENT_DELUSIONSOFJINDO, 10000); + events.ScheduleEvent(EVENT_TELEPORT, 5000); Talk(SAY_AGGRO); } - void UpdateAI(const uint32 diff) + void UpdateAI(uint32 diff) { if (!UpdateVictim()) return; - //BrainWashTotem_Timer - if (BrainWashTotem_Timer <= diff) - { - DoCast(me, SPELL_BRAINWASHTOTEM); - BrainWashTotem_Timer = urand(18000, 26000); - } else BrainWashTotem_Timer -= diff; - - //HealingWard_Timer - if (HealingWard_Timer <= diff) - { - //DoCast(me, SPELL_POWERFULLHEALINGWARD); - me->SummonCreature(14987, me->GetPositionX()+3, me->GetPositionY()-2, me->GetPositionZ(), 0, TEMPSUMMON_TIMED_OR_DEAD_DESPAWN, 30000); - HealingWard_Timer = urand(14000, 20000); - } else HealingWard_Timer -= diff; - - //Hex_Timer - if (Hex_Timer <= diff) - { - DoCast(me->getVictim(), SPELL_HEX); - - if (DoGetThreat(me->getVictim())) - DoModifyThreatPercent(me->getVictim(), -80); + events.Update(diff); - Hex_Timer = urand(12000, 20000); - } else Hex_Timer -= diff; - - //Casting the delusion curse with a shade. So shade will attack the same target with the curse. - if (Delusions_Timer <= diff) - { - if (Unit* target = SelectTarget(SELECT_TARGET_RANDOM, 0)) - { - DoCast(target, SPELL_DELUSIONSOFJINDO); - - Creature* Shade = me->SummonCreature(14986, target->GetPositionX(), target->GetPositionY(), target->GetPositionZ(), 0, TEMPSUMMON_TIMED_DESPAWN_OUT_OF_COMBAT, 15000); - if (Shade) - Shade->AI()->AttackStart(target); - } - - Delusions_Timer = urand(4000, 12000); - } else Delusions_Timer -= diff; + if (me->HasUnitState(UNIT_STATE_CASTING)) + return; - //Teleporting a random gamer and spawning 9 skeletons that will attack this gamer - if (Teleport_Timer <= diff) + while (uint32 eventId = events.ExecuteEvent()) { - Unit* target = NULL; - target = SelectTarget(SELECT_TARGET_RANDOM, 0); - if (target && target->GetTypeId() == TYPEID_PLAYER) + switch (eventId) { - DoTeleportPlayer(target, -11583.7783f, -1249.4278f, 77.5471f, 4.745f); - - if (DoGetThreat(me->getVictim())) - DoModifyThreatPercent(target, -100); - - Creature* Skeletons; - Skeletons = me->SummonCreature(14826, target->GetPositionX()+2, target->GetPositionY(), target->GetPositionZ(), 0, TEMPSUMMON_TIMED_DESPAWN_OUT_OF_COMBAT, 15000); - if (Skeletons) - Skeletons->AI()->AttackStart(target); - Skeletons = me->SummonCreature(14826, target->GetPositionX()-2, target->GetPositionY(), target->GetPositionZ(), 0, TEMPSUMMON_TIMED_DESPAWN_OUT_OF_COMBAT, 15000); - if (Skeletons) - Skeletons->AI()->AttackStart(target); - Skeletons = me->SummonCreature(14826, target->GetPositionX()+4, target->GetPositionY(), target->GetPositionZ(), 0, TEMPSUMMON_TIMED_DESPAWN_OUT_OF_COMBAT, 15000); - if (Skeletons) - Skeletons->AI()->AttackStart(target); - Skeletons = me->SummonCreature(14826, target->GetPositionX()-4, target->GetPositionY(), target->GetPositionZ(), 0, TEMPSUMMON_TIMED_DESPAWN_OUT_OF_COMBAT, 15000); - if (Skeletons) - Skeletons->AI()->AttackStart(target); - Skeletons = me->SummonCreature(14826, target->GetPositionX(), target->GetPositionY()+2, target->GetPositionZ(), 0, TEMPSUMMON_TIMED_DESPAWN_OUT_OF_COMBAT, 15000); - if (Skeletons) - Skeletons->AI()->AttackStart(target); - Skeletons = me->SummonCreature(14826, target->GetPositionX(), target->GetPositionY()-2, target->GetPositionZ(), 0, TEMPSUMMON_TIMED_DESPAWN_OUT_OF_COMBAT, 15000); - if (Skeletons) - Skeletons->AI()->AttackStart(target); - Skeletons = me->SummonCreature(14826, target->GetPositionX(), target->GetPositionY()+4, target->GetPositionZ(), 0, TEMPSUMMON_TIMED_DESPAWN_OUT_OF_COMBAT, 15000); - if (Skeletons) - Skeletons->AI()->AttackStart(target); - Skeletons = me->SummonCreature(14826, target->GetPositionX(), target->GetPositionY()-4, target->GetPositionZ(), 0, TEMPSUMMON_TIMED_DESPAWN_OUT_OF_COMBAT, 15000); - if (Skeletons) - Skeletons->AI()->AttackStart(target); - Skeletons = me->SummonCreature(14826, target->GetPositionX()+3, target->GetPositionY(), target->GetPositionZ(), 0, TEMPSUMMON_TIMED_DESPAWN_OUT_OF_COMBAT, 15000); - if (Skeletons) - Skeletons->AI()->AttackStart(target); + case EVENT_BRAINWASHTOTEM: + DoCast(me, SPELL_BRAINWASHTOTEM); + events.ScheduleEvent(EVENT_BRAINWASHTOTEM, urand(18000, 26000)); + break; + case EVENT_POWERFULLHEALINGWARD: // HACK + //DoCast(me, SPELL_POWERFULLHEALINGWARD); + me->SummonCreature(14987, me->GetPositionX()+3, me->GetPositionY()-2, me->GetPositionZ(), 0, TEMPSUMMON_TIMED_OR_DEAD_DESPAWN, 30000); + events.ScheduleEvent(EVENT_POWERFULLHEALINGWARD, urand(14000, 20000)); + break; + case EVENT_HEX: + if (Unit* target = me->getVictim()) + { + DoCast(target, SPELL_HEX, true); + if (DoGetThreat(target)) + DoModifyThreatPercent(target, -80); + } + events.ScheduleEvent(EVENT_HEX, urand(12000, 20000)); + break; + case EVENT_DELUSIONSOFJINDO: // HACK + // Casting the delusion curse with a shade so shade will attack the same target with the curse. + if (Unit* target = SelectTarget(SELECT_TARGET_RANDOM, 0)) + { + DoCast(target, SPELL_DELUSIONSOFJINDO); + Creature* Shade = me->SummonCreature(NPC_SHADE_OF_JINDO, target->GetPositionX(), target->GetPositionY(), target->GetPositionZ(), 0, TEMPSUMMON_TIMED_DESPAWN_OUT_OF_COMBAT, 15000); + if (Shade) + Shade->AI()->AttackStart(target); + } + events.ScheduleEvent(EVENT_DELUSIONSOFJINDO, urand(4000, 12000)); + break; + case EVENT_TELEPORT: // Possible HACK + // Teleports a random player and spawns 9 Sacrificed Trolls to attack player + if (Unit* target = SelectTarget(SELECT_TARGET_RANDOM, 0)) + { + DoTeleportPlayer(target, TeleportLoc.m_positionX, TeleportLoc.m_positionY, TeleportLoc.m_positionZ, TeleportLoc.m_orientation); + if (DoGetThreat(me->getVictim())) + DoModifyThreatPercent(target, -100); + Creature* SacrificedTroll; + SacrificedTroll = me->SummonCreature(NPC_SACRIFICED_TROLL, target->GetPositionX()+2, target->GetPositionY(), target->GetPositionZ(), 0, TEMPSUMMON_TIMED_DESPAWN_OUT_OF_COMBAT, 15000); + if (SacrificedTroll) + SacrificedTroll->AI()->AttackStart(target); + SacrificedTroll = me->SummonCreature(NPC_SACRIFICED_TROLL, target->GetPositionX()-2, target->GetPositionY(), target->GetPositionZ(), 0, TEMPSUMMON_TIMED_DESPAWN_OUT_OF_COMBAT, 15000); + if (SacrificedTroll) + SacrificedTroll->AI()->AttackStart(target); + SacrificedTroll = me->SummonCreature(NPC_SACRIFICED_TROLL, target->GetPositionX()+4, target->GetPositionY(), target->GetPositionZ(), 0, TEMPSUMMON_TIMED_DESPAWN_OUT_OF_COMBAT, 15000); + if (SacrificedTroll) + SacrificedTroll->AI()->AttackStart(target); + SacrificedTroll = me->SummonCreature(NPC_SACRIFICED_TROLL, target->GetPositionX()-4, target->GetPositionY(), target->GetPositionZ(), 0, TEMPSUMMON_TIMED_DESPAWN_OUT_OF_COMBAT, 15000); + if (SacrificedTroll) + SacrificedTroll->AI()->AttackStart(target); + SacrificedTroll = me->SummonCreature(NPC_SACRIFICED_TROLL, target->GetPositionX(), target->GetPositionY()+2, target->GetPositionZ(), 0, TEMPSUMMON_TIMED_DESPAWN_OUT_OF_COMBAT, 15000); + if (SacrificedTroll) + SacrificedTroll->AI()->AttackStart(target); + SacrificedTroll = me->SummonCreature(NPC_SACRIFICED_TROLL, target->GetPositionX(), target->GetPositionY()-2, target->GetPositionZ(), 0, TEMPSUMMON_TIMED_DESPAWN_OUT_OF_COMBAT, 15000); + if (SacrificedTroll) + SacrificedTroll->AI()->AttackStart(target); + SacrificedTroll = me->SummonCreature(NPC_SACRIFICED_TROLL, target->GetPositionX(), target->GetPositionY()+4, target->GetPositionZ(), 0, TEMPSUMMON_TIMED_DESPAWN_OUT_OF_COMBAT, 15000); + if (SacrificedTroll) + SacrificedTroll->AI()->AttackStart(target); + SacrificedTroll = me->SummonCreature(NPC_SACRIFICED_TROLL, target->GetPositionX(), target->GetPositionY()-4, target->GetPositionZ(), 0, TEMPSUMMON_TIMED_DESPAWN_OUT_OF_COMBAT, 15000); + if (SacrificedTroll) + SacrificedTroll->AI()->AttackStart(target); + SacrificedTroll = me->SummonCreature(NPC_SACRIFICED_TROLL, target->GetPositionX()+3, target->GetPositionY(), target->GetPositionZ(), 0, TEMPSUMMON_TIMED_DESPAWN_OUT_OF_COMBAT, 15000); + if (SacrificedTroll) + SacrificedTroll->AI()->AttackStart(target); + } + events.ScheduleEvent(EVENT_TELEPORT, urand(15000, 23000)); + break; + default: + break; } - - Teleport_Timer = urand(15000, 23000); - } else Teleport_Timer -= diff; + } DoMeleeAttackIfReady(); } @@ -209,7 +212,7 @@ class mob_healing_ward : public CreatureScript { } - void UpdateAI (const uint32 diff) + void UpdateAI(uint32 diff) { //Heal_Timer if (Heal_Timer <= diff) @@ -257,7 +260,7 @@ class mob_shade_of_jindo : public CreatureScript void EnterCombat(Unit* /*who*/){} - void UpdateAI (const uint32 diff) + void UpdateAI(uint32 diff) { //ShadowShock_Timer @@ -283,4 +286,3 @@ void AddSC_boss_jindo() new mob_healing_ward(); new mob_shade_of_jindo(); } - diff --git a/src/server/scripts/EasternKingdoms/ZulGurub/boss_mandokir.cpp b/src/server/scripts/EasternKingdoms/ZulGurub/boss_mandokir.cpp index bcc080bb8a5..bd7b7a8798c 100644 --- a/src/server/scripts/EasternKingdoms/ZulGurub/boss_mandokir.cpp +++ b/src/server/scripts/EasternKingdoms/ZulGurub/boss_mandokir.cpp @@ -25,336 +25,404 @@ EndScriptData */ #include "ScriptMgr.h" #include "ScriptedCreature.h" +#include "Spell.h" +#include "SpellAuras.h" +#include "SpellScript.h" #include "zulgurub.h" -enum Mandokir +enum Says { - SAY_AGGRO = 0, - SAY_DING_KILL = 1, - SAY_WATCH = 2, - SAY_WATCH_WHISPER = 3, //is this text for real? easter egg? - SAY_GRATS_JINDO = 0, - - SPELL_CHARGE = 24408, - SPELL_CLEAVE = 7160, - SPELL_FEAR = 29321, - SPELL_WHIRLWIND = 15589, - SPELL_MORTAL_STRIKE = 16856, - SPELL_ENRAGE = 24318, - SPELL_WATCH = 24314, - SPELL_LEVEL_UP = 24312, - -//Ohgans Spells - SPELL_SUNDERARMOR = 24317, - - NPC_SPEAKER = 11391 + SAY_AGGRO = 0, + SAY_DING_KILL = 1, + SAY_WATCH = 2, + SAY_WATCH_WHISPER = 3, + SAY_OHGAN_DEAD = 4, + SAY_GRATS_JINDO = 0, }; -class boss_mandokir : public CreatureScript +enum Spells { - public: + SPELL_CHARGE = 24408, // seen + SPELL_OVERPOWER = 24407, // Seen + SPELL_FEAR = 29321, + SPELL_WHIRLWIND = 13736, // Triggers 15589 + SPELL_MORTAL_STRIKE = 16856, // Seen + SPELL_FRENZY = 24318, // seen + SPELL_WATCH = 24314, // seen 24315, 24316 + SPELL_WATCH_CHARGE = 24315, // Triggers 24316 + SPELL_LEVEL_UP = 24312 // +}; - boss_mandokir() - : CreatureScript("boss_mandokir") - { - } +enum Events +{ + EVENT_CHECK_SPEAKER = 1, + EVENT_CHECK_START = 2, + EVENT_STARTED = 3, + EVENT_OVERPOWER = 4, + EVENT_MORTAL_STRIKE = 5, + EVENT_WHIRLWIND = 6, + EVENT_CHECK_OHGAN = 7, + EVENT_WATCH_PLAYER = 8, + EVENT_CHARGE_PLAYER = 9 +}; - struct boss_mandokirAI : public ScriptedAI - { - boss_mandokirAI(Creature* creature) : ScriptedAI(creature) - { - instance = creature->GetInstanceScript(); - } +enum Misc +{ + MODEL_OHGAN_MOUNT = 15271, + PATH_MANDOKIR = 492861, + POINT_MANDOKIR_END = 24, + CHAINED_SPIRT_COUNT = 20 +}; - uint32 KillCount; - uint32 Watch_Timer; - uint32 TargetInRange; - uint32 Cleave_Timer; - uint32 Whirlwind_Timer; - uint32 Fear_Timer; - uint32 MortalStrike_Timer; - uint32 Check_Timer; - float targetX; - float targetY; - float targetZ; +Position const PosSummonChainedSpirits[CHAINED_SPIRT_COUNT] = +{ + { -12167.17f, -1979.330f, 133.0992f, 2.268928f }, + { -12262.74f, -1953.394f, 133.5496f, 0.593412f }, + { -12176.89f, -1983.068f, 133.7841f, 2.129302f }, + { -12226.45f, -1977.933f, 132.7982f, 1.466077f }, + { -12204.74f, -1890.431f, 135.7569f, 4.415683f }, + { -12216.70f, -1891.806f, 136.3496f, 4.677482f }, + { -12236.19f, -1892.034f, 134.1041f, 5.044002f }, + { -12248.24f, -1893.424f, 134.1182f, 5.270895f }, + { -12257.36f, -1897.663f, 133.1484f, 5.462881f }, + { -12265.84f, -1903.077f, 133.1649f, 5.654867f }, + { -12158.69f, -1972.707f, 133.8751f, 2.408554f }, + { -12178.82f, -1891.974f, 134.1786f, 3.944444f }, + { -12193.36f, -1890.039f, 135.1441f, 4.188790f }, + { -12275.59f, -1932.845f, 134.9017f, 0.174533f }, + { -12273.51f, -1941.539f, 136.1262f, 0.314159f }, + { -12247.02f, -1963.497f, 133.9476f, 0.872665f }, + { -12238.68f, -1969.574f, 133.6273f, 1.134464f }, + { -12192.78f, -1982.116f, 132.6966f, 1.919862f }, + { -12210.81f, -1979.316f, 133.8700f, 1.797689f }, + { -12283.51f, -1924.839f, 133.5170f, 0.069813f } +}; - InstanceScript* instance; +Position const PosMandokir[2] = +{ + { -12167.8f, -1927.25f, 153.73f, 3.76991f }, + { -12197.86f, -1949.392f, 130.2745f, 0.0f } +}; - bool endWatch; - bool someWatched; - bool RaptorDead; - bool CombatStart; - bool SpeakerDead; +class boss_mandokir : public CreatureScript +{ + public: boss_mandokir() : CreatureScript("boss_mandokir") {} - uint64 WatchTarget; + struct boss_mandokirAI : public BossAI + { + boss_mandokirAI(Creature* creature) : BossAI(creature, DATA_MANDOKIR) { } void Reset() { - KillCount = 0; - Watch_Timer = 33000; - Cleave_Timer = 7000; - Whirlwind_Timer = 20000; - Fear_Timer = 1000; - MortalStrike_Timer = 1000; - Check_Timer = 1000; - - targetX = 0.0f; - targetY = 0.0f; - targetZ = 0.0f; - TargetInRange = 0; - - WatchTarget = 0; - - someWatched = false; - endWatch = false; - RaptorDead = false; - CombatStart = false; - SpeakerDead = false; - - DoCast(me, 23243); + if (me->GetPositionZ() > 140.0f) + { + _Reset(); + killCount = 0; + me->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_IMMUNE_TO_PC|UNIT_FLAG_IMMUNE_TO_NPC); + events.ScheduleEvent(EVENT_CHECK_START, 1000); + if (Creature* speaker = Creature::GetCreature(*me, instance->GetData64(NPC_VILEBRANCH_SPEAKER))) + if (!speaker->isAlive()) + speaker->Respawn(true); + } + summons.DespawnAll(); + me->Mount(MODEL_OHGAN_MOUNT); } - void KilledUnit(Unit* victim) + void JustDied(Unit* /*killer*/) { - if (victim->GetTypeId() == TYPEID_PLAYER) - { - ++KillCount; - - if (KillCount == 3) - { - Talk(SAY_DING_KILL); - - if (instance) - { - uint64 JindoGUID = instance->GetData64(DATA_JINDO); - if (JindoGUID) - { - if (Creature* jTemp = Creature::GetCreature(*me, JindoGUID)) - { - if (jTemp->isAlive()) - jTemp->AI()->Talk(SAY_GRATS_JINDO); - } - } - } - DoCast(me, SPELL_LEVEL_UP, true); - KillCount = 0; - } - } + // Do not want to unsummon Ohgan + for (int i = 0; i < CHAINED_SPIRT_COUNT; ++i) + if (Creature* unsummon = Creature::GetCreature(*me, chainedSpirtGUIDs[i])) + unsummon->DespawnOrUnsummon(); + instance->SetBossState(DATA_MANDOKIR, DONE); + instance->SaveToDB(); } void EnterCombat(Unit* /*who*/) { + _EnterCombat(); + events.ScheduleEvent(EVENT_OVERPOWER, urand(7000, 9000)); + events.ScheduleEvent(EVENT_MORTAL_STRIKE, urand(12000, 18000)); + events.ScheduleEvent(EVENT_WHIRLWIND, urand(24000, 30000)); + events.ScheduleEvent(EVENT_CHECK_OHGAN, 1000); + events.ScheduleEvent(EVENT_WATCH_PLAYER, urand(13000, 15000)); + events.ScheduleEvent(EVENT_CHARGE_PLAYER, urand(33000, 38000)); + me->SetHomePosition(me->GetPositionX(), me->GetPositionY(), me->GetPositionZ(), me->GetOrientation()); Talk(SAY_AGGRO); + me->Dismount(); + // Summon Ohgan (Spell missing) TEMP HACK + me->SummonCreature(NPC_OHGAN, me->GetPositionX()-3, me->GetPositionY(), me->GetPositionZ(), me->GetOrientation(), TEMPSUMMON_TIMED_DESPAWN_OUT_OF_COMBAT, 35000); + // Summon Chained Spirits + for (int i = 0; i < CHAINED_SPIRT_COUNT; ++i) + { + Creature* chainedSpirt = me->SummonCreature(NPC_CHAINED_SPIRT, PosSummonChainedSpirits[i], TEMPSUMMON_CORPSE_DESPAWN); + chainedSpirtGUIDs[i] = chainedSpirt->GetGUID(); + } + DoZoneInCombat(); } - void UpdateAI(const uint32 diff) + void KilledUnit(Unit* victim) { - if (!SpeakerDead) + if (victim->GetTypeId() != TYPEID_PLAYER) + return; + + if (++killCount == 3) { - if (!me->FindNearestCreature(NPC_SPEAKER, 100.0f, true)) + Talk(SAY_DING_KILL); + if (Creature* jindo = Creature::GetCreature(*me, instance->GetData64(DATA_JINDO))) + if (jindo->isAlive()) + jindo->AI()->Talk(SAY_GRATS_JINDO); + DoCast(me, SPELL_LEVEL_UP, true); + killCount = 0; + } + } + + void MovementInform(uint32 type, uint32 id) + { + if (type == WAYPOINT_MOTION_TYPE) + { + me->SetWalk(false); + if (id == POINT_MANDOKIR_END) { - me->GetMotionMaster()->MovePoint(0, -12196.3f, -1948.37f, 130.36f); - SpeakerDead = true; + me->SetHomePosition(PosMandokir[0]); + instance->SetBossState(DATA_MANDOKIR, NOT_STARTED); + me->DespawnOrUnsummon(6000); // No idea how to respawn on wipe. } } + } - if (me->GetMotionMaster()->GetCurrentMovementGeneratorType() != POINT_MOTION_TYPE && SpeakerDead) - me->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_IMMUNE_TO_PC); + void UpdateAI(uint32 diff) + { + events.Update(diff); if (!UpdateVictim()) - return; - - if (me->getVictim() && me->isAlive()) { - if (!CombatStart) + if (instance->GetBossState(DATA_MANDOKIR) == NOT_STARTED || instance->GetBossState(DATA_MANDOKIR) == SPECIAL) { - //At combat Start Mandokir is mounted so we must unmount it first - me->Dismount(); - - //And summon his raptor - me->SummonCreature(14988, me->getVictim()->GetPositionX(), me->getVictim()->GetPositionY(), me->getVictim()->GetPositionZ(), 0, TEMPSUMMON_TIMED_DESPAWN_OUT_OF_COMBAT, 35000); - CombatStart = true; - } - - if (Watch_Timer <= diff) //Every 20 Sec Mandokir will check this - { - if (WatchTarget) //If someone is watched and If the Position of the watched target is different from the one stored, or are attacking, mandokir will charge him + while (uint32 eventId = events.ExecuteEvent()) { - Unit* unit = Unit::GetUnit(*me, WatchTarget); - - if (unit && ( - targetX != unit->GetPositionX() || - targetY != unit->GetPositionY() || - targetZ != unit->GetPositionZ() || - unit->isInCombat())) + switch (eventId) { - if (me->IsWithinMeleeRange(unit)) - { - DoCast(unit, 24316); - } - else - { - DoCast(unit, SPELL_CHARGE); - //me->SendMonsterMove(unit->GetPositionX(), unit->GetPositionY(), unit->GetPositionZ(), 0, true, 1); - AttackStart(unit); - } + case EVENT_CHECK_START: + if (instance->GetBossState(DATA_MANDOKIR) == SPECIAL) + { + me->GetMotionMaster()->MovePoint(0, PosMandokir[1].m_positionX, PosMandokir[1].m_positionY, PosMandokir[1].m_positionZ); + events.ScheduleEvent(EVENT_STARTED, 6000); + } + else + events.ScheduleEvent(EVENT_CHECK_START, 1000); + break; + case EVENT_STARTED: + me->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_IMMUNE_TO_PC|UNIT_FLAG_IMMUNE_TO_NPC); + me->GetMotionMaster()->MovePath(PATH_MANDOKIR, false); + break; + default: + break; } } - someWatched = false; - Watch_Timer = 20000; - } else Watch_Timer -= diff; - - if ((Watch_Timer < 8000) && !someWatched) //8 sec(cast time + expire time) before the check for the watch effect mandokir will cast watch debuff on a random target - { - if (Unit* p = SelectTarget(SELECT_TARGET_RANDOM, 0)) - { - Talk(SAY_WATCH, p->GetGUID()); - DoCast(p, SPELL_WATCH); - WatchTarget = p->GetGUID(); - someWatched = true; - endWatch = true; - } } + return; + } - if ((Watch_Timer < 1000) && endWatch) //1 sec before the debuf expire, store the target position - { - Unit* unit = Unit::GetUnit(*me, WatchTarget); - if (unit) - { - targetX = unit->GetPositionX(); - targetY = unit->GetPositionY(); - targetZ = unit->GetPositionZ(); - } - endWatch = false; - } + if (me->HasUnitState(UNIT_STATE_CASTING)) + return; - if (!someWatched) + while (uint32 eventId = events.ExecuteEvent()) + { + switch (eventId) { - //Cleave - if (Cleave_Timer <= diff) - { - DoCast(me->getVictim(), SPELL_CLEAVE); - Cleave_Timer = 7000; - } else Cleave_Timer -= diff; - - //Whirlwind - if (Whirlwind_Timer <= diff) - { + case EVENT_OVERPOWER: + DoCastVictim(SPELL_OVERPOWER, true); + events.ScheduleEvent(EVENT_OVERPOWER, urand(6000, 12000)); + break; + case EVENT_MORTAL_STRIKE: + if (me->getVictim() && me->getVictim()->HealthBelowPct(50)) + DoCastVictim(SPELL_MORTAL_STRIKE, true); + events.ScheduleEvent(EVENT_MORTAL_STRIKE, urand(12000, 18000)); + break; + case EVENT_WHIRLWIND: DoCast(me, SPELL_WHIRLWIND); - Whirlwind_Timer = 18000; - } else Whirlwind_Timer -= diff; - - //If more then 3 targets in melee range mandokir will cast fear - if (Fear_Timer <= diff) - { - TargetInRange = 0; - - std::list<HostileReference*>::const_iterator i = me->getThreatManager().getThreatList().begin(); - for (; i != me->getThreatManager().getThreatList().end(); ++i) + events.ScheduleEvent(EVENT_WHIRLWIND, urand(22000, 26000)); + break; + case EVENT_CHECK_OHGAN: + if (instance->GetBossState(DATA_OHGAN) == DONE) { - Unit* unit = Unit::GetUnit(*me, (*i)->getUnitGuid()); - if (unit && me->IsWithinMeleeRange(unit)) - ++TargetInRange; + DoCast(me, SPELL_FRENZY); + Talk(SAY_OHGAN_DEAD); } - - if (TargetInRange > 3) - DoCast(me->getVictim(), SPELL_FEAR); - - Fear_Timer = 4000; - } else Fear_Timer -=diff; - - //Mortal Strike if target below 50% hp - if (me->getVictim() && me->getVictim()->HealthBelowPct(50)) - { - if (MortalStrike_Timer <= diff) - { - DoCast(me->getVictim(), SPELL_MORTAL_STRIKE); - MortalStrike_Timer = 15000; - } else MortalStrike_Timer -= diff; - } - } - //Checking if Ohgan is dead. If yes Mandokir will enrage. - if (Check_Timer <= diff) - { - if (instance) - { - if (instance->GetData(DATA_OHGAN) == DONE) + else + events.ScheduleEvent(EVENT_CHECK_OHGAN, 1000); + break; + case EVENT_WATCH_PLAYER: + if (Unit* player = SelectTarget(SELECT_TARGET_RANDOM, 0, 100, true)) { - if (!RaptorDead) - { - DoCast(me, SPELL_ENRAGE); - RaptorDead = true; - } + DoCast(player, SPELL_WATCH); + Talk(SAY_WATCH, player->GetGUID()); } - } - - Check_Timer = 1000; - } else Check_Timer -= diff; - - DoMeleeAttackIfReady(); + events.ScheduleEvent(EVENT_WATCH_PLAYER, urand(12000, 15000)); + break; + case EVENT_CHARGE_PLAYER: + DoCast(SelectTarget(SELECT_TARGET_RANDOM, 0, 40, true), SPELL_CHARGE); + events.ScheduleEvent(EVENT_CHARGE_PLAYER, urand(22000, 30000)); + break; + default: + break; + } } + + DoMeleeAttackIfReady(); } + + private: + uint8 killCount; + uint64 chainedSpirtGUIDs[CHAINED_SPIRT_COUNT]; }; CreatureAI* GetAI(Creature* creature) const { - return new boss_mandokirAI(creature); + return GetZulGurubAI<boss_mandokirAI>(creature); } }; -//Ohgan -class mob_ohgan : public CreatureScript +// Ohgan + +enum OhganSpells { - public: + SPELL_SUNDERARMOR = 24317 +}; - mob_ohgan() - : CreatureScript("mob_ohgan") - { - } +class mob_ohgan : public CreatureScript +{ + public: mob_ohgan() : CreatureScript("mob_ohgan") {} struct mob_ohganAI : public ScriptedAI { - mob_ohganAI(Creature* creature) : ScriptedAI(creature) + mob_ohganAI(Creature* creature) : ScriptedAI(creature), instance(creature->GetInstanceScript()) { } + + void Reset() { - instance = creature->GetInstanceScript(); + SunderArmor_Timer = 5000; + } + + void EnterCombat(Unit* /*who*/) {} + + void JustDied(Unit* /*killer*/) + { + instance->SetBossState(DATA_OHGAN, DONE); + } + + void UpdateAI(uint32 diff) + { + // Return since we have no target + if (!UpdateVictim()) + return; + + if (SunderArmor_Timer <= diff) + { + DoCastVictim(SPELL_SUNDERARMOR, true); + SunderArmor_Timer = urand(10000, 15000); + } else SunderArmor_Timer -= diff; + + DoMeleeAttackIfReady(); } + private: uint32 SunderArmor_Timer; InstanceScript* instance; + }; + + CreatureAI* GetAI(Creature* creature) const + { + return GetZulGurubAI<mob_ohganAI>(creature); + } +}; + +enum VilebranchSpells +{ + SPELL_DEMORALIZING_SHOUT = 13730, + SPELL_CLEAVE = 15284 +}; + +class mob_vilebranch_speaker : public CreatureScript +{ + public: mob_vilebranch_speaker() : CreatureScript("mob_vilebranch_speaker") {} + + struct mob_vilebranch_speakerAI : public ScriptedAI + { + mob_vilebranch_speakerAI(Creature* creature) : ScriptedAI(creature), instance(creature->GetInstanceScript()) { } void Reset() { - SunderArmor_Timer = 5000; + demoralizing_Shout_Timer = urand (2000, 4000); + cleave_Timer = urand (5000, 8000); } void EnterCombat(Unit* /*who*/) {} void JustDied(Unit* /*killer*/) { - if (instance) - instance->SetData(DATA_OHGAN, DONE); + instance->SetBossState(DATA_MANDOKIR, SPECIAL); } - void UpdateAI (const uint32 diff) + void UpdateAI(uint32 diff) { - //Return since we have no target + // Return since we have no target if (!UpdateVictim()) return; - //SunderArmor_Timer - if (SunderArmor_Timer <= diff) + if (demoralizing_Shout_Timer <= diff) { - DoCast(me->getVictim(), SPELL_SUNDERARMOR); - SunderArmor_Timer = urand(10000, 15000); - } else SunderArmor_Timer -= diff; + DoCast(me, SPELL_DEMORALIZING_SHOUT); + demoralizing_Shout_Timer = urand(22000, 30000); + } else demoralizing_Shout_Timer -= diff; + + if (cleave_Timer <= diff) + { + DoCastVictim(SPELL_CLEAVE, true); + cleave_Timer = urand(6000, 9000); + } else cleave_Timer -= diff; DoMeleeAttackIfReady(); } + + private: + uint32 demoralizing_Shout_Timer; + uint32 cleave_Timer; + InstanceScript* instance; }; CreatureAI* GetAI(Creature* creature) const { - return new mob_ohganAI(creature); + return new mob_vilebranch_speakerAI(creature); + } +}; + +class spell_threatening_gaze : public SpellScriptLoader +{ + public: + spell_threatening_gaze() : SpellScriptLoader("spell_threatening_gaze") { } + + class spell_threatening_gaze_AuraScript : public AuraScript + { + PrepareAuraScript(spell_threatening_gaze_AuraScript); + + void OnRemove(AuraEffect const* /*aurEff*/, AuraEffectHandleModes /*mode*/) + { + if (Unit* caster = GetCaster()) + if(Unit* target = GetTarget()) + if (GetTargetApplication()->GetRemoveMode() != AURA_REMOVE_BY_EXPIRE && GetTargetApplication()->GetRemoveMode() != AURA_REMOVE_BY_DEATH) + caster->CastSpell(target, SPELL_WATCH_CHARGE); + } + + void Register() + { + OnEffectRemove += AuraEffectRemoveFn(spell_threatening_gaze_AuraScript::OnRemove, EFFECT_0, SPELL_AURA_DUMMY, AURA_EFFECT_HANDLE_REAL); + } + }; + + AuraScript* GetAuraScript() const + { + return new spell_threatening_gaze_AuraScript(); } }; @@ -362,5 +430,6 @@ void AddSC_boss_mandokir() { new boss_mandokir(); new mob_ohgan(); + new mob_vilebranch_speaker(); + new spell_threatening_gaze(); } - diff --git a/src/server/scripts/EasternKingdoms/ZulGurub/boss_marli.cpp b/src/server/scripts/EasternKingdoms/ZulGurub/boss_marli.cpp index 56aeee93ee2..b1200c2899e 100644 --- a/src/server/scripts/EasternKingdoms/ZulGurub/boss_marli.cpp +++ b/src/server/scripts/EasternKingdoms/ZulGurub/boss_marli.cpp @@ -27,192 +27,189 @@ EndScriptData */ #include "ScriptedCreature.h" #include "zulgurub.h" -enum Marli +enum Says { SAY_AGGRO = 0, SAY_TRANSFORM = 1, SAY_SPIDER_SPAWN = 2, - SAY_DEATH = 3, + SAY_DEATH = 3 +}; + +enum Spells +{ + SPELL_CHARGE = 22911, + SPELL_ASPECT_OF_MARLI = 24686, // A stun spell + SPELL_ENVOLWINGWEB = 24110, + SPELL_POISON_VOLLEY = 24099, + SPELL_SPIDER_FORM = 24084, + // The Spider Spell + SPELL_LEVELUP = 24312 // Not right Spell. +}; - SPELL_CHARGE = 22911, - SPELL_ASPECT_OF_MARLI = 24686, // A stun spell - SPELL_ENVOLWINGWEB = 24110, - SPELL_POISONVOLLEY = 24099, - SPELL_SPIDER_FORM = 24084, +enum Events +{ + EVENT_SPAWN_START_SPIDERS = 0, // Phase 1 + EVENT_POISON_VOLLEY = 1, // Phase All + EVENT_SPAWN_SPIDER = 2, // Phase All + EVENT_CHARGE_PLAYER = 3, // Phase 3 + EVENT_ASPECT_OF_MARLI = 4, // Phase 2 + EVENT_TRANSFORM = 5, // Phase 2 + EVENT_TRANSFORM_BACK = 6 // Phase 3 +}; -//The Spider Spells - SPELL_LEVELUP = 24312 //Not right Spell. +enum Phases +{ + PHASE_ONE = 1, + PHASE_TWO = 2, + PHASE_THREE = 3 +}; + +enum ModelId +{ + MODEL_MARLI = 15220 }; class boss_marli : public CreatureScript { - public: + public: boss_marli() : CreatureScript("boss_marli") {} - boss_marli() - : CreatureScript("boss_marli") + struct boss_marliAI : public BossAI { - } + boss_marliAI(Creature* creature) : BossAI(creature, DATA_MARLI) {} - struct boss_marliAI : public ScriptedAI - { - boss_marliAI(Creature* creature) : ScriptedAI(creature) + void Reset() { - instance = creature->GetInstanceScript(); + _Reset(); } - InstanceScript* instance; - - uint32 SpawnStartSpiders_Timer; - uint32 PoisonVolley_Timer; - uint32 SpawnSpider_Timer; - uint32 Charge_Timer; - uint32 Aspect_Timer; - uint32 Transform_Timer; - uint32 TransformBack_Timer; - - bool Spawned; - bool PhaseTwo; - - void Reset() + void JustDied(Unit* /*killer*/) { - SpawnStartSpiders_Timer = 1000; - PoisonVolley_Timer = 15000; - SpawnSpider_Timer = 30000; - Charge_Timer = 1500; - Aspect_Timer = 12000; - Transform_Timer = 45000; - TransformBack_Timer = 25000; - - Spawned = false; - PhaseTwo = false; + _JustDied(); + Talk(SAY_DEATH); } void EnterCombat(Unit* /*who*/) { + _EnterCombat(); + events.ScheduleEvent(EVENT_SPAWN_START_SPIDERS, 1000, 0, PHASE_ONE); Talk(SAY_AGGRO); } - void JustDied(Unit* /*killer*/) - { - Talk(SAY_DEATH); - if (instance) - instance->SetData(DATA_MARLI, DONE); - } - - void UpdateAI(const uint32 diff) + void UpdateAI(uint32 diff) { if (!UpdateVictim()) return; - if (me->getVictim() && me->isAlive()) - { - if (PoisonVolley_Timer <= diff) - { - DoCast(me->getVictim(), SPELL_POISONVOLLEY); - PoisonVolley_Timer = urand(10000, 20000); - } else PoisonVolley_Timer -= diff; + events.Update(diff); - if (!PhaseTwo && Aspect_Timer <= diff) - { - DoCast(me->getVictim(), SPELL_ASPECT_OF_MARLI); - Aspect_Timer = urand(13000, 18000); - } else Aspect_Timer -= diff; - - if (!Spawned && SpawnStartSpiders_Timer <= diff) - { - Talk(SAY_SPIDER_SPAWN); - - Unit* target = SelectTarget(SELECT_TARGET_RANDOM, 0); - if (!target) - return; - - Creature* Spider = NULL; - - Spider = me->SummonCreature(15041, target->GetPositionX(), target->GetPositionY(), target->GetPositionZ(), 0, TEMPSUMMON_TIMED_DESPAWN_OUT_OF_COMBAT, 15000); - if (Spider) - Spider->AI()->AttackStart(target); - Spider = me->SummonCreature(15041, target->GetPositionX(), target->GetPositionY(), target->GetPositionZ(), 0, TEMPSUMMON_TIMED_DESPAWN_OUT_OF_COMBAT, 15000); - if (Spider) - Spider->AI()->AttackStart(target); - Spider = me->SummonCreature(15041, target->GetPositionX(), target->GetPositionY(), target->GetPositionZ(), 0, TEMPSUMMON_TIMED_DESPAWN_OUT_OF_COMBAT, 15000); - if (Spider) - Spider->AI()->AttackStart(target); - Spider = me->SummonCreature(15041, target->GetPositionX(), target->GetPositionY(), target->GetPositionZ(), 0, TEMPSUMMON_TIMED_DESPAWN_OUT_OF_COMBAT, 15000); - if (Spider) - Spider->AI()->AttackStart(target); - - Spawned = true; - } else SpawnStartSpiders_Timer -= diff; - - if (SpawnSpider_Timer <= diff) - { - Unit* target = SelectTarget(SELECT_TARGET_RANDOM, 0); - if (!target) - return; - - Creature* Spider = me->SummonCreature(15041, target->GetPositionX(), target->GetPositionY(), target->GetPositionZ(), 0, TEMPSUMMON_TIMED_DESPAWN_OUT_OF_COMBAT, 15000); - if (Spider) - Spider->AI()->AttackStart(target); - SpawnSpider_Timer = urand(12000, 17000); - } else SpawnSpider_Timer -= diff; + if (me->HasUnitState(UNIT_STATE_CASTING)) + return; - if (!PhaseTwo && Transform_Timer <= diff) + while (uint32 eventId = events.ExecuteEvent()) + { + switch (eventId) { - Talk(SAY_TRANSFORM); - DoCast(me, SPELL_SPIDER_FORM); - const CreatureTemplate* cinfo = me->GetCreatureTemplate(); - me->SetBaseWeaponDamage(BASE_ATTACK, MINDAMAGE, (cinfo->mindmg +((cinfo->mindmg/100) * 35))); - me->SetBaseWeaponDamage(BASE_ATTACK, MAXDAMAGE, (cinfo->maxdmg +((cinfo->maxdmg/100) * 35))); - me->UpdateDamagePhysical(BASE_ATTACK); - DoCast(me->getVictim(), SPELL_ENVOLWINGWEB); - - if (DoGetThreat(me->getVictim())) - DoModifyThreatPercent(me->getVictim(), -100); + case EVENT_SPAWN_START_SPIDERS: - PhaseTwo = true; - Transform_Timer = urand(35000, 60000); - } else Transform_Timer -= diff; - - if (PhaseTwo) - { - if (Charge_Timer <= diff) - { - Unit* target = NULL; - int i = 0; - while (i < 3) // max 3 tries to get a random target with power_mana + if (Unit* target = SelectTarget(SELECT_TARGET_RANDOM, 0)) { - ++i; - target = SelectTarget(SELECT_TARGET_RANDOM, 1, 100, true); // not aggro leader - if (target && target->getPowerType() == POWER_MANA) + Talk(SAY_SPIDER_SPAWN); + Creature* Spider = NULL; + Spider = me->SummonCreature(15041, target->GetPositionX(), target->GetPositionY(), target->GetPositionZ(), 0, TEMPSUMMON_TIMED_DESPAWN_OUT_OF_COMBAT, 15000); + if (Spider) + Spider->AI()->AttackStart(target); + Spider = me->SummonCreature(15041, target->GetPositionX(), target->GetPositionY(), target->GetPositionZ(), 0, TEMPSUMMON_TIMED_DESPAWN_OUT_OF_COMBAT, 15000); + if (Spider) + Spider->AI()->AttackStart(target); + Spider = me->SummonCreature(15041, target->GetPositionX(), target->GetPositionY(), target->GetPositionZ(), 0, TEMPSUMMON_TIMED_DESPAWN_OUT_OF_COMBAT, 15000); + if (Spider) + Spider->AI()->AttackStart(target); + Spider = me->SummonCreature(15041, target->GetPositionX(), target->GetPositionY(), target->GetPositionZ(), 0, TEMPSUMMON_TIMED_DESPAWN_OUT_OF_COMBAT, 15000); + if (Spider) + Spider->AI()->AttackStart(target); + } + events.ScheduleEvent(EVENT_ASPECT_OF_MARLI, 12000, 0, PHASE_TWO); + events.ScheduleEvent(EVENT_TRANSFORM, 45000, 0, PHASE_TWO); + events.ScheduleEvent(EVENT_POISON_VOLLEY, 15000); + events.ScheduleEvent(EVENT_SPAWN_SPIDER, 30000); + events.ScheduleEvent(EVENT_TRANSFORM, 45000, 0, PHASE_TWO); + events.SetPhase(PHASE_TWO); + break; + case EVENT_POISON_VOLLEY: + DoCastVictim(SPELL_POISON_VOLLEY, true); + events.ScheduleEvent(EVENT_POISON_VOLLEY, urand(10000, 20000)); + break; + case EVENT_ASPECT_OF_MARLI: + DoCastVictim(SPELL_ASPECT_OF_MARLI, true); + events.ScheduleEvent(EVENT_ASPECT_OF_MARLI, urand(13000, 18000), 0, PHASE_TWO); + break; + case EVENT_SPAWN_SPIDER: + if (Unit* target = SelectTarget(SELECT_TARGET_RANDOM, 0)) + { + Creature* Spider = me->SummonCreature(15041, target->GetPositionX(), target->GetPositionY(), target->GetPositionZ(), 0, TEMPSUMMON_TIMED_DESPAWN_OUT_OF_COMBAT, 15000); + if (Spider) + Spider->AI()->AttackStart(target); + } + events.ScheduleEvent(EVENT_SPAWN_SPIDER, urand(12000, 17000)); + break; + case EVENT_TRANSFORM: + { + Talk(SAY_TRANSFORM); + DoCast(me, SPELL_SPIDER_FORM); + const CreatureTemplate* cinfo = me->GetCreatureTemplate(); + me->SetBaseWeaponDamage(BASE_ATTACK, MINDAMAGE, (cinfo->mindmg +((cinfo->mindmg/100) * 35))); + me->SetBaseWeaponDamage(BASE_ATTACK, MAXDAMAGE, (cinfo->maxdmg +((cinfo->maxdmg/100) * 35))); + me->UpdateDamagePhysical(BASE_ATTACK); + DoCast(me->getVictim(), SPELL_ENVOLWINGWEB); + if (DoGetThreat(me->getVictim())) + DoModifyThreatPercent(me->getVictim(), -100); + events.ScheduleEvent(EVENT_CHARGE_PLAYER, 1500, 0, PHASE_THREE); + events.ScheduleEvent(EVENT_TRANSFORM_BACK, 25000, 0, PHASE_THREE); + events.SetPhase(PHASE_THREE); + break; + } + case EVENT_CHARGE_PLAYER: + { + Unit* target = NULL; + int i = 0; + while (i < 3) // max 3 tries to get a random target with power_mana + { + ++i; + Unit* target = SelectTarget(SELECT_TARGET_RANDOM, 1, 100, true); // not aggro leader + if (target && target->getPowerType() == POWER_MANA) i = 3; + } + if (target) + { + DoCast(target, SPELL_CHARGE); + //me->SetPosition(target->GetPositionX(), target->GetPositionY(), target->GetPositionZ(), 0); + //me->SendMonsterMove(target->GetPositionX(), target->GetPositionY(), target->GetPositionZ(), 0, true, 1); + AttackStart(target); + } + events.ScheduleEvent(EVENT_CHARGE_PLAYER, 8000, 0, PHASE_THREE); + break; } - if (target) + case EVENT_TRANSFORM_BACK: { - DoCast(target, SPELL_CHARGE); - //me->SetPosition(target->GetPositionX(), target->GetPositionY(), target->GetPositionZ(), 0); - //me->SendMonsterMove(target->GetPositionX(), target->GetPositionY(), target->GetPositionZ(), 0, true, 1); - AttackStart(target); + me->SetDisplayId(MODEL_MARLI); + const CreatureTemplate* cinfo = me->GetCreatureTemplate(); + me->SetBaseWeaponDamage(BASE_ATTACK, MINDAMAGE, (cinfo->mindmg +((cinfo->mindmg/100) * 1))); + me->SetBaseWeaponDamage(BASE_ATTACK, MAXDAMAGE, (cinfo->maxdmg +((cinfo->maxdmg/100) * 1))); + me->UpdateDamagePhysical(BASE_ATTACK); + events.ScheduleEvent(EVENT_ASPECT_OF_MARLI, 12000, 0, PHASE_TWO); + events.ScheduleEvent(EVENT_TRANSFORM, 45000, 0, PHASE_TWO); + events.ScheduleEvent(EVENT_POISON_VOLLEY, 15000); + events.ScheduleEvent(EVENT_SPAWN_SPIDER, 30000); + events.ScheduleEvent(EVENT_TRANSFORM, urand(35000, 60000), 0, PHASE_TWO); + events.SetPhase(PHASE_TWO); + break; } - - Charge_Timer = 8000; - } else Charge_Timer -= diff; - - if (TransformBack_Timer <= diff) - { - me->SetDisplayId(15220); - const CreatureTemplate* cinfo = me->GetCreatureTemplate(); - me->SetBaseWeaponDamage(BASE_ATTACK, MINDAMAGE, (cinfo->mindmg +((cinfo->mindmg/100) * 1))); - me->SetBaseWeaponDamage(BASE_ATTACK, MAXDAMAGE, (cinfo->maxdmg +((cinfo->maxdmg/100) * 1))); - me->UpdateDamagePhysical(BASE_ATTACK); - - PhaseTwo = false; - TransformBack_Timer = urand(25000, 40000); - } else TransformBack_Timer -= diff; - + default: + break; } - - DoMeleeAttackIfReady(); } + + DoMeleeAttackIfReady(); } }; @@ -222,15 +219,10 @@ class boss_marli : public CreatureScript } }; -//Spawn of Marli +// Spawn of Marli class mob_spawn_of_marli : public CreatureScript { - public: - - mob_spawn_of_marli() - : CreatureScript("mob_spawn_of_marli") - { - } + public: mob_spawn_of_marli() : CreatureScript("mob_spawn_of_marli") {} struct mob_spawn_of_marliAI : public ScriptedAI { @@ -247,7 +239,7 @@ class mob_spawn_of_marli : public CreatureScript { } - void UpdateAI (const uint32 diff) + void UpdateAI(uint32 diff) { //Return since we have no target if (!UpdateVictim()) @@ -275,4 +267,3 @@ void AddSC_boss_marli() new boss_marli(); new mob_spawn_of_marli(); } - diff --git a/src/server/scripts/EasternKingdoms/ZulGurub/boss_renataki.cpp b/src/server/scripts/EasternKingdoms/ZulGurub/boss_renataki.cpp index d562b7cdf9b..7e8c7dca7b4 100644 --- a/src/server/scripts/EasternKingdoms/ZulGurub/boss_renataki.cpp +++ b/src/server/scripts/EasternKingdoms/ZulGurub/boss_renataki.cpp @@ -40,16 +40,11 @@ enum Misc class boss_renataki : public CreatureScript { - public: + public: boss_renataki() : CreatureScript("boss_renataki") {} - boss_renataki() - : CreatureScript("boss_renataki") + struct boss_renatakiAI : public BossAI { - } - - struct boss_renatakiAI : public ScriptedAI - { - boss_renatakiAI(Creature* creature) : ScriptedAI(creature) {} + boss_renatakiAI(Creature* creature) : BossAI(creature, DATA_EDGE_OF_MADNESS) {} uint32 Invisible_Timer; uint32 Ambush_Timer; @@ -62,6 +57,7 @@ class boss_renataki : public CreatureScript void Reset() { + _Reset(); Invisible_Timer = urand(8000, 18000); Ambush_Timer = 3000; Visible_Timer = 4000; @@ -72,11 +68,17 @@ class boss_renataki : public CreatureScript Ambushed = false; } + void JustDied(Unit* /*killer*/) + { + _JustDied(); + } + void EnterCombat(Unit* /*who*/) { + _EnterCombat(); } - void UpdateAI(const uint32 diff) + void UpdateAI(uint32 diff) { if (!UpdateVictim()) return; diff --git a/src/server/scripts/EasternKingdoms/ZulGurub/boss_thekal.cpp b/src/server/scripts/EasternKingdoms/ZulGurub/boss_thekal.cpp index d91b8f0b483..f115daf0fb0 100644 --- a/src/server/scripts/EasternKingdoms/ZulGurub/boss_thekal.cpp +++ b/src/server/scripts/EasternKingdoms/ZulGurub/boss_thekal.cpp @@ -27,28 +27,29 @@ EndScriptData */ #include "ScriptedCreature.h" #include "zulgurub.h" -enum Thekal +enum Says { SAY_AGGRO = 0, - SAY_DEATH = 1, - - SPELL_MORTALCLEAVE = 22859, - SPELL_SILENCE = 22666, - SPELL_FRENZY = 8269, - SPELL_FORCEPUNCH = 24189, - SPELL_CHARGE = 24193, - SPELL_ENRAGE = 8269, - SPELL_SUMMONTIGERS = 24183, - SPELL_TIGER_FORM = 24169, - SPELL_RESURRECT = 24173, //We will not use this spell. - -//Zealot Lor'Khan Spells + SAY_DEATH = 1 +}; + +enum Spells +{ + SPELL_MORTALCLEAVE = 22859, // Phase 1 + SPELL_SILENCE = 22666, // Phase 1 + SPELL_TIGER_FORM = 24169, // Phase 1 + SPELL_RESURRECT = 24173, // Phase 1 // Not used in script. + SPELL_FRENZY = 8269, // Phase 2 + SPELL_FORCEPUNCH = 24189, // Phase 2 + SPELL_CHARGE = 24193, // Phase 2 + SPELL_ENRAGE = 8269, // Phase 2 + SPELL_SUMMONTIGERS = 24183, // Phase 2 + // Zealot Lor'Khan Spells SPELL_SHIELD = 20545, SPELL_BLOODLUST = 24185, SPELL_GREATERHEAL = 24208, SPELL_DISARM = 6713, - -//Zealot Zath Spells + // Zealot Zath Spells SPELL_SWEEPINGSTRIKES = 18765, SPELL_SINISTERSTRIKE = 15581, SPELL_GOUGE = 12540, @@ -56,128 +57,182 @@ enum Thekal SPELL_BLIND = 21060 }; -class boss_thekal : public CreatureScript +enum Events { - public: + EVENT_MORTALCLEAVE = 0, // Phase 1 + EVENT_SILENCE = 1, // Phase 1 + EVENT_CHECK_TIMER = 2, // Phase 1 + EVENT_RESURRECT_TIMER = 3, // Phase 1 + EVENT_FRENZY = 4, // Phase 2 + EVENT_FORCEPUNCH = 5, // Phase 2 + EVENT_SPELL_CHARGE = 6, // Phase 2 + EVENT_ENRAGE = 7, // Phase 2 + EVENT_SUMMONTIGERS = 8 // Phase 2 +}; - boss_thekal() - : CreatureScript("boss_thekal") - { - } +enum Phases +{ + PHASE_ONE = 1, + PHASE_TWO = 2 +}; - struct boss_thekalAI : public ScriptedAI - { - boss_thekalAI(Creature* creature) : ScriptedAI(creature) - { - instance = creature->GetInstanceScript(); - } +class boss_thekal : public CreatureScript +{ + public: boss_thekal() : CreatureScript("boss_thekal") {} - uint32 MortalCleave_Timer; - uint32 Silence_Timer; - uint32 Frenzy_Timer; - uint32 ForcePunch_Timer; - uint32 Charge_Timer; - uint32 Enrage_Timer; - uint32 SummonTigers_Timer; - uint32 Check_Timer; - uint32 Resurrect_Timer; + struct boss_thekalAI : public BossAI + { + boss_thekalAI(Creature* creature) : BossAI(creature, DATA_THEKAL) {} - InstanceScript* instance; bool Enraged; - bool PhaseTwo; bool WasDead; void Reset() { - MortalCleave_Timer = 4000; - Silence_Timer = 9000; - Frenzy_Timer = 30000; - ForcePunch_Timer = 4000; - Charge_Timer = 12000; - Enrage_Timer = 32000; - SummonTigers_Timer = 25000; - Check_Timer = 10000; - Resurrect_Timer = 10000; - + _Reset(); Enraged = false; - PhaseTwo = false; WasDead = false; } - void EnterCombat(Unit* /*who*/) + void JustDied(Unit* /*killer*/) { - Talk(SAY_AGGRO); + _JustDied(); + Talk(SAY_DEATH); } - void JustDied(Unit* /*killer*/) + void EnterCombat(Unit* /*who*/) { - Talk(SAY_DEATH); - if (instance) - instance->SetData(DATA_THEKAL, DONE); + _EnterCombat(); + events.ScheduleEvent(EVENT_MORTALCLEAVE, 4000, 0, PHASE_ONE); // Phase 1 + events.ScheduleEvent(EVENT_SILENCE, 9000, 0, PHASE_ONE); // Phase 1 + events.ScheduleEvent(EVENT_CHECK_TIMER, 10000, 0, PHASE_ONE); // Phase 1 + events.ScheduleEvent(EVENT_RESURRECT_TIMER, 10000, 0, PHASE_ONE); // Phase 1 + Talk(SAY_AGGRO); } void JustReachedHome() { if (instance) - instance->SetData(DATA_THEKAL, NOT_STARTED); + instance->SetBossState(DATA_THEKAL, NOT_STARTED); } - void UpdateAI(const uint32 diff) + void UpdateAI(uint32 diff) { if (!UpdateVictim()) return; - //Check_Timer for the death of LorKhan and Zath. - if (!WasDead && Check_Timer <= diff) + events.Update(diff); + + if (me->HasUnitState(UNIT_STATE_CASTING)) + return; + + while (uint32 eventId = events.ExecuteEvent()) + { + switch (eventId) { - if (instance) - { - if (instance->GetData(DATA_LORKHAN) == SPECIAL) + case EVENT_MORTALCLEAVE: + DoCastVictim(SPELL_MORTALCLEAVE, true); + events.ScheduleEvent(EVENT_MORTALCLEAVE, urand(15000, 20000), 0, PHASE_ONE); + break; + case EVENT_SILENCE: + DoCastVictim(SPELL_SILENCE, true); + events.ScheduleEvent(EVENT_SILENCE, urand(20000, 25000), 0, PHASE_ONE); + break; + case EVENT_RESURRECT_TIMER: + //Thekal will transform to Tiger if he died and was not resurrected after 10 seconds. + if (WasDead) { - //Resurrect LorKhan - if (Unit* pLorKhan = Unit::GetUnit(*me, instance->GetData64(DATA_LORKHAN))) - { - pLorKhan->SetUInt32Value(UNIT_FIELD_BYTES_1, 0); - pLorKhan->setFaction(14); - pLorKhan->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE); - pLorKhan->SetFullHealth(); - - instance->SetData(DATA_LORKHAN, DONE); - } + DoCast(me, SPELL_TIGER_FORM); + me->SetObjectScale(2.00f); + me->SetStandState(UNIT_STAND_STATE_STAND); + me->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE); + me->SetFullHealth(); + const CreatureTemplate* cinfo = me->GetCreatureTemplate(); + me->SetBaseWeaponDamage(BASE_ATTACK, MINDAMAGE, (cinfo->mindmg +((cinfo->mindmg/100) * 40))); + me->SetBaseWeaponDamage(BASE_ATTACK, MAXDAMAGE, (cinfo->maxdmg +((cinfo->maxdmg/100) * 40))); + me->UpdateDamagePhysical(BASE_ATTACK); + DoResetThreat(); + events.ScheduleEvent(EVENT_FRENZY, 30000, 0, PHASE_TWO); // Phase 2 + events.ScheduleEvent(EVENT_FORCEPUNCH, 4000, 0, PHASE_TWO); // Phase 2 + events.ScheduleEvent(EVENT_SPELL_CHARGE, 12000, 0, PHASE_TWO); // Phase 2 + events.ScheduleEvent(EVENT_ENRAGE, 32000, 0, PHASE_TWO); // Phase 2 + events.ScheduleEvent(EVENT_SUMMONTIGERS, 25000, 0, PHASE_TWO); // Phase 2 + events.SetPhase(PHASE_TWO); } - - if (instance->GetData(DATA_ZATH) == SPECIAL) + events.ScheduleEvent(EVENT_RESURRECT_TIMER, 10000, 0, PHASE_ONE); + break; + case EVENT_CHECK_TIMER: + //Check_Timer for the death of LorKhan and Zath. + if (!WasDead) { - //Resurrect Zath - Unit* pZath = Unit::GetUnit(*me, instance->GetData64(DATA_ZATH)); - if (pZath) + if (instance) { - pZath->SetUInt32Value(UNIT_FIELD_BYTES_1, 0); - pZath->setFaction(14); - pZath->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE); - pZath->SetFullHealth(); - - instance->SetData(DATA_ZATH, DONE); + if (instance->GetBossState(DATA_LORKHAN) == SPECIAL) + { + //Resurrect LorKhan + if (Unit* pLorKhan = Unit::GetUnit(*me, instance->GetData64(DATA_LORKHAN))) + { + pLorKhan->SetUInt32Value(UNIT_FIELD_BYTES_1, 0); + pLorKhan->setFaction(14); + pLorKhan->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE); + pLorKhan->SetFullHealth(); + instance->SetData(DATA_LORKHAN, DONE); + } + } + + if (instance->GetBossState(DATA_ZATH) == SPECIAL) + { + //Resurrect Zath + if (Unit* pZath = Unit::GetUnit(*me, instance->GetData64(DATA_ZATH))) + { + pZath->SetUInt32Value(UNIT_FIELD_BYTES_1, 0); + pZath->setFaction(14); + pZath->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE); + pZath->SetFullHealth(); + instance->SetBossState(DATA_ZATH, DONE); + } + } } } - } - - Check_Timer = 5000; - } else Check_Timer -= diff; - - if (!PhaseTwo && MortalCleave_Timer <= diff) - { - DoCast(me->getVictim(), SPELL_MORTALCLEAVE); - MortalCleave_Timer = urand(15000, 20000); - } else MortalCleave_Timer -= diff; + events.ScheduleEvent(EVENT_CHECK_TIMER, 5000, 0, PHASE_ONE); + break; + case EVENT_FRENZY: + DoCast(me, SPELL_FRENZY); + events.ScheduleEvent(EVENT_FRENZY, 30000, 0, PHASE_TWO); + break; + case EVENT_FORCEPUNCH: + DoCastVictim(SPELL_FORCEPUNCH, true); + events.ScheduleEvent(EVENT_FORCEPUNCH, urand(16000, 21000), 0, PHASE_TWO); + break; + case EVENT_CHARGE: + if (Unit* target = SelectTarget(SELECT_TARGET_RANDOM, 0)) + { + DoCast(target, SPELL_CHARGE); + DoResetThreat(); + AttackStart(target); + } + events.ScheduleEvent(EVENT_CHARGE, urand(15000, 22000), 0, PHASE_TWO); + break; + case EVENT_ENRAGE: + if (HealthBelowPct(11) && !Enraged) + { + DoCast(me, SPELL_ENRAGE); + Enraged = true; + } + events.ScheduleEvent(EVENT_ENRAGE, 30000); + break; + case EVENT_SUMMONTIGERS: + DoCastVictim(SPELL_SUMMONTIGERS, true); + events.ScheduleEvent(EVENT_SUMMONTIGERS, urand(10000, 14000), 0, PHASE_TWO); + break; + default: + break; + } - if (!PhaseTwo && Silence_Timer <= diff) - { - DoCast(me->getVictim(), SPELL_SILENCE); - Silence_Timer = urand(20000, 25000); - } else Silence_Timer -= diff; + if (me->IsFullHealth() && WasDead) + WasDead = false; - if (!PhaseTwo && !WasDead && !HealthAbovePct(5)) + if ((events.IsInPhase(PHASE_ONE)) && !WasDead && !HealthAbovePct(5)) { me->RemoveAurasByType(SPELL_AURA_PERIODIC_DAMAGE_PERCENT); me->RemoveAurasByType(SPELL_AURA_PERIODIC_DAMAGE); @@ -185,78 +240,12 @@ class boss_thekal : public CreatureScript me->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE); me->SetStandState(UNIT_STAND_STATE_SLEEP); me->AttackStop(); - if (instance) - instance->SetData(DATA_THEKAL, SPECIAL); - + instance->SetBossState(DATA_THEKAL, SPECIAL); WasDead=true; } - - //Thekal will transform to Tiger if he died and was not resurrected after 10 seconds. - if (!PhaseTwo && WasDead) - { - if (Resurrect_Timer <= diff) - { - DoCast(me, SPELL_TIGER_FORM); - me->SetObjectScale(2.00f); - me->SetStandState(UNIT_STAND_STATE_STAND); - me->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE); - me->SetFullHealth(); - const CreatureTemplate* cinfo = me->GetCreatureTemplate(); - me->SetBaseWeaponDamage(BASE_ATTACK, MINDAMAGE, (cinfo->mindmg +((cinfo->mindmg/100) * 40))); - me->SetBaseWeaponDamage(BASE_ATTACK, MAXDAMAGE, (cinfo->maxdmg +((cinfo->maxdmg/100) * 40))); - me->UpdateDamagePhysical(BASE_ATTACK); - DoResetThreat(); - PhaseTwo = true; - } else Resurrect_Timer -= diff; - } - - if (me->IsFullHealth() && WasDead) - { - WasDead = false; - } - - if (PhaseTwo) - { - if (Charge_Timer <= diff) - { - if (Unit* target = SelectTarget(SELECT_TARGET_RANDOM, 0)) - { - DoCast(target, SPELL_CHARGE); - DoResetThreat(); - AttackStart(target); - } - - Charge_Timer = urand(15000, 22000); - } else Charge_Timer -= diff; - - if (Frenzy_Timer <= diff) - { - DoCast(me, SPELL_FRENZY); - Frenzy_Timer = 30000; - } else Frenzy_Timer -= diff; - - if (ForcePunch_Timer <= diff) - { - DoCast(me->getVictim(), SPELL_SILENCE); - ForcePunch_Timer = urand(16000, 21000); - } else ForcePunch_Timer -= diff; - - if (SummonTigers_Timer <= diff) - { - DoCast(me->getVictim(), SPELL_SUMMONTIGERS); - SummonTigers_Timer = urand(10000, 14000); - } else SummonTigers_Timer -= diff; - - if (HealthBelowPct(11) && !Enraged) - { - DoCast(me, SPELL_ENRAGE); - Enraged = true; - } - } - - DoMeleeAttackIfReady(); - + } + DoMeleeAttackIfReady(); } }; @@ -269,12 +258,7 @@ class boss_thekal : public CreatureScript //Zealot Lor'Khan class mob_zealot_lorkhan : public CreatureScript { - public: - - mob_zealot_lorkhan() - : CreatureScript("mob_zealot_lorkhan") - { - } + public: mob_zealot_lorkhan() : CreatureScript("mob_zealot_lorkhan") {} struct mob_zealot_lorkhanAI : public ScriptedAI { @@ -304,7 +288,7 @@ class mob_zealot_lorkhan : public CreatureScript FakeDeath = false; if (instance) - instance->SetData(DATA_LORKHAN, NOT_STARTED); + instance->SetBossState(DATA_LORKHAN, NOT_STARTED); me->SetUInt32Value(UNIT_FIELD_BYTES_1, 0); me->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE); @@ -314,7 +298,7 @@ class mob_zealot_lorkhan : public CreatureScript { } - void UpdateAI (const uint32 diff) + void UpdateAI(uint32 diff) { if (!UpdateVictim()) return; @@ -372,7 +356,7 @@ class mob_zealot_lorkhan : public CreatureScript { if (instance) { - if (instance->GetData(DATA_THEKAL) == SPECIAL) + if (instance->GetBossState(DATA_THEKAL) == SPECIAL) { //Resurrect Thekal if (Unit* pThekal = Unit::GetUnit(*me, instance->GetData64(DATA_THEKAL))) @@ -384,7 +368,7 @@ class mob_zealot_lorkhan : public CreatureScript } } - if (instance->GetData(DATA_ZATH) == SPECIAL) + if (instance->GetBossState(DATA_ZATH) == SPECIAL) { //Resurrect Zath if (Unit* pZath = Unit::GetUnit(*me, instance->GetData64(DATA_ZATH))) @@ -411,7 +395,7 @@ class mob_zealot_lorkhan : public CreatureScript me->AttackStop(); if (instance) - instance->SetData(DATA_LORKHAN, SPECIAL); + instance->SetBossState(DATA_LORKHAN, SPECIAL); FakeDeath = true; } @@ -466,7 +450,7 @@ class mob_zealot_zath : public CreatureScript FakeDeath = false; if (instance) - instance->SetData(DATA_ZATH, NOT_STARTED); + instance->SetBossState(DATA_ZATH, NOT_STARTED); me->SetStandState(UNIT_STAND_STATE_STAND); me->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE); @@ -476,7 +460,7 @@ class mob_zealot_zath : public CreatureScript { } - void UpdateAI (const uint32 diff) + void UpdateAI(uint32 diff) { if (!UpdateVictim()) return; @@ -525,7 +509,7 @@ class mob_zealot_zath : public CreatureScript { if (instance) { - if (instance->GetData(DATA_LORKHAN) == SPECIAL) + if (instance->GetBossState(DATA_LORKHAN) == SPECIAL) { //Resurrect LorKhan if (Unit* pLorKhan = Unit::GetUnit(*me, instance->GetData64(DATA_LORKHAN))) @@ -537,7 +521,7 @@ class mob_zealot_zath : public CreatureScript } } - if (instance->GetData(DATA_THEKAL) == SPECIAL) + if (instance->GetBossState(DATA_THEKAL) == SPECIAL) { //Resurrect Thekal if (Unit* pThekal = Unit::GetUnit(*me, instance->GetData64(DATA_THEKAL))) @@ -564,7 +548,7 @@ class mob_zealot_zath : public CreatureScript me->AttackStop(); if (instance) - instance->SetData(DATA_ZATH, SPECIAL); + instance->SetBossState(DATA_ZATH, SPECIAL); FakeDeath = true; } @@ -585,4 +569,3 @@ void AddSC_boss_thekal() new mob_zealot_lorkhan(); new mob_zealot_zath(); } - diff --git a/src/server/scripts/EasternKingdoms/ZulGurub/boss_venoxis.cpp b/src/server/scripts/EasternKingdoms/ZulGurub/boss_venoxis.cpp index ff63e4a8adb..884e5bfad10 100644 --- a/src/server/scripts/EasternKingdoms/ZulGurub/boss_venoxis.cpp +++ b/src/server/scripts/EasternKingdoms/ZulGurub/boss_venoxis.cpp @@ -23,14 +23,14 @@ #include "zulgurub.h" /* - * TODO: + * @todo * - Fix timers (research some more) */ -enum Texts +enum Says { SAY_VENOXIS_TRANSFORM = 1, // Let the coils of hate unfurl! - SAY_VENOXIS_DEATH = 2, // Ssserenity.. at lassst! + SAY_VENOXIS_DEATH = 2 // Ssserenity.. at lassst! }; enum Spells @@ -42,7 +42,6 @@ enum Spells SPELL_HOLY_NOVA = 23858, SPELL_HOLY_FIRE = 23860, SPELL_HOLY_WRATH = 23979, - // snake form SPELL_POISON_CLOUD = 23861, SPELL_VENOM_SPIT = 23862, @@ -50,15 +49,9 @@ enum Spells SPELL_PARASITIC_SERPENT = 23865, SPELL_SUMMON_PARASITIC_SERPENT = 23866, SPELL_PARASITIC_SERPENT_TRIGGER = 23867, - // used when swapping event-stages SPELL_VENOXIS_TRANSFORM = 23849, // 50% health - shapechange to cobra - SPELL_FRENZY = 8269, // 20% health - frenzy -}; - -enum NPCs -{ - NPC_PARASITIC_SERPENT = 14884, + SPELL_FRENZY = 8269 // 20% health - frenzy }; enum Events @@ -70,10 +63,8 @@ enum Events EVENT_HOLY_NOVA = 4, EVENT_HOLY_FIRE = 5, EVENT_HOLY_WRATH = 6, - // phase-changing EVENT_TRANSFORM = 7, - // snake form events EVENT_POISON_CLOUD = 8, EVENT_VENOM_SPIT = 9, @@ -84,49 +75,48 @@ enum Events enum Phases { PHASE_ONE = 1, // troll form - PHASE_TWO = 2, // snake form + PHASE_TWO = 2 // snake form +}; + +enum NPCs +{ + NPC_PARASITIC_SERPENT = 14884 }; class boss_venoxis : public CreatureScript { - public: - boss_venoxis() : CreatureScript("boss_venoxis") {} + public: boss_venoxis() : CreatureScript("boss_venoxis") {} struct boss_venoxisAI : public BossAI { - boss_venoxisAI(Creature* creature) : BossAI(creature, DATA_VENOXIS) - { - } + boss_venoxisAI(Creature* creature) : BossAI(creature, DATA_VENOXIS) {} void Reset() { - events.Reset(); - summons.DespawnAll(); - - // make sure this boss is properly reset - instance->SetBossState(DATA_VENOXIS, NOT_STARTED); - + _Reset(); // remove all spells and auras from previous attempts me->RemoveAllAuras(); me->SetReactState(REACT_PASSIVE); - // set some internally used variables to their defaults _inMeleeRange = 0; _transformed = false; _frenzied = false; - events.SetPhase(PHASE_ONE); } + void JustDied(Unit* /*killer*/) + { + _JustDied(); + Talk(SAY_VENOXIS_DEATH); + me->RemoveAllAuras(); + } + void EnterCombat(Unit* /*who*/) { + _EnterCombat(); me->SetReactState(REACT_AGGRESSIVE); - - instance->SetBossState(DATA_VENOXIS, IN_PROGRESS); - // Always running events events.ScheduleEvent(EVENT_THRASH, 5000); - // Phase one events (regular form) events.ScheduleEvent(EVENT_HOLY_NOVA, 5000, 0, PHASE_ONE); events.ScheduleEvent(EVENT_DISPEL_MAGIC, 35000, 0, PHASE_ONE); @@ -157,15 +147,7 @@ class boss_venoxis : public CreatureScript } } - void JustDied(Unit* /*killer*/) - { - Talk(SAY_VENOXIS_DEATH); - // venoxis is dead, mark him as such for the instance - instance->SetBossState(DATA_VENOXIS, DONE); - me->RemoveAllAuras(); - } - - void UpdateAI(const uint32 diff) + void UpdateAI(uint32 diff) { if (!UpdateVictim()) return; diff --git a/src/server/scripts/EasternKingdoms/ZulGurub/boss_wushoolay.cpp b/src/server/scripts/EasternKingdoms/ZulGurub/boss_wushoolay.cpp index 810ee5e900e..945303f3d10 100644 --- a/src/server/scripts/EasternKingdoms/ZulGurub/boss_wushoolay.cpp +++ b/src/server/scripts/EasternKingdoms/ZulGurub/boss_wushoolay.cpp @@ -33,53 +33,63 @@ enum Spells SPELL_LIGHTNINGWAVE = 24819 }; -class boss_wushoolay : public CreatureScript +enum Events { - public: + EVENT_LIGHTNINGCLOUD = 0, + EVENT_LIGHTNINGWAVE = 1 +}; - boss_wushoolay() - : CreatureScript("boss_wushoolay") - { - } +class boss_wushoolay : public CreatureScript +{ + public: boss_wushoolay() : CreatureScript("boss_wushoolay") {} - struct boss_wushoolayAI : public ScriptedAI + struct boss_wushoolayAI : public BossAI { - boss_wushoolayAI(Creature* creature) : ScriptedAI(creature) {} - - uint32 LightningCloud_Timer; - uint32 LightningWave_Timer; + boss_wushoolayAI(Creature* creature) : BossAI(creature, DATA_EDGE_OF_MADNESS) {} void Reset() { - LightningCloud_Timer = urand(5000, 10000); - LightningWave_Timer = urand(8000, 16000); + _Reset(); + } + + void JustDied(Unit* /*killer*/) + { + _JustDied(); } void EnterCombat(Unit* /*who*/) { + _EnterCombat(); + events.ScheduleEvent(EVENT_LIGHTNINGCLOUD, urand(5000, 10000)); + events.ScheduleEvent(EVENT_LIGHTNINGWAVE, urand(8000, 16000)); } - void UpdateAI(const uint32 diff) + void UpdateAI(uint32 diff) { if (!UpdateVictim()) return; - //LightningCloud_Timer - if (LightningCloud_Timer <= diff) - { - DoCast(me->getVictim(), SPELL_LIGHTNINGCLOUD); - LightningCloud_Timer = urand(15000, 20000); - } else LightningCloud_Timer -= diff; + events.Update(diff); - //LightningWave_Timer - if (LightningWave_Timer <= diff) - { - Unit* target = NULL; - target = SelectTarget(SELECT_TARGET_RANDOM, 0); - if (target) DoCast(target, SPELL_LIGHTNINGWAVE); + if (me->HasUnitState(UNIT_STATE_CASTING)) + return; - LightningWave_Timer = urand(12000, 16000); - } else LightningWave_Timer -= diff; + while (uint32 eventId = events.ExecuteEvent()) + { + switch (eventId) + { + case EVENT_LIGHTNINGCLOUD: + DoCastVictim(SPELL_LIGHTNINGCLOUD, true); + events.ScheduleEvent(EVENT_LIGHTNINGCLOUD, urand(15000, 20000)); + break; + case EVENT_LIGHTNINGWAVE: + DoCast(SelectTarget(SELECT_TARGET_RANDOM, 0, 100, true), SPELL_LIGHTNINGWAVE); + events.ScheduleEvent(EVENT_LIGHTNINGWAVE, urand(12000, 16000)); + break; + default: + break; + } + } DoMeleeAttackIfReady(); } diff --git a/src/server/scripts/EasternKingdoms/ZulGurub/instance_zulgurub.cpp b/src/server/scripts/EasternKingdoms/ZulGurub/instance_zulgurub.cpp index cfaf19642f2..01c5ef998f5 100644 --- a/src/server/scripts/EasternKingdoms/ZulGurub/instance_zulgurub.cpp +++ b/src/server/scripts/EasternKingdoms/ZulGurub/instance_zulgurub.cpp @@ -29,38 +29,30 @@ EndScriptData */ class instance_zulgurub : public InstanceMapScript { - public: - instance_zulgurub() - : InstanceMapScript("instance_zulgurub", 309) - { - } + public: instance_zulgurub(): InstanceMapScript(ZGScriptName, 309) {} struct instance_zulgurub_InstanceMapScript : public InstanceScript { - instance_zulgurub_InstanceMapScript(Map* map) : InstanceScript(map) {} - - //If all High Priest bosses were killed. Lorkhan, Zath and Ohgan are added too. - uint32 m_auiEncounter[MAX_ENCOUNTERS]; - - //Storing Lorkhan, Zath and Thekal because we need to cast on them later. Jindo is needed for healfunction too. - uint64 m_uiLorKhanGUID; - uint64 m_uiZathGUID; - uint64 m_uiThekalGUID; - uint64 m_uiJindoGUID; + instance_zulgurub_InstanceMapScript(Map* map) : InstanceScript(map) + { + SetBossNumber(EncounterCount); + } void Initialize() { - memset(&m_auiEncounter, 0, sizeof(m_auiEncounter)); - - m_uiLorKhanGUID = 0; - m_uiZathGUID = 0; - m_uiThekalGUID = 0; - m_uiJindoGUID = 0; + _zealotLorkhanGUID = 0; + _zealotZathGUID = 0; + _highPriestTekalGUID = 0; + _jindoTheHexxerGUID = 0; + _vilebranchSpeakerGUID = 0; + _arlokkGUID = 0; + _goForcefieldGUID = 0; + _goGongOfBethekkGUID = 0; } bool IsEncounterInProgress() const { - //not active in Zul'Gurub + // not active in Zul'Gurub return false; } @@ -68,73 +60,44 @@ class instance_zulgurub : public InstanceMapScript { switch (creature->GetEntry()) { - case 11347: m_uiLorKhanGUID = creature->GetGUID(); break; - case 11348: m_uiZathGUID = creature->GetGUID(); break; - case 14509: m_uiThekalGUID = creature->GetGUID(); break; - case 11380: m_uiJindoGUID = creature->GetGUID(); break; - } - } - - void SetData(uint32 uiType, uint32 uiData) - { - switch (uiType) - { - case DATA_ARLOKK: - m_auiEncounter[0] = uiData; - break; - - case DATA_JEKLIK: - m_auiEncounter[1] = uiData; + case NPC_ZEALOT_LORKHAN: + _zealotLorkhanGUID = creature->GetGUID(); break; - - case DATA_VENOXIS: - m_auiEncounter[2] = uiData; + case NPC_ZEALOT_ZATH: + _zealotZathGUID = creature->GetGUID(); break; - - case DATA_MARLI: - m_auiEncounter[3] = uiData; + case NPC_HIGH_PRIEST_THEKAL: + _highPriestTekalGUID = creature->GetGUID(); break; - - case DATA_THEKAL: - m_auiEncounter[4] = uiData; + case NPC_JINDO_THE_HEXXER: + _jindoTheHexxerGUID = creature->GetGUID(); break; - - case DATA_LORKHAN: - m_auiEncounter[5] = uiData; + case NPC_VILEBRANCH_SPEAKER: + _vilebranchSpeakerGUID = creature->GetGUID(); break; - - case DATA_ZATH: - m_auiEncounter[6] = uiData; - break; - - case DATA_OHGAN: - m_auiEncounter[7] = uiData; + case NPC_ARLOKK: + _arlokkGUID = creature->GetGUID(); break; } } - uint32 GetData(uint32 uiType) const + void OnGameObjectCreate(GameObject* go) { - switch (uiType) + switch (go->GetEntry()) { - case DATA_ARLOKK: - return m_auiEncounter[0]; - case DATA_JEKLIK: - return m_auiEncounter[1]; - case DATA_VENOXIS: - return m_auiEncounter[2]; - case DATA_MARLI: - return m_auiEncounter[3]; - case DATA_THEKAL: - return m_auiEncounter[4]; - case DATA_LORKHAN: - return m_auiEncounter[5]; - case DATA_ZATH: - return m_auiEncounter[6]; - case DATA_OHGAN: - return m_auiEncounter[7]; + case GO_FORCEFIELD: + _goForcefieldGUID = go->GetGUID(); + break; + case GO_GONG_OF_BETHEKK: + _goGongOfBethekkGUID = go->GetGUID(); + if (GetBossState(DATA_ARLOKK) == DONE) + go->SetFlag(GAMEOBJECT_FLAGS, GO_FLAG_NOT_SELECTABLE); + else + go->RemoveFlag(GAMEOBJECT_FLAGS, GO_FLAG_NOT_SELECTABLE); + break; + default: + break; } - return 0; } uint64 GetData64(uint32 uiData) const @@ -142,16 +105,84 @@ class instance_zulgurub : public InstanceMapScript switch (uiData) { case DATA_LORKHAN: - return m_uiLorKhanGUID; + return _zealotLorkhanGUID; + break; case DATA_ZATH: - return m_uiZathGUID; + return _zealotZathGUID; + break; case DATA_THEKAL: - return m_uiThekalGUID; + return _highPriestTekalGUID; + break; case DATA_JINDO: - return m_uiJindoGUID; + return _jindoTheHexxerGUID; + break; + case NPC_ARLOKK: + return _arlokkGUID; + break; + case GO_FORCEFIELD: + return _goForcefieldGUID; + break; + case GO_GONG_OF_BETHEKK: + return _goGongOfBethekkGUID; + break; } return 0; } + + std::string GetSaveData() + { + OUT_SAVE_INST_DATA; + + std::ostringstream saveStream; + saveStream << "Z G " << GetBossSaveData(); + + OUT_SAVE_INST_DATA_COMPLETE; + return saveStream.str(); + } + + void Load(const char* str) + { + if (!str) + { + OUT_LOAD_INST_DATA_FAIL; + return; + } + + OUT_LOAD_INST_DATA(str); + + char dataHead1, dataHead2; + + std::istringstream loadStream(str); + loadStream >> dataHead1 >> dataHead2; + + if (dataHead1 == 'Z' && dataHead2 == 'G') + { + for (uint32 i = 0; i < EncounterCount; ++i) + { + uint32 tmpState; + loadStream >> tmpState; + if (tmpState == IN_PROGRESS || tmpState > SPECIAL) + tmpState = NOT_STARTED; + SetBossState(i, EncounterState(tmpState)); + } + } + else + OUT_LOAD_INST_DATA_FAIL; + + OUT_LOAD_INST_DATA_COMPLETE; + } + private: + //If all High Priest bosses were killed. Lorkhan, Zath and Ohgan are added too. + //Storing Lorkhan, Zath and Thekal because we need to cast on them later. Jindo is needed for healfunction too. + + uint64 _zealotLorkhanGUID; + uint64 _zealotZathGUID; + uint64 _highPriestTekalGUID; + uint64 _jindoTheHexxerGUID; + uint64 _vilebranchSpeakerGUID; + uint64 _arlokkGUID; + uint64 _goForcefieldGUID; + uint64 _goGongOfBethekkGUID; }; InstanceScript* GetInstanceScript(InstanceMap* map) const diff --git a/src/server/scripts/EasternKingdoms/ZulGurub/zulgurub.h b/src/server/scripts/EasternKingdoms/ZulGurub/zulgurub.h index 22637315066..77767153a96 100644 --- a/src/server/scripts/EasternKingdoms/ZulGurub/zulgurub.h +++ b/src/server/scripts/EasternKingdoms/ZulGurub/zulgurub.h @@ -1,6 +1,5 @@ /* * Copyright (C) 2008-2013 TrinityCore <http://www.trinitycore.org/> - * Copyright (C) 2006-2009 ScriptDev2 <https://scriptdev2.svn.sourceforge.net/> * * 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 @@ -19,20 +18,61 @@ #ifndef DEF_ZULGURUB_H #define DEF_ZULGURUB_H +uint32 const EncounterCount = 13; + +#define ZGScriptName "instance_zulgurub" + enum DataTypes { - MAX_ENCOUNTERS = 8, - - DATA_ARLOKK = 1, - DATA_JEKLIK = 2, - DATA_VENOXIS = 3, - DATA_MARLI = 4, - DATA_OHGAN = 5, - DATA_THEKAL = 6, - DATA_ZATH = 7, - DATA_LORKHAN = 8, - DATA_JINDO = 10, + DATA_JEKLIK = 0, // Main boss + DATA_VENOXIS = 1, // Main boss + DATA_MARLI = 2, // Main boss + DATA_ARLOKK = 3, // Main boss + DATA_THEKAL = 4, // Main boss + DATA_HAKKAR = 5, // End boss + DATA_MANDOKIR = 6, // Optional boss + DATA_JINDO = 7, // Optional boss + DATA_GAHZRANKA = 8, // Optional boss + DATA_EDGE_OF_MADNESS = 9, // Optional Event Edge of Madness - one of: Gri'lek, Renataki, Hazza'rah, or Wushoolay + DATA_LORKHAN = 10, // Zealot Lor'Khan add to High priest Thekal! + DATA_ZATH = 11, // Zealot Zath add to High priest Thekal! + DATA_OHGAN = 12, // Bloodlord Mandokir's raptor mount + TYPE_EDGE_OF_MADNESS = 13 // Boss storage }; -#endif +enum CreatureIds +{ + NPC_ARLOKK = 14515, // Arlokk Event + NPC_PANTHER_TRIGGER = 15091, // Arlokk Event + NPC_ZULIAN_PROWLER = 15101, // Arlokk Event + NPC_ZEALOT_LORKHAN = 11347, + NPC_ZEALOT_ZATH = 11348, + NPC_HIGH_PRIEST_THEKAL = 14509, + NPC_JINDO_THE_HEXXER = 11380, + NPC_NIGHTMARE_ILLUSION = 15163, + NPC_SHADE_OF_JINDO = 14986, + NPC_SACRIFICED_TROLL = 14826, + NPC_MANDOKIR = 11382, // Mandokir Event + NPC_OHGAN = 14988, // Mandokir Event + NPC_VILEBRANCH_SPEAKER = 11391, // Mandokir Event + NPC_CHAINED_SPIRT = 15117 // Mandokir Event + +}; +enum GameobjectIds +{ + GO_FORCEFIELD = 180497, // Arlokk Event + GO_GONG_OF_BETHEKK = 180526 // Arlokk Event +}; + +template<class AI> +CreatureAI* GetZulGurubAI(Creature* creature) +{ + if (InstanceMap* instance = creature->GetMap()->ToInstanceMap()) + if (instance->GetInstanceScript()) + if (instance->GetScriptId() == sObjectMgr->GetScriptId(ZGScriptName)) + return new AI(creature); + return NULL; +} + +#endif diff --git a/src/server/scripts/EasternKingdoms/boss_kruul.cpp b/src/server/scripts/EasternKingdoms/boss_kruul.cpp index 226ff794a9f..997417714e8 100644 --- a/src/server/scripts/EasternKingdoms/boss_kruul.cpp +++ b/src/server/scripts/EasternKingdoms/boss_kruul.cpp @@ -26,13 +26,16 @@ EndScriptData */ #include "ScriptMgr.h" #include "ScriptedCreature.h" -#define SPELL_SHADOWVOLLEY 21341 -#define SPELL_CLEAVE 20677 -#define SPELL_THUNDERCLAP 23931 -#define SPELL_TWISTEDREFLECTION 21063 -#define SPELL_VOIDBOLT 21066 -#define SPELL_RAGE 21340 -#define SPELL_CAPTURESOUL 21054 +enum Spells +{ + SPELL_SHADOWVOLLEY = 21341, + SPELL_CLEAVE = 20677, + SPELL_THUNDERCLAP = 23931, + SPELL_TWISTEDREFLECTION = 21063, + SPELL_VOIDBOLT = 21066, + SPELL_RAGE = 21340, + SPELL_CAPTURESOUL = 21054 +}; class boss_kruul : public CreatureScript { @@ -83,7 +86,7 @@ public: Hound->AI()->AttackStart(victim); } - void UpdateAI(const uint32 diff) + void UpdateAI(uint32 diff) { //Return since we have no target if (!UpdateVictim()) diff --git a/src/server/scripts/EasternKingdoms/zone_arathi_highlands.cpp b/src/server/scripts/EasternKingdoms/zone_arathi_highlands.cpp index d638a435936..74344f28a9b 100644 --- a/src/server/scripts/EasternKingdoms/zone_arathi_highlands.cpp +++ b/src/server/scripts/EasternKingdoms/zone_arathi_highlands.cpp @@ -115,7 +115,7 @@ class npc_professor_phizzlethorpe : public CreatureScript Talk(SAY_AGGRO); } - void UpdateAI(const uint32 diff) + void UpdateAI(uint32 diff) { npc_escortAI::UpdateAI(diff); } diff --git a/src/server/scripts/EasternKingdoms/zone_duskwood.cpp b/src/server/scripts/EasternKingdoms/zone_duskwood.cpp index 1ce83d31a63..5bfb5edadc1 100644 --- a/src/server/scripts/EasternKingdoms/zone_duskwood.cpp +++ b/src/server/scripts/EasternKingdoms/zone_duskwood.cpp @@ -116,7 +116,7 @@ public: } } - void UpdateAI(const uint32 diff) + void UpdateAI(uint32 diff) { if (!UpdateVictim()) return; diff --git a/src/server/scripts/EasternKingdoms/zone_eversong_woods.cpp b/src/server/scripts/EasternKingdoms/zone_eversong_woods.cpp index 432768a51de..ce62de8b368 100644 --- a/src/server/scripts/EasternKingdoms/zone_eversong_woods.cpp +++ b/src/server/scripts/EasternKingdoms/zone_eversong_woods.cpp @@ -166,7 +166,7 @@ public: void EnterCombat(Unit* /*who*/) {} - void UpdateAI(const uint32 diff) + void UpdateAI(uint32 diff) { if (questPhase == 1) { @@ -315,7 +315,7 @@ public: void EnterCombat(Unit* /*who*/) {} - void UpdateAI(const uint32 diff) + void UpdateAI(uint32 diff) { // Quest accepted but object not activated, object despawned (if in sync 1 minute!) if (questPhase == 1) @@ -496,7 +496,7 @@ public: player->FailQuest(QUEST_UNEXPECTED_RESULT); } - void UpdateAI(const uint32 /*diff*/) + void UpdateAI(uint32 /*diff*/) { if (KillCount >= 3 && PlayerGUID) if (Player* player = Unit::GetPlayer(*me, PlayerGUID)) @@ -551,9 +551,12 @@ public: return new npc_infused_crystalAI (creature); } - struct npc_infused_crystalAI : public Scripted_NoMovementAI + struct npc_infused_crystalAI : public ScriptedAI { - npc_infused_crystalAI(Creature* creature) : Scripted_NoMovementAI(creature) {} + npc_infused_crystalAI(Creature* creature) : ScriptedAI(creature) + { + SetCombatMovement(false); + } uint32 EndTimer; uint32 WaveTimer; @@ -596,7 +599,7 @@ public: CAST_PLR(player)->FailQuest(QUEST_POWERING_OUR_DEFENSES); } - void UpdateAI(const uint32 diff) + void UpdateAI(uint32 diff) { if (EndTimer < diff && Progress) { diff --git a/src/server/scripts/EasternKingdoms/zone_isle_of_queldanas.cpp b/src/server/scripts/EasternKingdoms/zone_isle_of_queldanas.cpp index bfd4d24cec6..45f5e17095f 100644 --- a/src/server/scripts/EasternKingdoms/zone_isle_of_queldanas.cpp +++ b/src/server/scripts/EasternKingdoms/zone_isle_of_queldanas.cpp @@ -71,7 +71,7 @@ public: void MoveInLineOfSight(Unit* /*who*/) {} void EnterCombat(Unit* /*who*/) {} - void UpdateAI(const uint32 diff) + void UpdateAI(uint32 diff) { if (!Credit) { @@ -145,7 +145,7 @@ public: } } - void UpdateAI(const uint32 /*diff*/) + void UpdateAI(uint32 /*diff*/) { DoMeleeAttackIfReady(); } diff --git a/src/server/scripts/EasternKingdoms/zone_redridge_mountains.cpp b/src/server/scripts/EasternKingdoms/zone_redridge_mountains.cpp index 5ff95f83f25..fc5ee94a55f 100644 --- a/src/server/scripts/EasternKingdoms/zone_redridge_mountains.cpp +++ b/src/server/scripts/EasternKingdoms/zone_redridge_mountains.cpp @@ -105,7 +105,7 @@ public: } } - void UpdateAI(const uint32 uiDiff) + void UpdateAI(uint32 uiDiff) { if (HasEscortState(STATE_ESCORT_NONE)) return; diff --git a/src/server/scripts/EasternKingdoms/zone_silvermoon_city.cpp b/src/server/scripts/EasternKingdoms/zone_silvermoon_city.cpp index e750faefbf5..fd36a02b8a5 100644 --- a/src/server/scripts/EasternKingdoms/zone_silvermoon_city.cpp +++ b/src/server/scripts/EasternKingdoms/zone_silvermoon_city.cpp @@ -77,7 +77,7 @@ public: { } - void UpdateAI(const uint32 diff) + void UpdateAI(uint32 diff) { if (me->IsStandState()) { diff --git a/src/server/scripts/EasternKingdoms/zone_silverpine_forest.cpp b/src/server/scripts/EasternKingdoms/zone_silverpine_forest.cpp index 290f7fa6882..80e47dbbf08 100644 --- a/src/server/scripts/EasternKingdoms/zone_silverpine_forest.cpp +++ b/src/server/scripts/EasternKingdoms/zone_silverpine_forest.cpp @@ -253,7 +253,7 @@ public: player->FailQuest(QUEST_PYREWOOD_AMBUSH); } - void UpdateAI(const uint32 diff) + void UpdateAI(uint32 diff) { //sLog->outInfo(LOG_FILTER_TSCR, "DEBUG: p(%i) k(%i) d(%u) W(%i)", Phase, KillCount, diff, WaitTimer); diff --git a/src/server/scripts/EasternKingdoms/zone_stormwind_city.cpp b/src/server/scripts/EasternKingdoms/zone_stormwind_city.cpp index e81567a1a7a..b9c9c8ff15b 100644 --- a/src/server/scripts/EasternKingdoms/zone_stormwind_city.cpp +++ b/src/server/scripts/EasternKingdoms/zone_stormwind_city.cpp @@ -308,7 +308,7 @@ public: } } - void UpdateAI(const uint32 uiDiff) + void UpdateAI(uint32 uiDiff) { if (uiPhase) { @@ -448,7 +448,7 @@ public: } } - void UpdateAI(const uint32 /*diff*/) + void UpdateAI(uint32 /*diff*/) { if (!UpdateVictim()) return; @@ -524,7 +524,7 @@ public: } } - void UpdateAI(const uint32 uiDiff) + void UpdateAI(uint32 uiDiff) { if (uiPhase) { diff --git a/src/server/scripts/EasternKingdoms/zone_stranglethorn_vale.cpp b/src/server/scripts/EasternKingdoms/zone_stranglethorn_vale.cpp index 6e14ef840a3..c11e850cbc8 100644 --- a/src/server/scripts/EasternKingdoms/zone_stranglethorn_vale.cpp +++ b/src/server/scripts/EasternKingdoms/zone_stranglethorn_vale.cpp @@ -83,7 +83,7 @@ public: void EnterCombat(Unit* /*who*/) {} - void UpdateAI(const uint32 diff) + void UpdateAI(uint32 diff) { if (bReset) { diff --git a/src/server/scripts/EasternKingdoms/zone_swamp_of_sorrows.cpp b/src/server/scripts/EasternKingdoms/zone_swamp_of_sorrows.cpp index f686de5d88f..c7780bb0065 100644 --- a/src/server/scripts/EasternKingdoms/zone_swamp_of_sorrows.cpp +++ b/src/server/scripts/EasternKingdoms/zone_swamp_of_sorrows.cpp @@ -128,7 +128,7 @@ public: } } - void UpdateAI(const uint32 uiDiff) + void UpdateAI(uint32 uiDiff) { npc_escortAI::UpdateAI(uiDiff); diff --git a/src/server/scripts/EasternKingdoms/zone_tirisfal_glades.cpp b/src/server/scripts/EasternKingdoms/zone_tirisfal_glades.cpp index f36220dec0f..9a496fadb1e 100644 --- a/src/server/scripts/EasternKingdoms/zone_tirisfal_glades.cpp +++ b/src/server/scripts/EasternKingdoms/zone_tirisfal_glades.cpp @@ -113,7 +113,7 @@ public: } } - void UpdateAI(uint32 const diff) + void UpdateAI(uint32 diff) { if (m_uiPhase) { diff --git a/src/server/scripts/EasternKingdoms/zone_undercity.cpp b/src/server/scripts/EasternKingdoms/zone_undercity.cpp index 2c3017a2f1a..43ee012ef40 100644 --- a/src/server/scripts/EasternKingdoms/zone_undercity.cpp +++ b/src/server/scripts/EasternKingdoms/zone_undercity.cpp @@ -142,7 +142,7 @@ public: } } - void UpdateAI(const uint32 diff) + void UpdateAI(uint32 diff) { if (LamentEvent) { @@ -248,7 +248,7 @@ public: void EnterCombat(Unit* /*who*/) {} - void UpdateAI(const uint32 diff) + void UpdateAI(uint32 diff) { if (EventMove) { diff --git a/src/server/scripts/EasternKingdoms/zone_western_plaguelands.cpp b/src/server/scripts/EasternKingdoms/zone_western_plaguelands.cpp index ee22b766154..1831d9f7ff1 100644 --- a/src/server/scripts/EasternKingdoms/zone_western_plaguelands.cpp +++ b/src/server/scripts/EasternKingdoms/zone_western_plaguelands.cpp @@ -254,9 +254,12 @@ public: return new npc_andorhal_towerAI (creature); } - struct npc_andorhal_towerAI : public Scripted_NoMovementAI + struct npc_andorhal_towerAI : public ScriptedAI { - npc_andorhal_towerAI(Creature* creature) : Scripted_NoMovementAI(creature) {} + npc_andorhal_towerAI(Creature* creature) : ScriptedAI(creature) + { + SetCombatMovement(false); + } void MoveInLineOfSight(Unit* who) { @@ -395,7 +398,7 @@ public: player->FailQuest(QUEST_TOMB_LIGHTBRINGER); } - void UpdateAI(const uint32 uiDiff) + void UpdateAI(uint32 uiDiff) { npc_escortAI::UpdateAI(uiDiff); DoMeleeAttackIfReady(); diff --git a/src/server/scripts/Events/childrens_week.cpp b/src/server/scripts/Events/childrens_week.cpp index 26f83922f87..2ec5e1190c8 100644 --- a/src/server/scripts/Events/childrens_week.cpp +++ b/src/server/scripts/Events/childrens_week.cpp @@ -173,7 +173,7 @@ class npc_winterfin_playmate : public CreatureScript } } - void UpdateAI(const uint32 diff) + void UpdateAI(uint32 diff) { if (!phase) return; @@ -189,10 +189,10 @@ class npc_winterfin_playmate : public CreatureScript return; } - switch(phase) + switch (phase) { case 1: - orphan->GetMotionMaster()->MovePoint(0, me->GetPositionX() + cos(me->GetOrientation()) * 5,me->GetPositionY() + sin(me->GetOrientation()) * 5, me->GetPositionZ()); + orphan->GetMotionMaster()->MovePoint(0, me->GetPositionX() + cos(me->GetOrientation()) * 5, me->GetPositionY() + sin(me->GetOrientation()) * 5, me->GetPositionZ()); orphan->AI()->Talk(TEXT_ORACLE_ORPHAN_1); timer = 3000; break; @@ -271,7 +271,7 @@ class npc_snowfall_glade_playmate : public CreatureScript } } - void UpdateAI(const uint32 diff) + void UpdateAI(uint32 diff) { if (!phase) return; @@ -290,7 +290,7 @@ class npc_snowfall_glade_playmate : public CreatureScript switch (phase) { case 1: - orphan->GetMotionMaster()->MovePoint(0, me->GetPositionX() + cos(me->GetOrientation()) * 5,me->GetPositionY() + sin(me->GetOrientation()) * 5, me->GetPositionZ()); + orphan->GetMotionMaster()->MovePoint(0, me->GetPositionX() + cos(me->GetOrientation()) * 5, me->GetPositionY() + sin(me->GetOrientation()) * 5, me->GetPositionZ()); orphan->AI()->Talk(TEXT_WOLVAR_ORPHAN_1); timer = 5000; break; @@ -371,7 +371,7 @@ class npc_the_biggest_tree : public CreatureScript } } - void UpdateAI(const uint32 diff) + void UpdateAI(uint32 diff) { if (!phase) return; @@ -457,7 +457,7 @@ class npc_high_oracle_soo_roo : public CreatureScript } } - void UpdateAI(const uint32 diff) + void UpdateAI(uint32 diff) { if (!phase) return; @@ -545,7 +545,7 @@ class npc_elder_kekek : public CreatureScript } } - void UpdateAI(const uint32 diff) + void UpdateAI(uint32 diff) { if (!phase) return; @@ -601,7 +601,7 @@ class npc_elder_kekek : public CreatureScript /*###### ## npc_the_etymidian -## TODO: A red crystal as a gift for the great one should be spawned during the event. +## @todo A red crystal as a gift for the great one should be spawned during the event. ######*/ class npc_the_etymidian : public CreatureScript { @@ -633,7 +633,7 @@ class npc_the_etymidian : public CreatureScript } } - void UpdateAI(const uint32 diff) + void UpdateAI(uint32 diff) { if (!phase) return; @@ -755,7 +755,7 @@ class npc_alexstraza_the_lifebinder : public CreatureScript } } - void UpdateAI(const uint32 diff) + void UpdateAI(uint32 diff) { if (!phase) return; @@ -810,7 +810,7 @@ class npc_alexstraza_the_lifebinder : public CreatureScript timer = 5000; break; case 8: - if(Creature* krasus = me->FindNearestCreature(NPC_KRASUS, 10.0f)) + if (Creature* krasus = me->FindNearestCreature(NPC_KRASUS, 10.0f)) { orphan->SetFacingToObject(krasus); krasus->AI()->Talk(TEXT_KRASUS_8); @@ -974,7 +974,7 @@ class npc_cw_area_trigger : public CreatureScript if (Creature* samuro = me->FindNearestCreature(25151, 20.0f)) { uint32 emote = 0; - switch(urand(1,5)) + switch (urand(1, 5)) { case 1: emote = EMOTE_ONESHOT_WAVE; diff --git a/src/server/scripts/Examples/example_creature.cpp b/src/server/scripts/Examples/example_creature.cpp index f82782448ea..d4e1b8d8ce2 100644 --- a/src/server/scripts/Examples/example_creature.cpp +++ b/src/server/scripts/Examples/example_creature.cpp @@ -165,7 +165,7 @@ class example_creature : public CreatureScript // *** HANDLED FUNCTION *** //Update AI is called Every single map update (roughly once every 50ms if a player is within the grid) - void UpdateAI(const uint32 uiDiff) + void UpdateAI(uint32 uiDiff) { //Out of combat timers if (!me->getVictim()) diff --git a/src/server/scripts/Examples/example_escort.cpp b/src/server/scripts/Examples/example_escort.cpp index a7906c4359a..e911736036c 100644 --- a/src/server/scripts/Examples/example_escort.cpp +++ b/src/server/scripts/Examples/example_escort.cpp @@ -136,7 +136,7 @@ class example_escort : public CreatureScript Talk(SAY_DEATH_3); } - void UpdateAI(const uint32 uiDiff) + void UpdateAI(uint32 uiDiff) { //Must update npc_escortAI npc_escortAI::UpdateAI(uiDiff); diff --git a/src/server/scripts/Kalimdor/BlackfathomDeeps/blackfathom_deeps.cpp b/src/server/scripts/Kalimdor/BlackfathomDeeps/blackfathom_deeps.cpp index 27a442f302e..0f52daba991 100644 --- a/src/server/scripts/Kalimdor/BlackfathomDeeps/blackfathom_deeps.cpp +++ b/src/server/scripts/Kalimdor/BlackfathomDeeps/blackfathom_deeps.cpp @@ -132,7 +132,7 @@ public: } } - void UpdateAI(const uint32 diff) + void UpdateAI(uint32 diff) { if (!UpdateVictim()) return; diff --git a/src/server/scripts/Kalimdor/BlackfathomDeeps/boss_aku_mai.cpp b/src/server/scripts/Kalimdor/BlackfathomDeeps/boss_aku_mai.cpp index e3fdc633382..535d9a4425b 100644 --- a/src/server/scripts/Kalimdor/BlackfathomDeeps/boss_aku_mai.cpp +++ b/src/server/scripts/Kalimdor/BlackfathomDeeps/boss_aku_mai.cpp @@ -67,7 +67,7 @@ public: instance->SetData(TYPE_AKU_MAI, DONE); } - void UpdateAI(const uint32 diff) + void UpdateAI(uint32 diff) { if (!UpdateVictim()) return; diff --git a/src/server/scripts/Kalimdor/BlackfathomDeeps/boss_gelihast.cpp b/src/server/scripts/Kalimdor/BlackfathomDeeps/boss_gelihast.cpp index ee87dfa3cf8..4fa9edd40c6 100644 --- a/src/server/scripts/Kalimdor/BlackfathomDeeps/boss_gelihast.cpp +++ b/src/server/scripts/Kalimdor/BlackfathomDeeps/boss_gelihast.cpp @@ -64,7 +64,7 @@ public: instance->SetData(TYPE_GELIHAST, DONE); } - void UpdateAI(const uint32 diff) + void UpdateAI(uint32 diff) { if (!UpdateVictim()) return; diff --git a/src/server/scripts/Kalimdor/BlackfathomDeeps/boss_kelris.cpp b/src/server/scripts/Kalimdor/BlackfathomDeeps/boss_kelris.cpp index 61f933d0893..72992c477a8 100644 --- a/src/server/scripts/Kalimdor/BlackfathomDeeps/boss_kelris.cpp +++ b/src/server/scripts/Kalimdor/BlackfathomDeeps/boss_kelris.cpp @@ -73,7 +73,7 @@ public: instance->SetData(TYPE_KELRIS, DONE); } - void UpdateAI(const uint32 diff) + void UpdateAI(uint32 diff) { if (!UpdateVictim()) return; diff --git a/src/server/scripts/Kalimdor/CMakeLists.txt b/src/server/scripts/Kalimdor/CMakeLists.txt index 5c44cd7ef27..536824e7a63 100644 --- a/src/server/scripts/Kalimdor/CMakeLists.txt +++ b/src/server/scripts/Kalimdor/CMakeLists.txt @@ -38,11 +38,11 @@ set(scripts_STAT_SRCS Kalimdor/CavernsOfTime/BattleForMountHyjal/hyjal.h Kalimdor/CavernsOfTime/BattleForMountHyjal/boss_azgalor.cpp Kalimdor/CavernsOfTime/BattleForMountHyjal/boss_anetheron.cpp - Kalimdor/CavernsOfTime/CullingOfStratholme/boss_infinite.cpp - Kalimdor/CavernsOfTime/CullingOfStratholme/boss_salramm.cpp + Kalimdor/CavernsOfTime/CullingOfStratholme/boss_infinite_corruptor.cpp + Kalimdor/CavernsOfTime/CullingOfStratholme/boss_salramm_the_fleshcrafter.cpp Kalimdor/CavernsOfTime/CullingOfStratholme/boss_meathook.cpp Kalimdor/CavernsOfTime/CullingOfStratholme/boss_mal_ganis.cpp - Kalimdor/CavernsOfTime/CullingOfStratholme/boss_epoch.cpp + Kalimdor/CavernsOfTime/CullingOfStratholme/boss_chrono_lord_epoch.cpp Kalimdor/CavernsOfTime/CullingOfStratholme/culling_of_stratholme.cpp Kalimdor/CavernsOfTime/CullingOfStratholme/instance_culling_of_stratholme.cpp Kalimdor/CavernsOfTime/CullingOfStratholme/culling_of_stratholme.h diff --git a/src/server/scripts/Kalimdor/CavernsOfTime/BattleForMountHyjal/boss_anetheron.cpp b/src/server/scripts/Kalimdor/CavernsOfTime/BattleForMountHyjal/boss_anetheron.cpp index 075d54937c7..6a697c3cc9c 100644 --- a/src/server/scripts/Kalimdor/CavernsOfTime/BattleForMountHyjal/boss_anetheron.cpp +++ b/src/server/scripts/Kalimdor/CavernsOfTime/BattleForMountHyjal/boss_anetheron.cpp @@ -106,7 +106,7 @@ public: Talk(SAY_ONDEATH); } - void UpdateAI(const uint32 diff) + void UpdateAI(uint32 diff) { if (IsEvent) { @@ -221,7 +221,7 @@ public: AttackStart(who); } - void UpdateAI(const uint32 diff) + void UpdateAI(uint32 diff) { if (CheckTimer <= diff) { diff --git a/src/server/scripts/Kalimdor/CavernsOfTime/BattleForMountHyjal/boss_archimonde.cpp b/src/server/scripts/Kalimdor/CavernsOfTime/BattleForMountHyjal/boss_archimonde.cpp index e278b3009a0..dcf9605f101 100644 --- a/src/server/scripts/Kalimdor/CavernsOfTime/BattleForMountHyjal/boss_archimonde.cpp +++ b/src/server/scripts/Kalimdor/CavernsOfTime/BattleForMountHyjal/boss_archimonde.cpp @@ -115,7 +115,7 @@ public: damage = 0; } - void UpdateAI(const uint32 diff) + void UpdateAI(uint32 diff) { if (CheckTimer <= diff) { @@ -200,7 +200,7 @@ public: damage = 0; } - void UpdateAI(const uint32 diff) + void UpdateAI(uint32 diff) { if (ChangeTargetTimer <= diff) { @@ -465,7 +465,7 @@ public: SoulChargeTimer = urand(2000, 30000); } - void UpdateAI(const uint32 diff) + void UpdateAI(uint32 diff) { if (!me->isInCombat()) { diff --git a/src/server/scripts/Kalimdor/CavernsOfTime/BattleForMountHyjal/boss_azgalor.cpp b/src/server/scripts/Kalimdor/CavernsOfTime/BattleForMountHyjal/boss_azgalor.cpp index 180aeb0962d..15470716ea7 100644 --- a/src/server/scripts/Kalimdor/CavernsOfTime/BattleForMountHyjal/boss_azgalor.cpp +++ b/src/server/scripts/Kalimdor/CavernsOfTime/BattleForMountHyjal/boss_azgalor.cpp @@ -112,7 +112,7 @@ public: Talk(SAY_ONDEATH); } - void UpdateAI(const uint32 diff) + void UpdateAI(uint32 diff) { if (IsEvent) { @@ -234,7 +234,7 @@ public: { } - void UpdateAI(const uint32 diff) + void UpdateAI(uint32 diff) { if (CheckTimer <= diff) { diff --git a/src/server/scripts/Kalimdor/CavernsOfTime/BattleForMountHyjal/boss_kazrogal.cpp b/src/server/scripts/Kalimdor/CavernsOfTime/BattleForMountHyjal/boss_kazrogal.cpp index 2432be2c31a..0780b3dcf0d 100644 --- a/src/server/scripts/Kalimdor/CavernsOfTime/BattleForMountHyjal/boss_kazrogal.cpp +++ b/src/server/scripts/Kalimdor/CavernsOfTime/BattleForMountHyjal/boss_kazrogal.cpp @@ -108,7 +108,7 @@ public: DoPlaySoundToSet(me, SOUND_ONDEATH); } - void UpdateAI(const uint32 diff) + void UpdateAI(uint32 diff) { if (IsEvent) { diff --git a/src/server/scripts/Kalimdor/CavernsOfTime/BattleForMountHyjal/boss_rage_winterchill.cpp b/src/server/scripts/Kalimdor/CavernsOfTime/BattleForMountHyjal/boss_rage_winterchill.cpp index 84ef05779ee..b35826c9d87 100644 --- a/src/server/scripts/Kalimdor/CavernsOfTime/BattleForMountHyjal/boss_rage_winterchill.cpp +++ b/src/server/scripts/Kalimdor/CavernsOfTime/BattleForMountHyjal/boss_rage_winterchill.cpp @@ -103,7 +103,7 @@ public: Talk(SAY_ONDEATH); } - void UpdateAI(const uint32 diff) + void UpdateAI(uint32 diff) { if (IsEvent) { diff --git a/src/server/scripts/Kalimdor/CavernsOfTime/BattleForMountHyjal/hyjalAI.cpp b/src/server/scripts/Kalimdor/CavernsOfTime/BattleForMountHyjal/hyjalAI.cpp index aa17fcf6af4..3f186c96d40 100644 --- a/src/server/scripts/Kalimdor/CavernsOfTime/BattleForMountHyjal/hyjalAI.cpp +++ b/src/server/scripts/Kalimdor/CavernsOfTime/BattleForMountHyjal/hyjalAI.cpp @@ -708,7 +708,7 @@ void hyjalAI::DeSpawnVeins() } } -void hyjalAI::UpdateAI(const uint32 diff) +void hyjalAI::UpdateAI(uint32 diff) { if (IsDummy) { diff --git a/src/server/scripts/Kalimdor/CavernsOfTime/BattleForMountHyjal/hyjalAI.h b/src/server/scripts/Kalimdor/CavernsOfTime/BattleForMountHyjal/hyjalAI.h index 0833dc2bf07..f40c868a96b 100644 --- a/src/server/scripts/Kalimdor/CavernsOfTime/BattleForMountHyjal/hyjalAI.h +++ b/src/server/scripts/Kalimdor/CavernsOfTime/BattleForMountHyjal/hyjalAI.h @@ -153,7 +153,7 @@ struct hyjalAI : public npc_escortAI void EnterCombat(Unit* /*who*/); // Used to reset cooldowns for our spells and to inform the raid that we're under attack - void UpdateAI(const uint32 diff); // Called to summon waves, check for boss deaths and to cast our spells. + void UpdateAI(uint32 diff); // Called to summon waves, check for boss deaths and to cast our spells. void JustDied(Unit* /*killer*/); // Called on death, informs the raid that they have failed. diff --git a/src/server/scripts/Kalimdor/CavernsOfTime/BattleForMountHyjal/hyjal_trash.cpp b/src/server/scripts/Kalimdor/CavernsOfTime/BattleForMountHyjal/hyjal_trash.cpp index 36f6f94b324..adb89ba5a69 100644 --- a/src/server/scripts/Kalimdor/CavernsOfTime/BattleForMountHyjal/hyjal_trash.cpp +++ b/src/server/scripts/Kalimdor/CavernsOfTime/BattleForMountHyjal/hyjal_trash.cpp @@ -199,7 +199,7 @@ void hyjal_trashAI::DamageTaken(Unit* done_by, uint32 &damage) } } -void hyjal_trashAI::UpdateAI(const uint32 /*diff*/) +void hyjal_trashAI::UpdateAI(uint32 /*diff*/) { if (IsOverrun && !SetupOverrun) { @@ -458,7 +458,7 @@ public: } } - void UpdateAI(const uint32 diff) + void UpdateAI(uint32 diff) { if (Delay <= diff) { @@ -596,7 +596,7 @@ public: void EnterCombat(Unit* /*who*/) {} - void UpdateAI(const uint32 diff) + void UpdateAI(uint32 diff) { hyjal_trashAI::UpdateAI(diff); if (IsEvent || IsOverrun) @@ -699,7 +699,7 @@ public: void EnterCombat(Unit* /*who*/) {} - void UpdateAI(const uint32 diff) + void UpdateAI(uint32 diff) { hyjal_trashAI::UpdateAI(diff); if (IsEvent || IsOverrun) @@ -822,7 +822,7 @@ public: void EnterCombat(Unit* /*who*/) {} - void UpdateAI(const uint32 diff) + void UpdateAI(uint32 diff) { hyjal_trashAI::UpdateAI(diff); @@ -920,7 +920,7 @@ public: void EnterCombat(Unit* /*who*/) {} - void UpdateAI(const uint32 diff) + void UpdateAI(uint32 diff) { hyjal_trashAI::UpdateAI(diff); if (IsEvent || IsOverrun) @@ -1019,7 +1019,7 @@ public: void EnterCombat(Unit* /*who*/) {} - void UpdateAI(const uint32 diff) + void UpdateAI(uint32 diff) { hyjal_trashAI::UpdateAI(diff); if (IsEvent || IsOverrun) @@ -1109,7 +1109,7 @@ public: void EnterCombat(Unit* /*who*/) {} - void UpdateAI(const uint32 diff) + void UpdateAI(uint32 diff) { hyjal_trashAI::UpdateAI(diff); if (IsEvent || IsOverrun) @@ -1208,7 +1208,7 @@ public: void EnterCombat(Unit* /*who*/) {} - void UpdateAI(const uint32 diff) + void UpdateAI(uint32 diff) { hyjal_trashAI::UpdateAI(diff); if (IsEvent || IsOverrun) @@ -1321,7 +1321,7 @@ public: hyjal_trashAI::JustDied(killer); } - void UpdateAI(const uint32 diff) + void UpdateAI(uint32 diff) { hyjal_trashAI::UpdateAI(diff); if (IsEvent || IsOverrun) @@ -1369,8 +1369,7 @@ public: forcemove = false; if (forcemove) { - Unit* target = SelectTarget(SELECT_TARGET_RANDOM, 0); - if (target) + if (Unit* target = SelectTarget(SELECT_TARGET_RANDOM, 0)) me->Attack(target, false); } if (MoveTimer <= diff) @@ -1409,11 +1408,11 @@ public: return new alliance_riflemanAI(creature); } - struct alliance_riflemanAI : public Scripted_NoMovementAI + struct alliance_riflemanAI : public ScriptedAI { - alliance_riflemanAI(Creature* creature) : Scripted_NoMovementAI(creature) + alliance_riflemanAI(Creature* creature) : ScriptedAI(creature) { - Reset(); + SetCombatMovement(false); } uint32 ExplodeTimer; @@ -1444,7 +1443,7 @@ public: { } - void UpdateAI(const uint32 diff) + void UpdateAI(uint32 diff) { //Check if we have a target if (!UpdateVictim()) diff --git a/src/server/scripts/Kalimdor/CavernsOfTime/BattleForMountHyjal/hyjal_trash.h b/src/server/scripts/Kalimdor/CavernsOfTime/BattleForMountHyjal/hyjal_trash.h index 1a9a4394a3d..01ae6244b4a 100644 --- a/src/server/scripts/Kalimdor/CavernsOfTime/BattleForMountHyjal/hyjal_trash.h +++ b/src/server/scripts/Kalimdor/CavernsOfTime/BattleForMountHyjal/hyjal_trash.h @@ -27,7 +27,7 @@ struct hyjal_trashAI : public npc_escortAI { hyjal_trashAI(Creature* creature); - void UpdateAI(const uint32 diff); + void UpdateAI(uint32 diff); void JustDied(Unit* /*killer*/); diff --git a/src/server/scripts/Kalimdor/CavernsOfTime/CullingOfStratholme/boss_epoch.cpp b/src/server/scripts/Kalimdor/CavernsOfTime/CullingOfStratholme/boss_chrono_lord_epoch.cpp index fad5736e18f..2259cc84e15 100644 --- a/src/server/scripts/Kalimdor/CavernsOfTime/CullingOfStratholme/boss_epoch.cpp +++ b/src/server/scripts/Kalimdor/CavernsOfTime/CullingOfStratholme/boss_chrono_lord_epoch.cpp @@ -19,7 +19,7 @@ SDName: Boss epoch SDAuthor: Tartalo SD%Complete: 80 -SDComment: TODO: Intro, consecutive attacks to a random target durin time wrap, adjust timers +SDComment: @todo Intro, consecutive attacks to a random target durin time wrap, adjust timers SDCategory: Script Data End */ @@ -93,7 +93,7 @@ public: instance->SetData(DATA_EPOCH_EVENT, IN_PROGRESS); } - void UpdateAI(const uint32 diff) + void UpdateAI(uint32 diff) { //Return since we have no target if (!UpdateVictim()) diff --git a/src/server/scripts/Kalimdor/CavernsOfTime/CullingOfStratholme/boss_infinite.cpp b/src/server/scripts/Kalimdor/CavernsOfTime/CullingOfStratholme/boss_infinite_corruptor.cpp index 8c2861db299..262f8a76509 100644 --- a/src/server/scripts/Kalimdor/CavernsOfTime/CullingOfStratholme/boss_infinite.cpp +++ b/src/server/scripts/Kalimdor/CavernsOfTime/CullingOfStratholme/boss_infinite_corruptor.cpp @@ -64,7 +64,7 @@ public: instance->SetData(DATA_INFINITE_EVENT, IN_PROGRESS); } - void UpdateAI(uint32 const /*diff*/) + void UpdateAI(uint32 /*diff*/) { //Return since we have no target if (!UpdateVictim()) diff --git a/src/server/scripts/Kalimdor/CavernsOfTime/CullingOfStratholme/boss_mal_ganis.cpp b/src/server/scripts/Kalimdor/CavernsOfTime/CullingOfStratholme/boss_mal_ganis.cpp index 5aacaf736e0..8020d606532 100644 --- a/src/server/scripts/Kalimdor/CavernsOfTime/CullingOfStratholme/boss_mal_ganis.cpp +++ b/src/server/scripts/Kalimdor/CavernsOfTime/CullingOfStratholme/boss_mal_ganis.cpp @@ -19,7 +19,7 @@ SDName: Boss mal_ganis SDAuthor: Tartalo SD%Complete: 80 -SDComment: TODO: Intro & outro +SDComment: @todo Intro & outro SDCategory: Script Data End */ @@ -119,7 +119,7 @@ public: damage = me->GetHealth()-1; } - void UpdateAI(const uint32 diff) + void UpdateAI(uint32 diff) { switch (Phase) { diff --git a/src/server/scripts/Kalimdor/CavernsOfTime/CullingOfStratholme/boss_meathook.cpp b/src/server/scripts/Kalimdor/CavernsOfTime/CullingOfStratholme/boss_meathook.cpp index c7b819dd243..7cf095d176c 100644 --- a/src/server/scripts/Kalimdor/CavernsOfTime/CullingOfStratholme/boss_meathook.cpp +++ b/src/server/scripts/Kalimdor/CavernsOfTime/CullingOfStratholme/boss_meathook.cpp @@ -87,7 +87,7 @@ public: instance->SetData(DATA_MEATHOOK_EVENT, IN_PROGRESS); } - void UpdateAI(const uint32 diff) + void UpdateAI(uint32 diff) { //Return since we have no target if (!UpdateVictim()) diff --git a/src/server/scripts/Kalimdor/CavernsOfTime/CullingOfStratholme/boss_salramm.cpp b/src/server/scripts/Kalimdor/CavernsOfTime/CullingOfStratholme/boss_salramm_the_fleshcrafter.cpp index d7d9beaedd4..cda2175a22d 100644 --- a/src/server/scripts/Kalimdor/CavernsOfTime/CullingOfStratholme/boss_salramm.cpp +++ b/src/server/scripts/Kalimdor/CavernsOfTime/CullingOfStratholme/boss_salramm_the_fleshcrafter.cpp @@ -19,7 +19,7 @@ SDName: Boss salramm SDAuthor: Tartalo SD%Complete: 80 -SDComment: TODO: Intro +SDComment: @todo Intro SDCategory: Script Data End */ @@ -96,7 +96,7 @@ public: instance->SetData(DATA_SALRAMM_EVENT, IN_PROGRESS); } - void UpdateAI(const uint32 diff) + void UpdateAI(uint32 diff) { //Return since we have no target if (!UpdateVictim()) diff --git a/src/server/scripts/Kalimdor/CavernsOfTime/CullingOfStratholme/culling_of_stratholme.cpp b/src/server/scripts/Kalimdor/CavernsOfTime/CullingOfStratholme/culling_of_stratholme.cpp index d5d5416f093..d8df5d56888 100644 --- a/src/server/scripts/Kalimdor/CavernsOfTime/CullingOfStratholme/culling_of_stratholme.cpp +++ b/src/server/scripts/Kalimdor/CavernsOfTime/CullingOfStratholme/culling_of_stratholme.cpp @@ -589,7 +589,7 @@ public: } } - void UpdateAI(const uint32 diff) + void UpdateAI(uint32 diff) { npc_escortAI::UpdateAI(diff); diff --git a/src/server/scripts/Kalimdor/CavernsOfTime/DarkPortal/boss_aeonus.cpp b/src/server/scripts/Kalimdor/CavernsOfTime/DarkPortal/boss_aeonus.cpp index 7643131edf7..7a18210791c 100644 --- a/src/server/scripts/Kalimdor/CavernsOfTime/DarkPortal/boss_aeonus.cpp +++ b/src/server/scripts/Kalimdor/CavernsOfTime/DarkPortal/boss_aeonus.cpp @@ -109,7 +109,7 @@ public: Talk(SAY_SLAY); } - void UpdateAI(const uint32 diff) + void UpdateAI(uint32 diff) { //Return since we have no target if (!UpdateVictim()) diff --git a/src/server/scripts/Kalimdor/CavernsOfTime/DarkPortal/boss_chrono_lord_deja.cpp b/src/server/scripts/Kalimdor/CavernsOfTime/DarkPortal/boss_chrono_lord_deja.cpp index ea372621026..ef0d7b1f418 100644 --- a/src/server/scripts/Kalimdor/CavernsOfTime/DarkPortal/boss_chrono_lord_deja.cpp +++ b/src/server/scripts/Kalimdor/CavernsOfTime/DarkPortal/boss_chrono_lord_deja.cpp @@ -108,7 +108,7 @@ public: instance->SetData(TYPE_RIFT, SPECIAL); } - void UpdateAI(const uint32 diff) + void UpdateAI(uint32 diff) { //Return since we have no target if (!UpdateVictim()) @@ -124,8 +124,8 @@ public: //Arcane Discharge if (ArcaneDischarge_Timer <= diff) { - Unit* target = SelectTarget(SELECT_TARGET_RANDOM, 0); - DoCast(target, SPELL_ARCANE_DISCHARGE); + if (Unit* target = SelectTarget(SELECT_TARGET_RANDOM, 0)) + DoCast(target, SPELL_ARCANE_DISCHARGE); ArcaneDischarge_Timer = 20000+rand()%10000; } else ArcaneDischarge_Timer -= diff; diff --git a/src/server/scripts/Kalimdor/CavernsOfTime/DarkPortal/boss_temporus.cpp b/src/server/scripts/Kalimdor/CavernsOfTime/DarkPortal/boss_temporus.cpp index 6e78e4dae7b..e224094b1f9 100644 --- a/src/server/scripts/Kalimdor/CavernsOfTime/DarkPortal/boss_temporus.cpp +++ b/src/server/scripts/Kalimdor/CavernsOfTime/DarkPortal/boss_temporus.cpp @@ -108,7 +108,7 @@ public: ScriptedAI::MoveInLineOfSight(who); } - void UpdateAI(const uint32 diff) + void UpdateAI(uint32 diff) { //Return since we have no target if (!UpdateVictim()) diff --git a/src/server/scripts/Kalimdor/CavernsOfTime/DarkPortal/dark_portal.cpp b/src/server/scripts/Kalimdor/CavernsOfTime/DarkPortal/dark_portal.cpp index 4c80bc017b7..69054727e4a 100644 --- a/src/server/scripts/Kalimdor/CavernsOfTime/DarkPortal/dark_portal.cpp +++ b/src/server/scripts/Kalimdor/CavernsOfTime/DarkPortal/dark_portal.cpp @@ -168,7 +168,7 @@ public: Talk(SAY_DEATH); } - void UpdateAI(const uint32 diff) + void UpdateAI(uint32 diff) { if (!instance) return; @@ -229,7 +229,7 @@ public: if (me->HasAura(SPELL_CHANNEL)) me->RemoveAura(SPELL_CHANNEL); - //TODO: start the post-event here + /// @todo start the post-event here instance->SetData(TYPE_MEDIVH, DONE); } } else Check_Timer -= diff; @@ -342,7 +342,7 @@ public: } else DoSummonAtRift(entry); } - void UpdateAI(const uint32 diff) + void UpdateAI(uint32 diff) { if (!instance) return; diff --git a/src/server/scripts/Kalimdor/CavernsOfTime/DarkPortal/instance_dark_portal.cpp b/src/server/scripts/Kalimdor/CavernsOfTime/DarkPortal/instance_dark_portal.cpp index 9c17ed10d9c..78b655bb73b 100644 --- a/src/server/scripts/Kalimdor/CavernsOfTime/DarkPortal/instance_dark_portal.cpp +++ b/src/server/scripts/Kalimdor/CavernsOfTime/DarkPortal/instance_dark_portal.cpp @@ -122,7 +122,7 @@ public: bool IsEncounterInProgress() const { - if (const_cast<instance_dark_portal_InstanceMapScript*>(this)->GetData(TYPE_MEDIVH) == IN_PROGRESS) + if (GetData(TYPE_MEDIVH) == IN_PROGRESS) return true; return false; diff --git a/src/server/scripts/Kalimdor/CavernsOfTime/EscapeFromDurnholdeKeep/boss_captain_skarloc.cpp b/src/server/scripts/Kalimdor/CavernsOfTime/EscapeFromDurnholdeKeep/boss_captain_skarloc.cpp index 5e7fc6e66e8..adbc7a14745 100644 --- a/src/server/scripts/Kalimdor/CavernsOfTime/EscapeFromDurnholdeKeep/boss_captain_skarloc.cpp +++ b/src/server/scripts/Kalimdor/CavernsOfTime/EscapeFromDurnholdeKeep/boss_captain_skarloc.cpp @@ -103,7 +103,7 @@ public: instance->SetData(TYPE_THRALL_PART1, DONE); } - void UpdateAI(const uint32 diff) + void UpdateAI(uint32 diff) { //Return since we have no target if (!UpdateVictim()) diff --git a/src/server/scripts/Kalimdor/CavernsOfTime/EscapeFromDurnholdeKeep/boss_epoch_hunter.cpp b/src/server/scripts/Kalimdor/CavernsOfTime/EscapeFromDurnholdeKeep/boss_epoch_hunter.cpp index ad3e6979dfb..b48e0b376ea 100644 --- a/src/server/scripts/Kalimdor/CavernsOfTime/EscapeFromDurnholdeKeep/boss_epoch_hunter.cpp +++ b/src/server/scripts/Kalimdor/CavernsOfTime/EscapeFromDurnholdeKeep/boss_epoch_hunter.cpp @@ -95,7 +95,7 @@ public: instance->SetData(TYPE_THRALL_PART4, DONE); } - void UpdateAI(const uint32 diff) + void UpdateAI(uint32 diff) { //Return since we have no target if (!UpdateVictim()) diff --git a/src/server/scripts/Kalimdor/CavernsOfTime/EscapeFromDurnholdeKeep/boss_leutenant_drake.cpp b/src/server/scripts/Kalimdor/CavernsOfTime/EscapeFromDurnholdeKeep/boss_leutenant_drake.cpp index 65f496a579f..a4de0409573 100644 --- a/src/server/scripts/Kalimdor/CavernsOfTime/EscapeFromDurnholdeKeep/boss_leutenant_drake.cpp +++ b/src/server/scripts/Kalimdor/CavernsOfTime/EscapeFromDurnholdeKeep/boss_leutenant_drake.cpp @@ -150,9 +150,9 @@ public: Talk(SAY_DEATH); } - void UpdateAI(const uint32 diff) + void UpdateAI(uint32 diff) { - //TODO: make this work + /// @todo make this work if (CanPatrol && wpId == 0) { me->GetMotionMaster()->MovePoint(DrakeWP[0].wpId, DrakeWP[0].x, DrakeWP[0].y, DrakeWP[0].z); diff --git a/src/server/scripts/Kalimdor/CavernsOfTime/EscapeFromDurnholdeKeep/old_hillsbrad.cpp b/src/server/scripts/Kalimdor/CavernsOfTime/EscapeFromDurnholdeKeep/old_hillsbrad.cpp index 4a4ba4f3ce2..b9820790d47 100644 --- a/src/server/scripts/Kalimdor/CavernsOfTime/EscapeFromDurnholdeKeep/old_hillsbrad.cpp +++ b/src/server/scripts/Kalimdor/CavernsOfTime/EscapeFromDurnholdeKeep/old_hillsbrad.cpp @@ -507,7 +507,7 @@ public: { switch (summoned->GetEntry()) { - //TODO: make Scarloc start into event instead, and not start attack directly + /// @todo make Scarloc start into event instead, and not start attack directly case MOB_ENTRY_BARN_GUARDSMAN: case MOB_ENTRY_BARN_PROTECTOR: case MOB_ENTRY_BARN_LOOKOUT: @@ -536,14 +536,14 @@ public: Talk(SAY_TH_RANDOM_DIE); } - void UpdateAI(const uint32 diff) + void UpdateAI(uint32 diff) { npc_escortAI::UpdateAI(diff); if (!UpdateVictim()) return; - //TODO: add his abilities'n-crap here + /// @todo add his abilities'n-crap here if (!LowHp && HealthBelowPct(20)) { Talk(SAY_TH_RANDOM_LOW_HP); @@ -642,7 +642,7 @@ public: void Reset() {} void EnterCombat(Unit* /*who*/) {} - void UpdateAI(const uint32 diff) + void UpdateAI(uint32 diff) { npc_escortAI::UpdateAI(diff); } diff --git a/src/server/scripts/Kalimdor/Maraudon/boss_celebras_the_cursed.cpp b/src/server/scripts/Kalimdor/Maraudon/boss_celebras_the_cursed.cpp index 222937621a8..695f9d2973e 100644 --- a/src/server/scripts/Kalimdor/Maraudon/boss_celebras_the_cursed.cpp +++ b/src/server/scripts/Kalimdor/Maraudon/boss_celebras_the_cursed.cpp @@ -65,7 +65,7 @@ public: me->SummonCreature(13716, me->GetPositionX(), me->GetPositionY(), me->GetPositionZ(), 0, TEMPSUMMON_TIMED_DESPAWN, 600000); } - void UpdateAI(const uint32 diff) + void UpdateAI(uint32 diff) { if (!UpdateVictim()) return; diff --git a/src/server/scripts/Kalimdor/Maraudon/boss_landslide.cpp b/src/server/scripts/Kalimdor/Maraudon/boss_landslide.cpp index c6c0387026c..eea34e1949f 100644 --- a/src/server/scripts/Kalimdor/Maraudon/boss_landslide.cpp +++ b/src/server/scripts/Kalimdor/Maraudon/boss_landslide.cpp @@ -62,7 +62,7 @@ public: { } - void UpdateAI(const uint32 diff) + void UpdateAI(uint32 diff) { if (!UpdateVictim()) return; diff --git a/src/server/scripts/Kalimdor/Maraudon/boss_noxxion.cpp b/src/server/scripts/Kalimdor/Maraudon/boss_noxxion.cpp index 3fcd840077f..96c3c4a6c45 100644 --- a/src/server/scripts/Kalimdor/Maraudon/boss_noxxion.cpp +++ b/src/server/scripts/Kalimdor/Maraudon/boss_noxxion.cpp @@ -69,7 +69,7 @@ public: Add->AI()->AttackStart(victim); } - void UpdateAI(const uint32 diff) + void UpdateAI(uint32 diff) { if (Invisible && InvisibleTimer <= diff) { diff --git a/src/server/scripts/Kalimdor/Maraudon/boss_princess_theradras.cpp b/src/server/scripts/Kalimdor/Maraudon/boss_princess_theradras.cpp index eda5f125b00..ddce2f658e7 100644 --- a/src/server/scripts/Kalimdor/Maraudon/boss_princess_theradras.cpp +++ b/src/server/scripts/Kalimdor/Maraudon/boss_princess_theradras.cpp @@ -69,7 +69,7 @@ public: me->SummonCreature(12238, 28.067f, 61.875f, -123.405f, 4.67f, TEMPSUMMON_TIMED_DESPAWN, 600000); } - void UpdateAI(const uint32 diff) + void UpdateAI(uint32 diff) { if (!UpdateVictim()) return; diff --git a/src/server/scripts/Kalimdor/OnyxiasLair/boss_onyxia.cpp b/src/server/scripts/Kalimdor/OnyxiasLair/boss_onyxia.cpp index 4724794d03b..e01f2b097b0 100644 --- a/src/server/scripts/Kalimdor/OnyxiasLair/boss_onyxia.cpp +++ b/src/server/scripts/Kalimdor/OnyxiasLair/boss_onyxia.cpp @@ -341,7 +341,7 @@ public: MovePoint = iTemp; } - void UpdateAI(const uint32 Diff) + void UpdateAI(uint32 Diff) { if (!UpdateVictim()) return; diff --git a/src/server/scripts/Kalimdor/RazorfenDowns/boss_amnennar_the_coldbringer.cpp b/src/server/scripts/Kalimdor/RazorfenDowns/boss_amnennar_the_coldbringer.cpp index d272b3cc84c..374652ee91d 100644 --- a/src/server/scripts/Kalimdor/RazorfenDowns/boss_amnennar_the_coldbringer.cpp +++ b/src/server/scripts/Kalimdor/RazorfenDowns/boss_amnennar_the_coldbringer.cpp @@ -81,7 +81,7 @@ public: Talk(SAY_KILL); } - void UpdateAI(const uint32 diff) + void UpdateAI(uint32 diff) { if (!UpdateVictim()) return; diff --git a/src/server/scripts/Kalimdor/RazorfenDowns/razorfen_downs.cpp b/src/server/scripts/Kalimdor/RazorfenDowns/razorfen_downs.cpp index b90d5a760d3..78535b7c3b0 100644 --- a/src/server/scripts/Kalimdor/RazorfenDowns/razorfen_downs.cpp +++ b/src/server/scripts/Kalimdor/RazorfenDowns/razorfen_downs.cpp @@ -142,7 +142,7 @@ public: uiWebTimer = urand(5000, 8000); } - void UpdateAI(const uint32 uiDiff) + void UpdateAI(uint32 uiDiff) { if (!UpdateVictim()) return; diff --git a/src/server/scripts/Kalimdor/RuinsOfAhnQiraj/boss_ayamiss.cpp b/src/server/scripts/Kalimdor/RuinsOfAhnQiraj/boss_ayamiss.cpp index e72e6dff9cf..aec78581514 100644 --- a/src/server/scripts/Kalimdor/RuinsOfAhnQiraj/boss_ayamiss.cpp +++ b/src/server/scripts/Kalimdor/RuinsOfAhnQiraj/boss_ayamiss.cpp @@ -16,25 +16,59 @@ * with this program. If not, see <http://www.gnu.org/licenses/>. */ -#include "ObjectMgr.h" #include "ScriptMgr.h" #include "ScriptedCreature.h" +#include "Player.h" #include "ruins_of_ahnqiraj.h" enum Spells { - SPELL_STINGERSPRAY = 25749, - SPELL_POISONSTINGER = 25748, // Only used in phase 1 + SPELL_STINGER_SPRAY = 25749, + SPELL_POISON_STINGER = 25748, SPELL_PARALYZE = 25725, SPELL_TRASH = 3391, - SPELL_FRENZY = 8269, // Not used + SPELL_FRENZY = 8269, SPELL_LASH = 25852, - SPELL_FEED = 25721, + SPELL_FEED = 25721 }; -enum Says +enum Events { - EMOTE_FRENZY = 0 // Not used + EVENT_STINGER_SPRAY = 0, + EVENT_POISON_STINGER = 1, + EVENT_SUMMON_SWARMER = 2, + EVENT_SWARMER_ATTACK = 3, + EVENT_PARALYZE = 4, + EVENT_LASH = 5, + EVENT_TRASH = 6 +}; + +enum Emotes +{ + EMOTE_FRENZY = 0 +}; + +enum Phases +{ + PHASE_AIR = 0, + PHASE_GROUND = 1 +}; + +enum Points +{ + POINT_AIR = 0, + POINT_GROUND = 1, + POINT_PARALYZE = 2 +}; + +const Position AyamissAirPos = { -9689.292f, 1547.912f, 48.02729f, 0.0f }; +const Position AltarPos = { -9717.18f, 1517.72f, 27.4677f, 0.0f }; +/// @todo These below are probably incorrect, taken from SD2 +const Position SwarmerPos = { -9647.352f, 1578.062f, 55.32f, 0.0f }; +const Position LarvaPos[2] = +{ + { -9674.4707f, 1528.4133f, 22.457f, 0.0f }, + { -9701.6005f, 1566.9993f, 24.118f, 0.0f } }; class boss_ayamiss : public CreatureScript @@ -42,65 +76,221 @@ class boss_ayamiss : public CreatureScript public: boss_ayamiss() : CreatureScript("boss_ayamiss") { } - struct boss_ayamissAI : public ScriptedAI + struct boss_ayamissAI : public BossAI { - boss_ayamissAI(Creature* creature) : ScriptedAI(creature) + boss_ayamissAI(Creature* creature) : BossAI(creature, DATA_AYAMISS) { - instance = creature->GetInstanceScript(); } - uint32 STINGERSPRAY_Timer; - uint32 POISONSTINGER_Timer; - uint32 SUMMONSWARMER_Timer; - uint32 phase; + void Reset() + { + _Reset(); + _phase = PHASE_AIR; + _enraged = false; + SetCombatMovement(false); + } - InstanceScript* instance; + void JustSummoned(Creature* who) + { + switch (who->GetEntry()) + { + case NPC_SWARMER: + _swarmers.push_back(who->GetGUID()); + break; + case NPC_LARVA: + who->GetMotionMaster()->MovePoint(POINT_PARALYZE, AltarPos); + break; + case NPC_HORNET: + if (Unit* target = SelectTarget(SELECT_TARGET_RANDOM)) + who->AI()->AttackStart(target); + break; + } + } - void Reset() + void MovementInform(uint32 type, uint32 id) + { + if (type == POINT_MOTION_TYPE) + { + switch (id) + { + case POINT_AIR: + me->AddUnitState(UNIT_STATE_ROOT); + break; + case POINT_GROUND: + me->ClearUnitState(UNIT_STATE_ROOT); + break; + } + } + } + + void EnterEvadeMode() { - STINGERSPRAY_Timer = 30000; - POISONSTINGER_Timer = 30000; - SUMMONSWARMER_Timer = 60000; - phase = 1; + me->ClearUnitState(UNIT_STATE_ROOT); + BossAI::EnterEvadeMode(); + } + + void EnterCombat(Unit* attacker) + { + BossAI::EnterCombat(attacker); + + events.ScheduleEvent(EVENT_STINGER_SPRAY, urand(20000, 30000)); + events.ScheduleEvent(EVENT_POISON_STINGER, 5000); + events.ScheduleEvent(EVENT_SUMMON_SWARMER, 5000); + events.ScheduleEvent(EVENT_SWARMER_ATTACK, 60000); + events.ScheduleEvent(EVENT_PARALYZE, 15000); + me->SetCanFly(true); + me->SetDisableGravity(true); + me->GetMotionMaster()->MovePoint(POINT_AIR, AyamissAirPos); } - void UpdateAI(uint32 const diff) + void UpdateAI(uint32 diff) { if (!UpdateVictim()) return; - //If he is 70% start phase 2 - if (phase == 1 && !HealthAbovePct(70) && !me->IsNonMeleeSpellCasted(false)) + events.Update(diff); + + if (_phase == PHASE_AIR && me->GetHealthPct() < 70.0f) + { + _phase = PHASE_GROUND; + SetCombatMovement(true); + me->SetCanFly(false); + Position VictimPos; + me->getVictim()->GetPosition(&VictimPos); + me->GetMotionMaster()->MovePoint(POINT_GROUND, VictimPos); + DoResetThreat(); + events.ScheduleEvent(EVENT_LASH, urand(5000, 8000)); + events.ScheduleEvent(EVENT_TRASH, urand(3000, 6000)); + events.CancelEvent(EVENT_POISON_STINGER); + } + else { - phase=2; + DoMeleeAttackIfReady(); } - //STINGERSPRAY_Timer (only in phase2) - if (phase == 2 && STINGERSPRAY_Timer <= diff) + if (!_enraged && me->GetHealthPct() < 20.0f) { - DoCast(me->getVictim(), SPELL_STINGERSPRAY); - STINGERSPRAY_Timer = 30000; - } else STINGERSPRAY_Timer -= diff; + DoCast(me, SPELL_FRENZY); + Talk(EMOTE_FRENZY); + _enraged = true; + } - //POISONSTINGER_Timer (only in phase1) - if (phase == 1 && POISONSTINGER_Timer <= diff) + while (uint32 eventId = events.ExecuteEvent()) { - DoCast(me->getVictim(), SPELL_POISONSTINGER); - POISONSTINGER_Timer = 30000; - } else POISONSTINGER_Timer -= diff; + switch (eventId) + { + case EVENT_STINGER_SPRAY: + DoCast(me, SPELL_STINGER_SPRAY); + events.ScheduleEvent(EVENT_STINGER_SPRAY, urand(15000, 20000)); + break; + case EVENT_POISON_STINGER: + DoCastVictim(SPELL_POISON_STINGER); + events.ScheduleEvent(EVENT_POISON_STINGER, urand(2000, 3000)); + break; + case EVENT_PARALYZE: + if (Unit* target = SelectTarget(SELECT_TARGET_RANDOM, 0, 0, true)) + { + DoCast(target, SPELL_PARALYZE); + instance->SetData64(DATA_PARALYZED, target->GetGUID()); + uint8 Index = urand(0, 1); + me->SummonCreature(NPC_LARVA, LarvaPos[Index], TEMPSUMMON_TIMED_OR_CORPSE_DESPAWN, 30000); + } + events.ScheduleEvent(EVENT_PARALYZE, 15000); + break; + case EVENT_SWARMER_ATTACK: + for (std::list<uint64>::iterator i = _swarmers.begin(); i != _swarmers.end(); ++i) + if (Creature* swarmer = me->GetMap()->GetCreature(*i)) + if (Unit* target = SelectTarget(SELECT_TARGET_RANDOM)) + swarmer->AI()->AttackStart(target); + + _swarmers.clear(); + events.ScheduleEvent(EVENT_SWARMER_ATTACK, 60000); + break; + case EVENT_SUMMON_SWARMER: + Position Pos; + me->GetRandomPoint(SwarmerPos, 80.0f, Pos); + me->SummonCreature(NPC_SWARMER, Pos); + events.ScheduleEvent(EVENT_SUMMON_SWARMER, 5000); + break; + case EVENT_TRASH: + DoCastVictim(SPELL_TRASH); + events.ScheduleEvent(EVENT_TRASH, urand(5000, 7000)); + break; + case EVENT_LASH: + DoCastVictim(SPELL_LASH); + events.ScheduleEvent(EVENT_LASH, urand(8000, 15000)); + break; + } + } + } + private: + std::list<uint64> _swarmers; + uint8 _phase; + bool _enraged; + }; + + CreatureAI* GetAI(Creature* creature) const + { + return new boss_ayamissAI(creature); + } +}; + +class npc_hive_zara_larva : public CreatureScript +{ + public: + npc_hive_zara_larva() : CreatureScript("npc_hive_zara_larva") { } + + struct npc_hive_zara_larvaAI : public ScriptedAI + { + npc_hive_zara_larvaAI(Creature* creature) : ScriptedAI(creature) + { + _instance = me->GetInstanceScript(); + } + + void MovementInform(uint32 type, uint32 id) + { + if (type == POINT_MOTION_TYPE) + if (id == POINT_PARALYZE) + if (Player* target = ObjectAccessor::GetPlayer(*me, _instance->GetData64(DATA_PARALYZED))) + DoCast(target, SPELL_FEED); // Omnomnom + } + + void MoveInLineOfSight(Unit* who) + { + if (_instance->GetBossState(DATA_AYAMISS) == IN_PROGRESS) + return; + + ScriptedAI::MoveInLineOfSight(who); + } + + void AttackStart(Unit* victim) + { + if (_instance->GetBossState(DATA_AYAMISS) == IN_PROGRESS) + return; + + ScriptedAI::AttackStart(victim); + } + + void UpdateAI(uint32 diff) + { + if (_instance->GetBossState(DATA_AYAMISS) == IN_PROGRESS) + return; - DoMeleeAttackIfReady(); + ScriptedAI::UpdateAI(diff); } + private: + InstanceScript* _instance; }; CreatureAI* GetAI(Creature* creature) const { - return new boss_ayamissAI (creature); + return new npc_hive_zara_larvaAI(creature); } }; void AddSC_boss_ayamiss() { new boss_ayamiss(); + new npc_hive_zara_larva(); } diff --git a/src/server/scripts/Kalimdor/RuinsOfAhnQiraj/boss_buru.cpp b/src/server/scripts/Kalimdor/RuinsOfAhnQiraj/boss_buru.cpp index e26cba9cb6e..0ad077aaa4e 100644 --- a/src/server/scripts/Kalimdor/RuinsOfAhnQiraj/boss_buru.cpp +++ b/src/server/scripts/Kalimdor/RuinsOfAhnQiraj/boss_buru.cpp @@ -70,11 +70,11 @@ class boss_buru : public CreatureScript boss_buruAI(Creature* creature) : BossAI(creature, DATA_BURU) { } - + void EnterEvadeMode() { BossAI::EnterEvadeMode(); - + for (std::list<uint64>::iterator i = Eggs.begin(); i != Eggs.end(); ++i) if (Creature* egg = me->GetMap()->GetCreature(*Eggs.begin())) egg->Respawn(); @@ -95,13 +95,13 @@ class boss_buru : public CreatureScript _phase = PHASE_EGG; } - void DoAction(int32 const action) + void DoAction(int32 action) { if (action == ACTION_EXPLODE) if (_phase == PHASE_EGG) me->DealDamage(me, 45000); } - + void KilledUnit(Unit* victim) { if (victim->GetTypeId() == TYPEID_PLAYER) @@ -112,12 +112,12 @@ class boss_buru : public CreatureScript { if (_phase != PHASE_EGG) return; - + me->RemoveAurasDueToSpell(SPELL_FULL_SPEED); me->RemoveAurasDueToSpell(SPELL_GATHERING_SPEED); events.ScheduleEvent(EVENT_GATHERING_SPEED, 9000); events.ScheduleEvent(EVENT_FULL_SPEED, 60000); - + if (Unit* victim = SelectTarget(SELECT_TARGET_RANDOM, 0, 0.0f, true)) { DoResetThreat(); @@ -125,21 +125,21 @@ class boss_buru : public CreatureScript Talk(EMOTE_TARGET, victim->GetGUID()); } } - + void ManageRespawn(uint64 EggGUID) { ChaseNewVictim(); Eggs.push_back(EggGUID); events.ScheduleEvent(EVENT_RESPAWN_EGG, 100000); } - - void UpdateAI(uint32 const diff) + + void UpdateAI(uint32 diff) { if (!UpdateVictim()) return; events.Update(diff); - + while (uint32 eventId = events.ExecuteEvent()) { switch (eventId) @@ -170,7 +170,7 @@ class boss_buru : public CreatureScript break; } } - + if (me->GetHealthPct() < 20.0f && _phase == PHASE_EGG) { DoCast(me, SPELL_BURU_TRANSFORM); // Enrage @@ -178,7 +178,7 @@ class boss_buru : public CreatureScript me->RemoveAurasDueToSpell(SPELL_THORNS); _phase = PHASE_TRANSFORM; } - + DoMeleeAttackIfReady(); } private: @@ -197,20 +197,21 @@ class npc_buru_egg : public CreatureScript public: npc_buru_egg() : CreatureScript("npc_buru_egg") { } - struct npc_buru_eggAI : public Scripted_NoMovementAI + struct npc_buru_eggAI : public ScriptedAI { - npc_buru_eggAI(Creature* creature) : Scripted_NoMovementAI(creature) + npc_buru_eggAI(Creature* creature) : ScriptedAI(creature) { _instance = me->GetInstanceScript(); + SetCombatMovement(false); } - + void EnterCombat(Unit* attacker) { if (Creature* buru = me->GetMap()->GetCreature(_instance->GetData64(DATA_BURU))) if (!buru->isInCombat()) buru->AI()->AttackStart(attacker); } - + void JustSummoned(Creature* who) { if (who->GetEntry() == NPC_HATCHLING) @@ -218,7 +219,7 @@ class npc_buru_egg : public CreatureScript if (Unit* target = buru->AI()->SelectTarget(SELECT_TARGET_RANDOM)) who->AI()->AttackStart(target); } - + void JustDied(Unit* /*killer*/) { DoCastAOE(SPELL_EXPLODE, true); @@ -247,13 +248,13 @@ class spell_egg_explosion : public SpellScriptLoader class spell_egg_explosion_SpellScript : public SpellScript { PrepareSpellScript(spell_egg_explosion_SpellScript); - + void HandleAfterCast() { if (Creature* buru = GetCaster()->FindNearestCreature(NPC_BURU, 5.f)) buru->AI()->DoAction(ACTION_EXPLODE); } - + void HandleDummyHitTarget(SpellEffIndex /*effIndex*/) { if (Unit* target = GetHitUnit()) diff --git a/src/server/scripts/Kalimdor/RuinsOfAhnQiraj/boss_kurinnaxx.cpp b/src/server/scripts/Kalimdor/RuinsOfAhnQiraj/boss_kurinnaxx.cpp index ddb9017f3dd..033980d746b 100644 --- a/src/server/scripts/Kalimdor/RuinsOfAhnQiraj/boss_kurinnaxx.cpp +++ b/src/server/scripts/Kalimdor/RuinsOfAhnQiraj/boss_kurinnaxx.cpp @@ -81,7 +81,7 @@ class boss_kurinnaxx : public CreatureScript sCreatureTextMgr->SendChat(Ossirian, SAY_KURINAXX_DEATH, 0, CHAT_MSG_ADDON, LANG_ADDON, TEXT_RANGE_ZONE); } - void UpdateAI(const uint32 diff) + void UpdateAI(uint32 diff) { if (!UpdateVictim()) return; diff --git a/src/server/scripts/Kalimdor/RuinsOfAhnQiraj/boss_moam.cpp b/src/server/scripts/Kalimdor/RuinsOfAhnQiraj/boss_moam.cpp index 70db1213394..dd52872e1da 100644 --- a/src/server/scripts/Kalimdor/RuinsOfAhnQiraj/boss_moam.cpp +++ b/src/server/scripts/Kalimdor/RuinsOfAhnQiraj/boss_moam.cpp @@ -80,7 +80,7 @@ class boss_moam : public CreatureScript } } - void DoAction(int32 const action) + void DoAction(int32 action) { switch (action) { @@ -105,7 +105,7 @@ class boss_moam : public CreatureScript } } - void UpdateAI(uint32 const diff) + void UpdateAI(uint32 diff) { if (!UpdateVictim()) return; diff --git a/src/server/scripts/Kalimdor/RuinsOfAhnQiraj/boss_ossirian.cpp b/src/server/scripts/Kalimdor/RuinsOfAhnQiraj/boss_ossirian.cpp index fcb6364244e..bd010849045 100644 --- a/src/server/scripts/Kalimdor/RuinsOfAhnQiraj/boss_ossirian.cpp +++ b/src/server/scripts/Kalimdor/RuinsOfAhnQiraj/boss_ossirian.cpp @@ -74,7 +74,7 @@ Position CrystalCoordinates[NUM_CRYSTALS] = }; float RoomRadius = 165.0f; -uint8 const NUM_TORNADOS = 5; // TODO: This number is completly random! +uint8 const NUM_TORNADOS = 5; /// @todo This number is completly random! uint8 const NUM_WEAKNESS = 5; uint32 const SpellWeakness[NUM_WEAKNESS] = { 25177, 25178, 25180, 25181, 25183 }; Position const RoomCenter = { -9343.041992f, 1923.278198f, 85.555984f, 0.0 }; @@ -89,7 +89,6 @@ class boss_ossirian : public CreatureScript boss_ossirianAI(Creature* creature) : BossAI(creature, DATA_OSSIRIAN) { SaidIntro = false; - Reset(); } uint64 TriggerGUID; @@ -118,16 +117,12 @@ class boss_ossirian : public CreatureScript } } - void DoAction(const int32 action) + void DoAction(int32 action) { if (action == ACTION_TRIGGER_WEAKNESS) - { if (Creature* Trigger = me->GetMap()->GetCreature(TriggerGUID)) - { if (!Trigger->HasUnitState(UNIT_STATE_CASTING)) Trigger->CastSpell(Trigger, SpellWeakness[urand(0, 4)], false); - } - } } void EnterCombat(Unit* /*who*/) @@ -172,7 +167,7 @@ class boss_ossirian : public CreatureScript { Cleanup(); summons.DespawnAll(); - ScriptedAI::EnterEvadeMode(); + BossAI::EnterEvadeMode(); } void JustDied(Unit* /*killer*/) @@ -207,16 +202,17 @@ class boss_ossirian : public CreatureScript } } - void MoveInLineOfSight(Unit* /*who*/) + void MoveInLineOfSight(Unit* who) { if (!SaidIntro) { Talk(SAY_INTRO); SaidIntro = true; } + BossAI::MoveInLineOfSight(who); } - void UpdateAI(uint32 const diff) + void UpdateAI(uint32 diff) { if (!UpdateVictim()) return; diff --git a/src/server/scripts/Kalimdor/RuinsOfAhnQiraj/boss_rajaxx.cpp b/src/server/scripts/Kalimdor/RuinsOfAhnQiraj/boss_rajaxx.cpp index dae447e43d2..a7151ec7c05 100644 --- a/src/server/scripts/Kalimdor/RuinsOfAhnQiraj/boss_rajaxx.cpp +++ b/src/server/scripts/Kalimdor/RuinsOfAhnQiraj/boss_rajaxx.cpp @@ -86,7 +86,7 @@ class boss_rajaxx : public CreatureScript _EnterCombat(); } - void UpdateAI(const uint32 diff) + void UpdateAI(uint32 diff) { if (!UpdateVictim()) return; diff --git a/src/server/scripts/Kalimdor/RuinsOfAhnQiraj/instance_ruins_of_ahnqiraj.cpp b/src/server/scripts/Kalimdor/RuinsOfAhnQiraj/instance_ruins_of_ahnqiraj.cpp index 6dbeaed9e5d..658528f1fb4 100644 --- a/src/server/scripts/Kalimdor/RuinsOfAhnQiraj/instance_ruins_of_ahnqiraj.cpp +++ b/src/server/scripts/Kalimdor/RuinsOfAhnQiraj/instance_ruins_of_ahnqiraj.cpp @@ -36,6 +36,7 @@ class instance_ruins_of_ahnqiraj : public InstanceMapScript _buruGUID = 0; _ayamissGUID = 0; _ossirianGUID = 0; + _paralyzedGUID = 0; } void OnCreatureCreate(Creature* creature) @@ -71,6 +72,12 @@ class instance_ruins_of_ahnqiraj : public InstanceMapScript return true; } + void SetData64(uint32 type, uint64 data) + { + if (type == DATA_PARALYZED) + _paralyzedGUID = data; + } + uint64 GetData64(uint32 type) const { switch (type) @@ -87,6 +94,8 @@ class instance_ruins_of_ahnqiraj : public InstanceMapScript return _ayamissGUID; case DATA_OSSIRIAN: return _ossirianGUID; + case DATA_PARALYZED: + return _paralyzedGUID; } return 0; @@ -142,6 +151,7 @@ class instance_ruins_of_ahnqiraj : public InstanceMapScript uint64 _buruGUID; uint64 _ayamissGUID; uint64 _ossirianGUID; + uint64 _paralyzedGUID; }; InstanceScript* GetInstanceScript(InstanceMap* map) const diff --git a/src/server/scripts/Kalimdor/RuinsOfAhnQiraj/ruins_of_ahnqiraj.h b/src/server/scripts/Kalimdor/RuinsOfAhnQiraj/ruins_of_ahnqiraj.h index 6ece21f627b..419aaf1c303 100644 --- a/src/server/scripts/Kalimdor/RuinsOfAhnQiraj/ruins_of_ahnqiraj.h +++ b/src/server/scripts/Kalimdor/RuinsOfAhnQiraj/ruins_of_ahnqiraj.h @@ -26,7 +26,9 @@ enum DataTypes DATA_BURU = 3, DATA_AYAMISS = 4, DATA_OSSIRIAN = 5, - NUM_ENCOUNTER = 6 + NUM_ENCOUNTER = 6, + + DATA_PARALYZED = 7 }; enum Creatures @@ -42,12 +44,15 @@ enum Creatures NPC_HIVEZARA_LARVA = 15555, NPC_SAND_VORTEX = 15428, NPC_OSSIRIAN_TRIGGER = 15590, - NPC_HATCHLING = 15521 + NPC_HATCHLING = 15521, + NPC_LARVA = 15555, + NPC_SWARMER = 15546, + NPC_HORNET = 15934 }; enum GameObjects { - GO_OSSIRIAN_CRYSTAL = 180619, + GO_OSSIRIAN_CRYSTAL = 180619 }; #endif diff --git a/src/server/scripts/Kalimdor/TempleOfAhnQiraj/boss_bug_trio.cpp b/src/server/scripts/Kalimdor/TempleOfAhnQiraj/boss_bug_trio.cpp index 2a9ea4ba4fc..becbd126d9b 100644 --- a/src/server/scripts/Kalimdor/TempleOfAhnQiraj/boss_bug_trio.cpp +++ b/src/server/scripts/Kalimdor/TempleOfAhnQiraj/boss_bug_trio.cpp @@ -89,7 +89,7 @@ public: instance->SetData(DATA_BUG_TRIO_DEATH, 1); } } - void UpdateAI(const uint32 diff) + void UpdateAI(uint32 diff) { //Return since we have no target if (!UpdateVictim()) @@ -185,7 +185,7 @@ public: { } - void UpdateAI(const uint32 diff) + void UpdateAI(uint32 diff) { //Return since we have no target if (!UpdateVictim()) @@ -274,10 +274,11 @@ public: for (uint8 i = 0; i < 10; ++i) { - Unit* target = SelectTarget(SELECT_TARGET_RANDOM, 0); - Creature* Summoned = me->SummonCreature(15621, me->GetPositionX(), me->GetPositionY(), me->GetPositionZ(), 0, TEMPSUMMON_TIMED_OR_CORPSE_DESPAWN, 90000); - if (Summoned && target) - Summoned->AI()->AttackStart(target); + if (Unit* target = SelectTarget(SELECT_TARGET_RANDOM, 0)) + { + if (Creature* Summoned = me->SummonCreature(15621, me->GetPositionX(), me->GetPositionY(), me->GetPositionZ(), 0, TEMPSUMMON_TIMED_OR_CORPSE_DESPAWN, 90000)) + Summoned->AI()->AttackStart(target); + } } } @@ -285,7 +286,7 @@ public: { } - void UpdateAI(const uint32 diff) + void UpdateAI(uint32 diff) { //Return since we have no target if (!UpdateVictim()) diff --git a/src/server/scripts/Kalimdor/TempleOfAhnQiraj/boss_cthun.cpp b/src/server/scripts/Kalimdor/TempleOfAhnQiraj/boss_cthun.cpp index 3da1fc1dc5c..e6460c00ab6 100644 --- a/src/server/scripts/Kalimdor/TempleOfAhnQiraj/boss_cthun.cpp +++ b/src/server/scripts/Kalimdor/TempleOfAhnQiraj/boss_cthun.cpp @@ -156,13 +156,15 @@ public: return new eye_of_cthunAI (creature); } - struct eye_of_cthunAI : public Scripted_NoMovementAI + struct eye_of_cthunAI : public ScriptedAI { - eye_of_cthunAI(Creature* creature) : Scripted_NoMovementAI(creature) + eye_of_cthunAI(Creature* creature) : ScriptedAI(creature) { instance = creature->GetInstanceScript(); if (!instance) sLog->outError(LOG_FILTER_TSCR, "No Instance eye_of_cthunAI"); + + SetCombatMovement(false); } InstanceScript* instance; @@ -228,7 +230,7 @@ public: Spawned->AI()->AttackStart(target); } - void UpdateAI(const uint32 diff) + void UpdateAI(uint32 diff) { //Check if we have a target if (!UpdateVictim()) @@ -460,9 +462,9 @@ public: return new cthunAI (creature); } - struct cthunAI : public Scripted_NoMovementAI + struct cthunAI : public ScriptedAI { - cthunAI(Creature* creature) : Scripted_NoMovementAI(creature) + cthunAI(Creature* creature) : ScriptedAI(creature) { SetCombatMovement(false); @@ -579,7 +581,7 @@ public: return (*j); } - void UpdateAI(const uint32 diff) + void UpdateAI(uint32 diff) { //Check if we have a target if (!UpdateVictim()) @@ -893,7 +895,7 @@ public: } } - void DoAction(const int32 param) + void DoAction(int32 param) { switch (param) { @@ -916,15 +918,17 @@ public: return new eye_tentacleAI (creature); } - struct eye_tentacleAI : public Scripted_NoMovementAI + struct eye_tentacleAI : public ScriptedAI { - eye_tentacleAI(Creature* creature) : Scripted_NoMovementAI(creature) + eye_tentacleAI(Creature* creature) : ScriptedAI(creature) { if (Creature* pPortal = me->SummonCreature(MOB_SMALL_PORTAL, *me, TEMPSUMMON_CORPSE_DESPAWN)) { pPortal->SetReactState(REACT_PASSIVE); Portal = pPortal->GetGUID(); } + + SetCombatMovement(false); } uint32 MindflayTimer; @@ -951,7 +955,7 @@ public: DoZoneInCombat(); } - void UpdateAI(const uint32 diff) + void UpdateAI(uint32 diff) { //Check if we have a target if (!UpdateVictim()) @@ -989,9 +993,9 @@ public: return new claw_tentacleAI (creature); } - struct claw_tentacleAI : public Scripted_NoMovementAI + struct claw_tentacleAI : public ScriptedAI { - claw_tentacleAI(Creature* creature) : Scripted_NoMovementAI(creature) + claw_tentacleAI(Creature* creature) : ScriptedAI(creature) { SetCombatMovement(false); @@ -1026,7 +1030,7 @@ public: DoZoneInCombat(); } - void UpdateAI(const uint32 diff) + void UpdateAI(uint32 diff) { //Check if we have a target if (!UpdateVictim()) @@ -1099,9 +1103,9 @@ public: return new giant_claw_tentacleAI (creature); } - struct giant_claw_tentacleAI : public Scripted_NoMovementAI + struct giant_claw_tentacleAI : public ScriptedAI { - giant_claw_tentacleAI(Creature* creature) : Scripted_NoMovementAI(creature) + giant_claw_tentacleAI(Creature* creature) : ScriptedAI(creature) { SetCombatMovement(false); @@ -1138,7 +1142,7 @@ public: DoZoneInCombat(); } - void UpdateAI(const uint32 diff) + void UpdateAI(uint32 diff) { //Check if we have a target if (!UpdateVictim()) @@ -1218,9 +1222,9 @@ public: return new giant_eye_tentacleAI (creature); } - struct giant_eye_tentacleAI : public Scripted_NoMovementAI + struct giant_eye_tentacleAI : public ScriptedAI { - giant_eye_tentacleAI(Creature* creature) : Scripted_NoMovementAI(creature) + giant_eye_tentacleAI(Creature* creature) : ScriptedAI(creature) { SetCombatMovement(false); @@ -1251,7 +1255,7 @@ public: DoZoneInCombat(); } - void UpdateAI(const uint32 diff) + void UpdateAI(uint32 diff) { //Check if we have a target if (!UpdateVictim()) @@ -1282,9 +1286,9 @@ public: return new flesh_tentacleAI (creature); } - struct flesh_tentacleAI : public Scripted_NoMovementAI + struct flesh_tentacleAI : public ScriptedAI { - flesh_tentacleAI(Creature* creature) : Scripted_NoMovementAI(creature) + flesh_tentacleAI(Creature* creature) : ScriptedAI(creature) { SetCombatMovement(false); } diff --git a/src/server/scripts/Kalimdor/TempleOfAhnQiraj/boss_fankriss.cpp b/src/server/scripts/Kalimdor/TempleOfAhnQiraj/boss_fankriss.cpp index 80fdc111911..de941ec266f 100644 --- a/src/server/scripts/Kalimdor/TempleOfAhnQiraj/boss_fankriss.cpp +++ b/src/server/scripts/Kalimdor/TempleOfAhnQiraj/boss_fankriss.cpp @@ -97,7 +97,7 @@ public: { } - void UpdateAI(const uint32 diff) + void UpdateAI(uint32 diff) { //Return since we have no target if (!UpdateVictim()) @@ -137,9 +137,7 @@ public: { if (SpawnHatchlings_Timer <= diff) { - Unit* target = NULL; - target = SelectTarget(SELECT_TARGET_RANDOM, 0); - if (target && target->GetTypeId() == TYPEID_PLAYER) + if (Unit* target = SelectTarget(SELECT_TARGET_RANDOM, 0, 0.0f, true)) { DoCast(target, SPELL_ROOT); diff --git a/src/server/scripts/Kalimdor/TempleOfAhnQiraj/boss_huhuran.cpp b/src/server/scripts/Kalimdor/TempleOfAhnQiraj/boss_huhuran.cpp index 5493e9d76b0..f8cf0917c37 100644 --- a/src/server/scripts/Kalimdor/TempleOfAhnQiraj/boss_huhuran.cpp +++ b/src/server/scripts/Kalimdor/TempleOfAhnQiraj/boss_huhuran.cpp @@ -80,7 +80,7 @@ public: { } - void UpdateAI(const uint32 diff) + void UpdateAI(uint32 diff) { //Return since we have no target if (!UpdateVictim()) diff --git a/src/server/scripts/Kalimdor/TempleOfAhnQiraj/boss_ouro.cpp b/src/server/scripts/Kalimdor/TempleOfAhnQiraj/boss_ouro.cpp index 53242d4cdc6..9b095b0100a 100644 --- a/src/server/scripts/Kalimdor/TempleOfAhnQiraj/boss_ouro.cpp +++ b/src/server/scripts/Kalimdor/TempleOfAhnQiraj/boss_ouro.cpp @@ -78,7 +78,7 @@ public: DoCast(me->getVictim(), SPELL_BIRTH); } - void UpdateAI(const uint32 diff) + void UpdateAI(uint32 diff) { //Return since we have no target if (!UpdateVictim()) diff --git a/src/server/scripts/Kalimdor/TempleOfAhnQiraj/boss_sartura.cpp b/src/server/scripts/Kalimdor/TempleOfAhnQiraj/boss_sartura.cpp index 3915a7655c5..d4bb5416a4e 100644 --- a/src/server/scripts/Kalimdor/TempleOfAhnQiraj/boss_sartura.cpp +++ b/src/server/scripts/Kalimdor/TempleOfAhnQiraj/boss_sartura.cpp @@ -98,7 +98,7 @@ public: Talk(SAY_SLAY); } - void UpdateAI(const uint32 diff) + void UpdateAI(uint32 diff) { //Return since we have no target if (!UpdateVictim()) @@ -225,7 +225,7 @@ public: { } - void UpdateAI(const uint32 diff) + void UpdateAI(uint32 diff) { //Return since we have no target if (!UpdateVictim()) diff --git a/src/server/scripts/Kalimdor/TempleOfAhnQiraj/boss_skeram.cpp b/src/server/scripts/Kalimdor/TempleOfAhnQiraj/boss_skeram.cpp index 1186459218c..79bc0c5accf 100644 --- a/src/server/scripts/Kalimdor/TempleOfAhnQiraj/boss_skeram.cpp +++ b/src/server/scripts/Kalimdor/TempleOfAhnQiraj/boss_skeram.cpp @@ -68,7 +68,7 @@ class boss_skeram : public CreatureScript { Talk(SAY_SLAY); } - + void EnterEvadeMode() { ScriptedAI::EnterEvadeMode(); @@ -93,10 +93,10 @@ class boss_skeram : public CreatureScript rand = urand(0, 2); creature->CastSpell(creature, BlinkSpells[rand]); _flag |= (1 << rand); - + if (_flag & (1 << 7)) _flag = 0; - + if (Unit* Target = SelectTarget(SELECT_TARGET_RANDOM)) creature->AI()->AttackStart(Target); @@ -134,7 +134,7 @@ class boss_skeram : public CreatureScript Talk(SAY_AGGRO); } - void UpdateAI(uint32 const diff) + void UpdateAI(uint32 diff) { if (!UpdateVictim()) return; @@ -150,7 +150,7 @@ class boss_skeram : public CreatureScript events.ScheduleEvent(EVENT_ARCANE_EXPLOSION, urand(8000, 18000)); break; case EVENT_FULLFILMENT: - // TODO: For some weird reason boss does not cast this + /// @todo For some weird reason boss does not cast this // Spell actually works, tested in duel DoCast(SelectTarget(SELECT_TARGET_RANDOM, 0, 0.0f, true), SPELL_TRUE_FULFILLMENT, true); events.ScheduleEvent(EVENT_FULLFILMENT, urand(20000, 30000)); @@ -183,12 +183,12 @@ class boss_skeram : public CreatureScript DoMeleeAttackIfReady(); } } - + private: float _hpct; uint8 _flag; }; - + CreatureAI* GetAI(Creature* creature) const { return new boss_skeramAI(creature); diff --git a/src/server/scripts/Kalimdor/TempleOfAhnQiraj/boss_twinemperors.cpp b/src/server/scripts/Kalimdor/TempleOfAhnQiraj/boss_twinemperors.cpp index d623963e929..5f677eedcf1 100644 --- a/src/server/scripts/Kalimdor/TempleOfAhnQiraj/boss_twinemperors.cpp +++ b/src/server/scripts/Kalimdor/TempleOfAhnQiraj/boss_twinemperors.cpp @@ -151,7 +151,7 @@ struct boss_twinemperorsAI : public ScriptedAI Creature* pOtherBoss = GetOtherBoss(); if (pOtherBoss) { - // TODO: we should activate the other boss location so he can start attackning even if nobody + /// @todo we should activate the other boss location so he can start attackning even if nobody // is near I dont know how to do that ScriptedAI* otherAI = CAST_AI(ScriptedAI, pOtherBoss->AI()); if (!pOtherBoss->isInCombat()) @@ -429,7 +429,7 @@ public: target->SetFullHealth(); } - void UpdateAI(const uint32 diff) + void UpdateAI(uint32 diff) { //Return since we have no target if (!UpdateVictim()) @@ -518,7 +518,7 @@ public: target->SetFullHealth(); } - void UpdateAI(const uint32 diff) + void UpdateAI(uint32 diff) { //Return since we have no target if (!UpdateVictim()) diff --git a/src/server/scripts/Kalimdor/TempleOfAhnQiraj/boss_viscidus.cpp b/src/server/scripts/Kalimdor/TempleOfAhnQiraj/boss_viscidus.cpp index fcbe3a84d62..ba93c3c2640 100644 --- a/src/server/scripts/Kalimdor/TempleOfAhnQiraj/boss_viscidus.cpp +++ b/src/server/scripts/Kalimdor/TempleOfAhnQiraj/boss_viscidus.cpp @@ -81,8 +81,8 @@ enum MovePoints ROOM_CENTER = 1 }; -Position const ViscidusCoord = { -7992.36f, 908.19f, -52.62f, 1.68f }; // TODO: Visci isn't in room middle -float const RoomRadius = 40.0f; // TODO: Not sure if its correct +Position const ViscidusCoord = { -7992.36f, 908.19f, -52.62f, 1.68f }; /// @todo Visci isn't in room middle +float const RoomRadius = 40.0f; /// @todo Not sure if its correct class boss_viscidus : public CreatureScript { @@ -194,7 +194,7 @@ class boss_viscidus : public CreatureScript summons.DespawnAll(); } - void UpdateAI(uint32 const diff) + void UpdateAI(uint32 diff) { if (!UpdateVictim()) return; diff --git a/src/server/scripts/Kalimdor/WailingCaverns/wailing_caverns.cpp b/src/server/scripts/Kalimdor/WailingCaverns/wailing_caverns.cpp index 7189abcc4fa..a4a5e0d94be 100644 --- a/src/server/scripts/Kalimdor/WailingCaverns/wailing_caverns.cpp +++ b/src/server/scripts/Kalimdor/WailingCaverns/wailing_caverns.cpp @@ -208,7 +208,7 @@ public: summoned->AI()->AttackStart(me); } - void UpdateAI(const uint32 diff) + void UpdateAI(uint32 diff) { if (currentEvent != TYPE_NARALEX_PART3) npc_escortAI::UpdateAI(diff); diff --git a/src/server/scripts/Kalimdor/ZulFarrak/zulfarrak.cpp b/src/server/scripts/Kalimdor/ZulFarrak/zulfarrak.cpp index ee89c9b6cad..f3a74c620ae 100644 --- a/src/server/scripts/Kalimdor/ZulFarrak/zulfarrak.cpp +++ b/src/server/scripts/Kalimdor/ZulFarrak/zulfarrak.cpp @@ -124,7 +124,7 @@ public: me->setFaction(FACTION_FRIENDLY); } - void UpdateAI(const uint32 diff) + void UpdateAI(uint32 diff) { if (postGossipStep>0 && postGossipStep<4) { @@ -182,7 +182,7 @@ public: DoMeleeAttackIfReady(); } - void DoAction(const int32 /*param*/) + void DoAction(int32 /*param*/) { postGossipStep=1; Text_Timer = 0; @@ -331,7 +331,7 @@ public: instance->SetData(0, DONE);*/ } - void UpdateAI(const uint32 diff) + void UpdateAI(uint32 diff) { if (!UpdateVictim()) return; @@ -370,13 +370,13 @@ public: if (destroyingDoor) { instance->DoUseDoorOrButton(instance->GetData64(GO_END_DOOR)); - //TODO: leave the area... + /// @todo leave the area... me->DespawnOrUnsummon(); }; } } - void DoAction(const int32 /*param*/) + void DoAction(int32 /*param*/) { DestroyDoor(); } diff --git a/src/server/scripts/Kalimdor/boss_azuregos.cpp b/src/server/scripts/Kalimdor/boss_azuregos.cpp index 4f37cacac02..dd202247aaa 100644 --- a/src/server/scripts/Kalimdor/boss_azuregos.cpp +++ b/src/server/scripts/Kalimdor/boss_azuregos.cpp @@ -81,7 +81,7 @@ public: void EnterCombat(Unit* /*who*/) {} - void UpdateAI(const uint32 diff) + void UpdateAI(uint32 diff) { //Return since we have no target if (!UpdateVictim()) diff --git a/src/server/scripts/Kalimdor/zone_ashenvale.cpp b/src/server/scripts/Kalimdor/zone_ashenvale.cpp index 94c68a1d3ec..4d7ded57501 100644 --- a/src/server/scripts/Kalimdor/zone_ashenvale.cpp +++ b/src/server/scripts/Kalimdor/zone_ashenvale.cpp @@ -91,7 +91,7 @@ class npc_torek : public CreatureScript Talk(SAY_PREPARE, player->GetGUID()); break; case 19: - //TODO: verify location and creatures amount. + /// @todo verify location and creatures amount. me->SummonCreature(ENTRY_DURIEL, 1776.73f, -2049.06f, 109.83f, 1.54f, TEMPSUMMON_TIMED_DESPAWN_OUT_OF_COMBAT, 25000); me->SummonCreature(ENTRY_SILVERWING_SENTINEL, 1774.64f, -2049.41f, 109.83f, 1.40f, TEMPSUMMON_TIMED_DESPAWN_OUT_OF_COMBAT, 25000); me->SummonCreature(ENTRY_SILVERWING_WARRIOR, 1778.73f, -2049.50f, 109.83f, 1.67f, TEMPSUMMON_TIMED_DESPAWN_OUT_OF_COMBAT, 25000); @@ -124,7 +124,7 @@ class npc_torek : public CreatureScript summoned->AI()->AttackStart(me); } - void UpdateAI(const uint32 diff) + void UpdateAI(uint32 diff) { npc_escortAI::UpdateAI(diff); @@ -154,7 +154,7 @@ class npc_torek : public CreatureScript { if (quest->GetQuestId() == QUEST_TOREK_ASSULT) { - //TODO: find companions, make them follow Torek, at any time (possibly done by core/database in future?) + /// @todo find companions, make them follow Torek, at any time (possibly done by core/database in future?) creature->AI()->Talk(SAY_READY, player->GetGUID()); creature->setFaction(113); @@ -242,7 +242,7 @@ class npc_ruul_snowhoof : public CreatureScript summoned->AI()->AttackStart(me); } - void UpdateAI(const uint32 diff) + void UpdateAI(uint32 diff) { npc_escortAI::UpdateAI(diff); } @@ -411,7 +411,7 @@ class npc_muglash : public CreatureScript } } - void UpdateAI(const uint32 uiDiff) + void UpdateAI(uint32 uiDiff) { npc_escortAI::UpdateAI(uiDiff); diff --git a/src/server/scripts/Kalimdor/zone_azshara.cpp b/src/server/scripts/Kalimdor/zone_azshara.cpp index 44f7e1e8172..40af9e522ea 100644 --- a/src/server/scripts/Kalimdor/zone_azshara.cpp +++ b/src/server/scripts/Kalimdor/zone_azshara.cpp @@ -78,7 +78,7 @@ public: } } - void UpdateAI(const uint32 diff) + void UpdateAI(uint32 diff) { // we mustn't remove the Creature in the same round in which we cast the summon spell, otherwise there will be no summons if (spellhit && morphtimer >= 5000) @@ -99,7 +99,7 @@ public: if (!UpdateVictim()) return; - //TODO: add abilities for the different creatures + /// @todo add abilities for the different creatures DoMeleeAttackIfReady(); } }; @@ -332,7 +332,7 @@ public: Reached = false; } - void UpdateAI(const uint32 diff) + void UpdateAI(uint32 diff) { if (MustDie) { @@ -485,7 +485,7 @@ public: WeMustDieTimer = 1000; } - void UpdateAI(const uint32 diff) + void UpdateAI(uint32 diff) { if (WeMustDie) { diff --git a/src/server/scripts/Kalimdor/zone_azuremyst_isle.cpp b/src/server/scripts/Kalimdor/zone_azuremyst_isle.cpp index 4b03cd65cad..5b6993dfef0 100644 --- a/src/server/scripts/Kalimdor/zone_azuremyst_isle.cpp +++ b/src/server/scripts/Kalimdor/zone_azuremyst_isle.cpp @@ -39,6 +39,7 @@ EndContentData */ #include "ScriptedGossip.h" #include "Cell.h" #include "CellImpl.h" +#include "GridNotifiersImpl.h" #include "GridNotifiers.h" /*###### @@ -124,7 +125,7 @@ public: } } - void UpdateAI(const uint32 diff) + void UpdateAI(uint32 diff) { if (SayThanksTimer) { @@ -254,7 +255,7 @@ public: Talk(ATTACK_YELL, who->GetGUID()); } - void UpdateAI(const uint32 diff) + void UpdateAI(uint32 diff) { if (!me->isInCombat() && !IsTreeEvent) { @@ -321,7 +322,7 @@ public: void MoveInLineOfSight(Unit* /*who*/) {} - void UpdateAI(const uint32 /*diff*/) {} + void UpdateAI(uint32 /*diff*/) {} }; }; @@ -555,7 +556,7 @@ public: sLog->outError(LOG_FILTER_TSCR, "SD2 ERROR: FlagList is empty!"); } - void UpdateAI(const uint32 diff) + void UpdateAI(uint32 diff) { if (SayTimer <= diff) { @@ -626,7 +627,7 @@ public: me->SetReactState(REACT_PASSIVE); } - void UpdateAI(const uint32 diff) + void UpdateAI(uint32 diff) { if (!UpdateVictim()) return; @@ -712,7 +713,7 @@ class npc_stillpine_capitive : public CreatureScript _events.ScheduleEvent(EVENT_DESPAWN, 3500); } - void UpdateAI(uint32 const diff) + void UpdateAI(uint32 diff) { if (!_movementComplete) return; diff --git a/src/server/scripts/Kalimdor/zone_darkshore.cpp b/src/server/scripts/Kalimdor/zone_darkshore.cpp index 09f061148d3..c7115a9098b 100644 --- a/src/server/scripts/Kalimdor/zone_darkshore.cpp +++ b/src/server/scripts/Kalimdor/zone_darkshore.cpp @@ -57,7 +57,7 @@ enum Kerlonian FACTION_KER_ESCORTEE = 113 }; -//TODO: make concept similar as "ringo" -escort. Find a way to run the scripted attacks, _if_ player are choosing road. +/// @todo make concept similar as "ringo" -escort. Find a way to run the scripted attacks, _if_ player are choosing road. class npc_kerlonian : public CreatureScript { public: @@ -143,7 +143,7 @@ public: SetFollowPaused(false); } - void UpdateFollowerAI(const uint32 Diff) + void UpdateFollowerAI(uint32 Diff) { if (!UpdateVictim()) { diff --git a/src/server/scripts/Kalimdor/zone_desolace.cpp b/src/server/scripts/Kalimdor/zone_desolace.cpp index 8f55bb6102c..b21cb28e0d5 100644 --- a/src/server/scripts/Kalimdor/zone_desolace.cpp +++ b/src/server/scripts/Kalimdor/zone_desolace.cpp @@ -39,7 +39,6 @@ EndContentData */ enum DyingKodo { - // signed for 9999 SAY_SMEED_HOME = 0, QUEST_KODO = 5561, @@ -51,7 +50,7 @@ enum DyingKodo NPC_TAMED_KODO = 11627, SPELL_KODO_KOMBO_ITEM = 18153, - SPELL_KODO_KOMBO_PLAYER_BUFF = 18172, //spells here have unclear function, but using them at least for visual parts and checks + SPELL_KODO_KOMBO_PLAYER_BUFF = 18172, SPELL_KODO_KOMBO_DESPAWN_BUFF = 18377, SPELL_KODO_KOMBO_GOSSIP = 18362 @@ -66,111 +65,56 @@ public: { if (player->HasAura(SPELL_KODO_KOMBO_PLAYER_BUFF) && creature->HasAura(SPELL_KODO_KOMBO_DESPAWN_BUFF)) { - //the expected quest objective - player->TalkedToCreature(creature->GetEntry(), creature->GetGUID()); - + player->TalkedToCreature(creature->GetEntry(), 0); player->RemoveAurasDueToSpell(SPELL_KODO_KOMBO_PLAYER_BUFF); - creature->GetMotionMaster()->MoveIdle(); } player->SEND_GOSSIP_MENU(player->GetGossipTextId(creature), creature->GetGUID()); return true; } - bool EffectDummyCreature(Unit* pCaster, uint32 spellId, uint32 effIndex, Creature* creatureTarget) - { - //always check spellid and effectindex - if (spellId == SPELL_KODO_KOMBO_ITEM && effIndex == 0) - { - //no effect if player/creature already have aura from spells - if (pCaster->HasAura(SPELL_KODO_KOMBO_PLAYER_BUFF) || creatureTarget->HasAura(SPELL_KODO_KOMBO_DESPAWN_BUFF)) - return true; - - if (creatureTarget->GetEntry() == NPC_AGED_KODO || - creatureTarget->GetEntry() == NPC_DYING_KODO || - creatureTarget->GetEntry() == NPC_ANCIENT_KODO) - { - pCaster->CastSpell(pCaster, SPELL_KODO_KOMBO_PLAYER_BUFF, true); - - creatureTarget->UpdateEntry(NPC_TAMED_KODO); - creatureTarget->CastSpell(creatureTarget, SPELL_KODO_KOMBO_DESPAWN_BUFF, false); - - if (creatureTarget->GetMotionMaster()->GetCurrentMovementGeneratorType() == WAYPOINT_MOTION_TYPE) - creatureTarget->GetMotionMaster()->MoveIdle(); - - creatureTarget->GetMotionMaster()->MoveFollow(pCaster, PET_FOLLOW_DIST, creatureTarget->GetFollowAngle()); - } - - //always return true when we are handling this spell and effect - return true; - } - return false; - } - - CreatureAI* GetAI(Creature* creature) const - { - return new npc_aged_dying_ancient_kodoAI(creature); - } - struct npc_aged_dying_ancient_kodoAI : public ScriptedAI { - npc_aged_dying_ancient_kodoAI(Creature* creature) : ScriptedAI(creature) { Reset(); } - - uint32 DespawnTimer; + npc_aged_dying_ancient_kodoAI(Creature* creature) : ScriptedAI(creature) {} - void Reset() + void MoveInLineOfSight(Unit* who) { - DespawnTimer = 0; + if (who->GetEntry() == NPC_SMEED && me->IsWithinDistInMap(who, 10.0f) && !me->HasAura(SPELL_KODO_KOMBO_GOSSIP)) + { + me->GetMotionMaster()->Clear(); + DoCast(me, SPELL_KODO_KOMBO_GOSSIP, true); + if (Creature* smeed = who->ToCreature()) + smeed->AI()->Talk(SAY_SMEED_HOME); + } } - void MoveInLineOfSight(Unit* who) + void SpellHit(Unit* caster, SpellInfo const* spell) { - if (who->GetEntry() == NPC_SMEED) + if (spell->Id == SPELL_KODO_KOMBO_ITEM) { - if (me->HasFlag(UNIT_NPC_FLAGS, UNIT_NPC_FLAG_GOSSIP)) - return; - - if (me->IsWithinDistInMap(who, 10.0f)) + if (!(caster->HasAura(SPELL_KODO_KOMBO_PLAYER_BUFF) || me->HasAura(SPELL_KODO_KOMBO_DESPAWN_BUFF)) + && (me->GetEntry() == NPC_AGED_KODO || me->GetEntry() == NPC_DYING_KODO || me->GetEntry() == NPC_ANCIENT_KODO)) { - if (Creature* talker = who->ToCreature()) - talker->AI()->Talk(SAY_SMEED_HOME); + caster->CastSpell(caster, SPELL_KODO_KOMBO_PLAYER_BUFF, true); + DoCast(me, SPELL_KODO_KOMBO_DESPAWN_BUFF, true); - //spell have no implemented effect (dummy), so useful to notify spellHit - DoCast(me, SPELL_KODO_KOMBO_GOSSIP, true); + me->UpdateEntry(NPC_TAMED_KODO); + me->GetMotionMaster()->MoveFollow(caster, PET_FOLLOW_DIST, me->GetFollowAngle()); } } - } - - void SpellHit(Unit* /*pCaster*/, SpellInfo const* pSpell) - { - if (pSpell->Id == SPELL_KODO_KOMBO_GOSSIP) + else if (spell->Id == SPELL_KODO_KOMBO_GOSSIP) { me->SetFlag(UNIT_NPC_FLAGS, UNIT_NPC_FLAG_GOSSIP); - DespawnTimer = 60000; + me->DespawnOrUnsummon(60000); } } - - void UpdateAI(const uint32 diff) - { - //timer should always be == 0 unless we already updated entry of creature. Then not expect this updated to ever be in combat. - if (DespawnTimer && DespawnTimer <= diff) - { - if (!me->getVictim() && me->isAlive()) - { - Reset(); - me->setDeathState(JUST_DIED); - me->Respawn(); - return; - } - } else DespawnTimer -= diff; - - if (!UpdateVictim()) - return; - - DoMeleeAttackIfReady(); - } }; + CreatureAI* GetAI(Creature* creature) const + { + return new npc_aged_dying_ancient_kodoAI(creature); + } + }; /*###### @@ -261,7 +205,7 @@ public: return; } - void UpdateAI(const uint32 Diff) + void UpdateAI(uint32 Diff) { npc_escortAI::UpdateAI(Diff); if (!UpdateVictim()) diff --git a/src/server/scripts/Kalimdor/zone_durotar.cpp b/src/server/scripts/Kalimdor/zone_durotar.cpp index fa6b830c1ae..7bb59e9828b 100644 --- a/src/server/scripts/Kalimdor/zone_durotar.cpp +++ b/src/server/scripts/Kalimdor/zone_durotar.cpp @@ -84,7 +84,7 @@ public: } } - void UpdateAI(const uint32 Diff) + void UpdateAI(uint32 Diff) { if (work == true) me->HandleEmoteCommand(EMOTE_ONESHOT_WORK_CHOPWOOD); @@ -175,14 +175,15 @@ class npc_tiger_matriarch_credit : public CreatureScript public: npc_tiger_matriarch_credit() : CreatureScript("npc_tiger_matriarch_credit") { } - struct npc_tiger_matriarch_creditAI : public Scripted_NoMovementAI + struct npc_tiger_matriarch_creditAI : public ScriptedAI { - npc_tiger_matriarch_creditAI(Creature* creature) : Scripted_NoMovementAI(creature) + npc_tiger_matriarch_creditAI(Creature* creature) : ScriptedAI(creature) { + SetCombatMovement(false); events.ScheduleEvent(EVENT_CHECK_SUMMON_AURA, 2000); } - void UpdateAI(uint32 const diff) + void UpdateAI(uint32 diff) { events.Update(diff); @@ -294,7 +295,7 @@ class npc_tiger_matriarch : public CreatureScript } } - void UpdateAI(const uint32 diff) + void UpdateAI(uint32 diff) { if (!UpdateVictim()) return; @@ -341,7 +342,7 @@ class npc_tiger_matriarch : public CreatureScript }; // These models was found in sniff. -// TODO: generalize these models with race from dbc +/// @todo generalize these models with race from dbc uint32 const trollmodel[] = {11665, 11734, 11750, 12037, 12038, 12042, 12049, 12849, 13529, 14759, 15570, 15701, 15702, 1882, 1897, 1976, 2025, 27286, 2734, 2735, 4084, 4085, 4087, 4089, 4231, 4357, diff --git a/src/server/scripts/Kalimdor/zone_dustwallow_marsh.cpp b/src/server/scripts/Kalimdor/zone_dustwallow_marsh.cpp index 37941227c78..0e858c20d26 100644 --- a/src/server/scripts/Kalimdor/zone_dustwallow_marsh.cpp +++ b/src/server/scripts/Kalimdor/zone_dustwallow_marsh.cpp @@ -95,7 +95,7 @@ class mobs_risen_husk_spirit : public CreatureScript } } - void UpdateAI(uint32 const diff) + void UpdateAI(uint32 diff) { if (!UpdateVictim()) return; @@ -204,7 +204,7 @@ public: Step = 0; } - void UpdateAI(const uint32 Diff) + void UpdateAI(uint32 Diff) { if (!me->HasAura(SPELL_PROPAGANDIZED)) me->SetFlag(UNIT_NPC_FLAGS, UNIT_NPC_FLAG_GOSSIP); @@ -336,7 +336,7 @@ enum Hendel NPC_TERVOSH = 4967 }; -//TODO: develop this further, end event not created +/// @todo develop this further, end event not created class npc_private_hendel : public CreatureScript { public: @@ -458,7 +458,7 @@ public: Talk(SAY_ZELFRAX2); } - void UpdateAI(uint32 const /*Diff*/) + void UpdateAI(uint32 /*Diff*/) { if (!UpdateVictim()) return; @@ -583,7 +583,7 @@ public: } } - void UpdateAI(const uint32 uiDiff) + void UpdateAI(uint32 uiDiff) { npc_escortAI::UpdateAI(uiDiff); diff --git a/src/server/scripts/Kalimdor/zone_feralas.cpp b/src/server/scripts/Kalimdor/zone_feralas.cpp index b2326de86ab..2d5b383cefc 100644 --- a/src/server/scripts/Kalimdor/zone_feralas.cpp +++ b/src/server/scripts/Kalimdor/zone_feralas.cpp @@ -221,7 +221,10 @@ class spell_gordunni_trap : public SpellScriptLoader { if (Unit* caster = GetCaster()) if (GameObject* chest = caster->SummonGameObject(GO_GORDUNNI_DIRT_MOUND, caster->GetPositionX(), caster->GetPositionY(), caster->GetPositionZ(), 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0)) + { chest->SetSpellId(GetSpellInfo()->Id); + caster->RemoveGameObject(chest, false); + } } void Register() diff --git a/src/server/scripts/Kalimdor/zone_moonglade.cpp b/src/server/scripts/Kalimdor/zone_moonglade.cpp index e41ffae03e6..b6a0c1e9d1e 100644 --- a/src/server/scripts/Kalimdor/zone_moonglade.cpp +++ b/src/server/scripts/Kalimdor/zone_moonglade.cpp @@ -37,9 +37,10 @@ EndContentData */ #include "ScriptedGossip.h" #include "Player.h" #include "SpellInfo.h" +#include "GridNotifiers.h" +#include "GridNotifiersImpl.h" #include "Cell.h" #include "CellImpl.h" -#include "GridNotifiers.h" /*###### ## npc_bunthen_plainswind @@ -383,7 +384,7 @@ public: return; } - void UpdateAI(uint32 const diff) + void UpdateAI(uint32 diff) { npc_escortAI::UpdateAI(diff); @@ -630,7 +631,7 @@ public: } } - void UpdateAI(const uint32 diff) + void UpdateAI(uint32 diff) { if (!UpdateVictim()) return; @@ -677,7 +678,7 @@ public: events.ScheduleEvent(EVENT_DESPAWN, 5*MINUTE*IN_MILLISECONDS); } - void UpdateAI(const uint32 diff) + void UpdateAI(uint32 diff) { events.Update(diff); diff --git a/src/server/scripts/Kalimdor/zone_mulgore.cpp b/src/server/scripts/Kalimdor/zone_mulgore.cpp index aca55284b67..b81b8eb9eb7 100644 --- a/src/server/scripts/Kalimdor/zone_mulgore.cpp +++ b/src/server/scripts/Kalimdor/zone_mulgore.cpp @@ -147,7 +147,7 @@ public: IsMovingToLunch = false; } - void UpdateAI(const uint32 diff) + void UpdateAI(uint32 diff) { if (EventActive) { @@ -303,7 +303,7 @@ public: } } - void UpdateAI(const uint32 /*diff*/) + void UpdateAI(uint32 /*diff*/) { if (newWaypoint) { diff --git a/src/server/scripts/Kalimdor/zone_orgrimmar.cpp b/src/server/scripts/Kalimdor/zone_orgrimmar.cpp index 42ef9843a4e..bae229b1161 100644 --- a/src/server/scripts/Kalimdor/zone_orgrimmar.cpp +++ b/src/server/scripts/Kalimdor/zone_orgrimmar.cpp @@ -83,7 +83,7 @@ public: void EnterCombat(Unit* /*who*/) {} - void UpdateAI(const uint32 diff) + void UpdateAI(uint32 diff) { if (CanEmote) { @@ -149,7 +149,7 @@ enum ThrallWarchief #define GOSSIP_STW5 "I live only to serve, Warchief! My life is empty and meaningless without your guidance." #define GOSSIP_STW6 "Of course, Warchief!" -//TODO: verify abilities/timers +/// @todo verify abilities/timers class npc_thrall_warchief : public CreatureScript { public: @@ -224,7 +224,7 @@ public: void EnterCombat(Unit* /*who*/) {} - void UpdateAI(const uint32 diff) + void UpdateAI(uint32 diff) { if (!UpdateVictim()) return; diff --git a/src/server/scripts/Kalimdor/zone_silithus.cpp b/src/server/scripts/Kalimdor/zone_silithus.cpp index 58665224bdd..70e7f731fc4 100644 --- a/src/server/scripts/Kalimdor/zone_silithus.cpp +++ b/src/server/scripts/Kalimdor/zone_silithus.cpp @@ -544,7 +544,7 @@ public: switch (AnimationCount) { case 0: - Talk(ANACHRONOS_SAY_1,Fandral->GetGUID()); + Talk(ANACHRONOS_SAY_1, Fandral->GetGUID()); break; case 1: Fandral->SetTarget(me->GetGUID()); @@ -791,7 +791,7 @@ public: } ++AnimationCount; } - void UpdateAI(const uint32 diff) + void UpdateAI(uint32 diff) { if (AnimationTimer) { @@ -843,7 +843,7 @@ public: void EnterCombat(Unit* /*who*/) {} void JustDied(Unit* /*slayer*/); - void UpdateAI(const uint32 diff) + void UpdateAI(uint32 diff) { if (!Timers) { @@ -1045,7 +1045,7 @@ public: Announced = false; } - void UpdateAI(const uint32 diff) + void UpdateAI(uint32 diff) { if (!PlayerGUID || !EventStarted) return; diff --git a/src/server/scripts/Kalimdor/zone_tanaris.cpp b/src/server/scripts/Kalimdor/zone_tanaris.cpp index 0648e40416d..9d257790ab8 100644 --- a/src/server/scripts/Kalimdor/zone_tanaris.cpp +++ b/src/server/scripts/Kalimdor/zone_tanaris.cpp @@ -104,7 +104,7 @@ public: Talk(AGGRO_YELL_AQUE, who->GetGUID()); } - void UpdateAI(const uint32 diff) + void UpdateAI(uint32 diff) { if (isFriendly) { @@ -270,7 +270,7 @@ public: void EnterCombat(Unit* /*who*/) {} void Reset() {} - void UpdateAI(const uint32 diff) + void UpdateAI(uint32 diff) { npc_escortAI::UpdateAI(diff); } @@ -603,7 +603,7 @@ public: SetFollowComplete(); } - void UpdateFollowerAI(const uint32 Diff) + void UpdateFollowerAI(uint32 Diff) { if (!UpdateVictim()) { diff --git a/src/server/scripts/Kalimdor/zone_the_barrens.cpp b/src/server/scripts/Kalimdor/zone_the_barrens.cpp index 8f7ab09260b..ff52af97c11 100644 --- a/src/server/scripts/Kalimdor/zone_the_barrens.cpp +++ b/src/server/scripts/Kalimdor/zone_the_barrens.cpp @@ -146,7 +146,7 @@ public: Talk(SAY_GIL_FREEBOOTERS, player->GetGUID()); break; case 37: - Talk(SAY_GIL_ALMOST,player->GetGUID()); + Talk(SAY_GIL_ALMOST, player->GetGUID()); break; case 47: Talk(SAY_GIL_SWEET, player->GetGUID()); @@ -278,7 +278,7 @@ public: void EnterCombat(Unit* /*who*/) {} - void UpdateAI(const uint32 diff) + void UpdateAI(uint32 diff) { if (IsFriend) { @@ -397,7 +397,7 @@ public: void KilledUnit(Unit* /*victim*/) { } - void UpdateAI(const uint32 diff) + void UpdateAI(uint32 diff) { if (EventInProgress) { Player* pWarrior = NULL; diff --git a/src/server/scripts/Kalimdor/zone_thousand_needles.cpp b/src/server/scripts/Kalimdor/zone_thousand_needles.cpp index 9c47991a5d5..02e64421ecb 100644 --- a/src/server/scripts/Kalimdor/zone_thousand_needles.cpp +++ b/src/server/scripts/Kalimdor/zone_thousand_needles.cpp @@ -368,7 +368,7 @@ public: } } - void UpdateAI(const uint32 Diff) + void UpdateAI(uint32 Diff) { if (me->HasFlag(UNIT_NPC_FLAGS, UNIT_NPC_FLAG_GOSSIP)) { @@ -441,7 +441,7 @@ public: me->SetReactState(REACT_PASSIVE); } - void UpdateAI(const uint32 /*diff*/) + void UpdateAI(uint32 /*diff*/) { if (!UpdateVictim()) return; diff --git a/src/server/scripts/Kalimdor/zone_thunder_bluff.cpp b/src/server/scripts/Kalimdor/zone_thunder_bluff.cpp index 0d915dc7c44..c949a551118 100644 --- a/src/server/scripts/Kalimdor/zone_thunder_bluff.cpp +++ b/src/server/scripts/Kalimdor/zone_thunder_bluff.cpp @@ -42,7 +42,7 @@ enum CairneBloodhoof }; #define GOSSIP_HCB "I know this is rather silly but a young ward who is a bit shy would like your hoofprint." -//TODO: verify abilities/timers +/// @todo verify abilities/timers class npc_cairne_bloodhoof : public CreatureScript { public: @@ -98,15 +98,14 @@ public: void EnterCombat(Unit* /*who*/) {} - void UpdateAI(const uint32 diff) + void UpdateAI(uint32 diff) { if (!UpdateVictim()) return; if (BerserkerChargeTimer <= diff) { - Unit* target = SelectTarget(SELECT_TARGET_RANDOM, 0); - if (target) + if (Unit* target = SelectTarget(SELECT_TARGET_RANDOM, 0)) DoCast(target, SPELL_BERSERKER_CHARGE); BerserkerChargeTimer = 25000; } else BerserkerChargeTimer -= diff; diff --git a/src/server/scripts/Kalimdor/zone_ungoro_crater.cpp b/src/server/scripts/Kalimdor/zone_ungoro_crater.cpp index e72c82bee97..9c89ad6d53a 100644 --- a/src/server/scripts/Kalimdor/zone_ungoro_crater.cpp +++ b/src/server/scripts/Kalimdor/zone_ungoro_crater.cpp @@ -126,7 +126,7 @@ public: player->FailQuest(QUEST_CHASING_AME); } - void UpdateAI(const uint32 diff) + void UpdateAI(uint32 diff) { npc_escortAI::UpdateAI(diff); if (!UpdateVictim()) @@ -261,7 +261,7 @@ public: SetFollowPaused(false); } - void UpdateFollowerAI(const uint32 Diff) + void UpdateFollowerAI(uint32 Diff) { if (!UpdateVictim()) { diff --git a/src/server/scripts/Northrend/AzjolNerub/Ahnkahet/boss_amanitar.cpp b/src/server/scripts/Northrend/AzjolNerub/Ahnkahet/boss_amanitar.cpp index 02245c92efd..24335c0e469 100644 --- a/src/server/scripts/Northrend/AzjolNerub/Ahnkahet/boss_amanitar.cpp +++ b/src/server/scripts/Northrend/AzjolNerub/Ahnkahet/boss_amanitar.cpp @@ -89,11 +89,11 @@ public: { _EnterCombat(); - events.ScheduleEvent(EVENT_ROOT, urand(5,9)*IN_MILLISECONDS); - events.ScheduleEvent(EVENT_BASH, urand(10,14)*IN_MILLISECONDS); - events.ScheduleEvent(EVENT_BOLT, urand(15,20)*IN_MILLISECONDS); - events.ScheduleEvent(EVENT_MINI, urand(12,18)*IN_MILLISECONDS); - events.ScheduleEvent(EVENT_SPAWN, 5 *IN_MILLISECONDS); + events.ScheduleEvent(EVENT_ROOT, urand(5, 9) * IN_MILLISECONDS); + events.ScheduleEvent(EVENT_BASH, urand(10, 14) * IN_MILLISECONDS); + events.ScheduleEvent(EVENT_BOLT, urand(15, 20) * IN_MILLISECONDS); + events.ScheduleEvent(EVENT_MINI, urand(12, 18) * IN_MILLISECONDS); + events.ScheduleEvent(EVENT_SPAWN, 5 * IN_MILLISECONDS); me->SetInCombatWithZone(); if (instance) @@ -123,13 +123,13 @@ public: { u = 1 - u; trigger->DisappearAndDie(); - me->SummonCreature(u > 0 ? NPC_POISONOUS_MUSHROOM : NPC_HEALTHY_MUSHROOM, pos, TEMPSUMMON_TIMED_OR_CORPSE_DESPAWN, 60*IN_MILLISECONDS); + me->SummonCreature(u > 0 ? NPC_POISONOUS_MUSHROOM : NPC_HEALTHY_MUSHROOM, pos, TEMPSUMMON_TIMED_OR_CORPSE_DESPAWN, 60 * IN_MILLISECONDS); } } } } - void UpdateAI(const uint32 diff) + void UpdateAI(uint32 diff) { if (!UpdateVictim()) return; @@ -145,23 +145,23 @@ public: { case EVENT_SPAWN: SpawnAdds(); - events.ScheduleEvent(EVENT_SPAWN, 20*IN_MILLISECONDS); + events.ScheduleEvent(EVENT_SPAWN, 20 * IN_MILLISECONDS); break; case EVENT_MINI: DoCast(SPELL_MINI); - events.ScheduleEvent(EVENT_MINI, urand(25,30)*IN_MILLISECONDS); + events.ScheduleEvent(EVENT_MINI, urand(25, 30) * IN_MILLISECONDS); break; case EVENT_ROOT: - DoCast(SelectTarget(SELECT_TARGET_RANDOM,0, 100, true),SPELL_ENTANGLING_ROOTS,true); - events.ScheduleEvent(EVENT_ROOT, urand(10,15)*IN_MILLISECONDS); + DoCast(SelectTarget(SELECT_TARGET_RANDOM, 0, 100, true), SPELL_ENTANGLING_ROOTS, true); + events.ScheduleEvent(EVENT_ROOT, urand(10, 15) * IN_MILLISECONDS); break; case EVENT_BASH: DoCastVictim(SPELL_BASH); - events.ScheduleEvent(EVENT_BASH, urand(7,12)*IN_MILLISECONDS); + events.ScheduleEvent(EVENT_BASH, urand(7, 12) * IN_MILLISECONDS); break; case EVENT_BOLT: - DoCast(SelectTarget(SELECT_TARGET_RANDOM,0, 100, true),SPELL_VENOM_BOLT_VOLLEY,true); - events.ScheduleEvent(EVENT_BOLT, urand(18,22)*IN_MILLISECONDS); + DoCast(SelectTarget(SELECT_TARGET_RANDOM, 0, 100, true), SPELL_VENOM_BOLT_VOLLEY, true); + events.ScheduleEvent(EVENT_BOLT, urand(18, 22) * IN_MILLISECONDS); break; default: break; @@ -182,16 +182,16 @@ class mob_amanitar_mushrooms : public CreatureScript public: mob_amanitar_mushrooms() : CreatureScript("mob_amanitar_mushrooms") { } - struct mob_amanitar_mushroomsAI : public Scripted_NoMovementAI + struct mob_amanitar_mushroomsAI : public ScriptedAI { - mob_amanitar_mushroomsAI(Creature* creature) : Scripted_NoMovementAI(creature) {} + mob_amanitar_mushroomsAI(Creature* creature) : ScriptedAI(creature) {} EventMap events; void Reset() { events.Reset(); - events.ScheduleEvent(EVENT_AURA, 1*IN_MILLISECONDS); + events.ScheduleEvent(EVENT_AURA, 1 * IN_MILLISECONDS); me->SetDisplayId(me->GetCreatureTemplate()->Modelid2); DoCast(SPELL_PUTRID_MUSHROOM); @@ -211,7 +211,7 @@ public: void EnterCombat(Unit* /*who*/) {} void AttackStart(Unit* /*victim*/) {} - void UpdateAI(const uint32 diff) + void UpdateAI(uint32 diff) { if (!UpdateVictim()) return; @@ -231,7 +231,7 @@ public: DoCast(me, SPELL_POISONOUS_MUSHROOM_VISUAL_AREA, true); DoCast(me, SPELL_POISONOUS_MUSHROOM_POISON_CLOUD); } - events.ScheduleEvent(EVENT_AURA, 7*IN_MILLISECONDS); + events.ScheduleEvent(EVENT_AURA, 7 * IN_MILLISECONDS); break; default: break; @@ -250,4 +250,4 @@ void AddSC_boss_amanitar() { new boss_amanitar(); new mob_amanitar_mushrooms(); -}
\ No newline at end of file +} diff --git a/src/server/scripts/Northrend/AzjolNerub/Ahnkahet/boss_elder_nadox.cpp b/src/server/scripts/Northrend/AzjolNerub/Ahnkahet/boss_elder_nadox.cpp index cd583603734..a9fad9c5451 100644 --- a/src/server/scripts/Northrend/AzjolNerub/Ahnkahet/boss_elder_nadox.cpp +++ b/src/server/scripts/Northrend/AzjolNerub/Ahnkahet/boss_elder_nadox.cpp @@ -94,13 +94,13 @@ class boss_elder_nadox : public CreatureScript if (instance) instance->SetData(DATA_ELDER_NADOX_EVENT, IN_PROGRESS); - events.ScheduleEvent(EVENT_PLAGUE, 13*IN_MILLISECONDS); - events.ScheduleEvent(EVENT_SUMMON_SWARMER, 10*IN_MILLISECONDS); + events.ScheduleEvent(EVENT_PLAGUE, 13 * IN_MILLISECONDS); + events.ScheduleEvent(EVENT_SUMMON_SWARMER, 10 * IN_MILLISECONDS); if (IsHeroic()) { - events.ScheduleEvent(EVENT_RAGE, 12*IN_MILLISECONDS); - events.ScheduleEvent(EVENT_CHECK_ENRAGE, 5*IN_MILLISECONDS); + events.ScheduleEvent(EVENT_RAGE, 12 * IN_MILLISECONDS); + events.ScheduleEvent(EVENT_CHECK_ENRAGE, 5 * IN_MILLISECONDS); } } @@ -139,7 +139,7 @@ class boss_elder_nadox : public CreatureScript instance->SetData(DATA_ELDER_NADOX_EVENT, DONE); } - void UpdateAI(uint32 const diff) + void UpdateAI(uint32 diff) { if (!UpdateVictim()) return; @@ -151,25 +151,25 @@ class boss_elder_nadox : public CreatureScript switch (eventId) { case EVENT_PLAGUE: - DoCast(SelectTarget(SELECT_TARGET_RANDOM,0, 100, true),SPELL_BROOD_PLAGUE,true); - events.ScheduleEvent(EVENT_PLAGUE, 15*IN_MILLISECONDS); + DoCast(SelectTarget(SELECT_TARGET_RANDOM, 0, 100, true), SPELL_BROOD_PLAGUE, true); + events.ScheduleEvent(EVENT_PLAGUE, 15 * IN_MILLISECONDS); break; case EVENT_RAGE: DoCast(H_SPELL_BROOD_RAGE); - events.ScheduleEvent(EVENT_RAGE, urand(10*IN_MILLISECONDS, 50*IN_MILLISECONDS)); + events.ScheduleEvent(EVENT_RAGE, urand(10 * IN_MILLISECONDS, 50 * IN_MILLISECONDS)); break; case EVENT_SUMMON_SWARMER: DoCast(me, SPELL_SUMMON_SWARMERS); if (urand(1, 3) == 3) // 33% chance of dialog Talk(SAY_EGG_SAC); - events.ScheduleEvent(EVENT_SUMMON_SWARMER, 10*IN_MILLISECONDS); + events.ScheduleEvent(EVENT_SUMMON_SWARMER, 10 * IN_MILLISECONDS); break; case EVENT_CHECK_ENRAGE: if (me->HasAura(SPELL_ENRAGE)) return; if (me->GetPositionZ() < 24.0f) DoCast(me, SPELL_ENRAGE, true); - events.ScheduleEvent(EVENT_CHECK_ENRAGE, 5*IN_MILLISECONDS); + events.ScheduleEvent(EVENT_CHECK_ENRAGE, 5 * IN_MILLISECONDS); break; default: break; @@ -209,7 +209,7 @@ class mob_ahnkahar_nerubian : public CreatureScript if (me->GetEntry() == NPC_AHNKAHAR_GUARDIAN) DoCast(me, SPELL_GUARDIAN_AURA, true); - events.ScheduleEvent(EVENT_SPRINT, 13*IN_MILLISECONDS); + events.ScheduleEvent(EVENT_SPRINT, 13 * IN_MILLISECONDS); } void JustDied(Unit* /*killer*/) @@ -218,7 +218,7 @@ class mob_ahnkahar_nerubian : public CreatureScript me->RemoveAurasDueToSpell(SPELL_GUARDIAN_AURA); } - void UpdateAI(const uint32 diff) + void UpdateAI(uint32 diff) { if (!UpdateVictim()) return; @@ -234,7 +234,7 @@ class mob_ahnkahar_nerubian : public CreatureScript { case EVENT_SPRINT: DoCast(me, SPELL_SPRINT); - events.ScheduleEvent(EVENT_SPRINT, 20*IN_MILLISECONDS); + events.ScheduleEvent(EVENT_SPRINT, 20 * IN_MILLISECONDS); break; } } @@ -254,9 +254,9 @@ class mob_nadox_eggs : public CreatureScript public: mob_nadox_eggs() : CreatureScript("mob_nadox_eggs") { } - struct mob_nadox_eggsAI : public Scripted_NoMovementAI + struct mob_nadox_eggsAI : public ScriptedAI { - mob_nadox_eggsAI(Creature* creature) : Scripted_NoMovementAI(creature) + mob_nadox_eggsAI(Creature* creature) : ScriptedAI(creature) { creature->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE | UNIT_FLAG_NON_ATTACKABLE); creature->UpdateAllStats(); @@ -266,7 +266,7 @@ public: void EnterCombat(Unit* /*who*/) {} void AttackStart(Unit* /*victim*/) {} void MoveInLineOfSight(Unit* /*who*/) {} - void UpdateAI(const uint32 /*diff*/) {} + void UpdateAI(uint32 /*diff*/) {} }; CreatureAI* GetAI(Creature* creature) const diff --git a/src/server/scripts/Northrend/AzjolNerub/Ahnkahet/boss_herald_volazj.cpp b/src/server/scripts/Northrend/AzjolNerub/Ahnkahet/boss_herald_volazj.cpp index 7f6709b34fa..82ac2e8387c 100644 --- a/src/server/scripts/Northrend/AzjolNerub/Ahnkahet/boss_herald_volazj.cpp +++ b/src/server/scripts/Northrend/AzjolNerub/Ahnkahet/boss_herald_volazj.cpp @@ -258,7 +258,7 @@ public: } } - void UpdateAI(const uint32 diff) + void UpdateAI(uint32 diff) { //Return since we have no target if (!UpdateVictim()) @@ -322,5 +322,5 @@ public: void AddSC_boss_volazj() { - new boss_volazj; + new boss_volazj(); } diff --git a/src/server/scripts/Northrend/AzjolNerub/Ahnkahet/boss_jedoga_shadowseeker.cpp b/src/server/scripts/Northrend/AzjolNerub/Ahnkahet/boss_jedoga_shadowseeker.cpp index c36bcf9708f..e8b17224179 100644 --- a/src/server/scripts/Northrend/AzjolNerub/Ahnkahet/boss_jedoga_shadowseeker.cpp +++ b/src/server/scripts/Northrend/AzjolNerub/Ahnkahet/boss_jedoga_shadowseeker.cpp @@ -150,7 +150,7 @@ public: instance->SetData(DATA_JEDOGA_SHADOWSEEKER_EVENT, DONE); } - void DoAction(int32 const action) + void DoAction(int32 action) { if (action == ACTION_INITIAND_KILLED) volunteerWork = false; @@ -280,7 +280,7 @@ public: bCanDown = true; } - void UpdateAI(const uint32 diff) + void UpdateAI(uint32 diff) { if (!instance) return; @@ -451,7 +451,7 @@ public: } } - void UpdateAI(const uint32 diff) + void UpdateAI(uint32 diff) { if (instance && bCheckTimer <= diff) { @@ -523,15 +523,17 @@ class npc_jedogas_aufseher_trigger : public CreatureScript public: npc_jedogas_aufseher_trigger() : CreatureScript("npc_jedogas_aufseher_trigger") { } - struct npc_jedogas_aufseher_triggerAI : public Scripted_NoMovementAI + struct npc_jedogas_aufseher_triggerAI : public ScriptedAI { - npc_jedogas_aufseher_triggerAI(Creature* creature) : Scripted_NoMovementAI(creature) + npc_jedogas_aufseher_triggerAI(Creature* creature) : ScriptedAI(creature) { instance = creature->GetInstanceScript(); bRemoved = false; bRemoved2 = false; bCasted = false; bCasted2 = false; + + SetCombatMovement(false); } InstanceScript* instance; @@ -546,7 +548,7 @@ public: void AttackStart(Unit* /*victim*/) {} void MoveInLineOfSight(Unit* /*who*/) {} - void UpdateAI(const uint32 /*diff*/) + void UpdateAI(uint32 /*diff*/) { if (!instance) return; diff --git a/src/server/scripts/Northrend/AzjolNerub/Ahnkahet/boss_prince_taldaram.cpp b/src/server/scripts/Northrend/AzjolNerub/Ahnkahet/boss_prince_taldaram.cpp index 8f77cc7ec6f..a68cbcb7ee6 100644 --- a/src/server/scripts/Northrend/AzjolNerub/Ahnkahet/boss_prince_taldaram.cpp +++ b/src/server/scripts/Northrend/AzjolNerub/Ahnkahet/boss_prince_taldaram.cpp @@ -121,7 +121,7 @@ public: Talk(SAY_AGGRO); } - void UpdateAI(const uint32 diff) + void UpdateAI(uint32 diff) { if (!UpdateVictim()) return; @@ -370,7 +370,7 @@ public: DoCast(me, SPELL_FLAME_SPHERE_DEATH_EFFECT); } - void UpdateAI(const uint32 diff) + void UpdateAI(uint32 diff) { if (uiDespawnTimer <= diff) me->DisappearAndDie(); @@ -424,7 +424,7 @@ public: void AddSC_boss_taldaram() { - new boss_taldaram; - new mob_taldaram_flamesphere; - new prince_taldaram_sphere; + new boss_taldaram(); + new mob_taldaram_flamesphere(); + new prince_taldaram_sphere(); } diff --git a/src/server/scripts/Northrend/AzjolNerub/Ahnkahet/instance_ahnkahet.cpp b/src/server/scripts/Northrend/AzjolNerub/Ahnkahet/instance_ahnkahet.cpp index db4959ae670..26a4aeeca01 100644 --- a/src/server/scripts/Northrend/AzjolNerub/Ahnkahet/instance_ahnkahet.cpp +++ b/src/server/scripts/Northrend/AzjolNerub/Ahnkahet/instance_ahnkahet.cpp @@ -336,5 +336,5 @@ public: void AddSC_instance_ahnkahet() { - new instance_ahnkahet; + new instance_ahnkahet(); } diff --git a/src/server/scripts/Northrend/AzjolNerub/AzjolNerub/boss_anubarak.cpp b/src/server/scripts/Northrend/AzjolNerub/AzjolNerub/boss_anubarak.cpp index 1442ff265f4..1ec61488c1b 100644 --- a/src/server/scripts/Northrend/AzjolNerub/AzjolNerub/boss_anubarak.cpp +++ b/src/server/scripts/Northrend/AzjolNerub/AzjolNerub/boss_anubarak.cpp @@ -168,7 +168,7 @@ public: instance->SetData(DATA_ANUBARAK_EVENT, IN_PROGRESS); } - void UpdateAI(const uint32 diff) + void UpdateAI(uint32 diff) { if (!UpdateVictim()) return; @@ -360,5 +360,5 @@ public: void AddSC_boss_anub_arak() { - new boss_anub_arak; + new boss_anub_arak(); } diff --git a/src/server/scripts/Northrend/AzjolNerub/AzjolNerub/boss_hadronox.cpp b/src/server/scripts/Northrend/AzjolNerub/AzjolNerub/boss_hadronox.cpp index 6c707a8388f..eec7959f56f 100644 --- a/src/server/scripts/Northrend/AzjolNerub/AzjolNerub/boss_hadronox.cpp +++ b/src/server/scripts/Northrend/AzjolNerub/AzjolNerub/boss_hadronox.cpp @@ -134,7 +134,7 @@ public: EnterEvadeMode(); } - void UpdateAI(const uint32 diff) + void UpdateAI(uint32 diff) { //Return since we have no target if (!UpdateVictim()) @@ -198,5 +198,5 @@ public: void AddSC_boss_hadronox() { - new boss_hadronox; + new boss_hadronox(); } diff --git a/src/server/scripts/Northrend/AzjolNerub/AzjolNerub/boss_krikthir_the_gatewatcher.cpp b/src/server/scripts/Northrend/AzjolNerub/AzjolNerub/boss_krikthir_the_gatewatcher.cpp index aa329f12f6a..295f38658e2 100644 --- a/src/server/scripts/Northrend/AzjolNerub/AzjolNerub/boss_krikthir_the_gatewatcher.cpp +++ b/src/server/scripts/Northrend/AzjolNerub/AzjolNerub/boss_krikthir_the_gatewatcher.cpp @@ -138,7 +138,7 @@ public: me->SummonCreature(MOB_SKITTERING_SWARMER, SpawnPoint[7], TEMPSUMMON_TIMED_DESPAWN, 25*IN_MILLISECONDS); } - void UpdateAI(const uint32 diff) + void UpdateAI(uint32 diff) { if (!UpdateVictim()) return; @@ -239,7 +239,7 @@ public: uiBackstabTimer = 7*IN_MILLISECONDS; } - void UpdateAI(const uint32 diff) + void UpdateAI(uint32 diff) { if (!UpdateVictim()) return; @@ -290,7 +290,7 @@ public: uiShadowNovaTimer = 15*IN_MILLISECONDS; } - void UpdateAI(const uint32 diff) + void UpdateAI(uint32 diff) { if (!UpdateVictim()) return; @@ -336,7 +336,7 @@ public: uiStrikeTimer = 6*IN_MILLISECONDS; } - void UpdateAI(const uint32 diff) + void UpdateAI(uint32 diff) { if (!UpdateVictim()) return; @@ -386,7 +386,7 @@ public: DoCast(me, SPELL_ENRAGE, true); } - void UpdateAI(const uint32 diff) + void UpdateAI(uint32 diff) { if (!UpdateVictim()) return; @@ -434,7 +434,7 @@ public: uiBindingWebsTimer = 17*IN_MILLISECONDS; } - void UpdateAI(const uint32 diff) + void UpdateAI(uint32 diff) { if (!UpdateVictim()) return; @@ -488,7 +488,7 @@ public: uiPoisonSprayTimer = 15*IN_MILLISECONDS; } - void UpdateAI(const uint32 diff) + void UpdateAI(uint32 diff) { if (!UpdateVictim()) return; diff --git a/src/server/scripts/Northrend/AzjolNerub/AzjolNerub/instance_azjol_nerub.cpp b/src/server/scripts/Northrend/AzjolNerub/AzjolNerub/instance_azjol_nerub.cpp index 7873cadd096..875aafe9826 100644 --- a/src/server/scripts/Northrend/AzjolNerub/AzjolNerub/instance_azjol_nerub.cpp +++ b/src/server/scripts/Northrend/AzjolNerub/AzjolNerub/instance_azjol_nerub.cpp @@ -213,5 +213,5 @@ public: void AddSC_instance_azjol_nerub() { - new instance_azjol_nerub; + new instance_azjol_nerub(); } diff --git a/src/server/scripts/Northrend/ChamberOfAspects/ObsidianSanctum/boss_sartharion.cpp b/src/server/scripts/Northrend/ChamberOfAspects/ObsidianSanctum/boss_sartharion.cpp index f5864fe7b8f..bbec79ea43d 100644 --- a/src/server/scripts/Northrend/ChamberOfAspects/ObsidianSanctum/boss_sartharion.cpp +++ b/src/server/scripts/Northrend/ChamberOfAspects/ObsidianSanctum/boss_sartharion.cpp @@ -547,7 +547,7 @@ public: (*itr)->CastSpell(target, SPELL_LAVA_STRIKE, true); } - void UpdateAI(const uint32 uiDiff) + void UpdateAI(uint32 uiDiff) { //Return since we have no target if (!UpdateVictim()) @@ -954,7 +954,7 @@ struct dummy_dragonAI : public ScriptedAI } } - void UpdateAI(const uint32 uiDiff) + void UpdateAI(uint32 uiDiff) { if (m_bCanMoveFree && m_uiMoveNextTimer) { @@ -1017,7 +1017,7 @@ public: Talk(SAY_TENEBRON_SLAY); } - void UpdateAI(const uint32 uiDiff) + void UpdateAI(uint32 uiDiff) { //if no target, update dummy and return if (!UpdateVictim()) @@ -1112,7 +1112,7 @@ public: Talk(SAY_SHADRON_SLAY); } - void UpdateAI(const uint32 uiDiff) + void UpdateAI(uint32 uiDiff) { //if no target, update dummy and return if (!UpdateVictim()) @@ -1210,7 +1210,7 @@ public: Talk(SAY_VESPERON_SLAY); } - void UpdateAI(const uint32 uiDiff) + void UpdateAI(uint32 uiDiff) { //if no target, update dummy and return if (!UpdateVictim()) @@ -1352,7 +1352,7 @@ public: } } - void UpdateAI(const uint32 uiDiff) + void UpdateAI(uint32 uiDiff) { if (uiDespawnTimer < uiDiff) { @@ -1447,7 +1447,7 @@ public: } } - void UpdateAI(const uint32 uiDiff) + void UpdateAI(uint32 uiDiff) { if (uiDespawnTimer < uiDiff) { @@ -1480,10 +1480,11 @@ public: return new mob_twilight_eggsAI(creature); } - struct mob_twilight_eggsAI : public Scripted_NoMovementAI + struct mob_twilight_eggsAI : public ScriptedAI { - mob_twilight_eggsAI(Creature* creature) : Scripted_NoMovementAI(creature) + mob_twilight_eggsAI(Creature* creature) : ScriptedAI(creature) { + SetCombatMovement(false); instance = creature->GetInstanceScript(); } @@ -1518,7 +1519,7 @@ public: who->SetInCombatWithZone(); } - void UpdateAI(const uint32 uiDiff) + void UpdateAI(uint32 uiDiff) { if (m_uiHatchEggTimer <= uiDiff) { @@ -1572,7 +1573,7 @@ public: entry = 0; } - void UpdateAI(const uint32 diff) + void UpdateAI(uint32 diff) { if (Tsunami_Timer <= diff) { @@ -1602,11 +1603,11 @@ public: return new npc_twilight_fissureAI(creature); } - struct npc_twilight_fissureAI : public Scripted_NoMovementAI + struct npc_twilight_fissureAI : public ScriptedAI { - npc_twilight_fissureAI(Creature* creature) : Scripted_NoMovementAI(creature) + npc_twilight_fissureAI(Creature* creature) : ScriptedAI(creature) { - Reset(); + SetCombatMovement(false); } uint32 VoidBlast_Timer; @@ -1620,7 +1621,7 @@ public: VoidBlast_Timer = 5000; } - void UpdateAI(const uint32 diff) + void UpdateAI(uint32 diff) { if (VoidBlast_Timer <= diff) { @@ -1667,7 +1668,7 @@ public: m_uiFadeArmorTimer = 1000; } - void UpdateAI(const uint32 uiDiff) + void UpdateAI(uint32 uiDiff) { //Return since we have no target if (!UpdateVictim()) diff --git a/src/server/scripts/Northrend/ChamberOfAspects/RubySanctum/boss_baltharus_the_warborn.cpp b/src/server/scripts/Northrend/ChamberOfAspects/RubySanctum/boss_baltharus_the_warborn.cpp index 205a0b10d69..d3a685bc6ba 100644 --- a/src/server/scripts/Northrend/ChamberOfAspects/RubySanctum/boss_baltharus_the_warborn.cpp +++ b/src/server/scripts/Northrend/ChamberOfAspects/RubySanctum/boss_baltharus_the_warborn.cpp @@ -61,9 +61,7 @@ enum Phases { PHASE_ALL = 0, PHASE_INTRO = 1, - PHASE_COMBAT = 2, - - PHASE_INTRO_MASK = 1 << PHASE_INTRO, + PHASE_COMBAT = 2 }; class boss_baltharus_the_warborn : public CreatureScript @@ -87,7 +85,7 @@ class boss_baltharus_the_warborn : public CreatureScript instance->SetData(DATA_BALTHARUS_SHARED_HEALTH, me->GetMaxHealth()); } - void DoAction(int32 const action) + void DoAction(int32 action) { switch (action) { @@ -164,17 +162,18 @@ class boss_baltharus_the_warborn : public CreatureScript instance->SetData(DATA_BALTHARUS_SHARED_HEALTH, me->GetHealth() - damage); } - void UpdateAI(uint32 const diff) + void UpdateAI(uint32 diff) { - if (!UpdateVictim() && !(events.GetPhaseMask() & PHASE_INTRO_MASK)) + bool introPhase = events.IsInPhase(PHASE_INTRO); + if (!UpdateVictim() && !introPhase) return; - if (!(events.GetPhaseMask() & PHASE_INTRO_MASK)) + if (!introPhase) me->SetHealth(instance->GetData(DATA_BALTHARUS_SHARED_HEALTH)); events.Update(diff); - if (me->HasUnitState(UNIT_STATE_CASTING) && !(events.GetPhaseMask() & PHASE_INTRO_MASK)) + if (me->HasUnitState(UNIT_STATE_CASTING) && !introPhase) return; while (uint32 eventId = events.ExecuteEvent()) @@ -258,7 +257,7 @@ class npc_baltharus_the_warborn_clone : public CreatureScript killer->Kill(baltharus); } - void UpdateAI(uint32 const diff) + void UpdateAI(uint32 diff) { if (!UpdateVictim()) return; diff --git a/src/server/scripts/Northrend/ChamberOfAspects/RubySanctum/boss_general_zarithrian.cpp b/src/server/scripts/Northrend/ChamberOfAspects/RubySanctum/boss_general_zarithrian.cpp index ab53351cd6b..c616d44816c 100644 --- a/src/server/scripts/Northrend/ChamberOfAspects/RubySanctum/boss_general_zarithrian.cpp +++ b/src/server/scripts/Northrend/ChamberOfAspects/RubySanctum/boss_general_zarithrian.cpp @@ -135,13 +135,18 @@ class boss_general_zarithrian : public CreatureScript Talk(SAY_KILL); } - void UpdateAI(uint32 const diff) + bool CanAIAttack(Unit const* /*target*/) const + { + return (instance->GetBossState(DATA_SAVIANA_RAGEFIRE) == DONE && instance->GetBossState(DATA_BALTHARUS_THE_WARBORN) == DONE); + } + + void UpdateAI(uint32 diff) { if (!UpdateVictim()) return; // Can't use room boundary here, the gameobject is spawned at the same position as the boss. This is just as good anyway. - if (me->GetPositionX() > 3060.0f) + if (me->GetPositionX() > 3058.0f) { EnterEvadeMode(); return; @@ -159,9 +164,11 @@ class boss_general_zarithrian : public CreatureScript case EVENT_SUMMON_ADDS: { if (Creature* stalker1 = ObjectAccessor::GetCreature(*me, instance->GetData64(DATA_ZARITHRIAN_SPAWN_STALKER_1))) - stalker1->AI()->DoCast(stalker1, SPELL_SUMMON_FLAMECALLER); + stalker1->CastSpell(stalker1, SPELL_SUMMON_FLAMECALLER, false); + if (Creature* stalker2 = ObjectAccessor::GetCreature(*me, instance->GetData64(DATA_ZARITHRIAN_SPAWN_STALKER_2))) - stalker2->AI()->DoCast(stalker2, SPELL_SUMMON_FLAMECALLER); + stalker2->CastSpell(stalker2, SPELL_SUMMON_FLAMECALLER, false); + Talk(SAY_ADDS); events.ScheduleEvent(EVENT_SUMMON_ADDS, 42000); break; @@ -195,9 +202,8 @@ class npc_onyx_flamecaller : public CreatureScript struct npc_onyx_flamecallerAI : public npc_escortAI { - npc_onyx_flamecallerAI(Creature* creature) : npc_escortAI(creature) + npc_onyx_flamecallerAI(Creature* creature) : npc_escortAI(creature), _instance(creature->GetInstanceScript()) { - _instance = creature->GetInstanceScript(); npc_escortAI::SetDespawnAtEnd(false); } @@ -289,7 +295,6 @@ class npc_onyx_flamecaller : public CreatureScript } private: EventMap _events; - bool _movementComplete; InstanceScript* _instance; uint8 _lavaGoutCount; }; diff --git a/src/server/scripts/Northrend/ChamberOfAspects/RubySanctum/boss_halion.cpp b/src/server/scripts/Northrend/ChamberOfAspects/RubySanctum/boss_halion.cpp index 781dd86cb86..48bc162c82c 100644 --- a/src/server/scripts/Northrend/ChamberOfAspects/RubySanctum/boss_halion.cpp +++ b/src/server/scripts/Northrend/ChamberOfAspects/RubySanctum/boss_halion.cpp @@ -165,12 +165,7 @@ enum Phases PHASE_INTRO = 1, PHASE_ONE = 2, PHASE_TWO = 3, - PHASE_THREE = 4, - - PHASE_INTRO_MASK = 1 << PHASE_INTRO, - PHASE_ONE_MASK = 1 << PHASE_ONE, - PHASE_TWO_MASK = 1 << PHASE_TWO, - PHASE_THREE_MASK = 1 << PHASE_THREE + PHASE_THREE = 4 }; enum Misc @@ -226,9 +221,9 @@ struct generic_halionAI : public BossAI { generic_halionAI(Creature* creature, uint32 bossId) : BossAI(creature, bossId), _canEvade(false) { } - void EnterCombat(Unit* who) + void EnterCombat(Unit* /*who*/) { - BossAI::EnterCombat(who); + _EnterCombat(); me->AddAura(SPELL_TWILIGHT_PRECISION, me); _canEvade = false; events.ScheduleEvent(EVENT_CLEAVE, urand(8000, 10000)); @@ -239,16 +234,16 @@ struct generic_halionAI : public BossAI void Reset() { _canEvade = false; - BossAI::Reset(); + _Reset(); } - void EnterEvadeMode() + void JustReachedHome() { - BossAI::EnterEvadeMode(); instance->SendEncounterUnit(ENCOUNTER_FRAME_DISENGAGE, me); + _JustReachedHome(); } - void ExecuteEvent(uint32 const eventId) + void ExecuteEvent(uint32 eventId) { switch (eventId) { @@ -267,7 +262,7 @@ struct generic_halionAI : public BossAI } } - void UpdateAI(uint32 const diff) + void UpdateAI(uint32 diff) { if (!UpdateVictim() || me->HasUnitState(UNIT_STATE_CASTING)) return; @@ -325,7 +320,7 @@ class boss_halion : public CreatureScript void EnterEvadeMode() { // Phase 1: We always can evade. Phase 2 & 3: We can evade if and only if the controller tells us to. - if ((events.GetPhaseMask() & PHASE_ONE_MASK) || _canEvade) + if (events.IsInPhase(PHASE_ONE) || _canEvade) generic_halionAI::EnterEvadeMode(); } @@ -349,22 +344,27 @@ class boss_halion : public CreatureScript controller->AI()->SetData(DATA_FIGHT_PHASE, PHASE_ONE); } - void JustDied(Unit* killer) + void JustDied(Unit* /*killer*/) { - BossAI::JustDied(killer); + _JustDied(); Talk(SAY_DEATH); instance->SendEncounterUnit(ENCOUNTER_FRAME_DISENGAGE, me); + if (Creature* twilightHalion = ObjectAccessor::GetCreature(*me, instance->GetData64(DATA_TWILIGHT_HALION))) + if (twilightHalion->isAlive()) + twilightHalion->Kill(twilightHalion); + if (Creature* controller = ObjectAccessor::GetCreature(*me, instance->GetData64(DATA_HALION_CONTROLLER))) - me->Kill(controller); + if (controller->isAlive()) + controller->Kill(controller); } Position const* GetMeteorStrikePosition() const { return &_meteorStrikePos; } void DamageTaken(Unit* attacker, uint32& damage) { - if (me->HealthBelowPctDamaged(75, damage) && (events.GetPhaseMask() & PHASE_ONE_MASK)) + if (me->HealthBelowPctDamaged(75, damage) && events.IsInPhase(PHASE_ONE)) { events.SetPhase(PHASE_TWO); Talk(SAY_PHASE_TWO); @@ -378,7 +378,7 @@ class boss_halion : public CreatureScript return; } - if (events.GetPhaseMask() & PHASE_THREE_MASK) + if (events.IsInPhase(PHASE_THREE)) { // Don't consider copied damage. if (!me->InSamePhase(attacker)) @@ -389,15 +389,15 @@ class boss_halion : public CreatureScript } } - void UpdateAI(uint32 const diff) + void UpdateAI(uint32 diff) { - if (events.GetPhaseMask() & PHASE_TWO_MASK) + if (events.IsInPhase(PHASE_TWO)) return; generic_halionAI::UpdateAI(diff); } - void ExecuteEvent(uint32 const eventId) + void ExecuteEvent(uint32 eventId) { switch (eventId) { @@ -515,14 +515,15 @@ class boss_twilight_halion : public CreatureScript } if (Creature* controller = ObjectAccessor::GetCreature(*me, instance->GetData64(DATA_HALION_CONTROLLER))) - controller->Kill(controller); + if (controller->isAlive()) + controller->Kill(controller); instance->SendEncounterUnit(ENCOUNTER_FRAME_DISENGAGE, me); } void DamageTaken(Unit* attacker, uint32& damage) { - if (me->HealthBelowPctDamaged(50, damage) && (events.GetPhaseMask() & PHASE_TWO_MASK)) + if (me->HealthBelowPctDamaged(50, damage) && events.IsInPhase(PHASE_TWO)) { events.SetPhase(PHASE_THREE); me->CastStop(); @@ -531,7 +532,7 @@ class boss_twilight_halion : public CreatureScript return; } - if (events.GetPhaseMask() & PHASE_THREE_MASK) + if (events.IsInPhase(PHASE_THREE)) { // Don't consider copied damage. if (!me->InSamePhase(attacker)) @@ -556,7 +557,7 @@ class boss_twilight_halion : public CreatureScript } } - void ExecuteEvent(uint32 const eventId) + void ExecuteEvent(uint32 eventId) { switch (eventId) { @@ -592,7 +593,6 @@ class npc_halion_controller : public CreatureScript _instance(creature->GetInstanceScript()), _summons(me) { me->SetPhaseMask(me->GetPhaseMask() | 0x20, true); - _events.SetPhase(PHASE_INTRO); } void Reset() @@ -641,7 +641,7 @@ class npc_halion_controller : public CreatureScript _instance->SetBossState(DATA_HALION, FAIL); } - void DoAction(int32 const action) + void DoAction(int32 action) { switch (action) { @@ -683,12 +683,12 @@ class npc_halion_controller : public CreatureScript } } - void UpdateAI(uint32 const diff) + void UpdateAI(uint32 diff) { // The isInCombat() check is needed because that check should be false when Halion is // not engaged, while it would return true without as UpdateVictim() checks for // combat state. - if (!(_events.GetPhaseMask() & PHASE_INTRO_MASK) && me->isInCombat() && !UpdateVictim()) + if (!(_events.IsInPhase(PHASE_INTRO)) && me->isInCombat() && !UpdateVictim()) { EnterEvadeMode(); return; @@ -780,7 +780,7 @@ class npc_halion_controller : public CreatureScript } private: - /// TODO: Find out a better scaling, if any. + //// @todo Find out a better scaling, if any. // [0 , 0.98[: Corporeality goes down // [0.98, 0.99]: Do nothing // ]0.99, 1.01[: Twilight Mending @@ -912,7 +912,7 @@ class npc_orb_carrier : public CreatureScript ASSERT(creature->GetVehicleKit()); } - void UpdateAI(uint32 const /*diff*/) + void UpdateAI(uint32 /*diff*/) { /// According to sniffs this spell is cast every 1 or 2 seconds. /// However, refreshing it looks bad, so just cast the spell if @@ -928,7 +928,7 @@ class npc_orb_carrier : public CreatureScript me->SetFacingToObject(rotationFocus); // setInFront } - void DoAction(int32 const action) + void DoAction(int32 action) { if (action == ACTION_SHOOT) { @@ -973,13 +973,15 @@ class npc_meteor_strike_initial : public CreatureScript public: npc_meteor_strike_initial() : CreatureScript("npc_meteor_strike_initial") { } - struct npc_meteor_strike_initialAI : public Scripted_NoMovementAI + struct npc_meteor_strike_initialAI : public ScriptedAI { - npc_meteor_strike_initialAI(Creature* creature) : Scripted_NoMovementAI(creature), + npc_meteor_strike_initialAI(Creature* creature) : ScriptedAI(creature), _instance(creature->GetInstanceScript()) - { } + { + SetCombatMovement(false); + } - void DoAction(int32 const action) + void DoAction(int32 action) { switch (action) { @@ -1027,7 +1029,7 @@ class npc_meteor_strike_initial : public CreatureScript } } - void UpdateAI(uint32 const /*diff*/) { } + void UpdateAI(uint32 /*diff*/) { } void EnterEvadeMode() { } private: InstanceScript* _instance; @@ -1045,16 +1047,18 @@ class npc_meteor_strike : public CreatureScript public: npc_meteor_strike() : CreatureScript("npc_meteor_strike") { } - struct npc_meteor_strikeAI : public Scripted_NoMovementAI + struct npc_meteor_strikeAI : public ScriptedAI { - npc_meteor_strikeAI(Creature* creature) : Scripted_NoMovementAI(creature), + npc_meteor_strikeAI(Creature* creature) : ScriptedAI(creature), _instance(creature->GetInstanceScript()) { _range = 5.0f; _spawnCount = 0; + + SetCombatMovement(false); } - void DoAction(int32 const action) + void DoAction(int32 action) { if (action == ACTION_METEOR_STRIKE_BURN) { @@ -1071,7 +1075,7 @@ class npc_meteor_strike : public CreatureScript controller->AI()->JustSummoned(me); } - void UpdateAI(uint32 const diff) + void UpdateAI(uint32 diff) { if (_spawnCount > 5) return; @@ -1114,11 +1118,13 @@ class npc_combustion_consumption : public CreatureScript public: npc_combustion_consumption() : CreatureScript("npc_combustion_consumption") { } - struct npc_combustion_consumptionAI : public Scripted_NoMovementAI + struct npc_combustion_consumptionAI : public ScriptedAI { - npc_combustion_consumptionAI(Creature* creature) : Scripted_NoMovementAI(creature), + npc_combustion_consumptionAI(Creature* creature) : ScriptedAI(creature), _instance(creature->GetInstanceScript()), _summonerGuid(0) { + SetCombatMovement(false); + switch (me->GetEntry()) { case NPC_COMBUSTION: @@ -1164,7 +1170,7 @@ class npc_combustion_consumption : public CreatureScript summoner->CastCustomSpell(_explosionSpell, SPELLVALUE_BASE_POINT0, damage, summoner); } - void UpdateAI(uint32 const /*diff*/) { } + void UpdateAI(uint32 /*diff*/) { } private: InstanceScript* _instance; @@ -1243,7 +1249,7 @@ class npc_living_ember : public CreatureScript me->DespawnOrUnsummon(1); } - void UpdateAI(uint32 const diff) + void UpdateAI(uint32 diff) { if (!UpdateVictim() || me->HasUnitState(UNIT_STATE_CASTING)) return; diff --git a/src/server/scripts/Northrend/ChamberOfAspects/RubySanctum/boss_saviana_ragefire.cpp b/src/server/scripts/Northrend/ChamberOfAspects/RubySanctum/boss_saviana_ragefire.cpp index 06743858ec0..d391abb0d4d 100644 --- a/src/server/scripts/Northrend/ChamberOfAspects/RubySanctum/boss_saviana_ragefire.cpp +++ b/src/server/scripts/Northrend/ChamberOfAspects/RubySanctum/boss_saviana_ragefire.cpp @@ -141,7 +141,7 @@ class boss_saviana_ragefire : public CreatureScript Talk(SAY_KILL); } - void UpdateAI(uint32 const diff) + void UpdateAI(uint32 diff) { if (!UpdateVictim()) return; diff --git a/src/server/scripts/Northrend/ChamberOfAspects/RubySanctum/instance_ruby_sanctum.cpp b/src/server/scripts/Northrend/ChamberOfAspects/RubySanctum/instance_ruby_sanctum.cpp index c373c2340ff..abfa2df5c97 100644 --- a/src/server/scripts/Northrend/ChamberOfAspects/RubySanctum/instance_ruby_sanctum.cpp +++ b/src/server/scripts/Northrend/ChamberOfAspects/RubySanctum/instance_ruby_sanctum.cpp @@ -60,8 +60,11 @@ class instance_ruby_sanctum : public InstanceMapScript void OnPlayerEnter(Player* /*player*/) { if (!GetData64(DATA_HALION_CONTROLLER) && GetBossState(DATA_HALION) != DONE && GetBossState(DATA_GENERAL_ZARITHRIAN) == DONE) + { + instance->LoadGrid(HalionControllerSpawnPos.GetPositionX(), HalionControllerSpawnPos.GetPositionY()); if (Creature* halionController = instance->SummonCreature(NPC_HALION_CONTROLLER, HalionControllerSpawnPos)) halionController->AI()->DoAction(ACTION_INTRO_HALION); + } } void OnCreatureCreate(Creature* creature) @@ -164,6 +167,20 @@ class instance_ruby_sanctum : public InstanceMapScript } } + void OnUnitDeath(Unit* unit) + { + Creature* creature = unit->ToCreature(); + if (!creature) + return; + + if (creature->GetEntry() == NPC_GENERAL_ZARITHRIAN && GetBossState(DATA_HALION) != DONE) + { + instance->LoadGrid(HalionControllerSpawnPos.GetPositionX(), HalionControllerSpawnPos.GetPositionY()); + if (Creature* halionController = instance->SummonCreature(NPC_HALION_CONTROLLER, HalionControllerSpawnPos)) + halionController->AI()->DoAction(ACTION_INTRO_HALION); + } + } + uint64 GetData64(uint32 type) const { switch (type) @@ -238,11 +255,6 @@ class instance_ruby_sanctum : public InstanceMapScript { if (GetBossState(DATA_SAVIANA_RAGEFIRE) == DONE && GetBossState(DATA_BALTHARUS_THE_WARBORN) == DONE) HandleGameObject(FlameWallsGUID, state != IN_PROGRESS); - - // Not called at instance loading, no big deal. - if (state == DONE && GetBossState(DATA_HALION) != DONE) - if (Creature* halionController = instance->SummonCreature(NPC_HALION_CONTROLLER, HalionControllerSpawnPos)) - halionController->AI()->DoAction(ACTION_INTRO_HALION); break; } case DATA_HALION: diff --git a/src/server/scripts/Northrend/ChamberOfAspects/RubySanctum/ruby_sanctum.cpp b/src/server/scripts/Northrend/ChamberOfAspects/RubySanctum/ruby_sanctum.cpp index 5baae66e65b..2623b2c542a 100644 --- a/src/server/scripts/Northrend/ChamberOfAspects/RubySanctum/ruby_sanctum.cpp +++ b/src/server/scripts/Northrend/ChamberOfAspects/RubySanctum/ruby_sanctum.cpp @@ -66,7 +66,7 @@ class npc_xerestrasza : public CreatureScript me->RemoveFlag(UNIT_NPC_FLAGS, GOSSIP_OPTION_QUESTGIVER); } - void DoAction(int32 const action) + void DoAction(int32 action) { if (action == ACTION_BALTHARUS_DEATH) { @@ -92,7 +92,7 @@ class npc_xerestrasza : public CreatureScript } } - void UpdateAI(uint32 const diff) + void UpdateAI(uint32 diff) { if (_isIntro) return; diff --git a/src/server/scripts/Northrend/CrusadersColiseum/TrialOfTheChampion/boss_argent_challenge.cpp b/src/server/scripts/Northrend/CrusadersColiseum/TrialOfTheChampion/boss_argent_challenge.cpp index fb0f0fbaee1..553b836da8f 100644 --- a/src/server/scripts/Northrend/CrusadersColiseum/TrialOfTheChampion/boss_argent_challenge.cpp +++ b/src/server/scripts/Northrend/CrusadersColiseum/TrialOfTheChampion/boss_argent_challenge.cpp @@ -175,7 +175,7 @@ public: me->DisappearAndDie(); } - void UpdateAI(const uint32 uiDiff) + void UpdateAI(uint32 uiDiff) { if (bDone && uiResetTimer <= uiDiff) { @@ -299,7 +299,7 @@ public: me->DisappearAndDie(); } - void UpdateAI(const uint32 uiDiff) + void UpdateAI(uint32 uiDiff) { if (bDone && uiResetTimer <= uiDiff) { @@ -403,7 +403,7 @@ public: uiWakingNightmare = 7000; } - void UpdateAI(const uint32 uiDiff) + void UpdateAI(uint32 uiDiff) { if (!UpdateVictim()) return; @@ -545,7 +545,7 @@ public: uiWaypoint = uiType; } - void UpdateAI(const uint32 uiDiff) + void UpdateAI(uint32 uiDiff) { npc_escortAI::UpdateAI(uiDiff); diff --git a/src/server/scripts/Northrend/CrusadersColiseum/TrialOfTheChampion/boss_black_knight.cpp b/src/server/scripts/Northrend/CrusadersColiseum/TrialOfTheChampion/boss_black_knight.cpp index ceb9724a078..b253d15773d 100644 --- a/src/server/scripts/Northrend/CrusadersColiseum/TrialOfTheChampion/boss_black_knight.cpp +++ b/src/server/scripts/Northrend/CrusadersColiseum/TrialOfTheChampion/boss_black_knight.cpp @@ -153,7 +153,7 @@ public: summon->AI()->AttackStart(me->getVictim()); } - void UpdateAI(const uint32 uiDiff) + void UpdateAI(uint32 uiDiff) { //Return since we have no target if (!UpdateVictim()) @@ -320,7 +320,7 @@ public: uiAttackTimer = 3500; } - void UpdateAI(const uint32 uiDiff) + void UpdateAI(uint32 uiDiff) { if (!UpdateVictim()) return; @@ -362,7 +362,7 @@ public: } - void UpdateAI(const uint32 uiDiff) + void UpdateAI(uint32 uiDiff) { npc_escortAI::UpdateAI(uiDiff); diff --git a/src/server/scripts/Northrend/CrusadersColiseum/TrialOfTheChampion/boss_grand_champions.cpp b/src/server/scripts/Northrend/CrusadersColiseum/TrialOfTheChampion/boss_grand_champions.cpp index 9299630b3d2..e637de75b4d 100644 --- a/src/server/scripts/Northrend/CrusadersColiseum/TrialOfTheChampion/boss_grand_champions.cpp +++ b/src/server/scripts/Northrend/CrusadersColiseum/TrialOfTheChampion/boss_grand_champions.cpp @@ -233,7 +233,7 @@ public: DoCast(me, SPELL_SHIELD, true); } - void UpdateAI(const uint32 uiDiff) + void UpdateAI(uint32 uiDiff) { npc_escortAI::UpdateAI(uiDiff); @@ -360,7 +360,7 @@ public: bHome = false; } - void UpdateAI(const uint32 uiDiff) + void UpdateAI(uint32 uiDiff) { if (!bDone && GrandChampionsOutVehicle(me)) { @@ -494,7 +494,7 @@ public: bHome = false; } - void UpdateAI(const uint32 uiDiff) + void UpdateAI(uint32 uiDiff) { if (!bDone && GrandChampionsOutVehicle(me)) { @@ -639,7 +639,7 @@ public: bHome = false; } - void UpdateAI(const uint32 uiDiff) + void UpdateAI(uint32 uiDiff) { if (!bDone && GrandChampionsOutVehicle(me)) { @@ -785,7 +785,7 @@ public: bHome = false; } - void UpdateAI(const uint32 uiDiff) + void UpdateAI(uint32 uiDiff) { if (!bDone && GrandChampionsOutVehicle(me)) { @@ -933,7 +933,7 @@ public: bHome = false; } - void UpdateAI(const uint32 uiDiff) + void UpdateAI(uint32 uiDiff) { if (!bDone && GrandChampionsOutVehicle(me)) { diff --git a/src/server/scripts/Northrend/CrusadersColiseum/TrialOfTheChampion/trial_of_the_champion.cpp b/src/server/scripts/Northrend/CrusadersColiseum/TrialOfTheChampion/trial_of_the_champion.cpp index 7e4a740cb13..472048501a5 100644 --- a/src/server/scripts/Northrend/CrusadersColiseum/TrialOfTheChampion/trial_of_the_champion.cpp +++ b/src/server/scripts/Northrend/CrusadersColiseum/TrialOfTheChampion/trial_of_the_champion.cpp @@ -412,7 +412,7 @@ public: } } - void UpdateAI(const uint32 uiDiff) + void UpdateAI(uint32 uiDiff) { ScriptedAI::UpdateAI(uiDiff); diff --git a/src/server/scripts/Northrend/CrusadersColiseum/TrialOfTheCrusader/boss_anubarak_trial.cpp b/src/server/scripts/Northrend/CrusadersColiseum/TrialOfTheCrusader/boss_anubarak_trial.cpp index e44f5fba1b8..9c6d481c207 100644 --- a/src/server/scripts/Northrend/CrusadersColiseum/TrialOfTheCrusader/boss_anubarak_trial.cpp +++ b/src/server/scripts/Northrend/CrusadersColiseum/TrialOfTheCrusader/boss_anubarak_trial.cpp @@ -154,9 +154,7 @@ enum Phases { // Anub'arak PHASE_MELEE = 1, - PHASE_SUBMERGED = 2, - - PHASE_MASK_MELEE = 1 << PHASE_MELEE + PHASE_SUBMERGED = 2 }; class boss_anubarak_trial : public CreatureScript @@ -286,7 +284,7 @@ class boss_anubarak_trial : public CreatureScript _sphereGUID[i] = summoned->GetGUID(); } - void UpdateAI(const uint32 diff) + void UpdateAI(uint32 diff) { if (!UpdateVictim()) return; @@ -403,7 +401,7 @@ class boss_anubarak_trial : public CreatureScript } - if (HealthBelowPct(30) && events.GetPhaseMask() & PHASE_MASK_MELEE && !_reachedPhase3) + if (HealthBelowPct(30) && events.IsInPhase(PHASE_MELEE) && !_reachedPhase3) { _reachedPhase3 = true; DoCastAOE(SPELL_LEECHING_SWARM); @@ -411,7 +409,7 @@ class boss_anubarak_trial : public CreatureScript Talk(SAY_LEECHING_SWARM); } - if (events.GetPhaseMask() & PHASE_MASK_MELEE) + if (events.IsInPhase(PHASE_MELEE)) DoMeleeAttackIfReady(); } @@ -453,7 +451,7 @@ class mob_swarm_scarab : public CreatureScript Anubarak->AI()->JustSummoned(me); } - void DoAction(const int32 actionId) + void DoAction(int32 actionId) { switch (actionId) { @@ -471,7 +469,7 @@ class mob_swarm_scarab : public CreatureScript DoCast(killer, RAID_MODE(SPELL_TRAITOR_KING_10, SPELL_TRAITOR_KING_25)); } - void UpdateAI(const uint32 diff) + void UpdateAI(uint32 diff) { if (_instance && _instance->GetBossState(BOSS_ANUBARAK) != IN_PROGRESS) me->DisappearAndDie(); @@ -527,7 +525,7 @@ class mob_nerubian_burrower : public CreatureScript Anubarak->AI()->JustSummoned(me); } - void DoAction(const int32 actionId) + void DoAction(int32 actionId) { switch (actionId) { @@ -541,7 +539,7 @@ class mob_nerubian_burrower : public CreatureScript } } - void UpdateAI(const uint32 diff) + void UpdateAI(uint32 diff) { if (_instance && _instance->GetBossState(BOSS_ANUBARAK) != IN_PROGRESS) me->DisappearAndDie(); @@ -702,7 +700,7 @@ class mob_anubarak_spike : public CreatureScript uiDamage = 0; } - void UpdateAI(const uint32 diff) + void UpdateAI(uint32 diff) { if (!UpdateVictim()) { diff --git a/src/server/scripts/Northrend/CrusadersColiseum/TrialOfTheCrusader/boss_faction_champions.cpp b/src/server/scripts/Northrend/CrusadersColiseum/TrialOfTheCrusader/boss_faction_champions.cpp index ba554c3703d..f1bf0579187 100644 --- a/src/server/scripts/Northrend/CrusadersColiseum/TrialOfTheCrusader/boss_faction_champions.cpp +++ b/src/server/scripts/Northrend/CrusadersColiseum/TrialOfTheCrusader/boss_faction_champions.cpp @@ -710,7 +710,7 @@ struct boss_faction_championsAI : public BossAI } } - void UpdateAI(const uint32 diff) + void UpdateAI(uint32 diff) { _events.Update(diff); @@ -773,7 +773,7 @@ class mob_toc_druid : public CreatureScript SetEquipmentSlots(false, 51799, EQUIP_NO_CHANGE, EQUIP_NO_CHANGE); } - void UpdateAI(const uint32 diff) + void UpdateAI(uint32 diff) { if (!UpdateVictim()) return; @@ -865,7 +865,7 @@ class mob_toc_shaman : public CreatureScript SetEquipmentSlots(false, 49992, EQUIP_NO_CHANGE, EQUIP_NO_CHANGE); } - void UpdateAI(const uint32 diff) + void UpdateAI(uint32 diff) { if (!UpdateVictim()) return; @@ -959,7 +959,7 @@ class mob_toc_paladin : public CreatureScript SetEquipmentSlots(false, 50771, 47079, EQUIP_NO_CHANGE); } - void UpdateAI(const uint32 diff) + void UpdateAI(uint32 diff) { if (!UpdateVictim()) return; @@ -1062,7 +1062,7 @@ class mob_toc_priest : public CreatureScript SetEquipmentSlots(false, 49992, EQUIP_NO_CHANGE, EQUIP_NO_CHANGE); } - void UpdateAI(const uint32 diff) + void UpdateAI(uint32 diff) { if (!UpdateVictim()) return; @@ -1152,7 +1152,7 @@ class mob_toc_shadow_priest : public CreatureScript DoCast(me, SPELL_SHADOWFORM); } - void UpdateAI(const uint32 diff) + void UpdateAI(uint32 diff) { if (!UpdateVictim()) return; @@ -1251,7 +1251,7 @@ class mob_toc_warlock : public CreatureScript DoCast(SPELL_SUMMON_FELHUNTER); } - void UpdateAI(const uint32 diff) + void UpdateAI(uint32 diff) { if (!UpdateVictim()) return; @@ -1337,7 +1337,7 @@ class mob_toc_mage : public CreatureScript SetEquipmentSlots(false, 47524, EQUIP_NO_CHANGE, EQUIP_NO_CHANGE); } - void UpdateAI(const uint32 diff) + void UpdateAI(uint32 diff) { if (!UpdateVictim()) return; @@ -1437,7 +1437,7 @@ class mob_toc_hunter : public CreatureScript DoCast(SPELL_CALL_PET); } - void UpdateAI(const uint32 diff) + void UpdateAI(uint32 diff) { if (!UpdateVictim()) return; @@ -1534,7 +1534,7 @@ class mob_toc_boomkin : public CreatureScript SetEquipmentSlots(false, 50966, EQUIP_NO_CHANGE, EQUIP_NO_CHANGE); } - void UpdateAI(const uint32 diff) + void UpdateAI(uint32 diff) { if (!UpdateVictim()) return; @@ -1629,7 +1629,7 @@ class mob_toc_warrior : public CreatureScript SetEquipmentSlots(false, 47427, 46964, EQUIP_NO_CHANGE); } - void UpdateAI(const uint32 diff) + void UpdateAI(uint32 diff) { if (!UpdateVictim()) return; @@ -1728,7 +1728,7 @@ class mob_toc_dk : public CreatureScript SetEquipmentSlots(false, 47518, 51021, EQUIP_NO_CHANGE); } - void UpdateAI(const uint32 diff) + void UpdateAI(uint32 diff) { if (!UpdateVictim()) return; @@ -1827,7 +1827,7 @@ class mob_toc_rogue : public CreatureScript me->SetMaxPower(POWER_ENERGY, 100); } - void UpdateAI(const uint32 diff) + void UpdateAI(uint32 diff) { if (!UpdateVictim()) return; @@ -1967,7 +1967,7 @@ class mob_toc_enh_shaman : public CreatureScript summons.DespawnAll(); } - void UpdateAI(const uint32 diff) + void UpdateAI(uint32 diff) { if (!UpdateVictim()) return; @@ -2062,7 +2062,7 @@ class mob_toc_retro_paladin : public CreatureScript DoCast(SPELL_SEAL_OF_COMMAND); } - void UpdateAI(const uint32 diff) + void UpdateAI(uint32 diff) { if (!UpdateVictim()) return; @@ -2155,7 +2155,7 @@ class mob_toc_pet_warlock : public CreatureScript events.ScheduleEvent(EVENT_SPELL_LOCK, urand(15*IN_MILLISECONDS, 30*IN_MILLISECONDS)); } - void UpdateAI(const uint32 diff) + void UpdateAI(uint32 diff) { if (!UpdateVictim()) return; @@ -2206,7 +2206,7 @@ class mob_toc_pet_hunter : public CreatureScript _clawTimer = urand(5*IN_MILLISECONDS, 10*IN_MILLISECONDS); } - void UpdateAI(const uint32 diff) + void UpdateAI(uint32 diff) { if (!UpdateVictim()) return; diff --git a/src/server/scripts/Northrend/CrusadersColiseum/TrialOfTheCrusader/boss_lord_jaraxxus.cpp b/src/server/scripts/Northrend/CrusadersColiseum/TrialOfTheCrusader/boss_lord_jaraxxus.cpp index ac520968db8..74324d6c515 100644 --- a/src/server/scripts/Northrend/CrusadersColiseum/TrialOfTheCrusader/boss_lord_jaraxxus.cpp +++ b/src/server/scripts/Northrend/CrusadersColiseum/TrialOfTheCrusader/boss_lord_jaraxxus.cpp @@ -18,8 +18,9 @@ #include "ScriptMgr.h" #include "ScriptedCreature.h" -#include "trial_of_the_crusader.h" #include "SpellScript.h" +#include "Player.h" +#include "trial_of_the_crusader.h" enum Yells { @@ -69,7 +70,6 @@ enum BossSpells SPELL_FEL_INFERNO = 67047, SPELL_FEL_STREAK = 66494, SPELL_LORD_HITTIN = 66326, // special effect preventing more specific spells be cast on the same player within 10 seconds - SPELL_MISTRESS_KISS_DEBUFF = 66334, SPELL_MISTRESS_KISS_DAMAGE_SILENCE = 66359 }; @@ -149,7 +149,7 @@ class boss_jaraxxus : public CreatureScript Talk(SAY_AGGRO); } - void UpdateAI(const uint32 diff) + void UpdateAI(uint32 diff) { if (!UpdateVictim()) return; @@ -182,7 +182,7 @@ class boss_jaraxxus : public CreatureScript events.ScheduleEvent(EVENT_INCINERATE_FLESH, urand(20*IN_MILLISECONDS, 25*IN_MILLISECONDS)); return; case EVENT_NETHER_POWER: - me->CastCustomSpell(SPELL_NETHER_POWER, SPELLVALUE_AURA_STACK, RAID_MODE<uint32>(5, 10, 5,10), me, true); + me->CastCustomSpell(SPELL_NETHER_POWER, SPELLVALUE_AURA_STACK, RAID_MODE<uint32>(5, 10, 5, 10), me, true); events.ScheduleEvent(EVENT_NETHER_POWER, 40*IN_MILLISECONDS); return; case EVENT_LEGION_FLAME: @@ -223,10 +223,11 @@ class mob_legion_flame : public CreatureScript public: mob_legion_flame() : CreatureScript("mob_legion_flame") { } - struct mob_legion_flameAI : public Scripted_NoMovementAI + struct mob_legion_flameAI : public ScriptedAI { - mob_legion_flameAI(Creature* creature) : Scripted_NoMovementAI(creature) + mob_legion_flameAI(Creature* creature) : ScriptedAI(creature) { + SetCombatMovement(false); _instance = creature->GetInstanceScript(); } @@ -237,7 +238,7 @@ class mob_legion_flame : public CreatureScript DoCast(SPELL_LEGION_FLAME_EFFECT); } - void UpdateAI(const uint32 /*diff*/) + void UpdateAI(uint32 /*diff*/) { UpdateVictim(); if (_instance && _instance->GetBossState(BOSS_JARAXXUS) != IN_PROGRESS) @@ -258,10 +259,11 @@ class mob_infernal_volcano : public CreatureScript public: mob_infernal_volcano() : CreatureScript("mob_infernal_volcano") { } - struct mob_infernal_volcanoAI : public Scripted_NoMovementAI + struct mob_infernal_volcanoAI : public ScriptedAI { - mob_infernal_volcanoAI(Creature* creature) : Scripted_NoMovementAI(creature), _summons(me) + mob_infernal_volcanoAI(Creature* creature) : ScriptedAI(creature), _summons(me) { + SetCombatMovement(false); } void Reset() @@ -294,7 +296,7 @@ class mob_infernal_volcano : public CreatureScript me->DespawnOrUnsummon(); } - void UpdateAI(uint32 const /*diff*/) {} + void UpdateAI(uint32 /*diff*/) {} private: SummonList _summons; @@ -324,7 +326,7 @@ class mob_fel_infernal : public CreatureScript me->SetInCombatWithZone(); } - void UpdateAI(const uint32 diff) + void UpdateAI(uint32 diff) { if (_instance && _instance->GetBossState(BOSS_JARAXXUS) != IN_PROGRESS) { @@ -398,7 +400,7 @@ class mob_nether_portal : public CreatureScript me->DespawnOrUnsummon(); } - void UpdateAI(uint32 const /*diff*/) {} + void UpdateAI(uint32 /*diff*/) {} private: SummonList _summons; @@ -439,7 +441,7 @@ class mob_mistress_of_pain : public CreatureScript _instance->SetData(DATA_MISTRESS_OF_PAIN_COUNT, DECREASE); } - void UpdateAI(const uint32 diff) + void UpdateAI(uint32 diff) { if (_instance && _instance->GetBossState(BOSS_JARAXXUS) != IN_PROGRESS) { @@ -533,6 +535,21 @@ class spell_mistress_kiss : public SpellScriptLoader } }; +class MistressKissTargetSelector +{ + public: + MistressKissTargetSelector() { } + + bool operator()(WorldObject* unit) const + { + if (unit->GetTypeId() == TYPEID_PLAYER) + if (unit->ToPlayer()->getPowerType() == POWER_MANA) + return false; + + return true; + } +}; + class spell_mistress_kiss_area : public SpellScriptLoader { public: @@ -542,44 +559,27 @@ class spell_mistress_kiss_area : public SpellScriptLoader { PrepareSpellScript(spell_mistress_kiss_area_SpellScript) - bool Load() + void FilterTargets(std::list<WorldObject*>& targets) { - if (GetCaster()) - if (sSpellMgr->GetSpellIdForDifficulty(SPELL_MISTRESS_KISS_DEBUFF, GetCaster())) - return true; - return false; - } + // get a list of players with mana + targets.remove_if(MistressKissTargetSelector()); + if (targets.empty()) + return; - void HandleScript(SpellEffIndex /*effIndex*/) - { - Unit* caster = GetCaster(); - Unit* target = GetHitUnit(); - if (caster && target) - caster->CastSpell(target, SPELL_MISTRESS_KISS_DEBUFF, true); + WorldObject* target = Trinity::Containers::SelectRandomContainerElement(targets); + targets.clear(); + targets.push_back(target); } - void FilterTargets(std::list<WorldObject*>& targets) + void HandleScript(SpellEffIndex /*effIndex*/) { - // get a list of players with mana - std::list<WorldObject*> _targets; - for (std::list<WorldObject*>::iterator itr = targets.begin(); itr != targets.end(); ++itr) - if ((*itr)->ToUnit()->getPowerType() == POWER_MANA) - _targets.push_back(*itr); - - // pick a random target and kiss him - if (WorldObject* _target = Trinity::Containers::SelectRandomContainerElement(_targets)) - { - // correctly fill "targets" for the visual effect - targets.clear(); - targets.push_back(_target); - if (Unit* caster = GetCaster()) - caster->CastSpell(_target->ToUnit(), SPELL_MISTRESS_KISS_DEBUFF, true); - } + GetCaster()->CastSpell(GetHitUnit(), uint32(GetEffectValue()), true); } void Register() { OnObjectAreaTargetSelect += SpellObjectAreaTargetSelectFn(spell_mistress_kiss_area_SpellScript::FilterTargets, EFFECT_0, TARGET_UNIT_SRC_AREA_ENEMY); + OnEffectHitTarget += SpellEffectFn(spell_mistress_kiss_area_SpellScript::HandleScript, EFFECT_0, SPELL_EFFECT_SCRIPT_EFFECT); } }; diff --git a/src/server/scripts/Northrend/CrusadersColiseum/TrialOfTheCrusader/boss_northrend_beasts.cpp b/src/server/scripts/Northrend/CrusadersColiseum/TrialOfTheCrusader/boss_northrend_beasts.cpp index 03a305356c4..c39b8403474 100644 --- a/src/server/scripts/Northrend/CrusadersColiseum/TrialOfTheCrusader/boss_northrend_beasts.cpp +++ b/src/server/scripts/Northrend/CrusadersColiseum/TrialOfTheCrusader/boss_northrend_beasts.cpp @@ -146,10 +146,7 @@ enum Phases { PHASE_MOBILE = 1, PHASE_STATIONARY = 2, - PHASE_SUBMERGED = 3, - - PHASE_MASK_MOBILE = 1 << PHASE_MOBILE, - PHASE_MASK_STATIONARY = 1 << PHASE_STATIONARY + PHASE_SUBMERGED = 3 }; class boss_gormok : public CreatureScript @@ -238,7 +235,7 @@ class boss_gormok : public CreatureScript pSnobold->ToCreature()->DespawnOrUnsummon(); } - void UpdateAI(uint32 const diff) + void UpdateAI(uint32 diff) { if (!UpdateVictim()) return; @@ -362,7 +359,7 @@ class mob_snobold_vassal : public CreatureScript _instance->SetData(DATA_SNOBOLD_COUNT, DECREASE); } - void DoAction(int32 const action) + void DoAction(int32 action) { switch (action) { @@ -377,7 +374,7 @@ class mob_snobold_vassal : public CreatureScript } } - void UpdateAI(uint32 const diff) + void UpdateAI(uint32 diff) { if (!UpdateVictim() || _targetDied) return; @@ -484,7 +481,7 @@ class npc_firebomb : public CreatureScript me->SetDisplayId(me->GetCreatureTemplate()->Modelid2); } - void UpdateAI(uint32 const /*diff*/) + void UpdateAI(uint32 /*diff*/) { if (_instance->GetData(TYPE_NORTHREND_BEASTS) != GORMOK_IN_PROGRESS) me->DespawnOrUnsummon(); @@ -561,7 +558,7 @@ struct boss_jormungarAI : public BossAI instance->SetData(TYPE_NORTHREND_BEASTS, SNAKES_IN_PROGRESS); } - void UpdateAI(uint32 const diff) + void UpdateAI(uint32 diff) { if (!UpdateVictim()) return; @@ -624,9 +621,9 @@ struct boss_jormungarAI : public BossAI return; } } - if (events.GetPhaseMask() & PHASE_MASK_MOBILE) + if (events.IsInPhase(PHASE_MOBILE)) DoMeleeAttackIfReady(); - if (events.GetPhaseMask() & PHASE_MASK_STATIONARY) + if (events.IsInPhase(PHASE_STATIONARY)) DoSpellAttackIfReady(SpitSpell); } @@ -807,7 +804,7 @@ class mob_slime_pool : public CreatureScript me->SetReactState(REACT_PASSIVE); } - void UpdateAI(uint32 const /*diff*/) + void UpdateAI(uint32 /*diff*/) { if (!_cast) { @@ -975,7 +972,7 @@ class boss_icehowl : public CreatureScript } } - void UpdateAI(uint32 const diff) + void UpdateAI(uint32 diff) { if (!UpdateVictim()) return; diff --git a/src/server/scripts/Northrend/CrusadersColiseum/TrialOfTheCrusader/boss_twin_valkyr.cpp b/src/server/scripts/Northrend/CrusadersColiseum/TrialOfTheCrusader/boss_twin_valkyr.cpp index 9b6f4a6a0da..b41e986741b 100644 --- a/src/server/scripts/Northrend/CrusadersColiseum/TrialOfTheCrusader/boss_twin_valkyr.cpp +++ b/src/server/scripts/Northrend/CrusadersColiseum/TrialOfTheCrusader/boss_twin_valkyr.cpp @@ -270,7 +270,7 @@ struct boss_twin_baseAI : public BossAI DoCast(me, SurgeSpellId); } - void DoAction(const int32 action) + void DoAction(int32 action) { switch (action) { @@ -292,7 +292,7 @@ struct boss_twin_baseAI : public BossAI me->UpdateDamagePhysical(mode ? OFF_ATTACK : BASE_ATTACK); } - void UpdateAI(const uint32 diff) + void UpdateAI(uint32 diff) { if (!instance || !UpdateVictim()) return; @@ -594,7 +594,7 @@ class mob_unleashed_dark : public CreatureScript { mob_unleashed_darkAI(Creature* creature) : mob_unleashed_ballAI(creature) {} - void UpdateAI(const uint32 diff) + void UpdateAI(uint32 diff) { if (RangeCheckTimer < diff) { @@ -626,7 +626,7 @@ class mob_unleashed_light : public CreatureScript { mob_unleashed_lightAI(Creature* creature) : mob_unleashed_ballAI(creature) {} - void UpdateAI(const uint32 diff) + void UpdateAI(uint32 diff) { if (RangeCheckTimer < diff) { @@ -654,11 +654,11 @@ class mob_bullet_controller : public CreatureScript public: mob_bullet_controller() : CreatureScript("mob_bullet_controller") { } - struct mob_bullet_controllerAI : public Scripted_NoMovementAI + struct mob_bullet_controllerAI : public ScriptedAI { - mob_bullet_controllerAI(Creature* creature) : Scripted_NoMovementAI(creature) + mob_bullet_controllerAI(Creature* creature) : ScriptedAI(creature) { - Reset(); + SetCombatMovement(false); } void Reset() @@ -666,7 +666,7 @@ class mob_bullet_controller : public CreatureScript DoCastAOE(SPELL_CONTROLLER_PERIODIC); } - void UpdateAI(const uint32 /*diff*/) + void UpdateAI(uint32 /*diff*/) { UpdateVictim(); } diff --git a/src/server/scripts/Northrend/CrusadersColiseum/TrialOfTheCrusader/instance_trial_of_the_crusader.cpp b/src/server/scripts/Northrend/CrusadersColiseum/TrialOfTheCrusader/instance_trial_of_the_crusader.cpp index 8d2d9f8b4c1..172423187e1 100644 --- a/src/server/scripts/Northrend/CrusadersColiseum/TrialOfTheCrusader/instance_trial_of_the_crusader.cpp +++ b/src/server/scripts/Northrend/CrusadersColiseum/TrialOfTheCrusader/instance_trial_of_the_crusader.cpp @@ -263,6 +263,8 @@ class instance_trial_of_the_crusader : public InstanceMapScript if (ResilienceWillFixItTimer > 0) DoUpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_BE_SPELL_TARGET, SPELL_CHAMPIONS_KILLED_IN_MINUTE); DoRespawnGameObject(CrusadersCacheGUID, 7*DAY); + if (GameObject* cache = instance->GetGameObject(CrusadersCacheGUID)) + cache->RemoveFlag(GAMEOBJECT_FLAGS, GO_FLAG_NOT_SELECTABLE); EventStage = 3100; break; default: diff --git a/src/server/scripts/Northrend/CrusadersColiseum/TrialOfTheCrusader/trial_of_the_crusader.cpp b/src/server/scripts/Northrend/CrusadersColiseum/TrialOfTheCrusader/trial_of_the_crusader.cpp index 3e3fbf51cd0..a68ea1025d5 100644 --- a/src/server/scripts/Northrend/CrusadersColiseum/TrialOfTheCrusader/trial_of_the_crusader.cpp +++ b/src/server/scripts/Northrend/CrusadersColiseum/TrialOfTheCrusader/trial_of_the_crusader.cpp @@ -267,7 +267,7 @@ class boss_lich_king_toc : public CreatureScript } } - void UpdateAI(const uint32 uiDiff) + void UpdateAI(uint32 uiDiff) { if (!_instance) return; @@ -415,7 +415,7 @@ class npc_fizzlebang_toc : public CreatureScript _summons.Summon(summoned); } - void UpdateAI(const uint32 uiDiff) + void UpdateAI(uint32 uiDiff) { if (!_instance) return; @@ -548,7 +548,7 @@ class npc_tirion_toc : public CreatureScript void AttackStart(Unit* /*who*/) {} - void UpdateAI(const uint32 uiDiff) + void UpdateAI(uint32 uiDiff) { if (!_instance) return; @@ -836,7 +836,7 @@ class npc_garrosh_toc : public CreatureScript void AttackStart(Unit* /*who*/) {} - void UpdateAI(const uint32 uiDiff) + void UpdateAI(uint32 uiDiff) { if (!_instance) return; @@ -920,7 +920,7 @@ class npc_varian_toc : public CreatureScript void AttackStart(Unit* /*who*/) {} - void UpdateAI(const uint32 uiDiff) + void UpdateAI(uint32 uiDiff) { if (!_instance) return; diff --git a/src/server/scripts/Northrend/CrusadersColiseum/TrialOfTheCrusader/trial_of_the_crusader.h b/src/server/scripts/Northrend/CrusadersColiseum/TrialOfTheCrusader/trial_of_the_crusader.h index 70fe03c5e0f..f42c985d3e5 100644 --- a/src/server/scripts/Northrend/CrusadersColiseum/TrialOfTheCrusader/trial_of_the_crusader.h +++ b/src/server/scripts/Northrend/CrusadersColiseum/TrialOfTheCrusader/trial_of_the_crusader.h @@ -136,8 +136,8 @@ const Position AnubarakLoc[]= const Position EndSpawnLoc[]= { {648.9167f, 131.0208f, 141.6161f, 0}, // 0 - Highlord Tirion Fordring - {649.1614f, 142.0399f, 141.3057f ,0}, // 1 - Argent Mage - {644.6250f, 149.2743f, 140.6015f ,0} // 2 - Portal to Dalaran + {649.1614f, 142.0399f, 141.3057f, 0}, // 1 - Argent Mage + {644.6250f, 149.2743f, 140.6015f, 0} // 2 - Portal to Dalaran }; enum euiWorldStates diff --git a/src/server/scripts/Northrend/DraktharonKeep/boss_dred.cpp b/src/server/scripts/Northrend/DraktharonKeep/boss_dred.cpp index 6cb970f6ab7..923f8a23d6f 100644 --- a/src/server/scripts/Northrend/DraktharonKeep/boss_dred.cpp +++ b/src/server/scripts/Northrend/DraktharonKeep/boss_dred.cpp @@ -86,7 +86,7 @@ class boss_dred : public CreatureScript instance->SetData(DATA_DRED_EVENT, IN_PROGRESS); } - void UpdateAI(uint32 const diff) + void UpdateAI(uint32 diff) { if (!UpdateVictim()) return; @@ -148,7 +148,7 @@ class boss_dred : public CreatureScript DoMeleeAttackIfReady(); } - void DoAction(int32 const action) + void DoAction(int32 action) { if (action == ACTION_RAPTOR_KILLED) ++raptorsKilled; @@ -196,7 +196,7 @@ class npc_drakkari_gutripper : public CreatureScript GutRipTimer = urand(10000, 15000); } - void UpdateAI(uint32 const diff) + void UpdateAI(uint32 diff) { if (!UpdateVictim()) return; @@ -246,7 +246,7 @@ class npc_drakkari_scytheclaw : public CreatureScript uiRendTimer = urand(10000, 15000); } - void UpdateAI(uint32 const diff) + void UpdateAI(uint32 diff) { if (!UpdateVictim()) return; diff --git a/src/server/scripts/Northrend/DraktharonKeep/boss_novos.cpp b/src/server/scripts/Northrend/DraktharonKeep/boss_novos.cpp index e99128fbbf9..6eedfb357db 100644 --- a/src/server/scripts/Northrend/DraktharonKeep/boss_novos.cpp +++ b/src/server/scripts/Northrend/DraktharonKeep/boss_novos.cpp @@ -112,7 +112,7 @@ public: DoStartNoMovement(target); } - void UpdateAI(const uint32 diff) + void UpdateAI(uint32 diff) { if (!UpdateVictim() || _bubbled) return; @@ -141,7 +141,7 @@ public: } } - void DoAction(int32 const action) + void DoAction(int32 action) { if (action == ACTION_CRYSTAL_HANDLER_DIED) CrystalHandlerDied(); @@ -279,7 +279,7 @@ public: _temp = 0; } - void UpdateAI(const uint32 diff) + void UpdateAI(uint32 diff) { if (_spell) { diff --git a/src/server/scripts/Northrend/DraktharonKeep/boss_tharon_ja.cpp b/src/server/scripts/Northrend/DraktharonKeep/boss_tharon_ja.cpp index 1f30b805f8a..0ca7ccd196a 100644 --- a/src/server/scripts/Northrend/DraktharonKeep/boss_tharon_ja.cpp +++ b/src/server/scripts/Northrend/DraktharonKeep/boss_tharon_ja.cpp @@ -107,7 +107,7 @@ public: instance->SetData(DATA_THARON_JA_EVENT, IN_PROGRESS); } - void UpdateAI(const uint32 diff) + void UpdateAI(uint32 diff) { //Return since we have no target if (!UpdateVictim()) diff --git a/src/server/scripts/Northrend/DraktharonKeep/boss_trollgore.cpp b/src/server/scripts/Northrend/DraktharonKeep/boss_trollgore.cpp index bcec5fc1547..3dcac3f68dc 100644 --- a/src/server/scripts/Northrend/DraktharonKeep/boss_trollgore.cpp +++ b/src/server/scripts/Northrend/DraktharonKeep/boss_trollgore.cpp @@ -16,7 +16,7 @@ */ /* - * Comment: TODO: spawn troll waves + * Comment: @todo spawn troll waves */ #include "ScriptMgr.h" @@ -108,7 +108,7 @@ public: instance->SetData(DATA_TROLLGORE_EVENT, IN_PROGRESS); } - void UpdateAI(const uint32 diff) + void UpdateAI(uint32 diff) { //Return since we have no target if (!UpdateVictim()) diff --git a/src/server/scripts/Northrend/FrozenHalls/ForgeOfSouls/boss_bronjahm.cpp b/src/server/scripts/Northrend/FrozenHalls/ForgeOfSouls/boss_bronjahm.cpp index 261eb854aa3..516a3e0f7c9 100644 --- a/src/server/scripts/Northrend/FrozenHalls/ForgeOfSouls/boss_bronjahm.cpp +++ b/src/server/scripts/Northrend/FrozenHalls/ForgeOfSouls/boss_bronjahm.cpp @@ -118,7 +118,7 @@ class boss_bronjahm : public CreatureScript void DamageTaken(Unit* /*attacker*/, uint32& /*damage*/) { - if (events.GetPhaseMask() & (1 << PHASE_1) && !HealthAbovePct(30)) + if (events.IsInPhase(PHASE_1) && !HealthAbovePct(30)) { events.SetPhase(PHASE_2); DoCast(me, SPELL_TELEPORT); @@ -136,7 +136,7 @@ class boss_bronjahm : public CreatureScript summon->CastSpell(summon, SPELL_PURPLE_BANISH_VISUAL, true); } - void UpdateAI(const uint32 diff) + void UpdateAI(uint32 diff) { if (!UpdateVictim()) return; diff --git a/src/server/scripts/Northrend/FrozenHalls/ForgeOfSouls/boss_devourer_of_souls.cpp b/src/server/scripts/Northrend/FrozenHalls/ForgeOfSouls/boss_devourer_of_souls.cpp index caf38fd2418..61a654ec2bb 100644 --- a/src/server/scripts/Northrend/FrozenHalls/ForgeOfSouls/boss_devourer_of_souls.cpp +++ b/src/server/scripts/Northrend/FrozenHalls/ForgeOfSouls/boss_devourer_of_souls.cpp @@ -22,7 +22,7 @@ #include "SpellInfo.h" /* - * TODO: + * @todo * - Fix model id during unleash soul -> seems DB issue 36503 is missing (likewise 36504 is also missing). * - Fix outro npc movement */ @@ -109,7 +109,7 @@ struct outroPosition { { 0, 0 }, { 0.0f, 0.0f, 0.0f, 0.0f } } }; -Position const CrucibleSummonPos = {5672.294f,2520.686f, 713.4386f, 0.9599311f}; +Position const CrucibleSummonPos = {5672.294f, 2520.686f, 713.4386f, 0.9599311f}; #define DATA_THREE_FACED 1 @@ -247,7 +247,7 @@ class boss_devourer_of_souls : public CreatureScript return 0; } - void UpdateAI(const uint32 diff) + void UpdateAI(uint32 diff) { // Return since we have no target if (!UpdateVictim()) diff --git a/src/server/scripts/Northrend/FrozenHalls/ForgeOfSouls/forge_of_souls.cpp b/src/server/scripts/Northrend/FrozenHalls/ForgeOfSouls/forge_of_souls.cpp index b5d95dfb0f6..efc687eb409 100644 --- a/src/server/scripts/Northrend/FrozenHalls/ForgeOfSouls/forge_of_souls.cpp +++ b/src/server/scripts/Northrend/FrozenHalls/ForgeOfSouls/forge_of_souls.cpp @@ -95,7 +95,7 @@ public: phase = PHASE_NORMAL; } - void DoAction(const int32 actionId) + void DoAction(int32 actionId) { switch (actionId) { @@ -109,7 +109,7 @@ public: } } - void UpdateAI(const uint32 diff) + void UpdateAI(uint32 diff) { if (phase == PHASE_INTRO) { @@ -221,7 +221,7 @@ public: phase = PHASE_NORMAL; } - void DoAction(const int32 actionId) + void DoAction(int32 actionId) { switch (actionId) { @@ -235,7 +235,7 @@ public: } } - void UpdateAI(const uint32 diff) + void UpdateAI(uint32 diff) { if (phase == PHASE_INTRO) { diff --git a/src/server/scripts/Northrend/FrozenHalls/HallsOfReflection/boss_falric.cpp b/src/server/scripts/Northrend/FrozenHalls/HallsOfReflection/boss_falric.cpp index 2278bfe409a..58dc74d0f0a 100644 --- a/src/server/scripts/Northrend/FrozenHalls/HallsOfReflection/boss_falric.cpp +++ b/src/server/scripts/Northrend/FrozenHalls/HallsOfReflection/boss_falric.cpp @@ -34,7 +34,7 @@ enum Spells SPELL_IMPENDING_DESPAIR = 72426, SPELL_DEFILING_HORROR = 72435, SPELL_HOPELESSNESS = 72395, - H_SPELL_HOPELESSNESS = 72390, // TODO: not in dbc. Add in DB. + H_SPELL_HOPELESSNESS = 72390, /// @todo not in dbc. Add in DB. }; enum Events @@ -79,7 +79,7 @@ public: events.ScheduleEvent(EVENT_QUIVERING_STRIKE, 23000); events.ScheduleEvent(EVENT_IMPENDING_DESPAIR, 9000); - events.ScheduleEvent(EVENT_DEFILING_HORROR, urand(25000, 45000)); // TODO adjust timer. + events.ScheduleEvent(EVENT_DEFILING_HORROR, urand(25000, 45000)); /// @todo adjust timer. } void JustDied(Unit* /*killer*/) @@ -95,7 +95,7 @@ public: Talk(SAY_SLAY); } - void UpdateAI(const uint32 diff) + void UpdateAI(uint32 diff) { // Return since we have no target if (!UpdateVictim()) @@ -122,7 +122,7 @@ public: break; case EVENT_DEFILING_HORROR: DoCast(SPELL_DEFILING_HORROR); - events.ScheduleEvent(EVENT_DEFILING_HORROR, urand(25000, 45000)); // TODO adjust timer. + events.ScheduleEvent(EVENT_DEFILING_HORROR, urand(25000, 45000)); /// @todo adjust timer. break; } diff --git a/src/server/scripts/Northrend/FrozenHalls/HallsOfReflection/boss_marwyn.cpp b/src/server/scripts/Northrend/FrozenHalls/HallsOfReflection/boss_marwyn.cpp index 1d7e405585f..08d5cf70ee1 100644 --- a/src/server/scripts/Northrend/FrozenHalls/HallsOfReflection/boss_marwyn.cpp +++ b/src/server/scripts/Northrend/FrozenHalls/HallsOfReflection/boss_marwyn.cpp @@ -72,10 +72,10 @@ public: if (instance) instance->SetData(DATA_MARWYN_EVENT, IN_PROGRESS); - events.ScheduleEvent(EVENT_OBLITERATE, 30000); // TODO Check timer + events.ScheduleEvent(EVENT_OBLITERATE, 30000); /// @todo Check timer events.ScheduleEvent(EVENT_WELL_OF_CORRUPTION, 13000); events.ScheduleEvent(EVENT_CORRUPTED_FLESH, 20000); - events.ScheduleEvent(EVENT_SHARED_SUFFERING, 20000); // TODO Check timer + events.ScheduleEvent(EVENT_SHARED_SUFFERING, 20000); /// @todo Check timer } void JustDied(Unit* /*killer*/) @@ -91,7 +91,7 @@ public: Talk(SAY_SLAY); } - void UpdateAI(const uint32 diff) + void UpdateAI(uint32 diff) { // Return since we have no target if (!UpdateVictim()) diff --git a/src/server/scripts/Northrend/FrozenHalls/HallsOfReflection/halls_of_reflection.cpp b/src/server/scripts/Northrend/FrozenHalls/HallsOfReflection/halls_of_reflection.cpp index e0a2f90b082..b140801d8f1 100644 --- a/src/server/scripts/Northrend/FrozenHalls/HallsOfReflection/halls_of_reflection.cpp +++ b/src/server/scripts/Northrend/FrozenHalls/HallsOfReflection/halls_of_reflection.cpp @@ -233,7 +233,7 @@ public: me->SetVisible(true); } - void DoAction(const int32 actionId) + void DoAction(int32 actionId) { switch (actionId) { @@ -246,7 +246,7 @@ public: } } - void UpdateAI(const uint32 diff) + void UpdateAI(uint32 diff) { events.Update(diff); switch (events.ExecuteEvent()) @@ -270,7 +270,7 @@ public: events.ScheduleEvent(EVENT_INTRO_A2_3, 10000); break; case EVENT_INTRO_A2_3: - // TODO: she's doing some kind of spell casting emote + /// @todo she's doing some kind of spell casting emote instance->HandleGameObject(instance->GetData64(DATA_FROSTMOURNE), true); events.ScheduleEvent(EVENT_INTRO_A2_4, 10000); break; @@ -367,7 +367,7 @@ public: break; case EVENT_INTRO_H2_3: Talk(SAY_SYLVANAS_INTRO_3); - // TODO: she's doing some kind of spell casting emote + /// @todo she's doing some kind of spell casting emote events.ScheduleEvent(EVENT_INTRO_H2_4, 6000); break; case EVENT_INTRO_H2_4: @@ -524,7 +524,7 @@ public: Talk(SAY_SYLVANAS_INTRO_END); me->GetMotionMaster()->MovePoint(0, LichKingSpawnPos); - // TODO: Loralen/Koreln shall run also + /// @todo Loralen/Koreln shall run also events.ScheduleEvent(EVENT_INTRO_END, 10000); break; @@ -537,7 +537,7 @@ public: break; case EVENT_SKIP_INTRO: - // TODO: implement + /// @todo implement if (Creature* pFalric = me->GetCreature(*me, instance->GetData64(DATA_FALRIC))) pFalric->SetVisible(true); @@ -545,7 +545,7 @@ public: pMarwyn->SetVisible(true); me->GetMotionMaster()->MovePoint(0, LichKingSpawnPos); - // TODO: Loralen/Koreln shall run also + /// @todo Loralen/Koreln shall run also events.ScheduleEvent(EVENT_INTRO_END, 15000); break; @@ -651,13 +651,13 @@ public: void EnterCombat(Unit* /*who*/) { - events.ScheduleEvent(EVENT_SHADOW_WORD_PAIN, 8000); // TODO: adjust timers + events.ScheduleEvent(EVENT_SHADOW_WORD_PAIN, 8000); /// @todo adjust timers events.ScheduleEvent(EVENT_CIRCLE_OF_DESTRUCTION, 12000); events.ScheduleEvent(EVENT_COWER_IN_FEAR, 10000); events.ScheduleEvent(EVENT_DARK_MENDING, 20000); } - void UpdateAI(const uint32 diff) + void UpdateAI(uint32 diff) { if (!UpdateVictim()) return; @@ -733,14 +733,14 @@ public: void EnterCombat(Unit* /*who*/) { - events.ScheduleEvent(EVENT_FIREBALL, 3000); // TODO: adjust timers + events.ScheduleEvent(EVENT_FIREBALL, 3000); /// @todo adjust timers events.ScheduleEvent(EVENT_FLAMESTRIKE, 6000); events.ScheduleEvent(EVENT_FROSTBOLT, 9000); events.ScheduleEvent(EVENT_CHAINS_OF_ICE, 12000); events.ScheduleEvent(EVENT_HALLUCINATION, 40000); } - void UpdateAI(const uint32 diff) + void UpdateAI(uint32 diff) { if (!UpdateVictim()) return; @@ -834,13 +834,13 @@ public: void EnterCombat(Unit* /*who*/) { - events.ScheduleEvent(EVENT_SHADOW_STEP, 8000); // TODO: adjust timers + events.ScheduleEvent(EVENT_SHADOW_STEP, 8000); /// @todo adjust timers events.ScheduleEvent(EVENT_DEADLY_POISON, 5000); events.ScheduleEvent(EVENT_ENVENOMED_DAGGER_THROW, 10000); events.ScheduleEvent(EVENT_KIDNEY_SHOT, 12000); } - void UpdateAI(const uint32 diff) + void UpdateAI(uint32 diff) { if (!UpdateVictim()) return; @@ -905,12 +905,12 @@ public: void EnterCombat(Unit* /*who*/) { - events.ScheduleEvent(EVENT_SPECTRAL_STRIKE, 5000); // TODO: adjust timers + events.ScheduleEvent(EVENT_SPECTRAL_STRIKE, 5000); /// @todo adjust timers events.ScheduleEvent(EVENT_SHIELD_BASH, 10000); events.ScheduleEvent(EVENT_TORTURED_ENRAGE, 15000); } - void UpdateAI(const uint32 diff) + void UpdateAI(uint32 diff) { if (!UpdateVictim()) return; @@ -970,13 +970,13 @@ public: void EnterCombat(Unit* /*who*/) { - events.ScheduleEvent(EVENT_SHOOT, 2000); // TODO: adjust timers + events.ScheduleEvent(EVENT_SHOOT, 2000); /// @todo adjust timers events.ScheduleEvent(EVENT_CURSED_ARROW, 10000); events.ScheduleEvent(EVENT_FROST_TRAP, 1000); events.ScheduleEvent(EVENT_ICE_SHOT, 15000); } - void UpdateAI(const uint32 diff) + void UpdateAI(uint32 diff) { if (!UpdateVictim()) return; diff --git a/src/server/scripts/Northrend/FrozenHalls/HallsOfReflection/halls_of_reflection.h b/src/server/scripts/Northrend/FrozenHalls/HallsOfReflection/halls_of_reflection.h index a8bd92cc070..2cab1cca214 100644 --- a/src/server/scripts/Northrend/FrozenHalls/HallsOfReflection/halls_of_reflection.h +++ b/src/server/scripts/Northrend/FrozenHalls/HallsOfReflection/halls_of_reflection.h @@ -102,7 +102,7 @@ struct boss_horAI : ScriptedAI uiDamage = 0; } - void DoAction(const int32 actionID) + void DoAction(int32 actionID) { switch (actionID) { diff --git a/src/server/scripts/Northrend/FrozenHalls/HallsOfReflection/instance_halls_of_reflection.cpp b/src/server/scripts/Northrend/FrozenHalls/HallsOfReflection/instance_halls_of_reflection.cpp index 3b910c39e38..dde3f7acc67 100644 --- a/src/server/scripts/Northrend/FrozenHalls/HallsOfReflection/instance_halls_of_reflection.cpp +++ b/src/server/scripts/Northrend/FrozenHalls/HallsOfReflection/instance_halls_of_reflection.cpp @@ -182,7 +182,7 @@ public: void OnGameObjectCreate(GameObject* go) { - // TODO: init state depending on encounters + /// @todo init state depending on encounters switch (go->GetEntry()) { case GO_FROSTMOURNE: @@ -364,7 +364,7 @@ public: DoUpdateWorldState(WORLD_STATE_HOR_WAVE_COUNT, uiWaveCount); HandleGameObject(uiFrontDoor, true); - // TODO + /// @todo // in case of wipe, the event is normally restarted by jumping into the center of the room. // As I can't find a trigger area there, just respawn Jaina/Sylvanas so the event may be restarted. if (Creature* pJaina = instance->GetCreature(uiJainaPart1)) @@ -385,7 +385,7 @@ public: summoner->SetVisible(true); - // TODO: do composition at random. # of spawn also depends on uiWaveCount + /// @todo do composition at random. # of spawn also depends on uiWaveCount // As of now, it is just one of each. index = urand(0, ENCOUNTER_WAVE_MERCENARY-1); summoner->SummonCreature(NPC_WAVE_MERCENARY, MercenarySpawnPos[index], TEMPSUMMON_TIMED_DESPAWN_OUT_OF_COMBAT, 0); @@ -417,7 +417,7 @@ public: AddWave(); break; case EVENT_START_LICH_KING: - // TODO + /// @todo break; } } diff --git a/src/server/scripts/Northrend/FrozenHalls/PitOfSaron/boss_forgemaster_garfrost.cpp b/src/server/scripts/Northrend/FrozenHalls/PitOfSaron/boss_forgemaster_garfrost.cpp index 160d45f5140..822adbb9201 100644 --- a/src/server/scripts/Northrend/FrozenHalls/PitOfSaron/boss_forgemaster_garfrost.cpp +++ b/src/server/scripts/Northrend/FrozenHalls/PitOfSaron/boss_forgemaster_garfrost.cpp @@ -52,11 +52,7 @@ enum Phases { PHASE_ONE = 1, PHASE_TWO = 2, - PHASE_THREE = 3, - - PHASE_ONE_MASK = 1 << PHASE_ONE, - PHASE_TWO_MASK = 1 << PHASE_TWO, - PHASE_THREE_MASK = 1 << PHASE_THREE, + PHASE_THREE = 3 }; enum MiscData @@ -136,7 +132,7 @@ enum Events void DamageTaken(Unit* /*attacker*/, uint32& /*uiDamage*/) { - if (events.GetPhaseMask() & PHASE_ONE_MASK && !HealthAbovePct(66)) + if (events.IsInPhase(PHASE_ONE) && !HealthAbovePct(66)) { events.SetPhase(PHASE_TWO); Talk(SAY_PHASE2); @@ -146,7 +142,7 @@ enum Events return; } - if (events.GetPhaseMask() & PHASE_TWO_MASK && !HealthAbovePct(33)) + if (events.IsInPhase(PHASE_TWO) && !HealthAbovePct(33)) { events.SetPhase(PHASE_THREE); Talk(SAY_PHASE3); @@ -162,12 +158,12 @@ enum Events if (type != EFFECT_MOTION_TYPE || id != POINT_FORGE) return; - if (events.GetPhaseMask() & PHASE_TWO_MASK) + if (events.IsInPhase(PHASE_TWO)) { DoCast(me, SPELL_FORGE_BLADE); SetEquipmentSlots(false, EQUIP_ID_SWORD); } - if (events.GetPhaseMask() & PHASE_THREE_MASK) + if (events.IsInPhase(PHASE_THREE)) { me->RemoveAurasDueToSpell(SPELL_FORGE_BLADE_HELPER); DoCast(me, SPELL_FORGE_MACE); @@ -190,7 +186,7 @@ enum Events return _permafrostStack; } - void UpdateAI(const uint32 diff) + void UpdateAI(uint32 diff) { if (!UpdateVictim()) return; @@ -226,15 +222,15 @@ enum Events break; case EVENT_JUMP: me->AttackStop(); - if (events.GetPhaseMask() & PHASE_TWO_MASK) + if (events.IsInPhase(PHASE_TWO)) me->GetMotionMaster()->MoveJump(northForgePos.GetPositionX(), northForgePos.GetPositionY(), northForgePos.GetPositionZ(), 25.0f, 15.0f); - else if (events.GetPhaseMask() & PHASE_THREE_MASK) + else if (events.IsInPhase(PHASE_THREE)) me->GetMotionMaster()->MoveJump(southForgePos.GetPositionX(), southForgePos.GetPositionY(), southForgePos.GetPositionZ(), 25.0f, 15.0f); break; case EVENT_RESUME_ATTACK: - if (events.GetPhaseMask() & PHASE_TWO_MASK) + if (events.IsInPhase(PHASE_THREE)) events.ScheduleEvent(EVENT_CHILLING_WAVE, 5000, 0, PHASE_TWO); - else if (events.GetPhaseMask() & PHASE_THREE_MASK) + else if (events.IsInPhase(PHASE_THREE)) events.ScheduleEvent(EVENT_DEEP_FREEZE, 10000, 0, PHASE_THREE); AttackStart(me->getVictim()); break; diff --git a/src/server/scripts/Northrend/FrozenHalls/PitOfSaron/boss_krickandick.cpp b/src/server/scripts/Northrend/FrozenHalls/PitOfSaron/boss_krickandick.cpp index f657c8e19b5..31a1e94357e 100644 --- a/src/server/scripts/Northrend/FrozenHalls/PitOfSaron/boss_krickandick.cpp +++ b/src/server/scripts/Northrend/FrozenHalls/PitOfSaron/boss_krickandick.cpp @@ -203,7 +203,7 @@ class boss_ick : public CreatureScript me->AddThreat(target, _tempThreat); } - void UpdateAI(const uint32 diff) + void UpdateAI(uint32 diff) { if (!me->isInCombat()) return; @@ -338,7 +338,7 @@ class boss_krick : public CreatureScript } } - void DoAction(const int32 actionId) + void DoAction(int32 actionId) { if (actionId == ACTION_OUTRO) { @@ -365,7 +365,7 @@ class boss_krick : public CreatureScript _events.ScheduleEvent(EVENT_OUTRO_1, 1000); } - void UpdateAI(const uint32 diff) + void UpdateAI(uint32 diff) { if (_phase != PHASE_OUTRO) return; @@ -448,7 +448,7 @@ class boss_krick : public CreatureScript break; case EVENT_OUTRO_9: Talk(SAY_KRICK_OUTRO_8); - // TODO: Tyrannus starts killing Krick. + /// @todo Tyrannus starts killing Krick. // there shall be some visual spell effect if (Creature* tyrannus = ObjectAccessor::GetCreature(*me, _tyrannusGUID)) tyrannus->CastSpell(me, SPELL_NECROMANTIC_POWER, true); //not sure if it's the right spell :/ diff --git a/src/server/scripts/Northrend/FrozenHalls/PitOfSaron/boss_scourgelord_tyrannus.cpp b/src/server/scripts/Northrend/FrozenHalls/PitOfSaron/boss_scourgelord_tyrannus.cpp index 783cc266509..3d22bac4376 100644 --- a/src/server/scripts/Northrend/FrozenHalls/PitOfSaron/boss_scourgelord_tyrannus.cpp +++ b/src/server/scripts/Northrend/FrozenHalls/PitOfSaron/boss_scourgelord_tyrannus.cpp @@ -54,7 +54,7 @@ enum Yells SAY_SYLVANAS_OUTRO_4 = 4 }; -enum Spelsl +enum Spells { SPELL_OVERLORD_BRAND = 69172, SPELL_OVERLORD_BRAND_HEAL = 69190, @@ -94,7 +94,7 @@ enum Phases PHASE_NONE = 0, PHASE_INTRO = 1, PHASE_COMBAT = 2, - PHASE_OUTRO = 3, + PHASE_OUTRO = 3 }; enum Actions @@ -168,7 +168,7 @@ class boss_tyrannus : public CreatureScript if (me->HasFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE)) return; - if (victim && me->Attack(victim, true) && !(events.GetPhaseMask() & (1 << PHASE_INTRO))) + if (victim && me->Attack(victim, true) && !events.IsInPhase(PHASE_INTRO)) me->GetMotionMaster()->MoveChase(victim); } @@ -201,7 +201,7 @@ class boss_tyrannus : public CreatureScript rimefang->AI()->DoAction(ACTION_END_COMBAT); } - void DoAction(const int32 actionId) + void DoAction(int32 actionId) { if (actionId == ACTION_START_INTRO) { @@ -215,9 +215,9 @@ class boss_tyrannus : public CreatureScript } } - void UpdateAI(const uint32 diff) + void UpdateAI(uint32 diff) { - if (!UpdateVictim() && !(events.GetPhaseMask() & (1 << PHASE_INTRO))) + if (!UpdateVictim() && !events.IsInPhase(PHASE_INTRO)) return; events.Update(diff); @@ -313,7 +313,7 @@ class boss_rimefang : public CreatureScript _vehicle->InstallAllAccessories(false); } - void DoAction(const int32 actionId) + void DoAction(int32 actionId) { if (actionId == ACTION_START_RIMEFANG) { @@ -335,9 +335,9 @@ class boss_rimefang : public CreatureScript } } - void UpdateAI(const uint32 diff) + void UpdateAI(uint32 diff) { - if (!UpdateVictim() && !(_events.GetPhaseMask() & (1 << PHASE_COMBAT))) + if (!UpdateVictim() && !_events.IsInPhase(PHASE_COMBAT)) return; _events.Update(diff); @@ -409,7 +409,7 @@ class player_overlord_brandAI : public PlayerAI me->CastCustomSpell(SPELL_OVERLORD_BRAND_HEAL, SPELLVALUE_BASE_POINT0, int32(addHealth*5.5f), tyrannus, true, NULL, NULL, tyrannus->GetGUID()); } - void UpdateAI(const uint32 /*diff*/) { } + void UpdateAI(uint32 /*diff*/) { } private: Creature* tyrannus; diff --git a/src/server/scripts/Northrend/FrozenHalls/PitOfSaron/pit_of_saron.cpp b/src/server/scripts/Northrend/FrozenHalls/PitOfSaron/pit_of_saron.cpp index 246d389e0e7..42d912e2bd2 100644 --- a/src/server/scripts/Northrend/FrozenHalls/PitOfSaron/pit_of_saron.cpp +++ b/src/server/scripts/Northrend/FrozenHalls/PitOfSaron/pit_of_saron.cpp @@ -60,7 +60,7 @@ class mob_ymirjar_flamebearer : public CreatureScript _events.ScheduleEvent(EVENT_TACTICAL_BLINK, 15000); } - void UpdateAI(const uint32 diff) + void UpdateAI(uint32 diff) { if (!UpdateVictim()) return; @@ -125,7 +125,7 @@ class mob_iceborn_protodrake : public CreatureScript _vehicle->RemoveAllPassengers(); } - void UpdateAI(const uint32 diff) + void UpdateAI(uint32 diff) { if (!UpdateVictim()) return; @@ -178,7 +178,7 @@ class mob_geist_ambusher : public CreatureScript DoCast(who, SPELL_LEAPING_FACE_MAUL); } - void UpdateAI(const uint32 diff) + void UpdateAI(uint32 diff) { if (!UpdateVictim()) return; diff --git a/src/server/scripts/Northrend/Gundrak/boss_drakkari_colossus.cpp b/src/server/scripts/Northrend/Gundrak/boss_drakkari_colossus.cpp index 58301df4ca2..1ec29224763 100644 --- a/src/server/scripts/Northrend/Gundrak/boss_drakkari_colossus.cpp +++ b/src/server/scripts/Northrend/Gundrak/boss_drakkari_colossus.cpp @@ -140,7 +140,7 @@ class boss_drakkari_colossus : public CreatureScript instance->SetData(DATA_DRAKKARI_COLOSSUS_EVENT, FAIL); } - void DoAction(const int32 action) + void DoAction(int32 action) { switch (action) { @@ -148,6 +148,7 @@ class boss_drakkari_colossus : public CreatureScript DoCast(SPELL_EMERGE); break; case ACTION_FREEZE_COLOSSUS: + me->GetMotionMaster()->Clear(); me->GetMotionMaster()->MoveIdle(); me->SetReactState(REACT_PASSIVE); @@ -207,7 +208,7 @@ class boss_drakkari_colossus : public CreatureScript introDone = data; } - void UpdateAI(const uint32 diff) + void UpdateAI(uint32 diff) { if (!UpdateVictim()) return; @@ -284,7 +285,7 @@ class boss_drakkari_elemental : public CreatureScript } } - void UpdateAI(const uint32 diff) + void UpdateAI(uint32 diff) { if (!UpdateVictim()) return; @@ -310,7 +311,7 @@ class boss_drakkari_elemental : public CreatureScript DoMeleeAttackIfReady(); } - void DoAction(const int32 action) + void DoAction(int32 action) { switch (action) { @@ -465,7 +466,7 @@ public: } } - void UpdateAI(const uint32 diff) + void UpdateAI(uint32 diff) { //Return since we have no target if (!UpdateVictim()) diff --git a/src/server/scripts/Northrend/Gundrak/boss_eck.cpp b/src/server/scripts/Northrend/Gundrak/boss_eck.cpp index d169fb163b2..df949c7a962 100644 --- a/src/server/scripts/Northrend/Gundrak/boss_eck.cpp +++ b/src/server/scripts/Northrend/Gundrak/boss_eck.cpp @@ -75,7 +75,7 @@ public: instance->SetData(DATA_ECK_THE_FEROCIOUS_EVENT, IN_PROGRESS); } - void UpdateAI(const uint32 diff) + void UpdateAI(uint32 diff) { //Return since we have no target if (!UpdateVictim()) diff --git a/src/server/scripts/Northrend/Gundrak/boss_gal_darah.cpp b/src/server/scripts/Northrend/Gundrak/boss_gal_darah.cpp index baba9d5396b..e4cdf89c165 100644 --- a/src/server/scripts/Northrend/Gundrak/boss_gal_darah.cpp +++ b/src/server/scripts/Northrend/Gundrak/boss_gal_darah.cpp @@ -127,7 +127,7 @@ public: instance->SetData(DATA_GAL_DARAH_EVENT, IN_PROGRESS); } - void UpdateAI(const uint32 diff) + void UpdateAI(uint32 diff) { if (!UpdateVictim()) return; diff --git a/src/server/scripts/Northrend/Gundrak/boss_moorabi.cpp b/src/server/scripts/Northrend/Gundrak/boss_moorabi.cpp index 8f325dafc82..97c75b5f391 100644 --- a/src/server/scripts/Northrend/Gundrak/boss_moorabi.cpp +++ b/src/server/scripts/Northrend/Gundrak/boss_moorabi.cpp @@ -91,7 +91,7 @@ public: instance->SetData(DATA_MOORABI_EVENT, IN_PROGRESS); } - void UpdateAI(const uint32 uiDiff) + void UpdateAI(uint32 uiDiff) { //Return since we have no target if (!UpdateVictim()) diff --git a/src/server/scripts/Northrend/Gundrak/boss_slad_ran.cpp b/src/server/scripts/Northrend/Gundrak/boss_slad_ran.cpp index 4acabc3b2b3..6deb0c20676 100644 --- a/src/server/scripts/Northrend/Gundrak/boss_slad_ran.cpp +++ b/src/server/scripts/Northrend/Gundrak/boss_slad_ran.cpp @@ -122,7 +122,7 @@ public: instance->SetData(DATA_SLAD_RAN_EVENT, IN_PROGRESS); } - void UpdateAI(const uint32 diff) + void UpdateAI(uint32 diff) { //Return since we have no target if (!UpdateVictim()) @@ -231,7 +231,7 @@ public: uiGripOfSladRanTimer = 1*IN_MILLISECONDS; } - void UpdateAI(const uint32 diff) + void UpdateAI(uint32 diff) { if (!UpdateVictim()) return; @@ -251,7 +251,7 @@ public: if (TempSummon* _me = me->ToTempSummon()) if (Creature* sladran = _me->GetSummoner()->ToCreature()) - sladran->AI()->SetGUID(target->GetGUID() ,DATA_SNAKES_WHYD_IT_HAVE_TO_BE_SNAKES); + sladran->AI()->SetGUID(target->GetGUID(), DATA_SNAKES_WHYD_IT_HAVE_TO_BE_SNAKES); me->DespawnOrUnsummon(); } @@ -286,7 +286,7 @@ public: uiVenomousBiteTimer = 2*IN_MILLISECONDS; } - void UpdateAI(const uint32 diff) + void UpdateAI(uint32 diff) { if (!UpdateVictim()) return; diff --git a/src/server/scripts/Northrend/IcecrownCitadel/boss_blood_prince_council.cpp b/src/server/scripts/Northrend/IcecrownCitadel/boss_blood_prince_council.cpp index cb073b1c569..833649b576d 100644 --- a/src/server/scripts/Northrend/IcecrownCitadel/boss_blood_prince_council.cpp +++ b/src/server/scripts/Northrend/IcecrownCitadel/boss_blood_prince_council.cpp @@ -282,7 +282,7 @@ class boss_blood_council_controller : public CreatureScript } } - void UpdateAI(uint32 const diff) + void UpdateAI(uint32 diff) { if (!UpdateVictim()) return; @@ -477,7 +477,7 @@ class boss_prince_keleseth_icc : public CreatureScript Talk(SAY_KELESETH_KILL); } - void DoAction(int32 const action) + void DoAction(int32 action) { switch (action) { @@ -522,7 +522,7 @@ class boss_prince_keleseth_icc : public CreatureScript return true; } - void UpdateAI(uint32 const diff) + void UpdateAI(uint32 diff) { if (!UpdateVictim() || !CheckRoom()) return; @@ -695,7 +695,7 @@ class boss_prince_taldaram_icc : public CreatureScript Talk(SAY_TALDARAM_KILL); } - void DoAction(int32 const action) + void DoAction(int32 action) { switch (action) { @@ -740,7 +740,7 @@ class boss_prince_taldaram_icc : public CreatureScript return true; } - void UpdateAI(uint32 const diff) + void UpdateAI(uint32 diff) { if (!UpdateVictim() || !CheckRoom()) return; @@ -933,7 +933,7 @@ class boss_prince_valanar_icc : public CreatureScript Talk(SAY_VALANAR_KILL); } - void DoAction(int32 const action) + void DoAction(int32 action) { switch (action) { @@ -978,7 +978,7 @@ class boss_prince_valanar_icc : public CreatureScript return true; } - void UpdateAI(uint32 const diff) + void UpdateAI(uint32 diff) { if (!UpdateVictim() || !CheckRoom()) return; @@ -1090,7 +1090,7 @@ class npc_blood_queen_lana_thel : public CreatureScript me->SetVisible(false); } - void UpdateAI(uint32 const diff) + void UpdateAI(uint32 diff) { if (!_events.GetPhaseMask()) return; @@ -1168,7 +1168,7 @@ class npc_ball_of_flame : public CreatureScript _chaseGUID = guid; } - void DoAction(int32 const action) + void DoAction(int32 action) { if (action == ACTION_FLAME_BALL_CHASE) if (Player* target = ObjectAccessor::GetPlayer(*me, _chaseGUID)) @@ -1189,7 +1189,7 @@ class npc_ball_of_flame : public CreatureScript _instance->SetData(DATA_ORB_WHISPERER_ACHIEVEMENT, uint32(false)); } - void UpdateAI(uint32 const diff) + void UpdateAI(uint32 diff) { if (!_despawnTimer) return; @@ -1236,7 +1236,7 @@ class npc_kinetic_bomb : public CreatureScript _groundZ = me->GetMap()->GetHeight(me->GetPhaseMask(), _x, _y, _groundZ, true, 500.0f); } - void DoAction(int32 const action) + void DoAction(int32 action) { if (action == SPELL_KINETIC_BOMB_EXPLOSION) _events.ScheduleEvent(EVENT_BOMB_DESPAWN, 1000); @@ -1248,7 +1248,7 @@ class npc_kinetic_bomb : public CreatureScript } } - void UpdateAI(uint32 const diff) + void UpdateAI(uint32 diff) { _events.Update(diff); @@ -1328,7 +1328,7 @@ class npc_dark_nucleus : public CreatureScript me->AddThreat(attacker, 500000000.0f); } - void UpdateAI(uint32 const diff) + void UpdateAI(uint32 diff) { if (!UpdateVictim()) return; diff --git a/src/server/scripts/Northrend/IcecrownCitadel/boss_blood_queen_lana_thel.cpp b/src/server/scripts/Northrend/IcecrownCitadel/boss_blood_queen_lana_thel.cpp index c8caa3976e4..f4df90c49e8 100644 --- a/src/server/scripts/Northrend/IcecrownCitadel/boss_blood_queen_lana_thel.cpp +++ b/src/server/scripts/Northrend/IcecrownCitadel/boss_blood_queen_lana_thel.cpp @@ -45,10 +45,13 @@ enum Spells SPELL_SHROUD_OF_SORROW = 70986, SPELL_FRENZIED_BLOODTHIRST_VISUAL = 71949, SPELL_VAMPIRIC_BITE = 71726, + SPELL_VAMPIRIC_BITE_DUMMY = 71837, SPELL_ESSENCE_OF_THE_BLOOD_QUEEN_PLR = 70879, + SPELL_ESSENCE_OF_THE_BLOOD_QUEEN_HEAL = 70872, SPELL_FRENZIED_BLOODTHIRST = 70877, SPELL_UNCONTROLLABLE_FRENZY = 70923, - SPELL_PRESENCE_OF_THE_DARKFALLEN = 71952, + SPELL_PRESENCE_OF_THE_DARKFALLEN = 70994, + SPELL_PRESENCE_OF_THE_DARKFALLEN_2 = 71952, SPELL_BLOOD_MIRROR_DAMAGE = 70821, SPELL_BLOOD_MIRROR_VISUAL = 71510, SPELL_BLOOD_MIRROR_DUMMY = 70838, @@ -87,6 +90,7 @@ uint32 const vampireAuras[3][MAX_DIFFICULTY] = #define ESSENCE_OF_BLOOD_QUEEN_PLR RAID_MODE<uint32>(70879, 71525, 71530, 71531) #define FRENZIED_BLOODTHIRST RAID_MODE<uint32>(70877, 71474, 70877, 71474) #define DELIRIOUS_SLASH RAID_MODE<uint32>(71623, 71624, 71625, 71626) +#define PRESENCE_OF_THE_DARKFALLEN RAID_MODE<uint32>(70994, 71962, 71963, 71964) enum Events { @@ -219,9 +223,10 @@ class boss_blood_queen_lana_thel : public CreatureScript instance->DoRemoveAurasDueToSpellOnPlayers(SPELL_BLOOD_MIRROR_DUMMY); instance->DoRemoveAurasDueToSpellOnPlayers(DELIRIOUS_SLASH); instance->DoRemoveAurasDueToSpellOnPlayers(SPELL_PACT_OF_THE_DARKFALLEN); + instance->DoRemoveAurasDueToSpellOnPlayers(PRESENCE_OF_THE_DARKFALLEN); } - void DoAction(int32 const action) + void DoAction(int32 action) { if (action != ACTION_KILL_MINCHAR) return; @@ -329,7 +334,7 @@ class boss_blood_queen_lana_thel : public CreatureScript } } - void UpdateAI(uint32 const diff) + void UpdateAI(uint32 diff) { if (!UpdateVictim() || !CheckInRoom()) return; @@ -356,8 +361,11 @@ class boss_blood_queen_lana_thel : public CreatureScript { Unit* target = targets.front(); DoCast(target, SPELL_VAMPIRIC_BITE); + DoCastAOE(SPELL_VAMPIRIC_BITE_DUMMY, true); Talk(SAY_VAMPIRIC_BITE); _vampires.insert(target->GetGUID()); + target->CastSpell(target, SPELL_PRESENCE_OF_THE_DARKFALLEN, TRIGGERED_FULL_MASK); + target->CastSpell(target, SPELL_PRESENCE_OF_THE_DARKFALLEN_2, TRIGGERED_FULL_MASK); } break; } @@ -376,9 +384,10 @@ class boss_blood_queen_lana_thel : public CreatureScript _offtank->CastSpell(me->getVictim(), SPELL_BLOOD_MIRROR_DAMAGE, true); me->getVictim()->CastSpell(_offtank, SPELL_BLOOD_MIRROR_DUMMY, true); DoCastVictim(SPELL_BLOOD_MIRROR_VISUAL); - if (Item* shadowsEdge = _offtank->GetWeaponForAttack(BASE_ATTACK, true)) - if (!_offtank->HasAura(SPELL_THIRST_QUENCHED) && shadowsEdge->GetEntry() == ITEM_SHADOW_S_EDGE && !_offtank->HasAura(SPELL_GUSHING_WOUND)) - _offtank->CastSpell(_offtank, SPELL_GUSHING_WOUND, true); + if (Is25ManRaid() && _offtank->GetQuestStatus(QUEST_BLOOD_INFUSION) == QUEST_STATUS_INCOMPLETE && + _offtank->HasAura(SPELL_UNSATED_CRAVING) && !_offtank->HasAura(SPELL_THIRST_QUENCHED) && + !_offtank->HasAura(SPELL_GUSHING_WOUND)) + _offtank->CastSpell(_offtank, SPELL_GUSHING_WOUND, TRIGGERED_FULL_MASK); } } @@ -395,13 +404,7 @@ class boss_blood_queen_lana_thel : public CreatureScript { std::list<Player*> targets; SelectRandomTarget(false, &targets); - uint32 targetCount = 2; - // do not combine these checks! we want it incremented TWICE when both conditions are met - if (IsHeroic()) - ++targetCount; - if (Is25ManRaid()) - ++targetCount; - Trinity::Containers::RandomResizeList<Player*>(targets, targetCount); + Trinity::Containers::RandomResizeList(targets, Is25ManRaid() ? 3 : 2); if (targets.size() > 1) { Talk(SAY_PACT_OF_THE_DARKFALLEN); @@ -478,7 +481,7 @@ class boss_blood_queen_lana_thel : public CreatureScript for (std::list<HostileReference*>::const_iterator itr = threatlist.begin(); itr != threatlist.end(); ++itr) if (Unit* refTarget = (*itr)->getTarget()) - if (refTarget != me->getVictim() && refTarget->GetTypeId() == TYPEID_PLAYER && (includeOfftank ? true : (refTarget != _offtank))) + if (refTarget != me->getVictim() && refTarget->GetTypeId() == TYPEID_PLAYER && (includeOfftank || (refTarget != _offtank))) tempTargets.push_back(refTarget->ToPlayer()); if (tempTargets.empty()) @@ -553,33 +556,36 @@ class spell_blood_queen_vampiric_bite : public SpellScriptLoader uint32 spellId = sSpellMgr->GetSpellIdForDifficulty(SPELL_FRENZIED_BLOODTHIRST, GetCaster()); GetCaster()->RemoveAura(spellId, 0, 0, AURA_REMOVE_BY_ENEMY_SPELL); - GetCaster()->CastSpell(GetCaster(), SPELL_ESSENCE_OF_THE_BLOOD_QUEEN_PLR, true); - // Presence of the Darkfallen buff on Blood-Queen - if (GetCaster()->GetMap()->IsHeroic()) - GetCaster()->CastSpell(GetCaster(), SPELL_PRESENCE_OF_THE_DARKFALLEN, true); + GetCaster()->CastSpell(GetCaster(), SPELL_ESSENCE_OF_THE_BLOOD_QUEEN_PLR, TRIGGERED_FULL_MASK); + // Shadowmourne questline - if (GetCaster()->ToPlayer()->GetQuestStatus(QUEST_BLOOD_INFUSION) == QUEST_STATUS_INCOMPLETE) + if (Aura* aura = GetCaster()->GetAura(SPELL_GUSHING_WOUND)) { - if (Aura* aura = GetCaster()->GetAura(SPELL_GUSHING_WOUND)) + if (aura->GetStackAmount() == 3) { - if (aura->GetStackAmount() == 3) - { - GetCaster()->CastSpell(GetCaster(), SPELL_THIRST_QUENCHED, true); - GetCaster()->RemoveAura(aura); - } - else - GetCaster()->CastSpell(GetCaster(), SPELL_GUSHING_WOUND, true); + GetCaster()->CastSpell(GetCaster(), SPELL_THIRST_QUENCHED, TRIGGERED_FULL_MASK); + GetCaster()->RemoveAura(aura); } + else + GetCaster()->CastSpell(GetCaster(), SPELL_GUSHING_WOUND, TRIGGERED_FULL_MASK); } + if (InstanceScript* instance = GetCaster()->GetInstanceScript()) if (Creature* bloodQueen = ObjectAccessor::GetCreature(*GetCaster(), instance->GetData64(DATA_BLOOD_QUEEN_LANA_THEL))) bloodQueen->AI()->SetGUID(GetHitUnit()->GetGUID(), GUID_VAMPIRE); } + void HandlePresence(SpellEffIndex /*effIndex*/) + { + GetHitUnit()->CastSpell(GetHitUnit(), SPELL_PRESENCE_OF_THE_DARKFALLEN, TRIGGERED_FULL_MASK); + GetHitUnit()->CastSpell(GetHitUnit(), SPELL_PRESENCE_OF_THE_DARKFALLEN_2, TRIGGERED_FULL_MASK); + } + void Register() { OnCheckCast += SpellCheckCastFn(spell_blood_queen_vampiric_bite_SpellScript::CheckTarget); BeforeHit += SpellHitFn(spell_blood_queen_vampiric_bite_SpellScript::OnCast); + OnEffectHitTarget += SpellEffectFn(spell_blood_queen_vampiric_bite_SpellScript::HandlePresence, EFFECT_1, SPELL_EFFECT_TRIGGER_SPELL); } }; @@ -698,6 +704,42 @@ class spell_blood_queen_bloodbolt : public SpellScriptLoader } }; +// 70871 - Essence of the Blood Queen +class spell_blood_queen_essence_of_the_blood_queen : public SpellScriptLoader +{ + public: + spell_blood_queen_essence_of_the_blood_queen() : SpellScriptLoader("spell_blood_queen_essence_of_the_blood_queen") { } + + class spell_blood_queen_essence_of_the_blood_queen_AuraScript : public AuraScript + { + PrepareAuraScript(spell_blood_queen_essence_of_the_blood_queen_AuraScript); + + bool Validate(SpellInfo const* /*spellInfo*/) + { + if (!sSpellMgr->GetSpellInfo(SPELL_ESSENCE_OF_THE_BLOOD_QUEEN_HEAL)) + return false; + return true; + } + + void OnProc(AuraEffect const* aurEff, ProcEventInfo& eventInfo) + { + PreventDefaultAction(); + int32 heal = CalculatePct(int32(eventInfo.GetDamageInfo()->GetDamage()), aurEff->GetAmount()); + GetTarget()->CastCustomSpell(SPELL_ESSENCE_OF_THE_BLOOD_QUEEN_HEAL, SPELLVALUE_BASE_POINT0, heal, GetTarget(), TRIGGERED_FULL_MASK, NULL, aurEff); + } + + void Register() + { + OnEffectProc += AuraEffectProcFn(spell_blood_queen_essence_of_the_blood_queen_AuraScript::OnProc, EFFECT_1, SPELL_AURA_DUMMY); + } + }; + + AuraScript* GetAuraScript() const + { + return new spell_blood_queen_essence_of_the_blood_queen_AuraScript(); + } +}; + class spell_blood_queen_pact_of_the_darkfallen : public SpellScriptLoader { public: @@ -849,6 +891,7 @@ void AddSC_boss_blood_queen_lana_thel() new spell_blood_queen_vampiric_bite(); new spell_blood_queen_frenzied_bloodthirst(); new spell_blood_queen_bloodbolt(); + new spell_blood_queen_essence_of_the_blood_queen(); new spell_blood_queen_pact_of_the_darkfallen(); new spell_blood_queen_pact_of_the_darkfallen_dmg(); new spell_blood_queen_pact_of_the_darkfallen_dmg_target(); diff --git a/src/server/scripts/Northrend/IcecrownCitadel/boss_deathbringer_saurfang.cpp b/src/server/scripts/Northrend/IcecrownCitadel/boss_deathbringer_saurfang.cpp index 23e4fc19dd2..f01c28766f9 100644 --- a/src/server/scripts/Northrend/IcecrownCitadel/boss_deathbringer_saurfang.cpp +++ b/src/server/scripts/Northrend/IcecrownCitadel/boss_deathbringer_saurfang.cpp @@ -63,7 +63,7 @@ enum ScriptTexts SAY_INTRO_ALLIANCE_1 = 0, SAY_INTRO_ALLIANCE_4 = 1, SAY_INTRO_ALLIANCE_5 = 2, - SAY_OUTRO_ALLIANCE_1 = 3, // TODO ALLIANCE OUTRO + SAY_OUTRO_ALLIANCE_1 = 3, /// @todo ALLIANCE OUTRO SAY_OUTRO_ALLIANCE_2 = 4, SAY_OUTRO_ALLIANCE_3 = 5, SAY_OUTRO_ALLIANCE_4 = 6, @@ -185,9 +185,7 @@ enum Phases { PHASE_INTRO_A = 1, PHASE_INTRO_H = 2, - PHASE_COMBAT = 3, - - PHASE_INTRO_MASK = (1 << PHASE_INTRO_A) | (1 << PHASE_INTRO_H), + PHASE_COMBAT = 3 }; enum Actions @@ -415,9 +413,16 @@ class boss_deathbringer_saurfang : public CreatureScript } } - void UpdateAI(uint32 const diff) + void SpellHit(Unit* /*caster*/, SpellInfo const* spell) + { + if (spell->Id == SPELL_BLOOD_LINK_POWER) + if (Aura* bloodPower = me->GetAura(SPELL_BLOOD_POWER)) + bloodPower->RecalculateAmountOfEffects(); + } + + void UpdateAI(uint32 diff) { - if (!UpdateVictim() && !(events.GetPhaseMask() & PHASE_INTRO_MASK)) + if (!UpdateVictim() && !(events.IsInPhase(PHASE_INTRO_A) || events.IsInPhase(PHASE_INTRO_H))) return; events.Update(diff); @@ -507,7 +512,7 @@ class boss_deathbringer_saurfang : public CreatureScript } // intro setup - void DoAction(int32 const action) + void DoAction(int32 action) { switch (action) { @@ -598,14 +603,14 @@ class npc_high_overlord_saurfang_icc : public CreatureScript _events.Reset(); } - void DoAction(int32 const action) + void DoAction(int32 action) { switch (action) { case ACTION_START_EVENT: { // Prevent crashes - if (_events.GetPhaseMask() & PHASE_INTRO_MASK) + if (_events.IsInPhase(PHASE_INTRO_A) || _events.IsInPhase(PHASE_INTRO_H)) return; GetCreatureListWithEntryInGrid(_guardList, me, NPC_SE_KOR_KRON_REAVER, 20.0f); @@ -703,7 +708,7 @@ class npc_high_overlord_saurfang_icc : public CreatureScript } } - void UpdateAI(uint32 const diff) + void UpdateAI(uint32 diff) { _events.Update(diff); while (uint32 eventId = _events.ExecuteEvent()) @@ -807,14 +812,14 @@ class npc_muradin_bronzebeard_icc : public CreatureScript _events.Reset(); } - void DoAction(int32 const action) + void DoAction(int32 action) { switch (action) { case ACTION_START_EVENT: { // Prevent crashes - if (_events.GetPhaseMask() & PHASE_INTRO_MASK) + if (_events.IsInPhase(PHASE_INTRO_A) || _events.IsInPhase(PHASE_INTRO_H)) return; _events.SetPhase(PHASE_INTRO_A); @@ -883,7 +888,7 @@ class npc_muradin_bronzebeard_icc : public CreatureScript } } - void UpdateAI(uint32 const diff) + void UpdateAI(uint32 diff) { _events.Update(diff); while (uint32 eventId = _events.ExecuteEvent()) @@ -965,7 +970,7 @@ class npc_saurfang_event : public CreatureScript } } - void DoAction(int32 const action) + void DoAction(int32 action) { if (action == ACTION_CHARGE && _index) me->GetMotionMaster()->MoveCharge(chargePos[_index].GetPositionX(), chargePos[_index].GetPositionY(), chargePos[_index].GetPositionZ(), 13.0f, POINT_CHARGE); @@ -1004,8 +1009,6 @@ class spell_deathbringer_blood_link : public SpellScriptLoader void HandleDummy(SpellEffIndex /*effIndex*/) { GetHitUnit()->CastCustomSpell(SPELL_BLOOD_LINK_POWER, SPELLVALUE_BASE_POINT0, GetEffectValue(), GetHitUnit(), true); - if (Aura* bloodPower = GetHitUnit()->GetAura(SPELL_BLOOD_POWER)) - bloodPower->RecalculateAmountOfEffects(); PreventHitDefaultEffect(EFFECT_0); } @@ -1093,13 +1096,6 @@ class spell_deathbringer_blood_power : public SpellScriptLoader DoEffectCalcAmount += AuraEffectCalcAmountFn(spell_deathbringer_blood_power_AuraScript::RecalculateHook, EFFECT_0, SPELL_AURA_MOD_SCALE); DoEffectCalcAmount += AuraEffectCalcAmountFn(spell_deathbringer_blood_power_AuraScript::RecalculateHook, EFFECT_1, SPELL_AURA_MOD_DAMAGE_PERCENT_DONE); } - - bool Load() - { - if (GetUnitOwner()->getPowerType() != POWER_ENERGY) - return false; - return true; - } }; SpellScript* GetSpellScript() const diff --git a/src/server/scripts/Northrend/IcecrownCitadel/boss_festergut.cpp b/src/server/scripts/Northrend/IcecrownCitadel/boss_festergut.cpp index 70cb585422d..4ec945fcb77 100644 --- a/src/server/scripts/Northrend/IcecrownCitadel/boss_festergut.cpp +++ b/src/server/scripts/Northrend/IcecrownCitadel/boss_festergut.cpp @@ -162,7 +162,7 @@ class boss_festergut : public CreatureScript target->RemoveAurasDueToSpell(INOCULATED_HELPER); } - void UpdateAI(uint32 const diff) + void UpdateAI(uint32 diff) { if (!UpdateVictim() || !CheckInRoom()) return; @@ -298,7 +298,7 @@ class npc_stinky_icc : public CreatureScript DoCast(me, SPELL_PLAGUE_STENCH); } - void UpdateAI(uint32 const diff) + void UpdateAI(uint32 diff) { if (!UpdateVictim()) return; diff --git a/src/server/scripts/Northrend/IcecrownCitadel/boss_lady_deathwhisper.cpp b/src/server/scripts/Northrend/IcecrownCitadel/boss_lady_deathwhisper.cpp index 4e677bf5b0e..59c9393c934 100644 --- a/src/server/scripts/Northrend/IcecrownCitadel/boss_lady_deathwhisper.cpp +++ b/src/server/scripts/Northrend/IcecrownCitadel/boss_lady_deathwhisper.cpp @@ -160,10 +160,7 @@ enum Phases PHASE_ALL = 0, PHASE_INTRO = 1, PHASE_ONE = 2, - PHASE_TWO = 3, - - PHASE_INTRO_MASK = 1 << PHASE_INTRO, - PHASE_ONE_MASK = 1 << PHASE_ONE, + PHASE_TWO = 3 }; enum DeprogrammingData @@ -259,7 +256,7 @@ class boss_lady_deathwhisper : public CreatureScript if (me->HasFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE)) return; - if (victim && me->Attack(victim, true) && !(events.GetPhaseMask() & PHASE_ONE_MASK)) + if (victim && me->Attack(victim, true) && !events.IsInPhase(PHASE_ONE)) me->GetMotionMaster()->MoveChase(victim); } @@ -358,7 +355,7 @@ class boss_lady_deathwhisper : public CreatureScript void DamageTaken(Unit* /*damageDealer*/, uint32& damage) { // phase transition - if (events.GetPhaseMask() & PHASE_ONE_MASK && damage > me->GetPower(POWER_MANA)) + if (events.IsInPhase(PHASE_ONE) && damage > me->GetPower(POWER_MANA)) { Talk(SAY_PHASE_2); Talk(EMOTE_PHASE_2); @@ -404,14 +401,14 @@ class boss_lady_deathwhisper : public CreatureScript summon->CastSpell(summon, SPELL_ADHERENT_S_DETERMINATION, true); } - void UpdateAI(uint32 const diff) + void UpdateAI(uint32 diff) { - if ((!UpdateVictim() && !(events.GetPhaseMask() & PHASE_INTRO_MASK)) || !CheckInRoom()) + if ((!UpdateVictim() && !events.IsInPhase(PHASE_INTRO)) || !CheckInRoom()) return; events.Update(diff); - if (me->HasUnitState(UNIT_STATE_CASTING) && !(events.GetPhaseMask() & PHASE_INTRO_MASK)) + if (me->HasUnitState(UNIT_STATE_CASTING) && !events.IsInPhase(PHASE_INTRO)) return; while (uint32 eventId = events.ExecuteEvent()) @@ -659,7 +656,7 @@ class npc_cult_fanatic : public CreatureScript } } - void UpdateAI(uint32 const diff) + void UpdateAI(uint32 diff) { if (!UpdateVictim()) return; @@ -737,7 +734,7 @@ class npc_cult_adherent : public CreatureScript } } - void UpdateAI(uint32 const diff) + void UpdateAI(uint32 diff) { if (!UpdateVictim()) return; @@ -882,7 +879,7 @@ class npc_darnavan : public CreatureScript Talk(SAY_DARNAVAN_AGGRO); } - void UpdateAI(const uint32 diff) + void UpdateAI(uint32 diff) { if (!UpdateVictim()) return; diff --git a/src/server/scripts/Northrend/IcecrownCitadel/boss_lord_marrowgar.cpp b/src/server/scripts/Northrend/IcecrownCitadel/boss_lord_marrowgar.cpp index e751ec2bd7b..7e72ad00a3c 100644 --- a/src/server/scripts/Northrend/IcecrownCitadel/boss_lord_marrowgar.cpp +++ b/src/server/scripts/Northrend/IcecrownCitadel/boss_lord_marrowgar.cpp @@ -20,8 +20,9 @@ #include "ScriptedCreature.h" #include "SpellAuras.h" #include "MapManager.h" -#include "icecrown_citadel.h" +#include "MoveSplineInit.h" #include "Player.h" +#include "icecrown_citadel.h" enum ScriptTexts { @@ -53,7 +54,7 @@ enum Spells SPELL_COLDFLAME_SUMMON = 69147, }; -uint32 const boneSpikeSummonId[3] = {69062, 72669, 72670}; +uint32 const BoneSpikeSummonId[3] = {69062, 72669, 72670}; enum Events { @@ -78,7 +79,46 @@ enum MovementPoints POINT_TARGET_COLDFLAME = 36672631, }; -#define DATA_COLDFLAME_GUID 0 +enum MiscInfo +{ + DATA_COLDFLAME_GUID = 0, + + // Manual marking for targets hit by Bone Slice as no aura exists for this purpose + // These units are the tanks in this encounter + // and should be immune to Bone Spike Graveyard + DATA_SPIKE_IMMUNE = 1, + //DATA_SPIKE_IMMUNE_1, = 2, // Reserved & used + //DATA_SPIKE_IMMUNE_2, = 3, // Reserved & used + + ACTION_CLEAR_SPIKE_IMMUNITIES = 1, + + MAX_BONE_SPIKE_IMMUNE = 3, +}; + +class BoneSpikeTargetSelector : public std::unary_function<Unit*, bool> +{ + public: + BoneSpikeTargetSelector(UnitAI* ai) : _ai(ai) { } + + bool operator()(Unit* unit) const + { + if (unit->GetTypeId() != TYPEID_PLAYER) + return false; + + if (unit->HasAura(SPELL_IMPALED)) + return false; + + // Check if it is one of the tanks soaking Bone Slice + for (uint32 i = 0; i < MAX_BONE_SPIKE_IMMUNE; ++i) + if (unit->GetGUID() == _ai->GetGUID(DATA_SPIKE_IMMUNE + i)) + return false; + + return true; + } + + private: + UnitAI* _ai; +}; class boss_lord_marrowgar : public CreatureScript { @@ -103,11 +143,12 @@ class boss_lord_marrowgar : public CreatureScript me->RemoveAurasDueToSpell(SPELL_BONE_STORM); me->RemoveAurasDueToSpell(SPELL_BERSERK); events.ScheduleEvent(EVENT_ENABLE_BONE_SLICE, 10000); - events.ScheduleEvent(EVENT_BONE_SPIKE_GRAVEYARD, urand(10000, 15000), EVENT_GROUP_SPECIAL); + events.ScheduleEvent(EVENT_BONE_SPIKE_GRAVEYARD, 15000, EVENT_GROUP_SPECIAL); events.ScheduleEvent(EVENT_COLDFLAME, 5000, EVENT_GROUP_SPECIAL); events.ScheduleEvent(EVENT_WARN_BONE_STORM, urand(45000, 50000)); events.ScheduleEvent(EVENT_ENRAGE, 600000); _boneSlice = false; + _boneSpikeImmune.clear(); } void EnterCombat(Unit* /*who*/) @@ -148,7 +189,7 @@ class boss_lord_marrowgar : public CreatureScript } } - void UpdateAI(uint32 const diff) + void UpdateAI(uint32 diff) { if (!UpdateVictim() || !CheckInRoom()) return; @@ -199,18 +240,18 @@ class boss_lord_marrowgar : public CreatureScript if (!unit) unit = SelectTarget(SELECT_TARGET_RANDOM, 0, 0.0f, true); if (unit) - me->GetMotionMaster()->MovePoint(POINT_TARGET_BONESTORM_PLAYER, unit->GetPositionX(), unit->GetPositionY(), unit->GetPositionZ()); + me->GetMotionMaster()->MovePoint(POINT_TARGET_BONESTORM_PLAYER, *unit); break; } case EVENT_BONE_STORM_END: if (me->GetMotionMaster()->GetCurrentMovementGeneratorType() == POINT_MOTION_TYPE) me->GetMotionMaster()->MovementExpired(); - DoStartMovement(me->getVictim()); + me->GetMotionMaster()->MoveChase(me->getVictim()); me->SetSpeed(MOVE_RUN, _baseSpeed, true); events.CancelEvent(EVENT_BONE_STORM_MOVE); events.ScheduleEvent(EVENT_ENABLE_BONE_SLICE, 10000); if (!IsHeroic()) - events.RescheduleEvent(EVENT_BONE_SPIKE_GRAVEYARD, urand(15000, 20000), EVENT_GROUP_SPECIAL); + events.RescheduleEvent(EVENT_BONE_SPIKE_GRAVEYARD, 15000, EVENT_GROUP_SPECIAL); break; case EVENT_ENABLE_BONE_SLICE: _boneSlice = true; @@ -239,7 +280,7 @@ class boss_lord_marrowgar : public CreatureScript return; // lock movement - DoStartNoMovement(me->getVictim()); + me->GetMotionMaster()->MoveIdle(); } Position const* GetLastColdflamePosition() const @@ -247,23 +288,51 @@ class boss_lord_marrowgar : public CreatureScript return &_coldflameLastPos; } - uint64 GetGUID(int32 type/* = 0 */) const + uint64 GetGUID(int32 type /*= 0 */) const { - if (type == DATA_COLDFLAME_GUID) - return _coldflameTarget; + switch (type) + { + case DATA_COLDFLAME_GUID: + return _coldflameTarget; + case DATA_SPIKE_IMMUNE + 0: + case DATA_SPIKE_IMMUNE + 1: + case DATA_SPIKE_IMMUNE + 2: + { + uint32 index = uint32(type - DATA_SPIKE_IMMUNE); + if (index < _boneSpikeImmune.size()) + return _boneSpikeImmune[index]; + + break; + } + } + return 0LL; } - void SetGUID(uint64 guid, int32 type/* = 0 */) + void SetGUID(uint64 guid, int32 type /*= 0 */) { - if (type != DATA_COLDFLAME_GUID) + switch (type) + { + case DATA_COLDFLAME_GUID: + _coldflameTarget = guid; + break; + case DATA_SPIKE_IMMUNE: + _boneSpikeImmune.push_back(guid); + break; + } + } + + void DoAction(int32 action) + { + if (action != ACTION_CLEAR_SPIKE_IMMUNITIES) return; - _coldflameTarget = guid; + _boneSpikeImmune.clear(); } private: Position _coldflameLastPos; + std::vector<uint64> _boneSpikeImmune; uint64 _coldflameTarget; uint32 _boneStormDuration; float _baseSpeed; @@ -295,19 +364,17 @@ class npc_coldflame : public CreatureScript if (owner->GetTypeId() != TYPEID_UNIT) return; - Creature* creOwner = owner->ToCreature(); Position pos; - // random target case + if (MarrowgarAI* marrowgarAI = CAST_AI(MarrowgarAI, owner->GetAI())) + pos.Relocate(marrowgarAI->GetLastColdflamePosition()); + else + pos.Relocate(owner); + if (owner->HasAura(SPELL_BONE_STORM)) { - if (MarrowgarAI* marrowgarAI = CAST_AI(MarrowgarAI, creOwner->AI())) - { - Position const* ownerPos = marrowgarAI->GetLastColdflamePosition(); - float ang = me->GetAngle(ownerPos) - static_cast<float>(M_PI); - MapManager::NormalizeOrientation(ang); - me->SetOrientation(ang); - owner->GetNearPosition(pos, 2.5f, 0.0f); - } + float ang = MapManager::NormalizeOrientation(pos.GetAngle(me)); + me->SetOrientation(ang); + owner->GetNearPoint2D(pos.m_positionX, pos.m_positionY, 5.0f - owner->GetObjectSize(), ang); } else { @@ -318,25 +385,27 @@ class npc_coldflame : public CreatureScript return; } - me->SetOrientation(owner->GetAngle(target)); - owner->GetNearPosition(pos, owner->GetObjectSize() / 2.0f, 0.0f); + float ang = MapManager::NormalizeOrientation(pos.GetAngle(target)); + me->SetOrientation(ang); + owner->GetNearPoint2D(pos.m_positionX, pos.m_positionY, 15.0f - owner->GetObjectSize(), ang); } me->NearTeleportTo(pos.GetPositionX(), pos.GetPositionY(), me->GetPositionZ(), me->GetOrientation()); - _events.ScheduleEvent(EVENT_COLDFLAME_TRIGGER, 450); + DoCast(SPELL_COLDFLAME_SUMMON); + _events.ScheduleEvent(EVENT_COLDFLAME_TRIGGER, 500); } - void UpdateAI(uint32 const diff) + void UpdateAI(uint32 diff) { _events.Update(diff); if (_events.ExecuteEvent() == EVENT_COLDFLAME_TRIGGER) { Position newPos; - me->GetNearPosition(newPos, 5.5f, 0.0f); + me->GetNearPosition(newPos, 5.0f, 0.0f); me->NearTeleportTo(newPos.GetPositionX(), newPos.GetPositionY(), me->GetPositionZ(), me->GetOrientation()); DoCast(SPELL_COLDFLAME_SUMMON); - _events.ScheduleEvent(EVENT_COLDFLAME_TRIGGER, 450); + _events.ScheduleEvent(EVENT_COLDFLAME_TRIGGER, 500); } } @@ -355,11 +424,13 @@ class npc_bone_spike : public CreatureScript public: npc_bone_spike() : CreatureScript("npc_bone_spike") { } - struct npc_bone_spikeAI : public Scripted_NoMovementAI + struct npc_bone_spikeAI : public ScriptedAI { - npc_bone_spikeAI(Creature* creature) : Scripted_NoMovementAI(creature), _hasTrappedUnit(false) + npc_bone_spikeAI(Creature* creature) : ScriptedAI(creature), _hasTrappedUnit(false) { ASSERT(creature->GetVehicleKit()); + + SetCombatMovement(false); } void JustDied(Unit* /*killer*/) @@ -385,7 +456,25 @@ class npc_bone_spike : public CreatureScript _hasTrappedUnit = true; } - void UpdateAI(uint32 const diff) + void PassengerBoarded(Unit* passenger, int8 /*seat*/, bool apply) + { + if (!apply) + return; + + /// @HACK - Change passenger offset to the one taken directly from sniffs + /// Remove this when proper calculations are implemented. + /// This fixes healing spiked people + Movement::MoveSplineInit init(passenger); + init.DisableTransportPathTransformations(); + init.MoveTo(-0.02206125f, -0.02132235f, 5.514783f, false); + init.Launch(); + + /// @WORKAROUND - Clear ON VEHICLE state to allow healing (Invalid target errors) + /// Current rule for applying this state is questionable (seatFlags & VEHICLE_SEAT_FLAG_ALLOW_TURNING ???) + passenger->ClearUnitState(UNIT_STATE_ONVEHICLE); + } + + void UpdateAI(uint32 diff) { if (!_hasTrappedUnit) return; @@ -487,16 +576,24 @@ class spell_marrowgar_coldflame_damage : public SpellScriptLoader { PrepareAuraScript(spell_marrowgar_coldflame_damage_AuraScript); - void OnPeriodic(AuraEffect const* /*aurEff*/) + bool CanBeAppliedOn(Unit* target) { - if (DynamicObject* owner = GetDynobjOwner()) - if (GetTarget()->GetExactDist2d(owner) >= owner->GetRadius() || GetTarget()->HasAura(SPELL_IMPALED)) - PreventDefaultAction(); + if (target->HasAura(SPELL_IMPALED)) + return false; + + if (target->GetExactDist2d(GetOwner()) > GetSpellInfo()->Effects[EFFECT_0].CalcRadius()) + return false; + + if (Aura* aur = target->GetAura(GetId())) + if (aur->GetOwner() != GetOwner()) + return false; + + return true; } void Register() { - OnEffectPeriodic += AuraEffectPeriodicFn(spell_marrowgar_coldflame_damage_AuraScript::OnPeriodic, EFFECT_0, SPELL_AURA_PERIODIC_DAMAGE); + DoCheckAreaTarget += AuraCheckAreaTargetFn(spell_marrowgar_coldflame_damage_AuraScript::CanBeAppliedOn); } }; @@ -515,9 +612,23 @@ class spell_marrowgar_bone_spike_graveyard : public SpellScriptLoader { PrepareSpellScript(spell_marrowgar_bone_spike_graveyard_SpellScript); + bool Validate(SpellInfo const* /*spell*/) + { + for (uint32 i = 0; i < 3; ++i) + if (!sSpellMgr->GetSpellInfo(BoneSpikeSummonId[i])) + return false; + + return true; + } + + bool Load() + { + return GetCaster()->GetTypeId() == TYPEID_UNIT && GetCaster()->IsAIEnabled; + } + SpellCastResult CheckCast() { - return GetCaster()->GetAI()->SelectTarget(SELECT_TARGET_TOPAGGRO, 1, 0.0f, true, -SPELL_IMPALED) ? SPELL_CAST_OK : SPELL_FAILED_NO_VALID_TARGETS; + return GetCaster()->GetAI()->SelectTarget(SELECT_TARGET_RANDOM, 0, BoneSpikeTargetSelector(GetCaster()->GetAI())) ? SPELL_CAST_OK : SPELL_FAILED_NO_VALID_TARGETS; } void HandleSpikes(SpellEffIndex effIndex) @@ -525,22 +636,22 @@ class spell_marrowgar_bone_spike_graveyard : public SpellScriptLoader PreventHitDefaultEffect(effIndex); if (Creature* marrowgar = GetCaster()->ToCreature()) { - bool didHit = false; CreatureAI* marrowgarAI = marrowgar->AI(); uint8 boneSpikeCount = uint8(GetCaster()->GetMap()->GetSpawnMode() & 1 ? 3 : 1); - for (uint8 i = 0; i < boneSpikeCount; ++i) - { - // select any unit but not the tank - Unit* target = marrowgarAI->SelectTarget(SELECT_TARGET_RANDOM, 1, 150.0f, true, -SPELL_IMPALED); - if (!target) - break; - didHit = true; - target->CastCustomSpell(boneSpikeSummonId[i], SPELLVALUE_BASE_POINT0, 0, target, true); + std::list<Unit*> targets; + marrowgarAI->SelectTargetList(targets, BoneSpikeTargetSelector(marrowgarAI), boneSpikeCount, SELECT_TARGET_RANDOM); + if (targets.empty()) + return; + + uint32 i = 0; + for (std::list<Unit*>::const_iterator itr = targets.begin(); itr != targets.end(); ++itr, ++i) + { + Unit* target = *itr; + target->CastCustomSpell(BoneSpikeSummonId[i], SPELLVALUE_BASE_POINT0, 0, target, true); } - if (didHit) - marrowgarAI->Talk(SAY_BONESPIKE); + marrowgarAI->Talk(SAY_BONESPIKE); } } @@ -583,6 +694,58 @@ class spell_marrowgar_bone_storm : public SpellScriptLoader } }; +class spell_marrowgar_bone_slice : public SpellScriptLoader +{ + public: + spell_marrowgar_bone_slice() : SpellScriptLoader("spell_marrowgar_bone_slice") { } + + class spell_marrowgar_bone_slice_SpellScript : public SpellScript + { + PrepareSpellScript(spell_marrowgar_bone_slice_SpellScript); + + bool Load() + { + _targetCount = 0; + return true; + } + + void ClearSpikeImmunities() + { + GetCaster()->GetAI()->DoAction(ACTION_CLEAR_SPIKE_IMMUNITIES); + } + + void CountTargets(std::list<WorldObject*>& targets) + { + _targetCount = std::min<uint32>(targets.size(), GetSpellInfo()->MaxAffectedTargets); + } + + void SplitDamage() + { + // Mark the unit as hit, even if the spell missed or was dodged/parried + GetCaster()->GetAI()->SetGUID(GetHitUnit()->GetGUID(), DATA_SPIKE_IMMUNE); + + if (!_targetCount) + return; // This spell can miss all targets + + SetHitDamage(GetHitDamage() / _targetCount); + } + + void Register() + { + BeforeCast += SpellCastFn(spell_marrowgar_bone_slice_SpellScript::ClearSpikeImmunities); + OnObjectAreaTargetSelect += SpellObjectAreaTargetSelectFn(spell_marrowgar_bone_slice_SpellScript::CountTargets, EFFECT_0, TARGET_UNIT_DEST_AREA_ENEMY); + OnHit += SpellHitFn(spell_marrowgar_bone_slice_SpellScript::SplitDamage); + } + + uint32 _targetCount; + }; + + SpellScript* GetSpellScript() const + { + return new spell_marrowgar_bone_slice_SpellScript(); + } +}; + void AddSC_boss_lord_marrowgar() { new boss_lord_marrowgar(); @@ -593,4 +756,5 @@ void AddSC_boss_lord_marrowgar() new spell_marrowgar_coldflame_damage(); new spell_marrowgar_bone_spike_graveyard(); new spell_marrowgar_bone_storm(); + new spell_marrowgar_bone_slice(); } diff --git a/src/server/scripts/Northrend/IcecrownCitadel/boss_professor_putricide.cpp b/src/server/scripts/Northrend/IcecrownCitadel/boss_professor_putricide.cpp index 05bf7b9794a..e377f5f8d07 100644 --- a/src/server/scripts/Northrend/IcecrownCitadel/boss_professor_putricide.cpp +++ b/src/server/scripts/Northrend/IcecrownCitadel/boss_professor_putricide.cpp @@ -145,10 +145,7 @@ enum Phases PHASE_ROTFACE = 2, PHASE_COMBAT_1 = 4, PHASE_COMBAT_2 = 5, - PHASE_COMBAT_3 = 6, - - PHASE_MASK_COMBAT = (1 << PHASE_COMBAT_1) | (1 << PHASE_COMBAT_2) | (1 << PHASE_COMBAT_3), - PHASE_MASK_NOT_SELF = (1 << PHASE_FESTERGUT) | (1 << PHASE_ROTFACE) + PHASE_COMBAT_3 = 6 }; enum Points @@ -233,7 +230,7 @@ class boss_professor_putricide : public CreatureScript void Reset() { - if (!(events.GetPhaseMask() & PHASE_MASK_NOT_SELF)) + if (!(events.IsInPhase(PHASE_ROTFACE) || events.IsInPhase(PHASE_FESTERGUT))) instance->SetBossState(DATA_PROFESSOR_PUTRICIDE, NOT_STARTED); instance->SetData(DATA_NAUSEA_ACHIEVEMENT, uint32(true)); @@ -252,7 +249,7 @@ class boss_professor_putricide : public CreatureScript void EnterCombat(Unit* who) { - if (events.GetPhaseMask() & PHASE_MASK_NOT_SELF) + if (events.IsInPhase(PHASE_ROTFACE) || events.IsInPhase(PHASE_FESTERGUT)) return; if (!instance->CheckRequiredBosses(DATA_PROFESSOR_PUTRICIDE, who->ToPlayer())) @@ -282,7 +279,7 @@ class boss_professor_putricide : public CreatureScript { _JustReachedHome(); me->SetWalk(false); - if (events.GetPhaseMask() & PHASE_MASK_COMBAT) + if (events.IsInPhase(PHASE_COMBAT_1) || events.IsInPhase(PHASE_COMBAT_2) || events.IsInPhase(PHASE_COMBAT_3)) instance->SetBossState(DATA_PROFESSOR_PUTRICIDE, FAIL); } @@ -416,7 +413,7 @@ class boss_professor_putricide : public CreatureScript } } - void DoAction(int32 const action) + void DoAction(int32 action) { switch (action) { @@ -566,9 +563,9 @@ class boss_professor_putricide : public CreatureScript _experimentState = bool(data); } - void UpdateAI(uint32 const diff) + void UpdateAI(uint32 diff) { - if ((!(events.GetPhaseMask() & PHASE_MASK_NOT_SELF) && !UpdateVictim()) || !CheckInRoom()) + if ((!(events.IsInPhase(PHASE_ROTFACE) || events.IsInPhase(PHASE_FESTERGUT)) && !UpdateVictim()) || !CheckInRoom()) return; events.Update(diff); @@ -745,7 +742,7 @@ class npc_putricide_oozeAI : public ScriptedAI _newTargetSelectTimer = 1000; } - void UpdateAI(uint32 const diff) + void UpdateAI(uint32 diff) { if (!UpdateVictim() && !_newTargetSelectTimer) return; diff --git a/src/server/scripts/Northrend/IcecrownCitadel/boss_rotface.cpp b/src/server/scripts/Northrend/IcecrownCitadel/boss_rotface.cpp index db5f373a753..f398ad55603 100644 --- a/src/server/scripts/Northrend/IcecrownCitadel/boss_rotface.cpp +++ b/src/server/scripts/Northrend/IcecrownCitadel/boss_rotface.cpp @@ -162,7 +162,7 @@ class boss_rotface : public CreatureScript // don't enter combat } - void UpdateAI(const uint32 diff) + void UpdateAI(uint32 diff) { if (!UpdateVictim() || !CheckInRoom()) return; @@ -239,7 +239,7 @@ class npc_little_ooze : public CreatureScript me->DespawnOrUnsummon(); } - void UpdateAI(const uint32 diff) + void UpdateAI(uint32 diff) { if (!UpdateVictim()) return; @@ -296,13 +296,13 @@ class npc_big_ooze : public CreatureScript me->DespawnOrUnsummon(); } - void DoAction(const int32 action) + void DoAction(int32 action) { if (action == EVENT_STICKY_OOZE) events.CancelEvent(EVENT_STICKY_OOZE); } - void UpdateAI(const uint32 diff) + void UpdateAI(uint32 diff) { if (!UpdateVictim()) return; @@ -377,7 +377,7 @@ class npc_precious_icc : public CreatureScript rotface->AI()->Talk(SAY_PRECIOUS_DIES); } - void UpdateAI(const uint32 diff) + void UpdateAI(uint32 diff) { if (!UpdateVictim()) return; diff --git a/src/server/scripts/Northrend/IcecrownCitadel/boss_sindragosa.cpp b/src/server/scripts/Northrend/IcecrownCitadel/boss_sindragosa.cpp index 45c5302bfe8..ea74d8ec61c 100644 --- a/src/server/scripts/Northrend/IcecrownCitadel/boss_sindragosa.cpp +++ b/src/server/scripts/Northrend/IcecrownCitadel/boss_sindragosa.cpp @@ -84,7 +84,9 @@ enum Spells SPELL_CONCUSSIVE_SHOCK = 71337, // Frost Infusion - SPELL_FROST_INFUSION_CREDIT = 72289 + SPELL_FROST_INFUSION_CREDIT = 72289, + SPELL_FROST_IMBUED_BLADE = 72290, + SPELL_FROST_INFUSION = 72292, }; enum Events @@ -147,11 +149,7 @@ enum MovementPoints enum Shadowmourne { - QUEST_FROST_INFUSION = 24757, - ITEM_SHADOW_S_EDGE = 49888, - - SPELL_FROST_INFUSION = 72292, - SPELL_FROST_IMBUED_BLADE = 72290, + QUEST_FROST_INFUSION = 24757 }; Position const RimefangFlyPos = {4413.309f, 2456.421f, 233.3795f, 2.890186f}; @@ -271,7 +269,7 @@ class boss_sindragosa : public CreatureScript Talk(SAY_KILL); } - void DoAction(int32 const action) + void DoAction(int32 action) { if (action == ACTION_START_FROSTWYRM) { @@ -390,50 +388,13 @@ class boss_sindragosa : public CreatureScript void SpellHitTarget(Unit* target, SpellInfo const* spell) { if (uint32 spellId = sSpellMgr->GetSpellIdForDifficulty(70127, me)) - { if (spellId == spell->Id) - { if (Aura const* mysticBuffet = target->GetAura(spell->Id)) _mysticBuffetStack = std::max<uint8>(_mysticBuffetStack, mysticBuffet->GetStackAmount()); - return; - } - } - - // Frost Infusion - if (Player* player = target->ToPlayer()) - { - if (uint32 spellId = sSpellMgr->GetSpellIdForDifficulty(_isThirdPhase ? SPELL_FROST_BREATH_P2 : SPELL_FROST_BREATH_P1, me)) - { - if (spellId == spell->Id) - { - Item* shadowsEdge = player->GetWeaponForAttack(BASE_ATTACK, true); - if (player->GetQuestStatus(QUEST_FROST_INFUSION) == QUEST_STATUS_INCOMPLETE && shadowsEdge) - { - if (!player->HasAura(SPELL_FROST_IMBUED_BLADE) && shadowsEdge->GetEntry() == ITEM_SHADOW_S_EDGE) - { - if (Aura* infusion = player->GetAura(SPELL_FROST_INFUSION)) - { - if (infusion->GetStackAmount() == 3) - { - player->CastSpell(player, SPELL_FROST_IMBUED_BLADE, true); - player->RemoveAura(infusion); - } - else - player->CastSpell(player, SPELL_FROST_INFUSION, true); - } - else - player->CastSpell(player, SPELL_FROST_INFUSION, true); - } - } - - return; - } - } - } } - void UpdateAI(uint32 const diff) + void UpdateAI(uint32 diff) { if (!UpdateVictim() || !CheckInRoom()) return; @@ -576,11 +537,12 @@ class npc_ice_tomb : public CreatureScript public: npc_ice_tomb() : CreatureScript("npc_ice_tomb") { } - struct npc_ice_tombAI : public Scripted_NoMovementAI + struct npc_ice_tombAI : public ScriptedAI { - npc_ice_tombAI(Creature* creature) : Scripted_NoMovementAI(creature) + npc_ice_tombAI(Creature* creature) : ScriptedAI(creature) { _trappedPlayerGUID = 0; + SetCombatMovement(false); } void Reset() @@ -597,7 +559,7 @@ class npc_ice_tomb : public CreatureScript } } - void DoAction(int32 const action) + void DoAction(int32 action) { if (action == ACTION_TRIGGER_ASPHYXIATION) if (Player* player = ObjectAccessor::GetPlayer(*me, _trappedPlayerGUID)) @@ -616,7 +578,7 @@ class npc_ice_tomb : public CreatureScript } } - void UpdateAI(uint32 const diff) + void UpdateAI(uint32 diff) { if (!_trappedPlayerGUID) return; @@ -695,7 +657,7 @@ class npc_spinestalker : public CreatureScript _events.Reset(); } - void DoAction(int32 const action) + void DoAction(int32 action) { if (action == ACTION_START_FROSTWYRM) { @@ -732,7 +694,7 @@ class npc_spinestalker : public CreatureScript me->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE); } - void UpdateAI(uint32 const diff) + void UpdateAI(uint32 diff) { if (!UpdateVictim()) return; @@ -825,7 +787,7 @@ class npc_rimefang : public CreatureScript _events.Reset(); } - void DoAction(int32 const action) + void DoAction(int32 action) { if (action == ACTION_START_FROSTWYRM) { @@ -867,7 +829,7 @@ class npc_rimefang : public CreatureScript DoCast(me, SPELL_FROST_AURA_RIMEFANG, true); } - void UpdateAI(uint32 const diff) + void UpdateAI(uint32 diff) { if (!UpdateVictim()) return; @@ -995,7 +957,7 @@ class npc_sindragosa_trash : public CreatureScript return 0; } - void UpdateAI(uint32 const diff) + void UpdateAI(uint32 diff) { if (!UpdateVictim()) return; @@ -1154,6 +1116,50 @@ class spell_sindragosa_unchained_magic : public SpellScriptLoader } }; +class spell_sindragosa_frost_breath : public SpellScriptLoader +{ + public: + spell_sindragosa_frost_breath() : SpellScriptLoader("spell_sindragosa_frost_breath") { } + + class spell_sindragosa_frost_breath_SpellScript : public SpellScript + { + PrepareSpellScript(spell_sindragosa_frost_breath_SpellScript); + + void HandleInfusion() + { + Player* target = GetHitPlayer(); + if (!target) + return; + + if (target->GetQuestStatus(QUEST_FROST_INFUSION) != QUEST_STATUS_INCOMPLETE) + return; + + // Check if player has Shadow's Edge equipped and not ready for infusion + if (!target->HasAura(SPELL_UNSATED_CRAVING) || target->HasAura(SPELL_FROST_IMBUED_BLADE)) + return; + + Aura* infusion = target->GetAura(SPELL_FROST_INFUSION, target->GetGUID()); + if (infusion && infusion->GetStackAmount() >= 3) + { + target->RemoveAura(infusion); + target->CastSpell(target, SPELL_FROST_IMBUED_BLADE, TRIGGERED_FULL_MASK); + } + else + target->CastSpell(target, SPELL_FROST_INFUSION, TRIGGERED_FULL_MASK); + } + + void Register() + { + AfterHit += SpellHitFn(spell_sindragosa_frost_breath_SpellScript::HandleInfusion); + } + }; + + SpellScript* GetSpellScript() const + { + return new spell_sindragosa_frost_breath_SpellScript(); + } +}; + class spell_sindragosa_instability : public SpellScriptLoader { public: @@ -1576,6 +1582,7 @@ void AddSC_boss_sindragosa() new npc_sindragosa_trash(); new spell_sindragosa_s_fury(); new spell_sindragosa_unchained_magic(); + new spell_sindragosa_frost_breath(); new spell_sindragosa_instability(); new spell_sindragosa_frost_beacon(); new spell_sindragosa_ice_tomb(); diff --git a/src/server/scripts/Northrend/IcecrownCitadel/boss_the_lich_king.cpp b/src/server/scripts/Northrend/IcecrownCitadel/boss_the_lich_king.cpp index 452d09cf65f..033674767e6 100644 --- a/src/server/scripts/Northrend/IcecrownCitadel/boss_the_lich_king.cpp +++ b/src/server/scripts/Northrend/IcecrownCitadel/boss_the_lich_king.cpp @@ -138,13 +138,14 @@ enum Spells SPELL_IN_FROSTMOURNE_ROOM = 74276, SPELL_KILL_FROSTMOURNE_PLAYERS = 75127, SPELL_HARVESTED_SOUL = 72679, - SPELL_TRIGGER_VILE_SPIRIT_HEROIC = 73582, // TODO: Cast every 3 seconds during Frostmourne phase, targets a Wicked Spirit amd activates it + SPELL_TRIGGER_VILE_SPIRIT_HEROIC = 73582, /// @todo Cast every 3 seconds during Frostmourne phase, targets a Wicked Spirit amd activates it // Frostmourne SPELL_LIGHTS_FAVOR = 69382, SPELL_RESTORE_SOUL = 72595, SPELL_RESTORE_SOULS = 73650, // Heroic SPELL_DARK_HUNGER = 69383, // Passive proc healing + SPELL_DARK_HUNGER_HEAL = 69384, SPELL_DESTROY_SOUL = 74086, // Used when Terenas Menethil dies SPELL_SOUL_RIP = 69397, // Deals increasing damage SPELL_SOUL_RIP_DAMAGE = 69398, @@ -278,20 +279,10 @@ enum Phases PHASE_THREE = 4, PHASE_TRANSITION = 5, PHASE_FROSTMOURNE = 6, // only set on heroic mode when all players are sent into frostmourne - PHASE_OUTRO = 7, - - PHASE_MASK_INTRO = 1 << PHASE_INTRO, - PHASE_MASK_ONE = 1 << PHASE_ONE, - PHASE_MASK_TWO = 1 << PHASE_TWO, - PHASE_MASK_THREE = 1 << PHASE_THREE, - PHASE_MASK_TRANSITION = 1 << PHASE_TRANSITION, - PHASE_MASK_NO_CAST_CHECK = (1 << PHASE_TRANSITION) | (1 << PHASE_FROSTMOURNE) | (1 << PHASE_OUTRO), - PHASE_MASK_FROSTMOURNE = 1 << PHASE_FROSTMOURNE, - PHASE_MASK_OUTRO = 1 << PHASE_OUTRO, - PHASE_MASK_NO_VICTIM = (1 << PHASE_INTRO) | (1 << PHASE_OUTRO) | (1 << PHASE_FROSTMOURNE), + PHASE_OUTRO = 7 }; -#define PHASE_TWO_THREE (events.GetPhaseMask() & PHASE_MASK_TWO ? PHASE_TWO : PHASE_THREE) +#define PHASE_TWO_THREE (events.IsInPhase(PHASE_TWO) ? PHASE_TWO : PHASE_THREE) Position const CenterPosition = {503.6282f, -2124.655f, 840.8569f, 0.0f}; Position const TirionIntro = {489.2970f, -2124.840f, 840.8569f, 0.0f}; @@ -588,11 +579,11 @@ class boss_the_lich_king : public CreatureScript void KilledUnit(Unit* victim) { - if (victim->GetTypeId() == TYPEID_PLAYER && !me->IsInEvadeMode() && !(events.GetPhaseMask() & PHASE_MASK_OUTRO)) + if (victim->GetTypeId() == TYPEID_PLAYER && !me->IsInEvadeMode() && !events.IsInPhase(PHASE_OUTRO)) Talk(SAY_LK_KILL); } - void DoAction(int32 const action) + void DoAction(int32 action) { switch (action) { @@ -668,7 +659,7 @@ class boss_the_lich_king : public CreatureScript void DamageTaken(Unit* /*attacker*/, uint32& /*damage*/) { - if (events.GetPhaseMask() & PHASE_MASK_ONE && !HealthAbovePct(70)) + if (events.IsInPhase(PHASE_ONE) && !HealthAbovePct(70)) { events.SetPhase(PHASE_TRANSITION); me->SetReactState(REACT_PASSIVE); @@ -677,7 +668,7 @@ class boss_the_lich_king : public CreatureScript return; } - if (events.GetPhaseMask() & PHASE_MASK_TWO && !HealthAbovePct(40)) + if (events.IsInPhase(PHASE_TWO) && !HealthAbovePct(40)) { events.SetPhase(PHASE_TRANSITION); me->SetReactState(REACT_PASSIVE); @@ -686,7 +677,7 @@ class boss_the_lich_king : public CreatureScript return; } - if (events.GetPhaseMask() & PHASE_MASK_THREE && !HealthAbovePct(10)) + if (events.IsInPhase(PHASE_THREE) && !HealthAbovePct(10)) { me->SetReactState(REACT_PASSIVE); me->AttackStop(); @@ -757,7 +748,7 @@ class boss_the_lich_king : public CreatureScript summon->SetReactState(REACT_PASSIVE); summon->SetSpeed(MOVE_FLIGHT, 0.5f); summon->GetMotionMaster()->MoveRandom(10.0f); - if (!(events.GetPhaseMask() & PHASE_MASK_FROSTMOURNE)) + if (!events.IsInPhase(PHASE_FROSTMOURNE)) summon->m_Events.AddEvent(new VileSpiritActivateEvent(summon), summon->m_Events.CalculateTime(15000)); return; } @@ -869,17 +860,17 @@ class boss_the_lich_king : public CreatureScript } } - void UpdateAI(uint32 const diff) + void UpdateAI(uint32 diff) { // check phase first to prevent updating victim and entering evade mode when not wanted - if (!(events.GetPhaseMask() & PHASE_MASK_NO_VICTIM)) + if (!(events.IsInPhase(PHASE_OUTRO) || events.IsInPhase(PHASE_INTRO) || events.IsInPhase(PHASE_FROSTMOURNE))) if (!UpdateVictim()) return; events.Update(diff); // during Remorseless Winter phases The Lich King is channeling a spell, but we must continue casting other spells - if (me->HasUnitState(UNIT_STATE_CASTING) && !(events.GetPhaseMask() & PHASE_MASK_NO_CAST_CHECK)) + if (me->HasUnitState(UNIT_STATE_CASTING) && !(events.IsInPhase(PHASE_TRANSITION) || events.IsInPhase(PHASE_OUTRO) || events.IsInPhase(PHASE_FROSTMOURNE))) return; while (uint32 eventId = events.ExecuteEvent()) @@ -935,7 +926,7 @@ class boss_the_lich_king : public CreatureScript break; case EVENT_INFEST: DoCast(me, SPELL_INFEST); - events.ScheduleEvent(EVENT_INFEST, urand(21000, 24000), 0, (events.GetPhaseMask() & PHASE_MASK_ONE) ? PHASE_ONE : PHASE_TWO); + events.ScheduleEvent(EVENT_INFEST, urand(21000, 24000), 0, events.IsInPhase(PHASE_ONE) ? PHASE_ONE : PHASE_TWO); break; case EVENT_NECROTIC_PLAGUE: if (Unit* target = SelectTarget(SELECT_TARGET_RANDOM, 1, NecroticPlagueTargetCheck(me, NECROTIC_PLAGUE_LK, NECROTIC_PLAGUE_PLR))) @@ -1004,7 +995,7 @@ class boss_the_lich_king : public CreatureScript break; case EVENT_START_ATTACK: me->SetReactState(REACT_AGGRESSIVE); - if (events.GetPhaseMask() & PHASE_MASK_FROSTMOURNE) + if (events.IsInPhase(PHASE_FROSTMOURNE)) events.SetPhase(PHASE_THREE); break; case EVENT_VILE_SPIRITS: @@ -1203,7 +1194,7 @@ class npc_tirion_fordring_tft : public CreatureScript } } - void DoAction(int32 const action) + void DoAction(int32 action) { switch (action) { @@ -1250,9 +1241,9 @@ class npc_tirion_fordring_tft : public CreatureScript me->SetFlag(UNIT_NPC_FLAGS, UNIT_NPC_FLAG_GOSSIP); } - void UpdateAI(uint32 const diff) + void UpdateAI(uint32 diff) { - if (!UpdateVictim() && !(_events.GetPhaseMask() & (PHASE_MASK_INTRO | PHASE_MASK_OUTRO))) + if (!UpdateVictim() && !(_events.IsInPhase(PHASE_OUTRO) || _events.IsInPhase(PHASE_INTRO))) return; _events.Update(diff); @@ -1344,7 +1335,7 @@ class npc_shambling_horror_icc : public CreatureScript } } - void UpdateAI(uint32 const diff) + void UpdateAI(uint32 diff) { if (!UpdateVictim()) return; @@ -1424,7 +1415,7 @@ class npc_raging_spirit : public CreatureScript summon->SetTempSummonType(TEMPSUMMON_CORPSE_DESPAWN); } - void UpdateAI(uint32 const diff) + void UpdateAI(uint32 diff) { if (!UpdateVictim()) return; @@ -1559,7 +1550,7 @@ class npc_valkyr_shadowguard : public CreatureScript _grabbedPlayer = guid; } - void UpdateAI(uint32 const diff) + void UpdateAI(uint32 diff) { if (!UpdateVictim()) return; @@ -1634,7 +1625,7 @@ class npc_strangulate_vehicle : public CreatureScript lichKing->AI()->JustSummoned(me); } - void DoAction(int32 const action) + void DoAction(int32 action) { if (action != ACTION_TELEPORT_BACK) return; @@ -1652,7 +1643,7 @@ class npc_strangulate_vehicle : public CreatureScript lichKing->AI()->SummonedCreatureDespawn(me); } - void UpdateAI(uint32 const diff) + void UpdateAI(uint32 diff) { UpdateVictim(); @@ -1733,7 +1724,7 @@ class npc_terenas_menethil : public CreatureScript return target->GetEntry() != NPC_THE_LICH_KING; } - void DoAction(int32 const action) + void DoAction(int32 action) { switch (action) { @@ -1802,7 +1793,7 @@ class npc_terenas_menethil : public CreatureScript _events.ScheduleEvent(EVENT_OUTRO_TERENAS_TALK_2, 14000, 0, PHASE_OUTRO); } - void UpdateAI(uint32 const diff) + void UpdateAI(uint32 diff) { UpdateVictim(); @@ -1894,7 +1885,7 @@ class npc_spirit_warden : public CreatureScript terenas->AI()->DoAction(ACTION_TELEPORT_BACK); } - void UpdateAI(uint32 const diff) + void UpdateAI(uint32 diff) { if (!UpdateVictim()) return; @@ -1962,7 +1953,7 @@ class npc_spirit_bomb : public CreatureScript { } - void UpdateAI(uint32 const /*diff*/) + void UpdateAI(uint32 /*diff*/) { UpdateVictim(); // no melee attacks @@ -1997,7 +1988,7 @@ class npc_broken_frostmourne : public CreatureScript _events.ScheduleEvent(EVENT_OUTRO_KNOCK_BACK, 3000, 0, PHASE_OUTRO); } - void DoAction(int32 const action) + void DoAction(int32 action) { if (action == ACTION_SUMMON_TERENAS) _events.ScheduleEvent(EVENT_OUTRO_SUMMON_TERENAS, 6000, 0, PHASE_OUTRO); @@ -2007,7 +1998,7 @@ class npc_broken_frostmourne : public CreatureScript { } - void UpdateAI(uint32 const diff) + void UpdateAI(uint32 diff) { UpdateVictim(); @@ -2187,7 +2178,8 @@ class spell_the_lich_king_necrotic_plague_jump : public SpellScriptLoader void OnApply(AuraEffect const* /*aurEff*/, AuraEffectHandleModes /*mode*/) { if (Unit* caster = GetCaster()) - caster->GetAI()->SetData(DATA_PLAGUE_STACK, GetStackAmount()); + if (caster->GetAI()) + caster->GetAI()->SetData(DATA_PLAGUE_STACK, GetStackAmount()); } void OnRemove(AuraEffect const* aurEff, AuraEffectHandleModes /*mode*/) @@ -2846,8 +2838,6 @@ class spell_the_lich_king_vile_spirit_damage_target_search : public SpellScriptL { OnObjectAreaTargetSelect += SpellObjectAreaTargetSelectFn(spell_the_lich_king_vile_spirit_damage_target_search_SpellScript::CheckTargetCount, EFFECT_0, TARGET_UNIT_SRC_AREA_ENEMY); } - - Unit* _target; }; SpellScript* GetSpellScript() const @@ -3008,6 +2998,41 @@ class spell_the_lich_king_restore_soul : public SpellScriptLoader } }; +class spell_the_lich_king_dark_hunger : public SpellScriptLoader +{ + public: + spell_the_lich_king_dark_hunger() : SpellScriptLoader("spell_the_lich_king_dark_hunger") { } + + class spell_the_lich_king_dark_hunger_AuraScript : public AuraScript + { + PrepareAuraScript(spell_the_lich_king_dark_hunger_AuraScript); + + bool Validate(SpellInfo const* /*spellInfo*/) + { + if (!sSpellMgr->GetSpellInfo(SPELL_DARK_HUNGER_HEAL)) + return false; + return true; + } + + void HandleProc(AuraEffect const* aurEff, ProcEventInfo& eventInfo) + { + PreventDefaultAction(); + int32 heal = int32(eventInfo.GetDamageInfo()->GetDamage() / 2); + GetTarget()->CastCustomSpell(SPELL_DARK_HUNGER_HEAL, SPELLVALUE_BASE_POINT0, heal, GetTarget(), true, NULL, aurEff); + } + + void Register() + { + OnEffectProc += AuraEffectProcFn(spell_the_lich_king_dark_hunger_AuraScript::HandleProc, EFFECT_0, SPELL_AURA_DUMMY); + } + }; + + AuraScript* GetAuraScript() const + { + return new spell_the_lich_king_dark_hunger_AuraScript(); + } +}; + class spell_the_lich_king_in_frostmourne_room : public SpellScriptLoader { public: @@ -3253,6 +3278,7 @@ void AddSC_boss_the_lich_king() new spell_the_lich_king_lights_favor(); new spell_the_lich_king_soul_rip(); new spell_the_lich_king_restore_soul(); + new spell_the_lich_king_dark_hunger(); new spell_the_lich_king_in_frostmourne_room(); new spell_the_lich_king_summon_spirit_bomb(); new spell_the_lich_king_trigger_vile_spirit(); diff --git a/src/server/scripts/Northrend/IcecrownCitadel/boss_valithria_dreamwalker.cpp b/src/server/scripts/Northrend/IcecrownCitadel/boss_valithria_dreamwalker.cpp index df23abd8312..97a70f43c27 100644 --- a/src/server/scripts/Northrend/IcecrownCitadel/boss_valithria_dreamwalker.cpp +++ b/src/server/scripts/Northrend/IcecrownCitadel/boss_valithria_dreamwalker.cpp @@ -316,7 +316,7 @@ class boss_valithria_dreamwalker : public CreatureScript { } - void DoAction(int32 const action) + void DoAction(int32 action) { if (action != ACTION_ENTER_COMBAT) return; @@ -423,7 +423,7 @@ class boss_valithria_dreamwalker : public CreatureScript ++_missedPortals; } - void UpdateAI(uint32 const diff) + void UpdateAI(uint32 diff) { // does not enter combat if (_instance->GetBossState(DATA_VALITHRIA_DREAMWALKER) != IN_PROGRESS) @@ -536,7 +536,7 @@ class npc_green_dragon_combat_trigger : public CreatureScript DoAction(ACTION_DEATH); } - void DoAction(int32 const action) + void DoAction(int32 action) { if (action == ACTION_DEATH) { @@ -545,7 +545,7 @@ class npc_green_dragon_combat_trigger : public CreatureScript } } - void UpdateAI(uint32 const /*diff*/) + void UpdateAI(uint32 /*diff*/) { if (!me->isInCombat()) return; @@ -624,7 +624,7 @@ class npc_the_lich_king_controller : public CreatureScript summon->AI()->AttackStart(target); } - void UpdateAI(uint32 const diff) + void UpdateAI(uint32 diff) { if (!UpdateVictim()) return; @@ -716,7 +716,7 @@ class npc_risen_archmage : public CreatureScript } } - void DoAction(int32 const action) + void DoAction(int32 action) { if (action != ACTION_ENTER_COMBAT) return; @@ -734,7 +734,7 @@ class npc_risen_archmage : public CreatureScript summon->DespawnOrUnsummon(36000); } - void UpdateAI(uint32 const diff) + void UpdateAI(uint32 diff) { if (!me->isInCombat()) if (me->GetDBTableGUIDLow()) @@ -805,7 +805,7 @@ class npc_blazing_skeleton : public CreatureScript _events.ScheduleEvent(EVENT_LEY_WASTE, urand(15000, 20000)); } - void UpdateAI(uint32 const diff) + void UpdateAI(uint32 diff) { if (!UpdateVictim()) return; @@ -871,7 +871,7 @@ class npc_suppresser : public CreatureScript AttackStart(valithria); } - void UpdateAI(uint32 const diff) + void UpdateAI(uint32 diff) { if (!UpdateVictim()) return; @@ -928,7 +928,7 @@ class npc_blistering_zombie : public CreatureScript DoCast(me, SPELL_ACID_BURST, true); } - void UpdateAI(uint32 const /*diff*/) + void UpdateAI(uint32 /*diff*/) { if (!UpdateVictim()) return; @@ -965,7 +965,7 @@ class npc_gluttonous_abomination : public CreatureScript DoCast(me, SPELL_ROT_WORM_SPAWNER, true); } - void UpdateAI(uint32 const diff) + void UpdateAI(uint32 diff) { if (!UpdateVictim()) return; @@ -1024,7 +1024,7 @@ class npc_dream_portal : public CreatureScript return (type == MISSED_PORTALS && _used) ? 0 : 1; } - void UpdateAI(uint32 const /*diff*/) + void UpdateAI(uint32 /*diff*/) { UpdateVictim(); } @@ -1059,7 +1059,7 @@ class npc_dream_cloud : public CreatureScript me->LoadCreaturesAddon(true); } - void UpdateAI(uint32 const diff) + void UpdateAI(uint32 diff) { // trigger if (_instance->GetBossState(DATA_VALITHRIA_DREAMWALKER) != IN_PROGRESS) diff --git a/src/server/scripts/Northrend/IcecrownCitadel/icecrown_citadel.cpp b/src/server/scripts/Northrend/IcecrownCitadel/icecrown_citadel.cpp index 12868094b2e..3ffa6a0c4be 100644 --- a/src/server/scripts/Northrend/IcecrownCitadel/icecrown_citadel.cpp +++ b/src/server/scripts/Northrend/IcecrownCitadel/icecrown_citadel.cpp @@ -460,7 +460,7 @@ class npc_highlord_tirion_fordring_lh : public CreatureScript } } - void UpdateAI(uint32 const diff) + void UpdateAI(uint32 diff) { if (_damnedKills != 2) return; @@ -611,7 +611,7 @@ class npc_rotting_frost_giant : public CreatureScript _events.Reset(); } - void UpdateAI(uint32 const diff) + void UpdateAI(uint32 diff) { if (!UpdateVictim()) return; @@ -664,13 +664,14 @@ class npc_frost_freeze_trap : public CreatureScript public: npc_frost_freeze_trap() : CreatureScript("npc_frost_freeze_trap") { } - struct npc_frost_freeze_trapAI: public Scripted_NoMovementAI + struct npc_frost_freeze_trapAI: public ScriptedAI { - npc_frost_freeze_trapAI(Creature* creature) : Scripted_NoMovementAI(creature) + npc_frost_freeze_trapAI(Creature* creature) : ScriptedAI(creature) { + SetCombatMovement(false); } - void DoAction(int32 const action) + void DoAction(int32 action) { switch (action) { @@ -683,7 +684,7 @@ class npc_frost_freeze_trap : public CreatureScript } } - void UpdateAI(uint32 const diff) + void UpdateAI(uint32 diff) { _events.Update(diff); @@ -807,7 +808,7 @@ class boss_sister_svalna : public CreatureScript me->SetHover(false); } - void DoAction(int32 const action) + void DoAction(int32 action) { switch (action) { @@ -876,7 +877,7 @@ class boss_sister_svalna : public CreatureScript } } - void UpdateAI(uint32 const diff) + void UpdateAI(uint32 diff) { if (!UpdateVictim() && !_isEventInProgress) return; @@ -955,7 +956,7 @@ class npc_crok_scourgebane : public CreatureScript _wipeCheckTimer = 1000; } - void DoAction(int32 const action) + void DoAction(int32 action) { if (action == ACTION_START_GAUNTLET) { @@ -1237,7 +1238,7 @@ struct npc_argent_captainAI : public ScriptedAI Talk(SAY_CAPTAIN_KILL); } - void DoAction(int32 const action) + void DoAction(int32 action) { if (action == ACTION_START_GAUNTLET) { @@ -1355,7 +1356,7 @@ class npc_captain_arnath : public CreatureScript Events.ScheduleEvent(EVENT_ARNATH_DOMINATE_MIND, urand(22000, 27000)); } - void UpdateAI(uint32 const diff) + void UpdateAI(uint32 diff) { if (!UpdateVictim()) return; @@ -1436,7 +1437,7 @@ class npc_captain_brandon : public CreatureScript Events.ScheduleEvent(EVENT_BRANDON_HAMMER_OF_BETRAYAL, urand(25000, 30000)); } - void UpdateAI(uint32 const diff) + void UpdateAI(uint32 diff) { if (!UpdateVictim()) return; @@ -1504,7 +1505,7 @@ class npc_captain_grondel : public CreatureScript Events.ScheduleEvent(EVENT_GRONDEL_CONFLAGRATION, urand(12000, 17000)); } - void UpdateAI(uint32 const diff) + void UpdateAI(uint32 diff) { if (!UpdateVictim()) return; @@ -1569,7 +1570,7 @@ class npc_captain_rupert : public CreatureScript Events.ScheduleEvent(EVENT_RUPERT_ROCKET_LAUNCH, urand(10000, 15000)); } - void UpdateAI(uint32 const diff) + void UpdateAI(uint32 diff) { if (!UpdateVictim()) return; @@ -1654,7 +1655,7 @@ class npc_impaling_spear : public CreatureScript _vehicleCheckTimer = 500; } - void UpdateAI(uint32 const diff) + void UpdateAI(uint32 diff) { if (_vehicleCheckTimer <= diff) { @@ -1695,7 +1696,7 @@ class npc_arthas_teleport_visual : public CreatureScript _events.ScheduleEvent(EVENT_SOUL_MISSILE, urand(1000, 6000)); } - void UpdateAI(uint32 const diff) + void UpdateAI(uint32 diff) { if (_events.Empty()) return; diff --git a/src/server/scripts/Northrend/IcecrownCitadel/icecrown_citadel.h b/src/server/scripts/Northrend/IcecrownCitadel/icecrown_citadel.h index 1407568686f..887a31baf9a 100644 --- a/src/server/scripts/Northrend/IcecrownCitadel/icecrown_citadel.h +++ b/src/server/scripts/Northrend/IcecrownCitadel/icecrown_citadel.h @@ -56,6 +56,7 @@ enum SharedSpells SPELL_FROSTMOURNE_TELEPORT_VISUAL = 73078, // Shadowmourne questline + SPELL_UNSATED_CRAVING = 71168, SPELL_SHADOWS_FATE = 71169 }; diff --git a/src/server/scripts/Northrend/IcecrownCitadel/icecrown_citadel_teleport.cpp b/src/server/scripts/Northrend/IcecrownCitadel/icecrown_citadel_teleport.cpp index 1efee1b45ba..c528b8413af 100644 --- a/src/server/scripts/Northrend/IcecrownCitadel/icecrown_citadel_teleport.cpp +++ b/src/server/scripts/Northrend/IcecrownCitadel/icecrown_citadel_teleport.cpp @@ -42,7 +42,7 @@ class icecrown_citadel_teleport : public GameObjectScript player->ADD_GOSSIP_ITEM(GOSSIP_ICON_CHAT, "Teleport to the Deathbringer's Rise.", GOSSIP_SENDER_ICC_PORT, DEATHBRINGER_S_RISE_TELEPORT); if (instance->GetData(DATA_COLDFLAME_JETS) == DONE) player->ADD_GOSSIP_ITEM(GOSSIP_ICON_CHAT, "Teleport to the Upper Spire.", GOSSIP_SENDER_ICC_PORT, UPPER_SPIRE_TELEPORT); - // TODO: Gauntlet event before Sindragosa + /// @todo Gauntlet event before Sindragosa if (instance->GetBossState(DATA_VALITHRIA_DREAMWALKER) == DONE) player->ADD_GOSSIP_ITEM(GOSSIP_ICON_CHAT, "Teleport to Sindragosa's Lair", GOSSIP_SENDER_ICC_PORT, SINDRAGOSA_S_LAIR_TELEPORT); } diff --git a/src/server/scripts/Northrend/IcecrownCitadel/instance_icecrown_citadel.cpp b/src/server/scripts/Northrend/IcecrownCitadel/instance_icecrown_citadel.cpp index 462708360e3..db4ab2f32d2 100644 --- a/src/server/scripts/Northrend/IcecrownCitadel/instance_icecrown_citadel.cpp +++ b/src/server/scripts/Northrend/IcecrownCitadel/instance_icecrown_citadel.cpp @@ -435,7 +435,7 @@ class instance_icecrown_citadel : public InstanceMapScript // these 2 gates are functional only on 25man modes case GO_DOODAD_ICECROWN_ROOSTPORTCULLIS_01: case GO_DOODAD_ICECROWN_ROOSTPORTCULLIS_04: - if (instance->GetSpawnMode() & 1) + if (instance->Is25ManRaid()) AddDoor(go, true); break; case GO_LADY_DEATHWHISPER_ELEVATOR: @@ -954,7 +954,7 @@ class instance_icecrown_citadel : public InstanceMapScript bool CheckRequiredBosses(uint32 bossId, Player const* player = NULL) const { - if (player && AccountMgr::IsGMAccount(player->GetSession()->GetSecurity())) + if (player && player->GetSession()->HasPermission(RBAC_PERM_SKIP_CHECK_INSTANCE_REQUIRED_BOSSES)) return true; switch (bossId) diff --git a/src/server/scripts/Northrend/Naxxramas/boss_anubrekhan.cpp b/src/server/scripts/Northrend/Naxxramas/boss_anubrekhan.cpp index 14e2d05a7c1..421dabf48ac 100644 --- a/src/server/scripts/Northrend/Naxxramas/boss_anubrekhan.cpp +++ b/src/server/scripts/Northrend/Naxxramas/boss_anubrekhan.cpp @@ -95,7 +95,7 @@ public: void KilledUnit(Unit* victim) { - //Force the player to spawn corpse scarabs via spell, TODO: Check percent chance for scarabs, 20% at the moment + /// Force the player to spawn corpse scarabs via spell, @todo Check percent chance for scarabs, 20% at the moment if (!(rand()%5)) if (victim->GetTypeId() == TYPEID_PLAYER) victim->CastSpell(victim, SPELL_SUMMON_CORPSE_SCARABS_PLR, true, NULL, NULL, me->GetGUID()); @@ -144,7 +144,7 @@ public: summon->CastSpell(summon, SPELL_SUMMON_CORPSE_SCARABS_MOB, true, NULL, NULL, me->GetGUID()); } - void UpdateAI(const uint32 diff) + void UpdateAI(uint32 diff) { if (!UpdateVictim() || !CheckInRoom()) return; @@ -164,13 +164,13 @@ public: events.ScheduleEvent(EVENT_IMPALE, urand(10000, 20000)); break; case EVENT_LOCUST: - // TODO : Add Text + /// @todo Add Text DoCast(me, RAID_MODE(SPELL_LOCUST_SWARM_10, SPELL_LOCUST_SWARM_25)); DoSummon(MOB_CRYPT_GUARD, GuardSummonPos, 0, TEMPSUMMON_CORPSE_DESPAWN); events.ScheduleEvent(EVENT_LOCUST, 90000); break; case EVENT_SPAWN_GUARDIAN_NORMAL: - // TODO : Add Text + /// @todo Add Text DoSummon(MOB_CRYPT_GUARD, GuardSummonPos, 0, TEMPSUMMON_CORPSE_DESPAWN); break; case EVENT_BERSERK: diff --git a/src/server/scripts/Northrend/Naxxramas/boss_faerlina.cpp b/src/server/scripts/Northrend/Naxxramas/boss_faerlina.cpp index 4d5efe4e89c..316ddee540c 100644 --- a/src/server/scripts/Northrend/Naxxramas/boss_faerlina.cpp +++ b/src/server/scripts/Northrend/Naxxramas/boss_faerlina.cpp @@ -107,7 +107,7 @@ class boss_faerlina : public CreatureScript { if (spell->Id == SPELL_WIDOWS_EMBRACE || spell->Id == H_SPELL_WIDOWS_EMBRACE) { - // TODO : Add Text + /// @todo Add Text ++_frenzyDispels; _delayFrenzy = true; me->Kill(caster); @@ -122,7 +122,7 @@ class boss_faerlina : public CreatureScript return 0; } - void UpdateAI(uint32 const diff) + void UpdateAI(uint32 diff) { if (!UpdateVictim()) return; @@ -153,7 +153,7 @@ class boss_faerlina : public CreatureScript events.ScheduleEvent(EVENT_FIRE, urand(6000, 18000)); break; case EVENT_FRENZY: - // TODO : Add Text + /// @todo Add Text if (!me->HasAura(SPELL_WIDOWS_EMBRACE_HELPER)) DoCast(me, RAID_MODE(SPELL_FRENZY, H_SPELL_FRENZY)); else diff --git a/src/server/scripts/Northrend/Naxxramas/boss_four_horsemen.cpp b/src/server/scripts/Northrend/Naxxramas/boss_four_horsemen.cpp index e037f627bee..9013b051b9a 100644 --- a/src/server/scripts/Northrend/Naxxramas/boss_four_horsemen.cpp +++ b/src/server/scripts/Northrend/Naxxramas/boss_four_horsemen.cpp @@ -326,7 +326,7 @@ public: events.ScheduleEvent(EVENT_BERSERK, 15*100*1000); } - void UpdateAI(const uint32 diff) + void UpdateAI(uint32 diff) { if (nextWP && movementStarted && !movementCompleted && !nextMovementStarted) { diff --git a/src/server/scripts/Northrend/Naxxramas/boss_gluth.cpp b/src/server/scripts/Northrend/Naxxramas/boss_gluth.cpp index c735107968a..86ea9ce929a 100644 --- a/src/server/scripts/Northrend/Naxxramas/boss_gluth.cpp +++ b/src/server/scripts/Northrend/Naxxramas/boss_gluth.cpp @@ -69,7 +69,7 @@ public: if (who->GetEntry() == MOB_ZOMBIE && me->IsWithinDistInMap(who, 7)) { SetGazeOn(who); - // TODO: use a script text + /// @todo use a script text me->MonsterTextEmote(EMOTE_NEARBY, 0, true); } else @@ -93,7 +93,7 @@ public: summons.Summon(summon); } - void UpdateAI(const uint32 diff) + void UpdateAI(uint32 diff) { if (!UpdateVictimWithGaze() || !CheckInRoom()) return; @@ -109,12 +109,12 @@ public: events.ScheduleEvent(EVENT_WOUND, 10000); break; case EVENT_ENRAGE: - // TODO : Add missing text + /// @todo Add missing text DoCast(me, SPELL_ENRAGE); events.ScheduleEvent(EVENT_ENRAGE, 15000); break; case EVENT_DECIMATE: - // TODO : Add missing text + /// @todo Add missing text DoCastAOE(SPELL_DECIMATE); events.ScheduleEvent(EVENT_DECIMATE, 105000); break; diff --git a/src/server/scripts/Northrend/Naxxramas/boss_gothik.cpp b/src/server/scripts/Northrend/Naxxramas/boss_gothik.cpp index 21f3141393a..451992b1d91 100644 --- a/src/server/scripts/Northrend/Naxxramas/boss_gothik.cpp +++ b/src/server/scripts/Northrend/Naxxramas/boss_gothik.cpp @@ -393,7 +393,7 @@ class boss_gothik : public CreatureScript } } - void UpdateAI(uint32 const diff) + void UpdateAI(uint32 diff) { if (!UpdateVictim() || !CheckInRoom()) return; @@ -524,7 +524,7 @@ class mob_gothik_minion : public CreatureScript return (liveSide == IN_LIVE_SIDE(who)); } - void DoAction(int32 const param) + void DoAction(int32 param) { gateClose = param; } @@ -574,7 +574,7 @@ class mob_gothik_minion : public CreatureScript Reset(); } - void UpdateAI(uint32 const diff) + void UpdateAI(uint32 diff) { if (gateClose && (!isOnSameSide(me) || (me->getVictim() && !isOnSameSide(me->getVictim())))) { diff --git a/src/server/scripts/Northrend/Naxxramas/boss_grobbulus.cpp b/src/server/scripts/Northrend/Naxxramas/boss_grobbulus.cpp index f3f2e587178..3e44fe9eba4 100644 --- a/src/server/scripts/Northrend/Naxxramas/boss_grobbulus.cpp +++ b/src/server/scripts/Northrend/Naxxramas/boss_grobbulus.cpp @@ -20,25 +20,33 @@ #include "naxxramas.h" #include "SpellInfo.h" -#define SPELL_BOMBARD_SLIME 28280 - -#define SPELL_POISON_CLOUD 28240 -#define SPELL_MUTATING_INJECTION 28169 -#define SPELL_SLIME_SPRAY RAID_MODE(28157, 54364) -#define SPELL_BERSERK 26662 -#define SPELL_POISON_CLOUD_ADD 59116 +enum Spells +{ + SPELL_BOMBARD_SLIME = 28280, + SPELL_POISON_CLOUD = 28240, + SPELL_MUTATING_INJECTION = 28169, + SPELL_SLIME_SPRAY = 28157, + H_SPELL_SLIME_SPRAY = 54364, + SPELL_BERSERK = 26662, + SPELL_POISON_CLOUD_ADD = 59116 +}; -#define EVENT_BERSERK 1 -#define EVENT_CLOUD 2 -#define EVENT_INJECT 3 -#define EVENT_SPRAY 4 +enum Events +{ + EVENT_BERSERK = 0, + EVENT_CLOUD = 1, + EVENT_INJECT = 2, + EVENT_SPRAY = 3 +}; -#define MOB_FALLOUT_SLIME 16290 +enum CreatureId +{ + MOB_FALLOUT_SLIME = 16290 +}; class boss_grobbulus : public CreatureScript { -public: - boss_grobbulus() : CreatureScript("boss_grobbulus") { } +public: boss_grobbulus() : CreatureScript("boss_grobbulus") { } CreatureAI* GetAI(Creature* creature) const { @@ -70,7 +78,7 @@ public: } } - void UpdateAI(const uint32 diff) + void UpdateAI(uint32 diff) { if (!UpdateVictim()) return; @@ -117,11 +125,11 @@ public: return new npc_grobbulus_poison_cloudAI(creature); } - struct npc_grobbulus_poison_cloudAI : public Scripted_NoMovementAI + struct npc_grobbulus_poison_cloudAI : public ScriptedAI { - npc_grobbulus_poison_cloudAI(Creature* creature) : Scripted_NoMovementAI(creature) + npc_grobbulus_poison_cloudAI(Creature* creature) : ScriptedAI(creature) { - Reset(); + SetCombatMovement(false); } uint32 Cloud_Timer; @@ -132,7 +140,7 @@ public: me->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE); } - void UpdateAI(const uint32 diff) + void UpdateAI(uint32 diff) { if (Cloud_Timer <= diff) { diff --git a/src/server/scripts/Northrend/Naxxramas/boss_heigan.cpp b/src/server/scripts/Northrend/Naxxramas/boss_heigan.cpp index c88ac807421..61640f1d225 100644 --- a/src/server/scripts/Northrend/Naxxramas/boss_heigan.cpp +++ b/src/server/scripts/Northrend/Naxxramas/boss_heigan.cpp @@ -133,7 +133,7 @@ public: } } - void UpdateAI(const uint32 diff) + void UpdateAI(uint32 diff) { if (!UpdateVictim() || !CheckInRoom()) return; @@ -153,7 +153,7 @@ public: events.ScheduleEvent(EVENT_FEVER, urand(20000, 25000)); break; case EVENT_PHASE: - // TODO : Add missing texts for both phase switches + /// @todo Add missing texts for both phase switches EnterPhase(phase == PHASE_FIGHT ? PHASE_DANCE : PHASE_FIGHT); break; case EVENT_ERUPT: diff --git a/src/server/scripts/Northrend/Naxxramas/boss_kelthuzad.cpp b/src/server/scripts/Northrend/Naxxramas/boss_kelthuzad.cpp index 35f703e0563..9b5b26dd4f5 100644 --- a/src/server/scripts/Northrend/Naxxramas/boss_kelthuzad.cpp +++ b/src/server/scripts/Northrend/Naxxramas/boss_kelthuzad.cpp @@ -382,7 +382,7 @@ public: KTTriggerGUID = instance ? instance->GetData64(DATA_KELTHUZAD_TRIGGER) : 0; } - void UpdateAI(const uint32 diff) + void UpdateAI(uint32 diff) { if (!UpdateVictim()) return; @@ -474,7 +474,7 @@ public: { if (uiGuardiansOfIcecrownTimer <= diff) { - // TODO : Add missing text + /// @todo Add missing text if (Creature* pGuardian = DoSummon(NPC_ICECROWN, Pos[RAND(2, 5, 8, 11)])) pGuardian->SetFloatValue(UNIT_FIELD_COMBATREACH, 2); ++nGuardiansOfIcecrownCount; @@ -603,7 +603,7 @@ public: ThreatContainer::StorageType const &threatList = me->getThreatManager().getThreatList(); for (ThreatContainer::StorageType::const_iterator itr = threatList.begin(); itr != threatList.end(); ++itr) { - Unit * const target = (*itr)->getTarget(); + Unit* const target = (*itr)->getTarget(); if (target->GetTypeId() == TYPEID_PLAYER && target->getPowerType() == POWER_MANA @@ -735,7 +735,7 @@ class npc_kelthuzad_abomination : public CreatureScript DoCast(me, SPELL_FRENZY, true); } - void UpdateAI(uint32 const diff) + void UpdateAI(uint32 diff) { if (!UpdateVictim()) return; diff --git a/src/server/scripts/Northrend/Naxxramas/boss_loatheb.cpp b/src/server/scripts/Northrend/Naxxramas/boss_loatheb.cpp index 75fe66b9faf..3664a166a9f 100644 --- a/src/server/scripts/Northrend/Naxxramas/boss_loatheb.cpp +++ b/src/server/scripts/Northrend/Naxxramas/boss_loatheb.cpp @@ -93,7 +93,7 @@ class boss_loatheb : public CreatureScript return uint32(_sporeLoserData); } - void UpdateAI(uint32 const diff) + void UpdateAI(uint32 diff) { if (!UpdateVictim()) return; diff --git a/src/server/scripts/Northrend/Naxxramas/boss_maexxna.cpp b/src/server/scripts/Northrend/Naxxramas/boss_maexxna.cpp index 28def13a0d2..f1b2d9aeaed 100644 --- a/src/server/scripts/Northrend/Naxxramas/boss_maexxna.cpp +++ b/src/server/scripts/Northrend/Naxxramas/boss_maexxna.cpp @@ -85,7 +85,7 @@ public: events.ScheduleEvent(EVENT_SUMMON, 30000); } - void UpdateAI(const uint32 diff) + void UpdateAI(uint32 diff) { if (!UpdateVictim() || !CheckInRoom()) return; @@ -103,7 +103,7 @@ public: switch (eventId) { case EVENT_WRAP: - // TODO : Add missing text + /// @todo Add missing text for (uint8 i = 0; i < RAID_MODE(1, 2); ++i) { if (Unit* target = SelectTarget(SELECT_TARGET_RANDOM, 1, 0, true, -SPELL_WEB_WRAP)) @@ -134,7 +134,7 @@ public: events.ScheduleEvent(EVENT_FRENZY, 600000); break; case EVENT_SUMMON: - // TODO : Add missing text + /// @todo Add missing text uint8 amount = urand(8, 10); for (uint8 i = 0; i < amount; ++i) DoSummon(MOB_SPIDERLING, me, 0, TEMPSUMMON_CORPSE_DESPAWN); diff --git a/src/server/scripts/Northrend/Naxxramas/boss_noth.cpp b/src/server/scripts/Northrend/Naxxramas/boss_noth.cpp index 89b65615a2e..d0034628424 100644 --- a/src/server/scripts/Northrend/Naxxramas/boss_noth.cpp +++ b/src/server/scripts/Northrend/Naxxramas/boss_noth.cpp @@ -145,7 +145,7 @@ public: } } - void UpdateAI(const uint32 diff) + void UpdateAI(uint32 diff) { if (!UpdateVictim() || !CheckInRoom()) return; diff --git a/src/server/scripts/Northrend/Naxxramas/boss_patchwerk.cpp b/src/server/scripts/Northrend/Naxxramas/boss_patchwerk.cpp index e77a9708ba5..13a5340fa8e 100644 --- a/src/server/scripts/Northrend/Naxxramas/boss_patchwerk.cpp +++ b/src/server/scripts/Northrend/Naxxramas/boss_patchwerk.cpp @@ -98,7 +98,7 @@ public: instance->DoStartTimedAchievement(ACHIEVEMENT_TIMED_TYPE_EVENT, ACHIEV_MAKE_QUICK_WERK_OF_HIM_STARTING_EVENT); } - void UpdateAI(const uint32 diff) + void UpdateAI(uint32 diff) { if (!UpdateVictim()) return; diff --git a/src/server/scripts/Northrend/Naxxramas/boss_razuvious.cpp b/src/server/scripts/Northrend/Naxxramas/boss_razuvious.cpp index 52dfd60f5f8..c78f7d0a757 100644 --- a/src/server/scripts/Northrend/Naxxramas/boss_razuvious.cpp +++ b/src/server/scripts/Northrend/Naxxramas/boss_razuvious.cpp @@ -86,7 +86,7 @@ public: { _JustDied(); DoPlaySoundToSet(me, SOUND_DEATH); - me->CastSpell(me, SPELL_HOPELESS, true); // TODO: this may affect other creatures + me->CastSpell(me, SPELL_HOPELESS, true); /// @todo this may affect other creatures } void EnterCombat(Unit* /*who*/) @@ -99,7 +99,7 @@ public: events.ScheduleEvent(EVENT_KNIFE, 10000); } - void UpdateAI(const uint32 diff) + void UpdateAI(uint32 diff) { if (!UpdateVictim()) return; diff --git a/src/server/scripts/Northrend/Naxxramas/boss_sapphiron.cpp b/src/server/scripts/Northrend/Naxxramas/boss_sapphiron.cpp index cd68d7ecac3..878107ab35d 100644 --- a/src/server/scripts/Northrend/Naxxramas/boss_sapphiron.cpp +++ b/src/server/scripts/Northrend/Naxxramas/boss_sapphiron.cpp @@ -159,7 +159,7 @@ class boss_sapphiron : public CreatureScript events.ScheduleEvent(EVENT_LIFTOFF, 0); } - void DoAction(int32 const param) + void DoAction(int32 param) { if (param == DATA_SAPPHIRON_BIRTH) { @@ -217,7 +217,7 @@ class boss_sapphiron : public CreatureScript return 0; } - void UpdateAI(uint32 const diff) + void UpdateAI(uint32 diff) { if (!_phase) return; diff --git a/src/server/scripts/Northrend/Naxxramas/boss_thaddius.cpp b/src/server/scripts/Northrend/Naxxramas/boss_thaddius.cpp index 6c09e7156fe..ea50c67ad1c 100644 --- a/src/server/scripts/Northrend/Naxxramas/boss_thaddius.cpp +++ b/src/server/scripts/Northrend/Naxxramas/boss_thaddius.cpp @@ -159,7 +159,7 @@ public: Talk(SAY_DEATH); } - void DoAction(const int32 action) + void DoAction(int32 action) { switch (action) { @@ -218,7 +218,7 @@ public: return uint32(polaritySwitch); } - void UpdateAI(const uint32 diff) + void UpdateAI(uint32 diff) { if (checkFeugenAlive && checkStalaggAlive) uiAddsTimer = 0; @@ -331,7 +331,7 @@ public: pThaddius->AI()->DoAction(ACTION_STALAGG_DIED); } - void UpdateAI(const uint32 uiDiff) + void UpdateAI(uint32 uiDiff) { if (!UpdateVictim()) return; @@ -423,7 +423,7 @@ public: pThaddius->AI()->DoAction(ACTION_FEUGEN_DIED); } - void UpdateAI(const uint32 uiDiff) + void UpdateAI(uint32 uiDiff) { if (!UpdateVictim()) return; diff --git a/src/server/scripts/Northrend/Nexus/EyeOfEternity/boss_malygos.cpp b/src/server/scripts/Northrend/Nexus/EyeOfEternity/boss_malygos.cpp index 952363c6dcf..47e39574690 100644 --- a/src/server/scripts/Northrend/Nexus/EyeOfEternity/boss_malygos.cpp +++ b/src/server/scripts/Northrend/Nexus/EyeOfEternity/boss_malygos.cpp @@ -16,143 +16,207 @@ */ /* Script Data Start -SDName: Boss malygos +SDName: Boss Malygos Script Data End */ -// TO-DOs: -// Implement a better pathing for Malygos. -// Find sniffed spawn position for chest -// Implement a better way to disappear the gameobjects -// Implement achievements -// Remove hack that re-adds targets to the aggro list after they enter to a vehicle when it works as expected -// Improve whatever can be improved :) - #include "ScriptMgr.h" #include "ScriptedCreature.h" #include "SpellScript.h" #include "SpellAuraEffects.h" -#include "PassiveAI.h" #include "eye_of_eternity.h" -#include "ScriptedEscortAI.h" #include "Player.h" #include "Vehicle.h" #include "CombatAI.h" +#include "GameObjectAI.h" #include "CreatureTextMgr.h" - -enum Achievements -{ - ACHIEV_TIMED_START_EVENT = 20387, -}; +#include "MoveSplineInit.h" enum Events { - // =========== PHASE ONE =============== - EVENT_ARCANE_BREATH = 1, - EVENT_ARCANE_STORM = 2, - EVENT_VORTEX = 3, - EVENT_POWER_SPARKS = 4, + // =========== INTRO BEFORE WE START ENCOUNTER =============== + EVENT_STOP_PORTAL_BEAM = 1, + EVENT_RANDOM_PORTAL = 2, + EVENT_SAY_INTRO = 3, + EVENT_LAND_START_ENCOUNTER = 4, - // =========== PHASE TWO =============== - EVENT_SURGE_POWER = 5, // wowhead is wrong, Surge of Power is casted instead of Arcane Pulse (source sniffs!) - EVENT_SUMMON_ARCANE = 6, + // =========== PHASE ONE =============== + EVENT_ARCANE_BREATH = 5, + EVENT_ARCANE_STORM = 6, + EVENT_VORTEX = 7, + EVENT_POWER_SPARKS = 8, // =========== PHASE TWO =============== - EVENT_SURGE_POWER_PHASE_3 = 7, - EVENT_STATIC_FIELD = 8, - - // =============== YELLS =============== - EVENT_YELL_0 = 9, - EVENT_YELL_1 = 10, - EVENT_YELL_2 = 11, - EVENT_YELL_3 = 12, - EVENT_YELL_4 = 13, + EVENT_FLY_OUT_OF_PLATFORM = 9, + EVENT_DELAYED_REINFORCEMENTS = 10, + EVENT_PATHING_AROUND_PLATFORM = 11, + EVENT_SURGE_OF_POWER_P_TWO = 12, + EVENT_SUMMON_ARCANE_BOMB = 13, + EVENT_MOVE_TO_POINT_SURGE_P_TWO = 14, + EVENT_LIGHT_DIMENSION_CHANGE = 15, + EVENT_MOVE_TO_P_THREE_POINT = 16, + EVENT_START_P_THREE = 17, + + // =========== PHASE THREE ============= + EVENT_ARCANE_PULSE = 18, + EVENT_SURGE_OF_POWER_P_THREE = 19, + EVENT_STATIC_FIELD = 20, + + // ========== MISC MECHANICS =========== + EVENT_PREVENT_SAY_SPAM_ON_KILL = 21, + EVENT_MOVE_TO_VORTEX_POINT = 22, // This should be fixed someday in core, we can't call new movement from MovementInform + EVENT_START_FIRST_RANDOM_PORTAL = 23, // There is something that is still loading when we first enter instance and it breaks + // first visual cast of intro portal beam mechanic, so we need short delay from the event. + EVENT_DELAY_MOVE_TO_DESTROY_P = 24, // If Malygos is too close to destroy platform point and transition from II to III is hit, + // this event will be sheduled to start after 5 seconds so there is enough time for "dimension change". + + // ============ NEXUS LORDS ============ + EVENT_ARCANE_SHOCK = 1, + EVENT_HASTE_BUFF = 2, + EVENT_NUKE_DUMMY = 3, + + // ======== SCIONS OF ETERNITY ========= + EVENT_ARCANE_BARRAGE = 1, + + // ======== WYRMREST SKYTALON ========== + EVENT_CAST_RIDE_SPELL = 1 }; enum Phases { - PHASE_ONE = 1, - PHASE_TWO = 2, - PHASE_THREE = 3 + PHASE_NOT_STARTED = 1, + PHASE_ONE = 2, + PHASE_TWO = 3, + PHASE_THREE = 4 }; enum Spells { - SPELL_ARCANE_BREATH = 56272, - SPELL_ARCANE_STORM = 57459, - SPELL_BERSEKER = 60670, - - SPELL_VORTEX_1 = 56237, // seems that frezze object animation - SPELL_VORTEX_2 = 55873, // visual effect - SPELL_VORTEX_3 = 56105, // this spell must handle all the script - casted by the boss and to himself - //SPELL_VORTEX_4 = 55853, // damage | used to enter to the vehicle - defined in eye_of_eternity.h - //SPELL_VORTEX_5 = 56263, // damage | used to enter to the vehicle - defined in eye_of_eternity.h - SPELL_VORTEX_6 = 73040, // teleport - (casted to all raid) | caster 30090 | target player - - SPELL_PORTAL_VISUAL_CLOSED = 55949, - SPELL_SUMMON_POWER_PARK = 56142, - SPELL_POWER_SPARK_DEATH = 55852, - SPELL_POWER_SPARK_MALYGOS = 56152, - - SPELL_SURGE_POWER = 56505, // used in phase 2 - SPELL_SUMMON_ARCANE_BOMB = 56429, - SPELL_ARCANE_OVERLOAD = 56432, - SPELL_SUMMOM_RED_DRAGON = 56070, - SPELL_SURGE_POWER_PHASE_3 = 57407, - SPELL_STATIC_FIELD = 57430 + // Intro + SPELL_RANDOM_PORTAL = 56047, + SPELL_PORTAL_BEAM = 56046, // Malygos cast on portal to activate it during PHASE_NOT_STARTED + + //Phase I + SPELL_BERSEKER = 60670, + SPELL_MALYGOS_BERSERK = 47008, // it's the berserk spell that will hit only Malygos after 10 min of 60670 + SPELL_PORTAL_VISUAL_CLOSED = 55949, + SPELL_SUMMON_POWER_PARK = 56142, + SPELL_POWER_SPARK_DEATH = 55852, + SPELL_POWER_SPARK_MALYGOS = 56152, + SPELL_ARCANE_BREATH = 56272, + SPELL_ARCANE_STORM_P_I = 61693, + SPELL_VORTEX_1 = 56237, // seems that frezze object animation + SPELL_VORTEX_2 = 55873, // visual effect + SPELL_VORTEX_3 = 56105, // this spell must handle all the script - casted by the boss and to himself + SPELL_VORTEX_6 = 73040, // teleport - (casted to all raid), caster vortex bunnies, targets players. + + // Phase II + SPELL_TELEPORT_VISUAL_ONLY = 41232, // Light blue animation cast by arcane NPCs when spawned on Hover Disks + SPELL_RIDE_HOVER_DISK = 61421, + SPELL_ALIGN_DISK_AGGRO = 61210, + SPELL_DUMMY_NUKE = 61215, + SPELL_SUMMON_ARCANE_BOMB = 56429, + SPELL_ARCANE_BOMB_TRIGGER = 56430, + SPELL_ARCANE_BOMB_KNOCKBACK_DAMAGE = 56431, + SPELL_ARCANE_OVERLOAD_1 = 56432, // casted by npc Arcane Overload ID: 30282 + // SPELL_ARCANE_OVERLOAD_2 = 56435, // Triggered by 56432 - resizing target + // SPELL_ARCANE_OVERLOAD_3 = 56438, // Triggered by 56432 - damage reduction + SPELL_SURGE_OF_POWER_P_II = 56505, + // SPELL_SURGE_OF_POWER_TRIGGERED = 56548, + SPELL_ARCANE_SHOCK = 57058, // used by Nexus Lords + SPELL_HASTE = 57060, // used by Nexus Lords + SPELL_ARCANE_BARRAGE = 56397, // used by Scions of Eternity + SPELL_ARCANE_BARRAGE_DAMAGE = 63934, // the actual damage - cast by affected player by script spell + + // Transition /II-III/ + SPELL_SUMMOM_RED_DRAGON_BUDYY = 56070, + SPELL_RIDE_RED_DRAGON_BUDDY = 56071, + SPELL_SUMMON_RED_DRAGON_BUDDY_F_CAST = 58846, // After implicitly hit player targets they will force cast 56070 on self + SPELL_DESTROY_PLATFORM_CHANNEL = 58842, + SPELL_DESTROY_PLATFORM_BOOM_VISUAL = 59084, + SPELL_DESTROY_PLATFORM_EVENT = 59099, + + // Phase III + SPELL_CLEAR_ALL_DEBUFFS = 34098, + SPELL_IMMUNE_CURSES = 64515, + SPELL_STATIC_FIELD_MISSLE = 57430, + SPELL_ARCANE_PULSE = 57432, + SPELL_SURGE_OF_POWER_PHASE_3_10 = 57407, + SPELL_SURGE_OF_POWER_PHASE_3_25 = 60936, + SPELL_SURGE_OF_POWER_WARNING_SELECTOR_25 = 60939, // used in 25 player mode for selecting targets for warnings and then sends to actual spell + SPELL_ARCANE_STORM_P_III = 57459, + + // Phase I and III + SPELL_ARCANE_STORM_EXTRA_VISUAL = 57473, + + // Outro + SPELL_ALEXSTRASZAS_GIFT_BEAM_VISUAL = 61023 }; enum Movements { - MOVE_VORTEX = 1, - MOVE_PHASE_TWO, - MOVE_DEEP_BREATH_ROTATION, - MOVE_INIT_PHASE_ONE, - MOVE_CENTER_PLATFORM + POINT_NEAR_RANDOM_PORTAL_P_NONE = 1, + POINT_LAND_P_ONE, + POINT_VORTEX_P_ONE, + POINT_LAND_AFTER_VORTEX_P_ONE, + POINT_LIFT_IN_AIR_P_ONE, + POINT_PHASE_ONE_TO_TWO_TRANSITION, + POINT_FLY_OUT_OF_PLATFORM_P_TWO, + POINT_SURGE_OF_POWER_P_TWO, + POINT_DESTROY_PLATFORM_P_TWO, + POINT_IDLE_P_THREE, }; enum Seats { - SEAT_0 = 0, + SEAT_0 = 0 }; enum Factions { - FACTION_FRIENDLY = 35, - FACTION_HOSTILE = 14 + // Needed for melee hover disks /when Nexus Lords die/ + FACTION_FRIENDLY = 35 }; enum Actions { - ACTION_HOVER_DISK_START_WP_1, - ACTION_HOVER_DISK_START_WP_2 -}; - -enum MalygosEvents -{ - DATA_SUMMON_DEATHS, // phase 2 - DATA_PHASE + // Malygos + ACTION_LAND_ENCOUNTER_START = 0, + ACTION_EXECUTE_VORTEX = 1, + ACTION_HANDLE_P_THREE_INTRO = 2, + ACTION_LIFT_IN_AIR = 3, + ACTION_HANDLE_RESPAWN = 4, + ACTION_CYCLIC_MOVEMENT = 5, + + // Caster hover disk despawn action + ACTION_DELAYED_DESPAWN = 8, + + // Nexus Lord's action used to shedule casting spell that determine disk's target to chase + ACTION_SET_DISK_VICTIM_CHASE = 0 }; -#define TEN_MINUTES 600000 - enum Texts { // Malygos - SAY_AGGRO_P_ONE = 0, - SAY_KILLED_PLAYER_P_ONE = 1, - SAY_END_P_ONE = 2, - SAY_AGGRO_P_TWO = 3, - SAY_ANTI_MAGIC_SHELL = 4, // not sure when execute it - SAY_MAGIC_BLAST = 5, // not sure when execute it - SAY_KILLED_PLAYER_P_TWO = 6, - SAY_END_P_TWO = 7, - SAY_INTRO_P_THREE = 8, - SAY_AGGRO_P_THREE = 9, - SAY_SURGE_POWER = 10, // not sure when execute it - SAY_BUFF_SPARK = 11, - SAY_KILLED_PLAYER_P_THREE = 12, - SAY_SPELL_CASTING_P_THREE = 13, - SAY_DEATH, + SAY_INTRO_EVENT = 0, + SAY_START_P_ONE = 1, + SAY_DEEP_BREATH = 2, + SAY_KILLED_PLAYER_P_ONE = 3, + SAY_END_P_ONE = 4, + // SAY_START_P_TWO = 5, // Unused by Blizzard for some reason on any version + SAY_ANTI_MAGIC_SHELL = 6, + SAY_MAGIC_BLAST = 7, + SAY_KILLED_PLAYER_P_TWO = 8, + SAY_END_P_TWO = 9, + SAY_START_P_THREE = 10, + // SAY_START_P_THREE = 11, // Unused by Blizzard for some reason on any version + EMOTE_SURGE_OF_POWER_WARNING_P2 = 12, + SAY_SURGE_OF_POWER = 13, + SAY_BUFF_SPARK = 14, + SAY_KILLED_PLAYER_P_THREE = 15, + SAY_SPELL_CASTING_P_THREE = 16, + SAY_DEATH = 17, + EMOTE_SURGE_OF_POWER_WARNING_P3 = 18, + EMOTE_HIT_BERSERKER_TIMER = 19, // Alexstrasza SAY_ONE = 0, @@ -161,252 +225,442 @@ enum Texts SAY_FOUR = 3, // Power Sparks - EMOTE_POWER_SPARK_SUMMONED = 0 + EMOTE_POWER_SPARK_SUMMONED = 0 }; +#define MAX_SUMMONS_PHASE_TWO_10MAN 6 +#define MAX_SUMMONS_PHASE_TWO_25MAN 12 -#define MAX_HOVER_DISK_WAYPOINTS 18 +#define MAX_RANGE_HOVER_DISK_SPAWNPOINTS 8 +Position const RangeHoverDisksSpawnPositions[MAX_RANGE_HOVER_DISK_SPAWNPOINTS] = +{ + { 782.9821f, 1296.652f, 282.1114f, 0.0f }, + { 764.3126f, 1328.871f, 282.3091f, 0.0f }, + { 725.8506f, 1306.749f, 282.2698f, 0.0f }, + { 744.5175f, 1274.396f, 282.3402f, 0.0f }, + { 764.3936f, 1274.371f, 282.6011f, 0.0f }, + { 779.3761f, 1316.166f, 282.1653f, 0.0f }, + { 744.4915f, 1328.901f, 282.2112f, 0.0f }, + { 729.2364f, 1287.328f, 282.4173f, 0.0f } +}; -// Sniffed data (x, y,z) -const Position HoverDiskWaypoints[MAX_HOVER_DISK_WAYPOINTS] = +#define MAX_MELEE_HOVER_DISK_SPAWNPOINTS 4 +Position const MeleeHoverDisksSpawnPositions[MAX_RANGE_HOVER_DISK_SPAWNPOINTS] = { - {782.9821f, 1296.652f, 282.1114f, 0.0f}, - {779.5459f, 1287.228f, 282.1393f, 0.0f}, - {773.0028f, 1279.52f, 282.4164f, 0.0f}, - {764.3626f, 1274.476f, 282.4731f, 0.0f}, - {754.3961f, 1272.639f, 282.4171f, 0.0f}, - {744.4422f, 1274.412f, 282.222f, 0.0f}, - {735.575f, 1279.742f, 281.9674f, 0.0f}, - {729.2788f, 1287.187f, 281.9943f, 0.0f}, - {726.1191f, 1296.688f, 282.2997f, 0.0f}, - {725.9396f, 1306.531f, 282.2448f, 0.0f}, - {729.3045f, 1316.122f, 281.9108f, 0.0f}, - {735.8322f, 1323.633f, 282.1887f, 0.0f}, - {744.4616f, 1328.999f, 281.9948f, 0.0f}, - {754.4739f, 1330.666f, 282.049f, 0.0f}, - {764.074f, 1329.053f, 281.9949f, 0.0f}, - {772.8409f, 1323.951f, 282.077f, 0.0f}, - {779.5085f, 1316.412f, 281.9145f, 0.0f}, - {782.8365f, 1306.778f, 282.3035f, 0.0f}, + { 754.4617f, 1283.859f, 285.0522f, 0.0f }, + { 771.7864f, 1301.853f, 285.0522f, 0.0f }, + { 753.9635f, 1319.003f, 285.0522f, 0.0f }, + { 736.4914f, 1301.683f, 285.0522f, 0.0f } }; -#define GROUND_Z 268 +#define MAX_MELEE_HOVER_DISK_WAYPOINTS 16 +Position const MeleeHoverDisksWaypoints[MAX_MELEE_HOVER_DISK_WAYPOINTS] = +{ + // First melee hover disk wps + { 766.2931f, 1312.904f, 277.0551f, 0.0f }, + { 754.3397f, 1319.759f, 274.0536f, 0.0f }, + { 742.1018f, 1312.714f, 270.1367f, 0.0f }, + { 735.6851f, 1301.422f, 266.7208f, 0.0f }, + // Second melee hover disk wps + { 742.6257f, 1313.471f, 275.9713f, 0.0f }, + { 736.8845f, 1301.921f, 274.0264f, 0.0f }, + { 742.6632f, 1289.951f, 269.8603f, 0.0f }, + { 754.3682f, 1283.942f, 266.6098f, 0.0f }, + // Third melee hover disk wps + { 742.2078f, 1290.518f, 276.2484f, 0.0f }, + { 754.5398f, 1284.311f, 273.5815f, 0.0f }, + { 766.5588f, 1290.345f, 269.6655f, 0.0f }, + { 773.4768f, 1301.474f, 266.5821f, 0.0f }, + // Forth melee hover disk wps + { 766.1189f, 1290.197f, 276.9436f, 0.0f }, + { 771.9507f, 1301.602f, 273.9712f, 0.0f }, + { 766.1253f, 1313.451f, 270.4991f, 0.0f }, + { 754.5378f, 1319.399f, 266.6653f, 0.0f } +}; -// Source: Sniffs (x,y,z) -#define MALYGOS_MAX_WAYPOINTS 16 -const Position MalygosPhaseTwoWaypoints[MALYGOS_MAX_WAYPOINTS] = +#define MAX_MALYGOS_POS 10 +Position const MalygosPositions[MAX_MALYGOS_POS] = { - {812.7299f, 1391.672f, 283.2763f, 0.0f}, - {848.2912f, 1358.61f, 283.2763f, 0.0f}, - {853.9227f, 1307.911f, 283.2763f, 0.0f}, - {847.1437f, 1265.538f, 283.2763f, 0.0f}, - {839.9229f, 1245.245f, 283.2763f, 0.0f}, - {827.3463f, 1221.818f, 283.2763f, 0.0f}, - {803.2727f, 1203.851f, 283.2763f, 0.0f}, - {772.9372f, 1197.981f, 283.2763f, 0.0f}, - {732.1138f, 1200.647f, 283.2763f, 0.0f}, - {693.8761f, 1217.995f, 283.2763f, 0.0f}, - {664.5038f, 1256.539f, 283.2763f, 0.0f}, - {650.1497f, 1303.485f, 283.2763f, 0.0f}, - {662.9109f, 1350.291f, 283.2763f, 0.0f}, - {677.6391f, 1377.607f, 283.2763f, 0.0f}, - {704.8198f, 1401.162f, 283.2763f, 0.0f}, - {755.2642f, 1417.1f, 283.2763f, 0.0f}, + { 754.544f, 1301.71f, 320.01f, 0.0f }, // Point destroy platform + { 754.393f, 1301.27f, 292.91f, 0.0f }, // Point Vortex + { 754.362f, 1301.61f, 266.17f, 0.0f }, // Point land after Vortex + { 754.695f, 1301.66f, 316.65f, 0.0f }, // Point Surge of Power phase II + { 755.681f, 1298.41f, 220.06f, 0.0f } // Point idle phase III }; -#define MAX_SUMMONS_PHASE_TWO 4 +Position const AlexstraszaSpawnPos = { 854.551f, 1225.31f, 300.901f, 0.0f }; // Alexstrasza's spawn position +Position const HeartOfMagicSpawnPos = { 755.351f, 1298.31f, 223.909f, 0.0f }; // Heart of Magic spawn position + +#define TEN_MINUTES (10*MINUTE*IN_MILLISECONDS) -#define MAX_MALYGOS_POS 2 -const Position MalygosPositions[MAX_MALYGOS_POS] = +enum Achievements { - {754.544f, 1301.71f, 320.0f, 0.0f}, - {754.39f, 1301.27f, 292.91f, 0.0f}, + ACHIEV_TIMED_START_EVENT = 20387 +}; + +enum AreaIds +{ + AREA_EYE_OF_ETERNITY = 4500 +}; + +enum MiscData +{ + // Lights + LIGHT_GET_DEFAULT_FOR_MAP = 0, + LIGHT_OBSCURE_SPACE = 1822, + LIGHT_CHANGE_DIMENSIONS = 1823, + LIGHT_ARCANE_RUNES = 1824, + LIGHT_OBSCURE_ARCANE_RUNES = 1825, + + // Data (setters/getters) + DATA_SUMMON_DEATHS = 0, // phase 2 + DATA_PHASE = 1, + + // Target guids + DATA_LAST_OVERLOAD_GUID = 13, // used to store last Arcane Overload guid + DATA_FIRST_SURGE_TARGET_GUID = 14, + // DATA_SECOND_SURGE_TARGET_GUID = 15, + // DATA_THIRD_SURGE_TARGET_GUID = 16, + DATA_LAST_TARGET_BARRAGE_GUID = 17, + + NUM_MAX_SURGE_TARGETS = 3, +}; + +// Used to check if summons guids come from vehicles +class VehicleCheckPredicate +{ + public: + bool operator()(uint64 guid) { return IS_VEHICLE_GUID(guid); } }; class boss_malygos : public CreatureScript { public: - boss_malygos() : CreatureScript("boss_malygos") {} - - CreatureAI* GetAI(Creature* creature) const - { - return new boss_malygosAI(creature); - } + boss_malygos() : CreatureScript("boss_malygos") { } struct boss_malygosAI : public BossAI { boss_malygosAI(Creature* creature) : BossAI(creature, DATA_MALYGOS_EVENT) { - // If we enter in combat when MovePoint generator is active, it overrwrites our homeposition - _homePosition = creature->GetHomePosition(); + _despawned = false; // We determine if Malygos will be realocated to spawning position on reset triggered by boss despawn on evade + _flySpeed = me->GetSpeed(MOVE_FLIGHT); // Get initial fly speed, otherwise on each wipe fly speed would add up if we get it } void Reset() { - _Reset(); - - _bersekerTimer = 0; - _currentPos = 0; - - SetPhase(PHASE_ONE, true); - - _delayedMovementTimer = 8000; - _delayedMovement = false; + // EnterEvadeMode and Reset() links are cut for the sake of properly functioning despawner. + if (!_despawned) + _Reset(); _summonDeaths = 0; + _preparingPulsesChecker = 0; + _arcaneOverloadGUID = 0; + _lastHitByArcaneBarrageGUID = 0; + memset(_surgeTargetGUID, 0, sizeof(_surgeTargetGUID)); + + _killSpamFilter = false; + _canAttack = false; + _executingVortex = false; + _arcaneReinforcements = true; + _flyingOutOfPlatform = false; + _firstCyclicMovementStarted = false; + _performingSurgeOfPower = false; + _performingDestroyPlatform = false; - me->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE); - - _cannotMove = true; - - me->SetCanFly(true); - + me->SetDisableGravity(true); + me->SetByteFlag(UNIT_FIELD_BYTES_1, 3, UNIT_BYTE1_FLAG_ALWAYS_STAND | UNIT_BYTE1_FLAG_HOVER); + // TO DO: find what in core is making boss slower than in retail (when correct speed data) or find missing movement flag update or forced spline change + me->SetSpeed(MOVE_FLIGHT, _flySpeed * 0.25f); + if (_despawned) + DoAction(ACTION_HANDLE_RESPAWN); + + SetPhase(PHASE_NOT_STARTED, true); + me->SetReactState(REACT_PASSIVE); if (instance) instance->DoStopTimedAchievement(ACHIEVEMENT_TIMED_TYPE_EVENT, ACHIEV_TIMED_START_EVENT); } uint32 GetData(uint32 data) const { - if (data == DATA_SUMMON_DEATHS) - return _summonDeaths; - else if (data == DATA_PHASE) - return _phase; + switch (data) + { + case DATA_SUMMON_DEATHS: + return _summonDeaths; + case DATA_PHASE: + return _phase; + } return 0; } void SetData(uint32 data, uint32 value) { - if (data == DATA_SUMMON_DEATHS && _phase == PHASE_TWO) + if (data == DATA_SUMMON_DEATHS && _phase == PHASE_TWO && !_despawned) { _summonDeaths = value; - if (_summonDeaths >= MAX_SUMMONS_PHASE_TWO) - StartPhaseThree(); + if (GetDifficulty() == RAID_DIFFICULTY_10MAN_NORMAL) + { + if (_summonDeaths == MAX_SUMMONS_PHASE_TWO_10MAN) + { + _performingDestroyPlatform = true; + DoAction(ACTION_HANDLE_P_THREE_INTRO); + } + } + else if (GetDifficulty() == RAID_DIFFICULTY_25MAN_NORMAL) + { + if (_summonDeaths == MAX_SUMMONS_PHASE_TWO_25MAN) + { + _performingDestroyPlatform = true; + DoAction(ACTION_HANDLE_P_THREE_INTRO); + } + } } } - void EnterEvadeMode() + uint64 GetGUID(int32 type) const { - me->SetHomePosition(_homePosition); + if (type >= DATA_FIRST_SURGE_TARGET_GUID && type < DATA_FIRST_SURGE_TARGET_GUID + NUM_MAX_SURGE_TARGETS) + return _surgeTargetGUID[type - DATA_FIRST_SURGE_TARGET_GUID]; + else if (type == DATA_LAST_TARGET_BARRAGE_GUID) + return _lastHitByArcaneBarrageGUID; - me->SetDisableGravity(true); + return 0; + } - BossAI::EnterEvadeMode(); + void SetGUID(uint64 guid, int32 type) + { + switch (type) + { + case DATA_LAST_OVERLOAD_GUID: + _arcaneOverloadGUID = guid; + break; + case DATA_FIRST_SURGE_TARGET_GUID: + case DATA_FIRST_SURGE_TARGET_GUID + 1: + case DATA_FIRST_SURGE_TARGET_GUID + 2: + _surgeTargetGUID[type - DATA_FIRST_SURGE_TARGET_GUID] = guid; + break; + case DATA_LAST_TARGET_BARRAGE_GUID: + _lastHitByArcaneBarrageGUID = guid; + } + } - if (instance) - instance->SetBossState(DATA_MALYGOS_EVENT, FAIL); + void DoAction(int32 action) + { + switch (action) + { + case ACTION_LAND_ENCOUNTER_START: + events.CancelEventGroup(1); + if (Creature* alexstraszaBunny = me->GetMap()->GetCreature(instance->GetData64(DATA_ALEXSTRASZA_BUNNY_GUID))) + { + Position pos; + pos.m_positionZ = alexstraszaBunny->GetPositionZ(); + alexstraszaBunny->GetNearPoint2D(pos.m_positionX, pos.m_positionY, 30.0f, alexstraszaBunny->GetAngle(me)); + me->GetMotionMaster()->MoveLand(POINT_LAND_P_ONE, pos); + me->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_IMMUNE_TO_NPC); + me->SetReactState(REACT_AGGRESSIVE); + me->SetInCombatWithZone(); + events.ScheduleEvent(EVENT_LAND_START_ENCOUNTER, 7*IN_MILLISECONDS, 1, PHASE_NOT_STARTED); + } + break; + case ACTION_EXECUTE_VORTEX: + DoCast(me, SPELL_VORTEX_1, true); + DoCast(me, SPELL_VORTEX_2, true); + // the vortex execution continues in the dummy effect of this spell (see it's script) + DoCast(me, SPELL_VORTEX_3, true); + break; + case ACTION_LIFT_IN_AIR: + Position _zToLift; + me->GetPosition(&_zToLift); + if (_phase == PHASE_ONE) + { + _zToLift.m_positionZ += 20.0f; + me->GetMotionMaster()->MoveTakeoff(POINT_LIFT_IN_AIR_P_ONE, _zToLift); + } + else if (_phase == PHASE_TWO) + { + _zToLift.m_positionZ = 300.1f; + me->GetMotionMaster()->MoveTakeoff(POINT_PHASE_ONE_TO_TWO_TRANSITION, _zToLift); + } + break; + case ACTION_HANDLE_P_THREE_INTRO: + events.CancelEventGroup(0); + events.CancelEventGroup(1); + events.CancelEventGroup(2); + // Vehicles shouldn't be despawned with 0 delay if the call comes from virtual function that overrides PassengerBoarded. + // Aside from that he doesn't despawn both vehicles and arcane overloads right away, but with some delay. + DummyEntryCheckPredicate pred; + summons.DoAction(ACTION_DELAYED_DESPAWN, pred); + Talk(SAY_END_P_TWO); + me->GetMotionMaster()->Clear(false); + me->StopMoving(); + if (me->GetPositionZ() > 300.0f) + events.ScheduleEvent(EVENT_DELAY_MOVE_TO_DESTROY_P, 5*IN_MILLISECONDS, 0, PHASE_TWO); + else + me->GetMotionMaster()->MovePoint(POINT_DESTROY_PLATFORM_P_TWO, MalygosPositions[0]); + + events.ScheduleEvent(EVENT_LIGHT_DIMENSION_CHANGE, 1*IN_MILLISECONDS, 0, PHASE_TWO); + break; + case ACTION_HANDLE_RESPAWN: + // Teleport to spawn position, we can't use normal relocate + float x, y, z, o; + me->GetRespawnPosition(x, y, z, &o); + me->NearTeleportTo(x, y, z, o); + // Respawn Iris + instance->SetData(DATA_RESPAWN_IRIS, 0); + _despawned = false; + break; + case ACTION_CYCLIC_MOVEMENT: + Movement::MoveSplineInit init(me); + FillCirclePath(MalygosPositions[3], 120.0f, 283.2763f, init.Path(), true); + init.SetFly(); + init.SetCyclic(); + init.Launch(); + break; + } } void SetPhase(uint8 phase, bool setEvents = false) { events.Reset(); - events.SetPhase(phase); _phase = phase; - if (setEvents) SetPhaseEvents(); } - void StartPhaseThree() - { - if (!instance) - return; - - SetPhase(PHASE_THREE, true); - - // this despawns Hover Disks - summons.DespawnAll(); - // players that used Hover Disk are no in the aggro list - me->SetInCombatWithZone(); - ThreatContainer::StorageType const& m_threatlist = me->getThreatManager().getThreatList(); - for (ThreatContainer::StorageType::const_iterator itr = m_threatlist.begin(); itr!= m_threatlist.end(); ++itr) - { - if (Unit* target = (*itr)->getTarget()) - { - if (target->GetTypeId() != TYPEID_PLAYER) - continue; - - // The rest is handled in the AI of the vehicle. - target->CastSpell(target, SPELL_SUMMOM_RED_DRAGON, true); - me->Attack(target, false); - } - } - - if (GameObject* go = GameObject::GetGameObject(*me, instance->GetData64(DATA_PLATFORM))) - go->SetFlag(GAMEOBJECT_FLAGS, GO_FLAG_DESTROYED); // In sniffs it has this flag, but i don't know how is applied. - - // pos sniffed - me->GetMotionMaster()->MoveIdle(); - me->GetMotionMaster()->MovePoint(MOVE_CENTER_PLATFORM, MalygosPositions[0].GetPositionX(), MalygosPositions[0].GetPositionY(), MalygosPositions[0].GetPositionZ()); - } - void SetPhaseEvents() { switch (_phase) { + case PHASE_NOT_STARTED: + events.ScheduleEvent(EVENT_SAY_INTRO, 1*IN_MILLISECONDS, 1, _phase); + events.ScheduleEvent(EVENT_START_FIRST_RANDOM_PORTAL, 2*IN_MILLISECONDS, 1, _phase); + break; case PHASE_ONE: - events.ScheduleEvent(EVENT_ARCANE_BREATH, urand(15, 20)*IN_MILLISECONDS, 0, _phase); - events.ScheduleEvent(EVENT_ARCANE_STORM, urand(5, 10)*IN_MILLISECONDS, 0, _phase); - events.ScheduleEvent(EVENT_VORTEX, urand(30, 40)*IN_MILLISECONDS, 0, _phase); - events.ScheduleEvent(EVENT_POWER_SPARKS, urand(30, 35)*IN_MILLISECONDS, 0, _phase); + events.ScheduleEvent(EVENT_ARCANE_BREATH, urand(8, 10)*IN_MILLISECONDS, 0, _phase); + events.ScheduleEvent(EVENT_ARCANE_STORM, urand(3, 6)*IN_MILLISECONDS, 0, _phase); + events.ScheduleEvent(EVENT_VORTEX, urand(30, 35)*IN_MILLISECONDS, 0, _phase); + events.ScheduleEvent(EVENT_POWER_SPARKS, urand(20, 30)*IN_MILLISECONDS, 0, _phase); break; case PHASE_TWO: - events.ScheduleEvent(EVENT_YELL_0, 0, 0, _phase); - events.ScheduleEvent(EVENT_YELL_1, 24*IN_MILLISECONDS, 0, _phase); - events.ScheduleEvent(EVENT_SURGE_POWER, urand(60, 70)*IN_MILLISECONDS, 0, _phase); - events.ScheduleEvent(EVENT_SUMMON_ARCANE, urand(2, 5)*IN_MILLISECONDS, 0, _phase); + events.ScheduleEvent(EVENT_MOVE_TO_POINT_SURGE_P_TWO, 60*IN_MILLISECONDS, 0, _phase); + me->AI()->DoAction(ACTION_LIFT_IN_AIR); break; case PHASE_THREE: - events.ScheduleEvent(EVENT_YELL_2, 0, 0, _phase); - events.ScheduleEvent(EVENT_YELL_3, 8*IN_MILLISECONDS, 0, _phase); - events.ScheduleEvent(EVENT_YELL_4, 16*IN_MILLISECONDS, 0, _phase); - events.ScheduleEvent(EVENT_SURGE_POWER_PHASE_3, urand(7, 16)*IN_MILLISECONDS, 0, _phase); + events.ScheduleEvent(EVENT_ARCANE_PULSE, 7*IN_MILLISECONDS, 0, _phase); + events.ScheduleEvent(EVENT_ARCANE_STORM, 10*IN_MILLISECONDS, 0, _phase); + events.ScheduleEvent(EVENT_SURGE_OF_POWER_P_THREE, urand(4, 6)*IN_MILLISECONDS, 0, _phase); events.ScheduleEvent(EVENT_STATIC_FIELD, urand(20, 30)*IN_MILLISECONDS, 0, _phase); break; - default: - break; } } + // There are moments where boss will do nothing while being attacked + void AttackStart(Unit* target) + { + if (_canAttack) + BossAI::AttackStart(target); + } + void EnterCombat(Unit* /*who*/) { - _EnterCombat(); + // We can't call full function here since it includes DoZoneInCombat(), + // if someone does it will be returned with a warning. + me->setActive(true); + if (instance) + { + if (!instance->CheckRequiredBosses(DATA_MALYGOS_EVENT)) + { + EnterEvadeMode(); + return; + } + + instance->SetBossState(DATA_MALYGOS_EVENT, IN_PROGRESS); + } + + Talk(SAY_START_P_ONE); + DoCast(SPELL_BERSEKER); // periodic aura, first tick in 10 minutes + if (instance) + instance->DoStartTimedAchievement(ACHIEVEMENT_TIMED_TYPE_EVENT, ACHIEV_TIMED_START_EVENT); + } + + void EnterEvadeMode() + { + if (instance) + instance->SetBossState(DATA_MALYGOS_EVENT, FAIL); - me->SetDisableGravity(false); - me->SetCanFly(false); + SendLightOverride(LIGHT_GET_DEFAULT_FOR_MAP, 1*IN_MILLISECONDS); + + if (_phase == PHASE_THREE) + me->SetControlled(false, UNIT_STATE_ROOT); + uint32 corpseDelay = me->GetCorpseDelay(); + uint32 respawnDelay = me->GetRespawnDelay(); + me->SetCorpseDelay(1); + me->SetRespawnDelay(29); + me->DespawnOrUnsummon(); + me->SetCorpseDelay(corpseDelay); + me->SetRespawnDelay(respawnDelay); + + // Set speed to normal value + me->SetSpeed(MOVE_FLIGHT, _flySpeed); + me->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_IMMUNE_TO_PC); me->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE); + me->RemoveAllAuras(); + me->CombatStop(); // Sometimes threat can remain, so it's a safety measure - Talk(SAY_AGGRO_P_ONE); + if (!_despawned) + _despawned = true; - DoCast(SPELL_BERSEKER); // periodic aura, first tick in 10 minutes + me->ResetLootMode(); + events.Reset(); + if (!summons.empty()) + { + if (_phase == PHASE_TWO) + { + VehicleCheckPredicate pred; + summons.DoAction(ACTION_DELAYED_DESPAWN, pred); + summons.remove_if(pred); + summons.DespawnAll(); + } + else if (_phase == PHASE_THREE) + summons.DespawnAll(); + } if (instance) - instance->DoStartTimedAchievement(ACHIEVEMENT_TIMED_TYPE_EVENT, ACHIEV_TIMED_START_EVENT); + instance->SetBossState(DATA_MALYGOS_EVENT, NOT_STARTED); } - void KilledUnit(Unit* who) + void KilledUnit(Unit* victim) { - if (who->GetTypeId() != TYPEID_PLAYER) + if (victim->GetTypeId() != TYPEID_PLAYER) return; - switch (_phase) + if (!_killSpamFilter) { - case PHASE_ONE: - Talk(SAY_KILLED_PLAYER_P_ONE); - break; - case PHASE_TWO: - Talk(SAY_KILLED_PLAYER_P_TWO); - break; - case PHASE_THREE: - Talk(SAY_KILLED_PLAYER_P_THREE); - break; + switch (_phase) + { + case PHASE_ONE: + Talk(SAY_KILLED_PLAYER_P_ONE); + events.ScheduleEvent(EVENT_PREVENT_SAY_SPAM_ON_KILL, 5*IN_MILLISECONDS, 0, _phase); + _killSpamFilter = true; + break; + case PHASE_TWO: + Talk(SAY_KILLED_PLAYER_P_TWO); + events.ScheduleEvent(EVENT_PREVENT_SAY_SPAM_ON_KILL, 5*IN_MILLISECONDS, 0, _phase); + _killSpamFilter = true; + break; + case PHASE_THREE: + Talk(SAY_KILLED_PLAYER_P_THREE); + events.ScheduleEvent(EVENT_PREVENT_SAY_SPAM_ON_KILL, 5*IN_MILLISECONDS, 0, _phase); + _killSpamFilter = true; + break; + } } } - void SpellHit(Unit* caster, const SpellInfo* spell) + void SpellHit(Unit* caster, SpellInfo const* spell) { if (spell->Id == SPELL_POWER_SPARK_MALYGOS) { @@ -415,346 +669,418 @@ public: Talk(SAY_BUFF_SPARK); } + else if (spell->Id == SPELL_MALYGOS_BERSERK) + sCreatureTextMgr->SendChat(me, EMOTE_HIT_BERSERKER_TIMER, 0, CHAT_MSG_ADDON, LANG_ADDON, TEXT_RANGE_MAP); } void MoveInLineOfSight(Unit* who) { - if (!me->isInCombat()) + if (!me->isInCombat() || _phase != PHASE_ONE) return; if (who->GetEntry() == NPC_POWER_SPARK) - { - // not sure about the distance | I think it is better check this here than in the UpdateAI function... if (who->GetDistance(me) <= 2.5f) who->CastSpell(me, SPELL_POWER_SPARK_MALYGOS, true); - } - } - - void PrepareForVortex() - { - me->SetDisableGravity(true); - me->SetCanFly(true); - - me->GetMotionMaster()->MovementExpired(); - me->GetMotionMaster()->MovePoint(MOVE_VORTEX, MalygosPositions[1].GetPositionX(), MalygosPositions[1].GetPositionY(), MalygosPositions[1].GetPositionZ()); - // continues in MovementInform function. - } - - void ExecuteVortex() - { - DoCast(me, SPELL_VORTEX_1, true); - DoCast(me, SPELL_VORTEX_2, true); - - // the vortex execution continues in the dummy effect of this spell (see its script) - DoCast(me, SPELL_VORTEX_3, true); } void MovementInform(uint32 type, uint32 id) { - if (type != POINT_MOTION_TYPE) + if (type != POINT_MOTION_TYPE && type != EFFECT_MOTION_TYPE) return; switch (id) { - case MOVE_VORTEX: + case POINT_NEAR_RANDOM_PORTAL_P_NONE: + if (Creature* portal = me->FindNearestCreature(NPC_PORTAL_TRIGGER, 31.0f, true)) + { + events.ScheduleEvent(EVENT_STOP_PORTAL_BEAM, 10*IN_MILLISECONDS, 1, PHASE_NOT_STARTED); + events.ScheduleEvent(EVENT_RANDOM_PORTAL, 14*IN_MILLISECONDS, 1, PHASE_NOT_STARTED); + DoCast(portal, SPELL_PORTAL_BEAM); + } + break; + case POINT_LAND_P_ONE: + me->SetDisableGravity(false); + break; + case POINT_VORTEX_P_ONE: me->GetMotionMaster()->MoveIdle(); - ExecuteVortex(); + DoAction(ACTION_EXECUTE_VORTEX); break; - case MOVE_DEEP_BREATH_ROTATION: - _currentPos = _currentPos == MALYGOS_MAX_WAYPOINTS - 1 ? 0 : _currentPos+1; - me->GetMotionMaster()->MovementExpired(); - me->GetMotionMaster()->MovePoint(MOVE_DEEP_BREATH_ROTATION, MalygosPhaseTwoWaypoints[_currentPos]); + case POINT_LAND_AFTER_VORTEX_P_ONE: + me->SetDisableGravity(false); + _executingVortex = false; + _canAttack = true; break; - case MOVE_INIT_PHASE_ONE: - me->SetInCombatWithZone(); + case POINT_LIFT_IN_AIR_P_ONE: + me->SetDisableGravity(true); + events.ScheduleEvent(EVENT_MOVE_TO_VORTEX_POINT, 1, 0, PHASE_ONE); break; - case MOVE_CENTER_PLATFORM: - // Malygos is already flying here, there is no need to set it again. - _cannotMove = false; - // malygos will move into center of platform and then he does not chase dragons, he just turns to his current target. - me->GetMotionMaster()->MoveIdle(); + case POINT_FLY_OUT_OF_PLATFORM_P_TWO: + if (!_firstCyclicMovementStarted) + { + _firstCyclicMovementStarted = true; + me->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE); + me->SetFacingToObject(me->GetMap()->GetCreature(instance->GetData64(DATA_ALEXSTRASZA_BUNNY_GUID))); + events.ScheduleEvent(EVENT_SUMMON_ARCANE_BOMB, 1*IN_MILLISECONDS, 0, PHASE_TWO); + } + _flyingOutOfPlatform = false; + _performingSurgeOfPower = false; + events.ScheduleEvent(EVENT_PATHING_AROUND_PLATFORM, 1*IN_MILLISECONDS, 0, PHASE_TWO); + break; + case POINT_PHASE_ONE_TO_TWO_TRANSITION: + me->SetDisableGravity(true); + me->SetFacingToObject(me->GetMap()->GetCreature(instance->GetData64(DATA_ALEXSTRASZA_BUNNY_GUID))); + SendLightOverride(LIGHT_ARCANE_RUNES, 5*IN_MILLISECONDS); + events.ScheduleEvent(EVENT_FLY_OUT_OF_PLATFORM, 18*IN_MILLISECONDS, 0, PHASE_TWO); + break; + case POINT_SURGE_OF_POWER_P_TWO: + if (!_performingDestroyPlatform) + { + Talk(EMOTE_SURGE_OF_POWER_WARNING_P2); + DoCastAOE(SPELL_SURGE_OF_POWER_P_II, true); + events.ScheduleEvent(EVENT_FLY_OUT_OF_PLATFORM, 7*IN_MILLISECONDS, 0, PHASE_TWO); + } + break; + case POINT_DESTROY_PLATFORM_P_TWO: + SendLightOverride(LIGHT_OBSCURE_SPACE, 1*IN_MILLISECONDS); + DoCast(me, SPELL_DESTROY_PLATFORM_CHANNEL); + events.ScheduleEvent(EVENT_MOVE_TO_P_THREE_POINT, 11*IN_MILLISECONDS, 0, PHASE_TWO); + break; + case POINT_IDLE_P_THREE: + me->SetControlled(true, UNIT_STATE_ROOT); + events.ScheduleEvent(EVENT_START_P_THREE, 5*IN_MILLISECONDS, 0, PHASE_TWO); break; } } - void StartPhaseTwo() - { - SetPhase(PHASE_TWO, true); - - me->SetDisableGravity(true); - me->SetCanFly(true); - - me->GetMotionMaster()->MoveIdle(); - me->GetMotionMaster()->MovePoint(MOVE_DEEP_BREATH_ROTATION, MalygosPhaseTwoWaypoints[0]); - - for (uint8 i = 0; i < 2; i++) - { - // Starting position. One starts from the first waypoint and another from the last. - uint8 pos = !i ? MAX_HOVER_DISK_WAYPOINTS-1 : 0; - if (Creature* summon = me->SummonCreature(NPC_HOVER_DISK_CASTER, HoverDiskWaypoints[pos])) - if (summon->IsAIEnabled) - summon->AI()->DoAction(ACTION_HOVER_DISK_START_WP_1+i); - - // not sure about its position. - if (Creature* summon = me->SummonCreature(NPC_HOVER_DISK_MELEE, HoverDiskWaypoints[0])) - summon->SetInCombatWithZone(); - } - } - - void UpdateAI(uint32 const diff) + void UpdateAI(uint32 diff) { - if (!UpdateVictim()) + if (!UpdateVictim() && _phase != PHASE_NOT_STARTED && _phase != PHASE_TWO) return; events.Update(diff); - if (_phase == PHASE_THREE) - { - if (!_cannotMove) - { - // it can change if the player falls from the vehicle. - if (me->GetMotionMaster()->GetCurrentMovementGeneratorType() != IDLE_MOTION_TYPE) - { - me->GetMotionMaster()->MovementExpired(); - me->GetMotionMaster()->MoveIdle(); - } - } else - { - if (me->GetMotionMaster()->GetCurrentMovementGeneratorType() != POINT_MOTION_TYPE) - { - me->GetMotionMaster()->MovementExpired(); - me->GetMotionMaster()->MovePoint(MOVE_CENTER_PLATFORM, MalygosPositions[0].GetPositionX(), MalygosPositions[0].GetPositionY(), MalygosPositions[0].GetPositionZ()); - } - } - } + // we can't cast if we are casting already unless in PHASE_NOT_STARTED channeling PORTAL_BEAM + if (me->HasUnitState(UNIT_STATE_CASTING) && _phase != PHASE_NOT_STARTED) + return; - // we need a better way for pathing - if (_delayedMovement) + // at 50% hp Malygos switchs to phase 2 and removes hovering until reset or end of encounter + if (_phase == PHASE_ONE && me->GetHealthPct() <= 50.0f) { - if (_delayedMovementTimer <= diff) - { - me->GetMotionMaster()->MovePoint(MOVE_DEEP_BREATH_ROTATION, MalygosPhaseTwoWaypoints[_currentPos]); - _delayedMovementTimer = 8000; - _delayedMovement = false; - } _delayedMovementTimer -= diff; + SetPhase(PHASE_TWO, true); + _canAttack = false; + me->AttackStop(); + Talk(SAY_END_P_ONE); } - // at 50 % health malygos switch to phase 2 - if (me->GetHealthPct() <= 50.0f && _phase == PHASE_ONE) - StartPhaseTwo(); - - // the boss is handling vortex - if (me->HasAura(SPELL_VORTEX_2)) - return; - - // We can't cast if we are casting already. - if (me->HasUnitState(UNIT_STATE_CASTING)) - return; - while (uint32 eventId = events.ExecuteEvent()) { switch (eventId) { - case EVENT_YELL_2: - Talk(SAY_END_P_TWO); + case EVENT_START_FIRST_RANDOM_PORTAL: + me->CastCustomSpell(SPELL_RANDOM_PORTAL, SPELLVALUE_MAX_TARGETS, 1); break; - case EVENT_YELL_3: - Talk(SAY_INTRO_P_THREE); + case EVENT_STOP_PORTAL_BEAM: + me->InterruptNonMeleeSpells(true); break; - case EVENT_YELL_4: - Talk(SAY_AGGRO_P_THREE); + case EVENT_RANDOM_PORTAL: + me->CastCustomSpell(SPELL_RANDOM_PORTAL, SPELLVALUE_MAX_TARGETS, 1); break; - case EVENT_YELL_0: - Talk(SAY_END_P_ONE); + case EVENT_LAND_START_ENCOUNTER: + if (GameObject* iris = me->GetMap()->GetGameObject(instance->GetData64(DATA_FOCUSING_IRIS_GUID))) + { + me->SetFacingToObject(iris); + iris->Delete(); // this is not the best way. + } + _canAttack = true; + SetPhase(PHASE_ONE, true); break; - case EVENT_YELL_1: - Talk(SAY_AGGRO_P_TWO); - break; - case EVENT_ARCANE_BREATH: - DoCast(me->getVictim(), SPELL_ARCANE_BREATH); - events.ScheduleEvent(EVENT_ARCANE_BREATH, urand(35, 60)*IN_MILLISECONDS, 0, PHASE_ONE); - break; - case EVENT_ARCANE_STORM: - DoCast(me->getVictim(), SPELL_ARCANE_STORM); - events.ScheduleEvent(EVENT_ARCANE_STORM, urand(5, 10)*IN_MILLISECONDS, 0, PHASE_ONE); + case EVENT_SAY_INTRO: + Talk(SAY_INTRO_EVENT); + events.ScheduleEvent(EVENT_SAY_INTRO, urand(85, 95)*IN_MILLISECONDS, 1, PHASE_NOT_STARTED); break; case EVENT_VORTEX: - PrepareForVortex(); + _executingVortex = true; + DoAction(ACTION_LIFT_IN_AIR); events.ScheduleEvent(EVENT_VORTEX, urand(60, 80)*IN_MILLISECONDS, 0, PHASE_ONE); break; + case EVENT_MOVE_TO_VORTEX_POINT: + _canAttack = false; + me->AttackStop(); + me->GetMotionMaster()->MovePoint(POINT_VORTEX_P_ONE, MalygosPositions[1]); + break; case EVENT_POWER_SPARKS: instance->SetData(DATA_POWER_SPARKS_HANDLING, 0); events.ScheduleEvent(EVENT_POWER_SPARKS, urand(30, 35)*IN_MILLISECONDS, 0, PHASE_ONE); break; - case EVENT_SURGE_POWER: - me->GetMotionMaster()->MoveIdle(); - _delayedMovement = true; - DoCast(SPELL_SURGE_POWER); - events.ScheduleEvent(EVENT_SURGE_POWER, urand(60, 70)*IN_MILLISECONDS, 0, PHASE_TWO); + case EVENT_ARCANE_BREATH: + if (_executingVortex) + { + events.ScheduleEvent(EVENT_ARCANE_BREATH, 20*IN_MILLISECONDS, 0, PHASE_ONE); + break; + } + + me->CastSpell(me->getVictim(), SPELL_ARCANE_BREATH); + events.ScheduleEvent(EVENT_ARCANE_BREATH, 20*IN_MILLISECONDS, 0, PHASE_ONE); + break; + case EVENT_ARCANE_STORM: + if (_phase == PHASE_ONE) + { + if (_executingVortex) + { + events.ScheduleEvent(EVENT_ARCANE_STORM, 10*IN_MILLISECONDS, 0, PHASE_ONE); + break; + } + + DoCastAOE(SPELL_ARCANE_STORM_P_I, true); + events.ScheduleEvent(EVENT_ARCANE_STORM, 10*IN_MILLISECONDS, 0, PHASE_ONE); + } + else if (_phase == PHASE_THREE) + { + DoCastAOE(SPELL_ARCANE_STORM_P_III, true); + events.ScheduleEvent(EVENT_ARCANE_STORM, urand(6, 12)*IN_MILLISECONDS, 0, PHASE_THREE); + } + break; + case EVENT_FLY_OUT_OF_PLATFORM: + if (!_performingDestroyPlatform) + { + if (Creature* alexstraszaBunny = me->GetMap()->GetCreature(instance->GetData64(DATA_ALEXSTRASZA_BUNNY_GUID))) + { + Position randomPosOnRadius; + // Hardcodded retail value, reason is Z getters can fail... (TO DO: Change to getter when height calculation works on 100%!) + randomPosOnRadius.m_positionZ = 283.0521f; + alexstraszaBunny->GetNearPoint2D(randomPosOnRadius.m_positionX, randomPosOnRadius.m_positionY, 120.0f, alexstraszaBunny->GetAngle(me)); + me->GetMotionMaster()->MovePoint(POINT_FLY_OUT_OF_PLATFORM_P_TWO, randomPosOnRadius); + _flyingOutOfPlatform = true; + } + } + + if (_arcaneReinforcements && instance) + { + for (uint8 rangeDisks = 0; rangeDisks < (GetDifficulty() == RAID_DIFFICULTY_10MAN_NORMAL ? 4 : 5); rangeDisks++) + { + Creature* casterDiskSummon = me->SummonCreature(NPC_HOVER_DISK_CASTER, RangeHoverDisksSpawnPositions[rangeDisks]); + + if (casterDiskSummon->IsAIEnabled) + casterDiskSummon->AI()->DoAction(rangeDisks); + } + + for (uint8 meleeDisks = 0; meleeDisks < 2; meleeDisks++) + { + Creature* meleeDiskSummon = me->SummonCreature(NPC_HOVER_DISK_MELEE, MeleeHoverDisksSpawnPositions[meleeDisks]); + meleeDiskSummon->GetMotionMaster()->MovePoint(meleeDisks * MAX_MELEE_HOVER_DISK_SPAWNPOINTS, MeleeHoverDisksWaypoints[meleeDisks * MAX_MELEE_HOVER_DISK_SPAWNPOINTS]); + } + + _arcaneReinforcements = false; + + if (GetDifficulty() == RAID_DIFFICULTY_25MAN_NORMAL) + events.ScheduleEvent(EVENT_DELAYED_REINFORCEMENTS, 1*IN_MILLISECONDS, 0, PHASE_TWO); + } + break; + case EVENT_DELAYED_REINFORCEMENTS: + for (uint8 rangeDisks = 5; rangeDisks < 8; rangeDisks++) + { + Creature* casterDiskSummon = me->SummonCreature(NPC_HOVER_DISK_CASTER, RangeHoverDisksSpawnPositions[rangeDisks]); + + if (casterDiskSummon->IsAIEnabled) + casterDiskSummon->AI()->DoAction(rangeDisks); + } + + for (uint8 meleeDisks = 2; meleeDisks < 4; meleeDisks++) + { + Creature* meleeDiskSummon = me->SummonCreature(NPC_HOVER_DISK_MELEE, MeleeHoverDisksSpawnPositions[meleeDisks]); + meleeDiskSummon->GetMotionMaster()->MovePoint(meleeDisks * MAX_MELEE_HOVER_DISK_SPAWNPOINTS, MeleeHoverDisksWaypoints[meleeDisks * MAX_MELEE_HOVER_DISK_SPAWNPOINTS]); + } + break; + case EVENT_PATHING_AROUND_PLATFORM: + if (!_performingSurgeOfPower && !_performingDestroyPlatform) + DoAction(ACTION_CYCLIC_MOVEMENT); + break; + case EVENT_MOVE_TO_POINT_SURGE_P_TWO: + if (!_performingDestroyPlatform) + { + _performingSurgeOfPower = true; + Talk(SAY_DEEP_BREATH); + me->GetMotionMaster()->MovePoint(POINT_SURGE_OF_POWER_P_TWO, MalygosPositions[3]); + events.ScheduleEvent(EVENT_MOVE_TO_POINT_SURGE_P_TWO, 60*IN_MILLISECONDS, 2, PHASE_TWO); + } + break; + case EVENT_SUMMON_ARCANE_BOMB: + if (!_performingSurgeOfPower && !_performingDestroyPlatform) + { + me->StopMoving(); + events.ScheduleEvent(EVENT_PATHING_AROUND_PLATFORM, 3*IN_MILLISECONDS, 0, PHASE_TWO); + } + + if (!_flyingOutOfPlatform) + { + DoCast(me, SPELL_SUMMON_ARCANE_BOMB, true); + if (Creature* lastArcaneOverloadBunny = me->GetMap()->GetCreature(_arcaneOverloadGUID)) + DoCast(lastArcaneOverloadBunny, SPELL_ARCANE_BOMB_TRIGGER, true); + } + events.ScheduleEvent(EVENT_SUMMON_ARCANE_BOMB, urand(15, 16)*IN_MILLISECONDS, 2, PHASE_TWO); + break; + case EVENT_ARCANE_PULSE: + if (_preparingPulsesChecker < 2) + { + DoCastAOE(SPELL_ARCANE_PULSE, true); + events.ScheduleEvent(EVENT_ARCANE_PULSE, 7*IN_MILLISECONDS, 0, PHASE_THREE); + _preparingPulsesChecker++; + } + else + { + DoCastAOE(SPELL_ARCANE_PULSE, true); + events.ScheduleEvent(EVENT_ARCANE_PULSE, 2*IN_MILLISECONDS, 0, PHASE_THREE); + } + break; + case EVENT_LIGHT_DIMENSION_CHANGE: + SendLightOverride(LIGHT_CHANGE_DIMENSIONS, 2*IN_MILLISECONDS); + break; + case EVENT_DELAY_MOVE_TO_DESTROY_P: + me->GetMotionMaster()->MovePoint(POINT_DESTROY_PLATFORM_P_TWO, MalygosPositions[0]); + break; + case EVENT_MOVE_TO_P_THREE_POINT: + Talk(SAY_START_P_THREE); + me->GetMotionMaster()->MovePoint(POINT_IDLE_P_THREE, MalygosPositions[4]); break; - case EVENT_SUMMON_ARCANE: - DoCast(SPELL_SUMMON_ARCANE_BOMB); - events.ScheduleEvent(EVENT_SUMMON_ARCANE, urand(12, 15)*IN_MILLISECONDS, 0, PHASE_TWO); + case EVENT_START_P_THREE: + SendLightOverride(LIGHT_OBSCURE_ARCANE_RUNES, 1*IN_MILLISECONDS); + DoCast(me, SPELL_CLEAR_ALL_DEBUFFS); + DoCast(me, SPELL_IMMUNE_CURSES); + _canAttack = true; + UpdateVictim(); + me->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE); + SetPhase(PHASE_THREE, true); break; - case EVENT_SURGE_POWER_PHASE_3: - DoCast(GetTargetPhaseThree(), SPELL_SURGE_POWER_PHASE_3); - events.ScheduleEvent(EVENT_SURGE_POWER_PHASE_3, urand(7, 16)*IN_MILLISECONDS, 0, PHASE_THREE); + case EVENT_SURGE_OF_POWER_P_THREE: + if (GetDifficulty() == RAID_DIFFICULTY_10MAN_NORMAL) + { + if (Unit* tempSurgeTarget = SelectTarget(SELECT_TARGET_RANDOM, 0, 0.0f, false, SPELL_RIDE_RED_DRAGON_BUDDY)) + { + if (Vehicle* drakeVehicle = tempSurgeTarget->GetVehicleKit()) + { + if (Unit* passenger = drakeVehicle->GetPassenger(0)) + { + if (passenger->GetTypeId() == TYPEID_PLAYER) + { + Talk(EMOTE_SURGE_OF_POWER_WARNING_P3, passenger->GetGUID()); + DoCast(tempSurgeTarget, SPELL_SURGE_OF_POWER_PHASE_3_10, true); + } + } + } + } + } + else if (GetDifficulty() == RAID_DIFFICULTY_25MAN_NORMAL) + { + memset(_surgeTargetGUID, 0, sizeof(_surgeTargetGUID)); + DoCastAOE(SPELL_SURGE_OF_POWER_WARNING_SELECTOR_25, true); + } + + events.ScheduleEvent(EVENT_SURGE_OF_POWER_P_THREE, urand(9, 18)*IN_MILLISECONDS, 0, PHASE_THREE); break; case EVENT_STATIC_FIELD: - DoCast(GetTargetPhaseThree(), SPELL_STATIC_FIELD); - events.ScheduleEvent(EVENT_STATIC_FIELD, urand(20, 30)*IN_MILLISECONDS, 0, PHASE_THREE); + if (Unit* target = SelectTarget(SELECT_TARGET_RANDOM, 0, 60.0f, false, SPELL_RIDE_RED_DRAGON_BUDDY)) + DoCast(target, SPELL_STATIC_FIELD_MISSLE, true); + + events.ScheduleEvent(EVENT_STATIC_FIELD, urand(15, 30)*IN_MILLISECONDS, 0, PHASE_THREE); + break; + case EVENT_PREVENT_SAY_SPAM_ON_KILL: + _killSpamFilter = false; break; default: break; } } - DoMeleeAttackIfReady(); + if (_phase != PHASE_THREE) + DoMeleeAttackIfReady(); } - Unit* GetTargetPhaseThree() + void JustDied(Unit* /*killer*/) { - Unit* target = SelectTarget(SELECT_TARGET_RANDOM, 0); - - // we are a drake - if (target->GetVehicleKit()) - return target; - - // we are a player using a drake (or at least you should) - if (target->GetTypeId() == TYPEID_PLAYER) + _JustDied(); + Talk(SAY_DEATH); + if (Creature* alexstraszaGiftBoxBunny = me->GetMap()->GetCreature(instance->GetData64(DATA_GIFT_BOX_BUNNY_GUID))) { - if (Unit* base = target->GetVehicleBase()) - return base; + if (GetDifficulty() == RAID_DIFFICULTY_10MAN_NORMAL) + alexstraszaGiftBoxBunny->SummonGameObject(GO_HEART_OF_MAGIC_10, HeartOfMagicSpawnPos.GetPositionX(), HeartOfMagicSpawnPos.GetPositionY(), + HeartOfMagicSpawnPos.GetPositionZ(), HeartOfMagicSpawnPos.GetOrientation(), 0.0f, 0.0f, 0.0f, 1.0f, 0); + else if (GetDifficulty() == RAID_DIFFICULTY_25MAN_NORMAL) + alexstraszaGiftBoxBunny->SummonGameObject(GO_HEART_OF_MAGIC_25, HeartOfMagicSpawnPos.GetPositionX(), HeartOfMagicSpawnPos.GetPositionY(), + HeartOfMagicSpawnPos.GetPositionZ(), HeartOfMagicSpawnPos.GetOrientation(), 0.0f, 0.0f, 0.0f, 1.0f, 0); } - // is a player falling from a vehicle? - return NULL; - } - - void JustDied(Unit* /*killer*/) - { - Talk(SAY_DEATH); - _JustDied(); + me->SummonCreature(NPC_ALEXSTRASZA, AlexstraszaSpawnPos, TEMPSUMMON_MANUAL_DESPAWN); + me->DespawnOrUnsummon(5*IN_MILLISECONDS); } private: - uint8 _phase; - uint32 _bersekerTimer; - uint8 _currentPos; // used for phase 2 rotation... - bool _delayedMovement; // used in phase 2. - uint32 _delayedMovementTimer; // used in phase 2 - uint8 _summonDeaths; - Position _homePosition; // it can get bugged because core thinks we are pathing - bool _mustTalk; - bool _cannotMove; - }; -}; - -class spell_malygos_vortex_dummy : public SpellScriptLoader -{ -public: - spell_malygos_vortex_dummy() : SpellScriptLoader("spell_malygos_vortex_dummy") {} - - class spell_malygos_vortex_dummy_SpellScript : public SpellScript - { - PrepareSpellScript(spell_malygos_vortex_dummy_SpellScript) - - void HandleScript(SpellEffIndex /*effIndex*/) + // Used to generate perfect cyclic movements (Enter Circle). + void FillCirclePath(Position const& centerPos, float radius, float z, Movement::PointsArray& path, bool clockwise) { - Unit* caster = GetCaster(); - - if (!caster) - return; + float step = clockwise ? -M_PI / 8.0f : M_PI / 8.0f; + float angle = centerPos.GetAngle(me->GetPositionX(), me->GetPositionY()); - // each player will enter to the trigger vehicle (entry 30090) already spawned (each one can hold up to 5 players, it has 5 seats) - // the players enter to the vehicles casting SPELL_VORTEX_4 OR SPELL_VORTEX_5 - if (InstanceScript* instance = caster->GetInstanceScript()) - instance->SetData(DATA_VORTEX_HANDLING, 0); + for (uint8 i = 0; i < 16; angle += step, ++i) + { + G3D::Vector3 point; + point.x = centerPos.GetPositionX() + radius * cosf(angle); + point.y = centerPos.GetPositionY() + radius * sinf(angle); + point.z = z; // Don't use any height getters unless all bugs are fixed. + path.push_back(point); + } + } - // the rest of the vortex execution continues when SPELL_VORTEX_2 is removed. + // Function that will change lights of map for all players on map. + void SendLightOverride(uint32 overrideId, uint32 fadeInTime) const + { + WorldPacket data(SMSG_OVERRIDE_LIGHT, 12); + data << uint32(1773); // Light.dbc entry (map default) + data << uint32(overrideId); // Light.dbc entry (override) + data << uint32(fadeInTime); + SendPacketToPlayers(&data); } - void Register() + // Send packet to all players in Eye of Eternity + void SendPacketToPlayers(WorldPacket const* data) const { - OnEffectHitTarget += SpellEffectFn(spell_malygos_vortex_dummy_SpellScript::HandleScript, EFFECT_0, SPELL_EFFECT_DUMMY); + Map::PlayerList const& players = me->GetMap()->GetPlayers(); + if (!players.isEmpty()) + for (Map::PlayerList::const_iterator itr = players.begin(); itr != players.end(); ++itr) + if (Player* player = itr->getSource()) + if (player->GetAreaId() == AREA_EYE_OF_ETERNITY) + player->GetSession()->SendPacket(data); } + + uint8 _phase; // Counter for phases used with a getter. + uint8 _summonDeaths; // Keeps count of arcane trash. + uint8 _preparingPulsesChecker; // In retail they use 2 preparing pulses with 7 sec CD, after they pass 2 seconds. + uint64 _arcaneOverloadGUID; // Last Arcane Overload summoned to know to which should visual be cast to (the purple ball, not bubble). + uint64 _lastHitByArcaneBarrageGUID; // Last hit player by Arcane Barrage, will be removed if targets > 1. + uint64 _surgeTargetGUID[3]; // All these three are used to keep current tagets to which warning should be sent. + + bool _killSpamFilter; // Prevent text spamming on killed player by helping implement a CD. + bool _canAttack; // Used to control attacking (Move Chase not being applied after Stop Attack, only few times should act like this). + bool _despawned; // Checks if boss pass through evade on reset. + bool _executingVortex; // Prevents some events being sheduled during Vortex takeoff/land. + bool _arcaneReinforcements; // Checks if 10 or 25 man arcane trash will be spawned. + bool _flyingOutOfPlatform; // Used to prevent Malygos casting Arcane Overload shields while leaving platform. + bool _firstCyclicMovementStarted; // At first movement start he throws one shield asap, so this check is needed for it only. + bool _performingSurgeOfPower; // Used to prevent starting Cyclic Movement called in Arcane Bomb event. + bool _performingDestroyPlatform; // Used to prevent starting some movements right when Destroy Platfrom event starts. + + float _flySpeed; // Used to store base fly speed to prevent stacking on each evade. }; - SpellScript* GetSpellScript() const + CreatureAI* GetAI(Creature* creature) const { - return new spell_malygos_vortex_dummy_SpellScript(); + return new boss_malygosAI(creature); } }; -class spell_malygos_vortex_visual : public SpellScriptLoader -{ - public: - spell_malygos_vortex_visual() : SpellScriptLoader("spell_malygos_vortex_visual") { } - - class spell_malygos_vortex_visual_AuraScript : public AuraScript - { - PrepareAuraScript(spell_malygos_vortex_visual_AuraScript); - - void OnRemove(AuraEffect const* /*aurEff*/, AuraEffectHandleModes /*mode*/) - { - if (Unit* caster = GetCaster()) - { - ThreatContainer::StorageType const& m_threatlist = caster->getThreatManager().getThreatList(); - for (ThreatContainer::StorageType::const_iterator itr = m_threatlist.begin(); itr!= m_threatlist.end(); ++itr) - { - if (Unit* target = (*itr)->getTarget()) - { - Player* targetPlayer = target->ToPlayer(); - - if (!targetPlayer || targetPlayer->isGameMaster()) - continue; - - if (InstanceScript* instance = caster->GetInstanceScript()) - { - // teleport spell - i am not sure but might be it must be casted by each vehicle when its passenger leaves it - if (Creature* trigger = caster->GetMap()->GetCreature(instance->GetData64(DATA_TRIGGER))) - trigger->CastSpell(targetPlayer, SPELL_VORTEX_6, true); - } - } - } - - if (Creature* malygos = caster->ToCreature()) - { - // This is a hack, we have to re add players to the threat list because when they enter to the vehicles they are removed. - // Anyway even with this issue, the boss does not enter in evade mode - this prevents iterate an empty list in the next vortex execution. - malygos->SetInCombatWithZone(); - - malygos->SetDisableGravity(false); - malygos->SetCanFly(false); - - malygos->GetMotionMaster()->MoveChase(caster->getVictim()); - malygos->RemoveAura(SPELL_VORTEX_1); - } - } - - } - - void Register() - { - AfterEffectRemove += AuraEffectRemoveFn(spell_malygos_vortex_visual_AuraScript::OnRemove, EFFECT_0, SPELL_AURA_DUMMY, AURA_EFFECT_HANDLE_REAL); - } - }; - - AuraScript* GetAuraScript() const - { - return new spell_malygos_vortex_visual_AuraScript(); - } -}; - class npc_portal_eoe: public CreatureScript { public: - npc_portal_eoe() : CreatureScript("npc_portal_eoe") {} - - CreatureAI* GetAI(Creature* creature) const - { - return new npc_portal_eoeAI(creature); - } + npc_portal_eoe() : CreatureScript("npc_portal_eoe") { } struct npc_portal_eoeAI : public ScriptedAI { @@ -763,27 +1089,29 @@ public: _instance = creature->GetInstanceScript(); } - void SpellHit(Unit* /*caster*/, const SpellInfo* spell) + void SpellHit(Unit* /*caster*/, SpellInfo const* spell) { if (spell->Id == SPELL_PORTAL_OPENED) { - DoCast(me, SPELL_SUMMON_POWER_PARK, true); + if (Creature* malygos = me->GetMap()->GetCreature(_instance->GetData64(DATA_MALYGOS))) + { + if (malygos->AI()->GetData(DATA_PHASE) == PHASE_ONE) + DoCast(me, SPELL_SUMMON_POWER_PARK, true); + } } } - void UpdateAI(uint32 const /*diff*/) + void UpdateAI(uint32 /*diff*/) { - // When duration of oppened riff visual ends, - // closed one should be cast - if (!me->HasAura(SPELL_PORTAL_VISUAL_CLOSED) && - !me->HasAura(SPELL_PORTAL_OPENED)) + // When duration of opened riff visual ends, closed one should be cast + if (!me->HasAura(SPELL_PORTAL_VISUAL_CLOSED) && !me->HasAura(SPELL_PORTAL_OPENED)) DoCast(me, SPELL_PORTAL_VISUAL_CLOSED, true); if (_instance) { - if (Creature* malygos = Unit::GetCreature(*me, _instance->GetData64(DATA_MALYGOS))) + if (Creature* malygos = me->GetMap()->GetCreature(_instance->GetData64(DATA_MALYGOS))) { - if (malygos->AI()->GetData(DATA_PHASE) != PHASE_ONE) + if (malygos->AI()->GetData(DATA_PHASE) != PHASE_ONE && me->HasAura(SPELL_PORTAL_OPENED)) { me->RemoveAura(SPELL_PORTAL_OPENED); DoCast(me, SPELL_PORTAL_VISUAL_CLOSED, true); @@ -792,42 +1120,29 @@ public: } } - void JustSummoned(Creature* summon) - { - summon->SetInCombatWithZone(); - } - private: - uint32 _summonTimer; InstanceScript* _instance; }; -}; + CreatureAI* GetAI(Creature* creature) const + { + return new npc_portal_eoeAI(creature); + } +}; class npc_power_spark: public CreatureScript { public: - npc_power_spark() : CreatureScript("npc_power_spark") {} - - CreatureAI* GetAI(Creature* creature) const - { - return new npc_power_sparkAI(creature); - } + npc_power_spark() : CreatureScript("npc_power_spark") { } struct npc_power_sparkAI : public ScriptedAI { npc_power_sparkAI(Creature* creature) : ScriptedAI(creature) { _instance = creature->GetInstanceScript(); - - MoveToMalygos(); // Talk range was not enough for this encounter sCreatureTextMgr->SendChat(me, EMOTE_POWER_SPARK_SUMMONED, 0, CHAT_MSG_ADDON, LANG_ADDON, TEXT_RANGE_MAP); - } - - void EnterEvadeMode() - { - me->DespawnOrUnsummon(); + MoveToMalygos(); } void MoveToMalygos() @@ -835,20 +1150,18 @@ public: me->GetMotionMaster()->MoveIdle(); if (_instance) - { - if (Creature* malygos = Unit::GetCreature(*me, _instance->GetData64(DATA_MALYGOS))) + if (Creature* malygos = me->GetMap()->GetCreature(_instance->GetData64(DATA_MALYGOS))) me->GetMotionMaster()->MoveFollow(malygos, 0.0f, 0.0f); - } } - void UpdateAI(uint32 const /*diff*/) + void UpdateAI(uint32 /*diff*/) { if (!_instance) return; - if (Creature* malygos = Unit::GetCreature(*me, _instance->GetData64(DATA_MALYGOS))) + if (Creature* malygos = me->GetMap()->GetCreature(_instance->GetData64(DATA_MALYGOS))) { - if (malygos->AI()->GetData(DATA_PHASE) != PHASE_ONE) + if (malygos->AI()->GetData(DATA_PHASE) != PHASE_ONE || _instance->GetBossState(DATA_MALYGOS_EVENT) == FAIL) { me->DespawnOrUnsummon(); return; @@ -873,28 +1186,33 @@ public: private: InstanceScript* _instance; }; + + CreatureAI* GetAI(Creature* creature) const + { + return new npc_power_sparkAI(creature); + } }; -class npc_hover_disk : public CreatureScript +class npc_melee_hover_disk : public CreatureScript { public: - npc_hover_disk() : CreatureScript("npc_hover_disk") { } + npc_melee_hover_disk() : CreatureScript("npc_melee_hover_disk") { } - CreatureAI* GetAI(Creature* creature) const + struct npc_melee_hover_diskAI : public VehicleAI { - return new npc_hover_diskAI(creature); - } + npc_melee_hover_diskAI(Creature* creature) : VehicleAI(creature) + { + _instance = creature->GetInstanceScript(); + me->SetReactState(REACT_PASSIVE); + // TO DO: These were a bit faster than what they should be. Not sure what is the reason. + me->SetSpeed(MOVE_FLIGHT, 1.25f); + } - struct npc_hover_diskAI : public npc_escortAI - { - npc_hover_diskAI(Creature* creature) : npc_escortAI(creature) + void Reset() { - if (me->GetEntry() == NPC_HOVER_DISK_CASTER) - me->SetReactState(REACT_PASSIVE); - else - me->SetInCombatWithZone(); + VehicleAI::Reset(); - _instance = creature->GetInstanceScript(); + _wpCount = 0; } void PassengerBoarded(Unit* unit, int8 /*seat*/, bool apply) @@ -903,208 +1221,1323 @@ public: { if (unit->GetTypeId() == TYPEID_UNIT) { - me->setFaction(FACTION_HOSTILE); + unit->CastSpell(unit, SPELL_TELEPORT_VISUAL_ONLY); unit->ToCreature()->SetInCombatWithZone(); } + else if (unit->GetTypeId() == TYPEID_PLAYER) + me->SetDisableGravity(true); } - else + else if (!apply) { - // Error found: This is not called if the passenger is a player - if (unit->GetTypeId() == TYPEID_UNIT || unit->GetTypeId() == TYPEID_PLAYER) + if (unit->GetTypeId() != TYPEID_PLAYER) { - // This will only be called if the passenger dies - if (_instance) - { - if (Creature* malygos = Unit::GetCreature(*me, _instance->GetData64(DATA_MALYGOS))) - malygos->AI()->SetData(DATA_SUMMON_DEATHS, malygos->AI()->GetData(DATA_SUMMON_DEATHS)+1); - } + me->SetHomePosition(me->GetPositionX(), me->GetPositionY(), me->GetPositionZ(), me->GetOrientation()); me->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE); + me->SetDisableGravity(false); + me->SetCanFly(false); } - - me->GetMotionMaster()->MoveIdle(); - - if (me->GetEntry() == NPC_HOVER_DISK_MELEE || me->GetEntry() == NPC_HOVER_DISK_CASTER) + else if (unit->GetTypeId() == TYPEID_PLAYER) { - // Hack: Fall ground function can fail (remember the platform is a gameobject), we will teleport the disk to the ground - if (me->GetPositionZ() > GROUND_Z) - me->NearTeleportTo(me->GetPositionX(), me->GetPositionY(), GROUND_Z, 0); - me->SetHomePosition(me->GetPositionX(), me->GetPositionY(), me->GetPositionZ(), me->GetOrientation()); - me->setFaction(FACTION_FRIENDLY); - me->AI()->EnterEvadeMode(); + me->SetDisableGravity(false); + me->SetCanFly(false); } + + me->setFaction(FACTION_FRIENDLY); + me->RemoveAllAuras(); } } - void EnterEvadeMode() + void UpdateAI(uint32 diff) { - // we dont evade + _events.Update(diff); + + while (uint32 eventId = _events.ExecuteEvent()) + me->GetMotionMaster()->MovePoint(eventId, MeleeHoverDisksWaypoints[eventId]); } - void DoAction(int32 const action) + void DoAction(int32 /*action*/) { - if (me->GetEntry() != NPC_HOVER_DISK_CASTER) + if (Vehicle* vehicleTemp = me->GetVehicleKit()) + if (vehicleTemp->GetPassenger(0) && vehicleTemp->GetPassenger(0)->GetTypeId() == TYPEID_PLAYER) + { + vehicleTemp->RemoveAllPassengers(); + me->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE); + } + + me->DespawnOrUnsummon(3*IN_MILLISECONDS); + } + + void MovementInform(uint32 type, uint32 id) + { + if (type != POINT_MOTION_TYPE) return; - switch (action) + if (_wpCount < 3) { - case ACTION_HOVER_DISK_START_WP_1: - for (uint8 i = 0; i < MAX_HOVER_DISK_WAYPOINTS; i++) - AddWaypoint(i, HoverDiskWaypoints[i].GetPositionX(), HoverDiskWaypoints[i].GetPositionY(), HoverDiskWaypoints[i].GetPositionZ()); - break; - case ACTION_HOVER_DISK_START_WP_2: - { - uint8 count = 0; - for (uint8 i = MAX_HOVER_DISK_WAYPOINTS-1; i > 0; i--) - { - AddWaypoint(count, HoverDiskWaypoints[i].GetPositionX(), HoverDiskWaypoints[i].GetPositionY(), HoverDiskWaypoints[i].GetPositionZ()); - count++; - } - break; - } - default: - return; + _events.ScheduleEvent(id + 1, 1); + ++_wpCount; } + else if (Vehicle* hoverDisk = me->GetVehicleKit()) + if (Unit* lordPassenger = hoverDisk->GetPassenger(0)) + lordPassenger->ToCreature()->AI()->DoAction(ACTION_SET_DISK_VICTIM_CHASE); + } + + private: + uint8 _wpCount; // how many points are triggered + InstanceScript* _instance; + EventMap _events; + }; - Start(true, false, 0, 0, false, true); + CreatureAI* GetAI(Creature* creature) const + { + return new npc_melee_hover_diskAI(creature); + } +}; + +class npc_caster_hover_disk : public CreatureScript +{ +public: + npc_caster_hover_disk() : CreatureScript("npc_caster_hover_disk") { } + + struct npc_caster_hover_diskAI : public VehicleAI + { + npc_caster_hover_diskAI(Creature* creature) : VehicleAI(creature) + { + _instance = creature->GetInstanceScript(); + me->SetReactState(REACT_PASSIVE); + // TO DO: Something is wrong with calculations for flying creatures that are on WP/Cyclic path. + // They should get the same difference as to when at ground from run creature switch to walk. + me->SetSpeed(MOVE_FLIGHT, 0.45f); } - void UpdateEscortAI(const uint32 /*diff*/) + void Reset() { - // we dont do melee damage! + VehicleAI::Reset(); } - void WaypointReached(uint32 /*waypointId*/) + void EnterEvadeMode() { + } + + void PassengerBoarded(Unit* unit, int8 /*seat*/, bool apply) + { + if (apply) + { + if (unit->GetTypeId() == TYPEID_UNIT) + unit->CastSpell(unit, SPELL_TELEPORT_VISUAL_ONLY); + } + else if (!apply) + { + me->StopMoving(); + me->SetDisableGravity(false); + me->SetCanFly(false); + me->RemoveAllAuras(); + } + } + void DoAction(int32 action) + { + if (action < ACTION_DELAYED_DESPAWN) + { + Movement::MoveSplineInit init(me); + FillCirclePath(MalygosPositions[3], 35.0f, 282.3402f, init.Path(), true); + init.SetFly(); + init.SetCyclic(); + init.Launch(); + } + else + { + me->DespawnOrUnsummon(3*IN_MILLISECONDS); + } } private: + void FillCirclePath(Position const& centerPos, float radius, float z, Movement::PointsArray& path, bool clockwise) + { + float step = clockwise ? -M_PI / 9.0f : M_PI / 9.0f; + float angle = centerPos.GetAngle(me->GetPositionX(), me->GetPositionY()); + + for (uint8 i = 0; i < 18; angle += step, ++i) + { + G3D::Vector3 point; + point.x = centerPos.GetPositionX() + radius * cosf(angle); + point.y = centerPos.GetPositionY() + radius * sinf(angle); + point.z = z; // Don't use any height getters unless all bugs are fixed. + path.push_back(point); + } + } + InstanceScript* _instance; }; + + CreatureAI* GetAI(Creature* creature) const + { + return new npc_caster_hover_diskAI(creature); + } }; +class npc_nexus_lord : public CreatureScript +{ + public: + npc_nexus_lord() : CreatureScript("npc_nexus_lord") { } + + struct npc_nexus_lordAI : public ScriptedAI + { + npc_nexus_lordAI(Creature* creature) : ScriptedAI(creature) + { + _instance = creature->GetInstanceScript(); + } + + void Reset() + { + _events.Reset(); + } + + void EnterEvadeMode() + { + } + + void DoAction(int32 /*action*/) + { + _events.ScheduleEvent(EVENT_NUKE_DUMMY, 1); + _events.ScheduleEvent(EVENT_ARCANE_SHOCK, 2*IN_MILLISECONDS); + _events.ScheduleEvent(EVENT_HASTE_BUFF, 12*IN_MILLISECONDS); + } + + void UpdateAI(uint32 diff) + { + if (!UpdateVictim()) + return; + + _events.Update(diff); + + while (uint32 eventId = _events.ExecuteEvent()) + { + switch (eventId) + { + case EVENT_ARCANE_SHOCK: + if (Unit* victim = SelectTarget(SELECT_TARGET_RANDOM, 0, 5.0f, true)) + DoCast(victim, SPELL_ARCANE_SHOCK); + _events.ScheduleEvent(EVENT_ARCANE_SHOCK, urand(7, 15)*IN_MILLISECONDS); + break; + case EVENT_HASTE_BUFF: + DoCast(me, SPELL_HASTE); + _events.ScheduleEvent(EVENT_HASTE_BUFF, 15*IN_MILLISECONDS); + break; + case EVENT_NUKE_DUMMY: + DoCast(me->getVictim(), SPELL_DUMMY_NUKE, true); + DoCast(me, SPELL_ALIGN_DISK_AGGRO, true); + _events.ScheduleEvent(EVENT_NUKE_DUMMY, 1*IN_MILLISECONDS); + break; + } + } + + DoMeleeAttackIfReady(); + } + + void JustDied(Unit* /*killer*/) + { + if (Creature* malygos = me->GetMap()->GetCreature(_instance->GetData64(DATA_MALYGOS))) + malygos->AI()->SetData(DATA_SUMMON_DEATHS, malygos->AI()->GetData(DATA_SUMMON_DEATHS) + 1); + } + + private: + InstanceScript* _instance; + EventMap _events; + }; + + CreatureAI* GetAI(Creature* creature) const + { + return new npc_nexus_lordAI(creature); + } +}; + +class npc_scion_of_eternity : public CreatureScript +{ + public: + npc_scion_of_eternity() : CreatureScript("npc_scion_of_eternity") { } + + struct npc_scion_of_eternityAI : public ScriptedAI + { + npc_scion_of_eternityAI(Creature* creature) : ScriptedAI(creature) + { + _instance = creature->GetInstanceScript(); + } + + void Reset() + { + _events.Reset(); + } + + void IsSummonedBy(Unit* /*summoner*/) + { + _events.ScheduleEvent(EVENT_ARCANE_BARRAGE, urand(14, 29)*IN_MILLISECONDS); + } + + void EnterCombat(Unit* /*who*/) + { + } + + void AttackStart(Unit* /*target*/) + { + } + + void EnterEvadeMode() + { + } + + void UpdateAI(uint32 diff) + { + _events.Update(diff); + + while (uint32 eventId = _events.ExecuteEvent()) + { + switch (eventId) + { + case EVENT_ARCANE_BARRAGE: + DoCast(me, SPELL_ARCANE_BARRAGE); + _events.ScheduleEvent(EVENT_ARCANE_BARRAGE, urand(3, 15)*IN_MILLISECONDS); + break; + } + } + } + + void JustDied(Unit* /*killer*/) + { + if (Creature* malygos = me->GetMap()->GetCreature(_instance->GetData64(DATA_MALYGOS))) + malygos->AI()->SetData(DATA_SUMMON_DEATHS, malygos->AI()->GetData(DATA_SUMMON_DEATHS) + 1); + } + + private: + InstanceScript* _instance; + EventMap _events; + }; + + CreatureAI* GetAI(Creature* creature) const + { + return new npc_scion_of_eternityAI(creature); + } +}; -// The reason of this AI is to make the creature able to enter in combat otherwise the spell casting of SPELL_ARCANE_OVERLOAD fails. class npc_arcane_overload : public CreatureScript { public: - npc_arcane_overload() : CreatureScript("npc_arcane_overload") {} - - CreatureAI* GetAI(Creature* creature) const - { - return new npc_arcane_overloadAI (creature); - } + npc_arcane_overload() : CreatureScript("npc_arcane_overload") { } struct npc_arcane_overloadAI : public ScriptedAI { - npc_arcane_overloadAI(Creature* creature) : ScriptedAI(creature) {} + npc_arcane_overloadAI(Creature* creature) : ScriptedAI(creature) + { + _instance = creature->GetInstanceScript(); + me->SetReactState(REACT_PASSIVE); + } - void AttackStart(Unit* who) + void IsSummonedBy(Unit* summoner) { - DoStartNoMovement(who); + if (Creature* creature = summoner->ToCreature()) + { + _malygos = creature; + _malygos->AI()->SetGUID(me->GetGUID(), DATA_LAST_OVERLOAD_GUID); + } } - void Reset() + void UpdateAI (uint32 /*diff*/) { - DoCast(me, SPELL_ARCANE_OVERLOAD, false); } - void UpdateAI(uint32 const /*diff*/) + void DoAction(int32 /*action*/) { - // we dont do melee damage! + if (Creature* malygos = me->GetMap()->GetCreature(_instance->GetData64(DATA_MALYGOS))) + { + if (malygos->AI()->GetData(DATA_PHASE) == PHASE_TWO) + me->DespawnOrUnsummon(6*IN_MILLISECONDS); + // If evade is hit during phase II shields should disappear with no delay + else if (malygos->AI()->GetData(DATA_PHASE) == 0) + me->DespawnOrUnsummon(); + } } + void SpellHit(Unit* /*caster*/, SpellInfo const* spell) + { + if (spell->Id == SPELL_ARCANE_BOMB_TRIGGER) + { + DoCastAOE(SPELL_ARCANE_BOMB_KNOCKBACK_DAMAGE, true); + DoCast(me, SPELL_ARCANE_OVERLOAD_1, true); + } + } + + private: + Creature* _malygos; + InstanceScript* _instance; }; + + CreatureAI* GetAI(Creature* creature) const + { + return new npc_arcane_overloadAI (creature); + } }; // SmartAI does not work correctly for vehicles class npc_wyrmrest_skytalon : public CreatureScript { public: - npc_wyrmrest_skytalon() : CreatureScript("npc_wyrmrest_skytalon") {} - - CreatureAI* GetAI(Creature* creature) const - { - return new npc_wyrmrest_skytalonAI (creature); - } + npc_wyrmrest_skytalon() : CreatureScript("npc_wyrmrest_skytalon") { } struct npc_wyrmrest_skytalonAI : public VehicleAI { - npc_wyrmrest_skytalonAI(Creature* creature) : VehicleAI(creature) { } + npc_wyrmrest_skytalonAI(Creature* creature) : VehicleAI(creature) + { + } void IsSummonedBy(Unit* summoner) { - summoner->CastSpell(me, SPELL_RIDE_RED_DRAGON, true); + _summoner = NULL; + if (Player* player = summoner->ToPlayer()) + { + _summoner = player; + _events.ScheduleEvent(EVENT_CAST_RIDE_SPELL, 2*IN_MILLISECONDS); + } + } + + void UpdateAI(uint32 diff) + { + VehicleAI::UpdateAI(diff); + _events.Update(diff); + + while (uint32 eventId = _events.ExecuteEvent()) + { + switch (eventId) + { + case EVENT_CAST_RIDE_SPELL: + me->CastSpell(_summoner, SPELL_RIDE_RED_DRAGON_TRIGGERED, true); + break; + } + } } void PassengerBoarded(Unit* /*unit*/, int8 /*seat*/, bool apply) { if (!apply) - me->DespawnOrUnsummon(); + { + me->DespawnOrUnsummon(2050); + me->SetOrientation(2.5f); + me->SetSpeed(MOVE_FLIGHT, 1.0f, true); + Position pos; + me->GetPosition(&pos); + pos.m_positionX += 10.0f; + pos.m_positionY += 10.0f; + pos.m_positionZ += 12.0f; + me->GetMotionMaster()->MovePoint(1, pos); + } } + + private: + Player* _summoner; + EventMap _events; }; + + CreatureAI* GetAI(Creature* creature) const + { + return new npc_wyrmrest_skytalonAI (creature); + } +}; + +// We shouldn't use SAI for stuff that aren't within boss main mechanic +// and SAI type of despawn can cause problems here. +class npc_static_field : public CreatureScript +{ + public: + npc_static_field() : CreatureScript("npc_static_field") { } + + struct npc_static_fieldAI : public ScriptedAI + { + npc_static_fieldAI(Creature* creature) : ScriptedAI(creature) + { + } + + void IsSummonedBy(Unit* /*summoner*/) + { + // For some great reason the spell doesn't time it... + me->DespawnOrUnsummon(30*IN_MILLISECONDS); + } + }; + + CreatureAI* GetAI(Creature* creature) const + { + return new npc_static_fieldAI (creature); + } +}; + +class spell_malygos_portal_beam : public SpellScriptLoader +{ + public: + spell_malygos_portal_beam() : SpellScriptLoader("spell_malygos_portal_beam") { } + + class spell_malygos_portal_beam_AuraScript : public AuraScript + { + PrepareAuraScript(spell_malygos_portal_beam_AuraScript); + + bool Load() + { + return GetCaster()->GetTypeId() == TYPEID_UNIT; + } + + bool Validate(SpellInfo const* /*spell*/) + { + if (!sSpellMgr->GetSpellInfo(SPELL_PORTAL_OPENED)) + return false; + + return true; + } + + void OnApply(AuraEffect const* /*aurEff*/, AuraEffectHandleModes /*mode*/) + { + if (Creature* target = GetTarget()->ToCreature()) + target->CastSpell(target, SPELL_PORTAL_OPENED); + } + + void OnRemove(AuraEffect const* /*aurEff*/, AuraEffectHandleModes /*mode*/) + { + if (Creature* target = GetTarget()->ToCreature()) + target->RemoveAura(SPELL_PORTAL_OPENED); + } + + void Register() + { + OnEffectApply += AuraEffectApplyFn(spell_malygos_portal_beam_AuraScript::OnApply, EFFECT_0, SPELL_AURA_DUMMY, AURA_EFFECT_HANDLE_REAL); + AfterEffectRemove += AuraEffectRemoveFn(spell_malygos_portal_beam_AuraScript::OnRemove, EFFECT_0, SPELL_AURA_DUMMY, AURA_EFFECT_HANDLE_REAL); + } + }; + + AuraScript* GetAuraScript() const + { + return new spell_malygos_portal_beam_AuraScript(); + } +}; + +class spell_malygos_random_portal : public SpellScriptLoader +{ + public: + spell_malygos_random_portal() : SpellScriptLoader("spell_malygos_random_portal") { } + + class spell_malygos_random_portal_SpellScript : public SpellScript + { + PrepareSpellScript(spell_malygos_random_portal_SpellScript); + + bool Load() + { + return GetCaster()->GetTypeId() == TYPEID_UNIT; + } + + void HandleDummy(SpellEffIndex /*effIndex*/) + { + Creature* malygos = GetCaster()->ToCreature(); + if (Creature* target = GetHitCreature()) + { + Position pos; + pos.m_positionZ = target->GetPositionZ(); + target->GetNearPoint2D(pos.m_positionX, pos.m_positionY, frand(29.1f, 30.0f), target->GetAngle(malygos)); + malygos->GetMotionMaster()->MovePoint(POINT_NEAR_RANDOM_PORTAL_P_NONE, pos); + } + } + + void Register() + { + OnEffectHitTarget += SpellEffectFn(spell_malygos_random_portal_SpellScript::HandleDummy, EFFECT_0, SPELL_EFFECT_DUMMY); + } + }; + + SpellScript* GetSpellScript() const + { + return new spell_malygos_random_portal_SpellScript(); + } +}; + +class IsCreatureVehicleCheck +{ + public: + IsCreatureVehicleCheck(bool isVehicle) : _isVehicle(isVehicle) { } + + bool operator()(WorldObject* obj) + { + if (Unit* unit = obj->ToUnit()) + if (unit->GetTypeId() == TYPEID_UNIT && unit->GetVehicleKit()) + return _isVehicle; + + return !_isVehicle; + } + + private: + bool _isVehicle; }; -class npc_alexstrasza_eoe : public CreatureScript +class spell_malygos_arcane_storm : public SpellScriptLoader +{ + public: + spell_malygos_arcane_storm() : SpellScriptLoader("spell_malygos_arcane_storm") { } + + class spell_malygos_arcane_storm_SpellScript : public SpellScript + { + PrepareSpellScript(spell_malygos_arcane_storm_SpellScript); + + bool Load() + { + return GetCaster()->GetTypeId() == TYPEID_UNIT; + } + + bool Validate(SpellInfo const* /*spell*/) + { + if (!sSpellMgr->GetSpellInfo(SPELL_ARCANE_STORM_EXTRA_VISUAL)) + return false; + + return true; + } + + void FilterTargets(std::list<WorldObject*>& targets) + { + if (targets.empty()) + return; + + Creature* malygos = GetCaster()->ToCreature(); + if (GetSpellInfo()->Id == SPELL_ARCANE_STORM_P_III) + { + // Resize list only to objects that are vehicles. + IsCreatureVehicleCheck check(true); + Trinity::Containers::RandomResizeList(targets, check, (malygos->GetMap()->GetDifficulty() == RAID_DIFFICULTY_10MAN_NORMAL ? 4 : 10)); + } + else + Trinity::Containers::RandomResizeList(targets, (malygos->GetMap()->GetDifficulty() == RAID_DIFFICULTY_10MAN_NORMAL ? 4 : 10)); + } + + void HandleVisual(SpellEffIndex /*effIndex*/) + { + // Both missiles should start approx at same time (with SPELL_ARCANE_STORM_EXTRA_VISUAL having advantage - it should lead) + if (!GetHitUnit()) + return; + + GetCaster()->CastSpell(GetHitUnit(), SPELL_ARCANE_STORM_EXTRA_VISUAL, true); + } + + void Register() + { + OnObjectAreaTargetSelect += SpellObjectAreaTargetSelectFn(spell_malygos_arcane_storm_SpellScript::FilterTargets, EFFECT_0, TARGET_UNIT_SRC_AREA_ENEMY); + OnEffectLaunchTarget += SpellEffectFn(spell_malygos_arcane_storm_SpellScript::HandleVisual, EFFECT_0, SPELL_EFFECT_SCHOOL_DAMAGE); + } + }; + + SpellScript* GetSpellScript() const + { + return new spell_malygos_arcane_storm_SpellScript(); + } +}; + +class spell_malygos_vortex_dummy : public SpellScriptLoader { public: - npc_alexstrasza_eoe() : CreatureScript("npc_alexstrasza_eoe") {} + spell_malygos_vortex_dummy() : SpellScriptLoader("spell_malygos_vortex_dummy") { } - CreatureAI* GetAI(Creature* creature) const + class spell_malygos_vortex_dummy_SpellScript : public SpellScript { - return new npc_alexstrasza_eoeAI (creature); - } + PrepareSpellScript(spell_malygos_vortex_dummy_SpellScript) - struct npc_alexstrasza_eoeAI : public ScriptedAI - { - npc_alexstrasza_eoeAI(Creature* creature) : ScriptedAI(creature) {} + bool Load() + { + return GetCaster()->GetTypeId() == TYPEID_UNIT; + } - void Reset() + void HandleScript(SpellEffIndex /*effIndex*/) { - _events.Reset(); - _events.ScheduleEvent(EVENT_YELL_1, 0); + Creature* caster = GetCaster()->ToCreature(); + // Each player will enter to the trigger vehicle (entry 30090) which is already spawned (each one can hold up to 5 players, it has 5 seats, + // the players enter the vehicles casting SPELL_VORTEX_4 or SPELL_VORTEX_5. + if (InstanceScript* instance = caster->GetInstanceScript()) + instance->SetData(DATA_VORTEX_HANDLING, 0); + + // the rest of the vortex execution continues when SPELL_VORTEX_2 is removed. } - void UpdateAI(uint32 const /*diff*/) + void Register() { - while (uint32 eventId = _events.ExecuteEvent()) + OnEffectHitTarget += SpellEffectFn(spell_malygos_vortex_dummy_SpellScript::HandleScript, EFFECT_0, SPELL_EFFECT_DUMMY); + } + }; + + SpellScript* GetSpellScript() const + { + return new spell_malygos_vortex_dummy_SpellScript(); + } +}; + +class spell_malygos_vortex_visual : public SpellScriptLoader +{ + public: + spell_malygos_vortex_visual() : SpellScriptLoader("spell_malygos_vortex_visual") { } + + class spell_malygos_vortex_visual_AuraScript : public AuraScript + { + PrepareAuraScript(spell_malygos_vortex_visual_AuraScript); + + bool Load() { - switch (eventId) + return GetCaster()->GetTypeId() == TYPEID_UNIT; + } + + bool Validate(SpellInfo const* /*spell*/) + { + if (!sSpellMgr->GetSpellInfo(SPELL_VORTEX_1) || !sSpellMgr->GetSpellInfo(SPELL_VORTEX_6)) + return false; + + return true; + } + + void OnRemove(AuraEffect const* /*aurEff*/, AuraEffectHandleModes /*mode*/) + { + if (Creature* caster = GetCaster()->ToCreature()) { - case EVENT_YELL_1: - Talk(SAY_ONE); - _events.ScheduleEvent(EVENT_YELL_2, 4*IN_MILLISECONDS); - break; - case EVENT_YELL_2: - Talk(SAY_TWO); - _events.ScheduleEvent(EVENT_YELL_3, 4*IN_MILLISECONDS); - break; - case EVENT_YELL_3: - Talk(SAY_THREE); - _events.ScheduleEvent(EVENT_YELL_4, 7*IN_MILLISECONDS); - break; - case EVENT_YELL_4: - Talk(SAY_FOUR); - break; + ThreatContainer::StorageType const& m_threatlist = caster->getThreatManager().getThreatList(); + for (ThreatContainer::StorageType::const_iterator itr = m_threatlist.begin(); itr!= m_threatlist.end(); ++itr) + { + if (Unit* target = (*itr)->getTarget()) + { + Player* targetPlayer = target->ToPlayer(); + if (!targetPlayer || targetPlayer->isGameMaster()) + continue; + + if (InstanceScript* instance = caster->GetInstanceScript()) + { + // Teleport spell - I'm not sure but might be it must be casted by each vehicle when it's passenger leaves it. + if (Creature* trigger = caster->GetMap()->GetCreature(instance->GetData64(DATA_TRIGGER))) + trigger->CastSpell(targetPlayer, SPELL_VORTEX_6, true); + } + } + } + + if (Creature* malygos = caster->ToCreature()) + { + malygos->GetMotionMaster()->MoveLand(POINT_LAND_AFTER_VORTEX_P_ONE, MalygosPositions[2]); + malygos->RemoveAura(SPELL_VORTEX_1); + } } } + + void Register() + { + AfterEffectRemove += AuraEffectRemoveFn(spell_malygos_vortex_visual_AuraScript::OnRemove, EFFECT_0, SPELL_AURA_DUMMY, AURA_EFFECT_HANDLE_REAL); + } + }; + + AuraScript* GetAuraScript() const + { + return new spell_malygos_vortex_visual_AuraScript(); } +}; + +class ExactDistanceCheck +{ + public: + ExactDistanceCheck(Unit* source, float dist) : _source(source), _dist(dist) { } + + bool operator()(WorldObject* unit) + { + return _source->GetExactDist2d(unit) > _dist; + } + private: - EventMap _events; - }; + Unit* _source; + float _dist; +}; + +class spell_arcane_overload : public SpellScriptLoader +{ + public: + spell_arcane_overload() : SpellScriptLoader("spell_arcane_overload") { } + + class spell_arcane_overload_SpellScript : public SpellScript + { + PrepareSpellScript(spell_arcane_overload_SpellScript); + + bool Load() + { + return GetCaster()->GetTypeId() == TYPEID_UNIT; + } + + void ResizeEffectRadiusTargetChecker(std::list<WorldObject*>& targets) + { + Creature* arcaneOverload = GetCaster()->ToCreature(); + targets.remove_if(ExactDistanceCheck(arcaneOverload, + GetSpellInfo()->Effects[EFFECT_0].CalcRadius(arcaneOverload) * arcaneOverload->GetFloatValue(OBJECT_FIELD_SCALE_X))); + } + + void Register() + { + OnObjectAreaTargetSelect += SpellObjectAreaTargetSelectFn(spell_arcane_overload_SpellScript::ResizeEffectRadiusTargetChecker, EFFECT_0, TARGET_UNIT_SRC_AREA_ENEMY); + } + }; + + SpellScript* GetSpellScript() const + { + return new spell_arcane_overload_SpellScript(); + } +}; + +class spell_nexus_lord_align_disk_aggro : public SpellScriptLoader +{ + public: + spell_nexus_lord_align_disk_aggro() : SpellScriptLoader("spell_nexus_lord_align_disk_aggro") { } + + class spell_nexus_lord_align_disk_aggro_SpellScript : public SpellScript + { + PrepareSpellScript(spell_nexus_lord_align_disk_aggro_SpellScript); + + bool Load() + { + return GetCaster()->GetTypeId() == TYPEID_UNIT; + } + + void HandleScript(SpellEffIndex /*effIndex*/) + { + Creature* caster = GetCaster()->ToCreature(); + if (Creature* target = GetHitCreature()) + target->GetMotionMaster()->MoveChase(caster->getVictim()); + } + + void Register() + { + OnEffectHitTarget += SpellEffectFn(spell_nexus_lord_align_disk_aggro_SpellScript::HandleScript, EFFECT_0, SPELL_EFFECT_SCRIPT_EFFECT); + } + }; + + SpellScript* GetSpellScript() const + { + return new spell_nexus_lord_align_disk_aggro_SpellScript(); + } +}; + +class IsPlayerOnHoverDisk +{ + public: + IsPlayerOnHoverDisk(bool isOnHoverDisk) : _isOnHoverDisk(isOnHoverDisk) { } + + bool operator()(WorldObject* obj) + { + if (Unit* passenger = obj->ToUnit()) + if (passenger->GetVehicleBase() && passenger->GetVehicleBase()->GetEntry() == NPC_HOVER_DISK_MELEE) + return _isOnHoverDisk; + + return !_isOnHoverDisk; + } + + private: + bool _isOnHoverDisk; +}; + +class spell_scion_of_eternity_arcane_barrage : public SpellScriptLoader +{ + public: + spell_scion_of_eternity_arcane_barrage() : SpellScriptLoader("spell_scion_of_eternity_arcane_barrage") { } + + class spell_scion_of_eternity_arcane_barrage_SpellScript : public SpellScript + { + PrepareSpellScript(spell_scion_of_eternity_arcane_barrage_SpellScript); + + bool Load() + { + return GetCaster()->GetTypeId() == TYPEID_UNIT && GetCaster()->GetInstanceScript() != NULL; + } + + void FilterMeleeHoverDiskPassangers(std::list<WorldObject*>& targets) + { + if (targets.empty()) + return; + + Creature* caster = GetCaster()->ToCreature(); + InstanceScript* instance = caster->GetInstanceScript(); + Creature* malygos = caster->GetMap()->GetCreature(instance->GetData64(DATA_MALYGOS)); + + // If max possible targets are more than 1 then Scions wouldn't select previosly selected target, + // in longer terms this means if spell picks target X then 2nd cast of this spell will pick smth else + // and if 3rd picks X again 4th will pick smth else (by not limiting the cast to certain caster). + if (targets.size() > 1) + if (malygos && malygos->AI()->GetGUID(DATA_LAST_TARGET_BARRAGE_GUID)) + targets.remove_if(Trinity::ObjectGUIDCheck(malygos->AI()->GetGUID(DATA_LAST_TARGET_BARRAGE_GUID))); + + // Remove players not on Hover Disk from second list + std::list<WorldObject*> playersWithoutDisk; + IsPlayerOnHoverDisk check(false); + for (std::list<WorldObject*>::iterator itr = targets.begin(); itr != targets.end(); ++itr) + if (check(*itr)) + playersWithoutDisk.push_back(*itr); + + // if it's empty than we can have player on Hover disk as target. + if (!playersWithoutDisk.empty()) + targets = playersWithoutDisk; + + // Finally here we remove all targets that have been damaged by Arcane Barrage + // and have 2 seconds long aura still lasting. Used to give healers some time. + if (!targets.empty()) + targets.remove_if(Trinity::UnitAuraCheck(true, SPELL_ARCANE_BARRAGE_DAMAGE)); + + // Now we resize the list to max output targets which can be only 1 + // to take it's guid and send/store it to DATA_LAST_TARGET_BARRAGE_GUID. + // Same target is never picked until next pick pass. This doesn't mean + // that it can't be hit more than once. In fact all is chance and raid speed. + if (!targets.empty()) + { + if (targets.size() > 1) + Trinity::Containers::RandomResizeList(targets, 1); + + if (WorldObject* filteredTarget = targets.front()) + if (malygos) + malygos->AI()->SetGUID(filteredTarget->GetGUID(), DATA_LAST_TARGET_BARRAGE_GUID); + } + } + + void TriggerDamageSpellFromPlayer() + { + if (Player* hitTarget = GetHitPlayer()) + { + // There is some proc in this spell I have absolutely no idea of use, but just in case... + TriggerCastFlags triggerFlags = TriggerCastFlags(TRIGGERED_FULL_MASK & ~TRIGGERED_DISALLOW_PROC_EVENTS); + hitTarget->CastSpell(hitTarget, SPELL_ARCANE_BARRAGE_DAMAGE, triggerFlags, NULL, NULL, GetCaster()->GetGUID()); + } + } + + void Register() + { + OnObjectAreaTargetSelect += SpellObjectAreaTargetSelectFn(spell_scion_of_eternity_arcane_barrage_SpellScript::FilterMeleeHoverDiskPassangers, EFFECT_0, TARGET_UNIT_SRC_AREA_ENEMY); + OnHit += SpellHitFn(spell_scion_of_eternity_arcane_barrage_SpellScript::TriggerDamageSpellFromPlayer); + } + }; + + SpellScript* GetSpellScript() const + { + return new spell_scion_of_eternity_arcane_barrage_SpellScript(); + } +}; + +class spell_malygos_destroy_platform_channel : public SpellScriptLoader +{ + public: + spell_malygos_destroy_platform_channel() : SpellScriptLoader("spell_malygos_destroy_platform_channel") { } + + class spell_malygos_destroy_platform_channel_AuraScript : public AuraScript + { + PrepareAuraScript(spell_malygos_destroy_platform_channel_AuraScript); + + bool Load() + { + return GetCaster()->GetTypeId() == TYPEID_UNIT; + } + + bool Validate(SpellInfo const* /*spell*/) + { + if (!sSpellMgr->GetSpellInfo(SPELL_DESTROY_PLATFORM_BOOM_VISUAL)) + return false; + + return true; + } + + void OnRemove(AuraEffect const* /*aurEff*/, AuraEffectHandleModes /*mode*/) + { + if (Creature* target = GetTarget()->ToCreature()) + if (InstanceScript* instance = target->GetInstanceScript()) + if (Creature* platformTrigger = target->GetMap()->GetCreature(instance->GetData64(DATA_ALEXSTRASZA_BUNNY_GUID))) + platformTrigger->CastSpell(platformTrigger, SPELL_DESTROY_PLATFORM_BOOM_VISUAL); + } + + void Register() + { + AfterEffectRemove += AuraEffectRemoveFn(spell_malygos_destroy_platform_channel_AuraScript::OnRemove, EFFECT_0, SPELL_AURA_DUMMY, AURA_EFFECT_HANDLE_REAL); + } + }; + + AuraScript* GetAuraScript() const + { + return new spell_malygos_destroy_platform_channel_AuraScript(); + } +}; + +class spell_alexstrasza_bunny_destroy_platform_boom_visual : public SpellScriptLoader +{ + public: + spell_alexstrasza_bunny_destroy_platform_boom_visual() : SpellScriptLoader("spell_alexstrasza_bunny_destroy_platform_boom_visual") { } + + class spell_alexstrasza_bunny_destroy_platform_boom_visual_SpellScript : public SpellScript + { + PrepareSpellScript(spell_alexstrasza_bunny_destroy_platform_boom_visual_SpellScript); + + bool Load() + { + return GetCaster()->GetTypeId() == TYPEID_UNIT; + } + + bool Validate(SpellInfo const* /*spell*/) + { + if (!sSpellMgr->GetSpellInfo(SPELL_DESTROY_PLATFORM_EVENT)) + return false; + + return true; + } + + void HandleDummy(SpellEffIndex /*effIndex*/) + { + if (Creature* target = GetHitCreature()) + target->CastSpell(target, SPELL_DESTROY_PLATFORM_EVENT); + } + + void Register() + { + OnEffectHitTarget += SpellEffectFn(spell_alexstrasza_bunny_destroy_platform_boom_visual_SpellScript::HandleDummy, EFFECT_0, SPELL_EFFECT_DUMMY); + } + }; + + SpellScript* GetSpellScript() const + { + return new spell_alexstrasza_bunny_destroy_platform_boom_visual_SpellScript(); + } +}; + +class spell_alexstrasza_bunny_destroy_platform_event : public SpellScriptLoader +{ + public: + spell_alexstrasza_bunny_destroy_platform_event() : SpellScriptLoader("spell_alexstrasza_bunny_destroy_platform_event") { } + + class spell_alexstrasza_bunny_destroy_platform_event_SpellScript : public SpellScript + { + PrepareSpellScript(spell_alexstrasza_bunny_destroy_platform_event_SpellScript); + + bool Load() + { + return GetCaster()->GetTypeId() == TYPEID_UNIT; + } + + void HandleSendEvent(SpellEffIndex /*effIndex*/) + { + Creature* caster = GetCaster()->ToCreature(); + if (InstanceScript* instance = caster->GetInstanceScript()) + if (GameObject* platform = caster->GetMap()->GetGameObject(instance->GetData64(DATA_PLATFORM))) + platform->SetFlag(GAMEOBJECT_FLAGS, GO_FLAG_DESTROYED); + } + + void HandleScript(SpellEffIndex /*effIndex*/) + { + GetCaster()->CastSpell((Unit*)NULL, SPELL_SUMMON_RED_DRAGON_BUDDY_F_CAST); + } + + void Register() + { + OnEffectHit += SpellEffectFn(spell_alexstrasza_bunny_destroy_platform_event_SpellScript::HandleSendEvent, EFFECT_0, SPELL_EFFECT_SEND_EVENT); + OnEffectHit += SpellEffectFn(spell_alexstrasza_bunny_destroy_platform_event_SpellScript::HandleScript, EFFECT_2, SPELL_EFFECT_SCRIPT_EFFECT); + } + }; + + SpellScript* GetSpellScript() const + { + return new spell_alexstrasza_bunny_destroy_platform_event_SpellScript(); + } +}; + +class spell_wyrmrest_skytalon_summon_red_dragon_buddy : public SpellScriptLoader +{ + public: + spell_wyrmrest_skytalon_summon_red_dragon_buddy() : SpellScriptLoader("spell_wyrmrest_skytalon_summon_red_dragon_buddy") { } + + class spell_wyrmrest_skytalon_summon_red_dragon_buddy_SpellScript : public SpellScript + { + PrepareSpellScript(spell_wyrmrest_skytalon_summon_red_dragon_buddy_SpellScript); + + bool Load() + { + return GetCaster()->GetTypeId() == TYPEID_PLAYER; + } + + void ChangeSummonPos(SpellEffIndex /*effIndex*/) + { + // Adjust effect summon position to lower Z + WorldLocation summonPos = *GetExplTargetDest(); + Position offset = { 0.0f, 0.0f, -80.0f, 0.0f }; + summonPos.RelocateOffset(offset); + SetExplTargetDest(summonPos); + GetHitDest()->RelocateOffset(offset); + } + + void Register() + { + OnEffectHit += SpellEffectFn(spell_wyrmrest_skytalon_summon_red_dragon_buddy_SpellScript::ChangeSummonPos, EFFECT_0, SPELL_EFFECT_SUMMON); + } + }; + + SpellScript* GetSpellScript() const + { + return new spell_wyrmrest_skytalon_summon_red_dragon_buddy_SpellScript(); + } +}; + +class spell_wyrmrest_skytalon_ride_red_dragon_buddy_trigger : public SpellScriptLoader +{ + public: + spell_wyrmrest_skytalon_ride_red_dragon_buddy_trigger() : SpellScriptLoader("spell_wyrmrest_skytalon_ride_red_dragon_buddy_trigger") { } + + class spell_wyrmrest_skytalon_ride_red_dragon_buddy_trigger_SpellScript : public SpellScript + { + PrepareSpellScript(spell_wyrmrest_skytalon_ride_red_dragon_buddy_trigger_SpellScript); + + bool Load() + { + return GetCaster()->GetTypeId() == TYPEID_UNIT; + } + + void HandleScript(SpellEffIndex /*effIndex*/) + { + if (Unit* target = GetHitUnit()) + target->CastSpell(GetCaster(), GetEffectValue(), true); + } + + void Register() + { + OnEffectHitTarget += SpellEffectFn(spell_wyrmrest_skytalon_ride_red_dragon_buddy_trigger_SpellScript::HandleScript, EFFECT_0, SPELL_EFFECT_SCRIPT_EFFECT); + } + }; + + SpellScript* GetSpellScript() const + { + return new spell_wyrmrest_skytalon_ride_red_dragon_buddy_trigger_SpellScript(); + } +}; + +class spell_malygos_surge_of_power_warning_selector_25 : public SpellScriptLoader +{ + public: + spell_malygos_surge_of_power_warning_selector_25() : SpellScriptLoader("spell_malygos_surge_of_power_warning_selector_25") { } + + class spell_malygos_surge_of_power_warning_selector_25_SpellScript : public SpellScript + { + PrepareSpellScript(spell_malygos_surge_of_power_warning_selector_25_SpellScript) + + bool Load() + { + return GetCaster()->GetTypeId() == TYPEID_UNIT; + } + + bool Validate(SpellInfo const* /*spell*/) + { + if (!sSpellMgr->GetSpellInfo(SPELL_SURGE_OF_POWER_PHASE_3_25)) + return false; + + return true; + } + + void SendThreeTargets(std::list<WorldObject*>& targets) + { + // This spell hits only vehicles (SMSG_SPELL_GO target) + Creature* caster = GetCaster()->ToCreature(); + // Remove all objects that aren't* vehicles. + targets.remove_if(IsCreatureVehicleCheck(false)); + if (targets.empty()) + return; + + // But in fact it selects 3 targets (SMSG_SPELL_GO target are not filtered) + std::list<WorldObject*> selectedTargets = targets; + + uint8 guidDataSlot = DATA_FIRST_SURGE_TARGET_GUID; // SetGuid in Malygos AI is reserved for 14th, 15th and 16th Id for the three targets + Trinity::Containers::RandomResizeList(selectedTargets, 3); + for (std::list<WorldObject*>::const_iterator itr = selectedTargets.begin(); itr != selectedTargets.end(); ++itr) + { + Creature* target = (*itr)->ToCreature(); + caster->AI()->SetGUID(target->GetGUID(), guidDataSlot++); + + if (Vehicle* vehicle = target->GetVehicleKit()) + if (Unit* passenger = vehicle->GetPassenger(0)) + if (passenger->GetTypeId() == TYPEID_PLAYER) + caster->AI()->Talk(EMOTE_SURGE_OF_POWER_WARNING_P3, passenger->GetGUID()); + } + } + + void ExecuteMainSpell() + { + GetCaster()->ToCreature()->AI()->DoCastAOE(SPELL_SURGE_OF_POWER_PHASE_3_25); + } + + void Register() + { + OnObjectAreaTargetSelect += SpellObjectAreaTargetSelectFn(spell_malygos_surge_of_power_warning_selector_25_SpellScript::SendThreeTargets, EFFECT_0, TARGET_UNIT_SRC_AREA_ENEMY); + AfterHit += SpellHitFn(spell_malygos_surge_of_power_warning_selector_25_SpellScript::ExecuteMainSpell); + } + }; + + SpellScript* GetSpellScript() const + { + return new spell_malygos_surge_of_power_warning_selector_25_SpellScript(); + } +}; + +class spell_malygos_surge_of_power_25 : public SpellScriptLoader +{ + public: + spell_malygos_surge_of_power_25() : SpellScriptLoader("spell_malygos_surge_of_power_25") { } + + class spell_malygos_surge_of_power_25_SpellScript : public SpellScript + { + PrepareSpellScript(spell_malygos_surge_of_power_25_SpellScript) + + bool Load() + { + return GetCaster()->GetTypeId() == TYPEID_UNIT; + } + + void FilterTargets(std::list<WorldObject*>& targets) + { + Creature* caster = GetCaster()->ToCreature(); + + for (std::list<WorldObject*>::iterator itr = targets.begin(); itr != targets.end();) + { + bool found = false; + WorldObject* target = *itr; + + for (uint32 guidSlot = DATA_FIRST_SURGE_TARGET_GUID; guidSlot < DATA_FIRST_SURGE_TARGET_GUID + NUM_MAX_SURGE_TARGETS; ++guidSlot) + { + if (target->GetGUID() == caster->AI()->GetGUID(guidSlot)) + { + found = true; + break; + } + } + + if (!found) + targets.erase(itr++); + else + ++itr; + } + } + + void Register() + { + OnObjectAreaTargetSelect += SpellObjectAreaTargetSelectFn(spell_malygos_surge_of_power_25_SpellScript::FilterTargets, EFFECT_0, TARGET_UNIT_SRC_AREA_ENEMY); + } + }; + + SpellScript* GetSpellScript() const + { + return new spell_malygos_surge_of_power_25_SpellScript(); + } +}; + +class spell_alexstrasza_gift_beam : public SpellScriptLoader +{ + public: + spell_alexstrasza_gift_beam() : SpellScriptLoader("spell_alexstrasza_gift_beam") { } + + class spell_alexstrasza_gift_beam_AuraScript : public AuraScript + { + PrepareAuraScript(spell_alexstrasza_gift_beam_AuraScript); + + bool Load() + { + return GetCaster()->GetTypeId() == TYPEID_UNIT; + } + + bool Validate(SpellInfo const* /*spell*/) + { + if (!sSpellMgr->GetSpellInfo(SPELL_ALEXSTRASZAS_GIFT_BEAM_VISUAL)) + return false; + + return true; + } + + void OnApply(AuraEffect const* /*aurEff*/, AuraEffectHandleModes /*mode*/) + { + if (Creature* target = GetTarget()->ToCreature()) + target->CastSpell(target, SPELL_ALEXSTRASZAS_GIFT_BEAM_VISUAL); + } + + void OnRemove(AuraEffect const* /*aurEff*/, AuraEffectHandleModes /*mode*/) + { + if (Creature* target = GetTarget()->ToCreature()) + target->RemoveAura(SPELL_ALEXSTRASZAS_GIFT_BEAM_VISUAL); + } + + void Register() + { + OnEffectApply += AuraEffectApplyFn(spell_alexstrasza_gift_beam_AuraScript::OnApply, EFFECT_0, SPELL_AURA_DUMMY, AURA_EFFECT_HANDLE_REAL); + AfterEffectRemove += AuraEffectRemoveFn(spell_alexstrasza_gift_beam_AuraScript::OnRemove, EFFECT_0, SPELL_AURA_DUMMY, AURA_EFFECT_HANDLE_REAL); + } + }; + + AuraScript* GetAuraScript() const + { + return new spell_alexstrasza_gift_beam_AuraScript(); + } +}; + +class spell_alexstrasza_gift_beam_visual : public SpellScriptLoader +{ + public: + spell_alexstrasza_gift_beam_visual() : SpellScriptLoader("spell_alexstrasza_gift_beam_visual") { } + + class spell_alexstrasza_gift_beam_visual_AuraScript : public AuraScript + { + PrepareAuraScript(spell_alexstrasza_gift_beam_visual_AuraScript); + + bool Load() + { + return GetCaster()->GetTypeId() == TYPEID_UNIT; + } + + void OnApply(AuraEffect const* /*aurEff*/, AuraEffectHandleModes /*mode*/) + { + if (Creature* target = GetTarget()->ToCreature()) + { + if (target->GetMap()->GetDifficulty() == RAID_DIFFICULTY_10MAN_NORMAL) + _alexstraszaGift = target->SummonGameObject(GO_ALEXSTRASZA_S_GIFT_10, target->GetPositionX(), target->GetPositionY(), target->GetPositionZ(), target->GetOrientation(), 0.0f, 0.0f, 0.0f, 0.0f, 0); + else if (target->GetMap()->GetDifficulty() == RAID_DIFFICULTY_25MAN_NORMAL) + _alexstraszaGift = target->SummonGameObject(GO_ALEXSTRASZA_S_GIFT_25, target->GetPositionX(), target->GetPositionY(), target->GetPositionZ(), target->GetOrientation(), 0.0f, 0.0f, 0.0f, 0.0f, 0); + } + } + + void OnRemove(AuraEffect const* /*aurEff*/, AuraEffectHandleModes /*mode*/) + { + if (Creature* target = GetTarget()->ToCreature()) + if (InstanceScript* instance = GetCaster()->GetInstanceScript()) + { + _alexstraszaGift->RemoveFlag(GAMEOBJECT_FLAGS, GO_FLAG_NOT_SELECTABLE); + if (GameObject* heartMagic = target->GetMap()->GetGameObject(instance->GetData64(DATA_HEART_OF_MAGIC_GUID))) + { + heartMagic->RemoveFlag(GAMEOBJECT_FLAGS, GO_FLAG_NOT_SELECTABLE); + // TO DO: This is hack, core doesn't have support for these flags, + // remove line below if it ever gets supported otherwise object won't be accessible. + heartMagic->RemoveFlag(GAMEOBJECT_FLAGS, GO_FLAG_INTERACT_COND); + } + } + } + + void Register() + { + OnEffectApply += AuraEffectApplyFn(spell_alexstrasza_gift_beam_visual_AuraScript::OnApply, EFFECT_0, SPELL_AURA_DUMMY, AURA_EFFECT_HANDLE_REAL); + AfterEffectRemove += AuraEffectRemoveFn(spell_alexstrasza_gift_beam_visual_AuraScript::OnRemove, EFFECT_0, SPELL_AURA_DUMMY, AURA_EFFECT_HANDLE_REAL); + } + + GameObject* _alexstraszaGift; + }; + + AuraScript* GetAuraScript() const + { + return new spell_alexstrasza_gift_beam_visual_AuraScript(); + } }; class achievement_denyin_the_scion : public AchievementCriteriaScript { public: - achievement_denyin_the_scion() : AchievementCriteriaScript("achievement_denyin_the_scion") {} + achievement_denyin_the_scion() : AchievementCriteriaScript("achievement_denyin_the_scion") { } bool OnCheck(Player* source, Unit* /*target*/) { + // Only melee disks can be used if (Unit* disk = source->GetVehicleBase()) - if (disk->GetEntry() == NPC_HOVER_DISK_CASTER || disk->GetEntry() == NPC_HOVER_DISK_MELEE) + if (disk->GetEntry() == NPC_HOVER_DISK_MELEE) return true; + return false; } }; @@ -1114,11 +2547,29 @@ void AddSC_boss_malygos() new boss_malygos(); new npc_portal_eoe(); new npc_power_spark(); - new npc_hover_disk(); + new npc_melee_hover_disk(); + new npc_caster_hover_disk(); + new npc_nexus_lord(); + new npc_scion_of_eternity(); new npc_arcane_overload(); new npc_wyrmrest_skytalon(); + new npc_static_field(); + new spell_malygos_portal_beam(); + new spell_malygos_random_portal(); + new spell_malygos_arcane_storm(); new spell_malygos_vortex_dummy(); new spell_malygos_vortex_visual(); - new npc_alexstrasza_eoe(); + new spell_arcane_overload(); + new spell_nexus_lord_align_disk_aggro(); + new spell_scion_of_eternity_arcane_barrage(); + new spell_malygos_destroy_platform_channel(); + new spell_alexstrasza_bunny_destroy_platform_boom_visual(); + new spell_alexstrasza_bunny_destroy_platform_event(); + new spell_wyrmrest_skytalon_summon_red_dragon_buddy(); + new spell_wyrmrest_skytalon_ride_red_dragon_buddy_trigger(); + new spell_malygos_surge_of_power_warning_selector_25(); + new spell_malygos_surge_of_power_25(); + new spell_alexstrasza_gift_beam(); + new spell_alexstrasza_gift_beam_visual(); new achievement_denyin_the_scion(); } diff --git a/src/server/scripts/Northrend/Nexus/EyeOfEternity/eye_of_eternity.h b/src/server/scripts/Northrend/Nexus/EyeOfEternity/eye_of_eternity.h index c25feaafaf8..db879eab6fb 100644 --- a/src/server/scripts/Northrend/Nexus/EyeOfEternity/eye_of_eternity.h +++ b/src/server/scripts/Northrend/Nexus/EyeOfEternity/eye_of_eternity.h @@ -24,14 +24,19 @@ enum InstanceData MAX_ENCOUNTER, DATA_VORTEX_HANDLING, - DATA_POWER_SPARKS_HANDLING + DATA_POWER_SPARKS_HANDLING, + DATA_RESPAWN_IRIS }; enum InstanceData64 { DATA_TRIGGER, DATA_MALYGOS, - DATA_PLATFORM + DATA_PLATFORM, + DATA_ALEXSTRASZA_BUNNY_GUID, + DATA_HEART_OF_MAGIC_GUID, + DATA_FOCUSING_IRIS_GUID, + DATA_GIFT_BOX_BUNNY_GUID }; enum InstanceNpcs @@ -44,16 +49,22 @@ enum InstanceNpcs NPC_HOVER_DISK_CASTER = 30248, NPC_ARCANE_OVERLOAD = 30282, NPC_WYRMREST_SKYTALON = 30161, - NPC_ALEXSTRASZA = 32295 + NPC_ALEXSTRASZA = 32295, + NPC_ALEXSTRASZA_BUNNY = 31253, + NPC_ALEXSTRASZAS_GIFT = 32448, + NPC_SURGE_OF_POWER = 30334 }; enum InstanceGameObjects { GO_NEXUS_RAID_PLATFORM = 193070, GO_EXIT_PORTAL = 193908, - GO_FOCUSING_IRIS = 193958, - GO_ALEXSTRASZA_S_GIFT = 193905, - GO_ALEXSTRASZA_S_GIFT_2 = 193967 + GO_FOCUSING_IRIS_10 = 193958, + GO_FOCUSING_IRIS_25 = 193960, + GO_ALEXSTRASZA_S_GIFT_10 = 193905, + GO_ALEXSTRASZA_S_GIFT_25 = 193967, + GO_HEART_OF_MAGIC_10 = 194158, + GO_HEART_OF_MAGIC_25 = 194159 }; enum InstanceEvents @@ -63,10 +74,11 @@ enum InstanceEvents enum InstanceSpells { - SPELL_VORTEX_4 = 55853, // damage | used to enter to the vehicle - SPELL_VORTEX_5 = 56263, // damage | used to enter to the vehicle - SPELL_PORTAL_OPENED = 61236, - SPELL_RIDE_RED_DRAGON = 56071, + SPELL_VORTEX_4 = 55853, // damage | used to enter to the vehicle + SPELL_VORTEX_5 = 56263, // damage | used to enter to the vehicle + SPELL_PORTAL_OPENED = 61236, + SPELL_RIDE_RED_DRAGON_TRIGGERED = 56072, + SPELL_IRIS_OPENED = 61012 // visual when starting encounter }; #endif diff --git a/src/server/scripts/Northrend/Nexus/EyeOfEternity/instance_eye_of_eternity.cpp b/src/server/scripts/Northrend/Nexus/EyeOfEternity/instance_eye_of_eternity.cpp index 6b1be15f110..079732b0f14 100644 --- a/src/server/scripts/Northrend/Nexus/EyeOfEternity/instance_eye_of_eternity.cpp +++ b/src/server/scripts/Northrend/Nexus/EyeOfEternity/instance_eye_of_eternity.cpp @@ -24,7 +24,7 @@ class instance_eye_of_eternity : public InstanceMapScript { public: - instance_eye_of_eternity() : InstanceMapScript("instance_eye_of_eternity", 616) {} + instance_eye_of_eternity() : InstanceMapScript("instance_eye_of_eternity", 616) { } InstanceScript* GetInstanceScript(InstanceMap* map) const { @@ -41,9 +41,11 @@ public: portalTriggers.clear(); malygosGUID = 0; + irisGUID = 0; lastPortalGUID = 0; platformGUID = 0; exitPortalGUID = 0; + alexstraszaBunnyGUID = 0; }; bool SetBossState(uint32 type, EncounterState state) @@ -65,31 +67,18 @@ public: } } - SpawnGameObject(GO_FOCUSING_IRIS, focusingIrisPosition); SpawnGameObject(GO_EXIT_PORTAL, exitPortalPosition); if (GameObject* platform = instance->GetGameObject(platformGUID)) platform->RemoveFlag(GAMEOBJECT_FLAGS, GO_FLAG_DESTROYED); } else if (state == DONE) - { - if (Creature* malygos = instance->GetCreature(malygosGUID)) - malygos->SummonCreature(NPC_ALEXSTRASZA, 829.0679f, 1244.77f, 279.7453f, 2.32f); - SpawnGameObject(GO_EXIT_PORTAL, exitPortalPosition); - - // we make the platform appear again because at the moment we don't support looting using a vehicle - if (GameObject* platform = instance->GetGameObject(platformGUID)) - platform->RemoveFlag(GAMEOBJECT_FLAGS, GO_FLAG_DESTROYED); - - if (GameObject* chest = instance->GetGameObject(chestGUID)) - chest->SetRespawnTime(7*DAY); - } } return true; } - //TODO: this should be handled in map, maybe add a summon function in map + /// @todo this should be handled in map, maybe add a summon function in map // There is no other way afaik... void SpawnGameObject(uint32 entry, Position& pos) { @@ -112,16 +101,31 @@ public: case GO_NEXUS_RAID_PLATFORM: platformGUID = go->GetGUID(); break; - case GO_FOCUSING_IRIS: - go->GetPosition(&focusingIrisPosition); + case GO_FOCUSING_IRIS_10: + if (instance->GetDifficulty() == RAID_DIFFICULTY_10MAN_NORMAL) + { + irisGUID = go->GetGUID(); + go->GetPosition(&focusingIrisPosition); + } + break; + case GO_FOCUSING_IRIS_25: + if (instance->GetDifficulty() == RAID_DIFFICULTY_25MAN_NORMAL) + { + irisGUID = go->GetGUID(); + go->GetPosition(&focusingIrisPosition); + } break; case GO_EXIT_PORTAL: exitPortalGUID = go->GetGUID(); go->GetPosition(&exitPortalPosition); break; - case GO_ALEXSTRASZA_S_GIFT: - case GO_ALEXSTRASZA_S_GIFT_2: - chestGUID = go->GetGUID(); + case GO_HEART_OF_MAGIC_10: + if (instance->GetDifficulty() == RAID_DIFFICULTY_10MAN_NORMAL) + heartOfMagicGUID = go->GetGUID(); + break; + case GO_HEART_OF_MAGIC_25: + if (instance->GetDifficulty() == RAID_DIFFICULTY_25MAN_NORMAL) + heartOfMagicGUID = go->GetGUID(); break; } } @@ -139,18 +143,40 @@ public: case NPC_PORTAL_TRIGGER: portalTriggers.push_back(creature->GetGUID()); break; + case NPC_ALEXSTRASZA_BUNNY: + alexstraszaBunnyGUID = creature->GetGUID(); + break; + case NPC_ALEXSTRASZAS_GIFT: + giftBoxBunnyGUID = creature->GetGUID(); + break; } } - void ProcessEvent(WorldObject* obj, uint32 eventId) + void OnUnitDeath(Unit* unit) + { + if (unit->GetTypeId() != TYPEID_PLAYER) + return; + + // Player continues to be moving after death no matter if spline will be cleared along with all movements, + // so on next world tick was all about delay if box will pop or not (when new movement will be registered) + // since in EoE you never stop falling. However root at this precise* moment works, + // it will get cleared on release. If by any chance some lag happen "Reload()" and "RepopMe()" works, + // last test I made now gave me 50/0 of this bug so I can't do more about it. + unit->SetControlled(true, UNIT_STATE_ROOT); + } + + void ProcessEvent(WorldObject* /*obj*/, uint32 eventId) { if (eventId == EVENT_FOCUSING_IRIS) { - if (GameObject* go = obj->ToGameObject()) - go->Delete(); // this is not the best way. + if (Creature* alexstraszaBunny = instance->GetCreature(alexstraszaBunnyGUID)) + { + alexstraszaBunny->CastSpell(alexstraszaBunny, SPELL_IRIS_OPENED); + instance->GetGameObject(irisGUID)->SetFlag(GAMEOBJECT_FLAGS, GO_FLAG_IN_USE); + } if (Creature* malygos = instance->GetCreature(malygosGUID)) - malygos->GetMotionMaster()->MovePoint(4, 770.10f, 1275.33f, 267.23f); // MOVE_INIT_PHASE_ONE + malygos->AI()->DoAction(0); // ACTION_LAND_ENCOUNTER_START if (GameObject* exitPortal = instance->GetGameObject(exitPortalGUID)) exitPortal->Delete(); @@ -194,7 +220,7 @@ public: void PowerSparksHandling() { - bool next = (lastPortalGUID == portalTriggers.back() || !lastPortalGUID ? true : false); + bool next = (lastPortalGUID == portalTriggers.back() || !lastPortalGUID ? true : false); for (std::list<uint64>::const_iterator itr_trigger = portalTriggers.begin(); itr_trigger != portalTriggers.end(); ++itr_trigger) { @@ -223,6 +249,9 @@ public: case DATA_POWER_SPARKS_HANDLING: PowerSparksHandling(); break; + case DATA_RESPAWN_IRIS: + SpawnGameObject(instance->GetDifficulty() == RAID_DIFFICULTY_10MAN_NORMAL ? GO_FOCUSING_IRIS_10 : GO_FOCUSING_IRIS_25, focusingIrisPosition); + break; } } @@ -236,6 +265,14 @@ public: return malygosGUID; case DATA_PLATFORM: return platformGUID; + case DATA_ALEXSTRASZA_BUNNY_GUID: + return alexstraszaBunnyGUID; + case DATA_HEART_OF_MAGIC_GUID: + return heartOfMagicGUID; + case DATA_FOCUSING_IRIS_GUID: + return irisGUID; + case DATA_GIFT_BOX_BUNNY_GUID: + return giftBoxBunnyGUID; } return 0; @@ -287,10 +324,13 @@ public: std::list<uint64> vortexTriggers; std::list<uint64> portalTriggers; uint64 malygosGUID; + uint64 irisGUID; uint64 lastPortalGUID; uint64 platformGUID; uint64 exitPortalGUID; - uint64 chestGUID; + uint64 heartOfMagicGUID; + uint64 alexstraszaBunnyGUID; + uint64 giftBoxBunnyGUID; Position focusingIrisPosition; Position exitPortalPosition; }; diff --git a/src/server/scripts/Northrend/Nexus/Nexus/boss_anomalus.cpp b/src/server/scripts/Northrend/Nexus/Nexus/boss_anomalus.cpp index 955c6b801af..8d1420ce12e 100644 --- a/src/server/scripts/Northrend/Nexus/Nexus/boss_anomalus.cpp +++ b/src/server/scripts/Northrend/Nexus/Nexus/boss_anomalus.cpp @@ -124,7 +124,7 @@ class boss_anomalus : public CreatureScript chaosTheory = false; } - void UpdateAI(uint32 const diff) + void UpdateAI(uint32 diff) { if (!UpdateVictim()) return; @@ -191,11 +191,12 @@ class mob_chaotic_rift : public CreatureScript public: mob_chaotic_rift() : CreatureScript("mob_chaotic_rift") { } - struct mob_chaotic_riftAI : public Scripted_NoMovementAI + struct mob_chaotic_riftAI : public ScriptedAI { - mob_chaotic_riftAI(Creature* creature) : Scripted_NoMovementAI(creature) + mob_chaotic_riftAI(Creature* creature) : ScriptedAI(creature) { instance = me->GetInstanceScript(); + SetCombatMovement(false); } InstanceScript* instance; @@ -211,7 +212,7 @@ class mob_chaotic_rift : public CreatureScript DoCast(me, SPELL_ARCANEFORM, false); } - void UpdateAI(uint32 const diff) + void UpdateAI(uint32 diff) { if (!UpdateVictim()) return; diff --git a/src/server/scripts/Northrend/Nexus/Nexus/boss_commander_kolurg.cpp b/src/server/scripts/Northrend/Nexus/Nexus/boss_commander_kolurg.cpp index fedb1f5cebc..7f32b2bc4a5 100644 --- a/src/server/scripts/Northrend/Nexus/Nexus/boss_commander_kolurg.cpp +++ b/src/server/scripts/Northrend/Nexus/Nexus/boss_commander_kolurg.cpp @@ -56,7 +56,7 @@ public: void EnterCombat(Unit* /*who*/) {} void AttackStart(Unit* /*who*/) {} void MoveInLineOfSight(Unit* /*who*/) {} - void UpdateAI(const uint32 /*diff*/) + void UpdateAI(uint32 /*diff*/) { //Return since we have no target if (!UpdateVictim()) diff --git a/src/server/scripts/Northrend/Nexus/Nexus/boss_commander_stoutbeard.cpp b/src/server/scripts/Northrend/Nexus/Nexus/boss_commander_stoutbeard.cpp index 39c93f15d6f..e257b898426 100644 --- a/src/server/scripts/Northrend/Nexus/Nexus/boss_commander_stoutbeard.cpp +++ b/src/server/scripts/Northrend/Nexus/Nexus/boss_commander_stoutbeard.cpp @@ -53,7 +53,7 @@ public: void Reset() {} void AttackStart(Unit* /*who*/) {} void MoveInLineOfSight(Unit* /*who*/) {} - void UpdateAI(const uint32 /*diff*/) + void UpdateAI(uint32 /*diff*/) { //Return since we have no target if (!UpdateVictim()) diff --git a/src/server/scripts/Northrend/Nexus/Nexus/boss_keristrasza.cpp b/src/server/scripts/Northrend/Nexus/Nexus/boss_keristrasza.cpp index d1a9227c6fb..e84431a0788 100644 --- a/src/server/scripts/Northrend/Nexus/Nexus/boss_keristrasza.cpp +++ b/src/server/scripts/Northrend/Nexus/Nexus/boss_keristrasza.cpp @@ -167,7 +167,7 @@ public: intenseColdList.push_back(guid); } - void UpdateAI(const uint32 diff) + void UpdateAI(uint32 diff) { if (!UpdateVictim()) return; @@ -244,7 +244,7 @@ class spell_intense_cold : public SpellScriptLoader if (aurEff->GetBase()->GetStackAmount() < 2) return; Unit* caster = GetCaster(); - //TODO: the caster should be boss but not the player + /// @todo the caster should be boss but not the player if (!caster || !caster->GetAI()) return; caster->GetAI()->SetGUID(GetTarget()->GetGUID(), DATA_INTENSE_COLD); diff --git a/src/server/scripts/Northrend/Nexus/Nexus/boss_magus_telestra.cpp b/src/server/scripts/Northrend/Nexus/Nexus/boss_magus_telestra.cpp index 7679ae53c80..26bf80cb32e 100644 --- a/src/server/scripts/Northrend/Nexus/Nexus/boss_magus_telestra.cpp +++ b/src/server/scripts/Northrend/Nexus/Nexus/boss_magus_telestra.cpp @@ -140,7 +140,7 @@ public: Talk(SAY_KILL); } - void DoAction(int32 const action) + void DoAction(int32 action) { if (action == ACTION_MAGUS_DEAD) { @@ -213,7 +213,7 @@ public: } } - void UpdateAI(const uint32 diff) + void UpdateAI(uint32 diff) { //Return since we have no target if (!UpdateVictim()) diff --git a/src/server/scripts/Northrend/Nexus/Nexus/boss_ormorok.cpp b/src/server/scripts/Northrend/Nexus/Nexus/boss_ormorok.cpp index c9cfe70b8de..0f480b1d101 100644 --- a/src/server/scripts/Northrend/Nexus/Nexus/boss_ormorok.cpp +++ b/src/server/scripts/Northrend/Nexus/Nexus/boss_ormorok.cpp @@ -109,7 +109,7 @@ public: Talk(SAY_KILL); } - void UpdateAI(const uint32 diff) + void UpdateAI(uint32 diff) { if (!UpdateVictim()) return; @@ -219,7 +219,7 @@ public: return type == DATA_COUNT ? _count : 0; } - void UpdateAI(const uint32 diff) + void UpdateAI(uint32 diff) { if (_despawntimer <= diff) { diff --git a/src/server/scripts/Northrend/Nexus/Oculus/boss_drakos.cpp b/src/server/scripts/Northrend/Nexus/Oculus/boss_drakos.cpp index feb801450b1..1a820cd3727 100644 --- a/src/server/scripts/Northrend/Nexus/Oculus/boss_drakos.cpp +++ b/src/server/scripts/Northrend/Nexus/Oculus/boss_drakos.cpp @@ -81,7 +81,7 @@ public: Talk(SAY_AGGRO); } - void UpdateAI(const uint32 diff) + void UpdateAI(uint32 diff) { //Return since we have no target if (!UpdateVictim()) @@ -170,7 +170,7 @@ public: deathTimer = 19000; } - void UpdateAI(const uint32 diff) + void UpdateAI(uint32 diff) { if (pulseTimer <= diff) { diff --git a/src/server/scripts/Northrend/Nexus/Oculus/boss_eregos.cpp b/src/server/scripts/Northrend/Nexus/Oculus/boss_eregos.cpp index 0af498f24c6..d27909328a5 100644 --- a/src/server/scripts/Northrend/Nexus/Oculus/boss_eregos.cpp +++ b/src/server/scripts/Northrend/Nexus/Oculus/boss_eregos.cpp @@ -141,7 +141,7 @@ public: return 0; } - void DoAction(const int32 action) + void DoAction(int32 action) { if (action != ACTION_SET_NORMAL_EVENTS) return; @@ -194,7 +194,7 @@ public: } } - void UpdateAI(const uint32 diff) + void UpdateAI(uint32 diff) { //Return since we have no target if (!UpdateVictim()) diff --git a/src/server/scripts/Northrend/Nexus/Oculus/boss_urom.cpp b/src/server/scripts/Northrend/Nexus/Oculus/boss_urom.cpp index 07f19ce9760..57a9c9958df 100644 --- a/src/server/scripts/Northrend/Nexus/Oculus/boss_urom.cpp +++ b/src/server/scripts/Northrend/Nexus/Oculus/boss_urom.cpp @@ -240,7 +240,7 @@ public: Talk(SAY_PLAYER_KILL); } - void UpdateAI(const uint32 uiDiff) + void UpdateAI(uint32 uiDiff) { if (!UpdateVictim()) return; diff --git a/src/server/scripts/Northrend/Nexus/Oculus/boss_varos.cpp b/src/server/scripts/Northrend/Nexus/Oculus/boss_varos.cpp index ec240db0b69..a2b5d340410 100644 --- a/src/server/scripts/Northrend/Nexus/Oculus/boss_varos.cpp +++ b/src/server/scripts/Northrend/Nexus/Oculus/boss_varos.cpp @@ -96,7 +96,7 @@ public: return coreEnergizeOrientation; } - void UpdateAI(const uint32 diff) + void UpdateAI(uint32 diff) { //Return since we have no target if (!UpdateVictim()) @@ -187,7 +187,7 @@ class npc_azure_ring_captain : public CreatureScript } } - void UpdateAI(const uint32 /*diff*/) + void UpdateAI(uint32 /*diff*/) { if (!UpdateVictim()) return; @@ -207,7 +207,7 @@ class npc_azure_ring_captain : public CreatureScript DoCast(target, SPELL_ICE_BEAM); } - void DoAction(const int32 action) + void DoAction(int32 action) { switch (action) { diff --git a/src/server/scripts/Northrend/Nexus/Oculus/oculus.cpp b/src/server/scripts/Northrend/Nexus/Oculus/oculus.cpp index f152d0011aa..1f8ba3edade 100644 --- a/src/server/scripts/Northrend/Nexus/Oculus/oculus.cpp +++ b/src/server/scripts/Northrend/Nexus/Oculus/oculus.cpp @@ -355,7 +355,7 @@ public: } } - void UpdateAI(const uint32 diff) + void UpdateAI(uint32 diff) { if (!(instance->GetBossState(DATA_VAROS_EVENT) == DONE)) { diff --git a/src/server/scripts/Northrend/Ulduar/HallsOfLightning/boss_bjarngrim.cpp b/src/server/scripts/Northrend/Ulduar/HallsOfLightning/boss_bjarngrim.cpp index 16e705e45ab..e7c6e920970 100644 --- a/src/server/scripts/Northrend/Ulduar/HallsOfLightning/boss_bjarngrim.cpp +++ b/src/server/scripts/Northrend/Ulduar/HallsOfLightning/boss_bjarngrim.cpp @@ -206,7 +206,7 @@ public: instance->SetData(TYPE_BJARNGRIM, DONE); } - //TODO: remove when removal is done by the core + /// @todo remove when removal is done by the core void DoRemoveStanceAura(uint8 uiStance) { switch (uiStance) @@ -223,7 +223,7 @@ public: } } - void UpdateAI(const uint32 uiDiff) + void UpdateAI(uint32 uiDiff) { //Return since we have no target if (!UpdateVictim()) @@ -412,7 +412,7 @@ public: } } - void UpdateAI(const uint32 uiDiff) + void UpdateAI(uint32 uiDiff) { //Return since we have no target if (!UpdateVictim()) diff --git a/src/server/scripts/Northrend/Ulduar/HallsOfLightning/boss_ionar.cpp b/src/server/scripts/Northrend/Ulduar/HallsOfLightning/boss_ionar.cpp index 6f017884063..9ce8ea3c52c 100644 --- a/src/server/scripts/Northrend/Ulduar/HallsOfLightning/boss_ionar.cpp +++ b/src/server/scripts/Northrend/Ulduar/HallsOfLightning/boss_ionar.cpp @@ -198,8 +198,7 @@ public: summoned->CastSpell(summoned, DUNGEON_MODE(SPELL_SPARK_VISUAL_TRIGGER, H_SPELL_SPARK_VISUAL_TRIGGER), true); - Unit* target = SelectTarget(SELECT_TARGET_RANDOM, 0); - if (target) + if (Unit* target = SelectTarget(SELECT_TARGET_RANDOM, 0)) { summoned->SetInCombatWith(target); summoned->GetMotionMaster()->Clear(); @@ -214,7 +213,7 @@ public: lSparkList.Despawn(summoned); } - void UpdateAI(const uint32 uiDiff) + void UpdateAI(uint32 uiDiff) { //Return since we have no target if (!UpdateVictim()) @@ -336,7 +335,7 @@ public: uiDamage = 0; } - void UpdateAI(const uint32 uiDiff) + void UpdateAI(uint32 uiDiff) { // Despawn if the encounter is not running if (instance && instance->GetData(TYPE_IONAR) != IN_PROGRESS) diff --git a/src/server/scripts/Northrend/Ulduar/HallsOfLightning/boss_loken.cpp b/src/server/scripts/Northrend/Ulduar/HallsOfLightning/boss_loken.cpp index df99ab33467..fe6c1c27155 100644 --- a/src/server/scripts/Northrend/Ulduar/HallsOfLightning/boss_loken.cpp +++ b/src/server/scripts/Northrend/Ulduar/HallsOfLightning/boss_loken.cpp @@ -123,7 +123,7 @@ public: Talk(SAY_SLAY); } - void UpdateAI(const uint32 uiDiff) + void UpdateAI(uint32 uiDiff) { //Return since we have no target if (!UpdateVictim()) diff --git a/src/server/scripts/Northrend/Ulduar/HallsOfLightning/boss_volkhan.cpp b/src/server/scripts/Northrend/Ulduar/HallsOfLightning/boss_volkhan.cpp index 9b22003bb1c..1e41f346942 100644 --- a/src/server/scripts/Northrend/Ulduar/HallsOfLightning/boss_volkhan.cpp +++ b/src/server/scripts/Northrend/Ulduar/HallsOfLightning/boss_volkhan.cpp @@ -226,7 +226,7 @@ public: return 0; } - void UpdateAI(const uint32 uiDiff) + void UpdateAI(uint32 uiDiff) { if (!UpdateVictim()) return; @@ -427,7 +427,7 @@ public: me->DespawnOrUnsummon(); } - void UpdateAI(const uint32 uiDiff) + void UpdateAI(uint32 uiDiff) { // Return since we have no target or if we are frozen if (!UpdateVictim() || m_bIsFrozen) diff --git a/src/server/scripts/Northrend/Ulduar/HallsOfStone/boss_krystallus.cpp b/src/server/scripts/Northrend/Ulduar/HallsOfStone/boss_krystallus.cpp index c9a4d2ba5bd..adbc8827212 100644 --- a/src/server/scripts/Northrend/Ulduar/HallsOfStone/boss_krystallus.cpp +++ b/src/server/scripts/Northrend/Ulduar/HallsOfStone/boss_krystallus.cpp @@ -99,7 +99,7 @@ public: instance->SetData(DATA_KRYSTALLUS_EVENT, IN_PROGRESS); } - void UpdateAI(const uint32 diff) + void UpdateAI(uint32 diff) { //Return since we have no target if (!UpdateVictim()) @@ -164,7 +164,7 @@ public: //this part should be in the core if (pSpell->Id == SPELL_SHATTER || pSpell->Id == H_SPELL_SHATTER) { - // todo: we need eventmap to kill this stuff + /// @todo we need eventmap to kill this stuff //clear this, if we are still performing if (bIsSlam) { diff --git a/src/server/scripts/Northrend/Ulduar/HallsOfStone/boss_maiden_of_grief.cpp b/src/server/scripts/Northrend/Ulduar/HallsOfStone/boss_maiden_of_grief.cpp index 7fbf5f3ee79..71222aba88b 100644 --- a/src/server/scripts/Northrend/Ulduar/HallsOfStone/boss_maiden_of_grief.cpp +++ b/src/server/scripts/Northrend/Ulduar/HallsOfStone/boss_maiden_of_grief.cpp @@ -107,7 +107,7 @@ public: } } - void UpdateAI(const uint32 diff) + void UpdateAI(uint32 diff) { //Return since we have no target if (!UpdateVictim()) @@ -117,9 +117,7 @@ public: { if (PartingSorrowTimer <= diff) { - Unit* target = SelectTarget(SELECT_TARGET_RANDOM, 0); - - if (target) + if (Unit* target = SelectTarget(SELECT_TARGET_RANDOM, 0)) DoCast(target, SPELL_PARTING_SORROW); PartingSorrowTimer = urand(30000, 40000); diff --git a/src/server/scripts/Northrend/Ulduar/HallsOfStone/boss_sjonnir.cpp b/src/server/scripts/Northrend/Ulduar/HallsOfStone/boss_sjonnir.cpp index 9e4c97ea0fc..3b0faa08574 100644 --- a/src/server/scripts/Northrend/Ulduar/HallsOfStone/boss_sjonnir.cpp +++ b/src/server/scripts/Northrend/Ulduar/HallsOfStone/boss_sjonnir.cpp @@ -147,7 +147,7 @@ public: } } - void UpdateAI(const uint32 diff) + void UpdateAI(uint32 diff) { //Return since we have no target if (!UpdateVictim()) @@ -228,7 +228,7 @@ public: Talk(SAY_SLAY); } - void DoAction(int32 const action) + void DoAction(int32 action) { if (action == ACTION_OOZE_DEAD) ++abuseTheOoze; @@ -266,7 +266,7 @@ public: uiMergeTimer = 10000; } - void UpdateAI(const uint32 diff) + void UpdateAI(uint32 diff) { if (uiMergeTimer <= diff) { diff --git a/src/server/scripts/Northrend/Ulduar/HallsOfStone/halls_of_stone.cpp b/src/server/scripts/Northrend/Ulduar/HallsOfStone/halls_of_stone.cpp index f1d690f32e0..0a9ae889588 100644 --- a/src/server/scripts/Northrend/Ulduar/HallsOfStone/halls_of_stone.cpp +++ b/src/server/scripts/Northrend/Ulduar/HallsOfStone/halls_of_stone.cpp @@ -204,7 +204,7 @@ public: }*/ } - void UpdateAI(const uint32 diff) + void UpdateAI(uint32 diff) { if (bKaddrakActivated) { diff --git a/src/server/scripts/Northrend/Ulduar/Ulduar/boss_algalon_the_observer.cpp b/src/server/scripts/Northrend/Ulduar/Ulduar/boss_algalon_the_observer.cpp index 1f96848fa0a..5a5efc36b3c 100644 --- a/src/server/scripts/Northrend/Ulduar/Ulduar/boss_algalon_the_observer.cpp +++ b/src/server/scripts/Northrend/Ulduar/Ulduar/boss_algalon_the_observer.cpp @@ -176,10 +176,7 @@ enum EncounterPhases { PHASE_NORMAL = 0, PHASE_ROLE_PLAY = 1, - PHASE_BIG_BANG = 2, - - PHASE_MASK_NO_UPDATE = (1 << PHASE_ROLE_PLAY) | (1 << PHASE_BIG_BANG), - PHASE_MASK_NO_CAST_CHECK = 1 << PHASE_ROLE_PLAY, + PHASE_BIG_BANG = 2 }; enum AchievmentInfo @@ -331,7 +328,7 @@ class boss_algalon_the_observer : public CreatureScript } } - void DoAction(int32 const action) + void DoAction(int32 action) { switch (action) { @@ -343,8 +340,8 @@ class boss_algalon_the_observer : public CreatureScript DoCast(me, SPELL_RIDE_THE_LIGHTNING, true); me->GetMotionMaster()->MovePoint(POINT_ALGALON_LAND, AlgalonLandPos); me->SetHomePosition(AlgalonLandPos); - Movement::MoveSplineInit init(*me); - init.MoveTo(AlgalonLandPos.GetPositionX(), AlgalonLandPos.GetPositionY(), AlgalonLandPos.GetPositionZ()); + Movement::MoveSplineInit init(me); + init.MoveTo(AlgalonLandPos.GetPositionX(), AlgalonLandPos.GetPositionY(), AlgalonLandPos.GetPositionZ(), false); init.SetOrientationFixed(true); init.Launch(); events.Reset(); @@ -540,14 +537,14 @@ class boss_algalon_the_observer : public CreatureScript } } - void UpdateAI(uint32 const diff) + void UpdateAI(uint32 diff) { - if ((!(events.GetPhaseMask() & PHASE_MASK_NO_UPDATE) && !UpdateVictim()) || !CheckInRoom()) + if ((!(events.IsInPhase(PHASE_ROLE_PLAY) || events.IsInPhase(PHASE_BIG_BANG)) && !UpdateVictim()) || !CheckInRoom()) return; events.Update(diff); - if (!(events.GetPhaseMask() & PHASE_MASK_NO_CAST_CHECK)) + if (!events.IsInPhase(PHASE_ROLE_PLAY)) if (me->HasUnitState(UNIT_STATE_CASTING)) return; @@ -733,7 +730,7 @@ class npc_living_constellation : public CreatureScript return _isActive ? 1 : 0; } - void DoAction(int32 const action) + void DoAction(int32 action) { switch (action) { @@ -770,9 +767,9 @@ class npc_living_constellation : public CreatureScript caster->ToCreature()->DespawnOrUnsummon(1); } - void UpdateAI(uint32 const diff) + void UpdateAI(uint32 diff) { - if (!(_events.GetPhaseMask() & PHASE_MASK_NO_UPDATE) && !UpdateVictim()) + if (!(_events.IsInPhase(PHASE_ROLE_PLAY) || _events.IsInPhase(PHASE_BIG_BANG)) && !UpdateVictim()) return; _events.Update(diff); @@ -864,7 +861,7 @@ class npc_brann_bronzebeard_algalon : public CreatureScript { } - void DoAction(int32 const action) + void DoAction(int32 action) { switch (action) { @@ -915,7 +912,7 @@ class npc_brann_bronzebeard_algalon : public CreatureScript _events.ScheduleEvent(EVENT_BRANN_MOVE_INTRO, delay); } - void UpdateAI(uint32 const diff) + void UpdateAI(uint32 diff) { UpdateVictim(); diff --git a/src/server/scripts/Northrend/Ulduar/Ulduar/boss_assembly_of_iron.cpp b/src/server/scripts/Northrend/Ulduar/Ulduar/boss_assembly_of_iron.cpp index 451ad6ed915..6ad70d38635 100644 --- a/src/server/scripts/Northrend/Ulduar/Ulduar/boss_assembly_of_iron.cpp +++ b/src/server/scripts/Northrend/Ulduar/Ulduar/boss_assembly_of_iron.cpp @@ -158,7 +158,7 @@ class boss_steelbreaker : public CreatureScript events.ScheduleEvent(EVENT_FUSION_PUNCH, 15000); } - void DoAction(int32 const action) + void DoAction(int32 action) { switch (action) { @@ -212,7 +212,7 @@ class boss_steelbreaker : public CreatureScript DoCast(me, SPELL_ELECTRICAL_CHARGE); } - void UpdateAI(uint32 const diff) + void UpdateAI(uint32 diff) { if (!UpdateVictim()) return; @@ -287,7 +287,7 @@ class boss_runemaster_molgeim : public CreatureScript events.ScheduleEvent(EVENT_RUNE_OF_POWER, 20000); } - void DoAction(int32 const action) + void DoAction(int32 action) { switch (action) { @@ -338,7 +338,7 @@ class boss_runemaster_molgeim : public CreatureScript Talk(SAY_MOLGEIM_SLAY); } - void UpdateAI(uint32 const diff) + void UpdateAI(uint32 diff) { if (!UpdateVictim()) return; @@ -440,7 +440,7 @@ class boss_stormcaller_brundir : public CreatureScript events.ScheduleEvent(EVENT_OVERLOAD, urand(60000, 120000)); } - void DoAction(int32 const action) + void DoAction(int32 action) { switch (action) { @@ -499,7 +499,7 @@ class boss_stormcaller_brundir : public CreatureScript Talk(SAY_BRUNDIR_SLAY); } - void UpdateAI(uint32 const diff) + void UpdateAI(uint32 diff) { if (!UpdateVictim()) return; diff --git a/src/server/scripts/Northrend/Ulduar/Ulduar/boss_auriaya.cpp b/src/server/scripts/Northrend/Ulduar/Ulduar/boss_auriaya.cpp index aa8c7a96898..5faa2cc4628 100644 --- a/src/server/scripts/Northrend/Ulduar/Ulduar/boss_auriaya.cpp +++ b/src/server/scripts/Northrend/Ulduar/Ulduar/boss_auriaya.cpp @@ -154,7 +154,7 @@ class boss_auriaya : public CreatureScript } } - void DoAction(int32 const action) + void DoAction(int32 action) { switch (action) { @@ -207,7 +207,7 @@ class boss_auriaya : public CreatureScript Talk(SAY_DEATH); } - void UpdateAI(uint32 const diff) + void UpdateAI(uint32 diff) { if (!UpdateVictim()) return; @@ -299,7 +299,7 @@ class npc_auriaya_seeping_trigger : public CreatureScript DoCast(me, SPELL_SEEPING_ESSENCE); } - void UpdateAI(uint32 const /*diff*/) + void UpdateAI(uint32 /*diff*/) { if (instance->GetBossState(BOSS_AURIAYA) != IN_PROGRESS) me->DespawnOrUnsummon(); @@ -338,7 +338,7 @@ class npc_sanctum_sentry : public CreatureScript DoCast(me, SPELL_STRENGHT_PACK, true); } - void UpdateAI(uint32 const diff) + void UpdateAI(uint32 diff) { if (!UpdateVictim()) return; @@ -408,7 +408,7 @@ class npc_feral_defender : public CreatureScript events.ScheduleEvent(EVENT_RUSH, 10000); } - void UpdateAI(uint32 const diff) + void UpdateAI(uint32 diff) { if (!UpdateVictim()) return; diff --git a/src/server/scripts/Northrend/Ulduar/Ulduar/boss_flame_leviathan.cpp b/src/server/scripts/Northrend/Ulduar/Ulduar/boss_flame_leviathan.cpp index 89ddbb7ac38..f89112e3d67 100644 --- a/src/server/scripts/Northrend/Ulduar/Ulduar/boss_flame_leviathan.cpp +++ b/src/server/scripts/Northrend/Ulduar/Ulduar/boss_flame_leviathan.cpp @@ -362,7 +362,7 @@ class boss_flame_leviathan : public CreatureScript Unbroken = data ? true : false; } - void UpdateAI(uint32 const diff) + void UpdateAI(uint32 diff) { if (!UpdateVictim() || !CheckInRoom()) return; @@ -467,7 +467,7 @@ class boss_flame_leviathan : public CreatureScript _pursueTarget = target->GetGUID(); } - void DoAction(int32 const action) + void DoAction(int32 action) { if (action && action <= 4) // Tower destruction, debuff leviathan loot and reduce active tower count { @@ -638,7 +638,7 @@ class boss_flame_leviathan_defense_cannon : public CreatureScript DoCast(me, AURA_STEALTH_DETECTION); } - void UpdateAI(uint32 const diff) + void UpdateAI(uint32 diff) { if (!UpdateVictim()) return; @@ -752,7 +752,7 @@ class boss_flame_leviathan_safety_container : public CreatureScript me->SetPosition(x, y, z, 0); } - void UpdateAI(uint32 const /*diff*/) + void UpdateAI(uint32 /*diff*/) { } }; @@ -802,7 +802,7 @@ class npc_mechanolift : public CreatureScript container->EnterVehicle(me); } - void UpdateAI(const uint32 diff) + void UpdateAI(uint32 diff) { if (MoveTimer <= diff) { @@ -851,7 +851,7 @@ class npc_pool_of_tar : public CreatureScript me->CastSpell(me, SPELL_BLAZE, true); } - void UpdateAI(uint32 const /*diff*/) {} + void UpdateAI(uint32 /*diff*/) {} }; CreatureAI* GetAI(Creature* creature) const @@ -880,7 +880,7 @@ class npc_colossus : public CreatureScript instance->SetData(DATA_COLOSSUS, instance->GetData(DATA_COLOSSUS)+1); } - void UpdateAI(uint32 const /*diff*/) + void UpdateAI(uint32 /*diff*/) { if (!UpdateVictim()) return; @@ -917,7 +917,7 @@ class npc_thorims_hammer : public CreatureScript } } - void UpdateAI(uint32 const /*diff*/) + void UpdateAI(uint32 /*diff*/) { if (!me->HasAura(AURA_DUMMY_BLUE)) me->CastSpell(me, AURA_DUMMY_BLUE, true); @@ -963,7 +963,7 @@ public: uint32 infernoTimer; - void UpdateAI(uint32 const diff) + void UpdateAI(uint32 diff) { npc_escortAI::UpdateAI(diff); @@ -1012,7 +1012,7 @@ class npc_hodirs_fury : public CreatureScript } } - void UpdateAI(uint32 const /*diff*/) + void UpdateAI(uint32 /*diff*/) { if (!me->HasAura(AURA_DUMMY_GREEN)) me->CastSpell(me, AURA_DUMMY_GREEN, true); @@ -1046,7 +1046,7 @@ class npc_freyas_ward : public CreatureScript summonTimer = 5000; } - void UpdateAI(uint32 const diff) + void UpdateAI(uint32 diff) { if (summonTimer <= diff) { @@ -1089,7 +1089,7 @@ class npc_freya_ward_summon : public CreatureScript lashTimer = 5000; } - void UpdateAI(uint32 const diff) + void UpdateAI(uint32 diff) { if (!UpdateVictim()) return; @@ -1127,7 +1127,7 @@ class npc_lorekeeper : public CreatureScript { } - void DoAction(int32 const action) + void DoAction(int32 action) { // Start encounter if (action == ACTION_SPAWN_VEHICLES) @@ -1176,7 +1176,7 @@ class npc_lorekeeper : public CreatureScript if (Creature* Branz = creature->FindNearestCreature(NPC_BRANZ_BRONZBEARD, 1000, true)) { Delorah->GetMotionMaster()->MovePoint(0, Branz->GetPositionX()-4, Branz->GetPositionY(), Branz->GetPositionZ()); - //TODO Delorah->AI()->Talk(xxxx, Branz->GetGUID()); when reached at branz + /// @todo Delorah->AI()->Talk(xxxx, Branz->GetGUID()); when reached at branz } } } @@ -1608,7 +1608,7 @@ class FlameLeviathanPursuedTargetSelector bool operator()(WorldObject* target) const { - //! No players, only vehicles (todo: check if blizzlike) + //! No players, only vehicles (@todo check if blizzlike) Creature* creatureTarget = target->ToCreature(); if (!creatureTarget) return true; diff --git a/src/server/scripts/Northrend/Ulduar/Ulduar/boss_freya.cpp b/src/server/scripts/Northrend/Ulduar/Ulduar/boss_freya.cpp index 4db3b58c53f..33a14aaa3df 100644 --- a/src/server/scripts/Northrend/Ulduar/Ulduar/boss_freya.cpp +++ b/src/server/scripts/Northrend/Ulduar/Ulduar/boss_freya.cpp @@ -216,10 +216,12 @@ class npc_iron_roots : public CreatureScript public: npc_iron_roots() : CreatureScript("npc_iron_roots") { } - struct npc_iron_rootsAI : public Scripted_NoMovementAI + struct npc_iron_rootsAI : public ScriptedAI { - npc_iron_rootsAI(Creature* creature) : Scripted_NoMovementAI(creature) + npc_iron_rootsAI(Creature* creature) : ScriptedAI(creature) { + SetCombatMovement(false); + me->ApplySpellImmune(0, IMMUNITY_EFFECT, SPELL_EFFECT_KNOCK_BACK, true); me->ApplySpellImmune(0, IMMUNITY_ID, 49560, true); // Death Grip me->setFaction(14); @@ -385,7 +387,7 @@ class boss_freya : public CreatureScript return 0; } - void UpdateAI(uint32 const diff) + void UpdateAI(uint32 diff) { if (!UpdateVictim()) return; @@ -720,7 +722,7 @@ class boss_elder_brightleaf : public CreatureScript Talk(SAY_ELDER_AGGRO); } - void UpdateAI(uint32 const diff) + void UpdateAI(uint32 diff) { if (!UpdateVictim() || me->HasAura(SPELL_DRAINED_OF_POWER)) return; @@ -763,7 +765,7 @@ class boss_elder_brightleaf : public CreatureScript DoMeleeAttackIfReady(); } - void DoAction(int32 const action) + void DoAction(int32 action) { switch (action) { @@ -854,7 +856,7 @@ class boss_elder_stonebark : public CreatureScript } } - void UpdateAI(uint32 const diff) + void UpdateAI(uint32 diff) { if (!UpdateVictim() || me->HasAura(SPELL_DRAINED_OF_POWER)) return; @@ -890,7 +892,7 @@ class boss_elder_stonebark : public CreatureScript DoMeleeAttackIfReady(); } - void DoAction(int32 const action) + void DoAction(int32 action) { switch (action) { @@ -968,7 +970,7 @@ class boss_elder_ironbranch : public CreatureScript Talk(SAY_ELDER_AGGRO); } - void UpdateAI(uint32 const diff) + void UpdateAI(uint32 diff) { if (!UpdateVictim() || me->HasAura(SPELL_DRAINED_OF_POWER)) return; @@ -1004,7 +1006,7 @@ class boss_elder_ironbranch : public CreatureScript DoMeleeAttackIfReady(); } - void DoAction(int32 const action) + void DoAction(int32 action) { switch (action) { @@ -1049,7 +1051,7 @@ class npc_detonating_lasher : public CreatureScript changeTargetTimer = 7500; } - void UpdateAI(uint32 const diff) + void UpdateAI(uint32 diff) { if (!UpdateVictim()) return; @@ -1108,7 +1110,7 @@ class npc_ancient_water_spirit : public CreatureScript tidalWaveTimer = 10000; } - void UpdateAI(uint32 const diff) + void UpdateAI(uint32 diff) { if (!UpdateVictim()) return; @@ -1169,7 +1171,7 @@ class npc_storm_lasher : public CreatureScript stormboltTimer = 5000; } - void UpdateAI(uint32 const diff) + void UpdateAI(uint32 diff) { if (!UpdateVictim()) return; @@ -1230,7 +1232,7 @@ class npc_snaplasher : public CreatureScript waveCount = CAST_AI(boss_freya::boss_freyaAI, Freya->AI())->trioWaveCount; } - void UpdateAI(uint32 const /*diff*/) + void UpdateAI(uint32 /*diff*/) { if (!UpdateVictim()) return; @@ -1295,7 +1297,7 @@ class npc_ancient_conservator : public CreatureScript DoCast(who, SPELL_CONSERVATOR_GRIP, true); } - void UpdateAI(uint32 const diff) + void UpdateAI(uint32 diff) { if (!UpdateVictim()) return; @@ -1337,10 +1339,11 @@ class npc_sun_beam : public CreatureScript public: npc_sun_beam() : CreatureScript("npc_sun_beam") { } - struct npc_sun_beamAI : public Scripted_NoMovementAI + struct npc_sun_beamAI : public ScriptedAI { - npc_sun_beamAI(Creature* creature) : Scripted_NoMovementAI(creature) + npc_sun_beamAI(Creature* creature) : ScriptedAI(creature) { + SetCombatMovement(false); me->SetReactState(REACT_PASSIVE); DoCastAOE(SPELL_FREYA_UNSTABLE_ENERGY_VISUAL, true); DoCast(SPELL_FREYA_UNSTABLE_ENERGY); @@ -1358,10 +1361,11 @@ class npc_healthy_spore : public CreatureScript public: npc_healthy_spore() : CreatureScript("npc_healthy_spore") { } - struct npc_healthy_sporeAI : public Scripted_NoMovementAI + struct npc_healthy_sporeAI : public ScriptedAI { - npc_healthy_sporeAI(Creature* creature) : Scripted_NoMovementAI(creature) + npc_healthy_sporeAI(Creature* creature) : ScriptedAI(creature) { + SetCombatMovement(false); me->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE | UNIT_FLAG_NON_ATTACKABLE | UNIT_FLAG_IMMUNE_TO_PC); me->SetReactState(REACT_PASSIVE); DoCast(me, SPELL_HEALTHY_SPORE_VISUAL); @@ -1370,7 +1374,7 @@ class npc_healthy_spore : public CreatureScript lifeTimer = urand(22000, 30000); } - void UpdateAI(uint32 const diff) + void UpdateAI(uint32 diff) { if (lifeTimer <= diff) { @@ -1397,17 +1401,19 @@ class npc_eonars_gift : public CreatureScript public: npc_eonars_gift() : CreatureScript("npc_eonars_gift") { } - struct npc_eonars_giftAI : public Scripted_NoMovementAI + struct npc_eonars_giftAI : public ScriptedAI { - npc_eonars_giftAI(Creature* creature) : Scripted_NoMovementAI(creature) + npc_eonars_giftAI(Creature* creature) : ScriptedAI(creature) { + SetCombatMovement(false); + lifeBindersGiftTimer = 12000; DoCast(me, SPELL_GROW); DoCast(me, SPELL_PHEROMONES, true); DoCast(me, SPELL_EONAR_VISUAL, true); } - void UpdateAI(uint32 const diff) + void UpdateAI(uint32 diff) { if (lifeBindersGiftTimer <= diff) { @@ -1435,15 +1441,17 @@ class npc_nature_bomb : public CreatureScript public: npc_nature_bomb() : CreatureScript("npc_nature_bomb") { } - struct npc_nature_bombAI : public Scripted_NoMovementAI + struct npc_nature_bombAI : public ScriptedAI { - npc_nature_bombAI(Creature* creature) : Scripted_NoMovementAI(creature) + npc_nature_bombAI(Creature* creature) : ScriptedAI(creature) { + SetCombatMovement(false); + bombTimer = urand(8000, 10000); DoCast(SPELL_OBJECT_BOMB); } - void UpdateAI(uint32 const diff) + void UpdateAI(uint32 diff) { if (bombTimer <= diff) { @@ -1475,10 +1483,12 @@ class npc_unstable_sun_beam : public CreatureScript public: npc_unstable_sun_beam() : CreatureScript("npc_unstable_sun_beam") { } - struct npc_unstable_sun_beamAI : public Scripted_NoMovementAI + struct npc_unstable_sun_beamAI : public ScriptedAI { - npc_unstable_sun_beamAI(Creature* creature) : Scripted_NoMovementAI(creature) + npc_unstable_sun_beamAI(Creature* creature) : ScriptedAI(creature) { + SetCombatMovement(false); + despawnTimer = urand(7000, 12000); instance = me->GetInstanceScript(); DoCast(me, SPELL_PHOTOSYNTHESIS); @@ -1486,7 +1496,7 @@ class npc_unstable_sun_beam : public CreatureScript me->SetReactState(REACT_PASSIVE); } - void UpdateAI(uint32 const diff) + void UpdateAI(uint32 diff) { if (despawnTimer <= diff) { diff --git a/src/server/scripts/Northrend/Ulduar/Ulduar/boss_general_vezax.cpp b/src/server/scripts/Northrend/Ulduar/Ulduar/boss_general_vezax.cpp index 6fa2c7127e6..1642cc0483f 100644 --- a/src/server/scripts/Northrend/Ulduar/Ulduar/boss_general_vezax.cpp +++ b/src/server/scripts/Northrend/Ulduar/Ulduar/boss_general_vezax.cpp @@ -135,7 +135,7 @@ class boss_general_vezax : public CreatureScript events.ScheduleEvent(EVENT_BERSERK, 600000); } - void UpdateAI(uint32 const diff) + void UpdateAI(uint32 diff) { if (!UpdateVictim()) return; @@ -250,7 +250,7 @@ class boss_general_vezax : public CreatureScript return 0; } - void DoAction(int32 const action) + void DoAction(int32 action) { switch (action) { @@ -333,7 +333,7 @@ class boss_saronite_animus : public CreatureScript Vezax->AI()->DoAction(ACTION_ANIMUS_DIE); } - void UpdateAI(uint32 const diff) + void UpdateAI(uint32 diff) { if (!UpdateVictim()) return; @@ -392,7 +392,7 @@ class npc_saronite_vapors : public CreatureScript events.ScheduleEvent(EVENT_RANDOM_MOVE, urand(5000, 7500)); } - void UpdateAI(uint32 const diff) + void UpdateAI(uint32 diff) { events.Update(diff); diff --git a/src/server/scripts/Northrend/Ulduar/Ulduar/boss_hodir.cpp b/src/server/scripts/Northrend/Ulduar/Ulduar/boss_hodir.cpp index 26d15d78e59..b970dc6d7ab 100644 --- a/src/server/scripts/Northrend/Ulduar/Ulduar/boss_hodir.cpp +++ b/src/server/scripts/Northrend/Ulduar/Ulduar/boss_hodir.cpp @@ -25,7 +25,7 @@ #include "GridNotifiersImpl.h" #include "ulduar.h" -/* #TODO: Achievements +/* @todo Achievements Storm Cloud (Shaman ability) Destroying of Toasty Fires */ @@ -193,7 +193,7 @@ class npc_flash_freeze : public CreatureScript checkDespawnTimer = 1000; } - void UpdateAI(uint32 const diff) + void UpdateAI(uint32 diff) { if (!UpdateVictim() || me->getVictim()->HasAura(SPELL_BLOCK_OF_ICE) || me->getVictim()->HasAura(SPELL_FLASH_FREEZE_HELPER)) return; @@ -381,7 +381,7 @@ class boss_hodir : public CreatureScript } } - void UpdateAI(uint32 const diff) + void UpdateAI(uint32 diff) { if (!UpdateVictim()) return; @@ -460,7 +460,7 @@ class boss_hodir : public CreatureScript DoMeleeAttackIfReady(); } - void DoAction(int32 const action) + void DoAction(int32 action) { switch (action) { @@ -525,7 +525,7 @@ class npc_icicle : public CreatureScript icicleTimer = 2500; } - void UpdateAI(uint32 const diff) + void UpdateAI(uint32 diff) { if (icicleTimer <= diff) { @@ -573,7 +573,7 @@ class npc_snowpacked_icicle : public CreatureScript despawnTimer = 12000; } - void UpdateAI(uint32 const diff) + void UpdateAI(uint32 diff) { if (despawnTimer <= diff) { @@ -611,7 +611,7 @@ class npc_hodir_priest : public CreatureScript events.ScheduleEvent(EVENT_DISPEL_MAGIC, urand(15000, 20000)); } - void UpdateAI(uint32 const diff) + void UpdateAI(uint32 diff) { if (!UpdateVictim() || me->HasUnitState(UNIT_STATE_STUNNED) || me->HasFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_STUNNED)) return; @@ -687,7 +687,7 @@ class npc_hodir_shaman : public CreatureScript events.ScheduleEvent(EVENT_STORM_CLOUD, urand(10000, 12500)); } - void UpdateAI(uint32 const diff) + void UpdateAI(uint32 diff) { if (!UpdateVictim() || me->HasUnitState(UNIT_STATE_STUNNED) || me->HasFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_STUNNED)) return; @@ -749,7 +749,7 @@ class npc_hodir_druid : public CreatureScript events.ScheduleEvent(EVENT_STARLIGHT, urand(15000, 17500)); } - void UpdateAI(uint32 const diff) + void UpdateAI(uint32 diff) { if (!UpdateVictim() || me->HasUnitState(UNIT_STATE_STUNNED) || me->HasFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_STUNNED)) return; @@ -824,7 +824,7 @@ class npc_hodir_mage : public CreatureScript summons.remove(summoned->GetGUID()); } - void UpdateAI(uint32 const diff) + void UpdateAI(uint32 diff) { if (!UpdateVictim() || me->HasUnitState(UNIT_STATE_STUNNED) || me->HasFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_STUNNED)) return; diff --git a/src/server/scripts/Northrend/Ulduar/Ulduar/boss_ignis.cpp b/src/server/scripts/Northrend/Ulduar/Ulduar/boss_ignis.cpp index f525bc874f7..b040a64c75a 100644 --- a/src/server/scripts/Northrend/Ulduar/Ulduar/boss_ignis.cpp +++ b/src/server/scripts/Northrend/Ulduar/Ulduar/boss_ignis.cpp @@ -180,7 +180,7 @@ class boss_ignis : public CreatureScript summons.Summon(summon); } - void DoAction(const int32 action) + void DoAction(int32 action) { if (action != ACTION_REMOVE_BUFF) return; @@ -193,7 +193,7 @@ class boss_ignis : public CreatureScript _firstConstructKill = secondKill; } - void UpdateAI(const uint32 diff) + void UpdateAI(uint32 diff) { if (!UpdateVictim()) return; @@ -319,7 +319,7 @@ class npc_iron_construct : public CreatureScript } } - void UpdateAI(const uint32 /*uiDiff*/) + void UpdateAI(uint32 /*uiDiff*/) { if (!UpdateVictim()) return; @@ -392,7 +392,7 @@ class npc_scorch_ground : public CreatureScript _heatTimer = 0; } - void UpdateAI(const uint32 uiDiff) + void UpdateAI(uint32 uiDiff) { if (_heat) { diff --git a/src/server/scripts/Northrend/Ulduar/Ulduar/boss_kologarn.cpp b/src/server/scripts/Northrend/Ulduar/Ulduar/boss_kologarn.cpp index 24282340278..5e94fc2ee5d 100644 --- a/src/server/scripts/Northrend/Ulduar/Ulduar/boss_kologarn.cpp +++ b/src/server/scripts/Northrend/Ulduar/Ulduar/boss_kologarn.cpp @@ -26,7 +26,7 @@ /* ScriptData SDName: boss_kologarn SD%Complete: 90 -SDComment: TODO: Achievements +SDComment: @todo Achievements SDCategory: Ulduar EndScriptData */ @@ -242,7 +242,7 @@ class boss_kologarn : public CreatureScript } } - void UpdateAI(uint32 const diff) + void UpdateAI(uint32 diff) { if (!UpdateVictim()) return; diff --git a/src/server/scripts/Northrend/Ulduar/Ulduar/boss_razorscale.cpp b/src/server/scripts/Northrend/Ulduar/Ulduar/boss_razorscale.cpp index 79edede01df..ac46fbc1227 100644 --- a/src/server/scripts/Northrend/Ulduar/Ulduar/boss_razorscale.cpp +++ b/src/server/scripts/Northrend/Ulduar/Ulduar/boss_razorscale.cpp @@ -15,7 +15,7 @@ * with this program. If not, see <http://www.gnu.org/licenses/>. */ -//TODO: Harpoon chain from 62505 should not get removed when other chain is applied +/// @todo Harpoon chain from 62505 should not get removed when other chain is applied #include "ScriptMgr.h" #include "ScriptedCreature.h" @@ -224,7 +224,7 @@ class boss_razorscale_controller : public CreatureScript _JustDied(); } - void DoAction(int32 const action) + void DoAction(int32 action) { if (instance->GetBossState(BOSS_RAZORSCALE) != IN_PROGRESS) return; @@ -243,7 +243,7 @@ class boss_razorscale_controller : public CreatureScript } } - void UpdateAI(uint32 const Diff) + void UpdateAI(uint32 Diff) { events.Update(Diff); @@ -394,7 +394,7 @@ class boss_razorscale : public CreatureScript return 0; } - void UpdateAI(uint32 const Diff) + void UpdateAI(uint32 Diff) { if (!UpdateVictim()) return; @@ -562,7 +562,7 @@ class boss_razorscale : public CreatureScript } } - void DoAction(int32 const action) + void DoAction(int32 action) { switch (action) { @@ -625,7 +625,7 @@ class npc_expedition_commander : public CreatureScript summons.push_back(summoned->GetGUID()); } - void DoAction(int32 const action) + void DoAction(int32 action) { switch (action) { @@ -639,7 +639,7 @@ class npc_expedition_commander : public CreatureScript } } - void UpdateAI(uint32 const Diff) + void UpdateAI(uint32 Diff) { if (AttackStartTimer <= Diff) { @@ -739,10 +739,11 @@ class npc_mole_machine_trigger : public CreatureScript public: npc_mole_machine_trigger() : CreatureScript("npc_mole_machine_trigger") { } - struct npc_mole_machine_triggerAI : public Scripted_NoMovementAI + struct npc_mole_machine_triggerAI : public ScriptedAI { - npc_mole_machine_triggerAI(Creature* creature) : Scripted_NoMovementAI(creature) + npc_mole_machine_triggerAI(Creature* creature) : ScriptedAI(creature) { + SetCombatMovement(false); me->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE | UNIT_FLAG_PACIFIED); } @@ -761,7 +762,7 @@ class npc_mole_machine_trigger : public CreatureScript NpcSummoned = false; } - void UpdateAI(uint32 const Diff) + void UpdateAI(uint32 Diff) { if (!GobSummoned && SummonGobTimer <= Diff) { @@ -818,10 +819,11 @@ class npc_devouring_flame : public CreatureScript public: npc_devouring_flame() : CreatureScript("npc_devouring_flame") { } - struct npc_devouring_flameAI : public Scripted_NoMovementAI + struct npc_devouring_flameAI : public ScriptedAI { - npc_devouring_flameAI(Creature* creature) : Scripted_NoMovementAI(creature) + npc_devouring_flameAI(Creature* creature) : ScriptedAI(creature) { + SetCombatMovement(false); me->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE | UNIT_FLAG_PACIFIED); } @@ -855,7 +857,7 @@ class npc_darkrune_watcher : public CreatureScript LightTimer = urand(1000, 3000); } - void UpdateAI(uint32 const Diff) + void UpdateAI(uint32 Diff) { if (!UpdateVictim()) return; @@ -915,7 +917,7 @@ class npc_darkrune_guardian : public CreatureScript } - void UpdateAI(uint32 const Diff) + void UpdateAI(uint32 Diff) { if (!UpdateVictim()) return; @@ -961,7 +963,7 @@ class npc_darkrune_sentinel : public CreatureScript ShoutTimer = urand(15000, 30000); } - void UpdateAI(uint32 const Diff) + void UpdateAI(uint32 Diff) { if (!UpdateVictim()) return; diff --git a/src/server/scripts/Northrend/Ulduar/Ulduar/boss_thorim.cpp b/src/server/scripts/Northrend/Ulduar/Ulduar/boss_thorim.cpp index 564087088d3..89ce6ab2733 100644 --- a/src/server/scripts/Northrend/Ulduar/Ulduar/boss_thorim.cpp +++ b/src/server/scripts/Northrend/Ulduar/Ulduar/boss_thorim.cpp @@ -78,11 +78,11 @@ class boss_thorim : public CreatureScript _EnterCombat(); } - void UpdateAI(uint32 const diff) + void UpdateAI(uint32 diff) { if (!UpdateVictim()) return; - //SPELLS TODO: + //SPELLS @todo // DoMeleeAttackIfReady(); diff --git a/src/server/scripts/Northrend/Ulduar/Ulduar/boss_xt002.cpp b/src/server/scripts/Northrend/Ulduar/Ulduar/boss_xt002.cpp index 43d19d78f8a..76a60607f7e 100644 --- a/src/server/scripts/Northrend/Ulduar/Ulduar/boss_xt002.cpp +++ b/src/server/scripts/Northrend/Ulduar/Ulduar/boss_xt002.cpp @@ -16,7 +16,7 @@ */ /* - TODO: + @todo Fix void zone damage If the boss is to close to a scrap pile -> no summon -- Needs retail confirmation make the life sparks visible... /? Need test @@ -241,7 +241,7 @@ class boss_xt002 : public CreatureScript instance->DoStartTimedAchievement(ACHIEVEMENT_TIMED_TYPE_EVENT, ACHIEV_MUST_DECONSTRUCT_FASTER); } - void DoAction(const int32 action) + void DoAction(int32 action) { switch (action) { @@ -269,7 +269,7 @@ class boss_xt002 : public CreatureScript ExposeHeart(); } - void UpdateAI(const uint32 diff) + void UpdateAI(uint32 diff) { if (!UpdateVictim() || !CheckInRoom()) return; @@ -451,14 +451,15 @@ class mob_xt002_heart : public CreatureScript public: mob_xt002_heart() : CreatureScript("mob_xt002_heart") { } - struct mob_xt002_heartAI : public Scripted_NoMovementAI + struct mob_xt002_heartAI : public ScriptedAI { - mob_xt002_heartAI(Creature* creature) : Scripted_NoMovementAI(creature), + mob_xt002_heartAI(Creature* creature) : ScriptedAI(creature), _instance(creature->GetInstanceScript()) { + SetCombatMovement(false); } - void UpdateAI(uint32 const /*diff*/) { } + void UpdateAI(uint32 /*diff*/) { } void JustDied(Unit* /*killer*/) { @@ -512,7 +513,7 @@ class mob_scrapbot : public CreatureScript me->GetMotionMaster()->MoveFollow(pXT002, 0.0f, 0.0f); } - void UpdateAI(const uint32 diff) + void UpdateAI(uint32 diff) { if (_rangeCheckTimer <= diff) { @@ -573,7 +574,7 @@ class mob_pummeller : public CreatureScript } } - void UpdateAI(const uint32 diff) + void UpdateAI(uint32 diff) { if (!UpdateVictim()) return; @@ -673,7 +674,7 @@ class mob_boombot : public CreatureScript me->SetFloatValue(UNIT_FIELD_MINDAMAGE, 15000.0f); me->SetFloatValue(UNIT_FIELD_MAXDAMAGE, 18000.0f); - // Todo: proper waypoints? + /// @todo proper waypoints? if (Creature* pXT002 = me->GetCreature(*me, _instance->GetData64(BOSS_XT002))) me->GetMotionMaster()->MoveFollow(pXT002, 0.0f, 0.0f); } @@ -703,7 +704,7 @@ class mob_boombot : public CreatureScript } } - void UpdateAI(uint32 const /*diff*/) + void UpdateAI(uint32 /*diff*/) { if (!UpdateVictim()) return; @@ -745,7 +746,7 @@ class mob_life_spark : public CreatureScript _shockTimer = 0; // first one is immediate. } - void UpdateAI(const uint32 diff) + void UpdateAI(uint32 diff) { if (!UpdateVictim()) return; diff --git a/src/server/scripts/Northrend/Ulduar/Ulduar/instance_ulduar.cpp b/src/server/scripts/Northrend/Ulduar/Ulduar/instance_ulduar.cpp index 7934f6fba72..125f66497bf 100644 --- a/src/server/scripts/Northrend/Ulduar/Ulduar/instance_ulduar.cpp +++ b/src/server/scripts/Northrend/Ulduar/Ulduar/instance_ulduar.cpp @@ -565,10 +565,6 @@ class instance_ulduar : public InstanceMapScript } HandleGameObject(KologarnBridgeGUID, false); } - if (state == IN_PROGRESS) - HandleGameObject(KologarnDoorGUID, false); - else - HandleGameObject(KologarnDoorGUID, true); break; case BOSS_HODIR: if (state == DONE) @@ -787,7 +783,7 @@ class instance_ulduar : public InstanceMapScript return 0; } - bool CheckAchievementCriteriaMeet(uint32 criteriaId, Player const* , Unit const* /* = NULL */, uint32 /* = 0 */) + bool CheckAchievementCriteriaMeet(uint32 criteriaId, Player const*, Unit const* /* = NULL */, uint32 /* = 0 */) { switch (criteriaId) { diff --git a/src/server/scripts/Northrend/UtgardeKeep/UtgardeKeep/boss_ingvar_the_plunderer.cpp b/src/server/scripts/Northrend/UtgardeKeep/UtgardeKeep/boss_ingvar_the_plunderer.cpp index 1fd84b6f6ce..215630ac5fa 100644 --- a/src/server/scripts/Northrend/UtgardeKeep/UtgardeKeep/boss_ingvar_the_plunderer.cpp +++ b/src/server/scripts/Northrend/UtgardeKeep/UtgardeKeep/boss_ingvar_the_plunderer.cpp @@ -124,10 +124,10 @@ public: events.Reset(); events.SetPhase(PHASE_HUMAN); - events.ScheduleEvent(EVENT_CLEAVE, urand(6,12)*IN_MILLISECONDS, 0, PHASE_HUMAN); - events.ScheduleEvent(EVENT_STAGGERING_ROAR, urand(18,21)*IN_MILLISECONDS, 0, PHASE_HUMAN); - events.ScheduleEvent(EVENT_ENRAGE, urand(7,14)*IN_MILLISECONDS, 0, PHASE_HUMAN); - events.ScheduleEvent(EVENT_SMASH, urand(12,17)*IN_MILLISECONDS, 0, PHASE_HUMAN); + events.ScheduleEvent(EVENT_CLEAVE, urand(6, 12)*IN_MILLISECONDS, 0, PHASE_HUMAN); + events.ScheduleEvent(EVENT_STAGGERING_ROAR, urand(18, 21)*IN_MILLISECONDS, 0, PHASE_HUMAN); + events.ScheduleEvent(EVENT_ENRAGE, urand(7, 14)*IN_MILLISECONDS, 0, PHASE_HUMAN); + events.ScheduleEvent(EVENT_SMASH, urand(12, 17)*IN_MILLISECONDS, 0, PHASE_HUMAN); if (instance) instance->SetData(DATA_INGVAR_EVENT, NOT_STARTED); @@ -154,7 +154,7 @@ public: Talk(YELL_DEAD_1); } - if (events.GetPhaseMask() & (1 << PHASE_EVENT)) + if (events.IsInPhase(PHASE_EVENT)) damage = 0; } @@ -193,9 +193,9 @@ public: void ScheduleSecondPhase() { events.SetPhase(PHASE_UNDEAD); - events.ScheduleEvent(EVENT_DARK_SMASH, urand(14,18)*IN_MILLISECONDS, 0, PHASE_UNDEAD); - events.ScheduleEvent(EVENT_DREADFUL_ROAR, urand(18,22)*IN_MILLISECONDS, 0, PHASE_UNDEAD); - events.ScheduleEvent(EVENT_WOE_STRIKE, urand(10,14)*IN_MILLISECONDS, 0, PHASE_UNDEAD); + events.ScheduleEvent(EVENT_DARK_SMASH, urand(14, 18)*IN_MILLISECONDS, 0, PHASE_UNDEAD); + events.ScheduleEvent(EVENT_DREADFUL_ROAR, urand(18, 22)*IN_MILLISECONDS, 0, PHASE_UNDEAD); + events.ScheduleEvent(EVENT_WOE_STRIKE, urand(10, 14)*IN_MILLISECONDS, 0, PHASE_UNDEAD); events.ScheduleEvent(EVENT_SHADOW_AXE, 30*IN_MILLISECONDS, 0, PHASE_UNDEAD); } @@ -204,9 +204,9 @@ public: Talk(bIsUndead ? YELL_KILL_1 : YELL_KILL_2); } - void UpdateAI(const uint32 diff) + void UpdateAI(uint32 diff) { - if (!UpdateVictim() && !(events.GetPhaseMask() & (1 << PHASE_EVENT))) + if (!UpdateVictim() && !events.IsInPhase(PHASE_EVENT)) return; events.Update(diff); @@ -221,19 +221,19 @@ public: // PHASE ONE case EVENT_CLEAVE: DoCastVictim(SPELL_CLEAVE); - events.ScheduleEvent(EVENT_CLEAVE, urand(6,12)*IN_MILLISECONDS, 0, PHASE_HUMAN); + events.ScheduleEvent(EVENT_CLEAVE, urand(6, 12)*IN_MILLISECONDS, 0, PHASE_HUMAN); break; case EVENT_STAGGERING_ROAR: DoCast(me, SPELL_STAGGERING_ROAR); - events.ScheduleEvent(EVENT_STAGGERING_ROAR, urand(18,22)*IN_MILLISECONDS, 0, PHASE_HUMAN); + events.ScheduleEvent(EVENT_STAGGERING_ROAR, urand(18, 22)*IN_MILLISECONDS, 0, PHASE_HUMAN); break; case EVENT_ENRAGE: DoCast(me, SPELL_ENRAGE); - events.ScheduleEvent(EVENT_ENRAGE, urand(7,14)*IN_MILLISECONDS, 0, PHASE_HUMAN); + events.ScheduleEvent(EVENT_ENRAGE, urand(7, 14)*IN_MILLISECONDS, 0, PHASE_HUMAN); break; case EVENT_SMASH: DoCastAOE(SPELL_SMASH); - events.ScheduleEvent(EVENT_SMASH, urand(12,16)*IN_MILLISECONDS, 0, PHASE_HUMAN); + events.ScheduleEvent(EVENT_SMASH, urand(12, 16)*IN_MILLISECONDS, 0, PHASE_HUMAN); break; case EVENT_JUST_TRANSFORMED: me->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE); @@ -247,15 +247,15 @@ public: // PHASE TWO case EVENT_DARK_SMASH: DoCastVictim(SPELL_DARK_SMASH); - events.ScheduleEvent(EVENT_DARK_SMASH, urand(12,16)*IN_MILLISECONDS, 0, PHASE_UNDEAD); + events.ScheduleEvent(EVENT_DARK_SMASH, urand(12, 16)*IN_MILLISECONDS, 0, PHASE_UNDEAD); break; case EVENT_DREADFUL_ROAR: DoCast(me, SPELL_DREADFUL_ROAR); - events.ScheduleEvent(EVENT_DREADFUL_ROAR, urand(18,22)*IN_MILLISECONDS, 0, PHASE_UNDEAD); + events.ScheduleEvent(EVENT_DREADFUL_ROAR, urand(18, 22)*IN_MILLISECONDS, 0, PHASE_UNDEAD); break; case EVENT_WOE_STRIKE: DoCastVictim(SPELL_WOE_STRIKE); - events.ScheduleEvent(EVENT_WOE_STRIKE, urand(10,14)*IN_MILLISECONDS, 0, PHASE_UNDEAD); + events.ScheduleEvent(EVENT_WOE_STRIKE, urand(10, 14)*IN_MILLISECONDS, 0, PHASE_UNDEAD); break; case EVENT_SHADOW_AXE: if (Unit* target = SelectTarget(SELECT_TARGET_TOPAGGRO, 1)) @@ -358,7 +358,7 @@ public: void AttackStart(Unit* /*who*/) {} void MoveInLineOfSight(Unit* /*who*/) {} void EnterCombat(Unit* /*who*/) {} - void UpdateAI(const uint32 diff) + void UpdateAI(uint32 diff) { if (uiResurectTimer) { diff --git a/src/server/scripts/Northrend/UtgardeKeep/UtgardeKeep/boss_keleseth.cpp b/src/server/scripts/Northrend/UtgardeKeep/UtgardeKeep/boss_keleseth.cpp index d709182bf04..896421909ad 100644 --- a/src/server/scripts/Northrend/UtgardeKeep/UtgardeKeep/boss_keleseth.cpp +++ b/src/server/scripts/Northrend/UtgardeKeep/UtgardeKeep/boss_keleseth.cpp @@ -94,7 +94,7 @@ public: instance = creature->GetInstanceScript(); } - void UpdateAI(const uint32 /*diff*/) {} + void UpdateAI(uint32 /*diff*/) {} void JustDied(Unit* /*killer*/) { @@ -129,8 +129,8 @@ public: instance->SetData(DATA_PRINCEKELESETH_EVENT, NOT_STARTED); events.Reset(); - events.ScheduleEvent(EVENT_SHADOWBOLT, urand(2,3)*IN_MILLISECONDS); - events.ScheduleEvent(EVENT_FROST_TOMB, urand(14,19)*IN_MILLISECONDS); + events.ScheduleEvent(EVENT_SHADOWBOLT, urand(2, 3)*IN_MILLISECONDS); + events.ScheduleEvent(EVENT_FROST_TOMB, urand(14, 19)*IN_MILLISECONDS); events.ScheduleEvent(EVENT_SUMMON_SKELETONS, 6*IN_MILLISECONDS); summons.DespawnAll(); @@ -193,7 +193,7 @@ public: return 0; } - void UpdateAI(uint32 const diff) + void UpdateAI(uint32 diff) { if (!UpdateVictim()) return; @@ -213,7 +213,7 @@ public: break; case EVENT_SHADOWBOLT: DoCastVictim(SPELL_SHADOWBOLT); - events.ScheduleEvent(EVENT_SHADOWBOLT, urand(2,3)*IN_MILLISECONDS); + events.ScheduleEvent(EVENT_SHADOWBOLT, urand(2, 3)*IN_MILLISECONDS); break; case EVENT_FROST_TOMB: if (Unit* target = SelectTarget(SELECT_TARGET_RANDOM, 0, 100, true, -SPELL_FROST_TOMB)) @@ -225,7 +225,7 @@ public: // checked from sniffs - the player casts the spell target->CastSpell(target, SPELL_FROST_TOMB_SUMMON, true); } - events.ScheduleEvent(EVENT_FROST_TOMB, urand(14,19)*IN_MILLISECONDS); + events.ScheduleEvent(EVENT_FROST_TOMB, urand(14, 19)*IN_MILLISECONDS); break; } } @@ -261,7 +261,7 @@ public: void Reset() { events.Reset(); - events.ScheduleEvent(EVENT_DECREPIFY, urand(4,6)*IN_MILLISECONDS); + events.ScheduleEvent(EVENT_DECREPIFY, urand(4, 6)*IN_MILLISECONDS); } @@ -280,7 +280,7 @@ public: me->SetFlag(UNIT_FIELD_BYTES_1, UNIT_STAND_STATE_DEAD); events.Reset(); - events.ScheduleEvent(EVENT_RESURRECT, urand(18,22)*IN_MILLISECONDS); + events.ScheduleEvent(EVENT_RESURRECT, urand(18, 22)*IN_MILLISECONDS); me->GetMotionMaster()->MovementExpired(false); me->GetMotionMaster()->MoveIdle(); @@ -288,7 +288,7 @@ public: } } - void UpdateAI(const uint32 diff) + void UpdateAI(uint32 diff) { if (!UpdateVictim()) return; @@ -304,7 +304,7 @@ public: { case EVENT_DECREPIFY: DoCast(SelectTarget(SELECT_TARGET_RANDOM, 0, 0.0f, true, -SPELL_DECREPIFY), SPELL_DECREPIFY); - events.ScheduleEvent(EVENT_DECREPIFY, urand(1,5)*IN_MILLISECONDS); + events.ScheduleEvent(EVENT_DECREPIFY, urand(1, 5)*IN_MILLISECONDS); break; case EVENT_RESURRECT: events.ScheduleEvent(EVENT_FULL_HEAL, 1*IN_MILLISECONDS); @@ -325,7 +325,7 @@ public: me->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE); me->RemoveFlag(UNIT_FIELD_BYTES_1, UNIT_STAND_STATE_DEAD); me->GetMotionMaster()->MoveChase(me->getVictim()); - events.ScheduleEvent(EVENT_DECREPIFY, urand(4,6)*IN_MILLISECONDS); + events.ScheduleEvent(EVENT_DECREPIFY, urand(4, 6)*IN_MILLISECONDS); break; } } diff --git a/src/server/scripts/Northrend/UtgardeKeep/UtgardeKeep/boss_skarvald_dalronn.cpp b/src/server/scripts/Northrend/UtgardeKeep/UtgardeKeep/boss_skarvald_dalronn.cpp index 05822aa2595..ef7ad659a24 100644 --- a/src/server/scripts/Northrend/UtgardeKeep/UtgardeKeep/boss_skarvald_dalronn.cpp +++ b/src/server/scripts/Northrend/UtgardeKeep/UtgardeKeep/boss_skarvald_dalronn.cpp @@ -180,7 +180,7 @@ public: } } - void UpdateAI(const uint32 diff) + void UpdateAI(uint32 diff) { if (ghost) { @@ -340,7 +340,7 @@ public: } } - void UpdateAI(const uint32 diff) + void UpdateAI(uint32 diff) { if (ghost) { diff --git a/src/server/scripts/Northrend/UtgardeKeep/UtgardeKeep/utgarde_keep.cpp b/src/server/scripts/Northrend/UtgardeKeep/UtgardeKeep/utgarde_keep.cpp index 7103095b252..4f7f0e844bb 100644 --- a/src/server/scripts/Northrend/UtgardeKeep/UtgardeKeep/utgarde_keep.cpp +++ b/src/server/scripts/Northrend/UtgardeKeep/UtgardeKeep/utgarde_keep.cpp @@ -146,7 +146,7 @@ public: return near_f > 0 && near_f < 4 ? near_f : 0; } - void UpdateAI(uint32 const /* diff */) + void UpdateAI(uint32 /* diff */) { if (fm_Type == 0) fm_Type = GetForgeMasterType(); @@ -291,7 +291,7 @@ public: } } - void UpdateAI(uint32 const diff) + void UpdateAI(uint32 diff) { if (!UpdateVictim()) return; diff --git a/src/server/scripts/Northrend/UtgardeKeep/UtgardePinnacle/boss_palehoof.cpp b/src/server/scripts/Northrend/UtgardeKeep/UtgardePinnacle/boss_palehoof.cpp index 36506227287..2b1d850ab25 100644 --- a/src/server/scripts/Northrend/UtgardeKeep/UtgardePinnacle/boss_palehoof.cpp +++ b/src/server/scripts/Northrend/UtgardeKeep/UtgardePinnacle/boss_palehoof.cpp @@ -174,7 +174,7 @@ public: } } - void UpdateAI(const uint32 diff) + void UpdateAI(uint32 diff) { if (currentPhase != PHASE_GORTOK_PALEHOOF) return; @@ -325,7 +325,7 @@ public: } } - void UpdateAI(const uint32 diff) + void UpdateAI(uint32 diff) { //Return since we have no target if (!UpdateVictim()) @@ -438,7 +438,7 @@ public: } } - void UpdateAI(const uint32 diff) + void UpdateAI(uint32 diff) { //Return since we have no target if (!UpdateVictim()) @@ -554,7 +554,7 @@ public: } } - void UpdateAI(const uint32 diff) + void UpdateAI(uint32 diff) { //Return since we have no target if (!UpdateVictim()) @@ -674,7 +674,7 @@ public: } } - void UpdateAI(const uint32 diff) + void UpdateAI(uint32 diff) { //Return since we have no target if (!UpdateVictim()) @@ -771,7 +771,7 @@ public: me->SetSpeed(MOVE_FLIGHT, 0.5f); } - void UpdateAI(const uint32 diff) + void UpdateAI(uint32 diff) { if (currentPhase == PHASE_NONE) return; diff --git a/src/server/scripts/Northrend/UtgardeKeep/UtgardePinnacle/boss_skadi.cpp b/src/server/scripts/Northrend/UtgardeKeep/UtgardePinnacle/boss_skadi.cpp index 2514cb3de78..3a74eebd947 100644 --- a/src/server/scripts/Northrend/UtgardeKeep/UtgardePinnacle/boss_skadi.cpp +++ b/src/server/scripts/Northrend/UtgardeKeep/UtgardePinnacle/boss_skadi.cpp @@ -303,7 +303,7 @@ public: } } - void UpdateAI(const uint32 diff) + void UpdateAI(uint32 diff) { switch (Phase) { diff --git a/src/server/scripts/Northrend/UtgardeKeep/UtgardePinnacle/boss_svala.cpp b/src/server/scripts/Northrend/UtgardeKeep/UtgardePinnacle/boss_svala.cpp index 9468a111db5..f2090f6a2e6 100644 --- a/src/server/scripts/Northrend/UtgardeKeep/UtgardePinnacle/boss_svala.cpp +++ b/src/server/scripts/Northrend/UtgardeKeep/UtgardePinnacle/boss_svala.cpp @@ -101,8 +101,8 @@ enum SvalaPhase static const float spectatorWP[2][3] = { - {296.95f,-312.76f,86.36f}, - {297.69f,-275.81f,86.36f} + {296.95f, -312.76f, 86.36f}, + {297.69f, -275.81f, 86.36f} }; static Position ArthasPos = { 295.81f, -366.16f, 92.57f, 1.58f }; @@ -250,7 +250,7 @@ public: } } - void UpdateAI(const uint32 diff) + void UpdateAI(uint32 diff) { if (Phase == IDLE) return; @@ -459,11 +459,13 @@ public: return new npc_ritual_channelerAI(creature); } - struct npc_ritual_channelerAI : public Scripted_NoMovementAI + struct npc_ritual_channelerAI : public ScriptedAI { - npc_ritual_channelerAI(Creature* creature) :Scripted_NoMovementAI(creature) + npc_ritual_channelerAI(Creature* creature) :ScriptedAI(creature) { instance = creature->GetInstanceScript(); + + SetCombatMovement(false); } InstanceScript* instance; @@ -477,7 +479,7 @@ public: DoCast(me, SPELL_SHADOWS_IN_THE_DARK); } - void UpdateAI(const uint32 diff) + void UpdateAI(uint32 diff) { if (me->HasUnitState(UNIT_STATE_CASTING)) return; @@ -517,7 +519,7 @@ public: if (motionType == POINT_MOTION_TYPE) { if (pointId == 1) - me->GetMotionMaster()->MovePoint(2,spectatorWP[1][0],spectatorWP[1][1],spectatorWP[1][2]); + me->GetMotionMaster()->MovePoint(2, spectatorWP[1][0], spectatorWP[1][1], spectatorWP[1][2]); else if (pointId == 2) me->DespawnOrUnsummon(1000); } @@ -599,7 +601,7 @@ class npc_scourge_hulk : public CreatureScript killedByRitualStrike = true; } - void UpdateAI(uint32 const diff) + void UpdateAI(uint32 diff) { if (!UpdateVictim()) return; diff --git a/src/server/scripts/Northrend/UtgardeKeep/UtgardePinnacle/boss_ymiron.cpp b/src/server/scripts/Northrend/UtgardeKeep/UtgardePinnacle/boss_ymiron.cpp index 99d987e63a4..f4c65216f4a 100644 --- a/src/server/scripts/Northrend/UtgardeKeep/UtgardePinnacle/boss_ymiron.cpp +++ b/src/server/scripts/Northrend/UtgardeKeep/UtgardePinnacle/boss_ymiron.cpp @@ -207,7 +207,7 @@ public: return 0; } - void UpdateAI(const uint32 diff) + void UpdateAI(uint32 diff) { if (m_bIsWalking) { diff --git a/src/server/scripts/Northrend/VaultOfArchavon/boss_archavon.cpp b/src/server/scripts/Northrend/VaultOfArchavon/boss_archavon.cpp index 33e0619c7e5..a4ea8649ff9 100644 --- a/src/server/scripts/Northrend/VaultOfArchavon/boss_archavon.cpp +++ b/src/server/scripts/Northrend/VaultOfArchavon/boss_archavon.cpp @@ -76,7 +76,7 @@ class boss_archavon : public CreatureScript } // Below UpdateAI may need review/debug. - void UpdateAI(const uint32 diff) + void UpdateAI(uint32 diff) { if (!UpdateVictim()) return; @@ -156,7 +156,7 @@ class mob_archavon_warder : public CreatureScript DoZoneInCombat(); } - void UpdateAI(const uint32 diff) + void UpdateAI(uint32 diff) { if (!UpdateVictim()) return; diff --git a/src/server/scripts/Northrend/VaultOfArchavon/boss_emalon.cpp b/src/server/scripts/Northrend/VaultOfArchavon/boss_emalon.cpp index b8b6acce54d..baed96453dc 100644 --- a/src/server/scripts/Northrend/VaultOfArchavon/boss_emalon.cpp +++ b/src/server/scripts/Northrend/VaultOfArchavon/boss_emalon.cpp @@ -115,7 +115,7 @@ class boss_emalon : public CreatureScript _EnterCombat(); } - void UpdateAI(const uint32 diff) + void UpdateAI(uint32 diff) { if (!UpdateVictim()) return; @@ -215,7 +215,7 @@ class mob_tempest_minion : public CreatureScript } } - void UpdateAI(const uint32 diff) + void UpdateAI(uint32 diff) { //Return since we have no target if (!UpdateVictim()) diff --git a/src/server/scripts/Northrend/VaultOfArchavon/boss_koralon.cpp b/src/server/scripts/Northrend/VaultOfArchavon/boss_koralon.cpp index fafeba6a570..d6db736b82c 100644 --- a/src/server/scripts/Northrend/VaultOfArchavon/boss_koralon.cpp +++ b/src/server/scripts/Northrend/VaultOfArchavon/boss_koralon.cpp @@ -65,15 +65,15 @@ class boss_koralon : public CreatureScript { DoCast(me, SPELL_BURNING_FURY); - events.ScheduleEvent(EVENT_BURNING_FURY, 20000); // TODO check timer + events.ScheduleEvent(EVENT_BURNING_FURY, 20000); /// @todo check timer events.ScheduleEvent(EVENT_BURNING_BREATH, 15000); // 1st after 15sec, then every 45sec events.ScheduleEvent(EVENT_METEOR_FISTS_A, 75000); // 1st after 75sec, then every 45sec - events.ScheduleEvent(EVENT_FLAME_CINDER_A, 30000); // TODO check timer + events.ScheduleEvent(EVENT_FLAME_CINDER_A, 30000); /// @todo check timer _EnterCombat(); } - void UpdateAI(const uint32 diff) + void UpdateAI(uint32 diff) { if (!UpdateVictim()) return; @@ -149,7 +149,7 @@ class mob_flame_warder : public CreatureScript events.ScheduleEvent(EVENT_FW_METEOR_FISTS_A, 10000); } - void UpdateAI(const uint32 diff) + void UpdateAI(uint32 diff) { if (!UpdateVictim()) return; diff --git a/src/server/scripts/Northrend/VaultOfArchavon/boss_toravon.cpp b/src/server/scripts/Northrend/VaultOfArchavon/boss_toravon.cpp index 613b8ebf8dc..3068049e322 100644 --- a/src/server/scripts/Northrend/VaultOfArchavon/boss_toravon.cpp +++ b/src/server/scripts/Northrend/VaultOfArchavon/boss_toravon.cpp @@ -74,7 +74,7 @@ class boss_toravon : public CreatureScript _EnterCombat(); } - void UpdateAI(const uint32 diff) + void UpdateAI(uint32 diff) { if (!UpdateVictim()) return; @@ -142,7 +142,7 @@ class mob_frost_warder : public CreatureScript events.ScheduleEvent(EVENT_FROST_BLAST, 5000); } - void UpdateAI(const uint32 diff) + void UpdateAI(uint32 diff) { if (!UpdateVictim()) return; @@ -196,7 +196,7 @@ public: DoZoneInCombat(); } - void UpdateAI(const uint32 diff) + void UpdateAI(uint32 diff) { if (!done) { @@ -234,9 +234,9 @@ class mob_frozen_orb_stalker : public CreatureScript public: mob_frozen_orb_stalker() : CreatureScript("mob_frozen_orb_stalker") { } - struct mob_frozen_orb_stalkerAI : public Scripted_NoMovementAI + struct mob_frozen_orb_stalkerAI : public ScriptedAI { - mob_frozen_orb_stalkerAI(Creature* creature) : Scripted_NoMovementAI(creature) + mob_frozen_orb_stalkerAI(Creature* creature) : ScriptedAI(creature) { creature->SetVisible(false); creature->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE|UNIT_FLAG_NON_ATTACKABLE|UNIT_FLAG_DISABLE_MOVE); @@ -244,9 +244,11 @@ class mob_frozen_orb_stalker : public CreatureScript instance = creature->GetInstanceScript(); spawned = false; + + SetCombatMovement(false); } - void UpdateAI(const uint32 /*diff*/) + void UpdateAI(uint32 /*diff*/) { if (spawned) return; diff --git a/src/server/scripts/Northrend/VioletHold/boss_cyanigosa.cpp b/src/server/scripts/Northrend/VioletHold/boss_cyanigosa.cpp index 1f12685a4b0..d524e3fb708 100644 --- a/src/server/scripts/Northrend/VioletHold/boss_cyanigosa.cpp +++ b/src/server/scripts/Northrend/VioletHold/boss_cyanigosa.cpp @@ -89,7 +89,7 @@ public: void MoveInLineOfSight(Unit* /*who*/) {} - void UpdateAI(const uint32 diff) + void UpdateAI(uint32 diff) { if (instance && instance->GetData(DATA_REMOVE_NPC) == 1) { diff --git a/src/server/scripts/Northrend/VioletHold/boss_erekem.cpp b/src/server/scripts/Northrend/VioletHold/boss_erekem.cpp index 6c16bb98ff1..9dbb10be601 100644 --- a/src/server/scripts/Northrend/VioletHold/boss_erekem.cpp +++ b/src/server/scripts/Northrend/VioletHold/boss_erekem.cpp @@ -144,7 +144,7 @@ public: void MoveInLineOfSight(Unit* /*who*/) {} - void UpdateAI(const uint32 diff) + void UpdateAI(uint32 diff) { //Return since we have no target if (!UpdateVictim()) @@ -303,7 +303,7 @@ public: void MoveInLineOfSight(Unit* /*who*/) {} - void UpdateAI(const uint32 diff) + void UpdateAI(uint32 diff) { if (!UpdateVictim()) return; diff --git a/src/server/scripts/Northrend/VioletHold/boss_ichoron.cpp b/src/server/scripts/Northrend/VioletHold/boss_ichoron.cpp index fb4297f595f..cfb3c03b12c 100644 --- a/src/server/scripts/Northrend/VioletHold/boss_ichoron.cpp +++ b/src/server/scripts/Northrend/VioletHold/boss_ichoron.cpp @@ -55,7 +55,7 @@ enum Actions ACTION_WATER_ELEMENT_KILLED = 2, }; -// TODO get those positions from spawn of creature 29326 +/// @todo get those positions from spawn of creature 29326 #define MAX_SPAWN_LOC 5 static Position SpawnLoc[MAX_SPAWN_LOC]= { @@ -151,7 +151,7 @@ public: } } - void DoAction(const int32 param) + void DoAction(int32 param) { if (!me->isAlive()) return; @@ -205,7 +205,7 @@ public: void MoveInLineOfSight(Unit* /*who*/) {} - void UpdateAI(const uint32 uiDiff) + void UpdateAI(uint32 uiDiff) { if (!UpdateVictim()) return; @@ -362,7 +362,7 @@ public: return; } - void UpdateAI(const uint32 uiDiff) + void UpdateAI(uint32 uiDiff) { if (uiRangeCheck_Timer < uiDiff) { diff --git a/src/server/scripts/Northrend/VioletHold/boss_lavanthor.cpp b/src/server/scripts/Northrend/VioletHold/boss_lavanthor.cpp index dc0b320b307..187cf5d6b30 100644 --- a/src/server/scripts/Northrend/VioletHold/boss_lavanthor.cpp +++ b/src/server/scripts/Northrend/VioletHold/boss_lavanthor.cpp @@ -102,7 +102,7 @@ public: void MoveInLineOfSight(Unit* /*who*/) {} - void UpdateAI(const uint32 diff) + void UpdateAI(uint32 diff) { //Return since we have no target if (!UpdateVictim()) diff --git a/src/server/scripts/Northrend/VioletHold/boss_moragg.cpp b/src/server/scripts/Northrend/VioletHold/boss_moragg.cpp index d40f3b14f87..d308c6c696b 100644 --- a/src/server/scripts/Northrend/VioletHold/boss_moragg.cpp +++ b/src/server/scripts/Northrend/VioletHold/boss_moragg.cpp @@ -95,7 +95,7 @@ public: void MoveInLineOfSight(Unit* /*who*/) {} - void UpdateAI(const uint32 diff) + void UpdateAI(uint32 diff) { //Return since we have no target if (!UpdateVictim()) diff --git a/src/server/scripts/Northrend/VioletHold/boss_xevozz.cpp b/src/server/scripts/Northrend/VioletHold/boss_xevozz.cpp index 92ced3c702f..b14a9e0dec5 100644 --- a/src/server/scripts/Northrend/VioletHold/boss_xevozz.cpp +++ b/src/server/scripts/Northrend/VioletHold/boss_xevozz.cpp @@ -28,7 +28,7 @@ enum Spells SPELL_ARCANE_BUFFET_H = 59485, SPELL_SUMMON_ETHEREAL_SPHERE_1 = 54102, SPELL_SUMMON_ETHEREAL_SPHERE_2 = 54137, - SPELL_SUMMON_ETHEREAL_SPHERE_3 = 54138, + SPELL_SUMMON_ETHEREAL_SPHERE_3 = 54138 }; enum NPCs @@ -42,7 +42,7 @@ enum CreatureSpells SPELL_ARCANE_POWER = 54160, H_SPELL_ARCANE_POWER = 59474, SPELL_SUMMON_PLAYERS = 54164, - SPELL_POWER_BALL_VISUAL = 54141, + SPELL_POWER_BALL_VISUAL = 54141 }; enum Yells @@ -154,7 +154,7 @@ public: void MoveInLineOfSight(Unit* /*who*/) {} - void UpdateAI(const uint32 uiDiff) + void UpdateAI(uint32 uiDiff) { //Return since we have no target if (!UpdateVictim()) @@ -251,7 +251,7 @@ public: uiRangeCheck_Timer = 1000; } - void UpdateAI(const uint32 uiDiff) + void UpdateAI(uint32 uiDiff) { //Return since we have no target if (!UpdateVictim()) diff --git a/src/server/scripts/Northrend/VioletHold/boss_zuramat.cpp b/src/server/scripts/Northrend/VioletHold/boss_zuramat.cpp index cf0ee82c01c..0f150fe88b8 100644 --- a/src/server/scripts/Northrend/VioletHold/boss_zuramat.cpp +++ b/src/server/scripts/Northrend/VioletHold/boss_zuramat.cpp @@ -122,7 +122,7 @@ public: void MoveInLineOfSight(Unit* /*who*/) {} - void UpdateAI(const uint32 diff) + void UpdateAI(uint32 diff) { //Return since we have no target if (!UpdateVictim()) diff --git a/src/server/scripts/Northrend/VioletHold/instance_violet_hold.cpp b/src/server/scripts/Northrend/VioletHold/instance_violet_hold.cpp index 11887e732ed..df79366e6cd 100644 --- a/src/server/scripts/Northrend/VioletHold/instance_violet_hold.cpp +++ b/src/server/scripts/Northrend/VioletHold/instance_violet_hold.cpp @@ -792,7 +792,7 @@ public: void ActivateCrystal() { // Kill all mobs registered with SetData64(ADD_TRASH_MOB) - // TODO: All visual, spells etc + /// @todo All visual, spells etc for (std::set<uint64>::const_iterator itr = trashMobs.begin(); itr != trashMobs.end(); ++itr) { Creature* creature = instance->GetCreature(*itr); diff --git a/src/server/scripts/Northrend/VioletHold/violet_hold.cpp b/src/server/scripts/Northrend/VioletHold/violet_hold.cpp index 5ebc2eaf973..fbbf3fa3df5 100644 --- a/src/server/scripts/Northrend/VioletHold/violet_hold.cpp +++ b/src/server/scripts/Northrend/VioletHold/violet_hold.cpp @@ -342,7 +342,7 @@ public: } } - void UpdateAI(const uint32 uiDiff) + void UpdateAI(uint32 uiDiff) { ScriptedAI::UpdateAI(uiDiff); @@ -481,7 +481,7 @@ public: } } - void UpdateAI(const uint32 diff) + void UpdateAI(uint32 diff) { if (instance && instance->GetData(DATA_MAIN_EVENT_PHASE) != IN_PROGRESS) me->CastStop(); @@ -578,7 +578,7 @@ public: void MoveInLineOfSight(Unit* /*who*/) {} - void UpdateAI(const uint32 diff) + void UpdateAI(uint32 diff) { if (!instance) //Massive usage of instance, global check return; @@ -724,7 +724,7 @@ struct violet_hold_trashAI : public npc_escortAI } } - void UpdateAI(const uint32) + void UpdateAI(uint32) { if (instance && instance->GetData(DATA_MAIN_EVENT_PHASE) != IN_PROGRESS) me->CastStop(); @@ -832,7 +832,7 @@ public: uiSunderArmorTimer = 4000; } - void UpdateAI(const uint32 diff) + void UpdateAI(uint32 diff) { violet_hold_trashAI::UpdateAI(diff); npc_escortAI::UpdateAI(diff); @@ -910,7 +910,7 @@ public: uiFrostboltTimer = 4000; } - void UpdateAI(const uint32 diff) + void UpdateAI(uint32 diff) { violet_hold_trashAI::UpdateAI(diff); npc_escortAI::UpdateAI(diff); @@ -984,7 +984,7 @@ public: uiSpellLockTimer = 5000; } - void UpdateAI(const uint32 diff) + void UpdateAI(uint32 diff) { violet_hold_trashAI::UpdateAI(diff); npc_escortAI::UpdateAI(diff); @@ -1044,7 +1044,7 @@ public: uiMagicReflectionTimer = 8000; } - void UpdateAI(const uint32 diff) + void UpdateAI(uint32 diff) { violet_hold_trashAI::UpdateAI(diff); npc_escortAI::UpdateAI(diff); @@ -1097,7 +1097,7 @@ public: TacticalBlinkCasted =false; } - void UpdateAI(const uint32 diff) + void UpdateAI(uint32 diff) { violet_hold_trashAI::UpdateAI(diff); npc_escortAI::UpdateAI(diff); @@ -1159,7 +1159,7 @@ public: uiConeOfColdTimer = 4000; } - void UpdateAI(const uint32 diff) + void UpdateAI(uint32 diff) { violet_hold_trashAI::UpdateAI(diff); npc_escortAI::UpdateAI(diff); @@ -1239,7 +1239,7 @@ public: uiWhirlwindTimer = 8000; } - void UpdateAI(const uint32 diff) + void UpdateAI(uint32 diff) { violet_hold_trashAI::UpdateAI(diff); npc_escortAI::UpdateAI(diff); @@ -1293,7 +1293,7 @@ public: uiManaDetonationTimer = 5000; } - void UpdateAI(const uint32 diff) + void UpdateAI(uint32 diff) { violet_hold_trashAI::UpdateAI(diff); npc_escortAI::UpdateAI(diff); diff --git a/src/server/scripts/Northrend/zone_borean_tundra.cpp b/src/server/scripts/Northrend/zone_borean_tundra.cpp index 8e7507bce61..fef900e1dfd 100644 --- a/src/server/scripts/Northrend/zone_borean_tundra.cpp +++ b/src/server/scripts/Northrend/zone_borean_tundra.cpp @@ -92,7 +92,7 @@ public: void EnterCombat(Unit* /*who*/){} - void UpdateAI(const uint32 diff) + void UpdateAI(uint32 diff) { if (!phase) return; @@ -436,7 +436,7 @@ public: DoCast(me, SPELL_DROP_CRATE, true); } - void UpdateAI(const uint32 /*diff*/) + void UpdateAI(uint32 /*diff*/) { if (setCrateNumber) { @@ -576,7 +576,7 @@ public: go_caribou->SetGoState(GO_STATE_READY); } - void UpdateAI(const uint32 diff) + void UpdateAI(uint32 diff) { if (phaseTimer <= diff) { @@ -701,7 +701,7 @@ public: } } - void UpdateAI(const uint32 diff) + void UpdateAI(uint32 diff) { if (IntroPhase) { @@ -867,7 +867,7 @@ public: } } - void UpdateAI(const uint32 /*diff*/) + void UpdateAI(uint32 /*diff*/) { if (WithRedDragonBlood && HarpoonerGUID && !me->HasAura(SPELL_RED_DRAGONBLOOD)) { @@ -1017,7 +1017,7 @@ public: } } - void UpdateAI(const uint32 uiDiff) + void UpdateAI(uint32 uiDiff) { npc_escortAI::UpdateAI(uiDiff); @@ -1360,7 +1360,7 @@ public: CAST_AI(npc_thassarian::npc_thassarianAI, CAST_CRE(summoner)->AI())->talbotInPosition = true; } - void UpdateAI(const uint32 uiDiff) + void UpdateAI(uint32 uiDiff) { if (bCheck) { @@ -1482,7 +1482,7 @@ public: } } - void UpdateAI(const uint32 uiDiff) + void UpdateAI(uint32 uiDiff) { ScriptedAI::UpdateAI(uiDiff); @@ -1622,7 +1622,7 @@ public: } } - void UpdateAI(const uint32 /*uiDiff*/) + void UpdateAI(uint32 /*uiDiff*/) { if (!UpdateVictim()) return; @@ -1674,7 +1674,7 @@ public: rebuff = 0; } - void UpdateAI(const uint32 diff) + void UpdateAI(uint32 diff) { UpdateVictim(); @@ -1990,7 +1990,7 @@ public: } } - void UpdateAI(const uint32 diff) + void UpdateAI(uint32 diff) { if (bStarted) { @@ -2005,7 +2005,7 @@ public: } } - void DoAction(const int32 param) + void DoAction(int32 param) { if (param == 1) bStarted = true; @@ -2105,7 +2105,7 @@ public: uiExplosionTimer = urand(5000, 10000); } - void UpdateAI(const uint32 diff) + void UpdateAI(uint32 diff) { if (uiExplosionTimer < diff) { @@ -2160,7 +2160,7 @@ public: uiTimer = urand(13000, 18000); } - void UpdateAI(const uint32 diff) + void UpdateAI(uint32 diff) { if (uiTimer <= diff) { @@ -2207,9 +2207,9 @@ class npc_warmage_coldarra : public CreatureScript public: npc_warmage_coldarra() : CreatureScript("npc_warmage_coldarra") { } - struct npc_warmage_coldarraAI : public Scripted_NoMovementAI + struct npc_warmage_coldarraAI : public ScriptedAI { - npc_warmage_coldarraAI(Creature* creature) : Scripted_NoMovementAI(creature){} + npc_warmage_coldarraAI(Creature* creature) : ScriptedAI(creature) {} uint32 m_uiTimer; //Timer until recast @@ -2222,7 +2222,7 @@ public: void AttackStart(Unit* /*who*/) {} - void UpdateAI(const uint32 uiDiff) + void UpdateAI(uint32 uiDiff) { if (m_uiTimer <= uiDiff) { @@ -2358,7 +2358,7 @@ public: me->RestoreFaction(); } - void DoAction(const int32 /*iParam*/) + void DoAction(int32 /*iParam*/) { me->StopMoving(); me->SetUInt32Value(UNIT_NPC_FLAGS, 0); @@ -2383,7 +2383,7 @@ public: me->AI()->AttackStart(player); } - void UpdateAI(const uint32 uiDiff) + void UpdateAI(uint32 uiDiff) { if (uiEventTimer && uiEventTimer <= uiDiff) { diff --git a/src/server/scripts/Northrend/zone_crystalsong_forest.cpp b/src/server/scripts/Northrend/zone_crystalsong_forest.cpp index d12b5176b15..d05e442b0f4 100644 --- a/src/server/scripts/Northrend/zone_crystalsong_forest.cpp +++ b/src/server/scripts/Northrend/zone_crystalsong_forest.cpp @@ -49,9 +49,12 @@ class npc_warmage_violetstand : public CreatureScript public: npc_warmage_violetstand() : CreatureScript("npc_warmage_violetstand") { } - struct npc_warmage_violetstandAI : public Scripted_NoMovementAI + struct npc_warmage_violetstandAI : public ScriptedAI { - npc_warmage_violetstandAI(Creature* creature) : Scripted_NoMovementAI(creature){} + npc_warmage_violetstandAI(Creature* creature) : ScriptedAI(creature) + { + SetCombatMovement(false); + } uint64 uiTargetGUID; @@ -60,7 +63,7 @@ public: uiTargetGUID = 0; } - void UpdateAI(const uint32 /*uiDiff*/) + void UpdateAI(uint32 /*uiDiff*/) { if (me->IsNonMeleeSpellCasted(false)) return; diff --git a/src/server/scripts/Northrend/zone_dalaran.cpp b/src/server/scripts/Northrend/zone_dalaran.cpp index d16b6fe4588..33440cad48b 100644 --- a/src/server/scripts/Northrend/zone_dalaran.cpp +++ b/src/server/scripts/Northrend/zone_dalaran.cpp @@ -55,9 +55,9 @@ class npc_mageguard_dalaran : public CreatureScript public: npc_mageguard_dalaran() : CreatureScript("npc_mageguard_dalaran") { } - struct npc_mageguard_dalaranAI : public Scripted_NoMovementAI + struct npc_mageguard_dalaranAI : public ScriptedAI { - npc_mageguard_dalaranAI(Creature* creature) : Scripted_NoMovementAI(creature) + npc_mageguard_dalaranAI(Creature* creature) : ScriptedAI(creature) { creature->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE); creature->ApplySpellImmune(0, IMMUNITY_DAMAGE, SPELL_SCHOOL_NORMAL, true); @@ -117,7 +117,7 @@ public: return; } - void UpdateAI(const uint32 /*diff*/){} + void UpdateAI(uint32 /*diff*/){} }; CreatureAI* GetAI(Creature* creature) const diff --git a/src/server/scripts/Northrend/zone_dragonblight.cpp b/src/server/scripts/Northrend/zone_dragonblight.cpp index a8fb0215902..ed7354acb50 100644 --- a/src/server/scripts/Northrend/zone_dragonblight.cpp +++ b/src/server/scripts/Northrend/zone_dragonblight.cpp @@ -248,7 +248,7 @@ class npc_wyrmrest_defender : public CreatureScript RenewRecoveryChecker = 0; } - void UpdateAI(uint32 const diff) + void UpdateAI(uint32 diff) { // Check system for Health Warning should happen first time whenever get under 30%, // after it should be able to happen only after recovery of last renew is fully done (20 sec), diff --git a/src/server/scripts/Northrend/zone_grizzly_hills.cpp b/src/server/scripts/Northrend/zone_grizzly_hills.cpp index fe1f561071c..e8eddea6ef7 100644 --- a/src/server/scripts/Northrend/zone_grizzly_hills.cpp +++ b/src/server/scripts/Northrend/zone_grizzly_hills.cpp @@ -192,7 +192,7 @@ public: RWORGGUID = 0; } - void UpdateAI(const uint32 uiDiff) + void UpdateAI(uint32 uiDiff) { npc_escortAI::UpdateAI(uiDiff); @@ -264,7 +264,7 @@ public: void MoveInLineOfSight(Unit* /*who*/) {} - void UpdateAI(const uint32 /*diff*/) + void UpdateAI(uint32 /*diff*/) { if (!UpdateVictim()) return; @@ -369,7 +369,7 @@ public: m_uiPhase = 1; } - void UpdateAI(const uint32 /*uiDiff*/) + void UpdateAI(uint32 /*uiDiff*/) { if (m_uiPhase == 1) { @@ -416,7 +416,7 @@ public: m_uiPhase = 1; } - void UpdateAI(const uint32 uiDiff) + void UpdateAI(uint32 uiDiff) { // call this each update tick? if (me->FindNearestCreature(TALLHORN_STAG, 0.2f)) @@ -510,7 +510,7 @@ public: } } - void UpdateAI(const uint32 /*diff*/) + void UpdateAI(uint32 /*diff*/) { if (!UpdateVictim()) return; @@ -558,7 +558,7 @@ public: uiChargedSentryTotem = urand(10000, 12000); } - void UpdateAI(const uint32 uiDiff) + void UpdateAI(uint32 uiDiff) { if (!UpdateVictim()) return; @@ -624,7 +624,7 @@ class npc_venture_co_straggler : public CreatureScript me->SetReactState(REACT_AGGRESSIVE); } - void UpdateAI(const uint32 uiDiff) + void UpdateAI(uint32 uiDiff) { if (uiPlayerGUID && uiRunAwayTimer <= uiDiff) { diff --git a/src/server/scripts/Northrend/zone_howling_fjord.cpp b/src/server/scripts/Northrend/zone_howling_fjord.cpp index ff4d8ec7a79..65d69e368b8 100644 --- a/src/server/scripts/Northrend/zone_howling_fjord.cpp +++ b/src/server/scripts/Northrend/zone_howling_fjord.cpp @@ -362,7 +362,7 @@ public: return true; } - // TODO: make prisoners help (unclear if summoned or using npc's from surrounding cages (summon inside small cages?)) + /// @todo make prisoners help (unclear if summoned or using npc's from surrounding cages (summon inside small cages?)) struct npc_daegarnAI : public ScriptedAI { npc_daegarnAI(Creature* creature) : ScriptedAI(creature) { } diff --git a/src/server/scripts/Northrend/zone_icecrown.cpp b/src/server/scripts/Northrend/zone_icecrown.cpp index 2ec5a3e8164..70b500166c9 100644 --- a/src/server/scripts/Northrend/zone_icecrown.cpp +++ b/src/server/scripts/Northrend/zone_icecrown.cpp @@ -32,6 +32,8 @@ EndContentData */ #include "ScriptedGossip.h" #include "SpellAuras.h" #include "Player.h" +#include "TemporarySummon.h" +#include "CombatAI.h" /*###### ## npc_arete @@ -219,7 +221,7 @@ public: } } - void UpdateAI(const uint32 uiDiff) + void UpdateAI(uint32 uiDiff) { if (!UpdateVictim()) return; @@ -264,9 +266,12 @@ class npc_guardian_pavilion : public CreatureScript public: npc_guardian_pavilion() : CreatureScript("npc_guardian_pavilion") { } - struct npc_guardian_pavilionAI : public Scripted_NoMovementAI + struct npc_guardian_pavilionAI : public ScriptedAI { - npc_guardian_pavilionAI(Creature* creature) : Scripted_NoMovementAI(creature) {} + npc_guardian_pavilionAI(Creature* creature) : ScriptedAI(creature) + { + SetCombatMovement(false); + } void MoveInLineOfSight(Unit* who) { @@ -370,9 +375,12 @@ class npc_tournament_training_dummy : public CreatureScript public: npc_tournament_training_dummy(): CreatureScript("npc_tournament_training_dummy"){} - struct npc_tournament_training_dummyAI : Scripted_NoMovementAI + struct npc_tournament_training_dummyAI : ScriptedAI { - npc_tournament_training_dummyAI(Creature* creature) : Scripted_NoMovementAI(creature) {} + npc_tournament_training_dummyAI(Creature* creature) : ScriptedAI(creature) + { + SetCombatMovement(false); + } EventMap events; bool isVulnerable; @@ -442,7 +450,7 @@ class npc_tournament_training_dummy : public CreatureScript isVulnerable = true; } - void UpdateAI(uint32 const diff) + void UpdateAI(uint32 diff) { events.Update(diff); @@ -584,13 +592,15 @@ class npc_blessed_banner : public CreatureScript public: npc_blessed_banner() : CreatureScript("npc_blessed_banner") { } - struct npc_blessed_bannerAI : public Scripted_NoMovementAI + struct npc_blessed_bannerAI : public ScriptedAI { - npc_blessed_bannerAI(Creature* creature) : Scripted_NoMovementAI(creature) , Summons(me) + npc_blessed_bannerAI(Creature* creature) : ScriptedAI(creature), Summons(me) { HalofSpawned = false; PhaseCount = 0; Summons.DespawnAll(); + + SetCombatMovement(false); } EventMap events; @@ -611,7 +621,7 @@ public: me->setRegeneratingHealth(false); DoCast(SPELL_THREAT_PULSE); me->AI()->Talk(BANNER_SAY); - events.ScheduleEvent(EVENT_SPAWN,3000); + events.ScheduleEvent(EVENT_SPAWN, 3000); } void EnterCombat(Unit* /*who*/) {} @@ -629,7 +639,7 @@ public: me->DespawnOrUnsummon(); } - void UpdateAI(uint32 const diff) + void UpdateAI(uint32 diff) { events.Update(diff); @@ -672,167 +682,167 @@ public: guidMason[2] = Mason3->GetGUID(); Mason3->GetMotionMaster()->MovePoint(0, Mason3Pos[1]); } - events.ScheduleEvent(EVENT_INTRO_1,15000); + events.ScheduleEvent(EVENT_INTRO_1, 15000); } break; case EVENT_INTRO_1: { - if (Creature* Dalfors = me->GetCreature(*me,guidDalfors)) + if (Creature* Dalfors = me->GetCreature(*me, guidDalfors)) Dalfors->AI()->Talk(DALFORS_SAY_PRE_1); - events.ScheduleEvent(EVENT_INTRO_2,5000); + events.ScheduleEvent(EVENT_INTRO_2, 5000); } break; case EVENT_INTRO_2: { - if (Creature* Dalfors = me->GetCreature(*me,guidDalfors)) + if (Creature* Dalfors = me->GetCreature(*me, guidDalfors)) { Dalfors->SetFacingTo(6.215f); Dalfors->AI()->Talk(DALFORS_SAY_PRE_2); } - events.ScheduleEvent(EVENT_INTRO_3,5000); + events.ScheduleEvent(EVENT_INTRO_3, 5000); } break; case EVENT_INTRO_3: { - if (Creature* Dalfors = me->GetCreature(*me,guidDalfors)) + if (Creature* Dalfors = me->GetCreature(*me, guidDalfors)) { Dalfors->GetMotionMaster()->MovePoint(0, DalforsPos[2]); Dalfors->SetHomePosition(DalforsPos[2]); } - if (Creature* Priest1 = me->GetCreature(*me,guidPriest[0])) + if (Creature* Priest1 = me->GetCreature(*me, guidPriest[0])) { Priest1->SetFacingTo(5.7421f); Priest1->SetHomePosition(Priest1Pos[1]); } - if (Creature* Priest2 = me->GetCreature(*me,guidPriest[1])) + if (Creature* Priest2 = me->GetCreature(*me, guidPriest[1])) { Priest2->SetFacingTo(5.7421f); Priest2->SetHomePosition(Priest2Pos[1]); } - if (Creature* Priest3 = me->GetCreature(*me,guidPriest[2])) + if (Creature* Priest3 = me->GetCreature(*me, guidPriest[2])) { Priest3->SetFacingTo(5.7421f); Priest3->SetHomePosition(Priest3Pos[1]); } - if (Creature* Mason1 = me->GetCreature(*me,guidMason[0])) + if (Creature* Mason1 = me->GetCreature(*me, guidMason[0])) { Mason1->GetMotionMaster()->MovePoint(0, Mason1Pos[2]); Mason1->SetHomePosition(Mason1Pos[2]); } - if (Creature* Mason2 = me->GetCreature(*me,guidMason[1])) + if (Creature* Mason2 = me->GetCreature(*me, guidMason[1])) { Mason2->GetMotionMaster()->MovePoint(0, Mason2Pos[2]); Mason2->SetHomePosition(Mason2Pos[2]); } - if (Creature* Mason3 = me->GetCreature(*me,guidMason[2])) + if (Creature* Mason3 = me->GetCreature(*me, guidMason[2])) { Mason3->GetMotionMaster()->MovePoint(0, Mason3Pos[2]); Mason3->SetHomePosition(Mason3Pos[2]); } - events.ScheduleEvent(EVENT_START_FIGHT,5000); - events.ScheduleEvent(EVENT_MASON_ACTION,15000); + events.ScheduleEvent(EVENT_START_FIGHT, 5000); + events.ScheduleEvent(EVENT_MASON_ACTION, 15000); } break; case EVENT_MASON_ACTION: { - if (Creature* Mason1 = me->GetCreature(*me,guidMason[0])) + if (Creature* Mason1 = me->GetCreature(*me, guidMason[0])) { Mason1->SetFacingTo(2.8972f); - Mason1->AI()->SetData(1,1); // triggers SAI actions on npc + Mason1->AI()->SetData(1, 1); // triggers SAI actions on npc } - if (Creature* Mason2 = me->GetCreature(*me,guidMason[1])) + if (Creature* Mason2 = me->GetCreature(*me, guidMason[1])) { Mason2->SetFacingTo(3.1241f); - Mason2->AI()->SetData(1,1); // triggers SAI actions on npc + Mason2->AI()->SetData(1, 1); // triggers SAI actions on npc } - if (Creature* Mason3 = me->GetCreature(*me,guidMason[2])) + if (Creature* Mason3 = me->GetCreature(*me, guidMason[2])) { Mason3->SetFacingTo(3.6651f); - Mason3->AI()->SetData(1,1); // triggers SAI actions on npc + Mason3->AI()->SetData(1, 1); // triggers SAI actions on npc } } break; case EVENT_START_FIGHT: { - if(Creature* LK = GetClosestCreatureWithEntry(me,NPC_LK,100)) + if (Creature* LK = GetClosestCreatureWithEntry(me, NPC_LK, 100)) LK->AI()->Talk(LK_TALK_1); - if (Creature* Dalfors = me->GetCreature(*me,guidDalfors)) + if (Creature* Dalfors = me->GetCreature(*me, guidDalfors)) Dalfors->AI()->Talk(DALFORS_SAY_START); - events.ScheduleEvent(EVENT_WAVE_SPAWN,1000); + events.ScheduleEvent(EVENT_WAVE_SPAWN, 1000); } break; case EVENT_WAVE_SPAWN: { if (PhaseCount == 3) { - if (Creature* LK = GetClosestCreatureWithEntry(me,NPC_LK,100)) + if (Creature* LK = GetClosestCreatureWithEntry(me, NPC_LK, 100)) LK->AI()->Talk(LK_TALK_2); } else if (PhaseCount == 6) { - if (Creature* LK = GetClosestCreatureWithEntry(me,NPC_LK,100)) + if (Creature* LK = GetClosestCreatureWithEntry(me, NPC_LK, 100)) LK->AI()->Talk(LK_TALK_3); } - if (Creature* tempsum = DoSummon(NPC_SCOURGE_DRUDGE,Mason3Pos[0])) + if (Creature* tempsum = DoSummon(NPC_SCOURGE_DRUDGE, Mason3Pos[0])) { tempsum->SetHomePosition(DalforsPos[2]); - tempsum->AI()->AttackStart(GetClosestCreatureWithEntry(me,NPC_BLESSED_BANNER,100)); + tempsum->AI()->AttackStart(GetClosestCreatureWithEntry(me, NPC_BLESSED_BANNER, 100)); } - if (urand(0,1) == 0) + if (urand(0, 1) == 0) { - if (Creature* tempsum = DoSummon(NPC_HIDEOUS_PLAGEBRINGER,Mason1Pos[0])) + if (Creature* tempsum = DoSummon(NPC_HIDEOUS_PLAGEBRINGER, Mason1Pos[0])) { tempsum->SetHomePosition(DalforsPos[2]); - tempsum->AI()->AttackStart(GetClosestCreatureWithEntry(me,NPC_BLESSED_BANNER,100)); + tempsum->AI()->AttackStart(GetClosestCreatureWithEntry(me, NPC_BLESSED_BANNER, 100)); } - if (Creature* tempsum = DoSummon(NPC_HIDEOUS_PLAGEBRINGER,Mason2Pos[0])) + if (Creature* tempsum = DoSummon(NPC_HIDEOUS_PLAGEBRINGER, Mason2Pos[0])) { tempsum->SetHomePosition(DalforsPos[2]); - tempsum->AI()->AttackStart(GetClosestCreatureWithEntry(me,NPC_BLESSED_BANNER,100)); + tempsum->AI()->AttackStart(GetClosestCreatureWithEntry(me, NPC_BLESSED_BANNER, 100)); } } else { - if (Creature* tempsum = DoSummon(NPC_REANIMATED_CAPTAIN,Mason1Pos[0])) + if (Creature* tempsum = DoSummon(NPC_REANIMATED_CAPTAIN, Mason1Pos[0])) { tempsum->SetHomePosition(DalforsPos[2]); - tempsum->AI()->AttackStart(GetClosestCreatureWithEntry(me,NPC_BLESSED_BANNER,100)); + tempsum->AI()->AttackStart(GetClosestCreatureWithEntry(me, NPC_BLESSED_BANNER, 100)); } - if (Creature* tempsum = DoSummon(NPC_REANIMATED_CAPTAIN,Mason2Pos[0])) + if (Creature* tempsum = DoSummon(NPC_REANIMATED_CAPTAIN, Mason2Pos[0])) { tempsum->SetHomePosition(DalforsPos[2]); - tempsum->AI()->AttackStart(GetClosestCreatureWithEntry(me,NPC_BLESSED_BANNER,100)); + tempsum->AI()->AttackStart(GetClosestCreatureWithEntry(me, NPC_BLESSED_BANNER, 100)); } } PhaseCount++; if (PhaseCount < 8) - events.ScheduleEvent(EVENT_WAVE_SPAWN,urand(10000,20000)); + events.ScheduleEvent(EVENT_WAVE_SPAWN, urand(10000, 20000)); else - events.ScheduleEvent(EVENT_HALOF,urand(10000,20000)); + events.ScheduleEvent(EVENT_HALOF, urand(10000, 20000)); } break; case EVENT_HALOF: { - if (Creature* LK = GetClosestCreatureWithEntry(me,NPC_LK,100)) + if (Creature* LK = GetClosestCreatureWithEntry(me, NPC_LK, 100)) LK->AI()->Talk(LK_TALK_4); - if (Creature* tempsum = DoSummon(NPC_SCOURGE_DRUDGE,Mason1Pos[0])) + if (Creature* tempsum = DoSummon(NPC_SCOURGE_DRUDGE, Mason1Pos[0])) { tempsum->SetHomePosition(DalforsPos[2]); - tempsum->AI()->AttackStart(GetClosestCreatureWithEntry(me,NPC_BLESSED_BANNER,100)); + tempsum->AI()->AttackStart(GetClosestCreatureWithEntry(me, NPC_BLESSED_BANNER, 100)); } - if (Creature* tempsum = DoSummon(NPC_SCOURGE_DRUDGE,Mason2Pos[0])) + if (Creature* tempsum = DoSummon(NPC_SCOURGE_DRUDGE, Mason2Pos[0])) { tempsum->SetHomePosition(DalforsPos[2]); - tempsum->AI()->AttackStart(GetClosestCreatureWithEntry(me,NPC_BLESSED_BANNER,100)); + tempsum->AI()->AttackStart(GetClosestCreatureWithEntry(me, NPC_BLESSED_BANNER, 100)); } - if (Creature* tempsum = DoSummon(NPC_HALOF_THE_DEATHBRINGER,DalforsPos[0])) + if (Creature* tempsum = DoSummon(NPC_HALOF_THE_DEATHBRINGER, DalforsPos[0])) { HalofSpawned = true; guidHalof = tempsum->GetGUID(); tempsum->SetHomePosition(DalforsPos[2]); - tempsum->AI()->AttackStart(GetClosestCreatureWithEntry(me,NPC_BLESSED_BANNER,100)); + tempsum->AI()->AttackStart(GetClosestCreatureWithEntry(me, NPC_BLESSED_BANNER, 100)); } } break; @@ -845,17 +855,17 @@ public: } if (PhaseCount == 8) - if (Creature* Halof = me->GetCreature(*me,guidHalof)) + if (Creature* Halof = me->GetCreature(*me, guidHalof)) if (Halof->isDead()) { - DoCast(me,SPELL_CRUSADERS_SPIRE_VICTORY,true); + DoCast(me, SPELL_CRUSADERS_SPIRE_VICTORY, true); Summons.DespawnEntry(NPC_HIDEOUS_PLAGEBRINGER); Summons.DespawnEntry(NPC_REANIMATED_CAPTAIN); Summons.DespawnEntry(NPC_SCOURGE_DRUDGE); Summons.DespawnEntry(NPC_HALOF_THE_DEATHBRINGER); - if (Creature* Dalfors = me->GetCreature(*me,guidDalfors)) + if (Creature* Dalfors = me->GetCreature(*me, guidDalfors)) Dalfors->AI()->Talk(DALFORS_YELL_FINISHED); - events.ScheduleEvent(EVENT_ENDED,10000); + events.ScheduleEvent(EVENT_ENDED, 10000); } } }; @@ -866,6 +876,92 @@ public: } }; +/*###### +## Borrowed Technology - Id: 13291, The Solution Solution (daily) - Id: 13292, Volatility - Id: 13239, Volatiliy - Id: 13261 (daily) +######*/ + +enum BorrowedTechnologyAndVolatility +{ + // Spells + SPELL_GRAB = 59318, + SPELL_PING_BUNNY = 59375, + SPELL_IMMOLATION = 54690, + SPELL_EXPLOSION = 59335, + SPELL_RIDE = 56687, + + // Points + POINT_GRAB_DECOY = 1, + POINT_FLY_AWAY = 2, + + // Events + EVENT_FLY_AWAY = 1 +}; + +class npc_frostbrood_skytalon : public CreatureScript +{ + public: + npc_frostbrood_skytalon() : CreatureScript("npc_frostbrood_skytalon") { } + + struct npc_frostbrood_skytalonAI : public VehicleAI + { + npc_frostbrood_skytalonAI(Creature* creature) : VehicleAI(creature) { } + + EventMap events; + + void IsSummonedBy(Unit* summoner) + { + me->GetMotionMaster()->MovePoint(POINT_GRAB_DECOY, summoner->GetPositionX(), summoner->GetPositionY(), summoner->GetPositionZ()); + } + + void MovementInform(uint32 type, uint32 id) + { + if (type != POINT_MOTION_TYPE) + return; + + if (id == POINT_GRAB_DECOY) + if (TempSummon* summon = me->ToTempSummon()) + if (Unit* summoner = summon->GetSummoner()) + DoCast(summoner, SPELL_GRAB); + } + + void UpdateAI(uint32 diff) + { + VehicleAI::UpdateAI(diff); + events.Update(diff); + + while (uint32 eventId = events.ExecuteEvent()) + { + if (eventId == EVENT_FLY_AWAY) + { + Position randomPosOnRadius; + randomPosOnRadius.m_positionZ = (me->GetPositionZ() + 40.0f); + me->GetNearPoint2D(randomPosOnRadius.m_positionX, randomPosOnRadius.m_positionY, 40.0f, me->GetAngle(me)); + me->GetMotionMaster()->MovePoint(POINT_FLY_AWAY, randomPosOnRadius); + } + } + } + + void SpellHit(Unit* /*caster*/, SpellInfo const* spell) + { + switch (spell->Id) + { + case SPELL_EXPLOSION: + DoCast(me, SPELL_IMMOLATION); + break; + case SPELL_RIDE: + DoCastAOE(SPELL_PING_BUNNY); + events.ScheduleEvent(EVENT_FLY_AWAY, 100); + break; + } + } + }; + + CreatureAI* GetAI(Creature* creature) const + { + return new npc_frostbrood_skytalonAI(creature); + } +}; + void AddSC_icecrown() { new npc_arete; @@ -875,4 +971,5 @@ void AddSC_icecrown() new npc_vereth_the_cunning; new npc_tournament_training_dummy; new npc_blessed_banner(); + new npc_frostbrood_skytalon(); } diff --git a/src/server/scripts/Northrend/zone_sholazar_basin.cpp b/src/server/scripts/Northrend/zone_sholazar_basin.cpp index 2aa355084a1..57228595b9b 100644 --- a/src/server/scripts/Northrend/zone_sholazar_basin.cpp +++ b/src/server/scripts/Northrend/zone_sholazar_basin.cpp @@ -321,7 +321,7 @@ public: Reset(); } - void UpdateAI(const uint32 /*uiDiff*/) + void UpdateAI(uint32 /*uiDiff*/) { if (!UpdateVictim()) return; @@ -420,7 +420,7 @@ public: } } - void UpdateAI(const uint32 uiDiff) + void UpdateAI(uint32 uiDiff) { npc_escortAI::UpdateAI(uiDiff); @@ -540,13 +540,13 @@ public: Player* player = Player::GetPlayer(*me, playerGUID); Creature* orphan = Creature::GetCreature(*me, orphanGUID); - if(!orphan || !player) + if (!orphan || !player) { Reset(); return; } - switch(phase) + switch (phase) { case 1: orphan->GetMotionMaster()->MovePoint(0, me->GetPositionX() + cos(me->GetOrientation()) * 5, me->GetPositionY() + sin(me->GetOrientation()) * 5, me->GetPositionZ()); @@ -582,7 +582,7 @@ public: timer -= diff; } - void UpdateAI(const uint32 uiDiff) + void UpdateAI(uint32 uiDiff) { if (phase) proceedCwEvent(uiDiff); @@ -948,7 +948,7 @@ public: bird->Kill(bird); crunchy->GetMotionMaster()->MovePoint(0, bird->GetPositionX(), bird->GetPositionY(), bird->GetMap()->GetWaterOrGroundLevel(bird->GetPositionX(), bird->GetPositionY(), bird->GetPositionZ())); - // TODO: Make crunchy perform emote eat when he reaches the bird + /// @todo Make crunchy perform emote eat when he reaches the bird break; } @@ -1033,6 +1033,102 @@ public: } }; +/*###### +## Quest: Reconnaissance Flight (12671) +######*/ +enum ReconnaissanceFlight +{ + NPC_PLANE = 28710, // Vic's Flying Machine + NPC_PILOT = 28646, + + VIC_SAY_0 = 0, + VIC_SAY_1 = 1, + VIC_SAY_2 = 2, + VIC_SAY_3 = 3, + VIC_SAY_4 = 4, + VIC_SAY_5 = 5, + VIC_SAY_6 = 6, + PLANE_EMOTE = 0, + + AURA_ENGINE = 52255, // Engine on Fire + + SPELL_LAND = 52226, // Land Flying Machine + SPELL_CREDIT = 53328 // Land Flying Machine Credit +}; + +class npc_vics_flying_machine : public CreatureScript +{ +public: + npc_vics_flying_machine() : CreatureScript("npc_vics_flying_machine") { } + + struct npc_vics_flying_machineAI : public VehicleAI + { + npc_vics_flying_machineAI(Creature* creature) : VehicleAI(creature) {} + + void PassengerBoarded(Unit* passenger, int8 /*seatId*/, bool apply) + { + if (apply && passenger->GetTypeId() == TYPEID_PLAYER) + me->GetMotionMaster()->MovePath(NPC_PLANE, false); + } + + void MovementInform(uint32 type, uint32 id) + { + if (type != WAYPOINT_MOTION_TYPE) + return; + + if (Creature* pilot = GetClosestCreatureWithEntry(me, NPC_PILOT, 10)) + switch (id) + { + case 5: + pilot->AI()->Talk(VIC_SAY_0); + break; + case 11: + pilot->AI()->Talk(VIC_SAY_1); + break; + case 12: + pilot->AI()->Talk(VIC_SAY_2); + break; + case 14: + pilot->AI()->Talk(VIC_SAY_3); + break; + case 15: + pilot->AI()->Talk(VIC_SAY_4); + break; + case 17: + pilot->AI()->Talk(VIC_SAY_5); + break; + case 21: + pilot->AI()->Talk(VIC_SAY_6); + break; + case 25: + me->AI()->Talk(PLANE_EMOTE); + me->AI()->DoCast(AURA_ENGINE); + break; + } + } + + void SpellHit(Unit* /*caster*/, SpellInfo const* spell) + { + if (spell->Id == SPELL_LAND) + { + Unit* passenger = me->GetVehicleKit()->GetPassenger(1); // player should be on seat 1 + if (passenger && passenger->GetTypeId() == TYPEID_PLAYER) + { + passenger->CastSpell(passenger, SPELL_CREDIT, true); + passenger->ExitVehicle(); + } + } + } + + void UpdateAI(uint32 /*diff*/) {} + }; + + CreatureAI* GetAI(Creature* creature) const + { + return new npc_vics_flying_machineAI(creature); + } +}; + void AddSC_sholazar_basin() { new npc_injured_rainspeaker_oracle(); @@ -1045,4 +1141,5 @@ void AddSC_sholazar_basin() new spell_q12620_the_lifewarden_wrath(); new spell_q12589_shoot_rjr(); new npc_haiphoon(); + new npc_vics_flying_machine(); } diff --git a/src/server/scripts/Northrend/zone_storm_peaks.cpp b/src/server/scripts/Northrend/zone_storm_peaks.cpp index 85ab1dc1127..ba725d2dda4 100644 --- a/src/server/scripts/Northrend/zone_storm_peaks.cpp +++ b/src/server/scripts/Northrend/zone_storm_peaks.cpp @@ -186,7 +186,7 @@ public: player->FailQuest(QUEST_BITTER_DEPARTURE); } - void UpdateAI(const uint32 uiDiff) + void UpdateAI(uint32 uiDiff) { npc_escortAI::UpdateAI(uiDiff); if (!UpdateVictim()) @@ -318,7 +318,7 @@ public: Reset(); } - void UpdateAI(const uint32 /*diff*/) + void UpdateAI(uint32 /*diff*/) { if (!freed) return; @@ -356,34 +356,20 @@ public: enum FreedProtoDrake { + NPC_DRAKE = 29709, + AREA_VALLEY_OF_ANCIENT_WINTERS = 4437, + TEXT_EMOTE = 0, + SPELL_KILL_CREDIT_PRISONER = 55144, SPELL_SUMMON_LIBERATED = 55073, - SPELL_KILL_CREDIT_DRAKE = 55143 -}; + SPELL_KILL_CREDIT_DRAKE = 55143, -const Position FreedDrakeWaypoints[16] = -{ - {7294.96f, -2418.733f, 823.869f, 0.0f}, - {7315.984f, -2331.46f, 826.3972f, 0.0f}, - {7271.826f, -2271.479f, 833.5917f, 0.0f}, - {7186.253f, -2218.475f, 847.5632f, 0.0f}, - {7113.195f, -2164.288f, 850.2301f, 0.0f}, - {7078.018f, -2063.106f, 854.7581f, 0.0f}, - {7073.221f, -1983.382f, 861.9246f, 0.0f}, - {7061.455f, -1885.899f, 865.119f, 0.0f}, - {7033.32f, -1826.775f, 876.2578f, 0.0f}, - {6999.902f, -1784.012f, 897.4521f, 0.0f}, - {6954.913f, -1747.043f, 897.4521f, 0.0f}, - {6933.856f, -1720.698f, 882.2022f, 0.0f}, - {6932.729f, -1687.306f, 866.1189f, 0.0f}, - {6952.458f, -1663.802f, 849.8133f, 0.0f}, - {7002.819f, -1651.681f, 831.397f, 0.0f}, - {7026.531f, -1649.239f, 828.8406f, 0.0f} + EVENT_CHECK_AREA = 1, + EVENT_REACHED_HOME = 2, }; - class npc_freed_protodrake : public CreatureScript { public: @@ -393,74 +379,60 @@ public: { npc_freed_protodrakeAI(Creature* creature) : VehicleAI(creature) {} - bool autoMove; - bool wpReached; - uint16 CheckTimer; - uint16 countWP; + EventMap events; void Reset() { - autoMove = false; - wpReached = false; - CheckTimer = 5000; - countWP = 0; + events.ScheduleEvent(EVENT_CHECK_AREA, 5000); } void MovementInform(uint32 type, uint32 id) { - if (type != POINT_MOTION_TYPE) + if (type != WAYPOINT_MOTION_TYPE) return; - if (id < 15) - { - ++countWP; - wpReached = true; - } - else + if (id == 15) // drake reached village - { - // get player that rides drake (from seat 0) - Unit* player = me->GetVehicleKit()->GetPassenger(0); - if (player && player->GetTypeId() == TYPEID_PLAYER) - { - // for each prisoner on drake,give credit - for (uint8 i = 1; i < 4; ++i) - if (Unit* prisoner = me->GetVehicleKit()->GetPassenger(i)) - { - if (prisoner->GetTypeId() != TYPEID_UNIT) - return; - prisoner->CastSpell(player, SPELL_KILL_CREDIT_PRISONER, true); - prisoner->CastSpell(prisoner, SPELL_SUMMON_LIBERATED, true); - prisoner->ExitVehicle(); - } - me->CastSpell(me, SPELL_KILL_CREDIT_DRAKE, true); - player->ExitVehicle(); - } - } + events.ScheduleEvent(EVENT_REACHED_HOME, 2000); } - void UpdateAI(const uint32 diff) + void UpdateAI(uint32 diff) { - if (!autoMove) + events.Update(diff); + + switch (events.ExecuteEvent()) { - if (CheckTimer < diff) - { - CheckTimer = 5000; + case EVENT_CHECK_AREA: if (me->GetAreaId() == AREA_VALLEY_OF_ANCIENT_WINTERS) { - Talk(TEXT_EMOTE, me->GetVehicleKit()->GetPassenger(0)->GetGUID()); - autoMove = true; - wpReached = true; + if (Vehicle* vehicle = me->GetVehicleKit()) + if (Unit* passenger = vehicle->GetPassenger(0)) + { + Talk(TEXT_EMOTE, passenger->GetGUID()); + me->GetMotionMaster()->MovePath(NPC_DRAKE, false); + } } - } - else - CheckTimer -= diff; - } - - if (wpReached && autoMove) - { - wpReached = false; - me->GetMotionMaster()->MovePoint(countWP, FreedDrakeWaypoints[countWP]); + else + events.ScheduleEvent(EVENT_CHECK_AREA, 5000); + break; + case EVENT_REACHED_HOME: + Unit* player = me->GetVehicleKit()->GetPassenger(0); + if (player && player->GetTypeId() == TYPEID_PLAYER) + { + // for each prisoner on drake, give credit + for (uint8 i = 1; i < 4; ++i) + if (Unit* prisoner = me->GetVehicleKit()->GetPassenger(i)) + { + if (prisoner->GetTypeId() != TYPEID_UNIT) + return; + prisoner->CastSpell(player, SPELL_KILL_CREDIT_PRISONER, true); + prisoner->CastSpell(prisoner, SPELL_SUMMON_LIBERATED, true); + prisoner->ExitVehicle(); + } + me->CastSpell(me, SPELL_KILL_CREDIT_DRAKE, true); + player->ExitVehicle(); + } + break; } } }; @@ -505,7 +477,7 @@ public: { } - void UpdateAI(const uint32 diff) + void UpdateAI(uint32 diff) { npc_escortAI::UpdateAI(diff); @@ -544,7 +516,7 @@ class npc_hyldsmeet_protodrake : public CreatureScript _accessoryRespawnTimer = 5 * MINUTE * IN_MILLISECONDS; } - void UpdateAI(uint32 const diff) + void UpdateAI(uint32 diff) { //! We need to manually reinstall accessories because the vehicle itself is friendly to players, //! so EnterEvadeMode is never triggered. The accessory on the other hand is hostile and killable. diff --git a/src/server/scripts/Northrend/zone_wintergrasp.cpp b/src/server/scripts/Northrend/zone_wintergrasp.cpp index 8935c77b30e..ce0eaefac90 100644 --- a/src/server/scripts/Northrend/zone_wintergrasp.cpp +++ b/src/server/scripts/Northrend/zone_wintergrasp.cpp @@ -224,7 +224,7 @@ class npc_wg_spirit_guide : public CreatureScript { npc_wg_spirit_guideAI(Creature* creature) : ScriptedAI(creature) { } - void UpdateAI(uint32 const /*diff*/) + void UpdateAI(uint32 /*diff*/) { if (!me->HasUnitState(UNIT_STATE_CASTING)) DoCast(me, SPELL_CHANNEL_SPIRIT_HEAL); @@ -271,7 +271,7 @@ class npc_wg_queue : public CreatureScript return true; } - bool OnGossipSelect(Player* player, Creature* /*creature*/ , uint32 /*sender*/ , uint32 /*action*/) + bool OnGossipSelect(Player* player, Creature* /*creature*/, uint32 /*sender*/, uint32 /*action*/) { player->CLOSE_GOSSIP_MENU(); diff --git a/src/server/scripts/Northrend/zone_zuldrak.cpp b/src/server/scripts/Northrend/zone_zuldrak.cpp index 69e8d900435..33a573b9b35 100644 --- a/src/server/scripts/Northrend/zone_zuldrak.cpp +++ b/src/server/scripts/Northrend/zone_zuldrak.cpp @@ -170,7 +170,7 @@ public: } } - void UpdateAI(const uint32 uiDiff) + void UpdateAI(uint32 uiDiff) { if (UpdateVictim()) { @@ -409,7 +409,7 @@ public: } } - void UpdateAI(const uint32 uiDiff) + void UpdateAI(uint32 uiDiff) { ScriptedAI::UpdateAI(uiDiff); @@ -636,7 +636,7 @@ public: DoCast(who, SPELL_IMPALE); } - void UpdateAI(const uint32 uiDiff) + void UpdateAI(uint32 uiDiff) { if (!UpdateVictim()) return; @@ -761,7 +761,7 @@ public: DoCast(me, SPELL_GROW); } - void UpdateAI(const uint32 uiDiff) + void UpdateAI(uint32 uiDiff) { npc_escortAI::UpdateAI(uiDiff); @@ -832,7 +832,7 @@ public: uiCorrodeFleshTimer = 6000; } - void UpdateAI(const uint32 uiDiff) + void UpdateAI(uint32 uiDiff) { if (!UpdateVictim()) return; @@ -950,7 +950,7 @@ public: } } - void UpdateAI(const uint32 uiDiff) + void UpdateAI(uint32 uiDiff) { npc_escortAI::UpdateAI(uiDiff); @@ -1099,7 +1099,7 @@ public: } } - void UpdateAI(const uint32 uiDiff) + void UpdateAI(uint32 uiDiff) { if (!UpdateVictim()) return; @@ -1213,7 +1213,7 @@ public: } - void UpdateAI(const uint32 uiDiff) + void UpdateAI(uint32 uiDiff) { if (!UpdateVictim()) return; @@ -1309,7 +1309,7 @@ public: m_heading = me->GetOrientation(); } - void UpdateAI(const uint32 uiDiff) + void UpdateAI(uint32 uiDiff) { if (m_uiPhase) { diff --git a/src/server/scripts/OutdoorPvP/OutdoorPvPNA.h b/src/server/scripts/OutdoorPvP/OutdoorPvPNA.h index 04555c671bb..637f86591d4 100644 --- a/src/server/scripts/OutdoorPvP/OutdoorPvPNA.h +++ b/src/server/scripts/OutdoorPvP/OutdoorPvPNA.h @@ -20,7 +20,7 @@ #include "OutdoorPvP.h" -// TODO: "sometimes" set to neutral +/// @todo "sometimes" set to neutral enum OutdoorPvPNASpells { diff --git a/src/server/scripts/OutdoorPvP/OutdoorPvPZM.h b/src/server/scripts/OutdoorPvP/OutdoorPvPZM.h index bab537682ad..60dce43bc42 100644 --- a/src/server/scripts/OutdoorPvP/OutdoorPvPZM.h +++ b/src/server/scripts/OutdoorPvP/OutdoorPvPZM.h @@ -267,5 +267,5 @@ class OutdoorPvPZM : public OutdoorPvP uint32 m_HordeTowersControlled; }; -// todo: flag carrier death/leave/mount/activitychange should give back the gossip options +/// @todo flag carrier death/leave/mount/activitychange should give back the gossip options #endif diff --git a/src/server/scripts/Outland/Auchindoun/AuchenaiCrypts/boss_exarch_maladaar.cpp b/src/server/scripts/Outland/Auchindoun/AuchenaiCrypts/boss_exarch_maladaar.cpp index 040ca012902..0fb49dfc284 100644 --- a/src/server/scripts/Outland/Auchindoun/AuchenaiCrypts/boss_exarch_maladaar.cpp +++ b/src/server/scripts/Outland/Auchindoun/AuchenaiCrypts/boss_exarch_maladaar.cpp @@ -72,7 +72,7 @@ public: myClass = myclass; } - void UpdateAI(const uint32 diff) + void UpdateAI(uint32 diff) { if (!UpdateVictim()) return; @@ -234,7 +234,7 @@ public: me->SummonCreature(19412, 0.0f, 0.0f, 0.0f, 0.0f, TEMPSUMMON_TIMED_DESPAWN, 600000); } - void UpdateAI(const uint32 diff) + void UpdateAI(uint32 diff) { if (!UpdateVictim()) return; @@ -322,7 +322,7 @@ public: { } - void UpdateAI(const uint32 diff) + void UpdateAI(uint32 diff) { if (!UpdateVictim()) return; diff --git a/src/server/scripts/Outland/Auchindoun/AuchenaiCrypts/boss_shirrak_the_dead_watcher.cpp b/src/server/scripts/Outland/Auchindoun/AuchenaiCrypts/boss_shirrak_the_dead_watcher.cpp index 7509f6331f7..00ec9b9fe4a 100644 --- a/src/server/scripts/Outland/Auchindoun/AuchenaiCrypts/boss_shirrak_the_dead_watcher.cpp +++ b/src/server/scripts/Outland/Auchindoun/AuchenaiCrypts/boss_shirrak_the_dead_watcher.cpp @@ -94,7 +94,7 @@ public: } } - void UpdateAI(const uint32 diff) + void UpdateAI(uint32 diff) { //Inhibitmagic_Timer if (Inhibitmagic_Timer <= diff) @@ -185,7 +185,7 @@ public: void EnterCombat(Unit* /*who*/) { } - void UpdateAI(const uint32 diff) + void UpdateAI(uint32 diff) { //Return since we have no target if (!UpdateVictim()) diff --git a/src/server/scripts/Outland/Auchindoun/ManaTombs/boss_nexusprince_shaffar.cpp b/src/server/scripts/Outland/Auchindoun/ManaTombs/boss_nexusprince_shaffar.cpp index 7e1fa41c6da..f26760a82b7 100644 --- a/src/server/scripts/Outland/Auchindoun/ManaTombs/boss_nexusprince_shaffar.cpp +++ b/src/server/scripts/Outland/Auchindoun/ManaTombs/boss_nexusprince_shaffar.cpp @@ -149,7 +149,7 @@ public: summons.DespawnAll(); } - void UpdateAI(const uint32 diff) + void UpdateAI(uint32 diff) { if (!UpdateVictim()) return; @@ -269,7 +269,7 @@ public: summoned->AI()->AttackStart(me->getVictim()); } - void UpdateAI(const uint32 diff) + void UpdateAI(uint32 diff) { if (!UpdateVictim()) return; @@ -335,7 +335,7 @@ public: isFireboltTurn = true; } - void UpdateAI(const uint32 diff) + void UpdateAI(uint32 diff) { if (!UpdateVictim()) return; diff --git a/src/server/scripts/Outland/Auchindoun/ManaTombs/boss_pandemonius.cpp b/src/server/scripts/Outland/Auchindoun/ManaTombs/boss_pandemonius.cpp index c8bd6dbb069..e4d8d959941 100644 --- a/src/server/scripts/Outland/Auchindoun/ManaTombs/boss_pandemonius.cpp +++ b/src/server/scripts/Outland/Auchindoun/ManaTombs/boss_pandemonius.cpp @@ -82,7 +82,7 @@ public: Talk(SAY_AGGRO); } - void UpdateAI(const uint32 diff) + void UpdateAI(uint32 diff) { if (!UpdateVictim()) return; diff --git a/src/server/scripts/Outland/Auchindoun/SethekkHalls/boss_darkweaver_syth.cpp b/src/server/scripts/Outland/Auchindoun/SethekkHalls/boss_darkweaver_syth.cpp index 1a53a140f28..371c94035ac 100644 --- a/src/server/scripts/Outland/Auchindoun/SethekkHalls/boss_darkweaver_syth.cpp +++ b/src/server/scripts/Outland/Auchindoun/SethekkHalls/boss_darkweaver_syth.cpp @@ -127,7 +127,7 @@ public: DoCast(me, SPELL_SUMMON_SYTH_SHADOW, true); //right } - void UpdateAI(const uint32 diff) + void UpdateAI(uint32 diff) { if (!UpdateVictim()) return; @@ -220,7 +220,7 @@ public: void EnterCombat(Unit* /*who*/) { } - void UpdateAI(const uint32 diff) + void UpdateAI(uint32 diff) { if (!UpdateVictim()) return; @@ -279,7 +279,7 @@ public: void EnterCombat(Unit* /*who*/) { } - void UpdateAI(const uint32 diff) + void UpdateAI(uint32 diff) { if (!UpdateVictim()) return; @@ -333,7 +333,7 @@ public: void EnterCombat(Unit* /*who*/) { } - void UpdateAI(const uint32 diff) + void UpdateAI(uint32 diff) { if (!UpdateVictim()) return; @@ -388,7 +388,7 @@ public: void EnterCombat(Unit* /*who*/) { } - void UpdateAI(const uint32 diff) + void UpdateAI(uint32 diff) { if (!UpdateVictim()) return; diff --git a/src/server/scripts/Outland/Auchindoun/SethekkHalls/boss_tailonking_ikiss.cpp b/src/server/scripts/Outland/Auchindoun/SethekkHalls/boss_tailonking_ikiss.cpp index 8a872039e37..4a9a98abcde 100644 --- a/src/server/scripts/Outland/Auchindoun/SethekkHalls/boss_tailonking_ikiss.cpp +++ b/src/server/scripts/Outland/Auchindoun/SethekkHalls/boss_tailonking_ikiss.cpp @@ -127,7 +127,7 @@ public: Talk(SAY_SLAY); } - void UpdateAI(const uint32 diff) + void UpdateAI(uint32 diff) { if (!UpdateVictim()) return; diff --git a/src/server/scripts/Outland/Auchindoun/ShadowLabyrinth/boss_ambassador_hellmaw.cpp b/src/server/scripts/Outland/Auchindoun/ShadowLabyrinth/boss_ambassador_hellmaw.cpp index b9163c13413..cd7f8e120de 100644 --- a/src/server/scripts/Outland/Auchindoun/ShadowLabyrinth/boss_ambassador_hellmaw.cpp +++ b/src/server/scripts/Outland/Auchindoun/ShadowLabyrinth/boss_ambassador_hellmaw.cpp @@ -142,7 +142,7 @@ public: instance->SetData(TYPE_HELLMAW, DONE); } - void UpdateAI(const uint32 diff) + void UpdateAI(uint32 diff) { if (!Intro && !HasEscortState(STATE_ESCORT_ESCORTING)) { diff --git a/src/server/scripts/Outland/Auchindoun/ShadowLabyrinth/boss_blackheart_the_inciter.cpp b/src/server/scripts/Outland/Auchindoun/ShadowLabyrinth/boss_blackheart_the_inciter.cpp index 4ae2d59799a..0c0bae17c5d 100644 --- a/src/server/scripts/Outland/Auchindoun/ShadowLabyrinth/boss_blackheart_the_inciter.cpp +++ b/src/server/scripts/Outland/Auchindoun/ShadowLabyrinth/boss_blackheart_the_inciter.cpp @@ -106,7 +106,7 @@ public: instance->SetData(DATA_BLACKHEARTTHEINCITEREVENT, IN_PROGRESS); } - void UpdateAI(const uint32 diff) + void UpdateAI(uint32 diff) { //Return since we have no target if (!UpdateVictim()) diff --git a/src/server/scripts/Outland/Auchindoun/ShadowLabyrinth/boss_grandmaster_vorpil.cpp b/src/server/scripts/Outland/Auchindoun/ShadowLabyrinth/boss_grandmaster_vorpil.cpp index 80eb7c03819..a067bbf92a0 100644 --- a/src/server/scripts/Outland/Auchindoun/ShadowLabyrinth/boss_grandmaster_vorpil.cpp +++ b/src/server/scripts/Outland/Auchindoun/ShadowLabyrinth/boss_grandmaster_vorpil.cpp @@ -93,7 +93,7 @@ public: void EnterCombat(Unit* /*who*/){} - void UpdateAI(const uint32 diff) + void UpdateAI(uint32 diff) { if (!VorpilGUID) { @@ -264,7 +264,7 @@ public: } } - void UpdateAI(const uint32 diff) + void UpdateAI(uint32 diff) { if (!UpdateVictim()) return; diff --git a/src/server/scripts/Outland/Auchindoun/ShadowLabyrinth/boss_murmur.cpp b/src/server/scripts/Outland/Auchindoun/ShadowLabyrinth/boss_murmur.cpp index fbe62e2a003..e09371bca13 100644 --- a/src/server/scripts/Outland/Auchindoun/ShadowLabyrinth/boss_murmur.cpp +++ b/src/server/scripts/Outland/Auchindoun/ShadowLabyrinth/boss_murmur.cpp @@ -111,7 +111,7 @@ public: me->DealDamage(target, (target->GetHealth()*90)/100, NULL, SPELL_DIRECT_DAMAGE, SPELL_SCHOOL_MASK_NATURE, spell); } - void UpdateAI(const uint32 diff) + void UpdateAI(uint32 diff) { //Return since we have no target or casting if (!UpdateVictim() || me->IsNonMeleeSpellCasted(false)) diff --git a/src/server/scripts/Outland/BlackTemple/black_temple.cpp b/src/server/scripts/Outland/BlackTemple/black_temple.cpp index ae0a17e1a8c..f8467b297cc 100644 --- a/src/server/scripts/Outland/BlackTemple/black_temple.cpp +++ b/src/server/scripts/Outland/BlackTemple/black_temple.cpp @@ -19,7 +19,7 @@ /* ScriptData SDName: Black_Temple SD%Complete: 95 -SDComment: Spirit of Olum: Player Teleporter to Seer Kanai Teleport after defeating Naj'entus and Supremus. TODO: Find proper gossip. +SDComment: Spirit of Olum: Player Teleporter to Seer Kanai Teleport after defeating Naj'entus and Supremus. @todo Find proper gossip. SDCategory: Black Temple EndScriptData */ diff --git a/src/server/scripts/Outland/BlackTemple/boss_bloodboil.cpp b/src/server/scripts/Outland/BlackTemple/boss_bloodboil.cpp index 3a56a0bfed2..5a292d165cc 100644 --- a/src/server/scripts/Outland/BlackTemple/boss_bloodboil.cpp +++ b/src/server/scripts/Outland/BlackTemple/boss_bloodboil.cpp @@ -187,9 +187,7 @@ public: void RevertThreatOnTarget(uint64 guid) { - Unit* unit = NULL; - unit = Unit::GetUnit(*me, guid); - if (unit) + if (Unit* unit = Unit::GetUnit(*me, guid)) { if (DoGetThreat(unit)) DoModifyThreatPercent(unit, -100); @@ -198,7 +196,7 @@ public: } } - void UpdateAI(const uint32 diff) + void UpdateAI(uint32 diff) { if (!UpdateVictim()) return; @@ -279,8 +277,7 @@ public: { if (Phase1) { - Unit* target = SelectTarget(SELECT_TARGET_RANDOM, 0); - if (target && target->isAlive()) + if (Unit* target = SelectTarget(SELECT_TARGET_RANDOM, 0)) { Phase1 = false; @@ -308,7 +305,8 @@ public: AcidGeyserTimer = 1000; PhaseChangeTimer = 30000; } - } else // Encounter is a loop pretty much. Phase 1 -> Phase 2 -> Phase 1 -> Phase 2 till death or enrage + } + else // Encounter is a loop pretty much. Phase 1 -> Phase 2 -> Phase 1 -> Phase 2 till death or enrage { if (TargetGUID) RevertThreatOnTarget(TargetGUID); diff --git a/src/server/scripts/Outland/BlackTemple/boss_illidan.cpp b/src/server/scripts/Outland/BlackTemple/boss_illidan.cpp index b8003761cc7..e990a6f6825 100644 --- a/src/server/scripts/Outland/BlackTemple/boss_illidan.cpp +++ b/src/server/scripts/Outland/BlackTemple/boss_illidan.cpp @@ -422,8 +422,7 @@ public: Glaive->InterruptNonMeleeSpells(true); DoCast(me, SPELL_FLAME_ENRAGE, true); DoResetThreat(); - Unit* target = SelectTarget(SELECT_TARGET_RANDOM, 0); - if (target && target->isAlive()) + if (SelectTarget(SELECT_TARGET_RANDOM, 0)) { me->AddThreat(me->getVictim(), 5000000.0f); AttackStart(me->getVictim()); @@ -442,7 +441,7 @@ public: GlaiveGUID = guid; } - void UpdateAI(const uint32 diff) + void UpdateAI(uint32 diff) { if (!UpdateVictim()) return; @@ -578,7 +577,7 @@ public: if (victim == me) return; - // TODO: Find better way to handle emote + /// @todo Find better way to handle emote switch (urand(0, 1)) { case 0: @@ -957,7 +956,7 @@ public: ++TransformCount; } - void UpdateAI(const uint32 diff) + void UpdateAI(uint32 diff) { if ((!UpdateVictim()) && Phase < PHASE_TALK_SEQUENCE) return; @@ -1231,7 +1230,7 @@ public: ScriptedAI::AttackStart(who); } - void DoAction(const int32 param) + void DoAction(int32 param) { if (param > PHASE_ILLIDAN_NULL && param < PHASE_ILLIDAN_MAX) EnterPhase(PhaseIllidan(param)); @@ -1303,7 +1302,7 @@ public: } } - void UpdateAI(const uint32 diff) + void UpdateAI(uint32 diff) { if ((!UpdateVictim()) && !Timer[EVENT_MAIEV_STEALTH]) @@ -1733,7 +1732,7 @@ public: } } - void UpdateAI(const uint32 diff) + void UpdateAI(uint32 diff) { if (!me->IsVisible()) { @@ -2079,7 +2078,7 @@ public: } } - void UpdateAI(const uint32 diff) + void UpdateAI(uint32 diff) { if (DespawnTimer) { @@ -2092,7 +2091,7 @@ public: // { // if (Unit* Illidan = Unit::GetUnit(*me, IllidanGUID) // { - // // TODO: Find proper spells and properly apply 'caged' Illidan effect + // /// @todo Find proper spells and properly apply 'caged' Illidan effect // } // } } @@ -2150,7 +2149,7 @@ public: target->RemoveAurasDueToSpell(SPELL_PARALYZE); } - void UpdateAI(const uint32 /*diff*/) + void UpdateAI(uint32 /*diff*/) { if (!UpdateVictim()) return; @@ -2248,7 +2247,7 @@ public: } } - void UpdateAI(const uint32 diff) + void UpdateAI(uint32 diff) { if (!me->getVictim()) { diff --git a/src/server/scripts/Outland/BlackTemple/boss_mother_shahraz.cpp b/src/server/scripts/Outland/BlackTemple/boss_mother_shahraz.cpp index 11569c30f1e..dc56f7abe07 100644 --- a/src/server/scripts/Outland/BlackTemple/boss_mother_shahraz.cpp +++ b/src/server/scripts/Outland/BlackTemple/boss_mother_shahraz.cpp @@ -45,7 +45,7 @@ enum MotherShahraz SPELL_ATTRACTION = 40871, SPELL_SILENCING_SHRIEK = 40823, SPELL_ENRAGE = 23537, - SPELL_SABER_LASH = 40810,//43267 + SPELL_SABER_LASH = 40810, //43267 SPELL_SABER_LASH_IMM = 43690, SPELL_TELEPORT_VISUAL = 40869, SPELL_BERSERK = 45078 @@ -174,7 +174,7 @@ public: } } - void UpdateAI(const uint32 diff) + void UpdateAI(uint32 diff) { if (!UpdateVictim()) return; diff --git a/src/server/scripts/Outland/BlackTemple/boss_reliquary_of_souls.cpp b/src/server/scripts/Outland/BlackTemple/boss_reliquary_of_souls.cpp index f9c46aa3f77..a6432114ded 100644 --- a/src/server/scripts/Outland/BlackTemple/boss_reliquary_of_souls.cpp +++ b/src/server/scripts/Outland/BlackTemple/boss_reliquary_of_souls.cpp @@ -248,7 +248,7 @@ public: instance->SetData(DATA_RELIQUARYOFSOULSEVENT, DONE); } - void UpdateAI(const uint32 diff) + void UpdateAI(uint32 diff) { if (!Phase) return; @@ -469,7 +469,7 @@ public: me->AddThreat(target, 1000000); } - void UpdateAI(const uint32 diff) + void UpdateAI(uint32 diff) { if (me->isInCombat()) { @@ -574,7 +574,7 @@ public: Talk(DESI_SAY_SLAY); } - void UpdateAI(const uint32 diff) + void UpdateAI(uint32 diff) { if (!UpdateVictim()) return; @@ -665,7 +665,7 @@ public: Talk(ANGER_SAY_SLAY); } - void UpdateAI(const uint32 diff) + void UpdateAI(uint32 diff) { //Return since we have no target if (!UpdateVictim()) diff --git a/src/server/scripts/Outland/BlackTemple/boss_shade_of_akama.cpp b/src/server/scripts/Outland/BlackTemple/boss_shade_of_akama.cpp index fe5af2a689e..9860cf0385a 100644 --- a/src/server/scripts/Outland/BlackTemple/boss_shade_of_akama.cpp +++ b/src/server/scripts/Outland/BlackTemple/boss_shade_of_akama.cpp @@ -139,7 +139,7 @@ public: void EnterCombat(Unit* /*who*/) {} void AttackStart(Unit* /*who*/) {} void MoveInLineOfSight(Unit* /*who*/) {} - void UpdateAI(const uint32 /*diff*/) {} + void UpdateAI(uint32 /*diff*/) {} }; }; @@ -175,7 +175,7 @@ public: void EnterCombat(Unit* /*who*/) {} void AttackStart(Unit* /*who*/) {} void MoveInLineOfSight(Unit* /*who*/) {} - void UpdateAI(const uint32 diff) + void UpdateAI(uint32 diff) { if (StartBanishing) return; @@ -423,7 +423,7 @@ public: void SetAkamaGUID(uint64 guid) { AkamaGUID = guid; } - void UpdateAI(const uint32 diff) + void UpdateAI(uint32 diff) { if (!me->isInCombat()) return; @@ -725,7 +725,7 @@ public: summons.DespawnAll(); } - void UpdateAI(const uint32 diff) + void UpdateAI(uint32 diff) { if (!EventBegun) return; diff --git a/src/server/scripts/Outland/BlackTemple/boss_supremus.cpp b/src/server/scripts/Outland/BlackTemple/boss_supremus.cpp index 6bc6633e49e..114f83661b3 100644 --- a/src/server/scripts/Outland/BlackTemple/boss_supremus.cpp +++ b/src/server/scripts/Outland/BlackTemple/boss_supremus.cpp @@ -203,7 +203,7 @@ public: return target; } - void UpdateAI(const uint32 diff) + void UpdateAI(uint32 diff) { if (!UpdateVictim()) return; @@ -272,9 +272,12 @@ public: return new npc_volcanoAI (creature); } - struct npc_volcanoAI : public Scripted_NoMovementAI + struct npc_volcanoAI : public ScriptedAI { - npc_volcanoAI(Creature* creature) : Scripted_NoMovementAI(creature) {} + npc_volcanoAI(Creature* creature) : ScriptedAI(creature) + { + SetCombatMovement(false); + } void Reset() { @@ -290,12 +293,12 @@ public: void MoveInLineOfSight(Unit* /*who*/) {} - void DoAction(const int32 /*info*/) + void DoAction(int32 /*info*/) { me->RemoveAura(SPELL_VOLCANIC_ERUPTION); } - void UpdateAI(const uint32 diff) + void UpdateAI(uint32 diff) { if (wait <= diff)//wait 3secs before casting { diff --git a/src/server/scripts/Outland/BlackTemple/boss_teron_gorefiend.cpp b/src/server/scripts/Outland/BlackTemple/boss_teron_gorefiend.cpp index 6c28b058cf7..5eb9ffcabc8 100644 --- a/src/server/scripts/Outland/BlackTemple/boss_teron_gorefiend.cpp +++ b/src/server/scripts/Outland/BlackTemple/boss_teron_gorefiend.cpp @@ -86,7 +86,7 @@ public: me->RemoveCorpse(); } - void UpdateAI(const uint32 diff) + void UpdateAI(uint32 diff) { if (CheckTeronTimer <= diff) { @@ -188,7 +188,7 @@ public: } } - void UpdateAI(const uint32 diff) + void UpdateAI(uint32 diff) { if (CheckPlayerTimer <= diff) { @@ -378,7 +378,7 @@ public: } } - void UpdateAI(const uint32 diff) + void UpdateAI(uint32 diff) { if (Intro && !Done) { @@ -468,8 +468,7 @@ public: if (CrushingShadowsTimer <= diff) { - Unit* target = SelectTarget(SELECT_TARGET_RANDOM, 0); - if (target && target->isAlive()) + if (Unit* target = SelectTarget(SELECT_TARGET_RANDOM, 0)) DoCast(target, SPELL_CRUSHING_SHADOWS); CrushingShadowsTimer = urand(10, 26) * 1000; } else CrushingShadowsTimer -= diff; diff --git a/src/server/scripts/Outland/BlackTemple/boss_warlord_najentus.cpp b/src/server/scripts/Outland/BlackTemple/boss_warlord_najentus.cpp index 7a56734bc3b..127ca68ce39 100644 --- a/src/server/scripts/Outland/BlackTemple/boss_warlord_najentus.cpp +++ b/src/server/scripts/Outland/BlackTemple/boss_warlord_najentus.cpp @@ -146,7 +146,7 @@ public: events.RescheduleEvent(EVENT_SHIELD, 60000 + inc); } - void UpdateAI(const uint32 diff) + void UpdateAI(uint32 diff) { if (!UpdateVictim()) return; diff --git a/src/server/scripts/Outland/BlackTemple/illidari_council.cpp b/src/server/scripts/Outland/BlackTemple/illidari_council.cpp index 03fa5235d18..d63e8ee20b0 100644 --- a/src/server/scripts/Outland/BlackTemple/illidari_council.cpp +++ b/src/server/scripts/Outland/BlackTemple/illidari_council.cpp @@ -169,7 +169,7 @@ public: void AttackStart(Unit* /*who*/) {} void MoveInLineOfSight(Unit* /*who*/) {} - void UpdateAI(const uint32 diff) + void UpdateAI(uint32 diff) { if (!EventStarted) return; @@ -315,7 +315,7 @@ public: } } - void UpdateAI(const uint32 diff) + void UpdateAI(uint32 diff) { if (!EventBegun) return; @@ -536,7 +536,7 @@ public: } } - void UpdateAI(const uint32 diff) + void UpdateAI(uint32 diff) { if (!UpdateVictim()) return; @@ -641,7 +641,7 @@ public: Talk(SAY_ZERE_DEATH); } - void UpdateAI(const uint32 diff) + void UpdateAI(uint32 diff) { if (!UpdateVictim()) return; @@ -741,7 +741,7 @@ public: Talk(SAY_MALA_DEATH); } - void UpdateAI(const uint32 diff) + void UpdateAI(uint32 diff) { if (!UpdateVictim()) return; @@ -827,7 +827,7 @@ public: Talk(SAY_VERA_DEATH); } - void UpdateAI(const uint32 diff) + void UpdateAI(uint32 diff) { if (!UpdateVictim()) return; diff --git a/src/server/scripts/Outland/CoilfangReservoir/SerpentShrine/boss_fathomlord_karathress.cpp b/src/server/scripts/Outland/CoilfangReservoir/SerpentShrine/boss_fathomlord_karathress.cpp index d9ad35f9552..b9df26d11c6 100644 --- a/src/server/scripts/Outland/CoilfangReservoir/SerpentShrine/boss_fathomlord_karathress.cpp +++ b/src/server/scripts/Outland/CoilfangReservoir/SerpentShrine/boss_fathomlord_karathress.cpp @@ -222,14 +222,12 @@ public: StartEvent(who); } - void UpdateAI(const uint32 diff) + void UpdateAI(uint32 diff) { //Only if not incombat check if the event is started if (!me->isInCombat() && instance && instance->GetData(DATA_KARATHRESSEVENT)) { - Unit* target = Unit::GetUnit(*me, instance->GetData64(DATA_KARATHRESSEVENT_STARTER)); - - if (target) + if (Unit* target = Unit::GetUnit(*me, instance->GetData64(DATA_KARATHRESSEVENT_STARTER))) { AttackStart(target); GetAdvisors(); @@ -360,12 +358,8 @@ public: { if (instance) { - Creature* Karathress = NULL; - Karathress = (Unit::GetCreature((*me), instance->GetData64(DATA_KARATHRESS))); - - if (Karathress) - if (!me->isAlive() && Karathress) - CAST_AI(boss_fathomlord_karathress::boss_fathomlord_karathressAI, Karathress->AI())->EventSharkkisDeath(); + if (Creature* Karathress = (Unit::GetCreature((*me), instance->GetData64(DATA_KARATHRESS)))) + CAST_AI(boss_fathomlord_karathress::boss_fathomlord_karathressAI, Karathress->AI())->EventSharkkisDeath(); } } @@ -378,17 +372,13 @@ public: } } - void UpdateAI(const uint32 diff) + void UpdateAI(uint32 diff) { //Only if not incombat check if the event is started if (!me->isInCombat() && instance && instance->GetData(DATA_KARATHRESSEVENT)) { - Unit* target = Unit::GetUnit(*me, instance->GetData64(DATA_KARATHRESSEVENT_STARTER)); - - if (target) - { + if (Unit* target = Unit::GetUnit(*me, instance->GetData64(DATA_KARATHRESSEVENT_STARTER))) AttackStart(target); - } } //Return since we have no target @@ -445,12 +435,13 @@ public: pet_id = CREATURE_FATHOM_SPOREBAT; } //DoCast(me, spell_id, true); - Creature* Pet = DoSpawnCreature(pet_id, 0, 0, 0, 0, TEMPSUMMON_TIMED_DESPAWN_OUT_OF_COMBAT, 15000); - Unit* target = SelectTarget(SELECT_TARGET_RANDOM, 0); - if (Pet && target) + if (Unit* target = SelectTarget(SELECT_TARGET_RANDOM, 0)) { - Pet->AI()->AttackStart(target); - SummonedPet = Pet->GetGUID(); + if (Creature* Pet = DoSpawnCreature(pet_id, 0, 0, 0, 0, TEMPSUMMON_TIMED_DESPAWN_OUT_OF_COMBAT, 15000)) + { + Pet->AI()->AttackStart(target); + SummonedPet = Pet->GetGUID(); + } } } else Pet_Timer -= diff; @@ -500,12 +491,8 @@ public: { if (instance) { - Creature* Karathress = NULL; - Karathress = (Unit::GetCreature((*me), instance->GetData64(DATA_KARATHRESS))); - - if (Karathress) - if (!me->isAlive() && Karathress) - CAST_AI(boss_fathomlord_karathress::boss_fathomlord_karathressAI, Karathress->AI())->EventTidalvessDeath(); + if (Creature* Karathress = Unit::GetCreature((*me), instance->GetData64(DATA_KARATHRESS))) + CAST_AI(boss_fathomlord_karathress::boss_fathomlord_karathressAI, Karathress->AI())->EventTidalvessDeath(); } } @@ -519,17 +506,13 @@ public: DoCast(me, SPELL_WINDFURY_WEAPON); } - void UpdateAI(const uint32 diff) + void UpdateAI(uint32 diff) { //Only if not incombat check if the event is started if (!me->isInCombat() && instance && instance->GetData(DATA_KARATHRESSEVENT)) { - Unit* target = Unit::GetUnit(*me, instance->GetData64(DATA_KARATHRESSEVENT_STARTER)); - - if (target) - { + if (Unit* target = Unit::GetUnit(*me, instance->GetData64(DATA_KARATHRESSEVENT_STARTER))) AttackStart(target); - } } //Return since we have no target @@ -627,12 +610,8 @@ public: { if (instance) { - Creature* Karathress = NULL; - Karathress = (Unit::GetCreature((*me), instance->GetData64(DATA_KARATHRESS))); - - if (Karathress) - if (!me->isAlive() && Karathress) - CAST_AI(boss_fathomlord_karathress::boss_fathomlord_karathressAI, Karathress->AI())->EventCaribdisDeath(); + if (Creature* Karathress = Unit::GetCreature((*me), instance->GetData64(DATA_KARATHRESS))) + CAST_AI(boss_fathomlord_karathress::boss_fathomlord_karathressAI, Karathress->AI())->EventCaribdisDeath(); } } @@ -645,17 +624,13 @@ public: } } - void UpdateAI(const uint32 diff) + void UpdateAI(uint32 diff) { //Only if not incombat check if the event is started if (!me->isInCombat() && instance && instance->GetData(DATA_KARATHRESSEVENT)) { - Unit* target = Unit::GetUnit(*me, instance->GetData64(DATA_KARATHRESSEVENT_STARTER)); - - if (target) - { + if (Unit* target = Unit::GetUnit(*me, instance->GetData64(DATA_KARATHRESSEVENT_STARTER))) AttackStart(target); - } } //Return since we have no target @@ -697,11 +672,8 @@ public: Cyclone->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE); Cyclone->setFaction(me->getFaction()); Cyclone->CastSpell(Cyclone, SPELL_CYCLONE_CYCLONE, true); - Unit* target = SelectTarget(SELECT_TARGET_RANDOM, 0); - if (target) - { + if (Unit* target = SelectTarget(SELECT_TARGET_RANDOM, 0)) Cyclone->AI()->AttackStart(target); - } } } else Cyclone_Timer -= diff; diff --git a/src/server/scripts/Outland/CoilfangReservoir/SerpentShrine/boss_hydross_the_unstable.cpp b/src/server/scripts/Outland/CoilfangReservoir/SerpentShrine/boss_hydross_the_unstable.cpp index b31292c4b00..2f0d736d8ef 100644 --- a/src/server/scripts/Outland/CoilfangReservoir/SerpentShrine/boss_hydross_the_unstable.cpp +++ b/src/server/scripts/Outland/CoilfangReservoir/SerpentShrine/boss_hydross_the_unstable.cpp @@ -212,7 +212,7 @@ public: Summons.DespawnAll(); } - void UpdateAI(const uint32 diff) + void UpdateAI(uint32 diff) { if (!beam) { @@ -272,8 +272,7 @@ public: //VileSludge_Timer if (VileSludge_Timer <= diff) { - Unit* target = SelectTarget(SELECT_TARGET_RANDOM, 0); - if (target) + if (Unit* target = SelectTarget(SELECT_TARGET_RANDOM, 0)) DoCast(target, SPELL_VILE_SLUDGE); VileSludge_Timer = 15000; diff --git a/src/server/scripts/Outland/CoilfangReservoir/SerpentShrine/boss_lady_vashj.cpp b/src/server/scripts/Outland/CoilfangReservoir/SerpentShrine/boss_lady_vashj.cpp index b0717d29228..19b57509093 100644 --- a/src/server/scripts/Outland/CoilfangReservoir/SerpentShrine/boss_lady_vashj.cpp +++ b/src/server/scripts/Outland/CoilfangReservoir/SerpentShrine/boss_lady_vashj.cpp @@ -310,7 +310,7 @@ public: } } - void UpdateAI(const uint32 diff) + void UpdateAI(uint32 diff) { if (!CanAttack && Intro) { @@ -599,7 +599,7 @@ public: void MoveInLineOfSight(Unit* /*who*/) {} - void UpdateAI(const uint32 diff) + void UpdateAI(uint32 diff) { if (!instance) return; @@ -677,7 +677,7 @@ public: me->AddThreat(who, 0.1f); } - void UpdateAI(const uint32 diff) + void UpdateAI(uint32 diff) { // PoisonBoltTimer if (PoisonBoltTimer <= diff) @@ -754,7 +754,7 @@ public: MovementTimer = 0; } - void UpdateAI (const uint32 diff) + void UpdateAI(uint32 diff) { // Random movement if (MovementTimer <= diff) @@ -834,7 +834,7 @@ public: void MoveInLineOfSight(Unit* /*who*/) {} - void UpdateAI (const uint32 diff) + void UpdateAI(uint32 diff) { if (!instance) return; diff --git a/src/server/scripts/Outland/CoilfangReservoir/SerpentShrine/boss_leotheras_the_blind.cpp b/src/server/scripts/Outland/CoilfangReservoir/SerpentShrine/boss_leotheras_the_blind.cpp index 2c8d067a865..f4e0c6cee2a 100644 --- a/src/server/scripts/Outland/CoilfangReservoir/SerpentShrine/boss_leotheras_the_blind.cpp +++ b/src/server/scripts/Outland/CoilfangReservoir/SerpentShrine/boss_leotheras_the_blind.cpp @@ -132,7 +132,7 @@ public: return; } - void UpdateAI(const uint32 diff) + void UpdateAI(uint32 diff) { //Return since we have no target if (!UpdateVictim()) @@ -316,7 +316,7 @@ public: me->SetDisplayId(MODEL_NIGHTELF); // and reseting equipment - me->LoadEquipment(me->GetEquipmentId()); + me->LoadEquipment(); if (instance && instance->GetData64(DATA_LEOTHERAS_EVENT_STARTER)) { @@ -410,10 +410,10 @@ public: if (me->HasAura(AURA_BANISH)) return; - me->LoadEquipment(me->GetEquipmentId()); + me->LoadEquipment(); } - void UpdateAI(const uint32 diff) + void UpdateAI(uint32 diff) { //Return since we have no target if (me->HasAura(AURA_BANISH) || !UpdateVictim()) @@ -558,7 +558,7 @@ public: { //switch to nightelf form me->SetDisplayId(MODEL_NIGHTELF); - me->LoadEquipment(me->GetEquipmentId()); + me->LoadEquipment(); CastConsumingMadness(); DespawnDemon(); @@ -589,7 +589,7 @@ public: Talk(SAY_FINAL_FORM); me->SetDisplayId(MODEL_NIGHTELF); - me->LoadEquipment(me->GetEquipmentId()); + me->LoadEquipment(); } } }; @@ -643,7 +643,7 @@ public: StartEvent(); } - void UpdateAI(const uint32 diff) + void UpdateAI(uint32 diff) { //Return since we have no target if (!UpdateVictim()) @@ -737,7 +737,7 @@ public: } } - void UpdateAI(const uint32 diff) + void UpdateAI(uint32 diff) { if (instance) { diff --git a/src/server/scripts/Outland/CoilfangReservoir/SerpentShrine/boss_lurker_below.cpp b/src/server/scripts/Outland/CoilfangReservoir/SerpentShrine/boss_lurker_below.cpp index 788de7753ff..18324822c4a 100644 --- a/src/server/scripts/Outland/CoilfangReservoir/SerpentShrine/boss_lurker_below.cpp +++ b/src/server/scripts/Outland/CoilfangReservoir/SerpentShrine/boss_lurker_below.cpp @@ -78,10 +78,11 @@ public: return new boss_the_lurker_belowAI (creature); } - struct boss_the_lurker_belowAI : public Scripted_NoMovementAI + struct boss_the_lurker_belowAI : public ScriptedAI { - boss_the_lurker_belowAI(Creature* creature) : Scripted_NoMovementAI(creature), Summons(me) + boss_the_lurker_belowAI(Creature* creature) : ScriptedAI(creature), Summons(me) { + SetCombatMovement(false); instance = creature->GetInstanceScript(); } @@ -152,11 +153,10 @@ public: Summons.DespawnAll(); } - void EnterCombat(Unit* who) + void EnterCombat(Unit* /*who*/) { if (instance) instance->SetData(DATA_THELURKERBELOWEVENT, IN_PROGRESS); - Scripted_NoMovementAI::EnterCombat(who); } void MoveInLineOfSight(Unit* who) @@ -177,7 +177,7 @@ public: me->SetReactState(REACT_AGGRESSIVE); } - void UpdateAI(const uint32 diff) + void UpdateAI(uint32 diff) { if (!CanStartEvent) // boss is invisible, don't attack { @@ -368,10 +368,11 @@ public: return new mob_coilfang_ambusherAI (creature); } - struct mob_coilfang_ambusherAI : public Scripted_NoMovementAI + struct mob_coilfang_ambusherAI : public ScriptedAI { - mob_coilfang_ambusherAI(Creature* creature) : Scripted_NoMovementAI(creature) + mob_coilfang_ambusherAI(Creature* creature) : ScriptedAI(creature) { + SetCombatMovement(false); } uint32 MultiShotTimer; @@ -392,7 +393,7 @@ public: AttackStart(who); } - void UpdateAI(const uint32 diff) + void UpdateAI(uint32 diff) { if (MultiShotTimer <= diff) { diff --git a/src/server/scripts/Outland/CoilfangReservoir/SerpentShrine/boss_morogrim_tidewalker.cpp b/src/server/scripts/Outland/CoilfangReservoir/SerpentShrine/boss_morogrim_tidewalker.cpp index 9476bb28f8e..592746742f5 100644 --- a/src/server/scripts/Outland/CoilfangReservoir/SerpentShrine/boss_morogrim_tidewalker.cpp +++ b/src/server/scripts/Outland/CoilfangReservoir/SerpentShrine/boss_morogrim_tidewalker.cpp @@ -163,7 +163,7 @@ public: } } - void UpdateAI(const uint32 diff) + void UpdateAI(uint32 diff) { //Return since we have no target if (!UpdateVictim()) @@ -184,10 +184,9 @@ public: for (uint8 i = 0; i < 10; ++i) { - Unit* target = SelectTarget(SELECT_TARGET_RANDOM, 0); - Creature* Murloc = me->SummonCreature(NPC_TIDEWALKER_LURKER, MurlocCords[i][0], MurlocCords[i][1], MurlocCords[i][2], MurlocCords[i][3], TEMPSUMMON_TIMED_DESPAWN_OUT_OF_COMBAT, 10000); - if (target && Murloc) - Murloc->AI()->AttackStart(target); + if (Unit* target = SelectTarget(SELECT_TARGET_RANDOM, 0)) + if (Creature* Murloc = me->SummonCreature(NPC_TIDEWALKER_LURKER, MurlocCords[i][0], MurlocCords[i][1], MurlocCords[i][2], MurlocCords[i][3], TEMPSUMMON_TIMED_DESPAWN_OUT_OF_COMBAT, 10000)) + Murloc->AI()->AttackStart(target); } Talk(EMOTE_EARTHQUAKE); Earthquake = false; @@ -321,7 +320,7 @@ public: } } - void UpdateAI(const uint32 diff) + void UpdateAI(uint32 diff) { //Return since we have no target if (!UpdateVictim()) diff --git a/src/server/scripts/Outland/CoilfangReservoir/SteamVault/boss_hydromancer_thespia.cpp b/src/server/scripts/Outland/CoilfangReservoir/SteamVault/boss_hydromancer_thespia.cpp index f2ed2560bbf..c9d394f6f2d 100644 --- a/src/server/scripts/Outland/CoilfangReservoir/SteamVault/boss_hydromancer_thespia.cpp +++ b/src/server/scripts/Outland/CoilfangReservoir/SteamVault/boss_hydromancer_thespia.cpp @@ -101,7 +101,7 @@ public: instance->SetData(TYPE_HYDROMANCER_THESPIA, IN_PROGRESS); } - void UpdateAI(const uint32 diff) + void UpdateAI(uint32 diff) { if (!UpdateVictim()) return; @@ -170,7 +170,7 @@ public: void EnterCombat(Unit* /*who*/) { } - void UpdateAI(const uint32 diff) + void UpdateAI(uint32 diff) { if (!UpdateVictim()) return; diff --git a/src/server/scripts/Outland/CoilfangReservoir/SteamVault/boss_mekgineer_steamrigger.cpp b/src/server/scripts/Outland/CoilfangReservoir/SteamVault/boss_mekgineer_steamrigger.cpp index 3897f370b0c..12e4e3a496f 100644 --- a/src/server/scripts/Outland/CoilfangReservoir/SteamVault/boss_mekgineer_steamrigger.cpp +++ b/src/server/scripts/Outland/CoilfangReservoir/SteamVault/boss_mekgineer_steamrigger.cpp @@ -122,7 +122,7 @@ public: DoSpawnCreature(ENTRY_STREAMRIGGER_MECHANIC, 7, -5, 0, 0, TEMPSUMMON_TIMED_OR_CORPSE_DESPAWN, 240000); } - void UpdateAI(const uint32 diff) + void UpdateAI(uint32 diff) { if (!UpdateVictim()) return; @@ -223,7 +223,7 @@ public: void EnterCombat(Unit* /*who*/) { } - void UpdateAI(const uint32 diff) + void UpdateAI(uint32 diff) { if (Repair_Timer <= diff) { diff --git a/src/server/scripts/Outland/CoilfangReservoir/SteamVault/boss_warlord_kalithresh.cpp b/src/server/scripts/Outland/CoilfangReservoir/SteamVault/boss_warlord_kalithresh.cpp index 23b25da91ea..914539b27c9 100644 --- a/src/server/scripts/Outland/CoilfangReservoir/SteamVault/boss_warlord_kalithresh.cpp +++ b/src/server/scripts/Outland/CoilfangReservoir/SteamVault/boss_warlord_kalithresh.cpp @@ -167,7 +167,7 @@ public: instance->SetData(TYPE_WARLORD_KALITHRESH, DONE); } - void UpdateAI(const uint32 diff) + void UpdateAI(uint32 diff) { if (!UpdateVictim()) return; diff --git a/src/server/scripts/Outland/CoilfangReservoir/underbog/boss_hungarfen.cpp b/src/server/scripts/Outland/CoilfangReservoir/underbog/boss_hungarfen.cpp index 9fa5a1a51f5..7e2c13483bd 100644 --- a/src/server/scripts/Outland/CoilfangReservoir/underbog/boss_hungarfen.cpp +++ b/src/server/scripts/Outland/CoilfangReservoir/underbog/boss_hungarfen.cpp @@ -26,8 +26,11 @@ EndScriptData */ #include "ScriptMgr.h" #include "ScriptedCreature.h" -#define SPELL_FOUL_SPORES 31673 -#define SPELL_ACID_GEYSER 38739 +enum Spells +{ + SPELL_FOUL_SPORES = 31673, + SPELL_ACID_GEYSER = 38739 +}; class boss_hungarfen : public CreatureScript { @@ -60,7 +63,7 @@ public: { } - void UpdateAI(const uint32 diff) + void UpdateAI(uint32 diff) { if (!UpdateVictim()) return; @@ -135,7 +138,7 @@ public: void EnterCombat(Unit* /*who*/) {} - void UpdateAI(const uint32 diff) + void UpdateAI(uint32 diff) { if (Stop) return; diff --git a/src/server/scripts/Outland/CoilfangReservoir/underbog/boss_the_black_stalker.cpp b/src/server/scripts/Outland/CoilfangReservoir/underbog/boss_the_black_stalker.cpp index 1e8fd8b2676..22f406c6c5b 100644 --- a/src/server/scripts/Outland/CoilfangReservoir/underbog/boss_the_black_stalker.cpp +++ b/src/server/scripts/Outland/CoilfangReservoir/underbog/boss_the_black_stalker.cpp @@ -102,7 +102,7 @@ public: strider->DisappearAndDie(); } - void UpdateAI(const uint32 diff) + void UpdateAI(uint32 diff) { if (!UpdateVictim()) return; diff --git a/src/server/scripts/Outland/GruulsLair/boss_gruul.cpp b/src/server/scripts/Outland/GruulsLair/boss_gruul.cpp index 0a5c8b0c8b6..6c3e21aa5c0 100644 --- a/src/server/scripts/Outland/GruulsLair/boss_gruul.cpp +++ b/src/server/scripts/Outland/GruulsLair/boss_gruul.cpp @@ -142,7 +142,7 @@ public: //this part should be in the core if (pSpell->Id == SPELL_SHATTER) { - // todo: use eventmap to kill this stuff + /// @todo use eventmap to kill this stuff //clear this, if we are still performing if (m_bPerformingGroundSlam) { @@ -158,7 +158,7 @@ public: } } - void UpdateAI(const uint32 uiDiff) + void UpdateAI(uint32 uiDiff) { //Return since we have no target if (!UpdateVictim()) diff --git a/src/server/scripts/Outland/GruulsLair/boss_high_king_maulgar.cpp b/src/server/scripts/Outland/GruulsLair/boss_high_king_maulgar.cpp index 83596c46936..3018c18383e 100644 --- a/src/server/scripts/Outland/GruulsLair/boss_high_king_maulgar.cpp +++ b/src/server/scripts/Outland/GruulsLair/boss_high_king_maulgar.cpp @@ -217,7 +217,7 @@ public: DoZoneInCombat(); } - void UpdateAI(const uint32 diff) + void UpdateAI(uint32 diff) { //Only if not incombat check if the event is started if (!me->isInCombat() && instance && instance->GetData(DATA_MAULGAREVENT)) @@ -377,7 +377,7 @@ public: } } - void UpdateAI(const uint32 diff) + void UpdateAI(uint32 diff) { //Only if not incombat check if the event is started if (!me->isInCombat() && instance && instance->GetData(DATA_MAULGAREVENT)) @@ -492,7 +492,7 @@ public: } } - void UpdateAI(const uint32 diff) + void UpdateAI(uint32 diff) { //Only if not incombat check if the event is started if (!me->isInCombat() && instance && instance->GetData(DATA_MAULGAREVENT)) @@ -519,8 +519,7 @@ public: //GreaterPolymorph_Timer if (GreaterPolymorph_Timer <= diff) { - Unit* target = SelectTarget(SELECT_TARGET_RANDOM, 0); - if (target) + if (Unit* target = SelectTarget(SELECT_TARGET_RANDOM, 0)) DoCast(target, SPELL_GREATER_POLYMORPH); GreaterPolymorph_Timer = urand(15000, 20000); @@ -612,7 +611,7 @@ public: } } - void UpdateAI(const uint32 diff) + void UpdateAI(uint32 diff) { //Only if not incombat check if the event is started if (!me->isInCombat() && instance && instance->GetData(DATA_MAULGAREVENT)) @@ -722,7 +721,7 @@ public: } } - void UpdateAI(const uint32 diff) + void UpdateAI(uint32 diff) { //Only if not incombat check if the event is started if (!me->isInCombat() && instance && instance->GetData(DATA_MAULGAREVENT)) diff --git a/src/server/scripts/Outland/HellfireCitadel/BloodFurnace/boss_broggok.cpp b/src/server/scripts/Outland/HellfireCitadel/BloodFurnace/boss_broggok.cpp index 6d3ec669cd5..0e584686f9b 100644 --- a/src/server/scripts/Outland/HellfireCitadel/BloodFurnace/boss_broggok.cpp +++ b/src/server/scripts/Outland/HellfireCitadel/BloodFurnace/boss_broggok.cpp @@ -84,7 +84,7 @@ class boss_broggok : public CreatureScript summoned->CastSpell(summoned, SPELL_POISON, false, 0, 0, me->GetGUID()); } - void UpdateAI(const uint32 diff) + void UpdateAI(uint32 diff) { if (!UpdateVictim()) return; @@ -127,7 +127,7 @@ class boss_broggok : public CreatureScript } } - void DoAction(int32 const action) + void DoAction(int32 action) { switch (action) { diff --git a/src/server/scripts/Outland/HellfireCitadel/BloodFurnace/boss_kelidan_the_breaker.cpp b/src/server/scripts/Outland/HellfireCitadel/BloodFurnace/boss_kelidan_the_breaker.cpp index 7d8885ae0ae..d2096140ff4 100644 --- a/src/server/scripts/Outland/HellfireCitadel/BloodFurnace/boss_kelidan_the_breaker.cpp +++ b/src/server/scripts/Outland/HellfireCitadel/BloodFurnace/boss_kelidan_the_breaker.cpp @@ -201,7 +201,7 @@ class boss_kelidan_the_breaker : public CreatureScript instance->HandleGameObject(instance->GetData64(DATA_DOOR6), true); } - void UpdateAI(const uint32 diff) + void UpdateAI(uint32 diff) { if (!UpdateVictim()) { @@ -330,7 +330,7 @@ class mob_shadowmoon_channeler : public CreatureScript CAST_AI(boss_kelidan_the_breaker::boss_kelidan_the_breakerAI, Kelidan->AI())->ChannelerDied(killer); } - void UpdateAI(const uint32 diff) + void UpdateAI(uint32 diff) { if (!UpdateVictim()) { diff --git a/src/server/scripts/Outland/HellfireCitadel/BloodFurnace/boss_the_maker.cpp b/src/server/scripts/Outland/HellfireCitadel/BloodFurnace/boss_the_maker.cpp index bab49b95974..8014ee9f8e0 100644 --- a/src/server/scripts/Outland/HellfireCitadel/BloodFurnace/boss_the_maker.cpp +++ b/src/server/scripts/Outland/HellfireCitadel/BloodFurnace/boss_the_maker.cpp @@ -105,7 +105,7 @@ class boss_the_maker : public CreatureScript } - void UpdateAI(const uint32 diff) + void UpdateAI(uint32 diff) { if (!UpdateVictim()) return; diff --git a/src/server/scripts/Outland/HellfireCitadel/BloodFurnace/instance_blood_furnace.cpp b/src/server/scripts/Outland/HellfireCitadel/BloodFurnace/instance_blood_furnace.cpp index 4eaf7cc2d6c..be51b7922a2 100644 --- a/src/server/scripts/Outland/HellfireCitadel/BloodFurnace/instance_blood_furnace.cpp +++ b/src/server/scripts/Outland/HellfireCitadel/BloodFurnace/instance_blood_furnace.cpp @@ -375,23 +375,23 @@ class instance_blood_furnace : public InstanceMapScript switch (id) { case DATA_PRISON_CELL5: - HandleGameObject(PrisonCell5GUID,true); + HandleGameObject(PrisonCell5GUID, true); ActivatePrisoners(PrisonersCell5); break; case DATA_PRISON_CELL6: - HandleGameObject(PrisonCell6GUID,true); + HandleGameObject(PrisonCell6GUID, true); ActivatePrisoners(PrisonersCell6); break; case DATA_PRISON_CELL7: - HandleGameObject(PrisonCell7GUID,true); + HandleGameObject(PrisonCell7GUID, true); ActivatePrisoners(PrisonersCell7); break; case DATA_PRISON_CELL8: - HandleGameObject(PrisonCell8GUID,true); + HandleGameObject(PrisonCell8GUID, true); ActivatePrisoners(PrisonersCell8); break; case DATA_DOOR5: - HandleGameObject(Door5GUID,true); + HandleGameObject(Door5GUID, true); if (Creature* broggok = instance->GetCreature(BroggokGUID)) broggok->AI()->DoAction(ACTION_ACTIVATE_BROGGOK); break; diff --git a/src/server/scripts/Outland/HellfireCitadel/HellfireRamparts/boss_omor_the_unscarred.cpp b/src/server/scripts/Outland/HellfireCitadel/HellfireRamparts/boss_omor_the_unscarred.cpp index b83307d8dcc..0c5325f7172 100644 --- a/src/server/scripts/Outland/HellfireCitadel/HellfireRamparts/boss_omor_the_unscarred.cpp +++ b/src/server/scripts/Outland/HellfireCitadel/HellfireRamparts/boss_omor_the_unscarred.cpp @@ -118,7 +118,7 @@ class boss_omor_the_unscarred : public CreatureScript Talk(SAY_DIE); } - void UpdateAI(const uint32 diff) + void UpdateAI(uint32 diff) { if (!UpdateVictim()) return; diff --git a/src/server/scripts/Outland/HellfireCitadel/HellfireRamparts/boss_vazruden_the_herald.cpp b/src/server/scripts/Outland/HellfireCitadel/HellfireRamparts/boss_vazruden_the_herald.cpp index 30a2813b286..e820e22d65a 100644 --- a/src/server/scripts/Outland/HellfireCitadel/HellfireRamparts/boss_vazruden_the_herald.cpp +++ b/src/server/scripts/Outland/HellfireCitadel/HellfireRamparts/boss_vazruden_the_herald.cpp @@ -124,7 +124,7 @@ class boss_nazan : public CreatureScript me->SummonCreature(ENTRY_LIQUID_FIRE, target->GetPositionX(), target->GetPositionY(), target->GetPositionZ(), target->GetOrientation(), TEMPSUMMON_TIMED_DESPAWN, 30000); } - void UpdateAI(const uint32 diff) + void UpdateAI(uint32 diff) { if (!UpdateVictim()) return; @@ -243,7 +243,7 @@ class boss_vazruden : public CreatureScript Talk(SAY_DIE); } - void UpdateAI(const uint32 diff) + void UpdateAI(uint32 diff) { if (!UpdateVictim()) { @@ -396,7 +396,7 @@ class boss_vazruden_the_herald : public CreatureScript sentryDown = true; } - void UpdateAI(const uint32 diff) + void UpdateAI(uint32 diff) { switch (phase) { @@ -487,7 +487,7 @@ class mob_hellfire_sentry : public CreatureScript CAST_AI(boss_vazruden_the_herald::boss_vazruden_the_heraldAI, herald->AI())->SentryDownBy(killer); } - void UpdateAI(const uint32 diff) + void UpdateAI(uint32 diff) { if (!UpdateVictim()) return; diff --git a/src/server/scripts/Outland/HellfireCitadel/HellfireRamparts/boss_watchkeeper_gargolmar.cpp b/src/server/scripts/Outland/HellfireCitadel/HellfireRamparts/boss_watchkeeper_gargolmar.cpp index 7aae6cebff9..8961c94ab31 100644 --- a/src/server/scripts/Outland/HellfireCitadel/HellfireRamparts/boss_watchkeeper_gargolmar.cpp +++ b/src/server/scripts/Outland/HellfireCitadel/HellfireRamparts/boss_watchkeeper_gargolmar.cpp @@ -112,7 +112,7 @@ class boss_watchkeeper_gargolmar : public CreatureScript Talk(SAY_DIE); } - void UpdateAI(const uint32 diff) + void UpdateAI(uint32 diff) { if (!UpdateVictim()) return; diff --git a/src/server/scripts/Outland/HellfireCitadel/MagtheridonsLair/boss_magtheridon.cpp b/src/server/scripts/Outland/HellfireCitadel/MagtheridonsLair/boss_magtheridon.cpp index aeec7d14b26..777f24f779b 100644 --- a/src/server/scripts/Outland/HellfireCitadel/MagtheridonsLair/boss_magtheridon.cpp +++ b/src/server/scripts/Outland/HellfireCitadel/MagtheridonsLair/boss_magtheridon.cpp @@ -151,7 +151,7 @@ class mob_abyssal : public CreatureScript ScriptedAI::MoveInLineOfSight(who); } - void UpdateAI(const uint32 diff) + void UpdateAI(uint32 diff) { if (trigger) { @@ -339,7 +339,7 @@ class boss_magtheridon : public CreatureScript Talk(SAY_FREED); } - void UpdateAI(const uint32 diff) + void UpdateAI(uint32 diff) { if (!me->isInCombat()) { @@ -528,7 +528,7 @@ class mob_hellfire_channeler : public CreatureScript instance->SetData(DATA_CHANNELER_EVENT, DONE); } - void UpdateAI(const uint32 diff) + void UpdateAI(uint32 diff) { if (!UpdateVictim()) return; diff --git a/src/server/scripts/Outland/HellfireCitadel/ShatteredHalls/boss_nethekurse.cpp b/src/server/scripts/Outland/HellfireCitadel/ShatteredHalls/boss_nethekurse.cpp index 00f0fd8964e..4095f3295fa 100644 --- a/src/server/scripts/Outland/HellfireCitadel/ShatteredHalls/boss_nethekurse.cpp +++ b/src/server/scripts/Outland/HellfireCitadel/ShatteredHalls/boss_nethekurse.cpp @@ -138,7 +138,7 @@ class boss_grand_warlock_nethekurse : public CreatureScript { Talk(SAY_TAUNT); - //TODO: kill the peons first + /// @todo kill the peons first IsIntroEvent = false; PeonEngagedCount = 4; PeonKilledCount = 4; @@ -213,7 +213,7 @@ class boss_grand_warlock_nethekurse : public CreatureScript instance->HandleGameObject(instance->GetData64(DATA_NETHEKURSE_DOOR), true); } - void UpdateAI(const uint32 diff) + void UpdateAI(uint32 diff) { if (IsIntroEvent) { @@ -346,7 +346,7 @@ class mob_fel_orc_convert : public CreatureScript } } - void UpdateAI(const uint32 diff) + void UpdateAI(uint32 diff) { if (!UpdateVictim()) return; diff --git a/src/server/scripts/Outland/HellfireCitadel/ShatteredHalls/boss_warbringer_omrogg.cpp b/src/server/scripts/Outland/HellfireCitadel/ShatteredHalls/boss_warbringer_omrogg.cpp index dd23f89dcfb..ac261cc5936 100644 --- a/src/server/scripts/Outland/HellfireCitadel/ShatteredHalls/boss_warbringer_omrogg.cpp +++ b/src/server/scripts/Outland/HellfireCitadel/ShatteredHalls/boss_warbringer_omrogg.cpp @@ -130,7 +130,7 @@ class mob_omrogg_heads : public CreatureScript DeathYell = true; } - void UpdateAI(const uint32 diff) + void UpdateAI(uint32 diff) { if (!DeathYell) return; @@ -312,7 +312,7 @@ class boss_warbringer_omrogg : public CreatureScript instance->SetData(TYPE_OMROGG, DONE); } - void UpdateAI(const uint32 diff) + void UpdateAI(uint32 diff) { if (Delay_Timer <= diff) { diff --git a/src/server/scripts/Outland/HellfireCitadel/ShatteredHalls/boss_warchief_kargath_bladefist.cpp b/src/server/scripts/Outland/HellfireCitadel/ShatteredHalls/boss_warchief_kargath_bladefist.cpp index f437018ac4b..13f47b276ef 100644 --- a/src/server/scripts/Outland/HellfireCitadel/ShatteredHalls/boss_warchief_kargath_bladefist.cpp +++ b/src/server/scripts/Outland/HellfireCitadel/ShatteredHalls/boss_warchief_kargath_bladefist.cpp @@ -194,7 +194,7 @@ class boss_warchief_kargath_bladefist : public CreatureScript me->SummonCreature(MOB_SHATTERED_ASSASSIN, AssassExit[0], AssassExit[1]-8, AssassExit[2], 0, TEMPSUMMON_TIMED_DESPAWN_OUT_OF_COMBAT, 30000); } - void UpdateAI(const uint32 diff) + void UpdateAI(uint32 diff) { //Return since we have no target if (!UpdateVictim()) diff --git a/src/server/scripts/Outland/TempestKeep/Eye/boss_alar.cpp b/src/server/scripts/Outland/TempestKeep/Eye/boss_alar.cpp index f0a823472df..099bd6949cb 100644 --- a/src/server/scripts/Outland/TempestKeep/Eye/boss_alar.cpp +++ b/src/server/scripts/Outland/TempestKeep/Eye/boss_alar.cpp @@ -212,7 +212,7 @@ class boss_alar : public CreatureScript } } - void UpdateAI(const uint32 diff) + void UpdateAI(uint32 diff) { if (!me->isInCombat()) // sometimes isincombat but !incombat, faction bug? return; @@ -515,7 +515,7 @@ class mob_ember_of_alar : public CreatureScript } } - void UpdateAI(const uint32 /*diff*/) + void UpdateAI(uint32 /*diff*/) { if (!UpdateVictim()) return; @@ -553,7 +553,7 @@ class mob_flame_patch_alar : public CreatureScript void EnterCombat(Unit* /*who*/) {} void AttackStart(Unit* /*who*/) {} void MoveInLineOfSight(Unit* /*who*/) {} - void UpdateAI(const uint32 /*diff*/) {} + void UpdateAI(uint32 /*diff*/) {} }; CreatureAI* GetAI(Creature* creature) const diff --git a/src/server/scripts/Outland/TempestKeep/Eye/boss_astromancer.cpp b/src/server/scripts/Outland/TempestKeep/Eye/boss_astromancer.cpp index 9c4b764fd2a..b8245729d73 100644 --- a/src/server/scripts/Outland/TempestKeep/Eye/boss_astromancer.cpp +++ b/src/server/scripts/Outland/TempestKeep/Eye/boss_astromancer.cpp @@ -195,7 +195,7 @@ class boss_high_astromancer_solarian : public CreatureScript return (z*sqrt(radius*radius - (x - CENTER_X)*(x - CENTER_X)) + CENTER_Y); } - void UpdateAI(const uint32 diff) + void UpdateAI(uint32 diff) { if (!UpdateVictim()) return; @@ -245,11 +245,13 @@ class boss_high_astromancer_solarian : public CreatureScript } else { - Unit* target = SelectTarget(SELECT_TARGET_RANDOM, 0); - if (!me->HasInArc(2.5f, target)) - target = me->getVictim(); - if (target) + if (Unit* target = SelectTarget(SELECT_TARGET_RANDOM, 0)) + { + if (!me->HasInArc(2.5f, target)) + target = me->getVictim(); + DoCast(target, SPELL_ARCANE_MISSILES); + } } ArcaneMissiles_Timer = 3000; } @@ -441,7 +443,7 @@ class mob_solarium_priest : public CreatureScript { } - void UpdateAI(const uint32 diff) + void UpdateAI(uint32 diff) { if (!UpdateVictim()) return; @@ -518,7 +520,7 @@ class spell_astromancer_wrath_of_the_astromancer : public SpellScriptLoader return; Unit* target = GetUnitOwner(); - target->CastSpell(target, GetSpellInfo()->Effects[EFFECT_1].CalcValue(),false); + target->CastSpell(target, GetSpellInfo()->Effects[EFFECT_1].CalcValue(), false); } void Register() diff --git a/src/server/scripts/Outland/TempestKeep/Eye/boss_kaelthas.cpp b/src/server/scripts/Outland/TempestKeep/Eye/boss_kaelthas.cpp index 07d563cd762..a6497e6a373 100644 --- a/src/server/scripts/Outland/TempestKeep/Eye/boss_kaelthas.cpp +++ b/src/server/scripts/Outland/TempestKeep/Eye/boss_kaelthas.cpp @@ -241,7 +241,7 @@ struct advisorbase_ai : public ScriptedAI } } - void UpdateAI(const uint32 diff) + void UpdateAI(uint32 diff) { if (DelayRes_Timer) { @@ -465,7 +465,7 @@ class boss_kaelthas : public CreatureScript } } - void UpdateAI(const uint32 diff) + void UpdateAI(uint32 diff) { //Phase 1 switch (Phase) @@ -1046,7 +1046,7 @@ class boss_thaladred_the_darkener : public CreatureScript Talk(SAY_THALADRED_DEATH); } - void UpdateAI(const uint32 diff) + void UpdateAI(uint32 diff) { advisorbase_ai::UpdateAI(diff); @@ -1138,7 +1138,7 @@ class boss_lord_sanguinar : public CreatureScript Talk(SAY_SANGUINAR_DEATH); } - void UpdateAI(const uint32 diff) + void UpdateAI(uint32 diff) { advisorbase_ai::UpdateAI(diff); @@ -1227,7 +1227,7 @@ class boss_grand_astromancer_capernian : public CreatureScript return; } - void UpdateAI(const uint32 diff) + void UpdateAI(uint32 diff) { advisorbase_ai::UpdateAI(diff); @@ -1353,7 +1353,7 @@ class boss_master_engineer_telonicus : public CreatureScript Talk(SAY_TELONICUS_AGGRO); } - void UpdateAI(const uint32 diff) + void UpdateAI(uint32 diff) { advisorbase_ai::UpdateAI(diff); @@ -1404,9 +1404,12 @@ class mob_kael_flamestrike : public CreatureScript : CreatureScript("mob_kael_flamestrike") { } - struct mob_kael_flamestrikeAI : public Scripted_NoMovementAI + struct mob_kael_flamestrikeAI : public ScriptedAI { - mob_kael_flamestrikeAI(Creature* creature) : Scripted_NoMovementAI(creature) {} + mob_kael_flamestrikeAI(Creature* creature) : ScriptedAI(creature) + { + SetCombatMovement(false); + } uint32 Timer; bool Casting; @@ -1426,7 +1429,7 @@ class mob_kael_flamestrike : public CreatureScript void EnterCombat(Unit* /*who*/) {} - void UpdateAI(const uint32 diff) + void UpdateAI(uint32 diff) { if (!Casting) { @@ -1487,7 +1490,7 @@ class mob_phoenix_tk : public CreatureScript me->SummonCreature(NPC_PHOENIX_EGG, me->GetPositionX(), me->GetPositionY(), me->GetPositionZ(), me->GetOrientation(), TEMPSUMMON_TIMED_DESPAWN, 16000); } - void UpdateAI(const uint32 diff) + void UpdateAI(uint32 diff) { if (!UpdateVictim()) return; @@ -1553,7 +1556,7 @@ class mob_phoenix_egg_tk : public CreatureScript summoned->CastSpell(summoned, SPELL_REBIRTH, false); } - void UpdateAI(const uint32 diff) + void UpdateAI(uint32 diff) { if (!Rebirth_Timer) return; diff --git a/src/server/scripts/Outland/TempestKeep/Eye/boss_void_reaver.cpp b/src/server/scripts/Outland/TempestKeep/Eye/boss_void_reaver.cpp index 468c9ab1e75..d4526e52543 100644 --- a/src/server/scripts/Outland/TempestKeep/Eye/boss_void_reaver.cpp +++ b/src/server/scripts/Outland/TempestKeep/Eye/boss_void_reaver.cpp @@ -100,7 +100,7 @@ class boss_void_reaver : public CreatureScript instance->SetData(DATA_VOIDREAVEREVENT, IN_PROGRESS); } - void UpdateAI(const uint32 diff) + void UpdateAI(uint32 diff) { if (!UpdateVictim()) return; diff --git a/src/server/scripts/Outland/TempestKeep/Eye/the_eye.cpp b/src/server/scripts/Outland/TempestKeep/Eye/the_eye.cpp index d5e39d09301..fd00b2c5b4e 100644 --- a/src/server/scripts/Outland/TempestKeep/Eye/the_eye.cpp +++ b/src/server/scripts/Outland/TempestKeep/Eye/the_eye.cpp @@ -62,7 +62,7 @@ class mob_crystalcore_devastator : public CreatureScript { } - void UpdateAI(const uint32 diff) + void UpdateAI(uint32 diff) { if (!UpdateVictim()) return; diff --git a/src/server/scripts/Outland/TempestKeep/Mechanar/boss_gatewatcher_gyrokill.cpp b/src/server/scripts/Outland/TempestKeep/Mechanar/boss_gatewatcher_gyrokill.cpp index 3c72c8353aa..2b597be8a9f 100644 --- a/src/server/scripts/Outland/TempestKeep/Mechanar/boss_gatewatcher_gyrokill.cpp +++ b/src/server/scripts/Outland/TempestKeep/Mechanar/boss_gatewatcher_gyrokill.cpp @@ -1,6 +1,5 @@ /* * Copyright (C) 2008-2013 TrinityCore <http://www.trinitycore.org/> - * Copyright (C) 2006-2009 ScriptDev2 <https://scriptdev2.svn.sourceforge.net/> * * 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 @@ -17,26 +16,112 @@ */ /* ScriptData -SDName: Boss_Gatewatcher_Gyrokill -SD%Complete: 0 -SDComment: Place Holder +SDName: boss_gatewatcher_gyrokill +SD%Complete: 99% +SDComment: SDCategory: Tempest Keep, The Mechanar EndScriptData */ #include "ScriptMgr.h" #include "ScriptedCreature.h" +#include "mechanar.h" -//not used -#define SAY_AGGRO -1554000 -#define SAY_SAW_ATTACK1 -1554001 -#define SAY_SAW_ATTACK2 -1554002 -#define SAY_SLAY1 -1554003 -#define SAY_SLAY2 -1554004 -#define SAY_DEATH -1554005 +enum Say +{ + SAY_AGGRO = 0, + SAY_SLAY = 1, + SAY_SAW_BLADEs = 2, + SAY_DEATH = 3 +}; -#define SPELL_STREAM_OF_MACHINE_FLUID 35311 -#define SPELL_SAW_BLADE 35318 -#define H_SPELL_SAW_BLADE 39192 -#define SPELL_SHADOW_POWER 35322 -#define H_SPELL_SHADOW_POWER 39193 +enum Spells +{ + SPELL_STREAM_OF_MACHINE_FLUID = 35311, + SPELL_SAW_BLADE = 35318, + H_SPELL_SAW_BLADE = 39192, + SPELL_SHADOW_POWER = 35322, + H_SPELL_SHADOW_POWER = 39193 +}; +enum Events +{ + EVENT_STREAM_OF_MACHINE_FLUID = 0, + EVENT_SAW_BLADE = 1, + EVENT_SHADOW_POWER = 2 +}; + +class boss_gatewatcher_gyrokill : public CreatureScript +{ + public: + boss_gatewatcher_gyrokill() : CreatureScript("boss_gatewatcher_gyrokill") {} + + struct boss_gatewatcher_gyrokillAI : public BossAI + { + boss_gatewatcher_gyrokillAI(Creature* creature) : BossAI(creature, DATA_GATEWATCHER_GYROKILL) {} + + void JustDied(Unit* /*killer*/) + { + _JustDied(); + Talk(SAY_DEATH); + } + + void EnterCombat(Unit* /*who*/) + { + _EnterCombat(); + events.ScheduleEvent(EVENT_STREAM_OF_MACHINE_FLUID, 10000); + events.ScheduleEvent(EVENT_SAW_BLADE, 20000); + events.ScheduleEvent(EVENT_SHADOW_POWER, 25000); + Talk(SAY_AGGRO); + } + + void KilledUnit(Unit* /*victim*/) + { + Talk(SAY_SLAY); + } + + void UpdateAI(uint32 diff) + { + if (!UpdateVictim()) + return; + + events.Update(diff); + + if (me->HasUnitState(UNIT_STATE_CASTING)) + return; + + while (uint32 eventId = events.ExecuteEvent()) + { + switch (eventId) + { + case EVENT_STREAM_OF_MACHINE_FLUID: + DoCastVictim(SPELL_STREAM_OF_MACHINE_FLUID, true); + events.ScheduleEvent(EVENT_STREAM_OF_MACHINE_FLUID, urand(13000, 17000)); + break; + case EVENT_SAW_BLADE: + DoCast(me, SPELL_SAW_BLADE); + Talk(SAY_SAW_BLADEs); + events.ScheduleEvent(EVENT_SAW_BLADE, urand(20000, 30000)); + break; + case EVENT_SHADOW_POWER: + DoCast(me, SPELL_SHADOW_POWER); + events.ScheduleEvent(EVENT_SAW_BLADE, urand(25000, 35000)); + break; + default: + break; + } + } + + DoMeleeAttackIfReady(); + } + }; + + CreatureAI* GetAI(Creature* creature) const + { + return new boss_gatewatcher_gyrokillAI (creature); + } +}; + +void AddSC_boss_gatewatcher_gyrokill() +{ + new boss_gatewatcher_gyrokill(); +} diff --git a/src/server/scripts/Outland/TempestKeep/Mechanar/boss_gatewatcher_ironhand.cpp b/src/server/scripts/Outland/TempestKeep/Mechanar/boss_gatewatcher_ironhand.cpp index 09ff6cf8e49..5e29a8d0c31 100644 --- a/src/server/scripts/Outland/TempestKeep/Mechanar/boss_gatewatcher_ironhand.cpp +++ b/src/server/scripts/Outland/TempestKeep/Mechanar/boss_gatewatcher_ironhand.cpp @@ -25,8 +25,9 @@ EndScriptData */ #include "ScriptMgr.h" #include "ScriptedCreature.h" +#include "mechanar.h" -enum eSays +enum Says { SAY_AGGRO = 0, SAY_HAMMER = 1, @@ -35,111 +36,96 @@ enum eSays EMOTE_HAMMER = 4 }; -enum eSpells +enum Spells { - // Spells to be casted SPELL_SHADOW_POWER = 35322, H_SPELL_SHADOW_POWER = 39193, SPELL_HAMMER_PUNCH = 35326, SPELL_JACKHAMMER = 35327, H_SPELL_JACKHAMMER = 39194, - SPELL_STREAM_OF_MACHINE_FLUID = 35311, + SPELL_STREAM_OF_MACHINE_FLUID = 35311 +}; + +enum Events +{ + EVENT_STREAM_OF_MACHINE_FLUID = 0, + EVENT_JACKHAMMER = 1, + EVENT_SHADOW_POWER = 2 }; class boss_gatewatcher_iron_hand : public CreatureScript { public: + boss_gatewatcher_iron_hand(): CreatureScript("boss_gatewatcher_iron_hand") {} - boss_gatewatcher_iron_hand() - : CreatureScript("boss_gatewatcher_iron_hand") + struct boss_gatewatcher_iron_handAI : public BossAI { - } - // Gatewatcher Iron-Hand AI - struct boss_gatewatcher_iron_handAI : public ScriptedAI - { - boss_gatewatcher_iron_handAI(Creature* creature) : ScriptedAI(creature) - { - } - - uint32 Shadow_Power_Timer; - uint32 Jackhammer_Timer; - uint32 Stream_of_Machine_Fluid_Timer; - - void Reset() - { - Shadow_Power_Timer = 25000; - Jackhammer_Timer = 45000; - Stream_of_Machine_Fluid_Timer = 55000; + boss_gatewatcher_iron_handAI(Creature* creature) : BossAI(creature, DATA_GATEWATCHER_IRON_HAND) {} - } - void EnterCombat(Unit* /*who*/) - { - Talk(SAY_AGGRO); - } - - void KilledUnit(Unit* /*victim*/) - { - if (rand()%2) - return; + void EnterCombat(Unit* /*who*/) + { + _EnterCombat(); + events.ScheduleEvent(EVENT_STREAM_OF_MACHINE_FLUID, 55000); + events.ScheduleEvent(EVENT_JACKHAMMER, 45000); + events.ScheduleEvent(EVENT_SHADOW_POWER, 25000); + Talk(SAY_AGGRO); + } + void KilledUnit(Unit* /*victim*/) + { + if (roll_chance_i(50)) Talk(SAY_SLAY); - } - - void JustDied(Unit* /*killer*/) - { - Talk(SAY_DEATH); - //TODO: Add door check/open code - } - - void UpdateAI(const uint32 diff) - { - //Return since we have no target - if (!UpdateVictim()) - return; + } - //Shadow Power - if (Shadow_Power_Timer <= diff) - { - DoCast(me, SPELL_SHADOW_POWER); - Shadow_Power_Timer = urand(20000, 28000); - } - else - Shadow_Power_Timer -= diff; + void JustDied(Unit* /*killer*/) + { + _JustDied(); + Talk(SAY_DEATH); + } - //Jack Hammer - if (Jackhammer_Timer <= diff) - { - //TODO: expect cast this about 5 times in a row (?), announce it by emote only once - Talk(EMOTE_HAMMER); - DoCast(me->getVictim(), SPELL_JACKHAMMER); + void UpdateAI(uint32 diff) + { + if (!UpdateVictim()) + return; - //chance to yell, but not same time as emote (after spell in fact casted) - if (rand()%2) - return; + events.Update(diff); - Talk(SAY_HAMMER); - Jackhammer_Timer = 30000; - } - else - Jackhammer_Timer -= diff; + if (me->HasUnitState(UNIT_STATE_CASTING)) + return; - //Stream of Machine Fluid - if (Stream_of_Machine_Fluid_Timer <= diff) + while (uint32 eventId = events.ExecuteEvent()) + { + switch (eventId) { - DoCast(me->getVictim(), SPELL_STREAM_OF_MACHINE_FLUID); - Stream_of_Machine_Fluid_Timer = urand(35000, 50000); + case EVENT_STREAM_OF_MACHINE_FLUID: + DoCastVictim(SPELL_STREAM_OF_MACHINE_FLUID, true); + events.ScheduleEvent(EVENT_STREAM_OF_MACHINE_FLUID, urand(35000, 50000)); + break; + case EVENT_JACKHAMMER: + Talk(EMOTE_HAMMER); + /// @todo expect cast this about 5 times in a row (?), announce it by emote only once + DoCastVictim(SPELL_JACKHAMMER, true); + if (roll_chance_i(50)) + Talk(SAY_HAMMER); + events.ScheduleEvent(EVENT_JACKHAMMER, 30000); + break; + case EVENT_SHADOW_POWER: + DoCast(me, SPELL_SHADOW_POWER); + events.ScheduleEvent(EVENT_SHADOW_POWER, urand(20000, 28000)); + break; + default: + break; } - else - Stream_of_Machine_Fluid_Timer -= diff; - - DoMeleeAttackIfReady(); } - }; - CreatureAI* GetAI(Creature* creature) const - { - return new boss_gatewatcher_iron_handAI(creature); + DoMeleeAttackIfReady(); } + }; + + CreatureAI* GetAI(Creature* creature) const + { + return new boss_gatewatcher_iron_handAI(creature); + } }; void AddSC_boss_gatewatcher_iron_hand() diff --git a/src/server/scripts/Outland/TempestKeep/Mechanar/boss_mechano_lord_capacitus.cpp b/src/server/scripts/Outland/TempestKeep/Mechanar/boss_mechano_lord_capacitus.cpp index f8c44471b30..728b3f715b2 100644 --- a/src/server/scripts/Outland/TempestKeep/Mechanar/boss_mechano_lord_capacitus.cpp +++ b/src/server/scripts/Outland/TempestKeep/Mechanar/boss_mechano_lord_capacitus.cpp @@ -15,21 +15,144 @@ * with this program. If not, see <http://www.gnu.org/licenses/>. */ -//! TODO - Boss not scripted, just ported required spellscript from core - #include "ScriptMgr.h" #include "ScriptedCreature.h" #include "SpellScript.h" +#include "mechanar.h" #include "Player.h" enum Spells { + SPELL_HEADCRACK = 35161, + SPELL_REFLECTIVE_MAGIC_SHIELD = 35158, + SPELL_REFLECTIVE_DAMAGE_SHIELD = 35159, + SPELL_POLARITY_SHIFT = 39096, + SPELL_BERSERK = 26662, + SPELL_NETHER_CHARGE_TIMER = 37670, + SPELL_NETHER_CHARGE_PASSIVE = 37670, + SPELL_POSITIVE_POLARITY = 39088, SPELL_POSITIVE_CHARGE_STACK = 39089, SPELL_POSITIVE_CHARGE = 39090, + SPELL_NEGATIVE_POLARITY = 39091, SPELL_NEGATIVE_CHARGE_STACK = 39092, - SPELL_NEGATIVE_CHARGE = 39093, + SPELL_NEGATIVE_CHARGE = 39093 +}; + +enum Yells +{ + YELL_AGGRO = 0, + YELL_REFLECTIVE_MAGIC_SHIELD = 1, + YELL_REFLECTIVE_DAMAGE_SHIELD = 2, + YELL_KILL = 3, + YELL_DEATH = 4 +}; + +enum Creatures +{ + NPC_NETHER_CHARGE = 20405 +}; + +enum Events +{ + EVENT_NONE = 0, + + EVENT_HEADCRACK = 1, + EVENT_REFLECTIVE_DAMAGE_SHIELD = 2, + EVENT_REFLECTIVE_MAGIE_SHIELD = 3, + EVENT_POSITIVE_SHIFT = 4, + EVENT_SUMMON_NETHER_CHARGE = 5, + EVENT_BERSERK = 6 +}; + +class boss_mechano_lord_capacitus : public CreatureScript +{ + public: + boss_mechano_lord_capacitus() : CreatureScript("boss_mechano_lord_capacitus") { } + + struct boss_mechano_lord_capacitusAI : public BossAI + { + boss_mechano_lord_capacitusAI(Creature* creature) : BossAI(creature, DATA_MECHANOLORD_CAPACITUS) { } + + void EnterCombat(Unit* /*who*/) + { + _EnterCombat(); + Talk(YELL_AGGRO); + events.ScheduleEvent(EVENT_HEADCRACK, 10 * IN_MILLISECONDS); + events.ScheduleEvent(EVENT_REFLECTIVE_DAMAGE_SHIELD, 15 * IN_MILLISECONDS); + events.ScheduleEvent(EVENT_SUMMON_NETHER_CHARGE, 10 * IN_MILLISECONDS); + events.ScheduleEvent(EVENT_BERSERK, 3 * MINUTE * IN_MILLISECONDS); + + if (IsHeroic()) + events.ScheduleEvent(EVENT_POSITIVE_SHIFT, 15 * IN_MILLISECONDS); + } + + void KilledUnit(Unit* /*victim*/) + { + Talk(YELL_KILL); + } + + void JustDied(Unit* /*victim*/) + { + _JustDied(); + Talk(YELL_DEATH); + } + + void UpdateAI(uint32 diff) + { + if (!UpdateVictim()) + return; + + events.Update(diff); + + if (me->HasUnitState(UNIT_STATE_CASTING)) + return; + + while (uint32 eventId = events.ExecuteEvent()) + { + switch (eventId) + { + case EVENT_HEADCRACK: + DoCastVictim(SPELL_HEADCRACK); + events.ScheduleEvent(EVENT_HEADCRACK, 10 * IN_MILLISECONDS); + break; + case EVENT_REFLECTIVE_DAMAGE_SHIELD: + Talk(YELL_REFLECTIVE_DAMAGE_SHIELD); + DoCast(me, SPELL_REFLECTIVE_DAMAGE_SHIELD); + events.ScheduleEvent(EVENT_REFLECTIVE_MAGIE_SHIELD, 30 * IN_MILLISECONDS); + break; + case EVENT_REFLECTIVE_MAGIE_SHIELD: + Talk(YELL_REFLECTIVE_MAGIC_SHIELD); + DoCast(me, SPELL_REFLECTIVE_MAGIC_SHIELD); + events.ScheduleEvent(EVENT_REFLECTIVE_DAMAGE_SHIELD, 30 * IN_MILLISECONDS); + break; + case EVENT_POSITIVE_SHIFT: + DoCastAOE(SPELL_POLARITY_SHIFT); + events.ScheduleEvent(EVENT_POSITIVE_SHIFT, urand(45, 60) * IN_MILLISECONDS); + break; + case EVENT_SUMMON_NETHER_CHARGE: + Position pos; + me->GetRandomNearPosition(pos, 5.0f); + me->SummonCreature(NPC_NETHER_CHARGE, pos, TEMPSUMMON_TIMED_DESPAWN, 18000); + events.ScheduleEvent(EVENT_SUMMON_NETHER_CHARGE, 10 * IN_MILLISECONDS); + break; + case EVENT_BERSERK: + DoCast(me, SPELL_BERSERK); + break; + default: + break; + } + } + + DoMeleeAttackIfReady(); + } + }; + + CreatureAI* GetAI(Creature* creature) const + { + return new boss_mechano_lord_capacitusAI(creature); + } }; class spell_capacitus_polarity_charge : public SpellScriptLoader @@ -138,6 +261,7 @@ class spell_capacitus_polarity_shift : public SpellScriptLoader void AddSC_boss_mechano_lord_capacitus() { + new boss_mechano_lord_capacitus(); new spell_capacitus_polarity_charge(); new spell_capacitus_polarity_shift(); } diff --git a/src/server/scripts/Outland/TempestKeep/Mechanar/boss_nethermancer_sepethrea.cpp b/src/server/scripts/Outland/TempestKeep/Mechanar/boss_nethermancer_sepethrea.cpp index 5a9e551375b..902fb8e76b3 100644 --- a/src/server/scripts/Outland/TempestKeep/Mechanar/boss_nethermancer_sepethrea.cpp +++ b/src/server/scripts/Outland/TempestKeep/Mechanar/boss_nethermancer_sepethrea.cpp @@ -36,60 +36,45 @@ enum eSays SAY_DEATH = 4 }; -enum eSpells +enum Spells { - SPELL_SUMMON_RAGIN_FLAMES = 35275, + SPELL_SUMMON_RAGIN_FLAMES = 35275, // Not scripted SPELL_FROST_ATTACK = 35263, SPELL_ARCANE_BLAST = 35314, SPELL_DRAGONS_BREATH = 35250, SPELL_KNOCKBACK = 37317, SPELL_SOLARBURN = 35267, - H_SPELL_SUMMON_RAGIN_FLAMES = 39084, - SPELL_INFERNO = 35268, - H_SPELL_INFERNO = 39346, - SPELL_FIRE_TAIL = 35278, + H_SPELL_SUMMON_RAGIN_FLAMES = 39084, // Not scripted + SPELL_INFERNO = 35268, // Not scripted + H_SPELL_INFERNO = 39346, // Not scripted + SPELL_FIRE_TAIL = 35278 // Not scripted +}; + +enum Events +{ + EVENT_FROST_ATTACK = 0, + EVENT_ARCANE_BLAST = 1, + EVENT_DRAGONS_BREATH = 2, + EVENT_KNOCKBACK = 3, + EVENT_SOLARBURN = 4 }; class boss_nethermancer_sepethrea : public CreatureScript { - public: + public: boss_nethermancer_sepethrea(): CreatureScript("boss_nethermancer_sepethrea") {} - boss_nethermancer_sepethrea() - : CreatureScript("boss_nethermancer_sepethrea") + struct boss_nethermancer_sepethreaAI : public BossAI { - } - struct boss_nethermancer_sepethreaAI : public ScriptedAI - { - boss_nethermancer_sepethreaAI(Creature* creature) : ScriptedAI(creature) - { - instance = creature->GetInstanceScript(); - } - - InstanceScript* instance; - - uint32 frost_attack_Timer; - uint32 arcane_blast_Timer; - uint32 dragons_breath_Timer; - uint32 knockback_Timer; - uint32 solarburn_Timer; - - void Reset() - { - frost_attack_Timer = urand(7000, 10000); - arcane_blast_Timer = urand(12000, 18000); - dragons_breath_Timer = urand(18000, 22000); - knockback_Timer = urand(22000, 28000); - solarburn_Timer = 30000; - - if (instance) - instance->SetData(DATA_NETHERMANCER_EVENT, NOT_STARTED); - } + boss_nethermancer_sepethreaAI(Creature* creature) : BossAI(creature, DATA_NETHERMANCER_SEPRETHREA) {} void EnterCombat(Unit* who) { - if (instance) - instance->SetData(DATA_NETHERMANCER_EVENT, IN_PROGRESS); - + _EnterCombat(); + events.ScheduleEvent(EVENT_FROST_ATTACK, urand(7000, 10000)); + events.ScheduleEvent(EVENT_ARCANE_BLAST, urand(12000, 18000)); + events.ScheduleEvent(EVENT_DRAGONS_BREATH, urand(18000, 22000)); + events.ScheduleEvent(EVENT_KNOCKBACK, urand(22000, 28000)); + events.ScheduleEvent(EVENT_SOLARBURN, 30000); Talk(SAY_AGGRO); DoCast(who, SPELL_SUMMON_RAGIN_FLAMES); Talk(SAY_SUMMON); @@ -102,66 +87,50 @@ class boss_nethermancer_sepethrea : public CreatureScript void JustDied(Unit* /*killer*/) { + _JustDied(); Talk(SAY_DEATH); - if (instance) - instance->SetData(DATA_NETHERMANCER_EVENT, DONE); } - void UpdateAI(const uint32 diff) + void UpdateAI(uint32 diff) { - //Return since we have no target if (!UpdateVictim()) return; - //Frost Attack - if (frost_attack_Timer <= diff) - { - DoCast(me->getVictim(), SPELL_FROST_ATTACK); + events.Update(diff); - frost_attack_Timer = urand(7000, 10000); - } - else - frost_attack_Timer -= diff; + if (me->HasUnitState(UNIT_STATE_CASTING)) + return; - //Arcane Blast - if (arcane_blast_Timer <= diff) - { - DoCast(me->getVictim(), SPELL_ARCANE_BLAST); - arcane_blast_Timer = 15000; - } - else - arcane_blast_Timer -= diff; - //Dragons Breath - if (dragons_breath_Timer <= diff) + while (uint32 eventId = events.ExecuteEvent()) { - DoCast(me->getVictim(), SPELL_DRAGONS_BREATH); + switch (eventId) { - if (rand()%2) - return; - Talk(SAY_DRAGONS_BREATH); + case EVENT_FROST_ATTACK: + DoCastVictim(SPELL_FROST_ATTACK, true); + events.ScheduleEvent(EVENT_FROST_ATTACK, urand(7000, 10000)); + break; + case EVENT_ARCANE_BLAST: + DoCastVictim(SPELL_ARCANE_BLAST, true); + events.ScheduleEvent(EVENT_ARCANE_BLAST, 15000); + break; + case EVENT_DRAGONS_BREATH: + DoCastVictim(SPELL_DRAGONS_BREATH, true); + events.ScheduleEvent(EVENT_DRAGONS_BREATH, urand(12000, 22000)); + if (roll_chance_i(50)) + Talk(SAY_DRAGONS_BREATH); + break; + case EVENT_KNOCKBACK: + DoCastVictim(SPELL_KNOCKBACK, true); + events.ScheduleEvent(EVENT_KNOCKBACK, urand(15000, 25000)); + break; + case EVENT_SOLARBURN: + DoCastVictim(SPELL_SOLARBURN, true); + events.ScheduleEvent(EVENT_SOLARBURN, 30000); + break; + default: + break; } - dragons_breath_Timer = urand(12000, 22000); } - else - dragons_breath_Timer -= diff; - - //Knockback - if (knockback_Timer <= diff) - { - DoCast(me->getVictim(), SPELL_KNOCKBACK); - knockback_Timer = urand(15000, 25000); - } - else - knockback_Timer -= diff; - - //Solarburn - if (solarburn_Timer <= diff) - { - DoCast(me->getVictim(), SPELL_SOLARBURN); - solarburn_Timer = 30000; - } - else - solarburn_Timer -= diff; DoMeleeAttackIfReady(); } @@ -172,13 +141,11 @@ class boss_nethermancer_sepethrea : public CreatureScript return new boss_nethermancer_sepethreaAI(creature); } }; + class mob_ragin_flames : public CreatureScript { public: - mob_ragin_flames() - : CreatureScript("mob_ragin_flames") - { - } + mob_ragin_flames() : CreatureScript("mob_ragin_flames") { } struct mob_ragin_flamesAI : public ScriptedAI { @@ -210,14 +177,14 @@ class mob_ragin_flames : public CreatureScript { } - void UpdateAI(const uint32 diff) + void UpdateAI(uint32 diff) { //Check_Timer if (Check_Timer <= diff) { if (instance) { - if (instance->GetData(DATA_NETHERMANCER_EVENT) != IN_PROGRESS) + if (instance->GetData(DATA_NETHERMANCER_SEPRETHREA) != IN_PROGRESS) { //remove me->setDeathState(JUST_DIED); @@ -259,9 +226,9 @@ class mob_ragin_flames : public CreatureScript return new mob_ragin_flamesAI(creature); } }; + void AddSC_boss_nethermancer_sepethrea() { new boss_nethermancer_sepethrea(); new mob_ragin_flames(); } - diff --git a/src/server/scripts/Outland/TempestKeep/Mechanar/boss_pathaleon_the_calculator.cpp b/src/server/scripts/Outland/TempestKeep/Mechanar/boss_pathaleon_the_calculator.cpp index 41296daf1fa..65cd195fb80 100644 --- a/src/server/scripts/Outland/TempestKeep/Mechanar/boss_pathaleon_the_calculator.cpp +++ b/src/server/scripts/Outland/TempestKeep/Mechanar/boss_pathaleon_the_calculator.cpp @@ -25,8 +25,9 @@ EndScriptData */ #include "ScriptMgr.h" #include "ScriptedCreature.h" +#include "mechanar.h" -enum eSays +enum Says { SAY_AGGRO = 0, SAY_DOMINATION = 1, @@ -35,65 +36,53 @@ enum eSays SAY_SLAY = 4, SAY_DEATH = 5 }; -// Spells to be casted -enum eSpells + +enum Spells { SPELL_MANA_TAP = 36021, SPELL_ARCANE_TORRENT = 36022, SPELL_DOMINATION = 35280, H_SPELL_ARCANE_EXPLOSION = 15453, SPELL_FRENZY = 36992, - //Spells work, but not implemented - SPELL_SUMMON_NETHER_WRAITH_1 = 35285, - SPELL_SUMMON_NETHER_WRAITH_2 = 35286, - SPELL_SUMMON_NETHER_WRAITH_3 = 35287, - SPELL_SUMMON_NETHER_WRAITH_4 = 35288, - // Add Spells - SPELL_DETONATION = 35058, - SPELL_ARCANE_MISSILES = 35034, + SPELL_SUMMON_NETHER_WRAITH_1 = 35285, // Not scripted + SPELL_SUMMON_NETHER_WRAITH_2 = 35286, // Not scripted + SPELL_SUMMON_NETHER_WRAITH_3 = 35287, // Not scripted + SPELL_SUMMON_NETHER_WRAITH_4 = 35288, // Not scripted + SPELL_DETONATION = 35058, // Used by Nether Wraith + SPELL_ARCANE_MISSILES = 35034 // Used by Nether Wraith +}; + +enum Events +{ + EVENT_SUMMON = 0, + EVENT_MANA_TAP = 1, + EVENT_ARCANE_TORRENT = 2, + EVENT_DOMINATION = 3, + EVENT_ARCANE_EXPLOSION = 4 +}; + +enum Creatures +{ + NPC_NETHER_WRAITH = 21062 }; class boss_pathaleon_the_calculator : public CreatureScript { public: + boss_pathaleon_the_calculator(): CreatureScript("boss_pathaleon_the_calculator") {} - boss_pathaleon_the_calculator() - : CreatureScript("boss_pathaleon_the_calculator") - { - } - - struct boss_pathaleon_the_calculatorAI : public ScriptedAI + struct boss_pathaleon_the_calculatorAI : public BossAI { - boss_pathaleon_the_calculatorAI(Creature* creature) : ScriptedAI(creature), summons(me) - { - } + boss_pathaleon_the_calculatorAI(Creature* creature) : BossAI(creature, DATA_PATHALEON_THE_CALCULATOR) { } - uint32 Summon_Timer; - SummonList summons; - uint32 ManaTap_Timer; - uint32 ArcaneTorrent_Timer; - uint32 Domination_Timer; - uint32 ArcaneExplosion_Timer; - - bool Enraged; - - uint32 Counter; - - void Reset() - { - Summon_Timer = 30000; - ManaTap_Timer = urand(12000, 20000); - ArcaneTorrent_Timer = urand(16000, 25000); - Domination_Timer = urand(25000, 40000); - ArcaneExplosion_Timer = urand(8000, 13000); - - Enraged = false; - - Counter = 0; - summons.DespawnAll(); - } void EnterCombat(Unit* /*who*/) { + _EnterCombat(); + events.ScheduleEvent(EVENT_SUMMON, 30000); + events.ScheduleEvent(EVENT_MANA_TAP, urand(12000, 20000)); + events.ScheduleEvent(EVENT_ARCANE_TORRENT, urand(16000, 25000)); + events.ScheduleEvent(EVENT_DOMINATION, urand(25000, 40000)); + events.ScheduleEvent(EVENT_ARCANE_EXPLOSION, urand(8000, 13000)); Talk(SAY_AGGRO); } @@ -104,107 +93,82 @@ class boss_pathaleon_the_calculator : public CreatureScript void JustDied(Unit* /*killer*/) { + _JustDied(); Talk(SAY_DEATH); - - summons.DespawnAll(); } - void JustSummoned(Creature* summon) - { - summons.Summon(summon); - } - void SummonedCreatureDespawn(Creature* summon) + void DamageTaken(Unit* /*attacker*/, uint32& damage) { - summons.Despawn(summon); + if (me->HealthBelowPctDamaged(20, damage) && !me->HasAura(SPELL_FRENZY)) + { + DoCast(me, SPELL_FRENZY); + Talk(SAY_ENRAGE); + } } - void UpdateAI(const uint32 diff) + void UpdateAI(uint32 diff) { - //Return since we have no target if (!UpdateVictim()) return; - if (Summon_Timer <= diff) - { - for (uint8 i = 0; i < 3; ++i) - { - Unit* target = SelectTarget(SELECT_TARGET_RANDOM, 0); - Creature* Wraith = me->SummonCreature(21062, me->GetPositionX(), me->GetPositionY(), me->GetPositionZ(), 0, TEMPSUMMON_TIMED_DESPAWN_OUT_OF_COMBAT, 25000); - if (target && Wraith) - Wraith->AI()->AttackStart(target); - } - Talk(SAY_SUMMON); - Summon_Timer = urand(30000, 45000); - } - else - Summon_Timer -= diff; - - if (ManaTap_Timer <= diff) - { - DoCast(me->getVictim(), SPELL_MANA_TAP); - ManaTap_Timer = urand(14000, 22000); - } - else - ManaTap_Timer -= diff; + events.Update(diff); - if (ArcaneTorrent_Timer <= diff) - { - DoCast(me->getVictim(), SPELL_ARCANE_TORRENT); - ArcaneTorrent_Timer = urand(12000, 18000); - } - else - ArcaneTorrent_Timer -= diff; - - if (Domination_Timer <= diff) - { - if (Unit* target = SelectTarget(SELECT_TARGET_RANDOM, 1)) - { - Talk(SAY_DOMINATION); - DoCast(target, SPELL_DOMINATION); - } - Domination_Timer = urand(25000, 30000); - } - else - Domination_Timer -= diff; + if (me->HasUnitState(UNIT_STATE_CASTING)) + return; - //Only casting if Heroic Mode is used - if (IsHeroic()) + while (uint32 eventId = events.ExecuteEvent()) { - if (ArcaneExplosion_Timer <= diff) + switch (eventId) { - DoCast(me->getVictim(), H_SPELL_ARCANE_EXPLOSION); - ArcaneExplosion_Timer = urand(10000, 14000); + case EVENT_SUMMON: + for (uint8 i = 0; i < 3; ++i) + { + if (Unit* target = SelectTarget(SELECT_TARGET_RANDOM, 0)) + { + if (Creature* Wraith = me->SummonCreature(NPC_NETHER_WRAITH, me->GetPositionX(), me->GetPositionY(), me->GetPositionZ(), 0, TEMPSUMMON_TIMED_DESPAWN_OUT_OF_COMBAT, 25000)) + Wraith->AI()->AttackStart(target); + } + } + Talk(SAY_SUMMON); + events.ScheduleEvent(EVENT_SUMMON, urand(30000, 45000)); + break; + case EVENT_MANA_TAP: + DoCastVictim(SPELL_MANA_TAP, true); + events.ScheduleEvent(EVENT_MANA_TAP, urand(14000, 22000)); + break; + case EVENT_ARCANE_TORRENT: + DoCastVictim(SPELL_ARCANE_TORRENT, true); + events.ScheduleEvent(EVENT_ARCANE_TORRENT, urand(12000, 18000)); + break; + case EVENT_DOMINATION: + Talk(SAY_DOMINATION); + DoCastVictim(SPELL_DOMINATION, true); + events.ScheduleEvent(EVENT_DOMINATION, urand(25000, 30000)); + break; + case EVENT_ARCANE_EXPLOSION: // Heroic only + DoCastVictim(H_SPELL_ARCANE_EXPLOSION, true); + events.ScheduleEvent(EVENT_ARCANE_EXPLOSION, urand(10000, 14000)); + break; + default: + break; } - else - ArcaneExplosion_Timer -= diff; - } - - if (!Enraged && HealthBelowPct(21)) - { - DoCast(me, SPELL_FRENZY); - Talk(SAY_ENRAGE); - Enraged = true; - } DoMeleeAttackIfReady(); } }; - CreatureAI* GetAI(Creature* creature) const - { - return new boss_pathaleon_the_calculatorAI (creature); - } + CreatureAI* GetAI(Creature* creature) const + { + return new boss_pathaleon_the_calculatorAI (creature); + } }; class mob_nether_wraith : public CreatureScript { public: - mob_nether_wraith() - : CreatureScript("mob_nether_wraith") - { - } + mob_nether_wraith() : CreatureScript("mob_nether_wraith") { } struct mob_nether_wraithAI : public ScriptedAI { @@ -225,7 +189,7 @@ class mob_nether_wraith : public CreatureScript void EnterCombat(Unit* /*who*/) {} - void UpdateAI(const uint32 diff) + void UpdateAI(uint32 diff) { if (!UpdateVictim()) return; diff --git a/src/server/scripts/Outland/TempestKeep/Mechanar/instance_mechanar.cpp b/src/server/scripts/Outland/TempestKeep/Mechanar/instance_mechanar.cpp index 1f9ddfcdd0b..146569db284 100644 --- a/src/server/scripts/Outland/TempestKeep/Mechanar/instance_mechanar.cpp +++ b/src/server/scripts/Outland/TempestKeep/Mechanar/instance_mechanar.cpp @@ -16,68 +16,122 @@ * with this program. If not, see <http://www.gnu.org/licenses/>. */ -/* ScriptData -SDName: Instance_Mechanar -SD%Complete: 100 -SDComment: -SDCategory: Mechanar -EndScriptData */ #include "ScriptMgr.h" #include "InstanceScript.h" #include "mechanar.h" -#define MAX_ENCOUNTER 1 +static DoorData const doorData[] = +{ + { GO_DOOR_MOARG_1, DATA_GATEWATCHER_IRON_HAND, DOOR_TYPE_PASSAGE, BOUNDARY_NONE }, + { GO_DOOR_MOARG_2, DATA_GATEWATCHER_GYROKILL, DOOR_TYPE_PASSAGE, BOUNDARY_NONE }, + { GO_DOOR_NETHERMANCER, DATA_NETHERMANCER_SEPRETHREA, DOOR_TYPE_ROOM, BOUNDARY_NONE }, + {0, 0, DOOR_TYPE_ROOM, BOUNDARY_NONE } +}; class instance_mechanar : public InstanceMapScript { public: - instance_mechanar() - : InstanceMapScript("instance_mechanar", 554) - { - } + instance_mechanar(): InstanceMapScript("instance_mechanar", 554) { } struct instance_mechanar_InstanceMapScript : public InstanceScript { - instance_mechanar_InstanceMapScript(Map* map) : InstanceScript(map) {} + instance_mechanar_InstanceMapScript(Map* map) : InstanceScript(map) + { + SetBossNumber(EncounterCount); + LoadDoorData(doorData); + } - uint32 m_auiEncounter[MAX_ENCOUNTER]; - void Initialize() + void OnGameObjectCreate(GameObject* gameObject) { - memset(&m_auiEncounter, 0, sizeof(m_auiEncounter)); + switch (gameObject->GetEntry()) + { + case GO_DOOR_MOARG_1: + case GO_DOOR_MOARG_2: + case GO_DOOR_NETHERMANCER: + AddDoor(gameObject, true); + break; + default: + break; + } } - bool IsEncounterInProgress() const + void OnGameObjectRemove(GameObject* gameObject) { - for (uint8 i = 0; i < MAX_ENCOUNTER; ++i) - if (m_auiEncounter[i] == IN_PROGRESS) - return true; - - return false; + switch (gameObject->GetEntry()) + { + case GO_DOOR_MOARG_1: + case GO_DOOR_MOARG_2: + case GO_DOOR_NETHERMANCER: + AddDoor(gameObject, false); + break; + default: + break; + } } - uint32 GetData(uint32 type) const + bool SetBossState(uint32 type, EncounterState state) { + if (!InstanceScript::SetBossState(type, state)) + return false; + switch (type) { - case DATA_NETHERMANCER_EVENT: return m_auiEncounter[0]; + case DATA_GATEWATCHER_GYROKILL: + case DATA_GATEWATCHER_IRON_HAND: + case DATA_MECHANOLORD_CAPACITUS: + case DATA_NETHERMANCER_SEPRETHREA: + case DATA_PATHALEON_THE_CALCULATOR: + break; + default: + break; } - return false; + return true; } - uint64 GetData64(uint32 /*identifier*/) const + std::string GetSaveData() { - return 0; + OUT_SAVE_INST_DATA; + + std::ostringstream saveStream; + saveStream << "M C " << GetBossSaveData(); + + OUT_SAVE_INST_DATA_COMPLETE; + return saveStream.str(); } - void SetData(uint32 type, uint32 data) + void Load(const char* str) { - switch (type) + if (!str) { - case DATA_NETHERMANCER_EVENT: m_auiEncounter[0] = data; break; + OUT_LOAD_INST_DATA_FAIL; + return; } + + OUT_LOAD_INST_DATA(str); + + char dataHead1, dataHead2; + + std::istringstream loadStream(str); + loadStream >> dataHead1 >> dataHead2; + + if (dataHead1 == 'M' && dataHead2 == 'C') + { + for (uint32 i = 0; i < EncounterCount; ++i) + { + uint32 tmpState; + loadStream >> tmpState; + if (tmpState == IN_PROGRESS || tmpState > SPECIAL) + tmpState = NOT_STARTED; + SetBossState(i, EncounterState(tmpState)); + } + } + else + OUT_LOAD_INST_DATA_FAIL; + + OUT_LOAD_INST_DATA_COMPLETE; } }; @@ -89,6 +143,5 @@ class instance_mechanar : public InstanceMapScript void AddSC_instance_mechanar() { - new instance_mechanar; + new instance_mechanar(); } - diff --git a/src/server/scripts/Outland/TempestKeep/Mechanar/mechanar.h b/src/server/scripts/Outland/TempestKeep/Mechanar/mechanar.h index c933c90afef..0d3a4ea241d 100644 --- a/src/server/scripts/Outland/TempestKeep/Mechanar/mechanar.h +++ b/src/server/scripts/Outland/TempestKeep/Mechanar/mechanar.h @@ -1,6 +1,5 @@ /* * Copyright (C) 2008-2013 TrinityCore <http://www.trinitycore.org/> - * Copyright (C) 2006-2009 ScriptDev2 <https://scriptdev2.svn.sourceforge.net/> * * 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 @@ -19,6 +18,22 @@ #ifndef DEF_MECHANAR_H #define DEF_MECHANAR_H -#define DATA_NETHERMANCER_EVENT 1 -#endif +uint32 const EncounterCount = 5; + +enum DataTypes +{ + DATA_GATEWATCHER_GYROKILL = 0, + DATA_GATEWATCHER_IRON_HAND = 1, + DATA_MECHANOLORD_CAPACITUS = 2, + DATA_NETHERMANCER_SEPRETHREA = 3, + DATA_PATHALEON_THE_CALCULATOR = 4 +}; +enum GameobjectIds +{ + GO_DOOR_MOARG_1 = 184632, + GO_DOOR_MOARG_2 = 184322, + GO_DOOR_NETHERMANCER = 184449 +}; + +#endif diff --git a/src/server/scripts/Outland/TempestKeep/arcatraz/arcatraz.cpp b/src/server/scripts/Outland/TempestKeep/arcatraz/arcatraz.cpp index cd3fb897181..2fc0b475cdf 100644 --- a/src/server/scripts/Outland/TempestKeep/arcatraz/arcatraz.cpp +++ b/src/server/scripts/Outland/TempestKeep/arcatraz/arcatraz.cpp @@ -19,7 +19,7 @@ /* ScriptData SDName: Arcatraz SD%Complete: 60 -SDComment: Warden Mellichar, event controller for Skyriss event. Millhouse Manastorm. TODO: make better combatAI for Millhouse. +SDComment: Warden Mellichar, event controller for Skyriss event. Millhouse Manastorm. @todo make better combatAI for Millhouse. SDCategory: Tempest Keep, The Arcatraz EndScriptData */ @@ -138,7 +138,7 @@ class npc_millhouse_manastorm : public CreatureScript ->FailQuest();*/ } - void UpdateAI(const uint32 diff) + void UpdateAI(uint32 diff) { if (!Init) { @@ -398,7 +398,7 @@ class npc_warden_mellichar : public CreatureScript } } - void UpdateAI(const uint32 diff) + void UpdateAI(uint32 diff) { if (!IsRunning) return; diff --git a/src/server/scripts/Outland/TempestKeep/arcatraz/boss_harbinger_skyriss.cpp b/src/server/scripts/Outland/TempestKeep/arcatraz/boss_harbinger_skyriss.cpp index 141257dae63..c6f47fe8de7 100644 --- a/src/server/scripts/Outland/TempestKeep/arcatraz/boss_harbinger_skyriss.cpp +++ b/src/server/scripts/Outland/TempestKeep/arcatraz/boss_harbinger_skyriss.cpp @@ -152,7 +152,7 @@ class boss_harbinger_skyriss : public CreatureScript DoCast(me, SPELL_33_ILLUSION); } - void UpdateAI(const uint32 diff) + void UpdateAI(uint32 diff) { if (!Intro) { diff --git a/src/server/scripts/Outland/TempestKeep/botanica/boss_commander_sarannis.cpp b/src/server/scripts/Outland/TempestKeep/botanica/boss_commander_sarannis.cpp index 20531f1f110..6775fb95824 100644 --- a/src/server/scripts/Outland/TempestKeep/botanica/boss_commander_sarannis.cpp +++ b/src/server/scripts/Outland/TempestKeep/botanica/boss_commander_sarannis.cpp @@ -93,7 +93,7 @@ class boss_commander_sarannis : public CreatureScript BossAI::JustSummoned(summon); } - void UpdateAI(uint32 const diff) + void UpdateAI(uint32 diff) { if (!UpdateVictim()) return; diff --git a/src/server/scripts/Outland/TempestKeep/botanica/boss_high_botanist_freywinn.cpp b/src/server/scripts/Outland/TempestKeep/botanica/boss_high_botanist_freywinn.cpp index 2ab527c2fd5..39ca6d32196 100644 --- a/src/server/scripts/Outland/TempestKeep/botanica/boss_high_botanist_freywinn.cpp +++ b/src/server/scripts/Outland/TempestKeep/botanica/boss_high_botanist_freywinn.cpp @@ -114,7 +114,7 @@ class boss_high_botanist_freywinn : public CreatureScript Talk(SAY_DEATH); } - void UpdateAI(const uint32 diff) + void UpdateAI(uint32 diff) { if (!UpdateVictim()) return; diff --git a/src/server/scripts/Outland/TempestKeep/botanica/boss_laj.cpp b/src/server/scripts/Outland/TempestKeep/botanica/boss_laj.cpp index bd9195e44f8..7b4ef77ac10 100644 --- a/src/server/scripts/Outland/TempestKeep/botanica/boss_laj.cpp +++ b/src/server/scripts/Outland/TempestKeep/botanica/boss_laj.cpp @@ -167,7 +167,7 @@ class boss_laj : public CreatureScript summon->AI()->AttackStart(SelectTarget(SELECT_TARGET_RANDOM, 0)); } - void UpdateAI(const uint32 diff) + void UpdateAI(uint32 diff) { if (!UpdateVictim()) return; diff --git a/src/server/scripts/Outland/TempestKeep/botanica/boss_thorngrin_the_tender.cpp b/src/server/scripts/Outland/TempestKeep/botanica/boss_thorngrin_the_tender.cpp index ffd48f4dcb5..70b626190b7 100644 --- a/src/server/scripts/Outland/TempestKeep/botanica/boss_thorngrin_the_tender.cpp +++ b/src/server/scripts/Outland/TempestKeep/botanica/boss_thorngrin_the_tender.cpp @@ -95,7 +95,7 @@ class boss_thorngrin_the_tender : public CreatureScript } } - void UpdateAI(uint32 const diff) + void UpdateAI(uint32 diff) { if (!UpdateVictim()) return; diff --git a/src/server/scripts/Outland/TempestKeep/botanica/boss_warp_splinter.cpp b/src/server/scripts/Outland/TempestKeep/botanica/boss_warp_splinter.cpp index d2b6c44ec7b..1275550a340 100644 --- a/src/server/scripts/Outland/TempestKeep/botanica/boss_warp_splinter.cpp +++ b/src/server/scripts/Outland/TempestKeep/botanica/boss_warp_splinter.cpp @@ -90,7 +90,7 @@ class mob_warp_splinter_treant : public CreatureScript void MoveInLineOfSight(Unit* /*who*/) {} - void UpdateAI(const uint32 diff) + void UpdateAI(uint32 diff) { if (!UpdateVictim()) { @@ -190,7 +190,7 @@ class boss_warp_splinter : public CreatureScript Talk(SAY_SUMMON); } - void UpdateAI(const uint32 diff) + void UpdateAI(uint32 diff) { if (!UpdateVictim()) return; diff --git a/src/server/scripts/Outland/boss_doomlord_kazzak.cpp b/src/server/scripts/Outland/boss_doomlord_kazzak.cpp index 8886e3e41f0..0e66893d3ac 100644 --- a/src/server/scripts/Outland/boss_doomlord_kazzak.cpp +++ b/src/server/scripts/Outland/boss_doomlord_kazzak.cpp @@ -108,7 +108,7 @@ class boss_doomlord_kazzak : public CreatureScript Talk(SAY_DEATH); } - void UpdateAI(uint32 const diff) + void UpdateAI(uint32 diff) { // Return since we have no target if (!UpdateVictim()) diff --git a/src/server/scripts/Outland/boss_doomwalker.cpp b/src/server/scripts/Outland/boss_doomwalker.cpp index 9826900d246..33896800ada 100644 --- a/src/server/scripts/Outland/boss_doomwalker.cpp +++ b/src/server/scripts/Outland/boss_doomwalker.cpp @@ -97,7 +97,7 @@ class boss_doomwalker : public CreatureScript who->CastSpell(who, SPELL_AURA_DEATH, 1); } - void UpdateAI(const uint32 diff) + void UpdateAI(uint32 diff) { if (!UpdateVictim()) return; diff --git a/src/server/scripts/Outland/zone_blades_edge_mountains.cpp b/src/server/scripts/Outland/zone_blades_edge_mountains.cpp index d03abc82b9c..91d9eb53506 100644 --- a/src/server/scripts/Outland/zone_blades_edge_mountains.cpp +++ b/src/server/scripts/Outland/zone_blades_edge_mountains.cpp @@ -54,7 +54,7 @@ bool obelisk_one, obelisk_two, obelisk_three, obelisk_four, obelisk_five; ## mobs_bladespire_ogre ######*/ -//TODO: add support for quest 10512 + Creature abilities +/// @todo add support for quest 10512 + Creature abilities class mobs_bladespire_ogre : public CreatureScript { public: @@ -71,7 +71,7 @@ public: void Reset() { } - void UpdateAI(const uint32 /*uiDiff*/) + void UpdateAI(uint32 /*uiDiff*/) { if (!UpdateVictim()) return; @@ -195,7 +195,7 @@ public: } } - void UpdateAI(const uint32 diff) + void UpdateAI(uint32 diff) { if (IsNihil) { @@ -296,7 +296,7 @@ public: if (who->HasAura(SPELL_LASHHAN_CHANNEL) && me->IsWithinDistInMap(who, 10.0f)) { Talk(SAY_SPELL_INFLUENCE, who->GetGUID()); - //TODO: Move the below to updateAI and run if this statement == true + /// @todo Move the below to updateAI and run if this statement == true DoCast(who, 37028, true); } } @@ -468,7 +468,7 @@ public: OgreGUID = 0; } - void UpdateAI(const uint32 /*uiDiff*/) {} + void UpdateAI(uint32 /*uiDiff*/) {} }; }; @@ -528,7 +528,7 @@ public: } } - void UpdateAI(const uint32 /*diff*/) + void UpdateAI(uint32 /*diff*/) { if (!UpdateVictim()) return; @@ -654,7 +654,7 @@ class npc_simon_bunny : public CreatureScript EventMap _events; std::list<uint8> colorSequence, playableSequence, playerSequence; - void UpdateAI(const uint32 diff) + void UpdateAI(uint32 diff) { _events.Update(diff); @@ -708,7 +708,7 @@ class npc_simon_bunny : public CreatureScript } } - void DoAction(const int32 action) + void DoAction(int32 action) { switch (action) { diff --git a/src/server/scripts/Outland/zone_hellfire_peninsula.cpp b/src/server/scripts/Outland/zone_hellfire_peninsula.cpp index 64b484268df..e950547ac30 100644 --- a/src/server/scripts/Outland/zone_hellfire_peninsula.cpp +++ b/src/server/scripts/Outland/zone_hellfire_peninsula.cpp @@ -86,7 +86,7 @@ public: Talk(SAY_SUMMON); } - void UpdateAI(const uint32 diff) + void UpdateAI(uint32 diff) { if (Faction_Timer) { @@ -487,7 +487,7 @@ public: } } - void UpdateAI(const uint32 uiDiff) + void UpdateAI(uint32 uiDiff) { if (uiCheckTimer <= uiDiff) { diff --git a/src/server/scripts/Outland/zone_nagrand.cpp b/src/server/scripts/Outland/zone_nagrand.cpp index 0a92b985c95..fd193aa4835 100644 --- a/src/server/scripts/Outland/zone_nagrand.cpp +++ b/src/server/scripts/Outland/zone_nagrand.cpp @@ -274,7 +274,7 @@ public: } } - void UpdateAI(const uint32 uiDiff) + void UpdateAI(uint32 uiDiff) { npc_escortAI::UpdateAI(uiDiff); if (!me->getVictim()) @@ -445,7 +445,7 @@ public: ReleasedFromCage = false; } - void UpdateAI(uint32 const diff) + void UpdateAI(uint32 diff) { if (ReleasedFromCage) { @@ -628,7 +628,7 @@ public: } } - void UpdateAI(const uint32 diff) + void UpdateAI(uint32 diff) { if (!UpdateVictim()) return; @@ -639,7 +639,7 @@ public: if (ChainLightningTimer <= diff) { DoCast(me->getVictim(), SPELL_KUR_CHAIN_LIGHTNING); - ChainLightningTimer = urand(7000,14000); + ChainLightningTimer = urand(7000, 14000); } else ChainLightningTimer -= diff; if (HealthBelowPct(30)) @@ -654,7 +654,7 @@ public: if (FrostShockTimer <= diff) { DoCast(me->getVictim(), SPELL_KUR_FROST_SHOCK); - FrostShockTimer = urand(7500,15000); + FrostShockTimer = urand(7500, 15000); } else FrostShockTimer -= diff; DoMeleeAttackIfReady(); diff --git a/src/server/scripts/Outland/zone_netherstorm.cpp b/src/server/scripts/Outland/zone_netherstorm.cpp index 769ee7dc68d..779ab3261ed 100644 --- a/src/server/scripts/Outland/zone_netherstorm.cpp +++ b/src/server/scripts/Outland/zone_netherstorm.cpp @@ -237,7 +237,7 @@ public: } } - void UpdateAI(const uint32 diff) + void UpdateAI(uint32 diff) { if (Event_Timer <= diff) { @@ -305,7 +305,7 @@ public: ## go_manaforge_control_console ######*/ -//TODO: clean up this workaround when Trinity adds support to do it properly (with gossip selections instead of instant summon) +/// @todo clean up this workaround when Trinity adds support to do it properly (with gossip selections instead of instant summon) class go_manaforge_control_console : public GameObjectScript { public: @@ -506,7 +506,7 @@ public: return false; } - void UpdateAI(const uint32 diff) + void UpdateAI(uint32 diff) { //Is event even running? if (!isEvent) @@ -784,7 +784,7 @@ public: // DoCast(me, SPELL_DE_MATERIALIZE); //} - void UpdateAI(const uint32 diff) + void UpdateAI(uint32 diff) { if (!Materialize) { @@ -997,7 +997,7 @@ public: player->FailQuest(QUEST_MARK_V_IS_ALIVE); } - void UpdateAI(const uint32 uiDiff) + void UpdateAI(uint32 uiDiff) { npc_escortAI::UpdateAI(uiDiff); diff --git a/src/server/scripts/Outland/zone_shadowmoon_valley.cpp b/src/server/scripts/Outland/zone_shadowmoon_valley.cpp index 0a016f0923c..b8f96e373f3 100644 --- a/src/server/scripts/Outland/zone_shadowmoon_valley.cpp +++ b/src/server/scripts/Outland/zone_shadowmoon_valley.cpp @@ -126,7 +126,7 @@ public: } } - void UpdateAI(const uint32 diff) + void UpdateAI(uint32 diff) { if (bCanEat || bIsEating) { @@ -280,7 +280,7 @@ public: } } - void UpdateAI(const uint32 diff) + void UpdateAI(uint32 diff) { if (!UpdateVictim()) { @@ -385,7 +385,7 @@ public: } } - void UpdateAI(const uint32 diff) + void UpdateAI(uint32 diff) { if (PoisonTimer) { @@ -661,6 +661,7 @@ class npc_karynaku : public CreatureScript /*#### # npc_overlord_morghor +# this whole script is wrong and needs a rewrite.even the illidan npc used is the wrong one.npc id 23467 may be the correct one ####*/ enum eOverlordData { @@ -766,7 +767,7 @@ public: Player* player = Unit::GetPlayer(*me, PlayerGUID); Creature* Illi = Creature::GetCreature(*me, IllidanGUID); - if (!player || !Illi) + if (!player) { EnterEvadeMode(); return 0; @@ -794,14 +795,21 @@ public: return 2000; break; case 5: - Illi->SetVisible(true); - Illi->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE); + if (Illi) + { + Illi->SetVisible(true); + Illi->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE); + Illi->SetDisplayId(21526); + } return 350; break; case 6: - Illi->CastSpell(Illi, SPELL_ONE, true); - Illi->SetTarget(me->GetGUID()); - me->SetTarget(IllidanGUID); + if (Illi) + { + Illi->CastSpell(Illi, SPELL_ONE, true); + Illi->SetTarget(me->GetGUID()); + me->SetTarget(IllidanGUID); + } return 2000; break; case 7: @@ -810,10 +818,15 @@ public: break; case 8: me->SetUInt32Value(UNIT_FIELD_BYTES_1, 8); - return 9000; + return 2500; + break; + case 9: + // missing text "Lord Illidan, this is the Dragonmaw that I, and others, have told you about. He will lead us to victory!" + return 5000; break; case 10: - Illi->AI()->Talk(LORD_ILLIDAN_SAY_1); + if (Illi) + Illi->AI()->Talk(LORD_ILLIDAN_SAY_1); return 5000; break; case 11: @@ -821,42 +834,53 @@ public: return 6000; break; case 12: - Illi->AI()->Talk(LORD_ILLIDAN_SAY_2); + if (Illi) + Illi->AI()->Talk(LORD_ILLIDAN_SAY_2); return 5500; break; case 13: - Illi->AI()->Talk(LORD_ILLIDAN_SAY_3); + if (Illi) + Illi->AI()->Talk(LORD_ILLIDAN_SAY_3); return 4000; break; case 14: - Illi->SetTarget(PlayerGUID); + if (Illi) + Illi->SetTarget(PlayerGUID); return 1500; break; case 15: - Illi->AI()->Talk(LORD_ILLIDAN_SAY_4); + if (Illi) + Illi->AI()->Talk(LORD_ILLIDAN_SAY_4); return 1500; break; case 16: - Illi->CastSpell(player, SPELL_TWO, true); + if (Illi) + Illi->CastSpell(player, SPELL_TWO, true); player->RemoveAurasDueToSpell(SPELL_THREE); player->RemoveAurasDueToSpell(SPELL_FOUR); return 5000; break; case 17: - Illi->AI()->Talk(LORD_ILLIDAN_SAY_5); + if (Illi) + Illi->AI()->Talk(LORD_ILLIDAN_SAY_5); return 5000; break; case 18: - Illi->AI()->Talk(LORD_ILLIDAN_SAY_6); + if (Illi) + Illi->AI()->Talk(LORD_ILLIDAN_SAY_6); return 5000; break; case 19: - Illi->AI()->Talk(LORD_ILLIDAN_SAY_7); + if (Illi) + Illi->AI()->Talk(LORD_ILLIDAN_SAY_7); return 5000; break; case 20: - Illi->HandleEmoteCommand(EMOTE_ONESHOT_LIFTOFF); - Illi->SetDisableGravity(true); + if (Illi) + { + Illi->HandleEmoteCommand(EMOTE_ONESHOT_LIFTOFF); + Illi->SetDisableGravity(true); + } return 500; break; case 21: @@ -864,8 +888,11 @@ public: return 500; break; case 22: - Illi->SetVisible(false); - Illi->setDeathState(JUST_DIED); + if (Illi) + { + Illi->SetVisible(false); + Illi->setDeathState(JUST_DIED); + } return 1000; break; case 23: @@ -886,7 +913,7 @@ public: break; case 27: { - Unit* Yarzill = me->FindNearestCreature(C_YARZILL, 50); + Unit* Yarzill = me->FindNearestCreature(C_YARZILL, 50.0f); if (Yarzill) Yarzill->SetTarget(PlayerGUID); return 500; @@ -921,9 +948,11 @@ public: } break; case 32: - me->GetMotionMaster()->MovePoint(0, -5085.77f, 577.231f, 86.6719f); return 5000; + me->GetMotionMaster()->MovePoint(0, -5085.77f, 577.231f, 86.6719f); + return 5000; break; case 33: + me->SetTarget(0); Reset(); return 100; break; @@ -933,14 +962,14 @@ public: } } - void UpdateAI(const uint32 diff) + void UpdateAI(uint32 diff) { if (!ConversationTimer) return; if (ConversationTimer <= diff) { - if (Event && IllidanGUID && PlayerGUID) + if (Event && PlayerGUID) ConversationTimer = NextStep(++Step); } else ConversationTimer -= diff; } @@ -1096,14 +1125,14 @@ public: } } - void UpdateAI(const uint32 uiDiff) + void UpdateAI(uint32 uiDiff) { npc_escortAI::UpdateAI(uiDiff); if (!UpdateVictim()) return; - //TODO: add more abilities + /// @todo add more abilities if (!HealthAbovePct(30)) { if (m_uiHealingTimer <= uiDiff) @@ -1297,7 +1326,7 @@ public: ++AnimationCount; } - void UpdateAI(const uint32 diff) + void UpdateAI(uint32 diff) { if (AnimationTimer) { @@ -1485,7 +1514,7 @@ public: Announced = false; } - void UpdateAI(const uint32 diff) + void UpdateAI(uint32 diff) { if (!PlayerGUID || !EventStarted) return; @@ -1552,7 +1581,7 @@ public: CAST_AI(npc_lord_illidan_stormrage::npc_lord_illidan_stormrageAI, LordIllidan->AI())->LiveCounter(); } - void UpdateAI(const uint32 diff) + void UpdateAI(uint32 diff) { if (!UpdateVictim()) return; @@ -1862,16 +1891,11 @@ class spell_unlocking_zuluheds_chains : public SpellScriptLoader { PrepareSpellScript(spell_unlocking_zuluheds_chains_SpellScript); - bool Load() - { - return GetCaster()->GetTypeId() == TYPEID_PLAYER; - } - void HandleAfterHit() { - Player* caster = GetCaster()->ToPlayer(); - if (caster->GetQuestStatus(QUEST_ZULUHED) == QUEST_STATUS_INCOMPLETE) - caster->KilledMonsterCredit(NPC_KARYNAKU, 0); + if (GetCaster()->GetTypeId() == TYPEID_PLAYER) + if (Creature* karynaku = GetCaster()->FindNearestCreature(NPC_KARYNAKU, 15.0f)) + GetCaster()->ToPlayer()->CastedCreatureOrGO(NPC_KARYNAKU, karynaku->GetGUID(), GetSpellInfo()->Id); } void Register() @@ -1946,7 +1970,7 @@ public: } } - void UpdateAI(const uint32 diff) + void UpdateAI(uint32 diff) { if (tapped) { diff --git a/src/server/scripts/Outland/zone_shattrath_city.cpp b/src/server/scripts/Outland/zone_shattrath_city.cpp index ac26614ae69..14553be0ef4 100644 --- a/src/server/scripts/Outland/zone_shattrath_city.cpp +++ b/src/server/scripts/Outland/zone_shattrath_city.cpp @@ -101,7 +101,7 @@ public: me->RestoreFaction(); } - void UpdateAI(const uint32 diff) + void UpdateAI(uint32 diff) { if (!UpdateVictim()) return; @@ -176,7 +176,7 @@ public: } } - void UpdateAI(const uint32 diff) + void UpdateAI(uint32 diff) { if (!UpdateVictim()) return; @@ -519,7 +519,7 @@ public: void EnterCombat(Unit* /*who*/){} - void UpdateAI(const uint32 diff) + void UpdateAI(uint32 diff) { if (SayTimer <= diff) { diff --git a/src/server/scripts/Outland/zone_terokkar_forest.cpp b/src/server/scripts/Outland/zone_terokkar_forest.cpp index 2b046a7518e..caa31ed472c 100644 --- a/src/server/scripts/Outland/zone_terokkar_forest.cpp +++ b/src/server/scripts/Outland/zone_terokkar_forest.cpp @@ -125,7 +125,7 @@ public: } } - void UpdateAI(const uint32 diff) + void UpdateAI(uint32 diff) { if (CanDoQuest) { @@ -244,7 +244,7 @@ public: void Reset() {} - void UpdateAI(const uint32 diff) + void UpdateAI(uint32 diff) { npc_escortAI::UpdateAI(diff); } @@ -416,7 +416,7 @@ public: void EnterCombat(Unit* /*who*/) {} - void UpdateAI(const uint32 diff) + void UpdateAI(uint32 diff) { if (!UpdateVictim()) return; diff --git a/src/server/scripts/Outland/zone_zangarmarsh.cpp b/src/server/scripts/Outland/zone_zangarmarsh.cpp index 319da372bf8..b4899189af5 100644 --- a/src/server/scripts/Outland/zone_zangarmarsh.cpp +++ b/src/server/scripts/Outland/zone_zangarmarsh.cpp @@ -192,7 +192,7 @@ public: void EnterCombat(Unit* /*who*/) {} - void UpdateAI(const uint32 diff) + void UpdateAI(uint32 diff) { if (!UpdateVictim()) return; diff --git a/src/server/scripts/Spells/spell_dk.cpp b/src/server/scripts/Spells/spell_dk.cpp index 4bd619155ac..ea8fb5795bd 100644 --- a/src/server/scripts/Spells/spell_dk.cpp +++ b/src/server/scripts/Spells/spell_dk.cpp @@ -28,21 +28,32 @@ enum DeathKnightSpells { - DK_SPELL_RUNIC_POWER_ENERGIZE = 49088, - DK_SPELL_ANTI_MAGIC_SHELL_TALENT = 51052, - DK_SPELL_CORPSE_EXPLOSION_TRIGGERED = 43999, - DK_SPELL_CORPSE_EXPLOSION_VISUAL = 51270, - DK_SPELL_GHOUL_EXPLODE = 47496, - DK_SPELL_SCOURGE_STRIKE_TRIGGERED = 70890, - DK_SPELL_BLOOD_BOIL_TRIGGERED = 65658, - DK_SPELL_WILL_OF_THE_NECROPOLIS_TALENT_R1 = 49189, - DK_SPELL_WILL_OF_THE_NECROPOLIS_AURA_R1 = 52284, - DK_SPELL_BLOOD_PRESENCE = 48266, - DK_SPELL_IMPROVED_BLOOD_PRESENCE_TRIGGERED = 63611, - DK_SPELL_UNHOLY_PRESENCE = 48265, - DK_SPELL_IMPROVED_UNHOLY_PRESENCE_TRIGGERED = 63622, + SPELL_DK_ANTI_MAGIC_SHELL_TALENT = 51052, + SPELL_DK_BLACK_ICE_R1 = 49140, + SPELL_DK_BLOOD_BOIL_TRIGGERED = 65658, + SPELL_DK_BLOOD_GORGED_HEAL = 50454, + SPELL_DK_CORPSE_EXPLOSION_TRIGGERED = 43999, + SPELL_DK_CORPSE_EXPLOSION_VISUAL = 51270, + SPELL_DK_DEATH_COIL_DAMAGE = 47632, + SPELL_DK_DEATH_COIL_HEAL = 47633, + SPELL_DK_DEATH_STRIKE_HEAL = 45470, + SPELL_DK_GHOUL_EXPLODE = 47496, + SPELL_DK_GLYPH_OF_ICEBOUND_FORTITUDE = 58625, + SPELL_DK_RUNIC_POWER_ENERGIZE = 49088, + SPELL_DK_SCOURGE_STRIKE_TRIGGERED = 70890, + SPELL_DK_WILL_OF_THE_NECROPOLIS_TALENT_R1 = 49189, + SPELL_DK_WILL_OF_THE_NECROPOLIS_AURA_R1 = 52284, + SPELL_DK_BLOOD_PRESENCE = 48266, + SPELL_DK_IMPROVED_BLOOD_PRESENCE_TRIGGERED = 63611, + SPELL_DK_UNHOLY_PRESENCE = 48265, + SPELL_DK_IMPROVED_UNHOLY_PRESENCE_TRIGGERED = 63622, + SPELL_DK_ITEM_SIGIL_VENGEFUL_HEART = 64962, SPELL_DK_ITEM_T8_MELEE_4P_BONUS = 64736, - DK_SPELL_BLACK_ICE_R1 = 49140, +}; + +enum DeathKnightSpellIcons +{ + DK_ICON_ID_IMPROVED_DEATH_STRIKE = 2751, }; // 50462 - Anti-Magic Shell (on raid member) @@ -65,19 +76,19 @@ class spell_dk_anti_magic_shell_raid : public SpellScriptLoader void CalculateAmount(AuraEffect const* /*aurEff*/, int32 & amount, bool & /*canBeRecalculated*/) { - // TODO: this should absorb limited amount of damage, but no info on calculation formula + /// @todo this should absorb limited amount of damage, but no info on calculation formula amount = -1; } void Absorb(AuraEffect* /*aurEff*/, DamageInfo & dmgInfo, uint32 & absorbAmount) { - absorbAmount = CalculatePct(dmgInfo.GetDamage(), absorbPct); + absorbAmount = CalculatePct(dmgInfo.GetDamage(), absorbPct); } void Register() { - DoEffectCalcAmount += AuraEffectCalcAmountFn(spell_dk_anti_magic_shell_raid_AuraScript::CalculateAmount, EFFECT_0, SPELL_AURA_SCHOOL_ABSORB); - OnEffectAbsorb += AuraEffectAbsorbFn(spell_dk_anti_magic_shell_raid_AuraScript::Absorb, EFFECT_0); + DoEffectCalcAmount += AuraEffectCalcAmountFn(spell_dk_anti_magic_shell_raid_AuraScript::CalculateAmount, EFFECT_0, SPELL_AURA_SCHOOL_ABSORB); + OnEffectAbsorb += AuraEffectAbsorbFn(spell_dk_anti_magic_shell_raid_AuraScript::Absorb, EFFECT_0); } }; @@ -105,9 +116,9 @@ class spell_dk_anti_magic_shell_self : public SpellScriptLoader return true; } - bool Validate(SpellInfo const* /*spellEntry*/) + bool Validate(SpellInfo const* /*spellInfo*/) { - if (!sSpellMgr->GetSpellInfo(DK_SPELL_RUNIC_POWER_ENERGIZE)) + if (!sSpellMgr->GetSpellInfo(SPELL_DK_RUNIC_POWER_ENERGIZE)) return false; return true; } @@ -128,14 +139,14 @@ class spell_dk_anti_magic_shell_self : public SpellScriptLoader // damage absorbed by Anti-Magic Shell energizes the DK with additional runic power. // This, if I'm not mistaken, shows that we get back ~20% of the absorbed damage as runic power. int32 bp = absorbAmount * 2 / 10; - target->CastCustomSpell(target, DK_SPELL_RUNIC_POWER_ENERGIZE, &bp, NULL, NULL, true, NULL, aurEff); + target->CastCustomSpell(target, SPELL_DK_RUNIC_POWER_ENERGIZE, &bp, NULL, NULL, true, NULL, aurEff); } void Register() { - DoEffectCalcAmount += AuraEffectCalcAmountFn(spell_dk_anti_magic_shell_self_AuraScript::CalculateAmount, EFFECT_0, SPELL_AURA_SCHOOL_ABSORB); - OnEffectAbsorb += AuraEffectAbsorbFn(spell_dk_anti_magic_shell_self_AuraScript::Absorb, EFFECT_0); - AfterEffectAbsorb += AuraEffectAbsorbFn(spell_dk_anti_magic_shell_self_AuraScript::Trigger, EFFECT_0); + DoEffectCalcAmount += AuraEffectCalcAmountFn(spell_dk_anti_magic_shell_self_AuraScript::CalculateAmount, EFFECT_0, SPELL_AURA_SCHOOL_ABSORB); + OnEffectAbsorb += AuraEffectAbsorbFn(spell_dk_anti_magic_shell_self_AuraScript::Absorb, EFFECT_0); + AfterEffectAbsorb += AuraEffectAbsorbFn(spell_dk_anti_magic_shell_self_AuraScript::Trigger, EFFECT_0); } }; @@ -163,16 +174,16 @@ class spell_dk_anti_magic_zone : public SpellScriptLoader return true; } - bool Validate(SpellInfo const* /*spellEntry*/) + bool Validate(SpellInfo const* /*spellInfo*/) { - if (!sSpellMgr->GetSpellInfo(DK_SPELL_ANTI_MAGIC_SHELL_TALENT)) + if (!sSpellMgr->GetSpellInfo(SPELL_DK_ANTI_MAGIC_SHELL_TALENT)) return false; return true; } void CalculateAmount(AuraEffect const* /*aurEff*/, int32 & amount, bool & /*canBeRecalculated*/) { - SpellInfo const* talentSpell = sSpellMgr->GetSpellInfo(DK_SPELL_ANTI_MAGIC_SHELL_TALENT); + SpellInfo const* talentSpell = sSpellMgr->GetSpellInfo(SPELL_DK_ANTI_MAGIC_SHELL_TALENT); amount = talentSpell->Effects[EFFECT_0].CalcValue(GetCaster()); if (Player* player = GetCaster()->ToPlayer()) amount += int32(2 * player->GetTotalAttackPowerValue(BASE_ATTACK)); @@ -196,7 +207,105 @@ class spell_dk_anti_magic_zone : public SpellScriptLoader } }; -// 49158 Corpse Explosion (51325, 51326, 51327, 51328) +// 48721 - Blood Boil +class spell_dk_blood_boil : public SpellScriptLoader +{ + public: + spell_dk_blood_boil() : SpellScriptLoader("spell_dk_blood_boil") { } + + class spell_dk_blood_boil_SpellScript : public SpellScript + { + PrepareSpellScript(spell_dk_blood_boil_SpellScript); + + bool Validate(SpellInfo const* /*spellInfo*/) + { + if (!sSpellMgr->GetSpellInfo(SPELL_DK_BLOOD_BOIL_TRIGGERED)) + return false; + return true; + } + + bool Load() + { + _executed = false; + return GetCaster()->GetTypeId() == TYPEID_PLAYER && GetCaster()->getClass() == CLASS_DEATH_KNIGHT; + } + + void HandleAfterHit() + { + if (_executed || !GetHitUnit()) + return; + + _executed = true; + GetCaster()->CastSpell(GetCaster(), SPELL_DK_BLOOD_BOIL_TRIGGERED, true); + } + + void Register() + { + AfterHit += SpellHitFn(spell_dk_blood_boil_SpellScript::HandleAfterHit); + } + + bool _executed; + }; + + SpellScript* GetSpellScript() const + { + return new spell_dk_blood_boil_SpellScript(); + } +}; + +// 50453 - Bloodworms Health Leech +class spell_dk_blood_gorged : public SpellScriptLoader +{ + public: + spell_dk_blood_gorged() : SpellScriptLoader("spell_dk_blood_gorged") { } + + class spell_dk_blood_gorged_AuraScript : public AuraScript + { + PrepareAuraScript(spell_dk_blood_gorged_AuraScript); + + bool Validate(SpellInfo const* /*spellInfo*/) + { + if (!sSpellMgr->GetSpellInfo(SPELL_DK_BLOOD_GORGED_HEAL)) + return false; + return true; + } + + bool Load() + { + _procTarget = NULL; + return true; + } + + bool CheckProc(ProcEventInfo& /*eventInfo*/) + { + _procTarget = GetTarget()->GetOwner(); + return _procTarget; + } + + void HandleProc(AuraEffect const* aurEff, ProcEventInfo& eventInfo) + { + PreventDefaultAction(); + int32 bp = int32(eventInfo.GetDamageInfo()->GetDamage() * 1.5f); + GetTarget()->CastCustomSpell(SPELL_DK_BLOOD_GORGED_HEAL, SPELLVALUE_BASE_POINT0, bp, _procTarget, true, NULL, aurEff); + } + + void Register() + { + DoCheckProc += AuraCheckProcFn(spell_dk_blood_gorged_AuraScript::CheckProc); + OnEffectProc += AuraEffectProcFn(spell_dk_blood_gorged_AuraScript::HandleProc, EFFECT_0, SPELL_AURA_DUMMY); + } + + private: + Unit* _procTarget; + }; + + AuraScript* GetAuraScript() const + { + return new spell_dk_blood_gorged_AuraScript(); + } +}; + +// 49158 - Corpse Explosion (51325, 51326, 51327, 51328) class spell_dk_corpse_explosion : public SpellScriptLoader { public: @@ -206,11 +315,11 @@ class spell_dk_corpse_explosion : public SpellScriptLoader { PrepareSpellScript(spell_dk_corpse_explosion_SpellScript); - bool Validate(SpellInfo const* /*spellEntry*/) + bool Validate(SpellInfo const* /*spellInfo*/) { - if (!sSpellMgr->GetSpellInfo(DK_SPELL_CORPSE_EXPLOSION_TRIGGERED) || !sSpellMgr->GetSpellInfo(DK_SPELL_GHOUL_EXPLODE)) + if (!sSpellMgr->GetSpellInfo(SPELL_DK_CORPSE_EXPLOSION_TRIGGERED) || !sSpellMgr->GetSpellInfo(SPELL_DK_GHOUL_EXPLODE)) return false; - if (!sSpellMgr->GetSpellInfo(DK_SPELL_CORPSE_EXPLOSION_VISUAL)) + if (!sSpellMgr->GetSpellInfo(SPELL_DK_CORPSE_EXPLOSION_VISUAL)) return false; return true; } @@ -223,17 +332,17 @@ class spell_dk_corpse_explosion : public SpellScriptLoader if (unitTarget->isAlive()) // Living ghoul as a target { bp = int32(unitTarget->CountPctFromMaxHealth(25)); - unitTarget->CastCustomSpell(unitTarget, DK_SPELL_GHOUL_EXPLODE, &bp, NULL, NULL, false); + unitTarget->CastCustomSpell(unitTarget, SPELL_DK_GHOUL_EXPLODE, &bp, NULL, NULL, false); } else // Some corpse { bp = GetEffectValue(); GetCaster()->CastCustomSpell(unitTarget, GetSpellInfo()->Effects[EFFECT_1].CalcValue(), &bp, NULL, NULL, true); // Corpse Explosion (Suicide) - unitTarget->CastSpell(unitTarget, DK_SPELL_CORPSE_EXPLOSION_TRIGGERED, true); + unitTarget->CastSpell(unitTarget, SPELL_DK_CORPSE_EXPLOSION_TRIGGERED, true); } // Set corpse look - GetCaster()->CastSpell(unitTarget, DK_SPELL_CORPSE_EXPLOSION_VISUAL, true); + GetCaster()->CastSpell(unitTarget, SPELL_DK_CORPSE_EXPLOSION_VISUAL, true); } } @@ -249,44 +358,74 @@ class spell_dk_corpse_explosion : public SpellScriptLoader } }; -// 47496 - Explode, Ghoul spell for Corpse Explosion -class spell_dk_ghoul_explode : public SpellScriptLoader +// -47541, 52375, 59134, -62900 - Death Coil +class spell_dk_death_coil : public SpellScriptLoader { public: - spell_dk_ghoul_explode() : SpellScriptLoader("spell_dk_ghoul_explode") { } + spell_dk_death_coil() : SpellScriptLoader("spell_dk_death_coil") { } - class spell_dk_ghoul_explode_SpellScript : public SpellScript + class spell_dk_death_coil_SpellScript : public SpellScript { - PrepareSpellScript(spell_dk_ghoul_explode_SpellScript); + PrepareSpellScript(spell_dk_death_coil_SpellScript); - bool Validate(SpellInfo const* /*spellEntry*/) + bool Validate(SpellInfo const* /*spell*/) { - if (!sSpellMgr->GetSpellInfo(DK_SPELL_CORPSE_EXPLOSION_TRIGGERED)) + if (!sSpellMgr->GetSpellInfo(SPELL_DK_DEATH_COIL_DAMAGE) || !sSpellMgr->GetSpellInfo(SPELL_DK_DEATH_COIL_HEAL)) return false; return true; } - void Suicide(SpellEffIndex /*effIndex*/) + void HandleDummy(SpellEffIndex /*effIndex*/) { - if (Unit* unitTarget = GetHitUnit()) + int32 damage = GetEffectValue(); + Unit* caster = GetCaster(); + if (Unit* target = GetHitUnit()) { - // Corpse Explosion (Suicide) - unitTarget->CastSpell(unitTarget, DK_SPELL_CORPSE_EXPLOSION_TRIGGERED, true); + if (caster->IsFriendlyTo(target)) + { + int32 bp = int32(damage * 1.5f); + caster->CastCustomSpell(target, SPELL_DK_DEATH_COIL_HEAL, &bp, NULL, NULL, true); + } + else + { + if (AuraEffect const* auraEffect = caster->GetAuraEffect(SPELL_DK_ITEM_SIGIL_VENGEFUL_HEART, EFFECT_1)) + damage += auraEffect->GetBaseAmount(); + caster->CastCustomSpell(target, SPELL_DK_DEATH_COIL_DAMAGE, &damage, NULL, NULL, true); + } } } + SpellCastResult CheckCast() + { + Unit* caster = GetCaster(); + if (Unit* target = GetExplTargetUnit()) + { + if (!caster->IsFriendlyTo(target) && !caster->isInFront(target)) + return SPELL_FAILED_UNIT_NOT_INFRONT; + + if (target->IsFriendlyTo(caster) && target->GetCreatureType() != CREATURE_TYPE_UNDEAD) + return SPELL_FAILED_BAD_TARGETS; + } + else + return SPELL_FAILED_BAD_TARGETS; + + return SPELL_CAST_OK; + } + void Register() { - OnEffectHitTarget += SpellEffectFn(spell_dk_ghoul_explode_SpellScript::Suicide, EFFECT_1, SPELL_EFFECT_SCHOOL_DAMAGE); + OnCheckCast += SpellCheckCastFn(spell_dk_death_coil_SpellScript::CheckCast); + OnEffectHitTarget += SpellEffectFn(spell_dk_death_coil_SpellScript::HandleDummy, EFFECT_0, SPELL_EFFECT_DUMMY); } }; SpellScript* GetSpellScript() const { - return new spell_dk_ghoul_explode_SpellScript(); + return new spell_dk_death_coil_SpellScript(); } }; +// 52751 - Death Gate class spell_dk_death_gate : public SpellScriptLoader { public: @@ -327,6 +466,41 @@ class spell_dk_death_gate : public SpellScriptLoader } }; +// 49560 - Death Grip +class spell_dk_death_grip : public SpellScriptLoader +{ + public: + spell_dk_death_grip() : SpellScriptLoader("spell_dk_death_grip") { } + + class spell_dk_death_grip_SpellScript : public SpellScript + { + PrepareSpellScript(spell_dk_death_grip_SpellScript); + + void HandleDummy(SpellEffIndex /*effIndex*/) + { + int32 damage = GetEffectValue(); + Position const* pos = GetExplTargetDest(); + if (Unit* target = GetHitUnit()) + { + if (!target->HasAuraType(SPELL_AURA_DEFLECT_SPELLS)) // Deterrence + target->CastSpell(pos->GetPositionX(), pos->GetPositionY(), pos->GetPositionZ(), damage, true); + } + } + + void Register() + { + OnEffectHitTarget += SpellEffectFn(spell_dk_death_grip_SpellScript::HandleDummy, EFFECT_0, SPELL_EFFECT_DUMMY); + } + + }; + + SpellScript* GetSpellScript() const + { + return new spell_dk_death_grip_SpellScript(); + } +}; + +// 48743 - Death Pact class spell_dk_death_pact : public SpellScriptLoader { public: @@ -351,22 +525,22 @@ class spell_dk_death_pact : public SpellScriptLoader return SPELL_FAILED_NO_PET; } - void FilterTargets(std::list<WorldObject*>& unitList) + void FilterTargets(std::list<WorldObject*>& targetList) { - Unit* unit_to_add = NULL; - for (std::list<WorldObject*>::iterator itr = unitList.begin(); itr != unitList.end(); ++itr) + Unit* target = NULL; + for (std::list<WorldObject*>::iterator itr = targetList.begin(); itr != targetList.end(); ++itr) { if (Unit* unit = (*itr)->ToUnit()) - if (unit->GetOwnerGUID() == GetCaster()->GetGUID() && unit->GetCreatureType() == CREATURE_TYPE_UNDEAD) - { - unit_to_add = unit; - break; - } + if (unit->GetOwnerGUID() == GetCaster()->GetGUID() && unit->GetCreatureType() == CREATURE_TYPE_UNDEAD) + { + target = unit; + break; + } } - unitList.clear(); - if (unit_to_add) - unitList.push_back(unit_to_add); + targetList.clear(); + if (target) + targetList.push_back(target); } void Register() @@ -382,26 +556,19 @@ class spell_dk_death_pact : public SpellScriptLoader } }; -// 55090 Scourge Strike (55265, 55270, 55271) -class spell_dk_scourge_strike : public SpellScriptLoader +// -49998 - Death Strike +class spell_dk_death_strike : public SpellScriptLoader { public: - spell_dk_scourge_strike() : SpellScriptLoader("spell_dk_scourge_strike") { } + spell_dk_death_strike() : SpellScriptLoader("spell_dk_death_strike") { } - class spell_dk_scourge_strike_SpellScript : public SpellScript + class spell_dk_death_strike_SpellScript : public SpellScript { - PrepareSpellScript(spell_dk_scourge_strike_SpellScript); - float multiplier; - - bool Load() - { - multiplier = 1.0f; - return true; - } + PrepareSpellScript(spell_dk_death_strike_SpellScript); - bool Validate(SpellInfo const* /*spellEntry*/) + bool Validate(SpellInfo const* /*spellInfo*/) { - if (!sSpellMgr->GetSpellInfo(DK_SPELL_SCOURGE_STRIKE_TRIGGERED)) + if (!sSpellMgr->GetSpellInfo(SPELL_DK_DEATH_STRIKE_HEAL)) return false; return true; } @@ -409,442 +576,432 @@ class spell_dk_scourge_strike : public SpellScriptLoader void HandleDummy(SpellEffIndex /*effIndex*/) { Unit* caster = GetCaster(); - if (Unit* unitTarget = GetHitUnit()) + if (Unit* target = GetHitUnit()) { - multiplier = (GetEffectValue() * unitTarget->GetDiseasesByCaster(caster->GetGUID()) / 100.f); - // Death Knight T8 Melee 4P Bonus - if (AuraEffect const* aurEff = caster->GetAuraEffect(SPELL_DK_ITEM_T8_MELEE_4P_BONUS, EFFECT_0)) - AddPct(multiplier, aurEff->GetAmount()); + uint32 count = target->GetDiseasesByCaster(caster->GetGUID()); + int32 bp = int32(count * caster->CountPctFromMaxHealth(int32(GetSpellInfo()->Effects[EFFECT_0].DamageMultiplier))); + // Improved Death Strike + if (AuraEffect const* aurEff = caster->GetAuraEffect(SPELL_AURA_ADD_PCT_MODIFIER, SPELLFAMILY_DEATHKNIGHT, DK_ICON_ID_IMPROVED_DEATH_STRIKE, 0)) + AddPct(bp, caster->CalculateSpellDamage(caster, aurEff->GetSpellInfo(), 2)); + caster->CastCustomSpell(caster, SPELL_DK_DEATH_STRIKE_HEAL, &bp, NULL, NULL, false); } } - void HandleAfterHit() + void Register() { - Unit* caster = GetCaster(); - if (Unit* unitTarget = GetHitUnit()) - { - int32 bp = GetHitDamage() * multiplier; + OnEffectHitTarget += SpellEffectFn(spell_dk_death_strike_SpellScript::HandleDummy, EFFECT_2, SPELL_EFFECT_DUMMY); + } - if (AuraEffect* aurEff = caster->GetAuraEffectOfRankedSpell(DK_SPELL_BLACK_ICE_R1, EFFECT_0)) - AddPct(bp, aurEff->GetAmount()); + }; + + SpellScript* GetSpellScript() const + { + return new spell_dk_death_strike_SpellScript(); + } +}; - caster->CastCustomSpell(unitTarget, DK_SPELL_SCOURGE_STRIKE_TRIGGERED, &bp, NULL, NULL, true); +// 47496 - Explode, Ghoul spell for Corpse Explosion +class spell_dk_ghoul_explode : public SpellScriptLoader +{ + public: + spell_dk_ghoul_explode() : SpellScriptLoader("spell_dk_ghoul_explode") { } + + class spell_dk_ghoul_explode_SpellScript : public SpellScript + { + PrepareSpellScript(spell_dk_ghoul_explode_SpellScript); + + bool Validate(SpellInfo const* /*spellInfo*/) + { + if (!sSpellMgr->GetSpellInfo(SPELL_DK_CORPSE_EXPLOSION_TRIGGERED)) + return false; + return true; + } + + void Suicide(SpellEffIndex /*effIndex*/) + { + if (Unit* unitTarget = GetHitUnit()) + { + // Corpse Explosion (Suicide) + unitTarget->CastSpell(unitTarget, SPELL_DK_CORPSE_EXPLOSION_TRIGGERED, true); } } void Register() { - OnEffectHitTarget += SpellEffectFn(spell_dk_scourge_strike_SpellScript::HandleDummy, EFFECT_2, SPELL_EFFECT_DUMMY); - AfterHit += SpellHitFn(spell_dk_scourge_strike_SpellScript::HandleAfterHit); + OnEffectHitTarget += SpellEffectFn(spell_dk_ghoul_explode_SpellScript::Suicide, EFFECT_1, SPELL_EFFECT_SCHOOL_DAMAGE); } }; SpellScript* GetSpellScript() const { - return new spell_dk_scourge_strike_SpellScript(); + return new spell_dk_ghoul_explode_SpellScript(); } }; -// 49145 - Spell Deflection -class spell_dk_spell_deflection : public SpellScriptLoader +// 48792 - Icebound Fortitude +class spell_dk_icebound_fortitude : public SpellScriptLoader { public: - spell_dk_spell_deflection() : SpellScriptLoader("spell_dk_spell_deflection") { } + spell_dk_icebound_fortitude() : SpellScriptLoader("spell_dk_icebound_fortitude") { } - class spell_dk_spell_deflection_AuraScript : public AuraScript + class spell_dk_icebound_fortitude_AuraScript : public AuraScript { - PrepareAuraScript(spell_dk_spell_deflection_AuraScript); - - uint32 absorbPct; + PrepareAuraScript(spell_dk_icebound_fortitude_AuraScript); bool Load() { - absorbPct = GetSpellInfo()->Effects[EFFECT_0].CalcValue(GetCaster()); - return true; + Unit* caster = GetCaster(); + return caster && caster->GetTypeId() == TYPEID_PLAYER; } - void CalculateAmount(AuraEffect const* /*aurEff*/, int32 & amount, bool & /*canBeRecalculated*/) + void CalculateAmount(AuraEffect const* /*aurEff*/, int32& amount, bool& /*canBeRecalculated*/) { - // Set absorbtion amount to unlimited - amount = -1; - } + if (Unit* caster = GetCaster()) + { + int32 value = amount; + uint32 defValue = uint32(caster->ToPlayer()->GetSkillValue(SKILL_DEFENSE) + caster->ToPlayer()->GetRatingBonusValue(CR_DEFENSE_SKILL)); - void Absorb(AuraEffect* /*aurEff*/, DamageInfo & dmgInfo, uint32 & absorbAmount) - { - // You have a chance equal to your Parry chance - if ((dmgInfo.GetDamageType() == SPELL_DIRECT_DAMAGE) && roll_chance_f(GetTarget()->GetUnitParryChance())) - absorbAmount = CalculatePct(dmgInfo.GetDamage(), absorbPct); + if (defValue > 400) + value -= int32((defValue - 400) * 0.15); + + // Glyph of Icebound Fortitude + if (AuraEffect const* aurEff = caster->GetAuraEffect(SPELL_DK_GLYPH_OF_ICEBOUND_FORTITUDE, EFFECT_0)) + { + int32 valMax = -aurEff->GetAmount(); + if (value > valMax) + value = valMax; + } + amount = value; + } } void Register() { - DoEffectCalcAmount += AuraEffectCalcAmountFn(spell_dk_spell_deflection_AuraScript::CalculateAmount, EFFECT_0, SPELL_AURA_SCHOOL_ABSORB); - OnEffectAbsorb += AuraEffectAbsorbFn(spell_dk_spell_deflection_AuraScript::Absorb, EFFECT_0); + DoEffectCalcAmount += AuraEffectCalcAmountFn(spell_dk_icebound_fortitude_AuraScript::CalculateAmount, EFFECT_2, SPELL_AURA_MOD_DAMAGE_PERCENT_TAKEN); } }; AuraScript* GetAuraScript() const { - return new spell_dk_spell_deflection_AuraScript(); + return new spell_dk_icebound_fortitude_AuraScript(); } }; -// 48721 Blood Boil -class spell_dk_blood_boil : public SpellScriptLoader +// 50365, 50371 - Improved Blood Presence +class spell_dk_improved_blood_presence : public SpellScriptLoader { public: - spell_dk_blood_boil() : SpellScriptLoader("spell_dk_blood_boil") { } + spell_dk_improved_blood_presence() : SpellScriptLoader("spell_dk_improved_blood_presence") { } - class spell_dk_blood_boil_SpellScript : public SpellScript + class spell_dk_improved_blood_presence_AuraScript : public AuraScript { - PrepareSpellScript(spell_dk_blood_boil_SpellScript); + PrepareAuraScript(spell_dk_improved_blood_presence_AuraScript); - bool Validate(SpellInfo const* /*spellEntry*/) + bool Validate(SpellInfo const* /*spellInfo*/) { - if (!sSpellMgr->GetSpellInfo(DK_SPELL_BLOOD_BOIL_TRIGGERED)) + if (!sSpellMgr->GetSpellInfo(SPELL_DK_BLOOD_PRESENCE) || !sSpellMgr->GetSpellInfo(SPELL_DK_IMPROVED_BLOOD_PRESENCE_TRIGGERED)) return false; return true; } - bool Load() + void HandleEffectApply(AuraEffect const* aurEff, AuraEffectHandleModes /*mode*/) { - _executed = false; - return GetCaster()->GetTypeId() == TYPEID_PLAYER && GetCaster()->getClass() == CLASS_DEATH_KNIGHT; + Unit* target = GetTarget(); + if (!target->HasAura(SPELL_DK_BLOOD_PRESENCE) && !target->HasAura(SPELL_DK_IMPROVED_BLOOD_PRESENCE_TRIGGERED)) + { + int32 basePoints1 = aurEff->GetAmount(); + target->CastCustomSpell(target, SPELL_DK_IMPROVED_BLOOD_PRESENCE_TRIGGERED, NULL, &basePoints1, NULL, true, 0, aurEff); + } } - void HandleAfterHit() + void HandleEffectRemove(AuraEffect const* /*aurEff*/, AuraEffectHandleModes /*mode*/) { - if (_executed || !GetHitUnit()) - return; - - _executed = true; - GetCaster()->CastSpell(GetCaster(), DK_SPELL_BLOOD_BOIL_TRIGGERED, true); + Unit* target = GetTarget(); + if (!target->HasAura(SPELL_DK_BLOOD_PRESENCE)) + target->RemoveAura(SPELL_DK_IMPROVED_BLOOD_PRESENCE_TRIGGERED); } void Register() { - AfterHit += SpellHitFn(spell_dk_blood_boil_SpellScript::HandleAfterHit); + AfterEffectApply += AuraEffectApplyFn(spell_dk_improved_blood_presence_AuraScript::HandleEffectApply, EFFECT_0, SPELL_AURA_DUMMY, AURA_EFFECT_HANDLE_REAL); + AfterEffectRemove += AuraEffectRemoveFn(spell_dk_improved_blood_presence_AuraScript::HandleEffectRemove, EFFECT_0, SPELL_AURA_DUMMY, AURA_EFFECT_HANDLE_REAL); } - - bool _executed; }; - SpellScript* GetSpellScript() const + AuraScript* GetAuraScript() const { - return new spell_dk_blood_boil_SpellScript(); + return new spell_dk_improved_blood_presence_AuraScript(); } }; -// 52284 - Will of the Necropolis -class spell_dk_will_of_the_necropolis : public SpellScriptLoader +// 50391, 50392 - Improved Unholy Presence +class spell_dk_improved_unholy_presence : public SpellScriptLoader { public: - spell_dk_will_of_the_necropolis() : SpellScriptLoader("spell_dk_will_of_the_necropolis") { } + spell_dk_improved_unholy_presence() : SpellScriptLoader("spell_dk_improved_unholy_presence") { } - class spell_dk_will_of_the_necropolis_AuraScript : public AuraScript + class spell_dk_improved_unholy_presence_AuraScript : public AuraScript { - PrepareAuraScript(spell_dk_will_of_the_necropolis_AuraScript); + PrepareAuraScript(spell_dk_improved_unholy_presence_AuraScript); - bool Validate(SpellInfo const* spellEntry) + bool Validate(SpellInfo const* /*spellInfo*/) { - // can't use other spell than will of the necropolis due to spell_ranks dependency - if (sSpellMgr->GetFirstSpellInChain(DK_SPELL_WILL_OF_THE_NECROPOLIS_AURA_R1) != sSpellMgr->GetFirstSpellInChain(spellEntry->Id)) - return false; - - uint8 rank = sSpellMgr->GetSpellRank(spellEntry->Id); - if (!sSpellMgr->GetSpellWithRank(DK_SPELL_WILL_OF_THE_NECROPOLIS_TALENT_R1, rank, true)) + if (!sSpellMgr->GetSpellInfo(SPELL_DK_UNHOLY_PRESENCE) || !sSpellMgr->GetSpellInfo(SPELL_DK_IMPROVED_UNHOLY_PRESENCE_TRIGGERED)) return false; - return true; } - uint32 absorbPct; - - bool Load() + void HandleEffectApply(AuraEffect const* aurEff, AuraEffectHandleModes /*mode*/) { - absorbPct = GetSpellInfo()->Effects[EFFECT_0].CalcValue(GetCaster()); - return true; + Unit* target = GetTarget(); + if (target->HasAura(SPELL_DK_UNHOLY_PRESENCE) && !target->HasAura(SPELL_DK_IMPROVED_UNHOLY_PRESENCE_TRIGGERED)) + { + // Not listed as any effect, only base points set in dbc + int32 basePoints0 = aurEff->GetSpellInfo()->Effects[EFFECT_1].CalcValue(); + target->CastCustomSpell(target, SPELL_DK_IMPROVED_UNHOLY_PRESENCE_TRIGGERED, &basePoints0, &basePoints0, &basePoints0, true, 0, aurEff); + } } - void CalculateAmount(AuraEffect const* /*aurEff*/, int32 & amount, bool & /*canBeRecalculated*/) + void HandleEffectRemove(AuraEffect const* /*aurEff*/, AuraEffectHandleModes /*mode*/) { - // Set absorbtion amount to unlimited - amount = -1; - } - - void Absorb(AuraEffect* /*aurEff*/, DamageInfo & dmgInfo, uint32 & absorbAmount) - { - // min pct of hp is stored in effect 0 of talent spell - uint32 rank = sSpellMgr->GetSpellRank(GetSpellInfo()->Id); - SpellInfo const* talentProto = sSpellMgr->GetSpellInfo(sSpellMgr->GetSpellWithRank(DK_SPELL_WILL_OF_THE_NECROPOLIS_TALENT_R1, rank)); - - int32 remainingHp = int32(GetTarget()->GetHealth() - dmgInfo.GetDamage()); - int32 minHp = int32(GetTarget()->CountPctFromMaxHealth(talentProto->Effects[EFFECT_0].CalcValue(GetCaster()))); - - // Damage that would take you below [effect0] health or taken while you are at [effect0] - if (remainingHp < minHp) - absorbAmount = CalculatePct(dmgInfo.GetDamage(), absorbPct); + GetTarget()->RemoveAura(SPELL_DK_IMPROVED_UNHOLY_PRESENCE_TRIGGERED); } void Register() { - DoEffectCalcAmount += AuraEffectCalcAmountFn(spell_dk_will_of_the_necropolis_AuraScript::CalculateAmount, EFFECT_0, SPELL_AURA_SCHOOL_ABSORB); - OnEffectAbsorb += AuraEffectAbsorbFn(spell_dk_will_of_the_necropolis_AuraScript::Absorb, EFFECT_0); + AfterEffectApply += AuraEffectApplyFn(spell_dk_improved_unholy_presence_AuraScript::HandleEffectApply, EFFECT_0, SPELL_AURA_DUMMY, AURA_EFFECT_HANDLE_REAL); + AfterEffectRemove += AuraEffectRemoveFn(spell_dk_improved_unholy_presence_AuraScript::HandleEffectRemove, EFFECT_0, SPELL_AURA_DUMMY, AURA_EFFECT_HANDLE_REAL); } }; AuraScript* GetAuraScript() const { - return new spell_dk_will_of_the_necropolis_AuraScript(); + return new spell_dk_improved_unholy_presence_AuraScript(); } }; -// 50365, 50371 Improved Blood Presence -class spell_dk_improved_blood_presence : public SpellScriptLoader +// 59754 Rune Tap - Party +class spell_dk_rune_tap_party : public SpellScriptLoader { -public: - spell_dk_improved_blood_presence() : SpellScriptLoader("spell_dk_improved_blood_presence") { } - - class spell_dk_improved_blood_presence_AuraScript : public AuraScript - { - PrepareAuraScript(spell_dk_improved_blood_presence_AuraScript); + public: + spell_dk_rune_tap_party() : SpellScriptLoader("spell_dk_rune_tap_party") { } - bool Validate(SpellInfo const* /*entry*/) + class spell_dk_rune_tap_party_SpellScript : public SpellScript { - if (!sSpellMgr->GetSpellInfo(DK_SPELL_BLOOD_PRESENCE) || !sSpellMgr->GetSpellInfo(DK_SPELL_IMPROVED_BLOOD_PRESENCE_TRIGGERED)) - return false; - return true; - } + PrepareSpellScript(spell_dk_rune_tap_party_SpellScript); - void HandleEffectApply(AuraEffect const* aurEff, AuraEffectHandleModes /*mode*/) - { - Unit* target = GetTarget(); - if (!target->HasAura(DK_SPELL_BLOOD_PRESENCE) && !target->HasAura(DK_SPELL_IMPROVED_BLOOD_PRESENCE_TRIGGERED)) + void CheckTargets(std::list<WorldObject*>& targets) { - int32 basePoints1 = aurEff->GetAmount(); - target->CastCustomSpell(target, DK_SPELL_IMPROVED_BLOOD_PRESENCE_TRIGGERED, NULL, &basePoints1, NULL, true, 0, aurEff); + targets.remove(GetCaster()); } - } - void HandleEffectRemove(AuraEffect const* /*aurEff*/, AuraEffectHandleModes /*mode*/) - { - Unit* target = GetTarget(); - if (!target->HasAura(DK_SPELL_BLOOD_PRESENCE)) - target->RemoveAura(DK_SPELL_IMPROVED_BLOOD_PRESENCE_TRIGGERED); - } - - void Register() - { - AfterEffectApply += AuraEffectApplyFn(spell_dk_improved_blood_presence_AuraScript::HandleEffectApply, EFFECT_0, SPELL_AURA_DUMMY, AURA_EFFECT_HANDLE_REAL); - AfterEffectRemove += AuraEffectRemoveFn(spell_dk_improved_blood_presence_AuraScript::HandleEffectRemove, EFFECT_0, SPELL_AURA_DUMMY, AURA_EFFECT_HANDLE_REAL); - } - }; - - AuraScript* GetAuraScript() const - { - return new spell_dk_improved_blood_presence_AuraScript(); - } -}; - -// 50391, 50392 Improved Unholy Presence -class spell_dk_improved_unholy_presence : public SpellScriptLoader -{ -public: - spell_dk_improved_unholy_presence() : SpellScriptLoader("spell_dk_improved_unholy_presence") { } - - class spell_dk_improved_unholy_presence_AuraScript : public AuraScript - { - PrepareAuraScript(spell_dk_improved_unholy_presence_AuraScript); - - bool Validate(SpellInfo const* /*entry*/) - { - if (!sSpellMgr->GetSpellInfo(DK_SPELL_UNHOLY_PRESENCE) || !sSpellMgr->GetSpellInfo(DK_SPELL_IMPROVED_UNHOLY_PRESENCE_TRIGGERED)) - return false; - return true; - } - - void HandleEffectApply(AuraEffect const* aurEff, AuraEffectHandleModes /*mode*/) - { - Unit* target = GetTarget(); - if (target->HasAura(DK_SPELL_UNHOLY_PRESENCE) && !target->HasAura(DK_SPELL_IMPROVED_UNHOLY_PRESENCE_TRIGGERED)) + void Register() { - // Not listed as any effect, only base points set in dbc - int32 basePoints0 = aurEff->GetSpellInfo()->Effects[EFFECT_1].CalcValue(); - target->CastCustomSpell(target, DK_SPELL_IMPROVED_UNHOLY_PRESENCE_TRIGGERED, &basePoints0, &basePoints0, &basePoints0, true, 0, aurEff); + OnObjectAreaTargetSelect += SpellObjectAreaTargetSelectFn(spell_dk_rune_tap_party_SpellScript::CheckTargets, EFFECT_0, TARGET_UNIT_CASTER_AREA_PARTY); } - } - - void HandleEffectRemove(AuraEffect const* /*aurEff*/, AuraEffectHandleModes /*mode*/) - { - GetTarget()->RemoveAura(DK_SPELL_IMPROVED_UNHOLY_PRESENCE_TRIGGERED); - } + }; - void Register() + SpellScript* GetSpellScript() const { - AfterEffectApply += AuraEffectApplyFn(spell_dk_improved_unholy_presence_AuraScript::HandleEffectApply, EFFECT_0, SPELL_AURA_DUMMY, AURA_EFFECT_HANDLE_REAL); - AfterEffectRemove += AuraEffectRemoveFn(spell_dk_improved_unholy_presence_AuraScript::HandleEffectRemove, EFFECT_0, SPELL_AURA_DUMMY, AURA_EFFECT_HANDLE_REAL); + return new spell_dk_rune_tap_party_SpellScript(); } - }; - - AuraScript* GetAuraScript() const - { - return new spell_dk_improved_unholy_presence_AuraScript(); - } }; -enum DeathStrike -{ - ICON_ID_IMPROVED_DEATH_STRIKE = 2751, - SPELL_DEATH_STRIKE_HEAL = 45470, -}; - -class spell_dk_death_strike : public SpellScriptLoader +// 55090 - Scourge Strike (55265, 55270, 55271) +class spell_dk_scourge_strike : public SpellScriptLoader { public: - spell_dk_death_strike() : SpellScriptLoader("spell_dk_death_strike") { } + spell_dk_scourge_strike() : SpellScriptLoader("spell_dk_scourge_strike") { } - class spell_dk_death_strike_SpellScript : public SpellScript + class spell_dk_scourge_strike_SpellScript : public SpellScript { - PrepareSpellScript(spell_dk_death_strike_SpellScript); + PrepareSpellScript(spell_dk_scourge_strike_SpellScript); + float multiplier; - bool Validate(SpellInfo const* /*SpellEntry*/) + bool Load() { - if (!sSpellMgr->GetSpellInfo(SPELL_DEATH_STRIKE_HEAL)) + multiplier = 1.0f; + return true; + } + + bool Validate(SpellInfo const* /*spellInfo*/) + { + if (!sSpellMgr->GetSpellInfo(SPELL_DK_SCOURGE_STRIKE_TRIGGERED)) return false; return true; } - void HandleDummy(SpellEffIndex /* effIndex */) + void HandleDummy(SpellEffIndex /*effIndex*/) { Unit* caster = GetCaster(); - if (Unit* target = GetHitUnit()) + if (Unit* unitTarget = GetHitUnit()) { - uint32 count = target->GetDiseasesByCaster(caster->GetGUID()); - int32 bp = int32(count * caster->CountPctFromMaxHealth(int32(GetSpellInfo()->Effects[EFFECT_0].DamageMultiplier))); - // Improved Death Strike - if (AuraEffect const* aurEff = caster->GetAuraEffect(SPELL_AURA_ADD_PCT_MODIFIER, SPELLFAMILY_DEATHKNIGHT, ICON_ID_IMPROVED_DEATH_STRIKE, 0)) - AddPct(bp, caster->CalculateSpellDamage(caster, aurEff->GetSpellInfo(), 2)); - caster->CastCustomSpell(caster, SPELL_DEATH_STRIKE_HEAL, &bp, NULL, NULL, false); + multiplier = (GetEffectValue() * unitTarget->GetDiseasesByCaster(caster->GetGUID()) / 100.f); + // Death Knight T8 Melee 4P Bonus + if (AuraEffect const* aurEff = caster->GetAuraEffect(SPELL_DK_ITEM_T8_MELEE_4P_BONUS, EFFECT_0)) + AddPct(multiplier, aurEff->GetAmount()); } } - void Register() + void HandleAfterHit() { - OnEffectHitTarget += SpellEffectFn(spell_dk_death_strike_SpellScript::HandleDummy, EFFECT_2, SPELL_EFFECT_DUMMY); + Unit* caster = GetCaster(); + if (Unit* unitTarget = GetHitUnit()) + { + int32 bp = GetHitDamage() * multiplier; + + if (AuraEffect* aurEff = caster->GetAuraEffectOfRankedSpell(SPELL_DK_BLACK_ICE_R1, EFFECT_0)) + AddPct(bp, aurEff->GetAmount()); + + caster->CastCustomSpell(unitTarget, SPELL_DK_SCOURGE_STRIKE_TRIGGERED, &bp, NULL, NULL, true); + } } + void Register() + { + OnEffectHitTarget += SpellEffectFn(spell_dk_scourge_strike_SpellScript::HandleDummy, EFFECT_2, SPELL_EFFECT_DUMMY); + AfterHit += SpellHitFn(spell_dk_scourge_strike_SpellScript::HandleAfterHit); + } }; SpellScript* GetSpellScript() const { - return new spell_dk_death_strike_SpellScript(); + return new spell_dk_scourge_strike_SpellScript(); } }; -enum DeathCoil -{ - SPELL_DEATH_COIL_DAMAGE = 47632, - SPELL_DEATH_COIL_HEAL = 47633, - SPELL_SIGIL_VENGEFUL_HEART = 64962, -}; - -class spell_dk_death_coil : public SpellScriptLoader +// 49145 - Spell Deflection +class spell_dk_spell_deflection : public SpellScriptLoader { public: - spell_dk_death_coil() : SpellScriptLoader("spell_dk_death_coil") { } + spell_dk_spell_deflection() : SpellScriptLoader("spell_dk_spell_deflection") { } - class spell_dk_death_coil_SpellScript : public SpellScript + class spell_dk_spell_deflection_AuraScript : public AuraScript { - PrepareSpellScript(spell_dk_death_coil_SpellScript); + PrepareAuraScript(spell_dk_spell_deflection_AuraScript); - bool Validate(SpellInfo const* /*spell*/) + uint32 absorbPct; + + bool Load() { - if (!sSpellMgr->GetSpellInfo(SPELL_DEATH_COIL_DAMAGE) || !sSpellMgr->GetSpellInfo(SPELL_DEATH_COIL_HEAL)) - return false; + absorbPct = GetSpellInfo()->Effects[EFFECT_0].CalcValue(GetCaster()); return true; } - void HandleDummy(SpellEffIndex /*effIndex*/) + void CalculateAmount(AuraEffect const* /*aurEff*/, int32 & amount, bool & /*canBeRecalculated*/) { - int32 damage = GetEffectValue(); - Unit* caster = GetCaster(); - if (Unit* target = GetHitUnit()) - { - if (caster->IsFriendlyTo(target)) - { - int32 bp = int32(damage * 1.5f); - caster->CastCustomSpell(target, SPELL_DEATH_COIL_HEAL, &bp, NULL, NULL, true); - } - else - { - if (AuraEffect const* auraEffect = caster->GetAuraEffect(SPELL_SIGIL_VENGEFUL_HEART, EFFECT_1)) - damage += auraEffect->GetBaseAmount(); - caster->CastCustomSpell(target, SPELL_DEATH_COIL_DAMAGE, &damage, NULL, NULL, true); - } - } + // Set absorbtion amount to unlimited + amount = -1; } - SpellCastResult CheckCast() + void Absorb(AuraEffect* /*aurEff*/, DamageInfo & dmgInfo, uint32 & absorbAmount) { - Unit* caster = GetCaster(); - if (Unit* target = GetExplTargetUnit()) - { - if (!caster->IsFriendlyTo(target) && !caster->isInFront(target)) - return SPELL_FAILED_UNIT_NOT_INFRONT; + // You have a chance equal to your Parry chance + if ((dmgInfo.GetDamageType() == SPELL_DIRECT_DAMAGE) && roll_chance_f(GetTarget()->GetUnitParryChance())) + absorbAmount = CalculatePct(dmgInfo.GetDamage(), absorbPct); + } - if (target->IsFriendlyTo(caster) && target->GetCreatureType() != CREATURE_TYPE_UNDEAD) - return SPELL_FAILED_BAD_TARGETS; - } - else - return SPELL_FAILED_BAD_TARGETS; + void Register() + { + DoEffectCalcAmount += AuraEffectCalcAmountFn(spell_dk_spell_deflection_AuraScript::CalculateAmount, EFFECT_0, SPELL_AURA_SCHOOL_ABSORB); + OnEffectAbsorb += AuraEffectAbsorbFn(spell_dk_spell_deflection_AuraScript::Absorb, EFFECT_0); + } + }; - return SPELL_CAST_OK; + AuraScript* GetAuraScript() const + { + return new spell_dk_spell_deflection_AuraScript(); + } +}; + +// 55233 - Vampiric Blood +class spell_dk_vampiric_blood : public SpellScriptLoader +{ + public: + spell_dk_vampiric_blood() : SpellScriptLoader("spell_dk_vampiric_blood") { } + + class spell_dk_vampiric_blood_AuraScript : public AuraScript + { + PrepareAuraScript(spell_dk_vampiric_blood_AuraScript); + + void CalculateAmount(AuraEffect const* /*aurEff*/, int32& amount, bool& /*canBeRecalculated*/) + { + amount = GetUnitOwner()->CountPctFromMaxHealth(amount); } void Register() { - OnCheckCast += SpellCheckCastFn(spell_dk_death_coil_SpellScript::CheckCast); - OnEffectHitTarget += SpellEffectFn(spell_dk_death_coil_SpellScript::HandleDummy, EFFECT_0, SPELL_EFFECT_DUMMY); + DoEffectCalcAmount += AuraEffectCalcAmountFn(spell_dk_vampiric_blood_AuraScript::CalculateAmount, EFFECT_1, SPELL_AURA_MOD_INCREASE_HEALTH); } - }; - SpellScript* GetSpellScript() const + AuraScript* GetAuraScript() const { - return new spell_dk_death_coil_SpellScript(); + return new spell_dk_vampiric_blood_AuraScript(); } }; -class spell_dk_death_grip : public SpellScriptLoader +// 52284 - Will of the Necropolis +class spell_dk_will_of_the_necropolis : public SpellScriptLoader { public: - spell_dk_death_grip() : SpellScriptLoader("spell_dk_death_grip") { } + spell_dk_will_of_the_necropolis() : SpellScriptLoader("spell_dk_will_of_the_necropolis") { } - class spell_dk_death_grip_SpellScript : public SpellScript + class spell_dk_will_of_the_necropolis_AuraScript : public AuraScript { - PrepareSpellScript(spell_dk_death_grip_SpellScript); + PrepareAuraScript(spell_dk_will_of_the_necropolis_AuraScript); - void HandleDummy(SpellEffIndex /*effIndex*/) + bool Validate(SpellInfo const* spellInfo) { - int32 damage = GetEffectValue(); - Position const* pos = GetExplTargetDest(); - if (Unit* target = GetHitUnit()) - { - if (!target->HasAuraType(SPELL_AURA_DEFLECT_SPELLS)) // Deterrence - target->CastSpell(pos->GetPositionX(), pos->GetPositionY(), pos->GetPositionZ(), damage, true); - } + // can't use other spell than will of the necropolis due to spell_ranks dependency + if (sSpellMgr->GetFirstSpellInChain(SPELL_DK_WILL_OF_THE_NECROPOLIS_AURA_R1) != sSpellMgr->GetFirstSpellInChain(spellInfo->Id)) + return false; + + uint8 rank = sSpellMgr->GetSpellRank(spellInfo->Id); + if (!sSpellMgr->GetSpellWithRank(SPELL_DK_WILL_OF_THE_NECROPOLIS_TALENT_R1, rank, true)) + return false; + + return true; } - void Register() + uint32 absorbPct; + + bool Load() { - OnEffectHitTarget += SpellEffectFn(spell_dk_death_grip_SpellScript::HandleDummy, EFFECT_0, SPELL_EFFECT_DUMMY); + absorbPct = GetSpellInfo()->Effects[EFFECT_0].CalcValue(GetCaster()); + return true; + } + + void CalculateAmount(AuraEffect const* /*aurEff*/, int32 & amount, bool & /*canBeRecalculated*/) + { + // Set absorbtion amount to unlimited + amount = -1; + } + + void Absorb(AuraEffect* /*aurEff*/, DamageInfo & dmgInfo, uint32 & absorbAmount) + { + // min pct of hp is stored in effect 0 of talent spell + uint32 rank = sSpellMgr->GetSpellRank(GetSpellInfo()->Id); + SpellInfo const* talentProto = sSpellMgr->GetSpellInfo(sSpellMgr->GetSpellWithRank(SPELL_DK_WILL_OF_THE_NECROPOLIS_TALENT_R1, rank)); + + int32 remainingHp = int32(GetTarget()->GetHealth() - dmgInfo.GetDamage()); + int32 minHp = int32(GetTarget()->CountPctFromMaxHealth(talentProto->Effects[EFFECT_0].CalcValue(GetCaster()))); + + // Damage that would take you below [effect0] health or taken while you are at [effect0] + if (remainingHp < minHp) + absorbAmount = CalculatePct(dmgInfo.GetDamage(), absorbPct); } + void Register() + { + DoEffectCalcAmount += AuraEffectCalcAmountFn(spell_dk_will_of_the_necropolis_AuraScript::CalculateAmount, EFFECT_0, SPELL_AURA_SCHOOL_ABSORB); + OnEffectAbsorb += AuraEffectAbsorbFn(spell_dk_will_of_the_necropolis_AuraScript::Absorb, EFFECT_0); + } }; - SpellScript* GetSpellScript() const + AuraScript* GetAuraScript() const { - return new spell_dk_death_grip_SpellScript(); + return new spell_dk_will_of_the_necropolis_AuraScript(); } }; @@ -853,17 +1010,21 @@ void AddSC_deathknight_spell_scripts() new spell_dk_anti_magic_shell_raid(); new spell_dk_anti_magic_shell_self(); new spell_dk_anti_magic_zone(); + new spell_dk_blood_boil(); + new spell_dk_blood_gorged(); new spell_dk_corpse_explosion(); - new spell_dk_ghoul_explode(); + new spell_dk_death_coil(); new spell_dk_death_gate(); + new spell_dk_death_grip(); new spell_dk_death_pact(); + new spell_dk_death_strike(); + new spell_dk_ghoul_explode(); + new spell_dk_icebound_fortitude(); + new spell_dk_improved_blood_presence(); + new spell_dk_improved_unholy_presence(); + new spell_dk_rune_tap_party(); new spell_dk_scourge_strike(); new spell_dk_spell_deflection(); - new spell_dk_blood_boil(); + new spell_dk_vampiric_blood(); new spell_dk_will_of_the_necropolis(); - new spell_dk_improved_blood_presence(); - new spell_dk_improved_unholy_presence(); - new spell_dk_death_strike(); - new spell_dk_death_coil(); - new spell_dk_death_grip(); } diff --git a/src/server/scripts/Spells/spell_druid.cpp b/src/server/scripts/Spells/spell_druid.cpp index a0307f994c9..160f14ff670 100644 --- a/src/server/scripts/Spells/spell_druid.cpp +++ b/src/server/scripts/Spells/spell_druid.cpp @@ -29,18 +29,53 @@ enum DruidSpells { - DRUID_INCREASED_MOONFIRE_DURATION = 38414, - DRUID_NATURES_SPLENDOR = 57865, - DRUID_LIFEBLOOM_FINAL_HEAL = 33778, - DRUID_LIFEBLOOM_ENERGIZE = 64372, - DRUID_SURVIVAL_INSTINCTS = 50322, - DRUID_SAVAGE_ROAR = 62071, - SPELL_DRUID_ITEM_T8_BALANCE_RELIC = 64950, - SPELL_KING_OF_THE_JUNGLE = 48492, - SPELL_TIGER_S_FURY_ENERGIZE = 51178, - SPELL_ENRAGE_MOD_DAMAGE = 51185, + SPELL_DRUID_ENRAGE_MOD_DAMAGE = 51185, + SPELL_DRUID_GLYPH_OF_TYPHOON = 62135, + SPELL_DRUID_IDOL_OF_FERAL_SHADOWS = 34241, + SPELL_DRUID_IDOL_OF_WORSHIP = 60774, + SPELL_DRUID_INCREASED_MOONFIRE_DURATION = 38414, + SPELL_DRUID_KING_OF_THE_JUNGLE = 48492, + SPELL_DRUID_LIFEBLOOM_ENERGIZE = 64372, + SPELL_DRUID_LIFEBLOOM_FINAL_HEAL = 33778, + SPELL_DRUID_LIVING_SEED_HEAL = 48503, + SPELL_DRUID_LIVING_SEED_PROC = 48504, + SPELL_DRUID_NATURES_SPLENDOR = 57865, + SPELL_DRUID_SURVIVAL_INSTINCTS = 50322, + SPELL_DRUID_SAVAGE_ROAR = 62071, + SPELL_DRUID_TIGER_S_FURY_ENERGIZE = 51178, + SPELL_DRUID_ITEM_T8_BALANCE_RELIC = 64950, }; +// -1850 - Dash +class spell_dru_dash : public SpellScriptLoader +{ + public: + spell_dru_dash() : SpellScriptLoader("spell_dru_dash") { } + + class spell_dru_dash_AuraScript : public AuraScript + { + PrepareAuraScript(spell_dru_dash_AuraScript); + + void CalculateAmount(AuraEffect const* /*aurEff*/, int32& amount, bool& /*canBeRecalculated*/) + { + // do not set speed if not in cat form + if (GetUnitOwner()->GetShapeshiftForm() != FORM_CAT) + amount = 0; + } + + void Register() + { + DoEffectCalcAmount += AuraEffectCalcAmountFn(spell_dru_dash_AuraScript::CalculateAmount, EFFECT_0, SPELL_AURA_MOD_INCREASE_SPEED); + } + }; + + AuraScript* GetAuraScript() const + { + return new spell_dru_dash_AuraScript(); + } +}; + +// -5229 - Enrage class spell_dru_enrage : public SpellScriptLoader { public: @@ -52,8 +87,8 @@ class spell_dru_enrage : public SpellScriptLoader void OnHit() { - if (AuraEffect const* aurEff = GetHitUnit()->GetAuraEffectOfRankedSpell(SPELL_KING_OF_THE_JUNGLE, EFFECT_0)) - GetHitUnit()->CastCustomSpell(SPELL_ENRAGE_MOD_DAMAGE, SPELLVALUE_BASE_POINT0, aurEff->GetAmount(), GetHitUnit(), true); + if (AuraEffect const* aurEff = GetHitUnit()->GetAuraEffectOfRankedSpell(SPELL_DRUID_KING_OF_THE_JUNGLE, EFFECT_0)) + GetHitUnit()->CastCustomSpell(SPELL_DRUID_ENRAGE_MOD_DAMAGE, SPELLVALUE_BASE_POINT0, aurEff->GetAmount(), GetHitUnit(), true); } void Register() @@ -68,7 +103,7 @@ class spell_dru_enrage : public SpellScriptLoader } }; -// 54846 Glyph of Starfire +// 54846 - Glyph of Starfire class spell_dru_glyph_of_starfire : public SpellScriptLoader { public: @@ -78,9 +113,9 @@ class spell_dru_glyph_of_starfire : public SpellScriptLoader { PrepareSpellScript(spell_dru_glyph_of_starfire_SpellScript); - bool Validate(SpellInfo const* /*spellEntry*/) + bool Validate(SpellInfo const* /*spellInfo*/) { - if (!sSpellMgr->GetSpellInfo(DRUID_INCREASED_MOONFIRE_DURATION) || !sSpellMgr->GetSpellInfo(DRUID_NATURES_SPLENDOR)) + if (!sSpellMgr->GetSpellInfo(SPELL_DRUID_INCREASED_MOONFIRE_DURATION) || !sSpellMgr->GetSpellInfo(SPELL_DRUID_NATURES_SPLENDOR)) return false; return true; } @@ -95,9 +130,9 @@ class spell_dru_glyph_of_starfire : public SpellScriptLoader uint32 countMin = aura->GetMaxDuration(); uint32 countMax = aura->GetSpellInfo()->GetMaxDuration() + 9000; - if (caster->HasAura(DRUID_INCREASED_MOONFIRE_DURATION)) + if (caster->HasAura(SPELL_DRUID_INCREASED_MOONFIRE_DURATION)) countMax += 3000; - if (caster->HasAura(DRUID_NATURES_SPLENDOR)) + if (caster->HasAura(SPELL_DRUID_NATURES_SPLENDOR)) countMax += 3000; if (countMin < countMax) @@ -120,6 +155,70 @@ class spell_dru_glyph_of_starfire : public SpellScriptLoader } }; +// 34246 - Idol of the Emerald Queen +// 60779 - Idol of Lush Moss +class spell_dru_idol_lifebloom : public SpellScriptLoader +{ + public: + spell_dru_idol_lifebloom() : SpellScriptLoader("spell_dru_idol_lifebloom") { } + + class spell_dru_idol_lifebloom_AuraScript : public AuraScript + { + PrepareAuraScript(spell_dru_idol_lifebloom_AuraScript); + + void HandleEffectCalcSpellMod(AuraEffect const* aurEff, SpellModifier*& spellMod) + { + if (!spellMod) + { + spellMod = new SpellModifier(GetAura()); + spellMod->op = SPELLMOD_DOT; + spellMod->type = SPELLMOD_FLAT; + spellMod->spellId = GetId(); + spellMod->mask = GetSpellInfo()->Effects[aurEff->GetEffIndex()].SpellClassMask; + } + spellMod->value = aurEff->GetAmount() / 7; + } + + void Register() + { + DoEffectCalcSpellMod += AuraEffectCalcSpellModFn(spell_dru_idol_lifebloom_AuraScript::HandleEffectCalcSpellMod, EFFECT_0, SPELL_AURA_DUMMY); + } + }; + + AuraScript* GetAuraScript() const + { + return new spell_dru_idol_lifebloom_AuraScript(); + } +}; + +// 29166 - Innervate +class spell_dru_innervate : public SpellScriptLoader +{ + public: + spell_dru_innervate() : SpellScriptLoader("spell_dru_innervate") { } + + class spell_dru_innervate_AuraScript : public AuraScript + { + PrepareAuraScript(spell_dru_innervate_AuraScript); + + void CalculateAmount(AuraEffect const* aurEff, int32& amount, bool& /*canBeRecalculated*/) + { + amount = CalculatePct(int32(GetUnitOwner()->GetCreatePowers(POWER_MANA) / aurEff->GetTotalTicks()), amount); + } + + void Register() + { + DoEffectCalcAmount += AuraEffectCalcAmountFn(spell_dru_innervate_AuraScript::CalculateAmount, EFFECT_0, SPELL_AURA_PERIODIC_ENERGIZE); + } + }; + + AuraScript* GetAuraScript() const + { + return new spell_dru_innervate_AuraScript(); + } +}; + +// -5570 - Insect Swarm class spell_dru_insect_swarm : public SpellScriptLoader { public: @@ -148,6 +247,7 @@ class spell_dru_insect_swarm : public SpellScriptLoader } }; +// -33763 - Lifebloom class spell_dru_lifebloom : public SpellScriptLoader { public: @@ -159,9 +259,9 @@ class spell_dru_lifebloom : public SpellScriptLoader bool Validate(SpellInfo const* /*spell*/) { - if (!sSpellMgr->GetSpellInfo(DRUID_LIFEBLOOM_FINAL_HEAL)) + if (!sSpellMgr->GetSpellInfo(SPELL_DRUID_LIFEBLOOM_FINAL_HEAL)) return false; - if (!sSpellMgr->GetSpellInfo(DRUID_LIFEBLOOM_ENERGIZE)) + if (!sSpellMgr->GetSpellInfo(SPELL_DRUID_LIFEBLOOM_ENERGIZE)) return false; return true; } @@ -180,15 +280,15 @@ class spell_dru_lifebloom : public SpellScriptLoader healAmount = caster->SpellHealingBonusDone(GetTarget(), GetSpellInfo(), healAmount, HEAL, stack); healAmount = GetTarget()->SpellHealingBonusTaken(caster, GetSpellInfo(), healAmount, HEAL, stack); - GetTarget()->CastCustomSpell(GetTarget(), DRUID_LIFEBLOOM_FINAL_HEAL, &healAmount, NULL, NULL, true, NULL, aurEff, GetCasterGUID()); + GetTarget()->CastCustomSpell(GetTarget(), SPELL_DRUID_LIFEBLOOM_FINAL_HEAL, &healAmount, NULL, NULL, true, NULL, aurEff, GetCasterGUID()); // restore mana int32 returnMana = CalculatePct(caster->GetCreateMana(), GetSpellInfo()->ManaCostPercentage) * stack / 2; - caster->CastCustomSpell(caster, DRUID_LIFEBLOOM_ENERGIZE, &returnMana, NULL, NULL, true, NULL, aurEff, GetCasterGUID()); + caster->CastCustomSpell(caster, SPELL_DRUID_LIFEBLOOM_ENERGIZE, &returnMana, NULL, NULL, true, NULL, aurEff, GetCasterGUID()); return; } - GetTarget()->CastCustomSpell(GetTarget(), DRUID_LIFEBLOOM_FINAL_HEAL, &healAmount, NULL, NULL, true, NULL, aurEff, GetCasterGUID()); + GetTarget()->CastCustomSpell(GetTarget(), SPELL_DRUID_LIFEBLOOM_FINAL_HEAL, &healAmount, NULL, NULL, true, NULL, aurEff, GetCasterGUID()); } void HandleDispel(DispelInfo* dispelInfo) @@ -203,15 +303,15 @@ class spell_dru_lifebloom : public SpellScriptLoader { healAmount = caster->SpellHealingBonusDone(target, GetSpellInfo(), healAmount, HEAL, dispelInfo->GetRemovedCharges()); healAmount = target->SpellHealingBonusTaken(caster, GetSpellInfo(), healAmount, HEAL, dispelInfo->GetRemovedCharges()); - target->CastCustomSpell(target, DRUID_LIFEBLOOM_FINAL_HEAL, &healAmount, NULL, NULL, true, NULL, NULL, GetCasterGUID()); + target->CastCustomSpell(target, SPELL_DRUID_LIFEBLOOM_FINAL_HEAL, &healAmount, NULL, NULL, true, NULL, NULL, GetCasterGUID()); // restore mana int32 returnMana = CalculatePct(caster->GetCreateMana(), GetSpellInfo()->ManaCostPercentage) * dispelInfo->GetRemovedCharges() / 2; - caster->CastCustomSpell(caster, DRUID_LIFEBLOOM_ENERGIZE, &returnMana, NULL, NULL, true, NULL, NULL, GetCasterGUID()); + caster->CastCustomSpell(caster, SPELL_DRUID_LIFEBLOOM_ENERGIZE, &returnMana, NULL, NULL, true, NULL, NULL, GetCasterGUID()); return; } - target->CastCustomSpell(target, DRUID_LIFEBLOOM_FINAL_HEAL, &healAmount, NULL, NULL, true, NULL, NULL, GetCasterGUID()); + target->CastCustomSpell(target, SPELL_DRUID_LIFEBLOOM_FINAL_HEAL, &healAmount, NULL, NULL, true, NULL, NULL, GetCasterGUID()); } } } @@ -229,6 +329,77 @@ class spell_dru_lifebloom : public SpellScriptLoader } }; +// -48496 - Living Seed +class spell_dru_living_seed : public SpellScriptLoader +{ + public: + spell_dru_living_seed() : SpellScriptLoader("spell_dru_living_seed") { } + + class spell_dru_living_seed_AuraScript : public AuraScript + { + PrepareAuraScript(spell_dru_living_seed_AuraScript); + + bool Validate(SpellInfo const* /*spellInfo*/) + { + if (!sSpellMgr->GetSpellInfo(SPELL_DRUID_LIVING_SEED_PROC)) + return false; + return true; + } + + void HandleProc(AuraEffect const* aurEff, ProcEventInfo& eventInfo) + { + PreventDefaultAction(); + int32 amount = CalculatePct(eventInfo.GetHealInfo()->GetHeal(), aurEff->GetAmount()); + GetTarget()->CastCustomSpell(SPELL_DRUID_LIVING_SEED_PROC, SPELLVALUE_BASE_POINT0, amount, eventInfo.GetProcTarget(), true, NULL, aurEff); + } + + void Register() + { + OnEffectProc += AuraEffectProcFn(spell_dru_living_seed_AuraScript::HandleProc, EFFECT_0, SPELL_AURA_DUMMY); + } + }; + + AuraScript* GetAuraScript() const + { + return new spell_dru_living_seed_AuraScript(); + } +}; + +// 48504 - Living Seed (Proc) +class spell_dru_living_seed_proc : public SpellScriptLoader +{ + public: + spell_dru_living_seed_proc() : SpellScriptLoader("spell_dru_living_seed_proc") { } + + class spell_dru_living_seed_proc_AuraScript : public AuraScript + { + PrepareAuraScript(spell_dru_living_seed_proc_AuraScript); + + bool Validate(SpellInfo const* /*spellInfo*/) + { + if (!sSpellMgr->GetSpellInfo(SPELL_DRUID_LIVING_SEED_HEAL)) + return false; + return true; + } + + void HandleProc(AuraEffect const* aurEff, ProcEventInfo& /*eventInfo*/) + { + PreventDefaultAction(); + GetTarget()->CastCustomSpell(SPELL_DRUID_LIVING_SEED_HEAL, SPELLVALUE_BASE_POINT0, aurEff->GetAmount(), GetTarget(), true, NULL, aurEff); + } + + void Register() + { + OnEffectProc += AuraEffectProcFn(spell_dru_living_seed_proc_AuraScript::HandleProc, EFFECT_0, SPELL_AURA_DUMMY); + } + }; + + AuraScript* GetAuraScript() const + { + return new spell_dru_living_seed_proc_AuraScript(); + } +}; + // 69366 - Moonkin Form passive class spell_dru_moonkin_form_passive : public SpellScriptLoader { @@ -273,6 +444,34 @@ class spell_dru_moonkin_form_passive : public SpellScriptLoader } }; +// 48391 - Owlkin Frenzy +class spell_dru_owlkin_frenzy : public SpellScriptLoader +{ + public: + spell_dru_owlkin_frenzy() : SpellScriptLoader("spell_dru_owlkin_frenzy") { } + + class spell_dru_owlkin_frenzy_AuraScript : public AuraScript + { + PrepareAuraScript(spell_dru_owlkin_frenzy_AuraScript); + + void CalculateAmount(AuraEffect const* /*aurEff*/, int32& amount, bool& /*canBeRecalculated*/) + { + amount = CalculatePct(GetUnitOwner()->GetCreatePowers(POWER_MANA), amount); + } + + void Register() + { + DoEffectCalcAmount += AuraEffectCalcAmountFn(spell_dru_owlkin_frenzy_AuraScript::CalculateAmount, EFFECT_2, SPELL_AURA_PERIODIC_ENERGIZE); + } + }; + + AuraScript* GetAuraScript() const + { + return new spell_dru_owlkin_frenzy_AuraScript(); + } +}; + +// -16972 - Predatory Strikes class spell_dru_predatory_strikes : public SpellScriptLoader { public: @@ -345,6 +544,54 @@ class spell_dru_primal_tenacity : public SpellScriptLoader } }; +// -1079 - Rip +class spell_dru_rip : public SpellScriptLoader +{ + public: + spell_dru_rip() : SpellScriptLoader("spell_dru_rip") { } + + class spell_dru_rip_AuraScript : public AuraScript + { + PrepareAuraScript(spell_dru_rip_AuraScript); + + bool Load() + { + Unit* caster = GetCaster(); + return caster && caster->GetTypeId() == TYPEID_PLAYER; + } + + void CalculateAmount(AuraEffect const* /*aurEff*/, int32& amount, bool& canBeRecalculated) + { + canBeRecalculated = false; + + if (Unit* caster = GetCaster()) + { + // 0.01 * $AP * cp + uint8 cp = caster->ToPlayer()->GetComboPoints(); + + // Idol of Feral Shadows. Can't be handled as SpellMod due its dependency from CPs + if (AuraEffect const* idol = caster->GetAuraEffect(SPELL_DRUID_IDOL_OF_FERAL_SHADOWS, EFFECT_0)) + amount += cp * idol->GetAmount(); + // Idol of Worship. Can't be handled as SpellMod due its dependency from CPs + else if (AuraEffect const* idol = caster->GetAuraEffect(SPELL_DRUID_IDOL_OF_WORSHIP, EFFECT_0)) + amount += cp * idol->GetAmount(); + + amount += int32(CalculatePct(caster->GetTotalAttackPowerValue(BASE_ATTACK), cp)); + } + } + + void Register() + { + DoEffectCalcAmount += AuraEffectCalcAmountFn(spell_dru_rip_AuraScript::CalculateAmount, EFFECT_0, SPELL_AURA_PERIODIC_DAMAGE); + } + }; + + AuraScript* GetAuraScript() const + { + return new spell_dru_rip_AuraScript(); + } +}; + // 62606 - Savage Defense class spell_dru_savage_defense : public SpellScriptLoader { @@ -388,6 +635,7 @@ class spell_dru_savage_defense : public SpellScriptLoader } }; +// 52610 - Savage Roar class spell_dru_savage_roar : public SpellScriptLoader { public: @@ -418,7 +666,7 @@ class spell_dru_savage_roar : public SpellScriptLoader bool Validate(SpellInfo const* /*spell*/) { - if (!sSpellMgr->GetSpellInfo(DRUID_SAVAGE_ROAR)) + if (!sSpellMgr->GetSpellInfo(SPELL_DRUID_SAVAGE_ROAR)) return false; return true; } @@ -426,12 +674,12 @@ class spell_dru_savage_roar : public SpellScriptLoader void AfterApply(AuraEffect const* aurEff, AuraEffectHandleModes /*mode*/) { Unit* target = GetTarget(); - target->CastSpell(target, DRUID_SAVAGE_ROAR, true, NULL, aurEff, GetCasterGUID()); + target->CastSpell(target, SPELL_DRUID_SAVAGE_ROAR, true, NULL, aurEff, GetCasterGUID()); } void AfterRemove(AuraEffect const* /*aurEff*/, AuraEffectHandleModes /*mode*/) { - GetTarget()->RemoveAurasDueToSpell(DRUID_SAVAGE_ROAR); + GetTarget()->RemoveAurasDueToSpell(SPELL_DRUID_SAVAGE_ROAR); } void Register() @@ -452,6 +700,7 @@ class spell_dru_savage_roar : public SpellScriptLoader } }; +// -50294 - Starfall (AOE) class spell_dru_starfall_aoe : public SpellScriptLoader { public: @@ -478,6 +727,7 @@ class spell_dru_starfall_aoe : public SpellScriptLoader } }; +// -50286 - Starfall (Dummy) class spell_dru_starfall_dummy : public SpellScriptLoader { public: @@ -523,6 +773,7 @@ class spell_dru_starfall_dummy : public SpellScriptLoader } }; +// 61336 - Survival Instincts class spell_dru_survival_instincts : public SpellScriptLoader { public: @@ -553,7 +804,7 @@ class spell_dru_survival_instincts : public SpellScriptLoader bool Validate(SpellInfo const* /*spell*/) { - if (!sSpellMgr->GetSpellInfo(DRUID_SURVIVAL_INSTINCTS)) + if (!sSpellMgr->GetSpellInfo(SPELL_DRUID_SURVIVAL_INSTINCTS)) return false; return true; } @@ -562,12 +813,12 @@ class spell_dru_survival_instincts : public SpellScriptLoader { Unit* target = GetTarget(); int32 bp0 = target->CountPctFromMaxHealth(aurEff->GetAmount()); - target->CastCustomSpell(target, DRUID_SURVIVAL_INSTINCTS, &bp0, NULL, NULL, true); + target->CastCustomSpell(target, SPELL_DRUID_SURVIVAL_INSTINCTS, &bp0, NULL, NULL, true); } void AfterRemove(AuraEffect const* /*aurEff*/, AuraEffectHandleModes /*mode*/) { - GetTarget()->RemoveAurasDueToSpell(DRUID_SURVIVAL_INSTINCTS); + GetTarget()->RemoveAurasDueToSpell(SPELL_DRUID_SURVIVAL_INSTINCTS); } void Register() @@ -622,6 +873,7 @@ class spell_dru_swift_flight_passive : public SpellScriptLoader } }; +// -5217 - Tiger's Fury class spell_dru_tiger_s_fury : public SpellScriptLoader { public: @@ -633,8 +885,8 @@ class spell_dru_tiger_s_fury : public SpellScriptLoader void OnHit() { - if (AuraEffect const* aurEff = GetHitUnit()->GetAuraEffectOfRankedSpell(SPELL_KING_OF_THE_JUNGLE, EFFECT_1)) - GetHitUnit()->CastCustomSpell(SPELL_TIGER_S_FURY_ENERGIZE, SPELLVALUE_BASE_POINT0, aurEff->GetAmount(), GetHitUnit(), true); + if (AuraEffect const* aurEff = GetHitUnit()->GetAuraEffectOfRankedSpell(SPELL_DRUID_KING_OF_THE_JUNGLE, EFFECT_1)) + GetHitUnit()->CastCustomSpell(SPELL_DRUID_TIGER_S_FURY_ENERGIZE, SPELLVALUE_BASE_POINT0, aurEff->GetAmount(), GetHitUnit(), true); } void Register() @@ -649,6 +901,36 @@ class spell_dru_tiger_s_fury : public SpellScriptLoader } }; +// -61391 - Typhoon +class spell_dru_typhoon : public SpellScriptLoader +{ + public: + spell_dru_typhoon() : SpellScriptLoader("spell_dru_typhoon") { } + + class spell_dru_typhoon_SpellScript : public SpellScript + { + PrepareSpellScript(spell_dru_typhoon_SpellScript); + + void HandleKnockBack(SpellEffIndex effIndex) + { + // Glyph of Typhoon + if (GetCaster()->HasAura(SPELL_DRUID_GLYPH_OF_TYPHOON)) + PreventHitDefaultEffect(effIndex); + } + + void Register() + { + OnEffectHitTarget += SpellEffectFn(spell_dru_typhoon_SpellScript::HandleKnockBack, EFFECT_0, SPELL_EFFECT_KNOCK_BACK); + } + }; + + SpellScript* GetSpellScript() const + { + return new spell_dru_typhoon_SpellScript(); + } +}; + +// 70691 - Item T10 Restoration 4P Bonus class spell_dru_t10_restoration_4p_bonus : public SpellScriptLoader { public: @@ -705,13 +987,20 @@ class spell_dru_t10_restoration_4p_bonus : public SpellScriptLoader void AddSC_druid_spell_scripts() { + new spell_dru_dash(); new spell_dru_enrage(); new spell_dru_glyph_of_starfire(); + new spell_dru_idol_lifebloom(); + new spell_dru_innervate(); new spell_dru_insect_swarm(); new spell_dru_lifebloom(); + new spell_dru_living_seed(); + new spell_dru_living_seed_proc(); new spell_dru_moonkin_form_passive(); + new spell_dru_owlkin_frenzy(); new spell_dru_predatory_strikes(); new spell_dru_primal_tenacity(); + new spell_dru_rip(); new spell_dru_savage_defense(); new spell_dru_savage_roar(); new spell_dru_starfall_aoe(); @@ -719,5 +1008,6 @@ void AddSC_druid_spell_scripts() new spell_dru_survival_instincts(); new spell_dru_swift_flight_passive(); new spell_dru_tiger_s_fury(); + new spell_dru_typhoon(); new spell_dru_t10_restoration_4p_bonus(); } diff --git a/src/server/scripts/Spells/spell_generic.cpp b/src/server/scripts/Spells/spell_generic.cpp index 4a1b0d558ff..00b504d2403 100644 --- a/src/server/scripts/Spells/spell_generic.cpp +++ b/src/server/scripts/Spells/spell_generic.cpp @@ -72,6 +72,97 @@ class spell_gen_absorb0_hitlimit1 : public SpellScriptLoader } }; +// 28764 - Adaptive Warding (Frostfire Regalia Set) +enum AdaptiveWarding +{ + SPELL_GEN_ADAPTIVE_WARDING_FIRE = 28765, + SPELL_GEN_ADAPTIVE_WARDING_NATURE = 28768, + SPELL_GEN_ADAPTIVE_WARDING_FROST = 28766, + SPELL_GEN_ADAPTIVE_WARDING_SHADOW = 28769, + SPELL_GEN_ADAPTIVE_WARDING_ARCANE = 28770 +}; + +class spell_gen_adaptive_warding : public SpellScriptLoader +{ + public: + spell_gen_adaptive_warding() : SpellScriptLoader("spell_gen_adaptive_warding") { } + + class spell_gen_adaptive_warding_AuraScript : public AuraScript + { + PrepareAuraScript(spell_gen_adaptive_warding_AuraScript); + + bool Validate(SpellInfo const* /*spellInfo*/) + { + if (!sSpellMgr->GetSpellInfo(SPELL_GEN_ADAPTIVE_WARDING_FIRE) || + !sSpellMgr->GetSpellInfo(SPELL_GEN_ADAPTIVE_WARDING_NATURE) || + !sSpellMgr->GetSpellInfo(SPELL_GEN_ADAPTIVE_WARDING_FROST) || + !sSpellMgr->GetSpellInfo(SPELL_GEN_ADAPTIVE_WARDING_SHADOW) || + !sSpellMgr->GetSpellInfo(SPELL_GEN_ADAPTIVE_WARDING_ARCANE)) + return false; + return true; + } + + bool CheckProc(ProcEventInfo& eventInfo) + { + if (eventInfo.GetDamageInfo()->GetSpellInfo()) // eventInfo.GetSpellInfo() + return false; + + // find Mage Armor + if (!GetTarget()->GetAuraEffect(SPELL_AURA_MOD_MANA_REGEN_INTERRUPT, SPELLFAMILY_MAGE, 0x10000000, 0x0, 0x0)) + return false; + + switch (GetFirstSchoolInMask(eventInfo.GetSchoolMask())) + { + case SPELL_SCHOOL_NORMAL: + case SPELL_SCHOOL_HOLY: + return false; + default: + break; + } + return true; + } + + void HandleProc(AuraEffect const* aurEff, ProcEventInfo& eventInfo) + { + PreventDefaultAction(); + + uint32 spellId = 0; + switch (GetFirstSchoolInMask(eventInfo.GetSchoolMask())) + { + case SPELL_SCHOOL_FIRE: + spellId = SPELL_GEN_ADAPTIVE_WARDING_FIRE; + break; + case SPELL_SCHOOL_NATURE: + spellId = SPELL_GEN_ADAPTIVE_WARDING_NATURE; + break; + case SPELL_SCHOOL_FROST: + spellId = SPELL_GEN_ADAPTIVE_WARDING_FROST; + break; + case SPELL_SCHOOL_SHADOW: + spellId = SPELL_GEN_ADAPTIVE_WARDING_SHADOW; + break; + case SPELL_SCHOOL_ARCANE: + spellId = SPELL_GEN_ADAPTIVE_WARDING_ARCANE; + break; + default: + return; + } + GetTarget()->CastSpell(GetTarget(), spellId, true, NULL, aurEff); + } + + void Register() + { + DoCheckProc += AuraCheckProcFn(spell_gen_adaptive_warding_AuraScript::CheckProc); + OnEffectProc += AuraEffectProcFn(spell_gen_adaptive_warding_AuraScript::HandleProc, EFFECT_0, SPELL_AURA_DUMMY); + } + }; + + AuraScript* GetAuraScript() const + { + return new spell_gen_adaptive_warding_AuraScript(); + } +}; + // 41337 Aura of Anger class spell_gen_aura_of_anger : public SpellScriptLoader { @@ -226,6 +317,245 @@ class spell_gen_cannibalize : public SpellScriptLoader } }; +// 63845 - Create Lance +enum CreateLanceSpells +{ + SPELL_CREATE_LANCE_ALLIANCE = 63914, + SPELL_CREATE_LANCE_HORDE = 63919 +}; + +class spell_gen_create_lance : public SpellScriptLoader +{ + public: + spell_gen_create_lance() : SpellScriptLoader("spell_gen_create_lance") { } + + class spell_gen_create_lance_SpellScript : public SpellScript + { + PrepareSpellScript(spell_gen_create_lance_SpellScript); + + bool Validate(SpellInfo const* /*spellInfo*/) + { + if (!sSpellMgr->GetSpellInfo(SPELL_CREATE_LANCE_ALLIANCE) || !sSpellMgr->GetSpellInfo(SPELL_CREATE_LANCE_HORDE)) + return false; + return true; + } + + void HandleScript(SpellEffIndex effIndex) + { + PreventHitDefaultEffect(effIndex); + + if (Player* target = GetHitPlayer()) + { + if (target->GetTeam() == ALLIANCE) + GetCaster()->CastSpell(target, SPELL_CREATE_LANCE_ALLIANCE, true); + else + GetCaster()->CastSpell(target, SPELL_CREATE_LANCE_HORDE, true); + } + } + + void Register() + { + OnEffectHitTarget += SpellEffectFn(spell_gen_create_lance_SpellScript::HandleScript, EFFECT_0, SPELL_EFFECT_SCRIPT_EFFECT); + } + }; + + SpellScript* GetSpellScript() const + { + return new spell_gen_create_lance_SpellScript(); + } +}; + +// 28702 - Netherbloom +enum Netherbloom +{ + SPELL_NETHERBLOOM_POLLEN_1 = 28703 +}; + +class spell_gen_netherbloom : public SpellScriptLoader +{ + public: + spell_gen_netherbloom() : SpellScriptLoader("spell_gen_netherbloom") { } + + class spell_gen_netherbloom_SpellScript : public SpellScript + { + PrepareSpellScript(spell_gen_netherbloom_SpellScript); + + bool Validate(SpellInfo const* /*spellInfo*/) + { + for (uint8 i = 0; i < 5; ++i) + if (!sSpellMgr->GetSpellInfo(SPELL_NETHERBLOOM_POLLEN_1 + i)) + return false; + return true; + } + + void HandleScript(SpellEffIndex effIndex) + { + PreventHitDefaultEffect(effIndex); + + if (Unit* target = GetHitUnit()) + { + // 25% chance of casting a random buff + if (roll_chance_i(75)) + return; + + // triggered spells are 28703 to 28707 + // Note: some sources say, that there was the possibility of + // receiving a debuff. However, this seems to be removed by a patch. + + // don't overwrite an existing aura + for (uint8 i = 0; i < 5; ++i) + if (target->HasAura(SPELL_NETHERBLOOM_POLLEN_1 + i)) + return; + + target->CastSpell(target, SPELL_NETHERBLOOM_POLLEN_1 + urand(0, 4), true); + } + } + + void Register() + { + OnEffectHitTarget += SpellEffectFn(spell_gen_netherbloom_SpellScript::HandleScript, EFFECT_0, SPELL_EFFECT_SCRIPT_EFFECT); + } + }; + + SpellScript* GetSpellScript() const + { + return new spell_gen_netherbloom_SpellScript(); + } +}; + +// 28720 - Nightmare Vine +enum NightmareVine +{ + SPELL_NIGHTMARE_POLLEN = 28721 +}; + +class spell_gen_nightmare_vine : public SpellScriptLoader +{ + public: + spell_gen_nightmare_vine() : SpellScriptLoader("spell_gen_nightmare_vine") { } + + class spell_gen_nightmare_vine_SpellScript : public SpellScript + { + PrepareSpellScript(spell_gen_nightmare_vine_SpellScript); + + bool Validate(SpellInfo const* /*spellInfo*/) + { + if (!sSpellMgr->GetSpellInfo(SPELL_NIGHTMARE_POLLEN)) + return false; + return true; + } + + void HandleScript(SpellEffIndex effIndex) + { + PreventHitDefaultEffect(effIndex); + + if (Unit* target = GetHitUnit()) + { + // 25% chance of casting Nightmare Pollen + if (roll_chance_i(25)) + target->CastSpell(target, SPELL_NIGHTMARE_POLLEN, true); + } + } + + void Register() + { + OnEffectHitTarget += SpellEffectFn(spell_gen_nightmare_vine_SpellScript::HandleScript, EFFECT_0, SPELL_EFFECT_SCRIPT_EFFECT); + } + }; + + SpellScript* GetSpellScript() const + { + return new spell_gen_nightmare_vine_SpellScript(); + } +}; + +// 27539 - Obsidian Armor +enum ObsidianArmor +{ + SPELL_GEN_OBSIDIAN_ARMOR_HOLY = 27536, + SPELL_GEN_OBSIDIAN_ARMOR_FIRE = 27533, + SPELL_GEN_OBSIDIAN_ARMOR_NATURE = 27538, + SPELL_GEN_OBSIDIAN_ARMOR_FROST = 27534, + SPELL_GEN_OBSIDIAN_ARMOR_SHADOW = 27535, + SPELL_GEN_OBSIDIAN_ARMOR_ARCANE = 27540 +}; + +class spell_gen_obsidian_armor : public SpellScriptLoader +{ + public: + spell_gen_obsidian_armor() : SpellScriptLoader("spell_gen_obsidian_armor") { } + + class spell_gen_obsidian_armor_AuraScript : public AuraScript + { + PrepareAuraScript(spell_gen_obsidian_armor_AuraScript); + + bool Validate(SpellInfo const* /*spellInfo*/) + { + if (!sSpellMgr->GetSpellInfo(SPELL_GEN_OBSIDIAN_ARMOR_HOLY) || + !sSpellMgr->GetSpellInfo(SPELL_GEN_OBSIDIAN_ARMOR_FIRE) || + !sSpellMgr->GetSpellInfo(SPELL_GEN_OBSIDIAN_ARMOR_NATURE) || + !sSpellMgr->GetSpellInfo(SPELL_GEN_OBSIDIAN_ARMOR_FROST) || + !sSpellMgr->GetSpellInfo(SPELL_GEN_OBSIDIAN_ARMOR_SHADOW) || + !sSpellMgr->GetSpellInfo(SPELL_GEN_OBSIDIAN_ARMOR_ARCANE)) + return false; + return true; + } + + bool CheckProc(ProcEventInfo& eventInfo) + { + if (eventInfo.GetDamageInfo()->GetSpellInfo()) // eventInfo.GetSpellInfo() + return false; + + if (GetFirstSchoolInMask(eventInfo.GetSchoolMask()) == SPELL_SCHOOL_NORMAL) + return false; + + return true; + } + + void OnProc(AuraEffect const* aurEff, ProcEventInfo& eventInfo) + { + PreventDefaultAction(); + + uint32 spellId = 0; + switch (GetFirstSchoolInMask(eventInfo.GetSchoolMask())) + { + case SPELL_SCHOOL_HOLY: + spellId = SPELL_GEN_OBSIDIAN_ARMOR_HOLY; + break; + case SPELL_SCHOOL_FIRE: + spellId = SPELL_GEN_OBSIDIAN_ARMOR_FIRE; + break; + case SPELL_SCHOOL_NATURE: + spellId = SPELL_GEN_OBSIDIAN_ARMOR_NATURE; + break; + case SPELL_SCHOOL_FROST: + spellId = SPELL_GEN_OBSIDIAN_ARMOR_FROST; + break; + case SPELL_SCHOOL_SHADOW: + spellId = SPELL_GEN_OBSIDIAN_ARMOR_SHADOW; + break; + case SPELL_SCHOOL_ARCANE: + spellId = SPELL_GEN_OBSIDIAN_ARMOR_ARCANE; + break; + default: + return; + } + GetTarget()->CastSpell(GetTarget(), spellId, true, NULL, aurEff); + } + + void Register() + { + DoCheckProc += AuraCheckProcFn(spell_gen_obsidian_armor_AuraScript::CheckProc); + OnEffectProc += AuraEffectProcFn(spell_gen_obsidian_armor_AuraScript::OnProc, EFFECT_0, SPELL_AURA_DUMMY); + } + }; + + AuraScript* GetAuraScript() const + { + return new spell_gen_obsidian_armor_AuraScript(); + } +}; + // 45472 Parachute enum ParachuteSpells { @@ -1242,7 +1572,7 @@ class spell_gen_vehicle_scaling : public SpellScriptLoader float factor; uint16 baseItemLevel; - // TODO: Reserach coeffs for different vehicles + /// @todo Reserach coeffs for different vehicles switch (GetId()) { case SPELL_GEAR_SCALING: @@ -1257,7 +1587,7 @@ class spell_gen_vehicle_scaling : public SpellScriptLoader float avgILvl = caster->ToPlayer()->GetAverageItemLevel(); if (avgILvl < baseItemLevel) - return; // TODO: Research possibility of scaling down + return; /// @todo Research possibility of scaling down amount = uint16((avgILvl - baseItemLevel) * factor); } @@ -1377,68 +1707,6 @@ class spell_gen_damage_reduction_aura : public SpellScriptLoader } }; -class spell_gen_luck_of_the_draw : public SpellScriptLoader -{ - public: - spell_gen_luck_of_the_draw() : SpellScriptLoader("spell_gen_luck_of_the_draw") { } - - class spell_gen_luck_of_the_draw_AuraScript : public AuraScript - { - PrepareAuraScript(spell_gen_luck_of_the_draw_AuraScript); - - bool Load() - { - return GetUnitOwner()->GetTypeId() == TYPEID_PLAYER; - } - - // cheap hax to make it have update calls - void CalcPeriodic(AuraEffect const* /*effect*/, bool& isPeriodic, int32& amplitude) - { - isPeriodic = true; - amplitude = 5 * IN_MILLISECONDS; - } - - void Update(AuraEffect* /*effect*/) - { - if (Player* owner = GetUnitOwner()->ToPlayer()) - { - const LfgDungeonSet dungeons = sLFGMgr->GetSelectedDungeons(owner->GetGUID()); - LfgDungeonSet::const_iterator itr = dungeons.begin(); - - if (itr == dungeons.end()) - { - Remove(AURA_REMOVE_BY_DEFAULT); - return; - } - - - LFGDungeonData const* randomDungeon = sLFGMgr->GetLFGDungeon(*itr); - if (Group* group = owner->GetGroup()) - if (Map const* map = owner->GetMap()) - if (group->isLFGGroup()) - if (uint32 dungeonId = sLFGMgr->GetDungeon(group->GetGUID(), true)) - if (LFGDungeonData const* dungeon = sLFGMgr->GetLFGDungeon(dungeonId)) - if (uint32(dungeon->map) == map->GetId() && dungeon->difficulty == map->GetDifficulty()) - if (randomDungeon && randomDungeon->type == LFG_TYPE_RANDOM) - return; // in correct dungeon - - Remove(AURA_REMOVE_BY_DEFAULT); - } - } - - void Register() - { - DoEffectCalcPeriodic += AuraEffectCalcPeriodicFn(spell_gen_luck_of_the_draw_AuraScript::CalcPeriodic, EFFECT_0, SPELL_AURA_MOD_DAMAGE_PERCENT_DONE); - OnEffectUpdatePeriodic += AuraEffectUpdatePeriodicFn(spell_gen_luck_of_the_draw_AuraScript::Update, EFFECT_0, SPELL_AURA_MOD_DAMAGE_PERCENT_DONE); - } - }; - - AuraScript* GetAuraScript() const - { - return new spell_gen_luck_of_the_draw_AuraScript(); - } -}; - enum DummyTrigger { SPELL_PERSISTANT_SHIELD_TRIGGERED = 26470, @@ -1594,7 +1862,7 @@ class spell_gen_gnomish_transporter : public SpellScriptLoader void HandleDummy(SpellEffIndex /* effIndex */) { Unit* caster = GetCaster(); - caster->CastSpell(caster, roll_chance_i(50) ? SPELL_TRANSPORTER_SUCCESS : SPELL_TRANSPORTER_FAILURE , true); + caster->CastSpell(caster, roll_chance_i(50) ? SPELL_TRANSPORTER_SUCCESS : SPELL_TRANSPORTER_FAILURE, true); } void Register() @@ -2796,7 +3064,7 @@ class spell_gen_summon_elemental : public SpellScriptLoader { if (GetCaster()) if (Unit* owner = GetCaster()->GetOwner()) - if (owner->GetTypeId() == TYPEID_PLAYER) // todo: this check is maybe wrong + if (owner->GetTypeId() == TYPEID_PLAYER) /// @todo this check is maybe wrong owner->ToPlayer()->RemovePet(NULL, PET_SAVE_NOT_IN_SLOT, true); } @@ -3188,13 +3456,75 @@ class spell_gen_replenishment : public SpellScriptLoader } }; +enum ServiceUniform +{ + SPELL_SERVICE_UNIFORM = 71450, + + MODEL_GOBLIN_MALE = 31002, + MODEL_GOBLIN_FEMALE = 31003, +}; + +class spell_gen_aura_service_uniform : public SpellScriptLoader +{ + public: + spell_gen_aura_service_uniform() : SpellScriptLoader("spell_gen_aura_service_uniform") { } + + class spell_gen_aura_service_uniform_AuraScript : public AuraScript + { + PrepareAuraScript(spell_gen_aura_service_uniform_AuraScript); + + bool Validate(SpellInfo const* /*spell*/) + { + if (!sSpellMgr->GetSpellInfo(SPELL_SERVICE_UNIFORM)) + return false; + return true; + } + + void OnApply(AuraEffect const* /*aurEff*/, AuraEffectHandleModes /*mode*/) + { + // Apply model goblin + Unit* target = GetTarget(); + if (target->GetTypeId() == TYPEID_PLAYER) + { + if (target->getGender() == GENDER_MALE) + target->SetDisplayId(MODEL_GOBLIN_MALE); + else + target->SetDisplayId(MODEL_GOBLIN_FEMALE); + } + } + + void OnRemove(AuraEffect const* /*aurEff*/, AuraEffectHandleModes /*mode*/) + { + Unit* target = GetTarget(); + if (target->GetTypeId() == TYPEID_PLAYER) + target->RestoreDisplayId(); + } + + void Register() + { + AfterEffectApply += AuraEffectRemoveFn(spell_gen_aura_service_uniform_AuraScript::OnApply, EFFECT_0, SPELL_AURA_TRANSFORM, AURA_EFFECT_HANDLE_REAL); + AfterEffectRemove += AuraEffectRemoveFn(spell_gen_aura_service_uniform_AuraScript::OnRemove, EFFECT_0, SPELL_AURA_TRANSFORM, AURA_EFFECT_HANDLE_REAL); + } + }; + + AuraScript* GetAuraScript() const + { + return new spell_gen_aura_service_uniform_AuraScript(); + } +}; + void AddSC_generic_spell_scripts() { new spell_gen_absorb0_hitlimit1(); + new spell_gen_adaptive_warding(); new spell_gen_aura_of_anger(); new spell_gen_av_drekthar_presence(); new spell_gen_burn_brutallus(); new spell_gen_cannibalize(); + new spell_gen_create_lance(); + new spell_gen_netherbloom(); + new spell_gen_nightmare_vine(); + new spell_gen_obsidian_armor(); new spell_gen_parachute(); new spell_gen_pet_summoned(); new spell_gen_remove_flight_auras(); @@ -3218,7 +3548,6 @@ void AddSC_generic_spell_scripts() new spell_gen_vehicle_scaling(); new spell_gen_oracle_wolvar_reputation(); new spell_gen_damage_reduction_aura(); - new spell_gen_luck_of_the_draw(); new spell_gen_dummy_trigger(); new spell_gen_spirit_healer_res(); new spell_gen_gadgetzan_transporter_backfire(); @@ -3262,4 +3591,5 @@ void AddSC_generic_spell_scripts() new spell_gen_bonked(); new spell_gen_gift_of_naaru(); new spell_gen_replenishment(); + new spell_gen_aura_service_uniform(); } diff --git a/src/server/scripts/Spells/spell_holiday.cpp b/src/server/scripts/Spells/spell_holiday.cpp index 83532e7d72d..37b6a202ed4 100644 --- a/src/server/scripts/Spells/spell_holiday.cpp +++ b/src/server/scripts/Spells/spell_holiday.cpp @@ -17,6 +17,7 @@ /* * Spells used in holidays/game events that do not fit any other category. + * Ordered alphabetically using scriptname. * Scriptnames in this file should be prefixed with "spell_#holidayname_". */ @@ -26,6 +27,7 @@ #include "SpellScript.h" #include "SpellAuraEffects.h" #include "GridNotifiers.h" +#include "GridNotifiersImpl.h" #include "CellImpl.h" // 45102 Romantic Picnic @@ -133,6 +135,7 @@ class spell_hallow_end_trick : public SpellScriptLoader class spell_hallow_end_trick_SpellScript : public SpellScript { PrepareSpellScript(spell_hallow_end_trick_SpellScript); + bool Validate(SpellInfo const* /*spell*/) { if (!sSpellMgr->GetSpellInfo(SPELL_PIRATE_COSTUME_MALE) || !sSpellMgr->GetSpellInfo(SPELL_PIRATE_COSTUME_FEMALE) || !sSpellMgr->GetSpellInfo(SPELL_NINJA_COSTUME_MALE) @@ -170,7 +173,7 @@ class spell_hallow_end_trick : public SpellScriptLoader break; } - caster->CastSpell(target, spellId, true, NULL); + caster->CastSpell(target, spellId, true); } } @@ -218,8 +221,8 @@ class spell_hallow_end_trick_or_treat : public SpellScriptLoader Unit* caster = GetCaster(); if (Player* target = GetHitPlayer()) { - caster->CastSpell(target, roll_chance_i(50) ? SPELL_TRICK : SPELL_TREAT, true, NULL); - caster->CastSpell(target, SPELL_TRICKED_OR_TREATED, true, NULL); + caster->CastSpell(target, roll_chance_i(50) ? SPELL_TRICK : SPELL_TREAT, true); + caster->CastSpell(target, SPELL_TRICKED_OR_TREATED, true); } } @@ -301,27 +304,10 @@ class spell_winter_veil_mistletoe : public SpellScriptLoader void HandleScript(SpellEffIndex /*effIndex*/) { - Unit* caster = GetCaster(); - if (Player* target = GetHitPlayer()) { - uint32 spellId = 0; - switch (urand(0, 2)) - { - case 0: - spellId = SPELL_CREATE_MISTLETOE; - break; - case 1: - spellId = SPELL_CREATE_HOLLY; - break; - case 2: - spellId = SPELL_CREATE_SNOWFLAKES; - break; - default: - return; - } - - caster->CastSpell(target, spellId, true); + uint32 spellId = RAND(SPELL_CREATE_HOLLY, SPELL_CREATE_MISTLETOE, SPELL_CREATE_SNOWFLAKES); + GetCaster()->CastSpell(target, spellId, true); } } @@ -337,6 +323,71 @@ class spell_winter_veil_mistletoe : public SpellScriptLoader } }; +// 26275 - PX-238 Winter Wondervolt TRAP +enum PX238WinterWondervolt +{ + SPELL_PX_238_WINTER_WONDERVOLT_TRANSFORM_1 = 26157, + SPELL_PX_238_WINTER_WONDERVOLT_TRANSFORM_2 = 26272, + SPELL_PX_238_WINTER_WONDERVOLT_TRANSFORM_3 = 26273, + SPELL_PX_238_WINTER_WONDERVOLT_TRANSFORM_4 = 26274 +}; + +class spell_winter_veil_px_238_winter_wondervolt : public SpellScriptLoader +{ + public: + spell_winter_veil_px_238_winter_wondervolt() : SpellScriptLoader("spell_winter_veil_px_238_winter_wondervolt") { } + + class spell_winter_veil_px_238_winter_wondervolt_SpellScript : public SpellScript + { + PrepareSpellScript(spell_winter_veil_px_238_winter_wondervolt_SpellScript); + + bool Validate(SpellInfo const* /*spellInfo*/) + { + if (!sSpellMgr->GetSpellInfo(SPELL_PX_238_WINTER_WONDERVOLT_TRANSFORM_1) || + !sSpellMgr->GetSpellInfo(SPELL_PX_238_WINTER_WONDERVOLT_TRANSFORM_2) || + !sSpellMgr->GetSpellInfo(SPELL_PX_238_WINTER_WONDERVOLT_TRANSFORM_3) || + !sSpellMgr->GetSpellInfo(SPELL_PX_238_WINTER_WONDERVOLT_TRANSFORM_4)) + return false; + return true; + } + + void HandleScript(SpellEffIndex effIndex) + { + PreventHitDefaultEffect(effIndex); + + uint32 const spells[4] = + { + SPELL_PX_238_WINTER_WONDERVOLT_TRANSFORM_1, + SPELL_PX_238_WINTER_WONDERVOLT_TRANSFORM_2, + SPELL_PX_238_WINTER_WONDERVOLT_TRANSFORM_3, + SPELL_PX_238_WINTER_WONDERVOLT_TRANSFORM_4 + }; + + if (Unit* target = GetHitUnit()) + { + for (uint8 i = 0; i < 4; ++i) + if (target->HasAura(spells[i])) + return; + + target->CastSpell(target, spells[urand(0, 3)], true); + } + } + + void Register() + { + OnEffectHitTarget += SpellEffectFn(spell_winter_veil_px_238_winter_wondervolt_SpellScript::HandleScript, EFFECT_0, SPELL_EFFECT_SCRIPT_EFFECT); + } + + private: + + }; + + SpellScript* GetSpellScript() const + { + return new spell_winter_veil_px_238_winter_wondervolt_SpellScript(); + } +}; + void AddSC_holiday_spell_scripts() { // Love is in the Air @@ -347,4 +398,5 @@ void AddSC_holiday_spell_scripts() new spell_hallow_end_tricky_treat(); // Winter Veil new spell_winter_veil_mistletoe(); + new spell_winter_veil_px_238_winter_wondervolt(); } diff --git a/src/server/scripts/Spells/spell_hunter.cpp b/src/server/scripts/Spells/spell_hunter.cpp index 18326a8f059..08f65d8323f 100644 --- a/src/server/scripts/Spells/spell_hunter.cpp +++ b/src/server/scripts/Spells/spell_hunter.cpp @@ -32,23 +32,28 @@ enum HunterSpells { - HUNTER_SPELL_READINESS = 23989, - DRAENEI_SPELL_GIFT_OF_THE_NAARU = 59543, - HUNTER_SPELL_BESTIAL_WRATH = 19574, - HUNTER_PET_SPELL_LAST_STAND_TRIGGERED = 53479, - HUNTER_PET_HEART_OF_THE_PHOENIX = 55709, - HUNTER_PET_HEART_OF_THE_PHOENIX_TRIGGERED = 54114, - HUNTER_PET_HEART_OF_THE_PHOENIX_DEBUFF = 55711, - HUNTER_PET_SPELL_CARRION_FEEDER_TRIGGERED = 54045, - HUNTER_SPELL_INVIGORATION_TRIGGERED = 53398, - HUNTER_SPELL_MASTERS_CALL_TRIGGERED = 62305, - HUNTER_SPELL_CHIMERA_SHOT_SERPENT = 53353, - HUNTER_SPELL_CHIMERA_SHOT_VIPER = 53358, - HUNTER_SPELL_CHIMERA_SHOT_SCORPID = 53359, - HUNTER_SPELL_ASPECT_OF_THE_BEAST_PET = 61669, + SPELL_HUNTER_ASPECT_OF_THE_BEAST_PET = 61669, + SPELL_HUNTER_ASPECT_OF_THE_VIPER_ENERGIZE = 34075, + SPELL_HUNTER_BESTIAL_WRATH = 19574, + SPELL_HUNTER_CHIMERA_SHOT_SERPENT = 53353, + SPELL_HUNTER_CHIMERA_SHOT_VIPER = 53358, + SPELL_HUNTER_CHIMERA_SHOT_SCORPID = 53359, + SPELL_HUNTER_GLYPH_OF_ASPECT_OF_THE_VIPER = 56851, + SPELL_HUNTER_INVIGORATION_TRIGGERED = 53398, + SPELL_HUNTER_MASTERS_CALL_TRIGGERED = 62305, + SPELL_HUNTER_MISDIRECTION_PROC = 35079, + SPELL_HUNTER_PET_LAST_STAND_TRIGGERED = 53479, + SPELL_HUNTER_PET_HEART_OF_THE_PHOENIX = 55709, + SPELL_HUNTER_PET_HEART_OF_THE_PHOENIX_TRIGGERED = 54114, + SPELL_HUNTER_PET_HEART_OF_THE_PHOENIX_DEBUFF = 55711, + SPELL_HUNTER_PET_CARRION_FEEDER_TRIGGERED = 54045, + SPELL_HUNTER_READINESS = 23989, + SPELL_HUNTER_SNIPER_TRAINING_R1 = 53302, + SPELL_HUNTER_SNIPER_TRAINING_BUFF_R1 = 64418, + SPELL_DRAENEI_GIFT_OF_THE_NAARU = 59543, }; -// 13161 Aspect of the Beast +// 13161 - Aspect of the Beast class spell_hun_aspect_of_the_beast : public SpellScriptLoader { public: @@ -63,9 +68,9 @@ class spell_hun_aspect_of_the_beast : public SpellScriptLoader return GetCaster()->GetTypeId() == TYPEID_PLAYER; } - bool Validate(SpellInfo const* /*entry*/) + bool Validate(SpellInfo const* /*spellInfo*/) { - if (!sSpellMgr->GetSpellInfo(HUNTER_SPELL_ASPECT_OF_THE_BEAST_PET)) + if (!sSpellMgr->GetSpellInfo(SPELL_HUNTER_ASPECT_OF_THE_BEAST_PET)) return false; return true; } @@ -74,14 +79,14 @@ class spell_hun_aspect_of_the_beast : public SpellScriptLoader { if (Player* caster = GetCaster()->ToPlayer()) if (Pet* pet = caster->GetPet()) - pet->RemoveAurasDueToSpell(HUNTER_SPELL_ASPECT_OF_THE_BEAST_PET); + pet->RemoveAurasDueToSpell(SPELL_HUNTER_ASPECT_OF_THE_BEAST_PET); } void OnApply(AuraEffect const* /*aurEff*/, AuraEffectHandleModes /*mode*/) { if (Player* caster = GetCaster()->ToPlayer()) if (caster->GetPet()) - caster->CastSpell(caster, HUNTER_SPELL_ASPECT_OF_THE_BEAST_PET, true); + caster->CastSpell(caster, SPELL_HUNTER_ASPECT_OF_THE_BEAST_PET, true); } void Register() @@ -97,7 +102,51 @@ class spell_hun_aspect_of_the_beast : public SpellScriptLoader } }; -// 53209 Chimera Shot +// 34074 - Aspect of the Viper +class spell_hun_ascpect_of_the_viper : public SpellScriptLoader +{ + public: + spell_hun_ascpect_of_the_viper() : SpellScriptLoader("spell_hun_ascpect_of_the_viper") { } + + class spell_hun_ascpect_of_the_viper_AuraScript : public AuraScript + { + PrepareAuraScript(spell_hun_ascpect_of_the_viper_AuraScript); + + bool Validate(SpellInfo const* /*spellInfo*/) + { + if (!sSpellMgr->GetSpellInfo(SPELL_HUNTER_ASPECT_OF_THE_VIPER_ENERGIZE)) + return false; + if (!sSpellMgr->GetSpellInfo(SPELL_HUNTER_GLYPH_OF_ASPECT_OF_THE_VIPER)) + return false; + return true; + } + + void HandleProc(AuraEffect const* aurEff, ProcEventInfo& /*eventInfo*/) + { + PreventDefaultAction(); + + uint32 maxMana = GetTarget()->GetMaxPower(POWER_MANA); + int32 mana = CalculatePct(maxMana, GetTarget()->GetAttackTime(RANGED_ATTACK) / 1000.0f); + + if (AuraEffect const* glyph = GetTarget()->GetAuraEffect(SPELL_HUNTER_GLYPH_OF_ASPECT_OF_THE_VIPER, EFFECT_0)) + AddPct(mana, glyph->GetAmount()); + + GetTarget()->CastCustomSpell(SPELL_HUNTER_ASPECT_OF_THE_VIPER_ENERGIZE, SPELLVALUE_BASE_POINT0, mana, GetTarget(), true, NULL, aurEff); + } + + void Register() + { + OnEffectProc += AuraEffectProcFn(spell_hun_ascpect_of_the_viper_AuraScript::HandleProc, EFFECT_0, SPELL_AURA_OBS_MOD_POWER); + } + }; + + AuraScript* GetAuraScript() const + { + return new spell_hun_ascpect_of_the_viper_AuraScript(); + } +}; + +// 53209 - Chimera Shot class spell_hun_chimera_shot : public SpellScriptLoader { public: @@ -107,9 +156,9 @@ class spell_hun_chimera_shot : public SpellScriptLoader { PrepareSpellScript(spell_hun_chimera_shot_SpellScript); - bool Validate(SpellInfo const* /*spellEntry*/) + bool Validate(SpellInfo const* /*spellInfo*/) { - if (!sSpellMgr->GetSpellInfo(HUNTER_SPELL_CHIMERA_SHOT_SERPENT) || !sSpellMgr->GetSpellInfo(HUNTER_SPELL_CHIMERA_SHOT_VIPER) || !sSpellMgr->GetSpellInfo(HUNTER_SPELL_CHIMERA_SHOT_SCORPID)) + if (!sSpellMgr->GetSpellInfo(SPELL_HUNTER_CHIMERA_SHOT_SERPENT) || !sSpellMgr->GetSpellInfo(SPELL_HUNTER_CHIMERA_SHOT_VIPER) || !sSpellMgr->GetSpellInfo(SPELL_HUNTER_CHIMERA_SHOT_SCORPID)) return false; return true; } @@ -138,7 +187,7 @@ class spell_hun_chimera_shot : public SpellScriptLoader if (familyFlag[0] & 0x4000) { int32 TickCount = aurEff->GetTotalTicks(); - spellId = HUNTER_SPELL_CHIMERA_SHOT_SERPENT; + spellId = SPELL_HUNTER_CHIMERA_SHOT_SERPENT; basePoint = caster->SpellDamageBonusDone(unitTarget, aura->GetSpellInfo(), aurEff->GetAmount(), DOT, aura->GetStackAmount()); ApplyPct(basePoint, TickCount * 40); basePoint = unitTarget->SpellDamageBonusTaken(caster, aura->GetSpellInfo(), basePoint, DOT, aura->GetStackAmount()); @@ -147,18 +196,18 @@ class spell_hun_chimera_shot : public SpellScriptLoader else if (familyFlag[1] & 0x00000080) { int32 TickCount = aura->GetEffect(0)->GetTotalTicks(); - spellId = HUNTER_SPELL_CHIMERA_SHOT_VIPER; + spellId = SPELL_HUNTER_CHIMERA_SHOT_VIPER; // Amount of one aura tick basePoint = int32(CalculatePct(unitTarget->GetMaxPower(POWER_MANA), aurEff->GetAmount())); - int32 casterBasePoint = aurEff->GetAmount() * unitTarget->GetMaxPower(POWER_MANA) / 50; // TODO: WTF? caster uses unitTarget? + int32 casterBasePoint = aurEff->GetAmount() * unitTarget->GetMaxPower(POWER_MANA) / 50; /// @todo WTF? caster uses unitTarget? if (basePoint > casterBasePoint) basePoint = casterBasePoint; ApplyPct(basePoint, TickCount * 60); } // Scorpid Sting - Attempts to Disarm the target for 10 sec. This effect cannot occur more than once per 1 minute. else if (familyFlag[0] & 0x00008000) - spellId = HUNTER_SPELL_CHIMERA_SHOT_SCORPID; + spellId = SPELL_HUNTER_CHIMERA_SHOT_SCORPID; // ?? nothing say in spell desc (possibly need addition check) //if (familyFlag & 0x0000010000000000LL || // dot // familyFlag & 0x0000100000000000LL) // stun @@ -173,7 +222,7 @@ class spell_hun_chimera_shot : public SpellScriptLoader } if (spellId) caster->CastCustomSpell(unitTarget, spellId, &basePoint, 0, 0, true); - if (spellId == HUNTER_SPELL_CHIMERA_SHOT_SCORPID && caster->ToPlayer()) // Scorpid Sting - Add 1 minute cooldown + if (spellId == SPELL_HUNTER_CHIMERA_SHOT_SCORPID && caster->ToPlayer()) // Scorpid Sting - Add 1 minute cooldown caster->ToPlayer()->AddSpellCooldown(spellId, 0, uint32(time(NULL) + 60)); } } @@ -190,7 +239,38 @@ class spell_hun_chimera_shot : public SpellScriptLoader } }; -// 53412 Invigoration +// 781 - Disengage +class spell_hun_disengage : public SpellScriptLoader +{ + public: + spell_hun_disengage() : SpellScriptLoader("spell_hun_disengage") { } + + class spell_hun_disengage_SpellScript : public SpellScript + { + PrepareSpellScript(spell_hun_disengage_SpellScript); + + SpellCastResult CheckCast() + { + Unit* caster = GetCaster(); + if (caster->GetTypeId() == TYPEID_PLAYER && !caster->isInCombat()) + return SPELL_FAILED_CANT_DO_THAT_RIGHT_NOW; + + return SPELL_CAST_OK; + } + + void Register() + { + OnCheckCast += SpellCheckCastFn(spell_hun_disengage_SpellScript::CheckCast); + } + }; + + SpellScript* GetSpellScript() const + { + return new spell_hun_disengage_SpellScript(); + } +}; + +// 53412 - Invigoration class spell_hun_invigoration : public SpellScriptLoader { public: @@ -200,9 +280,9 @@ class spell_hun_invigoration : public SpellScriptLoader { PrepareSpellScript(spell_hun_invigoration_SpellScript); - bool Validate(SpellInfo const* /*spellEntry*/) + bool Validate(SpellInfo const* /*spellInfo*/) { - if (!sSpellMgr->GetSpellInfo(HUNTER_SPELL_INVIGORATION_TRIGGERED)) + if (!sSpellMgr->GetSpellInfo(SPELL_HUNTER_INVIGORATION_TRIGGERED)) return false; return true; } @@ -212,7 +292,7 @@ class spell_hun_invigoration : public SpellScriptLoader if (Unit* unitTarget = GetHitUnit()) if (AuraEffect* aurEff = unitTarget->GetDummyAuraEffect(SPELLFAMILY_HUNTER, 3487, 0)) if (roll_chance_i(aurEff->GetAmount())) - unitTarget->CastSpell(unitTarget, HUNTER_SPELL_INVIGORATION_TRIGGERED, true); + unitTarget->CastSpell(unitTarget, SPELL_HUNTER_INVIGORATION_TRIGGERED, true); } void Register() @@ -227,6 +307,7 @@ class spell_hun_invigoration : public SpellScriptLoader } }; +// 53478 - Last Stand Pet class spell_hun_last_stand_pet : public SpellScriptLoader { public: @@ -236,9 +317,9 @@ class spell_hun_last_stand_pet : public SpellScriptLoader { PrepareSpellScript(spell_hun_last_stand_pet_SpellScript); - bool Validate(SpellInfo const* /*spellEntry*/) + bool Validate(SpellInfo const* /*spellInfo*/) { - if (!sSpellMgr->GetSpellInfo(HUNTER_PET_SPELL_LAST_STAND_TRIGGERED)) + if (!sSpellMgr->GetSpellInfo(SPELL_HUNTER_PET_LAST_STAND_TRIGGERED)) return false; return true; } @@ -247,12 +328,11 @@ class spell_hun_last_stand_pet : public SpellScriptLoader { Unit* caster = GetCaster(); int32 healthModSpellBasePoints0 = int32(caster->CountPctFromMaxHealth(30)); - caster->CastCustomSpell(caster, HUNTER_PET_SPELL_LAST_STAND_TRIGGERED, &healthModSpellBasePoints0, NULL, NULL, true, NULL); + caster->CastCustomSpell(caster, SPELL_HUNTER_PET_LAST_STAND_TRIGGERED, &healthModSpellBasePoints0, NULL, NULL, true, NULL); } void Register() { - // add dummy effect spell handler to pet's Last Stand OnEffectHitTarget += SpellEffectFn(spell_hun_last_stand_pet_SpellScript::HandleDummy, EFFECT_0, SPELL_EFFECT_DUMMY); } }; @@ -263,6 +343,7 @@ class spell_hun_last_stand_pet : public SpellScriptLoader } }; +// 53271 - Masters Call class spell_hun_masters_call : public SpellScriptLoader { public: @@ -272,9 +353,9 @@ class spell_hun_masters_call : public SpellScriptLoader { PrepareSpellScript(spell_hun_masters_call_SpellScript); - bool Validate(SpellInfo const* spellEntry) + bool Validate(SpellInfo const* spellInfo) { - if (!sSpellMgr->GetSpellInfo(HUNTER_SPELL_MASTERS_CALL_TRIGGERED) || !sSpellMgr->GetSpellInfo(spellEntry->Effects[EFFECT_0].CalcValue()) || !sSpellMgr->GetSpellInfo(spellEntry->Effects[EFFECT_1].CalcValue())) + if (!sSpellMgr->GetSpellInfo(SPELL_HUNTER_MASTERS_CALL_TRIGGERED) || !sSpellMgr->GetSpellInfo(spellInfo->Effects[EFFECT_0].CalcValue()) || !sSpellMgr->GetSpellInfo(spellInfo->Effects[EFFECT_1].CalcValue())) return false; return true; } @@ -297,7 +378,7 @@ class spell_hun_masters_call : public SpellScriptLoader { // Cannot be processed while pet is dead TriggerCastFlags castMask = TriggerCastFlags(TRIGGERED_FULL_MASK & ~TRIGGERED_IGNORE_CASTER_AURASTATE); - target->CastSpell(target, HUNTER_SPELL_MASTERS_CALL_TRIGGERED, castMask); + target->CastSpell(target, SPELL_HUNTER_MASTERS_CALL_TRIGGERED, castMask); } } @@ -314,156 +395,139 @@ class spell_hun_masters_call : public SpellScriptLoader } }; -class spell_hun_readiness : public SpellScriptLoader +// 34477 - Misdirection +class spell_hun_misdirection : public SpellScriptLoader { public: - spell_hun_readiness() : SpellScriptLoader("spell_hun_readiness") { } + spell_hun_misdirection() : SpellScriptLoader("spell_hun_misdirection") { } - class spell_hun_readiness_SpellScript : public SpellScript + class spell_hun_misdirection_AuraScript : public AuraScript { - PrepareSpellScript(spell_hun_readiness_SpellScript); + PrepareAuraScript(spell_hun_misdirection_AuraScript); - bool Load() + bool Validate(SpellInfo const* /*spellInfo*/) { - return GetCaster()->GetTypeId() == TYPEID_PLAYER; + if (!sSpellMgr->GetSpellInfo(SPELL_HUNTER_MISDIRECTION_PROC)) + return false; + return true; } - void HandleDummy(SpellEffIndex /*effIndex*/) + void OnRemove(AuraEffect const* /*aurEff*/, AuraEffectHandleModes /*mode*/) { - Player* caster = GetCaster()->ToPlayer(); - // immediately finishes the cooldown on your other Hunter abilities except Bestial Wrath - const SpellCooldowns& cm = caster->ToPlayer()->GetSpellCooldownMap(); - for (SpellCooldowns::const_iterator itr = cm.begin(); itr != cm.end();) - { - SpellInfo const* spellInfo = sSpellMgr->GetSpellInfo(itr->first); + if (GetTargetApplication()->GetRemoveMode() != AURA_REMOVE_BY_DEFAULT) + GetTarget()->ResetRedirectThreat(); + } - ///! If spellId in cooldown map isn't valid, the above will return a null pointer. - if (spellInfo && - spellInfo->SpellFamilyName == SPELLFAMILY_HUNTER && - spellInfo->Id != HUNTER_SPELL_READINESS && - spellInfo->Id != HUNTER_SPELL_BESTIAL_WRATH && - spellInfo->Id != DRAENEI_SPELL_GIFT_OF_THE_NAARU && - spellInfo->GetRecoveryTime() > 0) - caster->RemoveSpellCooldown((itr++)->first, true); - else - ++itr; - } + bool CheckProc(ProcEventInfo& /*eventInfo*/) + { + return GetTarget()->GetRedirectThreatTarget(); + } + + void HandleProc(AuraEffect const* aurEff, ProcEventInfo& /*eventInfo*/) + { + PreventDefaultAction(); + GetTarget()->CastSpell(GetTarget(), SPELL_HUNTER_MISDIRECTION_PROC, true, NULL, aurEff); } void Register() { - // add dummy effect spell handler to Readiness - OnEffectHitTarget += SpellEffectFn(spell_hun_readiness_SpellScript::HandleDummy, EFFECT_0, SPELL_EFFECT_DUMMY); + AfterEffectRemove += AuraEffectRemoveFn(spell_hun_misdirection_AuraScript::OnRemove, EFFECT_1, SPELL_AURA_DUMMY, AURA_EFFECT_HANDLE_REAL); + DoCheckProc += AuraCheckProcFn(spell_hun_misdirection_AuraScript::CheckProc); + OnEffectProc += AuraEffectProcFn(spell_hun_misdirection_AuraScript::HandleProc, EFFECT_1, SPELL_AURA_DUMMY); } }; - SpellScript* GetSpellScript() const + AuraScript* GetAuraScript() const { - return new spell_hun_readiness_SpellScript(); + return new spell_hun_misdirection_AuraScript(); } }; -// 37506 Scatter Shot -class spell_hun_scatter_shot : public SpellScriptLoader +// 35079 - Misdirection (Proc) +class spell_hun_misdirection_proc : public SpellScriptLoader { public: - spell_hun_scatter_shot() : SpellScriptLoader("spell_hun_scatter_shot") { } + spell_hun_misdirection_proc() : SpellScriptLoader("spell_hun_misdirection_proc") { } - class spell_hun_scatter_shot_SpellScript : public SpellScript + class spell_hun_misdirection_proc_AuraScript : public AuraScript { - PrepareSpellScript(spell_hun_scatter_shot_SpellScript); - - bool Load() - { - return GetCaster()->GetTypeId() == TYPEID_PLAYER; - } + PrepareAuraScript(spell_hun_misdirection_proc_AuraScript); - void HandleDummy(SpellEffIndex /*effIndex*/) + void OnRemove(AuraEffect const* /*aurEff*/, AuraEffectHandleModes /*mode*/) { - Player* caster = GetCaster()->ToPlayer(); - // break Auto Shot and autohit - caster->InterruptSpell(CURRENT_AUTOREPEAT_SPELL); - caster->AttackStop(); - caster->SendAttackSwingCancelAttack(); + GetTarget()->ResetRedirectThreat(); } void Register() { - OnEffectHitTarget += SpellEffectFn(spell_hun_scatter_shot_SpellScript::HandleDummy, EFFECT_0, SPELL_EFFECT_DUMMY); + AfterEffectRemove += AuraEffectRemoveFn(spell_hun_misdirection_proc_AuraScript::OnRemove, EFFECT_0, SPELL_AURA_DUMMY, AURA_EFFECT_HANDLE_REAL); } }; - SpellScript* GetSpellScript() const + AuraScript* GetAuraScript() const { - return new spell_hun_scatter_shot_SpellScript(); + return new spell_hun_misdirection_proc_AuraScript(); } }; -// 53302, 53303, 53304 Sniper Training -enum eSniperTrainingSpells -{ - SPELL_SNIPER_TRAINING_R1 = 53302, - SPELL_SNIPER_TRAINING_BUFF_R1 = 64418, -}; - -class spell_hun_sniper_training : public SpellScriptLoader +// 54044 - Pet Carrion Feeder +class spell_hun_pet_carrion_feeder : public SpellScriptLoader { public: - spell_hun_sniper_training() : SpellScriptLoader("spell_hun_sniper_training") { } + spell_hun_pet_carrion_feeder() : SpellScriptLoader("spell_hun_pet_carrion_feeder") { } - class spell_hun_sniper_training_AuraScript : public AuraScript + class spell_hun_pet_carrion_feeder_SpellScript : public SpellScript { - PrepareAuraScript(spell_hun_sniper_training_AuraScript); + PrepareSpellScript(spell_hun_pet_carrion_feeder_SpellScript); - bool Validate(SpellInfo const* /*entry*/) + bool Load() { - if (!sSpellMgr->GetSpellInfo(SPELL_SNIPER_TRAINING_R1) || !sSpellMgr->GetSpellInfo(SPELL_SNIPER_TRAINING_BUFF_R1)) + if (!GetCaster()->isPet()) return false; return true; } - void HandlePeriodic(AuraEffect const* aurEff) + bool Validate(SpellInfo const* /*spellInfo*/) { - PreventDefaultAction(); - if (aurEff->GetAmount() <= 0) - { - Unit* caster = GetCaster(); - uint32 spellId = SPELL_SNIPER_TRAINING_BUFF_R1 + GetId() - SPELL_SNIPER_TRAINING_R1; - if (Unit* target = GetTarget()) - if (!target->HasAura(spellId)) - { - SpellInfo const* triggeredSpellInfo = sSpellMgr->GetSpellInfo(spellId); - Unit* triggerCaster = triggeredSpellInfo->NeedsToBeTriggeredByCaster() ? caster : target; - triggerCaster->CastSpell(target, triggeredSpellInfo, true, 0, aurEff); - } - } + if (!sSpellMgr->GetSpellInfo(SPELL_HUNTER_PET_CARRION_FEEDER_TRIGGERED)) + return false; + return true; } - void HandleUpdatePeriodic(AuraEffect* aurEff) + SpellCastResult CheckIfCorpseNear() { - if (Player* playerTarget = GetUnitOwner()->ToPlayer()) - { - int32 baseAmount = aurEff->GetBaseAmount(); - int32 amount = playerTarget->isMoving() ? - playerTarget->CalculateSpellDamage(playerTarget, GetSpellInfo(), aurEff->GetEffIndex(), &baseAmount) : - aurEff->GetAmount() - 1; - aurEff->SetAmount(amount); - } + Unit* caster = GetCaster(); + float max_range = GetSpellInfo()->GetMaxRange(false); + WorldObject* result = NULL; + // search for nearby enemy corpse in range + Trinity::AnyDeadUnitSpellTargetInRangeCheck check(caster, max_range, GetSpellInfo(), TARGET_CHECK_ENEMY); + Trinity::WorldObjectSearcher<Trinity::AnyDeadUnitSpellTargetInRangeCheck> searcher(caster, result, check); + caster->GetMap()->VisitFirstFound(caster->m_positionX, caster->m_positionY, max_range, searcher); + if (!result) + return SPELL_FAILED_NO_EDIBLE_CORPSES; + return SPELL_CAST_OK; + } + + void HandleDummy(SpellEffIndex /*effIndex*/) + { + Unit* caster = GetCaster(); + caster->CastSpell(caster, SPELL_HUNTER_PET_CARRION_FEEDER_TRIGGERED, false); } void Register() { - OnEffectPeriodic += AuraEffectPeriodicFn(spell_hun_sniper_training_AuraScript::HandlePeriodic, EFFECT_0, SPELL_AURA_PERIODIC_TRIGGER_SPELL); - OnEffectUpdatePeriodic += AuraEffectUpdatePeriodicFn(spell_hun_sniper_training_AuraScript::HandleUpdatePeriodic, EFFECT_0, SPELL_AURA_PERIODIC_TRIGGER_SPELL); + OnEffectHit += SpellEffectFn(spell_hun_pet_carrion_feeder_SpellScript::HandleDummy, EFFECT_0, SPELL_EFFECT_DUMMY); + OnCheckCast += SpellCheckCastFn(spell_hun_pet_carrion_feeder_SpellScript::CheckIfCorpseNear); } }; - AuraScript* GetAuraScript() const + SpellScript* GetSpellScript() const { - return new spell_hun_sniper_training_AuraScript(); + return new spell_hun_pet_carrion_feeder_SpellScript(); } }; +// 55709 - Pet Heart of the Phoenix class spell_hun_pet_heart_of_the_phoenix : public SpellScriptLoader { public: @@ -480,9 +544,9 @@ class spell_hun_pet_heart_of_the_phoenix : public SpellScriptLoader return true; } - bool Validate(SpellInfo const* /*spellEntry*/) + bool Validate(SpellInfo const* /*spellInfo*/) { - if (!sSpellMgr->GetSpellInfo(HUNTER_PET_HEART_OF_THE_PHOENIX_TRIGGERED) || !sSpellMgr->GetSpellInfo(HUNTER_PET_HEART_OF_THE_PHOENIX_DEBUFF)) + if (!sSpellMgr->GetSpellInfo(SPELL_HUNTER_PET_HEART_OF_THE_PHOENIX_TRIGGERED) || !sSpellMgr->GetSpellInfo(SPELL_HUNTER_PET_HEART_OF_THE_PHOENIX_DEBUFF)) return false; return true; } @@ -491,16 +555,15 @@ class spell_hun_pet_heart_of_the_phoenix : public SpellScriptLoader { Unit* caster = GetCaster(); if (Unit* owner = caster->GetOwner()) - if (!caster->HasAura(HUNTER_PET_HEART_OF_THE_PHOENIX_DEBUFF)) + if (!caster->HasAura(SPELL_HUNTER_PET_HEART_OF_THE_PHOENIX_DEBUFF)) { - owner->CastCustomSpell(HUNTER_PET_HEART_OF_THE_PHOENIX_TRIGGERED, SPELLVALUE_BASE_POINT0, 100, caster, true); - caster->CastSpell(caster, HUNTER_PET_HEART_OF_THE_PHOENIX_DEBUFF, true); + owner->CastCustomSpell(SPELL_HUNTER_PET_HEART_OF_THE_PHOENIX_TRIGGERED, SPELLVALUE_BASE_POINT0, 100, caster, true); + caster->CastSpell(caster, SPELL_HUNTER_PET_HEART_OF_THE_PHOENIX_DEBUFF, true); } } void Register() { - // add dummy effect spell handler to pet's Last Stand OnEffectHitTarget += SpellEffectFn(spell_hun_pet_heart_of_the_phoenix_SpellScript::HandleScript, EFFECT_0, SPELL_EFFECT_SCRIPT_EFFECT); } }; @@ -511,150 +574,151 @@ class spell_hun_pet_heart_of_the_phoenix : public SpellScriptLoader } }; -class spell_hun_pet_carrion_feeder : public SpellScriptLoader +// 23989 - Readiness +class spell_hun_readiness : public SpellScriptLoader { public: - spell_hun_pet_carrion_feeder() : SpellScriptLoader("spell_hun_pet_carrion_feeder") { } + spell_hun_readiness() : SpellScriptLoader("spell_hun_readiness") { } - class spell_hun_pet_carrion_feeder_SpellScript : public SpellScript + class spell_hun_readiness_SpellScript : public SpellScript { - PrepareSpellScript(spell_hun_pet_carrion_feeder_SpellScript); + PrepareSpellScript(spell_hun_readiness_SpellScript); bool Load() { - if (!GetCaster()->isPet()) - return false; - return true; - } - - bool Validate(SpellInfo const* /*spellEntry*/) - { - if (!sSpellMgr->GetSpellInfo(HUNTER_PET_SPELL_CARRION_FEEDER_TRIGGERED)) - return false; - return true; - } - - SpellCastResult CheckIfCorpseNear() - { - Unit* caster = GetCaster(); - float max_range = GetSpellInfo()->GetMaxRange(false); - WorldObject* result = NULL; - // search for nearby enemy corpse in range - Trinity::AnyDeadUnitSpellTargetInRangeCheck check(caster, max_range, GetSpellInfo(), TARGET_CHECK_ENEMY); - Trinity::WorldObjectSearcher<Trinity::AnyDeadUnitSpellTargetInRangeCheck> searcher(caster, result, check); - caster->GetMap()->VisitFirstFound(caster->m_positionX, caster->m_positionY, max_range, searcher); - if (!result) - return SPELL_FAILED_NO_EDIBLE_CORPSES; - return SPELL_CAST_OK; + return GetCaster()->GetTypeId() == TYPEID_PLAYER; } void HandleDummy(SpellEffIndex /*effIndex*/) { - Unit* caster = GetCaster(); - caster->CastSpell(caster, HUNTER_PET_SPELL_CARRION_FEEDER_TRIGGERED, false); + Player* caster = GetCaster()->ToPlayer(); + // immediately finishes the cooldown on your other Hunter abilities except Bestial Wrath + const SpellCooldowns& cm = caster->ToPlayer()->GetSpellCooldownMap(); + for (SpellCooldowns::const_iterator itr = cm.begin(); itr != cm.end();) + { + SpellInfo const* spellInfo = sSpellMgr->GetSpellInfo(itr->first); + + ///! If spellId in cooldown map isn't valid, the above will return a null pointer. + if (spellInfo && + spellInfo->SpellFamilyName == SPELLFAMILY_HUNTER && + spellInfo->Id != SPELL_HUNTER_READINESS && + spellInfo->Id != SPELL_HUNTER_BESTIAL_WRATH && + spellInfo->Id != SPELL_DRAENEI_GIFT_OF_THE_NAARU && + spellInfo->GetRecoveryTime() > 0) + caster->RemoveSpellCooldown((itr++)->first, true); + else + ++itr; + } } void Register() { - // add dummy effect spell handler to pet's Last Stand - OnEffectHit += SpellEffectFn(spell_hun_pet_carrion_feeder_SpellScript::HandleDummy, EFFECT_0, SPELL_EFFECT_DUMMY); - OnCheckCast += SpellCheckCastFn(spell_hun_pet_carrion_feeder_SpellScript::CheckIfCorpseNear); + OnEffectHitTarget += SpellEffectFn(spell_hun_readiness_SpellScript::HandleDummy, EFFECT_0, SPELL_EFFECT_DUMMY); } }; SpellScript* GetSpellScript() const { - return new spell_hun_pet_carrion_feeder_SpellScript(); + return new spell_hun_readiness_SpellScript(); } }; -// 34477 Misdirection -class spell_hun_misdirection : public SpellScriptLoader +// 37506 - Scatter Shot +class spell_hun_scatter_shot : public SpellScriptLoader { public: - spell_hun_misdirection() : SpellScriptLoader("spell_hun_misdirection") { } + spell_hun_scatter_shot() : SpellScriptLoader("spell_hun_scatter_shot") { } - class spell_hun_misdirection_AuraScript : public AuraScript + class spell_hun_scatter_shot_SpellScript : public SpellScript { - PrepareAuraScript(spell_hun_misdirection_AuraScript); + PrepareSpellScript(spell_hun_scatter_shot_SpellScript); - void OnRemove(AuraEffect const* /*aurEff*/, AuraEffectHandleModes /*mode*/) + bool Load() + { + return GetCaster()->GetTypeId() == TYPEID_PLAYER; + } + + void HandleDummy(SpellEffIndex /*effIndex*/) { - if (Unit* caster = GetCaster()) - if (GetTargetApplication()->GetRemoveMode() != AURA_REMOVE_BY_DEFAULT) - caster->SetReducedThreatPercent(0, 0); + Player* caster = GetCaster()->ToPlayer(); + // break Auto Shot and autohit + caster->InterruptSpell(CURRENT_AUTOREPEAT_SPELL); + caster->AttackStop(); + caster->SendAttackSwingCancelAttack(); } void Register() { - AfterEffectRemove += AuraEffectRemoveFn(spell_hun_misdirection_AuraScript::OnRemove, EFFECT_1, SPELL_AURA_DUMMY, AURA_EFFECT_HANDLE_REAL); + OnEffectHitTarget += SpellEffectFn(spell_hun_scatter_shot_SpellScript::HandleDummy, EFFECT_0, SPELL_EFFECT_DUMMY); } }; - AuraScript* GetAuraScript() const + SpellScript* GetSpellScript() const { - return new spell_hun_misdirection_AuraScript(); + return new spell_hun_scatter_shot_SpellScript(); } }; -// 35079 Misdirection proc -class spell_hun_misdirection_proc : public SpellScriptLoader +// -53302 - Sniper Training +class spell_hun_sniper_training : public SpellScriptLoader { public: - spell_hun_misdirection_proc() : SpellScriptLoader("spell_hun_misdirection_proc") { } + spell_hun_sniper_training() : SpellScriptLoader("spell_hun_sniper_training") { } - class spell_hun_misdirection_proc_AuraScript : public AuraScript + class spell_hun_sniper_training_AuraScript : public AuraScript { - PrepareAuraScript(spell_hun_misdirection_proc_AuraScript); + PrepareAuraScript(spell_hun_sniper_training_AuraScript); - void OnRemove(AuraEffect const* /*aurEff*/, AuraEffectHandleModes /*mode*/) + bool Validate(SpellInfo const* /*spellInfo*/) { - if (GetCaster()) - GetCaster()->SetReducedThreatPercent(0, 0); + if (!sSpellMgr->GetSpellInfo(SPELL_HUNTER_SNIPER_TRAINING_R1) || !sSpellMgr->GetSpellInfo(SPELL_HUNTER_SNIPER_TRAINING_BUFF_R1)) + return false; + return true; } - void Register() + void HandlePeriodic(AuraEffect const* aurEff) { - AfterEffectRemove += AuraEffectRemoveFn(spell_hun_misdirection_proc_AuraScript::OnRemove, EFFECT_0, SPELL_AURA_DUMMY, AURA_EFFECT_HANDLE_REAL); + PreventDefaultAction(); + if (aurEff->GetAmount() <= 0) + { + Unit* caster = GetCaster(); + uint32 spellId = SPELL_HUNTER_SNIPER_TRAINING_BUFF_R1 + GetId() - SPELL_HUNTER_SNIPER_TRAINING_R1; + if (Unit* target = GetTarget()) + if (!target->HasAura(spellId)) + { + SpellInfo const* triggeredSpellInfo = sSpellMgr->GetSpellInfo(spellId); + Unit* triggerCaster = triggeredSpellInfo->NeedsToBeTriggeredByCaster() ? caster : target; + triggerCaster->CastSpell(target, triggeredSpellInfo, true, 0, aurEff); + } + } } - }; - - AuraScript* GetAuraScript() const - { - return new spell_hun_misdirection_proc_AuraScript(); - } -}; - -class spell_hun_disengage : public SpellScriptLoader -{ - public: - spell_hun_disengage() : SpellScriptLoader("spell_hun_disengage") { } - class spell_hun_disengage_SpellScript : public SpellScript - { - PrepareSpellScript(spell_hun_disengage_SpellScript); - - SpellCastResult CheckCast() + void HandleUpdatePeriodic(AuraEffect* aurEff) { - Unit* caster = GetCaster(); - if (caster->GetTypeId() == TYPEID_PLAYER && !caster->isInCombat()) - return SPELL_FAILED_CANT_DO_THAT_RIGHT_NOW; - - return SPELL_CAST_OK; + if (Player* playerTarget = GetUnitOwner()->ToPlayer()) + { + int32 baseAmount = aurEff->GetBaseAmount(); + int32 amount = playerTarget->isMoving() ? + playerTarget->CalculateSpellDamage(playerTarget, GetSpellInfo(), aurEff->GetEffIndex(), &baseAmount) : + aurEff->GetAmount() - 1; + aurEff->SetAmount(amount); + } } void Register() { - OnCheckCast += SpellCheckCastFn(spell_hun_disengage_SpellScript::CheckCast); + OnEffectPeriodic += AuraEffectPeriodicFn(spell_hun_sniper_training_AuraScript::HandlePeriodic, EFFECT_0, SPELL_AURA_PERIODIC_TRIGGER_SPELL); + OnEffectUpdatePeriodic += AuraEffectUpdatePeriodicFn(spell_hun_sniper_training_AuraScript::HandleUpdatePeriodic, EFFECT_0, SPELL_AURA_PERIODIC_TRIGGER_SPELL); } }; - SpellScript* GetSpellScript() const + AuraScript* GetAuraScript() const { - return new spell_hun_disengage_SpellScript(); + return new spell_hun_sniper_training_AuraScript(); } }; +// 1515 - Tame Beast class spell_hun_tame_beast : public SpellScriptLoader { public: @@ -706,6 +770,8 @@ class spell_hun_tame_beast : public SpellScriptLoader } }; +// -24604 - Furious Howl +// 53434 - Call of the Wild class spell_hun_target_only_pet_and_owner : public SpellScriptLoader { public: @@ -739,18 +805,19 @@ class spell_hun_target_only_pet_and_owner : public SpellScriptLoader void AddSC_hunter_spell_scripts() { new spell_hun_aspect_of_the_beast(); + new spell_hun_ascpect_of_the_viper(); new spell_hun_chimera_shot(); + new spell_hun_disengage(); new spell_hun_invigoration(); new spell_hun_last_stand_pet(); new spell_hun_masters_call(); + new spell_hun_misdirection(); + new spell_hun_misdirection_proc(); + new spell_hun_pet_carrion_feeder(); + new spell_hun_pet_heart_of_the_phoenix(); new spell_hun_readiness(); new spell_hun_scatter_shot(); new spell_hun_sniper_training(); - new spell_hun_pet_heart_of_the_phoenix(); - new spell_hun_pet_carrion_feeder(); - new spell_hun_misdirection(); - new spell_hun_misdirection_proc(); - new spell_hun_disengage(); new spell_hun_tame_beast(); new spell_hun_target_only_pet_and_owner(); } diff --git a/src/server/scripts/Spells/spell_item.cpp b/src/server/scripts/Spells/spell_item.cpp index ccd8f3f81e7..c9c75cdb134 100644 --- a/src/server/scripts/Spells/spell_item.cpp +++ b/src/server/scripts/Spells/spell_item.cpp @@ -73,6 +73,150 @@ class spell_item_trigger_spell : public SpellScriptLoader } }; +// 26400 - Arcane Shroud +class spell_item_arcane_shroud : public SpellScriptLoader +{ + public: + spell_item_arcane_shroud() : SpellScriptLoader("spell_item_arcane_shroud") { } + + class spell_item_arcane_shroud_AuraScript : public AuraScript + { + PrepareAuraScript(spell_item_arcane_shroud_AuraScript); + + void CalculateAmount(AuraEffect const* /*aurEff*/, int32& amount, bool& /*canBeRecalculated*/) + { + int32 diff = GetUnitOwner()->getLevel() - 60; + if (diff > 0) + amount += 2 * diff; + } + + void Register() + { + DoEffectCalcAmount += AuraEffectCalcAmountFn(spell_item_arcane_shroud_AuraScript::CalculateAmount, EFFECT_0, SPELL_AURA_MOD_THREAT); + } + }; + + AuraScript* GetAuraScript() const + { + return new spell_item_arcane_shroud_AuraScript(); + } +}; + +// 64411 - Blessing of Ancient Kings (Val'anyr, Hammer of Ancient Kings) +enum BlessingOfAncientKings +{ + SPELL_PROTECTION_OF_ANCIENT_KINGS = 64413 +}; + +class spell_item_blessing_of_ancient_kings : public SpellScriptLoader +{ + public: + spell_item_blessing_of_ancient_kings() : SpellScriptLoader("spell_item_blessing_of_ancient_kings") { } + + class spell_item_blessing_of_ancient_kings_AuraScript : public AuraScript + { + PrepareAuraScript(spell_item_blessing_of_ancient_kings_AuraScript); + + bool Validate(SpellInfo const* /*spellInfo*/) + { + if (!sSpellMgr->GetSpellInfo(SPELL_PROTECTION_OF_ANCIENT_KINGS)) + return false; + return true; + } + + bool CheckProc(ProcEventInfo& eventInfo) + { + return eventInfo.GetProcTarget(); + } + + void HandleProc(AuraEffect const* aurEff, ProcEventInfo& eventInfo) + { + PreventDefaultAction(); + + int32 absorb = int32(CalculatePct(eventInfo.GetHealInfo()->GetHeal(), 15.0f)); + if (AuraEffect* protEff = eventInfo.GetProcTarget()->GetAuraEffect(SPELL_PROTECTION_OF_ANCIENT_KINGS, 0, eventInfo.GetActor()->GetGUID())) + { + // The shield can grow to a maximum size of 20,000 damage absorbtion + protEff->SetAmount(std::min<int32>(protEff->GetAmount() + absorb, 20000)); + + // Refresh and return to prevent replacing the aura + protEff->GetBase()->RefreshDuration(); + } + else + GetTarget()->CastCustomSpell(SPELL_PROTECTION_OF_ANCIENT_KINGS, SPELLVALUE_BASE_POINT0, absorb, eventInfo.GetProcTarget(), true, NULL, aurEff); + } + + void Register() + { + DoCheckProc += AuraCheckProcFn(spell_item_blessing_of_ancient_kings_AuraScript::CheckProc); + OnEffectProc += AuraEffectProcFn(spell_item_blessing_of_ancient_kings_AuraScript::HandleProc, EFFECT_0, SPELL_AURA_DUMMY); + } + }; + + AuraScript* GetAuraScript() const + { + return new spell_item_blessing_of_ancient_kings_AuraScript(); + } +}; + +// 8342 - Defibrillate (Goblin Jumper Cables) have 33% chance on success +// 22999 - Defibrillate (Goblin Jumper Cables XL) have 50% chance on success +// 54732 - Defibrillate (Gnomish Army Knife) have 67% chance on success +enum Defibrillate +{ + SPELL_GOBLIN_JUMPER_CABLES_FAIL = 8338, + SPELL_GOBLIN_JUMPER_CABLES_XL_FAIL = 23055 +}; + +class spell_item_defibrillate : public SpellScriptLoader +{ + public: + spell_item_defibrillate(char const* name, uint8 chance, uint32 failSpell = 0) : SpellScriptLoader(name), _chance(chance), _failSpell(failSpell) { } + + class spell_item_defibrillate_SpellScript : public SpellScript + { + PrepareSpellScript(spell_item_defibrillate_SpellScript); + + public: + spell_item_defibrillate_SpellScript(uint8 chance, uint32 failSpell) : SpellScript(), _chance(chance), _failSpell(failSpell) { } + + bool Validate(SpellInfo const* /*spellInfo*/) + { + if (_failSpell && !sSpellMgr->GetSpellInfo(_failSpell)) + return false; + return true; + } + + void HandleScript(SpellEffIndex effIndex) + { + if (roll_chance_i(_chance)) + { + PreventHitDefaultEffect(effIndex); + if (_failSpell) + GetCaster()->CastSpell(GetCaster(), _failSpell, true, GetCastItem()); + } + } + + void Register() + { + OnEffectHitTarget += SpellEffectFn(spell_item_defibrillate_SpellScript::HandleScript, EFFECT_0, SPELL_EFFECT_RESURRECT); + } + + private: + uint8 _chance; + uint32 _failSpell; + }; + + SpellScript* GetSpellScript() const + { + return new spell_item_defibrillate_SpellScript(_chance, _failSpell); + } + + private: + uint8 _chance; + uint32 _failSpell; +}; + // http://www.wowhead.com/item=6522 Deviate Fish // 8063 Deviate Fish enum DeviateFishSpells @@ -357,6 +501,47 @@ class spell_item_mingos_fortune_generator : public SpellScriptLoader } }; +// 71875, 71877 - Item - Black Bruise: Necrotic Touch Proc +enum NecroticTouch +{ + SPELL_ITEM_NECROTIC_TOUCH_PROC = 71879 +}; + +class spell_item_necrotic_touch : public SpellScriptLoader +{ + public: + spell_item_necrotic_touch() : SpellScriptLoader("spell_item_necrotic_touch") { } + + class spell_item_necrotic_touch_AuraScript : public AuraScript + { + PrepareAuraScript(spell_item_necrotic_touch_AuraScript); + + bool Validate(SpellInfo const* /*spellInfo*/) + { + if (!sSpellMgr->GetSpellInfo(SPELL_ITEM_NECROTIC_TOUCH_PROC)) + return false; + return true; + } + + void HandleProc(AuraEffect const* aurEff, ProcEventInfo& eventInfo) + { + PreventDefaultAction(); + int32 bp = CalculatePct(int32(eventInfo.GetDamageInfo()->GetDamage()), aurEff->GetAmount()); + GetTarget()->CastCustomSpell(SPELL_ITEM_NECROTIC_TOUCH_PROC, SPELLVALUE_BASE_POINT0, bp, GetTarget(), true, NULL, aurEff); + } + + void Register() + { + OnEffectProc += AuraEffectProcFn(spell_item_necrotic_touch_AuraScript::HandleProc, EFFECT_0, SPELL_AURA_DUMMY); + } + }; + + AuraScript* GetAuraScript() const + { + return new spell_item_necrotic_touch_AuraScript(); + } +}; + // http://www.wowhead.com/item=10720 Gnomish Net-o-Matic Projector // 13120 Net-o-Matic enum NetOMaticSpells @@ -464,6 +649,35 @@ class spell_item_noggenfogger_elixir : public SpellScriptLoader } }; +// 17512 - Piccolo of the Flaming Fire +class spell_item_piccolo_of_the_flaming_fire : public SpellScriptLoader +{ + public: + spell_item_piccolo_of_the_flaming_fire() : SpellScriptLoader("spell_item_piccolo_of_the_flaming_fire") { } + + class spell_item_piccolo_of_the_flaming_fire_SpellScript : public SpellScript + { + PrepareSpellScript(spell_item_piccolo_of_the_flaming_fire_SpellScript); + + void HandleScript(SpellEffIndex effIndex) + { + PreventHitDefaultEffect(effIndex); + if (Player* target = GetHitPlayer()) + target->HandleEmoteCommand(EMOTE_STATE_DANCE); + } + + void Register() + { + OnEffectHitTarget += SpellEffectFn(spell_item_piccolo_of_the_flaming_fire_SpellScript::HandleScript, EFFECT_0, SPELL_EFFECT_SCRIPT_EFFECT); + } + }; + + SpellScript* GetSpellScript() const + { + return new spell_item_piccolo_of_the_flaming_fire_SpellScript(); + } +}; + // http://www.wowhead.com/item=6657 Savory Deviate Delight // 8213 Savory Deviate Delight enum SavoryDeviateDelight @@ -522,6 +736,274 @@ class spell_item_savory_deviate_delight : public SpellScriptLoader } }; +// 48129 - Scroll of Recall +// 60320 - Scroll of Recall II +// 60321 - Scroll of Recall III +enum ScrollOfRecall +{ + SPELL_SCROLL_OF_RECALL_I = 48129, + SPELL_SCROLL_OF_RECALL_II = 60320, + SPELL_SCROLL_OF_RECALL_III = 60321, + SPELL_LOST = 60444, + SPELL_SCROLL_OF_RECALL_FAIL_ALLIANCE_1 = 60323, + SPELL_SCROLL_OF_RECALL_FAIL_HORDE_1 = 60328, +}; + +class spell_item_scroll_of_recall : public SpellScriptLoader +{ + public: + spell_item_scroll_of_recall() : SpellScriptLoader("spell_item_scroll_of_recall") { } + + class spell_item_scroll_of_recall_SpellScript : public SpellScript + { + PrepareSpellScript(spell_item_scroll_of_recall_SpellScript); + + bool Load() + { + return GetCaster()->GetTypeId() == TYPEID_PLAYER; + } + + void HandleScript(SpellEffIndex effIndex) + { + Unit* caster = GetCaster(); + uint8 maxSafeLevel = 0; + switch (GetSpellInfo()->Id) + { + case SPELL_SCROLL_OF_RECALL_I: // Scroll of Recall + maxSafeLevel = 40; + break; + case SPELL_SCROLL_OF_RECALL_II: // Scroll of Recall II + maxSafeLevel = 70; + break; + case SPELL_SCROLL_OF_RECALL_III: // Scroll of Recal III + maxSafeLevel = 80; + break; + default: + break; + } + + if (caster->getLevel() > maxSafeLevel) + { + caster->CastSpell(caster, SPELL_LOST, true); + + // ALLIANCE from 60323 to 60330 - HORDE from 60328 to 60335 + uint32 spellId = SPELL_SCROLL_OF_RECALL_FAIL_ALLIANCE_1; + if (GetCaster()->ToPlayer()->GetTeam() == HORDE) + spellId = SPELL_SCROLL_OF_RECALL_FAIL_HORDE_1; + + GetCaster()->CastSpell(GetCaster(), spellId + urand(0, 7), true); + + PreventHitDefaultEffect(effIndex); + } + } + + void Register() + { + OnEffectHitTarget += SpellEffectFn(spell_item_scroll_of_recall_SpellScript::HandleScript, EFFECT_0, SPELL_EFFECT_TELEPORT_UNITS); + } + }; + + SpellScript* GetSpellScript() const + { + return new spell_item_scroll_of_recall_SpellScript(); + } +}; + +// 71169 - Shadow's Fate (Shadowmourne questline) +enum ShadowsFate +{ + SPELL_SOUL_FEAST = 71203, +}; + +class spell_item_unsated_craving : public SpellScriptLoader +{ + public: + spell_item_unsated_craving() : SpellScriptLoader("spell_item_unsated_craving") { } + + class spell_item_unsated_craving_AuraScript : public AuraScript + { + PrepareAuraScript(spell_item_unsated_craving_AuraScript); + + bool CheckProc(ProcEventInfo& procInfo) + { + Unit* caster = procInfo.GetActor(); + if (!caster || caster->GetTypeId() != TYPEID_PLAYER) + return false; + + Unit* target = procInfo.GetActionTarget(); + if (!target || target->GetTypeId() != TYPEID_UNIT || target->GetCreatureType() == CREATURE_TYPE_CRITTER || target->isSummon()) + return false; + + return true; + } + + void Register() + { + DoCheckProc += AuraCheckProcFn(spell_item_unsated_craving_AuraScript::CheckProc); + } + }; + + AuraScript* GetAuraScript() const + { + return new spell_item_unsated_craving_AuraScript(); + } +}; + +class spell_item_shadows_fate : public SpellScriptLoader +{ + public: + spell_item_shadows_fate() : SpellScriptLoader("spell_item_shadows_fate") { } + + class spell_item_shadows_fate_AuraScript : public AuraScript + { + PrepareAuraScript(spell_item_shadows_fate_AuraScript); + + void HandleProc(ProcEventInfo& procInfo) + { + Unit* caster = procInfo.GetActor(); + Unit* target = GetCaster(); + if (!caster || !target) + return; + + caster->CastSpell(target, SPELL_SOUL_FEAST, TRIGGERED_FULL_MASK); + } + + void Register() + { + OnProc += AuraProcFn(spell_item_shadows_fate_AuraScript::HandleProc); + } + }; + + AuraScript* GetAuraScript() const + { + return new spell_item_shadows_fate_AuraScript(); + } +}; + +enum Shadowmourne +{ + SPELL_SHADOWMOURNE_CHAOS_BANE_DAMAGE = 71904, + SPELL_SHADOWMOURNE_SOUL_FRAGMENT = 71905, + SPELL_SHADOWMOURNE_VISUAL_LOW = 72521, + SPELL_SHADOWMOURNE_VISUAL_HIGH = 72523, + SPELL_SHADOWMOURNE_CHAOS_BANE_BUFF = 73422, +}; + +// 71903 - Item - Shadowmourne Legendary +class spell_item_shadowmourne : public SpellScriptLoader +{ + public: + spell_item_shadowmourne() : SpellScriptLoader("spell_item_shadowmourne") { } + + class spell_item_shadowmourne_AuraScript : public AuraScript + { + PrepareAuraScript(spell_item_shadowmourne_AuraScript); + + bool Validate(SpellInfo const* /*spellInfo*/) + { + if (!sSpellMgr->GetSpellInfo(SPELL_SHADOWMOURNE_CHAOS_BANE_DAMAGE)) + return false; + if (!sSpellMgr->GetSpellInfo(SPELL_SHADOWMOURNE_SOUL_FRAGMENT)) + return false; + if (!sSpellMgr->GetSpellInfo(SPELL_SHADOWMOURNE_CHAOS_BANE_BUFF)) + return false; + return true; + } + + bool CheckProc(ProcEventInfo& eventInfo) + { + if (GetTarget()->HasAura(SPELL_SHADOWMOURNE_CHAOS_BANE_BUFF)) // cant collect shards while under effect of Chaos Bane buff + return false; + return eventInfo.GetProcTarget() && eventInfo.GetProcTarget()->isAlive(); + } + + void HandleProc(AuraEffect const* aurEff, ProcEventInfo& eventInfo) + { + PreventDefaultAction(); + GetTarget()->CastSpell(GetTarget(), SPELL_SHADOWMOURNE_SOUL_FRAGMENT, true, NULL, aurEff); + + // this can't be handled in AuraScript of SoulFragments because we need to know victim + if (Aura* soulFragments = GetTarget()->GetAura(SPELL_SHADOWMOURNE_SOUL_FRAGMENT)) + { + if (soulFragments->GetStackAmount() >= 10) + { + GetTarget()->CastSpell(eventInfo.GetProcTarget(), SPELL_SHADOWMOURNE_CHAOS_BANE_DAMAGE, true, NULL, aurEff); + soulFragments->Remove(); + } + } + } + + void Register() + { + DoCheckProc += AuraCheckProcFn(spell_item_shadowmourne_AuraScript::CheckProc); + OnEffectProc += AuraEffectProcFn(spell_item_shadowmourne_AuraScript::HandleProc, EFFECT_0, SPELL_AURA_DUMMY); + } + }; + + AuraScript* GetAuraScript() const + { + return new spell_item_shadowmourne_AuraScript(); + } +}; + +// 71905 - Soul Fragment +class spell_item_shadowmourne_soul_fragment : public SpellScriptLoader +{ + public: + spell_item_shadowmourne_soul_fragment() : SpellScriptLoader("spell_item_shadowmourne_soul_fragment") { } + + class spell_item_shadowmourne_soul_fragment_AuraScript : public AuraScript + { + PrepareAuraScript(spell_item_shadowmourne_soul_fragment_AuraScript); + + bool Validate(SpellInfo const* /*spellInfo*/) + { + if (!sSpellMgr->GetSpellInfo(SPELL_SHADOWMOURNE_VISUAL_LOW) || !sSpellMgr->GetSpellInfo(SPELL_SHADOWMOURNE_VISUAL_HIGH) || !sSpellMgr->GetSpellInfo(SPELL_SHADOWMOURNE_CHAOS_BANE_BUFF)) + return false; + return true; + } + + void OnStackChange(AuraEffect const* /*aurEff*/, AuraEffectHandleModes /*mode*/) + { + Unit* target = GetTarget(); + switch (GetStackAmount()) + { + case 1: + target->CastSpell(target, SPELL_SHADOWMOURNE_VISUAL_LOW, true); + break; + case 6: + target->RemoveAurasDueToSpell(SPELL_SHADOWMOURNE_VISUAL_LOW); + target->CastSpell(target, SPELL_SHADOWMOURNE_VISUAL_HIGH, true); + break; + case 10: + target->RemoveAurasDueToSpell(SPELL_SHADOWMOURNE_VISUAL_HIGH); + target->CastSpell(target, SPELL_SHADOWMOURNE_CHAOS_BANE_BUFF, true); + break; + default: + break; + } + } + + void OnRemove(AuraEffect const* /*aurEff*/, AuraEffectHandleModes /*mode*/) + { + Unit* target = GetTarget(); + target->RemoveAurasDueToSpell(SPELL_SHADOWMOURNE_VISUAL_LOW); + target->RemoveAurasDueToSpell(SPELL_SHADOWMOURNE_VISUAL_HIGH); + } + + void Register() + { + AfterEffectApply += AuraEffectApplyFn(spell_item_shadowmourne_soul_fragment_AuraScript::OnStackChange, EFFECT_0, SPELL_AURA_MOD_STAT, AuraEffectHandleModes(AURA_EFFECT_HANDLE_REAL | AURA_EFFECT_HANDLE_REAPPLY)); + AfterEffectRemove += AuraEffectRemoveFn(spell_item_shadowmourne_soul_fragment_AuraScript::OnRemove, EFFECT_0, SPELL_AURA_MOD_STAT, AURA_EFFECT_HANDLE_REAL); + } + }; + + AuraScript* GetAuraScript() const + { + return new spell_item_shadowmourne_soul_fragment_AuraScript(); + } +}; + // http://www.wowhead.com/item=7734 Six Demon Bag // 14537 Six Demon Bag enum SixDemonBagSpells @@ -593,6 +1075,35 @@ class spell_item_six_demon_bag : public SpellScriptLoader } }; +// 28862 - The Eye of Diminution +class spell_item_the_eye_of_diminution : public SpellScriptLoader +{ + public: + spell_item_the_eye_of_diminution() : SpellScriptLoader("spell_item_the_eye_of_diminution") { } + + class spell_item_the_eye_of_diminution_AuraScript : public AuraScript + { + PrepareAuraScript(spell_item_the_eye_of_diminution_AuraScript); + + void CalculateAmount(AuraEffect const* /*aurEff*/, int32& amount, bool& /*canBeRecalculated*/) + { + int32 diff = GetUnitOwner()->getLevel() - 60; + if (diff > 0) + amount += diff; + } + + void Register() + { + DoEffectCalcAmount += AuraEffectCalcAmountFn(spell_item_the_eye_of_diminution_AuraScript::CalculateAmount, EFFECT_0, SPELL_AURA_MOD_THREAT); + } + }; + + AuraScript* GetAuraScript() const + { + return new spell_item_the_eye_of_diminution_AuraScript(); + } +}; + // http://www.wowhead.com/item=44012 Underbelly Elixir // 59640 Underbelly Elixir enum UnderbellyElixirSpells @@ -646,70 +1157,6 @@ class spell_item_underbelly_elixir : public SpellScriptLoader } }; -enum eShadowmourneVisuals -{ - SPELL_SHADOWMOURNE_VISUAL_LOW = 72521, - SPELL_SHADOWMOURNE_VISUAL_HIGH = 72523, - SPELL_SHADOWMOURNE_CHAOS_BANE_BUFF = 73422, -}; - -class spell_item_shadowmourne : public SpellScriptLoader -{ -public: - spell_item_shadowmourne() : SpellScriptLoader("spell_item_shadowmourne") { } - - class spell_item_shadowmourne_AuraScript : public AuraScript - { - PrepareAuraScript(spell_item_shadowmourne_AuraScript); - - bool Validate(SpellInfo const* /*spellEntry*/) - { - if (!sSpellMgr->GetSpellInfo(SPELL_SHADOWMOURNE_VISUAL_LOW) || !sSpellMgr->GetSpellInfo(SPELL_SHADOWMOURNE_VISUAL_HIGH) || !sSpellMgr->GetSpellInfo(SPELL_SHADOWMOURNE_CHAOS_BANE_BUFF)) - return false; - return true; - } - - void OnStackChange(AuraEffect const* /*aurEff*/, AuraEffectHandleModes /*mode*/) - { - Unit* target = GetTarget(); - switch (GetStackAmount()) - { - case 1: - target->CastSpell(target, SPELL_SHADOWMOURNE_VISUAL_LOW, true); - break; - case 6: - target->RemoveAurasDueToSpell(SPELL_SHADOWMOURNE_VISUAL_LOW); - target->CastSpell(target, SPELL_SHADOWMOURNE_VISUAL_HIGH, true); - break; - case 10: - target->RemoveAurasDueToSpell(SPELL_SHADOWMOURNE_VISUAL_HIGH); - target->CastSpell(target, SPELL_SHADOWMOURNE_CHAOS_BANE_BUFF, true); - break; - default: - break; - } - } - - void OnRemove(AuraEffect const* /*aurEff*/, AuraEffectHandleModes /*mode*/) - { - Unit* target = GetTarget(); - target->RemoveAurasDueToSpell(SPELL_SHADOWMOURNE_VISUAL_LOW); - target->RemoveAurasDueToSpell(SPELL_SHADOWMOURNE_VISUAL_HIGH); - } - - void Register() - { - AfterEffectApply += AuraEffectApplyFn(spell_item_shadowmourne_AuraScript::OnStackChange, EFFECT_0, SPELL_AURA_MOD_STAT, AuraEffectHandleModes(AURA_EFFECT_HANDLE_REAL | AURA_EFFECT_HANDLE_REAPPLY)); - AfterEffectRemove += AuraEffectRemoveFn(spell_item_shadowmourne_AuraScript::OnRemove, EFFECT_0, SPELL_AURA_MOD_STAT, AURA_EFFECT_HANDLE_REAL); - } - }; - - AuraScript* GetAuraScript() const - { - return new spell_item_shadowmourne_AuraScript(); - } -}; - enum AirRifleSpells { SPELL_AIR_RIFLE_HOLD_VISUAL = 65582, @@ -1350,7 +1797,7 @@ class spell_item_poultryizer : public SpellScriptLoader void HandleDummy(SpellEffIndex /* effIndex */) { if (GetCastItem() && GetHitUnit()) - GetCaster()->CastSpell(GetHitUnit(), roll_chance_i(80) ? SPELL_POULTRYIZER_SUCCESS : SPELL_POULTRYIZER_BACKFIRE , true, GetCastItem()); + GetCaster()->CastSpell(GetHitUnit(), roll_chance_i(80) ? SPELL_POULTRYIZER_SUCCESS : SPELL_POULTRYIZER_BACKFIRE, true, GetCastItem()); } void Register() @@ -1710,7 +2157,7 @@ class spell_item_teach_language : public SpellScriptLoader Player* caster = GetCaster()->ToPlayer(); if (roll_chance_i(34)) - caster->CastSpell(caster,caster->GetTeam() == ALLIANCE ? SPELL_LEARN_GNOMISH_BINARY : SPELL_LEARN_GOBLIN_BINARY, true); + caster->CastSpell(caster, caster->GetTeam() == ALLIANCE ? SPELL_LEARN_GNOMISH_BINARY : SPELL_LEARN_GOBLIN_BINARY, true); } void Register() @@ -2004,7 +2451,7 @@ public: void HandleDummy(SpellEffIndex /*effIndex*/) { if (GetHitUnit()) - GetCaster()->CastSpell(GetCaster(),SPELL_FORCE_CAST_SUMMON_GNOME_SOUL); + GetCaster()->CastSpell(GetCaster(), SPELL_FORCE_CAST_SUMMON_GNOME_SOUL); } void Register() @@ -2030,17 +2477,29 @@ void AddSC_item_spell_scripts() // 23075 Mithril Mechanical Dragonling new spell_item_trigger_spell("spell_item_mithril_mechanical_dragonling", SPELL_MITHRIL_MECHANICAL_DRAGONLING); + new spell_item_arcane_shroud(); + new spell_item_blessing_of_ancient_kings(); + new spell_item_defibrillate("spell_item_goblin_jumper_cables", 67, SPELL_GOBLIN_JUMPER_CABLES_FAIL); + new spell_item_defibrillate("spell_item_goblin_jumper_cables_xl", 50, SPELL_GOBLIN_JUMPER_CABLES_XL_FAIL); + new spell_item_defibrillate("spell_item_gnomish_army_knife", 33); new spell_item_deviate_fish(); new spell_item_flask_of_the_north(); new spell_item_gnomish_death_ray(); new spell_item_make_a_wish(); new spell_item_mingos_fortune_generator(); + new spell_item_necrotic_touch(); new spell_item_net_o_matic(); new spell_item_noggenfogger_elixir(); + new spell_item_piccolo_of_the_flaming_fire(); new spell_item_savory_deviate_delight(); + new spell_item_scroll_of_recall(); + new spell_item_unsated_craving(); + new spell_item_shadows_fate(); + new spell_item_shadowmourne(); + new spell_item_shadowmourne_soul_fragment(); new spell_item_six_demon_bag(); + new spell_item_the_eye_of_diminution(); new spell_item_underbelly_elixir(); - new spell_item_shadowmourne(); new spell_item_red_rider_air_rifle(); new spell_item_create_heart_candy(); diff --git a/src/server/scripts/Spells/spell_mage.cpp b/src/server/scripts/Spells/spell_mage.cpp index cf10cfdab5c..e27248da6fc 100644 --- a/src/server/scripts/Spells/spell_mage.cpp +++ b/src/server/scripts/Spells/spell_mage.cpp @@ -28,7 +28,15 @@ enum MageSpells { + SPELL_MAGE_BURNOUT = 29077, SPELL_MAGE_COLD_SNAP = 11958, + SPELL_MAGE_FOCUS_MAGIC_PROC = 54648, + SPELL_MAGE_FROST_WARDING_R1 = 11189, + SPELL_MAGE_FROST_WARDING_TRIGGERED = 57776, + SPELL_MAGE_INCANTERS_ABSORBTION_R1 = 44394, + SPELL_MAGE_INCANTERS_ABSORBTION_TRIGGERED = 44413, + SPELL_MAGE_IGNITE = 12654, + SPELL_MAGE_MASTER_OF_ELEMENTS_ENERGIZE = 29077, SPELL_MAGE_SQUIRREL_FORM = 32813, SPELL_MAGE_GIRAFFE_FORM = 32816, SPELL_MAGE_SERPENT_FORM = 32817, @@ -41,6 +49,32 @@ enum MageSpells SPELL_MAGE_GLYPH_OF_BLAST_WAVE = 62126, }; +// Incanter's Absorbtion +class spell_mage_incanters_absorbtion_base_AuraScript : public AuraScript +{ + public: + bool Validate(SpellInfo const* /*spellInfo*/) + { + if (!sSpellMgr->GetSpellInfo(SPELL_MAGE_INCANTERS_ABSORBTION_TRIGGERED)) + return false; + if (!sSpellMgr->GetSpellInfo(SPELL_MAGE_INCANTERS_ABSORBTION_R1)) + return false; + return true; + } + + void Trigger(AuraEffect* aurEff, DamageInfo& /*dmgInfo*/, uint32& absorbAmount) + { + Unit* target = GetTarget(); + + if (AuraEffect* talentAurEff = target->GetAuraEffectOfRankedSpell(SPELL_MAGE_INCANTERS_ABSORBTION_R1, EFFECT_0)) + { + int32 bp = CalculatePct(absorbAmount, talentAurEff->GetAmount()); + target->CastCustomSpell(target, SPELL_MAGE_INCANTERS_ABSORBTION_TRIGGERED, &bp, NULL, NULL, true, NULL, aurEff); + } + } +}; + +// -11113 - Blast Wave class spell_mage_blast_wave : public SpellScriptLoader { public: @@ -50,7 +84,7 @@ class spell_mage_blast_wave : public SpellScriptLoader { PrepareSpellScript(spell_mage_blast_wave_SpellScript); - bool Validate(SpellInfo const* /*spellEntry*/) + bool Validate(SpellInfo const* /*spellInfo*/) { if (!sSpellMgr->GetSpellInfo(SPELL_MAGE_GLYPH_OF_BLAST_WAVE)) return false; @@ -75,6 +109,52 @@ class spell_mage_blast_wave : public SpellScriptLoader } }; +// -44449 - Burnout +class spell_mage_burnout : public SpellScriptLoader +{ + public: + spell_mage_burnout() : SpellScriptLoader("spell_mage_burnout") { } + + class spell_mage_burnout_AuraScript : public AuraScript + { + PrepareAuraScript(spell_mage_burnout_AuraScript); + + bool Validate(SpellInfo const* /*spellInfo*/) + { + if (!sSpellMgr->GetSpellInfo(SPELL_MAGE_BURNOUT)) + return false; + return true; + } + + bool CheckProc(ProcEventInfo& eventInfo) + { + return eventInfo.GetDamageInfo()->GetSpellInfo(); // eventInfo.GetSpellInfo() + } + + void HandleProc(AuraEffect const* aurEff, ProcEventInfo& eventInfo) + { + PreventDefaultAction(); + + int32 mana = int32(eventInfo.GetDamageInfo()->GetSpellInfo()->CalcPowerCost(GetTarget(), eventInfo.GetDamageInfo()->GetSchoolMask())); + mana = CalculatePct(mana, aurEff->GetAmount()); + + GetTarget()->CastCustomSpell(SPELL_MAGE_BURNOUT, SPELLVALUE_BASE_POINT0, mana, GetTarget(), true, NULL, aurEff); + } + + void Register() + { + DoCheckProc += AuraCheckProcFn(spell_mage_burnout_AuraScript::CheckProc); + OnEffectProc += AuraEffectProcFn(spell_mage_burnout_AuraScript::HandleProc, EFFECT_1, SPELL_AURA_DUMMY); + } + }; + + AuraScript* GetAuraScript() const + { + return new spell_mage_burnout_AuraScript(); + } +}; + +// 11958 - Cold Snap class spell_mage_cold_snap : public SpellScriptLoader { public: @@ -91,7 +171,6 @@ class spell_mage_cold_snap : public SpellScriptLoader void HandleDummy(SpellEffIndex /*effIndex*/) { - Player* caster = GetCaster()->ToPlayer(); // immediately finishes the cooldown on Frost spells const SpellCooldowns& cm = caster->GetSpellCooldownMap(); @@ -112,7 +191,6 @@ class spell_mage_cold_snap : public SpellScriptLoader void Register() { - // add dummy effect spell handler to Cold Snap OnEffectHit += SpellEffectFn(spell_mage_cold_snap_SpellScript::HandleDummy, EFFECT_0, SPELL_EFFECT_DUMMY); } }; @@ -123,271 +201,444 @@ class spell_mage_cold_snap : public SpellScriptLoader } }; -enum SilvermoonPolymorph +// -543 - Fire Ward +// -6143 - Frost Ward +class spell_mage_fire_frost_ward : public SpellScriptLoader { - NPC_AUROSALIA = 18744, + public: + spell_mage_fire_frost_ward() : SpellScriptLoader("spell_mage_fire_frost_ward") { } + + class spell_mage_fire_frost_ward_AuraScript : public spell_mage_incanters_absorbtion_base_AuraScript + { + PrepareAuraScript(spell_mage_fire_frost_ward_AuraScript); + + bool Validate(SpellInfo const* /*spellInfo*/) + { + if (!sSpellMgr->GetSpellInfo(SPELL_MAGE_FROST_WARDING_TRIGGERED)) + return false; + if (!sSpellMgr->GetSpellInfo(SPELL_MAGE_FROST_WARDING_R1)) + return false; + return true; + } + + void CalculateAmount(AuraEffect const* /*aurEff*/, int32& amount, bool& canBeRecalculated) + { + canBeRecalculated = false; + if (Unit* caster = GetCaster()) + { + // +80.68% from sp bonus + float bonus = 0.8068f; + + bonus *= caster->SpellBaseHealingBonusDone(GetSpellInfo()->GetSchoolMask()); + bonus *= caster->CalculateLevelPenalty(GetSpellInfo()); + + amount += int32(bonus); + } + } + + void Absorb(AuraEffect* aurEff, DamageInfo& dmgInfo, uint32& absorbAmount) + { + Unit* target = GetTarget(); + if (AuraEffect* talentAurEff = target->GetAuraEffectOfRankedSpell(SPELL_MAGE_FROST_WARDING_R1, EFFECT_0)) + { + int32 chance = talentAurEff->GetSpellInfo()->Effects[EFFECT_1].CalcValue(); // SPELL_EFFECT_DUMMY with NO_TARGET + + if (roll_chance_i(chance)) + { + int32 bp = dmgInfo.GetDamage(); + dmgInfo.AbsorbDamage(bp); + target->CastCustomSpell(target, SPELL_MAGE_FROST_WARDING_TRIGGERED, &bp, NULL, NULL, true, NULL, aurEff); + absorbAmount = 0; + PreventDefaultAction(); + } + } + } + + void Register() + { + DoEffectCalcAmount += AuraEffectCalcAmountFn(spell_mage_fire_frost_ward_AuraScript::CalculateAmount, EFFECT_0, SPELL_AURA_SCHOOL_ABSORB); + OnEffectAbsorb += AuraEffectAbsorbFn(spell_mage_fire_frost_ward_AuraScript::Absorb, EFFECT_0); + AfterEffectAbsorb += AuraEffectAbsorbFn(spell_mage_fire_frost_ward_AuraScript::Trigger, EFFECT_0); + } + }; + + AuraScript* GetAuraScript() const + { + return new spell_mage_fire_frost_ward_AuraScript(); + } }; -// TODO: move out of here and rename - not a mage spell -class spell_mage_polymorph_cast_visual : public SpellScriptLoader +// 54646 - Focus Magic +class spell_mage_focus_magic : public SpellScriptLoader { public: - spell_mage_polymorph_cast_visual() : SpellScriptLoader("spell_mage_polymorph_visual") { } + spell_mage_focus_magic() : SpellScriptLoader("spell_mage_focus_magic") { } - class spell_mage_polymorph_cast_visual_SpellScript : public SpellScript + class spell_mage_focus_magic_AuraScript : public AuraScript { - PrepareSpellScript(spell_mage_polymorph_cast_visual_SpellScript); + PrepareAuraScript(spell_mage_focus_magic_AuraScript); - static const uint32 PolymorhForms[6]; + bool Validate(SpellInfo const* /*spellInfo*/) + { + if (!sSpellMgr->GetSpellInfo(SPELL_MAGE_FOCUS_MAGIC_PROC)) + return false; + return true; + } - bool Validate(SpellInfo const* /*spellEntry*/) + bool Load() { - // check if spell ids exist in dbc - for (uint32 i = 0; i < 6; i++) - if (!sSpellMgr->GetSpellInfo(PolymorhForms[i])) - return false; + _procTarget = NULL; return true; } - void HandleDummy(SpellEffIndex /*effIndex*/) + bool CheckProc(ProcEventInfo& /*eventInfo*/) { - if (Unit* target = GetCaster()->FindNearestCreature(NPC_AUROSALIA, 30.0f)) - if (target->GetTypeId() == TYPEID_UNIT) - target->CastSpell(target, PolymorhForms[urand(0, 5)], true); + _procTarget = GetCaster(); + return _procTarget && _procTarget->isAlive(); + } + + void HandleProc(AuraEffect const* aurEff, ProcEventInfo& /*eventInfo*/) + { + PreventDefaultAction(); + GetTarget()->CastSpell(_procTarget, SPELL_MAGE_FOCUS_MAGIC_PROC, true, NULL, aurEff); } void Register() { - // add dummy effect spell handler to Polymorph visual - OnEffectHitTarget += SpellEffectFn(spell_mage_polymorph_cast_visual_SpellScript::HandleDummy, EFFECT_0, SPELL_EFFECT_DUMMY); + DoCheckProc += AuraCheckProcFn(spell_mage_focus_magic_AuraScript::CheckProc); + OnEffectProc += AuraEffectProcFn(spell_mage_focus_magic_AuraScript::HandleProc, EFFECT_0, SPELL_AURA_MOD_SPELL_CRIT_CHANCE); } + + private: + Unit* _procTarget; }; - SpellScript* GetSpellScript() const + AuraScript* GetAuraScript() const { - return new spell_mage_polymorph_cast_visual_SpellScript(); + return new spell_mage_focus_magic_AuraScript(); } }; -const uint32 spell_mage_polymorph_cast_visual::spell_mage_polymorph_cast_visual_SpellScript::PolymorhForms[6] = +// -11426 - Ice Barrier +class spell_mage_ice_barrier : public SpellScriptLoader { - SPELL_MAGE_SQUIRREL_FORM, - SPELL_MAGE_GIRAFFE_FORM, - SPELL_MAGE_SERPENT_FORM, - SPELL_MAGE_DRAGONHAWK_FORM, - SPELL_MAGE_WORGEN_FORM, - SPELL_MAGE_SHEEP_FORM + public: + spell_mage_ice_barrier() : SpellScriptLoader("spell_mage_ice_barrier") { } + + class spell_mage_ice_barrier_AuraScript : public spell_mage_incanters_absorbtion_base_AuraScript + { + PrepareAuraScript(spell_mage_ice_barrier_AuraScript); + + void CalculateAmount(AuraEffect const* aurEff, int32& amount, bool& canBeRecalculated) + { + canBeRecalculated = false; + if (Unit* caster = GetCaster()) + { + // +80.68% from sp bonus + float bonus = 0.8068f; + + bonus *= caster->SpellBaseHealingBonusDone(GetSpellInfo()->GetSchoolMask()); + + // Glyph of Ice Barrier: its weird having a SPELLMOD_ALL_EFFECTS here but its blizzards doing :) + // Glyph of Ice Barrier is only applied at the spell damage bonus because it was already applied to the base value in CalculateSpellDamage + bonus = caster->ApplyEffectModifiers(GetSpellInfo(), aurEff->GetEffIndex(), bonus); + + bonus *= caster->CalculateLevelPenalty(GetSpellInfo()); + + amount += int32(bonus); + } + } + + void Register() + { + DoEffectCalcAmount += AuraEffectCalcAmountFn(spell_mage_ice_barrier_AuraScript::CalculateAmount, EFFECT_0, SPELL_AURA_SCHOOL_ABSORB); + AfterEffectAbsorb += AuraEffectAbsorbFn(spell_mage_ice_barrier_AuraScript::Trigger, EFFECT_0); + } + }; + + AuraScript* GetAuraScript() const + { + return new spell_mage_ice_barrier_AuraScript(); + } }; -class spell_mage_summon_water_elemental : public SpellScriptLoader +// -11119 - Ignite +class spell_mage_ignite : public SpellScriptLoader { public: - spell_mage_summon_water_elemental() : SpellScriptLoader("spell_mage_summon_water_elemental") { } + spell_mage_ignite() : SpellScriptLoader("spell_mage_ignite") { } - class spell_mage_summon_water_elemental_SpellScript : public SpellScript + class spell_mage_ignite_AuraScript : public AuraScript { - PrepareSpellScript(spell_mage_summon_water_elemental_SpellScript); + PrepareAuraScript(spell_mage_ignite_AuraScript); - bool Validate(SpellInfo const* /*spellEntry*/) + bool Validate(SpellInfo const* /*spellInfo*/) { - if (!sSpellMgr->GetSpellInfo(SPELL_MAGE_GLYPH_OF_ETERNAL_WATER) || !sSpellMgr->GetSpellInfo(SPELL_MAGE_SUMMON_WATER_ELEMENTAL_TEMPORARY) || !sSpellMgr->GetSpellInfo(SPELL_MAGE_SUMMON_WATER_ELEMENTAL_PERMANENT)) + if (!sSpellMgr->GetSpellInfo(SPELL_MAGE_IGNITE)) return false; return true; } - void HandleDummy(SpellEffIndex /*effIndex*/) + bool CheckProc(ProcEventInfo& eventInfo) { - Unit* caster = GetCaster(); - // Glyph of Eternal Water - if (caster->HasAura(SPELL_MAGE_GLYPH_OF_ETERNAL_WATER)) - caster->CastSpell(caster, SPELL_MAGE_SUMMON_WATER_ELEMENTAL_PERMANENT, true); - else - caster->CastSpell(caster, SPELL_MAGE_SUMMON_WATER_ELEMENTAL_TEMPORARY, true); + return eventInfo.GetProcTarget(); + } + + void HandleProc(AuraEffect const* aurEff, ProcEventInfo& eventInfo) + { + PreventDefaultAction(); + + SpellInfo const* igniteDot = sSpellMgr->GetSpellInfo(SPELL_MAGE_IGNITE); + int32 pct = 8 * GetSpellInfo()->GetRank(); + + int32 amount = int32(CalculatePct(eventInfo.GetDamageInfo()->GetDamage(), pct) / igniteDot->GetMaxTicks()); + amount += eventInfo.GetProcTarget()->GetRemainingPeriodicAmount(eventInfo.GetActor()->GetGUID(), SPELL_MAGE_IGNITE, SPELL_AURA_PERIODIC_DAMAGE); + GetTarget()->CastCustomSpell(SPELL_MAGE_IGNITE, SPELLVALUE_BASE_POINT0, amount, eventInfo.GetProcTarget(), true, NULL, aurEff); } void Register() { - // add dummy effect spell handler to Summon Water Elemental - OnEffectHit += SpellEffectFn(spell_mage_summon_water_elemental_SpellScript::HandleDummy, EFFECT_0, SPELL_EFFECT_DUMMY); + DoCheckProc += AuraCheckProcFn(spell_mage_ignite_AuraScript::CheckProc); + OnEffectProc += AuraEffectProcFn(spell_mage_ignite_AuraScript::HandleProc, EFFECT_0, SPELL_AURA_DUMMY); } }; - SpellScript* GetSpellScript() const + AuraScript* GetAuraScript() const { - return new spell_mage_summon_water_elemental_SpellScript(); + return new spell_mage_ignite_AuraScript(); } }; -// Frost Warding -class spell_mage_frost_warding_trigger : public SpellScriptLoader +// -44457 - Living Bomb +class spell_mage_living_bomb : public SpellScriptLoader { public: - spell_mage_frost_warding_trigger() : SpellScriptLoader("spell_mage_frost_warding_trigger") { } + spell_mage_living_bomb() : SpellScriptLoader("spell_mage_living_bomb") { } - class spell_mage_frost_warding_trigger_AuraScript : public AuraScript + class spell_mage_living_bomb_AuraScript : public AuraScript { - PrepareAuraScript(spell_mage_frost_warding_trigger_AuraScript); - - enum Spells - { - SPELL_MAGE_FROST_WARDING_TRIGGERED = 57776, - SPELL_MAGE_FROST_WARDING_R1 = 28332, - }; + PrepareAuraScript(spell_mage_living_bomb_AuraScript); - bool Validate(SpellInfo const* /*spellEntry*/) + bool Validate(SpellInfo const* spell) { - if (!sSpellMgr->GetSpellInfo(SPELL_MAGE_FROST_WARDING_TRIGGERED) || !sSpellMgr->GetSpellInfo(SPELL_MAGE_FROST_WARDING_R1)) + if (!sSpellMgr->GetSpellInfo(uint32(spell->Effects[EFFECT_1].CalcValue()))) return false; return true; } - void Absorb(AuraEffect* aurEff, DamageInfo & dmgInfo, uint32 & absorbAmount) + void AfterRemove(AuraEffect const* aurEff, AuraEffectHandleModes /*mode*/) { - Unit* target = GetTarget(); - if (AuraEffect* talentAurEff = target->GetAuraEffectOfRankedSpell(SPELL_MAGE_FROST_WARDING_R1, EFFECT_0)) - { - int32 chance = talentAurEff->GetSpellInfo()->Effects[EFFECT_1].CalcValue(); + AuraRemoveMode removeMode = GetTargetApplication()->GetRemoveMode(); + if (removeMode != AURA_REMOVE_BY_ENEMY_SPELL && removeMode != AURA_REMOVE_BY_EXPIRE) + return; - if (roll_chance_i(chance)) - { - int32 bp = dmgInfo.GetDamage(); - dmgInfo.AbsorbDamage(bp); - target->CastCustomSpell(target, SPELL_MAGE_FROST_WARDING_TRIGGERED, &bp, NULL, NULL, true, NULL, aurEff); - absorbAmount = 0; - PreventDefaultAction(); - } - } + if (Unit* caster = GetCaster()) + caster->CastSpell(GetTarget(), uint32(aurEff->GetAmount()), true, NULL, aurEff); } void Register() { - OnEffectAbsorb += AuraEffectAbsorbFn(spell_mage_frost_warding_trigger_AuraScript::Absorb, EFFECT_0); + AfterEffectRemove += AuraEffectRemoveFn(spell_mage_living_bomb_AuraScript::AfterRemove, EFFECT_1, SPELL_AURA_DUMMY, AURA_EFFECT_HANDLE_REAL); } }; AuraScript* GetAuraScript() const { - return new spell_mage_frost_warding_trigger_AuraScript(); + return new spell_mage_living_bomb_AuraScript(); } }; -class spell_mage_incanters_absorbtion_base_AuraScript : public AuraScript +// -1463 - Mana Shield +class spell_mage_mana_shield : public SpellScriptLoader { public: - enum Spells + spell_mage_mana_shield() : SpellScriptLoader("spell_mage_mana_shield") { } + + class spell_mage_mana_shield_AuraScript : public spell_mage_incanters_absorbtion_base_AuraScript { - SPELL_MAGE_INCANTERS_ABSORBTION_TRIGGERED = 44413, - SPELL_MAGE_INCANTERS_ABSORBTION_R1 = 44394, + PrepareAuraScript(spell_mage_mana_shield_AuraScript); + + void CalculateAmount(AuraEffect const* /*aurEff*/, int32& amount, bool& canBeRecalculated) + { + canBeRecalculated = false; + if (Unit* caster = GetCaster()) + { + // +80.53% from sp bonus + float bonus = 0.8053f; + + bonus *= caster->SpellBaseHealingBonusDone(GetSpellInfo()->GetSchoolMask()); + bonus *= caster->CalculateLevelPenalty(GetSpellInfo()); + + amount += int32(bonus); + } + } + + void Register() + { + DoEffectCalcAmount += AuraEffectCalcAmountFn(spell_mage_mana_shield_AuraScript::CalculateAmount, EFFECT_0, SPELL_AURA_MANA_SHIELD); + AfterEffectManaShield += AuraEffectManaShieldFn(spell_mage_mana_shield_AuraScript::Trigger, EFFECT_0); + } }; - bool Validate(SpellInfo const* /*spellEntry*/) + AuraScript* GetAuraScript() const { - return sSpellMgr->GetSpellInfo(SPELL_MAGE_INCANTERS_ABSORBTION_TRIGGERED) - && sSpellMgr->GetSpellInfo(SPELL_MAGE_INCANTERS_ABSORBTION_R1); + return new spell_mage_mana_shield_AuraScript(); } +}; - void Trigger(AuraEffect* aurEff, DamageInfo & /*dmgInfo*/, uint32 & absorbAmount) +// -29074 - Master of Elements +class spell_mage_master_of_elements : public SpellScriptLoader +{ + public: + spell_mage_master_of_elements() : SpellScriptLoader("spell_mage_master_of_elements") { } + + class spell_mage_master_of_elements_AuraScript : public AuraScript { - Unit* target = GetTarget(); + PrepareAuraScript(spell_mage_master_of_elements_AuraScript); - if (AuraEffect* talentAurEff = target->GetAuraEffectOfRankedSpell(SPELL_MAGE_INCANTERS_ABSORBTION_R1, EFFECT_0)) + bool Validate(SpellInfo const* /*spellInfo*/) { - int32 bp = CalculatePct(absorbAmount, talentAurEff->GetAmount()); - target->CastCustomSpell(target, SPELL_MAGE_INCANTERS_ABSORBTION_TRIGGERED, &bp, NULL, NULL, true, NULL, aurEff); + if (!sSpellMgr->GetSpellInfo(SPELL_MAGE_MASTER_OF_ELEMENTS_ENERGIZE)) + return false; + return true; } - } -}; -// Incanter's Absorption -class spell_mage_incanters_absorbtion_absorb : public SpellScriptLoader -{ -public: - spell_mage_incanters_absorbtion_absorb() : SpellScriptLoader("spell_mage_incanters_absorbtion_absorb") { } + bool CheckProc(ProcEventInfo& eventInfo) + { + return eventInfo.GetDamageInfo()->GetSpellInfo(); // eventInfo.GetSpellInfo() + } - class spell_mage_incanters_absorbtion_absorb_AuraScript : public spell_mage_incanters_absorbtion_base_AuraScript - { - PrepareAuraScript(spell_mage_incanters_absorbtion_absorb_AuraScript); + void HandleProc(AuraEffect const* aurEff, ProcEventInfo& eventInfo) + { + PreventDefaultAction(); + + int32 mana = int32(eventInfo.GetDamageInfo()->GetSpellInfo()->CalcPowerCost(GetTarget(), eventInfo.GetDamageInfo()->GetSchoolMask())); + mana = CalculatePct(mana, aurEff->GetAmount()); + + if (mana > 0) + GetTarget()->CastCustomSpell(SPELL_MAGE_MASTER_OF_ELEMENTS_ENERGIZE, SPELLVALUE_BASE_POINT0, mana, GetTarget(), true, NULL, aurEff); + } + + void Register() + { + DoCheckProc += AuraCheckProcFn(spell_mage_master_of_elements_AuraScript::CheckProc); + OnEffectProc += AuraEffectProcFn(spell_mage_master_of_elements_AuraScript::HandleProc, EFFECT_0, SPELL_AURA_DUMMY); + } + }; - void Register() + AuraScript* GetAuraScript() const { - AfterEffectAbsorb += AuraEffectAbsorbFn(spell_mage_incanters_absorbtion_absorb_AuraScript::Trigger, EFFECT_0); + return new spell_mage_master_of_elements_AuraScript(); } - }; +}; - AuraScript* GetAuraScript() const - { - return new spell_mage_incanters_absorbtion_absorb_AuraScript(); - } +enum SilvermoonPolymorph +{ + NPC_AUROSALIA = 18744, }; -// Incanter's Absorption -class spell_mage_incanters_absorbtion_manashield : public SpellScriptLoader +/// @todo move out of here and rename - not a mage spell +// 32826 - Polymorph (Visual) +class spell_mage_polymorph_cast_visual : public SpellScriptLoader { -public: - spell_mage_incanters_absorbtion_manashield() : SpellScriptLoader("spell_mage_incanters_absorbtion_manashield") { } + public: + spell_mage_polymorph_cast_visual() : SpellScriptLoader("spell_mage_polymorph_visual") { } + + class spell_mage_polymorph_cast_visual_SpellScript : public SpellScript + { + PrepareSpellScript(spell_mage_polymorph_cast_visual_SpellScript); - class spell_mage_incanters_absorbtion_manashield_AuraScript : public spell_mage_incanters_absorbtion_base_AuraScript - { - PrepareAuraScript(spell_mage_incanters_absorbtion_manashield_AuraScript); + static const uint32 PolymorhForms[6]; + + bool Validate(SpellInfo const* /*spellInfo*/) + { + // check if spell ids exist in dbc + for (uint32 i = 0; i < 6; ++i) + if (!sSpellMgr->GetSpellInfo(PolymorhForms[i])) + return false; + return true; + } - void Register() + void HandleDummy(SpellEffIndex /*effIndex*/) + { + if (Unit* target = GetCaster()->FindNearestCreature(NPC_AUROSALIA, 30.0f)) + if (target->GetTypeId() == TYPEID_UNIT) + target->CastSpell(target, PolymorhForms[urand(0, 5)], true); + } + + void Register() + { + OnEffectHitTarget += SpellEffectFn(spell_mage_polymorph_cast_visual_SpellScript::HandleDummy, EFFECT_0, SPELL_EFFECT_DUMMY); + } + }; + + SpellScript* GetSpellScript() const { - AfterEffectManaShield += AuraEffectManaShieldFn(spell_mage_incanters_absorbtion_manashield_AuraScript::Trigger, EFFECT_0); + return new spell_mage_polymorph_cast_visual_SpellScript(); } - }; +}; - AuraScript* GetAuraScript() const - { - return new spell_mage_incanters_absorbtion_manashield_AuraScript(); - } +const uint32 spell_mage_polymorph_cast_visual::spell_mage_polymorph_cast_visual_SpellScript::PolymorhForms[6] = +{ + SPELL_MAGE_SQUIRREL_FORM, + SPELL_MAGE_GIRAFFE_FORM, + SPELL_MAGE_SERPENT_FORM, + SPELL_MAGE_DRAGONHAWK_FORM, + SPELL_MAGE_WORGEN_FORM, + SPELL_MAGE_SHEEP_FORM }; -class spell_mage_living_bomb : public SpellScriptLoader +// 31687 - Summon Water Elemental +class spell_mage_summon_water_elemental : public SpellScriptLoader { public: - spell_mage_living_bomb() : SpellScriptLoader("spell_mage_living_bomb") { } + spell_mage_summon_water_elemental() : SpellScriptLoader("spell_mage_summon_water_elemental") { } - class spell_mage_living_bomb_AuraScript : public AuraScript + class spell_mage_summon_water_elemental_SpellScript : public SpellScript { - PrepareAuraScript(spell_mage_living_bomb_AuraScript); + PrepareSpellScript(spell_mage_summon_water_elemental_SpellScript); - bool Validate(SpellInfo const* spell) + bool Validate(SpellInfo const* /*spellInfo*/) { - if (!sSpellMgr->GetSpellInfo(uint32(spell->Effects[EFFECT_1].CalcValue()))) + if (!sSpellMgr->GetSpellInfo(SPELL_MAGE_GLYPH_OF_ETERNAL_WATER) || !sSpellMgr->GetSpellInfo(SPELL_MAGE_SUMMON_WATER_ELEMENTAL_TEMPORARY) || !sSpellMgr->GetSpellInfo(SPELL_MAGE_SUMMON_WATER_ELEMENTAL_PERMANENT)) return false; return true; } - void AfterRemove(AuraEffect const* aurEff, AuraEffectHandleModes /*mode*/) + void HandleDummy(SpellEffIndex /*effIndex*/) { - AuraRemoveMode removeMode = GetTargetApplication()->GetRemoveMode(); - if (removeMode != AURA_REMOVE_BY_ENEMY_SPELL && removeMode != AURA_REMOVE_BY_EXPIRE) - return; - - if (Unit* caster = GetCaster()) - caster->CastSpell(GetTarget(), uint32(aurEff->GetAmount()), true, NULL, aurEff); + Unit* caster = GetCaster(); + // Glyph of Eternal Water + if (caster->HasAura(SPELL_MAGE_GLYPH_OF_ETERNAL_WATER)) + caster->CastSpell(caster, SPELL_MAGE_SUMMON_WATER_ELEMENTAL_PERMANENT, true); + else + caster->CastSpell(caster, SPELL_MAGE_SUMMON_WATER_ELEMENTAL_TEMPORARY, true); } void Register() { - AfterEffectRemove += AuraEffectRemoveFn(spell_mage_living_bomb_AuraScript::AfterRemove, EFFECT_1, SPELL_AURA_DUMMY, AURA_EFFECT_HANDLE_REAL); + OnEffectHit += SpellEffectFn(spell_mage_summon_water_elemental_SpellScript::HandleDummy, EFFECT_0, SPELL_EFFECT_DUMMY); } }; - AuraScript* GetAuraScript() const + SpellScript* GetSpellScript() const { - return new spell_mage_living_bomb_AuraScript(); + return new spell_mage_summon_water_elemental_SpellScript(); } }; void AddSC_mage_spell_scripts() { new spell_mage_blast_wave(); + new spell_mage_burnout(); new spell_mage_cold_snap(); - new spell_mage_frost_warding_trigger(); - new spell_mage_incanters_absorbtion_absorb(); - new spell_mage_incanters_absorbtion_manashield(); + new spell_mage_fire_frost_ward(); + new spell_mage_focus_magic(); + new spell_mage_ice_barrier(); + new spell_mage_ignite(); + new spell_mage_living_bomb(); + new spell_mage_mana_shield(); + new spell_mage_master_of_elements(); new spell_mage_polymorph_cast_visual(); new spell_mage_summon_water_elemental(); - new spell_mage_living_bomb(); } diff --git a/src/server/scripts/Spells/spell_paladin.cpp b/src/server/scripts/Spells/spell_paladin.cpp index 07d903c9587..6be2453affb 100644 --- a/src/server/scripts/Spells/spell_paladin.cpp +++ b/src/server/scripts/Spells/spell_paladin.cpp @@ -29,28 +29,40 @@ enum PaladinSpells { - PALADIN_SPELL_DIVINE_PLEA = 54428, - PALADIN_SPELL_BLESSING_OF_SANCTUARY_BUFF = 67480, + SPELL_PALADIN_DIVINE_PLEA = 54428, + SPELL_PALADIN_BLESSING_OF_SANCTUARY_BUFF = 67480, + SPELL_PALADIN_BLESSING_OF_SANCTUARY_ENERGIZE = 57319, - PALADIN_SPELL_HOLY_SHOCK_R1 = 20473, - PALADIN_SPELL_HOLY_SHOCK_R1_DAMAGE = 25912, - PALADIN_SPELL_HOLY_SHOCK_R1_HEALING = 25914, + SPELL_PALADIN_HOLY_SHOCK_R1 = 20473, + SPELL_PALADIN_HOLY_SHOCK_R1_DAMAGE = 25912, + SPELL_PALADIN_HOLY_SHOCK_R1_HEALING = 25914, - SPELL_BLESSING_OF_LOWER_CITY_DRUID = 37878, - SPELL_BLESSING_OF_LOWER_CITY_PALADIN = 37879, - SPELL_BLESSING_OF_LOWER_CITY_PRIEST = 37880, - SPELL_BLESSING_OF_LOWER_CITY_SHAMAN = 37881, + SPELL_PALADIN_BLESSING_OF_LOWER_CITY_DRUID = 37878, + SPELL_PALADIN_BLESSING_OF_LOWER_CITY_PALADIN = 37879, + SPELL_PALADIN_BLESSING_OF_LOWER_CITY_PRIEST = 37880, + SPELL_PALADIN_BLESSING_OF_LOWER_CITY_SHAMAN = 37881, - SPELL_DIVINE_STORM = 53385, - SPELL_DIVINE_STORM_DUMMY = 54171, - SPELL_DIVINE_STORM_HEAL = 54172, + SPELL_PALADIN_DIVINE_STORM = 53385, + SPELL_PALADIN_DIVINE_STORM_DUMMY = 54171, + SPELL_PALADIN_DIVINE_STORM_HEAL = 54172, - SPELL_FORBEARANCE = 25771, - SPELL_AVENGING_WRATH_MARKER = 61987, - SPELL_IMMUNE_SHIELD_MARKER = 61988, + SPELL_PALADIN_EYE_FOR_AN_EYE_DAMAGE = 25997, - SPELL_HAND_OF_SACRIFICE = 6940, - SPELL_DIVINE_SACRIFICE = 64205, + SPELL_PALADIN_FORBEARANCE = 25771, + SPELL_PALADIN_AVENGING_WRATH_MARKER = 61987, + SPELL_PALADIN_IMMUNE_SHIELD_MARKER = 61988, + + SPELL_PALADIN_HAND_OF_SACRIFICE = 6940, + SPELL_PALADIN_DIVINE_SACRIFICE = 64205, + + SPELL_PALADIN_GLYPH_OF_SALVATION = 63225, + + SPELL_PALADIN_RIGHTEOUS_DEFENSE_TAUNT = 31790, + + SPELL_PALADIN_SEAL_OF_RIGHTEOUSNESS = 25742, + + SPELL_GENERIC_ARENA_DAMPENING = 74410, + SPELL_GENERIC_BATTLEGROUND_DAMPENING = 74411 }; // 31850 - Ardent Defender @@ -129,6 +141,7 @@ class spell_pal_ardent_defender : public SpellScriptLoader } }; +// 37877 - Blessing of Faith class spell_pal_blessing_of_faith : public SpellScriptLoader { public: @@ -138,9 +151,9 @@ class spell_pal_blessing_of_faith : public SpellScriptLoader { PrepareSpellScript(spell_pal_blessing_of_faith_SpellScript); - bool Validate(SpellInfo const* /*spellEntry*/) + bool Validate(SpellInfo const* /*spellInfo*/) { - if (!sSpellMgr->GetSpellInfo(SPELL_BLESSING_OF_LOWER_CITY_DRUID) || !sSpellMgr->GetSpellInfo(SPELL_BLESSING_OF_LOWER_CITY_PALADIN) || !sSpellMgr->GetSpellInfo(SPELL_BLESSING_OF_LOWER_CITY_PRIEST) || !sSpellMgr->GetSpellInfo(SPELL_BLESSING_OF_LOWER_CITY_SHAMAN)) + if (!sSpellMgr->GetSpellInfo(SPELL_PALADIN_BLESSING_OF_LOWER_CITY_DRUID) || !sSpellMgr->GetSpellInfo(SPELL_PALADIN_BLESSING_OF_LOWER_CITY_PALADIN) || !sSpellMgr->GetSpellInfo(SPELL_PALADIN_BLESSING_OF_LOWER_CITY_PRIEST) || !sSpellMgr->GetSpellInfo(SPELL_PALADIN_BLESSING_OF_LOWER_CITY_SHAMAN)) return false; return true; } @@ -152,11 +165,20 @@ class spell_pal_blessing_of_faith : public SpellScriptLoader uint32 spell_id = 0; switch (unitTarget->getClass()) { - case CLASS_DRUID: spell_id = SPELL_BLESSING_OF_LOWER_CITY_DRUID; break; - case CLASS_PALADIN: spell_id = SPELL_BLESSING_OF_LOWER_CITY_PALADIN; break; - case CLASS_PRIEST: spell_id = SPELL_BLESSING_OF_LOWER_CITY_PRIEST; break; - case CLASS_SHAMAN: spell_id = SPELL_BLESSING_OF_LOWER_CITY_SHAMAN; break; - default: return; // ignore for non-healing classes + case CLASS_DRUID: + spell_id = SPELL_PALADIN_BLESSING_OF_LOWER_CITY_DRUID; + break; + case CLASS_PALADIN: + spell_id = SPELL_PALADIN_BLESSING_OF_LOWER_CITY_PALADIN; + break; + case CLASS_PRIEST: + spell_id = SPELL_PALADIN_BLESSING_OF_LOWER_CITY_PRIEST; + break; + case CLASS_SHAMAN: + spell_id = SPELL_PALADIN_BLESSING_OF_LOWER_CITY_SHAMAN; + break; + default: + return; // ignore for non-healing classes } Unit* caster = GetCaster(); caster->CastSpell(caster, spell_id, true); @@ -165,7 +187,6 @@ class spell_pal_blessing_of_faith : public SpellScriptLoader void Register() { - // add dummy effect spell handler to Blessing of Faith OnEffectHitTarget += SpellEffectFn(spell_pal_blessing_of_faith_SpellScript::HandleDummy, EFFECT_0, SPELL_EFFECT_DUMMY); } }; @@ -176,8 +197,8 @@ class spell_pal_blessing_of_faith : public SpellScriptLoader } }; -// 20911 Blessing of Sanctuary -// 25899 Greater Blessing of Sanctuary +// 20911 - Blessing of Sanctuary +// 25899 - Greater Blessing of Sanctuary class spell_pal_blessing_of_sanctuary : public SpellScriptLoader { public: @@ -187,9 +208,11 @@ class spell_pal_blessing_of_sanctuary : public SpellScriptLoader { PrepareAuraScript(spell_pal_blessing_of_sanctuary_AuraScript); - bool Validate(SpellInfo const* /*entry*/) + bool Validate(SpellInfo const* /*spellInfo*/) { - if (!sSpellMgr->GetSpellInfo(PALADIN_SPELL_BLESSING_OF_SANCTUARY_BUFF)) + if (!sSpellMgr->GetSpellInfo(SPELL_PALADIN_BLESSING_OF_SANCTUARY_BUFF)) + return false; + if (!sSpellMgr->GetSpellInfo(SPELL_PALADIN_BLESSING_OF_SANCTUARY_ENERGIZE)) return false; return true; } @@ -198,19 +221,32 @@ class spell_pal_blessing_of_sanctuary : public SpellScriptLoader { Unit* target = GetTarget(); if (Unit* caster = GetCaster()) - caster->CastSpell(target, PALADIN_SPELL_BLESSING_OF_SANCTUARY_BUFF, true); + caster->CastSpell(target, SPELL_PALADIN_BLESSING_OF_SANCTUARY_BUFF, true); } void HandleEffectRemove(AuraEffect const* /*aurEff*/, AuraEffectHandleModes /*mode*/) { Unit* target = GetTarget(); - target->RemoveAura(PALADIN_SPELL_BLESSING_OF_SANCTUARY_BUFF, GetCasterGUID()); + target->RemoveAura(SPELL_PALADIN_BLESSING_OF_SANCTUARY_BUFF, GetCasterGUID()); + } + + bool CheckProc(ProcEventInfo& /*eventInfo*/) + { + return GetTarget()->getPowerType() == POWER_MANA; + } + + void HandleProc(AuraEffect const* aurEff, ProcEventInfo& /*eventInfo*/) + { + PreventDefaultAction(); + GetTarget()->CastSpell(GetTarget(), SPELL_PALADIN_BLESSING_OF_SANCTUARY_ENERGIZE, true, NULL, aurEff); } void Register() { AfterEffectApply += AuraEffectApplyFn(spell_pal_blessing_of_sanctuary_AuraScript::HandleEffectApply, EFFECT_0, SPELL_AURA_DUMMY, AURA_EFFECT_HANDLE_REAL_OR_REAPPLY_MASK); AfterEffectRemove += AuraEffectRemoveFn(spell_pal_blessing_of_sanctuary_AuraScript::HandleEffectRemove, EFFECT_0, SPELL_AURA_DUMMY, AURA_EFFECT_HANDLE_REAL_OR_REAPPLY_MASK); + DoCheckProc += AuraCheckProcFn(spell_pal_blessing_of_sanctuary_AuraScript::CheckProc); + OnEffectProc += AuraEffectProcFn(spell_pal_blessing_of_sanctuary_AuraScript::HandleProc, EFFECT_0, SPELL_AURA_DUMMY); } }; @@ -220,7 +256,225 @@ class spell_pal_blessing_of_sanctuary : public SpellScriptLoader } }; -// 63521 Guarded by The Light +// 64205 - Divine Sacrifice +class spell_pal_divine_sacrifice : public SpellScriptLoader +{ + public: + spell_pal_divine_sacrifice() : SpellScriptLoader("spell_pal_divine_sacrifice") { } + + class spell_pal_divine_sacrifice_AuraScript : public AuraScript + { + PrepareAuraScript(spell_pal_divine_sacrifice_AuraScript); + + uint32 groupSize, minHpPct; + int32 remainingAmount; + + bool Load() + { + + if (Unit* caster = GetCaster()) + { + if (caster->GetTypeId() == TYPEID_PLAYER) + { + if (caster->ToPlayer()->GetGroup()) + groupSize = caster->ToPlayer()->GetGroup()->GetMembersCount(); + else + groupSize = 1; + } + else + return false; + + remainingAmount = (caster->CountPctFromMaxHealth(GetSpellInfo()->Effects[EFFECT_2].CalcValue(caster)) * groupSize); + minHpPct = GetSpellInfo()->Effects[EFFECT_1].CalcValue(caster); + return true; + } + return false; + } + + void Split(AuraEffect* /*aurEff*/, DamageInfo & /*dmgInfo*/, uint32 & splitAmount) + { + remainingAmount -= splitAmount; + // break when absorbed everything it could, or if the casters hp drops below 20% + if (Unit* caster = GetCaster()) + if (remainingAmount <= 0 || (caster->GetHealthPct() < minHpPct)) + caster->RemoveAura(SPELL_PALADIN_DIVINE_SACRIFICE); + } + + void Register() + { + OnEffectSplit += AuraEffectSplitFn(spell_pal_divine_sacrifice_AuraScript::Split, EFFECT_0); + } + }; + + AuraScript* GetAuraScript() const + { + return new spell_pal_divine_sacrifice_AuraScript(); + } +}; + +// 53385 - Divine Storm +class spell_pal_divine_storm : public SpellScriptLoader +{ + public: + spell_pal_divine_storm() : SpellScriptLoader("spell_pal_divine_storm") { } + + class spell_pal_divine_storm_SpellScript : public SpellScript + { + PrepareSpellScript(spell_pal_divine_storm_SpellScript); + + uint32 healPct; + + bool Validate(SpellInfo const* /*spellInfo*/) + { + if (!sSpellMgr->GetSpellInfo(SPELL_PALADIN_DIVINE_STORM_DUMMY)) + return false; + return true; + } + + bool Load() + { + healPct = GetSpellInfo()->Effects[EFFECT_1].CalcValue(GetCaster()); + return true; + } + + void TriggerHeal() + { + Unit* caster = GetCaster(); + caster->CastCustomSpell(SPELL_PALADIN_DIVINE_STORM_DUMMY, SPELLVALUE_BASE_POINT0, (GetHitDamage() * healPct) / 100, caster, true); + } + + void Register() + { + AfterHit += SpellHitFn(spell_pal_divine_storm_SpellScript::TriggerHeal); + } + }; + + SpellScript* GetSpellScript() const + { + return new spell_pal_divine_storm_SpellScript(); + } +}; + +// 54171 - Divine Storm (Dummy) +class spell_pal_divine_storm_dummy : public SpellScriptLoader +{ + public: + spell_pal_divine_storm_dummy() : SpellScriptLoader("spell_pal_divine_storm_dummy") { } + + class spell_pal_divine_storm_dummy_SpellScript : public SpellScript + { + PrepareSpellScript(spell_pal_divine_storm_dummy_SpellScript); + + bool Validate(SpellInfo const* /*spellInfo*/) + { + if (!sSpellMgr->GetSpellInfo(SPELL_PALADIN_DIVINE_STORM_HEAL)) + return false; + return true; + } + + void CountTargets(std::list<WorldObject*>& targetList) + { + _targetCount = targetList.size(); + } + + void HandleDummy(SpellEffIndex /*effIndex*/) + { + if (!_targetCount || ! GetHitUnit()) + return; + + int32 heal = GetEffectValue() / _targetCount; + GetCaster()->CastCustomSpell(GetHitUnit(), SPELL_PALADIN_DIVINE_STORM_HEAL, &heal, NULL, NULL, true); + } + private: + uint32 _targetCount; + + void Register() + { + OnEffectHitTarget += SpellEffectFn(spell_pal_divine_storm_dummy_SpellScript::HandleDummy, EFFECT_0, SPELL_EFFECT_DUMMY); + OnObjectAreaTargetSelect += SpellObjectAreaTargetSelectFn(spell_pal_divine_storm_dummy_SpellScript::CountTargets, EFFECT_0, TARGET_UNIT_CASTER_AREA_RAID); + } + }; + + SpellScript* GetSpellScript() const + { + return new spell_pal_divine_storm_dummy_SpellScript(); + } +}; + +// 33695 - Exorcism and Holy Wrath Damage +class spell_pal_exorcism_and_holy_wrath_damage : public SpellScriptLoader +{ + public: + spell_pal_exorcism_and_holy_wrath_damage() : SpellScriptLoader("spell_pal_exorcism_and_holy_wrath_damage") { } + + class spell_pal_exorcism_and_holy_wrath_damage_AuraScript : public AuraScript + { + PrepareAuraScript(spell_pal_exorcism_and_holy_wrath_damage_AuraScript); + + void HandleEffectCalcSpellMod(AuraEffect const* aurEff, SpellModifier*& spellMod) + { + if (!spellMod) + { + spellMod = new SpellModifier(aurEff->GetBase()); + spellMod->op = SPELLMOD_DAMAGE; + spellMod->type = SPELLMOD_FLAT; + spellMod->spellId = GetId(); + spellMod->mask[1] = 0x200002; + } + + spellMod->value = aurEff->GetAmount(); + } + + void Register() + { + DoEffectCalcSpellMod += AuraEffectCalcSpellModFn(spell_pal_exorcism_and_holy_wrath_damage_AuraScript::HandleEffectCalcSpellMod, EFFECT_0, SPELL_AURA_DUMMY); + } + }; + + AuraScript* GetAuraScript() const + { + return new spell_pal_exorcism_and_holy_wrath_damage_AuraScript(); + } +}; + +// -9799 - Eye for an Eye +class spell_pal_eye_for_an_eye : public SpellScriptLoader +{ + public: + spell_pal_eye_for_an_eye() : SpellScriptLoader("spell_pal_eye_for_an_eye") { } + + class spell_pal_eye_for_an_eye_AuraScript : public AuraScript + { + PrepareAuraScript(spell_pal_eye_for_an_eye_AuraScript); + + bool Validate(SpellInfo const* /*spellInfo*/) + { + if (!sSpellMgr->GetSpellInfo(SPELL_PALADIN_EYE_FOR_AN_EYE_DAMAGE)) + return false; + return true; + } + + void OnProc(AuraEffect const* aurEff, ProcEventInfo& eventInfo) + { + PreventDefaultAction(); + // return damage % to attacker but < 50% own total health + int32 damage = int32(std::min(CalculatePct(eventInfo.GetDamageInfo()->GetDamage(), aurEff->GetAmount()), GetTarget()->GetMaxHealth() / 2)); + GetTarget()->CastCustomSpell(SPELL_PALADIN_EYE_FOR_AN_EYE_DAMAGE, SPELLVALUE_BASE_POINT0, damage, eventInfo.GetProcTarget(), true, NULL, aurEff); + } + + void Register() + { + OnEffectProc += AuraEffectProcFn(spell_pal_eye_for_an_eye_AuraScript::OnProc, EFFECT_0, SPELL_AURA_DUMMY); + } + }; + + AuraScript* GetAuraScript() const + { + return new spell_pal_eye_for_an_eye_AuraScript(); + } +}; + +// 63521 - Guarded by The Light class spell_pal_guarded_by_the_light : public SpellScriptLoader { public: @@ -230,9 +484,9 @@ class spell_pal_guarded_by_the_light : public SpellScriptLoader { PrepareSpellScript(spell_pal_guarded_by_the_light_SpellScript); - bool Validate(SpellInfo const* /*spellEntry*/) + bool Validate(SpellInfo const* /*spellInfo*/) { - if (!sSpellMgr->GetSpellInfo(PALADIN_SPELL_DIVINE_PLEA)) + if (!sSpellMgr->GetSpellInfo(SPELL_PALADIN_DIVINE_PLEA)) return false; return true; } @@ -240,7 +494,7 @@ class spell_pal_guarded_by_the_light : public SpellScriptLoader void HandleScriptEffect(SpellEffIndex /*effIndex*/) { // Divine Plea - if (Aura* aura = GetCaster()->GetAura(PALADIN_SPELL_DIVINE_PLEA)) + if (Aura* aura = GetCaster()->GetAura(SPELL_PALADIN_DIVINE_PLEA)) aura->RefreshDuration(); } @@ -256,6 +510,84 @@ class spell_pal_guarded_by_the_light : public SpellScriptLoader } }; +// 6940 - Hand of Sacrifice +class spell_pal_hand_of_sacrifice : public SpellScriptLoader +{ + public: + spell_pal_hand_of_sacrifice() : SpellScriptLoader("spell_pal_hand_of_sacrifice") { } + + class spell_pal_hand_of_sacrifice_AuraScript : public AuraScript + { + PrepareAuraScript(spell_pal_hand_of_sacrifice_AuraScript); + + int32 remainingAmount; + + bool Load() + { + if (Unit* caster = GetCaster()) + { + remainingAmount = caster->GetMaxHealth(); + return true; + } + return false; + } + + void Split(AuraEffect* /*aurEff*/, DamageInfo & /*dmgInfo*/, uint32 & splitAmount) + { + remainingAmount -= splitAmount; + + if (remainingAmount <= 0) + { + GetTarget()->RemoveAura(SPELL_PALADIN_HAND_OF_SACRIFICE); + } + } + + void Register() + { + OnEffectSplit += AuraEffectSplitFn(spell_pal_hand_of_sacrifice_AuraScript::Split, EFFECT_0); + } + }; + + AuraScript* GetAuraScript() const + { + return new spell_pal_hand_of_sacrifice_AuraScript(); + } +}; + +// 1038 - Hand of Salvation +class spell_pal_hand_of_salvation : public SpellScriptLoader +{ + public: + spell_pal_hand_of_salvation() : SpellScriptLoader("spell_pal_hand_of_salvation") { } + + class spell_pal_hand_of_salvation_AuraScript : public AuraScript + { + PrepareAuraScript(spell_pal_hand_of_salvation_AuraScript); + + void CalculateAmount(AuraEffect const* /*aurEff*/, int32& amount, bool& /*canBeRecalculated*/) + { + if (Unit* caster = GetCaster()) + { + // Glyph of Salvation + if (caster->GetGUID() == GetUnitOwner()->GetGUID()) + if (AuraEffect const* aurEff = caster->GetAuraEffect(SPELL_PALADIN_GLYPH_OF_SALVATION, EFFECT_0)) + amount -= aurEff->GetAmount(); + } + } + + void Register() + { + DoEffectCalcAmount += AuraEffectCalcAmountFn(spell_pal_hand_of_salvation_AuraScript::CalculateAmount, EFFECT_1, SPELL_AURA_MOD_DAMAGE_PERCENT_TAKEN); + } + }; + + AuraScript* GetAuraScript() const + { + return new spell_pal_hand_of_salvation_AuraScript(); + } +}; + +// -20473 - Holy Shock class spell_pal_holy_shock : public SpellScriptLoader { public: @@ -267,15 +599,15 @@ class spell_pal_holy_shock : public SpellScriptLoader bool Validate(SpellInfo const* spell) { - if (!sSpellMgr->GetSpellInfo(PALADIN_SPELL_HOLY_SHOCK_R1)) + if (!sSpellMgr->GetSpellInfo(SPELL_PALADIN_HOLY_SHOCK_R1)) return false; // can't use other spell than holy shock due to spell_ranks dependency - if (sSpellMgr->GetFirstSpellInChain(PALADIN_SPELL_HOLY_SHOCK_R1) != sSpellMgr->GetFirstSpellInChain(spell->Id)) + if (sSpellMgr->GetFirstSpellInChain(SPELL_PALADIN_HOLY_SHOCK_R1) != sSpellMgr->GetFirstSpellInChain(spell->Id)) return false; uint8 rank = sSpellMgr->GetSpellRank(spell->Id); - if (!sSpellMgr->GetSpellWithRank(PALADIN_SPELL_HOLY_SHOCK_R1_DAMAGE, rank, true) || !sSpellMgr->GetSpellWithRank(PALADIN_SPELL_HOLY_SHOCK_R1_HEALING, rank, true)) + if (!sSpellMgr->GetSpellWithRank(SPELL_PALADIN_HOLY_SHOCK_R1_DAMAGE, rank, true) || !sSpellMgr->GetSpellWithRank(SPELL_PALADIN_HOLY_SHOCK_R1_HEALING, rank, true)) return false; return true; @@ -288,9 +620,9 @@ class spell_pal_holy_shock : public SpellScriptLoader { uint8 rank = sSpellMgr->GetSpellRank(GetSpellInfo()->Id); if (caster->IsFriendlyTo(unitTarget)) - caster->CastSpell(unitTarget, sSpellMgr->GetSpellWithRank(PALADIN_SPELL_HOLY_SHOCK_R1_HEALING, rank), true, 0); + caster->CastSpell(unitTarget, sSpellMgr->GetSpellWithRank(SPELL_PALADIN_HOLY_SHOCK_R1_HEALING, rank), true, 0); else - caster->CastSpell(unitTarget, sSpellMgr->GetSpellWithRank(PALADIN_SPELL_HOLY_SHOCK_R1_DAMAGE, rank), true, 0); + caster->CastSpell(unitTarget, sSpellMgr->GetSpellWithRank(SPELL_PALADIN_HOLY_SHOCK_R1_DAMAGE, rank), true, 0); } } @@ -315,7 +647,6 @@ class spell_pal_holy_shock : public SpellScriptLoader void Register() { - // add dummy effect spell handler to Holy Shock OnCheckCast += SpellCheckCastFn(spell_pal_holy_shock_SpellScript::CheckCast); OnEffectHitTarget += SpellEffectFn(spell_pal_holy_shock_SpellScript::HandleDummy, EFFECT_0, SPELL_EFFECT_DUMMY); } @@ -327,6 +658,7 @@ class spell_pal_holy_shock : public SpellScriptLoader } }; +// 20425 - Judgement of Command class spell_pal_judgement_of_command : public SpellScriptLoader { public: @@ -334,7 +666,8 @@ class spell_pal_judgement_of_command : public SpellScriptLoader class spell_pal_judgement_of_command_SpellScript : public SpellScript { - PrepareSpellScript(spell_pal_judgement_of_command_SpellScript) + PrepareSpellScript(spell_pal_judgement_of_command_SpellScript); + void HandleDummy(SpellEffIndex /*effIndex*/) { if (Unit* unitTarget = GetHitUnit()) @@ -344,7 +677,6 @@ class spell_pal_judgement_of_command : public SpellScriptLoader void Register() { - // add dummy effect spell handler to Judgement of Command OnEffectHitTarget += SpellEffectFn(spell_pal_judgement_of_command_SpellScript::HandleDummy, EFFECT_0, SPELL_EFFECT_DUMMY); } }; @@ -355,93 +687,7 @@ class spell_pal_judgement_of_command : public SpellScriptLoader } }; -class spell_pal_divine_storm : public SpellScriptLoader -{ - public: - spell_pal_divine_storm() : SpellScriptLoader("spell_pal_divine_storm") { } - - class spell_pal_divine_storm_SpellScript : public SpellScript - { - PrepareSpellScript(spell_pal_divine_storm_SpellScript); - - uint32 healPct; - - bool Validate(SpellInfo const* /* spell */) - { - if (!sSpellMgr->GetSpellInfo(SPELL_DIVINE_STORM_DUMMY)) - return false; - return true; - } - - bool Load() - { - healPct = GetSpellInfo()->Effects[EFFECT_1].CalcValue(GetCaster()); - return true; - } - - void TriggerHeal() - { - Unit* caster = GetCaster(); - caster->CastCustomSpell(SPELL_DIVINE_STORM_DUMMY, SPELLVALUE_BASE_POINT0, (GetHitDamage() * healPct) / 100, caster, true); - } - - void Register() - { - AfterHit += SpellHitFn(spell_pal_divine_storm_SpellScript::TriggerHeal); - } - }; - - SpellScript* GetSpellScript() const - { - return new spell_pal_divine_storm_SpellScript(); - } -}; - -class spell_pal_divine_storm_dummy : public SpellScriptLoader -{ - public: - spell_pal_divine_storm_dummy() : SpellScriptLoader("spell_pal_divine_storm_dummy") { } - - class spell_pal_divine_storm_dummy_SpellScript : public SpellScript - { - PrepareSpellScript(spell_pal_divine_storm_dummy_SpellScript); - - bool Validate(SpellInfo const* /* spell */) - { - if (!sSpellMgr->GetSpellInfo(SPELL_DIVINE_STORM_HEAL)) - return false; - return true; - } - - void CountTargets(std::list<WorldObject*>& targetList) - { - _targetCount = targetList.size(); - } - - void HandleDummy(SpellEffIndex /* effIndex */) - { - if (!_targetCount || ! GetHitUnit()) - return; - - int32 heal = GetEffectValue() / _targetCount; - GetCaster()->CastCustomSpell(GetHitUnit(), SPELL_DIVINE_STORM_HEAL, &heal, NULL, NULL, true); - } - private: - uint32 _targetCount; - - void Register() - { - OnEffectHitTarget += SpellEffectFn(spell_pal_divine_storm_dummy_SpellScript::HandleDummy, EFFECT_0, SPELL_EFFECT_DUMMY); - OnObjectAreaTargetSelect += SpellObjectAreaTargetSelectFn(spell_pal_divine_storm_dummy_SpellScript::CountTargets, EFFECT_0, TARGET_UNIT_CASTER_AREA_RAID); - } - }; - - SpellScript* GetSpellScript() const - { - return new spell_pal_divine_storm_dummy_SpellScript(); - } -}; - +// -633 - Lay on Hands class spell_pal_lay_on_hands : public SpellScriptLoader { public: @@ -453,11 +699,11 @@ class spell_pal_lay_on_hands : public SpellScriptLoader bool Validate(SpellInfo const* /*spell*/) { - if (!sSpellMgr->GetSpellInfo(SPELL_FORBEARANCE)) + if (!sSpellMgr->GetSpellInfo(SPELL_PALADIN_FORBEARANCE)) return false; - if (!sSpellMgr->GetSpellInfo(SPELL_AVENGING_WRATH_MARKER)) + if (!sSpellMgr->GetSpellInfo(SPELL_PALADIN_AVENGING_WRATH_MARKER)) return false; - if (!sSpellMgr->GetSpellInfo(SPELL_IMMUNE_SHIELD_MARKER)) + if (!sSpellMgr->GetSpellInfo(SPELL_PALADIN_IMMUNE_SHIELD_MARKER)) return false; return true; } @@ -467,7 +713,7 @@ class spell_pal_lay_on_hands : public SpellScriptLoader Unit* caster = GetCaster(); if (Unit* target = GetExplTargetUnit()) if (caster == target) - if (target->HasAura(SPELL_FORBEARANCE) || target->HasAura(SPELL_AVENGING_WRATH_MARKER) || target->HasAura(SPELL_IMMUNE_SHIELD_MARKER)) + if (target->HasAura(SPELL_PALADIN_FORBEARANCE) || target->HasAura(SPELL_PALADIN_AVENGING_WRATH_MARKER) || target->HasAura(SPELL_PALADIN_IMMUNE_SHIELD_MARKER)) return SPELL_FAILED_TARGET_AURASTATE; return SPELL_CAST_OK; @@ -478,9 +724,9 @@ class spell_pal_lay_on_hands : public SpellScriptLoader Unit* caster = GetCaster(); if (caster == GetHitUnit()) { - caster->CastSpell(caster, SPELL_FORBEARANCE, true); - caster->CastSpell(caster, SPELL_AVENGING_WRATH_MARKER, true); - caster->CastSpell(caster, SPELL_IMMUNE_SHIELD_MARKER, true); + caster->CastSpell(caster, SPELL_PALADIN_FORBEARANCE, true); + caster->CastSpell(caster, SPELL_PALADIN_AVENGING_WRATH_MARKER, true); + caster->CastSpell(caster, SPELL_PALADIN_IMMUNE_SHIELD_MARKER, true); } } @@ -497,6 +743,7 @@ class spell_pal_lay_on_hands : public SpellScriptLoader } }; +// 31789 - Righteous Defense class spell_pal_righteous_defense : public SpellScriptLoader { public: @@ -506,6 +753,13 @@ class spell_pal_righteous_defense : public SpellScriptLoader { PrepareSpellScript(spell_pal_righteous_defense_SpellScript); + bool Validate(SpellInfo const* /*spellInfo*/) + { + if (!sSpellMgr->GetSpellInfo(SPELL_PALADIN_RIGHTEOUS_DEFENSE_TAUNT)) + return false; + return true; + } + SpellCastResult CheckCast() { Unit* caster = GetCaster(); @@ -523,148 +777,123 @@ class spell_pal_righteous_defense : public SpellScriptLoader return SPELL_CAST_OK; } - void Register() + void HandleTriggerSpellLaunch(SpellEffIndex effIndex) { - OnCheckCast += SpellCheckCastFn(spell_pal_righteous_defense_SpellScript::CheckCast); + PreventHitDefaultEffect(effIndex); } - }; - SpellScript* GetSpellScript() const - { - return new spell_pal_righteous_defense_SpellScript(); - } -}; - -class spell_pal_exorcism_and_holy_wrath_damage : public SpellScriptLoader -{ - public: - spell_pal_exorcism_and_holy_wrath_damage() : SpellScriptLoader("spell_pal_exorcism_and_holy_wrath_damage") { } - - class spell_pal_exorcism_and_holy_wrath_damage_AuraScript : public AuraScript - { - PrepareAuraScript(spell_pal_exorcism_and_holy_wrath_damage_AuraScript); - - void HandleEffectCalcSpellMod(AuraEffect const* aurEff, SpellModifier*& spellMod) + void HandleTriggerSpellHit(SpellEffIndex effIndex) { - if (!spellMod) - { - spellMod = new SpellModifier(aurEff->GetBase()); - spellMod->op = SPELLMOD_DAMAGE; - spellMod->type = SPELLMOD_FLAT; - spellMod->spellId = GetId(); - spellMod->mask[1] = 0x200002; - } - - spellMod->value = aurEff->GetAmount(); + PreventHitDefaultEffect(effIndex); + if (Unit* target = GetHitUnit()) + GetCaster()->CastSpell(target, SPELL_PALADIN_RIGHTEOUS_DEFENSE_TAUNT, true); } void Register() { - DoEffectCalcSpellMod += AuraEffectCalcSpellModFn(spell_pal_exorcism_and_holy_wrath_damage_AuraScript::HandleEffectCalcSpellMod, EFFECT_0, SPELL_AURA_DUMMY); + OnCheckCast += SpellCheckCastFn(spell_pal_righteous_defense_SpellScript::CheckCast); + //! WORKAROUND + //! target select will be executed in hitphase of effect 0 + //! so we must handle trigger spell also in hit phase (default execution in launch phase) + //! see issue #3718 + OnEffectLaunchTarget += SpellEffectFn(spell_pal_righteous_defense_SpellScript::HandleTriggerSpellLaunch, EFFECT_1, SPELL_EFFECT_TRIGGER_SPELL); + OnEffectHitTarget += SpellEffectFn(spell_pal_righteous_defense_SpellScript::HandleTriggerSpellHit, EFFECT_1, SPELL_EFFECT_TRIGGER_SPELL); } }; - AuraScript* GetAuraScript() const + SpellScript* GetSpellScript() const { - return new spell_pal_exorcism_and_holy_wrath_damage_AuraScript(); + return new spell_pal_righteous_defense_SpellScript(); } }; -class spell_pal_hand_of_sacrifice : public SpellScriptLoader +// 58597 - Sacred Shield +class spell_pal_sacred_shield : public SpellScriptLoader { public: - spell_pal_hand_of_sacrifice() : SpellScriptLoader("spell_pal_hand_of_sacrifice") { } + spell_pal_sacred_shield() : SpellScriptLoader("spell_pal_sacred_shield") { } - class spell_pal_hand_of_sacrifice_AuraScript : public AuraScript + class spell_pal_sacred_shield_AuraScript : public AuraScript { - PrepareAuraScript(spell_pal_hand_of_sacrifice_AuraScript); - - int32 remainingAmount; + PrepareAuraScript(spell_pal_sacred_shield_AuraScript); - bool Load() + void CalculateAmount(AuraEffect const* aurEff, int32& amount, bool& /*canBeRecalculated*/) { if (Unit* caster = GetCaster()) { - remainingAmount = caster->GetMaxHealth(); - return true; - } - return false; - } + // +75.00% from sp bonus + float bonus = CalculatePct(caster->SpellBaseHealingBonusDone(GetSpellInfo()->GetSchoolMask()), 75.0f); - void Split(AuraEffect* /*aurEff*/, DamageInfo & /*dmgInfo*/, uint32 & splitAmount) - { - remainingAmount -= splitAmount; + // Divine Guardian is only applied at the spell healing bonus because it was already applied to the base value in CalculateSpellDamage + bonus = caster->ApplyEffectModifiers(GetSpellInfo(), aurEff->GetEffIndex(), bonus); + bonus *= caster->CalculateLevelPenalty(GetSpellInfo()); - if (remainingAmount <= 0) - { - GetTarget()->RemoveAura(SPELL_HAND_OF_SACRIFICE); + amount += int32(bonus); + + // Arena - Dampening + if (AuraEffect const* dampening = caster->GetAuraEffect(SPELL_GENERIC_ARENA_DAMPENING, EFFECT_0)) + AddPct(amount, dampening->GetAmount()); + // Battleground - Dampening + else if (AuraEffect const* dampening = caster->GetAuraEffect(SPELL_GENERIC_BATTLEGROUND_DAMPENING, EFFECT_0)) + AddPct(amount, dampening->GetAmount()); } } void Register() { - OnEffectSplit += AuraEffectSplitFn(spell_pal_hand_of_sacrifice_AuraScript::Split, EFFECT_0); + DoEffectCalcAmount += AuraEffectCalcAmountFn(spell_pal_sacred_shield_AuraScript::CalculateAmount, EFFECT_0, SPELL_AURA_SCHOOL_ABSORB); } }; AuraScript* GetAuraScript() const { - return new spell_pal_hand_of_sacrifice_AuraScript(); + return new spell_pal_sacred_shield_AuraScript(); } }; -class spell_pal_divine_sacrifice : public SpellScriptLoader +// 20154, 21084 - Seal of Righteousness - melee proc dummy (addition ${$MWS*(0.022*$AP+0.044*$SPH)} damage) +class spell_pal_seal_of_righteousness : public SpellScriptLoader { public: - spell_pal_divine_sacrifice() : SpellScriptLoader("spell_pal_divine_sacrifice") { } + spell_pal_seal_of_righteousness() : SpellScriptLoader("spell_pal_seal_of_righteousness") { } - class spell_pal_divine_sacrifice_AuraScript : public AuraScript + class spell_pal_seal_of_righteousness_AuraScript : public AuraScript { - PrepareAuraScript(spell_pal_divine_sacrifice_AuraScript); + PrepareAuraScript(spell_pal_seal_of_righteousness_AuraScript); - uint32 groupSize, minHpPct; - int32 remainingAmount; - - bool Load() + bool Validate(SpellInfo const* /*spellInfo*/) { + if (!sSpellMgr->GetSpellInfo(SPELL_PALADIN_SEAL_OF_RIGHTEOUSNESS)) + return false; + return true; + } - if (Unit* caster = GetCaster()) - { - if (caster->GetTypeId() == TYPEID_PLAYER) - { - if (caster->ToPlayer()->GetGroup()) - groupSize = caster->ToPlayer()->GetGroup()->GetMembersCount(); - else - groupSize = 1; - } - else - return false; - - remainingAmount = (caster->CountPctFromMaxHealth(GetSpellInfo()->Effects[EFFECT_2].CalcValue(caster)) * groupSize); - minHpPct = GetSpellInfo()->Effects[EFFECT_1].CalcValue(caster); - return true; - } - return false; + bool CheckProc(ProcEventInfo& eventInfo) + { + return eventInfo.GetProcTarget(); } - void Split(AuraEffect* /*aurEff*/, DamageInfo & /*dmgInfo*/, uint32 & splitAmount) + void HandleProc(AuraEffect const* aurEff, ProcEventInfo& eventInfo) { - remainingAmount -= splitAmount; - // break when absorbed everything it could, or if the casters hp drops below 20% - if (Unit* caster = GetCaster()) - if (remainingAmount <= 0 || (caster->GetHealthPct() < minHpPct)) - caster->RemoveAura(SPELL_DIVINE_SACRIFICE); + PreventDefaultAction(); + + float ap = GetTarget()->GetTotalAttackPowerValue(BASE_ATTACK); + int32 holy = GetTarget()->SpellBaseDamageBonusDone(SPELL_SCHOOL_MASK_HOLY); + holy += eventInfo.GetProcTarget()->SpellBaseDamageBonusTaken(SPELL_SCHOOL_MASK_HOLY); + int32 bp = int32((ap * 0.022f + 0.044f * holy) * GetTarget()->GetAttackTime(BASE_ATTACK) / 1000); + GetTarget()->CastCustomSpell(SPELL_PALADIN_SEAL_OF_RIGHTEOUSNESS, SPELLVALUE_BASE_POINT0, bp, eventInfo.GetProcTarget(), true, NULL, aurEff); } void Register() { - OnEffectSplit += AuraEffectSplitFn(spell_pal_divine_sacrifice_AuraScript::Split, EFFECT_0); + DoCheckProc += AuraCheckProcFn(spell_pal_seal_of_righteousness_AuraScript::CheckProc); + OnEffectProc += AuraEffectProcFn(spell_pal_seal_of_righteousness_AuraScript::HandleProc, EFFECT_0, SPELL_AURA_DUMMY); } }; AuraScript* GetAuraScript() const { - return new spell_pal_divine_sacrifice_AuraScript(); + return new spell_pal_seal_of_righteousness_AuraScript(); } }; @@ -673,14 +902,18 @@ void AddSC_paladin_spell_scripts() new spell_pal_ardent_defender(); new spell_pal_blessing_of_faith(); new spell_pal_blessing_of_sanctuary(); + new spell_pal_divine_sacrifice(); + new spell_pal_divine_storm(); + new spell_pal_divine_storm_dummy(); + new spell_pal_exorcism_and_holy_wrath_damage(); + new spell_pal_eye_for_an_eye(); new spell_pal_guarded_by_the_light(); + new spell_pal_hand_of_sacrifice(); + new spell_pal_hand_of_salvation(); new spell_pal_holy_shock(); new spell_pal_judgement_of_command(); - new spell_pal_divine_storm(); - new spell_pal_divine_storm_dummy(); new spell_pal_lay_on_hands(); new spell_pal_righteous_defense(); - new spell_pal_exorcism_and_holy_wrath_damage(); - new spell_pal_hand_of_sacrifice(); - new spell_pal_divine_sacrifice(); + new spell_pal_sacred_shield(); + new spell_pal_seal_of_righteousness(); } diff --git a/src/server/scripts/Spells/spell_pet.cpp b/src/server/scripts/Spells/spell_pet.cpp index 5198e555ee1..c4d5562ab39 100644 --- a/src/server/scripts/Spells/spell_pet.cpp +++ b/src/server/scripts/Spells/spell_pet.cpp @@ -1451,7 +1451,7 @@ public: if (pet->GetEntry() == ENTRY_ARMY_OF_THE_DEAD_GHOUL) amount = -90; // Night of the dead - else if ( Aura * aur = owner->GetAuraOfRankedSpell(SPELL_NIGHT_OF_THE_DEAD)) + else if (Aura* aur = owner->GetAuraOfRankedSpell(SPELL_NIGHT_OF_THE_DEAD)) amount = aur->GetSpellInfo()->Effects[EFFECT_2].CalcValue(); } } diff --git a/src/server/scripts/Spells/spell_priest.cpp b/src/server/scripts/Spells/spell_priest.cpp index 045df640090..4e86a895484 100644 --- a/src/server/scripts/Spells/spell_priest.cpp +++ b/src/server/scripts/Spells/spell_priest.cpp @@ -29,20 +29,118 @@ enum PriestSpells { - PRIEST_SPELL_GUARDIAN_SPIRIT_HEAL = 48153, - PRIEST_SPELL_PENANCE_R1 = 47540, - PRIEST_SPELL_PENANCE_R1_DAMAGE = 47758, - PRIEST_SPELL_PENANCE_R1_HEAL = 47757, - PRIEST_SPELL_REFLECTIVE_SHIELD_TRIGGERED = 33619, - PRIEST_SPELL_REFLECTIVE_SHIELD_R1 = 33201, - PRIEST_SPELL_VAMPIRIC_TOUCH_DISPEL = 64085, - PRIEST_SPELL_EMPOWERED_RENEW = 63544, - PRIEST_ICON_ID_EMPOWERED_RENEW_TALENT = 3021, - PRIEST_ICON_ID_PAIN_AND_SUFFERING = 2874, - PRIEST_SHADOW_WORD_DEATH = 32409, + SPELL_PRIEST_DIVINE_AEGIS = 47753, + SPELL_PRIEST_EMPOWERED_RENEW = 63544, + SPELL_PRIEST_GLYPH_OF_LIGHTWELL = 55673, + SPELL_PRIEST_GLYPH_OF_PRAYER_OF_HEALING_HEAL = 56161, + SPELL_PRIEST_GUARDIAN_SPIRIT_HEAL = 48153, + SPELL_PRIEST_MANA_LEECH_PROC = 34650, + SPELL_PRIEST_PENANCE_R1 = 47540, + SPELL_PRIEST_PENANCE_R1_DAMAGE = 47758, + SPELL_PRIEST_PENANCE_R1_HEAL = 47757, + SPELL_PRIEST_REFLECTIVE_SHIELD_TRIGGERED = 33619, + SPELL_PRIEST_REFLECTIVE_SHIELD_R1 = 33201, + SPELL_PRIEST_SHADOW_WORD_DEATH = 32409, + SPELL_PRIEST_T9_HEALING_2P = 67201, + SPELL_PRIEST_VAMPIRIC_TOUCH_DISPEL = 64085, }; -// Guardian Spirit +enum PriestSpellIcons +{ + PRIEST_ICON_ID_BORROWED_TIME = 2899, + PRIEST_ICON_ID_EMPOWERED_RENEW_TALENT = 3021, + PRIEST_ICON_ID_PAIN_AND_SUFFERING = 2874, +}; + +// -47509 - Divine Aegis +class spell_pri_divine_aegis : public SpellScriptLoader +{ + public: + spell_pri_divine_aegis() : SpellScriptLoader("spell_pri_divine_aegis") { } + + class spell_pri_divine_aegis_AuraScript : public AuraScript + { + PrepareAuraScript(spell_pri_divine_aegis_AuraScript); + + bool Validate(SpellInfo const* /*spellInfo*/) + { + if (!sSpellMgr->GetSpellInfo(SPELL_PRIEST_DIVINE_AEGIS)) + return false; + return true; + } + + bool CheckProc(ProcEventInfo& eventInfo) + { + return eventInfo.GetProcTarget(); + } + + void HandleProc(AuraEffect const* aurEff, ProcEventInfo& eventInfo) + { + PreventDefaultAction(); + + int32 absorb = CalculatePct(int32(eventInfo.GetHealInfo()->GetHeal()), aurEff->GetAmount()); + + // Multiple effects stack, so let's try to find this aura. + if (AuraEffect const* aegis = eventInfo.GetProcTarget()->GetAuraEffect(SPELL_PRIEST_DIVINE_AEGIS, EFFECT_0)) + absorb += aegis->GetAmount(); + + absorb = std::min(absorb, eventInfo.GetProcTarget()->getLevel() * 125); + + GetTarget()->CastCustomSpell(SPELL_PRIEST_DIVINE_AEGIS, SPELLVALUE_BASE_POINT0, absorb, eventInfo.GetProcTarget(), true, NULL, aurEff); + } + + void Register() + { + DoCheckProc += AuraCheckProcFn(spell_pri_divine_aegis_AuraScript::CheckProc); + OnEffectProc += AuraEffectProcFn(spell_pri_divine_aegis_AuraScript::HandleProc, EFFECT_0, SPELL_AURA_DUMMY); + } + }; + + AuraScript* GetAuraScript() const + { + return new spell_pri_divine_aegis_AuraScript(); + } +}; + +// 55680 - Glyph of Prayer of Healing +class spell_pri_glyph_of_prayer_of_healing : public SpellScriptLoader +{ + public: + spell_pri_glyph_of_prayer_of_healing() : SpellScriptLoader("spell_pri_glyph_of_prayer_of_healing") { } + + class spell_pri_glyph_of_prayer_of_healing_AuraScript : public AuraScript + { + PrepareAuraScript(spell_pri_glyph_of_prayer_of_healing_AuraScript); + + bool Validate(SpellInfo const* /*spellInfo*/) + { + if (!sSpellMgr->GetSpellInfo(SPELL_PRIEST_GLYPH_OF_PRAYER_OF_HEALING_HEAL)) + return false; + return true; + } + + void HandleProc(AuraEffect const* aurEff, ProcEventInfo& eventInfo) + { + PreventDefaultAction(); + + SpellInfo const* triggeredSpellInfo = sSpellMgr->GetSpellInfo(SPELL_PRIEST_GLYPH_OF_PRAYER_OF_HEALING_HEAL); + int32 heal = int32(CalculatePct(int32(eventInfo.GetHealInfo()->GetHeal()), aurEff->GetAmount()) / triggeredSpellInfo->GetMaxTicks()); + GetTarget()->CastCustomSpell(SPELL_PRIEST_GLYPH_OF_PRAYER_OF_HEALING_HEAL, SPELLVALUE_BASE_POINT0, heal, eventInfo.GetProcTarget(), true, NULL, aurEff); + } + + void Register() + { + OnEffectProc += AuraEffectProcFn(spell_pri_glyph_of_prayer_of_healing_AuraScript::HandleProc, EFFECT_0, SPELL_AURA_DUMMY); + } + }; + + AuraScript* GetAuraScript() const + { + return new spell_pri_glyph_of_prayer_of_healing_AuraScript(); + } +}; + +// -47788 - Guardian Spirit class spell_pri_guardian_spirit : public SpellScriptLoader { public: @@ -54,9 +152,9 @@ class spell_pri_guardian_spirit : public SpellScriptLoader uint32 healPct; - bool Validate(SpellInfo const* /*spellEntry*/) + bool Validate(SpellInfo const* /*spellInfo*/) { - if (!sSpellMgr->GetSpellInfo(PRIEST_SPELL_GUARDIAN_SPIRIT_HEAL)) + if (!sSpellMgr->GetSpellInfo(SPELL_PRIEST_GUARDIAN_SPIRIT_HEAL)) return false; return true; } @@ -82,7 +180,7 @@ class spell_pri_guardian_spirit : public SpellScriptLoader int32 healAmount = int32(target->CountPctFromMaxHealth(healPct)); // remove the aura now, we don't want 40% healing bonus Remove(AURA_REMOVE_BY_ENEMY_SPELL); - target->CastCustomSpell(target, PRIEST_SPELL_GUARDIAN_SPIRIT_HEAL, &healAmount, NULL, NULL, true); + target->CastCustomSpell(target, SPELL_PRIEST_GUARDIAN_SPIRIT_HEAL, &healAmount, NULL, NULL, true); absorbAmount = dmgInfo.GetDamage(); } @@ -99,6 +197,39 @@ class spell_pri_guardian_spirit : public SpellScriptLoader } }; +// -7001 - Lightwell Renew +class spell_pri_lightwell_renew : public SpellScriptLoader +{ + public: + spell_pri_lightwell_renew() : SpellScriptLoader("spell_pri_lightwell_renew") { } + + class spell_pri_lightwell_renew_AuraScript : public AuraScript + { + PrepareAuraScript(spell_pri_lightwell_renew_AuraScript); + + void CalculateAmount(AuraEffect const* /*aurEff*/, int32& amount, bool& /*canBeRecalculated*/) + { + if (Unit* caster = GetCaster()) + { + // Bonus from Glyph of Lightwell + if (AuraEffect* modHealing = caster->GetAuraEffect(SPELL_PRIEST_GLYPH_OF_LIGHTWELL, EFFECT_0)) + AddPct(amount, modHealing->GetAmount()); + } + } + + void Register() + { + DoEffectCalcAmount += AuraEffectCalcAmountFn(spell_pri_lightwell_renew_AuraScript::CalculateAmount, EFFECT_0, SPELL_AURA_PERIODIC_HEAL); + } + }; + + AuraScript* GetAuraScript() const + { + return new spell_pri_lightwell_renew_AuraScript(); + } +}; + +// -8129 - Mana Burn class spell_pri_mana_burn : public SpellScriptLoader { public: @@ -126,6 +257,58 @@ class spell_pri_mana_burn : public SpellScriptLoader } }; +// 28305 - Mana Leech (Passive) (Priest Pet Aura) +class spell_pri_mana_leech : public SpellScriptLoader +{ + public: + spell_pri_mana_leech() : SpellScriptLoader("spell_pri_mana_leech") { } + + class spell_pri_mana_leech_AuraScript : public AuraScript + { + PrepareAuraScript(spell_pri_mana_leech_AuraScript); + + bool Validate(SpellInfo const* /*spellInfo*/) + { + if (!sSpellMgr->GetSpellInfo(SPELL_PRIEST_MANA_LEECH_PROC)) + return false; + return true; + } + + bool Load() + { + _procTarget = NULL; + return true; + } + + bool CheckProc(ProcEventInfo& /*eventInfo*/) + { + _procTarget = GetTarget()->GetOwner(); + return _procTarget; + } + + void HandleProc(AuraEffect const* aurEff, ProcEventInfo& /*eventInfo*/) + { + PreventDefaultAction(); + GetTarget()->CastSpell(_procTarget, SPELL_PRIEST_MANA_LEECH_PROC, true, NULL, aurEff); + } + + void Register() + { + DoCheckProc += AuraCheckProcFn(spell_pri_mana_leech_AuraScript::CheckProc); + OnEffectProc += AuraEffectProcFn(spell_pri_mana_leech_AuraScript::HandleProc, EFFECT_0, SPELL_AURA_DUMMY); + } + + private: + Unit* _procTarget; + }; + + AuraScript* GetAuraScript() const + { + return new spell_pri_mana_leech_AuraScript(); + } +}; + +// -49821 - Mind Sear class spell_pri_mind_sear : public SpellScriptLoader { public: @@ -152,12 +335,12 @@ class spell_pri_mind_sear : public SpellScriptLoader } }; +// 47948 - Pain and Suffering (Proc) class spell_pri_pain_and_suffering_proc : public SpellScriptLoader { public: spell_pri_pain_and_suffering_proc() : SpellScriptLoader("spell_pri_pain_and_suffering_proc") { } - // 47948 Pain and Suffering (proc) class spell_pri_pain_and_suffering_proc_SpellScript : public SpellScript { PrepareSpellScript(spell_pri_pain_and_suffering_proc_SpellScript); @@ -182,6 +365,7 @@ class spell_pri_pain_and_suffering_proc : public SpellScriptLoader } }; +// -47540 - Penance class spell_pri_penance : public SpellScriptLoader { public: @@ -196,18 +380,18 @@ class spell_pri_penance : public SpellScriptLoader return GetCaster()->GetTypeId() == TYPEID_PLAYER; } - bool Validate(SpellInfo const* spellEntry) + bool Validate(SpellInfo const* spellInfo) { - if (!sSpellMgr->GetSpellInfo(PRIEST_SPELL_PENANCE_R1)) + if (!sSpellMgr->GetSpellInfo(SPELL_PRIEST_PENANCE_R1)) return false; // can't use other spell than this penance due to spell_ranks dependency - if (sSpellMgr->GetFirstSpellInChain(PRIEST_SPELL_PENANCE_R1) != sSpellMgr->GetFirstSpellInChain(spellEntry->Id)) + if (sSpellMgr->GetFirstSpellInChain(SPELL_PRIEST_PENANCE_R1) != sSpellMgr->GetFirstSpellInChain(spellInfo->Id)) return false; - uint8 rank = sSpellMgr->GetSpellRank(spellEntry->Id); - if (!sSpellMgr->GetSpellWithRank(PRIEST_SPELL_PENANCE_R1_DAMAGE, rank, true)) + uint8 rank = sSpellMgr->GetSpellRank(spellInfo->Id); + if (!sSpellMgr->GetSpellWithRank(SPELL_PRIEST_PENANCE_R1_DAMAGE, rank, true)) return false; - if (!sSpellMgr->GetSpellWithRank(PRIEST_SPELL_PENANCE_R1_HEAL, rank, true)) + if (!sSpellMgr->GetSpellWithRank(SPELL_PRIEST_PENANCE_R1_HEAL, rank, true)) return false; return true; @@ -224,9 +408,9 @@ class spell_pri_penance : public SpellScriptLoader uint8 rank = sSpellMgr->GetSpellRank(GetSpellInfo()->Id); if (caster->IsFriendlyTo(unitTarget)) - caster->CastSpell(unitTarget, sSpellMgr->GetSpellWithRank(PRIEST_SPELL_PENANCE_R1_HEAL, rank), false, 0); + caster->CastSpell(unitTarget, sSpellMgr->GetSpellWithRank(SPELL_PRIEST_PENANCE_R1_HEAL, rank), false, 0); else - caster->CastSpell(unitTarget, sSpellMgr->GetSpellWithRank(PRIEST_SPELL_PENANCE_R1_DAMAGE, rank), false, 0); + caster->CastSpell(unitTarget, sSpellMgr->GetSpellWithRank(SPELL_PRIEST_PENANCE_R1_DAMAGE, rank), false, 0); } } @@ -241,7 +425,6 @@ class spell_pri_penance : public SpellScriptLoader void Register() { - // add dummy effect spell handler to Penance OnEffectHitTarget += SpellEffectFn(spell_pri_penance_SpellScript::HandleDummy, EFFECT_0, SPELL_EFFECT_DUMMY); OnCheckCast += SpellCheckCastFn(spell_pri_penance_SpellScript::CheckCast); } @@ -253,129 +436,118 @@ class spell_pri_penance : public SpellScriptLoader } }; -// Reflective Shield -class spell_pri_reflective_shield_trigger : public SpellScriptLoader +// -17 - Power Word: Shield +class spell_pri_power_word_shield : public SpellScriptLoader { public: - spell_pri_reflective_shield_trigger() : SpellScriptLoader("spell_pri_reflective_shield_trigger") { } + spell_pri_power_word_shield() : SpellScriptLoader("spell_pri_power_word_shield") { } - class spell_pri_reflective_shield_trigger_AuraScript : public AuraScript + class spell_pri_power_word_shield_AuraScript : public AuraScript { - PrepareAuraScript(spell_pri_reflective_shield_trigger_AuraScript); + PrepareAuraScript(spell_pri_power_word_shield_AuraScript); - bool Validate(SpellInfo const* /*spellEntry*/) + bool Validate(SpellInfo const* /*spellInfo*/) { - if (!sSpellMgr->GetSpellInfo(PRIEST_SPELL_REFLECTIVE_SHIELD_TRIGGERED) || !sSpellMgr->GetSpellInfo(PRIEST_SPELL_REFLECTIVE_SHIELD_R1)) + if (!sSpellMgr->GetSpellInfo(SPELL_PRIEST_REFLECTIVE_SHIELD_TRIGGERED)) + return false; + if (!sSpellMgr->GetSpellInfo(SPELL_PRIEST_REFLECTIVE_SHIELD_R1)) return false; return true; } - void Trigger(AuraEffect* aurEff, DamageInfo & dmgInfo, uint32 & absorbAmount) + void CalculateAmount(AuraEffect const* aurEff, int32& amount, bool& canBeRecalculated) + { + canBeRecalculated = false; + if (Unit* caster = GetCaster()) + { + // +80.68% from sp bonus + float bonus = 0.8068f; + + // Borrowed Time + if (AuraEffect const* borrowedTime = caster->GetDummyAuraEffect(SPELLFAMILY_PRIEST, PRIEST_ICON_ID_BORROWED_TIME, EFFECT_1)) + bonus += CalculatePct(1.0f, borrowedTime->GetAmount()); + + bonus *= caster->SpellBaseHealingBonusDone(GetSpellInfo()->GetSchoolMask()); + + // Improved PW: Shield: its weird having a SPELLMOD_ALL_EFFECTS here but its blizzards doing :) + // Improved PW: Shield is only applied at the spell healing bonus because it was already applied to the base value in CalculateSpellDamage + bonus = caster->ApplyEffectModifiers(GetSpellInfo(), aurEff->GetEffIndex(), bonus); + bonus *= caster->CalculateLevelPenalty(GetSpellInfo()); + + amount += int32(bonus); + + // Twin Disciplines + if (AuraEffect const* twinDisciplines = caster->GetAuraEffect(SPELL_AURA_ADD_PCT_MODIFIER, SPELLFAMILY_PRIEST, 0x400000, 0, 0, GetCasterGUID())) + AddPct(amount, twinDisciplines->GetAmount()); + + // Focused Power + amount *= caster->GetTotalAuraMultiplier(SPELL_AURA_MOD_HEALING_DONE_PERCENT); + } + } + + void ReflectDamage(AuraEffect* aurEff, DamageInfo& dmgInfo, uint32& absorbAmount) { Unit* target = GetTarget(); if (dmgInfo.GetAttacker() == target) return; - if (GetCaster()) - if (AuraEffect* talentAurEff = target->GetAuraEffectOfRankedSpell(PRIEST_SPELL_REFLECTIVE_SHIELD_R1, EFFECT_0)) + if (Unit* caster = GetCaster()) + if (AuraEffect* talentAurEff = caster->GetAuraEffectOfRankedSpell(SPELL_PRIEST_REFLECTIVE_SHIELD_R1, EFFECT_0)) { int32 bp = CalculatePct(absorbAmount, talentAurEff->GetAmount()); - target->CastCustomSpell(dmgInfo.GetAttacker(), PRIEST_SPELL_REFLECTIVE_SHIELD_TRIGGERED, &bp, NULL, NULL, true, NULL, aurEff); + target->CastCustomSpell(dmgInfo.GetAttacker(), SPELL_PRIEST_REFLECTIVE_SHIELD_TRIGGERED, &bp, NULL, NULL, true, NULL, aurEff); } } void Register() { - AfterEffectAbsorb += AuraEffectAbsorbFn(spell_pri_reflective_shield_trigger_AuraScript::Trigger, EFFECT_0); + DoEffectCalcAmount += AuraEffectCalcAmountFn(spell_pri_power_word_shield_AuraScript::CalculateAmount, EFFECT_0, SPELL_AURA_SCHOOL_ABSORB); + AfterEffectAbsorb += AuraEffectAbsorbFn(spell_pri_power_word_shield_AuraScript::ReflectDamage, EFFECT_0); } }; AuraScript* GetAuraScript() const { - return new spell_pri_reflective_shield_trigger_AuraScript(); + return new spell_pri_power_word_shield_AuraScript(); } }; -enum PrayerOfMending -{ - SPELL_T9_HEALING_2_PIECE = 67201, -}; -// Prayer of Mending Heal +// 33110 - Prayer of Mending Heal class spell_pri_prayer_of_mending_heal : public SpellScriptLoader { -public: - spell_pri_prayer_of_mending_heal() : SpellScriptLoader("spell_pri_prayer_of_mending_heal") { } - - class spell_pri_prayer_of_mending_heal_SpellScript : public SpellScript - { - PrepareSpellScript(spell_pri_prayer_of_mending_heal_SpellScript); - - void HandleHeal(SpellEffIndex /*effIndex*/) - { - if (Unit* caster = GetOriginalCaster()) - { - if (AuraEffect* aurEff = caster->GetAuraEffect(SPELL_T9_HEALING_2_PIECE, EFFECT_0)) - { - int32 heal = GetHitHeal(); - AddPct(heal, aurEff->GetAmount()); - SetHitHeal(heal); - } - } - - } - - void Register() - { - OnEffectHitTarget += SpellEffectFn(spell_pri_prayer_of_mending_heal_SpellScript::HandleHeal, EFFECT_0, SPELL_EFFECT_HEAL); - } - }; - - SpellScript* GetSpellScript() const - { - return new spell_pri_prayer_of_mending_heal_SpellScript(); - } -}; - -class spell_pri_vampiric_touch : public SpellScriptLoader -{ public: - spell_pri_vampiric_touch() : SpellScriptLoader("spell_pri_vampiric_touch") { } + spell_pri_prayer_of_mending_heal() : SpellScriptLoader("spell_pri_prayer_of_mending_heal") { } - class spell_pri_vampiric_touch_AuraScript : public AuraScript + class spell_pri_prayer_of_mending_heal_SpellScript : public SpellScript { - PrepareAuraScript(spell_pri_vampiric_touch_AuraScript); + PrepareSpellScript(spell_pri_prayer_of_mending_heal_SpellScript); - bool Validate(SpellInfo const* /*spell*/) + void HandleHeal(SpellEffIndex /*effIndex*/) { - if (!sSpellMgr->GetSpellInfo(PRIEST_SPELL_VAMPIRIC_TOUCH_DISPEL)) - return false; - return true; - } - - void HandleDispel(DispelInfo* /*dispelInfo*/) - { - if (Unit* caster = GetCaster()) - if (Unit* target = GetUnitOwner()) - if (AuraEffect const* aurEff = GetEffect(EFFECT_1)) - { - int32 damage = aurEff->GetAmount() * 8; - // backfire damage - caster->CastCustomSpell(target, PRIEST_SPELL_VAMPIRIC_TOUCH_DISPEL, &damage, NULL, NULL, true, NULL, aurEff); - } + if (Unit* caster = GetOriginalCaster()) + { + if (AuraEffect* aurEff = caster->GetAuraEffect(SPELL_PRIEST_T9_HEALING_2P, EFFECT_0)) + { + int32 heal = GetHitHeal(); + AddPct(heal, aurEff->GetAmount()); + SetHitHeal(heal); + } + } } void Register() { - AfterDispel += AuraDispelFn(spell_pri_vampiric_touch_AuraScript::HandleDispel); + OnEffectHitTarget += SpellEffectFn(spell_pri_prayer_of_mending_heal_SpellScript::HandleHeal, EFFECT_0, SPELL_EFFECT_HEAL); } }; - AuraScript* GetAuraScript() const + SpellScript* GetSpellScript() const { - return new spell_pri_vampiric_touch_AuraScript(); + return new spell_pri_prayer_of_mending_heal_SpellScript(); } }; +// -139 - Renew class spell_pri_renew : public SpellScriptLoader { public: @@ -401,7 +573,7 @@ class spell_pri_renew : public SpellScriptLoader heal = GetTarget()->SpellHealingBonusTaken(caster, GetSpellInfo(), heal, DOT); int32 basepoints0 = empoweredRenewAurEff->GetAmount() * GetEffect(EFFECT_0)->GetTotalTicks() * int32(heal) / 100; - caster->CastCustomSpell(GetTarget(), PRIEST_SPELL_EMPOWERED_RENEW, &basepoints0, NULL, NULL, true, NULL, aurEff); + caster->CastCustomSpell(GetTarget(), SPELL_PRIEST_EMPOWERED_RENEW, &basepoints0, NULL, NULL, true, NULL, aurEff); } } } @@ -418,6 +590,7 @@ class spell_pri_renew : public SpellScriptLoader } }; +// -32379 - Shadow Word Death class spell_pri_shadow_word_death : public SpellScriptLoader { public: @@ -435,7 +608,7 @@ class spell_pri_shadow_word_death : public SpellScriptLoader if (AuraEffect* aurEff = GetCaster()->GetDummyAuraEffect(SPELLFAMILY_PRIEST, PRIEST_ICON_ID_PAIN_AND_SUFFERING, EFFECT_1)) AddPct(damage, aurEff->GetAmount()); - GetCaster()->CastCustomSpell(GetCaster(), PRIEST_SHADOW_WORD_DEATH, &damage, 0, 0, true); + GetCaster()->CastCustomSpell(GetCaster(), SPELL_PRIEST_SHADOW_WORD_DEATH, &damage, 0, 0, true); } void Register() @@ -450,16 +623,61 @@ class spell_pri_shadow_word_death : public SpellScriptLoader } }; +// -34914 - Vampiric Touch +class spell_pri_vampiric_touch : public SpellScriptLoader +{ + public: + spell_pri_vampiric_touch() : SpellScriptLoader("spell_pri_vampiric_touch") { } + + class spell_pri_vampiric_touch_AuraScript : public AuraScript + { + PrepareAuraScript(spell_pri_vampiric_touch_AuraScript); + + bool Validate(SpellInfo const* /*spell*/) + { + if (!sSpellMgr->GetSpellInfo(SPELL_PRIEST_VAMPIRIC_TOUCH_DISPEL)) + return false; + return true; + } + + void HandleDispel(DispelInfo* /*dispelInfo*/) + { + if (Unit* caster = GetCaster()) + if (Unit* target = GetUnitOwner()) + if (AuraEffect const* aurEff = GetEffect(EFFECT_1)) + { + int32 damage = aurEff->GetAmount() * 8; + // backfire damage + caster->CastCustomSpell(target, SPELL_PRIEST_VAMPIRIC_TOUCH_DISPEL, &damage, NULL, NULL, true, NULL, aurEff); + } + } + + void Register() + { + AfterDispel += AuraDispelFn(spell_pri_vampiric_touch_AuraScript::HandleDispel); + } + }; + + AuraScript* GetAuraScript() const + { + return new spell_pri_vampiric_touch_AuraScript(); + } +}; + void AddSC_priest_spell_scripts() { + new spell_pri_divine_aegis(); + new spell_pri_glyph_of_prayer_of_healing(); new spell_pri_guardian_spirit(); + new spell_pri_lightwell_renew(); new spell_pri_mana_burn(); + new spell_pri_mana_leech(); + new spell_pri_mind_sear(); new spell_pri_pain_and_suffering_proc(); new spell_pri_penance(); - new spell_pri_reflective_shield_trigger(); - new spell_pri_mind_sear(); + new spell_pri_power_word_shield(); new spell_pri_prayer_of_mending_heal(); - new spell_pri_vampiric_touch(); new spell_pri_renew(); new spell_pri_shadow_word_death(); + new spell_pri_vampiric_touch(); } diff --git a/src/server/scripts/Spells/spell_quest.cpp b/src/server/scripts/Spells/spell_quest.cpp index 9cd94e9c7d5..3036c52876d 100644 --- a/src/server/scripts/Spells/spell_quest.cpp +++ b/src/server/scripts/Spells/spell_quest.cpp @@ -25,6 +25,7 @@ #include "ScriptMgr.h" #include "ScriptedCreature.h" #include "SpellScript.h" +#include "SpellAuras.h" #include "Vehicle.h" #include "GridNotifiers.h" #include "GridNotifiersImpl.h" @@ -1517,6 +1518,128 @@ class spell_q11010_q11102_q11023_q11008_check_fly_mount : public SpellScriptLoad } }; +enum SpellZuldrakRat +{ + SPELL_SUMMON_GORGED_LURKING_BASILISK = 50928 +}; + +class spell_q12527_zuldrak_rat : public SpellScriptLoader +{ + public: + spell_q12527_zuldrak_rat() : SpellScriptLoader("spell_q12527_zuldrak_rat") { } + + class spell_q12527_zuldrak_rat_SpellScript : public SpellScript + { + PrepareSpellScript(spell_q12527_zuldrak_rat_SpellScript); + + bool Validate(SpellInfo const* /*spell*/) + { + if (!sSpellMgr->GetSpellInfo(SPELL_SUMMON_GORGED_LURKING_BASILISK)) + return false; + return true; + } + + void HandleScriptEffect(SpellEffIndex /* effIndex */) + { + if (GetHitAura() && GetHitAura()->GetStackAmount() >= GetSpellInfo()->StackAmount) + { + GetHitUnit()->CastSpell((Unit*) NULL, SPELL_SUMMON_GORGED_LURKING_BASILISK, true); + if (Creature* basilisk = GetHitUnit()->ToCreature()) + basilisk->DespawnOrUnsummon(); + } + } + + void Register() + { + OnEffectHitTarget += SpellEffectFn(spell_q12527_zuldrak_rat_SpellScript::HandleScriptEffect, EFFECT_1, SPELL_EFFECT_SCRIPT_EFFECT); + } + }; + + SpellScript* GetSpellScript() const + { + return new spell_q12527_zuldrak_rat_SpellScript(); + } +}; + +// 13291 - Borrowed Technology/13292 - The Solution Solution /Daily//13239 - Volatility/13261 - Volatiliy /Daily// +enum Quest13291_13292_13239_13261Data +{ + // NPCs + NPC_SKYTALON = 31583, + NPC_DECOY = 31578, + // Spells + SPELL_RIDE = 56687 +}; + +class spell_q13291_q13292_q13239_q13261_frostbrood_skytalon_grab_decoy : public SpellScriptLoader +{ + public: + spell_q13291_q13292_q13239_q13261_frostbrood_skytalon_grab_decoy() : SpellScriptLoader("spell_q13291_q13292_q13239_q13261_frostbrood_skytalon_grab_decoy") { } + + class spell_q13291_q13292_q13239_q13261_frostbrood_skytalon_grab_decoy_SpellScript : public SpellScript + { + PrepareSpellScript(spell_q13291_q13292_q13239_q13261_frostbrood_skytalon_grab_decoy_SpellScript); + + bool Validate(SpellInfo const* /*spell*/) + { + if (!sSpellMgr->GetSpellInfo(SPELL_RIDE)) + return false; + + return true; + } + + void HandleDummy(SpellEffIndex /*effIndex*/) + { + if (!GetHitCreature()) + return; + // TO DO: Being triggered is hack, but in checkcast it doesn't pass aurastate requirements. + // Beside that the decoy won't keep it's freeze animation state when enter. + GetHitCreature()->CastSpell(GetCaster(), SPELL_RIDE, true); + } + + void Register() + { + OnEffectHitTarget += SpellEffectFn(spell_q13291_q13292_q13239_q13261_frostbrood_skytalon_grab_decoy_SpellScript::HandleDummy, EFFECT_0, SPELL_EFFECT_DUMMY); + } + }; + + SpellScript* GetSpellScript() const + { + return new spell_q13291_q13292_q13239_q13261_frostbrood_skytalon_grab_decoy_SpellScript(); + } +}; + +class spell_q13291_q13292_q13239_q13261_armored_decoy_summon_skytalon : public SpellScriptLoader +{ + public: + spell_q13291_q13292_q13239_q13261_armored_decoy_summon_skytalon() : SpellScriptLoader("spell_q13291_q13292_q13239_q13261_armored_decoy_summon_skytalon") { } + + class spell_q13291_q13292_q13239_q13261_armored_decoy_summon_skytalon_SpellScript : public SpellScript + { + PrepareSpellScript(spell_q13291_q13292_q13239_q13261_armored_decoy_summon_skytalon_SpellScript); + + void ChangeSummonPos(SpellEffIndex /*effIndex*/) + { + // Adjust effect summon position + WorldLocation summonPos = *GetExplTargetDest(); + Position offset = { 0.0f, 0.0f, 20.0f, 0.0f }; + summonPos.RelocateOffset(offset); + SetExplTargetDest(summonPos); + GetHitDest()->RelocateOffset(offset); + } + + void Register() + { + OnEffectHit += SpellEffectFn(spell_q13291_q13292_q13239_q13261_armored_decoy_summon_skytalon_SpellScript::ChangeSummonPos, EFFECT_0, SPELL_EFFECT_SUMMON); + } + }; + + SpellScript* GetSpellScript() const + { + return new spell_q13291_q13292_q13239_q13261_armored_decoy_summon_skytalon_SpellScript(); + } +}; + void AddSC_quest_spell_scripts() { new spell_q55_sacred_cleansing(); @@ -1554,4 +1677,7 @@ void AddSC_quest_spell_scripts() new spell_q11010_q11102_q11023_choose_loc(); new spell_q11010_q11102_q11023_q11008_check_fly_mount(); new spell_q12372_azure_on_death_force_whisper(); + new spell_q12527_zuldrak_rat(); + new spell_q13291_q13292_q13239_q13261_frostbrood_skytalon_grab_decoy(); + new spell_q13291_q13292_q13239_q13261_armored_decoy_summon_skytalon(); } diff --git a/src/server/scripts/Spells/spell_rogue.cpp b/src/server/scripts/Spells/spell_rogue.cpp index ad69b4b1026..f6391c80d63 100644 --- a/src/server/scripts/Spells/spell_rogue.cpp +++ b/src/server/scripts/Spells/spell_rogue.cpp @@ -28,13 +28,71 @@ enum RogueSpells { - ROGUE_SPELL_SHIV_TRIGGERED = 5940, - ROGUE_SPELL_GLYPH_OF_PREPARATION = 56819, - ROGUE_SPELL_PREY_ON_THE_WEAK = 58670, - ROGUE_SPELL_CHEAT_DEATH_COOLDOWN = 31231, + SPELL_ROGUE_BLADE_FLURRY_EXTRA_ATTACK = 22482, + SPELL_ROGUE_CHEAT_DEATH_COOLDOWN = 31231, + SPELL_ROGUE_GLYPH_OF_PREPARATION = 56819, + SPELL_ROGUE_PREY_ON_THE_WEAK = 58670, + SPELL_ROGUE_SHIV_TRIGGERED = 5940, + SPELL_ROGUE_TRICKS_OF_THE_TRADE_DMG_BOOST = 57933, + SPELL_ROGUE_TRICKS_OF_THE_TRADE_PROC = 59628, }; -// Cheat Death +// 13877, 33735, (check 51211, 65956) - Blade Flurry +class spell_rog_blade_flurry : public SpellScriptLoader +{ + public: + spell_rog_blade_flurry() : SpellScriptLoader("spell_rog_blade_flurry") { } + + class spell_rog_blade_flurry_AuraScript : public AuraScript + { + PrepareAuraScript(spell_rog_blade_flurry_AuraScript); + + bool Validate(SpellInfo const* /*spellInfo*/) + { + if (!sSpellMgr->GetSpellInfo(SPELL_ROGUE_BLADE_FLURRY_EXTRA_ATTACK)) + return false; + return true; + } + + bool Load() + { + _procTarget = NULL; + return true; + } + + bool CheckProc(ProcEventInfo& eventInfo) + { + _procTarget = eventInfo.GetActor()->SelectNearbyTarget(eventInfo.GetProcTarget()); + return _procTarget; + } + + void HandleProc(AuraEffect const* aurEff, ProcEventInfo& eventInfo) + { + PreventDefaultAction(); + if (eventInfo.GetDamageInfo()) + { + int32 damage = eventInfo.GetDamageInfo()->GetDamage(); + GetTarget()->CastCustomSpell(SPELL_ROGUE_BLADE_FLURRY_EXTRA_ATTACK, SPELLVALUE_BASE_POINT0, damage, _procTarget, true, NULL, aurEff); + } + } + + void Register() + { + DoCheckProc += AuraCheckProcFn(spell_rog_blade_flurry_AuraScript::CheckProc); + OnEffectProc += AuraEffectProcFn(spell_rog_blade_flurry_AuraScript::HandleProc, EFFECT_0, SPELL_AURA_MOD_MELEE_HASTE); + } + + private: + Unit* _procTarget; + }; + + AuraScript* GetAuraScript() const + { + return new spell_rog_blade_flurry_AuraScript(); + } +}; + +// -31228 - Cheat Death class spell_rog_cheat_death : public SpellScriptLoader { public: @@ -46,9 +104,9 @@ class spell_rog_cheat_death : public SpellScriptLoader uint32 absorbChance; - bool Validate(SpellInfo const* /*spellEntry*/) + bool Validate(SpellInfo const* /*spellInfo*/) { - if (!sSpellMgr->GetSpellInfo(ROGUE_SPELL_CHEAT_DEATH_COOLDOWN)) + if (!sSpellMgr->GetSpellInfo(SPELL_ROGUE_CHEAT_DEATH_COOLDOWN)) return false; return true; } @@ -68,11 +126,11 @@ class spell_rog_cheat_death : public SpellScriptLoader void Absorb(AuraEffect* /*aurEff*/, DamageInfo & dmgInfo, uint32 & absorbAmount) { Player* target = GetTarget()->ToPlayer(); - if (dmgInfo.GetDamage() < target->GetHealth() || target->HasSpellCooldown(ROGUE_SPELL_CHEAT_DEATH_COOLDOWN) || !roll_chance_i(absorbChance)) + if (dmgInfo.GetDamage() < target->GetHealth() || target->HasSpellCooldown(SPELL_ROGUE_CHEAT_DEATH_COOLDOWN) || !roll_chance_i(absorbChance)) return; - target->CastSpell(target, ROGUE_SPELL_CHEAT_DEATH_COOLDOWN, true); - target->AddSpellCooldown(ROGUE_SPELL_CHEAT_DEATH_COOLDOWN, 0, time(NULL) + 60); + target->CastSpell(target, SPELL_ROGUE_CHEAT_DEATH_COOLDOWN, true); + target->AddSpellCooldown(SPELL_ROGUE_CHEAT_DEATH_COOLDOWN, 0, time(NULL) + 60); uint32 health10 = target->CountPctFromMaxHealth(10); @@ -97,7 +155,101 @@ class spell_rog_cheat_death : public SpellScriptLoader } }; -// 31130 - Nerves of Steel +// -2818 - Deadly Poison +class spell_rog_deadly_poison : public SpellScriptLoader +{ + public: + spell_rog_deadly_poison() : SpellScriptLoader("spell_rog_deadly_poison") { } + + class spell_rog_deadly_poison_SpellScript : public SpellScript + { + PrepareSpellScript(spell_rog_deadly_poison_SpellScript); + + bool Load() + { + _stackAmount = 0; + // at this point CastItem must already be initialized + return GetCaster()->GetTypeId() == TYPEID_PLAYER && GetCastItem(); + } + + void HandleBeforeHit() + { + if (Unit* target = GetHitUnit()) + // Deadly Poison + if (AuraEffect const* aurEff = target->GetAuraEffect(SPELL_AURA_PERIODIC_DAMAGE, SPELLFAMILY_ROGUE, 0x10000, 0x80000, 0, GetCaster()->GetGUID())) + _stackAmount = aurEff->GetBase()->GetStackAmount(); + } + + void HandleAfterHit() + { + if (_stackAmount < 5) + return; + + Player* player = GetCaster()->ToPlayer(); + + if (Unit* target = GetHitUnit()) + { + + Item* item = player->GetItemByPos(INVENTORY_SLOT_BAG_0, EQUIPMENT_SLOT_MAINHAND); + + if (item == GetCastItem()) + item = player->GetItemByPos(INVENTORY_SLOT_BAG_0, EQUIPMENT_SLOT_OFFHAND); + + if (!item) + return; + + // item combat enchantments + for (uint8 slot = 0; slot < MAX_ENCHANTMENT_SLOT; ++slot) + { + SpellItemEnchantmentEntry const* enchant = sSpellItemEnchantmentStore.LookupEntry(item->GetEnchantmentId(EnchantmentSlot(slot))); + if (!enchant) + continue; + + for (uint8 s = 0; s < 3; ++s) + { + if (enchant->type[s] != ITEM_ENCHANTMENT_TYPE_COMBAT_SPELL) + continue; + + SpellInfo const* spellInfo = sSpellMgr->GetSpellInfo(enchant->spellid[s]); + if (!spellInfo) + { + sLog->outError(LOG_FILTER_SPELLS_AURAS, "Player::CastItemCombatSpell Enchant %i, player (Name: %s, GUID: %u) cast unknown spell %i", enchant->ID, player->GetName().c_str(), player->GetGUIDLow(), enchant->spellid[s]); + continue; + } + + // Proc only rogue poisons + if (spellInfo->SpellFamilyName != SPELLFAMILY_ROGUE || spellInfo->Dispel != DISPEL_POISON) + continue; + + // Do not reproc deadly + if (spellInfo->SpellFamilyFlags.IsEqual(0x10000, 0x80000, 0)) + continue; + + if (spellInfo->IsPositive()) + player->CastSpell(player, enchant->spellid[s], true, item); + else + player->CastSpell(target, enchant->spellid[s], true, item); + } + } + } + } + + void Register() + { + BeforeHit += SpellHitFn(spell_rog_deadly_poison_SpellScript::HandleBeforeHit); + AfterHit += SpellHitFn(spell_rog_deadly_poison_SpellScript::HandleAfterHit); + } + + uint8 _stackAmount; + }; + + SpellScript* GetSpellScript() const + { + return new spell_rog_deadly_poison_SpellScript(); + } +}; + +// -31130 - Nerves of Steel class spell_rog_nerves_of_steel : public SpellScriptLoader { public: @@ -141,6 +293,7 @@ class spell_rog_nerves_of_steel : public SpellScriptLoader } }; +// 14185 - Preparation class spell_rog_preparation : public SpellScriptLoader { public: @@ -155,9 +308,9 @@ class spell_rog_preparation : public SpellScriptLoader return GetCaster()->GetTypeId() == TYPEID_PLAYER; } - bool Validate(SpellInfo const* /*spellEntry*/) + bool Validate(SpellInfo const* /*spellInfo*/) { - if (!sSpellMgr->GetSpellInfo(ROGUE_SPELL_GLYPH_OF_PREPARATION)) + if (!sSpellMgr->GetSpellInfo(SPELL_ROGUE_GLYPH_OF_PREPARATION)) return false; return true; } @@ -177,7 +330,7 @@ class spell_rog_preparation : public SpellScriptLoader if (spellInfo->SpellFamilyFlags[1] & SPELLFAMILYFLAG1_ROGUE_COLDB_SHADOWSTEP || // Cold Blood, Shadowstep spellInfo->SpellFamilyFlags[0] & SPELLFAMILYFLAG_ROGUE_VAN_EVAS_SPRINT) // Vanish, Evasion, Sprint caster->RemoveSpellCooldown((itr++)->first, true); - else if (caster->HasAura(ROGUE_SPELL_GLYPH_OF_PREPARATION)) + else if (caster->HasAura(SPELL_ROGUE_GLYPH_OF_PREPARATION)) { if (spellInfo->SpellFamilyFlags[1] & SPELLFAMILYFLAG1_ROGUE_DISMANTLE || // Dismantle spellInfo->SpellFamilyFlags[0] & SPELLFAMILYFLAG_ROGUE_KICK || // Kick @@ -197,7 +350,6 @@ class spell_rog_preparation : public SpellScriptLoader void Register() { - // add dummy effect spell handler to Preparation OnEffectHitTarget += SpellEffectFn(spell_rog_preparation_SpellScript::HandleDummy, EFFECT_0, SPELL_EFFECT_DUMMY); } }; @@ -208,51 +360,104 @@ class spell_rog_preparation : public SpellScriptLoader } }; -// 51685-51689 Prey on the Weak +// -51685 - Prey on the Weak class spell_rog_prey_on_the_weak : public SpellScriptLoader { -public: - spell_rog_prey_on_the_weak() : SpellScriptLoader("spell_rog_prey_on_the_weak") { } + public: + spell_rog_prey_on_the_weak() : SpellScriptLoader("spell_rog_prey_on_the_weak") { } - class spell_rog_prey_on_the_weak_AuraScript : public AuraScript - { - PrepareAuraScript(spell_rog_prey_on_the_weak_AuraScript); + class spell_rog_prey_on_the_weak_AuraScript : public AuraScript + { + PrepareAuraScript(spell_rog_prey_on_the_weak_AuraScript); + + bool Validate(SpellInfo const* /*spellInfo*/) + { + if (!sSpellMgr->GetSpellInfo(SPELL_ROGUE_PREY_ON_THE_WEAK)) + return false; + return true; + } - bool Validate(SpellInfo const* /*spellEntry*/) + void HandleEffectPeriodic(AuraEffect const* /*aurEff*/) + { + Unit* target = GetTarget(); + Unit* victim = target->getVictim(); + if (victim && (target->GetHealthPct() > victim->GetHealthPct())) + { + if (!target->HasAura(SPELL_ROGUE_PREY_ON_THE_WEAK)) + { + int32 bp = GetSpellInfo()->Effects[EFFECT_0].CalcValue(); + target->CastCustomSpell(target, SPELL_ROGUE_PREY_ON_THE_WEAK, &bp, 0, 0, true); + } + } + else + target->RemoveAurasDueToSpell(SPELL_ROGUE_PREY_ON_THE_WEAK); + } + + void Register() + { + OnEffectPeriodic += AuraEffectPeriodicFn(spell_rog_prey_on_the_weak_AuraScript::HandleEffectPeriodic, EFFECT_0, SPELL_AURA_PERIODIC_DUMMY); + } + }; + + AuraScript* GetAuraScript() const { - if (!sSpellMgr->GetSpellInfo(ROGUE_SPELL_PREY_ON_THE_WEAK)) - return false; - return true; + return new spell_rog_prey_on_the_weak_AuraScript(); } +}; + +// -1943 - Rupture +class spell_rog_rupture : public SpellScriptLoader +{ + public: + spell_rog_rupture() : SpellScriptLoader("spell_rog_rupture") { } - void HandleEffectPeriodic(AuraEffect const* /*aurEff*/) + class spell_rog_rupture_AuraScript : public AuraScript { - Unit* target = GetTarget(); - Unit* victim = target->getVictim(); - if (victim && (target->GetHealthPct() > victim->GetHealthPct())) + PrepareAuraScript(spell_rog_rupture_AuraScript); + + bool Load() + { + Unit* caster = GetCaster(); + return caster && caster->GetTypeId() == TYPEID_PLAYER; + } + + void CalculateAmount(AuraEffect const* /*aurEff*/, int32& amount, bool& canBeRecalculated) { - if (!target->HasAura(ROGUE_SPELL_PREY_ON_THE_WEAK)) + if (Unit* caster = GetCaster()) { - int32 bp = GetSpellInfo()->Effects[EFFECT_0].CalcValue(); - target->CastCustomSpell(target, ROGUE_SPELL_PREY_ON_THE_WEAK, &bp, 0, 0, true); + canBeRecalculated = false; + + float const attackpowerPerCombo[6] = + { + 0.0f, + 0.015f, // 1 point: ${($m1 + $b1*1 + 0.015 * $AP) * 4} damage over 8 secs + 0.024f, // 2 points: ${($m1 + $b1*2 + 0.024 * $AP) * 5} damage over 10 secs + 0.03f, // 3 points: ${($m1 + $b1*3 + 0.03 * $AP) * 6} damage over 12 secs + 0.03428571f, // 4 points: ${($m1 + $b1*4 + 0.03428571 * $AP) * 7} damage over 14 secs + 0.0375f // 5 points: ${($m1 + $b1*5 + 0.0375 * $AP) * 8} damage over 16 secs + }; + + uint8 cp = caster->ToPlayer()->GetComboPoints(); + if (cp > 5) + cp = 5; + + amount += int32(caster->GetTotalAttackPowerValue(BASE_ATTACK) * attackpowerPerCombo[cp]); } } - else - target->RemoveAurasDueToSpell(ROGUE_SPELL_PREY_ON_THE_WEAK); - } - void Register() + void Register() + { + DoEffectCalcAmount += AuraEffectCalcAmountFn(spell_rog_rupture_AuraScript::CalculateAmount, EFFECT_0, SPELL_AURA_PERIODIC_DAMAGE); + } + }; + + AuraScript* GetAuraScript() const { - OnEffectPeriodic += AuraEffectPeriodicFn(spell_rog_prey_on_the_weak_AuraScript::HandleEffectPeriodic, EFFECT_0, SPELL_AURA_PERIODIC_DUMMY); + return new spell_rog_rupture_AuraScript(); } - }; - - AuraScript* GetAuraScript() const - { - return new spell_rog_prey_on_the_weak_AuraScript(); - } }; +// 5938 - Shiv class spell_rog_shiv : public SpellScriptLoader { public: @@ -267,9 +472,9 @@ class spell_rog_shiv : public SpellScriptLoader return GetCaster()->GetTypeId() == TYPEID_PLAYER; } - bool Validate(SpellInfo const* /*spellEntry*/) + bool Validate(SpellInfo const* /*spellInfo*/) { - if (!sSpellMgr->GetSpellInfo(ROGUE_SPELL_SHIV_TRIGGERED)) + if (!sSpellMgr->GetSpellInfo(SPELL_ROGUE_SHIV_TRIGGERED)) return false; return true; } @@ -278,12 +483,11 @@ class spell_rog_shiv : public SpellScriptLoader { Unit* caster = GetCaster(); if (Unit* unitTarget = GetHitUnit()) - caster->CastSpell(unitTarget, ROGUE_SPELL_SHIV_TRIGGERED, true); + caster->CastSpell(unitTarget, SPELL_ROGUE_SHIV_TRIGGERED, true); } void Register() { - // add dummy effect spell handler to Shiv OnEffectHitTarget += SpellEffectFn(spell_rog_shiv_SpellScript::HandleDummy, EFFECT_0, SPELL_EFFECT_DUMMY); } }; @@ -294,134 +498,107 @@ class spell_rog_shiv : public SpellScriptLoader } }; -class spell_rog_deadly_poison : public SpellScriptLoader +// 57934 - Tricks of the Trade +class spell_rog_tricks_of_the_trade : public SpellScriptLoader { public: - spell_rog_deadly_poison() : SpellScriptLoader("spell_rog_deadly_poison") { } + spell_rog_tricks_of_the_trade() : SpellScriptLoader("spell_rog_tricks_of_the_trade") { } - class spell_rog_deadly_poison_SpellScript : public SpellScript + class spell_rog_tricks_of_the_trade_AuraScript : public AuraScript { - PrepareSpellScript(spell_rog_deadly_poison_SpellScript); + PrepareAuraScript(spell_rog_tricks_of_the_trade_AuraScript); - bool Load() + bool Validate(SpellInfo const* /*spellInfo*/) { - _stackAmount = 0; - // at this point CastItem must already be initialized - return GetCaster()->GetTypeId() == TYPEID_PLAYER && GetCastItem(); + if (!sSpellMgr->GetSpellInfo(SPELL_ROGUE_TRICKS_OF_THE_TRADE_DMG_BOOST)) + return false; + if (!sSpellMgr->GetSpellInfo(SPELL_ROGUE_TRICKS_OF_THE_TRADE_PROC)) + return false; + return true; } - void HandleBeforeHit() + bool Load() { - if (Unit* target = GetHitUnit()) - // Deadly Poison - if (AuraEffect const* aurEff = target->GetAuraEffect(SPELL_AURA_PERIODIC_DAMAGE, SPELLFAMILY_ROGUE, 0x10000, 0x80000, 0, GetCaster()->GetGUID())) - _stackAmount = aurEff->GetBase()->GetStackAmount(); + _redirectTarget = NULL; + return true; } - void HandleAfterHit() + void OnRemove(AuraEffect const* /*aurEff*/, AuraEffectHandleModes /*mode*/) { - if (_stackAmount < 5) - return; - - Player* player = GetCaster()->ToPlayer(); - - if (Unit* target = GetHitUnit()) - { - - Item* item = player->GetItemByPos(INVENTORY_SLOT_BAG_0, EQUIPMENT_SLOT_MAINHAND); - - if (item == GetCastItem()) - item = player->GetItemByPos(INVENTORY_SLOT_BAG_0, EQUIPMENT_SLOT_OFFHAND); - - if (!item) - return; - - // item combat enchantments - for (uint8 slot = 0; slot < MAX_ENCHANTMENT_SLOT; ++slot) - { - SpellItemEnchantmentEntry const* enchant = sSpellItemEnchantmentStore.LookupEntry(item->GetEnchantmentId(EnchantmentSlot(slot))); - if (!enchant) - continue; - - for (uint8 s = 0; s < 3; ++s) - { - if (enchant->type[s] != ITEM_ENCHANTMENT_TYPE_COMBAT_SPELL) - continue; - - SpellInfo const* spellInfo = sSpellMgr->GetSpellInfo(enchant->spellid[s]); - if (!spellInfo) - { - sLog->outError(LOG_FILTER_SPELLS_AURAS, "Player::CastItemCombatSpell Enchant %i, player (Name: %s, GUID: %u) cast unknown spell %i", enchant->ID, player->GetName().c_str(), player->GetGUIDLow(), enchant->spellid[s]); - continue; - } + if (GetTargetApplication()->GetRemoveMode() != AURA_REMOVE_BY_DEFAULT) + GetTarget()->ResetRedirectThreat(); + } - // Proc only rogue poisons - if (spellInfo->SpellFamilyName != SPELLFAMILY_ROGUE || spellInfo->Dispel != DISPEL_POISON) - continue; + bool CheckProc(ProcEventInfo& /*eventInfo*/) + { + _redirectTarget = GetTarget()->GetRedirectThreatTarget(); + return _redirectTarget; + } - // Do not reproc deadly - if (spellInfo->SpellFamilyFlags.IsEqual(0x10000, 0x80000, 0)) - continue; + void HandleProc(AuraEffect const* /*aurEff*/, ProcEventInfo& /*eventInfo*/) + { + PreventDefaultAction(); - if (spellInfo->IsPositive()) - player->CastSpell(player, enchant->spellid[s], true, item); - else - player->CastSpell(target, enchant->spellid[s], true, item); - } - } - } + Unit* target = GetTarget(); + target->CastSpell(_redirectTarget, SPELL_ROGUE_TRICKS_OF_THE_TRADE_DMG_BOOST, true); + target->CastSpell(target, SPELL_ROGUE_TRICKS_OF_THE_TRADE_PROC, true); + Remove(AURA_REMOVE_BY_DEFAULT); // maybe handle by proc charges } void Register() { - BeforeHit += SpellHitFn(spell_rog_deadly_poison_SpellScript::HandleBeforeHit); - AfterHit += SpellHitFn(spell_rog_deadly_poison_SpellScript::HandleAfterHit); + AfterEffectRemove += AuraEffectRemoveFn(spell_rog_tricks_of_the_trade_AuraScript::OnRemove, EFFECT_1, SPELL_AURA_DUMMY, AURA_EFFECT_HANDLE_REAL); + DoCheckProc += AuraCheckProcFn(spell_rog_tricks_of_the_trade_AuraScript::CheckProc); + OnEffectProc += AuraEffectProcFn(spell_rog_tricks_of_the_trade_AuraScript::HandleProc, EFFECT_1, SPELL_AURA_DUMMY); } - uint8 _stackAmount; + private: + Unit* _redirectTarget; }; - SpellScript* GetSpellScript() const + AuraScript* GetAuraScript() const { - return new spell_rog_deadly_poison_SpellScript(); + return new spell_rog_tricks_of_the_trade_AuraScript(); } }; -class spell_rog_shadowstep : public SpellScriptLoader +// 59628 - Tricks of the Trade (Proc) +class spell_rog_tricks_of_the_trade_proc : public SpellScriptLoader { public: - spell_rog_shadowstep() : SpellScriptLoader("spell_rog_shadowstep") { } + spell_rog_tricks_of_the_trade_proc() : SpellScriptLoader("spell_rog_tricks_of_the_trade_proc") { } - class spell_rog_shadowstep_SpellScript : public SpellScript + class spell_rog_tricks_of_the_trade_proc_AuraScript : public AuraScript { - PrepareSpellScript(spell_rog_shadowstep_SpellScript); + PrepareAuraScript(spell_rog_tricks_of_the_trade_proc_AuraScript); - SpellCastResult CheckCast() + void HandleRemove(AuraEffect const* /*aurEff*/, AuraEffectHandleModes /*mode*/) { - if (GetCaster()->HasUnitState(UNIT_STATE_ROOT)) - return SPELL_FAILED_ROOTED; - return SPELL_CAST_OK; + GetTarget()->ResetRedirectThreat(); } void Register() { - OnCheckCast += SpellCheckCastFn(spell_rog_shadowstep_SpellScript::CheckCast); + AfterEffectRemove += AuraEffectRemoveFn(spell_rog_tricks_of_the_trade_proc_AuraScript::HandleRemove, EFFECT_0, SPELL_AURA_DUMMY, AURA_EFFECT_HANDLE_REAL); } }; - SpellScript* GetSpellScript() const + AuraScript* GetAuraScript() const { - return new spell_rog_shadowstep_SpellScript(); + return new spell_rog_tricks_of_the_trade_proc_AuraScript(); } }; void AddSC_rogue_spell_scripts() { + new spell_rog_blade_flurry(); new spell_rog_cheat_death(); + new spell_rog_deadly_poison(); new spell_rog_nerves_of_steel(); new spell_rog_preparation(); new spell_rog_prey_on_the_weak(); + new spell_rog_rupture(); new spell_rog_shiv(); - new spell_rog_deadly_poison(); - new spell_rog_shadowstep(); + new spell_rog_tricks_of_the_trade(); + new spell_rog_tricks_of_the_trade_proc(); } diff --git a/src/server/scripts/Spells/spell_shaman.cpp b/src/server/scripts/Spells/spell_shaman.cpp index ff7c83b95a5..f970807bb94 100644 --- a/src/server/scripts/Spells/spell_shaman.cpp +++ b/src/server/scripts/Spells/spell_shaman.cpp @@ -30,28 +30,72 @@ enum ShamanSpells { - SHAMAN_SPELL_GLYPH_OF_MANA_TIDE = 55441, - SHAMAN_SPELL_MANA_TIDE_TOTEM = 39609, - SHAMAN_SPELL_FIRE_NOVA_R1 = 1535, - SHAMAN_SPELL_FIRE_NOVA_TRIGGERED_R1 = 8349, - SHAMAN_SPELL_SATED = 57724, - SHAMAN_SPELL_EXHAUSTION = 57723, + SPELL_SHAMAN_ANCESTRAL_AWAKENING_PROC = 52752, + SPELL_SHAMAN_BIND_SIGHT = 6277, + SPELL_SHAMAN_CLEANSING_TOTEM_EFFECT = 52025, + SPELL_SHAMAN_EARTH_SHIELD_HEAL = 379, + SPELL_SHAMAN_EXHAUSTION = 57723, + SPELL_SHAMAN_FIRE_NOVA_R1 = 1535, + SPELL_SHAMAN_FIRE_NOVA_TRIGGERED_R1 = 8349, + SPELL_SHAMAN_GLYPH_OF_EARTH_SHIELD = 63279, + SPELL_SHAMAN_GLYPH_OF_HEALING_STREAM_TOTEM = 55456, + SPELL_SHAMAN_GLYPH_OF_MANA_TIDE = 55441, + SPELL_SHAMAN_GLYPH_OF_THUNDERSTORM = 62132, + SPELL_SHAMAN_LAVA_FLOWS_R1 = 51480, + SPELL_SHAMAN_LAVA_FLOWS_TRIGGERED_R1 = 64694, + SPELL_SHAMAN_MANA_SPRING_TOTEM_ENERGIZE = 52032, + SPELL_SHAMAN_MANA_TIDE_TOTEM = 39609, + SPELL_SHAMAN_SATED = 57724, + SPELL_SHAMAN_STORM_EARTH_AND_FIRE = 51483, + SPELL_SHAMAN_TOTEM_EARTHBIND_EARTHGRAB = 64695, + SPELL_SHAMAN_TOTEM_EARTHBIND_TOTEM = 6474, + SPELL_SHAMAN_TOTEM_EARTHEN_POWER = 59566, + SPELL_SHAMAN_TOTEM_HEALING_STREAM_HEAL = 52042 +}; + +enum ShamanSpellIcons +{ + SHAMAN_ICON_ID_RESTORATIVE_TOTEMS = 338, + SHAMAN_ICON_ID_SHAMAN_LAVA_FLOW = 3087 +}; + +// 52759 - Ancestral Awakening (Proc) +class spell_sha_ancestral_awakening_proc : public SpellScriptLoader +{ + public: + spell_sha_ancestral_awakening_proc() : SpellScriptLoader("spell_sha_ancestral_awakening_proc") { } - SHAMAN_SPELL_STORM_EARTH_AND_FIRE = 51483, - EARTHBIND_TOTEM_SPELL_EARTHGRAB = 64695, + class spell_sha_ancestral_awakening_proc_SpellScript : public SpellScript + { + PrepareSpellScript(spell_sha_ancestral_awakening_proc_SpellScript); + + bool Validate(SpellInfo const* /*spellInfo*/) + { + if (!sSpellMgr->GetSpellInfo(SPELL_SHAMAN_ANCESTRAL_AWAKENING_PROC)) + return false; + return true; + } - // For Earthen Power - SHAMAN_TOTEM_SPELL_EARTHBIND_TOTEM = 6474, - SHAMAN_TOTEM_SPELL_EARTHEN_POWER = 59566, + void HandleDummy(SpellEffIndex /*effIndex*/) + { + int32 damage = GetEffectValue(); + if (GetHitUnit()) + GetCaster()->CastCustomSpell(GetHitUnit(), SPELL_SHAMAN_ANCESTRAL_AWAKENING_PROC, &damage, NULL, NULL, true); + } - SHAMAN_BIND_SIGHT = 6277, + void Register() + { + OnEffectHitTarget += SpellEffectFn(spell_sha_ancestral_awakening_proc_SpellScript::HandleDummy, EFFECT_0, SPELL_EFFECT_DUMMY); + } + }; - ICON_ID_SHAMAN_LAVA_FLOW = 3087, - SHAMAN_LAVA_FLOWS_R1 = 51480, - SHAMAN_LAVA_FLOWS_TRIGGERED_R1 = 64694, + SpellScript* GetSpellScript() const + { + return new spell_sha_ancestral_awakening_proc_SpellScript(); + } }; -// 51474 - Astral shift +// 51474 - Astral Shift class spell_sha_astral_shift : public SpellScriptLoader { public: @@ -95,115 +139,198 @@ class spell_sha_astral_shift : public SpellScriptLoader } }; -// 1535 Fire Nova -class spell_sha_fire_nova : public SpellScriptLoader +// 2825 - Bloodlust +class spell_sha_bloodlust : public SpellScriptLoader { public: - spell_sha_fire_nova() : SpellScriptLoader("spell_sha_fire_nova") { } + spell_sha_bloodlust() : SpellScriptLoader("spell_sha_bloodlust") { } - class spell_sha_fire_nova_SpellScript : public SpellScript + class spell_sha_bloodlust_SpellScript : public SpellScript { - PrepareSpellScript(spell_sha_fire_nova_SpellScript); + PrepareSpellScript(spell_sha_bloodlust_SpellScript); - bool Validate(SpellInfo const* spellEntry) + bool Validate(SpellInfo const* /*spellInfo*/) { - if (!sSpellMgr->GetSpellInfo(SHAMAN_SPELL_FIRE_NOVA_R1) || sSpellMgr->GetFirstSpellInChain(SHAMAN_SPELL_FIRE_NOVA_R1) != sSpellMgr->GetFirstSpellInChain(spellEntry->Id)) - return false; - - uint8 rank = sSpellMgr->GetSpellRank(spellEntry->Id); - if (!sSpellMgr->GetSpellWithRank(SHAMAN_SPELL_FIRE_NOVA_TRIGGERED_R1, rank, true)) + if (!sSpellMgr->GetSpellInfo(SPELL_SHAMAN_SATED)) return false; return true; } - SpellCastResult CheckFireTotem() + void RemoveInvalidTargets(std::list<WorldObject*>& targets) { - // fire totem - if (!GetCaster()->m_SummonSlot[1]) - { - SetCustomCastResultMessage(SPELL_CUSTOM_ERROR_MUST_HAVE_FIRE_TOTEM); - return SPELL_FAILED_CUSTOM_ERROR; - } + targets.remove_if(Trinity::UnitAuraCheck(true, SPELL_SHAMAN_SATED)); + } - return SPELL_CAST_OK; + void ApplyDebuff() + { + if (Unit* target = GetHitUnit()) + target->CastSpell(target, SPELL_SHAMAN_SATED, true); } - void HandleDummy(SpellEffIndex /*effIndex*/) + void Register() { - if (Unit* caster = GetCaster()) + OnObjectAreaTargetSelect += SpellObjectAreaTargetSelectFn(spell_sha_bloodlust_SpellScript::RemoveInvalidTargets, EFFECT_0, TARGET_UNIT_CASTER_AREA_RAID); + OnObjectAreaTargetSelect += SpellObjectAreaTargetSelectFn(spell_sha_bloodlust_SpellScript::RemoveInvalidTargets, EFFECT_1, TARGET_UNIT_CASTER_AREA_RAID); + OnObjectAreaTargetSelect += SpellObjectAreaTargetSelectFn(spell_sha_bloodlust_SpellScript::RemoveInvalidTargets, EFFECT_2, TARGET_UNIT_CASTER_AREA_RAID); + AfterHit += SpellHitFn(spell_sha_bloodlust_SpellScript::ApplyDebuff); + } + }; + + SpellScript* GetSpellScript() const + { + return new spell_sha_bloodlust_SpellScript(); + } +}; + +// -1064 - Chain Heal +class spell_sha_chain_heal : public SpellScriptLoader +{ + public: + spell_sha_chain_heal() : SpellScriptLoader("spell_sha_chain_heal") { } + + class spell_sha_chain_heal_SpellScript : public SpellScript + { + PrepareSpellScript(spell_sha_chain_heal_SpellScript); + + bool Load() + { + firstHeal = true; + riptide = false; + return true; + } + + void HandleHeal(SpellEffIndex /*effIndex*/) + { + if (firstHeal) { - uint8 rank = sSpellMgr->GetSpellRank(GetSpellInfo()->Id); - if (uint32 spellId = sSpellMgr->GetSpellWithRank(SHAMAN_SPELL_FIRE_NOVA_TRIGGERED_R1, rank)) + // Check if the target has Riptide + if (AuraEffect* aurEff = GetHitUnit()->GetAuraEffect(SPELL_AURA_PERIODIC_HEAL, SPELLFAMILY_SHAMAN, 0, 0, 0x10, GetCaster()->GetGUID())) { - Creature* totem = caster->GetMap()->GetCreature(caster->m_SummonSlot[1]); - if (totem && totem->isTotem()) - caster->CastSpell(totem, spellId, true); + riptide = true; + // Consume it + GetHitUnit()->RemoveAura(aurEff->GetBase()); } + firstHeal = false; } + // Riptide increases the Chain Heal effect by 25% + if (riptide) + SetHitHeal(GetHitHeal() * 1.25f); } void Register() { - OnCheckCast += SpellCheckCastFn(spell_sha_fire_nova_SpellScript::CheckFireTotem); - OnEffectHitTarget += SpellEffectFn(spell_sha_fire_nova_SpellScript::HandleDummy, EFFECT_0, SPELL_EFFECT_DUMMY); + OnEffectHitTarget += SpellEffectFn(spell_sha_chain_heal_SpellScript::HandleHeal, EFFECT_0, SPELL_EFFECT_HEAL); } + + bool firstHeal; + bool riptide; }; SpellScript* GetSpellScript() const { - return new spell_sha_fire_nova_SpellScript(); + return new spell_sha_chain_heal_SpellScript(); } }; -// 39610 Mana Tide Totem -class spell_sha_mana_tide_totem : public SpellScriptLoader +// 8171 - Cleansing Totem (Pulse) +class spell_sha_cleansing_totem_pulse : public SpellScriptLoader { public: - spell_sha_mana_tide_totem() : SpellScriptLoader("spell_sha_mana_tide_totem") { } + spell_sha_cleansing_totem_pulse() : SpellScriptLoader("spell_sha_cleansing_totem_pulse") { } - class spell_sha_mana_tide_totem_SpellScript : public SpellScript + class spell_sha_cleansing_totem_pulse_SpellScript : public SpellScript { - PrepareSpellScript(spell_sha_mana_tide_totem_SpellScript); + PrepareSpellScript(spell_sha_cleansing_totem_pulse_SpellScript); - bool Validate(SpellInfo const* /*spellEntry*/) + bool Validate(SpellInfo const* /*spellInfo*/) { - if (!sSpellMgr->GetSpellInfo(SHAMAN_SPELL_GLYPH_OF_MANA_TIDE) || !sSpellMgr->GetSpellInfo(SHAMAN_SPELL_MANA_TIDE_TOTEM)) + if (!sSpellMgr->GetSpellInfo(SPELL_SHAMAN_CLEANSING_TOTEM_EFFECT)) return false; return true; } void HandleDummy(SpellEffIndex /*effIndex*/) { - if (Unit* caster = GetCaster()) - if (Unit* unitTarget = GetHitUnit()) - { - if (unitTarget->getPowerType() == POWER_MANA) - { - int32 effValue = GetEffectValue(); - // Glyph of Mana Tide - if (Unit* owner = caster->GetOwner()) - if (AuraEffect* dummy = owner->GetAuraEffect(SHAMAN_SPELL_GLYPH_OF_MANA_TIDE, 0)) - effValue += dummy->GetAmount(); - // Regenerate 6% of Total Mana Every 3 secs - int32 effBasePoints0 = int32(CalculatePct(unitTarget->GetMaxPower(POWER_MANA), effValue)); - caster->CastCustomSpell(unitTarget, SHAMAN_SPELL_MANA_TIDE_TOTEM, &effBasePoints0, NULL, NULL, true, NULL, NULL, GetOriginalCaster()->GetGUID()); - } - } + int32 bp = 1; + if (GetCaster() && GetHitUnit() && GetOriginalCaster()) + GetCaster()->CastCustomSpell(GetHitUnit(), SPELL_SHAMAN_CLEANSING_TOTEM_EFFECT, NULL, &bp, NULL, true, NULL, NULL, GetOriginalCaster()->GetGUID()); } void Register() { - OnEffectHitTarget += SpellEffectFn(spell_sha_mana_tide_totem_SpellScript::HandleDummy, EFFECT_0, SPELL_EFFECT_DUMMY); + OnEffectHitTarget += SpellEffectFn(spell_sha_cleansing_totem_pulse_SpellScript::HandleDummy, EFFECT_0, SPELL_EFFECT_DUMMY); } }; SpellScript* GetSpellScript() const { - return new spell_sha_mana_tide_totem_SpellScript(); + return new spell_sha_cleansing_totem_pulse_SpellScript(); + } +}; + +// -974 - Earth Shield +class spell_sha_earth_shield : public SpellScriptLoader +{ + public: + spell_sha_earth_shield() : SpellScriptLoader("spell_sha_earth_shield") { } + + class spell_sha_earth_shield_AuraScript : public AuraScript + { + PrepareAuraScript(spell_sha_earth_shield_AuraScript); + + bool Validate(SpellInfo const* /*spellInfo*/) + { + if (!sSpellMgr->GetSpellInfo(SPELL_SHAMAN_EARTH_SHIELD_HEAL)) + return false; + if (!sSpellMgr->GetSpellInfo(SPELL_SHAMAN_GLYPH_OF_EARTH_SHIELD)) + return false; + return true; + } + + void CalculateAmount(AuraEffect const* /*aurEff*/, int32& amount, bool & /*canBeRecalculated*/) + { + if (Unit* caster = GetCaster()) + { + amount = caster->SpellHealingBonusDone(GetUnitOwner(), GetSpellInfo(), amount, HEAL); + amount = GetUnitOwner()->SpellHealingBonusTaken(caster, GetSpellInfo(), amount, HEAL); + + // Glyph of Earth Shield + //! WORKAROUND + //! this glyph is a proc + if (AuraEffect* glyph = caster->GetAuraEffect(SPELL_SHAMAN_GLYPH_OF_EARTH_SHIELD, EFFECT_0)) + AddPct(amount, glyph->GetAmount()); + } + } + + void HandleProc(AuraEffect const* aurEff, ProcEventInfo& /*eventInfo*/) + { + PreventDefaultAction(); + + //! HACK due to currenct proc system implementation + if (Player* player = GetTarget()->ToPlayer()) + if (player->HasSpellCooldown(SPELL_SHAMAN_EARTH_SHIELD_HEAL)) + return; + + GetTarget()->CastCustomSpell(SPELL_SHAMAN_EARTH_SHIELD_HEAL, SPELLVALUE_BASE_POINT0, aurEff->GetAmount(), GetTarget(), true, NULL, aurEff, GetCasterGUID()); + + if (Player* player = GetTarget()->ToPlayer()) + player->AddSpellCooldown(SPELL_SHAMAN_EARTH_SHIELD_HEAL, 0, time(NULL) + 3); + } + + void Register() + { + DoEffectCalcAmount += AuraEffectCalcAmountFn(spell_sha_earth_shield_AuraScript::CalculateAmount, EFFECT_0, SPELL_AURA_DUMMY); + OnEffectProc += AuraEffectProcFn(spell_sha_earth_shield_AuraScript::HandleProc, EFFECT_0, SPELL_AURA_DUMMY); + } + }; + + AuraScript* GetAuraScript() const + { + return new spell_sha_earth_shield_AuraScript(); } }; -// 6474 - Earthbind Totem - Fix Talent:Earthen Power +// 6474 - Earthbind Totem - Fix Talent: Earthen Power class spell_sha_earthbind_totem : public SpellScriptLoader { public: @@ -213,9 +340,9 @@ class spell_sha_earthbind_totem : public SpellScriptLoader { PrepareAuraScript(spell_sha_earthbind_totem_AuraScript); - bool Validate(SpellInfo const* /*spellEntry*/) + bool Validate(SpellInfo const* /*spellInfo*/) { - if (!sSpellMgr->GetSpellInfo(SHAMAN_TOTEM_SPELL_EARTHBIND_TOTEM) || !sSpellMgr->GetSpellInfo(SHAMAN_TOTEM_SPELL_EARTHEN_POWER)) + if (!sSpellMgr->GetSpellInfo(SPELL_SHAMAN_TOTEM_EARTHBIND_TOTEM) || !sSpellMgr->GetSpellInfo(SPELL_SHAMAN_TOTEM_EARTHEN_POWER)) return false; return true; } @@ -227,7 +354,7 @@ class spell_sha_earthbind_totem : public SpellScriptLoader if (Player* owner = GetCaster()->GetCharmerOrOwnerPlayerOrPlayerItself()) if (AuraEffect* aur = owner->GetDummyAuraEffect(SPELLFAMILY_SHAMAN, 2289, 0)) if (roll_chance_i(aur->GetBaseAmount())) - GetTarget()->CastSpell((Unit*)NULL, SHAMAN_TOTEM_SPELL_EARTHEN_POWER, true); + GetTarget()->CastSpell((Unit*)NULL, SPELL_SHAMAN_TOTEM_EARTHEN_POWER, true); } void Apply(AuraEffect const* /*aurEff*/, AuraEffectHandleModes /*mode*/) @@ -238,10 +365,10 @@ class spell_sha_earthbind_totem : public SpellScriptLoader if (!owner) return; // Storm, Earth and Fire - if (AuraEffect* aurEff = owner->GetAuraEffectOfRankedSpell(SHAMAN_SPELL_STORM_EARTH_AND_FIRE, EFFECT_1)) + if (AuraEffect* aurEff = owner->GetAuraEffectOfRankedSpell(SPELL_SHAMAN_STORM_EARTH_AND_FIRE, EFFECT_1)) { if (roll_chance_i(aurEff->GetAmount())) - GetCaster()->CastSpell(GetCaster(), EARTHBIND_TOTEM_SPELL_EARTHGRAB, false); + GetCaster()->CastSpell(GetCaster(), SPELL_SHAMAN_TOTEM_EARTHBIND_EARTHGRAB, false); } } @@ -275,6 +402,7 @@ class EarthenPowerTargetSelector } }; +// 59566 - Earthen Power class spell_sha_earthen_power : public SpellScriptLoader { public: @@ -301,177 +429,112 @@ class spell_sha_earthen_power : public SpellScriptLoader } }; -class spell_sha_bloodlust : public SpellScriptLoader +// -1535 - Fire Nova +class spell_sha_fire_nova : public SpellScriptLoader { public: - spell_sha_bloodlust() : SpellScriptLoader("spell_sha_bloodlust") { } + spell_sha_fire_nova() : SpellScriptLoader("spell_sha_fire_nova") { } - class spell_sha_bloodlust_SpellScript : public SpellScript + class spell_sha_fire_nova_SpellScript : public SpellScript { - PrepareSpellScript(spell_sha_bloodlust_SpellScript); + PrepareSpellScript(spell_sha_fire_nova_SpellScript); - bool Validate(SpellInfo const* /*spellEntry*/) + bool Validate(SpellInfo const* spellInfo) { - if (!sSpellMgr->GetSpellInfo(SHAMAN_SPELL_SATED)) + if (!sSpellMgr->GetSpellInfo(SPELL_SHAMAN_FIRE_NOVA_R1) || sSpellMgr->GetFirstSpellInChain(SPELL_SHAMAN_FIRE_NOVA_R1) != sSpellMgr->GetFirstSpellInChain(spellInfo->Id)) return false; - return true; - } - - void RemoveInvalidTargets(std::list<WorldObject*>& targets) - { - targets.remove_if(Trinity::UnitAuraCheck(true, SHAMAN_SPELL_SATED)); - } - - void ApplyDebuff() - { - if (Unit* target = GetHitUnit()) - target->CastSpell(target, SHAMAN_SPELL_SATED, true); - } - void Register() - { - OnObjectAreaTargetSelect += SpellObjectAreaTargetSelectFn(spell_sha_bloodlust_SpellScript::RemoveInvalidTargets, EFFECT_0, TARGET_UNIT_CASTER_AREA_RAID); - OnObjectAreaTargetSelect += SpellObjectAreaTargetSelectFn(spell_sha_bloodlust_SpellScript::RemoveInvalidTargets, EFFECT_1, TARGET_UNIT_CASTER_AREA_RAID); - OnObjectAreaTargetSelect += SpellObjectAreaTargetSelectFn(spell_sha_bloodlust_SpellScript::RemoveInvalidTargets, EFFECT_2, TARGET_UNIT_CASTER_AREA_RAID); - AfterHit += SpellHitFn(spell_sha_bloodlust_SpellScript::ApplyDebuff); - } - }; - - SpellScript* GetSpellScript() const - { - return new spell_sha_bloodlust_SpellScript(); - } -}; - -class spell_sha_heroism : public SpellScriptLoader -{ - public: - spell_sha_heroism() : SpellScriptLoader("spell_sha_heroism") { } - - class spell_sha_heroism_SpellScript : public SpellScript - { - PrepareSpellScript(spell_sha_heroism_SpellScript); - - bool Validate(SpellInfo const* /*spellEntry*/) - { - if (!sSpellMgr->GetSpellInfo(SHAMAN_SPELL_EXHAUSTION)) + uint8 rank = sSpellMgr->GetSpellRank(spellInfo->Id); + if (!sSpellMgr->GetSpellWithRank(SPELL_SHAMAN_FIRE_NOVA_TRIGGERED_R1, rank, true)) return false; return true; } - void RemoveInvalidTargets(std::list<WorldObject*>& targets) - { - targets.remove_if(Trinity::UnitAuraCheck(true, SHAMAN_SPELL_EXHAUSTION)); - } - - void ApplyDebuff() - { - if (Unit* target = GetHitUnit()) - target->CastSpell(target, SHAMAN_SPELL_EXHAUSTION, true); - } - - void Register() + SpellCastResult CheckFireTotem() { - OnObjectAreaTargetSelect += SpellObjectAreaTargetSelectFn(spell_sha_heroism_SpellScript::RemoveInvalidTargets, EFFECT_0, TARGET_UNIT_CASTER_AREA_RAID); - OnObjectAreaTargetSelect += SpellObjectAreaTargetSelectFn(spell_sha_heroism_SpellScript::RemoveInvalidTargets, EFFECT_1, TARGET_UNIT_CASTER_AREA_RAID); - OnObjectAreaTargetSelect += SpellObjectAreaTargetSelectFn(spell_sha_heroism_SpellScript::RemoveInvalidTargets, EFFECT_2, TARGET_UNIT_CASTER_AREA_RAID); - AfterHit += SpellHitFn(spell_sha_heroism_SpellScript::ApplyDebuff); - } - }; - - SpellScript* GetSpellScript() const - { - return new spell_sha_heroism_SpellScript(); - } -}; - -enum AncestralAwakeningProc -{ - SPELL_ANCESTRAL_AWAKENING_PROC = 52752, -}; - -class spell_sha_ancestral_awakening_proc : public SpellScriptLoader -{ - public: - spell_sha_ancestral_awakening_proc() : SpellScriptLoader("spell_sha_ancestral_awakening_proc") { } - - class spell_sha_ancestral_awakening_proc_SpellScript : public SpellScript - { - PrepareSpellScript(spell_sha_ancestral_awakening_proc_SpellScript); + // fire totem + if (!GetCaster()->m_SummonSlot[1]) + { + SetCustomCastResultMessage(SPELL_CUSTOM_ERROR_MUST_HAVE_FIRE_TOTEM); + return SPELL_FAILED_CUSTOM_ERROR; + } - bool Validate(SpellInfo const* /*SpellEntry*/) - { - if (!sSpellMgr->GetSpellInfo(SPELL_ANCESTRAL_AWAKENING_PROC)) - return false; - return true; + return SPELL_CAST_OK; } - void HandleDummy(SpellEffIndex /* effIndex */) + void HandleDummy(SpellEffIndex /*effIndex*/) { - int32 damage = GetEffectValue(); - if (GetCaster() && GetHitUnit()) - GetCaster()->CastCustomSpell(GetHitUnit(), SPELL_ANCESTRAL_AWAKENING_PROC, &damage, NULL, NULL, true); + if (Unit* caster = GetCaster()) + { + uint8 rank = sSpellMgr->GetSpellRank(GetSpellInfo()->Id); + if (uint32 spellId = sSpellMgr->GetSpellWithRank(SPELL_SHAMAN_FIRE_NOVA_TRIGGERED_R1, rank)) + { + Creature* totem = caster->GetMap()->GetCreature(caster->m_SummonSlot[1]); + if (totem && totem->isTotem()) + caster->CastSpell(totem, spellId, true); + } + } } void Register() { - OnEffectHitTarget += SpellEffectFn(spell_sha_ancestral_awakening_proc_SpellScript::HandleDummy, EFFECT_0, SPELL_EFFECT_DUMMY); + OnCheckCast += SpellCheckCastFn(spell_sha_fire_nova_SpellScript::CheckFireTotem); + OnEffectHitTarget += SpellEffectFn(spell_sha_fire_nova_SpellScript::HandleDummy, EFFECT_0, SPELL_EFFECT_DUMMY); } }; SpellScript* GetSpellScript() const { - return new spell_sha_ancestral_awakening_proc_SpellScript(); + return new spell_sha_fire_nova_SpellScript(); } }; -enum CleansingTotemPulse -{ - SPELL_CLEANSING_TOTEM_EFFECT = 52025, -}; - -class spell_sha_cleansing_totem_pulse : public SpellScriptLoader +// -8050 - Flame Shock +class spell_sha_flame_shock : public SpellScriptLoader { public: - spell_sha_cleansing_totem_pulse() : SpellScriptLoader("spell_sha_cleansing_totem_pulse") { } + spell_sha_flame_shock() : SpellScriptLoader("spell_sha_flame_shock") { } - class spell_sha_cleansing_totem_pulse_SpellScript : public SpellScript + class spell_sha_flame_shock_AuraScript : public AuraScript { - PrepareSpellScript(spell_sha_cleansing_totem_pulse_SpellScript); + PrepareAuraScript(spell_sha_flame_shock_AuraScript); - bool Validate(SpellInfo const* /*SpellEntry*/) + bool Validate(SpellInfo const* /*spell*/) { - if (!sSpellMgr->GetSpellInfo(SPELL_CLEANSING_TOTEM_EFFECT)) + if (!sSpellMgr->GetSpellInfo(SPELL_SHAMAN_LAVA_FLOWS_R1)) + return false; + if (!sSpellMgr->GetSpellInfo(SPELL_SHAMAN_LAVA_FLOWS_TRIGGERED_R1)) return false; return true; } - void HandleDummy(SpellEffIndex /* effIndex */) + void HandleDispel(DispelInfo* /*dispelInfo*/) { - int32 bp = 1; - if (GetCaster() && GetHitUnit() && GetOriginalCaster()) - GetCaster()->CastCustomSpell(GetHitUnit(), SPELL_CLEANSING_TOTEM_EFFECT, NULL, &bp, NULL, true, NULL, NULL, GetOriginalCaster()->GetGUID()); + if (Unit* caster = GetCaster()) + // Lava Flows + if (AuraEffect const* aurEff = caster->GetDummyAuraEffect(SPELLFAMILY_SHAMAN, SHAMAN_ICON_ID_SHAMAN_LAVA_FLOW, EFFECT_0)) + { + if (sSpellMgr->GetFirstSpellInChain(SPELL_SHAMAN_LAVA_FLOWS_R1) != sSpellMgr->GetFirstSpellInChain(aurEff->GetId())) + return; + + uint8 rank = sSpellMgr->GetSpellRank(aurEff->GetId()); + caster->CastSpell(caster, sSpellMgr->GetSpellWithRank(SPELL_SHAMAN_LAVA_FLOWS_TRIGGERED_R1, rank), true); + } } void Register() { - OnEffectHitTarget += SpellEffectFn(spell_sha_cleansing_totem_pulse_SpellScript::HandleDummy, EFFECT_0, SPELL_EFFECT_DUMMY); + AfterDispel += AuraDispelFn(spell_sha_flame_shock_AuraScript::HandleDispel); } }; - SpellScript* GetSpellScript() const + AuraScript* GetAuraScript() const { - return new spell_sha_cleansing_totem_pulse_SpellScript(); + return new spell_sha_flame_shock_AuraScript(); } }; -enum HealingStreamTotem -{ - SPELL_GLYPH_OF_HEALING_STREAM_TOTEM = 55456, - ICON_ID_RESTORATIVE_TOTEMS = 338, - SPELL_HEALING_STREAM_TOTEM_HEAL = 52042, -}; - +// 52041, 52046, 52047, 52048, 52049, 52050, 58759, 58760, 58761 - Healing Stream Totem class spell_sha_healing_stream_totem : public SpellScriptLoader { public: @@ -481,14 +544,14 @@ class spell_sha_healing_stream_totem : public SpellScriptLoader { PrepareSpellScript(spell_sha_healing_stream_totem_SpellScript); - bool Validate(SpellInfo const* /*SpellEntry*/) + bool Validate(SpellInfo const* /*spellInfo*/) { - if (!sSpellMgr->GetSpellInfo(SPELL_GLYPH_OF_HEALING_STREAM_TOTEM) || !sSpellMgr->GetSpellInfo(SPELL_HEALING_STREAM_TOTEM_HEAL)) + if (!sSpellMgr->GetSpellInfo(SPELL_SHAMAN_GLYPH_OF_HEALING_STREAM_TOTEM) || !sSpellMgr->GetSpellInfo(SPELL_SHAMAN_TOTEM_HEALING_STREAM_HEAL)) return false; return true; } - void HandleDummy(SpellEffIndex /* effIndex */) + void HandleDummy(SpellEffIndex /*effIndex*/) { int32 damage = GetEffectValue(); SpellInfo const* triggeringSpell = GetTriggeringSpell(); @@ -501,16 +564,16 @@ class spell_sha_healing_stream_totem : public SpellScriptLoader damage = int32(owner->SpellHealingBonusDone(target, triggeringSpell, damage, HEAL)); // Restorative Totems - if (AuraEffect* dummy = owner->GetAuraEffect(SPELL_AURA_DUMMY, SPELLFAMILY_SHAMAN, ICON_ID_RESTORATIVE_TOTEMS, 1)) + if (AuraEffect* dummy = owner->GetAuraEffect(SPELL_AURA_DUMMY, SPELLFAMILY_SHAMAN, SHAMAN_ICON_ID_RESTORATIVE_TOTEMS, 1)) AddPct(damage, dummy->GetAmount()); // Glyph of Healing Stream Totem - if (AuraEffect const* aurEff = owner->GetAuraEffect(SPELL_GLYPH_OF_HEALING_STREAM_TOTEM, EFFECT_0)) + if (AuraEffect const* aurEff = owner->GetAuraEffect(SPELL_SHAMAN_GLYPH_OF_HEALING_STREAM_TOTEM, EFFECT_0)) AddPct(damage, aurEff->GetAmount()); damage = int32(target->SpellHealingBonusTaken(owner, triggeringSpell, damage, HEAL)); } - caster->CastCustomSpell(target, SPELL_HEALING_STREAM_TOTEM_HEAL, &damage, 0, 0, true, 0, 0, GetOriginalCaster()->GetGUID()); + caster->CastCustomSpell(target, SPELL_SHAMAN_TOTEM_HEALING_STREAM_HEAL, &damage, 0, 0, true, 0, 0, GetOriginalCaster()->GetGUID()); } } @@ -526,49 +589,50 @@ class spell_sha_healing_stream_totem : public SpellScriptLoader } }; -enum ManaSpringTotem -{ - SPELL_MANA_SPRING_TOTEM_ENERGIZE = 52032, -}; - -class spell_sha_mana_spring_totem : public SpellScriptLoader +// 32182 - Heroism +class spell_sha_heroism : public SpellScriptLoader { public: - spell_sha_mana_spring_totem() : SpellScriptLoader("spell_sha_mana_spring_totem") { } + spell_sha_heroism() : SpellScriptLoader("spell_sha_heroism") { } - class spell_sha_mana_spring_totem_SpellScript : public SpellScript + class spell_sha_heroism_SpellScript : public SpellScript { - PrepareSpellScript(spell_sha_mana_spring_totem_SpellScript); + PrepareSpellScript(spell_sha_heroism_SpellScript); - bool Validate(SpellInfo const* /*SpellEntry*/) + bool Validate(SpellInfo const* /*spellInfo*/) { - if (!sSpellMgr->GetSpellInfo(SPELL_MANA_SPRING_TOTEM_ENERGIZE)) + if (!sSpellMgr->GetSpellInfo(SPELL_SHAMAN_EXHAUSTION)) return false; return true; } - void HandleDummy(SpellEffIndex /* effIndex */) + void RemoveInvalidTargets(std::list<WorldObject*>& targets) + { + targets.remove_if(Trinity::UnitAuraCheck(true, SPELL_SHAMAN_EXHAUSTION)); + } + + void ApplyDebuff() { - int32 damage = GetEffectValue(); if (Unit* target = GetHitUnit()) - if (Unit* caster = GetCaster()) - if (target->getPowerType() == POWER_MANA) - caster->CastCustomSpell(target, SPELL_MANA_SPRING_TOTEM_ENERGIZE, &damage, 0, 0, true, 0, 0, GetOriginalCaster()->GetGUID()); + target->CastSpell(target, SPELL_SHAMAN_EXHAUSTION, true); } void Register() { - OnEffectHitTarget += SpellEffectFn(spell_sha_mana_spring_totem_SpellScript::HandleDummy, EFFECT_0, SPELL_EFFECT_DUMMY); + OnObjectAreaTargetSelect += SpellObjectAreaTargetSelectFn(spell_sha_heroism_SpellScript::RemoveInvalidTargets, EFFECT_0, TARGET_UNIT_CASTER_AREA_RAID); + OnObjectAreaTargetSelect += SpellObjectAreaTargetSelectFn(spell_sha_heroism_SpellScript::RemoveInvalidTargets, EFFECT_1, TARGET_UNIT_CASTER_AREA_RAID); + OnObjectAreaTargetSelect += SpellObjectAreaTargetSelectFn(spell_sha_heroism_SpellScript::RemoveInvalidTargets, EFFECT_2, TARGET_UNIT_CASTER_AREA_RAID); + AfterHit += SpellHitFn(spell_sha_heroism_SpellScript::ApplyDebuff); } - }; SpellScript* GetSpellScript() const { - return new spell_sha_mana_spring_totem_SpellScript(); + return new spell_sha_heroism_SpellScript(); } }; +// 60103 - Lava Lash class spell_sha_lava_lash : public SpellScriptLoader { public: @@ -583,7 +647,7 @@ class spell_sha_lava_lash : public SpellScriptLoader return GetCaster()->GetTypeId() == TYPEID_PLAYER; } - void HandleDummy(SpellEffIndex /* effIndex */) + void HandleDummy(SpellEffIndex /*effIndex*/) { if (Player* caster = GetCaster()->ToPlayer()) { @@ -612,100 +676,94 @@ class spell_sha_lava_lash : public SpellScriptLoader } }; -// 1064 Chain Heal -class spell_sha_chain_heal : public SpellScriptLoader +// 52031, 52033, 52034, 52035, 52036, 58778, 58779, 58780 - Mana Spring Totem +class spell_sha_mana_spring_totem : public SpellScriptLoader { public: - spell_sha_chain_heal() : SpellScriptLoader("spell_sha_chain_heal") { } + spell_sha_mana_spring_totem() : SpellScriptLoader("spell_sha_mana_spring_totem") { } - class spell_sha_chain_heal_SpellScript : public SpellScript + class spell_sha_mana_spring_totem_SpellScript : public SpellScript { - PrepareSpellScript(spell_sha_chain_heal_SpellScript); + PrepareSpellScript(spell_sha_mana_spring_totem_SpellScript); - bool Load() + bool Validate(SpellInfo const* /*spellInfo*/) { - firstHeal = true; - riptide = false; + if (!sSpellMgr->GetSpellInfo(SPELL_SHAMAN_MANA_SPRING_TOTEM_ENERGIZE)) + return false; return true; } - void HandleHeal(SpellEffIndex /*effIndex*/) + void HandleDummy(SpellEffIndex /*effIndex*/) { - if (firstHeal) - { - // Check if the target has Riptide - if (AuraEffect* aurEff = GetHitUnit()->GetAuraEffect(SPELL_AURA_PERIODIC_HEAL, SPELLFAMILY_SHAMAN, 0, 0, 0x10, GetCaster()->GetGUID())) - { - riptide = true; - // Consume it - GetHitUnit()->RemoveAura(aurEff->GetBase()); - } - firstHeal = false; - } - // Riptide increases the Chain Heal effect by 25% - if (riptide) - SetHitHeal(GetHitHeal() * 1.25f); + int32 damage = GetEffectValue(); + if (Unit* target = GetHitUnit()) + if (Unit* caster = GetCaster()) + if (target->getPowerType() == POWER_MANA) + caster->CastCustomSpell(target, SPELL_SHAMAN_MANA_SPRING_TOTEM_ENERGIZE, &damage, 0, 0, true, 0, 0, GetOriginalCaster()->GetGUID()); } void Register() { - OnEffectHitTarget += SpellEffectFn(spell_sha_chain_heal_SpellScript::HandleHeal, EFFECT_0, SPELL_EFFECT_HEAL); + OnEffectHitTarget += SpellEffectFn(spell_sha_mana_spring_totem_SpellScript::HandleDummy, EFFECT_0, SPELL_EFFECT_DUMMY); } - bool firstHeal; - bool riptide; }; SpellScript* GetSpellScript() const { - return new spell_sha_chain_heal_SpellScript(); + return new spell_sha_mana_spring_totem_SpellScript(); } }; -class spell_sha_flame_shock : public SpellScriptLoader +// 39610 - Mana Tide Totem +class spell_sha_mana_tide_totem : public SpellScriptLoader { public: - spell_sha_flame_shock() : SpellScriptLoader("spell_sha_flame_shock") { } + spell_sha_mana_tide_totem() : SpellScriptLoader("spell_sha_mana_tide_totem") { } - class spell_sha_flame_shock_AuraScript : public AuraScript + class spell_sha_mana_tide_totem_SpellScript : public SpellScript { - PrepareAuraScript(spell_sha_flame_shock_AuraScript); + PrepareSpellScript(spell_sha_mana_tide_totem_SpellScript); - bool Validate(SpellInfo const* /*spell*/) + bool Validate(SpellInfo const* /*spellInfo*/) { - if (!sSpellMgr->GetSpellInfo(SHAMAN_LAVA_FLOWS_R1)) - return false; - if (!sSpellMgr->GetSpellInfo(SHAMAN_LAVA_FLOWS_TRIGGERED_R1)) + if (!sSpellMgr->GetSpellInfo(SPELL_SHAMAN_GLYPH_OF_MANA_TIDE) || !sSpellMgr->GetSpellInfo(SPELL_SHAMAN_MANA_TIDE_TOTEM)) return false; return true; } - void HandleDispel(DispelInfo* /*dispelInfo*/) + void HandleDummy(SpellEffIndex /*effIndex*/) { if (Unit* caster = GetCaster()) - // Lava Flows - if (AuraEffect const* aurEff = caster->GetDummyAuraEffect(SPELLFAMILY_SHAMAN, ICON_ID_SHAMAN_LAVA_FLOW, EFFECT_0)) + if (Unit* unitTarget = GetHitUnit()) { - if (sSpellMgr->GetFirstSpellInChain(SHAMAN_LAVA_FLOWS_R1) != sSpellMgr->GetFirstSpellInChain(aurEff->GetId())) - return; - - uint8 rank = sSpellMgr->GetSpellRank(aurEff->GetId()); - caster->CastSpell(caster, sSpellMgr->GetSpellWithRank(SHAMAN_LAVA_FLOWS_TRIGGERED_R1, rank), true); + if (unitTarget->getPowerType() == POWER_MANA) + { + int32 effValue = GetEffectValue(); + // Glyph of Mana Tide + if (Unit* owner = caster->GetOwner()) + if (AuraEffect* dummy = owner->GetAuraEffect(SPELL_SHAMAN_GLYPH_OF_MANA_TIDE, 0)) + effValue += dummy->GetAmount(); + // Regenerate 6% of Total Mana Every 3 secs + int32 effBasePoints0 = int32(CalculatePct(unitTarget->GetMaxPower(POWER_MANA), effValue)); + caster->CastCustomSpell(unitTarget, SPELL_SHAMAN_MANA_TIDE_TOTEM, &effBasePoints0, NULL, NULL, true, NULL, NULL, GetOriginalCaster()->GetGUID()); + } } } void Register() { - AfterDispel += AuraDispelFn(spell_sha_flame_shock_AuraScript::HandleDispel); + OnEffectHitTarget += SpellEffectFn(spell_sha_mana_tide_totem_SpellScript::HandleDummy, EFFECT_0, SPELL_EFFECT_DUMMY); } }; - AuraScript* GetAuraScript() const + SpellScript* GetSpellScript() const { - return new spell_sha_flame_shock_AuraScript(); + return new spell_sha_mana_tide_totem_SpellScript(); } }; +// 6495 - Sentry Totem class spell_sha_sentry_totem : public SpellScriptLoader { public: @@ -717,7 +775,7 @@ class spell_sha_sentry_totem : public SpellScriptLoader bool Validate(SpellInfo const* /*spell*/) { - if (!sSpellMgr->GetSpellInfo(SHAMAN_BIND_SIGHT)) + if (!sSpellMgr->GetSpellInfo(SPELL_SHAMAN_BIND_SIGHT)) return false; return true; } @@ -727,7 +785,7 @@ class spell_sha_sentry_totem : public SpellScriptLoader if (Unit* caster = GetCaster()) if (Creature* totem = caster->GetMap()->GetCreature(caster->m_SummonSlot[4])) if (totem->isTotem()) - caster->CastSpell(totem, SHAMAN_BIND_SIGHT, true); + caster->CastSpell(totem, SPELL_SHAMAN_BIND_SIGHT, true); } void AfterRemove(AuraEffect const* /*aurEff*/, AuraEffectHandleModes /*mode*/) @@ -750,21 +808,52 @@ class spell_sha_sentry_totem : public SpellScriptLoader } }; +// -51490 - Thunderstorm +class spell_sha_thunderstorm : public SpellScriptLoader +{ + public: + spell_sha_thunderstorm() : SpellScriptLoader("spell_sha_thunderstorm") { } + + class spell_sha_thunderstorm_SpellScript : public SpellScript + { + PrepareSpellScript(spell_sha_thunderstorm_SpellScript); + + void HandleKnockBack(SpellEffIndex effIndex) + { + // Glyph of Thunderstorm + if (GetCaster()->HasAura(SPELL_SHAMAN_GLYPH_OF_THUNDERSTORM)) + PreventHitDefaultEffect(effIndex); + } + + void Register() + { + OnEffectHitTarget += SpellEffectFn(spell_sha_thunderstorm_SpellScript::HandleKnockBack, EFFECT_2, SPELL_EFFECT_KNOCK_BACK); + } + }; + + SpellScript* GetSpellScript() const + { + return new spell_sha_thunderstorm_SpellScript(); + } +}; + void AddSC_shaman_spell_scripts() { + new spell_sha_ancestral_awakening_proc(); new spell_sha_astral_shift(); - new spell_sha_fire_nova(); - new spell_sha_mana_tide_totem(); - new spell_sha_earthbind_totem(); - new spell_sha_earthen_power(); new spell_sha_bloodlust(); - new spell_sha_heroism(); - new spell_sha_ancestral_awakening_proc(); + new spell_sha_chain_heal(); new spell_sha_cleansing_totem_pulse(); + new spell_sha_earth_shield(); + new spell_sha_earthbind_totem(); + new spell_sha_earthen_power(); + new spell_sha_fire_nova(); + new spell_sha_flame_shock(); new spell_sha_healing_stream_totem(); - new spell_sha_mana_spring_totem(); + new spell_sha_heroism(); new spell_sha_lava_lash(); - new spell_sha_chain_heal(); - new spell_sha_flame_shock(); + new spell_sha_mana_spring_totem(); + new spell_sha_mana_tide_totem(); new spell_sha_sentry_totem(); + new spell_sha_thunderstorm(); } diff --git a/src/server/scripts/Spells/spell_warlock.cpp b/src/server/scripts/Spells/spell_warlock.cpp index 2070933173b..a9a4b2d749a 100644 --- a/src/server/scripts/Spells/spell_warlock.cpp +++ b/src/server/scripts/Spells/spell_warlock.cpp @@ -28,141 +28,91 @@ enum WarlockSpells { - WARLOCK_DEMONIC_EMPOWERMENT_SUCCUBUS = 54435, - WARLOCK_DEMONIC_EMPOWERMENT_VOIDWALKER = 54443, - WARLOCK_DEMONIC_EMPOWERMENT_FELGUARD = 54508, - WARLOCK_DEMONIC_EMPOWERMENT_FELHUNTER = 54509, - WARLOCK_DEMONIC_EMPOWERMENT_IMP = 54444, - WARLOCK_IMPROVED_HEALTHSTONE_R1 = 18692, - WARLOCK_IMPROVED_HEALTHSTONE_R2 = 18693, - WARLOCK_DEMONIC_CIRCLE_SUMMON = 48018, - WARLOCK_DEMONIC_CIRCLE_TELEPORT = 48020, - WARLOCK_DEMONIC_CIRCLE_ALLOW_CAST = 62388, - WARLOCK_HAUNT = 48181, - WARLOCK_HAUNT_HEAL = 48210, - WARLOCK_UNSTABLE_AFFLICTION_DISPEL = 31117, - WARLOCK_CURSE_OF_DOOM_EFFECT = 18662, - WARLOCK_IMPROVED_HEALTH_FUNNEL_R1 = 18703, - WARLOCK_IMPROVED_HEALTH_FUNNEL_R2 = 18704, - WARLOCK_IMPROVED_HEALTH_FUNNEL_BUFF_R1 = 60955, - WARLOCK_IMPROVED_HEALTH_FUNNEL_BUFF_R2 = 60956, + SPELL_WARLOCK_CURSE_OF_DOOM_EFFECT = 18662, + SPELL_WARLOCK_DEMONIC_CIRCLE_SUMMON = 48018, + SPELL_WARLOCK_DEMONIC_CIRCLE_TELEPORT = 48020, + SPELL_WARLOCK_DEMONIC_CIRCLE_ALLOW_CAST = 62388, + SPELL_WARLOCK_DEMONIC_EMPOWERMENT_SUCCUBUS = 54435, + SPELL_WARLOCK_DEMONIC_EMPOWERMENT_VOIDWALKER = 54443, + SPELL_WARLOCK_DEMONIC_EMPOWERMENT_FELGUARD = 54508, + SPELL_WARLOCK_DEMONIC_EMPOWERMENT_FELHUNTER = 54509, + SPELL_WARLOCK_DEMONIC_EMPOWERMENT_IMP = 54444, + SPELL_WARLOCK_FEL_SYNERGY_HEAL = 54181, + SPELL_WARLOCK_GLYPH_OF_SIPHON_LIFE = 63106, + SPELL_WARLOCK_IMPROVED_HEALTHSTONE_R1 = 18692, + SPELL_WARLOCK_IMPROVED_HEALTHSTONE_R2 = 18693, + SPELL_WARLOCK_IMPROVED_HEALTH_FUNNEL_R1 = 18703, + SPELL_WARLOCK_IMPROVED_HEALTH_FUNNEL_R2 = 18704, + SPELL_WARLOCK_IMPROVED_HEALTH_FUNNEL_BUFF_R1 = 60955, + SPELL_WARLOCK_IMPROVED_HEALTH_FUNNEL_BUFF_R2 = 60956, + SPELL_WARLOCK_HAUNT = 48181, + SPELL_WARLOCK_HAUNT_HEAL = 48210, + SPELL_WARLOCK_LIFE_TAP_ENERGIZE = 31818, + SPELL_WARLOCK_LIFE_TAP_ENERGIZE_2 = 32553, + SPELL_WARLOCK_SOULSHATTER = 32835, + SPELL_WARLOCK_SIPHON_LIFE_HEAL = 63106, + SPELL_WARLOCK_UNSTABLE_AFFLICTION_DISPEL = 31117 }; -class spell_warl_banish : public SpellScriptLoader +enum WarlockSpellIcons { -public: - spell_warl_banish() : SpellScriptLoader("spell_warl_banish") { } - - class spell_warl_banish_SpellScript : public SpellScript - { - PrepareSpellScript(spell_warl_banish_SpellScript); - - bool Load() - { - _removed = false; - return true; - } - - void HandleBanish() - { - if (Unit* target = GetHitUnit()) - { - if (target->GetAuraEffect(SPELL_AURA_SCHOOL_IMMUNITY, SPELLFAMILY_WARLOCK, 0, 0x08000000, 0)) - { - //No need to remove old aura since its removed due to not stack by current Banish aura - PreventHitDefaultEffect(EFFECT_0); - PreventHitDefaultEffect(EFFECT_1); - PreventHitDefaultEffect(EFFECT_2); - _removed = true; - } - } - } - - void RemoveAura() - { - if (_removed) - PreventHitAura(); - } - - void Register() - { - BeforeHit += SpellHitFn(spell_warl_banish_SpellScript::HandleBanish); - AfterHit += SpellHitFn(spell_warl_banish_SpellScript::RemoveAura); - } - - bool _removed; - }; - - SpellScript* GetSpellScript() const - { - return new spell_warl_banish_SpellScript(); - } + WARLOCK_ICON_ID_IMPROVED_LIFE_TAP = 208, + WARLOCK_ICON_ID_MANA_FEED = 1982 }; -// 47193 Demonic Empowerment -class spell_warl_demonic_empowerment : public SpellScriptLoader +// 710, 18647 - Banish +class spell_warl_banish : public SpellScriptLoader { public: - spell_warl_demonic_empowerment() : SpellScriptLoader("spell_warl_demonic_empowerment") { } + spell_warl_banish() : SpellScriptLoader("spell_warl_banish") { } - class spell_warl_demonic_empowerment_SpellScript : public SpellScript + class spell_warl_banish_SpellScript : public SpellScript { - PrepareSpellScript(spell_warl_demonic_empowerment_SpellScript); + PrepareSpellScript(spell_warl_banish_SpellScript); - bool Validate(SpellInfo const* /*spellEntry*/) + bool Load() { - if (!sSpellMgr->GetSpellInfo(WARLOCK_DEMONIC_EMPOWERMENT_SUCCUBUS) || !sSpellMgr->GetSpellInfo(WARLOCK_DEMONIC_EMPOWERMENT_VOIDWALKER) || !sSpellMgr->GetSpellInfo(WARLOCK_DEMONIC_EMPOWERMENT_FELGUARD) || !sSpellMgr->GetSpellInfo(WARLOCK_DEMONIC_EMPOWERMENT_FELHUNTER) || !sSpellMgr->GetSpellInfo(WARLOCK_DEMONIC_EMPOWERMENT_IMP)) - return false; + _removed = false; return true; } - void HandleScriptEffect(SpellEffIndex /*effIndex*/) + void HandleBanish() { - if (Creature* targetCreature = GetHitCreature()) + if (Unit* target = GetHitUnit()) { - if (targetCreature->isPet()) + if (target->GetAuraEffect(SPELL_AURA_SCHOOL_IMMUNITY, SPELLFAMILY_WARLOCK, 0, 0x08000000, 0)) { - CreatureTemplate const* ci = sObjectMgr->GetCreatureTemplate(targetCreature->GetEntry()); - switch (ci->family) - { - case CREATURE_FAMILY_SUCCUBUS: - targetCreature->CastSpell(targetCreature, WARLOCK_DEMONIC_EMPOWERMENT_SUCCUBUS, true); - break; - case CREATURE_FAMILY_VOIDWALKER: - { - SpellInfo const* spellInfo = sSpellMgr->GetSpellInfo(WARLOCK_DEMONIC_EMPOWERMENT_VOIDWALKER); - int32 hp = int32(targetCreature->CountPctFromMaxHealth(GetCaster()->CalculateSpellDamage(targetCreature, spellInfo, 0))); - targetCreature->CastCustomSpell(targetCreature, WARLOCK_DEMONIC_EMPOWERMENT_VOIDWALKER, &hp, NULL, NULL, true); - //unitTarget->CastSpell(unitTarget, 54441, true); - break; - } - case CREATURE_FAMILY_FELGUARD: - targetCreature->CastSpell(targetCreature, WARLOCK_DEMONIC_EMPOWERMENT_FELGUARD, true); - break; - case CREATURE_FAMILY_FELHUNTER: - targetCreature->CastSpell(targetCreature, WARLOCK_DEMONIC_EMPOWERMENT_FELHUNTER, true); - break; - case CREATURE_FAMILY_IMP: - targetCreature->CastSpell(targetCreature, WARLOCK_DEMONIC_EMPOWERMENT_IMP, true); - break; - } + // No need to remove old aura since its removed due to not stack by current Banish aura + PreventHitDefaultEffect(EFFECT_0); + PreventHitDefaultEffect(EFFECT_1); + PreventHitDefaultEffect(EFFECT_2); + _removed = true; } } } + void RemoveAura() + { + if (_removed) + PreventHitAura(); + } + void Register() { - OnEffectHitTarget += SpellEffectFn(spell_warl_demonic_empowerment_SpellScript::HandleScriptEffect, EFFECT_0, SPELL_EFFECT_SCRIPT_EFFECT); + BeforeHit += SpellHitFn(spell_warl_banish_SpellScript::HandleBanish); + AfterHit += SpellHitFn(spell_warl_banish_SpellScript::RemoveAura); } + + bool _removed; }; SpellScript* GetSpellScript() const { - return new spell_warl_demonic_empowerment_SpellScript(); + return new spell_warl_banish_SpellScript(); } }; -// 6201 Create Healthstone (and ranks) +// 6201 - Create Healthstone (and ranks) class spell_warl_create_healthstone : public SpellScriptLoader { public: @@ -174,9 +124,9 @@ class spell_warl_create_healthstone : public SpellScriptLoader static uint32 const iTypes[8][3]; - bool Validate(SpellInfo const* /*spellEntry*/) + bool Validate(SpellInfo const* /*spellInfo*/) { - if (!sSpellMgr->GetSpellInfo(WARLOCK_IMPROVED_HEALTHSTONE_R1) || !sSpellMgr->GetSpellInfo(WARLOCK_IMPROVED_HEALTHSTONE_R2)) + if (!sSpellMgr->GetSpellInfo(SPELL_WARLOCK_IMPROVED_HEALTHSTONE_R1) || !sSpellMgr->GetSpellInfo(SPELL_WARLOCK_IMPROVED_HEALTHSTONE_R2)) return false; return true; } @@ -204,8 +154,12 @@ class spell_warl_create_healthstone : public SpellScriptLoader { switch (aurEff->GetId()) { - case WARLOCK_IMPROVED_HEALTHSTONE_R1: rank = 1; break; - case WARLOCK_IMPROVED_HEALTHSTONE_R2: rank = 2; break; + case SPELL_WARLOCK_IMPROVED_HEALTHSTONE_R1: + rank = 1; + break; + case SPELL_WARLOCK_IMPROVED_HEALTHSTONE_R2: + rank = 2; + break; default: sLog->outError(LOG_FILTER_SPELLS_AURAS, "Unknown rank of Improved Healthstone id: %d", aurEff->GetId()); break; @@ -241,142 +195,379 @@ uint32 const spell_warl_create_healthstone::spell_warl_create_healthstone_SpellS {36892, 36893, 36894} // Fel Healthstone }; -// 47422 Everlasting Affliction -class spell_warl_everlasting_affliction : public SpellScriptLoader +// -603 - Curse of Doom +class spell_warl_curse_of_doom : public SpellScriptLoader { public: - spell_warl_everlasting_affliction() : SpellScriptLoader("spell_warl_everlasting_affliction") { } + spell_warl_curse_of_doom() : SpellScriptLoader("spell_warl_curse_of_doom") { } - class spell_warl_everlasting_affliction_SpellScript : public SpellScript + class spell_warl_curse_of_doom_AuraScript : public AuraScript { - PrepareSpellScript(spell_warl_everlasting_affliction_SpellScript); + PrepareAuraScript(spell_warl_curse_of_doom_AuraScript); - void HandleScriptEffect(SpellEffIndex /*effIndex*/) + bool Validate(SpellInfo const* /*spell*/) { - if (Unit* unitTarget = GetHitUnit()) - // Refresh corruption on target - if (AuraEffect* aur = unitTarget->GetAuraEffect(SPELL_AURA_PERIODIC_DAMAGE, SPELLFAMILY_WARLOCK, 0x2, 0, 0, GetCaster()->GetGUID())) - aur->GetBase()->RefreshDuration(); + if (!sSpellMgr->GetSpellInfo(SPELL_WARLOCK_CURSE_OF_DOOM_EFFECT)) + return false; + return true; + } + + bool Load() + { + return GetCaster() && GetCaster()->GetTypeId() == TYPEID_PLAYER; + } + + void OnRemove(AuraEffect const* aurEff, AuraEffectHandleModes /*mode*/) + { + if (!GetCaster()) + return; + + AuraRemoveMode removeMode = GetTargetApplication()->GetRemoveMode(); + if (removeMode != AURA_REMOVE_BY_DEATH || !IsExpired()) + return; + + if (GetCaster()->ToPlayer()->isHonorOrXPTarget(GetTarget())) + GetCaster()->CastSpell(GetTarget(), SPELL_WARLOCK_CURSE_OF_DOOM_EFFECT, true, NULL, aurEff); } void Register() { - OnEffectHitTarget += SpellEffectFn(spell_warl_everlasting_affliction_SpellScript::HandleScriptEffect, EFFECT_0, SPELL_EFFECT_SCRIPT_EFFECT); + AfterEffectRemove += AuraEffectRemoveFn(spell_warl_curse_of_doom_AuraScript::OnRemove, EFFECT_0, SPELL_AURA_PERIODIC_DAMAGE, AURA_EFFECT_HANDLE_REAL); } }; - SpellScript* GetSpellScript() const + AuraScript* GetAuraScript() const { - return new spell_warl_everlasting_affliction_SpellScript(); + return new spell_warl_curse_of_doom_AuraScript(); } }; -// 18541 Ritual of Doom Effect -class spell_warl_ritual_of_doom_effect : public SpellScriptLoader +// 48018 - Demonic Circle Summon +class spell_warl_demonic_circle_summon : public SpellScriptLoader { -public: - spell_warl_ritual_of_doom_effect() : SpellScriptLoader("spell_warl_ritual_of_doom_effect") { } + public: + spell_warl_demonic_circle_summon() : SpellScriptLoader("spell_warl_demonic_circle_summon") { } + + class spell_warl_demonic_circle_summon_AuraScript : public AuraScript + { + PrepareAuraScript(spell_warl_demonic_circle_summon_AuraScript); + + void HandleRemove(AuraEffect const* /*aurEff*/, AuraEffectHandleModes mode) + { + // If effect is removed by expire remove the summoned demonic circle too. + if (!(mode & AURA_EFFECT_HANDLE_REAPPLY)) + GetTarget()->RemoveGameObject(GetId(), true); + + GetTarget()->RemoveAura(SPELL_WARLOCK_DEMONIC_CIRCLE_ALLOW_CAST); + } + + void HandleDummyTick(AuraEffect const* /*aurEff*/) + { + if (GameObject* circle = GetTarget()->GetGameObject(GetId())) + { + // Here we check if player is in demonic circle teleport range, if so add + // WARLOCK_DEMONIC_CIRCLE_ALLOW_CAST; allowing him to cast the WARLOCK_DEMONIC_CIRCLE_TELEPORT. + // If not in range remove the WARLOCK_DEMONIC_CIRCLE_ALLOW_CAST. - class spell_warl_ritual_of_doom_effect_SpellScript : public SpellScript - { - PrepareSpellScript(spell_warl_ritual_of_doom_effect_SpellScript); + SpellInfo const* spellInfo = sSpellMgr->GetSpellInfo(SPELL_WARLOCK_DEMONIC_CIRCLE_TELEPORT); - void HandleDummy(SpellEffIndex /*effIndex*/) + if (GetTarget()->IsWithinDist(circle, spellInfo->GetMaxRange(true))) + { + if (!GetTarget()->HasAura(SPELL_WARLOCK_DEMONIC_CIRCLE_ALLOW_CAST)) + GetTarget()->CastSpell(GetTarget(), SPELL_WARLOCK_DEMONIC_CIRCLE_ALLOW_CAST, true); + } + else + GetTarget()->RemoveAura(SPELL_WARLOCK_DEMONIC_CIRCLE_ALLOW_CAST); + } + } + + void Register() + { + OnEffectRemove += AuraEffectApplyFn(spell_warl_demonic_circle_summon_AuraScript::HandleRemove, EFFECT_0, SPELL_AURA_PERIODIC_DUMMY, AURA_EFFECT_HANDLE_REAL_OR_REAPPLY_MASK); + OnEffectPeriodic += AuraEffectPeriodicFn(spell_warl_demonic_circle_summon_AuraScript::HandleDummyTick, EFFECT_0, SPELL_AURA_PERIODIC_DUMMY); + } + }; + + AuraScript* GetAuraScript() const { - Unit* caster = GetCaster(); - caster->CastSpell(caster, GetEffectValue(), true); + return new spell_warl_demonic_circle_summon_AuraScript(); } +}; + +// 48020 - Demonic Circle Teleport +class spell_warl_demonic_circle_teleport : public SpellScriptLoader +{ + public: + spell_warl_demonic_circle_teleport() : SpellScriptLoader("spell_warl_demonic_circle_teleport") { } - void Register() + class spell_warl_demonic_circle_teleport_AuraScript : public AuraScript { - OnEffectHit += SpellEffectFn(spell_warl_ritual_of_doom_effect_SpellScript::HandleDummy, EFFECT_0, SPELL_EFFECT_DUMMY); + PrepareAuraScript(spell_warl_demonic_circle_teleport_AuraScript); + + void HandleTeleport(AuraEffect const* /*aurEff*/, AuraEffectHandleModes /*mode*/) + { + if (Player* player = GetTarget()->ToPlayer()) + { + if (GameObject* circle = player->GetGameObject(SPELL_WARLOCK_DEMONIC_CIRCLE_SUMMON)) + { + player->NearTeleportTo(circle->GetPositionX(), circle->GetPositionY(), circle->GetPositionZ(), circle->GetOrientation()); + player->RemoveMovementImpairingAuras(); + } + } + } + + void Register() + { + OnEffectApply += AuraEffectApplyFn(spell_warl_demonic_circle_teleport_AuraScript::HandleTeleport, EFFECT_0, SPELL_AURA_MECHANIC_IMMUNITY, AURA_EFFECT_HANDLE_REAL); + } + }; + + AuraScript* GetAuraScript() const + { + return new spell_warl_demonic_circle_teleport_AuraScript(); } - }; +}; + +// 47193 - Demonic Empowerment +class spell_warl_demonic_empowerment : public SpellScriptLoader +{ + public: + spell_warl_demonic_empowerment() : SpellScriptLoader("spell_warl_demonic_empowerment") { } + + class spell_warl_demonic_empowerment_SpellScript : public SpellScript + { + PrepareSpellScript(spell_warl_demonic_empowerment_SpellScript); - SpellScript* GetSpellScript() const - { - return new spell_warl_ritual_of_doom_effect_SpellScript(); - } + bool Validate(SpellInfo const* /*spellInfo*/) + { + if (!sSpellMgr->GetSpellInfo(SPELL_WARLOCK_DEMONIC_EMPOWERMENT_SUCCUBUS) || !sSpellMgr->GetSpellInfo(SPELL_WARLOCK_DEMONIC_EMPOWERMENT_VOIDWALKER) || !sSpellMgr->GetSpellInfo(SPELL_WARLOCK_DEMONIC_EMPOWERMENT_FELGUARD) || !sSpellMgr->GetSpellInfo(SPELL_WARLOCK_DEMONIC_EMPOWERMENT_FELHUNTER) || !sSpellMgr->GetSpellInfo(SPELL_WARLOCK_DEMONIC_EMPOWERMENT_IMP)) + return false; + return true; + } + + void HandleScriptEffect(SpellEffIndex /*effIndex*/) + { + if (Creature* targetCreature = GetHitCreature()) + { + if (targetCreature->isPet()) + { + CreatureTemplate const* ci = sObjectMgr->GetCreatureTemplate(targetCreature->GetEntry()); + switch (ci->family) + { + case CREATURE_FAMILY_SUCCUBUS: + targetCreature->CastSpell(targetCreature, SPELL_WARLOCK_DEMONIC_EMPOWERMENT_SUCCUBUS, true); + break; + case CREATURE_FAMILY_VOIDWALKER: + { + SpellInfo const* spellInfo = sSpellMgr->GetSpellInfo(SPELL_WARLOCK_DEMONIC_EMPOWERMENT_VOIDWALKER); + int32 hp = int32(targetCreature->CountPctFromMaxHealth(GetCaster()->CalculateSpellDamage(targetCreature, spellInfo, 0))); + targetCreature->CastCustomSpell(targetCreature, SPELL_WARLOCK_DEMONIC_EMPOWERMENT_VOIDWALKER, &hp, NULL, NULL, true); + //unitTarget->CastSpell(unitTarget, 54441, true); + break; + } + case CREATURE_FAMILY_FELGUARD: + targetCreature->CastSpell(targetCreature, SPELL_WARLOCK_DEMONIC_EMPOWERMENT_FELGUARD, true); + break; + case CREATURE_FAMILY_FELHUNTER: + targetCreature->CastSpell(targetCreature, SPELL_WARLOCK_DEMONIC_EMPOWERMENT_FELHUNTER, true); + break; + case CREATURE_FAMILY_IMP: + targetCreature->CastSpell(targetCreature, SPELL_WARLOCK_DEMONIC_EMPOWERMENT_IMP, true); + break; + } + } + } + } + + void Register() + { + OnEffectHitTarget += SpellEffectFn(spell_warl_demonic_empowerment_SpellScript::HandleScriptEffect, EFFECT_0, SPELL_EFFECT_SCRIPT_EFFECT); + } + }; + + SpellScript* GetSpellScript() const + { + return new spell_warl_demonic_empowerment_SpellScript(); + } }; -class spell_warl_seed_of_corruption : public SpellScriptLoader +// 47422 - Everlasting Affliction +class spell_warl_everlasting_affliction : public SpellScriptLoader { public: - spell_warl_seed_of_corruption() : SpellScriptLoader("spell_warl_seed_of_corruption") { } + spell_warl_everlasting_affliction() : SpellScriptLoader("spell_warl_everlasting_affliction") { } - class spell_warl_seed_of_corruption_SpellScript : public SpellScript + class spell_warl_everlasting_affliction_SpellScript : public SpellScript { - PrepareSpellScript(spell_warl_seed_of_corruption_SpellScript); + PrepareSpellScript(spell_warl_everlasting_affliction_SpellScript); - void FilterTargets(std::list<WorldObject*>& targets) + void HandleScriptEffect(SpellEffIndex /*effIndex*/) { - if (GetExplTargetUnit()) - targets.remove(GetExplTargetUnit()); + if (Unit* unitTarget = GetHitUnit()) + // Refresh corruption on target + if (AuraEffect* aur = unitTarget->GetAuraEffect(SPELL_AURA_PERIODIC_DAMAGE, SPELLFAMILY_WARLOCK, 0x2, 0, 0, GetCaster()->GetGUID())) + aur->GetBase()->RefreshDuration(); } void Register() { - OnObjectAreaTargetSelect += SpellObjectAreaTargetSelectFn(spell_warl_seed_of_corruption_SpellScript::FilterTargets, EFFECT_0, TARGET_UNIT_DEST_AREA_ENEMY); + OnEffectHitTarget += SpellEffectFn(spell_warl_everlasting_affliction_SpellScript::HandleScriptEffect, EFFECT_0, SPELL_EFFECT_SCRIPT_EFFECT); } }; SpellScript* GetSpellScript() const { - return new spell_warl_seed_of_corruption_SpellScript(); + return new spell_warl_everlasting_affliction_SpellScript(); } }; -enum Soulshatter +// -47230 - Fel Synergy +class spell_warl_fel_synergy : public SpellScriptLoader { - SPELL_SOULSHATTER = 32835, + public: + spell_warl_fel_synergy() : SpellScriptLoader("spell_warl_fel_synergy") { } + + class spell_warl_fel_synergy_AuraScript : public AuraScript + { + PrepareAuraScript(spell_warl_fel_synergy_AuraScript); + + bool Validate(SpellInfo const* /*spellInfo*/) + { + if (!sSpellMgr->GetSpellInfo(SPELL_WARLOCK_FEL_SYNERGY_HEAL)) + return false; + return true; + } + + bool CheckProc(ProcEventInfo& eventInfo) + { + return GetTarget()->GetGuardianPet() && eventInfo.GetDamageInfo()->GetDamage(); + } + + void OnProc(AuraEffect const* aurEff, ProcEventInfo& eventInfo) + { + PreventDefaultAction(); + + int32 heal = CalculatePct(int32(eventInfo.GetDamageInfo()->GetDamage()), aurEff->GetAmount()); + GetTarget()->CastCustomSpell(SPELL_WARLOCK_FEL_SYNERGY_HEAL, SPELLVALUE_BASE_POINT0, heal, (Unit*)NULL, true, NULL, aurEff); // TARGET_UNIT_PET + } + + void Register() + { + DoCheckProc += AuraCheckProcFn(spell_warl_fel_synergy_AuraScript::CheckProc); + OnEffectProc += AuraEffectProcFn(spell_warl_fel_synergy_AuraScript::OnProc, EFFECT_0, SPELL_AURA_DUMMY); + } + }; + + AuraScript* GetAuraScript() const + { + return new spell_warl_fel_synergy_AuraScript(); + } }; -class spell_warl_soulshatter : public SpellScriptLoader +// -48181 - Haunt +class spell_warl_haunt : public SpellScriptLoader { public: - spell_warl_soulshatter() : SpellScriptLoader("spell_warl_soulshatter") { } + spell_warl_haunt() : SpellScriptLoader("spell_warl_haunt") { } - class spell_warl_soulshatter_SpellScript : public SpellScript + class spell_warl_haunt_SpellScript : public SpellScript { - PrepareSpellScript(spell_warl_soulshatter_SpellScript); + PrepareSpellScript(spell_warl_haunt_SpellScript); + + void HandleOnHit() + { + if (Aura* aura = GetHitAura()) + if (AuraEffect* aurEff = aura->GetEffect(EFFECT_1)) + aurEff->SetAmount(CalculatePct(aurEff->GetAmount(), GetHitDamage())); + } + + void Register() + { + OnHit += SpellHitFn(spell_warl_haunt_SpellScript::HandleOnHit); + } + }; + + class spell_warl_haunt_AuraScript : public AuraScript + { + PrepareAuraScript(spell_warl_haunt_AuraScript); bool Validate(SpellInfo const* /*spell*/) { - if (!sSpellMgr->GetSpellInfo(SPELL_SOULSHATTER)) + if (!sSpellMgr->GetSpellInfo(SPELL_WARLOCK_HAUNT_HEAL)) return false; return true; } - void HandleDummy(SpellEffIndex /*effIndex*/) + void HandleRemove(AuraEffect const* aurEff, AuraEffectHandleModes /*mode*/) { - Unit* caster = GetCaster(); - if (Unit* target = GetHitUnit()) + if (Unit* caster = GetCaster()) { - if (target->CanHaveThreatList() && target->getThreatManager().getThreat(caster) > 0.0f) - caster->CastSpell(target, SPELL_SOULSHATTER, true); + int32 amount = aurEff->GetAmount(); + GetTarget()->CastCustomSpell(caster, SPELL_WARLOCK_HAUNT_HEAL, &amount, NULL, NULL, true, NULL, aurEff, GetCasterGUID()); } } void Register() { - OnEffectHitTarget += SpellEffectFn(spell_warl_soulshatter_SpellScript::HandleDummy, EFFECT_0, SPELL_EFFECT_DUMMY); + OnEffectRemove += AuraEffectApplyFn(spell_warl_haunt_AuraScript::HandleRemove, EFFECT_1, SPELL_AURA_DUMMY, AURA_EFFECT_HANDLE_REAL_OR_REAPPLY_MASK); } }; SpellScript* GetSpellScript() const { - return new spell_warl_soulshatter_SpellScript(); + return new spell_warl_haunt_SpellScript(); + } + + AuraScript* GetAuraScript() const + { + return new spell_warl_haunt_AuraScript(); } }; -enum LifeTap +// -755 - Health Funnel +class spell_warl_health_funnel : public SpellScriptLoader { - SPELL_LIFE_TAP_ENERGIZE = 31818, - SPELL_LIFE_TAP_ENERGIZE_2 = 32553, - ICON_ID_IMPROVED_LIFE_TAP = 208, - ICON_ID_MANA_FEED = 1982, + public: + spell_warl_health_funnel() : SpellScriptLoader("spell_warl_health_funnel") { } + + class spell_warl_health_funnel_AuraScript : public AuraScript + { + PrepareAuraScript(spell_warl_health_funnel_AuraScript); + + void ApplyEffect(AuraEffect const* /*aurEff*/, AuraEffectHandleModes /*mode*/) + { + Unit* caster = GetCaster(); + if (!caster) + return; + + Unit* target = GetTarget(); + if (caster->HasAura(SPELL_WARLOCK_IMPROVED_HEALTH_FUNNEL_R2)) + target->CastSpell(target, SPELL_WARLOCK_IMPROVED_HEALTH_FUNNEL_BUFF_R2, true); + else if (caster->HasAura(SPELL_WARLOCK_IMPROVED_HEALTH_FUNNEL_R1)) + target->CastSpell(target, SPELL_WARLOCK_IMPROVED_HEALTH_FUNNEL_BUFF_R1, true); + } + + void RemoveEffect(AuraEffect const* /*aurEff*/, AuraEffectHandleModes /*mode*/) + { + Unit* target = GetTarget(); + target->RemoveAurasDueToSpell(SPELL_WARLOCK_IMPROVED_HEALTH_FUNNEL_BUFF_R1); + target->RemoveAurasDueToSpell(SPELL_WARLOCK_IMPROVED_HEALTH_FUNNEL_BUFF_R2); + } + + void Register() + { + OnEffectRemove += AuraEffectRemoveFn(spell_warl_health_funnel_AuraScript::RemoveEffect, EFFECT_0, SPELL_AURA_PERIODIC_HEAL, AURA_EFFECT_HANDLE_REAL); + OnEffectApply += AuraEffectApplyFn(spell_warl_health_funnel_AuraScript::ApplyEffect, EFFECT_0, SPELL_AURA_PERIODIC_HEAL, AURA_EFFECT_HANDLE_REAL); + } + }; + + AuraScript* GetAuraScript() const + { + return new spell_warl_health_funnel_AuraScript(); + } }; +// -1454 - Life Tap class spell_warl_life_tap : public SpellScriptLoader { public: @@ -393,7 +584,7 @@ class spell_warl_life_tap : public SpellScriptLoader bool Validate(SpellInfo const* /*spell*/) { - if (!sSpellMgr->GetSpellInfo(SPELL_LIFE_TAP_ENERGIZE) || !sSpellMgr->GetSpellInfo(SPELL_LIFE_TAP_ENERGIZE_2)) + if (!sSpellMgr->GetSpellInfo(SPELL_WARLOCK_LIFE_TAP_ENERGIZE) || !sSpellMgr->GetSpellInfo(SPELL_WARLOCK_LIFE_TAP_ENERGIZE_2)) return false; return true; } @@ -410,20 +601,20 @@ class spell_warl_life_tap : public SpellScriptLoader target->ModifyHealth(-damage); // Improved Life Tap mod - if (AuraEffect const* aurEff = caster->GetDummyAuraEffect(SPELLFAMILY_WARLOCK, ICON_ID_IMPROVED_LIFE_TAP, 0)) + if (AuraEffect const* aurEff = caster->GetDummyAuraEffect(SPELLFAMILY_WARLOCK, WARLOCK_ICON_ID_IMPROVED_LIFE_TAP, 0)) AddPct(mana, aurEff->GetAmount()); - caster->CastCustomSpell(target, SPELL_LIFE_TAP_ENERGIZE, &mana, NULL, NULL, false); + caster->CastCustomSpell(target, SPELL_WARLOCK_LIFE_TAP_ENERGIZE, &mana, NULL, NULL, false); // Mana Feed int32 manaFeedVal = 0; - if (AuraEffect const* aurEff = caster->GetAuraEffect(SPELL_AURA_ADD_FLAT_MODIFIER, SPELLFAMILY_WARLOCK, ICON_ID_MANA_FEED, 0)) + if (AuraEffect const* aurEff = caster->GetAuraEffect(SPELL_AURA_ADD_FLAT_MODIFIER, SPELLFAMILY_WARLOCK, WARLOCK_ICON_ID_MANA_FEED, 0)) manaFeedVal = aurEff->GetAmount(); if (manaFeedVal > 0) { ApplyPct(manaFeedVal, mana); - caster->CastCustomSpell(caster, SPELL_LIFE_TAP_ENERGIZE_2, &manaFeedVal, NULL, NULL, true, NULL); + caster->CastCustomSpell(caster, SPELL_WARLOCK_LIFE_TAP_ENERGIZE_2, &manaFeedVal, NULL, NULL, true, NULL); } } } @@ -448,149 +639,188 @@ class spell_warl_life_tap : public SpellScriptLoader } }; -class spell_warl_demonic_circle_summon : public SpellScriptLoader +// 18541 - Ritual of Doom Effect +class spell_warl_ritual_of_doom_effect : public SpellScriptLoader { public: - spell_warl_demonic_circle_summon() : SpellScriptLoader("spell_warl_demonic_circle_summon") { } + spell_warl_ritual_of_doom_effect() : SpellScriptLoader("spell_warl_ritual_of_doom_effect") { } - class spell_warl_demonic_circle_summon_AuraScript : public AuraScript + class spell_warl_ritual_of_doom_effect_SpellScript : public SpellScript { - PrepareAuraScript(spell_warl_demonic_circle_summon_AuraScript); + PrepareSpellScript(spell_warl_ritual_of_doom_effect_SpellScript); - void HandleRemove(AuraEffect const* /*aurEff*/, AuraEffectHandleModes mode) + void HandleDummy(SpellEffIndex /*effIndex*/) { - // If effect is removed by expire remove the summoned demonic circle too. - if (!(mode & AURA_EFFECT_HANDLE_REAPPLY)) - GetTarget()->RemoveGameObject(GetId(), true); - - GetTarget()->RemoveAura(WARLOCK_DEMONIC_CIRCLE_ALLOW_CAST); + Unit* caster = GetCaster(); + caster->CastSpell(caster, GetEffectValue(), true); } - void HandleDummyTick(AuraEffect const* /*aurEff*/) + void Register() { - if (GameObject* circle = GetTarget()->GetGameObject(GetId())) - { - // Here we check if player is in demonic circle teleport range, if so add - // WARLOCK_DEMONIC_CIRCLE_ALLOW_CAST; allowing him to cast the WARLOCK_DEMONIC_CIRCLE_TELEPORT. - // If not in range remove the WARLOCK_DEMONIC_CIRCLE_ALLOW_CAST. + OnEffectHit += SpellEffectFn(spell_warl_ritual_of_doom_effect_SpellScript::HandleDummy, EFFECT_0, SPELL_EFFECT_DUMMY); + } + }; - SpellInfo const* spellInfo = sSpellMgr->GetSpellInfo(WARLOCK_DEMONIC_CIRCLE_TELEPORT); + SpellScript* GetSpellScript() const + { + return new spell_warl_ritual_of_doom_effect_SpellScript(); + } +}; - if (GetTarget()->IsWithinDist(circle, spellInfo->GetMaxRange(true))) - { - if (!GetTarget()->HasAura(WARLOCK_DEMONIC_CIRCLE_ALLOW_CAST)) - GetTarget()->CastSpell(GetTarget(), WARLOCK_DEMONIC_CIRCLE_ALLOW_CAST, true); - } - else - GetTarget()->RemoveAura(WARLOCK_DEMONIC_CIRCLE_ALLOW_CAST); - } +// -27285 - Seed of Corruption +class spell_warl_seed_of_corruption : public SpellScriptLoader +{ + public: + spell_warl_seed_of_corruption() : SpellScriptLoader("spell_warl_seed_of_corruption") { } + + class spell_warl_seed_of_corruption_SpellScript : public SpellScript + { + PrepareSpellScript(spell_warl_seed_of_corruption_SpellScript); + + void FilterTargets(std::list<WorldObject*>& targets) + { + if (GetExplTargetUnit()) + targets.remove(GetExplTargetUnit()); } void Register() { - OnEffectRemove += AuraEffectApplyFn(spell_warl_demonic_circle_summon_AuraScript::HandleRemove, EFFECT_0, SPELL_AURA_PERIODIC_DUMMY, AURA_EFFECT_HANDLE_REAL_OR_REAPPLY_MASK); - OnEffectPeriodic += AuraEffectPeriodicFn(spell_warl_demonic_circle_summon_AuraScript::HandleDummyTick, EFFECT_0, SPELL_AURA_PERIODIC_DUMMY); + OnObjectAreaTargetSelect += SpellObjectAreaTargetSelectFn(spell_warl_seed_of_corruption_SpellScript::FilterTargets, EFFECT_0, TARGET_UNIT_DEST_AREA_ENEMY); } }; - AuraScript* GetAuraScript() const + SpellScript* GetSpellScript() const { - return new spell_warl_demonic_circle_summon_AuraScript(); + return new spell_warl_seed_of_corruption_SpellScript(); } }; -class spell_warl_demonic_circle_teleport : public SpellScriptLoader +// -7235 - Shadow Ward +class spell_warl_shadow_ward : public SpellScriptLoader { public: - spell_warl_demonic_circle_teleport() : SpellScriptLoader("spell_warl_demonic_circle_teleport") { } + spell_warl_shadow_ward() : SpellScriptLoader("spell_warl_shadow_ward") { } - class spell_warl_demonic_circle_teleport_AuraScript : public AuraScript + class spell_warl_shadow_ward_AuraScript : public AuraScript { - PrepareAuraScript(spell_warl_demonic_circle_teleport_AuraScript); + PrepareAuraScript(spell_warl_shadow_ward_AuraScript); - void HandleTeleport(AuraEffect const* /*aurEff*/, AuraEffectHandleModes /*mode*/) + void CalculateAmount(AuraEffect const* /*aurEff*/, int32& amount, bool& canBeRecalculated) { - if (Player* player = GetTarget()->ToPlayer()) + canBeRecalculated = false; + if (Unit* caster = GetCaster()) { - if (GameObject* circle = player->GetGameObject(WARLOCK_DEMONIC_CIRCLE_SUMMON)) - { - player->NearTeleportTo(circle->GetPositionX(), circle->GetPositionY(), circle->GetPositionZ(), circle->GetOrientation()); - player->RemoveMovementImpairingAuras(); - } + // +80.68% from sp bonus + float bonus = 0.8068f; + + bonus *= caster->SpellBaseHealingBonusDone(GetSpellInfo()->GetSchoolMask()); + bonus *= caster->CalculateLevelPenalty(GetSpellInfo()); + + amount += int32(bonus); } } void Register() { - OnEffectApply += AuraEffectApplyFn(spell_warl_demonic_circle_teleport_AuraScript::HandleTeleport, EFFECT_0, SPELL_AURA_MECHANIC_IMMUNITY, AURA_EFFECT_HANDLE_REAL); + DoEffectCalcAmount += AuraEffectCalcAmountFn(spell_warl_shadow_ward_AuraScript::CalculateAmount, EFFECT_0, SPELL_AURA_SCHOOL_ABSORB); } }; AuraScript* GetAuraScript() const { - return new spell_warl_demonic_circle_teleport_AuraScript(); + return new spell_warl_shadow_ward_AuraScript(); } }; -class spell_warl_haunt : public SpellScriptLoader +// 63108 - Siphon Life +class spell_warl_siphon_life : public SpellScriptLoader { public: - spell_warl_haunt() : SpellScriptLoader("spell_warl_haunt") { } + spell_warl_siphon_life() : SpellScriptLoader("spell_warl_siphon_life") { } - class spell_warl_haunt_SpellScript : public SpellScript + class spell_warl_siphon_life_AuraScript : public AuraScript { - PrepareSpellScript(spell_warl_haunt_SpellScript); + PrepareAuraScript(spell_warl_siphon_life_AuraScript); - void HandleOnHit() + bool Validate(SpellInfo const* /*spellInfo*/) { - if (Aura* aura = GetHitAura()) - if (AuraEffect* aurEff = aura->GetEffect(EFFECT_1)) - aurEff->SetAmount(CalculatePct(aurEff->GetAmount(), GetHitDamage())); + if (!sSpellMgr->GetSpellInfo(SPELL_WARLOCK_SIPHON_LIFE_HEAL)) + return false; + if (!sSpellMgr->GetSpellInfo(SPELL_WARLOCK_GLYPH_OF_SIPHON_LIFE)) + return false; + return true; + } + + bool CheckProc(ProcEventInfo& eventInfo) + { + return eventInfo.GetDamageInfo()->GetDamage(); + } + + void OnProc(AuraEffect const* aurEff, ProcEventInfo& eventInfo) + { + PreventDefaultAction(); + + int32 amount = int32(CalculatePct(eventInfo.GetDamageInfo()->GetDamage(), aurEff->GetAmount())); + // Glyph of Siphon Life + if (AuraEffect const* glyph = GetTarget()->GetAuraEffect(SPELL_WARLOCK_GLYPH_OF_SIPHON_LIFE, EFFECT_0)) + AddPct(amount, glyph->GetAmount()); + + GetTarget()->CastCustomSpell(SPELL_WARLOCK_SIPHON_LIFE_HEAL, SPELLVALUE_BASE_POINT0, amount, GetTarget(), true, NULL, aurEff); } void Register() { - OnHit += SpellHitFn(spell_warl_haunt_SpellScript::HandleOnHit); + DoCheckProc += AuraCheckProcFn(spell_warl_siphon_life_AuraScript::CheckProc); + OnEffectProc += AuraEffectProcFn(spell_warl_siphon_life_AuraScript::OnProc, EFFECT_0, SPELL_AURA_DUMMY); } }; - class spell_warl_haunt_AuraScript : public AuraScript + AuraScript* GetAuraScript() const { - PrepareAuraScript(spell_warl_haunt_AuraScript); + return new spell_warl_siphon_life_AuraScript(); + } +}; + +// 29858 - Soulshatter +class spell_warl_soulshatter : public SpellScriptLoader +{ + public: + spell_warl_soulshatter() : SpellScriptLoader("spell_warl_soulshatter") { } + + class spell_warl_soulshatter_SpellScript : public SpellScript + { + PrepareSpellScript(spell_warl_soulshatter_SpellScript); bool Validate(SpellInfo const* /*spell*/) { - if (!sSpellMgr->GetSpellInfo(WARLOCK_HAUNT_HEAL)) + if (!sSpellMgr->GetSpellInfo(SPELL_WARLOCK_SOULSHATTER)) return false; return true; } - void HandleRemove(AuraEffect const* aurEff, AuraEffectHandleModes /*mode*/) + void HandleDummy(SpellEffIndex /*effIndex*/) { - if (Unit* caster = GetCaster()) + Unit* caster = GetCaster(); + if (Unit* target = GetHitUnit()) { - int32 amount = aurEff->GetAmount(); - GetTarget()->CastCustomSpell(caster, WARLOCK_HAUNT_HEAL, &amount, NULL, NULL, true, NULL, aurEff, GetCasterGUID()); + if (target->CanHaveThreatList() && target->getThreatManager().getThreat(caster) > 0.0f) + caster->CastSpell(target, SPELL_WARLOCK_SOULSHATTER, true); } } void Register() { - OnEffectRemove += AuraEffectApplyFn(spell_warl_haunt_AuraScript::HandleRemove, EFFECT_1, SPELL_AURA_DUMMY, AURA_EFFECT_HANDLE_REAL_OR_REAPPLY_MASK); + OnEffectHitTarget += SpellEffectFn(spell_warl_soulshatter_SpellScript::HandleDummy, EFFECT_0, SPELL_EFFECT_DUMMY); } }; SpellScript* GetSpellScript() const { - return new spell_warl_haunt_SpellScript(); - } - - AuraScript* GetAuraScript() const - { - return new spell_warl_haunt_AuraScript(); + return new spell_warl_soulshatter_SpellScript(); } }; +// -30108 - Unstable Affliction class spell_warl_unstable_affliction : public SpellScriptLoader { public: @@ -602,7 +832,7 @@ class spell_warl_unstable_affliction : public SpellScriptLoader bool Validate(SpellInfo const* /*spell*/) { - if (!sSpellMgr->GetSpellInfo(WARLOCK_UNSTABLE_AFFLICTION_DISPEL)) + if (!sSpellMgr->GetSpellInfo(SPELL_WARLOCK_UNSTABLE_AFFLICTION_DISPEL)) return false; return true; } @@ -614,7 +844,7 @@ class spell_warl_unstable_affliction : public SpellScriptLoader { int32 damage = aurEff->GetAmount() * 9; // backfire damage and silence - caster->CastCustomSpell(dispelInfo->GetDispeller(), WARLOCK_UNSTABLE_AFFLICTION_DISPEL, &damage, NULL, NULL, true, NULL, aurEff); + caster->CastCustomSpell(dispelInfo->GetDispeller(), SPELL_WARLOCK_UNSTABLE_AFFLICTION_DISPEL, &damage, NULL, NULL, true, NULL, aurEff); } } @@ -630,108 +860,23 @@ class spell_warl_unstable_affliction : public SpellScriptLoader } }; -class spell_warl_curse_of_doom : public SpellScriptLoader -{ - public: - spell_warl_curse_of_doom() : SpellScriptLoader("spell_warl_curse_of_doom") { } - - class spell_warl_curse_of_doom_AuraScript : public AuraScript - { - PrepareAuraScript(spell_warl_curse_of_doom_AuraScript); - - bool Validate(SpellInfo const* /*spell*/) - { - if (!sSpellMgr->GetSpellInfo(WARLOCK_CURSE_OF_DOOM_EFFECT)) - return false; - return true; - } - - bool Load() - { - return GetCaster() && GetCaster()->GetTypeId() == TYPEID_PLAYER; - } - - void OnRemove(AuraEffect const* aurEff, AuraEffectHandleModes /*mode*/) - { - if (!GetCaster()) - return; - - AuraRemoveMode removeMode = GetTargetApplication()->GetRemoveMode(); - if (removeMode != AURA_REMOVE_BY_DEATH || !IsExpired()) - return; - - if (GetCaster()->ToPlayer()->isHonorOrXPTarget(GetTarget())) - GetCaster()->CastSpell(GetTarget(), WARLOCK_CURSE_OF_DOOM_EFFECT, true, NULL, aurEff); - } - - void Register() - { - AfterEffectRemove += AuraEffectRemoveFn(spell_warl_curse_of_doom_AuraScript::OnRemove, EFFECT_0, SPELL_AURA_PERIODIC_DAMAGE, AURA_EFFECT_HANDLE_REAL); - } - }; - - AuraScript* GetAuraScript() const - { - return new spell_warl_curse_of_doom_AuraScript(); - } -}; - -class spell_warl_health_funnel : public SpellScriptLoader -{ -public: - spell_warl_health_funnel() : SpellScriptLoader("spell_warl_health_funnel") { } - - class spell_warl_health_funnel_AuraScript : public AuraScript - { - PrepareAuraScript(spell_warl_health_funnel_AuraScript); - - void ApplyEffect(AuraEffect const* /*aurEff*/, AuraEffectHandleModes /*mode*/) - { - Unit* caster = GetCaster(); - if (!caster) - return; - - Unit* target = GetTarget(); - if (caster->HasAura(WARLOCK_IMPROVED_HEALTH_FUNNEL_R2)) - target->CastSpell(target, WARLOCK_IMPROVED_HEALTH_FUNNEL_BUFF_R2, true); - else if (caster->HasAura(WARLOCK_IMPROVED_HEALTH_FUNNEL_R1)) - target->CastSpell(target, WARLOCK_IMPROVED_HEALTH_FUNNEL_BUFF_R1, true); - } - - void RemoveEffect(AuraEffect const* /*aurEff*/, AuraEffectHandleModes /*mode*/) - { - Unit* target = GetTarget(); - target->RemoveAurasDueToSpell(WARLOCK_IMPROVED_HEALTH_FUNNEL_BUFF_R1); - target->RemoveAurasDueToSpell(WARLOCK_IMPROVED_HEALTH_FUNNEL_BUFF_R2); - } - - void Register() - { - OnEffectRemove += AuraEffectRemoveFn(spell_warl_health_funnel_AuraScript::RemoveEffect, EFFECT_0, SPELL_AURA_PERIODIC_HEAL, AURA_EFFECT_HANDLE_REAL); - OnEffectApply += AuraEffectApplyFn(spell_warl_health_funnel_AuraScript::ApplyEffect, EFFECT_0, SPELL_AURA_PERIODIC_HEAL, AURA_EFFECT_HANDLE_REAL); - } - }; - - AuraScript* GetAuraScript() const - { - return new spell_warl_health_funnel_AuraScript(); - } -}; - void AddSC_warlock_spell_scripts() { new spell_warl_banish(); - new spell_warl_demonic_empowerment(); new spell_warl_create_healthstone(); + new spell_warl_curse_of_doom(); + new spell_warl_demonic_circle_summon(); + new spell_warl_demonic_circle_teleport(); + new spell_warl_demonic_empowerment(); new spell_warl_everlasting_affliction(); + new spell_warl_fel_synergy(); + new spell_warl_haunt(); + new spell_warl_health_funnel(); + new spell_warl_life_tap(); new spell_warl_ritual_of_doom_effect(); new spell_warl_seed_of_corruption(); + new spell_warl_shadow_ward(); + new spell_warl_siphon_life(); new spell_warl_soulshatter(); - new spell_warl_life_tap(); - new spell_warl_demonic_circle_summon(); - new spell_warl_demonic_circle_teleport(); - new spell_warl_haunt(); new spell_warl_unstable_affliction(); - new spell_warl_curse_of_doom(); - new spell_warl_health_funnel(); } diff --git a/src/server/scripts/Spells/spell_warrior.cpp b/src/server/scripts/Spells/spell_warrior.cpp index 7b6ac8fed12..7136f046873 100644 --- a/src/server/scripts/Spells/spell_warrior.cpp +++ b/src/server/scripts/Spells/spell_warrior.cpp @@ -28,137 +28,217 @@ enum WarriorSpells { - WARRIOR_SPELL_LAST_STAND_TRIGGERED = 12976, + SPELL_WARRIOR_BLOODTHIRST = 23885, + SPELL_WARRIOR_BLOODTHIRST_DAMAGE = 23881, + SPELL_WARRIOR_CHARGE = 34846, + SPELL_WARRIOR_DAMAGE_SHIELD_DAMAGE = 59653, + SPELL_WARRIOR_DEEP_WOUNDS_RANK_1 = 12162, + SPELL_WARRIOR_DEEP_WOUNDS_RANK_2 = 12850, + SPELL_WARRIOR_DEEP_WOUNDS_RANK_3 = 12868, + SPELL_WARRIOR_DEEP_WOUNDS_RANK_PERIODIC = 12721, + SPELL_WARRIOR_EXECUTE = 20647, + SPELL_WARRIOR_GLYPH_OF_EXECUTION = 58367, + SPELL_WARRIOR_GLYPH_OF_VIGILANCE = 63326, + SPELL_WARRIOR_JUGGERNAUT_CRIT_BONUS_BUFF = 65156, + SPELL_WARRIOR_JUGGERNAUT_CRIT_BONUS_TALENT = 64976, + SPELL_WARRIOR_LAST_STAND_TRIGGERED = 12976, + SPELL_WARRIOR_SLAM = 50783, + SPELL_WARRIOR_SWEEPING_STRIKES_EXTRA_ATTACK = 26654, + SPELL_WARRIOR_TAUNT = 355, + SPELL_WARRIOR_UNRELENTING_ASSAULT_RANK_1 = 46859, + SPELL_WARRIOR_UNRELENTING_ASSAULT_RANK_2 = 46860, + SPELL_WARRIOR_UNRELENTING_ASSAULT_TRIGGER_1 = 64849, + SPELL_WARRIOR_UNRELENTING_ASSAULT_TRIGGER_2 = 64850, + SPELL_WARRIOR_VIGILANCE_PROC = 50725, + SPELL_WARRIOR_VIGILANCE_REDIRECT_THREAT = 59665, + + SPELL_PALADIN_BLESSING_OF_SANCTUARY = 20911, + SPELL_PALADIN_GREATER_BLESSING_OF_SANCTUARY = 25899, + SPELL_PRIEST_RENEWED_HOPE = 63944, + SPELL_GEN_DAMAGE_REDUCTION_AURA = 68066, }; -class spell_warr_last_stand : public SpellScriptLoader +enum WarriorSpellIcons +{ + WARRIOR_ICON_ID_SUDDEN_DEATH = 1989, +}; + +// 23881 - Bloodthirst +class spell_warr_bloodthirst : public SpellScriptLoader { public: - spell_warr_last_stand() : SpellScriptLoader("spell_warr_last_stand") { } + spell_warr_bloodthirst() : SpellScriptLoader("spell_warr_bloodthirst") { } - class spell_warr_last_stand_SpellScript : public SpellScript + class spell_warr_bloodthirst_SpellScript : public SpellScript { - PrepareSpellScript(spell_warr_last_stand_SpellScript); + PrepareSpellScript(spell_warr_bloodthirst_SpellScript); - bool Validate(SpellInfo const* /*spellEntry*/) + void HandleDamage(SpellEffIndex /*effIndex*/) { - if (!sSpellMgr->GetSpellInfo(WARRIOR_SPELL_LAST_STAND_TRIGGERED)) - return false; - return true; + int32 damage = GetEffectValue(); + ApplyPct(damage, GetCaster()->GetTotalAttackPowerValue(BASE_ATTACK)); + + if (Unit* target = GetHitUnit()) + { + damage = GetCaster()->SpellDamageBonusDone(target, GetSpellInfo(), uint32(damage), SPELL_DIRECT_DAMAGE); + damage = target->SpellDamageBonusTaken(GetCaster(), GetSpellInfo(), uint32(damage), SPELL_DIRECT_DAMAGE); + } + SetHitDamage(damage); } void HandleDummy(SpellEffIndex /*effIndex*/) { - if (Unit* caster = GetCaster()) - { - int32 healthModSpellBasePoints0 = int32(caster->CountPctFromMaxHealth(30)); - caster->CastCustomSpell(caster, WARRIOR_SPELL_LAST_STAND_TRIGGERED, &healthModSpellBasePoints0, NULL, NULL, true, NULL); - } + int32 damage = GetEffectValue(); + GetCaster()->CastCustomSpell(GetCaster(), SPELL_WARRIOR_BLOODTHIRST, &damage, NULL, NULL, true, NULL); } void Register() { - // add dummy effect spell handler to Last Stand - OnEffectHit += SpellEffectFn(spell_warr_last_stand_SpellScript::HandleDummy, EFFECT_0, SPELL_EFFECT_DUMMY); + OnEffectHitTarget += SpellEffectFn(spell_warr_bloodthirst_SpellScript::HandleDamage, EFFECT_0, SPELL_EFFECT_SCHOOL_DAMAGE); + OnEffectHit += SpellEffectFn(spell_warr_bloodthirst_SpellScript::HandleDummy, EFFECT_1, SPELL_EFFECT_DUMMY); } }; SpellScript* GetSpellScript() const { - return new spell_warr_last_stand_SpellScript(); + return new spell_warr_bloodthirst_SpellScript(); } }; -class spell_warr_improved_spell_reflection : public SpellScriptLoader +// 23880 - Bloodthirst (Heal) +class spell_warr_bloodthirst_heal : public SpellScriptLoader { public: - spell_warr_improved_spell_reflection() : SpellScriptLoader("spell_warr_improved_spell_reflection") { } + spell_warr_bloodthirst_heal() : SpellScriptLoader("spell_warr_bloodthirst_heal") { } - class spell_warr_improved_spell_reflection_SpellScript : public SpellScript + class spell_warr_bloodthirst_heal_SpellScript : public SpellScript { - PrepareSpellScript(spell_warr_improved_spell_reflection_SpellScript); + PrepareSpellScript(spell_warr_bloodthirst_heal_SpellScript); - void FilterTargets(std::list<WorldObject*>& unitList) + void HandleHeal(SpellEffIndex /*effIndex*/) { - if (GetCaster()) - unitList.remove(GetCaster()); + if (SpellInfo const* spellInfo = sSpellMgr->GetSpellInfo(SPELL_WARRIOR_BLOODTHIRST_DAMAGE)) + SetHitHeal(GetCaster()->CountPctFromMaxHealth(spellInfo->Effects[EFFECT_1].CalcValue(GetCaster()))); } void Register() { - OnObjectAreaTargetSelect += SpellObjectAreaTargetSelectFn(spell_warr_improved_spell_reflection_SpellScript::FilterTargets, EFFECT_0, TARGET_UNIT_CASTER_AREA_PARTY); + OnEffectHitTarget += SpellEffectFn(spell_warr_bloodthirst_heal_SpellScript::HandleHeal, EFFECT_0, SPELL_EFFECT_HEAL); } }; SpellScript* GetSpellScript() const { - return new spell_warr_improved_spell_reflection_SpellScript(); + return new spell_warr_bloodthirst_heal_SpellScript(); } }; -enum DamageReductionAura +// -100 - Charge +class spell_warr_charge : public SpellScriptLoader { - SPELL_BLESSING_OF_SANCTUARY = 20911, - SPELL_GREATER_BLESSING_OF_SANCTUARY = 25899, - SPELL_RENEWED_HOPE = 63944, - SPELL_DAMAGE_REDUCTION_AURA = 68066, -}; + public: + spell_warr_charge() : SpellScriptLoader("spell_warr_charge") { } -class spell_warr_vigilance : public SpellScriptLoader -{ -public: - spell_warr_vigilance() : SpellScriptLoader("spell_warr_vigilance") { } + class spell_warr_charge_SpellScript : public SpellScript + { + PrepareSpellScript(spell_warr_charge_SpellScript); - class spell_warr_vigilance_AuraScript : public AuraScript - { - PrepareAuraScript(spell_warr_vigilance_AuraScript); + bool Validate(SpellInfo const* /*spellInfo*/) + { + if (!sSpellMgr->GetSpellInfo(SPELL_WARRIOR_JUGGERNAUT_CRIT_BONUS_TALENT) || !sSpellMgr->GetSpellInfo(SPELL_WARRIOR_JUGGERNAUT_CRIT_BONUS_BUFF) || !sSpellMgr->GetSpellInfo(SPELL_WARRIOR_CHARGE)) + return false; + return true; + } - bool Validate(SpellInfo const* /*SpellEntry*/) - { - if (!sSpellMgr->GetSpellInfo(SPELL_DAMAGE_REDUCTION_AURA)) - return false; - return true; - } + void HandleDummy(SpellEffIndex /*effIndex*/) + { + int32 chargeBasePoints0 = GetEffectValue(); + Unit* caster = GetCaster(); + caster->CastCustomSpell(caster, SPELL_WARRIOR_CHARGE, &chargeBasePoints0, NULL, NULL, true); + + // Juggernaut crit bonus + if (caster->HasAura(SPELL_WARRIOR_JUGGERNAUT_CRIT_BONUS_TALENT)) + caster->CastSpell(caster, SPELL_WARRIOR_JUGGERNAUT_CRIT_BONUS_BUFF, true); + } + + void Register() + { + OnEffectHitTarget += SpellEffectFn(spell_warr_charge_SpellScript::HandleDummy, EFFECT_1, SPELL_EFFECT_DUMMY); + } + }; - void OnApply(AuraEffect const* /*aurEff*/, AuraEffectHandleModes /*mode*/) + SpellScript* GetSpellScript() const { - if (Unit* target = GetTarget()) - target->CastSpell(target, SPELL_DAMAGE_REDUCTION_AURA, true); + return new spell_warr_charge_SpellScript(); } +}; - void OnRemove(AuraEffect const* /*aurEff*/, AuraEffectHandleModes /*mode*/) +// 12809 - Concussion Blow +class spell_warr_concussion_blow : public SpellScriptLoader +{ + public: + spell_warr_concussion_blow() : SpellScriptLoader("spell_warr_concussion_blow") { } + + class spell_warr_concussion_blow_SpellScript : public SpellScript { - if (Unit* target = GetTarget()) + PrepareSpellScript(spell_warr_concussion_blow_SpellScript); + + void HandleDummy(SpellEffIndex /*effIndex*/) { - if (target->HasAura(SPELL_DAMAGE_REDUCTION_AURA) && !(target->HasAura(SPELL_BLESSING_OF_SANCTUARY) || - target->HasAura(SPELL_GREATER_BLESSING_OF_SANCTUARY) || - target->HasAura(SPELL_RENEWED_HOPE))) - target->RemoveAurasDueToSpell(SPELL_DAMAGE_REDUCTION_AURA); + SetHitDamage(CalculatePct(GetCaster()->GetTotalAttackPowerValue(BASE_ATTACK), GetEffectValue())); } - } - void Register() + void Register() + { + OnEffectHitTarget += SpellEffectFn(spell_warr_concussion_blow_SpellScript::HandleDummy, EFFECT_2, SPELL_EFFECT_DUMMY); + } + }; + + SpellScript* GetSpellScript() const { - OnEffectApply += AuraEffectApplyFn(spell_warr_vigilance_AuraScript::OnApply, EFFECT_0, SPELL_AURA_PROC_TRIGGER_SPELL, AURA_EFFECT_HANDLE_REAL_OR_REAPPLY_MASK); - OnEffectRemove += AuraEffectRemoveFn(spell_warr_vigilance_AuraScript::OnRemove, EFFECT_0, SPELL_AURA_PROC_TRIGGER_SPELL, AURA_EFFECT_HANDLE_REAL_OR_REAPPLY_MASK); + return new spell_warr_concussion_blow_SpellScript(); } - - }; - - AuraScript* GetAuraScript() const - { - return new spell_warr_vigilance_AuraScript(); - } }; -enum DeepWounds +// -58872 - Damage Shield +class spell_warr_damage_shield : public SpellScriptLoader { - SPELL_DEEP_WOUNDS_RANK_1 = 12162, - SPELL_DEEP_WOUNDS_RANK_2 = 12850, - SPELL_DEEP_WOUNDS_RANK_3 = 12868, - SPELL_DEEP_WOUNDS_RANK_PERIODIC = 12721, + public: + spell_warr_damage_shield() : SpellScriptLoader("spell_warr_damage_shield") { } + + class spell_warr_damage_shield_AuraScript : public AuraScript + { + PrepareAuraScript(spell_warr_damage_shield_AuraScript); + + bool Validate(SpellInfo const* /*spellInfo*/) + { + if (!sSpellMgr->GetSpellInfo(SPELL_WARRIOR_DAMAGE_SHIELD_DAMAGE)) + return false; + return true; + } + + void OnProc(AuraEffect const* aurEff, ProcEventInfo& eventInfo) + { + PreventDefaultAction(); + + // % of amount blocked + int32 damage = CalculatePct(int32(GetTarget()->GetShieldBlockValue()), aurEff->GetAmount()); + GetTarget()->CastCustomSpell(SPELL_WARRIOR_DAMAGE_SHIELD_DAMAGE, SPELLVALUE_BASE_POINT0, damage, eventInfo.GetProcTarget(), true, NULL, aurEff); + } + + void Register() + { + OnEffectProc += AuraEffectProcFn(spell_warr_damage_shield_AuraScript::OnProc, EFFECT_0, SPELL_AURA_DUMMY); + } + }; + + AuraScript* GetAuraScript() const + { + return new spell_warr_damage_shield_AuraScript(); + } }; +// -12162 - Deep Wounds class spell_warr_deep_wounds : public SpellScriptLoader { public: @@ -168,14 +248,14 @@ class spell_warr_deep_wounds : public SpellScriptLoader { PrepareSpellScript(spell_warr_deep_wounds_SpellScript); - bool Validate(SpellInfo const* /*SpellEntry*/) + bool Validate(SpellInfo const* /*spellInfo*/) { - if (!sSpellMgr->GetSpellInfo(SPELL_DEEP_WOUNDS_RANK_1) || !sSpellMgr->GetSpellInfo(SPELL_DEEP_WOUNDS_RANK_2) || !sSpellMgr->GetSpellInfo(SPELL_DEEP_WOUNDS_RANK_3)) + if (!sSpellMgr->GetSpellInfo(SPELL_WARRIOR_DEEP_WOUNDS_RANK_1) || !sSpellMgr->GetSpellInfo(SPELL_WARRIOR_DEEP_WOUNDS_RANK_2) || !sSpellMgr->GetSpellInfo(SPELL_WARRIOR_DEEP_WOUNDS_RANK_3)) return false; return true; } - void HandleDummy(SpellEffIndex /* effIndex */) + void HandleDummy(SpellEffIndex /*effIndex*/) { int32 damage = GetEffectValue(); Unit* caster = GetCaster(); @@ -188,16 +268,16 @@ class spell_warr_deep_wounds : public SpellScriptLoader damage = target->SpellDamageBonusTaken(caster, GetSpellInfo(), damage, SPELL_DIRECT_DAMAGE); - SpellInfo const* spellInfo = sSpellMgr->GetSpellInfo(SPELL_DEEP_WOUNDS_RANK_PERIODIC); + SpellInfo const* spellInfo = sSpellMgr->GetSpellInfo(SPELL_WARRIOR_DEEP_WOUNDS_RANK_PERIODIC); uint32 ticks = spellInfo->GetDuration() / spellInfo->Effects[EFFECT_0].Amplitude; // Add remaining ticks to damage done - if (AuraEffect const* aurEff = target->GetAuraEffect(SPELL_DEEP_WOUNDS_RANK_PERIODIC, EFFECT_0, caster->GetGUID())) + if (AuraEffect const* aurEff = target->GetAuraEffect(SPELL_WARRIOR_DEEP_WOUNDS_RANK_PERIODIC, EFFECT_0, caster->GetGUID())) damage += aurEff->GetAmount() * (ticks - aurEff->GetTickNumber()); - damage = damage / ticks; + damage /= ticks; - caster->CastCustomSpell(target, SPELL_DEEP_WOUNDS_RANK_PERIODIC, &damage, NULL, NULL, true); + caster->CastCustomSpell(target, SPELL_WARRIOR_DEEP_WOUNDS_RANK_PERIODIC, &damage, NULL, NULL, true); } } @@ -213,311 +293,500 @@ class spell_warr_deep_wounds : public SpellScriptLoader } }; -enum Charge -{ - SPELL_JUGGERNAUT_CRIT_BONUS_TALENT = 64976, - SPELL_JUGGERNAUT_CRIT_BONUS_BUFF = 65156, - SPELL_CHARGE = 34846, -}; - -class spell_warr_charge : public SpellScriptLoader +// -5308 - Execute +class spell_warr_execute : public SpellScriptLoader { public: - spell_warr_charge() : SpellScriptLoader("spell_warr_charge") { } + spell_warr_execute() : SpellScriptLoader("spell_warr_execute") { } - class spell_warr_charge_SpellScript : public SpellScript + class spell_warr_execute_SpellScript : public SpellScript { - PrepareSpellScript(spell_warr_charge_SpellScript); + PrepareSpellScript(spell_warr_execute_SpellScript); - bool Validate(SpellInfo const* /*SpellEntry*/) + bool Validate(SpellInfo const* /*spellInfo*/) { - if (!sSpellMgr->GetSpellInfo(SPELL_JUGGERNAUT_CRIT_BONUS_TALENT) || !sSpellMgr->GetSpellInfo(SPELL_JUGGERNAUT_CRIT_BONUS_BUFF) || !sSpellMgr->GetSpellInfo(SPELL_CHARGE)) + if (!sSpellMgr->GetSpellInfo(SPELL_WARRIOR_EXECUTE) || !sSpellMgr->GetSpellInfo(SPELL_WARRIOR_GLYPH_OF_EXECUTION)) return false; return true; } - void HandleDummy(SpellEffIndex /* effIndex */) + + void HandleDummy(SpellEffIndex effIndex) { - int32 chargeBasePoints0 = GetEffectValue(); Unit* caster = GetCaster(); - caster->CastCustomSpell(caster, SPELL_CHARGE, &chargeBasePoints0, NULL, NULL, true); + if (Unit* target = GetHitUnit()) + { + SpellInfo const* spellInfo = GetSpellInfo(); + int32 rageUsed = std::min<int32>(300 - spellInfo->CalcPowerCost(caster, SpellSchoolMask(spellInfo->SchoolMask)), caster->GetPower(POWER_RAGE)); + int32 newRage = std::max<int32>(0, caster->GetPower(POWER_RAGE) - rageUsed); - //Juggernaut crit bonus - if (caster->HasAura(SPELL_JUGGERNAUT_CRIT_BONUS_TALENT)) - caster->CastSpell(caster, SPELL_JUGGERNAUT_CRIT_BONUS_BUFF, true); + // Sudden Death rage save + if (AuraEffect* aurEff = caster->GetAuraEffect(SPELL_AURA_PROC_TRIGGER_SPELL, SPELLFAMILY_GENERIC, WARRIOR_ICON_ID_SUDDEN_DEATH, EFFECT_0)) + { + int32 ragesave = aurEff->GetSpellInfo()->Effects[EFFECT_1].CalcValue() * 10; + newRage = std::max(newRage, ragesave); + } + + caster->SetPower(POWER_RAGE, uint32(newRage)); + // Glyph of Execution bonus + if (AuraEffect* aurEff = caster->GetAuraEffect(SPELL_WARRIOR_GLYPH_OF_EXECUTION, EFFECT_0)) + rageUsed += aurEff->GetAmount() * 10; + + + int32 bp = GetEffectValue() + int32(rageUsed * spellInfo->Effects[effIndex].DamageMultiplier + caster->GetTotalAttackPowerValue(BASE_ATTACK) * 0.2f); + caster->CastCustomSpell(target, SPELL_WARRIOR_EXECUTE, &bp, NULL, NULL, true, NULL, NULL, GetOriginalCaster()->GetGUID()); + } } void Register() { - OnEffectHitTarget += SpellEffectFn(spell_warr_charge_SpellScript::HandleDummy, EFFECT_1, SPELL_EFFECT_DUMMY); + OnEffectHitTarget += SpellEffectFn(spell_warr_execute_SpellScript::HandleDummy, EFFECT_0, SPELL_EFFECT_DUMMY); } }; SpellScript* GetSpellScript() const { - return new spell_warr_charge_SpellScript(); + return new spell_warr_execute_SpellScript(); } }; -enum Slam -{ - SPELL_SLAM = 50783, -}; - -class spell_warr_slam : public SpellScriptLoader +// 59725 - Improved Spell Reflection +class spell_warr_improved_spell_reflection : public SpellScriptLoader { public: - spell_warr_slam() : SpellScriptLoader("spell_warr_slam") { } + spell_warr_improved_spell_reflection() : SpellScriptLoader("spell_warr_improved_spell_reflection") { } - class spell_warr_slam_SpellScript : public SpellScript + class spell_warr_improved_spell_reflection_SpellScript : public SpellScript { - PrepareSpellScript(spell_warr_slam_SpellScript); + PrepareSpellScript(spell_warr_improved_spell_reflection_SpellScript); - bool Validate(SpellInfo const* /*SpellEntry*/) - { - if (!sSpellMgr->GetSpellInfo(SPELL_SLAM)) - return false; - return true; - } - void HandleDummy(SpellEffIndex /* effIndex */) + void FilterTargets(std::list<WorldObject*>& unitList) { - int32 bp0 = GetEffectValue(); - if (GetHitUnit()) - GetCaster()->CastCustomSpell(GetHitUnit(), SPELL_SLAM, &bp0, NULL, NULL, true, 0); + if (GetCaster()) + unitList.remove(GetCaster()); } void Register() { - OnEffectHitTarget += SpellEffectFn(spell_warr_slam_SpellScript::HandleDummy, EFFECT_0, SPELL_EFFECT_DUMMY); + OnObjectAreaTargetSelect += SpellObjectAreaTargetSelectFn(spell_warr_improved_spell_reflection_SpellScript::FilterTargets, EFFECT_0, TARGET_UNIT_CASTER_AREA_PARTY); } }; SpellScript* GetSpellScript() const { - return new spell_warr_slam_SpellScript(); + return new spell_warr_improved_spell_reflection_SpellScript(); } }; -enum Execute +// 5246 - Intimidating Shout +class spell_warr_intimidating_shout : public SpellScriptLoader { - SPELL_EXECUTE = 20647, - SPELL_GLYPH_OF_EXECUTION = 58367, - ICON_ID_SUDDEN_DEATH = 1989, + public: + spell_warr_intimidating_shout() : SpellScriptLoader("spell_warr_intimidating_shout") { } + + class spell_warr_intimidating_shout_SpellScript : public SpellScript + { + PrepareSpellScript(spell_warr_intimidating_shout_SpellScript); + + void FilterTargets(std::list<WorldObject*>& unitList) + { + unitList.remove(GetExplTargetWorldObject()); + } + + void Register() + { + OnObjectAreaTargetSelect += SpellObjectAreaTargetSelectFn(spell_warr_intimidating_shout_SpellScript::FilterTargets, EFFECT_1, TARGET_UNIT_SRC_AREA_ENEMY); + OnObjectAreaTargetSelect += SpellObjectAreaTargetSelectFn(spell_warr_intimidating_shout_SpellScript::FilterTargets, EFFECT_2, TARGET_UNIT_SRC_AREA_ENEMY); + } + }; + + SpellScript* GetSpellScript() const + { + return new spell_warr_intimidating_shout_SpellScript(); + } }; -class spell_warr_execute : public SpellScriptLoader +// 12975 - Last Stand +class spell_warr_last_stand : public SpellScriptLoader { public: - spell_warr_execute() : SpellScriptLoader("spell_warr_execute") { } + spell_warr_last_stand() : SpellScriptLoader("spell_warr_last_stand") { } - class spell_warr_execute_SpellScript : public SpellScript + class spell_warr_last_stand_SpellScript : public SpellScript { - PrepareSpellScript(spell_warr_execute_SpellScript); + PrepareSpellScript(spell_warr_last_stand_SpellScript); - bool Validate(SpellInfo const* /*SpellEntry*/) + bool Validate(SpellInfo const* /*spellInfo*/) { - if (!sSpellMgr->GetSpellInfo(SPELL_EXECUTE) || !sSpellMgr->GetSpellInfo(SPELL_GLYPH_OF_EXECUTION)) + if (!sSpellMgr->GetSpellInfo(SPELL_WARRIOR_LAST_STAND_TRIGGERED)) return false; return true; } - void HandleDummy(SpellEffIndex effIndex) + + void HandleDummy(SpellEffIndex /*effIndex*/) { - Unit* caster = GetCaster(); - if (Unit* target = GetHitUnit()) + if (Unit* caster = GetCaster()) { - SpellInfo const* spellInfo = GetSpellInfo(); - int32 rageUsed = std::min<int32>(300 - spellInfo->CalcPowerCost(caster, SpellSchoolMask(spellInfo->SchoolMask)), caster->GetPower(POWER_RAGE)); - int32 newRage = std::max<int32>(0, caster->GetPower(POWER_RAGE) - rageUsed); - - // Sudden Death rage save - if (AuraEffect* aurEff = caster->GetAuraEffect(SPELL_AURA_PROC_TRIGGER_SPELL, SPELLFAMILY_GENERIC, ICON_ID_SUDDEN_DEATH, EFFECT_0)) - { - int32 ragesave = aurEff->GetSpellInfo()->Effects[EFFECT_1].CalcValue() * 10; - newRage = std::max(newRage, ragesave); - } - - caster->SetPower(POWER_RAGE, uint32(newRage)); - // Glyph of Execution bonus - if (AuraEffect* aurEff = caster->GetAuraEffect(SPELL_GLYPH_OF_EXECUTION, EFFECT_0)) - rageUsed += aurEff->GetAmount() * 10; - - - int32 bp = GetEffectValue() + int32(rageUsed * spellInfo->Effects[effIndex].DamageMultiplier + caster->GetTotalAttackPowerValue(BASE_ATTACK) * 0.2f); - caster->CastCustomSpell(target,SPELL_EXECUTE,&bp,0,0,true,0,0,GetOriginalCaster()->GetGUID()); + int32 healthModSpellBasePoints0 = int32(caster->CountPctFromMaxHealth(30)); + caster->CastCustomSpell(caster, SPELL_WARRIOR_LAST_STAND_TRIGGERED, &healthModSpellBasePoints0, NULL, NULL, true, NULL); } } void Register() { - OnEffectHitTarget += SpellEffectFn(spell_warr_execute_SpellScript::HandleDummy, EFFECT_0, SPELL_EFFECT_DUMMY); + OnEffectHit += SpellEffectFn(spell_warr_last_stand_SpellScript::HandleDummy, EFFECT_0, SPELL_EFFECT_DUMMY); } }; SpellScript* GetSpellScript() const { - return new spell_warr_execute_SpellScript(); + return new spell_warr_last_stand_SpellScript(); } }; -class spell_warr_concussion_blow : public SpellScriptLoader +// 7384, 7887, 11584, 11585 - Overpower +class spell_warr_overpower : public SpellScriptLoader { public: - spell_warr_concussion_blow() : SpellScriptLoader("spell_warr_concussion_blow") { } + spell_warr_overpower() : SpellScriptLoader("spell_warr_overpower") { } - class spell_warr_concussion_blow_SpellScript : public SpellScript + class spell_warr_overpower_SpellScript : public SpellScript { - PrepareSpellScript(spell_warr_concussion_blow_SpellScript); + PrepareSpellScript(spell_warr_overpower_SpellScript); - void HandleDummy(SpellEffIndex /* effIndex */) + void HandleEffect(SpellEffIndex /*effIndex*/) { - SetHitDamage(CalculatePct(GetCaster()->GetTotalAttackPowerValue(BASE_ATTACK), GetEffectValue())); + uint32 spellId = 0; + if (GetCaster()->HasAura(SPELL_WARRIOR_UNRELENTING_ASSAULT_RANK_1)) + spellId = SPELL_WARRIOR_UNRELENTING_ASSAULT_TRIGGER_1; + else if (GetCaster()->HasAura(SPELL_WARRIOR_UNRELENTING_ASSAULT_RANK_2)) + spellId = SPELL_WARRIOR_UNRELENTING_ASSAULT_TRIGGER_2; + + if (!spellId) + return; + + if (Player* target = GetHitPlayer()) + if (target->HasUnitState(UNIT_STATE_CASTING)) + target->CastSpell(target, spellId, true); } void Register() { - OnEffectHitTarget += SpellEffectFn(spell_warr_concussion_blow_SpellScript::HandleDummy, EFFECT_2, SPELL_EFFECT_DUMMY); + OnEffectHitTarget += SpellEffectFn(spell_warr_overpower_SpellScript::HandleEffect, EFFECT_0, SPELL_EFFECT_ANY); } }; SpellScript* GetSpellScript() const { - return new spell_warr_concussion_blow_SpellScript(); + return new spell_warr_overpower_SpellScript(); } }; -enum Bloodthirst +// -772 - Rend +class spell_warr_rend : public SpellScriptLoader { - SPELL_BLOODTHIRST = 23885, + public: + spell_warr_rend() : SpellScriptLoader("spell_warr_rend") { } + + class spell_warr_rend_AuraScript : public AuraScript + { + PrepareAuraScript(spell_warr_rend_AuraScript); + + void CalculateAmount(AuraEffect const* aurEff, int32& amount, bool& canBeRecalculated) + { + if (Unit* caster = GetCaster()) + { + canBeRecalculated = false; + + // $0.2 * (($MWB + $mwb) / 2 + $AP / 14 * $MWS) bonus per tick + float ap = caster->GetTotalAttackPowerValue(BASE_ATTACK); + int32 mws = caster->GetAttackTime(BASE_ATTACK); + float mwbMin = caster->GetWeaponDamageRange(BASE_ATTACK, MINDAMAGE); + float mwbMax = caster->GetWeaponDamageRange(BASE_ATTACK, MAXDAMAGE); + float mwb = ((mwbMin + mwbMax) / 2 + ap * mws / 14000) * 0.2f; + amount += int32(caster->ApplyEffectModifiers(GetSpellInfo(), aurEff->GetEffIndex(), mwb)); + + // "If used while your target is above 75% health, Rend does 35% more damage." + // as for 3.1.3 only ranks above 9 (wrong tooltip?) + if (GetSpellInfo()->GetRank() >= 9) + { + if (GetUnitOwner()->HasAuraState(AURA_STATE_HEALTH_ABOVE_75_PERCENT, GetSpellInfo(), caster)) + AddPct(amount, GetSpellInfo()->Effects[EFFECT_2].CalcValue(caster)); + } + } + } + + void Register() + { + DoEffectCalcAmount += AuraEffectCalcAmountFn(spell_warr_rend_AuraScript::CalculateAmount, EFFECT_0, SPELL_AURA_PERIODIC_DAMAGE); + } + }; + + AuraScript* GetAuraScript() const + { + return new spell_warr_rend_AuraScript(); + } }; -class spell_warr_bloodthirst : public SpellScriptLoader +// 64380, 65941 - Shattering Throw +class spell_warr_shattering_throw : public SpellScriptLoader { public: - spell_warr_bloodthirst() : SpellScriptLoader("spell_warr_bloodthirst") { } + spell_warr_shattering_throw() : SpellScriptLoader("spell_warr_shattering_throw") { } - class spell_warr_bloodthirst_SpellScript : public SpellScript + class spell_warr_shattering_throw_SpellScript : public SpellScript { - PrepareSpellScript(spell_warr_bloodthirst_SpellScript); + PrepareSpellScript(spell_warr_shattering_throw_SpellScript); - void HandleDamage(SpellEffIndex /*effIndex*/) + void HandleScript(SpellEffIndex effIndex) { - int32 damage = GetEffectValue(); - ApplyPct(damage, GetCaster()->GetTotalAttackPowerValue(BASE_ATTACK)); + PreventHitDefaultEffect(effIndex); + // remove shields, will still display immune to damage part if (Unit* target = GetHitUnit()) - { - damage = GetCaster()->SpellDamageBonusDone(target, GetSpellInfo(), uint32(damage), SPELL_DIRECT_DAMAGE); - damage = target->SpellDamageBonusTaken(GetCaster(), GetSpellInfo(), uint32(damage), SPELL_DIRECT_DAMAGE); - } - SetHitDamage(damage); + target->RemoveAurasWithMechanic(1 << MECHANIC_IMMUNE_SHIELD, AURA_REMOVE_BY_ENEMY_SPELL); + } + + void Register() + { + OnEffectHitTarget += SpellEffectFn(spell_warr_shattering_throw_SpellScript::HandleScript, EFFECT_0, SPELL_EFFECT_SCRIPT_EFFECT); + } + }; + + SpellScript* GetSpellScript() const + { + return new spell_warr_shattering_throw_SpellScript(); + } +}; + +// -1464 - Slam +class spell_warr_slam : public SpellScriptLoader +{ + public: + spell_warr_slam() : SpellScriptLoader("spell_warr_slam") { } + + class spell_warr_slam_SpellScript : public SpellScript + { + PrepareSpellScript(spell_warr_slam_SpellScript); + + bool Validate(SpellInfo const* /*spellInfo*/) + { + if (!sSpellMgr->GetSpellInfo(SPELL_WARRIOR_SLAM)) + return false; + return true; } void HandleDummy(SpellEffIndex /*effIndex*/) { - int32 damage = GetEffectValue(); - GetCaster()->CastCustomSpell(GetCaster(), SPELL_BLOODTHIRST, &damage, NULL, NULL, true, NULL); + int32 bp0 = GetEffectValue(); + if (GetHitUnit()) + GetCaster()->CastCustomSpell(GetHitUnit(), SPELL_WARRIOR_SLAM, &bp0, NULL, NULL, true, 0); } void Register() { - OnEffectHitTarget += SpellEffectFn(spell_warr_bloodthirst_SpellScript::HandleDamage, EFFECT_0, SPELL_EFFECT_SCHOOL_DAMAGE); - OnEffectHit += SpellEffectFn(spell_warr_bloodthirst_SpellScript::HandleDummy, EFFECT_1, SPELL_EFFECT_DUMMY); + OnEffectHitTarget += SpellEffectFn(spell_warr_slam_SpellScript::HandleDummy, EFFECT_0, SPELL_EFFECT_DUMMY); } }; SpellScript* GetSpellScript() const { - return new spell_warr_bloodthirst_SpellScript(); + return new spell_warr_slam_SpellScript(); } }; -enum BloodthirstHeal -{ - SPELL_BLOODTHIRST_DAMAGE = 23881, -}; - -class spell_warr_bloodthirst_heal : public SpellScriptLoader +// 12328, 18765, 35429 - Sweeping Strikes +class spell_warr_sweeping_strikes : public SpellScriptLoader { public: - spell_warr_bloodthirst_heal() : SpellScriptLoader("spell_warr_bloodthirst_heal") { } + spell_warr_sweeping_strikes() : SpellScriptLoader("spell_warr_sweeping_strikes") { } - class spell_warr_bloodthirst_heal_SpellScript : public SpellScript + class spell_warr_sweeping_strikes_AuraScript : public AuraScript { - PrepareSpellScript(spell_warr_bloodthirst_heal_SpellScript); + PrepareAuraScript(spell_warr_sweeping_strikes_AuraScript); - void HandleHeal(SpellEffIndex /*effIndex*/) + bool Validate(SpellInfo const* /*spellInfo*/) { - if (SpellInfo const* spellInfo = sSpellMgr->GetSpellInfo(SPELL_BLOODTHIRST_DAMAGE)) - SetHitHeal(GetCaster()->CountPctFromMaxHealth(spellInfo->Effects[EFFECT_1].CalcValue(GetCaster()))); + if (!sSpellMgr->GetSpellInfo(SPELL_WARRIOR_SWEEPING_STRIKES_EXTRA_ATTACK)) + return false; + return true; + } + + bool Load() + { + _procTarget = NULL; + return true; + } + + bool CheckProc(ProcEventInfo& eventInfo) + { + _procTarget = eventInfo.GetActor()->SelectNearbyTarget(eventInfo.GetProcTarget()); + return _procTarget; + } + + void HandleProc(AuraEffect const* aurEff, ProcEventInfo& /*eventInfo*/) + { + PreventDefaultAction(); + GetTarget()->CastSpell(_procTarget, SPELL_WARRIOR_SWEEPING_STRIKES_EXTRA_ATTACK, true, NULL, aurEff); } void Register() { - OnEffectHitTarget += SpellEffectFn(spell_warr_bloodthirst_heal_SpellScript::HandleHeal, EFFECT_0, SPELL_EFFECT_HEAL); + DoCheckProc += AuraCheckProcFn(spell_warr_sweeping_strikes_AuraScript::CheckProc); + OnEffectProc += AuraEffectProcFn(spell_warr_sweeping_strikes_AuraScript::HandleProc, EFFECT_0, SPELL_AURA_DUMMY); } + + private: + Unit* _procTarget; }; - SpellScript* GetSpellScript() const + AuraScript* GetAuraScript() const { - return new spell_warr_bloodthirst_heal_SpellScript(); + return new spell_warr_sweeping_strikes_AuraScript(); } }; -enum Overpower +// 50720 - Vigilance +class spell_warr_vigilance : public SpellScriptLoader { - SPELL_UNRELENTING_ASSAULT_RANK_1 = 46859, - SPELL_UNRELENTING_ASSAULT_RANK_2 = 46860, - SPELL_UNRELENTING_ASSAULT_TRIGGER_1 = 64849, - SPELL_UNRELENTING_ASSAULT_TRIGGER_2 = 64850, + public: + spell_warr_vigilance() : SpellScriptLoader("spell_warr_vigilance") { } + + class spell_warr_vigilance_AuraScript : public AuraScript + { + PrepareAuraScript(spell_warr_vigilance_AuraScript); + + bool Validate(SpellInfo const* /*spellInfo*/) + { + if (!sSpellMgr->GetSpellInfo(SPELL_WARRIOR_GLYPH_OF_VIGILANCE)) + return false; + if (!sSpellMgr->GetSpellInfo(SPELL_WARRIOR_VIGILANCE_PROC)) + return false; + if (!sSpellMgr->GetSpellInfo(SPELL_WARRIOR_VIGILANCE_REDIRECT_THREAT)) + return false; + if (!sSpellMgr->GetSpellInfo(SPELL_GEN_DAMAGE_REDUCTION_AURA)) + return false; + return true; + } + + bool Load() + { + _procTarget = NULL; + return true; + } + + void HandleApply(AuraEffect const* /*aurEff*/, AuraEffectHandleModes /*mode*/) + { + Unit* target = GetTarget(); + target->CastSpell(target, SPELL_GEN_DAMAGE_REDUCTION_AURA, true); + + if (Unit* caster = GetCaster()) + target->CastSpell(caster, SPELL_WARRIOR_VIGILANCE_REDIRECT_THREAT, true); + } + + void HandleAfterApply(AuraEffect const* /*aurEff*/, AuraEffectHandleModes /*mode*/) + { + //! WORKAROUND + //! this glyph is a proc + if (Unit* caster = GetCaster()) + { + if (AuraEffect const* glyph = caster->GetAuraEffect(SPELL_WARRIOR_GLYPH_OF_VIGILANCE, EFFECT_0)) + GetTarget()->ModifyRedirectThreat(glyph->GetAmount()); + } + } + + void HandleRemove(AuraEffect const* /*aurEff*/, AuraEffectHandleModes /*mode*/) + { + Unit* target = GetTarget(); + if (target->HasAura(SPELL_GEN_DAMAGE_REDUCTION_AURA) && + !(target->HasAura(SPELL_PALADIN_BLESSING_OF_SANCTUARY) || + target->HasAura(SPELL_PALADIN_GREATER_BLESSING_OF_SANCTUARY) || + target->HasAura(SPELL_PRIEST_RENEWED_HOPE))) + { + target->RemoveAurasDueToSpell(SPELL_GEN_DAMAGE_REDUCTION_AURA); + } + + target->ResetRedirectThreat(); + } + + bool CheckProc(ProcEventInfo& /*eventInfo*/) + { + _procTarget = GetCaster(); + return _procTarget; + } + + void HandleProc(AuraEffect const* aurEff, ProcEventInfo& /*eventInfo*/) + { + PreventDefaultAction(); + GetTarget()->CastSpell(_procTarget, SPELL_WARRIOR_VIGILANCE_PROC, true, NULL, aurEff); + } + + void Register() + { + OnEffectApply += AuraEffectApplyFn(spell_warr_vigilance_AuraScript::HandleApply, EFFECT_0, SPELL_AURA_PROC_TRIGGER_SPELL, AURA_EFFECT_HANDLE_REAL_OR_REAPPLY_MASK); + AfterEffectApply += AuraEffectApplyFn(spell_warr_vigilance_AuraScript::HandleAfterApply, EFFECT_0, SPELL_AURA_PROC_TRIGGER_SPELL, AURA_EFFECT_HANDLE_REAL_OR_REAPPLY_MASK); + OnEffectRemove += AuraEffectRemoveFn(spell_warr_vigilance_AuraScript::HandleRemove, EFFECT_0, SPELL_AURA_PROC_TRIGGER_SPELL, AURA_EFFECT_HANDLE_REAL_OR_REAPPLY_MASK); + DoCheckProc += AuraCheckProcFn(spell_warr_vigilance_AuraScript::CheckProc); + OnEffectProc += AuraEffectProcFn(spell_warr_vigilance_AuraScript::HandleProc, EFFECT_0, SPELL_AURA_PROC_TRIGGER_SPELL); + } + + private: + Unit* _procTarget; + }; + + AuraScript* GetAuraScript() const + { + return new spell_warr_vigilance_AuraScript(); + } }; -class spell_warr_overpower : public SpellScriptLoader +// 50725 Vigilance +class spell_warr_vigilance_trigger : public SpellScriptLoader { -public: - spell_warr_overpower() : SpellScriptLoader("spell_warr_overpower") { } - - class spell_warr_overpower_SpellScript : public SpellScript - { - PrepareSpellScript(spell_warr_overpower_SpellScript); + public: + spell_warr_vigilance_trigger() : SpellScriptLoader("spell_warr_vigilance_trigger") { } - void HandleEffect(SpellEffIndex /* effIndex */) + class spell_warr_vigilance_trigger_SpellScript : public SpellScript { - uint32 spellId = 0; - if (GetCaster()->HasAura(SPELL_UNRELENTING_ASSAULT_RANK_1)) - spellId = SPELL_UNRELENTING_ASSAULT_TRIGGER_1; - else if (GetCaster()->HasAura(SPELL_UNRELENTING_ASSAULT_RANK_2)) - spellId = SPELL_UNRELENTING_ASSAULT_TRIGGER_2; + PrepareSpellScript(spell_warr_vigilance_trigger_SpellScript); + + void HandleScript(SpellEffIndex effIndex) + { + PreventHitDefaultEffect(effIndex); - if (!spellId) - return; + // Remove Taunt cooldown + if (Player* target = GetHitPlayer()) + target->RemoveSpellCooldown(SPELL_WARRIOR_TAUNT, true); + } - if (Player* target = GetHitPlayer()) - if (target->HasUnitState(UNIT_STATE_CASTING)) - target->CastSpell(target, spellId, true); - } + void Register() + { + OnEffectHitTarget += SpellEffectFn(spell_warr_vigilance_trigger_SpellScript::HandleScript, EFFECT_0, SPELL_EFFECT_SCRIPT_EFFECT); + } + }; - void Register() + SpellScript* GetSpellScript() const { - OnEffectHitTarget += SpellEffectFn(spell_warr_overpower_SpellScript::HandleEffect, EFFECT_0, SPELL_EFFECT_ANY); + return new spell_warr_vigilance_trigger_SpellScript(); } - }; - - SpellScript* GetSpellScript() const - { - return new spell_warr_overpower_SpellScript(); - } }; void AddSC_warrior_spell_scripts() { - new spell_warr_last_stand(); - new spell_warr_improved_spell_reflection(); - new spell_warr_vigilance(); - new spell_warr_deep_wounds(); - new spell_warr_charge(); - new spell_warr_slam(); - new spell_warr_execute(); - new spell_warr_concussion_blow(); new spell_warr_bloodthirst(); new spell_warr_bloodthirst_heal(); + new spell_warr_charge(); + new spell_warr_concussion_blow(); + new spell_warr_damage_shield(); + new spell_warr_deep_wounds(); + new spell_warr_execute(); + new spell_warr_improved_spell_reflection(); + new spell_warr_intimidating_shout(); + new spell_warr_last_stand(); new spell_warr_overpower(); + new spell_warr_rend(); + new spell_warr_shattering_throw(); + new spell_warr_slam(); + new spell_warr_sweeping_strikes(); + new spell_warr_vigilance(); + new spell_warr_vigilance_trigger(); } diff --git a/src/server/scripts/World/achievement_scripts.cpp b/src/server/scripts/World/achievement_scripts.cpp index 41a32185620..d0ffe5214db 100644 --- a/src/server/scripts/World/achievement_scripts.cpp +++ b/src/server/scripts/World/achievement_scripts.cpp @@ -315,6 +315,30 @@ class achievement_not_even_a_scratch : public AchievementCriteriaScript } }; +enum FlirtWithDisaster +{ + AURA_PERFUME_FOREVER = 70235, + AURA_PERFUME_ENCHANTRESS = 70234, + AURA_PERFUME_VICTORY = 70233, +}; + +class achievement_flirt_with_disaster_perf_check : public AchievementCriteriaScript +{ + public: + achievement_flirt_with_disaster_perf_check() : AchievementCriteriaScript("achievement_flirt_with_disaster_perf_check") { } + + bool OnCheck(Player* player, Unit* /*target*/) + { + if (!player) + return false; + + if (player->HasAura(AURA_PERFUME_FOREVER) || player->HasAura(AURA_PERFUME_ENCHANTRESS) || player->HasAura(AURA_PERFUME_VICTORY)) + return true; + + return false; + } +}; + void AddSC_achievement_scripts() { new achievement_resilient_victory(); @@ -333,4 +357,5 @@ void AddSC_achievement_scripts() new achievement_bg_sa_defense_of_ancients(); new achievement_tilted(); new achievement_not_even_a_scratch(); + new achievement_flirt_with_disaster_perf_check(); } diff --git a/src/server/scripts/World/areatrigger_scripts.cpp b/src/server/scripts/World/areatrigger_scripts.cpp index c031c4a3b4d..c8436dfa1f0 100644 --- a/src/server/scripts/World/areatrigger_scripts.cpp +++ b/src/server/scripts/World/areatrigger_scripts.cpp @@ -425,6 +425,71 @@ class AreaTrigger_at_area_52_entrance : public AreaTriggerScript std::map<uint32, time_t> _triggerTimes; }; +/*###### + ## at_frostgrips_hollow + ######*/ + +enum FrostgripsHollow +{ + QUEST_THE_LONESOME_WATCHER = 12877, + + NPC_STORMFORGED_MONITOR = 29862, + NPC_STORMFORGED_ERADICTOR = 29861, + + TYPE_WAYPOINT = 0, + DATA_START = 0 +}; + +Position const stormforgedMonitorPosition = {6963.95f, 45.65f, 818.71f, 4.948f}; +Position const stormforgedEradictorPosition = {6983.18f, 7.15f, 806.33f, 2.228f}; + +class AreaTrigger_at_frostgrips_hollow : public AreaTriggerScript +{ +public: + AreaTrigger_at_frostgrips_hollow() : AreaTriggerScript("at_frostgrips_hollow") + { + stormforgedMonitorGUID = 0; + stormforgedEradictorGUID = 0; + } + + bool OnTrigger(Player* player, AreaTriggerEntry const* /* trigger */) + { + if (player->GetQuestStatus(QUEST_THE_LONESOME_WATCHER) != QUEST_STATUS_INCOMPLETE) + return false; + + Creature* stormforgedMonitor = Creature::GetCreature(*player, stormforgedMonitorGUID); + if (stormforgedMonitor) + return false; + + Creature* stormforgedEradictor = Creature::GetCreature(*player, stormforgedEradictorGUID); + if (stormforgedEradictor) + return false; + + stormforgedMonitor = player->SummonCreature(NPC_STORMFORGED_MONITOR, stormforgedMonitorPosition, TEMPSUMMON_TIMED_DESPAWN_OUT_OF_COMBAT, 60000); + if (stormforgedMonitor) + { + stormforgedMonitorGUID = stormforgedMonitor->GetGUID(); + stormforgedMonitor->SetWalk(false); + /// The npc would search an alternative way to get to the last waypoint without this unit state. + stormforgedMonitor->AddUnitState(UNIT_STATE_IGNORE_PATHFINDING); + stormforgedMonitor->GetMotionMaster()->MovePath(NPC_STORMFORGED_MONITOR * 100, false); + } + + stormforgedEradictor = player->SummonCreature(NPC_STORMFORGED_ERADICTOR, stormforgedEradictorPosition, TEMPSUMMON_TIMED_DESPAWN_OUT_OF_COMBAT, 60000); + if (stormforgedEradictor) + { + stormforgedEradictorGUID = stormforgedEradictor->GetGUID(); + stormforgedEradictor->GetMotionMaster()->MovePath(NPC_STORMFORGED_ERADICTOR * 100, false); + } + + return true; + } + +private: + uint64 stormforgedMonitorGUID; + uint64 stormforgedEradictorGUID; +}; + void AddSC_areatrigger_scripts() { new AreaTrigger_at_coilfang_waterfall(); @@ -436,4 +501,5 @@ void AddSC_areatrigger_scripts() new AreaTrigger_at_nats_landing(); new AreaTrigger_at_brewfest(); new AreaTrigger_at_area_52_entrance(); + new AreaTrigger_at_frostgrips_hollow(); } diff --git a/src/server/scripts/World/boss_emerald_dragons.cpp b/src/server/scripts/World/boss_emerald_dragons.cpp index 7699712a1e4..4e95a6162d3 100644 --- a/src/server/scripts/World/boss_emerald_dragons.cpp +++ b/src/server/scripts/World/boss_emerald_dragons.cpp @@ -113,7 +113,7 @@ struct emerald_dragonAI : public WorldBossAI } // Execute and reschedule base events shared between all Emerald Dragons - void ExecuteEvent(uint32 const eventId) + void ExecuteEvent(uint32 eventId) { switch (eventId) { @@ -137,7 +137,7 @@ struct emerald_dragonAI : public WorldBossAI } } - void UpdateAI(uint32 const diff) + void UpdateAI(uint32 diff) { if (!UpdateVictim()) return; @@ -177,7 +177,7 @@ class npc_dream_fog : public CreatureScript _roamTimer = 0; } - void UpdateAI(uint32 const diff) + void UpdateAI(uint32 diff) { if (!UpdateVictim()) return; @@ -275,7 +275,7 @@ class boss_ysondre : public CreatureScript } } - void ExecuteEvent(uint32 const eventId) + void ExecuteEvent(uint32 eventId) { switch (eventId) { @@ -304,7 +304,7 @@ class boss_ysondre : public CreatureScript * --- Dragonspecific scripts and handling: LETHON * --- * - * TODO: + * @todo * - Spell: Shadow bolt whirl casts needs custom handling (spellscript) */ @@ -370,7 +370,7 @@ class boss_lethon : public CreatureScript } } - void ExecuteEvent(uint32 const eventId) + void ExecuteEvent(uint32 eventId) { switch (eventId) { @@ -490,7 +490,7 @@ class boss_emeriss : public CreatureScript } } - void ExecuteEvent(uint32 const eventId) + void ExecuteEvent(uint32 eventId) { switch (eventId) { @@ -604,7 +604,7 @@ class boss_taerar : public CreatureScript } } - void ExecuteEvent(uint32 const eventId) + void ExecuteEvent(uint32 eventId) { switch (eventId) { @@ -622,7 +622,7 @@ class boss_taerar : public CreatureScript } } - void UpdateAI(uint32 const diff) + void UpdateAI(uint32 diff) { if (!me->isInCombat()) return; diff --git a/src/server/scripts/World/go_scripts.cpp b/src/server/scripts/World/go_scripts.cpp index 5ed45764ed6..f57b6b8942c 100644 --- a/src/server/scripts/World/go_scripts.cpp +++ b/src/server/scripts/World/go_scripts.cpp @@ -251,7 +251,7 @@ class go_tablet_of_the_seven : public GameObjectScript public: go_tablet_of_the_seven() : GameObjectScript("go_tablet_of_the_seven") { } - //TODO: use gossip option ("Transcript the Tablet") instead, if Trinity adds support. + /// @todo use gossip option ("Transcript the Tablet") instead, if Trinity adds support. bool OnGossipHello(Player* player, GameObject* go) { if (go->GetGoType() != GAMEOBJECT_TYPE_QUESTGIVER) @@ -1072,7 +1072,7 @@ public: Quest const* qInfo = sObjectMgr->GetQuestTemplate(QUEST_PRISONERS_OF_WYRMSKULL); if (qInfo) { - //TODO: prisoner should help player for a short period of time + /// @todo prisoner should help player for a short period of time player->KilledMonsterCredit(qInfo->RequiredNpcOrGo[0], 0); pPrisoner->DisappearAndDie(); } diff --git a/src/server/scripts/World/guards.cpp b/src/server/scripts/World/guards.cpp index f07a9ed7671..bff30f6cca5 100644 --- a/src/server/scripts/World/guards.cpp +++ b/src/server/scripts/World/guards.cpp @@ -70,7 +70,7 @@ public: DoCast(who, spell->Id); } - void UpdateAI(const uint32 diff) + void UpdateAI(uint32 diff) { //Always decrease our global cooldown first if (globalCooldown > diff) @@ -273,7 +273,7 @@ public: canTeleport = false; } - void UpdateAI(const uint32 diff) + void UpdateAI(uint32 diff) { if (!UpdateVictim()) return; @@ -338,7 +338,7 @@ public: canTeleport = false; } - void UpdateAI(const uint32 diff) + void UpdateAI(uint32 diff) { if (!UpdateVictim()) return; diff --git a/src/server/scripts/World/mob_generic_creature.cpp b/src/server/scripts/World/mob_generic_creature.cpp index 174ba8870d1..d0ac142e050 100644 --- a/src/server/scripts/World/mob_generic_creature.cpp +++ b/src/server/scripts/World/mob_generic_creature.cpp @@ -55,7 +55,7 @@ public: IsSelfRooted = true; } - void UpdateAI(const uint32 diff) + void UpdateAI(uint32 diff) { //Always decrease our global cooldown first if (GlobalCooldown > diff) @@ -186,7 +186,7 @@ public: uint32 timer, interval; const SpellInfo* spell; - void UpdateAI(const uint32 diff) + void UpdateAI(uint32 diff) { if (timer <= diff) { diff --git a/src/server/scripts/World/npcs_special.cpp b/src/server/scripts/World/npcs_special.cpp index aaac8ee4b83..12796d5f88e 100644 --- a/src/server/scripts/World/npcs_special.cpp +++ b/src/server/scripts/World/npcs_special.cpp @@ -344,7 +344,7 @@ public: void EnterCombat(Unit* /*who*/) {} - void UpdateAI(uint32 const diff) + void UpdateAI(uint32 diff) { // Reset flags after a certain time has passed so that the next player has to start the 'event' again if (me->HasFlag(UNIT_NPC_FLAGS, UNIT_NPC_FLAG_QUESTGIVER)) @@ -444,7 +444,7 @@ public: me->SendMessageToSet(&data, true); } - void UpdateAI(uint32 const diff) + void UpdateAI(uint32 diff) { if (!Active) { @@ -689,7 +689,7 @@ public: } } - void UpdateAI(uint32 const diff); + void UpdateAI(uint32 diff); void EnterCombat(Unit* /*who*/){} }; @@ -798,7 +798,7 @@ public: } } - void UpdateAI(uint32 const /*diff*/) + void UpdateAI(uint32 /*diff*/) { //lower HP on every world tick makes it a useful counter, not officlone though if (me->isAlive() && me->GetHealth() > 6) @@ -824,7 +824,7 @@ public: } }; -void npc_doctor::npc_doctorAI::UpdateAI(uint32 const diff) +void npc_doctor::npc_doctorAI::UpdateAI(uint32 diff) { if (Event && SummonPatientCount >= 20) { @@ -881,7 +881,7 @@ void npc_doctor::npc_doctorAI::UpdateAI(uint32 const diff) ## npc_garments_of_quests ######*/ -//TODO: get text for each NPC +/// @todo get text for each NPC enum Garments { @@ -1056,7 +1056,7 @@ public: } - void UpdateAI(uint32 const diff) + void UpdateAI(uint32 diff) { if (CanRun && !me->isInCombat()) { @@ -1128,7 +1128,7 @@ public: { } - void UpdateAI(uint32 const /*diff*/) + void UpdateAI(uint32 /*diff*/) { if (!UpdateVictim()) return; @@ -1540,7 +1540,7 @@ public: void AttackStart(Unit* /*who*/) {} void MoveInLineOfSight(Unit* /*who*/) {} - void UpdateAI(uint32 const diff) + void UpdateAI(uint32 diff) { if (ExplosionTimer <= diff) { @@ -1656,7 +1656,7 @@ public: } } - void UpdateAI(uint32 const diff) + void UpdateAI(uint32 diff) { if (!UpdateVictim()) return; @@ -1734,7 +1734,7 @@ public: void EnterCombat(Unit* /*who*/){} - void UpdateAI(uint32 const diff) + void UpdateAI(uint32 diff) { if (me->HasAura(20372)) { @@ -1921,7 +1921,7 @@ public: despawnTimer = 4 * IN_MILLISECONDS; } - void UpdateAI(const uint32 diff) + void UpdateAI(uint32 diff) { if (despawnTimer > 0) { @@ -1981,10 +1981,11 @@ class npc_training_dummy : public CreatureScript public: npc_training_dummy() : CreatureScript("npc_training_dummy") { } - struct npc_training_dummyAI : Scripted_NoMovementAI + struct npc_training_dummyAI : ScriptedAI { - npc_training_dummyAI(Creature* creature) : Scripted_NoMovementAI(creature) + npc_training_dummyAI(Creature* creature) : ScriptedAI(creature) { + SetCombatMovement(false); entry = creature->GetEntry(); } @@ -2015,13 +2016,7 @@ public: damage = 0; } - void EnterCombat(Unit* /*who*/) - { - if (entry != NPC_ADVANCED_TARGET_DUMMY && entry != NPC_TARGET_DUMMY) - return; - } - - void UpdateAI(uint32 const diff) + void UpdateAI(uint32 diff) { if (!UpdateVictim()) return; @@ -2115,7 +2110,7 @@ public: me->ApplySpellImmune(0, IMMUNITY_SCHOOL, SPELL_SCHOOL_MASK_FIRE, true); } - void UpdateAI(const uint32 diff) + void UpdateAI(uint32 diff) { if (!UpdateVictim()) return; @@ -2179,7 +2174,7 @@ public: me->ApplySpellImmune(0, IMMUNITY_SCHOOL, SPELL_SCHOOL_MASK_NATURE, true); } - void UpdateAI(const uint32 diff) + void UpdateAI(uint32 diff) { if (!UpdateVictim()) return; @@ -2509,11 +2504,11 @@ public: break; case GOSSIP_ACTION_INFO_DEF + 8: player->CLOSE_GOSSIP_MENU(); - player->AddItem(ITEM_KEY_TO_THE_FOCUSING_IRIS,1); + player->AddItem(ITEM_KEY_TO_THE_FOCUSING_IRIS, 1); break; case GOSSIP_ACTION_INFO_DEF + 9: player->CLOSE_GOSSIP_MENU(); - player->AddItem(ITEM_HC_KEY_TO_THE_FOCUSING_IRIS,1); + player->AddItem(ITEM_HC_KEY_TO_THE_FOCUSING_IRIS, 1); break; } return true; @@ -2828,7 +2823,7 @@ public: { if (!me->FindNearestCreature(NPC_OMEN, 100.0f, false) && me->GetDistance2d(omenSummonPos.GetPositionX(), omenSummonPos.GetPositionY()) <= 100.0f) { - switch (urand(0,9)) + switch (urand(0, 9)) { case 0: case 1: @@ -2909,14 +2904,14 @@ public: void EnterCombat(Unit* /*who*/) { } - void DoAction(const int32 /*param*/) + void DoAction(int32 /*param*/) { inLove = true; if (Unit* owner = me->GetOwner()) owner->CastSpell(owner, SPELL_SPRING_FLING, true); } - void UpdateAI(const uint32 diff) + void UpdateAI(uint32 diff) { if (inLove) { @@ -2956,31 +2951,6 @@ public: }; }; -/*###### -## npc_generic_harpoon_cannon -######*/ - -class npc_generic_harpoon_cannon : public CreatureScript -{ -public: - npc_generic_harpoon_cannon() : CreatureScript("npc_generic_harpoon_cannon") { } - - struct npc_generic_harpoon_cannonAI : public ScriptedAI - { - npc_generic_harpoon_cannonAI(Creature* creature) : ScriptedAI(creature) {} - - void Reset() - { - me->SetUnitMovementFlags(MOVEMENTFLAG_ROOT); - } - }; - - CreatureAI* GetAI(Creature* creature) const - { - return new npc_generic_harpoon_cannonAI(creature); - } -}; - void AddSC_npcs_special() { new npc_air_force_bots(); @@ -3012,5 +2982,4 @@ void AddSC_npcs_special() new npc_earth_elemental(); new npc_firework(); new npc_spring_rabbit(); - new npc_generic_harpoon_cannon(); } diff --git a/src/server/shared/CMakeLists.txt b/src/server/shared/CMakeLists.txt index 86d0cbf613b..01ccf648b31 100644 --- a/src/server/shared/CMakeLists.txt +++ b/src/server/shared/CMakeLists.txt @@ -50,6 +50,7 @@ set(shared_STAT_SRCS include_directories( ${CMAKE_BINARY_DIR} + ${CMAKE_SOURCE_DIR}/dep/recastnavigation/Detour ${CMAKE_SOURCE_DIR}/dep/SFMT ${CMAKE_SOURCE_DIR}/dep/sockets/include ${CMAKE_SOURCE_DIR}/dep/utf8cpp diff --git a/src/server/shared/Common.h b/src/server/shared/Common.h index d0c3490bc2d..70ee32d2868 100644 --- a/src/server/shared/Common.h +++ b/src/server/shared/Common.h @@ -20,7 +20,7 @@ #define TRINITYCORE_COMMON_H // config.h needs to be included 1st -// TODO this thingy looks like hack, but its not, need to +/// @todo this thingy looks like hack, but its not, need to // make separate header however, because It makes mess here. #ifdef HAVE_CONFIG_H // Remove Some things that we will define @@ -116,7 +116,7 @@ #define I32FMT "%08I32X" #define I64FMT "%016I64X" #define snprintf _snprintf -#define atoll __atoi64 +#define atoll _atoi64 #define vsnprintf _vsnprintf #define finite(X) _finite(X) #define llabs _abs64 @@ -170,7 +170,7 @@ enum LocaleConstant }; const uint8 TOTAL_LOCALES = 9; -const LocaleConstant DEFAULT_LOCALE = LOCALE_enUS; +#define DEFAULT_LOCALE LOCALE_enUS #define MAX_LOCALES 8 #define MAX_ACCOUNT_TUTORIAL_VALUES 8 diff --git a/src/server/shared/Cryptography/WardenKeyGeneration.h b/src/server/shared/Cryptography/WardenKeyGeneration.h index 5c04da38dc9..6d5fd563ba3 100644 --- a/src/server/shared/Cryptography/WardenKeyGeneration.h +++ b/src/server/shared/Cryptography/WardenKeyGeneration.h @@ -73,7 +73,7 @@ private: SHA1Hash sh; uint32 taken; - uint8 o0[20],o1[20],o2[20]; + uint8 o0[20], o1[20], o2[20]; }; #endif diff --git a/src/server/shared/Database/DatabaseWorkerPool.h b/src/server/shared/Database/DatabaseWorkerPool.h index 34b7c5083e3..524a3de2628 100644 --- a/src/server/shared/Database/DatabaseWorkerPool.h +++ b/src/server/shared/Database/DatabaseWorkerPool.h @@ -31,6 +31,9 @@ #include "QueryHolder.h" #include "AdhocStatement.h" +#define MIN_MYSQL_SERVER_VERSION 50100u +#define MIN_MYSQL_CLIENT_VERSION 50100u + class PingOperation : public SQLOperation { //! Operation for idle delaythreads @@ -53,6 +56,7 @@ class DatabaseWorkerPool _connections.resize(IDX_SIZE); WPFatal (mysql_thread_safe(), "Used MySQL library isn't thread-safe."); + WPFatal (mysql_get_client_version() >= MIN_MYSQL_CLIENT_VERSION, "TrinityCore does not support MySQL versions below 5.1"); } ~DatabaseWorkerPool() @@ -73,6 +77,8 @@ class DatabaseWorkerPool { T* t = new T(_queue, _connectionInfo); res &= t->Open(); + if (res) // only check mysql version if connection is valid + WPFatal(mysql_get_server_version(t->GetHandle()) >= MIN_MYSQL_SERVER_VERSION, "TrinityCore does not support MySQL versions below 5.1"); _connections[IDX_ASYNC][i] = t; ++_connectionCount[IDX_ASYNC]; } @@ -216,7 +222,7 @@ class DatabaseWorkerPool //! Directly executes an SQL query in string format that will block the calling thread until finished. //! Returns reference counted auto pointer, no need for manual memory management in upper level code. - QueryResult Query(const char* sql, MySQLConnection* conn = NULL) + QueryResult Query(const char* sql, T* conn = NULL) { if (!conn) conn = GetFreeConnection(); @@ -235,7 +241,7 @@ class DatabaseWorkerPool //! Directly executes an SQL query in string format -with variable args- that will block the calling thread until finished. //! Returns reference counted auto pointer, no need for manual memory management in upper level code. - QueryResult PQuery(const char* sql, MySQLConnection* conn, ...) + QueryResult PQuery(const char* sql, T* conn, ...) { if (!sql) return QueryResult(NULL); @@ -374,7 +380,7 @@ class DatabaseWorkerPool //! were appended to the transaction will be respected during execution. void DirectCommitTransaction(SQLTransaction& transaction) { - MySQLConnection* con = GetFreeConnection(); + T* con = GetFreeConnection(); if (con->ExecuteTransaction(transaction)) { con->Unlock(); // OK, operation succesful @@ -382,7 +388,7 @@ class DatabaseWorkerPool } //! Handle MySQL Errno 1213 without extending deadlock to the core itself - //! TODO: More elegant way + /// @todo More elegant way if (con->GetLastError() == 1213) { uint8 loopBreaker = 5; @@ -484,17 +490,17 @@ class DatabaseWorkerPool { uint8 i = 0; size_t num_cons = _connectionCount[IDX_SYNCH]; + T* t = NULL; //! Block forever until a connection is free for (;;) { - T* t = _connections[IDX_SYNCH][++i % num_cons]; + t = _connections[IDX_SYNCH][++i % num_cons]; //! Must be matched with t->Unlock() or you will get deadlocks if (t->LockIfReady()) - return t; + break; } - //! This will be called when Celine Dion learns to sing - return NULL; + return t; } char const* GetDatabaseName() const diff --git a/src/server/shared/Database/Implementation/CharacterDatabase.cpp b/src/server/shared/Database/Implementation/CharacterDatabase.cpp index cfbd4b2bc45..2b57693db9b 100644 --- a/src/server/shared/Database/Implementation/CharacterDatabase.cpp +++ b/src/server/shared/Database/Implementation/CharacterDatabase.cpp @@ -38,6 +38,10 @@ void CharacterDatabaseConnection::DoPrepareStatements() PrepareStatement(CHAR_SEL_GUID_BY_NAME_FILTER, "SELECT guid, name FROM characters WHERE name LIKE CONCAT('%%', ?, '%%')", CONNECTION_SYNCH); PrepareStatement(CHAR_SEL_BANINFO_LIST, "SELECT bandate, unbandate, bannedby, banreason FROM character_banned WHERE guid = ? ORDER BY unbandate", CONNECTION_SYNCH); PrepareStatement(CHAR_SEL_BANNED_NAME, "SELECT characters.name FROM characters, character_banned WHERE character_banned.guid = ? AND character_banned.guid = characters.guid", CONNECTION_SYNCH); + PrepareStatement(CHAR_SEL_MAIL_LIST_COUNT, "SELECT COUNT(id) FROM mail WHERE receiver = ? ", CONNECTION_SYNCH); + PrepareStatement(CHAR_SEL_MAIL_LIST_INFO, "SELECT id, sender, (SELECT name FROM characters WHERE guid = sender) AS sendername, receiver, (SELECT name FROM characters WHERE guid = receiver) AS receivername, " + "subject, deliver_time, expire_time, money, has_items FROM mail WHERE receiver = ? ", CONNECTION_SYNCH); + PrepareStatement(CHAR_SEL_MAIL_LIST_ITEMS, "SELECT itemEntry,count FROM item_instance WHERE guid = ?", CONNECTION_SYNCH); PrepareStatement(CHAR_SEL_ENUM, "SELECT c.guid, c.name, c.race, c.class, c.gender, c.playerBytes, c.playerBytes2, c.level, c.zone, c.map, c.position_x, c.position_y, c.position_z, " "gm.guildid, c.playerFlags, c.at_login, cp.entry, cp.modelid, cp.level, c.equipmentCache, cb.guid " "FROM characters AS c LEFT JOIN character_pet AS cp ON c.guid = cp.owner AND cp.slot = ? LEFT JOIN guild_member AS gm ON c.guid = gm.guid " @@ -101,6 +105,9 @@ void CharacterDatabaseConnection::DoPrepareStatements() PrepareStatement(CHAR_SEL_CHARACTER_SPELLCOOLDOWNS, "SELECT spell, item, time FROM character_spell_cooldown WHERE guid = ?", CONNECTION_ASYNC); PrepareStatement(CHAR_SEL_CHARACTER_DECLINEDNAMES, "SELECT genitive, dative, accusative, instrumental, prepositional FROM character_declinedname WHERE guid = ?", CONNECTION_ASYNC); PrepareStatement(CHAR_SEL_GUILD_MEMBER, "SELECT guildid, rank FROM guild_member WHERE guid = ?", CONNECTION_BOTH); + PrepareStatement(CHAR_SEL_GUILD_MEMBER_EXTENDED, "SELECT g.guildid, g.name, gr.rname, gm.pnote, gm.offnote " + "FROM guild g JOIN guild_member gm ON g.guildid = gm.guildid " + "JOIN guild_rank gr ON g.guildid = gr.guildid AND gm.rank = gr.rid WHERE gm.guid = ?", CONNECTION_BOTH); PrepareStatement(CHAR_SEL_CHARACTER_ACHIEVEMENTS, "SELECT achievement, date FROM character_achievement WHERE guid = ?", CONNECTION_ASYNC); PrepareStatement(CHAR_SEL_CHARACTER_CRITERIAPROGRESS, "SELECT criteria, counter, date FROM character_achievement_progress WHERE guid = ?", CONNECTION_ASYNC); PrepareStatement(CHAR_SEL_CHARACTER_EQUIPMENTSETS, "SELECT setguid, setindex, name, iconname, ignore_mask, item0, item1, item2, item3, item4, item5, item6, item7, item8, " @@ -111,7 +118,7 @@ void CharacterDatabaseConnection::DoPrepareStatements() PrepareStatement(CHAR_SEL_CHARACTER_SKILLS, "SELECT skill, value, max FROM character_skills WHERE guid = ?", CONNECTION_ASYNC); PrepareStatement(CHAR_SEL_CHARACTER_RANDOMBG, "SELECT guid FROM character_battleground_random WHERE guid = ?", CONNECTION_ASYNC); PrepareStatement(CHAR_SEL_CHARACTER_BANNED, "SELECT guid FROM character_banned WHERE guid = ? AND active = 1", CONNECTION_ASYNC); - PrepareStatement(CHAR_SEL_CHARACTER_QUESTSTATUSREW, "SELECT quest FROM character_queststatus_rewarded WHERE guid = ?", CONNECTION_ASYNC); + PrepareStatement(CHAR_SEL_CHARACTER_QUESTSTATUSREW, "SELECT quest FROM character_queststatus_rewarded WHERE guid = ? AND active = 1", CONNECTION_ASYNC); PrepareStatement(CHAR_SEL_ACCOUNT_INSTANCELOCKTIMES, "SELECT instanceId, releaseTime FROM account_instance_times WHERE accountId = ?", CONNECTION_ASYNC); // End LoginQueryHolder content @@ -144,6 +151,7 @@ void CharacterDatabaseConnection::DoPrepareStatements() PrepareStatement(CHAR_UPD_ITEM_INSTANCE, "UPDATE item_instance SET itemEntry = ?, owner_guid = ?, creatorGuid = ?, giftCreatorGuid = ?, count = ?, duration = ?, charges = ?, flags = ?, enchantments = ?, randomPropertyId = ?, durability = ?, playedTime = ?, text = ? WHERE guid = ?", CONNECTION_ASYNC); PrepareStatement(CHAR_UPD_ITEM_INSTANCE_ON_LOAD, "UPDATE item_instance SET duration = ?, flags = ?, durability = ? WHERE guid = ?", CONNECTION_ASYNC); PrepareStatement(CHAR_DEL_ITEM_INSTANCE, "DELETE FROM item_instance WHERE guid = ?", CONNECTION_ASYNC); + PrepareStatement(CHAR_DEL_ITEM_INSTANCE_BY_OWNER, "DELETE FROM item_instance WHERE owner_guid = ?", CONNECTION_ASYNC); PrepareStatement(CHAR_UPD_GIFT_OWNER, "UPDATE character_gifts SET guid = ? WHERE item_guid = ?", CONNECTION_ASYNC); PrepareStatement(CHAR_DEL_GIFT, "DELETE FROM character_gifts WHERE item_guid = ?", CONNECTION_ASYNC); PrepareStatement(CHAR_SEL_CHARACTER_GIFT_BY_ITEM, "SELECT entry, flags FROM character_gifts WHERE item_guid = ?", CONNECTION_SYNCH); @@ -374,7 +382,8 @@ void CharacterDatabaseConnection::DoPrepareStatements() PrepareStatement(CHAR_UPD_GROUP_DIFFICULTY, "UPDATE groups SET difficulty = ? WHERE guid = ?", CONNECTION_ASYNC); PrepareStatement(CHAR_UPD_GROUP_RAID_DIFFICULTY, "UPDATE groups SET raiddifficulty = ? WHERE guid = ?", CONNECTION_ASYNC); PrepareStatement(CHAR_DEL_ALL_GM_TICKETS, "TRUNCATE TABLE gm_tickets", CONNECTION_ASYNC); - PrepareStatement(CHAR_DEL_INVALID_SPELL, "DELETE FROM character_talent WHERE spell = ?", CONNECTION_ASYNC); + PrepareStatement(CHAR_DEL_INVALID_SPELL_TALENTS, "DELETE FROM character_talent WHERE spell = ?", CONNECTION_ASYNC); + PrepareStatement(CHAR_DEL_INVALID_SPELL_SPELLS, "DELETE FROM character_spell WHERE spell = ?", CONNECTION_ASYNC); PrepareStatement(CHAR_UPD_DELETE_INFO, "UPDATE characters SET deleteInfos_Name = name, deleteInfos_Account = account, deleteDate = UNIX_TIMESTAMP(), name = '', account = 0 WHERE guid = ?", CONNECTION_ASYNC); PrepareStatement(CHAR_UDP_RESTORE_DELETE_INFO, "UPDATE characters SET name = ?, account = ?, deleteDate = NULL, deleteInfos_Name = NULL, deleteInfos_Account = NULL WHERE deleteDate IS NOT NULL AND guid = ?", CONNECTION_ASYNC); PrepareStatement(CHAR_UPD_ZONE, "UPDATE characters SET zone = ? WHERE guid = ?", CONNECTION_ASYNC); @@ -509,8 +518,11 @@ void CharacterDatabaseConnection::DoPrepareStatements() PrepareStatement(CHAR_UPD_MAIL, "UPDATE mail SET has_items = ?, expire_time = ?, deliver_time = ?, money = ?, cod = ?, checked = ? WHERE id = ?", CONNECTION_ASYNC); PrepareStatement(CHAR_REP_CHAR_QUESTSTATUS, "REPLACE INTO character_queststatus (guid, quest, status, explored, timer, mobcount1, mobcount2, mobcount3, mobcount4, itemcount1, itemcount2, itemcount3, itemcount4, playercount) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)", CONNECTION_ASYNC); PrepareStatement(CHAR_DEL_CHAR_QUESTSTATUS_BY_QUEST, "DELETE FROM character_queststatus WHERE guid = ? AND quest = ?", CONNECTION_ASYNC); - PrepareStatement(CHAR_INS_CHAR_QUESTSTATUS, "INSERT IGNORE INTO character_queststatus_rewarded (guid, quest) VALUES (?, ?)", CONNECTION_ASYNC); + PrepareStatement(CHAR_INS_CHAR_QUESTSTATUS_REWARDED, "INSERT IGNORE INTO character_queststatus_rewarded (guid, quest, active) VALUES (?, ?, 1)", CONNECTION_ASYNC); PrepareStatement(CHAR_DEL_CHAR_QUESTSTATUS_REWARDED_BY_QUEST, "DELETE FROM character_queststatus_rewarded WHERE guid = ? AND quest = ?", CONNECTION_ASYNC); + PrepareStatement(CHAR_UPD_CHAR_QUESTSTATUS_REWARDED_FACTION_CHANGE, "UPDATE character_queststatus_rewarded SET quest = ? WHERE quest = ? AND guid = ?", CONNECTION_ASYNC); + PrepareStatement(CHAR_UPD_CHAR_QUESTSTATUS_REWARDED_ACTIVE, "UPDATE character_queststatus_rewarded SET active = 1 WHERE guid = ?", CONNECTION_ASYNC); + PrepareStatement(CHAR_UPD_CHAR_QUESTSTATUS_REWARDED_ACTIVE_BY_QUEST, "UPDATE character_queststatus_rewarded SET active = 0 WHERE quest = ? AND guid = ?", CONNECTION_ASYNC); PrepareStatement(CHAR_DEL_CHAR_SKILL_BY_SKILL, "DELETE FROM character_skills WHERE guid = ? AND skill = ?", CONNECTION_ASYNC); PrepareStatement(CHAR_INS_CHAR_SKILLS, "INSERT INTO character_skills (guid, skill, value, max) VALUES (?, ?, ?, ?)", CONNECTION_ASYNC); PrepareStatement(CHAR_UDP_CHAR_SKILLS, "UPDATE character_skills SET value = ?, max = ? WHERE guid = ? AND skill = ?", CONNECTION_ASYNC); diff --git a/src/server/shared/Database/Implementation/CharacterDatabase.h b/src/server/shared/Database/Implementation/CharacterDatabase.h index bfa7bc48cf5..3eb6a726007 100644 --- a/src/server/shared/Database/Implementation/CharacterDatabase.h +++ b/src/server/shared/Database/Implementation/CharacterDatabase.h @@ -58,6 +58,9 @@ enum CharacterDatabaseStatements CHAR_SEL_GUID_BY_NAME_FILTER, CHAR_SEL_BANINFO_LIST, CHAR_SEL_BANNED_NAME, + CHAR_SEL_MAIL_LIST_COUNT, + CHAR_SEL_MAIL_LIST_INFO, + CHAR_SEL_MAIL_LIST_ITEMS, CHAR_SEL_ENUM, CHAR_SEL_ENUM_DECLINED_NAME, CHAR_SEL_FREE_NAME, @@ -105,6 +108,7 @@ enum CharacterDatabaseStatements CHAR_SEL_CHARACTER_SPELLCOOLDOWNS, CHAR_SEL_CHARACTER_DECLINEDNAMES, CHAR_SEL_GUILD_MEMBER, + CHAR_SEL_GUILD_MEMBER_EXTENDED, CHAR_SEL_CHARACTER_ARENAINFO, CHAR_SEL_CHARACTER_ACHIEVEMENTS, CHAR_SEL_CHARACTER_CRITERIAPROGRESS, @@ -144,6 +148,7 @@ enum CharacterDatabaseStatements CHAR_UPD_ITEM_INSTANCE, CHAR_UPD_ITEM_INSTANCE_ON_LOAD, CHAR_DEL_ITEM_INSTANCE, + CHAR_DEL_ITEM_INSTANCE_BY_OWNER, CHAR_UPD_GIFT_OWNER, CHAR_DEL_GIFT, CHAR_SEL_CHARACTER_GIFT_BY_ITEM, @@ -315,7 +320,8 @@ enum CharacterDatabaseStatements CHAR_UPD_GROUP_MEMBER_FLAG, CHAR_UPD_GROUP_DIFFICULTY, CHAR_UPD_GROUP_RAID_DIFFICULTY, - CHAR_DEL_INVALID_SPELL, + CHAR_DEL_INVALID_SPELL_SPELLS, + CHAR_DEL_INVALID_SPELL_TALENTS, CHAR_UPD_DELETE_INFO, CHAR_UDP_RESTORE_DELETE_INFO, CHAR_UPD_ZONE, @@ -451,8 +457,11 @@ enum CharacterDatabaseStatements CHAR_UPD_MAIL, CHAR_REP_CHAR_QUESTSTATUS, CHAR_DEL_CHAR_QUESTSTATUS_BY_QUEST, - CHAR_INS_CHAR_QUESTSTATUS, + CHAR_INS_CHAR_QUESTSTATUS_REWARDED, CHAR_DEL_CHAR_QUESTSTATUS_REWARDED_BY_QUEST, + CHAR_UPD_CHAR_QUESTSTATUS_REWARDED_FACTION_CHANGE, + CHAR_UPD_CHAR_QUESTSTATUS_REWARDED_ACTIVE, + CHAR_UPD_CHAR_QUESTSTATUS_REWARDED_ACTIVE_BY_QUEST, CHAR_DEL_CHAR_SKILL_BY_SKILL, CHAR_INS_CHAR_SKILLS, CHAR_UDP_CHAR_SKILLS, diff --git a/src/server/shared/Database/Implementation/LoginDatabase.cpp b/src/server/shared/Database/Implementation/LoginDatabase.cpp index 70d509af6fe..a23294a038c 100644 --- a/src/server/shared/Database/Implementation/LoginDatabase.cpp +++ b/src/server/shared/Database/Implementation/LoginDatabase.cpp @@ -22,11 +22,11 @@ void LoginDatabaseConnection::DoPrepareStatements() if (!m_reconnecting) m_stmts.resize(MAX_LOGINDATABASE_STATEMENTS); - PrepareStatement(LOGIN_SEL_REALMLIST, "SELECT id, name, address, port, icon, flag, timezone, allowedSecurityLevel, population, gamebuild FROM realmlist WHERE flag <> 3 ORDER BY name", CONNECTION_SYNCH); + PrepareStatement(LOGIN_SEL_REALMLIST, "SELECT id, name, address, localAddress, localSubnetMask, port, icon, flag, timezone, allowedSecurityLevel, population, gamebuild FROM realmlist WHERE flag <> 3 ORDER BY name", CONNECTION_SYNCH); PrepareStatement(LOGIN_DEL_EXPIRED_IP_BANS, "DELETE FROM ip_banned WHERE unbandate<>bandate AND unbandate<=UNIX_TIMESTAMP()", CONNECTION_ASYNC); PrepareStatement(LOGIN_UPD_EXPIRED_ACCOUNT_BANS, "UPDATE account_banned SET active = 0 WHERE active = 1 AND unbandate<>bandate AND unbandate<=UNIX_TIMESTAMP()", CONNECTION_ASYNC); PrepareStatement(LOGIN_SEL_IP_BANNED, "SELECT * FROM ip_banned WHERE ip = ?", CONNECTION_SYNCH); - PrepareStatement(LOGIN_INS_IP_AUTO_BANNED, "INSERT INTO ip_banned VALUES (?, UNIX_TIMESTAMP(), UNIX_TIMESTAMP()+?, 'Trinity realmd', 'Failed login autoban')", CONNECTION_ASYNC); + PrepareStatement(LOGIN_INS_IP_AUTO_BANNED, "INSERT INTO ip_banned (ip, bandate, unbandate, bannedby, banreason) VALUES (?, UNIX_TIMESTAMP(), UNIX_TIMESTAMP()+?, 'Trinity realmd', 'Failed login autoban')", CONNECTION_ASYNC); PrepareStatement(LOGIN_SEL_IP_BANNED_ALL, "SELECT ip, bandate, unbandate, bannedby, banreason FROM ip_banned WHERE (bandate = unbandate OR unbandate > UNIX_TIMESTAMP()) ORDER BY unbandate", CONNECTION_SYNCH); PrepareStatement(LOGIN_SEL_IP_BANNED_BY_IP, "SELECT ip, bandate, unbandate, bannedby, banreason FROM ip_banned WHERE (bandate = unbandate OR unbandate > UNIX_TIMESTAMP()) AND ip LIKE CONCAT('%%', ?, '%%') ORDER BY unbandate", CONNECTION_SYNCH); PrepareStatement(LOGIN_SEL_ACCOUNT_BANNED, "SELECT bandate, unbandate FROM account_banned WHERE id = ? AND active = 1", CONNECTION_SYNCH); @@ -42,12 +42,12 @@ void LoginDatabaseConnection::DoPrepareStatements() PrepareStatement(LOGIN_SEL_FAILEDLOGINS, "SELECT id, failed_logins FROM account WHERE username = ?", CONNECTION_SYNCH); PrepareStatement(LOGIN_SEL_ACCOUNT_ID_BY_NAME, "SELECT id FROM account WHERE username = ?", CONNECTION_SYNCH); PrepareStatement(LOGIN_SEL_ACCOUNT_LIST_BY_NAME, "SELECT id, username FROM account WHERE username = ?", CONNECTION_SYNCH); - PrepareStatement(LOGIN_SEL_ACCOUNT_INFO_BY_NAME, "SELECT id, sessionkey, last_ip, locked, v, s, expansion, mutetime, locale, recruiter, os FROM account WHERE username = ?", CONNECTION_SYNCH); + PrepareStatement(LOGIN_SEL_ACCOUNT_INFO_BY_NAME, "SELECT id, sessionkey, last_ip, locked, expansion, mutetime, locale, recruiter, os FROM account WHERE username = ?", CONNECTION_SYNCH); PrepareStatement(LOGIN_SEL_ACCOUNT_LIST_BY_EMAIL, "SELECT id, username FROM account WHERE email = ?", CONNECTION_SYNCH); PrepareStatement(LOGIN_SEL_NUM_CHARS_ON_REALM, "SELECT numchars FROM realmcharacters WHERE realmid = ? AND acctid= ?", CONNECTION_SYNCH); PrepareStatement(LOGIN_SEL_ACCOUNT_BY_IP, "SELECT id, username FROM account WHERE last_ip = ?", CONNECTION_SYNCH); PrepareStatement(LOGIN_SEL_ACCOUNT_BY_ID, "SELECT 1 FROM account WHERE id = ?", CONNECTION_SYNCH); - PrepareStatement(LOGIN_INS_IP_BANNED, "INSERT INTO ip_banned VALUES (?, UNIX_TIMESTAMP(), UNIX_TIMESTAMP()+?, ?, ?)", CONNECTION_ASYNC); + PrepareStatement(LOGIN_INS_IP_BANNED, "INSERT INTO ip_banned (ip, bandate, unbandate, bannedby, banreason) VALUES (?, UNIX_TIMESTAMP(), UNIX_TIMESTAMP()+?, ?, ?)", CONNECTION_ASYNC); PrepareStatement(LOGIN_DEL_IP_NOT_BANNED, "DELETE FROM ip_banned WHERE ip = ?", CONNECTION_ASYNC); PrepareStatement(LOGIN_INS_ACCOUNT_BANNED, "INSERT INTO account_banned VALUES (?, UNIX_TIMESTAMP(), UNIX_TIMESTAMP()+?, ?, ?, 1)", CONNECTION_ASYNC); PrepareStatement(LOGIN_UPD_ACCOUNT_NOT_BANNED, "UPDATE account_banned SET active = 0 WHERE id = ? AND active != 0", CONNECTION_ASYNC); @@ -55,14 +55,15 @@ void LoginDatabaseConnection::DoPrepareStatements() PrepareStatement(LOGIN_DEL_REALM_CHARACTERS, "DELETE FROM realmcharacters WHERE acctid = ?", CONNECTION_ASYNC); PrepareStatement(LOGIN_INS_REALM_CHARACTERS, "INSERT INTO realmcharacters (numchars, acctid, realmid) VALUES (?, ?, ?)", CONNECTION_ASYNC); PrepareStatement(LOGIN_SEL_SUM_REALM_CHARACTERS, "SELECT SUM(numchars) FROM realmcharacters WHERE acctid = ?", CONNECTION_ASYNC); - PrepareStatement(LOGIN_INS_ACCOUNT, "INSERT INTO account(username, sha_pass_hash, joindate) VALUES(?, ?, NOW())", CONNECTION_ASYNC); + PrepareStatement(LOGIN_INS_ACCOUNT, "INSERT INTO account(username, sha_pass_hash, joindate) VALUES(?, ?, NOW())", CONNECTION_SYNCH); PrepareStatement(LOGIN_INS_REALM_CHARACTERS_INIT, "INSERT INTO realmcharacters (realmid, acctid, numchars) SELECT realmlist.id, account.id, 0 FROM realmlist, account LEFT JOIN realmcharacters ON acctid=account.id WHERE acctid IS NULL", CONNECTION_ASYNC); PrepareStatement(LOGIN_UPD_EXPANSION, "UPDATE account SET expansion = ? WHERE id = ?", CONNECTION_ASYNC); PrepareStatement(LOGIN_UPD_ACCOUNT_LOCK, "UPDATE account SET locked = ? WHERE id = ?", CONNECTION_ASYNC); PrepareStatement(LOGIN_INS_LOG, "INSERT INTO logs (time, realm, type, level, string) VALUES (?, ?, ?, ?, ?)", CONNECTION_ASYNC); PrepareStatement(LOGIN_UPD_USERNAME, "UPDATE account SET v = 0, s = 0, username = ?, sha_pass_hash = ? WHERE id = ?", CONNECTION_ASYNC); PrepareStatement(LOGIN_UPD_PASSWORD, "UPDATE account SET v = 0, s = 0, sha_pass_hash = ? WHERE id = ?", CONNECTION_ASYNC); - PrepareStatement(LOGIN_UPD_MUTE_TIME, "UPDATE account SET mutetime = ? WHERE id = ?", CONNECTION_ASYNC); + PrepareStatement(LOGIN_UPD_MUTE_TIME, "UPDATE account SET mutetime = ? , mutereason = ? , muteby = ? WHERE id = ?", CONNECTION_ASYNC); + PrepareStatement(LOGIN_UPD_MUTE_TIME_LOGIN, "UPDATE account SET mutetime = ? WHERE id = ?", CONNECTION_ASYNC); PrepareStatement(LOGIN_UPD_LAST_IP, "UPDATE account SET last_ip = ? WHERE username = ?", CONNECTION_ASYNC); PrepareStatement(LOGIN_UPD_ACCOUNT_ONLINE, "UPDATE account SET online = 1 WHERE id = ?", CONNECTION_ASYNC); PrepareStatement(LOGIN_UPD_UPTIME_PLAYERS, "UPDATE uptime SET uptime = ?, maxplayers = ? WHERE realmid = ? AND starttime = ?", CONNECTION_ASYNC); @@ -76,7 +77,7 @@ void LoginDatabaseConnection::DoPrepareStatements() PrepareStatement(LOGIN_GET_USERNAME_BY_ID, "SELECT username FROM account WHERE id = ?", CONNECTION_SYNCH); PrepareStatement(LOGIN_SEL_CHECK_PASSWORD, "SELECT 1 FROM account WHERE id = ? AND sha_pass_hash = ?", CONNECTION_SYNCH); PrepareStatement(LOGIN_SEL_CHECK_PASSWORD_BY_NAME, "SELECT 1 FROM account WHERE username = ? AND sha_pass_hash = ?", CONNECTION_SYNCH); - PrepareStatement(LOGIN_SEL_PINFO, "SELECT a.username, aa.gmlevel, a.email, a.last_ip, DATE_FORMAT(a.last_login, '%Y-%m-%d %T'), a.mutetime FROM account a LEFT JOIN account_access aa ON (a.id = aa.id AND (aa.RealmID = ? OR aa.RealmID = -1)) WHERE a.id = ?", CONNECTION_SYNCH); + PrepareStatement(LOGIN_SEL_PINFO, "SELECT a.username, aa.gmlevel, a.email, a.last_ip, DATE_FORMAT(a.last_login, '%Y-%m-%d %T'), a.mutetime, a.mutereason, a.muteby FROM account a LEFT JOIN account_access aa ON (a.id = aa.id AND (aa.RealmID = ? OR aa.RealmID = -1)) WHERE a.id = ?", CONNECTION_SYNCH); PrepareStatement(LOGIN_SEL_PINFO_BANS, "SELECT unbandate, bandate = unbandate, bannedby, banreason FROM account_banned WHERE id = ? AND active ORDER BY bandate ASC LIMIT 1", CONNECTION_SYNCH); PrepareStatement(LOGIN_SEL_GM_ACCOUNTS, "SELECT a.username, aa.gmlevel FROM account a, account_access aa WHERE a.id=aa.id AND aa.gmlevel >= ? AND (aa.realmid = -1 OR aa.realmid = ?)", CONNECTION_SYNCH); PrepareStatement(LOGIN_SEL_ACCOUNT_INFO, "SELECT a.username, a.last_ip, aa.gmlevel, a.expansion FROM account a LEFT JOIN account_access aa ON (a.id = aa.id) WHERE a.id = ?", CONNECTION_SYNCH); @@ -87,4 +88,18 @@ void LoginDatabaseConnection::DoPrepareStatements() PrepareStatement(LOGIN_SEL_ACCOUNT_WHOIS, "SELECT username, email, last_ip FROM account WHERE id = ?", CONNECTION_SYNCH); PrepareStatement(LOGIN_SEL_REALMLIST_SECURITY_LEVEL, "SELECT allowedSecurityLevel from realmlist WHERE id = ?", CONNECTION_SYNCH); PrepareStatement(LOGIN_DEL_ACCOUNT, "DELETE FROM account WHERE id = ?", CONNECTION_ASYNC); + + PrepareStatement(LOGIN_SEL_ACCOUNT_ACCESS_BY_ID, "SELECT gmlevel, RealmID FROM account_access WHERE id = ? and (RealmID = ? OR RealmID = -1) ORDER BY gmlevel desc", CONNECTION_SYNCH); + + PrepareStatement(LOGIN_SEL_RBAC_ACCOUNT_GROUPS, "SELECT groupId FROM rbac_account_groups WHERE accountId = ? AND (realmId = ? OR realmId = -1) GROUP BY groupId", CONNECTION_SYNCH); + PrepareStatement(LOGIN_INS_RBAC_ACCOUNT_GROUP, "INSERT INTO rbac_account_groups (accountId, groupId, realmId) VALUES (?, ?, ?)", CONNECTION_ASYNC); + PrepareStatement(LOGIN_DEL_RBAC_ACCOUNT_GROUP, "DELETE FROM rbac_account_groups WHERE accountId = ? AND groupId = ? AND (realmId = ? OR realmId = -1)", CONNECTION_ASYNC); + + PrepareStatement(LOGIN_SEL_RBAC_ACCOUNT_ROLES, "SELECT roleId, granted FROM rbac_account_roles WHERE accountId = ? AND (realmId = ? OR realmId = -1) ORDER BY roleId, realmId", CONNECTION_SYNCH); + PrepareStatement(LOGIN_INS_RBAC_ACCOUNT_ROLE, "INSERT INTO rbac_account_roles (accountId, roleId, granted, realmId) VALUES (?, ?, ?, ?) ON DUPLICATE KEY UPDATE granted = VALUES(granted)", CONNECTION_ASYNC); + PrepareStatement(LOGIN_DEL_RBAC_ACCOUNT_ROLE, "DELETE FROM rbac_account_roles WHERE accountId = ? AND roleId = ? AND (realmId = ? OR realmId = -1)", CONNECTION_ASYNC); + + PrepareStatement(LOGIN_SEL_RBAC_ACCOUNT_PERMISSIONS, "SELECT permissionId, granted FROM rbac_account_permissions WHERE accountId = ? AND (realmId = ? OR realmId = -1) ORDER BY permissionId, realmId", CONNECTION_SYNCH); + PrepareStatement(LOGIN_INS_RBAC_ACCOUNT_PERMISSION, "INSERT INTO rbac_account_permissions (accountId, permissionId, granted, realmId) VALUES (?, ?, ?, ?) ON DUPLICATE KEY UPDATE granted = VALUES(granted)", CONNECTION_ASYNC); + PrepareStatement(LOGIN_DEL_RBAC_ACCOUNT_PERMISSION, "DELETE FROM rbac_account_permissions WHERE accountId = ? AND permissionId = ? AND (realmId = ? OR realmId = -1)", CONNECTION_ASYNC); } diff --git a/src/server/shared/Database/Implementation/LoginDatabase.h b/src/server/shared/Database/Implementation/LoginDatabase.h index 798016d553d..939cc4b4790 100644 --- a/src/server/shared/Database/Implementation/LoginDatabase.h +++ b/src/server/shared/Database/Implementation/LoginDatabase.h @@ -83,6 +83,7 @@ enum LoginDatabaseStatements LOGIN_UPD_USERNAME, LOGIN_UPD_PASSWORD, LOGIN_UPD_MUTE_TIME, + LOGIN_UPD_MUTE_TIME_LOGIN, LOGIN_UPD_LAST_IP, LOGIN_UPD_ACCOUNT_ONLINE, LOGIN_UPD_UPTIME_PLAYERS, @@ -108,6 +109,16 @@ enum LoginDatabaseStatements LOGIN_SEL_REALMLIST_SECURITY_LEVEL, LOGIN_DEL_ACCOUNT, + LOGIN_SEL_ACCOUNT_ACCESS_BY_ID, + LOGIN_SEL_RBAC_ACCOUNT_GROUPS, + LOGIN_INS_RBAC_ACCOUNT_GROUP, + LOGIN_DEL_RBAC_ACCOUNT_GROUP, + LOGIN_SEL_RBAC_ACCOUNT_ROLES, + LOGIN_INS_RBAC_ACCOUNT_ROLE, + LOGIN_DEL_RBAC_ACCOUNT_ROLE, + LOGIN_SEL_RBAC_ACCOUNT_PERMISSIONS, + LOGIN_INS_RBAC_ACCOUNT_PERMISSION, + LOGIN_DEL_RBAC_ACCOUNT_PERMISSION, MAX_LOGINDATABASE_STATEMENTS }; diff --git a/src/server/shared/Database/Implementation/WorldDatabase.cpp b/src/server/shared/Database/Implementation/WorldDatabase.cpp index 399a4eeb031..89f3cf8fdce 100644 --- a/src/server/shared/Database/Implementation/WorldDatabase.cpp +++ b/src/server/shared/Database/Implementation/WorldDatabase.cpp @@ -60,7 +60,7 @@ void WorldDatabaseConnection::DoPrepareStatements() PrepareStatement(WORLD_UPD_WAYPOINT_DATA_ALL_WPGUID, "UPDATE waypoint_data SET wpguid = 0", CONNECTION_ASYNC); PrepareStatement(WORLD_SEL_WAYPOINT_DATA_BY_POS, "SELECT id, point FROM waypoint_data WHERE (abs(position_x - ?) <= ?) and (abs(position_y - ?) <= ?) and (abs(position_z - ?) <= ?)", CONNECTION_SYNCH); PrepareStatement(WORLD_SEL_WAYPOINT_DATA_WPGUID_BY_ID, "SELECT wpguid FROM waypoint_data WHERE id = ? and wpguid <> 0", CONNECTION_SYNCH); - PrepareStatement(WOLRD_SEL_WAYPOINT_DATA_ACTION, "SELECT DISTINCT action FROM waypoint_data", CONNECTION_SYNCH); + PrepareStatement(WORLD_SEL_WAYPOINT_DATA_ACTION, "SELECT DISTINCT action FROM waypoint_data", CONNECTION_SYNCH); PrepareStatement(WORLD_SEL_WAYPOINT_SCRIPTS_MAX_ID, "SELECT MAX(guid) FROM waypoint_scripts", CONNECTION_SYNCH); PrepareStatement(WORLD_INS_CREATURE_ADDON, "INSERT INTO creature_addon(guid, path_id) VALUES (?, ?)", CONNECTION_ASYNC); PrepareStatement(WORLD_UPD_CREATURE_ADDON_PATH, "UPDATE creature_addon SET path_id = ? WHERE guid = ?", CONNECTION_ASYNC); @@ -78,7 +78,7 @@ void WorldDatabaseConnection::DoPrepareStatements() PrepareStatement(WORLD_INS_CREATURE_TRANSPORT, "INSERT INTO creature_transport (guid, npc_entry, transport_entry, TransOffsetX, TransOffsetY, TransOffsetZ, TransOffsetO) values (?, ?, ?, ?, ?, ?, ?)", CONNECTION_ASYNC); PrepareStatement(WORLD_UPD_CREATURE_TRANSPORT_EMOTE, "UPDATE creature_transport SET emote = ? WHERE transport_entry = ? AND guid = ?", CONNECTION_ASYNC); PrepareStatement(WORLD_SEL_COMMANDS, "SELECT name, security, help FROM command", CONNECTION_SYNCH); - PrepareStatement(WORLD_SEL_CREATURE_TEMPLATE, "SELECT difficulty_entry_1, difficulty_entry_2, difficulty_entry_3, KillCredit1, KillCredit2, modelid1, modelid2, modelid3, modelid4, name, subname, IconName, gossip_menu_id, minlevel, maxlevel, exp, faction_A, faction_H, npcflag, speed_walk, speed_run, scale, rank, mindmg, maxdmg, dmgschool, attackpower, dmg_multiplier, baseattacktime, rangeattacktime, unit_class, unit_flags, unit_flags2, dynamicflags, family, trainer_type, trainer_spell, trainer_class, trainer_race, minrangedmg, maxrangedmg, rangedattackpower, type, type_flags, lootid, pickpocketloot, skinloot, resistance1, resistance2, resistance3, resistance4, resistance5, resistance6, spell1, spell2, spell3, spell4, spell5, spell6, spell7, spell8, PetSpellDataId, VehicleId, mingold, maxgold, AIName, MovementType, InhabitType, HoverHeight, Health_mod, Mana_mod, Armor_mod, RacialLeader, questItem1, questItem2, questItem3, questItem4, questItem5, questItem6, movementId, RegenHealth, equipment_id, mechanic_immune_mask, flags_extra, ScriptName FROM creature_template WHERE entry = ?", CONNECTION_SYNCH); + PrepareStatement(WORLD_SEL_CREATURE_TEMPLATE, "SELECT difficulty_entry_1, difficulty_entry_2, difficulty_entry_3, KillCredit1, KillCredit2, modelid1, modelid2, modelid3, modelid4, name, subname, IconName, gossip_menu_id, minlevel, maxlevel, exp, faction_A, faction_H, npcflag, speed_walk, speed_run, scale, rank, mindmg, maxdmg, dmgschool, attackpower, dmg_multiplier, baseattacktime, rangeattacktime, unit_class, unit_flags, unit_flags2, dynamicflags, family, trainer_type, trainer_spell, trainer_class, trainer_race, minrangedmg, maxrangedmg, rangedattackpower, type, type_flags, lootid, pickpocketloot, skinloot, resistance1, resistance2, resistance3, resistance4, resistance5, resistance6, spell1, spell2, spell3, spell4, spell5, spell6, spell7, spell8, PetSpellDataId, VehicleId, mingold, maxgold, AIName, MovementType, InhabitType, HoverHeight, Health_mod, Mana_mod, Armor_mod, RacialLeader, questItem1, questItem2, questItem3, questItem4, questItem5, questItem6, movementId, RegenHealth, mechanic_immune_mask, flags_extra, ScriptName FROM creature_template WHERE entry = ?", CONNECTION_SYNCH); PrepareStatement(WORLD_SEL_WAYPOINT_SCRIPT_BY_ID, "SELECT guid, delay, command, datalong, datalong2, dataint, x, y, z, o FROM waypoint_scripts WHERE id = ?", CONNECTION_SYNCH); PrepareStatement(WORLD_SEL_IP2NATION_COUNTRY, "SELECT c.country FROM ip2nationCountries c, ip2nation i WHERE i.ip < ? AND c.code = i.country ORDER BY i.ip DESC LIMIT 0,1", CONNECTION_SYNCH); PrepareStatement(WORLD_SEL_ITEM_TEMPLATE_BY_NAME, "SELECT entry FROM item_template WHERE name = ?", CONNECTION_SYNCH); diff --git a/src/server/shared/Database/Implementation/WorldDatabase.h b/src/server/shared/Database/Implementation/WorldDatabase.h index 30cc45c535a..032baf29dd9 100644 --- a/src/server/shared/Database/Implementation/WorldDatabase.h +++ b/src/server/shared/Database/Implementation/WorldDatabase.h @@ -80,7 +80,7 @@ enum WorldDatabaseStatements WORLD_SEL_WAYPOINT_DATA_MAX_POINT, WORLD_SEL_WAYPOINT_DATA_BY_POS, WORLD_SEL_WAYPOINT_DATA_WPGUID_BY_ID, - WOLRD_SEL_WAYPOINT_DATA_ACTION, + WORLD_SEL_WAYPOINT_DATA_ACTION, WORLD_SEL_WAYPOINT_SCRIPTS_MAX_ID, WORLD_UPD_CREATURE_ADDON_PATH, WORLD_INS_CREATURE_ADDON, diff --git a/src/server/shared/Database/MySQLConnection.cpp b/src/server/shared/Database/MySQLConnection.cpp index 10ff16b5ddd..a5bcac7eeef 100644 --- a/src/server/shared/Database/MySQLConnection.cpp +++ b/src/server/shared/Database/MySQLConnection.cpp @@ -124,8 +124,9 @@ bool MySQLConnection::Open() { sLog->outInfo(LOG_FILTER_SQL, "MySQL client library: %s", mysql_get_client_info()); sLog->outInfo(LOG_FILTER_SQL, "MySQL server ver: %s ", mysql_get_server_info(m_Mysql)); - if (mysql_get_server_version(m_Mysql) != mysql_get_client_version()) - sLog->outInfo(LOG_FILTER_SQL, "[WARNING] MySQL client/server version mismatch; may conflict with behaviour of prepared statements."); + // MySQL version above 5.1 IS required in both client and server and there is no known issue with different versions above 5.1 + // if (mysql_get_server_version(m_Mysql) != mysql_get_client_version()) + // sLog->outInfo(LOG_FILTER_SQL, "[WARNING] MySQL client/server version mismatch; may conflict with behaviour of prepared statements."); } sLog->outInfo(LOG_FILTER_SQL, "Connected to MySQL database at %s", m_connectionInfo.host.c_str()); @@ -187,7 +188,7 @@ bool MySQLConnection::Execute(PreparedStatement* stmt) MySQLPreparedStatement* m_mStmt = GetPreparedStatement(index); ASSERT(m_mStmt); // Can only be null if preparation failed, server side error or bad query m_mStmt->m_stmt = stmt; // Cross reference them for debug output - stmt->m_stmt = m_mStmt; // TODO: Cleaner way + stmt->m_stmt = m_mStmt; /// @todo Cleaner way stmt->BindParameters(); @@ -237,7 +238,7 @@ bool MySQLConnection::_Query(PreparedStatement* stmt, MYSQL_RES **pResult, uint6 MySQLPreparedStatement* m_mStmt = GetPreparedStatement(index); ASSERT(m_mStmt); // Can only be null if preparation failed, server side error or bad query m_mStmt->m_stmt = stmt; // Cross reference them for debug output - stmt->m_stmt = m_mStmt; // TODO: Cleaner way + stmt->m_stmt = m_mStmt; /// @todo Cleaner way stmt->BindParameters(); diff --git a/src/server/shared/Database/SQLOperation.h b/src/server/shared/Database/SQLOperation.h index 0c000848477..400355e7c76 100644 --- a/src/server/shared/Database/SQLOperation.h +++ b/src/server/shared/Database/SQLOperation.h @@ -59,7 +59,7 @@ class MySQLConnection; class SQLOperation : public ACE_Method_Request { public: - SQLOperation(): m_conn(NULL) {}; + SQLOperation(): m_conn(NULL) {} virtual int call() { Execute(); diff --git a/src/server/shared/Debugging/Errors.h b/src/server/shared/Debugging/Errors.h index 3d10740f149..10e94634e9a 100644 --- a/src/server/shared/Debugging/Errors.h +++ b/src/server/shared/Debugging/Errors.h @@ -24,7 +24,7 @@ #include <ace/Stack_Trace.h> #include <ace/OS_NS_unistd.h> -#define WPAssert(assertion) { if (!(assertion)) { ACE_Stack_Trace st; sLog->outError(LOG_FILTER_GENERAL, "\n%s:%i in %s ASSERTION FAILED:\n %s\n%s\n", __FILE__, __LINE__, __FUNCTION__, #assertion, st.c_str()); *((volatile int*)NULL) = 0; } } +#define WPAssert(assertion) { if (!(assertion)) { ACE_Stack_Trace st; fprintf(stderr, "\n%s:%i in %s ASSERTION FAILED:\n %s\n%s\n", __FILE__, __LINE__, __FUNCTION__, #assertion, st.c_str()); *((volatile int*)NULL) = 0; } } #define WPError(assertion, errmsg) { if (!(assertion)) { sLog->outError(LOG_FILTER_GENERAL, "%\n%s:%i in %s ERROR:\n %s\n", __FILE__, __LINE__, __FUNCTION__, (char *)errmsg); *((volatile int*)NULL) = 0; } } #define WPWarning(assertion, errmsg) { if (!(assertion)) { sLog->outError(LOG_FILTER_GENERAL, "\n%s:%i in %s WARNING:\n %s\n", __FILE__, __LINE__, __FUNCTION__, (char *)errmsg); } } #define WPFatal(assertion, errmsg) { if (!(assertion)) { sLog->outError(LOG_FILTER_GENERAL, "\n%s:%i in %s FATAL ERROR:\n %s\n", __FILE__, __LINE__, __FUNCTION__, (char *)errmsg); ACE_OS::sleep(10); *((volatile int*)NULL) = 0; } } diff --git a/src/server/shared/Debugging/WheatyExceptionReport.cpp b/src/server/shared/Debugging/WheatyExceptionReport.cpp index 96a115f8057..d07e579ab5d 100644 --- a/src/server/shared/Debugging/WheatyExceptionReport.cpp +++ b/src/server/shared/Debugging/WheatyExceptionReport.cpp @@ -3,7 +3,7 @@ // MSDN Magazine, 2002 // FILE: WheatyExceptionReport.CPP //========================================== -#if PLATFORM == PLATFORM_WINDOWS +#if PLATFORM == PLATFORM_WINDOWS && !defined(__MINGW32__) #define WIN32_LEAN_AND_MEAN #pragma warning(disable:4996) #pragma warning(disable:4312) @@ -193,154 +193,125 @@ BOOL WheatyExceptionReport::_GetWindowsVersion(TCHAR* szVersion, DWORD cntMax) { // Windows NT product family. case VER_PLATFORM_WIN32_NT: + { + #if WINVER < 0x0500 + BYTE suiteMask = osvi.wReserved[0]; + BYTE productType = osvi.wReserved[1]; + #else + WORD suiteMask = osvi.wSuiteMask; + BYTE productType = osvi.wProductType; + #endif // WINVER < 0x0500 + // Test for the specific product family. if (osvi.dwMajorVersion == 6) { - #if WINVER < 0x0500 - if (osvi.wReserved[1] == VER_NT_WORKSTATION) - #else - if (osvi.wProductType == VER_NT_WORKSTATION) - #endif // WINVER < 0x0500 + if (productType == VER_NT_WORKSTATION) { - if (osvi.dwMinorVersion == 1) + if (osvi.dwMinorVersion == 2) + _tcsncat(szVersion, _T("Windows 8 "), cntMax); + else if (osvi.dwMinorVersion == 1) _tcsncat(szVersion, _T("Windows 7 "), cntMax); else _tcsncat(szVersion, _T("Windows Vista "), cntMax); } + else if (osvi.dwMinorVersion == 2) + _tcsncat(szVersion, _T("Windows Server 2012 "), cntMax); else if (osvi.dwMinorVersion == 1) _tcsncat(szVersion, _T("Windows Server 2008 R2 "), cntMax); else _tcsncat(szVersion, _T("Windows Server 2008 "), cntMax); } - if (osvi.dwMajorVersion == 5 && osvi.dwMinorVersion == 2) + else if (osvi.dwMajorVersion == 5 && osvi.dwMinorVersion == 2) _tcsncat(szVersion, _T("Microsoft Windows Server 2003 "), cntMax); - if (osvi.dwMajorVersion == 5 && osvi.dwMinorVersion == 1) + else if (osvi.dwMajorVersion == 5 && osvi.dwMinorVersion == 1) _tcsncat(szVersion, _T("Microsoft Windows XP "), cntMax); - if (osvi.dwMajorVersion == 5 && osvi.dwMinorVersion == 0) + else if (osvi.dwMajorVersion == 5 && osvi.dwMinorVersion == 0) _tcsncat(szVersion, _T("Microsoft Windows 2000 "), cntMax); - if (osvi.dwMajorVersion <= 4) + else if (osvi.dwMajorVersion <= 4) _tcsncat(szVersion, _T("Microsoft Windows NT "), cntMax); // Test for specific product on Windows NT 4.0 SP6 and later. if (bOsVersionInfoEx) { // Test for the workstation type. - #if WINVER < 0x0500 - if (osvi.wReserved[1] == VER_NT_WORKSTATION) - #else - if (osvi.wProductType == VER_NT_WORKSTATION) - #endif // WINVER < 0x0500 - { - if (osvi.dwMajorVersion == 4) - _tcsncat(szVersion, _T("Workstation 4.0 "), cntMax); - #if WINVER < 0x0500 - else if (osvi.wReserved[0] & VER_SUITE_PERSONAL) - #else - else if (osvi.wSuiteMask & VER_SUITE_PERSONAL) - #endif // WINVER < 0x0500 + if (productType == VER_NT_WORKSTATION) + { + if (osvi.dwMajorVersion == 4) + _tcsncat(szVersion, _T("Workstation 4.0 "), cntMax); + else if (suiteMask & VER_SUITE_PERSONAL) _tcsncat(szVersion, _T("Home Edition "), cntMax); - #if WINVER < 0x0500 - else if (osvi.wReserved[0] & VER_SUITE_EMBEDDEDNT) - #else - else if (osvi.wSuiteMask & VER_SUITE_EMBEDDEDNT) - #endif // WINVER < 0x0500 + else if (suiteMask & VER_SUITE_EMBEDDEDNT) _tcsncat(szVersion, _T("Embedded "), cntMax); - else - _tcsncat(szVersion, _T("Professional "), cntMax); - } - // Test for the server type. - #if WINVER < 0x0500 - else if (osvi.wReserved[1] == VER_NT_SERVER) - #else - else if (osvi.wProductType == VER_NT_SERVER) - #endif // WINVER < 0x0500 - { - if (osvi.dwMajorVersion == 5 && osvi.dwMinorVersion == 2) + else + _tcsncat(szVersion, _T("Professional "), cntMax); + } + // Test for the server type. + else if (productType == VER_NT_SERVER) { - #if WINVER < 0x0500 - if (osvi.wReserved[0] & VER_SUITE_DATACENTER) - #else - if (osvi.wSuiteMask & VER_SUITE_DATACENTER) - #endif // WINVER < 0x0500 + if (osvi.dwMajorVersion == 5 && osvi.dwMinorVersion == 2) + { + if (suiteMask & VER_SUITE_DATACENTER) _tcsncat(szVersion, _T("Datacenter Edition "), cntMax); - #if WINVER < 0x0500 - else if (osvi.wReserved[0] & VER_SUITE_ENTERPRISE) - #else - else if (osvi.wSuiteMask & VER_SUITE_ENTERPRISE) - #endif // WINVER < 0x0500 + else if (suiteMask & VER_SUITE_ENTERPRISE) _tcsncat(szVersion, _T("Enterprise Edition "), cntMax); - #if WINVER < 0x0500 - else if (osvi.wReserved[0] == VER_SUITE_BLADE) - #else - else if (osvi.wSuiteMask == VER_SUITE_BLADE) - #endif // WINVER < 0x0500 + else if (suiteMask == VER_SUITE_BLADE) _tcsncat(szVersion, _T("Web Edition "), cntMax); - else - _tcsncat(szVersion, _T("Standard Edition "), cntMax); - } - else if (osvi.dwMajorVersion == 5 && osvi.dwMinorVersion == 0) - { - #if WINVER < 0x0500 - if (osvi.wReserved[0] & VER_SUITE_DATACENTER) - #else - if (osvi.wSuiteMask & VER_SUITE_DATACENTER) - #endif // WINVER < 0x0500 + else + _tcsncat(szVersion, _T("Standard Edition "), cntMax); + } + else if (osvi.dwMajorVersion == 5 && osvi.dwMinorVersion == 0) + { + if (suiteMask & VER_SUITE_DATACENTER) _tcsncat(szVersion, _T("Datacenter Server "), cntMax); - #if WINVER < 0x0500 - else if (osvi.wReserved[0] & VER_SUITE_ENTERPRISE) - #else - else if (osvi.wSuiteMask & VER_SUITE_ENTERPRISE) - #endif // WINVER < 0x0500 + else if (suiteMask & VER_SUITE_ENTERPRISE) _tcsncat(szVersion, _T("Advanced Server "), cntMax); - else - _tcsncat(szVersion, _T("Server "), cntMax); - } - else // Windows NT 4.0 - { - #if WINVER < 0x0500 - if (osvi.wReserved[0] & VER_SUITE_ENTERPRISE) - #else - if (osvi.wSuiteMask & VER_SUITE_ENTERPRISE) - #endif // WINVER < 0x0500 + else + _tcsncat(szVersion, _T("Server "), cntMax); + } + else // Windows NT 4.0 + { + if (suiteMask & VER_SUITE_ENTERPRISE) _tcsncat(szVersion, _T("Server 4.0, Enterprise Edition "), cntMax); - else - _tcsncat(szVersion, _T("Server 4.0 "), cntMax); + else + _tcsncat(szVersion, _T("Server 4.0 "), cntMax); + } } } - } - // Display service pack (if any) and build number. - if (osvi.dwMajorVersion == 4 && _tcsicmp(osvi.szCSDVersion, _T("Service Pack 6")) == 0) - { - HKEY hKey; - LONG lRet; - // Test for SP6 versus SP6a. - lRet = ::RegOpenKeyEx(HKEY_LOCAL_MACHINE, _T("SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\Hotfix\\Q246009"), 0, KEY_QUERY_VALUE, &hKey); - if (lRet == ERROR_SUCCESS) + // Display service pack (if any) and build number. + if (osvi.dwMajorVersion == 4 && _tcsicmp(osvi.szCSDVersion, _T("Service Pack 6")) == 0) { - _stprintf(wszTmp, _T("Service Pack 6a (Version %d.%d, Build %d)"), - osvi.dwMajorVersion, osvi.dwMinorVersion, osvi.dwBuildNumber & 0xFFFF); - _tcsncat(szVersion, wszTmp, cntMax); + HKEY hKey; + LONG lRet; + + // Test for SP6 versus SP6a. + lRet = ::RegOpenKeyEx(HKEY_LOCAL_MACHINE, _T("SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\Hotfix\\Q246009"), 0, KEY_QUERY_VALUE, &hKey); + if (lRet == ERROR_SUCCESS) + { + _stprintf(wszTmp, _T("Service Pack 6a (Version %d.%d, Build %d)"), + osvi.dwMajorVersion, osvi.dwMinorVersion, osvi.dwBuildNumber & 0xFFFF); + _tcsncat(szVersion, wszTmp, cntMax); + } + else // Windows NT 4.0 prior to SP6a + { + _stprintf(wszTmp, _T("%s (Version %d.%d, Build %d)"), + osvi.szCSDVersion, osvi.dwMajorVersion, osvi.dwMinorVersion, osvi.dwBuildNumber & 0xFFFF); + _tcsncat(szVersion, wszTmp, cntMax); + } + ::RegCloseKey(hKey); } - else // Windows NT 4.0 prior to SP6a + else // Windows NT 3.51 and earlier or Windows 2000 and later { - _stprintf(wszTmp, _T("%s (Version %d.%d, Build %d)"), - osvi.szCSDVersion, osvi.dwMajorVersion, osvi.dwMinorVersion, osvi.dwBuildNumber & 0xFFFF); + if (!_tcslen(osvi.szCSDVersion)) + _stprintf(wszTmp, _T("(Version %d.%d, Build %d)"), + osvi.dwMajorVersion, osvi.dwMinorVersion, osvi.dwBuildNumber & 0xFFFF); + else + _stprintf(wszTmp, _T("%s (Version %d.%d, Build %d)"), + osvi.szCSDVersion, osvi.dwMajorVersion, osvi.dwMinorVersion, osvi.dwBuildNumber & 0xFFFF); _tcsncat(szVersion, wszTmp, cntMax); } - ::RegCloseKey(hKey); - } - else // Windows NT 3.51 and earlier or Windows 2000 and later - { - if (!_tcslen(osvi.szCSDVersion)) - _stprintf(wszTmp, _T("(Version %d.%d, Build %d)"), - osvi.dwMajorVersion, osvi.dwMinorVersion, osvi.dwBuildNumber & 0xFFFF); - else - _stprintf(wszTmp, _T("%s (Version %d.%d, Build %d)"), - osvi.szCSDVersion, osvi.dwMajorVersion, osvi.dwMinorVersion, osvi.dwBuildNumber & 0xFFFF); - _tcsncat(szVersion, wszTmp, cntMax); + break; } - break; default: _stprintf(wszTmp, _T("%s (Version %d.%d, Build %d)"), osvi.szCSDVersion, osvi.dwMajorVersion, osvi.dwMinorVersion, osvi.dwBuildNumber & 0xFFFF); diff --git a/src/server/shared/Debugging/WheatyExceptionReport.h b/src/server/shared/Debugging/WheatyExceptionReport.h index 8ade80ca47b..582f1f157b8 100644 --- a/src/server/shared/Debugging/WheatyExceptionReport.h +++ b/src/server/shared/Debugging/WheatyExceptionReport.h @@ -1,7 +1,7 @@ #ifndef _WHEATYEXCEPTIONREPORT_ #define _WHEATYEXCEPTIONREPORT_ -#if PLATFORM == PLATFORM_WINDOWS +#if PLATFORM == PLATFORM_WINDOWS && !defined(__MINGW32__) #include <dbghelp.h> diff --git a/src/server/shared/Dynamic/HashNamespace.h b/src/server/shared/Dynamic/HashNamespace.h index afb55ae0e00..88fa8c6f00e 100644 --- a/src/server/shared/Dynamic/HashNamespace.h +++ b/src/server/shared/Dynamic/HashNamespace.h @@ -93,7 +93,7 @@ template<> struct hash<std::string> { size_t operator()(const std::string &__x) const { - return hash<char const *>()(__x.c_str()); + return hash<char const*>()(__x.c_str()); } }; diff --git a/src/server/shared/Logging/Appender.cpp b/src/server/shared/Logging/Appender.cpp index f2f5da53dae..efb141d1060 100644 --- a/src/server/shared/Logging/Appender.cpp +++ b/src/server/shared/Logging/Appender.cpp @@ -73,10 +73,7 @@ void Appender::setLogLevel(LogLevel _level) void Appender::write(LogMessage& message) { if (!level || level > message.level) - { - //fprintf(stderr, "Appender::write: Appender %s, Level %s. Msg %s Level %s Type %s WRONG LEVEL MASK\n", getName().c_str(), getLogLevelString(level), message.text.c_str(), getLogLevelString(message.level), getLogFilterTypeString(message.type)); // DEBUG - RemoveMe return; - } message.prefix.clear(); if (flags & APPENDER_FLAGS_PREFIX_TIMESTAMP) @@ -219,8 +216,11 @@ char const* Appender::getLogFilterTypeString(LogFilterType type) return "OPCODE"; case LOG_FILTER_SOAP: return "SOAP"; + case LOG_FILTER_RBAC: + return "RBAC"; default: break; } + return "???"; } diff --git a/src/server/shared/Logging/Appender.h b/src/server/shared/Logging/Appender.h index 6a0f0bdac26..e11bc40c42f 100644 --- a/src/server/shared/Logging/Appender.h +++ b/src/server/shared/Logging/Appender.h @@ -67,7 +67,8 @@ enum LogFilterType LOG_FILTER_BATTLEFIELD = 39, LOG_FILTER_SERVER_LOADING = 40, LOG_FILTER_OPCODES = 41, - LOG_FILTER_SOAP = 42 + LOG_FILTER_SOAP = 42, + LOG_FILTER_RBAC = 43 }; const uint8 MaxLogFilter = 43; @@ -123,6 +124,12 @@ struct LogMessage std::string prefix; std::string param1; time_t mtime; + + ///@ Returns size of the log message content in bytes + uint32 Size() const + { + return prefix.size() + text.size(); + } }; class Appender @@ -143,7 +150,7 @@ class Appender static const char* getLogFilterTypeString(LogFilterType type); private: - virtual void _write(LogMessage& /*message*/) = 0; + virtual void _write(LogMessage const& /*message*/) = 0; uint8 id; std::string name; diff --git a/src/server/shared/Logging/AppenderConsole.cpp b/src/server/shared/Logging/AppenderConsole.cpp index d0af761188c..a1212bd135b 100644 --- a/src/server/shared/Logging/AppenderConsole.cpp +++ b/src/server/shared/Logging/AppenderConsole.cpp @@ -154,7 +154,7 @@ void AppenderConsole::ResetColor(bool stdout_stream) #endif } -void AppenderConsole::_write(LogMessage& message) +void AppenderConsole::_write(LogMessage const& message) { bool stdout_stream = message.level == LOG_LEVEL_ERROR || message.level == LOG_LEVEL_FATAL; diff --git a/src/server/shared/Logging/AppenderConsole.h b/src/server/shared/Logging/AppenderConsole.h index 3319c84e887..6f3fcca901c 100644 --- a/src/server/shared/Logging/AppenderConsole.h +++ b/src/server/shared/Logging/AppenderConsole.h @@ -51,7 +51,7 @@ class AppenderConsole: public Appender private: void SetColor(bool stdout_stream, ColorTypes color); void ResetColor(bool stdout_stream); - void _write(LogMessage& message); + void _write(LogMessage const& message); bool _colored; ColorTypes _colors[MaxLogLevels]; }; diff --git a/src/server/shared/Logging/AppenderDB.cpp b/src/server/shared/Logging/AppenderDB.cpp index 86677eeedd8..ae5fc17de73 100644 --- a/src/server/shared/Logging/AppenderDB.cpp +++ b/src/server/shared/Logging/AppenderDB.cpp @@ -18,8 +18,8 @@ #include "AppenderDB.h" #include "Database/DatabaseEnv.h" -AppenderDB::AppenderDB(uint8 id, std::string const& name, LogLevel level, uint32 realmId) - : Appender(id, name, APPENDER_DB, level), realm(realmId), enable(false) +AppenderDB::AppenderDB(uint8 id, std::string const& name, LogLevel level) + : Appender(id, name, APPENDER_DB, level), realmId(0), enabled(false) { } @@ -27,10 +27,11 @@ AppenderDB::~AppenderDB() { } -void AppenderDB::_write(LogMessage& message) +void AppenderDB::_write(LogMessage const& message) { - if (!enable) + if (!enabled) return; + switch (message.type) { case LOG_FILTER_SQL: @@ -40,7 +41,7 @@ void AppenderDB::_write(LogMessage& message) default: PreparedStatement* stmt = LoginDatabase.GetPreparedStatement(LOGIN_INS_LOG); stmt->setUInt64(0, message.mtime); - stmt->setUInt32(1, realm); + stmt->setUInt32(1, realmId); stmt->setUInt8(2, uint8(message.type)); stmt->setUInt8(3, uint8(message.level)); stmt->setString(4, message.text); @@ -49,7 +50,8 @@ void AppenderDB::_write(LogMessage& message) } } -void AppenderDB::setEnable(bool _enable) +void AppenderDB::setRealmId(uint32 _realmId) { - enable = _enable; + enabled = true; + realmId = _realmId; } diff --git a/src/server/shared/Logging/AppenderDB.h b/src/server/shared/Logging/AppenderDB.h index 5ab9a1ee423..f9dde0a1e82 100644 --- a/src/server/shared/Logging/AppenderDB.h +++ b/src/server/shared/Logging/AppenderDB.h @@ -23,14 +23,15 @@ class AppenderDB: public Appender { public: - AppenderDB(uint8 _id, std::string const& _name, LogLevel level, uint32 realmId); + AppenderDB(uint8 _id, std::string const& _name, LogLevel level); ~AppenderDB(); - void setEnable(bool enable); + + void setRealmId(uint32 realmId); private: - uint32 realm; - bool enable; - void _write(LogMessage& message); + uint32 realmId; + bool enabled; + void _write(LogMessage const& message); }; #endif diff --git a/src/server/shared/Logging/AppenderFile.cpp b/src/server/shared/Logging/AppenderFile.cpp index 7b0bac03d03..93d53bcc30d 100644 --- a/src/server/shared/Logging/AppenderFile.cpp +++ b/src/server/shared/Logging/AppenderFile.cpp @@ -18,57 +18,76 @@ #include "AppenderFile.h" #include "Common.h" -AppenderFile::AppenderFile(uint8 id, std::string const& name, LogLevel level, const char* _filename, const char* _logDir, const char* _mode, AppenderFlags _flags) - : Appender(id, name, APPENDER_FILE, level, _flags) - , filename(_filename) - , logDir(_logDir) - , mode(_mode) +AppenderFile::AppenderFile(uint8 id, std::string const& name, LogLevel level, const char* _filename, const char* _logDir, const char* _mode, AppenderFlags _flags, uint64 fileSize): + Appender(id, name, APPENDER_FILE, level, _flags), + logfile(NULL), + filename(_filename), + logDir(_logDir), + mode(_mode), + maxFileSize(fileSize), + fileSize(0) { dynamicName = std::string::npos != filename.find("%s"); backup = _flags & APPENDER_FLAGS_MAKE_FILE_BACKUP; - logfile = !dynamicName ? OpenFile(_filename, _mode, backup) : NULL; + logfile = !dynamicName ? OpenFile(_filename, _mode, mode == "w" && backup) : NULL; } AppenderFile::~AppenderFile() { - if (logfile) - { - fclose(logfile); - logfile = NULL; - } + CloseFile(); } -void AppenderFile::_write(LogMessage& message) +void AppenderFile::_write(LogMessage const& message) { + bool exceedMaxSize = maxFileSize > 0 && (fileSize + message.Size()) > maxFileSize; + if (dynamicName) { char namebuf[TRINITY_PATH_MAX]; snprintf(namebuf, TRINITY_PATH_MAX, filename.c_str(), message.param1.c_str()); - logfile = OpenFile(namebuf, mode, backup); + logfile = OpenFile(namebuf, mode, backup || exceedMaxSize); } + else if (exceedMaxSize) + logfile = OpenFile(filename, "w", true); - if (logfile) - { - fprintf(logfile, "%s%s", message.prefix.c_str(), message.text.c_str()); - fflush(logfile); + if (!logfile) + return; - if (dynamicName) - { - fclose(logfile); - logfile = NULL; - } - } + fprintf(logfile, "%s%s", message.prefix.c_str(), message.text.c_str()); + fflush(logfile); + fileSize += message.Size(); + + if (dynamicName) + CloseFile(); } FILE* AppenderFile::OpenFile(std::string const &filename, std::string const &mode, bool backup) { - if (mode == "w" && backup) + std::string fullName(logDir + filename); + if (backup) { - std::string newName(filename); + CloseFile(); + std::string newName(fullName); newName.push_back('.'); newName.append(LogMessage::getTimeStr(time(NULL))); - rename(filename.c_str(), newName.c_str()); // no error handling... if we couldn't make a backup, just ignore + rename(fullName.c_str(), newName.c_str()); // no error handling... if we couldn't make a backup, just ignore + } + + if (FILE* ret = fopen(fullName.c_str(), mode.c_str())) + { + fileSize = ftell(ret); + return ret; + } + + return NULL; +} + +void AppenderFile::CloseFile() +{ + if (logfile) + { + fclose(logfile); + logfile = NULL; } - return fopen((logDir + filename).c_str(), mode.c_str()); } diff --git a/src/server/shared/Logging/AppenderFile.h b/src/server/shared/Logging/AppenderFile.h index 934370d70b4..c15974799e1 100644 --- a/src/server/shared/Logging/AppenderFile.h +++ b/src/server/shared/Logging/AppenderFile.h @@ -23,18 +23,21 @@ class AppenderFile: public Appender { public: - AppenderFile(uint8 _id, std::string const& _name, LogLevel level, const char* filename, const char* logDir, const char* mode, AppenderFlags flags); + AppenderFile(uint8 _id, std::string const& _name, LogLevel level, const char* filename, const char* logDir, const char* mode, AppenderFlags flags, uint64 maxSize); ~AppenderFile(); FILE* OpenFile(std::string const& _name, std::string const& _mode, bool _backup); private: - void _write(LogMessage& message); + void CloseFile(); + void _write(LogMessage const& message); FILE* logfile; std::string filename; std::string logDir; std::string mode; bool dynamicName; bool backup; + uint64 maxFileSize; + uint64 fileSize; }; #endif diff --git a/src/server/shared/Logging/Log.cpp b/src/server/shared/Logging/Log.cpp index 4048f056f46..f0275f8c6b2 100644 --- a/src/server/shared/Logging/Log.cpp +++ b/src/server/shared/Logging/Log.cpp @@ -31,7 +31,6 @@ Log::Log() : worker(NULL) { - SetRealmID(0); m_logsTimestamp = "_" + GetTimestampStr(); LoadFromConfig(); } @@ -82,7 +81,7 @@ void Log::CreateAppenderFromConfig(const char* name) if (!name || *name == '\0') return; - // Format=type,level,flags,optional1,optional2 + // Format=type, level, flags, optional1, optional2 // if type = File. optional1 = file and option2 = mode // if type = Console. optional1 = Color std::string options = "Appender."; @@ -90,8 +89,9 @@ void Log::CreateAppenderFromConfig(const char* name) options = ConfigMgr::GetStringDefault(options.c_str(), ""); Tokenizer tokens(options, ','); Tokenizer::const_iterator iter = tokens.begin(); + uint8 size = tokens.size(); - if (tokens.size() < 2) + if (size < 2) { fprintf(stderr, "Log::CreateAppenderFromConfig: Wrong configuration for appender %s. Config line: %s\n", name, options.c_str()); return; @@ -99,16 +99,15 @@ void Log::CreateAppenderFromConfig(const char* name) AppenderFlags flags = APPENDER_FLAGS_NONE; AppenderType type = AppenderType(atoi(*iter)); - ++iter; - LogLevel level = LogLevel(atoi(*iter)); + LogLevel level = LogLevel(atoi(*(++iter))); if (level > LOG_LEVEL_FATAL) { fprintf(stderr, "Log::CreateAppenderFromConfig: Wrong Log Level %d for appender %s\n", level, name); return; } - if (++iter != tokens.end()) - flags = AppenderFlags(atoi(*iter)); + if (size > 2) + flags = AppenderFlags(atoi(*(++iter))); switch (type) { @@ -116,8 +115,8 @@ void Log::CreateAppenderFromConfig(const char* name) { AppenderConsole* appender = new AppenderConsole(NextAppenderId(), name, level, flags); appenders[appender->getId()] = appender; - if (++iter != tokens.end()) - appender->InitColors(*iter); + if (size > 3) + appender->InitColors(*(++iter)); //fprintf(stdout, "Log::CreateAppenderFromConfig: Created Appender %s (%u), Type CONSOLE, Mask %u\n", appender->getName().c_str(), appender->getId(), appender->getLogLevel()); // DEBUG - RemoveMe break; } @@ -126,16 +125,16 @@ void Log::CreateAppenderFromConfig(const char* name) std::string filename; std::string mode = "a"; - if (++iter == tokens.end()) + if (size < 4) { fprintf(stderr, "Log::CreateAppenderFromConfig: Missing file name for appender %s\n", name); return; } - filename = *iter; + filename = *(++iter); - if (++iter != tokens.end()) - mode = *iter; + if (size > 4) + mode = *(++iter); if (flags & APPENDER_FLAGS_USE_TIMESTAMP) { @@ -146,15 +145,19 @@ void Log::CreateAppenderFromConfig(const char* name) filename += m_logsTimestamp; } + uint64 maxFileSize = 0; + if (size > 5) + maxFileSize = atoi(*(++iter)); + uint8 id = NextAppenderId(); - appenders[id] = new AppenderFile(id, name, level, filename.c_str(), m_logsDir.c_str(), mode.c_str(), flags); + appenders[id] = new AppenderFile(id, name, level, filename.c_str(), m_logsDir.c_str(), mode.c_str(), flags, maxFileSize); //fprintf(stdout, "Log::CreateAppenderFromConfig: Created Appender %s (%u), Type FILE, Mask %u, File %s, Mode %s\n", name, id, level, filename.c_str(), mode.c_str()); // DEBUG - RemoveMe break; } case APPENDER_DB: { uint8 id = NextAppenderId(); - appenders[id] = new AppenderDB(id, name, level, realm); + appenders[id] = new AppenderDB(id, name, level); break; } default: @@ -265,13 +268,6 @@ void Log::ReadLoggersFromConfig() loggers[LOG_FILTER_GENERAL].Create("root", LOG_FILTER_GENERAL, LOG_LEVEL_DISABLED); } -void Log::EnableDBAppenders() -{ - for (AppenderMap::iterator it = appenders.begin(); it != appenders.end(); ++it) - if (it->second && it->second->getType() == APPENDER_DB) - ((AppenderDB *)it->second)->setEnable(true); -} - void Log::vlog(LogFilterType filter, LogLevel level, char const* str, va_list argptr) { char text[MAX_QUERY_LEN]; @@ -281,11 +277,18 @@ void Log::vlog(LogFilterType filter, LogLevel level, char const* str, va_list ar void Log::write(LogMessage* msg) { + if (loggers.empty()) + return; + + msg->text.append("\n"); + Logger* logger = GetLoggerByType(msg->type); + if (worker) - { - msg->text.append("\n"); - Logger* logger = GetLoggerByType(msg->type); worker->enqueue(new LogOperation(logger, msg)); + else + { + logger->write(*msg); + delete msg; } } @@ -463,9 +466,11 @@ void Log::outCommand(uint32 account, const char * str, ...) write(msg); } -void Log::SetRealmID(uint32 id) +void Log::SetRealmId(uint32 id) { - realm = id; + for (AppenderMap::iterator it = appenders.begin(); it != appenders.end(); ++it) + if (it->second && it->second->getType() == APPENDER_DB) + ((AppenderDB *)it->second)->setRealmId(id); } void Log::Close() @@ -484,7 +489,10 @@ void Log::Close() void Log::LoadFromConfig() { Close(); - worker = new LogWorker(); + + if (ConfigMgr::GetBoolDefault("Log.Async.Enable", false)) + worker = new LogWorker(); + AppenderId = 0; m_logsDir = ConfigMgr::GetStringDefault("LogsDir", ""); if (!m_logsDir.empty()) diff --git a/src/server/shared/Logging/Log.h b/src/server/shared/Logging/Log.h index 26fcc40c5e0..46aaea4bad1 100644 --- a/src/server/shared/Logging/Log.h +++ b/src/server/shared/Logging/Log.h @@ -45,19 +45,18 @@ class Log bool ShouldLog(LogFilterType type, LogLevel level) const; bool SetLogLevel(std::string const& name, char const* level, bool isLogger = true); - void outTrace(LogFilterType f, char const* str, ...) ATTR_PRINTF(3,4); - void outDebug(LogFilterType f, char const* str, ...) ATTR_PRINTF(3,4); - void outInfo(LogFilterType f, char const* str, ...) ATTR_PRINTF(3,4); - void outWarn(LogFilterType f, char const* str, ...) ATTR_PRINTF(3,4); - void outError(LogFilterType f, char const* str, ...) ATTR_PRINTF(3,4); - void outFatal(LogFilterType f, char const* str, ...) ATTR_PRINTF(3,4); - - void EnableDBAppenders(); + void outTrace(LogFilterType f, char const* str, ...) ATTR_PRINTF(3, 4); + void outDebug(LogFilterType f, char const* str, ...) ATTR_PRINTF(3, 4); + void outInfo(LogFilterType f, char const* str, ...) ATTR_PRINTF(3, 4); + void outWarn(LogFilterType f, char const* str, ...) ATTR_PRINTF(3, 4); + void outError(LogFilterType f, char const* str, ...) ATTR_PRINTF(3, 4); + void outFatal(LogFilterType f, char const* str, ...) ATTR_PRINTF(3, 4); + void outCommand(uint32 account, const char * str, ...) ATTR_PRINTF(3, 4); void outCharDump(char const* str, uint32 account_id, uint32 guid, char const* name); static std::string GetTimestampStr(); - void SetRealmID(uint32 id); + void SetRealmId(uint32 id); private: void vlog(LogFilterType f, LogLevel level, char const* str, va_list argptr); @@ -78,7 +77,6 @@ class Log std::string m_logsDir; std::string m_logsTimestamp; - uint32 realm; LogWorker* worker; }; diff --git a/src/server/shared/Memory.h b/src/server/shared/Memory.h new file mode 100644 index 00000000000..25533638915 --- /dev/null +++ b/src/server/shared/Memory.h @@ -0,0 +1,19 @@ + + +#ifndef _MEMORY_H +#define _MEMORY_H + +#include "DetourAlloc.h" + +// memory management +inline void* dtCustomAlloc(int size, dtAllocHint /*hint*/) +{ + return (void*)new unsigned char[size]; +} + +inline void dtCustomFree(void* ptr) +{ + delete [] (unsigned char*)ptr; +} + +#endif
\ No newline at end of file diff --git a/src/server/shared/Packets/ByteBuffer.h b/src/server/shared/Packets/ByteBuffer.h index 5553b04f461..ceab4ca442e 100644 --- a/src/server/shared/Packets/ByteBuffer.h +++ b/src/server/shared/Packets/ByteBuffer.h @@ -52,7 +52,7 @@ class ByteBufferPositionException : public ByteBufferException { ACE_Stack_Trace trace; - sLog->outError(LOG_FILTER_NETWORKIO, "Attempted to %s value with size: "SIZEFMTD" in ByteBuffer (pos: " SIZEFMTD " size: "SIZEFMTD")\n[Stacktrace: %s]" , + sLog->outError(LOG_FILTER_NETWORKIO, "Attempted to %s value with size: "SIZEFMTD" in ByteBuffer (pos: " SIZEFMTD " size: "SIZEFMTD")\n[Stacktrace: %s]", (_add ? "put" : "get"), ValueSize, Pos, Size, trace.c_str()); } @@ -381,6 +381,8 @@ class ByteBuffer return *this; } + uint8 * contents() { return &_storage[0]; } + const uint8 *contents() const { return &_storage[0]; } size_t size() const { return _storage.size(); } @@ -624,7 +626,7 @@ inline ByteBuffer &operator>>(ByteBuffer &b, std::map<K, V> &m) return b; } -// TODO: Make a ByteBuffer.cpp and move all this inlining to it. +/// @todo Make a ByteBuffer.cpp and move all this inlining to it. template<> inline std::string ByteBuffer::read<std::string>() { std::string tmp; diff --git a/src/server/shared/Utilities/Util.cpp b/src/server/shared/Utilities/Util.cpp index 0d9314c48a3..1bba3c2db09 100644 --- a/src/server/shared/Utilities/Util.cpp +++ b/src/server/shared/Utilities/Util.cpp @@ -22,7 +22,6 @@ #include "SFMT.h" #include "Errors.h" // for ASSERT #include <ace/TSS_T.h> -#include <ace/INET_Addr.h> typedef ACE_TSS<SFMTRand> SFMTRandTSS; static SFMTRandTSS sfmtRand; @@ -239,6 +238,21 @@ bool IsIPAddress(char const* ipaddress) return inet_addr(ipaddress) != INADDR_NONE; } +std::string GetAddressString(ACE_INET_Addr const& addr) +{ + char buf[ACE_MAX_FULLY_QUALIFIED_NAME_LEN + 16]; + addr.addr_to_string(buf, ACE_MAX_FULLY_QUALIFIED_NAME_LEN + 16); + return buf; +} + +bool IsIPAddrInNetwork(ACE_INET_Addr const& net, ACE_INET_Addr const& addr, ACE_INET_Addr const& subnetMask) +{ + uint32 mask = subnetMask.get_ip_address(); + if ((net.get_ip_address() & mask) == (addr.get_ip_address() & mask)) + return true; + return false; +} + /// create PID file uint32 CreatePIDFile(const std::string& filename) { diff --git a/src/server/shared/Utilities/Util.h b/src/server/shared/Utilities/Util.h index 10c2e866a7d..a379bfd32fc 100644 --- a/src/server/shared/Utilities/Util.h +++ b/src/server/shared/Utilities/Util.h @@ -25,6 +25,7 @@ #include <string> #include <vector> #include <list> +#include <ace/INET_Addr.h> // Searcher for map of structs template<typename T, class S> struct Finder @@ -39,7 +40,7 @@ template<typename T, class S> struct Finder class Tokenizer { public: - typedef std::vector<char const *> StorageType; + typedef std::vector<char const*> StorageType; typedef StorageType::size_type size_type; @@ -343,6 +344,13 @@ void utf8printf(FILE* out, const char *str, ...); void vutf8printf(FILE* out, const char *str, va_list* ap); bool IsIPAddress(char const* ipaddress); + +/// Checks if address belongs to the a network with specified submask +bool IsIPAddrInNetwork(ACE_INET_Addr const& net, ACE_INET_Addr const& addr, ACE_INET_Addr const& subnetMask); + +/// Transforms ACE_INET_Addr address into string format "dotted_ip:port" +std::string GetAddressString(ACE_INET_Addr const& addr); + uint32 CreatePIDFile(const std::string& filename); std::string ByteArrayToHexStr(uint8 const* bytes, uint32 length, bool reverse = false); diff --git a/src/server/worldserver/CMakeLists.txt b/src/server/worldserver/CMakeLists.txt index 413d6487480..b7097be8e2a 100644 --- a/src/server/worldserver/CMakeLists.txt +++ b/src/server/worldserver/CMakeLists.txt @@ -29,16 +29,24 @@ set(worldserver_SRCS ) if( WIN32 ) - set(worldserver_SRCS - ${worldserver_SRCS} - ${sources_Debugging} - worldserver.rc - ) + if ( MSVC ) + set(worldserver_SRCS + ${worldserver_SRCS} + ${sources_Debugging} + worldserver.rc + ) + else ( ) + set(worldserver_SRCS + ${worldserver_SRCS} + ${sources_Debugging} + ) + endif () endif() include_directories( ${CMAKE_BINARY_DIR} ${CMAKE_SOURCE_DIR}/dep/g3dlite/include + ${CMAKE_SOURCE_DIR}/dep/recastnavigation/Detour ${CMAKE_SOURCE_DIR}/dep/gsoap ${CMAKE_SOURCE_DIR}/dep/sockets/include ${CMAKE_SOURCE_DIR}/dep/SFMT @@ -163,6 +171,7 @@ target_link_libraries(worldserver collision g3dlib gsoap + Detour ${JEMALLOC_LIBRARY} ${READLINE_LIBRARY} ${TERMCAP_LIBRARY} @@ -173,10 +182,17 @@ target_link_libraries(worldserver ) if( WIN32 ) - add_custom_command(TARGET worldserver - POST_BUILD - COMMAND ${CMAKE_COMMAND} -E copy ${CMAKE_CURRENT_SOURCE_DIR}/worldserver.conf.dist ${CMAKE_BINARY_DIR}/bin/$(ConfigurationName)/ - ) + if ( MSVC ) + add_custom_command(TARGET worldserver + POST_BUILD + COMMAND ${CMAKE_COMMAND} -E copy ${CMAKE_CURRENT_SOURCE_DIR}/worldserver.conf.dist ${CMAKE_BINARY_DIR}/bin/$(ConfigurationName)/ + ) + elseif ( MINGW ) + add_custom_command(TARGET worldserver + POST_BUILD + COMMAND ${CMAKE_COMMAND} -E copy ${CMAKE_CURRENT_SOURCE_DIR}/worldserver.conf.dist ${CMAKE_BINARY_DIR}/bin/ + ) + endif() endif() if( UNIX ) diff --git a/src/server/worldserver/Main.cpp b/src/server/worldserver/Main.cpp index 5287847fa6f..3bd6ff8edf3 100644 --- a/src/server/worldserver/Main.cpp +++ b/src/server/worldserver/Main.cpp @@ -141,7 +141,7 @@ extern int main(int argc, char **argv) sLog->outInfo(LOG_FILTER_WORLDSERVER, "Using ACE version: %s", ACE_VERSION); ///- and run the 'Master' - /// \todo Why do we need this 'Master'? Can't all of this be in the Main as for Realmd? + /// @todo Why do we need this 'Master'? Can't all of this be in the Main as for Realmd? int ret = sMaster->Run(); // at sMaster return function exist with codes diff --git a/src/server/worldserver/Master.cpp b/src/server/worldserver/Master.cpp index fe872c1977f..56dd64bc45a 100644 --- a/src/server/worldserver/Master.cpp +++ b/src/server/worldserver/Master.cpp @@ -438,8 +438,6 @@ bool Master::_StartDB() } sLog->outInfo(LOG_FILTER_WORLDSERVER, "Realm running as realm ID %d", realmID); - sLog->SetRealmID(realmID); - ///- Clean the database before starting ClearOnlineAccounts(); diff --git a/src/server/worldserver/RemoteAccess/RASocket.cpp b/src/server/worldserver/RemoteAccess/RASocket.cpp index 75c95d5ea98..359abd39901 100644 --- a/src/server/worldserver/RemoteAccess/RASocket.cpp +++ b/src/server/worldserver/RemoteAccess/RASocket.cpp @@ -33,6 +33,7 @@ RASocket::RASocket() { _minLevel = uint8(ConfigMgr::GetIntDefault("RA.MinLevel", 3)); + _commandExecuting = false; } RASocket::~RASocket() @@ -49,23 +50,35 @@ int RASocket::open(void *) return -1; } - sLog->outDebug(LOG_FILTER_REMOTECOMMAND, "Incoming connection from %s", remote_addr.get_host_addr()); + sLog->outInfo(LOG_FILTER_REMOTECOMMAND, "Incoming connection from %s", remote_addr.get_host_addr()); return activate(); } int RASocket::handle_close(ACE_HANDLE, ACE_Reactor_Mask) { - sLog->outDebug(LOG_FILTER_REMOTECOMMAND, "Closing connection"); + sLog->outInfo(LOG_FILTER_REMOTECOMMAND, "Closing connection"); peer().close_reader(); wait(); + // While the above wait() will wait for the ::svc() to finish, it will not wait for the async event + // RASocket::commandfinished to be completed. Calling destroy() before the latter function ends + // will lead to using a freed pointer -> crash. + while (_commandExecuting.value()) + ACE_OS::sleep(1); + destroy(); return 0; } int RASocket::send(const std::string& line) { - return size_t(peer().send(line.c_str(), line.length())) == line.length() ? 0 : -1; +#ifdef MSG_NOSIGNAL + ssize_t n = peer().send(line.c_str(), line.length(), MSG_NOSIGNAL); +#else + ssize_t n = peer().send(line.c_str(), line.length()); +#endif // MSG_NOSIGNAL + + return n == ssize_t(line.length()) ? 0 : -1; } int RASocket::recv_line(ACE_Message_Block& buffer) @@ -136,7 +149,7 @@ int RASocket::process_command(const std::string& command) if (command.length() == 0) return 0; - sLog->outDebug(LOG_FILTER_REMOTECOMMAND, "Got command: %s", command.c_str()); + sLog->outInfo(LOG_FILTER_REMOTECOMMAND, "Received command: %s", command.c_str()); // handle quit, exit and logout commands to terminate connection if (command == "quit" || command == "exit" || command == "logout") { @@ -144,6 +157,7 @@ int RASocket::process_command(const std::string& command) return -1; } + _commandExecuting = true; CliCommandHolder* cmd = new CliCommandHolder(this, command.c_str(), &RASocket::zprint, &RASocket::commandFinished); sWorld->QueueCliCommand(cmd); @@ -160,7 +174,7 @@ int RASocket::process_command(const std::string& command) break; } - if (size_t(peer().send(mb->rd_ptr(), mb->length())) != mb->length()) + if (send(std::string(mb->rd_ptr(), mb->length())) == -1) { mb->release(); return -1; @@ -178,15 +192,13 @@ int RASocket::check_access_level(const std::string& user) AccountMgr::normalizeString(safeUser); - - PreparedStatement* stmt = LoginDatabase.GetPreparedStatement(LOGIN_SEL_ACCOUNT_ACCESS); stmt->setString(0, safeUser); PreparedQueryResult result = LoginDatabase.Query(stmt); if (!result) { - sLog->outDebug(LOG_FILTER_REMOTECOMMAND, "User %s does not exist in database", user.c_str()); + sLog->outInfo(LOG_FILTER_REMOTECOMMAND, "User %s does not exist in database", user.c_str()); return -1; } @@ -194,12 +206,12 @@ int RASocket::check_access_level(const std::string& user) if (fields[1].GetUInt8() < _minLevel) { - sLog->outDebug(LOG_FILTER_REMOTECOMMAND, "User %s has no privilege to login", user.c_str()); + sLog->outInfo(LOG_FILTER_REMOTECOMMAND, "User %s has no privilege to login", user.c_str()); return -1; } else if (fields[2].GetInt32() != -1) { - sLog->outDebug(LOG_FILTER_REMOTECOMMAND, "User %s has to be assigned on all realms (with RealmID = '-1')", user.c_str()); + sLog->outInfo(LOG_FILTER_REMOTECOMMAND, "User %s has to be assigned on all realms (with RealmID = '-1')", user.c_str()); return -1; } @@ -225,7 +237,7 @@ int RASocket::check_password(const std::string& user, const std::string& pass) if (!result) { - sLog->outDebug(LOG_FILTER_REMOTECOMMAND, "Wrong password for user: %s", user.c_str()); + sLog->outInfo(LOG_FILTER_REMOTECOMMAND, "Wrong password for user: %s", user.c_str()); return -1; } @@ -248,7 +260,7 @@ int RASocket::authenticate() if (recv_line(pass) == -1) return -1; - sLog->outDebug(LOG_FILTER_REMOTECOMMAND, "Login attempt for user: %s", user.c_str()); + sLog->outInfo(LOG_FILTER_REMOTECOMMAND, "Login attempt for user: %s", user.c_str()); if (check_access_level(user) == -1) return -1; @@ -256,7 +268,7 @@ int RASocket::authenticate() if (check_password(user, pass) == -1) return -1; - sLog->outDebug(LOG_FILTER_REMOTECOMMAND, "User login: %s", user.c_str()); + sLog->outInfo(LOG_FILTER_REMOTECOMMAND, "User login: %s", user.c_str()); return 0; } @@ -332,7 +344,12 @@ int RASocket::subnegotiate() //! Just send back end of subnegotiation packet uint8 const reply[2] = {0xFF, 0xF0}; + +#ifdef MSG_NOSIGNAL + return int(peer().send(reply, 2, MSG_NOSIGNAL)); +#else return int(peer().send(reply, 2)); +#endif // MSG_NOSIGNAL } int RASocket::svc(void) @@ -356,8 +373,7 @@ int RASocket::svc(void) for (;;) { // show prompt - const char* tc_prompt = "TC> "; - if (size_t(peer().send(tc_prompt, strlen(tc_prompt))) != strlen(tc_prompt)) + if (send("TC> ") == -1) return -1; std::string line; @@ -383,7 +399,8 @@ void RASocket::zprint(void* callbackArg, const char * szText) ACE_Message_Block* mb = new ACE_Message_Block(sz); mb->copy(szText, sz); - if (socket->putq(mb, const_cast<ACE_Time_Value*>(&ACE_Time_Value::zero)) == -1) + ACE_Time_Value tv = ACE_Time_Value::zero; + if (socket->putq(mb, &tv) == -1) { sLog->outDebug(LOG_FILTER_REMOTECOMMAND, "Failed to enqueue message, queue is full or closed. Error is %s", ACE_OS::strerror(errno)); mb->release(); @@ -403,10 +420,11 @@ void RASocket::commandFinished(void* callbackArg, bool /*success*/) // the message is 0 size control message to tell that command output is finished // hence we don't put timeout, because it shouldn't increase queue size and shouldn't block - if (socket->putq(mb) == -1) - { + if (socket->putq(mb->duplicate()) == -1) // getting here is bad, command can't be marked as complete sLog->outDebug(LOG_FILTER_REMOTECOMMAND, "Failed to enqueue command end message. Error is %s", ACE_OS::strerror(errno)); - mb->release(); - } + + mb->release(); + + socket->_commandExecuting = false; } diff --git a/src/server/worldserver/RemoteAccess/RASocket.h b/src/server/worldserver/RemoteAccess/RASocket.h index d23d1f0d5fd..e92cb35eaf0 100644 --- a/src/server/worldserver/RemoteAccess/RASocket.h +++ b/src/server/worldserver/RemoteAccess/RASocket.h @@ -57,6 +57,7 @@ class RASocket: public ACE_Svc_Handler<ACE_SOCK_STREAM, ACE_MT_SYNCH> private: /// Minimum security level required to connect uint8 _minLevel; + ACE_Atomic_Op<ACE_Thread_Mutex, bool> _commandExecuting; }; #endif /// @} diff --git a/src/server/worldserver/TCSoap/TCSoap.cpp b/src/server/worldserver/TCSoap/TCSoap.cpp index 5d578a19124..dd82c6ce0c7 100644 --- a/src/server/worldserver/TCSoap/TCSoap.cpp +++ b/src/server/worldserver/TCSoap/TCSoap.cpp @@ -18,6 +18,9 @@ #include "TCSoap.h" #include "soapH.h" #include "soapStub.h" +#include "World.h" +#include "AccountMgr.h" +#include "Log.h" void TCSoapRunnable::run() { @@ -78,33 +81,33 @@ int ns1__executeCommand(soap* soap, char* command, char** result) // security check if (!soap->userid || !soap->passwd) { - sLog->outDebug(LOG_FILTER_SOAP, "Client didn't provide login information"); + sLog->outInfo(LOG_FILTER_SOAP, "Client didn't provide login information"); return 401; } uint32 accountId = AccountMgr::GetId(soap->userid); if (!accountId) { - sLog->outDebug(LOG_FILTER_SOAP, "Client used invalid username '%s'", soap->userid); + sLog->outInfo(LOG_FILTER_SOAP, "Client used invalid username '%s'", soap->userid); return 401; } if (!AccountMgr::CheckPassword(accountId, soap->passwd)) { - sLog->outDebug(LOG_FILTER_SOAP, "Invalid password for account '%s'", soap->userid); + sLog->outInfo(LOG_FILTER_SOAP, "Invalid password for account '%s'", soap->userid); return 401; } if (AccountMgr::GetSecurity(accountId) < SEC_ADMINISTRATOR) { - sLog->outDebug(LOG_FILTER_SOAP, "%s's gmlevel is too low", soap->userid); + sLog->outInfo(LOG_FILTER_SOAP, "%s's gmlevel is too low", soap->userid); return 403; } if (!command || !*command) - return soap_sender_fault(soap, "Command mustn't be empty", "The supplied command was an empty string"); + return soap_sender_fault(soap, "Command can not be empty", "The supplied command was an empty string"); - sLog->outDebug(LOG_FILTER_SOAP, "Got command '%s'", command); + sLog->outInfo(LOG_FILTER_SOAP, "Received command '%s'", command); SOAPCommand connection; // commands are executed in the world thread. We have to wait for them to be completed diff --git a/src/server/worldserver/TCSoap/TCSoap.h b/src/server/worldserver/TCSoap/TCSoap.h index ccdc7b1f89f..b786ee94e81 100644 --- a/src/server/worldserver/TCSoap/TCSoap.h +++ b/src/server/worldserver/TCSoap/TCSoap.h @@ -18,17 +18,11 @@ #ifndef _TCSOAP_H #define _TCSOAP_H -#include "Common.h" -#include "World.h" -#include "AccountMgr.h" -#include "Log.h" - -#include "soapH.h" -#include "soapStub.h" -#include "stdsoap2.h" +#include "Define.h" #include <ace/Semaphore.h> #include <ace/Task.h> +#include <Threading.h> class TCSoapRunnable: public ACE_Based::Runnable { diff --git a/src/server/worldserver/worldserver.conf.dist b/src/server/worldserver/worldserver.conf.dist index 68cf3994e3b..0802aca43ce 100644 --- a/src/server/worldserver/worldserver.conf.dist +++ b/src/server/worldserver/worldserver.conf.dist @@ -269,6 +269,14 @@ PlayerSave.Stats.MinLevel = 0 PlayerSave.Stats.SaveOnlyOnLogout = 1 # +# mmap.enablePathFinding +# Description: Enable/Disable pathfinding using mmaps - experimental +# Default: 0 - (Disabled) +# 1 - (Enabled) + +mmap.enablePathFinding = 0 + +# # vmap.enableLOS # vmap.enableHeight # Description: VMmap support for line of sight and height calculation. @@ -280,14 +288,6 @@ vmap.enableLOS = 1 vmap.enableHeight = 1 # -# vmap.petLOS -# Description: Check line of sight for pets, to avoid them attacking through walls. -# Default: 1 - (Enabled, each pet attack will be checked for line of sight) -# 0 - (Disabled, somewhat less CPU usage) - -vmap.petLOS = 1 - -# # vmap.enableIndoorCheck # Description: VMap based indoor check to remove outdoor-only auras (mounts etc.). # Default: 1 - (Enabled) @@ -814,18 +814,6 @@ RecruitAFriend.MaxLevel = 60 RecruitAFriend.MaxDifference = 4 # -# InstantLogout -# Description: Required security level for instantly logging out everywhere. -# Does not work while in combat, dueling or falling. -# Default: 1 - (Enabled, Mods/GMs/Admins) -# 0 - (Enabled, Everyone) -# 2 - (Enabled, GMs/Admins) -# 3 - (Enabled, Admins) -# 4 - (Disabled) - -InstantLogout = 1 - -# # DisableWaterBreath # Description: Required security level for water breathing. # Default: 4 - (Disabled) @@ -1066,7 +1054,7 @@ Event.Announce = 0 # # BeepAtStart -# Description: Beep when the world server finished starting (Unix/Linux systems). +# Description: Beep when the world server finished starting. # Default: 1 - (Enabled) # 0 - (Disabled) @@ -1132,6 +1120,14 @@ DBC.EnforceItemAttributes = 1 AccountInstancesPerHour = 5 # +# RBAC.DefaultGroups +# Description: Comma separated list of groups to be added to any account +# Check auth.rbac_groups for correct ids +# Default: "" (No group) + +RBAC.DefaultGroups = "" + +# ################################################################################################### ################################################################################################### @@ -1204,13 +1200,6 @@ Warden.BanDuration = 86400 ################################################################################################### # PLAYER INTERACTION # -# AllowTwoSide.Accounts -# Description: Allow creating characters of both factions on the same account. -# Default: 1 - (Enabled) -# 0 - (Disabled) - -AllowTwoSide.Accounts = 1 - # # AllowTwoSide.Interaction.Calendar # Description: Allow calendar invites between factions. @@ -1220,14 +1209,6 @@ AllowTwoSide.Accounts = 1 AllowTwoSide.Interaction.Calendar = 0 # -# AllowTwoSide.Interaction.Chat -# Description: Allow say chat between factions. -# Default: 0 - (Disabled) -# 1 - (Enabled) - -AllowTwoSide.Interaction.Chat = 0 - -# # AllowTwoSide.Interaction.Channel # Description: Allow channel chat between factions. # Default: 0 - (Disabled) @@ -1260,30 +1241,6 @@ AllowTwoSide.Interaction.Guild = 0 AllowTwoSide.Interaction.Auction = 0 # -# AllowTwoSide.Interaction.Mail -# Description: Allow sending mails between factions. -# Default: 0 - (Disabled) -# 1 - (Enabled) - -AllowTwoSide.Interaction.Mail = 0 - -# -# AllowTwoSide.WhoList -# Description: Show characters from both factions in the /who list. -# Default: 0 - (Disabled) -# 1 - (Enabled) - -AllowTwoSide.WhoList = 0 - -# -# AllowTwoSide.AddFriend -# Description: Allow adding friends from other faction the friends list. -# Default: 0 - (Disabled) -# 1 - (Enabled) - -AllowTwoSide.AddFriend = 0 - -# # AllowTwoSide.Trade # Description: Allow trading between factions. # Default: 0 - (Disabled) @@ -1538,15 +1495,6 @@ ChatFlood.MuteTime = 10 Channel.RestrictedLfg = 1 # -# Channel.SilentlyGMJoin -# Description: Silently join GM characters to channels. If set to 1, channel kick and ban -# commands issued by a GM will not be broadcasted. -# Default: 0 - (Disabled, Join with announcement) -# 1 - (Enabled, Join without announcement) - -Channel.SilentlyGMJoin = 0 - -# # ChatLevelReq.Channel # Description: Level requirement for characters to be able to write in chat channels. # Default: 1 @@ -1568,14 +1516,6 @@ ChatLevelReq.Whisper = 1 ChatLevelReq.Say = 1 # -# AllowPlayerCommands -# Description: Allow players to use commands. -# Default: 1 - (Enabled) -# 0 - (Disabled) - -AllowPlayerCommands = 1 - -# # PreserveCustomChannels # Description: Store custom chat channel settings like password, automatic ownership handout # or ban list in the database. Needs to be enabled to save custom @@ -1658,14 +1598,6 @@ GM.InGMList.Level = 3 GM.InWhoList.Level = 3 # -# GM.LogTrade -# Description: Include GM trade and trade slot enchanting operations in GM log. -# Default: 1 - (Enabled) -# 0 - (Disabled) - -GM.LogTrade = 1 - -# # GM.StartLevel # Description: GM character starting level. # Default: 1 @@ -1681,14 +1613,6 @@ GM.StartLevel = 1 GM.AllowInvite = 0 # -# GM.AllowFriend -# Description: Allow players to add GM characters to their friends list. -# Default: 0 - (Disabled) -# 1 - (Enabled) - -GM.AllowFriend = 0 - -# # GM.LowerSecurity # Description: Allow lower security levels to use commands on higher security level # characters. @@ -1895,20 +1819,6 @@ Rate.Auction.Cut = 1 Rate.Honor = 1 # -# Rate.Mining.Amount -# Description: Rate for minimum/maximum times a deposit can be used. -# Default: 1 - -Rate.Mining.Amount = 1 - -# -# Rate.Mining.Next -# Description: Mining rates. -# Default: Chance to to mine a deposit again. - -Rate.Mining.Next = 1 - -# # Rate.Talent # Description: Talent point rate. # Default: 1 @@ -2652,6 +2562,14 @@ PlayerDump.DisallowPaths = 1 PlayerDump.DisallowOverwrite = 1 # +# UI.ShowQuestLevelsInDialogs +# Description: Show quest levels next to quest titles in UI dialogs +# Example: [13] Westfall Stew +# Default: 0 (do not show) + +UI.ShowQuestLevelsInDialogs = 0 + +# ################################################################################################### ################################################################################################### @@ -2661,7 +2579,7 @@ PlayerDump.DisallowOverwrite = 1 # Appender config values: Given a appender "name" # Appender.name # Description: Defines 'where to log' -# Format: Type,LogLevel,Flags,optional1,optional2 +# Format: Type,LogLevel,Flags,optional1,optional2,optional3 # # Type # 0 - (None) @@ -2712,6 +2630,13 @@ PlayerDump.DisallowOverwrite = 1 # a - (Append) # w - (Overwrite) # +# MaxFileSize: Maximum file size of the log file before creating a new log file +# (read as optional3 if Type = File) +# Size is measured in bytes expressed in a 64-bit unsigned integer. +# Maximum value is 4294967295 (4 gb). Leave blank for no limit. +# NOTE: Does not work with dynamic filenames. +# Example: 536870912 (512 mb) +# Appender.Console=1,3,0 Appender.Server=2,2,0,Server.log,w @@ -2786,6 +2711,7 @@ Appenders=Console Server GM DBErrors Char RA Warden Chat # 40 - Server Loading # 41 - Opcodes (just id and name sent / received) # 42 - SOAP +# 43 - RBAC (Role Based Access Control) # # LogLevel # 0 - (Disabled) @@ -2824,4 +2750,12 @@ Logger.Opcodes=41,6,Console Server Loggers=Root Chat DBErrors GM RA Warden Character Load WorldServer Opcodes # +# Log.Async.Enable +# Description: Enables asyncronous message logging. +# Default: 0 - (Disabled) +# 1 - (Enabled) + +Log.Async.Enable = 0 + +# ################################################################################################### |
