diff --git a/.travis.yml b/.travis.yml
index 4380eeea7bb..f2f8d20b0df 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -9,24 +9,31 @@ before_install:
- echo "yes" | sudo add-apt-repository ppa:kalakris/cmake
- echo "yes" | sudo add-apt-repository ppa:boost-latest/ppa
- echo "yes" | sudo add-apt-repository ppa:ubuntu-toolchain-r/test
+ - echo "yes" | sudo add-apt-repository 'deb http://llvm.org/apt/precise/ llvm-toolchain-precise-3.5 main'
+ - wget -O - http://llvm.org/apt/llvm-snapshot.gpg.key | sudo apt-key add -
- sudo apt-get -qq update
- - sudo apt-get -qq install build-essential libtool gcc-4.8 g++-4.8 make cmake openssl
+ - sudo apt-get -qq install build-essential libtool gcc-4.8 g++-4.8 make cmake openssl clang-3.5
- sudo apt-get -qq install libssl-dev libmysqlclient-dev libmysql++-dev libreadline6-dev zlib1g-dev libbz2-dev libzmq3-dev
- sudo apt-get -qq install libboost1.55-dev libboost-thread1.55-dev libboost-filesystem1.55-dev libboost-system1.55-dev libboost-program-options1.55-dev libboost-iostreams1.55-dev
+ - export CC=clang-3.5 CXX=clang++-3.5
install:
- mysql -uroot -e 'create database test_mysql;'
- mkdir bin
- cd bin
- - cmake ../ -DWITH_WARNINGS=1 -DWITH_COREDEBUG=0 -DUSE_COREPCH=1 -DUSE_SCRIPTPCH=1 -DTOOLS=1 -DSCRIPTS=1 -DSERVERS=1 -DNOJEM=1 -DCMAKE_BUILD_TYPE=Release
+ - cmake ../ -DWITH_WARNINGS=1 -DWITH_COREDEBUG=0 -DUSE_COREPCH=1 -DUSE_SCRIPTPCH=1 -DTOOLS=1 -DSCRIPTS=1 -DSERVERS=1 -DNOJEM=1 -DCMAKE_BUILD_TYPE=Release -DCMAKE_C_FLAGS="-Werror" -DCMAKE_CXX_FLAGS="-Werror"
+ - cd ..
+ - sudo chmod +x contrib/check_updates.sh
script:
- - cd ..
+ - $CXX --version
- mysql -uroot < sql/create/create_mysql.sql
- mysql -utrinity -ptrinity auth < sql/base/auth_database.sql
+ - ./contrib/check_updates.sh auth auth
- mysql -utrinity -ptrinity characters < sql/base/characters_database.sql
+ - ./contrib/check_updates.sh characters characters
- mysql -utrinity -ptrinity world < sql/base/dev/world_database.sql
- cat sql/updates/world/*.sql | mysql -utrinity -ptrinity world
- mysql -uroot < sql/create/drop_mysql.sql
- cd bin
- - make -j 10
+ - make -j 10 -k
diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md
index edef7a085f1..4baa1197965 100644
--- a/CONTRIBUTING.md
+++ b/CONTRIBUTING.md
@@ -61,13 +61,8 @@ You are welcome to create an account and help us improve and extend the wiki.
Requirements
============
-Platform: Linux, Windows or Mac
-Processor with SSE2 support
-Boost ≥ 1.4.9
-MySQL ≥ 5.1.0
-CMake ≥ 2.8.11.2 / 2.8.9 (Windows / Linux)
-OpenSSL ≥ 1.0.0
-GCC ≥ 4.7.2 (Linux only)
-MS Visual Studio ≥ 12 (2013) Update 4 (Windows only)
-If you choose Linux, we recommend to use Debian 8, since it's the Linux that we use to test compilations.
\ No newline at end of file
+Software requirements are available in the [wiki](http://www.trinitycore.info/display/tc/Requirements) for
+Windows, Linux and Mac OSX.
+
+If you choose Linux, we recommend to use Debian 8, since it's the Linux that we use to test compilations.
diff --git a/PreLoad.cmake b/PreLoad.cmake
index f7cf5a1ebe6..5914118186a 100644
--- a/PreLoad.cmake
+++ b/PreLoad.cmake
@@ -1,4 +1,4 @@
-# Copyright (C) 2008-2015 TrinityCore
+# Copyright (C) 2008-2016 TrinityCore
#
# This file is free software; as a special exception the author gives
# unlimited permission to copy and/or distribute it, with or without
diff --git a/contrib/check_updates.sh b/contrib/check_updates.sh
new file mode 100644
index 00000000000..017542eb807
--- /dev/null
+++ b/contrib/check_updates.sh
@@ -0,0 +1,44 @@
+#!/bin/sh
+name=$1
+database=$2
+
+echo "Database Updater check script:"
+echo " Checking database '${name}' for missing filenames in tables..."
+echo
+
+# Select all entries which are in the updates table
+entries=$(mysql -uroot ${database} -e "SELECT name FROM updates" | grep ".sql")
+
+cd sql/updates/${name}
+
+error=0
+updates=0
+
+for file in *.sql
+do
+ # Check if the given update is in the `updates` table.
+ if echo "${entries}" | grep -q "^${file}"; then
+ # File is ok
+ updates=$((updates+1))
+ else
+ # The update isn't listed in the updates table of the given database.
+ echo "- \"sql/updates/${name}/${file}\" is missing in the '${name}'.'updates' table."
+ error=1
+ fi
+done
+
+if [ ${error} -ne 0 ]
+ then
+ echo
+ echo "Fatal error:"
+ echo " The Database Updater is broken for the '${name}' database,"
+ echo " because the applied update is missing in the '${name}'.'updates' table."
+ echo
+ echo "How to fix:"
+ echo " Insert the missing names of the already applied sql updates"
+ echo " to the 'updates' table of the '${name}' base dump ('sql/base/${name}_database.sql')."
+ exit 1
+ else
+ echo " Everything is OK, finished checking ${updates} updates."
+ exit 0
+fi
diff --git a/contrib/conf_merge/tc-conf-merger.pl b/contrib/conf_merge/tc-conf-merger.pl
index 074689979af..23c8385f0c8 100644
--- a/contrib/conf_merge/tc-conf-merger.pl
+++ b/contrib/conf_merge/tc-conf-merger.pl
@@ -1,6 +1,6 @@
#!/usr/bin/perl -w
-# Copyright (C) 2008-2015 TrinityCore
+# Copyright (C) 2008-2016 TrinityCore
# Author: leak
# Date: 2010-12-06
# Note: Based on conf file format of rev 10507
diff --git a/dep/CMakeLists.txt b/dep/CMakeLists.txt
index 23c90e160f4..47924575e7f 100644
--- a/dep/CMakeLists.txt
+++ b/dep/CMakeLists.txt
@@ -1,4 +1,4 @@
-# Copyright (C) 2008-2015 TrinityCore
+# Copyright (C) 2008-2016 TrinityCore
#
# This file is free software; as a special exception the author gives
# unlimited permission to copy and/or distribute it, with or without
@@ -32,10 +32,10 @@ endif()
if(SERVERS OR TOOLS)
add_subdirectory(g3dlite)
add_subdirectory(recastnavigation)
+ add_subdirectory(cppformat)
endif()
if(SERVERS)
- add_subdirectory(cppformat)
add_subdirectory(gsoap)
add_subdirectory(zmqpp)
endif()
diff --git a/dep/SFMT/SFMT-hotfix1.diff b/dep/SFMT/SFMT-hotfix1.diff
new file mode 100644
index 00000000000..ba7810dc100
--- /dev/null
+++ b/dep/SFMT/SFMT-hotfix1.diff
@@ -0,0 +1,14 @@
+diff --git a/dep/SFMT/SFMT.h b/dep/SFMT/SFMT.h
+index 3d15d65..ccf21ce 100644
+--- a/dep/SFMT/SFMT.h
++++ b/dep/SFMT/SFMT.h
+@@ -173,7 +173,8 @@ public:
+ uint32_t statesize = SFMT_N*4; // Size of state vector
+
+ // Fill state vector with random numbers from seed
+- ((uint32_t*)state)[0] = y;
++ uint32_t* s = (uint32_t*)&state;
++ s[0] = y;
+ const uint32_t factor = 1812433253U;// Multiplication factor
+
+ for (i = 1; i < statesize; i++) {
diff --git a/dep/SFMT/SFMT.h b/dep/SFMT/SFMT.h
index 3d15d651e5b..ccf21cecd5f 100644
--- a/dep/SFMT/SFMT.h
+++ b/dep/SFMT/SFMT.h
@@ -173,7 +173,8 @@ public:
uint32_t statesize = SFMT_N*4; // Size of state vector
// Fill state vector with random numbers from seed
- ((uint32_t*)state)[0] = y;
+ uint32_t* s = (uint32_t*)&state;
+ s[0] = y;
const uint32_t factor = 1812433253U;// Multiplication factor
for (i = 1; i < statesize; i++) {
diff --git a/dep/bzip2/CMakeLists.txt b/dep/bzip2/CMakeLists.txt
index 37f44be7686..d3aadbe002e 100644
--- a/dep/bzip2/CMakeLists.txt
+++ b/dep/bzip2/CMakeLists.txt
@@ -1,4 +1,4 @@
-# Copyright (C) 2008-2015 TrinityCore
+# Copyright (C) 2008-2016 TrinityCore
#
# This file is free software; as a special exception the author gives
# unlimited permission to copy and/or distribute it, with or without
diff --git a/dep/g3dlite/G3D-v9.0 hotfix5.diff b/dep/g3dlite/G3D-v9.0 hotfix5.diff
new file mode 100644
index 00000000000..7bc4073ef62
--- /dev/null
+++ b/dep/g3dlite/G3D-v9.0 hotfix5.diff
@@ -0,0 +1,28 @@
+diff --git a/dep/g3dlite/include/G3D/Quat.h b/dep/g3dlite/include/G3D/Quat.h
+index 04e11e0..b26708a 100644
+--- a/dep/g3dlite/include/G3D/Quat.h
++++ b/dep/g3dlite/include/G3D/Quat.h
+@@ -335,8 +335,8 @@ public:
+ Note that q.pow(a).pow(b) == q.pow(a + b)
+ @cite Dam98 pg 21
+ */
+- inline Quat pow(float x) const {
+- return (log() * x).exp();
++ inline Quat pow(float r) const {
++ return (log() * r).exp();
+ }
+
+ /** Make unit length in place */
+@@ -349,9 +349,9 @@ public:
+ the magnitude.
+ */
+ Quat toUnit() const {
+- Quat x = *this;
+- x.unitize();
+- return x;
++ Quat copyOfThis = *this;
++ copyOfThis.unitize();
++ return copyOfThis;
+ }
+
+ /**
diff --git a/dep/g3dlite/G3D-v9.0 hotfix6.diff b/dep/g3dlite/G3D-v9.0 hotfix6.diff
new file mode 100644
index 00000000000..3ff735c734e
--- /dev/null
+++ b/dep/g3dlite/G3D-v9.0 hotfix6.diff
@@ -0,0 +1,32 @@
+diff --git a/dep/g3dlite/include/G3D/platform.h b/dep/g3dlite/include/G3D/platform.h
+index 17e3bf2..439495a 100644
+--- a/dep/g3dlite/include/G3D/platform.h
++++ b/dep/g3dlite/include/G3D/platform.h
+@@ -364,13 +364,18 @@ int WINAPI WinMain(HINSTANCE hInst, HINSTANCE hPrev, LPSTR szCmdLine, int sw) {\
+ #endif
+ #if (!defined(_LIBCPP_VERSION) && defined(__APPLE__)) || (!defined(_LIBCPP_VERSION) && defined(__linux__))
+ # include
++#else
++# include
++#endif
++
++namespace G3D {
++#if (!defined(_LIBCPP_VERSION) && defined(__APPLE__)) || (!defined(_LIBCPP_VERSION) && defined(__linux__))
+ using std::tr1::shared_ptr;
+ using std::tr1::weak_ptr;
+ using std::tr1::dynamic_pointer_cast;
+ using std::tr1::static_pointer_cast;
+ using std::tr1::enable_shared_from_this;
+ #else
+-# include
+ using std::shared_ptr;
+ using std::weak_ptr;
+ using std::dynamic_pointer_cast;
+@@ -378,7 +383,6 @@ int WINAPI WinMain(HINSTANCE hInst, HINSTANCE hPrev, LPSTR szCmdLine, int sw) {\
+ using std::enable_shared_from_this;
+ #endif
+
+-namespace G3D {
+ /** Options for initG3D and initGLG3D. */
+ class G3DSpecification {
+ public:
diff --git a/dep/g3dlite/Readme.txt b/dep/g3dlite/Readme.txt
index 682a2404d96..d4e3fa5d06b 100644
--- a/dep/g3dlite/Readme.txt
+++ b/dep/g3dlite/Readme.txt
@@ -14,3 +14,5 @@ G3D-v9.0 hotfix1.diff - 2014-08-22 - updated to G3D9, reapplied previous patches
G3D-v9.0 hotfix2.diff - 2014-08-23 - fix some -Wconversion warnings
G3D-v9.0 hotfix3.diff - 2015-06-28 - fix some warnings
G3D-v9.0 hotfix4.diff - 2015-07-02 - backport G3D10 fix
+G3D-v9.0 hotfix5.diff - 2015-07-31 - fix MSVC 2015 warning: dep/g3dlite/include/G3D/Quat.h(352): warning C4458: declaration of 'x' hides class member
+G3D-v9.0 hotfix6.diff - 2015-11-04 - fix adding std::shared_ptr, std::weak_ptr, std::dynamic_pointer_cast, std::static_pointer_cast and std::enable_shared_from_this to global namespace
diff --git a/dep/g3dlite/include/G3D/Quat.h b/dep/g3dlite/include/G3D/Quat.h
index 04e11e084a0..73e661a4f48 100644
--- a/dep/g3dlite/include/G3D/Quat.h
+++ b/dep/g3dlite/include/G3D/Quat.h
@@ -335,8 +335,8 @@ public:
Note that q.pow(a).pow(b) == q.pow(a + b)
@cite Dam98 pg 21
*/
- inline Quat pow(float x) const {
- return (log() * x).exp();
+ inline Quat pow(float r) const {
+ return (log() * r).exp();
}
/** Make unit length in place */
@@ -349,9 +349,9 @@ public:
the magnitude.
*/
Quat toUnit() const {
- Quat x = *this;
- x.unitize();
- return x;
+ Quat copyOfThis = *this;
+ copyOfThis.unitize();
+ return copyOfThis;
}
/**
diff --git a/dep/g3dlite/include/G3D/platform.h b/dep/g3dlite/include/G3D/platform.h
index 17e3bf279eb..439495ab131 100644
--- a/dep/g3dlite/include/G3D/platform.h
+++ b/dep/g3dlite/include/G3D/platform.h
@@ -364,13 +364,18 @@ int WINAPI WinMain(HINSTANCE hInst, HINSTANCE hPrev, LPSTR szCmdLine, int sw) {\
#endif
#if (!defined(_LIBCPP_VERSION) && defined(__APPLE__)) || (!defined(_LIBCPP_VERSION) && defined(__linux__))
# include
+#else
+# include
+#endif
+
+namespace G3D {
+#if (!defined(_LIBCPP_VERSION) && defined(__APPLE__)) || (!defined(_LIBCPP_VERSION) && defined(__linux__))
using std::tr1::shared_ptr;
using std::tr1::weak_ptr;
using std::tr1::dynamic_pointer_cast;
using std::tr1::static_pointer_cast;
using std::tr1::enable_shared_from_this;
#else
-# include
using std::shared_ptr;
using std::weak_ptr;
using std::dynamic_pointer_cast;
@@ -378,7 +383,6 @@ int WINAPI WinMain(HINSTANCE hInst, HINSTANCE hPrev, LPSTR szCmdLine, int sw) {\
using std::enable_shared_from_this;
#endif
-namespace G3D {
/** Options for initG3D and initGLG3D. */
class G3DSpecification {
public:
diff --git a/dep/jemalloc/CMakeLists.txt b/dep/jemalloc/CMakeLists.txt
index 8f0692fc82c..cf0ac435f0a 100644
--- a/dep/jemalloc/CMakeLists.txt
+++ b/dep/jemalloc/CMakeLists.txt
@@ -1,4 +1,4 @@
-# Copyright (C) 2008-2015 TrinityCore
+# Copyright (C) 2008-2016 TrinityCore
#
# This file is free software; as a special exception the author gives
# unlimited permission to copy and/or distribute it, with or without
diff --git a/doc/UnixInstall.txt b/doc/UnixInstall.txt
index be1cdf74d0e..bced72b2eb7 100644
--- a/doc/UnixInstall.txt
+++ b/doc/UnixInstall.txt
@@ -1,5 +1,5 @@
= TrinityCore -- Linux installation =
-Copyright (C) 2008-2015 TrinityCore (http://www.trinitycore.org)
+Copyright (C) 2008-2016 TrinityCore (http://www.trinitycore.org/)
=========================================================
WARNING: THIS DOCUMENTATION IS NOT ALWAYS UP TO DATE.
diff --git a/sql/base/auth_database.sql b/sql/base/auth_database.sql
index 275da0fd910..80604802372 100644
--- a/sql/base/auth_database.sql
+++ b/sql/base/auth_database.sql
@@ -1,8 +1,8 @@
--- MySQL dump 10.13 Distrib 5.6.9-rc, for Win64 (x86_64)
+-- MySQL dump 10.13 Distrib 5.6.26, for Win64 (x86_64)
--
-- Host: localhost Database: auth_4x
-- ------------------------------------------------------
--- Server version 5.6.9-rc
+-- Server version 5.6.26-log
/*!40101 SET @OLD_CHARACTER_SET_CLIENT=@@CHARACTER_SET_CLIENT */;
/*!40101 SET @OLD_CHARACTER_SET_RESULTS=@@CHARACTER_SET_RESULTS */;
diff --git a/sql/base/characters_database.sql b/sql/base/characters_database.sql
index fd7859e2d23..29beb347283 100644
--- a/sql/base/characters_database.sql
+++ b/sql/base/characters_database.sql
@@ -1,8 +1,8 @@
--- MySQL dump 10.13 Distrib 5.6.9-rc, for Win64 (x86_64)
+-- MySQL dump 10.13 Distrib 5.6.26, for Win64 (x86_64)
--
-- Host: localhost Database: characters_4x
-- ------------------------------------------------------
--- Server version 5.6.9-rc
+-- Server version 5.6.26-log
/*!40101 SET @OLD_CHARACTER_SET_CLIENT=@@CHARACTER_SET_CLIENT */;
/*!40101 SET @OLD_CHARACTER_SET_RESULTS=@@CHARACTER_SET_RESULTS */;
@@ -239,6 +239,29 @@ LOCK TABLES `banned_addons` WRITE;
/*!40000 ALTER TABLE `banned_addons` ENABLE KEYS */;
UNLOCK TABLES;
+--
+-- Table structure for table `battleground_deserters`
+--
+
+DROP TABLE IF EXISTS `battleground_deserters`;
+/*!40101 SET @saved_cs_client = @@character_set_client */;
+/*!40101 SET character_set_client = utf8 */;
+CREATE TABLE `battleground_deserters` (
+ `guid` int(10) unsigned NOT NULL COMMENT 'characters.guid',
+ `type` tinyint(3) unsigned NOT NULL COMMENT 'type of the desertion',
+ `datetime` datetime NOT NULL COMMENT 'datetime of the desertion'
+) ENGINE=InnoDB DEFAULT CHARSET=latin1;
+/*!40101 SET character_set_client = @saved_cs_client */;
+
+--
+-- Dumping data for table `battleground_deserters`
+--
+
+LOCK TABLES `battleground_deserters` WRITE;
+/*!40000 ALTER TABLE `battleground_deserters` DISABLE KEYS */;
+/*!40000 ALTER TABLE `battleground_deserters` ENABLE KEYS */;
+UNLOCK TABLES;
+
--
-- Table structure for table `bugreport`
--
@@ -1631,6 +1654,7 @@ DROP TABLE IF EXISTS `gm_ticket`;
/*!40101 SET character_set_client = utf8 */;
CREATE TABLE `gm_ticket` (
`id` int(10) unsigned NOT NULL AUTO_INCREMENT,
+ `type` tinyint(3) unsigned NOT NULL DEFAULT '0' COMMENT '0 open, 1 closed, 2 character deleted',
`playerGuid` int(10) unsigned NOT NULL DEFAULT '0' COMMENT 'Global Unique Identifier of ticket creator',
`name` varchar(12) NOT NULL COMMENT 'Name of ticket creator',
`description` text NOT NULL,
@@ -1648,6 +1672,7 @@ CREATE TABLE `gm_ticket` (
`escalated` tinyint(3) unsigned NOT NULL DEFAULT '0',
`viewed` tinyint(3) unsigned NOT NULL DEFAULT '0',
`needMoreHelp` tinyint(3) unsigned NOT NULL DEFAULT '0',
+ `resolvedBy` int(10) NOT NULL DEFAULT '0' COMMENT 'GUID of GM who resolved the ticket',
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='Player System';
/*!40101 SET character_set_client = @saved_cs_client */;
@@ -2487,7 +2512,7 @@ CREATE TABLE `pet_aura` (
`maxDuration` int(11) NOT NULL DEFAULT '0',
`remainTime` int(11) NOT NULL DEFAULT '0',
`remainCharges` tinyint(3) unsigned NOT NULL DEFAULT '0',
- PRIMARY KEY (`guid`,`spell`,`effectMask`)
+ PRIMARY KEY (`guid`,`casterGuid`,`spell`,`effectMask`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='Pet System';
/*!40101 SET character_set_client = @saved_cs_client */;
@@ -2663,6 +2688,7 @@ DROP TABLE IF EXISTS `pvpstats_players`;
CREATE TABLE `pvpstats_players` (
`battleground_id` bigint(20) unsigned NOT NULL,
`character_guid` int(10) unsigned NOT NULL,
+ `winner` bit(1) NOT NULL,
`score_killing_blows` mediumint(8) unsigned NOT NULL,
`score_deaths` mediumint(8) unsigned NOT NULL,
`score_honorable_kills` mediumint(8) unsigned NOT NULL,
diff --git a/sql/base/dev/world_database.sql b/sql/base/dev/world_database.sql
index 89f59ddbd9e..3553f02dce8 100644
--- a/sql/base/dev/world_database.sql
+++ b/sql/base/dev/world_database.sql
@@ -1,8 +1,8 @@
--- MySQL dump 10.13 Distrib 5.6.9-rc, for Win64 (x86_64)
+-- MySQL dump 10.13 Distrib 5.6.26, for Win64 (x86_64)
--
-- Host: localhost Database: world434
-- ------------------------------------------------------
--- Server version 5.6.9-rc
+-- Server version 5.6.26-log
/*!40101 SET @OLD_CHARACTER_SET_CLIENT=@@CHARACTER_SET_CLIENT */;
/*!40101 SET @OLD_CHARACTER_SET_RESULTS=@@CHARACTER_SET_RESULTS */;
@@ -472,6 +472,7 @@ CREATE TABLE `creature_questitem` (
`CreatureEntry` int(10) unsigned NOT NULL DEFAULT '0',
`Idx` int(10) unsigned NOT NULL DEFAULT '0',
`ItemId` int(10) unsigned NOT NULL DEFAULT '0',
+ `VerifiedBuild` smallint(5) NOT NULL DEFAULT '0',
PRIMARY KEY (`CreatureEntry`,`Idx`)
) ENGINE=MyISAM DEFAULT CHARSET=utf8;
/*!40101 SET character_set_client = @saved_cs_client */;
@@ -623,6 +624,24 @@ CREATE TABLE `creature_template_addon` (
) ENGINE=MyISAM DEFAULT CHARSET=utf8;
/*!40101 SET character_set_client = @saved_cs_client */;
+--
+-- Table structure for table `creature_template_locale`
+--
+
+DROP TABLE IF EXISTS `creature_template_locale`;
+/*!40101 SET @saved_cs_client = @@character_set_client */;
+/*!40101 SET character_set_client = utf8 */;
+CREATE TABLE `creature_template_locale` (
+ `entry` mediumint(8) unsigned NOT NULL DEFAULT '0',
+ `locale` varchar(4) NOT NULL,
+ `Name` text,
+ `FemaleName` text,
+ `Title` text,
+ `VerifiedBuild` smallint(5) DEFAULT '0',
+ PRIMARY KEY (`entry`,`locale`)
+) ENGINE=MyISAM DEFAULT CHARSET=utf8;
+/*!40101 SET character_set_client = @saved_cs_client */;
+
--
-- Table structure for table `creature_text`
--
@@ -1136,6 +1155,7 @@ CREATE TABLE `gameobject_questitem` (
`GameObjectEntry` int(10) unsigned NOT NULL DEFAULT '0',
`Idx` int(10) unsigned NOT NULL DEFAULT '0',
`ItemId` int(10) unsigned NOT NULL DEFAULT '0',
+ `VerifiedBuild` smallint(5) NOT NULL DEFAULT '0',
PRIMARY KEY (`GameObjectEntry`,`Idx`)
) ENGINE=MyISAM DEFAULT CHARSET=utf8;
/*!40101 SET character_set_client = @saved_cs_client */;
@@ -1213,6 +1233,23 @@ CREATE TABLE `gameobject_template` (
) ENGINE=MyISAM DEFAULT CHARSET=utf8 ROW_FORMAT=FIXED COMMENT='Gameobject System';
/*!40101 SET character_set_client = @saved_cs_client */;
+--
+-- Table structure for table `gameobject_template_locale`
+--
+
+DROP TABLE IF EXISTS `gameobject_template_locale`;
+/*!40101 SET @saved_cs_client = @@character_set_client */;
+/*!40101 SET character_set_client = utf8 */;
+CREATE TABLE `gameobject_template_locale` (
+ `entry` mediumint(8) unsigned NOT NULL DEFAULT '0',
+ `locale` varchar(4) NOT NULL,
+ `name` text,
+ `castBarCaption` text,
+ `VerifiedBuild` smallint(5) DEFAULT '0',
+ PRIMARY KEY (`entry`,`locale`)
+) ENGINE=MyISAM DEFAULT CHARSET=utf8;
+/*!40101 SET character_set_client = @saved_cs_client */;
+
--
-- Table structure for table `gossip_menu`
--
@@ -1720,44 +1757,6 @@ CREATE TABLE `locales_broadcast_text` (
) ENGINE=MyISAM DEFAULT CHARSET=utf8;
/*!40101 SET character_set_client = @saved_cs_client */;
---
--- Table structure for table `locales_creature`
---
-
-DROP TABLE IF EXISTS `locales_creature`;
-/*!40101 SET @saved_cs_client = @@character_set_client */;
-/*!40101 SET character_set_client = utf8 */;
-CREATE TABLE `locales_creature` (
- `entry` mediumint(8) unsigned NOT NULL DEFAULT '0',
- `name_loc1` varchar(100) NOT NULL DEFAULT '',
- `femaleName_loc1` char(100) NOT NULL,
- `name_loc2` varchar(100) NOT NULL DEFAULT '',
- `femaleName_loc2` char(100) NOT NULL,
- `name_loc3` varchar(100) NOT NULL DEFAULT '',
- `femaleName_loc3` char(100) NOT NULL,
- `name_loc4` varchar(100) NOT NULL DEFAULT '',
- `femaleName_loc4` char(100) NOT NULL,
- `name_loc5` varchar(100) NOT NULL DEFAULT '',
- `femaleName_loc5` char(100) NOT NULL,
- `name_loc6` varchar(100) NOT NULL DEFAULT '',
- `femaleName_loc6` char(100) NOT NULL,
- `name_loc7` varchar(100) NOT NULL DEFAULT '',
- `femaleName_loc7` char(100) NOT NULL,
- `name_loc8` varchar(100) NOT NULL DEFAULT '',
- `femaleName_loc8` char(100) NOT NULL,
- `subname_loc1` varchar(100) DEFAULT NULL,
- `subname_loc2` varchar(100) DEFAULT NULL,
- `subname_loc3` varchar(100) DEFAULT NULL,
- `subname_loc4` varchar(100) DEFAULT NULL,
- `subname_loc5` varchar(100) DEFAULT NULL,
- `subname_loc6` varchar(100) DEFAULT NULL,
- `subname_loc7` varchar(100) DEFAULT NULL,
- `subname_loc8` varchar(100) DEFAULT NULL,
- `VerifiedBuild` smallint(5) DEFAULT '0',
- PRIMARY KEY (`entry`)
-) ENGINE=MyISAM DEFAULT CHARSET=utf8;
-/*!40101 SET character_set_client = @saved_cs_client */;
-
--
-- Table structure for table `locales_creature_text`
--
@@ -1781,36 +1780,6 @@ CREATE TABLE `locales_creature_text` (
) ENGINE=MyISAM DEFAULT CHARSET=utf8;
/*!40101 SET character_set_client = @saved_cs_client */;
---
--- Table structure for table `locales_gameobject`
---
-
-DROP TABLE IF EXISTS `locales_gameobject`;
-/*!40101 SET @saved_cs_client = @@character_set_client */;
-/*!40101 SET character_set_client = utf8 */;
-CREATE TABLE `locales_gameobject` (
- `entry` mediumint(8) unsigned NOT NULL DEFAULT '0',
- `name_loc1` varchar(100) NOT NULL DEFAULT '',
- `name_loc2` varchar(100) NOT NULL DEFAULT '',
- `name_loc3` varchar(100) NOT NULL DEFAULT '',
- `name_loc4` varchar(100) NOT NULL DEFAULT '',
- `name_loc5` varchar(100) NOT NULL DEFAULT '',
- `name_loc6` varchar(100) NOT NULL DEFAULT '',
- `name_loc7` varchar(100) NOT NULL DEFAULT '',
- `name_loc8` varchar(100) NOT NULL DEFAULT '',
- `castbarcaption_loc1` varchar(100) NOT NULL DEFAULT '',
- `castbarcaption_loc2` varchar(100) NOT NULL DEFAULT '',
- `castbarcaption_loc3` varchar(100) NOT NULL DEFAULT '',
- `castbarcaption_loc4` varchar(100) NOT NULL DEFAULT '',
- `castbarcaption_loc5` varchar(100) NOT NULL DEFAULT '',
- `castbarcaption_loc6` varchar(100) NOT NULL DEFAULT '',
- `castbarcaption_loc7` varchar(100) NOT NULL DEFAULT '',
- `castbarcaption_loc8` varchar(100) NOT NULL DEFAULT '',
- `VerifiedBuild` smallint(5) DEFAULT '0',
- PRIMARY KEY (`entry`)
-) ENGINE=MyISAM DEFAULT CHARSET=utf8;
-/*!40101 SET character_set_client = @saved_cs_client */;
-
--
-- Table structure for table `locales_gossip_menu_option`
--
@@ -2916,6 +2885,51 @@ CREATE TABLE `prospecting_loot_template` (
) ENGINE=MyISAM DEFAULT CHARSET=utf8 ROW_FORMAT=FIXED COMMENT='Loot System';
/*!40101 SET character_set_client = @saved_cs_client */;
+--
+-- Table structure for table `quest_details`
+--
+
+DROP TABLE IF EXISTS `quest_details`;
+/*!40101 SET @saved_cs_client = @@character_set_client */;
+/*!40101 SET character_set_client = utf8 */;
+CREATE TABLE `quest_details` (
+ `ID` mediumint(8) unsigned NOT NULL DEFAULT '0',
+ `Emote1` smallint(5) unsigned NOT NULL DEFAULT '0',
+ `Emote2` smallint(5) unsigned NOT NULL DEFAULT '0',
+ `Emote3` smallint(5) unsigned NOT NULL DEFAULT '0',
+ `Emote4` smallint(5) unsigned NOT NULL DEFAULT '0',
+ `EmoteDelay1` int(10) unsigned NOT NULL DEFAULT '0',
+ `EmoteDelay2` int(10) unsigned NOT NULL DEFAULT '0',
+ `EmoteDelay3` int(10) unsigned NOT NULL DEFAULT '0',
+ `EmoteDelay4` int(10) unsigned NOT NULL DEFAULT '0',
+ `VerifiedBuild` smallint(5) NOT NULL DEFAULT '0',
+ PRIMARY KEY (`ID`)
+) ENGINE=MyISAM DEFAULT CHARSET=utf8;
+/*!40101 SET character_set_client = @saved_cs_client */;
+
+--
+-- Table structure for table `quest_offer_reward`
+--
+
+DROP TABLE IF EXISTS `quest_offer_reward`;
+/*!40101 SET @saved_cs_client = @@character_set_client */;
+/*!40101 SET character_set_client = utf8 */;
+CREATE TABLE `quest_offer_reward` (
+ `ID` mediumint(8) unsigned NOT NULL DEFAULT '0',
+ `Emote1` smallint(5) unsigned NOT NULL DEFAULT '0',
+ `Emote2` smallint(5) unsigned NOT NULL DEFAULT '0',
+ `Emote3` smallint(5) unsigned NOT NULL DEFAULT '0',
+ `Emote4` smallint(5) unsigned NOT NULL DEFAULT '0',
+ `EmoteDelay1` int(10) unsigned NOT NULL DEFAULT '0',
+ `EmoteDelay2` int(10) unsigned NOT NULL DEFAULT '0',
+ `EmoteDelay3` int(10) unsigned NOT NULL DEFAULT '0',
+ `EmoteDelay4` int(10) unsigned NOT NULL DEFAULT '0',
+ `RewardText` text,
+ `VerifiedBuild` smallint(5) NOT NULL DEFAULT '0',
+ PRIMARY KEY (`ID`)
+) ENGINE=MyISAM DEFAULT CHARSET=utf8;
+/*!40101 SET character_set_client = @saved_cs_client */;
+
--
-- Table structure for table `quest_poi`
--
@@ -2957,6 +2971,23 @@ CREATE TABLE `quest_poi_points` (
) ENGINE=MyISAM DEFAULT CHARSET=utf8;
/*!40101 SET character_set_client = @saved_cs_client */;
+--
+-- Table structure for table `quest_request_items`
+--
+
+DROP TABLE IF EXISTS `quest_request_items`;
+/*!40101 SET @saved_cs_client = @@character_set_client */;
+/*!40101 SET character_set_client = utf8 */;
+CREATE TABLE `quest_request_items` (
+ `ID` mediumint(8) unsigned NOT NULL DEFAULT '0',
+ `EmoteOnComplete` smallint(5) unsigned NOT NULL DEFAULT '0',
+ `EmoteOnIncomplete` smallint(5) unsigned NOT NULL DEFAULT '0',
+ `CompletionText` text,
+ `VerifiedBuild` smallint(5) NOT NULL DEFAULT '0',
+ PRIMARY KEY (`ID`)
+) ENGINE=MyISAM DEFAULT CHARSET=utf8;
+/*!40101 SET character_set_client = @saved_cs_client */;
+
--
-- Table structure for table `quest_template`
--
@@ -2966,99 +2997,86 @@ DROP TABLE IF EXISTS `quest_template`;
/*!40101 SET character_set_client = utf8 */;
CREATE TABLE `quest_template` (
`ID` mediumint(8) unsigned NOT NULL DEFAULT '0',
- `Method` tinyint(3) unsigned NOT NULL DEFAULT '2',
+ `QuestType` tinyint(3) unsigned NOT NULL DEFAULT '2',
`QuestLevel` smallint(3) NOT NULL DEFAULT '1',
`MinLevel` smallint(6) NOT NULL DEFAULT '0',
`MaxLevel` smallint(6) NOT NULL DEFAULT '0',
`QuestSortID` smallint(6) NOT NULL DEFAULT '0',
- `QuestType` smallint(5) unsigned NOT NULL DEFAULT '0',
+ `QuestInfoID` smallint(5) unsigned NOT NULL DEFAULT '0',
`SuggestedGroupNum` tinyint(3) unsigned NOT NULL DEFAULT '0',
- `LimitTime` int(10) unsigned NOT NULL DEFAULT '0',
- `RequiredClasses` smallint(5) unsigned NOT NULL DEFAULT '0',
- `RequiredRaces` mediumint(8) unsigned NOT NULL DEFAULT '0',
- `RequiredSkillId` smallint(5) unsigned NOT NULL DEFAULT '0',
- `RequiredSkillPoints` smallint(5) unsigned NOT NULL DEFAULT '0',
`RequiredFactionId1` smallint(5) unsigned NOT NULL DEFAULT '0',
`RequiredFactionId2` smallint(5) unsigned NOT NULL DEFAULT '0',
`RequiredFactionValue1` mediumint(8) NOT NULL DEFAULT '0',
`RequiredFactionValue2` mediumint(8) NOT NULL DEFAULT '0',
- `RequiredMinRepFaction` smallint(5) unsigned NOT NULL DEFAULT '0',
- `RequiredMaxRepFaction` smallint(5) unsigned NOT NULL DEFAULT '0',
- `RequiredMinRepValue` mediumint(8) NOT NULL DEFAULT '0',
- `RequiredMaxRepValue` mediumint(8) NOT NULL DEFAULT '0',
- `PrevQuestId` mediumint(8) NOT NULL DEFAULT '0',
- `NextQuestId` mediumint(8) NOT NULL DEFAULT '0',
+ `RewardNextQuest` mediumint(8) unsigned NOT NULL DEFAULT '0',
+ `RewardXPDifficulty` tinyint(3) unsigned NOT NULL DEFAULT '0',
+ `RewardMoney` int(11) NOT NULL DEFAULT '0',
+ `RewardBonusMoney` int(10) unsigned NOT NULL DEFAULT '0',
+ `RewardDisplaySpell` mediumint(8) unsigned NOT NULL DEFAULT '0',
+ `RewardSpell` int(11) NOT NULL DEFAULT '0',
`ExclusiveGroup` mediumint(8) NOT NULL DEFAULT '0',
- `NextQuestIdChain` mediumint(8) unsigned NOT NULL DEFAULT '0',
- `RewardXPId` tinyint(3) unsigned NOT NULL DEFAULT '0',
- `RewardOrRequiredMoney` int(11) NOT NULL DEFAULT '0',
- `RewardMoneyMaxLevel` int(10) unsigned NOT NULL DEFAULT '0',
- `RewardSpell` mediumint(8) unsigned NOT NULL DEFAULT '0',
- `RewardSpellCast` int(11) NOT NULL DEFAULT '0',
`RewardHonor` int(11) NOT NULL DEFAULT '0',
`RewardHonorMultiplier` float NOT NULL DEFAULT '0',
`RewardMailTemplateId` mediumint(8) unsigned NOT NULL DEFAULT '0',
`RewardMailDelay` int(11) unsigned NOT NULL DEFAULT '0',
- `SourceItemId` mediumint(8) unsigned NOT NULL DEFAULT '0',
`SourceItemCount` tinyint(3) unsigned NOT NULL DEFAULT '0',
`SourceSpellId` mediumint(8) unsigned NOT NULL DEFAULT '0',
`Flags` int(10) unsigned NOT NULL DEFAULT '0',
`SpecialFlags` tinyint(3) unsigned NOT NULL DEFAULT '0',
`MinimapTargetMark` tinyint(3) unsigned NOT NULL DEFAULT '0',
- `RewardTitle` tinyint(3) unsigned NOT NULL DEFAULT '0',
`RequiredPlayerKills` tinyint(3) unsigned NOT NULL DEFAULT '0',
- `RewardTalents` tinyint(3) unsigned NOT NULL DEFAULT '0',
- `RewardArenaPoints` smallint(5) unsigned NOT NULL DEFAULT '0',
`RewardSkillId` smallint(5) unsigned NOT NULL DEFAULT '0',
`RewardSkillPoints` tinyint(3) unsigned NOT NULL DEFAULT '0',
`RewardReputationMask` tinyint(3) unsigned NOT NULL DEFAULT '0',
`QuestGiverPortrait` mediumint(8) unsigned NOT NULL DEFAULT '0',
`QuestTurnInPortrait` mediumint(8) unsigned NOT NULL DEFAULT '0',
- `RewardItem1` mediumint(8) unsigned NOT NULL DEFAULT '0',
- `RewardItem2` mediumint(8) unsigned NOT NULL DEFAULT '0',
- `RewardItem3` mediumint(8) unsigned NOT NULL DEFAULT '0',
- `RewardItem4` mediumint(8) unsigned NOT NULL DEFAULT '0',
- `RewardAmount1` smallint(5) unsigned NOT NULL DEFAULT '0',
- `RewardAmount2` smallint(5) unsigned NOT NULL DEFAULT '0',
- `RewardAmount3` smallint(5) unsigned NOT NULL DEFAULT '0',
- `RewardAmount4` smallint(5) unsigned NOT NULL DEFAULT '0',
+ `ItemDrop1` mediumint(8) unsigned NOT NULL DEFAULT '0',
+ `ItemDropQuantity1` smallint(5) unsigned NOT NULL DEFAULT '0',
+ `ItemDrop2` mediumint(8) unsigned NOT NULL DEFAULT '0',
+ `ItemDropQuantity2` smallint(5) unsigned NOT NULL DEFAULT '0',
+ `ItemDrop3` mediumint(8) unsigned NOT NULL DEFAULT '0',
+ `ItemDropQuantity3` smallint(5) unsigned NOT NULL DEFAULT '0',
+ `ItemDrop4` mediumint(8) unsigned NOT NULL DEFAULT '0',
+ `ItemDropQuantity4` smallint(5) unsigned NOT NULL DEFAULT '0',
`RewardChoiceItemID1` mediumint(8) unsigned NOT NULL DEFAULT '0',
- `RewardChoiceItemID2` mediumint(8) unsigned NOT NULL DEFAULT '0',
- `RewardChoiceItemID3` mediumint(8) unsigned NOT NULL DEFAULT '0',
- `RewardChoiceItemID4` mediumint(8) unsigned NOT NULL DEFAULT '0',
- `RewardChoiceItemID5` mediumint(8) unsigned NOT NULL DEFAULT '0',
- `RewardChoiceItemID6` mediumint(8) unsigned NOT NULL DEFAULT '0',
`RewardChoiceItemQuantity1` smallint(5) unsigned NOT NULL DEFAULT '0',
+ `RewardChoiceItemID2` mediumint(8) unsigned NOT NULL DEFAULT '0',
`RewardChoiceItemQuantity2` smallint(5) unsigned NOT NULL DEFAULT '0',
+ `RewardChoiceItemID3` mediumint(8) unsigned NOT NULL DEFAULT '0',
`RewardChoiceItemQuantity3` smallint(5) unsigned NOT NULL DEFAULT '0',
+ `RewardChoiceItemID4` mediumint(8) unsigned NOT NULL DEFAULT '0',
`RewardChoiceItemQuantity4` smallint(5) unsigned NOT NULL DEFAULT '0',
+ `RewardChoiceItemID5` mediumint(8) unsigned NOT NULL DEFAULT '0',
`RewardChoiceItemQuantity5` smallint(5) unsigned NOT NULL DEFAULT '0',
+ `RewardChoiceItemID6` mediumint(8) unsigned NOT NULL DEFAULT '0',
`RewardChoiceItemQuantity6` smallint(5) unsigned NOT NULL DEFAULT '0',
+ `POIContinent` smallint(5) unsigned NOT NULL DEFAULT '0',
+ `POIx` float NOT NULL DEFAULT '0',
+ `POIy` float NOT NULL DEFAULT '0',
+ `POIPriority` mediumint(8) unsigned NOT NULL DEFAULT '0',
+ `RewardTitle` tinyint(3) unsigned NOT NULL DEFAULT '0',
+ `RewardTalents` tinyint(3) unsigned NOT NULL DEFAULT '0',
+ `RewardArenaPoints` smallint(5) unsigned NOT NULL DEFAULT '0',
`RewardFactionID1` smallint(5) unsigned NOT NULL DEFAULT '0' COMMENT 'faction id from Faction.dbc in this case',
- `RewardFactionID2` smallint(5) unsigned NOT NULL DEFAULT '0' COMMENT 'faction id from Faction.dbc in this case',
- `RewardFactionID3` smallint(5) unsigned NOT NULL DEFAULT '0' COMMENT 'faction id from Faction.dbc in this case',
- `RewardFactionID4` smallint(5) unsigned NOT NULL DEFAULT '0' COMMENT 'faction id from Faction.dbc in this case',
- `RewardFactionID5` smallint(5) unsigned NOT NULL DEFAULT '0' COMMENT 'faction id from Faction.dbc in this case',
`RewardFactionValue1` mediumint(8) NOT NULL DEFAULT '0',
- `RewardFactionValue2` mediumint(8) NOT NULL DEFAULT '0',
- `RewardFactionValue3` mediumint(8) NOT NULL DEFAULT '0',
- `RewardFactionValue4` mediumint(8) NOT NULL DEFAULT '0',
- `RewardFactionValue5` mediumint(8) NOT NULL DEFAULT '0',
`RewardFactionOverride1` mediumint(8) NOT NULL DEFAULT '0',
+ `RewardFactionID2` smallint(5) unsigned NOT NULL DEFAULT '0' COMMENT 'faction id from Faction.dbc in this case',
+ `RewardFactionValue2` mediumint(8) NOT NULL DEFAULT '0',
`RewardFactionOverride2` mediumint(8) NOT NULL DEFAULT '0',
+ `RewardFactionID3` smallint(5) unsigned NOT NULL DEFAULT '0' COMMENT 'faction id from Faction.dbc in this case',
+ `RewardFactionValue3` mediumint(8) NOT NULL DEFAULT '0',
`RewardFactionOverride3` mediumint(8) NOT NULL DEFAULT '0',
+ `RewardFactionID4` smallint(5) unsigned NOT NULL DEFAULT '0' COMMENT 'faction id from Faction.dbc in this case',
+ `RewardFactionValue4` mediumint(8) NOT NULL DEFAULT '0',
`RewardFactionOverride4` mediumint(8) NOT NULL DEFAULT '0',
+ `RewardFactionID5` smallint(5) unsigned NOT NULL DEFAULT '0' COMMENT 'faction id from Faction.dbc in this case',
+ `RewardFactionValue5` mediumint(8) NOT NULL DEFAULT '0',
`RewardFactionOverride5` mediumint(8) NOT NULL DEFAULT '0',
- `PointMapId` smallint(5) unsigned NOT NULL DEFAULT '0',
- `PointX` float NOT NULL DEFAULT '0',
- `PointY` float NOT NULL DEFAULT '0',
- `PointOption` mediumint(8) unsigned NOT NULL DEFAULT '0',
+ `TimeAllowed` int(10) unsigned NOT NULL DEFAULT '0',
`LogTitle` text,
`LogDescription` text,
`QuestDescription` text,
- `EndText` text,
- `OfferRewardText` text,
- `RequestItemsText` text,
+ `AreaDescription` text,
`QuestCompletionLog` text,
`RequiredNpcOrGo1` mediumint(8) NOT NULL DEFAULT '0',
`RequiredNpcOrGo2` mediumint(8) NOT NULL DEFAULT '0',
@@ -3068,14 +3086,6 @@ CREATE TABLE `quest_template` (
`RequiredNpcOrGoCount2` smallint(5) unsigned NOT NULL DEFAULT '0',
`RequiredNpcOrGoCount3` smallint(5) unsigned NOT NULL DEFAULT '0',
`RequiredNpcOrGoCount4` smallint(5) unsigned NOT NULL DEFAULT '0',
- `RequiredSourceItemId1` mediumint(8) unsigned NOT NULL DEFAULT '0',
- `RequiredSourceItemId2` mediumint(8) unsigned NOT NULL DEFAULT '0',
- `RequiredSourceItemId3` mediumint(8) unsigned NOT NULL DEFAULT '0',
- `RequiredSourceItemId4` mediumint(8) unsigned NOT NULL DEFAULT '0',
- `RequiredSourceItemCount1` smallint(5) unsigned NOT NULL DEFAULT '0',
- `RequiredSourceItemCount2` smallint(5) unsigned NOT NULL DEFAULT '0',
- `RequiredSourceItemCount3` smallint(5) unsigned NOT NULL DEFAULT '0',
- `RequiredSourceItemCount4` smallint(5) unsigned NOT NULL DEFAULT '0',
`RequiredItemId1` mediumint(8) unsigned NOT NULL DEFAULT '0',
`RequiredItemId2` mediumint(8) unsigned NOT NULL DEFAULT '0',
`RequiredItemId3` mediumint(8) unsigned NOT NULL DEFAULT '0',
@@ -3115,24 +3125,6 @@ CREATE TABLE `quest_template` (
`QuestTurnTargetName` text,
`SoundAccept` smallint(5) unsigned NOT NULL DEFAULT '890',
`SoundTurnIn` smallint(5) unsigned NOT NULL DEFAULT '878',
- `DetailsEmote1` smallint(5) unsigned NOT NULL DEFAULT '0',
- `DetailsEmote2` smallint(5) unsigned NOT NULL DEFAULT '0',
- `DetailsEmote3` smallint(5) unsigned NOT NULL DEFAULT '0',
- `DetailsEmote4` smallint(5) unsigned NOT NULL DEFAULT '0',
- `DetailsEmoteDelay1` int(10) unsigned NOT NULL DEFAULT '0',
- `DetailsEmoteDelay2` int(10) unsigned NOT NULL DEFAULT '0',
- `DetailsEmoteDelay3` int(10) unsigned NOT NULL DEFAULT '0',
- `DetailsEmoteDelay4` int(10) unsigned NOT NULL DEFAULT '0',
- `EmoteOnIncomplete` smallint(5) unsigned NOT NULL DEFAULT '0',
- `EmoteOnComplete` smallint(5) unsigned NOT NULL DEFAULT '0',
- `OfferRewardEmote1` smallint(5) unsigned NOT NULL DEFAULT '0',
- `OfferRewardEmote2` smallint(5) unsigned NOT NULL DEFAULT '0',
- `OfferRewardEmote3` smallint(5) unsigned NOT NULL DEFAULT '0',
- `OfferRewardEmote4` smallint(5) unsigned NOT NULL DEFAULT '0',
- `OfferRewardEmoteDelay1` int(10) unsigned NOT NULL DEFAULT '0',
- `OfferRewardEmoteDelay2` int(10) unsigned NOT NULL DEFAULT '0',
- `OfferRewardEmoteDelay3` int(10) unsigned NOT NULL DEFAULT '0',
- `OfferRewardEmoteDelay4` int(10) unsigned NOT NULL DEFAULT '0',
`VerifiedBuild` smallint(5) DEFAULT '0',
PRIMARY KEY (`ID`)
) ENGINE=MyISAM DEFAULT CHARSET=utf8 COMMENT='Quest System';
@@ -3149,6 +3141,7 @@ CREATE TABLE `quest_template_addon` (
`ID` mediumint(8) unsigned NOT NULL DEFAULT '0',
`MaxLevel` tinyint(3) unsigned NOT NULL DEFAULT '0',
`AllowableClasses` int(10) unsigned NOT NULL DEFAULT '0',
+ `AllowableRaces` smallint(5) unsigned NOT NULL DEFAULT '0',
`SourceSpellID` mediumint(8) unsigned NOT NULL DEFAULT '0',
`PrevQuestID` mediumint(8) NOT NULL DEFAULT '0',
`NextQuestID` mediumint(8) NOT NULL DEFAULT '0',
@@ -3302,6 +3295,22 @@ CREATE TABLE `skill_fishing_base_level` (
) ENGINE=MyISAM DEFAULT CHARSET=utf8 ROW_FORMAT=FIXED COMMENT='Fishing system';
/*!40101 SET character_set_client = @saved_cs_client */;
+--
+-- Table structure for table `skill_perfect_item_template`
+--
+
+DROP TABLE IF EXISTS `skill_perfect_item_template`;
+/*!40101 SET @saved_cs_client = @@character_set_client */;
+/*!40101 SET character_set_client = utf8 */;
+CREATE TABLE `skill_perfect_item_template` (
+ `spellId` mediumint(8) unsigned NOT NULL DEFAULT '0' COMMENT 'SpellId of the item creation spell',
+ `requiredSpecialization` mediumint(8) unsigned NOT NULL DEFAULT '0' COMMENT 'Specialization spell id',
+ `perfectCreateChance` float NOT NULL DEFAULT '0' COMMENT 'chance to create the perfect item instead',
+ `perfectItemType` mediumint(8) unsigned NOT NULL DEFAULT '0' COMMENT 'perfect item type to create instead',
+ PRIMARY KEY (`spellId`)
+) ENGINE=MyISAM DEFAULT CHARSET=utf8 ROW_FORMAT=FIXED COMMENT='Crafting Perfection System';
+/*!40101 SET character_set_client = @saved_cs_client */;
+
--
-- Table structure for table `skinning_loot_template`
--
@@ -3993,4 +4002,4 @@ CREATE TABLE `waypoints` (
/*!40101 SET COLLATION_CONNECTION=@OLD_COLLATION_CONNECTION */;
/*!40111 SET SQL_NOTES=@OLD_SQL_NOTES */;
--- Dump completed on 2014-10-30 13:45:31
+-- Dump completed on 2015-11-07 14:42:45
diff --git a/sql/updates/auth/2016_01_13_00_auth.sql b/sql/updates/auth/2016_01_13_00_auth.sql
new file mode 100644
index 00000000000..c70d4c09468
--- /dev/null
+++ b/sql/updates/auth/2016_01_13_00_auth.sql
@@ -0,0 +1,6 @@
+--
+DELETE FROM `rbac_permissions` WHERE `id`=836;
+INSERT INTO `rbac_permissions` (`id`,`name`) VALUES (836,"Command: .debug boundary");
+
+DELETE FROM `rbac_linked_permissions` WHERE `linkedId`=836;
+INSERT INTO `rbac_linked_permissions` (`id`,`linkedId`) VALUES (196, 836);
diff --git a/sql/updates/characters/2016_01_14_from_335_2015_10_06_00_characters.sql b/sql/updates/characters/2016_01_14_from_335_2015_10_06_00_characters.sql
new file mode 100644
index 00000000000..c8d8e3211f4
--- /dev/null
+++ b/sql/updates/characters/2016_01_14_from_335_2015_10_06_00_characters.sql
@@ -0,0 +1,2 @@
+ALTER TABLE `gm_ticket`
+ ADD COLUMN `resolvedBy` INT(10) NOT NULL DEFAULT '0' COMMENT 'GUID of GM who resolved the ticket' AFTER `needMoreHelp`;
diff --git a/sql/updates/characters/2016_01_14_from_335_2015_10_07_00_characters.sql b/sql/updates/characters/2016_01_14_from_335_2015_10_07_00_characters.sql
new file mode 100644
index 00000000000..a03fffcd77a
--- /dev/null
+++ b/sql/updates/characters/2016_01_14_from_335_2015_10_07_00_characters.sql
@@ -0,0 +1,3 @@
+ALTER TABLE `pet_aura`
+DROP PRIMARY KEY,
+ADD PRIMARY KEY (`guid`,`casterGuid`,`spell`,`effectMask`);
diff --git a/sql/updates/characters/2016_01_14_from_335_2015_10_12_00_characters.sql b/sql/updates/characters/2016_01_14_from_335_2015_10_12_00_characters.sql
new file mode 100644
index 00000000000..d7d4fb90f02
--- /dev/null
+++ b/sql/updates/characters/2016_01_14_from_335_2015_10_12_00_characters.sql
@@ -0,0 +1,17 @@
+-- Add new winner field, bound to player
+ALTER TABLE `pvpstats_players`
+ ADD COLUMN `winner` BIT(1) NOT NULL AFTER `character_guid`;
+
+-- Resolve horde players victories
+UPDATE `pvpstats_players` SET `winner` = 1 WHERE `battleground_id` IN (
+ SELECT `id` FROM `pvpstats_battlegrounds` WHERE `winner_faction` = 0
+) AND `character_guid` IN (
+ SELECT `guid` FROM `characters` WHERE `race` IN (2, 5, 6, 8, 9, 10)
+);
+
+-- Resolve alliance players victories
+UPDATE `pvpstats_players` SET `winner` = 1 WHERE `battleground_id` IN (
+ SELECT `id` FROM `pvpstats_battlegrounds` WHERE `winner_faction` = 1
+) AND `character_guid` IN (
+ SELECT `guid` FROM `characters` WHERE `race` IN (1, 3, 4, 7, 11, 22)
+);
diff --git a/sql/updates/characters/2016_01_14_from_335_2015_10_28_00_characters.sql b/sql/updates/characters/2016_01_14_from_335_2015_10_28_00_characters.sql
new file mode 100644
index 00000000000..9d353773a33
--- /dev/null
+++ b/sql/updates/characters/2016_01_14_from_335_2015_10_28_00_characters.sql
@@ -0,0 +1,6 @@
+DROP TABLE IF EXISTS `battleground_deserters`;
+CREATE TABLE `battleground_deserters` (
+ `guid` INT(10) UNSIGNED NOT NULL COMMENT 'characters.guid',
+ `type` TINYINT(3) UNSIGNED NOT NULL COMMENT 'type of the desertion',
+ `datetime` DATETIME NOT NULL COMMENT 'datetime of the desertion'
+);
diff --git a/sql/updates/characters/2016_01_14_from_335_2015_11_03_00_characters.sql b/sql/updates/characters/2016_01_14_from_335_2015_11_03_00_characters.sql
new file mode 100644
index 00000000000..b74824477be
--- /dev/null
+++ b/sql/updates/characters/2016_01_14_from_335_2015_11_03_00_characters.sql
@@ -0,0 +1,10 @@
+ALTER TABLE `gm_ticket`
+ ADD COLUMN `type` TINYINT(3) UNSIGNED NOT NULL DEFAULT '0' COMMENT '0 open, 1 closed, 2 character deleted' AFTER `id`;
+
+UPDATE `gm_ticket` SET `type` = 1 WHERE `closedBy` != 0 OR `completed` != 0 OR `resolvedBy` != 0;
+UPDATE `gm_ticket` SET `closedBy` = 0 WHERE `closedBy` < 0;
+UPDATE `gm_ticket` SET `resolvedBy` = 0 WHERE `resolvedBy` < 0;
+
+ALTER TABLE `gm_ticket`
+ CHANGE COLUMN `closedBy` `closedBy` INT(10) UNSIGNED NOT NULL DEFAULT '0' AFTER `lastModifiedTime`,
+ CHANGE COLUMN `resolvedBy` `resolvedBy` INT(10) UNSIGNED NOT NULL DEFAULT '0' COMMENT 'GUID of GM who resolved the ticket' AFTER `needMoreHelp`;
diff --git a/sql/updates/world/2016_01_14_00_world_434.sql b/sql/updates/world/2016_01_14_00_world_434.sql
new file mode 100644
index 00000000000..64db893de5f
--- /dev/null
+++ b/sql/updates/world/2016_01_14_00_world_434.sql
@@ -0,0 +1,46 @@
+-- creating `quest_template_addon` table
+DROP TABLE IF EXISTS `quest_template_addon`;
+CREATE TABLE IF NOT EXISTS `quest_template_addon` ( -- old names:
+ `ID` mediumint(8) unsigned NOT NULL DEFAULT '0', -- ID
+ `MaxLevel` tinyint(3) unsigned NOT NULL DEFAULT '0', -- MaxLevel
+ `AllowableClasses` int(10) unsigned NOT NULL DEFAULT '0', -- RequiredClasses
+ `SourceSpellID` mediumint(8) unsigned NOT NULL DEFAULT '0', -- SourceSpellId
+ `PrevQuestID` mediumint(8) NOT NULL DEFAULT '0', -- PrevQuestId
+ `NextQuestID` mediumint(8) NOT NULL DEFAULT '0', -- NextQuestId
+ `ExclusiveGroup` mediumint(8) NOT NULL DEFAULT '0', -- ExclusiveGroup
+ `RewardMailTemplateID` mediumint(8) unsigned NOT NULL DEFAULT '0', -- RewardMailTemplateId
+ `RewardMailDelay` int(10) unsigned NOT NULL DEFAULT '0', -- RewardMailDelay
+ `RequiredSkillID` smallint(5) unsigned NOT NULL DEFAULT '0', -- RequiredSkillId
+ `RequiredSkillPoints` smallint(5) unsigned NOT NULL DEFAULT '0', -- RequiredSkillPoints
+ `RequiredMinRepFaction` smallint(5) unsigned NOT NULL DEFAULT '0', -- RequiredMinRepFaction
+ `RequiredMaxRepFaction` smallint(5) unsigned NOT NULL DEFAULT '0', -- RequiredMaxRepFaction
+ `RequiredMinRepValue` mediumint(8) NOT NULL DEFAULT '0', -- RequiredMinRepValue
+ `RequiredMaxRepValue` mediumint(8) NOT NULL DEFAULT '0', -- RequiredMaxRepValue
+ `ProvidedItemCount` tinyint(3) unsigned NOT NULL DEFAULT '0', -- SourceItemCount
+ `SpecialFlags` tinyint(3) unsigned NOT NULL DEFAULT '0', -- SpecialFlags
+ PRIMARY KEY (`ID`)
+) ENGINE=MyISAM DEFAULT CHARSET=utf8;
+
+-- moving data from `quest_template` to `quest_template_addon`
+INSERT INTO `quest_template_addon`
+(`ID`, `MaxLevel`, `AllowableClasses`, `SourceSpellID`, `PrevQuestID`, `NextQuestID`, `ExclusiveGroup`, `RewardMailTemplateID`, `RewardMailDelay`, `RequiredSkillID`, `RequiredSkillPoints`, `RequiredMinRepFaction`, `RequiredMaxRepFaction`, `RequiredMinRepValue`, `RequiredMaxRepValue`, `ProvidedItemCount`, `SpecialFlags`)
+(SELECT `ID`, `MaxLevel`, `RequiredClasses`, `SourceSpellId`, `PrevQuestId`, `NextQuestId`, `ExclusiveGroup`, `RewardMailTemplateId`, `RewardMailDelay`, `RequiredSkillId`, `RequiredSkillPoints`, `RequiredMinRepFaction`, `RequiredMaxRepFaction`, `RequiredMinRepValue`, `RequiredMaxRepValue`, `SourceItemCount`, `SpecialFlags` FROM `quest_template`);
+
+-- drop `quest_template` fields
+ALTER TABLE `quest_template`
+DROP `MaxLevel`,
+DROP `RequiredClasses`,
+DROP `SourceSpellId`,
+DROP `PrevQuestId`,
+DROP `NextQuestId`,
+DROP `ExclusiveGroup`,
+DROP `RewardMailTemplateId`,
+DROP `RewardMailDelay`,
+DROP `RequiredSkillId`,
+DROP `RequiredSkillPoints`,
+DROP `RequiredMinRepFaction`,
+DROP `RequiredMaxRepFaction`,
+DROP `RequiredMinRepValue`,
+DROP `RequiredMaxRepValue`,
+DROP `SourceItemCount`,
+DROP `SpecialFlags`;
diff --git a/sql/updates/world/2016_01_14_from_335_2015_10_31_03_world_2015_08_01_01.sql b/sql/updates/world/2016_01_14_from_335_2015_10_31_03_world_2015_08_01_01.sql
new file mode 100644
index 00000000000..d3425272313
--- /dev/null
+++ b/sql/updates/world/2016_01_14_from_335_2015_10_31_03_world_2015_08_01_01.sql
@@ -0,0 +1,44 @@
+DROP TABLE IF EXISTS `creature_template_locale`;
+CREATE TABLE IF NOT EXISTS `creature_template_locale` (
+ `entry` MEDIUMINT(8) UNSIGNED NOT NULL DEFAULT '0',
+ `locale` VARCHAR(4) NOT NULL,
+ `Name` TEXT,
+ `FemaleName` TEXT,
+ `Title` TEXT,
+ `VerifiedBuild` SMALLINT(5) DEFAULT '0',
+ PRIMARY KEY (`entry`,`locale`)
+) ENGINE=MYISAM DEFAULT CHARSET=utf8;
+
+-- koKR
+INSERT INTO `creature_template_locale` (`entry`, `locale`, `Name`, `FemaleName`, `Title`, `VerifiedBuild`)
+ (SELECT `entry`, "koKR", `name_loc1`, `femaleName_loc1`, `subname_loc1`, `VerifiedBuild` FROM `locales_creature` WHERE LENGTH(`name_loc1`) > 0 OR LENGTH(`femaleName_loc1`) > 0 OR LENGTH(`subname_loc1`) > 0);
+
+-- frFR
+INSERT INTO `creature_template_locale` (`entry`, `locale`, `Name`, `FemaleName`, `Title`, `VerifiedBuild`)
+ (SELECT `entry`, "frFR", `name_loc2`, `femaleName_loc2`, `subname_loc2`, `VerifiedBuild` FROM `locales_creature` WHERE LENGTH(`name_loc2`) > 0 OR LENGTH(`femaleName_loc2`) > 0 OR LENGTH(`subname_loc2`) > 0);
+
+-- deDE
+INSERT INTO `creature_template_locale` (`entry`, `locale`, `Name`, `FemaleName`, `Title`, `VerifiedBuild`)
+ (SELECT `entry`, "deDE", `name_loc3`, `femaleName_loc3`, `subname_loc3`, `VerifiedBuild` FROM `locales_creature` WHERE LENGTH(`name_loc3`) > 0 OR LENGTH(`femaleName_loc3`) > 0 OR LENGTH(`subname_loc3`) > 0);
+
+-- zhCN
+INSERT INTO `creature_template_locale` (`entry`, `locale`, `Name`, `FemaleName`, `Title`, `VerifiedBuild`)
+ (SELECT `entry`, "zhCN", `name_loc4`, `femaleName_loc4`, `subname_loc4`, `VerifiedBuild` FROM `locales_creature` WHERE LENGTH(`name_loc4`) > 0 OR LENGTH(`femaleName_loc4`) > 0 OR LENGTH(`subname_loc4`) > 0);
+
+-- zhTW
+INSERT INTO `creature_template_locale` (`entry`, `locale`, `Name`, `FemaleName`, `Title`, `VerifiedBuild`)
+ (SELECT `entry`, "zhTW", `name_loc5`, `femaleName_loc5`, `subname_loc5`, `VerifiedBuild` FROM `locales_creature` WHERE LENGTH(`name_loc5`) > 0 OR LENGTH(`femaleName_loc5`) > 0 OR LENGTH(`subname_loc5`) > 0);
+
+-- esES
+INSERT INTO `creature_template_locale` (`entry`, `locale`, `Name`, `FemaleName`, `Title`, `VerifiedBuild`)
+ (SELECT `entry`, "esES", `name_loc6`, `femaleName_loc6`, `subname_loc6`, `VerifiedBuild` FROM `locales_creature` WHERE LENGTH(`name_loc6`) > 0 OR LENGTH(`femaleName_loc6`) > 0 OR LENGTH(`subname_loc6`) > 0);
+
+-- esMX
+INSERT INTO `creature_template_locale` (`entry`, `locale`, `Name`, `FemaleName`, `Title`, `VerifiedBuild`)
+ (SELECT `entry`, "esMX", `name_loc7`, `femaleName_loc7`, `subname_loc7`, `VerifiedBuild` FROM `locales_creature` WHERE LENGTH(`name_loc7`) > 0 OR LENGTH(`femaleName_loc7`) > 0 OR LENGTH(`subname_loc7`) > 0);
+
+-- ruRU
+INSERT INTO `creature_template_locale` (`entry`, `locale`, `Name`, `FemaleName`, `Title`, `VerifiedBuild`)
+ (SELECT `entry`, "ruRU", `name_loc8`, `femaleName_loc8`, `subname_loc8`, `VerifiedBuild` FROM `locales_creature` WHERE LENGTH(`name_loc8`) > 0 OR LENGTH(`femaleName_loc8`) > 0 OR LENGTH(`subname_loc8`) > 0);
+
+DROP TABLE IF EXISTS `locales_creature`;
diff --git a/sql/updates/world/2016_01_14_from_335_2016_01_07_02_world.sql b/sql/updates/world/2016_01_14_from_335_2016_01_07_02_world.sql
new file mode 100644
index 00000000000..7724b42ac9d
--- /dev/null
+++ b/sql/updates/world/2016_01_14_from_335_2016_01_07_02_world.sql
@@ -0,0 +1,2 @@
+-- fix a start-up warning
+UPDATE `creature` SET `spawndist`=0 WHERE `guid` IN (79007,79008,79009);
diff --git a/sql/updates/world/2016_01_14_from_335_2016_01_08_01_world.sql b/sql/updates/world/2016_01_14_from_335_2016_01_08_01_world.sql
new file mode 100644
index 00000000000..ebf4560d326
--- /dev/null
+++ b/sql/updates/world/2016_01_14_from_335_2016_01_08_01_world.sql
@@ -0,0 +1,52 @@
+--
+SET @Oguid :=6008;
+DELETE FROM `gameobject` WHERE `id`=186487;
+INSERT INTO `gameobject` (`guid`, `id`, `map`, `spawnMask`, `phaseMask`, `position_x`, `position_y`, `position_z`, `orientation`, `rotation0`, `rotation1`, `rotation2`, `rotation3`, `spawntimesecs`, `animprogress`, `state`) VALUES
+(@Oguid, 186487, 571, 1, 1, 2821.75, -3603.67, 245.555, 3.49556, 0, 0, 0.984379, -0.176061, -300, 0, 1);
+
+SET @CGUID := 76053;
+DELETE FROM `creature_template_addon` WHERE `entry` IN (24029);
+INSERT INTO `creature_template_addon` (`entry`, `mount`, `bytes1`, `bytes2`, `auras`) VALUES
+(24029, 0, 0x0, 0x1, 12544); -- Wyrmcaller Vile - Frost Armor
+
+DELETE FROM `creature_addon` WHERE `guid` IN (@CGUID+5);
+INSERT INTO `creature_addon` (`guid`, `mount`, `bytes1`, `bytes2`, `auras`) VALUES
+(@CGUID+5, 0, 0x0, 0x1, 43570); -- Invisible Stalker (Floating) - Frost State
+
+DELETE FROM `spell_linked_spell` WHERE `spell_trigger` IN(43568,43569);
+INSERT INTO `spell_linked_spell` (`spell_trigger`, `spell_effect`, `type`, `comment`) VALUES
+(43568, 34872, 1, 'Frost Strike'),
+(43569, 34872, 1, 'Frost trigger ');
+
+DELETE FROM `conditions` WHERE `SourceTypeOrReferenceId`=13 AND `SourceEntry` IN(43568);
+INSERT INTO `conditions` (`SourceTypeOrReferenceId`, `SourceGroup`, `SourceEntry`, `SourceId`, `ElseGroup`, `ConditionTypeOrReference`, `ConditionTarget`, `ConditionValue1`, `ConditionValue2`, `ConditionValue3`, `NegativeCondition`, `ErrorType`, `ErrorTextId`, `ScriptName`, `Comment`) VALUES
+(13,1,43568,0,0,31,0,3,15214,0,0,0,0,'',"Spell 'Frost Strike' Effect 0 can hit 'Invisible Stalker'");
+
+DELETE FROM `creature` WHERE `guid` BETWEEN @CGUID AND @CGUID+8;
+INSERT INTO `creature` (`guid`, `id`, `map`, `spawnMask`, `phaseMask`, `position_x`, `position_y`, `position_z`, `orientation`, `spawntimesecs`, `spawndist`, `MovementType`) VALUES
+(@CGUID, 15214, 571, 1, 1, 2842.762, -3599.551, 247.2563, 1.658063, 120, 0, 0), -- Invisible Stalker (Area: -Unknown-)
+(@CGUID+1, 15214, 571, 1, 1, 2807.391, -3586.93, 247.6916, 3.455752, 120, 0, 0), -- Invisible Stalker (Area: -Unknown-)
+(@CGUID+2, 15214, 571, 1, 1, 2833.016, -3621.016, 247.373, 1.850049, 120, 0, 0), -- Invisible Stalker (Area: -Unknown-)
+(@CGUID+3, 23033, 571, 1, 1, 2831.685, -3611.948, 257.9287, 0.2479207, 120, 0, 0), -- Invisible Stalker (Floating) (Area: -Unknown-) (Auras: 43570 - Frost State)
+(@CGUID+4, 23033, 571, 1, 1, 2832.849, -3638.875, 246.9362, 0.5235988, 120, 0, 0), -- Invisible Stalker (Floating) (Area: -Unknown-)
+(@CGUID+5, 23033, 571, 1, 1, 2820.243, -3602.598, 261.4395, 6.161012, 120, 0, 0), -- Invisible Stalker (Floating) (Area: -Unknown-)
+(@CGUID+6, 23033, 571, 1, 1, 2855.824, -3596.345, 248.4855, 5.131268, 120, 0, 0), -- Invisible Stalker (Floating) (Area: -Unknown-)
+(@CGUID+7, 24029, 571, 1, 1, 2820.328, -3602.552, 247.9988, 3.665191, 120, 0, 0), -- Wyrmcaller Vile (Area: -Unknown-) (Auras: 12544 - Frost Armor)
+(@CGUID+8, 23033, 571, 1, 1, 2818.341, -3604.437, 252.666, 3.845377, 120, 0, 0); -- Invisible Stalker (Floating) (Area: -Unknown-)
+
+UPDATE `creature_template` SET `AIName`='SmartAI' WHERE `entry`=24029;
+DELETE FROM `smart_scripts` WHERE `entryorguid` IN (24029,-106031,-@CGUID,-(@CGUID+1),-(@CGUID+2),-(@CGUID+5),-(@CGUID+8)) AND `source_type`=0;
+DELETE FROM `smart_scripts` WHERE `entryorguid` IN (@CGUID*100,@CGUID*100+1) AND `source_type`=9;
+INSERT INTO `smart_scripts` (`entryorguid`,`source_type`,`id`,`link`,`event_type`,`event_phase_mask`,`event_chance`,`event_flags`,`event_param1`,`event_param2`,`event_param3`,`event_param4`,`action_type`,`action_param1`,`action_param2`,`action_param3`,`action_param4`,`action_param5`,`action_param6`,`target_type`,`target_param1`,`target_param2`,`target_param3`,`target_x`,`target_y`,`target_z`,`target_o`,`comment`) VALUES
+(24029,0,0,0,1,0,100,1,0,0,3000,3000,11,43576,2,0,0,0,0,1,0,0,0,0,0,0,0,'Wyrmcaller Vile - OOC - Cast \'Frost Power\''),
+(24029,0,1,0,0,0,100,0,0,0,4000,4000,11,9672,0,0,0,0,0,2,0,0,0,0,0,0,0,'Wyrmcaller Vile - IC - Cast \'Frostbolt\''),
+(24029,0,2,0,0,0,100,0,0,0,6000,10000,11,15532,0,0,0,0,0,2,0,0,0,0,0,0,0,'Wyrmcaller Vile - IC - Cast \'Frost Nova\''),
+(24029,0,3,0,1,0,100,0,0,0,3000,3000,45,0,1,0,0,0,0,19,23033,10,0,0,0,0,0,'Wyrmcaller Vile - OOC - Cast \'Set Data\''),
+(-106031,0,0,0,8,0,100,0,43568,0,0,0,80,@CGUID*100,0,0,0,0,0,1,0,0,0,0,0,0,0,'Invisible Stalker - On SpellHit \'Frost Strike\' - Call ActionList'),
+(-@CGUID,0,0,0,8,0,100,0,43568,0,0,0,80,@CGUID*100,0,0,0,0,0,1,0,0,0,0,0,0,0,'Invisible Stalker - On SpellHit \'Frost Strike\' - Call ActionList'),
+(-(@CGUID+1),0,0,0,8,0,100,0,43568,0,0,0,80,@CGUID*100,0,0,0,0,0,1,0,0,0,0,0,0,0,'Invisible Stalker - On SpellHit \'Frost Strike\' - Call ActionList'),
+(-(@CGUID+2),0,0,0,8,0,100,0,43568,0,0,0,80,@CGUID*100+1,0,0,0,0,0,1,0,0,0,0,0,0,0,'Invisible Stalker - On SpellHit \'Frost Strike\' - Call ActionList'),
+(@CGUID*100,9,0,0,0,0,100,0,2400,2400,0,0,11,43569,2,0,0,0,0,19,23033,19,0,0,0,0,0,'Invisible Stalker - Action list - Cast \'Frost\''),
+(@CGUID*100+1,9,0,0,0,0,100,0,2400,2400,0,0,11,43569,2,0,0,0,0,10,@CGUID+4,23033,0,0,0,0,0,'Invisible Stalker - Action list - Cast \'Frost\''),
+(-(@CGUID+5),0,0,0,1,0,100,0,0,0,5000,7000,11,43591,2,0,0,0,0,19,24029,16,0,0,0,0,0,'Invisible Stalker - OOC - Cast \'Soul Siphon\''),
+(-(@CGUID+8),0,0,0,38,0,100,0,0,1,0,0,11,43568,2,0,0,0,0,1,0,0,0,0,0,0,0,'Invisible Stalker - On data set - Cast \'Frost Strike\'');
diff --git a/sql/updates/world/2016_01_14_from_335_2016_01_08_02_world.sql b/sql/updates/world/2016_01_14_from_335_2016_01_08_02_world.sql
new file mode 100644
index 00000000000..28e55dfba3b
--- /dev/null
+++ b/sql/updates/world/2016_01_14_from_335_2016_01_08_02_world.sql
@@ -0,0 +1,35 @@
+--
+DELETE FROM `creature_formations` WHERE `leaderGUID`=79010;
+INSERT INTO `creature_formations` (`leaderGUID`, `memberGUID`, `dist`, `angle`, `groupAI`, `point_1`, `point_2`) VALUES
+(79010, 79010, 0, 0, 2, 0, 0),
+(79010, 79012, 6, 360, 2, 0, 0);
+
+-- Pathing for Entry: 22987 'TDB FORMAT'
+SET @NPC := 79010;
+SET @PATH := @NPC * 10;
+UPDATE `creature` SET `spawndist`=0,`MovementType`=2,`position_x`=-3376.641,`position_y`=3642.897,`position_z`=285.1084 WHERE `guid`=@NPC;
+DELETE FROM `creature_addon` WHERE `guid`=@NPC;
+INSERT INTO `creature_addon` (`guid`,`path_id`,`mount`,`bytes1`,`bytes2`,`emote`,`auras`) VALUES (@NPC,@PATH,0,0,1,0, '');
+DELETE FROM `waypoint_data` WHERE `id`=@PATH;
+INSERT INTO `waypoint_data` (`id`,`point`,`position_x`,`position_y`,`position_z`,`orientation`,`delay`,`move_type`,`action`,`action_chance`,`wpguid`) VALUES
+(@PATH,1,-3376.641,3642.897,285.1084,0,0,0,0,100,0), -- 00:15:15
+(@PATH,2,-3372.496,3645.907,284.7475,0,0,0,0,100,0), -- 00:15:16
+(@PATH,3,-3376.866,3642.62,285.2078,0,0,0,0,100,0), -- 00:15:22
+(@PATH,4,-3381.402,3626.403,279.4974,0,0,0,0,100,0), -- 00:15:26
+(@PATH,5,-3382.558,3624.162,278.2544,0,0,0,0,100,0), -- 00:15:31
+(@PATH,6,-3385.898,3620.779,276.7867,0,0,0,0,100,0), -- 00:15:33
+(@PATH,7,-3389.558,3619.429,276.3516,0,0,0,0,100,0), -- 00:15:35
+(@PATH,8,-3393.407,3613.085,276.4259,0,0,0,0,100,0), -- 00:15:38
+(@PATH,9,-3390.018,3604.891,276.2281,0,0,0,0,100,0), -- 00:15:41
+(@PATH,10,-3397.005,3597.193,277.0055,0,0,0,0,100,0), -- 00:15:44
+(@PATH,11,-3393.93,3598.741,276.5433,0,0,0,0,100,0), -- 00:15:48
+(@PATH,12,-3390.969,3600.254,276.3882,0,0,0,0,100,0), -- 00:15:50
+(@PATH,13,-3389.908,3605.303,276.3074,0,0,0,0,100,0), -- 00:15:51
+(@PATH,14,-3390.732,3618.796,276.4376,0,0,0,0,100,0), -- 00:15:55
+(@PATH,15,-3384.879,3620.886,277.2273,0,0,0,0,100,0), -- 00:15:58
+(@PATH,16,-3382.095,3624.67,278.3322,0,0,0,0,100,0), -- 00:16:01
+(@PATH,17,-3381.752,3635.601,284.2187,0,0,0,0,100,0), -- 00:16:03
+(@PATH,18,-3379.75,3638.496,285.585,0,0,0,0,100,0), -- 00:16:08
+(@PATH,19,-3376.617,3642.928,285.1052,0,0,0,0,100,0), -- 00:16:12
+(@PATH,20,-3372.458,3645.933,284.7447,0,0,0,0,100,0); -- 00:16:13
+-- 0x1C011842401672C000002500008BC617 .go -3376.641 3642.897 285.1084
diff --git a/sql/updates/world/2016_01_14_from_335_2016_01_08_03_world.sql b/sql/updates/world/2016_01_14_from_335_2016_01_08_03_world.sql
new file mode 100644
index 00000000000..2899c6e06eb
--- /dev/null
+++ b/sql/updates/world/2016_01_14_from_335_2016_01_08_03_world.sql
@@ -0,0 +1,3 @@
+--
+UPDATE `creature_template` SET `AIName`='SmartAI' WHERE `entry`=25968;
+DELETE FROM `creature` WHERE `id`=25801;
diff --git a/sql/updates/world/2016_01_14_from_335_2016_01_09_00_world.sql b/sql/updates/world/2016_01_14_from_335_2016_01_09_00_world.sql
new file mode 100644
index 00000000000..534e17ccb00
--- /dev/null
+++ b/sql/updates/world/2016_01_14_from_335_2016_01_09_00_world.sql
@@ -0,0 +1,16 @@
+--
+-- Enable Landmine Knockback Achievement by removing it from disables
+DELETE FROM `disables` WHERE `sourceType`= 4 AND `entry`= 5258;
+
+-- Insert missing Landmine Knockback Achievement criteria data
+DELETE FROM `achievement_criteria_data` WHERE `criteria_id`= 5258;
+INSERT INTO `achievement_criteria_data` (`criteria_id`, `type`, `value1`, `value2`, `ScriptName`) VALUES
+(5258,0,57064,0,'');
+
+-- Update description for the linked spells 54355 and 54402
+UPDATE `spell_linked_spell` SET `comment`= 'Trigger Detonation with Land Mine Knockback' WHERE `spell_trigger` = 54355;
+
+-- Insert spell script name for spell 57099
+DELETE FROM `spell_script_names` WHERE `ScriptName`='spell_gen_landmine_knockback_achievement';
+INSERT INTO `spell_script_names` (`spell_id`,`ScriptName`) VALUES
+(57099,'spell_gen_landmine_knockback_achievement');
diff --git a/sql/updates/world/2016_01_14_from_335_2016_01_10_00_world.sql b/sql/updates/world/2016_01_14_from_335_2016_01_10_00_world.sql
new file mode 100644
index 00000000000..83ed21c8489
--- /dev/null
+++ b/sql/updates/world/2016_01_14_from_335_2016_01_10_00_world.sql
@@ -0,0 +1,3 @@
+--
+UPDATE `creature_text` SET `text`='Windroc Matriarch lets loose a terrifying shriek.', `BroadcastTextId`=16149 WHERE `entry`=19055;
+UPDATE `smart_scripts` SET `action_type`=49, `action_param1`=0 WHERE `entryorguid`=1905500 AND `id`=3;
diff --git a/sql/updates/world/2016_01_14_from_335_2016_01_10_01_world.sql b/sql/updates/world/2016_01_14_from_335_2016_01_10_01_world.sql
new file mode 100644
index 00000000000..c79c157a1a1
--- /dev/null
+++ b/sql/updates/world/2016_01_14_from_335_2016_01_10_01_world.sql
@@ -0,0 +1,2 @@
+--
+UPDATE `creature_template` SET `unit_flags`=32832 WHERE `entry`= 18689;
diff --git a/sql/updates/world/2016_01_14_from_335_2016_01_10_02_world.sql b/sql/updates/world/2016_01_14_from_335_2016_01_10_02_world.sql
new file mode 100644
index 00000000000..eca8ef07849
--- /dev/null
+++ b/sql/updates/world/2016_01_14_from_335_2016_01_10_02_world.sql
@@ -0,0 +1,6 @@
+--
+UPDATE `creature_template` SET `AIName`='SmartAI', `ScriptName`='' WHERE `entry`=25623;
+DELETE FROM `smart_scripts` WHERE `entryorguid`=25623 AND `source_type`=0;
+INSERT INTO `smart_scripts` (`entryorguid`, `source_type`, `id`, `link`, `event_type`, `event_phase_mask`, `event_chance`, `event_flags`, `event_param1`, `event_param2`, `event_param3`, `event_param4`, `action_type`, `action_param1`, `action_param2`, `action_param3`, `action_param4`, `action_param5`, `action_param6`, `target_type`, `target_param1`, `target_param2`, `target_param3`, `target_x`, `target_y`, `target_z`, `target_o`, `comment`) VALUES
+(25623, 0, 0, 0, 0, 0, 100, 0, 3000, 5000, 4000, 6000, 11, 54185, 0, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0, 0, 'Harvest Collector - IC - Cast Claw Slash'),
+(25623, 0, 1, 0, 8, 0, 100, 0, 47166, 0, 0, 0, 41, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 'Harvest Collector - On spell hit - Despawn');
diff --git a/sql/updates/world/2016_01_14_from_335_2016_01_10_03_world.sql b/sql/updates/world/2016_01_14_from_335_2016_01_10_03_world.sql
new file mode 100644
index 00000000000..5ac352ffe10
--- /dev/null
+++ b/sql/updates/world/2016_01_14_from_335_2016_01_10_03_world.sql
@@ -0,0 +1,2 @@
+--
+UPDATE `smart_scripts` SET `action_param6`=2 WHERE `entryorguid`=-96556 AND `id`=0 AND `source_type`=0;
diff --git a/sql/updates/world/2016_01_14_from_335_2016_01_10_04_world.sql b/sql/updates/world/2016_01_14_from_335_2016_01_10_04_world.sql
new file mode 100644
index 00000000000..da6eed191ad
--- /dev/null
+++ b/sql/updates/world/2016_01_14_from_335_2016_01_10_04_world.sql
@@ -0,0 +1,11 @@
+--
+DELETE FROM `instance_template` WHERE `map` = 169;
+INSERT INTO `instance_template` (`map`, `parent`, `script`, `allowMount`) VALUES
+(169, 0, '', 0);
+
+DELETE FROM `game_tele` WHERE `id` IN (1425, 1426, 1427, 1428);
+INSERT INTO `game_tele` (`id`, `position_x`, `position_y`, `position_z`, `orientation`, `map`, `name`) VALUES
+(1425, -366.091, 3097.86, 92.317, 0.0487625, 169, 'EmeraldDream'),
+(1426, 2781.566406, 3006.763184, 23.221882, 0.5, 169, 'EmeraldStatue'),
+(1427, -2128.12, -1005.89, 132.213, 0.5, 169, 'VerdantFields'),
+(1428, 2732.93, -3319.63, 101.284, 0.5, 169, 'EmeraldForest');
diff --git a/sql/updates/world/2016_01_14_from_335_2016_01_10_05_world335.sql b/sql/updates/world/2016_01_14_from_335_2016_01_10_05_world335.sql
new file mode 100644
index 00000000000..7fb021cc9dd
--- /dev/null
+++ b/sql/updates/world/2016_01_14_from_335_2016_01_10_05_world335.sql
@@ -0,0 +1,21 @@
+DELETE FROM `conditions` WHERE `SourceTypeOrReferenceId` IN (19,20) AND `SourceEntry` IN (5066,5090,5091,5093,5094,5095,10373,10374);
+
+INSERT INTO `conditions` (`SourceTypeOrReferenceId`, `SourceGroup`, `SourceEntry`, `SourceId`, `ElseGroup`, `ConditionTypeOrReference`, `ConditionTarget`, `ConditionValue1`, `ConditionValue2`, `ConditionValue3`, `NegativeCondition`, `ErrorType`, `ErrorTextId`, `ScriptName`, `Comment`) VALUES
+(19, 0, 5066, 0, 0, 14, 0, 5092, 0, 0, 0, 0, 0, '', 'Call to Arms: The Plaguelands (Breadcrumb)'),
+(20, 0, 5066, 0, 0, 14, 0, 5092, 0, 0, 0, 0, 0, '', 'Call to Arms: The Plaguelands (Breadcrumb)'),
+(19, 0, 5090, 0, 0, 14, 0, 5092, 0, 0, 0, 0, 0, '', 'Call to Arms: The Plaguelands (Breadcrumb)'),
+(20, 0, 5090, 0, 0, 14, 0, 5092, 0, 0, 0, 0, 0, '', 'Call to Arms: The Plaguelands (Breadcrumb)'),
+(19, 0, 5091, 0, 0, 14, 0, 5092, 0, 0, 0, 0, 0, '', 'Call to Arms: The Plaguelands (Breadcrumb)'),
+(20, 0, 5091, 0, 0, 14, 0, 5092, 0, 0, 0, 0, 0, '', 'Call to Arms: The Plaguelands (Breadcrumb)'),
+(19, 0, 5093, 0, 0, 14, 0, 5096, 0, 0, 0, 0, 0, '', 'Call to Arms: The Plaguelands (Breadcrumb)'),
+(20, 0, 5093, 0, 0, 14, 0, 5096, 0, 0, 0, 0, 0, '', 'Call to Arms: The Plaguelands (Breadcrumb)'),
+(19, 0, 5094, 0, 0, 14, 0, 5096, 0, 0, 0, 0, 0, '', 'Call to Arms: The Plaguelands (Breadcrumb)'),
+(20, 0, 5094, 0, 0, 14, 0, 5096, 0, 0, 0, 0, 0, '', 'Call to Arms: The Plaguelands (Breadcrumb)'),
+(19, 0, 5095, 0, 0, 14, 0, 5096, 0, 0, 0, 0, 0, '', 'Call to Arms: The Plaguelands (Breadcrumb)'),
+(20, 0, 5095, 0, 0, 14, 0, 5096, 0, 0, 0, 0, 0, '', 'Call to Arms: The Plaguelands (Breadcrumb)'),
+(19, 0, 10373, 0, 0, 14, 0, 5092, 0, 0, 0, 0, 0, '', 'Call to Arms: The Plaguelands (Breadcrumb)'),
+(20, 0, 10373, 0, 0, 14, 0, 5092, 0, 0, 0, 0, 0, '', 'Call to Arms: The Plaguelands (Breadcrumb)'),
+(19, 0, 10374, 0, 0, 14, 0, 5096, 0, 0, 0, 0, 0, '', 'Call to Arms: The Plaguelands (Breadcrumb)'),
+(20, 0, 10374, 0, 0, 14, 0, 5096, 0, 0, 0, 0, 0, '', 'Call to Arms: The Plaguelands (Breadcrumb)');
+
+UPDATE `quest_template_addon` SET `NextQuestID`=0 WHERE `ID` IN (5066,5090,5091,5093,5094,5095,10373,10374);
diff --git a/sql/updates/world/2016_01_14_from_335_2016_01_12_00_world.sql b/sql/updates/world/2016_01_14_from_335_2016_01_12_00_world.sql
new file mode 100644
index 00000000000..8ed4099450b
--- /dev/null
+++ b/sql/updates/world/2016_01_14_from_335_2016_01_12_00_world.sql
@@ -0,0 +1,125 @@
+-- Susurrus
+-- Add sniffed gossip text to menu
+DELETE FROM `gossip_menu_option` WHERE `menu_id` = 7415;
+INSERT INTO `gossip_menu_option` (`menu_id`, `id`, `option_icon`, `option_text`, `OptionBroadcastTextID`, `option_id`, `npc_option_npcflag`, `action_menu_id`, `action_poi_id`, `box_coded`, `box_money`, `box_text`, `BoxBroadcastTextID`) VALUES
+(7415, 0, 0, 'I am ready to be flown down to the Exodar.',14010,1,1,0,0,0,0,'',0);
+
+DELETE FROM `npc_text` WHERE `ID` = 8955;
+INSERT INTO `npc_text` (`ID`, `text0_0`, `text0_1`, `BroadcastTextID0`, `lang0`, `Probability0`, `em0_0`, `em0_1`, `em0_2`, `em0_3`, `em0_4`, `em0_5`) VALUES
+(8955, 'Are you ready, $n?', '', 14012, 0, 1, 0, 0, 0, 0, 0, 0);
+
+-- Set second gossip in gossip menu
+DELETE FROM `gossip_menu` WHERE `entry` = 7415;
+INSERT INTO `gossip_menu` (`entry`, `text_id`) VALUES
+(7415, 8954),
+(7415, 8955);
+
+-- Migrate NPC to use SmartAI
+UPDATE `creature_template` SET `AIName` = 'SmartAI', `ScriptName` = '' WHERE `entry` = 17435;
+
+DELETE FROM `conditions` WHERE `SourceTypeOrReferenceId` IN (14, 15) AND `SourceGroup` = 7415;
+INSERT INTO `conditions` (`SourceTypeOrReferenceId`,`SourceGroup`,`SourceEntry`,`SourceId`,`ElseGroup`,`ConditionTypeOrReference`,`ConditionTarget`,`ConditionValue1`,`ConditionValue2`,`ConditionValue3`,`NegativeCondition`,`ErrorTextId`,`ScriptName`,`Comment`) VALUES
+(14,7415,8954,0,0,2,0,23843,1,0,1,0,'','Susurrus - Show gossip menu text if player does not have item 23843 in inventory'),
+(14,7415,8955,0,0,2,0,23843,1,0,0,0,'','Susurrus - Show gossip menu text if player has item 23843 in inventory'),
+(15,7415,0,0,0,2,0,23843,1,0,0,0,'','Susurrus - Show gossip option 0 if player has item 23843 in inventory');
+
+-- Create SmartAI for Susurrus
+DELETE FROM `smart_scripts` WHERE (source_type = 0 AND entryorguid = 17435);
+INSERT INTO `smart_scripts` (`entryorguid`, `source_type`, `id`, `link`, `event_type`, `event_phase_mask`, `event_chance`, `event_flags`, `event_param1`, `event_param2`, `event_param3`, `event_param4`, `action_type`, `action_param1`, `action_param2`, `action_param3`, `action_param4`, `action_param5`, `action_param6`, `target_type`, `target_param1`, `target_param2`, `target_param3`, `target_x`, `target_y`, `target_z`, `target_o`, `comment`) VALUES
+(17435,0,0,1,62,0,100,0,7415,0,0,0,11,32474,0,0,0,0,0,7,0,0,0,0,0,0,0,'Susurrus - On Gossip Option 0 Selected - Cast Spell 32474'),
+(17435,0,1,0,61,0,100,0,0,0,0,0,72,0,0,0,0,0,0,7,0,0,0,0,0,0,0,'Susurrus - On Linked Actions - Close Gossip');
+
+
+-- Protectorate Nether Drake
+-- Add sniffed gossip text to menu
+DELETE FROM `gossip_menu_option` WHERE `menu_id` = 8229;
+INSERT INTO `gossip_menu_option` (`menu_id`, `id`, `option_icon`, `option_text`, `OptionBroadcastTextID`, `option_id`, `npc_option_npcflag`, `action_menu_id`, `action_poi_id`, `box_coded`, `box_money`, `box_text`, `BoxBroadcastTextID`) VALUES
+(8229, 0, 0, 'I''m ready to fly! Take me up, dragon!',18637,1,1,0,0,0,0,'',0);
+
+-- Migrate NPC to use SmartAI
+UPDATE `creature_template` SET `AIName` = 'SmartAI', `ScriptName` = '' WHERE `entry` = 20903;
+
+DELETE FROM `conditions` WHERE `SourceTypeOrReferenceId` = 15 AND `SourceGroup` = 8229;
+INSERT INTO `conditions` (`SourceTypeOrReferenceId`,`SourceGroup`,`SourceEntry`,`SourceId`,`ElseGroup`,`ConditionTypeOrReference`,`ConditionTarget`,`ConditionValue1`,`ConditionValue2`,`ConditionValue3`,`NegativeCondition`,`ErrorTextId`,`ScriptName`,`Comment`) VALUES
+(15,8229,0,0,0,2,0,29778,1,0,0,0,'','Protectorate Nether Drake - Show gossip option 0 if player has item 23843 in inventory'),
+(15,8229,0,0,0,9,0,10438,0,0,0,0,'','Protectorate Nether Drake - Show gossip option 0 if player has quest 10438');
+-- Create SmartAI for Protectorate Nether Drake
+DELETE FROM `smart_scripts` WHERE (source_type = 0 AND entryorguid = 20903);
+INSERT INTO `smart_scripts` (`entryorguid`, `source_type`, `id`, `link`, `event_type`, `event_phase_mask`, `event_chance`, `event_flags`, `event_param1`, `event_param2`, `event_param3`, `event_param4`, `action_type`, `action_param1`, `action_param2`, `action_param3`, `action_param4`, `action_param5`, `action_param6`, `target_type`, `target_param1`, `target_param2`, `target_param3`, `target_x`, `target_y`, `target_z`, `target_o`, `comment`) VALUES
+(20903,0,0,1,62,0,100,0,8229,0,0,0,52,627,0,0,0,0,0,7,0,0,0,0,0,0,0,'Protectorate Nether Drake - On Gossip Option 0 Selected - Init Taxi Path 627'),
+(20903,0,1,0,61,0,100,0,0,0,0,0,72,0,0,0,0,0,0,7,0,0,0,0,0,0,0,'Protectorate Nether Drake - On Linked Actions - Close Gossip');
+
+
+-- Veronia
+-- Add sniffed gossip text to menu
+DELETE FROM `gossip_menu_option` WHERE `menu_id` = 8082;
+INSERT INTO `gossip_menu_option` (`menu_id`, `id`, `option_icon`, `option_text`, `OptionBroadcastTextID`, `option_id`, `npc_option_npcflag`, `action_menu_id`, `action_poi_id`, `box_coded`, `box_money`, `box_text`, `BoxBroadcastTextID`) VALUES
+(8082, 0, 0, 'I''m as ready as I''ll ever be.',17761,1,1,0,0,0,0,'',0);
+
+DELETE FROM `gossip_menu` WHERE `entry` = 8082;
+INSERT INTO `gossip_menu` (`entry`, `text_id`) VALUES
+(8082, 9989),
+(8082, 9990);
+
+-- Migrate NPC to use SmartAI
+UPDATE `creature_template` SET `AIName` = 'SmartAI', `ScriptName` = '' WHERE `entry` = 20162;
+
+DELETE FROM `conditions` WHERE `SourceTypeOrReferenceId` IN (14,15) AND `SourceGroup` = 8082;
+INSERT INTO `conditions` (`SourceTypeOrReferenceId`,`SourceGroup`,`SourceEntry`,`SourceId`,`ElseGroup`,`ConditionTypeOrReference`,`ConditionTarget`,`ConditionValue1`,`ConditionValue2`,`ConditionValue3`,`NegativeCondition`,`ErrorTextId`,`ScriptName`,`Comment`) VALUES
+(14,8082,9989,0,0,28,0,10652,0,0,1,0,'','Veronia - Show gossip menu text if player does not have quest 10652'),
+(14,8082,9990,0,0,28,0,10652,0,0,0,0,'','Veronia - Show gossip menu text if player has quest 10652'),
+(15,8082,0,0,0,28,0,10652,0,0,0,0,'','Veronia - Show gossip option 0 if player has quest 10652');
+-- Create SmartAI for Veronia
+DELETE FROM `smart_scripts` WHERE (source_type = 0 AND entryorguid = 20162);
+INSERT INTO `smart_scripts` (`entryorguid`, `source_type`, `id`, `link`, `event_type`, `event_phase_mask`, `event_chance`, `event_flags`, `event_param1`, `event_param2`, `event_param3`, `event_param4`, `action_type`, `action_param1`, `action_param2`, `action_param3`, `action_param4`, `action_param5`, `action_param6`, `target_type`, `target_param1`, `target_param2`, `target_param3`, `target_x`, `target_y`, `target_z`, `target_o`, `comment`) VALUES
+(20162,0,0,1,62,0,100,0,8082,0,0,0,85,34905,0,0,0,0,0,7,0,0,0,0,0,0,0,'Veronia - On Gossip Option 0 Selected - Invoker Cast \'Stealth Flight\''),
+(20162,0,1,0,61,0,100,0,0,0,0,0,72,0,0,0,0,0,0,7,0,0,0,0,0,0,0,'Veronia - On Linked Actions - Close Gossip');
+
+
+-- Cassa Crimsonwing
+-- Add sniffed gossip text to menu
+DELETE FROM `gossip_menu_option` WHERE `menu_id` = 8782;
+INSERT INTO `gossip_menu_option` (`menu_id`, `id`, `option_icon`, `option_text`, `OptionBroadcastTextID`, `option_id`, `npc_option_npcflag`, `action_menu_id`, `action_poi_id`, `box_coded`, `box_money`, `box_text`, `BoxBroadcastTextID`) VALUES
+(8782, 0, 0, 'Lady Jaina told me to speak to you about using a gryphon to survey Alcaz Island.',22176,1,1,0,0,0,0,'',0);
+
+-- Migrate NPC to use SmartAI
+UPDATE `creature_template` SET `AIName` = 'SmartAI', `ScriptName` = '' WHERE `entry` = 23704;
+
+-- Condition: Gossip menu ID 0 needs quest ID 11142 to be incomplete.
+DELETE FROM `conditions` WHERE `SourceTypeOrReferenceId`= 15 AND `SourceGroup` = 8782 AND `SourceEntry` = 0;
+INSERT INTO `conditions` (`SourceTypeOrReferenceId`,`SourceGroup`,`SourceEntry`,`SourceId`,`ElseGroup`,`ConditionTypeOrReference`,`ConditionTarget`,`ConditionValue1`,`ConditionValue2`,`ConditionValue3`,`NegativeCondition`,`ErrorTextId`,`ScriptName`,`Comment`) VALUES
+(15,8782,0,0,0,9,0,11142,0,0,0,0,'','Cassa Crimsonwing - Show gossip option 0 if player has taken quest ID 11142');
+
+-- Create SmartAI for Cassa Crimsonwing
+DELETE FROM `smart_scripts` WHERE (source_type = 0 AND entryorguid = 23704);
+INSERT INTO `smart_scripts` (`entryorguid`, `source_type`, `id`, `link`, `event_type`, `event_phase_mask`, `event_chance`, `event_flags`, `event_param1`, `event_param2`, `event_param3`, `event_param4`, `action_type`, `action_param1`, `action_param2`, `action_param3`, `action_param4`, `action_param5`, `action_param6`, `target_type`, `target_param1`, `target_param2`, `target_param3`, `target_x`, `target_y`, `target_z`, `target_o`, `comment`) VALUES
+(23704,0,0,1,62,0,100,0,8782,0,0,0,11,42295,0,0,0,0,0,7,0,0,0,0,0,0,0,'Cassa Crimsonwing - On Gossip Option 0 Selected - Cast Spell 42295'),
+(23704,0,1,0,61,0,100,0,0,0,0,0,72,0,0,0,0,0,0,7,0,0,0,0,0,0,0,'Cassa Crimsonwing - On Linked Actions - Close Gossip');
+
+
+-- Brazen
+-- Add sniffed gossip text to menu
+DELETE FROM `gossip_menu_option` WHERE `menu_id` = 7959;
+INSERT INTO `gossip_menu_option` (`menu_id`, `id`, `option_icon`, `option_text`, `OptionBroadcastTextID`, `option_id`, `npc_option_npcflag`, `action_menu_id`, `action_poi_id`, `box_coded`, `box_money`, `box_text`, `BoxBroadcastTextID`) VALUES
+(7959, 0, 0, 'I''m ready to go to Durnholde Keep.',16461,1,1,0,0,0,0,'',0);
+
+DELETE FROM `gossip_menu` WHERE `entry` = 7959;
+INSERT INTO `gossip_menu` (`entry`, `text_id`) VALUES
+(7959, 9779),
+(7959, 9780);
+
+UPDATE `creature_template` SET `AIName` = 'SmartAI', `ScriptName` = '' WHERE `entry` = 18725;
+
+-- Condition: On gossip menu click, if item exists, perform linked action
+-- Condition: On gossip menu click, if item exists, perform linked action
+DELETE FROM `conditions` WHERE `SourceTypeOrReferenceId`IN (14, 15) AND `SourceGroup` = 7959;
+INSERT INTO `conditions` (`SourceTypeOrReferenceId`,`SourceGroup`,`SourceEntry`,`SourceId`,`ElseGroup`,`ConditionTypeOrReference`,`ConditionTarget`,`ConditionValue1`,`ConditionValue2`,`ConditionValue3`,`NegativeCondition`,`ErrorTextId`,`ScriptName`,`Comment`) VALUES
+(14,7959,9779,0,0,2,0,25853,1,0,0,0,'','Brazen - Show gossip menu text if player has item 25853'),
+(14,7959,9780,0,0,2,0,25853,1,0,1,0,'','Brazen - Show gossip menu text if player does not have item 25853'),
+(15,7959,0,0,0,2,0,25853,1,0,0,0,'','Brazen - Show gossip option 0 if player has item 25853');
+
+-- Create SmartAI for Brazen
+DELETE FROM `smart_scripts` WHERE (source_type = 0 AND entryorguid = 18725);
+INSERT INTO `smart_scripts` (`entryorguid`, `source_type`, `id`, `link`, `event_type`, `event_phase_mask`, `event_chance`, `event_flags`, `event_param1`, `event_param2`, `event_param3`, `event_param4`, `action_type`, `action_param1`, `action_param2`, `action_param3`, `action_param4`, `action_param5`, `action_param6`, `target_type`, `target_param1`, `target_param2`, `target_param3`, `target_x`, `target_y`, `target_z`, `target_o`, `comment`) VALUES
+(18725,0,0,1,62,0,100,0,7959,0,0,0,52,534,0,0,0,0,0,7,0,0,0,0,0,0,0,'Brazen - On Gossip Option 0 Selected - Activate Taxi Path 534'),
+(18725,0,1,0,61,0,100,0,0,0,0,0,72,0,0,0,0,0,0,7,0,0,0,0,0,0,0,'Brazen - On Linked Actions - Close Gossip');
diff --git a/sql/updates/world/2016_01_14_from_335_2016_01_12_01_world335.sql b/sql/updates/world/2016_01_14_from_335_2016_01_12_01_world335.sql
new file mode 100644
index 00000000000..c3206e70ac4
--- /dev/null
+++ b/sql/updates/world/2016_01_14_from_335_2016_01_12_01_world335.sql
@@ -0,0 +1,5 @@
+-- Insert missing gossip_menu_option 21213 for Sorcerer Ashcrombe and 21214 for Deathstalker Adamant:
+DELETE FROM `gossip_menu_option` WHERE `menu_id` IN (21213,21214) AND `OptionBroadcastTextID`= 2802;
+INSERT INTO `gossip_menu_option` (`menu_id`,`id`,`option_icon`,`option_text`,`OptionBroadcastTextID`,`option_id`,`npc_option_npcflag`,`action_menu_id`,`action_poi_id`,`box_coded`,`box_money`,`box_text`,`BoxBroadcastTextID`) VALUES
+(21213,0,0,'Please unlock the courtyard door.',2802,1,1,0,0,0,0,'',0),
+(21214,0,0,'Please unlock the courtyard door.',2802,1,1,0,0,0,0,'',0);
diff --git a/sql/updates/world/2016_01_14_from_335_2016_01_12_02_world335.sql b/sql/updates/world/2016_01_14_from_335_2016_01_12_02_world335.sql
new file mode 100644
index 00000000000..354d0bc129d
--- /dev/null
+++ b/sql/updates/world/2016_01_14_from_335_2016_01_12_02_world335.sql
@@ -0,0 +1,4 @@
+-- Insert missing gossip_menu_option 3801 for Myranda the Hag:
+DELETE FROM `gossip_menu_option` WHERE `menu_id`= 3801 AND `OptionBroadcastTextID`= 7306;
+INSERT INTO `gossip_menu_option` (`menu_id`,`id`,`option_icon`,`option_text`,`OptionBroadcastTextID`,`option_id`,`npc_option_npcflag`,`action_menu_id`,`action_poi_id`,`box_coded`,`box_money`,`box_text`,`BoxBroadcastTextID`) VALUES
+(3801,0,0,'I am ready for the illusion, Myranda.',7306,2,3,0,0,0,0,'',0);
diff --git a/sql/updates/world/2016_01_14_from_335_2016_01_12_03_world.sql b/sql/updates/world/2016_01_14_from_335_2016_01_12_03_world.sql
new file mode 100644
index 00000000000..6ff3a769918
--- /dev/null
+++ b/sql/updates/world/2016_01_14_from_335_2016_01_12_03_world.sql
@@ -0,0 +1,15 @@
+UPDATE `creature_template` SET `AIName`='SmartAI' WHERE `entry`=32820;
+DELETE FROM `smart_scripts` WHERE `source_type`=0 AND `entryorguid`=32820;
+INSERT INTO `smart_scripts` (`entryorguid`,`source_type`,`id`,`link`,`event_type`,`event_phase_mask`,`event_chance`,`event_flags`,`event_param1`,`event_param2`,`event_param3`,`event_param4`,`action_type`,`action_param1`,`action_param2`,`action_param3`,`action_param4`,`action_param5`,`action_param6`,`target_type`,`target_param1`,`target_param2`,`target_param3`,`target_x`,`target_y`,`target_z`,`target_o`,`comment`) VALUES
+(32820,0,0,0,6,0,100,0,0,0,0,0,11,62014,2,0,0,0,0,7,0,0,0,0,0,0,0,"Wild Turkey - On Just Died - Cast 'Turkey Tracker'");
+
+DELETE FROM `creature_text` WHERE `entry`=32820;
+INSERT INTO `creature_text` (`entry`,`groupid`,`id`,`text`,`type`,`language`,`probability`,`emote`,`duration`,`sound`,`BroadcastTextId`,`TextRange`,`comment`) VALUES
+(32820,0,0,'Turkey Hunter!',42,0,100,0,0,0,33163,0,'Wild Turkey'),
+(32820,1,0,'Turkey Domination!',42,0,100,0,0,0,33164,0,'Wild Turkey'),
+(32820,2,0,'Turkey Slaughter!',42,0,100,0,0,0,33165,0,'Wild Turkey'),
+(32820,3,0,'TURKEY TRIUMPH!',42,0,100,0,0,0,33167,0,'Wild Turkey');
+
+DELETE FROM `spell_script_names` WHERE `ScriptName`='spell_pilgrims_bounty_turkey_tracker';
+INSERT INTO `spell_script_names` (`spell_id`,`ScriptName`) VALUES
+(62014,'spell_pilgrims_bounty_turkey_tracker');
diff --git a/sql/updates/world/2016_01_14_from_335_2016_01_12_04_world.sql b/sql/updates/world/2016_01_14_from_335_2016_01_12_04_world.sql
new file mode 100644
index 00000000000..7cee9220060
--- /dev/null
+++ b/sql/updates/world/2016_01_14_from_335_2016_01_12_04_world.sql
@@ -0,0 +1,14 @@
+SET @OGUID:=79521;
+SET @CGUID:=52265;
+SET @Event:=2;
+
+DELETE FROM `gameobject` WHERE `guid` IN (@OGUID+0);
+INSERT INTO `gameobject` (`guid`, `id`, `map`, `spawnMask`, `phaseMask`, `position_x`, `position_y`, `position_z`, `orientation`, `rotation0`, `rotation1`, `rotation2`, `rotation3`, `spawntimesecs`, `animprogress`, `state`) VALUES
+(@OGUID+0, 187567, 530, 1, 1, -690.7932, 2724.943, 100.9289, 6.265733, 0, 0, 0, 1, 120, 255, 1); -- 187567 (Area: 3483)
+
+DELETE FROM `game_event_gameobject` WHERE `guid` IN (@OGUID+0);
+INSERT INTO `game_event_gameobject` (`eventEntry`, `guid`) VALUES
+(@Event, @OGUID+0);
+
+DELETE FROM `game_event_creature` WHERE `guid` BETWEEN @CGUID+0 AND @CGUID+4 AND `eventEntry`=@Event;
+INSERT INTO `game_event_creature` SELECT @Event, creature.guid FROM `creature` WHERE creature.guid BETWEEN @CGUID+0 AND @CGUID+4;
diff --git a/sql/updates/world/2016_01_14_from_335_2016_01_13_00_world.sql b/sql/updates/world/2016_01_14_from_335_2016_01_13_00_world.sql
new file mode 100644
index 00000000000..cba5d3a18a1
--- /dev/null
+++ b/sql/updates/world/2016_01_14_from_335_2016_01_13_00_world.sql
@@ -0,0 +1,10 @@
+--
+DELETE FROM `command` WHERE `permission`=836;
+INSERT INTO `command` (`name`,`permission`,`help`) VALUES ("debug boundary",836,"Syntax: .debug boundary [fill] [duration]
+Flood fills the targeted unit's movement boundary and marks the edge of said boundary with debug creatures.\nSpecify 'fill' as first parameter to fill the entire area with debug creatures.");
+
+DELETE FROM `trinity_string` WHERE `entry` IN (11011,11012,11013);
+INSERT INTO `trinity_string` (`entry`,`content_default`) VALUES
+(11011,"VisualizeBoundary warning: No interior point of the creature's boundary could be found - check if you have mutually exclusive boundaries!"),
+(11012,"VisualizeBoundary error: Creature movement is unbounded"),
+(11013,"VisualizeBoundary warning: Reached fail-safe flood boundary - check is your boundary is unbounded!");
diff --git a/src/common/CMakeLists.txt b/src/common/CMakeLists.txt
index 98075692476..8dee99c65e7 100644
--- a/src/common/CMakeLists.txt
+++ b/src/common/CMakeLists.txt
@@ -83,6 +83,8 @@ add_library(common STATIC
${common_STAT_PCH_SRC}
)
+add_dependencies(common revision_data.h)
+
# Generate precompiled header
if (USE_COREPCH)
add_cxx_pch(common ${common_STAT_PCH_HDR} ${common_STAT_PCH_SRC})
diff --git a/src/common/Collision/Management/MMapManager.cpp b/src/common/Collision/Management/MMapManager.cpp
index 2274e1a6980..ce1ff4e23fc 100644
--- a/src/common/Collision/Management/MMapManager.cpp
+++ b/src/common/Collision/Management/MMapManager.cpp
@@ -335,7 +335,7 @@ namespace MMAP
// if the grid is later reloaded, dtNavMesh::addTile will return error but no extra memory is used
// we cannot recover from this error - assert out
TC_LOG_ERROR("maps", "MMAP:unloadMap: Could not unload %03u%02i%02i.mmtile from navmesh", mapId, x, y);
- ASSERT(false);
+ ABORT();
}
else
{
diff --git a/src/common/Collision/Management/VMapManager2.cpp b/src/common/Collision/Management/VMapManager2.cpp
index 1c98a34bd67..bce16598389 100644
--- a/src/common/Collision/Management/VMapManager2.cpp
+++ b/src/common/Collision/Management/VMapManager2.cpp
@@ -326,4 +326,9 @@ namespace VMAP
return StaticMapTree::CanLoadMap(std::string(basePath), mapId, x, y);
}
+ void VMapManager2::getInstanceMapTree(InstanceTreeMap &instanceMapTree)
+ {
+ instanceMapTree = iInstanceMapTrees;
+ }
+
} // namespace VMAP
diff --git a/src/common/Collision/Management/VMapManager2.h b/src/common/Collision/Management/VMapManager2.h
index d2829582d9a..4125970f757 100644
--- a/src/common/Collision/Management/VMapManager2.h
+++ b/src/common/Collision/Management/VMapManager2.h
@@ -128,7 +128,7 @@ namespace VMAP
return getMapFileName(mapId);
}
virtual bool existsMap(const char* basePath, unsigned int mapId, int x, int y) override;
- public:
+
void getInstanceMapTree(InstanceTreeMap &instanceMapTree);
typedef uint32(*GetLiquidFlagsFn)(uint32 liquidType);
diff --git a/src/common/Collision/Maps/MapTree.cpp b/src/common/Collision/Maps/MapTree.cpp
index 8744a2242bc..4d0996e1961 100644
--- a/src/common/Collision/Maps/MapTree.cpp
+++ b/src/common/Collision/Maps/MapTree.cpp
@@ -474,4 +474,10 @@ namespace VMAP
}
iLoadedTiles.erase(tile);
}
+
+ void StaticMapTree::getModelInstances(ModelInstance* &models, uint32 &count)
+ {
+ models = iTreeValues;
+ count = iNTreeValues;
+ }
}
diff --git a/src/common/Collision/Models/ModelInstance.h b/src/common/Collision/Models/ModelInstance.h
index f308ee4e54c..d101630d1e9 100644
--- a/src/common/Collision/Models/ModelInstance.h
+++ b/src/common/Collision/Models/ModelInstance.h
@@ -70,12 +70,11 @@ namespace VMAP
void intersectPoint(const G3D::Vector3& p, AreaInfo &info) const;
bool GetLocationInfo(const G3D::Vector3& p, LocationInfo &info) const;
bool GetLiquidLevel(const G3D::Vector3& p, LocationInfo &info, float &liqHeight) const;
+ WorldModel* getWorldModel() { return iModel; }
protected:
G3D::Matrix3 iInvRot;
float iInvScale;
WorldModel* iModel;
- public:
- WorldModel* getWorldModel();
};
} // namespace VMAP
diff --git a/src/common/Collision/Models/WorldModel.cpp b/src/common/Collision/Models/WorldModel.cpp
index f92fece228e..96ee6d2d55c 100644
--- a/src/common/Collision/Models/WorldModel.cpp
+++ b/src/common/Collision/Models/WorldModel.cpp
@@ -249,6 +249,13 @@ namespace VMAP
return result;
}
+ void WmoLiquid::getPosInfo(uint32 &tilesX, uint32 &tilesY, G3D::Vector3 &corner) const
+ {
+ tilesX = iTilesX;
+ tilesY = iTilesY;
+ corner = iCorner;
+ }
+
// ===================== GroupModel ==================================
GroupModel::GroupModel(const GroupModel &other):
@@ -409,6 +416,13 @@ namespace VMAP
return 0;
}
+ void GroupModel::getMeshData(std::vector& outVertices, std::vector& outTriangles, WmoLiquid*& liquid)
+ {
+ outVertices = vertices;
+ outTriangles = triangles;
+ liquid = iLiquid;
+ }
+
// ===================== WorldModel ==================================
void WorldModel::setGroupModels(std::vector &models)
@@ -582,4 +596,9 @@ namespace VMAP
fclose(rf);
return result;
}
+
+ void WorldModel::getGroupModels(std::vector& outGroupModels)
+ {
+ outGroupModels = groupModels;
+ }
}
diff --git a/src/common/Collision/Models/WorldModel.h b/src/common/Collision/Models/WorldModel.h
index 2926a037415..39787f6c664 100644
--- a/src/common/Collision/Models/WorldModel.h
+++ b/src/common/Collision/Models/WorldModel.h
@@ -58,6 +58,7 @@ namespace VMAP
uint32 GetFileSize();
bool writeToFile(FILE* wf);
static bool readFromFile(FILE* rf, WmoLiquid* &liquid);
+ void getPosInfo(uint32 &tilesX, uint32 &tilesY, G3D::Vector3 &corner) const;
private:
WmoLiquid() : iTilesX(0), iTilesY(0), iCorner(), iType(0), iHeight(NULL), iFlags(NULL) { }
uint32 iTilesX; //!< number of tiles in x direction, each
@@ -66,8 +67,6 @@ namespace VMAP
uint32 iType; //!< liquid type
float *iHeight; //!< (tilesX + 1)*(tilesY + 1) height values
uint8 *iFlags; //!< info if liquid tile is used
- public:
- void getPosInfo(uint32 &tilesX, uint32 &tilesY, G3D::Vector3 &corner) const;
};
/*! holding additional info for WMO group files */
@@ -92,6 +91,7 @@ namespace VMAP
const G3D::AABox& GetBound() const { return iBound; }
uint32 GetMogpFlags() const { return iMogpFlags; }
uint32 GetWmoID() const { return iGroupWMOID; }
+ void getMeshData(std::vector& outVertices, std::vector& outTriangles, WmoLiquid*& liquid);
protected:
G3D::AABox iBound;
uint32 iMogpFlags;// 0x8 outdor; 0x2000 indoor
@@ -100,9 +100,8 @@ namespace VMAP
std::vector triangles;
BIH meshTree;
WmoLiquid* iLiquid;
- public:
- void getMeshData(std::vector &vertices, std::vector &triangles, WmoLiquid* &liquid);
};
+
/*! Holds a model (converted M2 or WMO) in its original coordinate space */
class WorldModel
{
@@ -117,12 +116,11 @@ namespace VMAP
bool GetLocationInfo(const G3D::Vector3 &p, const G3D::Vector3 &down, float &dist, LocationInfo &info) const;
bool writeFile(const std::string &filename);
bool readFile(const std::string &filename);
+ void getGroupModels(std::vector& outGroupModels);
protected:
uint32 RootWMOID;
std::vector groupModels;
BIH groupTree;
- public:
- void getGroupModels(std::vector &groupModels);
};
} // namespace VMAP
diff --git a/src/common/Common.h b/src/common/Common.h
index 8583ad8435c..940006e0a05 100644
--- a/src/common/Common.h
+++ b/src/common/Common.h
@@ -40,7 +40,9 @@
#include
#include
#include
+#include
#include
+
#include
#include "Debugging/Errors.h"
diff --git a/src/common/Debugging/Errors.cpp b/src/common/Debugging/Errors.cpp
index efa86352250..1ec66ff6d59 100644
--- a/src/common/Debugging/Errors.cpp
+++ b/src/common/Debugging/Errors.cpp
@@ -23,6 +23,17 @@
#include
#include
+/**
+ @file Errors.cpp
+
+ @brief This file contains definitions of functions used for reporting critical application errors
+
+ It is very important that (std::)abort is NEVER called in place of *((volatile int*)NULL) = 0;
+ Calling abort() on Windows does not invoke unhandled exception filters - a mechanism used by WheatyExceptionReport
+ to log crashes. exit(1) calls here are for static analysis tools to indicate that calling functions defined in this file
+ terminates the application.
+ */
+
namespace Trinity {
void Assert(char const* file, int line, char const* function, char const* message)
@@ -48,10 +59,15 @@ void Assert(char const* file, int line, char const* function, char const* messag
exit(1);
}
-void Fatal(char const* file, int line, char const* function, char const* message)
+void Fatal(char const* file, int line, char const* function, char const* message, ...)
{
- fprintf(stderr, "\n%s:%i in %s FATAL ERROR:\n %s\n",
- file, line, function, message);
+ va_list args;
+ va_start(args, message);
+
+ fprintf(stderr, "\n%s:%i in %s FATAL ERROR:\n ", file, line, function);
+ vfprintf(stderr, message, args);
+ fprintf(stderr, "\n");
+ fflush(stderr);
std::this_thread::sleep_for(std::chrono::seconds(10));
*((volatile int*)NULL) = 0;
@@ -72,4 +88,12 @@ void Warning(char const* file, int line, char const* function, char const* messa
file, line, function, message);
}
+void Abort(char const* file, int line, char const* function)
+{
+ fprintf(stderr, "\n%s:%i in %s ABORTED\n",
+ file, line, function);
+ *((volatile int*)NULL) = 0;
+ exit(1);
+}
+
} // namespace Trinity
diff --git a/src/common/Debugging/Errors.h b/src/common/Debugging/Errors.h
index a79e0815bf9..38e311a6b13 100644
--- a/src/common/Debugging/Errors.h
+++ b/src/common/Debugging/Errors.h
@@ -26,10 +26,12 @@ namespace Trinity
DECLSPEC_NORETURN void Assert(char const* file, int line, char const* function, char const* message) ATTR_NORETURN;
DECLSPEC_NORETURN void Assert(char const* file, int line, char const* function, char const* message, char const* format, ...) ATTR_NORETURN ATTR_PRINTF(5, 6);
- DECLSPEC_NORETURN void Fatal(char const* file, int line, char const* function, char const* message) ATTR_NORETURN;
+ DECLSPEC_NORETURN void Fatal(char const* file, int line, char const* function, char const* message, ...) ATTR_NORETURN ATTR_PRINTF(4, 5);
DECLSPEC_NORETURN void Error(char const* file, int line, char const* function, char const* message) ATTR_NORETURN;
+ DECLSPEC_NORETURN void Abort(char const* file, int line, char const* function) ATTR_NORETURN;
+
void Warning(char const* file, int line, char const* function, char const* message);
} // namespace Trinity
@@ -43,11 +45,13 @@ namespace Trinity
#endif
#define WPAssert(cond, ...) ASSERT_BEGIN do { if (!(cond)) Trinity::Assert(__FILE__, __LINE__, __FUNCTION__, #cond, ##__VA_ARGS__); } while(0) ASSERT_END
-#define WPFatal(cond, msg) ASSERT_BEGIN do { if (!(cond)) Trinity::Fatal(__FILE__, __LINE__, __FUNCTION__, (msg)); } while(0) ASSERT_END
+#define WPFatal(cond, ...) ASSERT_BEGIN do { if (!(cond)) Trinity::Fatal(__FILE__, __LINE__, __FUNCTION__, ##__VA_ARGS__); } while(0) ASSERT_END
#define WPError(cond, msg) ASSERT_BEGIN do { if (!(cond)) Trinity::Error(__FILE__, __LINE__, __FUNCTION__, (msg)); } while(0) ASSERT_END
#define WPWarning(cond, msg) ASSERT_BEGIN do { if (!(cond)) Trinity::Warning(__FILE__, __LINE__, __FUNCTION__, (msg)); } while(0) ASSERT_END
+#define WPAbort() ASSERT_BEGIN do { Trinity::Abort(__FILE__, __LINE__, __FUNCTION__); } while(0) ASSERT_END
#define ASSERT WPAssert
+#define ABORT WPAbort
template inline T* ASSERT_NOTNULL(T* pointer)
{
diff --git a/src/common/Debugging/WheatyExceptionReport.cpp b/src/common/Debugging/WheatyExceptionReport.cpp
index 7cf109b4070..5b9a1b1bd6c 100644
--- a/src/common/Debugging/WheatyExceptionReport.cpp
+++ b/src/common/Debugging/WheatyExceptionReport.cpp
@@ -63,6 +63,8 @@ std::stack WheatyExceptionReport::symbolDetails;
bool WheatyExceptionReport::stackOverflowException;
bool WheatyExceptionReport::alreadyCrashed;
std::mutex WheatyExceptionReport::alreadyCrashedLock;
+WheatyExceptionReport::pRtlGetVersion WheatyExceptionReport::RtlGetVersion;
+
// Declare global instance of class
WheatyExceptionReport g_WheatyExceptionReport;
@@ -76,6 +78,7 @@ WheatyExceptionReport::WheatyExceptionReport() // Constructor
m_hProcess = GetCurrentProcess();
stackOverflowException = false;
alreadyCrashed = false;
+ RtlGetVersion = (pRtlGetVersion)GetProcAddress(GetModuleHandle(_T("ntdll.dll")), "RtlGetVersion");
if (!IsDebuggerPresent())
{
_CrtSetReportMode(_CRT_ERROR, _CRTDBG_MODE_FILE);
@@ -207,21 +210,36 @@ BOOL WheatyExceptionReport::_GetProcessorName(TCHAR* sProcessorName, DWORD maxco
return TRUE;
}
+template
+void ToTchar(wchar_t const* src, TCHAR (&dst)[size], std::true_type)
+{
+ wcstombs_s(nullptr, dst, src, size);
+}
+
+template
+void ToTchar(wchar_t const* src, TCHAR (&dst)[size], std::false_type)
+{
+ wcscpy_s(dst, src);
+}
+
BOOL WheatyExceptionReport::_GetWindowsVersion(TCHAR* szVersion, DWORD cntMax)
{
// Try calling GetVersionEx using the OSVERSIONINFOEX structure.
// If that fails, try using the OSVERSIONINFO structure.
- OSVERSIONINFOEX osvi = { 0 };
- osvi.dwOSVersionInfoSize = sizeof(OSVERSIONINFOEX);
- BOOL bOsVersionInfoEx;
- bOsVersionInfoEx = ::GetVersionEx((LPOSVERSIONINFO)(&osvi));
- if (!bOsVersionInfoEx)
+ RTL_OSVERSIONINFOEXW osvi = { 0 };
+ osvi.dwOSVersionInfoSize = sizeof(RTL_OSVERSIONINFOEXW);
+ NTSTATUS bVersionEx = RtlGetVersion((PRTL_OSVERSIONINFOW)&osvi);
+ if (bVersionEx < 0)
{
- osvi.dwOSVersionInfoSize = sizeof(OSVERSIONINFO);
- if (!::GetVersionEx((OSVERSIONINFO*)&osvi))
+ osvi.dwOSVersionInfoSize = sizeof(RTL_OSVERSIONINFOW);
+ if (!RtlGetVersion((PRTL_OSVERSIONINFOW)&osvi))
return FALSE;
}
*szVersion = _T('\0');
+
+ TCHAR szCSDVersion[256];
+ ToTchar(osvi.szCSDVersion, szCSDVersion, std::is_same::type());
+
TCHAR wszTmp[128];
switch (osvi.dwPlatformId)
{
@@ -237,17 +255,28 @@ BOOL WheatyExceptionReport::_GetWindowsVersion(TCHAR* szVersion, DWORD cntMax)
#endif // WINVER < 0x0500
// Test for the specific product family.
- if (osvi.dwMajorVersion == 6)
+ if (osvi.dwMajorVersion == 10)
+ {
+ if (productType == VER_NT_WORKSTATION)
+ _tcsncat(szVersion, _T("Windows 10 "), cntMax);
+ else
+ _tcsncat(szVersion, _T("Windows Server 2016 "), cntMax);
+ }
+ else if (osvi.dwMajorVersion == 6)
{
if (productType == VER_NT_WORKSTATION)
{
- if (osvi.dwMinorVersion == 2)
+ if (osvi.dwMinorVersion == 3)
+ _tcsncat(szVersion, _T("Windows 8.1 "), cntMax);
+ else if (osvi.dwMinorVersion == 2)
_tcsncat(szVersion, _T("Windows 8 "), cntMax);
else if (osvi.dwMinorVersion == 1)
_tcsncat(szVersion, _T("Windows 7 "), cntMax);
else
_tcsncat(szVersion, _T("Windows Vista "), cntMax);
}
+ else if (osvi.dwMinorVersion == 3)
+ _tcsncat(szVersion, _T("Windows Server 2012 R2 "), cntMax);
else if (osvi.dwMinorVersion == 2)
_tcsncat(szVersion, _T("Windows Server 2012 "), cntMax);
else if (osvi.dwMinorVersion == 1)
@@ -265,7 +294,7 @@ BOOL WheatyExceptionReport::_GetWindowsVersion(TCHAR* szVersion, DWORD cntMax)
_tcsncat(szVersion, _T("Microsoft Windows NT "), cntMax);
// Test for specific product on Windows NT 4.0 SP6 and later.
- if (bOsVersionInfoEx)
+ if (bVersionEx >= 0)
{
// Test for the workstation type.
if (productType == VER_NT_WORKSTATION)
@@ -282,7 +311,18 @@ BOOL WheatyExceptionReport::_GetWindowsVersion(TCHAR* szVersion, DWORD cntMax)
// Test for the server type.
else if (productType == VER_NT_SERVER)
{
- if (osvi.dwMajorVersion == 5 && osvi.dwMinorVersion == 2)
+ if (osvi.dwMajorVersion == 6 || osvi.dwMajorVersion == 10)
+ {
+ if (suiteMask & VER_SUITE_SMALLBUSINESS_RESTRICTED)
+ _tcsncat(szVersion, _T("Essentials "), cntMax);
+ else if (suiteMask & VER_SUITE_DATACENTER)
+ _tcsncat(szVersion, _T("Datacenter "), cntMax);
+ else if (suiteMask & VER_SUITE_ENTERPRISE)
+ _tcsncat(szVersion, _T("Enterprise "), cntMax);
+ else
+ _tcsncat(szVersion, _T("Standard "), cntMax);
+ }
+ else if (osvi.dwMajorVersion == 5 && osvi.dwMinorVersion == 2)
{
if (suiteMask & VER_SUITE_DATACENTER)
_tcsncat(szVersion, _T("Datacenter Edition "), cntMax);
@@ -313,7 +353,7 @@ BOOL WheatyExceptionReport::_GetWindowsVersion(TCHAR* szVersion, DWORD cntMax)
}
// Display service pack (if any) and build number.
- if (osvi.dwMajorVersion == 4 && _tcsicmp(osvi.szCSDVersion, _T("Service Pack 6")) == 0)
+ if (osvi.dwMajorVersion == 4 && _tcsicmp(szCSDVersion, _T("Service Pack 6")) == 0)
{
HKEY hKey;
LONG lRet;
@@ -329,26 +369,26 @@ BOOL WheatyExceptionReport::_GetWindowsVersion(TCHAR* szVersion, DWORD cntMax)
else // Windows NT 4.0 prior to SP6a
{
_stprintf(wszTmp, _T("%s (Version %d.%d, Build %d)"),
- osvi.szCSDVersion, osvi.dwMajorVersion, osvi.dwMinorVersion, osvi.dwBuildNumber & 0xFFFF);
+ szCSDVersion, osvi.dwMajorVersion, osvi.dwMinorVersion, osvi.dwBuildNumber & 0xFFFF);
_tcsncat(szVersion, wszTmp, cntMax);
}
::RegCloseKey(hKey);
}
else // Windows NT 3.51 and earlier or Windows 2000 and later
{
- if (!_tcslen(osvi.szCSDVersion))
+ if (!_tcslen(szCSDVersion))
_stprintf(wszTmp, _T("(Version %d.%d, Build %d)"),
osvi.dwMajorVersion, osvi.dwMinorVersion, osvi.dwBuildNumber & 0xFFFF);
else
_stprintf(wszTmp, _T("%s (Version %d.%d, Build %d)"),
- osvi.szCSDVersion, osvi.dwMajorVersion, osvi.dwMinorVersion, osvi.dwBuildNumber & 0xFFFF);
+ szCSDVersion, osvi.dwMajorVersion, osvi.dwMinorVersion, osvi.dwBuildNumber & 0xFFFF);
_tcsncat(szVersion, wszTmp, cntMax);
}
break;
}
default:
_stprintf(wszTmp, _T("%s (Version %d.%d, Build %d)"),
- osvi.szCSDVersion, osvi.dwMajorVersion, osvi.dwMinorVersion, osvi.dwBuildNumber & 0xFFFF);
+ szCSDVersion, osvi.dwMajorVersion, osvi.dwMinorVersion, osvi.dwBuildNumber & 0xFFFF);
_tcsncat(szVersion, wszTmp, cntMax);
break;
}
diff --git a/src/common/Debugging/WheatyExceptionReport.h b/src/common/Debugging/WheatyExceptionReport.h
index 8c2479d5232..eb62d8bceef 100644
--- a/src/common/Debugging/WheatyExceptionReport.h
+++ b/src/common/Debugging/WheatyExceptionReport.h
@@ -3,6 +3,8 @@
#if PLATFORM == PLATFORM_WINDOWS && !defined(__MINGW32__)
+#include
+#include
#include
#include
#include
@@ -197,6 +199,8 @@ class WheatyExceptionReport
static bool stackOverflowException;
static bool alreadyCrashed;
static std::mutex alreadyCrashedLock;
+ typedef NTSTATUS(NTAPI* pRtlGetVersion)(PRTL_OSVERSIONINFOW lpVersionInformation);
+ static pRtlGetVersion RtlGetVersion;
static char* PushSymbolDetail(char* pszCurrBuffer);
static char* PopSymbolDetail(char* pszCurrBuffer);
diff --git a/src/common/Define.h b/src/common/Define.h
index 42076608023..dd10298f65c 100644
--- a/src/common/Define.h
+++ b/src/common/Define.h
@@ -33,6 +33,8 @@
# endif
# if defined(HELGRIND)
# include
+# undef _GLIBCXX_SYNCHRONIZATION_HAPPENS_BEFORE
+# undef _GLIBCXX_SYNCHRONIZATION_HAPPENS_AFTER
# define _GLIBCXX_SYNCHRONIZATION_HAPPENS_BEFORE(A) ANNOTATE_HAPPENS_BEFORE(A)
# define _GLIBCXX_SYNCHRONIZATION_HAPPENS_AFTER(A) ANNOTATE_HAPPENS_AFTER(A)
# endif
diff --git a/src/common/Utilities/Util.cpp b/src/common/Utilities/Util.cpp
index 91941dc0067..388e05a9bbb 100644
--- a/src/common/Utilities/Util.cpp
+++ b/src/common/Utilities/Util.cpp
@@ -58,6 +58,13 @@ uint32 urand(uint32 min, uint32 max)
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);
@@ -595,4 +602,4 @@ void HexStrToByteArray(std::string const& str, uint8* out, bool reverse /*= fals
char buffer[3] = { str[i], str[i + 1], '\0' };
out[j++] = strtoul(buffer, NULL, 16);
}
-}
\ No newline at end of file
+}
diff --git a/src/common/Utilities/Util.h b/src/common/Utilities/Util.h
index 46c131330f8..1a94b3e1672 100644
--- a/src/common/Utilities/Util.h
+++ b/src/common/Utilities/Util.h
@@ -82,6 +82,9 @@ 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();
@@ -539,7 +542,7 @@ bool CompareValues(ComparisionType type, T val1, T val2)
return val1 <= val2;
default:
// incorrect parameter
- ASSERT(false);
+ ABORT();
return false;
}
}
diff --git a/src/server/CMakeLists.txt b/src/server/CMakeLists.txt
index 32118db6a62..a427f9c238f 100644
--- a/src/server/CMakeLists.txt
+++ b/src/server/CMakeLists.txt
@@ -1,4 +1,4 @@
-# Copyright (C) 2008-2015 TrinityCore
+# Copyright (C) 2008-2016 TrinityCore
#
# This file is free software; as a special exception the author gives
# unlimited permission to copy and/or distribute it, with or without
diff --git a/src/server/authserver/Realms/RealmList.cpp b/src/server/authserver/Realms/RealmList.cpp
index db349438ddb..081610f2af9 100644
--- a/src/server/authserver/Realms/RealmList.cpp
+++ b/src/server/authserver/Realms/RealmList.cpp
@@ -180,7 +180,7 @@ void RealmList::UpdateRealms(bool init)
catch (std::exception& ex)
{
TC_LOG_ERROR("server.authserver", "Realmlist::UpdateRealms has thrown an exception: %s", ex.what());
- ASSERT(false);
+ ABORT();
}
}
while (result->NextRow());
diff --git a/src/server/authserver/Server/AuthSession.cpp b/src/server/authserver/Server/AuthSession.cpp
index 93ee2ea26d8..f3725383065 100644
--- a/src/server/authserver/Server/AuthSession.cpp
+++ b/src/server/authserver/Server/AuthSession.cpp
@@ -537,7 +537,7 @@ bool AuthSession::HandleLogonProof()
packet << uint8(3);
packet << uint8(0);
SendPacket(packet);
- return false;
+ return true;
}
}
@@ -585,7 +585,7 @@ bool AuthSession::HandleLogonProof()
uint32 MaxWrongPassCount = sConfigMgr->GetIntDefault("WrongPass.MaxCount", 0);
// We can not include the failed account login hook. However, this is a workaround to still log this.
- if (sConfigMgr->GetBoolDefault("Wrong.Password.Login.Logging", false))
+ if (sConfigMgr->GetBoolDefault("WrongPass.Logging", false))
{
PreparedStatement* logstmt = LoginDatabase.GetPreparedStatement(LOGIN_INS_FALP_IP_LOGGING);
logstmt->setString(0, _login);
diff --git a/src/server/authserver/authserver.conf.dist b/src/server/authserver/authserver.conf.dist
index 437ec221e94..604988d62e5 100644
--- a/src/server/authserver/authserver.conf.dist
+++ b/src/server/authserver/authserver.conf.dist
@@ -122,6 +122,14 @@ WrongPass.BanTime = 600
WrongPass.BanType = 0
+#
+# WrongPass.Logging
+# Description: Additionally log attempted wrong password logging
+# Default: 0 - (Disabled)
+# 1 - (Enabled)
+
+WrongPass.Logging = 0
+
#
###################################################################################################
@@ -148,13 +156,6 @@ LoginDatabaseInfo = "127.0.0.1;3306;trinity;trinity;auth"
LoginDatabase.WorkerThreads = 1
-#
-# Wrong.Password.Login.Logging
-# Description: Additionally log attempted wrong password logging
-# Default: 0 - (Disabled)
-# 1 - (Enabled)
-
-Wrong.Password.Login.Logging = 0
#
###################################################################################################
diff --git a/src/server/database/Database/DatabaseLoader.cpp b/src/server/database/Database/DatabaseLoader.cpp
index b54643298f0..92d8730cd12 100644
--- a/src/server/database/Database/DatabaseLoader.cpp
+++ b/src/server/database/Database/DatabaseLoader.cpp
@@ -37,14 +37,14 @@ DatabaseLoader& DatabaseLoader::AddDatabase(DatabaseWorkerPool& pool, std::st
std::string const dbString = sConfigMgr->GetStringDefault(name + "DatabaseInfo", "");
if (dbString.empty())
{
- TC_LOG_ERROR(_logger.c_str(), "Database %s not specified in configuration file!", name.c_str());
+ TC_LOG_ERROR(_logger, "Database %s not specified in configuration file!", name.c_str());
return false;
}
uint8 const asyncThreads = uint8(sConfigMgr->GetIntDefault(name + "Database.WorkerThreads", 1));
if (asyncThreads < 1 || asyncThreads > 32)
{
- TC_LOG_ERROR(_logger.c_str(), "%s database: invalid number of worker threads specified. "
+ TC_LOG_ERROR(_logger, "%s database: invalid number of worker threads specified. "
"Please pick a value between 1 and 32.", name.c_str());
return false;
}
@@ -66,7 +66,7 @@ DatabaseLoader& DatabaseLoader::AddDatabase(DatabaseWorkerPool& pool, std::st
if (error)
{
TC_LOG_ERROR("sql.driver", "\nDatabasePool %s NOT opened. There were errors opening the MySQL connections. Check your SQLDriverLogFile "
- "for specific errors. Read wiki at http://collab.kpsn.org/display/tc/TrinityCore+Home", name.c_str());
+ "for specific errors. Read wiki at http://www.trinitycore.info/display/tc/TrinityCore+Home", name.c_str());
return false;
}
@@ -85,7 +85,7 @@ DatabaseLoader& DatabaseLoader::AddDatabase(DatabaseWorkerPool& pool, std::st
{
if (!DBUpdater::Populate(pool))
{
- TC_LOG_ERROR(_logger.c_str(), "Could not populate the %s database, see log for details.", name.c_str());
+ TC_LOG_ERROR(_logger, "Could not populate the %s database, see log for details.", name.c_str());
return false;
}
return true;
@@ -95,7 +95,7 @@ DatabaseLoader& DatabaseLoader::AddDatabase(DatabaseWorkerPool& pool, std::st
{
if (!DBUpdater::Update(pool))
{
- TC_LOG_ERROR(_logger.c_str(), "Could not update the %s database, see log for details.", name.c_str());
+ TC_LOG_ERROR(_logger, "Could not update the %s database, see log for details.", name.c_str());
return false;
}
return true;
@@ -106,7 +106,7 @@ DatabaseLoader& DatabaseLoader::AddDatabase(DatabaseWorkerPool& pool, std::st
{
if (!pool.PrepareStatements())
{
- TC_LOG_ERROR(_logger.c_str(), "Could not prepare statements of the %s database, see log for details.", name.c_str());
+ TC_LOG_ERROR(_logger, "Could not prepare statements of the %s database, see log for details.", name.c_str());
return false;
}
return true;
diff --git a/src/server/database/Database/DatabaseWorkerPool.h b/src/server/database/Database/DatabaseWorkerPool.h
index 1e8e595afe7..d5a254647eb 100644
--- a/src/server/database/Database/DatabaseWorkerPool.h
+++ b/src/server/database/Database/DatabaseWorkerPool.h
@@ -67,6 +67,8 @@ class DatabaseWorkerPool
WPFatal(mysql_thread_safe(), "Used MySQL library isn't thread-safe.");
WPFatal(mysql_get_client_version() >= MIN_MYSQL_CLIENT_VERSION, "TrinityCore does not support MySQL versions below 5.1");
+ WPFatal(mysql_get_client_version() == MYSQL_VERSION_ID, "Used MySQL library version (%s) does not match the version used to compile TrinityCore (%s).",
+ mysql_get_client_info(), MYSQL_SERVER_VERSION);
}
~DatabaseWorkerPool()
@@ -484,7 +486,7 @@ class DatabaseWorkerPool
else if (type == IDX_SYNCH)
t = new T(*_connectionInfo);
else
- ASSERT(false);
+ ABORT();
_connections[type][i] = t;
++_connectionCount[type];
diff --git a/src/server/database/Database/Field.cpp b/src/server/database/Database/Field.cpp
index bcb2c1534ed..20a42871b91 100644
--- a/src/server/database/Database/Field.cpp
+++ b/src/server/database/Database/Field.cpp
@@ -30,18 +30,11 @@ Field::~Field()
CleanUp();
}
-void Field::SetByteValue(const void* newValue, const size_t newSize, enum_field_types newType, uint32 length)
+void Field::SetByteValue(void* newValue, enum_field_types newType, uint32 length)
{
- if (data.value)
- CleanUp();
-
// This value stores raw bytes that have to be explicitly cast later
- if (newValue)
- {
- data.value = new char[newSize];
- memcpy(data.value, newValue, newSize);
- data.length = length;
- }
+ data.value = newValue;
+ data.length = length;
data.type = newType;
data.raw = true;
}
diff --git a/src/server/database/Database/Field.h b/src/server/database/Database/Field.h
index ca91b5d6263..ec9e626ee1b 100644
--- a/src/server/database/Database/Field.h
+++ b/src/server/database/Database/Field.h
@@ -23,12 +23,44 @@
#include
+/**
+ @class Field
+
+ @brief Class used to access individual fields of database query result
+
+ Guideline on field type matching:
+
+ | MySQL type | method to use |
+ |------------------------|----------------------------------------|
+ | TINYINT | GetBool, GetInt8, GetUInt8 |
+ | SMALLINT | GetInt16, GetUInt16 |
+ | MEDIUMINT, INT | GetInt32, GetUInt32 |
+ | BIGINT | GetInt64, GetUInt64 |
+ | FLOAT | GetFloat |
+ | DOUBLE, DECIMAL | GetDouble |
+ | CHAR, VARCHAR, | GetCString, GetString |
+ | TINYTEXT, MEDIUMTEXT, | GetCString, GetString |
+ | TEXT, LONGTEXT | GetCString, GetString |
+ | TINYBLOB, MEDIUMBLOB, | GetBinary, GetString |
+ | BLOB, LONGBLOB | GetBinary, GetString |
+ | BINARY, VARBINARY | GetBinary |
+
+ Return types of aggregate functions:
+
+ | Function | Type |
+ |----------|-------------------|
+ | MIN, MAX | Same as the field |
+ | SUM, AVG | DECIMAL |
+ | COUNT | BIGINT |
+*/
class Field
{
friend class ResultSet;
friend class PreparedResultSet;
public:
+ Field();
+ ~Field();
bool GetBool() const // Wrapper, actually gets integer
{
@@ -43,7 +75,8 @@ class Field
#ifdef TRINITY_DEBUG
if (!IsType(MYSQL_TYPE_TINY))
{
- TC_LOG_WARN("sql.sql", "Warning: GetUInt8() on non-tinyint field. Using type: %s.", FieldTypeToString(data.type));
+ TC_LOG_WARN("sql.sql", "Warning: GetUInt8() on non-tinyint field %s.%s (%s.%s) at index %u. Using type: %s.",
+ meta.TableAlias, meta.Alias, meta.TableName, meta.Name, meta.Index, meta.Type);
return 0;
}
#endif
@@ -61,7 +94,8 @@ class Field
#ifdef TRINITY_DEBUG
if (!IsType(MYSQL_TYPE_TINY))
{
- TC_LOG_WARN("sql.sql", "Warning: GetInt8() on non-tinyint field. Using type: %s.", FieldTypeToString(data.type));
+ TC_LOG_WARN("sql.sql", "Warning: GetInt8() on non-tinyint field %s.%s (%s.%s) at index %u. Using type: %s.",
+ meta.TableAlias, meta.Alias, meta.TableName, meta.Name, meta.Index, meta.Type);
return 0;
}
#endif
@@ -79,7 +113,8 @@ class Field
#ifdef TRINITY_DEBUG
if (!IsType(MYSQL_TYPE_SHORT) && !IsType(MYSQL_TYPE_YEAR))
{
- TC_LOG_WARN("sql.sql", "Warning: GetUInt16() on non-smallint field. Using type: %s.", FieldTypeToString(data.type));
+ TC_LOG_WARN("sql.sql", "Warning: GetUInt16() on non-smallint field %s.%s (%s.%s) at index %u. Using type: %s.",
+ meta.TableAlias, meta.Alias, meta.TableName, meta.Name, meta.Index, meta.Type);
return 0;
}
#endif
@@ -97,7 +132,8 @@ class Field
#ifdef TRINITY_DEBUG
if (!IsType(MYSQL_TYPE_SHORT) && !IsType(MYSQL_TYPE_YEAR))
{
- TC_LOG_WARN("sql.sql", "Warning: GetInt16() on non-smallint field. Using type: %s.", FieldTypeToString(data.type));
+ TC_LOG_WARN("sql.sql", "Warning: GetInt16() on non-smallint field %s.%s (%s.%s) at index %u. Using type: %s.",
+ meta.TableAlias, meta.Alias, meta.TableName, meta.Name, meta.Index, meta.Type);
return 0;
}
#endif
@@ -115,7 +151,8 @@ class Field
#ifdef TRINITY_DEBUG
if (!IsType(MYSQL_TYPE_INT24) && !IsType(MYSQL_TYPE_LONG))
{
- TC_LOG_WARN("sql.sql", "Warning: GetUInt32() on non-(medium)int field. Using type: %s.", FieldTypeToString(data.type));
+ TC_LOG_WARN("sql.sql", "Warning: GetUInt32() on non-(medium)int field %s.%s (%s.%s) at index %u. Using type: %s.",
+ meta.TableAlias, meta.Alias, meta.TableName, meta.Name, meta.Index, meta.Type);
return 0;
}
#endif
@@ -133,7 +170,8 @@ class Field
#ifdef TRINITY_DEBUG
if (!IsType(MYSQL_TYPE_INT24) && !IsType(MYSQL_TYPE_LONG))
{
- TC_LOG_WARN("sql.sql", "Warning: GetInt32() on non-(medium)int field. Using type: %s.", FieldTypeToString(data.type));
+ TC_LOG_WARN("sql.sql", "Warning: GetInt32() on non-(medium)int field %s.%s (%s.%s) at index %u. Using type: %s.",
+ meta.TableAlias, meta.Alias, meta.TableName, meta.Name, meta.Index, meta.Type);
return 0;
}
#endif
@@ -151,7 +189,8 @@ class Field
#ifdef TRINITY_DEBUG
if (!IsType(MYSQL_TYPE_LONGLONG) && !IsType(MYSQL_TYPE_BIT))
{
- TC_LOG_WARN("sql.sql", "Warning: GetUInt64() on non-bigint field. Using type: %s.", FieldTypeToString(data.type));
+ TC_LOG_WARN("sql.sql", "Warning: GetUInt64() on non-bigint field %s.%s (%s.%s) at index %u. Using type: %s.",
+ meta.TableAlias, meta.Alias, meta.TableName, meta.Name, meta.Index, meta.Type);
return 0;
}
#endif
@@ -169,7 +208,8 @@ class Field
#ifdef TRINITY_DEBUG
if (!IsType(MYSQL_TYPE_LONGLONG) && !IsType(MYSQL_TYPE_BIT))
{
- TC_LOG_WARN("sql.sql", "Warning: GetInt64() on non-bigint field. Using type: %s.", FieldTypeToString(data.type));
+ TC_LOG_WARN("sql.sql", "Warning: GetInt64() on non-bigint field %s.%s (%s.%s) at index %u. Using type: %s.",
+ meta.TableAlias, meta.Alias, meta.TableName, meta.Name, meta.Index, meta.Type);
return 0;
}
#endif
@@ -187,7 +227,8 @@ class Field
#ifdef TRINITY_DEBUG
if (!IsType(MYSQL_TYPE_FLOAT))
{
- TC_LOG_WARN("sql.sql", "Warning: GetFloat() on non-float field. Using type: %s.", FieldTypeToString(data.type));
+ TC_LOG_WARN("sql.sql", "Warning: GetFloat() on non-float field %s.%s (%s.%s) at index %u. Using type: %s.",
+ meta.TableAlias, meta.Alias, meta.TableName, meta.Name, meta.Index, meta.Type);
return 0.0f;
}
#endif
@@ -203,14 +244,15 @@ class Field
return 0.0f;
#ifdef TRINITY_DEBUG
- if (!IsType(MYSQL_TYPE_DOUBLE))
+ if (!IsType(MYSQL_TYPE_DOUBLE) && !IsType(MYSQL_TYPE_NEWDECIMAL))
{
- TC_LOG_WARN("sql.sql", "Warning: GetDouble() on non-double field. Using type: %s.", FieldTypeToString(data.type));
+ TC_LOG_WARN("sql.sql", "Warning: GetDouble() on non-double/non-decimal field %s.%s (%s.%s) at index %u. Using type: %s.",
+ meta.TableAlias, meta.Alias, meta.TableName, meta.Name, meta.Index, meta.Type);
return 0.0f;
}
#endif
- if (data.raw)
+ if (data.raw && !IsType(MYSQL_TYPE_NEWDECIMAL))
return *reinterpret_cast(data.value);
return static_cast(atof((char*)data.value));
}
@@ -223,7 +265,8 @@ class Field
#ifdef TRINITY_DEBUG
if (IsNumeric())
{
- TC_LOG_WARN("sql.sql", "Error: GetCString() on numeric field. Using type: %s.", FieldTypeToString(data.type));
+ TC_LOG_WARN("sql.sql", "Error: GetCString() on numeric field %s.%s (%s.%s) at index %u. Using type: %s.",
+ meta.TableAlias, meta.Alias, meta.TableName, meta.Name, meta.Index, meta.Type);
return NULL;
}
#endif
@@ -236,14 +279,11 @@ class Field
if (!data.value)
return "";
- if (data.raw)
- {
- char const* string = GetCString();
- if (!string)
- string = "";
- return std::string(string, data.length);
- }
- return std::string((char*)data.value);
+ char const* string = GetCString();
+ if (!string)
+ return "";
+
+ return std::string(string, data.length);
}
bool IsNull() const
@@ -251,10 +291,17 @@ class Field
return data.value == NULL;
}
- protected:
- Field();
- ~Field();
+ struct Metadata
+ {
+ char const* TableName;
+ char const* TableAlias;
+ char const* Name;
+ char const* Alias;
+ char const* Type;
+ uint32 Index;
+ };
+ protected:
#pragma pack(push, 1)
struct
{
@@ -265,12 +312,14 @@ class Field
} data;
#pragma pack(pop)
- void SetByteValue(void const* newValue, size_t const newSize, enum_field_types newType, uint32 length);
+ void SetByteValue(void* newValue, enum_field_types newType, uint32 length);
void SetStructuredValue(char* newValue, enum_field_types newType);
void CleanUp()
{
- delete[] ((char*)data.value);
+ // Field does not own the data if fetched with prepared statement
+ if (!data.raw)
+ delete[] ((char*)data.value);
data.value = NULL;
}
@@ -375,6 +424,19 @@ class Field
default: return "-Unknown-";
}
}
+
+ void SetMetadata(MYSQL_FIELD* field, uint32 fieldIndex)
+ {
+ meta.TableName = field->org_table;
+ meta.TableAlias = field->table;
+ meta.Name = field->org_name;
+ meta.Alias = field->name;
+ meta.Type = FieldTypeToString(field->type);
+ meta.Index = fieldIndex;
+ }
+
+ Metadata meta;
+
#endif
};
diff --git a/src/server/database/Database/Implementation/CharacterDatabase.cpp b/src/server/database/Database/Implementation/CharacterDatabase.cpp
index 0a4c288d559..3885aa098b7 100644
--- a/src/server/database/Database/Implementation/CharacterDatabase.cpp
+++ b/src/server/database/Database/Implementation/CharacterDatabase.cpp
@@ -355,10 +355,11 @@ void CharacterDatabaseConnection::DoPrepareStatements()
PrepareStatement(CHAR_DEL_GO_RESPAWN_BY_INSTANCE, "DELETE FROM gameobject_respawn WHERE mapId = ? AND instanceId = ?", CONNECTION_ASYNC);
// GM Tickets
- PrepareStatement(CHAR_SEL_GM_TICKETS, "SELECT id, playerGuid, name, description, createTime, mapId, posX, posY, posZ, lastModifiedTime, closedBy, assignedTo, comment, response, completed, escalated, viewed, needMoreHelp FROM gm_ticket", CONNECTION_SYNCH);
- PrepareStatement(CHAR_REP_GM_TICKET, "REPLACE INTO gm_ticket (id, playerGuid, name, description, createTime, mapId, posX, posY, posZ, lastModifiedTime, closedBy, assignedTo, comment, response, completed, escalated, viewed, needMoreHelp) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)", CONNECTION_ASYNC);
+ PrepareStatement(CHAR_SEL_GM_TICKETS, "SELECT id, type, playerGuid, name, description, createTime, mapId, posX, posY, posZ, lastModifiedTime, closedBy, assignedTo, comment, response, completed, escalated, viewed, needMoreHelp FROM gm_ticket", CONNECTION_SYNCH);
+ PrepareStatement(CHAR_REP_GM_TICKET, "REPLACE INTO gm_ticket (id, type, playerGuid, name, description, createTime, mapId, posX, posY, posZ, lastModifiedTime, closedBy, assignedTo, comment, response, completed, escalated, viewed, needMoreHelp, resolvedBy) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)", CONNECTION_ASYNC);
PrepareStatement(CHAR_DEL_GM_TICKET, "DELETE FROM gm_ticket WHERE id = ?", CONNECTION_ASYNC);
PrepareStatement(CHAR_DEL_PLAYER_GM_TICKETS, "DELETE FROM gm_ticket WHERE playerGuid = ?", CONNECTION_ASYNC);
+ PrepareStatement(CHAR_UPD_PLAYER_GM_TICKETS_ON_CHAR_DELETION, "UPDATE gm_ticket SET type = 2 WHERE playerGuid = ?", CONNECTION_ASYNC);
// GM Survey/subsurvey/lag report
PrepareStatement(CHAR_INS_GM_SURVEY, "INSERT INTO gm_survey (guid, surveyId, mainSurvey, comment, createTime) VALUES (?, ?, ?, ?, UNIX_TIMESTAMP(NOW()))", CONNECTION_ASYNC);
@@ -637,7 +638,7 @@ void CharacterDatabaseConnection::DoPrepareStatements()
// PvPstats
PrepareStatement(CHAR_SEL_PVPSTATS_MAXID, "SELECT MAX(id) FROM pvpstats_battlegrounds", CONNECTION_SYNCH);
PrepareStatement(CHAR_INS_PVPSTATS_BATTLEGROUND, "INSERT INTO pvpstats_battlegrounds (id, winner_faction, bracket_id, type, date) VALUES (?, ?, ?, ?, NOW())", CONNECTION_ASYNC);
- PrepareStatement(CHAR_INS_PVPSTATS_PLAYER, "INSERT INTO pvpstats_players (battleground_id, character_guid, score_killing_blows, score_deaths, score_honorable_kills, score_bonus_honor, score_damage_done, score_healing_done, attr_1, attr_2, attr_3, attr_4, attr_5) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)", CONNECTION_ASYNC);
+ PrepareStatement(CHAR_INS_PVPSTATS_PLAYER, "INSERT INTO pvpstats_players (battleground_id, character_guid, winner, score_killing_blows, score_deaths, score_honorable_kills, score_bonus_honor, score_damage_done, score_healing_done, attr_1, attr_2, attr_3, attr_4, attr_5) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)", CONNECTION_ASYNC);
PrepareStatement(CHAR_SEL_PVPSTATS_FACTIONS_OVERALL, "SELECT winner_faction, COUNT(*) AS count FROM pvpstats_battlegrounds WHERE DATEDIFF(NOW(), date) < 7 GROUP BY winner_faction ORDER BY winner_faction ASC", CONNECTION_SYNCH);
// QuestTracker
@@ -645,4 +646,7 @@ void CharacterDatabaseConnection::DoPrepareStatements()
PrepareStatement(CHAR_UPD_QUEST_TRACK_GM_COMPLETE, "UPDATE quest_tracker SET completed_by_gm = 1 WHERE id = ? AND character_guid = ? ORDER BY quest_accept_time DESC LIMIT 1", CONNECTION_ASYNC);
PrepareStatement(CHAR_UPD_QUEST_TRACK_COMPLETE_TIME, "UPDATE quest_tracker SET quest_complete_time = NOW() WHERE id = ? AND character_guid = ? ORDER BY quest_accept_time DESC LIMIT 1", CONNECTION_ASYNC);
PrepareStatement(CHAR_UPD_QUEST_TRACK_ABANDON_TIME, "UPDATE quest_tracker SET quest_abandon_time = NOW() WHERE id = ? AND character_guid = ? ORDER BY quest_accept_time DESC LIMIT 1", CONNECTION_ASYNC);
+
+ // DeserterTracker
+ PrepareStatement(CHAR_INS_DESERTER_TRACK, "INSERT INTO battleground_deserters (guid, type, datetime) VALUES (?, ?, NOW())", CONNECTION_ASYNC);
}
diff --git a/src/server/database/Database/Implementation/CharacterDatabase.h b/src/server/database/Database/Implementation/CharacterDatabase.h
index a959a074ade..c6e9f01b897 100644
--- a/src/server/database/Database/Implementation/CharacterDatabase.h
+++ b/src/server/database/Database/Implementation/CharacterDatabase.h
@@ -304,6 +304,7 @@ enum CharacterDatabaseStatements
CHAR_DEL_GM_TICKET,
CHAR_DEL_ALL_GM_TICKETS,
CHAR_DEL_PLAYER_GM_TICKETS,
+ CHAR_UPD_PLAYER_GM_TICKETS_ON_CHAR_DELETION,
CHAR_INS_GM_SURVEY,
CHAR_INS_GM_SUBSURVEY,
@@ -560,6 +561,8 @@ enum CharacterDatabaseStatements
CHAR_UPD_QUEST_TRACK_COMPLETE_TIME,
CHAR_UPD_QUEST_TRACK_ABANDON_TIME,
+ CHAR_INS_DESERTER_TRACK,
+
MAX_CHARACTERDATABASE_STATEMENTS
};
diff --git a/src/server/database/Database/QueryResult.cpp b/src/server/database/Database/QueryResult.cpp
index f518b5db13f..f02457f67ca 100644
--- a/src/server/database/Database/QueryResult.cpp
+++ b/src/server/database/Database/QueryResult.cpp
@@ -26,7 +26,10 @@ _result(result),
_fields(fields)
{
_currentRow = new Field[_fieldCount];
- ASSERT(_currentRow);
+#ifdef TRINITY_DEBUG
+ for (uint32 i = 0; i < _fieldCount; i++)
+ _currentRow[i].SetMetadata(&_fields[i], i);
+#endif
}
PreparedResultSet::PreparedResultSet(MYSQL_STMT* stmt, MYSQL_RES *result, uint64 rowCount, uint32 fieldCount) :
@@ -35,11 +38,11 @@ m_rowPosition(0),
m_fieldCount(fieldCount),
m_rBind(NULL),
m_stmt(stmt),
-m_res(result),
+m_metadataResult(result),
m_isNull(NULL),
m_length(NULL)
{
- if (!m_res)
+ if (!m_metadataResult)
return;
if (m_stmt->bind_result_done)
@@ -66,50 +69,52 @@ m_length(NULL)
return;
}
- //- This is where we prepare the buffer based on metadata
- uint32 i = 0;
- MYSQL_FIELD* field = mysql_fetch_field(m_res);
- while (field)
- {
- size_t size = Field::SizeForType(field);
+ m_rowCount = mysql_stmt_num_rows(m_stmt);
- m_rBind[i].buffer_type = field->type;
- m_rBind[i].buffer = malloc(size);
- memset(m_rBind[i].buffer, 0, size);
+ //- This is where we prepare the buffer based on metadata
+ MYSQL_FIELD* field = mysql_fetch_fields(m_metadataResult);
+ std::size_t rowSize = 0;
+ for (uint32 i = 0; i < m_fieldCount; ++i)
+ {
+ size_t size = Field::SizeForType(&field[i]);
+ rowSize += size;
+
+ m_rBind[i].buffer_type = field[i].type;
m_rBind[i].buffer_length = size;
m_rBind[i].length = &m_length[i];
m_rBind[i].is_null = &m_isNull[i];
m_rBind[i].error = NULL;
- m_rBind[i].is_unsigned = field->flags & UNSIGNED_FLAG;
+ m_rBind[i].is_unsigned = field[i].flags & UNSIGNED_FLAG;
+ }
- ++i;
- field = mysql_fetch_field(m_res);
+ char* dataBuffer = new char[rowSize * m_rowCount];
+ for (uint32 i = 0, offset = 0; i < m_fieldCount; ++i)
+ {
+ m_rBind[i].buffer = dataBuffer + offset;
+ offset += m_rBind[i].buffer_length;
}
//- This is where we bind the bind the buffer to the statement
if (mysql_stmt_bind_result(m_stmt, m_rBind))
{
TC_LOG_WARN("sql.sql", "%s:mysql_stmt_bind_result, cannot bind result from MySQL server. Error: %s", __FUNCTION__, mysql_stmt_error(m_stmt));
- delete[] m_rBind;
+ mysql_stmt_free_result(m_stmt);
+ CleanUp();
delete[] m_isNull;
delete[] m_length;
return;
}
- m_rowCount = mysql_stmt_num_rows(m_stmt);
-
- m_rows.resize(uint32(m_rowCount));
+ m_rows.resize(uint32(m_rowCount) * m_fieldCount);
while (_NextRow())
{
- m_rows[uint32(m_rowPosition)] = new Field[m_fieldCount];
- for (uint64 fIndex = 0; fIndex < m_fieldCount; ++fIndex)
+ for (uint32 fIndex = 0; fIndex < m_fieldCount; ++fIndex)
{
+ unsigned long buffer_length = m_rBind[fIndex].buffer_length;
+ unsigned long fetched_length = *m_rBind[fIndex].length;
if (!*m_rBind[fIndex].is_null)
- m_rows[uint32(m_rowPosition)][fIndex].SetByteValue(m_rBind[fIndex].buffer,
- m_rBind[fIndex].buffer_length,
- m_rBind[fIndex].buffer_type,
- *m_rBind[fIndex].length);
- else
+ {
+ void* buffer = m_stmt->bind[fIndex].buffer;
switch (m_rBind[fIndex].buffer_type)
{
case MYSQL_TYPE_TINY_BLOB:
@@ -118,24 +123,44 @@ m_length(NULL)
case MYSQL_TYPE_BLOB:
case MYSQL_TYPE_STRING:
case MYSQL_TYPE_VAR_STRING:
- m_rows[uint32(m_rowPosition)][fIndex].SetByteValue("",
- m_rBind[fIndex].buffer_length,
- m_rBind[fIndex].buffer_type,
- *m_rBind[fIndex].length);
- break;
+ // warning - the string will not be null-terminated if there is no space for it in the buffer
+ // when mysql_stmt_fetch returned MYSQL_DATA_TRUNCATED
+ // we cannot blindly null-terminate the data either as it may be retrieved as binary blob and not specifically a string
+ // in this case using Field::GetCString will result in garbage
+ // TODO: remove Field::GetCString and use boost::string_ref (currently proposed for TS as string_view, maybe in C++17)
+ if (fetched_length < buffer_length)
+ *((char*)buffer + fetched_length) = '\0';
+ break;
default:
- m_rows[uint32(m_rowPosition)][fIndex].SetByteValue(nullptr,
- m_rBind[fIndex].buffer_length,
- m_rBind[fIndex].buffer_type,
- *m_rBind[fIndex].length);
+ break;
}
+
+ m_rows[uint32(m_rowPosition) * m_fieldCount + fIndex].SetByteValue(
+ buffer,
+ m_rBind[fIndex].buffer_type,
+ fetched_length);
+
+ // move buffer pointer to next part
+ m_stmt->bind[fIndex].buffer = (char*)buffer + rowSize;
+ }
+ else
+ {
+ m_rows[uint32(m_rowPosition) * m_fieldCount + fIndex].SetByteValue(
+ nullptr,
+ m_rBind[fIndex].buffer_type,
+ *m_rBind[fIndex].length);
+ }
+
+#ifdef TRINITY_DEBUG
+ m_rows[uint32(m_rowPosition) * m_fieldCount + fIndex].SetMetadata(&field[fIndex], fIndex);
+#endif
}
m_rowPosition++;
}
m_rowPosition = 0;
/// All data is buffered, let go of mysql c api structures
- CleanUp();
+ mysql_stmt_free_result(m_stmt);
}
ResultSet::~ResultSet()
@@ -145,8 +170,7 @@ ResultSet::~ResultSet()
PreparedResultSet::~PreparedResultSet()
{
- for (uint32 i = 0; i < uint32(m_rowCount); ++i)
- delete[] m_rows[i];
+ CleanUp();
}
bool ResultSet::NextRow()
@@ -207,18 +231,13 @@ void ResultSet::CleanUp()
void PreparedResultSet::CleanUp()
{
- /// More of the in our code allocated sources are deallocated by the poorly documented mysql c api
- if (m_res)
- mysql_free_result(m_res);
+ if (m_metadataResult)
+ mysql_free_result(m_metadataResult);
- FreeBindBuffer();
- mysql_stmt_free_result(m_stmt);
-
- delete[] m_rBind;
-}
-
-void PreparedResultSet::FreeBindBuffer()
-{
- for (uint32 i = 0; i < m_fieldCount; ++i)
- free (m_rBind[i].buffer);
+ if (m_rBind)
+ {
+ delete[](char*)m_rBind->buffer;
+ delete[] m_rBind;
+ m_rBind = nullptr;
+ }
}
diff --git a/src/server/database/Database/QueryResult.h b/src/server/database/Database/QueryResult.h
index b561b32afbb..d4d63b5ec85 100644
--- a/src/server/database/Database/QueryResult.h
+++ b/src/server/database/Database/QueryResult.h
@@ -73,18 +73,18 @@ class PreparedResultSet
Field* Fetch() const
{
ASSERT(m_rowPosition < m_rowCount);
- return m_rows[uint32(m_rowPosition)];
+ return const_cast(&m_rows[uint32(m_rowPosition) * m_fieldCount]);
}
- const Field & operator [] (uint32 index) const
+ Field const& operator[](uint32 index) const
{
ASSERT(m_rowPosition < m_rowCount);
ASSERT(index < m_fieldCount);
- return m_rows[uint32(m_rowPosition)][index];
+ return m_rows[uint32(m_rowPosition) * m_fieldCount + index];
}
protected:
- std::vector m_rows;
+ std::vector m_rows;
uint64 m_rowCount;
uint64 m_rowPosition;
uint32 m_fieldCount;
@@ -92,12 +92,11 @@ class PreparedResultSet
private:
MYSQL_BIND* m_rBind;
MYSQL_STMT* m_stmt;
- MYSQL_RES* m_res;
+ MYSQL_RES* m_metadataResult; ///< Field metadata, returned by mysql_stmt_result_metadata
my_bool* m_isNull;
unsigned long* m_length;
- void FreeBindBuffer();
void CleanUp();
bool _NextRow();
diff --git a/src/server/database/Updater/DBUpdater.cpp b/src/server/database/Updater/DBUpdater.cpp
index 42c2f53b0f4..170954a86f4 100644
--- a/src/server/database/Updater/DBUpdater.cpp
+++ b/src/server/database/Updater/DBUpdater.cpp
@@ -26,6 +26,8 @@
#include
#include
#include
+#include
+#include
#include
#include
@@ -33,6 +35,56 @@ using namespace boost::process;
using namespace boost::process::initializers;
using namespace boost::iostreams;
+std::string DBUpdaterUtil::GetMySqlCli()
+{
+ if (!corrected_path().empty())
+ return corrected_path();
+ else
+ {
+ std::string const entry = sConfigMgr->GetStringDefault("Updates.MySqlCLIPath", "");
+ if (!entry.empty())
+ return entry;
+ else
+ return GitRevision::GetMySQLExecutable();
+ }
+}
+
+bool DBUpdaterUtil::CheckExecutable()
+{
+ boost::filesystem::path exe(GetMySqlCli());
+ if (!exists(exe))
+ {
+ exe.clear();
+
+ try
+ {
+ exe = search_path("mysql");
+ }
+ catch (std::runtime_error&)
+ {
+ }
+
+ if (!exe.empty() && exists(exe))
+ {
+ // Correct the path to the cli
+ corrected_path() = absolute(exe).generic_string();
+ return true;
+ }
+
+ TC_LOG_FATAL("sql.updates", "Didn't find executeable mysql binary at \'%s\' or in path, correct the path in the *.conf (\"Updates.MySqlCLIPath\").",
+ absolute(exe).generic_string().c_str());
+
+ return false;
+ }
+ return true;
+}
+
+std::string& DBUpdaterUtil::corrected_path()
+{
+ static std::string path;
+ return path;
+}
+
template
std::string DBUpdater::GetSourceDirectory()
{
@@ -43,16 +95,6 @@ std::string DBUpdater::GetSourceDirectory()
return GitRevision::GetSourceDirectory();
}
-template
-std::string DBUpdater::GetMySqlCli()
-{
- std::string const entry = sConfigMgr->GetStringDefault("Updates.MySqlCLIPath", "");
- if (!entry.empty())
- return entry;
- else
- return GitRevision::GetMySQLExecutable();
-}
-
// Auth Database
template<>
std::string DBUpdater::GetConfigEntry()
@@ -144,36 +186,6 @@ BaseLocation DBUpdater::GetBaseLocationType()
return LOCATION_REPOSITORY;
}
-template
-bool DBUpdater::CheckExecutable()
-{
- DBUpdater::Path const exe(DBUpdater::GetMySqlCli());
- if (!exists(exe))
- {
- // Check for mysql in path
- std::vector args = {"--version"};
- uint32 ret;
- try
- {
- child c = execute(run_exe("mysql"), set_args(args), throw_on_error(), close_stdout());
- ret = wait_for_exit(c);
- }
- catch (boost::system::system_error&)
- {
- ret = EXIT_FAILURE;
- }
-
- if (ret == EXIT_FAILURE)
- {
- TC_LOG_FATAL("sql.updates", "Didn't find executeable mysql binary at \'%s\', correct the path in the *.conf (\"Updates.MySqlCLIPath\").",
- absolute(exe).generic_string().c_str());
-
- return false;
- }
- }
- return true;
-}
-
template
bool DBUpdater::Create(DatabaseWorkerPool& pool)
{
@@ -222,7 +234,7 @@ bool DBUpdater::Create(DatabaseWorkerPool& pool)
template
bool DBUpdater::Update(DatabaseWorkerPool& pool)
{
- if (!DBUpdater::CheckExecutable())
+ if (!DBUpdaterUtil::CheckExecutable())
return false;
TC_LOG_INFO("sql.updates", "Updating %s database...", DBUpdater::GetTableName().c_str());
@@ -273,7 +285,7 @@ bool DBUpdater::Populate(DatabaseWorkerPool& pool)
return true;
}
- if (!DBUpdater::CheckExecutable())
+ if (!DBUpdaterUtil::CheckExecutable())
return false;
TC_LOG_INFO("sql.updates", "Database %s is empty, auto populating it...", DBUpdater::GetTableName().c_str());
@@ -299,7 +311,7 @@ bool DBUpdater::Populate(DatabaseWorkerPool& pool)
}
case LOCATION_DOWNLOAD:
{
- TC_LOG_ERROR("sql.updates", ">> File \"%s\" is missing, download it from \"http://www.trinitycore.org/f/files/category/1-database/\"" \
+ TC_LOG_ERROR("sql.updates", ">> File \"%s\" is missing, download it from \"https://github.com/TrinityCore/TrinityCore/releases\"" \
" and place it in your server directory.", base.filename().generic_string().c_str());
break;
}
@@ -346,7 +358,10 @@ void DBUpdater::ApplyFile(DatabaseWorkerPool& pool, std::string const& hos
std::string const& password, std::string const& port_or_socket, std::string const& database, Path const& path)
{
std::vector args;
- args.reserve(7);
+ args.reserve(8);
+
+ // args[0] represents the program name
+ args.push_back("mysql");
// CLI Client connection info
args.push_back("-h" + host);
@@ -391,9 +406,29 @@ void DBUpdater::ApplyFile(DatabaseWorkerPool& pool, std::string const& hos
uint32 ret;
try
{
- child c = execute(run_exe(DBUpdater::GetMySqlCli().empty() ? "mysql" :
- boost::filesystem::absolute(DBUpdater::GetMySqlCli()).generic_string()),
- set_args(args), bind_stdin(source), throw_on_error());
+ boost::process::pipe outPipe = create_pipe();
+ boost::process::pipe errPipe = create_pipe();
+
+ child c = execute(run_exe(
+ boost::filesystem::absolute(DBUpdaterUtil::GetMySqlCli()).generic_string()),
+ set_args(args), bind_stdin(source), throw_on_error(),
+ bind_stdout(file_descriptor_sink(outPipe.sink, close_handle)),
+ bind_stderr(file_descriptor_sink(errPipe.sink, close_handle)));
+
+ file_descriptor_source mysqlOutfd(outPipe.source, close_handle);
+ file_descriptor_source mysqlErrfd(errPipe.source, close_handle);
+
+ stream mysqlOutStream(mysqlOutfd);
+ stream mysqlErrStream(mysqlErrfd);
+
+ std::stringstream out;
+ std::stringstream err;
+
+ copy(mysqlOutStream, out);
+ copy(mysqlErrStream, err);
+
+ TC_LOG_INFO("sql.updates", "%s", out.str().c_str());
+ TC_LOG_ERROR("sql.updates", "%s", err.str().c_str());
ret = wait_for_exit(c);
}
diff --git a/src/server/database/Updater/DBUpdater.h b/src/server/database/Updater/DBUpdater.h
index 402b8db4f38..c9792ffe060 100644
--- a/src/server/database/Updater/DBUpdater.h
+++ b/src/server/database/Updater/DBUpdater.h
@@ -54,6 +54,17 @@ struct UpdateResult
size_t archived;
};
+class DBUpdaterUtil
+{
+public:
+ static std::string GetMySqlCli();
+
+ static bool CheckExecutable();
+
+private:
+ static std::string& corrected_path();
+};
+
template
class DBUpdater
{
@@ -79,9 +90,6 @@ public:
static bool Populate(DatabaseWorkerPool& pool);
private:
- static std::string GetMySqlCli();
- static bool CheckExecutable();
-
static QueryResult Retrieve(DatabaseWorkerPool& pool, std::string const& query);
static void Apply(DatabaseWorkerPool& pool, std::string const& query);
static void ApplyFile(DatabaseWorkerPool& pool, Path const& path);
diff --git a/src/server/game/AI/CoreAI/GuardAI.cpp b/src/server/game/AI/CoreAI/GuardAI.cpp
index 176dd41fdae..c7d618a9918 100644
--- a/src/server/game/AI/CoreAI/GuardAI.cpp
+++ b/src/server/game/AI/CoreAI/GuardAI.cpp
@@ -43,7 +43,7 @@ bool GuardAI::CanSeeAlways(WorldObject const* obj)
return false;
}
-void GuardAI::EnterEvadeMode()
+void GuardAI::EnterEvadeMode(EvadeReason /*why*/)
{
if (!me->IsAlive())
{
diff --git a/src/server/game/AI/CoreAI/GuardAI.h b/src/server/game/AI/CoreAI/GuardAI.h
index 01d54e47b9a..63f2750a5d4 100644
--- a/src/server/game/AI/CoreAI/GuardAI.h
+++ b/src/server/game/AI/CoreAI/GuardAI.h
@@ -31,7 +31,7 @@ class GuardAI : public ScriptedAI
static int Permissible(Creature const* creature);
bool CanSeeAlways(WorldObject const* obj) override;
- void EnterEvadeMode() override;
+ void EnterEvadeMode(EvadeReason /*why*/) override;
void JustDied(Unit* killer) override;
};
#endif
diff --git a/src/server/game/AI/CoreAI/PassiveAI.cpp b/src/server/game/AI/CoreAI/PassiveAI.cpp
index 5f2c1ba5c52..aafde3c1d9a 100644
--- a/src/server/game/AI/CoreAI/PassiveAI.cpp
+++ b/src/server/game/AI/CoreAI/PassiveAI.cpp
@@ -26,7 +26,7 @@ NullCreatureAI::NullCreatureAI(Creature* c) : CreatureAI(c) { me->SetReactState(
void PassiveAI::UpdateAI(uint32)
{
if (me->IsInCombat() && me->getAttackers().empty())
- EnterEvadeMode();
+ EnterEvadeMode(EVADE_REASON_NO_HOSTILES);
}
void PossessedAI::AttackStart(Unit* target)
@@ -64,11 +64,11 @@ void CritterAI::DamageTaken(Unit* /*done_by*/, uint32&)
me->SetControlled(true, UNIT_STATE_FLEEING);
}
-void CritterAI::EnterEvadeMode()
+void CritterAI::EnterEvadeMode(EvadeReason why)
{
if (me->HasUnitState(UNIT_STATE_FLEEING))
me->SetControlled(false, UNIT_STATE_FLEEING);
- CreatureAI::EnterEvadeMode();
+ CreatureAI::EnterEvadeMode(why);
}
void TriggerAI::IsSummonedBy(Unit* summoner)
diff --git a/src/server/game/AI/CoreAI/PassiveAI.h b/src/server/game/AI/CoreAI/PassiveAI.h
index 28a73cff5de..bd72cd7fbe7 100644
--- a/src/server/game/AI/CoreAI/PassiveAI.h
+++ b/src/server/game/AI/CoreAI/PassiveAI.h
@@ -41,7 +41,7 @@ class PossessedAI : public CreatureAI
void MoveInLineOfSight(Unit*) override { }
void AttackStart(Unit* target) override;
void UpdateAI(uint32) override;
- void EnterEvadeMode() override { }
+ void EnterEvadeMode(EvadeReason /*why*/) override { }
void JustDied(Unit*) override;
void KilledUnit(Unit* victim) override;
@@ -57,7 +57,7 @@ class NullCreatureAI : public CreatureAI
void MoveInLineOfSight(Unit*) override { }
void AttackStart(Unit*) override { }
void UpdateAI(uint32) override { }
- void EnterEvadeMode() override { }
+ void EnterEvadeMode(EvadeReason /*why*/) override { }
void OnCharmed(bool /*apply*/) override { }
static int Permissible(const Creature*) { return PERMIT_BASE_IDLE; }
@@ -69,7 +69,7 @@ class CritterAI : public PassiveAI
explicit CritterAI(Creature* c) : PassiveAI(c) { }
void DamageTaken(Unit* done_by, uint32& /*damage*/) override;
- void EnterEvadeMode() override;
+ void EnterEvadeMode(EvadeReason why) override;
};
class TriggerAI : public NullCreatureAI
diff --git a/src/server/game/AI/CoreAI/PetAI.h b/src/server/game/AI/CoreAI/PetAI.h
index 9f220e64bfb..9c33baa9a9f 100644
--- a/src/server/game/AI/CoreAI/PetAI.h
+++ b/src/server/game/AI/CoreAI/PetAI.h
@@ -47,7 +47,7 @@ class PetAI : public CreatureAI
//
void MoveInLineOfSight(Unit* /*who*/) override { } // CreatureAI interferes with returning pets
void MoveInLineOfSight_Safe(Unit* /*who*/) { } // CreatureAI interferes with returning pets
- void EnterEvadeMode() override { } // For fleeing, pets don't use this type of Evade mechanic
+ void EnterEvadeMode(EvadeReason /*why*/) override { } // For fleeing, pets don't use this type of Evade mechanic
private:
bool _isVisible(Unit*) const;
diff --git a/src/server/game/AI/CoreAI/TotemAI.cpp b/src/server/game/AI/CoreAI/TotemAI.cpp
index f27fe67fc31..57e1e58da21 100644
--- a/src/server/game/AI/CoreAI/TotemAI.cpp
+++ b/src/server/game/AI/CoreAI/TotemAI.cpp
@@ -40,7 +40,7 @@ TotemAI::TotemAI(Creature* c) : CreatureAI(c), i_victimGuid()
void TotemAI::MoveInLineOfSight(Unit* /*who*/) { }
-void TotemAI::EnterEvadeMode()
+void TotemAI::EnterEvadeMode(EvadeReason /*why*/)
{
me->CombatStop(true);
}
diff --git a/src/server/game/AI/CoreAI/TotemAI.h b/src/server/game/AI/CoreAI/TotemAI.h
index fdde303c7b2..e1d1618037f 100644
--- a/src/server/game/AI/CoreAI/TotemAI.h
+++ b/src/server/game/AI/CoreAI/TotemAI.h
@@ -33,7 +33,7 @@ class TotemAI : public CreatureAI
void MoveInLineOfSight(Unit* who) override;
void AttackStart(Unit* victim) override;
- void EnterEvadeMode() override;
+ void EnterEvadeMode(EvadeReason /*why*/) override;
void UpdateAI(uint32 diff) override;
static int Permissible(Creature const* creature);
diff --git a/src/server/game/AI/CoreAI/UnitAI.cpp b/src/server/game/AI/CoreAI/UnitAI.cpp
index 1d237015f8d..a3a5e7f7663 100644
--- a/src/server/game/AI/CoreAI/UnitAI.cpp
+++ b/src/server/game/AI/CoreAI/UnitAI.cpp
@@ -29,7 +29,15 @@
void UnitAI::AttackStart(Unit* victim)
{
if (victim && me->Attack(victim, true))
+ {
+ // Clear distracted state on attacking
+ if (me->HasUnitState(UNIT_STATE_DISTRACTED))
+ {
+ me->ClearUnitState(UNIT_STATE_DISTRACTED);
+ me->GetMotionMaster()->Clear();
+ }
me->GetMotionMaster()->MoveChase(victim);
+ }
}
void UnitAI::AttackStartCaster(Unit* victim, float dist)
diff --git a/src/server/game/AI/CoreAI/UnitAI.h b/src/server/game/AI/CoreAI/UnitAI.h
index e6c7ccb5d11..5dc5946b226 100644
--- a/src/server/game/AI/CoreAI/UnitAI.h
+++ b/src/server/game/AI/CoreAI/UnitAI.h
@@ -255,8 +255,8 @@ class UnitAI
static void FillAISpellInfo();
virtual void sGossipHello(Player* /*player*/) { }
- virtual void sGossipSelect(Player* /*player*/, uint32 /*sender*/, uint32 /*action*/) { }
- virtual void sGossipSelectCode(Player* /*player*/, uint32 /*sender*/, uint32 /*action*/, char const* /*code*/) { }
+ virtual void sGossipSelect(Player* /*player*/, uint32 /*menuId*/, uint32 /*gossipListId*/) { }
+ virtual void sGossipSelectCode(Player* /*player*/, uint32 /*menuId*/, uint32 /*gossipListId*/, char const* /*code*/) { }
virtual void sQuestAccept(Player* /*player*/, Quest const* /*quest*/) { }
virtual void sQuestSelect(Player* /*player*/, Quest const* /*quest*/) { }
virtual void sQuestReward(Player* /*player*/, Quest const* /*quest*/, uint32 /*opt*/) { }
diff --git a/src/server/game/AI/CreatureAI.cpp b/src/server/game/AI/CreatureAI.cpp
index e94f5a037a3..c254a9124c1 100644
--- a/src/server/game/AI/CreatureAI.cpp
+++ b/src/server/game/AI/CreatureAI.cpp
@@ -26,6 +26,7 @@
#include "MapReference.h"
#include "Player.h"
#include "CreatureTextMgr.h"
+#include "Language.h"
//Disable CreatureAI when charmed
void CreatureAI::OnCharmed(bool /*apply*/)
@@ -164,9 +165,9 @@ void CreatureAI::TriggerAlert(Unit const* who) const
me->GetMotionMaster()->MoveDistract(5 * IN_MILLISECONDS);
}
-void CreatureAI::EnterEvadeMode()
+void CreatureAI::EnterEvadeMode(EvadeReason why)
{
- if (!_EnterEvadeMode())
+ if (!_EnterEvadeMode(why))
return;
TC_LOG_DEBUG("entities.unit", "Creature %u enters evade mode.", me->GetEntry());
@@ -203,7 +204,8 @@ void CreatureAI::SetGazeOn(Unit* target)
{
if (me->IsValidAttackTarget(target))
{
- AttackStart(target);
+ if (!me->IsFocusing(nullptr, true))
+ AttackStart(target);
me->SetReactState(REACT_PASSIVE);
}
}
@@ -222,7 +224,8 @@ bool CreatureAI::UpdateVictimWithGaze()
}
if (Unit* victim = me->SelectVictim())
- AttackStart(victim);
+ if (!me->IsFocusing(nullptr, true))
+ AttackStart(victim);
return me->GetVictim() != nullptr;
}
@@ -235,20 +238,21 @@ bool CreatureAI::UpdateVictim()
if (!me->HasReactState(REACT_PASSIVE))
{
if (Unit* victim = me->SelectVictim())
- AttackStart(victim);
+ if (!me->IsFocusing(nullptr, true))
+ AttackStart(victim);
return me->GetVictim() != nullptr;
}
else if (me->getThreatManager().isThreatListEmpty())
{
- EnterEvadeMode();
+ EnterEvadeMode(EVADE_REASON_NO_HOSTILES);
return false;
}
return true;
}
-bool CreatureAI::_EnterEvadeMode()
+bool CreatureAI::_EnterEvadeMode(EvadeReason /*why*/)
{
if (!me->IsAlive())
return false;
@@ -271,6 +275,105 @@ bool CreatureAI::_EnterEvadeMode()
return true;
}
+#define BOUNDARY_VISUALIZE_CREATURE 15425
+#define BOUNDARY_VISUALIZE_CREATURE_SCALE 0.25f
+#define BOUNDARY_VISUALIZE_STEP_SIZE 1
+#define BOUNDARY_VISUALIZE_FAILSAFE_LIMIT 750
+#define BOUNDARY_VISUALIZE_SPAWN_HEIGHT 5
+int32 CreatureAI::VisualizeBoundary(uint32 duration, Unit* owner, bool fill) const
+{
+ typedef std::pair coordinate;
+
+ if (!owner)
+ return -1;
+
+ if (!_boundary || _boundary->empty())
+ return LANG_CREATURE_MOVEMENT_NOT_BOUNDED;
+
+ std::queue Q;
+ std::unordered_set alreadyChecked;
+ std::unordered_set outOfBounds;
+
+ Position startPosition = owner->GetPosition();
+ if (!CheckBoundary(&startPosition)) // fall back to creature position
+ {
+ startPosition = me->GetPosition();
+ if (!CheckBoundary(&startPosition))
+ {
+ startPosition = me->GetHomePosition();
+ if (!CheckBoundary(&startPosition)) // fall back to creature home position
+ return LANG_CREATURE_NO_INTERIOR_POINT_FOUND;
+ }
+ }
+ float spawnZ = startPosition.GetPositionZ() + BOUNDARY_VISUALIZE_SPAWN_HEIGHT;
+
+ bool boundsWarning = false;
+ Q.push({ 0,0 });
+ while (!Q.empty())
+ {
+ coordinate front = Q.front();
+ bool hasOutOfBoundsNeighbor = false;
+ for (coordinate off : std::initializer_list{{1,0}, {0,1}, {-1,0}, {0,-1}})
+ {
+ coordinate next(front.first + off.first, front.second + off.second);
+ if (next.first > BOUNDARY_VISUALIZE_FAILSAFE_LIMIT || next.first < -BOUNDARY_VISUALIZE_FAILSAFE_LIMIT || next.second > BOUNDARY_VISUALIZE_FAILSAFE_LIMIT || next.second < -BOUNDARY_VISUALIZE_FAILSAFE_LIMIT)
+ {
+ boundsWarning = true;
+ continue;
+ }
+ if (alreadyChecked.find(next) == alreadyChecked.end()) // never check a coordinate twice
+ {
+ Position nextPos(startPosition.GetPositionX() + next.first*BOUNDARY_VISUALIZE_STEP_SIZE, startPosition.GetPositionY() + next.second*BOUNDARY_VISUALIZE_STEP_SIZE, startPosition.GetPositionZ());
+ if (CheckBoundary(&nextPos))
+ Q.push(next);
+ else
+ {
+ outOfBounds.insert(next);
+ hasOutOfBoundsNeighbor = true;
+ }
+ alreadyChecked.insert(next);
+ }
+ else
+ if (outOfBounds.find(next) != outOfBounds.end())
+ hasOutOfBoundsNeighbor = true;
+ }
+ if (fill || hasOutOfBoundsNeighbor)
+ if (TempSummon* point = owner->SummonCreature(BOUNDARY_VISUALIZE_CREATURE, Position(startPosition.GetPositionX() + front.first*BOUNDARY_VISUALIZE_STEP_SIZE, startPosition.GetPositionY() + front.second*BOUNDARY_VISUALIZE_STEP_SIZE, spawnZ), TEMPSUMMON_TIMED_DESPAWN, duration * IN_MILLISECONDS))
+ {
+ point->SetObjectScale(BOUNDARY_VISUALIZE_CREATURE_SCALE);
+ point->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_IMMUNE_TO_PC | UNIT_FLAG_STUNNED | UNIT_FLAG_IMMUNE_TO_NPC);
+ if (!hasOutOfBoundsNeighbor)
+ point->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE);
+ }
+ Q.pop();
+ }
+ return boundsWarning ? LANG_CREATURE_MOVEMENT_MAYBE_UNBOUNDED : 0;
+}
+
+bool CreatureAI::CheckBoundary(Position* who) const
+{
+ if (!who)
+ who = me;
+
+ if (_boundary)
+ for (CreatureBoundary::const_iterator it = _boundary->begin(); it != _boundary->end(); ++it)
+ if (!(*it)->IsWithinBoundary(who))
+ return false;
+
+ return true;
+}
+
+bool CreatureAI::CheckInRoom()
+{
+ if (CheckBoundary())
+ return true;
+ else
+ {
+ EnterEvadeMode(EVADE_REASON_BOUNDARY);
+ return false;
+ }
+}
+
Creature* CreatureAI::DoSummon(uint32 entry, const Position& pos, uint32 despawnTime, TempSummonType summonType)
{
return me->SummonCreature(entry, pos, summonType, despawnTime);
diff --git a/src/server/game/AI/CreatureAI.h b/src/server/game/AI/CreatureAI.h
index 0a2cce723dc..3b7c489e018 100644
--- a/src/server/game/AI/CreatureAI.h
+++ b/src/server/game/AI/CreatureAI.h
@@ -21,6 +21,7 @@
#include "Creature.h"
#include "UnitAI.h"
+#include "AreaBoundary.h"
#include "Common.h"
class WorldObject;
@@ -63,6 +64,7 @@ enum SCEquip
EQUIP_UNEQUIP = 0
};
+typedef std::set CreatureBoundary;
class CreatureAI : public UnitAI
{
protected:
@@ -77,10 +79,20 @@ 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;
+ void SetBoundary(CreatureBoundary const* boundary) { _boundary = boundary; CheckInRoom(); }
public:
+ enum EvadeReason
+ {
+ EVADE_REASON_NO_HOSTILES, // the creature's threat list is empty
+ EVADE_REASON_BOUNDARY, // the creature has moved outside its evade boundary
+ EVADE_REASON_SEQUENCE_BREAK, // this is a boss and the pre-requisite encounters for engaging it are not defeated yet
+ EVADE_REASON_OTHER
+ };
+
void Talk(uint8 id, WorldObject const* whisperTarget = nullptr);
- explicit CreatureAI(Creature* creature) : UnitAI(creature), me(creature), m_MoveInLineOfSight_locked(false) { }
+ explicit CreatureAI(Creature* creature) : UnitAI(creature), me(creature), _boundary(nullptr), m_MoveInLineOfSight_locked(false) { }
virtual ~CreatureAI() { }
@@ -96,7 +108,7 @@ class CreatureAI : public UnitAI
virtual bool CanRespawn() { return true; }
// Called for reaction at stopping attack at no attackers or targets
- virtual void EnterEvadeMode();
+ virtual void EnterEvadeMode(EvadeReason why = EVADE_REASON_OTHER);
// Called for reaction at enter to combat if not in combat yet (enemy can be NULL)
virtual void EnterCombat(Unit* /*victim*/) { }
@@ -174,10 +186,17 @@ class CreatureAI : public UnitAI
virtual bool CanSeeAlways(WorldObject const* /*obj*/) { return false; }
+ // intended for encounter design/debugging. do not use for other purposes. expensive.
+ int32 VisualizeBoundary(uint32 duration, Unit* owner=nullptr, bool fill=false) const;
+ virtual bool CheckInRoom();
+ CreatureBoundary const* GetBoundary() const { return _boundary; }
+
protected:
virtual void MoveInLineOfSight(Unit* /*who*/);
- bool _EnterEvadeMode();
+ bool _EnterEvadeMode(EvadeReason why = EVADE_REASON_OTHER);
+
+ CreatureBoundary const* _boundary;
private:
bool m_MoveInLineOfSight_locked;
diff --git a/src/server/game/AI/CreatureAIFactory.h b/src/server/game/AI/CreatureAIFactory.h
index 01a17cdf76f..f83bdc9a8b1 100644
--- a/src/server/game/AI/CreatureAIFactory.h
+++ b/src/server/game/AI/CreatureAIFactory.h
@@ -50,6 +50,8 @@ CreatureAIFactory::Create(void* data) const
typedef FactoryHolder CreatureAICreator;
typedef FactoryHolder::FactoryHolderRegistry CreatureAIRegistry;
+#define sCreatureAIRegistry CreatureAIRegistry::instance()
+
//GO
struct SelectableGameObjectAI : public FactoryHolder, public Permissible
{
@@ -76,4 +78,7 @@ GameObjectAIFactory::Create(void* data) const
typedef FactoryHolder GameObjectAICreator;
typedef FactoryHolder::FactoryHolderRegistry GameObjectAIRegistry;
+
+#define sGameObjectAIRegistry GameObjectAIRegistry::instance()
+
#endif
diff --git a/src/server/game/AI/CreatureAIImpl.h b/src/server/game/AI/CreatureAIImpl.h
index b8db67479c9..a45283b3d37 100644
--- a/src/server/game/AI/CreatureAIImpl.h
+++ b/src/server/game/AI/CreatureAIImpl.h
@@ -23,292 +23,14 @@
#include "CreatureAI.h"
#include "SpellMgr.h"
-template
-inline
-const T& RAND(const T& v1, const T& v2)
-{
- return (urand(0, 1)) ? v1 : v2;
-}
+#include
+#include
-template
-inline
-const T& RAND(const T& v1, const T& v2, const T& v3)
+template
+static inline First const& RAND(First const& first, Second const& second, Rest const&... rest)
{
- switch (urand(0, 2))
- {
- default:
- case 0: return v1;
- case 1: return v2;
- case 2: return v3;
- }
-}
-
-template
-inline
-const T& RAND(const T& v1, const T& v2, const T& v3, const T& v4)
-{
- switch (urand(0, 3))
- {
- default:
- case 0: return v1;
- case 1: return v2;
- case 2: return v3;
- case 3: return v4;
- }
-}
-
-template
-inline
-const T& RAND(const T& v1, const T& v2, const T& v3, const T& v4, const T& v5)
-{
- switch (urand(0, 4))
- {
- default:
- case 0: return v1;
- case 1: return v2;
- case 2: return v3;
- case 3: return v4;
- case 4: return v5;
- }
-}
-
-template
-inline
-const T& RAND(const T& v1, const T& v2, const T& v3, const T& v4, const T& v5, const T& v6)
-{
- switch (urand(0, 5))
- {
- default:
- case 0: return v1;
- case 1: return v2;
- case 2: return v3;
- case 3: return v4;
- case 4: return v5;
- case 5: return v6;
- }
-}
-
-template
-inline
-const T& RAND(const T& v1, const T& v2, const T& v3, const T& v4, const T& v5, const T& v6, const T& v7)
-{
- switch (urand(0, 6))
- {
- default:
- case 0: return v1;
- case 1: return v2;
- case 2: return v3;
- case 3: return v4;
- case 4: return v5;
- case 5: return v6;
- case 6: return v7;
- }
-}
-
-template
-inline
-const T& RAND(const T& v1, const T& v2, const T& v3, const T& v4, const T& v5, const T& v6, const T& v7, const T& v8)
-{
- switch (urand(0, 7))
- {
- default:
- case 0: return v1;
- case 1: return v2;
- case 2: return v3;
- case 3: return v4;
- case 4: return v5;
- case 5: return v6;
- case 6: return v7;
- case 7: return v8;
- }
-}
-
-template
-inline
-const T& RAND(const T& v1, const T& v2, const T& v3, const T& v4, const T& v5, const T& v6, const T& v7, const T& v8,
- const T& v9)
-{
- switch (urand(0, 8))
- {
- default:
- case 0: return v1;
- case 1: return v2;
- case 2: return v3;
- case 3: return v4;
- case 4: return v5;
- case 5: return v6;
- case 6: return v7;
- case 7: return v8;
- case 8: return v9;
- }
-}
-
-template
-inline
-const T& RAND(const T& v1, const T& v2, const T& v3, const T& v4, const T& v5, const T& v6, const T& v7, const T& v8,
- const T& v9, const T& v10)
-{
- switch (urand(0, 9))
- {
- default:
- case 0: return v1;
- case 1: return v2;
- case 2: return v3;
- case 3: return v4;
- case 4: return v5;
- case 5: return v6;
- case 6: return v7;
- case 7: return v8;
- case 8: return v9;
- case 9: return v10;
- }
-}
-
-template
-inline
-const T& RAND(const T& v1, const T& v2, const T& v3, const T& v4, const T& v5, const T& v6, const T& v7, const T& v8,
- const T& v9, const T& v10, const T& v11)
-{
- switch (urand(0, 10))
- {
- default:
- case 0: return v1;
- case 1: return v2;
- case 2: return v3;
- case 3: return v4;
- case 4: return v5;
- case 5: return v6;
- case 6: return v7;
- case 7: return v8;
- case 8: return v9;
- case 9: return v10;
- case 10: return v11;
- }
-}
-
-template
-inline
-const T& RAND(const T& v1, const T& v2, const T& v3, const T& v4, const T& v5, const T& v6, const T& v7, const T& v8,
- const T& v9, const T& v10, const T& v11, const T& v12)
-{
- switch (urand(0, 11))
- {
- default:
- case 0: return v1;
- case 1: return v2;
- case 2: return v3;
- case 3: return v4;
- case 4: return v5;
- case 5: return v6;
- case 6: return v7;
- case 7: return v8;
- case 8: return v9;
- case 9: return v10;
- case 10: return v11;
- case 11: return v12;
- }
-}
-
-template
-inline
-const T& RAND(const T& v1, const T& v2, const T& v3, const T& v4, const T& v5, const T& v6, const T& v7, const T& v8,
- const T& v9, const T& v10, const T& v11, const T& v12, const T& v13)
-{
- switch (urand(0, 12))
- {
- default:
- case 0: return v1;
- case 1: return v2;
- case 2: return v3;
- case 3: return v4;
- case 4: return v5;
- case 5: return v6;
- case 6: return v7;
- case 7: return v8;
- case 8: return v9;
- case 9: return v10;
- case 10: return v11;
- case 11: return v12;
- case 12: return v13;
- }
-}
-
-template
-inline
-const T& RAND(const T& v1, const T& v2, const T& v3, const T& v4, const T& v5, const T& v6, const T& v7, const T& v8,
- const T& v9, const T& v10, const T& v11, const T& v12, const T& v13, const T& v14)
-{
- switch (urand(0, 13))
- {
- default:
- case 0: return v1;
- case 1: return v2;
- case 2: return v3;
- case 3: return v4;
- case 4: return v5;
- case 5: return v6;
- case 6: return v7;
- case 7: return v8;
- case 8: return v9;
- case 9: return v10;
- case 10: return v11;
- case 11: return v12;
- case 12: return v13;
- case 13: return v14;
- }
-}
-
-template
-inline
-const T& RAND(const T& v1, const T& v2, const T& v3, const T& v4, const T& v5, const T& v6, const T& v7, const T& v8,
- const T& v9, const T& v10, const T& v11, const T& v12, const T& v13, const T& v14, const T& v15)
-{
- switch (urand(0, 14))
- {
- default:
- case 0: return v1;
- case 1: return v2;
- case 2: return v3;
- case 3: return v4;
- case 4: return v5;
- case 5: return v6;
- case 6: return v7;
- case 7: return v8;
- case 8: return v9;
- case 9: return v10;
- case 10: return v11;
- case 11: return v12;
- case 12: return v13;
- case 13: return v14;
- case 14: return v15;
- }
-}
-
-template
-inline
-const T& RAND(const T& v1, const T& v2, const T& v3, const T& v4, const T& v5, const T& v6, const T& v7, const T& v8,
- const T& v9, const T& v10, const T& v11, const T& v12, const T& v13, const T& v14, const T& v15, const T& v16)
-{
- switch (urand(0, 15))
- {
- default:
- case 0: return v1;
- case 1: return v2;
- case 2: return v3;
- case 3: return v4;
- case 4: return v5;
- case 5: return v6;
- case 6: return v7;
- case 7: return v8;
- case 8: return v9;
- case 9: return v10;
- case 10: return v11;
- case 11: return v12;
- case 12: return v13;
- case 13: return v14;
- case 14: return v15;
- case 15: return v16;
- }
+ std::reference_wrapper::type> const pack[] = { first, second, rest... };
+ return pack[urand(0, sizeof...(rest) + 1)].get();
}
enum AITarget
diff --git a/src/server/game/AI/CreatureAISelector.cpp b/src/server/game/AI/CreatureAISelector.cpp
index 2cb4b721a35..c8c7838beec 100644
--- a/src/server/game/AI/CreatureAISelector.cpp
+++ b/src/server/game/AI/CreatureAISelector.cpp
@@ -30,10 +30,9 @@ namespace FactorySelector
CreatureAI* selectAI(Creature* creature)
{
const CreatureAICreator* ai_factory = NULL;
- CreatureAIRegistry& ai_registry(*CreatureAIRegistry::instance());
if (creature->IsPet())
- ai_factory = ai_registry.GetRegistryItem("PetAI");
+ ai_factory = sCreatureAIRegistry->GetRegistryItem("PetAI");
//scriptname in db
if (!ai_factory)
@@ -43,32 +42,32 @@ namespace FactorySelector
// AIname in db
std::string ainame=creature->GetAIName();
if (!ai_factory && !ainame.empty())
- ai_factory = ai_registry.GetRegistryItem(ainame);
+ ai_factory = sCreatureAIRegistry->GetRegistryItem(ainame);
// select by NPC flags
if (!ai_factory)
{
if (creature->IsVehicle())
- ai_factory = ai_registry.GetRegistryItem("VehicleAI");
+ ai_factory = sCreatureAIRegistry->GetRegistryItem("VehicleAI");
else if (creature->HasUnitTypeMask(UNIT_MASK_CONTROLABLE_GUARDIAN) && ((Guardian*)creature)->GetOwner()->GetTypeId() == TYPEID_PLAYER)
- ai_factory = ai_registry.GetRegistryItem("PetAI");
+ ai_factory = sCreatureAIRegistry->GetRegistryItem("PetAI");
else if (creature->HasFlag(UNIT_NPC_FLAGS, UNIT_NPC_FLAG_SPELLCLICK))
- ai_factory = ai_registry.GetRegistryItem("NullCreatureAI");
+ ai_factory = sCreatureAIRegistry->GetRegistryItem("NullCreatureAI");
else if (creature->IsGuard())
- ai_factory = ai_registry.GetRegistryItem("GuardAI");
+ ai_factory = sCreatureAIRegistry->GetRegistryItem("GuardAI");
else if (creature->HasUnitTypeMask(UNIT_MASK_CONTROLABLE_GUARDIAN))
- ai_factory = ai_registry.GetRegistryItem("PetAI");
+ ai_factory = sCreatureAIRegistry->GetRegistryItem("PetAI");
else if (creature->IsTotem())
- ai_factory = ai_registry.GetRegistryItem("TotemAI");
+ ai_factory = sCreatureAIRegistry->GetRegistryItem("TotemAI");
else if (creature->IsTrigger())
{
if (creature->m_spells[0])
- ai_factory = ai_registry.GetRegistryItem("TriggerAI");
+ ai_factory = sCreatureAIRegistry->GetRegistryItem("TriggerAI");
else
- ai_factory = ai_registry.GetRegistryItem("NullCreatureAI");
+ ai_factory = sCreatureAIRegistry->GetRegistryItem("NullCreatureAI");
}
else if (creature->IsCritter() && !creature->HasUnitTypeMask(UNIT_MASK_GUARDIAN))
- ai_factory = ai_registry.GetRegistryItem("CritterAI");
+ ai_factory = sCreatureAIRegistry->GetRegistryItem("CritterAI");
}
// select by permit check
@@ -76,7 +75,7 @@ namespace FactorySelector
{
int best_val = -1;
typedef CreatureAIRegistry::RegistryMapType RMT;
- RMT const& l = ai_registry.GetRegisteredItems();
+ RMT const& l = sCreatureAIRegistry->GetRegisteredItems();
for (RMT::const_iterator iter = l.begin(); iter != l.end(); ++iter)
{
const CreatureAICreator* factory = iter->second;
@@ -128,14 +127,13 @@ namespace FactorySelector
GameObjectAI* SelectGameObjectAI(GameObject* go)
{
- const GameObjectAICreator* ai_factory = NULL;
- GameObjectAIRegistry& ai_registry(*GameObjectAIRegistry::instance());
+ GameObjectAICreator const* ai_factory = NULL;
// scriptname in db
if (GameObjectAI* scriptedAI = sScriptMgr->GetGameObjectAI(go))
return scriptedAI;
- ai_factory = ai_registry.GetRegistryItem(go->GetAIName());
+ ai_factory = sGameObjectAIRegistry->GetRegistryItem(go->GetAIName());
//future goAI types go here
diff --git a/src/server/game/AI/ScriptedAI/ScriptedCreature.cpp b/src/server/game/AI/ScriptedAI/ScriptedCreature.cpp
index 76d72f3441a..fe957abcc75 100644
--- a/src/server/game/AI/ScriptedAI/ScriptedCreature.cpp
+++ b/src/server/game/AI/ScriptedAI/ScriptedCreature.cpp
@@ -23,6 +23,7 @@
#include "Cell.h"
#include "CellImpl.h"
#include "ObjectMgr.h"
+#include "AreaBoundary.h"
// Spell summary for ScriptedAI::SelectSpell
struct TSpellSummary
@@ -97,9 +98,7 @@ bool SummonList::HasEntry(uint32 entry) const
}
ScriptedAI::ScriptedAI(Creature* creature) : CreatureAI(creature),
- me(creature),
IsFleeing(false),
- _evadeCheckCooldown(2500),
_isCombatMovementAllowed(true)
{
_isHeroic = me->GetMap()->IsHeroic();
@@ -406,7 +405,7 @@ enum NPCs
// Hacklike storage used for misc creatures that are expected to evade of outside of a certain area.
// It is assumed the information is found elswehere and can be handled by the core. So far no luck finding such information/way to extract it.
-bool ScriptedAI::EnterEvadeIfOutOfCombatArea(uint32 const diff)
+/*bool ScriptedAI::EnterEvadeIfOutOfCombatArea(uint32 const diff)
{
if (_evadeCheckCooldown <= diff)
_evadeCheckCooldown = 2500;
@@ -450,15 +449,16 @@ bool ScriptedAI::EnterEvadeIfOutOfCombatArea(uint32 const diff)
EnterEvadeMode();
return true;
-}
+}*/
// BossAI - for instanced bosses
BossAI::BossAI(Creature* creature, uint32 bossId) : ScriptedAI(creature),
instance(creature->GetInstanceScript()),
summons(creature),
- _boundary(instance ? instance->GetBossBoundary(bossId) : NULL),
_bossId(bossId)
{
+ if (instance)
+ SetBoundary(instance->GetBossBoundary(bossId));
scheduler.SetValidator([this]
{
return !me->HasUnitState(UNIT_STATE_CASTING);
@@ -470,6 +470,7 @@ void BossAI::_Reset()
if (!me->IsAlive())
return;
+ me->SetCombatPulseDelay(0);
me->ResetLootMode();
events.Reset();
summons.DespawnAll();
@@ -494,12 +495,13 @@ void BossAI::_EnterCombat()
// bosses do not respawn, check only on enter combat
if (!instance->CheckRequiredBosses(_bossId))
{
- EnterEvadeMode();
+ EnterEvadeMode(EVADE_REASON_SEQUENCE_BREAK);
return;
}
instance->SetBossState(_bossId, IN_PROGRESS);
}
+ me->SetCombatPulseDelay(5);
me->setActive(true);
DoZoneInCombat();
ScheduleTasks();
@@ -517,55 +519,6 @@ void BossAI::TeleportCheaters()
target->NearTeleportTo(x, y, z, 0);
}
-bool BossAI::CheckBoundary(Unit* who)
-{
- if (!GetBoundary() || !who)
- return true;
-
- for (BossBoundaryMap::const_iterator itr = GetBoundary()->begin(); itr != GetBoundary()->end(); ++itr)
- {
- switch (itr->first)
- {
- case BOUNDARY_N:
- if (who->GetPositionX() > itr->second)
- return false;
- break;
- case BOUNDARY_S:
- if (who->GetPositionX() < itr->second)
- return false;
- break;
- case BOUNDARY_E:
- if (who->GetPositionY() < itr->second)
- return false;
- break;
- case BOUNDARY_W:
- if (who->GetPositionY() > itr->second)
- return false;
- break;
- case BOUNDARY_NW:
- if (who->GetPositionX() + who->GetPositionY() > itr->second)
- return false;
- break;
- case BOUNDARY_SE:
- if (who->GetPositionX() + who->GetPositionY() < itr->second)
- return false;
- break;
- case BOUNDARY_NE:
- if (who->GetPositionX() - who->GetPositionY() > itr->second)
- return false;
- break;
- case BOUNDARY_SW:
- if (who->GetPositionX() - who->GetPositionY() < itr->second)
- return false;
- break;
- default:
- break;
- }
- }
-
- return true;
-}
-
void BossAI::JustSummoned(Creature* summon)
{
summons.Summon(summon);
diff --git a/src/server/game/AI/ScriptedAI/ScriptedCreature.h b/src/server/game/AI/ScriptedAI/ScriptedCreature.h
index dcd54a5bfcc..ff0e7d3d7f9 100644
--- a/src/server/game/AI/ScriptedAI/ScriptedCreature.h
+++ b/src/server/game/AI/ScriptedAI/ScriptedCreature.h
@@ -184,9 +184,6 @@ struct ScriptedAI : public CreatureAI
// Variables
// *************
- //Pointer to creature we are manipulating
- Creature* me;
-
//For fleeing
bool IsFleeing;
@@ -266,8 +263,6 @@ struct ScriptedAI : public CreatureAI
void SetCombatMovement(bool allowMovement);
bool IsCombatMovementAllowed() const { return _isCombatMovementAllowed; }
- bool EnterEvadeIfOutOfCombatArea(uint32 const diff);
-
// return true for heroic mode. i.e.
// - for dungeon in mode 10-heroic,
// - for raid in mode 10-Heroic
@@ -335,7 +330,6 @@ struct ScriptedAI : public CreatureAI
private:
Difficulty _difficulty;
- uint32 _evadeCheckCooldown;
bool _isCombatMovementAllowed;
bool _isHeroic;
};
@@ -347,7 +341,6 @@ class BossAI : public ScriptedAI
virtual ~BossAI() { }
InstanceScript* const instance;
- BossBoundaryMap const* GetBoundary() const { return _boundary; }
void JustSummoned(Creature* summon) override;
void SummonedCreatureDespawn(Creature* summon) override;
@@ -374,16 +367,6 @@ class BossAI : public ScriptedAI
void _JustReachedHome() { me->setActive(false); }
void _DespawnAtEvade();
- virtual bool CheckInRoom()
- {
- if (CheckBoundary(me))
- return true;
-
- EnterEvadeMode();
- return false;
- }
-
- bool CheckBoundary(Unit* who);
void TeleportCheaters();
EventMap events;
@@ -391,7 +374,6 @@ class BossAI : public ScriptedAI
TaskScheduler scheduler;
private:
- BossBoundaryMap const* const _boundary;
uint32 const _bossId;
};
diff --git a/src/server/game/AI/ScriptedAI/ScriptedEscortAI.cpp b/src/server/game/AI/ScriptedAI/ScriptedEscortAI.cpp
index 70c44f6fe90..68cb8d346d0 100644
--- a/src/server/game/AI/ScriptedAI/ScriptedEscortAI.cpp
+++ b/src/server/game/AI/ScriptedAI/ScriptedEscortAI.cpp
@@ -184,7 +184,7 @@ void npc_escortAI::ReturnToLastPoint()
me->GetMotionMaster()->MovePoint(POINT_LAST_POINT, x, y, z);
}
-void npc_escortAI::EnterEvadeMode()
+void npc_escortAI::EnterEvadeMode(EvadeReason /*why*/)
{
me->RemoveAllAuras();
me->DeleteThreatList();
diff --git a/src/server/game/AI/ScriptedAI/ScriptedEscortAI.h b/src/server/game/AI/ScriptedAI/ScriptedEscortAI.h
index 3b7428e2b9e..673f3e671a0 100644
--- a/src/server/game/AI/ScriptedAI/ScriptedEscortAI.h
+++ b/src/server/game/AI/ScriptedAI/ScriptedEscortAI.h
@@ -66,7 +66,7 @@ struct npc_escortAI : public ScriptedAI
void ReturnToLastPoint();
- void EnterEvadeMode() override;
+ void EnterEvadeMode(EvadeReason /*why*/ = EVADE_REASON_OTHER) override;
void UpdateAI(uint32 diff) override; // the "internal" update, calls UpdateEscortAI()
virtual void UpdateEscortAI(uint32 diff); // used when it's needed to add code in update (abilities, scripted events, etc)
diff --git a/src/server/game/AI/ScriptedAI/ScriptedFollowerAI.cpp b/src/server/game/AI/ScriptedAI/ScriptedFollowerAI.cpp
index 40c404933a2..dc9f6d2681e 100644
--- a/src/server/game/AI/ScriptedAI/ScriptedFollowerAI.cpp
+++ b/src/server/game/AI/ScriptedAI/ScriptedFollowerAI.cpp
@@ -176,7 +176,7 @@ void FollowerAI::JustRespawned()
Reset();
}
-void FollowerAI::EnterEvadeMode()
+void FollowerAI::EnterEvadeMode(EvadeReason /*why*/)
{
me->RemoveAllAuras();
me->DeleteThreatList();
diff --git a/src/server/game/AI/ScriptedAI/ScriptedFollowerAI.h b/src/server/game/AI/ScriptedAI/ScriptedFollowerAI.h
index f3919ea63bc..d1c976b45c8 100644
--- a/src/server/game/AI/ScriptedAI/ScriptedFollowerAI.h
+++ b/src/server/game/AI/ScriptedAI/ScriptedFollowerAI.h
@@ -46,7 +46,7 @@ class FollowerAI : public ScriptedAI
void MoveInLineOfSight(Unit*) override;
- void EnterEvadeMode() override;
+ void EnterEvadeMode(EvadeReason /*why*/ = EVADE_REASON_OTHER) override;
void JustDied(Unit*) override;
diff --git a/src/server/game/AI/SmartScripts/SmartAI.cpp b/src/server/game/AI/SmartScripts/SmartAI.cpp
index b4e0152688b..eca327e770e 100644
--- a/src/server/game/AI/SmartScripts/SmartAI.cpp
+++ b/src/server/game/AI/SmartScripts/SmartAI.cpp
@@ -408,7 +408,7 @@ void SmartAI::MovementInform(uint32 MovementType, uint32 Data)
MovepointReached(Data);
}
-void SmartAI::EnterEvadeMode()
+void SmartAI::EnterEvadeMode(EvadeReason /*why*/)
{
if (!me->IsAlive() || me->IsInEvadeMode())
return;
@@ -453,45 +453,15 @@ void SmartAI::MoveInLineOfSight(Unit* who)
GetScript()->OnMoveInLineOfSight(who);
- if (me->HasReactState(REACT_PASSIVE) || AssistPlayerInCombat(who))
+ if (AssistPlayerInCombat(who))
return;
- if (!CanAIAttack(who))
- return;
-
- if (!me->CanStartAttack(who, false))
- return;
-
- if (me->IsHostileTo(who))
- {
- float fAttackRadius = me->GetAttackDistance(who);
- if (me->IsWithinDistInMap(who, fAttackRadius) && me->IsWithinLOSInMap(who))
- {
- if (!me->GetVictim())
- {
- // Clear distracted state on combat
- if (me->HasUnitState(UNIT_STATE_DISTRACTED))
- {
- me->ClearUnitState(UNIT_STATE_DISTRACTED);
- me->GetMotionMaster()->Clear();
- }
-
- AttackStart(who);
- }
- else/* if (me->GetMap()->IsDungeon())*/
- {
- who->SetInCombatWith(me);
- me->AddThreat(who, 0.0f);
- }
- }
- }
+ CreatureAI::MoveInLineOfSight(who);
}
bool SmartAI::CanAIAttack(const Unit* /*who*/) const
{
- if (me->GetReactState() == REACT_PASSIVE)
- return false;
- return true;
+ return !(me->HasReactState(REACT_PASSIVE));
}
bool SmartAI::AssistPlayerInCombat(Unit* who)
@@ -728,12 +698,12 @@ void SmartAI::sGossipHello(Player* player)
GetScript()->ProcessEventsFor(SMART_EVENT_GOSSIP_HELLO, player);
}
-void SmartAI::sGossipSelect(Player* player, uint32 sender, uint32 action)
+void SmartAI::sGossipSelect(Player* player, uint32 menuId, uint32 gossipListId)
{
- GetScript()->ProcessEventsFor(SMART_EVENT_GOSSIP_SELECT, player, sender, action);
+ GetScript()->ProcessEventsFor(SMART_EVENT_GOSSIP_SELECT, player, menuId, gossipListId);
}
-void SmartAI::sGossipSelectCode(Player* /*player*/, uint32 /*sender*/, uint32 /*action*/, const char* /*code*/) { }
+void SmartAI::sGossipSelectCode(Player* /*player*/, uint32 /*menuId*/, uint32 /*gossipListId*/, const char* /*code*/) { }
void SmartAI::sQuestAccept(Player* player, Quest const* quest)
{
diff --git a/src/server/game/AI/SmartScripts/SmartAI.h b/src/server/game/AI/SmartScripts/SmartAI.h
index 4989e241ff4..02c057247f6 100644
--- a/src/server/game/AI/SmartScripts/SmartAI.h
+++ b/src/server/game/AI/SmartScripts/SmartAI.h
@@ -79,7 +79,7 @@ class SmartAI : public CreatureAI
void EnterCombat(Unit* enemy) override;
// Called for reaction at stopping attack at no attackers or targets
- void EnterEvadeMode() override;
+ void EnterEvadeMode(EvadeReason why = EVADE_REASON_OTHER) override;
// Called when the creature is killed
void JustDied(Unit* killer) override;
@@ -175,8 +175,8 @@ class SmartAI : public CreatureAI
void SetInvincibilityHpLevel(uint32 level) { mInvincibilityHpLevel = level; }
void sGossipHello(Player* player) override;
- void sGossipSelect(Player* player, uint32 sender, uint32 action) override;
- void sGossipSelectCode(Player* player, uint32 sender, uint32 action, const char* code) override;
+ void sGossipSelect(Player* player, uint32 menuId, uint32 gossipListId) override;
+ void sGossipSelectCode(Player* player, uint32 menuId, uint32 gossipListId, const char* code) override;
void sQuestAccept(Player* player, Quest const* quest) override;
//void sQuestSelect(Player* player, Quest const* quest) override;
void sQuestReward(Player* player, Quest const* quest, uint32 opt) override;
diff --git a/src/server/game/AI/SmartScripts/SmartScript.cpp b/src/server/game/AI/SmartScripts/SmartScript.cpp
index c2ea45d64cd..206f8d121da 100644
--- a/src/server/game/AI/SmartScripts/SmartScript.cpp
+++ b/src/server/game/AI/SmartScripts/SmartScript.cpp
@@ -979,7 +979,7 @@ void SmartScript::ProcessAction(SmartScriptHolder& e, Unit* unit, uint32 var0, u
{
if (me && !me->isDead())
{
- me->Kill(me);
+ me->KillSelf();
TC_LOG_DEBUG("scripts.ai", "SmartScript::ProcessAction: SMART_ACTION_DIE: Creature %u", me->GetGUID().GetCounter());
}
break;
@@ -1026,16 +1026,21 @@ void SmartScript::ProcessAction(SmartScriptHolder& e, Unit* unit, uint32 var0, u
for (ObjectList::const_iterator itr = targets->begin(); itr != targets->end(); ++itr)
{
- if (!IsCreature(*itr))
- continue;
-
- if ((*itr)->ToUnit()->IsAlive() && IsSmart((*itr)->ToCreature()))
+ if (Creature* target = (*itr)->ToCreature())
{
- ENSURE_AI(SmartAI, (*itr)->ToCreature()->AI())->SetDespawnTime(e.action.forceDespawn.delay + 1); // Next tick
- ENSURE_AI(SmartAI, (*itr)->ToCreature()->AI())->StartDespawn();
+ if (target->IsAlive() && IsSmart(target))
+ {
+ ENSURE_AI(SmartAI, target->AI())->SetDespawnTime(e.action.forceDespawn.delay + 1); // Next tick
+ ENSURE_AI(SmartAI, target->AI())->StartDespawn();
+ }
+ else
+ target->DespawnOrUnsummon(e.action.forceDespawn.delay);
+ }
+ else if (GameObject* goTarget = (*itr)->ToGameObject())
+ {
+ if (IsSmartGO(goTarget))
+ goTarget->SetRespawnTime(e.action.forceDespawn.delay + 1);
}
- else
- (*itr)->ToCreature()->DespawnOrUnsummon(e.action.forceDespawn.delay);
}
delete targets;
@@ -1142,6 +1147,14 @@ void SmartScript::ProcessAction(SmartScriptHolder& e, Unit* unit, uint32 var0, u
me->GetMotionMaster()->MovePoint(SMART_RANDOM_POINT, x, y, z);
break;
}
+ case SMART_ACTION_RISE_UP:
+ {
+ if (!me)
+ break;
+
+ me->GetMotionMaster()->MovePoint(SMART_RANDOM_POINT, me->GetPositionX(), me->GetPositionY(), me->GetPositionZ() + (float)e.action.moveRandom.distance);
+ break;
+ }
case SMART_ACTION_SET_VISIBILITY:
{
if (me)
@@ -1247,7 +1260,7 @@ void SmartScript::ProcessAction(SmartScriptHolder& e, Unit* unit, uint32 var0, u
if (!IsUnit(*itr))
continue;
- (*itr)->ToUnit()->Kill((*itr)->ToUnit());
+ (*itr)->ToUnit()->KillSelf();
}
delete targets;
diff --git a/src/server/game/AI/SmartScripts/SmartScript.h b/src/server/game/AI/SmartScripts/SmartScript.h
index 273d45ca7f1..4cbf439e489 100644
--- a/src/server/game/AI/SmartScripts/SmartScript.h
+++ b/src/server/game/AI/SmartScripts/SmartScript.h
@@ -190,6 +190,7 @@ class SmartScript
if (bounds.first == bounds.second)
return nullptr;
+
auto creatureItr = std::find_if(bounds.first, bounds.second, [](Map::CreatureBySpawnIdContainer::value_type const& pair) -> bool { return pair.second->IsAlive(); });
return creatureItr != bounds.second ? creatureItr->second : bounds.first->second;
}
@@ -243,10 +244,10 @@ class SmartScript
DecPhase(abs(p));
}
- void DecPhase(int32 p = 1)
- {
- if(mEventPhase > (uint32)p)
- mEventPhase -= (uint32)p;
+ void DecPhase(int32 p = 1)
+ {
+ if (mEventPhase > (uint32)p)
+ mEventPhase -= (uint32)p;
else
mEventPhase = 0;
}
diff --git a/src/server/game/AI/SmartScripts/SmartScriptMgr.cpp b/src/server/game/AI/SmartScripts/SmartScriptMgr.cpp
index 5214ef0eba3..e7782f46020 100644
--- a/src/server/game/AI/SmartScripts/SmartScriptMgr.cpp
+++ b/src/server/game/AI/SmartScripts/SmartScriptMgr.cpp
@@ -1235,6 +1235,7 @@ bool SmartAIMgr::IsEventValid(SmartScriptHolder& e)
case SMART_ACTION_ADD_GO_FLAG:
case SMART_ACTION_REMOVE_GO_FLAG:
case SMART_ACTION_SUMMON_CREATURE_GROUP:
+ case SMART_ACTION_RISE_UP:
break;
default:
TC_LOG_ERROR("sql.sql", "SmartAIMgr: Not handled action_type(%u), event_type(%u), Entry %d SourceType %u Event %u, skipped.", e.GetActionType(), e.GetEventType(), e.entryOrGuid, e.GetScriptType(), e.event_id);
diff --git a/src/server/game/AI/SmartScripts/SmartScriptMgr.h b/src/server/game/AI/SmartScripts/SmartScriptMgr.h
index 5929a488aef..324c04d87ce 100644
--- a/src/server/game/AI/SmartScripts/SmartScriptMgr.h
+++ b/src/server/game/AI/SmartScripts/SmartScriptMgr.h
@@ -540,8 +540,9 @@ enum SMART_ACTION
SMART_ACTION_GAME_EVENT_STOP = 111, // GameEventId
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_END = 114
+ SMART_ACTION_END = 115
};
struct SmartAction
diff --git a/src/server/game/Accounts/RBAC.h b/src/server/game/Accounts/RBAC.h
index 24854b3e11a..b7015d750ea 100644
--- a/src/server/game/Accounts/RBAC.h
+++ b/src/server/game/Accounts/RBAC.h
@@ -705,6 +705,7 @@ enum RBACPermissions
RBAC_PERM_COMMAND_MODIFY_XP = 798,
// 799 - 834 6.x only
RBAC_PERM_COMMAND_DEBUG_LOADCELLS = 835,
+ RBAC_PERM_COMMAND_DEBUG_BOUNDARY = 836,
// custom permissions 1000+
RBAC_PERM_MAX
diff --git a/src/server/game/Achievements/AchievementMgr.cpp b/src/server/game/Achievements/AchievementMgr.cpp
index 0e2624e234c..961b99b71a8 100644
--- a/src/server/game/Achievements/AchievementMgr.cpp
+++ b/src/server/game/Achievements/AchievementMgr.cpp
@@ -1952,7 +1952,7 @@ void AchievementMgr::CompletedAchievement(AchievementEntry const* achiev
//! Since no common attributes were found, (not even in titleRewardFlags field)
//! we explicitly check by ID. Maybe in the future we could move the achievement_reward
//! condition fields to the condition system.
- if (uint32 titleId = reward->titleId[achievement->ID == 1793 ? GetOwner()->getGender() : (GetOwner()->GetTeam() == ALLIANCE ? 0 : 1)])
+ if (uint32 titleId = reward->titleId[achievement->ID == 1793 ? GetOwner()->GetByteValue(PLAYER_BYTES_3, 0) : (GetOwner()->GetTeam() == ALLIANCE ? 0 : 1)])
if (CharTitlesEntry const* titleEntry = sCharTitlesStore.LookupEntry(titleId))
GetOwner()->SetTitle(titleEntry);
@@ -3234,7 +3234,7 @@ void AchievementGlobalMgr::LoadAchievementCriteriaData()
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);
else
- scriptId = sObjectMgr->GetScriptId(scriptName.c_str());
+ scriptId = sObjectMgr->GetScriptId(scriptName);
}
AchievementCriteriaData data(dataType, fields[2].GetUInt32(), fields[3].GetUInt32(), scriptId);
diff --git a/src/server/game/AuctionHouse/AuctionHouseMgr.cpp b/src/server/game/AuctionHouse/AuctionHouseMgr.cpp
index 2e97ba1064c..04cbf41d810 100644
--- a/src/server/game/AuctionHouse/AuctionHouseMgr.cpp
+++ b/src/server/game/AuctionHouse/AuctionHouseMgr.cpp
@@ -79,7 +79,7 @@ uint32 AuctionHouseMgr::GetAuctionDeposit(AuctionHouseEntry const* entry, uint32
uint32 MSV = pItem->GetTemplate()->SellPrice;
if (MSV <= 0)
- return AH_MINIMUM_DEPOSIT;
+ return AH_MINIMUM_DEPOSIT * sWorld->getRate(RATE_AUCTION_DEPOSIT);
float multiplier = CalculatePct(float(entry->depositPercent), 3);
uint32 timeHr = (((time / 60) / 60) / 12);
@@ -101,8 +101,8 @@ uint32 AuctionHouseMgr::GetAuctionDeposit(AuctionHouseEntry const* entry, uint32
TC_LOG_DEBUG("auctionHouse", "Deposit: %u", deposit);
TC_LOG_DEBUG("auctionHouse", "Deposit rm: %f", remainderbase * count);
- if (deposit < AH_MINIMUM_DEPOSIT)
- return AH_MINIMUM_DEPOSIT;
+ if (deposit < AH_MINIMUM_DEPOSIT * sWorld->getRate(RATE_AUCTION_DEPOSIT))
+ return AH_MINIMUM_DEPOSIT * sWorld->getRate(RATE_AUCTION_DEPOSIT);
else
return deposit;
}
diff --git a/src/server/game/AuctionHouseBot/AuctionHouseBot.cpp b/src/server/game/AuctionHouseBot/AuctionHouseBot.cpp
index 4c4a3d8028f..e1ba9a64191 100644
--- a/src/server/game/AuctionHouseBot/AuctionHouseBot.cpp
+++ b/src/server/game/AuctionHouseBot/AuctionHouseBot.cpp
@@ -242,6 +242,22 @@ void AuctionBotConfig::GetConfigFromFile()
SetConfig(CONFIG_AHBOT_CLASS_TRADEGOOD_MAX_ITEM_LEVEL, "AuctionHouseBot.Class.TradeGood.ItemLevel.Max", 0);
SetConfig(CONFIG_AHBOT_CLASS_CONTAINER_MIN_ITEM_LEVEL, "AuctionHouseBot.Class.Container.ItemLevel.Min", 0);
SetConfig(CONFIG_AHBOT_CLASS_CONTAINER_MAX_ITEM_LEVEL, "AuctionHouseBot.Class.Container.ItemLevel.Max", 0);
+
+ SetConfig(CONFIG_AHBOT_CLASS_RANDOMSTACKRATIO_CONSUMABLE, "AuctionHouseBot.Class.RandomStackRatio.Consumable", 20);
+ SetConfig(CONFIG_AHBOT_CLASS_RANDOMSTACKRATIO_CONTAINER, "AuctionHouseBot.Class.RandomStackRatio.Container", 0);
+ SetConfig(CONFIG_AHBOT_CLASS_RANDOMSTACKRATIO_WEAPON, "AuctionHouseBot.Class.RandomStackRatio.Weapon", 0);
+ SetConfig(CONFIG_AHBOT_CLASS_RANDOMSTACKRATIO_GEM, "AuctionHouseBot.Class.RandomStackRatio.Gem", 20);
+ SetConfig(CONFIG_AHBOT_CLASS_RANDOMSTACKRATIO_ARMOR, "AuctionHouseBot.Class.RandomStackRatio.Armor", 0);
+ SetConfig(CONFIG_AHBOT_CLASS_RANDOMSTACKRATIO_REAGENT, "AuctionHouseBot.Class.RandomStackRatio.Reagent", 100);
+ SetConfig(CONFIG_AHBOT_CLASS_RANDOMSTACKRATIO_PROJECTILE, "AuctionHouseBot.Class.RandomStackRatio.Projectile", 100);
+ SetConfig(CONFIG_AHBOT_CLASS_RANDOMSTACKRATIO_TRADEGOOD, "AuctionHouseBot.Class.RandomStackRatio.TradeGood", 50);
+ SetConfig(CONFIG_AHBOT_CLASS_RANDOMSTACKRATIO_GENERIC, "AuctionHouseBot.Class.RandomStackRatio.Generic", 100);
+ SetConfig(CONFIG_AHBOT_CLASS_RANDOMSTACKRATIO_RECIPE, "AuctionHouseBot.Class.RandomStackRatio.Recipe", 0);
+ SetConfig(CONFIG_AHBOT_CLASS_RANDOMSTACKRATIO_QUIVER, "AuctionHouseBot.Class.RandomStackRatio.Quiver", 0);
+ SetConfig(CONFIG_AHBOT_CLASS_RANDOMSTACKRATIO_QUEST, "AuctionHouseBot.Class.RandomStackRatio.Quest", 100);
+ SetConfig(CONFIG_AHBOT_CLASS_RANDOMSTACKRATIO_KEY, "AuctionHouseBot.Class.RandomStackRatio.Key", 100);
+ SetConfig(CONFIG_AHBOT_CLASS_RANDOMSTACKRATIO_MISC, "AuctionHouseBot.Class.RandomStackRatio.Misc", 100);
+ SetConfig(CONFIG_AHBOT_CLASS_RANDOMSTACKRATIO_GLYPH, "AuctionHouseBot.Class.RandomStackRatio.Glyph", 0);
}
char const* AuctionBotConfig::GetHouseTypeName(AuctionHouseType houseType)
diff --git a/src/server/game/AuctionHouseBot/AuctionHouseBot.h b/src/server/game/AuctionHouseBot/AuctionHouseBot.h
index 63641fc7da2..87f76a17dcc 100644
--- a/src/server/game/AuctionHouseBot/AuctionHouseBot.h
+++ b/src/server/game/AuctionHouseBot/AuctionHouseBot.h
@@ -137,6 +137,21 @@ enum AuctionBotConfigUInt32Values
CONFIG_AHBOT_CLASS_TRADEGOOD_MAX_ITEM_LEVEL,
CONFIG_AHBOT_CLASS_CONTAINER_MIN_ITEM_LEVEL,
CONFIG_AHBOT_CLASS_CONTAINER_MAX_ITEM_LEVEL,
+ CONFIG_AHBOT_CLASS_RANDOMSTACKRATIO_CONSUMABLE,
+ CONFIG_AHBOT_CLASS_RANDOMSTACKRATIO_CONTAINER,
+ CONFIG_AHBOT_CLASS_RANDOMSTACKRATIO_WEAPON,
+ CONFIG_AHBOT_CLASS_RANDOMSTACKRATIO_GEM,
+ CONFIG_AHBOT_CLASS_RANDOMSTACKRATIO_ARMOR,
+ CONFIG_AHBOT_CLASS_RANDOMSTACKRATIO_REAGENT,
+ CONFIG_AHBOT_CLASS_RANDOMSTACKRATIO_PROJECTILE,
+ CONFIG_AHBOT_CLASS_RANDOMSTACKRATIO_TRADEGOOD,
+ CONFIG_AHBOT_CLASS_RANDOMSTACKRATIO_GENERIC,
+ CONFIG_AHBOT_CLASS_RANDOMSTACKRATIO_RECIPE,
+ CONFIG_AHBOT_CLASS_RANDOMSTACKRATIO_QUIVER,
+ CONFIG_AHBOT_CLASS_RANDOMSTACKRATIO_QUEST,
+ CONFIG_AHBOT_CLASS_RANDOMSTACKRATIO_KEY,
+ CONFIG_AHBOT_CLASS_RANDOMSTACKRATIO_MISC,
+ CONFIG_AHBOT_CLASS_RANDOMSTACKRATIO_GLYPH,
CONFIG_UINT32_AHBOT_UINT32_COUNT
};
diff --git a/src/server/game/AuctionHouseBot/AuctionHouseBotBuyer.cpp b/src/server/game/AuctionHouseBot/AuctionHouseBotBuyer.cpp
index 35f49cc0bbc..7f05cd2efd7 100644
--- a/src/server/game/AuctionHouseBot/AuctionHouseBotBuyer.cpp
+++ b/src/server/game/AuctionHouseBot/AuctionHouseBotBuyer.cpp
@@ -102,6 +102,10 @@ uint32 AuctionBotBuyer::GetItemInformation(BuyerConfiguration& config)
for (AuctionHouseObject::AuctionEntryMap::const_iterator itr = house->GetAuctionsBegin(); itr != house->GetAuctionsEnd(); ++itr)
{
AuctionEntry* entry = itr->second;
+
+ if (!entry->owner)
+ continue; // Skip auctions owned by AHBot
+
Item* item = sAuctionMgr->GetAItem(entry->itemGUIDLow);
if (!item)
continue;
@@ -135,10 +139,10 @@ uint32 AuctionBotBuyer::GetItemInformation(BuyerConfiguration& config)
itemInfo.MinBuyPrice = std::min(itemInfo.MinBuyPrice, itemBuyPrice);
}
- // Add/update to EligibleItems if:
- // has a bid by player or
- // has no bids and not owned by bot
- if ((entry->bid && entry->bidder) || (entry->owner && !entry->bid))
+ // Add/update EligibleItems if:
+ // * no bid
+ // * bid from player
+ if (!entry->bid || entry->bidder)
{
config.EligibleItems[entry->Id].LastExist = now;
config.EligibleItems[entry->Id].AuctionId = entry->Id;
diff --git a/src/server/game/AuctionHouseBot/AuctionHouseBotSeller.cpp b/src/server/game/AuctionHouseBot/AuctionHouseBotSeller.cpp
index 4880ace9e9c..41ca008047f 100644
--- a/src/server/game/AuctionHouseBot/AuctionHouseBotSeller.cpp
+++ b/src/server/game/AuctionHouseBot/AuctionHouseBotSeller.cpp
@@ -533,6 +533,23 @@ void AuctionBotSeller::LoadItemsQuantity(SellerConfiguration& config)
config.SetItemsQuantityPerClass(AUCTION_QUALITY_YELLOW, ITEM_CLASS_GLYPH, 0);
// ============================================================================================
+ // Set Stack Quantities
+ config.SetRandomStackRatioPerClass(ITEM_CLASS_CONSUMABLE, sAuctionBotConfig->GetConfig(CONFIG_AHBOT_CLASS_RANDOMSTACKRATIO_CONSUMABLE));
+ config.SetRandomStackRatioPerClass(ITEM_CLASS_CONTAINER, sAuctionBotConfig->GetConfig(CONFIG_AHBOT_CLASS_RANDOMSTACKRATIO_CONTAINER));
+ config.SetRandomStackRatioPerClass(ITEM_CLASS_WEAPON, sAuctionBotConfig->GetConfig(CONFIG_AHBOT_CLASS_RANDOMSTACKRATIO_WEAPON));
+ config.SetRandomStackRatioPerClass(ITEM_CLASS_GEM, sAuctionBotConfig->GetConfig(CONFIG_AHBOT_CLASS_RANDOMSTACKRATIO_GEM));
+ config.SetRandomStackRatioPerClass(ITEM_CLASS_ARMOR, sAuctionBotConfig->GetConfig(CONFIG_AHBOT_CLASS_RANDOMSTACKRATIO_ARMOR));
+ config.SetRandomStackRatioPerClass(ITEM_CLASS_REAGENT, sAuctionBotConfig->GetConfig(CONFIG_AHBOT_CLASS_RANDOMSTACKRATIO_REAGENT));
+ config.SetRandomStackRatioPerClass(ITEM_CLASS_PROJECTILE, sAuctionBotConfig->GetConfig(CONFIG_AHBOT_CLASS_RANDOMSTACKRATIO_PROJECTILE));
+ config.SetRandomStackRatioPerClass(ITEM_CLASS_TRADE_GOODS, sAuctionBotConfig->GetConfig(CONFIG_AHBOT_CLASS_RANDOMSTACKRATIO_TRADEGOOD));
+ config.SetRandomStackRatioPerClass(ITEM_CLASS_GENERIC, sAuctionBotConfig->GetConfig(CONFIG_AHBOT_CLASS_RANDOMSTACKRATIO_GENERIC));
+ config.SetRandomStackRatioPerClass(ITEM_CLASS_RECIPE, sAuctionBotConfig->GetConfig(CONFIG_AHBOT_CLASS_RANDOMSTACKRATIO_RECIPE));
+ config.SetRandomStackRatioPerClass(ITEM_CLASS_QUIVER, sAuctionBotConfig->GetConfig(CONFIG_AHBOT_CLASS_RANDOMSTACKRATIO_QUIVER));
+ config.SetRandomStackRatioPerClass(ITEM_CLASS_QUEST, sAuctionBotConfig->GetConfig(CONFIG_AHBOT_CLASS_RANDOMSTACKRATIO_QUEST));
+ config.SetRandomStackRatioPerClass(ITEM_CLASS_KEY, sAuctionBotConfig->GetConfig(CONFIG_AHBOT_CLASS_RANDOMSTACKRATIO_KEY));
+ config.SetRandomStackRatioPerClass(ITEM_CLASS_MISCELLANEOUS, sAuctionBotConfig->GetConfig(CONFIG_AHBOT_CLASS_RANDOMSTACKRATIO_MISC));
+ config.SetRandomStackRatioPerClass(ITEM_CLASS_GLYPH, sAuctionBotConfig->GetConfig(CONFIG_AHBOT_CLASS_RANDOMSTACKRATIO_GLYPH));
+
// Set the best value to get nearest amount of items wanted
for (uint32 j = 0; j < MAX_AUCTION_QUALITY; ++j)
{
@@ -719,6 +736,15 @@ void AuctionBotSeller::SetPricesOfItem(ItemTemplate const* itemProto, SellerConf
bidp = urand(basePrice - range, basePrice + range) + 1;
}
+// Determines the stack size to use for the item
+uint32 AuctionBotSeller::GetStackSizeForItem(ItemTemplate const* itemProto, SellerConfiguration& config) const
+{
+ if (config.GetRandomStackRatioPerClass(ItemClass(itemProto->Class)) > urand(0, 99))
+ return urand(1, itemProto->GetMaxStackSize());
+ else
+ return 1;
+}
+
// Determine the multiplier for the sell price of any weapon without a buy price.
uint32 AuctionBotSeller::GetSellModifier(ItemTemplate const* prototype)
{
@@ -952,7 +978,7 @@ void AuctionBotSeller::AddNewAuctions(SellerConfiguration& config)
continue;
}
- uint32 stackCount = urand(1, prototype->GetMaxStackSize());
+ uint32 stackCount = GetStackSizeForItem(prototype, config);
Item* item = Item::CreateItem(itemId, stackCount);
if (!item)
diff --git a/src/server/game/AuctionHouseBot/AuctionHouseBotSeller.h b/src/server/game/AuctionHouseBot/AuctionHouseBotSeller.h
index 4f293e03d9a..dd82b0f3dda 100644
--- a/src/server/game/AuctionHouseBot/AuctionHouseBotSeller.h
+++ b/src/server/game/AuctionHouseBot/AuctionHouseBotSeller.h
@@ -33,12 +33,13 @@ typedef std::vector> AllItemsArray;
struct SellerItemClassInfo
{
- SellerItemClassInfo(): AmountOfItems(0), MissItems(0), Quantity(0), PriceRatio(0) {}
+ SellerItemClassInfo(): AmountOfItems(0), MissItems(0), Quantity(0), PriceRatio(0), RandomStackRatio(100) {}
uint32 AmountOfItems;
uint32 MissItems;
uint32 Quantity;
uint32 PriceRatio;
+ uint32 RandomStackRatio;
};
struct SellerItemInfo
@@ -102,6 +103,8 @@ public:
uint32 GetPriceRatioPerQuality(AuctionQuality quality) const { return _ItemInfo[quality].PriceRatio; }
void SetPriceRatioPerClass(ItemClass item, uint32 value) { _ItemInfo[0].ItemClassInfos[item].PriceRatio = value; }
uint32 GetPriceRatioPerClass(ItemClass item) const { return _ItemInfo[0].ItemClassInfos[item].PriceRatio; }
+ void SetRandomStackRatioPerClass(ItemClass item, uint32 value) { _ItemInfo[0].ItemClassInfos[item].RandomStackRatio = value; }
+ uint32 GetRandomStackRatioPerClass(ItemClass item) const { return _ItemInfo[0].ItemClassInfos[item].RandomStackRatio; }
private:
AuctionHouseType _houseType;
@@ -139,6 +142,7 @@ private:
uint32 SetStat(SellerConfiguration& config);
bool GetItemsToSell(SellerConfiguration& config, ItemsToSellArray& itemsToSellArray, AllItemsArray const& addedItem);
void SetPricesOfItem(ItemTemplate const* itemProto, SellerConfiguration& config, uint32& buyp, uint32& bidp, uint32 stackcnt);
+ uint32 GetStackSizeForItem(ItemTemplate const* itemProto, SellerConfiguration& config) const;
void LoadItemsQuantity(SellerConfiguration& config);
static uint32 GetBuyModifier(ItemTemplate const* prototype);
static uint32 GetSellModifier(ItemTemplate const* itemProto);
diff --git a/src/server/game/Battlegrounds/ArenaTeam.cpp b/src/server/game/Battlegrounds/ArenaTeam.cpp
index 91acee2fcd3..4c86e96e5ef 100644
--- a/src/server/game/Battlegrounds/ArenaTeam.cpp
+++ b/src/server/game/Battlegrounds/ArenaTeam.cpp
@@ -659,7 +659,7 @@ int32 ArenaTeam::GetMatchmakerRatingMod(uint32 ownRating, uint32 opponentRating,
*/
// Real rating modification
- mod *= 24.0f;
+ mod *= sWorld->getFloatConfig(CONFIG_ARENA_MATCHMAKER_RATING_MODIFIER);
return (int32)ceil(mod);
}
@@ -669,21 +669,27 @@ int32 ArenaTeam::GetRatingMod(uint32 ownRating, uint32 opponentRating, bool won
// 'Chance' calculation - to beat the opponent
// This is a simulation. Not much info on how it really works
float chance = GetChanceAgainst(ownRating, opponentRating);
- float won_mod = (won) ? 1.0f : 0.0f;
// Calculate the rating modification
float mod;
/// @todo Replace this hack with using the confidence factor (limiting the factor to 2.0f)
- if (won && ownRating < 1300)
+ if (won)
{
- if (ownRating < 1000)
- mod = 48.0f * (won_mod - chance);
+ if (ownRating < 1300)
+ {
+ float win_rating_modifier1 = sWorld->getFloatConfig(CONFIG_ARENA_WIN_RATING_MODIFIER_1);
+
+ if (ownRating < 1000)
+ mod = win_rating_modifier1 * (1.0f - chance);
+ else
+ mod = ((win_rating_modifier1 / 2.0f) + ((win_rating_modifier1 / 2.0f) * (1300.0f - float(ownRating)) / 300.0f)) * (1.0f - chance);
+ }
else
- mod = (24.0f + (24.0f * (1300.0f - float(ownRating)) / 300.0f)) * (won_mod - chance);
+ mod = sWorld->getFloatConfig(CONFIG_ARENA_WIN_RATING_MODIFIER_2) * (1.0f - chance);
}
else
- mod = 24.0f * (won_mod - chance);
+ mod = sWorld->getFloatConfig(CONFIG_ARENA_LOSE_RATING_MODIFIER) * (-chance);
return (int32)ceil(mod);
}
diff --git a/src/server/game/Battlegrounds/Battleground.cpp b/src/server/game/Battlegrounds/Battleground.cpp
index 46282b07997..b6a256eb204 100644
--- a/src/server/game/Battlegrounds/Battleground.cpp
+++ b/src/server/game/Battlegrounds/Battleground.cpp
@@ -313,6 +313,15 @@ inline void Battleground::_ProcessOfflineQueue()
{
if (itr->second.OfflineRemoveTime <= sWorld->GetGameTime())
{
+ if (isBattleground() && sWorld->getBoolConfig(CONFIG_BATTLEGROUND_TRACK_DESERTERS) &&
+ (GetStatus() == STATUS_IN_PROGRESS || GetStatus() == STATUS_WAIT_JOIN))
+ {
+ PreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_INS_DESERTER_TRACK);
+ stmt->setUInt32(0, itr->first.GetCounter());
+ stmt->setUInt8(1, BG_DESERTION_TYPE_OFFLINE);
+ CharacterDatabase.Execute(stmt);
+ }
+
RemovePlayerAtLeave(itr->first, true, true);// remove player from BG
m_OfflineQueue.pop_front(); // remove from offline queue
//do not use itr for anything, because it is erased in RemovePlayerAtLeave()
@@ -822,19 +831,20 @@ void Battleground::EndBattleground(uint32 winner)
stmt = CharacterDatabase.GetPreparedStatement(CHAR_INS_PVPSTATS_PLAYER);
BattlegroundScoreMap::const_iterator score = PlayerScores.find(player->GetGUID().GetCounter());
- stmt->setUInt32(0, battlegroundId);
- stmt->setUInt32(1, player->GetGUID().GetCounter());
- stmt->setUInt32(2, score->second->GetKillingBlows());
- stmt->setUInt32(3, score->second->GetDeaths());
- stmt->setUInt32(4, score->second->GetHonorableKills());
- stmt->setUInt32(5, score->second->GetBonusHonor());
- stmt->setUInt32(6, score->second->GetDamageDone());
- stmt->setUInt32(7, score->second->GetHealingDone());
- stmt->setUInt32(8, score->second->GetAttr1());
- stmt->setUInt32(9, score->second->GetAttr2());
- stmt->setUInt32(10, score->second->GetAttr3());
- stmt->setUInt32(11, score->second->GetAttr4());
- stmt->setUInt32(12, score->second->GetAttr5());
+ stmt->setUInt32(0, battlegroundId);
+ stmt->setUInt32(1, player->GetGUID().GetCounter());
+ stmt->setBool (2, team == winner);
+ stmt->setUInt32(3, score->second->GetKillingBlows());
+ stmt->setUInt32(4, score->second->GetDeaths());
+ stmt->setUInt32(5, score->second->GetHonorableKills());
+ stmt->setUInt32(6, score->second->GetBonusHonor());
+ stmt->setUInt32(7, score->second->GetDamageDone());
+ stmt->setUInt32(8, score->second->GetHealingDone());
+ stmt->setUInt32(9, score->second->GetAttr1());
+ stmt->setUInt32(10, score->second->GetAttr2());
+ stmt->setUInt32(11, score->second->GetAttr3());
+ stmt->setUInt32(12, score->second->GetAttr4());
+ stmt->setUInt32(13, score->second->GetAttr5());
CharacterDatabase.Execute(stmt);
}
@@ -1237,48 +1247,58 @@ void Battleground::RemoveFromBGFreeSlotQueue()
// returns the number how many players can join battleground to MaxPlayersPerTeam
uint32 Battleground::GetFreeSlotsForTeam(uint32 Team) const
{
- // if BG is starting ... invite anyone
- if (GetStatus() == STATUS_WAIT_JOIN)
+ // if BG is starting and CONFIG_BATTLEGROUND_INVITATION_TYPE == BG_QUEUE_INVITATION_TYPE_NO_BALANCE, invite anyone
+ if (GetStatus() == STATUS_WAIT_JOIN && sWorld->getIntConfig(CONFIG_BATTLEGROUND_INVITATION_TYPE) == BG_QUEUE_INVITATION_TYPE_NO_BALANCE)
return (GetInvitedCount(Team) < GetMaxPlayersPerTeam()) ? GetMaxPlayersPerTeam() - GetInvitedCount(Team) : 0;
- // if BG is already started .. do not allow to join too much players of one faction
- uint32 otherTeam;
- uint32 otherIn;
+
+ // if BG is already started or CONFIG_BATTLEGROUND_INVITATION_TYPE != BG_QUEUE_INVITATION_TYPE_NO_BALANCE, do not allow to join too much players of one faction
+ uint32 otherTeamInvitedCount;
+ uint32 thisTeamInvitedCount;
+ uint32 otherTeamPlayersCount;
+ uint32 thisTeamPlayersCount;
+
if (Team == ALLIANCE)
{
- otherTeam = GetInvitedCount(HORDE);
- otherIn = GetPlayersCountByTeam(HORDE);
+ thisTeamInvitedCount = GetInvitedCount(ALLIANCE);
+ otherTeamInvitedCount = GetInvitedCount(HORDE);
+ thisTeamPlayersCount = GetPlayersCountByTeam(ALLIANCE);
+ otherTeamPlayersCount = GetPlayersCountByTeam(HORDE);
}
else
{
- otherTeam = GetInvitedCount(ALLIANCE);
- otherIn = GetPlayersCountByTeam(ALLIANCE);
+ thisTeamInvitedCount = GetInvitedCount(HORDE);
+ otherTeamInvitedCount = GetInvitedCount(ALLIANCE);
+ thisTeamPlayersCount = GetPlayersCountByTeam(HORDE);
+ otherTeamPlayersCount = GetPlayersCountByTeam(ALLIANCE);
}
- if (GetStatus() == STATUS_IN_PROGRESS)
+ if (GetStatus() == STATUS_IN_PROGRESS || GetStatus() == STATUS_WAIT_JOIN)
{
// difference based on ppl invited (not necessarily entered battle)
// default: allow 0
uint32 diff = 0;
- // allow join one person if the sides are equal (to fill up bg to minplayersperteam)
- if (otherTeam == GetInvitedCount(Team))
+
+ // allow join one person if the sides are equal (to fill up bg to minPlayerPerTeam)
+ if (otherTeamInvitedCount == thisTeamInvitedCount)
diff = 1;
// allow join more ppl if the other side has more players
- else if (otherTeam > GetInvitedCount(Team))
- diff = otherTeam - GetInvitedCount(Team);
+ else if (otherTeamInvitedCount > thisTeamInvitedCount)
+ diff = otherTeamInvitedCount - thisTeamInvitedCount;
// difference based on max players per team (don't allow inviting more)
- uint32 diff2 = (GetInvitedCount(Team) < GetMaxPlayersPerTeam()) ? GetMaxPlayersPerTeam() - GetInvitedCount(Team) : 0;
+ uint32 diff2 = (thisTeamInvitedCount < GetMaxPlayersPerTeam()) ? GetMaxPlayersPerTeam() - thisTeamInvitedCount : 0;
+
// difference based on players who already entered
// default: allow 0
uint32 diff3 = 0;
- // allow join one person if the sides are equal (to fill up bg minplayersperteam)
- if (otherIn == GetPlayersCountByTeam(Team))
+ // allow join one person if the sides are equal (to fill up bg minPlayerPerTeam)
+ if (otherTeamPlayersCount == thisTeamPlayersCount)
diff3 = 1;
// allow join more ppl if the other side has more players
- else if (otherIn > GetPlayersCountByTeam(Team))
- diff3 = otherIn - GetPlayersCountByTeam(Team);
+ else if (otherTeamPlayersCount > thisTeamPlayersCount)
+ diff3 = otherTeamPlayersCount - thisTeamPlayersCount;
// or other side has less than minPlayersPerTeam
- else if (GetInvitedCount(Team) <= GetMinPlayersPerTeam())
- diff3 = GetMinPlayersPerTeam() - GetInvitedCount(Team) + 1;
+ else if (thisTeamInvitedCount <= GetMinPlayersPerTeam())
+ diff3 = GetMinPlayersPerTeam() - thisTeamInvitedCount + 1;
// return the minimum of the 3 differences
@@ -1421,7 +1441,7 @@ bool Battleground::AddObject(uint32 type, uint32 entry, float x, float y, float
// and when loading it (in go::LoadFromDB()), a new guid would be assigned to the object, and a new object would be created
// So we must create it specific for this instance
GameObject* go = new GameObject;
- if (!go->Create(map->GenerateLowGuid(), entry, GetBgMap(),
+ if (!go->Create(GetBgMap()->GenerateLowGuid(), entry, GetBgMap(),
PHASEMASK_NORMAL, x, y, z, o, rotation0, rotation1, rotation2, rotation3, 100, goState))
{
TC_LOG_ERROR("bg.battleground", "Battleground::AddObject: cannot create gameobject (entry: %u) for BG (map: %u, instance id: %u)!",
diff --git a/src/server/game/Battlegrounds/Battleground.h b/src/server/game/Battlegrounds/Battleground.h
index 3e664637aae..f06fbc6c1c3 100644
--- a/src/server/game/Battlegrounds/Battleground.h
+++ b/src/server/game/Battlegrounds/Battleground.h
@@ -40,6 +40,15 @@ class BattlegroundMap;
struct PvPDifficultyEntry;
struct WorldSafeLocsEntry;
+enum BattlegroundDesertionType
+{
+ BG_DESERTION_TYPE_LEAVE_BG = 0, // player leaves the BG
+ BG_DESERTION_TYPE_OFFLINE = 1, // player is kicked from BG because offline
+ BG_DESERTION_TYPE_LEAVE_QUEUE = 2, // player is invited to join and refuses to do it
+ BG_DESERTION_TYPE_NO_ENTER_BUTTON = 3, // player is invited to join and do nothing (time expires)
+ BG_DESERTION_TYPE_INVITE_LOGOUT = 4, // player is invited to join and logs out
+};
+
enum BattlegroundCriteriaId
{
BG_CRITERIA_CHECK_RESILIENT_VICTORY,
diff --git a/src/server/game/Battlegrounds/BattlegroundMgr.cpp b/src/server/game/Battlegrounds/BattlegroundMgr.cpp
index 8932ae77b68..067083b64eb 100644
--- a/src/server/game/Battlegrounds/BattlegroundMgr.cpp
+++ b/src/server/game/Battlegrounds/BattlegroundMgr.cpp
@@ -803,7 +803,7 @@ void BattlegroundMgr::LoadBattlegroundTemplates()
float dist = fields[9].GetFloat();
bgTemplate.MaxStartDistSq = dist * dist;
bgTemplate.Weight = fields[10].GetUInt8();
- bgTemplate.ScriptId = sObjectMgr->GetScriptId(fields[11].GetCString());
+ bgTemplate.ScriptId = sObjectMgr->GetScriptId(fields[11].GetString());
bgTemplate.BattlemasterEntry = bl;
if (bgTemplate.MaxPlayersPerTeam == 0 || bgTemplate.MinPlayersPerTeam > bgTemplate.MaxPlayersPerTeam)
diff --git a/src/server/game/Battlegrounds/BattlegroundQueue.cpp b/src/server/game/Battlegrounds/BattlegroundQueue.cpp
index e5409afea66..86f0b15ffd5 100644
--- a/src/server/game/Battlegrounds/BattlegroundQueue.cpp
+++ b/src/server/game/Battlegrounds/BattlegroundQueue.cpp
@@ -498,24 +498,51 @@ void BattlegroundQueue::FillPlayersToBG(Battleground* bg, BattlegroundBracketId
{
int32 hordeFree = bg->GetFreeSlotsForTeam(HORDE);
int32 aliFree = bg->GetFreeSlotsForTeam(ALLIANCE);
+ uint32 aliCount = m_QueuedGroups[bracket_id][BG_QUEUE_NORMAL_ALLIANCE].size();
+ uint32 hordeCount = m_QueuedGroups[bracket_id][BG_QUEUE_NORMAL_HORDE].size();
+
+ // try to get even teams
+ if (sWorld->getIntConfig(CONFIG_BATTLEGROUND_INVITATION_TYPE) == BG_QUEUE_INVITATION_TYPE_EVEN)
+ {
+ // check if the teams are even
+ if (hordeFree == 1 && aliFree == 1)
+ {
+ // if we are here, the teams have the same amount of players
+ // then we have to allow to join the same amount of players
+ int32 hordeExtra = hordeCount - aliCount;
+ int32 aliExtra = aliCount - hordeCount;
+
+ hordeExtra = std::max(hordeExtra, 0);
+ aliExtra = std::max(aliExtra, 0);
+
+ if (aliCount != hordeCount)
+ {
+ aliFree -= aliExtra;
+ hordeFree -= hordeExtra;
+
+ aliFree = std::max(aliFree, 0);
+ hordeFree = std::max(hordeFree, 0);
+ }
+ }
+ }
//iterator for iterating through bg queue
GroupsQueueType::const_iterator Ali_itr = m_QueuedGroups[bracket_id][BG_QUEUE_NORMAL_ALLIANCE].begin();
//count of groups in queue - used to stop cycles
- uint32 aliCount = m_QueuedGroups[bracket_id][BG_QUEUE_NORMAL_ALLIANCE].size();
+
//index to queue which group is current
uint32 aliIndex = 0;
for (; aliIndex < aliCount && m_SelectionPools[TEAM_ALLIANCE].AddGroup((*Ali_itr), aliFree); aliIndex++)
++Ali_itr;
//the same thing for horde
GroupsQueueType::const_iterator Horde_itr = m_QueuedGroups[bracket_id][BG_QUEUE_NORMAL_HORDE].begin();
- uint32 hordeCount = m_QueuedGroups[bracket_id][BG_QUEUE_NORMAL_HORDE].size();
+
uint32 hordeIndex = 0;
for (; hordeIndex < hordeCount && m_SelectionPools[TEAM_HORDE].AddGroup((*Horde_itr), hordeFree); hordeIndex++)
++Horde_itr;
//if ofc like BG queue invitation is set in config, then we are happy
- if (sWorld->getIntConfig(CONFIG_BATTLEGROUND_INVITATION_TYPE) == 0)
+ if (sWorld->getIntConfig(CONFIG_BATTLEGROUND_INVITATION_TYPE) == BG_QUEUE_INVITATION_TYPE_NO_BALANCE)
return;
/*
@@ -650,7 +677,7 @@ bool BattlegroundQueue::CheckNormalMatch(Battleground* /*bg_template*/, Battlegr
uint32 j = TEAM_ALLIANCE;
if (m_SelectionPools[TEAM_HORDE].GetPlayerCount() < m_SelectionPools[TEAM_ALLIANCE].GetPlayerCount())
j = TEAM_HORDE;
- if (sWorld->getIntConfig(CONFIG_BATTLEGROUND_INVITATION_TYPE) != 0
+ if (sWorld->getIntConfig(CONFIG_BATTLEGROUND_INVITATION_TYPE) != BG_QUEUE_INVITATION_TYPE_NO_BALANCE
&& m_SelectionPools[TEAM_HORDE].GetPlayerCount() >= minPlayers && m_SelectionPools[TEAM_ALLIANCE].GetPlayerCount() >= minPlayers)
{
//we will try to invite more groups to team with less players indexed by j
@@ -1042,6 +1069,16 @@ bool BGQueueRemoveEvent::Execute(uint64 /*e_time*/, uint32 /*p_time*/)
BattlegroundQueue &bgQueue = sBattlegroundMgr->GetBattlegroundQueue(m_BgQueueTypeId);
if (bgQueue.IsPlayerInvited(m_PlayerGuid, m_BgInstanceGUID, m_RemoveTime))
{
+ // track if player leaves the BG by not clicking enter button
+ if (bg && bg->isBattleground() && sWorld->getBoolConfig(CONFIG_BATTLEGROUND_TRACK_DESERTERS) &&
+ (bg->GetStatus() == STATUS_IN_PROGRESS || bg->GetStatus() == STATUS_WAIT_JOIN))
+ {
+ PreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_INS_DESERTER_TRACK);
+ stmt->setUInt32(0, player->GetGUID().GetCounter());
+ stmt->setUInt8(1, BG_DESERTION_TYPE_NO_ENTER_BUTTON);
+ CharacterDatabase.Execute(stmt);
+ }
+
TC_LOG_DEBUG("bg.battleground", "Battleground: removing player %u from bg queue for instance %u because of not pressing enter battle in time.", player->GetGUID().GetCounter(), m_BgInstanceGUID);
player->RemoveBattlegroundQueueId(m_BgQueueTypeId);
diff --git a/src/server/game/Battlegrounds/BattlegroundQueue.h b/src/server/game/Battlegrounds/BattlegroundQueue.h
index 6a5b1110681..9291adf9e8d 100644
--- a/src/server/game/Battlegrounds/BattlegroundQueue.h
+++ b/src/server/game/Battlegrounds/BattlegroundQueue.h
@@ -64,6 +64,13 @@ enum BattlegroundQueueGroupTypes
};
#define BG_QUEUE_GROUP_TYPES_COUNT 4
+enum BattlegroundQueueInvitationType
+{
+ BG_QUEUE_INVITATION_TYPE_NO_BALANCE = 0, // no balance: N+M vs N players
+ BG_QUEUE_INVITATION_TYPE_BALANCED = 1, // teams balanced: N+1 vs N players
+ BG_QUEUE_INVITATION_TYPE_EVEN = 2 // teams even: N vs N players
+};
+
class Battleground;
class BattlegroundQueue
{
diff --git a/src/server/game/Battlegrounds/Zones/BattlegroundAB.cpp b/src/server/game/Battlegrounds/Zones/BattlegroundAB.cpp
index 011bc57ab0b..77d0bb9f1a2 100644
--- a/src/server/game/Battlegrounds/Zones/BattlegroundAB.cpp
+++ b/src/server/game/Battlegrounds/Zones/BattlegroundAB.cpp
@@ -309,7 +309,7 @@ int32 BattlegroundAB::_GetNodeNameId(uint8 node)
case BG_AB_NODE_LUMBER_MILL:return LANG_BG_AB_NODE_LUMBER_MILL;
case BG_AB_NODE_GOLD_MINE: return LANG_BG_AB_NODE_GOLD_MINE;
default:
- ASSERT(false);
+ ABORT();
}
return 0;
}
diff --git a/src/server/game/Battlegrounds/Zones/BattlegroundAV.cpp b/src/server/game/Battlegrounds/Zones/BattlegroundAV.cpp
index 98953005aec..8446bc18222 100644
--- a/src/server/game/Battlegrounds/Zones/BattlegroundAV.cpp
+++ b/src/server/game/Battlegrounds/Zones/BattlegroundAV.cpp
@@ -789,7 +789,7 @@ BG_AV_Nodes BattlegroundAV::GetNodeThroughObject(uint32 object)
if (object == BG_AV_OBJECT_FLAG_N_SNOWFALL_GRAVE)
return BG_AV_NODES_SNOWFALL_GRAVE;
TC_LOG_ERROR("bg.battleground", "BattlegroundAV: ERROR! GetPlace got a wrong object :(");
- ASSERT(false);
+ ABORT();
return BG_AV_Nodes(0);
}
@@ -827,7 +827,7 @@ uint32 BattlegroundAV::GetObjectThroughNode(BG_AV_Nodes node)
else if (m_Nodes[node].Owner == AV_NEUTRAL_TEAM)
return BG_AV_OBJECT_FLAG_N_SNOWFALL_GRAVE;
TC_LOG_ERROR("bg.battleground", "BattlegroundAV: Error! GetPlaceNode couldn't resolve node %i", node);
- ASSERT(false);
+ ABORT();
return 0;
}
@@ -1402,22 +1402,22 @@ void BattlegroundAV::AssaultNode(BG_AV_Nodes node, uint16 team)
if (m_Nodes[node].TotalOwner == team)
{
TC_LOG_FATAL("bg.battleground", "Assaulting team is TotalOwner of node");
- ASSERT(false);
+ ABORT();
}
if (m_Nodes[node].Owner == team)
{
TC_LOG_FATAL("bg.battleground", "Assaulting team is owner of node");
- ASSERT(false);
+ ABORT();
}
if (m_Nodes[node].State == POINT_DESTROYED)
{
TC_LOG_FATAL("bg.battleground", "Destroyed node is being assaulted");
- ASSERT(false);
+ ABORT();
}
if (m_Nodes[node].State == POINT_ASSAULTED && m_Nodes[node].TotalOwner) //only assault an assaulted node if no totalowner exists
{
TC_LOG_FATAL("bg.battleground", "Assault on an not assaulted node with total owner");
- ASSERT(false);
+ ABORT();
}
//the timer gets another time, if the previous owner was 0 == Neutral
m_Nodes[node].Timer = (m_Nodes[node].PrevOwner)? BG_AV_CAPTIME : BG_AV_SNOWFALL_FIRSTCAP;
diff --git a/src/server/game/Battlegrounds/Zones/BattlegroundEY.cpp b/src/server/game/Battlegrounds/Zones/BattlegroundEY.cpp
index fcd605e8da5..c6efdfcd1fd 100644
--- a/src/server/game/Battlegrounds/Zones/BattlegroundEY.cpp
+++ b/src/server/game/Battlegrounds/Zones/BattlegroundEY.cpp
@@ -162,6 +162,7 @@ void BattlegroundEY::CheckSomeoneJoinedPoint()
for (uint8 i = 0; i < EY_POINTS_MAX; ++i)
{
obj = GetBgMap()->GetGameObject(BgObjects[BG_EY_OBJECT_TOWER_CAP_FEL_REAVER + i]);
+
if (obj)
{
uint8 j = 0;
@@ -202,6 +203,7 @@ void BattlegroundEY::CheckSomeoneLeftPoint()
for (uint8 i = 0; i < EY_POINTS_MAX; ++i)
{
obj = GetBgMap()->GetGameObject(BgObjects[BG_EY_OBJECT_TOWER_CAP_FEL_REAVER + i]);
+
if (obj)
{
uint8 j = 0;
@@ -589,6 +591,7 @@ void BattlegroundEY::RespawnFlagAfterDrop()
RespawnFlag(true);
GameObject* obj = GetBgMap()->GetGameObject(GetDroppedFlagGUID());
+
if (obj)
obj->Delete();
else
diff --git a/src/server/game/Battlegrounds/Zones/BattlegroundSA.cpp b/src/server/game/Battlegrounds/Zones/BattlegroundSA.cpp
index 920c503f287..8176ddc8012 100644
--- a/src/server/game/Battlegrounds/Zones/BattlegroundSA.cpp
+++ b/src/server/game/Battlegrounds/Zones/BattlegroundSA.cpp
@@ -744,7 +744,7 @@ bool BattlegroundSA::CanInteractWithObject(uint32 objectId)
return false;
break;
default:
- ASSERT(false);
+ ABORT();
break;
}
@@ -877,7 +877,7 @@ void BattlegroundSA::CaptureGraveyard(BG_SA_Graveyards i, Player* Source)
break;
default:
- ASSERT(false);
+ ABORT();
break;
};
}
diff --git a/src/server/game/Chat/Chat.cpp b/src/server/game/Chat/Chat.cpp
index a07cd851580..4675fda810e 100644
--- a/src/server/game/Chat/Chat.cpp
+++ b/src/server/game/Chat/Chat.cpp
@@ -308,7 +308,7 @@ bool ChatHandler::ExecuteCommandInTable(std::vector const& table, c
fullcmd.c_str(), player->GetName().c_str(), player->GetGUID().ToString().c_str(),
m_session->GetAccountId(), player->GetPositionX(), player->GetPositionY(),
player->GetPositionZ(), player->GetMapId(),
- player->GetMap() ? player->GetMap()->GetMapName() : "Unknown",
+ player->FindMap() ? player->FindMap()->GetMapName() : "Unknown",
areaId, areaName.c_str(), zoneName.c_str(),
(player->GetSelectedUnit()) ? player->GetSelectedUnit()->GetName().c_str() : "",
guid.ToString().c_str());
diff --git a/src/server/game/Chat/Chat.h b/src/server/game/Chat/Chat.h
index d6fdb585906..494dd9e193d 100644
--- a/src/server/game/Chat/Chat.h
+++ b/src/server/game/Chat/Chat.h
@@ -42,7 +42,7 @@ class ChatCommand
public:
ChatCommand(char const* name, uint32 permission, bool allowConsole, pHandler handler, std::string help, std::vector childCommands = std::vector())
- : Name(name), Permission(permission), AllowConsole(allowConsole), Handler(handler), Help(std::move(help)), ChildCommands(std::move(childCommands)) { }
+ : Name(ASSERT_NOTNULL(name)), Permission(permission), AllowConsole(allowConsole), Handler(handler), Help(std::move(help)), ChildCommands(std::move(childCommands)) { }
char const* Name;
uint32 Permission; // function pointer required correct align (use uint32)
diff --git a/src/server/game/Conditions/ConditionMgr.cpp b/src/server/game/Conditions/ConditionMgr.cpp
index 76dbd1b8f09..e2fad683aad 100644
--- a/src/server/game/Conditions/ConditionMgr.cpp
+++ b/src/server/game/Conditions/ConditionMgr.cpp
@@ -90,7 +90,7 @@ ConditionMgr::ConditionTypeInfo const ConditionMgr::StaticConditionTypeData[COND
{ "PhaseMask", true, false, false },
{ "Level", true, true, false },
{ "Quest Completed", true, false, false },
- { "Near Creature", true, true, false },
+ { "Near Creature", true, true, true },
{ "Near GameObject", true, true, false },
{ "Object Entry or Guid", true, true, true },
{ "Object TypeMask", true, false, false },
@@ -233,7 +233,7 @@ bool Condition::Meets(ConditionSourceInfo& sourceInfo) const
case CONDITION_INSTANCE_INFO:
{
Map* map = object->GetMap();
- if (map && map->IsDungeon())
+ if (map->IsDungeon())
{
if (InstanceScript const* instance = ((InstanceMap*)map)->GetInstanceScript())
{
@@ -282,7 +282,7 @@ bool Condition::Meets(ConditionSourceInfo& sourceInfo) const
}
case CONDITION_NEAR_CREATURE:
{
- condMeets = GetClosestCreatureWithEntry(object, ConditionValue1, (float)ConditionValue2) ? true : false;
+ condMeets = GetClosestCreatureWithEntry(object, ConditionValue1, (float)ConditionValue2, bool(!ConditionValue3)) ? true : false;
break;
}
case CONDITION_NEAR_GAMEOBJECT:
@@ -326,7 +326,7 @@ bool Condition::Meets(ConditionSourceInfo& sourceInfo) const
Unit* unit = object->ToUnit();
if (toUnit && unit)
{
- switch (ConditionValue2)
+ switch (static_cast(ConditionValue2))
{
case RELATION_SELF:
condMeets = unit == toUnit;
@@ -346,6 +346,8 @@ bool Condition::Meets(ConditionSourceInfo& sourceInfo) const
case RELATION_CREATED_BY:
condMeets = unit->GetCreatorGUID() == toUnit->GetGUID();
break;
+ default:
+ break;
}
}
}
@@ -996,7 +998,7 @@ void ConditionMgr::LoadConditions(bool isReload)
cond->NegativeCondition = fields[10].GetBool();
cond->ErrorType = fields[11].GetUInt32();
cond->ErrorTextId = fields[12].GetUInt32();
- cond->ScriptId = sObjectMgr->GetScriptId(fields[13].GetCString());
+ cond->ScriptId = sObjectMgr->GetScriptId(fields[13].GetString());
if (iConditionTypeOrReference >= 0)
cond->ConditionType = ConditionTypes(iConditionTypeOrReference);
@@ -1276,9 +1278,9 @@ bool ConditionMgr::addToSpellImplicitTargetConditions(Condition* cond) const
continue;
// build new shared mask with found effect
- uint32 sharedMask = (1 << i);
+ uint32 sharedMask = 1 << i;
ConditionContainer* cmp = spellInfo->Effects[i].ImplicitTargetConditions;
- for (uint8 effIndex = i+1; effIndex < MAX_SPELL_EFFECTS; ++effIndex)
+ for (uint8 effIndex = i + 1; effIndex < MAX_SPELL_EFFECTS; ++effIndex)
{
if (spellInfo->Effects[effIndex].ImplicitTargetConditions == cmp)
sharedMask |= 1 << effIndex;
@@ -2243,9 +2245,9 @@ void ConditionMgr::LogUselessConditionValue(Condition* cond, uint8 index, uint32
void ConditionMgr::Clean()
{
- for (ConditionReferenceContainer::iterator itr = ConditionReferenceStore.begin(); itr != ConditionReferenceStore.end(); ++itr)
- for (ConditionContainer::const_iterator it = itr->second.begin(); it != itr->second.end(); ++it)
- delete *it;
+ for (ConditionReferenceContainer::iterator it = ConditionReferenceStore.begin(); it != ConditionReferenceStore.end(); ++it)
+ for (ConditionContainer::const_iterator i = it->second.begin(); i != it->second.end(); ++i)
+ delete *i;
ConditionReferenceStore.clear();
diff --git a/src/server/game/Conditions/ConditionMgr.h b/src/server/game/Conditions/ConditionMgr.h
index e57fe257f6a..3f0e7db1503 100644
--- a/src/server/game/Conditions/ConditionMgr.h
+++ b/src/server/game/Conditions/ConditionMgr.h
@@ -59,7 +59,7 @@ enum ConditionTypes
CONDITION_PHASEID = 26, // phaseid 0 0 true if object is in phaseid
CONDITION_LEVEL = 27, // level ComparisonType 0 true if unit's level is equal to param1 (param2 can modify the statement)
CONDITION_QUEST_COMPLETE = 28, // quest_id 0 0 true if player has quest_id with all objectives complete, but not yet rewarded
- CONDITION_NEAR_CREATURE = 29, // creature entry distance 0 true if there is a creature of entry in range
+ CONDITION_NEAR_CREATURE = 29, // creature entry distance dead (0/1) true if there is a creature of entry in range
CONDITION_NEAR_GAMEOBJECT = 30, // gameobject entry distance 0 true if there is a gameobject of entry in range
CONDITION_OBJECT_ENTRY_GUID = 31, // TypeID entry guid true if object is type TypeID and the entry is 0 or matches entry of the object or matches guid of the object
CONDITION_TYPE_MASK = 32, // TypeMask 0 0 true if object is type object's TypeMask matches provided TypeMask
diff --git a/src/server/game/DataStores/DBCStores.cpp b/src/server/game/DataStores/DBCStores.cpp
index 9d1d020befe..4891b17d71b 100644
--- a/src/server/game/DataStores/DBCStores.cpp
+++ b/src/server/game/DataStores/DBCStores.cpp
@@ -740,7 +740,7 @@ void LoadDBCStores(const std::string& dataPath)
// fill data
for (uint32 i = 1; i < sTaxiPathNodeStore.GetNumRows(); ++i)
if (TaxiPathNodeEntry const* entry = sTaxiPathNodeStore.LookupEntry(i))
- sTaxiPathNodesByPath[entry->PathID].set(entry->NodeIndex, entry);
+ sTaxiPathNodesByPath[entry->PathID][entry->NodeIndex] = entry;
// Initialize global taxinodes mask
// include existed nodes that have at least single not spell base (scripted) path
diff --git a/src/server/game/DataStores/DBCStructure.h b/src/server/game/DataStores/DBCStructure.h
index 57103c6b0b1..1b0aaa70565 100644
--- a/src/server/game/DataStores/DBCStructure.h
+++ b/src/server/game/DataStores/DBCStructure.h
@@ -21,13 +21,8 @@
#include "Common.h"
#include "DBCEnums.h"
-#include "Path.h"
#include "Util.h"
-#include