Merge remote-tracking branch 'tc/3.3.5' into 4.3.4

Conflicts:
	sql/base/characters_database.sql
	sql/updates/world/2016_01_26_00_world.sql
	sql/updates/world/2016_01_31_00_world.sql
	sql/updates/world/2016_02_07_00_world.sql
	src/server/authserver/Server/AuthSession.cpp
	src/server/database/Database/Implementation/LoginDatabase.cpp
	src/server/database/Database/Implementation/LoginDatabase.h
	src/server/game/AI/ScriptedAI/ScriptedCreature.cpp
	src/server/game/AI/ScriptedAI/ScriptedCreature.h
	src/server/game/Achievements/AchievementMgr.cpp
	src/server/game/Chat/Chat.cpp
	src/server/game/DataStores/DBCStores.cpp
	src/server/game/DataStores/DBCStructure.h
	src/server/game/DataStores/DBCfmt.h
	src/server/game/Entities/Player/Player.cpp
	src/server/game/Entities/Unit/Unit.cpp
	src/server/game/Globals/ObjectMgr.cpp
	src/server/game/Handlers/AuctionHouseHandler.cpp
	src/server/game/Handlers/MailHandler.cpp
	src/server/game/Handlers/MovementHandler.cpp
	src/server/game/Server/WorldSocket.cpp
	src/server/game/Server/WorldSocket.h
	src/server/game/Spells/Auras/SpellAuraEffects.cpp
	src/server/game/Spells/SpellEffects.cpp
	src/server/game/Spells/SpellMgr.cpp
	src/server/scripts/Spells/spell_druid.cpp
	src/server/scripts/Spells/spell_generic.cpp
	src/server/scripts/Spells/spell_hunter.cpp
	src/server/scripts/Spells/spell_rogue.cpp
	src/server/scripts/Spells/spell_shaman.cpp
	src/server/shared/Networking/AsyncAcceptor.h
	src/tools/map_extractor/CMakeLists.txt
	src/tools/map_extractor/System.cpp
	src/tools/map_extractor/adt.h
	src/tools/mmaps_generator/MapBuilder.cpp
This commit is contained in:
ariel- committed 2016-02-21 07:02:53 -03:00
commit 8bc477a2de
161 files changed
+3548 -2022

No files matched your search

