diff options
Diffstat (limited to 'src')
207 files changed, 6254 insertions, 5573 deletions
diff --git a/src/common/Configuration/BuiltInConfig.cpp b/src/common/Configuration/BuiltInConfig.cpp new file mode 100644 index 00000000000..c2fc3b91766 --- /dev/null +++ b/src/common/Configuration/BuiltInConfig.cpp @@ -0,0 +1,52 @@ +/* + * Copyright (C) 2008-2016 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 "BuiltInConfig.h" +#include "Config.h" +#include "GitRevision.h" + +template<typename Fn> +static std::string GetStringWithDefaultValueFromFunction( + std::string const& key, Fn getter) +{ + std::string const value = sConfigMgr->GetStringDefault(key, ""); + return value.empty() ? getter() : value; +} + +std::string BuiltInConfig::GetCMakeCommand() +{ + return GetStringWithDefaultValueFromFunction( + "CMakeCommand", GitRevision::GetCMakeCommand); +} + +std::string BuiltInConfig::GetBuildDirectory() +{ + return GetStringWithDefaultValueFromFunction( + "BuildDirectory", GitRevision::GetBuildDirectory); +} + +std::string BuiltInConfig::GetSourceDirectory() +{ + return GetStringWithDefaultValueFromFunction( + "SourceDirectory", GitRevision::GetSourceDirectory); +} + +std::string BuiltInConfig::GetMySQLExecutable() +{ + return GetStringWithDefaultValueFromFunction( + "MySQLExecutable", GitRevision::GetMySQLExecutable); +} diff --git a/src/common/Configuration/BuiltInConfig.h b/src/common/Configuration/BuiltInConfig.h new file mode 100644 index 00000000000..4ae4ed40189 --- /dev/null +++ b/src/common/Configuration/BuiltInConfig.h @@ -0,0 +1,42 @@ +/* + * Copyright (C) 2008-2016 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/>. + */ + +#ifndef BUILT_IN_CONFIG_H +#define BUILT_IN_CONFIG_H + +#include <string> + +/// Provides helper functions to access built-in values +/// which can be overwritten in config +namespace BuiltInConfig +{ + /// Returns the CMake command when any is specified in the config, + /// returns the built-in path otherwise + std::string GetCMakeCommand(); + /// Returns the build directory path when any is specified in the config, + /// returns the built-in one otherwise + std::string GetBuildDirectory(); + /// Returns the source directory path when any is specified in the config, + /// returns the built-in one otherwise + std::string GetSourceDirectory(); + /// Returns the path to the mysql executable (`mysql`) when any is specified + /// in the config, returns the built-in one otherwise + std::string GetMySQLExecutable(); + +} // namespace BuiltInConfig + +#endif // BUILT_IN_CONFIG_H diff --git a/src/common/Configuration/Config.cpp b/src/common/Configuration/Config.cpp index 6ac04615315..5db333c8aff 100644 --- a/src/common/Configuration/Config.cpp +++ b/src/common/Configuration/Config.cpp @@ -61,7 +61,7 @@ bool ConfigMgr::Reload(std::string& error) return LoadInitial(_filename, error); } -std::string ConfigMgr::GetStringDefault(std::string const& name, const std::string& def) +std::string ConfigMgr::GetStringDefault(std::string const& name, const std::string& def) const { std::string value = _config.get<std::string>(ptree::path_type(name, '/'), def); @@ -70,7 +70,7 @@ std::string ConfigMgr::GetStringDefault(std::string const& name, const std::stri return value; } -bool ConfigMgr::GetBoolDefault(std::string const& name, bool def) +bool ConfigMgr::GetBoolDefault(std::string const& name, bool def) const { try { @@ -84,12 +84,12 @@ bool ConfigMgr::GetBoolDefault(std::string const& name, bool def) } } -int ConfigMgr::GetIntDefault(std::string const& name, int def) +int ConfigMgr::GetIntDefault(std::string const& name, int def) const { return _config.get<int>(ptree::path_type(name, '/'), def); } -float ConfigMgr::GetFloatDefault(std::string const& name, float def) +float ConfigMgr::GetFloatDefault(std::string const& name, float def) const { return _config.get<float>(ptree::path_type(name, '/'), def); } diff --git a/src/common/Configuration/Config.h b/src/common/Configuration/Config.h index 5b04212ed7c..ada910d8fcc 100644 --- a/src/common/Configuration/Config.h +++ b/src/common/Configuration/Config.h @@ -41,10 +41,10 @@ public: bool Reload(std::string& error); - std::string GetStringDefault(std::string const& name, const std::string& def); - bool GetBoolDefault(std::string const& name, bool def); - int GetIntDefault(std::string const& name, int def); - float GetFloatDefault(std::string const& name, float def); + std::string GetStringDefault(std::string const& name, const std::string& def) const; + bool GetBoolDefault(std::string const& name, bool def) const; + int GetIntDefault(std::string const& name, int def) const; + float GetFloatDefault(std::string const& name, float def) const; std::string const& GetFilename(); std::list<std::string> GetKeysByString(std::string const& name); diff --git a/src/common/Define.h b/src/common/Define.h index df3dd37b503..b34edb6a549 100644 --- a/src/common/Define.h +++ b/src/common/Define.h @@ -83,10 +83,16 @@ # define ATTR_NORETURN __attribute__((__noreturn__)) # define ATTR_PRINTF(F, V) __attribute__ ((__format__ (__printf__, F, V))) # define ATTR_DEPRECATED __attribute__((__deprecated__)) +# define TRINITY_CONSTEXPR constexpr #else //COMPILER != COMPILER_GNU # define ATTR_NORETURN # define ATTR_PRINTF(F, V) # define ATTR_DEPRECATED +#if _MSC_VER >= 1900 +# define TRINITY_CONSTEXPR constexpr +#else +# define TRINITY_CONSTEXPR +#endif #endif //COMPILER == COMPILER_GNU #define UI64FMTD "%" PRIu64 diff --git a/src/common/GitRevision.cpp b/src/common/GitRevision.cpp index d0719c09959..5343fbd6531 100644 --- a/src/common/GitRevision.cpp +++ b/src/common/GitRevision.cpp @@ -17,6 +17,16 @@ char const* GitRevision::GetBranch() return _BRANCH; } +char const* GitRevision::GetCMakeCommand() +{ + return _CMAKE_COMMAND; +} + +char const* GitRevision::GetBuildDirectory() +{ + return _BUILD_DIRECTORY; +} + char const* GitRevision::GetSourceDirectory() { return _SOURCE_DIRECTORY; @@ -66,13 +76,3 @@ char const* GitRevision::GetProductVersionStr() { return VER_PRODUCTVERSION_STR; } - -char const* GitRevision::GetCompilerCFlags() -{ - return COMPILER_C_FLAGS; -} - -char const* GitRevision::GetCompilerCXXFlags() -{ - return COMPILER_CXX_FLAGS; -} diff --git a/src/common/GitRevision.h b/src/common/GitRevision.h index 8d2764ba861..7fddcb7605a 100644 --- a/src/common/GitRevision.h +++ b/src/common/GitRevision.h @@ -25,6 +25,8 @@ namespace GitRevision char const* GetHash(); char const* GetDate(); char const* GetBranch(); + char const* GetCMakeCommand(); + char const* GetBuildDirectory(); char const* GetSourceDirectory(); char const* GetMySQLExecutable(); char const* GetFullDatabase(); @@ -33,8 +35,6 @@ namespace GitRevision char const* GetLegalCopyrightStr(); char const* GetFileVersionStr(); char const* GetProductVersionStr(); - char const* GetCompilerCFlags(); - char const* GetCompilerCXXFlags(); } #endif diff --git a/src/common/Logging/Log.cpp b/src/common/Logging/Log.cpp index 4bd0487343d..a80a4671822 100644 --- a/src/common/Logging/Log.cpp +++ b/src/common/Logging/Log.cpp @@ -214,13 +214,13 @@ void Log::ReadLoggersFromConfig() AppenderConsole* appender = new AppenderConsole(NextAppenderId(), "Console", LOG_LEVEL_DEBUG, APPENDER_FLAGS_NONE, ExtraAppenderArgs()); appenders[appender->getId()] = appender; - Logger& logger = loggers[LOGGER_ROOT]; - logger.Create(LOGGER_ROOT, LOG_LEVEL_ERROR); - logger.addAppender(appender->getId(), appender); + Logger& rootLogger = loggers[LOGGER_ROOT]; + rootLogger.Create(LOGGER_ROOT, LOG_LEVEL_ERROR); + rootLogger.addAppender(appender->getId(), appender); - logger = loggers["server"]; - logger.Create("server", LOG_LEVEL_ERROR); - logger.addAppender(appender->getId(), appender); + Logger& serverLogger = loggers["server"]; + serverLogger.Create("server", LOG_LEVEL_INFO); + serverLogger.addAppender(appender->getId(), appender); } } diff --git a/src/common/Threading/MPSCQueue.h b/src/common/Threading/MPSCQueue.h new file mode 100644 index 00000000000..09648b844be --- /dev/null +++ b/src/common/Threading/MPSCQueue.h @@ -0,0 +1,83 @@ +/* + * Copyright (C) 2008-2016 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/>. + */ + +#ifndef MPSCQueue_h__ +#define MPSCQueue_h__ + +#include <atomic> +#include <utility> + +// C++ implementation of Dmitry Vyukov's lock free MPSC queue +// http://www.1024cores.net/home/lock-free-algorithms/queues/non-intrusive-mpsc-node-based-queue +template<typename T> +class MPSCQueue +{ +public: + MPSCQueue() : _head(new Node()), _tail(_head.load(std::memory_order_relaxed)) + { + Node* front = _head.load(std::memory_order_relaxed); + front->Next.store(nullptr, std::memory_order_relaxed); + } + + ~MPSCQueue() + { + T* output; + while (this->Dequeue(output)) + ; + + Node* front = _head.load(std::memory_order_relaxed); + delete front; + } + + void Enqueue(T* input) + { + Node* node = new Node(input); + Node* prevHead = _head.exchange(node, std::memory_order_acq_rel); + prevHead->Next.store(node, std::memory_order_release); + } + + bool Dequeue(T*& result) + { + Node* tail = _tail.load(std::memory_order_relaxed); + Node* next = tail->Next.load(std::memory_order_acquire); + if (!next) + return false; + + result = next->Data; + _tail.store(next, std::memory_order_release); + delete tail; + return true; + } + +private: + struct Node + { + Node() = default; + explicit Node(T* data) : Data(data) { Next.store(nullptr, std::memory_order_relaxed); } + + T* Data; + std::atomic<Node*> Next; + }; + + std::atomic<Node*> _head; + std::atomic<Node*> _tail; + + MPSCQueue(MPSCQueue const&) = delete; + MPSCQueue& operator=(MPSCQueue const&) = delete; +}; + +#endif // MPSCQueue_h__ diff --git a/src/server/shared/Containers.h b/src/common/Utilities/Containers.h index c2ebbf58a1e..f3e9432ca4c 100644 --- a/src/server/shared/Containers.h +++ b/src/common/Utilities/Containers.h @@ -19,10 +19,11 @@ #define TRINITY_CONTAINERS_H #include "Define.h" +#include "Random.h" +#include <algorithm> +#include <functional> #include <list> - -//! Because circular includes are bad -extern uint32 urand(uint32 min, uint32 max); +#include <vector> namespace Trinity { @@ -57,14 +58,64 @@ namespace Trinity list = listCopy; } - /* Select a random element from a container. Note: make sure you explicitly empty check the container */ - template <class C> typename C::value_type const& SelectRandomContainerElement(C const& container) + /* + * Select a random element from a container. + * + * Note: container cannot be empty + */ + template <class C> + typename C::value_type const& SelectRandomContainerElement(C const& container) { typename C::const_iterator it = container.begin(); std::advance(it, urand(0, container.size() - 1)); return *it; } + /* + * Select a random element from a container where each element has a different chance to be selected. + * + * @param container Container to select an element from + * @param weights Chances of each element to be selected, must be in the same order as elements in container. + * Caller is responsible for checking that sum of all weights is greater than 0. + * + * Note: container cannot be empty + */ + template <class C> + typename C::const_iterator SelectRandomWeightedContainerElement(C const& container, std::vector<double> weights) + { + Trinity::discrete_distribution_param<uint32> ddParam(weights.begin(), weights.end()); + std::discrete_distribution<uint32> dd(ddParam); + typename C::const_iterator it = container.begin(); + std::advance(it, dd(SFMTEngine::Instance())); + return it; + } + + /* + * Select a random element from a container where each element has a different chance to be selected. + * + * @param container Container to select an element from + * @param weightExtractor Function retrieving chance of each element in container, expected to take an element of the container and returning a double + * + * Note: container cannot be empty + */ + template <class C, class Fn> + typename C::const_iterator SelectRandomWeightedContainerElement(C const& container, Fn weightExtractor) + { + std::vector<double> weights; + weights.reserve(container.size()); + double weightSum = 0.0; + for (auto itr = container.begin(); itr != container.end(); ++itr) + { + double weight = weightExtractor(*itr); + weights.push_back(weight); + weightSum += weight; + } + if (weightSum <= 0.0) + weights.assign(container.size(), 1.0); + + return SelectRandomWeightedContainerElement(container, weights); + } + /** * @fn bool Trinity::Containers::Intersects(Iterator first1, Iterator last1, Iterator first2, Iterator last2) * diff --git a/src/common/Utilities/Random.cpp b/src/common/Utilities/Random.cpp new file mode 100644 index 00000000000..31318e8f52d --- /dev/null +++ b/src/common/Utilities/Random.cpp @@ -0,0 +1,91 @@ +/* + * Copyright (C) 2008-2015 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 "Random.h" +#include "Common.h" +#include "Errors.h" +#include "SFMT.h" +#include <boost/thread/tss.hpp> + +static boost::thread_specific_ptr<SFMTRand> sfmtRand; + +static SFMTRand* GetRng() +{ + SFMTRand* rand = sfmtRand.get(); + + if (!rand) + { + rand = new SFMTRand(); + sfmtRand.reset(rand); + } + + return rand; +} + +int32 irand(int32 min, int32 max) +{ + ASSERT(max >= min); + return int32(GetRng()->IRandom(min, max)); +} + +uint32 urand(uint32 min, uint32 max) +{ + ASSERT(max >= min); + return GetRng()->URandom(min, max); +} + +uint32 urandms(uint32 min, uint32 max) +{ + ASSERT(max >= min); + ASSERT(INT_MAX / IN_MILLISECONDS >= max); + return GetRng()->URandom(min * IN_MILLISECONDS, max * IN_MILLISECONDS); +} + +float frand(float min, float max) +{ + ASSERT(max >= min); + return float(GetRng()->Random() * (max - min) + min); +} + +Milliseconds randtime(Milliseconds const& min, Milliseconds const& max) +{ + long long diff = max.count() - min.count(); + ASSERT(diff >= 0); + ASSERT(diff <= (uint32)-1); + return min + Milliseconds(urand(0, diff)); +} + +uint32 rand32() +{ + return GetRng()->BRandom(); +} + +double rand_norm() +{ + return GetRng()->Random(); +} + +double rand_chance() +{ + return GetRng()->Random() * 100.0; +} + +SFMTEngine& SFMTEngine::Instance() +{ + static SFMTEngine engine; + return engine; +} diff --git a/src/common/Utilities/Random.h b/src/common/Utilities/Random.h new file mode 100644 index 00000000000..5dea6117f97 --- /dev/null +++ b/src/common/Utilities/Random.h @@ -0,0 +1,99 @@ +/* + * Copyright (C) 2008-2015 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/>. + */ + +#ifndef Random_h__ +#define Random_h__ + +#include "Define.h" +#include "Duration.h" +#include <limits> +#include <random> + +/* Return a random number in the range min..max. */ +int32 irand(int32 min, int32 max); + +/* Return a random number in the range min..max (inclusive). */ +uint32 urand(uint32 min, uint32 max); + +/* Return a random millisecond value between min and max seconds. Functionally equivalent to urand(min*IN_MILLISECONDS, max*IN_MILLISECONDS). */ +uint32 urandms(uint32 min, uint32 max); + +/* Return a random number in the range 0 .. UINT32_MAX. */ +uint32 rand32(); + +/* Return a random time in the range min..max (up to millisecond precision). Only works for values where millisecond difference is a valid uint32. */ +Milliseconds randtime(Milliseconds const& min, Milliseconds const& max); + +/* Return a random number in the range min..max */ +float frand(float min, float max); + +/* Return a random double from 0.0 to 1.0 (exclusive). */ +double rand_norm(); + +/* Return a random double from 0.0 to 100.0 (exclusive). */ +double rand_chance(); + +/* Return true if a random roll fits in the specified chance (range 0-100). */ +inline bool roll_chance_f(float chance) +{ + return chance > rand_chance(); +} + +/* Return true if a random roll fits in the specified chance (range 0-100). */ +inline bool roll_chance_i(int chance) +{ + return chance > irand(0, 99); +} + +/* +* SFMT wrapper satisfying UniformRandomNumberGenerator concept for use in <random> algorithms +*/ +class SFMTEngine +{ +public: + typedef uint32 result_type; + + static TRINITY_CONSTEXPR result_type min() { return std::numeric_limits<result_type>::min(); } + static TRINITY_CONSTEXPR result_type max() { return std::numeric_limits<result_type>::max(); } + result_type operator()() const { return rand32(); } + + static SFMTEngine& Instance(); +}; + +// Ugly, horrible, i don't even..., hack for VS2013 to work around missing discrete_distribution(iterator, iterator) constructor +namespace Trinity +{ +#if COMPILER == COMPILER_MICROSOFT && _MSC_VER <= 1800 + template<typename T> + struct discrete_distribution_param : public std::discrete_distribution<T>::param_type + { + typedef typename std::discrete_distribution<T>::param_type base; + + template<typename InIt> + discrete_distribution_param(InIt begin, InIt end) : base(_Noinit()) + { + this->_Pvec.assign(begin, end); + this->_Init(); + } + }; +#else + template<typename T> + using discrete_distribution_param = typename std::discrete_distribution<T>::param_type; +#endif +} + +#endif // Random_h__ diff --git a/src/common/Utilities/Util.cpp b/src/common/Utilities/Util.cpp index 3eb901ca35d..1360253294f 100644 --- a/src/common/Utilities/Util.cpp +++ b/src/common/Utilities/Util.cpp @@ -20,10 +20,8 @@ #include "Common.h" #include "CompilerDefs.h" #include "utf8.h" -#include "SFMT.h" #include "Errors.h" // for ASSERT #include <stdarg.h> -#include <boost/thread/tss.hpp> #if COMPILER == COMPILER_GNU #include <sys/socket.h> @@ -31,61 +29,6 @@ #include <arpa/inet.h> #endif -static boost::thread_specific_ptr<SFMTRand> sfmtRand; - -static SFMTRand* GetRng() -{ - SFMTRand* rand = sfmtRand.get(); - - if (!rand) - { - rand = new SFMTRand(); - sfmtRand.reset(rand); - } - - return rand; -} - -int32 irand(int32 min, int32 max) -{ - ASSERT(max >= min); - return int32(GetRng()->IRandom(min, max)); -} - -uint32 urand(uint32 min, uint32 max) -{ - ASSERT(max >= min); - return GetRng()->URandom(min, max); -} - -uint32 urandms(uint32 min, uint32 max) -{ - ASSERT(max >= min); - ASSERT(INT_MAX/IN_MILLISECONDS >= max); - return GetRng()->URandom(min * IN_MILLISECONDS, max * IN_MILLISECONDS); -} - -float frand(float min, float max) -{ - ASSERT(max >= min); - return float(GetRng()->Random() * (max - min) + min); -} - -uint32 rand32() -{ - return GetRng()->BRandom(); -} - -double rand_norm() -{ - return GetRng()->Random(); -} - -double rand_chance() -{ - return GetRng()->Random() * 100.0; -} - Tokenizer::Tokenizer(const std::string &src, const char sep, uint32 vectorReserve) { m_str = new char[src.length() + 1]; diff --git a/src/common/Utilities/Util.h b/src/common/Utilities/Util.h index 1f3b78a8d56..ab5cabca8d2 100644 --- a/src/common/Utilities/Util.h +++ b/src/common/Utilities/Util.h @@ -21,6 +21,7 @@ #include "Define.h" #include "Errors.h" +#include "Random.h" #include <algorithm> #include <string> @@ -77,39 +78,6 @@ std::string secsToTimeString(uint64 timeInSecs, bool shortText = false, bool hou uint32 TimeStringToSecs(const std::string& timestring); std::string TimeToTimestampStr(time_t t); -/* Return a random number in the range min..max. */ -int32 irand(int32 min, int32 max); - -/* Return a random number in the range min..max (inclusive). */ -uint32 urand(uint32 min, uint32 max); - -/* Return a random millisecond value between min and max seconds. Functionally equivalent to urand(min*IN_MILLISECONDS, max*IN_MILLISECONDS). */ -uint32 urandms(uint32 min, uint32 max); - -/* Return a random number in the range 0 .. UINT32_MAX. */ -uint32 rand32(); - -/* Return a random number in the range min..max */ -float frand(float min, float max); - -/* Return a random double from 0.0 to 1.0 (exclusive). */ -double rand_norm(); - -/* Return a random double from 0.0 to 100.0 (exclusive). */ -double rand_chance(); - -/* Return true if a random roll fits in the specified chance (range 0-100). */ -inline bool roll_chance_f(float chance) -{ - return chance > rand_chance(); -} - -/* Return true if a random roll fits in the specified chance (range 0-100). */ -inline bool roll_chance_i(int chance) -{ - return chance > irand(0, 99); -} - inline void ApplyPercentModFloatVar(float& var, float val, bool apply) { if (val == -100.0f) // prevent set var to zero diff --git a/src/server/authserver/CMakeLists.txt b/src/server/authserver/CMakeLists.txt index c11deec39bb..d87847d6740 100644 --- a/src/server/authserver/CMakeLists.txt +++ b/src/server/authserver/CMakeLists.txt @@ -79,10 +79,10 @@ if( NOT WIN32 ) endif() target_link_libraries(authserver - common shared - format database + common + format ${MYSQL_LIBRARY} ${OPENSSL_LIBRARIES} ${CMAKE_THREAD_LIBS_INIT} diff --git a/src/server/authserver/Main.cpp b/src/server/authserver/Main.cpp index 0c812ebd494..0618ec437b6 100644 --- a/src/server/authserver/Main.cpp +++ b/src/server/authserver/Main.cpp @@ -68,11 +68,14 @@ bool StartDB(); void StopDB(); void SignalHandler(const boost::system::error_code& error, int signalNumber); void KeepDatabaseAliveHandler(const boost::system::error_code& error); +void BanExpiryHandler(boost::system::error_code const& error); variables_map GetConsoleArguments(int argc, char** argv, std::string& configFile, std::string& configService); boost::asio::io_service* _ioService; boost::asio::deadline_timer* _dbPingTimer; uint32 _dbPingInterval; +boost::asio::deadline_timer* _banExpiryCheckTimer; +uint32 _banExpiryCheckInterval; LoginDatabaseWorkerPool LoginDatabase; int main(int argc, char** argv) @@ -169,6 +172,11 @@ int main(int argc, char** argv) _dbPingTimer->expires_from_now(boost::posix_time::minutes(_dbPingInterval)); _dbPingTimer->async_wait(KeepDatabaseAliveHandler); + _banExpiryCheckInterval = sConfigMgr->GetIntDefault("BanExpiryCheckInterval", 60); + _banExpiryCheckTimer = new boost::asio::deadline_timer(*_ioService); + _banExpiryCheckTimer->expires_from_now(boost::posix_time::seconds(_banExpiryCheckInterval)); + _banExpiryCheckTimer->async_wait(BanExpiryHandler); + #if PLATFORM == PLATFORM_WINDOWS if (m_ServiceStatus != -1) { @@ -181,6 +189,7 @@ int main(int argc, char** argv) // Start the io service worker loop _ioService->run(); + _banExpiryCheckTimer->cancel(); _dbPingTimer->cancel(); sAuthSocketMgr.StopNetwork(); @@ -192,6 +201,7 @@ int main(int argc, char** argv) signals.cancel(); + delete _banExpiryCheckTimer; delete _dbPingTimer; delete _ioService; return 0; @@ -242,6 +252,18 @@ void KeepDatabaseAliveHandler(const boost::system::error_code& error) } } +void BanExpiryHandler(boost::system::error_code const& error) +{ + if (!error) + { + LoginDatabase.Execute(LoginDatabase.GetPreparedStatement(LOGIN_DEL_EXPIRED_IP_BANS)); + LoginDatabase.Execute(LoginDatabase.GetPreparedStatement(LOGIN_UPD_EXPIRED_ACCOUNT_BANS)); + + _banExpiryCheckTimer->expires_from_now(boost::posix_time::seconds(_banExpiryCheckInterval)); + _banExpiryCheckTimer->async_wait(BanExpiryHandler); + } +} + #if PLATFORM == PLATFORM_WINDOWS void ServiceStatusWatcher(boost::system::error_code const& error) { diff --git a/src/server/authserver/Server/AuthSession.cpp b/src/server/authserver/Server/AuthSession.cpp index 60e9b734b13..57e5d6682f2 100644 --- a/src/server/authserver/Server/AuthSession.cpp +++ b/src/server/authserver/Server/AuthSession.cpp @@ -43,12 +43,6 @@ enum eAuthCmd XFER_CANCEL = 0x34 }; -enum eStatus -{ - STATUS_CONNECTED = 0, - STATUS_AUTHED -}; - #pragma pack(push, 1) typedef struct AUTH_LOGON_CHALLENGE_C @@ -115,11 +109,10 @@ enum class BufferSizes : uint32 SRP_6_S = 0x20, }; +#define MAX_ACCEPTED_CHALLENGE_SIZE (sizeof(AUTH_LOGON_CHALLENGE_C) + 16) + #define AUTH_LOGON_CHALLENGE_INITIAL_SIZE 4 #define REALM_LIST_PACKET_SIZE 5 -#define XFER_ACCEPT_SIZE 1 -#define XFER_RESUME_SIZE 9 -#define XFER_CANCEL_SIZE 1 std::unordered_map<uint8, AuthHandler> AuthSession::InitHandlers() { @@ -130,15 +123,98 @@ std::unordered_map<uint8, AuthHandler> AuthSession::InitHandlers() handlers[AUTH_RECONNECT_CHALLENGE] = { STATUS_CONNECTED, AUTH_LOGON_CHALLENGE_INITIAL_SIZE, &AuthSession::HandleReconnectChallenge }; handlers[AUTH_RECONNECT_PROOF] = { STATUS_CONNECTED, sizeof(AUTH_RECONNECT_PROOF_C), &AuthSession::HandleReconnectProof }; handlers[REALM_LIST] = { STATUS_AUTHED, REALM_LIST_PACKET_SIZE, &AuthSession::HandleRealmList }; - handlers[XFER_ACCEPT] = { STATUS_AUTHED, XFER_ACCEPT_SIZE, &AuthSession::HandleXferAccept }; - handlers[XFER_RESUME] = { STATUS_AUTHED, XFER_RESUME_SIZE, &AuthSession::HandleXferResume }; - handlers[XFER_CANCEL] = { STATUS_AUTHED, XFER_CANCEL_SIZE, &AuthSession::HandleXferCancel }; return handlers; } std::unordered_map<uint8, AuthHandler> const Handlers = AuthSession::InitHandlers(); +void AccountInfo::LoadResult(Field* fields) +{ + // 0 1 2 3 4 5 6 + //SELECT a.id, a.username, a.locked, a.lock_country, a.last_ip, a.failed_logins, ab.unbandate > UNIX_TIMESTAMP() OR ab.unbandate = ab.bandate, + // 7 8 9 10 11 12 + // ab.unbandate = ab.bandate, aa.gmlevel, a.token_key, a.sha_pass_hash, a.v, a.s + //FROM account a LEFT JOIN account_access aa ON a.id = aa.id LEFT JOIN account_banned ab ON ab.id = a.id AND ab.active = 1 WHERE a.username = ? + + Id = fields[0].GetUInt32(); + Login = fields[1].GetString(); + IsLockedToIP = fields[2].GetBool(); + LockCountry = fields[3].GetString(); + LastIP = fields[4].GetString(); + FailedLogins = fields[5].GetUInt32(); + IsBanned = fields[6].GetUInt64() != 0; + IsPermanenetlyBanned = fields[7].GetUInt64() != 0; + SecurityLevel = AccountTypes(fields[8].GetUInt8()); +} + +AuthSession::AuthSession(tcp::socket&& socket) : Socket(std::move(socket)), +_sentChallenge(false), _sentProof(false), +_status(STATUS_CONNECTED), _build(0), _expversion(0) +{ + N.SetHexStr("894B645E89E1535BBDAD5B8B290650530801B18EBFBF5E8FAB3C82872A3E9BB7"); + g.SetDword(7); +} + +void AuthSession::Start() +{ + std::string ip_address = GetRemoteIpAddress().to_string(); + TC_LOG_TRACE("session", "Accepted connection from %s", ip_address.c_str()); + + PreparedStatement* stmt = LoginDatabase.GetPreparedStatement(LOGIN_SEL_IP_INFO); + stmt->setString(0, ip_address); + stmt->setUInt32(1, inet_addr(ip_address.c_str())); + + _queryCallback = std::bind(&AuthSession::CheckIpCallback, this, std::placeholders::_1); + _queryFuture = LoginDatabase.AsyncQuery(stmt); +} + +bool AuthSession::Update() +{ + if (!AuthSocket::Update()) + return false; + + if (_queryFuture.valid() && _queryFuture.wait_for(std::chrono::seconds(0)) == std::future_status::ready) + { + auto callback = _queryCallback; + _queryCallback = nullptr; + callback(_queryFuture.get()); + } + + return true; +} + +void AuthSession::CheckIpCallback(PreparedQueryResult result) +{ + if (result) + { + bool banned = false; + do + { + Field* fields = result->Fetch(); + if (fields[0].GetUInt64() != 0) + banned = true; + + if (!fields[1].GetString().empty()) + _ipCountry = fields[1].GetString(); + + } while (result->NextRow()); + + if (banned) + { + ByteBuffer pkt; + pkt << uint8(AUTH_LOGON_CHALLENGE); + pkt << uint8(0x00); + pkt << uint8(WOW_FAIL_BANNED); + SendPacket(pkt); + TC_LOG_DEBUG("session", "[AuthSession::CheckIpCallback] Banned ip '%s:%d' tries to login!", GetRemoteIpAddress().to_string().c_str(), GetRemotePort()); + return; + } + } + + AsyncRead(); +} + void AuthSession::ReadHandler() { MessageBuffer& packet = GetReadBuffer(); @@ -153,6 +229,12 @@ void AuthSession::ReadHandler() break; } + if (_status != itr->second.status) + { + CloseSocket(); + return; + } + uint16 size = uint16(itr->second.packetSize); if (packet.GetActiveSize() < size) break; @@ -161,12 +243,17 @@ void AuthSession::ReadHandler() { sAuthLogonChallenge_C* challenge = reinterpret_cast<sAuthLogonChallenge_C*>(packet.GetReadPointer()); size += challenge->size; + if (size > MAX_ACCEPTED_CHALLENGE_SIZE) + { + CloseSocket(); + return; + } } if (packet.GetActiveSize() < size) break; - if (!(*this.*Handlers.at(cmd).handler)()) + if (!(*this.*itr->second.handler)()) { CloseSocket(); return; @@ -187,233 +274,209 @@ void AuthSession::SendPacket(ByteBuffer& packet) { MessageBuffer buffer; buffer.Write(packet.contents(), packet.size()); - - std::unique_lock<std::mutex> guard(_writeLock); - - QueuePacket(std::move(buffer), guard); + QueuePacket(std::move(buffer)); } } bool AuthSession::HandleLogonChallenge() { + if (_sentChallenge) + return false; + + _sentChallenge = true; + sAuthLogonChallenge_C* challenge = reinterpret_cast<sAuthLogonChallenge_C*>(GetReadBuffer().GetReadPointer()); + if (challenge->size - (sizeof(sAuthLogonChallenge_C) - AUTH_LOGON_CHALLENGE_INITIAL_SIZE - 1) != challenge->I_len) + return false; - //TC_LOG_DEBUG("server.authserver", "[AuthChallenge] got full packet, %#04x bytes", challenge->size); - TC_LOG_DEBUG("server.authserver", "[AuthChallenge] name(%d): '%s'", challenge->I_len, challenge->I); + std::string login((const char*)challenge->I, challenge->I_len); + TC_LOG_DEBUG("server.authserver", "[AuthChallenge] '%s'", login.c_str()); - ByteBuffer pkt; + if (_queryCallback) + { + ByteBuffer pkt; + pkt << uint8(AUTH_LOGON_CHALLENGE); + pkt << uint8(0x00); + pkt << uint8(WOW_FAIL_DB_BUSY); + SendPacket(pkt); + + TC_LOG_DEBUG("server.authserver", "[AuthChallenge] %s attempted to log too quick after previous attempt!", login.c_str()); + return true; + } - _login.assign((const char*)challenge->I, challenge->I_len); _build = challenge->build; _expversion = uint8(AuthHelper::IsPostBCAcceptedClientBuild(_build) ? POST_BC_EXP_FLAG : (AuthHelper::IsPreBCAcceptedClientBuild(_build) ? PRE_BC_EXP_FLAG : NO_VALID_EXP_FLAG)); - _os = (const char*)challenge->os; - - if (_os.size() > 4) - return false; + std::array<char, 5> os; + os.fill('\0'); + memcpy(os.data(), challenge->os, sizeof(challenge->os)); + _os = os.data(); // Restore string order as its byte order is reversed std::reverse(_os.begin(), _os.end()); + _localizationName.resize(4); + for (int i = 0; i < 4; ++i) + _localizationName[i] = challenge->country[4 - i - 1]; + + // Get the account details from the account table + PreparedStatement* stmt = LoginDatabase.GetPreparedStatement(LOGIN_SEL_LOGONCHALLENGE); + stmt->setString(0, login); + + _queryCallback = std::bind(&AuthSession::LogonChallengeCallback, this, std::placeholders::_1); + _queryFuture = LoginDatabase.AsyncQuery(stmt); + return true; +} + +void AuthSession::LogonChallengeCallback(PreparedQueryResult result) +{ + ByteBuffer pkt; pkt << uint8(AUTH_LOGON_CHALLENGE); pkt << uint8(0x00); - // Verify that this IP is not in the ip_banned table - LoginDatabase.Execute(LoginDatabase.GetPreparedStatement(LOGIN_DEL_EXPIRED_IP_BANS)); + if (!result) + { + pkt << uint8(WOW_FAIL_UNKNOWN_ACCOUNT); + SendPacket(pkt); + return; + } + + Field* fields = result->Fetch(); + + _accountInfo.LoadResult(fields); std::string ipAddress = GetRemoteIpAddress().to_string(); uint16 port = GetRemotePort(); - PreparedStatement* stmt = LoginDatabase.GetPreparedStatement(LOGIN_SEL_IP_BANNED); - stmt->setString(0, ipAddress); - PreparedQueryResult result = LoginDatabase.Query(stmt); - if (result) + // If the IP is 'locked', check that the player comes indeed from the correct IP address + if (_accountInfo.IsLockedToIP) { - pkt << uint8(WOW_FAIL_BANNED); - TC_LOG_DEBUG("server.authserver", "'%s:%d' [AuthChallenge] Banned ip tries to login!", ipAddress.c_str(), port); + TC_LOG_DEBUG("server.authserver", "[AuthChallenge] Account '%s' is locked to IP - '%s' is logging in from '%s'", _accountInfo.Login.c_str(), _accountInfo.LastIP.c_str(), ipAddress.c_str()); + if (_accountInfo.LastIP != ipAddress) + { + pkt << uint8(WOW_FAIL_LOCKED_ENFORCED); + SendPacket(pkt); + return; + } } else { - // Get the account details from the account table - // No SQL injection (prepared statement) - stmt = LoginDatabase.GetPreparedStatement(LOGIN_SEL_LOGONCHALLENGE); - stmt->setString(0, _login); - - PreparedQueryResult res2 = LoginDatabase.Query(stmt); - if (res2) + TC_LOG_DEBUG("server.authserver", "[AuthChallenge] Account '%s' is not locked to ip", _accountInfo.Login.c_str()); + if (_accountInfo.LockCountry.empty() || _accountInfo.LockCountry == "00") + TC_LOG_DEBUG("server.authserver", "[AuthChallenge] Account '%s' is not locked to country", _accountInfo.Login.c_str()); + else if (!_accountInfo.LockCountry.empty() && !_ipCountry.empty()) { - Field* fields = res2->Fetch(); - - // If the IP is 'locked', check that the player comes indeed from the correct IP address - bool locked = false; - if (fields[2].GetUInt8() == 1) // if ip is locked - { - TC_LOG_DEBUG("server.authserver", "[AuthChallenge] Account '%s' is locked to IP - '%s'", _login.c_str(), fields[4].GetCString()); - TC_LOG_DEBUG("server.authserver", "[AuthChallenge] Player address is '%s'", ipAddress.c_str()); - - if (strcmp(fields[4].GetCString(), ipAddress.c_str()) != 0) - { - TC_LOG_DEBUG("server.authserver", "[AuthChallenge] Account IP differs"); - pkt << uint8(WOW_FAIL_LOCKED_ENFORCED); - locked = true; - } - else - TC_LOG_DEBUG("server.authserver", "[AuthChallenge] Account IP matches"); - } - else + TC_LOG_DEBUG("server.authserver", "[AuthChallenge] Account '%s' is locked to country: '%s' Player country is '%s'", _accountInfo.Login.c_str(), _accountInfo.LockCountry.c_str(), _ipCountry.c_str()); + if (_ipCountry != _accountInfo.LockCountry) { - TC_LOG_DEBUG("server.authserver", "[AuthChallenge] Account '%s' is not locked to ip", _login.c_str()); - std::string accountCountry = fields[3].GetString(); - if (accountCountry.empty() || accountCountry == "00") - TC_LOG_DEBUG("server.authserver", "[AuthChallenge] Account '%s' is not locked to country", _login.c_str()); - else if (!accountCountry.empty()) - { - uint32 ip = inet_addr(ipAddress.c_str()); - EndianConvertReverse(ip); - - stmt = LoginDatabase.GetPreparedStatement(LOGIN_SEL_LOGON_COUNTRY); - stmt->setUInt32(0, ip); - if (PreparedQueryResult sessionCountryQuery = LoginDatabase.Query(stmt)) - { - std::string loginCountry = (*sessionCountryQuery)[0].GetString(); - TC_LOG_DEBUG("server.authserver", "[AuthChallenge] Account '%s' is locked to country: '%s' Player country is '%s'", _login.c_str(), - accountCountry.c_str(), loginCountry.c_str()); - - if (loginCountry != accountCountry) - { - TC_LOG_DEBUG("server.authserver", "[AuthChallenge] Account country differs."); - pkt << uint8(WOW_FAIL_UNLOCKABLE_LOCK); - locked = true; - } - else - TC_LOG_DEBUG("server.authserver", "[AuthChallenge] Account country matches"); - } - else - TC_LOG_DEBUG("server.authserver", "[AuthChallenge] IP2NATION Table empty"); - } + pkt << uint8(WOW_FAIL_UNLOCKABLE_LOCK); + SendPacket(pkt); + return; } + } + } - if (!locked) - { - //set expired bans to inactive - LoginDatabase.DirectExecute(LoginDatabase.GetPreparedStatement(LOGIN_UPD_EXPIRED_ACCOUNT_BANS)); - - // If the account is banned, reject the logon attempt - stmt = LoginDatabase.GetPreparedStatement(LOGIN_SEL_ACCOUNT_BANNED); - stmt->setUInt32(0, fields[1].GetUInt32()); - PreparedQueryResult banresult = LoginDatabase.Query(stmt); - if (banresult) - { - if ((*banresult)[0].GetUInt32() == (*banresult)[1].GetUInt32()) - { - pkt << uint8(WOW_FAIL_BANNED); - TC_LOG_DEBUG("server.authserver", "'%s:%d' [AuthChallenge] Banned account %s tried to login!", ipAddress.c_str(), - port, _login.c_str()); - } - else - { - pkt << uint8(WOW_FAIL_SUSPENDED); - TC_LOG_DEBUG("server.authserver", "'%s:%d' [AuthChallenge] Temporarily banned account %s tried to login!", - ipAddress.c_str(), port, _login.c_str()); - } - } - else - { - // Get the password from the account table, upper it, and make the SRP6 calculation - std::string rI = fields[0].GetString(); - - // Don't calculate (v, s) if there are already some in the database - std::string databaseV = fields[6].GetString(); - std::string databaseS = fields[7].GetString(); - - TC_LOG_DEBUG("network", "database authentication values: v='%s' s='%s'", databaseV.c_str(), databaseS.c_str()); - - // multiply with 2 since bytes are stored as hexstring - if (databaseV.size() != size_t(BufferSizes::SRP_6_V) * 2 || databaseS.size() != size_t(BufferSizes::SRP_6_S) * 2) - SetVSFields(rI); - else - { - s.SetHexStr(databaseS.c_str()); - v.SetHexStr(databaseV.c_str()); - } - - b.SetRand(19 * 8); - BigNumber gmod = g.ModExp(b, N); - B = ((v * 3) + gmod) % N; - - ASSERT(gmod.GetNumBytes() <= 32); - - BigNumber unk3; - unk3.SetRand(16 * 8); - - // Fill the response packet with the result - if (AuthHelper::IsAcceptedClientBuild(_build)) - pkt << uint8(WOW_SUCCESS); - else - pkt << uint8(WOW_FAIL_VERSION_INVALID); - - // B may be calculated < 32B so we force minimal length to 32B - pkt.append(B.AsByteArray(32).get(), 32); // 32 bytes - pkt << uint8(1); - pkt.append(g.AsByteArray(1).get(), 1); - pkt << uint8(32); - pkt.append(N.AsByteArray(32).get(), 32); - pkt.append(s.AsByteArray(int32(BufferSizes::SRP_6_S)).get(), size_t(BufferSizes::SRP_6_S)); // 32 bytes - pkt.append(unk3.AsByteArray(16).get(), 16); - uint8 securityFlags = 0; - - // Check if token is used - _tokenKey = fields[8].GetString(); - if (!_tokenKey.empty()) - securityFlags = 4; - - pkt << uint8(securityFlags); // security flags (0x0...0x04) - - if (securityFlags & 0x01) // PIN input - { - pkt << uint32(0); - pkt << uint64(0) << uint64(0); // 16 bytes hash? - } - - if (securityFlags & 0x02) // Matrix input - { - pkt << uint8(0); - pkt << uint8(0); - pkt << uint8(0); - pkt << uint8(0); - pkt << uint64(0); - } - - if (securityFlags & 0x04) // Security token input - pkt << uint8(1); - - uint8 secLevel = fields[5].GetUInt8(); - _accountSecurityLevel = secLevel <= SEC_ADMINISTRATOR ? AccountTypes(secLevel) : SEC_ADMINISTRATOR; - - _localizationName.resize(4); - for (int i = 0; i < 4; ++i) - _localizationName[i] = challenge->country[4 - i - 1]; - - TC_LOG_DEBUG("server.authserver", "'%s:%d' [AuthChallenge] account %s is using '%c%c%c%c' locale (%u)", - ipAddress.c_str(), port, _login.c_str(), - challenge->country[3], challenge->country[2], challenge->country[1], challenge->country[0], - GetLocaleByName(_localizationName) - ); - } - } + // If the account is banned, reject the logon attempt + if (_accountInfo.IsBanned) + { + if (_accountInfo.IsPermanenetlyBanned) + { + pkt << uint8(WOW_FAIL_BANNED); + SendPacket(pkt); + TC_LOG_DEBUG("server.authserver", "'%s:%d' [AuthChallenge] Banned account %s tried to login!", ipAddress.c_str(), port, _accountInfo.Login.c_str()); + return; + } + else + { + pkt << uint8(WOW_FAIL_SUSPENDED); + SendPacket(pkt); + TC_LOG_DEBUG("server.authserver", "'%s:%d' [AuthChallenge] Temporarily banned account %s tried to login!", ipAddress.c_str(), port, _accountInfo.Login.c_str()); + return; } - else //no account - pkt << uint8(WOW_FAIL_UNKNOWN_ACCOUNT); } + // Get the password from the account table, upper it, and make the SRP6 calculation + std::string rI = fields[10].GetString(); + + // Don't calculate (v, s) if there are already some in the database + std::string databaseV = fields[11].GetString(); + std::string databaseS = fields[12].GetString(); + + TC_LOG_DEBUG("network", "database authentication values: v='%s' s='%s'", databaseV.c_str(), databaseS.c_str()); + + // multiply with 2 since bytes are stored as hexstring + if (databaseV.size() != size_t(BufferSizes::SRP_6_V) * 2 || databaseS.size() != size_t(BufferSizes::SRP_6_S) * 2) + SetVSFields(rI); + else + { + s.SetHexStr(databaseS.c_str()); + v.SetHexStr(databaseV.c_str()); + } + + b.SetRand(19 * 8); + BigNumber gmod = g.ModExp(b, N); + B = ((v * 3) + gmod) % N; + + ASSERT(gmod.GetNumBytes() <= 32); + + BigNumber unk3; + unk3.SetRand(16 * 8); + + // Fill the response packet with the result + if (AuthHelper::IsAcceptedClientBuild(_build)) + pkt << uint8(WOW_SUCCESS); + else + pkt << uint8(WOW_FAIL_VERSION_INVALID); + + // B may be calculated < 32B so we force minimal length to 32B + pkt.append(B.AsByteArray(32).get(), 32); // 32 bytes + pkt << uint8(1); + pkt.append(g.AsByteArray(1).get(), 1); + pkt << uint8(32); + pkt.append(N.AsByteArray(32).get(), 32); + pkt.append(s.AsByteArray(int32(BufferSizes::SRP_6_S)).get(), size_t(BufferSizes::SRP_6_S)); // 32 bytes + pkt.append(unk3.AsByteArray(16).get(), 16); + uint8 securityFlags = 0; + + // Check if token is used + _tokenKey = fields[9].GetString(); + if (!_tokenKey.empty()) + securityFlags = 4; + + pkt << uint8(securityFlags); // security flags (0x0...0x04) + + if (securityFlags & 0x01) // PIN input + { + pkt << uint32(0); + pkt << uint64(0) << uint64(0); // 16 bytes hash? + } + + if (securityFlags & 0x02) // Matrix input + { + pkt << uint8(0); + pkt << uint8(0); + pkt << uint8(0); + pkt << uint8(0); + pkt << uint64(0); + } + + if (securityFlags & 0x04) // Security token input + pkt << uint8(1); + + TC_LOG_DEBUG("server.authserver", "'%s:%d' [AuthChallenge] account %s is using '%s' locale (%u)", + ipAddress.c_str(), port, _accountInfo.Login.c_str(), _localizationName.c_str(), GetLocaleByName(_localizationName)); + SendPacket(pkt); - return true; } // Logon Proof command handler bool AuthSession::HandleLogonProof() { - TC_LOG_DEBUG("server.authserver", "Entering _HandleLogonProof"); + if (_sentProof) + return false; + + _sentProof = true; + // Read the packet sAuthLogonProof_C *logonProof = reinterpret_cast<sAuthLogonProof_C*>(GetReadBuffer().GetReadPointer()); @@ -487,7 +550,7 @@ bool AuthSession::HandleLogonProof() t3.SetBinary(hash, 20); sha.Initialize(); - sha.UpdateData(_login); + sha.UpdateData(_accountInfo.Login); sha.Finalize(); uint8 t4[SHA_DIGEST_LENGTH]; memcpy(t4, sha.GetDigest(), SHA_DIGEST_LENGTH); @@ -503,7 +566,7 @@ bool AuthSession::HandleLogonProof() // Check if SRP6 results match (password is correct), else send an error if (!memcmp(M.AsByteArray(sha.GetLength()).get(), logonProof->M1, 20)) { - TC_LOG_DEBUG("server.authserver", "'%s:%d' User '%s' successfully authenticated", GetRemoteIpAddress().to_string().c_str(), GetRemotePort(), _login.c_str()); + TC_LOG_DEBUG("server.authserver", "'%s:%d' User '%s' successfully authenticated", GetRemoteIpAddress().to_string().c_str(), GetRemotePort(), _accountInfo.Login.c_str()); // Update the sessionkey, last_ip, last login time and reset number of failed logins in the account table for this account // No SQL injection (escaped user name) and IP address as received by socket @@ -514,7 +577,7 @@ bool AuthSession::HandleLogonProof() stmt->setString(1, GetRemoteIpAddress().to_string().c_str()); stmt->setUInt32(2, GetLocaleByName(_localizationName)); stmt->setString(3, _os); - stmt->setString(4, _login); + stmt->setString(4, _accountInfo.Login); LoginDatabase.DirectExecute(stmt); OPENSSL_free((void*)K_hex); @@ -531,6 +594,7 @@ bool AuthSession::HandleLogonProof() std::string token(reinterpret_cast<char*>(GetReadBuffer().GetReadPointer() + sizeof(sAuthLogonProof_C) + sizeof(size)), size); GetReadBuffer().ReadCompleted(sizeof(size) + size); uint32 validToken = TOTP::GenerateToken(_tokenKey.c_str()); + _tokenKey.clear(); uint32 incomingToken = atoi(token.c_str()); if (validToken != incomingToken) { @@ -571,7 +635,7 @@ bool AuthSession::HandleLogonProof() } SendPacket(packet); - _isAuthenticated = true; + _status = STATUS_AUTHED; } else { @@ -583,7 +647,7 @@ bool AuthSession::HandleLogonProof() SendPacket(packet); TC_LOG_DEBUG("server.authserver", "'%s:%d' [AuthChallenge] account %s tried to login with invalid password!", - GetRemoteIpAddress().to_string().c_str(), GetRemotePort(), _login.c_str()); + GetRemoteIpAddress().to_string().c_str(), GetRemotePort(), _accountInfo.Login.c_str()); uint32 MaxWrongPassCount = sConfigMgr->GetIntDefault("WrongPass.MaxCount", 0); @@ -591,7 +655,7 @@ bool AuthSession::HandleLogonProof() if (sConfigMgr->GetBoolDefault("WrongPass.Logging", false)) { PreparedStatement* logstmt = LoginDatabase.GetPreparedStatement(LOGIN_INS_FALP_IP_LOGGING); - logstmt->setString(0, _login); + logstmt->setString(0, _accountInfo.Login); logstmt->setString(1, GetRemoteIpAddress().to_string()); logstmt->setString(2, "Logged on failed AccountLogin due wrong password"); @@ -602,42 +666,33 @@ bool AuthSession::HandleLogonProof() { //Increment number of failed logins by one and if it reaches the limit temporarily ban that account or IP PreparedStatement* stmt = LoginDatabase.GetPreparedStatement(LOGIN_UPD_FAILEDLOGINS); - stmt->setString(0, _login); + stmt->setString(0, _accountInfo.Login); LoginDatabase.Execute(stmt); - stmt = LoginDatabase.GetPreparedStatement(LOGIN_SEL_FAILEDLOGINS); - stmt->setString(0, _login); - - if (PreparedQueryResult loginfail = LoginDatabase.Query(stmt)) + if (_accountInfo.FailedLogins >= MaxWrongPassCount) { - uint32 failed_logins = (*loginfail)[1].GetUInt32(); + uint32 WrongPassBanTime = sConfigMgr->GetIntDefault("WrongPass.BanTime", 600); + bool WrongPassBanType = sConfigMgr->GetBoolDefault("WrongPass.BanType", false); - if (failed_logins >= MaxWrongPassCount) + if (WrongPassBanType) + { + stmt = LoginDatabase.GetPreparedStatement(LOGIN_INS_ACCOUNT_AUTO_BANNED); + stmt->setUInt32(0, _accountInfo.Id); + stmt->setUInt32(1, WrongPassBanTime); + LoginDatabase.Execute(stmt); + + TC_LOG_DEBUG("server.authserver", "'%s:%d' [AuthChallenge] account %s got banned for '%u' seconds because it failed to authenticate '%u' times", + GetRemoteIpAddress().to_string().c_str(), GetRemotePort(), _accountInfo.Login.c_str(), WrongPassBanTime, _accountInfo.FailedLogins); + } + else { - uint32 WrongPassBanTime = sConfigMgr->GetIntDefault("WrongPass.BanTime", 600); - bool WrongPassBanType = sConfigMgr->GetBoolDefault("WrongPass.BanType", false); - - if (WrongPassBanType) - { - uint32 acc_id = (*loginfail)[0].GetUInt32(); - stmt = LoginDatabase.GetPreparedStatement(LOGIN_INS_ACCOUNT_AUTO_BANNED); - stmt->setUInt32(0, acc_id); - stmt->setUInt32(1, WrongPassBanTime); - LoginDatabase.Execute(stmt); - - TC_LOG_DEBUG("server.authserver", "'%s:%d' [AuthChallenge] account %s got banned for '%u' seconds because it failed to authenticate '%u' times", - GetRemoteIpAddress().to_string().c_str(), GetRemotePort(), _login.c_str(), WrongPassBanTime, failed_logins); - } - else - { - stmt = LoginDatabase.GetPreparedStatement(LOGIN_INS_IP_AUTO_BANNED); - stmt->setString(0, GetRemoteIpAddress().to_string()); - stmt->setUInt32(1, WrongPassBanTime); - LoginDatabase.Execute(stmt); - - TC_LOG_DEBUG("server.authserver", "'%s:%d' [AuthChallenge] IP got banned for '%u' seconds because account %s failed to authenticate '%u' times", - GetRemoteIpAddress().to_string().c_str(), GetRemotePort(), WrongPassBanTime, _login.c_str(), failed_logins); - } + stmt = LoginDatabase.GetPreparedStatement(LOGIN_INS_IP_AUTO_BANNED); + stmt->setString(0, GetRemoteIpAddress().to_string()); + stmt->setUInt32(1, WrongPassBanTime); + LoginDatabase.Execute(stmt); + + TC_LOG_DEBUG("server.authserver", "'%s:%d' [AuthChallenge] IP got banned for '%u' seconds because account %s failed to authenticate '%u' times", + GetRemoteIpAddress().to_string().c_str(), GetRemotePort(), WrongPassBanTime, _accountInfo.Login.c_str(), _accountInfo.FailedLogins); } } } @@ -648,61 +703,88 @@ bool AuthSession::HandleLogonProof() bool AuthSession::HandleReconnectChallenge() { - TC_LOG_DEBUG("server.authserver", "Entering _HandleReconnectChallenge"); - sAuthLogonChallenge_C* challenge = reinterpret_cast<sAuthLogonChallenge_C*>(GetReadBuffer().GetReadPointer()); + if (_sentChallenge) + return false; - //TC_LOG_DEBUG("server.authserver", "[AuthChallenge] got full packet, %#04x bytes", challenge->size); - TC_LOG_DEBUG("server.authserver", "[AuthChallenge] name(%d): '%s'", challenge->I_len, challenge->I); + _sentChallenge = true; - _login.assign((const char*)challenge->I, challenge->I_len); + sAuthLogonChallenge_C* challenge = reinterpret_cast<sAuthLogonChallenge_C*>(GetReadBuffer().GetReadPointer()); + if (challenge->size - (sizeof(sAuthLogonChallenge_C) - AUTH_LOGON_CHALLENGE_INITIAL_SIZE - 1) != challenge->I_len) + return false; - PreparedStatement* stmt = LoginDatabase.GetPreparedStatement(LOGIN_SEL_SESSIONKEY); - stmt->setString(0, _login); - PreparedQueryResult result = LoginDatabase.Query(stmt); + std::string login((const char*)challenge->I, challenge->I_len); + TC_LOG_DEBUG("server.authserver", "[ReconnectChallenge] '%s'", login.c_str()); - // Stop if the account is not found - if (!result) + if (_queryCallback) { - TC_LOG_ERROR("server.authserver", "'%s:%d' [ERROR] user %s tried to login and we cannot find his session key in the database.", - GetRemoteIpAddress().to_string().c_str(), GetRemotePort(), _login.c_str()); - return false; + ByteBuffer pkt; + pkt << uint8(AUTH_RECONNECT_CHALLENGE); + pkt << uint8(WOW_FAIL_DB_BUSY); + SendPacket(pkt); + + TC_LOG_DEBUG("server.authserver", "[ReconnectChallenge] %s attempted to log too quick after previous attempt!", login.c_str()); + return true; } - // Reinitialize build, expansion and the account securitylevel _build = challenge->build; _expversion = uint8(AuthHelper::IsPostBCAcceptedClientBuild(_build) ? POST_BC_EXP_FLAG : (AuthHelper::IsPreBCAcceptedClientBuild(_build) ? PRE_BC_EXP_FLAG : NO_VALID_EXP_FLAG)); - _os = (const char*)challenge->os; - - if (_os.size() > 4) - return false; + std::array<char, 5> os; + os.fill('\0'); + memcpy(os.data(), challenge->os, sizeof(challenge->os)); + _os = os.data(); // Restore string order as its byte order is reversed std::reverse(_os.begin(), _os.end()); - Field* fields = result->Fetch(); - uint8 secLevel = fields[2].GetUInt8(); - _accountSecurityLevel = secLevel <= SEC_ADMINISTRATOR ? AccountTypes(secLevel) : SEC_ADMINISTRATOR; + _localizationName.resize(4); + for (int i = 0; i < 4; ++i) + _localizationName[i] = challenge->country[4 - i - 1]; - K.SetHexStr((*result)[0].GetCString()); + // Get the account details from the account table + PreparedStatement* stmt = LoginDatabase.GetPreparedStatement(LOGIN_SEL_RECONNECTCHALLENGE); + stmt->setString(0, login); + + _queryCallback = std::bind(&AuthSession::ReconnectChallengeCallback, this, std::placeholders::_1); + _queryFuture = LoginDatabase.AsyncQuery(stmt); + return true; +} - // Sending response +void AuthSession::ReconnectChallengeCallback(PreparedQueryResult result) +{ ByteBuffer pkt; pkt << uint8(AUTH_RECONNECT_CHALLENGE); - pkt << uint8(0x00); + + if (!result) + { + pkt << uint8(WOW_FAIL_UNKNOWN_ACCOUNT); + SendPacket(pkt); + return; + } + + Field* fields = result->Fetch(); + + _accountInfo.LoadResult(fields); + K.SetHexStr(fields[9].GetCString()); _reconnectProof.SetRand(16 * 8); - pkt.append(_reconnectProof.AsByteArray(16).get(), 16); // 16 bytes random + + pkt << uint8(WOW_SUCCESS); + pkt.append(_reconnectProof.AsByteArray(16).get(), 16); // 16 bytes random pkt << uint64(0x00) << uint64(0x00); // 16 bytes zeros SendPacket(pkt); - - return true; } + bool AuthSession::HandleReconnectProof() { TC_LOG_DEBUG("server.authserver", "Entering _HandleReconnectProof"); + if (_sentProof) + return false; + + _sentProof = true; + sAuthReconnectProof_C *reconnectProof = reinterpret_cast<sAuthReconnectProof_C*>(GetReadBuffer().GetReadPointer()); - if (_login.empty() || !_reconnectProof.GetNumBytes() || !K.GetNumBytes()) + if (_accountInfo.Login.empty() || !_reconnectProof.GetNumBytes() || !K.GetNumBytes()) return false; BigNumber t1; @@ -710,7 +792,7 @@ bool AuthSession::HandleReconnectProof() SHA1Hash sha; sha.Initialize(); - sha.UpdateData(_login); + sha.UpdateData(_accountInfo.Login); sha.UpdateBigNumbers(&t1, &_reconnectProof, &K, NULL); sha.Finalize(); @@ -722,13 +804,13 @@ bool AuthSession::HandleReconnectProof() pkt << uint8(0x00); pkt << uint16(0x00); // 2 bytes zeros SendPacket(pkt); - _isAuthenticated = true; + _status = STATUS_AUTHED; return true; } else { TC_LOG_ERROR("server.authserver", "'%s:%d' [ERROR] user %s tried to login, but session is invalid.", GetRemoteIpAddress().to_string().c_str(), - GetRemotePort(), _login.c_str()); + GetRemotePort(), _accountInfo.Login.c_str()); return false; } } @@ -772,20 +854,31 @@ bool AuthSession::HandleRealmList() { TC_LOG_DEBUG("server.authserver", "Entering _HandleRealmList"); - // Get the user id (else close the connection) - // No SQL injection (prepared statement) - PreparedStatement* stmt = LoginDatabase.GetPreparedStatement(LOGIN_SEL_ACCOUNT_ID_BY_NAME); - stmt->setString(0, _login); - PreparedQueryResult result = LoginDatabase.Query(stmt); - if (!result) + if (_queryCallback) { - TC_LOG_ERROR("server.authserver", "'%s:%d' [ERROR] user %s tried to login but we cannot find him in the database.", GetRemoteIpAddress().to_string().c_str(), - GetRemotePort(), _login.c_str()); + TC_LOG_DEBUG("server.authserver", "[RealmList] %s attempted to get realmlist too quick after previous attempt!", _accountInfo.Login.c_str()); return false; } - Field* fields = result->Fetch(); - uint32 id = fields[0].GetUInt32(); + PreparedStatement* stmt = LoginDatabase.GetPreparedStatement(LOGIN_SEL_REALM_CHARACTER_COUNTS); + stmt->setUInt32(0, _accountInfo.Id); + + _queryCallback = std::bind(&AuthSession::RealmListCallback, this, std::placeholders::_1); + _queryFuture = LoginDatabase.AsyncQuery(stmt); + return true; +} + +void AuthSession::RealmListCallback(PreparedQueryResult result) +{ + std::map<uint32, uint8> characterCounts; + if (result) + { + do + { + Field* fields = result->Fetch(); + characterCounts[fields[0].GetUInt32()] = fields[1].GetUInt8(); + } while (result->NextRow()); + } // Update realm list if need sRealmList->UpdateIfNeed(); @@ -822,25 +915,17 @@ bool AuthSession::HandleRealmList() name = ss.str(); } - uint8 lock = (realm.allowedSecurityLevel > _accountSecurityLevel) ? 1 : 0; - - uint8 AmountOfCharacters = 0; - stmt = LoginDatabase.GetPreparedStatement(LOGIN_SEL_NUM_CHARS_ON_REALM); - stmt->setUInt32(0, realm.m_ID); - stmt->setUInt32(1, id); - result = LoginDatabase.Query(stmt); - if (result) - AmountOfCharacters = (*result)[0].GetUInt8(); + uint8 lock = (realm.allowedSecurityLevel > _accountInfo.SecurityLevel) ? 1 : 0; - pkt << realm.icon; // realm type + pkt << uint8(realm.icon); // realm type if (_expversion & POST_BC_EXP_FLAG) // only 2.x and 3.x clients - pkt << lock; // if 1, then realm locked + pkt << uint8(lock); // if 1, then realm locked pkt << uint8(flag); // RealmFlags pkt << name; pkt << boost::lexical_cast<std::string>(GetAddressForClient(realm, GetRemoteIpAddress())); - pkt << realm.populationLevel; - pkt << AmountOfCharacters; - pkt << realm.timezone; // realm category + pkt << float(realm.populationLevel); + pkt << uint8(characterCounts[realm.m_ID]); + pkt << uint8(realm.timezone); // realm category if (_expversion & POST_BC_EXP_FLAG) // 2.x and 3.x clients pkt << uint8(realm.m_ID); else @@ -882,32 +967,6 @@ bool AuthSession::HandleRealmList() hdr.append(RealmListSizeBuffer); // append RealmList's size buffer hdr.append(pkt); // append realms in the realmlist SendPacket(hdr); - return true; -} - -// Resume patch transfer -bool AuthSession::HandleXferResume() -{ - TC_LOG_DEBUG("server.authserver", "Entering _HandleXferResume"); - //uint8 - //uint64 - return true; -} - -// Cancel patch transfer -bool AuthSession::HandleXferCancel() -{ - TC_LOG_DEBUG("server.authserver", "Entering _HandleXferCancel"); - //uint8 - return false; -} - -// Accept patch transfer -bool AuthSession::HandleXferAccept() -{ - TC_LOG_DEBUG("server.authserver", "Entering _HandleXferAccept"); - //uint8 - return true; } // Make the SRP6 calculation from hash in dB @@ -940,7 +999,7 @@ void AuthSession::SetVSFields(const std::string& rI) PreparedStatement* stmt = LoginDatabase.GetPreparedStatement(LOGIN_UPD_VS); stmt->setString(0, v_hex); stmt->setString(1, s_hex); - stmt->setString(2, _login); + stmt->setString(2, _accountInfo.Login); LoginDatabase.Execute(stmt); OPENSSL_free(v_hex); diff --git a/src/server/authserver/Server/AuthSession.h b/src/server/authserver/Server/AuthSession.h index d40e0852b57..1babb7407a9 100644 --- a/src/server/authserver/Server/AuthSession.h +++ b/src/server/authserver/Server/AuthSession.h @@ -23,29 +23,48 @@ #include "ByteBuffer.h" #include "Socket.h" #include "BigNumber.h" +#include "Callback.h" #include <memory> #include <boost/asio/ip/tcp.hpp> using boost::asio::ip::tcp; +class Field; struct AuthHandler; +enum AuthStatus +{ + STATUS_CONNECTED = 0, + STATUS_AUTHED +}; + +struct AccountInfo +{ + void LoadResult(Field* fields); + + uint32 Id = 0; + std::string Login; + bool IsLockedToIP = false; + std::string LockCountry; + std::string LastIP; + uint32 FailedLogins = 0; + bool IsBanned = false; + bool IsPermanenetlyBanned = false; + AccountTypes SecurityLevel = SEC_PLAYER; + std::string TokenKey; +}; + class AuthSession : public Socket<AuthSession> { + typedef Socket<AuthSession> AuthSocket; + public: static std::unordered_map<uint8, AuthHandler> InitHandlers(); - AuthSession(tcp::socket&& socket) : Socket(std::move(socket)), - _isAuthenticated(false), _build(0), _expversion(0), _accountSecurityLevel(SEC_PLAYER) - { - N.SetHexStr("894B645E89E1535BBDAD5B8B290650530801B18EBFBF5E8FAB3C82872A3E9BB7"); - g.SetDword(7); - } + AuthSession(tcp::socket&& socket); - void Start() override - { - AsyncRead(); - } + void Start() override; + bool Update() override; void SendPacket(ByteBuffer& packet); @@ -59,10 +78,10 @@ private: bool HandleReconnectProof(); bool HandleRealmList(); - //data transfer handle for patch - bool HandleXferResume(); - bool HandleXferCancel(); - bool HandleXferAccept(); + void CheckIpCallback(PreparedQueryResult result); + void LogonChallengeCallback(PreparedQueryResult result); + void ReconnectChallengeCallback(PreparedQueryResult result); + void RealmListCallback(PreparedQueryResult result); void SetVSFields(const std::string& rI); @@ -71,22 +90,27 @@ private: BigNumber K; BigNumber _reconnectProof; - bool _isAuthenticated; + bool _sentChallenge; + bool _sentProof; + + AuthStatus _status; + AccountInfo _accountInfo; std::string _tokenKey; - std::string _login; std::string _localizationName; std::string _os; + std::string _ipCountry; uint16 _build; uint8 _expversion; - AccountTypes _accountSecurityLevel; + PreparedQueryResultFuture _queryFuture; + std::function<void(PreparedQueryResult)> _queryCallback; }; #pragma pack(push, 1) struct AuthHandler { - uint32 status; + AuthStatus status; size_t packetSize; bool (AuthSession::*handler)(); }; diff --git a/src/server/authserver/Server/AuthSocketMgr.h b/src/server/authserver/Server/AuthSocketMgr.h index fa96502663f..a16b7d405b9 100644 --- a/src/server/authserver/Server/AuthSocketMgr.h +++ b/src/server/authserver/Server/AuthSocketMgr.h @@ -21,8 +21,6 @@ #include "SocketMgr.h" #include "AuthSession.h" -void OnSocketAccept(tcp::socket&& sock); - class AuthSocketMgr : public SocketMgr<AuthSession> { typedef SocketMgr<AuthSession> BaseSocketMgr; @@ -39,7 +37,7 @@ public: if (!BaseSocketMgr::StartNetwork(service, bindIp, port)) return false; - _acceptor->AsyncAcceptManaged(&OnSocketAccept); + _acceptor->AsyncAcceptWithCallback<&AuthSocketMgr::OnSocketAccept>(); return true; } @@ -48,14 +46,13 @@ protected: { return new NetworkThread<AuthSession>[1]; } + + static void OnSocketAccept(tcp::socket&& sock, uint32 threadIndex) + { + Instance().OnSocketOpen(std::forward<tcp::socket>(sock), threadIndex); + } }; #define sAuthSocketMgr AuthSocketMgr::Instance() -void OnSocketAccept(tcp::socket&& sock) -{ - sAuthSocketMgr.OnSocketOpen(std::forward<tcp::socket>(sock)); -} - - #endif // AuthSocketMgr_h__ diff --git a/src/server/authserver/authserver.conf.dist b/src/server/authserver/authserver.conf.dist index 604988d62e5..a97d75b3f57 100644 --- a/src/server/authserver/authserver.conf.dist +++ b/src/server/authserver/authserver.conf.dist @@ -131,6 +131,33 @@ WrongPass.BanType = 0 WrongPass.Logging = 0 # +# BanExpiryCheckInterval +# Description: Time (in seconds) between checks for expired bans +# Default: 60 + +BanExpiryCheckInterval = 60 + +# +# SourceDirectory +# Description: The path to your TrinityCore source directory. +# If the path is left empty, the built-in CMAKE_SOURCE_DIR is used. +# Example: "../TrinityCore" +# Default: "" + +SourceDirectory = "" + +# +# MySQLExecutable +# Description: The path to your mysql cli binary. +# If the path is left empty, built-in path from cmake is used. +# Example: "C:/Program Files/MySQL/MySQL Server 5.6/bin/mysql.exe" +# "mysql.exe" +# "/usr/bin/mysql" +# Default: "" + +MySQLExecutable = "" + +# ################################################################################################### ################################################################################################### @@ -174,26 +201,6 @@ LoginDatabase.WorkerThreads = 1 Updates.EnableDatabases = 0 # -# Updates.SourcePath -# Description: The path to your TrinityCore source directory. -# If the path is left empty, built-in CMAKE_SOURCE_DIR is used. -# Example: "../TrinityCore" -# Default: "" - -Updates.SourcePath = "" - -# -# Updates.MySqlCLIPath -# Description: The path to your mysql cli binary. -# If the path is left empty, built-in path from cmake is used. -# Example: "C:/Program Files/MySQL/MySQL Server 5.6/bin/mysql.exe" -# "mysql.exe" -# "/usr/bin/mysql" -# Default: "" - -Updates.MySqlCLIPath = "" - -# # Updates.AutoSetup # Description: Auto populate empty databases. # Default: 1 - (Enabled) diff --git a/src/server/database/Database/DatabaseLoader.cpp b/src/server/database/Database/DatabaseLoader.cpp index 92d8730cd12..6a8e86ffca9 100644 --- a/src/server/database/Database/DatabaseLoader.cpp +++ b/src/server/database/Database/DatabaseLoader.cpp @@ -32,7 +32,7 @@ DatabaseLoader& DatabaseLoader::AddDatabase(DatabaseWorkerPool<T>& pool, std::st { bool const updatesEnabledForThis = DBUpdater<T>::IsEnabled(_updateFlags); - _open.push(std::make_pair([this, name, updatesEnabledForThis, &pool]() -> bool + _open.push([this, name, updatesEnabledForThis, &pool]() -> bool { std::string const dbString = sConfigMgr->GetStringDefault(name + "DatabaseInfo", ""); if (dbString.empty()) @@ -71,12 +71,13 @@ DatabaseLoader& DatabaseLoader::AddDatabase(DatabaseWorkerPool<T>& pool, std::st return false; } } + // Add the close operation + _close.push([&pool] + { + pool.Close(); + }); return true; - }, - [&pool]() - { - pool.Close(); - })); + }); // Populate and update only if updates are enabled for this pool if (updatesEnabledForThis) @@ -137,38 +138,7 @@ bool DatabaseLoader::Load() bool DatabaseLoader::OpenDatabases() { - while (!_open.empty()) - { - std::pair<Predicate, std::function<void()>> const load = _open.top(); - if (load.first()) - _close.push(load.second); - else - { - // Close all loaded databases - while (!_close.empty()) - { - _close.top()(); - _close.pop(); - } - return false; - } - - _open.pop(); - } - return true; -} - -// Processes the elements of the given stack until a predicate returned false. -bool DatabaseLoader::Process(std::stack<Predicate>& stack) -{ - while (!stack.empty()) - { - if (!stack.top()()) - return false; - - stack.pop(); - } - return true; + return Process(_open); } bool DatabaseLoader::PopulateDatabases() @@ -186,6 +156,27 @@ bool DatabaseLoader::PrepareStatements() return Process(_prepare); } +bool DatabaseLoader::Process(std::queue<Predicate>& queue) +{ + while (!queue.empty()) + { + if (!queue.front()()) + { + // Close all open databases which have a registered close operation + while (!_close.empty()) + { + _close.top()(); + _close.pop(); + } + + return false; + } + + queue.pop(); + } + return true; +} + template DatabaseLoader& DatabaseLoader::AddDatabase<LoginDatabaseConnection>(DatabaseWorkerPool<LoginDatabaseConnection>& pool, std::string const& name); template diff --git a/src/server/database/Database/DatabaseLoader.h b/src/server/database/Database/DatabaseLoader.h index da92cf85a9f..ec390a427ad 100644 --- a/src/server/database/Database/DatabaseLoader.h +++ b/src/server/database/Database/DatabaseLoader.h @@ -21,8 +21,9 @@ #include "DatabaseWorkerPool.h" #include "DatabaseEnv.h" -#include <stack> #include <functional> +#include <stack> +#include <queue> // A helper class to initiate all database worker pools, // handles updating, delays preparing of statements and cleans up on failure. @@ -56,16 +57,18 @@ private: bool PrepareStatements(); using Predicate = std::function<bool()>; + using Closer = std::function<void()>; - static bool Process(std::stack<Predicate>& stack); + // Invokes all functions in the given queue and closes the databases on errors. + // Returns false when there was an error. + bool Process(std::queue<Predicate>& queue); std::string const _logger; bool const _autoSetup; uint32 const _updateFlags; - std::stack<std::pair<Predicate, std::function<void()>>> _open; - std::stack<std::function<void()>> _close; - std::stack<Predicate> _populate, _update, _prepare; + std::queue<Predicate> _open, _populate, _update, _prepare; + std::stack<Closer> _close; }; #endif // DatabaseLoader_h__ diff --git a/src/server/database/Database/DatabaseWorkerPool.cpp b/src/server/database/Database/DatabaseWorkerPool.cpp new file mode 100644 index 00000000000..5d914b6e0e8 --- /dev/null +++ b/src/server/database/Database/DatabaseWorkerPool.cpp @@ -0,0 +1,322 @@ +/* + * Copyright (C) 2008-2016 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 "DatabaseWorkerPool.h" +#include "DatabaseEnv.h" + +#define MIN_MYSQL_SERVER_VERSION 50100u +#define MIN_MYSQL_CLIENT_VERSION 50100u + +template <class T> +DatabaseWorkerPool<T>::DatabaseWorkerPool() + : _queue(new ProducerConsumerQueue<SQLOperation*>()), + _async_threads(0), _synch_threads(0) +{ + 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"); + WPFatal(mysql_get_client_version() == MYSQL_VERSION_ID, "Used MySQL library version (%s) does not match the version used to compile TrinityCore (%s).", + mysql_get_client_info(), MYSQL_SERVER_VERSION); +} + +template <class T> +void DatabaseWorkerPool<T>::SetConnectionInfo(std::string const& infoString, + uint8 const asyncThreads, uint8 const synchThreads) +{ + _connectionInfo = Trinity::make_unique<MySQLConnectionInfo>(infoString); + + _async_threads = asyncThreads; + _synch_threads = synchThreads; +} + +template <class T> +uint32 DatabaseWorkerPool<T>::Open() +{ + WPFatal(_connectionInfo.get(), "Connection info was not set!"); + + TC_LOG_INFO("sql.driver", "Opening DatabasePool '%s'. " + "Asynchronous connections: %u, synchronous connections: %u.", + GetDatabaseName(), _async_threads, _synch_threads); + + uint32 error = OpenConnections(IDX_ASYNC, _async_threads); + + if (error) + return error; + + error = OpenConnections(IDX_SYNCH, _synch_threads); + + if (!error) + { + TC_LOG_INFO("sql.driver", "DatabasePool '%s' opened successfully. " SZFMTD + " total connections running.", GetDatabaseName(), + (_connections[IDX_SYNCH].size() + _connections[IDX_ASYNC].size())); + } + + return error; +} + +template <class T> +void DatabaseWorkerPool<T>::Close() +{ + TC_LOG_INFO("sql.driver", "Closing down DatabasePool '%s'.", GetDatabaseName()); + + //! Closes the actualy MySQL connection. + _connections[IDX_ASYNC].clear(); + + TC_LOG_INFO("sql.driver", "Asynchronous connections on DatabasePool '%s' terminated. " + "Proceeding with synchronous connections.", + GetDatabaseName()); + + //! Shut down the synchronous connections + //! There's no need for locking the connection, because DatabaseWorkerPool<>::Close + //! should only be called after any other thread tasks in the core have exited, + //! meaning there can be no concurrent access at this point. + _connections[IDX_SYNCH].clear(); + + TC_LOG_INFO("sql.driver", "All connections on DatabasePool '%s' closed.", GetDatabaseName()); +} + +template <class T> +bool DatabaseWorkerPool<T>::PrepareStatements() +{ + for (auto& connections : _connections) + for (auto& connection : connections) + { + connection->LockIfReady(); + if (!connection->PrepareStatements()) + { + connection->Unlock(); + Close(); + return false; + } + else + connection->Unlock(); + } + + return true; +} + +template <class T> +QueryResult DatabaseWorkerPool<T>::Query(const char* sql, T* connection /*= nullptr*/) +{ + if (!connection) + connection = GetFreeConnection(); + + ResultSet* result = connection->Query(sql); + connection->Unlock(); + if (!result || !result->GetRowCount() || !result->NextRow()) + { + delete result; + return QueryResult(NULL); + } + + return QueryResult(result); +} + +template <class T> +PreparedQueryResult DatabaseWorkerPool<T>::Query(PreparedStatement* stmt) +{ + auto connection = GetFreeConnection(); + PreparedResultSet* ret = connection->Query(stmt); + connection->Unlock(); + + //! Delete proxy-class. Not needed anymore + delete stmt; + + if (!ret || !ret->GetRowCount()) + { + delete ret; + return PreparedQueryResult(NULL); + } + + return PreparedQueryResult(ret); +} + +template <class T> +QueryResultFuture DatabaseWorkerPool<T>::AsyncQuery(const char* sql) +{ + BasicStatementTask* task = new BasicStatementTask(sql, true); + // Store future result before enqueueing - task might get already processed and deleted before returning from this method + QueryResultFuture result = task->GetFuture(); + Enqueue(task); + return result; +} + +template <class T> +PreparedQueryResultFuture DatabaseWorkerPool<T>::AsyncQuery(PreparedStatement* stmt) +{ + PreparedStatementTask* task = new PreparedStatementTask(stmt, true); + // Store future result before enqueueing - task might get already processed and deleted before returning from this method + PreparedQueryResultFuture result = task->GetFuture(); + Enqueue(task); + return result; +} + +template <class T> +QueryResultHolderFuture DatabaseWorkerPool<T>::DelayQueryHolder(SQLQueryHolder* holder) +{ + SQLQueryHolderTask* task = new SQLQueryHolderTask(holder); + // Store future result before enqueueing - task might get already processed and deleted before returning from this method + QueryResultHolderFuture result = task->GetFuture(); + Enqueue(task); + return result; +} + +template <class T> +void DatabaseWorkerPool<T>::CommitTransaction(SQLTransaction transaction) +{ +#ifdef TRINITY_DEBUG + //! Only analyze transaction weaknesses in Debug mode. + //! Ideally we catch the faults in Debug mode and then correct them, + //! so there's no need to waste these CPU cycles in Release mode. + switch (transaction->GetSize()) + { + case 0: + TC_LOG_DEBUG("sql.driver", "Transaction contains 0 queries. Not executing."); + return; + case 1: + TC_LOG_DEBUG("sql.driver", "Warning: Transaction only holds 1 query, consider removing Transaction context in code."); + break; + default: + break; + } +#endif // TRINITY_DEBUG + + Enqueue(new TransactionTask(transaction)); +} + +template <class T> +void DatabaseWorkerPool<T>::DirectCommitTransaction(SQLTransaction& transaction) +{ + T* connection = GetFreeConnection(); + int errorCode = connection->ExecuteTransaction(transaction); + if (!errorCode) + { + connection->Unlock(); // OK, operation succesful + return; + } + + //! Handle MySQL Errno 1213 without extending deadlock to the core itself + /// @todo More elegant way + if (errorCode == ER_LOCK_DEADLOCK) + { + uint8 loopBreaker = 5; + for (uint8 i = 0; i < loopBreaker; ++i) + { + if (!connection->ExecuteTransaction(transaction)) + break; + } + } + + //! Clean up now. + transaction->Cleanup(); + + connection->Unlock(); +} + +template <class T> +void DatabaseWorkerPool<T>::EscapeString(std::string& str) +{ + if (str.empty()) + return; + + char* buf = new char[str.size() * 2 + 1]; + EscapeString(buf, str.c_str(), str.size()); + str = buf; + delete[] buf; +} + +template <class T> +void DatabaseWorkerPool<T>::KeepAlive() +{ + //! Ping synchronous connections + for (auto& connection : _connections[IDX_SYNCH]) + { + if (connection->LockIfReady()) + { + connection->Ping(); + connection->Unlock(); + } + } + + //! Assuming all worker threads are free, every worker thread will receive 1 ping operation request + //! If one or more worker threads are busy, the ping operations will not be split evenly, but this doesn't matter + //! as the sole purpose is to prevent connections from idling. + auto const count = _connections[IDX_ASYNC].size(); + for (uint8 i = 0; i < count; ++i) + Enqueue(new PingOperation); +} + +template <class T> +uint32 DatabaseWorkerPool<T>::OpenConnections(InternalIndex type, uint8 numConnections) +{ + for (uint8 i = 0; i < numConnections; ++i) + { + // Create the connection + auto connection = [&] { + switch (type) + { + case IDX_ASYNC: + return Trinity::make_unique<T>(_queue.get(), *_connectionInfo); + case IDX_SYNCH: + return Trinity::make_unique<T>(*_connectionInfo); + default: + ABORT(); + } + }(); + + if (uint32 error = connection->Open()) + { + // Failed to open a connection or invalid version, abort and cleanup + _connections[type].clear(); + return error; + } + else if (mysql_get_server_version(connection->GetHandle()) < MIN_MYSQL_SERVER_VERSION) + { + TC_LOG_ERROR("sql.driver", "TrinityCore does not support MySQL versions below 5.1"); + return 1; + } + else + { + _connections[type].push_back(std::move(connection)); + } + } + + // Everything is fine + return 0; +} + +template <class T> +T* DatabaseWorkerPool<T>::GetFreeConnection() +{ + uint8 i = 0; + auto const num_cons = _connections[IDX_SYNCH].size(); + T* connection = nullptr; + //! Block forever until a connection is free + for (;;) + { + connection = _connections[IDX_SYNCH][++i % num_cons].get(); + //! Must be matched with t->Unlock() or you will get deadlocks + if (connection->LockIfReady()) + break; + } + + return connection; +} + +template class DatabaseWorkerPool<LoginDatabaseConnection>; +template class DatabaseWorkerPool<WorldDatabaseConnection>; +template class DatabaseWorkerPool<CharacterDatabaseConnection>; diff --git a/src/server/database/Database/DatabaseWorkerPool.h b/src/server/database/Database/DatabaseWorkerPool.h index d5a254647eb..d883366237f 100644 --- a/src/server/database/Database/DatabaseWorkerPool.h +++ b/src/server/database/Database/DatabaseWorkerPool.h @@ -32,9 +32,7 @@ #include <mysqld_error.h> #include <memory> - -#define MIN_MYSQL_SERVER_VERSION 50100u -#define MIN_MYSQL_CLIENT_VERSION 50100u +#include <array> class PingOperation : public SQLOperation { @@ -59,97 +57,21 @@ class DatabaseWorkerPool public: /* Activity state */ - DatabaseWorkerPool() : _queue(new ProducerConsumerQueue<SQLOperation*>()), - _async_threads(0), _synch_threads(0) - { - memset(_connectionCount, 0, sizeof(_connectionCount)); - _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"); - WPFatal(mysql_get_client_version() == MYSQL_VERSION_ID, "Used MySQL library version (%s) does not match the version used to compile TrinityCore (%s).", - mysql_get_client_info(), MYSQL_SERVER_VERSION); - } + DatabaseWorkerPool(); ~DatabaseWorkerPool() { _queue->Cancel(); } - void SetConnectionInfo(std::string const& infoString, uint8 const asyncThreads, uint8 const synchThreads) - { - _connectionInfo.reset(new MySQLConnectionInfo(infoString)); - - _async_threads = asyncThreads; - _synch_threads = synchThreads; - } - - uint32 Open() - { - WPFatal(_connectionInfo.get(), "Connection info was not set!"); - - TC_LOG_INFO("sql.driver", "Opening DatabasePool '%s'. Asynchronous connections: %u, synchronous connections: %u.", - GetDatabaseName(), _async_threads, _synch_threads); - - uint32 error = OpenConnections(IDX_ASYNC, _async_threads); - - if (error) - return error; - - error = OpenConnections(IDX_SYNCH, _synch_threads); - - if (!error) - { - TC_LOG_INFO("sql.driver", "DatabasePool '%s' opened successfully. %u total connections running.", GetDatabaseName(), - (_connectionCount[IDX_SYNCH] + _connectionCount[IDX_ASYNC])); - } - - return error; - } - - void Close() - { - TC_LOG_INFO("sql.driver", "Closing down DatabasePool '%s'.", GetDatabaseName()); + void SetConnectionInfo(std::string const& infoString, uint8 const asyncThreads, uint8 const synchThreads); - for (uint8 i = 0; i < _connectionCount[IDX_ASYNC]; ++i) - { - T* t = _connections[IDX_ASYNC][i]; - t->Close(); //! Closes the actualy MySQL connection. - } + uint32 Open(); - TC_LOG_INFO("sql.driver", "Asynchronous connections on DatabasePool '%s' terminated. Proceeding with synchronous connections.", - GetDatabaseName()); - - //! Shut down the synchronous connections - //! There's no need for locking the connection, because DatabaseWorkerPool<>::Close - //! should only be called after any other thread tasks in the core have exited, - //! meaning there can be no concurrent access at this point. - for (uint8 i = 0; i < _connectionCount[IDX_SYNCH]; ++i) - _connections[IDX_SYNCH][i]->Close(); - - TC_LOG_INFO("sql.driver", "All connections on DatabasePool '%s' closed.", GetDatabaseName()); - } + void Close(); //! Prepares all prepared statements - bool PrepareStatements() - { - for (uint8 i = 0; i < IDX_SIZE; ++i) - for (uint32 c = 0; c < _connectionCount[i]; ++c) - { - T* t = _connections[i][c]; - t->LockIfReady(); - if (!t->PrepareStatements()) - { - t->Unlock(); - Close(); - return false; - } - else - t->Unlock(); - } - - return true; - } + bool PrepareStatements(); inline MySQLConnectionInfo const* GetConnectionInfo() const { @@ -201,9 +123,9 @@ class DatabaseWorkerPool if (!sql) return; - T* t = GetFreeConnection(); - t->Execute(sql); - t->Unlock(); + T* connection = GetFreeConnection(); + connection->Execute(sql); + connection->Unlock(); } //! Directly executes a one-way SQL operation in string format -with variable args-, that will block the calling thread until finished. @@ -221,9 +143,9 @@ class DatabaseWorkerPool //! Statement must be prepared with the CONNECTION_SYNCH flag. void DirectExecute(PreparedStatement* stmt) { - T* t = GetFreeConnection(); - t->Execute(stmt); - t->Unlock(); + T* connection = GetFreeConnection(); + connection->Execute(stmt); + connection->Unlock(); //! Delete proxy-class. Not needed anymore delete stmt; @@ -235,21 +157,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, T* conn = nullptr) - { - if (!conn) - conn = GetFreeConnection(); - - ResultSet* result = conn->Query(sql); - conn->Unlock(); - if (!result || !result->GetRowCount() || !result->NextRow()) - { - delete result; - return QueryResult(NULL); - } - - return QueryResult(result); - } + QueryResult Query(const char* sql, T* connection = nullptr); //! 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. @@ -276,23 +184,7 @@ class DatabaseWorkerPool //! Directly executes an SQL query in prepared format that will block the calling thread until finished. //! Returns reference counted auto pointer, no need for manual memory management in upper level code. //! Statement must be prepared with CONNECTION_SYNCH flag. - PreparedQueryResult Query(PreparedStatement* stmt) - { - T* t = GetFreeConnection(); - PreparedResultSet* ret = t->Query(stmt); - t->Unlock(); - - //! Delete proxy-class. Not needed anymore - delete stmt; - - if (!ret || !ret->GetRowCount()) - { - delete ret; - return PreparedQueryResult(NULL); - } - - return PreparedQueryResult(ret); - } + PreparedQueryResult Query(PreparedStatement* stmt); /** Asynchronous query (with resultset) methods. @@ -300,14 +192,7 @@ class DatabaseWorkerPool //! Enqueues a query in string format that will set the value of the QueryResultFuture return object as soon as the query is executed. //! The return value is then processed in ProcessQueryCallback methods. - QueryResultFuture AsyncQuery(const char* sql) - { - BasicStatementTask* task = new BasicStatementTask(sql, true); - // Store future result before enqueueing - task might get already processed and deleted before returning from this method - QueryResultFuture result = task->GetFuture(); - Enqueue(task); - return result; - } + QueryResultFuture AsyncQuery(const char* sql); //! Enqueues a query in string format -with variable args- that will set the value of the QueryResultFuture return object as soon as the query is executed. //! The return value is then processed in ProcessQueryCallback methods. @@ -320,27 +205,13 @@ class DatabaseWorkerPool //! Enqueues a query in prepared format that will set the value of the PreparedQueryResultFuture return object as soon as the query is executed. //! The return value is then processed in ProcessQueryCallback methods. //! Statement must be prepared with CONNECTION_ASYNC flag. - PreparedQueryResultFuture AsyncQuery(PreparedStatement* stmt) - { - PreparedStatementTask* task = new PreparedStatementTask(stmt, true); - // Store future result before enqueueing - task might get already processed and deleted before returning from this method - PreparedQueryResultFuture result = task->GetFuture(); - Enqueue(task); - return result; - } + PreparedQueryResultFuture AsyncQuery(PreparedStatement* stmt); //! Enqueues a vector of SQL operations (can be both adhoc and prepared) that will set the value of the QueryResultHolderFuture //! return object as soon as the query is executed. //! The return value is then processed in ProcessQueryCallback methods. //! Any prepared statements added to this holder need to be prepared with the CONNECTION_ASYNC flag. - QueryResultHolderFuture DelayQueryHolder(SQLQueryHolder* holder) - { - SQLQueryHolderTask* task = new SQLQueryHolderTask(holder); - // Store future result before enqueueing - task might get already processed and deleted before returning from this method - QueryResultHolderFuture result = task->GetFuture(); - Enqueue(task); - return result; - } + QueryResultHolderFuture DelayQueryHolder(SQLQueryHolder* holder); /** Transaction context methods. @@ -354,57 +225,11 @@ class DatabaseWorkerPool //! Enqueues a collection of one-way SQL operations (can be both adhoc and prepared). The order in which these operations //! were appended to the transaction will be respected during execution. - void CommitTransaction(SQLTransaction transaction) - { - #ifdef TRINITY_DEBUG - //! Only analyze transaction weaknesses in Debug mode. - //! Ideally we catch the faults in Debug mode and then correct them, - //! so there's no need to waste these CPU cycles in Release mode. - switch (transaction->GetSize()) - { - case 0: - TC_LOG_DEBUG("sql.driver", "Transaction contains 0 queries. Not executing."); - return; - case 1: - TC_LOG_DEBUG("sql.driver", "Warning: Transaction only holds 1 query, consider removing Transaction context in code."); - break; - default: - break; - } - #endif // TRINITY_DEBUG - - Enqueue(new TransactionTask(transaction)); - } + void CommitTransaction(SQLTransaction transaction); //! Directly executes a collection of one-way SQL operations (can be both adhoc and prepared). The order in which these operations //! were appended to the transaction will be respected during execution. - void DirectCommitTransaction(SQLTransaction& transaction) - { - T* con = GetFreeConnection(); - int errorCode = con->ExecuteTransaction(transaction); - if (!errorCode) - { - con->Unlock(); // OK, operation succesful - return; - } - - //! Handle MySQL Errno 1213 without extending deadlock to the core itself - /// @todo More elegant way - if (errorCode == ER_LOCK_DEADLOCK) - { - uint8 loopBreaker = 5; - for (uint8 i = 0; i < loopBreaker; ++i) - { - if (!con->ExecuteTransaction(transaction)) - break; - } - } - - //! Clean up now. - transaction->Cleanup(); - - con->Unlock(); - } + void DirectCommitTransaction(SQLTransaction& transaction); //! Method used to execute prepared statements in a diverse context. //! Will be wrapped in a transaction if valid object is present, otherwise executed standalone. @@ -441,90 +266,21 @@ class DatabaseWorkerPool } //! Apply escape string'ing for current collation. (utf8) - void EscapeString(std::string& str) - { - if (str.empty()) - return; - - char* buf = new char[str.size() * 2 + 1]; - EscapeString(buf, str.c_str(), str.size()); - str = buf; - delete[] buf; - } + void EscapeString(std::string& str); //! Keeps all our MySQL connections alive, prevent the server from disconnecting us. - void KeepAlive() - { - //! Ping synchronous connections - for (uint8 i = 0; i < _connectionCount[IDX_SYNCH]; ++i) - { - T* t = _connections[IDX_SYNCH][i]; - if (t->LockIfReady()) - { - t->Ping(); - t->Unlock(); - } - } - - //! Assuming all worker threads are free, every worker thread will receive 1 ping operation request - //! If one or more worker threads are busy, the ping operations will not be split evenly, but this doesn't matter - //! as the sole purpose is to prevent connections from idling. - for (size_t i = 0; i < _connections[IDX_ASYNC].size(); ++i) - Enqueue(new PingOperation); - } + void KeepAlive(); private: - uint32 OpenConnections(InternalIndex type, uint8 numConnections) - { - _connections[type].resize(numConnections); - for (uint8 i = 0; i < numConnections; ++i) - { - T* t; - - if (type == IDX_ASYNC) - t = new T(_queue.get(), *_connectionInfo); - else if (type == IDX_SYNCH) - t = new T(*_connectionInfo); - else - ABORT(); - - _connections[type][i] = t; - ++_connectionCount[type]; - - uint32 error = t->Open(); - - if (!error) - { - if (mysql_get_server_version(t->GetHandle()) < MIN_MYSQL_SERVER_VERSION) - { - TC_LOG_ERROR("sql.driver", "TrinityCore does not support MySQL versions below 5.1"); - error = 1; - } - } - - // Failed to open a connection or invalid version, abort and cleanup - if (error) - { - while (_connectionCount[type] != 0) - { - t = _connections[type][i--]; - delete t; - --_connectionCount[type]; - } - return error; - } - } - - // Everything is fine - return 0; - } + uint32 OpenConnections(InternalIndex type, uint8 numConnections); unsigned long EscapeString(char *to, const char *from, unsigned long length) { if (!to || !from || !length) return 0; - return mysql_real_escape_string(_connections[IDX_SYNCH][0]->GetHandle(), to, from, length); + return mysql_real_escape_string( + _connections[IDX_SYNCH].front()->GetHandle(), to, from, length); } void Enqueue(SQLOperation* op) @@ -534,22 +290,7 @@ class DatabaseWorkerPool //! Gets a free connection in the synchronous connection pool. //! Caller MUST call t->Unlock() after touching the MySQL context to prevent deadlocks. - T* GetFreeConnection() - { - uint8 i = 0; - size_t num_cons = _connectionCount[IDX_SYNCH]; - T* t = NULL; - //! Block forever until a connection is free - for (;;) - { - t = _connections[IDX_SYNCH][++i % num_cons]; - //! Must be matched with t->Unlock() or you will get deadlocks - if (t->LockIfReady()) - break; - } - - return t; - } + T* GetFreeConnection(); char const* GetDatabaseName() const { @@ -558,9 +299,7 @@ class DatabaseWorkerPool //! Queue shared by async worker threads. std::unique_ptr<ProducerConsumerQueue<SQLOperation*>> _queue; - std::vector<std::vector<T*>> _connections; - //! Counter of MySQL connections; - uint32 _connectionCount[IDX_SIZE]; + std::array<std::vector<std::unique_ptr<T>>, IDX_SIZE> _connections; std::unique_ptr<MySQLConnectionInfo> _connectionInfo; uint8 _async_threads, _synch_threads; }; diff --git a/src/server/database/Database/Implementation/CharacterDatabase.cpp b/src/server/database/Database/Implementation/CharacterDatabase.cpp index 140f3bf31c9..ab68aca2a8c 100644 --- a/src/server/database/Database/Implementation/CharacterDatabase.cpp +++ b/src/server/database/Database/Implementation/CharacterDatabase.cpp @@ -72,7 +72,7 @@ void CharacterDatabaseConnection::DoPrepareStatements() "FROM characters WHERE guid = ?", CONNECTION_ASYNC); PrepareStatement(CHAR_SEL_GROUP_MEMBER, "SELECT guid FROM group_member WHERE memberGuid = ?", CONNECTION_BOTH); - PrepareStatement(CHAR_SEL_CHARACTER_INSTANCE, "SELECT id, permanent, map, difficulty, resettime FROM character_instance LEFT JOIN instance ON instance = id WHERE guid = ?", CONNECTION_ASYNC); + PrepareStatement(CHAR_SEL_CHARACTER_INSTANCE, "SELECT id, permanent, map, difficulty, extendState, resettime FROM character_instance LEFT JOIN instance ON instance = id WHERE guid = ?", CONNECTION_ASYNC); PrepareStatement(CHAR_SEL_CHARACTER_AURAS, "SELECT casterGuid, spell, effectMask, recalculateMask, stackCount, amount0, amount1, amount2, " "base_amount0, base_amount1, base_amount2, maxDuration, remainTime, remainCharges FROM character_aura WHERE guid = ?", CONNECTION_ASYNC); PrepareStatement(CHAR_SEL_CHARACTER_SPELL, "SELECT spell, active, disabled FROM character_spell WHERE guid = ?", CONNECTION_ASYNC); @@ -405,8 +405,8 @@ void CharacterDatabaseConnection::DoPrepareStatements() PrepareStatement(CHAR_UPD_WORLDSTATE, "UPDATE worldstates SET value = ? WHERE entry = ?", CONNECTION_ASYNC); PrepareStatement(CHAR_INS_WORLDSTATE, "INSERT INTO worldstates (entry, value) VALUES (?, ?)", CONNECTION_ASYNC); PrepareStatement(CHAR_DEL_CHAR_INSTANCE_BY_INSTANCE_GUID, "DELETE FROM character_instance WHERE guid = ? AND instance = ?", CONNECTION_ASYNC); - PrepareStatement(CHAR_UPD_CHAR_INSTANCE, "UPDATE character_instance SET instance = ?, permanent = ? WHERE guid = ? AND instance = ?", CONNECTION_ASYNC); - PrepareStatement(CHAR_INS_CHAR_INSTANCE, "INSERT INTO character_instance (guid, instance, permanent) VALUES (?, ?, ?)", CONNECTION_ASYNC); + PrepareStatement(CHAR_UPD_CHAR_INSTANCE, "UPDATE character_instance SET instance = ?, permanent = ?, extendState = ? WHERE guid = ? AND instance = ?", CONNECTION_ASYNC); + PrepareStatement(CHAR_INS_CHAR_INSTANCE, "INSERT INTO character_instance (guid, instance, permanent, extendState) VALUES (?, ?, ?, ?)", CONNECTION_ASYNC); PrepareStatement(CHAR_UPD_GENDER_PLAYERBYTES, "UPDATE characters SET gender = ?, playerBytes = ?, playerBytes2 = ? WHERE guid = ?", CONNECTION_ASYNC); PrepareStatement(CHAR_DEL_CHARACTER_SKILL, "DELETE FROM character_skills WHERE guid = ? AND skill = ?", CONNECTION_ASYNC); PrepareStatement(CHAR_UPD_ADD_CHARACTER_SOCIAL_FLAGS, "UPDATE character_social SET flags = flags | ? WHERE guid = ? AND friend = ?", CONNECTION_ASYNC); @@ -434,6 +434,7 @@ void CharacterDatabaseConnection::DoPrepareStatements() PrepareStatement(CHAR_SEL_CHAR_CLASS_LVL_AT_LOGIN, "SELECT class, level, at_login, knownTitles FROM characters WHERE guid = ?", CONNECTION_SYNCH); PrepareStatement(CHAR_SEL_CHAR_AT_LOGIN_TITLES, "SELECT at_login, knownTitles FROM characters WHERE guid = ?", CONNECTION_SYNCH); PrepareStatement(CHAR_SEL_INSTANCE, "SELECT data, completedEncounters FROM instance WHERE map = ? AND id = ?", CONNECTION_SYNCH); + PrepareStatement(CHAR_SEL_PERM_BIND_BY_INSTANCE, "SELECT guid FROM character_instance WHERE instance = ? and permanent = 1", CONNECTION_SYNCH); PrepareStatement(CHAR_SEL_CHAR_COD_ITEM_MAIL, "SELECT id, messageType, mailTemplateId, sender, subject, body, money, has_items FROM mail WHERE receiver = ? AND has_items <> 0 AND cod <> 0", CONNECTION_SYNCH); PrepareStatement(CHAR_SEL_CHAR_SOCIAL, "SELECT DISTINCT guid FROM character_social WHERE friend = ?", CONNECTION_SYNCH); PrepareStatement(CHAR_SEL_CHAR_OLD_CHARS, "SELECT guid, deleteInfos_Account FROM characters WHERE deleteDate IS NOT NULL AND deleteDate < ?", CONNECTION_SYNCH); @@ -470,9 +471,10 @@ void CharacterDatabaseConnection::DoPrepareStatements() PrepareStatement(CHAR_INS_CHAR_GIFT, "INSERT INTO character_gifts (guid, item_guid, entry, flags) VALUES (?, ?, ?, ?)", CONNECTION_ASYNC); PrepareStatement(CHAR_DEL_INSTANCE_BY_INSTANCE, "DELETE FROM instance WHERE id = ?", CONNECTION_ASYNC); PrepareStatement(CHAR_DEL_CHAR_INSTANCE_BY_INSTANCE, "DELETE FROM character_instance WHERE instance = ?", CONNECTION_ASYNC); - PrepareStatement(CHAR_DEL_CHAR_INSTANCE_BY_MAP_DIFF, "DELETE FROM character_instance USING character_instance LEFT JOIN instance ON character_instance.instance = id WHERE map = ? and difficulty = ?", CONNECTION_ASYNC); + PrepareStatement(CHAR_DEL_EXPIRED_CHAR_INSTANCE_BY_MAP_DIFF, "DELETE FROM character_instance USING character_instance LEFT JOIN instance ON character_instance.instance = id WHERE (extendState = 0 or permanent = 0) and map = ? and difficulty = ?", CONNECTION_ASYNC); PrepareStatement(CHAR_DEL_GROUP_INSTANCE_BY_MAP_DIFF, "DELETE FROM group_instance USING group_instance LEFT JOIN instance ON group_instance.instance = id WHERE map = ? and difficulty = ?", CONNECTION_ASYNC); - PrepareStatement(CHAR_DEL_INSTANCE_BY_MAP_DIFF, "DELETE FROM instance WHERE map = ? and difficulty = ?", CONNECTION_ASYNC); + PrepareStatement(CHAR_DEL_EXPIRED_INSTANCE_BY_MAP_DIFF, "DELETE FROM instance WHERE map = ? and difficulty = ? and (SELECT guid FROM character_instance WHERE extendState != 0 AND instance = id LIMIT 1) IS NULL", CONNECTION_ASYNC); + PrepareStatement(CHAR_UPD_EXPIRE_CHAR_INSTANCE_BY_MAP_DIFF, "UPDATE character_instance LEFT JOIN instance ON character_instance.instance = id SET extendState = extendState-1 WHERE map = ? and difficulty = ?", CONNECTION_ASYNC); PrepareStatement(CHAR_DEL_MAIL_ITEM_BY_ID, "DELETE FROM mail_items WHERE mail_id = ?", CONNECTION_ASYNC); PrepareStatement(CHAR_INS_PETITION, "INSERT INTO petition (ownerguid, petitionguid, name, type) VALUES (?, ?, ?, ?)", CONNECTION_ASYNC); PrepareStatement(CHAR_DEL_PETITION_BY_GUID, "DELETE FROM petition WHERE petitionguid = ?", CONNECTION_ASYNC); diff --git a/src/server/database/Database/Implementation/CharacterDatabase.h b/src/server/database/Database/Implementation/CharacterDatabase.h index c0ff9cbbfbe..19d4a609e77 100644 --- a/src/server/database/Database/Implementation/CharacterDatabase.h +++ b/src/server/database/Database/Implementation/CharacterDatabase.h @@ -365,6 +365,7 @@ enum CharacterDatabaseStatements CHAR_SEL_CHAR_CLASS_LVL_AT_LOGIN, CHAR_SEL_CHAR_AT_LOGIN_TITLES, CHAR_SEL_INSTANCE, + CHAR_SEL_PERM_BIND_BY_INSTANCE, CHAR_SEL_CHAR_COD_ITEM_MAIL, CHAR_SEL_CHAR_SOCIAL, CHAR_SEL_CHAR_OLD_CHARS, @@ -396,9 +397,10 @@ enum CharacterDatabaseStatements CHAR_INS_CHAR_GIFT, CHAR_DEL_INSTANCE_BY_INSTANCE, CHAR_DEL_CHAR_INSTANCE_BY_INSTANCE, - CHAR_DEL_CHAR_INSTANCE_BY_MAP_DIFF, + CHAR_DEL_EXPIRED_CHAR_INSTANCE_BY_MAP_DIFF, CHAR_DEL_GROUP_INSTANCE_BY_MAP_DIFF, - CHAR_DEL_INSTANCE_BY_MAP_DIFF, + CHAR_DEL_EXPIRED_INSTANCE_BY_MAP_DIFF, + CHAR_UPD_EXPIRE_CHAR_INSTANCE_BY_MAP_DIFF, CHAR_DEL_MAIL_ITEM_BY_ID, CHAR_INS_PETITION, CHAR_DEL_PETITION_BY_GUID, diff --git a/src/server/database/Database/Implementation/LoginDatabase.cpp b/src/server/database/Database/Implementation/LoginDatabase.cpp index 66847f0a6a0..2749c08594f 100644 --- a/src/server/database/Database/Implementation/LoginDatabase.cpp +++ b/src/server/database/Database/Implementation/LoginDatabase.cpp @@ -24,33 +24,34 @@ void LoginDatabaseConnection::DoPrepareStatements() 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_SYNCH); + 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_INFO, "(SELECT unbandate > UNIX_TIMESTAMP() OR unbandate = bandate AS banned, NULL as country FROM ip_banned WHERE ip = ?) " "UNION " "(SELECT NULL AS banned, country FROM ip2nation WHERE INET_NTOA(ip) = ?)", 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 (ip, bandate, unbandate, bannedby, banreason) VALUES (?, UNIX_TIMESTAMP(), UNIX_TIMESTAMP()+?, 'Trinity Auth', '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); PrepareStatement(LOGIN_SEL_ACCOUNT_BANNED_ALL, "SELECT account.id, username FROM account, account_banned WHERE account.id = account_banned.id AND active = 1 GROUP BY account.id", CONNECTION_SYNCH); PrepareStatement(LOGIN_SEL_ACCOUNT_BANNED_BY_USERNAME, "SELECT account.id, username FROM account, account_banned WHERE account.id = account_banned.id AND active = 1 AND username LIKE CONCAT('%%', ?, '%%') GROUP BY account.id", CONNECTION_SYNCH); PrepareStatement(LOGIN_INS_ACCOUNT_AUTO_BANNED, "INSERT INTO account_banned VALUES (?, UNIX_TIMESTAMP(), UNIX_TIMESTAMP()+?, 'Trinity Auth', 'Failed login autoban', 1)", CONNECTION_ASYNC); PrepareStatement(LOGIN_DEL_ACCOUNT_BANNED, "DELETE FROM account_banned WHERE id = ?", CONNECTION_ASYNC); - PrepareStatement(LOGIN_SEL_SESSIONKEY, "SELECT a.sessionkey, a.id, aa.gmlevel FROM account a LEFT JOIN account_access aa ON (a.id = aa.id) WHERE username = ?", CONNECTION_SYNCH); PrepareStatement(LOGIN_UPD_VS, "UPDATE account SET v = ?, s = ? WHERE username = ?", CONNECTION_ASYNC); PrepareStatement(LOGIN_UPD_LOGONPROOF, "UPDATE account SET sessionkey = ?, last_ip = ?, last_login = NOW(), locale = ?, failed_logins = 0, os = ? WHERE username = ?", CONNECTION_SYNCH); - PrepareStatement(LOGIN_SEL_LOGONCHALLENGE, "SELECT a.sha_pass_hash, a.id, a.locked, a.lock_country, a.last_ip, aa.gmlevel, a.v, a.s, a.token_key FROM account a LEFT JOIN account_access aa ON (a.id = aa.id) WHERE a.username = ?", CONNECTION_SYNCH); + PrepareStatement(LOGIN_SEL_LOGONCHALLENGE, "SELECT a.id, UPPER(a.username), a.locked, a.lock_country, a.last_ip, a.failed_logins, ab.unbandate > UNIX_TIMESTAMP() OR ab.unbandate = ab.bandate, " + "ab.unbandate = ab.bandate, aa.gmlevel, a.token_key, a.sha_pass_hash, a.v, a.s " + "FROM account a LEFT JOIN account_access aa ON a.id = aa.id LEFT JOIN account_banned ab ON ab.id = a.id AND ab.active = 1 WHERE a.username = ?", CONNECTION_ASYNC); + PrepareStatement(LOGIN_SEL_RECONNECTCHALLENGE, "SELECT a.id, UPPER(a.username), a.locked, a.lock_country, a.last_ip, a.failed_logins, ab.unbandate > UNIX_TIMESTAMP() OR ab.unbandate = ab.bandate, " + "ab.unbandate = ab.bandate, aa.gmlevel, a.sessionKey " + "FROM account a LEFT JOIN account_access aa ON a.id = aa.id LEFT JOIN account_banned ab ON ab.id = a.id AND ab.active = 1 WHERE a.username = ?", CONNECTION_ASYNC); PrepareStatement(LOGIN_SEL_LOGON_COUNTRY, "SELECT country FROM ip2nation WHERE ip < ? ORDER BY ip DESC LIMIT 0,1", CONNECTION_SYNCH); PrepareStatement(LOGIN_UPD_FAILEDLOGINS, "UPDATE account SET failed_logins = failed_logins + 1 WHERE username = ?", CONNECTION_ASYNC); - 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 a.id, a.sessionkey, a.last_ip, a.locked, a.lock_country, a.expansion, a.mutetime, a.locale, a.recruiter, a.os, aa.gmLevel, " "ab.unbandate > UNIX_TIMESTAMP() OR ab.unbandate = ab.bandate, r.id FROM account a LEFT JOIN account_access aa ON a.id = aa.id AND aa.RealmID IN (-1, ?) " "LEFT JOIN account_banned ab ON a.id = ab.id AND ab.active = 1 LEFT JOIN account r ON a.id = r.recruiter WHERE a.username = ? ORDER BY aa.RealmID DESC LIMIT 1", CONNECTION_ASYNC); 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_REALM_CHARACTER_COUNTS, "SELECT realmid, numchars FROM realmcharacters WHERE acctid = ?", CONNECTION_ASYNC); 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 (ip, bandate, unbandate, bannedby, banreason) VALUES (?, UNIX_TIMESTAMP(), UNIX_TIMESTAMP()+?, ?, ?)", CONNECTION_ASYNC); diff --git a/src/server/database/Database/Implementation/LoginDatabase.h b/src/server/database/Database/Implementation/LoginDatabase.h index 69c2e758551..a3789fa2557 100644 --- a/src/server/database/Database/Implementation/LoginDatabase.h +++ b/src/server/database/Database/Implementation/LoginDatabase.h @@ -33,25 +33,22 @@ enum LoginDatabaseStatements LOGIN_DEL_EXPIRED_IP_BANS, LOGIN_UPD_EXPIRED_ACCOUNT_BANS, LOGIN_SEL_IP_INFO, - LOGIN_SEL_IP_BANNED, LOGIN_INS_IP_AUTO_BANNED, - LOGIN_SEL_ACCOUNT_BANNED, LOGIN_SEL_ACCOUNT_BANNED_ALL, LOGIN_SEL_ACCOUNT_BANNED_BY_USERNAME, LOGIN_INS_ACCOUNT_AUTO_BANNED, LOGIN_DEL_ACCOUNT_BANNED, - LOGIN_SEL_SESSIONKEY, LOGIN_UPD_VS, LOGIN_UPD_LOGONPROOF, LOGIN_SEL_LOGONCHALLENGE, + LOGIN_SEL_RECONNECTCHALLENGE, LOGIN_SEL_LOGON_COUNTRY, LOGIN_UPD_FAILEDLOGINS, - LOGIN_SEL_FAILEDLOGINS, LOGIN_SEL_ACCOUNT_ID_BY_NAME, LOGIN_SEL_ACCOUNT_LIST_BY_NAME, LOGIN_SEL_ACCOUNT_INFO_BY_NAME, LOGIN_SEL_ACCOUNT_LIST_BY_EMAIL, - LOGIN_SEL_NUM_CHARS_ON_REALM, + LOGIN_SEL_REALM_CHARACTER_COUNTS, LOGIN_SEL_ACCOUNT_BY_IP, LOGIN_INS_IP_BANNED, LOGIN_DEL_IP_NOT_BANNED, diff --git a/src/server/database/Database/MySQLConnection.cpp b/src/server/database/Database/MySQLConnection.cpp index 41dd61d3c3a..93d2a35f310 100644 --- a/src/server/database/Database/MySQLConnection.cpp +++ b/src/server/database/Database/MySQLConnection.cpp @@ -37,7 +37,6 @@ MySQLConnection::MySQLConnection(MySQLConnectionInfo& connInfo) : m_reconnecting(false), m_prepareError(false), m_queue(NULL), -m_worker(NULL), m_Mysql(NULL), m_connectionInfo(connInfo), m_connectionFlags(CONNECTION_SYNCH) { } @@ -50,24 +49,26 @@ m_Mysql(NULL), m_connectionInfo(connInfo), m_connectionFlags(CONNECTION_ASYNC) { - m_worker = new DatabaseWorker(m_queue, this); + m_worker = Trinity::make_unique<DatabaseWorker>(m_queue, this); } MySQLConnection::~MySQLConnection() { - delete m_worker; - - for (size_t i = 0; i < m_stmts.size(); ++i) - delete m_stmts[i]; - - if (m_Mysql) - mysql_close(m_Mysql); + Close(); } void MySQLConnection::Close() { - /// Only close us if we're not operating - delete this; + // Stop the worker thread before the statements are cleared + m_worker.reset(); + + m_stmts.clear(); + + if (m_Mysql) + { + mysql_close(m_Mysql); + m_Mysql = nullptr; + } } uint32 MySQLConnection::Open() @@ -412,7 +413,7 @@ int MySQLConnection::ExecuteTransaction(SQLTransaction& transaction) MySQLPreparedStatement* MySQLConnection::GetPreparedStatement(uint32 index) { ASSERT(index < m_stmts.size()); - MySQLPreparedStatement* ret = m_stmts[index]; + MySQLPreparedStatement* ret = m_stmts[index].get(); if (!ret) TC_LOG_ERROR("sql.sql", "Could not fetch prepared statement %u on database `%s`, connection type: %s.", index, m_connectionInfo.database.c_str(), (m_connectionFlags & CONNECTION_ASYNC) ? "asynchronous" : "synchronous"); @@ -424,16 +425,12 @@ void MySQLConnection::PrepareStatement(uint32 index, const char* sql, Connection { m_queries.insert(PreparedStatementMap::value_type(index, std::make_pair(sql, flags))); - // For reconnection case - if (m_reconnecting) - delete m_stmts[index]; - // Check if specified query should be prepared on this connection // i.e. don't prepare async statements on synchronous connections // to save memory that will not be used. if (!(m_connectionFlags & flags)) { - m_stmts[index] = NULL; + m_stmts[index].reset(); return; } @@ -455,8 +452,7 @@ void MySQLConnection::PrepareStatement(uint32 index, const char* sql, Connection } else { - MySQLPreparedStatement* mStmt = new MySQLPreparedStatement(stmt); - m_stmts[index] = mStmt; + m_stmts[index] = Trinity::make_unique<MySQLPreparedStatement>(stmt); } } } @@ -477,7 +473,7 @@ PreparedResultSet* MySQLConnection::Query(PreparedStatement* stmt) return new PreparedResultSet(stmt->m_stmt->GetSTMT(), result, rowCount, fieldCount); } -bool MySQLConnection::_HandleMySQLErrno(uint32 errNo) +bool MySQLConnection::_HandleMySQLErrno(uint32 errNo, uint8 attempts /*= 5*/) { switch (errNo) { @@ -486,9 +482,21 @@ bool MySQLConnection::_HandleMySQLErrno(uint32 errNo) case CR_INVALID_CONN_HANDLE: case CR_SERVER_LOST_EXTENDED: { + if (m_Mysql) + { + TC_LOG_ERROR("sql.sql", "Lost the connection to the MySQL server!"); + + mysql_close(GetHandle()); + m_Mysql = nullptr; + } + + /*no break*/ + } + case CR_CONN_HOST_ERROR: + { + TC_LOG_INFO("sql.sql", "Attempting to reconnect to the MySQL server..."); + m_reconnecting = true; - uint64 oldThreadId = mysql_thread_id(GetHandle()); - mysql_close(GetHandle()); uint32 const lErrno = Open(); if (!lErrno) @@ -496,24 +504,37 @@ bool MySQLConnection::_HandleMySQLErrno(uint32 errNo) // Don't remove 'this' pointer unless you want to skip loading all prepared statements... if (!this->PrepareStatements()) { - TC_LOG_ERROR("sql.sql", "Could not re-prepare statements!"); - Close(); - return false; + TC_LOG_FATAL("sql.sql", "Could not re-prepare statements!"); + std::this_thread::sleep_for(std::chrono::seconds(10)); + std::abort(); } - TC_LOG_INFO("sql.sql", "Connection to the MySQL server is active."); - if (oldThreadId != mysql_thread_id(GetHandle())) - TC_LOG_INFO("sql.sql", "Successfully reconnected to %s @%s:%s (%s).", - m_connectionInfo.database.c_str(), m_connectionInfo.host.c_str(), m_connectionInfo.port_or_socket.c_str(), - (m_connectionFlags & CONNECTION_ASYNC) ? "asynchronous" : "synchronous"); + TC_LOG_INFO("sql.sql", "Successfully reconnected to %s @%s:%s (%s).", + m_connectionInfo.database.c_str(), m_connectionInfo.host.c_str(), m_connectionInfo.port_or_socket.c_str(), + (m_connectionFlags & CONNECTION_ASYNC) ? "asynchronous" : "synchronous"); m_reconnecting = false; return true; } - // It's possible this attempted reconnect throws 2006 at us. To prevent crazy recursive calls, sleep here. - std::this_thread::sleep_for(std::chrono::seconds(3)); // Sleep 3 seconds - return _HandleMySQLErrno(lErrno); // Call self (recursive) + if ((--attempts) == 0) + { + // Shut down the server when the mysql server isn't + // reachable for some time + TC_LOG_FATAL("sql.sql", "Failed to reconnect to the MySQL server, " + "terminating the server to prevent data corruption!"); + + // We could also initiate a shutdown through using std::raise(SIGTERM) + std::this_thread::sleep_for(std::chrono::seconds(10)); + std::abort(); + } + else + { + // It's possible this attempted reconnect throws 2006 at us. + // To prevent crazy recursive calls, sleep here. + std::this_thread::sleep_for(std::chrono::seconds(3)); // Sleep 3 seconds + return _HandleMySQLErrno(lErrno, attempts); // Call self (recursive) + } } case ER_LOCK_DEADLOCK: diff --git a/src/server/database/Database/MySQLConnection.h b/src/server/database/Database/MySQLConnection.h index a981caa607e..a0b908593df 100644 --- a/src/server/database/Database/MySQLConnection.h +++ b/src/server/database/Database/MySQLConnection.h @@ -116,18 +116,18 @@ class MySQLConnection virtual void DoPrepareStatements() = 0; protected: - std::vector<MySQLPreparedStatement*> m_stmts; //! PreparedStatements storage + std::vector<std::unique_ptr<MySQLPreparedStatement>> m_stmts; //! PreparedStatements storage PreparedStatementMap m_queries; //! Query storage bool m_reconnecting; //! Are we reconnecting? bool m_prepareError; //! Was there any error while preparing statements? private: - bool _HandleMySQLErrno(uint32 errNo); + bool _HandleMySQLErrno(uint32 errNo, uint8 attempts = 5); private: ProducerConsumerQueue<SQLOperation*>* m_queue; //! Queue shared with other asynchronous connections. - DatabaseWorker* m_worker; //! Core worker task. - MYSQL * m_Mysql; //! MySQL Handle. + std::unique_ptr<DatabaseWorker> m_worker; //! Core worker task. + MYSQL* m_Mysql; //! MySQL Handle. MySQLConnectionInfo& m_connectionInfo; //! Connection info (used for logging) ConnectionFlags m_connectionFlags; //! Connection flags (for preparing relevant statements) std::mutex m_Mutex; diff --git a/src/server/database/Updater/DBUpdater.cpp b/src/server/database/Updater/DBUpdater.cpp index 170954a86f4..b18d6c67612 100644 --- a/src/server/database/Updater/DBUpdater.cpp +++ b/src/server/database/Updater/DBUpdater.cpp @@ -21,6 +21,7 @@ #include "UpdateFetcher.h" #include "DatabaseLoader.h" #include "Config.h" +#include "BuiltInConfig.h" #include <fstream> #include <iostream> @@ -35,23 +36,17 @@ using namespace boost::process; using namespace boost::process::initializers; using namespace boost::iostreams; -std::string DBUpdaterUtil::GetMySqlCli() +std::string DBUpdaterUtil::GetCorrectedMySQLExecutable() { if (!corrected_path().empty()) return corrected_path(); else - { - std::string const entry = sConfigMgr->GetStringDefault("Updates.MySqlCLIPath", ""); - if (!entry.empty()) - return entry; - else - return GitRevision::GetMySQLExecutable(); - } + return BuiltInConfig::GetMySQLExecutable(); } bool DBUpdaterUtil::CheckExecutable() { - boost::filesystem::path exe(GetMySqlCli()); + boost::filesystem::path exe(GetCorrectedMySQLExecutable()); if (!exists(exe)) { exe.clear(); @@ -85,16 +80,6 @@ std::string& DBUpdaterUtil::corrected_path() return path; } -template<class T> -std::string DBUpdater<T>::GetSourceDirectory() -{ - std::string const entry = sConfigMgr->GetStringDefault("Updates.SourcePath", ""); - if (!entry.empty()) - return entry; - else - return GitRevision::GetSourceDirectory(); -} - // Auth Database template<> std::string DBUpdater<LoginDatabaseConnection>::GetConfigEntry() @@ -111,7 +96,8 @@ std::string DBUpdater<LoginDatabaseConnection>::GetTableName() template<> std::string DBUpdater<LoginDatabaseConnection>::GetBaseFile() { - return DBUpdater<LoginDatabaseConnection>::GetSourceDirectory() + "/sql/base/auth_database.sql"; + return BuiltInConfig::GetSourceDirectory() + + "/sql/base/auth_database.sql"; } template<> @@ -169,7 +155,8 @@ std::string DBUpdater<CharacterDatabaseConnection>::GetTableName() template<> std::string DBUpdater<CharacterDatabaseConnection>::GetBaseFile() { - return DBUpdater<CharacterDatabaseConnection>::GetSourceDirectory() + "/sql/base/characters_database.sql"; + return BuiltInConfig::GetSourceDirectory() + + "/sql/base/characters_database.sql"; } template<> @@ -239,7 +226,7 @@ bool DBUpdater<T>::Update(DatabaseWorkerPool<T>& pool) TC_LOG_INFO("sql.updates", "Updating %s database...", DBUpdater<T>::GetTableName().c_str()); - Path const sourceDirectory(GetSourceDirectory()); + Path const sourceDirectory(BuiltInConfig::GetSourceDirectory()); if (!is_directory(sourceDirectory)) { @@ -410,7 +397,7 @@ void DBUpdater<T>::ApplyFile(DatabaseWorkerPool<T>& pool, std::string const& hos boost::process::pipe errPipe = create_pipe(); child c = execute(run_exe( - boost::filesystem::absolute(DBUpdaterUtil::GetMySqlCli()).generic_string()), + boost::filesystem::absolute(DBUpdaterUtil::GetCorrectedMySQLExecutable()).generic_string()), set_args(args), bind_stdin(source), throw_on_error(), bind_stdout(file_descriptor_sink(outPipe.sink, close_handle)), bind_stderr(file_descriptor_sink(errPipe.sink, close_handle))); diff --git a/src/server/database/Updater/DBUpdater.h b/src/server/database/Updater/DBUpdater.h index c9792ffe060..dbb897d2527 100644 --- a/src/server/database/Updater/DBUpdater.h +++ b/src/server/database/Updater/DBUpdater.h @@ -57,7 +57,7 @@ struct UpdateResult class DBUpdaterUtil { public: - static std::string GetMySqlCli(); + static std::string GetCorrectedMySQLExecutable(); static bool CheckExecutable(); @@ -71,8 +71,6 @@ class DBUpdater public: using Path = boost::filesystem::path; - static std::string GetSourceDirectory(); - static inline std::string GetConfigEntry(); static inline std::string GetTableName(); diff --git a/src/server/database/Updater/UpdateFetcher.cpp b/src/server/database/Updater/UpdateFetcher.cpp index fd0dbdd4b5a..2d60cdb92ef 100644 --- a/src/server/database/Updater/UpdateFetcher.cpp +++ b/src/server/database/Updater/UpdateFetcher.cpp @@ -137,24 +137,33 @@ UpdateFetcher::AppliedFileStorage UpdateFetcher::ReceiveAppliedFiles() const return map; } -UpdateFetcher::SQLUpdate UpdateFetcher::ReadSQLUpdate(boost::filesystem::path const& file) const +std::string UpdateFetcher::ReadSQLUpdate(boost::filesystem::path const& file) const { std::ifstream in(file.c_str()); - WPFatal(in.is_open(), "Could not read an update file."); + if (!in.is_open()) + { + TC_LOG_FATAL("sql.updates", "Failed to open the sql update \"%s\" for reading! " + "Stopping the server to keep the database integrity, " + "try to identify and solve the issue or disabled the database updater.", + file.generic_string().c_str()); - auto const start_pos = in.tellg(); - in.ignore(std::numeric_limits<std::streamsize>::max()); - auto const char_count = in.gcount(); - in.seekg(start_pos); + throw UpdateException("Opening the sql update failed!"); + } - SQLUpdate const update(new std::string(char_count, char{})); + auto update = [&in] { + std::ostringstream ss; + ss << in.rdbuf(); + return ss.str(); + }(); - in.read(&(*update)[0], update->size()); in.close(); return update; } -UpdateResult UpdateFetcher::Update(bool const redundancyChecks, bool const allowRehash, bool const archivedRedundancy, int32 const cleanDeadReferencesMaxCount) const +UpdateResult UpdateFetcher::Update(bool const redundancyChecks, + bool const allowRehash, + bool const archivedRedundancy, + int32 const cleanDeadReferencesMaxCount) const { LocaleFileStorage const available = GetFileList(); AppliedFileStorage applied = ReceiveAppliedFiles(); @@ -200,11 +209,9 @@ UpdateResult UpdateFetcher::Update(bool const redundancyChecks, bool const allow } } - // Read update from file - SQLUpdate const update = ReadSQLUpdate(availableQuery.first); - // Calculate hash - std::string const hash = CalculateHash(update); + std::string const hash = + CalculateHash(ReadSQLUpdate(availableQuery.first)); UpdateMode mode = MODE_APPLY; @@ -327,11 +334,11 @@ UpdateResult UpdateFetcher::Update(bool const redundancyChecks, bool const allow return UpdateResult(importedUpdates, countRecentUpdates, countArchivedUpdates); } -std::string UpdateFetcher::CalculateHash(SQLUpdate const& query) const +std::string UpdateFetcher::CalculateHash(std::string const& query) const { // Calculate a Sha1 hash based on query content. unsigned char digest[SHA_DIGEST_LENGTH]; - SHA1((unsigned char*)query->c_str(), query->length(), (unsigned char*)&digest); + SHA1((unsigned char*)query.c_str(), query.length(), (unsigned char*)&digest); return ByteArrayToHexStr(digest, SHA_DIGEST_LENGTH); } diff --git a/src/server/database/Updater/UpdateFetcher.h b/src/server/database/Updater/UpdateFetcher.h index 22a0d08c7f8..c87efea2b02 100644 --- a/src/server/database/Updater/UpdateFetcher.h +++ b/src/server/database/Updater/UpdateFetcher.h @@ -103,16 +103,16 @@ private: typedef std::unordered_map<std::string, std::string> HashToFileNameStorage; typedef std::unordered_map<std::string, AppliedFileEntry> AppliedFileStorage; typedef std::vector<UpdateFetcher::DirectoryEntry> DirectoryStorage; - typedef std::shared_ptr<std::string> SQLUpdate; LocaleFileStorage GetFileList() const; - void FillFileListRecursively(Path const& path, LocaleFileStorage& storage, State const state, uint32 const depth) const; + void FillFileListRecursively(Path const& path, LocaleFileStorage& storage, + State const state, uint32 const depth) const; DirectoryStorage ReceiveIncludedDirectories() const; AppliedFileStorage ReceiveAppliedFiles() const; - SQLUpdate ReadSQLUpdate(Path const& file) const; - std::string CalculateHash(SQLUpdate const& query) const; + std::string ReadSQLUpdate(Path const& file) const; + std::string CalculateHash(std::string const& query) const; uint32 Apply(Path const& path) const; diff --git a/src/server/game/AI/CoreAI/UnitAI.cpp b/src/server/game/AI/CoreAI/UnitAI.cpp index a3a5e7f7663..3aadf6e59a0 100644 --- a/src/server/game/AI/CoreAI/UnitAI.cpp +++ b/src/server/game/AI/CoreAI/UnitAI.cpp @@ -259,36 +259,6 @@ void UnitAI::FillAISpellInfo() } } -//Enable PlayerAI when charmed -void PlayerAI::OnCharmed(bool apply) -{ - me->IsAIEnabled = apply; -} - -void SimpleCharmedAI::UpdateAI(const uint32 /*diff*/) -{ - Creature* charmer = me->GetCharmer()->ToCreature(); - - //kill self if charm aura has infinite duration - if (charmer->IsInEvadeMode()) - { - Unit::AuraEffectList const& auras = me->GetAuraEffectsByType(SPELL_AURA_MOD_CHARM); - for (Unit::AuraEffectList::const_iterator iter = auras.begin(); iter != auras.end(); ++iter) - if ((*iter)->GetCasterGUID() == charmer->GetGUID() && (*iter)->GetBase()->IsPermanent()) - { - charmer->Kill(me); - return; - } - } - - if (!charmer->IsInCombat()) - me->GetMotionMaster()->MoveFollow(charmer, PET_FOLLOW_DIST, me->GetFollowAngle()); - - Unit* target = me->GetVictim(); - if (!target || !charmer->IsValidAttackTarget(target)) - AttackStart(charmer->SelectNearestTargetInAttackDistance()); -} - SpellTargetSelector::SpellTargetSelector(Unit* caster, uint32 spellId) : _caster(caster), _spellInfo(sSpellMgr->GetSpellForDifficultyFromSpell(sSpellMgr->GetSpellInfo(spellId), caster)) { diff --git a/src/server/game/AI/CoreAI/UnitAI.h b/src/server/game/AI/CoreAI/UnitAI.h index 5dc5946b226..766e747d998 100644 --- a/src/server/game/AI/CoreAI/UnitAI.h +++ b/src/server/game/AI/CoreAI/UnitAI.h @@ -268,21 +268,4 @@ class UnitAI UnitAI& operator=(UnitAI const& right) = delete; }; -class PlayerAI : public UnitAI -{ - protected: - Player* const me; - public: - explicit PlayerAI(Player* player) : UnitAI((Unit*)player), me(player) { } - - void OnCharmed(bool apply) override; -}; - -class SimpleCharmedAI : public PlayerAI -{ - public: - void UpdateAI(uint32 diff) override; - SimpleCharmedAI(Player* player): PlayerAI(player) { } -}; - #endif diff --git a/src/server/game/AI/CreatureAI.cpp b/src/server/game/AI/CreatureAI.cpp index c254a9124c1..352ae635878 100644 --- a/src/server/game/AI/CreatureAI.cpp +++ b/src/server/game/AI/CreatureAI.cpp @@ -133,7 +133,7 @@ void CreatureAI::MoveInLineOfSight(Unit* who) if (me->GetCreatureType() == CREATURE_TYPE_NON_COMBAT_PET) // non-combat pets should just stand there and look good;) return; - if (me->CanStartAttack(who, false)) + if (me->HasReactState(REACT_AGGRESSIVE) && me->CanStartAttack(who, false)) AttackStart(who); //else if (who->GetVictim() && me->IsFriendlyTo(who) // && me->IsWithinDistInMap(who, sWorld->getIntConfig(CONFIG_CREATURE_FAMILY_ASSISTANCE_RADIUS)) @@ -350,7 +350,7 @@ int32 CreatureAI::VisualizeBoundary(uint32 duration, Unit* owner, bool fill) con return boundsWarning ? LANG_CREATURE_MOVEMENT_MAYBE_UNBOUNDED : 0; } -bool CreatureAI::CheckBoundary(Position* who) const +bool CreatureAI::CheckBoundary(Position const* who) const { if (!who) who = me; diff --git a/src/server/game/AI/CreatureAI.h b/src/server/game/AI/CreatureAI.h index f250a79ea25..e009e2ed0b6 100644 --- a/src/server/game/AI/CreatureAI.h +++ b/src/server/game/AI/CreatureAI.h @@ -28,6 +28,7 @@ class WorldObject; class Unit; class Creature; class Player; +class PlayerAI; class SpellInfo; #define TIME_INTERVAL_LOOK 5000 @@ -79,7 +80,7 @@ class CreatureAI : public UnitAI Creature* DoSummon(uint32 entry, WorldObject* obj, float radius = 5.0f, uint32 despawnTime = 30000, TempSummonType summonType = TEMPSUMMON_CORPSE_TIMED_DESPAWN); Creature* DoSummonFlyer(uint32 entry, WorldObject* obj, float flightZ, float radius = 5.0f, uint32 despawnTime = 30000, TempSummonType summonType = TEMPSUMMON_CORPSE_TIMED_DESPAWN); - bool CheckBoundary(Position* who = nullptr) const; + bool CheckBoundary(Position const* who = nullptr) const; void SetBoundary(CreatureBoundary const* boundary) { _boundary = boundary; me->DoImmediateBoundaryCheck(); } public: enum EvadeReason @@ -186,6 +187,11 @@ class CreatureAI : public UnitAI virtual bool CanSeeAlways(WorldObject const* /*obj*/) { return false; } + // Called when a player is charmed by the creature + // If a PlayerAI* is returned, that AI is placed on the player instead of the default charm AI + // Object destruction is handled by Unit::RemoveCharmedBy + virtual PlayerAI* GetAIForCharmedPlayer(Player* /*who*/) { return nullptr; } + // intended for encounter design/debugging. do not use for other purposes. expensive. int32 VisualizeBoundary(uint32 duration, Unit* owner=nullptr, bool fill=false) const; virtual bool CheckInRoom(); diff --git a/src/server/game/AI/PlayerAI/PlayerAI.cpp b/src/server/game/AI/PlayerAI/PlayerAI.cpp new file mode 100644 index 00000000000..bafa1a0ecf7 --- /dev/null +++ b/src/server/game/AI/PlayerAI/PlayerAI.cpp @@ -0,0 +1,224 @@ +/* + * Copyright (C) 2016-2016 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 "PlayerAI.h" +#include "SpellAuras.h" +#include "SpellAuraEffects.h" + +enum Spells +{ + /* Generic */ + SPELL_AUTO_SHOT = 75, + SPELL_SHOOT = 3018, + SPELL_THROW = 2764, + SPELL_SHOOT_WAND = 5019, + + /* Paladin */ + PASSIVE_ILLUMINATION = 20215, + + /* Priest */ + SPELL_SOUL_WARDING = 63574, + SPELL_SPIRIT_REDEMPTION = 20711, + SPELL_SHADOWFORM = 15473, + + /* Shaman */ + SPELL_TIDAL_FORCE = 582, + SPELL_MANA_TIDE_TOTEM = 590, + SPELL_SHA_NATURE_SWIFT = 591, + SPELL_STORMSTRIKE = 17364, + + /* Druid */ + SPELL_MOONKIN_FORM = 24858, + SPELL_SWIFTMEND = 18562, + SPELL_DRU_NATURE_SWIFT = 17116, + SPELL_TREE_OF_LIFE = 33891 +}; + +bool PlayerAI::IsPlayerHealer(Player const* who) +{ + switch (who->getClass()) + { + case CLASS_WARRIOR: + case CLASS_HUNTER: + case CLASS_ROGUE: + case CLASS_DEATH_KNIGHT: + case CLASS_MAGE: + case CLASS_WARLOCK: + default: + return false; + case CLASS_PALADIN: + return who->HasSpell(PASSIVE_ILLUMINATION); + case CLASS_PRIEST: + return who->HasSpell(SPELL_SOUL_WARDING) || who->HasSpell(SPELL_SPIRIT_REDEMPTION); + case CLASS_SHAMAN: + return who->HasSpell(SPELL_MANA_TIDE_TOTEM) || who->HasSpell(SPELL_SHA_NATURE_SWIFT) || who->HasSpell(SPELL_TIDAL_FORCE); + case CLASS_DRUID: + return who->HasSpell(SPELL_SWIFTMEND) || who->HasSpell(SPELL_DRU_NATURE_SWIFT) || who->HasSpell(SPELL_TREE_OF_LIFE); + } +} + +bool PlayerAI::IsPlayerRangedAttacker(Player const* who) +{ + switch (who->getClass()) + { + case CLASS_WARRIOR: + case CLASS_PALADIN: + case CLASS_ROGUE: + case CLASS_DEATH_KNIGHT: + default: + return false; + case CLASS_MAGE: + case CLASS_WARLOCK: + return true; + case CLASS_HUNTER: + { + // check if we have a ranged weapon equipped + Item const* rangedSlot = who->GetItemByPos(INVENTORY_SLOT_BAG_0, EQUIPMENT_SLOT_RANGED); + if (ItemTemplate const* rangedTemplate = rangedSlot ? rangedSlot->GetTemplate() : nullptr) + if ((1 << rangedTemplate->SubClass) & ITEM_SUBCLASS_MASK_WEAPON_RANGED) + return true; + return false; + } + case CLASS_PRIEST: + return who->HasSpell(SPELL_SHADOWFORM); + case CLASS_SHAMAN: + return !who->HasSpell(SPELL_STORMSTRIKE); + case CLASS_DRUID: + return who->HasSpell(SPELL_MOONKIN_FORM); + } +} + +void PlayerAI::DoRangedAttackIfReady() +{ + if (me->HasUnitState(UNIT_STATE_CASTING)) + return; + + if (!me->isAttackReady(RANGED_ATTACK)) + return; + + Unit* victim = me->GetVictim(); + if (!victim) + return; + + uint32 rangedAttackSpell = 0; + + Item const* rangedItem = me->GetItemByPos(INVENTORY_SLOT_BAG_0, EQUIPMENT_SLOT_RANGED); + if (ItemTemplate const* rangedTemplate = rangedItem ? rangedItem->GetTemplate() : nullptr) + { + switch (rangedTemplate->SubClass) + { + case ITEM_SUBCLASS_WEAPON_BOW: + case ITEM_SUBCLASS_WEAPON_GUN: + case ITEM_SUBCLASS_WEAPON_CROSSBOW: + rangedAttackSpell = SPELL_SHOOT; + break; + case ITEM_SUBCLASS_WEAPON_THROWN: + rangedAttackSpell = SPELL_THROW; + break; + case ITEM_SUBCLASS_WEAPON_WAND: + rangedAttackSpell = SPELL_SHOOT_WAND; + break; + } + } + + if (!rangedAttackSpell) + return; + + me->CastSpell(victim, rangedAttackSpell, TRIGGERED_CAST_DIRECTLY); + me->resetAttackTimer(RANGED_ATTACK); +} + +void PlayerAI::DoAutoAttackIfReady() +{ + if (IsRangedAttacker()) + DoRangedAttackIfReady(); + else + DoMeleeAttackIfReady(); +} + +struct UncontrolledTargetSelectPredicate : public std::unary_function<Unit*, bool> +{ + bool operator()(Unit const* target) const + { + return !target->HasBreakableByDamageCrowdControlAura(); + } +}; +Unit* SimpleCharmedPlayerAI::SelectAttackTarget() const +{ + if (Unit* charmer = me->GetCharmer()) + return charmer->IsAIEnabled ? charmer->GetAI()->SelectTarget(SELECT_TARGET_RANDOM, 0, UncontrolledTargetSelectPredicate()) : charmer->GetVictim(); + return nullptr; +} + +void SimpleCharmedPlayerAI::UpdateAI(const uint32 /*diff*/) +{ + Creature* charmer = me->GetCharmer() ? me->GetCharmer()->ToCreature() : nullptr; + + //kill self if charm aura has infinite duration + if (charmer->IsInEvadeMode()) + { + Player::AuraEffectList const& auras = me->GetAuraEffectsByType(SPELL_AURA_MOD_CHARM); + for (Player::AuraEffectList::const_iterator iter = auras.begin(); iter != auras.end(); ++iter) + if ((*iter)->GetCasterGUID() == charmer->GetGUID() && (*iter)->GetBase()->IsPermanent()) + { + me->Kill(me); + return; + } + } + + if (charmer->IsInCombat()) + { + Unit* target = me->GetVictim(); + if (!target || !charmer->IsValidAttackTarget(target) || target->HasBreakableByDamageCrowdControlAura()) + { + target = SelectAttackTarget(); + if (!target) + return; + + if (IsRangedAttacker()) + AttackStartCaster(target, 28.0f); + else + AttackStart(target); + } + DoAutoAttackIfReady(); + } + else + { + me->AttackStop(); + me->CastStop(); + me->StopMoving(); + me->GetMotionMaster()->Clear(); + me->GetMotionMaster()->MoveFollow(charmer, PET_FOLLOW_DIST, PET_FOLLOW_ANGLE); + } +} + +void SimpleCharmedPlayerAI::OnCharmed(bool apply) +{ + if (apply) + { + me->CastStop(); + me->AttackStop(); + } + else + { + me->CastStop(); + me->AttackStop(); + // @todo only voluntary movement (don't cancel stuff like death grip or charge mid-animation) + me->GetMotionMaster()->Clear(); + me->StopMoving(); + } +} diff --git a/src/server/game/AI/PlayerAI/PlayerAI.h b/src/server/game/AI/PlayerAI/PlayerAI.h new file mode 100644 index 00000000000..1820bcf11c0 --- /dev/null +++ b/src/server/game/AI/PlayerAI/PlayerAI.h @@ -0,0 +1,60 @@ +/* + * Copyright (C) 2016-2016 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/>. + */ + +#ifndef TRINITY_PLAYERAI_H +#define TRINITY_PLAYERAI_H + +#include "UnitAI.h" +#include "Player.h" +#include "Creature.h" + +class PlayerAI : public UnitAI +{ + public: + explicit PlayerAI(Player* player) : UnitAI(static_cast<Unit*>(player)), me(player), _isSelfHealer(PlayerAI::IsPlayerHealer(player)), _isSelfRangedAttacker(PlayerAI::IsPlayerRangedAttacker(player)) { } + + void OnCharmed(bool /*apply*/) override { } // charm AI application for players is handled by Unit::SetCharmedBy / Unit::RemoveCharmedBy + + // helper functions to determine player info + static bool IsPlayerHealer(Player const* who); + bool IsHealer(Player const* who = nullptr) const { return (!who || who == me) ? _isSelfHealer : IsPlayerHealer(who); } + static bool IsPlayerRangedAttacker(Player const* who); + bool IsRangedAttacker(Player const* who = nullptr) const { return (!who || who == me) ? _isSelfRangedAttacker : IsPlayerRangedAttacker(who); } + + protected: + Player* const me; + void SetIsRangedAttacker(bool state) { _isSelfRangedAttacker = state; } // this allows overriding of the default ranged attacker detection + + virtual Unit* SelectAttackTarget() const { return me->GetCharmer() ? me->GetCharmer()->GetVictim() : nullptr; } + void DoRangedAttackIfReady(); + void DoAutoAttackIfReady(); + + private: + bool _isSelfHealer; + bool _isSelfRangedAttacker; +}; + +class SimpleCharmedPlayerAI : public PlayerAI +{ + public: + SimpleCharmedPlayerAI(Player* player) : PlayerAI(player) { } + void UpdateAI(uint32 diff) override; + void OnCharmed(bool apply) override; + Unit* SelectAttackTarget() const override; +}; + +#endif diff --git a/src/server/game/AI/ScriptedAI/ScriptedCreature.cpp b/src/server/game/AI/ScriptedAI/ScriptedCreature.cpp index 8a1be33cc2b..2fc87347364 100644 --- a/src/server/game/AI/ScriptedAI/ScriptedCreature.cpp +++ b/src/server/game/AI/ScriptedAI/ScriptedCreature.cpp @@ -547,6 +547,29 @@ void BossAI::UpdateAI(uint32 diff) DoMeleeAttackIfReady(); } +void BossAI::_DespawnAtEvade(uint32 delayToRespawn) +{ + if (delayToRespawn < 2) + { + TC_LOG_ERROR("scripts", "_DespawnAtEvade called with delay of %u seconds, defaulting to 2.", delayToRespawn); + delayToRespawn = 2; + } + + uint32 corpseDelay = me->GetCorpseDelay(); + uint32 respawnDelay = me->GetRespawnDelay(); + + me->SetCorpseDelay(1); + me->SetRespawnDelay(delayToRespawn - 1); + + me->DespawnOrUnsummon(); + + me->SetCorpseDelay(corpseDelay); + me->SetRespawnDelay(respawnDelay); + + if(instance) + instance->SetBossState(_bossId, FAIL); +} + // WorldBossAI - for non-instanced bosses WorldBossAI::WorldBossAI(Creature* creature) : diff --git a/src/server/game/AI/ScriptedAI/ScriptedCreature.h b/src/server/game/AI/ScriptedAI/ScriptedCreature.h index 448ddc7dc73..5452a033a17 100644 --- a/src/server/game/AI/ScriptedAI/ScriptedCreature.h +++ b/src/server/game/AI/ScriptedAI/ScriptedCreature.h @@ -360,11 +360,14 @@ class BossAI : public ScriptedAI void JustDied(Unit* /*killer*/) override { _JustDied(); } void JustReachedHome() override { _JustReachedHome(); } + bool CanAIAttack(Unit const* target) const override { return CheckBoundary(target); } + protected: void _Reset(); void _EnterCombat(); void _JustDied(); void _JustReachedHome() { me->setActive(false); } + void _DespawnAtEvade(uint32 delayToRespawn = 30); void TeleportCheaters(); diff --git a/src/server/game/AI/ScriptedAI/ScriptedEscortAI.cpp b/src/server/game/AI/ScriptedAI/ScriptedEscortAI.cpp index 68cb8d346d0..fa80634e0f0 100644 --- a/src/server/game/AI/ScriptedAI/ScriptedEscortAI.cpp +++ b/src/server/game/AI/ScriptedAI/ScriptedEscortAI.cpp @@ -105,7 +105,7 @@ bool npc_escortAI::AssistPlayerInCombat(Unit* who) void npc_escortAI::MoveInLineOfSight(Unit* who) { - if (!me->HasUnitState(UNIT_STATE_STUNNED) && who->isTargetableForAttack() && who->isInAccessiblePlaceFor(me)) + if (me->HasReactState(REACT_AGGRESSIVE) && !me->HasUnitState(UNIT_STATE_STUNNED) && who->isTargetableForAttack() && who->isInAccessiblePlaceFor(me)) { if (HasEscortState(STATE_ESCORT_ESCORTING) && AssistPlayerInCombat(who)) return; diff --git a/src/server/game/AI/ScriptedAI/ScriptedFollowerAI.cpp b/src/server/game/AI/ScriptedAI/ScriptedFollowerAI.cpp index dc9f6d2681e..778edf8cab5 100644 --- a/src/server/game/AI/ScriptedAI/ScriptedFollowerAI.cpp +++ b/src/server/game/AI/ScriptedAI/ScriptedFollowerAI.cpp @@ -102,7 +102,7 @@ bool FollowerAI::AssistPlayerInCombat(Unit* who) void FollowerAI::MoveInLineOfSight(Unit* who) { - if (!me->HasUnitState(UNIT_STATE_STUNNED) && who->isTargetableForAttack() && who->isInAccessiblePlaceFor(me)) + if (me->HasReactState(REACT_AGGRESSIVE) && !me->HasUnitState(UNIT_STATE_STUNNED) && who->isTargetableForAttack() && who->isInAccessiblePlaceFor(me)) { if (HasFollowState(STATE_FOLLOW_INPROGRESS) && AssistPlayerInCombat(who)) return; diff --git a/src/server/game/AI/SmartScripts/SmartAI.cpp b/src/server/game/AI/SmartScripts/SmartAI.cpp index eca327e770e..361bb1a5b1d 100644 --- a/src/server/game/AI/SmartScripts/SmartAI.cpp +++ b/src/server/game/AI/SmartScripts/SmartAI.cpp @@ -466,6 +466,9 @@ bool SmartAI::CanAIAttack(const Unit* /*who*/) const bool SmartAI::AssistPlayerInCombat(Unit* who) { + if (me->HasReactState(REACT_PASSIVE)) + return false; + if (!who || !who->GetVictim()) return false; diff --git a/src/server/game/AI/SmartScripts/SmartScript.cpp b/src/server/game/AI/SmartScripts/SmartScript.cpp index 01f47582926..859282891fb 100644 --- a/src/server/game/AI/SmartScripts/SmartScript.cpp +++ b/src/server/game/AI/SmartScripts/SmartScript.cpp @@ -1998,7 +1998,7 @@ void SmartScript::ProcessAction(SmartScriptHolder& e, Unit* unit, uint32 var0, u 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); + creature->GetMotionMaster()->MoveJump(e.target.x, e.target.y, e.target.z, 0.0f, (float)e.action.jump.speedxy, (float)e.action.jump.speedz); // @todo add optional jump orientation support? } } /// @todo Resume path when reached jump location diff --git a/src/server/game/AI/SmartScripts/SmartScriptMgr.cpp b/src/server/game/AI/SmartScripts/SmartScriptMgr.cpp index 6f424003006..3fe6fcdb4ae 100644 --- a/src/server/game/AI/SmartScripts/SmartScriptMgr.cpp +++ b/src/server/game/AI/SmartScripts/SmartScriptMgr.cpp @@ -468,7 +468,7 @@ bool SmartAIMgr::IsEventValid(SmartScriptHolder& e) TC_LOG_ERROR("sql.sql", "SmartAIMgr: Entry %d SourceType %u Event %u Action %u uses non-existent Map entry %u, skipped.", e.entryOrGuid, e.GetScriptType(), e.event_id, e.GetActionType(), e.event.respawn.map); return false; } - if (e.event.respawn.type == SMART_SCRIPT_RESPAWN_CONDITION_AREA && !GetAreaEntryByAreaID(e.event.respawn.area)) + if (e.event.respawn.type == SMART_SCRIPT_RESPAWN_CONDITION_AREA && !sAreaTableStore.LookupEntry(e.event.respawn.area)) { TC_LOG_ERROR("sql.sql", "SmartAIMgr: Entry %d SourceType %u Event %u Action %u uses non-existent Area entry %u, skipped.", e.entryOrGuid, e.GetScriptType(), e.event_id, e.GetActionType(), e.event.respawn.area); return false; diff --git a/src/server/game/Accounts/RBAC.h b/src/server/game/Accounts/RBAC.h index 4ebd3ae7042..3f5db56558b 100644 --- a/src/server/game/Accounts/RBAC.h +++ b/src/server/game/Accounts/RBAC.h @@ -670,8 +670,8 @@ enum RBACPermissions RBAC_PERM_COMMAND_WP_UNLOAD = 772, RBAC_PERM_COMMAND_WP_RELOAD = 773, RBAC_PERM_COMMAND_WP_SHOW = 774, - RBAC_PERM_COMMAND_MODIFY_CURRENCY = 775, // only 4.3.4 - RBAC_PERM_COMMAND_DEBUG_PHASE = 776, // only 4.3.4 + RBAC_PERM_COMMAND_MODIFY_CURRENCY = 775, // only 6.x + RBAC_PERM_COMMAND_DEBUG_PHASE = 776, // only 6.x RBAC_PERM_COMMAND_MAILBOX = 777, RBAC_PERM_COMMAND_AHBOT = 778, RBAC_PERM_COMMAND_AHBOT_ITEMS = 779, diff --git a/src/server/game/Achievements/AchievementMgr.cpp b/src/server/game/Achievements/AchievementMgr.cpp index 90e61826e35..40cb643bbb5 100644 --- a/src/server/game/Achievements/AchievementMgr.cpp +++ b/src/server/game/Achievements/AchievementMgr.cpp @@ -46,7 +46,7 @@ bool AchievementCriteriaData::IsValid(AchievementCriteriaEntry const* criteria) { if (dataType >= MAX_ACHIEVEMENT_CRITERIA_DATA_TYPE) { - TC_LOG_ERROR("sql.sql", "Table `achievement_criteria_data` for criteria (Entry: %u) has wrong data type (%u), ignored.", criteria->ID, dataType); + TC_LOG_ERROR("sql.sql", "Table `achievement_criteria_data` for criteria (Entry: %u) contains a wrong data type (%u), ignored.", criteria->ID, dataType); return false; } @@ -81,7 +81,7 @@ bool AchievementCriteriaData::IsValid(AchievementCriteriaEntry const* criteria) default: if (dataType != ACHIEVEMENT_CRITERIA_DATA_TYPE_SCRIPT) { - TC_LOG_ERROR("sql.sql", "Table `achievement_criteria_data` has data for non-supported criteria type (Entry: %u Type: %u), ignored.", criteria->ID, criteria->requiredType); + TC_LOG_ERROR("sql.sql", "Table `achievement_criteria_data` contains data for a non-supported criteria type (Entry: %u Type: %u), ignored.", criteria->ID, criteria->requiredType); return false; } break; @@ -96,7 +96,7 @@ bool AchievementCriteriaData::IsValid(AchievementCriteriaEntry const* criteria) case ACHIEVEMENT_CRITERIA_DATA_TYPE_T_CREATURE: if (!creature.id || !sObjectMgr->GetCreatureTemplate(creature.id)) { - TC_LOG_ERROR("sql.sql", "Table `achievement_criteria_data` (Entry: %u Type: %u) for data type ACHIEVEMENT_CRITERIA_DATA_TYPE_CREATURE (%u) has non-existing creature id in value1 (%u), ignored.", + TC_LOG_ERROR("sql.sql", "Table `achievement_criteria_data` (Entry: %u Type: %u) for data type ACHIEVEMENT_CRITERIA_DATA_TYPE_CREATURE (%u) contains a non-existing creature id in value1 (%u), ignored.", criteria->ID, criteria->requiredType, dataType, creature.id); return false; } @@ -104,13 +104,13 @@ bool AchievementCriteriaData::IsValid(AchievementCriteriaEntry const* criteria) case ACHIEVEMENT_CRITERIA_DATA_TYPE_T_PLAYER_CLASS_RACE: if (classRace.class_id && ((1 << (classRace.class_id-1)) & CLASSMASK_ALL_PLAYABLE) == 0) { - TC_LOG_ERROR("sql.sql", "Table `achievement_criteria_data` (Entry: %u Type: %u) for data type ACHIEVEMENT_CRITERIA_DATA_TYPE_T_PLAYER_CLASS_RACE (%u) has non-existing class in value1 (%u), ignored.", + TC_LOG_ERROR("sql.sql", "Table `achievement_criteria_data` (Entry: %u Type: %u) for data type ACHIEVEMENT_CRITERIA_DATA_TYPE_T_PLAYER_CLASS_RACE (%u) contains a non-existing class in value1 (%u), ignored.", criteria->ID, criteria->requiredType, dataType, classRace.class_id); return false; } if (classRace.race_id && ((1 << (classRace.race_id-1)) & RACEMASK_ALL_PLAYABLE) == 0) { - TC_LOG_ERROR("sql.sql", "Table `achievement_criteria_data` (Entry: %u Type: %u) for data type ACHIEVEMENT_CRITERIA_DATA_TYPE_T_PLAYER_CLASS_RACE (%u) has non-existing race in value2 (%u), ignored.", + TC_LOG_ERROR("sql.sql", "Table `achievement_criteria_data` (Entry: %u Type: %u) for data type ACHIEVEMENT_CRITERIA_DATA_TYPE_T_PLAYER_CLASS_RACE (%u) contains a non-existing race in value2 (%u), ignored.", criteria->ID, criteria->requiredType, dataType, classRace.race_id); return false; } @@ -118,7 +118,7 @@ bool AchievementCriteriaData::IsValid(AchievementCriteriaEntry const* criteria) case ACHIEVEMENT_CRITERIA_DATA_TYPE_T_PLAYER_LESS_HEALTH: if (health.percent < 1 || health.percent > 100) { - TC_LOG_ERROR("sql.sql", "Table `achievement_criteria_data` (Entry: %u Type: %u) for data type ACHIEVEMENT_CRITERIA_DATA_TYPE_PLAYER_LESS_HEALTH (%u) has wrong percent value in value1 (%u), ignored.", + TC_LOG_ERROR("sql.sql", "Table `achievement_criteria_data` (Entry: %u Type: %u) for data type ACHIEVEMENT_CRITERIA_DATA_TYPE_PLAYER_LESS_HEALTH (%u) contains a wrong percent value in value1 (%u), ignored.", criteria->ID, criteria->requiredType, dataType, health.percent); return false; } @@ -126,7 +126,7 @@ bool AchievementCriteriaData::IsValid(AchievementCriteriaEntry const* criteria) case ACHIEVEMENT_CRITERIA_DATA_TYPE_T_PLAYER_DEAD: if (player_dead.own_team_flag > 1) { - TC_LOG_ERROR("sql.sql", "Table `achievement_criteria_data` (Entry: %u Type: %u) for data type ACHIEVEMENT_CRITERIA_DATA_TYPE_T_PLAYER_DEAD (%u) has wrong boolean value1 (%u).", + TC_LOG_ERROR("sql.sql", "Table `achievement_criteria_data` (Entry: %u Type: %u) for data type ACHIEVEMENT_CRITERIA_DATA_TYPE_T_PLAYER_DEAD (%u) contains a wrong boolean value1 (%u).", criteria->ID, criteria->requiredType, dataType, player_dead.own_team_flag); return false; } @@ -137,28 +137,28 @@ bool AchievementCriteriaData::IsValid(AchievementCriteriaEntry const* criteria) SpellInfo const* spellEntry = sSpellMgr->GetSpellInfo(aura.spell_id); if (!spellEntry) { - TC_LOG_ERROR("sql.sql", "Table `achievement_criteria_data` (Entry: %u Type: %u) for data type %s (%u) has wrong spell id in value1 (%u), ignored.", + TC_LOG_ERROR("sql.sql", "Table `achievement_criteria_data` (Entry: %u Type: %u) for data type %s (%u) contains a wrong spell id in value1 (%u), ignored.", criteria->ID, criteria->requiredType, (dataType == ACHIEVEMENT_CRITERIA_DATA_TYPE_S_AURA?"ACHIEVEMENT_CRITERIA_DATA_TYPE_S_AURA":"ACHIEVEMENT_CRITERIA_DATA_TYPE_T_AURA"), dataType, aura.spell_id); return false; } if (aura.effect_idx >= 3) { - TC_LOG_ERROR("sql.sql", "Table `achievement_criteria_data` (Entry: %u Type: %u) for data type %s (%u) has wrong spell effect index in value2 (%u), ignored.", + TC_LOG_ERROR("sql.sql", "Table `achievement_criteria_data` (Entry: %u Type: %u) for data type %s (%u) contains a wrong spell effect index in value2 (%u), ignored.", criteria->ID, criteria->requiredType, (dataType == ACHIEVEMENT_CRITERIA_DATA_TYPE_S_AURA?"ACHIEVEMENT_CRITERIA_DATA_TYPE_S_AURA":"ACHIEVEMENT_CRITERIA_DATA_TYPE_T_AURA"), dataType, aura.effect_idx); return false; } if (!spellEntry->Effects[aura.effect_idx].ApplyAuraName) { - TC_LOG_ERROR("sql.sql", "Table `achievement_criteria_data` (Entry: %u Type: %u) for data type %s (%u) has non-aura spell effect (ID: %u Effect: %u), ignores.", + TC_LOG_ERROR("sql.sql", "Table `achievement_criteria_data` (Entry: %u Type: %u) for data type %s (%u) contains a non-aura spell effect (ID: %u Effect: %u), ignored.", criteria->ID, criteria->requiredType, (dataType == ACHIEVEMENT_CRITERIA_DATA_TYPE_S_AURA?"ACHIEVEMENT_CRITERIA_DATA_TYPE_S_AURA":"ACHIEVEMENT_CRITERIA_DATA_TYPE_T_AURA"), dataType, aura.spell_id, aura.effect_idx); return false; } return true; } case ACHIEVEMENT_CRITERIA_DATA_TYPE_S_AREA: - if (!GetAreaEntryByAreaID(area.id)) + if (!sAreaTableStore.LookupEntry(area.id)) { - TC_LOG_ERROR("sql.sql", "Table `achievement_criteria_data` (Entry: %u Type: %u) for data type ACHIEVEMENT_CRITERIA_DATA_TYPE_S_AREA (%u) has wrong area id in value1 (%u), ignored.", + TC_LOG_ERROR("sql.sql", "Table `achievement_criteria_data` (Entry: %u Type: %u) for data type ACHIEVEMENT_CRITERIA_DATA_TYPE_S_AREA (%u) contains a wrong area id in value1 (%u), ignored.", criteria->ID, criteria->requiredType, dataType, area.id); return false; } @@ -166,7 +166,7 @@ bool AchievementCriteriaData::IsValid(AchievementCriteriaEntry const* criteria) case ACHIEVEMENT_CRITERIA_DATA_TYPE_VALUE: if (value.compType >= COMP_TYPE_MAX) { - TC_LOG_ERROR("sql.sql", "Table `achievement_criteria_data` (Entry: %u Type: %u) for data type ACHIEVEMENT_CRITERIA_DATA_TYPE_VALUE (%u) has wrong ComparisionType in value2 (%u), ignored.", + TC_LOG_ERROR("sql.sql", "Table `achievement_criteria_data` (Entry: %u Type: %u) for data type ACHIEVEMENT_CRITERIA_DATA_TYPE_VALUE (%u) contains a wrong ComparisionType in value2 (%u), ignored.", criteria->ID, criteria->requiredType, dataType, value.compType); return false; } @@ -174,7 +174,7 @@ bool AchievementCriteriaData::IsValid(AchievementCriteriaEntry const* criteria) case ACHIEVEMENT_CRITERIA_DATA_TYPE_T_LEVEL: if (level.minlevel > STRONG_MAX_LEVEL) { - TC_LOG_ERROR("sql.sql", "Table `achievement_criteria_data` (Entry: %u Type: %u) for data type ACHIEVEMENT_CRITERIA_DATA_TYPE_T_LEVEL (%u) has wrong minlevel in value1 (%u), ignored.", + TC_LOG_ERROR("sql.sql", "Table `achievement_criteria_data` (Entry: %u Type: %u) for data type ACHIEVEMENT_CRITERIA_DATA_TYPE_T_LEVEL (%u) contains a wrong minlevel in value1 (%u), ignored.", criteria->ID, criteria->requiredType, dataType, level.minlevel); return false; } @@ -182,7 +182,7 @@ bool AchievementCriteriaData::IsValid(AchievementCriteriaEntry const* criteria) case ACHIEVEMENT_CRITERIA_DATA_TYPE_T_GENDER: if (gender.gender > GENDER_NONE) { - TC_LOG_ERROR("sql.sql", "Table `achievement_criteria_data` (Entry: %u Type: %u) for data type ACHIEVEMENT_CRITERIA_DATA_TYPE_T_GENDER (%u) has wrong gender in value1 (%u), ignored.", + TC_LOG_ERROR("sql.sql", "Table `achievement_criteria_data` (Entry: %u Type: %u) for data type ACHIEVEMENT_CRITERIA_DATA_TYPE_T_GENDER (%u) contains a wrong gender value in value1 (%u), ignored.", criteria->ID, criteria->requiredType, dataType, gender.gender); return false; } @@ -190,7 +190,7 @@ bool AchievementCriteriaData::IsValid(AchievementCriteriaEntry const* criteria) case ACHIEVEMENT_CRITERIA_DATA_TYPE_SCRIPT: if (!ScriptId) { - TC_LOG_ERROR("sql.sql", "Table `achievement_criteria_data` (Entry: %u Type: %u) for data type ACHIEVEMENT_CRITERIA_DATA_TYPE_SCRIPT (%u) does not have ScriptName set, ignored.", + TC_LOG_ERROR("sql.sql", "Table `achievement_criteria_data` (Entry: %u Type: %u) for data type ACHIEVEMENT_CRITERIA_DATA_TYPE_SCRIPT (%u) does not have a ScriptName set, ignored.", criteria->ID, criteria->requiredType, dataType); return false; } @@ -198,7 +198,7 @@ bool AchievementCriteriaData::IsValid(AchievementCriteriaEntry const* criteria) case ACHIEVEMENT_CRITERIA_DATA_TYPE_MAP_DIFFICULTY: if (difficulty.difficulty >= MAX_DIFFICULTY) { - TC_LOG_ERROR("sql.sql", "Table `achievement_criteria_data` (Entry: %u Type: %u) for data type ACHIEVEMENT_CRITERIA_DATA_TYPE_MAP_DIFFICULTY (%u) has wrong difficulty in value1 (%u), ignored.", + TC_LOG_ERROR("sql.sql", "Table `achievement_criteria_data` (Entry: %u Type: %u) for data type ACHIEVEMENT_CRITERIA_DATA_TYPE_MAP_DIFFICULTY (%u) contains a wrong difficulty value in value1 (%u), ignored.", criteria->ID, criteria->requiredType, dataType, difficulty.difficulty); return false; } @@ -206,7 +206,7 @@ bool AchievementCriteriaData::IsValid(AchievementCriteriaEntry const* criteria) case ACHIEVEMENT_CRITERIA_DATA_TYPE_MAP_PLAYER_COUNT: if (map_players.maxcount <= 0) { - TC_LOG_ERROR("sql.sql", "Table `achievement_criteria_data` (Entry: %u Type: %u) for data type ACHIEVEMENT_CRITERIA_DATA_TYPE_MAP_PLAYER_COUNT (%u) has wrong max players count in value1 (%u), ignored.", + TC_LOG_ERROR("sql.sql", "Table `achievement_criteria_data` (Entry: %u Type: %u) for data type ACHIEVEMENT_CRITERIA_DATA_TYPE_MAP_PLAYER_COUNT (%u) contains a wrong max players count in value1 (%u), ignored.", criteria->ID, criteria->requiredType, dataType, map_players.maxcount); return false; } @@ -214,7 +214,7 @@ bool AchievementCriteriaData::IsValid(AchievementCriteriaEntry const* criteria) case ACHIEVEMENT_CRITERIA_DATA_TYPE_T_TEAM: if (team.team != ALLIANCE && team.team != HORDE) { - TC_LOG_ERROR("sql.sql", "Table `achievement_criteria_data` (Entry: %u Type: %u) for data type ACHIEVEMENT_CRITERIA_DATA_TYPE_T_TEAM (%u) has unknown team in value1 (%u), ignored.", + TC_LOG_ERROR("sql.sql", "Table `achievement_criteria_data` (Entry: %u Type: %u) for data type ACHIEVEMENT_CRITERIA_DATA_TYPE_T_TEAM (%u) contains an unknown team value in value1 (%u), ignored.", criteria->ID, criteria->requiredType, dataType, team.team); return false; } @@ -222,7 +222,7 @@ bool AchievementCriteriaData::IsValid(AchievementCriteriaEntry const* criteria) case ACHIEVEMENT_CRITERIA_DATA_TYPE_S_DRUNK: if (drunk.state >= MAX_DRUNKEN) { - TC_LOG_ERROR("sql.sql", "Table `achievement_criteria_data` (Entry: %u Type: %u) for data type ACHIEVEMENT_CRITERIA_DATA_TYPE_S_DRUNK (%u) has unknown drunken state in value1 (%u), ignored.", + TC_LOG_ERROR("sql.sql", "Table `achievement_criteria_data` (Entry: %u Type: %u) for data type ACHIEVEMENT_CRITERIA_DATA_TYPE_S_DRUNK (%u) contains an unknown drunken state value in value1 (%u), ignored.", criteria->ID, criteria->requiredType, dataType, drunk.state); return false; } @@ -230,7 +230,7 @@ bool AchievementCriteriaData::IsValid(AchievementCriteriaEntry const* criteria) case ACHIEVEMENT_CRITERIA_DATA_TYPE_HOLIDAY: if (!sHolidaysStore.LookupEntry(holiday.id)) { - TC_LOG_ERROR("sql.sql", "Table `achievement_criteria_data` (Entry: %u Type: %u) for data type ACHIEVEMENT_CRITERIA_DATA_TYPE_HOLIDAY (%u) has unknown holiday in value1 (%u), ignored.", + TC_LOG_ERROR("sql.sql", "Table `achievement_criteria_data` (Entry: %u Type: %u) for data type ACHIEVEMENT_CRITERIA_DATA_TYPE_HOLIDAY (%u) contains an unknown holiday entry in value1 (%u), ignored.", criteria->ID, criteria->requiredType, dataType, holiday.id); return false; } @@ -240,7 +240,7 @@ bool AchievementCriteriaData::IsValid(AchievementCriteriaEntry const* criteria) case ACHIEVEMENT_CRITERIA_DATA_TYPE_S_EQUIPED_ITEM: if (equipped_item.item_quality >= MAX_ITEM_QUALITY) { - TC_LOG_ERROR("sql.sql", "Table `achievement_criteria_data` (Entry: %u Type: %u) for data type ACHIEVEMENT_CRITERIA_DATA_TYPE_S_EQUIPED_ITEM (%u) has unknown quality state in value1 (%u), ignored.", + TC_LOG_ERROR("sql.sql", "Table `achievement_criteria_data` (Entry: %u Type: %u) for data type ACHIEVEMENT_CRITERIA_DATA_TYPE_S_EQUIPED_ITEM (%u) contains an unknown quality state value in value1 (%u), ignored.", criteria->ID, criteria->requiredType, dataType, equipped_item.item_quality); return false; } @@ -248,7 +248,7 @@ bool AchievementCriteriaData::IsValid(AchievementCriteriaEntry const* criteria) case ACHIEVEMENT_CRITERIA_DATA_TYPE_MAP_ID: if (!sMapStore.LookupEntry(map_id.mapId)) { - TC_LOG_ERROR("sql.sql", "Table `achievement_criteria_data` (Entry: %u Type: %u) for data type ACHIEVEMENT_CRITERIA_DATA_TYPE_MAP_ID (%u) has unknown map id in value1 (%u), ignored.", + TC_LOG_ERROR("sql.sql", "Table `achievement_criteria_data` (Entry: %u Type: %u) for data type ACHIEVEMENT_CRITERIA_DATA_TYPE_MAP_ID (%u) contains an unknown map id in value1 (%u), ignored.", criteria->ID, criteria->requiredType, dataType, map_id.mapId); return false; } @@ -256,19 +256,19 @@ bool AchievementCriteriaData::IsValid(AchievementCriteriaEntry const* criteria) case ACHIEVEMENT_CRITERIA_DATA_TYPE_S_PLAYER_CLASS_RACE: if (!classRace.class_id && !classRace.race_id) { - TC_LOG_ERROR("sql.sql", "Table `achievement_criteria_data` (Entry: %u Type: %u) for data type ACHIEVEMENT_CRITERIA_DATA_TYPE_S_PLAYER_CLASS_RACE (%u) must not have 0 in either value field, ignored.", + TC_LOG_ERROR("sql.sql", "Table `achievement_criteria_data` (Entry: %u Type: %u) for data type ACHIEVEMENT_CRITERIA_DATA_TYPE_S_PLAYER_CLASS_RACE (%u) should not have 0 in either value field. Ignored.", criteria->ID, criteria->requiredType, dataType); return false; } if (classRace.class_id && ((1 << (classRace.class_id-1)) & CLASSMASK_ALL_PLAYABLE) == 0) { - TC_LOG_ERROR("sql.sql", "Table `achievement_criteria_data` (Entry: %u Type: %u) for data type ACHIEVEMENT_CRITERIA_DATA_TYPE_S_PLAYER_CLASS_RACE (%u) has non-existing class in value1 (%u), ignored.", + TC_LOG_ERROR("sql.sql", "Table `achievement_criteria_data` (Entry: %u Type: %u) for data type ACHIEVEMENT_CRITERIA_DATA_TYPE_S_PLAYER_CLASS_RACE (%u) contains a non-existing class entry in value1 (%u), ignored.", criteria->ID, criteria->requiredType, dataType, classRace.class_id); return false; } if (classRace.race_id && ((1 << (classRace.race_id-1)) & RACEMASK_ALL_PLAYABLE) == 0) { - TC_LOG_ERROR("sql.sql", "Table `achievement_criteria_data` (Entry: %u Type: %u) for data type ACHIEVEMENT_CRITERIA_DATA_TYPE_S_PLAYER_CLASS_RACE (%u) has non-existing race in value2 (%u), ignored.", + TC_LOG_ERROR("sql.sql", "Table `achievement_criteria_data` (Entry: %u Type: %u) for data type ACHIEVEMENT_CRITERIA_DATA_TYPE_S_PLAYER_CLASS_RACE (%u) contains a non-existing race entry in value2 (%u), ignored.", criteria->ID, criteria->requiredType, dataType, classRace.race_id); return false; } @@ -276,13 +276,13 @@ bool AchievementCriteriaData::IsValid(AchievementCriteriaEntry const* criteria) case ACHIEVEMENT_CRITERIA_DATA_TYPE_S_KNOWN_TITLE: if (!sCharTitlesStore.LookupEntry(known_title.title_id)) { - TC_LOG_ERROR("sql.sql", "Table `achievement_criteria_data` (Entry: %u Type: %u) for data type ACHIEVEMENT_CRITERIA_DATA_TYPE_S_KNOWN_TITLE (%u) have unknown title_id in value1 (%u), ignore.", + TC_LOG_ERROR("sql.sql", "Table `achievement_criteria_data` (Entry: %u Type: %u) for data type ACHIEVEMENT_CRITERIA_DATA_TYPE_S_KNOWN_TITLE (%u) contains an unknown title_id in value1 (%u), ignore.", criteria->ID, criteria->requiredType, dataType, known_title.title_id); return false; } return true; default: - TC_LOG_ERROR("sql.sql", "Table `achievement_criteria_data` (Entry: %u Type: %u) has data for non-supported data type (%u), ignored.", criteria->ID, criteria->requiredType, dataType); + TC_LOG_ERROR("sql.sql", "Table `achievement_criteria_data` (Entry: %u Type: %u) contains data of a non-supported data type (%u), ignored.", criteria->ID, criteria->requiredType, dataType); return false; } } @@ -377,14 +377,14 @@ bool AchievementCriteriaData::Meets(uint32 criteria_id, Player const* source, Un Map* map = source->GetMap(); if (!map->IsDungeon()) { - TC_LOG_ERROR("achievement", "Achievement system call ACHIEVEMENT_CRITERIA_DATA_TYPE_INSTANCE_SCRIPT (%u) for achievement criteria %u for non-dungeon/non-raid map %u", + TC_LOG_ERROR("achievement", "Achievement system call ACHIEVEMENT_CRITERIA_DATA_TYPE_INSTANCE_SCRIPT (%u) for achievement criteria %u in a non-dungeon/non-raid map %u", dataType, criteria_id, map->GetId()); return false; } InstanceScript* instance = map->ToInstanceMap()->GetInstanceScript(); if (!instance) { - TC_LOG_ERROR("achievement", "Achievement system call ACHIEVEMENT_CRITERIA_DATA_TYPE_INSTANCE_SCRIPT (%u) for achievement criteria %u for map %u but map does not have a instance script", + TC_LOG_ERROR("achievement", "Achievement system call ACHIEVEMENT_CRITERIA_DATA_TYPE_INSTANCE_SCRIPT (%u) for achievement criteria %u in map %u, but the map does not have an instance script.", dataType, criteria_id, map->GetId()); return false; } @@ -601,8 +601,8 @@ void AchievementMgr::LoadFromDB(PreparedQueryResult achievementResult, PreparedQ AchievementCriteriaEntry const* criteria = sAchievementMgr->GetAchievementCriteria(id); if (!criteria) { - // we will remove not existed criteria for all characters - TC_LOG_ERROR("achievement", "Non-existing achievement criteria %u data removed from table `character_achievement_progress`.", id); + // Removing non-existing criteria data for all characters + TC_LOG_ERROR("achievement", "Non-existing achievement criteria %u data has been removed from the table `character_achievement_progress`.", id); PreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_DEL_INVALID_ACHIEV_PROGRESS_CRITERIA); @@ -1066,7 +1066,7 @@ void AchievementMgr::UpdateAchievementCriteria(AchievementCriteriaTypes type, ui break; } - // std case: not exist in DBC, not triggered in code as result + // std case: does not exist in DBC, not triggered in code as result case ACHIEVEMENT_CRITERIA_TYPE_HIGHEST_HEALTH: case ACHIEVEMENT_CRITERIA_TYPE_HIGHEST_SPELLPOWER: case ACHIEVEMENT_CRITERIA_TYPE_HIGHEST_ARMOR: @@ -1404,7 +1404,7 @@ void AchievementMgr::SetCriteriaProgress(AchievementCriteriaEntry const* entry, if (entry->timeLimit) { - // has to exist else we wouldn't be here + // has to exist, otherwise we wouldn't be here timedCompleted = IsCompletedCriteria(entry, sAchievementMgr->GetAchievement(entry->referredAchievement)); // Client expects this in packet timeElapsed = entry->timeLimit - (timedIter->second/IN_MILLISECONDS); @@ -1655,14 +1655,14 @@ bool AchievementMgr::CanUpdateCriteria(AchievementCriteriaEntry const* criteria, if (!RequirementsSatisfied(criteria, achievement, miscValue1, miscValue2, unit)) { - TC_LOG_TRACE("achievement", "CanUpdateCriteria: (Id: %u Type %s) Requirements not satisfied", + TC_LOG_TRACE("achievement", "CanUpdateCriteria: (Id: %u Type %s) Requirements have not been satisfied", criteria->ID, AchievementGlobalMgr::GetCriteriaTypeString(criteria->requiredType)); return false; } if (!ConditionsSatisfied(criteria)) { - TC_LOG_TRACE("achievement", "CanUpdateCriteria: (Id: %u Type %s) Conditions not satisfied", + TC_LOG_TRACE("achievement", "CanUpdateCriteria: (Id: %u Type %s) Conditions have not been satisfied", criteria->ID, AchievementGlobalMgr::GetCriteriaTypeString(criteria->requiredType)); return false; } @@ -1905,17 +1905,15 @@ bool AchievementMgr::RequirementsSatisfied(AchievementCriteriaEntry const* achie bool matchFound = false; for (int j = 0; j < MAX_WORLD_MAP_OVERLAY_AREA_IDX; ++j) { - uint32 area_id = worldOverlayEntry->areatableID[j]; - if (!area_id) // array have 0 only in empty tail + AreaTableEntry const* area = sAreaTableStore.LookupEntry(worldOverlayEntry->areatableID[j]); + if (!area) break; - int32 exploreFlag = GetAreaFlagByAreaID(area_id); - if (exploreFlag < 0) + uint32 playerIndexOffset = uint32(area->exploreFlag) / 32; + if (playerIndexOffset >= PLAYER_EXPLORED_ZONES_SIZE) continue; - uint32 playerIndexOffset = uint32(exploreFlag) / 32; - uint32 mask = 1 << (uint32(exploreFlag) % 32); - + uint32 mask = 1 << (uint32(area->exploreFlag) % 32); if (GetPlayer()->GetUInt32Value(PLAYER_EXPLORED_ZONES_1 + playerIndexOffset) & mask) { matchFound = true; @@ -2275,7 +2273,7 @@ void AchievementGlobalMgr::LoadAchievementCriteriaList() ++loaded; } - TC_LOG_INFO("server.loading", ">> Loaded %u achievement criteria in %u ms", loaded, GetMSTimeDiffToNow(oldMSTime)); + TC_LOG_INFO("server.loading", ">> Loaded %u achievement criteria in %u ms.", loaded, GetMSTimeDiffToNow(oldMSTime)); } void AchievementGlobalMgr::LoadAchievementReferenceList() @@ -2304,7 +2302,7 @@ void AchievementGlobalMgr::LoadAchievementReferenceList() if (AchievementEntry const* achievement = sAchievementMgr->GetAchievement(4539)) const_cast<AchievementEntry*>(achievement)->mapID = 631; // Correct map requirement (currently has Ulduar) - TC_LOG_INFO("server.loading", ">> Loaded %u achievement references in %u ms", count, GetMSTimeDiffToNow(oldMSTime)); + TC_LOG_INFO("server.loading", ">> Loaded %u achievement references in %u ms.", count, GetMSTimeDiffToNow(oldMSTime)); } void AchievementGlobalMgr::LoadAchievementCriteriaData() @@ -2332,7 +2330,7 @@ void AchievementGlobalMgr::LoadAchievementCriteriaData() if (!criteria) { - TC_LOG_ERROR("sql.sql", "Table `achievement_criteria_data` has data for non-existing criteria (Entry: %u), ignore.", criteria_id); + TC_LOG_ERROR("sql.sql", "Table `achievement_criteria_data` contains data for non-existing criteria (Entry: %u). Ignored.", criteria_id); continue; } @@ -2342,7 +2340,7 @@ void AchievementGlobalMgr::LoadAchievementCriteriaData() if (scriptName.length()) // not empty { if (dataType != ACHIEVEMENT_CRITERIA_DATA_TYPE_SCRIPT) - TC_LOG_ERROR("sql.sql", "Table `achievement_criteria_data` has ScriptName set for non-scripted data type (Entry: %u, type %u), useless data.", criteria_id, dataType); + TC_LOG_ERROR("sql.sql", "Table `achievement_criteria_data` contains a ScriptName for non-scripted data type (Entry: %u, type %u), useless data.", criteria_id, dataType); else scriptId = sObjectMgr->GetScriptId(scriptName); } @@ -2398,7 +2396,7 @@ void AchievementGlobalMgr::LoadAchievementCriteriaData() if (!achievement) continue; - // exist many achievements with this criteria, use at this moment hardcoded check to skil simple case + // There are many achievements with these criteria, use hardcoded check at this moment to pick a simple case if (achievement->ID == 1282) break; @@ -2435,7 +2433,7 @@ void AchievementGlobalMgr::LoadAchievementCriteriaData() } if (!GetCriteriaDataSet(criteria) && !DisableMgr::IsDisabledFor(DISABLE_TYPE_ACHIEVEMENT_CRITERIA, entryId, NULL)) - TC_LOG_ERROR("sql.sql", "Table `achievement_criteria_data` does not have expected data for criteria (Entry: %u Type: %u) for achievement %u.", criteria->ID, criteria->requiredType, criteria->referredAchievement); + TC_LOG_ERROR("sql.sql", "Table `achievement_criteria_data` does not contain expected data for criteria (Entry: %u Type: %u) for achievement %u.", criteria->ID, criteria->requiredType, criteria->referredAchievement); } TC_LOG_INFO("server.loading", ">> Loaded %u additional achievement criteria data in %u ms", count, GetMSTimeDiffToNow(oldMSTime)); @@ -2461,8 +2459,8 @@ void AchievementGlobalMgr::LoadCompletedAchievements() const AchievementEntry* achievement = sAchievementMgr->GetAchievement(achievementId); if (!achievement) { - // Remove non existent achievements from all characters - TC_LOG_ERROR("achievement", "Non-existing achievement %u data removed from table `character_achievement`.", achievementId); + // Remove non-existing achievements from all characters + TC_LOG_ERROR("achievement", "Non-existing achievement %u data has been removed from the table `character_achievement`.", achievementId); PreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_DEL_INVALID_ACHIEVMENT); stmt->setUInt16(0, uint16(achievementId)); @@ -2475,7 +2473,7 @@ void AchievementGlobalMgr::LoadCompletedAchievements() } while (result->NextRow()); - TC_LOG_INFO("server.loading", ">> Loaded %lu realm first completed achievements in %u ms", (unsigned long)m_allCompletedAchievements.size(), GetMSTimeDiffToNow(oldMSTime)); + TC_LOG_INFO("server.loading", ">> Loaded %lu realm first completed achievements in %u ms.", (unsigned long)m_allCompletedAchievements.size(), GetMSTimeDiffToNow(oldMSTime)); } void AchievementGlobalMgr::LoadRewards() @@ -2502,7 +2500,7 @@ void AchievementGlobalMgr::LoadRewards() AchievementEntry const* achievement = GetAchievement(entry); if (!achievement) { - TC_LOG_ERROR("sql.sql", "Table `achievement_reward` has wrong achievement (Entry: %u), ignored.", entry); + TC_LOG_ERROR("sql.sql", "Table `achievement_reward` contains a wrong achievement entry (Entry: %u), ignored.", entry); continue; } @@ -2518,19 +2516,19 @@ void AchievementGlobalMgr::LoadRewards() // must be title or mail at least if (!reward.titleId[0] && !reward.titleId[1] && !reward.sender) { - TC_LOG_ERROR("sql.sql", "Table `achievement_reward` (Entry: %u) does not have title or item reward data, ignored.", entry); + TC_LOG_ERROR("sql.sql", "Table `achievement_reward` (Entry: %u) does not contain title or item reward data. Ignored.", entry); continue; } if (achievement->requiredFaction == ACHIEVEMENT_FACTION_ANY && (!reward.titleId[0] ^ !reward.titleId[1])) - TC_LOG_ERROR("sql.sql", "Table `achievement_reward` (Entry: %u) has title (A: %u H: %u) for only one team.", entry, reward.titleId[0], reward.titleId[1]); + TC_LOG_ERROR("sql.sql", "Table `achievement_reward` (Entry: %u) contains the title (A: %u H: %u) for only one team.", entry, reward.titleId[0], reward.titleId[1]); if (reward.titleId[0]) { CharTitlesEntry const* titleEntry = sCharTitlesStore.LookupEntry(reward.titleId[0]); if (!titleEntry) { - TC_LOG_ERROR("sql.sql", "Table `achievement_reward` (Entry: %u) has invalid title id (%u) in `title_A`, set to 0", entry, reward.titleId[0]); + TC_LOG_ERROR("sql.sql", "Table `achievement_reward` (Entry: %u) contains an invalid title id (%u) in `title_A`, set to 0", entry, reward.titleId[0]); reward.titleId[0] = 0; } } @@ -2540,7 +2538,7 @@ void AchievementGlobalMgr::LoadRewards() CharTitlesEntry const* titleEntry = sCharTitlesStore.LookupEntry(reward.titleId[1]); if (!titleEntry) { - TC_LOG_ERROR("sql.sql", "Table `achievement_reward` (Entry: %u) has invalid title id (%u) in `title_H`, set to 0", entry, reward.titleId[1]); + TC_LOG_ERROR("sql.sql", "Table `achievement_reward` (Entry: %u) contains an invalid title id (%u) in `title_H`, set to 0", entry, reward.titleId[1]); reward.titleId[1] = 0; } } @@ -2550,41 +2548,41 @@ void AchievementGlobalMgr::LoadRewards() { if (!sObjectMgr->GetCreatureTemplate(reward.sender)) { - TC_LOG_ERROR("sql.sql", "Table `achievement_reward` (Entry: %u) has invalid creature entry %u as sender, mail reward skipped.", entry, reward.sender); + TC_LOG_ERROR("sql.sql", "Table `achievement_reward` (Entry: %u) contains an invalid creature entry %u as sender, mail reward skipped.", entry, reward.sender); reward.sender = 0; } } else { if (reward.itemId) - TC_LOG_ERROR("sql.sql", "Table `achievement_reward` (Entry: %u) does not have sender data but has item reward, item will not be rewarded.", entry); + TC_LOG_ERROR("sql.sql", "Table `achievement_reward` (Entry: %u) does not have sender data, but contains an item reward. Item will not be rewarded.", entry); if (!reward.subject.empty()) - TC_LOG_ERROR("sql.sql", "Table `achievement_reward` (Entry: %u) does not have sender data but has mail subject.", entry); + TC_LOG_ERROR("sql.sql", "Table `achievement_reward` (Entry: %u) does not have sender data, but contains a mail subject.", entry); if (!reward.text.empty()) - TC_LOG_ERROR("sql.sql", "Table `achievement_reward` (Entry: %u) does not have sender data but has mail text.", entry); + TC_LOG_ERROR("sql.sql", "Table `achievement_reward` (Entry: %u) does not have sender data, but contains mail text.", entry); if (reward.mailTemplate) - TC_LOG_ERROR("sql.sql", "Table `achievement_reward` (Entry: %u) does not have sender data but has mailTemplate.", entry); + TC_LOG_ERROR("sql.sql", "Table `achievement_reward` (Entry: %u) does not have sender data, but has a mailTemplate.", entry); } if (reward.mailTemplate) { if (!sMailTemplateStore.LookupEntry(reward.mailTemplate)) { - TC_LOG_ERROR("sql.sql", "Table `achievement_reward` (Entry: %u) has invalid mailTemplate (%u).", entry, reward.mailTemplate); + TC_LOG_ERROR("sql.sql", "Table `achievement_reward` (Entry: %u) is using an invalid mailTemplate (%u).", entry, reward.mailTemplate); reward.mailTemplate = 0; } else if (!reward.subject.empty() || !reward.text.empty()) - TC_LOG_ERROR("sql.sql", "Table `achievement_reward` (Entry: %u) has mailTemplate (%u) and mail subject/text.", entry, reward.mailTemplate); + TC_LOG_ERROR("sql.sql", "Table `achievement_reward` (Entry: %u) is using mailTemplate (%u) and mail subject/text.", entry, reward.mailTemplate); } if (reward.itemId) { if (!sObjectMgr->GetItemTemplate(reward.itemId)) { - TC_LOG_ERROR("sql.sql", "Table `achievement_reward` (Entry: %u) has invalid item id %u, reward mail will not contain item.", entry, reward.itemId); + TC_LOG_ERROR("sql.sql", "Table `achievement_reward` (Entry: %u) contains an invalid item id %u, reward mail will not contain the rewarded item.", entry, reward.itemId); reward.itemId = 0; } } @@ -2594,7 +2592,7 @@ void AchievementGlobalMgr::LoadRewards() } while (result->NextRow()); - TC_LOG_INFO("server.loading", ">> Loaded %u achievement rewards in %u ms", count, GetMSTimeDiffToNow(oldMSTime)); + TC_LOG_INFO("server.loading", ">> Loaded %u achievement rewards in %u ms.", count, GetMSTimeDiffToNow(oldMSTime)); } void AchievementGlobalMgr::LoadRewardLocales() @@ -2609,7 +2607,7 @@ void AchievementGlobalMgr::LoadRewardLocales() if (!result) { - TC_LOG_INFO("server.loading", ">> Loaded 0 achievement reward locale strings. DB table `locales_achievement_reward` is empty"); + TC_LOG_INFO("server.loading", ">> Loaded 0 achievement reward locale strings. DB table `locales_achievement_reward` is empty."); return; } @@ -2621,7 +2619,7 @@ void AchievementGlobalMgr::LoadRewardLocales() if (m_achievementRewards.find(entry) == m_achievementRewards.end()) { - TC_LOG_ERROR("sql.sql", "Table `locales_achievement_reward` (Entry: %u) has locale strings for non-existing achievement reward.", entry); + TC_LOG_ERROR("sql.sql", "Table `locales_achievement_reward` (Entry: %u) contains locale strings for a non-existing achievement reward.", entry); continue; } @@ -2636,7 +2634,7 @@ void AchievementGlobalMgr::LoadRewardLocales() } while (result->NextRow()); - TC_LOG_INFO("server.loading", ">> Loaded %u achievement reward locale strings in %u ms", uint32(m_achievementRewardLocales.size()), GetMSTimeDiffToNow(oldMSTime)); + TC_LOG_INFO("server.loading", ">> Loaded %u achievement reward locale strings in %u ms.", uint32(m_achievementRewardLocales.size()), GetMSTimeDiffToNow(oldMSTime)); } AchievementEntry const* AchievementGlobalMgr::GetAchievement(uint32 achievementId) const diff --git a/src/server/game/Battlefield/Battlefield.cpp b/src/server/game/Battlefield/Battlefield.cpp index 34326d09e2f..e69d0f3085c 100644 --- a/src/server/game/Battlefield/Battlefield.cpp +++ b/src/server/game/Battlefield/Battlefield.cpp @@ -285,7 +285,7 @@ void Battlefield::InitStalker(uint32 entry, Position const& pos) if (Creature* creature = SpawnCreature(entry, pos, TEAM_NEUTRAL)) StalkerGuid = creature->GetGUID(); else - TC_LOG_ERROR("bg.battlefield", "Battlefield::InitStalker: could not spawn Stalker (Creature entry %u), zone messeges will be un-available", entry); + TC_LOG_ERROR("bg.battlefield", "Battlefield::InitStalker: Could not spawn Stalker (Creature entry %u), zone messages will be unavailable!", entry); } void Battlefield::KickAfkPlayers() @@ -544,10 +544,10 @@ BfGraveyard* Battlefield::GetGraveyardById(uint32 id) const if (BfGraveyard* graveyard = m_GraveyardList.at(id)) return graveyard; else - TC_LOG_ERROR("bg.battlefield", "Battlefield::GetGraveyardById Id:%u not existed", id); + TC_LOG_ERROR("bg.battlefield", "Battlefield::GetGraveyardById Id:%u does not exist.", id); } else - TC_LOG_ERROR("bg.battlefield", "Battlefield::GetGraveyardById Id:%u cant be found", id); + TC_LOG_ERROR("bg.battlefield", "Battlefield::GetGraveyardById Id:%u could not be found.", id); return NULL; } @@ -765,7 +765,7 @@ Creature* Battlefield::SpawnCreature(uint32 entry, float x, float y, float z, fl Map* map = sMapMgr->CreateBaseMap(m_MapId); if (!map) { - TC_LOG_ERROR("bg.battlefield", "Battlefield::SpawnCreature: Can't create creature entry: %u map not found", entry); + TC_LOG_ERROR("bg.battlefield", "Battlefield::SpawnCreature: Can't create creature entry: %u, map not found.", entry); return nullptr; } @@ -782,7 +782,7 @@ Creature* Battlefield::SpawnCreature(uint32 entry, float x, float y, float z, fl CreatureTemplate const* cinfo = sObjectMgr->GetCreatureTemplate(entry); if (!cinfo) { - TC_LOG_ERROR("bg.battlefield", "Battlefield::SpawnCreature: entry %u does not exist.", entry); + TC_LOG_ERROR("bg.battlefield", "Battlefield::SpawnCreature: Entry %u does not exist.", entry); return nullptr; } @@ -805,8 +805,8 @@ GameObject* Battlefield::SpawnGameObject(uint32 entry, float x, float y, float z GameObject* go = new GameObject; if (!go->Create(map->GenerateLowGuid<HighGuid::GameObject>(), entry, map, PHASEMASK_NORMAL, x, y, z, o, 0, 0, 0, 0, 100, GO_STATE_READY)) { - TC_LOG_ERROR("bg.battlefield", "Battlefield::SpawnGameObject: Gameobject template %u not found in database! Battlefield not created!", entry); - TC_LOG_ERROR("bg.battlefield", "Battlefield::SpawnGameObject: Cannot create gameobject template %u! Battlefield not created!", entry); + TC_LOG_ERROR("bg.battlefield", "Battlefield::SpawnGameObject: Gameobject template %u could not be found in the database! Battlefield has not been created!", entry); + TC_LOG_ERROR("bg.battlefield", "Battlefield::SpawnGameObject: Could not create gameobject template %u! Battlefield has not been created!", entry); delete go; return NULL; } @@ -907,7 +907,7 @@ bool BfCapturePoint::SetCapturePointData(GameObject* capturePoint) GameObjectTemplate const* goinfo = capturePoint->GetGOInfo(); if (goinfo->type != GAMEOBJECT_TYPE_CAPTURE_POINT) { - TC_LOG_ERROR("misc", "OutdoorPvP: GO %u is not capture point!", capturePoint->GetEntry()); + TC_LOG_ERROR("misc", "OutdoorPvP: GO %u is not a capture point!", capturePoint->GetEntry()); return false; } diff --git a/src/server/game/Battlegrounds/BattlegroundMgr.cpp b/src/server/game/Battlegrounds/BattlegroundMgr.cpp index 062d4702d43..8942ca7a18e 100644 --- a/src/server/game/Battlegrounds/BattlegroundMgr.cpp +++ b/src/server/game/Battlegrounds/BattlegroundMgr.cpp @@ -536,7 +536,7 @@ void BattlegroundMgr::LoadBattlegroundTemplates() BattlemasterListEntry const* bl = sBattlemasterListStore.LookupEntry(bgTypeId); if (!bl) { - TC_LOG_ERROR("bg.battleground", "Battleground ID %u not found in BattlemasterList.dbc. Battleground not created.", bgTypeId); + TC_LOG_ERROR("bg.battleground", "Battleground ID %u could not be found in BattlemasterList.dbc. The battleground was not created.", bgTypeId); continue; } @@ -554,14 +554,14 @@ void BattlegroundMgr::LoadBattlegroundTemplates() if (bgTemplate.MaxPlayersPerTeam == 0 || bgTemplate.MinPlayersPerTeam > bgTemplate.MaxPlayersPerTeam) { - TC_LOG_ERROR("sql.sql", "Table `battleground_template` for id %u has bad values for MinPlayersPerTeam (%u) and MaxPlayersPerTeam(%u)", + TC_LOG_ERROR("sql.sql", "Table `battleground_template` for id %u contains bad values for MinPlayersPerTeam (%u) and MaxPlayersPerTeam(%u).", bgTemplate.Id, bgTemplate.MinPlayersPerTeam, bgTemplate.MaxPlayersPerTeam); continue; } if (bgTemplate.MinLevel == 0 || bgTemplate.MaxLevel == 0 || bgTemplate.MinLevel > bgTemplate.MaxLevel) { - TC_LOG_ERROR("sql.sql", "Table `battleground_template` for id %u has bad values for MinLevel (%u) and MaxLevel (%u)", + TC_LOG_ERROR("sql.sql", "Table `battleground_template` for id %u contains bad values for MinLevel (%u) and MaxLevel (%u).", bgTemplate.Id, bgTemplate.MinLevel, bgTemplate.MaxLevel); continue; } @@ -575,7 +575,7 @@ void BattlegroundMgr::LoadBattlegroundTemplates() } else { - TC_LOG_ERROR("sql.sql", "Table `battleground_template` for id %u has non-existed WorldSafeLocs.dbc id %u in field `AllianceStartLoc`. BG not created.", bgTemplate.Id, startId); + TC_LOG_ERROR("sql.sql", "Table `battleground_template` for id %u contains a non-existing WorldSafeLocs.dbc id %u in field `AllianceStartLoc`. BG not created.", bgTemplate.Id, startId); continue; } @@ -586,7 +586,7 @@ void BattlegroundMgr::LoadBattlegroundTemplates() } else { - TC_LOG_ERROR("sql.sql", "Table `battleground_template` for id %u has non-existed WorldSafeLocs.dbc id %u in field `HordeStartLoc`. BG not created.", bgTemplate.Id, startId); + TC_LOG_ERROR("sql.sql", "Table `battleground_template` for id %u contains a non-existing WorldSafeLocs.dbc id %u in field `HordeStartLoc`. BG not created.", bgTemplate.Id, startId); continue; } } @@ -788,7 +788,7 @@ BattlegroundTypeId BattlegroundMgr::BGTemplateId(BattlegroundQueueTypeId bgQueue case BATTLEGROUND_QUEUE_5v5: return BATTLEGROUND_AA; default: - return BattlegroundTypeId(0); // used for unknown template (it existed and do nothing) + return BattlegroundTypeId(0); // used for unknown template (it exists and does nothing) } } @@ -892,7 +892,7 @@ void BattlegroundMgr::LoadBattleMastersEntry() uint32 bgTypeId = fields[1].GetUInt32(); if (!sBattlemasterListStore.LookupEntry(bgTypeId)) { - TC_LOG_ERROR("sql.sql", "Table `battlemaster_entry` contain entry %u for not existed battleground type %u, ignored.", entry, bgTypeId); + TC_LOG_ERROR("sql.sql", "Table `battlemaster_entry` contains entry %u for a non-existing battleground type %u, ignored.", entry, bgTypeId); continue; } @@ -912,7 +912,7 @@ void BattlegroundMgr::CheckBattleMasters() { if ((itr->second.npcflag & UNIT_NPC_FLAG_BATTLEMASTER) && mBattleMastersMap.find(itr->second.Entry) == mBattleMastersMap.end()) { - TC_LOG_ERROR("sql.sql", "CreatureTemplate (Entry: %u) has UNIT_NPC_FLAG_BATTLEMASTER but no data in `battlemaster_entry` table. Removing flag!", itr->second.Entry); + TC_LOG_ERROR("sql.sql", "Creature_Template Entry: %u has UNIT_NPC_FLAG_BATTLEMASTER, but no data in the `battlemaster_entry` table. Removing flag.", itr->second.Entry); const_cast<CreatureTemplate*>(&itr->second)->npcflag &= ~UNIT_NPC_FLAG_BATTLEMASTER; } } diff --git a/src/server/game/Battlegrounds/Zones/BattlegroundEY.cpp b/src/server/game/Battlegrounds/Zones/BattlegroundEY.cpp index 626bcacbf27..e52106a8efe 100644 --- a/src/server/game/Battlegrounds/Zones/BattlegroundEY.cpp +++ b/src/server/game/Battlegrounds/Zones/BattlegroundEY.cpp @@ -171,7 +171,7 @@ void BattlegroundEY::CheckSomeoneJoinedPoint() Player* player = ObjectAccessor::FindPlayer(m_PlayersNearPoint[EY_POINTS_MAX][j]); if (!player) { - TC_LOG_ERROR("bg.battleground", "BattlegroundEY:CheckSomeoneJoinedPoint: Player (%s) not found!", m_PlayersNearPoint[EY_POINTS_MAX][j].ToString().c_str()); + TC_LOG_ERROR("bg.battleground", "BattlegroundEY:CheckSomeoneJoinedPoint: Player (%s) could not be found!", m_PlayersNearPoint[EY_POINTS_MAX][j].ToString().c_str()); ++j; continue; } @@ -212,8 +212,8 @@ void BattlegroundEY::CheckSomeoneLeftPoint() Player* player = ObjectAccessor::FindPlayer(m_PlayersNearPoint[i][j]); if (!player) { - TC_LOG_ERROR("bg.battleground", "BattlegroundEY:CheckSomeoneLeftPoint Player (%s) not found!", m_PlayersNearPoint[i][j].ToString().c_str()); - //move not existed player to "free space" - this will cause many error showing in log, but it is a very important bug + TC_LOG_ERROR("bg.battleground", "BattlegroundEY:CheckSomeoneLeftPoint Player (%s) could not be found!", m_PlayersNearPoint[i][j].ToString().c_str()); + //move non-existing players to "free space" - this will cause many errors showing in log, but it is a very important bug m_PlayersNearPoint[EY_POINTS_MAX].push_back(m_PlayersNearPoint[i][j]); m_PlayersNearPoint[i].erase(m_PlayersNearPoint[i].begin() + j); continue; @@ -498,7 +498,7 @@ bool BattlegroundEY::SetupBattleground() || !AddObject(BG_EY_OBJECT_TOWER_CAP_MAGE_TOWER, BG_OBJECT_HU_TOWER_CAP_EY_ENTRY, 2282.121582f, 1760.006958f, 1189.707153f, 1.919862f, 0, 0, 0.819152f, 0.573576f, RESPAWN_ONE_DAY) ) { - TC_LOG_ERROR("sql.sql", "BatteGroundEY: Failed to spawn some object Battleground not created!"); + TC_LOG_ERROR("sql.sql", "BatteGroundEY: Failed to spawn some objects. The battleground was not created."); return false; } @@ -515,21 +515,21 @@ bool BattlegroundEY::SetupBattleground() || !AddObject(BG_EY_OBJECT_SPEEDBUFF_FEL_REAVER + i * 3 + 1, Buff_Entries[1], at->x, at->y, at->z, 0.907571f, 0, 0, 0.438371f, 0.898794f, RESPAWN_ONE_DAY) || !AddObject(BG_EY_OBJECT_SPEEDBUFF_FEL_REAVER + i * 3 + 2, Buff_Entries[2], at->x, at->y, at->z, 0.907571f, 0, 0, 0.438371f, 0.898794f, RESPAWN_ONE_DAY) ) - TC_LOG_ERROR("bg.battleground", "BattlegroundEY: Cannot spawn buff"); + TC_LOG_ERROR("bg.battleground", "BattlegroundEY: Could not spawn Speedbuff Fel Reaver."); } WorldSafeLocsEntry const* sg = NULL; sg = sWorldSafeLocsStore.LookupEntry(EY_GRAVEYARD_MAIN_ALLIANCE); if (!sg || !AddSpiritGuide(EY_SPIRIT_MAIN_ALLIANCE, sg->x, sg->y, sg->z, 3.124139f, TEAM_ALLIANCE)) { - TC_LOG_ERROR("sql.sql", "BatteGroundEY: Failed to spawn spirit guide! Battleground not created!"); + TC_LOG_ERROR("sql.sql", "BatteGroundEY: Failed to spawn spirit guide. The battleground was not created."); return false; } sg = sWorldSafeLocsStore.LookupEntry(EY_GRAVEYARD_MAIN_HORDE); if (!sg || !AddSpiritGuide(EY_SPIRIT_MAIN_HORDE, sg->x, sg->y, sg->z, 3.193953f, TEAM_HORDE)) { - TC_LOG_ERROR("sql.sql", "BatteGroundEY: Failed to spawn spirit guide! Battleground not created!"); + TC_LOG_ERROR("sql.sql", "BatteGroundEY: Failed to spawn spirit guide. The battleground was not created."); return false; } @@ -595,7 +595,7 @@ void BattlegroundEY::RespawnFlagAfterDrop() if (obj) obj->Delete(); else - TC_LOG_ERROR("bg.battleground", "BattlegroundEY: Unknown dropped flag (%s)", GetDroppedFlagGUID().ToString().c_str()); + TC_LOG_ERROR("bg.battleground", "BattlegroundEY: Unknown dropped flag (%s).", GetDroppedFlagGUID().ToString().c_str()); SetDroppedFlagGUID(ObjectGuid::Empty); } @@ -767,7 +767,7 @@ void BattlegroundEY::EventTeamCapturedPoint(Player* player, uint32 Point) WorldSafeLocsEntry const* sg = NULL; sg = sWorldSafeLocsStore.LookupEntry(m_CapturingPointTypes[Point].GraveYardId); if (!sg || !AddSpiritGuide(Point, sg->x, sg->y, sg->z, 3.124139f, GetTeamIndexByTeamId(Team))) - TC_LOG_ERROR("bg.battleground", "BatteGroundEY: Failed to spawn spirit guide! point: %u, team: %u, graveyard_id: %u", + TC_LOG_ERROR("bg.battleground", "BatteGroundEY: Failed to spawn spirit guide. point: %u, team: %u, graveyard_id: %u", Point, Team, m_CapturingPointTypes[Point].GraveYardId); // SpawnBGCreature(Point, RESPAWN_IMMEDIATELY); @@ -917,7 +917,7 @@ WorldSafeLocsEntry const* BattlegroundEY::GetClosestGraveYard(Player* player) if (!entry) { - TC_LOG_ERROR("bg.battleground", "BattlegroundEY: Not found the main team graveyard. Graveyard system isn't working!"); + TC_LOG_ERROR("bg.battleground", "BattlegroundEY: The main team graveyard could not be found. The graveyard system will not be operational!"); return NULL; } @@ -934,7 +934,7 @@ WorldSafeLocsEntry const* BattlegroundEY::GetClosestGraveYard(Player* player) { entry = sWorldSafeLocsStore.LookupEntry(m_CapturingPointTypes[i].GraveYardId); if (!entry) - TC_LOG_ERROR("bg.battleground", "BattlegroundEY: Not found graveyard: %u", m_CapturingPointTypes[i].GraveYardId); + TC_LOG_ERROR("bg.battleground", "BattlegroundEY: Graveyard %u could not be found.", m_CapturingPointTypes[i].GraveYardId); else { distance = (entry->x - plr_x)*(entry->x - plr_x) + (entry->y - plr_y)*(entry->y - plr_y) + (entry->z - plr_z)*(entry->z - plr_z); diff --git a/src/server/game/CMakeLists.txt b/src/server/game/CMakeLists.txt index aae5b4874d8..4d41fbc32eb 100644 --- a/src/server/game/CMakeLists.txt +++ b/src/server/game/CMakeLists.txt @@ -108,6 +108,7 @@ include_directories( ${CMAKE_CURRENT_SOURCE_DIR}/Addons ${CMAKE_CURRENT_SOURCE_DIR}/AI ${CMAKE_CURRENT_SOURCE_DIR}/AI/CoreAI + ${CMAKE_CURRENT_SOURCE_DIR}/AI/PlayerAI ${CMAKE_CURRENT_SOURCE_DIR}/AI/ScriptedAI ${CMAKE_CURRENT_SOURCE_DIR}/AI/SmartScripts ${CMAKE_CURRENT_SOURCE_DIR}/AuctionHouse diff --git a/src/server/game/Chat/Chat.cpp b/src/server/game/Chat/Chat.cpp index 011b68a2bb3..aa0f6ce09fc 100644 --- a/src/server/game/Chat/Chat.cpp +++ b/src/server/game/Chat/Chat.cpp @@ -296,11 +296,11 @@ bool ChatHandler::ExecuteCommandInTable(std::vector<ChatCommand> const& table, c uint32 areaId = player->GetAreaId(); std::string areaName = "Unknown"; std::string zoneName = "Unknown"; - if (AreaTableEntry const* area = GetAreaEntryByAreaID(areaId)) + if (AreaTableEntry const* area = sAreaTableStore.LookupEntry(areaId)) { int locale = GetSessionDbcLocale(); areaName = area->area_name[locale]; - if (AreaTableEntry const* zone = GetAreaEntryByAreaID(area->zone)) + if (AreaTableEntry const* zone = sAreaTableStore.LookupEntry(area->zone)) zoneName = zone->area_name[locale]; } @@ -360,7 +360,7 @@ bool ChatHandler::SetDataForCommandInTable(std::vector<ChatCommand>& table, char // expected subcommand by full name DB content else if (*text) { - TC_LOG_ERROR("sql.sql", "Table `command` have unexpected subcommand '%s' in command '%s', skip.", text, fullcommand.c_str()); + TC_LOG_ERROR("sql.sql", "Table `command` contains an unexpected subcommand '%s' in command '%s', skipped.", text, fullcommand.c_str()); return false; } @@ -376,9 +376,9 @@ bool ChatHandler::SetDataForCommandInTable(std::vector<ChatCommand>& table, char if (!cmd.empty()) { if (&table == &getCommandTable()) - TC_LOG_ERROR("sql.sql", "Table `command` have not existed command '%s', skip.", cmd.c_str()); + TC_LOG_ERROR("sql.sql", "Table `command` contains a non-existing command '%s', skipped.", cmd.c_str()); else - TC_LOG_ERROR("sql.sql", "Table `command` have not existed subcommand '%s' in command '%s', skip.", cmd.c_str(), fullcommand.c_str()); + TC_LOG_ERROR("sql.sql", "Table `command` contains a non-existing subcommand '%s' in command '%s', skipped.", cmd.c_str(), fullcommand.c_str()); } return false; @@ -486,7 +486,7 @@ bool ChatHandler::ShowHelpForSubCommands(std::vector<ChatCommand> const& table, std::string list; for (uint32 i = 0; i < table.size(); ++i) { - // must be available (ignore handler existence for show command with possible available subcommands) + // must be available (ignore handler existence to show command with possible available subcommands) if (!isAvailable(table[i])) continue; @@ -525,7 +525,7 @@ bool ChatHandler::ShowHelpForCommand(std::vector<ChatCommand> const& table, cons { for (uint32 i = 0; i < table.size(); ++i) { - // must be available (ignore handler existence for show command with possible available subcommands) + // must be available (ignore handler existence to show command with possible available subcommands) if (!isAvailable(table[i])) continue; @@ -555,7 +555,7 @@ bool ChatHandler::ShowHelpForCommand(std::vector<ChatCommand> const& table, cons { for (uint32 i = 0; i < table.size(); ++i) { - // must be available (ignore handler existence for show command with possible available subcommands) + // must be available (ignore handler existence to show command with possible available subcommands) if (!isAvailable(table[i])) continue; @@ -1100,7 +1100,7 @@ bool ChatHandler::extractPlayerTarget(char* args, Player** player, ObjectGuid* p *player_name = pl ? pl->GetName() : ""; } - // some from req. data must be provided (note: name is empty if player not exist) + // some from req. data must be provided (note: name is empty if player does not exist) if ((!player || !*player) && (!player_guid || !*player_guid) && (!player_name || player_name->empty())) { SendSysMessage(LANG_PLAYER_NOT_FOUND); diff --git a/src/server/game/Combat/ThreatManager.cpp b/src/server/game/Combat/ThreatManager.cpp index 588e7b1a93b..9767d69e2aa 100644 --- a/src/server/game/Combat/ThreatManager.cpp +++ b/src/server/game/Combat/ThreatManager.cpp @@ -335,7 +335,7 @@ HostileReference* ThreatContainer::selectNextVictim(Creature* attacker, HostileR { // current victim is a second choice target, so don't compare threat with it below if (currentRef == currentVictim) - currentVictim = NULL; + currentVictim = nullptr; ++iter; continue; } @@ -437,12 +437,15 @@ void ThreatManager::_addThreat(Unit* victim, float threat) if (!ref) // there was no ref => create a new one { + bool isFirst = iThreatContainer.empty(); // threat has to be 0 here HostileReference* hostileRef = new HostileReference(victim, this, 0); iThreatContainer.addReference(hostileRef); hostileRef->addThreat(threat); // now we add the real threat if (victim->GetTypeId() == TYPEID_PLAYER && victim->ToPlayer()->IsGameMaster()) hostileRef->setOnlineOfflineState(false); // GM is always offline + else if (isFirst) + setCurrentVictim(hostileRef); } } diff --git a/src/server/game/Combat/ThreatManager.h b/src/server/game/Combat/ThreatManager.h index 7d20e99c128..0f4efdbeab9 100644 --- a/src/server/game/Combat/ThreatManager.h +++ b/src/server/game/Combat/ThreatManager.h @@ -169,7 +169,7 @@ class ThreatContainer HostileReference* getMostHated() const { - return iThreatList.empty() ? NULL : iThreatList.front(); + return iThreatList.empty() ? nullptr : iThreatList.front(); } HostileReference* getReferenceByTarget(Unit* victim) const; diff --git a/src/server/game/Conditions/ConditionMgr.cpp b/src/server/game/Conditions/ConditionMgr.cpp index d5367e919a3..6da83aad1a8 100644 --- a/src/server/game/Conditions/ConditionMgr.cpp +++ b/src/server/game/Conditions/ConditionMgr.cpp @@ -55,7 +55,8 @@ char const* const ConditionMgr::StaticSourceTypeData[CONDITION_SOURCE_TYPE_MAX] "SmartScript", "Npc Vendor", "Spell Proc", - "Phase Def" + "Terrain Swap", + "Phase" }; ConditionMgr::ConditionTypeInfo const ConditionMgr::StaticConditionTypeData[CONDITION_MAX] = @@ -100,7 +101,9 @@ ConditionMgr::ConditionTypeInfo const ConditionMgr::StaticConditionTypeData[COND { "Health Value", true, true, false }, { "Health Pct", true, true, false }, { "Realm Achievement", true, false, false }, - { "In Water", false, false, false } + { "In Water", false, false, false }, + { "Terrain Swap", false, false, false }, + { "Sit/stand state", true, true, false } }; // Checks if object meets the condition @@ -432,6 +435,19 @@ bool Condition::Meets(ConditionSourceInfo& sourceInfo) const condMeets = unit->IsInWater(); break; } + case CONDITION_STAND_STATE: + { + if (Unit* unit = object->ToUnit()) + { + if (ConditionValue1 == 0) + condMeets = (unit->getStandState() == ConditionValue2); + else if (ConditionValue2 == 0) + condMeets = unit->IsStandState(); + else if (ConditionValue2 == 1) + condMeets = unit->IsSitState(); + } + break; + } default: condMeets = false; break; @@ -602,6 +618,9 @@ uint32 Condition::GetSearcherTypeMaskForCondition() const case CONDITION_IN_WATER: mask |= GRID_MAP_TYPE_MASK_CREATURE | GRID_MAP_TYPE_MASK_PLAYER; break; + case CONDITION_STAND_STATE: + mask |= GRID_MAP_TYPE_MASK_CREATURE | GRID_MAP_TYPE_MASK_PLAYER; + break; default: ASSERT(false && "Condition::GetSearcherTypeMaskForCondition - missing condition handling!"); break; @@ -1633,9 +1652,14 @@ bool ConditionMgr::isSourceTypeValid(Condition* cond) const } break; } - case CONDITION_SOURCE_TYPE_PHASE_DEFINITION: + case CONDITION_SOURCE_TYPE_TERRAIN_SWAP: + { + TC_LOG_ERROR("sql.sql", "CONDITION_SOURCE_TYPE_TERRAIN_SWAP: is only for 6.x branch, skipped"); + return false; + } + case CONDITION_SOURCE_TYPE_PHASE: { - TC_LOG_ERROR("sql.sql", "CONDITION_SOURCE_TYPE_PHASE_DEFINITION:: is only for 4.3.4 branch, skipped"); + TC_LOG_ERROR("sql.sql", "CONDITION_SOURCE_TYPE_PHASE: is only for 6.x branch, skipped"); return false; } case CONDITION_SOURCE_TYPE_GOSSIP_MENU: @@ -1653,7 +1677,7 @@ bool ConditionMgr::isConditionTypeValid(Condition* cond) const { if (cond->ConditionType == CONDITION_NONE || cond->ConditionType >= CONDITION_MAX) { - TC_LOG_ERROR("sql.sql", "%s Invalid ConditionType in `condition` table, ignoring.", cond->ToString().c_str()); + TC_LOG_ERROR("sql.sql", "%s Invalid ConditionType in `condition` table, ignoring.", cond->ToString(true).c_str()); return false; } @@ -1708,7 +1732,7 @@ bool ConditionMgr::isConditionTypeValid(Condition* cond) const } case CONDITION_ZONEID: { - AreaTableEntry const* areaEntry = GetAreaEntryByAreaID(cond->ConditionValue1); + AreaTableEntry const* areaEntry = sAreaTableStore.LookupEntry(cond->ConditionValue1); if (!areaEntry) { TC_LOG_ERROR("sql.sql", "%s Area (%u) does not exist, skipped.", cond->ToString(true).c_str(), cond->ConditionValue1); @@ -2090,6 +2114,31 @@ bool ConditionMgr::isConditionTypeValid(Condition* cond) const } case CONDITION_IN_WATER: break; + case CONDITION_TERRAIN_SWAP: + TC_LOG_ERROR("sql.sql", "%s is not valid for this branch, skipped.", cond->ToString(true).c_str()); + return false; + case CONDITION_STAND_STATE: + { + bool valid = false; + switch (cond->ConditionValue1) + { + case 0: + valid = cond->ConditionValue2 <= UNIT_STAND_STATE_SUBMERGED; + break; + case 1: + valid = cond->ConditionValue2 <= 1; + break; + default: + valid = false; + break; + } + if (!valid) + { + TC_LOG_ERROR("sql.sql", "%s has non-existing stand state (%u,%u), skipped.", cond->ToString(true).c_str(), cond->ConditionValue1, cond->ConditionValue2); + return false; + } + break; + } default: break; } diff --git a/src/server/game/Conditions/ConditionMgr.h b/src/server/game/Conditions/ConditionMgr.h index 35096ae18ff..7dc4592a6a9 100644 --- a/src/server/game/Conditions/ConditionMgr.h +++ b/src/server/game/Conditions/ConditionMgr.h @@ -71,7 +71,9 @@ enum ConditionTypes CONDITION_HP_PCT = 38, // hpPct ComparisonType 0 true if unit's hp matches given pct CONDITION_REALM_ACHIEVEMENT = 39, // achievement_id 0 0 true if realm achievement is complete CONDITION_IN_WATER = 40, // 0 0 0 true if unit in water - CONDITION_MAX = 41 // MAX + CONDITION_TERRAIN_SWAP = 41, // only for 6.x + CONDITION_STAND_STATE = 42, // stateType state 0 true if unit matches specified sitstate (0,x: has exactly state x; 1,0: any standing state; 1,1: any sitting state;) + CONDITION_MAX = 43 // MAX }; /*! Documentation on implementing a new ConditionSourceType: @@ -128,8 +130,9 @@ enum ConditionSourceType CONDITION_SOURCE_TYPE_SMART_EVENT = 22, CONDITION_SOURCE_TYPE_NPC_VENDOR = 23, CONDITION_SOURCE_TYPE_SPELL_PROC = 24, - CONDITION_SOURCE_TYPE_PHASE_DEFINITION = 25, // only 4.3.4 - CONDITION_SOURCE_TYPE_MAX = 26 // MAX + CONDITION_SOURCE_TYPE_TERRAIN_SWAP = 25, // only 6.x + CONDITION_SOURCE_TYPE_PHASE = 26, // only 6.x + CONDITION_SOURCE_TYPE_MAX = 27 // MAX }; enum RelationType diff --git a/src/server/game/DataStores/DBCStores.cpp b/src/server/game/DataStores/DBCStores.cpp index c73350872cc..6c51c71fe7b 100644 --- a/src/server/game/DataStores/DBCStores.cpp +++ b/src/server/game/DataStores/DBCStores.cpp @@ -51,11 +51,9 @@ struct WMOAreaTableTripple typedef std::map<WMOAreaTableTripple, WMOAreaTableEntry const*> WMOAreaInfoByTripple; typedef std::multimap<uint32, CharSectionsEntry const*> CharSectionsMap; -DBCStorage <AreaTableEntry> sAreaStore(AreaTableEntryfmt); +DBCStorage <AreaTableEntry> sAreaTableStore(AreaTableEntryfmt); DBCStorage <AreaGroupEntry> sAreaGroupStore(AreaGroupEntryfmt); DBCStorage <AreaPOIEntry> sAreaPOIStore(AreaPOIEntryfmt); -static AreaFlagByAreaID sAreaFlagByAreaID; -static AreaFlagByMapID sAreaFlagByMapID; // for instances without generated *.map files static WMOAreaInfoByTripple sWMOAreaInfoByTripple; @@ -286,21 +284,7 @@ void LoadDBCStores(const std::string& dataPath) StoreProblemList bad_dbc_files; uint32 availableDbcLocales = 0xFFFFFFFF; - LoadDBC(availableDbcLocales, bad_dbc_files, sAreaStore, dbcPath, "AreaTable.dbc"); - - // must be after sAreaStore loading - for (uint32 i = 0; i < sAreaStore.GetNumRows(); ++i) // areaflag numbered from 0 - { - if (AreaTableEntry const* area = sAreaStore.LookupEntry(i)) - { - // fill AreaId->DBC records - sAreaFlagByAreaID.insert(AreaFlagByAreaID::value_type(uint16(area->ID), area->exploreFlag)); - - // fill MapId->DBC records (skip sub zones and continents) - if (area->zone == 0 && area->mapid != 0 && area->mapid != 1 && area->mapid != 530 && area->mapid != 571) - sAreaFlagByMapID.insert(AreaFlagByMapID::value_type(area->mapid, area->exploreFlag)); - } - } + LoadDBC(availableDbcLocales, bad_dbc_files, sAreaTableStore, dbcPath, "AreaTable.dbc"); LoadDBC(availableDbcLocales, bad_dbc_files, sAchievementStore, dbcPath, "Achievement.dbc", &CustomAchievementfmt, &CustomAchievementIndex); LoadDBC(availableDbcLocales, bad_dbc_files, sAchievementCriteriaStore, dbcPath, "Achievement_Criteria.dbc"); @@ -721,7 +705,7 @@ void LoadDBCStores(const std::string& dataPath) } // Check loaded DBC files proper version - if (!sAreaStore.LookupEntry(3617) || // last area (areaflag) added in 3.3.5a + if (!sAreaTableStore.LookupEntry(4987) || // last area added in 3.3.5a !sCharTitlesStore.LookupEntry(177) || // last char title added in 3.3.5a !sGemPropertiesStore.LookupEntry(1629) || // last added spell in 3.3.5a !sItemStore.LookupEntry(56806) || // last gem property added in 3.3.5a @@ -773,41 +757,13 @@ uint32 GetTalentSpellCost(uint32 spellId) return 0; } -int32 GetAreaFlagByAreaID(uint32 area_id) -{ - AreaFlagByAreaID::iterator i = sAreaFlagByAreaID.find(area_id); - if (i == sAreaFlagByAreaID.end()) - return -1; - - return i->second; -} WMOAreaTableEntry const* GetWMOAreaTableEntryByTripple(int32 rootid, int32 adtid, int32 groupid) { WMOAreaInfoByTripple::iterator i = sWMOAreaInfoByTripple.find(WMOAreaTableTripple(rootid, adtid, groupid)); - if (i == sWMOAreaInfoByTripple.end()) - return NULL; - return i->second; -} - -AreaTableEntry const* GetAreaEntryByAreaID(uint32 area_id) -{ - int32 areaflag = GetAreaFlagByAreaID(area_id); - if (areaflag < 0) + if (i == sWMOAreaInfoByTripple.end()) return NULL; - - return sAreaStore.LookupEntry(areaflag); -} - -AreaTableEntry const* GetAreaEntryByAreaFlagAndMap(uint32 area_flag, uint32 map_id) -{ - if (area_flag) - return sAreaStore.LookupEntry(area_flag); - - if (MapEntry const* mapEntry = sMapStore.LookupEntry(map_id)) - return GetAreaEntryByAreaID(mapEntry->linked_zone); - - return NULL; + return i->second; } char const* GetRaceName(uint8 race, uint8 locale) @@ -822,15 +778,6 @@ char const* GetClassName(uint8 class_, uint8 locale) return classEntry ? classEntry->name[locale] : NULL; } -uint32 GetAreaFlagByMapId(uint32 mapid) -{ - AreaFlagByMapID::iterator i = sAreaFlagByMapID.find(mapid); - if (i == sAreaFlagByMapID.end()) - return 0; - else - return i->second; -} - uint32 GetVirtualMapForMapAndZone(uint32 mapid, uint32 zoneId) { if (mapid != 530 && mapid != 571) // speed for most cases diff --git a/src/server/game/DataStores/DBCStores.h b/src/server/game/DataStores/DBCStores.h index 14f59b04e6d..56ee1f618dd 100644 --- a/src/server/game/DataStores/DBCStores.h +++ b/src/server/game/DataStores/DBCStores.h @@ -33,11 +33,6 @@ char* GetPetName(uint32 petfamily, uint32 dbclang); uint32 GetTalentSpellCost(uint32 spellId); TalentSpellPos const* GetTalentSpellPos(uint32 spellId); -int32 GetAreaFlagByAreaID(uint32 area_id); // -1 if not found -AreaTableEntry const* GetAreaEntryByAreaID(uint32 area_id); -AreaTableEntry const* GetAreaEntryByAreaFlagAndMap(uint32 area_flag, uint32 map_id); -uint32 GetAreaFlagByMapId(uint32 mapid); - char const* GetRaceName(uint8 race, uint8 locale); char const* GetClassName(uint8 class_, uint8 locale); @@ -86,7 +81,7 @@ EmotesTextSoundEntry const* FindTextSoundEmoteFor(uint32 emote, uint32 race, uin extern DBCStorage <AchievementEntry> sAchievementStore; extern DBCStorage <AchievementCriteriaEntry> sAchievementCriteriaStore; -extern DBCStorage <AreaTableEntry> sAreaStore;// recommend access using functions +extern DBCStorage <AreaTableEntry> sAreaTableStore; extern DBCStorage <AreaGroupEntry> sAreaGroupStore; extern DBCStorage <AreaPOIEntry> sAreaPOIStore; extern DBCStorage <AreaTriggerEntry> sAreaTriggerStore; diff --git a/src/server/game/DataStores/DBCStructure.h b/src/server/game/DataStores/DBCStructure.h index 2f4820d0353..b5dc4489148 100644 --- a/src/server/game/DataStores/DBCStructure.h +++ b/src/server/game/DataStores/DBCStructure.h @@ -509,7 +509,7 @@ struct AreaTableEntry uint32 ID; // 0 uint32 mapid; // 1 uint32 zone; // 2 if 0 then it's zone, else it's zone id of this area - uint32 exploreFlag; // 3, main index + uint32 exploreFlag; // 3 uint32 flags; // 4, unknown value but 312 for all cities // 5-9 unused int32 area_level; // 10 diff --git a/src/server/game/DataStores/DBCfmt.h b/src/server/game/DataStores/DBCfmt.h index 22a01dae9f0..c61ec997bc2 100644 --- a/src/server/game/DataStores/DBCfmt.h +++ b/src/server/game/DataStores/DBCfmt.h @@ -23,7 +23,7 @@ char const Achievementfmt[] = "niixssssssssssssssssxxxxxxxxxxxxxxxxxxiixixxxxxxx const std::string CustomAchievementfmt = "pppaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaapapaaaaaaaaaaaaaaaaaapp"; const std::string CustomAchievementIndex = "ID"; char const AchievementCriteriafmt[] = "niiiiiiiixxxxxxxxxxxxxxxxxiiiix"; -char const AreaTableEntryfmt[] = "iiinixxxxxissssssssssssssssxiiiiixxx"; +char const AreaTableEntryfmt[] = "niiiixxxxxissssssssssssssssxiiiiixxx"; char const AreaGroupEntryfmt[] = "niiiiiii"; char const AreaPOIEntryfmt[] = "niiiiiiiiiiifffixixxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxix"; char const AreaTriggerEntryfmt[] = "niffffffff"; diff --git a/src/server/game/Entities/Corpse/Corpse.cpp b/src/server/game/Entities/Corpse/Corpse.cpp index 8f700cc636f..22bb9bca712 100644 --- a/src/server/game/Entities/Corpse/Corpse.cpp +++ b/src/server/game/Entities/Corpse/Corpse.cpp @@ -147,7 +147,7 @@ bool Corpse::LoadCorpseFromDB(ObjectGuid::LowType guid, Field* fields) SetObjectScale(1.0f); SetUInt32Value(CORPSE_FIELD_DISPLAY_ID, fields[5].GetUInt32()); - _LoadIntoDataField(fields[6].GetCString(), CORPSE_FIELD_ITEM, EQUIPMENT_SLOT_END); + _LoadIntoDataField(fields[6].GetString(), CORPSE_FIELD_ITEM, EQUIPMENT_SLOT_END); SetUInt32Value(CORPSE_FIELD_BYTES_1, fields[7].GetUInt32()); SetUInt32Value(CORPSE_FIELD_BYTES_2, fields[8].GetUInt32()); SetUInt32Value(CORPSE_FIELD_GUILD, fields[9].GetUInt32()); diff --git a/src/server/game/Entities/Creature/Creature.cpp b/src/server/game/Entities/Creature/Creature.cpp index 8711cd1a5f5..9562f8424c1 100644 --- a/src/server/game/Entities/Creature/Creature.cpp +++ b/src/server/game/Entities/Creature/Creature.cpp @@ -578,7 +578,8 @@ void Creature::Update(uint32 diff) IsAIEnabled = true; if (!IsInEvadeMode() && LastCharmerGUID) if (Unit* charmer = ObjectAccessor::GetUnit(*this, LastCharmerGUID)) - i_AI->AttackStart(charmer); + if (CanStartAttack(charmer, true)) + i_AI->AttackStart(charmer); LastCharmerGUID.Clear(); } @@ -2149,6 +2150,11 @@ bool Creature::CanCreatureAttack(Unit const* victim, bool /*force*/) const if (GetMap()->IsDungeon()) return true; + // if the mob is actively being damaged, do not reset due to distance unless it's a world boss + if (!isWorldBoss()) + if (time(NULL) - GetLastDamagedTime() <= MAX_AGGRO_RESET_TIME) + return true; + //Use AttackDistance in distance check if threat radius is lower. This prevents creature bounce in and out of combat every update tick. float dist = std::max(GetAttackDistance(victim), sWorld->getFloatConfig(CONFIG_THREAT_RADIUS)) + m_CombatDistance; diff --git a/src/server/game/Entities/Creature/Creature.h b/src/server/game/Entities/Creature/Creature.h index 49bd854ef2f..0803345f4f0 100644 --- a/src/server/game/Entities/Creature/Creature.h +++ b/src/server/game/Entities/Creature/Creature.h @@ -479,7 +479,7 @@ class Creature : public Unit, public GridObject<Creature>, public MapObject bool AIM_Initialize(CreatureAI* ai = NULL); void Motion_Initialize(); - CreatureAI* AI() const { return (CreatureAI*)i_AI; } + CreatureAI* AI() const { return reinterpret_cast<CreatureAI*>(i_AI); } bool SetWalk(bool enable) override; bool SetDisableGravity(bool disable, bool packetOnly = false) override; diff --git a/src/server/game/Entities/Creature/TemporarySummon.cpp b/src/server/game/Entities/Creature/TemporarySummon.cpp index 8bf3a1e2846..12e3af3c290 100644 --- a/src/server/game/Entities/Creature/TemporarySummon.cpp +++ b/src/server/game/Entities/Creature/TemporarySummon.cpp @@ -227,6 +227,11 @@ void TempSummon::InitSummon() } } +void TempSummon::UpdateObjectVisibilityOnCreate() +{ + WorldObject::UpdateObjectVisibility(true); +} + void TempSummon::SetTempSummonType(TempSummonType type) { m_type = type; diff --git a/src/server/game/Entities/Creature/TemporarySummon.h b/src/server/game/Entities/Creature/TemporarySummon.h index 6d058f405a8..b80e7d3e2bc 100644 --- a/src/server/game/Entities/Creature/TemporarySummon.h +++ b/src/server/game/Entities/Creature/TemporarySummon.h @@ -45,6 +45,7 @@ class TempSummon : public Creature void Update(uint32 time) override; virtual void InitStats(uint32 lifetime); virtual void InitSummon(); + void UpdateObjectVisibilityOnCreate() override; virtual void UnSummon(uint32 msTime = 0); void RemoveFromWorld() override; void SetTempSummonType(TempSummonType type); diff --git a/src/server/game/Entities/GameObject/GameObject.cpp b/src/server/game/Entities/GameObject/GameObject.cpp index b030f42bef7..1acfeacbf83 100644 --- a/src/server/game/Entities/GameObject/GameObject.cpp +++ b/src/server/game/Entities/GameObject/GameObject.cpp @@ -1399,7 +1399,10 @@ void GameObject::Use(Unit* user) player->SendCinematicStart(info->camera.cinematicId); if (info->camera.eventID) + { GetMap()->ScriptsStart(sEventScripts, info->camera.eventID, player, this); + EventInform(info->camera.eventID, user); + } return; } diff --git a/src/server/game/Entities/Item/Item.cpp b/src/server/game/Entities/Item/Item.cpp index 70fa4714547..773d5a05772 100644 --- a/src/server/game/Entities/Item/Item.cpp +++ b/src/server/game/Entities/Item/Item.cpp @@ -447,8 +447,7 @@ bool Item::LoadFromDB(ObjectGuid::LowType guid, ObjectGuid owner_guid, Field* fi need_save = true; } - std::string enchants = fields[6].GetString(); - _LoadIntoDataField(enchants.c_str(), ITEM_FIELD_ENCHANTMENT_1_1, MAX_ENCHANTMENT_SLOT * MAX_ENCHANTMENT_OFFSET); + _LoadIntoDataField(fields[6].GetString(), ITEM_FIELD_ENCHANTMENT_1_1, MAX_ENCHANTMENT_SLOT * MAX_ENCHANTMENT_OFFSET); SetInt32Value(ITEM_FIELD_RANDOM_PROPERTIES_ID, fields[7].GetInt16()); // recalculate suffix factor if (GetItemRandomPropertyId() < 0) diff --git a/src/server/game/Entities/Object/Object.cpp b/src/server/game/Entities/Object/Object.cpp index 4877ff094e1..836a041abc3 100644 --- a/src/server/game/Entities/Object/Object.cpp +++ b/src/server/game/Entities/Object/Object.cpp @@ -1878,7 +1878,9 @@ TempSummon* Map::SummonCreature(uint32 entry, Position const& pos, SummonPropert AddToMap(summon->ToCreature()); summon->InitSummon(); - //ObjectAccessor::UpdateObjectVisibility(summon); + // call MoveInLineOfSight for nearby creatures + Trinity::AIRelocationNotifier notifier(*summon); + summon->VisitNearbyObject(GetVisibilityRange(), notifier); return summon; } diff --git a/src/server/game/Entities/Object/Object.h b/src/server/game/Entities/Object/Object.h index 419044081e3..ba03c16fa1e 100644 --- a/src/server/game/Entities/Object/Object.h +++ b/src/server/game/Entities/Object/Object.h @@ -555,6 +555,11 @@ class WorldObject : public Object, public WorldLocation void DestroyForNearbyPlayers(); virtual void UpdateObjectVisibility(bool forced = true); + virtual void UpdateObjectVisibilityOnCreate() + { + UpdateObjectVisibility(true); + } + void BuildUpdate(UpdateDataMapType&) override; void AddToObjectUpdate() override; diff --git a/src/server/game/Entities/Player/Player.cpp b/src/server/game/Entities/Player/Player.cpp index 8ce78f88906..f3d45b005d8 100644 --- a/src/server/game/Entities/Player/Player.cpp +++ b/src/server/game/Entities/Player/Player.cpp @@ -213,7 +213,7 @@ void PlayerTaxi::AppendTaximaskTo(ByteBuffer& data, bool all) if (all) { for (uint8 i = 0; i < TaxiMaskSize; ++i) - data << uint32(sTaxiNodesMask[i]); // all existed nodes + data << uint32(sTaxiNodesMask[i]); // all existing nodes } else { @@ -605,7 +605,7 @@ bool Player::Create(ObjectGuid::LowType guidlow, CharacterCreateInfo* createInfo PlayerInfo const* info = sObjectMgr->GetPlayerInfo(createInfo->Race, createInfo->Class); if (!info) { - TC_LOG_ERROR("entities.player", "Player::Create: Possible hacking-attempt: Account %u tried creating a character named '%s' with an invalid race/class pair (%u/%u) - refusing to do so.", + TC_LOG_ERROR("entities.player", "Player::Create: Possible hacking attempt: Account %u tried to create a character named '%s' with an invalid race/class pair (%u/%u) - refusing to do so.", GetSession()->GetAccountId(), m_name.c_str(), createInfo->Race, createInfo->Class); return false; } @@ -618,7 +618,7 @@ bool Player::Create(ObjectGuid::LowType guidlow, CharacterCreateInfo* createInfo ChrClassesEntry const* cEntry = sChrClassesStore.LookupEntry(createInfo->Class); if (!cEntry) { - TC_LOG_ERROR("entities.player", "Player::Create: Possible hacking-attempt: Account %u tried creating a character named '%s' with an invalid character class (%u) - refusing to do so (wrong DBC-files?)", + TC_LOG_ERROR("entities.player", "Player::Create: Possible hacking attempt: Account %u tried to create a character named '%s' with an invalid character class (%u) - refusing to do so (wrong DBC-files?)", GetSession()->GetAccountId(), m_name.c_str(), createInfo->Class); return false; } @@ -633,14 +633,14 @@ bool Player::Create(ObjectGuid::LowType guidlow, CharacterCreateInfo* createInfo if (!IsValidGender(createInfo->Gender)) { - TC_LOG_ERROR("entities.player", "Player::Create: Possible hacking-attempt: Account %u tried creating a character named '%s' with an invalid gender (%u) - refusing to do so", + TC_LOG_ERROR("entities.player", "Player::Create: Possible hacking attempt: Account %u tried to create a character named '%s' with an invalid gender (%u) - refusing to do so", GetSession()->GetAccountId(), m_name.c_str(), createInfo->Gender); return false; } if (!ValidateAppearance(createInfo->Race, createInfo->Class, createInfo->Gender, createInfo->HairStyle, createInfo->HairColor, createInfo->Face, createInfo->FacialHair, createInfo->Skin, true)) { - TC_LOG_ERROR("entities.player", "Player::Create: Possible hacking-attempt: Account %u tried creating a character named '%s' with invalid appearance attributes - refusing to do so", + TC_LOG_ERROR("entities.player", "Player::Create: Possible hacking attempt: Account %u tried to create a character named '%s' with invalid appearance attributes - refusing to do so", GetSession()->GetAccountId(), m_name.c_str()); return false; } @@ -962,9 +962,9 @@ uint32 Player::EnvironmentalDamage(EnviromentalDamage type, uint32 damage) if (!IsAlive()) { - if (type == DAMAGE_FALL) // DealDamage not apply item durability loss at self damage + if (type == DAMAGE_FALL) // DealDamage does not apply item durability loss from self-induced damage. { - TC_LOG_DEBUG("entities.player", "We are fall to death, loosing 10 percents durability"); + TC_LOG_DEBUG("entities.player", "You have died from falling, losing 10 percent total armor durability."); DurabilityLossAll(0.10f, false); // durability lost message WorldPacket data2(SMSG_DURABILITY_DAMAGE_DEATH, 0); @@ -1237,13 +1237,14 @@ void Player::Update(uint32 p_time) UpdateAfkReport(now); - if (IsCharmed()) - if (Unit* charmer = GetCharmer()) - if (charmer->GetTypeId() == TYPEID_UNIT && charmer->IsAlive()) - UpdateCharmedAI(); - - if (GetAI() && IsAIEnabled) + if (IsAIEnabled && GetAI()) GetAI()->UpdateAI(p_time); + else if (NeedChangeAI) + { + UpdateCharmAI(); + NeedChangeAI = false; + IsAIEnabled = (GetAI() != nullptr); + } // Update items that have just a limited lifetime if (now > m_Last_tick) @@ -1551,7 +1552,7 @@ void Player::setDeathState(DeathState s) { if (!cur) { - TC_LOG_ERROR("entities.player", "setDeathState: attempt to kill a dead player %s(%d)", GetName().c_str(), GetGUID().GetCounter()); + TC_LOG_ERROR("entities.player", "setDeathState: Attempted to kill a dead player %s(%d)", GetName().c_str(), GetGUID().GetCounter()); return; } @@ -1824,7 +1825,7 @@ bool Player::TeleportTo(uint32 mapid, float x, float y, float z, float orientati // client without expansion support if (GetSession()->Expansion() < mEntry->Expansion()) { - TC_LOG_DEBUG("maps", "Player %s using client without required expansion tried teleport to non accessible map %u", GetName().c_str(), mapid); + TC_LOG_DEBUG("maps", "Player %s using client without required expansion tried teleporting to non accessible map %u", GetName().c_str(), mapid); if (Transport* transport = GetTransport()) { @@ -3164,12 +3165,12 @@ bool Player::AddTalent(uint32 spellId, uint8 spec, bool learning) // do character spell book cleanup (all characters) if (!IsInWorld() && !learning) // spell load case { - TC_LOG_ERROR("spells", "Player::addSpell: Non-existed in SpellStore spell #%u request, deleting for all characters in `character_spell`.", spellId); + TC_LOG_ERROR("spells", "Player::addSpell: Non-existing spell #%u requested from SpellStore. Deleting spell for all characters in `character_spell`.", spellId); DeleteSpellFromAllPlayers(spellId); } else - TC_LOG_ERROR("spells", "Player::addSpell: Non-existed in SpellStore spell #%u request.", spellId); + TC_LOG_ERROR("spells", "Player::addSpell: Non-existing spell #%u requested from SpellStore.", spellId); return false; } @@ -3179,12 +3180,12 @@ bool Player::AddTalent(uint32 spellId, uint8 spec, bool learning) // do character spell book cleanup (all characters) if (!IsInWorld() && !learning) // spell load case { - TC_LOG_ERROR("spells", "Player::addTalent: Broken spell #%u learning not allowed, deleting for all characters in `character_talent`.", spellId); + TC_LOG_ERROR("spells", "Player::addTalent: Broken spell #%u, learning this spell is not allowed. Deleting this spell for all characters in `character_talent`.", spellId); DeleteSpellFromAllPlayers(spellId); } else - TC_LOG_ERROR("spells", "Player::addTalent: Broken spell #%u learning not allowed.", spellId); + TC_LOG_ERROR("spells", "Player::addTalent: Broken spell #%u, learning this spell is not allowed.", spellId); return false; } @@ -3229,12 +3230,12 @@ bool Player::AddSpell(uint32 spellId, bool active, bool learning, bool dependent // do character spell book cleanup (all characters) if (!IsInWorld() && !learning) // spell load case { - TC_LOG_ERROR("spells", "Player::addSpell: Non-existed in SpellStore spell #%u request, deleting for all characters in `character_spell`.", spellId); + TC_LOG_ERROR("spells", "Player::addSpell: Non-existing spell #%u requested from SpellStore. Deleting for all characters in `character_spell`.", spellId); DeleteSpellFromAllPlayers(spellId); } else - TC_LOG_ERROR("spells", "Player::addSpell: Non-existed in SpellStore spell #%u request.", spellId); + TC_LOG_ERROR("spells", "Player::addSpell: Non-existing spell #%u requested from SpellStore.", spellId); return false; } @@ -3244,12 +3245,12 @@ bool Player::AddSpell(uint32 spellId, bool active, bool learning, bool dependent // do character spell book cleanup (all characters) if (!IsInWorld() && !learning) // spell load case { - TC_LOG_ERROR("spells", "Player::addSpell: Broken spell #%u learning not allowed, deleting for all characters in `character_spell`.", spellId); + TC_LOG_ERROR("spells", "Player::addSpell: Broken spell #%u, learning this spell is not allowed. Deleting this spell for all characters in `character_spell`.", spellId); DeleteSpellFromAllPlayers(spellId); } else - TC_LOG_ERROR("spells", "Player::addSpell: Broken spell #%u learning not allowed.", spellId); + TC_LOG_ERROR("spells", "Player::addSpell: Broken spell #%u, learning this spell is not allowed.", spellId); return false; } @@ -3966,7 +3967,7 @@ bool Player::ResetTalents(bool no_cost) for (int8 rank = MAX_TALENT_RANK-1; rank >= 0; --rank) { - // skip non-existant talent ranks + // skip non-existing talent ranks if (talentInfo->RankID[rank] == 0) continue; const SpellInfo* _spellEntry = sSpellMgr->GetSpellInfo(talentInfo->RankID[rank]); @@ -4682,6 +4683,7 @@ void Player::ResurrectPlayer(float restore_percent, bool applySickness) // remove death flag + set aura SetByteValue(UNIT_FIELD_BYTES_1, 3, 0x00); + RemoveFlag(PLAYER_FLAGS, PLAYER_FLAGS_IS_OUT_OF_BOUNDS); // This must be called always even on Players with race != RACE_NIGHTELF in case of faction change RemoveAurasDueToSpell(20584); // RACE_NIGHTELF speed bonuses @@ -4816,7 +4818,7 @@ void Player::OfflineResurrect(ObjectGuid const& guid, SQLTransaction& trans) Corpse* Player::CreateCorpse() { - // prevent existence 2 corpse for player + // prevent the existence of 2 corpses for one player SpawnCorpseBones(); uint32 _pb, _pb2, _cfb1, _cfb2; @@ -5041,7 +5043,7 @@ uint32 Player::DurabilityRepair(uint16 pos, bool cost, float discountMod, bool g DurabilityCostsEntry const* dcost = sDurabilityCostsStore.LookupEntry(ditemProto->ItemLevel); if (!dcost) { - TC_LOG_ERROR("entities.player.items", "RepairDurability: Wrong item lvl %u", ditemProto->ItemLevel); + TC_LOG_ERROR("entities.player.items", "RepairDurability: Wrong item level %u", ditemProto->ItemLevel); return TotalCost; } @@ -5065,7 +5067,7 @@ uint32 Player::DurabilityRepair(uint16 pos, bool cost, float discountMod, bool g { if (GetGuildId() == 0) { - TC_LOG_DEBUG("entities.player.items", "You are not member of a guild"); + TC_LOG_DEBUG("entities.player.items", "You are not member of a guild."); return TotalCost; } @@ -5080,7 +5082,7 @@ uint32 Player::DurabilityRepair(uint16 pos, bool cost, float discountMod, bool g } else if (!HasEnoughMoney(costs)) { - TC_LOG_DEBUG("entities.player.items", "You do not have enough money"); + TC_LOG_DEBUG("entities.player.items", "You do not have enough money."); return TotalCost; } else @@ -5102,10 +5104,10 @@ void Player::RepopAtGraveyard() // note: this can be called also when the player is alive // for example from WorldSession::HandleMovementOpcodes - AreaTableEntry const* zone = GetAreaEntryByAreaID(GetAreaId()); + AreaTableEntry const* zone = sAreaTableStore.LookupEntry(GetAreaId()); // Such zones are considered unreachable as a ghost and the player must be automatically revived - if ((!IsAlive() && zone && zone->flags & AREA_FLAG_NEED_FLY) || GetTransport() || GetPositionZ() < -500.0f) + if ((!IsAlive() && zone && zone->flags & AREA_FLAG_NEED_FLY) || GetTransport() || GetPositionZ() < GetMap()->GetMinHeight(GetPositionX(), GetPositionY())) { ResurrectPlayer(0.5f); SpawnCorpseBones(); @@ -5142,8 +5144,10 @@ void Player::RepopAtGraveyard() GetSession()->SendPacket(&data); } } - else if (GetPositionZ() < -500.0f) + else if (GetPositionZ() < GetMap()->GetMinHeight(GetPositionX(), GetPositionY())) TeleportTo(m_homebindMapId, m_homebindX, m_homebindY, m_homebindZ, GetOrientation()); + + RemoveFlag(PLAYER_FLAGS, PLAYER_FLAGS_IS_OUT_OF_BOUNDS); } bool Player::CanJoinConstantChannelInZone(ChatChannelsEntry const* channel, AreaTableEntry const* zone) @@ -5188,7 +5192,7 @@ void Player::UpdateLocalChannels(uint32 newZone) if (GetSession()->PlayerLoading() && !IsBeingTeleportedFar()) return; // The client handles it automatically after loading, but not after teleporting - AreaTableEntry const* current_zone = GetAreaEntryByAreaID(newZone); + AreaTableEntry const* current_zone = sAreaTableStore.LookupEntry(newZone); if (!current_zone) return; @@ -5288,7 +5292,7 @@ void Player::HandleBaseModValue(BaseModGroup modGroup, BaseModType modType, floa { if (modGroup >= BASEMOD_END || modType >= MOD_END) { - TC_LOG_ERROR("spells", "ERROR in HandleBaseModValue(): non existed BaseModGroup of wrong BaseModType!"); + TC_LOG_ERROR("spells", "ERROR in HandleBaseModValue(): Non-existing BaseModGroup or wrong BaseModType!"); return; } @@ -5314,7 +5318,7 @@ float Player::GetBaseModValue(BaseModGroup modGroup, BaseModType modType) const { if (modGroup >= BASEMOD_END || modType >= MOD_END) { - TC_LOG_ERROR("spells", "trial to access non existed BaseModGroup or wrong BaseModType!"); + TC_LOG_ERROR("spells", "Attempt to access non-existing BaseModGroup or wrong BaseModType!"); return 0.0f; } @@ -5328,7 +5332,7 @@ float Player::GetTotalBaseModValue(BaseModGroup modGroup) const { if (modGroup >= BASEMOD_END) { - TC_LOG_ERROR("spells", "wrong BaseModGroup in GetTotalBaseModValue()!"); + TC_LOG_ERROR("spells", "Wrong BaseModGroup in GetTotalBaseModValue()!"); return 0.0f; } @@ -6266,20 +6270,20 @@ bool Player::IsActionButtonDataValid(uint8 button, uint32 action, uint8 type) case ACTION_BUTTON_SPELL: if (!sSpellMgr->GetSpellInfo(action)) { - TC_LOG_DEBUG("entities.player", "Spell action %u not added into button %u for player %s (GUID: %u): spell not exist", action, button, GetName().c_str(), GetGUID().GetCounter()); + TC_LOG_DEBUG("entities.player", "Spell action %u not added into button %u for player %s (GUID: %u): spell does not exist", action, button, GetName().c_str(), GetGUID().GetCounter()); return false; } if (!HasSpell(action)) { - TC_LOG_DEBUG("entities.player", "Spell action %u not added into button %u for player %s (GUID: %u): player don't known this spell", action, button, GetName().c_str(), GetGUID().GetCounter()); + TC_LOG_DEBUG("entities.player", "Spell action %u not added into button %u for player %s (GUID: %u): player does not know this spell", action, button, GetName().c_str(), GetGUID().GetCounter()); return false; } break; case ACTION_BUTTON_ITEM: if (!sObjectMgr->GetItemTemplate(action)) { - TC_LOG_DEBUG("entities.player", "Item action %u not added into button %u for player %s (GUID: %u): item not exist", action, button, GetName().c_str(), GetGUID().GetCounter()); + TC_LOG_DEBUG("entities.player", "Item action %u not added into button %u for player %s (GUID: %u): item does not exist", action, button, GetName().c_str(), GetGUID().GetCounter()); return false; } break; @@ -6301,7 +6305,7 @@ ActionButton* Player::addActionButton(uint8 button, uint32 action, uint8 type) if (!IsActionButtonDataValid(button, action, type)) return NULL; - // it create new button (NEW state) if need or return existed + // it create new button (NEW state) if need or return existing ActionButton& ab = m_actionButtons[button]; // set data and update to CHANGED if not NEW @@ -6429,22 +6433,32 @@ void Player::CheckAreaExploreAndOutdoor() return; bool isOutdoor; - uint16 areaFlag = GetBaseMap()->GetAreaFlag(GetPositionX(), GetPositionY(), GetPositionZ(), &isOutdoor); + uint32 areaId = GetBaseMap()->GetAreaId(GetPositionX(), GetPositionY(), GetPositionZ(), &isOutdoor); + AreaTableEntry const* areaEntry = sAreaTableStore.LookupEntry(areaId); if (sWorld->getBoolConfig(CONFIG_VMAP_INDOOR_CHECK) && !isOutdoor) RemoveAurasWithAttribute(SPELL_ATTR0_OUTDOORS_ONLY); - if (areaFlag == 0xffff) + if (!areaId) return; - int offset = areaFlag / 32; + + if (!areaEntry) + { + TC_LOG_ERROR("entities.player", "Player '%s' (%s) discovered unknown area (x: %f y: %f z: %f map: %u)", + GetName().c_str(), GetGUID().ToString().c_str(), GetPositionX(), GetPositionY(), GetPositionZ(), GetMapId()); + return; + } + + uint32 offset = areaEntry->exploreFlag / 32; if (offset >= PLAYER_EXPLORED_ZONES_SIZE) { - TC_LOG_ERROR("entities.player", "Wrong area flag %u in map data for (X: %f Y: %f) point to field PLAYER_EXPLORED_ZONES_1 + %u ( %u must be < %u ).", areaFlag, GetPositionX(), GetPositionY(), offset, offset, PLAYER_EXPLORED_ZONES_SIZE); + TC_LOG_ERROR("entities.player", "Player::CheckAreaExploreAndOutdoor: Wrong area flag %u in map data for (X: %f Y: %f) point to field PLAYER_EXPLORED_ZONES_1 + %u ( %u must be < %u ).", + areaEntry->exploreFlag, GetPositionX(), GetPositionY(), offset, offset, PLAYER_EXPLORED_ZONES_SIZE); return; } - uint32 val = (uint32)(1 << (areaFlag % 32)); + uint32 val = (uint32)(1 << (areaEntry->exploreFlag % 32)); uint32 currFields = GetUInt32Value(PLAYER_EXPLORED_ZONES_1 + offset); if (!(currFields & val)) @@ -6453,19 +6467,11 @@ void Player::CheckAreaExploreAndOutdoor() UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_EXPLORE_AREA); - AreaTableEntry const* areaEntry = GetAreaEntryByAreaFlagAndMap(areaFlag, GetMapId()); - if (!areaEntry) - { - TC_LOG_ERROR("entities.player", "Player %u discovered unknown area (x: %f y: %f z: %f map: %u", GetGUID().GetCounter(), GetPositionX(), GetPositionY(), GetPositionZ(), GetMapId()); - return; - } - if (areaEntry->area_level > 0) { - uint32 area = areaEntry->ID; if (getLevel() >= sWorld->getIntConfig(CONFIG_MAX_PLAYER_LEVEL)) { - SendExplorationExperience(area, 0); + SendExplorationExperience(areaId, 0); } else { @@ -6489,9 +6495,9 @@ void Player::CheckAreaExploreAndOutdoor() } GiveXP(XP, NULL); - SendExplorationExperience(area, XP); + SendExplorationExperience(areaId, XP); } - TC_LOG_DEBUG("entities.player", "Player %u discovered a new area: %u", GetGUID().GetCounter(), area); + TC_LOG_DEBUG("entities.player", "Player '%s' (%s) discovered a new area: %u", GetName().c_str(),GetGUID().ToString().c_str(), areaId); } } } @@ -7061,7 +7067,7 @@ void Player::UpdateArea(uint32 newArea) // so apply them accordingly m_areaUpdateId = newArea; - AreaTableEntry const* area = GetAreaEntryByAreaID(newArea); + AreaTableEntry const* area = sAreaTableStore.LookupEntry(newArea); pvpInfo.IsInFFAPvPArea = area && (area->flags & AREA_FLAG_ARENA); UpdatePvPState(true); @@ -7109,7 +7115,7 @@ void Player::UpdateZone(uint32 newZone, uint32 newArea) // zone changed, so area changed as well, update it UpdateArea(newArea); - AreaTableEntry const* zone = GetAreaEntryByAreaID(newZone); + AreaTableEntry const* zone = sAreaTableStore.LookupEntry(newZone); if (!zone) return; @@ -7945,7 +7951,7 @@ void Player::CastItemCombatSpell(Unit* target, WeaponAttackType attType, uint32 SpellInfo const* spellInfo = sSpellMgr->GetSpellInfo(spellData.SpellId); if (!spellInfo) { - TC_LOG_ERROR("entities.player.items", "WORLD: unknown Item spellid %i", spellData.SpellId); + TC_LOG_ERROR("entities.player.items", "WORLD: Unknown item spellid %i", spellData.SpellId); continue; } @@ -8045,7 +8051,7 @@ void Player::CastItemUseSpell(Item* item, SpellCastTargets const& targets, uint8 SpellInfo const* spellInfo = sSpellMgr->GetSpellInfo(learn_spell_id); if (!spellInfo) { - TC_LOG_ERROR("entities.player", "Player::CastItemUseSpell: Item (Entry: %u) in have wrong spell id %u, ignoring ", proto->ItemId, learn_spell_id); + TC_LOG_ERROR("entities.player", "Player::CastItemUseSpell: Item (Entry: %u) has wrong spell id %u, ignoring.", proto->ItemId, learn_spell_id); SendEquipError(EQUIP_ERR_NONE, item, NULL); return; } @@ -8074,7 +8080,7 @@ void Player::CastItemUseSpell(Item* item, SpellCastTargets const& targets, uint8 SpellInfo const* spellInfo = sSpellMgr->GetSpellInfo(spellData.SpellId); if (!spellInfo) { - TC_LOG_ERROR("entities.player", "Player::CastItemUseSpell: Item (Entry: %u) in have wrong spell id %u, ignoring", proto->ItemId, spellData.SpellId); + TC_LOG_ERROR("entities.player", "Player::CastItemUseSpell: Item (Entry: %u) has wrong spell id %u, ignoring.", proto->ItemId, spellData.SpellId); continue; } @@ -8101,7 +8107,7 @@ void Player::CastItemUseSpell(Item* item, SpellCastTargets const& targets, uint8 SpellInfo const* spellInfo = sSpellMgr->GetSpellInfo(pEnchant->spellid[s]); if (!spellInfo) { - TC_LOG_ERROR("entities.player", "Player::CastItemUseSpell Enchant %i, cast unknown spell %i", pEnchant->ID, pEnchant->spellid[s]); + TC_LOG_ERROR("entities.player", "Player::CastItemUseSpell Enchant %i casts unknown spell %i.", pEnchant->ID, pEnchant->spellid[s]); continue; } @@ -9357,7 +9363,7 @@ uint32 Player::GetXPRestBonus(uint32 xp) SetRestBonus(GetRestBonus() - rested_bonus); - TC_LOG_DEBUG("entities.player", "GetXPRestBonus: Player %s (%u) gain %u xp (+%u Rested Bonus). Rested points=%f", GetName().c_str(), GetGUID().GetCounter(), xp+rested_bonus, rested_bonus, GetRestBonus()); + TC_LOG_DEBUG("entities.player", "GetXPRestBonus: Player %s (%u) gains %u xp (+%u Rested Bonus). Rested points=%f", GetName().c_str(), GetGUID().GetCounter(), xp+rested_bonus, rested_bonus, GetRestBonus()); return rested_bonus; } @@ -9389,7 +9395,7 @@ void Player::ResetPetTalents() CharmInfo* charmInfo = pet->GetCharmInfo(); if (!charmInfo) { - TC_LOG_ERROR("entities.player", "Object (GUID: %u TypeId: %u) is considered pet-like but doesn't have a charminfo!", pet->GetGUID().GetCounter(), pet->GetTypeId()); + TC_LOG_ERROR("entities.player", "Object (GUID: %u TypeId: %u) is considered pet-like, but doesn't have charm info!", pet->GetGUID().GetCounter(), pet->GetTypeId()); return; } pet->resetTalents(); @@ -10306,7 +10312,7 @@ InventoryResult Player::CanStoreItem_InBag(uint8 bag, ItemPosCountVec &dest, Ite if (bag == skip_bag) return EQUIP_ERR_ITEM_DOESNT_GO_INTO_BAG; - // skip not existed bag or self targeted bag + // skip non-existing bag or self targeted bag Bag* pBag = GetBagByPos(bag); if (!pBag || pBag == pSrcItem) return EQUIP_ERR_ITEM_DOESNT_GO_INTO_BAG; @@ -11291,7 +11297,7 @@ InventoryResult Player::CanUnequipItem(uint16 pos, bool swap) const Item* pItem = GetItemByPos(pos); - // Applied only to existed equipped item + // Applied only to existing equipped item if (!pItem) return EQUIP_ERR_OK; @@ -11972,7 +11978,7 @@ Item* Player::EquipItem(uint16 pos, Item* pItem, bool update) SpellInfo const* spellProto = sSpellMgr->GetSpellInfo(cooldownSpell); if (!spellProto) - TC_LOG_ERROR("entities.player", "Weapon switch cooldown spell %u couldn't be found in Spell.dbc", cooldownSpell); + TC_LOG_ERROR("entities.player", "Weapon switch cooldown spell %u could not be found in Spell.dbc", cooldownSpell); else { m_weaponChangeTimer = spellProto->StartRecoveryTime; @@ -12220,7 +12226,7 @@ void Player::MoveItemToInventory(ItemPosCountVec const& dest, Item* pItem, bool // store item Item* pLastItem = StoreItem(dest, pItem, update); - // only set if not merged to existed stack (pItem can be deleted already but we can compare pointers any way) + // only set if not merged to existing stack (pItem can be deleted already but we can compare pointers any way) if (pLastItem == pItem) { // update owner for last item (this can be original item with wrong owner @@ -12666,7 +12672,7 @@ void Player::SplitItem(uint16 src, uint16 dst, uint32 count) return; } - // not let split more existed items (can be only at cheating) + // not let split more existing items (can be only at cheating) if (pSrcItem->GetCount() < count) { SendEquipError(EQUIP_ERR_TRIED_TO_SPLIT_MORE_THAN_COUNT, pSrcItem, NULL); @@ -13962,7 +13968,7 @@ void Player::PrepareGossipMenu(WorldObject* source, uint32 menuId /*= 0*/, bool VendorItemData const* vendorItems = creature->GetVendorItems(); if (!vendorItems || vendorItems->Empty()) { - TC_LOG_ERROR("sql.sql", "Creature %s (Entry: %u GUID: %u DB GUID: %u) has UNIT_NPC_FLAG_VENDOR set but has an empty trading item list.", creature->GetName().c_str(), creature->GetEntry(), creature->GetGUID().GetCounter(), creature->GetSpawnId()); + TC_LOG_ERROR("sql.sql", "Creature %s (Entry: %u GUID: %u DB GUID: %u) has UNIT_NPC_FLAG_VENDOR set, but has an empty trading item list.", creature->GetName().c_str(), creature->GetEntry(), creature->GetGUID().GetCounter(), creature->GetSpawnId()); canTalk = false; } break; @@ -13996,7 +14002,7 @@ void Player::PrepareGossipMenu(WorldObject* source, uint32 menuId /*= 0*/, bool break; case GOSSIP_OPTION_TRAINER: if (getClass() != creature->GetCreatureTemplate()->trainer_class && creature->GetCreatureTemplate()->trainer_type == TRAINER_TYPE_CLASS) - TC_LOG_ERROR("sql.sql", "GOSSIP_OPTION_TRAINER:: Player %s (GUID: %u) request wrong gossip menu: %u with wrong class: %u at Creature: %s (Entry: %u, Trainer Class: %u)", + TC_LOG_ERROR("sql.sql", "GOSSIP_OPTION_TRAINER:: Player %s (GUID: %u) requested wrong gossip menu: %u with wrong class: %u at Creature: %s (Entry: %u, Trainer Class: %u)", GetName().c_str(), GetGUID().GetCounter(), menu->GetGossipMenu().GetMenuId(), getClass(), creature->GetName().c_str(), creature->GetEntry(), creature->GetCreatureTemplate()->trainer_class); // no break; case GOSSIP_OPTION_GOSSIP: @@ -14012,7 +14018,7 @@ void Player::PrepareGossipMenu(WorldObject* source, uint32 menuId /*= 0*/, bool canTalk = false; break; default: - TC_LOG_ERROR("sql.sql", "Creature entry %u has unknown gossip option %u for menu %u", creature->GetEntry(), itr->second.OptionType, itr->second.MenuId); + TC_LOG_ERROR("sql.sql", "Creature entry %u has unknown gossip option %u for menu %u.", creature->GetEntry(), itr->second.OptionType, itr->second.MenuId); canTalk = false; break; } @@ -14053,14 +14059,14 @@ void Player::PrepareGossipMenu(WorldObject* source, uint32 menuId /*= 0*/, bool if (!optionBroadcastText) { /// Find localizations from database. - if (GossipMenuItemsLocale const* gossipMenuLocale = sObjectMgr->GetGossipMenuItemsLocale(MAKE_PAIR32(menuId, menuId))) + if (GossipMenuItemsLocale const* gossipMenuLocale = sObjectMgr->GetGossipMenuItemsLocale(MAKE_PAIR32(menuId, itr->second.OptionIndex))) ObjectMgr::GetLocaleString(gossipMenuLocale->OptionText, locale, strOptionText); } if (!boxBroadcastText) { /// Find localizations from database. - if (GossipMenuItemsLocale const* gossipMenuLocale = sObjectMgr->GetGossipMenuItemsLocale(MAKE_PAIR32(menuId, menuId))) + if (GossipMenuItemsLocale const* gossipMenuLocale = sObjectMgr->GetGossipMenuItemsLocale(MAKE_PAIR32(menuId, itr->second.OptionIndex))) ObjectMgr::GetLocaleString(gossipMenuLocale->BoxText, locale, strBoxText); } } @@ -14125,7 +14131,7 @@ void Player::OnGossipSelect(WorldObject* source, uint32 gossipListId, uint32 men { if (gossipOptionId > GOSSIP_OPTION_QUESTGIVER) { - TC_LOG_ERROR("entities.player", "Player guid %u request invalid gossip option for GameObject entry %u", GetGUID().GetCounter(), source->GetEntry()); + TC_LOG_ERROR("entities.player", "Player guid %u requested invalid gossip option for GameObject entry %u.", GetGUID().GetCounter(), source->GetEntry()); return; } } @@ -14229,7 +14235,7 @@ void Player::OnGossipSelect(WorldObject* source, uint32 gossipListId, uint32 men if (bgTypeId == BATTLEGROUND_TYPE_NONE) { - TC_LOG_ERROR("entities.player", "a user (guid %u) requested battlegroundlist from a npc who is no battlemaster", GetGUID().GetCounter()); + TC_LOG_ERROR("entities.player", "User (guid %u) requested battlegroundlist from an NPC who is not a battlemaster.", GetGUID().GetCounter()); return; } @@ -15188,7 +15194,7 @@ bool Player::SatisfyQuestPreviousQuest(Quest const* qInfo, bool msg) if (msg) { SendCanTakeQuestResponse(INVALIDREASON_DONT_HAVE_REQ); - TC_LOG_DEBUG("misc", "SatisfyQuestPreviousQuest: Sent INVALIDREASON_DONT_HAVE_REQ (questId: %u) because player does not have required quest (1).", qInfo->GetQuestId()); + TC_LOG_DEBUG("misc", "SatisfyQuestPreviousQuest: Sent INVALIDREASON_DONT_HAVE_REQ (questId: %u) because player does not have the required quest(s) (1).", qInfo->GetQuestId()); } return false; } @@ -15221,7 +15227,7 @@ bool Player::SatisfyQuestPreviousQuest(Quest const* qInfo, bool msg) if (msg) { SendCanTakeQuestResponse(INVALIDREASON_DONT_HAVE_REQ); - TC_LOG_DEBUG("misc", "SatisfyQuestPreviousQuest: Sent INVALIDREASON_DONT_HAVE_REQ (questId: %u) because player does not have required quest (2).", qInfo->GetQuestId()); + TC_LOG_DEBUG("misc", "SatisfyQuestPreviousQuest: Sent INVALIDREASON_DONT_HAVE_REQ (questId: %u) because player does not have the required quest(s) (2).", qInfo->GetQuestId()); } return false; @@ -15237,7 +15243,7 @@ bool Player::SatisfyQuestPreviousQuest(Quest const* qInfo, bool msg) if (msg) { SendCanTakeQuestResponse(INVALIDREASON_DONT_HAVE_REQ); - TC_LOG_DEBUG("misc", "SatisfyQuestPreviousQuest: Sent INVALIDREASON_DONT_HAVE_REQ (questId: %u) because player does not have required quest (3).", qInfo->GetQuestId()); + TC_LOG_DEBUG("misc", "SatisfyQuestPreviousQuest: Sent INVALIDREASON_DONT_HAVE_REQ (questId: %u) because player does not have the required quest(s) (3).", qInfo->GetQuestId()); } return false; @@ -15255,7 +15261,7 @@ bool Player::SatisfyQuestClass(Quest const* qInfo, bool msg) const if (msg) { SendCanTakeQuestResponse(INVALIDREASON_DONT_HAVE_REQ); - TC_LOG_DEBUG("misc", "SatisfyQuestClass: Sent INVALIDREASON_DONT_HAVE_REQ (questId: %u) because player does not have required class.", qInfo->GetQuestId()); + TC_LOG_DEBUG("misc", "SatisfyQuestClass: Sent INVALIDREASON_DONT_HAVE_REQ (questId: %u) because player is not (one of) the required class(es).", qInfo->GetQuestId()); } return false; @@ -15274,7 +15280,7 @@ bool Player::SatisfyQuestRace(Quest const* qInfo, bool msg) if (msg) { SendCanTakeQuestResponse(INVALIDREASON_QUEST_FAILED_WRONG_RACE); - TC_LOG_DEBUG("misc", "SatisfyQuestRace: Sent INVALIDREASON_QUEST_FAILED_WRONG_RACE (questId: %u) because player does not have required race.", qInfo->GetQuestId()); + TC_LOG_DEBUG("misc", "SatisfyQuestRace: Sent INVALIDREASON_QUEST_FAILED_WRONG_RACE (questId: %u) because player is not (one of) the required race(s).", qInfo->GetQuestId()); } return false; @@ -15290,7 +15296,7 @@ bool Player::SatisfyQuestReputation(Quest const* qInfo, bool msg) if (msg) { SendCanTakeQuestResponse(INVALIDREASON_DONT_HAVE_REQ); - TC_LOG_DEBUG("misc", "SatisfyQuestReputation: Sent INVALIDREASON_DONT_HAVE_REQ (questId: %u) because player does not have required reputation (min).", qInfo->GetQuestId()); + TC_LOG_DEBUG("misc", "SatisfyQuestReputation: Sent INVALIDREASON_DONT_HAVE_REQ (questId: %u) because player does not have the required reputation (min).", qInfo->GetQuestId()); } return false; } @@ -15301,7 +15307,7 @@ bool Player::SatisfyQuestReputation(Quest const* qInfo, bool msg) if (msg) { SendCanTakeQuestResponse(INVALIDREASON_DONT_HAVE_REQ); - TC_LOG_DEBUG("misc", "SatisfyQuestReputation: Sent INVALIDREASON_DONT_HAVE_REQ (questId: %u) because player does not have required reputation (max).", qInfo->GetQuestId()); + TC_LOG_DEBUG("misc", "SatisfyQuestReputation: Sent INVALIDREASON_DONT_HAVE_REQ (questId: %u) because player does not have the required reputation (max).", qInfo->GetQuestId()); } return false; } @@ -15314,7 +15320,7 @@ bool Player::SatisfyQuestReputation(Quest const* qInfo, bool msg) if (msg) { SendCanTakeQuestResponse(INVALIDREASON_DONT_HAVE_REQ); - TC_LOG_DEBUG("misc", "SatisfyQuestReputation: Sent INVALIDREASON_DONT_HAVE_REQ (questId: %u) because player does not have required reputation (ReputationObjective2).", qInfo->GetQuestId()); + TC_LOG_DEBUG("misc", "SatisfyQuestReputation: Sent INVALIDREASON_DONT_HAVE_REQ (questId: %u) because player does not have the required reputation (ReputationObjective2).", qInfo->GetQuestId()); } return false; } @@ -15343,7 +15349,7 @@ bool Player::SatisfyQuestConditions(Quest const* qInfo, bool msg) if (msg) { SendCanTakeQuestResponse(INVALIDREASON_DONT_HAVE_REQ); - TC_LOG_DEBUG("misc", "SatisfyQuestConditions: Sent INVALIDREASON_DONT_HAVE_REQ (questId: %u) because player does not meet conditions.", qInfo->GetQuestId()); + TC_LOG_DEBUG("misc", "SatisfyQuestConditions: Sent INVALIDREASON_DONT_HAVE_REQ (questId: %u) because player does not meet the conditions.", qInfo->GetQuestId()); } TC_LOG_DEBUG("condition", "Player::SatisfyQuestConditions: conditions not met for quest %u", qInfo->GetQuestId()); return false; @@ -15389,7 +15395,7 @@ bool Player::SatisfyQuestExclusiveGroup(Quest const* qInfo, bool msg) if (msg) { SendCanTakeQuestResponse(INVALIDREASON_DONT_HAVE_REQ); - TC_LOG_DEBUG("misc", "SatisfyQuestExclusiveGroup: Sent INVALIDREASON_DONT_HAVE_REQ (questId: %u) because player already did daily quests in exclusive group.", qInfo->GetQuestId()); + TC_LOG_DEBUG("misc", "SatisfyQuestExclusiveGroup: Sent INVALIDREASON_DONT_HAVE_REQ (questId: %u) because player already did all daily quests in exclusive group.", qInfo->GetQuestId()); } return false; @@ -15401,7 +15407,7 @@ bool Player::SatisfyQuestExclusiveGroup(Quest const* qInfo, bool msg) if (msg) { SendCanTakeQuestResponse(INVALIDREASON_DONT_HAVE_REQ); - TC_LOG_DEBUG("misc", "SatisfyQuestExclusiveGroup: Sent INVALIDREASON_DONT_HAVE_REQ (questId: %u) because player already did quest in exclusive group.", qInfo->GetQuestId()); + TC_LOG_DEBUG("misc", "SatisfyQuestExclusiveGroup: Sent INVALIDREASON_DONT_HAVE_REQ (questId: %u) because player has already taken one or more quests in the exclusive group.", qInfo->GetQuestId()); } return false; } @@ -15470,7 +15476,7 @@ bool Player::SatisfyQuestDay(Quest const* qInfo, bool msg) if (qInfo->IsDFQuest()) { - if (!m_DFQuests.empty()) + if (m_DFQuests.find(qInfo->GetQuestId()) != m_DFQuests.end()) return false; return true; @@ -16781,7 +16787,7 @@ bool Player::LoadFromDB(ObjectGuid guid, SQLQueryHolder *holder) { std::string name = "<unknown>"; sObjectMgr->GetPlayerNameByGUID(guid, name); - TC_LOG_ERROR("entities.player", "Player %s %s not found in table `characters`, can't load. ", name.c_str(), guid.ToString().c_str()); + TC_LOG_ERROR("entities.player", "Player %s %s not found in table `characters`, can't load.", name.c_str(), guid.ToString().c_str()); return false; } @@ -16793,7 +16799,7 @@ bool Player::LoadFromDB(ObjectGuid guid, SQLQueryHolder *holder) // player should be able to load/delete character only with correct account! if (dbAccountId != GetSession()->GetAccountId()) { - TC_LOG_ERROR("entities.player", "Player %s loading from wrong account (is: %u, should be: %u)", guid.ToString().c_str(), GetSession()->GetAccountId(), dbAccountId); + TC_LOG_ERROR("entities.player", "Player %s attempts to load from wrong account (current: %u, should be: %u)", guid.ToString().c_str(), GetSession()->GetAccountId(), dbAccountId); return false; } @@ -16825,7 +16831,7 @@ bool Player::LoadFromDB(ObjectGuid guid, SQLQueryHolder *holder) uint8 gender = fields[5].GetUInt8(); if (!IsValidGender(gender)) { - TC_LOG_ERROR("entities.player", "Player %s has wrong gender (%u), can't be loaded.", guid.ToString().c_str(), gender); + TC_LOG_ERROR("entities.player", "Player %s is the wrong gender (%u) and can't be loaded.", guid.ToString().c_str(), gender); return false; } @@ -16840,15 +16846,15 @@ bool Player::LoadFromDB(ObjectGuid guid, SQLQueryHolder *holder) PlayerInfo const* info = sObjectMgr->GetPlayerInfo(getRace(), getClass()); if (!info) { - TC_LOG_ERROR("entities.player", "Player %s has wrong race/class (%u/%u), can't be loaded.", guid.ToString().c_str(), getRace(), getClass()); + TC_LOG_ERROR("entities.player", "Player %s has an invalid race/class combination (%u/%u) and can't be loaded.", guid.ToString().c_str(), getRace(), getClass()); return false; } SetUInt32Value(UNIT_FIELD_LEVEL, fields[6].GetUInt8()); SetUInt32Value(PLAYER_XP, fields[7].GetUInt32()); - _LoadIntoDataField(fields[61].GetCString(), PLAYER_EXPLORED_ZONES_1, PLAYER_EXPLORED_ZONES_SIZE); - _LoadIntoDataField(fields[64].GetCString(), PLAYER__FIELD_KNOWN_TITLES, KNOWN_TITLES_SIZE*2); + _LoadIntoDataField(fields[61].GetString(), PLAYER_EXPLORED_ZONES_1, PLAYER_EXPLORED_ZONES_SIZE); + _LoadIntoDataField(fields[64].GetString(), PLAYER__FIELD_KNOWN_TITLES, KNOWN_TITLES_SIZE * 2); SetObjectScale(1.0f); SetFloatValue(UNIT_FIELD_HOVERHEIGHT, 1.0f); @@ -16875,7 +16881,7 @@ bool Player::LoadFromDB(ObjectGuid guid, SQLQueryHolder *holder) GetByteValue(PLAYER_BYTES_2, 0), // facial hair GetByteValue(PLAYER_BYTES, 0))) // skin color { - TC_LOG_ERROR("entities.player", "Player %s has wrong Appearance values (Hair/Skin/Color), can't be loaded.", guid.ToString().c_str()); + TC_LOG_ERROR("entities.player", "Player %s has wrong Appearance values (Hair/Skin/Color) and can't be loaded.", guid.ToString().c_str()); return false; } @@ -16891,7 +16897,7 @@ bool Player::LoadFromDB(ObjectGuid guid, SQLQueryHolder *holder) InitDisplayIds(); - // cleanup inventory related item value fields (its will be filled correctly in _LoadInventory) + // cleanup inventory related item value fields (it will be filled correctly in _LoadInventory) for (uint8 slot = EQUIPMENT_SLOT_START; slot < EQUIPMENT_SLOT_END; ++slot) { SetGuidValue(PLAYER_FIELD_INV_SLOT_HEAD + (slot * 2), ObjectGuid::Empty); @@ -16901,7 +16907,7 @@ bool Player::LoadFromDB(ObjectGuid guid, SQLQueryHolder *holder) m_items[slot] = NULL; } - TC_LOG_DEBUG("entities.player.loading", "Load Basic value of player %s is: ", m_name.c_str()); + TC_LOG_DEBUG("entities.player.loading", "Load Basic values of player %s: ", m_name.c_str()); outDebugValues(); //Need to call it to initialize m_team (m_team can be calculated from race) @@ -16970,7 +16976,7 @@ bool Player::LoadFromDB(ObjectGuid guid, SQLQueryHolder *holder) MapEntry const* mapEntry = sMapStore.LookupEntry(mapId); if (!mapEntry || !IsPositionValid()) { - TC_LOG_ERROR("entities.player", "Player %s have invalid coordinates (MapId: %u X: %f Y: %f Z: %f O: %f). Teleport to default race/class locations.", + TC_LOG_ERROR("entities.player", "Player %s has invalid coordinates (MapId: %u X: %f Y: %f Z: %f O: %f). Teleporting player to default race/class location.", guid.ToString().c_str(), mapId, GetPositionX(), GetPositionY(), GetPositionZ(), GetOrientation()); RelocateToHomebind(); } @@ -17011,7 +17017,7 @@ bool Player::LoadFromDB(ObjectGuid guid, SQLQueryHolder *holder) //if (mapId == MAPID_INVALID) -- code kept for reference if (int16(mapId) == int16(-1)) // Battleground Entry Point not found (???) { - TC_LOG_ERROR("entities.player", "Player %s was in BG in database, but BG was not found, and entry point was invalid! Teleport to default race/class locations.", + TC_LOG_ERROR("entities.player", "Player %s was in BG in database, but BG was not found and entry point was invalid! Teleporting to default race/class locations.", guid.ToString().c_str()); RelocateToHomebind(); } @@ -17043,7 +17049,7 @@ bool Player::LoadFromDB(ObjectGuid guid, SQLQueryHolder *holder) std::fabs(m_movementInfo.transport.pos.GetPositionY()) > 250.0f || std::fabs(m_movementInfo.transport.pos.GetPositionZ()) > 250.0f) { - TC_LOG_ERROR("entities.player", "Player %s have invalid transport coordinates (X: %f Y: %f Z: %f O: %f). Teleport to bind location.", + TC_LOG_ERROR("entities.player", "Player %s has invalid transport coordinates (X: %f Y: %f Z: %f O: %f). Teleporting player to bind location.", guid.ToString().c_str(), x, y, z, o); m_movementInfo.transport.Reset(); @@ -17060,7 +17066,7 @@ bool Player::LoadFromDB(ObjectGuid guid, SQLQueryHolder *holder) } else { - TC_LOG_ERROR("entities.player", "Player %s have problems with transport guid (%u). Teleport to bind location.", + TC_LOG_ERROR("entities.player", "Player %s has problems with transport guid (%u). Teleporting to bind location.", guid.ToString().c_str(), transLowGUID); RelocateToHomebind(); @@ -17084,14 +17090,14 @@ bool Player::LoadFromDB(ObjectGuid guid, SQLQueryHolder *holder) if (uint32 node_id = m_taxi.GetTaxiSource()) nodeEntry = sTaxiNodesStore.LookupEntry(node_id); - if (!nodeEntry) // don't know taxi start node, to homebind + if (!nodeEntry) // don't know taxi start node, teleport to homebind { - TC_LOG_ERROR("entities.player", "Character %u have wrong data in taxi destination list, teleport to homebind.", GetGUID().GetCounter()); + TC_LOG_ERROR("entities.player", "Character %u has wrong data in taxi destination list. Teleporting player to homebind.", GetGUID().GetCounter()); RelocateToHomebind(); } - else // have start node, to it + else // has start node, teleport to it { - TC_LOG_ERROR("entities.player", "Character %u have too short taxi destination list, teleport to original node.", GetGUID().GetCounter()); + TC_LOG_ERROR("entities.player", "Character %u has too short taxi destination list. Teleporting player to original node.", GetGUID().GetCounter()); mapId = nodeEntry->map_id; Relocate(nodeEntry->x, nodeEntry->y, nodeEntry->z, 0.0f); } @@ -17120,7 +17126,7 @@ bool Player::LoadFromDB(ObjectGuid guid, SQLQueryHolder *holder) { if (GetSession()->Expansion() < mapEntry->Expansion()) { - TC_LOG_DEBUG("entities.player.loading", "Player %s using client without required expansion tried login at non accessible map %u", GetName().c_str(), mapId); + TC_LOG_DEBUG("entities.player.loading", "Player %s is using client without required expansion, tried to log in to inaccessible map %u.", GetName().c_str(), mapId); RelocateToHomebind(); } @@ -17250,7 +17256,7 @@ bool Player::LoadFromDB(ObjectGuid guid, SQLQueryHolder *holder) m_stableSlots = fields[32].GetUInt8(); if (m_stableSlots > MAX_PET_STABLES) { - TC_LOG_ERROR("entities.player", "Player can have not more %u stable slots, but have in DB %u", MAX_PET_STABLES, uint32(m_stableSlots)); + TC_LOG_ERROR("entities.player", "Player can not have more than %u stable slots, but has %u in DB.", MAX_PET_STABLES, uint32(m_stableSlots)); m_stableSlots = MAX_PET_STABLES; } @@ -17258,7 +17264,7 @@ bool Player::LoadFromDB(ObjectGuid guid, SQLQueryHolder *holder) if (HasAtLoginFlag(AT_LOGIN_RENAME)) { - TC_LOG_ERROR("entities.player", "Player (GUID: %u) tried to login while forced to rename, can't load.'", GetGUID().GetCounter()); + TC_LOG_ERROR("entities.player", "Player (GUID: %u) tried to login while forced to rename, could not load player.", GetGUID().GetCounter()); return false; } @@ -17545,9 +17551,9 @@ void Player::_LoadActions(PreparedQueryResult result) ab->uState = ACTIONBUTTON_UNCHANGED; else { - TC_LOG_ERROR("entities.player", " ...at loading, and will deleted in DB also"); + TC_LOG_ERROR("entities.player", " ...at loading, and will also be deleted in DB."); - // Will deleted in DB at next save (it can create data until save but marked as deleted) + // Will be deleted in DB at next save (it can create data until save but marked as deleted). m_actionButtons[button].uState = ACTIONBUTTON_DELETED; } } while (result->NextRow()); @@ -17556,7 +17562,7 @@ void Player::_LoadActions(PreparedQueryResult result) void Player::_LoadAuras(PreparedQueryResult result, uint32 timediff) { - TC_LOG_DEBUG("entities.player.loading", "Loading auras for player %u", GetGUID().GetCounter()); + TC_LOG_DEBUG("entities.player.loading", "Loading auras for player %u.", GetGUID().GetCounter()); /* 0 1 2 3 4 5 6 7 8 9 10 QueryResult* result = CharacterDatabase.PQuery("SELECT casterGuid, spell, effectMask, recalculateMask, stackCount, amount0, amount1, amount2, base_amount0, base_amount1, base_amount2, @@ -17589,7 +17595,7 @@ void Player::_LoadAuras(PreparedQueryResult result, uint32 timediff) SpellInfo const* spellInfo = sSpellMgr->GetSpellInfo(spellid); if (!spellInfo) { - TC_LOG_ERROR("entities.player", "Unknown aura (spellid %u), ignore.", spellid); + TC_LOG_ERROR("entities.player", "Unknown aura (spellid %u), ignored.", spellid); continue; } @@ -17623,7 +17629,7 @@ void Player::_LoadAuras(PreparedQueryResult result, uint32 timediff) aura->SetLoadedState(maxduration, remaintime, remaincharges, stackcount, recalculatemask, &damage[0]); aura->ApplyForTargets(); - TC_LOG_DEBUG("entities.player", "Added aura spellid %u, effectmask %u", spellInfo->Id, effmask); + TC_LOG_DEBUG("entities.player", "Added aura spellid %u, effectmask %u.", spellInfo->Id, effmask); } } while (result->NextRow()); @@ -17649,10 +17655,10 @@ void Player::_LoadGlyphAuras() TC_LOG_ERROR("entities.player", "Player %s has glyph with typeflags %u in slot with typeflags %u, removing.", m_name.c_str(), gp->TypeFlags, gs->TypeFlags); } else - TC_LOG_ERROR("entities.player", "Player %s has not existing glyph slot entry %u on index %u", m_name.c_str(), GetGlyphSlot(i), i); + TC_LOG_ERROR("entities.player", "Player %s has non-existing glyph slot entry %u on index %u.", m_name.c_str(), GetGlyphSlot(i), i); } else - TC_LOG_ERROR("entities.player", "Player %s has not existing glyph entry %u on index %u", m_name.c_str(), glyph, i); + TC_LOG_ERROR("entities.player", "Player %s has non-existing glyph entry %u on index %u.", m_name.c_str(), glyph, i); // On any error remove glyph SetGlyph(i, 0); @@ -17782,7 +17788,7 @@ void Player::_LoadInventory(PreparedQueryResult result, uint32 timeDiff) item->SetState(ITEM_UNCHANGED, this); else { - TC_LOG_ERROR("entities.player", "Player::_LoadInventory: player (GUID: %u, name: '%s') has item (GUID: %u, entry: %u) which can't be loaded into inventory (Bag GUID: %u, slot: %u) by reason %u. Item will be sent by mail.", + TC_LOG_ERROR("entities.player", "Player::_LoadInventory: player (GUID: %u, name: '%s') has item (GUID: %u, entry: %u) which can't be loaded into inventory (Bag GUID: %u, slot: %u) for reason %u. Item will be sent by mail.", GetGUID().GetCounter(), GetName().c_str(), item->GetGUID().GetCounter(), item->GetEntry(), bagGuid, slot, err); item->DeleteFromInventoryDB(trans); problematicItems.push_back(item); @@ -17915,7 +17921,7 @@ Item* Player::_LoadItem(SQLTransaction& trans, uint32 zoneId, uint32 timeDiff, F } else { - TC_LOG_ERROR("entities.player", "Player::_LoadInventory: player (GUID: %u, name: '%s') has broken item (GUID: %u, entry: %u) in inventory. Deleting item.", + TC_LOG_ERROR("entities.player", "Player::_LoadInventory: player (GUID: %u, name: '%s') has a broken item (GUID: %u, entry: %u) in inventory. Deleting item.", GetGUID().GetCounter(), GetName().c_str(), itemGuid, itemEntry); remove = true; } @@ -17930,7 +17936,7 @@ Item* Player::_LoadItem(SQLTransaction& trans, uint32 zoneId, uint32 timeDiff, F } else { - TC_LOG_ERROR("entities.player", "Player::_LoadInventory: player (GUID: %u, name: '%s') has unknown item (entry: %u) in inventory. Deleting item.", + TC_LOG_ERROR("entities.player", "Player::_LoadInventory: player (GUID: %u, name: '%s') has an unknown item (entry: %u) in inventory. Deleting item.", GetGUID().GetCounter(), GetName().c_str(), itemEntry); Item::DeleteFromInventoryDB(trans, itemGuid); Item::DeleteFromDB(trans, itemGuid); @@ -17961,7 +17967,7 @@ void Player::_LoadMailedItems(Mail* mail) if (!proto) { - TC_LOG_ERROR("entities.player", "Player %u has unknown item_template (ProtoType) in mailed items(GUID: %u template: %u) in mail (%u), deleted.", GetGUID().GetCounter(), itemGuid, itemTemplate, mail->messageID); + TC_LOG_ERROR("entities.player", "Player %u has an unknown item_template (ProtoType) in mailed items(GUID: %u template: %u) in mail (%u), deleted.", GetGUID().GetCounter(), itemGuid, itemTemplate, mail->messageID); stmt = CharacterDatabase.GetPreparedStatement(CHAR_DEL_INVALID_MAIL_ITEM); stmt->setUInt32(0, itemGuid); @@ -17977,7 +17983,7 @@ void Player::_LoadMailedItems(Mail* mail) if (!item->LoadFromDB(itemGuid, ObjectGuid(HighGuid::Player, fields[13].GetUInt32()), fields, itemTemplate)) { - TC_LOG_ERROR("entities.player", "Player::_LoadMailedItems - Item in mail (%u) doesn't exist !!!! - item guid: %u, deleted from mail", mail->messageID, itemGuid); + TC_LOG_ERROR("entities.player", "Player::_LoadMailedItems - Item in mail (%u) doesn't exist!!! - item guid: %u, deleted from mail.", mail->messageID, itemGuid); stmt = CharacterDatabase.GetPreparedStatement(CHAR_DEL_MAIL_ITEM); stmt->setUInt32(0, itemGuid); @@ -18040,7 +18046,7 @@ void Player::_LoadMail() if (m->mailTemplateId && !sMailTemplateStore.LookupEntry(m->mailTemplateId)) { - TC_LOG_ERROR("entities.player", "Player::_LoadMail - Mail (%u) have not existed MailTemplateId (%u), remove at load", m->messageID, m->mailTemplateId); + TC_LOG_ERROR("entities.player", "Player::_LoadMail - Mail (%u) contains a non-existing MailTemplateId (%u), removing at load.", m->messageID, m->mailTemplateId); m->mailTemplateId = 0; } @@ -18221,7 +18227,7 @@ void Player::_LoadDailyQuestStatus(PreparedQueryResult result) if (quest_daily_idx >= PLAYER_MAX_DAILY_QUESTS) // max amount with exist data in query { - TC_LOG_ERROR("entities.player", "Player (GUID: %u) have more 25 daily quest records in `charcter_queststatus_daily`", GetGUID().GetCounter()); + TC_LOG_ERROR("entities.player", "Player (GUID: %u) has more than 25 daily quest records in `charcter_queststatus_daily`", GetGUID().GetCounter()); break; } @@ -18370,8 +18376,9 @@ void Player::_LoadBoundInstances(PreparedQueryResult result) uint32 mapId = fields[2].GetUInt16(); uint32 instanceId = fields[0].GetUInt32(); uint8 difficulty = fields[3].GetUInt8(); + BindExtensionState extendState = BindExtensionState(fields[4].GetUInt8()); - time_t resetTime = time_t(fields[4].GetUInt32()); + time_t resetTime = time_t(fields[5].GetUInt32()); // the resettime for normal instances is only saved when the InstanceSave is unloaded // so the value read from the DB may be wrong here but only if the InstanceSave is loaded // and in that case it is not used @@ -18383,12 +18390,12 @@ void Player::_LoadBoundInstances(PreparedQueryResult result) if (!mapEntry || !mapEntry->IsDungeon()) { - TC_LOG_ERROR("entities.player", "_LoadBoundInstances: player %s(%d) has bind to not existed or not dungeon map %d (%s)", GetName().c_str(), GetGUID().GetCounter(), mapId, mapname.c_str()); + TC_LOG_ERROR("entities.player", "_LoadBoundInstances: player %s(%d) has bind to a non-existing or non-dungeon map %d (%s).", GetName().c_str(), GetGUID().GetCounter(), mapId, mapname.c_str()); deleteInstance = true; } else if (difficulty >= MAX_DIFFICULTY) { - TC_LOG_ERROR("entities.player", "_LoadBoundInstances: player %s(%d) has bind to not existed difficulty %d instance for map %u (%s)", GetName().c_str(), GetGUID().GetCounter(), difficulty, mapId, mapname.c_str()); + TC_LOG_ERROR("entities.player", "_LoadBoundInstances: player %s(%d) has a bind to a non-existing difficulty %d instance for map %u (%s)", GetName().c_str(), GetGUID().GetCounter(), difficulty, mapId, mapname.c_str()); deleteInstance = true; } else @@ -18396,12 +18403,12 @@ void Player::_LoadBoundInstances(PreparedQueryResult result) MapDifficulty const* mapDiff = GetMapDifficultyData(mapId, Difficulty(difficulty)); if (!mapDiff) { - TC_LOG_ERROR("entities.player", "_LoadBoundInstances: player %s(%d) has bind to not existed difficulty %d instance for map %u (%s)", GetName().c_str(), GetGUID().GetCounter(), difficulty, mapId, mapname.c_str()); + TC_LOG_ERROR("entities.player", "_LoadBoundInstances: player %s(%d) has a bind to a non-existing difficulty %d instance for map %u (%s).", GetName().c_str(), GetGUID().GetCounter(), difficulty, mapId, mapname.c_str()); deleteInstance = true; } else if (!perm && group) { - TC_LOG_ERROR("entities.player", "_LoadBoundInstances: player %s(%d) is in group %d but has a non-permanent character bind to map %d (%s), %d, %d", GetName().c_str(), GetGUID().GetCounter(), group->GetLowGUID(), mapId, mapname.c_str(), instanceId, difficulty); + TC_LOG_ERROR("entities.player", "_LoadBoundInstances: player %s(%d) is in group %d, but has a non-permanent character bind to map %d (%s), %d, %d.", GetName().c_str(), GetGUID().GetCounter(), group->GetLowGUID(), mapId, mapname.c_str(), instanceId, difficulty); deleteInstance = true; } } @@ -18420,13 +18427,13 @@ void Player::_LoadBoundInstances(PreparedQueryResult result) // since non permanent binds are always solo bind, they can always be reset if (InstanceSave* save = sInstanceSaveMgr->AddInstanceSave(mapId, instanceId, Difficulty(difficulty), resetTime, !perm, true)) - BindToInstance(save, perm, true); + BindToInstance(save, perm, extendState, true); } while (result->NextRow()); } } -InstancePlayerBind* Player::GetBoundInstance(uint32 mapid, Difficulty difficulty) +InstancePlayerBind* Player::GetBoundInstance(uint32 mapid, Difficulty difficulty, bool withExpired) { // some instances only have one difficulty MapDifficulty const* mapDiff = GetDownscaledMapDifficultyData(mapid, difficulty); @@ -18435,9 +18442,9 @@ InstancePlayerBind* Player::GetBoundInstance(uint32 mapid, Difficulty difficulty BoundInstancesMap::iterator itr = m_boundInstances[difficulty].find(mapid); if (itr != m_boundInstances[difficulty].end()) - return &itr->second; - else - return NULL; + if (itr->second.extendState || withExpired) + return &itr->second; + return nullptr; } InstanceSave* Player::GetInstanceSave(uint32 mapid, bool raid) @@ -18480,24 +18487,32 @@ void Player::UnbindInstance(BoundInstancesMap::iterator &itr, Difficulty difficu } } -InstancePlayerBind* Player::BindToInstance(InstanceSave* save, bool permanent, bool load) +InstancePlayerBind* Player::BindToInstance(InstanceSave* save, bool permanent, BindExtensionState extendState, bool load) { if (save) { InstancePlayerBind& bind = m_boundInstances[save->GetDifficulty()][save->GetMapId()]; + if (extendState == EXTEND_STATE_KEEP) // special flag, keep the player's current extend state when updating for new boss down + { + if (save == bind.save) + extendState = bind.extendState; + else + extendState = EXTEND_STATE_NORMAL; + } if (!load) { if (bind.save) { // update the save when the group kills a boss - if (permanent != bind.perm || save != bind.save) + if (permanent != bind.perm || save != bind.save || extendState != bind.extendState) { PreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_UPD_CHAR_INSTANCE); stmt->setUInt32(0, save->GetInstanceId()); stmt->setBool(1, permanent); - stmt->setUInt32(2, GetGUID().GetCounter()); - stmt->setUInt32(3, bind.save->GetInstanceId()); + stmt->setUInt8(2, extendState); + stmt->setUInt32(3, GetGUID().GetCounter()); + stmt->setUInt32(4, bind.save->GetInstanceId()); CharacterDatabase.Execute(stmt); } @@ -18509,6 +18524,7 @@ InstancePlayerBind* Player::BindToInstance(InstanceSave* save, bool permanent, b stmt->setUInt32(0, GetGUID().GetCounter()); stmt->setUInt32(1, save->GetInstanceId()); stmt->setBool(2, permanent); + stmt->setUInt8(3, extendState); CharacterDatabase.Execute(stmt); } @@ -18526,9 +18542,10 @@ InstancePlayerBind* Player::BindToInstance(InstanceSave* save, bool permanent, b bind.save = save; bind.perm = permanent; + bind.extendState = extendState; if (!load) TC_LOG_DEBUG("maps", "Player::BindToInstance: %s(%d) is now bound to map %d, instance %d, difficulty %d", GetName().c_str(), GetGUID().GetCounter(), save->GetMapId(), save->GetInstanceId(), save->GetDifficulty()); - sScriptMgr->OnPlayerBindToInstance(this, save->GetDifficulty(), save->GetMapId(), permanent); + sScriptMgr->OnPlayerBindToInstance(this, save->GetDifficulty(), save->GetMapId(), permanent, uint8(extendState)); return &bind; } @@ -18546,7 +18563,7 @@ void Player::BindToInstance() GetSession()->SendPacket(&data); if (!IsGameMaster()) { - BindToInstance(mapSave, true); + BindToInstance(mapSave, true, EXTEND_STATE_KEEP); GetSession()->SendCalendarRaidLockout(mapSave, true); } } @@ -18572,15 +18589,19 @@ void Player::SendRaidInfo() { for (BoundInstancesMap::iterator itr = m_boundInstances[i].begin(); itr != m_boundInstances[i].end(); ++itr) { - if (itr->second.perm) - { - InstanceSave* save = itr->second.save; - data << uint32(save->GetMapId()); // map id - data << uint32(save->GetDifficulty()); // difficulty - data << uint64(save->GetInstanceId()); // instance id - data << uint8(1); // expired = 0 - data << uint8(0); // extended = 1 - data << uint32(save->GetResetTime() - now); // reset time + InstancePlayerBind const& bind = itr->second; + if (bind.perm) + { + InstanceSave* save = bind.save; + data << uint32(save->GetMapId()); // map id + data << uint32(save->GetDifficulty()); // difficulty + data << uint64(save->GetInstanceId()); // instance id + data << uint8(bind.extendState != EXTEND_STATE_EXPIRED); // expired = 0 + data << uint8(bind.extendState == EXTEND_STATE_EXTENDED); // extended = 1 + time_t nextReset = save->GetResetTime(); + if (bind.extendState == EXTEND_STATE_EXTENDED) + nextReset = sInstanceSaveMgr->GetSubsequentResetTime(save->GetMapId(), save->GetDifficulty(), save->GetResetTime()); + data << uint32(nextReset - now); // reset time ++counter; } } @@ -19298,7 +19319,7 @@ void Player::_SaveInventory(SQLTransaction& trans) } else { - TC_LOG_ERROR("entities.player", "Can't find %s but is in refundable storage for player %u ! Removing.", itr->ToString().c_str(), GetGUID().GetCounter()); + TC_LOG_ERROR("entities.player", "Can't find %s, but is in refundable storage for player %u ! Removing.", itr->ToString().c_str(), GetGUID().GetCounter()); m_refundableItems.erase(itr); } } @@ -19347,7 +19368,7 @@ void Player::_SaveInventory(SQLTransaction& trans) { TC_LOG_ERROR("entities.player", "Player(GUID: %u Name: %s)::_SaveInventory - the bag(%u) and slot(%u) values for the item with guid %u are incorrect, the item with guid %u is there instead!", lowGuid, GetName().c_str(), item->GetBagSlot(), item->GetSlot(), item->GetGUID().GetCounter(), test->GetGUID().GetCounter()); // save all changes to the item... - if (item->GetState() != ITEM_NEW) // only for existing items, no dupes + if (item->GetState() != ITEM_NEW) // only for existing items, no duplicates item->SaveToDB(trans); // ...but do not save position in invntory continue; @@ -20106,8 +20127,8 @@ Pet* Player::GetPet() const if (IsInWorld() && pet) return pet; - //there may be a guardian in slot - //TC_LOG_ERROR("entities.player", "Player::GetPet: Pet %u not exist.", GUID_LOPART(pet_guid)); + // there may be a guardian in this slot + //TC_LOG_ERROR("entities.player", "Player::GetPet: Pet %u does not exist.", GUID_LOPART(pet_guid)); //const_cast<Player*>(this)->SetPetGUID(0); } @@ -20215,7 +20236,7 @@ void Player::StopCastingCharm() if (GetCharmGUID()) { - TC_LOG_FATAL("entities.player", "Player %s (%s) is not able to uncharm unit (%s)", GetName().c_str(), GetGUID().ToString().c_str(), GetCharmGUID().ToString().c_str()); + TC_LOG_FATAL("entities.player", "Player %s (%s) is not able to uncharm unit (%s)!", GetName().c_str(), GetGUID().ToString().c_str(), GetCharmGUID().ToString().c_str()); if (charm->GetCharmerGUID()) { TC_LOG_FATAL("entities.player", "Charmed unit has charmer %s", charm->GetCharmerGUID().ToString().c_str()); @@ -21320,7 +21341,7 @@ bool Player::BuyItemFromVendorSlot(ObjectGuid vendorguid, uint32 vendorslot, uin ItemExtendedCostEntry const* iece = sItemExtendedCostStore.LookupEntry(crItem->ExtendedCost); if (!iece) { - TC_LOG_ERROR("entities.player", "Item %u have wrong ExtendedCost field value %u", pProto->ItemId, crItem->ExtendedCost); + TC_LOG_ERROR("entities.player", "Item %u has wrong ExtendedCost field value %u", pProto->ItemId, crItem->ExtendedCost); return false; } @@ -21363,7 +21384,7 @@ bool Player::BuyItemFromVendorSlot(ObjectGuid vendorguid, uint32 vendorslot, uin uint32 maxCount = MAX_MONEY_AMOUNT / pProto->BuyPrice; if ((uint32)count > maxCount) { - TC_LOG_ERROR("entities.player", "Player %s tried to buy %u item id %u, causing overflow", GetName().c_str(), (uint32)count, pProto->ItemId); + TC_LOG_ERROR("entities.player", "Player %s tried to buy %u item id %u, causing overflow.", GetName().c_str(), (uint32)count, pProto->ItemId); count = (uint8)maxCount; } price = pProto->BuyPrice * count; //it should not exceed MAX_MONEY_AMOUNT @@ -21457,7 +21478,7 @@ void Player::UpdateHomebindTime(uint32 time) data << uint32(m_HomebindTimer); data << uint32(1); GetSession()->SendPacket(&data); - TC_LOG_DEBUG("maps", "PLAYER: Player '%s' (GUID: %u) will be teleported to homebind in 60 seconds", GetName().c_str(), GetGUID().GetCounter()); + TC_LOG_DEBUG("maps", "PLAYER: Player '%s' (GUID: %u) will be teleported to homebind in 60 seconds.", GetName().c_str(), GetGUID().GetCounter()); } } @@ -21527,7 +21548,7 @@ void Player::UpdatePotionCooldown(Spell* spell) // Call not from spell cast, send cooldown event for item spells if no in combat if (!spell) { - // spell/item pair let set proper cooldown (except not existed charged spell cooldown spellmods for potions) + // spell/item pair let set proper cooldown (except non-existing charged spell cooldown spellmods for potions) if (ItemTemplate const* proto = sObjectMgr->GetItemTemplate(m_lastPotionId)) for (uint8 idx = 0; idx < MAX_ITEM_PROTO_SPELLS; ++idx) if (proto->Spells[idx].SpellId && proto->Spells[idx].SpellTrigger == ITEM_SPELLTRIGGER_ON_USE) @@ -23222,7 +23243,7 @@ bool Player::HasItemFitToSpellRequirements(SpellInfo const* spellInfo, Item cons break; } default: - TC_LOG_ERROR("entities.player", "HasItemFitToSpellRequirements: Not handled spell requirement for item class %u", spellInfo->EquippedItemClass); + TC_LOG_ERROR("entities.player", "HasItemFitToSpellRequirements: Spell requirement not handled for item class %u", spellInfo->EquippedItemClass); break; } @@ -23874,7 +23895,7 @@ void Player::SetViewpoint(WorldObject* target, bool apply) { if (apply) { - TC_LOG_DEBUG("maps", "Player::CreateViewpoint: Player %s create seer %u (TypeId: %u).", GetName().c_str(), target->GetEntry(), target->GetTypeId()); + TC_LOG_DEBUG("maps", "Player::CreateViewpoint: Player %s created seer %u (TypeId: %u).", GetName().c_str(), target->GetEntry(), target->GetTypeId()); if (!AddGuidValue(PLAYER_FARSIGHT, target->GetGUID())) { @@ -23890,7 +23911,7 @@ void Player::SetViewpoint(WorldObject* target, bool apply) } else { - TC_LOG_DEBUG("maps", "Player::CreateViewpoint: Player %s remove seer", GetName().c_str()); + TC_LOG_DEBUG("maps", "Player::CreateViewpoint: Player %s removed seer", GetName().c_str()); if (!RemoveGuidValue(PLAYER_FARSIGHT, target->GetGUID())) { @@ -24109,38 +24130,6 @@ bool Player::isTotalImmunity() return false; } -void Player::UpdateCharmedAI() -{ - //This should only called in Player::Update - Creature* charmer = GetCharmer()->ToCreature(); - - //kill self if charm aura has infinite duration - if (charmer->IsInEvadeMode()) - { - AuraEffectList const& auras = GetAuraEffectsByType(SPELL_AURA_MOD_CHARM); - for (AuraEffectList::const_iterator iter = auras.begin(); iter != auras.end(); ++iter) - if ((*iter)->GetCasterGUID() == charmer->GetGUID() && (*iter)->GetBase()->IsPermanent()) - { - charmer->DealDamage(this, GetHealth(), NULL, DIRECT_DAMAGE, SPELL_SCHOOL_MASK_NORMAL, NULL, false); - return; - } - } - - if (!charmer->IsInCombat()) - GetMotionMaster()->MoveFollow(charmer, PET_FOLLOW_DIST, PET_FOLLOW_ANGLE); - - Unit* target = GetVictim(); - if (!target || !charmer->IsValidAttackTarget(target)) - { - target = charmer->SelectNearestTarget(); - if (!target) - return; - - GetMotionMaster()->MoveChase(target); - Attack(target, true); - } -} - uint32 Player::GetRuneBaseCooldown(uint8 index) { uint8 rune = GetBaseRune(index); @@ -24471,7 +24460,7 @@ void Player::_LoadSkills(PreparedQueryResult result) if (value == 0) { - TC_LOG_ERROR("entities.player", "Character %u has skill %u with value 0. Will be deleted.", GetGUID().GetCounter(), skill); + TC_LOG_ERROR("entities.player", "Character %u has skill %u with value 0. Skill will be deleted.", GetGUID().GetCounter(), skill); PreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_DEL_CHARACTER_SKILL); @@ -24808,7 +24797,7 @@ void Player::LearnTalent(uint32 talentId, uint32 talentRank) uint32 spellid = talentInfo->RankID[talentRank]; if (spellid == 0) { - TC_LOG_ERROR("entities.player", "Talent.dbc have for talent: %u Rank: %u spell id = 0", talentId, talentRank); + TC_LOG_ERROR("entities.player", "Talent.dbc contains talent: %u Rank: %u spell id = 0", talentId, talentRank); return; } @@ -24945,7 +24934,7 @@ void Player::LearnPetTalent(ObjectGuid petGuid, uint32 talentId, uint32 talentRa uint32 spellid = talentInfo->RankID[talentRank]; if (spellid == 0) { - TC_LOG_ERROR("entities.player", "Talent.dbc have for talent: %u Rank: %u spell id = 0", talentId, talentRank); + TC_LOG_ERROR("entities.player", "Talent.dbc contains talent: %u Rank: %u spell id = 0", talentId, talentRank); return; } @@ -25272,7 +25261,7 @@ void Player::SetEquipmentSet(uint32 index, EquipmentSet eqset) if (!found) // something wrong... { - TC_LOG_ERROR("entities.player", "Player %s tried to save equipment set " UI64FMTD " (index %u), but that equipment set not found!", GetName().c_str(), eqset.Guid, index); + TC_LOG_ERROR("entities.player", "Player %s tried to save equipment set " UI64FMTD " (index %u), but that equipment set was not found!", GetName().c_str(), eqset.Guid, index); return; } } @@ -25615,7 +25604,7 @@ void Player::ActivateSpec(uint8 spec) for (int8 rank = MAX_TALENT_RANK-1; rank >= 0; --rank) { - // skip non-existant talent ranks + // skip non-existing talent ranks if (talentInfo->RankID[rank] == 0) continue; RemoveSpell(talentInfo->RankID[rank], true); // removes the talent, and all dependant, learned, and chained spells.. @@ -25659,7 +25648,7 @@ void Player::ActivateSpec(uint8 spec) // learn highest talent rank that exists in newly activated spec for (int8 rank = MAX_TALENT_RANK-1; rank >= 0; --rank) { - // skip non-existant talent ranks + // skip non-existing talent ranks if (talentInfo->RankID[rank] == 0) continue; // if the talent can be found in the newly activated PlayerTalentMap @@ -26154,11 +26143,11 @@ std::string Player::GetMapAreaAndZoneString() uint32 areaId = GetAreaId(); std::string areaName = "Unknown"; std::string zoneName = "Unknown"; - if (AreaTableEntry const* area = GetAreaEntryByAreaID(areaId)) + if (AreaTableEntry const* area = sAreaTableStore.LookupEntry(areaId)) { int locale = GetSession()->GetSessionDbcLocale(); areaName = area->area_name[locale]; - if (AreaTableEntry const* zone = GetAreaEntryByAreaID(area->zone)) + if (AreaTableEntry const* zone = sAreaTableStore.LookupEntry(area->zone)) zoneName = zone->area_name[locale]; } @@ -26215,7 +26204,7 @@ Pet* Player::SummonPet(uint32 entry, float x, float y, float z, float ang, PetTy pet->Relocate(x, y, z, ang); if (!pet->IsPositionValid()) { - TC_LOG_ERROR("misc", "Pet (guidlow %d, entry %d) not summoned. Suggested coordinates isn't valid (X: %f Y: %f)", pet->GetGUID().GetCounter(), pet->GetEntry(), pet->GetPositionX(), pet->GetPositionY()); + TC_LOG_ERROR("misc", "Pet (guidlow %d, entry %d) not summoned. Suggested coordinates are not valid (X: %f Y: %f)", pet->GetGUID().GetCounter(), pet->GetEntry(), pet->GetPositionX(), pet->GetPositionY()); delete pet; return NULL; } @@ -26224,7 +26213,7 @@ Pet* Player::SummonPet(uint32 entry, float x, float y, float z, float ang, PetTy uint32 pet_number = sObjectMgr->GeneratePetNumber(); if (!pet->Create(map->GenerateLowGuid<HighGuid::Pet>(), map, GetPhaseMask(), entry, pet_number)) { - TC_LOG_ERROR("misc", "no such creature entry %u", entry); + TC_LOG_ERROR("misc", "No such creature entry %u", entry); delete pet; return NULL; } diff --git a/src/server/game/Entities/Player/Player.h b/src/server/game/Entities/Player/Player.h index 9b64023698c..0d6d21c6b28 100644 --- a/src/server/game/Entities/Player/Player.h +++ b/src/server/game/Entities/Player/Player.h @@ -54,6 +54,7 @@ class PlayerMenu; class PlayerSocial; class SpellCastTargets; class UpdateMask; +class PlayerAI; struct CharacterCustomizeInfo; @@ -834,14 +835,27 @@ enum PlayerDelayedOperations // Maximum money amount : 2^31 - 1 extern uint32 const MAX_MONEY_AMOUNT; +enum BindExtensionState +{ + EXTEND_STATE_EXPIRED = 0, + EXTEND_STATE_NORMAL = 1, + EXTEND_STATE_EXTENDED = 2, + EXTEND_STATE_KEEP = 255 // special state: keep current save type +}; struct InstancePlayerBind { InstanceSave* save; - bool perm; /* permanent PlayerInstanceBinds are created in Raid/Heroic instances for players - that aren't already permanently bound when they are inside when a boss is killed - or when they enter an instance that the group leader is permanently bound to. */ - InstancePlayerBind() : save(NULL), perm(false) { } + that aren't already permanently bound when they are inside when a boss is killed + or when they enter an instance that the group leader is permanently bound to. */ + bool perm; + /* extend state listing: + EXPIRED - doesn't affect anything unless manually re-extended by player + NORMAL - standard state + EXTENDED - won't be promoted to EXPIRED at next reset period, will instead be promoted to NORMAL */ + BindExtensionState extendState; + + InstancePlayerBind() : save(NULL), perm(false), extendState(EXTEND_STATE_NORMAL) { } }; struct AccessRequirement @@ -1009,6 +1023,8 @@ class Player : public Unit, public GridObject<Player> explicit Player(WorldSession* session); ~Player(); + PlayerAI* AI() const { return reinterpret_cast<PlayerAI*>(i_AI); } + void CleanupsBeforeDelete(bool finalCleanup = true) override; void AddToWorld() override; @@ -2115,12 +2131,12 @@ class Player : public Unit, public GridObject<Player> bool m_InstanceValid; // permanent binds and solo binds by difficulty BoundInstancesMap m_boundInstances[MAX_DIFFICULTY]; - InstancePlayerBind* GetBoundInstance(uint32 mapid, Difficulty difficulty); + InstancePlayerBind* GetBoundInstance(uint32 mapid, Difficulty difficulty, bool withExpired = false); BoundInstancesMap& GetBoundInstances(Difficulty difficulty) { return m_boundInstances[difficulty]; } InstanceSave* GetInstanceSave(uint32 mapid, bool raid); void UnbindInstance(uint32 mapid, Difficulty difficulty, bool unload = false); void UnbindInstance(BoundInstancesMap::iterator &itr, Difficulty difficulty, bool unload = false); - InstancePlayerBind* BindToInstance(InstanceSave* save, bool permanent, bool load = false); + InstancePlayerBind* BindToInstance(InstanceSave* save, bool permanent, BindExtensionState extendState = EXTEND_STATE_NORMAL, bool load = false); void BindToInstance(); void SetPendingBind(uint32 instanceId, uint32 bindTimer); bool HasPendingBind() const { return _pendingBindId > 0; } @@ -2520,8 +2536,6 @@ class Player : public Unit, public GridObject<Player> MapReference m_mapRef; - void UpdateCharmedAI(); - uint32 m_lastFallTime; float m_lastFallZ; diff --git a/src/server/game/Entities/Unit/Unit.cpp b/src/server/game/Entities/Unit/Unit.cpp index 3aed5fde7b3..b6272b81693 100644 --- a/src/server/game/Entities/Unit/Unit.cpp +++ b/src/server/game/Entities/Unit/Unit.cpp @@ -45,6 +45,7 @@ #include "PetAI.h" #include "Pet.h" #include "Player.h" +#include "PlayerAI.h" #include "QuestDef.h" #include "ReputationMgr.h" #include "SpellAuraEffects.h" @@ -3748,6 +3749,77 @@ void Unit::RemoveAura(Aura* aura, AuraRemoveMode mode) RemoveAura(aurApp, mode); } +void Unit::RemoveAppliedAuras(std::function<bool(AuraApplication const*)> const& check) +{ + for (AuraApplicationMap::iterator iter = m_appliedAuras.begin(); iter != m_appliedAuras.end();) + { + if (check(iter->second)) + { + RemoveAura(iter); + continue; + } + ++iter; + } +} + +void Unit::RemoveOwnedAuras(std::function<bool(Aura const*)> const& check) +{ + for (AuraMap::iterator iter = m_ownedAuras.begin(); iter != m_ownedAuras.end();) + { + if (check(iter->second)) + { + RemoveOwnedAura(iter); + continue; + } + ++iter; + } +} + +void Unit::RemoveAppliedAuras(uint32 spellId, std::function<bool(AuraApplication const*)> const& check) +{ + for (AuraApplicationMap::iterator iter = m_appliedAuras.lower_bound(spellId); iter != m_appliedAuras.upper_bound(spellId);) + { + if (check(iter->second)) + { + RemoveAura(iter); + continue; + } + ++iter; + } +} + +void Unit::RemoveOwnedAuras(uint32 spellId, std::function<bool(Aura const*)> const& check) +{ + for (AuraMap::iterator iter = m_ownedAuras.lower_bound(spellId); iter != m_ownedAuras.upper_bound(spellId);) + { + if (check(iter->second)) + { + RemoveOwnedAura(iter); + continue; + } + ++iter; + } +} + +void Unit::RemoveAurasByType(AuraType auraType, std::function<bool(AuraApplication const*)> const& check) +{ + for (AuraEffectList::iterator iter = m_modAuras[auraType].begin(); iter != m_modAuras[auraType].end();) + { + Aura* aura = (*iter)->GetBase(); + AuraApplication * aurApp = aura->GetApplicationOfTarget(GetGUID()); + ASSERT(aurApp); + + ++iter; + if (check(aurApp)) + { + uint32 removedAuras = m_removedAurasCount; + RemoveAura(aurApp); + if (m_removedAurasCount > removedAuras + 1) + iter = m_modAuras[auraType].begin(); + } + } +} + void Unit::RemoveAurasDueToSpell(uint32 spellId, ObjectGuid casterGUID, uint8 reqEffMask, AuraRemoveMode removeMode) { for (AuraApplicationMap::iterator iter = m_appliedAuras.lower_bound(spellId); iter != m_appliedAuras.upper_bound(spellId);) @@ -4355,13 +4427,10 @@ void Unit::GetDispellableAuraList(Unit* caster, uint32 dispelMask, DispelCharges if (aura->GetSpellInfo()->GetDispelMask() & dispelMask) { - if (aura->GetSpellInfo()->Dispel == DISPEL_MAGIC) - { - // do not remove positive auras if friendly target - // negative auras if non-friendly target - if (aurApp->IsPositive() == IsFriendlyTo(caster)) - continue; - } + // do not remove positive auras if friendly target + // negative auras if non-friendly target + if (aurApp->IsPositive() == IsFriendlyTo(caster)) + continue; // The charges / stack amounts don't count towards the total number of auras that can be dispelled. // Ie: A dispel on a target with 5 stacks of Winters Chill and a Polymorph has 1 / (1 + 1) -> 50% chance to dispell @@ -8328,8 +8397,6 @@ bool Unit::HandleProcTriggerSpell(Unit* victim, uint32 damage, AuraEffect* trigg case 52914: case 52915: case 52910: - // Honor Among Thieves - case 52916: { target = triggeredByAura->GetBase()->GetCaster(); if (!target) @@ -8985,10 +9052,10 @@ bool Unit::Attack(Unit* victim, bool meleeAttack) if (GetTypeId() == TYPEID_UNIT && !IsPet()) { // should not let player enter combat by right clicking target - doesn't helps + AddThreat(victim, 0.0f); SetInCombatWith(victim); if (victim->GetTypeId() == TYPEID_PLAYER) victim->SetInCombatWith(this); - AddThreat(victim, 0.0f); ToCreature()->SendAIReaction(AI_REACTION_HOSTILE); ToCreature()->CallAssistance(); @@ -9232,7 +9299,7 @@ Unit* Unit::GetCharmer() const if (ObjectGuid charmerGUID = GetCharmerGUID()) return ObjectAccessor::GetUnit(*this, charmerGUID); - return NULL; + return nullptr; } Player* Unit::GetCharmerOrOwnerPlayerOrPlayerItself() const @@ -12346,7 +12413,7 @@ void Unit::UpdateSpeed(UnitMoveType mtype, bool forced) if (Creature* creature = ToCreature()) { uint32 immuneMask = creature->GetCreatureTemplate()->MechanicImmuneMask; - if (immuneMask & (1 << MECHANIC_SNARE) || immuneMask & (1 << MECHANIC_DAZE)) + if (immuneMask & (1 << (MECHANIC_SNARE - 1)) || immuneMask & (1 << (MECHANIC_DAZE - 1))) break; } @@ -12750,7 +12817,7 @@ Unit* Creature::SelectVictim() } } else - return NULL; + return nullptr; if (target && _IsTargetAcceptable(target) && CanCreatureAttack(target)) { @@ -12759,14 +12826,6 @@ Unit* Creature::SelectVictim() return target; } - // Case where mob is being kited. - // Mob may not be in range to attack or may have dropped target. In any case, - // don't evade if damage received within the last 10 seconds - // Does not apply to world bosses to prevent kiting to cities - if (!isWorldBoss() && !GetInstanceId()) - if (time(NULL) - GetLastDamagedTime() <= MAX_AGGRO_RESET_TIME) - return target; - // last case when creature must not go to evade mode: // it in combat but attacker not make any damage and not enter to aggro radius to have record in threat list // for example at owner command to pet attack some far away creature @@ -12775,12 +12834,12 @@ Unit* Creature::SelectVictim() { if ((*itr) && !CanCreatureAttack(*itr) && (*itr)->GetTypeId() != TYPEID_PLAYER && !(*itr)->ToCreature()->HasUnitTypeMask(UNIT_MASK_CONTROLABLE_GUARDIAN)) - return NULL; + return nullptr; } /// @todo a vehicle may eat some mob, so mob should not evade if (GetVehicle()) - return NULL; + return nullptr; // search nearby enemy before enter evade mode if (HasReactState(REACT_AGGRESSIVE)) @@ -12798,17 +12857,17 @@ Unit* Creature::SelectVictim() { if ((*itr)->GetBase()->IsPermanent()) { - AI()->EnterEvadeMode(); + AI()->EnterEvadeMode(CreatureAI::EVADE_REASON_OTHER); break; } } - return NULL; + return nullptr; } // enter in evade mode in other case AI()->EnterEvadeMode(CreatureAI::EVADE_REASON_NO_HOSTILES); - return NULL; + return nullptr; } //====================================================================== @@ -13665,28 +13724,76 @@ void Unit::CleanupsBeforeDelete(bool finalCleanup) void Unit::UpdateCharmAI() { - if (GetTypeId() == TYPEID_PLAYER) - return; - - if (i_disabledAI) // disabled AI must be primary AI + switch (GetTypeId()) { - if (!IsCharmed()) - { - delete i_AI; - i_AI = i_disabledAI; - i_disabledAI = NULL; - } - } - else - { - if (IsCharmed()) + case TYPEID_UNIT: + if (i_disabledAI) // disabled AI must be primary AI + { + if (!IsCharmed()) + { + delete i_AI; + i_AI = i_disabledAI; + i_disabledAI = nullptr; + } + } + else + { + if (IsCharmed()) + { + i_disabledAI = i_AI; + if (isPossessed() || IsVehicle()) + i_AI = new PossessedAI(ToCreature()); + else + i_AI = new PetAI(ToCreature()); + } + } + break; + case TYPEID_PLAYER: { - i_disabledAI = i_AI; - if (isPossessed() || IsVehicle()) - i_AI = new PossessedAI(ToCreature()); + if (IsCharmed()) // if we are currently being charmed, then we should apply charm AI + { + i_disabledAI = i_AI; + + UnitAI* newAI = nullptr; + // first, we check if the creature's own AI specifies an override playerai for its owned players + if (Unit* charmer = GetCharmer()) + { + if (Creature* creatureCharmer = charmer->ToCreature()) + { + if (PlayerAI* charmAI = creatureCharmer->IsAIEnabled ? creatureCharmer->AI()->GetAIForCharmedPlayer(ToPlayer()) : nullptr) + newAI = charmAI; + } + else + { + TC_LOG_ERROR("misc", "Attempt to assign charm AI to player %s who is charmed by non-creature %s.", GetGUID().ToString().c_str(), GetCharmerGUID().ToString().c_str()); + } + } + if (!newAI) // otherwise, we default to the generic one + newAI = new SimpleCharmedPlayerAI(ToPlayer()); + i_AI = newAI; + } else - i_AI = new PetAI(ToCreature()); + { + if (i_AI) + { + // we allow the charmed PlayerAI to clean up + i_AI->OnCharmed(false); + // then delete it + delete i_AI; + } + else + { + TC_LOG_ERROR("misc", "Attempt to remove charm AI from player %s who doesn't currently have charm AI.", GetGUID().ToString().c_str()); + } + // and restore our previous PlayerAI (if we had one) + i_AI = i_disabledAI; + i_disabledAI = nullptr; + // IsAIEnabled gets handled in the caller + } + break; } + default: + TC_LOG_ERROR("misc", "Attempt to update charm AI for unit %s, which is neither player nor creature.", GetGUID().ToString().c_str()); } } @@ -15915,11 +16022,17 @@ bool Unit::SetCharmedBy(Unit* charmer, CharmType type, AuraApplication const* au ToCreature()->AI()->OnCharmed(true); GetMotionMaster()->MoveIdle(); } - else + else if (Player* player = ToPlayer()) { - Player* player = ToPlayer(); if (player->isAFK()) player->ToggleAFK(); + + if (charmer->GetTypeId() == TYPEID_UNIT) // we are charmed by a creature + { + // change AI to charmed AI on next Update tick + NeedChangeAI = true; + IsAIEnabled = false; + } player->SetClientControl(this, false); } @@ -16077,7 +16190,14 @@ void Unit::RemoveCharmedBy(Unit* charmer) } if (Player* player = ToPlayer()) + { + if (charmer->GetTypeId() == TYPEID_UNIT) // charmed by a creature, this means we had PlayerAI + { + NeedChangeAI = true; + IsAIEnabled = false; + } player->SetClientControl(this, true); + } // a guardian should always have charminfo if (playerCharmer && this != charmer->GetFirstControlled()) @@ -16869,12 +16989,12 @@ void Unit::JumpTo(float speedXY, float speedZ, bool forward) } } -void Unit::JumpTo(WorldObject* obj, float speedZ) +void Unit::JumpTo(WorldObject* obj, float speedZ, bool withOrientation) { float x, y, z; obj->GetContactPoint(this, x, y, z); float speedXY = GetExactDist2d(x, y) * 10.0f / speedZ; - GetMotionMaster()->MoveJump(x, y, z, speedXY, speedZ); + GetMotionMaster()->MoveJump(x, y, z, GetAngle(obj), speedXY, speedZ, EVENT_JUMP, withOrientation); } bool Unit::HandleSpellClick(Unit* clicker, int8 seatId) diff --git a/src/server/game/Entities/Unit/Unit.h b/src/server/game/Entities/Unit/Unit.h index 8572c791d67..19fd4089168 100644 --- a/src/server/game/Entities/Unit/Unit.h +++ b/src/server/game/Entities/Unit/Unit.h @@ -1567,7 +1567,7 @@ class Unit : public WorldObject void KnockbackFrom(float x, float y, float speedXY, float speedZ); void JumpTo(float speedXY, float speedZ, bool forward = true); - void JumpTo(WorldObject* obj, float speedZ); + void JumpTo(WorldObject* obj, float speedZ, bool withOrientation = false); void MonsterMoveWithSpeed(float x, float y, float z, float speed, bool generatePath = false, bool forceDestination = false); //void SetFacing(float ori, WorldObject* obj = NULL); @@ -1704,6 +1704,16 @@ class Unit : public WorldObject void RemoveAura(AuraApplication * aurApp, AuraRemoveMode mode = AURA_REMOVE_BY_DEFAULT); void RemoveAura(Aura* aur, AuraRemoveMode mode = AURA_REMOVE_BY_DEFAULT); + // Convenience methods removing auras by predicate + void RemoveAppliedAuras(std::function<bool(AuraApplication const*)> const& check); + void RemoveOwnedAuras(std::function<bool(Aura const*)> const& check); + + // Optimized overloads taking advantage of map key + void RemoveAppliedAuras(uint32 spellId, std::function<bool(AuraApplication const*)> const& check); + void RemoveOwnedAuras(uint32 spellId, std::function<bool(Aura const*)> const& check); + + void RemoveAurasByType(AuraType auraType, std::function<bool(AuraApplication const*)> const& check); + void RemoveAurasDueToSpell(uint32 spellId, ObjectGuid casterGUID = ObjectGuid::Empty, uint8 reqEffMask = 0, AuraRemoveMode removeMode = AURA_REMOVE_BY_DEFAULT); void RemoveAuraFromStack(uint32 spellId, ObjectGuid casterGUID = ObjectGuid::Empty, AuraRemoveMode removeMode = AURA_REMOVE_BY_DEFAULT); void RemoveAurasDueToSpellByDispel(uint32 spellId, uint32 dispellerSpellId, ObjectGuid casterGUID, Unit* dispeller, uint8 chargesRemoved = 1); diff --git a/src/server/game/Events/GameEventMgr.cpp b/src/server/game/Events/GameEventMgr.cpp index b2871786034..79584c6261e 100644 --- a/src/server/game/Events/GameEventMgr.cpp +++ b/src/server/game/Events/GameEventMgr.cpp @@ -221,7 +221,7 @@ void GameEventMgr::LoadFromDB() uint8 event_id = fields[0].GetUInt8(); if (event_id == 0) { - TC_LOG_ERROR("sql.sql", "`game_event` game event entry 0 is reserved and can't be used."); + TC_LOG_ERROR("sql.sql", "`game_event`: game event entry 0 is reserved and can't be used."); continue; } @@ -240,7 +240,7 @@ void GameEventMgr::LoadFromDB() if (pGameEvent.length == 0 && pGameEvent.state == GAMEEVENT_NORMAL) // length>0 is validity check { - TC_LOG_ERROR("sql.sql", "`game_event` game event id (%i) isn't a world event and has length = 0, thus it can't be used.", event_id); + TC_LOG_ERROR("sql.sql", "`game_event`: game event id (%i) is not a world event and has length = 0, thus cannot be used.", event_id); continue; } @@ -248,7 +248,7 @@ void GameEventMgr::LoadFromDB() { if (!sHolidaysStore.LookupEntry(pGameEvent.holiday_id)) { - TC_LOG_ERROR("sql.sql", "`game_event` game event id (%i) have not existed holiday id %u.", event_id, pGameEvent.holiday_id); + TC_LOG_ERROR("sql.sql", "`game_event`: game event id (%i) contains nonexisting holiday id %u.", event_id, pGameEvent.holiday_id); pGameEvent.holiday_id = HOLIDAY_NONE; } } @@ -259,7 +259,7 @@ void GameEventMgr::LoadFromDB() } while (result->NextRow()); - TC_LOG_INFO("server.loading", ">> Loaded %u game events in %u ms", count, GetMSTimeDiffToNow(oldMSTime)); + TC_LOG_INFO("server.loading", ">> Loaded %u game events in %u ms.", count, GetMSTimeDiffToNow(oldMSTime)); } @@ -283,7 +283,7 @@ void GameEventMgr::LoadFromDB() if (event_id >= mGameEvent.size()) { - TC_LOG_ERROR("sql.sql", "`game_event_save` game event entry (%i) is out of range compared to max event entry in `game_event`", event_id); + TC_LOG_ERROR("sql.sql", "`game_event_save`: game event entry (%i) is out of range compared to max event entry in `game_event`.", event_id); continue; } @@ -294,7 +294,7 @@ void GameEventMgr::LoadFromDB() } else { - TC_LOG_ERROR("sql.sql", "game_event_save includes event save for non-worldevent id %u", event_id); + TC_LOG_ERROR("sql.sql", "game_event_save includes event save for non-worldevent id %u.", event_id); continue; } @@ -302,7 +302,7 @@ void GameEventMgr::LoadFromDB() } while (result->NextRow()); - TC_LOG_INFO("server.loading", ">> Loaded %u game event saves in game events in %u ms", count, GetMSTimeDiffToNow(oldMSTime)); + TC_LOG_INFO("server.loading", ">> Loaded %u game event saves in game events in %u ms.", count, GetMSTimeDiffToNow(oldMSTime)); } } @@ -326,7 +326,7 @@ void GameEventMgr::LoadFromDB() if (event_id >= mGameEvent.size()) { - TC_LOG_ERROR("sql.sql", "`game_event_prerequisite` game event id (%i) is out of range compared to max event id in `game_event`", event_id); + TC_LOG_ERROR("sql.sql", "`game_event_prerequisite`: game event id (%i) is out of range compared to max event id in `game_event`.", event_id); continue; } @@ -335,14 +335,14 @@ void GameEventMgr::LoadFromDB() uint16 prerequisite_event = fields[1].GetUInt32(); if (prerequisite_event >= mGameEvent.size()) { - TC_LOG_ERROR("sql.sql", "`game_event_prerequisite` game event prerequisite id (%i) is out of range compared to max event id in `game_event`", prerequisite_event); + TC_LOG_ERROR("sql.sql", "`game_event_prerequisite`: game event prerequisite id (%i) is out of range compared to max event id in `game_event`.", prerequisite_event); continue; } mGameEvent[event_id].prerequisite_events.insert(prerequisite_event); } else { - TC_LOG_ERROR("sql.sql", "game_event_prerequisiste includes event entry for non-worldevent id %u", event_id); + TC_LOG_ERROR("sql.sql", "game_event_prerequisiste includes event entry for non-worldevent id %u.", event_id); continue; } @@ -350,7 +350,7 @@ void GameEventMgr::LoadFromDB() } while (result->NextRow()); - TC_LOG_INFO("server.loading", ">> Loaded %u game event prerequisites in game events in %u ms", count, GetMSTimeDiffToNow(oldMSTime)); + TC_LOG_INFO("server.loading", ">> Loaded %u game event prerequisites in game events in %u ms.", count, GetMSTimeDiffToNow(oldMSTime)); } } @@ -363,7 +363,7 @@ void GameEventMgr::LoadFromDB() QueryResult result = WorldDatabase.Query("SELECT guid, eventEntry FROM game_event_creature"); if (!result) - TC_LOG_INFO("server.loading", ">> Loaded 0 creatures in game events. DB table `game_event_creature` is empty"); + TC_LOG_INFO("server.loading", ">> Loaded 0 creatures in game events. DB table `game_event_creature` is empty."); else { uint32 count = 0; @@ -385,7 +385,7 @@ void GameEventMgr::LoadFromDB() if (internal_event_id < 0 || internal_event_id >= int32(mGameEventCreatureGuids.size())) { - TC_LOG_ERROR("sql.sql", "`game_event_creature` game event id (%i) is out of range compared to max event id in `game_event`", event_id); + TC_LOG_ERROR("sql.sql", "`game_event_creature`: game event id (%i) is out of range compared to max event id in `game_event`.", event_id); continue; } @@ -396,7 +396,7 @@ void GameEventMgr::LoadFromDB() } while (result->NextRow()); - TC_LOG_INFO("server.loading", ">> Loaded %u creatures in game events in %u ms", count, GetMSTimeDiffToNow(oldMSTime)); + TC_LOG_INFO("server.loading", ">> Loaded %u creatures in game events in %u ms.", count, GetMSTimeDiffToNow(oldMSTime)); } } @@ -431,7 +431,7 @@ void GameEventMgr::LoadFromDB() if (internal_event_id < 0 || internal_event_id >= int32(mGameEventGameobjectGuids.size())) { - TC_LOG_ERROR("sql.sql", "`game_event_gameobject` game event id (%i) is out of range compared to max event id in `game_event`", event_id); + TC_LOG_ERROR("sql.sql", "`game_event_gameobject`: game event id (%i) is out of range compared to max event id in `game_event`.", event_id); continue; } @@ -442,7 +442,7 @@ void GameEventMgr::LoadFromDB() } while (result->NextRow()); - TC_LOG_INFO("server.loading", ">> Loaded %u gameobjects in game events in %u ms", count, GetMSTimeDiffToNow(oldMSTime)); + TC_LOG_INFO("server.loading", ">> Loaded %u gameobjects in game events in %u ms.", count, GetMSTimeDiffToNow(oldMSTime)); } } @@ -469,7 +469,7 @@ void GameEventMgr::LoadFromDB() if (event_id >= mGameEventModelEquip.size()) { - TC_LOG_ERROR("sql.sql", "`game_event_model_equip` game event id (%u) is out of range compared to max event id in `game_event`", event_id); + TC_LOG_ERROR("sql.sql", "`game_event_model_equip`: game event id (%u) is out of range compared to max event id in `game_event`.", event_id); continue; } @@ -485,7 +485,7 @@ void GameEventMgr::LoadFromDB() int8 equipId = static_cast<int8>(newModelEquipSet.equipment_id); if (!sObjectMgr->GetEquipmentInfo(entry, equipId)) { - TC_LOG_ERROR("sql.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.", + TC_LOG_ERROR("sql.sql", "Table `game_event_model_equip` contains creature (Guid: %u, entry: %u) with equipment_id %u not found in table `creature_equip_template`. Setting entry to no equipment.", guid, entry, newModelEquipSet.equipment_id); continue; } @@ -497,7 +497,7 @@ void GameEventMgr::LoadFromDB() } while (result->NextRow()); - TC_LOG_INFO("server.loading", ">> Loaded %u model/equipment changes in game events in %u ms", count, GetMSTimeDiffToNow(oldMSTime)); + TC_LOG_INFO("server.loading", ">> Loaded %u model/equipment changes in game events in %u ms.", count, GetMSTimeDiffToNow(oldMSTime)); } } @@ -523,7 +523,7 @@ void GameEventMgr::LoadFromDB() if (event_id >= mGameEventCreatureQuests.size()) { - TC_LOG_ERROR("sql.sql", "`game_event_creature_quest` game event id (%u) is out of range compared to max event id in `game_event`", event_id); + TC_LOG_ERROR("sql.sql", "`game_event_creature_quest`: game event id (%u) is out of range compared to max event id in `game_event`.", event_id); continue; } @@ -534,7 +534,7 @@ void GameEventMgr::LoadFromDB() } while (result->NextRow()); - TC_LOG_INFO("server.loading", ">> Loaded %u quests additions in game events in %u ms", count, GetMSTimeDiffToNow(oldMSTime)); + TC_LOG_INFO("server.loading", ">> Loaded %u quests additions in game events in %u ms.", count, GetMSTimeDiffToNow(oldMSTime)); } } @@ -560,7 +560,7 @@ void GameEventMgr::LoadFromDB() if (event_id >= mGameEventGameObjectQuests.size()) { - TC_LOG_ERROR("sql.sql", "`game_event_gameobject_quest` game event id (%u) is out of range compared to max event id in `game_event`", event_id); + TC_LOG_ERROR("sql.sql", "`game_event_gameobject_quest`: game event id (%u) is out of range compared to max event id in `game_event`.", event_id); continue; } @@ -571,7 +571,7 @@ void GameEventMgr::LoadFromDB() } while (result->NextRow()); - TC_LOG_INFO("server.loading", ">> Loaded %u quests additions in game events in %u ms", count, GetMSTimeDiffToNow(oldMSTime)); + TC_LOG_INFO("server.loading", ">> Loaded %u quests additions in game events in %u ms.", count, GetMSTimeDiffToNow(oldMSTime)); } } @@ -598,7 +598,7 @@ void GameEventMgr::LoadFromDB() if (event_id >= mGameEvent.size()) { - TC_LOG_ERROR("sql.sql", "`game_event_quest_condition` game event id (%u) is out of range compared to max event id in `game_event`", event_id); + TC_LOG_ERROR("sql.sql", "`game_event_quest_condition`: game event id (%u) is out of range compared to max event id in `game_event`.", event_id); continue; } @@ -610,7 +610,7 @@ void GameEventMgr::LoadFromDB() } while (result->NextRow()); - TC_LOG_INFO("server.loading", ">> Loaded %u quest event conditions in game events in %u ms", count, GetMSTimeDiffToNow(oldMSTime)); + TC_LOG_INFO("server.loading", ">> Loaded %u quest event conditions in game events in %u ms.", count, GetMSTimeDiffToNow(oldMSTime)); } } @@ -635,7 +635,7 @@ void GameEventMgr::LoadFromDB() if (event_id >= mGameEvent.size()) { - TC_LOG_ERROR("sql.sql", "`game_event_condition` game event id (%u) is out of range compared to max event id in `game_event`", event_id); + TC_LOG_ERROR("sql.sql", "`game_event_condition`: game event id (%u) is out of range compared to max event id in `game_event`.", event_id); continue; } @@ -648,7 +648,7 @@ void GameEventMgr::LoadFromDB() } while (result->NextRow()); - TC_LOG_INFO("server.loading", ">> Loaded %u conditions in game events in %u ms", count, GetMSTimeDiffToNow(oldMSTime)); + TC_LOG_INFO("server.loading", ">> Loaded %u conditions in game events in %u ms.", count, GetMSTimeDiffToNow(oldMSTime)); } } @@ -673,7 +673,7 @@ void GameEventMgr::LoadFromDB() if (event_id >= mGameEvent.size()) { - TC_LOG_ERROR("sql.sql", "`game_event_condition_save` game event id (%u) is out of range compared to max event id in `game_event`", event_id); + TC_LOG_ERROR("sql.sql", "`game_event_condition_save`: game event id (%u) is out of range compared to max event id in `game_event`.", event_id); continue; } @@ -684,7 +684,7 @@ void GameEventMgr::LoadFromDB() } else { - TC_LOG_ERROR("sql.sql", "game_event_condition_save contains not present condition evt id %u cond id %u", event_id, condition); + TC_LOG_ERROR("sql.sql", "game_event_condition_save contains not present condition event id %u condition id %u.", event_id, condition); continue; } @@ -692,7 +692,7 @@ void GameEventMgr::LoadFromDB() } while (result->NextRow()); - TC_LOG_INFO("server.loading", ">> Loaded %u condition saves in game events in %u ms", count, GetMSTimeDiffToNow(oldMSTime)); + TC_LOG_INFO("server.loading", ">> Loaded %u condition saves in game events in %u ms.", count, GetMSTimeDiffToNow(oldMSTime)); } } @@ -718,7 +718,7 @@ void GameEventMgr::LoadFromDB() if (event_id >= mGameEvent.size()) { - TC_LOG_ERROR("sql.sql", "`game_event_npcflag` game event id (%u) is out of range compared to max event id in `game_event`", event_id); + TC_LOG_ERROR("sql.sql", "`game_event_npcflag`: game event id (%u) is out of range compared to max event id in `game_event`.", event_id); continue; } @@ -728,7 +728,7 @@ void GameEventMgr::LoadFromDB() } while (result->NextRow()); - TC_LOG_INFO("server.loading", ">> Loaded %u npcflags in game events in %u ms", count, GetMSTimeDiffToNow(oldMSTime)); + TC_LOG_INFO("server.loading", ">> Loaded %u npcflags in game events in %u ms.", count, GetMSTimeDiffToNow(oldMSTime)); } } @@ -753,13 +753,13 @@ void GameEventMgr::LoadFromDB() if (!sObjectMgr->GetQuestTemplate(questId)) { - TC_LOG_ERROR("sql.sql", "`game_event_seasonal_questrelation` quest id (%u) does not exist in `quest_template`", questId); + TC_LOG_ERROR("sql.sql", "`game_event_seasonal_questrelation`: quest id (%u) does not exist in `quest_template`.", questId); continue; } if (eventEntry >= mGameEvent.size()) { - TC_LOG_ERROR("sql.sql", "`game_event_seasonal_questrelation` event id (%u) is out of range compared to max event in `game_event`", eventEntry); + TC_LOG_ERROR("sql.sql", "`game_event_seasonal_questrelation`: event id (%u) is out of range compared to max event in `game_event`.", eventEntry); continue; } @@ -768,7 +768,7 @@ void GameEventMgr::LoadFromDB() } while (result->NextRow()); - TC_LOG_INFO("server.loading", ">> Loaded %u quests additions in game events in %u ms", count, GetMSTimeDiffToNow(oldMSTime)); + TC_LOG_INFO("server.loading", ">> Loaded %u quests additions in game events in %u ms.", count, GetMSTimeDiffToNow(oldMSTime)); } } @@ -792,7 +792,7 @@ void GameEventMgr::LoadFromDB() if (event_id >= mGameEventVendors.size()) { - TC_LOG_ERROR("sql.sql", "`game_event_npc_vendor` game event id (%u) is out of range compared to max event id in `game_event`", event_id); + TC_LOG_ERROR("sql.sql", "`game_event_npc_vendor`: game event id (%u) is out of range compared to max event id in `game_event`.", event_id); continue; } @@ -830,7 +830,7 @@ void GameEventMgr::LoadFromDB() } while (result->NextRow()); - TC_LOG_INFO("server.loading", ">> Loaded %u vendor additions in game events in %u ms", count, GetMSTimeDiffToNow(oldMSTime)); + TC_LOG_INFO("server.loading", ">> Loaded %u vendor additions in game events in %u ms.", count, GetMSTimeDiffToNow(oldMSTime)); } } @@ -854,7 +854,7 @@ void GameEventMgr::LoadFromDB() if (event_id >= mGameEvent.size()) { - TC_LOG_ERROR("sql.sql", "`game_event_battleground_holiday` game event id (%u) is out of range compared to max event id in `game_event`", event_id); + TC_LOG_ERROR("sql.sql", "`game_event_battleground_holiday`: game event id (%u) is out of range compared to max event id in `game_event`.", event_id); continue; } @@ -864,7 +864,7 @@ void GameEventMgr::LoadFromDB() } while (result->NextRow()); - TC_LOG_INFO("server.loading", ">> Loaded %u battleground holidays in game events in %u ms", count, GetMSTimeDiffToNow(oldMSTime)); + TC_LOG_INFO("server.loading", ">> Loaded %u battleground holidays in game events in %u ms.", count, GetMSTimeDiffToNow(oldMSTime)); } } @@ -892,13 +892,13 @@ void GameEventMgr::LoadFromDB() if (internal_event_id < 0 || internal_event_id >= int32(mGameEventPoolIds.size())) { - TC_LOG_ERROR("sql.sql", "`game_event_pool` game event id (%i) is out of range compared to max event id in `game_event`", event_id); + TC_LOG_ERROR("sql.sql", "`game_event_pool`: game event id (%i) is out of range compared to max event id in `game_event`.", event_id); continue; } if (!sPoolMgr->CheckPool(entry)) { - TC_LOG_ERROR("sql.sql", "Pool Id (%u) has all creatures or gameobjects with explicit chance sum <>100 and no equal chance defined. The pool system cannot pick one to spawn.", entry); + TC_LOG_ERROR("sql.sql", "Pool Id (%u) has all creatures or gameobjects with explicit chance sum <> 100 and no equal chance defined. The pool system cannot pick one to spawn.", entry); continue; } @@ -909,7 +909,7 @@ void GameEventMgr::LoadFromDB() } while (result->NextRow()); - TC_LOG_INFO("server.loading", ">> Loaded %u pools for game events in %u ms", count, GetMSTimeDiffToNow(oldMSTime)); + TC_LOG_INFO("server.loading", ">> Loaded %u pools for game events in %u ms.", count, GetMSTimeDiffToNow(oldMSTime)); } } } @@ -971,7 +971,7 @@ void GameEventMgr::StartArenaSeason() if (!result) { - TC_LOG_ERROR("gameevent", "ArenaSeason (%u) must be an existant Arena Season", season); + TC_LOG_ERROR("gameevent", "ArenaSeason (%u) must be an existing Arena Season.", season); return; } @@ -980,7 +980,7 @@ void GameEventMgr::StartArenaSeason() if (eventId >= mGameEvent.size()) { - TC_LOG_ERROR("gameevent", "EventEntry %u for ArenaSeason (%u) does not exists", eventId, season); + TC_LOG_ERROR("gameevent", "EventEntry %u for ArenaSeason (%u) does not exist.", eventId, season); return; } @@ -1171,7 +1171,7 @@ void GameEventMgr::GameEventSpawn(int16 event_id) if (internal_event_id < 0 || internal_event_id >= int32(mGameEventCreatureGuids.size())) { - TC_LOG_ERROR("gameevent", "GameEventMgr::GameEventSpawn attempt access to out of range mGameEventCreatureGuids element %i (size: %zu)", + TC_LOG_ERROR("gameevent", "GameEventMgr::GameEventSpawn attempted access to out of range mGameEventCreatureGuids element %i (size: %zu).", internal_event_id, mGameEventCreatureGuids.size()); return; } @@ -1198,7 +1198,7 @@ void GameEventMgr::GameEventSpawn(int16 event_id) if (internal_event_id < 0 || internal_event_id >= int32(mGameEventGameobjectGuids.size())) { - TC_LOG_ERROR("gameevent", "GameEventMgr::GameEventSpawn attempt access to out of range mGameEventGameobjectGuids element %i (size: %zu)", + TC_LOG_ERROR("gameevent", "GameEventMgr::GameEventSpawn attempted access to out of range mGameEventGameobjectGuids element %i (size: %zu).", internal_event_id, mGameEventGameobjectGuids.size()); return; } @@ -1231,7 +1231,7 @@ void GameEventMgr::GameEventSpawn(int16 event_id) if (internal_event_id < 0 || internal_event_id >= int32(mGameEventPoolIds.size())) { - TC_LOG_ERROR("gameevent", "GameEventMgr::GameEventSpawn attempt access to out of range mGameEventPoolIds element %u (size: %zu)", + TC_LOG_ERROR("gameevent", "GameEventMgr::GameEventSpawn attempted access to out of range mGameEventPoolIds element %u (size: %zu).", internal_event_id, mGameEventPoolIds.size()); return; } @@ -1246,7 +1246,7 @@ void GameEventMgr::GameEventUnspawn(int16 event_id) if (internal_event_id < 0 || internal_event_id >= int32(mGameEventCreatureGuids.size())) { - TC_LOG_ERROR("gameevent", "GameEventMgr::GameEventUnspawn attempt access to out of range mGameEventCreatureGuids element %i (size: %zu)", + TC_LOG_ERROR("gameevent", "GameEventMgr::GameEventUnspawn attempted access to out of range mGameEventCreatureGuids element %i (size: %zu).", internal_event_id, mGameEventCreatureGuids.size()); return; } @@ -1276,7 +1276,7 @@ void GameEventMgr::GameEventUnspawn(int16 event_id) if (internal_event_id < 0 || internal_event_id >= int32(mGameEventGameobjectGuids.size())) { - TC_LOG_ERROR("gameevent", "GameEventMgr::GameEventUnspawn attempt access to out of range mGameEventGameobjectGuids element %i (size: %zu)", + TC_LOG_ERROR("gameevent", "GameEventMgr::GameEventUnspawn attempted access to out of range mGameEventGameobjectGuids element %i (size: %zu).", internal_event_id, mGameEventGameobjectGuids.size()); return; } @@ -1305,7 +1305,7 @@ void GameEventMgr::GameEventUnspawn(int16 event_id) } if (internal_event_id < 0 || internal_event_id >= int32(mGameEventPoolIds.size())) { - TC_LOG_ERROR("gameevent", "GameEventMgr::GameEventUnspawn attempt access to out of range mGameEventPoolIds element %u (size: %zu)", internal_event_id, mGameEventPoolIds.size()); + TC_LOG_ERROR("gameevent", "GameEventMgr::GameEventUnspawn attempted access to out of range mGameEventPoolIds element %u (size: %zu).", internal_event_id, mGameEventPoolIds.size()); return; } diff --git a/src/server/game/Globals/ObjectMgr.cpp b/src/server/game/Globals/ObjectMgr.cpp index 327bccd7e19..f45634e9684 100644 --- a/src/server/game/Globals/ObjectMgr.cpp +++ b/src/server/game/Globals/ObjectMgr.cpp @@ -2773,7 +2773,7 @@ void ObjectMgr::LoadItemTemplates() itemTemplate.ItemSet = 0; } - if (itemTemplate.Area && !GetAreaEntryByAreaID(itemTemplate.Area)) + if (itemTemplate.Area && !sAreaTableStore.LookupEntry(itemTemplate.Area)) TC_LOG_ERROR("sql.sql", "Item (Entry: %u) has wrong Area (%u)", entry, itemTemplate.Area); if (itemTemplate.Map && !sMapStore.LookupEntry(itemTemplate.Map)) @@ -4143,7 +4143,7 @@ void ObjectMgr::LoadQuests() // client quest log visual (area case) if (qinfo->ZoneOrSort > 0) { - if (!GetAreaEntryByAreaID(qinfo->ZoneOrSort)) + if (!sAreaTableStore.LookupEntry(qinfo->ZoneOrSort)) { TC_LOG_ERROR("sql.sql", "Quest %u has `ZoneOrSort` = %u (zone case) but zone with this id does not exist.", qinfo->GetQuestId(), qinfo->ZoneOrSort); @@ -5956,7 +5956,7 @@ void ObjectMgr::LoadGraveyardZones() continue; } - AreaTableEntry const* areaEntry = GetAreaEntryByAreaID(zoneId); + AreaTableEntry const* areaEntry = sAreaTableStore.LookupEntry(zoneId); if (!areaEntry) { TC_LOG_ERROR("sql.sql", "Table `game_graveyard_zone` has a record for not existing zone id (%u), skipped.", zoneId); @@ -7796,7 +7796,7 @@ void ObjectMgr::LoadFishingBaseSkillLevel() uint32 entry = fields[0].GetUInt32(); int32 skill = fields[1].GetInt16(); - AreaTableEntry const* fArea = GetAreaEntryByAreaID(entry); + AreaTableEntry const* fArea = sAreaTableStore.LookupEntry(entry); if (!fArea) { TC_LOG_ERROR("sql.sql", "AreaId %u defined in `skill_fishing_base_level` does not exist", entry); diff --git a/src/server/game/Grids/GridDefines.h b/src/server/game/Grids/GridDefines.h index 162c39b951b..24c9100b222 100644 --- a/src/server/game/Grids/GridDefines.h +++ b/src/server/game/Grids/GridDefines.h @@ -226,7 +226,7 @@ namespace Trinity inline bool IsValidMapCoord(float x, float y, float z) { - return IsValidMapCoord(x, y) && std::isfinite(z); + return IsValidMapCoord(x, y) && IsValidMapCoord(z); } inline bool IsValidMapCoord(float x, float y, float z, float o) diff --git a/src/server/game/Grids/Notifiers/GridNotifiers.cpp b/src/server/game/Grids/Notifiers/GridNotifiers.cpp index c48d1947eec..2cdbdca4e4f 100644 --- a/src/server/game/Grids/Notifiers/GridNotifiers.cpp +++ b/src/server/game/Grids/Notifiers/GridNotifiers.cpp @@ -131,7 +131,7 @@ inline void CreatureUnitRelocationWorker(Creature* c, Unit* u) if (!u->IsAlive() || !c->IsAlive() || c == u || u->IsInFlight()) return; - if (c->HasReactState(REACT_AGGRESSIVE) && !c->HasUnitState(UNIT_STATE_SIGHTLESS)) + if (!c->HasUnitState(UNIT_STATE_SIGHTLESS)) { if (c->IsAIEnabled && c->CanSeeOrDetect(u, false, true)) c->AI()->MoveInLineOfSight_Safe(u); diff --git a/src/server/game/Groups/Group.cpp b/src/server/game/Groups/Group.cpp index 43159828a3c..99c5d610e64 100644 --- a/src/server/game/Groups/Group.cpp +++ b/src/server/game/Groups/Group.cpp @@ -687,7 +687,8 @@ void Group::ConvertLeaderInstancesToGroup(Player* player, Group* group, bool swi for (Player::BoundInstancesMap::iterator itr = player->m_boundInstances[i].begin(); itr != player->m_boundInstances[i].end();) { if (!switchLeader || !group->GetBoundInstance(itr->second.save->GetDifficulty(), itr->first)) - group->BindToInstance(itr->second.save, itr->second.perm, false); + if (itr->second.extendState) // not expired + group->BindToInstance(itr->second.save, itr->second.perm, false); // permanent binds are not removed if (switchLeader && !itr->second.perm) diff --git a/src/server/game/Handlers/CalendarHandler.cpp b/src/server/game/Handlers/CalendarHandler.cpp index 8bd7086fc1b..540eeba0752 100644 --- a/src/server/game/Handlers/CalendarHandler.cpp +++ b/src/server/game/Handlers/CalendarHandler.cpp @@ -695,6 +695,21 @@ void WorldSession::HandleSetSavedInstanceExtend(WorldPacket& recvData) recvData >> mapId >> difficulty>> toggleExtend; TC_LOG_DEBUG("network", "CMSG_SET_SAVED_INSTANCE_EXTEND - MapId: %u, Difficulty: %u, ToggleExtend: %s", mapId, difficulty, toggleExtend ? "On" : "Off"); + if (Player* player = GetPlayer()) + { + InstancePlayerBind* instanceBind = player->GetBoundInstance(mapId, Difficulty(difficulty), toggleExtend == 1); // include expired instances if we are toggling extend on + if (!instanceBind || !instanceBind->save || !instanceBind->perm) + return; + + BindExtensionState newState; + if (!toggleExtend || instanceBind->extendState == EXTEND_STATE_EXPIRED) + newState = EXTEND_STATE_NORMAL; + else + newState = EXTEND_STATE_EXTENDED; + + player->BindToInstance(instanceBind->save, true, newState, false); + } + /* InstancePlayerBind* instanceBind = _player->GetBoundInstance(mapId, Difficulty(difficulty)); if (!instanceBind || !instanceBind->save) diff --git a/src/server/game/Handlers/ChannelHandler.cpp b/src/server/game/Handlers/ChannelHandler.cpp index 976860e8cc0..9285f4247b2 100644 --- a/src/server/game/Handlers/ChannelHandler.cpp +++ b/src/server/game/Handlers/ChannelHandler.cpp @@ -39,7 +39,7 @@ void WorldSession::HandleJoinChannel(WorldPacket& recvPacket) if (!channel) return; - AreaTableEntry const* zone = GetAreaEntryByAreaID(GetPlayer()->GetZoneId()); + AreaTableEntry const* zone = sAreaTableStore.LookupEntry(GetPlayer()->GetZoneId()); if (!zone || !GetPlayer()->CanJoinConstantChannelInZone(channel, zone)) return; } diff --git a/src/server/game/Handlers/MailHandler.cpp b/src/server/game/Handlers/MailHandler.cpp index aaf6ca39d09..36df5b64f1b 100644 --- a/src/server/game/Handlers/MailHandler.cpp +++ b/src/server/game/Handlers/MailHandler.cpp @@ -35,7 +35,7 @@ bool WorldSession::CanOpenMailBox(ObjectGuid guid) { if (!HasPermission(rbac::RBAC_PERM_COMMAND_MAILBOX)) { - TC_LOG_WARN("cheat", "%s attempt open mailbox in cheating way.", _player->GetName().c_str()); + TC_LOG_WARN("cheat", "%s attempted to open mailbox by using a cheat.", _player->GetName().c_str()); return false; } } @@ -108,7 +108,7 @@ void WorldSession::HandleSendMail(WorldPacket& recvData) if (!receiverGuid) { - TC_LOG_INFO("network", "Player %u is sending mail to %s (GUID: not existed!) with subject %s " + TC_LOG_INFO("network", "Player %u is sending mail to %s (GUID: non-existing!) with subject %s " "and body %s includes %u items, %u copper and %u COD copper with unk1 = %u, unk2 = %u", player->GetGUID().GetCounter(), receiverName.c_str(), subject.c_str(), body.c_str(), items_count, money, COD, stationery, package); @@ -117,7 +117,7 @@ void WorldSession::HandleSendMail(WorldPacket& recvData) } TC_LOG_INFO("network", "Player %u is sending mail to %s (%s) with subject %s and body %s " - "includes %u items, %u copper and %u COD copper with unk1 = %u, unk2 = %u", + "including %u items, %u copper and %u COD copper with unk1 = %u, unk2 = %u", player->GetGUID().GetCounter(), receiverName.c_str(), receiverGuid.ToString().c_str(), subject.c_str(), body.c_str(), items_count, money, COD, stationery, package); diff --git a/src/server/game/Handlers/MiscHandler.cpp b/src/server/game/Handlers/MiscHandler.cpp index 6cd8bfc014e..45cee59aec9 100644 --- a/src/server/game/Handlers/MiscHandler.cpp +++ b/src/server/game/Handlers/MiscHandler.cpp @@ -319,7 +319,7 @@ void WorldSession::HandleWhoOpcode(WorldPacket& recvData) continue; std::string aname; - if (AreaTableEntry const* areaEntry = GetAreaEntryByAreaID(pzoneid)) + if (AreaTableEntry const* areaEntry = sAreaTableStore.LookupEntry(pzoneid)) aname = areaEntry->area_name[GetSessionDbcLocale()]; bool s_show = true; @@ -1203,7 +1203,7 @@ void WorldSession::HandleInspectOpcode(WorldPacket& recvData) WorldPacket data(SMSG_INSPECT_TALENT, guid_size+4+talent_points); data << player->GetPackGUID(); - if (sWorld->getBoolConfig(CONFIG_TALENTS_INSPECTING) || _player->IsGameMaster()) + if (GetPlayer()->CanBeGameMaster() || sWorld->getIntConfig(CONFIG_TALENTS_INSPECTING) + (GetPlayer()->GetTeamId() == player->GetTeamId()) > 1) player->BuildPlayerTalentsInfoData(&data); else { @@ -1753,7 +1753,7 @@ void WorldSession::HandleHearthAndResurrect(WorldPacket& /*recvData*/) return; } - AreaTableEntry const* atEntry = GetAreaEntryByAreaID(_player->GetAreaId()); + AreaTableEntry const* atEntry = sAreaTableStore.LookupEntry(_player->GetAreaId()); if (!atEntry || !(atEntry->flags & AREA_FLAG_WINTERGRASP_2)) return; diff --git a/src/server/game/Handlers/MovementHandler.cpp b/src/server/game/Handlers/MovementHandler.cpp index eea5c62fbd1..02702fc5622 100644 --- a/src/server/game/Handlers/MovementHandler.cpp +++ b/src/server/game/Handlers/MovementHandler.cpp @@ -386,7 +386,7 @@ void WorldSession::HandleMovementOpcodes(WorldPacket& recvData) plrMover->UpdateFallInformationIfNeed(movementInfo, opcode); - if (movementInfo.pos.GetPositionZ() < -500.0f) + if (movementInfo.pos.GetPositionZ() < plrMover->GetMap()->GetMinHeight(movementInfo.pos.GetPositionX(), movementInfo.pos.GetPositionY())) { if (!(plrMover->GetBattleground() && plrMover->GetBattleground()->HandlePlayerUnderMap(_player))) { @@ -395,6 +395,7 @@ void WorldSession::HandleMovementOpcodes(WorldPacket& recvData) /// @todo discard movement packets after the player is rooted if (plrMover->IsAlive()) { + plrMover->SetFlag(PLAYER_FLAGS, PLAYER_FLAGS_IS_OUT_OF_BOUNDS); plrMover->EnvironmentalDamage(DAMAGE_FALL_TO_VOID, GetPlayer()->GetMaxHealth()); // player can be alive if GM/etc // change the death state to CORPSE to prevent the death timer from diff --git a/src/server/game/Instances/InstanceSaveMgr.cpp b/src/server/game/Instances/InstanceSaveMgr.cpp index 9a64335e6f0..3538262ed35 100644 --- a/src/server/game/Instances/InstanceSaveMgr.cpp +++ b/src/server/game/Instances/InstanceSaveMgr.cpp @@ -439,6 +439,23 @@ void InstanceSaveManager::LoadResetTimes() } } +time_t InstanceSaveManager::GetSubsequentResetTime(uint32 mapid, Difficulty difficulty, time_t resetTime) const +{ + MapDifficulty const* mapDiff = GetMapDifficultyData(mapid, difficulty); + if (!mapDiff || !mapDiff->resetTime) + { + TC_LOG_ERROR("misc", "InstanceSaveManager::GetSubsequentResetTime: not valid difficulty or no reset delay for map %u", mapid); + return 0; + } + + time_t diff = sWorld->getIntConfig(CONFIG_INSTANCE_RESET_TIME_HOUR) * HOUR; + time_t period = uint32(((mapDiff->resetTime * sWorld->getRate(RATE_INSTANCE_RESET_TIME)) / DAY) * DAY); + if (period < DAY) + period = DAY; + + return ((resetTime + MINUTE) / DAY * DAY) + period + diff; +} + void InstanceSaveManager::ScheduleReset(bool add, time_t time, InstResetEvent event) { if (!add) @@ -476,6 +493,17 @@ void InstanceSaveManager::ScheduleReset(bool add, time_t time, InstResetEvent ev m_resetTimeQueue.insert(std::pair<time_t, InstResetEvent>(time, event)); } +void InstanceSaveManager::ForceGlobalReset(uint32 mapId, Difficulty difficulty) +{ + if (!GetDownscaledMapDifficultyData(mapId, difficulty)) + return; + // remove currently scheduled reset times + ScheduleReset(false, 0, InstResetEvent(1, mapId, difficulty, 0)); + ScheduleReset(false, 0, InstResetEvent(4, mapId, difficulty, 0)); + // force global reset on the instance + _ResetOrWarnAll(mapId, difficulty, false, time(nullptr)); +} + void InstanceSaveManager::Update() { time_t now = time(NULL); @@ -516,10 +544,26 @@ void InstanceSaveManager::_ResetSave(InstanceSaveHashMap::iterator &itr) // do not allow UnbindInstance to automatically unload the InstanceSaves lock_instLists = true; + bool shouldDelete = true; InstanceSave::PlayerListType &pList = itr->second->m_playerList; - while (!pList.empty()) + std::vector<Player*> temp; // list of expired binds that should be unbound + for (Player* player : pList) + { + if (InstancePlayerBind* bind = player->GetBoundInstance(itr->second->GetMapId(), itr->second->GetDifficulty())) + { + ASSERT(bind->save == itr->second); + if (bind->perm && bind->extendState) // permanent and not already expired + { + // actual promotion in DB already happened in caller + bind->extendState = bind->extendState == EXTEND_STATE_EXTENDED ? EXTEND_STATE_NORMAL : EXTEND_STATE_EXPIRED; + shouldDelete = false; + continue; + } + } + temp.push_back(player); + } + for (Player* player : temp) { - Player* player = *(pList.begin()); player->UnbindInstance(itr->second->GetMapId(), itr->second->GetDifficulty(), true); } @@ -530,8 +574,13 @@ void InstanceSaveManager::_ResetSave(InstanceSaveHashMap::iterator &itr) group->UnbindInstance(itr->second->GetMapId(), itr->second->GetDifficulty(), true); } - delete itr->second; - m_instanceSaveById.erase(itr++); + if (shouldDelete) + { + delete itr->second; + itr = m_instanceSaveById.erase(itr); + } + else + ++itr; lock_instLists = false; } @@ -572,31 +621,21 @@ void InstanceSaveManager::_ResetOrWarnAll(uint32 mapid, Difficulty difficulty, b MapEntry const* mapEntry = sMapStore.LookupEntry(mapid); if (!mapEntry->Instanceable()) return; + TC_LOG_DEBUG("misc", "InstanceSaveManager::ResetOrWarnAll: Processing map %s (%u) on difficulty %u (warn? %u)", mapEntry->name[0], mapid, uint8(difficulty), warn); time_t now = time(NULL); if (!warn) { - MapDifficulty const* mapDiff = GetMapDifficultyData(mapid, difficulty); - if (!mapDiff || !mapDiff->resetTime) - { - TC_LOG_ERROR("misc", "InstanceSaveManager::ResetOrWarnAll: not valid difficulty or no reset delay for map %d", mapid); + // calculate the next reset time + time_t next_reset = GetSubsequentResetTime(mapid, difficulty, resetTime); + if (!next_reset) return; - } - // remove all binds to instances of the given map - for (InstanceSaveHashMap::iterator itr = m_instanceSaveById.begin(); itr != m_instanceSaveById.end();) - { - if (itr->second->GetMapId() == mapid && itr->second->GetDifficulty() == difficulty) - _ResetSave(itr); - else - ++itr; - } - - // delete them from the DB, even if not loaded + // delete/promote instance binds from the DB, even if not loaded SQLTransaction trans = CharacterDatabase.BeginTransaction(); - PreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_DEL_CHAR_INSTANCE_BY_MAP_DIFF); + PreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_DEL_EXPIRED_CHAR_INSTANCE_BY_MAP_DIFF); stmt->setUInt16(0, uint16(mapid)); stmt->setUInt8(1, uint8(difficulty)); trans->Append(stmt); @@ -606,21 +645,26 @@ void InstanceSaveManager::_ResetOrWarnAll(uint32 mapid, Difficulty difficulty, b stmt->setUInt8(1, uint8(difficulty)); trans->Append(stmt); - stmt = CharacterDatabase.GetPreparedStatement(CHAR_DEL_INSTANCE_BY_MAP_DIFF); + stmt = CharacterDatabase.GetPreparedStatement(CHAR_DEL_EXPIRED_INSTANCE_BY_MAP_DIFF); stmt->setUInt16(0, uint16(mapid)); stmt->setUInt8(1, uint8(difficulty)); trans->Append(stmt); - CharacterDatabase.CommitTransaction(trans); - - // calculate the next reset time - uint32 diff = sWorld->getIntConfig(CONFIG_INSTANCE_RESET_TIME_HOUR) * HOUR; + stmt = CharacterDatabase.GetPreparedStatement(CHAR_UPD_EXPIRE_CHAR_INSTANCE_BY_MAP_DIFF); + stmt->setUInt16(0, uint16(mapid)); + stmt->setUInt8(1, uint8(difficulty)); + trans->Append(stmt); - uint32 period = uint32(((mapDiff->resetTime * sWorld->getRate(RATE_INSTANCE_RESET_TIME))/DAY) * DAY); - if (period < DAY) - period = DAY; + CharacterDatabase.CommitTransaction(trans); - uint32 next_reset = uint32(((resetTime + MINUTE) / DAY * DAY) + period + diff); + // promote loaded binds to instances of the given map + for (InstanceSaveHashMap::iterator itr = m_instanceSaveById.begin(); itr != m_instanceSaveById.end();) + { + if (itr->second->GetMapId() == mapid && itr->second->GetDifficulty() == difficulty) + _ResetSave(itr); + else + ++itr; + } SetResetTimeFor(mapid, difficulty, next_reset); ScheduleReset(true, time_t(next_reset-3600), InstResetEvent(1, mapid, difficulty, 0)); diff --git a/src/server/game/Instances/InstanceSaveMgr.h b/src/server/game/Instances/InstanceSaveMgr.h index e3d8175cbc4..d2b3237b3cf 100644 --- a/src/server/game/Instances/InstanceSaveMgr.h +++ b/src/server/game/Instances/InstanceSaveMgr.h @@ -190,6 +190,7 @@ class InstanceSaveManager ResetTimeByMapDifficultyMap::const_iterator itr = m_resetTimeByMapDifficulty.find(MAKE_PAIR32(mapid, d)); return itr != m_resetTimeByMapDifficulty.end() ? itr->second : 0; } + time_t GetSubsequentResetTime(uint32 mapid, Difficulty difficulty, time_t resetTime) const; // Use this on startup when initializing reset times void InitializeResetTimeFor(uint32 mapid, Difficulty d, time_t t) @@ -210,6 +211,7 @@ class InstanceSaveManager return m_resetTimeByMapDifficulty; } void ScheduleReset(bool add, time_t time, InstResetEvent event); + void ForceGlobalReset(uint32 mapId, Difficulty difficulty); void Update(); diff --git a/src/server/game/Loot/LootMgr.cpp b/src/server/game/Loot/LootMgr.cpp index 530bcd2902c..19dc210ea5b 100644 --- a/src/server/game/Loot/LootMgr.cpp +++ b/src/server/game/Loot/LootMgr.cpp @@ -1580,8 +1580,8 @@ void LoadLootTemplates_Fishing() uint32 count = LootTemplates_Fishing.LoadAndCollectLootIds(lootIdSet); // remove real entries and check existence loot - for (uint32 i = 1; i < sAreaStore.GetNumRows(); ++i) - if (AreaTableEntry const* areaEntry = sAreaStore.LookupEntry(i)) + for (uint32 i = 1; i < sAreaTableStore.GetNumRows(); ++i) + if (AreaTableEntry const* areaEntry = sAreaTableStore.LookupEntry(i)) if (lootIdSet.find(areaEntry->ID) != lootIdSet.end()) lootIdSet.erase(areaEntry->ID); diff --git a/src/server/game/Mails/Mail.cpp b/src/server/game/Mails/Mail.cpp index b0e8a1ebe02..bc31a3c8c06 100644 --- a/src/server/game/Mails/Mail.cpp +++ b/src/server/game/Mails/Mail.cpp @@ -49,8 +49,8 @@ MailSender::MailSender(Object* sender, MailStationery stationery) : m_stationery break; default: m_messageType = MAIL_NORMAL; - m_senderId = 0; // will show mail from not existed player - TC_LOG_ERROR("misc", "MailSender::MailSender - Mail have unexpected sender typeid (%u)", sender->GetTypeId()); + m_senderId = 0; // will show mail from non-existing player + TC_LOG_ERROR("misc", "MailSender::MailSender - Mail message contains unexpected sender typeid (%u).", sender->GetTypeId()); break; } } diff --git a/src/server/game/Maps/Map.cpp b/src/server/game/Maps/Map.cpp index a2cb84359f2..2da5193b2ec 100644 --- a/src/server/game/Maps/Map.cpp +++ b/src/server/game/Maps/Map.cpp @@ -37,7 +37,7 @@ #include "VMapFactory.h" u_map_magic MapMagic = { {'M','A','P','S'} }; -u_map_magic MapVersionMagic = { {'v','1','.','3'} }; +u_map_magic MapVersionMagic = { {'v','1','.','8'} }; u_map_magic MapAreaMagic = { {'A','R','E','A'} }; u_map_magic MapHeightMagic = { {'M','H','G','T'} }; u_map_magic MapLiquidMagic = { {'M','L','I','Q'} }; @@ -594,7 +594,7 @@ bool Map::AddToMap(T* obj) //something, such as vehicle, needs to be update immediately //also, trigger needs to cast spell, if not update, cannot see visual - obj->UpdateObjectVisibility(true); + obj->UpdateObjectVisibilityOnCreate(); return true; } @@ -1644,13 +1644,15 @@ GridMap::GridMap() _flags = 0; // Area data _gridArea = 0; - _areaMap = NULL; + _areaMap = nullptr; // Height level data _gridHeight = INVALID_HEIGHT; _gridGetHeight = &GridMap::getHeightFromFlat; _gridIntHeightMultiplier = 0; - m_V9 = NULL; - m_V8 = NULL; + m_V9 = nullptr; + m_V8 = nullptr; + _maxHeight = nullptr; + _minHeight = nullptr; // Liquid data _liquidType = 0; _liquidOffX = 0; @@ -1658,9 +1660,9 @@ GridMap::GridMap() _liquidWidth = 0; _liquidHeight = 0; _liquidLevel = INVALID_HEIGHT; - _liquidEntry = NULL; - _liquidFlags = NULL; - _liquidMap = NULL; + _liquidEntry = nullptr; + _liquidFlags = nullptr; + _liquidMap = nullptr; } GridMap::~GridMap() @@ -1723,15 +1725,19 @@ void GridMap::unloadData() delete[] _areaMap; delete[] m_V9; delete[] m_V8; + delete[] _maxHeight; + delete[] _minHeight; delete[] _liquidEntry; delete[] _liquidFlags; delete[] _liquidMap; - _areaMap = NULL; - m_V9 = NULL; - m_V8 = NULL; - _liquidEntry = NULL; - _liquidFlags = NULL; - _liquidMap = NULL; + _areaMap = nullptr; + m_V9 = nullptr; + m_V8 = nullptr; + _maxHeight = nullptr; + _minHeight = nullptr; + _liquidEntry = nullptr; + _liquidFlags = nullptr; + _liquidMap = nullptr; _gridGetHeight = &GridMap::getHeightFromFlat; } @@ -1746,7 +1752,7 @@ bool GridMap::loadAreaData(FILE* in, uint32 offset, uint32 /*size*/) _gridArea = header.gridArea; if (!(header.flags & MAP_AREA_NO_AREA)) { - _areaMap = new uint16 [16*16]; + _areaMap = new uint16[16 * 16]; if (fread(_areaMap, sizeof(uint16), 16*16, in) != 16*16) return false; } @@ -1796,6 +1802,16 @@ bool GridMap::loadHeightData(FILE* in, uint32 offset, uint32 /*size*/) } else _gridGetHeight = &GridMap::getHeightFromFlat; + + if (header.flags & MAP_HEIGHT_HAS_FLIGHT_BOUNDS) + { + _maxHeight = new int16[3 * 3]; + _minHeight = new int16[3 * 3]; + if (fread(_maxHeight, sizeof(int16), 3 * 3, in) != 3 * 3 || + fread(_minHeight, sizeof(int16), 3 * 3, in) != 3 * 3) + return false; + } + return true; } @@ -2066,6 +2082,66 @@ float GridMap::getHeightFromUint16(float x, float y) const return (float)((a * x) + (b * y) + c)*_gridIntHeightMultiplier + _gridHeight; } +float GridMap::getMinHeight(float x, float y) const +{ + if (!_minHeight) + return -500.0f; + + static uint32 const indices[] = + { + 3, 0, 4, + 0, 1, 4, + 1, 2, 4, + 2, 5, 4, + 5, 8, 4, + 8, 7, 4, + 7, 6, 4, + 6, 3, 4 + }; + + static float const boundGridCoords[] = + { + 0.0f, 0.0f, + 0.0f, -266.66666f, + 0.0f, -533.33331f, + -266.66666f, 0.0f, + -266.66666f, -266.66666f, + -266.66666f, -533.33331f, + -533.33331f, 0.0f, + -533.33331f, -266.66666f, + -533.33331f, -533.33331f + }; + + Cell cell(x, y); + float gx = x - (int32(cell.GridX()) - CENTER_GRID_ID + 1) * SIZE_OF_GRIDS; + float gy = y - (int32(cell.GridY()) - CENTER_GRID_ID + 1) * SIZE_OF_GRIDS; + + uint32 quarterIndex = 0; + if (cell.CellY() < MAX_NUMBER_OF_CELLS / 2) + { + if (cell.CellX() < MAX_NUMBER_OF_CELLS / 2) + { + quarterIndex = 4 + (gy > gx); + } + else + quarterIndex = 2 + ((-SIZE_OF_GRIDS - gx) > gy); + } + else if (cell.CellX() < MAX_NUMBER_OF_CELLS / 2) + { + quarterIndex = 6 + ((-SIZE_OF_GRIDS - gx) <= gy); + } + else + quarterIndex = gx > gy; + + quarterIndex *= 3; + + return G3D::Plane( + G3D::Vector3(boundGridCoords[indices[quarterIndex + 0] * 2 + 0], boundGridCoords[indices[quarterIndex + 0] * 2 + 1], _minHeight[indices[quarterIndex + 0]]), + G3D::Vector3(boundGridCoords[indices[quarterIndex + 1] * 2 + 0], boundGridCoords[indices[quarterIndex + 1] * 2 + 1], _minHeight[indices[quarterIndex + 1]]), + G3D::Vector3(boundGridCoords[indices[quarterIndex + 2] * 2 + 0], boundGridCoords[indices[quarterIndex + 2] * 2 + 1], _minHeight[indices[quarterIndex + 2]]) + ).distance(G3D::Vector3(gx, gy, 0.0f)); +} + float GridMap::getLiquidLevel(float x, float y) const { if (!_liquidMap) @@ -2125,12 +2201,12 @@ inline ZLiquidStatus GridMap::getLiquidStatus(float x, float y, float z, uint8 R uint32 liqTypeIdx = liquidEntry->Type; if (entry < 21) { - if (AreaTableEntry const* area = GetAreaEntryByAreaFlagAndMap(getArea(x, y), MAPID_INVALID)) + if (AreaTableEntry const* area = sAreaTableStore.LookupEntry(getArea(x, y))) { uint32 overrideLiquid = area->LiquidTypeOverride[liquidEntry->Type]; if (!overrideLiquid && area->zone) { - area = GetAreaEntryByAreaID(area->zone); + area = sAreaTableStore.LookupEntry(area->zone); if (area) overrideLiquid = area->LiquidTypeOverride[liquidEntry->Type]; } @@ -2266,6 +2342,14 @@ float Map::GetHeight(float x, float y, float z, bool checkVMap /*= true*/, float return mapHeight; // explicitly use map data } +float Map::GetMinHeight(float x, float y) const +{ + if (GridMap const* grid = const_cast<Map*>(this)->GetGrid(x, y)) + return grid->getMinHeight(x, y); + + return -500.0f; +} + inline bool IsOutdoorWMO(uint32 mogpFlags, int32 /*adtId*/, int32 /*rootId*/, int32 /*groupId*/, WMOAreaTableEntry const* wmoEntry, AreaTableEntry const* atEntry) { bool outdoor = true; @@ -2304,7 +2388,7 @@ bool Map::IsOutdoors(float x, float y, float z) const if (wmoEntry) { TC_LOG_DEBUG("maps", "Got WMOAreaTableEntry! flag %u, areaid %u", wmoEntry->Flags, wmoEntry->areaId); - atEntry = GetAreaEntryByAreaID(wmoEntry->areaId); + atEntry = sAreaTableStore.LookupEntry(wmoEntry->areaId); } return IsOutdoorWMO(mogpFlags, adtId, rootId, groupId, wmoEntry, atEntry); } @@ -2328,7 +2412,7 @@ bool Map::GetAreaInfo(float x, float y, float z, uint32 &flags, int32 &adtId, in return false; } -uint16 Map::GetAreaFlag(float x, float y, float z, bool *isOutdoors) const +uint32 Map::GetAreaId(float x, float y, float z, bool *isOutdoors) const { uint32 mogpFlags; int32 adtId, rootId, groupId; @@ -2341,20 +2425,21 @@ uint16 Map::GetAreaFlag(float x, float y, float z, bool *isOutdoors) const haveAreaInfo = true; wmoEntry = GetWMOAreaTableEntryByTripple(rootId, adtId, groupId); if (wmoEntry) - atEntry = GetAreaEntryByAreaID(wmoEntry->areaId); + atEntry = sAreaTableStore.LookupEntry(wmoEntry->areaId); } - uint16 areaflag; + uint32 areaId = 0; if (atEntry) - areaflag = atEntry->exploreFlag; + areaId = atEntry->ID; else { if (GridMap* gmap = const_cast<Map*>(this)->GetGrid(x, y)) - areaflag = gmap->getArea(x, y); + areaId = gmap->getArea(x, y); + // this used while not all *.map files generated (instances) - else - areaflag = GetAreaFlagByMapId(i_mapEntry->MapID); + if (!areaId) + areaId = i_mapEntry->linked_zone; } if (isOutdoors) @@ -2364,8 +2449,31 @@ uint16 Map::GetAreaFlag(float x, float y, float z, bool *isOutdoors) const else *isOutdoors = true; } - return areaflag; - } + return areaId; +} + +uint32 Map::GetAreaId(float x, float y, float z) const +{ + return GetAreaId(x, y, z, nullptr); +} + +uint32 Map::GetZoneId(float x, float y, float z) const +{ + uint32 areaId = GetAreaId(x, y, z); + if (AreaTableEntry const* area = sAreaTableStore.LookupEntry(areaId)) + if (area->zone) + return area->zone; + + return areaId; +} + +void Map::GetZoneAndAreaId(uint32& zoneid, uint32& areaid, float x, float y, float z) const +{ + areaid = zoneid = GetAreaId(x, y, z); + if (AreaTableEntry const* area = sAreaTableStore.LookupEntry(areaid)) + if (area->zone) + zoneid = area->zone; +} uint8 Map::GetTerrainType(float x, float y) const { @@ -2401,12 +2509,12 @@ ZLiquidStatus Map::getLiquidStatus(float x, float y, float z, uint8 ReqLiquidTyp if (liquid_type && liquid_type < 21) { - if (AreaTableEntry const* area = GetAreaEntryByAreaFlagAndMap(GetAreaFlag(x, y, z), GetId())) + if (AreaTableEntry const* area = sAreaTableStore.LookupEntry(GetAreaId(x, y, z))) { uint32 overrideLiquid = area->LiquidTypeOverride[liquidFlagType]; if (!overrideLiquid && area->zone) { - area = GetAreaEntryByAreaID(area->zone); + area = sAreaTableStore.LookupEntry(area->zone); if (area) overrideLiquid = area->LiquidTypeOverride[liquidFlagType]; } @@ -2468,34 +2576,6 @@ float Map::GetWaterLevel(float x, float y) const return 0; } -uint32 Map::GetAreaIdByAreaFlag(uint16 areaflag, uint32 map_id) -{ - AreaTableEntry const* entry = GetAreaEntryByAreaFlagAndMap(areaflag, map_id); - - if (entry) - return entry->ID; - else - return 0; -} - -uint32 Map::GetZoneIdByAreaFlag(uint16 areaflag, uint32 map_id) -{ - AreaTableEntry const* entry = GetAreaEntryByAreaFlagAndMap(areaflag, map_id); - - if (entry) - return (entry->zone != 0) ? entry->zone : entry->ID; - else - return 0; -} - -void Map::GetZoneAndAreaIdByAreaFlag(uint32& zoneid, uint32& areaid, uint16 areaflag, uint32 map_id) -{ - AreaTableEntry const* entry = GetAreaEntryByAreaFlagAndMap(areaflag, map_id); - - areaid = entry ? entry->ID : 0; - zoneid = entry ? ((entry->zone != 0) ? entry->zone : entry->ID) : 0; -} - bool Map::isInLineOfSight(float x1, float y1, float z1, float x2, float y2, float z2, uint32 phasemask) const { return VMAP::VMapFactory::createOrGetVMapManager()->isInLineOfSight(GetId(), x1, y1, z1, x2, y2, z2) @@ -3178,22 +3258,37 @@ bool InstanceMap::Reset(uint8 method) } else { + bool doUnload = true; if (method == INSTANCE_RESET_GLOBAL) + { // set the homebind timer for players inside (1 minute) for (MapRefManager::iterator itr = m_mapRefManager.begin(); itr != m_mapRefManager.end(); ++itr) - itr->GetSource()->m_InstanceValid = false; + { + InstancePlayerBind* bind = itr->GetSource()->GetBoundInstance(GetId(), GetDifficulty()); + if (bind && bind->extendState && bind->save->GetInstanceId() == GetInstanceId()) + doUnload = false; + else + itr->GetSource()->m_InstanceValid = false; + } + + if (doUnload && HasPermBoundPlayers()) // check if any unloaded players have a nonexpired save to this + doUnload = false; + } - // the unload timer is not started - // instead the map will unload immediately after the players have left - m_unloadWhenEmpty = true; - m_resetAfterUnload = true; + if (doUnload) + { + // the unload timer is not started + // instead the map will unload immediately after the players have left + m_unloadWhenEmpty = true; + m_resetAfterUnload = true; + } } } else { // unloaded at next update m_unloadTimer = MIN_UNLOAD_DELAY; - m_resetAfterUnload = true; + m_resetAfterUnload = !(method == INSTANCE_RESET_GLOBAL && HasPermBoundPlayers()); } return m_mapRefManager.isEmpty(); @@ -3274,6 +3369,13 @@ MapDifficulty const* Map::GetMapDifficulty() const return GetMapDifficultyData(GetId(), GetDifficulty()); } +bool InstanceMap::HasPermBoundPlayers() const +{ + PreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_SEL_PERM_BIND_BY_INSTANCE); + stmt->setUInt16(0,GetInstanceId()); + return !!CharacterDatabase.Query(stmt); +} + uint32 InstanceMap::GetMaxPlayers() const { MapDifficulty const* mapDiff = GetMapDifficulty(); diff --git a/src/server/game/Maps/Map.h b/src/server/game/Maps/Map.h index 01db38d9c30..bc2bf72f271 100644 --- a/src/server/game/Maps/Map.h +++ b/src/server/game/Maps/Map.h @@ -98,9 +98,10 @@ struct map_areaHeader uint16 gridArea; }; -#define MAP_HEIGHT_NO_HEIGHT 0x0001 -#define MAP_HEIGHT_AS_INT16 0x0002 -#define MAP_HEIGHT_AS_INT8 0x0004 +#define MAP_HEIGHT_NO_HEIGHT 0x0001 +#define MAP_HEIGHT_AS_INT16 0x0002 +#define MAP_HEIGHT_AS_INT8 0x0004 +#define MAP_HEIGHT_HAS_FLIGHT_BOUNDS 0x0008 struct map_heightHeader { @@ -166,6 +167,8 @@ class GridMap uint16* m_uint16_V8; uint8* m_uint8_V8; }; + int16* _maxHeight; + int16* _minHeight; // Height level data float _gridHeight; float _gridIntHeightMultiplier; @@ -206,6 +209,7 @@ public: uint16 getArea(float x, float y) const; inline float getHeight(float x, float y) const {return (this->*_gridGetHeight)(x, y);} + float getMinHeight(float x, float y) const; float getLiquidLevel(float x, float y) const; uint8 getTerrainType(float x, float y) const; ZLiquidStatus getLiquidStatus(float x, float y, float z, uint8 ReqLiquidType, LiquidData* data = 0); @@ -326,11 +330,15 @@ class Map : public GridRefManager<NGridType> // some calls like isInWater should not use vmaps due to processor power // can return INVALID_HEIGHT if under z+2 z coord not found height float GetHeight(float x, float y, float z, bool checkVMap = true, float maxSearchDist = DEFAULT_HEIGHT_SEARCH) const; + float GetMinHeight(float x, float y) const; ZLiquidStatus getLiquidStatus(float x, float y, float z, uint8 ReqLiquidType, LiquidData* data = nullptr) const; - uint16 GetAreaFlag(float x, float y, float z, bool *isOutdoors=nullptr) const; - bool GetAreaInfo(float x, float y, float z, uint32 &mogpflags, int32 &adtId, int32 &rootId, int32 &groupId) const; + uint32 GetAreaId(float x, float y, float z, bool *isOutdoors) const; + bool GetAreaInfo(float x, float y, float z, uint32& mogpflags, int32& adtId, int32& rootId, int32& groupId) const; + uint32 GetAreaId(float x, float y, float z) const; + uint32 GetZoneId(float x, float y, float z) const; + void GetZoneAndAreaId(uint32& zoneid, uint32& areaid, float x, float y, float z) const; bool IsOutdoors(float x, float y, float z) const; @@ -339,25 +347,6 @@ class Map : public GridRefManager<NGridType> bool IsInWater(float x, float y, float z, LiquidData* data = nullptr) const; bool IsUnderWater(float x, float y, float z) const; - static uint32 GetAreaIdByAreaFlag(uint16 areaflag, uint32 map_id); - static uint32 GetZoneIdByAreaFlag(uint16 areaflag, uint32 map_id); - static void GetZoneAndAreaIdByAreaFlag(uint32& zoneid, uint32& areaid, uint16 areaflag, uint32 map_id); - - uint32 GetAreaId(float x, float y, float z) const - { - return GetAreaIdByAreaFlag(GetAreaFlag(x, y, z), GetId()); - } - - uint32 GetZoneId(float x, float y, float z) const - { - return GetZoneIdByAreaFlag(GetAreaFlag(x, y, z), GetId()); - } - - void GetZoneAndAreaId(uint32& zoneid, uint32& areaid, float x, float y, float z) const - { - GetZoneAndAreaIdByAreaFlag(zoneid, areaid, GetAreaFlag(x, y, z), GetId()); - } - void MoveAllCreaturesInMoveList(); void MoveAllGameObjectsInMoveList(); void MoveAllDynamicObjectsInMoveList(); @@ -782,6 +771,9 @@ class InstanceMap : public Map void SendResetWarnings(uint32 timeLeft) const; void SetResetSchedule(bool on); + /* this checks if any players have a permanent bind (included reactivatable expired binds) to the instance ID + it needs a DB query, so use sparingly */ + bool HasPermBoundPlayers() const; uint32 GetMaxPlayers() const; uint32 GetMaxResetDelay() const; diff --git a/src/server/game/Maps/MapManager.h b/src/server/game/Maps/MapManager.h index 51bb418bdf5..7f9621593d4 100644 --- a/src/server/game/Maps/MapManager.h +++ b/src/server/game/Maps/MapManager.h @@ -42,22 +42,20 @@ class MapManager Map* CreateMap(uint32 mapId, Player* player, uint32 loginInstanceId=0); Map* FindMap(uint32 mapId, uint32 instanceId) const; - uint16 GetAreaFlag(uint32 mapid, float x, float y, float z) const - { - Map const* m = const_cast<MapManager*>(this)->CreateBaseMap(mapid); - return m->GetAreaFlag(x, y, z); - } uint32 GetAreaId(uint32 mapid, float x, float y, float z) const { - return Map::GetAreaIdByAreaFlag(GetAreaFlag(mapid, x, y, z), mapid); + Map const* m = const_cast<MapManager*>(this)->CreateBaseMap(mapid); + return m->GetAreaId(x, y, z); } uint32 GetZoneId(uint32 mapid, float x, float y, float z) const { - return Map::GetZoneIdByAreaFlag(GetAreaFlag(mapid, x, y, z), mapid); + Map const* m = const_cast<MapManager*>(this)->CreateBaseMap(mapid); + return m->GetZoneId(x, y, z); } void GetZoneAndAreaId(uint32& zoneid, uint32& areaid, uint32 mapid, float x, float y, float z) { - Map::GetZoneAndAreaIdByAreaFlag(zoneid, areaid, GetAreaFlag(mapid, x, y, z), mapid); + Map const* m = const_cast<MapManager*>(this)->CreateBaseMap(mapid); + m->GetZoneAndAreaId(zoneid, areaid, x, y, z); } void Initialize(void); diff --git a/src/server/game/Movement/MotionMaster.cpp b/src/server/game/Movement/MotionMaster.cpp index 3fcae1398f9..2a57524cb3c 100644 --- a/src/server/game/Movement/MotionMaster.cpp +++ b/src/server/game/Movement/MotionMaster.cpp @@ -193,7 +193,7 @@ void MotionMaster::MoveRandom(float spawndist) { if (_owner->GetTypeId() == TYPEID_UNIT) { - TC_LOG_DEBUG("misc", "Creature (GUID: %u) start moving random", _owner->GetGUID().GetCounter()); + TC_LOG_DEBUG("misc", "Creature (GUID: %u) started random movement.", _owner->GetGUID().GetCounter()); Mutate(new RandomMovementGenerator<Creature>(spawndist), MOTION_SLOT_IDLE); } } @@ -204,22 +204,22 @@ void MotionMaster::MoveTargetedHome() if (_owner->GetTypeId() == TYPEID_UNIT && !_owner->ToCreature()->GetCharmerOrOwnerGUID()) { - TC_LOG_DEBUG("misc", "Creature (Entry: %u GUID: %u) targeted home", _owner->GetEntry(), _owner->GetGUID().GetCounter()); + TC_LOG_DEBUG("misc", "Creature (Entry: %u GUID: %u) targeted home.", _owner->GetEntry(), _owner->GetGUID().GetCounter()); Mutate(new HomeMovementGenerator<Creature>(), MOTION_SLOT_ACTIVE); } else if (_owner->GetTypeId() == TYPEID_UNIT && _owner->ToCreature()->GetCharmerOrOwnerGUID()) { - TC_LOG_DEBUG("misc", "Pet or controlled creature (Entry: %u GUID: %u) targeting home", _owner->GetEntry(), _owner->GetGUID().GetCounter()); + TC_LOG_DEBUG("misc", "Pet or controlled creature (Entry: %u GUID: %u) is targeting home.", _owner->GetEntry(), _owner->GetGUID().GetCounter()); Unit* target = _owner->ToCreature()->GetCharmerOrOwner(); if (target) { - TC_LOG_DEBUG("misc", "Following %s (GUID: %u)", target->GetTypeId() == TYPEID_PLAYER ? "player" : "creature", target->GetTypeId() == TYPEID_PLAYER ? target->GetGUID().GetCounter() : ((Creature*)target)->GetSpawnId()); + TC_LOG_DEBUG("misc", "Following %s (GUID: %u).", target->GetTypeId() == TYPEID_PLAYER ? "player" : "creature", target->GetTypeId() == TYPEID_PLAYER ? target->GetGUID().GetCounter() : ((Creature*)target)->GetSpawnId()); Mutate(new FollowMovementGenerator<Creature>(target, PET_FOLLOW_DIST, PET_FOLLOW_ANGLE), MOTION_SLOT_ACTIVE); } } else { - TC_LOG_ERROR("misc", "Player (GUID: %u) attempt targeted home", _owner->GetGUID().GetCounter()); + TC_LOG_ERROR("misc", "Player (GUID: %u) attempted to move towards target home.", _owner->GetGUID().GetCounter()); } } @@ -272,14 +272,14 @@ void MotionMaster::MoveFollow(Unit* target, float dist, float angle, MovementSlo //_owner->AddUnitState(UNIT_STATE_FOLLOW); if (_owner->GetTypeId() == TYPEID_PLAYER) { - TC_LOG_DEBUG("misc", "Player (GUID: %u) follow to %s (GUID: %u)", _owner->GetGUID().GetCounter(), + TC_LOG_DEBUG("misc", "Player (GUID: %u) follows %s (GUID: %u).", _owner->GetGUID().GetCounter(), target->GetTypeId() == TYPEID_PLAYER ? "player" : "creature", target->GetTypeId() == TYPEID_PLAYER ? target->GetGUID().GetCounter() : target->ToCreature()->GetSpawnId()); Mutate(new FollowMovementGenerator<Player>(target, dist, angle), slot); } else { - TC_LOG_DEBUG("misc", "Creature (Entry: %u GUID: %u) follow to %s (GUID: %u)", + TC_LOG_DEBUG("misc", "Creature (Entry: %u GUID: %u) follows %s (GUID: %u).", _owner->GetEntry(), _owner->GetGUID().GetCounter(), target->GetTypeId() == TYPEID_PLAYER ? "player" : "creature", target->GetTypeId() == TYPEID_PLAYER ? target->GetGUID().GetCounter() : target->ToCreature()->GetSpawnId()); @@ -291,12 +291,12 @@ void MotionMaster::MovePoint(uint32 id, float x, float y, float z, bool generate { if (_owner->GetTypeId() == TYPEID_PLAYER) { - TC_LOG_DEBUG("misc", "Player (GUID: %u) targeted point (Id: %u X: %f Y: %f Z: %f)", _owner->GetGUID().GetCounter(), id, x, y, z); + TC_LOG_DEBUG("misc", "Player (GUID: %u) targeted point (Id: %u X: %f Y: %f Z: %f).", _owner->GetGUID().GetCounter(), id, x, y, z); Mutate(new PointMovementGenerator<Player>(id, x, y, z, generatePath), MOTION_SLOT_ACTIVE); } else { - TC_LOG_DEBUG("misc", "Creature (Entry: %u GUID: %u) targeted point (ID: %u X: %f Y: %f Z: %f)", + TC_LOG_DEBUG("misc", "Creature (Entry: %u GUID: %u) targeted point (ID: %u X: %f Y: %f Z: %f).", _owner->GetEntry(), _owner->GetGUID().GetCounter(), id, x, y, z); Mutate(new PointMovementGenerator<Creature>(id, x, y, z, generatePath), MOTION_SLOT_ACTIVE); } @@ -307,7 +307,7 @@ void MotionMaster::MoveLand(uint32 id, Position const& pos) float x, y, z; pos.GetPosition(x, y, z); - TC_LOG_DEBUG("misc", "Creature (Entry: %u) landing point (ID: %u X: %f Y: %f Z: %f)", _owner->GetEntry(), id, x, y, z); + TC_LOG_DEBUG("misc", "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); @@ -321,7 +321,7 @@ void MotionMaster::MoveTakeoff(uint32 id, Position const& pos) float x, y, z; pos.GetPosition(x, y, z); - TC_LOG_DEBUG("misc", "Creature (Entry: %u) landing point (ID: %u X: %f Y: %f Z: %f)", _owner->GetEntry(), id, x, y, z); + TC_LOG_DEBUG("misc", "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); @@ -366,12 +366,12 @@ void MotionMaster::MoveJumpTo(float angle, float speedXY, float speedZ) float moveTimeHalf = speedZ / Movement::gravity; float dist = 2 * moveTimeHalf * speedXY; _owner->GetClosePoint(x, y, z, _owner->GetObjectSize(), dist, angle); - MoveJump(x, y, z, speedXY, speedZ); + MoveJump(x, y, z, 0.0f, speedXY, speedZ); } -void MotionMaster::MoveJump(float x, float y, float z, float speedXY, float speedZ, uint32 id) +void MotionMaster::MoveJump(float x, float y, float z, float o, float speedXY, float speedZ, uint32 id, bool hasOrientation /* = false*/) { - TC_LOG_DEBUG("misc", "Unit (GUID: %u) jump to point (X: %f Y: %f Z: %f)", _owner->GetGUID().GetCounter(), x, y, z); + TC_LOG_DEBUG("misc", "Unit (GUID: %u) jumps to point (X: %f Y: %f Z: %f).", _owner->GetGUID().GetCounter(), x, y, z); if (speedXY <= 0.1f) return; @@ -382,6 +382,8 @@ void MotionMaster::MoveJump(float x, float y, float z, float speedXY, float spee init.MoveTo(x, y, z, false); init.SetParabolic(max_height, 0); init.SetVelocity(speedXY); + if (hasOrientation) + init.SetFacing(o); init.Launch(); Mutate(new EffectMovementGenerator(id), MOTION_SLOT_CONTROLLED); } @@ -447,7 +449,7 @@ void MotionMaster::MoveFall(uint32 id /*=0*/) float tz = _owner->GetMap()->GetHeight(_owner->GetPhaseMask(), _owner->GetPositionX(), _owner->GetPositionY(), _owner->GetPositionZ(), true, MAX_FALL_DISTANCE); if (tz <= INVALID_HEIGHT) { - TC_LOG_DEBUG("misc", "MotionMaster::MoveFall: unable retrive a proper height at map %u (x: %f, y: %f, z: %f).", + TC_LOG_DEBUG("misc", "MotionMaster::MoveFall: unable to retrieve a proper height at map %u (x: %f, y: %f, z: %f).", _owner->GetMap()->GetId(), _owner->GetPositionX(), _owner->GetPositionY(), _owner->GetPositionZ()); return; } @@ -476,12 +478,12 @@ void MotionMaster::MoveCharge(float x, float y, float z, float speed /*= SPEED_C if (_owner->GetTypeId() == TYPEID_PLAYER) { - TC_LOG_DEBUG("misc", "Player (GUID: %u) charge point (X: %f Y: %f Z: %f)", _owner->GetGUID().GetCounter(), x, y, z); + TC_LOG_DEBUG("misc", "Player (GUID: %u) charged point (X: %f Y: %f Z: %f).", _owner->GetGUID().GetCounter(), x, y, z); Mutate(new PointMovementGenerator<Player>(id, x, y, z, generatePath, speed), MOTION_SLOT_CONTROLLED); } else { - TC_LOG_DEBUG("misc", "Creature (Entry: %u GUID: %u) charge point (X: %f Y: %f Z: %f)", + TC_LOG_DEBUG("misc", "Creature (Entry: %u GUID: %u) charged point (X: %f Y: %f Z: %f).", _owner->GetEntry(), _owner->GetGUID().GetCounter(), x, y, z); Mutate(new PointMovementGenerator<Creature>(id, x, y, z, generatePath, speed), MOTION_SLOT_CONTROLLED); } @@ -504,7 +506,7 @@ void MotionMaster::MoveSeekAssistance(float x, float y, float z) { if (_owner->GetTypeId() == TYPEID_PLAYER) { - TC_LOG_ERROR("misc", "Player (GUID: %u) attempt to seek assistance", _owner->GetGUID().GetCounter()); + TC_LOG_ERROR("misc", "Player (GUID: %u) attempted to seek assistance.", _owner->GetGUID().GetCounter()); } else { @@ -520,11 +522,11 @@ void MotionMaster::MoveSeekAssistanceDistract(uint32 time) { if (_owner->GetTypeId() == TYPEID_PLAYER) { - TC_LOG_ERROR("misc", "Player (GUID: %u) attempt to call distract after assistance", _owner->GetGUID().GetCounter()); + TC_LOG_ERROR("misc", "Player (GUID: %u) attempted to call distract assistance.", _owner->GetGUID().GetCounter()); } else { - TC_LOG_DEBUG("misc", "Creature (Entry: %u GUID: %u) is distracted after assistance call (Time: %u)", + TC_LOG_DEBUG("misc", "Creature (Entry: %u GUID: %u) is distracted after assistance call (Time: %u).", _owner->GetEntry(), _owner->GetGUID().GetCounter(), time); Mutate(new AssistanceDistractMovementGenerator(time), MOTION_SLOT_ACTIVE); } @@ -537,14 +539,14 @@ void MotionMaster::MoveFleeing(Unit* enemy, uint32 time) if (_owner->GetTypeId() == TYPEID_PLAYER) { - TC_LOG_DEBUG("misc", "Player (GUID: %u) flee from %s (GUID: %u)", _owner->GetGUID().GetCounter(), + TC_LOG_DEBUG("misc", "Player (GUID: %u) flees from %s (GUID: %u).", _owner->GetGUID().GetCounter(), enemy->GetTypeId() == TYPEID_PLAYER ? "player" : "creature", enemy->GetTypeId() == TYPEID_PLAYER ? enemy->GetGUID().GetCounter() : enemy->ToCreature()->GetSpawnId()); Mutate(new FleeingMovementGenerator<Player>(enemy->GetGUID()), MOTION_SLOT_CONTROLLED); } else { - TC_LOG_DEBUG("misc", "Creature (Entry: %u GUID: %u) flee from %s (GUID: %u)%s", + TC_LOG_DEBUG("misc", "Creature (Entry: %u GUID: %u) flees from %s (GUID: %u)%s.", _owner->GetEntry(), _owner->GetGUID().GetCounter(), enemy->GetTypeId() == TYPEID_PLAYER ? "player" : "creature", enemy->GetTypeId() == TYPEID_PLAYER ? enemy->GetGUID().GetCounter() : enemy->ToCreature()->GetSpawnId(), @@ -562,20 +564,20 @@ void MotionMaster::MoveTaxiFlight(uint32 path, uint32 pathnode) { if (path < sTaxiPathNodesByPath.size()) { - TC_LOG_DEBUG("misc", "%s taxi to (Path %u node %u)", _owner->GetName().c_str(), path, pathnode); + TC_LOG_DEBUG("misc", "%s taxi to (Path %u node %u).", _owner->GetName().c_str(), path, pathnode); FlightPathMovementGenerator* mgen = new FlightPathMovementGenerator(pathnode); mgen->LoadPath(_owner->ToPlayer()); Mutate(mgen, MOTION_SLOT_CONTROLLED); } else { - TC_LOG_ERROR("misc", "%s attempt taxi to (not existed Path %u node %u)", + TC_LOG_ERROR("misc", "%s attempted taxi to (non-existing Path %u node %u).", _owner->GetName().c_str(), path, pathnode); } } else { - TC_LOG_ERROR("misc", "Creature (Entry: %u GUID: %u) attempt taxi to (Path %u node %u)", + TC_LOG_ERROR("misc", "Creature (Entry: %u GUID: %u) attempted taxi to (Path %u node %u).", _owner->GetEntry(), _owner->GetGUID().GetCounter(), path, pathnode); } } @@ -587,11 +589,11 @@ void MotionMaster::MoveDistract(uint32 timer) if (_owner->GetTypeId() == TYPEID_PLAYER) { - TC_LOG_DEBUG("misc", "Player (GUID: %u) distracted (timer: %u)", _owner->GetGUID().GetCounter(), timer); + TC_LOG_DEBUG("misc", "Player (GUID: %u) distracted (timer: %u).", _owner->GetGUID().GetCounter(), timer); } else { - TC_LOG_DEBUG("misc", "Creature (Entry: %u GUID: %u) (timer: %u)", + TC_LOG_DEBUG("misc", "Creature (Entry: %u GUID: %u) distracted (timer: %u)", _owner->GetEntry(), _owner->GetGUID().GetCounter(), timer); } @@ -643,7 +645,7 @@ void MotionMaster::MovePath(uint32 path_id, bool repeatable) //Mutate(new WaypointMovementGenerator<Player>(path_id, repeatable)): Mutate(new WaypointMovementGenerator<Creature>(path_id, repeatable), MOTION_SLOT_IDLE); - TC_LOG_DEBUG("misc", "%s (GUID: %u) start moving over path(Id:%u, repeatable: %s)", + TC_LOG_DEBUG("misc", "%s (GUID: %u) starts moving over path(Id:%u, repeatable: %s).", _owner->GetTypeId() == TYPEID_PLAYER ? "Player" : "Creature", _owner->GetGUID().GetCounter(), path_id, repeatable ? "YES" : "NO"); } diff --git a/src/server/game/Movement/MotionMaster.h b/src/server/game/Movement/MotionMaster.h index ce0f1f7836e..76ae12986d5 100644 --- a/src/server/game/Movement/MotionMaster.h +++ b/src/server/game/Movement/MotionMaster.h @@ -181,9 +181,11 @@ class MotionMaster //: private std::stack<MovementGenerator *> void MoveCharge(PathGenerator const& path, float speed = SPEED_CHARGE); 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) - { MoveJump(pos.m_positionX, pos.m_positionY, pos.m_positionZ, speedXY, speedZ, id); } - void MoveJump(float x, float y, float z, float speedXY, float speedZ, uint32 id = EVENT_JUMP); + void MoveJump(Position const& pos, float speedXY, float speedZ, uint32 id = EVENT_JUMP, bool hasOrientation = false) + { + MoveJump(pos.GetPositionX(), pos.GetPositionY(), pos.GetPositionZ(), pos.GetOrientation(), speedXY, speedZ, id, hasOrientation); + } + void MoveJump(float x, float y, float z, float o, float speedXY, float speedZ, uint32 id = EVENT_JUMP, bool hasOrientation = false); void MoveCirclePath(float x, float y, float z, float radius, bool clockwise, uint8 stepCount); void MoveSmoothPath(uint32 pointId, G3D::Vector3 const* pathPoints, size_t pathSize, bool walk); void MoveFall(uint32 id = 0); diff --git a/src/server/game/OutdoorPvP/OutdoorPvP.cpp b/src/server/game/OutdoorPvP/OutdoorPvP.cpp index 868cba9a5b9..d329ab27de9 100644 --- a/src/server/game/OutdoorPvP/OutdoorPvP.cpp +++ b/src/server/game/OutdoorPvP/OutdoorPvP.cpp @@ -687,7 +687,7 @@ void OutdoorPvP::BroadcastWorker(Worker& _worker, uint32 zoneId) void OutdoorPvP::SetMapFromZone(uint32 zone) { - AreaTableEntry const* areaTable = GetAreaEntryByAreaID(zone); + AreaTableEntry const* areaTable = sAreaTableStore.LookupEntry(zone); ASSERT(areaTable); Map* map = sMapMgr->CreateBaseMap(areaTable->mapid); ASSERT(!map->Instanceable()); diff --git a/src/server/game/Scripting/ScriptLoader.cpp b/src/server/game/Scripting/ScriptLoader.cpp index 2922e4ef58d..07ac1a2ed5b 100644 --- a/src/server/game/Scripting/ScriptLoader.cpp +++ b/src/server/game/Scripting/ScriptLoader.cpp @@ -18,1404 +18,36 @@ #include "ScriptLoader.h" #include "World.h" -// spells -void AddSC_deathknight_spell_scripts(); -void AddSC_druid_spell_scripts(); -void AddSC_generic_spell_scripts(); -void AddSC_hunter_spell_scripts(); -void AddSC_mage_spell_scripts(); -void AddSC_paladin_spell_scripts(); -void AddSC_priest_spell_scripts(); -void AddSC_rogue_spell_scripts(); -void AddSC_shaman_spell_scripts(); -void AddSC_warlock_spell_scripts(); -void AddSC_warrior_spell_scripts(); -void AddSC_quest_spell_scripts(); -void AddSC_item_spell_scripts(); -void AddSC_holiday_spell_scripts(); - +void AddSpellsScripts(); void AddSC_SmartScripts(); - -//Commands -void AddSC_account_commandscript(); -void AddSC_achievement_commandscript(); -void AddSC_ahbot_commandscript(); -void AddSC_arena_commandscript(); -void AddSC_ban_commandscript(); -void AddSC_bf_commandscript(); -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(); -void AddSC_go_commandscript(); -void AddSC_gobject_commandscript(); -void AddSC_group_commandscript(); -void AddSC_guild_commandscript(); -void AddSC_honor_commandscript(); -void AddSC_instance_commandscript(); -void AddSC_learn_commandscript(); -void AddSC_lfg_commandscript(); -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_pet_commandscript(); -void AddSC_quest_commandscript(); -void AddSC_rbac_commandscript(); -void AddSC_reload_commandscript(); -void AddSC_reset_commandscript(); -void AddSC_send_commandscript(); -void AddSC_server_commandscript(); -void AddSC_tele_commandscript(); -void AddSC_ticket_commandscript(); -void AddSC_titles_commandscript(); -void AddSC_wp_commandscript(); +void AddCommandsScripts(); #ifdef SCRIPTS -//world -void AddSC_areatrigger_scripts(); -void AddSC_emerald_dragons(); -void AddSC_generic_creature(); -void AddSC_go_scripts(); -void AddSC_guards(); -void AddSC_item_scripts(); -void AddSC_npc_professions(); -void AddSC_npc_innkeeper(); -void AddSC_npcs_special(); -void AddSC_achievement_scripts(); -void AddSC_action_ip_logger(); -void AddSC_duel_reset(); - -//eastern kingdoms -void AddSC_alterac_valley(); //Alterac Valley -void AddSC_boss_balinda(); -void AddSC_boss_drekthar(); -void AddSC_boss_galvangar(); -void AddSC_boss_vanndar(); -void AddSC_blackrock_depths(); //Blackrock Depths -void AddSC_boss_ambassador_flamelash(); -void AddSC_boss_draganthaurissan(); -void AddSC_boss_general_angerforge(); -void AddSC_boss_high_interrogator_gerstahn(); -void AddSC_boss_magmus(); -void AddSC_boss_moira_bronzebeard(); -void AddSC_boss_tomb_of_seven(); -void AddSC_instance_blackrock_depths(); -void AddSC_boss_drakkisath(); //Blackrock Spire -void AddSC_boss_halycon(); -void AddSC_boss_highlordomokk(); -void AddSC_boss_mothersmolderweb(); -void AddSC_boss_overlordwyrmthalak(); -void AddSC_boss_shadowvosh(); -void AddSC_boss_thebeast(); -void AddSC_boss_warmastervoone(); -void AddSC_boss_quatermasterzigris(); -void AddSC_boss_pyroguard_emberseer(); -void AddSC_boss_gyth(); -void AddSC_boss_rend_blackhand(); -void AddSC_boss_gizrul_the_slavener(); -void AddSC_boss_urok_doomhowl(); -void AddSC_boss_lord_valthalak(); -void AddSC_instance_blackrock_spire(); -void AddSC_boss_razorgore(); //Blackwing lair -void AddSC_boss_vaelastrasz(); -void AddSC_boss_broodlord(); -void AddSC_boss_firemaw(); -void AddSC_boss_ebonroc(); -void AddSC_boss_flamegor(); -void AddSC_boss_chromaggus(); -void AddSC_boss_nefarian(); -void AddSC_instance_blackwing_lair(); -void AddSC_deadmines(); //Deadmines -void AddSC_instance_deadmines(); -void AddSC_boss_mr_smite(); -void AddSC_gnomeregan(); //Gnomeregan -void AddSC_instance_gnomeregan(); -void AddSC_boss_attumen(); //Karazhan -void AddSC_boss_curator(); -void AddSC_boss_maiden_of_virtue(); -void AddSC_boss_shade_of_aran(); -void AddSC_boss_malchezaar(); -void AddSC_boss_terestian_illhoof(); -void AddSC_boss_moroes(); -void AddSC_bosses_opera(); -void AddSC_boss_netherspite(); -void AddSC_instance_karazhan(); -void AddSC_karazhan(); -void AddSC_boss_nightbane(); -void AddSC_boss_felblood_kaelthas(); // Magister's Terrace -void AddSC_boss_selin_fireheart(); -void AddSC_boss_vexallus(); -void AddSC_boss_priestess_delrissa(); -void AddSC_instance_magisters_terrace(); -void AddSC_magisters_terrace(); -void AddSC_boss_lucifron(); //Molten core -void AddSC_boss_magmadar(); -void AddSC_boss_gehennas(); -void AddSC_boss_garr(); -void AddSC_boss_baron_geddon(); -void AddSC_boss_shazzrah(); -void AddSC_boss_golemagg(); -void AddSC_boss_sulfuron(); -void AddSC_boss_majordomo(); -void AddSC_boss_ragnaros(); -void AddSC_instance_molten_core(); -void AddSC_instance_ragefire_chasm(); //Ragefire Chasm -void AddSC_the_scarlet_enclave(); //Scarlet Enclave -void AddSC_the_scarlet_enclave_c1(); -void AddSC_the_scarlet_enclave_c2(); -void AddSC_the_scarlet_enclave_c5(); -void AddSC_boss_arcanist_doan(); //Scarlet Monastery -void AddSC_boss_azshir_the_sleepless(); -void AddSC_boss_bloodmage_thalnos(); -void AddSC_boss_headless_horseman(); -void AddSC_boss_herod(); -void AddSC_boss_high_inquisitor_fairbanks(); -void AddSC_boss_houndmaster_loksey(); -void AddSC_boss_interrogator_vishas(); -void AddSC_boss_scorn(); -void AddSC_instance_scarlet_monastery(); -void AddSC_boss_mograine_and_whitemane(); -void AddSC_boss_darkmaster_gandling(); //Scholomance -void AddSC_boss_death_knight_darkreaver(); -void AddSC_boss_theolenkrastinov(); -void AddSC_boss_illuciabarov(); -void AddSC_boss_instructormalicia(); -void AddSC_boss_jandicebarov(); -void AddSC_boss_kormok(); -void AddSC_boss_lordalexeibarov(); -void AddSC_boss_lorekeeperpolkelt(); -void AddSC_boss_rasfrost(); -void AddSC_boss_theravenian(); -void AddSC_boss_vectus(); -void AddSC_boss_kirtonos_the_herald(); -void AddSC_instance_scholomance(); -void AddSC_shadowfang_keep(); //Shadowfang keep -void AddSC_instance_shadowfang_keep(); -void AddSC_boss_magistrate_barthilas(); //Stratholme -void AddSC_boss_maleki_the_pallid(); -void AddSC_boss_nerubenkan(); -void AddSC_boss_cannon_master_willey(); -void AddSC_boss_baroness_anastari(); -void AddSC_boss_ramstein_the_gorger(); -void AddSC_boss_timmy_the_cruel(); -void AddSC_boss_postmaster_malown(); -void AddSC_boss_baron_rivendare(); -void AddSC_boss_dathrohan_balnazzar(); -void AddSC_boss_order_of_silver_hand(); -void AddSC_instance_stratholme(); -void AddSC_stratholme(); -void AddSC_sunken_temple(); // Sunken Temple -void AddSC_instance_sunken_temple(); -void AddSC_instance_sunwell_plateau(); //Sunwell Plateau -void AddSC_boss_kalecgos(); -void AddSC_boss_brutallus(); -void AddSC_boss_felmyst(); -void AddSC_boss_eredar_twins(); -void AddSC_boss_muru(); -void AddSC_boss_kiljaeden(); -void AddSC_sunwell_plateau(); -void AddSC_boss_archaedas(); //Uldaman -void AddSC_boss_ironaya(); -void AddSC_uldaman(); -void AddSC_instance_uldaman(); -void AddSC_instance_the_stockade(); //The Stockade -void AddSC_boss_akilzon(); //Zul'Aman -void AddSC_boss_halazzi(); -void AddSC_boss_hex_lord_malacrass(); -void AddSC_boss_janalai(); -void AddSC_boss_nalorakk(); -void AddSC_boss_zuljin(); -void AddSC_instance_zulaman(); -void AddSC_zulaman(); -void AddSC_boss_jeklik(); //Zul'Gurub -void AddSC_boss_venoxis(); -void AddSC_boss_marli(); -void AddSC_boss_mandokir(); -void AddSC_boss_gahzranka(); -void AddSC_boss_thekal(); -void AddSC_boss_arlokk(); -void AddSC_boss_jindo(); -void AddSC_boss_hakkar(); -void AddSC_boss_grilek(); -void AddSC_boss_hazzarah(); -void AddSC_boss_renataki(); -void AddSC_boss_wushoolay(); -void AddSC_instance_zulgurub(); - -//void AddSC_alterac_mountains(); -void AddSC_arathi_highlands(); -void AddSC_blasted_lands(); -void AddSC_burning_steppes(); -void AddSC_duskwood(); -void AddSC_eastern_plaguelands(); -void AddSC_ghostlands(); -void AddSC_hinterlands(); -void AddSC_isle_of_queldanas(); -void AddSC_loch_modan(); -void AddSC_redridge_mountains(); -void AddSC_silverpine_forest(); -void AddSC_stormwind_city(); -void AddSC_stranglethorn_vale(); -void AddSC_swamp_of_sorrows(); -void AddSC_tirisfal_glades(); -void AddSC_undercity(); -void AddSC_western_plaguelands(); -void AddSC_wetlands(); - -//kalimdor -void AddSC_blackfathom_deeps(); //Blackfathom Depths -void AddSC_boss_gelihast(); -void AddSC_boss_kelris(); -void AddSC_boss_aku_mai(); -void AddSC_instance_blackfathom_deeps(); -void AddSC_hyjal(); //CoT Battle for Mt. Hyjal -void AddSC_boss_archimonde(); -void AddSC_instance_mount_hyjal(); -void AddSC_hyjal_trash(); -void AddSC_boss_rage_winterchill(); -void AddSC_boss_anetheron(); -void AddSC_boss_kazrogal(); -void AddSC_boss_azgalor(); -void AddSC_boss_captain_skarloc(); //CoT Old Hillsbrad -void AddSC_boss_epoch_hunter(); -void AddSC_boss_lieutenant_drake(); -void AddSC_instance_old_hillsbrad(); -void AddSC_old_hillsbrad(); -void AddSC_boss_aeonus(); //CoT The Black Morass -void AddSC_boss_chrono_lord_deja(); -void AddSC_boss_temporus(); -void AddSC_the_black_morass(); -void AddSC_instance_the_black_morass(); -void AddSC_boss_epoch(); //CoT Culling Of Stratholme -void AddSC_boss_infinite_corruptor(); -void AddSC_boss_salramm(); -void AddSC_boss_mal_ganis(); -void AddSC_boss_meathook(); -void AddSC_culling_of_stratholme(); -void AddSC_instance_culling_of_stratholme(); -void AddSC_instance_dire_maul(); //Dire Maul -void AddSC_boss_celebras_the_cursed(); //Maraudon -void AddSC_boss_landslide(); -void AddSC_boss_noxxion(); -void AddSC_boss_ptheradras(); -void AddSC_instance_maraudon(); -void AddSC_boss_onyxia(); //Onyxia's Lair -void AddSC_instance_onyxias_lair(); -void AddSC_boss_tuten_kash(); //Razorfen Downs -void AddSC_boss_mordresh_fire_eye(); -void AddSC_boss_glutton(); -void AddSC_boss_amnennar_the_coldbringer(); -void AddSC_razorfen_downs(); -void AddSC_instance_razorfen_downs(); -void AddSC_razorfen_kraul(); //Razorfen Kraul -void AddSC_instance_razorfen_kraul(); -void AddSC_boss_kurinnaxx(); //Ruins of ahn'qiraj -void AddSC_boss_rajaxx(); -void AddSC_boss_moam(); -void AddSC_boss_buru(); -void AddSC_boss_ayamiss(); -void AddSC_boss_ossirian(); -void AddSC_instance_ruins_of_ahnqiraj(); -void AddSC_boss_cthun(); //Temple of ahn'qiraj -void AddSC_boss_viscidus(); -void AddSC_boss_fankriss(); -void AddSC_boss_huhuran(); -void AddSC_bug_trio(); -void AddSC_boss_sartura(); -void AddSC_boss_skeram(); -void AddSC_boss_twinemperors(); -void AddSC_boss_ouro(); -void AddSC_npc_anubisath_sentinel(); -void AddSC_instance_temple_of_ahnqiraj(); -void AddSC_wailing_caverns(); //Wailing caverns -void AddSC_instance_wailing_caverns(); -void AddSC_boss_zum_rah(); //Zul'Farrak -void AddSC_zulfarrak(); -void AddSC_instance_zulfarrak(); - -void AddSC_ashenvale(); -void AddSC_azshara(); -void AddSC_azuremyst_isle(); -void AddSC_bloodmyst_isle(); -void AddSC_boss_azuregos(); -void AddSC_darkshore(); -void AddSC_desolace(); -void AddSC_durotar(); -void AddSC_dustwallow_marsh(); -void AddSC_felwood(); -void AddSC_feralas(); -void AddSC_moonglade(); -void AddSC_orgrimmar(); -void AddSC_silithus(); -void AddSC_stonetalon_mountains(); -void AddSC_tanaris(); -void AddSC_the_barrens(); -void AddSC_thousand_needles(); -void AddSC_thunder_bluff(); -void AddSC_ungoro_crater(); -void AddSC_winterspring(); - -// Northrend - -void AddSC_boss_slad_ran(); -void AddSC_boss_moorabi(); -void AddSC_boss_drakkari_colossus(); -void AddSC_boss_gal_darah(); -void AddSC_boss_eck(); -void AddSC_instance_gundrak(); - -// Azjol-Nerub - Azjol-Nerub -void AddSC_boss_krik_thir(); -void AddSC_boss_hadronox(); -void AddSC_boss_anub_arak(); -void AddSC_instance_azjol_nerub(); - -// Azjol-Nerub - Ahn'kahet -void AddSC_boss_elder_nadox(); -void AddSC_boss_taldaram(); -void AddSC_boss_amanitar(); -void AddSC_boss_jedoga_shadowseeker(); -void AddSC_boss_volazj(); -void AddSC_instance_ahnkahet(); - -// Drak'Tharon Keep -void AddSC_boss_trollgore(); -void AddSC_boss_novos(); -void AddSC_boss_king_dred(); -void AddSC_boss_tharon_ja(); -void AddSC_instance_drak_tharon_keep(); - -void AddSC_boss_argent_challenge(); //Trial of the Champion -void AddSC_boss_black_knight(); -void AddSC_boss_grand_champions(); -void AddSC_instance_trial_of_the_champion(); -void AddSC_trial_of_the_champion(); -void AddSC_boss_anubarak_trial(); //Trial of the Crusader -void AddSC_boss_faction_champions(); -void AddSC_boss_jaraxxus(); -void AddSC_boss_northrend_beasts(); -void AddSC_boss_twin_valkyr(); -void AddSC_trial_of_the_crusader(); -void AddSC_instance_trial_of_the_crusader(); -void AddSC_boss_anubrekhan(); //Naxxramas -void AddSC_boss_maexxna(); -void AddSC_boss_patchwerk(); -void AddSC_boss_grobbulus(); -void AddSC_boss_razuvious(); -void AddSC_boss_kelthuzad(); -void AddSC_boss_loatheb(); -void AddSC_boss_noth(); -void AddSC_boss_gluth(); -void AddSC_boss_sapphiron(); -void AddSC_boss_four_horsemen(); -void AddSC_boss_faerlina(); -void AddSC_boss_heigan(); -void AddSC_boss_gothik(); -void AddSC_boss_thaddius(); -void AddSC_instance_naxxramas(); -void AddSC_boss_nexus_commanders(); // The Nexus Nexus -void AddSC_boss_magus_telestra(); -void AddSC_boss_anomalus(); -void AddSC_boss_ormorok(); -void AddSC_boss_keristrasza(); -void AddSC_instance_nexus(); -void AddSC_boss_drakos(); //The Nexus The Oculus -void AddSC_boss_urom(); -void AddSC_boss_varos(); -void AddSC_boss_eregos(); -void AddSC_instance_oculus(); -void AddSC_oculus(); -void AddSC_boss_malygos(); // The Nexus: Eye of Eternity -void AddSC_instance_eye_of_eternity(); -void AddSC_boss_sartharion(); //Obsidian Sanctum -void AddSC_obsidian_sanctum(); -void AddSC_instance_obsidian_sanctum(); -void AddSC_boss_bjarngrim(); //Ulduar Halls of Lightning -void AddSC_boss_loken(); -void AddSC_boss_ionar(); -void AddSC_boss_volkhan(); -void AddSC_instance_halls_of_lightning(); -void AddSC_boss_maiden_of_grief(); //Ulduar Halls of Stone -void AddSC_boss_krystallus(); -void AddSC_boss_sjonnir(); -void AddSC_instance_halls_of_stone(); -void AddSC_halls_of_stone(); -void AddSC_boss_auriaya(); //Ulduar Ulduar -void AddSC_boss_flame_leviathan(); -void AddSC_boss_ignis(); -void AddSC_boss_razorscale(); -void AddSC_boss_xt002(); -void AddSC_boss_kologarn(); -void AddSC_boss_assembly_of_iron(); -void AddSC_boss_general_vezax(); -void AddSC_boss_mimiron(); -void AddSC_boss_hodir(); -void AddSC_boss_freya(); -void AddSC_boss_yogg_saron(); -void AddSC_boss_algalon_the_observer(); -void AddSC_instance_ulduar(); - -// Utgarde Keep - Utgarde Keep -void AddSC_boss_keleseth(); -void AddSC_boss_skarvald_dalronn(); -void AddSC_boss_ingvar_the_plunderer(); -void AddSC_instance_utgarde_keep(); -void AddSC_utgarde_keep(); - -// Utgarde Keep - Utgarde Pinnacle -void AddSC_boss_svala(); -void AddSC_boss_palehoof(); -void AddSC_boss_skadi(); -void AddSC_boss_ymiron(); -void AddSC_instance_utgarde_pinnacle(); - -// Vault of Archavon -void AddSC_boss_archavon(); -void AddSC_boss_emalon(); -void AddSC_boss_koralon(); -void AddSC_boss_toravon(); -void AddSC_instance_vault_of_archavon(); - -void AddSC_boss_cyanigosa(); //Violet Hold -void AddSC_boss_erekem(); -void AddSC_boss_ichoron(); -void AddSC_boss_lavanthor(); -void AddSC_boss_moragg(); -void AddSC_boss_xevozz(); -void AddSC_boss_zuramat(); -void AddSC_instance_violet_hold(); -void AddSC_violet_hold(); -void AddSC_instance_forge_of_souls(); //Forge of Souls -void AddSC_forge_of_souls(); -void AddSC_boss_bronjahm(); -void AddSC_boss_devourer_of_souls(); -void AddSC_instance_pit_of_saron(); //Pit of Saron -void AddSC_pit_of_saron(); -void AddSC_boss_garfrost(); -void AddSC_boss_ick(); -void AddSC_boss_tyrannus(); -void AddSC_instance_halls_of_reflection(); // Halls of Reflection -void AddSC_halls_of_reflection(); -void AddSC_boss_falric(); -void AddSC_boss_marwyn(); -void AddSC_boss_lord_marrowgar(); // Icecrown Citadel -void AddSC_boss_lady_deathwhisper(); -void AddSC_boss_icecrown_gunship_battle(); -void AddSC_boss_deathbringer_saurfang(); -void AddSC_boss_festergut(); -void AddSC_boss_rotface(); -void AddSC_boss_professor_putricide(); -void AddSC_boss_blood_prince_council(); -void AddSC_boss_blood_queen_lana_thel(); -void AddSC_boss_valithria_dreamwalker(); -void AddSC_boss_sindragosa(); -void AddSC_boss_the_lich_king(); -void AddSC_icecrown_citadel_teleport(); -void AddSC_instance_icecrown_citadel(); -void AddSC_icecrown_citadel(); -void AddSC_instance_ruby_sanctum(); // Ruby Sanctum -void AddSC_ruby_sanctum(); -void AddSC_boss_baltharus_the_warborn(); -void AddSC_boss_saviana_ragefire(); -void AddSC_boss_general_zarithrian(); -void AddSC_boss_halion(); - -void AddSC_dalaran(); -void AddSC_borean_tundra(); -void AddSC_dragonblight(); -void AddSC_grizzly_hills(); -void AddSC_howling_fjord(); -void AddSC_icecrown(); -void AddSC_sholazar_basin(); -void AddSC_storm_peaks(); -void AddSC_wintergrasp(); -void AddSC_zuldrak(); -void AddSC_crystalsong_forest(); -void AddSC_isle_of_conquest(); - -// Outland - -// Auchindoun - Auchenai Crypts -void AddSC_boss_shirrak_the_dead_watcher(); -void AddSC_boss_exarch_maladaar(); -void AddSC_instance_auchenai_crypts(); - -// Auchindoun - Mana Tombs -void AddSC_boss_pandemonius(); -void AddSC_boss_nexusprince_shaffar(); -void AddSC_instance_mana_tombs(); - -// Auchindoun - Sekketh Halls -void AddSC_boss_darkweaver_syth(); -void AddSC_boss_talon_king_ikiss(); -void AddSC_boss_anzu(); -void AddSC_instance_sethekk_halls(); - -// Auchindoun - Shadow Labyrinth -void AddSC_boss_ambassador_hellmaw(); -void AddSC_boss_blackheart_the_inciter(); -void AddSC_boss_grandmaster_vorpil(); -void AddSC_boss_murmur(); -void AddSC_instance_shadow_labyrinth(); - -// Black Temple -void AddSC_black_temple(); -void AddSC_boss_illidan(); -void AddSC_boss_shade_of_akama(); -void AddSC_boss_supremus(); -void AddSC_boss_gurtogg_bloodboil(); -void AddSC_boss_mother_shahraz(); -void AddSC_boss_reliquary_of_souls(); -void AddSC_boss_teron_gorefiend(); -void AddSC_boss_najentus(); -void AddSC_boss_illidari_council(); -void AddSC_instance_black_temple(); - -// Coilfang Reservoir - Serpent Shrine Cavern -void AddSC_boss_fathomlord_karathress(); -void AddSC_boss_hydross_the_unstable(); -void AddSC_boss_lady_vashj(); -void AddSC_boss_leotheras_the_blind(); -void AddSC_boss_morogrim_tidewalker(); -void AddSC_instance_serpentshrine_cavern(); -void AddSC_boss_the_lurker_below(); - -// Coilfang Reservoir - The Steam Vault -void AddSC_boss_hydromancer_thespia(); -void AddSC_boss_mekgineer_steamrigger(); -void AddSC_boss_warlord_kalithresh(); -void AddSC_instance_steam_vault(); - -// Coilfang Reservoir - The Slave Pens -void AddSC_instance_the_slave_pens(); -void AddSC_boss_mennu_the_betrayer(); -void AddSC_boss_rokmar_the_crackler(); -void AddSC_boss_quagmirran(); - -// Coilfang Reservoir - The Underbog -void AddSC_instance_the_underbog(); -void AddSC_boss_hungarfen(); -void AddSC_boss_the_black_stalker(); - -// Gruul's Lair -void AddSC_boss_gruul(); -void AddSC_boss_high_king_maulgar(); -void AddSC_instance_gruuls_lair(); -void AddSC_boss_broggok(); //HC Blood Furnace -void AddSC_boss_kelidan_the_breaker(); -void AddSC_boss_the_maker(); -void AddSC_instance_blood_furnace(); -void AddSC_boss_magtheridon(); //HC Magtheridon's Lair -void AddSC_instance_magtheridons_lair(); -void AddSC_boss_grand_warlock_nethekurse(); //HC Shattered Halls -void AddSC_boss_warbringer_omrogg(); -void AddSC_boss_warchief_kargath_bladefist(); -void AddSC_shattered_halls(); -void AddSC_instance_shattered_halls(); -void AddSC_boss_watchkeeper_gargolmar(); //HC Ramparts -void AddSC_boss_omor_the_unscarred(); -void AddSC_boss_vazruden_the_herald(); -void AddSC_instance_ramparts(); -void AddSC_arcatraz(); //TK Arcatraz -void AddSC_boss_zereketh_the_unbound(); -void AddSC_boss_dalliah_the_doomsayer(); -void AddSC_boss_wrath_scryer_soccothrates(); -void AddSC_boss_harbinger_skyriss(); -void AddSC_instance_arcatraz(); -void AddSC_boss_high_botanist_freywinn(); //TK Botanica -void AddSC_boss_laj(); -void AddSC_boss_warp_splinter(); -void AddSC_boss_thorngrin_the_tender(); -void AddSC_boss_commander_sarannis(); -void AddSC_instance_the_botanica(); -void AddSC_boss_alar(); //TK The Eye -void AddSC_boss_kaelthas(); -void AddSC_boss_void_reaver(); -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(); -void AddSC_instance_mechanar(); - -void AddSC_blades_edge_mountains(); -void AddSC_boss_doomlordkazzak(); -void AddSC_boss_doomwalker(); -void AddSC_hellfire_peninsula(); -void AddSC_nagrand(); -void AddSC_netherstorm(); -void AddSC_shadowmoon_valley(); -void AddSC_shattrath_city(); -void AddSC_terokkar_forest(); -void AddSC_zangarmarsh(); - -// Events -void AddSC_event_childrens_week(); - -// Pets -void AddSC_deathknight_pet_scripts(); -void AddSC_generic_pet_scripts(); -void AddSC_hunter_pet_scripts(); -void AddSC_mage_pet_scripts(); -void AddSC_priest_pet_scripts(); -void AddSC_shaman_pet_scripts(); - -// battlegrounds - -// outdoor pvp -void AddSC_outdoorpvp_ep(); -void AddSC_outdoorpvp_hp(); -void AddSC_outdoorpvp_na(); -void AddSC_outdoorpvp_si(); -void AddSC_outdoorpvp_tf(); -void AddSC_outdoorpvp_zm(); - -// player -void AddSC_chat_log(); -void AddSC_action_ip_logger(); - +void AddWorldScripts(); +void AddEasternKingdomsScripts(); +void AddKalimdorScripts(); +void AddOutlandScripts(); +void AddNorthrendScripts(); +void AddEventsScripts(); +void AddPetScripts(); +void AddOutdoorPvPScripts(); +void AddCustomScripts(); #endif void AddScripts() { - AddSpellScripts(); + AddSpellsScripts(); AddSC_SmartScripts(); - AddCommandScripts(); + AddCommandsScripts(); #ifdef SCRIPTS AddWorldScripts(); AddEasternKingdomsScripts(); AddKalimdorScripts(); AddOutlandScripts(); AddNorthrendScripts(); - AddEventScripts(); + AddEventsScripts(); AddPetScripts(); - AddBattlegroundScripts(); AddOutdoorPvPScripts(); AddCustomScripts(); #endif } - -void AddSpellScripts() -{ - AddSC_deathknight_spell_scripts(); - AddSC_druid_spell_scripts(); - AddSC_generic_spell_scripts(); - AddSC_hunter_spell_scripts(); - AddSC_mage_spell_scripts(); - AddSC_paladin_spell_scripts(); - AddSC_priest_spell_scripts(); - AddSC_rogue_spell_scripts(); - AddSC_shaman_spell_scripts(); - AddSC_warlock_spell_scripts(); - AddSC_warrior_spell_scripts(); - AddSC_quest_spell_scripts(); - AddSC_item_spell_scripts(); - AddSC_holiday_spell_scripts(); -} - -void AddCommandScripts() -{ - AddSC_account_commandscript(); - AddSC_achievement_commandscript(); - AddSC_ahbot_commandscript(); - AddSC_arena_commandscript(); - AddSC_ban_commandscript(); - AddSC_bf_commandscript(); - AddSC_cast_commandscript(); - AddSC_character_commandscript(); - AddSC_cheat_commandscript(); - AddSC_debug_commandscript(); - AddSC_deserter_commandscript(); - AddSC_disable_commandscript(); - AddSC_event_commandscript(); - AddSC_gm_commandscript(); - AddSC_go_commandscript(); - AddSC_gobject_commandscript(); - AddSC_group_commandscript(); - AddSC_guild_commandscript(); - AddSC_honor_commandscript(); - AddSC_instance_commandscript(); - AddSC_learn_commandscript(); - AddSC_lookup_commandscript(); - AddSC_lfg_commandscript(); - AddSC_list_commandscript(); - AddSC_message_commandscript(); - AddSC_misc_commandscript(); - AddSC_mmaps_commandscript(); - AddSC_modify_commandscript(); - AddSC_npc_commandscript(); - AddSC_quest_commandscript(); - AddSC_pet_commandscript(); - AddSC_rbac_commandscript(); - AddSC_reload_commandscript(); - AddSC_reset_commandscript(); - AddSC_send_commandscript(); - AddSC_server_commandscript(); - AddSC_tele_commandscript(); - AddSC_ticket_commandscript(); - AddSC_titles_commandscript(); - AddSC_wp_commandscript(); -} - -void AddWorldScripts() -{ -#ifdef SCRIPTS - AddSC_areatrigger_scripts(); - AddSC_emerald_dragons(); - AddSC_generic_creature(); - AddSC_go_scripts(); - AddSC_guards(); - AddSC_item_scripts(); - AddSC_npc_professions(); - AddSC_npc_innkeeper(); - AddSC_npcs_special(); - AddSC_achievement_scripts(); - AddSC_chat_log(); // location: scripts\World\chat_log.cpp - // To avoid duplicate code, we check once /*ONLY*/ if logging is permitted or not. - if (sWorld->getBoolConfig(CONFIG_IP_BASED_ACTION_LOGGING)) - AddSC_action_ip_logger(); // location: scripts\World\action_ip_logger.cpp - AddSC_duel_reset(); -#endif -} - -void AddEasternKingdomsScripts() -{ -#ifdef SCRIPTS - AddSC_alterac_valley(); //Alterac Valley - AddSC_boss_balinda(); - AddSC_boss_drekthar(); - AddSC_boss_galvangar(); - AddSC_boss_vanndar(); - AddSC_blackrock_depths(); //Blackrock Depths - AddSC_boss_ambassador_flamelash(); - AddSC_boss_draganthaurissan(); - AddSC_boss_general_angerforge(); - AddSC_boss_high_interrogator_gerstahn(); - AddSC_boss_magmus(); - AddSC_boss_moira_bronzebeard(); - AddSC_boss_tomb_of_seven(); - AddSC_instance_blackrock_depths(); - AddSC_boss_drakkisath(); //Blackrock Spire - AddSC_boss_halycon(); - AddSC_boss_highlordomokk(); - AddSC_boss_mothersmolderweb(); - AddSC_boss_overlordwyrmthalak(); - AddSC_boss_shadowvosh(); - AddSC_boss_thebeast(); - AddSC_boss_warmastervoone(); - AddSC_boss_quatermasterzigris(); - AddSC_boss_pyroguard_emberseer(); - AddSC_boss_gyth(); - AddSC_boss_rend_blackhand(); - AddSC_boss_gizrul_the_slavener(); - AddSC_boss_urok_doomhowl(); - AddSC_boss_lord_valthalak(); - AddSC_instance_blackrock_spire(); - AddSC_boss_razorgore(); //Blackwing lair - AddSC_boss_vaelastrasz(); - AddSC_boss_broodlord(); - AddSC_boss_firemaw(); - AddSC_boss_ebonroc(); - AddSC_boss_flamegor(); - AddSC_boss_chromaggus(); - AddSC_boss_nefarian(); - AddSC_instance_blackwing_lair(); - AddSC_deadmines(); //Deadmines - AddSC_boss_mr_smite(); - AddSC_instance_deadmines(); - AddSC_gnomeregan(); //Gnomeregan - AddSC_instance_gnomeregan(); - AddSC_boss_attumen(); //Karazhan - AddSC_boss_curator(); - AddSC_boss_maiden_of_virtue(); - AddSC_boss_shade_of_aran(); - AddSC_boss_malchezaar(); - AddSC_boss_terestian_illhoof(); - AddSC_boss_moroes(); - AddSC_bosses_opera(); - AddSC_boss_netherspite(); - AddSC_instance_karazhan(); - AddSC_karazhan(); - AddSC_boss_nightbane(); - AddSC_boss_felblood_kaelthas(); // Magister's Terrace - AddSC_boss_selin_fireheart(); - AddSC_boss_vexallus(); - AddSC_boss_priestess_delrissa(); - AddSC_instance_magisters_terrace(); - AddSC_magisters_terrace(); - AddSC_boss_lucifron(); //Molten core - AddSC_boss_magmadar(); - AddSC_boss_gehennas(); - AddSC_boss_garr(); - AddSC_boss_baron_geddon(); - AddSC_boss_shazzrah(); - AddSC_boss_golemagg(); - AddSC_boss_sulfuron(); - AddSC_boss_majordomo(); - AddSC_boss_ragnaros(); - AddSC_instance_molten_core(); - AddSC_instance_ragefire_chasm(); //Ragefire Chasm - AddSC_the_scarlet_enclave(); //Scarlet Enclave - AddSC_the_scarlet_enclave_c1(); - AddSC_the_scarlet_enclave_c2(); - AddSC_the_scarlet_enclave_c5(); - AddSC_boss_arcanist_doan(); //Scarlet Monastery - AddSC_boss_azshir_the_sleepless(); - AddSC_boss_bloodmage_thalnos(); - AddSC_boss_headless_horseman(); - AddSC_boss_herod(); - AddSC_boss_high_inquisitor_fairbanks(); - AddSC_boss_houndmaster_loksey(); - AddSC_boss_interrogator_vishas(); - AddSC_boss_scorn(); - AddSC_instance_scarlet_monastery(); - AddSC_boss_mograine_and_whitemane(); - AddSC_boss_darkmaster_gandling(); //Scholomance - AddSC_boss_death_knight_darkreaver(); - AddSC_boss_theolenkrastinov(); - AddSC_boss_illuciabarov(); - AddSC_boss_instructormalicia(); - AddSC_boss_jandicebarov(); - AddSC_boss_kormok(); - AddSC_boss_lordalexeibarov(); - AddSC_boss_lorekeeperpolkelt(); - AddSC_boss_rasfrost(); - AddSC_boss_theravenian(); - AddSC_boss_vectus(); - AddSC_boss_kirtonos_the_herald(); - AddSC_instance_scholomance(); - AddSC_shadowfang_keep(); //Shadowfang keep - AddSC_instance_shadowfang_keep(); - AddSC_boss_magistrate_barthilas(); //Stratholme - AddSC_boss_maleki_the_pallid(); - AddSC_boss_nerubenkan(); - AddSC_boss_cannon_master_willey(); - AddSC_boss_baroness_anastari(); - AddSC_boss_ramstein_the_gorger(); - AddSC_boss_timmy_the_cruel(); - AddSC_boss_postmaster_malown(); - AddSC_boss_baron_rivendare(); - AddSC_boss_dathrohan_balnazzar(); - AddSC_boss_order_of_silver_hand(); - AddSC_instance_stratholme(); - AddSC_stratholme(); - AddSC_sunken_temple(); // Sunken Temple - AddSC_instance_sunken_temple(); - AddSC_instance_sunwell_plateau(); //Sunwell Plateau - AddSC_boss_kalecgos(); - AddSC_boss_brutallus(); - AddSC_boss_felmyst(); - AddSC_boss_eredar_twins(); - AddSC_boss_muru(); - AddSC_boss_kiljaeden(); - AddSC_sunwell_plateau(); - AddSC_instance_the_stockade(); //The Stockade - AddSC_boss_archaedas(); //Uldaman - AddSC_boss_ironaya(); - AddSC_uldaman(); - AddSC_instance_uldaman(); - AddSC_boss_akilzon(); //Zul'Aman - AddSC_boss_halazzi(); - AddSC_boss_hex_lord_malacrass(); - AddSC_boss_janalai(); - AddSC_boss_nalorakk(); - AddSC_boss_zuljin(); - AddSC_instance_zulaman(); - AddSC_zulaman(); - AddSC_boss_jeklik(); //Zul'Gurub - AddSC_boss_venoxis(); - AddSC_boss_marli(); - AddSC_boss_mandokir(); - AddSC_boss_gahzranka(); - AddSC_boss_thekal(); - AddSC_boss_arlokk(); - AddSC_boss_jindo(); - AddSC_boss_hakkar(); - AddSC_boss_grilek(); - AddSC_boss_hazzarah(); - AddSC_boss_renataki(); - AddSC_boss_wushoolay(); - AddSC_instance_zulgurub(); - - //AddSC_alterac_mountains(); - AddSC_arathi_highlands(); - AddSC_blasted_lands(); - AddSC_burning_steppes(); - AddSC_duskwood(); - AddSC_eastern_plaguelands(); - AddSC_ghostlands(); - AddSC_hinterlands(); - AddSC_isle_of_queldanas(); - AddSC_loch_modan(); - AddSC_redridge_mountains(); - AddSC_silverpine_forest(); - AddSC_stormwind_city(); - AddSC_stranglethorn_vale(); - AddSC_swamp_of_sorrows(); - AddSC_tirisfal_glades(); - AddSC_undercity(); - AddSC_western_plaguelands(); - AddSC_wetlands(); -#endif -} - -void AddKalimdorScripts() -{ -#ifdef SCRIPTS - AddSC_blackfathom_deeps(); //Blackfathom Depths - AddSC_boss_gelihast(); - AddSC_boss_kelris(); - AddSC_boss_aku_mai(); - AddSC_instance_blackfathom_deeps(); - AddSC_hyjal(); //CoT Battle for Mt. Hyjal - AddSC_boss_archimonde(); - AddSC_instance_mount_hyjal(); - AddSC_hyjal_trash(); - AddSC_boss_rage_winterchill(); - AddSC_boss_anetheron(); - AddSC_boss_kazrogal(); - AddSC_boss_azgalor(); - AddSC_boss_captain_skarloc(); //CoT Old Hillsbrad - AddSC_boss_epoch_hunter(); - AddSC_boss_lieutenant_drake(); - AddSC_instance_old_hillsbrad(); - AddSC_old_hillsbrad(); - AddSC_boss_aeonus(); //CoT The Black Morass - AddSC_boss_chrono_lord_deja(); - AddSC_boss_temporus(); - AddSC_the_black_morass(); - AddSC_instance_the_black_morass(); - AddSC_boss_epoch(); //CoT Culling Of Stratholme - AddSC_boss_infinite_corruptor(); - AddSC_boss_salramm(); - AddSC_boss_mal_ganis(); - AddSC_boss_meathook(); - AddSC_culling_of_stratholme(); - AddSC_instance_culling_of_stratholme(); - AddSC_instance_dire_maul(); //Dire Maul - AddSC_boss_celebras_the_cursed(); //Maraudon - AddSC_boss_landslide(); - AddSC_boss_noxxion(); - AddSC_boss_ptheradras(); - AddSC_instance_maraudon(); - AddSC_boss_onyxia(); //Onyxia's Lair - AddSC_instance_onyxias_lair(); - AddSC_boss_tuten_kash(); //Razorfen Downs - AddSC_boss_mordresh_fire_eye(); - AddSC_boss_glutton(); - AddSC_boss_amnennar_the_coldbringer(); - AddSC_razorfen_downs(); - AddSC_instance_razorfen_downs(); - AddSC_razorfen_kraul(); //Razorfen Kraul - AddSC_instance_razorfen_kraul(); - AddSC_boss_kurinnaxx(); //Ruins of ahn'qiraj - AddSC_boss_rajaxx(); - AddSC_boss_moam(); - AddSC_boss_buru(); - AddSC_boss_ayamiss(); - AddSC_boss_ossirian(); - AddSC_instance_ruins_of_ahnqiraj(); - AddSC_boss_cthun(); //Temple of ahn'qiraj - AddSC_boss_viscidus(); - AddSC_boss_fankriss(); - AddSC_boss_huhuran(); - AddSC_bug_trio(); - AddSC_boss_sartura(); - AddSC_boss_skeram(); - AddSC_boss_twinemperors(); - AddSC_boss_ouro(); - AddSC_npc_anubisath_sentinel(); - AddSC_instance_temple_of_ahnqiraj(); - AddSC_wailing_caverns(); //Wailing caverns - AddSC_instance_wailing_caverns(); - AddSC_boss_zum_rah(); //Zul'Farrak - AddSC_zulfarrak(); - AddSC_instance_zulfarrak(); - - AddSC_ashenvale(); - AddSC_azshara(); - AddSC_azuremyst_isle(); - AddSC_bloodmyst_isle(); - AddSC_boss_azuregos(); - AddSC_darkshore(); - AddSC_desolace(); - AddSC_durotar(); - AddSC_dustwallow_marsh(); - AddSC_felwood(); - AddSC_feralas(); - AddSC_moonglade(); - AddSC_orgrimmar(); - AddSC_silithus(); - AddSC_stonetalon_mountains(); - AddSC_tanaris(); - AddSC_the_barrens(); - AddSC_thousand_needles(); - AddSC_thunder_bluff(); - AddSC_ungoro_crater(); - AddSC_winterspring(); -#endif -} - -void AddOutlandScripts() -{ -#ifdef SCRIPTS - // Auchindoun - Auchenai Crypts - AddSC_boss_shirrak_the_dead_watcher(); - AddSC_boss_exarch_maladaar(); - AddSC_instance_auchenai_crypts(); - - // Auchindoun - Mana Tombs - AddSC_boss_pandemonius(); - AddSC_boss_nexusprince_shaffar(); - AddSC_instance_mana_tombs(); - - // Auchindoun - Sekketh Halls - AddSC_boss_darkweaver_syth(); - AddSC_boss_talon_king_ikiss(); - AddSC_boss_anzu(); - AddSC_instance_sethekk_halls(); - - // Auchindoun - Shadow Labyrinth - AddSC_boss_ambassador_hellmaw(); - AddSC_boss_blackheart_the_inciter(); - AddSC_boss_grandmaster_vorpil(); - AddSC_boss_murmur(); - AddSC_instance_shadow_labyrinth(); - - // Black Temple - AddSC_black_temple(); - AddSC_boss_illidan(); - AddSC_boss_shade_of_akama(); - AddSC_boss_supremus(); - AddSC_boss_gurtogg_bloodboil(); - AddSC_boss_mother_shahraz(); - AddSC_boss_reliquary_of_souls(); - AddSC_boss_teron_gorefiend(); - AddSC_boss_najentus(); - AddSC_boss_illidari_council(); - AddSC_instance_black_temple(); - - // Coilfang Reservoir - Serpent Shrine Cavern - AddSC_boss_fathomlord_karathress(); - AddSC_boss_hydross_the_unstable(); - AddSC_boss_lady_vashj(); - AddSC_boss_leotheras_the_blind(); - AddSC_boss_morogrim_tidewalker(); - AddSC_instance_serpentshrine_cavern(); - AddSC_boss_the_lurker_below(); - - // Coilfang Reservoir - The Steam Vault - AddSC_instance_steam_vault(); - AddSC_boss_hydromancer_thespia(); - AddSC_boss_mekgineer_steamrigger(); - AddSC_boss_warlord_kalithresh(); - - // Coilfang Reservoir - The Slave Pens - AddSC_instance_the_slave_pens(); - AddSC_boss_mennu_the_betrayer(); - AddSC_boss_rokmar_the_crackler(); - AddSC_boss_quagmirran(); - - // Coilfang Reservoir - The Underbog - AddSC_instance_the_underbog(); - AddSC_boss_hungarfen(); - AddSC_boss_the_black_stalker(); - - // Gruul's Lair - AddSC_boss_gruul(); - AddSC_boss_high_king_maulgar(); - AddSC_instance_gruuls_lair(); - AddSC_boss_broggok(); //HC Blood Furnace - AddSC_boss_kelidan_the_breaker(); - AddSC_boss_the_maker(); - AddSC_instance_blood_furnace(); - AddSC_boss_magtheridon(); //HC Magtheridon's Lair - AddSC_instance_magtheridons_lair(); - AddSC_boss_grand_warlock_nethekurse(); //HC Shattered Halls - AddSC_boss_warbringer_omrogg(); - AddSC_boss_warchief_kargath_bladefist(); - AddSC_shattered_halls(); - AddSC_instance_shattered_halls(); - AddSC_boss_watchkeeper_gargolmar(); //HC Ramparts - AddSC_boss_omor_the_unscarred(); - AddSC_boss_vazruden_the_herald(); - AddSC_instance_ramparts(); - AddSC_arcatraz(); //TK Arcatraz - AddSC_boss_zereketh_the_unbound(); - AddSC_boss_dalliah_the_doomsayer(); - AddSC_boss_wrath_scryer_soccothrates(); - AddSC_boss_harbinger_skyriss(); - AddSC_instance_arcatraz(); - AddSC_boss_high_botanist_freywinn(); //TK Botanica - AddSC_boss_laj(); - AddSC_boss_warp_splinter(); - AddSC_boss_thorngrin_the_tender(); - AddSC_boss_commander_sarannis(); - AddSC_instance_the_botanica(); - AddSC_boss_alar(); //TK The Eye - AddSC_boss_kaelthas(); - AddSC_boss_void_reaver(); - AddSC_boss_high_astromancer_solarian(); - 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(); - AddSC_instance_mechanar(); - - AddSC_blades_edge_mountains(); - AddSC_boss_doomlordkazzak(); - AddSC_boss_doomwalker(); - AddSC_hellfire_peninsula(); - AddSC_nagrand(); - AddSC_netherstorm(); - AddSC_shadowmoon_valley(); - AddSC_shattrath_city(); - AddSC_terokkar_forest(); - AddSC_zangarmarsh(); -#endif -} - -void AddNorthrendScripts() -{ -#ifdef SCRIPTS - AddSC_boss_slad_ran(); //Gundrak - AddSC_boss_moorabi(); - AddSC_boss_drakkari_colossus(); - AddSC_boss_gal_darah(); - AddSC_boss_eck(); - AddSC_instance_gundrak(); - - // Azjol-Nerub - Ahn'kahet - AddSC_boss_elder_nadox(); - AddSC_boss_taldaram(); - AddSC_boss_amanitar(); - AddSC_boss_jedoga_shadowseeker(); - AddSC_boss_volazj(); - AddSC_instance_ahnkahet(); - - // Azjol-Nerub - Azjol-Nerub - AddSC_boss_krik_thir(); - AddSC_boss_hadronox(); - AddSC_boss_anub_arak(); - AddSC_instance_azjol_nerub(); - - // Drak'Tharon Keep - AddSC_boss_trollgore(); - AddSC_boss_novos(); - AddSC_boss_king_dred(); - AddSC_boss_tharon_ja(); - AddSC_instance_drak_tharon_keep(); - - AddSC_boss_argent_challenge(); //Trial of the Champion - AddSC_boss_black_knight(); - AddSC_boss_grand_champions(); - AddSC_instance_trial_of_the_champion(); - AddSC_trial_of_the_champion(); - AddSC_boss_anubarak_trial(); //Trial of the Crusader - AddSC_boss_faction_champions(); - AddSC_boss_jaraxxus(); - AddSC_trial_of_the_crusader(); - AddSC_boss_twin_valkyr(); - AddSC_boss_northrend_beasts(); - AddSC_instance_trial_of_the_crusader(); - AddSC_boss_anubrekhan(); //Naxxramas - AddSC_boss_maexxna(); - AddSC_boss_patchwerk(); - AddSC_boss_grobbulus(); - AddSC_boss_razuvious(); - AddSC_boss_kelthuzad(); - AddSC_boss_loatheb(); - AddSC_boss_noth(); - AddSC_boss_gluth(); - AddSC_boss_sapphiron(); - AddSC_boss_four_horsemen(); - AddSC_boss_faerlina(); - AddSC_boss_heigan(); - AddSC_boss_gothik(); - AddSC_boss_thaddius(); - AddSC_instance_naxxramas(); - AddSC_boss_nexus_commanders(); // The Nexus Nexus - AddSC_boss_magus_telestra(); - AddSC_boss_anomalus(); - AddSC_boss_ormorok(); - AddSC_boss_keristrasza(); - AddSC_instance_nexus(); - AddSC_boss_drakos(); //The Nexus The Oculus - AddSC_boss_urom(); - AddSC_boss_varos(); - AddSC_boss_eregos(); - AddSC_instance_oculus(); - AddSC_oculus(); - AddSC_boss_malygos(); // The Nexus: Eye of Eternity - AddSC_instance_eye_of_eternity(); - AddSC_boss_sartharion(); //Obsidian Sanctum - AddSC_obsidian_sanctum(); - AddSC_instance_obsidian_sanctum(); - AddSC_boss_bjarngrim(); //Ulduar Halls of Lightning - AddSC_boss_loken(); - AddSC_boss_ionar(); - AddSC_boss_volkhan(); - AddSC_instance_halls_of_lightning(); - AddSC_boss_maiden_of_grief(); //Ulduar Halls of Stone - AddSC_boss_krystallus(); - AddSC_boss_sjonnir(); - AddSC_instance_halls_of_stone(); - AddSC_halls_of_stone(); - AddSC_boss_auriaya(); //Ulduar Ulduar - AddSC_boss_flame_leviathan(); - AddSC_boss_ignis(); - AddSC_boss_razorscale(); - AddSC_boss_xt002(); - AddSC_boss_general_vezax(); - AddSC_boss_assembly_of_iron(); - AddSC_boss_kologarn(); - AddSC_boss_mimiron(); - AddSC_boss_hodir(); - AddSC_boss_freya(); - AddSC_boss_yogg_saron(); - AddSC_boss_algalon_the_observer(); - AddSC_instance_ulduar(); - - // Utgarde Keep - Utgarde Keep - AddSC_boss_keleseth(); - AddSC_boss_skarvald_dalronn(); - AddSC_boss_ingvar_the_plunderer(); - AddSC_instance_utgarde_keep(); - AddSC_utgarde_keep(); - - // Utgarde Keep - Utgarde Pinnacle - AddSC_boss_svala(); - AddSC_boss_palehoof(); - AddSC_boss_skadi(); - AddSC_boss_ymiron(); - AddSC_instance_utgarde_pinnacle(); - - // Vault of Archavon - AddSC_boss_archavon(); - AddSC_boss_emalon(); - AddSC_boss_koralon(); - AddSC_boss_toravon(); - AddSC_instance_vault_of_archavon(); - - AddSC_boss_cyanigosa(); //Violet Hold - AddSC_boss_erekem(); - AddSC_boss_ichoron(); - AddSC_boss_lavanthor(); - AddSC_boss_moragg(); - AddSC_boss_xevozz(); - AddSC_boss_zuramat(); - AddSC_instance_violet_hold(); - AddSC_violet_hold(); - AddSC_instance_forge_of_souls(); //Forge of Souls - AddSC_forge_of_souls(); - AddSC_boss_bronjahm(); - AddSC_boss_devourer_of_souls(); - AddSC_instance_pit_of_saron(); //Pit of Saron - AddSC_pit_of_saron(); - AddSC_boss_garfrost(); - AddSC_boss_ick(); - AddSC_boss_tyrannus(); - AddSC_instance_halls_of_reflection(); // Halls of Reflection - AddSC_halls_of_reflection(); - AddSC_boss_falric(); - AddSC_boss_marwyn(); - AddSC_boss_lord_marrowgar(); // Icecrown Citadel - AddSC_boss_lady_deathwhisper(); - AddSC_boss_icecrown_gunship_battle(); - AddSC_boss_deathbringer_saurfang(); - AddSC_boss_festergut(); - AddSC_boss_rotface(); - AddSC_boss_professor_putricide(); - AddSC_boss_blood_prince_council(); - AddSC_boss_blood_queen_lana_thel(); - AddSC_boss_valithria_dreamwalker(); - AddSC_boss_sindragosa(); - AddSC_boss_the_lich_king(); - AddSC_icecrown_citadel_teleport(); - AddSC_instance_icecrown_citadel(); - AddSC_icecrown_citadel(); - AddSC_instance_ruby_sanctum(); // Ruby Sanctum - AddSC_ruby_sanctum(); - AddSC_boss_baltharus_the_warborn(); - AddSC_boss_saviana_ragefire(); - AddSC_boss_general_zarithrian(); - AddSC_boss_halion(); - - AddSC_dalaran(); - AddSC_borean_tundra(); - AddSC_dragonblight(); - AddSC_grizzly_hills(); - AddSC_howling_fjord(); - AddSC_icecrown(); - AddSC_sholazar_basin(); - AddSC_storm_peaks(); - AddSC_wintergrasp(); - AddSC_zuldrak(); - AddSC_crystalsong_forest(); - AddSC_isle_of_conquest(); -#endif -} - -void AddEventScripts() -{ -#ifdef SCRIPTS - AddSC_event_childrens_week(); -#endif -} - -void AddPetScripts() -{ -#ifdef SCRIPTS - AddSC_deathknight_pet_scripts(); - AddSC_generic_pet_scripts(); - AddSC_hunter_pet_scripts(); - AddSC_mage_pet_scripts(); - AddSC_priest_pet_scripts(); - AddSC_shaman_pet_scripts(); -#endif -} - -void AddOutdoorPvPScripts() -{ -#ifdef SCRIPTS - AddSC_outdoorpvp_ep(); - AddSC_outdoorpvp_hp(); - AddSC_outdoorpvp_na(); - AddSC_outdoorpvp_si(); - AddSC_outdoorpvp_tf(); - AddSC_outdoorpvp_zm(); -#endif -} - -void AddBattlegroundScripts() -{ -#ifdef SCRIPTS -#endif -} - -#ifdef SCRIPTS -/* This is where custom scripts' loading functions should be declared. */ - -#endif - -void AddCustomScripts() -{ -#ifdef SCRIPTS - /* This is where custom scripts should be added. */ - -#endif -} diff --git a/src/server/game/Scripting/ScriptLoader.h b/src/server/game/Scripting/ScriptLoader.h index 4adb215e130..57b62df22d1 100644 --- a/src/server/game/Scripting/ScriptLoader.h +++ b/src/server/game/Scripting/ScriptLoader.h @@ -19,17 +19,5 @@ #define SC_SCRIPTLOADER_H void AddScripts(); -void AddSpellScripts(); -void AddCommandScripts(); -void AddWorldScripts(); -void AddEasternKingdomsScripts(); -void AddKalimdorScripts(); -void AddOutlandScripts(); -void AddNorthrendScripts(); -void AddEventScripts(); -void AddPetScripts(); -void AddBattlegroundScripts(); -void AddOutdoorPvPScripts(); -void AddCustomScripts(); #endif diff --git a/src/server/game/Scripting/ScriptMgr.cpp b/src/server/game/Scripting/ScriptMgr.cpp index 3fa16cf4517..4b26ba96c9b 100644 --- a/src/server/game/Scripting/ScriptMgr.cpp +++ b/src/server/game/Scripting/ScriptMgr.cpp @@ -37,7 +37,6 @@ // namespace // { - UnusedScriptContainer UnusedScripts; UnusedScriptNamesContainer UnusedScriptNames; // } @@ -107,8 +106,9 @@ class ScriptRegistry // The actual list of scripts. This will be accessed concurrently, so it must not be modified // after server startup. static ScriptMap ScriptPointerList; + static std::vector<TScript*> Scripts; - static void AddScript(TScript* const script) + static void AddScript(TScript* const script, bool addToDeleteContainer = true) { ASSERT(script); @@ -126,6 +126,8 @@ class ScriptRegistry } AddScript(is_script_database_bound<TScript>{}, script); + if (addToDeleteContainer) + Scripts.push_back(script); } // Gets a script by its ID (assigned by ObjectMgr). @@ -186,11 +188,6 @@ class ScriptRegistry { // The script uses a script name from database, but isn't assigned to anything. TC_LOG_ERROR("sql.sql", "Script named '%s' does not have a script name assigned in database.", script->GetName().c_str()); - - // Avoid calling "delete script;" because we are currently in the script constructor - // In a valid scenario this will not happen because every script has a name assigned in the database - UnusedScripts.push_back(script); - return; } } @@ -210,6 +207,7 @@ class ScriptRegistry #define SCR_REG_MAP(T) ScriptRegistry<T>::ScriptMap #define SCR_REG_ITR(T) ScriptRegistry<T>::ScriptMapIterator #define SCR_REG_LST(T) ScriptRegistry<T>::ScriptPointerList +#define SCR_REG_VEC(T) ScriptRegistry<T>::Scripts // Utility macros for looping over scripts. #define FOR_SCRIPTS(T, C, E) \ @@ -266,17 +264,15 @@ void ScriptMgr::Initialize() } #endif - UnloadUnusedScripts(); - TC_LOG_INFO("server.loading", ">> Loaded %u C++ scripts in %u ms", GetScriptCount(), GetMSTimeDiffToNow(oldMSTime)); } void ScriptMgr::Unload() { #define SCR_CLEAR(T) \ - for (SCR_REG_ITR(T) itr = SCR_REG_LST(T).begin(); itr != SCR_REG_LST(T).end(); ++itr) \ - delete itr->second; \ - SCR_REG_LST(T).clear(); + for (T* scr : SCR_REG_VEC(T)) \ + delete scr; \ + SCR_REG_VEC(T).clear(); // Clear scripts for every script type. SCR_CLEAR(SpellScriptLoader); @@ -308,19 +304,10 @@ void ScriptMgr::Unload() #undef SCR_CLEAR - UnloadUnusedScripts(); - delete[] SpellSummary; delete[] UnitAI::AISpellInfo; } -void ScriptMgr::UnloadUnusedScripts() -{ - for (size_t i = 0; i < UnusedScripts.size(); ++i) - delete UnusedScripts[i]; - UnusedScripts.clear(); -} - void ScriptMgr::LoadDatabase() { sScriptSystemMgr->LoadScriptWaypoints(); @@ -1368,9 +1355,9 @@ void ScriptMgr::OnPlayerSave(Player* player) FOREACH_SCRIPT(PlayerScript)->OnSave(player); } -void ScriptMgr::OnPlayerBindToInstance(Player* player, Difficulty difficulty, uint32 mapid, bool permanent) +void ScriptMgr::OnPlayerBindToInstance(Player* player, Difficulty difficulty, uint32 mapid, bool permanent, uint8 extendState) { - FOREACH_SCRIPT(PlayerScript)->OnBindToInstance(player, difficulty, mapid, permanent); + FOREACH_SCRIPT(PlayerScript)->OnBindToInstance(player, difficulty, mapid, permanent, extendState); } void ScriptMgr::OnPlayerUpdateZone(Player* player, uint32 newZone, uint32 newArea) @@ -1555,8 +1542,7 @@ FormulaScript::FormulaScript(const char* name) UnitScript::UnitScript(const char* name, bool addToScripts) : ScriptObject(name) { - if (addToScripts) - ScriptRegistry<UnitScript>::AddScript(this); + ScriptRegistry<UnitScript>::AddScript(this, addToScripts); } WorldMapScript::WorldMapScript(const char* name, uint32 mapId) @@ -1696,6 +1682,7 @@ GroupScript::GroupScript(const char* name) // Instantiate static members of ScriptRegistry. template<class TScript> std::map<uint32, TScript*> ScriptRegistry<TScript>::ScriptPointerList; +template<class TScript> std::vector<TScript*> ScriptRegistry<TScript>::Scripts; template<class TScript> uint32 ScriptRegistry<TScript>::_scriptIdCounter = 0; // Specialize for each script type class like so: diff --git a/src/server/game/Scripting/ScriptMgr.h b/src/server/game/Scripting/ScriptMgr.h index 5dfc0be688a..8a00305b4da 100644 --- a/src/server/game/Scripting/ScriptMgr.h +++ b/src/server/game/Scripting/ScriptMgr.h @@ -734,7 +734,7 @@ class PlayerScript : public UnitScript virtual void OnSave(Player* /*player*/) { } // Called when a player is bound to an instance - virtual void OnBindToInstance(Player* /*player*/, Difficulty /*difficulty*/, uint32 /*mapId*/, bool /*permanent*/) { } + virtual void OnBindToInstance(Player* /*player*/, Difficulty /*difficulty*/, uint32 /*mapId*/, bool /*permanent*/, uint8 /*extendState*/) { } // Called when a player switches to a new zone virtual void OnUpdateZone(Player* /*player*/, uint32 /*newZone*/, uint32 /*newArea*/) { } @@ -843,10 +843,7 @@ class GroupScript : public ScriptObject // namespace // { - typedef std::vector<ScriptObject*> UnusedScriptContainer; typedef std::list<std::string> UnusedScriptNamesContainer; - - extern UnusedScriptContainer UnusedScripts; extern UnusedScriptNamesContainer UnusedScriptNames; // } @@ -878,7 +875,6 @@ class ScriptMgr public: /* Unloading */ void Unload(); - void UnloadUnusedScripts(); public: /* SpellScriptLoader */ @@ -1054,7 +1050,7 @@ class ScriptMgr void OnPlayerDelete(ObjectGuid guid, uint32 accountId); void OnPlayerFailedDelete(ObjectGuid guid, uint32 accountId); void OnPlayerSave(Player* player); - void OnPlayerBindToInstance(Player* player, Difficulty difficulty, uint32 mapid, bool permanent); + void OnPlayerBindToInstance(Player* player, Difficulty difficulty, uint32 mapid, bool permanent, uint8 extendState); void OnPlayerUpdateZone(Player* player, uint32 newZone, uint32 newArea); void OnQuestStatusChange(Player* player, uint32 questId, QuestStatus status); diff --git a/src/server/game/Server/WorldSocket.cpp b/src/server/game/Server/WorldSocket.cpp index a2d357cbc4d..36029113055 100644 --- a/src/server/game/Server/WorldSocket.cpp +++ b/src/server/game/Server/WorldSocket.cpp @@ -25,6 +25,17 @@ #include <memory> +class EncryptablePacket : public WorldPacket +{ +public: + EncryptablePacket(WorldPacket const& packet, bool encrypt) : WorldPacket(packet), _encrypt(encrypt) { } + + bool NeedsEncryption() const { return _encrypt; } + +private: + bool _encrypt; +}; + using boost::asio::ip::tcp; WorldSocket::WorldSocket(tcp::socket&& socket) @@ -40,11 +51,8 @@ void WorldSocket::Start() stmt->setString(0, ip_address); stmt->setUInt32(1, inet_addr(ip_address.c_str())); - { - std::lock_guard<std::mutex> guard(_queryLock); - _queryCallback = io_service().wrap(std::bind(&WorldSocket::CheckIpCallback, this, std::placeholders::_1)); - _queryFuture = LoginDatabase.AsyncQuery(stmt); - } + _queryCallback = std::bind(&WorldSocket::CheckIpCallback, this, std::placeholders::_1); + _queryFuture = LoginDatabase.AsyncQuery(stmt); } void WorldSocket::CheckIpCallback(PreparedQueryResult result) @@ -78,17 +86,50 @@ void WorldSocket::CheckIpCallback(PreparedQueryResult result) bool WorldSocket::Update() { + EncryptablePacket* queued; + MessageBuffer buffer; + while (_bufferQueue.Dequeue(queued)) + { + ServerPktHeader header(queued->size() + 2, queued->GetOpcode()); + if (queued->NeedsEncryption()) + _authCrypt.EncryptSend(header.header, header.getHeaderLength()); + + if (buffer.GetRemainingSpace() < queued->size() + header.getHeaderLength()) + { + QueuePacket(std::move(buffer)); + buffer.Resize(4096); + } + + if (buffer.GetRemainingSpace() >= queued->size() + header.getHeaderLength()) + { + buffer.Write(header.header, header.getHeaderLength()); + if (!queued->empty()) + buffer.Write(queued->contents(), queued->size()); + } + else // single packet larger than 4096 bytes + { + MessageBuffer packetBuffer(queued->size() + header.getHeaderLength()); + packetBuffer.Write(header.header, header.getHeaderLength()); + if (!queued->empty()) + packetBuffer.Write(queued->contents(), queued->size()); + + QueuePacket(std::move(packetBuffer)); + } + + delete queued; + } + + if (buffer.GetActiveSize() > 0) + QueuePacket(std::move(buffer)); + if (!BaseSocket::Update()) return false; + if (_queryFuture.valid() && _queryFuture.wait_for(std::chrono::seconds(0)) == std::future_status::ready) { - std::lock_guard<std::mutex> guard(_queryLock); - if (_queryFuture.valid() && _queryFuture.wait_for(std::chrono::seconds(0)) == std::future_status::ready) - { - auto callback = std::move(_queryCallback); - _queryCallback = nullptr; - callback(_queryFuture.get()); - } + auto callback = _queryCallback; + _queryCallback = nullptr; + callback(_queryFuture.get()); } return true; @@ -351,29 +392,7 @@ void WorldSocket::SendPacket(WorldPacket const& packet) if (sPacketLog->CanLogPacket()) sPacketLog->LogPacket(packet, SERVER_TO_CLIENT, GetRemoteIpAddress(), GetRemotePort()); - ServerPktHeader header(packet.size() + 2, packet.GetOpcode()); - - std::unique_lock<std::mutex> guard(_writeLock); - - _authCrypt.EncryptSend(header.header, header.getHeaderLength()); - -#ifndef TC_SOCKET_USE_IOCP - if (_writeQueue.empty() && _writeBuffer.GetRemainingSpace() >= header.getHeaderLength() + packet.size()) - { - _writeBuffer.Write(header.header, header.getHeaderLength()); - if (!packet.empty()) - _writeBuffer.Write(packet.contents(), packet.size()); - } - else -#endif - { - MessageBuffer buffer(header.getHeaderLength() + packet.size()); - buffer.Write(header.header, header.getHeaderLength()); - if (!packet.empty()) - buffer.Write(packet.contents(), packet.size()); - - QueuePacket(std::move(buffer), guard); - } + _bufferQueue.Enqueue(new EncryptablePacket(packet, _authCrypt.IsInitialized())); } void WorldSocket::HandleAuthSession(WorldPacket& recvPacket) @@ -398,11 +417,8 @@ void WorldSocket::HandleAuthSession(WorldPacket& recvPacket) stmt->setInt32(0, int32(realmID)); stmt->setString(1, authSession->Account); - { - std::lock_guard<std::mutex> guard(_queryLock); - _queryCallback = io_service().wrap(std::bind(&WorldSocket::HandleAuthSessionCallback, this, authSession, std::placeholders::_1)); - _queryFuture = LoginDatabase.AsyncQuery(stmt); - } + _queryCallback = std::bind(&WorldSocket::HandleAuthSessionCallback, this, authSession, std::placeholders::_1); + _queryFuture = LoginDatabase.AsyncQuery(stmt); } void WorldSocket::HandleAuthSessionCallback(std::shared_ptr<AuthSession> authSession, PreparedQueryResult result) @@ -559,7 +575,7 @@ void WorldSocket::HandleAuthSessionCallback(std::shared_ptr<AuthSession> authSes if (wardenActive) _worldSession->InitWarden(&account.SessionKey, account.OS); - _queryCallback = io_service().wrap(std::bind(&WorldSocket::LoadSessionPermissionsCallback, this, std::placeholders::_1)); + _queryCallback = std::bind(&WorldSocket::LoadSessionPermissionsCallback, this, std::placeholders::_1); _queryFuture = _worldSession->LoadPermissionsAsync(); AsyncRead(); } diff --git a/src/server/game/Server/WorldSocket.h b/src/server/game/Server/WorldSocket.h index 9e5b35992a6..08a5b185cf1 100644 --- a/src/server/game/Server/WorldSocket.h +++ b/src/server/game/Server/WorldSocket.h @@ -26,11 +26,13 @@ #include "Util.h" #include "WorldPacket.h" #include "WorldSession.h" +#include "MPSCQueue.h" #include <chrono> #include <boost/asio/ip/tcp.hpp> #include <boost/asio/buffer.hpp> using boost::asio::ip::tcp; +class EncryptablePacket; #pragma pack(push, 1) @@ -104,8 +106,8 @@ private: MessageBuffer _headerBuffer; MessageBuffer _packetBuffer; + MPSCQueue<EncryptablePacket> _bufferQueue; - std::mutex _queryLock; PreparedQueryResultFuture _queryFuture; std::function<void(PreparedQueryResult&&)> _queryCallback; std::string _ipCountry; diff --git a/src/server/game/Server/WorldSocketMgr.cpp b/src/server/game/Server/WorldSocketMgr.cpp index 529396b3966..e8f8c59f4af 100644 --- a/src/server/game/Server/WorldSocketMgr.cpp +++ b/src/server/game/Server/WorldSocketMgr.cpp @@ -24,9 +24,9 @@ #include <boost/system/error_code.hpp> -static void OnSocketAccept(tcp::socket&& sock) +static void OnSocketAccept(tcp::socket&& sock, uint32 threadIndex) { - sWorldSocketMgr.OnSocketOpen(std::forward<tcp::socket>(sock)); + sWorldSocketMgr.OnSocketOpen(std::forward<tcp::socket>(sock), threadIndex); } class WorldSocketThread : public NetworkThread<WorldSocket> @@ -67,7 +67,9 @@ bool WorldSocketMgr::StartNetwork(boost::asio::io_service& service, std::string BaseSocketMgr::StartNetwork(service, bindIp, port); - _acceptor->AsyncAcceptManaged(&OnSocketAccept); + _acceptor->SetSocketFactory(std::bind(&BaseSocketMgr::GetSocketForAccept, this)); + + _acceptor->AsyncAcceptWithCallback<&OnSocketAccept>(); sScriptMgr->OnNetworkStart(); return true; @@ -80,7 +82,7 @@ void WorldSocketMgr::StopNetwork() sScriptMgr->OnNetworkStop(); } -void WorldSocketMgr::OnSocketOpen(tcp::socket&& sock) +void WorldSocketMgr::OnSocketOpen(tcp::socket&& sock, uint32 threadIndex) { // set some options here if (_socketSendBufferSize >= 0) @@ -108,7 +110,7 @@ void WorldSocketMgr::OnSocketOpen(tcp::socket&& sock) //sock->m_OutBufferSize = static_cast<size_t> (m_SockOutUBuff); - BaseSocketMgr::OnSocketOpen(std::forward<tcp::socket>(sock)); + BaseSocketMgr::OnSocketOpen(std::forward<tcp::socket>(sock), threadIndex); } NetworkThread<WorldSocket>* WorldSocketMgr::CreateThreads() const diff --git a/src/server/game/Server/WorldSocketMgr.h b/src/server/game/Server/WorldSocketMgr.h index 92a28d0c135..38e2e7abb69 100644 --- a/src/server/game/Server/WorldSocketMgr.h +++ b/src/server/game/Server/WorldSocketMgr.h @@ -47,7 +47,7 @@ public: /// Stops all network threads, It will wait for all running threads . void StopNetwork() override; - void OnSocketOpen(tcp::socket&& sock) override; + void OnSocketOpen(tcp::socket&& sock, uint32 threadIndex) override; protected: WorldSocketMgr(); diff --git a/src/server/game/Skills/SkillDiscovery.cpp b/src/server/game/Skills/SkillDiscovery.cpp index 36a7d147192..8860b391f48 100644 --- a/src/server/game/Skills/SkillDiscovery.cpp +++ b/src/server/game/Skills/SkillDiscovery.cpp @@ -88,7 +88,7 @@ void LoadSkillDiscoveryTable() { if (reportedReqSpells.find(absReqSkillOrSpell) == reportedReqSpells.end()) { - TC_LOG_ERROR("sql.sql", "Spell (ID: %u) have not existed spell (ID: %i) in `reqSpell` field in `skill_discovery_template` table", spellId, reqSkillOrSpell); + TC_LOG_ERROR("sql.sql", "Spell (ID: %u) has a non-existing spell (ID: %i) in `reqSpell` field in the `skill_discovery_template` table.", spellId, reqSkillOrSpell); reportedReqSpells.insert(absReqSkillOrSpell); } continue; @@ -101,8 +101,8 @@ void LoadSkillDiscoveryTable() { if (reportedReqSpells.find(absReqSkillOrSpell) == reportedReqSpells.end()) { - TC_LOG_ERROR("sql.sql", "Spell (ID: %u) not have MECHANIC_DISCOVERY (28) value in Mechanic field in spell.dbc" - " and not 100%% chance random discovery ability but listed for spellId %u (and maybe more) in `skill_discovery_template` table", + TC_LOG_ERROR("sql.sql", "Spell (ID: %u) does not have any MECHANIC_DISCOVERY (28) value in the Mechanic field in spell.dbc" + " nor 100%% chance random discovery ability, but is listed for spellId %u (and maybe more) in the `skill_discovery_template` table.", absReqSkillOrSpell, spellId); reportedReqSpells.insert(absReqSkillOrSpell); } @@ -117,7 +117,7 @@ void LoadSkillDiscoveryTable() if (bounds.first == bounds.second) { - TC_LOG_ERROR("sql.sql", "Spell (ID: %u) not listed in `SkillLineAbility.dbc` but listed with `reqSpell`=0 in `skill_discovery_template` table", spellId); + TC_LOG_ERROR("sql.sql", "Spell (ID: %u) is not listed in `SkillLineAbility.dbc`, but listed with `reqSpell`= 0 in the `skill_discovery_template` table.", spellId); continue; } @@ -126,7 +126,7 @@ void LoadSkillDiscoveryTable() } else { - TC_LOG_ERROR("sql.sql", "Spell (ID: %u) have negative value in `reqSpell` field in `skill_discovery_template` table", spellId); + TC_LOG_ERROR("sql.sql", "Spell (ID: %u) has a negative value in `reqSpell` field in the `skill_discovery_template` table.", spellId); continue; } @@ -135,7 +135,7 @@ void LoadSkillDiscoveryTable() while (result->NextRow()); if (!ssNonDiscoverableEntries.str().empty()) - TC_LOG_ERROR("sql.sql", "Some items can't be successfully discovered: have in chance field value < 0.000001 in `skill_discovery_template` DB table . List:\n%s", ssNonDiscoverableEntries.str().c_str()); + TC_LOG_ERROR("sql.sql", "Some items can't be successfully discovered, their chance field value is < 0.000001 in the `skill_discovery_template` DB table. List:\n%s", ssNonDiscoverableEntries.str().c_str()); // report about empty data for explicit discovery spells for (uint32 spell_id = 1; spell_id < sSpellMgr->GetSpellInfoStoreSize(); ++spell_id) @@ -149,10 +149,10 @@ void LoadSkillDiscoveryTable() continue; if (SkillDiscoveryStore.find(int32(spell_id)) == SkillDiscoveryStore.end()) - TC_LOG_ERROR("sql.sql", "Spell (ID: %u) is 100%% chance random discovery ability but not have data in `skill_discovery_template` table", spell_id); + TC_LOG_ERROR("sql.sql", "Spell (ID: %u) has got 100%% chance random discovery ability, but does not have data in the `skill_discovery_template` table.", spell_id); } - TC_LOG_INFO("server.loading", ">> Loaded %u skill discovery definitions in %u ms", count, GetMSTimeDiffToNow(oldMSTime)); + TC_LOG_INFO("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 5213944cc90..f76e4623137 100644 --- a/src/server/game/Skills/SkillExtraItems.cpp +++ b/src/server/game/Skills/SkillExtraItems.cpp @@ -74,28 +74,28 @@ void LoadSkillPerfectItemTable() if (!sSpellMgr->GetSpellInfo(spellId)) { - TC_LOG_ERROR("sql.sql", "Skill perfection data for spell %u has non-existent spell id in `skill_perfect_item_template`!", spellId); + TC_LOG_ERROR("sql.sql", "Skill perfection data for spell %u has a non-existing spell id in the `skill_perfect_item_template`!", spellId); continue; } uint32 requiredSpecialization = fields[1].GetUInt32(); if (!sSpellMgr->GetSpellInfo(requiredSpecialization)) { - TC_LOG_ERROR("sql.sql", "Skill perfection data for spell %u has non-existent required specialization spell id %u in `skill_perfect_item_template`!", spellId, requiredSpecialization); + TC_LOG_ERROR("sql.sql", "Skill perfection data for spell %u has a non-existing required specialization spell id %u in the `skill_perfect_item_template`!", spellId, requiredSpecialization); continue; } float perfectCreateChance = fields[2].GetFloat(); if (perfectCreateChance <= 0.0f) { - TC_LOG_ERROR("sql.sql", "Skill perfection data for spell %u has impossibly low proc chance in `skill_perfect_item_template`!", spellId); + TC_LOG_ERROR("sql.sql", "Skill perfection data for spell %u has impossibly low proc chance in the `skill_perfect_item_template`!", spellId); continue; } uint32 perfectItemType = fields[3].GetUInt32(); if (!sObjectMgr->GetItemTemplate(perfectItemType)) { - TC_LOG_ERROR("sql.sql", "Skill perfection data for spell %u references non-existent perfect item id %u in `skill_perfect_item_template`!", spellId, perfectItemType); + TC_LOG_ERROR("sql.sql", "Skill perfection data for spell %u references a non-existing perfect item id %u in the `skill_perfect_item_template`!", spellId, perfectItemType); continue; } @@ -109,7 +109,7 @@ void LoadSkillPerfectItemTable() } while (result->NextRow()); - TC_LOG_INFO("server.loading", ">> Loaded %u spell perfection definitions in %u ms", count, GetMSTimeDiffToNow(oldMSTime)); + TC_LOG_INFO("server.loading", ">> Loaded %u spell perfection definitions in %u ms.", count, GetMSTimeDiffToNow(oldMSTime)); } // struct to store information about extra item creation @@ -161,28 +161,28 @@ void LoadSkillExtraItemTable() if (!sSpellMgr->GetSpellInfo(spellId)) { - TC_LOG_ERROR("sql.sql", "Skill specialization %u has non-existent spell id in `skill_extra_item_template`!", spellId); + TC_LOG_ERROR("sql.sql", "Skill specialization %u has a non-existing spell id in the `skill_extra_item_template`!", spellId); continue; } uint32 requiredSpecialization = fields[1].GetUInt32(); if (!sSpellMgr->GetSpellInfo(requiredSpecialization)) { - TC_LOG_ERROR("sql.sql", "Skill specialization %u have not existed required specialization spell id %u in `skill_extra_item_template`!", spellId, requiredSpecialization); + TC_LOG_ERROR("sql.sql", "Skill specialization %u has a non-existing required specialization spell id %u in the `skill_extra_item_template`!", spellId, requiredSpecialization); continue; } float additionalCreateChance = fields[2].GetFloat(); if (additionalCreateChance <= 0.0f) { - TC_LOG_ERROR("sql.sql", "Skill specialization %u has too low additional create chance in `skill_extra_item_template`!", spellId); + TC_LOG_ERROR("sql.sql", "Skill specialization %u has too low additional create chance in the `skill_extra_item_template`!", spellId); continue; } uint8 additionalMaxNum = fields[3].GetUInt8(); if (!additionalMaxNum) { - TC_LOG_ERROR("sql.sql", "Skill specialization %u has 0 max number of extra items in `skill_extra_item_template`!", spellId); + TC_LOG_ERROR("sql.sql", "Skill specialization %u has 0 max number of extra items in the `skill_extra_item_template`!", spellId); continue; } diff --git a/src/server/game/Spells/Auras/SpellAuraEffects.cpp b/src/server/game/Spells/Auras/SpellAuraEffects.cpp index b72ceecfff0..207908c6d51 100644 --- a/src/server/game/Spells/Auras/SpellAuraEffects.cpp +++ b/src/server/game/Spells/Auras/SpellAuraEffects.cpp @@ -4683,11 +4683,6 @@ void AuraEffect::HandleAuraDummy(AuraApplication const* aurApp, uint8 mode, bool if (target->GetTypeId() == TYPEID_PLAYER) target->ToPlayer()->RemoveAmmo(); // not use ammo and not allow use break; - case 52916: // Honor Among Thieves - if (target->GetTypeId() == TYPEID_PLAYER) - if (Unit* spellTarget = ObjectAccessor::GetUnit(*target, target->ToPlayer()->GetComboTarget())) - target->CastSpell(spellTarget, 51699, true); - break; case 71563: if (Aura* newAura = target->AddAura(71564, target)) newAura->SetStackAmount(newAura->GetSpellInfo()->StackAmount); diff --git a/src/server/game/Spells/Spell.cpp b/src/server/game/Spells/Spell.cpp index 63fe148dd93..23e2f144ff2 100644 --- a/src/server/game/Spells/Spell.cpp +++ b/src/server/game/Spells/Spell.cpp @@ -2429,7 +2429,7 @@ void Spell::DoAllEffectOnTarget(TargetInfo* target) if (missInfo != SPELL_MISS_EVADE && !m_caster->IsFriendlyTo(unit) && (!m_spellInfo->IsPositive() || m_spellInfo->HasEffect(SPELL_EFFECT_DISPEL))) { - m_caster->CombatStart(unit, !m_spellInfo->HasAttribute(SPELL_ATTR3_NO_INITIAL_AGGRO)); + m_caster->CombatStart(unit, m_spellInfo->HasInitialAggro()); if (!unit->IsStandState()) unit->SetStandState(UNIT_STAND_STATE_STAND); @@ -2535,7 +2535,7 @@ SpellMissInfo Spell::DoSpellHitOnUnit(Unit* unit, uint32 effectMask, bool scaleA if (m_caster->GetTypeId() == TYPEID_PLAYER) m_caster->ToPlayer()->UpdatePvP(true); } - if (unit->IsInCombat() && !m_spellInfo->HasAttribute(SPELL_ATTR3_NO_INITIAL_AGGRO)) + if (unit->IsInCombat() && m_spellInfo->HasInitialAggro()) { m_caster->SetInCombatState(unit->GetCombatTimer() > 0, unit); unit->getHostileRefManager().threatAssist(m_caster, 0.0f); @@ -4611,8 +4611,7 @@ void Spell::HandleThreatSpells() if (m_UniqueTargetInfo.empty()) return; - if (m_spellInfo->HasAttribute(SPELL_ATTR1_NO_THREAT) || - m_spellInfo->HasAttribute(SPELL_ATTR3_NO_INITIAL_AGGRO)) + if (!m_spellInfo->HasInitialAggro()) return; float threat = 0.0f; @@ -4623,7 +4622,7 @@ void Spell::HandleThreatSpells() threat += threatEntry->flatMod; } - else if (m_spellInfo->HasAttribute(SPELL_ATTR0_CU_NO_INITIAL_THREAT) == 0) + else if (!m_spellInfo->HasAttribute(SPELL_ATTR0_CU_NO_INITIAL_THREAT)) threat += m_spellInfo->SpellLevel; // past this point only multiplicative effects occur @@ -5477,7 +5476,7 @@ SpellCastResult Spell::CheckCast(bool strict) if (m_originalCaster && m_originalCaster->GetTypeId() == TYPEID_PLAYER && m_originalCaster->IsAlive()) { Battlefield* Bf = sBattlefieldMgr->GetBattlefieldToZoneId(m_originalCaster->GetZoneId()); - if (AreaTableEntry const* area = GetAreaEntryByAreaID(m_originalCaster->GetAreaId())) + if (AreaTableEntry const* area = sAreaTableStore.LookupEntry(m_originalCaster->GetAreaId())) if (area->flags & AREA_FLAG_NO_FLY_ZONE || (Bf && !Bf->CanFlyIn())) return (_triggeredCastFlags & TRIGGERED_DONT_REPORT_CAST_ERROR) ? SPELL_FAILED_DONT_REPORT : SPELL_FAILED_NOT_HERE; } diff --git a/src/server/game/Spells/SpellEffects.cpp b/src/server/game/Spells/SpellEffects.cpp index f961654f279..f9bf33553cc 100644 --- a/src/server/game/Spells/SpellEffects.cpp +++ b/src/server/game/Spells/SpellEffects.cpp @@ -893,7 +893,7 @@ void Spell::EffectTriggerMissileSpell(SpellEffIndex effIndex) SpellInfo const* spellInfo = sSpellMgr->GetSpellInfo(triggered_spell_id); if (!spellInfo) { - TC_LOG_ERROR("spells", "Spell::EffectTriggerMissileSpell spell %u tried to trigger unknown spell %u", m_spellInfo->Id, triggered_spell_id); + TC_LOG_ERROR("spells", "Spell::EffectTriggerMissileSpell spell %u tried to trigger unknown spell %u.", m_spellInfo->Id, triggered_spell_id); return; } @@ -944,7 +944,7 @@ void Spell::EffectForceCast(SpellEffIndex effIndex) if (!spellInfo) { - TC_LOG_ERROR("spells", "Spell::EffectForceCast of spell %u: triggering unknown spell id %i", m_spellInfo->Id, triggered_spell_id); + TC_LOG_ERROR("spells", "Spell::EffectForceCast of spell %u: triggering unknown spell id %i.", m_spellInfo->Id, triggered_spell_id); return; } @@ -996,7 +996,7 @@ void Spell::EffectTriggerRitualOfSummoning(SpellEffIndex effIndex) if (!spellInfo) { - TC_LOG_ERROR("spells", "EffectTriggerRitualOfSummoning of spell %u: triggering unknown spell id %i", m_spellInfo->Id, triggered_spell_id); + TC_LOG_ERROR("spells", "EffectTriggerRitualOfSummoning of spell %u: triggering unknown spell id %i.", m_spellInfo->Id, triggered_spell_id); return; } @@ -1021,7 +1021,7 @@ void Spell::EffectJump(SpellEffIndex effIndex) float speedXY, speedZ; CalculateJumpSpeeds(effIndex, m_caster->GetExactDist2d(x, y), speedXY, speedZ); - m_caster->GetMotionMaster()->MoveJump(x, y, z, speedXY, speedZ); + m_caster->GetMotionMaster()->MoveJump(x, y, z, 0.0f, speedXY, speedZ, EVENT_JUMP, false); } void Spell::EffectJumpDest(SpellEffIndex effIndex) @@ -1035,13 +1035,9 @@ void Spell::EffectJumpDest(SpellEffIndex effIndex) if (!m_targets.HasDst()) return; - // Init dest coordinates - float x, y, z; - destTarget->GetPosition(x, y, z); - float speedXY, speedZ; - CalculateJumpSpeeds(effIndex, m_caster->GetExactDist2d(x, y), speedXY, speedZ); - m_caster->GetMotionMaster()->MoveJump(x, y, z, speedXY, speedZ); + CalculateJumpSpeeds(effIndex, m_caster->GetExactDist2d(destTarget), speedXY, speedZ); + m_caster->GetMotionMaster()->MoveJump(*destTarget, speedXY, speedZ, EVENT_JUMP, true); } void Spell::CalculateJumpSpeeds(uint8 i, float dist, float & speedXY, float & speedZ) @@ -1066,7 +1062,7 @@ void Spell::EffectTeleportUnits(SpellEffIndex /*effIndex*/) // If not exist data for dest location - return if (!m_targets.HasDst()) { - TC_LOG_ERROR("spells", "Spell::EffectTeleportUnits - does not have destination for spellId %u.", m_spellInfo->Id); + TC_LOG_ERROR("spells", "Spell::EffectTeleportUnits - does not have a destination for spellId %u.", m_spellInfo->Id); return; } @@ -1397,7 +1393,7 @@ void Spell::EffectHeal(SpellEffIndex /*effIndex*/) if (!targetAura) { - TC_LOG_ERROR("spells", "Target (%s) has aurastate AURA_STATE_SWIFTMEND but no matching aura.", unitTarget->GetGUID().ToString().c_str()); + TC_LOG_ERROR("spells", "Target (%s) has the aurastate AURA_STATE_SWIFTMEND, but no matching aura.", unitTarget->GetGUID().ToString().c_str()); return; } @@ -1890,7 +1886,7 @@ void Spell::SendLoot(ObjectGuid guid, LootType loottype) // Players shouldn't be able to loot gameobjects that are currently despawned if (!gameObjTarget->isSpawned() && !player->IsGameMaster()) { - TC_LOG_ERROR("spells", "Possible hacking attempt: Player %s [guid: %u] tried to loot a gameobject [entry: %u id: %u] which is on respawn time without being in GM mode!", + TC_LOG_ERROR("spells", "Possible hacking attempt: Player %s [guid: %u] tried to loot a gameobject [entry: %u id: %u] which is on respawn timer without being in GM mode!", player->GetName().c_str(), player->GetGUID().GetCounter(), gameObjTarget->GetEntry(), gameObjTarget->GetGUID().GetCounter()); return; } @@ -2195,7 +2191,7 @@ void Spell::EffectSummonType(SpellEffIndex effIndex) SummonPropertiesEntry const* properties = sSummonPropertiesStore.LookupEntry(m_spellInfo->Effects[effIndex].MiscValueB); if (!properties) { - TC_LOG_ERROR("spells", "EffectSummonType: Unhandled summon type %u", m_spellInfo->Effects[effIndex].MiscValueB); + TC_LOG_ERROR("spells", "EffectSummonType: Unhandled summon type %u.", m_spellInfo->Effects[effIndex].MiscValueB); return; } @@ -2383,7 +2379,7 @@ void Spell::EffectLearnSpell(SpellEffIndex effIndex) uint32 spellToLearn = (m_spellInfo->Id == 483 || m_spellInfo->Id == 55884) ? damage : m_spellInfo->Effects[effIndex].TriggerSpell; player->LearnSpell(spellToLearn, false); - TC_LOG_DEBUG("spells", "Spell: Player %u has learned spell %u from NpcGUID=%u", player->GetGUID().GetCounter(), spellToLearn, m_caster->GetGUID().GetCounter()); + TC_LOG_DEBUG("spells", "Spell: Player %u has learned spell %u from NpcGUID: %u", player->GetGUID().GetCounter(), spellToLearn, m_caster->GetGUID().GetCounter()); } void Spell::EffectDispel(SpellEffIndex effIndex) @@ -2762,7 +2758,7 @@ void Spell::EffectEnchantItemPrismatic(SpellEffIndex effIndex) } if (!add_socket) { - TC_LOG_ERROR("spells", "Spell::EffectEnchantItemPrismatic: attempt apply enchant spell %u with SPELL_EFFECT_ENCHANT_ITEM_PRISMATIC (%u) but without ITEM_ENCHANTMENT_TYPE_PRISMATIC_SOCKET (%u), not suppoted yet.", + TC_LOG_ERROR("spells", "Spell::EffectEnchantItemPrismatic: attempt to apply the enchant spell %u with SPELL_EFFECT_ENCHANT_ITEM_PRISMATIC (%u), but without ITEM_ENCHANTMENT_TYPE_PRISMATIC_SOCKET (%u), not supported yet.", m_spellInfo->Id, SPELL_EFFECT_ENCHANT_ITEM_PRISMATIC, ITEM_ENCHANTMENT_TYPE_PRISMATIC_SOCKET); return; } @@ -2827,7 +2823,7 @@ void Spell::EffectEnchantItemTmp(SpellEffIndex effIndex) case 10: spell_id = 36758; break; // 14% case 11: spell_id = 36760; break; // 20% default: - TC_LOG_ERROR("spells", "Spell::EffectEnchantItemTmp: Damage %u not handled in S'RW", damage); + TC_LOG_ERROR("spells", "Spell::EffectEnchantItemTmp: Damage %u not handled in S'RW.", damage); return; } @@ -2861,14 +2857,14 @@ void Spell::EffectEnchantItemTmp(SpellEffIndex effIndex) if (!enchant_id) { - TC_LOG_ERROR("spells", "Spell %u Effect %u (SPELL_EFFECT_ENCHANT_ITEM_TEMPORARY) have 0 as enchanting id", m_spellInfo->Id, effIndex); + TC_LOG_ERROR("spells", "Spell %u Effect %u (SPELL_EFFECT_ENCHANT_ITEM_TEMPORARY) has enchanting id 0.", m_spellInfo->Id, effIndex); return; } SpellItemEnchantmentEntry const* pEnchant = sSpellItemEnchantmentStore.LookupEntry(enchant_id); if (!pEnchant) { - TC_LOG_ERROR("spells", "Spell %u Effect %u (SPELL_EFFECT_ENCHANT_ITEM_TEMPORARY) have not existed enchanting id %u ", m_spellInfo->Id, effIndex, enchant_id); + TC_LOG_ERROR("spells", "Spell %u Effect %u (SPELL_EFFECT_ENCHANT_ITEM_TEMPORARY) has a non-existing enchanting id %u ", m_spellInfo->Id, effIndex, enchant_id); return; } @@ -3984,7 +3980,7 @@ void Spell::EffectScriptEffect(SpellEffIndex effIndex) case 31893: spell_heal = 48084; break; case 31883: spell_heal = 48085; break; default: - TC_LOG_ERROR("spells", "Unknown Lightwell spell caster %u", m_caster->GetEntry()); + TC_LOG_ERROR("spells", "Unknown Lightwell spell caster %u.", m_caster->GetEntry()); return; } @@ -4137,14 +4133,14 @@ void Spell::EffectDuel(SpellEffIndex effIndex) return; // Players can only fight a duel in zones with this flag - AreaTableEntry const* casterAreaEntry = GetAreaEntryByAreaID(caster->GetAreaId()); + AreaTableEntry const* casterAreaEntry = sAreaTableStore.LookupEntry(caster->GetAreaId()); if (casterAreaEntry && !(casterAreaEntry->flags & AREA_FLAG_ALLOW_DUELS)) { SendCastResult(SPELL_FAILED_NO_DUELING); // Dueling isn't allowed here return; } - AreaTableEntry const* targetAreaEntry = GetAreaEntryByAreaID(target->GetAreaId()); + AreaTableEntry const* targetAreaEntry = sAreaTableStore.LookupEntry(target->GetAreaId()); if (targetAreaEntry && !(targetAreaEntry->flags & AREA_FLAG_ALLOW_DUELS)) { SendCastResult(SPELL_FAILED_NO_DUELING); // Dueling isn't allowed here @@ -4223,7 +4219,7 @@ void Spell::EffectStuck(SpellEffIndex /*effIndex*/) return; TC_LOG_DEBUG("spells", "Spell Effect: Stuck"); - TC_LOG_DEBUG("spells", "Player %s (guid %u) used auto-unstuck future at map %u (%f, %f, %f)", player->GetName().c_str(), player->GetGUID().GetCounter(), player->GetMapId(), player->GetPositionX(), player->GetPositionY(), player->GetPositionZ()); + TC_LOG_DEBUG("spells", "Player %s (guid %u) used the auto-unstuck feature at map %u (%f, %f, %f).", player->GetName().c_str(), player->GetGUID().GetCounter(), player->GetMapId(), player->GetPositionX(), player->GetPositionY(), player->GetPositionZ()); if (player->IsInFlight()) return; @@ -4903,7 +4899,7 @@ void Spell::EffectPullTowards(SpellEffIndex effIndex) float speedXY = float(m_spellInfo->Effects[effIndex].MiscValue) * 0.1f; float speedZ = unitTarget->GetDistance(pos) / speedXY * 0.5f * Movement::gravity; - unitTarget->GetMotionMaster()->MoveJump(pos.GetPositionX(), pos.GetPositionY(), pos.GetPositionZ(), speedXY, speedZ); + unitTarget->GetMotionMaster()->MoveJump(pos, speedXY, speedZ); } void Spell::EffectDispelMechanic(SpellEffIndex effIndex) @@ -5105,7 +5101,7 @@ void Spell::EffectTransmitted(SpellEffIndex effIndex) if (!goinfo) { - TC_LOG_ERROR("sql.sql", "Gameobject (Entry: %u) not exist and not created at spell (ID: %u) cast", name_id, m_spellInfo->Id); + TC_LOG_ERROR("sql.sql", "Gameobject (Entry: %u) does not exist and is not created by spell (ID: %u) cast.", name_id, m_spellInfo->Id); return; } @@ -5746,7 +5742,7 @@ void Spell::EffectPlayMusic(SpellEffIndex effIndex) if (!sSoundEntriesStore.LookupEntry(soundid)) { - TC_LOG_ERROR("spells", "EffectPlayMusic: Sound (Id: %u) not exist in spell %u.", soundid, m_spellInfo->Id); + TC_LOG_ERROR("spells", "EffectPlayMusic: Sound (Id: %u) does not exist in spell %u.", soundid, m_spellInfo->Id); return; } @@ -5803,7 +5799,7 @@ void Spell::EffectPlaySound(SpellEffIndex effIndex) if (!sSoundEntriesStore.LookupEntry(soundId)) { - TC_LOG_ERROR("spells", "EffectPlaySound: Sound (Id: %u) not exist in spell %u.", soundId, m_spellInfo->Id); + TC_LOG_ERROR("spells", "EffectPlaySound: Sound (Id: %u) does 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 699e4857ee0..069c794ca8b 100644 --- a/src/server/game/Spells/SpellInfo.cpp +++ b/src/server/game/Spells/SpellInfo.cpp @@ -1180,6 +1180,11 @@ bool SpellInfo::IsAutoRepeatRangedSpell() const return HasAttribute(SPELL_ATTR2_AUTOREPEAT_FLAG); } +bool SpellInfo::HasInitialAggro() const +{ + return !(HasAttribute(SPELL_ATTR1_NO_THREAT) || HasAttribute(SPELL_ATTR3_NO_INITIAL_AGGRO)); +} + bool SpellInfo::IsAffectedBySpellMods() const { return !HasAttribute(SPELL_ATTR3_NO_DONE_BONUS); diff --git a/src/server/game/Spells/SpellInfo.h b/src/server/game/Spells/SpellInfo.h index dbbab5fb30b..ba658c885fa 100644 --- a/src/server/game/Spells/SpellInfo.h +++ b/src/server/game/Spells/SpellInfo.h @@ -420,6 +420,7 @@ public: bool IsBreakingStealth() const; bool IsRangedWeaponSpell() const; bool IsAutoRepeatRangedSpell() const; + bool HasInitialAggro() const; bool IsAffectedBySpellMods() const; bool IsAffectedBySpellMod(SpellModifier const* mod) const; diff --git a/src/server/game/Spells/SpellMgr.cpp b/src/server/game/Spells/SpellMgr.cpp index ff8fc4539ff..0f80d83e0ff 100644 --- a/src/server/game/Spells/SpellMgr.cpp +++ b/src/server/game/Spells/SpellMgr.cpp @@ -376,29 +376,29 @@ bool SpellMgr::IsSpellValid(SpellInfo const* spellInfo, Player* player, bool msg { if (spellInfo->Effects[i].ItemType == 0) { - // skip auto-loot crafting spells, its not need explicit item info (but have special fake items sometime) + // skip auto-loot crafting spells, it does not need explicit item info (but has special fake items sometimes). if (!spellInfo->IsLootCrafting()) { if (msg) { if (player) - ChatHandler(player->GetSession()).PSendSysMessage("Craft spell %u not have create item entry.", spellInfo->Id); + ChatHandler(player->GetSession()).PSendSysMessage("The craft spell %u does not have a create item entry.", spellInfo->Id); else - TC_LOG_ERROR("sql.sql", "Craft spell %u not have create item entry.", spellInfo->Id); + TC_LOG_ERROR("sql.sql", "The craft spell %u does not have a create item entry.", spellInfo->Id); } return false; } } - // also possible IsLootCrafting case but fake item must exist anyway + // also possible IsLootCrafting case but fake items must exist anyway else if (!sObjectMgr->GetItemTemplate(spellInfo->Effects[i].ItemType)) { if (msg) { if (player) - ChatHandler(player->GetSession()).PSendSysMessage("Craft spell %u create not-exist in DB item (Entry: %u) and then...", spellInfo->Id, spellInfo->Effects[i].ItemType); + ChatHandler(player->GetSession()).PSendSysMessage("Craft spell %u has created a non-existing item in DB (Entry: %u) and then...", spellInfo->Id, spellInfo->Effects[i].ItemType); else - TC_LOG_ERROR("sql.sql", "Craft spell %u create not-exist in DB item (Entry: %u) and then...", spellInfo->Id, spellInfo->Effects[i].ItemType); + TC_LOG_ERROR("sql.sql", "Craft spell %u has created a non-existing item in DB (Entry: %u) and then...", spellInfo->Id, spellInfo->Effects[i].ItemType); } return false; } @@ -434,9 +434,9 @@ bool SpellMgr::IsSpellValid(SpellInfo const* spellInfo, Player* player, bool msg if (msg) { if (player) - ChatHandler(player->GetSession()).PSendSysMessage("Craft spell %u have not-exist reagent in DB item (Entry: %u) and then...", spellInfo->Id, spellInfo->Reagent[j]); + ChatHandler(player->GetSession()).PSendSysMessage("Craft spell %u refers a non-existing reagent in DB item (Entry: %u) and then...", spellInfo->Id, spellInfo->Reagent[j]); else - TC_LOG_ERROR("sql.sql", "Craft spell %u have not-exist reagent in DB item (Entry: %u) and then...", spellInfo->Id, spellInfo->Reagent[j]); + TC_LOG_ERROR("sql.sql", "Craft spell %u refers to a non-existing reagent in DB, item (Entry: %u) and then...", spellInfo->Id, spellInfo->Reagent[j]); } return false; } @@ -455,7 +455,7 @@ uint32 SpellMgr::GetSpellDifficultyId(uint32 spellId) const void SpellMgr::SetSpellDifficultyId(uint32 spellId, uint32 id) { if (uint32 i = GetSpellDifficultyId(spellId)) - TC_LOG_ERROR("spells", "SpellMgr::SetSpellDifficultyId: Spell %u has already spellDifficultyId %u. Will override with spellDifficultyId %u.", spellId, i, id); + TC_LOG_ERROR("spells", "SpellMgr::SetSpellDifficultyId: The spell %u already has spellDifficultyId %u. Will override with spellDifficultyId %u.", spellId, i, id); mSpellDifficultySearcherMap[spellId] = id; } @@ -470,7 +470,7 @@ uint32 SpellMgr::GetSpellIdForDifficulty(uint32 spellId, Unit const* caster) con uint32 mode = uint32(caster->GetMap()->GetSpawnMode()); if (mode >= MAX_DIFFICULTY) { - TC_LOG_ERROR("spells", "SpellMgr::GetSpellIdForDifficulty: Incorrect Difficulty for spell %u.", spellId); + TC_LOG_ERROR("spells", "SpellMgr::GetSpellIdForDifficulty: Incorrect difficulty for spell %u.", spellId); return spellId; //return source spell } @@ -481,7 +481,7 @@ uint32 SpellMgr::GetSpellIdForDifficulty(uint32 spellId, Unit const* caster) con SpellDifficultyEntry const* difficultyEntry = sSpellDifficultyStore.LookupEntry(difficultyId); if (!difficultyEntry) { - TC_LOG_ERROR("spells", "SpellMgr::GetSpellIdForDifficulty: SpellDifficultyEntry not found for spell %u. This should never happen.", spellId); + TC_LOG_ERROR("spells", "SpellMgr::GetSpellIdForDifficulty: SpellDifficultyEntry was not found for spell %u. This should never happen.", spellId); return spellId; //return source spell } @@ -874,7 +874,7 @@ bool SpellMgr::IsSpellProcEventCanTriggeredBy(SpellInfo const* spellProto, Spell // For melee triggers if (procSpell == NULL) { - // Check (if set) for school (melee attack have Normal school) + // Check (if set) for school (melee attack has Normal school) if (spellProcEvent->schoolMask && (spellProcEvent->schoolMask & SPELL_SCHOOL_MASK_NORMAL) == 0) return false; } @@ -894,7 +894,7 @@ bool SpellMgr::IsSpellProcEventCanTriggeredBy(SpellInfo const* spellProto, Spell if (!(spellProcEvent->spellFamilyMask & procSpell->SpellFamilyFlags)) return false; hasFamilyMask = true; - // Some spells are not considered as active even with have spellfamilyflags + // Some spells are not considered as active even with spellfamilyflags set if (!(procEvent_procEx & PROC_EX_ONLY_ACTIVE_SPELL)) active = true; } @@ -1121,27 +1121,27 @@ SpellAreaForAreaMapBounds SpellMgr::GetSpellAreaForAreaMapBounds(uint32 area_id) bool SpellArea::IsFitToRequirements(Player const* player, uint32 newZone, uint32 newArea) const { - if (gender != GENDER_NONE) // not in expected gender + if (gender != GENDER_NONE) // is not expected gender if (!player || gender != player->getGender()) return false; - if (raceMask) // not in expected race + if (raceMask) // is not expected race if (!player || !(raceMask & player->getRaceMask())) return false; - if (areaId) // not in expected zone + if (areaId) // is not in expected zone if (newZone != areaId && newArea != areaId) return false; - if (questStart) // not in expected required quest state + if (questStart) // is not in expected required quest state if (!player || (((1 << player->GetQuestStatus(questStart)) & questStartStatus) == 0)) return false; - if (questEnd) // not in expected forbidden quest state + if (questEnd) // is not in expected forbidden quest state if (!player || (((1 << player->GetQuestStatus(questEnd)) & questEndStatus) == 0)) return false; - if (auraSpell) // not have expected aura + if (auraSpell) // does not have expected aura if (!player || (auraSpell > 0 && !player->HasAura(auraSpell)) || (auraSpell < 0 && player->HasAura(-auraSpell))) return false; @@ -1159,7 +1159,7 @@ bool SpellArea::IsFitToRequirements(Player const* player, uint32 newZone, uint32 if (!player) return false; - AreaTableEntry const* pArea = GetAreaEntryByAreaID(player->GetAreaId()); + AreaTableEntry const* pArea = sAreaTableStore.LookupEntry(player->GetAreaId()); if (!(pArea && pArea->flags & AREA_FLAG_NO_FLY_ZONE)) return false; if (!player->HasAuraType(SPELL_AURA_MOD_INCREASE_MOUNTED_FLIGHT_SPEED) && !player->HasAuraType(SPELL_AURA_FLY)) @@ -1341,7 +1341,7 @@ void SpellMgr::LoadSpellRanks() SpellInfo const* first = GetSpellInfo(lastSpell); if (!first) { - TC_LOG_ERROR("sql.sql", "Spell rank identifier(first_spell_id) %u listed in `spell_ranks` does not exist!", lastSpell); + TC_LOG_ERROR("sql.sql", "The spell rank identifier(first_spell_id) %u listed in `spell_ranks` does not exist!", lastSpell); continue; } // check if chain is long enough @@ -1358,14 +1358,14 @@ void SpellMgr::LoadSpellRanks() SpellInfo const* spell = GetSpellInfo(itr->first); if (!spell) { - TC_LOG_ERROR("sql.sql", "Spell %u (rank %u) listed in `spell_ranks` for chain %u does not exist!", itr->first, itr->second, lastSpell); + TC_LOG_ERROR("sql.sql", "The spell %u (rank %u) listed in `spell_ranks` for chain %u does not exist!", itr->first, itr->second, lastSpell); valid = false; break; } ++curRank; if (itr->second != curRank) { - TC_LOG_ERROR("sql.sql", "Spell %u (rank %u) listed in `spell_ranks` for chain %u does not have proper rank value(should be %u)!", itr->first, itr->second, lastSpell, curRank); + TC_LOG_ERROR("sql.sql", "The spell %u (rank %u) listed in `spell_ranks` for chain %u does not have a proper rank value (should be %u)!", itr->first, itr->second, lastSpell, curRank); valid = false; break; } @@ -1381,7 +1381,7 @@ void SpellMgr::LoadSpellRanks() int32 addedSpell = itr->first; if (mSpellInfoMap[addedSpell]->ChainEntry) - TC_LOG_ERROR("sql.sql", "Spell %u (rank: %u, first: %u) listed in `spell_ranks` has already ChainEntry from dbc.", addedSpell, itr->second, lastSpell); + TC_LOG_ERROR("sql.sql", "The spell %u (rank: %u, first: %u) listed in `spell_ranks` already has ChainEntry from dbc.", addedSpell, itr->second, lastSpell); mSpellChains[addedSpell].first = GetSpellInfo(lastSpell); mSpellChains[addedSpell].last = GetSpellInfo(rankChain.back().first); @@ -1435,26 +1435,26 @@ void SpellMgr::LoadSpellRequired() SpellInfo const* spell = GetSpellInfo(spell_id); if (!spell) { - TC_LOG_ERROR("sql.sql", "spell_id %u in `spell_required` table is not found in dbcs, skipped", spell_id); + TC_LOG_ERROR("sql.sql", "spell_id %u in `spell_required` table could not be found in dbc, skipped.", spell_id); continue; } SpellInfo const* reqSpell = GetSpellInfo(spell_req); if (!reqSpell) { - TC_LOG_ERROR("sql.sql", "req_spell %u in `spell_required` table is not found in dbcs, skipped", spell_req); + TC_LOG_ERROR("sql.sql", "req_spell %u in `spell_required` table could not be found in dbc, skipped.", spell_req); continue; } if (spell->IsRankOf(reqSpell)) { - TC_LOG_ERROR("sql.sql", "req_spell %u and spell_id %u in `spell_required` table are ranks of the same spell, entry not needed, skipped", spell_req, spell_id); + TC_LOG_ERROR("sql.sql", "req_spell %u and spell_id %u in `spell_required` table are ranks of the same spell, entry not needed, skipped.", spell_req, spell_id); continue; } if (IsSpellRequiringSpell(spell_id, spell_req)) { - TC_LOG_ERROR("sql.sql", "duplicated entry of req_spell %u and spell_id %u in `spell_required`, skipped", spell_req, spell_id); + TC_LOG_ERROR("sql.sql", "Duplicate entry of req_spell %u and spell_id %u in `spell_required`, skipped.", spell_req, spell_id); continue; } @@ -1532,19 +1532,19 @@ void SpellMgr::LoadSpellLearnSpells() if (!GetSpellInfo(spell_id)) { - TC_LOG_ERROR("sql.sql", "Spell %u listed in `spell_learn_spell` does not exist", spell_id); + TC_LOG_ERROR("sql.sql", "The spell %u listed in `spell_learn_spell` does not exist.", spell_id); continue; } if (!GetSpellInfo(node.spell)) { - TC_LOG_ERROR("sql.sql", "Spell %u listed in `spell_learn_spell` learning not existed spell %u", spell_id, node.spell); + TC_LOG_ERROR("sql.sql", "The spell %u listed in `spell_learn_spell` learning non-existing spell %u.", spell_id, node.spell); continue; } if (GetTalentSpellCost(node.spell)) { - TC_LOG_ERROR("sql.sql", "Spell %u listed in `spell_learn_spell` attempt learning talent spell %u, skipped", spell_id, node.spell); + TC_LOG_ERROR("sql.sql", "The spell %u listed in `spell_learn_spell` attempts learning talent spell %u, skipped.", spell_id, node.spell); continue; } @@ -1586,7 +1586,7 @@ void SpellMgr::LoadSpellLearnSpells() { if (itr->second.spell == dbc_node.spell) { - TC_LOG_ERROR("sql.sql", "Spell %u auto-learn spell %u in spell.dbc then the record in `spell_learn_spell` is redundant, please fix DB.", + TC_LOG_ERROR("sql.sql", "The spell %u is an auto-learn spell %u in spell.dbc and the record in `spell_learn_spell` is redundant. Please update your DB.", spell, dbc_node.spell); found = true; break; @@ -1663,7 +1663,7 @@ void SpellMgr::LoadSpellTargetPositions() } else { - TC_LOG_ERROR("sql.sql", "Spell (Id: %u, effIndex: %u) listed in `spell_target_position` does not have target TARGET_DEST_DB (17).", Spell_ID, effIndex); + TC_LOG_ERROR("sql.sql", "Spell (Id: %u, effIndex: %u) listed in `spell_target_position` does not have a target TARGET_DEST_DB (17).", Spell_ID, effIndex); continue; } @@ -1700,7 +1700,7 @@ void SpellMgr::LoadSpellTargetPositions() if (found) { if (!sSpellMgr->GetSpellTargetPosition(i)) - TC_LOG_DEBUG("spells", "Spell (ID: %u) does not have record in `spell_target_position`", i); + TC_LOG_DEBUG("spells", "Spell (ID: %u) does not have a record in `spell_target_position`.", i); } }*/ @@ -1759,12 +1759,12 @@ void SpellMgr::LoadSpellGroups() if (!spellInfo) { - TC_LOG_ERROR("sql.sql", "Spell %u listed in `spell_group` does not exist", itr->second); + TC_LOG_ERROR("sql.sql", "The spell %u listed in `spell_group` does not exist", itr->second); mSpellGroupSpell.erase(itr++); } else if (spellInfo->GetRank() > 1) { - TC_LOG_ERROR("sql.sql", "Spell %u listed in `spell_group` is not first rank of spell", itr->second); + TC_LOG_ERROR("sql.sql", "The spell %u listed in `spell_group` is not the first rank of the spell.", itr->second); mSpellGroupSpell.erase(itr++); } else @@ -1810,7 +1810,7 @@ void SpellMgr::LoadSpellGroupStackRules() uint8 stack_rule = fields[1].GetInt8(); if (stack_rule >= SPELL_GROUP_STACK_RULE_MAX) { - TC_LOG_ERROR("sql.sql", "SpellGroupStackRule %u listed in `spell_group_stack_rules` does not exist", stack_rule); + TC_LOG_ERROR("sql.sql", "SpellGroupStackRule %u listed in `spell_group_stack_rules` does not exist.", stack_rule); continue; } @@ -1818,7 +1818,7 @@ void SpellMgr::LoadSpellGroupStackRules() if (spellGroup.first == spellGroup.second) { - TC_LOG_ERROR("sql.sql", "SpellGroup id %u listed in `spell_group_stack_rules` does not exist", group_id); + TC_LOG_ERROR("sql.sql", "SpellGroup id %u listed in `spell_group_stack_rules` does not exist.", group_id); continue; } @@ -1862,18 +1862,18 @@ void SpellMgr::LoadSpellProcEvents() SpellInfo const* spellInfo = GetSpellInfo(spellId); if (!spellInfo) { - TC_LOG_ERROR("sql.sql", "Spell %u listed in `spell_proc_event` does not exist", spellId); + TC_LOG_ERROR("sql.sql", "The spell %u listed in `spell_proc_event` does not exist.", spellId); continue; } if (allRanks) { if (!spellInfo->IsRanked()) - TC_LOG_ERROR("sql.sql", "Spell %u listed in `spell_proc_event` with all ranks, but spell has no ranks.", spellId); + TC_LOG_ERROR("sql.sql", "The spell %u is listed in `spell_proc_event` with all ranks, but spell has no ranks.", spellId); if (spellInfo->GetFirstRankSpell()->Id != uint32(spellId)) { - TC_LOG_ERROR("sql.sql", "Spell %u listed in `spell_proc_event` is not first rank of spell.", spellId); + TC_LOG_ERROR("sql.sql", "The spell %u listed in `spell_proc_event` is not first rank of spell.", spellId); continue; } } @@ -1895,12 +1895,12 @@ void SpellMgr::LoadSpellProcEvents() { if (mSpellProcEventMap.find(spellInfo->Id) != mSpellProcEventMap.end()) { - TC_LOG_ERROR("sql.sql", "Spell %u listed in `spell_proc_event` already has its first rank in table.", spellInfo->Id); + TC_LOG_ERROR("sql.sql", "The spell %u listed in `spell_proc_event` already has its first rank in table.", spellInfo->Id); break; } if (!spellInfo->ProcFlags && !spellProcEvent.procFlags) - TC_LOG_ERROR("sql.sql", "Spell %u listed in `spell_proc_event` probably not triggered spell", spellInfo->Id); + TC_LOG_ERROR("sql.sql", "The spell %u listed in `spell_proc_event` is probably not a triggered spell.", spellInfo->Id); mSpellProcEventMap[spellInfo->Id] = spellProcEvent; @@ -1948,18 +1948,18 @@ void SpellMgr::LoadSpellProcs() SpellInfo const* spellInfo = GetSpellInfo(spellId); if (!spellInfo) { - TC_LOG_ERROR("sql.sql", "Spell %u listed in `spell_proc` does not exist", spellId); + TC_LOG_ERROR("sql.sql", "The spell %u listed in `spell_proc` does not exist", spellId); continue; } if (allRanks) { if (!spellInfo->IsRanked()) - TC_LOG_ERROR("sql.sql", "Spell %u listed in `spell_proc` with all ranks, but spell has no ranks.", spellId); + TC_LOG_ERROR("sql.sql", "The spell %u listed in `spell_proc` with all ranks, but spell has no ranks.", spellId); if (spellInfo->GetFirstRankSpell()->Id != uint32(spellId)) { - TC_LOG_ERROR("sql.sql", "Spell %u listed in `spell_proc` is not first rank of spell.", spellId); + TC_LOG_ERROR("sql.sql", "The spell %u listed in `spell_proc` is not the first rank of the spell.", spellId); continue; } } @@ -1986,7 +1986,7 @@ void SpellMgr::LoadSpellProcs() { if (mSpellProcMap.find(spellInfo->Id) != mSpellProcMap.end()) { - TC_LOG_ERROR("sql.sql", "Spell %u listed in `spell_proc` already has its first rank in table.", spellInfo->Id); + TC_LOG_ERROR("sql.sql", "The spell %u listed in `spell_proc` already has its first rank in the table.", spellInfo->Id); break; } @@ -2007,42 +2007,42 @@ void SpellMgr::LoadSpellProcs() TC_LOG_ERROR("sql.sql", "`spell_proc` table entry for spellId %u has wrong `spellFamilyName` set: %u", spellInfo->Id, procEntry.spellFamilyName); if (procEntry.chance < 0) { - TC_LOG_ERROR("sql.sql", "`spell_proc` table entry for spellId %u has negative value in `chance` field", spellInfo->Id); + TC_LOG_ERROR("sql.sql", "`spell_proc` table entry for spellId %u has negative value in the `chance` field", spellInfo->Id); procEntry.chance = 0; } if (procEntry.ratePerMinute < 0) { - TC_LOG_ERROR("sql.sql", "`spell_proc` table entry for spellId %u has negative value in `ratePerMinute` field", spellInfo->Id); + TC_LOG_ERROR("sql.sql", "`spell_proc` table entry for spellId %u has negative value in the `ratePerMinute` field", spellInfo->Id); procEntry.ratePerMinute = 0; } if (cooldown < 0) { - TC_LOG_ERROR("sql.sql", "`spell_proc` table entry for spellId %u has negative value in `cooldown` field", spellInfo->Id); + TC_LOG_ERROR("sql.sql", "`spell_proc` table entry for spellId %u has negative value in the `cooldown` field", spellInfo->Id); procEntry.cooldown = 0; } if (procEntry.chance == 0 && procEntry.ratePerMinute == 0) - TC_LOG_ERROR("sql.sql", "`spell_proc` table entry for spellId %u doesn't have `chance` and `ratePerMinute` values defined, proc will not be triggered", spellInfo->Id); + TC_LOG_ERROR("sql.sql", "`spell_proc` table entry for spellId %u doesn't have any `chance` and `ratePerMinute` values defined, proc will not be triggered", spellInfo->Id); if (procEntry.charges > 99) { - TC_LOG_ERROR("sql.sql", "`spell_proc` table entry for spellId %u has too big value in `charges` field", spellInfo->Id); + TC_LOG_ERROR("sql.sql", "The `spell_proc` table entry for spellId %u has a too big `charges` field value.", spellInfo->Id); procEntry.charges = 99; } if (!procEntry.typeMask) - TC_LOG_ERROR("sql.sql", "`spell_proc` table entry for spellId %u doesn't have `typeMask` value defined, proc will not be triggered", spellInfo->Id); + TC_LOG_ERROR("sql.sql", "The `spell_proc` table entry for spellId %u doesn't have any `typeMask` value defined, proc will not be triggered.", spellInfo->Id); if (procEntry.spellTypeMask & ~PROC_SPELL_TYPE_MASK_ALL) TC_LOG_ERROR("sql.sql", "`spell_proc` table entry for spellId %u has wrong `spellTypeMask` set: %u", spellInfo->Id, procEntry.spellTypeMask); if (procEntry.spellTypeMask && !(procEntry.typeMask & (SPELL_PROC_FLAG_MASK | PERIODIC_PROC_FLAG_MASK))) - TC_LOG_ERROR("sql.sql", "`spell_proc` table entry for spellId %u has `spellTypeMask` value defined, but it won't be used for defined `typeMask` value", spellInfo->Id); + TC_LOG_ERROR("sql.sql", "The `spell_proc` table entry for spellId %u has `spellTypeMask` value defined, but it will not be used for the defined `typeMask` value.", spellInfo->Id); if (!procEntry.spellPhaseMask && procEntry.typeMask & REQ_SPELL_PHASE_PROC_FLAG_MASK) - TC_LOG_ERROR("sql.sql", "`spell_proc` table entry for spellId %u doesn't have `spellPhaseMask` value defined, but it's required for defined `typeMask` value, proc will not be triggered", spellInfo->Id); + TC_LOG_ERROR("sql.sql", "The `spell_proc` table entry for spellId %u doesn't have any `spellPhaseMask` value defined, but it is required for the defined `typeMask` value. Proc will not be triggered.", spellInfo->Id); if (procEntry.spellPhaseMask & ~PROC_SPELL_PHASE_MASK_ALL) - TC_LOG_ERROR("sql.sql", "`spell_proc` table entry for spellId %u has wrong `spellPhaseMask` set: %u", spellInfo->Id, procEntry.spellPhaseMask); + TC_LOG_ERROR("sql.sql", "The `spell_proc` table entry for spellId %u has wrong `spellPhaseMask` set: %u", spellInfo->Id, procEntry.spellPhaseMask); if (procEntry.spellPhaseMask && !(procEntry.typeMask & REQ_SPELL_PHASE_PROC_FLAG_MASK)) - TC_LOG_ERROR("sql.sql", "`spell_proc` table entry for spellId %u has `spellPhaseMask` value defined, but it won't be used for defined `typeMask` value", spellInfo->Id); + TC_LOG_ERROR("sql.sql", "The `spell_proc` table entry for spellId %u has a `spellPhaseMask` value defined, but it will not be used for the defined `typeMask` value.", spellInfo->Id); if (procEntry.hitMask & ~PROC_HIT_MASK_ALL) - TC_LOG_ERROR("sql.sql", "`spell_proc` table entry for spellId %u has wrong `hitMask` set: %u", spellInfo->Id, procEntry.hitMask); + TC_LOG_ERROR("sql.sql", "The `spell_proc` table entry for spellId %u has wrong `hitMask` set: %u", spellInfo->Id, procEntry.hitMask); if (procEntry.hitMask && !(procEntry.typeMask & TAKEN_HIT_PROC_FLAG_MASK || (procEntry.typeMask & DONE_HIT_PROC_FLAG_MASK && (!procEntry.spellPhaseMask || procEntry.spellPhaseMask & (PROC_SPELL_PHASE_HIT | PROC_SPELL_PHASE_FINISH))))) - TC_LOG_ERROR("sql.sql", "`spell_proc` table entry for spellId %u has `hitMask` value defined, but it won't be used for defined `typeMask` and `spellPhaseMask` values", spellInfo->Id); + TC_LOG_ERROR("sql.sql", "The `spell_proc` table entry for spellId %u has `hitMask` value defined, but it will not be used for defined `typeMask` and `spellPhaseMask` values.", spellInfo->Id); mSpellProcMap[spellInfo->Id] = procEntry; @@ -2081,7 +2081,7 @@ void SpellMgr::LoadSpellBonusess() SpellInfo const* spell = GetSpellInfo(entry); if (!spell) { - TC_LOG_ERROR("sql.sql", "Spell %u listed in `spell_bonus_data` does not exist", entry); + TC_LOG_ERROR("sql.sql", "The spell %u listed in `spell_bonus_data` does not exist.", entry); continue; } @@ -2120,7 +2120,7 @@ void SpellMgr::LoadSpellThreats() if (!GetSpellInfo(entry)) { - TC_LOG_ERROR("sql.sql", "Spell %u listed in `spell_threat` does not exist", entry); + TC_LOG_ERROR("sql.sql", "The spell %u listed in `spell_threat` does not exist.", entry); continue; } @@ -2189,21 +2189,21 @@ void SpellMgr::LoadSpellPetAuras() SpellInfo const* spellInfo = GetSpellInfo(spell); if (!spellInfo) { - TC_LOG_ERROR("sql.sql", "Spell %u listed in `spell_pet_auras` does not exist", spell); + TC_LOG_ERROR("sql.sql", "The spell %u listed in `spell_pet_auras` does not exist.", spell); continue; } if (spellInfo->Effects[eff].Effect != SPELL_EFFECT_DUMMY && (spellInfo->Effects[eff].Effect != SPELL_EFFECT_APPLY_AURA || spellInfo->Effects[eff].ApplyAuraName != SPELL_AURA_DUMMY)) { - TC_LOG_ERROR("spells", "Spell %u listed in `spell_pet_auras` does not have dummy aura or dummy effect", spell); + TC_LOG_ERROR("spells", "The spell %u listed in `spell_pet_auras` does not have any dummy aura or dummy effect.", spell); continue; } SpellInfo const* spellInfo2 = GetSpellInfo(aura); if (!spellInfo2) { - TC_LOG_ERROR("sql.sql", "Aura %u listed in `spell_pet_auras` does not exist", aura); + TC_LOG_ERROR("sql.sql", "The aura %u listed in `spell_pet_auras` does not exist.", aura); continue; } @@ -2281,7 +2281,7 @@ void SpellMgr::LoadSpellEnchantProcData() SpellItemEnchantmentEntry const* ench = sSpellItemEnchantmentStore.LookupEntry(enchantId); if (!ench) { - TC_LOG_ERROR("sql.sql", "Enchancment %u listed in `spell_enchant_proc_data` does not exist", enchantId); + TC_LOG_ERROR("sql.sql", "The enchancment %u listed in `spell_enchant_proc_data` does not exist.", enchantId); continue; } @@ -2325,7 +2325,7 @@ void SpellMgr::LoadSpellLinked() SpellInfo const* spellInfo = GetSpellInfo(abs(trigger)); if (!spellInfo) { - TC_LOG_ERROR("sql.sql", "Spell %u listed in `spell_linked_spell` does not exist", abs(trigger)); + TC_LOG_ERROR("sql.sql", "The spell %u listed in `spell_linked_spell` does not exist.", abs(trigger)); continue; } @@ -2333,13 +2333,13 @@ void SpellMgr::LoadSpellLinked() for (uint8 j = 0; j < MAX_SPELL_EFFECTS; ++j) { if (spellInfo->Effects[j].CalcValue() == abs(effect)) - TC_LOG_ERROR("sql.sql", "Spell %u Effect: %u listed in `spell_linked_spell` has same bp%u like effect (possible hack)", abs(trigger), abs(effect), j); + TC_LOG_ERROR("sql.sql", "The spell %u Effect: %u listed in `spell_linked_spell` has same bp%u like effect (possible hack).", abs(trigger), abs(effect), j); } spellInfo = GetSpellInfo(abs(effect)); if (!spellInfo) { - TC_LOG_ERROR("sql.sql", "Spell %u listed in `spell_linked_spell` does not exist", abs(effect)); + TC_LOG_ERROR("sql.sql", "The spell %u listed in `spell_linked_spell` does not exist.", abs(effect)); continue; } @@ -2584,7 +2584,7 @@ void SpellMgr::LoadSpellAreas() } else { - TC_LOG_ERROR("sql.sql", "Spell %u listed in `spell_area` does not exist", spell); + TC_LOG_ERROR("sql.sql", "The spell %u listed in `spell_area` does not exist", spell); continue; } @@ -2613,20 +2613,20 @@ void SpellMgr::LoadSpellAreas() if (!ok) { - TC_LOG_ERROR("sql.sql", "Spell %u listed in `spell_area` already listed with similar requirements.", spell); + TC_LOG_ERROR("sql.sql", "The spell %u listed in `spell_area` is already listed with similar requirements.", spell); continue; } } - if (spellArea.areaId && !GetAreaEntryByAreaID(spellArea.areaId)) + if (spellArea.areaId && !sAreaTableStore.LookupEntry(spellArea.areaId)) { - TC_LOG_ERROR("sql.sql", "Spell %u listed in `spell_area` have wrong area (%u) requirement", spell, spellArea.areaId); + TC_LOG_ERROR("sql.sql", "The spell %u listed in `spell_area` has a wrong area (%u) requirement.", spell, spellArea.areaId); continue; } if (spellArea.questStart && !sObjectMgr->GetQuestTemplate(spellArea.questStart)) { - TC_LOG_ERROR("sql.sql", "Spell %u listed in `spell_area` have wrong start quest (%u) requirement", spell, spellArea.questStart); + TC_LOG_ERROR("sql.sql", "The spell %u listed in `spell_area` has a wrong start quest (%u) requirement.", spell, spellArea.questStart); continue; } @@ -2634,7 +2634,7 @@ void SpellMgr::LoadSpellAreas() { if (!sObjectMgr->GetQuestTemplate(spellArea.questEnd)) { - TC_LOG_ERROR("sql.sql", "Spell %u listed in `spell_area` have wrong end quest (%u) requirement", spell, spellArea.questEnd); + TC_LOG_ERROR("sql.sql", "The spell %u listed in `spell_area` has a wrong ending quest (%u) requirement.", spell, spellArea.questEnd); continue; } } @@ -2644,13 +2644,13 @@ void SpellMgr::LoadSpellAreas() SpellInfo const* spellInfo = GetSpellInfo(abs(spellArea.auraSpell)); if (!spellInfo) { - TC_LOG_ERROR("sql.sql", "Spell %u listed in `spell_area` have wrong aura spell (%u) requirement", spell, abs(spellArea.auraSpell)); + TC_LOG_ERROR("sql.sql", "The spell %u listed in `spell_area` has wrong aura spell (%u) requirement", spell, abs(spellArea.auraSpell)); continue; } if (uint32(abs(spellArea.auraSpell)) == spellArea.spellId) { - TC_LOG_ERROR("sql.sql", "Spell %u listed in `spell_area` have aura spell (%u) requirement for itself", spell, abs(spellArea.auraSpell)); + TC_LOG_ERROR("sql.sql", "The spell %u listed in `spell_area` has aura spell (%u) requirement for itself", spell, abs(spellArea.auraSpell)); continue; } @@ -2670,7 +2670,7 @@ void SpellMgr::LoadSpellAreas() if (chain) { - TC_LOG_ERROR("sql.sql", "Spell %u listed in `spell_area` have aura spell (%u) requirement that itself autocast from aura", spell, spellArea.auraSpell); + TC_LOG_ERROR("sql.sql", "The spell %u listed in `spell_area` has the aura spell (%u) requirement that it autocasts itself from the aura.", spell, spellArea.auraSpell); continue; } @@ -2686,7 +2686,7 @@ void SpellMgr::LoadSpellAreas() if (chain) { - TC_LOG_ERROR("sql.sql", "Spell %u listed in `spell_area` have aura spell (%u) requirement that itself autocast from aura", spell, spellArea.auraSpell); + TC_LOG_ERROR("sql.sql", "The spell %u listed in `spell_area` has the aura spell (%u) requirement that the spell itself autocasts from the aura.", spell, spellArea.auraSpell); continue; } } @@ -2694,13 +2694,13 @@ void SpellMgr::LoadSpellAreas() if (spellArea.raceMask && (spellArea.raceMask & RACEMASK_ALL_PLAYABLE) == 0) { - TC_LOG_ERROR("sql.sql", "Spell %u listed in `spell_area` have wrong race mask (%u) requirement", spell, spellArea.raceMask); + TC_LOG_ERROR("sql.sql", "The spell %u listed in `spell_area` has wrong race mask (%u) requirement.", spell, spellArea.raceMask); continue; } if (spellArea.gender != GENDER_NONE && spellArea.gender != GENDER_FEMALE && spellArea.gender != GENDER_MALE) { - TC_LOG_ERROR("sql.sql", "Spell %u listed in `spell_area` have wrong gender (%u) requirement", spell, spellArea.gender); + TC_LOG_ERROR("sql.sql", "The spell %u listed in `spell_area` has wrong gender (%u) requirement.", spell, spellArea.gender); continue; } @@ -2987,13 +2987,6 @@ void SpellMgr::LoadSpellInfoCorrections() case 36350: // They Must Burn Bomb Aura (self) spellInfo->Effects[EFFECT_0].TriggerSpell = 36325; // They Must Burn Bomb Drop (DND) break; - case 49838: // Stop Time - case 69438: // Sample Satisfaction - case 69445: // Perfume Spritz - case 69489: // Chocolate Sample - case 69563: // Cologne Spritz - spellInfo->AttributesEx3 |= SPELL_ATTR3_NO_INITIAL_AGGRO; - break; case 61407: // Energize Cores case 62136: // Energize Cores case 54069: // Energize Cores diff --git a/src/server/game/Texts/CreatureTextMgr.cpp b/src/server/game/Texts/CreatureTextMgr.cpp index 8d3ee939e2c..499f0c9cbf0 100644 --- a/src/server/game/Texts/CreatureTextMgr.cpp +++ b/src/server/game/Texts/CreatureTextMgr.cpp @@ -191,7 +191,6 @@ void CreatureTextMgr::LoadCreatureTextLocales() } while (result->NextRow()); TC_LOG_INFO("server.loading", ">> Loaded %u creature localized texts in %u ms", textCount, GetMSTimeDiffToNow(oldMSTime)); - } uint32 CreatureTextMgr::SendChat(Creature* source, uint8 textGroup, WorldObject const* whisperTarget /*= nullptr*/, ChatMsg msgType /*= CHAT_MSG_ADDON*/, Language language /*= LANG_ADDON*/, CreatureTextRange range /*= TEXT_RANGE_NORMAL*/, uint32 sound /*= 0*/, Team team /*= TEAM_OTHER*/, bool gmOnly /*= false*/, Player* srcPlr /*= nullptr*/) @@ -228,42 +227,10 @@ uint32 CreatureTextMgr::SendChat(Creature* source, uint8 textGroup, WorldObject tempGroup = textGroupContainer; } - uint8 count = 0; - float lastChance = -1; - bool isEqualChanced = true; - - float totalChance = 0; - - for (CreatureTextGroup::const_iterator iter = tempGroup.begin(); iter != tempGroup.end(); ++iter) + auto iter = Trinity::Containers::SelectRandomWeightedContainerElement(tempGroup, [](CreatureTextEntry const& t) -> double { - if (lastChance >= 0 && lastChance != iter->probability) - isEqualChanced = false; - - lastChance = iter->probability; - totalChance += iter->probability; - ++count; - } - - int32 offset = -1; - if (!isEqualChanced) - { - for (CreatureTextGroup::const_iterator iter = tempGroup.begin(); iter != tempGroup.end(); ++iter) - { - uint32 chance = uint32(iter->probability); - uint32 r = urand(0, 100); - ++offset; - if (r <= chance) - break; - } - } - - uint32 pos = 0; - if (isEqualChanced || offset < 0) - pos = urand(0, count - 1); - else if (offset >= 0) - pos = offset; - - CreatureTextGroup::const_iterator iter = tempGroup.begin() + pos; + return t.probability; + }); ChatMsg finalType = (msgType == CHAT_MSG_ADDON) ? iter->type : msgType; Language finalLang = (language == LANG_ADDON) ? iter->lang : language; @@ -293,9 +260,7 @@ uint32 CreatureTextMgr::SendChat(Creature* source, uint8 textGroup, WorldObject SendChatPacket(finalSource, builder, finalType, whisperTarget, range, team, gmOnly); } - if (isEqualChanced || totalChance == 100.0f) - SetRepeatId(source, textGroup, iter->id); - + SetRepeatId(source, textGroup, iter->id); return iter->duration; } diff --git a/src/server/game/Weather/Weather.cpp b/src/server/game/Weather/Weather.cpp index f774916f4a5..7ef16e32031 100644 --- a/src/server/game/Weather/Weather.cpp +++ b/src/server/game/Weather/Weather.cpp @@ -152,7 +152,7 @@ bool Weather::ReGenerate() uint32 chance2 = chance1+ m_weatherChances->data[season].snowChance; uint32 chance3 = chance2+ m_weatherChances->data[season].stormChance; - uint32 rnd = urand(0, 99); + uint32 rnd = urand(1, 100); if (rnd <= chance1) m_type = WEATHER_TYPE_RAIN; else if (rnd <= chance2) diff --git a/src/server/game/World/World.cpp b/src/server/game/World/World.cpp index 289a4d47666..b238b0a356d 100644 --- a/src/server/game/World/World.cpp +++ b/src/server/game/World/World.cpp @@ -1003,7 +1003,7 @@ void World::LoadConfigSettings(bool reload) m_bool_configs[CONFIG_DETECT_POS_COLLISION] = sConfigMgr->GetBoolDefault("DetectPosCollision", true); m_bool_configs[CONFIG_RESTRICTED_LFG_CHANNEL] = sConfigMgr->GetBoolDefault("Channel.RestrictedLfg", true); - m_bool_configs[CONFIG_TALENTS_INSPECTING] = sConfigMgr->GetBoolDefault("TalentsInspecting", true); + m_int_configs[CONFIG_TALENTS_INSPECTING] = sConfigMgr->GetIntDefault("TalentsInspecting", 1); m_bool_configs[CONFIG_CHAT_FAKE_MESSAGE_PREVENTING] = sConfigMgr->GetBoolDefault("ChatFakeMessagePreventing", false); m_int_configs[CONFIG_CHAT_STRICT_LINK_CHECKING_SEVERITY] = sConfigMgr->GetIntDefault("ChatStrictLinkChecking.Severity", 0); m_int_configs[CONFIG_CHAT_STRICT_LINK_CHECKING_KICK] = sConfigMgr->GetIntDefault("ChatStrictLinkChecking.Kick", 0); diff --git a/src/server/game/World/World.h b/src/server/game/World/World.h index 00b244c9efb..2f1580d887c 100644 --- a/src/server/game/World/World.h +++ b/src/server/game/World/World.h @@ -113,7 +113,6 @@ enum WorldBoolConfigs CONFIG_QUEST_IGNORE_RAID, CONFIG_DETECT_POS_COLLISION, CONFIG_RESTRICTED_LFG_CHANNEL, - CONFIG_TALENTS_INSPECTING, CONFIG_CHAT_FAKE_MESSAGE_PREVENTING, CONFIG_DEATH_CORPSE_RECLAIM_DELAY_PVP, CONFIG_DEATH_CORPSE_RECLAIM_DELAY_PVE, @@ -358,6 +357,7 @@ enum WorldIntConfigs CONFIG_NO_GRAY_AGGRO_BELOW, CONFIG_AUCTION_GETALL_DELAY, CONFIG_AUCTION_SEARCH_DELAY, + CONFIG_TALENTS_INSPECTING, INT_CONFIG_VALUE_COUNT }; diff --git a/src/server/scripts/CMakeLists.txt b/src/server/scripts/CMakeLists.txt index a15b6f8ad07..ea0b058b91d 100644 --- a/src/server/scripts/CMakeLists.txt +++ b/src/server/scripts/CMakeLists.txt @@ -16,9 +16,15 @@ if (USE_SCRIPTPCH) endif () message(STATUS "SCRIPT PREPARATIONS") -include(Spells/CMakeLists.txt) -include(Commands/CMakeLists.txt) +macro(PrepareScripts name out) + file(GLOB_RECURSE found + ${name}/*.h + ${name}/*.cpp + ) + list(APPEND ${out} ${found}) + message(STATUS " -> Prepared: ${name}") +endmacro(PrepareScripts) set(scripts_STAT_SRCS ${scripts_STAT_SRCS} @@ -28,16 +34,19 @@ set(scripts_STAT_SRCS ../game/Maps/AreaBoundary.cpp ) +PrepareScripts(Spells scripts_STAT_SRCS) +PrepareScripts(Commands scripts_STAT_SRCS) + if(SCRIPTS) - include(Custom/CMakeLists.txt) - include(World/CMakeLists.txt) - include(OutdoorPvP/CMakeLists.txt) - include(EasternKingdoms/CMakeLists.txt) - include(Kalimdor/CMakeLists.txt) - include(Outland/CMakeLists.txt) - include(Northrend/CMakeLists.txt) - include(Events/CMakeLists.txt) - include(Pet/CMakeLists.txt) + PrepareScripts(Custom scripts_STAT_SRCS) + PrepareScripts(World scripts_STAT_SRCS) + PrepareScripts(OutdoorPvP scripts_STAT_SRCS) + PrepareScripts(EasternKingdoms scripts_STAT_SRCS) + PrepareScripts(Kalimdor scripts_STAT_SRCS) + PrepareScripts(Outland scripts_STAT_SRCS) + PrepareScripts(Northrend scripts_STAT_SRCS) + PrepareScripts(Events scripts_STAT_SRCS) + PrepareScripts(Pet scripts_STAT_SRCS) endif() message(STATUS "SCRIPT PREPARATION COMPLETE") @@ -63,6 +72,7 @@ include_directories( ${CMAKE_SOURCE_DIR}/src/server/game/Addons ${CMAKE_SOURCE_DIR}/src/server/game/AI ${CMAKE_SOURCE_DIR}/src/server/game/AI/CoreAI + ${CMAKE_SOURCE_DIR}/src/server/game/AI/PlayerAI ${CMAKE_SOURCE_DIR}/src/server/game/AI/ScriptedAI ${CMAKE_SOURCE_DIR}/src/server/game/AI/SmartScripts ${CMAKE_SOURCE_DIR}/src/server/game/AuctionHouse diff --git a/src/server/scripts/Commands/CMakeLists.txt b/src/server/scripts/Commands/CMakeLists.txt deleted file mode 100644 index d4d75cd175f..00000000000 --- a/src/server/scripts/Commands/CMakeLists.txt +++ /dev/null @@ -1,18 +0,0 @@ -# Copyright (C) 2008-2016 TrinityCore <http://www.trinitycore.org/> -# -# This file is free software; as a special exception the author gives -# unlimited permission to copy and/or distribute it, with or without -# modifications, as long as this notice is preserved. -# -# This program is distributed in the hope that it will be useful, but -# WITHOUT ANY WARRANTY, to the extent permitted by law; without even the -# implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. - -file(GLOB_RECURSE sources_Commands Commands/*.cpp Commands/*.h) - -set(scripts_STAT_SRCS - ${scripts_STAT_SRCS} - ${sources_Commands} -) - -message(" -> Prepared: Commands") diff --git a/src/server/scripts/Commands/cs_character.cpp b/src/server/scripts/Commands/cs_character.cpp index e048aabd4d7..eb1aa98f4ff 100644 --- a/src/server/scripts/Commands/cs_character.cpp +++ b/src/server/scripts/Commands/cs_character.cpp @@ -133,7 +133,7 @@ public: info.name = fields[1].GetString(); info.accountId = fields[2].GetUInt32(); - // account name will be empty for not existed account + // account name will be empty for nonexisting account AccountMgr::GetName(info.accountId, info.accountName); info.deleteDate = time_t(fields[3].GetUInt32()); foundList.push_back(info); @@ -169,11 +169,11 @@ public: if (!handler->GetSession()) handler->PSendSysMessage(LANG_CHARACTER_DELETED_LIST_LINE_CONSOLE, - itr->guid.GetCounter(), itr->name.c_str(), itr->accountName.empty() ? "<Not existed>" : itr->accountName.c_str(), + itr->guid.GetCounter(), itr->name.c_str(), itr->accountName.empty() ? "<Not existing>" : itr->accountName.c_str(), itr->accountId, dateStr.c_str()); else handler->PSendSysMessage(LANG_CHARACTER_DELETED_LIST_LINE_CHAT, - itr->guid.GetCounter(), itr->name.c_str(), itr->accountName.empty() ? "<Not existed>" : itr->accountName.c_str(), + itr->guid.GetCounter(), itr->name.c_str(), itr->accountName.empty() ? "<Not existing>" : itr->accountName.c_str(), itr->accountId, dateStr.c_str()); } @@ -193,7 +193,7 @@ public: */ static void HandleCharacterDeletedRestoreHelper(DeletedInfo const& delInfo, ChatHandler* handler) { - if (delInfo.accountName.empty()) // account not exist + if (delInfo.accountName.empty()) // account does not exist { handler->PSendSysMessage(LANG_CHARACTER_DELETED_SKIP_ACCOUNT, delInfo.name.c_str(), delInfo.guid.GetCounter(), delInfo.accountId); return; @@ -660,7 +660,7 @@ public: if (newCharName.empty()) { - // Drop not existed account cases + // Drop nonexisting account cases for (DeletedInfoList::iterator itr = foundList.begin(); itr != foundList.end(); ++itr) HandleCharacterDeletedRestoreHelper(*itr, handler); } @@ -810,7 +810,7 @@ public: if (levelStr && isalpha(levelStr[0])) { nameStr = levelStr; - levelStr = NULL; // current level will used + levelStr = NULL; // current level will be used } Player* target; diff --git a/src/server/scripts/Commands/cs_debug.cpp b/src/server/scripts/Commands/cs_debug.cpp index 9902b83ff63..b937fc4e0a4 100644 --- a/src/server/scripts/Commands/cs_debug.cpp +++ b/src/server/scripts/Commands/cs_debug.cpp @@ -93,7 +93,8 @@ public: { "moveflags", rbac::RBAC_PERM_COMMAND_DEBUG_MOVEFLAGS, false, &HandleDebugMoveflagsCommand, "" }, { "transport", rbac::RBAC_PERM_COMMAND_DEBUG_TRANSPORT, false, &HandleDebugTransportCommand, "" }, { "loadcells", rbac::RBAC_PERM_COMMAND_DEBUG_LOADCELLS, false, &HandleDebugLoadCellsCommand, "" }, - { "boundary", rbac::RBAC_PERM_COMMAND_DEBUG_BOUNDARY, false, &HandleDebugBoundaryCommand, "" } + { "boundary", rbac::RBAC_PERM_COMMAND_DEBUG_BOUNDARY, false, &HandleDebugBoundaryCommand, "" }, + { "raidreset", rbac::RBAC_PERM_COMMAND_INSTANCE_UNBIND, false, &HandleDebugRaidResetCommand, "" } }; static std::vector<ChatCommand> commandTable = { @@ -1442,6 +1443,32 @@ public: return true; } + + static bool HandleDebugRaidResetCommand(ChatHandler* /*handler*/, char const* args) + { + char* map_str = args ? strtok((char*)args, " ") : nullptr; + char* difficulty_str = args ? strtok(nullptr, " ") : nullptr; + + int32 map = map_str ? atoi(map_str) : -1; + if (map <= 0) + return false; + MapEntry const* mEntry = sMapStore.LookupEntry(map); + if (!mEntry || !mEntry->IsRaid()) + return false; + int32 difficulty = difficulty_str ? atoi(difficulty_str) : -1; + if (difficulty >= MAX_RAID_DIFFICULTY || difficulty < -1) + return false; + + if (difficulty == -1) + for (uint8 diff = 0; diff < MAX_RAID_DIFFICULTY; ++diff) + { + if (GetMapDifficultyData(mEntry->MapID, Difficulty(diff))) + sInstanceSaveMgr->ForceGlobalReset(mEntry->MapID, Difficulty(diff)); + } + else + sInstanceSaveMgr->ForceGlobalReset(mEntry->MapID, Difficulty(difficulty)); + return true; + } }; void AddSC_debug_commandscript() diff --git a/src/server/scripts/Commands/cs_go.cpp b/src/server/scripts/Commands/cs_go.cpp index b7acfb85f50..039af61c010 100644 --- a/src/server/scripts/Commands/cs_go.cpp +++ b/src/server/scripts/Commands/cs_go.cpp @@ -424,7 +424,7 @@ public: uint32 areaId = id ? (uint32)atoi(id) : player->GetZoneId(); - AreaTableEntry const* areaEntry = GetAreaEntryByAreaID(areaId); + AreaTableEntry const* areaEntry = sAreaTableStore.LookupEntry(areaId); if (x < 0 || x > 100 || y < 0 || y > 100 || !areaEntry) { @@ -434,7 +434,7 @@ public: } // update to parent zone if exist (client map show only zones without parents) - AreaTableEntry const* zoneEntry = areaEntry->zone ? GetAreaEntryByAreaID(areaEntry->zone) : areaEntry; + AreaTableEntry const* zoneEntry = areaEntry->zone ? sAreaTableStore.LookupEntry(areaEntry->zone) : areaEntry; ASSERT(zoneEntry); Map const* map = sMapMgr->CreateBaseMap(zoneEntry->mapid); diff --git a/src/server/scripts/Commands/cs_group.cpp b/src/server/scripts/Commands/cs_group.cpp index 5e8952ce881..9f2bc86f9c0 100644 --- a/src/server/scripts/Commands/cs_group.cpp +++ b/src/server/scripts/Commands/cs_group.cpp @@ -348,10 +348,10 @@ public: phase = (!p->IsGameMaster() ? p->GetPhaseMask() : -1); uint32 locale = handler->GetSessionDbcLocale(); - AreaTableEntry const* area = GetAreaEntryByAreaID(p->GetAreaId()); + AreaTableEntry const* area = sAreaTableStore.LookupEntry(p->GetAreaId()); if (area) { - AreaTableEntry const* zone = GetAreaEntryByAreaID(area->zone); + AreaTableEntry const* zone = sAreaTableStore.LookupEntry(area->zone); if (zone) zoneName = zone->area_name[locale]; } diff --git a/src/server/scripts/Commands/cs_instance.cpp b/src/server/scripts/Commands/cs_instance.cpp index a53d1f00b54..d0325a317db 100644 --- a/src/server/scripts/Commands/cs_instance.cpp +++ b/src/server/scripts/Commands/cs_instance.cpp @@ -82,7 +82,7 @@ public: { InstanceSave* save = itr->second.save; std::string timeleft = GetTimeString(save->GetResetTime() - time(NULL)); - handler->PSendSysMessage(LANG_COMMAND_LIST_BIND_INFO, itr->first, save->GetInstanceId(), itr->second.perm ? "yes" : "no", save->GetDifficulty(), save->CanReset() ? "yes" : "no", timeleft.c_str()); + handler->PSendSysMessage(LANG_COMMAND_LIST_BIND_INFO, itr->first, save->GetInstanceId(), itr->second.perm ? "yes" : "no", itr->second.extendState == EXTEND_STATE_EXPIRED ? "expired" : itr->second.extendState == EXTEND_STATE_EXTENDED ? "yes" : "no", save->GetDifficulty(), save->CanReset() ? "yes" : "no", timeleft.c_str()); counter++; } } @@ -98,7 +98,7 @@ public: { InstanceSave* save = itr->second.save; std::string timeleft = GetTimeString(save->GetResetTime() - time(NULL)); - handler->PSendSysMessage(LANG_COMMAND_LIST_BIND_INFO, itr->first, save->GetInstanceId(), itr->second.perm ? "yes" : "no", save->GetDifficulty(), save->CanReset() ? "yes" : "no", timeleft.c_str()); + handler->PSendSysMessage(LANG_COMMAND_LIST_BIND_INFO, itr->first, save->GetInstanceId(), itr->second.perm ? "yes" : "no", "-", save->GetDifficulty(), save->CanReset() ? "yes" : "no", timeleft.c_str()); counter++; } } diff --git a/src/server/scripts/Commands/cs_lookup.cpp b/src/server/scripts/Commands/cs_lookup.cpp index 4e749d33fcf..61e6acfb4d8 100644 --- a/src/server/scripts/Commands/cs_lookup.cpp +++ b/src/server/scripts/Commands/cs_lookup.cpp @@ -97,9 +97,9 @@ public: wstrToLower(wNamePart); // Search in AreaTable.dbc - for (uint32 areaflag = 0; areaflag < sAreaStore.GetNumRows(); ++areaflag) + for (uint32 i = 0; i < sAreaTableStore.GetNumRows(); ++i) { - AreaTableEntry const* areaEntry = sAreaStore.LookupEntry(areaflag); + AreaTableEntry const* areaEntry = sAreaTableStore.LookupEntry(i); if (areaEntry) { int locale = handler->GetSessionDbcLocale(); diff --git a/src/server/scripts/Commands/cs_misc.cpp b/src/server/scripts/Commands/cs_misc.cpp index 6ae509af443..c70246f7fb5 100644 --- a/src/server/scripts/Commands/cs_misc.cpp +++ b/src/server/scripts/Commands/cs_misc.cpp @@ -198,8 +198,8 @@ public: uint32 mapId = object->GetMapId(); MapEntry const* mapEntry = sMapStore.LookupEntry(mapId); - AreaTableEntry const* zoneEntry = GetAreaEntryByAreaID(zoneId); - AreaTableEntry const* areaEntry = GetAreaEntryByAreaID(areaId); + AreaTableEntry const* zoneEntry = sAreaTableStore.LookupEntry(zoneId); + AreaTableEntry const* areaEntry = sAreaTableStore.LookupEntry(areaId); float zoneX = object->GetPositionX(); float zoneY = object->GetPositionY(); @@ -961,7 +961,7 @@ public: uint32 zoneId = player->GetZoneId(); - AreaTableEntry const* areaEntry = GetAreaEntryByAreaID(zoneId); + AreaTableEntry const* areaEntry = sAreaTableStore.LookupEntry(zoneId); if (!areaEntry || areaEntry->zone !=0) { handler->PSendSysMessage(LANG_COMMAND_GRAVEYARDWRONGZONE, graveyardId, zoneId); @@ -1052,17 +1052,23 @@ public: return false; } - int32 area = GetAreaFlagByAreaID(atoi((char*)args)); - int32 offset = area / 32; + AreaTableEntry const* area = sAreaTableStore.LookupEntry(atoi(args)); + if (!area) + { + handler->SendSysMessage(LANG_BAD_VALUE); + handler->SetSentErrorMessage(true); + return false; + } - if (area<0 || offset >= PLAYER_EXPLORED_ZONES_SIZE) + int32 offset = area->exploreFlag / 32; + if (offset >= PLAYER_EXPLORED_ZONES_SIZE) { handler->SendSysMessage(LANG_BAD_VALUE); handler->SetSentErrorMessage(true); return false; } - uint32 val = uint32((1 << (area % 32))); + uint32 val = uint32((1 << (area->exploreFlag % 32))); uint32 currFields = playerTarget->GetUInt32Value(PLAYER_EXPLORED_ZONES_1 + offset); playerTarget->SetUInt32Value(PLAYER_EXPLORED_ZONES_1 + offset, uint32((currFields | val))); @@ -1083,17 +1089,23 @@ public: return false; } - int32 area = GetAreaFlagByAreaID(atoi((char*)args)); - int32 offset = area / 32; + AreaTableEntry const* area = sAreaTableStore.LookupEntry(atoi(args)); + if (!area) + { + handler->SendSysMessage(LANG_BAD_VALUE); + handler->SetSentErrorMessage(true); + return false; + } - if (area < 0 || offset >= PLAYER_EXPLORED_ZONES_SIZE) + int32 offset = area->exploreFlag / 32; + if (offset >= PLAYER_EXPLORED_ZONES_SIZE) { handler->SendSysMessage(LANG_BAD_VALUE); handler->SetSentErrorMessage(true); return false; } - uint32 val = uint32((1 << (area % 32))); + uint32 val = uint32((1 << (area->exploreFlag % 32))); uint32 currFields = playerTarget->GetUInt32Value(PLAYER_EXPLORED_ZONES_1 + offset); playerTarget->SetUInt32Value(PLAYER_EXPLORED_ZONES_1 + offset, uint32((currFields ^ val))); @@ -1737,12 +1749,12 @@ public: // Position data MapEntry const* map = sMapStore.LookupEntry(mapId); - AreaTableEntry const* area = GetAreaEntryByAreaID(areaId); + AreaTableEntry const* area = sAreaTableStore.LookupEntry(areaId); if (area) { areaName = area->area_name[locale]; - AreaTableEntry const* zone = GetAreaEntryByAreaID(area->zone); + AreaTableEntry const* zone = sAreaTableStore.LookupEntry(area->zone); if (zone) zoneName = zone->area_name[locale]; } diff --git a/src/server/scripts/Commands/cs_script_loader.cpp b/src/server/scripts/Commands/cs_script_loader.cpp new file mode 100644 index 00000000000..449e7053942 --- /dev/null +++ b/src/server/scripts/Commands/cs_script_loader.cpp @@ -0,0 +1,104 @@ +/* + * Copyright (C) 2008-2016 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/>. + */ + +// This is where scripts' loading functions should be declared: +void AddSC_account_commandscript(); +void AddSC_achievement_commandscript(); +void AddSC_ahbot_commandscript(); +void AddSC_arena_commandscript(); +void AddSC_ban_commandscript(); +void AddSC_bf_commandscript(); +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(); +void AddSC_go_commandscript(); +void AddSC_gobject_commandscript(); +void AddSC_group_commandscript(); +void AddSC_guild_commandscript(); +void AddSC_honor_commandscript(); +void AddSC_instance_commandscript(); +void AddSC_learn_commandscript(); +void AddSC_lfg_commandscript(); +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_pet_commandscript(); +void AddSC_quest_commandscript(); +void AddSC_rbac_commandscript(); +void AddSC_reload_commandscript(); +void AddSC_reset_commandscript(); +void AddSC_send_commandscript(); +void AddSC_server_commandscript(); +void AddSC_tele_commandscript(); +void AddSC_ticket_commandscript(); +void AddSC_titles_commandscript(); +void AddSC_wp_commandscript(); + +// The name of this function should match: +// void Add${NameOfDirectory}Scripts() +void AddCommandsScripts() +{ + AddSC_account_commandscript(); + AddSC_achievement_commandscript(); + AddSC_ahbot_commandscript(); + AddSC_arena_commandscript(); + AddSC_ban_commandscript(); + AddSC_bf_commandscript(); + AddSC_cast_commandscript(); + AddSC_character_commandscript(); + AddSC_cheat_commandscript(); + AddSC_debug_commandscript(); + AddSC_deserter_commandscript(); + AddSC_disable_commandscript(); + AddSC_event_commandscript(); + AddSC_gm_commandscript(); + AddSC_go_commandscript(); + AddSC_gobject_commandscript(); + AddSC_group_commandscript(); + AddSC_guild_commandscript(); + AddSC_honor_commandscript(); + AddSC_instance_commandscript(); + AddSC_learn_commandscript(); + AddSC_lookup_commandscript(); + AddSC_lfg_commandscript(); + AddSC_list_commandscript(); + AddSC_message_commandscript(); + AddSC_misc_commandscript(); + AddSC_mmaps_commandscript(); + AddSC_modify_commandscript(); + AddSC_npc_commandscript(); + AddSC_quest_commandscript(); + AddSC_pet_commandscript(); + AddSC_rbac_commandscript(); + AddSC_reload_commandscript(); + AddSC_reset_commandscript(); + AddSC_send_commandscript(); + AddSC_server_commandscript(); + AddSC_tele_commandscript(); + AddSC_ticket_commandscript(); + AddSC_titles_commandscript(); + AddSC_wp_commandscript(); +} diff --git a/src/server/scripts/Commands/cs_send.cpp b/src/server/scripts/Commands/cs_send.cpp index 672db3a3ab0..31544543426 100644 --- a/src/server/scripts/Commands/cs_send.cpp +++ b/src/server/scripts/Commands/cs_send.cpp @@ -74,7 +74,7 @@ public: std::string subject = msgSubject; std::string text = msgText; - // from console show not existed sender + // from console, use non-existing sender MailSender sender(MAIL_NORMAL, handler->GetSession() ? handler->GetSession()->GetPlayer()->GetGUID().GetCounter() : 0, MAIL_STATIONERY_GM); /// @todo Fix poor design @@ -173,7 +173,7 @@ public: } } - // from console show not existed sender + // from console show nonexisting sender MailSender sender(MAIL_NORMAL, handler->GetSession() ? handler->GetSession()->GetPlayer()->GetGUID().GetCounter() : 0, MAIL_STATIONERY_GM); // fill mail @@ -185,7 +185,7 @@ public: { if (Item* item = Item::CreateItem(itr->first, itr->second, handler->GetSession() ? handler->GetSession()->GetPlayer() : 0)) { - item->SaveToDB(trans); // save for prevent lost at next mail load, if send fail then item will deleted + item->SaveToDB(trans); // Save to prevent being lost at next mail load. If send fails, the item will be deleted. draft.AddItem(item); } } @@ -233,7 +233,7 @@ public: std::string subject = msgSubject; std::string text = msgText; - // from console show not existed sender + // from console show nonexisting sender MailSender sender(MAIL_NORMAL, handler->GetSession() ? handler->GetSession()->GetPlayer()->GetGUID().GetCounter() : 0, MAIL_STATIONERY_GM); SQLTransaction trans = CharacterDatabase.BeginTransaction(); @@ -260,7 +260,7 @@ public: if (!msgStr) return false; - ///- Check that he is not logging out. + /// - Check if player is logging out. if (player->GetSession()->isLogingOut()) { handler->SendSysMessage(LANG_PLAYER_NOT_FOUND); diff --git a/src/server/scripts/Commands/cs_titles.cpp b/src/server/scripts/Commands/cs_titles.cpp index 2f5d7b8364c..6309e7279c9 100644 --- a/src/server/scripts/Commands/cs_titles.cpp +++ b/src/server/scripts/Commands/cs_titles.cpp @@ -225,7 +225,7 @@ public: if (CharTitlesEntry const* tEntry = sCharTitlesStore.LookupEntry(i)) titles2 &= ~(uint64(1) << tEntry->bit_index); - titles &= ~titles2; // remove not existed titles + titles &= ~titles2; // remove non-existing titles target->SetUInt64Value(PLAYER__FIELD_KNOWN_TITLES, titles); handler->SendSysMessage(LANG_DONE); diff --git a/src/server/scripts/Custom/CMakeLists.txt b/src/server/scripts/Custom/CMakeLists.txt deleted file mode 100644 index 595ff801813..00000000000 --- a/src/server/scripts/Custom/CMakeLists.txt +++ /dev/null @@ -1,18 +0,0 @@ -# Copyright (C) 2008-2016 TrinityCore <http://www.trinitycore.org/> -# -# This file is free software; as a special exception the author gives -# unlimited permission to copy and/or distribute it, with or without -# modifications, as long as this notice is preserved. -# -# This program is distributed in the hope that it will be useful, but -# WITHOUT ANY WARRANTY, to the extent permitted by law; without even the -# implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. - -# file(GLOB_RECURSE sources_Custom Custom/*.cpp Custom/*.h) - -set(scripts_STAT_SRCS - ${scripts_STAT_SRCS} -# ${sources_Custom} -) - -message(" -> Prepared: Custom") diff --git a/src/server/scripts/Custom/custom_script_loader.cpp b/src/server/scripts/Custom/custom_script_loader.cpp new file mode 100644 index 00000000000..dd4b5e99d77 --- /dev/null +++ b/src/server/scripts/Custom/custom_script_loader.cpp @@ -0,0 +1,25 @@ +/* + * Copyright (C) 2008-2016 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/>. + */ + +// This is where scripts' loading functions should be declared: + + +// The name of this function should match: +// void Add${NameOfDirectory}Scripts() +void AddCustomScripts() +{ +} diff --git a/src/server/scripts/EasternKingdoms/BlackrockMountain/BlackrockDepths/blackrock_depths.cpp b/src/server/scripts/EasternKingdoms/BlackrockMountain/BlackrockDepths/blackrock_depths.cpp index 9cd724e5596..79709734e18 100644 --- a/src/server/scripts/EasternKingdoms/BlackrockMountain/BlackrockDepths/blackrock_depths.cpp +++ b/src/server/scripts/EasternKingdoms/BlackrockMountain/BlackrockDepths/blackrock_depths.cpp @@ -508,19 +508,11 @@ public: }; // npc_lokhtos_darkbargainer -enum LokhtosItems +enum Lokhtos { + QUEST_A_BINDING_CONTRACT = 7604, + ITEM_SULFURON_INGOT = 17203, ITEM_THRORIUM_BROTHERHOOD_CONTRACT = 18628, - ITEM_SULFURON_INGOT = 17203 -}; - -enum LokhtosQuests -{ - QUEST_A_BINDING_CONTRACT = 7604 -}; - -enum LokhtosSpells -{ SPELL_CREATE_THORIUM_BROTHERHOOD_CONTRACT_DND = 23059 }; @@ -570,67 +562,12 @@ public: } }; -// npc_dughal_stormwing -enum DughalQuests -{ - QUEST_JAIL_BREAK = 4322 -}; - -#define SAY_DUGHAL_FREE "Thank you, $N! I'm free!!!" -#define GOSSIP_DUGHAL "You're free, Dughal! Get out of here!" - -// npc_marshal_windsor -#define SAY_WINDSOR_AGGRO1 "You locked up the wrong Marshal. Prepare to be destroyed!" -#define SAY_WINDSOR_AGGRO2 "I bet you're sorry now, aren't you !?!!" -#define SAY_WINDSOR_AGGRO3 "You better hold me back $N or they are going to feel some prison house beatings." -#define SAY_WINDSOR_1 "Let's get a move on. My gear should be in the storage area up this way..." -#define SAY_WINDSOR_4_1 "Check that cell, $N. If someone is alive in there, we need to get them out." -#define SAY_WINDSOR_4_2 "Get him out of there!" -#define SAY_WINDSOR_4_3 "Good work! We're almost there, $N. This way." -#define SAY_WINDSOR_6 "This is it, $N. My stuff should be in that room. Cover me, I'm going in!" -#define SAY_WINDSOR_9 "Ah, there it is!" - -enum MarshalWindsor -{ - NPC_REGINALD_WINDSOR = 9682 -}; - -// npc_marshal_reginald_windsor -#define SAY_REGINALD_WINDSOR_0_1 "Can you feel the power, $N??? It's time to ROCK!" -#define SAY_REGINALD_WINDSOR_0_2 "Now we just have to free Tobias and we can get out of here. This way!" -#define SAY_REGINALD_WINDSOR_5_1 "Open it." -#define SAY_REGINALD_WINDSOR_5_2 "I never did like those two. Let's get moving." -#define SAY_REGINALD_WINDSOR_7_1 "Open it and be careful this time!" -#define SAY_REGINALD_WINDSOR_7_2 "That intolerant dirtbag finally got what was coming to him. Good riddance!" -#define SAY_REGINALD_WINDSOR_7_3 "Alright, let's go." -#define SAY_REGINALD_WINDSOR_13_1 "Open it. We need to hurry up. I can smell those Dark Irons coming a mile away and I can tell you one thing, they're COMING!" -#define SAY_REGINALD_WINDSOR_13_2 "Administering fists of fury on Crest Killer!" -#define SAY_REGINALD_WINDSOR_13_3 "He has to be in the last cell. Unless... they killed him." -#define SAY_REGINALD_WINDSOR_14_1 "Get him out of there!" -#define SAY_REGINALD_WINDSOR_14_2 "Excellent work, $N. Let's find the exit. I think I know the way. Follow me!" -#define SAY_REGINALD_WINDSOR_20_1 "We made it!" -#define SAY_REGINALD_WINDSOR_20_2 "Meet me at Maxwell's encampment. We'll go over the next stages of the plan there and figure out a way to decode my tablets without the decryption ring." - -enum MarshalReginaldWindor -{ - NPC_SHILL_DINGER = 9678, - NPC_CREST_KILLER = 9680 -}; - // npc_rocknot -enum RocknotSays -{ - SAY_GOT_BEER = 0 -}; - -enum RocknotSpells -{ - SPELL_DRUNKEN_RAGE = 14872 -}; - -enum RocknotQuests +enum Rocknot { - QUEST_ALE = 4295 + SAY_GOT_BEER = 0, + QUEST_ALE = 4295, + SPELL_DRUNKEN_RAGE = 14872 }; class npc_rocknot : public CreatureScript diff --git a/src/server/scripts/EasternKingdoms/CMakeLists.txt b/src/server/scripts/EasternKingdoms/CMakeLists.txt deleted file mode 100644 index 8e6616347f9..00000000000 --- a/src/server/scripts/EasternKingdoms/CMakeLists.txt +++ /dev/null @@ -1,204 +0,0 @@ -# Copyright (C) 2008-2016 TrinityCore <http://www.trinitycore.org/> -# -# This file is free software; as a special exception the author gives -# unlimited permission to copy and/or distribute it, with or without -# modifications, as long as this notice is preserved. -# -# This program is distributed in the hope that it will be useful, but -# WITHOUT ANY WARRANTY, to the extent permitted by law; without even the -# implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. - -set(scripts_STAT_SRCS - ${scripts_STAT_SRCS} - EasternKingdoms/zone_ghostlands.cpp - EasternKingdoms/AlteracValley/boss_galvangar.cpp - EasternKingdoms/AlteracValley/boss_balinda.cpp - EasternKingdoms/AlteracValley/boss_drekthar.cpp - EasternKingdoms/AlteracValley/boss_vanndar.cpp - EasternKingdoms/AlteracValley/alterac_valley.cpp - EasternKingdoms/BlackrockMountain/BlackrockDepths/boss_high_interrogator_gerstahn.cpp - EasternKingdoms/BlackrockMountain/BlackrockDepths/blackrock_depths.cpp - EasternKingdoms/BlackrockMountain/BlackrockDepths/boss_tomb_of_seven.cpp - EasternKingdoms/BlackrockMountain/BlackrockDepths/boss_general_angerforge.cpp - EasternKingdoms/BlackrockMountain/BlackrockDepths/boss_ambassador_flamelash.cpp - EasternKingdoms/BlackrockMountain/BlackrockDepths/instance_blackrock_depths.cpp - EasternKingdoms/BlackrockMountain/BlackrockDepths/boss_moira_bronzebeard.cpp - EasternKingdoms/BlackrockMountain/BlackrockDepths/blackrock_depths.h - EasternKingdoms/BlackrockMountain/BlackrockDepths/boss_emperor_dagran_thaurissan.cpp - EasternKingdoms/BlackrockMountain/BlackrockDepths/boss_magmus.cpp - EasternKingdoms/BlackrockMountain/BlackwingLair/boss_chromaggus.cpp - EasternKingdoms/BlackrockMountain/BlackwingLair/boss_razorgore.cpp - EasternKingdoms/BlackrockMountain/BlackwingLair/boss_firemaw.cpp - EasternKingdoms/BlackrockMountain/BlackwingLair/boss_broodlord_lashlayer.cpp - EasternKingdoms/BlackrockMountain/BlackwingLair/boss_ebonroc.cpp - EasternKingdoms/BlackrockMountain/BlackwingLair/instance_blackwing_lair.cpp - EasternKingdoms/BlackrockMountain/BlackwingLair/boss_vaelastrasz.cpp - EasternKingdoms/BlackrockMountain/BlackwingLair/boss_nefarian.cpp - EasternKingdoms/BlackrockMountain/BlackwingLair/boss_flamegor.cpp - EasternKingdoms/BlackrockMountain/BlackwingLair/blackwing_lair.h - EasternKingdoms/BlackrockMountain/BlackrockSpire/boss_pyroguard_emberseer.cpp - EasternKingdoms/BlackrockMountain/BlackrockSpire/boss_drakkisath.cpp - EasternKingdoms/BlackrockMountain/BlackrockSpire/boss_warmaster_voone.cpp - EasternKingdoms/BlackrockMountain/BlackrockSpire/boss_mother_smolderweb.cpp - EasternKingdoms/BlackrockMountain/BlackrockSpire/boss_quartermaster_zigris.cpp - EasternKingdoms/BlackrockMountain/BlackrockSpire/boss_halycon.cpp - EasternKingdoms/BlackrockMountain/BlackrockSpire/boss_overlord_wyrmthalak.cpp - EasternKingdoms/BlackrockMountain/BlackrockSpire/boss_shadow_hunter_voshgajin.cpp - EasternKingdoms/BlackrockMountain/BlackrockSpire/boss_gyth.cpp - EasternKingdoms/BlackrockMountain/BlackrockSpire/boss_rend_blackhand.cpp - EasternKingdoms/BlackrockMountain/BlackrockSpire/boss_highlord_omokk.cpp - EasternKingdoms/BlackrockMountain/BlackrockSpire/boss_the_beast.cpp - EasternKingdoms/BlackrockMountain/BlackrockSpire/boss_gizrul_the_slavener.cpp - EasternKingdoms/BlackrockMountain/BlackrockSpire/boss_urok_doomhowl.cpp - EasternKingdoms/BlackrockMountain/BlackrockSpire/boss_lord_valthalak.cpp - EasternKingdoms/BlackrockMountain/BlackrockSpire/blackrock_spire.h - EasternKingdoms/BlackrockMountain/BlackrockSpire/instance_blackrock_spire.cpp - EasternKingdoms/BlackrockMountain/MoltenCore/boss_gehennas.cpp - EasternKingdoms/BlackrockMountain/MoltenCore/boss_lucifron.cpp - EasternKingdoms/BlackrockMountain/MoltenCore/boss_golemagg.cpp - EasternKingdoms/BlackrockMountain/MoltenCore/boss_majordomo_executus.cpp - EasternKingdoms/BlackrockMountain/MoltenCore/boss_baron_geddon.cpp - EasternKingdoms/BlackrockMountain/MoltenCore/boss_ragnaros.cpp - EasternKingdoms/BlackrockMountain/MoltenCore/boss_garr.cpp - EasternKingdoms/BlackrockMountain/MoltenCore/molten_core.h - EasternKingdoms/BlackrockMountain/MoltenCore/instance_molten_core.cpp - EasternKingdoms/BlackrockMountain/MoltenCore/boss_sulfuron_harbinger.cpp - EasternKingdoms/BlackrockMountain/MoltenCore/boss_magmadar.cpp - EasternKingdoms/BlackrockMountain/MoltenCore/boss_shazzrah.cpp - EasternKingdoms/Scholomance/boss_the_ravenian.cpp - EasternKingdoms/Scholomance/boss_instructor_malicia.cpp - EasternKingdoms/Scholomance/boss_death_knight_darkreaver.cpp - EasternKingdoms/Scholomance/boss_illucia_barov.cpp - EasternKingdoms/Scholomance/scholomance.h - EasternKingdoms/Scholomance/boss_vectus.cpp - EasternKingdoms/Scholomance/boss_jandice_barov.cpp - EasternKingdoms/Scholomance/boss_kormok.cpp - EasternKingdoms/Scholomance/boss_lord_alexei_barov.cpp - EasternKingdoms/Scholomance/boss_doctor_theolen_krastinov.cpp - EasternKingdoms/Scholomance/boss_darkmaster_gandling.cpp - EasternKingdoms/Scholomance/instance_scholomance.cpp - EasternKingdoms/Scholomance/boss_lorekeeper_polkelt.cpp - EasternKingdoms/Scholomance/boss_ras_frostwhisper.cpp - EasternKingdoms/Scholomance/boss_kirtonos_the_herald.cpp - EasternKingdoms/zone_isle_of_queldanas.cpp - EasternKingdoms/ZulGurub/boss_hakkar.cpp - EasternKingdoms/ZulGurub/boss_mandokir.cpp - EasternKingdoms/ZulGurub/boss_marli.cpp - EasternKingdoms/ZulGurub/boss_hazzarah.cpp - EasternKingdoms/ZulGurub/boss_jeklik.cpp - EasternKingdoms/ZulGurub/boss_grilek.cpp - EasternKingdoms/ZulGurub/zulgurub.h - EasternKingdoms/ZulGurub/boss_renataki.cpp - EasternKingdoms/ZulGurub/boss_arlokk.cpp - EasternKingdoms/ZulGurub/boss_gahzranka.cpp - EasternKingdoms/ZulGurub/boss_venoxis.cpp - EasternKingdoms/ZulGurub/instance_zulgurub.cpp - EasternKingdoms/ZulGurub/boss_jindo.cpp - EasternKingdoms/ZulGurub/boss_wushoolay.cpp - EasternKingdoms/ZulGurub/boss_thekal.cpp - EasternKingdoms/zone_wetlands.cpp - EasternKingdoms/zone_arathi_highlands.cpp - EasternKingdoms/Gnomeregan/instance_gnomeregan.cpp - EasternKingdoms/Gnomeregan/gnomeregan.cpp - EasternKingdoms/Gnomeregan/gnomeregan.h - EasternKingdoms/zone_redridge_mountains.cpp - EasternKingdoms/ScarletEnclave/chapter2.cpp - EasternKingdoms/ScarletEnclave/chapter5.cpp - EasternKingdoms/ScarletEnclave/chapter1.cpp - EasternKingdoms/ScarletEnclave/zone_the_scarlet_enclave.cpp - EasternKingdoms/zone_eastern_plaguelands.cpp - EasternKingdoms/Stratholme/boss_baroness_anastari.cpp - EasternKingdoms/Stratholme/boss_nerubenkan.cpp - EasternKingdoms/Stratholme/instance_stratholme.cpp - EasternKingdoms/Stratholme/boss_dathrohan_balnazzar.cpp - EasternKingdoms/Stratholme/boss_timmy_the_cruel.cpp - EasternKingdoms/Stratholme/boss_baron_rivendare.cpp - EasternKingdoms/Stratholme/boss_magistrate_barthilas.cpp - EasternKingdoms/Stratholme/boss_order_of_silver_hand.cpp - EasternKingdoms/Stratholme/boss_ramstein_the_gorger.cpp - EasternKingdoms/Stratholme/boss_cannon_master_willey.cpp - EasternKingdoms/Stratholme/boss_maleki_the_pallid.cpp - EasternKingdoms/Stratholme/boss_postmaster_malown.cpp - EasternKingdoms/Stratholme/stratholme.h - EasternKingdoms/Stratholme/stratholme.cpp - EasternKingdoms/zone_tirisfal_glades.cpp - EasternKingdoms/SunkenTemple/sunken_temple.cpp - EasternKingdoms/SunkenTemple/sunken_temple.h - EasternKingdoms/SunkenTemple/instance_sunken_temple.cpp - EasternKingdoms/MagistersTerrace/boss_felblood_kaelthas.cpp - EasternKingdoms/MagistersTerrace/magisters_terrace.h - EasternKingdoms/MagistersTerrace/boss_priestess_delrissa.cpp - EasternKingdoms/MagistersTerrace/instance_magisters_terrace.cpp - EasternKingdoms/MagistersTerrace/boss_selin_fireheart.cpp - EasternKingdoms/MagistersTerrace/boss_vexallus.cpp - EasternKingdoms/MagistersTerrace/magisters_terrace.cpp - EasternKingdoms/Uldaman/uldaman.cpp - EasternKingdoms/Uldaman/boss_ironaya.cpp - EasternKingdoms/Uldaman/uldaman.h - EasternKingdoms/Uldaman/instance_uldaman.cpp - EasternKingdoms/Uldaman/boss_archaedas.cpp - EasternKingdoms/zone_swamp_of_sorrows.cpp - EasternKingdoms/SunwellPlateau/boss_eredar_twins.cpp - EasternKingdoms/SunwellPlateau/boss_kiljaeden.cpp - EasternKingdoms/SunwellPlateau/sunwell_plateau.h - EasternKingdoms/SunwellPlateau/boss_muru.cpp - EasternKingdoms/SunwellPlateau/instance_sunwell_plateau.cpp - EasternKingdoms/SunwellPlateau/boss_kalecgos.cpp - EasternKingdoms/SunwellPlateau/boss_brutallus.cpp - EasternKingdoms/SunwellPlateau/sunwell_plateau.cpp - EasternKingdoms/SunwellPlateau/boss_felmyst.cpp - EasternKingdoms/zone_stranglethorn_vale.cpp - EasternKingdoms/Deadmines/deadmines.h - EasternKingdoms/Deadmines/deadmines.cpp - EasternKingdoms/Deadmines/boss_mr_smite.cpp - EasternKingdoms/Deadmines/instance_deadmines.cpp - EasternKingdoms/zone_duskwood.cpp - EasternKingdoms/ScarletMonastery/boss_azshir_the_sleepless.cpp - EasternKingdoms/ScarletMonastery/boss_mograine_and_whitemane.cpp - EasternKingdoms/ScarletMonastery/boss_bloodmage_thalnos.cpp - EasternKingdoms/ScarletMonastery/boss_interrogator_vishas.cpp - EasternKingdoms/ScarletMonastery/boss_headless_horseman.cpp - EasternKingdoms/ScarletMonastery/instance_scarlet_monastery.cpp - EasternKingdoms/ScarletMonastery/boss_houndmaster_loksey.cpp - EasternKingdoms/ScarletMonastery/scarlet_monastery.h - EasternKingdoms/ScarletMonastery/boss_high_inquisitor_fairbanks.cpp - EasternKingdoms/ScarletMonastery/boss_arcanist_doan.cpp - EasternKingdoms/ScarletMonastery/boss_herod.cpp - EasternKingdoms/ScarletMonastery/boss_scorn.cpp - EasternKingdoms/zone_undercity.cpp - EasternKingdoms/zone_loch_modan.cpp - EasternKingdoms/ShadowfangKeep/shadowfang_keep.cpp - EasternKingdoms/ShadowfangKeep/instance_shadowfang_keep.cpp - EasternKingdoms/ShadowfangKeep/shadowfang_keep.h - EasternKingdoms/zone_burning_steppes.cpp - EasternKingdoms/zone_blasted_lands.cpp - EasternKingdoms/zone_stormwind_city.cpp - EasternKingdoms/ZulAman/boss_halazzi.cpp - EasternKingdoms/ZulAman/boss_hexlord.cpp - EasternKingdoms/ZulAman/boss_zuljin.cpp - EasternKingdoms/ZulAman/boss_akilzon.cpp - EasternKingdoms/ZulAman/instance_zulaman.cpp - EasternKingdoms/ZulAman/boss_janalai.cpp - EasternKingdoms/ZulAman/boss_nalorakk.cpp - EasternKingdoms/ZulAman/zulaman.cpp - EasternKingdoms/ZulAman/zulaman.h - EasternKingdoms/zone_hinterlands.cpp - EasternKingdoms/zone_western_plaguelands.cpp - EasternKingdoms/zone_silverpine_forest.cpp - EasternKingdoms/Karazhan/instance_karazhan.cpp - EasternKingdoms/Karazhan/boss_nightbane.cpp - EasternKingdoms/Karazhan/karazhan.cpp - EasternKingdoms/Karazhan/boss_curator.cpp - EasternKingdoms/Karazhan/boss_shade_of_aran.cpp - EasternKingdoms/Karazhan/boss_netherspite.cpp - EasternKingdoms/Karazhan/boss_maiden_of_virtue.cpp - EasternKingdoms/Karazhan/boss_midnight.cpp - EasternKingdoms/Karazhan/boss_prince_malchezaar.cpp - EasternKingdoms/Karazhan/bosses_opera.cpp - EasternKingdoms/Karazhan/boss_moroes.cpp - EasternKingdoms/Karazhan/boss_terestian_illhoof.cpp - EasternKingdoms/Karazhan/karazhan.h - EasternKingdoms/TheStockade/instance_the_stockade.cpp -) - -message(" -> Prepared: Eastern Kingdoms") diff --git a/src/server/scripts/EasternKingdoms/Deadmines/boss_mr_smite.cpp b/src/server/scripts/EasternKingdoms/Deadmines/boss_mr_smite.cpp index 541ddc0e1c8..8f246ab9bf0 100644 --- a/src/server/scripts/EasternKingdoms/Deadmines/boss_mr_smite.cpp +++ b/src/server/scripts/EasternKingdoms/Deadmines/boss_mr_smite.cpp @@ -25,17 +25,25 @@ EndScriptData */ #include "ScriptedCreature.h" #include "deadmines.h" -enum Spels +enum Spells { SPELL_TRASH = 3391, SPELL_SMITE_STOMP = 6432, SPELL_SMITE_SLAM = 6435, - SPELL_NIMBLE_REFLEXES = 6264, + SPELL_NIMBLE_REFLEXES = 6264 +}; +enum Equips +{ EQUIP_SWORD = 5191, - EQUIP_MACE = 7230, + EQUIP_AXE = 5196, + EQUIP_MACE = 7230 +}; - SAY_AGGRO = 0, +enum Texts +{ + SAY_PHASE_1 = 2, + SAY_PHASE_2 = 3 }; class boss_mr_smite : public CreatureScript @@ -66,6 +74,8 @@ public: uiPhase = 0; uiTimer = 0; + + uiIsMoving = false; } InstanceScript* instance; @@ -79,16 +89,19 @@ public: uint32 uiPhase; uint32 uiTimer; + bool uiIsMoving; + void Reset() override { Initialize(); SetEquipmentSlots(false, EQUIP_SWORD, EQUIP_UNEQUIP, EQUIP_NO_CHANGE); + me->SetStandState(UNIT_STAND_STATE_STAND); + me->SetReactState(REACT_AGGRESSIVE); } void EnterCombat(Unit* /*who*/) override { - Talk(SAY_AGGRO); } bool bCheckChances() @@ -105,38 +118,52 @@ public: if (!UpdateVictim()) return; - /*START ACID-AI*/ - if (uiTrashTimer <= uiDiff) + if (!uiIsMoving) // halt abilities in between phases { - if (bCheckChances()) - DoCast(me, SPELL_TRASH); - uiTrashTimer = urand(6000, 15500); - } else uiTrashTimer -= uiDiff; + if (uiTrashTimer <= uiDiff) + { + if (bCheckChances()) + DoCast(me, SPELL_TRASH); + uiTrashTimer = urand(6000, 15500); + } + else uiTrashTimer -= uiDiff; - if (uiSlamTimer <= uiDiff) - { - if (bCheckChances()) - DoCastVictim(SPELL_SMITE_SLAM); - uiSlamTimer = 11000; - } else uiSlamTimer -= uiDiff; + if (uiSlamTimer <= uiDiff) + { + if (bCheckChances()) + DoCastVictim(SPELL_SMITE_SLAM); + uiSlamTimer = 11000; + } + else uiSlamTimer -= uiDiff; - if (uiNimbleReflexesTimer <= uiDiff) - { - if (bCheckChances()) - DoCast(me, SPELL_NIMBLE_REFLEXES); - uiNimbleReflexesTimer = urand(27300, 60100); - } else uiNimbleReflexesTimer -= uiDiff; - /*END ACID-AI*/ + if (uiNimbleReflexesTimer <= uiDiff) + { + if (bCheckChances()) + DoCast(me, SPELL_NIMBLE_REFLEXES); + uiNimbleReflexesTimer = urand(27300, 60100); + } + else uiNimbleReflexesTimer -= uiDiff; + } if ((uiHealth == 0 && !HealthAbovePct(66)) || (uiHealth == 1 && !HealthAbovePct(33))) { ++uiHealth; DoCastAOE(SPELL_SMITE_STOMP, false); SetCombatMovement(false); - if (GameObject* go = ObjectAccessor::GetGameObject(*me, instance->GetGuidData(DATA_SMITE_CHEST))) + me->AttackStop(); + me->InterruptNonMeleeSpells(false); + me->SetReactState(REACT_PASSIVE); + uiTimer = 2500; + uiPhase = 1; + + switch (uiHealth) { - me->GetMotionMaster()->Clear(); - me->GetMotionMaster()->MovePoint(1, go->GetPositionX() - 3.0f, go->GetPositionY(), go->GetPositionZ()); + case 1: + Talk(SAY_PHASE_1); + break; + case 2: + Talk(SAY_PHASE_2); + break; } } @@ -147,21 +174,36 @@ public: switch (uiPhase) { case 1: - me->HandleEmoteCommand(EMOTE_STATE_KNEEL); //dosen't work? - uiTimer = 1000; - uiPhase = 2; + { + if (uiIsMoving) + break; + + if (GameObject* go = ObjectAccessor::GetGameObject(*me, instance->GetGuidData(DATA_SMITE_CHEST))) + { + me->GetMotionMaster()->Clear(); + me->GetMotionMaster()->MovePoint(1, go->GetPositionX() - 1.5f, go->GetPositionY() + 1.4f, go->GetPositionZ()); + uiIsMoving = true; + } break; + } case 2: if (uiHealth == 1) - SetEquipmentSlots(false, EQUIP_SWORD, EQUIP_SWORD, EQUIP_NO_CHANGE); + SetEquipmentSlots(false, EQUIP_AXE, EQUIP_AXE, EQUIP_NO_CHANGE); else SetEquipmentSlots(false, EQUIP_MACE, EQUIP_UNEQUIP, EQUIP_NO_CHANGE); uiTimer = 500; uiPhase = 3; break; case 3: + me->SetStandState(UNIT_STAND_STATE_STAND); + uiTimer = 750; + uiPhase = 4; + break; + case 4: + me->SetReactState(REACT_AGGRESSIVE); SetCombatMovement(true); me->GetMotionMaster()->MoveChase(me->GetVictim(), me->m_CombatDistance); + uiIsMoving = false; uiPhase = 0; break; } @@ -176,8 +218,11 @@ public: if (uiType != POINT_MOTION_TYPE) return; - uiTimer = 1500; - uiPhase = 1; + me->SetFacingTo(5.47f); + me->SetStandState(UNIT_STAND_STATE_KNEEL); + + uiTimer = 2000; + uiPhase = 2; } }; }; diff --git a/src/server/scripts/EasternKingdoms/Deadmines/deadmines.h b/src/server/scripts/EasternKingdoms/Deadmines/deadmines.h index dff4243617e..01ebabb160e 100644 --- a/src/server/scripts/EasternKingdoms/Deadmines/deadmines.h +++ b/src/server/scripts/EasternKingdoms/Deadmines/deadmines.h @@ -26,6 +26,7 @@ enum CannonState CANNON_GUNPOWDER_USED, CANNON_BLAST_INITIATED, PIRATES_ATTACK, + SMITE_ALARMED, EVENT_DONE }; @@ -48,4 +49,16 @@ enum GameObjects GO_DOOR_LEVER = 101833, GO_MR_SMITE_CHEST = 144111 }; + +enum CreaturesIds +{ + NPC_MR_SMITE = 646 +}; + +enum InstanceTexts +{ + SAY_ALARM1 = 0, + SAY_ALARM2 = 1 +}; + #endif diff --git a/src/server/scripts/EasternKingdoms/Deadmines/instance_deadmines.cpp b/src/server/scripts/EasternKingdoms/Deadmines/instance_deadmines.cpp index 6714b243765..b827fdf7e8b 100644 --- a/src/server/scripts/EasternKingdoms/Deadmines/instance_deadmines.cpp +++ b/src/server/scripts/EasternKingdoms/Deadmines/instance_deadmines.cpp @@ -32,18 +32,14 @@ EndScriptData */ enum Sounds { SOUND_CANNONFIRE = 1400, - SOUND_DESTROYDOOR = 3079, - SOUND_MR_SMITE_ALARM1 = 5775, - SOUND_MR_SMITE_ALARM2 = 5777 + SOUND_DESTROYDOOR = 3079 }; -#define SAY_MR_SMITE_ALARM1 "You there, check out that noise!" -#define SAY_MR_SMITE_ALARM2 "We're under attack! A vast, ye swabs! Repel the invaders!" - enum Misc { DATA_CANNON_BLAST_TIMER = 3000, - DATA_PIRATES_DELAY_TIMER = 1000 + DATA_PIRATES_DELAY_TIMER = 1000, + DATA_SMITE_ALARM_DELAY_TIMER = 5000 }; class instance_deadmines : public InstanceMapScript @@ -72,10 +68,12 @@ class instance_deadmines : public InstanceMapScript ObjectGuid DefiasPirate1GUID; ObjectGuid DefiasPirate2GUID; ObjectGuid DefiasCompanionGUID; + ObjectGuid MrSmiteGUID; uint32 State; uint32 CannonBlast_Timer; uint32 PiratesDelay_Timer; + uint32 SmiteAlarmDelay_Timer; ObjectGuid uiSmiteChestGUID; virtual void Update(uint32 diff) override @@ -91,22 +89,20 @@ class instance_deadmines : public InstanceMapScript { case CANNON_GUNPOWDER_USED: CannonBlast_Timer = DATA_CANNON_BLAST_TIMER; - // it's a hack - Mr. Smite should do that but his too far away - //pIronCladDoor->SetName("Mr. Smite"); - //pIronCladDoor->MonsterYell(SAY_MR_SMITE_ALARM1, LANG_UNIVERSAL, NULL); - pIronCladDoor->PlayDirectSound(SOUND_MR_SMITE_ALARM1); State = CANNON_BLAST_INITIATED; break; case CANNON_BLAST_INITIATED: PiratesDelay_Timer = DATA_PIRATES_DELAY_TIMER; + SmiteAlarmDelay_Timer = DATA_SMITE_ALARM_DELAY_TIMER; if (CannonBlast_Timer <= diff) { SummonCreatures(); ShootCannon(); BlastOutDoor(); LeverStucked(); - //pIronCladDoor->MonsterYell(SAY_MR_SMITE_ALARM2, LANG_UNIVERSAL, NULL); - pIronCladDoor->PlayDirectSound(SOUND_MR_SMITE_ALARM2); + instance->LoadGrid(-22.8f, -797.24f); // Loads Mr. Smite's grid. + if (Creature* smite = instance->GetCreature(MrSmiteGUID)) // goes off when door blows up + smite->AI()->Talk(SAY_ALARM1); State = PIRATES_ATTACK; } else CannonBlast_Timer -= diff; break; @@ -114,9 +110,17 @@ class instance_deadmines : public InstanceMapScript if (PiratesDelay_Timer <= diff) { MoveCreaturesInside(); - State = EVENT_DONE; + State = SMITE_ALARMED; } else PiratesDelay_Timer -= diff; break; + case SMITE_ALARMED: + if (SmiteAlarmDelay_Timer <= diff) + { + if (Creature* smite = instance->GetCreature(MrSmiteGUID)) + smite->AI()->Talk(SAY_ALARM2); + State = EVENT_DONE; + } else SmiteAlarmDelay_Timer -= diff; + break; } } @@ -180,6 +184,18 @@ class instance_deadmines : public InstanceMapScript pDoorLever->SetUInt32Value(GAMEOBJECT_FLAGS, 4); } + void OnCreatureCreate(Creature* creature) override + { + switch (creature->GetEntry()) + { + case NPC_MR_SMITE: + MrSmiteGUID = creature->GetGUID(); + break; + default: + break; + } + } + void OnGameObjectCreate(GameObject* go) override { switch (go->GetEntry()) 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 9f4a31fdbbc..b694c074879 100644 --- a/src/server/scripts/EasternKingdoms/Karazhan/boss_maiden_of_virtue.cpp +++ b/src/server/scripts/EasternKingdoms/Karazhan/boss_maiden_of_virtue.cpp @@ -50,19 +50,9 @@ class boss_maiden_of_virtue : public CreatureScript public: boss_maiden_of_virtue() : CreatureScript("boss_maiden_of_virtue") { } - CreatureAI* GetAI(Creature* creature) const override - { - return new boss_maiden_of_virtueAI(creature); - } - struct boss_maiden_of_virtueAI : public BossAI { - boss_maiden_of_virtueAI(Creature* creature) : BossAI(creature, TYPE_MAIDEN) { } - - void Reset() override - { - _Reset(); - } + boss_maiden_of_virtueAI(Creature* creature) : BossAI(creature, DATA_MAIDEN_OF_VIRTUE) { } void KilledUnit(Unit* /*Victim*/) override { @@ -132,6 +122,11 @@ public: DoMeleeAttackIfReady(); } }; + + CreatureAI* GetAI(Creature* creature) const override + { + return new boss_maiden_of_virtueAI(creature); + } }; void AddSC_boss_maiden_of_virtue() diff --git a/src/server/scripts/EasternKingdoms/Karazhan/boss_midnight.cpp b/src/server/scripts/EasternKingdoms/Karazhan/boss_midnight.cpp index ced8dd8f37e..d4de862244c 100644 --- a/src/server/scripts/EasternKingdoms/Karazhan/boss_midnight.cpp +++ b/src/server/scripts/EasternKingdoms/Karazhan/boss_midnight.cpp @@ -26,6 +26,7 @@ EndScriptData */ #include "ScriptMgr.h" #include "ScriptedCreature.h" #include "SpellInfo.h" +#include "karazhan.h" enum Midnight { @@ -109,6 +110,9 @@ public: Talk(SAY_DEATH); if (Unit* midnight = ObjectAccessor::GetUnit(*me, Midnight)) midnight->KillSelf(); + + if (InstanceScript* instance = me->GetInstanceScript()) + instance->SetBossState(DATA_ATTUMEN, DONE); } void UpdateAI(uint32 diff) override; @@ -157,7 +161,11 @@ public: me->SetVisible(true); } - void EnterCombat(Unit* /*who*/) override { } + void EnterCombat(Unit* /*who*/) override + { + if (InstanceScript* instance = me->GetInstanceScript()) + instance->SetBossState(DATA_ATTUMEN, IN_PROGRESS); + } void KilledUnit(Unit* /*victim*/) override { diff --git a/src/server/scripts/EasternKingdoms/Karazhan/boss_moroes.cpp b/src/server/scripts/EasternKingdoms/Karazhan/boss_moroes.cpp index 79e36442f4b..e667141fa29 100644 --- a/src/server/scripts/EasternKingdoms/Karazhan/boss_moroes.cpp +++ b/src/server/scripts/EasternKingdoms/Karazhan/boss_moroes.cpp @@ -143,12 +143,12 @@ public: if (me->IsAlive()) SpawnAdds(); - instance->SetData(TYPE_MOROES, NOT_STARTED); + instance->SetBossState(DATA_MOROES, NOT_STARTED); } void StartEvent() { - instance->SetData(TYPE_MOROES, IN_PROGRESS); + instance->SetBossState(DATA_MOROES, IN_PROGRESS); DoZoneInCombat(); } @@ -171,7 +171,7 @@ public: { Talk(SAY_DEATH); - instance->SetData(TYPE_MOROES, DONE); + instance->SetBossState(DATA_MOROES, DONE); DeSpawnAdds(); @@ -257,12 +257,6 @@ public: if (!UpdateVictim()) return; - if (!instance->GetData(TYPE_MOROES)) - { - EnterEvadeMode(); - return; - } - if (!Enrage && HealthBelowPct(30)) { DoCast(me, SPELL_FRENZY); @@ -347,7 +341,7 @@ struct boss_moroes_guestAI : public ScriptedAI void Reset() override { - instance->SetData(TYPE_MOROES, NOT_STARTED); + instance->SetBossState(DATA_MOROES, NOT_STARTED); } void AcquireGUID() @@ -373,7 +367,7 @@ struct boss_moroes_guestAI : public ScriptedAI void UpdateAI(uint32 /*diff*/) override { - if (!instance->GetData(TYPE_MOROES)) + if (instance->GetBossState(DATA_MOROES) != IN_PROGRESS) EnterEvadeMode(); DoMeleeAttackIfReady(); diff --git a/src/server/scripts/EasternKingdoms/Karazhan/boss_nightbane.cpp b/src/server/scripts/EasternKingdoms/Karazhan/boss_nightbane.cpp index 6f5f2b8f65f..7d7c60ac419 100644 --- a/src/server/scripts/EasternKingdoms/Karazhan/boss_nightbane.cpp +++ b/src/server/scripts/EasternKingdoms/Karazhan/boss_nightbane.cpp @@ -143,10 +143,10 @@ public: me->SetWalk(false); me->setActive(true); - if (instance->GetData(TYPE_NIGHTBANE) == DONE || instance->GetData(TYPE_NIGHTBANE) == IN_PROGRESS) + if (instance->GetBossState(DATA_NIGHTBANE) == DONE || instance->GetBossState(DATA_NIGHTBANE) == IN_PROGRESS) me->DisappearAndDie(); else - instance->SetData(TYPE_NIGHTBANE, NOT_STARTED); + instance->SetBossState(DATA_NIGHTBANE, NOT_STARTED); HandleTerraceDoors(true); @@ -165,10 +165,10 @@ public: void EnterCombat(Unit* /*who*/) override { - instance->SetData(TYPE_NIGHTBANE, IN_PROGRESS); + instance->SetBossState(DATA_NIGHTBANE, IN_PROGRESS); HandleTerraceDoors(false); - Talk(YELL_AGGRO); + Talk(YELL_AGGRO); } void AttackStart(Unit* who) override @@ -179,7 +179,7 @@ public: void JustDied(Unit* /*killer*/) override { - instance->SetData(TYPE_NIGHTBANE, DONE); + instance->SetBossState(DATA_NIGHTBANE, DONE); HandleTerraceDoors(true); } 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 450678a0f86..17a23a0b2e7 100644 --- a/src/server/scripts/EasternKingdoms/Karazhan/boss_shade_of_aran.cpp +++ b/src/server/scripts/EasternKingdoms/Karazhan/boss_shade_of_aran.cpp @@ -154,7 +154,7 @@ public: Initialize(); // Not in progress - instance->SetData(TYPE_ARAN, NOT_STARTED); + instance->SetBossState(DATA_ARAN, NOT_STARTED); instance->HandleGameObject(instance->GetGuidData(DATA_GO_LIBRARY_DOOR), true); } @@ -167,7 +167,7 @@ public: { Talk(SAY_DEATH); - instance->SetData(TYPE_ARAN, DONE); + instance->SetBossState(DATA_ARAN, DONE); instance->HandleGameObject(instance->GetGuidData(DATA_GO_LIBRARY_DOOR), true); } @@ -175,7 +175,7 @@ public: { Talk(SAY_AGGRO); - instance->SetData(TYPE_ARAN, IN_PROGRESS); + instance->SetBossState(DATA_ARAN, IN_PROGRESS); instance->HandleGameObject(instance->GetGuidData(DATA_GO_LIBRARY_DOOR), false); } diff --git a/src/server/scripts/EasternKingdoms/Karazhan/boss_terestian_illhoof.cpp b/src/server/scripts/EasternKingdoms/Karazhan/boss_terestian_illhoof.cpp index 7bc835dcced..2e33f0933e3 100644 --- a/src/server/scripts/EasternKingdoms/Karazhan/boss_terestian_illhoof.cpp +++ b/src/server/scripts/EasternKingdoms/Karazhan/boss_terestian_illhoof.cpp @@ -61,7 +61,6 @@ enum Creatures NPC_DEMONCHAINS = 17248, NPC_FIENDISHIMP = 17267, NPC_PORTAL = 17265, - NPC_KILREK = 17229 }; @@ -316,7 +315,7 @@ public: Initialize(); - instance->SetData(TYPE_TERESTIAN, NOT_STARTED); + instance->SetBossState(DATA_TERESTIAN, NOT_STARTED); me->RemoveAurasDueToSpell(SPELL_BROKEN_PACT); @@ -371,7 +370,7 @@ public: Talk(SAY_DEATH); - instance->SetData(TYPE_TERESTIAN, DONE); + instance->SetBossState(DATA_TERESTIAN, DONE); } void UpdateAI(uint32 diff) override diff --git a/src/server/scripts/EasternKingdoms/Karazhan/bosses_opera.cpp b/src/server/scripts/EasternKingdoms/Karazhan/bosses_opera.cpp index d4d0e6fa70d..0f6913b7ebc 100644 --- a/src/server/scripts/EasternKingdoms/Karazhan/bosses_opera.cpp +++ b/src/server/scripts/EasternKingdoms/Karazhan/bosses_opera.cpp @@ -708,13 +708,7 @@ public: void JustDied(Unit* /*killer*/) override { Talk(SAY_CRONE_DEATH); - - instance->SetData(TYPE_OPERA, DONE); - instance->HandleGameObject(instance->GetGuidData(DATA_GO_STAGEDOORLEFT), true); - instance->HandleGameObject(instance->GetGuidData(DATA_GO_STAGEDOORRIGHT), true); - - if (GameObject* pSideEntrance = instance->instance->GetGameObject(instance->GetGuidData(DATA_GO_SIDE_ENTRANCE_DOOR))) - pSideEntrance->RemoveFlag(GAMEOBJECT_FLAGS, GO_FLAG_LOCKED); + instance->SetBossState(DATA_OPERA_PERFORMANCE, DONE); } void UpdateAI(uint32 diff) override @@ -908,13 +902,7 @@ public: void JustDied(Unit* /*killer*/) override { DoPlaySoundToSet(me, SOUND_WOLF_DEATH); - - instance->SetData(TYPE_OPERA, DONE); - instance->HandleGameObject(instance->GetGuidData(DATA_GO_STAGEDOORLEFT), true); - instance->HandleGameObject(instance->GetGuidData(DATA_GO_STAGEDOORRIGHT), true); - - if (GameObject* pSideEntrance = instance->instance->GetGameObject(instance->GetGuidData(DATA_GO_SIDE_ENTRANCE_DOOR))) - pSideEntrance->RemoveFlag(GAMEOBJECT_FLAGS, GO_FLAG_LOCKED); + instance->SetBossState(DATA_OPERA_PERFORMANCE, DONE); } void UpdateAI(uint32 diff) override @@ -1158,12 +1146,7 @@ public: void JustDied(Unit* /*killer*/) override { Talk(SAY_JULIANNE_DEATH02); - - instance->SetData(TYPE_OPERA, DONE); - instance->HandleGameObject(instance->GetGuidData(DATA_GO_STAGEDOORLEFT), true); - instance->HandleGameObject(instance->GetGuidData(DATA_GO_STAGEDOORRIGHT), true); - if (GameObject* pSideEntrance = instance->instance->GetGameObject(instance->GetGuidData(DATA_GO_SIDE_ENTRANCE_DOOR))) - pSideEntrance->RemoveFlag(GAMEOBJECT_FLAGS, GO_FLAG_LOCKED); + instance->SetBossState(DATA_OPERA_PERFORMANCE, DONE); } void KilledUnit(Unit* /*victim*/) override @@ -1316,13 +1299,7 @@ public: void JustDied(Unit* /*killer*/) override { Talk(SAY_ROMULO_DEATH); - - instance->SetData(TYPE_OPERA, DONE); - instance->HandleGameObject(instance->GetGuidData(DATA_GO_STAGEDOORLEFT), true); - instance->HandleGameObject(instance->GetGuidData(DATA_GO_STAGEDOORRIGHT), true); - - if (GameObject* pSideEntrance = instance->instance->GetGameObject(instance->GetGuidData(DATA_GO_SIDE_ENTRANCE_DOOR))) - pSideEntrance->RemoveFlag(GAMEOBJECT_FLAGS, GO_FLAG_LOCKED); + instance->SetBossState(DATA_OPERA_PERFORMANCE, DONE); } void KilledUnit(Unit* /*victim*/) override diff --git a/src/server/scripts/EasternKingdoms/Karazhan/instance_karazhan.cpp b/src/server/scripts/EasternKingdoms/Karazhan/instance_karazhan.cpp index b23b9e645d0..ad403e6aeed 100644 --- a/src/server/scripts/EasternKingdoms/Karazhan/instance_karazhan.cpp +++ b/src/server/scripts/EasternKingdoms/Karazhan/instance_karazhan.cpp @@ -27,8 +27,6 @@ EndScriptData */ #include "InstanceScript.h" #include "karazhan.h" -#define MAX_ENCOUNTER 12 - /* 0 - Attumen + Midnight (optional) 1 - Moroes @@ -44,6 +42,13 @@ EndScriptData */ 11 - Nightbane */ +const Position OptionalSpawn[] = +{ + { -10960.981445f, -1940.138428f, 46.178097f, 4.12f }, // Hyakiss the Lurker + { -10945.769531f, -2040.153320f, 49.474438f, 0.077f }, // Shadikith the Glider + { -10899.903320f, -2085.573730f, 49.474449f, 1.38f } // Rokad the Ravager +}; + class instance_karazhan : public InstanceMapScript { public: @@ -59,150 +64,169 @@ public: instance_karazhan_InstanceMapScript(Map* map) : InstanceScript(map) { SetHeaders(DataHeader); - memset(&m_auiEncounter, 0, sizeof(m_auiEncounter)); + SetBossNumber(EncounterCount); // 1 - OZ, 2 - HOOD, 3 - RAJ, this never gets altered. - m_uiOperaEvent = urand(1, 3); - m_uiOzDeathCount = 0; + OperaEvent = urand(EVENT_OZ, EVENT_RAJ); + OzDeathCount = 0; + OptionalBossCount = 0; } - uint32 m_auiEncounter[MAX_ENCOUNTER]; - std::string strSaveData; - - uint32 m_uiOperaEvent; - uint32 m_uiOzDeathCount; - - ObjectGuid m_uiCurtainGUID; - ObjectGuid m_uiStageDoorLeftGUID; - ObjectGuid m_uiStageDoorRightGUID; - ObjectGuid m_uiKilrekGUID; - ObjectGuid m_uiTerestianGUID; - ObjectGuid m_uiMoroesGUID; - ObjectGuid m_uiLibraryDoor; // Door at Shade of Aran - ObjectGuid m_uiMassiveDoor; // Door at Netherspite - ObjectGuid m_uiSideEntranceDoor; // Side Entrance - ObjectGuid m_uiGamesmansDoor; // Door before Chess - ObjectGuid m_uiGamesmansExitDoor; // Door after Chess - ObjectGuid m_uiNetherspaceDoor; // Door at Malchezaar - ObjectGuid MastersTerraceDoor[2]; - ObjectGuid ImageGUID; - ObjectGuid DustCoveredChest; - - bool IsEncounterInProgress() const override + void OnCreatureCreate(Creature* creature) override { - for (uint8 i = 0; i < MAX_ENCOUNTER; ++i) - if (m_auiEncounter[i] == IN_PROGRESS) - return true; - - return false; + switch (creature->GetEntry()) + { + case NPC_KILREK: + KilrekGUID = creature->GetGUID(); + break; + case NPC_TERESTIAN_ILLHOOF: + TerestianGUID = creature->GetGUID(); + break; + case NPC_MOROES: + MoroesGUID = creature->GetGUID(); + break; + } } - void OnCreatureCreate(Creature* creature) override + void OnUnitDeath(Unit* unit) override { + Creature* creature = unit->ToCreature(); + if (!creature) + return; + switch (creature->GetEntry()) { - case 17229: m_uiKilrekGUID = creature->GetGUID(); break; - case 15688: m_uiTerestianGUID = creature->GetGUID(); break; - case 15687: m_uiMoroesGUID = creature->GetGUID(); break; + case NPC_COLDMIST_WIDOW: + case NPC_COLDMIST_STALKER: + case NPC_SHADOWBAT: + case NPC_VAMPIRIC_SHADOWBAT: + case NPC_GREATER_SHADOWBAT: + case NPC_PHASE_HOUND: + case NPC_DREADBEAST: + case NPC_SHADOWBEAST: + if (GetBossState(DATA_OPTIONAL_BOSS) == TO_BE_DECIDED) + { + ++OptionalBossCount; + if (OptionalBossCount == OPTIONAL_BOSS_REQUIRED_DEATH_COUNT) + { + switch (urand(NPC_HYAKISS_THE_LURKER, NPC_ROKAD_THE_RAVAGER)) + { + case NPC_HYAKISS_THE_LURKER: + instance->SummonCreature(NPC_HYAKISS_THE_LURKER, OptionalSpawn[0]); + break; + case NPC_SHADIKITH_THE_GLIDER: + instance->SummonCreature(NPC_SHADIKITH_THE_GLIDER, OptionalSpawn[1]); + break; + case NPC_ROKAD_THE_RAVAGER: + instance->SummonCreature(NPC_ROKAD_THE_RAVAGER, OptionalSpawn[2]); + break; + } + } + } + break; + default: + break; } } - void SetData(uint32 type, uint32 uiData) override + void SetData(uint32 type, uint32 data) override { switch (type) { - case TYPE_ATTUMEN: m_auiEncounter[0] = uiData; break; - case TYPE_MOROES: - if (m_auiEncounter[1] == DONE) - break; - m_auiEncounter[1] = uiData; + case DATA_OPERA_OZ_DEATHCOUNT: + if (data == SPECIAL) + ++OzDeathCount; + else if (data == IN_PROGRESS) + OzDeathCount = 0; break; - case TYPE_MAIDEN: m_auiEncounter[2] = uiData; break; - case TYPE_OPTIONAL_BOSS: m_auiEncounter[3] = uiData; break; - case TYPE_OPERA: - m_auiEncounter[4] = uiData; - if (uiData == DONE) + } + } + + bool SetBossState(uint32 type, EncounterState state) override + { + if (!InstanceScript::SetBossState(type, state)) + return false; + + switch (type) + { + case DATA_OPERA_PERFORMANCE: + if (state == DONE) + { + HandleGameObject(StageDoorLeftGUID, true); + HandleGameObject(StageDoorRightGUID, true); + if (GameObject* sideEntrance = instance->GetGameObject(SideEntranceDoor)) + sideEntrance->RemoveFlag(GAMEOBJECT_FLAGS, GO_FLAG_LOCKED); UpdateEncounterState(ENCOUNTER_CREDIT_KILL_CREATURE, 16812, NULL); + } break; - case TYPE_CURATOR: m_auiEncounter[5] = uiData; break; - case TYPE_ARAN: m_auiEncounter[6] = uiData; break; - case TYPE_TERESTIAN: m_auiEncounter[7] = uiData; break; - case TYPE_NETHERSPITE: m_auiEncounter[8] = uiData; break; - case TYPE_CHESS: - if (uiData == DONE) + case DATA_CHESS: + if (state == DONE) DoRespawnGameObject(DustCoveredChest, DAY); - m_auiEncounter[9] = uiData; break; - case TYPE_MALCHEZZAR: m_auiEncounter[10] = uiData; break; - case TYPE_NIGHTBANE: - if (m_auiEncounter[11] != DONE) - m_auiEncounter[11] = uiData; - break; - case DATA_OPERA_OZ_DEATHCOUNT: - if (uiData == SPECIAL) - ++m_uiOzDeathCount; - else if (uiData == IN_PROGRESS) - m_uiOzDeathCount = 0; + default: break; } - if (uiData == DONE) - { - OUT_SAVE_INST_DATA; - - std::ostringstream saveStream; - saveStream << m_auiEncounter[0] << ' ' << m_auiEncounter[1] << ' ' << m_auiEncounter[2] << ' ' - << m_auiEncounter[3] << ' ' << m_auiEncounter[4] << ' ' << m_auiEncounter[5] << ' ' << m_auiEncounter[6] << ' ' - << m_auiEncounter[7] << ' ' << m_auiEncounter[8] << ' ' << m_auiEncounter[9] << ' ' << m_auiEncounter[10] << ' ' << m_auiEncounter[11]; - - strSaveData = saveStream.str(); - - SaveToDB(); - OUT_SAVE_INST_DATA_COMPLETE; - } + return true; } - void SetGuidData(uint32 identifier, ObjectGuid data) override + void SetGuidData(uint32 type, ObjectGuid data) override { - switch (identifier) - { - case DATA_IMAGE_OF_MEDIVH: ImageGUID = data; - } + if (type == DATA_IMAGE_OF_MEDIVH) + ImageGUID = data; } void OnGameObjectCreate(GameObject* go) override { switch (go->GetEntry()) { - case 183932: m_uiCurtainGUID = go->GetGUID(); break; - case 184278: - m_uiStageDoorLeftGUID = go->GetGUID(); - if (m_auiEncounter[4] == DONE) + case GO_STAGE_CURTAIN: + CurtainGUID = go->GetGUID(); + break; + case GO_STAGE_DOOR_LEFT: + StageDoorLeftGUID = go->GetGUID(); + if (GetBossState(DATA_OPERA_PERFORMANCE) == DONE) go->SetGoState(GO_STATE_ACTIVE); break; - case 184279: - m_uiStageDoorRightGUID = go->GetGUID(); - if (m_auiEncounter[4] == DONE) + case GO_STAGE_DOOR_RIGHT: + StageDoorRightGUID = go->GetGUID(); + if (GetBossState(DATA_OPERA_PERFORMANCE) == DONE) go->SetGoState(GO_STATE_ACTIVE); break; - case 184517: m_uiLibraryDoor = go->GetGUID(); break; - case 185521: m_uiMassiveDoor = go->GetGUID(); break; - case 184276: m_uiGamesmansDoor = go->GetGUID(); break; - case 184277: m_uiGamesmansExitDoor = go->GetGUID(); break; - case 185134: m_uiNetherspaceDoor = go->GetGUID(); break; - case 184274: MastersTerraceDoor[0] = go->GetGUID(); break; - case 184280: MastersTerraceDoor[1] = go->GetGUID(); break; - case 184275: - m_uiSideEntranceDoor = go->GetGUID(); - if (m_auiEncounter[4] == DONE) + case GO_PRIVATE_LIBRARY_DOOR: + LibraryDoor = go->GetGUID(); + break; + case GO_MASSIVE_DOOR: + MassiveDoor = go->GetGUID(); + break; + case GO_GAMESMAN_HALL_DOOR: + GamesmansDoor = go->GetGUID(); + break; + case GO_GAMESMAN_HALL_EXIT_DOOR: + GamesmansExitDoor = go->GetGUID(); + break; + case GO_NETHERSPACE_DOOR: + NetherspaceDoor = go->GetGUID(); + break; + case GO_MASTERS_TERRACE_DOOR: + MastersTerraceDoor[0] = go->GetGUID(); + break; + case GO_MASTERS_TERRACE_DOOR2: + MastersTerraceDoor[1] = go->GetGUID(); + break; + case GO_SIDE_ENTRANCE_DOOR: + SideEntranceDoor = go->GetGUID(); + if (GetBossState(DATA_OPERA_PERFORMANCE) == DONE) go->SetFlag(GAMEOBJECT_FLAGS, GO_FLAG_LOCKED); else go->RemoveFlag(GAMEOBJECT_FLAGS, GO_FLAG_LOCKED); break; - case 185119: DustCoveredChest = go->GetGUID(); break; + case GO_DUST_COVERED_CHEST: + DustCoveredChest = go->GetGUID(); + break; } - switch (m_uiOperaEvent) + switch (OperaEvent) { /// @todo Set Object visibilities for Opera based on performance case EVENT_OZ: @@ -216,77 +240,77 @@ public: } } - std::string GetSaveData() override + uint32 GetData(uint32 type) const override { - return strSaveData; - } - - uint32 GetData(uint32 uiData) const override - { - switch (uiData) + switch (type) { - case TYPE_ATTUMEN: return m_auiEncounter[0]; - case TYPE_MOROES: return m_auiEncounter[1]; - case TYPE_MAIDEN: return m_auiEncounter[2]; - case TYPE_OPTIONAL_BOSS: return m_auiEncounter[3]; - case TYPE_OPERA: return m_auiEncounter[4]; - case TYPE_CURATOR: return m_auiEncounter[5]; - case TYPE_ARAN: return m_auiEncounter[6]; - case TYPE_TERESTIAN: return m_auiEncounter[7]; - case TYPE_NETHERSPITE: return m_auiEncounter[8]; - case TYPE_CHESS: return m_auiEncounter[9]; - case TYPE_MALCHEZZAR: return m_auiEncounter[10]; - case TYPE_NIGHTBANE: return m_auiEncounter[11]; - case DATA_OPERA_PERFORMANCE: return m_uiOperaEvent; - case DATA_OPERA_OZ_DEATHCOUNT: return m_uiOzDeathCount; + case DATA_OPERA_PERFORMANCE: + return OperaEvent; + case DATA_OPERA_OZ_DEATHCOUNT: + return OzDeathCount; } return 0; } - ObjectGuid GetGuidData(uint32 uiData) const override + ObjectGuid GetGuidData(uint32 type) const override { - switch (uiData) + switch (type) { - case DATA_KILREK: return m_uiKilrekGUID; - case DATA_TERESTIAN: return m_uiTerestianGUID; - case DATA_MOROES: return m_uiMoroesGUID; - case DATA_GO_STAGEDOORLEFT: return m_uiStageDoorLeftGUID; - case DATA_GO_STAGEDOORRIGHT: return m_uiStageDoorRightGUID; - case DATA_GO_CURTAINS: return m_uiCurtainGUID; - case DATA_GO_LIBRARY_DOOR: return m_uiLibraryDoor; - case DATA_GO_MASSIVE_DOOR: return m_uiMassiveDoor; - case DATA_GO_SIDE_ENTRANCE_DOOR: return m_uiSideEntranceDoor; - case DATA_GO_GAME_DOOR: return m_uiGamesmansDoor; - case DATA_GO_GAME_EXIT_DOOR: return m_uiGamesmansExitDoor; - case DATA_GO_NETHER_DOOR: return m_uiNetherspaceDoor; - case DATA_MASTERS_TERRACE_DOOR_1: return MastersTerraceDoor[0]; - case DATA_MASTERS_TERRACE_DOOR_2: return MastersTerraceDoor[1]; - case DATA_IMAGE_OF_MEDIVH: return ImageGUID; + case DATA_KILREK: + return KilrekGUID; + case DATA_TERESTIAN: + return TerestianGUID; + case DATA_MOROES: + return MoroesGUID; + case DATA_GO_STAGEDOORLEFT: + return StageDoorLeftGUID; + case DATA_GO_STAGEDOORRIGHT: + return StageDoorRightGUID; + case DATA_GO_CURTAINS: + return CurtainGUID; + case DATA_GO_LIBRARY_DOOR: + return LibraryDoor; + case DATA_GO_MASSIVE_DOOR: + return MassiveDoor; + case DATA_GO_SIDE_ENTRANCE_DOOR: + return SideEntranceDoor; + case DATA_GO_GAME_DOOR: + return GamesmansDoor; + case DATA_GO_GAME_EXIT_DOOR: + return GamesmansExitDoor; + case DATA_GO_NETHER_DOOR: + return NetherspaceDoor; + case DATA_MASTERS_TERRACE_DOOR_1: + return MastersTerraceDoor[0]; + case DATA_MASTERS_TERRACE_DOOR_2: + return MastersTerraceDoor[1]; + case DATA_IMAGE_OF_MEDIVH: + return ImageGUID; } return ObjectGuid::Empty; } - void Load(char const* chrIn) override - { - if (!chrIn) - { - OUT_LOAD_INST_DATA_FAIL; - return; - } - - OUT_LOAD_INST_DATA(chrIn); - std::istringstream loadStream(chrIn); - - loadStream >> m_auiEncounter[0] >> m_auiEncounter[1] >> m_auiEncounter[2] >> m_auiEncounter[3] - >> m_auiEncounter[4] >> m_auiEncounter[5] >> m_auiEncounter[6] >> m_auiEncounter[7] - >> m_auiEncounter[8] >> m_auiEncounter[9] >> m_auiEncounter[10] >> m_auiEncounter[11]; - for (uint8 i = 0; i < MAX_ENCOUNTER; ++i) - if (m_auiEncounter[i] == IN_PROGRESS) // Do not load an encounter as "In Progress" - reset it instead. - m_auiEncounter[i] = NOT_STARTED; - OUT_LOAD_INST_DATA_COMPLETE; - } + private: + uint32 OperaEvent; + uint32 OzDeathCount; + uint32 OptionalBossCount; + ObjectGuid CurtainGUID; + ObjectGuid StageDoorLeftGUID; + ObjectGuid StageDoorRightGUID; + ObjectGuid KilrekGUID; + ObjectGuid TerestianGUID; + ObjectGuid MoroesGUID; + ObjectGuid LibraryDoor; // Door at Shade of Aran + ObjectGuid MassiveDoor; // Door at Netherspite + ObjectGuid SideEntranceDoor; // Side Entrance + ObjectGuid GamesmansDoor; // Door before Chess + ObjectGuid GamesmansExitDoor; // Door after Chess + ObjectGuid NetherspaceDoor; // Door at Malchezaar + ObjectGuid MastersTerraceDoor[2]; + ObjectGuid ImageGUID; + ObjectGuid DustCoveredChest; }; }; diff --git a/src/server/scripts/EasternKingdoms/Karazhan/karazhan.cpp b/src/server/scripts/EasternKingdoms/Karazhan/karazhan.cpp index aa2da8cc391..4aef3c8d4a3 100644 --- a/src/server/scripts/EasternKingdoms/Karazhan/karazhan.cpp +++ b/src/server/scripts/EasternKingdoms/Karazhan/karazhan.cpp @@ -168,7 +168,7 @@ public: void StartEvent() { - instance->SetData(TYPE_OPERA, IN_PROGRESS); + instance->SetBossState(DATA_OPERA_PERFORMANCE, IN_PROGRESS); //resets count for this event, in case earlier failed if (m_uiEventId == EVENT_OZ) @@ -377,7 +377,7 @@ public: if (InstanceScript* instance = creature->GetInstanceScript()) { // Check for death of Moroes and if opera event is not done already - if (instance->GetData(TYPE_MOROES) == DONE && instance->GetData(TYPE_OPERA) != DONE) + if (instance->GetBossState(DATA_MOROES) == DONE && instance->GetBossState(DATA_OPERA_PERFORMANCE) != DONE) { player->ADD_GOSSIP_ITEM(GOSSIP_ICON_CHAT, OZ_GOSSIP1, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 1); diff --git a/src/server/scripts/EasternKingdoms/Karazhan/karazhan.h b/src/server/scripts/EasternKingdoms/Karazhan/karazhan.h index db68484c4a8..05de9e43a91 100644 --- a/src/server/scripts/EasternKingdoms/Karazhan/karazhan.h +++ b/src/server/scripts/EasternKingdoms/Karazhan/karazhan.h @@ -21,27 +21,26 @@ #define DataHeader "KZ" +uint32 const EncounterCount = 12; + enum DataTypes { - TYPE_ATTUMEN = 1, - TYPE_MOROES = 2, - TYPE_MAIDEN = 3, - TYPE_OPTIONAL_BOSS = 4, - TYPE_OPERA = 5, - TYPE_CURATOR = 6, - TYPE_ARAN = 7, - TYPE_TERESTIAN = 8, - TYPE_NETHERSPITE = 9, - TYPE_CHESS = 10, - TYPE_MALCHEZZAR = 11, - TYPE_NIGHTBANE = 12, + DATA_ATTUMEN = 0, + DATA_MOROES = 1, + DATA_MAIDEN_OF_VIRTUE = 2, + DATA_OPTIONAL_BOSS = 3, + DATA_OPERA_PERFORMANCE = 4, + DATA_CURATOR = 5, + DATA_ARAN = 6, + DATA_TERESTIAN = 7, + DATA_NETHERSPITE = 8, + DATA_CHESS = 9, + DATA_MALCHEZZAR = 10, + DATA_NIGHTBANE = 11, - DATA_OPERA_PERFORMANCE = 13, DATA_OPERA_OZ_DEATHCOUNT = 14, DATA_KILREK = 15, - DATA_TERESTIAN = 16, - DATA_MOROES = 17, DATA_GO_CURTAINS = 18, DATA_GO_STAGEDOORLEFT = 19, DATA_GO_STAGEDOORRIGHT = 20, @@ -64,4 +63,45 @@ enum OperaEvents EVENT_RAJ = 3 }; +enum MiscCreatures +{ + NPC_HYAKISS_THE_LURKER = 16179, + NPC_ROKAD_THE_RAVAGER = 16181, + NPC_SHADIKITH_THE_GLIDER = 16180, + NPC_TERESTIAN_ILLHOOF = 15688, + NPC_MOROES = 15687, + + // Trash + NPC_COLDMIST_WIDOW = 16171, + NPC_COLDMIST_STALKER = 16170, + NPC_SHADOWBAT = 16173, + NPC_VAMPIRIC_SHADOWBAT = 16175, + NPC_GREATER_SHADOWBAT = 16174, + NPC_PHASE_HOUND = 16178, + NPC_DREADBEAST = 16177, + NPC_SHADOWBEAST = 16176, + NPC_KILREK = 17229 +}; + +enum GameObjectIds +{ + GO_STAGE_CURTAIN = 183932, + GO_STAGE_DOOR_LEFT = 184278, + GO_STAGE_DOOR_RIGHT = 184279, + GO_PRIVATE_LIBRARY_DOOR = 184517, + GO_MASSIVE_DOOR = 185521, + GO_GAMESMAN_HALL_DOOR = 184276, + GO_GAMESMAN_HALL_EXIT_DOOR = 184277, + GO_NETHERSPACE_DOOR = 185134, + GO_MASTERS_TERRACE_DOOR = 184274, + GO_MASTERS_TERRACE_DOOR2 = 184280, + GO_SIDE_ENTRANCE_DOOR = 184275, + GO_DUST_COVERED_CHEST = 185119 +}; + +enum Misc +{ + OPTIONAL_BOSS_REQUIRED_DEATH_COUNT = 50 +}; + #endif diff --git a/src/server/scripts/EasternKingdoms/MagistersTerrace/instance_magisters_terrace.cpp b/src/server/scripts/EasternKingdoms/MagistersTerrace/instance_magisters_terrace.cpp index b48f0edec25..6386bb50e1a 100644 --- a/src/server/scripts/EasternKingdoms/MagistersTerrace/instance_magisters_terrace.cpp +++ b/src/server/scripts/EasternKingdoms/MagistersTerrace/instance_magisters_terrace.cpp @@ -16,8 +16,10 @@ */ #include "ScriptMgr.h" +#include "ScriptedCreature.h" #include "InstanceScript.h" #include "magisters_terrace.h" +#include "EventMap.h" /* 0 - Selin Fireheart @@ -36,6 +38,8 @@ DoorData const doorData[] = { 0, 0, DOOR_TYPE_ROOM } // END }; +Position const KalecgosSpawnPos = { 164.3747f, -397.1197f, 2.151798f, 1.66219f }; + class instance_magisters_terrace : public InstanceMapScript { public: @@ -93,6 +97,10 @@ class instance_magisters_terrace : public InstanceMapScript case NPC_DELRISSA: DelrissaGUID = creature->GetGUID(); break; + case NPC_KALECGOS: + case NPC_HUMAN_KALECGOS: + KalecgosGUID = creature->GetGUID(); + break; default: break; } @@ -139,6 +147,25 @@ class instance_magisters_terrace : public InstanceMapScript } } + void ProcessEvent(WorldObject* obj, uint32 eventId) override + { + if (eventId == EVENT_SPAWN_KALECGOS) + if (!ObjectAccessor::GetCreature(*obj, KalecgosGUID) && Events.Empty()) + Events.ScheduleEvent(EVENT_SPAWN_KALECGOS, Minutes(1)); + } + + void Update(uint32 diff) override + { + Events.Update(diff); + + if (Events.ExecuteEvent() == EVENT_SPAWN_KALECGOS) + if (Creature* kalecgos = instance->SummonCreature(NPC_KALECGOS, KalecgosSpawnPos)) + { + kalecgos->GetMotionMaster()->MovePath(PATH_KALECGOS_FLIGHT, false); + kalecgos->AI()->Talk(SAY_KALECGOS_SPAWN); + } + } + bool SetBossState(uint32 type, EncounterState state) override { if (!InstanceScript::SetBossState(type, state)) @@ -177,10 +204,12 @@ class instance_magisters_terrace : public InstanceMapScript } protected: + EventMap Events; ObjectGuid SelinGUID; ObjectGuid DelrissaGUID; ObjectGuid KaelStatue[2]; ObjectGuid EscapeOrbGUID; + ObjectGuid KalecgosGUID; uint32 DelrissaDeathCount; }; diff --git a/src/server/scripts/EasternKingdoms/MagistersTerrace/magisters_terrace.cpp b/src/server/scripts/EasternKingdoms/MagistersTerrace/magisters_terrace.cpp index e216a024468..5b90ac8ccf4 100644 --- a/src/server/scripts/EasternKingdoms/MagistersTerrace/magisters_terrace.cpp +++ b/src/server/scripts/EasternKingdoms/MagistersTerrace/magisters_terrace.cpp @@ -31,7 +31,8 @@ EndContentData */ #include "ScriptedCreature.h" #include "ScriptedGossip.h" #include "Player.h" -#include "SpellInfo.h" +#include "magisters_terrace.h" +#include "EventMap.h" /*###### ## npc_kalecgos @@ -39,30 +40,29 @@ EndContentData */ enum Spells { - SPELL_TRANSFORM_TO_KAEL = 44670, + SPELL_KALECGOS_TRANSFORM = 44670, + SPELL_TRANSFORM_VISUAL = 24085, + SPELL_CAMERA_SHAKE = 44762, SPELL_ORB_KILL_CREDIT = 46307 }; -enum Creatures +enum MovementPoints { - NPC_KAEL = 24848 //human form entry + POINT_ID_PREPARE_LANDING = 6 }; -enum Misc +enum EventIds { - POINT_ID_LAND = 1 + EVENT_KALECGOS_TRANSFORM = 1, + EVENT_KALECGOS_LANDING = 2 }; -const float afKaelLandPoint[] = {225.045f, -276.236f, -5.434f}; - #define GOSSIP_ITEM_KAEL_1 "Who are you?" #define GOSSIP_ITEM_KAEL_2 "What can we do to assist you?" #define GOSSIP_ITEM_KAEL_3 "What brings you to the Sunwell?" #define GOSSIP_ITEM_KAEL_4 "You're not alone here?" #define GOSSIP_ITEM_KAEL_5 "What would Kil'jaeden want with a mortal woman?" -// This is friendly keal that appear after used Orb. -// If we assume DB handle summon, summon appear somewhere outside the platform where Orb is class npc_kalecgos : public CreatureScript { public: @@ -115,52 +115,46 @@ public: struct npc_kalecgosAI : public ScriptedAI { - npc_kalecgosAI(Creature* creature) : ScriptedAI(creature) - { - Initialize(); - } + npc_kalecgosAI(Creature* creature) : ScriptedAI(creature) { } - void Initialize() + void MovementInform(uint32 type, uint32 pointId) override { - m_uiTransformTimer = 0; - } - - uint32 m_uiTransformTimer; - - void Reset() override - { - Initialize(); - - // we must assume he appear as dragon somewhere outside the platform of orb, and then move directly to here - if (me->GetEntry() != NPC_KAEL) - me->GetMotionMaster()->MovePoint(POINT_ID_LAND, afKaelLandPoint[0], afKaelLandPoint[1], afKaelLandPoint[2]); - } - - void MovementInform(uint32 uiType, uint32 uiPointId) override - { - if (uiType != POINT_MOTION_TYPE) + if (type != WAYPOINT_MOTION_TYPE) return; - if (uiPointId == POINT_ID_LAND) - m_uiTransformTimer = MINUTE*IN_MILLISECONDS; + if (pointId == POINT_ID_PREPARE_LANDING) + { + me->HandleEmoteCommand(EMOTE_ONESHOT_LAND); + me->SetDisableGravity(false); + me->SetHover(false); + events.ScheduleEvent(EVENT_KALECGOS_LANDING, Seconds(2)); + } } - void UpdateAI(uint32 uiDiff) override + void UpdateAI(uint32 diff) override { - if (m_uiTransformTimer) + events.Update(diff); + + switch (events.ExecuteEvent()) { - if (m_uiTransformTimer <= uiDiff) - { + case EVENT_KALECGOS_LANDING: + DoCastAOE(SPELL_CAMERA_SHAKE); + me->SetObjectScale(0.6f); + events.ScheduleEvent(EVENT_KALECGOS_TRANSFORM, Seconds(1)); + break; + case EVENT_KALECGOS_TRANSFORM: DoCast(me, SPELL_ORB_KILL_CREDIT, true); - - // Transform and update entry, now ready for quest/read gossip - DoCast(me, SPELL_TRANSFORM_TO_KAEL, false); - me->UpdateEntry(NPC_KAEL); - - m_uiTransformTimer = 0; - } else m_uiTransformTimer -= uiDiff; + DoCast(me, SPELL_TRANSFORM_VISUAL, false); + DoCast(me, SPELL_KALECGOS_TRANSFORM, false); + me->UpdateEntry(NPC_HUMAN_KALECGOS); + break; + default: + break; } } + + private: + EventMap events; }; }; diff --git a/src/server/scripts/EasternKingdoms/MagistersTerrace/magisters_terrace.h b/src/server/scripts/EasternKingdoms/MagistersTerrace/magisters_terrace.h index 917ad0eb50b..05718dfc1dd 100644 --- a/src/server/scripts/EasternKingdoms/MagistersTerrace/magisters_terrace.h +++ b/src/server/scripts/EasternKingdoms/MagistersTerrace/magisters_terrace.h @@ -42,7 +42,9 @@ enum CreatureIds { NPC_SELIN = 24723, NPC_DELRISSA = 24560, - NPC_FEL_CRYSTAL = 24722 + NPC_FEL_CRYSTAL = 24722, + NPC_KALECGOS = 24844, + NPC_HUMAN_KALECGOS = 24848 }; enum GameObjectIds @@ -57,4 +59,19 @@ enum GameObjectIds GO_ESCAPE_ORB = 188173 }; +enum InstanceEventIds +{ + EVENT_SPAWN_KALECGOS = 16547 +}; + +enum InstanceText +{ + SAY_KALECGOS_SPAWN = 0 +}; + +enum MovementData +{ + PATH_KALECGOS_FLIGHT = 248440 +}; + #endif diff --git a/src/server/scripts/EasternKingdoms/ScarletMonastery/boss_headless_horseman.cpp b/src/server/scripts/EasternKingdoms/ScarletMonastery/boss_headless_horseman.cpp index dff0a66cec0..74b300919d8 100644 --- a/src/server/scripts/EasternKingdoms/ScarletMonastery/boss_headless_horseman.cpp +++ b/src/server/scripts/EasternKingdoms/ScarletMonastery/boss_headless_horseman.cpp @@ -134,8 +134,6 @@ static char const* Text[]= "Now, know demise!" }; -#define EMOTE_LAUGHS "Headless Horseman laughs" // needs assigned to db. - class npc_wisp_invis : public CreatureScript { public: @@ -347,7 +345,6 @@ public: Creature* speaker = DoSpawnCreature(HELPER, 0, 0, 0, 0, TEMPSUMMON_TIMED_DESPAWN, 1000); if (speaker) speaker->CastSpell(speaker, SPELL_HEAD_SPEAKS, false); - me->TextEmote(EMOTE_LAUGHS); } else laugh -= diff; } @@ -724,7 +721,6 @@ public: if (laugh <= diff) { laugh = urand(11000, 22000); - me->TextEmote(EMOTE_LAUGHS); DoPlaySoundToSet(me, RandomLaugh[rand32() % 3]); } else laugh -= diff; diff --git a/src/server/scripts/EasternKingdoms/ZulAman/boss_hexlord.cpp b/src/server/scripts/EasternKingdoms/ZulAman/boss_hexlord.cpp index cc55f758a22..5ec57fc44b6 100644 --- a/src/server/scripts/EasternKingdoms/ZulAman/boss_hexlord.cpp +++ b/src/server/scripts/EasternKingdoms/ZulAman/boss_hexlord.cpp @@ -29,109 +29,104 @@ EndScriptData */ #include "SpellAuraEffects.h" #include "zulaman.h" -#define YELL_AGGRO "Da shadow gonna fall on you... " -#define SOUND_YELL_AGGRO 12041 -#define YELL_SPIRIT_BOLTS "Your soul gonna bleed!" -#define SOUND_YELL_SPIRIT_BOLTS 12047 -#define YELL_DRAIN_POWER "Darkness comin\' for you" -#define SOUND_YELL_DRAIN_POWER 12046 -#define YELL_KILL_ONE "Dis a nightmare ya don\' wake up from!" -#define SOUND_YELL_KILL_ONE 12043 -#define YELL_KILL_TWO "Azzaga choogo zinn!" -#define SOUND_YELL_KILL_TWO 12044 -#define YELL_DEATH "Dis not... da end of me..." -#define SOUND_YELL_DEATH 12051 - +enum Yells +{ + YELL_AGGRO = 0, + YELL_KILL_ONE = 1, + YELL_KILL_TWO = 2, + YELL_DRAIN_POWER = 3, + YELL_SPIRIT_BOLTS = 4, + YELL_DEATH = 5 +}; enum Creatures { - NPC_TEMP_TRIGGER = 23920 + NPC_TEMP_TRIGGER = 23920 }; enum Spells { - SPELL_SPIRIT_BOLTS = 43383, - SPELL_DRAIN_POWER = 44131, - SPELL_SIPHON_SOUL = 43501, + SPELL_SPIRIT_BOLTS = 43383, + SPELL_DRAIN_POWER = 44131, + SPELL_SIPHON_SOUL = 43501, // Druid - SPELL_DR_THORNS = 43420, - SPELL_DR_LIFEBLOOM = 43421, - SPELL_DR_MOONFIRE = 43545, + SPELL_DR_THORNS = 43420, + SPELL_DR_LIFEBLOOM = 43421, + SPELL_DR_MOONFIRE = 43545, // Hunter - SPELL_HU_EXPLOSIVE_TRAP = 43444, - SPELL_HU_FREEZING_TRAP = 43447, - SPELL_HU_SNAKE_TRAP = 43449, + SPELL_HU_EXPLOSIVE_TRAP = 43444, + SPELL_HU_FREEZING_TRAP = 43447, + SPELL_HU_SNAKE_TRAP = 43449, // Mage - SPELL_MG_FIREBALL = 41383, - SPELL_MG_FROST_NOVA = 43426, - SPELL_MG_ICE_LANCE = 43427, - SPELL_MG_FROSTBOLT = 43428, + SPELL_MG_FIREBALL = 41383, + SPELL_MG_FROST_NOVA = 43426, + SPELL_MG_ICE_LANCE = 43427, + SPELL_MG_FROSTBOLT = 43428, // Paladin - SPELL_PA_CONSECRATION = 43429, - SPELL_PA_AVENGING_WRATH = 43430, - SPELL_PA_HOLY_LIGHT = 43451, + SPELL_PA_CONSECRATION = 43429, + SPELL_PA_AVENGING_WRATH = 43430, + SPELL_PA_HOLY_LIGHT = 43451, // Priest - SPELL_PR_HEAL = 41372, - SPELL_PR_MIND_BLAST = 41374, - SPELL_PR_SW_DEATH = 41375, - SPELL_PR_PSYCHIC_SCREAM = 43432, - SPELL_PR_MIND_CONTROL = 43550, - SPELL_PR_PAIN_SUPP = 44416, + SPELL_PR_HEAL = 41372, + SPELL_PR_MIND_BLAST = 41374, + SPELL_PR_SW_DEATH = 41375, + SPELL_PR_PSYCHIC_SCREAM = 43432, + SPELL_PR_MIND_CONTROL = 43550, + SPELL_PR_PAIN_SUPP = 44416, // Rogue - SPELL_RO_BLIND = 43433, - SPELL_RO_SLICE_DICE = 43457, - SPELL_RO_WOUND_POISON = 43461, + SPELL_RO_BLIND = 43433, + SPELL_RO_SLICE_DICE = 43457, + SPELL_RO_WOUND_POISON = 43461, // Shaman - SPELL_SH_CHAIN_LIGHT = 43435, - SPELL_SH_FIRE_NOVA = 43436, - SPELL_SH_HEALING_WAVE = 43548, + SPELL_SH_CHAIN_LIGHT = 43435, + SPELL_SH_FIRE_NOVA = 43436, + SPELL_SH_HEALING_WAVE = 43548, // Warlock - SPELL_WL_CURSE_OF_DOOM = 43439, - SPELL_WL_RAIN_OF_FIRE = 43440, - SPELL_WL_UNSTABLE_AFFL = 43522, - SPELL_WL_UNSTABLE_AFFL_DISPEL = 43523, + SPELL_WL_CURSE_OF_DOOM = 43439, + SPELL_WL_RAIN_OF_FIRE = 43440, + SPELL_WL_UNSTABLE_AFFL = 43522, + SPELL_WL_UNSTABLE_AFFL_DISPEL = 43523, // Warrior - SPELL_WR_MORTAL_STRIKE = 43441, - SPELL_WR_WHIRLWIND = 43442, - SPELL_WR_SPELL_REFLECT = 43443, + SPELL_WR_MORTAL_STRIKE = 43441, + SPELL_WR_WHIRLWIND = 43442, + SPELL_WR_SPELL_REFLECT = 43443, // Thurg - SPELL_BLOODLUST = 43578, - SPELL_CLEAVE = 15496, + SPELL_BLOODLUST = 43578, + SPELL_CLEAVE = 15496, // Gazakroth - SPELL_FIREBOLT = 43584, + SPELL_FIREBOLT = 43584, // Alyson Antille - SPELL_FLASH_HEAL = 43575, - SPELL_DISPEL_MAGIC = 43577, + SPELL_FLASH_HEAL = 43575, + SPELL_DISPEL_MAGIC = 43577, // Lord Raadan - SPELL_FLAME_BREATH = 43582, - SPELL_THUNDERCLAP = 43583, + SPELL_FLAME_BREATH = 43582, + SPELL_THUNDERCLAP = 43583, // Darkheart - SPELL_PSYCHIC_WAIL = 43590, + SPELL_PSYCHIC_WAIL = 43590, // Slither - SPELL_VENOM_SPIT = 43579, + SPELL_VENOM_SPIT = 43579, // Fenstalker - SPELL_VOLATILE_INFECTION = 43586, + SPELL_VOLATILE_INFECTION = 43586, // Koragg - SPELL_COLD_STARE = 43593, - SPELL_MIGHTY_BLOW = 43592 - + SPELL_COLD_STARE = 43593, + SPELL_MIGHTY_BLOW = 43592 }; #define ORIENT 1.5696f @@ -306,8 +301,7 @@ class boss_hexlord_malacrass : public CreatureScript instance->SetData(DATA_HEXLORDEVENT, IN_PROGRESS); DoZoneInCombat(); - me->Yell(YELL_AGGRO, LANG_UNIVERSAL); - DoPlaySoundToSet(me, SOUND_YELL_AGGRO); + Talk(YELL_AGGRO); for (uint8 i = 0; i < 4; ++i) { @@ -327,12 +321,10 @@ class boss_hexlord_malacrass : public CreatureScript switch (urand(0, 1)) { case 0: - me->Yell(YELL_KILL_ONE, LANG_UNIVERSAL); - DoPlaySoundToSet(me, SOUND_YELL_KILL_ONE); + Talk(YELL_KILL_ONE); break; case 1: - me->Yell(YELL_KILL_TWO, LANG_UNIVERSAL); - DoPlaySoundToSet(me, SOUND_YELL_KILL_TWO); + Talk(YELL_KILL_TWO); break; } } @@ -341,8 +333,7 @@ class boss_hexlord_malacrass : public CreatureScript { instance->SetData(DATA_HEXLORDEVENT, DONE); - me->Yell(YELL_DEATH, LANG_UNIVERSAL); - DoPlaySoundToSet(me, SOUND_YELL_DEATH); + Talk(YELL_DEATH); for (uint8 i = 0; i < 4; ++i) { @@ -415,8 +406,7 @@ class boss_hexlord_malacrass : public CreatureScript if (DrainPower_Timer <= diff) { DoCast(me, SPELL_DRAIN_POWER, true); - me->Yell(YELL_DRAIN_POWER, LANG_UNIVERSAL); - DoPlaySoundToSet(me, SOUND_YELL_DRAIN_POWER); + Talk(YELL_DRAIN_POWER); DrainPower_Timer = urand(40000, 55000); // must cast in 60 sec, or buff/debuff will disappear } else DrainPower_Timer -= diff; @@ -427,8 +417,7 @@ class boss_hexlord_malacrass : public CreatureScript else { DoCast(me, SPELL_SPIRIT_BOLTS, false); - me->Yell(YELL_SPIRIT_BOLTS, LANG_UNIVERSAL); - DoPlaySoundToSet(me, SOUND_YELL_SPIRIT_BOLTS); + Talk(YELL_SPIRIT_BOLTS); SpiritBolts_Timer = 40000; SiphonSoul_Timer = 10000; // ready to drain PlayerAbility_Timer = 99999; diff --git a/src/server/scripts/EasternKingdoms/ZulAman/boss_nalorakk.cpp b/src/server/scripts/EasternKingdoms/ZulAman/boss_nalorakk.cpp index 37505a8b74d..0407cb6cd7c 100644 --- a/src/server/scripts/EasternKingdoms/ZulAman/boss_nalorakk.cpp +++ b/src/server/scripts/EasternKingdoms/ZulAman/boss_nalorakk.cpp @@ -30,21 +30,41 @@ EndScriptData */ #include "GridNotifiersImpl.h" #include "CellImpl.h" -enum Spells +enum Yells { - SPELL_BERSERK = 45078, + YELL_NALORAKK_WAVE1 = 0, + YELL_NALORAKK_WAVE2 = 1, + YELL_NALORAKK_WAVE3 = 2, + YELL_NALORAKK_WAVE4 = 3, + YELL_AGGRO = 4, + YELL_SURGE = 5, + YELL_SHIFTEDTOBEAR = 6, + YELL_SHIFTEDTOTROLL = 7, + YELL_BERSERK = 8, + YELL_KILL_ONE = 9, + YELL_KILL_TWO = 10, + YELL_DEATH = 11 + +// Not yet implemented +// YELL_NALORAKK_EVENT1 = 12, +// YELL_NALORAKK_EVENT2 = 13 +}; +enum Spells +{ // Troll form - SPELL_BRUTALSWIPE = 42384, - SPELL_MANGLE = 42389, - SPELL_MANGLEEFFECT = 44955, - SPELL_SURGE = 42402, - SPELL_BEARFORM = 42377, + SPELL_BRUTALSWIPE = 42384, + SPELL_MANGLE = 42389, + SPELL_MANGLEEFFECT = 44955, + SPELL_SURGE = 42402, + SPELL_BEARFORM = 42377, // Bear form - SPELL_LACERATINGSLASH = 42395, - SPELL_RENDFLESH = 42397, - SPELL_DEAFENINGROAR = 42398 + SPELL_LACERATINGSLASH = 42395, + SPELL_RENDFLESH = 42397, + SPELL_DEAFENINGROAR = 42398, + + SPELL_BERSERK = 45078 }; // Trash Waves @@ -57,45 +77,9 @@ float NalorakkWay[8][3] = {-79.929f, 1395.958f, 27.31f}, {-80.072f, 1374.555f, 40.87f}, // waypoint 3 {-80.072f, 1314.398f, 40.87f}, - {-80.072f, 1295.775f, 48.60f} // waypoint 4 + {-80.072f, 1295.775f, 48.60f} // waypoint 4 }; -#define YELL_NALORAKK_WAVE1 "Get da move on, guards! It be killin' time!" -#define SOUND_NALORAKK_WAVE1 12066 -#define YELL_NALORAKK_WAVE2 "Guards, go already! Who you more afraid of, dem... or me?" -#define SOUND_NALORAKK_WAVE2 12067 -#define YELL_NALORAKK_WAVE3 "Ride now! Ride out dere and bring me back some heads!" -#define SOUND_NALORAKK_WAVE3 12068 -#define YELL_NALORAKK_WAVE4 "I be losin' me patience! Go on: make dem wish dey was never born!" -#define SOUND_NALORAKK_WAVE4 12069 - -//Unimplemented SoundIDs -/* -#define SOUND_NALORAKK_EVENT1 12078 -#define SOUND_NALORAKK_EVENT2 12079 -*/ - -//General defines -#define YELL_AGGRO "You be dead soon enough!" -#define SOUND_YELL_AGGRO 12070 -#define YELL_KILL_ONE "Mua-ha-ha! Now whatchoo got to say?" -#define SOUND_YELL_KILL_ONE 12075 -#define YELL_KILL_TWO "Da Amani gonna rule again!" -#define SOUND_YELL_KILL_TWO 12076 -#define YELL_DEATH "I... be waitin' on da udda side...." -#define SOUND_YELL_DEATH 12077 -#define YELL_BERSERK "You had your chance, now it be too late!" //Never seen this being used, so just guessing from what I hear. -#define SOUND_YELL_BERSERK 12074 -#define YELL_SURGE "I bring da pain!" -#define SOUND_YELL_SURGE 12071 - -#define YELL_SHIFTEDTOTROLL "Make way for Nalorakk!" -#define SOUND_YELL_TOTROLL 12073 - - -#define YELL_SHIFTEDTOBEAR "You call on da beast, you gonna get more dan you bargain for!" -#define SOUND_YELL_TOBEAR 12072 - class boss_nalorakk : public CreatureScript { public: @@ -227,8 +211,7 @@ class boss_nalorakk : public CreatureScript case 0: if (me->IsWithinDistInMap(who, 50)) { - me->Yell(YELL_NALORAKK_WAVE1, LANG_UNIVERSAL); - DoPlaySoundToSet(me, SOUND_NALORAKK_WAVE1); + Talk(YELL_NALORAKK_WAVE1); (*me).GetMotionMaster()->MovePoint(1, NalorakkWay[1][0], NalorakkWay[1][1], NalorakkWay[1][2]); MovePhase ++; @@ -240,8 +223,7 @@ class boss_nalorakk : public CreatureScript case 2: if (me->IsWithinDistInMap(who, 40)) { - me->Yell(YELL_NALORAKK_WAVE2, LANG_UNIVERSAL); - DoPlaySoundToSet(me, SOUND_NALORAKK_WAVE2); + Talk(YELL_NALORAKK_WAVE2); (*me).GetMotionMaster()->MovePoint(3, NalorakkWay[3][0], NalorakkWay[3][1], NalorakkWay[3][2]); MovePhase ++; @@ -253,8 +235,7 @@ class boss_nalorakk : public CreatureScript case 5: if (me->IsWithinDistInMap(who, 40)) { - me->Yell(YELL_NALORAKK_WAVE3, LANG_UNIVERSAL); - DoPlaySoundToSet(me, SOUND_NALORAKK_WAVE3); + Talk(YELL_NALORAKK_WAVE3); (*me).GetMotionMaster()->MovePoint(6, NalorakkWay[6][0], NalorakkWay[6][1], NalorakkWay[6][2]); MovePhase ++; @@ -268,8 +249,7 @@ class boss_nalorakk : public CreatureScript { SendAttacker(who); - me->Yell(YELL_NALORAKK_WAVE4, LANG_UNIVERSAL); - DoPlaySoundToSet(me, SOUND_NALORAKK_WAVE4); + Talk(YELL_NALORAKK_WAVE4); me->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE); me->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE); @@ -287,8 +267,7 @@ class boss_nalorakk : public CreatureScript { instance->SetData(DATA_NALORAKKEVENT, IN_PROGRESS); - me->Yell(YELL_AGGRO, LANG_UNIVERSAL); - DoPlaySoundToSet(me, SOUND_YELL_AGGRO); + Talk(YELL_AGGRO); DoZoneInCombat(); } @@ -296,8 +275,7 @@ class boss_nalorakk : public CreatureScript { instance->SetData(DATA_NALORAKKEVENT, DONE); - me->Yell(YELL_DEATH, LANG_UNIVERSAL); - DoPlaySoundToSet(me, SOUND_YELL_DEATH); + Talk(YELL_DEATH); } void KilledUnit(Unit* /*victim*/) override @@ -305,12 +283,10 @@ class boss_nalorakk : public CreatureScript switch (urand(0, 1)) { case 0: - me->Yell(YELL_KILL_ONE, LANG_UNIVERSAL); - DoPlaySoundToSet(me, SOUND_YELL_KILL_ONE); + Talk(YELL_KILL_ONE); break; case 1: - me->Yell(YELL_KILL_TWO, LANG_UNIVERSAL); - DoPlaySoundToSet(me, SOUND_YELL_KILL_TWO); + Talk(YELL_KILL_TWO); break; } } @@ -373,8 +349,7 @@ class boss_nalorakk : public CreatureScript if (Berserk_Timer <= diff) { DoCast(me, SPELL_BERSERK, true); - me->Yell(YELL_BERSERK, LANG_UNIVERSAL); - DoPlaySoundToSet(me, SOUND_YELL_BERSERK); + Talk(YELL_BERSERK); Berserk_Timer = 600000; } else Berserk_Timer -= diff; @@ -383,8 +358,7 @@ class boss_nalorakk : public CreatureScript if (inBearForm) { // me->SetUInt32Value(UNIT_VIRTUAL_ITEM_SLOT_ID + 1, 5122); - me->Yell(YELL_SHIFTEDTOTROLL, LANG_UNIVERSAL); - DoPlaySoundToSet(me, SOUND_YELL_TOTROLL); + Talk(YELL_SHIFTEDTOTROLL); me->RemoveAurasDueToSpell(SPELL_BEARFORM); Surge_Timer = urand(15000, 20000); BrutalSwipe_Timer = urand(7000, 12000); @@ -395,8 +369,7 @@ class boss_nalorakk : public CreatureScript else { // me->SetUInt32Value(UNIT_VIRTUAL_ITEM_SLOT_ID + 1, 0); - me->Yell(YELL_SHIFTEDTOBEAR, LANG_UNIVERSAL); - DoPlaySoundToSet(me, SOUND_YELL_TOBEAR); + Talk(YELL_SHIFTEDTOBEAR); DoCast(me, SPELL_BEARFORM, true); LaceratingSlash_Timer = 2000; // dur 18s RendFlesh_Timer = 3000; // dur 5s @@ -426,8 +399,7 @@ class boss_nalorakk : public CreatureScript if (Surge_Timer <= diff) { - me->Yell(YELL_SURGE, LANG_UNIVERSAL); - DoPlaySoundToSet(me, SOUND_YELL_SURGE); + Talk(YELL_SURGE); Unit* target = SelectTarget(SELECT_TARGET_RANDOM, 1, 45, true); if (target) DoCast(target, SPELL_SURGE); diff --git a/src/server/scripts/EasternKingdoms/eastern_kingdoms_script_loader.cpp b/src/server/scripts/EasternKingdoms/eastern_kingdoms_script_loader.cpp new file mode 100644 index 00000000000..8c781bb9001 --- /dev/null +++ b/src/server/scripts/EasternKingdoms/eastern_kingdoms_script_loader.cpp @@ -0,0 +1,372 @@ +/* + * Copyright (C) 2008-2016 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/>. + */ + +// This is where scripts' loading functions should be declared: +void AddSC_alterac_valley(); //Alterac Valley +void AddSC_boss_balinda(); +void AddSC_boss_drekthar(); +void AddSC_boss_galvangar(); +void AddSC_boss_vanndar(); +void AddSC_blackrock_depths(); //Blackrock Depths +void AddSC_boss_ambassador_flamelash(); +void AddSC_boss_draganthaurissan(); +void AddSC_boss_general_angerforge(); +void AddSC_boss_high_interrogator_gerstahn(); +void AddSC_boss_magmus(); +void AddSC_boss_moira_bronzebeard(); +void AddSC_boss_tomb_of_seven(); +void AddSC_instance_blackrock_depths(); +void AddSC_boss_drakkisath(); //Blackrock Spire +void AddSC_boss_halycon(); +void AddSC_boss_highlordomokk(); +void AddSC_boss_mothersmolderweb(); +void AddSC_boss_overlordwyrmthalak(); +void AddSC_boss_shadowvosh(); +void AddSC_boss_thebeast(); +void AddSC_boss_warmastervoone(); +void AddSC_boss_quatermasterzigris(); +void AddSC_boss_pyroguard_emberseer(); +void AddSC_boss_gyth(); +void AddSC_boss_rend_blackhand(); +void AddSC_boss_gizrul_the_slavener(); +void AddSC_boss_urok_doomhowl(); +void AddSC_boss_lord_valthalak(); +void AddSC_instance_blackrock_spire(); +void AddSC_boss_razorgore(); //Blackwing lair +void AddSC_boss_vaelastrasz(); +void AddSC_boss_broodlord(); +void AddSC_boss_firemaw(); +void AddSC_boss_ebonroc(); +void AddSC_boss_flamegor(); +void AddSC_boss_chromaggus(); +void AddSC_boss_nefarian(); +void AddSC_instance_blackwing_lair(); +void AddSC_deadmines(); //Deadmines +void AddSC_instance_deadmines(); +void AddSC_boss_mr_smite(); +void AddSC_gnomeregan(); //Gnomeregan +void AddSC_instance_gnomeregan(); +void AddSC_boss_attumen(); //Karazhan +void AddSC_boss_curator(); +void AddSC_boss_maiden_of_virtue(); +void AddSC_boss_shade_of_aran(); +void AddSC_boss_malchezaar(); +void AddSC_boss_terestian_illhoof(); +void AddSC_boss_moroes(); +void AddSC_bosses_opera(); +void AddSC_boss_netherspite(); +void AddSC_instance_karazhan(); +void AddSC_karazhan(); +void AddSC_boss_nightbane(); +void AddSC_boss_felblood_kaelthas(); // Magister's Terrace +void AddSC_boss_selin_fireheart(); +void AddSC_boss_vexallus(); +void AddSC_boss_priestess_delrissa(); +void AddSC_instance_magisters_terrace(); +void AddSC_magisters_terrace(); +void AddSC_boss_lucifron(); //Molten core +void AddSC_boss_magmadar(); +void AddSC_boss_gehennas(); +void AddSC_boss_garr(); +void AddSC_boss_baron_geddon(); +void AddSC_boss_shazzrah(); +void AddSC_boss_golemagg(); +void AddSC_boss_sulfuron(); +void AddSC_boss_majordomo(); +void AddSC_boss_ragnaros(); +void AddSC_instance_molten_core(); +void AddSC_instance_ragefire_chasm(); //Ragefire Chasm +void AddSC_the_scarlet_enclave(); //Scarlet Enclave +void AddSC_the_scarlet_enclave_c1(); +void AddSC_the_scarlet_enclave_c2(); +void AddSC_the_scarlet_enclave_c5(); +void AddSC_boss_arcanist_doan(); //Scarlet Monastery +void AddSC_boss_azshir_the_sleepless(); +void AddSC_boss_bloodmage_thalnos(); +void AddSC_boss_headless_horseman(); +void AddSC_boss_herod(); +void AddSC_boss_high_inquisitor_fairbanks(); +void AddSC_boss_houndmaster_loksey(); +void AddSC_boss_interrogator_vishas(); +void AddSC_boss_scorn(); +void AddSC_instance_scarlet_monastery(); +void AddSC_boss_mograine_and_whitemane(); +void AddSC_boss_darkmaster_gandling(); //Scholomance +void AddSC_boss_death_knight_darkreaver(); +void AddSC_boss_theolenkrastinov(); +void AddSC_boss_illuciabarov(); +void AddSC_boss_instructormalicia(); +void AddSC_boss_jandicebarov(); +void AddSC_boss_kormok(); +void AddSC_boss_lordalexeibarov(); +void AddSC_boss_lorekeeperpolkelt(); +void AddSC_boss_rasfrost(); +void AddSC_boss_theravenian(); +void AddSC_boss_vectus(); +void AddSC_boss_kirtonos_the_herald(); +void AddSC_instance_scholomance(); +void AddSC_shadowfang_keep(); //Shadowfang keep +void AddSC_instance_shadowfang_keep(); +void AddSC_boss_magistrate_barthilas(); //Stratholme +void AddSC_boss_maleki_the_pallid(); +void AddSC_boss_nerubenkan(); +void AddSC_boss_cannon_master_willey(); +void AddSC_boss_baroness_anastari(); +void AddSC_boss_ramstein_the_gorger(); +void AddSC_boss_timmy_the_cruel(); +void AddSC_boss_postmaster_malown(); +void AddSC_boss_baron_rivendare(); +void AddSC_boss_dathrohan_balnazzar(); +void AddSC_boss_order_of_silver_hand(); +void AddSC_instance_stratholme(); +void AddSC_stratholme(); +void AddSC_sunken_temple(); // Sunken Temple +void AddSC_instance_sunken_temple(); +void AddSC_instance_sunwell_plateau(); //Sunwell Plateau +void AddSC_boss_kalecgos(); +void AddSC_boss_brutallus(); +void AddSC_boss_felmyst(); +void AddSC_boss_eredar_twins(); +void AddSC_boss_muru(); +void AddSC_boss_kiljaeden(); +void AddSC_sunwell_plateau(); +void AddSC_boss_archaedas(); //Uldaman +void AddSC_boss_ironaya(); +void AddSC_uldaman(); +void AddSC_instance_uldaman(); +void AddSC_instance_the_stockade(); //The Stockade +void AddSC_boss_akilzon(); //Zul'Aman +void AddSC_boss_halazzi(); +void AddSC_boss_hex_lord_malacrass(); +void AddSC_boss_janalai(); +void AddSC_boss_nalorakk(); +void AddSC_boss_zuljin(); +void AddSC_instance_zulaman(); +void AddSC_zulaman(); +void AddSC_boss_jeklik(); //Zul'Gurub +void AddSC_boss_venoxis(); +void AddSC_boss_marli(); +void AddSC_boss_mandokir(); +void AddSC_boss_gahzranka(); +void AddSC_boss_thekal(); +void AddSC_boss_arlokk(); +void AddSC_boss_jindo(); +void AddSC_boss_hakkar(); +void AddSC_boss_grilek(); +void AddSC_boss_hazzarah(); +void AddSC_boss_renataki(); +void AddSC_boss_wushoolay(); +void AddSC_instance_zulgurub(); +//void AddSC_alterac_mountains(); +void AddSC_arathi_highlands(); +void AddSC_blasted_lands(); +void AddSC_burning_steppes(); +void AddSC_duskwood(); +void AddSC_eastern_plaguelands(); +void AddSC_ghostlands(); +void AddSC_hinterlands(); +void AddSC_isle_of_queldanas(); +void AddSC_loch_modan(); +void AddSC_redridge_mountains(); +void AddSC_silverpine_forest(); +void AddSC_stormwind_city(); +void AddSC_stranglethorn_vale(); +void AddSC_swamp_of_sorrows(); +void AddSC_tirisfal_glades(); +void AddSC_undercity(); +void AddSC_western_plaguelands(); +void AddSC_wetlands(); + +// The name of this function should match: +// void Add${NameOfDirectory}Scripts() +void AddEasternKingdomsScripts() +{ + AddSC_alterac_valley(); //Alterac Valley + AddSC_boss_balinda(); + AddSC_boss_drekthar(); + AddSC_boss_galvangar(); + AddSC_boss_vanndar(); + AddSC_blackrock_depths(); //Blackrock Depths + AddSC_boss_ambassador_flamelash(); + AddSC_boss_draganthaurissan(); + AddSC_boss_general_angerforge(); + AddSC_boss_high_interrogator_gerstahn(); + AddSC_boss_magmus(); + AddSC_boss_moira_bronzebeard(); + AddSC_boss_tomb_of_seven(); + AddSC_instance_blackrock_depths(); + AddSC_boss_drakkisath(); //Blackrock Spire + AddSC_boss_halycon(); + AddSC_boss_highlordomokk(); + AddSC_boss_mothersmolderweb(); + AddSC_boss_overlordwyrmthalak(); + AddSC_boss_shadowvosh(); + AddSC_boss_thebeast(); + AddSC_boss_warmastervoone(); + AddSC_boss_quatermasterzigris(); + AddSC_boss_pyroguard_emberseer(); + AddSC_boss_gyth(); + AddSC_boss_rend_blackhand(); + AddSC_boss_gizrul_the_slavener(); + AddSC_boss_urok_doomhowl(); + AddSC_boss_lord_valthalak(); + AddSC_instance_blackrock_spire(); + AddSC_boss_razorgore(); //Blackwing lair + AddSC_boss_vaelastrasz(); + AddSC_boss_broodlord(); + AddSC_boss_firemaw(); + AddSC_boss_ebonroc(); + AddSC_boss_flamegor(); + AddSC_boss_chromaggus(); + AddSC_boss_nefarian(); + AddSC_instance_blackwing_lair(); + AddSC_deadmines(); //Deadmines + AddSC_boss_mr_smite(); + AddSC_instance_deadmines(); + AddSC_gnomeregan(); //Gnomeregan + AddSC_instance_gnomeregan(); + AddSC_boss_attumen(); //Karazhan + AddSC_boss_curator(); + AddSC_boss_maiden_of_virtue(); + AddSC_boss_shade_of_aran(); + AddSC_boss_malchezaar(); + AddSC_boss_terestian_illhoof(); + AddSC_boss_moroes(); + AddSC_bosses_opera(); + AddSC_boss_netherspite(); + AddSC_instance_karazhan(); + AddSC_karazhan(); + AddSC_boss_nightbane(); + AddSC_boss_felblood_kaelthas(); // Magister's Terrace + AddSC_boss_selin_fireheart(); + AddSC_boss_vexallus(); + AddSC_boss_priestess_delrissa(); + AddSC_instance_magisters_terrace(); + AddSC_magisters_terrace(); + AddSC_boss_lucifron(); //Molten core + AddSC_boss_magmadar(); + AddSC_boss_gehennas(); + AddSC_boss_garr(); + AddSC_boss_baron_geddon(); + AddSC_boss_shazzrah(); + AddSC_boss_golemagg(); + AddSC_boss_sulfuron(); + AddSC_boss_majordomo(); + AddSC_boss_ragnaros(); + AddSC_instance_molten_core(); + AddSC_instance_ragefire_chasm(); //Ragefire Chasm + AddSC_the_scarlet_enclave(); //Scarlet Enclave + AddSC_the_scarlet_enclave_c1(); + AddSC_the_scarlet_enclave_c2(); + AddSC_the_scarlet_enclave_c5(); + AddSC_boss_arcanist_doan(); //Scarlet Monastery + AddSC_boss_azshir_the_sleepless(); + AddSC_boss_bloodmage_thalnos(); + AddSC_boss_headless_horseman(); + AddSC_boss_herod(); + AddSC_boss_high_inquisitor_fairbanks(); + AddSC_boss_houndmaster_loksey(); + AddSC_boss_interrogator_vishas(); + AddSC_boss_scorn(); + AddSC_instance_scarlet_monastery(); + AddSC_boss_mograine_and_whitemane(); + AddSC_boss_darkmaster_gandling(); //Scholomance + AddSC_boss_death_knight_darkreaver(); + AddSC_boss_theolenkrastinov(); + AddSC_boss_illuciabarov(); + AddSC_boss_instructormalicia(); + AddSC_boss_jandicebarov(); + AddSC_boss_kormok(); + AddSC_boss_lordalexeibarov(); + AddSC_boss_lorekeeperpolkelt(); + AddSC_boss_rasfrost(); + AddSC_boss_theravenian(); + AddSC_boss_vectus(); + AddSC_boss_kirtonos_the_herald(); + AddSC_instance_scholomance(); + AddSC_shadowfang_keep(); //Shadowfang keep + AddSC_instance_shadowfang_keep(); + AddSC_boss_magistrate_barthilas(); //Stratholme + AddSC_boss_maleki_the_pallid(); + AddSC_boss_nerubenkan(); + AddSC_boss_cannon_master_willey(); + AddSC_boss_baroness_anastari(); + AddSC_boss_ramstein_the_gorger(); + AddSC_boss_timmy_the_cruel(); + AddSC_boss_postmaster_malown(); + AddSC_boss_baron_rivendare(); + AddSC_boss_dathrohan_balnazzar(); + AddSC_boss_order_of_silver_hand(); + AddSC_instance_stratholme(); + AddSC_stratholme(); + AddSC_sunken_temple(); // Sunken Temple + AddSC_instance_sunken_temple(); + AddSC_instance_sunwell_plateau(); //Sunwell Plateau + AddSC_boss_kalecgos(); + AddSC_boss_brutallus(); + AddSC_boss_felmyst(); + AddSC_boss_eredar_twins(); + AddSC_boss_muru(); + AddSC_boss_kiljaeden(); + AddSC_sunwell_plateau(); + AddSC_instance_the_stockade(); //The Stockade + AddSC_boss_archaedas(); //Uldaman + AddSC_boss_ironaya(); + AddSC_uldaman(); + AddSC_instance_uldaman(); + AddSC_boss_akilzon(); //Zul'Aman + AddSC_boss_halazzi(); + AddSC_boss_hex_lord_malacrass(); + AddSC_boss_janalai(); + AddSC_boss_nalorakk(); + AddSC_boss_zuljin(); + AddSC_instance_zulaman(); + AddSC_zulaman(); + AddSC_boss_jeklik(); //Zul'Gurub + AddSC_boss_venoxis(); + AddSC_boss_marli(); + AddSC_boss_mandokir(); + AddSC_boss_gahzranka(); + AddSC_boss_thekal(); + AddSC_boss_arlokk(); + AddSC_boss_jindo(); + AddSC_boss_hakkar(); + AddSC_boss_grilek(); + AddSC_boss_hazzarah(); + AddSC_boss_renataki(); + AddSC_boss_wushoolay(); + AddSC_instance_zulgurub(); + //AddSC_alterac_mountains(); + AddSC_arathi_highlands(); + AddSC_blasted_lands(); + AddSC_burning_steppes(); + AddSC_duskwood(); + AddSC_eastern_plaguelands(); + AddSC_ghostlands(); + AddSC_hinterlands(); + AddSC_isle_of_queldanas(); + AddSC_loch_modan(); + AddSC_redridge_mountains(); + AddSC_silverpine_forest(); + AddSC_stormwind_city(); + AddSC_stranglethorn_vale(); + AddSC_swamp_of_sorrows(); + AddSC_tirisfal_glades(); + AddSC_undercity(); + AddSC_western_plaguelands(); + AddSC_wetlands(); +} diff --git a/src/server/scripts/EasternKingdoms/zone_burning_steppes.cpp b/src/server/scripts/EasternKingdoms/zone_burning_steppes.cpp index df61a010f84..6caf253570a 100644 --- a/src/server/scripts/EasternKingdoms/zone_burning_steppes.cpp +++ b/src/server/scripts/EasternKingdoms/zone_burning_steppes.cpp @@ -19,7 +19,7 @@ /* ScriptData SDName: Burning_Steppes SD%Complete: 100 -SDComment: Quest support: 4224, 4866 +SDComment: Quest support: 4866 SDCategory: Burning Steppes EndScriptData */ @@ -36,25 +36,11 @@ EndContentData */ ## npc_ragged_john ######*/ -#define GOSSIP_HELLO "Official buisness, John. I need some information about Marsha Windsor. Tell me about the last time you saw him." -#define GOSSIP_SELECT1 "So what did you do?" -#define GOSSIP_SELECT2 "Start making sense, dwarf. I don't want to have anything to do with your cracker, your pappy, or any sort of 'discreditin'." -#define GOSSIP_SELECT3 "Ironfoe?" -#define GOSSIP_SELECT4 "Interesting... continue John." -#define GOSSIP_SELECT5 "So that's how Windsor died..." -#define GOSSIP_SELECT6 "So how did he die?" -#define GOSSIP_SELECT7 "Ok so where the hell is he? Wait a minute! Are you drunk?" -#define GOSSIP_SELECT8 "WHY is he in Blackrock Depths?" -#define GOSSIP_SELECT9 "300? So the Dark Irons killed him and dragged him into the Depths?" -#define GOSSIP_SELECT10 "Ahh... Ironfoe" -#define GOSSIP_SELECT11 "Thanks, Ragged John. Your story was very uplifting and informative" - enum RaggedJohn { - QUEST_THE_TRUE_MASTERS = 4224, - QUEST_MOTHERS_MILK = 4866, - SPELL_MOTHERS_MILK = 16468, - SPELL_WICKED_MILKING = 16472 + QUEST_MOTHERS_MILK = 4866, + SPELL_MOTHERS_MILK = 16468, + SPELL_WICKED_MILKING = 16472 }; class npc_ragged_john : public CreatureScript @@ -86,72 +72,13 @@ public: void EnterCombat(Unit* /*who*/) override { } }; - bool OnGossipSelect(Player* player, Creature* creature, uint32 /*sender*/, uint32 action) override - { - player->PlayerTalkClass->ClearMenus(); - switch (action) - { - case GOSSIP_ACTION_INFO_DEF: - player->ADD_GOSSIP_ITEM(GOSSIP_ICON_CHAT, GOSSIP_SELECT1, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 1); - player->SEND_GOSSIP_MENU(2714, creature->GetGUID()); - break; - case GOSSIP_ACTION_INFO_DEF+1: - player->ADD_GOSSIP_ITEM(GOSSIP_ICON_CHAT, GOSSIP_SELECT2, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 2); - player->SEND_GOSSIP_MENU(2715, creature->GetGUID()); - break; - case GOSSIP_ACTION_INFO_DEF+2: - player->ADD_GOSSIP_ITEM(GOSSIP_ICON_CHAT, GOSSIP_SELECT3, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 3); - player->SEND_GOSSIP_MENU(2716, creature->GetGUID()); - break; - case GOSSIP_ACTION_INFO_DEF+3: - player->ADD_GOSSIP_ITEM(GOSSIP_ICON_CHAT, GOSSIP_SELECT4, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 4); - player->SEND_GOSSIP_MENU(2717, creature->GetGUID()); - break; - case GOSSIP_ACTION_INFO_DEF+4: - player->ADD_GOSSIP_ITEM(GOSSIP_ICON_CHAT, GOSSIP_SELECT5, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 5); - player->SEND_GOSSIP_MENU(2718, creature->GetGUID()); - break; - case GOSSIP_ACTION_INFO_DEF+5: - player->ADD_GOSSIP_ITEM(GOSSIP_ICON_CHAT, GOSSIP_SELECT6, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 6); - player->SEND_GOSSIP_MENU(2719, creature->GetGUID()); - break; - case GOSSIP_ACTION_INFO_DEF+6: - player->ADD_GOSSIP_ITEM(GOSSIP_ICON_CHAT, GOSSIP_SELECT7, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 7); - player->SEND_GOSSIP_MENU(2720, creature->GetGUID()); - break; - case GOSSIP_ACTION_INFO_DEF+7: - player->ADD_GOSSIP_ITEM(GOSSIP_ICON_CHAT, GOSSIP_SELECT8, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 8); - player->SEND_GOSSIP_MENU(2721, creature->GetGUID()); - break; - case GOSSIP_ACTION_INFO_DEF+8: - player->ADD_GOSSIP_ITEM(GOSSIP_ICON_CHAT, GOSSIP_SELECT9, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 9); - player->SEND_GOSSIP_MENU(2722, creature->GetGUID()); - break; - case GOSSIP_ACTION_INFO_DEF+9: - player->ADD_GOSSIP_ITEM(GOSSIP_ICON_CHAT, GOSSIP_SELECT10, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 10); - player->SEND_GOSSIP_MENU(2723, creature->GetGUID()); - break; - case GOSSIP_ACTION_INFO_DEF+10: - player->ADD_GOSSIP_ITEM(GOSSIP_ICON_CHAT, GOSSIP_SELECT11, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 11); - player->SEND_GOSSIP_MENU(2725, creature->GetGUID()); - break; - case GOSSIP_ACTION_INFO_DEF+11: - player->CLOSE_GOSSIP_MENU(); - player->AreaExploredOrEventHappens(QUEST_THE_TRUE_MASTERS); - break; - } - return true; - } - bool OnGossipHello(Player* player, Creature* creature) override { if (creature->IsQuestGiver()) + { player->PrepareQuestMenu(creature->GetGUID()); - - if (player->GetQuestStatus(QUEST_THE_TRUE_MASTERS) == QUEST_STATUS_INCOMPLETE) - player->ADD_GOSSIP_ITEM(GOSSIP_ICON_CHAT, GOSSIP_HELLO, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF); - - player->SEND_GOSSIP_MENU(2713, creature->GetGUID()); + player->SEND_GOSSIP_MENU(player->GetGossipTextId(creature), creature->GetGUID()); + } return true; } diff --git a/src/server/scripts/EasternKingdoms/zone_eastern_plaguelands.cpp b/src/server/scripts/EasternKingdoms/zone_eastern_plaguelands.cpp index ce0ebf4d129..4cc72715868 100644 --- a/src/server/scripts/EasternKingdoms/zone_eastern_plaguelands.cpp +++ b/src/server/scripts/EasternKingdoms/zone_eastern_plaguelands.cpp @@ -19,7 +19,7 @@ /* ScriptData SDName: Eastern_Plaguelands SD%Complete: 100 -SDComment: Quest support: 5211, 5742. Special vendor Augustus the Touched +SDComment: Quest support: 5211. Special vendor Augustus the Touched SDCategory: Eastern Plaguelands EndScriptData */ @@ -27,7 +27,6 @@ EndScriptData */ npc_ghoul_flayer npc_augustus_the_touched npc_darrowshire_spirit -npc_tirion_fordring EndContentData */ #include "ScriptMgr.h" @@ -133,63 +132,9 @@ public: }; }; -/*###### -## npc_tirion_fordring -######*/ - -#define GOSSIP_HELLO "I am ready to hear your tale, Tirion." -#define GOSSIP_SELECT1 "Thank you, Tirion. What of your identity?" -#define GOSSIP_SELECT2 "That is terrible." -#define GOSSIP_SELECT3 "I will, Tirion." - -class npc_tirion_fordring : public CreatureScript -{ -public: - npc_tirion_fordring() : CreatureScript("npc_tirion_fordring") { } - - bool OnGossipSelect(Player* player, Creature* creature, uint32 /*sender*/, uint32 action) override - { - player->PlayerTalkClass->ClearMenus(); - switch (action) - { - case GOSSIP_ACTION_INFO_DEF+1: - player->ADD_GOSSIP_ITEM(GOSSIP_ICON_CHAT, GOSSIP_SELECT1, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 2); - player->SEND_GOSSIP_MENU(4493, creature->GetGUID()); - break; - case GOSSIP_ACTION_INFO_DEF+2: - player->ADD_GOSSIP_ITEM(GOSSIP_ICON_CHAT, GOSSIP_SELECT2, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 3); - player->SEND_GOSSIP_MENU(4494, creature->GetGUID()); - break; - case GOSSIP_ACTION_INFO_DEF+3: - player->ADD_GOSSIP_ITEM(GOSSIP_ICON_CHAT, GOSSIP_SELECT3, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 4); - player->SEND_GOSSIP_MENU(4495, creature->GetGUID()); - break; - case GOSSIP_ACTION_INFO_DEF+4: - player->CLOSE_GOSSIP_MENU(); - player->AreaExploredOrEventHappens(5742); - break; - } - return true; - } - - bool OnGossipHello(Player* player, Creature* creature) override - { - if (creature->IsQuestGiver()) - player->PrepareQuestMenu(creature->GetGUID()); - - if (player->GetQuestStatus(5742) == QUEST_STATUS_INCOMPLETE && player->getStandState() == UNIT_STAND_STATE_SIT) - player->ADD_GOSSIP_ITEM(GOSSIP_ICON_CHAT, GOSSIP_HELLO, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF+1); - - player->SEND_GOSSIP_MENU(player->GetGossipTextId(creature), creature->GetGUID()); - - return true; - } -}; - void AddSC_eastern_plaguelands() { new npc_ghoul_flayer(); new npc_augustus_the_touched(); new npc_darrowshire_spirit(); - new npc_tirion_fordring(); } diff --git a/src/server/scripts/EasternKingdoms/zone_stormwind_city.cpp b/src/server/scripts/EasternKingdoms/zone_stormwind_city.cpp index 2d6d4da5aef..4a585bcb267 100644 --- a/src/server/scripts/EasternKingdoms/zone_stormwind_city.cpp +++ b/src/server/scripts/EasternKingdoms/zone_stormwind_city.cpp @@ -19,14 +19,12 @@ /* ScriptData SDName: Stormwind_City SD%Complete: 100 -SDComment: Quest support: 1640, 1447, 4185, 11223, 434. +SDComment: Quest support: 1640, 1447, 434. SDCategory: Stormwind City EndScriptData */ /* ContentData -npc_archmage_malin npc_bartleby -npc_lady_katrana_prestor npc_tyrion npc_tyrion_spybot npc_marzon_silent_blade @@ -40,50 +38,13 @@ EndContentData */ #include "Player.h" /*###### -## npc_archmage_malin -######*/ - -#define GOSSIP_ITEM_MALIN "Can you send me to Theramore? I have an urgent message for Lady Jaina from Highlord Bolvar." - -class npc_archmage_malin : public CreatureScript -{ -public: - npc_archmage_malin() : CreatureScript("npc_archmage_malin") { } - - bool OnGossipSelect(Player* player, Creature* creature, uint32 /*sender*/, uint32 action) override - { - player->PlayerTalkClass->ClearMenus(); - if (action == GOSSIP_ACTION_INFO_DEF) - { - player->CLOSE_GOSSIP_MENU(); - creature->CastSpell(player, 42711, true); - } - - return true; - } - - bool OnGossipHello(Player* player, Creature* creature) override - { - if (creature->IsQuestGiver()) - player->PrepareQuestMenu(creature->GetGUID()); - - if (player->GetQuestStatus(11223) == QUEST_STATUS_COMPLETE) - player->ADD_GOSSIP_ITEM(GOSSIP_ICON_CHAT, GOSSIP_ITEM_MALIN, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF); - - player->SEND_GOSSIP_MENU(player->GetGossipTextId(creature), creature->GetGUID()); - - return true; - } -}; - -/*###### ## npc_bartleby ######*/ enum Bartleby { - FACTION_ENEMY = 168, - QUEST_BEAT = 1640 + FACTION_ENEMY = 168, + QUEST_BEAT = 1640 }; class npc_bartleby : public CreatureScript @@ -148,71 +109,18 @@ public: }; /*###### -## npc_lady_katrana_prestor -######*/ - -#define GOSSIP_ITEM_KAT_1 "Pardon the intrusion, Lady Prestor, but Highlord Bolvar suggested that I seek your advice." -#define GOSSIP_ITEM_KAT_2 "My apologies, Lady Prestor." -#define GOSSIP_ITEM_KAT_3 "Begging your pardon, Lady Prestor. That was not my intent." -#define GOSSIP_ITEM_KAT_4 "Thank you for your time, Lady Prestor." - -class npc_lady_katrana_prestor : public CreatureScript -{ -public: - npc_lady_katrana_prestor() : CreatureScript("npc_lady_katrana_prestor") { } - - bool OnGossipSelect(Player* player, Creature* creature, uint32 /*sender*/, uint32 action) override - { - player->PlayerTalkClass->ClearMenus(); - switch (action) - { - case GOSSIP_ACTION_INFO_DEF: - player->ADD_GOSSIP_ITEM(GOSSIP_ICON_CHAT, GOSSIP_ITEM_KAT_2, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 1); - player->SEND_GOSSIP_MENU(2694, creature->GetGUID()); - break; - case GOSSIP_ACTION_INFO_DEF+1: - player->ADD_GOSSIP_ITEM(GOSSIP_ICON_CHAT, GOSSIP_ITEM_KAT_3, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 2); - player->SEND_GOSSIP_MENU(2695, creature->GetGUID()); - break; - case GOSSIP_ACTION_INFO_DEF+2: - player->ADD_GOSSIP_ITEM(GOSSIP_ICON_CHAT, GOSSIP_ITEM_KAT_4, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 3); - player->SEND_GOSSIP_MENU(2696, creature->GetGUID()); - break; - case GOSSIP_ACTION_INFO_DEF+3: - player->CLOSE_GOSSIP_MENU(); - player->AreaExploredOrEventHappens(4185); - break; - } - return true; - } - - bool OnGossipHello(Player* player, Creature* creature) override - { - if (creature->IsQuestGiver()) - player->PrepareQuestMenu(creature->GetGUID()); - - if (player->GetQuestStatus(4185) == QUEST_STATUS_INCOMPLETE) - player->ADD_GOSSIP_ITEM(GOSSIP_ICON_CHAT, GOSSIP_ITEM_KAT_1, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF); - - player->SEND_GOSSIP_MENU(2693, creature->GetGUID()); - - return true; - } -}; - -/*###### ## npc_lord_gregor_lescovar ######*/ enum LordGregorLescovar { - SAY_GUARD_2 = 0, - SAY_LESCOVAR_2 = 0, - SAY_LESCOVAR_3 = 1, - SAY_LESCOVAR_4 = 2, - SAY_MARZON_1 = 0, - SAY_MARZON_2 = 1, - SAY_TYRION_2 = 1, + SAY_GUARD_2 = 0, + SAY_LESCOVAR_2 = 0, + SAY_LESCOVAR_3 = 1, + SAY_LESCOVAR_4 = 2, + SAY_MARZON_1 = 0, + SAY_MARZON_2 = 1, + SAY_TYRION_2 = 1, NPC_STORMWIND_ROYAL = 1756, NPC_MARZON_BLADE = 1755, @@ -650,9 +558,7 @@ public: void AddSC_stormwind_city() { - new npc_archmage_malin(); new npc_bartleby(); - new npc_lady_katrana_prestor(); new npc_tyrion(); new npc_tyrion_spybot(); new npc_lord_gregor_lescovar(); diff --git a/src/server/scripts/EasternKingdoms/zone_undercity.cpp b/src/server/scripts/EasternKingdoms/zone_undercity.cpp index c0b4e06cfff..99556587e65 100644 --- a/src/server/scripts/EasternKingdoms/zone_undercity.cpp +++ b/src/server/scripts/EasternKingdoms/zone_undercity.cpp @@ -157,7 +157,7 @@ public: { if (Creature* target = ObjectAccessor::GetCreature(*summoned, targetGUID)) { - target->GetMotionMaster()->MoveJump(target->GetPositionX(), target->GetPositionY(), me->GetPositionZ() + 15.0f, 0); + target->GetMotionMaster()->MoveJump(target->GetPositionX(), target->GetPositionY(), me->GetPositionZ() + 15.0f, me->GetOrientation(), 0); target->SetPosition(target->GetPositionX(), target->GetPositionY(), me->GetPositionZ()+15.0f, 0.0f); summoned->CastSpell(target, SPELL_RIBBON_OF_SOULS, false); } diff --git a/src/server/scripts/EasternKingdoms/zone_western_plaguelands.cpp b/src/server/scripts/EasternKingdoms/zone_western_plaguelands.cpp index b1a00f35bb5..a01b93a140b 100644 --- a/src/server/scripts/EasternKingdoms/zone_western_plaguelands.cpp +++ b/src/server/scripts/EasternKingdoms/zone_western_plaguelands.cpp @@ -25,7 +25,6 @@ EndScriptData */ /* ContentData npcs_dithers_and_arbington -npc_myranda_the_hag npc_the_scourge_cauldron npc_andorhal_tower EndContentData */ @@ -33,7 +32,6 @@ EndContentData */ #include "ScriptMgr.h" #include "ScriptedCreature.h" #include "ScriptedGossip.h" -#include "ScriptedEscortAI.h" #include "Player.h" #include "WorldSession.h" @@ -120,54 +118,6 @@ public: }; /*###### -## npc_myranda_the_hag -######*/ - -enum Myranda -{ - ILLUSION_GOSSIP = 4773, - QUEST_SUBTERFUGE = 5862, - QUEST_IN_DREAMS = 5944, - SPELL_SCARLET_ILLUSION = 17961 -}; - -class npc_myranda_the_hag : public CreatureScript -{ -public: - npc_myranda_the_hag() : CreatureScript("npc_myranda_the_hag") { } - - bool OnGossipSelect(Player* player, Creature* /*creature*/, uint32 /*sender*/, uint32 action) override - { - player->PlayerTalkClass->ClearMenus(); - if (action == GOSSIP_ACTION_INFO_DEF + 1) - { - player->CLOSE_GOSSIP_MENU(); - player->CastSpell(player, SPELL_SCARLET_ILLUSION, false); - } - return true; - } - - bool OnGossipHello(Player* player, Creature* creature) override - { - if (creature->IsQuestGiver()) - player->PrepareQuestMenu(creature->GetGUID()); - - if (player->GetQuestStatus(QUEST_SUBTERFUGE) == QUEST_STATUS_COMPLETE && - player->GetQuestStatus(QUEST_IN_DREAMS) != QUEST_STATUS_COMPLETE && - !player->HasAura(SPELL_SCARLET_ILLUSION)) - { - player->ADD_GOSSIP_ITEM_DB(Player::GetDefaultGossipMenuForSource(creature), 0, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 1); - player->SEND_GOSSIP_MENU(ILLUSION_GOSSIP, creature->GetGUID()); - return true; - } - else - player->SEND_GOSSIP_MENU(player->GetGossipTextId(creature), creature->GetGUID()); - - return true; - } -}; - -/*###### ## npc_the_scourge_cauldron ######*/ @@ -195,7 +145,7 @@ public: me->DealDamage(me, me->GetHealth(), NULL, DIRECT_DAMAGE, SPELL_SCHOOL_MASK_NORMAL, NULL, false); //override any database `spawntimesecs` to prevent duplicated summons uint32 rTime = me->GetRespawnDelay(); - if (rTime<600) + if (rTime < 600) me->SetRespawnDelay(600); } @@ -274,7 +224,6 @@ public: } void MoveInLineOfSight(Unit* who) override - { if (!who || who->GetTypeId() != TYPEID_PLAYER) return; @@ -286,14 +235,9 @@ public: }; }; -/*###### -## -######*/ - void AddSC_western_plaguelands() { new npcs_dithers_and_arbington(); - new npc_myranda_the_hag(); new npc_the_scourge_cauldron(); new npc_andorhal_tower(); } diff --git a/src/server/scripts/Events/CMakeLists.txt b/src/server/scripts/Events/CMakeLists.txt deleted file mode 100644 index 1c9e5cfe8e1..00000000000 --- a/src/server/scripts/Events/CMakeLists.txt +++ /dev/null @@ -1,18 +0,0 @@ -# Copyright (C) 2008-2016 TrinityCore <http://www.trinitycore.org/> -# -# This file is free software; as a special exception the author gives -# unlimited permission to copy and/or distribute it, with or without -# modifications, as long as this notice is preserved. -# -# This program is distributed in the hope that it will be useful, but -# WITHOUT ANY WARRANTY, to the extent permitted by law; without even the -# implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. - -file(GLOB_RECURSE sources_Events Events/*.cpp Events/*.h) - -set(scripts_STAT_SRCS - ${scripts_STAT_SRCS} - ${sources_Events} -) - -message(" -> Prepared: Events") diff --git a/src/server/scripts/Events/events_script_loader.cpp b/src/server/scripts/Events/events_script_loader.cpp new file mode 100644 index 00000000000..625c08f5389 --- /dev/null +++ b/src/server/scripts/Events/events_script_loader.cpp @@ -0,0 +1,26 @@ +/* + * Copyright (C) 2008-2016 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/>. + */ + +// This is where scripts' loading functions should be declared: +void AddSC_event_childrens_week(); + +// The name of this function should match: +// void Add${NameOfDirectory}Scripts() +void AddEventsScripts() +{ + AddSC_event_childrens_week(); +} diff --git a/src/server/scripts/Kalimdor/CMakeLists.txt b/src/server/scripts/Kalimdor/CMakeLists.txt deleted file mode 100644 index 2d1b4b49649..00000000000 --- a/src/server/scripts/Kalimdor/CMakeLists.txt +++ /dev/null @@ -1,121 +0,0 @@ -# Copyright (C) 2008-2016 TrinityCore <http://www.trinitycore.org/> -# -# This file is free software; as a special exception the author gives -# unlimited permission to copy and/or distribute it, with or without -# modifications, as long as this notice is preserved. -# -# This program is distributed in the hope that it will be useful, but -# WITHOUT ANY WARRANTY, to the extent permitted by law; without even the -# implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. - -set(scripts_STAT_SRCS - ${scripts_STAT_SRCS} - Kalimdor/zone_stonetalon_mountains.cpp - Kalimdor/zone_silithus.cpp - Kalimdor/zone_moonglade.cpp - Kalimdor/RazorfenDowns/razorfen_downs.cpp - Kalimdor/RazorfenDowns/instance_razorfen_downs.cpp - Kalimdor/RazorfenDowns/boss_tuten_kash.cpp - Kalimdor/RazorfenDowns/boss_mordresh_fire_eye.cpp - Kalimdor/RazorfenDowns/boss_glutton.cpp - Kalimdor/RazorfenDowns/boss_amnennar_the_coldbringer.cpp - Kalimdor/RazorfenDowns/razorfen_downs.h - Kalimdor/ZulFarrak/zulfarrak.cpp - Kalimdor/ZulFarrak/instance_zulfarrak.cpp - Kalimdor/ZulFarrak/boss_zum_rah.cpp - Kalimdor/ZulFarrak/zulfarrak.h - Kalimdor/CavernsOfTime/EscapeFromDurnholdeKeep/boss_epoch_hunter.cpp - Kalimdor/CavernsOfTime/EscapeFromDurnholdeKeep/old_hillsbrad.h - Kalimdor/CavernsOfTime/EscapeFromDurnholdeKeep/boss_leutenant_drake.cpp - Kalimdor/CavernsOfTime/EscapeFromDurnholdeKeep/old_hillsbrad.cpp - Kalimdor/CavernsOfTime/EscapeFromDurnholdeKeep/instance_old_hillsbrad.cpp - Kalimdor/CavernsOfTime/EscapeFromDurnholdeKeep/boss_captain_skarloc.cpp - Kalimdor/CavernsOfTime/BattleForMountHyjal/boss_archimonde.cpp - Kalimdor/CavernsOfTime/BattleForMountHyjal/hyjalAI.h - Kalimdor/CavernsOfTime/BattleForMountHyjal/hyjal_trash.h - Kalimdor/CavernsOfTime/BattleForMountHyjal/boss_kazrogal.cpp - Kalimdor/CavernsOfTime/BattleForMountHyjal/hyjal_trash.cpp - Kalimdor/CavernsOfTime/BattleForMountHyjal/hyjal.cpp - Kalimdor/CavernsOfTime/BattleForMountHyjal/hyjalAI.cpp - Kalimdor/CavernsOfTime/BattleForMountHyjal/instance_hyjal.cpp - Kalimdor/CavernsOfTime/BattleForMountHyjal/boss_rage_winterchill.cpp - Kalimdor/CavernsOfTime/BattleForMountHyjal/hyjal.h - Kalimdor/CavernsOfTime/BattleForMountHyjal/boss_azgalor.cpp - Kalimdor/CavernsOfTime/BattleForMountHyjal/boss_anetheron.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_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 - Kalimdor/CavernsOfTime/TheBlackMorass/the_black_morass.h - Kalimdor/CavernsOfTime/TheBlackMorass/instance_the_black_morass.cpp - Kalimdor/CavernsOfTime/TheBlackMorass/boss_chrono_lord_deja.cpp - Kalimdor/CavernsOfTime/TheBlackMorass/the_black_morass.cpp - Kalimdor/CavernsOfTime/TheBlackMorass/boss_aeonus.cpp - Kalimdor/CavernsOfTime/TheBlackMorass/boss_temporus.cpp - Kalimdor/BlackfathomDeeps/boss_kelris.cpp - Kalimdor/BlackfathomDeeps/instance_blackfathom_deeps.cpp - Kalimdor/BlackfathomDeeps/boss_gelihast.cpp - Kalimdor/BlackfathomDeeps/blackfathom_deeps.cpp - Kalimdor/BlackfathomDeeps/boss_aku_mai.cpp - Kalimdor/BlackfathomDeeps/blackfathom_deeps.h - Kalimdor/zone_azuremyst_isle.cpp - Kalimdor/zone_orgrimmar.cpp - Kalimdor/zone_desolace.cpp - Kalimdor/zone_feralas.cpp - Kalimdor/Maraudon/boss_princess_theradras.cpp - Kalimdor/Maraudon/boss_landslide.cpp - Kalimdor/Maraudon/boss_celebras_the_cursed.cpp - Kalimdor/Maraudon/boss_noxxion.cpp - Kalimdor/Maraudon/instance_maraudon.cpp - Kalimdor/TempleOfAhnQiraj/boss_fankriss.cpp - Kalimdor/TempleOfAhnQiraj/boss_huhuran.cpp - Kalimdor/TempleOfAhnQiraj/instance_temple_of_ahnqiraj.cpp - Kalimdor/TempleOfAhnQiraj/mob_anubisath_sentinel.cpp - Kalimdor/TempleOfAhnQiraj/boss_viscidus.cpp - Kalimdor/TempleOfAhnQiraj/boss_twinemperors.cpp - Kalimdor/TempleOfAhnQiraj/boss_sartura.cpp - Kalimdor/TempleOfAhnQiraj/boss_cthun.cpp - Kalimdor/TempleOfAhnQiraj/temple_of_ahnqiraj.h - Kalimdor/TempleOfAhnQiraj/boss_skeram.cpp - Kalimdor/TempleOfAhnQiraj/boss_ouro.cpp - Kalimdor/TempleOfAhnQiraj/boss_bug_trio.cpp - Kalimdor/zone_darkshore.cpp - Kalimdor/RuinsOfAhnQiraj/boss_buru.cpp - Kalimdor/RuinsOfAhnQiraj/instance_ruins_of_ahnqiraj.cpp - Kalimdor/RuinsOfAhnQiraj/boss_rajaxx.cpp - Kalimdor/RuinsOfAhnQiraj/boss_ossirian.cpp - Kalimdor/RuinsOfAhnQiraj/boss_ayamiss.cpp - Kalimdor/RuinsOfAhnQiraj/boss_moam.cpp - Kalimdor/RuinsOfAhnQiraj/ruins_of_ahnqiraj.h - Kalimdor/RuinsOfAhnQiraj/boss_kurinnaxx.cpp - Kalimdor/zone_bloodmyst_isle.cpp - Kalimdor/zone_thunder_bluff.cpp - Kalimdor/zone_azshara.cpp - Kalimdor/RazorfenKraul/razorfen_kraul.h - Kalimdor/RazorfenKraul/instance_razorfen_kraul.cpp - Kalimdor/RazorfenKraul/razorfen_kraul.cpp - Kalimdor/zone_the_barrens.cpp - Kalimdor/zone_ungoro_crater.cpp - Kalimdor/WailingCaverns/wailing_caverns.h - Kalimdor/WailingCaverns/instance_wailing_caverns.cpp - Kalimdor/WailingCaverns/wailing_caverns.cpp - Kalimdor/zone_durotar.cpp - Kalimdor/zone_felwood.cpp - Kalimdor/boss_azuregos.cpp - Kalimdor/zone_tanaris.cpp - Kalimdor/zone_dustwallow_marsh.cpp - Kalimdor/zone_winterspring.cpp - Kalimdor/zone_thousand_needles.cpp - Kalimdor/zone_ashenvale.cpp - Kalimdor/OnyxiasLair/boss_onyxia.cpp - Kalimdor/OnyxiasLair/onyxias_lair.h - Kalimdor/OnyxiasLair/instance_onyxias_lair.cpp - Kalimdor/RagefireChasm/instance_ragefire_chasm.cpp - Kalimdor/DireMaul/instance_dire_maul.cpp -) - -message(" -> Prepared: Kalimdor") diff --git a/src/server/scripts/Kalimdor/kalimdor_script_loader.cpp b/src/server/scripts/Kalimdor/kalimdor_script_loader.cpp new file mode 100644 index 00000000000..f1969a063d6 --- /dev/null +++ b/src/server/scripts/Kalimdor/kalimdor_script_loader.cpp @@ -0,0 +1,206 @@ +/* + * Copyright (C) 2008-2016 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/>. + */ + +// This is where scripts' loading functions should be declared: +void AddSC_blackfathom_deeps(); //Blackfathom Depths +void AddSC_boss_gelihast(); +void AddSC_boss_kelris(); +void AddSC_boss_aku_mai(); +void AddSC_instance_blackfathom_deeps(); +void AddSC_hyjal(); //CoT Battle for Mt. Hyjal +void AddSC_boss_archimonde(); +void AddSC_instance_mount_hyjal(); +void AddSC_hyjal_trash(); +void AddSC_boss_rage_winterchill(); +void AddSC_boss_anetheron(); +void AddSC_boss_kazrogal(); +void AddSC_boss_azgalor(); +void AddSC_boss_captain_skarloc(); //CoT Old Hillsbrad +void AddSC_boss_epoch_hunter(); +void AddSC_boss_lieutenant_drake(); +void AddSC_instance_old_hillsbrad(); +void AddSC_old_hillsbrad(); +void AddSC_boss_aeonus(); //CoT The Black Morass +void AddSC_boss_chrono_lord_deja(); +void AddSC_boss_temporus(); +void AddSC_the_black_morass(); +void AddSC_instance_the_black_morass(); +void AddSC_boss_epoch(); //CoT Culling Of Stratholme +void AddSC_boss_infinite_corruptor(); +void AddSC_boss_salramm(); +void AddSC_boss_mal_ganis(); +void AddSC_boss_meathook(); +void AddSC_culling_of_stratholme(); +void AddSC_instance_culling_of_stratholme(); +void AddSC_instance_dire_maul(); //Dire Maul +void AddSC_boss_celebras_the_cursed(); //Maraudon +void AddSC_boss_landslide(); +void AddSC_boss_noxxion(); +void AddSC_boss_ptheradras(); +void AddSC_instance_maraudon(); +void AddSC_boss_onyxia(); //Onyxia's Lair +void AddSC_instance_onyxias_lair(); +void AddSC_boss_tuten_kash(); //Razorfen Downs +void AddSC_boss_mordresh_fire_eye(); +void AddSC_boss_glutton(); +void AddSC_boss_amnennar_the_coldbringer(); +void AddSC_razorfen_downs(); +void AddSC_instance_razorfen_downs(); +void AddSC_razorfen_kraul(); //Razorfen Kraul +void AddSC_instance_razorfen_kraul(); +void AddSC_boss_kurinnaxx(); //Ruins of ahn'qiraj +void AddSC_boss_rajaxx(); +void AddSC_boss_moam(); +void AddSC_boss_buru(); +void AddSC_boss_ayamiss(); +void AddSC_boss_ossirian(); +void AddSC_instance_ruins_of_ahnqiraj(); +void AddSC_boss_cthun(); //Temple of ahn'qiraj +void AddSC_boss_viscidus(); +void AddSC_boss_fankriss(); +void AddSC_boss_huhuran(); +void AddSC_bug_trio(); +void AddSC_boss_sartura(); +void AddSC_boss_skeram(); +void AddSC_boss_twinemperors(); +void AddSC_boss_ouro(); +void AddSC_npc_anubisath_sentinel(); +void AddSC_instance_temple_of_ahnqiraj(); +void AddSC_wailing_caverns(); //Wailing caverns +void AddSC_instance_wailing_caverns(); +void AddSC_boss_zum_rah(); //Zul'Farrak +void AddSC_zulfarrak(); +void AddSC_instance_zulfarrak(); + +void AddSC_ashenvale(); +void AddSC_azshara(); +void AddSC_azuremyst_isle(); +void AddSC_bloodmyst_isle(); +void AddSC_boss_azuregos(); +void AddSC_darkshore(); +void AddSC_desolace(); +void AddSC_durotar(); +void AddSC_dustwallow_marsh(); +void AddSC_felwood(); +void AddSC_feralas(); +void AddSC_moonglade(); +void AddSC_orgrimmar(); +void AddSC_silithus(); +void AddSC_stonetalon_mountains(); +void AddSC_tanaris(); +void AddSC_the_barrens(); +void AddSC_thousand_needles(); +void AddSC_thunder_bluff(); +void AddSC_ungoro_crater(); +void AddSC_winterspring(); + +// The name of this function should match: +// void Add${NameOfDirectory}Scripts() +void AddKalimdorScripts() +{ + AddSC_blackfathom_deeps(); //Blackfathom Depths + AddSC_boss_gelihast(); + AddSC_boss_kelris(); + AddSC_boss_aku_mai(); + AddSC_instance_blackfathom_deeps(); + AddSC_hyjal(); //CoT Battle for Mt. Hyjal + AddSC_boss_archimonde(); + AddSC_instance_mount_hyjal(); + AddSC_hyjal_trash(); + AddSC_boss_rage_winterchill(); + AddSC_boss_anetheron(); + AddSC_boss_kazrogal(); + AddSC_boss_azgalor(); + AddSC_boss_captain_skarloc(); //CoT Old Hillsbrad + AddSC_boss_epoch_hunter(); + AddSC_boss_lieutenant_drake(); + AddSC_instance_old_hillsbrad(); + AddSC_old_hillsbrad(); + AddSC_boss_aeonus(); //CoT The Black Morass + AddSC_boss_chrono_lord_deja(); + AddSC_boss_temporus(); + AddSC_the_black_morass(); + AddSC_instance_the_black_morass(); + AddSC_boss_epoch(); //CoT Culling Of Stratholme + AddSC_boss_infinite_corruptor(); + AddSC_boss_salramm(); + AddSC_boss_mal_ganis(); + AddSC_boss_meathook(); + AddSC_culling_of_stratholme(); + AddSC_instance_culling_of_stratholme(); + AddSC_instance_dire_maul(); //Dire Maul + AddSC_boss_celebras_the_cursed(); //Maraudon + AddSC_boss_landslide(); + AddSC_boss_noxxion(); + AddSC_boss_ptheradras(); + AddSC_instance_maraudon(); + AddSC_boss_onyxia(); //Onyxia's Lair + AddSC_instance_onyxias_lair(); + AddSC_boss_tuten_kash(); //Razorfen Downs + AddSC_boss_mordresh_fire_eye(); + AddSC_boss_glutton(); + AddSC_boss_amnennar_the_coldbringer(); + AddSC_razorfen_downs(); + AddSC_instance_razorfen_downs(); + AddSC_razorfen_kraul(); //Razorfen Kraul + AddSC_instance_razorfen_kraul(); + AddSC_boss_kurinnaxx(); //Ruins of ahn'qiraj + AddSC_boss_rajaxx(); + AddSC_boss_moam(); + AddSC_boss_buru(); + AddSC_boss_ayamiss(); + AddSC_boss_ossirian(); + AddSC_instance_ruins_of_ahnqiraj(); + AddSC_boss_cthun(); //Temple of ahn'qiraj + AddSC_boss_viscidus(); + AddSC_boss_fankriss(); + AddSC_boss_huhuran(); + AddSC_bug_trio(); + AddSC_boss_sartura(); + AddSC_boss_skeram(); + AddSC_boss_twinemperors(); + AddSC_boss_ouro(); + AddSC_npc_anubisath_sentinel(); + AddSC_instance_temple_of_ahnqiraj(); + AddSC_wailing_caverns(); //Wailing caverns + AddSC_instance_wailing_caverns(); + AddSC_boss_zum_rah(); //Zul'Farrak + AddSC_zulfarrak(); + AddSC_instance_zulfarrak(); + + AddSC_ashenvale(); + AddSC_azshara(); + AddSC_azuremyst_isle(); + AddSC_bloodmyst_isle(); + AddSC_boss_azuregos(); + AddSC_darkshore(); + AddSC_desolace(); + AddSC_durotar(); + AddSC_dustwallow_marsh(); + AddSC_felwood(); + AddSC_feralas(); + AddSC_moonglade(); + AddSC_orgrimmar(); + AddSC_silithus(); + AddSC_stonetalon_mountains(); + AddSC_tanaris(); + AddSC_the_barrens(); + AddSC_thousand_needles(); + AddSC_thunder_bluff(); + AddSC_ungoro_crater(); + AddSC_winterspring(); +} diff --git a/src/server/scripts/Northrend/CMakeLists.txt b/src/server/scripts/Northrend/CMakeLists.txt deleted file mode 100644 index 1dc453ad416..00000000000 --- a/src/server/scripts/Northrend/CMakeLists.txt +++ /dev/null @@ -1,199 +0,0 @@ -# Copyright (C) 2008-2016 TrinityCore <http://www.trinitycore.org/> -# -# This file is free software; as a special exception the author gives -# unlimited permission to copy and/or distribute it, with or without -# modifications, as long as this notice is preserved. -# -# This program is distributed in the hope that it will be useful, but -# WITHOUT ANY WARRANTY, to the extent permitted by law; without even the -# implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. - -set(scripts_STAT_SRCS - ${scripts_STAT_SRCS} - Northrend/zone_wintergrasp.cpp - Northrend/isle_of_conquest.cpp - Northrend/zone_storm_peaks.cpp - Northrend/Ulduar/HallsOfLightning/instance_halls_of_lightning.cpp - Northrend/Ulduar/HallsOfLightning/boss_bjarngrim.cpp - Northrend/Ulduar/HallsOfLightning/halls_of_lightning.h - Northrend/Ulduar/HallsOfLightning/boss_ionar.cpp - Northrend/Ulduar/HallsOfLightning/boss_volkhan.cpp - Northrend/Ulduar/HallsOfLightning/boss_loken.cpp - Northrend/Ulduar/Ulduar/boss_general_vezax.cpp - Northrend/Ulduar/Ulduar/boss_thorim.cpp - Northrend/Ulduar/Ulduar/boss_ignis.cpp - Northrend/Ulduar/Ulduar/boss_algalon_the_observer.cpp - Northrend/Ulduar/Ulduar/instance_ulduar.cpp - Northrend/Ulduar/Ulduar/boss_auriaya.cpp - Northrend/Ulduar/Ulduar/boss_yogg_saron.cpp - Northrend/Ulduar/Ulduar/boss_hodir.cpp - Northrend/Ulduar/Ulduar/boss_assembly_of_iron.cpp - Northrend/Ulduar/Ulduar/boss_flame_leviathan.cpp - Northrend/Ulduar/Ulduar/boss_xt002.cpp - Northrend/Ulduar/Ulduar/boss_mimiron.cpp - Northrend/Ulduar/Ulduar/ulduar.h - Northrend/Ulduar/Ulduar/boss_freya.cpp - Northrend/Ulduar/Ulduar/boss_razorscale.cpp - Northrend/Ulduar/Ulduar/boss_kologarn.cpp - Northrend/Ulduar/HallsOfStone/boss_krystallus.cpp - Northrend/Ulduar/HallsOfStone/halls_of_stone.h - Northrend/Ulduar/HallsOfStone/instance_halls_of_stone.cpp - Northrend/Ulduar/HallsOfStone/boss_maiden_of_grief.cpp - Northrend/Ulduar/HallsOfStone/boss_sjonnir.cpp - Northrend/Ulduar/HallsOfStone/halls_of_stone.cpp - Northrend/ChamberOfAspects/ObsidianSanctum/instance_obsidian_sanctum.cpp - Northrend/ChamberOfAspects/ObsidianSanctum/obsidian_sanctum.h - Northrend/ChamberOfAspects/ObsidianSanctum/boss_sartharion.cpp - Northrend/ChamberOfAspects/ObsidianSanctum/obsidian_sanctum.cpp - Northrend/ChamberOfAspects/RubySanctum/instance_ruby_sanctum.cpp - Northrend/ChamberOfAspects/RubySanctum/ruby_sanctum.h - Northrend/ChamberOfAspects/RubySanctum/ruby_sanctum.cpp - Northrend/ChamberOfAspects/RubySanctum/boss_baltharus_the_warborn.cpp - Northrend/ChamberOfAspects/RubySanctum/boss_saviana_ragefire.cpp - Northrend/ChamberOfAspects/RubySanctum/boss_general_zarithrian.cpp - Northrend/ChamberOfAspects/RubySanctum/boss_halion.cpp - Northrend/FrozenHalls/HallsOfReflection/halls_of_reflection.h - Northrend/FrozenHalls/HallsOfReflection/boss_falric.cpp - Northrend/FrozenHalls/HallsOfReflection/instance_halls_of_reflection.cpp - Northrend/FrozenHalls/HallsOfReflection/halls_of_reflection.cpp - Northrend/FrozenHalls/HallsOfReflection/boss_marwyn.cpp - Northrend/FrozenHalls/PitOfSaron/boss_forgemaster_garfrost.cpp - Northrend/FrozenHalls/PitOfSaron/boss_krickandick.cpp - Northrend/FrozenHalls/PitOfSaron/pit_of_saron.cpp - Northrend/FrozenHalls/PitOfSaron/boss_scourgelord_tyrannus.cpp - Northrend/FrozenHalls/PitOfSaron/pit_of_saron.h - Northrend/FrozenHalls/PitOfSaron/instance_pit_of_saron.cpp - Northrend/FrozenHalls/ForgeOfSouls/forge_of_souls.cpp - Northrend/FrozenHalls/ForgeOfSouls/boss_bronjahm.cpp - Northrend/FrozenHalls/ForgeOfSouls/instance_forge_of_souls.cpp - Northrend/FrozenHalls/ForgeOfSouls/boss_devourer_of_souls.cpp - Northrend/FrozenHalls/ForgeOfSouls/forge_of_souls.h - Northrend/Nexus/EyeOfEternity/boss_malygos.cpp - Northrend/Nexus/EyeOfEternity/instance_eye_of_eternity.cpp - Northrend/Nexus/EyeOfEternity/eye_of_eternity.h - Northrend/Nexus/Oculus/boss_eregos.cpp - Northrend/Nexus/Oculus/boss_drakos.cpp - Northrend/Nexus/Oculus/oculus.h - Northrend/Nexus/Oculus/boss_varos.cpp - Northrend/Nexus/Oculus/boss_urom.cpp - Northrend/Nexus/Oculus/oculus.cpp - Northrend/Nexus/Oculus/instance_oculus.cpp - Northrend/Nexus/Nexus/boss_nexus_commanders.cpp - Northrend/Nexus/Nexus/boss_ormorok.cpp - Northrend/Nexus/Nexus/boss_magus_telestra.cpp - Northrend/Nexus/Nexus/instance_nexus.cpp - Northrend/Nexus/Nexus/boss_keristrasza.cpp - Northrend/Nexus/Nexus/boss_anomalus.cpp - Northrend/Nexus/Nexus/nexus.h - Northrend/CrusadersColiseum/TrialOfTheCrusader/boss_anubarak_trial.cpp - Northrend/CrusadersColiseum/TrialOfTheCrusader/boss_faction_champions.cpp - Northrend/CrusadersColiseum/TrialOfTheCrusader/boss_lord_jaraxxus.cpp - Northrend/CrusadersColiseum/TrialOfTheCrusader/trial_of_the_crusader.h - Northrend/CrusadersColiseum/TrialOfTheCrusader/boss_northrend_beasts.cpp - Northrend/CrusadersColiseum/TrialOfTheCrusader/trial_of_the_crusader.cpp - Northrend/CrusadersColiseum/TrialOfTheCrusader/boss_twin_valkyr.cpp - Northrend/CrusadersColiseum/TrialOfTheCrusader/instance_trial_of_the_crusader.cpp - Northrend/CrusadersColiseum/TrialOfTheChampion/trial_of_the_champion.h - Northrend/CrusadersColiseum/TrialOfTheChampion/trial_of_the_champion.cpp - Northrend/CrusadersColiseum/TrialOfTheChampion/boss_grand_champions.cpp - Northrend/CrusadersColiseum/TrialOfTheChampion/boss_black_knight.cpp - Northrend/CrusadersColiseum/TrialOfTheChampion/instance_trial_of_the_champion.cpp - Northrend/CrusadersColiseum/TrialOfTheChampion/boss_argent_challenge.cpp - Northrend/Naxxramas/boss_loatheb.cpp - Northrend/Naxxramas/boss_anubrekhan.cpp - Northrend/Naxxramas/boss_maexxna.cpp - Northrend/Naxxramas/boss_patchwerk.cpp - Northrend/Naxxramas/boss_gothik.cpp - Northrend/Naxxramas/boss_faerlina.cpp - Northrend/Naxxramas/boss_gluth.cpp - Northrend/Naxxramas/boss_four_horsemen.cpp - Northrend/Naxxramas/naxxramas.h - Northrend/Naxxramas/boss_kelthuzad.cpp - Northrend/Naxxramas/boss_heigan.cpp - Northrend/Naxxramas/boss_thaddius.cpp - Northrend/Naxxramas/boss_razuvious.cpp - Northrend/Naxxramas/boss_sapphiron.cpp - Northrend/Naxxramas/instance_naxxramas.cpp - Northrend/Naxxramas/boss_grobbulus.cpp - Northrend/Naxxramas/boss_noth.cpp - Northrend/zone_crystalsong_forest.cpp - Northrend/VaultOfArchavon/boss_archavon.cpp - Northrend/VaultOfArchavon/boss_koralon.cpp - Northrend/VaultOfArchavon/vault_of_archavon.h - Northrend/VaultOfArchavon/instance_vault_of_archavon.cpp - Northrend/VaultOfArchavon/boss_emalon.cpp - Northrend/VaultOfArchavon/boss_toravon.cpp - Northrend/zone_sholazar_basin.cpp - Northrend/UtgardeKeep/UtgardePinnacle/boss_svala.cpp - Northrend/UtgardeKeep/UtgardePinnacle/boss_palehoof.cpp - Northrend/UtgardeKeep/UtgardePinnacle/boss_skadi.cpp - Northrend/UtgardeKeep/UtgardePinnacle/boss_ymiron.cpp - Northrend/UtgardeKeep/UtgardePinnacle/instance_utgarde_pinnacle.cpp - Northrend/UtgardeKeep/UtgardePinnacle/utgarde_pinnacle.h - Northrend/UtgardeKeep/UtgardeKeep/boss_ingvar_the_plunderer.cpp - Northrend/UtgardeKeep/UtgardeKeep/boss_skarvald_dalronn.cpp - Northrend/UtgardeKeep/UtgardeKeep/utgarde_keep.h - Northrend/UtgardeKeep/UtgardeKeep/instance_utgarde_keep.cpp - Northrend/UtgardeKeep/UtgardeKeep/boss_keleseth.cpp - Northrend/UtgardeKeep/UtgardeKeep/utgarde_keep.cpp - Northrend/zone_dragonblight.cpp - Northrend/zone_grizzly_hills.cpp - Northrend/AzjolNerub/AzjolNerub/azjol_nerub.h - Northrend/AzjolNerub/AzjolNerub/instance_azjol_nerub.cpp - Northrend/AzjolNerub/AzjolNerub/boss_krikthir_the_gatewatcher.cpp - Northrend/AzjolNerub/AzjolNerub/boss_hadronox.cpp - Northrend/AzjolNerub/AzjolNerub/boss_anubarak.cpp - Northrend/AzjolNerub/Ahnkahet/boss_herald_volazj.cpp - Northrend/AzjolNerub/Ahnkahet/boss_prince_taldaram.cpp - Northrend/AzjolNerub/Ahnkahet/instance_ahnkahet.cpp - Northrend/AzjolNerub/Ahnkahet/boss_jedoga_shadowseeker.cpp - Northrend/AzjolNerub/Ahnkahet/boss_elder_nadox.cpp - Northrend/AzjolNerub/Ahnkahet/boss_amanitar.cpp - Northrend/AzjolNerub/Ahnkahet/ahnkahet.h - Northrend/VioletHold/boss_zuramat.cpp - Northrend/VioletHold/instance_violet_hold.cpp - Northrend/VioletHold/boss_lavanthor.cpp - Northrend/VioletHold/boss_cyanigosa.cpp - Northrend/VioletHold/violet_hold.h - Northrend/VioletHold/boss_ichoron.cpp - Northrend/VioletHold/boss_moragg.cpp - Northrend/VioletHold/boss_xevozz.cpp - Northrend/VioletHold/boss_erekem.cpp - Northrend/VioletHold/violet_hold.cpp - Northrend/IcecrownCitadel/instance_icecrown_citadel.cpp - Northrend/IcecrownCitadel/icecrown_citadel.cpp - Northrend/IcecrownCitadel/icecrown_citadel.h - Northrend/IcecrownCitadel/icecrown_citadel_teleport.cpp - Northrend/IcecrownCitadel/boss_lord_marrowgar.cpp - Northrend/IcecrownCitadel/boss_lady_deathwhisper.cpp - Northrend/IcecrownCitadel/boss_icecrown_gunship_battle.cpp - Northrend/IcecrownCitadel/boss_deathbringer_saurfang.cpp - Northrend/IcecrownCitadel/boss_festergut.cpp - Northrend/IcecrownCitadel/boss_rotface.cpp - Northrend/IcecrownCitadel/boss_professor_putricide.cpp - Northrend/IcecrownCitadel/boss_blood_prince_council.cpp - Northrend/IcecrownCitadel/boss_blood_queen_lana_thel.cpp - Northrend/IcecrownCitadel/boss_valithria_dreamwalker.cpp - Northrend/IcecrownCitadel/boss_sindragosa.cpp - Northrend/IcecrownCitadel/boss_the_lich_king.cpp - Northrend/zone_zuldrak.cpp - Northrend/zone_icecrown.cpp - Northrend/Gundrak/boss_slad_ran.cpp - Northrend/Gundrak/instance_gundrak.cpp - Northrend/Gundrak/boss_drakkari_colossus.cpp - Northrend/Gundrak/gundrak.h - Northrend/Gundrak/boss_gal_darah.cpp - Northrend/Gundrak/boss_moorabi.cpp - Northrend/Gundrak/boss_eck.cpp - Northrend/zone_borean_tundra.cpp - Northrend/zone_howling_fjord.cpp - Northrend/zone_dalaran.cpp - Northrend/DraktharonKeep/boss_trollgore.cpp - Northrend/DraktharonKeep/instance_drak_tharon_keep.cpp - Northrend/DraktharonKeep/boss_novos.cpp - Northrend/DraktharonKeep/drak_tharon_keep.h - Northrend/DraktharonKeep/boss_tharon_ja.cpp - Northrend/DraktharonKeep/boss_king_dred.cpp -) - -message(" -> Prepared: Northrend") 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 fb5642c6f3b..84d7d92acfe 100644 --- a/src/server/scripts/Northrend/ChamberOfAspects/RubySanctum/boss_general_zarithrian.cpp +++ b/src/server/scripts/Northrend/ChamberOfAspects/RubySanctum/boss_general_zarithrian.cpp @@ -135,9 +135,9 @@ class boss_general_zarithrian : public CreatureScript Talk(SAY_KILL); } - bool CanAIAttack(Unit const* /*target*/) const override + bool CanAIAttack(Unit const* target) const override { - return (instance->GetBossState(DATA_SAVIANA_RAGEFIRE) == DONE && instance->GetBossState(DATA_BALTHARUS_THE_WARBORN) == DONE); + return (instance->GetBossState(DATA_SAVIANA_RAGEFIRE) == DONE && instance->GetBossState(DATA_BALTHARUS_THE_WARBORN) == DONE && BossAI::CanAIAttack(target)); } void UpdateAI(uint32 diff) override 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 1e860fb6ec5..6c1b516c7de 100644 --- a/src/server/scripts/Northrend/CrusadersColiseum/TrialOfTheCrusader/boss_faction_champions.cpp +++ b/src/server/scripts/Northrend/CrusadersColiseum/TrialOfTheCrusader/boss_faction_champions.cpp @@ -461,13 +461,13 @@ class boss_toc_champion_controller : public CreatureScript if (playerTeam == ALLIANCE) { temp->SetHomePosition(vChampionJumpTarget[pos].GetPositionX(), vChampionJumpTarget[pos].GetPositionY(), vChampionJumpTarget[pos].GetPositionZ(), 0); - temp->GetMotionMaster()->MoveJump(vChampionJumpTarget[pos].GetPositionX(), vChampionJumpTarget[pos].GetPositionY(), vChampionJumpTarget[pos].GetPositionZ(), 20.0f, 20.0f); + temp->GetMotionMaster()->MoveJump(vChampionJumpTarget[pos], 20.0f, 20.0f); temp->SetOrientation(0); } else { temp->SetHomePosition((ToCCommonLoc[1].GetPositionX()*2)-vChampionJumpTarget[pos].GetPositionX(), vChampionJumpTarget[pos].GetPositionY(), vChampionJumpTarget[pos].GetPositionZ(), 3); - temp->GetMotionMaster()->MoveJump((ToCCommonLoc[1].GetPositionX()*2)-vChampionJumpTarget[pos].GetPositionX(), vChampionJumpTarget[pos].GetPositionY(), vChampionJumpTarget[pos].GetPositionZ(), 20.0f, 20.0f); + temp->GetMotionMaster()->MoveJump((ToCCommonLoc[1].GetPositionX() * 2) - vChampionJumpTarget[pos].GetPositionX(), vChampionJumpTarget[pos].GetPositionY(), vChampionJumpTarget[pos].GetPositionZ(), vChampionJumpTarget[pos].GetOrientation(), 20.0f, 20.0f); temp->SetOrientation(3); } } 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 83daa6e35a2..e3720503d0a 100644 --- a/src/server/scripts/Northrend/CrusadersColiseum/TrialOfTheCrusader/boss_northrend_beasts.cpp +++ b/src/server/scripts/Northrend/CrusadersColiseum/TrialOfTheCrusader/boss_northrend_beasts.cpp @@ -390,7 +390,7 @@ class npc_snobold_vassal : public CreatureScript else if (Unit* target2 = SelectTarget(SELECT_TARGET_RANDOM, 0, 0.0f, true)) { _targetGUID = target2->GetGUID(); - me->GetMotionMaster()->MoveJump(target2->GetPositionX(), target2->GetPositionY(), target2->GetPositionZ(), 15.0f, 15.0f); + me->GetMotionMaster()->MoveJump(*target2, 15.0f, 15.0f); } } } @@ -981,7 +981,7 @@ class boss_icehowl : public CreatureScript events.ScheduleEvent(EVENT_WHIRL, urand(15*IN_MILLISECONDS, 30*IN_MILLISECONDS)); return; case EVENT_MASSIVE_CRASH: - me->GetMotionMaster()->MoveJump(ToCCommonLoc[1].GetPositionX(), ToCCommonLoc[1].GetPositionY(), ToCCommonLoc[1].GetPositionZ(), 20.0f, 20.0f, 0); // 1: Middle of the room + me->GetMotionMaster()->MoveJump(ToCCommonLoc[1], 20.0f, 20.0f, 0); // 1: Middle of the room SetCombatMovement(false); me->AttackStop(); _stage = 7; //Invalid (Do nothing more than move) @@ -1034,7 +1034,7 @@ class boss_icehowl : public CreatureScript _trampleTargetY = target->GetPositionY(); _trampleTargetZ = target->GetPositionZ(); // 2: Hop Backwards - me->GetMotionMaster()->MoveJump(2*me->GetPositionX() - _trampleTargetX, 2*me->GetPositionY() - _trampleTargetY, me->GetPositionZ(), 30.0f, 20.0f, 0); + me->GetMotionMaster()->MoveJump(2*me->GetPositionX() - _trampleTargetX, 2*me->GetPositionY() - _trampleTargetY, me->GetPositionZ(), me->GetOrientation(), 30.0f, 20.0f, 0); _stage = 7; //Invalid (Do nothing more than move) } else 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 96bd0aaa35e..5410f403ab9 100644 --- a/src/server/scripts/Northrend/FrozenHalls/PitOfSaron/boss_scourgelord_tyrannus.cpp +++ b/src/server/scripts/Northrend/FrozenHalls/PitOfSaron/boss_scourgelord_tyrannus.cpp @@ -22,6 +22,7 @@ #include "pit_of_saron.h" #include "Vehicle.h" #include "Player.h" +#include "PlayerAI.h" enum Yells { @@ -438,9 +439,10 @@ class spell_tyrannus_overlord_brand : public SpellScriptLoader if (GetTarget()->GetTypeId() != TYPEID_PLAYER) return; - oldAI = GetTarget()->GetAI(); - oldAIState = GetTarget()->IsAIEnabled; - GetTarget()->SetAI(new player_overlord_brandAI(GetTarget()->ToPlayer(), GetCasterGUID())); + Player* pTarget = GetTarget()->ToPlayer(); + oldAI = pTarget->AI(); + oldAIState = pTarget->IsAIEnabled; + GetTarget()->SetAI(new player_overlord_brandAI(pTarget, GetCasterGUID())); GetTarget()->IsAIEnabled = true; } @@ -450,7 +452,7 @@ class spell_tyrannus_overlord_brand : public SpellScriptLoader return; GetTarget()->IsAIEnabled = oldAIState; - UnitAI* thisAI = GetTarget()->GetAI(); + PlayerAI* thisAI = GetTarget()->ToPlayer()->AI(); GetTarget()->SetAI(oldAI); delete thisAI; } @@ -461,7 +463,7 @@ class spell_tyrannus_overlord_brand : public SpellScriptLoader AfterEffectRemove += AuraEffectRemoveFn(spell_tyrannus_overlord_brand_AuraScript::OnRemove, EFFECT_0, SPELL_AURA_DUMMY, AURA_EFFECT_HANDLE_REAL); } - UnitAI* oldAI; + PlayerAI* oldAI; bool oldAIState; }; diff --git a/src/server/scripts/Northrend/IcecrownCitadel/boss_deathbringer_saurfang.cpp b/src/server/scripts/Northrend/IcecrownCitadel/boss_deathbringer_saurfang.cpp index 7e9083115b8..3ea0de31764 100644 --- a/src/server/scripts/Northrend/IcecrownCitadel/boss_deathbringer_saurfang.cpp +++ b/src/server/scripts/Northrend/IcecrownCitadel/boss_deathbringer_saurfang.cpp @@ -598,7 +598,7 @@ class boss_deathbringer_saurfang : public CreatureScript if (target->GetTransport()) return false; - return true; + return BossAI::CanAIAttack(target); } static uint32 const FightWonValue; 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 755bbd759e7..9fa624aaad3 100644 --- a/src/server/scripts/Northrend/IcecrownCitadel/boss_the_lich_king.cpp +++ b/src/server/scripts/Northrend/IcecrownCitadel/boss_the_lich_king.cpp @@ -285,6 +285,7 @@ enum Phases #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 TirionSpawn = {505.2118f, -2124.353f, 840.9403f, 3.141593f}; Position const TirionIntro = {489.2970f, -2124.840f, 840.8569f, 0.0f}; Position const TirionCharge = {482.9019f, -2124.479f, 840.8570f, 0.0f}; Position const LichKingIntro[3] = @@ -514,13 +515,33 @@ class boss_the_lich_king : public CreatureScript _vileSpiritExplosions = 0; } - void Reset() override + void InitializeAI() override + { + SetupEncounter(); + } + + void JustRespawned() override + { + SetupEncounter(); + } + + void SetupEncounter() { _Reset(); me->SetReactState(REACT_PASSIVE); events.SetPhase(PHASE_INTRO); Initialize(); SetEquipmentSlots(true); + + // Reset The Frozen Throne gameobjects + FrozenThroneResetWorker reset; + Trinity::GameObjectWorker<FrozenThroneResetWorker> worker(me, reset); + me->VisitNearbyGridObject(333.0f, worker); + + // Reset any light override + me->GetMap()->SetZoneOverrideLight(AREA_THE_FROZEN_THRONE, 0, 5000); + + me->SummonCreature(NPC_HIGHLORD_TIRION_FORDRING_LK, TirionSpawn, TEMPSUMMON_MANUAL_DESPAWN); } void JustDied(Unit* /*killer*/) override @@ -556,40 +577,21 @@ class boss_the_lich_king : public CreatureScript events.ScheduleEvent(EVENT_SHADOW_TRAP, 15500, 0, PHASE_ONE); } - void JustReachedHome() override - { - _JustReachedHome(); - instance->SetBossState(DATA_THE_LICH_KING, NOT_STARTED); - - // Reset The Frozen Throne gameobjects - FrozenThroneResetWorker reset; - Trinity::GameObjectWorker<FrozenThroneResetWorker> worker(me, reset); - me->VisitNearbyGridObject(333.0f, worker); - - // Restore Tirion's gossip only after The Lich King fully resets to prevent - // restarting the encounter while LK still runs back to spawn point - if (Creature* tirion = ObjectAccessor::GetCreature(*me, instance->GetGuidData(DATA_HIGHLORD_TIRION_FORDRING))) - tirion->SetFlag(UNIT_NPC_FLAGS, UNIT_NPC_FLAG_GOSSIP); - - // Reset any light override - me->GetMap()->SetZoneOverrideLight(AREA_THE_FROZEN_THRONE, 0, 5000); - } - bool CanAIAttack(Unit const* target) const override { // The Lich King must not select targets in frostmourne room if he killed everyone outside - return !target->HasAura(SPELL_IN_FROSTMOURNE_ROOM); + return !target->HasAura(SPELL_IN_FROSTMOURNE_ROOM) && BossAI::CanAIAttack(target); } - void EnterEvadeMode(EvadeReason why) override + void EnterEvadeMode(EvadeReason /*why*/) override { - instance->SetBossState(DATA_THE_LICH_KING, FAIL); - BossAI::EnterEvadeMode(why); if (Creature* tirion = ObjectAccessor::GetCreature(*me, instance->GetGuidData(DATA_HIGHLORD_TIRION_FORDRING))) - tirion->AI()->EnterEvadeMode(); + tirion->DespawnOrUnsummon(); DoCastAOE(SPELL_KILL_FROSTMOURNE_PLAYERS); EntryCheckPredicate pred(NPC_STRANGULATE_VEHICLE); summons.DoAction(ACTION_TELEPORT_BACK, pred); + summons.DespawnAll(); + _DespawnAtEvade(); } void KilledUnit(Unit* victim) override @@ -770,6 +772,8 @@ class boss_the_lich_king : public CreatureScript case NPC_STRANGULATE_VEHICLE: summons.Summon(summon); return; + case NPC_HIGHLORD_TIRION_FORDRING_LK: + return; default: break; } @@ -1153,6 +1157,7 @@ class npc_tirion_fordring_tft : public CreatureScript _events.Reset(); if (_instance->GetBossState(DATA_THE_LICH_KING) == DONE) me->RemoveFlag(UNIT_NPC_FLAGS, UNIT_NPC_FLAG_GOSSIP); + me->LoadEquipment(1); } void MovementInform(uint32 type, uint32 id) override diff --git a/src/server/scripts/Northrend/Naxxramas/boss_gothik.cpp b/src/server/scripts/Northrend/Naxxramas/boss_gothik.cpp index 81f1e071da0..be12894ebea 100644 --- a/src/server/scripts/Northrend/Naxxramas/boss_gothik.cpp +++ b/src/server/scripts/Northrend/Naxxramas/boss_gothik.cpp @@ -375,8 +375,12 @@ class boss_gothik : public CreatureScript _gateIsOpen = true; for (ObjectGuid summonGuid : summons) + { if (Creature* summon = ObjectAccessor::GetCreature(*me, summonGuid)) summon->AI()->DoAction(ACTION_GATE_OPENED); + if (summons.empty()) // ACTION_GATE_OPENED may cause an evade, despawning summons and invalidating our iterator + break; + } } void DamageTaken(Unit* /*who*/, uint32& damage) override 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 01c4704592f..98827fb3e00 100644 --- a/src/server/scripts/Northrend/Ulduar/Ulduar/boss_flame_leviathan.cpp +++ b/src/server/scripts/Northrend/Ulduar/Ulduar/boss_flame_leviathan.cpp @@ -334,7 +334,8 @@ class boss_flame_leviathan : public CreatureScript void SpellHit(Unit* /*caster*/, SpellInfo const* spell) override { if (spell->Id == SPELL_START_THE_ENGINE) - ASSERT_NOTNULL(me->GetVehicleKit())->InstallAllAccessories(false); + if (Vehicle* vehicleKit = me->GetVehicleKit()) + vehicleKit->InstallAllAccessories(false); if (spell->Id == SPELL_ELECTROSHOCK) me->InterruptSpell(CURRENT_CHANNELED_SPELL); @@ -1768,9 +1769,7 @@ class spell_vehicle_throw_passenger : public SpellScriptLoader else { passenger->ExitVehicle(); - float x, y, z; - targets.GetDstPos()->GetPosition(x, y, z); - passenger->GetMotionMaster()->MoveJump(x, y, z, targets.GetSpeedXY(), targets.GetSpeedZ()); + passenger->GetMotionMaster()->MoveJump(*targets.GetDstPos(), targets.GetSpeedXY(), targets.GetSpeedZ()); } } } diff --git a/src/server/scripts/Northrend/Ulduar/Ulduar/boss_mimiron.cpp b/src/server/scripts/Northrend/Ulduar/Ulduar/boss_mimiron.cpp index f435c669935..e694433c614 100644 --- a/src/server/scripts/Northrend/Ulduar/Ulduar/boss_mimiron.cpp +++ b/src/server/scripts/Northrend/Ulduar/Ulduar/boss_mimiron.cpp @@ -444,7 +444,7 @@ class boss_mimiron : public CreatureScript DoCastAOE(SPELL_DESPAWN_ASSAULT_BOTS); me->ExitVehicle(); // ExitVehicle() offset position is not implemented, so we make up for that with MoveJump()... - me->GetMotionMaster()->MoveJump(me->GetPositionX() + (10.f * std::cos(me->GetOrientation())), me->GetPositionY() + (10.f * std::sin(me->GetOrientation())), me->GetPositionZ(), 10.f, 5.f); + me->GetMotionMaster()->MoveJump(me->GetPositionX() + (10.f * std::cos(me->GetOrientation())), me->GetPositionY() + (10.f * std::sin(me->GetOrientation())), me->GetPositionZ(), me->GetOrientation(), 10.f, 5.f); events.ScheduleEvent(EVENT_OUTTRO_1, 7000); } diff --git a/src/server/scripts/Northrend/UtgardeKeep/UtgardePinnacle/boss_skadi.cpp b/src/server/scripts/Northrend/UtgardeKeep/UtgardePinnacle/boss_skadi.cpp index 77b376bf7d5..d7b65093898 100644 --- a/src/server/scripts/Northrend/UtgardeKeep/UtgardePinnacle/boss_skadi.cpp +++ b/src/server/scripts/Northrend/UtgardeKeep/UtgardePinnacle/boss_skadi.cpp @@ -238,7 +238,7 @@ public: me->SetInCombatWithZone(); instance->SetBossState(DATA_SKADI_THE_RUTHLESS, IN_PROGRESS); instance->DoStartTimedAchievement(ACHIEVEMENT_TIMED_TYPE_EVENT, ACHIEV_TIMED_START_EVENT); - me->GetMotionMaster()->MoveJump(Location[0].GetPositionX(), Location[0].GetPositionY(), Location[0].GetPositionZ(), 5.0f, 10.0f); + me->GetMotionMaster()->MoveJump(Location[0], 5.0f, 10.0f); me->SetWalk(false); m_uiMountTimer = 1000; Summons.DespawnEntry(NPC_GRAUF); @@ -289,7 +289,7 @@ public: pGrauf->GetMotionMaster()->MoveFall(); pGrauf->HandleEmoteCommand(EMOTE_ONESHOT_FLYDEATH); } - me->GetMotionMaster()->MoveJump(Location[4].GetPositionX(), Location[4].GetPositionY(), Location[4].GetPositionZ(), 5.0f, 10.0f); + me->GetMotionMaster()->MoveJump(Location[4], 5.0f, 10.0f); me->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE | UNIT_FLAG_NON_ATTACKABLE); Talk(SAY_DRAKE_DEATH); m_uiCrushTimer = 8000; diff --git a/src/server/scripts/Northrend/isle_of_conquest.cpp b/src/server/scripts/Northrend/isle_of_conquest.cpp index 14d862eca39..68121e940c9 100644 --- a/src/server/scripts/Northrend/isle_of_conquest.cpp +++ b/src/server/scripts/Northrend/isle_of_conquest.cpp @@ -206,7 +206,7 @@ class spell_ioc_parachute_ic : public SpellScriptLoader class StartLaunchEvent : public BasicEvent { public: - StartLaunchEvent(float x, float y, float z, ObjectGuid::LowType lowGuid) : _x(x), _y(y), _z(z), _lowGuid(lowGuid) + StartLaunchEvent(Position const& pos, ObjectGuid::LowType lowGuid) : _pos(pos), _lowGuid(lowGuid) { } @@ -218,15 +218,15 @@ class StartLaunchEvent : public BasicEvent player->AddAura(SPELL_LAUNCH_NO_FALLING_DAMAGE, player); // prevents falling damage float speedZ = 10.0f; - float dist = player->GetExactDist2d(_x, _y); + float dist = player->GetExactDist2d(&_pos); player->ExitVehicle(); - player->GetMotionMaster()->MoveJump(_x, _y, _z, dist, speedZ); + player->GetMotionMaster()->MoveJump(_pos, dist, speedZ, EVENT_JUMP, true); return true; } private: - float _x, _y, _z; + Position _pos; ObjectGuid::LowType _lowGuid; }; @@ -244,11 +244,7 @@ class spell_ioc_launch : public SpellScriptLoader if (!GetCaster()->ToCreature() || !GetExplTargetDest()) return; - float x, y, z; - x = GetExplTargetDest()->GetPositionX(); - y = GetExplTargetDest()->GetPositionY(); - z = GetExplTargetDest()->GetPositionZ(); - GetCaster()->ToCreature()->m_Events.AddEvent(new StartLaunchEvent(x, y, z, GetHitPlayer()->GetGUID().GetCounter()), GetCaster()->ToCreature()->m_Events.CalculateTime(2500)); + GetCaster()->ToCreature()->m_Events.AddEvent(new StartLaunchEvent(*GetExplTargetDest(), GetHitPlayer()->GetGUID().GetCounter()), GetCaster()->ToCreature()->m_Events.CalculateTime(2500)); } void Register() override diff --git a/src/server/scripts/Northrend/northrend_script_loader.cpp b/src/server/scripts/Northrend/northrend_script_loader.cpp new file mode 100644 index 00000000000..7d104b85f6d --- /dev/null +++ b/src/server/scripts/Northrend/northrend_script_loader.cpp @@ -0,0 +1,374 @@ +/* + * Copyright (C) 2008-2016 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/>. + */ + +// This is where scripts' loading functions should be declared: +void AddSC_boss_slad_ran(); +void AddSC_boss_moorabi(); +void AddSC_boss_drakkari_colossus(); +void AddSC_boss_gal_darah(); +void AddSC_boss_eck(); +void AddSC_instance_gundrak(); + +// Azjol-Nerub - Azjol-Nerub +void AddSC_boss_krik_thir(); +void AddSC_boss_hadronox(); +void AddSC_boss_anub_arak(); +void AddSC_instance_azjol_nerub(); + +// Azjol-Nerub - Ahn'kahet +void AddSC_boss_elder_nadox(); +void AddSC_boss_taldaram(); +void AddSC_boss_amanitar(); +void AddSC_boss_jedoga_shadowseeker(); +void AddSC_boss_volazj(); +void AddSC_instance_ahnkahet(); + +// Drak'Tharon Keep +void AddSC_boss_trollgore(); +void AddSC_boss_novos(); +void AddSC_boss_king_dred(); +void AddSC_boss_tharon_ja(); +void AddSC_instance_drak_tharon_keep(); + +void AddSC_boss_argent_challenge(); //Trial of the Champion +void AddSC_boss_black_knight(); +void AddSC_boss_grand_champions(); +void AddSC_instance_trial_of_the_champion(); +void AddSC_trial_of_the_champion(); +void AddSC_boss_anubarak_trial(); //Trial of the Crusader +void AddSC_boss_faction_champions(); +void AddSC_boss_jaraxxus(); +void AddSC_boss_northrend_beasts(); +void AddSC_boss_twin_valkyr(); +void AddSC_trial_of_the_crusader(); +void AddSC_instance_trial_of_the_crusader(); +void AddSC_boss_anubrekhan(); //Naxxramas +void AddSC_boss_maexxna(); +void AddSC_boss_patchwerk(); +void AddSC_boss_grobbulus(); +void AddSC_boss_razuvious(); +void AddSC_boss_kelthuzad(); +void AddSC_boss_loatheb(); +void AddSC_boss_noth(); +void AddSC_boss_gluth(); +void AddSC_boss_sapphiron(); +void AddSC_boss_four_horsemen(); +void AddSC_boss_faerlina(); +void AddSC_boss_heigan(); +void AddSC_boss_gothik(); +void AddSC_boss_thaddius(); +void AddSC_instance_naxxramas(); +void AddSC_boss_nexus_commanders(); // The Nexus Nexus +void AddSC_boss_magus_telestra(); +void AddSC_boss_anomalus(); +void AddSC_boss_ormorok(); +void AddSC_boss_keristrasza(); +void AddSC_instance_nexus(); +void AddSC_boss_drakos(); //The Nexus The Oculus +void AddSC_boss_urom(); +void AddSC_boss_varos(); +void AddSC_boss_eregos(); +void AddSC_instance_oculus(); +void AddSC_oculus(); +void AddSC_boss_malygos(); // The Nexus: Eye of Eternity +void AddSC_instance_eye_of_eternity(); +void AddSC_boss_sartharion(); //Obsidian Sanctum +void AddSC_obsidian_sanctum(); +void AddSC_instance_obsidian_sanctum(); +void AddSC_boss_bjarngrim(); //Ulduar Halls of Lightning +void AddSC_boss_loken(); +void AddSC_boss_ionar(); +void AddSC_boss_volkhan(); +void AddSC_instance_halls_of_lightning(); +void AddSC_boss_maiden_of_grief(); //Ulduar Halls of Stone +void AddSC_boss_krystallus(); +void AddSC_boss_sjonnir(); +void AddSC_instance_halls_of_stone(); +void AddSC_halls_of_stone(); +void AddSC_boss_auriaya(); //Ulduar Ulduar +void AddSC_boss_flame_leviathan(); +void AddSC_boss_ignis(); +void AddSC_boss_razorscale(); +void AddSC_boss_xt002(); +void AddSC_boss_kologarn(); +void AddSC_boss_assembly_of_iron(); +void AddSC_boss_general_vezax(); +void AddSC_boss_mimiron(); +void AddSC_boss_hodir(); +void AddSC_boss_freya(); +void AddSC_boss_yogg_saron(); +void AddSC_boss_algalon_the_observer(); +void AddSC_instance_ulduar(); + +// Utgarde Keep - Utgarde Keep +void AddSC_boss_keleseth(); +void AddSC_boss_skarvald_dalronn(); +void AddSC_boss_ingvar_the_plunderer(); +void AddSC_instance_utgarde_keep(); +void AddSC_utgarde_keep(); + +// Utgarde Keep - Utgarde Pinnacle +void AddSC_boss_svala(); +void AddSC_boss_palehoof(); +void AddSC_boss_skadi(); +void AddSC_boss_ymiron(); +void AddSC_instance_utgarde_pinnacle(); + +// Vault of Archavon +void AddSC_boss_archavon(); +void AddSC_boss_emalon(); +void AddSC_boss_koralon(); +void AddSC_boss_toravon(); +void AddSC_instance_vault_of_archavon(); + +void AddSC_boss_cyanigosa(); //Violet Hold +void AddSC_boss_erekem(); +void AddSC_boss_ichoron(); +void AddSC_boss_lavanthor(); +void AddSC_boss_moragg(); +void AddSC_boss_xevozz(); +void AddSC_boss_zuramat(); +void AddSC_instance_violet_hold(); +void AddSC_violet_hold(); +void AddSC_instance_forge_of_souls(); //Forge of Souls +void AddSC_forge_of_souls(); +void AddSC_boss_bronjahm(); +void AddSC_boss_devourer_of_souls(); +void AddSC_instance_pit_of_saron(); //Pit of Saron +void AddSC_pit_of_saron(); +void AddSC_boss_garfrost(); +void AddSC_boss_ick(); +void AddSC_boss_tyrannus(); +void AddSC_instance_halls_of_reflection(); // Halls of Reflection +void AddSC_halls_of_reflection(); +void AddSC_boss_falric(); +void AddSC_boss_marwyn(); +void AddSC_boss_lord_marrowgar(); // Icecrown Citadel +void AddSC_boss_lady_deathwhisper(); +void AddSC_boss_icecrown_gunship_battle(); +void AddSC_boss_deathbringer_saurfang(); +void AddSC_boss_festergut(); +void AddSC_boss_rotface(); +void AddSC_boss_professor_putricide(); +void AddSC_boss_blood_prince_council(); +void AddSC_boss_blood_queen_lana_thel(); +void AddSC_boss_valithria_dreamwalker(); +void AddSC_boss_sindragosa(); +void AddSC_boss_the_lich_king(); +void AddSC_icecrown_citadel_teleport(); +void AddSC_instance_icecrown_citadel(); +void AddSC_icecrown_citadel(); +void AddSC_instance_ruby_sanctum(); // Ruby Sanctum +void AddSC_ruby_sanctum(); +void AddSC_boss_baltharus_the_warborn(); +void AddSC_boss_saviana_ragefire(); +void AddSC_boss_general_zarithrian(); +void AddSC_boss_halion(); + +void AddSC_dalaran(); +void AddSC_borean_tundra(); +void AddSC_dragonblight(); +void AddSC_grizzly_hills(); +void AddSC_howling_fjord(); +void AddSC_icecrown(); +void AddSC_sholazar_basin(); +void AddSC_storm_peaks(); +void AddSC_wintergrasp(); +void AddSC_zuldrak(); +void AddSC_crystalsong_forest(); +void AddSC_isle_of_conquest(); + +// The name of this function should match: +// void Add${NameOfDirectory}Scripts() +void AddNorthrendScripts() +{ + AddSC_boss_slad_ran(); //Gundrak + AddSC_boss_moorabi(); + AddSC_boss_drakkari_colossus(); + AddSC_boss_gal_darah(); + AddSC_boss_eck(); + AddSC_instance_gundrak(); + + // Azjol-Nerub - Ahn'kahet + AddSC_boss_elder_nadox(); + AddSC_boss_taldaram(); + AddSC_boss_amanitar(); + AddSC_boss_jedoga_shadowseeker(); + AddSC_boss_volazj(); + AddSC_instance_ahnkahet(); + + // Azjol-Nerub - Azjol-Nerub + AddSC_boss_krik_thir(); + AddSC_boss_hadronox(); + AddSC_boss_anub_arak(); + AddSC_instance_azjol_nerub(); + + // Drak'Tharon Keep + AddSC_boss_trollgore(); + AddSC_boss_novos(); + AddSC_boss_king_dred(); + AddSC_boss_tharon_ja(); + AddSC_instance_drak_tharon_keep(); + + AddSC_boss_argent_challenge(); //Trial of the Champion + AddSC_boss_black_knight(); + AddSC_boss_grand_champions(); + AddSC_instance_trial_of_the_champion(); + AddSC_trial_of_the_champion(); + AddSC_boss_anubarak_trial(); //Trial of the Crusader + AddSC_boss_faction_champions(); + AddSC_boss_jaraxxus(); + AddSC_trial_of_the_crusader(); + AddSC_boss_twin_valkyr(); + AddSC_boss_northrend_beasts(); + AddSC_instance_trial_of_the_crusader(); + AddSC_boss_anubrekhan(); //Naxxramas + AddSC_boss_maexxna(); + AddSC_boss_patchwerk(); + AddSC_boss_grobbulus(); + AddSC_boss_razuvious(); + AddSC_boss_kelthuzad(); + AddSC_boss_loatheb(); + AddSC_boss_noth(); + AddSC_boss_gluth(); + AddSC_boss_sapphiron(); + AddSC_boss_four_horsemen(); + AddSC_boss_faerlina(); + AddSC_boss_heigan(); + AddSC_boss_gothik(); + AddSC_boss_thaddius(); + AddSC_instance_naxxramas(); + AddSC_boss_nexus_commanders(); // The Nexus Nexus + AddSC_boss_magus_telestra(); + AddSC_boss_anomalus(); + AddSC_boss_ormorok(); + AddSC_boss_keristrasza(); + AddSC_instance_nexus(); + AddSC_boss_drakos(); //The Nexus The Oculus + AddSC_boss_urom(); + AddSC_boss_varos(); + AddSC_boss_eregos(); + AddSC_instance_oculus(); + AddSC_oculus(); + AddSC_boss_malygos(); // The Nexus: Eye of Eternity + AddSC_instance_eye_of_eternity(); + AddSC_boss_sartharion(); //Obsidian Sanctum + AddSC_obsidian_sanctum(); + AddSC_instance_obsidian_sanctum(); + AddSC_boss_bjarngrim(); //Ulduar Halls of Lightning + AddSC_boss_loken(); + AddSC_boss_ionar(); + AddSC_boss_volkhan(); + AddSC_instance_halls_of_lightning(); + AddSC_boss_maiden_of_grief(); //Ulduar Halls of Stone + AddSC_boss_krystallus(); + AddSC_boss_sjonnir(); + AddSC_instance_halls_of_stone(); + AddSC_halls_of_stone(); + AddSC_boss_auriaya(); //Ulduar Ulduar + AddSC_boss_flame_leviathan(); + AddSC_boss_ignis(); + AddSC_boss_razorscale(); + AddSC_boss_xt002(); + AddSC_boss_general_vezax(); + AddSC_boss_assembly_of_iron(); + AddSC_boss_kologarn(); + AddSC_boss_mimiron(); + AddSC_boss_hodir(); + AddSC_boss_freya(); + AddSC_boss_yogg_saron(); + AddSC_boss_algalon_the_observer(); + AddSC_instance_ulduar(); + + // Utgarde Keep - Utgarde Keep + AddSC_boss_keleseth(); + AddSC_boss_skarvald_dalronn(); + AddSC_boss_ingvar_the_plunderer(); + AddSC_instance_utgarde_keep(); + AddSC_utgarde_keep(); + + // Utgarde Keep - Utgarde Pinnacle + AddSC_boss_svala(); + AddSC_boss_palehoof(); + AddSC_boss_skadi(); + AddSC_boss_ymiron(); + AddSC_instance_utgarde_pinnacle(); + + // Vault of Archavon + AddSC_boss_archavon(); + AddSC_boss_emalon(); + AddSC_boss_koralon(); + AddSC_boss_toravon(); + AddSC_instance_vault_of_archavon(); + + AddSC_boss_cyanigosa(); //Violet Hold + AddSC_boss_erekem(); + AddSC_boss_ichoron(); + AddSC_boss_lavanthor(); + AddSC_boss_moragg(); + AddSC_boss_xevozz(); + AddSC_boss_zuramat(); + AddSC_instance_violet_hold(); + AddSC_violet_hold(); + AddSC_instance_forge_of_souls(); //Forge of Souls + AddSC_forge_of_souls(); + AddSC_boss_bronjahm(); + AddSC_boss_devourer_of_souls(); + AddSC_instance_pit_of_saron(); //Pit of Saron + AddSC_pit_of_saron(); + AddSC_boss_garfrost(); + AddSC_boss_ick(); + AddSC_boss_tyrannus(); + AddSC_instance_halls_of_reflection(); // Halls of Reflection + AddSC_halls_of_reflection(); + AddSC_boss_falric(); + AddSC_boss_marwyn(); + AddSC_boss_lord_marrowgar(); // Icecrown Citadel + AddSC_boss_lady_deathwhisper(); + AddSC_boss_icecrown_gunship_battle(); + AddSC_boss_deathbringer_saurfang(); + AddSC_boss_festergut(); + AddSC_boss_rotface(); + AddSC_boss_professor_putricide(); + AddSC_boss_blood_prince_council(); + AddSC_boss_blood_queen_lana_thel(); + AddSC_boss_valithria_dreamwalker(); + AddSC_boss_sindragosa(); + AddSC_boss_the_lich_king(); + AddSC_icecrown_citadel_teleport(); + AddSC_instance_icecrown_citadel(); + AddSC_icecrown_citadel(); + AddSC_instance_ruby_sanctum(); // Ruby Sanctum + AddSC_ruby_sanctum(); + AddSC_boss_baltharus_the_warborn(); + AddSC_boss_saviana_ragefire(); + AddSC_boss_general_zarithrian(); + AddSC_boss_halion(); + + AddSC_dalaran(); + AddSC_borean_tundra(); + AddSC_dragonblight(); + AddSC_grizzly_hills(); + AddSC_howling_fjord(); + AddSC_icecrown(); + AddSC_sholazar_basin(); + AddSC_storm_peaks(); + AddSC_wintergrasp(); + AddSC_zuldrak(); + AddSC_crystalsong_forest(); + AddSC_isle_of_conquest(); +} diff --git a/src/server/scripts/OutdoorPvP/CMakeLists.txt b/src/server/scripts/OutdoorPvP/CMakeLists.txt deleted file mode 100644 index 91ce4ce4186..00000000000 --- a/src/server/scripts/OutdoorPvP/CMakeLists.txt +++ /dev/null @@ -1,27 +0,0 @@ -# Copyright (C) 2008-2016 TrinityCore <http://www.trinitycore.org/> -# -# This file is free software; as a special exception the author gives -# unlimited permission to copy and/or distribute it, with or without -# modifications, as long as this notice is preserved. -# -# This program is distributed in the hope that it will be useful, but -# WITHOUT ANY WARRANTY, to the extent permitted by law; without even the -# implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. - -set(scripts_STAT_SRCS - ${scripts_STAT_SRCS} - OutdoorPvP/OutdoorPvPTF.cpp - OutdoorPvP/OutdoorPvPSI.cpp - OutdoorPvP/OutdoorPvPSI.h - OutdoorPvP/OutdoorPvPZM.cpp - OutdoorPvP/OutdoorPvPNA.cpp - OutdoorPvP/OutdoorPvPHP.cpp - OutdoorPvP/OutdoorPvPTF.h - OutdoorPvP/OutdoorPvPEP.h - OutdoorPvP/OutdoorPvPEP.cpp - OutdoorPvP/OutdoorPvPHP.h - OutdoorPvP/OutdoorPvPZM.h - OutdoorPvP/OutdoorPvPNA.h -) - -message(" -> Prepared: Outdoor PVP Zones") diff --git a/src/server/scripts/OutdoorPvP/OutdoorPvPScriptLoader.cpp b/src/server/scripts/OutdoorPvP/OutdoorPvPScriptLoader.cpp new file mode 100644 index 00000000000..ebf29910046 --- /dev/null +++ b/src/server/scripts/OutdoorPvP/OutdoorPvPScriptLoader.cpp @@ -0,0 +1,36 @@ +/* + * Copyright (C) 2008-2016 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/>. + */ + +// This is where scripts' loading functions should be declared: +void AddSC_outdoorpvp_ep(); +void AddSC_outdoorpvp_hp(); +void AddSC_outdoorpvp_na(); +void AddSC_outdoorpvp_si(); +void AddSC_outdoorpvp_tf(); +void AddSC_outdoorpvp_zm(); + +// The name of this function should match: +// void Add${NameOfDirectory}Scripts() +void AddOutdoorPvPScripts() +{ + AddSC_outdoorpvp_ep(); + AddSC_outdoorpvp_hp(); + AddSC_outdoorpvp_na(); + AddSC_outdoorpvp_si(); + AddSC_outdoorpvp_tf(); + AddSC_outdoorpvp_zm(); +} diff --git a/src/server/scripts/Outland/CMakeLists.txt b/src/server/scripts/Outland/CMakeLists.txt deleted file mode 100644 index 55b0452fb0b..00000000000 --- a/src/server/scripts/Outland/CMakeLists.txt +++ /dev/null @@ -1,128 +0,0 @@ -# Copyright (C) 2008-2016 TrinityCore <http://www.trinitycore.org/> -# -# This file is free software; as a special exception the author gives -# unlimited permission to copy and/or distribute it, with or without -# modifications, as long as this notice is preserved. -# -# This program is distributed in the hope that it will be useful, but -# WITHOUT ANY WARRANTY, to the extent permitted by law; without even the -# implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. - -set(scripts_STAT_SRCS - ${scripts_STAT_SRCS} - Outland/zone_nagrand.cpp - Outland/HellfireCitadel/MagtheridonsLair/magtheridons_lair.h - Outland/HellfireCitadel/MagtheridonsLair/instance_magtheridons_lair.cpp - Outland/HellfireCitadel/MagtheridonsLair/boss_magtheridon.cpp - Outland/HellfireCitadel/HellfireRamparts/instance_hellfire_ramparts.cpp - Outland/HellfireCitadel/HellfireRamparts/boss_omor_the_unscarred.cpp - Outland/HellfireCitadel/HellfireRamparts/boss_watchkeeper_gargolmar.cpp - Outland/HellfireCitadel/HellfireRamparts/boss_vazruden_the_herald.cpp - Outland/HellfireCitadel/HellfireRamparts/hellfire_ramparts.h - Outland/HellfireCitadel/BloodFurnace/boss_the_maker.cpp - Outland/HellfireCitadel/BloodFurnace/boss_kelidan_the_breaker.cpp - Outland/HellfireCitadel/BloodFurnace/blood_furnace.h - Outland/HellfireCitadel/BloodFurnace/instance_blood_furnace.cpp - Outland/HellfireCitadel/BloodFurnace/boss_broggok.cpp - Outland/HellfireCitadel/ShatteredHalls/shattered_halls.h - Outland/HellfireCitadel/ShatteredHalls/boss_warchief_kargath_bladefist.cpp - Outland/HellfireCitadel/ShatteredHalls/boss_nethekurse.cpp - Outland/HellfireCitadel/ShatteredHalls/shattered_halls.cpp - Outland/HellfireCitadel/ShatteredHalls/instance_shattered_halls.cpp - Outland/HellfireCitadel/ShatteredHalls/boss_warbringer_omrogg.cpp - Outland/CoilfangReservoir/SteamVault/boss_mekgineer_steamrigger.cpp - Outland/CoilfangReservoir/SteamVault/instance_steam_vault.cpp - Outland/CoilfangReservoir/SteamVault/boss_hydromancer_thespia.cpp - Outland/CoilfangReservoir/SteamVault/boss_warlord_kalithresh.cpp - Outland/CoilfangReservoir/SteamVault/steam_vault.h - Outland/CoilfangReservoir/SerpentShrine/boss_hydross_the_unstable.cpp - Outland/CoilfangReservoir/SerpentShrine/boss_fathomlord_karathress.cpp - Outland/CoilfangReservoir/SerpentShrine/instance_serpent_shrine.cpp - Outland/CoilfangReservoir/SerpentShrine/serpent_shrine.h - Outland/CoilfangReservoir/SerpentShrine/boss_lady_vashj.cpp - Outland/CoilfangReservoir/SerpentShrine/boss_leotheras_the_blind.cpp - Outland/CoilfangReservoir/SerpentShrine/boss_lurker_below.cpp - Outland/CoilfangReservoir/SerpentShrine/boss_morogrim_tidewalker.cpp - Outland/CoilfangReservoir/TheSlavePens/instance_the_slave_pens.cpp - Outland/CoilfangReservoir/TheSlavePens/the_slave_pens.h - Outland/CoilfangReservoir/TheSlavePens/boss_mennu_the_betrayer.cpp - Outland/CoilfangReservoir/TheSlavePens/boss_rokmar_the_crackler.cpp - Outland/CoilfangReservoir/TheSlavePens/boss_quagmirran.cpp - Outland/CoilfangReservoir/TheUnderbog/instance_the_underbog.cpp - Outland/CoilfangReservoir/TheUnderbog/boss_hungarfen.cpp - Outland/CoilfangReservoir/TheUnderbog/boss_the_black_stalker.cpp - Outland/zone_shattrath_city.cpp - Outland/TempestKeep/Mechanar/boss_mechano_lord_capacitus.cpp - Outland/TempestKeep/Mechanar/boss_pathaleon_the_calculator.cpp - Outland/TempestKeep/Mechanar/boss_nethermancer_sepethrea.cpp - Outland/TempestKeep/Mechanar/mechanar.h - Outland/TempestKeep/Mechanar/boss_gatewatcher_gyrokill.cpp - Outland/TempestKeep/Mechanar/instance_mechanar.cpp - Outland/TempestKeep/Mechanar/boss_gatewatcher_ironhand.cpp - Outland/TempestKeep/Eye/the_eye.h - Outland/TempestKeep/Eye/instance_the_eye.cpp - Outland/TempestKeep/Eye/boss_void_reaver.cpp - Outland/TempestKeep/Eye/boss_astromancer.cpp - Outland/TempestKeep/Eye/boss_alar.cpp - Outland/TempestKeep/Eye/boss_kaelthas.cpp - Outland/TempestKeep/Eye/the_eye.cpp - Outland/TempestKeep/botanica/the_botanica.h - Outland/TempestKeep/botanica/instance_the_botanica.cpp - Outland/TempestKeep/botanica/boss_commander_sarannis.cpp - Outland/TempestKeep/botanica/boss_thorngrin_the_tender.cpp - Outland/TempestKeep/botanica/boss_high_botanist_freywinn.cpp - Outland/TempestKeep/botanica/boss_warp_splinter.cpp - Outland/TempestKeep/botanica/boss_laj.cpp - Outland/TempestKeep/arcatraz/boss_zereketh_the_unbound.cpp - Outland/TempestKeep/arcatraz/boss_dalliah_the_doomsayer.cpp - Outland/TempestKeep/arcatraz/boss_wrath_scryer_soccothrates.cpp - Outland/TempestKeep/arcatraz/boss_harbinger_skyriss.cpp - Outland/TempestKeep/arcatraz/instance_arcatraz.cpp - Outland/TempestKeep/arcatraz/arcatraz.h - Outland/TempestKeep/arcatraz/arcatraz.cpp - Outland/Auchindoun/AuchenaiCrypts/boss_shirrak_the_dead_watcher.cpp - Outland/Auchindoun/AuchenaiCrypts/boss_exarch_maladaar.cpp - Outland/Auchindoun/AuchenaiCrypts/instance_auchenai_crypts.cpp - Outland/Auchindoun/AuchenaiCrypts/auchenai_crypts.h - Outland/Auchindoun/ManaTombs/boss_pandemonius.cpp - Outland/Auchindoun/ManaTombs/boss_nexusprince_shaffar.cpp - Outland/Auchindoun/ManaTombs/instance_mana_tombs.cpp - Outland/Auchindoun/ManaTombs/mana_tombs.h - Outland/Auchindoun/SethekkHalls/boss_darkweaver_syth.cpp - Outland/Auchindoun/SethekkHalls/boss_talon_king_ikiss.cpp - Outland/Auchindoun/SethekkHalls/boss_anzu.cpp - Outland/Auchindoun/SethekkHalls/instance_sethekk_halls.cpp - Outland/Auchindoun/SethekkHalls/sethekk_halls.h - Outland/Auchindoun/ShadowLabyrinth/boss_ambassador_hellmaw.cpp - Outland/Auchindoun/ShadowLabyrinth/boss_blackheart_the_inciter.cpp - Outland/Auchindoun/ShadowLabyrinth/boss_grandmaster_vorpil.cpp - Outland/Auchindoun/ShadowLabyrinth/boss_murmur.cpp - Outland/Auchindoun/ShadowLabyrinth/instance_shadow_labyrinth.cpp - Outland/Auchindoun/ShadowLabyrinth/shadow_labyrinth.h - Outland/boss_doomwalker.cpp - Outland/zone_terokkar_forest.cpp - Outland/zone_hellfire_peninsula.cpp - Outland/boss_doomlord_kazzak.cpp - Outland/BlackTemple/boss_teron_gorefiend.cpp - Outland/BlackTemple/black_temple.h - Outland/BlackTemple/illidari_council.cpp - Outland/BlackTemple/boss_shade_of_akama.cpp - Outland/BlackTemple/boss_supremus.cpp - Outland/BlackTemple/black_temple.cpp - Outland/BlackTemple/boss_mother_shahraz.cpp - Outland/BlackTemple/instance_black_temple.cpp - Outland/BlackTemple/boss_reliquary_of_souls.cpp - Outland/BlackTemple/boss_warlord_najentus.cpp - Outland/BlackTemple/boss_gurtogg_bloodboil.cpp - Outland/BlackTemple/boss_illidan.cpp - Outland/zone_shadowmoon_valley.cpp - Outland/zone_blades_edge_mountains.cpp - Outland/GruulsLair/boss_high_king_maulgar.cpp - Outland/GruulsLair/boss_gruul.cpp - Outland/GruulsLair/gruuls_lair.h - Outland/GruulsLair/instance_gruuls_lair.cpp - Outland/zone_netherstorm.cpp - Outland/zone_zangarmarsh.cpp -) - -message(" -> Prepared: Outland") diff --git a/src/server/scripts/Outland/TempestKeep/Eye/boss_kaelthas.cpp b/src/server/scripts/Outland/TempestKeep/Eye/boss_kaelthas.cpp index e5812390bd2..be27932e6b4 100644 --- a/src/server/scripts/Outland/TempestKeep/Eye/boss_kaelthas.cpp +++ b/src/server/scripts/Outland/TempestKeep/Eye/boss_kaelthas.cpp @@ -144,6 +144,7 @@ enum Spells // Thaladred the Darkener spells SPELL_PSYCHIC_BLOW = 10689, SPELL_SILENCE = 30225, + SPELL_REND = 36965, // Lord Sanguinar spells SPELL_BELLOWING_ROAR = 40636, // Grand Astromancer Capernian spells @@ -881,11 +882,13 @@ class boss_thaladred_the_darkener : public CreatureScript { Gaze_Timer = 100; Silence_Timer = 20000; + Rend_Timer = 4000; PsychicBlow_Timer = 10000; } uint32 Gaze_Timer; uint32 Silence_Timer; + uint32 Rend_Timer; uint32 PsychicBlow_Timer; void Reset() override @@ -939,6 +942,15 @@ class boss_thaladred_the_darkener : public CreatureScript else Silence_Timer -= diff; + //Rend_Timer + if (Rend_Timer <= diff) + { + DoCastVictim(SPELL_REND); + Rend_Timer = 4000; + } + else + Rend_Timer -= diff; + //PsychicBlow_Timer if (PsychicBlow_Timer <= diff) { diff --git a/src/server/scripts/Outland/outland_script_loader.cpp b/src/server/scripts/Outland/outland_script_loader.cpp new file mode 100644 index 00000000000..91ba4e5689f --- /dev/null +++ b/src/server/scripts/Outland/outland_script_loader.cpp @@ -0,0 +1,256 @@ +/* + * Copyright (C) 2008-2016 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/>. + */ + +// This is where scripts' loading functions should be declared: +// Auchindoun - Auchenai Crypts +void AddSC_boss_shirrak_the_dead_watcher(); +void AddSC_boss_exarch_maladaar(); +void AddSC_instance_auchenai_crypts(); + +// Auchindoun - Mana Tombs +void AddSC_boss_pandemonius(); +void AddSC_boss_nexusprince_shaffar(); +void AddSC_instance_mana_tombs(); + +// Auchindoun - Sekketh Halls +void AddSC_boss_darkweaver_syth(); +void AddSC_boss_talon_king_ikiss(); +void AddSC_boss_anzu(); +void AddSC_instance_sethekk_halls(); + +// Auchindoun - Shadow Labyrinth +void AddSC_boss_ambassador_hellmaw(); +void AddSC_boss_blackheart_the_inciter(); +void AddSC_boss_grandmaster_vorpil(); +void AddSC_boss_murmur(); +void AddSC_instance_shadow_labyrinth(); + +// Black Temple +void AddSC_black_temple(); +void AddSC_boss_illidan(); +void AddSC_boss_shade_of_akama(); +void AddSC_boss_supremus(); +void AddSC_boss_gurtogg_bloodboil(); +void AddSC_boss_mother_shahraz(); +void AddSC_boss_reliquary_of_souls(); +void AddSC_boss_teron_gorefiend(); +void AddSC_boss_najentus(); +void AddSC_boss_illidari_council(); +void AddSC_instance_black_temple(); + +// Coilfang Reservoir - Serpent Shrine Cavern +void AddSC_boss_fathomlord_karathress(); +void AddSC_boss_hydross_the_unstable(); +void AddSC_boss_lady_vashj(); +void AddSC_boss_leotheras_the_blind(); +void AddSC_boss_morogrim_tidewalker(); +void AddSC_instance_serpentshrine_cavern(); +void AddSC_boss_the_lurker_below(); + +// Coilfang Reservoir - The Steam Vault +void AddSC_boss_hydromancer_thespia(); +void AddSC_boss_mekgineer_steamrigger(); +void AddSC_boss_warlord_kalithresh(); +void AddSC_instance_steam_vault(); + +// Coilfang Reservoir - The Slave Pens +void AddSC_instance_the_slave_pens(); +void AddSC_boss_mennu_the_betrayer(); +void AddSC_boss_rokmar_the_crackler(); +void AddSC_boss_quagmirran(); + +// Coilfang Reservoir - The Underbog +void AddSC_instance_the_underbog(); +void AddSC_boss_hungarfen(); +void AddSC_boss_the_black_stalker(); + +// Gruul's Lair +void AddSC_boss_gruul(); +void AddSC_boss_high_king_maulgar(); +void AddSC_instance_gruuls_lair(); +void AddSC_boss_broggok(); //HC Blood Furnace +void AddSC_boss_kelidan_the_breaker(); +void AddSC_boss_the_maker(); +void AddSC_instance_blood_furnace(); +void AddSC_boss_magtheridon(); //HC Magtheridon's Lair +void AddSC_instance_magtheridons_lair(); +void AddSC_boss_grand_warlock_nethekurse(); //HC Shattered Halls +void AddSC_boss_warbringer_omrogg(); +void AddSC_boss_warchief_kargath_bladefist(); +void AddSC_shattered_halls(); +void AddSC_instance_shattered_halls(); +void AddSC_boss_watchkeeper_gargolmar(); //HC Ramparts +void AddSC_boss_omor_the_unscarred(); +void AddSC_boss_vazruden_the_herald(); +void AddSC_instance_ramparts(); +void AddSC_arcatraz(); //TK Arcatraz +void AddSC_boss_zereketh_the_unbound(); +void AddSC_boss_dalliah_the_doomsayer(); +void AddSC_boss_wrath_scryer_soccothrates(); +void AddSC_boss_harbinger_skyriss(); +void AddSC_instance_arcatraz(); +void AddSC_boss_high_botanist_freywinn(); //TK Botanica +void AddSC_boss_laj(); +void AddSC_boss_warp_splinter(); +void AddSC_boss_thorngrin_the_tender(); +void AddSC_boss_commander_sarannis(); +void AddSC_instance_the_botanica(); +void AddSC_boss_alar(); //TK The Eye +void AddSC_boss_kaelthas(); +void AddSC_boss_void_reaver(); +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(); +void AddSC_instance_mechanar(); + +void AddSC_blades_edge_mountains(); +void AddSC_boss_doomlordkazzak(); +void AddSC_boss_doomwalker(); +void AddSC_hellfire_peninsula(); +void AddSC_nagrand(); +void AddSC_netherstorm(); +void AddSC_shadowmoon_valley(); +void AddSC_shattrath_city(); +void AddSC_terokkar_forest(); +void AddSC_zangarmarsh(); + +// The name of this function should match: +// void Add${NameOfDirectory}Scripts() +void AddOutlandScripts() +{ + // Auchindoun - Auchenai Crypts + AddSC_boss_shirrak_the_dead_watcher(); + AddSC_boss_exarch_maladaar(); + AddSC_instance_auchenai_crypts(); + + // Auchindoun - Mana Tombs + AddSC_boss_pandemonius(); + AddSC_boss_nexusprince_shaffar(); + AddSC_instance_mana_tombs(); + + // Auchindoun - Sekketh Halls + AddSC_boss_darkweaver_syth(); + AddSC_boss_talon_king_ikiss(); + AddSC_boss_anzu(); + AddSC_instance_sethekk_halls(); + + // Auchindoun - Shadow Labyrinth + AddSC_boss_ambassador_hellmaw(); + AddSC_boss_blackheart_the_inciter(); + AddSC_boss_grandmaster_vorpil(); + AddSC_boss_murmur(); + AddSC_instance_shadow_labyrinth(); + + // Black Temple + AddSC_black_temple(); + AddSC_boss_illidan(); + AddSC_boss_shade_of_akama(); + AddSC_boss_supremus(); + AddSC_boss_gurtogg_bloodboil(); + AddSC_boss_mother_shahraz(); + AddSC_boss_reliquary_of_souls(); + AddSC_boss_teron_gorefiend(); + AddSC_boss_najentus(); + AddSC_boss_illidari_council(); + AddSC_instance_black_temple(); + + // Coilfang Reservoir - Serpent Shrine Cavern + AddSC_boss_fathomlord_karathress(); + AddSC_boss_hydross_the_unstable(); + AddSC_boss_lady_vashj(); + AddSC_boss_leotheras_the_blind(); + AddSC_boss_morogrim_tidewalker(); + AddSC_instance_serpentshrine_cavern(); + AddSC_boss_the_lurker_below(); + + // Coilfang Reservoir - The Steam Vault + AddSC_instance_steam_vault(); + AddSC_boss_hydromancer_thespia(); + AddSC_boss_mekgineer_steamrigger(); + AddSC_boss_warlord_kalithresh(); + + // Coilfang Reservoir - The Slave Pens + AddSC_instance_the_slave_pens(); + AddSC_boss_mennu_the_betrayer(); + AddSC_boss_rokmar_the_crackler(); + AddSC_boss_quagmirran(); + + // Coilfang Reservoir - The Underbog + AddSC_instance_the_underbog(); + AddSC_boss_hungarfen(); + AddSC_boss_the_black_stalker(); + + // Gruul's Lair + AddSC_boss_gruul(); + AddSC_boss_high_king_maulgar(); + AddSC_instance_gruuls_lair(); + AddSC_boss_broggok(); //HC Blood Furnace + AddSC_boss_kelidan_the_breaker(); + AddSC_boss_the_maker(); + AddSC_instance_blood_furnace(); + AddSC_boss_magtheridon(); //HC Magtheridon's Lair + AddSC_instance_magtheridons_lair(); + AddSC_boss_grand_warlock_nethekurse(); //HC Shattered Halls + AddSC_boss_warbringer_omrogg(); + AddSC_boss_warchief_kargath_bladefist(); + AddSC_shattered_halls(); + AddSC_instance_shattered_halls(); + AddSC_boss_watchkeeper_gargolmar(); //HC Ramparts + AddSC_boss_omor_the_unscarred(); + AddSC_boss_vazruden_the_herald(); + AddSC_instance_ramparts(); + AddSC_arcatraz(); //TK Arcatraz + AddSC_boss_zereketh_the_unbound(); + AddSC_boss_dalliah_the_doomsayer(); + AddSC_boss_wrath_scryer_soccothrates(); + AddSC_boss_harbinger_skyriss(); + AddSC_instance_arcatraz(); + AddSC_boss_high_botanist_freywinn(); //TK Botanica + AddSC_boss_laj(); + AddSC_boss_warp_splinter(); + AddSC_boss_thorngrin_the_tender(); + AddSC_boss_commander_sarannis(); + AddSC_instance_the_botanica(); + AddSC_boss_alar(); //TK The Eye + AddSC_boss_kaelthas(); + AddSC_boss_void_reaver(); + AddSC_boss_high_astromancer_solarian(); + 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(); + AddSC_instance_mechanar(); + + AddSC_blades_edge_mountains(); + AddSC_boss_doomlordkazzak(); + AddSC_boss_doomwalker(); + AddSC_hellfire_peninsula(); + AddSC_nagrand(); + AddSC_netherstorm(); + AddSC_shadowmoon_valley(); + AddSC_shattrath_city(); + AddSC_terokkar_forest(); + AddSC_zangarmarsh(); +} diff --git a/src/server/scripts/Outland/zone_terokkar_forest.cpp b/src/server/scripts/Outland/zone_terokkar_forest.cpp index 06a8af947b7..4b757544d65 100644 --- a/src/server/scripts/Outland/zone_terokkar_forest.cpp +++ b/src/server/scripts/Outland/zone_terokkar_forest.cpp @@ -27,7 +27,6 @@ EndScriptData */ npc_unkor_the_ruthless npc_infested_root_walker npc_rotting_forest_rager -npc_netherweb_victim npc_floon npc_isla_starmane npc_slim @@ -47,13 +46,13 @@ EndContentData */ enum UnkorTheRuthless { - SAY_SUBMIT = 0, - - FACTION_HOSTILE = 45, - FACTION_FRIENDLY = 35, - QUEST_DONTKILLTHEFATONE = 9889, - - SPELL_PULVERIZE = 2676 + SAY_SUBMIT = 0, + REQUIRED_KILL_COUNT = 10, + FACTION_FRIENDLY = 35, + FACTION_HOSTILE = 45, + SPELL_PULVERIZE = 2676, + QUEST_DONTKILLTHEFATONE = 9889, + NPC_BOULDERFIST_INVADER = 18260 }; class npc_unkor_the_ruthless : public CreatureScript @@ -117,7 +116,7 @@ public: Player* groupie = itr->GetSource(); if (groupie && groupie->GetQuestStatus(QUEST_DONTKILLTHEFATONE) == QUEST_STATUS_INCOMPLETE && - groupie->GetReqKillOrCastCurrentCount(QUEST_DONTKILLTHEFATONE, 18260) == 10) + groupie->GetReqKillOrCastCurrentCount(QUEST_DONTKILLTHEFATONE, NPC_BOULDERFIST_INVADER) == REQUIRED_KILL_COUNT) { groupie->AreaExploredOrEventHappens(QUEST_DONTKILLTHEFATONE); if (!CanDoQuest) @@ -126,7 +125,7 @@ public: } } else if (player->GetQuestStatus(QUEST_DONTKILLTHEFATONE) == QUEST_STATUS_INCOMPLETE && - player->GetReqKillOrCastCurrentCount(QUEST_DONTKILLTHEFATONE, 18260) == 10) + player->GetReqKillOrCastCurrentCount(QUEST_DONTKILLTHEFATONE, NPC_BOULDERFIST_INVADER) == REQUIRED_KILL_COUNT) { player->AreaExploredOrEventHappens(QUEST_DONTKILLTHEFATONE); CanDoQuest = true; @@ -171,6 +170,11 @@ public: ## npc_infested_root_walker ######*/ +enum InfestedRootWalker +{ + SPELL_SUMMON_WOOD_MITES = 39130 +}; + class npc_infested_root_walker : public CreatureScript { public: @@ -194,7 +198,7 @@ public: if (me->GetHealth() <= damage) if (rand32() % 100 < 75) //Summon Wood Mites - DoCast(me, 39130, true); + DoCast(me, SPELL_SUMMON_WOOD_MITES, true); } }; }; @@ -202,6 +206,12 @@ public: /*###### ## npc_skywing ######*/ + +enum Skywing +{ + QUEST_SKYWING = 10898 +}; + class npc_skywing : public CreatureScript { public: @@ -226,7 +236,7 @@ public: switch (waypointId) { case 8: - player->AreaExploredOrEventHappens(10898); + player->AreaExploredOrEventHappens(QUEST_SKYWING); break; } } @@ -240,7 +250,7 @@ public: return; Player* player = who->ToPlayer(); - if (player && player->GetQuestStatus(10898) == QUEST_STATUS_INCOMPLETE) + if (player && player->GetQuestStatus(QUEST_SKYWING) == QUEST_STATUS_INCOMPLETE) if (me->IsWithinDistInMap(who, 10.0f)) Start(false, false, who->GetGUID()); } @@ -258,6 +268,11 @@ public: ## npc_rotting_forest_rager ######*/ +enum RottingForestRager +{ + SPELL_SUMMON_LOTS_OF_WOOD_MITES = 39134 +}; + class npc_rotting_forest_rager : public CreatureScript { public: @@ -280,67 +295,8 @@ public: if (done_by->GetTypeId() == TYPEID_PLAYER) if (me->GetHealth() <= damage) if (rand32() % 100 < 75) - //Summon Lots of Wood Mights - DoCast(me, 39134, true); - } - }; -}; - -/*###### -## npc_netherweb_victim -######*/ - -enum NetherwebVictim -{ - QUEST_TARGET = 22459 - //SPELL_FREE_WEBBED = 38950 -}; - -const uint32 netherwebVictims[6] = -{ - 18470, 16805, 21242, 18452, 22482, 21285 -}; - -class npc_netherweb_victim : public CreatureScript -{ -public: - npc_netherweb_victim() : CreatureScript("npc_netherweb_victim") { } - - CreatureAI* GetAI(Creature* creature) const override - { - return new npc_netherweb_victimAI(creature); - } - - struct npc_netherweb_victimAI : public ScriptedAI - { - npc_netherweb_victimAI(Creature* creature) : ScriptedAI(creature) { } - - void Reset() override { } - void EnterCombat(Unit* /*who*/) override { } - void MoveInLineOfSight(Unit* /*who*/) override { } - - - void JustDied(Unit* killer) override - { - Player* player = killer->ToPlayer(); - if (!player) - return; - - if (player->GetQuestStatus(10873) == QUEST_STATUS_INCOMPLETE) - { - if (rand32() % 100 < 25) - { - me->SummonCreature(QUEST_TARGET, 0.0f, 0.0f, 0.0f, 0.0f, TEMPSUMMON_TIMED_DESPAWN_OUT_OF_COMBAT, 60000); - player->KilledMonsterCredit(QUEST_TARGET); - } - else - me->SummonCreature(netherwebVictims[rand32() % 6], 0.0f, 0.0f, 0.0f, 0.0f, TEMPSUMMON_TIMED_DESPAWN_OUT_OF_COMBAT, 60000); - - if (rand32() % 100 < 75) - me->SummonCreature(netherwebVictims[rand32() % 6], 0.0f, 0.0f, 0.0f, 0.0f, TEMPSUMMON_TIMED_DESPAWN_OUT_OF_COMBAT, 60000); - - me->SummonCreature(netherwebVictims[rand32() % 6], 0.0f, 0.0f, 0.0f, 0.0f, TEMPSUMMON_TIMED_DESPAWN_OUT_OF_COMBAT, 60000); - } + //Summon Lots of Wood Mites + DoCast(me, SPELL_SUMMON_LOTS_OF_WOOD_MITES, true); } }; }; @@ -349,19 +305,22 @@ public: ## npc_floon ######*/ -#define GOSSIP_FLOON1 "You owe Sim'salabim money. Hand them over or die!" -#define GOSSIP_FLOON2 "Hand over the money or die...again!" - enum Floon { - SAY_FLOON_ATTACK = 0, - - SPELL_SILENCE = 6726, - SPELL_FROSTBOLT = 9672, - SPELL_FROST_NOVA = 11831, - - FACTION_HOSTILE_FL = 1738, - QUEST_CRACK_SKULLS = 10009 + SAY_FLOON_ATTACK = 0, + OPTION_ID_PAY_UP_OR_DIE = 0, + OPTION_ID_COLLECT_A_DEBT = 0, + FACTION_HOSTILE_FLOON = 1738, + MENU_ID_PAY_UP_OR_DIE = 7731, + MENU_ID_COLLECT_A_DEBT = 7732, + GOSSIP_FLOON_STRANGE_SOUNDS = 9442, + GOSSIP_HE_ALREADY_KILLED_ME = 9443, + + SPELL_SILENCE = 6726, + SPELL_FROSTBOLT = 9672, + SPELL_FROST_NOVA = 11831, + + QUEST_CRACKIN_SOME_SKULLS = 10009 }; class npc_floon : public CreatureScript @@ -374,13 +333,13 @@ public: player->PlayerTalkClass->ClearMenus(); if (action == GOSSIP_ACTION_INFO_DEF) { - player->ADD_GOSSIP_ITEM(GOSSIP_ICON_CHAT, GOSSIP_FLOON2, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF+1); - player->SEND_GOSSIP_MENU(9443, creature->GetGUID()); + player->ADD_GOSSIP_ITEM_DB(MENU_ID_PAY_UP_OR_DIE, OPTION_ID_PAY_UP_OR_DIE, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF+1); + player->SEND_GOSSIP_MENU(GOSSIP_HE_ALREADY_KILLED_ME, creature->GetGUID()); } if (action == GOSSIP_ACTION_INFO_DEF+1) { player->CLOSE_GOSSIP_MENU(); - creature->setFaction(FACTION_HOSTILE_FL); + creature->setFaction(FACTION_HOSTILE_FLOON); creature->AI()->Talk(SAY_FLOON_ATTACK, player); creature->AI()->AttackStart(player); } @@ -389,10 +348,10 @@ public: bool OnGossipHello(Player* player, Creature* creature) override { - if (player->GetQuestStatus(QUEST_CRACK_SKULLS) == QUEST_STATUS_INCOMPLETE) - player->ADD_GOSSIP_ITEM(GOSSIP_ICON_CHAT, GOSSIP_FLOON1, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF); + if (player->GetQuestStatus(QUEST_CRACKIN_SOME_SKULLS) == QUEST_STATUS_INCOMPLETE) + player->ADD_GOSSIP_ITEM_DB(MENU_ID_COLLECT_A_DEBT, OPTION_ID_COLLECT_A_DEBT, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF); - player->SEND_GOSSIP_MENU(9442, creature->GetGUID()); + player->SEND_GOSSIP_MENU(GOSSIP_FLOON_STRANGE_SOUNDS, creature->GetGUID()); return true; } @@ -463,15 +422,16 @@ public: ######*/ enum IslaStarmaneData { - SAY_PROGRESS_1 = 0, - SAY_PROGRESS_2 = 1, - SAY_PROGRESS_3 = 2, - SAY_PROGRESS_4 = 3, - - QUEST_EFTW_H = 10052, - QUEST_EFTW_A = 10051, - GO_CAGE = 182794, - SPELL_CAT = 32447, + SAY_PROGRESS_1 = 0, + SAY_PROGRESS_2 = 1, + SAY_PROGRESS_3 = 2, + SAY_PROGRESS_4 = 3, + GO_DISTANCE = 10, + FACTION_ESCORTEE = 113, + ESCAPE_FROM_FIREWING_POINT_A = 10051, + ESCAPE_FROM_FIREWING_POINT_H = 10052, + SPELL_TRAVEL_FORM_CAT = 32447, + GO_CAGE = 182794 }; class npc_isla_starmane : public CreatureScript @@ -492,7 +452,7 @@ public: switch (waypointId) { case 0: - if (GameObject* Cage = me->FindNearestGameObject(GO_CAGE, 10)) + if (GameObject* Cage = me->FindNearestGameObject(GO_CAGE, GO_DISTANCE)) Cage->SetGoState(GO_STATE_ACTIVE); break; case 2: @@ -507,16 +467,16 @@ public: case 29: Talk(SAY_PROGRESS_4, player); if (player->GetTeam() == ALLIANCE) - player->GroupEventHappens(QUEST_EFTW_A, me); + player->GroupEventHappens(ESCAPE_FROM_FIREWING_POINT_A, me); else if (player->GetTeam() == HORDE) - player->GroupEventHappens(QUEST_EFTW_H, me); + player->GroupEventHappens(ESCAPE_FROM_FIREWING_POINT_H, me); me->SetInFront(player); break; case 30: me->HandleEmoteCommand(EMOTE_ONESHOT_WAVE); break; case 31: - DoCast(me, SPELL_CAT); + DoCast(me, SPELL_TRAVEL_FORM_CAT); me->SetWalk(false); break; } @@ -532,19 +492,19 @@ public: if (Player* player = GetPlayerForEscort()) { if (player->GetTeam() == ALLIANCE) - player->FailQuest(QUEST_EFTW_A); + player->FailQuest(ESCAPE_FROM_FIREWING_POINT_A); else if (player->GetTeam() == HORDE) - player->FailQuest(QUEST_EFTW_H); + player->FailQuest(ESCAPE_FROM_FIREWING_POINT_H); } } }; bool OnQuestAccept(Player* player, Creature* creature, Quest const* quest) override { - if (quest->GetQuestId() == QUEST_EFTW_H || quest->GetQuestId() == QUEST_EFTW_A) + if (quest->GetQuestId() == ESCAPE_FROM_FIREWING_POINT_H || quest->GetQuestId() == ESCAPE_FROM_FIREWING_POINT_A) { ENSURE_AI(npc_escortAI, (creature->AI()))->Start(true, false, player->GetGUID()); - creature->setFaction(113); + creature->setFaction(FACTION_ESCORTEE); } return true; } @@ -558,10 +518,20 @@ public: /*###### ## go_skull_pile ######*/ -#define GOSSIP_S_DARKSCREECHER_AKKARAI "Summon Darkscreecher Akkarai" -#define GOSSIP_S_KARROG "Summon Karrog" -#define GOSSIP_S_GEZZARAK_THE_HUNTRESS "Summon Gezzarak the Huntress" -#define GOSSIP_S_VAKKIZ_THE_WINDRAGER "Summon Vakkiz the Windrager" + +enum SkullPile +{ + OPTION_ID_GEZZARAK_THE_HUNTRESS = 0, + OPTION_ID_DARKSCREECHER_AKKARAI = 1, + OPTION_ID_KARROG = 2, + OPTION_ID_VAKKIZ_THE_WINDRAGER = 3, + GOSSIP_MENU_ID_SKULL_PILE = 8660, + ADVERSARIAL_BLOOD = 11885, + SUMMON_GEZZARAK_THE_HUNTRESS = 40632, + SUMMON_KARROG = 40640, + SUMMON_DARKSCREECHER_AKKARAI = 40642, + SUMMON_VAKKIZ_THE_WINDRAGER = 40644 +}; class go_skull_pile : public GameObjectScript { @@ -580,12 +550,12 @@ public: bool OnGossipHello(Player* player, GameObject* go) override { - if ((player->GetQuestStatus(11885) == QUEST_STATUS_INCOMPLETE) || player->GetQuestRewardStatus(11885)) + if ((player->GetQuestStatus(ADVERSARIAL_BLOOD) == QUEST_STATUS_INCOMPLETE) || player->GetQuestRewardStatus(ADVERSARIAL_BLOOD)) { - player->ADD_GOSSIP_ITEM(GOSSIP_ICON_CHAT, GOSSIP_S_DARKSCREECHER_AKKARAI, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 1); - player->ADD_GOSSIP_ITEM(GOSSIP_ICON_CHAT, GOSSIP_S_KARROG, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 2); - player->ADD_GOSSIP_ITEM(GOSSIP_ICON_CHAT, GOSSIP_S_GEZZARAK_THE_HUNTRESS, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 3); - player->ADD_GOSSIP_ITEM(GOSSIP_ICON_CHAT, GOSSIP_S_VAKKIZ_THE_WINDRAGER, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 4); + player->ADD_GOSSIP_ITEM_DB(GOSSIP_MENU_ID_SKULL_PILE, OPTION_ID_GEZZARAK_THE_HUNTRESS, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 1); + player->ADD_GOSSIP_ITEM_DB(GOSSIP_MENU_ID_SKULL_PILE, OPTION_ID_DARKSCREECHER_AKKARAI, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 2); + player->ADD_GOSSIP_ITEM_DB(GOSSIP_MENU_ID_SKULL_PILE, OPTION_ID_KARROG, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 3); + player->ADD_GOSSIP_ITEM_DB(GOSSIP_MENU_ID_SKULL_PILE, OPTION_ID_VAKKIZ_THE_WINDRAGER, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 4); } player->SEND_GOSSIP_MENU(go->GetGOInfo()->questgiver.gossipID, go->GetGUID()); @@ -597,16 +567,16 @@ public: switch (action) { case GOSSIP_ACTION_INFO_DEF + 1: - player->CastSpell(player, 40642, false); + player->CastSpell(player, SUMMON_GEZZARAK_THE_HUNTRESS, false); break; case GOSSIP_ACTION_INFO_DEF + 2: - player->CastSpell(player, 40640, false); + player->CastSpell(player, SUMMON_DARKSCREECHER_AKKARAI, false); break; case GOSSIP_ACTION_INFO_DEF + 3: - player->CastSpell(player, 40632, false); + player->CastSpell(player, SUMMON_KARROG, false); break; case GOSSIP_ACTION_INFO_DEF + 4: - player->CastSpell(player, 40644, false); + player->CastSpell(player, SUMMON_VAKKIZ_THE_WINDRAGER, false); break; } } @@ -618,7 +588,9 @@ public: enum Slim { - FACTION_CONSORTIUM = 933 + FACTION_CONSORTIUM = 933, + NPC_TEXT_NEITHER_SLIM_NOR_SHADY = 9895, + NPC_TEXT_I_SEE_YOU_ARE_A_FRIEND = 9896 }; class npc_slim : public CreatureScript @@ -640,10 +612,10 @@ public: if (creature->IsVendor() && player->GetReputationRank(FACTION_CONSORTIUM) >= REP_FRIENDLY) { player->ADD_GOSSIP_ITEM(GOSSIP_ICON_VENDOR, GOSSIP_TEXT_BROWSE_GOODS, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_TRADE); - player->SEND_GOSSIP_MENU(9896, creature->GetGUID()); + player->SEND_GOSSIP_MENU(NPC_TEXT_I_SEE_YOU_ARE_A_FRIEND, creature->GetGUID()); } else - player->SEND_GOSSIP_MENU(9895, creature->GetGUID()); + player->SEND_GOSSIP_MENU(NPC_TEXT_NEITHER_SLIM_NOR_SHADY, creature->GetGUID()); return true; } @@ -719,7 +691,6 @@ void AddSC_terokkar_forest() new npc_unkor_the_ruthless(); new npc_infested_root_walker(); new npc_rotting_forest_rager(); - new npc_netherweb_victim(); new npc_floon(); new npc_isla_starmane(); new go_skull_pile(); diff --git a/src/server/scripts/Pet/CMakeLists.txt b/src/server/scripts/Pet/CMakeLists.txt deleted file mode 100644 index 9ca268a9a3f..00000000000 --- a/src/server/scripts/Pet/CMakeLists.txt +++ /dev/null @@ -1,21 +0,0 @@ -# Copyright (C) 2008-2016 TrinityCore <http://www.trinitycore.org/> -# -# This file is free software; as a special exception the author gives -# unlimited permission to copy and/or distribute it, with or without -# modifications, as long as this notice is preserved. -# -# This program is distributed in the hope that it will be useful, but -# WITHOUT ANY WARRANTY, to the extent permitted by law; without even the -# implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. - -set(scripts_STAT_SRCS - ${scripts_STAT_SRCS} - Pet/pet_dk.cpp - Pet/pet_generic.cpp - Pet/pet_hunter.cpp - Pet/pet_mage.cpp - Pet/pet_priest.cpp - Pet/pet_shaman.cpp -) - -message(" -> Prepared: Pet") diff --git a/src/server/scripts/Pet/pet_generic.cpp b/src/server/scripts/Pet/pet_generic.cpp index 35455bc474b..0ec6f08ae58 100644 --- a/src/server/scripts/Pet/pet_generic.cpp +++ b/src/server/scripts/Pet/pet_generic.cpp @@ -20,10 +20,181 @@ * Scriptnames of files in this file should be prefixed with "npc_pet_gen_". */ + /* ContentData + npc_pet_gen_egbert 100% Egbert run's around + npc_pet_gen_pandaren_monk 100% Pandaren Monk drinks and bows with you + npc_pet_gen_mojo 100% Mojo follows you when you kiss it + EndContentData */ + #include "ScriptMgr.h" #include "ScriptedCreature.h" +#include "PassiveAI.h" #include "Player.h" +enum EgbertMisc +{ + SPELL_EGBERT = 40669, + EVENT_RETURN = 3 +}; + +class npc_pet_gen_egbert : public CreatureScript +{ +public: + npc_pet_gen_egbert() : CreatureScript("npc_pet_gen_egbert") {} + + struct npc_pet_gen_egbertAI : public NullCreatureAI + { + npc_pet_gen_egbertAI(Creature* creature) : NullCreatureAI(creature) + { + if (Unit* owner = me->GetCharmerOrOwner()) + if (owner->GetMap()->GetEntry()->addon > 1) + me->SetCanFly(true); + } + + void Reset() override + { + _events.Reset(); + if (Unit* owner = me->GetCharmerOrOwner()) + me->GetMotionMaster()->MoveFollow(owner, PET_FOLLOW_DIST, me->GetFollowAngle()); + } + + void EnterEvadeMode(EvadeReason why) override + { + if (!_EnterEvadeMode(why)) + return; + + Reset(); + } + + void UpdateAI(uint32 diff) override + { + _events.Update(diff); + + if (Unit* owner = me->GetCharmerOrOwner()) + { + if (!me->IsWithinDist(owner, 40.f)) + { + me->RemoveAura(SPELL_EGBERT); + me->GetMotionMaster()->MoveFollow(owner, PET_FOLLOW_DIST, me->GetFollowAngle()); + } + } + + if (me->HasAura(SPELL_EGBERT)) + _events.ScheduleEvent(EVENT_RETURN, urandms(5, 20)); + + while (uint32 eventId = _events.ExecuteEvent()) + { + switch (eventId) + { + case EVENT_RETURN: + me->RemoveAura(SPELL_EGBERT); + break; + default: + break; + } + } + } + private: + EventMap _events; + }; + + CreatureAI* GetAI(Creature* creature) const + { + return new npc_pet_gen_egbertAI(creature); + } +}; + +enum PandarenMonkMisc +{ + SPELL_PANDAREN_MONK = 69800, + EVENT_FOCUS = 1, + EVENT_EMOTE = 2, + EVENT_FOLLOW = 3, + EVENT_DRINK = 4 +}; + +class npc_pet_gen_pandaren_monk : public CreatureScript +{ +public: + npc_pet_gen_pandaren_monk() : CreatureScript("npc_pet_gen_pandaren_monk") {} + + struct npc_pet_gen_pandaren_monkAI : public NullCreatureAI + { + npc_pet_gen_pandaren_monkAI(Creature* creature) : NullCreatureAI(creature) { } + + void Reset() override + { + _events.Reset(); + _events.ScheduleEvent(EVENT_FOCUS, 1000); + } + + void EnterEvadeMode(EvadeReason why) override + { + if (!_EnterEvadeMode(why)) + return; + + Reset(); + } + + void ReceiveEmote(Player* /*player*/, uint32 emote) override + { + me->InterruptSpell(CURRENT_CHANNELED_SPELL); + me->StopMoving(); + + switch (emote) + { + case TEXT_EMOTE_BOW: + _events.ScheduleEvent(EVENT_FOCUS, 1000); + break; + case TEXT_EMOTE_DRINK: + _events.ScheduleEvent(EVENT_DRINK, 1000); + break; + } + } + + void UpdateAI(uint32 diff) override + { + _events.Update(diff); + + if (Unit* owner = me->GetCharmerOrOwner()) + if (!me->IsWithinDist(owner, 30.f)) + me->InterruptSpell(CURRENT_CHANNELED_SPELL); + + while (uint32 eventId = _events.ExecuteEvent()) + { + switch (eventId) + { + case EVENT_FOCUS: + if (Unit* owner = me->GetCharmerOrOwner()) + me->SetFacingToObject(owner); + _events.ScheduleEvent(EVENT_EMOTE, 1000); + break; + case EVENT_EMOTE: + me->HandleEmoteCommand(EMOTE_ONESHOT_BOW); + _events.ScheduleEvent(EVENT_FOLLOW, 1000); + break; + case EVENT_FOLLOW: + if (Unit* owner = me->GetCharmerOrOwner()) + me->GetMotionMaster()->MoveFollow(owner, PET_FOLLOW_DIST, PET_FOLLOW_ANGLE); + break; + case EVENT_DRINK: + me->CastSpell(me, SPELL_PANDAREN_MONK, false); + break; + default: + break; + } + } + } + private: + EventMap _events; + }; + + CreatureAI* GetAI(Creature* creature) const + { + return new npc_pet_gen_pandaren_monkAI(creature); + } +}; + enum Mojo { SAY_MOJO = 0, @@ -89,5 +260,7 @@ class npc_pet_gen_mojo : public CreatureScript void AddSC_generic_pet_scripts() { + new npc_pet_gen_egbert(); + new npc_pet_gen_pandaren_monk(); new npc_pet_gen_mojo(); } diff --git a/src/server/scripts/Pet/pet_script_loader.cpp b/src/server/scripts/Pet/pet_script_loader.cpp new file mode 100644 index 00000000000..c3c0079fd46 --- /dev/null +++ b/src/server/scripts/Pet/pet_script_loader.cpp @@ -0,0 +1,36 @@ +/* + * Copyright (C) 2008-2016 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/>. + */ + +// This is where scripts' loading functions should be declared: +void AddSC_deathknight_pet_scripts(); +void AddSC_generic_pet_scripts(); +void AddSC_hunter_pet_scripts(); +void AddSC_mage_pet_scripts(); +void AddSC_priest_pet_scripts(); +void AddSC_shaman_pet_scripts(); + +// The name of this function should match: +// void Add${NameOfDirectory}Scripts() +void AddPetScripts() +{ + AddSC_deathknight_pet_scripts(); + AddSC_generic_pet_scripts(); + AddSC_hunter_pet_scripts(); + AddSC_mage_pet_scripts(); + AddSC_priest_pet_scripts(); + AddSC_shaman_pet_scripts(); +} diff --git a/src/server/scripts/Spells/CMakeLists.txt b/src/server/scripts/Spells/CMakeLists.txt deleted file mode 100644 index 7434d98cf49..00000000000 --- a/src/server/scripts/Spells/CMakeLists.txt +++ /dev/null @@ -1,30 +0,0 @@ -# Copyright (C) 2008-2016 TrinityCore <http://www.trinitycore.org/> -# -# This file is free software; as a special exception the author gives -# unlimited permission to copy and/or distribute it, with or without -# modifications, as long as this notice is preserved. -# -# This program is distributed in the hope that it will be useful, but -# WITHOUT ANY WARRANTY, to the extent permitted by law; without even the -# implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. - -set(scripts_STAT_SRCS - ${scripts_STAT_SRCS} - Spells/spell_shaman.cpp - Spells/spell_hunter.cpp - Spells/spell_rogue.cpp - Spells/spell_druid.cpp - Spells/spell_dk.cpp - Spells/spell_quest.cpp - Spells/spell_warrior.cpp - Spells/spell_generic.cpp - Spells/spell_warlock.cpp - Spells/spell_priest.cpp - Spells/spell_mage.cpp - Spells/spell_paladin.cpp - Spells/spell_item.cpp - Spells/spell_holiday.cpp - Spells/spell_pet.cpp -) - -message(" -> Prepared: Spells") diff --git a/src/server/scripts/Spells/spell_dk.cpp b/src/server/scripts/Spells/spell_dk.cpp index 3cea620559a..7c2bb0bfaa5 100644 --- a/src/server/scripts/Spells/spell_dk.cpp +++ b/src/server/scripts/Spells/spell_dk.cpp @@ -22,7 +22,7 @@ */ #include "Player.h" -#include "UnitAI.h" +#include "PlayerAI.h" #include "ScriptMgr.h" #include "SpellScript.h" #include "SpellAuraEffects.h" @@ -1909,7 +1909,7 @@ public: if (!player || player->GetGhoulResurrectGhoulGUID().IsEmpty()) return; - oldAI = player->GetAI(); + oldAI = player->AI(); oldAIState = player->IsAIEnabled; player->SetAI(new player_ghoulAI(player, player->GetGhoulResurrectGhoulGUID())); player->IsAIEnabled = true; @@ -1922,7 +1922,7 @@ public: return; player->IsAIEnabled = oldAIState; - UnitAI* thisAI = player->GetAI(); + PlayerAI* thisAI = player->AI(); player->SetAI(oldAI); delete thisAI; @@ -1943,7 +1943,7 @@ public: AfterEffectRemove += AuraEffectRemoveFn(spell_dk_raise_ally_AuraScript::OnRemove, EFFECT_1, SPELL_AURA_DUMMY, AURA_EFFECT_HANDLE_REAL); } - UnitAI* oldAI; + PlayerAI* oldAI; bool oldAIState; }; diff --git a/src/server/scripts/Spells/spell_druid.cpp b/src/server/scripts/Spells/spell_druid.cpp index 7b853c36075..c088ae07e66 100644 --- a/src/server/scripts/Spells/spell_druid.cpp +++ b/src/server/scripts/Spells/spell_druid.cpp @@ -991,6 +991,37 @@ class spell_dru_swift_flight_passive : public SpellScriptLoader } }; +// -33943 - Flight Form +class spell_dru_flight_form : public SpellScriptLoader +{ + public: + spell_dru_flight_form() : SpellScriptLoader("spell_dru_flight_form") { } + + class spell_dru_flight_form_SpellScript : public SpellScript + { + PrepareSpellScript(spell_dru_flight_form_SpellScript); + + SpellCastResult CheckCast() + { + Unit* caster = GetCaster(); + if (caster->IsInDisallowedMountForm()) + return SPELL_FAILED_NOT_SHAPESHIFT; + + return SPELL_CAST_OK; + } + + void Register() override + { + OnCheckCast += SpellCheckCastFn(spell_dru_flight_form_SpellScript::CheckCast); + } + }; + + SpellScript* GetSpellScript() const override + { + return new spell_dru_flight_form_SpellScript(); + } +}; + // -5217 - Tiger's Fury class spell_dru_tiger_s_fury : public SpellScriptLoader { @@ -1196,6 +1227,7 @@ void AddSC_druid_spell_scripts() new spell_dru_starfall_dummy(); new spell_dru_survival_instincts(); new spell_dru_swift_flight_passive(); + new spell_dru_flight_form(); 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 5c3ee1d7f4a..abde43ef952 100644 --- a/src/server/scripts/Spells/spell_generic.cpp +++ b/src/server/scripts/Spells/spell_generic.cpp @@ -1930,10 +1930,7 @@ class spell_gen_mount : public SpellScriptLoader if (map == 530 || (map == 571 && target->HasSpell(SPELL_COLD_WEATHER_FLYING))) canFly = true; - float x, y, z; - target->GetPosition(x, y, z); - uint32 areaFlag = target->GetBaseMap()->GetAreaFlag(x, y, z); - AreaTableEntry const* area = sAreaStore.LookupEntry(areaFlag); + AreaTableEntry const* area = sAreaTableStore.LookupEntry(target->GetAreaId()); if (!area || (canFly && (area->flags & AREA_FLAG_NO_FLY_ZONE))) canFly = false; diff --git a/src/server/scripts/Spells/spell_holiday.cpp b/src/server/scripts/Spells/spell_holiday.cpp index 7fe1f54a594..a3359fdf6f9 100644 --- a/src/server/scripts/Spells/spell_holiday.cpp +++ b/src/server/scripts/Spells/spell_holiday.cpp @@ -29,6 +29,7 @@ #include "GridNotifiers.h" #include "GridNotifiersImpl.h" #include "CellImpl.h" +#include "Vehicle.h" // 45102 Romantic Picnic enum SpellsPicnic @@ -410,6 +411,84 @@ class spell_pilgrims_bounty_buff_food : public SpellScriptLoader } }; +enum FeastOnSpells +{ + FEAST_ON_TURKEY = 61784, + FEAST_ON_CRANBERRIES = 61785, + FEAST_ON_SWEET_POTATOES = 61786, + FEAST_ON_PIE = 61787, + FEAST_ON_STUFFING = 61788, + SPELL_CRANBERRY_HELPINS = 61841, + SPELL_TURKEY_HELPINS = 61842, + SPELL_STUFFING_HELPINS = 61843, + SPELL_SWEET_POTATO_HELPINS = 61844, + SPELL_PIE_HELPINS = 61845, + SPELL_ON_PLATE_EAT_VISUAL = 61826 +}; + +class spell_pilgrims_bounty_feast_on : public SpellScriptLoader +{ + public: + spell_pilgrims_bounty_feast_on() : SpellScriptLoader("spell_pilgrims_bounty_feast_on") { } + + class spell_pilgrims_bounty_feast_on_SpellScript : public SpellScript + { + PrepareSpellScript(spell_pilgrims_bounty_feast_on_SpellScript); + + void HandleDummy(SpellEffIndex /*effIndex*/) + { + Unit* caster = GetCaster(); + + uint32 _spellId = 0; + switch (GetSpellInfo()->Id) + { + case FEAST_ON_TURKEY: + _spellId = SPELL_TURKEY_HELPINS; + break; + case FEAST_ON_CRANBERRIES: + _spellId = SPELL_CRANBERRY_HELPINS; + break; + case FEAST_ON_SWEET_POTATOES: + _spellId = SPELL_SWEET_POTATO_HELPINS; + break; + case FEAST_ON_PIE: + _spellId = SPELL_PIE_HELPINS; + break; + case FEAST_ON_STUFFING: + _spellId = SPELL_STUFFING_HELPINS; + break; + default: + return; + } + + if (Vehicle* vehicle = caster->GetVehicleKit()) + if (Unit* target = vehicle->GetPassenger(0)) + if (Player* player = target->ToPlayer()) + { + player->CastSpell(player, SPELL_ON_PLATE_EAT_VISUAL, true); + caster->CastSpell(player, _spellId, true, NULL, NULL, player->GetGUID()); + } + + if (Aura* aura = caster->GetAura(GetEffectValue())) + { + if (aura->GetStackAmount() == 1) + caster->RemoveAurasDueToSpell(aura->GetSpellInfo()->Effects[EFFECT_0].CalcValue()); + aura->ModStackAmount(-1); + } + } + + void Register() override + { + OnEffectHitTarget += SpellEffectFn(spell_pilgrims_bounty_feast_on_SpellScript::HandleDummy, EFFECT_0, SPELL_EFFECT_DUMMY); + } + }; + + SpellScript* GetSpellScript() const override + { + return new spell_pilgrims_bounty_feast_on_SpellScript(); + } +}; + enum TheTurkinator { SPELL_KILL_COUNTER_VISUAL = 62015, @@ -429,7 +508,7 @@ class spell_pilgrims_bounty_turkey_tracker : public SpellScriptLoader { PrepareSpellScript(spell_pilgrims_bounty_turkey_tracker_SpellScript); - bool Validate(SpellInfo const* /*spell*/) + bool Validate(SpellInfo const* /*spell*/) override { if (!sSpellMgr->GetSpellInfo(SPELL_KILL_COUNTER_VISUAL) || !sSpellMgr->GetSpellInfo(SPELL_KILL_COUNTER_VISUAL_MAX)) return false; @@ -472,18 +551,90 @@ class spell_pilgrims_bounty_turkey_tracker : public SpellScriptLoader } } - void Register() + void Register() override { OnEffectHitTarget += SpellEffectFn(spell_pilgrims_bounty_turkey_tracker_SpellScript::HandleScript, EFFECT_1, SPELL_EFFECT_SCRIPT_EFFECT); } }; - SpellScript* GetSpellScript() const + SpellScript* GetSpellScript() const override { return new spell_pilgrims_bounty_turkey_tracker_SpellScript(); } }; +enum SpiritOfSharing +{ + SPELL_THE_SPIRIT_OF_SHARING = 61849 +}; + +class spell_pilgrims_bounty_well_fed : public SpellScriptLoader +{ + private: + uint32 _triggeredSpellId; + + public: + spell_pilgrims_bounty_well_fed(const char* name, uint32 triggeredSpellId) : SpellScriptLoader(name), _triggeredSpellId(triggeredSpellId) { } + + class spell_pilgrims_bounty_well_fed_SpellScript : public SpellScript + { + PrepareSpellScript(spell_pilgrims_bounty_well_fed_SpellScript); + private: + uint32 _triggeredSpellId; + + public: + spell_pilgrims_bounty_well_fed_SpellScript(uint32 triggeredSpellId) : SpellScript(), _triggeredSpellId(triggeredSpellId) { } + + bool Validate(SpellInfo const* /*spell*/) override + { + if (!sSpellMgr->GetSpellInfo(_triggeredSpellId)) + return false; + return true; + } + + void HandleScript(SpellEffIndex effIndex) + { + PreventHitDefaultEffect(effIndex); + Player* target = GetHitPlayer(); + if (!target) + return; + + if (Aura const* aura = target->GetAura(GetSpellInfo()->Id)) + { + if (aura->GetStackAmount() == 5) + target->CastSpell(target, _triggeredSpellId, true); + } + + Aura const* turkey = target->GetAura(SPELL_TURKEY_HELPINS); + Aura const* cranberies = target->GetAura(SPELL_CRANBERRY_HELPINS); + Aura const* stuffing = target->GetAura(SPELL_STUFFING_HELPINS); + Aura const* sweetPotatoes = target->GetAura(SPELL_SWEET_POTATO_HELPINS); + Aura const* pie = target->GetAura(SPELL_PIE_HELPINS); + + if ((turkey && turkey->GetStackAmount() == 5) && (cranberies && cranberies->GetStackAmount() == 5) && (stuffing && stuffing->GetStackAmount() == 5) + && (sweetPotatoes && sweetPotatoes->GetStackAmount() == 5) && (pie && pie->GetStackAmount() == 5)) + { + target->CastSpell(target, SPELL_THE_SPIRIT_OF_SHARING, true); + target->RemoveAurasDueToSpell(SPELL_TURKEY_HELPINS); + target->RemoveAurasDueToSpell(SPELL_CRANBERRY_HELPINS); + target->RemoveAurasDueToSpell(SPELL_STUFFING_HELPINS); + target->RemoveAurasDueToSpell(SPELL_SWEET_POTATO_HELPINS); + target->RemoveAurasDueToSpell(SPELL_PIE_HELPINS); + } + } + + void Register() override + { + OnEffectHitTarget += SpellEffectFn(spell_pilgrims_bounty_well_fed_SpellScript::HandleScript, EFFECT_1, SPELL_EFFECT_SCRIPT_EFFECT); + } + }; + + SpellScript* GetSpellScript() const override + { + return new spell_pilgrims_bounty_well_fed_SpellScript(_triggeredSpellId); + } +}; + enum Mistletoe { SPELL_CREATE_MISTLETOE = 26206, @@ -1047,6 +1198,12 @@ void AddSC_holiday_spell_scripts() new spell_pilgrims_bounty_buff_food("spell_gen_spice_bread_stuffing", SPELL_WELL_FED_HIT_TRIGGER); new spell_pilgrims_bounty_buff_food("spell_gen_pumpkin_pie", SPELL_WELL_FED_SPIRIT_TRIGGER); new spell_pilgrims_bounty_buff_food("spell_gen_candied_sweet_potato", SPELL_WELL_FED_HASTE_TRIGGER); + new spell_pilgrims_bounty_feast_on(); + new spell_pilgrims_bounty_well_fed("spell_pilgrims_bounty_well_fed_turkey", SPELL_WELL_FED_AP_TRIGGER); + new spell_pilgrims_bounty_well_fed("spell_pilgrims_bounty_well_fed_cranberry", SPELL_WELL_FED_ZM_TRIGGER); + new spell_pilgrims_bounty_well_fed("spell_pilgrims_bounty_well_fed_stuffing", SPELL_WELL_FED_HIT_TRIGGER); + new spell_pilgrims_bounty_well_fed("spell_pilgrims_bounty_well_fed_sweet_potatoes", SPELL_WELL_FED_HASTE_TRIGGER); + new spell_pilgrims_bounty_well_fed("spell_pilgrims_bounty_well_fed_pie", SPELL_WELL_FED_SPIRIT_TRIGGER); new spell_pilgrims_bounty_turkey_tracker(); // Winter Veil new spell_winter_veil_mistletoe(); diff --git a/src/server/scripts/Spells/spell_hunter.cpp b/src/server/scripts/Spells/spell_hunter.cpp index abf4c6c1ad8..4d7cc277ff6 100644 --- a/src/server/scripts/Spells/spell_hunter.cpp +++ b/src/server/scripts/Spells/spell_hunter.cpp @@ -40,6 +40,7 @@ enum HunterSpells SPELL_HUNTER_CHIMERA_SHOT_SERPENT = 53353, SPELL_HUNTER_CHIMERA_SHOT_VIPER = 53358, SPELL_HUNTER_CHIMERA_SHOT_SCORPID = 53359, + SPELL_HUNTER_GLYPH_OF_ARCANE_SHOT = 61389, SPELL_HUNTER_GLYPH_OF_ASPECT_OF_THE_VIPER = 56851, SPELL_HUNTER_IMPROVED_MEND_PET = 24406, SPELL_HUNTER_INVIGORATION_TRIGGERED = 53398, @@ -192,8 +193,8 @@ class spell_hun_chimera_shot : public SpellScriptLoader { uint32 spellId = 0; int32 basePoint = 0; - Unit::AuraApplicationMap& Auras = unitTarget->GetAppliedAuras(); - for (Unit::AuraApplicationMap::iterator i = Auras.begin(); i != Auras.end(); ++i) + Unit::AuraApplicationMap const& auras = unitTarget->GetAppliedAuras(); + for (Unit::AuraApplicationMap::const_iterator i = auras.begin(); i != auras.end(); ++i) { Aura* aura = i->second->GetBase(); if (aura->GetCasterGUID() != caster->GetGUID()) @@ -296,6 +297,68 @@ class spell_hun_disengage : public SpellScriptLoader } }; +// 56841 - Glyph of Arcane Shot +class spell_hun_glyph_of_arcane_shot : public SpellScriptLoader +{ + public: + spell_hun_glyph_of_arcane_shot() : SpellScriptLoader("spell_hun_glyph_of_arcane_shot") { } + + class spell_hun_glyph_of_arcane_shot_AuraScript : public AuraScript + { + PrepareAuraScript(spell_hun_glyph_of_arcane_shot_AuraScript); + + bool Validate(SpellInfo const* /*spellInfo*/) override + { + if (!sSpellMgr->GetSpellInfo(SPELL_HUNTER_GLYPH_OF_ARCANE_SHOT)) + return false; + return true; + } + + bool CheckProc(ProcEventInfo& eventInfo) + { + if (Unit* procTarget = eventInfo.GetProcTarget()) + { + Unit::AuraApplicationMap const& auras = procTarget->GetAppliedAuras(); + for (Unit::AuraApplicationMap::const_iterator i = auras.begin(); i != auras.end(); ++i) + { + Aura const* aura = i->second->GetBase(); + if (aura->GetCasterGUID() != GetTarget()->GetGUID()) + continue; + // Search only Serpent Sting, Viper Sting, Scorpid Sting, Wyvern Sting + if (aura->GetSpellInfo()->SpellFamilyName == SPELLFAMILY_HUNTER + && aura->GetSpellInfo()->SpellFamilyFlags.HasFlag(0xC000, 0x1080)) + return true; + } + } + return false; + } + + void HandleProc(AuraEffect const* aurEff, ProcEventInfo& eventInfo) + { + PreventDefaultAction(); + SpellInfo const* procSpell = eventInfo.GetSpellInfo(); + if (!procSpell) + return; + + int32 mana = procSpell->CalcPowerCost(GetTarget(), procSpell->GetSchoolMask()); + ApplyPct(mana, aurEff->GetAmount()); + + GetTarget()->CastCustomSpell(SPELL_HUNTER_GLYPH_OF_ARCANE_SHOT, SPELLVALUE_BASE_POINT0, mana, GetTarget()); + } + + void Register() override + { + DoCheckProc += AuraCheckProcFn(spell_hun_glyph_of_arcane_shot_AuraScript::CheckProc); + OnEffectProc += AuraEffectProcFn(spell_hun_glyph_of_arcane_shot_AuraScript::HandleProc, EFFECT_0, SPELL_AURA_DUMMY); + } + }; + + AuraScript* GetAuraScript() const override + { + return new spell_hun_glyph_of_arcane_shot_AuraScript(); + } +}; + // -19572 - Improved Mend Pet class spell_hun_improved_mend_pet : public SpellScriptLoader { @@ -336,6 +399,7 @@ class spell_hun_improved_mend_pet : public SpellScriptLoader return new spell_hun_improved_mend_pet_AuraScript(); } }; + // 53412 - Invigoration class spell_hun_invigoration : public SpellScriptLoader { @@ -952,6 +1016,7 @@ void AddSC_hunter_spell_scripts() new spell_hun_ascpect_of_the_viper(); new spell_hun_chimera_shot(); new spell_hun_disengage(); + new spell_hun_glyph_of_arcane_shot(); new spell_hun_improved_mend_pet(); new spell_hun_invigoration(); new spell_hun_last_stand_pet(); diff --git a/src/server/scripts/Spells/spell_rogue.cpp b/src/server/scripts/Spells/spell_rogue.cpp index 3ca2db40d65..9b577d4e140 100644 --- a/src/server/scripts/Spells/spell_rogue.cpp +++ b/src/server/scripts/Spells/spell_rogue.cpp @@ -41,6 +41,9 @@ enum RogueSpells SPELL_ROGUE_SHIV_TRIGGERED = 5940, SPELL_ROGUE_TRICKS_OF_THE_TRADE_DMG_BOOST = 57933, SPELL_ROGUE_TRICKS_OF_THE_TRADE_PROC = 59628, + SPELL_ROGUE_HONOR_AMONG_THIEVES = 51698, + SPELL_ROGUE_HONOR_AMONG_THIEVES_PROC = 52916, + SPELL_ROGUE_HONOR_AMONG_THIEVES_2 = 51699 }; // 13877, 33735, (check 51211, 65956) - Blade Flurry @@ -703,6 +706,143 @@ class spell_rog_tricks_of_the_trade_proc : public SpellScriptLoader } }; +// 51698,51700,51701 - Honor Among Thieves +class spell_rog_honor_among_thieves : public SpellScriptLoader +{ +public: + spell_rog_honor_among_thieves() : SpellScriptLoader("spell_rog_honor_among_thieves") { } + + class spell_rog_honor_among_thieves_AuraScript : public AuraScript + { + PrepareAuraScript(spell_rog_honor_among_thieves_AuraScript); + + bool CheckProc(ProcEventInfo& /*eventInfo*/) + { + Unit* caster = GetCaster(); + if (!caster) + return false; + + if (!caster->GetSpellHistory()->HasCooldown(GetSpellInfo()->Effects[EFFECT_0].TriggerSpell)) + return true; + + return false; + } + + void HandleProc(AuraEffect const* aurEff, ProcEventInfo& /*eventInfo*/) + { + PreventDefaultAction(); + + Unit* caster = GetCaster(); + if (!caster) + return; + + Unit* target = GetTarget(); + target->CastSpell(target, GetSpellInfo()->Effects[EFFECT_0].TriggerSpell, TriggerCastFlags(TRIGGERED_FULL_MASK & ~TRIGGERED_IGNORE_SPELL_AND_CATEGORY_CD), nullptr, aurEff, caster->GetGUID()); + } + + void Register() override + { + DoCheckProc += AuraCheckProcFn(spell_rog_honor_among_thieves_AuraScript::CheckProc); + OnEffectProc += AuraEffectProcFn(spell_rog_honor_among_thieves_AuraScript::HandleProc, EFFECT_0, SPELL_AURA_PROC_TRIGGER_SPELL); + } + }; + + AuraScript* GetAuraScript() const override + { + return new spell_rog_honor_among_thieves_AuraScript(); + } +}; + +// 52916 - Honor Among Thieves (Proc) +class spell_rog_honor_among_thieves_proc : public SpellScriptLoader +{ +public: + spell_rog_honor_among_thieves_proc() : SpellScriptLoader("spell_rog_honor_among_thieves_proc") { } + + class spell_rog_honor_among_thieves_proc_SpellScript : public SpellScript + { + PrepareSpellScript(spell_rog_honor_among_thieves_proc_SpellScript); + + bool Validate(SpellInfo const* /*spellInfo*/) override + { + if (!sSpellMgr->GetSpellInfo(SPELL_ROGUE_HONOR_AMONG_THIEVES_PROC)) + return false; + + return true; + } + + void FilterTargets(std::list<WorldObject*>& targets) + { + targets.clear(); + + Unit* target = GetOriginalCaster(); + if (!target) + return; + + targets.push_back(target); + } + + void HandleBeforeHit() + { + Unit* target = GetHitUnit(); + if (!target) + return; + + /* + * The applied aura has a duration of 8 seconds + * This prevents new applications while its active + * Removing it on each new proc enables the application from different sources (different grouped players) + * and on new procs after the source cooldown is finished (1 second) + */ + if (target->HasAura(GetSpellInfo()->Id)) + target->RemoveAura(GetSpellInfo()->Id); + } + + void TriggerCooldown() + { + Unit* target = GetHitUnit(); + if (!target) + return; + + target->GetSpellHistory()->AddCooldown(GetSpellInfo()->Id, 0, std::chrono::seconds(1)); + } + + void Register() override + { + OnObjectAreaTargetSelect += SpellObjectAreaTargetSelectFn(spell_rog_honor_among_thieves_proc_SpellScript::FilterTargets, EFFECT_0, TARGET_UNIT_CASTER_AREA_PARTY); + BeforeHit += SpellHitFn(spell_rog_honor_among_thieves_proc_SpellScript::HandleBeforeHit); + AfterHit += SpellHitFn(spell_rog_honor_among_thieves_proc_SpellScript::TriggerCooldown); + } + }; + + SpellScript* GetSpellScript() const override + { + return new spell_rog_honor_among_thieves_proc_SpellScript(); + } + + class spell_rog_honor_among_thieves_proc_AuraScript : public AuraScript + { + PrepareAuraScript(spell_rog_honor_among_thieves_proc_AuraScript); + + void HandleEffectApply(AuraEffect const* /*aurEff*/, AuraEffectHandleModes /*mode*/) + { + if (Player* player = GetTarget()->ToPlayer()) + if (Unit* spellTarget = ObjectAccessor::GetUnit(*player, player->GetTarget())) + player->CastSpell(spellTarget, SPELL_ROGUE_HONOR_AMONG_THIEVES_2, true); + } + + void Register() override + { + AfterEffectApply += AuraEffectApplyFn(spell_rog_honor_among_thieves_proc_AuraScript::HandleEffectApply, EFFECT_0, SPELL_AURA_DUMMY, AURA_EFFECT_HANDLE_REAL); + } + }; + + AuraScript* GetAuraScript() const override + { + return new spell_rog_honor_among_thieves_proc_AuraScript(); + } +}; + void AddSC_rogue_spell_scripts() { new spell_rog_blade_flurry(); @@ -716,4 +856,6 @@ void AddSC_rogue_spell_scripts() new spell_rog_shiv(); new spell_rog_tricks_of_the_trade(); new spell_rog_tricks_of_the_trade_proc(); + new spell_rog_honor_among_thieves(); + new spell_rog_honor_among_thieves_proc(); } diff --git a/src/server/scripts/Spells/spell_script_loader.cpp b/src/server/scripts/Spells/spell_script_loader.cpp new file mode 100644 index 00000000000..b2c8d6663fa --- /dev/null +++ b/src/server/scripts/Spells/spell_script_loader.cpp @@ -0,0 +1,52 @@ +/* + * Copyright (C) 2008-2016 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/>. + */ + +// This is where scripts' loading functions should be declared: +void AddSC_deathknight_spell_scripts(); +void AddSC_druid_spell_scripts(); +void AddSC_generic_spell_scripts(); +void AddSC_hunter_spell_scripts(); +void AddSC_mage_spell_scripts(); +void AddSC_paladin_spell_scripts(); +void AddSC_priest_spell_scripts(); +void AddSC_rogue_spell_scripts(); +void AddSC_shaman_spell_scripts(); +void AddSC_warlock_spell_scripts(); +void AddSC_warrior_spell_scripts(); +void AddSC_quest_spell_scripts(); +void AddSC_item_spell_scripts(); +void AddSC_holiday_spell_scripts(); + +// The name of this function should match: +// void Add${NameOfDirectory}Scripts() +void AddSpellsScripts() +{ + AddSC_deathknight_spell_scripts(); + AddSC_druid_spell_scripts(); + AddSC_generic_spell_scripts(); + AddSC_hunter_spell_scripts(); + AddSC_mage_spell_scripts(); + AddSC_paladin_spell_scripts(); + AddSC_priest_spell_scripts(); + AddSC_rogue_spell_scripts(); + AddSC_shaman_spell_scripts(); + AddSC_warlock_spell_scripts(); + AddSC_warrior_spell_scripts(); + AddSC_quest_spell_scripts(); + AddSC_item_spell_scripts(); + AddSC_holiday_spell_scripts(); +} diff --git a/src/server/scripts/World/CMakeLists.txt b/src/server/scripts/World/CMakeLists.txt deleted file mode 100644 index 17b3f2d8492..00000000000 --- a/src/server/scripts/World/CMakeLists.txt +++ /dev/null @@ -1,18 +0,0 @@ -# Copyright (C) 2008-2016 TrinityCore <http://www.trinitycore.org/> -# -# This file is free software; as a special exception the author gives -# unlimited permission to copy and/or distribute it, with or without -# modifications, as long as this notice is preserved. -# -# This program is distributed in the hope that it will be useful, but -# WITHOUT ANY WARRANTY, to the extent permitted by law; without even the -# implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. - -file(GLOB_RECURSE sources_World World/*.cpp World/*.h) - -set(scripts_STAT_SRCS - ${scripts_STAT_SRCS} - ${sources_World} -) - -message(" -> Prepared: World") diff --git a/src/server/scripts/World/npcs_special.cpp b/src/server/scripts/World/npcs_special.cpp index 56d48949fac..159faa38c62 100644 --- a/src/server/scripts/World/npcs_special.cpp +++ b/src/server/scripts/World/npcs_special.cpp @@ -57,7 +57,6 @@ EndContentData */ #include "SpellHistory.h" #include "SpellAuras.h" #include "Pet.h" -#include "PetAI.h" #include "CreatureTextMgr.h" #include "SmartAI.h" @@ -2192,7 +2191,7 @@ public: // Check if we are near Elune'ara lake south, if so try to summon Omen or a minion if (me->GetZoneId() == ZONE_MOONGLADE) { - if (!me->FindNearestCreature(NPC_OMEN, 100.0f, false) && me->GetDistance2d(omenSummonPos.GetPositionX(), omenSummonPos.GetPositionY()) <= 100.0f) + if (!me->FindNearestCreature(NPC_OMEN, 100.0f) && me->GetDistance2d(omenSummonPos.GetPositionX(), omenSummonPos.GetPositionY()) <= 100.0f) { switch (urand(0, 9)) { @@ -2572,159 +2571,6 @@ class npc_train_wrecker : public CreatureScript } }; -enum EgbertMisc -{ - EVENT_MOVE_POS = 1, - EVENT_RETURN = 2 -}; - -class npc_egbert : public CreatureScript -{ -public: - npc_egbert() : CreatureScript("npc_egbert") {} - - struct npc_egbertAI : public PetAI - { - npc_egbertAI(Creature* creature) : PetAI(creature) - { - if (Unit* owner = me->GetCharmerOrOwner()) - if (owner->GetMap()->GetEntry()->addon > 1) - me->SetCanFly(true); - } - - void Reset() override - { - _events.Reset(); - _events.ScheduleEvent(EVENT_MOVE_POS, urandms(1, 20)); - } - - void UpdateAI(uint32 diff) override - { - _events.Update(diff); - - while (uint32 eventId = _events.ExecuteEvent()) - { - switch (eventId) - { - case EVENT_MOVE_POS: - if (Unit* owner = me->GetCharmerOrOwner()) - { - me->GetMotionMaster()->Clear(); - me->GetMotionMaster()->MovePoint(0, owner->GetPositionX() + frand(-30.0f, 30.0f), owner->GetPositionY() + frand(-30.0f, 30.0f), owner->GetPositionZ()); - } - _events.ScheduleEvent(EVENT_RETURN, urandms(3, 4)); - break; - case EVENT_RETURN: - if (Unit* owner = me->GetCharmerOrOwner()) - me->GetMotionMaster()->MoveFollow(owner, PET_FOLLOW_DIST, me->GetFollowAngle()); - _events.ScheduleEvent(EVENT_MOVE_POS, urandms(1, 20)); - break; - default: - break; - } - } - } - private: - EventMap _events; - }; - - CreatureAI* GetAI(Creature* creature) const - { - return new npc_egbertAI(creature); - } -}; - -enum PandarenMonkMisc -{ - SPELL_PANDAREN_MONK = 69800, - EVENT_FOCUS = 1, - EVENT_EMOTE = 2, - EVENT_FOLLOW = 3, - EVENT_DRINK = 4 -}; - -class npc_pandaren_monk : public CreatureScript -{ -public: - npc_pandaren_monk() : CreatureScript("npc_pandaren_monk") {} - - struct npc_pandaren_monkAI : public NullCreatureAI - { - npc_pandaren_monkAI(Creature* creature) : NullCreatureAI(creature) { } - - void Reset() override - { - _events.Reset(); - _events.ScheduleEvent(EVENT_FOCUS, 1000); - } - - void EnterEvadeMode(EvadeReason why) override - { - if (!_EnterEvadeMode(why)) - return; - - Reset(); - } - - void ReceiveEmote(Player* /*player*/, uint32 emote) override - { - me->InterruptSpell(CURRENT_CHANNELED_SPELL); - me->StopMoving(); - - switch (emote) - { - case TEXT_EMOTE_BOW: - _events.ScheduleEvent(EVENT_FOCUS, 1000); - break; - case TEXT_EMOTE_DRINK: - _events.ScheduleEvent(EVENT_DRINK, 1000); - break; - } - } - - void UpdateAI(uint32 diff) override - { - _events.Update(diff); - - if (Unit* owner = me->GetCharmerOrOwner()) - if (!me->IsWithinDist(owner, 30.f)) - me->InterruptSpell(CURRENT_CHANNELED_SPELL); - - while (uint32 eventId = _events.ExecuteEvent()) - { - switch (eventId) - { - case EVENT_FOCUS: - if (Unit* owner = me->GetCharmerOrOwner()) - me->SetFacingToObject(owner); - _events.ScheduleEvent(EVENT_EMOTE, 1000); - break; - case EVENT_EMOTE: - me->HandleEmoteCommand(EMOTE_ONESHOT_BOW); - _events.ScheduleEvent(EVENT_FOLLOW, 1000); - break; - case EVENT_FOLLOW: - if (Unit* owner = me->GetCharmerOrOwner()) - me->GetMotionMaster()->MoveFollow(owner, PET_FOLLOW_DIST, PET_FOLLOW_ANGLE); - break; - case EVENT_DRINK: - me->CastSpell(me, SPELL_PANDAREN_MONK, false); - break; - default: - break; - } - } - } - private: - EventMap _events; - }; - - CreatureAI* GetAI(Creature* creature) const - { - return new npc_pandaren_monkAI(creature); - } -}; - void AddSC_npcs_special() { new npc_air_force_bots(); @@ -2750,6 +2596,4 @@ void AddSC_npcs_special() new npc_imp_in_a_ball(); new npc_stable_master(); new npc_train_wrecker(); - new npc_egbert(); - new npc_pandaren_monk(); } diff --git a/src/server/scripts/World/world_script_loader.cpp b/src/server/scripts/World/world_script_loader.cpp new file mode 100644 index 00000000000..0167024799f --- /dev/null +++ b/src/server/scripts/World/world_script_loader.cpp @@ -0,0 +1,59 @@ +/* + * Copyright (C) 2008-2016 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 "World.h" + +// This is where scripts' loading functions should be declared: +// world +void AddSC_areatrigger_scripts(); +void AddSC_emerald_dragons(); +void AddSC_generic_creature(); +void AddSC_go_scripts(); +void AddSC_guards(); +void AddSC_item_scripts(); +void AddSC_npc_professions(); +void AddSC_npc_innkeeper(); +void AddSC_npcs_special(); +void AddSC_achievement_scripts(); +void AddSC_action_ip_logger(); +void AddSC_duel_reset(); +// player +void AddSC_chat_log(); +void AddSC_action_ip_logger(); + +// The name of this function should match: +// void Add${NameOfDirectory}Scripts() +void AddWorldScripts() +{ + AddSC_areatrigger_scripts(); + AddSC_emerald_dragons(); + AddSC_generic_creature(); + AddSC_go_scripts(); + AddSC_guards(); + AddSC_item_scripts(); + AddSC_npc_professions(); + AddSC_npc_innkeeper(); + AddSC_npcs_special(); + AddSC_achievement_scripts(); + AddSC_chat_log(); // location: scripts\World\chat_log.cpp + + // FIXME: This should be moved in a script validation hook. + // To avoid duplicate code, we check once /*ONLY*/ if logging is permitted or not. + if (sWorld->getBoolConfig(CONFIG_IP_BASED_ACTION_LOGGING)) + AddSC_action_ip_logger(); // location: scripts\World\action_ip_logger.cpp + AddSC_duel_reset(); +} diff --git a/src/server/shared/Networking/AsyncAcceptor.h b/src/server/shared/Networking/AsyncAcceptor.h index 260e1c8ea11..0f3fd9a145b 100644 --- a/src/server/shared/Networking/AsyncAcceptor.h +++ b/src/server/shared/Networking/AsyncAcceptor.h @@ -20,34 +20,39 @@ #include "Log.h" #include <boost/asio.hpp> +#include <functional> using boost::asio::ip::tcp; class AsyncAcceptor { public: - typedef void(*ManagerAcceptHandler)(tcp::socket&& newSocket); + typedef void(*AcceptCallback)(tcp::socket&& newSocket, uint32 threadIndex); AsyncAcceptor(boost::asio::io_service& ioService, std::string const& bindIp, uint16 port) : _acceptor(ioService, tcp::endpoint(boost::asio::ip::address::from_string(bindIp), port)), - _socket(ioService) + _socket(ioService), _closed(false), _socketFactory(std::bind(&AsyncAcceptor::DefeaultSocketFactory, this)) { } - template <class T> + template<class T> void AsyncAccept(); - void AsyncAcceptManaged(ManagerAcceptHandler mgrHandler) + template<AcceptCallback acceptCallback> + void AsyncAcceptWithCallback() { - _acceptor.async_accept(_socket, [this, mgrHandler](boost::system::error_code error) + tcp::socket* socket; + uint32 threadIndex; + std::tie(socket, threadIndex) = _socketFactory(); + _acceptor.async_accept(*socket, [this, socket, threadIndex](boost::system::error_code error) { if (!error) { try { - _socket.non_blocking(true); + socket->non_blocking(true); - mgrHandler(std::move(_socket)); + acceptCallback(std::move(*socket), threadIndex); } catch (boost::system::system_error const& err) { @@ -55,13 +60,29 @@ public: } } - AsyncAcceptManaged(mgrHandler); + if (!_closed) + this->AsyncAcceptWithCallback<acceptCallback>(); }); } + void Close() + { + if (_closed.exchange(true)) + return; + + boost::system::error_code err; + _acceptor.close(err); + } + + void SetSocketFactory(std::function<std::pair<tcp::socket*, uint32>()> func) { _socketFactory = func; } + private: + std::pair<tcp::socket*, uint32> DefeaultSocketFactory() { return std::make_pair(&_socket, 0); } + tcp::acceptor _acceptor; tcp::socket _socket; + std::atomic<bool> _closed; + std::function<std::pair<tcp::socket*, uint32>()> _socketFactory; }; template<class T> @@ -83,7 +104,8 @@ void AsyncAcceptor::AsyncAccept() } // lets slap some more this-> on this so we can fix this bug with gcc 4.7.2 throwing internals in yo face - this->AsyncAccept<T>(); + if (!_closed) + this->AsyncAccept<T>(); }); } diff --git a/src/server/shared/Networking/MessageBuffer.h b/src/server/shared/Networking/MessageBuffer.h index 189a56f18b6..d68bee181b1 100644 --- a/src/server/shared/Networking/MessageBuffer.h +++ b/src/server/shared/Networking/MessageBuffer.h @@ -105,7 +105,7 @@ public: return std::move(_storage); } - MessageBuffer& operator=(MessageBuffer& right) + MessageBuffer& operator=(MessageBuffer const& right) { if (this != &right) { diff --git a/src/server/shared/Networking/NetworkThread.h b/src/server/shared/Networking/NetworkThread.h index ac216838bce..be0e9f10176 100644 --- a/src/server/shared/Networking/NetworkThread.h +++ b/src/server/shared/Networking/NetworkThread.h @@ -22,6 +22,8 @@ #include "Errors.h" #include "Log.h" #include "Timer.h" +#include <boost/asio/ip/tcp.hpp> +#include <boost/asio/deadline_timer.hpp> #include <atomic> #include <chrono> #include <memory> @@ -29,11 +31,14 @@ #include <set> #include <thread> +using boost::asio::ip::tcp; + template<class SocketType> class NetworkThread { public: - NetworkThread() : _connections(0), _stopped(false), _thread(nullptr) + NetworkThread() : _connections(0), _stopped(false), _thread(nullptr), + _acceptSocket(_io_service), _updateTimer(_io_service) { } @@ -50,6 +55,7 @@ public: void Stop() { _stopped = true; + _io_service.stop(); } bool Start() @@ -80,10 +86,12 @@ public: std::lock_guard<std::mutex> lock(_newSocketsLock); ++_connections; - _newSockets.insert(sock); + _newSockets.push_back(sock); SocketAdded(sock); } + tcp::socket* GetSocketForAccept() { return &_acceptSocket; } + protected: virtual void SocketAdded(std::shared_ptr<SocketType> /*sock*/) { } virtual void SocketRemoved(std::shared_ptr<SocketType> /*sock*/) { } @@ -95,16 +103,15 @@ protected: if (_newSockets.empty()) return; - for (typename SocketSet::const_iterator i = _newSockets.begin(); i != _newSockets.end(); ++i) + for (std::shared_ptr<SocketType> sock : _newSockets) { - if (!(*i)->IsOpen()) + if (!sock->IsOpen()) { - SocketRemoved(*i); - + SocketRemoved(sock); --_connections; } else - _Sockets.insert(*i); + _sockets.push_back(sock); } _newSockets.clear(); @@ -114,53 +121,58 @@ protected: { TC_LOG_DEBUG("misc", "Network Thread Starting"); - typename SocketSet::iterator i, t; + _updateTimer.expires_from_now(boost::posix_time::milliseconds(10)); + _updateTimer.async_wait(std::bind(&NetworkThread<SocketType>::Update, this)); + _io_service.run(); - uint32 sleepTime = 10; - uint32 tickStart = 0, diff = 0; - while (!_stopped) - { - std::this_thread::sleep_for(std::chrono::milliseconds(sleepTime)); + TC_LOG_DEBUG("misc", "Network Thread exits"); + _newSockets.clear(); + _sockets.clear(); + } + + void Update() + { + if (_stopped) + return; - tickStart = getMSTime(); + _updateTimer.expires_from_now(boost::posix_time::milliseconds(10)); + _updateTimer.async_wait(std::bind(&NetworkThread<SocketType>::Update, this)); - AddNewSockets(); + AddNewSockets(); - for (i = _Sockets.begin(); i != _Sockets.end();) + _sockets.erase(std::remove_if(_sockets.begin(), _sockets.end(), [this](std::shared_ptr<SocketType> sock) + { + if (!sock->Update()) { - if (!(*i)->Update()) - { - if ((*i)->IsOpen()) - (*i)->CloseSocket(); - - SocketRemoved(*i); - - --_connections; - _Sockets.erase(i++); - } - else - ++i; - } + if (sock->IsOpen()) + sock->CloseSocket(); - diff = GetMSTimeDiffToNow(tickStart); - sleepTime = diff > 10 ? 0 : 10 - diff; - } + this->SocketRemoved(sock); - TC_LOG_DEBUG("misc", "Network Thread exits"); + --this->_connections; + return true; + } + + return false; + }), _sockets.end()); } private: - typedef std::set<std::shared_ptr<SocketType> > SocketSet; + typedef std::vector<std::shared_ptr<SocketType>> SocketContainer; std::atomic<int32> _connections; std::atomic<bool> _stopped; std::thread* _thread; - SocketSet _Sockets; + SocketContainer _sockets; std::mutex _newSocketsLock; - SocketSet _newSockets; + SocketContainer _newSockets; + + boost::asio::io_service _io_service; + tcp::socket _acceptSocket; + boost::asio::deadline_timer _updateTimer; }; #endif // NetworkThread_h__ diff --git a/src/server/shared/Networking/Socket.h b/src/server/shared/Networking/Socket.h index a2f57b5029e..d1ba7f49aa4 100644 --- a/src/server/shared/Networking/Socket.h +++ b/src/server/shared/Networking/Socket.h @@ -21,15 +21,11 @@ #include "MessageBuffer.h" #include "Log.h" #include <atomic> -#include <vector> -#include <mutex> #include <queue> #include <memory> #include <functional> #include <type_traits> #include <boost/asio/ip/tcp.hpp> -#include <boost/asio/write.hpp> -#include <boost/asio/read.hpp> using boost::asio::ip::tcp; @@ -63,14 +59,10 @@ public: return false; #ifndef TC_SOCKET_USE_IOCP - std::unique_lock<std::mutex> guard(_writeLock); - if (!guard) + if (_isWritingAsync || _writeQueue.empty()) return true; - if (_isWritingAsync || (!_writeBuffer.GetActiveSize() && _writeQueue.empty())) - return true; - - for (; WriteHandler(guard);) + for (; HandleQueue();) ; #endif @@ -98,14 +90,12 @@ public: std::bind(&Socket<T>::ReadHandlerInternal, this->shared_from_this(), std::placeholders::_1, std::placeholders::_2)); } - void QueuePacket(MessageBuffer&& buffer, std::unique_lock<std::mutex>& guard) + void QueuePacket(MessageBuffer&& buffer) { _writeQueue.push(std::move(buffer)); #ifdef TC_SOCKET_USE_IOCP - AsyncProcessQueue(guard); -#else - (void)guard; + AsyncProcessQueue(); #endif } @@ -135,7 +125,7 @@ protected: virtual void ReadHandler() = 0; - bool AsyncProcessQueue(std::unique_lock<std::mutex>&) + bool AsyncProcessQueue() { if (_isWritingAsync) return false; @@ -154,14 +144,6 @@ protected: return false; } - std::mutex _writeLock; - std::queue<MessageBuffer> _writeQueue; -#ifndef TC_SOCKET_USE_IOCP - MessageBuffer _writeBuffer; -#endif - - boost::asio::io_service& io_service() { return _socket.get_io_service(); } - private: void ReadHandlerInternal(boost::system::error_code error, size_t transferredBytes) { @@ -181,15 +163,13 @@ private: { if (!error) { - std::unique_lock<std::mutex> deleteGuard(_writeLock); - _isWritingAsync = false; _writeQueue.front().ReadCompleted(transferedBytes); if (!_writeQueue.front().GetActiveSize()) _writeQueue.pop(); if (!_writeQueue.empty()) - AsyncProcessQueue(deleteGuard); + AsyncProcessQueue(); else if (_closing) CloseSocket(); } @@ -201,48 +181,15 @@ private: void WriteHandlerWrapper(boost::system::error_code /*error*/, std::size_t /*transferedBytes*/) { - std::unique_lock<std::mutex> guard(_writeLock); _isWritingAsync = false; - WriteHandler(guard); + HandleQueue(); } - bool WriteHandler(std::unique_lock<std::mutex>& guard) + bool HandleQueue() { if (!IsOpen()) return false; - std::size_t bytesToSend = _writeBuffer.GetActiveSize(); - - if (bytesToSend == 0) - return HandleQueue(guard); - - boost::system::error_code error; - std::size_t bytesWritten = _socket.write_some(boost::asio::buffer(_writeBuffer.GetReadPointer(), bytesToSend), error); - - if (error) - { - if (error == boost::asio::error::would_block || error == boost::asio::error::try_again) - return AsyncProcessQueue(guard); - - return false; - } - else if (bytesWritten == 0) - return false; - else if (bytesWritten < bytesToSend) - { - _writeBuffer.ReadCompleted(bytesWritten); - _writeBuffer.Normalize(); - return AsyncProcessQueue(guard); - } - - // now bytesWritten == bytesToSend - _writeBuffer.Reset(); - - return HandleQueue(guard); - } - - bool HandleQueue(std::unique_lock<std::mutex>& guard) - { if (_writeQueue.empty()) return false; @@ -256,7 +203,7 @@ private: if (error) { if (error == boost::asio::error::would_block || error == boost::asio::error::try_again) - return AsyncProcessQueue(guard); + return AsyncProcessQueue(); _writeQueue.pop(); return false; @@ -269,7 +216,7 @@ private: else if (bytesSent < bytesToSend) // now n > 0 { queuedMessage.ReadCompleted(bytesSent); - return AsyncProcessQueue(guard); + return AsyncProcessQueue(); } _writeQueue.pop(); @@ -284,6 +231,7 @@ private: uint16 _remotePort; MessageBuffer _readBuffer; + std::queue<MessageBuffer> _writeQueue; std::atomic<bool> _closed; std::atomic<bool> _closing; diff --git a/src/server/shared/Networking/SocketMgr.h b/src/server/shared/Networking/SocketMgr.h index ce5bc2d8fc2..b14aac4ca47 100644 --- a/src/server/shared/Networking/SocketMgr.h +++ b/src/server/shared/Networking/SocketMgr.h @@ -33,7 +33,7 @@ class SocketMgr public: virtual ~SocketMgr() { - delete[] _threads; + ASSERT(!_threads && !_acceptor && !_threadCount, "StopNetwork must be called prior to SocketMgr destruction"); } virtual bool StartNetwork(boost::asio::io_service& service, std::string const& bindIp, uint16 port) @@ -68,11 +68,19 @@ public: virtual void StopNetwork() { + _acceptor->Close(); + if (_threadCount != 0) for (int32 i = 0; i < _threadCount; ++i) _threads[i].Stop(); Wait(); + + delete _acceptor; + _acceptor = nullptr; + delete[] _threads; + _threads = nullptr; + _threadCount = 0; } void Wait() @@ -82,20 +90,14 @@ public: _threads[i].Wait(); } - virtual void OnSocketOpen(tcp::socket&& sock) + virtual void OnSocketOpen(tcp::socket&& sock, uint32 threadIndex) { - size_t min = 0; - - for (int32 i = 1; i < _threadCount; ++i) - if (_threads[i].GetConnectionCount() < _threads[min].GetConnectionCount()) - min = i; - try { std::shared_ptr<SocketType> newSocket = std::make_shared<SocketType>(std::move(sock)); newSocket->Start(); - _threads[min].AddSocket(newSocket); + _threads[threadIndex].AddSocket(newSocket); } catch (boost::system::system_error const& err) { @@ -105,6 +107,23 @@ public: int32 GetNetworkThreadCount() const { return _threadCount; } + uint32 SelectThreadWithMinConnections() const + { + uint32 min = 0; + + for (int32 i = 1; i < _threadCount; ++i) + if (_threads[i].GetConnectionCount() < _threads[min].GetConnectionCount()) + min = i; + + return min; + } + + std::pair<tcp::socket*, uint32> GetSocketForAccept() + { + uint32 threadIndex = SelectThreadWithMinConnections(); + return std::make_pair(_threads[threadIndex].GetSocketForAccept(), threadIndex); + } + protected: SocketMgr() : _acceptor(nullptr), _threads(nullptr), _threadCount(1) { diff --git a/src/server/worldserver/CMakeLists.txt b/src/server/worldserver/CMakeLists.txt index 535383ac605..99495986842 100644 --- a/src/server/worldserver/CMakeLists.txt +++ b/src/server/worldserver/CMakeLists.txt @@ -131,10 +131,10 @@ set_target_properties(worldserver PROPERTIES LINK_FLAGS "${worldserver_LINK_FLAG target_link_libraries(worldserver game - common + scripts shared database - scripts + common g3dlib gsoap Detour diff --git a/src/server/worldserver/Main.cpp b/src/server/worldserver/Main.cpp index 53c5f250851..58ddce532c0 100644 --- a/src/server/worldserver/Main.cpp +++ b/src/server/worldserver/Main.cpp @@ -449,9 +449,9 @@ bool StartDB() // Load databases DatabaseLoader loader("server.worldserver", DatabaseLoader::DATABASE_NONE); loader - .AddDatabase(WorldDatabase, "World") + .AddDatabase(LoginDatabase, "Login") .AddDatabase(CharacterDatabase, "Character") - .AddDatabase(LoginDatabase, "Login"); + .AddDatabase(WorldDatabase, "World"); if (!loader.Load()) return false; diff --git a/src/server/worldserver/worldserver.conf.dist b/src/server/worldserver/worldserver.conf.dist index 217995cb88a..05d303cfd9b 100644 --- a/src/server/worldserver/worldserver.conf.dist +++ b/src/server/worldserver/worldserver.conf.dist @@ -161,6 +161,45 @@ BindIP = "0.0.0.0" ThreadPool = 2 # +# CMakeCommand +# Description: The path to your CMake binary. +# If the path is left empty, the built-in CMAKE_COMMAND is used. +# Example: "C:/Program Files (x86)/CMake/bin/cmake.exe" +# "/usr/bin/cmake" +# Default: "" + +CMakeCommand = "" + +# +# BuildDirectory +# Description: The path to your build directory. +# If the path is left empty, the built-in CMAKE_BINARY_DIR is used. +# Example: "../TrinityCore" +# Default: "" + +BuildDirectory = "" + +# +# SourceDirectory +# Description: The path to your TrinityCore source directory. +# If the path is left empty, the built-in CMAKE_SOURCE_DIR is used. +# Example: "../TrinityCore" +# Default: "" + +SourceDirectory = "" + +# +# MySQLExecutable +# Description: The path to your mysql cli binary. +# If the path is left empty, built-in path from cmake is used. +# Example: "C:/Program Files/MySQL/MySQL Server 5.6/bin/mysql.exe" +# "mysql.exe" +# "/usr/bin/mysql" +# Default: "" + +MySQLExecutable = "" + +# ################################################################################################### ################################################################################################### @@ -1167,26 +1206,6 @@ BirthdayTime = 1222964635 Updates.EnableDatabases = 7 # -# Updates.SourcePath -# Description: The path to your TrinityCore source directory. -# If the path is left empty, built-in CMAKE_SOURCE_DIR is used. -# Example: "../TrinityCore" -# Default: "" - -Updates.SourcePath = "" - -# -# Updates.MySqlCLIPath -# Description: The path to your mysql cli binary. -# If the path is left empty, built-in path from cmake is used. -# Example: "C:/Program Files/MySQL/MySQL Server 5.6/bin/mysql.exe" -# "mysql.exe" -# "/usr/bin/mysql" -# Default: "" - -Updates.MySqlCLIPath = "" - -# # Updates.AutoSetup # Description: Auto populate empty databases. # Default: 1 - (Enabled) @@ -1354,10 +1373,11 @@ AllowTwoSide.Trade = 0 # # TalentsInspecting -# Description: Allow inspecting characters from the opposing faction. -# Doesn't affect characters in gamemaster mode. -# Default: 1 - (Enabled) -# 0 - (Disabled) +# Description: Allow/disallow inspecting other characters' talents. +# Doesn't affect game master accounts. +# 2 - (Enabled for all characters) +# Default: 1 - (Enabled for characters of the same faction) +# 0 - (Talent inspecting is disabled) TalentsInspecting = 1 diff --git a/src/tools/map_extractor/CMakeLists.txt b/src/tools/map_extractor/CMakeLists.txt index e86ef6aedcb..d0f3e42cef8 100644 --- a/src/tools/map_extractor/CMakeLists.txt +++ b/src/tools/map_extractor/CMakeLists.txt @@ -14,6 +14,7 @@ file(GLOB_RECURSE mapextractor_SRCS *.cpp *.h) set(include_Dirs ${CMAKE_SOURCE_DIR} ${CMAKE_SOURCE_DIR}/dep/cppformat + ${CMAKE_SOURCE_DIR}/dep/g3dlite/include ${CMAKE_SOURCE_DIR}/dep/libmpq ${CMAKE_SOURCE_DIR}/src/common ${CMAKE_SOURCE_DIR}/src/common/Utilities @@ -37,6 +38,7 @@ add_executable(mapextractor target_link_libraries(mapextractor common format + g3dlib mpq ${BZIP2_LIBRARIES} ${ZLIB_LIBRARIES} diff --git a/src/tools/map_extractor/System.cpp b/src/tools/map_extractor/System.cpp index 5d1c31ba2dc..f3a761fd437 100644 --- a/src/tools/map_extractor/System.cpp +++ b/src/tools/map_extractor/System.cpp @@ -31,6 +31,7 @@ #include "adt.h" #include "wdt.h" +#include <G3D/Plane.h> #include <boost/filesystem.hpp> extern ArchiveSet gOpenArchives; @@ -42,12 +43,10 @@ typedef struct } map_id; map_id *map_ids; -uint16 *areas; uint16 *LiqType; #define MAX_PATH_LENGTH 128 char output_path[MAX_PATH_LENGTH] = "."; char input_path[MAX_PATH_LENGTH] = "."; -uint32 maxAreaId = 0; // ************************************************** // Extractor options @@ -231,30 +230,6 @@ uint32 ReadMapDBC() return map_count; } -void ReadAreaTableDBC() -{ - printf("Read AreaTable.dbc file..."); - DBCFile dbc("DBFilesClient\\AreaTable.dbc"); - - if(!dbc.open()) - { - printf("Fatal error: Invalid AreaTable.dbc file format!\n"); - exit(1); - } - - size_t area_count = dbc.getRecordCount(); - size_t maxid = dbc.getMaxId(); - areas = new uint16[maxid + 1]; - memset(areas, 0xff, (maxid + 1) * sizeof(uint16)); - - for(uint32 x = 0; x < area_count; ++x) - areas[dbc.getRecord(x).getUInt(0)] = dbc.getRecord(x).getUInt(3); - - maxAreaId = dbc.getMaxId(); - - printf("Done! (" SZFMTD " areas loaded)\n", area_count); -} - void ReadLiquidTypeTableDBC() { printf("Read LiquidType.dbc file..."); @@ -282,7 +257,7 @@ void ReadLiquidTypeTableDBC() // Map file format data static char const* MAP_MAGIC = "MAPS"; -static char const* MAP_VERSION_MAGIC = "v1.3"; +static char const* MAP_VERSION_MAGIC = "v1.8"; static char const* MAP_AREA_MAGIC = "AREA"; static char const* MAP_HEIGHT_MAGIC = "MHGT"; static char const* MAP_LIQUID_MAGIC = "MLIQ"; @@ -311,9 +286,10 @@ struct map_areaHeader uint16 gridArea; }; -#define MAP_HEIGHT_NO_HEIGHT 0x0001 -#define MAP_HEIGHT_AS_INT16 0x0002 -#define MAP_HEIGHT_AS_INT8 0x0004 +#define MAP_HEIGHT_NO_HEIGHT 0x0001 +#define MAP_HEIGHT_AS_INT16 0x0002 +#define MAP_HEIGHT_AS_INT8 0x0004 +#define MAP_HEIGHT_HAS_FLIGHT_BOUNDS 0x0008 struct map_heightHeader { @@ -358,7 +334,7 @@ float selectUInt16StepStore(float maxDiff) return 65535 / maxDiff; } // Temporary grid data store -uint16 area_flags[ADT_CELLS_PER_GRID][ADT_CELLS_PER_GRID]; +uint16 area_ids[ADT_CELLS_PER_GRID][ADT_CELLS_PER_GRID]; float V8[ADT_GRID_SIZE][ADT_GRID_SIZE]; float V9[ADT_GRID_SIZE+1][ADT_GRID_SIZE+1]; @@ -372,6 +348,9 @@ uint8 liquid_flags[ADT_CELLS_PER_GRID][ADT_CELLS_PER_GRID]; bool liquid_show[ADT_GRID_SIZE][ADT_GRID_SIZE]; float liquid_height[ADT_GRID_SIZE+1][ADT_GRID_SIZE+1]; +int16 flight_box_max[3][3]; +int16 flight_box_min[3][3]; + bool ConvertADT(std::string const& inputPath, std::string const& outputPath, int /*cell_y*/, int /*cell_x*/, uint32 build) { ADT_file adt; @@ -397,34 +376,20 @@ bool ConvertADT(std::string const& inputPath, std::string const& outputPath, int map.buildMagic = build; // Get area flags data - for (int i=0;i<ADT_CELLS_PER_GRID;i++) - { - for(int j=0;j<ADT_CELLS_PER_GRID;j++) - { - adt_MCNK * cell = cells->getMCNK(i,j); - uint32 areaid = cell->areaid; - if(areaid && areaid <= maxAreaId) - { - if(areas[areaid] != 0xffff) - { - area_flags[i][j] = areas[areaid]; - continue; - } - printf("File: %s\nCan't find area flag for areaid %u [%d, %d].\n", inputPath.c_str(), areaid, cell->ix, cell->iy); - } - area_flags[i][j] = 0xffff; - } - } + for (int i = 0; i < ADT_CELLS_PER_GRID; i++) + for (int j = 0; j < ADT_CELLS_PER_GRID; j++) + area_ids[i][j] = cells->getMCNK(i, j)->areaid; + //============================================ // Try pack area data //============================================ bool fullAreaData = false; - uint32 areaflag = area_flags[0][0]; - for (int y=0;y<ADT_CELLS_PER_GRID;y++) + uint32 areaId = area_ids[0][0]; + for (int y = 0; y < ADT_CELLS_PER_GRID; ++y) { - for(int x=0;x<ADT_CELLS_PER_GRID;x++) + for (int x = 0; x < ADT_CELLS_PER_GRID; ++x) { - if(area_flags[y][x]!=areaflag) + if (area_ids[y][x] != areaId) { fullAreaData = true; break; @@ -441,12 +406,12 @@ bool ConvertADT(std::string const& inputPath, std::string const& outputPath, int if (fullAreaData) { areaHeader.gridArea = 0; - map.areaMapSize+=sizeof(area_flags); + map.areaMapSize += sizeof(area_ids); } else { areaHeader.flags |= MAP_AREA_NO_AREA; - areaHeader.gridArea = static_cast<uint16>(areaflag); + areaHeader.gridArea = static_cast<uint16>(areaId); } // @@ -561,6 +526,14 @@ bool ConvertADT(std::string const& inputPath, std::string const& outputPath, int maxHeight = CONF_use_minHeight; } + bool hasFlightBox = false; + if (adt_MFBO* mfbo = adt.a_grid->getMFBO()) + { + memcpy(flight_box_max, &mfbo->max, sizeof(flight_box_max)); + memcpy(flight_box_min, &mfbo->min, sizeof(flight_box_min)); + hasFlightBox = true; + } + map.heightMapOffset = map.areaMapOffset + map.areaMapSize; map.heightMapSize = sizeof(map_heightHeader); @@ -577,6 +550,12 @@ bool ConvertADT(std::string const& inputPath, std::string const& outputPath, int if (CONF_allow_float_to_int && (maxHeight - minHeight) < CONF_flat_height_delta_limit) heightHeader.flags |= MAP_HEIGHT_NO_HEIGHT; + if (hasFlightBox) + { + heightHeader.flags |= MAP_HEIGHT_HAS_FLIGHT_BOUNDS; + map.heightMapSize += sizeof(flight_box_max) + sizeof(flight_box_min); + } + // Try store as packed in uint16 or uint8 values if (!(heightHeader.flags & MAP_HEIGHT_NO_HEIGHT)) { @@ -875,8 +854,8 @@ bool ConvertADT(std::string const& inputPath, std::string const& outputPath, int outFile.write(reinterpret_cast<const char*>(&map), sizeof(map)); // Store area data outFile.write(reinterpret_cast<const char*>(&areaHeader), sizeof(areaHeader)); - if (!(areaHeader.flags&MAP_AREA_NO_AREA)) - outFile.write(reinterpret_cast<const char*>(area_flags), sizeof(area_flags)); + if (!(areaHeader.flags & MAP_AREA_NO_AREA)) + outFile.write(reinterpret_cast<const char*>(area_ids), sizeof(area_ids)); // Store height data outFile.write(reinterpret_cast<const char*>(&heightHeader), sizeof(heightHeader)); @@ -899,6 +878,12 @@ bool ConvertADT(std::string const& inputPath, std::string const& outputPath, int } } + if (heightHeader.flags & MAP_HEIGHT_HAS_FLIGHT_BOUNDS) + { + outFile.write(reinterpret_cast<char*>(flight_box_max), sizeof(flight_box_max)); + outFile.write(reinterpret_cast<char*>(flight_box_min), sizeof(flight_box_min)); + } + // Store liquid data if need if (map.liquidMapOffset) { @@ -935,7 +920,6 @@ void ExtractMapsFromMpq(uint32 build) uint32 map_count = ReadMapDBC(); - ReadAreaTableDBC(); ReadLiquidTypeTableDBC(); std::string path = output_path; @@ -972,8 +956,7 @@ void ExtractMapsFromMpq(uint32 build) } } printf("\n"); - delete [] areas; - delete [] map_ids; + delete[] map_ids; } bool ExtractFile( char const* mpq_name, std::string const& filename ) diff --git a/src/tools/map_extractor/adt.cpp b/src/tools/map_extractor/adt.cpp index f8e6e469ff0..e97b40475d0 100644 --- a/src/tools/map_extractor/adt.cpp +++ b/src/tools/map_extractor/adt.cpp @@ -21,15 +21,16 @@ #include "adt.h" // Helper -int holetab_h[4] = {0x1111, 0x2222, 0x4444, 0x8888}; -int holetab_v[4] = {0x000F, 0x00F0, 0x0F00, 0xF000}; +int holetab_h[4] = { 0x1111, 0x2222, 0x4444, 0x8888 }; +int holetab_v[4] = { 0x000F, 0x00F0, 0x0F00, 0xF000 }; -u_map_fcc MHDRMagic = { {'R','D','H','M'} }; -u_map_fcc MCINMagic = { {'N','I','C','M'} }; -u_map_fcc MH2OMagic = { {'O','2','H','M'} }; -u_map_fcc MCNKMagic = { {'K','N','C','M'} }; -u_map_fcc MCVTMagic = { {'T','V','C','M'} }; -u_map_fcc MCLQMagic = { {'Q','L','C','M'} }; +u_map_fcc MHDRMagic = { { 'R','D','H','M' } }; +u_map_fcc MCINMagic = { { 'N','I','C','M' } }; +u_map_fcc MH2OMagic = { { 'O','2','H','M' } }; +u_map_fcc MCNKMagic = { { 'K','N','C','M' } }; +u_map_fcc MCVTMagic = { { 'T','V','C','M' } }; +u_map_fcc MCLQMagic = { { 'Q','L','C','M' } }; +u_map_fcc MFBOMagic = { { 'O','B','F','M' } }; bool isHole(int holes, int i, int j) { @@ -81,7 +82,7 @@ bool adt_MHDR::prepareLoadedData() if (fcc != MHDRMagic.fcc) return false; - if (size!=sizeof(adt_MHDR)-8) + if (size != sizeof(adt_MHDR) - 8) return false; // Check and prepare MCIN @@ -92,6 +93,9 @@ bool adt_MHDR::prepareLoadedData() if (offsMH2O && !getMH2O()->prepareLoadedData()) return false; + if (offsMFBO && flags & 1 && !getMFBO()->prepareLoadedData()) + return false; + return true; } @@ -154,3 +158,8 @@ bool adt_MCLQ::prepareLoadedData() return true; } + +bool adt_MFBO::prepareLoadedData() +{ + return fcc == MFBOMagic.fcc; +} diff --git a/src/tools/map_extractor/adt.h b/src/tools/map_extractor/adt.h index 7b3dc07ae84..30389939f38 100644 --- a/src/tools/map_extractor/adt.h +++ b/src/tools/map_extractor/adt.h @@ -263,6 +263,28 @@ public: }; // +// Adt file min/max height chunk +// +class adt_MFBO +{ + union + { + uint32 fcc; + char fcc_txt[4]; + }; +public: + uint32 size; + struct plane + { + int16 coords[9]; + }; + plane max; + plane min; + + bool prepareLoadedData(); +}; + +// // Adt file header chunk // class adt_MHDR @@ -274,12 +296,12 @@ class adt_MHDR public: uint32 size; - uint32 pad; + uint32 flags; uint32 offsMCIN; // MCIN - uint32 offsTex; // MTEX - uint32 offsModels; // MMDX - uint32 offsModelsIds; // MMID - uint32 offsMapObejcts; // MWMO + uint32 offsTex; // MTEX + uint32 offsModels; // MMDX + uint32 offsModelsIds; // MMID + uint32 offsMapObejcts; // MWMO uint32 offsMapObejctsIds; // MWID uint32 offsDoodsDef; // MDDF uint32 offsObjectsDef; // MODF @@ -291,9 +313,22 @@ public: uint32 data4; uint32 data5; bool prepareLoadedData(); - adt_MCIN *getMCIN(){ return (adt_MCIN *)((uint8 *)&pad+offsMCIN);} - adt_MH2O *getMH2O(){ return offsMH2O ? (adt_MH2O *)((uint8 *)&pad+offsMH2O) : 0;} - + adt_MCIN* getMCIN() + { + return reinterpret_cast<adt_MCIN*>(reinterpret_cast<uint8*>(&flags) + offsMCIN); + } + adt_MH2O* getMH2O() + { + if (offsMH2O) + return reinterpret_cast<adt_MH2O*>(reinterpret_cast<uint8*>(&flags) + offsMH2O); + return nullptr; + } + adt_MFBO* getMFBO() + { + if (flags & 1 && offsMFBO) + return reinterpret_cast<adt_MFBO*>(reinterpret_cast<uint8*>(&flags) + offsMFBO); + return nullptr; + } }; class ADT_file : public FileLoader{ diff --git a/src/tools/mmaps_generator/MapBuilder.cpp b/src/tools/mmaps_generator/MapBuilder.cpp index 3a63f9718db..80b7b266f27 100644 --- a/src/tools/mmaps_generator/MapBuilder.cpp +++ b/src/tools/mmaps_generator/MapBuilder.cpp @@ -699,7 +699,7 @@ namespace MMAP iv.polyMesh = rcAllocPolyMesh(); if (!iv.polyMesh) { - printf("%s alloc iv.polyMesh FIALED!\n", tileString); + printf("%s alloc iv.polyMesh FAILED!\n", tileString); delete[] pmmerge; delete[] dmmerge; delete[] tiles; @@ -710,7 +710,7 @@ namespace MMAP iv.polyMeshDetail = rcAllocPolyMeshDetail(); if (!iv.polyMeshDetail) { - printf("%s alloc m_dmesh FIALED!\n", tileString); + printf("%s alloc m_dmesh FAILED!\n", tileString); delete[] pmmerge; delete[] dmmerge; delete[] tiles; diff --git a/src/tools/mmaps_generator/TerrainBuilder.cpp b/src/tools/mmaps_generator/TerrainBuilder.cpp index 02f3fb1cf4d..69b1ffcb062 100644 --- a/src/tools/mmaps_generator/TerrainBuilder.cpp +++ b/src/tools/mmaps_generator/TerrainBuilder.cpp @@ -80,7 +80,7 @@ struct map_liquidHeader namespace MMAP { - char const* MAP_VERSION_MAGIC = "v1.3"; + char const* MAP_VERSION_MAGIC = "v1.8"; TerrainBuilder::TerrainBuilder(bool skipLiquid) : m_skipLiquid (skipLiquid){ } TerrainBuilder::~TerrainBuilder() { } |