+23
View File
@@ -0,0 +1,23 @@
**Description**:
**Current behaviour**: Tell us what happens
**Expected behaviour**: Tell us what should happen instead
**Steps to reproduce the problem**:
1.
2.
3.
**Branch(es)**: 335/6x
**TC hash/commit**:
**TDB version**:
**Operating system**:
[//]: # (This template is for problem reports, for other type of reports edit it accordingly)
[//]: # (If this is a crash report, include the crashlog with https://gist.github.com/)
+13
View File
@@ -0,0 +1,13 @@
**Changes proposed**:
-
-
-
**Target branch(es)**: 335/6x
**Issues addressed**: Fixes #
**Tests performed**: (Does it build? Tested in-game?)
**Known issues and TODO list**:
+2 -1
View File
@@ -847,6 +847,7 @@ CREATE TABLE `character_instance` (
`guid` int(10) unsigned NOT NULL DEFAULT '0',
`instance` int(10) unsigned NOT NULL DEFAULT '0',
`permanent` tinyint(3) unsigned NOT NULL DEFAULT '0',
`extendState` TINYINT(2) UNSIGNED NOT NULL DEFAULT '1',
PRIMARY KEY (`guid`,`instance`),
KEY `instance` (`instance`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
@@ -2786,7 +2787,7 @@ CREATE TABLE `updates` (
LOCK TABLES `updates` WRITE;
/*!40000 ALTER TABLE `updates` DISABLE KEYS */;
INSERT INTO `updates` VALUES ('2015_03_20_00_characters.sql','B761760804EA73BD297F296C5C1919687DF7191C','ARCHIVED','2015-03-21 21:44:15',0),('2015_03_20_01_characters.sql','894F08B70449A5481FFAF394EE5571D7FC4D8A3A','ARCHIVED','2015-03-21 21:44:15',0),('2015_03_20_02_characters.sql','97D7BE0CAADC79F3F11B9FD296B8C6CD40FE593B','ARCHIVED','2015-03-21 21:44:51',0),('2015_06_26_00_characters_335.sql','f8230a59a9e878a6f54f421d6621f1595bd93861','ARCHIVED','2015-03-21 21:44:51',0),('2015_09_28_00_characters_335.sql','F8682A431D50E54BDC4AC0E7DBED21AE8AAB6AD4','ARCHIVED','2015-09-28 21:00:00',0),('2016_01_11_00_characters_from_335.sql','AAECE4BA6FDCF0C34A57FADD11DB68DAFD8AE9CD','ARCHIVED','2016-01-10 21:57:56',0),('2016_01_11_01_characters_from_335.sql','F8682A431D50E54BDC4AC0E7DBED21AE8AAB6AD4','ARCHIVED','2015-09-29 22:23:32',0),('2016_01_11_02_characters_from_335.sql','4555A7F35C107E54C13D74D20F141039ED42943E','ARCHIVED','2015-10-29 20:32:37',0),('2016_01_14_from_335_2015_10_06_00_characters.sql','16842FDD7E8547F2260D3312F53EFF8761EFAB35','ARCHIVED','2015-10-11 19:47:41',0),('2016_01_14_from_335_2015_10_07_00_characters.sql','E15AB463CEBE321001D7BFDEA4B662FF618728FD','ARCHIVED','2015-10-11 19:47:41',0),('2016_01_14_from_335_2015_10_12_00_characters.sql','D6F9927BDED72AD0A81D6EC2C6500CBC34A39FA2','ARCHIVED','2015-10-13 01:06:25',0),('2016_01_14_from_335_2015_10_28_00_characters.sql','622A9CA8FCE690429EBE23BA071A37C7A007BF8B','ARCHIVED','2015-10-28 21:49:52',0),('2016_01_14_from_335_2015_11_03_00_characters.sql','CC045717B8FDD9733351E52A5302560CD08AAD57','ARCHIVED','2015-11-03 22:56:17',0);
INSERT INTO `updates` VALUES ('2015_03_20_00_characters.sql','B761760804EA73BD297F296C5C1919687DF7191C','ARCHIVED','2015-03-21 21:44:15',0),('2015_03_20_01_characters.sql','894F08B70449A5481FFAF394EE5571D7FC4D8A3A','ARCHIVED','2015-03-21 21:44:15',0),('2015_03_20_02_characters.sql','97D7BE0CAADC79F3F11B9FD296B8C6CD40FE593B','ARCHIVED','2015-03-21 21:44:51',0),('2015_06_26_00_characters_335.sql','f8230a59a9e878a6f54f421d6621f1595bd93861','ARCHIVED','2015-03-21 21:44:51',0),('2015_09_28_00_characters_335.sql','F8682A431D50E54BDC4AC0E7DBED21AE8AAB6AD4','ARCHIVED','2015-09-28 21:00:00',0),('2016_01_11_00_characters_from_335.sql','AAECE4BA6FDCF0C34A57FADD11DB68DAFD8AE9CD','ARCHIVED','2016-01-10 21:57:56',0),('2016_01_11_01_characters_from_335.sql','F8682A431D50E54BDC4AC0E7DBED21AE8AAB6AD4','ARCHIVED','2015-09-29 22:23:32',0),('2016_01_11_02_characters_from_335.sql','4555A7F35C107E54C13D74D20F141039ED42943E','ARCHIVED','2015-10-29 20:32:37',0),('2016_01_14_from_335_2015_10_06_00_characters.sql','16842FDD7E8547F2260D3312F53EFF8761EFAB35','ARCHIVED','2015-10-11 19:47:41',0),('2016_01_14_from_335_2015_10_07_00_characters.sql','E15AB463CEBE321001D7BFDEA4B662FF618728FD','ARCHIVED','2015-10-11 19:47:41',0),('2016_01_14_from_335_2015_10_12_00_characters.sql','D6F9927BDED72AD0A81D6EC2C6500CBC34A39FA2','ARCHIVED','2015-10-13 01:06:25',0),('2016_01_14_from_335_2015_10_28_00_characters.sql','622A9CA8FCE690429EBE23BA071A37C7A007BF8B','ARCHIVED','2015-10-28 21:49:52',0),('2016_01_14_from_335_2015_11_03_00_characters.sql','CC045717B8FDD9733351E52A5302560CD08AAD57','ARCHIVED','2015-11-03 22:56:17',0),('2016_02_21_from_335_2016_02_10_00_characters.sql','F1B4DA202819CABC7319A4470A2D224A34609E97','RELEASED','2016-02-10 00:00:00',0);
/*!40000 ALTER TABLE `updates` ENABLE KEYS */;
UNLOCK TABLES;
@@ -0,0 +1,2 @@
-- extend=0 is expired, extend=1 is normal, extend=2 is extended
ALTER TABLE `character_instance` ADD COLUMN `extendState` TINYINT(2) UNSIGNED NOT NULL DEFAULT '1';
+6
View File
@@ -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
+83
View File
@@ -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__
@@ -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)
*
+83
View File
@@ -0,0 +1,83 @@
/*
* 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);
}
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;
}
+95
View File
@@ -0,0 +1,95 @@
/*
* 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 <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 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__
-57
View File
@@ -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];
+1 -33
View File
@@ -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
+22
View File
@@ -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)
{
+383 -324
View File
@@ -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,235 +274,211 @@ 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 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 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 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");
}
}
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 (fields[9].GetUInt32() && AuthHelper::IsBuildSupportingBattlenet(_build))
pkt << uint8(WOW_FAIL_USE_BATTLENET);
else 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)
);
}
pkt << uint8(WOW_FAIL_UNLOCKABLE_LOCK);
SendPacket(pkt);
return;
}
}
else //no account
pkt << uint8(WOW_FAIL_UNKNOWN_ACCOUNT);
}
// 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;
}
}
// 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 (fields[13].GetUInt32() && AuthHelper::IsBuildSupportingBattlenet(_build))
pkt << uint8(WOW_FAIL_USE_BATTLENET);
else 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());
@@ -489,7 +552,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);
@@ -505,7 +568,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
PreparedStatement *stmt = LoginDatabase.GetPreparedStatement(LOGIN_UPD_LOGONPROOF);
@@ -513,7 +576,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);
// Finish SRP6 and send the final result to the client
@@ -528,6 +591,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)
{
@@ -568,7 +632,7 @@ bool AuthSession::HandleLogonProof()
}
SendPacket(packet);
_isAuthenticated = true;
_status = STATUS_AUTHED;
}
else
{
@@ -580,7 +644,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);
@@ -588,7 +652,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");
@@ -599,42 +663,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)
{
uint32 WrongPassBanTime = sConfigMgr->GetIntDefault("WrongPass.BanTime", 600);
bool WrongPassBanType = sConfigMgr->GetBoolDefault("WrongPass.BanType", false);
stmt = LoginDatabase.GetPreparedStatement(LOGIN_INS_ACCOUNT_AUTO_BANNED);
stmt->setUInt32(0, _accountInfo.Id);
stmt->setUInt32(1, WrongPassBanTime);
LoginDatabase.Execute(stmt);
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(), _accountInfo.Login.c_str(), WrongPassBanTime, _accountInfo.FailedLogins);
}
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] 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);
}
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);
}
}
}
@@ -645,61 +700,88 @@ bool AuthSession::HandleLogonProof()
bool AuthSession::HandleReconnectChallenge()
{
TC_LOG_DEBUG("server.authserver", "Entering _HandleReconnectChallenge");
sAuthLogonChallenge_C* challenge = reinterpret_cast<sAuthLogonChallenge_C*>(GetReadBuffer().GetReadPointer());
//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);
_login.assign((const char*)challenge->I, challenge->I_len);
PreparedStatement* stmt = LoginDatabase.GetPreparedStatement(LOGIN_SEL_SESSIONKEY);
stmt->setString(0, _login);
PreparedQueryResult result = LoginDatabase.Query(stmt);
// Stop if the account is not found
if (!result)
{
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());
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;
std::string login((const char*)challenge->I, challenge->I_len);
TC_LOG_DEBUG("server.authserver", "[ReconnectChallenge] '%s'", login.c_str());
if (_queryCallback)
{
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);
// Sending response
_queryCallback = std::bind(&AuthSession::ReconnectChallengeCallback, this, std::placeholders::_1);
_queryFuture = LoginDatabase.AsyncQuery(stmt);
return true;
}
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;
@@ -707,7 +789,7 @@ bool AuthSession::HandleReconnectProof()
SHA1Hash sha;
sha.Initialize();
sha.UpdateData(_login);
sha.UpdateData(_accountInfo.Login);
sha.UpdateBigNumbers(&t1, &_reconnectProof, &K, NULL);
sha.Finalize();
@@ -719,13 +801,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;
}
}
@@ -734,20 +816,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();
@@ -784,25 +877,17 @@ bool AuthSession::HandleRealmList()
name = ss.str();
}
uint8 lock = (realm.allowedSecurityLevel > _accountSecurityLevel) ? 1 : 0;
uint8 lock = (realm.allowedSecurityLevel > _accountInfo.SecurityLevel) ? 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();
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>(realm.GetAddressForClient(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
@@ -844,32 +929,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
@@ -897,6 +956,6 @@ void AuthSession::SetVSFields(const std::string& rI)
PreparedStatement* stmt = LoginDatabase.GetPreparedStatement(LOGIN_UPD_VS);
stmt->setString(0, v.AsHexStr());
stmt->setString(1, s.AsHexStr());
stmt->setString(2, _login);
stmt->setString(2, _accountInfo.Login);
LoginDatabase.Execute(stmt);
}
+42 -18
View File
@@ -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)();
};
+6 -9
View File
@@ -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__
@@ -130,6 +130,13 @@ WrongPass.BanType = 0
WrongPass.Logging = 0
#
# BanExpiryCheckInterval
# Description: Time (in seconds) between checks for expired bans
# Default: 60
BanExpiryCheckInterval = 60
#
###################################################################################################
@@ -217,6 +217,7 @@ namespace Battlenet
uint8* GetBuffer() { return _buffer.data(); }
uint8 const* GetBuffer() const { return _buffer.data(); }
uint32 GetReadPos() const { return _readPos; }
size_t GetSize() const { return ((_writePos + 7) & ~7) / 8; }
// These methods are meant to only be used when their corresponding actions in the client ignore the value completely
@@ -63,6 +63,8 @@ namespace Battlenet
void Read() override { }
std::string ToString() const override;
void CallHandler(Session* session) override;
uint8* GetRemainingData() { return _stream.GetBuffer() + (((_stream.GetReadPos() + 7) & ~7) / 8); }
size_t GetRemainingSize() const { return _stream.GetSize() - (((_stream.GetReadPos() + 7) & ~7) / 8); }
};
class LogoutRequest final : public ClientPacket
+58 -34
View File
@@ -141,6 +141,7 @@ void Battlenet::Session::HandleLogonRequest(Authentication::LogonRequest const&
Authentication::LogonResponse* logonResponse = new Authentication::LogonResponse();
logonResponse->SetAuthResult(AUTH_INVALID_PROGRAM);
AsyncWrite(logonResponse);
TC_LOG_DEBUG("session", "[Battlenet::LogonRequest] %s attempted to log in with game other than WoW (using %s)!", GetClientInfo().c_str(), logonRequest.Program.c_str());
return;
}
@@ -149,6 +150,7 @@ void Battlenet::Session::HandleLogonRequest(Authentication::LogonRequest const&
Authentication::LogonResponse* logonResponse = new Authentication::LogonResponse();
logonResponse->SetAuthResult(AUTH_INVALID_OS);
AsyncWrite(logonResponse);
TC_LOG_DEBUG("session", "[Battlenet::LogonRequest] %s attempted to log in from an unsupported platform (using %s)!", GetClientInfo().c_str(), logonRequest.Platform.c_str());
return;
}
@@ -157,6 +159,7 @@ void Battlenet::Session::HandleLogonRequest(Authentication::LogonRequest const&
Authentication::LogonResponse* logonResponse = new Authentication::LogonResponse();
logonResponse->SetAuthResult(AUTH_UNSUPPORTED_LANGUAGE);
AsyncWrite(logonResponse);
TC_LOG_DEBUG("session", "[Battlenet::LogonRequest] %s attempted to log in with unsupported locale (using %s)!", GetClientInfo().c_str(), logonRequest.Locale.c_str());
return;
}
@@ -166,15 +169,23 @@ void Battlenet::Session::HandleLogonRequest(Authentication::LogonRequest const&
{
Authentication::LogonResponse* logonResponse = new Authentication::LogonResponse();
if (!sComponentMgr->HasProgram(component.Program))
{
logonResponse->SetAuthResult(AUTH_INVALID_PROGRAM);
TC_LOG_DEBUG("session", "[Battlenet::LogonRequest] %s is using unsupported component program %s!", GetClientInfo().c_str(), component.Program.c_str());
}
else if (!sComponentMgr->HasPlatform(component.Platform))
{
logonResponse->SetAuthResult(AUTH_INVALID_OS);
TC_LOG_DEBUG("session", "[Battlenet::LogonRequest] %s is using unsupported component platform %s!", GetClientInfo().c_str(), component.Platform.c_str());
}
else
{
if (component.Program != "WoW" || AuthHelper::IsBuildSupportingBattlenet(component.Build))
logonResponse->SetAuthResult(AUTH_REGION_BAD_VERSION);
else
logonResponse->SetAuthResult(AUTH_USE_GRUNT_LOGON);
TC_LOG_DEBUG("session", "[Battlenet::LogonRequest] %s is using unsupported component version %u!", GetClientInfo().c_str(), component.Build);
}
AsyncWrite(logonResponse);
@@ -204,6 +215,7 @@ void Battlenet::Session::HandleLogonRequestCallback(PreparedQueryResult result)
Authentication::LogonResponse* logonResponse = new Authentication::LogonResponse();
logonResponse->SetAuthResult(AUTH_UNKNOWN_ACCOUNT);
AsyncWrite(logonResponse);
TC_LOG_DEBUG("session", "[Battlenet::LogonRequest] %s is trying to log in from unknown account!", GetClientInfo().c_str());
return;
}
@@ -224,7 +236,7 @@ void Battlenet::Session::HandleLogonRequestCallback(PreparedQueryResult result)
std::string ip_address = GetRemoteIpAddress().to_string();
// If the IP is 'locked', check that the player comes indeed from the correct IP address
if (_accountInfo->IsLockedToIP) // if ip is locked
if (_accountInfo->IsLockedToIP)
{
TC_LOG_DEBUG("session", "[Battlenet::LogonRequest] Account '%s' is locked to IP - '%s' is logging in from '%s'", _accountInfo->Login.c_str(), _accountInfo->LastIP.c_str(), ip_address.c_str());
@@ -417,9 +429,10 @@ void Battlenet::Session::HandlePing(Connection::Ping const& /*ping*/)
AsyncWrite(new Connection::Pong());
}
void Battlenet::Session::HandleEnableEncryption(Connection::EnableEncryption const& /*enableEncryption*/)
void Battlenet::Session::HandleEnableEncryption(Connection::EnableEncryption& enableEncryption)
{
_crypt.Init(&K);
_crypt.DecryptRecv(enableEncryption.GetRemainingData(), enableEncryption.GetRemainingSize());
}
void Battlenet::Session::HandleLogoutRequest(Connection::LogoutRequest const& /*logoutRequest*/)
@@ -461,12 +474,13 @@ void Battlenet::Session::HandleListSubscribeRequestCallback(PreparedQueryResult
} while (result->NextRow());
}
for (RealmList::RealmMap::value_type const& i : sRealmList->GetRealms())
listSubscribeResponse->RealmData.push_back(BuildListUpdate(&i.second));
listSubscribeResponse->RealmData.push_back(new WoWRealm::ListComplete());
AsyncWrite(listSubscribeResponse);
for (RealmList::RealmMap::value_type const& i : sRealmList->GetRealms())
AsyncWrite(BuildListUpdate(&i.second));
AsyncWrite(new WoWRealm::ListComplete());
_subscribedToRealmListUpdates = true;
}
@@ -486,7 +500,7 @@ void Battlenet::Session::HandleJoinRequestV2(WoWRealm::JoinRequestV2 const& join
return;
}
joinResponse->ServerSeed = uint32(rand32());
joinResponse->ServerSeed = rand32();
uint8 sessionKey[40];
HmacSha1 hmac(K.GetNumBytes(), K.AsByteArray().get());
@@ -563,7 +577,7 @@ void Battlenet::Session::ReadHandler()
if (stream.Read<bool>(1))
header.Channel = stream.Read<int32>(4);
if (header.Channel != AUTHENTICATION && !_authed)
if (header.Channel != AUTHENTICATION && (header.Channel != CONNECTION || header.Opcode != Connection::CMSG_PING) && !_authed)
{
TC_LOG_DEBUG("session.packets", "%s Received not allowed %s. Client has not authed yet.", GetClientInfo().c_str(), header.ToString().c_str());
CloseSocket();
@@ -608,18 +622,6 @@ void Battlenet::Session::Start()
std::string ip_address = GetRemoteIpAddress().to_string();
TC_LOG_TRACE("session", "Accepted connection from %s", ip_address.c_str());
if (_queryCallback)
{
Authentication::LogonResponse* logonResponse = new Authentication::LogonResponse();
logonResponse->SetAuthResult(AUTH_LOGON_TOO_FAST);
AsyncWrite(logonResponse);
TC_LOG_DEBUG("session", "[Session::Start] %s attempted to log too quick after previous attempt!", GetClientInfo().c_str());
return;
}
// Verify that this IP is not in the ip_banned table
LoginDatabase.Execute(LoginDatabase.GetPreparedStatement(LOGIN_DEL_EXPIRED_IP_BANS));
PreparedStatement* stmt = LoginDatabase.GetPreparedStatement(LOGIN_SEL_IP_INFO);
stmt->setString(0, ip_address);
stmt->setUInt32(1, inet_addr(ip_address.c_str()));
@@ -659,12 +661,37 @@ void Battlenet::Session::CheckIpCallback(PreparedQueryResult result)
bool Battlenet::Session::Update()
{
EncryptableBuffer* queued;
MessageBuffer buffer((std::size_t(BufferSizes::Read)));
while (_bufferQueue.Dequeue(queued))
{
std::size_t packetSize = queued->Buffer.GetActiveSize();
if (queued->Encrypt)
_crypt.EncryptSend(queued->Buffer.GetReadPointer(), packetSize);
if (buffer.GetRemainingSpace() < packetSize)
{
QueuePacket(std::move(buffer));
buffer.Resize(std::size_t(BufferSizes::Read));
}
if (buffer.GetRemainingSpace() >= packetSize)
buffer.Write(queued->Buffer.GetReadPointer(), packetSize);
else // single packet larger than 16384 bytes - client will reject.
QueuePacket(std::move(queued->Buffer));
delete queued;
}
if (buffer.GetActiveSize() > 0)
QueuePacket(std::move(buffer));
if (!BattlenetSocket::Update())
return false;
if (_queryFuture.valid() && _queryFuture.wait_for(std::chrono::seconds(0)) == std::future_status::ready)
{
auto callback = std::move(_queryCallback);
auto callback = _queryCallback;
_queryCallback = nullptr;
callback(_queryFuture.get());
}
@@ -684,15 +711,12 @@ void Battlenet::Session::AsyncWrite(ServerPacket* packet)
packet->Write();
MessageBuffer buffer;
buffer.Write(packet->GetData(), packet->GetSize());
EncryptableBuffer* buffer = new EncryptableBuffer();
buffer->Buffer.Write(packet->GetData(), packet->GetSize());
buffer->Encrypt = _crypt.IsInitialized();
delete packet;
std::unique_lock<std::mutex> guard(_writeLock);
_crypt.EncryptSend(buffer.GetReadPointer(), buffer.GetActiveSize());
QueuePacket(std::move(buffer), guard);
_bufferQueue.Enqueue(buffer);
}
inline void ReplaceResponse(Battlenet::ServerPacket** oldResponse, Battlenet::ServerPacket* newResponse)
@@ -807,6 +831,7 @@ bool Battlenet::Session::HandlePasswordModule(BitStream* dataStream, ServerPacke
Authentication::LogonResponse* logonResponse = new Authentication::LogonResponse();
logonResponse->SetAuthResult(AUTH_UNKNOWN_ACCOUNT);
ReplaceResponse(response, logonResponse);
TC_LOG_DEBUG("session", "[Battlenet::Password] %s attempted to log in with invalid password!", GetClientInfo().c_str());
return false;
}
@@ -815,12 +840,10 @@ bool Battlenet::Session::HandlePasswordModule(BitStream* dataStream, ServerPacke
Authentication::LogonResponse* logonResponse = new Authentication::LogonResponse();
logonResponse->SetAuthResult(LOGIN_NO_GAME_ACCOUNT);
ReplaceResponse(response, logonResponse);
TC_LOG_DEBUG("session", "[Battlenet::Password] %s does not have any linked game accounts!", GetClientInfo().c_str());
return false;
}
//set expired game account bans to inactive
LoginDatabase.Execute(LoginDatabase.GetPreparedStatement(LOGIN_UPD_EXPIRED_ACCOUNT_BANS));
BigNumber M;
sha.Initialize();
sha.UpdateBigNumbers(&A, &M1, &K, NULL);
@@ -929,6 +952,7 @@ bool Battlenet::Session::HandleSelectGameAccountModule(BitStream* dataStream, Se
Authentication::LogonResponse* complete = new Authentication::LogonResponse();
complete->SetAuthResult(LOGIN_NO_GAME_ACCOUNT);
ReplaceResponse(response, complete);
TC_LOG_DEBUG("session", "[Battlenet::SelectGameAccount] %s attempted to log in with invalid game account name %s!", GetClientInfo().c_str(), account.c_str());
return false;
}
@@ -961,7 +985,7 @@ bool Battlenet::Session::HandleSelectGameAccountModule(BitStream* dataStream, Se
bool Battlenet::Session::HandleRiskFingerprintModule(BitStream* dataStream, ServerPacket** response)
{
Authentication::LogonResponse* logonResponse = new Authentication::LogonResponse();
if (dataStream->Read<uint8>(8) == 1 && _accountInfo && _gameAccountInfo)
if (dataStream->Read<uint8>(8) == 1 && _accountInfo && _gameAccountInfo)
{
logonResponse->AccountId = _accountInfo->Id;
logonResponse->GameAccountName = _gameAccountInfo->Name;
@@ -1043,7 +1067,7 @@ bool Battlenet::Session::HandleResumeModule(BitStream* dataStream, ServerPacket*
stmt->setString(0, _accountInfo->Login);
LoginDatabase.Execute(stmt);
TC_LOG_DEBUG("session", "[Battlenet::Resume] Invalid proof!");
TC_LOG_DEBUG("session", "[Battlenet::Resume] %s attempted to reconnect with invalid password!", GetClientInfo().c_str());
Authentication::ResumeResponse* resumeResponse = new Authentication::ResumeResponse();
resumeResponse->SetAuthResult(AUTH_UNKNOWN_ACCOUNT);
ReplaceResponse(response, resumeResponse);
+12 -3
View File
@@ -22,7 +22,8 @@
#include "BattlenetPacketCrypt.h"
#include "Socket.h"
#include "BigNumber.h"
#include "Database/DatabaseEnv.h"
#include "Callback.h"
#include "MPSCQueue.h"
#include <memory>
#include <boost/asio/ip/tcp.hpp>
@@ -96,7 +97,7 @@ namespace Battlenet
// Connection
void HandlePing(Connection::Ping const& ping);
void HandleEnableEncryption(Connection::EnableEncryption const& enableEncryption);
void HandleEnableEncryption(Connection::EnableEncryption& enableEncryption);
void HandleLogoutRequest(Connection::LogoutRequest const& logoutRequest);
void HandleConnectionClosing(Connection::ConnectionClosing const& connectionClosing);
@@ -172,10 +173,18 @@ namespace Battlenet
std::queue<ModuleType> _modulesWaitingForData;
struct EncryptableBuffer
{
MessageBuffer Buffer;
bool Encrypt;
};
MPSCQueue<EncryptableBuffer> _bufferQueue;
PacketCrypt _crypt;
bool _authed;
bool _subscribedToRealmListUpdates;
PreparedQueryResultFuture _queryFuture;
std::function<void(PreparedQueryResult)> _queryCallback;
};
@@ -22,7 +22,8 @@ bool Battlenet::SessionManager::StartNetwork(boost::asio::io_service& service, s
if (!BaseSocketMgr::StartNetwork(service, bindIp, port))
return false;
_acceptor->AsyncAcceptManaged(&OnSocketAccept);
_acceptor->SetSocketFactory(std::bind(&BaseSocketMgr::GetSocketForAccept, this));
_acceptor->AsyncAcceptWithCallback<&OnSocketAccept>();
return true;
}
@@ -31,9 +32,9 @@ NetworkThread<Battlenet::Session>* Battlenet::SessionManager::CreateThreads() co
return new NetworkThread<Session>[GetNetworkThreadCount()];
}
void Battlenet::SessionManager::OnSocketAccept(tcp::socket&& sock)
void Battlenet::SessionManager::OnSocketAccept(tcp::socket&& sock, uint32 threadIndex)
{
sSessionMgr.OnSocketOpen(std::forward<tcp::socket>(sock));
sSessionMgr.OnSocketOpen(std::forward<tcp::socket>(sock), threadIndex);
}
void Battlenet::SessionManager::AddSession(Session* session)
@@ -46,7 +47,11 @@ void Battlenet::SessionManager::AddSession(Session* session)
void Battlenet::SessionManager::RemoveSession(Session* session)
{
std::unique_lock<boost::shared_mutex> lock(_sessionMutex);
_sessions.erase({ session->GetAccountId(), session->GetGameAccountId() });
auto itr = _sessions.find({ session->GetAccountId(), session->GetGameAccountId() });
// Remove old session only if it was not overwritten by reconnecting
if (itr != _sessions.end() && itr->second == session)
_sessions.erase(itr);
_sessionsByAccountId[session->GetAccountId()].remove(session);
}
@@ -40,7 +40,7 @@ namespace Battlenet
#pragma pack(pop)
class SessionManager : SocketMgr<Session>
class SessionManager : public SocketMgr<Session>
{
typedef SocketMgr<Session> BaseSocketMgr;
typedef std::map<SessionInfo, Session*> SessionMap;
@@ -75,7 +75,7 @@ namespace Battlenet
NetworkThread<Session>* CreateThreads() const override;
private:
static void OnSocketAccept(tcp::socket&& sock);
static void OnSocketAccept(tcp::socket&& sock, uint32 threadIndex);
SessionMap _sessions;
SessionByAccountMap _sessionsByAccountId;
@@ -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);
@@ -426,8 +426,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);
@@ -455,6 +455,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);
@@ -490,9 +491,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);
@@ -384,6 +384,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,
@@ -414,9 +415,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,
@@ -24,26 +24,27 @@ void LoginDatabaseConnection::DoPrepareStatements()
PrepareStatement(LOGIN_SEL_REALMLIST, "SELECT id, name, address, localAddress, localSubnetMask, port, icon, flag, timezone, allowedSecurityLevel, population, gamebuild, Region, Battlegroup 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_SEL_IP_BANNED, "SELECT * FROM ip_banned WHERE ip = ?", 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_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, a.battlenet_account 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, a.battlenet_account "
"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, ba.last_ip, ba.locked, ba.lock_country, a.expansion, a.mutetime, ba.locale, a.recruiter, ba.os, ba.id, aa.gmLevel, "
@@ -53,7 +54,7 @@ void LoginDatabaseConnection::DoPrepareStatements()
"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);
@@ -32,26 +32,23 @@ enum LoginDatabaseStatements
LOGIN_SEL_REALMLIST,
LOGIN_DEL_EXPIRED_IP_BANS,
LOGIN_UPD_EXPIRED_ACCOUNT_BANS,
LOGIN_SEL_IP_BANNED,
LOGIN_SEL_IP_INFO,
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,
@@ -142,14 +142,12 @@ UpdateFetcher::SQLUpdate UpdateFetcher::ReadSQLUpdate(boost::filesystem::path co
std::ifstream in(file.c_str());
WPFatal(in.is_open(), "Could not read an update file.");
auto const start_pos = in.tellg();
in.ignore(std::numeric_limits<std::streamsize>::max());
auto const char_count = in.gcount();
in.seekg(start_pos);
auto update = [&in] {
std::ostringstream ss;
ss << in.rdbuf();
return Trinity::make_unique<std::string>(ss.str());
}();
SQLUpdate const update(new std::string(char_count, char{}));
in.read(&(*update)[0], update->size());
in.close();
return update;
}
+1 -1
View File
@@ -103,7 +103,7 @@ 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;
typedef std::unique_ptr<std::string> SQLUpdate;
LocaleFileStorage GetFileList() const;
void FillFileListRecursively(Path const& path, LocaleFileStorage& storage, State const state, uint32 const depth) const;
+2 -2
View File
@@ -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;
+1 -1
View File
@@ -79,7 +79,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
@@ -547,18 +547,27 @@ void BossAI::UpdateAI(uint32 diff)
DoMeleeAttackIfReady();
}
void BossAI::_DespawnAtEvade()
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(29);
me->SetRespawnDelay(delayToRespawn - 1);
me->DespawnOrUnsummon();
me->SetCorpseDelay(corpseDelay);
me->SetRespawnDelay(respawnDelay);
if(instance)
instance->SetBossState(_bossId, FAIL);
}
// WorldBossAI - for non-instanced bosses
@@ -360,12 +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();
void _DespawnAtEvade(uint32 delayToRespawn = 30);
void TeleportCheaters();
@@ -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;
@@ -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;
@@ -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;
@@ -2008,7 +2008,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
@@ -2315,6 +2315,31 @@ void SmartScript::ProcessAction(SmartScriptHolder& e, Unit* unit, uint32 var0, u
}
break;
}
case SMART_ACTION_RANDOM_SOUND:
{
std::vector<uint32> sounds;
std::copy_if(e.action.randomSound.sounds.begin(), e.action.randomSound.sounds.end(),
std::back_inserter(sounds), [](uint32 sound) { return sound != 0; });
bool onlySelf = e.action.randomSound.onlySelf != 0;
if (ObjectList* targets = GetTargets(e, unit))
{
for (WorldObject* const obj : *targets)
{
if (IsUnit(obj))
{
uint32 sound = Trinity::Containers::SelectRandomContainerElement(sounds);
obj->PlayDirectSound(sound, onlySelf ? obj->ToPlayer() : nullptr);
TC_LOG_DEBUG("scripts.ai", "SmartScript::ProcessAction:: SMART_ACTION_RANDOM_SOUND: target: %s (%s), sound: %u, onlyself: %s",
obj->GetName().c_str(), obj->GetGUID().ToString().c_str(), sound, onlySelf ? "true" : "false");
}
}
delete targets;
break;
}
}
default:
TC_LOG_ERROR("sql.sql", "SmartScript::ProcessAction: Entry %d SourceType %u, Event %u, Unhandled Action type %u", e.entryOrGuid, e.GetScriptType(), e.event_id, e.GetActionType());
break;
@@ -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;
@@ -827,6 +827,21 @@ bool SmartAIMgr::IsEventValid(SmartScriptHolder& e)
if (e.action.randomEmote.emote6 && !IsEmoteValid(e, e.action.randomEmote.emote6))
return false;
break;
case SMART_ACTION_RANDOM_SOUND:
{
if (std::all_of(e.action.randomSound.sounds.begin(), e.action.randomSound.sounds.end(), [](uint32 sound) { return sound == 0; }))
{
TC_LOG_ERROR("sql.sql", "SmartAIMgr: Entry %d SourceType %u Event %u Action %u does not have any non-zero sound",
e.entryOrGuid, e.GetScriptType(), e.event_id, e.GetActionType());
return false;
}
for (uint32 sound : e.action.randomSound.sounds)
if (sound && !IsSoundValid(e, sound))
return false;
break;
}
case SMART_ACTION_CAST:
{
if (!IsSpellValid(e, e.action.cast.spell))
@@ -44,6 +44,16 @@ struct WayPoint
float z;
};
enum eSmartAI
{
SMART_EVENT_PARAM_COUNT = 4,
SMART_ACTION_PARAM_COUNT = 6,
SMART_SUMMON_COUNTER = 0xFFFFFF,
SMART_ESCORT_LAST_OOC_POINT = 0xFFFFFF,
SMART_RANDOM_POINT = 0xFFFFFE,
SMART_ESCORT_TARGETS = 0xFFFFFF
};
enum SMART_EVENT_PHASE
{
SMART_EVENT_PHASE_ALWAYS = 0,
@@ -541,8 +551,9 @@ enum SMART_ACTION
SMART_ACTION_GAME_EVENT_START = 112, // GameEventId
SMART_ACTION_START_CLOSEST_WAYPOINT = 113, // wp1, wp2, wp3, wp4, wp5, wp6, wp7
SMART_ACTION_RISE_UP = 114, // distance
SMART_ACTION_RANDOM_SOUND = 115, // soundId1, soundId2, soundId3, soundId4, soundId5, onlySelf
SMART_ACTION_END = 115
SMART_ACTION_END = 116
};
struct SmartAction
@@ -1025,6 +1036,12 @@ struct SmartAction
uint32 wp6;
} closestWaypointFromList;
struct
{
std::array<uint32, SMART_ACTION_PARAM_COUNT - 1> sounds;
uint32 onlySelf;
} randomSound;
//! Note for any new future actions
//! All parameters must have type uint32
@@ -1188,16 +1205,6 @@ struct SmartTarget
};
};
enum eSmartAI
{
SMART_EVENT_PARAM_COUNT = 4,
SMART_ACTION_PARAM_COUNT = 6,
SMART_SUMMON_COUNTER = 0xFFFFFF,
SMART_ESCORT_LAST_OOC_POINT = 0xFFFFFF,
SMART_RANDOM_POINT = 0xFFFFFE,
SMART_ESCORT_TARGETS = 0xFFFFFF
};
enum SmartScriptType
{
SMART_SCRIPT_TYPE_CREATURE = 0, //done
+56 -58
View File
@@ -47,7 +47,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;
}
@@ -82,7 +82,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->type);
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->type);
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->type, dataType, creature.id);
return false;
}
@@ -110,13 +110,13 @@ bool AchievementCriteriaData::IsValid(AchievementCriteriaEntry const* criteria)
}
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->type, 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->type, dataType, classRace.race_id);
return false;
}
@@ -124,7 +124,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->type, dataType, health.percent);
return false;
}
@@ -135,19 +135,19 @@ 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->type, (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->type, (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->type, (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;
}
@@ -156,7 +156,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->type, dataType, value.compType);
return false;
}
@@ -164,7 +164,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->type, dataType, level.minlevel);
return false;
}
@@ -172,7 +172,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->type, dataType, gender.gender);
return false;
}
@@ -180,7 +180,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->type, dataType);
return false;
}
@@ -188,7 +188,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->type, dataType, map_players.maxcount);
return false;
}
@@ -196,7 +196,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->type, dataType, team.team);
return false;
}
@@ -204,7 +204,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->type, dataType, drunk.state);
return false;
}
@@ -212,7 +212,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->type, dataType, holiday.id);
return false;
}
@@ -233,7 +233,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->type, dataType, equipped_item.item_quality);
return false;
}
@@ -241,19 +241,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->type, 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->type, 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->type, dataType, classRace.race_id);
return false;
}
@@ -261,13 +261,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->type, 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->type, 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->type, dataType);
return false;
}
}
@@ -346,14 +346,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;
}
@@ -695,8 +695,8 @@ void AchievementMgr<Player>::LoadFromDB(PreparedQueryResult achievementResult, P
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);
stmt->setUInt16(0, uint16(id));
@@ -2636,17 +2636,15 @@ bool AchievementMgr<T>::RequirementsSatisfied(AchievementCriteriaEntry const* ac
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 (referencePlayer->GetUInt32Value(PLAYER_EXPLORED_ZONES_1 + playerIndexOffset) & mask)
{
matchFound = true;
@@ -3165,7 +3163,7 @@ void AchievementGlobalMgr::LoadAchievementCriteriaList()
m_AchievementCriteriasByTimedType[criteria->timedCriteriaStartType].push_back(criteria);
}
TC_LOG_INFO("server.loading", ">> Loaded %u achievement criteria and %u guild achievement crieteria in %u ms", criterias, guildCriterias, GetMSTimeDiffToNow(oldMSTime));
TC_LOG_INFO("server.loading", ">> Loaded %u achievement criteria and %u guild achievement crieteria in %u ms.", criterias, guildCriterias, GetMSTimeDiffToNow(oldMSTime));
}
void AchievementGlobalMgr::LoadAchievementReferenceList()
@@ -3194,7 +3192,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()
@@ -3222,7 +3220,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;
}
@@ -3232,7 +3230,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);
}
@@ -3278,8 +3276,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));
@@ -3292,7 +3290,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()
@@ -3319,7 +3317,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;
}
@@ -3335,19 +3333,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;
}
}
@@ -3357,7 +3355,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;
}
}
@@ -3367,41 +3365,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;
}
}
@@ -3411,7 +3409,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()
@@ -3426,7 +3424,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;
}
@@ -3438,7 +3436,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;
}
@@ -3453,7 +3451,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
@@ -576,6 +576,14 @@ void AuctionHouseObject::Update()
if (AuctionsMap.empty())
return;
// Clear expired throttled players
for (PlayerGetAllThrottleMap::const_iterator itr = GetAllThrottleMap.begin(); itr != GetAllThrottleMap.end();)
{
if (itr->second <= curTime)
itr = GetAllThrottleMap.erase(itr);
else
++itr;
}
SQLTransaction trans = CharacterDatabase.BeginTransaction();
@@ -651,13 +659,40 @@ void AuctionHouseObject::BuildListOwnerItems(WorldPacket& data, Player* player,
void AuctionHouseObject::BuildListAuctionItems(WorldPacket& data, Player* player,
std::wstring const& wsearchedname, uint32 listfrom, uint8 levelmin, uint8 levelmax, uint8 usable,
uint32 inventoryType, uint32 itemClass, uint32 itemSubClass, uint32 quality,
uint32& count, uint32& totalcount)
uint32& count, uint32& totalcount, bool getall)
{
int loc_idx = player->GetSession()->GetSessionDbLocaleIndex();
int locdbc_idx = player->GetSession()->GetSessionDbcLocale();
time_t curTime = sWorld->GetGameTime();
PlayerGetAllThrottleMap::const_iterator itr = GetAllThrottleMap.find(player->GetGUID());
time_t throttleTime = itr != GetAllThrottleMap.end() ? itr->second : curTime;
if (getall && throttleTime <= curTime)
{
for (AuctionEntryMap::const_iterator itr = AuctionsMap.begin(); itr != AuctionsMap.end(); ++itr)
{
AuctionEntry* Aentry = itr->second;
// Skip expired auctions
if (Aentry->expire_time < curTime)
continue;
Item* item = sAuctionMgr->GetAItem(Aentry->itemGUIDLow);
if (!item)
continue;
++count;
++totalcount;
Aentry->BuildAuctionInfo(data, item);
if (count >= MAX_GETALL_RETURN)
break;
}
GetAllThrottleMap[player->GetGUID()] = curTime + sWorld->getIntConfig(CONFIG_AUCTION_GETALL_DELAY);
return;
}
for (AuctionEntryMap::const_iterator itr = AuctionsMap.begin(); itr != AuctionsMap.end(); ++itr)
{
AuctionEntry* Aentry = itr->second;
@@ -747,16 +782,16 @@ void AuctionHouseObject::BuildListAuctionItems(WorldPacket& data, Player* player
if (count < 50 && totalcount >= listfrom)
{
++count;
Aentry->BuildAuctionInfo(data);
Aentry->BuildAuctionInfo(data, item);
}
++totalcount;
}
}
//this function inserts to WorldPacket auction's data
bool AuctionEntry::BuildAuctionInfo(WorldPacket& data) const
bool AuctionEntry::BuildAuctionInfo(WorldPacket& data, Item* sourceItem) const
{
Item* item = sAuctionMgr->GetAItem(itemGUIDLow);
Item* item = (sourceItem) ? sourceItem : sAuctionMgr->GetAItem(itemGUIDLow);
if (!item)
{
TC_LOG_ERROR("misc", "AuctionEntry::BuildAuctionInfo: Auction %u has a non-existent item: %u", Id, itemGUIDLow);
@@ -30,6 +30,7 @@ class WorldPacket;
#define MIN_AUCTION_TIME (12*HOUR)
#define MAX_AUCTION_ITEMS 160
#define MAX_GETALL_RETURN 55000
enum AuctionError
{
@@ -90,7 +91,7 @@ struct AuctionEntry
uint8 GetHouseId() const { return houseId; }
uint32 GetAuctionCut() const;
uint32 GetAuctionOutBid() const;
bool BuildAuctionInfo(WorldPacket & data) const;
bool BuildAuctionInfo(WorldPacket & data, Item* sourceItem = nullptr) const;
void DeleteFromDB(SQLTransaction& trans) const;
void SaveToDB(SQLTransaction& trans) const;
bool LoadFromDB(Field* fields);
@@ -110,6 +111,7 @@ class AuctionHouseObject
}
typedef std::map<uint32, AuctionEntry*> AuctionEntryMap;
typedef std::unordered_map<ObjectGuid, time_t> PlayerGetAllThrottleMap;
uint32 Getcount() const { return AuctionsMap.size(); }
@@ -133,10 +135,15 @@ class AuctionHouseObject
void BuildListAuctionItems(WorldPacket& data, Player* player,
std::wstring const& searchedname, uint32 listfrom, uint8 levelmin, uint8 levelmax, uint8 usable,
uint32 inventoryType, uint32 itemClass, uint32 itemSubClass, uint32 quality,
uint32& count, uint32& totalcount);
uint32& count, uint32& totalcount, bool getall = false);
private:
AuctionEntryMap AuctionsMap;
// Map of throttled players for GetAll, and throttle expiry time
// Stored here, rather than player object to maintain persistence after logout
PlayerGetAllThrottleMap GetAllThrottleMap;
};
class AuctionHouseMgr
+8 -8
View File
@@ -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()
@@ -543,10 +543,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;
}
@@ -764,7 +764,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;
}
@@ -780,7 +780,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;
}
@@ -803,8 +803,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;
}
@@ -905,7 +905,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;
}
@@ -790,7 +790,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;
}
@@ -808,14 +808,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;
}
@@ -829,7 +829,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;
}
@@ -840,7 +840,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;
}
}
@@ -1036,7 +1036,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)
}
}
@@ -1140,7 +1140,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;
}
@@ -1160,7 +1160,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;
}
}
@@ -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);
@@ -389,6 +389,8 @@ void BattlegroundSA::PostUpdateImpl(uint32 diff)
{
if (TotalTime >= BG_SA_ROUNDLENGTH)
{
CastSpellOnTeam(SPELL_END_OF_ROUND, ALLIANCE);
CastSpellOnTeam(SPELL_END_OF_ROUND, HORDE);
RoundScores[0].winner = Attackers;
RoundScores[0].time = BG_SA_ROUNDLENGTH;
TotalTime = 0;
@@ -401,8 +403,6 @@ void BattlegroundSA::PostUpdateImpl(uint32 diff)
ToggleTimer();
ResetObjs();
GetBgMap()->UpdateAreaDependentAuras();
CastSpellOnTeam(SPELL_END_OF_ROUND, ALLIANCE);
CastSpellOnTeam(SPELL_END_OF_ROUND, HORDE);
return;
}
}
@@ -410,6 +410,8 @@ void BattlegroundSA::PostUpdateImpl(uint32 diff)
{
if (TotalTime >= EndRoundTimer)
{
CastSpellOnTeam(SPELL_END_OF_ROUND, ALLIANCE);
CastSpellOnTeam(SPELL_END_OF_ROUND, HORDE);
RoundScores[1].time = BG_SA_ROUNDLENGTH;
RoundScores[1].winner = (Attackers == TEAM_ALLIANCE) ? TEAM_HORDE : TEAM_ALLIANCE;
if (RoundScores[0].time == RoundScores[1].time)
+9 -9
View File
@@ -297,10 +297,10 @@ 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))
{
areaName = area->area_name;
if (AreaTableEntry const* zone = GetAreaEntryByAreaID(area->zone))
if (AreaTableEntry const* zone = sAreaTableStore.LookupEntry(area->zone))
zoneName = zone->area_name;
}
@@ -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;
@@ -1116,7 +1116,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);
+2 -2
View File
@@ -1749,7 +1749,7 @@ bool ConditionMgr::isSourceTypeValid(Condition* cond) const
}
case CONDITION_SOURCE_TYPE_PHASE:
{
if (cond->SourceEntry && !GetAreaEntryByAreaID(cond->SourceEntry))
if (cond->SourceEntry && !sAreaTableStore.LookupEntry(cond->SourceEntry))
{
TC_LOG_ERROR("sql.sql", "%s SourceEntry in `condition` table, does not exist in AreaTable.dbc, ignoring.", cond->ToString().c_str());
return false;
@@ -1826,7 +1826,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);
+17 -58
View File
@@ -52,11 +52,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;
@@ -95,6 +93,9 @@ DBCStorage <DurabilityCostsEntry> sDurabilityCostsStore(DurabilityCostsfmt);
DBCStorage <EmotesEntry> sEmotesStore(EmotesEntryfmt);
DBCStorage <EmotesTextEntry> sEmotesTextStore(EmotesTextEntryfmt);
typedef std::tuple<uint32, uint32, uint32> EmotesTextSoundKey;
static std::map<EmotesTextSoundKey, EmotesTextSoundEntry const*> sEmotesTextSoundMap;
DBCStorage <EmotesTextSoundEntry> sEmotesTextSoundStore(EmotesTextSoundEntryfmt);
typedef std::map<uint32, SimpleFactionsList> FactionTeamMap;
static FactionTeamMap sFactionTeamMap;
@@ -337,21 +338,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);//15595
LoadDBC(availableDbcLocales, bad_dbc_files, sAchievementCriteriaStore, dbcPath, "Achievement_Criteria.dbc");//15595
@@ -397,6 +384,10 @@ void LoadDBCStores(const std::string& dataPath)
}
}
LoadDBC(availableDbcLocales, bad_dbc_files, sEmotesTextSoundStore, dbcPath, "EmotesTextSound.dbc");
for (uint32 i = 0; i < sEmotesTextSoundStore.GetNumRows(); ++i)
if (EmotesTextSoundEntry const* entry = sEmotesTextSoundStore.LookupEntry(i))
sEmotesTextSoundMap[EmotesTextSoundKey(entry->EmotesTextId, entry->RaceId, entry->SexId)] = entry;
LoadDBC(availableDbcLocales, bad_dbc_files, sCinematicSequencesStore, dbcPath, "CinematicSequences.dbc");//15595
LoadDBC(availableDbcLocales, bad_dbc_files, sCreatureDisplayInfoStore, dbcPath, "CreatureDisplayInfo.dbc");//15595
LoadDBC(availableDbcLocales, bad_dbc_files, sCreatureDisplayInfoExtraStore, dbcPath, "CreatureDisplayInfoExtra.dbc");//15595
@@ -854,7 +845,7 @@ void LoadDBCStores(const std::string& dataPath)
}
// Check loaded DBC files proper version
if (!sAreaStore.LookupEntry(4713) || // last area (areaflag) added in 4.3.4 (15595)
if (!sAreaTableStore.LookupEntry(5995) || // last area (areaflag) added in 4.3.4 (15595)
!sCharTitlesStore.LookupEntry(287) || // last char title added in 4.3.4 (15595)
!sGemPropertiesStore.LookupEntry(2250) || // last gem property added in 4.3.4 (15595)
!sMapStore.LookupEntry(980) || // last map added in 4.3.4 (15595)
@@ -911,41 +902,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*/)
@@ -960,15 +923,6 @@ char const* GetClassName(uint8 class_, uint8 /*locale*/)
return classEntry ? classEntry->name : 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 && mapid != 732) // speed for most cases
@@ -1404,3 +1358,8 @@ ResponseCodes ValidateName(std::string const& name, LocaleConstant locale)
return CHAR_NAME_SUCCESS;
}
EmotesTextSoundEntry const* FindTextSoundEmoteFor(uint32 emote, uint32 race, uint32 gender)
{
return sEmotesTextSoundMap[EmotesTextSoundKey(emote, race, gender)];
}
+4 -6
View File
@@ -33,11 +33,6 @@ char const* 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);
@@ -93,9 +88,11 @@ SkillRaceClassInfoEntry const* GetSkillRaceClassInfo(uint32 skill, uint8 race, u
ResponseCodes ValidateName(std::string const& name, LocaleConstant locale);
EmotesTextSoundEntry const* FindTextSoundEmoteFor(uint32 emote, uint32 race, uint32 gender);
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;
@@ -126,6 +123,7 @@ extern DBCStorage <DurabilityCostsEntry> sDurabilityCostsStore;
extern DBCStorage <DurabilityQualityEntry> sDurabilityQualityStore;
extern DBCStorage <EmotesEntry> sEmotesStore;
extern DBCStorage <EmotesTextEntry> sEmotesTextStore;
extern DBCStorage <EmotesTextSoundEntry> sEmotesTextSoundStore;
extern DBCStorage <FactionEntry> sFactionStore;
extern DBCStorage <FactionTemplateEntry> sFactionTemplateStore;
extern DBCStorage <GameObjectDisplayInfoEntry> sGameObjectDisplayInfoStore;
+10 -1
View File
@@ -525,7 +525,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,
//uint32 unk5; // 5,
//uint32 unk6; // 6,
@@ -980,6 +980,15 @@ struct EmotesTextEntry
uint32 textid;
};
struct EmotesTextSoundEntry
{
uint32 Id; // 0
uint32 EmotesTextId; // 1
uint32 RaceId; // 2
uint32 SexId; // 3, 0 male / 1 female
uint32 SoundId; // 4
};
struct FactionEntry
{
uint32 ID; // 0 m_ID
+2 -1
View File
@@ -26,7 +26,7 @@ char const Achievementfmt[] = "niixsxiixixxii";
const std::string CustomAchievementfmt = "pppaaaapapaapp";
const std::string CustomAchievementIndex = "ID";
char const AchievementCriteriafmt[] = "niiiliiiisiiiiixxiiiiii";
char const AreaTableEntryfmt[] = "iiinixxxxxisiiiiiffixxxxxx";
char const AreaTableEntryfmt[] = "niiiixxxxxisiiiiiffixxxxxx";
char const AreaGroupEntryfmt[] = "niiiiiii";
char const AreaPOIEntryfmt[] = "niiiiiiiiiiiffixixxixx";
char const AreaTriggerEntryfmt[] = "nifffxxxfffff";
@@ -57,6 +57,7 @@ char const DurabilityCostsfmt[] = "niiiiiiiiiiiiiiiiiiiiiiiiiiiii";
char const DurabilityQualityfmt[] = "nf";
char const EmotesEntryfmt[] = "nxxiiixx";
char const EmotesTextEntryfmt[] = "nxixxxxxxxxxxxxxxxx";
char const EmotesTextSoundEntryfmt[] = "niiii";
char const FactionEntryfmt[] = "niiiiiiiiiiiiiiiiiiffixsxi";
char const FactionTemplateEntryfmt[] = "niiiiiiiiiiiii";
char const GameObjectDisplayInfofmt[] = "nsxxxxxxxxxxffffffxxx";
+1 -1
View File
@@ -158,7 +158,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_FLAGS, fields[9].GetUInt8());
+68 -8
View File
@@ -369,13 +369,13 @@ bool Creature::InitEntry(uint32 entry, CreatureData const* data /*= nullptr*/)
SetByteValue(UNIT_FIELD_BYTES_0, 2, minfo->gender);
// Load creature equipment
if (!data || data->equipmentId == 0)
LoadEquipment(); // use default equipment (if available)
else if (data && data->equipmentId != 0) // override, 0 means no equipment
if (data && data->equipmentId != 0)
{
m_originalEquipmentId = data->equipmentId;
LoadEquipment(data->equipmentId);
}
else
LoadEquipment(0, true);
SetName(normalInfo->Name); // at normal entry always
@@ -911,6 +911,12 @@ bool Creature::Create(ObjectGuid::LowType guidlow, Map* map, uint32 /*phaseMask*
if (GetCreatureTemplate()->flags_extra & CREATURE_FLAG_EXTRA_IGNORE_PATHFINDING)
AddUnitState(UNIT_STATE_IGNORE_PATHFINDING);
if (GetCreatureTemplate()->flags_extra & CREATURE_FLAG_EXTRA_IMMUNITY_KNOCKBACK)
{
ApplySpellImmune(0, IMMUNITY_EFFECT, SPELL_EFFECT_KNOCK_BACK, true);
ApplySpellImmune(0, IMMUNITY_EFFECT, SPELL_EFFECT_KNOCK_BACK_DEST, true);
}
return true;
}
@@ -1312,8 +1318,38 @@ bool Creature::CreateFromProto(ObjectGuid::LowType guidlow, uint32 entry, Creatu
return true;
}
bool Creature::LoadCreatureFromDB(ObjectGuid::LowType spawnId, Map* map, bool addToMap)
bool Creature::LoadCreatureFromDB(ObjectGuid::LowType spawnId, Map* map, bool addToMap, bool allowDuplicate)
{
if (!allowDuplicate)
{
// If an alive instance of this spawnId is already found, skip creation
// If only dead instance(s) exist, despawn them and spawn a new (maybe also dead) version
const auto creatureBounds = map->GetCreatureBySpawnIdStore().equal_range(spawnId);
std::vector <Creature*> despawnList;
if (creatureBounds.first != creatureBounds.second)
{
for (auto itr = creatureBounds.first; itr != creatureBounds.second; ++itr)
{
if (itr->second->IsAlive())
{
TC_LOG_DEBUG("maps", "Would have spawned %u but %s already exists", spawnId, creatureBounds.first->second->GetGUID().ToString().c_str());
return false;
}
else
{
despawnList.push_back(itr->second);
TC_LOG_DEBUG("maps", "Despawned dead instance of spawn %u (%s)", spawnId, itr->second->GetGUID().ToString().c_str());
}
}
for (Creature* despawnCreature : despawnList)
{
despawnCreature->AddObjectToRemoveList();
}
}
}
CreatureData const* data = sObjectMgr->GetCreatureData(spawnId);
if (!data)
@@ -1393,6 +1429,7 @@ void Creature::LoadEquipment(int8 id, bool force /*= true*/)
SetUInt32Value(UNIT_VIRTUAL_ITEM_SLOT_ID + i, 0);
m_equipmentId = 0;
}
return;
}
@@ -1401,7 +1438,7 @@ void Creature::LoadEquipment(int8 id, bool force /*= true*/)
return;
m_equipmentId = id;
for (uint8 i = 0; i < 3; ++i)
for (uint8 i = 0; i < MAX_EQUIPMENT_ITEMS; ++i)
SetUInt32Value(UNIT_VIRTUAL_ITEM_SLOT_ID + i, einfo->ItemEntry[i]);
}
@@ -1624,10 +1661,28 @@ void Creature::setDeathState(DeathState s)
UpdateMovementFlags();
CreatureTemplate const* cinfo = GetCreatureTemplate();
SetUInt32Value(UNIT_NPC_FLAGS, cinfo->npcflag);
ClearUnitState(uint32(UNIT_STATE_ALL_STATE & ~UNIT_STATE_IGNORE_PATHFINDING));
SetMeleeDamageSchool(SpellSchools(cinfo->dmgschool));
if (!IsPet())
{
CreatureData const* creatureData = GetCreatureData();
CreatureTemplate const* cinfo = GetCreatureTemplate();
uint32 npcflag, unit_flags, dynamicflags;
ObjectMgr::ChooseCreatureFlags(cinfo, npcflag, unit_flags, dynamicflags, creatureData);
SetUInt32Value(UNIT_NPC_FLAGS, npcflag);
SetUInt32Value(UNIT_FIELD_FLAGS, unit_flags);
SetUInt32Value(UNIT_DYNAMIC_FLAGS, dynamicflags);
RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_IN_COMBAT);
SetMeleeDamageSchool(SpellSchools(cinfo->dmgschool));
if (creatureData && GetPhaseMask() != creatureData->phaseMask)
SetPhaseMask(creatureData->phaseMask, false);
}
Motion_Initialize();
Unit::setDeathState(ALIVE);
LoadCreaturesAddon();
@@ -2114,6 +2169,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;
+22 -20
View File
@@ -39,23 +39,25 @@ class WorldSession;
enum CreatureFlagsExtra
{
CREATURE_FLAG_EXTRA_INSTANCE_BIND = 0x00000001, // creature kill bind instance with killer and killer's group
CREATURE_FLAG_EXTRA_CIVILIAN = 0x00000002, // not aggro (ignore faction/reputation hostility)
CREATURE_FLAG_EXTRA_NO_PARRY = 0x00000004, // creature can't parry
CREATURE_FLAG_EXTRA_NO_PARRY_HASTEN = 0x00000008, // creature can't counter-attack at parry
CREATURE_FLAG_EXTRA_NO_BLOCK = 0x00000010, // creature can't block
CREATURE_FLAG_EXTRA_NO_CRUSH = 0x00000020, // creature can't do crush attacks
CREATURE_FLAG_EXTRA_NO_XP_AT_KILL = 0x00000040, // creature kill not provide XP
CREATURE_FLAG_EXTRA_TRIGGER = 0x00000080, // trigger creature
CREATURE_FLAG_EXTRA_NO_TAUNT = 0x00000100, // creature is immune to taunt auras and effect attack me
CREATURE_FLAG_EXTRA_WORLDEVENT = 0x00004000, // custom flag for world event creatures (left room for merging)
CREATURE_FLAG_EXTRA_GUARD = 0x00008000, // Creature is guard
CREATURE_FLAG_EXTRA_NO_CRIT = 0x00020000, // creature can't do critical strikes
CREATURE_FLAG_EXTRA_NO_SKILLGAIN = 0x00040000, // creature won't increase weapon skills
CREATURE_FLAG_EXTRA_TAUNT_DIMINISH = 0x00080000, // Taunt is a subject to diminishing returns on this creautre
CREATURE_FLAG_EXTRA_ALL_DIMINISH = 0x00100000, // Creature is subject to all diminishing returns as player are
CREATURE_FLAG_EXTRA_DUNGEON_BOSS = 0x10000000, // creature is a dungeon boss (SET DYNAMICALLY, DO NOT ADD IN DB)
CREATURE_FLAG_EXTRA_IGNORE_PATHFINDING = 0x20000000 // creature ignore pathfinding
CREATURE_FLAG_EXTRA_INSTANCE_BIND = 0x00000001, // creature kill bind instance with killer and killer's group
CREATURE_FLAG_EXTRA_CIVILIAN = 0x00000002, // not aggro (ignore faction/reputation hostility)
CREATURE_FLAG_EXTRA_NO_PARRY = 0x00000004, // creature can't parry
CREATURE_FLAG_EXTRA_NO_PARRY_HASTEN = 0x00000008, // creature can't counter-attack at parry
CREATURE_FLAG_EXTRA_NO_BLOCK = 0x00000010, // creature can't block
CREATURE_FLAG_EXTRA_NO_CRUSH = 0x00000020, // creature can't do crush attacks
CREATURE_FLAG_EXTRA_NO_XP_AT_KILL = 0x00000040, // creature kill not provide XP
CREATURE_FLAG_EXTRA_TRIGGER = 0x00000080, // trigger creature
CREATURE_FLAG_EXTRA_NO_TAUNT = 0x00000100, // creature is immune to taunt auras and effect attack me
CREATURE_FLAG_EXTRA_WORLDEVENT = 0x00004000, // custom flag for world event creatures (left room for merging)
CREATURE_FLAG_EXTRA_GUARD = 0x00008000, // Creature is guard
CREATURE_FLAG_EXTRA_NO_CRIT = 0x00020000, // creature can't do critical strikes
CREATURE_FLAG_EXTRA_NO_SKILLGAIN = 0x00040000, // creature won't increase weapon skills
CREATURE_FLAG_EXTRA_TAUNT_DIMINISH = 0x00080000, // Taunt is a subject to diminishing returns on this creautre
CREATURE_FLAG_EXTRA_ALL_DIMINISH = 0x00100000, // creature is subject to all diminishing returns as player are
CREATURE_FLAG_EXTRA_NO_PLAYER_DAMAGE_REQ = 0x00200000, // creature does not need to take player damage for kill credit
CREATURE_FLAG_EXTRA_DUNGEON_BOSS = 0x10000000, // creature is a dungeon boss (SET DYNAMICALLY, DO NOT ADD IN DB)
CREATURE_FLAG_EXTRA_IGNORE_PATHFINDING = 0x20000000, // creature ignore pathfinding
CREATURE_FLAG_EXTRA_IMMUNITY_KNOCKBACK = 0x40000000 // creature is immune to knockback effects
};
#define CREATURE_FLAG_EXTRA_DB_ALLOWED (CREATURE_FLAG_EXTRA_INSTANCE_BIND | CREATURE_FLAG_EXTRA_CIVILIAN | \
@@ -63,7 +65,7 @@ enum CreatureFlagsExtra
CREATURE_FLAG_EXTRA_NO_CRUSH | CREATURE_FLAG_EXTRA_NO_XP_AT_KILL | CREATURE_FLAG_EXTRA_TRIGGER | \
CREATURE_FLAG_EXTRA_NO_TAUNT | CREATURE_FLAG_EXTRA_WORLDEVENT | CREATURE_FLAG_EXTRA_NO_CRIT | \
CREATURE_FLAG_EXTRA_NO_SKILLGAIN | CREATURE_FLAG_EXTRA_TAUNT_DIMINISH | CREATURE_FLAG_EXTRA_ALL_DIMINISH | \
CREATURE_FLAG_EXTRA_GUARD | CREATURE_FLAG_EXTRA_IGNORE_PATHFINDING)
CREATURE_FLAG_EXTRA_GUARD | CREATURE_FLAG_EXTRA_IGNORE_PATHFINDING | CREATURE_FLAG_EXTRA_NO_PLAYER_DAMAGE_REQ | CREATURE_FLAG_EXTRA_IMMUNITY_KNOCKBACK)
#define CREATURE_REGEN_INTERVAL 2 * IN_MILLISECONDS
@@ -532,7 +534,7 @@ class Creature : public Unit, public GridObject<Creature>, public MapObject
void setDeathState(DeathState s) override; // override virtual Unit::setDeathState
bool LoadFromDB(ObjectGuid::LowType spawnId, Map* map) { return LoadCreatureFromDB(spawnId, map, false); }
bool LoadCreatureFromDB(ObjectGuid::LowType spawnId, Map* map, bool addToMap = true);
bool LoadCreatureFromDB(ObjectGuid::LowType spawnId, Map* map, bool addToMap = true, bool allowDuplicate = false);
void SaveToDB();
// overriden in Pet
virtual void SaveToDB(uint32 mapid, uint8 spawnMask, uint32 phaseMask);
@@ -654,7 +656,7 @@ class Creature : public Unit, public GridObject<Creature>, public MapObject
void SetDisableReputationGain(bool disable) { DisableReputationGain = disable; }
bool IsReputationGainDisabled() const { return DisableReputationGain; }
bool IsDamageEnoughForLootingAndReward() const { return m_PlayerDamageReq == 0; }
bool IsDamageEnoughForLootingAndReward() const { return (m_creatureInfo->flags_extra & CREATURE_FLAG_EXTRA_NO_PLAYER_DAMAGE_REQ) || (m_PlayerDamageReq == 0); }
void LowerPlayerDamageReq(uint32 unDamage);
void ResetPlayerDamageReq() { m_PlayerDamageReq = GetHealth() / 2; }
uint32 m_PlayerDamageReq;
@@ -1392,7 +1392,15 @@ void GameObject::Use(Unit* user)
break;
}
player->KillCreditGO(info->entry, GetGUID());
if (Group* group = player->GetGroup())
{
for (GroupReference const* itr = group->GetFirstMember(); itr != nullptr; itr = itr->next())
if (Player* member = itr->GetSource())
if (member->IsAtGroupRewardDistance(this))
member->KillCreditGO(info->entry, GetGUID());
}
else
player->KillCreditGO(info->entry, GetGUID());
}
if (uint32 trapEntry = info->goober.linkedTrapId)
@@ -1430,7 +1438,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;
}
+1 -2
View File
@@ -452,8 +452,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)
File diff suppressed because it is too large. Load diff
+22 -8
View File
@@ -909,14 +909,27 @@ enum PlayerDelayedOperations
// Maximum money amount : 2^31 - 1
extern uint64 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
@@ -1198,8 +1211,9 @@ class Player : public Unit, public GridObject<Player>
void SendInstanceResetWarning(uint32 mapid, Difficulty difficulty, uint32 time, bool welcome);
bool CanInteractWithQuestGiver(Object* questGiver);
Creature* GetNPCIfCanInteractWith(ObjectGuid guid, uint32 npcflagmask);
GameObject* GetGameObjectIfCanInteractWith(ObjectGuid guid, GameobjectTypes type) const;
Creature* GetNPCIfCanInteractWith(ObjectGuid const& guid, uint32 npcflagmask);
GameObject* GetGameObjectIfCanInteractWith(ObjectGuid const& guid) const;
GameObject* GetGameObjectIfCanInteractWith(ObjectGuid const& guid, GameobjectTypes type) const;
void ToggleAFK();
void ToggleDND();
@@ -2316,12 +2330,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; }
+17 -28
View File
@@ -1633,6 +1633,9 @@ void Unit::CalcAbsorbResist(Unit* victim, SpellSchoolMask schoolMask, DamageEffe
RoundToInterval(auraAbsorbMod, 0.0f, 100.0f);
int32 absorbIgnoringDamage = CalculatePct(dmgInfo.GetDamage(), auraAbsorbMod);
dmgInfo.ModifyDamage(-absorbIgnoringDamage);
// We're going to call functions which can modify content of the list during iteration over it's elements
// Let's copy the list so we can prevent iterator invalidation
AuraEffectList vSchoolAbsorbCopy(victim->GetAuraEffectsByType(SPELL_AURA_SCHOOL_ABSORB));
@@ -1665,9 +1668,6 @@ void Unit::CalcAbsorbResist(Unit* victim, SpellSchoolMask schoolMask, DamageEffe
if (defaultPrevented)
continue;
// Apply absorb mod auras
AddPct(currentAbsorb, -auraAbsorbMod);
// absorb must be smaller than the damage itself
currentAbsorb = RoundToInterval(currentAbsorb, 0, int32(dmgInfo.GetDamage()));
@@ -1716,8 +1716,6 @@ void Unit::CalcAbsorbResist(Unit* victim, SpellSchoolMask schoolMask, DamageEffe
if (defaultPrevented)
continue;
AddPct(currentAbsorb, -auraAbsorbMod);
// absorb must be smaller than the damage itself
currentAbsorb = RoundToInterval(currentAbsorb, 0, int32(dmgInfo.GetDamage()));
@@ -1746,6 +1744,8 @@ void Unit::CalcAbsorbResist(Unit* victim, SpellSchoolMask schoolMask, DamageEffe
}
}
dmgInfo.ModifyDamage(absorbIgnoringDamage);
// split damage auras - only when not damaging self
if (victim != this)
{
@@ -4130,13 +4130,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
@@ -11140,7 +11137,7 @@ Unit* Creature::SelectVictim()
}
}
else
return NULL;
return nullptr;
if (target && _IsTargetAcceptable(target) && CanCreatureAttack(target))
{
@@ -11149,14 +11146,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
@@ -11165,12 +11154,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))
@@ -11188,17 +11177,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;
}
//======================================================================
@@ -15458,12 +15447,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)
+1 -1
View File
@@ -1583,7 +1583,7 @@ class Unit : public WorldObject
void SendMoveKnockBack(Player* player, float speedXY, float speedZ, float vcos, float vsin);
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);
+50 -50
View File
@@ -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;
}
@@ -831,7 +831,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));
}
}
@@ -855,7 +855,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;
}
@@ -865,7 +865,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));
}
}
@@ -893,13 +893,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;
}
@@ -910,7 +910,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));
}
}
}
@@ -972,7 +972,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;
}
@@ -981,7 +981,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;
}
@@ -1172,7 +1172,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;
}
@@ -1199,7 +1199,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;
}
@@ -1232,7 +1232,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;
}
@@ -1247,7 +1247,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;
}
@@ -1277,7 +1277,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;
}
@@ -1306,7 +1306,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;
}
+4 -4
View File
@@ -1786,7 +1786,7 @@ void ObjectMgr::LoadCreatures()
if (!ok)
continue;
// -1 random, 0 no equipment,
// -1 random, 0 no equipment
if (data.equipmentId != 0)
{
if (!GetEquipmentInfo(data.id, data.equipmentId))
@@ -4069,7 +4069,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);
@@ -6025,7 +6025,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);
@@ -7885,7 +7885,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);
+1 -1
View File
@@ -229,7 +229,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)
@@ -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);
+4 -1
View File
@@ -718,7 +718,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)
@@ -2322,6 +2323,8 @@ LootMethod Group::GetLootMethod() const
ObjectGuid Group::GetLooterGuid() const
{
if (GetLootMethod() == FREE_FOR_ALL)
return ObjectGuid::Empty;
return m_looterGuid;
}
@@ -731,7 +731,7 @@ void WorldSession::HandleAuctionListItems(WorldPacket& recvData)
TC_LOG_DEBUG("network", "WORLD: Received CMSG_AUCTION_LIST_ITEMS");
std::string searchedname;
uint8 levelmin, levelmax, usable;
uint8 levelmin, levelmax, usable, getAll;
uint32 listfrom, auctionSlotID, auctionMainCategory, auctionSubCategory, quality;
ObjectGuid guid;
@@ -743,7 +743,7 @@ void WorldSession::HandleAuctionListItems(WorldPacket& recvData)
recvData >> auctionSlotID >> auctionMainCategory >> auctionSubCategory;
recvData >> quality >> usable;
recvData.read_skip<uint8>(); // unk
recvData >> getAll;
recvData.read_skip<uint8>(); // unk
// this block looks like it uses some lame byte packing or similar...
@@ -781,11 +781,11 @@ void WorldSession::HandleAuctionListItems(WorldPacket& recvData)
auctionHouse->BuildListAuctionItems(data, _player,
wsearchedname, listfrom, levelmin, levelmax, usable,
auctionSlotID, auctionMainCategory, auctionSubCategory, quality,
count, totalcount);
count, totalcount, (getAll != 0 && sWorld->getIntConfig(CONFIG_AUCTION_GETALL_DELAY) != 0));
data.put<uint32>(0, count);
data << uint32(totalcount);
data << uint32(300); //unk 2.3.0
data << (uint32) sWorld->getIntConfig(CONFIG_AUCTION_SEARCH_DELAY);
SendPacket(&data);
}
@@ -700,6 +700,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)
+1 -1
View File
@@ -46,7 +46,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;
}
+3 -3
View File
@@ -37,7 +37,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;
}
}
@@ -158,7 +158,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, " UI64FMTD " copper and " UI64FMTD " 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);
@@ -167,7 +167,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, " UI64FMTD " copper and " UI64FMTD " COD copper with unk1 = %u, unk2 = %u",
"including %u items, " UI64FMTD " copper and " UI64FMTD " 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);
+6 -6
View File
@@ -105,7 +105,7 @@ void WorldSession::HandleGossipSelectOptionOpcode(WorldPacket& recvData)
GameObject* go = NULL;
if (guid.IsCreatureOrVehicle())
{
unit = GetPlayer()->GetNPCIfCanInteractWith(guid, UNIT_NPC_FLAG_NONE);
unit = GetPlayer()->GetNPCIfCanInteractWith(guid, UNIT_NPC_FLAG_GOSSIP);
if (!unit)
{
TC_LOG_DEBUG("network", "WORLD: HandleGossipSelectOptionOpcode - %s not found or you can't interact with him.", guid.ToString().c_str());
@@ -114,10 +114,10 @@ void WorldSession::HandleGossipSelectOptionOpcode(WorldPacket& recvData)
}
else if (guid.IsGameObject())
{
go = _player->GetMap()->GetGameObject(guid);
go = _player->GetGameObjectIfCanInteractWith(guid);
if (!go)
{
TC_LOG_DEBUG("network", "WORLD: HandleGossipSelectOptionOpcode - %s not found.", guid.ToString().c_str());
TC_LOG_DEBUG("network", "WORLD: HandleGossipSelectOptionOpcode - %s not found or you can't interact with it.", guid.ToString().c_str());
return;
}
}
@@ -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;
@@ -1255,7 +1255,7 @@ void WorldSession::HandleInspectOpcode(WorldPacket& recvData)
WorldPacket data(SMSG_INSPECT_TALENT, 8 + 4 + 1 + 1 + talent_points + 8 + 4 + 8 + 4);
data << player->GetGUID();
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
{
@@ -1886,7 +1886,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;
+2 -1
View File
@@ -402,7 +402,7 @@ void WorldSession::HandleMovementOpcodes(WorldPacket& recvPacket)
plrMover->UpdateFallInformationIfNeed(movementInfo, opcode);
AreaTableEntry const* zone = GetAreaEntryByAreaID(plrMover->GetAreaId());
AreaTableEntry const* zone = sAreaTableStore.LookupEntry(plrMover->GetAreaId());
float depth = zone ? zone->MaxDepth : -500.0f;
if (movementInfo.pos.GetPositionZ() < depth)
{
@@ -413,6 +413,7 @@ void WorldSession::HandleMovementOpcodes(WorldPacket& recvPacket)
/// @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
+1 -42
View File
@@ -317,7 +317,7 @@ void WorldSession::HandleGossipHelloOpcode(WorldPacket& recvData)
ObjectGuid guid;
recvData >> guid;
Creature* unit = GetPlayer()->GetNPCIfCanInteractWith(guid, UNIT_NPC_FLAG_NONE);
Creature* unit = GetPlayer()->GetNPCIfCanInteractWith(guid, UNIT_NPC_FLAG_GOSSIP);
if (!unit)
{
TC_LOG_DEBUG("network", "WORLD: HandleGossipHelloOpcode - %s not found or you can not interact with him.", guid.ToString().c_str());
@@ -357,47 +357,6 @@ void WorldSession::HandleGossipHelloOpcode(WorldPacket& recvData)
unit->AI()->sGossipHello(_player);
}
/*void WorldSession::HandleGossipSelectOptionOpcode(WorldPacket& recvData)
{
TC_LOG_DEBUG("network", "WORLD: CMSG_GOSSIP_SELECT_OPTION");
uint32 option;
uint32 unk;
uint64 guid;
std::string code = "";
recvData >> guid >> unk >> option;
if (_player->PlayerTalkClass->GossipOptionCoded(option))
{
TC_LOG_DEBUG("network", "reading string");
recvData >> code;
TC_LOG_DEBUG("network", "string read: %s", code.c_str());
}
Creature* unit = GetPlayer()->GetNPCIfCanInteractWith(guid, UNIT_NPC_FLAG_NONE);
if (!unit)
{
TC_LOG_DEBUG("network", "WORLD: HandleGossipSelectOptionOpcode - Unit (GUID: %u) not found or you can't interact with him.", uint32(GUID_LOPART(guid)));
return;
}
// remove fake death
if (GetPlayer()->HasUnitState(UNIT_STATE_DIED))
GetPlayer()->RemoveAurasByType(SPELL_AURA_FEIGN_DEATH);
if (!code.empty())
{
if (!Script->GossipSelectWithCode(_player, unit, _player->PlayerTalkClass->GossipOptionSender (option), _player->PlayerTalkClass->GossipOptionAction(option), code.c_str()))
unit->OnGossipSelect (_player, option);
}
else
{
if (!Script->OnGossipSelect (_player, unit, _player->PlayerTalkClass->GossipOptionSender (option), _player->PlayerTalkClass->GossipOptionAction (option)))
unit->OnGossipSelect (_player, option);
}
}*/
void WorldSession::HandleSpiritHealerActivateOpcode(WorldPacket& recvData)
{
TC_LOG_DEBUG("network", "WORLD: CMSG_SPIRIT_HEALER_ACTIVATE");
+1 -1
View File
@@ -75,7 +75,7 @@ void WorldSession::HandleQuestgiverHelloOpcode(WorldPacket& recvData)
TC_LOG_DEBUG("network", "WORLD: Received CMSG_QUESTGIVER_HELLO %s", guid.ToString().c_str());
Creature* creature = GetPlayer()->GetNPCIfCanInteractWith(guid, UNIT_NPC_FLAG_NONE);
Creature* creature = GetPlayer()->GetNPCIfCanInteractWith(guid, UNIT_NPC_FLAG_QUESTGIVER);
if (!creature)
{
TC_LOG_DEBUG("network", "WORLD: HandleQuestgiverHelloOpcode - %s not found or you can't interact with him.",
+7 -14
View File
@@ -287,11 +287,8 @@ void WorldSession::HandleGameObjectUseOpcode(WorldPacket& recvData)
TC_LOG_DEBUG("network", "WORLD: Recvd CMSG_GAMEOBJ_USE Message [%s]", guid.ToString().c_str());
if (GameObject* obj = GetPlayer()->GetMap()->GetGameObject(guid))
if (GameObject* obj = GetPlayer()->GetGameObjectIfCanInteractWith(guid))
{
if (!obj->IsWithinDistInMap(GetPlayer(), obj->GetInteractionDistance()))
return;
// ignore for remote control state
if (GetPlayer()->m_mover != GetPlayer())
if (!(GetPlayer()->IsOnVehicle(GetPlayer()->m_mover) || GetPlayer()->IsMounted()) && !obj->GetGOInfo()->IsUsableMounted())
@@ -312,17 +309,13 @@ void WorldSession::HandleGameobjectReportUse(WorldPacket& recvPacket)
if (_player->m_mover != _player)
return;
GameObject* go = GetPlayer()->GetMap()->GetGameObject(guid);
if (!go)
return;
if (GameObject* go = GetPlayer()->GetGameObjectIfCanInteractWith(guid))
{
if (go->AI()->GossipHello(_player))
return;
if (!go->IsWithinDistInMap(_player, INTERACTION_DISTANCE))
return;
if (go->AI()->GossipHello(_player))
return;
_player->UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_USE_GAMEOBJECT, go->GetEntry());
_player->UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_USE_GAMEOBJECT, go->GetEntry());
}
}
void WorldSession::HandleCastSpellOpcode(WorldPacket& recvPacket)
+73 -29
View File
@@ -435,6 +435,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)
@@ -472,6 +489,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);
@@ -512,10 +540,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);
}
@@ -526,8 +570,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;
}
@@ -568,31 +617,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);
@@ -602,21 +641,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);
stmt = CharacterDatabase.GetPreparedStatement(CHAR_UPD_EXPIRE_CHAR_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;
uint32 period = uint32(((mapDiff->resetTime * sWorld->getRate(RATE_INSTANCE_RESET_TIME))/DAY) * DAY);
if (period < DAY)
period = DAY;
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));
@@ -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();
+2 -2
View File
@@ -1591,8 +1591,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);
+2 -2
View File
@@ -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;
}
}
+80 -61
View File
@@ -1640,13 +1640,13 @@ 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;
// Liquid data
_liquidType = 0;
_liquidOffX = 0;
@@ -1654,9 +1654,9 @@ GridMap::GridMap()
_liquidWidth = 0;
_liquidHeight = 0;
_liquidLevel = INVALID_HEIGHT;
_liquidEntry = NULL;
_liquidFlags = NULL;
_liquidMap = NULL;
_liquidEntry = nullptr;
_liquidFlags = nullptr;
_liquidMap = nullptr;
}
GridMap::~GridMap()
@@ -1722,12 +1722,12 @@ void GridMap::unloadData()
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;
_liquidEntry = nullptr;
_liquidFlags = nullptr;
_liquidMap = nullptr;
_gridGetHeight = &GridMap::getHeightFromFlat;
}
@@ -1742,7 +1742,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;
}
@@ -1792,6 +1792,7 @@ bool GridMap::loadHeightData(FILE* in, uint32 offset, uint32 /*size*/)
}
else
_gridGetHeight = &GridMap::getHeightFromFlat;
return true;
}
@@ -2121,12 +2122,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];
}
@@ -2300,7 +2301,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);
}
@@ -2324,7 +2325,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;
@@ -2337,20 +2338,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)
@@ -2360,8 +2362,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
{
@@ -2397,12 +2422,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];
}
@@ -2464,34 +2489,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)
@@ -3200,22 +3197,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;
}
// 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 && HasPermBoundPlayers()) // check if any unloaded players have a nonexpired save to this
doUnload = false;
}
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();
@@ -3296,6 +3308,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();
+11 -24
View File
@@ -98,9 +98,9 @@ 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
struct map_heightHeader
{
@@ -329,8 +329,11 @@ class Map : public GridRefManager<NGridType>
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 +342,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();
@@ -785,6 +769,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;
+6 -8
View File
@@ -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);
+3
View File
@@ -188,6 +188,9 @@ namespace Trinity
}
xpMod *= isBattleGround ? sWorld->getRate(RATE_XP_BG_KILL) : sWorld->getRate(RATE_XP_KILL);
if (creature && creature->m_PlayerDamageReq) // if players dealt less than 50% of the damage and were credited anyway (due to CREATURE_FLAG_EXTRA_NO_PLAYER_DAMAGE_REQ), scale XP gained appropriately (linear scaling)
xpMod *= 1.0f - 2.0f*creature->m_PlayerDamageReq / creature->GetMaxHealth();
gain = uint32(gain * xpMod);
}
+30 -28
View File
@@ -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;
}
@@ -473,12 +475,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);
}
@@ -501,7 +503,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
{
@@ -517,11 +519,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);
}
@@ -534,14 +536,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(),
@@ -559,20 +561,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);
}
}
@@ -584,11 +586,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);
}
@@ -640,7 +642,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");
}
+5 -3
View File
@@ -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);
+1 -1
View File
@@ -689,7 +689,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());
+12 -25
View File
@@ -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:
+2 -6
View File
@@ -733,7 +733,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*/) { }
@@ -842,10 +842,7 @@ class GroupScript : public ScriptObject
// namespace
// {
typedef std::vector<ScriptObject*> UnusedScriptContainer;
typedef std::list<std::string> UnusedScriptNamesContainer;
extern UnusedScriptContainer UnusedScripts;
extern UnusedScriptNamesContainer UnusedScriptNames;
// }
@@ -877,7 +874,6 @@ class ScriptMgr
public: /* Unloading */
void Unload();
void UnloadUnusedScripts();
public: /* SpellScriptLoader */
@@ -1053,7 +1049,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);
+62 -46
View File
@@ -25,6 +25,17 @@
#include "BattlenetAccountMgr.h"
#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;
std::string const WorldSocket::ServerConnectionInitialize("WORLD OF WARCRAFT CONNECTION - SERVER TO CLIENT");
@@ -45,11 +56,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)
@@ -84,23 +92,59 @@ void WorldSocket::CheckIpCallback(PreparedQueryResult result)
initializer.Write(header.header, header.getHeaderLength() - 2);
initializer.Write(ServerConnectionInitialize.c_str(), ServerConnectionInitialize.length());
std::unique_lock<std::mutex> dummy(_writeLock, std::defer_lock);
QueuePacket(std::move(initializer), dummy);
// - io_service.run thread, safe.
QueuePacket(std::move(initializer));
}
bool WorldSocket::Update()
{
EncryptablePacket* queued;
MessageBuffer buffer;
while (_bufferQueue.Dequeue(queued))
{
if (_worldSession && queued->size() > 0x400 && !queued->IsCompressed())
queued->Compress(_worldSession->GetCompressionStream());
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;
@@ -418,32 +462,7 @@ void WorldSocket::SendPacket(WorldPacket& packet)
if (sPacketLog->CanLogPacket())
sPacketLog->LogPacket(packet, SERVER_TO_CLIENT, GetRemoteIpAddress(), GetRemotePort());
if (_worldSession && packet.size() > 0x400 && !packet.IsCompressed())
packet.Compress(_worldSession->GetCompressionStream());
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)
@@ -497,11 +516,8 @@ void WorldSocket::HandleAuthSession(WorldPacket& recvPacket)
stmt->setInt32(0, realmHandle.Index);
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)
@@ -655,7 +671,7 @@ void WorldSocket::HandleAuthSessionCallback(std::shared_ptr<AuthSession> authSes
if (wardenActive)
_worldSession->InitWarden(&account.Game.SessionKey, account.BattleNet.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();
}
+3 -1
View File
@@ -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)
@@ -107,10 +109,10 @@ private:
MessageBuffer _headerBuffer;
MessageBuffer _packetBuffer;
MPSCQueue<EncryptablePacket> _bufferQueue;
bool _initialized;
std::mutex _queryLock;
PreparedQueryResultFuture _queryFuture;
std::function<void(PreparedQueryResult&&)> _queryCallback;
std::string _ipCountry;
+7 -5
View File
@@ -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
+1 -1
View File
@@ -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();
+8 -8
View File
@@ -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)
+9 -9
View File
@@ -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;
}
@@ -4702,11 +4702,6 @@ void AuraEffect::HandleAuraDummy(AuraApplication const* aurApp, uint8 mode, bool
if (caster)
target->GetMotionMaster()->MoveFall();
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);
@@ -5626,25 +5621,6 @@ void AuraEffect::HandlePeriodicTriggerSpellAuraTick(Unit* target, Unit* caster)
target->RemoveAurasDueToSpell(28820);
return;
}
// Totemic Mastery (Skyshatter Regalia (Shaman Tier 6) - bonus)
case 38443:
{
bool all = true;
for (int i = SUMMON_SLOT_TOTEM; i < MAX_TOTEM_SLOT; ++i)
{
if (!target->m_SummonSlot[i])
{
all = false;
break;
}
}
if (all)
target->CastSpell(target, 38437, true, NULL, this);
else
target->RemoveAurasDueToSpell(38437);
return;
}
}
break;
}
+1 -1
View File
@@ -1404,7 +1404,7 @@ void Aura::HandleAuraSpecificMods(AuraApplication const* aurApp, Unit* caster, b
{
// This additional check is needed to add a minimal delay before cooldown in in effect
// to allow all bubbles broken by a single damage source proc mana return
if (caster->GetSpellHistory()->GetRemainingCooldown(aura->GetSpellInfo()) <= 11)
if (caster->GetSpellHistory()->GetRemainingCooldown(aura->GetSpellInfo()) <= 11 * IN_MILLISECONDS)
break;
}
else // and add if needed
+5 -6
View File
@@ -2435,7 +2435,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);
@@ -2525,7 +2525,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);
@@ -4649,8 +4649,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;
@@ -4661,7 +4660,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
@@ -5548,7 +5547,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;
}
+22 -26
View File
@@ -751,7 +751,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;
}
@@ -802,7 +802,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;
}
@@ -854,7 +854,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;
}
@@ -879,7 +879,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)
@@ -893,13 +893,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)
@@ -924,7 +920,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;
}
@@ -1245,7 +1241,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;
}
@@ -1721,7 +1717,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;
}
@@ -2026,7 +2022,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;
}
@@ -2214,7 +2210,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)
@@ -2577,7 +2573,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;
}
@@ -2624,14 +2620,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;
}
@@ -3681,7 +3677,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;
}
@@ -3834,14 +3830,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
@@ -3922,7 +3918,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;
@@ -4632,7 +4628,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)
@@ -4834,7 +4830,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;
}
@@ -5484,7 +5480,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;
}
@@ -5541,7 +5537,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;
}
+5
View File
@@ -1349,6 +1349,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);
+1
View File
@@ -474,6 +474,7 @@ public:
bool IsBreakingStealth() const;
bool IsRangedWeaponSpell() const;
bool IsAutoRepeatRangedSpell() const;
bool HasInitialAggro() const;
bool IsAffectedBySpellMods() const;
bool IsAffectedBySpellMod(SpellModifier const* mod) const;
+80 -86
View File
@@ -379,29 +379,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;
}
@@ -437,9 +437,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;
}
@@ -458,7 +458,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;
}
@@ -473,7 +473,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
}
@@ -484,7 +484,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
}
@@ -877,7 +877,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;
}
@@ -897,7 +897,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;
}
@@ -1124,27 +1124,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;
@@ -1332,7 +1332,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
@@ -1349,14 +1349,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;
}
@@ -1372,7 +1372,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);
@@ -1426,26 +1426,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;
}
@@ -1523,19 +1523,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;
}
@@ -1580,7 +1580,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;
@@ -1718,7 +1718,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;
}
@@ -1755,7 +1755,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);
}
}*/
@@ -1814,12 +1814,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
@@ -1865,7 +1865,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;
}
@@ -1873,7 +1873,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;
}
@@ -1917,18 +1917,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;
}
}
@@ -1950,12 +1950,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;
@@ -2003,18 +2003,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;
}
}
@@ -2041,7 +2041,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;
}
@@ -2062,42 +2062,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;
@@ -2136,7 +2136,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;
}
@@ -2175,7 +2175,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;
}
@@ -2244,21 +2244,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;
}
@@ -2336,7 +2336,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;
}
@@ -2380,7 +2380,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;
}
@@ -2388,13 +2388,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;
}
@@ -2639,7 +2639,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;
}
@@ -2668,20 +2668,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;
}
@@ -2689,7 +2689,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;
}
}
@@ -2699,13 +2699,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;
}
@@ -2725,7 +2725,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;
}
@@ -2741,7 +2741,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;
}
}
@@ -2749,13 +2749,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;
}
@@ -3022,6 +3022,7 @@ void SpellMgr::LoadSpellInfoCorrections()
break;
case 70743: // AoD Special
case 70614: // AoD Special - Vegard
case 4020: // Safirdrang's Chill
case 42436: // Drink! (Brewfest)
spellInfo->Effects[EFFECT_0].TargetA = SpellImplicitTargetInfo(TARGET_UNIT_TARGET_ANY);
break;
@@ -3061,13 +3062,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
Loaded 100 of 161 files, more files were not shown because too many files have changed in this diff. Show more