aboutsummaryrefslogtreecommitdiff
path: root/src/server
diff options
context:
space:
mode:
Diffstat (limited to 'src/server')
-rw-r--r--src/server/CMakeLists.txt1
-rw-r--r--src/server/authserver/Realms/RealmList.cpp42
-rw-r--r--src/server/authserver/Realms/RealmList.h6
-rw-r--r--src/server/authserver/Server/AuthSocket.cpp30
-rw-r--r--src/server/authserver/Server/AuthSocket.h5
-rw-r--r--src/server/authserver/authserver.conf.dist11
-rw-r--r--src/server/collision/BoundingIntervalHierarchyWrapper.h18
-rw-r--r--src/server/collision/CMakeLists.txt2
-rw-r--r--src/server/collision/Management/MMapFactory.cpp52
-rw-r--r--src/server/collision/Management/MMapFactory.h50
-rw-r--r--src/server/collision/Management/MMapManager.cpp302
-rw-r--r--src/server/collision/Management/MMapManager.h84
-rw-r--r--src/server/collision/Management/VMapManager2.cpp12
-rw-r--r--src/server/collision/Management/VMapManager2.h2
-rw-r--r--src/server/collision/Maps/MapTree.cpp22
-rw-r--r--src/server/collision/Maps/MapTree.h1
-rw-r--r--src/server/collision/Models/GameObjectModel.cpp13
-rw-r--r--src/server/collision/Models/ModelInstance.h2
-rw-r--r--src/server/collision/Models/WorldModel.h6
-rw-r--r--src/server/collision/VMapDefinitions.h12
-rw-r--r--src/server/game/AI/CoreAI/PetAI.cpp35
-rw-r--r--src/server/game/AI/SmartScripts/SmartScript.cpp64
-rw-r--r--src/server/game/AI/SmartScripts/SmartScript.h1
-rw-r--r--src/server/game/Battlegrounds/Battleground.cpp6
-rw-r--r--src/server/game/Battlegrounds/BattlegroundMgr.cpp25
-rw-r--r--src/server/game/CMakeLists.txt2
-rw-r--r--src/server/game/Combat/ThreatManager.cpp20
-rw-r--r--src/server/game/Conditions/DisableMgr.cpp31
-rw-r--r--src/server/game/Conditions/DisableMgr.h8
-rw-r--r--src/server/game/DataStores/DBCStores.cpp7
-rw-r--r--src/server/game/Entities/Creature/GossipDef.cpp35
-rw-r--r--src/server/game/Entities/Creature/GossipDef.h2
-rw-r--r--src/server/game/Entities/Object/Object.cpp50
-rw-r--r--src/server/game/Entities/Object/Object.h5
-rw-r--r--src/server/game/Entities/Player/Player.cpp39
-rw-r--r--src/server/game/Entities/Player/Player.h8
-rw-r--r--src/server/game/Entities/Unit/Unit.cpp537
-rw-r--r--src/server/game/Entities/Unit/Unit.h45
-rwxr-xr-x[-rw-r--r--]src/server/game/Entities/Vehicle/Vehicle.cpp2
-rw-r--r--src/server/game/Globals/ObjectMgr.cpp2
-rw-r--r--src/server/game/Groups/Group.cpp2
-rw-r--r--src/server/game/Handlers/BattleGroundHandler.cpp10
-rw-r--r--src/server/game/Handlers/MovementHandler.cpp2
-rw-r--r--src/server/game/Handlers/PetHandler.cpp7
-rw-r--r--src/server/game/Maps/Map.cpp35
-rw-r--r--src/server/game/Maps/Map.h3
-rw-r--r--src/server/game/Maps/MapInstanced.cpp2
-rw-r--r--src/server/game/Miscellaneous/Language.h36
-rw-r--r--src/server/game/Miscellaneous/SharedDefines.h30
-rw-r--r--src/server/game/Movement/FollowerRefManager.h1
-rw-r--r--src/server/game/Movement/FollowerReference.cpp1
-rw-r--r--src/server/game/Movement/FollowerReference.h1
-rw-r--r--src/server/game/Movement/MotionMaster.cpp72
-rw-r--r--src/server/game/Movement/MotionMaster.h7
-rwxr-xr-x[-rw-r--r--]src/server/game/Movement/MovementGenerator.h31
-rw-r--r--src/server/game/Movement/MovementGeneratorImpl.h1
-rwxr-xr-xsrc/server/game/Movement/MovementGenerators/ConfusedMovementGenerator.cpp150
-rwxr-xr-xsrc/server/game/Movement/MovementGenerators/ConfusedMovementGenerator.h15
-rw-r--r--[-rwxr-xr-x]src/server/game/Movement/MovementGenerators/FleeingMovementGenerator.cpp387
-rwxr-xr-xsrc/server/game/Movement/MovementGenerators/FleeingMovementGenerator.h29
-rw-r--r--src/server/game/Movement/MovementGenerators/HomeMovementGenerator.cpp47
-rw-r--r--src/server/game/Movement/MovementGenerators/HomeMovementGenerator.h11
-rwxr-xr-xsrc/server/game/Movement/MovementGenerators/IdleMovementGenerator.cpp55
-rwxr-xr-x[-rw-r--r--]src/server/game/Movement/MovementGenerators/IdleMovementGenerator.h27
-rwxr-xr-x[-rw-r--r--]src/server/game/Movement/MovementGenerators/PointMovementGenerator.cpp106
-rw-r--r--src/server/game/Movement/MovementGenerators/PointMovementGenerator.h30
-rw-r--r--src/server/game/Movement/MovementGenerators/RandomMovementGenerator.cpp50
-rw-r--r--src/server/game/Movement/MovementGenerators/RandomMovementGenerator.h13
-rwxr-xr-xsrc/server/game/Movement/MovementGenerators/TargetedMovementGenerator.cpp302
-rwxr-xr-xsrc/server/game/Movement/MovementGenerators/TargetedMovementGenerator.h63
-rwxr-xr-x[-rw-r--r--]src/server/game/Movement/MovementGenerators/WaypointMovementGenerator.cpp426
-rwxr-xr-x[-rw-r--r--]src/server/game/Movement/MovementGenerators/WaypointMovementGenerator.h33
-rw-r--r--src/server/game/Movement/PathGenerator.cpp803
-rw-r--r--src/server/game/Movement/PathGenerator.h135
-rw-r--r--src/server/game/Movement/Spline/MoveSpline.h3
-rw-r--r--src/server/game/Movement/Spline/MoveSplineInit.cpp46
-rw-r--r--src/server/game/Movement/Spline/MoveSplineInit.h21
-rw-r--r--src/server/game/Movement/Waypoints/Path.h25
-rw-r--r--src/server/game/Movement/Waypoints/WaypointManager.h1
-rw-r--r--src/server/game/Scripting/ScriptLoader.cpp2
-rw-r--r--src/server/game/Spells/Auras/SpellAuraEffects.cpp215
-rw-r--r--src/server/game/Spells/Auras/SpellAuras.cpp11
-rw-r--r--src/server/game/Spells/Spell.cpp32
-rw-r--r--src/server/game/Spells/Spell.h2
-rw-r--r--src/server/game/Spells/SpellEffects.cpp219
-rw-r--r--src/server/game/World/World.cpp29
-rw-r--r--src/server/game/World/World.h3
-rw-r--r--src/server/scripts/CMakeLists.txt2
-rw-r--r--src/server/scripts/Commands/CMakeLists.txt1
-rw-r--r--src/server/scripts/Commands/cs_disable.cpp32
-rw-r--r--src/server/scripts/Commands/cs_misc.cpp154
-rw-r--r--src/server/scripts/Commands/cs_mmaps.cpp294
-rw-r--r--src/server/scripts/Commands/cs_npc.cpp44
-rw-r--r--src/server/scripts/EasternKingdoms/Scholomance/boss_kirtonos_the_herald.cpp4
-rw-r--r--src/server/scripts/Northrend/IcecrownCitadel/boss_blood_queen_lana_thel.cpp38
-rw-r--r--src/server/scripts/Northrend/IcecrownCitadel/boss_deathbringer_saurfang.cpp16
-rw-r--r--src/server/scripts/Northrend/IcecrownCitadel/boss_lord_marrowgar.cpp18
-rw-r--r--src/server/scripts/Northrend/IcecrownCitadel/boss_the_lich_king.cpp37
-rw-r--r--src/server/scripts/Northrend/Ulduar/Ulduar/boss_algalon_the_observer.cpp2
-rw-r--r--src/server/scripts/Outland/zone_shadowmoon_valley.cpp75
-rw-r--r--src/server/scripts/Spells/spell_dk.cpp161
-rw-r--r--src/server/scripts/Spells/spell_druid.cpp280
-rw-r--r--src/server/scripts/Spells/spell_generic.cpp335
-rw-r--r--src/server/scripts/Spells/spell_holiday.cpp87
-rw-r--r--src/server/scripts/Spells/spell_hunter.cpp78
-rw-r--r--src/server/scripts/Spells/spell_item.cpp576
-rw-r--r--src/server/scripts/Spells/spell_mage.cpp349
-rw-r--r--src/server/scripts/Spells/spell_paladin.cpp180
-rw-r--r--src/server/scripts/Spells/spell_priest.cpp266
-rw-r--r--src/server/scripts/Spells/spell_rogue.cpp207
-rw-r--r--src/server/scripts/Spells/spell_shaman.cpp98
-rw-r--r--src/server/scripts/Spells/spell_warlock.cpp137
-rw-r--r--src/server/scripts/Spells/spell_warrior.cpp414
-rw-r--r--src/server/shared/CMakeLists.txt1
-rw-r--r--src/server/shared/Database/DatabaseWorkerPool.h5
-rw-r--r--src/server/shared/Database/Implementation/CharacterDatabase.cpp1
-rwxr-xr-xsrc/server/shared/Database/Implementation/CharacterDatabase.h1
-rw-r--r--src/server/shared/Database/Implementation/LoginDatabase.cpp2
-rw-r--r--src/server/shared/Database/Implementation/WorldDatabase.cpp2
-rw-r--r--src/server/shared/Database/Implementation/WorldDatabase.h2
-rw-r--r--src/server/shared/Debugging/Errors.h2
-rw-r--r--src/server/shared/Logging/Appender.h6
-rw-r--r--src/server/shared/Logging/AppenderFile.cpp70
-rw-r--r--src/server/shared/Logging/AppenderFile.h5
-rw-r--r--src/server/shared/Logging/Log.cpp28
-rw-r--r--src/server/shared/Memory.h19
-rw-r--r--src/server/shared/Utilities/Util.cpp16
-rw-r--r--src/server/shared/Utilities/Util.h8
-rw-r--r--src/server/worldserver/CMakeLists.txt2
-rw-r--r--src/server/worldserver/worldserver.conf.dist33
130 files changed, 6519 insertions, 2698 deletions
diff --git a/src/server/CMakeLists.txt b/src/server/CMakeLists.txt
index 7d85cdb6e21..e8816ea8816 100644
--- a/src/server/CMakeLists.txt
+++ b/src/server/CMakeLists.txt
@@ -30,5 +30,6 @@ if( SERVERS )
else()
if( TOOLS )
add_subdirectory(collision)
+ add_subdirectory(shared)
endif()
endif()
diff --git a/src/server/authserver/Realms/RealmList.cpp b/src/server/authserver/Realms/RealmList.cpp
index 72873e40ce5..b4becc96451 100644
--- a/src/server/authserver/Realms/RealmList.cpp
+++ b/src/server/authserver/Realms/RealmList.cpp
@@ -31,12 +31,12 @@ void RealmList::Initialize(uint32 updateInterval)
UpdateRealms(true);
}
-void RealmList::UpdateRealm(uint32 ID, const std::string& name, ACE_INET_Addr const& address, uint8 icon, RealmFlags flag, uint8 timezone, AccountTypes allowedSecurityLevel, float popu, uint32 build)
+void RealmList::UpdateRealm(uint32 id, const std::string& name, ACE_INET_Addr const& address, ACE_INET_Addr const& localAddr, ACE_INET_Addr const& localSubmask, uint8 icon, RealmFlags flag, uint8 timezone, AccountTypes allowedSecurityLevel, float popu, uint32 build)
{
// Create new if not exist or update existed
Realm& realm = m_realms[name];
- realm.m_ID = ID;
+ realm.m_ID = id;
realm.name = name;
realm.icon = icon;
realm.flag = flag;
@@ -45,7 +45,9 @@ void RealmList::UpdateRealm(uint32 ID, const std::string& name, ACE_INET_Addr co
realm.populationLevel = popu;
// Append port to IP address.
- address.addr_to_string(realm.address, ACE_MAX_FULLY_QUALIFIED_NAME_LEN + 16);
+ realm.ExternalAddress = address;
+ realm.LocalAddress = localAddr;
+ realm.LocalSubnetMask = localSubmask;
realm.gamebuild = build;
}
@@ -77,23 +79,27 @@ void RealmList::UpdateRealms(bool init)
do
{
Field* fields = result->Fetch();
- uint32 realmId = fields[0].GetUInt32();
- std::string name = fields[1].GetString();
- std::string address = fields[2].GetString();
- uint16 port = fields[3].GetUInt16();
- uint8 icon = fields[4].GetUInt8();
- RealmFlags flag = RealmFlags(fields[5].GetUInt8());
- uint8 timezone = fields[6].GetUInt8();
- uint8 allowedSecurityLevel = fields[7].GetUInt8();
- float pop = fields[8].GetFloat();
- uint32 build = fields[9].GetUInt32();
-
- ACE_INET_Addr addr(port, address.c_str(), AF_INET);
-
- UpdateRealm(realmId, name, addr, icon, flag, timezone, (allowedSecurityLevel <= SEC_ADMINISTRATOR ? AccountTypes(allowedSecurityLevel) : SEC_ADMINISTRATOR), pop, build);
+ uint32 realmId = fields[0].GetUInt32();
+ std::string name = fields[1].GetString();
+ std::string externalAddress = fields[2].GetString();
+ std::string localAddress = fields[3].GetString();
+ std::string localSubmask = fields[4].GetString();
+ uint16 port = fields[5].GetUInt16();
+ uint8 icon = fields[6].GetUInt8();
+ RealmFlags flag = RealmFlags(fields[7].GetUInt8());
+ uint8 timezone = fields[8].GetUInt8();
+ uint8 allowedSecurityLevel = fields[9].GetUInt8();
+ float pop = fields[10].GetFloat();
+ uint32 build = fields[11].GetUInt32();
+
+ ACE_INET_Addr externalAddr(port, externalAddress.c_str(), AF_INET);
+ ACE_INET_Addr localAddr(port, localAddress.c_str(), AF_INET);
+ ACE_INET_Addr submask(0, localSubmask.c_str(), AF_INET);
+
+ UpdateRealm(realmId, name, externalAddr, localAddr, submask, icon, flag, timezone, (allowedSecurityLevel <= SEC_ADMINISTRATOR ? AccountTypes(allowedSecurityLevel) : SEC_ADMINISTRATOR), pop, build);
if (init)
- sLog->outInfo(LOG_FILTER_AUTHSERVER, "Added realm \"%s\" at %s.", name.c_str(), m_realms[name].address);
+ sLog->outInfo(LOG_FILTER_AUTHSERVER, "Added realm \"%s\" at %s:%u.", name.c_str(), m_realms[name].ExternalAddress.get_host_addr(), port);
}
while (result->NextRow());
}
diff --git a/src/server/authserver/Realms/RealmList.h b/src/server/authserver/Realms/RealmList.h
index 1949c34df9a..68e6524c334 100644
--- a/src/server/authserver/Realms/RealmList.h
+++ b/src/server/authserver/Realms/RealmList.h
@@ -40,7 +40,9 @@ enum RealmFlags
// Storage object for a realm
struct Realm
{
- char address[ACE_MAX_FULLY_QUALIFIED_NAME_LEN + 16];
+ ACE_INET_Addr ExternalAddress;
+ ACE_INET_Addr LocalAddress;
+ ACE_INET_Addr LocalSubnetMask;
std::string name;
uint8 icon;
RealmFlags flag;
@@ -72,7 +74,7 @@ public:
private:
void UpdateRealms(bool init=false);
- void UpdateRealm(uint32 ID, const std::string& name, ACE_INET_Addr const& address, uint8 icon, RealmFlags flag, uint8 timezone, AccountTypes allowedSecurityLevel, float popu, uint32 build);
+ void UpdateRealm(uint32 id, const std::string& name, ACE_INET_Addr const& address, ACE_INET_Addr const& localAddr, ACE_INET_Addr const& localSubmask, uint8 icon, RealmFlags flag, uint8 timezone, AccountTypes allowedSecurityLevel, float popu, uint32 build);
RealmMap m_realms;
uint32 m_UpdateInterval;
diff --git a/src/server/authserver/Server/AuthSocket.cpp b/src/server/authserver/Server/AuthSocket.cpp
index 8ab4ab8a1a2..b0bce520d4f 100644
--- a/src/server/authserver/Server/AuthSocket.cpp
+++ b/src/server/authserver/Server/AuthSocket.cpp
@@ -818,6 +818,28 @@ bool AuthSocket::_HandleReconnectProof()
}
}
+ACE_INET_Addr const& AuthSocket::GetAddressForClient(Realm const& realm, ACE_INET_Addr const& clientAddr)
+{
+ // Attempt to send best address for client
+ if (clientAddr.is_loopback())
+ {
+ // Try guessing if realm is also connected locally
+ if (realm.LocalAddress.is_loopback() || realm.ExternalAddress.is_loopback())
+ return clientAddr;
+
+ // Assume that user connecting from the machine that authserver is located on
+ // has all realms available in his local network
+ return realm.LocalAddress;
+ }
+
+ // Check if connecting client is in the same network
+ if (IsIPAddrInNetwork(realm.LocalAddress, clientAddr, realm.LocalSubnetMask))
+ return realm.LocalAddress;
+
+ // Return external IP
+ return realm.ExternalAddress;
+}
+
// Realm List command handler
bool AuthSocket::_HandleRealmList()
{
@@ -845,6 +867,9 @@ bool AuthSocket::_HandleRealmList()
// Update realm list if need
sRealmList->UpdateIfNeed();
+ ACE_INET_Addr clientAddr;
+ socket().peer().get_remote_addr(clientAddr);
+
// Circle through realms in the RealmList and construct the return packet (including # of user characters in each realm)
ByteBuffer pkt;
@@ -876,6 +901,9 @@ bool AuthSocket::_HandleRealmList()
name = ss.str();
}
+ // We don't need the port number from which client connects with but the realm's port
+ clientAddr.set_port_number(i->second.ExternalAddress.get_port_number());
+
uint8 lock = (i->second.allowedSecurityLevel > _accountSecurityLevel) ? 1 : 0;
uint8 AmountOfCharacters = 0;
@@ -891,7 +919,7 @@ bool AuthSocket::_HandleRealmList()
pkt << lock; // if 1, then realm locked
pkt << uint8(flag); // RealmFlags
pkt << name;
- pkt << i->second.address;
+ pkt << GetAddressString(GetAddressForClient(i->second, clientAddr));
pkt << i->second.populationLevel;
pkt << AmountOfCharacters;
pkt << i->second.timezone; // realm category
diff --git a/src/server/authserver/Server/AuthSocket.h b/src/server/authserver/Server/AuthSocket.h
index 87fd092381e..6c13f85a022 100644
--- a/src/server/authserver/Server/AuthSocket.h
+++ b/src/server/authserver/Server/AuthSocket.h
@@ -23,6 +23,9 @@
#include "BigNumber.h"
#include "RealmSocket.h"
+class ACE_INET_Addr;
+struct Realm;
+
// Handle login commands
class AuthSocket: public RealmSocket::Session
{
@@ -36,6 +39,8 @@ public:
virtual void OnAccept(void);
virtual void OnClose(void);
+ static ACE_INET_Addr const& GetAddressForClient(Realm const& realm, ACE_INET_Addr const& clientAddr);
+
bool _HandleLogonChallenge();
bool _HandleLogonProof();
bool _HandleReconnectChallenge();
diff --git a/src/server/authserver/authserver.conf.dist b/src/server/authserver/authserver.conf.dist
index 67d22c49da1..dda19c3b849 100644
--- a/src/server/authserver/authserver.conf.dist
+++ b/src/server/authserver/authserver.conf.dist
@@ -154,7 +154,7 @@ LoginDatabase.WorkerThreads = 1
# Appender config values: Given a appender "name"
# Appender.name
# Description: Defines 'where to log'
-# Format: Type,LogLevel,Flags,optional1,optional2
+# Format: Type,LogLevel,Flags,optional1,optional2,optional3
#
# Type
# 0 - (None)
@@ -205,6 +205,13 @@ LoginDatabase.WorkerThreads = 1
# a - (Append)
# w - (Overwrite)
#
+# MaxFileSize: Maximum file size of the log file before creating a new log file
+# (read as optional3 if Type = File)
+# Size is measured in bytes expressed in a 64-bit unsigned integer.
+# Maximum value is 4294967295 (4 gb). Leave blank for no limit.
+# NOTE: Does not work with dynamic filenames.
+# Example: 536870912 (512 mb)
+#
Appender.Console=1,2,0
Appender.Auth=2,2,0,Auth.log,w
@@ -250,4 +257,4 @@ Logger.Root=0,3,Console Auth
Loggers=Root
#
-################################################################################################### \ No newline at end of file
+###################################################################################################
diff --git a/src/server/collision/BoundingIntervalHierarchyWrapper.h b/src/server/collision/BoundingIntervalHierarchyWrapper.h
index 8a99078caab..315f3004306 100644
--- a/src/server/collision/BoundingIntervalHierarchyWrapper.h
+++ b/src/server/collision/BoundingIntervalHierarchyWrapper.h
@@ -33,11 +33,14 @@ class BIHWrap
{
const T* const* objects;
RayCallback& _callback;
+ uint32 objects_size;
- MDLCallback(RayCallback& callback, const T* const* objects_array ) : objects(objects_array), _callback(callback) {}
+ MDLCallback(RayCallback& callback, const T* const* objects_array, uint32 objects_size ) : objects(objects_array), _callback(callback), objects_size(objects_size) {}
bool operator() (const Ray& ray, uint32 Idx, float& MaxDist, bool /*stopAtFirst*/)
{
+ if (Idx >= objects_size)
+ return false;
if (const T* obj = objects[Idx])
return _callback(ray, *obj, MaxDist/*, stopAtFirst*/);
return false;
@@ -45,6 +48,8 @@ class BIHWrap
void operator() (const Vector3& p, uint32 Idx)
{
+ if (Idx >= objects_size)
+ return false;
if (const T* obj = objects[Idx])
_callback(p, *obj);
}
@@ -87,21 +92,24 @@ public:
m_objects.fastClear();
m_obj2Idx.getKeys(m_objects);
m_objects_to_push.getMembers(m_objects);
+ //assert that m_obj2Idx has all the keys
m_tree.build(m_objects, BoundsFunc::getBounds2);
}
template<typename RayCallback>
- void intersectRay(const Ray& ray, RayCallback& intersectCallback, float& maxDist) const
+ void intersectRay(const Ray& ray, RayCallback& intersectCallback, float& maxDist)
{
- MDLCallback<RayCallback> temp_cb(intersectCallback, m_objects.getCArray());
+ balance();
+ MDLCallback<RayCallback> temp_cb(intersectCallback, m_objects.getCArray(), m_objects.size());
m_tree.intersectRay(ray, temp_cb, maxDist, true);
}
template<typename IsectCallback>
- void intersectPoint(const Vector3& point, IsectCallback& intersectCallback) const
+ void intersectPoint(const Vector3& point, IsectCallback& intersectCallback)
{
- MDLCallback<IsectCallback> callback(intersectCallback, m_objects.getCArray());
+ balance();
+ MDLCallback<IsectCallback> callback(intersectCallback, m_objects.getCArray(), m_objects.size());
m_tree.intersectPoint(point, callback);
}
};
diff --git a/src/server/collision/CMakeLists.txt b/src/server/collision/CMakeLists.txt
index 62af7dd081e..b4012b63812 100644
--- a/src/server/collision/CMakeLists.txt
+++ b/src/server/collision/CMakeLists.txt
@@ -33,7 +33,9 @@ set(collision_STAT_SRCS
include_directories(
${CMAKE_BINARY_DIR}
${CMAKE_SOURCE_DIR}/dep/g3dlite/include
+ ${CMAKE_SOURCE_DIR}/dep/recastnavigation/Detour
${CMAKE_SOURCE_DIR}/src/server/shared
+ ${CMAKE_SOURCE_DIR}/src/server/shared/Configuration
${CMAKE_SOURCE_DIR}/src/server/shared/Debugging
${CMAKE_SOURCE_DIR}/src/server/shared/Database
${CMAKE_SOURCE_DIR}/src/server/shared/Debugging
diff --git a/src/server/collision/Management/MMapFactory.cpp b/src/server/collision/Management/MMapFactory.cpp
new file mode 100644
index 00000000000..7adf7fbfa66
--- /dev/null
+++ b/src/server/collision/Management/MMapFactory.cpp
@@ -0,0 +1,52 @@
+/*
+ * Copyright (C) 2008-2013 TrinityCore <http://www.trinitycore.org/>
+ * Copyright (C) 2005-2010 MaNGOS <http://getmangos.com/>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "MMapFactory.h"
+#include "World.h"
+#include "Config.h"
+#include "DisableMgr.h"
+
+namespace MMAP
+{
+ // ######################## MMapFactory ########################
+ // our global singleton copy
+ MMapManager *g_MMapManager = NULL;
+
+ MMapManager* MMapFactory::createOrGetMMapManager()
+ {
+ if (g_MMapManager == NULL)
+ g_MMapManager = new MMapManager();
+
+ return g_MMapManager;
+ }
+
+ bool MMapFactory::IsPathfindingEnabled(uint32 mapId)
+ {
+ return sWorld->getBoolConfig(CONFIG_ENABLE_MMAPS)
+ && !DisableMgr::IsDisabledFor(DISABLE_TYPE_MMAP, mapId, NULL, MMAP_DISABLE_PATHFINDING);
+ }
+
+ void MMapFactory::clear()
+ {
+ if (g_MMapManager)
+ {
+ delete g_MMapManager;
+ g_MMapManager = NULL;
+ }
+ }
+} \ No newline at end of file
diff --git a/src/server/collision/Management/MMapFactory.h b/src/server/collision/Management/MMapFactory.h
new file mode 100644
index 00000000000..00f19a194d3
--- /dev/null
+++ b/src/server/collision/Management/MMapFactory.h
@@ -0,0 +1,50 @@
+/*
+ * Copyright (C) 2008-2013 TrinityCore <http://www.trinitycore.org/>
+ * Copyright (C) 2005-2010 MaNGOS <http://getmangos.com/>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef _MMAP_FACTORY_H
+#define _MMAP_FACTORY_H
+
+#include "MMapManager.h"
+#include "UnorderedMap.h"
+#include "DetourAlloc.h"
+#include "DetourNavMesh.h"
+#include "DetourNavMeshQuery.h"
+
+namespace MMAP
+{
+ enum MMAP_LOAD_RESULT
+ {
+ MMAP_LOAD_RESULT_ERROR,
+ MMAP_LOAD_RESULT_OK,
+ MMAP_LOAD_RESULT_IGNORED,
+ };
+
+ // static class
+ // holds all mmap global data
+ // access point to MMapManager singleton
+ class MMapFactory
+ {
+ public:
+ static MMapManager* createOrGetMMapManager();
+ static void clear();
+ static bool IsPathfindingEnabled(uint32 mapId);
+ };
+}
+
+#endif
+
diff --git a/src/server/collision/Management/MMapManager.cpp b/src/server/collision/Management/MMapManager.cpp
new file mode 100644
index 00000000000..e3ed8f3310a
--- /dev/null
+++ b/src/server/collision/Management/MMapManager.cpp
@@ -0,0 +1,302 @@
+/*
+ * Copyright (C) 2008-2013 TrinityCore <http://www.trinitycore.org/>
+ * Copyright (C) 2005-2010 MaNGOS <http://getmangos.com/>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "MMapManager.h"
+#include "Log.h"
+#include "World.h"
+
+namespace MMAP
+{
+ // ######################## MMapManager ########################
+ MMapManager::~MMapManager()
+ {
+ for (MMapDataSet::iterator i = loadedMMaps.begin(); i != loadedMMaps.end(); ++i)
+ delete i->second;
+
+ // by now we should not have maps loaded
+ // if we had, tiles in MMapData->mmapLoadedTiles, their actual data is lost!
+ }
+
+ bool MMapManager::loadMapData(uint32 mapId)
+ {
+ // we already have this map loaded?
+ if (loadedMMaps.find(mapId) != loadedMMaps.end())
+ return true;
+
+ // load and init dtNavMesh - read parameters from file
+ uint32 pathLen = sWorld->GetDataPath().length() + strlen("mmaps/%03i.mmap")+1;
+ char *fileName = new char[pathLen];
+ snprintf(fileName, pathLen, (sWorld->GetDataPath()+"mmaps/%03i.mmap").c_str(), mapId);
+
+ FILE* file = fopen(fileName, "rb");
+ if (!file)
+ {
+ sLog->outDebug(LOG_FILTER_MAPS, "MMAP:loadMapData: Error: Could not open mmap file '%s'", fileName);
+ delete [] fileName;
+ return false;
+ }
+
+ dtNavMeshParams params;
+ int count = fread(&params, sizeof(dtNavMeshParams), 1, file);
+ fclose(file);
+ if (count != 1)
+ {
+ sLog->outDebug(LOG_FILTER_MAPS, "MMAP:loadMapData: Error: Could not read params from file '%s'", fileName);
+ delete [] fileName;
+ return false;
+ }
+
+ dtNavMesh* mesh = dtAllocNavMesh();
+ ASSERT(mesh);
+ if (DT_SUCCESS != mesh->init(&params))
+ {
+ dtFreeNavMesh(mesh);
+ sLog->outError(LOG_FILTER_MAPS, "MMAP:loadMapData: Failed to initialize dtNavMesh for mmap %03u from file %s", mapId, fileName);
+ delete [] fileName;
+ return false;
+ }
+
+ delete [] fileName;
+
+ sLog->outInfo(LOG_FILTER_MAPS, "MMAP:loadMapData: Loaded %03i.mmap", mapId);
+
+ // store inside our map list
+ MMapData* mmap_data = new MMapData(mesh);
+ mmap_data->mmapLoadedTiles.clear();
+
+ loadedMMaps.insert(std::pair<uint32, MMapData*>(mapId, mmap_data));
+ return true;
+ }
+
+ uint32 MMapManager::packTileID(int32 x, int32 y)
+ {
+ return uint32(x << 16 | y);
+ }
+
+ bool MMapManager::loadMap(const std::string& /*basePath*/, uint32 mapId, int32 x, int32 y)
+ {
+ // make sure the mmap is loaded and ready to load tiles
+ if (!loadMapData(mapId))
+ return false;
+
+ // get this mmap data
+ MMapData* mmap = loadedMMaps[mapId];
+ ASSERT(mmap->navMesh);
+
+ // check if we already have this tile loaded
+ uint32 packedGridPos = packTileID(x, y);
+ if (mmap->mmapLoadedTiles.find(packedGridPos) != mmap->mmapLoadedTiles.end())
+ return false;
+
+ // load this tile :: mmaps/MMMXXYY.mmtile
+ uint32 pathLen = sWorld->GetDataPath().length() + strlen("mmaps/%03i%02i%02i.mmtile")+1;
+ char *fileName = new char[pathLen];
+
+ snprintf(fileName, pathLen, (sWorld->GetDataPath()+"mmaps/%03i%02i%02i.mmtile").c_str(), mapId, x, y);
+
+ FILE *file = fopen(fileName, "rb");
+ if (!file)
+ {
+ sLog->outDebug(LOG_FILTER_MAPS, "MMAP:loadMap: Could not open mmtile file '%s'", fileName);
+ delete [] fileName;
+ return false;
+ }
+ delete [] fileName;
+
+ // read header
+ MmapTileHeader fileHeader;
+ if (fread(&fileHeader, sizeof(MmapTileHeader), 1, file) != 1 || fileHeader.mmapMagic != MMAP_MAGIC)
+ {
+ sLog->outError(LOG_FILTER_MAPS, "MMAP:loadMap: Bad header in mmap %03u%02i%02i.mmtile", mapId, x, y);
+ return false;
+ }
+
+ if (fileHeader.mmapVersion != MMAP_VERSION)
+ {
+ sLog->outError(LOG_FILTER_MAPS, "MMAP:loadMap: %03u%02i%02i.mmtile was built with generator v%i, expected v%i",
+ mapId, x, y, fileHeader.mmapVersion, MMAP_VERSION);
+ return false;
+ }
+
+ unsigned char* data = (unsigned char*)dtAlloc(fileHeader.size, DT_ALLOC_PERM);
+ ASSERT(data);
+
+ size_t result = fread(data, fileHeader.size, 1, file);
+ if (!result)
+ {
+ sLog->outError(LOG_FILTER_MAPS, "MMAP:loadMap: Bad header or data in mmap %03u%02i%02i.mmtile", mapId, x, y);
+ fclose(file);
+ return false;
+ }
+
+ fclose(file);
+
+ dtMeshHeader* header = (dtMeshHeader*)data;
+ dtTileRef tileRef = 0;
+
+ // memory allocated for data is now managed by detour, and will be deallocated when the tile is removed
+ if (DT_SUCCESS == mmap->navMesh->addTile(data, fileHeader.size, DT_TILE_FREE_DATA, 0, &tileRef))
+ {
+ mmap->mmapLoadedTiles.insert(std::pair<uint32, dtTileRef>(packedGridPos, tileRef));
+ ++loadedTiles;
+ sLog->outInfo(LOG_FILTER_MAPS, "MMAP:loadMap: Loaded mmtile %03i[%02i,%02i] into %03i[%02i,%02i]", mapId, x, y, mapId, header->x, header->y);
+ return true;
+ }
+ else
+ {
+ sLog->outError(LOG_FILTER_MAPS, "MMAP:loadMap: Could not load %03u%02i%02i.mmtile into navmesh", mapId, x, y);
+ dtFree(data);
+ return false;
+ }
+
+ return false;
+ }
+
+ bool MMapManager::unloadMap(uint32 mapId, int32 x, int32 y)
+ {
+ // check if we have this map loaded
+ if (loadedMMaps.find(mapId) == loadedMMaps.end())
+ {
+ // file may not exist, therefore not loaded
+ sLog->outDebug(LOG_FILTER_MAPS, "MMAP:unloadMap: Asked to unload not loaded navmesh map. %03u%02i%02i.mmtile", mapId, x, y);
+ return false;
+ }
+
+ MMapData* mmap = loadedMMaps[mapId];
+
+ // check if we have this tile loaded
+ uint32 packedGridPos = packTileID(x, y);
+ if (mmap->mmapLoadedTiles.find(packedGridPos) == mmap->mmapLoadedTiles.end())
+ {
+ // file may not exist, therefore not loaded
+ sLog->outDebug(LOG_FILTER_MAPS, "MMAP:unloadMap: Asked to unload not loaded navmesh tile. %03u%02i%02i.mmtile", mapId, x, y);
+ return false;
+ }
+
+ dtTileRef tileRef = mmap->mmapLoadedTiles[packedGridPos];
+
+ // unload, and mark as non loaded
+ if (DT_SUCCESS != mmap->navMesh->removeTile(tileRef, NULL, NULL))
+ {
+ // this is technically a memory leak
+ // if the grid is later reloaded, dtNavMesh::addTile will return error but no extra memory is used
+ // we cannot recover from this error - assert out
+ sLog->outError(LOG_FILTER_MAPS, "MMAP:unloadMap: Could not unload %03u%02i%02i.mmtile from navmesh", mapId, x, y);
+ ASSERT(false);
+ }
+ else
+ {
+ mmap->mmapLoadedTiles.erase(packedGridPos);
+ --loadedTiles;
+ sLog->outInfo(LOG_FILTER_MAPS, "MMAP:unloadMap: Unloaded mmtile %03i[%02i,%02i] from %03i", mapId, x, y, mapId);
+ return true;
+ }
+
+ return false;
+ }
+
+ bool MMapManager::unloadMap(uint32 mapId)
+ {
+ if (loadedMMaps.find(mapId) == loadedMMaps.end())
+ {
+ // file may not exist, therefore not loaded
+ sLog->outDebug(LOG_FILTER_MAPS, "MMAP:unloadMap: Asked to unload not loaded navmesh map %03u", mapId);
+ return false;
+ }
+
+ // unload all tiles from given map
+ MMapData* mmap = loadedMMaps[mapId];
+ for (MMapTileSet::iterator i = mmap->mmapLoadedTiles.begin(); i != mmap->mmapLoadedTiles.end(); ++i)
+ {
+ uint32 x = (i->first >> 16);
+ uint32 y = (i->first & 0x0000FFFF);
+ if (DT_SUCCESS != mmap->navMesh->removeTile(i->second, NULL, NULL))
+ sLog->outError(LOG_FILTER_MAPS, "MMAP:unloadMap: Could not unload %03u%02i%02i.mmtile from navmesh", mapId, x, y);
+ else
+ {
+ --loadedTiles;
+ sLog->outInfo(LOG_FILTER_MAPS, "MMAP:unloadMap: Unloaded mmtile %03i[%02i,%02i] from %03i", mapId, x, y, mapId);
+ }
+ }
+
+ delete mmap;
+ loadedMMaps.erase(mapId);
+ sLog->outInfo(LOG_FILTER_MAPS, "MMAP:unloadMap: Unloaded %03i.mmap", mapId);
+
+ return true;
+ }
+
+ bool MMapManager::unloadMapInstance(uint32 mapId, uint32 instanceId)
+ {
+ // check if we have this map loaded
+ if (loadedMMaps.find(mapId) == loadedMMaps.end())
+ {
+ // file may not exist, therefore not loaded
+ sLog->outDebug(LOG_FILTER_MAPS, "MMAP:unloadMapInstance: Asked to unload not loaded navmesh map %03u", mapId);
+ return false;
+ }
+
+ MMapData* mmap = loadedMMaps[mapId];
+ if (mmap->navMeshQueries.find(instanceId) == mmap->navMeshQueries.end())
+ {
+ sLog->outDebug(LOG_FILTER_MAPS, "MMAP:unloadMapInstance: Asked to unload not loaded dtNavMeshQuery mapId %03u instanceId %u", mapId, instanceId);
+ return false;
+ }
+
+ dtNavMeshQuery* query = mmap->navMeshQueries[instanceId];
+
+ dtFreeNavMeshQuery(query);
+ mmap->navMeshQueries.erase(instanceId);
+ sLog->outInfo(LOG_FILTER_MAPS, "MMAP:unloadMapInstance: Unloaded mapId %03u instanceId %u", mapId, instanceId);
+
+ return true;
+ }
+
+ dtNavMesh const* MMapManager::GetNavMesh(uint32 mapId)
+ {
+ if (loadedMMaps.find(mapId) == loadedMMaps.end())
+ return NULL;
+
+ return loadedMMaps[mapId]->navMesh;
+ }
+
+ dtNavMeshQuery const* MMapManager::GetNavMeshQuery(uint32 mapId, uint32 instanceId)
+ {
+ if (loadedMMaps.find(mapId) == loadedMMaps.end())
+ return NULL;
+
+ MMapData* mmap = loadedMMaps[mapId];
+ if (mmap->navMeshQueries.find(instanceId) == mmap->navMeshQueries.end())
+ {
+ // allocate mesh query
+ dtNavMeshQuery* query = dtAllocNavMeshQuery();
+ ASSERT(query);
+ if (DT_SUCCESS != query->init(mmap->navMesh, 1024))
+ {
+ dtFreeNavMeshQuery(query);
+ sLog->outError(LOG_FILTER_MAPS, "MMAP:GetNavMeshQuery: Failed to initialize dtNavMeshQuery for mapId %03u instanceId %u", mapId, instanceId);
+ return NULL;
+ }
+
+ sLog->outInfo(LOG_FILTER_MAPS, "MMAP:GetNavMeshQuery: created dtNavMeshQuery for mapId %03u instanceId %u", mapId, instanceId);
+ mmap->navMeshQueries.insert(std::pair<uint32, dtNavMeshQuery*>(instanceId, query));
+ }
+
+ return mmap->navMeshQueries[instanceId];
+ }
+}
diff --git a/src/server/collision/Management/MMapManager.h b/src/server/collision/Management/MMapManager.h
new file mode 100644
index 00000000000..56b1b856d65
--- /dev/null
+++ b/src/server/collision/Management/MMapManager.h
@@ -0,0 +1,84 @@
+/*
+ * Copyright (C) 2008-2013 TrinityCore <http://www.trinitycore.org/>
+ * Copyright (C) 2005-2010 MaNGOS <http://getmangos.com/>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef _MMAP_MANAGER_H
+#define _MMAP_MANAGER_H
+
+#include "UnorderedMap.h"
+#include "DetourAlloc.h"
+#include "DetourNavMesh.h"
+#include "DetourNavMeshQuery.h"
+
+// move map related classes
+namespace MMAP
+{
+ typedef UNORDERED_MAP<uint32, dtTileRef> MMapTileSet;
+ typedef UNORDERED_MAP<uint32, dtNavMeshQuery*> NavMeshQuerySet;
+
+ // dummy struct to hold map's mmap data
+ struct MMapData
+ {
+ MMapData(dtNavMesh* mesh) : navMesh(mesh) {}
+ ~MMapData()
+ {
+ for (NavMeshQuerySet::iterator i = navMeshQueries.begin(); i != navMeshQueries.end(); ++i)
+ dtFreeNavMeshQuery(i->second);
+
+ if (navMesh)
+ dtFreeNavMesh(navMesh);
+ }
+
+ dtNavMesh* navMesh;
+
+ // we have to use single dtNavMeshQuery for every instance, since those are not thread safe
+ NavMeshQuerySet navMeshQueries; // instanceId to query
+ MMapTileSet mmapLoadedTiles; // maps [map grid coords] to [dtTile]
+ };
+
+
+ typedef UNORDERED_MAP<uint32, MMapData*> MMapDataSet;
+
+ // singleton class
+ // holds all all access to mmap loading unloading and meshes
+ class MMapManager
+ {
+ public:
+ MMapManager() : loadedTiles(0) {}
+ ~MMapManager();
+
+ bool loadMap(const std::string& basePath, uint32 mapId, int32 x, int32 y);
+ bool unloadMap(uint32 mapId, int32 x, int32 y);
+ bool unloadMap(uint32 mapId);
+ bool unloadMapInstance(uint32 mapId, uint32 instanceId);
+
+ // the returned [dtNavMeshQuery const*] is NOT threadsafe
+ dtNavMeshQuery const* GetNavMeshQuery(uint32 mapId, uint32 instanceId);
+ dtNavMesh const* GetNavMesh(uint32 mapId);
+
+ uint32 getLoadedTilesCount() const { return loadedTiles; }
+ uint32 getLoadedMapsCount() const { return loadedMMaps.size(); }
+ private:
+ bool loadMapData(uint32 mapId);
+ uint32 packTileID(int32 x, int32 y);
+
+ MMapDataSet loadedMMaps;
+ uint32 loadedTiles;
+ };
+}
+
+#endif \ No newline at end of file
diff --git a/src/server/collision/Management/VMapManager2.cpp b/src/server/collision/Management/VMapManager2.cpp
index 5e3741ca753..8a1bd346957 100644
--- a/src/server/collision/Management/VMapManager2.cpp
+++ b/src/server/collision/Management/VMapManager2.cpp
@@ -24,13 +24,13 @@
#include "MapTree.h"
#include "ModelInstance.h"
#include "WorldModel.h"
-#include "VMapDefinitions.h"
-#include "Log.h"
#include <G3D/Vector3.h>
#include <ace/Null_Mutex.h>
#include <ace/Singleton.h>
#include "DisableMgr.h"
#include "DBCStores.h"
+#include "Log.h"
+#include "VMapDefinitions.h"
using G3D::Vector3;
@@ -257,11 +257,11 @@ namespace VMAP
WorldModel* worldmodel = new WorldModel();
if (!worldmodel->readFile(basepath + filename + ".vmo"))
{
- sLog->outError(LOG_FILTER_GENERAL, "VMapManager2: could not load '%s%s.vmo'", basepath.c_str(), filename.c_str());
+ VMAP_ERROR_LOG(LOG_FILTER_GENERAL, "VMapManager2: could not load '%s%s.vmo'", basepath.c_str(), filename.c_str());
delete worldmodel;
return NULL;
}
- sLog->outDebug(LOG_FILTER_MAPS, "VMapManager2: loading file '%s%s'", basepath.c_str(), filename.c_str());
+ VMAP_DEBUG_LOG(LOG_FILTER_MAPS, "VMapManager2: loading file '%s%s'", basepath.c_str(), filename.c_str());
model = iLoadedModelFiles.insert(std::pair<std::string, ManagedModel>(filename, ManagedModel())).first;
model->second.setModel(worldmodel);
}
@@ -277,12 +277,12 @@ namespace VMAP
ModelFileMap::iterator model = iLoadedModelFiles.find(filename);
if (model == iLoadedModelFiles.end())
{
- sLog->outError(LOG_FILTER_GENERAL, "VMapManager2: trying to unload non-loaded file '%s'", filename.c_str());
+ VMAP_ERROR_LOG(LOG_FILTER_GENERAL, "VMapManager2: trying to unload non-loaded file '%s'", filename.c_str());
return;
}
if (model->second.decRefCount() == 0)
{
- sLog->outDebug(LOG_FILTER_MAPS, "VMapManager2: unloading file '%s'", filename.c_str());
+ VMAP_DEBUG_LOG(LOG_FILTER_MAPS, "VMapManager2: unloading file '%s'", filename.c_str());
delete model->second.getModel();
iLoadedModelFiles.erase(model);
}
diff --git a/src/server/collision/Management/VMapManager2.h b/src/server/collision/Management/VMapManager2.h
index e2e9965dbfc..51f15f0fda4 100644
--- a/src/server/collision/Management/VMapManager2.h
+++ b/src/server/collision/Management/VMapManager2.h
@@ -112,6 +112,8 @@ namespace VMAP
return getMapFileName(mapId);
}
virtual bool existsMap(const char* basePath, unsigned int mapId, int x, int y);
+ public:
+ void getInstanceMapTree(InstanceTreeMap &instanceMapTree);
};
}
diff --git a/src/server/collision/Maps/MapTree.cpp b/src/server/collision/Maps/MapTree.cpp
index 5f4e2b6aa8b..eb4b4555cb4 100644
--- a/src/server/collision/Maps/MapTree.cpp
+++ b/src/server/collision/Maps/MapTree.cpp
@@ -21,18 +21,13 @@
#include "VMapManager2.h"
#include "VMapDefinitions.h"
#include "Log.h"
+#include "Errors.h"
#include <string>
#include <sstream>
#include <iomanip>
#include <limits>
-#ifndef NO_CORE_FUNCS
- #include "Errors.h"
-#else
- #define ASSERT(x)
-#endif
-
using G3D::Vector3;
namespace VMAP
@@ -277,7 +272,7 @@ namespace VMAP
bool StaticMapTree::InitMap(const std::string &fname, VMapManager2* vm)
{
- sLog->outDebug(LOG_FILTER_MAPS, "StaticMapTree::InitMap() : initializing StaticMapTree '%s'", fname.c_str());
+ VMAP_DEBUG_LOG(LOG_FILTER_MAPS, "StaticMapTree::InitMap() : initializing StaticMapTree '%s'", fname.c_str());
bool success = true;
std::string fullname = iBasePath + fname;
FILE* rf = fopen(fullname.c_str(), "rb");
@@ -310,7 +305,7 @@ namespace VMAP
if (!iIsTiled && ModelSpawn::readFromFile(rf, spawn))
{
WorldModel* model = vm->acquireModelInstance(iBasePath, spawn.name);
- sLog->outDebug(LOG_FILTER_MAPS, "StaticMapTree::InitMap() : loading %s", spawn.name.c_str());
+ VMAP_DEBUG_LOG(LOG_FILTER_MAPS, "StaticMapTree::InitMap() : loading %s", spawn.name.c_str());
if (model)
{
// assume that global model always is the first and only tree value (could be improved...)
@@ -320,7 +315,7 @@ namespace VMAP
else
{
success = false;
- sLog->outError(LOG_FILTER_GENERAL, "StaticMapTree::InitMap() : could not acquire WorldModel pointer for '%s'", spawn.name.c_str());
+ VMAP_ERROR_LOG(LOG_FILTER_GENERAL, "StaticMapTree::InitMap() : could not acquire WorldModel pointer for '%s'", spawn.name.c_str());
}
}
@@ -356,7 +351,7 @@ namespace VMAP
}
if (!iTreeValues)
{
- sLog->outError(LOG_FILTER_GENERAL, "StaticMapTree::LoadMapTile() : tree has not been initialized [%u, %u]", tileX, tileY);
+ VMAP_ERROR_LOG(LOG_FILTER_GENERAL, "StaticMapTree::LoadMapTile() : tree has not been initialized [%u, %u]", tileX, tileY);
return false;
}
bool result = true;
@@ -382,7 +377,7 @@ namespace VMAP
// acquire model instance
WorldModel* model = vm->acquireModelInstance(iBasePath, spawn.name);
if (!model)
- sLog->outError(LOG_FILTER_GENERAL, "StaticMapTree::LoadMapTile() : could not acquire WorldModel pointer [%u, %u]", tileX, tileY);
+ VMAP_ERROR_LOG(LOG_FILTER_GENERAL, "StaticMapTree::LoadMapTile() : could not acquire WorldModel pointer [%u, %u]", tileX, tileY);
// update tree
uint32 referencedVal;
@@ -432,7 +427,7 @@ namespace VMAP
loadedTileMap::iterator tile = iLoadedTiles.find(tileID);
if (tile == iLoadedTiles.end())
{
- sLog->outError(LOG_FILTER_GENERAL, "StaticMapTree::UnloadMapTile() : trying to unload non-loaded tile - Map:%u X:%u Y:%u", iMapID, tileX, tileY);
+ VMAP_ERROR_LOG(LOG_FILTER_GENERAL, "StaticMapTree::UnloadMapTile() : trying to unload non-loaded tile - Map:%u X:%u Y:%u", iMapID, tileX, tileY);
return;
}
if (tile->second) // file associated with tile
@@ -466,7 +461,7 @@ namespace VMAP
else
{
if (!iLoadedSpawns.count(referencedNode))
- sLog->outError(LOG_FILTER_GENERAL, "StaticMapTree::UnloadMapTile() : trying to unload non-referenced model '%s' (ID:%u)", spawn.name.c_str(), spawn.ID);
+ VMAP_ERROR_LOG(LOG_FILTER_GENERAL, "StaticMapTree::UnloadMapTile() : trying to unload non-referenced model '%s' (ID:%u)", spawn.name.c_str(), spawn.ID);
else if (--iLoadedSpawns[referencedNode] == 0)
{
iTreeValues[referencedNode].setUnloaded();
@@ -480,5 +475,4 @@ namespace VMAP
}
iLoadedTiles.erase(tile);
}
-
}
diff --git a/src/server/collision/Maps/MapTree.h b/src/server/collision/Maps/MapTree.h
index bd928d85c5a..c8e9628dff1 100644
--- a/src/server/collision/Maps/MapTree.h
+++ b/src/server/collision/Maps/MapTree.h
@@ -80,6 +80,7 @@ namespace VMAP
void UnloadMapTile(uint32 tileX, uint32 tileY, VMapManager2* vm);
bool isTiled() const { return iIsTiled; }
uint32 numLoadedTiles() const { return iLoadedTiles.size(); }
+ void getModelInstances(ModelInstance* &models, uint32 &count);
};
struct AreaInfo
diff --git a/src/server/collision/Models/GameObjectModel.cpp b/src/server/collision/Models/GameObjectModel.cpp
index 0ecf02648f9..54283389387 100644
--- a/src/server/collision/Models/GameObjectModel.cpp
+++ b/src/server/collision/Models/GameObjectModel.cpp
@@ -34,8 +34,6 @@ using G3D::Vector3;
using G3D::Ray;
using G3D::AABox;
-#ifndef NO_CORE_FUNCS
-
struct GameobjectModelData
{
GameobjectModelData(const std::string& name_, const AABox& box) :
@@ -54,7 +52,7 @@ void LoadGameObjectModelList()
FILE* model_list_file = fopen((sWorld->GetDataPath() + "vmaps/" + VMAP::GAMEOBJECT_MODELS).c_str(), "rb");
if (!model_list_file)
{
- sLog->outError(LOG_FILTER_GENERAL, "Unable to open '%s' file.", VMAP::GAMEOBJECT_MODELS);
+ VMAP_ERROR_LOG(LOG_FILTER_GENERAL, "Unable to open '%s' file.", VMAP::GAMEOBJECT_MODELS);
return;
}
@@ -73,7 +71,7 @@ void LoadGameObjectModelList()
|| fread(&v1, sizeof(Vector3), 1, model_list_file) != 1
|| fread(&v2, sizeof(Vector3), 1, model_list_file) != 1)
{
- sLog->outError(LOG_FILTER_GENERAL, "File '%s' seems to be corrupted!", VMAP::GAMEOBJECT_MODELS);
+ VMAP_ERROR_LOG(LOG_FILTER_GENERAL, "File '%s' seems to be corrupted!", VMAP::GAMEOBJECT_MODELS);
break;
}
@@ -84,8 +82,7 @@ void LoadGameObjectModelList()
}
fclose(model_list_file);
- sLog->outInfo(LOG_FILTER_SERVER_LOADING, ">> Loaded %u GameObject models in %u ms", uint32(model_list.size()), GetMSTimeDiffToNow(oldMSTime));
-
+ VMAP_INFO_LOG(LOG_FILTER_SERVER_LOADING, ">> Loaded %u GameObject models in %u ms", uint32(model_list.size()), GetMSTimeDiffToNow(oldMSTime));
}
GameObjectModel::~GameObjectModel()
@@ -104,7 +101,7 @@ bool GameObjectModel::initialize(const GameObject& go, const GameObjectDisplayIn
// ignore models with no bounds
if (mdl_box == G3D::AABox::zero())
{
- sLog->outError(LOG_FILTER_GENERAL, "GameObject model %s has zero bounds, loading skipped", it->second.name.c_str());
+ VMAP_ERROR_LOG(LOG_FILTER_GENERAL, "GameObject model %s has zero bounds, loading skipped", it->second.name.c_str());
return false;
}
@@ -184,5 +181,3 @@ bool GameObjectModel::intersectRay(const G3D::Ray& ray, float& MaxDist, bool Sto
}
return hit;
}
-
-#endif
diff --git a/src/server/collision/Models/ModelInstance.h b/src/server/collision/Models/ModelInstance.h
index 5af02a1d1b1..f26089bb46c 100644
--- a/src/server/collision/Models/ModelInstance.h
+++ b/src/server/collision/Models/ModelInstance.h
@@ -74,6 +74,8 @@ namespace VMAP
G3D::Matrix3 iInvRot;
float iInvScale;
WorldModel* iModel;
+ public:
+ WorldModel* getWorldModel();
};
} // namespace VMAP
diff --git a/src/server/collision/Models/WorldModel.h b/src/server/collision/Models/WorldModel.h
index 8e046e561f7..ade9efbb040 100644
--- a/src/server/collision/Models/WorldModel.h
+++ b/src/server/collision/Models/WorldModel.h
@@ -66,6 +66,8 @@ 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, Vector3 &corner) const;
};
/*! holding additional info for WMO group files */
@@ -98,6 +100,8 @@ namespace VMAP
std::vector<MeshTriangle> triangles;
BIH meshTree;
WmoLiquid* iLiquid;
+ public:
+ void getMeshData(std::vector<Vector3> &vertices, std::vector<MeshTriangle> &triangles, WmoLiquid* &liquid);
};
/*! Holds a model (converted M2 or WMO) in its original coordinate space */
class WorldModel
@@ -117,6 +121,8 @@ namespace VMAP
uint32 RootWMOID;
std::vector<GroupModel> groupModels;
BIH groupTree;
+ public:
+ void getGroupModels(std::vector<GroupModel> &groupModels);
};
} // namespace VMAP
diff --git a/src/server/collision/VMapDefinitions.h b/src/server/collision/VMapDefinitions.h
index 609d00cd00f..bb0766dc8ff 100644
--- a/src/server/collision/VMapDefinitions.h
+++ b/src/server/collision/VMapDefinitions.h
@@ -31,4 +31,16 @@ namespace VMAP
// defined in TileAssembler.cpp currently...
bool readChunk(FILE* rf, char *dest, const char *compare, uint32 len);
}
+
+// Set of helper macros for extractors (VMAP and MMAP)
+#ifndef NO_CORE_FUNCS
+#define VMAP_ERROR_LOG(FILTER, ...) sLog->outError(FILTER, __VA_ARGS__)
+#define VMAP_DEBUG_LOG(FILTER, ...) sLog->outDebug(FILTER, __VA_ARGS__)
+#define VMAP_INFO_LOG(FILTER, ...) sLog->outInfo(FILTER, __VA_ARGS__)
+#else
+#define VMAP_ERROR_LOG(FILTER, ...) (void)sizeof(FILTER)
+#define VMAP_DEBUG_LOG(FILTER, ...) (void)sizeof(FILTER)
+#define VMAP_INFO_LOG(FILTER, ...) (void)sizeof(FILTER)
+#endif
+
#endif
diff --git a/src/server/game/AI/CoreAI/PetAI.cpp b/src/server/game/AI/CoreAI/PetAI.cpp
index a8d2a2248ad..2792f68004f 100644
--- a/src/server/game/AI/CoreAI/PetAI.cpp
+++ b/src/server/game/AI/CoreAI/PetAI.cpp
@@ -432,29 +432,23 @@ void PetAI::HandleReturnMovement()
if (!me->GetCharmInfo()->IsAtStay() && !me->GetCharmInfo()->IsReturning())
{
// Return to previous position where stay was clicked
- if (!me->GetCharmInfo()->IsCommandAttack())
- {
- float x, y, z;
+ float x, y, z;
- me->GetCharmInfo()->GetStayPosition(x, y, z);
- ClearCharmInfoFlags();
- me->GetCharmInfo()->SetIsReturning(true);
- me->GetMotionMaster()->Clear();
- me->GetMotionMaster()->MovePoint(me->GetGUIDLow(), x, y, z);
- }
+ me->GetCharmInfo()->GetStayPosition(x, y, z);
+ ClearCharmInfoFlags();
+ me->GetCharmInfo()->SetIsReturning(true);
+ me->GetMotionMaster()->Clear();
+ me->GetMotionMaster()->MovePoint(me->GetGUIDLow(), x, y, z);
}
}
else // COMMAND_FOLLOW
{
if (!me->GetCharmInfo()->IsFollowing() && !me->GetCharmInfo()->IsReturning())
{
- if (!me->GetCharmInfo()->IsCommandAttack())
- {
- ClearCharmInfoFlags();
- me->GetCharmInfo()->SetIsReturning(true);
- me->GetMotionMaster()->Clear();
- me->GetMotionMaster()->MoveFollow(me->GetCharmerOrOwner(), PET_FOLLOW_DIST, me->GetFollowAngle());
- }
+ ClearCharmInfoFlags();
+ me->GetCharmInfo()->SetIsReturning(true);
+ me->GetMotionMaster()->Clear();
+ me->GetMotionMaster()->MoveFollow(me->GetCharmerOrOwner(), PET_FOLLOW_DIST, me->GetFollowAngle());
}
}
}
@@ -473,12 +467,13 @@ void PetAI::DoAttack(Unit* target, bool chase)
if (me->HasReactState(REACT_AGGRESSIVE) && !me->GetCharmInfo()->IsCommandAttack())
me->SendPetAIReaction(me->GetGUID());
-
if (chase)
{
- ClearCharmInfoFlags();
- me->GetMotionMaster()->Clear();
- me->GetMotionMaster()->MoveChase(target);
+ bool oldCmdAttack = me->GetCharmInfo()->IsCommandAttack(); // This needs to be reset after other flags are cleared
+ ClearCharmInfoFlags();
+ me->GetCharmInfo()->SetIsCommandAttack(oldCmdAttack); // For passive pets commanded to attack so they will use spells
+ me->GetMotionMaster()->Clear();
+ me->GetMotionMaster()->MoveChase(target);
}
else // (Stay && ((Aggressive || Defensive) && In Melee Range)))
{
diff --git a/src/server/game/AI/SmartScripts/SmartScript.cpp b/src/server/game/AI/SmartScripts/SmartScript.cpp
index 84c9dffabd2..86d86739bc9 100644
--- a/src/server/game/AI/SmartScripts/SmartScript.cpp
+++ b/src/server/game/AI/SmartScripts/SmartScript.cpp
@@ -2011,6 +2011,17 @@ void SmartScript::ProcessAction(SmartScriptHolder& e, Unit* unit, uint32 var0, u
}
}
+void SmartScript::ProcessTimedAction(SmartScriptHolder& e, uint32 const& min, uint32 const& max, Unit* unit, uint32 var0, uint32 var1, bool bvar, const SpellInfo* spell, GameObject* gob)
+{
+ ConditionList const conds = sConditionMgr->GetConditionsForSmartEvent(e.entryOrGuid, e.event_id, e.source_type);
+ ConditionSourceInfo info = ConditionSourceInfo(unit, GetBaseObject());
+
+ if (sConditionMgr->IsObjectMeetToConditions(info, conds))
+ ProcessAction(e, unit, var0, var1, bvar, spell, gob);
+
+ RecalcTimer(e, min, max);
+}
+
void SmartScript::InstallTemplate(SmartScriptHolder const& e)
{
if (!GetBaseObject())
@@ -2409,20 +2420,17 @@ void SmartScript::ProcessEvent(SmartScriptHolder& e, Unit* unit, uint32 var0, ui
break;
//called from Update tick
case SMART_EVENT_UPDATE:
- RecalcTimer(e, e.event.minMaxRepeat.repeatMin, e.event.minMaxRepeat.repeatMax);
- ProcessAction(e);
+ ProcessTimedAction(e, e.event.minMaxRepeat.repeatMin, e.event.minMaxRepeat.repeatMax);
break;
case SMART_EVENT_UPDATE_OOC:
if (me && me->isInCombat())
return;
- RecalcTimer(e, e.event.minMaxRepeat.repeatMin, e.event.minMaxRepeat.repeatMax);
- ProcessAction(e);
+ ProcessTimedAction(e, e.event.minMaxRepeat.repeatMin, e.event.minMaxRepeat.repeatMax);
break;
case SMART_EVENT_UPDATE_IC:
if (!me || !me->isInCombat())
return;
- RecalcTimer(e, e.event.minMaxRepeat.repeatMin, e.event.minMaxRepeat.repeatMax);
- ProcessAction(e);
+ ProcessTimedAction(e, e.event.minMaxRepeat.repeatMin, e.event.minMaxRepeat.repeatMax);
break;
case SMART_EVENT_HEALT_PCT:
{
@@ -2431,8 +2439,7 @@ void SmartScript::ProcessEvent(SmartScriptHolder& e, Unit* unit, uint32 var0, ui
uint32 perc = (uint32)me->GetHealthPct();
if (perc > e.event.minMaxRepeat.max || perc < e.event.minMaxRepeat.min)
return;
- RecalcTimer(e, e.event.minMaxRepeat.repeatMin, e.event.minMaxRepeat.repeatMax);
- ProcessAction(e);
+ ProcessTimedAction(e, e.event.minMaxRepeat.repeatMin, e.event.minMaxRepeat.repeatMax);
break;
}
case SMART_EVENT_TARGET_HEALTH_PCT:
@@ -2442,8 +2449,7 @@ void SmartScript::ProcessEvent(SmartScriptHolder& e, Unit* unit, uint32 var0, ui
uint32 perc = (uint32)me->getVictim()->GetHealthPct();
if (perc > e.event.minMaxRepeat.max || perc < e.event.minMaxRepeat.min)
return;
- RecalcTimer(e, e.event.minMaxRepeat.repeatMin, e.event.minMaxRepeat.repeatMax);
- ProcessAction(e, me->getVictim());
+ ProcessTimedAction(e, e.event.minMaxRepeat.repeatMin, e.event.minMaxRepeat.repeatMax, me->getVictim());
break;
}
case SMART_EVENT_MANA_PCT:
@@ -2453,8 +2459,7 @@ void SmartScript::ProcessEvent(SmartScriptHolder& e, Unit* unit, uint32 var0, ui
uint32 perc = uint32(100.0f * me->GetPower(POWER_MANA) / me->GetMaxPower(POWER_MANA));
if (perc > e.event.minMaxRepeat.max || perc < e.event.minMaxRepeat.min)
return;
- RecalcTimer(e, e.event.minMaxRepeat.repeatMin, e.event.minMaxRepeat.repeatMax);
- ProcessAction(e);
+ ProcessTimedAction(e, e.event.minMaxRepeat.repeatMin, e.event.minMaxRepeat.repeatMax);
break;
}
case SMART_EVENT_TARGET_MANA_PCT:
@@ -2464,8 +2469,7 @@ void SmartScript::ProcessEvent(SmartScriptHolder& e, Unit* unit, uint32 var0, ui
uint32 perc = uint32(100.0f * me->getVictim()->GetPower(POWER_MANA) / me->getVictim()->GetMaxPower(POWER_MANA));
if (perc > e.event.minMaxRepeat.max || perc < e.event.minMaxRepeat.min)
return;
- RecalcTimer(e, e.event.minMaxRepeat.repeatMin, e.event.minMaxRepeat.repeatMax);
- ProcessAction(e, me->getVictim());
+ ProcessTimedAction(e, e.event.minMaxRepeat.repeatMin, e.event.minMaxRepeat.repeatMax, me->getVictim());
break;
}
case SMART_EVENT_RANGE:
@@ -2474,18 +2478,15 @@ void SmartScript::ProcessEvent(SmartScriptHolder& e, Unit* unit, uint32 var0, ui
return;
if (me->IsInRange(me->getVictim(), (float)e.event.minMaxRepeat.min, (float)e.event.minMaxRepeat.max))
- {
- ProcessAction(e, me->getVictim());
- RecalcTimer(e, e.event.minMaxRepeat.repeatMin, e.event.minMaxRepeat.repeatMax);
- }
+ ProcessTimedAction(e, e.event.minMaxRepeat.repeatMin, e.event.minMaxRepeat.repeatMax, me->getVictim());
break;
}
case SMART_EVENT_TARGET_CASTING:
{
if (!me || !me->isInCombat() || !me->getVictim() || !me->getVictim()->IsNonMeleeSpellCasted(false, false, true))
return;
- ProcessAction(e, me->getVictim());
- RecalcTimer(e, e.event.minMax.repeatMin, e.event.minMax.repeatMax);
+
+ ProcessTimedAction(e, e.event.minMaxRepeat.repeatMin, e.event.minMaxRepeat.repeatMax, me->getVictim());
}
case SMART_EVENT_FRIENDLY_HEALTH:
{
@@ -2495,8 +2496,7 @@ void SmartScript::ProcessEvent(SmartScriptHolder& e, Unit* unit, uint32 var0, ui
Unit* target = DoSelectLowestHpFriendly((float)e.event.friendlyHealt.radius, e.event.friendlyHealt.hpDeficit);
if (!target)
return;
- ProcessAction(e, target);
- RecalcTimer(e, e.event.friendlyHealt.repeatMin, e.event.friendlyHealt.repeatMax);
+ ProcessTimedAction(e, e.event.friendlyHealt.repeatMin, e.event.friendlyHealt.repeatMax, target);
break;
}
case SMART_EVENT_FRIENDLY_IS_CC:
@@ -2508,8 +2508,7 @@ void SmartScript::ProcessEvent(SmartScriptHolder& e, Unit* unit, uint32 var0, ui
DoFindFriendlyCC(pList, (float)e.event.friendlyCC.radius);
if (pList.empty())
return;
- ProcessAction(e, *(pList.begin()));
- RecalcTimer(e, e.event.friendlyCC.repeatMin, e.event.friendlyCC.repeatMax);
+ ProcessTimedAction(e, e.event.friendlyCC.repeatMin, e.event.friendlyCC.repeatMax, *pList.begin());
break;
}
case SMART_EVENT_FRIENDLY_MISSING_BUFF:
@@ -2519,8 +2518,8 @@ void SmartScript::ProcessEvent(SmartScriptHolder& e, Unit* unit, uint32 var0, ui
if (pList.empty())
return;
- ProcessAction(e, *(pList.begin()));
- RecalcTimer(e, e.event.missingBuff.repeatMin, e.event.missingBuff.repeatMax);
+
+ ProcessTimedAction(e, e.event.missingBuff.repeatMin, e.event.missingBuff.repeatMax, *pList.begin());
break;
}
case SMART_EVENT_HAS_AURA:
@@ -2529,10 +2528,7 @@ void SmartScript::ProcessEvent(SmartScriptHolder& e, Unit* unit, uint32 var0, ui
return;
uint32 count = me->GetAuraCount(e.event.aura.spell);
if ((!e.event.aura.count && !count) || (e.event.aura.count && count >= e.event.aura.count))
- {
- ProcessAction(e);
- RecalcTimer(e, e.event.aura.repeatMin, e.event.aura.repeatMax);
- }
+ ProcessTimedAction(e, e.event.aura.repeatMin, e.event.aura.repeatMax);
break;
}
case SMART_EVENT_TARGET_BUFFED:
@@ -2542,8 +2538,7 @@ void SmartScript::ProcessEvent(SmartScriptHolder& e, Unit* unit, uint32 var0, ui
uint32 count = me->getVictim()->GetAuraCount(e.event.aura.spell);
if (count < e.event.aura.count)
return;
- ProcessAction(e);
- RecalcTimer(e, e.event.aura.repeatMin, e.event.aura.repeatMax);
+ ProcessTimedAction(e, e.event.aura.repeatMin, e.event.aura.repeatMax);
break;
}
//no params
@@ -2578,10 +2573,7 @@ void SmartScript::ProcessEvent(SmartScriptHolder& e, Unit* unit, uint32 var0, ui
if (Unit* victim = me->getVictim())
{
if (!victim->HasInArc(static_cast<float>(M_PI), me))
- {
- ProcessAction(e, victim);
- RecalcTimer(e, e.event.behindTarget.cooldownMin, e.event.behindTarget.cooldownMax);
- }
+ ProcessTimedAction(e, e.event.behindTarget.cooldownMin, e.event.behindTarget.cooldownMax, victim);
}
break;
}
diff --git a/src/server/game/AI/SmartScripts/SmartScript.h b/src/server/game/AI/SmartScripts/SmartScript.h
index d0d0221493f..28b328a2947 100644
--- a/src/server/game/AI/SmartScripts/SmartScript.h
+++ b/src/server/game/AI/SmartScripts/SmartScript.h
@@ -45,6 +45,7 @@ class SmartScript
void UpdateTimer(SmartScriptHolder& e, uint32 const diff);
void InitTimer(SmartScriptHolder& e);
void ProcessAction(SmartScriptHolder& e, Unit* unit = NULL, uint32 var0 = 0, uint32 var1 = 0, bool bvar = false, const SpellInfo* spell = NULL, GameObject* gob = NULL);
+ void ProcessTimedAction(SmartScriptHolder& e, uint32 const& min, uint32 const& max, Unit* unit = NULL, uint32 var0 = 0, uint32 var1 = 0, bool bvar = false, const SpellInfo* spell = NULL, GameObject* gob = NULL);
ObjectList* GetTargets(SmartScriptHolder const& e, Unit* invoker = NULL);
ObjectList* GetWorldObjectsInDist(float dist);
void InstallTemplate(SmartScriptHolder const& e);
diff --git a/src/server/game/Battlegrounds/Battleground.cpp b/src/server/game/Battlegrounds/Battleground.cpp
index 445d1295629..e2ae9f50452 100644
--- a/src/server/game/Battlegrounds/Battleground.cpp
+++ b/src/server/game/Battlegrounds/Battleground.cpp
@@ -973,7 +973,7 @@ void Battleground::EndBattleground(uint32 winner)
player->GetSession()->SendPacket(&pvpLogData);
WorldPacket data;
- sBattlegroundMgr->BuildBattlegroundStatusPacket(&data, this, player, player->GetBattlegroundQueueIndex(bgQueueTypeId), STATUS_IN_PROGRESS, player->GetBattlegroundQueueJoinTime(GetTypeID()), GetElapsedTime(), GetArenaType());
+ sBattlegroundMgr->BuildBattlegroundStatusPacket(&data, this, player, player->GetBattlegroundQueueIndex(bgQueueTypeId), STATUS_IN_PROGRESS, TIME_TO_AUTOREMOVE, player->GetBattlegroundQueueJoinTime(GetTypeID()), GetElapsedTime(), GetArenaType());
player->GetSession()->SendPacket(&data);
player->UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_COMPLETE_BATTLEGROUND, 1);
@@ -1204,13 +1204,9 @@ void Battleground::AddPlayer(Player* player)
sBattlegroundMgr->BuildPlayerJoinedBattlegroundPacket(&data, player->GetGUID());
SendPacketToTeam(team, &data, player, false);
- // BG Status packet
- BattlegroundQueueTypeId bgQueueTypeId = sBattlegroundMgr->BGQueueTypeId(m_TypeID, GetArenaType());
- uint32 queueSlot = player->GetBattlegroundQueueIndex(bgQueueTypeId);
sBattlegroundMgr->BuildBattlegroundStatusPacket(&data, this, player, queueSlot, STATUS_IN_PROGRESS, player->GetBattlegroundQueueJoinTime(m_TypeID), GetElapsedTime(), GetArenaType());
player->GetSession()->SendPacket(&data);
-
player->RemoveAurasByType(SPELL_AURA_MOUNTED);
// add arena specific auras
diff --git a/src/server/game/Battlegrounds/BattlegroundMgr.cpp b/src/server/game/Battlegrounds/BattlegroundMgr.cpp
index c370b3a26ce..1061f8aadba 100644
--- a/src/server/game/Battlegrounds/BattlegroundMgr.cpp
+++ b/src/server/game/Battlegrounds/BattlegroundMgr.cpp
@@ -891,6 +891,27 @@ Battleground* BattlegroundMgr::CreateNewBattleground(BattlegroundTypeId original
bg->SetRandom(isRandom);
bg->SetGuid(MAKE_NEW_GUID(bgTypeId, 0, HIGHGUID_BATTLEGROUND));
+ // Set up correct min/max player counts for scoreboards
+ if (bg->isArena())
+ {
+ uint32 maxPlayersPerTeam = 0;
+ switch (arenaType)
+ {
+ case ARENA_TYPE_2v2:
+ maxPlayersPerTeam = 2;
+ break;
+ case ARENA_TYPE_3v3:
+ maxPlayersPerTeam = 3;
+ break;
+ case ARENA_TYPE_5v5:
+ maxPlayersPerTeam = 5;
+ break;
+ }
+
+ bg->SetMaxPlayersPerTeam(maxPlayersPerTeam);
+ bg->SetMaxPlayers(maxPlayersPerTeam * 2);
+ }
+
return bg;
}
@@ -957,8 +978,8 @@ bool BattlegroundMgr::CreateBattleground(CreateBattlegroundData& data)
bg->SetArenaorBGType(data.IsArena);
bg->SetMinPlayersPerTeam(data.MinPlayersPerTeam);
bg->SetMaxPlayersPerTeam(data.MaxPlayersPerTeam);
- bg->SetMinPlayers(data.MinPlayersPerTeam* 2);
- bg->SetMaxPlayers(data.MaxPlayersPerTeam* 2);
+ bg->SetMinPlayers(data.MinPlayersPerTeam * 2);
+ bg->SetMaxPlayers(data.MaxPlayersPerTeam * 2);
bg->SetName(data.BattlegroundName);
bg->SetTeamStartLoc(ALLIANCE, data.Team1StartLocX, data.Team1StartLocY, data.Team1StartLocZ, data.Team1StartLocO);
bg->SetTeamStartLoc(HORDE, data.Team2StartLocX, data.Team2StartLocY, data.Team2StartLocZ, data.Team2StartLocO);
diff --git a/src/server/game/CMakeLists.txt b/src/server/game/CMakeLists.txt
index 12de44ac57f..be3997243e4 100644
--- a/src/server/game/CMakeLists.txt
+++ b/src/server/game/CMakeLists.txt
@@ -102,6 +102,8 @@ set(game_STAT_SRCS
include_directories(
${CMAKE_BINARY_DIR}
+ ${CMAKE_SOURCE_DIR}/dep/recastnavigation/Detour
+ ${CMAKE_SOURCE_DIR}/dep/recastnavigation/Recast
${CMAKE_SOURCE_DIR}/dep/g3dlite/include
${CMAKE_SOURCE_DIR}/dep/SFMT
${CMAKE_SOURCE_DIR}/dep/zlib
diff --git a/src/server/game/Combat/ThreatManager.cpp b/src/server/game/Combat/ThreatManager.cpp
index bedc167b711..1464dfece95 100644
--- a/src/server/game/Combat/ThreatManager.cpp
+++ b/src/server/game/Combat/ThreatManager.cpp
@@ -416,23 +416,21 @@ void ThreatManager::addThreat(Unit* victim, float threat, SpellSchoolMask school
void ThreatManager::doAddThreat(Unit* victim, float threat)
{
- uint32 reducedThreadPercent = victim->GetReducedThreatPercent();
+ uint32 redirectThreadPct = victim->GetRedirectThreatPercent();
// must check > 0.0f, otherwise dead loop
- if (threat > 0.0f && reducedThreadPercent)
+ if (threat > 0.0f && redirectThreadPct)
{
- Unit* redirectTarget = victim->GetMisdirectionTarget();
- if (redirectTarget)
- if (Aura* glyphAura = redirectTarget->GetAura(63326)) // Glyph of Vigilance
- reducedThreadPercent += glyphAura->GetSpellInfo()->Effects[0].CalcValue(glyphAura->GetCaster());
-
- float reducedThreat = threat * reducedThreadPercent / 100.0f;
- threat -= reducedThreat;
- if (redirectTarget)
- _addThreat(redirectTarget, reducedThreat);
+ if (Unit* redirectTarget = victim->GetRedirectThreatTarget())
+ {
+ float redirectThreat = CalculatePct(threat, redirectThreadPct);
+ threat -= redirectThreat;
+ _addThreat(redirectTarget, redirectThreat);
+ }
}
_addThreat(victim, threat);
+
}
void ThreatManager::_addThreat(Unit* victim, float threat)
diff --git a/src/server/game/Conditions/DisableMgr.cpp b/src/server/game/Conditions/DisableMgr.cpp
index fefb51323c4..7e379fdaded 100644
--- a/src/server/game/Conditions/DisableMgr.cpp
+++ b/src/server/game/Conditions/DisableMgr.cpp
@@ -42,7 +42,7 @@ namespace
DisableMap m_DisableMap;
- uint8 MAX_DISABLE_TYPES = 7;
+ uint8 MAX_DISABLE_TYPES = 8;
}
void LoadDisables()
@@ -222,6 +222,34 @@ void LoadDisables()
}
break;
}
+ case DISABLE_TYPE_MMAP:
+ {
+ MapEntry const* mapEntry = sMapStore.LookupEntry(entry);
+ if (!mapEntry)
+ {
+ sLog->outError(LOG_FILTER_SQL, "Map entry %u from `disables` doesn't exist in dbc, skipped.", entry);
+ continue;
+ }
+ switch (mapEntry->map_type)
+ {
+ case MAP_COMMON:
+ sLog->outInfo(LOG_FILTER_GENERAL, "Pathfinding disabled for world map %u.", entry);
+ break;
+ case MAP_INSTANCE:
+ case MAP_RAID:
+ sLog->outInfo(LOG_FILTER_GENERAL, "Pathfinding disabled for instance map %u.", entry);
+ break;
+ case MAP_BATTLEGROUND:
+ sLog->outInfo(LOG_FILTER_GENERAL, "Pathfinding disabled for battleground map %u.", entry);
+ break;
+ case MAP_ARENA:
+ sLog->outInfo(LOG_FILTER_GENERAL, "Pathfinding disabled for arena map %u.", entry);
+ break;
+ default:
+ break;
+ }
+ break;
+ }
default:
break;
}
@@ -350,6 +378,7 @@ bool IsDisabledFor(DisableType type, uint32 entry, Unit const* unit, uint8 flags
case DISABLE_TYPE_BATTLEGROUND:
case DISABLE_TYPE_OUTDOORPVP:
case DISABLE_TYPE_ACHIEVEMENT_CRITERIA:
+ case DISABLE_TYPE_MMAP:
return true;
case DISABLE_TYPE_VMAP:
return flags & itr->second.flags;
diff --git a/src/server/game/Conditions/DisableMgr.h b/src/server/game/Conditions/DisableMgr.h
index 89761931048..38751b8a89f 100644
--- a/src/server/game/Conditions/DisableMgr.h
+++ b/src/server/game/Conditions/DisableMgr.h
@@ -31,7 +31,8 @@ enum DisableType
DISABLE_TYPE_BATTLEGROUND = 3,
DISABLE_TYPE_ACHIEVEMENT_CRITERIA = 4,
DISABLE_TYPE_OUTDOORPVP = 5,
- DISABLE_TYPE_VMAP = 6
+ DISABLE_TYPE_VMAP = 6,
+ DISABLE_TYPE_MMAP = 7
};
enum SpellDisableTypes
@@ -56,6 +57,11 @@ enum VmapDisableTypes
VMAP_DISABLE_LIQUIDSTATUS = 0x8
};
+enum MMapDisableTypes
+{
+ MMAP_DISABLE_PATHFINDING = 0x0
+};
+
namespace DisableMgr
{
void LoadDisables();
diff --git a/src/server/game/DataStores/DBCStores.cpp b/src/server/game/DataStores/DBCStores.cpp
index c168f0e1acf..de05fd200b3 100644
--- a/src/server/game/DataStores/DBCStores.cpp
+++ b/src/server/game/DataStores/DBCStores.cpp
@@ -288,9 +288,10 @@ inline void LoadDBC(uint32& availableDbcLocales, StoreProblemList& errors, DBCSt
// sort problematic dbc to (1) non compatible and (2) non-existed
if (FILE* f = fopen(dbcFilename.c_str(), "rb"))
{
- char buf[100];
- snprintf(buf, 100, " exists, and has %u field(s) (expected " SIZEFMTD "). Extracted file might be from wrong client version or a database-update has been forgotten.", storage.GetFieldCount(), strlen(storage.GetFormat()));
- errors.push_back(dbcFilename + buf);
+ std::ostringstream stream;
+ stream << dbcFilename << " exists, and has " << storage.GetFieldCount() << " field(s) (expected " << strlen(storage.GetFormat()) << "). Extracted file might be from wrong client version or a database-update has been forgotten.";
+ std::string buf = stream.str();
+ errors.push_back(buf);
fclose(f);
}
else
diff --git a/src/server/game/Entities/Creature/GossipDef.cpp b/src/server/game/Entities/Creature/GossipDef.cpp
index 700b71303ab..3cd0a1223dd 100644
--- a/src/server/game/Entities/Creature/GossipDef.cpp
+++ b/src/server/game/Entities/Creature/GossipDef.cpp
@@ -142,6 +142,9 @@ void PlayerMenu::SendGossipMenu(uint32 titleTextId, uint64 objectGUID) const
data << uint32(_questMenu.GetMenuItemCount()); // max count 0x20
+ // Store this instead of checking the Singleton every loop iteration
+ bool questLevelInTitle = sWorld->getBoolConfig(CONFIG_UI_QUESTLEVELS_IN_DIALOGS);
+
for (uint8 i = 0; i < _questMenu.GetMenuItemCount(); ++i)
{
QuestMenuItem const& item = _questMenu.GetItem(i);
@@ -160,6 +163,9 @@ void PlayerMenu::SendGossipMenu(uint32 titleTextId, uint64 objectGUID) const
if (QuestLocale const* localeData = sObjectMgr->GetQuestLocale(questID))
ObjectMgr::GetLocaleString(localeData->Title, locale, title);
+ if (questLevelInTitle)
+ AddQuestLevelToTitle(title, quest->GetQuestLevel());
+
data << title; // max 0x200
}
@@ -252,6 +258,10 @@ void PlayerMenu::SendQuestGiverQuestList(QEmote eEmote, const std::string& Title
size_t count_pos = data.wpos();
data << uint8 (_questMenu.GetMenuItemCount());
uint32 count = 0;
+
+ // Store this instead of checking the Singleton every loop iteration
+ bool questLevelInTitle = sWorld->getBoolConfig(CONFIG_UI_QUESTLEVELS_IN_DIALOGS);
+
for (; count < _questMenu.GetMenuItemCount(); ++count)
{
QuestMenuItem const& qmi = _questMenu.GetItem(count);
@@ -267,6 +277,9 @@ void PlayerMenu::SendQuestGiverQuestList(QEmote eEmote, const std::string& Title
if (QuestLocale const* localeData = sObjectMgr->GetQuestLocale(questID))
ObjectMgr::GetLocaleString(localeData->Title, locale, title);
+ if (questLevelInTitle)
+ AddQuestLevelToTitle(title, quest->GetQuestLevel());
+
data << uint32(questID);
data << uint32(qmi.QuestIcon);
data << int32(quest->GetQuestLevel());
@@ -318,6 +331,9 @@ void PlayerMenu::SendQuestGiverQuestDetails(Quest const* quest, uint64 npcGUID,
}
}
+ if (sWorld->getBoolConfig(CONFIG_UI_QUESTLEVELS_IN_DIALOGS))
+ AddQuestLevelToTitle(questTitle, quest->GetQuestLevel());
+
WorldPacket data(SMSG_QUESTGIVER_QUEST_DETAILS, 100); // guess size
data << uint64(npcGUID);
data << uint64(0); // either 0 or a npc guid (quest giver)
@@ -467,6 +483,9 @@ void PlayerMenu::SendQuestQueryResponse(Quest const* quest) const
data << float(quest->GetPointY());
data << uint32(quest->GetPointOpt());
+ if (sWorld->getBoolConfig(CONFIG_UI_QUESTLEVELS_IN_DIALOGS))
+ AddQuestLevelToTitle(questTitle, quest->GetQuestLevel());
+
data << questTitle;
data << questObjectives;
data << questDetails;
@@ -542,6 +561,9 @@ void PlayerMenu::SendQuestGiverOfferReward(Quest const* quest, uint64 npcGUID, b
}
}
+ if (sWorld->getBoolConfig(CONFIG_UI_QUESTLEVELS_IN_DIALOGS))
+ AddQuestLevelToTitle(questTitle, quest->GetQuestLevel());
+
WorldPacket data(SMSG_QUESTGIVER_OFFER_REWARD, 50); // guess size
data << uint64(npcGUID);
data << uint32(quest->GetQuestId());
@@ -604,6 +626,9 @@ void PlayerMenu::SendQuestGiverRequestItems(Quest const* quest, uint64 npcGUID,
return;
}
+ if (sWorld->getBoolConfig(CONFIG_UI_QUESTLEVELS_IN_DIALOGS))
+ AddQuestLevelToTitle(questTitle, quest->GetQuestLevel());
+
WorldPacket data(SMSG_QUESTGIVER_REQUEST_ITEMS, 50); // guess size
data << uint64(npcGUID);
data << uint32(quest->GetQuestId());
@@ -664,3 +689,13 @@ void PlayerMenu::SendQuestGiverRequestItems(Quest const* quest, uint64 npcGUID,
_session->SendPacket(&data);
sLog->outDebug(LOG_FILTER_NETWORKIO, "WORLD: Sent SMSG_QUESTGIVER_REQUEST_ITEMS NPCGuid=%u, questid=%u", GUID_LOPART(npcGUID), quest->GetQuestId());
}
+
+void PlayerMenu::AddQuestLevelToTitle(std::string &title, int32 level)
+{
+ // Adds the quest level to the front of the quest title
+ // example: [13] Westfall Stew
+
+ std::stringstream questTitlePretty;
+ questTitlePretty << "[" << level << "] " << title;
+ title = questTitlePretty.str();
+}
diff --git a/src/server/game/Entities/Creature/GossipDef.h b/src/server/game/Entities/Creature/GossipDef.h
index b1b45b3d459..7d6d21cd9ad 100644
--- a/src/server/game/Entities/Creature/GossipDef.h
+++ b/src/server/game/Entities/Creature/GossipDef.h
@@ -277,6 +277,8 @@ class PlayerMenu
void SendQuestGiverOfferReward(Quest const* quest, uint64 npcGUID, bool enableNext) const;
void SendQuestGiverRequestItems(Quest const* quest, uint64 npcGUID, bool canComplete, bool closeOnCancel) const;
+ static void AddQuestLevelToTitle(std::string &title, int32 level);
+
private:
GossipMenu _gossipMenu;
QuestMenu _questMenu;
diff --git a/src/server/game/Entities/Object/Object.cpp b/src/server/game/Entities/Object/Object.cpp
index 4c6a13136eb..53e7c3405a0 100644
--- a/src/server/game/Entities/Object/Object.cpp
+++ b/src/server/game/Entities/Object/Object.cpp
@@ -76,7 +76,6 @@ Object::Object() : m_PackGUID(sizeof(uint64)+1)
m_objectType = TYPEMASK_OBJECT;
m_uint32Values = NULL;
- _changedFields = NULL;
m_valuesCount = 0;
_fieldNotifyFlags = UF_FLAG_DYNAMIC;
@@ -120,8 +119,6 @@ Object::~Object()
}
delete [] m_uint32Values;
- delete [] _changedFields;
-
}
void Object::_InitValues()
@@ -129,8 +126,7 @@ void Object::_InitValues()
m_uint32Values = new uint32[m_valuesCount];
memset(m_uint32Values, 0, m_valuesCount*sizeof(uint32));
- _changedFields = new bool[m_valuesCount];
- memset(_changedFields, 0, m_valuesCount*sizeof(bool));
+ _changesMask.SetCount(m_valuesCount);
m_objectUpdated = false;
}
@@ -901,7 +897,7 @@ void Object::_BuildValuesUpdate(uint8 updatetype, ByteBuffer* data, UpdateMask*
void Object::ClearUpdateMask(bool remove)
{
- memset(_changedFields, 0, m_valuesCount*sizeof(bool));
+ _changesMask.Clear();
if (m_objectUpdated)
{
@@ -998,13 +994,12 @@ void Object::_LoadIntoDataField(std::string const& data, uint32 startOffset, uin
for (uint32 index = 0; index < count; ++index)
{
m_uint32Values[startOffset + index] = atol(tokens[index]);
- _changedFields[startOffset + index] = true;
+ _changesMask.SetBit(startOffset + index);
}
}
void Object::_SetUpdateBits(UpdateMask* updateMask, Player* target) const
{
- bool* indexes = _changedFields;
uint32* flags = NULL;
bool isSelf = target == this;
bool isOwner = false;
@@ -1018,8 +1013,7 @@ void Object::_SetUpdateBits(UpdateMask* updateMask, Player* target) const
if (GetTypeId() == TYPEID_PLAYER && target != this)
valCount = PLAYER_END_NOT_SELF;
- for (uint16 index = 0; index < valCount; ++index, ++indexes)
- if (_fieldNotifyFlags & flags[index] || (flags[index] & UF_FLAG_SPECIAL_INFO && hasSpecialInfo) || (*indexes && IsUpdateFieldVisible(flags[index], isSelf, isOwner, isItemOwner, isPartyMember)))
+ for (uint16 index = 0; index < valCount; ++index)
updateMask->SetBit(index);
}
@@ -1051,7 +1045,7 @@ void Object::SetInt32Value(uint16 index, int32 value)
if (m_int32Values[index] != value)
{
m_int32Values[index] = value;
- _changedFields[index] = true;
+ _changesMask.SetBit(index);
if (m_inWorld && !m_objectUpdated)
{
@@ -1068,7 +1062,7 @@ void Object::SetUInt32Value(uint16 index, uint32 value)
if (m_uint32Values[index] != value)
{
m_uint32Values[index] = value;
- _changedFields[index] = true;
+ _changesMask.SetBit(index);
if (m_inWorld && !m_objectUpdated)
{
@@ -1083,7 +1077,7 @@ void Object::UpdateUInt32Value(uint16 index, uint32 value)
ASSERT(index < m_valuesCount || PrintIndexError(index, true));
m_uint32Values[index] = value;
- _changedFields[index] = true;
+ _changesMask.SetBit(index);
}
void Object::SetUInt64Value(uint16 index, uint64 value)
@@ -1093,8 +1087,8 @@ void Object::SetUInt64Value(uint16 index, uint64 value)
{
m_uint32Values[index] = PAIR64_LOPART(value);
m_uint32Values[index + 1] = PAIR64_HIPART(value);
- _changedFields[index] = true;
- _changedFields[index + 1] = true;
+ _changesMask.SetBit(index);
+ _changesMask.SetBit(index + 1);
if (m_inWorld && !m_objectUpdated)
{
@@ -1111,8 +1105,8 @@ bool Object::AddUInt64Value(uint16 index, uint64 value)
{
m_uint32Values[index] = PAIR64_LOPART(value);
m_uint32Values[index + 1] = PAIR64_HIPART(value);
- _changedFields[index] = true;
- _changedFields[index + 1] = true;
+ _changesMask.SetBit(index);
+ _changesMask.SetBit(index + 1);
if (m_inWorld && !m_objectUpdated)
{
@@ -1133,8 +1127,8 @@ bool Object::RemoveUInt64Value(uint16 index, uint64 value)
{
m_uint32Values[index] = 0;
m_uint32Values[index + 1] = 0;
- _changedFields[index] = true;
- _changedFields[index + 1] = true;
+ _changesMask.SetBit(index);
+ _changesMask.SetBit(index + 1);
if (m_inWorld && !m_objectUpdated)
{
@@ -1155,7 +1149,7 @@ void Object::SetFloatValue(uint16 index, float value)
if (m_floatValues[index] != value)
{
m_floatValues[index] = value;
- _changedFields[index] = true;
+ _changesMask.SetBit(index);
if (m_inWorld && !m_objectUpdated)
{
@@ -1179,7 +1173,7 @@ void Object::SetByteValue(uint16 index, uint8 offset, uint8 value)
{
m_uint32Values[index] &= ~uint32(uint32(0xFF) << (offset * 8));
m_uint32Values[index] |= uint32(uint32(value) << (offset * 8));
- _changedFields[index] = true;
+ _changesMask.SetBit(index);
if (m_inWorld && !m_objectUpdated)
{
@@ -1203,7 +1197,7 @@ void Object::SetUInt16Value(uint16 index, uint8 offset, uint16 value)
{
m_uint32Values[index] &= ~uint32(uint32(0xFFFF) << (offset * 16));
m_uint32Values[index] |= uint32(uint32(value) << (offset * 16));
- _changedFields[index] = true;
+ _changesMask.SetBit(index);
if (m_inWorld && !m_objectUpdated)
{
@@ -1270,7 +1264,7 @@ void Object::SetFlag(uint16 index, uint32 newFlag)
if (oldval != newval)
{
m_uint32Values[index] = newval;
- _changedFields[index] = true;
+ _changesMask.SetBit(index);
if (m_inWorld && !m_objectUpdated)
{
@@ -1291,7 +1285,7 @@ void Object::RemoveFlag(uint16 index, uint32 oldFlag)
if (oldval != newval)
{
m_uint32Values[index] = newval;
- _changedFields[index] = true;
+ _changesMask.SetBit(index);
if (m_inWorld && !m_objectUpdated)
{
@@ -1314,7 +1308,7 @@ void Object::SetByteFlag(uint16 index, uint8 offset, uint8 newFlag)
if (!(uint8(m_uint32Values[index] >> (offset * 8)) & newFlag))
{
m_uint32Values[index] |= uint32(uint32(newFlag) << (offset * 8));
- _changedFields[index] = true;
+ _changesMask.SetBit(index);
if (m_inWorld && !m_objectUpdated)
{
@@ -1337,7 +1331,7 @@ void Object::RemoveByteFlag(uint16 index, uint8 offset, uint8 oldFlag)
if (uint8(m_uint32Values[index] >> (offset * 8)) & oldFlag)
{
m_uint32Values[index] &= ~uint32(uint32(oldFlag) << (offset * 8));
- _changedFields[index] = true;
+ _changesMask.SetBit(index);
if (m_inWorld && !m_objectUpdated)
{
@@ -2113,7 +2107,7 @@ void WorldObject::SendPlaySound(uint32 Sound, bool OnlySelf)
void Object::ForceValuesUpdateAtIndex(uint32 i)
{
- _changedFields[i] = true;
+ _changesMask.SetBit(i);
if (m_inWorld && !m_objectUpdated)
{
sObjectAccessor->AddUpdateObject(this);
@@ -2838,7 +2832,7 @@ void WorldObject::MovePosition(Position &pos, float dist, float angle)
desty = pos.m_positionY + dist * std::sin(angle);
// Prevent invalid coordinates here, position is unchanged
- if (!Trinity::IsValidMapCoord(destx, desty))
+ if (!Trinity::IsValidMapCoord(destx, desty, pos.m_positionZ))
{
sLog->outFatal(LOG_FILTER_GENERAL, "WorldObject::MovePosition invalid coordinates X: %f and Y: %f were passed!", destx, desty);
return;
diff --git a/src/server/game/Entities/Object/Object.h b/src/server/game/Entities/Object/Object.h
index ebe29e0f5a3..3ec5146f876 100644
--- a/src/server/game/Entities/Object/Object.h
+++ b/src/server/game/Entities/Object/Object.h
@@ -20,7 +20,7 @@
#define _OBJECT_H
#include "Common.h"
-#include "UpdateFields.h"
+#include "UpdateMask.h"
#include "UpdateData.h"
#include "GridReference.h"
#include "ObjectDefines.h"
@@ -107,7 +107,6 @@ class ByteBuffer;
class WorldSession;
class Creature;
class Player;
-class UpdateMask;
class InstanceScript;
class GameObject;
class TempSummon;
@@ -408,7 +407,7 @@ class Object
float *m_floatValues;
};
- bool* _changedFields;
+ UpdateMask _changesMask;
uint16 m_valuesCount;
diff --git a/src/server/game/Entities/Player/Player.cpp b/src/server/game/Entities/Player/Player.cpp
index 1fe980f60b5..fb8891893da 100644
--- a/src/server/game/Entities/Player/Player.cpp
+++ b/src/server/game/Entities/Player/Player.cpp
@@ -10825,7 +10825,7 @@ InventoryResult Player::CanStoreItem(uint8 bag, uint8 slot, ItemPosCountVec &des
{
if (no_space_count)
*no_space_count = count;
- return swap ? EQUIP_ERR_CANT_SWAP :EQUIP_ERR_ITEM_NOT_FOUND;
+ return swap ? EQUIP_ERR_CANT_SWAP : EQUIP_ERR_ITEM_NOT_FOUND;
}
if (pItem)
@@ -11365,8 +11365,37 @@ InventoryResult Player::CanEquipItem(uint8 slot, uint16 &dest, Item* pItem, bool
if (!swap && GetItemByPos(INVENTORY_SLOT_BAG_0, eslot))
return EQUIP_ERR_NO_SLOT_AVAILABLE;
- // if swap ignore item (equipped also)
- InventoryResult res2 = CanEquipUniqueItem(pItem, swap ? eslot : uint8(NULL_SLOT));
+ // if we are swapping 2 equiped items, CanEquipUniqueItem check
+ // should ignore the item we are trying to swap, and not the
+ // destination item. CanEquipUniqueItem should ignore destination
+ // item only when we are swapping weapon from bag
+ uint8 ignore = uint8(NULL_SLOT);
+ switch (eslot)
+ {
+ case EQUIPMENT_SLOT_MAINHAND:
+ ignore = EQUIPMENT_SLOT_OFFHAND;
+ break;
+ case EQUIPMENT_SLOT_OFFHAND:
+ ignore = EQUIPMENT_SLOT_MAINHAND;
+ break;
+ case EQUIPMENT_SLOT_FINGER1:
+ ignore = EQUIPMENT_SLOT_FINGER2;
+ break;
+ case EQUIPMENT_SLOT_FINGER2:
+ ignore = EQUIPMENT_SLOT_FINGER1;
+ break;
+ case EQUIPMENT_SLOT_TRINKET1:
+ ignore = EQUIPMENT_SLOT_TRINKET2;
+ break;
+ case EQUIPMENT_SLOT_TRINKET2:
+ ignore = EQUIPMENT_SLOT_TRINKET1;
+ break;
+ }
+
+ if (ignore == uint8(NULL_SLOT) || pItem != GetItemByPos(INVENTORY_SLOT_BAG_0, ignore))
+ ignore = eslot;
+
+ InventoryResult res2 = CanEquipUniqueItem(pItem, swap ? ignore : uint8(NULL_SLOT));
if (res2 != EQUIP_ERR_OK)
return res2;
@@ -14275,7 +14304,7 @@ void Player::PrepareGossipMenu(WorldObject* source, uint32 menuId /*= 0*/, bool
VendorItemData const* vendorItems = creature->GetVendorItems();
if (!vendorItems || vendorItems->Empty())
{
- sLog->outError(LOG_FILTER_SQL, "Creature %u (Entry: %u) have UNIT_NPC_FLAG_VENDOR but have empty trading item list.", creature->GetGUIDLow(), creature->GetEntry());
+ sLog->outError(LOG_FILTER_SQL, "Creature (GUID: %u, Entry: %u) have UNIT_NPC_FLAG_VENDOR but have empty trading item list.", creature->GetGUIDLow(), creature->GetEntry());
canTalk = false;
}
break;
@@ -22141,7 +22170,7 @@ void Player::LeaveBattleground(bool teleportToEntryPoint)
}
}
-bool Player::CanJoinToBattleground() const
+bool Player::CanJoinToBattleground(Battleground const* /*bg*/) const
{
// check Deserter debuff
if (HasAura(26013))
diff --git a/src/server/game/Entities/Player/Player.h b/src/server/game/Entities/Player/Player.h
index b27d66a7654..511c3356b15 100644
--- a/src/server/game/Entities/Player/Player.h
+++ b/src/server/game/Entities/Player/Player.h
@@ -2469,11 +2469,15 @@ class Player : public Unit, public GridObject<Player>
WorldLocation const& GetBattlegroundEntryPoint() const { return m_bgData.joinPos; }
void SetBattlegroundEntryPoint();
- void SetBGTeam(uint32 team) { m_bgData.bgTeam = team; }
+ void SetBGTeam(uint32 team)
+ {
+ m_bgData.bgTeam = team;
+ SetByteValue(PLAYER_BYTES_3, 3, uint8(team == ALLIANCE ? 1 : 0));
+ }
uint32 GetBGTeam() const { return m_bgData.bgTeam ? m_bgData.bgTeam : GetTeam(); }
void LeaveBattleground(bool teleportToEntryPoint = true);
- bool CanJoinToBattleground() const;
+ bool CanJoinToBattleground(Battleground const* bg) const;
bool CanReportAfkDueToLimit();
void ReportedAfkBy(Player* reporter);
void ClearAfkReports() { m_bgData.bgAfkReporter.clear(); }
diff --git a/src/server/game/Entities/Unit/Unit.cpp b/src/server/game/Entities/Unit/Unit.cpp
index faf6c5dcf0b..0a1bf3cecb1 100644
--- a/src/server/game/Entities/Unit/Unit.cpp
+++ b/src/server/game/Entities/Unit/Unit.cpp
@@ -256,8 +256,8 @@ Unit::Unit(bool isWorldObject): WorldObject(isWorldObject)
m_speed_rate[i] = 1.0f;
m_charmInfo = NULL;
- m_reducedThreatPercent = 0;
- m_misdirectionTargetGUID = 0;
+
+ _redirectThreadInfo = RedirectThreatInfo();
// remove aurastates allowing special moves
for (uint8 i = 0; i < MAX_REACTIVE; ++i)
@@ -385,10 +385,10 @@ bool Unit::haveOffhandWeapon() const
return m_canDualWield;
}
-void Unit::MonsterMoveWithSpeed(float x, float y, float z, float speed)
+void Unit::MonsterMoveWithSpeed(float x, float y, float z, float speed, bool generatePath, bool forceDestination)
{
- Movement::MoveSplineInit init(*this);
- init.MoveTo(x, y, z);
+ Movement::MoveSplineInit init(this);
+ init.MoveTo(x, y, z, generatePath, forceDestination);
init.SetVelocity(speed);
init.Launch();
}
@@ -4776,106 +4776,6 @@ void Unit::SendAttackStateUpdate(uint32 HitInfo, Unit* target, uint8 /*SwingType
SendAttackStateUpdate(&dmgInfo);
}
-bool Unit::HandleHasteAuraProc(Unit* victim, uint32 damage, AuraEffect* triggeredByAura, SpellInfo const* /*procSpell*/, uint32 /*procFlag*/, uint32 /*procEx*/, uint32 cooldown)
-{
- SpellInfo const* hasteSpell = triggeredByAura->GetSpellInfo();
-
- Item* castItem = triggeredByAura->GetBase()->GetCastItemGUID() && GetTypeId() == TYPEID_PLAYER
- ? ToPlayer()->GetItemByGuid(triggeredByAura->GetBase()->GetCastItemGUID()) : NULL;
-
- uint32 triggered_spell_id = 0;
- Unit* target = victim;
- int32 basepoints0 = 0;
-
- switch (hasteSpell->SpellFamilyName)
- {
- case SPELLFAMILY_ROGUE:
- {
- switch (hasteSpell->Id)
- {
- // Blade Flurry
- case 13877:
- case 33735:
- {
- target = SelectNearbyTarget(victim);
- if (!target)
- return false;
- basepoints0 = damage;
- triggered_spell_id = 22482;
- break;
- }
- }
- break;
- }
- }
-
- // processed charge only counting case
- if (!triggered_spell_id)
- return true;
-
- SpellInfo const* triggerEntry = sSpellMgr->GetSpellInfo(triggered_spell_id);
-
- if (!triggerEntry)
- {
- sLog->outError(LOG_FILTER_UNITS, "Unit::HandleHasteAuraProc: Spell %u has non-existing triggered spell %u", hasteSpell->Id, triggered_spell_id);
- return false;
- }
-
- if (cooldown && GetTypeId() == TYPEID_PLAYER && ToPlayer()->HasSpellCooldown(triggered_spell_id))
- return false;
-
- if (basepoints0)
- CastCustomSpell(target, triggered_spell_id, &basepoints0, NULL, NULL, true, castItem, triggeredByAura);
- else
- CastSpell(target, triggered_spell_id, true, castItem, triggeredByAura);
-
- if (cooldown && GetTypeId() == TYPEID_PLAYER)
- ToPlayer()->AddSpellCooldown(triggered_spell_id, 0, time(NULL) + cooldown);
-
- return true;
-}
-
-bool Unit::HandleSpellCritChanceAuraProc(Unit* victim, uint32 /*damage*/, AuraEffect* triggeredByAura, SpellInfo const* /*procSpell*/, uint32 /*procFlag*/, uint32 /*procEx*/, uint32 cooldown)
-{
- SpellInfo const* triggeredByAuraSpell = triggeredByAura->GetSpellInfo();
-
- Item* castItem = triggeredByAura->GetBase()->GetCastItemGUID() && GetTypeId() == TYPEID_PLAYER
- ? ToPlayer()->GetItemByGuid(triggeredByAura->GetBase()->GetCastItemGUID()) : NULL;
-
- uint32 triggered_spell_id = 0;
- Unit* target = victim;
- int32 basepoints0 = 0;
-
- // processed charge only counting case
- if (!triggered_spell_id)
- return true;
-
- SpellInfo const* triggerEntry = sSpellMgr->GetSpellInfo(triggered_spell_id);
-
- if (!triggerEntry)
- {
- sLog->outError(LOG_FILTER_UNITS, "Unit::HandleSpellCritChanceAuraProc: Spell %u has non-existing triggered spell %u", triggeredByAuraSpell->Id, triggered_spell_id);
- return false;
- }
-
- // default case
- if (!target || (target != this && !target->isAlive()))
- return false;
-
- if (cooldown && GetTypeId() == TYPEID_PLAYER && ToPlayer()->HasSpellCooldown(triggered_spell_id))
- return false;
-
- if (basepoints0)
- CastCustomSpell(target, triggered_spell_id, &basepoints0, NULL, NULL, true, castItem, triggeredByAura);
- else
- CastSpell(target, triggered_spell_id, true, castItem, triggeredByAura);
-
- if (cooldown && GetTypeId() == TYPEID_PLAYER)
- ToPlayer()->AddSpellCooldown(triggered_spell_id, 0, time(NULL) + cooldown);
-
- return true;
-}
-
bool Unit::HandleAuraProcOnPowerAmount(Unit* victim, uint32 /*damage*/, AuraEffect* triggeredByAura, SpellInfo const* procSpell, uint32 procFlag, uint32 /*procEx*/, uint32 cooldown)
{
// Get triggered aura spell info
@@ -5020,38 +4920,6 @@ bool Unit::HandleDummyAuraProc(Unit* victim, uint32 damage, AuraEffect* triggere
{
switch (dummySpell->Id)
{
- // Bloodworms Health Leech
- case 50453:
- {
- if (Unit* owner = GetOwner())
- {
- basepoints0 = int32(damage * 1.50f);
- target = owner;
- triggered_spell_id = 50454;
- break;
- }
- return false;
- }
- // Eye for an Eye
- case 9799:
- case 25988:
- {
- // return damage % to attacker but < 50% own total health
- basepoints0 = int32(std::min(CalculatePct(damage, triggerAmount), CountPctFromMaxHealth(50)));
- triggered_spell_id = 25997;
- break;
- }
- // Sweeping Strikes
- case 18765:
- case 35429:
- {
- target = SelectNearbyTarget(victim);
- if (!target)
- return false;
-
- triggered_spell_id = 26654;
- break;
- }
// Unstable Power
case 24658:
{
@@ -5068,67 +4936,6 @@ bool Unit::HandleDummyAuraProc(Unit* victim, uint32 damage, AuraEffect* triggere
RemoveAuraFromStack(24662);
return true;
}
- // Adaptive Warding (Frostfire Regalia set)
- case 28764:
- {
- if (!procSpell)
- return false;
-
- // find Mage Armor
- if (!GetAuraEffect(SPELL_AURA_MOD_MANA_REGEN_INTERRUPT, SPELLFAMILY_MAGE, 0x10000000, 0, 0))
- return false;
-
- switch (GetFirstSchoolInMask(procSpell->GetSchoolMask()))
- {
- case SPELL_SCHOOL_NORMAL:
- case SPELL_SCHOOL_HOLY:
- return false; // ignored
- case SPELL_SCHOOL_FIRE: triggered_spell_id = 28765; break;
- case SPELL_SCHOOL_NATURE: triggered_spell_id = 28768; break;
- case SPELL_SCHOOL_FROST: triggered_spell_id = 28766; break;
- case SPELL_SCHOOL_SHADOW: triggered_spell_id = 28769; break;
- case SPELL_SCHOOL_ARCANE: triggered_spell_id = 28770; break;
- default:
- return false;
- }
-
- target = this;
- break;
- }
- // Obsidian Armor (Justice Bearer`s Pauldrons shoulder)
- case 27539:
- {
- if (!procSpell)
- return false;
-
- switch (GetFirstSchoolInMask(procSpell->GetSchoolMask()))
- {
- case SPELL_SCHOOL_NORMAL:
- return false; // ignore
- case SPELL_SCHOOL_HOLY: triggered_spell_id = 27536; break;
- case SPELL_SCHOOL_FIRE: triggered_spell_id = 27533; break;
- case SPELL_SCHOOL_NATURE: triggered_spell_id = 27538; break;
- case SPELL_SCHOOL_FROST: triggered_spell_id = 27534; break;
- case SPELL_SCHOOL_SHADOW: triggered_spell_id = 27535; break;
- case SPELL_SCHOOL_ARCANE: triggered_spell_id = 27540; break;
- default:
- return false;
- }
-
- target = this;
- break;
- }
- // Mana Leech (Passive) (Priest Pet Aura)
- case 28305:
- {
- // Cast on owner
- target = GetOwner();
- if (!target)
- return false;
-
- triggered_spell_id = 34650;
- break;
- }
// Mark of Malice
case 33493:
{
@@ -5319,14 +5126,6 @@ bool Unit::HandleDummyAuraProc(Unit* victim, uint32 damage, AuraEffect* triggere
}
return false;
}
- // Living Seed
- case 48504:
- {
- triggered_spell_id = 48503;
- basepoints0 = triggerAmount;
- target = this;
- break;
- }
// Kill command
case 58914:
{
@@ -5486,50 +5285,6 @@ bool Unit::HandleDummyAuraProc(Unit* victim, uint32 damage, AuraEffect* triggere
}
break;
}
- case 71875: // Item - Black Bruise: Necrotic Touch Proc
- case 71877:
- {
- basepoints0 = CalculatePct(int32(damage), triggerAmount);
- triggered_spell_id = 71879;
- break;
- }
- // Item - Shadowmourne Legendary
- case 71903:
- {
- if (!victim || !victim->isAlive() || HasAura(73422)) // cant collect shards while under effect of Chaos Bane buff
- return false;
-
- CastSpell(this, 71905, true, NULL, triggeredByAura);
-
- // this can't be handled in AuraScript because we need to know victim
- Aura const* dummy = GetAura(71905);
- if (!dummy || dummy->GetStackAmount() < 10)
- return false;
-
- RemoveAurasDueToSpell(71905);
- triggered_spell_id = 71904;
- target = victim;
- break;
- }
- // Shadow's Fate (Shadowmourne questline)
- case 71169:
- {
- Unit* caster = triggeredByAura->GetCaster();
- if (caster && caster->GetTypeId() == TYPEID_PLAYER && caster->ToPlayer()->GetQuestStatus(24547) == QUEST_STATUS_INCOMPLETE)
- {
- CastSpell(caster, 71203, true);
- return true;
- }
- else
- return false;
- }
- // Essence of the Blood Queen
- case 70871:
- {
- basepoints0 = CalculatePct(int32(damage), triggerAmount);
- CastCustomSpell(70872, SPELLVALUE_BASE_POINT0, basepoints0, this);
- return true;
- }
case 65032: // Boom aura (321 Boombot)
{
if (victim->GetEntry() != 33343) // Scrapbot
@@ -5542,13 +5297,6 @@ bool Unit::HandleDummyAuraProc(Unit* victim, uint32 damage, AuraEffect* triggere
instance->DoCastSpellOnPlayers(65037); // Achievement criteria marker
break;
}
- // Dark Hunger (The Lich King encounter)
- case 69383:
- {
- basepoints0 = CalculatePct(int32(damage), 50);
- triggered_spell_id = 69384;
- break;
- }
case 47020: // Enter vehicle XT-002 (Scrapbot)
{
if (GetTypeId() != TYPEID_UNIT)
@@ -5579,22 +5327,6 @@ bool Unit::HandleDummyAuraProc(Unit* victim, uint32 damage, AuraEffect* triggere
triggered_spell_id = 29442;
break;
}
- // Master of Elements
- if (dummySpell->SpellIconID == 1920)
- {
- if (!procSpell)
- return false;
-
- // mana cost save
- int32 cost = int32(procSpell->ManaCost + CalculatePct(GetCreateMana(), procSpell->ManaCostPercentage));
- basepoints0 = CalculatePct(cost, triggerAmount);
- if (basepoints0 <= 0)
- return false;
-
- target = this;
- triggered_spell_id = 29077;
- break;
- }
// Arcane Potency
if (dummySpell->SpellIconID == 2120)
{
@@ -5612,7 +5344,6 @@ bool Unit::HandleDummyAuraProc(Unit* victim, uint32 damage, AuraEffect* triggere
}
break;
}
-
// Hot Streak & Improved Hot Streak
if (dummySpell->SpellIconID == 2999)
{
@@ -5664,16 +5395,6 @@ bool Unit::HandleDummyAuraProc(Unit* victim, uint32 damage, AuraEffect* triggere
RemoveAurasByType(SPELL_AURA_MOD_DECREASE_SPEED);
return true;
}
- // Ignite
- case 11119:
- case 11120:
- case 12846:
- {
- basepoints0 = CalculatePct(damage, triggerAmount);
- triggered_spell_id = 12654;
- basepoints0 += victim->GetRemainingPeriodicAmount(GetGUID(), triggered_spell_id, SPELL_AURA_PERIODIC_DAMAGE);
- break;
- }
// Glyph of Ice Block
case 56372:
{
@@ -5685,25 +5406,6 @@ bool Unit::HandleDummyAuraProc(Unit* victim, uint32 damage, AuraEffect* triggere
player->RemoveSpellCooldown(122, true);
break;
}
- // Blessing of Ancient Kings (Val'anyr, Hammer of Ancient Kings)
- case 64411:
- {
- if (!victim)
- return false;
- basepoints0 = int32(CalculatePct(damage, 15));
- if (AuraEffect* aurEff = victim->GetAuraEffect(64413, 0, GetGUID()))
- {
- // The shield can grow to a maximum size of 20, 000 damage absorbtion
- aurEff->SetAmount(std::min<int32>(aurEff->GetAmount() + basepoints0, 20000));
-
- // Refresh and return to prevent replacing the aura
- aurEff->GetBase()->RefreshDuration();
- return true;
- }
- target = victim;
- triggered_spell_id = 64413;
- break;
- }
// Permafrost
case 11175:
case 12569:
@@ -5725,16 +5427,6 @@ bool Unit::HandleDummyAuraProc(Unit* victim, uint32 damage, AuraEffect* triggere
{
switch (dummySpell->Id)
{
- // Sweeping Strikes
- case 12328:
- {
- target = SelectNearbyTarget(victim);
- if (!target)
- return false;
-
- triggered_spell_id = 26654;
- break;
- }
// Victorious
case 32216:
{
@@ -5840,16 +5532,6 @@ bool Unit::HandleDummyAuraProc(Unit* victim, uint32 damage, AuraEffect* triggere
triggeredByAura->SetAmount(triggeredByAura->GetAmount() - damage);
return true;
}
- // Fel Synergy
- if (dummySpell->SpellIconID == 3222)
- {
- target = GetGuardianPet();
- if (!target)
- return false;
- basepoints0 = CalculatePct(int32(damage), triggerAmount);
- triggered_spell_id = 54181;
- break;
- }
switch (dummySpell->Id)
{
// Glyph of Shadowflame
@@ -5935,24 +5617,6 @@ bool Unit::HandleDummyAuraProc(Unit* victim, uint32 damage, AuraEffect* triggere
victim->CastSpell(victim, 57669, true, castItem, triggeredByAura);
return true; // no hidden cooldown
}
- // Divine Aegis
- if (dummySpell->SpellIconID == 2820)
- {
- if (!target)
- return false;
-
- // Multiple effects stack, so let's try to find this aura.
- int32 bonus = 0;
- if (AuraEffect const* aurEff = target->GetAuraEffect(47753, 0))
- bonus = aurEff->GetAmount();
-
- basepoints0 = CalculatePct(int32(damage), triggerAmount) + bonus;
- if (basepoints0 > target->getLevel() * 125)
- basepoints0 = target->getLevel() * 125;
-
- triggered_spell_id = 47753;
- break;
- }
// Body and Soul
if (dummySpell->SpellIconID == 2218)
{
@@ -5992,19 +5656,6 @@ bool Unit::HandleDummyAuraProc(Unit* victim, uint32 damage, AuraEffect* triggere
target = this;
break;
}
- // Glyph of Prayer of Healing
- case 55680:
- {
- triggered_spell_id = 56161;
-
- SpellInfo const* GoPoH = sSpellMgr->GetSpellInfo(triggered_spell_id);
- if (!GoPoH)
- return false;
-
- int32 tickcount = GoPoH->GetMaxDuration() / GoPoH->Effects[EFFECT_0].Amplitude;
- basepoints0 = CalculatePct(int32(damage), triggerAmount) / tickcount;
- break;
- }
// Phantasm
case 47569:
case 47570:
@@ -6228,13 +5879,6 @@ bool Unit::HandleDummyAuraProc(Unit* victim, uint32 damage, AuraEffect* triggere
return true;
}
}
- // Living Seed
- if (dummySpell->SpellIconID == 2860)
- {
- triggered_spell_id = 48504;
- basepoints0 = CalculatePct(int32(damage), triggerAmount);
- break;
- }
break;
}
case SPELLFAMILY_ROGUE:
@@ -6250,16 +5894,6 @@ bool Unit::HandleDummyAuraProc(Unit* victim, uint32 damage, AuraEffect* triggere
triggered_spell_id = 32747;
break;
}
- case 57934: // Tricks of the Trade
- {
- Unit* redirectTarget = GetMisdirectionTarget();
- RemoveAura(57934);
- if (!redirectTarget)
- break;
- CastSpell(this, 59628, true);
- CastSpell(redirectTarget, 57933, true);
- break;
- }
}
switch (dummySpell->SpellIconID)
@@ -6324,31 +5958,11 @@ bool Unit::HandleDummyAuraProc(Unit* victim, uint32 damage, AuraEffect* triggere
switch (dummySpell->Id)
{
- case 34477: // Misdirection
- {
- if (!GetMisdirectionTarget())
- return false;
- triggered_spell_id = 35079; // 4 sec buff on self
- target = this;
- break;
- }
}
break;
}
case SPELLFAMILY_PALADIN:
{
- // Seal of Righteousness - melee proc dummy (addition (MWS * (0.011 * AP.022 * holy spell power) * 100 / 100) damage)
- if (dummySpell->SpellFamilyFlags[0] & 0x8000000)
- {
- if (effIndex != 0)
- return false;
- triggered_spell_id = 25742;
- float ap = GetTotalAttackPowerValue(BASE_ATTACK);
- int32 holy = SpellBaseDamageBonusDone(SPELL_SCHOOL_MASK_HOLY) +
- victim->SpellBaseDamageBonusTaken(SPELL_SCHOOL_MASK_HOLY);
- basepoints0 = (int32)GetAttackTime(BASE_ATTACK) * int32(ap * 0.011f + 0.022f * holy) / 1000;
- break;
- }
// Light's Beacon - Beacon of Light
if (dummySpell->Id == 53651)
{
@@ -6472,7 +6086,6 @@ bool Unit::HandleDummyAuraProc(Unit* victim, uint32 damage, AuraEffect* triggere
}
break;
}
- // Seal of Truth (damage calc on apply aura)
case 31801:
{
if (effIndex != 0) // effect 2 used by seal unleashing code
@@ -6875,20 +6488,6 @@ bool Unit::HandleDummyAuraProc(Unit* victim, uint32 damage, AuraEffect* triggere
target = this;
break;
}
- // Earth Shield
- if (dummySpell->Id == 974)
- {
- // 3.0.8: Now correctly uses the Shaman's own spell critical strike chance to determine the chance of a critical heal.
- originalCaster = triggeredByAura->GetCasterGUID();
- target = this;
- basepoints0 = triggerAmount;
-
- // Glyph of Earth Shield
- if (AuraEffect* aur = GetAuraEffect(63279, 0))
- AddPct(basepoints0, aur->GetAmount());
- triggered_spell_id = 379;
- break;
- }
// Flametongue Weapon (Passive)
if (dummySpell->SpellFamilyFlags[0] & 0x200000)
{
@@ -7143,88 +6742,9 @@ bool Unit::HandleDummyAuraProc(Unit* victim, uint32 damage, AuraEffect* triggere
return true;
}
-bool Unit::HandleObsModEnergyAuraProc(Unit* victim, uint32 /*damage*/, AuraEffect* triggeredByAura, SpellInfo const* /*procSpell*/, uint32 /*procFlag*/, uint32 /*procEx*/, uint32 cooldown)
-{
- SpellInfo const* dummySpell = triggeredByAura->GetSpellInfo();
- //uint32 effIndex = triggeredByAura->GetEffIndex();
- //int32 triggerAmount = triggeredByAura->GetAmount();
-
- Item* castItem = triggeredByAura->GetBase()->GetCastItemGUID() && GetTypeId() == TYPEID_PLAYER
- ? ToPlayer()->GetItemByGuid(triggeredByAura->GetBase()->GetCastItemGUID()) : NULL;
-
- uint32 triggered_spell_id = 0;
- Unit* target = victim;
- int32 basepoints0 = 0;
-
- // processed charge only counting case
- if (!triggered_spell_id)
- return true;
-
- SpellInfo const* triggerEntry = sSpellMgr->GetSpellInfo(triggered_spell_id);
-
- // Try handle unknown trigger spells
- if (!triggerEntry)
- {
- sLog->outError(LOG_FILTER_UNITS, "Unit::HandleObsModEnergyAuraProc: Spell %u has non-existing triggered spell %u", dummySpell->Id, triggered_spell_id);
- return false;
- }
-
- if (cooldown && GetTypeId() == TYPEID_PLAYER && ToPlayer()->HasSpellCooldown(triggered_spell_id))
- return false;
- if (basepoints0)
- CastCustomSpell(target, triggered_spell_id, &basepoints0, NULL, NULL, true, castItem, triggeredByAura);
- else
- CastSpell(target, triggered_spell_id, true, castItem, triggeredByAura);
-
- if (cooldown && GetTypeId() == TYPEID_PLAYER)
- ToPlayer()->AddSpellCooldown(triggered_spell_id, 0, time(NULL) + cooldown);
- return true;
-}
-bool Unit::HandleModDamagePctTakenAuraProc(Unit* victim, uint32 /*damage*/, AuraEffect* triggeredByAura, SpellInfo const* /*procSpell*/, uint32 /*procFlag*/, uint32 /*procEx*/, uint32 cooldown)
-{
- SpellInfo const* dummySpell = triggeredByAura->GetSpellInfo();
- //uint32 effIndex = triggeredByAura->GetEffIndex();
- //int32 triggerAmount = triggeredByAura->GetAmount();
-
- Item* castItem = triggeredByAura->GetBase()->GetCastItemGUID() && GetTypeId() == TYPEID_PLAYER
- ? ToPlayer()->GetItemByGuid(triggeredByAura->GetBase()->GetCastItemGUID()) : NULL;
-
- uint32 triggered_spell_id = 0;
- Unit* target = victim;
- int32 basepoints0 = 0;
-
/*
- switch (dummySpell->SpellFamilyName)
- {
-
- }
*/
- // processed charge only counting case
- if (!triggered_spell_id)
- return true;
-
- SpellInfo const* triggerEntry = sSpellMgr->GetSpellInfo(triggered_spell_id);
-
- if (!triggerEntry)
- {
- sLog->outError(LOG_FILTER_UNITS, "Unit::HandleModDamagePctTakenAuraProc: Spell %u has non-existing triggered spell %u", dummySpell->Id, triggered_spell_id);
- return false;
- }
-
- if (cooldown && GetTypeId() == TYPEID_PLAYER && ToPlayer()->HasSpellCooldown(triggered_spell_id))
- return false;
-
- if (basepoints0)
- CastCustomSpell(target, triggered_spell_id, &basepoints0, NULL, NULL, true, castItem, triggeredByAura);
- else
- CastSpell(target, triggered_spell_id, true, castItem, triggeredByAura);
-
- if (cooldown && GetTypeId() == TYPEID_PLAYER)
- ToPlayer()->AddSpellCooldown(triggered_spell_id, 0, time(NULL) + cooldown);
-
- return true;
-}
// Used in case when access to whole aura is needed
// All procs should be handled like this...
@@ -13606,7 +13126,7 @@ void Unit::ProcDamageAndSpellFor(bool isVictim, Unit* target, uint32 procFlag, u
SpellInfo const* spellInfo = i->aura->GetSpellInfo();
uint32 Id = i->aura->GetId();
- AuraApplication const* aurApp = i->aura->GetApplicationOfTarget(GetGUID());
+ AuraApplication* aurApp = i->aura->GetApplicationOfTarget(GetGUID());
bool prepare = i->aura->CallScriptPrepareProcHandlers(aurApp, eventInfo);
@@ -13660,17 +13180,10 @@ void Unit::ProcDamageAndSpellFor(bool isVictim, Unit* target, uint32 procFlag, u
case SPELL_AURA_PROC_TRIGGER_DAMAGE:
{
// target has to be valid
- if (!target)
+ if (!eventInfo.GetProcTarget())
break;
- sLog->outDebug(LOG_FILTER_SPELLS_AURAS, "ProcDamageAndSpell: doing %u damage from spell id %u (triggered by %s aura of spell %u)", triggeredByAura->GetAmount(), spellInfo->Id, (isVictim?"a victim's":"an attacker's"), triggeredByAura->GetId());
- SpellNonMeleeDamage damageInfo(this, target, spellInfo->Id, spellInfo->SchoolMask);
- uint32 newDamage = SpellDamageBonusDone(target, spellInfo, triggeredByAura->GetAmount(), SPELL_DIRECT_DAMAGE);
- newDamage = target->SpellDamageBonusTaken(this, spellInfo, newDamage, SPELL_DIRECT_DAMAGE);
- CalculateSpellDamageTaken(&damageInfo, newDamage, spellInfo);
- DealDamageMods(damageInfo.target, damageInfo.damage, &damageInfo.absorb);
- SendSpellNonMeleeDamageLog(&damageInfo);
- DealSpellDamage(&damageInfo, true);
+ triggeredByAura->HandleProcTriggerDamageAuraProc(aurApp, eventInfo); // this function is part of the new proc system
takeCharges = true;
break;
}
@@ -13690,23 +13203,13 @@ void Unit::ProcDamageAndSpellFor(bool isVictim, Unit* target, uint32 procFlag, u
break;
}
case SPELL_AURA_OBS_MOD_POWER:
- sLog->outDebug(LOG_FILTER_SPELLS_AURAS, "ProcDamageAndSpell: casting spell id %u (triggered by %s aura of spell %u)", spellInfo->Id, (isVictim?"a victim's":"an attacker's"), triggeredByAura->GetId());
- if (HandleObsModEnergyAuraProc(target, damage, triggeredByAura, procSpell, procFlag, procExtra, cooldown))
- takeCharges = true;
- break;
+ case SPELL_AURA_MOD_SPELL_CRIT_CHANCE:
case SPELL_AURA_MOD_DAMAGE_PERCENT_TAKEN:
- sLog->outDebug(LOG_FILTER_SPELLS_AURAS, "ProcDamageAndSpell: casting spell id %u (triggered by %s aura of spell %u)", spellInfo->Id, (isVictim?"a victim's":"an attacker's"), triggeredByAura->GetId());
- if (HandleModDamagePctTakenAuraProc(target, damage, triggeredByAura, procSpell, procFlag, procExtra, cooldown))
- takeCharges = true;
- break;
case SPELL_AURA_MOD_MELEE_HASTE:
case SPELL_AURA_MOD_MELEE_HASTE_3:
- {
- sLog->outDebug(LOG_FILTER_SPELLS_AURAS, "ProcDamageAndSpell: casting spell id %u (triggered by %s haste aura of spell %u)", spellInfo->Id, (isVictim?"a victim's":"an attacker's"), triggeredByAura->GetId());
- if (HandleHasteAuraProc(target, damage, triggeredByAura, procSpell, procFlag, procExtra, cooldown))
- takeCharges = true;
+ sLog->outDebug(LOG_FILTER_SPELLS_AURAS, "ProcDamageAndSpell: casting spell id %u (triggered by %s aura of spell %u)", spellInfo->Id, isVictim ? "a victim's" : "an attacker's", triggeredByAura->GetId());
+ takeCharges = true;
break;
- }
case SPELL_AURA_OVERRIDE_CLASS_SCRIPTS:
{
sLog->outDebug(LOG_FILTER_SPELLS_AURAS, "ProcDamageAndSpell: casting spell id %u (triggered by %s aura of spell %u)", spellInfo->Id, (isVictim?"a victim's":"an attacker's"), triggeredByAura->GetId());
@@ -13778,11 +13281,6 @@ void Unit::ProcDamageAndSpellFor(bool isVictim, Unit* target, uint32 procFlag, u
if (triggeredByAura->GetCasterGUID() == target->GetGUID())
takeCharges = true;
break;
- case SPELL_AURA_MOD_SPELL_CRIT_CHANCE:
- sLog->outDebug(LOG_FILTER_SPELLS_AURAS, "ProcDamageAndSpell: casting spell id %u (triggered by %s spell crit chance aura of spell %u)", spellInfo->Id, (isVictim?"a victim's":"an attacker's"), triggeredByAura->GetId());
- if (procSpell && HandleSpellCritChanceAuraProc(target, damage, triggeredByAura, procSpell, procFlag, procExtra, cooldown))
- takeCharges = true;
- break;
// CC Auras which use their amount amount to drop
// Are there any more auras which need this?
case SPELL_AURA_MOD_CONFUSE:
@@ -13985,9 +13483,10 @@ void Unit::StopMoving()
if (!IsInWorld() || movespline->Finalized())
return;
- // Update position using old spline
- UpdateSplinePosition();
- Movement::MoveSplineInit(*this).Stop();
+ Movement::MoveSplineInit init(this);
+ init.MoveTo(GetPositionX(), GetPositionY(), GetPositionZMinusOffset());
+ init.SetFacing(GetOrientation());
+ init.Launch();
}
void Unit::SendMovementFlagUpdate(bool self /* = false */)
@@ -16659,8 +16158,8 @@ void Unit::_ExitVehicle(Position const* exitPosition)
SendMessageToSet(&data, false);
}
- Movement::MoveSplineInit init(*this);
- init.MoveTo(pos.GetPositionX(), pos.GetPositionY(), pos.GetPositionZ());
+ Movement::MoveSplineInit init(this);
+ init.MoveTo(pos.GetPositionX(), pos.GetPositionY(), pos.GetPositionZ(), false);
init.SetFacing(GetOrientation());
init.SetTransportExit();
init.Launch();
@@ -17669,7 +17168,7 @@ void Unit::SetInFront(Unit const* target)
void Unit::SetFacingTo(float ori)
{
- Movement::MoveSplineInit init(*this);
+ Movement::MoveSplineInit init(this);
init.MoveTo(GetPositionX(), GetPositionY(), GetPositionZMinusOffset());
init.SetFacing(ori);
init.Launch();
diff --git a/src/server/game/Entities/Unit/Unit.h b/src/server/game/Entities/Unit/Unit.h
index 40918dbb611..b723be7bee7 100644
--- a/src/server/game/Entities/Unit/Unit.h
+++ b/src/server/game/Entities/Unit/Unit.h
@@ -497,6 +497,7 @@ enum UnitState
UNIT_STATE_FLEEING_MOVE = 0x02000000,
UNIT_STATE_CHASE_MOVE = 0x04000000,
UNIT_STATE_FOLLOW_MOVE = 0x08000000,
+ UNIT_STATE_IGNORE_PATHFINDING = 0x10000000, // do not use pathfinding in any MovementGenerator
UNIT_STATE_UNATTACKABLE = (UNIT_STATE_IN_FLIGHT | UNIT_STATE_ONVEHICLE),
// for real move using movegen check and stop (except unstoppable flight)
UNIT_STATE_MOVING = UNIT_STATE_ROAMING_MOVE | UNIT_STATE_CONFUSED_MOVE | UNIT_STATE_FLEEING_MOVE | UNIT_STATE_CHASE_MOVE | UNIT_STATE_FOLLOW_MOVE,
@@ -973,6 +974,28 @@ struct SpellPeriodicAuraLogInfo
uint32 createProcExtendMask(SpellNonMeleeDamage* damageInfo, SpellMissInfo missCondition);
+struct RedirectThreatInfo
+{
+ RedirectThreatInfo() : _targetGUID(0), _threatPct(0) { }
+ uint64 _targetGUID;
+ uint32 _threatPct;
+
+ uint64 GetTargetGUID() { return _targetGUID; }
+ uint32 GetThreatPct() { return _threatPct; }
+
+ void Set(uint64 guid, uint32 pct)
+ {
+ _targetGUID = guid;
+ _threatPct = pct;
+ }
+
+ void ModifyThreatPct(int32 amount)
+ {
+ amount += _threatPct;
+ _threatPct = uint32(std::max(0, amount));
+ }
+};
+
#define MAX_DECLINED_NAME_CASES 5
struct DeclinedName
@@ -1599,7 +1622,7 @@ class Unit : public WorldObject
void JumpTo(float speedXY, float speedZ, bool forward = true);
void JumpTo(WorldObject* obj, float speedZ);
- void MonsterMoveWithSpeed(float x, float y, float z, float speed);
+ void MonsterMoveWithSpeed(float x, float y, float z, float speed, bool generatePath = false, bool forceDestination = false);
//void SetFacing(float ori, WorldObject* obj = NULL);
//void SendMonsterMove(float NewPosX, float NewPosY, float NewPosZ, uint8 type, uint32 MovementFlags, uint32 Time, Player* player = NULL);
void SendMovementFlagUpdate(bool self = false);
@@ -2139,13 +2162,12 @@ class Unit : public WorldObject
uint32 GetModelForForm(ShapeshiftForm form) const;
uint32 GetModelForTotem(PlayerTotemType totemType);
- void SetReducedThreatPercent(uint32 pct, uint64 guid)
- {
- m_reducedThreatPercent = pct;
- m_misdirectionTargetGUID = guid;
- }
- uint32 GetReducedThreatPercent() { return m_reducedThreatPercent; }
- Unit* GetMisdirectionTarget() { return m_misdirectionTargetGUID ? GetUnit(*this, m_misdirectionTargetGUID) : NULL; }
+ // Redirect Threat
+ void SetRedirectThreat(uint64 guid, uint32 pct) { _redirectThreadInfo.Set(guid, pct); }
+ void ResetRedirectThreat() { SetRedirectThreat(0, 0); }
+ void ModifyRedirectThreat(int32 amount) { _redirectThreadInfo.ModifyThreatPct(amount); }
+ uint32 GetRedirectThreatPercent() { return _redirectThreadInfo.GetThreatPct(); }
+ Unit* GetRedirectThreatTarget() { return _redirectThreadInfo.GetTargetGUID() ? GetUnit(*this, _redirectThreadInfo.GetTargetGUID()) : NULL; }
bool IsAIEnabled, NeedChangeAI;
bool CreateVehicleKit(uint32 id, uint32 creatureEntry);
@@ -2298,10 +2320,6 @@ class Unit : public WorldObject
bool IsTriggeredAtSpellProcEvent(Unit* victim, Aura* aura, SpellInfo const* procSpell, uint32 procFlag, uint32 procExtra, WeaponAttackType attType, bool isVictim, bool active, SpellProcEventEntry const* & spellProcEvent);
bool HandleAuraProcOnPowerAmount(Unit* victim, uint32 damage, AuraEffect* triggeredByAura, SpellInfo const* procSpell, uint32 procFlag, uint32 procEx, uint32 cooldown);
bool HandleDummyAuraProc(Unit* victim, uint32 damage, AuraEffect* triggeredByAura, SpellInfo const* procSpell, uint32 procFlag, uint32 procEx, uint32 cooldown);
- bool HandleHasteAuraProc(Unit* victim, uint32 damage, AuraEffect* triggeredByAura, SpellInfo const* procSpell, uint32 procFlag, uint32 procEx, uint32 cooldown);
- bool HandleSpellCritChanceAuraProc(Unit* victim, uint32 damage, AuraEffect* triggredByAura, SpellInfo const* procSpell, uint32 procFlag, uint32 procEx, uint32 cooldown);
- bool HandleObsModEnergyAuraProc(Unit* victim, uint32 damage, AuraEffect* triggeredByAura, SpellInfo const* procSpell, uint32 procFlag, uint32 procEx, uint32 cooldown);
- bool HandleModDamagePctTakenAuraProc(Unit* victim, uint32 damage, AuraEffect* triggeredByAura, SpellInfo const* procSpell, uint32 procFlag, uint32 procEx, uint32 cooldown);
bool HandleAuraProc(Unit* victim, uint32 damage, Aura* triggeredByAura, SpellInfo const* procSpell, uint32 procFlag, uint32 procEx, uint32 cooldown, bool * handled);
bool HandleProcTriggerSpell(Unit* victim, uint32 damage, AuraEffect* triggeredByAura, SpellInfo const* procSpell, uint32 procFlag, uint32 procEx, uint32 cooldown);
bool HandleOverrideClassScriptAuraProc(Unit* victim, uint32 damage, AuraEffect* triggeredByAura, SpellInfo const* procSpell, uint32 cooldown);
@@ -2338,8 +2356,7 @@ class Unit : public WorldObject
ComboPointHolderSet m_ComboPointHolders;
- uint32 m_reducedThreatPercent;
- uint64 m_misdirectionTargetGUID;
+ RedirectThreatInfo _redirectThreadInfo;
bool m_cleanupDone; // lock made to not add stuff after cleanup before delete
bool m_duringRemoveFromWorld; // lock made to not add stuff after begining removing from world
diff --git a/src/server/game/Entities/Vehicle/Vehicle.cpp b/src/server/game/Entities/Vehicle/Vehicle.cpp
index d81feffa71e..b11a0996196 100644..100755
--- a/src/server/game/Entities/Vehicle/Vehicle.cpp
+++ b/src/server/game/Entities/Vehicle/Vehicle.cpp
@@ -381,7 +381,7 @@ bool Vehicle::AddPassenger(Unit* unit, int8 seatId)
unit->SendClearTarget(); // SMSG_BREAK_TARGET
unit->SetControlled(true, UNIT_STATE_ROOT); // SMSG_FORCE_ROOT - In some cases we send SMSG_SPLINE_MOVE_ROOT here (for creatures)
// also adds MOVEMENTFLAG_ROOT
- Movement::MoveSplineInit init(*unit);
+ Movement::MoveSplineInit init(unit);
init.DisableTransportPathTransformations();
init.MoveTo(veSeat->m_attachmentOffsetX, veSeat->m_attachmentOffsetY, veSeat->m_attachmentOffsetZ);
init.SetFacing(0.0f);
diff --git a/src/server/game/Globals/ObjectMgr.cpp b/src/server/game/Globals/ObjectMgr.cpp
index 45859290d1f..05d986e3f92 100644
--- a/src/server/game/Globals/ObjectMgr.cpp
+++ b/src/server/game/Globals/ObjectMgr.cpp
@@ -4672,7 +4672,7 @@ void ObjectMgr::LoadWaypointScripts()
for (ScriptMapMap::const_iterator itr = sWaypointScripts.begin(); itr != sWaypointScripts.end(); ++itr)
actionSet.insert(itr->first);
- PreparedStatement* stmt = WorldDatabase.GetPreparedStatement(WOLRD_SEL_WAYPOINT_DATA_ACTION);
+ PreparedStatement* stmt = WorldDatabase.GetPreparedStatement(WORLD_SEL_WAYPOINT_DATA_ACTION);
PreparedQueryResult result = WorldDatabase.Query(stmt);
if (result)
diff --git a/src/server/game/Groups/Group.cpp b/src/server/game/Groups/Group.cpp
index d70d1c824ec..acc15efcbed 100644
--- a/src/server/game/Groups/Group.cpp
+++ b/src/server/game/Groups/Group.cpp
@@ -1866,7 +1866,7 @@ GroupJoinBattlegroundResult Group::CanJoinBattlegroundQueue(Battleground const*
if (bgOrTemplate->GetTypeID() == BATTLEGROUND_RB && member->InBattlegroundQueue())
return ERR_IN_NON_RANDOM_BG;
// check for deserter debuff in case not arena queue
- if (bgOrTemplate->GetTypeID() != BATTLEGROUND_AA && !member->CanJoinToBattleground())
+ if (bgOrTemplate->GetTypeID() != BATTLEGROUND_AA && !member->CanJoinToBattleground(bgOrTemplate))
return ERR_GROUP_JOIN_BATTLEGROUND_DESERTERS;
// check if member can join any more battleground queues
if (!member->HasFreeBattlegroundQueueId())
diff --git a/src/server/game/Handlers/BattleGroundHandler.cpp b/src/server/game/Handlers/BattleGroundHandler.cpp
index 71c5da9af2b..d28b67106c4 100644
--- a/src/server/game/Handlers/BattleGroundHandler.cpp
+++ b/src/server/game/Handlers/BattleGroundHandler.cpp
@@ -154,7 +154,7 @@ void WorldSession::HandleBattlemasterJoinOpcode(WorldPacket& recvData)
}
// check Deserter debuff
- if (!_player->CanJoinToBattleground())
+ if (!_player->CanJoinToBattleground(bg))
{
WorldPacket data;
sBattlegroundMgr->BuildStatusFailedPacket(&data, bg, _player, 0, ERR_GROUP_JOIN_BATTLEGROUND_DESERTERS);
@@ -498,7 +498,7 @@ void WorldSession::HandleBattleFieldPortOpcode(WorldPacket &recvData)
if (action == 1 && ginfo.ArenaType == 0)
{
//if player is trying to enter battleground (not arena!) and he has deserter debuff, we must just remove him from queue
- if (!_player->CanJoinToBattleground())
+ if (!_player->CanJoinToBattleground(bg))
{
//send bg command result to show nice message
WorldPacket data2;
@@ -538,8 +538,9 @@ void WorldSession::HandleBattleFieldPortOpcode(WorldPacket &recvData)
_player->CleanupAfterTaxiFlight();
}
- sBattlegroundMgr->BuildBattlegroundStatusPacket(&data, bg, _player, queueSlot, STATUS_IN_PROGRESS, _player->GetBattlegroundQueueJoinTime(bgTypeId), bg->GetElapsedTime(), bg->GetArenaType());
+ sBattlegroundMgr->BuildBattlegroundStatusPacket(&data, bg, queueSlot, STATUS_IN_PROGRESS, 0, bg->GetStartTime(), bg->GetArenaType(), ginfo.Team);
_player->GetSession()->SendPacket(&data);
+
// remove battleground queue status from BGmgr
bgQueue.RemovePlayer(_player->GetGUID(), false);
// this is still needed here if battleground "jumping" shouldn't add deserter debuff
@@ -551,6 +552,7 @@ void WorldSession::HandleBattleFieldPortOpcode(WorldPacket &recvData)
_player->SetBattlegroundId(bg->GetInstanceID(), bgTypeId);
// set the destination team
_player->SetBGTeam(ginfo.Team);
+
// bg->HandleBeforeTeleportToBattleground(_player);
sBattlegroundMgr->SendToBattleground(_player, ginfo.IsInvitedToBGInstanceGUID, bgTypeId);
// add only in HandleMoveWorldPortAck()
@@ -620,7 +622,7 @@ void WorldSession::HandleBattlefieldStatusOpcode(WorldPacket & /*recvData*/)
{
// this line is checked, i only don't know if GetElapsedTime() is changing itself after bg end!
// send status in Battleground
- sBattlegroundMgr->BuildBattlegroundStatusPacket(&data, bg, GetPlayer(), i, STATUS_IN_PROGRESS, _player->GetBattlegroundQueueJoinTime(bgTypeId), bg->GetElapsedTime(), arenaType);
+ sBattlegroundMgr->BuildBattlegroundStatusPacket(&data, bg, i, STATUS_IN_PROGRESS, bg->GetEndTime(), bg->GetStartTime(), arenaType, _player->GetBGTeam());
SendPacket(&data);
continue;
}
diff --git a/src/server/game/Handlers/MovementHandler.cpp b/src/server/game/Handlers/MovementHandler.cpp
index 3d2e84c57e8..b2971abaeba 100644
--- a/src/server/game/Handlers/MovementHandler.cpp
+++ b/src/server/game/Handlers/MovementHandler.cpp
@@ -126,7 +126,7 @@ void WorldSession::HandleMoveWorldportAckOpcode()
{
// short preparations to continue flight
FlightPathMovementGenerator* flight = (FlightPathMovementGenerator*)(GetPlayer()->GetMotionMaster()->top());
- flight->Initialize(*GetPlayer());
+ flight->Initialize(GetPlayer());
return;
}
diff --git a/src/server/game/Handlers/PetHandler.cpp b/src/server/game/Handlers/PetHandler.cpp
index 340b5a3ddc1..f7f540a7be5 100644
--- a/src/server/game/Handlers/PetHandler.cpp
+++ b/src/server/game/Handlers/PetHandler.cpp
@@ -203,13 +203,6 @@ void WorldSession::HandlePetActionHelper(Unit* pet, uint64 guid1, uint32 spellid
if (!owner->IsValidAttackTarget(TargetUnit))
return;
- // Not let attack through obstructions
- if (sWorld->getBoolConfig(CONFIG_PET_LOS))
- {
- if (!pet->IsWithinLOSInMap(TargetUnit))
- return;
- }
-
pet->ClearUnitState(UNIT_STATE_FOLLOW);
// This is true if pet has no target or has target but targets differs.
if (pet->getVictim() != TargetUnit || (pet->getVictim() == TargetUnit && !pet->GetCharmInfo()->IsCommandAttack()))
diff --git a/src/server/game/Maps/Map.cpp b/src/server/game/Maps/Map.cpp
index 9c3b7d5e5b5..b56833214d6 100644
--- a/src/server/game/Maps/Map.cpp
+++ b/src/server/game/Maps/Map.cpp
@@ -18,6 +18,7 @@
#include "Map.h"
#include "Battleground.h"
+#include "MMapFactory.h"
#include "CellImpl.h"
#include "DynamicTree.h"
#include "GridNotifiers.h"
@@ -43,7 +44,7 @@ union u_map_magic
};
u_map_magic MapMagic = { {'M','A','P','S'} };
-u_map_magic MapVersionMagic = { {'v','1','.','2'} };
+u_map_magic MapVersionMagic = { {'v','1','.','3'} };
u_map_magic MapAreaMagic = { {'A','R','E','A'} };
u_map_magic MapHeightMagic = { {'M','H','G','T'} };
u_map_magic MapLiquidMagic = { {'M','L','I','Q'} };
@@ -71,6 +72,8 @@ Map::~Map()
if (!m_scriptSchedule.empty())
sScriptMgr->DecreaseScheduledScriptCount(m_scriptSchedule.size());
+
+ MMAP::MMapFactory::createOrGetMMapManager()->unloadMapInstance(GetId(), i_InstanceId);
}
bool Map::ExistMap(uint32 mapid, int gx, int gy)
@@ -119,6 +122,16 @@ bool Map::ExistVMap(uint32 mapid, int gx, int gy)
return true;
}
+void Map::LoadMMap(int gx, int gy)
+{
+ bool mmapLoadResult = MMAP::MMapFactory::createOrGetMMapManager()->loadMap((sWorld->GetDataPath() + "mmaps").c_str(), GetId(), gx, gy);
+
+ if (mmapLoadResult)
+ sLog->outInfo(LOG_FILTER_MAPS, "MMAP loaded name:%s, id:%d, x:%d, y:%d (mmap rep.: x:%d, y:%d)", GetMapName(), GetId(), gx, gy, gx, gy);
+ else
+ sLog->outInfo(LOG_FILTER_MAPS, "Could not load MMAP name:%s, id:%d, x:%d, y:%d (mmap rep.: x:%d, y:%d)", GetMapName(), GetId(), gx, gy, gx, gy);
+}
+
void Map::LoadVMap(int gx, int gy)
{
// x and y are swapped !!
@@ -167,18 +180,16 @@ void Map::LoadMap(int gx, int gy, bool reload)
}
// map file name
- char *tmp=NULL;
- int len = sWorld->GetDataPath().length()+strlen("maps/%03u%02u%02u.map")+1;
+ char* tmp = NULL;
+ int len = sWorld->GetDataPath().length() + strlen("maps/%03u%02u%02u.map") + 1;
tmp = new char[len];
- snprintf(tmp, len, (char *)(sWorld->GetDataPath()+"maps/%03u%02u%02u.map").c_str(), GetId(), gx, gy);
+ snprintf(tmp, len, (char *)(sWorld->GetDataPath() + "maps/%03u%02u%02u.map").c_str(), GetId(), gx, gy);
sLog->outInfo(LOG_FILTER_MAPS, "Loading map %s", tmp);
// loading data
GridMaps[gx][gy] = new GridMap();
if (!GridMaps[gx][gy]->loadData(tmp))
- {
sLog->outError(LOG_FILTER_MAPS, "Error loading map file: \n %s\n", tmp);
- }
- delete [] tmp;
+ delete[] tmp;
sScriptMgr->OnLoadGridMap(this, GridMaps[gx][gy], gx, gy);
}
@@ -186,8 +197,12 @@ void Map::LoadMap(int gx, int gy, bool reload)
void Map::LoadMapAndVMap(int gx, int gy)
{
LoadMap(gx, gy);
+ // Only load the data for the base map
if (i_InstanceId == 0)
- LoadVMap(gx, gy); // Only load the data for the base map
+ {
+ LoadVMap(gx, gy);
+ LoadMMap(gx, gy);
+ }
}
void Map::InitStateMachine()
@@ -998,8 +1013,8 @@ bool Map::UnloadGrid(NGridType& ngrid, bool unloadAll)
GridMaps[gx][gy]->unloadData();
delete GridMaps[gx][gy];
}
- // x and y are swapped
VMAP::VMapFactory::createOrGetVMapManager()->unloadMap(GetId(), gx, gy);
+ MMAP::MMapFactory::createOrGetMMapManager()->unloadMap(GetId(), gx, gy);
}
else
((MapInstanced*)m_parentMap)->RemoveGridMapReference(GridCoord(gx, gy));
@@ -1071,7 +1086,7 @@ GridMap::~GridMap()
unloadData();
}
-bool GridMap::loadData(char *filename)
+bool GridMap::loadData(char* filename)
{
// Unload old data if exist
unloadData();
diff --git a/src/server/game/Maps/Map.h b/src/server/game/Maps/Map.h
index 5bb40a45f7e..e66e0869686 100644
--- a/src/server/game/Maps/Map.h
+++ b/src/server/game/Maps/Map.h
@@ -76,6 +76,8 @@ struct map_fileheader
uint32 heightMapSize;
uint32 liquidMapOffset;
uint32 liquidMapSize;
+ uint32 holesOffset;
+ uint32 holesSize;
};
#define MAP_AREA_NO_AREA 0x0001
@@ -480,6 +482,7 @@ class Map : public GridRefManager<NGridType>
void LoadMapAndVMap(int gx, int gy);
void LoadVMap(int gx, int gy);
void LoadMap(int gx, int gy, bool reload = false);
+ void LoadMMap(int gx, int gy);
GridMap* GetGrid(float x, float y);
void SetTimer(uint32 t) { i_gridExpiry = t < MIN_GRID_DELAY ? MIN_GRID_DELAY : t; }
diff --git a/src/server/game/Maps/MapInstanced.cpp b/src/server/game/Maps/MapInstanced.cpp
index 27a1e0cc432..c2079c22e76 100644
--- a/src/server/game/Maps/MapInstanced.cpp
+++ b/src/server/game/Maps/MapInstanced.cpp
@@ -21,6 +21,7 @@
#include "MapManager.h"
#include "Battleground.h"
#include "VMapFactory.h"
+#include "MMapFactory.h"
#include "InstanceSaveMgr.h"
#include "World.h"
#include "Group.h"
@@ -261,6 +262,7 @@ bool MapInstanced::DestroyInstance(InstancedMaps::iterator &itr)
if (m_InstancedMaps.size() <= 1 && sWorld->getBoolConfig(CONFIG_GRID_UNLOAD))
{
VMAP::VMapFactory::createOrGetVMapManager()->unloadMap(itr->second->GetId());
+ MMAP::MMapFactory::createOrGetMMapManager()->unloadMap(itr->second->GetId());
// in that case, unload grids of the base map, too
// so in the next map creation, (EnsureGridCreated actually) VMaps will be reloaded
Map::UnloadAll();
diff --git a/src/server/game/Miscellaneous/Language.h b/src/server/game/Miscellaneous/Language.h
index 77acb5e0218..036d25acc61 100644
--- a/src/server/game/Miscellaneous/Language.h
+++ b/src/server/game/Miscellaneous/Language.h
@@ -530,6 +530,7 @@ enum TrinityStrings
LANG_PINFO_BAN = 453,
LANG_PINFO_MAP_ONLINE = 714,
LANG_PINFO_MAP_OFFLINE = 716,
+ LANG_PINFO_GUILD_INFO = 749,
LANG_YOU_SET_EXPLORE_ALL = 551,
LANG_YOU_SET_EXPLORE_NOTHING = 552,
@@ -750,7 +751,32 @@ enum TrinityStrings
LANG_COMMAND_CREATURESTORAGE_NOTFOUND = 818,
LANG_CHANNEL_CITY = 819,
- // Room for in-game strings 820-999 not used
+
+ LANG_NPCINFO_GOSSIP = 820,
+ LANG_NPCINFO_QUESTGIVER = 821,
+ LANG_NPCINFO_TRAINER_CLASS = 822,
+ LANG_NPCINFO_TRAINER_PROFESSION = 823,
+ LANG_NPCINFO_VENDOR_AMMO = 824,
+ LANG_NPCINFO_VENDOR_FOOD = 825,
+ LANG_NPCINFO_VENDOR_POISON = 826,
+ LANG_NPCINFO_VENDOR_REAGENT = 827,
+ LANG_NPCINFO_REPAIR = 828,
+ LANG_NPCINFO_FLIGHTMASTER = 829,
+ LANG_NPCINFO_SPIRITHEALER = 830,
+ LANG_NPCINFO_SPIRITGUIDE = 831,
+ LANG_NPCINFO_INNKEEPER = 832,
+ LANG_NPCINFO_BANKER = 833,
+ LANG_NPCINFO_PETITIONER = 834,
+ LANG_NPCINFO_TABARDDESIGNER = 835,
+ LANG_NPCINFO_BATTLEMASTER = 836,
+ LANG_NPCINFO_AUCTIONEER = 837,
+ LANG_NPCINFO_STABLEMASTER = 838,
+ LANG_NPCINFO_GUILD_BANKER = 839,
+ LANG_NPCINFO_SPELLCLICK = 840,
+ LANG_NPCINFO_MAILBOX = 841,
+ LANG_NPCINFO_PLAYER_VEHICLE = 842,
+
+ // Room for in-game strings 843-999 not used
// Level 4 (CLI only commands)
LANG_COMMAND_EXIT = 1000,
@@ -830,7 +856,13 @@ enum TrinityStrings
LANG_MOVEGENS_EFFECT = 1142,
LANG_MOVEFLAGS_GET = 1143,
LANG_MOVEFLAGS_SET = 1144,
- // Room for more level 3 1144-1199 not used
+ LANG_GROUP_ALREADY_IN_GROUP = 1145,
+ LANG_GROUP_PLAYER_JOINED = 1146,
+ LANG_GROUP_NOT_IN_GROUP = 1147,
+ LANG_GROUP_FULL = 1148,
+ LANG_GROUP_TYPE = 1149,
+ LANG_GROUP_PLAYER_NAME_GUID = 1150,
+ // Room for more level 3 1151-1199 not used
// Debug commands
LANG_CINEMATIC_NOT_EXIST = 1200,
diff --git a/src/server/game/Miscellaneous/SharedDefines.h b/src/server/game/Miscellaneous/SharedDefines.h
index 6ff47f40ed4..f5c748c7b88 100644
--- a/src/server/game/Miscellaneous/SharedDefines.h
+++ b/src/server/game/Miscellaneous/SharedDefines.h
@@ -19,6 +19,7 @@
#ifndef TRINITY_SHAREDDEFINES_H
#define TRINITY_SHAREDDEFINES_H
+#include "DetourNavMesh.h"
#include "Define.h"
#include <cassert>
@@ -3874,4 +3875,33 @@ enum PartyResult
ERR_PARTY_LFG_TELEPORT_IN_COMBAT = 30
};
+const uint32 MMAP_MAGIC = 0x4d4d4150; // 'MMAP'
+#define MMAP_VERSION 3
+
+struct MmapTileHeader
+{
+ uint32 mmapMagic;
+ uint32 dtVersion;
+ uint32 mmapVersion;
+ uint32 size;
+ bool usesLiquids : 1;
+
+ MmapTileHeader() : mmapMagic(MMAP_MAGIC), dtVersion(DT_NAVMESH_VERSION),
+ mmapVersion(MMAP_VERSION), size(0), usesLiquids(true) {}
+};
+
+enum NavTerrain
+{
+ NAV_EMPTY = 0x00,
+ NAV_GROUND = 0x01,
+ NAV_MAGMA = 0x02,
+ NAV_SLIME = 0x04,
+ NAV_WATER = 0x08,
+ NAV_UNUSED1 = 0x10,
+ NAV_UNUSED2 = 0x20,
+ NAV_UNUSED3 = 0x40,
+ NAV_UNUSED4 = 0x80
+ // we only have 8 bits
+};
+
#endif
diff --git a/src/server/game/Movement/FollowerRefManager.h b/src/server/game/Movement/FollowerRefManager.h
index 2bb31d27227..92904f8e4af 100644
--- a/src/server/game/Movement/FollowerRefManager.h
+++ b/src/server/game/Movement/FollowerRefManager.h
@@ -29,4 +29,3 @@ class FollowerRefManager : public RefManager<Unit, TargetedMovementGeneratorBase
};
#endif
-
diff --git a/src/server/game/Movement/FollowerReference.cpp b/src/server/game/Movement/FollowerReference.cpp
index 2ce23e214d1..30797bbaaca 100644
--- a/src/server/game/Movement/FollowerReference.cpp
+++ b/src/server/game/Movement/FollowerReference.cpp
@@ -34,4 +34,3 @@ void FollowerReference::sourceObjectDestroyLink()
{
getSource()->stopFollowing();
}
-
diff --git a/src/server/game/Movement/FollowerReference.h b/src/server/game/Movement/FollowerReference.h
index 9e373d2527e..43ad7e7fa58 100644
--- a/src/server/game/Movement/FollowerReference.h
+++ b/src/server/game/Movement/FollowerReference.h
@@ -32,4 +32,3 @@ class FollowerReference : public Reference<Unit, TargetedMovementGeneratorBase>
void sourceObjectDestroyLink();
};
#endif
-
diff --git a/src/server/game/Movement/MotionMaster.cpp b/src/server/game/Movement/MotionMaster.cpp
index 277a5721c3d..c9ca7772186 100644
--- a/src/server/game/Movement/MotionMaster.cpp
+++ b/src/server/game/Movement/MotionMaster.cpp
@@ -87,7 +87,7 @@ void MotionMaster::UpdateMotion(uint32 diff)
ASSERT(!empty());
_cleanFlag |= MMCF_UPDATE;
- if (!top()->Update(*_owner, diff))
+ if (!top()->Update(_owner, diff))
{
_cleanFlag &= ~MMCF_UPDATE;
MovementExpired();
@@ -111,7 +111,7 @@ void MotionMaster::UpdateMotion(uint32 diff)
else if (needInitTop())
InitTop();
else if (_cleanFlag & MMCF_RESET)
- top()->Reset(*_owner);
+ top()->Reset(_owner);
_cleanFlag &= ~MMCF_RESET;
}
@@ -132,7 +132,7 @@ void MotionMaster::DirectClean(bool reset)
if (needInitTop())
InitTop();
else if (reset)
- top()->Reset(*_owner);
+ top()->Reset(_owner);
}
void MotionMaster::DelayedClean()
@@ -163,7 +163,7 @@ void MotionMaster::DirectExpire(bool reset)
else if (needInitTop())
InitTop();
else if (reset)
- top()->Reset(*_owner);
+ top()->Reset(_owner);
}
void MotionMaster::DelayedExpire()
@@ -199,19 +199,19 @@ void MotionMaster::MoveTargetedHome()
{
Clear(false);
- if (_owner->GetTypeId()==TYPEID_UNIT && !((Creature*)_owner)->GetCharmerOrOwnerGUID())
+ if (_owner->GetTypeId() == TYPEID_UNIT && !_owner->ToCreature()->GetCharmerOrOwnerGUID())
{
sLog->outDebug(LOG_FILTER_GENERAL, "Creature (Entry: %u GUID: %u) targeted home", _owner->GetEntry(), _owner->GetGUIDLow());
Mutate(new HomeMovementGenerator<Creature>(), MOTION_SLOT_ACTIVE);
}
- else if (_owner->GetTypeId()==TYPEID_UNIT && ((Creature*)_owner)->GetCharmerOrOwnerGUID())
+ else if (_owner->GetTypeId() == TYPEID_UNIT && _owner->ToCreature()->GetCharmerOrOwnerGUID())
{
sLog->outDebug(LOG_FILTER_GENERAL, "Pet or controlled creature (Entry: %u GUID: %u) targeting home", _owner->GetEntry(), _owner->GetGUIDLow());
- Unit* target = ((Creature*)_owner)->GetCharmerOrOwner();
+ Unit* target = _owner->ToCreature()->GetCharmerOrOwner();
if (target)
{
sLog->outDebug(LOG_FILTER_GENERAL, "Following %s (GUID: %u)", target->GetTypeId() == TYPEID_PLAYER ? "player" : "creature", target->GetTypeId() == TYPEID_PLAYER ? target->GetGUIDLow() : ((Creature*)target)->GetDBTableGUIDLow());
- Mutate(new FollowMovementGenerator<Creature>(*target, PET_FOLLOW_DIST, PET_FOLLOW_ANGLE), MOTION_SLOT_ACTIVE);
+ Mutate(new FollowMovementGenerator<Creature>(target, PET_FOLLOW_DIST, PET_FOLLOW_ANGLE), MOTION_SLOT_ACTIVE);
}
}
else
@@ -248,7 +248,7 @@ void MotionMaster::MoveChase(Unit* target, float dist, float angle)
_owner->GetGUIDLow(),
target->GetTypeId() == TYPEID_PLAYER ? "player" : "creature",
target->GetTypeId() == TYPEID_PLAYER ? target->GetGUIDLow() : target->ToCreature()->GetDBTableGUIDLow());
- Mutate(new ChaseMovementGenerator<Player>(*target, dist, angle), MOTION_SLOT_ACTIVE);
+ Mutate(new ChaseMovementGenerator<Player>(target, dist, angle), MOTION_SLOT_ACTIVE);
}
else
{
@@ -256,7 +256,7 @@ void MotionMaster::MoveChase(Unit* target, float dist, float angle)
_owner->GetEntry(), _owner->GetGUIDLow(),
target->GetTypeId() == TYPEID_PLAYER ? "player" : "creature",
target->GetTypeId() == TYPEID_PLAYER ? target->GetGUIDLow() : target->ToCreature()->GetDBTableGUIDLow());
- Mutate(new ChaseMovementGenerator<Creature>(*target, dist, angle), MOTION_SLOT_ACTIVE);
+ Mutate(new ChaseMovementGenerator<Creature>(target, dist, angle), MOTION_SLOT_ACTIVE);
}
}
@@ -272,7 +272,7 @@ void MotionMaster::MoveFollow(Unit* target, float dist, float angle, MovementSlo
sLog->outDebug(LOG_FILTER_GENERAL, "Player (GUID: %u) follow to %s (GUID: %u)", _owner->GetGUIDLow(),
target->GetTypeId() == TYPEID_PLAYER ? "player" : "creature",
target->GetTypeId() == TYPEID_PLAYER ? target->GetGUIDLow() : target->ToCreature()->GetDBTableGUIDLow());
- Mutate(new FollowMovementGenerator<Player>(*target, dist, angle), slot);
+ Mutate(new FollowMovementGenerator<Player>(target, dist, angle), slot);
}
else
{
@@ -280,22 +280,22 @@ void MotionMaster::MoveFollow(Unit* target, float dist, float angle, MovementSlo
_owner->GetEntry(), _owner->GetGUIDLow(),
target->GetTypeId() == TYPEID_PLAYER ? "player" : "creature",
target->GetTypeId() == TYPEID_PLAYER ? target->GetGUIDLow() : target->ToCreature()->GetDBTableGUIDLow());
- Mutate(new FollowMovementGenerator<Creature>(*target, dist, angle), slot);
+ Mutate(new FollowMovementGenerator<Creature>(target, dist, angle), slot);
}
}
-void MotionMaster::MovePoint(uint32 id, float x, float y, float z)
+void MotionMaster::MovePoint(uint32 id, float x, float y, float z, bool generatePath)
{
if (_owner->GetTypeId() == TYPEID_PLAYER)
{
sLog->outDebug(LOG_FILTER_GENERAL, "Player (GUID: %u) targeted point (Id: %u X: %f Y: %f Z: %f)", _owner->GetGUIDLow(), id, x, y, z);
- Mutate(new PointMovementGenerator<Player>(id, x, y, z), MOTION_SLOT_ACTIVE);
+ Mutate(new PointMovementGenerator<Player>(id, x, y, z, generatePath), MOTION_SLOT_ACTIVE);
}
else
{
sLog->outDebug(LOG_FILTER_GENERAL, "Creature (Entry: %u GUID: %u) targeted point (ID: %u X: %f Y: %f Z: %f)",
_owner->GetEntry(), _owner->GetGUIDLow(), id, x, y, z);
- Mutate(new PointMovementGenerator<Creature>(id, x, y, z), MOTION_SLOT_ACTIVE);
+ Mutate(new PointMovementGenerator<Creature>(id, x, y, z, generatePath), MOTION_SLOT_ACTIVE);
}
}
@@ -306,7 +306,7 @@ void MotionMaster::MoveLand(uint32 id, Position const& pos)
sLog->outDebug(LOG_FILTER_GENERAL, "Creature (Entry: %u) landing point (ID: %u X: %f Y: %f Z: %f)", _owner->GetEntry(), id, x, y, z);
- Movement::MoveSplineInit init(*_owner);
+ Movement::MoveSplineInit init(_owner);
init.MoveTo(x, y, z);
init.SetAnimation(Movement::ToGround);
init.Launch();
@@ -320,7 +320,7 @@ void MotionMaster::MoveTakeoff(uint32 id, Position const& pos)
sLog->outDebug(LOG_FILTER_GENERAL, "Creature (Entry: %u) landing point (ID: %u X: %f Y: %f Z: %f)", _owner->GetEntry(), id, x, y, z);
- Movement::MoveSplineInit init(*_owner);
+ Movement::MoveSplineInit init(_owner);
init.MoveTo(x, y, z);
init.SetAnimation(Movement::ToFly);
init.Launch();
@@ -340,7 +340,7 @@ void MotionMaster::MoveKnockbackFrom(float srcX, float srcY, float speedXY, floa
_owner->GetNearPoint(_owner, x, y, z, _owner->GetObjectSize(), dist, _owner->GetAngle(srcX, srcY) + M_PI);
- Movement::MoveSplineInit init(*_owner);
+ Movement::MoveSplineInit init(_owner);
init.MoveTo(x, y, z);
init.SetParabolic(max_height, 0);
init.SetOrientationFixed(true);
@@ -370,8 +370,8 @@ void MotionMaster::MoveJump(float x, float y, float z, float speedXY, float spee
float moveTimeHalf = speedZ / Movement::gravity;
float max_height = -Movement::computeFallElevation(moveTimeHalf, false, -speedZ);
- Movement::MoveSplineInit init(*_owner);
- init.MoveTo(x, y, z);
+ Movement::MoveSplineInit init(_owner);
+ init.MoveTo(x, y, z, false);
init.SetParabolic(max_height, 0);
init.SetVelocity(speedXY);
init.Launch();
@@ -399,14 +399,14 @@ void MotionMaster::MoveFall(uint32 id /*=0*/)
_owner->m_movementInfo.SetFallTime(0);
}
- Movement::MoveSplineInit init(*_owner);
- init.MoveTo(_owner->GetPositionX(), _owner->GetPositionY(), tz);
+ Movement::MoveSplineInit init(_owner);
+ init.MoveTo(_owner->GetPositionX(), _owner->GetPositionY(), tz, false);
init.SetFall();
init.Launch();
Mutate(new EffectMovementGenerator(id), MOTION_SLOT_CONTROLLED);
}
-void MotionMaster::MoveCharge(float x, float y, float z, float speed, uint32 id)
+void MotionMaster::MoveCharge(float x, float y, float z, float speed, uint32 id, bool generatePath)
{
if (Impl[MOTION_SLOT_CONTROLLED] && Impl[MOTION_SLOT_CONTROLLED]->GetMovementGeneratorType() != DISTRACT_MOTION_TYPE)
return;
@@ -414,16 +414,28 @@ void MotionMaster::MoveCharge(float x, float y, float z, float speed, uint32 id)
if (_owner->GetTypeId() == TYPEID_PLAYER)
{
sLog->outDebug(LOG_FILTER_GENERAL, "Player (GUID: %u) charge point (X: %f Y: %f Z: %f)", _owner->GetGUIDLow(), x, y, z);
- Mutate(new PointMovementGenerator<Player>(id, x, y, z, speed), MOTION_SLOT_CONTROLLED);
+ Mutate(new PointMovementGenerator<Player>(id, x, y, z, generatePath, speed), MOTION_SLOT_CONTROLLED);
}
else
{
sLog->outDebug(LOG_FILTER_GENERAL, "Creature (Entry: %u GUID: %u) charge point (X: %f Y: %f Z: %f)",
_owner->GetEntry(), _owner->GetGUIDLow(), x, y, z);
- Mutate(new PointMovementGenerator<Creature>(id, x, y, z, speed), MOTION_SLOT_CONTROLLED);
+ Mutate(new PointMovementGenerator<Creature>(id, x, y, z, generatePath, speed), MOTION_SLOT_CONTROLLED);
}
}
+void MotionMaster::MoveCharge(PathGenerator path, float speed, uint32 id)
+{
+ Vector3 dest = path.GetActualEndPosition();
+
+ MoveCharge(dest.x, dest.y, dest.z, speed, id);
+
+ Movement::MoveSplineInit init(_owner);
+ init.MovebyPath(path.GetPath());
+ init.SetVelocity(speed);
+ init.Launch();
+}
+
void MotionMaster::MoveSeekAssistance(float x, float y, float z)
{
if (_owner->GetTypeId() == TYPEID_PLAYER)
@@ -546,7 +558,7 @@ void MotionMaster::Mutate(MovementGenerator *m, MovementSlot slot)
else
{
_needInit[slot] = false;
- m->Initialize(*_owner);
+ m->Initialize(_owner);
}
}
@@ -614,7 +626,7 @@ MovementGeneratorType MotionMaster::GetMotionSlotType(int slot) const
void MotionMaster::InitTop()
{
- top()->Initialize(*_owner);
+ top()->Initialize(_owner);
_needInit[_top] = false;
}
@@ -622,7 +634,7 @@ void MotionMaster::DirectDelete(_Ty curr)
{
if (isStatic(curr))
return;
- curr->Finalize(*_owner);
+ curr->Finalize(_owner);
delete curr;
}
@@ -639,9 +651,9 @@ void MotionMaster::DelayedDelete(_Ty curr)
bool MotionMaster::GetDestination(float &x, float &y, float &z)
{
if (_owner->movespline->Finalized())
- return false;
+ return false;
- const G3D::Vector3& dest = _owner->movespline->FinalDestination();
+ G3D::Vector3 const& dest = _owner->movespline->FinalDestination();
x = dest.x;
y = dest.y;
z = dest.z;
diff --git a/src/server/game/Movement/MotionMaster.h b/src/server/game/Movement/MotionMaster.h
index f6f58afef22..4b6075aac10 100644
--- a/src/server/game/Movement/MotionMaster.h
+++ b/src/server/game/Movement/MotionMaster.h
@@ -26,6 +26,7 @@
class MovementGenerator;
class Unit;
+class PathGenerator;
// Creature Entry ID used for waypoints show, visible only for GMs
#define VISUAL_WAYPOINT 1
@@ -154,13 +155,14 @@ class MotionMaster //: private std::stack<MovementGenerator *>
void MoveFleeing(Unit* enemy, uint32 time = 0);
void MovePoint(uint32 id, const Position &pos)
{ MovePoint(id, pos.m_positionX, pos.m_positionY, pos.m_positionZ); }
- void MovePoint(uint32 id, float x, float y, float z);
+ void MovePoint(uint32 id, float x, float y, float z, bool generatePath = true);
// These two movement types should only be used with creatures having landing/takeoff animations
void MoveLand(uint32 id, Position const& pos);
void MoveTakeoff(uint32 id, Position const& pos);
- void MoveCharge(float x, float y, float z, float speed = SPEED_CHARGE, uint32 id = EVENT_CHARGE);
+ void MoveCharge(float x, float y, float z, float speed = SPEED_CHARGE, uint32 id = EVENT_CHARGE, bool generatePath = false);
+ void MoveCharge(PathGenerator path, float speed = SPEED_CHARGE, uint32 id = EVENT_CHARGE);
void MoveKnockbackFrom(float srcX, float srcY, float speedXY, float speedZ);
void MoveJumpTo(float angle, float speedXY, float speedZ);
void MoveJump(Position const& pos, float speedXY, float speedZ, uint32 id = EVENT_JUMP)
@@ -199,4 +201,3 @@ class MotionMaster //: private std::stack<MovementGenerator *>
uint8 _cleanFlag;
};
#endif
-
diff --git a/src/server/game/Movement/MovementGenerator.h b/src/server/game/Movement/MovementGenerator.h
index 1c1c38bc72f..39394a75513 100644..100755
--- a/src/server/game/Movement/MovementGenerator.h
+++ b/src/server/game/Movement/MovementGenerator.h
@@ -33,41 +33,47 @@ class MovementGenerator
public:
virtual ~MovementGenerator();
- virtual void Initialize(Unit &) = 0;
- virtual void Finalize(Unit &) = 0;
+ virtual void Initialize(Unit*) = 0;
+ virtual void Finalize(Unit*) = 0;
- virtual void Reset(Unit &) = 0;
+ virtual void Reset(Unit*) = 0;
- virtual bool Update(Unit &, uint32 time_diff) = 0;
+ virtual bool Update(Unit*, uint32 time_diff) = 0;
virtual MovementGeneratorType GetMovementGeneratorType() = 0;
virtual void unitSpeedChanged() { }
+
+ // used by Evade code for select point to evade with expected restart default movement
+ virtual bool GetResetPosition(Unit*, float& /*x*/, float& /*y*/, float& /*z*/) { return false; }
};
template<class T, class D>
class MovementGeneratorMedium : public MovementGenerator
{
public:
- void Initialize(Unit &u)
+ void Initialize(Unit* u)
{
//u->AssertIsType<T>();
- (static_cast<D*>(this))->DoInitialize(*((T*)&u));
+ (static_cast<D*>(this))->DoInitialize(static_cast<T*>(u));
}
- void Finalize(Unit &u)
+
+ void Finalize(Unit* u)
{
//u->AssertIsType<T>();
- (static_cast<D*>(this))->DoFinalize(*((T*)&u));
+ (static_cast<D*>(this))->DoFinalize(static_cast<T*>(u));
}
- void Reset(Unit &u)
+
+ void Reset(Unit* u)
{
//u->AssertIsType<T>();
- (static_cast<D*>(this))->DoReset(*((T*)&u));
+ (static_cast<D*>(this))->DoReset(static_cast<T*>(u));
}
- bool Update(Unit &u, uint32 time_diff)
+
+ bool Update(Unit* u, uint32 time_diff)
{
//u->AssertIsType<T>();
- return (static_cast<D*>(this))->DoUpdate(*((T*)&u), time_diff);
+ return (static_cast<D*>(this))->DoUpdate(static_cast<T*>(u), time_diff);
}
};
@@ -88,4 +94,3 @@ typedef FactoryHolder<MovementGenerator, MovementGeneratorType> MovementGenerato
typedef FactoryHolder<MovementGenerator, MovementGeneratorType>::FactoryHolderRegistry MovementGeneratorRegistry;
typedef FactoryHolder<MovementGenerator, MovementGeneratorType>::FactoryHolderRepository MovementGeneratorRepository;
#endif
-
diff --git a/src/server/game/Movement/MovementGeneratorImpl.h b/src/server/game/Movement/MovementGeneratorImpl.h
index 2618cadc14f..b77db7b5b9d 100644
--- a/src/server/game/Movement/MovementGeneratorImpl.h
+++ b/src/server/game/Movement/MovementGeneratorImpl.h
@@ -28,4 +28,3 @@ MovementGeneratorFactory<MOVEMENT_GEN>::Create(void * /*data*/) const
return (new MOVEMENT_GEN());
}
#endif
-
diff --git a/src/server/game/Movement/MovementGenerators/ConfusedMovementGenerator.cpp b/src/server/game/Movement/MovementGenerators/ConfusedMovementGenerator.cpp
index 482c16997a0..72537f0898c 100755
--- a/src/server/game/Movement/MovementGenerators/ConfusedMovementGenerator.cpp
+++ b/src/server/game/Movement/MovementGenerators/ConfusedMovementGenerator.cpp
@@ -19,6 +19,7 @@
#include "Creature.h"
#include "MapManager.h"
#include "ConfusedMovementGenerator.h"
+#include "PathGenerator.h"
#include "VMapFactory.h"
#include "MoveSplineInit.h"
#include "MoveSpline.h"
@@ -30,100 +31,44 @@
#endif
template<class T>
-void ConfusedMovementGenerator<T>::DoInitialize(T &unit)
+void ConfusedMovementGenerator<T>::DoInitialize(T* unit)
{
- unit.StopMoving();
- float const wander_distance = 4;
- float x = unit.GetPositionX();
- float y = unit.GetPositionY();
- float z = unit.GetPositionZ();
+ unit->AddUnitState(UNIT_STATE_CONFUSED);
+ unit->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_CONFUSED);
+ unit->GetPosition(i_x, i_y, i_z);
- Map const* map = unit.GetBaseMap();
+ if (!unit->isAlive() || unit->IsStopped())
+ return;
- i_nextMove = 1;
-
- bool is_water_ok, is_land_ok;
- _InitSpecific(unit, is_water_ok, is_land_ok);
-
- for (uint8 idx = 0; idx < MAX_CONF_WAYPOINTS + 1; ++idx)
- {
- float wanderX = x + (wander_distance * (float)rand_norm() - wander_distance/2);
- float wanderY = y + (wander_distance * (float)rand_norm() - wander_distance/2);
-
- // prevent invalid coordinates generation
- Trinity::NormalizeMapCoord(wanderX);
- Trinity::NormalizeMapCoord(wanderY);
-
- if (unit.IsWithinLOS(wanderX, wanderY, z))
- {
- bool is_water = map->IsInWater(wanderX, wanderY, z);
-
- if ((is_water && !is_water_ok) || (!is_water && !is_land_ok))
- {
- //! Cannot use coordinates outside our InhabitType. Use the current or previous position.
- wanderX = idx > 0 ? i_waypoints[idx-1][0] : x;
- wanderY = idx > 0 ? i_waypoints[idx-1][1] : y;
- }
- }
- else
- {
- //! Trying to access path outside line of sight. Skip this by using the current or previous position.
- wanderX = idx > 0 ? i_waypoints[idx-1][0] : x;
- wanderY = idx > 0 ? i_waypoints[idx-1][1] : y;
- }
-
- unit.UpdateAllowedPositionZ(wanderX, wanderY, z);
-
- //! Positions are fine - apply them to this waypoint
- i_waypoints[idx][0] = wanderX;
- i_waypoints[idx][1] = wanderY;
- i_waypoints[idx][2] = z;
- }
-
- unit.StopMoving();
- unit.SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_CONFUSED);
- unit.AddUnitState(UNIT_STATE_CONFUSED | UNIT_STATE_CONFUSED_MOVE);
-}
-
-template<>
-void ConfusedMovementGenerator<Creature>::_InitSpecific(Creature &creature, bool &is_water_ok, bool &is_land_ok)
-{
- is_water_ok = creature.canSwim();
- is_land_ok = creature.canWalk();
-}
-
-template<>
-void ConfusedMovementGenerator<Player>::_InitSpecific(Player &, bool &is_water_ok, bool &is_land_ok)
-{
- is_water_ok = true;
- is_land_ok = true;
+ unit->StopMoving();
+ unit->AddUnitState(UNIT_STATE_CONFUSED_MOVE);
}
template<class T>
-void ConfusedMovementGenerator<T>::DoReset(T &unit)
+void ConfusedMovementGenerator<T>::DoReset(T* unit)
{
- i_nextMove = 1;
i_nextMoveTime.Reset(0);
- unit.StopMoving();
- unit.AddUnitState(UNIT_STATE_CONFUSED | UNIT_STATE_CONFUSED_MOVE);
+
+ if (!unit->isAlive() || unit->IsStopped())
+ return;
+
+ unit->StopMoving();
+ unit->AddUnitState(UNIT_STATE_CONFUSED | UNIT_STATE_CONFUSED_MOVE);
}
template<class T>
-bool ConfusedMovementGenerator<T>::DoUpdate(T &unit, uint32 diff)
+bool ConfusedMovementGenerator<T>::DoUpdate(T* unit, uint32 diff)
{
- if (unit.HasUnitState(UNIT_STATE_ROOT | UNIT_STATE_STUNNED | UNIT_STATE_DISTRACTED))
+ if (unit->HasUnitState(UNIT_STATE_ROOT | UNIT_STATE_STUNNED | UNIT_STATE_DISTRACTED))
return true;
if (i_nextMoveTime.Passed())
{
// currently moving, update location
- unit.AddUnitState(UNIT_STATE_CONFUSED_MOVE);
+ unit->AddUnitState(UNIT_STATE_CONFUSED_MOVE);
- if (unit.movespline->Finalized())
- {
- i_nextMove = urand(1, MAX_CONF_WAYPOINTS);
- i_nextMoveTime.Reset(urand(500, 1200)); // Guessed
- }
+ if (unit->movespline->Finalized())
+ i_nextMoveTime.Reset(urand(800, 1500));
}
else
{
@@ -132,14 +77,25 @@ bool ConfusedMovementGenerator<T>::DoUpdate(T &unit, uint32 diff)
if (i_nextMoveTime.Passed())
{
// start moving
- unit.AddUnitState(UNIT_STATE_CONFUSED_MOVE);
+ unit->AddUnitState(UNIT_STATE_CONFUSED_MOVE);
+
+ float dest = 4.0f * (float)rand_norm() - 2.0f;
+
+ Position pos;
+ pos.Relocate(i_x, i_y, i_z);
+ unit->MovePositionToFirstCollision(pos, dest, 0.0f);
+
+ PathGenerator path(unit);
+ path.SetPathLengthLimit(30.0f);
+ bool result = path.CalculatePath(pos.m_positionX, pos.m_positionY, pos.m_positionZ);
+ if (!result || (path.GetPathType() & PATHFIND_NOPATH))
+ {
+ i_nextMoveTime.Reset(100);
+ return true;
+ }
- ASSERT(i_nextMove <= MAX_CONF_WAYPOINTS);
- float x = i_waypoints[i_nextMove][0];
- float y = i_waypoints[i_nextMove][1];
- float z = i_waypoints[i_nextMove][2];
Movement::MoveSplineInit init(unit);
- init.MoveTo(x, y, z);
+ init.MovebyPath(path.GetPath());
init.SetWalk(true);
init.Launch();
}
@@ -149,25 +105,25 @@ bool ConfusedMovementGenerator<T>::DoUpdate(T &unit, uint32 diff)
}
template<>
-void ConfusedMovementGenerator<Player>::DoFinalize(Player &unit)
+void ConfusedMovementGenerator<Player>::DoFinalize(Player* unit)
{
- unit.RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_CONFUSED);
- unit.ClearUnitState(UNIT_STATE_CONFUSED | UNIT_STATE_CONFUSED_MOVE);
+ unit->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_CONFUSED);
+ unit->ClearUnitState(UNIT_STATE_CONFUSED | UNIT_STATE_CONFUSED_MOVE);
+ unit->StopMoving();
}
template<>
-void ConfusedMovementGenerator<Creature>::DoFinalize(Creature &unit)
+void ConfusedMovementGenerator<Creature>::DoFinalize(Creature* unit)
{
- unit.RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_CONFUSED);
- unit.ClearUnitState(UNIT_STATE_CONFUSED | UNIT_STATE_CONFUSED_MOVE);
- if (unit.getVictim())
- unit.SetTarget(unit.getVictim()->GetGUID());
+ unit->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_CONFUSED);
+ unit->ClearUnitState(UNIT_STATE_CONFUSED | UNIT_STATE_CONFUSED_MOVE);
+ if (unit->getVictim())
+ unit->SetTarget(unit->getVictim()->GetGUID());
}
-template void ConfusedMovementGenerator<Player>::DoInitialize(Player &player);
-template void ConfusedMovementGenerator<Creature>::DoInitialize(Creature &creature);
-template void ConfusedMovementGenerator<Player>::DoReset(Player &player);
-template void ConfusedMovementGenerator<Creature>::DoReset(Creature &creature);
-template bool ConfusedMovementGenerator<Player>::DoUpdate(Player &player, uint32 diff);
-template bool ConfusedMovementGenerator<Creature>::DoUpdate(Creature &creature, uint32 diff);
-
+template void ConfusedMovementGenerator<Player>::DoInitialize(Player*);
+template void ConfusedMovementGenerator<Creature>::DoInitialize(Creature*);
+template void ConfusedMovementGenerator<Player>::DoReset(Player*);
+template void ConfusedMovementGenerator<Creature>::DoReset(Creature*);
+template bool ConfusedMovementGenerator<Player>::DoUpdate(Player*, uint32 diff);
+template bool ConfusedMovementGenerator<Creature>::DoUpdate(Creature*, uint32 diff);
diff --git a/src/server/game/Movement/MovementGenerators/ConfusedMovementGenerator.h b/src/server/game/Movement/MovementGenerators/ConfusedMovementGenerator.h
index 20e84f3a97f..da29b8aa12e 100755
--- a/src/server/game/Movement/MovementGenerators/ConfusedMovementGenerator.h
+++ b/src/server/game/Movement/MovementGenerators/ConfusedMovementGenerator.h
@@ -22,25 +22,20 @@
#include "MovementGenerator.h"
#include "Timer.h"
-#define MAX_CONF_WAYPOINTS 24 //! Allows a twelve second confusion if i_nextMove always is the absolute minimum timer.
-
template<class T>
class ConfusedMovementGenerator : public MovementGeneratorMedium< T, ConfusedMovementGenerator<T> >
{
public:
explicit ConfusedMovementGenerator() : i_nextMoveTime(0) {}
- void DoInitialize(T &);
- void DoFinalize(T &);
- void DoReset(T &);
- bool DoUpdate(T &, uint32);
+ void DoInitialize(T*);
+ void DoFinalize(T*);
+ void DoReset(T*);
+ bool DoUpdate(T*, uint32);
MovementGeneratorType GetMovementGeneratorType() { return CONFUSED_MOTION_TYPE; }
private:
- void _InitSpecific(T &, bool &, bool &);
TimeTracker i_nextMoveTime;
- float i_waypoints[MAX_CONF_WAYPOINTS+1][3];
- uint32 i_nextMove;
+ float i_x, i_y, i_z;
};
#endif
-
diff --git a/src/server/game/Movement/MovementGenerators/FleeingMovementGenerator.cpp b/src/server/game/Movement/MovementGenerators/FleeingMovementGenerator.cpp
index d9050e2b76a..216fffbfee1 100755..100644
--- a/src/server/game/Movement/MovementGenerators/FleeingMovementGenerator.cpp
+++ b/src/server/game/Movement/MovementGenerators/FleeingMovementGenerator.cpp
@@ -20,6 +20,7 @@
#include "CreatureAI.h"
#include "MapManager.h"
#include "FleeingMovementGenerator.h"
+#include "PathGenerator.h"
#include "ObjectAccessor.h"
#include "MoveSplineInit.h"
#include "MoveSpline.h"
@@ -29,384 +30,163 @@
#define MAX_QUIET_DISTANCE 43.0f
template<class T>
-void FleeingMovementGenerator<T>::_setTargetLocation(T &owner)
+void FleeingMovementGenerator<T>::_setTargetLocation(T* owner)
{
- if (!&owner)
+ if (!owner)
return;
- if (owner.HasUnitState(UNIT_STATE_ROOT | UNIT_STATE_STUNNED))
+ if (owner->HasUnitState(UNIT_STATE_ROOT | UNIT_STATE_STUNNED))
return;
- if (!_setMoveData(owner))
- return;
+ owner->AddUnitState(UNIT_STATE_FLEEING_MOVE);
float x, y, z;
- if (!_getPoint(owner, x, y, z))
- return;
+ _getPoint(owner, x, y, z);
- owner.AddUnitState(UNIT_STATE_FLEEING_MOVE);
+ PathGenerator path(owner);
+ path.SetPathLengthLimit(30.0f);
+ bool result = path.CalculatePath(x, y, z);
+ if (!result || (path.GetPathType() & PATHFIND_NOPATH))
+ {
+ i_nextCheckTime.Reset(100);
+ return;
+ }
Movement::MoveSplineInit init(owner);
- init.MoveTo(x, y, z);
+ init.MovebyPath(path.GetPath());
init.SetWalk(false);
- init.Launch();
+ int32 traveltime = init.Launch();
+ i_nextCheckTime.Reset(traveltime + urand(800, 1500));
}
template<class T>
-bool FleeingMovementGenerator<T>::_getPoint(T &owner, float &x, float &y, float &z)
+void FleeingMovementGenerator<T>::_getPoint(T* owner, float &x, float &y, float &z)
{
- if (!&owner)
- return false;
-
- x = owner.GetPositionX();
- y = owner.GetPositionY();
- z = owner.GetPositionZ();
-
- float temp_x, temp_y, angle;
- const Map* _map = owner.GetBaseMap();
- // primitive path-finding
- for (uint8 i = 0; i < 18; ++i)
+ float dist_from_caster, angle_to_caster;
+ if (Unit* fright = ObjectAccessor::GetUnit(*owner, i_frightGUID))
{
- if (i_only_forward && i > 2)
- break;
-
- float distance = 5.0f;
-
- switch (i)
- {
- case 0:
- angle = i_cur_angle;
- break;
- case 1:
- angle = i_cur_angle;
- distance /= 2;
- break;
- case 2:
- angle = i_cur_angle;
- distance /= 4;
- break;
- case 3:
- angle = i_cur_angle + static_cast<float>(M_PI/4);
- break;
- case 4:
- angle = i_cur_angle - static_cast<float>(M_PI/4);
- break;
- case 5:
- angle = i_cur_angle + static_cast<float>(M_PI/4);
- distance /= 2;
- break;
- case 6:
- angle = i_cur_angle - static_cast<float>(M_PI/4);
- distance /= 2;
- break;
- case 7:
- angle = i_cur_angle + static_cast<float>(M_PI/2);
- break;
- case 8:
- angle = i_cur_angle - static_cast<float>(M_PI/2);
- break;
- case 9:
- angle = i_cur_angle + static_cast<float>(M_PI/2);
- distance /= 2;
- break;
- case 10:
- angle = i_cur_angle - static_cast<float>(M_PI/2);
- distance /= 2;
- break;
- case 11:
- angle = i_cur_angle + static_cast<float>(M_PI/4);
- distance /= 4;
- break;
- case 12:
- angle = i_cur_angle - static_cast<float>(M_PI/4);
- distance /= 4;
- break;
- case 13:
- angle = i_cur_angle + static_cast<float>(M_PI/2);
- distance /= 4;
- break;
- case 14:
- angle = i_cur_angle - static_cast<float>(M_PI/2);
- distance /= 4;
- break;
- case 15:
- angle = i_cur_angle + static_cast<float>(3*M_PI/4);
- distance /= 2;
- break;
- case 16:
- angle = i_cur_angle - static_cast<float>(3*M_PI/4);
- distance /= 2;
- break;
- case 17:
- angle = i_cur_angle + static_cast<float>(M_PI);
- distance /= 2;
- break;
- default:
- angle = 0.0f;
- distance = 0.0f;
- break;
- }
-
- temp_x = x + distance * std::cos(angle);
- temp_y = y + distance * std::sin(angle);
- Trinity::NormalizeMapCoord(temp_x);
- Trinity::NormalizeMapCoord(temp_y);
- if (owner.IsWithinLOS(temp_x, temp_y, z))
- {
- bool is_water_now = _map->IsInWater(x, y, z);
-
- if (is_water_now && _map->IsInWater(temp_x, temp_y, z))
- {
- x = temp_x;
- y = temp_y;
- return true;
- }
- float new_z = _map->GetHeight(owner.GetPhaseMask(), temp_x, temp_y, z, true);
-
- if (new_z <= INVALID_HEIGHT)
- continue;
-
- bool is_water_next = _map->IsInWater(temp_x, temp_y, new_z);
-
- if ((is_water_now && !is_water_next && !is_land_ok) || (!is_water_now && is_water_next && !is_water_ok))
- continue;
-
- if (!(new_z - z) || distance / fabs(new_z - z) > 1.0f)
- {
- float new_z_left = _map->GetHeight(owner.GetPhaseMask(), temp_x + 1.0f * std::cos(angle+static_cast<float>(M_PI/2)), temp_y + 1.0f * std::sin(angle+static_cast<float>(M_PI/2)), z, true);
- float new_z_right = _map->GetHeight(owner.GetPhaseMask(), temp_x + 1.0f * std::cos(angle-static_cast<float>(M_PI/2)), temp_y + 1.0f * std::sin(angle-static_cast<float>(M_PI/2)), z, true);
- if (fabs(new_z_left - new_z) < 1.2f && fabs(new_z_right - new_z) < 1.2f)
- {
- x = temp_x;
- y = temp_y;
- z = new_z;
- return true;
- }
- }
- }
- }
- i_to_distance_from_caster = 0.0f;
- i_nextCheckTime.Reset(urand(500, 1000));
- return false;
-}
-
-template<class T>
-bool FleeingMovementGenerator<T>::_setMoveData(T &owner)
-{
- float cur_dist_xyz = owner.GetDistance(i_caster_x, i_caster_y, i_caster_z);
-
- if (i_to_distance_from_caster > 0.0f)
- {
- if ((i_last_distance_from_caster > i_to_distance_from_caster && cur_dist_xyz < i_to_distance_from_caster) ||
- // if we reach lower distance
- (i_last_distance_from_caster > i_to_distance_from_caster && cur_dist_xyz > i_last_distance_from_caster) ||
- // if we can't be close
- (i_last_distance_from_caster < i_to_distance_from_caster && cur_dist_xyz > i_to_distance_from_caster) ||
- // if we reach bigger distance
- (cur_dist_xyz > MAX_QUIET_DISTANCE) || // if we are too far
- (i_last_distance_from_caster > MIN_QUIET_DISTANCE && cur_dist_xyz < MIN_QUIET_DISTANCE))
- // if we leave 'quiet zone'
- {
- // we are very far or too close, stopping
- i_to_distance_from_caster = 0.0f;
- i_nextCheckTime.Reset(urand(500, 1000));
- return false;
- }
+ dist_from_caster = fright->GetDistance(owner);
+ if (dist_from_caster > 0.2f)
+ angle_to_caster = fright->GetAngle(owner);
else
- {
- // now we are running, continue
- i_last_distance_from_caster = cur_dist_xyz;
- return true;
- }
- }
-
- float cur_dist;
- float angle_to_caster;
-
- if (Unit* fright = ObjectAccessor::GetUnit(owner, i_frightGUID))
- {
- cur_dist = fright->GetDistance(&owner);
- if (cur_dist < cur_dist_xyz)
- {
- i_caster_x = fright->GetPositionX();
- i_caster_y = fright->GetPositionY();
- i_caster_z = fright->GetPositionZ();
- angle_to_caster = fright->GetAngle(&owner);
- }
- else
- {
- cur_dist = cur_dist_xyz;
- angle_to_caster = owner.GetAngle(i_caster_x, i_caster_y) + static_cast<float>(M_PI);
- }
+ angle_to_caster = frand(0, 2 * static_cast<float>(M_PI));
}
else
{
- cur_dist = cur_dist_xyz;
- angle_to_caster = owner.GetAngle(i_caster_x, i_caster_y) + static_cast<float>(M_PI);
+ dist_from_caster = 0.0f;
+ angle_to_caster = frand(0, 2 * static_cast<float>(M_PI));
}
- // if we too close may use 'path-finding' else just stop
- i_only_forward = cur_dist >= MIN_QUIET_DISTANCE/3;
-
- //get angle and 'distance from caster' to run
- float angle;
-
- if (i_cur_angle == 0.0f && i_last_distance_from_caster == 0.0f) //just started, first time
+ float dist, angle;
+ if (dist_from_caster < MIN_QUIET_DISTANCE)
{
- angle = (float)rand_norm()*(1.0f - cur_dist/MIN_QUIET_DISTANCE) * static_cast<float>(M_PI/3) + (float)rand_norm()*static_cast<float>(M_PI*2/3);
- i_to_distance_from_caster = MIN_QUIET_DISTANCE;
- i_only_forward = true;
+ dist = frand(0.4f, 1.3f)*(MIN_QUIET_DISTANCE - dist_from_caster);
+ angle = angle_to_caster + frand(-static_cast<float>(M_PI)/8, static_cast<float>(M_PI)/8);
}
- else if (cur_dist < MIN_QUIET_DISTANCE)
+ else if (dist_from_caster > MAX_QUIET_DISTANCE)
{
- angle = static_cast<float>(M_PI/6) + (float)rand_norm()*static_cast<float>(M_PI*2/3);
- i_to_distance_from_caster = cur_dist*2/3 + (float)rand_norm()*(MIN_QUIET_DISTANCE - cur_dist*2/3);
+ dist = frand(0.4f, 1.0f)*(MAX_QUIET_DISTANCE - MIN_QUIET_DISTANCE);
+ angle = -angle_to_caster + frand(-static_cast<float>(M_PI)/4, static_cast<float>(M_PI)/4);
}
- else if (cur_dist > MAX_QUIET_DISTANCE)
+ else // we are inside quiet range
{
- angle = (float)rand_norm()*static_cast<float>(M_PI/3) + static_cast<float>(M_PI*2/3);
- i_to_distance_from_caster = MIN_QUIET_DISTANCE + 2.5f + (float)rand_norm()*(MAX_QUIET_DISTANCE - MIN_QUIET_DISTANCE - 2.5f);
+ dist = frand(0.6f, 1.2f)*(MAX_QUIET_DISTANCE - MIN_QUIET_DISTANCE);
+ angle = frand(0, 2*static_cast<float>(M_PI));
}
- else
- {
- angle = (float)rand_norm()*static_cast<float>(M_PI);
- i_to_distance_from_caster = MIN_QUIET_DISTANCE + 2.5f + (float)rand_norm()*(MAX_QUIET_DISTANCE - MIN_QUIET_DISTANCE - 2.5f);
- }
-
- int8 sign = (float)rand_norm() > 0.5f ? 1 : -1;
- i_cur_angle = sign*angle + angle_to_caster;
- // current distance
- i_last_distance_from_caster = cur_dist;
-
- return true;
+ Position pos;
+ owner->GetFirstCollisionPosition(pos, dist, angle);
+ x = pos.m_positionX;
+ y = pos.m_positionY;
+ z = pos.m_positionZ;
}
template<class T>
-void FleeingMovementGenerator<T>::DoInitialize(T &owner)
+void FleeingMovementGenerator<T>::DoInitialize(T* owner)
{
- if (!&owner)
+ if (!owner)
return;
- owner.SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_FLEEING);
- owner.AddUnitState(UNIT_STATE_FLEEING|UNIT_STATE_FLEEING_MOVE);
-
- _Init(owner);
-
- if (Unit* fright = ObjectAccessor::GetUnit(owner, i_frightGUID))
- {
- i_caster_x = fright->GetPositionX();
- i_caster_y = fright->GetPositionY();
- i_caster_z = fright->GetPositionZ();
- }
- else
- {
- i_caster_x = owner.GetPositionX();
- i_caster_y = owner.GetPositionY();
- i_caster_z = owner.GetPositionZ();
- }
-
- i_only_forward = true;
- i_cur_angle = 0.0f;
- i_last_distance_from_caster = 0.0f;
- i_to_distance_from_caster = 0.0f;
+ owner->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_FLEEING);
+ owner->AddUnitState(UNIT_STATE_FLEEING | UNIT_STATE_FLEEING_MOVE);
_setTargetLocation(owner);
}
template<>
-void FleeingMovementGenerator<Creature>::_Init(Creature &owner)
+void FleeingMovementGenerator<Player>::DoFinalize(Player* owner)
{
- if (!&owner)
- return;
-
- //owner.SetTargetGuid(ObjectGuid());
- is_water_ok = owner.canSwim();
- is_land_ok = owner.canWalk();
+ owner->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_FLEEING);
+ owner->ClearUnitState(UNIT_STATE_FLEEING | UNIT_STATE_FLEEING_MOVE);
+ owner->StopMoving();
}
template<>
-void FleeingMovementGenerator<Player>::_Init(Player &)
+void FleeingMovementGenerator<Creature>::DoFinalize(Creature* owner)
{
- is_water_ok = true;
- is_land_ok = true;
-}
-
-template<>
-void FleeingMovementGenerator<Player>::DoFinalize(Player &owner)
-{
- owner.RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_FLEEING);
- owner.ClearUnitState(UNIT_STATE_FLEEING|UNIT_STATE_FLEEING_MOVE);
- owner.StopMoving();
-}
-
-template<>
-void FleeingMovementGenerator<Creature>::DoFinalize(Creature &owner)
-{
- owner.RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_FLEEING);
- owner.ClearUnitState(UNIT_STATE_FLEEING|UNIT_STATE_FLEEING_MOVE);
- if (owner.getVictim())
- owner.SetTarget(owner.getVictim()->GetGUID());
+ owner->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_FLEEING);
+ owner->ClearUnitState(UNIT_STATE_FLEEING|UNIT_STATE_FLEEING_MOVE);
+ if (owner->getVictim())
+ owner->SetTarget(owner->getVictim()->GetGUID());
}
template<class T>
-void FleeingMovementGenerator<T>::DoReset(T &owner)
+void FleeingMovementGenerator<T>::DoReset(T* owner)
{
DoInitialize(owner);
}
template<class T>
-bool FleeingMovementGenerator<T>::DoUpdate(T &owner, uint32 time_diff)
+bool FleeingMovementGenerator<T>::DoUpdate(T* owner, uint32 time_diff)
{
- if (!&owner || !owner.isAlive())
+ if (!owner || !owner->isAlive())
return false;
- if (owner.HasUnitState(UNIT_STATE_ROOT | UNIT_STATE_STUNNED))
+
+ if (owner->HasUnitState(UNIT_STATE_ROOT | UNIT_STATE_STUNNED))
{
- owner.ClearUnitState(UNIT_STATE_FLEEING_MOVE);
+ owner->ClearUnitState(UNIT_STATE_FLEEING_MOVE);
return true;
}
i_nextCheckTime.Update(time_diff);
- if (i_nextCheckTime.Passed() && owner.movespline->Finalized())
+ if (i_nextCheckTime.Passed() && owner->movespline->Finalized())
_setTargetLocation(owner);
return true;
}
-template void FleeingMovementGenerator<Player>::DoInitialize(Player &);
-template void FleeingMovementGenerator<Creature>::DoInitialize(Creature &);
-template bool FleeingMovementGenerator<Player>::_setMoveData(Player &);
-template bool FleeingMovementGenerator<Creature>::_setMoveData(Creature &);
-template bool FleeingMovementGenerator<Player>::_getPoint(Player &, float &, float &, float &);
-template bool FleeingMovementGenerator<Creature>::_getPoint(Creature &, float &, float &, float &);
-template void FleeingMovementGenerator<Player>::_setTargetLocation(Player &);
-template void FleeingMovementGenerator<Creature>::_setTargetLocation(Creature &);
-template void FleeingMovementGenerator<Player>::DoReset(Player &);
-template void FleeingMovementGenerator<Creature>::DoReset(Creature &);
-template bool FleeingMovementGenerator<Player>::DoUpdate(Player &, uint32);
-template bool FleeingMovementGenerator<Creature>::DoUpdate(Creature &, uint32);
-
-void TimedFleeingMovementGenerator::Finalize(Unit &owner)
+template void FleeingMovementGenerator<Player>::DoInitialize(Player*);
+template void FleeingMovementGenerator<Creature>::DoInitialize(Creature*);
+template void FleeingMovementGenerator<Player>::_getPoint(Player*, float&, float&, float&);
+template void FleeingMovementGenerator<Creature>::_getPoint(Creature*, float&, float&, float&);
+template void FleeingMovementGenerator<Player>::_setTargetLocation(Player*);
+template void FleeingMovementGenerator<Creature>::_setTargetLocation(Creature*);
+template void FleeingMovementGenerator<Player>::DoReset(Player*);
+template void FleeingMovementGenerator<Creature>::DoReset(Creature*);
+template bool FleeingMovementGenerator<Player>::DoUpdate(Player*, uint32);
+template bool FleeingMovementGenerator<Creature>::DoUpdate(Creature*, uint32);
+
+void TimedFleeingMovementGenerator::Finalize(Unit* owner)
{
- owner.RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_FLEEING);
- owner.ClearUnitState(UNIT_STATE_FLEEING|UNIT_STATE_FLEEING_MOVE);
- if (Unit* victim = owner.getVictim())
+ owner->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_FLEEING);
+ owner->ClearUnitState(UNIT_STATE_FLEEING|UNIT_STATE_FLEEING_MOVE);
+ if (Unit* victim = owner->getVictim())
{
- if (owner.isAlive())
+ if (owner->isAlive())
{
- owner.AttackStop();
- owner.ToCreature()->AI()->AttackStart(victim);
+ owner->AttackStop();
+ owner->ToCreature()->AI()->AttackStart(victim);
}
}
}
-bool TimedFleeingMovementGenerator::Update(Unit & owner, uint32 time_diff)
+bool TimedFleeingMovementGenerator::Update(Unit* owner, uint32 time_diff)
{
- if (!owner.isAlive())
+ if (!owner->isAlive())
return false;
- if (owner.HasUnitState(UNIT_STATE_ROOT | UNIT_STATE_STUNNED))
+ if (owner->HasUnitState(UNIT_STATE_ROOT | UNIT_STATE_STUNNED))
{
- owner.ClearUnitState(UNIT_STATE_FLEEING_MOVE);
+ owner->ClearUnitState(UNIT_STATE_FLEEING_MOVE);
return true;
}
@@ -418,4 +198,3 @@ bool TimedFleeingMovementGenerator::Update(Unit & owner, uint32 time_diff)
// This is done instead of casting Unit& to Creature& and call parent method, then we can use Unit directly
return MovementGeneratorMedium< Creature, FleeingMovementGenerator<Creature> >::Update(owner, time_diff);
}
-
diff --git a/src/server/game/Movement/MovementGenerators/FleeingMovementGenerator.h b/src/server/game/Movement/MovementGenerators/FleeingMovementGenerator.h
index 8ad165c8206..33a7c705564 100755
--- a/src/server/game/Movement/MovementGenerators/FleeingMovementGenerator.h
+++ b/src/server/game/Movement/MovementGenerators/FleeingMovementGenerator.h
@@ -27,29 +27,17 @@ class FleeingMovementGenerator : public MovementGeneratorMedium< T, FleeingMovem
public:
FleeingMovementGenerator(uint64 fright) : i_frightGUID(fright), i_nextCheckTime(0) {}
- void DoInitialize(T &);
- void DoFinalize(T &);
- void DoReset(T &);
- bool DoUpdate(T &, uint32);
+ void DoInitialize(T*);
+ void DoFinalize(T*);
+ void DoReset(T*);
+ bool DoUpdate(T*, uint32);
MovementGeneratorType GetMovementGeneratorType() { return FLEEING_MOTION_TYPE; }
private:
- void _setTargetLocation(T &owner);
- bool _getPoint(T &owner, float &x, float &y, float &z);
- bool _setMoveData(T &owner);
- void _Init(T &);
+ void _setTargetLocation(T*);
+ void _getPoint(T*, float &x, float &y, float &z);
- bool is_water_ok :1;
- bool is_land_ok :1;
- bool i_only_forward:1;
-
- float i_caster_x;
- float i_caster_y;
- float i_caster_z;
- float i_last_distance_from_caster;
- float i_to_distance_from_caster;
- float i_cur_angle;
uint64 i_frightGUID;
TimeTracker i_nextCheckTime;
};
@@ -62,12 +50,11 @@ class TimedFleeingMovementGenerator : public FleeingMovementGenerator<Creature>
i_totalFleeTime(time) {}
MovementGeneratorType GetMovementGeneratorType() { return TIMED_FLEEING_MOTION_TYPE; }
- bool Update(Unit &, uint32);
- void Finalize(Unit &);
+ bool Update(Unit*, uint32);
+ void Finalize(Unit*);
private:
TimeTracker i_totalFleeTime;
};
#endif
-
diff --git a/src/server/game/Movement/MovementGenerators/HomeMovementGenerator.cpp b/src/server/game/Movement/MovementGenerators/HomeMovementGenerator.cpp
index 4f0a620c303..a94ef5d4f87 100644
--- a/src/server/game/Movement/MovementGenerators/HomeMovementGenerator.cpp
+++ b/src/server/game/Movement/MovementGenerators/HomeMovementGenerator.cpp
@@ -23,49 +23,50 @@
#include "MoveSplineInit.h"
#include "MoveSpline.h"
-void HomeMovementGenerator<Creature>::DoInitialize(Creature & owner)
+void HomeMovementGenerator<Creature>::DoInitialize(Creature* owner)
{
_setTargetLocation(owner);
}
-void HomeMovementGenerator<Creature>::DoReset(Creature &)
+void HomeMovementGenerator<Creature>::DoFinalize(Creature* owner)
+{
+ if (arrived)
+ {
+ owner->ClearUnitState(UNIT_STATE_EVADE);
+ owner->SetWalk(true);
+ owner->LoadCreaturesAddon(true);
+ owner->AI()->JustReachedHome();
+ }
+}
+
+void HomeMovementGenerator<Creature>::DoReset(Creature*)
{
}
-void HomeMovementGenerator<Creature>::_setTargetLocation(Creature & owner)
+void HomeMovementGenerator<Creature>::_setTargetLocation(Creature* owner)
{
- if (owner.HasUnitState(UNIT_STATE_ROOT | UNIT_STATE_STUNNED | UNIT_STATE_DISTRACTED))
+ if (owner->HasUnitState(UNIT_STATE_ROOT | UNIT_STATE_STUNNED | UNIT_STATE_DISTRACTED))
return;
Movement::MoveSplineInit init(owner);
float x, y, z, o;
// at apply we can select more nice return points base at current movegen
- //if (owner.GetMotionMaster()->empty() || !owner.GetMotionMaster()->top()->GetResetPosition(owner, x, y, z))
- //{
- owner.GetHomePosition(x, y, z, o);
- init.SetFacing(o);
- //}
+ if (owner->GetMotionMaster()->empty() || !owner->GetMotionMaster()->top()->GetResetPosition(owner, x, y, z))
+ {
+ owner->GetHomePosition(x, y, z, o);
+ init.SetFacing(o);
+ }
init.MoveTo(x, y, z);
init.SetWalk(false);
init.Launch();
arrived = false;
- owner.ClearUnitState(uint32(UNIT_STATE_ALL_STATE & ~UNIT_STATE_EVADE));
-}
-bool HomeMovementGenerator<Creature>::DoUpdate(Creature &owner, const uint32 /*time_diff*/)
-{
- arrived = owner.movespline->Finalized();
- return !arrived;
+ owner->ClearUnitState(uint32(UNIT_STATE_ALL_STATE & ~UNIT_STATE_EVADE));
}
-void HomeMovementGenerator<Creature>::DoFinalize(Creature& owner)
+bool HomeMovementGenerator<Creature>::DoUpdate(Creature* owner, const uint32 /*time_diff*/)
{
- if (arrived)
- {
- owner.ClearUnitState(UNIT_STATE_EVADE);
- owner.SetWalk(true);
- owner.LoadCreaturesAddon(true);
- owner.AI()->JustReachedHome();
- }
+ arrived = owner->movespline->Finalized();
+ return !arrived;
}
diff --git a/src/server/game/Movement/MovementGenerators/HomeMovementGenerator.h b/src/server/game/Movement/MovementGenerators/HomeMovementGenerator.h
index c93241b82db..3d6c6ab18c9 100644
--- a/src/server/game/Movement/MovementGenerators/HomeMovementGenerator.h
+++ b/src/server/game/Movement/MovementGenerators/HomeMovementGenerator.h
@@ -34,15 +34,14 @@ class HomeMovementGenerator<Creature> : public MovementGeneratorMedium< Creature
HomeMovementGenerator() : arrived(false) {}
~HomeMovementGenerator() {}
- void DoInitialize(Creature &);
- void DoFinalize(Creature &);
- void DoReset(Creature &);
- bool DoUpdate(Creature &, const uint32);
+ void DoInitialize(Creature*);
+ void DoFinalize(Creature*);
+ void DoReset(Creature*);
+ bool DoUpdate(Creature*, const uint32);
MovementGeneratorType GetMovementGeneratorType() { return HOME_MOTION_TYPE; }
private:
- void _setTargetLocation(Creature &);
+ void _setTargetLocation(Creature*);
bool arrived;
};
#endif
-
diff --git a/src/server/game/Movement/MovementGenerators/IdleMovementGenerator.cpp b/src/server/game/Movement/MovementGenerators/IdleMovementGenerator.cpp
index c952ad9ba94..81442570940 100755
--- a/src/server/game/Movement/MovementGenerators/IdleMovementGenerator.cpp
+++ b/src/server/game/Movement/MovementGenerators/IdleMovementGenerator.cpp
@@ -24,33 +24,33 @@ IdleMovementGenerator si_idleMovement;
// StopMoving is needed to make unit stop if its last movement generator expires
// But it should not be sent otherwise there are many redundent packets
-void IdleMovementGenerator::Initialize(Unit &owner)
+void IdleMovementGenerator::Initialize(Unit* owner)
{
Reset(owner);
}
-void IdleMovementGenerator::Reset(Unit& owner)
+void IdleMovementGenerator::Reset(Unit* owner)
{
- if (!owner.IsStopped())
- owner.StopMoving();
+ if (!owner->IsStopped())
+ owner->StopMoving();
}
-void RotateMovementGenerator::Initialize(Unit& owner)
+void RotateMovementGenerator::Initialize(Unit* owner)
{
- if (!owner.IsStopped())
- owner.StopMoving();
+ if (!owner->IsStopped())
+ owner->StopMoving();
- if (owner.getVictim())
- owner.SetInFront(owner.getVictim());
+ if (owner->getVictim())
+ owner->SetInFront(owner->getVictim());
- owner.AddUnitState(UNIT_STATE_ROTATING);
+ owner->AddUnitState(UNIT_STATE_ROTATING);
- owner.AttackStop();
+ owner->AttackStop();
}
-bool RotateMovementGenerator::Update(Unit& owner, uint32 diff)
+bool RotateMovementGenerator::Update(Unit* owner, uint32 diff)
{
- float angle = owner.GetOrientation();
+ float angle = owner->GetOrientation();
if (m_direction == ROTATE_DIRECTION_LEFT)
{
angle += (float)diff * static_cast<float>(M_PI * 2) / m_maxDuration;
@@ -61,8 +61,8 @@ bool RotateMovementGenerator::Update(Unit& owner, uint32 diff)
angle -= (float)diff * static_cast<float>(M_PI * 2) / m_maxDuration;
while (angle < 0) angle += static_cast<float>(M_PI * 2);
}
- owner.SetOrientation(angle);
- owner.SendMovementFlagUpdate(); // this is a hack. we do not have anything correct to send in the beginning
+ owner->SetOrientation(angle);
+ owner->SendMovementFlagUpdate(); // this is a hack. we do not have anything correct to send in the beginning
if (m_duration > diff)
m_duration -= diff;
@@ -72,24 +72,24 @@ bool RotateMovementGenerator::Update(Unit& owner, uint32 diff)
return true;
}
-void RotateMovementGenerator::Finalize(Unit &unit)
+void RotateMovementGenerator::Finalize(Unit* unit)
{
- unit.ClearUnitState(UNIT_STATE_ROTATING);
- if (unit.GetTypeId() == TYPEID_UNIT)
- unit.ToCreature()->AI()->MovementInform(ROTATE_MOTION_TYPE, 0);
+ unit->ClearUnitState(UNIT_STATE_ROTATING);
+ if (unit->GetTypeId() == TYPEID_UNIT)
+ unit->ToCreature()->AI()->MovementInform(ROTATE_MOTION_TYPE, 0);
}
-void DistractMovementGenerator::Initialize(Unit& owner)
+void DistractMovementGenerator::Initialize(Unit* owner)
{
- owner.AddUnitState(UNIT_STATE_DISTRACTED);
+ owner->AddUnitState(UNIT_STATE_DISTRACTED);
}
-void DistractMovementGenerator::Finalize(Unit& owner)
+void DistractMovementGenerator::Finalize(Unit* owner)
{
- owner.ClearUnitState(UNIT_STATE_DISTRACTED);
+ owner->ClearUnitState(UNIT_STATE_DISTRACTED);
}
-bool DistractMovementGenerator::Update(Unit& /*owner*/, uint32 time_diff)
+bool DistractMovementGenerator::Update(Unit* /*owner*/, uint32 time_diff)
{
if (time_diff > m_timer)
return false;
@@ -98,9 +98,8 @@ bool DistractMovementGenerator::Update(Unit& /*owner*/, uint32 time_diff)
return true;
}
-void AssistanceDistractMovementGenerator::Finalize(Unit &unit)
+void AssistanceDistractMovementGenerator::Finalize(Unit* unit)
{
- unit.ClearUnitState(UNIT_STATE_DISTRACTED);
- unit.ToCreature()->SetReactState(REACT_AGGRESSIVE);
+ unit->ClearUnitState(UNIT_STATE_DISTRACTED);
+ unit->ToCreature()->SetReactState(REACT_AGGRESSIVE);
}
-
diff --git a/src/server/game/Movement/MovementGenerators/IdleMovementGenerator.h b/src/server/game/Movement/MovementGenerators/IdleMovementGenerator.h
index bbcc2413cae..0043891db2c 100644..100755
--- a/src/server/game/Movement/MovementGenerators/IdleMovementGenerator.h
+++ b/src/server/game/Movement/MovementGenerators/IdleMovementGenerator.h
@@ -25,10 +25,10 @@ class IdleMovementGenerator : public MovementGenerator
{
public:
- void Initialize(Unit &);
- void Finalize(Unit &) { }
- void Reset(Unit &);
- bool Update(Unit &, uint32) { return true; }
+ void Initialize(Unit*);
+ void Finalize(Unit*) { }
+ void Reset(Unit*);
+ bool Update(Unit*, uint32) { return true; }
MovementGeneratorType GetMovementGeneratorType() { return IDLE_MOTION_TYPE; }
};
@@ -39,10 +39,10 @@ class RotateMovementGenerator : public MovementGenerator
public:
explicit RotateMovementGenerator(uint32 time, RotateDirection direction) : m_duration(time), m_maxDuration(time), m_direction(direction) {}
- void Initialize(Unit& owner);
- void Finalize(Unit& owner);
- void Reset(Unit& owner) { Initialize(owner); }
- bool Update(Unit& owner, uint32 time_diff);
+ void Initialize(Unit*);
+ void Finalize(Unit*);
+ void Reset(Unit* owner) { Initialize(owner); }
+ bool Update(Unit*, uint32);
MovementGeneratorType GetMovementGeneratorType() { return ROTATE_MOTION_TYPE; }
private:
@@ -55,10 +55,10 @@ class DistractMovementGenerator : public MovementGenerator
public:
explicit DistractMovementGenerator(uint32 timer) : m_timer(timer) {}
- void Initialize(Unit& owner);
- void Finalize(Unit& owner);
- void Reset(Unit& owner) { Initialize(owner); }
- bool Update(Unit& owner, uint32 time_diff);
+ void Initialize(Unit*);
+ void Finalize(Unit*);
+ void Reset(Unit* owner) { Initialize(owner); }
+ bool Update(Unit*, uint32);
MovementGeneratorType GetMovementGeneratorType() { return DISTRACT_MOTION_TYPE; }
private:
@@ -72,8 +72,7 @@ class AssistanceDistractMovementGenerator : public DistractMovementGenerator
DistractMovementGenerator(timer) {}
MovementGeneratorType GetMovementGeneratorType() { return ASSISTANCE_DISTRACT_MOTION_TYPE; }
- void Finalize(Unit& unit);
+ void Finalize(Unit*);
};
#endif
-
diff --git a/src/server/game/Movement/MovementGenerators/PointMovementGenerator.cpp b/src/server/game/Movement/MovementGenerators/PointMovementGenerator.cpp
index 68f62d28899..06b2315f294 100644..100755
--- a/src/server/game/Movement/MovementGenerators/PointMovementGenerator.cpp
+++ b/src/server/game/Movement/MovementGenerators/PointMovementGenerator.cpp
@@ -27,111 +27,115 @@
//----- Point Movement Generator
template<class T>
-void PointMovementGenerator<T>::DoInitialize(T &unit)
+void PointMovementGenerator<T>::DoInitialize(T* unit)
{
- if (!unit.IsStopped())
- unit.StopMoving();
+ if (!unit->IsStopped())
+ unit->StopMoving();
+
+ unit->AddUnitState(UNIT_STATE_ROAMING|UNIT_STATE_ROAMING_MOVE);
+
+ if (id == EVENT_CHARGE)
+ return;
- unit.AddUnitState(UNIT_STATE_ROAMING|UNIT_STATE_ROAMING_MOVE);
- i_recalculateSpeed = false;
Movement::MoveSplineInit init(unit);
- init.MoveTo(i_x, i_y, i_z);
+ init.MoveTo(i_x, i_y, i_z, m_generatePath);
if (speed > 0.0f)
init.SetVelocity(speed);
init.Launch();
}
template<class T>
-bool PointMovementGenerator<T>::DoUpdate(T &unit, uint32 /*diff*/)
+bool PointMovementGenerator<T>::DoUpdate(T* unit, uint32 /*diff*/)
{
- if (!&unit)
+ if (!unit)
return false;
- if (unit.HasUnitState(UNIT_STATE_ROOT | UNIT_STATE_STUNNED))
+ if (unit->HasUnitState(UNIT_STATE_ROOT | UNIT_STATE_STUNNED))
{
- unit.ClearUnitState(UNIT_STATE_ROAMING_MOVE);
+ unit->ClearUnitState(UNIT_STATE_ROAMING_MOVE);
return true;
}
- unit.AddUnitState(UNIT_STATE_ROAMING_MOVE);
+ unit->AddUnitState(UNIT_STATE_ROAMING_MOVE);
- if (i_recalculateSpeed && !unit.movespline->Finalized())
+ if (id != EVENT_CHARGE && i_recalculateSpeed && !unit->movespline->Finalized())
{
i_recalculateSpeed = false;
Movement::MoveSplineInit init(unit);
- init.MoveTo(i_x, i_y, i_z);
+ init.MoveTo(i_x, i_y, i_z, m_generatePath);
if (speed > 0.0f) // Default value for point motion type is 0.0, if 0.0 spline will use GetSpeed on unit
init.SetVelocity(speed);
init.Launch();
}
- return !unit.movespline->Finalized();
+ return !unit->movespline->Finalized();
}
template<class T>
-void PointMovementGenerator<T>::DoFinalize(T &unit)
+void PointMovementGenerator<T>::DoFinalize(T* unit)
{
- unit.ClearUnitState(UNIT_STATE_ROAMING|UNIT_STATE_ROAMING_MOVE);
+ if (unit->HasUnitState(UNIT_STATE_CHARGING))
+ unit->ClearUnitState(UNIT_STATE_ROAMING | UNIT_STATE_ROAMING_MOVE);
- if (unit.movespline->Finalized())
+ if (unit->movespline->Finalized())
MovementInform(unit);
}
template<class T>
-void PointMovementGenerator<T>::DoReset(T &unit)
+void PointMovementGenerator<T>::DoReset(T* unit)
{
- if (!unit.IsStopped())
- unit.StopMoving();
+ if (!unit->IsStopped())
+ unit->StopMoving();
- unit.AddUnitState(UNIT_STATE_ROAMING|UNIT_STATE_ROAMING_MOVE);
+ unit->AddUnitState(UNIT_STATE_ROAMING|UNIT_STATE_ROAMING_MOVE);
}
template<class T>
-void PointMovementGenerator<T>::MovementInform(T & /*unit*/)
+void PointMovementGenerator<T>::MovementInform(T* /*unit*/)
{
}
-template <> void PointMovementGenerator<Creature>::MovementInform(Creature &unit)
+template <> void PointMovementGenerator<Creature>::MovementInform(Creature* unit)
{
- if (unit.AI())
- unit.AI()->MovementInform(POINT_MOTION_TYPE, id);
+ if (unit->AI())
+ unit->AI()->MovementInform(POINT_MOTION_TYPE, id);
}
-template void PointMovementGenerator<Player>::DoInitialize(Player&);
-template void PointMovementGenerator<Creature>::DoInitialize(Creature&);
-template void PointMovementGenerator<Player>::DoFinalize(Player&);
-template void PointMovementGenerator<Creature>::DoFinalize(Creature&);
-template void PointMovementGenerator<Player>::DoReset(Player&);
-template void PointMovementGenerator<Creature>::DoReset(Creature&);
-template bool PointMovementGenerator<Player>::DoUpdate(Player &, uint32);
-template bool PointMovementGenerator<Creature>::DoUpdate(Creature&, uint32);
+template void PointMovementGenerator<Player>::DoInitialize(Player*);
+template void PointMovementGenerator<Creature>::DoInitialize(Creature*);
+template void PointMovementGenerator<Player>::DoFinalize(Player*);
+template void PointMovementGenerator<Creature>::DoFinalize(Creature*);
+template void PointMovementGenerator<Player>::DoReset(Player*);
+template void PointMovementGenerator<Creature>::DoReset(Creature*);
+template bool PointMovementGenerator<Player>::DoUpdate(Player*, uint32);
+template bool PointMovementGenerator<Creature>::DoUpdate(Creature*, uint32);
-void AssistanceMovementGenerator::Finalize(Unit &unit)
+void AssistanceMovementGenerator::Finalize(Unit* unit)
{
- unit.ToCreature()->SetNoCallAssistance(false);
- unit.ToCreature()->CallAssistance();
- if (unit.isAlive())
- unit.GetMotionMaster()->MoveSeekAssistanceDistract(sWorld->getIntConfig(CONFIG_CREATURE_FAMILY_ASSISTANCE_DELAY));
+ unit->ToCreature()->SetNoCallAssistance(false);
+ unit->ToCreature()->CallAssistance();
+ if (unit->isAlive())
+ unit->GetMotionMaster()->MoveSeekAssistanceDistract(sWorld->getIntConfig(CONFIG_CREATURE_FAMILY_ASSISTANCE_DELAY));
}
-bool EffectMovementGenerator::Update(Unit &unit, uint32)
+bool EffectMovementGenerator::Update(Unit* unit, uint32)
{
- return !unit.movespline->Finalized();
+ return !unit->movespline->Finalized();
}
-void EffectMovementGenerator::Finalize(Unit &unit)
+void EffectMovementGenerator::Finalize(Unit* unit)
{
- if (unit.GetTypeId() != TYPEID_UNIT)
+ if (unit->GetTypeId() != TYPEID_UNIT)
return;
- if (((Creature&)unit).AI())
- ((Creature&)unit).AI()->MovementInform(EFFECT_MOTION_TYPE, m_Id);
+ if (unit->ToCreature()->AI())
+ unit->ToCreature()->AI()->MovementInform(EFFECT_MOTION_TYPE, m_Id);
// Need restore previous movement since we have no proper states system
- //if (unit.isAlive() && !unit.HasUnitState(UNIT_STATE_CONFUSED|UNIT_STATE_FLEEING))
- //{
- // if (Unit* victim = unit.getVictim())
- // unit.GetMotionMaster()->MoveChase(victim);
- // else
- // unit.GetMotionMaster()->Initialize();
- //}
+ if (unit->isAlive() && !unit->HasUnitState(UNIT_STATE_CONFUSED | UNIT_STATE_FLEEING))
+ {
+ if (Unit* victim = unit->getVictim())
+ unit->GetMotionMaster()->MoveChase(victim);
+ else
+ unit->GetMotionMaster()->Initialize();
+ }
}
diff --git a/src/server/game/Movement/MovementGenerators/PointMovementGenerator.h b/src/server/game/Movement/MovementGenerators/PointMovementGenerator.h
index f9a51d0c5f3..421736ca4ec 100644
--- a/src/server/game/Movement/MovementGenerators/PointMovementGenerator.h
+++ b/src/server/game/Movement/MovementGenerators/PointMovementGenerator.h
@@ -26,25 +26,26 @@ template<class T>
class PointMovementGenerator : public MovementGeneratorMedium< T, PointMovementGenerator<T> >
{
public:
- PointMovementGenerator(uint32 _id, float _x, float _y, float _z, float _speed = 0.0f) : id(_id),
- i_x(_x), i_y(_y), i_z(_z), speed(_speed) {}
+ PointMovementGenerator(uint32 _id, float _x, float _y, float _z, bool _generatePath, float _speed = 0.0f) : id(_id),
+ i_x(_x), i_y(_y), i_z(_z), speed(_speed), m_generatePath(_generatePath), i_recalculateSpeed(false) {}
- void DoInitialize(T &);
- void DoFinalize(T &);
- void DoReset(T &);
- bool DoUpdate(T &, uint32);
+ void DoInitialize(T*);
+ void DoFinalize(T*);
+ void DoReset(T*);
+ bool DoUpdate(T*, uint32);
- void MovementInform(T &);
+ void MovementInform(T*);
void unitSpeedChanged() { i_recalculateSpeed = true; }
MovementGeneratorType GetMovementGeneratorType() { return POINT_MOTION_TYPE; }
- bool GetDestination(float& x, float& y, float& z) const { x=i_x; y=i_y; z=i_z; return true; }
+ void GetDestination(float& x, float& y, float& z) const { x = i_x; y = i_y; z = i_z; }
private:
uint32 id;
float i_x, i_y, i_z;
float speed;
+ bool m_generatePath;
bool i_recalculateSpeed;
};
@@ -52,10 +53,10 @@ class AssistanceMovementGenerator : public PointMovementGenerator<Creature>
{
public:
AssistanceMovementGenerator(float _x, float _y, float _z) :
- PointMovementGenerator<Creature>(0, _x, _y, _z) {}
+ PointMovementGenerator<Creature>(0, _x, _y, _z, true) {}
MovementGeneratorType GetMovementGeneratorType() { return ASSISTANCE_MOTION_TYPE; }
- void Finalize(Unit &);
+ void Finalize(Unit*);
};
// Does almost nothing - just doesn't allows previous movegen interrupt current effect.
@@ -63,14 +64,13 @@ class EffectMovementGenerator : public MovementGenerator
{
public:
explicit EffectMovementGenerator(uint32 Id) : m_Id(Id) {}
- void Initialize(Unit &) {}
- void Finalize(Unit &unit);
- void Reset(Unit &) {}
- bool Update(Unit &u, uint32);
+ void Initialize(Unit*) {}
+ void Finalize(Unit*);
+ void Reset(Unit*) {}
+ bool Update(Unit*, uint32);
MovementGeneratorType GetMovementGeneratorType() { return EFFECT_MOTION_TYPE; }
private:
uint32 m_Id;
};
#endif
-
diff --git a/src/server/game/Movement/MovementGenerators/RandomMovementGenerator.cpp b/src/server/game/Movement/MovementGenerators/RandomMovementGenerator.cpp
index 94819e87213..67136792fa6 100644
--- a/src/server/game/Movement/MovementGenerators/RandomMovementGenerator.cpp
+++ b/src/server/game/Movement/MovementGenerators/RandomMovementGenerator.cpp
@@ -33,16 +33,16 @@
#endif
template<>
-void RandomMovementGenerator<Creature>::_setRandomLocation(Creature& creature)
+void RandomMovementGenerator<Creature>::_setRandomLocation(Creature* creature)
{
float respX, respY, respZ, respO, destX, destY, destZ, travelDistZ;
- creature.GetHomePosition(respX, respY, respZ, respO);
- Map const* map = creature.GetBaseMap();
+ creature->GetHomePosition(respX, respY, respZ, respO);
+ Map const* map = creature->GetBaseMap();
// For 2D/3D system selection
//bool is_land_ok = creature.CanWalk(); // not used?
//bool is_water_ok = creature.CanSwim(); // not used?
- bool is_air_ok = creature.CanFly();
+ bool is_air_ok = creature->CanFly();
const float angle = float(rand_norm()) * static_cast<float>(M_PI*2.0f);
const float range = float(rand_norm()) * wander_distance;
@@ -77,17 +77,17 @@ void RandomMovementGenerator<Creature>::_setRandomLocation(Creature& creature)
// The fastest way to get an accurate result 90% of the time.
// Better result can be obtained like 99% accuracy with a ray light, but the cost is too high and the code is too long.
- destZ = map->GetHeight(creature.GetPhaseMask(), destX, destY, respZ+travelDistZ-2.0f, false);
+ destZ = map->GetHeight(creature->GetPhaseMask(), destX, destY, respZ+travelDistZ-2.0f, false);
if (fabs(destZ - respZ) > travelDistZ) // Map check
{
// Vmap Horizontal or above
- destZ = map->GetHeight(creature.GetPhaseMask(), destX, destY, respZ - 2.0f, true);
+ destZ = map->GetHeight(creature->GetPhaseMask(), destX, destY, respZ - 2.0f, true);
if (fabs(destZ - respZ) > travelDistZ)
{
// Vmap Higher
- destZ = map->GetHeight(creature.GetPhaseMask(), destX, destY, respZ+travelDistZ-2.0f, true);
+ destZ = map->GetHeight(creature->GetPhaseMask(), destX, destY, respZ+travelDistZ-2.0f, true);
// let's forget this bad coords where a z cannot be find and retry at next tick
if (fabs(destZ - respZ) > travelDistZ)
@@ -101,7 +101,7 @@ void RandomMovementGenerator<Creature>::_setRandomLocation(Creature& creature)
else
i_nextMoveTime.Reset(urand(500, 10000));
- creature.AddUnitState(UNIT_STATE_ROAMING_MOVE);
+ creature->AddUnitState(UNIT_STATE_ROAMING_MOVE);
Movement::MoveSplineInit init(creature);
init.MoveTo(destX, destY, destZ);
@@ -109,47 +109,47 @@ void RandomMovementGenerator<Creature>::_setRandomLocation(Creature& creature)
init.Launch();
//Call for creature group update
- if (creature.GetFormation() && creature.GetFormation()->getLeader() == &creature)
- creature.GetFormation()->LeaderMoveTo(destX, destY, destZ);
+ if (creature->GetFormation() && creature->GetFormation()->getLeader() == creature)
+ creature->GetFormation()->LeaderMoveTo(destX, destY, destZ);
}
template<>
-void RandomMovementGenerator<Creature>::DoInitialize(Creature &creature)
+void RandomMovementGenerator<Creature>::DoInitialize(Creature* creature)
{
- if (!creature.isAlive())
+ if (!creature->isAlive())
return;
if (!wander_distance)
- wander_distance = creature.GetRespawnRadius();
+ wander_distance = creature->GetRespawnRadius();
- creature.AddUnitState(UNIT_STATE_ROAMING|UNIT_STATE_ROAMING_MOVE);
+ creature->AddUnitState(UNIT_STATE_ROAMING | UNIT_STATE_ROAMING_MOVE);
_setRandomLocation(creature);
}
template<>
-void RandomMovementGenerator<Creature>::DoReset(Creature &creature)
+void RandomMovementGenerator<Creature>::DoReset(Creature* creature)
{
DoInitialize(creature);
}
template<>
-void RandomMovementGenerator<Creature>::DoFinalize(Creature &creature)
+void RandomMovementGenerator<Creature>::DoFinalize(Creature* creature)
{
- creature.ClearUnitState(UNIT_STATE_ROAMING|UNIT_STATE_ROAMING_MOVE);
- creature.SetWalk(false);
+ creature->ClearUnitState(UNIT_STATE_ROAMING|UNIT_STATE_ROAMING_MOVE);
+ creature->SetWalk(false);
}
template<>
-bool RandomMovementGenerator<Creature>::DoUpdate(Creature &creature, const uint32 diff)
+bool RandomMovementGenerator<Creature>::DoUpdate(Creature* creature, const uint32 diff)
{
- if (creature.HasUnitState(UNIT_STATE_ROOT | UNIT_STATE_STUNNED | UNIT_STATE_DISTRACTED))
+ if (creature->HasUnitState(UNIT_STATE_ROOT | UNIT_STATE_STUNNED | UNIT_STATE_DISTRACTED))
{
i_nextMoveTime.Reset(0); // Expire the timer
- creature.ClearUnitState(UNIT_STATE_ROAMING_MOVE);
+ creature->ClearUnitState(UNIT_STATE_ROAMING_MOVE);
return true;
}
- if (creature.movespline->Finalized())
+ if (creature->movespline->Finalized())
{
i_nextMoveTime.Update(diff);
if (i_nextMoveTime.Passed())
@@ -159,14 +159,14 @@ bool RandomMovementGenerator<Creature>::DoUpdate(Creature &creature, const uint3
}
template<>
-bool RandomMovementGenerator<Creature>::GetResetPosition(Creature &creature, float& x, float& y, float& z)
+bool RandomMovementGenerator<Creature>::GetResetPos(Creature* creature, float& x, float& y, float& z)
{
float radius;
- creature.GetRespawnPosition(x, y, z, NULL, &radius);
+ creature->GetRespawnPosition(x, y, z, NULL, &radius);
// use current if in range
if (creature.IsWithinDist2d(x, y, radius))
- creature.GetPosition(x, y, z);
+ creature->GetPosition(x, y, z);
return true;
}
diff --git a/src/server/game/Movement/MovementGenerators/RandomMovementGenerator.h b/src/server/game/Movement/MovementGenerators/RandomMovementGenerator.h
index 3e74753bc91..a6159e995fe 100644
--- a/src/server/game/Movement/MovementGenerators/RandomMovementGenerator.h
+++ b/src/server/game/Movement/MovementGenerators/RandomMovementGenerator.h
@@ -27,12 +27,12 @@ class RandomMovementGenerator : public MovementGeneratorMedium< T, RandomMovemen
public:
RandomMovementGenerator(float spawn_dist = 0.0f) : i_nextMoveTime(0), wander_distance(spawn_dist) {}
- void _setRandomLocation(T &);
- void DoInitialize(T &);
- void DoFinalize(T &);
- void DoReset(T &);
- bool DoUpdate(T &, const uint32);
- bool GetResetPosition(T&, float& x, float& y, float& z);
+ void _setRandomLocation(T*);
+ void DoInitialize(T*);
+ void DoFinalize(T*);
+ void DoReset(T*);
+ bool DoUpdate(T*, const uint32);
+ bool GetResetPos(T*, float& x, float& y, float& z);
MovementGeneratorType GetMovementGeneratorType() { return RANDOM_MOTION_TYPE; }
private:
TimeTrackerSmall i_nextMoveTime;
@@ -41,4 +41,3 @@ class RandomMovementGenerator : public MovementGeneratorMedium< T, RandomMovemen
float wander_distance;
};
#endif
-
diff --git a/src/server/game/Movement/MovementGenerators/TargetedMovementGenerator.cpp b/src/server/game/Movement/MovementGenerators/TargetedMovementGenerator.cpp
index c1a4c5f70a3..abb4ac9964b 100755
--- a/src/server/game/Movement/MovementGenerators/TargetedMovementGenerator.cpp
+++ b/src/server/game/Movement/MovementGenerators/TargetedMovementGenerator.cpp
@@ -26,89 +26,87 @@
#include "MoveSpline.h"
#include "Player.h"
-#include <cmath>
-
template<class T, typename D>
-void TargetedMovementGeneratorMedium<T, D>::_setTargetLocation(T &owner)
+void TargetedMovementGeneratorMedium<T,D>::_setTargetLocation(T* owner, bool updateDestination)
{
if (!i_target.isValid() || !i_target->IsInWorld())
return;
- if (owner.HasUnitState(UNIT_STATE_NOT_MOVE))
+ if (owner->HasUnitState(UNIT_STATE_NOT_MOVE))
+ return;
+
+ if (owner->GetTypeId() == TYPEID_UNIT && !i_target->isInAccessiblePlaceFor(owner->ToCreature()))
return;
float x, y, z;
- //! Following block of code deleted by MrSmite in issue 4891
- //! Code kept for learning and diagnostical purposes
-//
-// if (i_offset && i_target->IsWithinDistInMap(&owner, 2*i_offset))
-// {
-// if (!owner.movespline->Finalized())
-// return;
-//
-// owner.GetPosition(x, y, z);
-// }
-// else
- if (!i_offset)
- {
- if (i_target->IsWithinMeleeRange(&owner))
- return;
- // to nearest random contact position
- i_target->GetRandomContactPoint(&owner, x, y, z, 0, MELEE_RANGE - 0.5f);
- }
- else
+ if (updateDestination || !i_path)
{
- float dist;
- float size;
-
- // Pets need special handling.
- // We need to subtract GetObjectSize() because it gets added back further down the chain
- // and that makes pets too far away. Subtracting it allows pets to properly
- // be (GetCombatReach() + i_offset) away.
- // Only applies when i_target is pet's owner otherwise pets and mobs end up
- // doing a "dance" while fighting
- if (owner.isPet() && i_target->GetTypeId() == TYPEID_PLAYER)
+ if (!i_offset)
{
- dist = i_target->GetCombatReach();
- size = i_target->GetCombatReach() - i_target->GetObjectSize();
+ // to nearest contact position
+ i_target->GetContactPoint(owner, x, y, z);
}
else
{
- dist = i_offset + 1.0f;
- size = owner.GetObjectSize();
+ float dist;
+ float size;
+
+ // Pets need special handling.
+ // We need to subtract GetObjectSize() because it gets added back further down the chain
+ // and that makes pets too far away. Subtracting it allows pets to properly
+ // be (GetCombatReach() + i_offset) away.
+ // Only applies when i_target is pet's owner otherwise pets and mobs end up
+ // doing a "dance" while fighting
+ if (owner->isPet() && i_target->GetTypeId() == TYPEID_PLAYER)
+ {
+ dist = i_target->GetCombatReach();
+ size = i_target->GetCombatReach() - i_target->GetObjectSize();
+ }
+ else
+ {
+ dist = i_offset + 1.0f;
+ size = owner->GetObjectSize();
+ }
+
+ if (i_target->IsWithinDistInMap(owner, dist))
+ return;
+
+ // to at i_offset distance from target and i_angle from target facing
+ i_target->GetClosePoint(x, y, z, size, i_offset, i_angle);
}
+ }
+ else
+ {
+ // the destination has not changed, we just need to refresh the path (usually speed change)
+ G3D::Vector3 end = i_path->GetEndPosition();
+ x = end.x;
+ y = end.y;
+ z = end.z;
+ }
- if (i_target->IsWithinDistInMap(&owner, dist))
- return;
+ if (!i_path)
+ i_path = new PathGenerator(owner);
- // to at i_offset distance from target and i_angle from target facing
- i_target->GetClosePoint(x, y, z, size, i_offset, i_angle);
- }
+ // allow pets to use shortcut if no path found when following their master
+ bool forceDest = (owner->GetTypeId() == TYPEID_UNIT && owner->ToCreature()->isPet()
+ && owner->HasUnitState(UNIT_STATE_FOLLOW));
- /*
- We MUST not check the distance difference and avoid setting the new location for smaller distances.
- By that we risk having far too many GetContactPoint() calls freezing the whole system.
- In TargetedMovementGenerator<T>::Update() we check the distance to the target and at
- some range we calculate a new position. The calculation takes some processor cycles due to vmaps.
- If the distance to the target it too large to ignore,
- but the distance to the new contact point is short enough to be ignored,
- we will calculate a new contact point each update loop, but will never move to it.
- The system will freeze.
- ralf
-
- //We don't update Mob Movement, if the difference between New destination and last destination is < BothObjectSize
- float bothObjectSize = i_target->GetObjectBoundingRadius() + owner.GetObjectBoundingRadius() + CONTACT_DISTANCE;
- if ( i_destinationHolder.HasDestination() && i_destinationHolder.GetDestinationDiff(x, y, z) < bothObjectSize )
- return;
- */
+ bool result = i_path->CalculatePath(x, y, z, forceDest);
+ if (!result || (i_path->GetPathType() & PATHFIND_NOPATH))
+ {
+ // Cant reach target
+ i_recalculateTravel = true;
+ return;
+ }
D::_addUnitStateMove(owner);
i_targetReached = false;
i_recalculateTravel = false;
+ owner->AddUnitState(UNIT_STATE_CHASE);
Movement::MoveSplineInit init(owner);
- init.MoveTo(x, y, z);
+ init.MovebyPath(i_path->GetPath());
init.SetWalk(((D*)this)->EnableWalking());
// Using the same condition for facing target as the one that is used for SetInFront on movement end
// - applies to ChaseMovementGenerator mostly
@@ -118,52 +116,26 @@ void TargetedMovementGeneratorMedium<T, D>::_setTargetLocation(T &owner)
init.Launch();
}
-template<>
-void TargetedMovementGeneratorMedium<Player, ChaseMovementGenerator<Player> >::UpdateFinalDistance(float /*fDistance*/)
-{
- // nothing to do for Player
-}
-
-template<>
-void TargetedMovementGeneratorMedium<Player, FollowMovementGenerator<Player> >::UpdateFinalDistance(float /*fDistance*/)
-{
- // nothing to do for Player
-}
-
-template<>
-void TargetedMovementGeneratorMedium<Creature, ChaseMovementGenerator<Creature> >::UpdateFinalDistance(float fDistance)
-{
- i_offset = fDistance;
- i_recalculateTravel = true;
-}
-
-template<>
-void TargetedMovementGeneratorMedium<Creature, FollowMovementGenerator<Creature> >::UpdateFinalDistance(float fDistance)
-{
- i_offset = fDistance;
- i_recalculateTravel = true;
-}
-
template<class T, typename D>
-bool TargetedMovementGeneratorMedium<T, D>::DoUpdate(T &owner, uint32 time_diff)
+bool TargetedMovementGeneratorMedium<T,D>::DoUpdate(T* owner, uint32 time_diff)
{
if (!i_target.isValid() || !i_target->IsInWorld())
return false;
- if (!owner.isAlive())
- return true;
+ if (!owner || !owner->isAlive())
+ return false;
- if (owner.HasUnitState(UNIT_STATE_NOT_MOVE))
+ if (owner->HasUnitState(UNIT_STATE_NOT_MOVE))
{
D::_clearUnitStateMove(owner);
return true;
}
// prevent movement while casting spells with cast time or channel time
- if (owner.HasUnitState(UNIT_STATE_CASTING))
+ if (owner->HasUnitState(UNIT_STATE_CASTING))
{
- if (!owner.IsStopped())
- owner.StopMoving();
+ if (!owner->IsStopped())
+ owner->StopMoving();
return true;
}
@@ -174,22 +146,29 @@ bool TargetedMovementGeneratorMedium<T, D>::DoUpdate(T &owner, uint32 time_diff)
return true;
}
+ bool targetMoved = false;
i_recheckDistance.Update(time_diff);
if (i_recheckDistance.Passed())
{
- i_recheckDistance.Reset(50);
+ i_recheckDistance.Reset(100);
//More distance let have better performance, less distance let have more sensitive reaction at target move.
- float allowed_dist = i_target->GetObjectSize() + owner.GetObjectSize() + MELEE_RANGE - 0.5f;
- float dist = (owner.movespline->FinalDestination() - G3D::Vector3(i_target->GetPositionX(), i_target->GetPositionY(), i_target->GetPositionZ())).squaredLength();
- if (dist >= allowed_dist * allowed_dist)
- _setTargetLocation(owner);
+ float allowed_dist = owner->GetCombatReach() + sWorld->getRate(RATE_TARGET_POS_RECALCULATION_RANGE);
+ G3D::Vector3 dest = owner->movespline->FinalDestination();
+
+ if (owner->GetTypeId() == TYPEID_UNIT && owner->ToCreature()->CanFly())
+ targetMoved = !i_target->IsWithinDist3d(dest.x, dest.y, dest.z, allowed_dist);
+ else
+ targetMoved = !i_target->IsWithinDist2d(dest.x, dest.y, allowed_dist);
}
- if (owner.movespline->Finalized())
+ if (i_recalculateTravel || targetMoved)
+ _setTargetLocation(owner, targetMoved);
+
+ if (owner->movespline->Finalized())
{
static_cast<D*>(this)->MovementInform(owner);
- if (i_angle == 0.f && !owner.HasInArc(0.01f, i_target.getTarget()))
- owner.SetInFront(i_target.getTarget());
+ if (i_angle == 0.f && !owner->HasInArc(0.01f, i_target.getTarget()))
+ owner->SetInFront(i_target.getTarget());
if (!i_targetReached)
{
@@ -197,60 +176,56 @@ bool TargetedMovementGeneratorMedium<T, D>::DoUpdate(T &owner, uint32 time_diff)
static_cast<D*>(this)->_reachTarget(owner);
}
}
- else
- {
- if (i_recalculateTravel)
- _setTargetLocation(owner);
- }
+
return true;
}
//-----------------------------------------------//
template<class T>
-void ChaseMovementGenerator<T>::_reachTarget(T &owner)
+void ChaseMovementGenerator<T>::_reachTarget(T* owner)
{
- if (owner.IsWithinMeleeRange(this->i_target.getTarget()))
- owner.Attack(this->i_target.getTarget(), true);
+ if (owner->IsWithinMeleeRange(this->i_target.getTarget()))
+ owner->Attack(this->i_target.getTarget(),true);
}
template<>
-void ChaseMovementGenerator<Player>::DoInitialize(Player &owner)
+void ChaseMovementGenerator<Player>::DoInitialize(Player* owner)
{
- owner.AddUnitState(UNIT_STATE_CHASE|UNIT_STATE_CHASE_MOVE);
- _setTargetLocation(owner);
+ owner->AddUnitState(UNIT_STATE_CHASE | UNIT_STATE_CHASE_MOVE);
+ _setTargetLocation(owner, true);
}
template<>
-void ChaseMovementGenerator<Creature>::DoInitialize(Creature &owner)
+void ChaseMovementGenerator<Creature>::DoInitialize(Creature* owner)
{
- owner.SetWalk(false);
- owner.AddUnitState(UNIT_STATE_CHASE|UNIT_STATE_CHASE_MOVE);
- _setTargetLocation(owner);
+ owner->SetWalk(false);
+ owner->AddUnitState(UNIT_STATE_CHASE | UNIT_STATE_CHASE_MOVE);
+ _setTargetLocation(owner, true);
}
template<class T>
-void ChaseMovementGenerator<T>::DoFinalize(T &owner)
+void ChaseMovementGenerator<T>::DoFinalize(T* owner)
{
- owner.ClearUnitState(UNIT_STATE_CHASE|UNIT_STATE_CHASE_MOVE);
+ owner->ClearUnitState(UNIT_STATE_CHASE | UNIT_STATE_CHASE_MOVE);
}
template<class T>
-void ChaseMovementGenerator<T>::DoReset(T &owner)
+void ChaseMovementGenerator<T>::DoReset(T* owner)
{
DoInitialize(owner);
}
template<class T>
-void ChaseMovementGenerator<T>::MovementInform(T & /*unit*/)
+void ChaseMovementGenerator<T>::MovementInform(T* /*unit*/)
{
}
template<>
-void ChaseMovementGenerator<Creature>::MovementInform(Creature &unit)
+void ChaseMovementGenerator<Creature>::MovementInform(Creature* unit)
{
// Pass back the GUIDLow of the target. If it is pet's owner then PetAI will handle
- if (unit.AI())
- unit.AI()->MovementInform(CHASE_MOTION_TYPE, i_target.getTarget()->GetGUIDLow());
+ if (unit->AI())
+ unit->AI()->MovementInform(CHASE_MOTION_TYPE, i_target.getTarget()->GetGUIDLow());
}
//-----------------------------------------------//
@@ -267,85 +242,86 @@ bool FollowMovementGenerator<Player>::EnableWalking() const
}
template<>
-void FollowMovementGenerator<Player>::_updateSpeed(Player &/*u*/)
+void FollowMovementGenerator<Player>::_updateSpeed(Player* /*owner*/)
{
// nothing to do for Player
}
template<>
-void FollowMovementGenerator<Creature>::_updateSpeed(Creature &u)
+void FollowMovementGenerator<Creature>::_updateSpeed(Creature* owner)
{
// pet only sync speed with owner
- if (!((Creature&)u).isPet() || !i_target.isValid() || i_target->GetGUID() != u.GetOwnerGUID())
+ /// Make sure we are not in the process of a map change (IsInWorld)
+ if (!owner->isPet() || !owner->IsInWorld() || !i_target.isValid() || i_target->GetGUID() != owner->GetOwnerGUID())
return;
- u.UpdateSpeed(MOVE_RUN, true);
- u.UpdateSpeed(MOVE_WALK, true);
- u.UpdateSpeed(MOVE_SWIM, true);
+ owner->UpdateSpeed(MOVE_RUN, true);
+ owner->UpdateSpeed(MOVE_WALK, true);
+ owner->UpdateSpeed(MOVE_SWIM, true);
}
template<>
-void FollowMovementGenerator<Player>::DoInitialize(Player &owner)
+void FollowMovementGenerator<Player>::DoInitialize(Player* owner)
{
- owner.AddUnitState(UNIT_STATE_FOLLOW|UNIT_STATE_FOLLOW_MOVE);
+ owner->AddUnitState(UNIT_STATE_FOLLOW | UNIT_STATE_FOLLOW_MOVE);
_updateSpeed(owner);
- _setTargetLocation(owner);
+ _setTargetLocation(owner, true);
}
template<>
-void FollowMovementGenerator<Creature>::DoInitialize(Creature &owner)
+void FollowMovementGenerator<Creature>::DoInitialize(Creature* owner)
{
- owner.AddUnitState(UNIT_STATE_FOLLOW|UNIT_STATE_FOLLOW_MOVE);
+ owner->AddUnitState(UNIT_STATE_FOLLOW | UNIT_STATE_FOLLOW_MOVE);
_updateSpeed(owner);
- _setTargetLocation(owner);
+ _setTargetLocation(owner, true);
}
template<class T>
-void FollowMovementGenerator<T>::DoFinalize(T &owner)
+void FollowMovementGenerator<T>::DoFinalize(T* owner)
{
- owner.ClearUnitState(UNIT_STATE_FOLLOW|UNIT_STATE_FOLLOW_MOVE);
+ owner->ClearUnitState(UNIT_STATE_FOLLOW | UNIT_STATE_FOLLOW_MOVE);
_updateSpeed(owner);
}
template<class T>
-void FollowMovementGenerator<T>::DoReset(T &owner)
+void FollowMovementGenerator<T>::DoReset(T* owner)
{
DoInitialize(owner);
}
template<class T>
-void FollowMovementGenerator<T>::MovementInform(T & /*unit*/)
+void FollowMovementGenerator<T>::MovementInform(T* /*unit*/)
{
}
template<>
-void FollowMovementGenerator<Creature>::MovementInform(Creature &unit)
+void FollowMovementGenerator<Creature>::MovementInform(Creature* unit)
{
// Pass back the GUIDLow of the target. If it is pet's owner then PetAI will handle
- if (unit.AI())
- unit.AI()->MovementInform(FOLLOW_MOTION_TYPE, i_target.getTarget()->GetGUIDLow());
+ if (unit->AI())
+ unit->AI()->MovementInform(FOLLOW_MOTION_TYPE, i_target.getTarget()->GetGUIDLow());
}
//-----------------------------------------------//
-template void TargetedMovementGeneratorMedium<Player, ChaseMovementGenerator<Player> >::_setTargetLocation(Player &);
-template void TargetedMovementGeneratorMedium<Player, FollowMovementGenerator<Player> >::_setTargetLocation(Player &);
-template void TargetedMovementGeneratorMedium<Creature, ChaseMovementGenerator<Creature> >::_setTargetLocation(Creature &);
-template void TargetedMovementGeneratorMedium<Creature, FollowMovementGenerator<Creature> >::_setTargetLocation(Creature &);
-template bool TargetedMovementGeneratorMedium<Player, ChaseMovementGenerator<Player> >::DoUpdate(Player &, uint32);
-template bool TargetedMovementGeneratorMedium<Player, FollowMovementGenerator<Player> >::DoUpdate(Player &, uint32);
-template bool TargetedMovementGeneratorMedium<Creature, ChaseMovementGenerator<Creature> >::DoUpdate(Creature &, uint32);
-template bool TargetedMovementGeneratorMedium<Creature, FollowMovementGenerator<Creature> >::DoUpdate(Creature &, uint32);
-
-template void ChaseMovementGenerator<Player>::_reachTarget(Player &);
-template void ChaseMovementGenerator<Creature>::_reachTarget(Creature &);
-template void ChaseMovementGenerator<Player>::DoFinalize(Player &);
-template void ChaseMovementGenerator<Creature>::DoFinalize(Creature &);
-template void ChaseMovementGenerator<Player>::DoReset(Player &);
-template void ChaseMovementGenerator<Creature>::DoReset(Creature &);
-template void ChaseMovementGenerator<Player>::MovementInform(Player &unit);
-
-template void FollowMovementGenerator<Player>::DoFinalize(Player &);
-template void FollowMovementGenerator<Creature>::DoFinalize(Creature &);
-template void FollowMovementGenerator<Player>::DoReset(Player &);
-template void FollowMovementGenerator<Creature>::DoReset(Creature &);
-template void FollowMovementGenerator<Player>::MovementInform(Player &unit);
+template void TargetedMovementGeneratorMedium<Player,ChaseMovementGenerator<Player> >::_setTargetLocation(Player*, bool);
+template void TargetedMovementGeneratorMedium<Player,FollowMovementGenerator<Player> >::_setTargetLocation(Player*, bool);
+template void TargetedMovementGeneratorMedium<Creature,ChaseMovementGenerator<Creature> >::_setTargetLocation(Creature*, bool);
+template void TargetedMovementGeneratorMedium<Creature,FollowMovementGenerator<Creature> >::_setTargetLocation(Creature*, bool);
+template bool TargetedMovementGeneratorMedium<Player,ChaseMovementGenerator<Player> >::DoUpdate(Player*, uint32);
+template bool TargetedMovementGeneratorMedium<Player,FollowMovementGenerator<Player> >::DoUpdate(Player*, uint32);
+template bool TargetedMovementGeneratorMedium<Creature,ChaseMovementGenerator<Creature> >::DoUpdate(Creature*, uint32);
+template bool TargetedMovementGeneratorMedium<Creature,FollowMovementGenerator<Creature> >::DoUpdate(Creature*, uint32);
+
+template void ChaseMovementGenerator<Player>::_reachTarget(Player*);
+template void ChaseMovementGenerator<Creature>::_reachTarget(Creature*);
+template void ChaseMovementGenerator<Player>::DoFinalize(Player*);
+template void ChaseMovementGenerator<Creature>::DoFinalize(Creature*);
+template void ChaseMovementGenerator<Player>::DoReset(Player*);
+template void ChaseMovementGenerator<Creature>::DoReset(Creature*);
+template void ChaseMovementGenerator<Player>::MovementInform(Player*);
+
+template void FollowMovementGenerator<Player>::DoFinalize(Player*);
+template void FollowMovementGenerator<Creature>::DoFinalize(Creature*);
+template void FollowMovementGenerator<Player>::DoReset(Player*);
+template void FollowMovementGenerator<Creature>::DoReset(Creature*);
+template void FollowMovementGenerator<Player>::MovementInform(Player*);
diff --git a/src/server/game/Movement/MovementGenerators/TargetedMovementGenerator.h b/src/server/game/Movement/MovementGenerators/TargetedMovementGenerator.h
index 4105668838d..3edeb348d54 100755
--- a/src/server/game/Movement/MovementGenerators/TargetedMovementGenerator.h
+++ b/src/server/game/Movement/MovementGenerators/TargetedMovementGenerator.h
@@ -23,11 +23,12 @@
#include "FollowerReference.h"
#include "Timer.h"
#include "Unit.h"
+#include "PathGenerator.h"
class TargetedMovementGeneratorBase
{
public:
- TargetedMovementGeneratorBase(Unit &target) { i_target.link(&target, this); }
+ TargetedMovementGeneratorBase(Unit* target) { i_target.link(target, this); }
void stopFollowing() { }
protected:
FollowerReference i_target;
@@ -37,24 +38,24 @@ template<class T, typename D>
class TargetedMovementGeneratorMedium : public MovementGeneratorMedium< T, D >, public TargetedMovementGeneratorBase
{
protected:
- TargetedMovementGeneratorMedium(Unit &target, float offset, float angle) :
- TargetedMovementGeneratorBase(target), i_recheckDistance(0),
- i_offset(offset), i_angle(angle),
+ TargetedMovementGeneratorMedium(Unit* target, float offset, float angle) :
+ TargetedMovementGeneratorBase(target), i_path(NULL),
+ i_recheckDistance(0), i_offset(offset), i_angle(angle),
i_recalculateTravel(false), i_targetReached(false)
{
}
- ~TargetedMovementGeneratorMedium() {}
+ ~TargetedMovementGeneratorMedium() { delete i_path; }
public:
- bool DoUpdate(T &, uint32);
+ bool DoUpdate(T*, uint32);
Unit* GetTarget() const { return i_target.getTarget(); }
- void unitSpeedChanged() { i_recalculateTravel=true; }
- void UpdateFinalDistance(float fDistance);
-
+ void unitSpeedChanged() { i_recalculateTravel = true; }
+ bool IsReachable() const { return (i_path) ? (i_path->GetPathType() & PATHFIND_NORMAL) : true; }
protected:
- void _setTargetLocation(T &);
+ void _setTargetLocation(T* owner, bool updateDestination);
+ PathGenerator* i_path;
TimeTrackerSmall i_recheckDistance;
float i_offset;
float i_angle;
@@ -66,50 +67,50 @@ template<class T>
class ChaseMovementGenerator : public TargetedMovementGeneratorMedium<T, ChaseMovementGenerator<T> >
{
public:
- ChaseMovementGenerator(Unit &target)
+ ChaseMovementGenerator(Unit* target)
: TargetedMovementGeneratorMedium<T, ChaseMovementGenerator<T> >(target) {}
- ChaseMovementGenerator(Unit &target, float offset, float angle)
+ ChaseMovementGenerator(Unit* target, float offset, float angle)
: TargetedMovementGeneratorMedium<T, ChaseMovementGenerator<T> >(target, offset, angle) {}
~ChaseMovementGenerator() {}
MovementGeneratorType GetMovementGeneratorType() { return CHASE_MOTION_TYPE; }
- void DoInitialize(T &);
- void DoFinalize(T &);
- void DoReset(T &);
- void MovementInform(T &);
+ void DoInitialize(T*);
+ void DoFinalize(T*);
+ void DoReset(T*);
+ void MovementInform(T*);
- static void _clearUnitStateMove(T &u) { u.ClearUnitState(UNIT_STATE_CHASE_MOVE); }
- static void _addUnitStateMove(T &u) { u.AddUnitState(UNIT_STATE_CHASE_MOVE); }
+ static void _clearUnitStateMove(T* u) { u->ClearUnitState(UNIT_STATE_CHASE_MOVE); }
+ static void _addUnitStateMove(T* u) { u->AddUnitState(UNIT_STATE_CHASE_MOVE); }
bool EnableWalking() const { return false;}
- bool _lostTarget(T &u) const { return u.getVictim() != this->GetTarget(); }
- void _reachTarget(T &);
+ bool _lostTarget(T* u) const { return u->getVictim() != this->GetTarget(); }
+ void _reachTarget(T*);
};
template<class T>
class FollowMovementGenerator : public TargetedMovementGeneratorMedium<T, FollowMovementGenerator<T> >
{
public:
- FollowMovementGenerator(Unit &target)
+ FollowMovementGenerator(Unit* target)
: TargetedMovementGeneratorMedium<T, FollowMovementGenerator<T> >(target){}
- FollowMovementGenerator(Unit &target, float offset, float angle)
+ FollowMovementGenerator(Unit* target, float offset, float angle)
: TargetedMovementGeneratorMedium<T, FollowMovementGenerator<T> >(target, offset, angle) {}
~FollowMovementGenerator() {}
MovementGeneratorType GetMovementGeneratorType() { return FOLLOW_MOTION_TYPE; }
- void DoInitialize(T &);
- void DoFinalize(T &);
- void DoReset(T &);
- void MovementInform(T &);
+ void DoInitialize(T*);
+ void DoFinalize(T*);
+ void DoReset(T*);
+ void MovementInform(T*);
- static void _clearUnitStateMove(T &u) { u.ClearUnitState(UNIT_STATE_FOLLOW_MOVE); }
- static void _addUnitStateMove(T &u) { u.AddUnitState(UNIT_STATE_FOLLOW_MOVE); }
+ static void _clearUnitStateMove(T* u) { u->ClearUnitState(UNIT_STATE_FOLLOW_MOVE); }
+ static void _addUnitStateMove(T* u) { u->AddUnitState(UNIT_STATE_FOLLOW_MOVE); }
bool EnableWalking() const;
- bool _lostTarget(T &) const { return false; }
- void _reachTarget(T &) {}
+ bool _lostTarget(T*) const { return false; }
+ void _reachTarget(T*) {}
private:
- void _updateSpeed(T &u);
+ void _updateSpeed(T* owner);
};
#endif
diff --git a/src/server/game/Movement/MovementGenerators/WaypointMovementGenerator.cpp b/src/server/game/Movement/MovementGenerators/WaypointMovementGenerator.cpp
index 2add3439575..626039ed2d5 100644..100755
--- a/src/server/game/Movement/MovementGenerators/WaypointMovementGenerator.cpp
+++ b/src/server/game/Movement/MovementGenerators/WaypointMovementGenerator.cpp
@@ -31,64 +31,64 @@
#include "MoveSplineInit.h"
#include "MoveSpline.h"
-void WaypointMovementGenerator<Creature>::LoadPath(Creature &creature)
+void WaypointMovementGenerator<Creature>::LoadPath(Creature* creature)
{
if (!path_id)
- path_id = creature.GetWaypointPath();
+ path_id = creature->GetWaypointPath();
i_path = sWaypointMgr->GetPath(path_id);
if (!i_path)
{
// No movement found for entry
- sLog->outError(LOG_FILTER_SQL, "WaypointMovementGenerator::LoadPath: creature %s (Entry: %u GUID: %u) doesn't have waypoint path id: %u", creature.GetName().c_str(), creature.GetEntry(), creature.GetGUIDLow(), path_id);
+ sLog->outError(LOG_FILTER_SQL, "WaypointMovementGenerator::LoadPath: creature %s (Entry: %u GUID: %u) doesn't have waypoint path id: %u", creature->GetName().c_str(), creature->GetEntry(), creature->GetGUIDLow(), path_id);
return;
}
StartMoveNow(creature);
}
-void WaypointMovementGenerator<Creature>::DoInitialize(Creature &creature)
+void WaypointMovementGenerator<Creature>::DoInitialize(Creature* creature)
{
LoadPath(creature);
- creature.AddUnitState(UNIT_STATE_ROAMING|UNIT_STATE_ROAMING_MOVE);
+ creature->AddUnitState(UNIT_STATE_ROAMING|UNIT_STATE_ROAMING_MOVE);
}
-void WaypointMovementGenerator<Creature>::DoFinalize(Creature &creature)
+void WaypointMovementGenerator<Creature>::DoFinalize(Creature* creature)
{
- creature.ClearUnitState(UNIT_STATE_ROAMING|UNIT_STATE_ROAMING_MOVE);
- creature.SetWalk(false);
+ creature->ClearUnitState(UNIT_STATE_ROAMING|UNIT_STATE_ROAMING_MOVE);
+ creature->SetWalk(false);
}
-void WaypointMovementGenerator<Creature>::DoReset(Creature &creature)
+void WaypointMovementGenerator<Creature>::DoReset(Creature* creature)
{
- creature.AddUnitState(UNIT_STATE_ROAMING|UNIT_STATE_ROAMING_MOVE);
+ creature->AddUnitState(UNIT_STATE_ROAMING|UNIT_STATE_ROAMING_MOVE);
StartMoveNow(creature);
}
-void WaypointMovementGenerator<Creature>::OnArrived(Creature& creature)
+void WaypointMovementGenerator<Creature>::OnArrived(Creature* creature)
{
if (!i_path || i_path->empty())
return;
if (m_isArrivalDone)
return;
- creature.ClearUnitState(UNIT_STATE_ROAMING_MOVE);
+ creature->ClearUnitState(UNIT_STATE_ROAMING_MOVE);
m_isArrivalDone = true;
if (i_path->at(i_currentNode)->event_id && urand(0, 99) < i_path->at(i_currentNode)->event_chance)
{
- sLog->outDebug(LOG_FILTER_MAPSCRIPTS, "Creature movement start script %u at point %u for "UI64FMTD".", i_path->at(i_currentNode)->event_id, i_currentNode, creature.GetGUID());
- creature.GetMap()->ScriptsStart(sWaypointScripts, i_path->at(i_currentNode)->event_id, &creature, NULL);
+ sLog->outDebug(LOG_FILTER_MAPSCRIPTS, "Creature movement start script %u at point %u for "UI64FMTD".", i_path->at(i_currentNode)->event_id, i_currentNode, creature->GetGUID());
+ creature->GetMap()->ScriptsStart(sWaypointScripts, i_path->at(i_currentNode)->event_id, creature, NULL);
}
// Inform script
MovementInform(creature);
- creature.UpdateWaypointID(i_currentNode);
+ creature->UpdateWaypointID(i_currentNode);
Stop(i_path->at(i_currentNode)->delay);
}
-bool WaypointMovementGenerator<Creature>::StartMove(Creature &creature)
+bool WaypointMovementGenerator<Creature>::StartMove(Creature* creature)
{
if (!i_path || i_path->empty())
return false;
@@ -99,8 +99,8 @@ bool WaypointMovementGenerator<Creature>::StartMove(Creature &creature)
{
if ((i_currentNode == i_path->size() - 1) && !repeating) // If that's our last waypoint
{
- creature.SetHomePosition(i_path->at(i_currentNode)->x, i_path->at(i_currentNode)->y, i_path->at(i_currentNode)->z, creature.GetOrientation());
- creature.GetMotionMaster()->Initialize();
+ creature->SetHomePosition(i_path->at(i_currentNode)->x, i_path->at(i_currentNode)->y, i_path->at(i_currentNode)->z, creature->GetOrientation());
+ creature->GetMotionMaster()->Initialize();
return false;
}
@@ -111,7 +111,7 @@ bool WaypointMovementGenerator<Creature>::StartMove(Creature &creature)
m_isArrivalDone = false;
- creature.AddUnitState(UNIT_STATE_ROAMING_MOVE);
+ creature->AddUnitState(UNIT_STATE_ROAMING_MOVE);
Movement::MoveSplineInit init(creature);
init.MoveTo(node->x, node->y, node->z);
@@ -124,19 +124,19 @@ bool WaypointMovementGenerator<Creature>::StartMove(Creature &creature)
init.Launch();
//Call for creature group update
- if (creature.GetFormation() && creature.GetFormation()->getLeader() == &creature)
- creature.GetFormation()->LeaderMoveTo(node->x, node->y, node->z);
+ if (creature->GetFormation() && creature->GetFormation()->getLeader() == creature)
+ creature->GetFormation()->LeaderMoveTo(node->x, node->y, node->z);
return true;
}
-bool WaypointMovementGenerator<Creature>::DoUpdate(Creature &creature, uint32 diff)
+bool WaypointMovementGenerator<Creature>::DoUpdate(Creature* creature, uint32 diff)
{
// Waypoint movement can be switched on/off
// This is quite handy for escort quests and other stuff
- if (creature.HasUnitState(UNIT_STATE_NOT_MOVE))
+ if (creature->HasUnitState(UNIT_STATE_NOT_MOVE))
{
- creature.ClearUnitState(UNIT_STATE_ROAMING_MOVE);
+ creature->ClearUnitState(UNIT_STATE_ROAMING_MOVE);
return true;
}
// prevent a crash at empty waypoint path.
@@ -150,9 +150,9 @@ bool WaypointMovementGenerator<Creature>::DoUpdate(Creature &creature, uint32 di
}
else
{
- if (creature.IsStopped())
+ if (creature->IsStopped())
Stop(STOP_TIME_FOR_PLAYER);
- else if (creature.movespline->Finalized())
+ else if (creature->movespline->Finalized())
{
OnArrived(creature);
return StartMove(creature);
@@ -161,13 +161,13 @@ bool WaypointMovementGenerator<Creature>::DoUpdate(Creature &creature, uint32 di
return true;
}
-void WaypointMovementGenerator<Creature>::MovementInform(Creature &creature)
+void WaypointMovementGenerator<Creature>::MovementInform(Creature* creature)
{
- if (creature.AI())
- creature.AI()->MovementInform(WAYPOINT_MOTION_TYPE, i_currentNode);
+ if (creature->AI())
+ creature->AI()->MovementInform(WAYPOINT_MOTION_TYPE, i_currentNode);
}
-bool WaypointMovementGenerator<Creature>::GetResetPosition(Creature&, float& x, float& y, float& z)
+bool WaypointMovementGenerator<Creature>::GetResetPos(Creature*, float& x, float& y, float& z)
{
// prevent a crash at empty waypoint path.
if (!i_path || i_path->empty())
@@ -196,37 +196,37 @@ uint32 FlightPathMovementGenerator::GetPathAtMapEnd() const
return i_path->size();
}
-void FlightPathMovementGenerator::DoInitialize(Player &player)
+void FlightPathMovementGenerator::DoInitialize(Player* player)
{
- DoReset(player);
+ Reset(player);
InitEndGridInfo();
}
-void FlightPathMovementGenerator::DoFinalize(Player& player)
+void FlightPathMovementGenerator::DoFinalize(Player* player)
{
// remove flag to prevent send object build movement packets for flight state and crash (movement generator already not at top of stack)
- player.ClearUnitState(UNIT_STATE_IN_FLIGHT);
+ player->ClearUnitState(UNIT_STATE_IN_FLIGHT);
- player.Dismount();
- player.RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_DISABLE_MOVE | UNIT_FLAG_TAXI_FLIGHT);
+ player->Dismount();
+ player->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_DISABLE_MOVE | UNIT_FLAG_TAXI_FLIGHT);
- if (player.m_taxi.empty())
+ if (player->m_taxi.empty())
{
- player.getHostileRefManager().setOnlineOfflineState(true);
+ player->getHostileRefManager().setOnlineOfflineState(true);
// update z position to ground and orientation for landing point
// this prevent cheating with landing point at lags
// when client side flight end early in comparison server side
- player.StopMoving();
+ player->StopMoving();
}
}
#define PLAYER_FLIGHT_SPEED 32.0f
-void FlightPathMovementGenerator::DoReset(Player & player)
+void FlightPathMovementGenerator::DoReset(Player* player)
{
- player.getHostileRefManager().setOnlineOfflineState(false);
- player.AddUnitState(UNIT_STATE_IN_FLIGHT);
- player.SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_DISABLE_MOVE | UNIT_FLAG_TAXI_FLIGHT);
+ player->getHostileRefManager().setOnlineOfflineState(false);
+ player->AddUnitState(UNIT_STATE_IN_FLIGHT);
+ player->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_DISABLE_MOVE | UNIT_FLAG_TAXI_FLIGHT);
Movement::MoveSplineInit init(player);
uint32 end = GetPathAtMapEnd();
@@ -243,9 +243,9 @@ void FlightPathMovementGenerator::DoReset(Player & player)
init.Launch();
}
-bool FlightPathMovementGenerator::DoUpdate(Player &player, uint32 /*diff*/)
+bool FlightPathMovementGenerator::DoUpdate(Player* player, uint32 /*diff*/)
{
- uint32 pointId = (uint32)player.movespline->currentPathIdx();
+ uint32 pointId = (uint32)player->movespline->currentPathIdx();
if (pointId > i_currentNode)
{
bool departureEvent = true;
@@ -281,16 +281,16 @@ void FlightPathMovementGenerator::SetCurrentNodeAfterTeleport()
}
}
-void FlightPathMovementGenerator::DoEventIfAny(Player& player, TaxiPathNodeEntry const& node, bool departure)
+void FlightPathMovementGenerator::DoEventIfAny(Player* player, TaxiPathNodeEntry const& node, bool departure)
{
if (uint32 eventid = departure ? node.departureEventID : node.arrivalEventID)
{
- sLog->outDebug(LOG_FILTER_MAPSCRIPTS, "Taxi %s event %u of node %u of path %u for player %s", departure ? "departure" : "arrival", eventid, node.index, node.path, player.GetName().c_str());
- player.GetMap()->ScriptsStart(sEventScripts, eventid, &player, &player);
+ sLog->outDebug(LOG_FILTER_MAPSCRIPTS, "Taxi %s event %u of node %u of path %u for player %s", departure ? "departure" : "arrival", eventid, node.index, node.path, player->GetName().c_str());
+ player->GetMap()->ScriptsStart(sEventScripts, eventid, player, player);
}
}
-bool FlightPathMovementGenerator::GetResetPosition(Player&, float& x, float& y, float& z)
+bool FlightPathMovementGenerator::GetResetPos(Player*, float& x, float& y, float& z)
{
const TaxiPathNodeEntry& node = (*i_path)[i_currentNode];
x = node.x; y = node.y; z = node.z;
@@ -322,331 +322,3 @@ void FlightPathMovementGenerator::PreloadEndGrid()
else
sLog->outInfo(LOG_FILTER_GENERAL, "Unable to determine map to preload flightmaster grid");
}
-
-
-//
-// Unique1's ASTAR Pathfinding Code... For future use & reference...
-//
-
-#ifdef __PATHFINDING__
-
-int GetFCost(int to, int num, int parentNum, float *gcost); // Below...
-
-int ShortenASTARRoute(short int *pathlist, int number)
-{ // Wrote this to make the routes a little smarter (shorter)... No point looping back to the same places... Unique1
- short int temppathlist[MAX_PATHLIST_NODES];
- int count = 0;
- // int count2 = 0;
- int temp, temp2;
- int link;
- int upto = 0;
-
- for (temp = number; temp >= 0; temp--)
- {
- qboolean shortened = qfalse;
-
- for (temp2 = 0; temp2 < temp; temp2++)
- {
- for (link = 0; link < nodes[pathlist[temp]].enodenum; link++)
- {
- if (nodes[pathlist[temp]].links[link].flags & PATH_BLOCKED)
- continue;
-
- //if ((bot->client->ps.eFlags & EF_TANK) && nodes[bot->current_node].links[link].flags & PATH_NOTANKS) //if this path is blocked, skip it
- // continue;
-
- //if (nodes[nodes[pathlist[temp]].links[link].targetNode].origin[2] > nodes[pathlist[temp]].origin[2] + 32)
- // continue;
-
- if (nodes[pathlist[temp]].links[link].targetNode == pathlist[temp2])
- { // Found a shorter route...
- //if (OrgVisible(nodes[pathlist[temp2]].origin, nodes[pathlist[temp]].origin, -1))
- {
- temppathlist[count] = pathlist[temp2];
- temp = temp2;
- ++count;
- shortened = qtrue;
- }
- }
- }
- }
-
- if (!shortened)
- {
- temppathlist[count] = pathlist[temp];
- ++count;
- }
- }
-
- upto = count;
-
- for (temp = 0; temp < count; temp++)
- {
- pathlist[temp] = temppathlist[upto];
- --upto;
- }
-
- G_Printf("ShortenASTARRoute: Path size reduced from %i to %i nodes...n", number, count);
- return count;
-}
-
-/*
-===========================================================================
-CreatePathAStar
-This function uses the A* pathfinding algorithm to determine the
-shortest path between any two nodes.
-It's fairly complex, so I'm not really going to explain it much.
-Look up A* and binary heaps for more info.
-pathlist stores the ideal path between the nodes, in reverse order,
-and the return value is the number of nodes in that path
-===========================================================================
-*/
-int CreatePathAStar(gentity_t *bot, int from, int to, short int *pathlist)
-{
- //all the data we have to hold...since we can't do dynamic allocation, has to be MAX_NODES
- //we can probably lower this later - eg, the open list should never have more than at most a few dozen items on it
- short int openlist[MAX_NODES+1]; //add 1 because it's a binary heap, and they don't use 0 - 1 is the first used index
- float gcost[MAX_NODES];
- int fcost[MAX_NODES];
- char list[MAX_NODES]; //0 is neither, 1 is open, 2 is closed - char because it's the smallest data type
- short int parent[MAX_NODES];
-
- short int numOpen = 0;
- short int atNode, temp, newnode=-1;
- qboolean found = qfalse;
- int count = -1;
- float gc;
- int i, u, v, m;
- vec3_t vec;
-
- //clear out all the arrays
- memset(openlist, 0, sizeof(short int)*(MAX_NODES+1));
- memset(fcost, 0, sizeof(int)*MAX_NODES);
- memset(list, 0, sizeof(char)*MAX_NODES);
- memset(parent, 0, sizeof(short int)*MAX_NODES);
- memset(gcost, -1, sizeof(float)*MAX_NODES);
-
- //make sure we have valid data before calculating everything
- if ((from == NODE_INVALID) || (to == NODE_INVALID) || (from >= MAX_NODES) || (to >= MAX_NODES) || (from == to))
- return -1;
-
- openlist[1] = from; //add the starting node to the open list
- ++numOpen;
- gcost[from] = 0; //its f and g costs are obviously 0
- fcost[from] = 0;
-
- while (1)
- {
- if (numOpen != 0) //if there are still items in the open list
- {
- //pop the top item off of the list
- atNode = openlist[1];
- list[atNode] = 2; //put the node on the closed list so we don't check it again
- --numOpen;
-
- openlist[1] = openlist[numOpen+1]; //move the last item in the list to the top position
- v = 1;
-
- //this while loop reorders the list so that the new lowest fcost is at the top again
- while (1)
- {
- u = v;
- if ((2*u+1) < numOpen) //if both children exist
- {
- if (fcost[openlist[u]] >= fcost[openlist[2*u]])
- v = 2*u;
- if (fcost[openlist[v]] >= fcost[openlist[2*u+1]])
- v = 2*u+1;
- }
- else
- {
- if ((2*u) < numOpen) //if only one child exists
- {
- if (fcost[openlist[u]] >= fcost[openlist[2*u]])
- v = 2*u;
- }
- }
-
- if (u != v) //if they're out of order, swap this item with its parent
- {
- temp = openlist[u];
- openlist[u] = openlist[v];
- openlist[v] = temp;
- }
- else
- break;
- }
-
- for (i = 0; i < nodes[atNode].enodenum; ++i) //loop through all the links for this node
- {
- newnode = nodes[atNode].links[i].targetNode;
-
- //if this path is blocked, skip it
- if (nodes[atNode].links[i].flags & PATH_BLOCKED)
- continue;
- //if this path is blocked, skip it
- if (bot->client && (bot->client->ps.eFlags & EF_TANK) && nodes[atNode].links[i].flags & PATH_NOTANKS)
- continue;
- //skip any unreachable nodes
- if (bot->client && (nodes[newnode].type & NODE_ALLY_UNREACHABLE) && (bot->client->sess.sessionTeam == TEAM_ALLIES))
- continue;
- if (bot->client && (nodes[newnode].type & NODE_AXIS_UNREACHABLE) && (bot->client->sess.sessionTeam == TEAM_AXIS))
- continue;
-
- if (list[newnode] == 2) //if this node is on the closed list, skip it
- continue;
-
- if (list[newnode] != 1) //if this node is not already on the open list
- {
- openlist[++numOpen] = newnode; //add the new node to the open list
- list[newnode] = 1;
- parent[newnode] = atNode; //record the node's parent
-
- if (newnode == to) //if we've found the goal, don't keep computing paths!
- break; //this will break the 'for' and go all the way to 'if (list[to] == 1)'
-
- //store it's f cost value
- fcost[newnode] = GetFCost(to, newnode, parent[newnode], gcost);
-
- //this loop re-orders the heap so that the lowest fcost is at the top
- m = numOpen;
- while (m != 1) //while this item isn't at the top of the heap already
- {
- //if it has a lower fcost than its parent
- if (fcost[openlist[m]] <= fcost[openlist[m/2]])
- {
- temp = openlist[m/2];
- openlist[m/2] = openlist[m];
- openlist[m] = temp; //swap them
- m /= 2;
- }
- else
- break;
- }
- }
- else //if this node is already on the open list
- {
- gc = gcost[atNode];
- VectorSubtract(nodes[newnode].origin, nodes[atNode].origin, vec);
- gc += VectorLength(vec); //calculate what the gcost would be if we reached this node along the current path
-
- if (gc < gcost[newnode]) //if the new gcost is less (ie, this path is shorter than what we had before)
- {
- parent[newnode] = atNode; //set the new parent for this node
- gcost[newnode] = gc; //and the new g cost
-
- for (i = 1; i < numOpen; ++i) //loop through all the items on the open list
- {
- if (openlist[i] == newnode) //find this node in the list
- {
- //calculate the new fcost and store it
- fcost[newnode] = GetFCost(to, newnode, parent[newnode], gcost);
-
- //reorder the list again, with the lowest fcost item on top
- m = i;
- while (m != 1)
- {
- //if the item has a lower fcost than it's parent
- if (fcost[openlist[m]] < fcost[openlist[m/2]])
- {
- temp = openlist[m/2];
- openlist[m/2] = openlist[m];
- openlist[m] = temp; //swap them
- m /= 2;
- }
- else
- break;
- }
- break; //exit the 'for' loop because we already changed this node
- } //if
- } //for
- } //if (gc < gcost[newnode])
- } //if (list[newnode] != 1) --> else
- } //for (loop through links)
- } //if (numOpen != 0)
- else
- {
- found = qfalse; //there is no path between these nodes
- break;
- }
-
- if (list[to] == 1) //if the destination node is on the open list, we're done
- {
- found = qtrue;
- break;
- }
- } //while (1)
-
- if (found == qtrue) //if we found a path
- {
- //G_Printf("%s - path found!n", bot->client->pers.netname);
- count = 0;
-
- temp = to; //start at the end point
- while (temp != from) //travel along the path (backwards) until we reach the starting point
- {
- pathlist[count++] = temp; //add the node to the pathlist and increment the count
- temp = parent[temp]; //move to the parent of this node to continue the path
- }
-
- pathlist[count++] = from; //add the beginning node to the end of the pathlist
-
- #ifdef __BOT_SHORTEN_ROUTING__
- count = ShortenASTARRoute(pathlist, count); // This isn't working... Dunno why.. Unique1
- #endif //__BOT_SHORTEN_ROUTING__
- }
- else
- {
- //G_Printf("^1*** ^4BOT DEBUG^5: (CreatePathAStar) There is no route between node ^7%i^5 and node ^7%i^5.n", from, to);
- count = CreateDumbRoute(from, to, pathlist);
-
- if (count > 0)
- {
- #ifdef __BOT_SHORTEN_ROUTING__
- count = ShortenASTARRoute(pathlist, count); // This isn't working... Dunno why.. Unique1
- #endif //__BOT_SHORTEN_ROUTING__
- return count;
- }
- }
-
- return count; //return the number of nodes in the path, -1 if not found
-}
-
-/*
-===========================================================================
-GetFCost
-Utility function used by A* pathfinding to calculate the
-cost to move between nodes towards a goal. Using the A*
-algorithm F = G + H, G here is the distance along the node
-paths the bot must travel, and H is the straight-line distance
-to the goal node.
-Returned as an int because more precision is unnecessary and it
-will slightly speed up heap access
-===========================================================================
-*/
-int GetFCost(int to, int num, int parentNum, float *gcost)
-{
- float gc = 0;
- float hc = 0;
- vec3_t v;
-
- if (gcost[num] == -1)
- {
- if (parentNum != -1)
- {
- gc = gcost[parentNum];
- VectorSubtract(nodes[num].origin, nodes[parentNum].origin, v);
- gc += VectorLength(v);
- }
- gcost[num] = gc;
- }
- else
- gc = gcost[num];
-
- VectorSubtract(nodes[to].origin, nodes[num].origin, v);
- hc = VectorLength(v);
-
- return (int)(gc + hc);
-}
-#endif //__PATHFINDING__
-
diff --git a/src/server/game/Movement/MovementGenerators/WaypointMovementGenerator.h b/src/server/game/Movement/MovementGenerators/WaypointMovementGenerator.h
index 319a5c66a03..72650570e12 100644..100755
--- a/src/server/game/Movement/MovementGenerators/WaypointMovementGenerator.h
+++ b/src/server/game/Movement/MovementGenerators/WaypointMovementGenerator.h
@@ -65,19 +65,19 @@ class WaypointMovementGenerator<Creature> : public MovementGeneratorMedium< Crea
WaypointMovementGenerator(uint32 _path_id = 0, bool _repeating = true)
: i_nextMoveTime(0), m_isArrivalDone(false), path_id(_path_id), repeating(_repeating) {}
~WaypointMovementGenerator() { i_path = NULL; }
- void DoInitialize(Creature &);
- void DoFinalize(Creature &);
- void DoReset(Creature &);
- bool DoUpdate(Creature &, uint32 diff);
+ void DoInitialize(Creature*);
+ void DoFinalize(Creature*);
+ void DoReset(Creature*);
+ bool DoUpdate(Creature*, uint32 diff);
- void MovementInform(Creature &);
+ void MovementInform(Creature*);
MovementGeneratorType GetMovementGeneratorType() { return WAYPOINT_MOTION_TYPE; }
// now path movement implmementation
- void LoadPath(Creature &c);
+ void LoadPath(Creature*);
- bool GetResetPosition(Creature&, float& x, float& y, float& z);
+ bool GetResetPos(Creature*, float& x, float& y, float& z);
private:
@@ -91,10 +91,10 @@ class WaypointMovementGenerator<Creature> : public MovementGeneratorMedium< Crea
return i_nextMoveTime.Passed();
}
- void OnArrived(Creature&);
- bool StartMove(Creature&);
+ void OnArrived(Creature*);
+ bool StartMove(Creature*);
- void StartMoveNow(Creature& creature)
+ void StartMoveNow(Creature* creature)
{
i_nextMoveTime.Reset(0);
StartMove(creature);
@@ -118,10 +118,10 @@ class FlightPathMovementGenerator : public MovementGeneratorMedium< Player, Flig
i_path = &pathnodes;
i_currentNode = startNode;
}
- void DoInitialize(Player &);
- void DoReset(Player &);
- void DoFinalize(Player &);
- bool DoUpdate(Player &, uint32);
+ void DoInitialize(Player*);
+ void DoReset(Player*);
+ void DoFinalize(Player*);
+ bool DoUpdate(Player*, uint32);
MovementGeneratorType GetMovementGeneratorType() { return FLIGHT_MOTION_TYPE; }
TaxiPathNodeList const& GetPath() { return *i_path; }
@@ -129,9 +129,9 @@ class FlightPathMovementGenerator : public MovementGeneratorMedium< Player, Flig
bool HasArrived() const { return (i_currentNode >= i_path->size()); }
void SetCurrentNodeAfterTeleport();
void SkipCurrentNode() { ++i_currentNode; }
- void DoEventIfAny(Player& player, TaxiPathNodeEntry const& node, bool departure);
+ void DoEventIfAny(Player* player, TaxiPathNodeEntry const& node, bool departure);
- bool GetResetPosition(Player&, float& x, float& y, float& z);
+ bool GetResetPos(Player*, float& x, float& y, float& z);
void InitEndGridInfo();
void PreloadEndGrid();
@@ -143,4 +143,3 @@ class FlightPathMovementGenerator : public MovementGeneratorMedium< Player, Flig
uint32 _preloadTargetNode; //! node index where preloading starts
};
#endif
-
diff --git a/src/server/game/Movement/PathGenerator.cpp b/src/server/game/Movement/PathGenerator.cpp
new file mode 100644
index 00000000000..dbda4aa2411
--- /dev/null
+++ b/src/server/game/Movement/PathGenerator.cpp
@@ -0,0 +1,803 @@
+/*
+ * Copyright (C) 2005-2011 MaNGOS <http://getmangos.com/>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#include "PathGenerator.h"
+#include "Map.h"
+#include "Creature.h"
+#include "MMapFactory.h"
+#include "MMapManager.h"
+#include "Log.h"
+
+#include "DetourCommon.h"
+#include "DetourNavMeshQuery.h"
+
+////////////////// PathGenerator //////////////////
+PathGenerator::PathGenerator(const Unit* owner) :
+ _polyLength(0), _type(PATHFIND_BLANK),
+ _useStraightPath(false), _forceDestination(false), _pointPathLimit(MAX_POINT_PATH_LENGTH),
+ _endPosition(Vector3::zero()), _sourceUnit(owner), _navMesh(NULL), _navMeshQuery(NULL)
+{
+ sLog->outDebug(LOG_FILTER_MAPS, "++ PathGenerator::PathGenerator for %u \n", _sourceUnit->GetGUIDLow());
+
+ uint32 mapId = _sourceUnit->GetMapId();
+ if (MMAP::MMapFactory::IsPathfindingEnabled(mapId))
+ {
+ MMAP::MMapManager* mmap = MMAP::MMapFactory::createOrGetMMapManager();
+ _navMesh = mmap->GetNavMesh(mapId);
+ _navMeshQuery = mmap->GetNavMeshQuery(mapId, _sourceUnit->GetInstanceId());
+ }
+
+ CreateFilter();
+}
+
+PathGenerator::~PathGenerator()
+{
+ sLog->outDebug(LOG_FILTER_MAPS, "++ PathGenerator::~PathGenerator() for %u \n", _sourceUnit->GetGUIDLow());
+}
+
+bool PathGenerator::CalculatePath(float destX, float destY, float destZ, bool forceDest)
+{
+ float x, y, z;
+ _sourceUnit->GetPosition(x, y, z);
+
+ if (!Trinity::IsValidMapCoord(destX, destY, destZ) || !Trinity::IsValidMapCoord(x, y, z))
+ return false;
+
+ Vector3 dest(destX, destY, destZ);
+ SetEndPosition(dest);
+
+ Vector3 start(x, y, z);
+ SetStartPosition(start);
+
+ _forceDestination = forceDest;
+
+ sLog->outDebug(LOG_FILTER_MAPS, "++ PathGenerator::CalculatePath() for %u \n", _sourceUnit->GetGUIDLow());
+
+ // make sure navMesh works - we can run on map w/o mmap
+ // check if the start and end point have a .mmtile loaded (can we pass via not loaded tile on the way?)
+ if (!_navMesh || !_navMeshQuery || _sourceUnit->HasUnitState(UNIT_STATE_IGNORE_PATHFINDING) ||
+ !HaveTile(start) || !HaveTile(dest))
+ {
+ BuildShortcut();
+ _type = PathType(PATHFIND_NORMAL | PATHFIND_NOT_USING_PATH);
+ return true;
+ }
+
+ UpdateFilter();
+
+ BuildPolyPath(start, dest);
+ return true;
+}
+
+dtPolyRef PathGenerator::GetPathPolyByPosition(dtPolyRef const* polyPath, uint32 polyPathSize, float const* point, float* distance) const
+{
+ if (!polyPath || !polyPathSize)
+ return INVALID_POLYREF;
+
+ dtPolyRef nearestPoly = INVALID_POLYREF;
+ float minDist2d = FLT_MAX;
+ float minDist3d = 0.0f;
+
+ for (uint32 i = 0; i < polyPathSize; ++i)
+ {
+ float closestPoint[VERTEX_SIZE];
+ if (DT_SUCCESS != _navMeshQuery->closestPointOnPoly(polyPath[i], point, closestPoint))
+ continue;
+
+ float d = dtVdist2DSqr(point, closestPoint);
+ if (d < minDist2d)
+ {
+ minDist2d = d;
+ nearestPoly = polyPath[i];
+ minDist3d = dtVdistSqr(point, closestPoint);
+ }
+
+ if (minDist2d < 1.0f) // shortcut out - close enough for us
+ break;
+ }
+
+ if (distance)
+ *distance = dtSqrt(minDist3d);
+
+ return (minDist2d < 3.0f) ? nearestPoly : INVALID_POLYREF;
+}
+
+dtPolyRef PathGenerator::GetPolyByLocation(float const* point, float* distance) const
+{
+ // first we check the current path
+ // if the current path doesn't contain the current poly,
+ // we need to use the expensive navMesh.findNearestPoly
+ dtPolyRef polyRef = GetPathPolyByPosition(_pathPolyRefs, _polyLength, point, distance);
+ if (polyRef != INVALID_POLYREF)
+ return polyRef;
+
+ // we don't have it in our old path
+ // try to get it by findNearestPoly()
+ // first try with low search box
+ float extents[VERTEX_SIZE] = {3.0f, 5.0f, 3.0f}; // bounds of poly search area
+ float closestPoint[VERTEX_SIZE] = {0.0f, 0.0f, 0.0f};
+ dtStatus result = _navMeshQuery->findNearestPoly(point, extents, &_filter, &polyRef, closestPoint);
+ if (DT_SUCCESS == result && polyRef != INVALID_POLYREF)
+ {
+ *distance = dtVdist(closestPoint, point);
+ return polyRef;
+ }
+
+ // still nothing ..
+ // try with bigger search box
+ extents[1] = 200.0f;
+ result = _navMeshQuery->findNearestPoly(point, extents, &_filter, &polyRef, closestPoint);
+ if (DT_SUCCESS == result && polyRef != INVALID_POLYREF)
+ {
+ *distance = dtVdist(closestPoint, point);
+ return polyRef;
+ }
+
+ return INVALID_POLYREF;
+}
+
+void PathGenerator::BuildPolyPath(Vector3 const& startPos, Vector3 const& endPos)
+{
+ // *** getting start/end poly logic ***
+
+ float distToStartPoly, distToEndPoly;
+ float startPoint[VERTEX_SIZE] = {startPos.y, startPos.z, startPos.x};
+ float endPoint[VERTEX_SIZE] = {endPos.y, endPos.z, endPos.x};
+
+ dtPolyRef startPoly = GetPolyByLocation(startPoint, &distToStartPoly);
+ dtPolyRef endPoly = GetPolyByLocation(endPoint, &distToEndPoly);
+
+ // we have a hole in our mesh
+ // make shortcut path and mark it as NOPATH ( with flying and swimming exception )
+ // its up to caller how he will use this info
+ if (startPoly == INVALID_POLYREF || endPoly == INVALID_POLYREF)
+ {
+ sLog->outDebug(LOG_FILTER_MAPS, "++ BuildPolyPath :: (startPoly == 0 || endPoly == 0)\n");
+ BuildShortcut();
+ bool path = _sourceUnit->GetTypeId() == TYPEID_UNIT && _sourceUnit->ToCreature()->CanFly();
+
+ bool waterPath = _sourceUnit->GetTypeId() == TYPEID_UNIT && _sourceUnit->ToCreature()->canSwim();
+ if (waterPath)
+ {
+ // Check both start and end points, if they're both in water, then we can *safely* let the creature move
+ for (uint32 i = 0; i < _pathPoints.size(); ++i)
+ {
+ ZLiquidStatus status = _sourceUnit->GetBaseMap()->getLiquidStatus(_pathPoints[i].x, _pathPoints[i].y, _pathPoints[i].z, MAP_ALL_LIQUIDS, NULL);
+ // One of the points is not in the water, cancel movement.
+ if (status == LIQUID_MAP_NO_WATER)
+ {
+ waterPath = false;
+ break;
+ }
+ }
+ }
+
+ _type = (path || waterPath) ? PathType(PATHFIND_NORMAL | PATHFIND_NOT_USING_PATH) : PATHFIND_NOPATH;
+ return;
+ }
+
+ // we may need a better number here
+ bool farFromPoly = (distToStartPoly > 7.0f || distToEndPoly > 7.0f);
+ if (farFromPoly)
+ {
+ sLog->outDebug(LOG_FILTER_MAPS, "++ BuildPolyPath :: farFromPoly distToStartPoly=%.3f distToEndPoly=%.3f\n", distToStartPoly, distToEndPoly);
+
+ bool buildShotrcut = false;
+ if (_sourceUnit->GetTypeId() == TYPEID_UNIT)
+ {
+ Creature* owner = (Creature*)_sourceUnit;
+
+ Vector3 p = (distToStartPoly > 7.0f) ? startPos : endPos;
+ if (_sourceUnit->GetBaseMap()->IsUnderWater(p.x, p.y, p.z))
+ {
+ sLog->outDebug(LOG_FILTER_MAPS, "++ BuildPolyPath :: underWater case\n");
+ if (owner->canSwim())
+ buildShotrcut = true;
+ }
+ else
+ {
+ sLog->outDebug(LOG_FILTER_MAPS, "++ BuildPolyPath :: flying case\n");
+ if (owner->CanFly())
+ buildShotrcut = true;
+ }
+ }
+
+ if (buildShotrcut)
+ {
+ BuildShortcut();
+ _type = PathType(PATHFIND_NORMAL | PATHFIND_NOT_USING_PATH);
+ return;
+ }
+ else
+ {
+ float closestPoint[VERTEX_SIZE];
+ // we may want to use closestPointOnPolyBoundary instead
+ if (DT_SUCCESS == _navMeshQuery->closestPointOnPoly(endPoly, endPoint, closestPoint))
+ {
+ dtVcopy(endPoint, closestPoint);
+ SetActualEndPosition(Vector3(endPoint[2], endPoint[0], endPoint[1]));
+ }
+
+ _type = PATHFIND_INCOMPLETE;
+ }
+ }
+
+ // *** poly path generating logic ***
+
+ // start and end are on same polygon
+ // just need to move in straight line
+ if (startPoly == endPoly)
+ {
+ sLog->outDebug(LOG_FILTER_MAPS, "++ BuildPolyPath :: (startPoly == endPoly)\n");
+
+ BuildShortcut();
+
+ _pathPolyRefs[0] = startPoly;
+ _polyLength = 1;
+
+ _type = farFromPoly ? PATHFIND_INCOMPLETE : PATHFIND_NORMAL;
+ sLog->outDebug(LOG_FILTER_MAPS, "++ BuildPolyPath :: path type %d\n", _type);
+ return;
+ }
+
+ // look for startPoly/endPoly in current path
+ // TODO: we can merge it with getPathPolyByPosition() loop
+ bool startPolyFound = false;
+ bool endPolyFound = false;
+ uint32 pathStartIndex = 0;
+ uint32 pathEndIndex = 0;
+
+ if (_polyLength)
+ {
+ for (; pathStartIndex < _polyLength; ++pathStartIndex)
+ {
+ // here to carch few bugs
+ ASSERT(_pathPolyRefs[pathStartIndex] != INVALID_POLYREF);
+
+ if (_pathPolyRefs[pathStartIndex] == startPoly)
+ {
+ startPolyFound = true;
+ break;
+ }
+ }
+
+ for (pathEndIndex = _polyLength-1; pathEndIndex > pathStartIndex; --pathEndIndex)
+ if (_pathPolyRefs[pathEndIndex] == endPoly)
+ {
+ endPolyFound = true;
+ break;
+ }
+ }
+
+ if (startPolyFound && endPolyFound)
+ {
+ sLog->outDebug(LOG_FILTER_MAPS, "++ BuildPolyPath :: (startPolyFound && endPolyFound)\n");
+
+ // we moved along the path and the target did not move out of our old poly-path
+ // our path is a simple subpath case, we have all the data we need
+ // just "cut" it out
+
+ _polyLength = pathEndIndex - pathStartIndex + 1;
+ memmove(_pathPolyRefs, _pathPolyRefs + pathStartIndex, _polyLength * sizeof(dtPolyRef));
+ }
+ else if (startPolyFound && !endPolyFound)
+ {
+ sLog->outDebug(LOG_FILTER_MAPS, "++ BuildPolyPath :: (startPolyFound && !endPolyFound)\n");
+
+ // we are moving on the old path but target moved out
+ // so we have atleast part of poly-path ready
+
+ _polyLength -= pathStartIndex;
+
+ // try to adjust the suffix of the path instead of recalculating entire length
+ // at given interval the target cannot get too far from its last location
+ // thus we have less poly to cover
+ // sub-path of optimal path is optimal
+
+ // take ~80% of the original length
+ // TODO : play with the values here
+ uint32 prefixPolyLength = uint32(_polyLength * 0.8f + 0.5f);
+ memmove(_pathPolyRefs, _pathPolyRefs+pathStartIndex, prefixPolyLength * sizeof(dtPolyRef));
+
+ dtPolyRef suffixStartPoly = _pathPolyRefs[prefixPolyLength-1];
+
+ // we need any point on our suffix start poly to generate poly-path, so we need last poly in prefix data
+ float suffixEndPoint[VERTEX_SIZE];
+ if (DT_SUCCESS != _navMeshQuery->closestPointOnPoly(suffixStartPoly, endPoint, suffixEndPoint))
+ {
+ // we can hit offmesh connection as last poly - closestPointOnPoly() don't like that
+ // try to recover by using prev polyref
+ --prefixPolyLength;
+ suffixStartPoly = _pathPolyRefs[prefixPolyLength-1];
+ if (DT_SUCCESS != _navMeshQuery->closestPointOnPoly(suffixStartPoly, endPoint, suffixEndPoint))
+ {
+ // suffixStartPoly is still invalid, error state
+ BuildShortcut();
+ _type = PATHFIND_NOPATH;
+ return;
+ }
+ }
+
+ // generate suffix
+ uint32 suffixPolyLength = 0;
+ dtStatus dtResult = _navMeshQuery->findPath(
+ suffixStartPoly, // start polygon
+ endPoly, // end polygon
+ suffixEndPoint, // start position
+ endPoint, // end position
+ &_filter, // polygon search filter
+ _pathPolyRefs + prefixPolyLength - 1, // [out] path
+ (int*)&suffixPolyLength,
+ MAX_PATH_LENGTH-prefixPolyLength); // max number of polygons in output path
+
+ if (!suffixPolyLength || dtResult != DT_SUCCESS)
+ {
+ // this is probably an error state, but we'll leave it
+ // and hopefully recover on the next Update
+ // we still need to copy our preffix
+ sLog->outError(LOG_FILTER_MAPS, "%u's Path Build failed: 0 length path", _sourceUnit->GetGUIDLow());
+ }
+
+ sLog->outDebug(LOG_FILTER_MAPS, "++ m_polyLength=%u prefixPolyLength=%u suffixPolyLength=%u \n", _polyLength, prefixPolyLength, suffixPolyLength);
+
+ // new path = prefix + suffix - overlap
+ _polyLength = prefixPolyLength + suffixPolyLength - 1;
+ }
+ else
+ {
+ sLog->outDebug(LOG_FILTER_MAPS, "++ BuildPolyPath :: (!startPolyFound && !endPolyFound)\n");
+
+ // either we have no path at all -> first run
+ // or something went really wrong -> we aren't moving along the path to the target
+ // just generate new path
+
+ // free and invalidate old path data
+ Clear();
+
+ dtStatus dtResult = _navMeshQuery->findPath(
+ startPoly, // start polygon
+ endPoly, // end polygon
+ startPoint, // start position
+ endPoint, // end position
+ &_filter, // polygon search filter
+ _pathPolyRefs, // [out] path
+ (int*)&_polyLength,
+ MAX_PATH_LENGTH); // max number of polygons in output path
+
+ if (!_polyLength || dtResult != DT_SUCCESS)
+ {
+ // only happens if we passed bad data to findPath(), or navmesh is messed up
+ sLog->outError(LOG_FILTER_MAPS, "%u's Path Build failed: 0 length path", _sourceUnit->GetGUIDLow());
+ BuildShortcut();
+ _type = PATHFIND_NOPATH;
+ return;
+ }
+ }
+
+ // by now we know what type of path we can get
+ if (_pathPolyRefs[_polyLength - 1] == endPoly && !(_type & PATHFIND_INCOMPLETE))
+ _type = PATHFIND_NORMAL;
+ else
+ _type = PATHFIND_INCOMPLETE;
+
+ // generate the point-path out of our up-to-date poly-path
+ BuildPointPath(startPoint, endPoint);
+}
+
+void PathGenerator::BuildPointPath(const float *startPoint, const float *endPoint)
+{
+ float pathPoints[MAX_POINT_PATH_LENGTH*VERTEX_SIZE];
+ uint32 pointCount = 0;
+ dtStatus dtResult = DT_FAILURE;
+ if (_useStraightPath)
+ {
+ dtResult = _navMeshQuery->findStraightPath(
+ startPoint, // start position
+ endPoint, // end position
+ _pathPolyRefs, // current path
+ _polyLength, // lenth of current path
+ pathPoints, // [out] path corner points
+ NULL, // [out] flags
+ NULL, // [out] shortened path
+ (int*)&pointCount,
+ _pointPathLimit); // maximum number of points/polygons to use
+ }
+ else
+ {
+ dtResult = FindSmoothPath(
+ startPoint, // start position
+ endPoint, // end position
+ _pathPolyRefs, // current path
+ _polyLength, // length of current path
+ pathPoints, // [out] path corner points
+ (int*)&pointCount,
+ _pointPathLimit); // maximum number of points
+ }
+
+ if (pointCount < 2 || dtResult != DT_SUCCESS)
+ {
+ // only happens if pass bad data to findStraightPath or navmesh is broken
+ // single point paths can be generated here
+ // TODO : check the exact cases
+ sLog->outDebug(LOG_FILTER_MAPS, "++ PathGenerator::BuildPointPath FAILED! path sized %d returned\n", pointCount);
+ BuildShortcut();
+ _type = PATHFIND_NOPATH;
+ return;
+ }
+ else if (pointCount == _pointPathLimit)
+ {
+ sLog->outDebug(LOG_FILTER_MAPS, "++ PathGenerator::BuildPointPath FAILED! path sized %d returned, lower than limit set to %d\n", pointCount, _pointPathLimit);
+ BuildShortcut();
+ _type = PATHFIND_SHORT;
+ return;
+ }
+
+ _pathPoints.resize(pointCount);
+ for (uint32 i = 0; i < pointCount; ++i)
+ _pathPoints[i] = Vector3(pathPoints[i*VERTEX_SIZE+2], pathPoints[i*VERTEX_SIZE], pathPoints[i*VERTEX_SIZE+1]);
+
+ NormalizePath();
+
+ // first point is always our current location - we need the next one
+ SetActualEndPosition(_pathPoints[pointCount-1]);
+
+ // force the given destination, if needed
+ if (_forceDestination &&
+ (!(_type & PATHFIND_NORMAL) || !InRange(GetEndPosition(), GetActualEndPosition(), 1.0f, 1.0f)))
+ {
+ // we may want to keep partial subpath
+ if (Dist3DSqr(GetActualEndPosition(), GetEndPosition()) < 0.3f * Dist3DSqr(GetStartPosition(), GetEndPosition()))
+ {
+ SetActualEndPosition(GetEndPosition());
+ _pathPoints[_pathPoints.size()-1] = GetEndPosition();
+ }
+ else
+ {
+ SetActualEndPosition(GetEndPosition());
+ BuildShortcut();
+ }
+
+ _type = PathType(PATHFIND_NORMAL | PATHFIND_NOT_USING_PATH);
+ }
+
+ sLog->outDebug(LOG_FILTER_MAPS, "++ PathGenerator::BuildPointPath path type %d size %d poly-size %d\n", _type, pointCount, _polyLength);
+}
+
+void PathGenerator::NormalizePath()
+{
+ for (uint32 i = 0; i < _pathPoints.size(); ++i)
+ _sourceUnit->UpdateAllowedPositionZ(_pathPoints[i].x, _pathPoints[i].y, _pathPoints[i].z);
+}
+
+void PathGenerator::BuildShortcut()
+{
+ sLog->outDebug(LOG_FILTER_MAPS, "++ BuildShortcut :: making shortcut\n");
+
+ Clear();
+
+ // make two point path, our curr pos is the start, and dest is the end
+ _pathPoints.resize(2);
+
+ // set start and a default next position
+ _pathPoints[0] = GetStartPosition();
+ _pathPoints[1] = GetActualEndPosition();
+
+ NormalizePath();
+
+ _type = PATHFIND_SHORTCUT;
+}
+
+void PathGenerator::CreateFilter()
+{
+ uint16 includeFlags = 0;
+ uint16 excludeFlags = 0;
+
+ if (_sourceUnit->GetTypeId() == TYPEID_UNIT)
+ {
+ Creature* creature = (Creature*)_sourceUnit;
+ if (creature->canWalk())
+ includeFlags |= NAV_GROUND; // walk
+
+ // creatures don't take environmental damage
+ if (creature->canSwim())
+ includeFlags |= (NAV_WATER | NAV_MAGMA | NAV_SLIME); // swim
+ }
+ else // assume Player
+ {
+ // perfect support not possible, just stay 'safe'
+ includeFlags |= (NAV_GROUND | NAV_WATER | NAV_MAGMA | NAV_SLIME);
+ }
+
+ _filter.setIncludeFlags(includeFlags);
+ _filter.setExcludeFlags(excludeFlags);
+
+ UpdateFilter();
+}
+
+void PathGenerator::UpdateFilter()
+{
+ // allow creatures to cheat and use different movement types if they are moved
+ // forcefully into terrain they can't normally move in
+ if (_sourceUnit->IsInWater() || _sourceUnit->IsUnderWater())
+ {
+ uint16 includedFlags = _filter.getIncludeFlags();
+ includedFlags |= GetNavTerrain(_sourceUnit->GetPositionX(),
+ _sourceUnit->GetPositionY(),
+ _sourceUnit->GetPositionZ());
+
+ _filter.setIncludeFlags(includedFlags);
+ }
+}
+
+NavTerrain PathGenerator::GetNavTerrain(float x, float y, float z)
+{
+ LiquidData data;
+ _sourceUnit->GetBaseMap()->getLiquidStatus(x, y, z, MAP_ALL_LIQUIDS, &data);
+
+ switch (data.type_flags)
+ {
+ case MAP_LIQUID_TYPE_WATER:
+ case MAP_LIQUID_TYPE_OCEAN:
+ return NAV_WATER;
+ case MAP_LIQUID_TYPE_MAGMA:
+ return NAV_MAGMA;
+ case MAP_LIQUID_TYPE_SLIME:
+ return NAV_SLIME;
+ default:
+ return NAV_GROUND;
+ }
+}
+
+bool PathGenerator::HaveTile(const Vector3& p) const
+{
+ int tx = -1, ty = -1;
+ float point[VERTEX_SIZE] = {p.y, p.z, p.x};
+
+ _navMesh->calcTileLoc(point, &tx, &ty);
+
+ /// Workaround
+ /// For some reason, often the tx and ty variables wont get a valid value
+ /// Use this check to prevent getting negative tile coords and crashing on getTileAt
+ if (tx < 0 || ty < 0)
+ return false;
+
+ return (_navMesh->getTileAt(tx, ty) != NULL);
+}
+
+uint32 PathGenerator::FixupCorridor(dtPolyRef* path, uint32 npath, uint32 maxPath, dtPolyRef const* visited, uint32 nvisited)
+{
+ int32 furthestPath = -1;
+ int32 furthestVisited = -1;
+
+ // Find furthest common polygon.
+ for (int32 i = npath-1; i >= 0; --i)
+ {
+ bool found = false;
+ for (int32 j = nvisited-1; j >= 0; --j)
+ {
+ if (path[i] == visited[j])
+ {
+ furthestPath = i;
+ furthestVisited = j;
+ found = true;
+ }
+ }
+ if (found)
+ break;
+ }
+
+ // If no intersection found just return current path.
+ if (furthestPath == -1 || furthestVisited == -1)
+ return npath;
+
+ // Concatenate paths.
+
+ // Adjust beginning of the buffer to include the visited.
+ uint32 req = nvisited - furthestVisited;
+ uint32 orig = uint32(furthestPath + 1) < npath ? furthestPath + 1 : npath;
+ uint32 size = npath > orig ? npath - orig : 0;
+ if (req + size > maxPath)
+ size = maxPath-req;
+
+ if (size)
+ memmove(path + req, path + orig, size * sizeof(dtPolyRef));
+
+ // Store visited
+ for (uint32 i = 0; i < req; ++i)
+ path[i] = visited[(nvisited - 1) - i];
+
+ return req+size;
+}
+
+bool PathGenerator::GetSteerTarget(float const* startPos, float const* endPos,
+ float minTargetDist, dtPolyRef const* path, uint32 pathSize,
+ float* steerPos, unsigned char& steerPosFlag, dtPolyRef& steerPosRef)
+{
+ // Find steer target.
+ static const uint32 MAX_STEER_POINTS = 3;
+ float steerPath[MAX_STEER_POINTS*VERTEX_SIZE];
+ unsigned char steerPathFlags[MAX_STEER_POINTS];
+ dtPolyRef steerPathPolys[MAX_STEER_POINTS];
+ uint32 nsteerPath = 0;
+ dtStatus dtResult = _navMeshQuery->findStraightPath(startPos, endPos, path, pathSize,
+ steerPath, steerPathFlags, steerPathPolys, (int*)&nsteerPath, MAX_STEER_POINTS);
+ if (!nsteerPath || DT_SUCCESS != dtResult)
+ return false;
+
+ // Find vertex far enough to steer to.
+ uint32 ns = 0;
+ while (ns < nsteerPath)
+ {
+ // Stop at Off-Mesh link or when point is further than slop away.
+ if ((steerPathFlags[ns] & DT_STRAIGHTPATH_OFFMESH_CONNECTION) ||
+ !InRangeYZX(&steerPath[ns*VERTEX_SIZE], startPos, minTargetDist, 1000.0f))
+ break;
+ ns++;
+ }
+ // Failed to find good point to steer to.
+ if (ns >= nsteerPath)
+ return false;
+
+ dtVcopy(steerPos, &steerPath[ns*VERTEX_SIZE]);
+ steerPos[1] = startPos[1]; // keep Z value
+ steerPosFlag = steerPathFlags[ns];
+ steerPosRef = steerPathPolys[ns];
+
+ return true;
+}
+
+dtStatus PathGenerator::FindSmoothPath(float const* startPos, float const* endPos,
+ dtPolyRef const* polyPath, uint32 polyPathSize,
+ float* smoothPath, int* smoothPathSize, uint32 maxSmoothPathSize)
+{
+ *smoothPathSize = 0;
+ uint32 nsmoothPath = 0;
+
+ dtPolyRef polys[MAX_PATH_LENGTH];
+ memcpy(polys, polyPath, sizeof(dtPolyRef)*polyPathSize);
+ uint32 npolys = polyPathSize;
+
+ float iterPos[VERTEX_SIZE], targetPos[VERTEX_SIZE];
+ if (DT_SUCCESS != _navMeshQuery->closestPointOnPolyBoundary(polys[0], startPos, iterPos))
+ return DT_FAILURE;
+
+ if (DT_SUCCESS != _navMeshQuery->closestPointOnPolyBoundary(polys[npolys-1], endPos, targetPos))
+ return DT_FAILURE;
+
+ dtVcopy(&smoothPath[nsmoothPath*VERTEX_SIZE], iterPos);
+ nsmoothPath++;
+
+ // Move towards target a small advancement at a time until target reached or
+ // when ran out of memory to store the path.
+ while (npolys && nsmoothPath < maxSmoothPathSize)
+ {
+ // Find location to steer towards.
+ float steerPos[VERTEX_SIZE];
+ unsigned char steerPosFlag;
+ dtPolyRef steerPosRef = INVALID_POLYREF;
+
+ if (!GetSteerTarget(iterPos, targetPos, SMOOTH_PATH_SLOP, polys, npolys, steerPos, steerPosFlag, steerPosRef))
+ break;
+
+ bool endOfPath = (steerPosFlag & DT_STRAIGHTPATH_END);
+ bool offMeshConnection = (steerPosFlag & DT_STRAIGHTPATH_OFFMESH_CONNECTION);
+
+ // Find movement delta.
+ float delta[VERTEX_SIZE];
+ dtVsub(delta, steerPos, iterPos);
+ float len = dtSqrt(dtVdot(delta,delta));
+ // If the steer target is end of path or off-mesh link, do not move past the location.
+ if ((endOfPath || offMeshConnection) && len < SMOOTH_PATH_STEP_SIZE)
+ len = 1.0f;
+ else
+ len = SMOOTH_PATH_STEP_SIZE / len;
+
+ float moveTgt[VERTEX_SIZE];
+ dtVmad(moveTgt, iterPos, delta, len);
+
+ // Move
+ float result[VERTEX_SIZE];
+ const static uint32 MAX_VISIT_POLY = 16;
+ dtPolyRef visited[MAX_VISIT_POLY];
+
+ uint32 nvisited = 0;
+ _navMeshQuery->moveAlongSurface(polys[0], iterPos, moveTgt, &_filter, result, visited, (int*)&nvisited, MAX_VISIT_POLY);
+ npolys = FixupCorridor(polys, npolys, MAX_PATH_LENGTH, visited, nvisited);
+
+ _navMeshQuery->getPolyHeight(polys[0], result, &result[1]);
+ result[1] += 0.5f;
+ dtVcopy(iterPos, result);
+
+ // Handle end of path and off-mesh links when close enough.
+ if (endOfPath && InRangeYZX(iterPos, steerPos, SMOOTH_PATH_SLOP, 1.0f))
+ {
+ // Reached end of path.
+ dtVcopy(iterPos, targetPos);
+ if (nsmoothPath < maxSmoothPathSize)
+ {
+ dtVcopy(&smoothPath[nsmoothPath*VERTEX_SIZE], iterPos);
+ nsmoothPath++;
+ }
+ break;
+ }
+ else if (offMeshConnection && InRangeYZX(iterPos, steerPos, SMOOTH_PATH_SLOP, 1.0f))
+ {
+ // Advance the path up to and over the off-mesh connection.
+ dtPolyRef prevRef = INVALID_POLYREF;
+ dtPolyRef polyRef = polys[0];
+ uint32 npos = 0;
+ while (npos < npolys && polyRef != steerPosRef)
+ {
+ prevRef = polyRef;
+ polyRef = polys[npos];
+ npos++;
+ }
+
+ for (uint32 i = npos; i < npolys; ++i)
+ polys[i-npos] = polys[i];
+
+ npolys -= npos;
+
+ // Handle the connection.
+ float startPos[VERTEX_SIZE], endPos[VERTEX_SIZE];
+ if (DT_SUCCESS == _navMesh->getOffMeshConnectionPolyEndPoints(prevRef, polyRef, startPos, endPos))
+ {
+ if (nsmoothPath < maxSmoothPathSize)
+ {
+ dtVcopy(&smoothPath[nsmoothPath*VERTEX_SIZE], startPos);
+ nsmoothPath++;
+ }
+ // Move position at the other side of the off-mesh link.
+ dtVcopy(iterPos, endPos);
+ _navMeshQuery->getPolyHeight(polys[0], iterPos, &iterPos[1]);
+ iterPos[1] += 0.5f;
+ }
+ }
+
+ // Store results.
+ if (nsmoothPath < maxSmoothPathSize)
+ {
+ dtVcopy(&smoothPath[nsmoothPath*VERTEX_SIZE], iterPos);
+ nsmoothPath++;
+ }
+ }
+
+ *smoothPathSize = nsmoothPath;
+
+ // this is most likely a loop
+ return nsmoothPath < MAX_POINT_PATH_LENGTH ? DT_SUCCESS : DT_FAILURE;
+}
+
+bool PathGenerator::InRangeYZX(const float* v1, const float* v2, float r, float h) const
+{
+ const float dx = v2[0] - v1[0];
+ const float dy = v2[1] - v1[1]; // elevation
+ const float dz = v2[2] - v1[2];
+ return (dx * dx + dz * dz) < r * r && fabsf(dy) < h;
+}
+
+bool PathGenerator::InRange(Vector3 const& p1, Vector3 const& p2, float r, float h) const
+{
+ Vector3 d = p1 - p2;
+ return (d.x * d.x + d.y * d.y) < r * r && fabsf(d.z) < h;
+}
+
+float PathGenerator::Dist3DSqr(Vector3 const& p1, Vector3 const& p2) const
+{
+ return (p1 - p2).squaredLength();
+}
diff --git a/src/server/game/Movement/PathGenerator.h b/src/server/game/Movement/PathGenerator.h
new file mode 100644
index 00000000000..a20f900b584
--- /dev/null
+++ b/src/server/game/Movement/PathGenerator.h
@@ -0,0 +1,135 @@
+/*
+ * Copyright (C) 2005-2011 MaNGOS <http://getmangos.com/>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#ifndef _PATH_GENERATOR_H
+#define _PATH_GENERATOR_H
+
+#include "SharedDefines.h"
+#include "DetourNavMesh.h"
+#include "DetourNavMeshQuery.h"
+#include "MoveSplineInitArgs.h"
+
+using Movement::Vector3;
+using Movement::PointsArray;
+
+class Unit;
+
+// 74*4.0f=296y number_of_points*interval = max_path_len
+// this is way more than actual evade range
+// I think we can safely cut those down even more
+#define MAX_PATH_LENGTH 74
+#define MAX_POINT_PATH_LENGTH 74
+
+#define SMOOTH_PATH_STEP_SIZE 4.0f
+#define SMOOTH_PATH_SLOP 0.3f
+
+#define VERTEX_SIZE 3
+#define INVALID_POLYREF 0
+
+enum PathType
+{
+ PATHFIND_BLANK = 0x00, // path not built yet
+ PATHFIND_NORMAL = 0x01, // normal path
+ PATHFIND_SHORTCUT = 0x02, // travel through obstacles, terrain, air, etc (old behavior)
+ PATHFIND_INCOMPLETE = 0x04, // we have partial path to follow - getting closer to target
+ PATHFIND_NOPATH = 0x08, // no valid path at all or error in generating one
+ PATHFIND_NOT_USING_PATH = 0x10, // used when we are either flying/swiming or on map w/o mmaps
+ PATHFIND_SHORT = 0x20, // path is longer or equal to its limited path length
+};
+
+class PathGenerator
+{
+ public:
+ PathGenerator(Unit const* owner);
+ ~PathGenerator();
+
+ // Calculate the path from owner to given destination
+ // return: true if new path was calculated, false otherwise (no change needed)
+ bool CalculatePath(float destX, float destY, float destZ, bool forceDest = false);
+
+ // option setters - use optional
+ void SetUseStraightPath(bool useStraightPath) { _useStraightPath = useStraightPath; };
+ void SetPathLengthLimit(float distance) { _pointPathLimit = std::min<uint32>(uint32(distance/SMOOTH_PATH_STEP_SIZE), MAX_POINT_PATH_LENGTH); };
+
+ // result getters
+ Vector3 const& GetStartPosition() const { return _startPosition; }
+ Vector3 const& GetEndPosition() const { return _endPosition; }
+ Vector3 const& GetActualEndPosition() const { return _actualEndPosition; }
+
+ PointsArray& GetPath() { return _pathPoints; }
+ PathType GetPathType() const { return _type; }
+
+ private:
+
+ dtPolyRef _pathPolyRefs[MAX_PATH_LENGTH]; // array of detour polygon references
+ uint32 _polyLength; // number of polygons in the path
+
+ PointsArray _pathPoints; // our actual (x,y,z) path to the target
+ PathType _type; // tells what kind of path this is
+
+ bool _useStraightPath; // type of path will be generated
+ bool _forceDestination; // when set, we will always arrive at given point
+ uint32 _pointPathLimit; // limit point path size; min(this, MAX_POINT_PATH_LENGTH)
+
+ Vector3 _startPosition; // {x, y, z} of current location
+ Vector3 _endPosition; // {x, y, z} of the destination
+ Vector3 _actualEndPosition;// {x, y, z} of the closest possible point to given destination
+
+ Unit const* const _sourceUnit; // the unit that is moving
+ dtNavMesh const* _navMesh; // the nav mesh
+ dtNavMeshQuery const* _navMeshQuery; // the nav mesh query used to find the path
+
+ dtQueryFilter _filter; // use single filter for all movements, update it when needed
+
+ void SetStartPosition(Vector3 Point) { _startPosition = Point; }
+ void SetEndPosition(Vector3 Point) { _actualEndPosition = Point; _endPosition = Point; }
+ void SetActualEndPosition(Vector3 Point) { _actualEndPosition = Point; }
+ void NormalizePath();
+
+ void Clear()
+ {
+ _polyLength = 0;
+ _pathPoints.clear();
+ }
+
+ bool InRange(Vector3 const& p1, Vector3 const& p2, float r, float h) const;
+ float Dist3DSqr(Vector3 const& p1, Vector3 const& p2) const;
+ bool InRangeYZX(float const* v1, float const* v2, float r, float h) const;
+
+ dtPolyRef GetPathPolyByPosition(dtPolyRef const* polyPath, uint32 polyPathSize, float const* Point, float* Distance = NULL) const;
+ dtPolyRef GetPolyByLocation(float const* Point, float* Distance) const;
+ bool HaveTile(Vector3 const& p) const;
+
+ void BuildPolyPath(Vector3 const& startPos, Vector3 const& endPos);
+ void BuildPointPath(float const* startPoint, float const* endPoint);
+ void BuildShortcut();
+
+ NavTerrain GetNavTerrain(float x, float y, float z);
+ void CreateFilter();
+ void UpdateFilter();
+
+ // smooth path aux functions
+ uint32 FixupCorridor(dtPolyRef* path, uint32 npath, uint32 maxPath, dtPolyRef const* visited, uint32 nvisited);
+ bool GetSteerTarget(float const* startPos, float const* endPos, float minTargetDist, dtPolyRef const* path, uint32 pathSize, float* steerPos,
+ unsigned char& steerPosFlag, dtPolyRef& steerPosRef);
+ dtStatus FindSmoothPath(float const* startPos, float const* endPos,
+ dtPolyRef const* polyPath, uint32 polyPathSize,
+ float* smoothPath, int* smoothPathSize, uint32 smoothPathMaxSize);
+};
+
+#endif
diff --git a/src/server/game/Movement/Spline/MoveSpline.h b/src/server/game/Movement/Spline/MoveSpline.h
index 8e51e2678dd..b18166ea615 100644
--- a/src/server/game/Movement/Spline/MoveSpline.h
+++ b/src/server/game/Movement/Spline/MoveSpline.h
@@ -78,18 +78,17 @@ namespace Movement
UpdateResult _updateState(int32& ms_time_diff);
int32 next_timestamp() const { return spline.length(point_Idx+1); }
int32 segment_time_elapsed() const { return next_timestamp()-time_passed; }
- int32 Duration() const { return spline.length(); }
int32 timeElapsed() const { return Duration() - time_passed; }
int32 timePassed() const { return time_passed; }
public:
+ int32 Duration() const { return spline.length(); }
const MySpline& _Spline() const { return spline; }
int32 _currentSplineIdx() const { return point_Idx; }
void _Finalize();
void _Interrupt() { splineflags.done = true;}
public:
-
void Initialize(const MoveSplineInitArgs&);
bool Initialized() const { return !spline.empty(); }
diff --git a/src/server/game/Movement/Spline/MoveSplineInit.cpp b/src/server/game/Movement/Spline/MoveSplineInit.cpp
index 61178f3f9ad..a8ae40926b8 100644
--- a/src/server/game/Movement/Spline/MoveSplineInit.cpp
+++ b/src/server/game/Movement/Spline/MoveSplineInit.cpp
@@ -58,14 +58,15 @@ namespace Movement
return MOVE_RUN;
}
- void MoveSplineInit::Launch()
+ int32 MoveSplineInit::Launch()
{
MoveSpline& move_spline = *unit.movespline;
Location real_position(unit.GetPositionX(), unit.GetPositionY(), unit.GetPositionZMinusOffset(), unit.GetOrientation());
// Elevators also use MOVEMENTFLAG_ONTRANSPORT but we do not keep track of their position changes
- if (unit.GetTransGUID())
+ if (unit->HasUnitMovementFlag(MOVEMENTFLAG_ONTRANSPORT) && unit.GetTransGUID())
{
+ transport = true;
real_position.x = unit.GetTransOffsetX();
real_position.y = unit.GetTransOffsetY();
real_position.z = unit.GetTransOffsetZ();
@@ -73,21 +74,21 @@ namespace Movement
}
// there is a big chance that current position is unknown if current state is not finalized, need compute it
- // this also allows calculate spline position and update map position in much greater intervals
+ // this also allows CalculatePath spline position and update map position in much greater intervals
// Don't compute for transport movement if the unit is in a motion between two transports
if (!move_spline.Finalized() && move_spline.onTransport == (unit.GetTransGUID() != 0))
real_position = move_spline.ComputePosition();
// should i do the things that user should do? - no.
if (args.path.empty())
- return;
+ return 0;
// correct first vertex
args.path[0] = real_position;
args.initialOrientation = real_position.orientation;
move_spline.onTransport = (unit.GetTransGUID() != 0);
- uint32 moveFlags = unit.m_movementInfo.GetMovementFlags();
+ uint32 moveFlags = unit->m_movementInfo.GetMovementFlags();
if (args.flags.walkmode)
moveFlags |= MOVEMENTFLAG_WALKING;
else
@@ -96,10 +97,10 @@ namespace Movement
moveFlags |= MOVEMENTFLAG_FORWARD;
if (!args.HasVelocity)
- args.velocity = unit.GetSpeed(SelectSpeedType(moveFlags));
+ args.velocity = unit->GetSpeed(SelectSpeedType(moveFlags));
- if (!args.Validate(&unit))
- return;
+ if (!args.Validate(unit))
+ return 0;
if (moveFlags & MOVEMENTFLAG_ROOT)
moveFlags &= ~MOVEMENTFLAG_MASK_MOVING;
@@ -108,7 +109,7 @@ namespace Movement
move_spline.Initialize(args);
WorldPacket data(SMSG_MONSTER_MOVE, 64);
- data.append(unit.GetPackGUID());
+ data.append(unit->GetPackGUID());
if (unit.GetTransGUID())
{
data.SetOpcode(SMSG_MONSTER_MOVE_TRANSPORT);
@@ -117,7 +118,9 @@ namespace Movement
}
PacketBuilder::WriteMonsterMove(move_spline, data);
- unit.SendMessageToSet(&data, true);
+ unit->SendMessageToSet(&data,true);
+
+ return move_spline.Duration();
}
void MoveSplineInit::Stop()
@@ -150,10 +153,10 @@ namespace Movement
{
args.splineId = splineIdGen.NewId();
// Elevators also use MOVEMENTFLAG_ONTRANSPORT but we do not keep track of their position changes
- args.TransformForTransport = unit.GetTransGUID();
+ args.TransformForTransport = unit.HasUnitMovementFlag(MOVEMENTFLAG_ONTRANSPORT) && unit->GetTransGUID();
// mix existing state into new
args.flags.walkmode = unit.m_movementInfo.HasMovementFlag(MOVEMENTFLAG_WALKING);
- args.flags.flying = unit.m_movementInfo.HasMovementFlag(MovementFlags(MOVEMENTFLAG_CAN_FLY | MOVEMENTFLAG_DISABLE_GRAVITY));
+ args.flags.flying = unit.m_movementInfo.HasMovementFlag(MOVEMENTFLAG_CAN_FLY | MOVEMENTFLAG_DISABLE_GRAVITY);
args.flags.smoothGroundPath = true; // enabled by default, CatmullRom mode or client config "pathSmoothing" will disable this
}
@@ -167,9 +170,9 @@ namespace Movement
{
if (args.TransformForTransport)
{
- if (Unit* vehicle = unit.GetVehicleBase())
+ if (Unit* vehicle = unit->GetVehicleBase())
angle -= vehicle->GetOrientation();
- else if (Transport* transport = unit.GetTransport())
+ else if (Transport* transport = unit->GetTransport())
angle -= transport->GetOrientation();
}
@@ -177,8 +180,19 @@ namespace Movement
args.flags.EnableFacingAngle();
}
- void MoveSplineInit::MoveTo(Vector3 const& dest)
+ void MoveSplineInit::MoveTo(const Vector3& dest, bool generatePath, bool forceDestination)
{
+ if (generatePath)
+ {
+ PathGenerator path(unit);
+ bool result = path.CalculatePath(dest.x, dest.y, dest.z, forceDestination);
+ if (result && path.GetPathType() & ~PATHFIND_NOPATH)
+ {
+ MovebyPath(path.GetPath());
+ return;
+ }
+ }
+
args.path_Idx_offset = 0;
args.path.resize(2);
TransportPathTransform transform(unit, args.TransformForTransport);
@@ -195,7 +209,7 @@ namespace Movement
{
if (_transformForTransport)
{
- if (TransportBase* transport = _owner.GetDirectTransport())
+ if (TransportBase* transport = _owner->GetDirectTransport())
{
float unused = 0.0f; // need reference
transport->CalculatePassengerOffset(input.x, input.y, input.z, unused);
diff --git a/src/server/game/Movement/Spline/MoveSplineInit.h b/src/server/game/Movement/Spline/MoveSplineInit.h
index 74e5cdfa9f4..79e0f085d44 100644
--- a/src/server/game/Movement/Spline/MoveSplineInit.h
+++ b/src/server/game/Movement/Spline/MoveSplineInit.h
@@ -20,6 +20,7 @@
#define TRINITYSERVER_MOVESPLINEINIT_H
#include "MoveSplineInitArgs.h"
+#include "PathGenerator.h"
class Unit;
@@ -37,12 +38,12 @@ namespace Movement
class TransportPathTransform
{
public:
- TransportPathTransform(Unit& owner, bool transformForTransport)
+ TransportPathTransform(Unit* owner, bool transformForTransport)
: _owner(owner), _transformForTransport(transformForTransport) { }
Vector3 operator()(Vector3 input);
private:
- Unit& _owner;
+ Unit* _owner;
bool _transformForTransport;
};
@@ -52,11 +53,11 @@ namespace Movement
{
public:
- explicit MoveSplineInit(Unit& m);
+ explicit MoveSplineInit(Unit* m);
/* Final pass of initialization that launches spline movement.
*/
- void Launch();
+ int32 Launch();
/* Final pass of initialization that stops movement.
*/
@@ -87,10 +88,10 @@ namespace Movement
*/
void MovebyPath(const PointsArray& path, int32 pointId = 0);
- /* Initializes simple A to B mition, A is current unit's position, B is destination
+ /* Initializes simple A to B motion, A is current unit's position, B is destination
*/
- void MoveTo(const Vector3& destination);
- void MoveTo(float x, float y, float z);
+ void MoveTo(const Vector3& destination, bool generatePath = true, bool forceDestination = false);
+ void MoveTo(float x, float y, float z, bool generatePath = true, bool forceDestination = false);
/* Sets Id of fisrt point of the path. When N-th path point will be done ILisener will notify that pointId + N done
* Needed for waypoint movement where path splitten into parts
@@ -145,7 +146,7 @@ namespace Movement
protected:
MoveSplineInitArgs args;
- Unit& unit;
+ Unit* unit;
};
inline void MoveSplineInit::SetFly() { args.flags.flying = true; }
@@ -165,9 +166,9 @@ namespace Movement
std::transform(controls.begin(), controls.end(), args.path.begin(), TransportPathTransform(unit, args.TransformForTransport));
}
- inline void MoveSplineInit::MoveTo(float x, float y, float z)
+ inline void MoveSplineInit::MoveTo(float x, float y, float z, bool generatePath, bool forceDestination)
{
- MoveTo(G3D::Vector3(x, y, z));
+ MoveTo(G3D::Vector3(x, y, z), generatePath, forceDestination);
}
inline void MoveSplineInit::SetParabolic(float amplitude, float time_shift)
diff --git a/src/server/game/Movement/Waypoints/Path.h b/src/server/game/Movement/Waypoints/Path.h
index 3f78a640384..39f05184cf6 100644
--- a/src/server/game/Movement/Waypoints/Path.h
+++ b/src/server/game/Movement/Waypoints/Path.h
@@ -20,10 +20,12 @@
#define TRINITYCORE_PATH_H
#include "Common.h"
-#include <vector>
+#include <deque>
-struct SimplePathNode
+struct PathNode
{
+ PathNode(): x(0.0f), y(0.0f), z(0.0f) { }
+ PathNode(float _x, float _y, float _z): x(_x), y(_y), z(_z) { }
float x, y, z;
};
template<typename PathElem, typename PathNode = PathElem>
@@ -36,6 +38,20 @@ class Path
void resize(unsigned int sz) { i_nodes.resize(sz); }
void clear() { i_nodes.clear(); }
void erase(uint32 idx) { i_nodes.erase(i_nodes.begin()+idx); }
+ void crop(unsigned int start, unsigned int end)
+ {
+ while(start && !i_nodes.empty())
+ {
+ i_nodes.pop_front();
+ --start;
+ }
+
+ while(end && !i_nodes.empty())
+ {
+ i_nodes.pop_back();
+ --end;
+ }
+ }
float GetTotalLength(uint32 start, uint32 end) const
{
@@ -76,10 +92,9 @@ class Path
void set(size_t idx, PathElem elem) { i_nodes[idx] = elem; }
protected:
- std::vector<PathElem> i_nodes;
+ std::deque<PathElem> i_nodes;
};
-typedef Path<SimplePathNode> SimplePath;
+typedef Path<PathNode> SimplePath;
#endif
-
diff --git a/src/server/game/Movement/Waypoints/WaypointManager.h b/src/server/game/Movement/Waypoints/WaypointManager.h
index 07f855380f9..b17714f1a51 100644
--- a/src/server/game/Movement/Waypoints/WaypointManager.h
+++ b/src/server/game/Movement/Waypoints/WaypointManager.h
@@ -68,4 +68,3 @@ class WaypointMgr
#define sWaypointMgr ACE_Singleton<WaypointMgr, ACE_Null_Mutex>::instance()
#endif
-
diff --git a/src/server/game/Scripting/ScriptLoader.cpp b/src/server/game/Scripting/ScriptLoader.cpp
index 8cbc4b62424..5b31d4a6950 100644
--- a/src/server/game/Scripting/ScriptLoader.cpp
+++ b/src/server/game/Scripting/ScriptLoader.cpp
@@ -66,6 +66,7 @@ void AddSC_list_commandscript();
void AddSC_lookup_commandscript();
void AddSC_message_commandscript();
void AddSC_misc_commandscript();
+void AddSC_mmaps_commandscript();
void AddSC_modify_commandscript();
void AddSC_npc_commandscript();
void AddSC_quest_commandscript();
@@ -695,6 +696,7 @@ void AddCommandScripts()
AddSC_list_commandscript();
AddSC_message_commandscript();
AddSC_misc_commandscript();
+ AddSC_mmaps_commandscript();
AddSC_modify_commandscript();
AddSC_npc_commandscript();
AddSC_quest_commandscript();
diff --git a/src/server/game/Spells/Auras/SpellAuraEffects.cpp b/src/server/game/Spells/Auras/SpellAuraEffects.cpp
index 18128660436..ac7f0348b84 100644
--- a/src/server/game/Spells/Auras/SpellAuraEffects.cpp
+++ b/src/server/game/Spells/Auras/SpellAuraEffects.cpp
@@ -504,8 +504,6 @@ int32 AuraEffect::CalculateAmount(Unit* caster)
}
}
- float DoneActualBenefit = 0.0f;
-
// custom amount calculations go here
switch (GetAuraType())
{
@@ -538,176 +536,14 @@ int32 AuraEffect::CalculateAmount(Unit* caster)
}
break;
case SPELL_AURA_SCHOOL_ABSORB:
- m_canBeRecalculated = false;
- if (!caster)
- break;
- switch (GetSpellInfo()->SpellFamilyName)
- {
- case SPELLFAMILY_MAGE:
- // Ice Barrier
- if (GetSpellInfo()->SpellFamilyFlags[1] & 0x1 && GetSpellInfo()->SpellFamilyFlags[2] & 0x8)
- {
- // +87% from sp bonus
- DoneActualBenefit += caster->SpellBaseDamageBonusDone(m_spellInfo->GetSchoolMask()) * 0.87f;
- }
- // Mage Ward
- else if (GetSpellInfo()->SpellFamilyFlags[0] & 0x8 && GetSpellInfo()->SpellFamilyFlags[2] & 0x8)
- {
- // +80.68% from sp bonus
- DoneActualBenefit += caster->SpellBaseDamageBonusDone(m_spellInfo->GetSchoolMask()) * 0.8068f;
- }
- break;
- case SPELLFAMILY_WARLOCK:
- // Shadow Ward
- if (m_spellInfo->SpellFamilyFlags[2] & 0x80000000)
- {
- // +80.68% from sp bonus
- DoneActualBenefit += caster->SpellBaseDamageBonusDone(m_spellInfo->GetSchoolMask()) * 0.8068f;
- }
- break;
- case SPELLFAMILY_PRIEST:
- // Power Word: Shield
- if (GetSpellInfo()->SpellFamilyFlags[0] & 0x1)
- {
- // +80.68% from sp bonus
- DoneActualBenefit += caster->SpellBaseHealingBonusDone(m_spellInfo->GetSchoolMask()) * 0.8068f;
- DoneActualBenefit *= caster->CalculateLevelPenalty(GetSpellInfo());
-
- amount += int32(DoneActualBenefit);
-
- // Twin Disciplines
- if (AuraEffect const* pAurEff = caster->GetAuraEffect(SPELL_AURA_MOD_DAMAGE_PERCENT_DONE, SPELLFAMILY_PRIEST, 2292, 0))
- AddPct(amount, pAurEff->GetAmount());
-
- // Reuse variable, not sure if this code below can be moved before Twin Disciplines
- DoneActualBenefit = float(amount);
- DoneActualBenefit *= caster->GetTotalAuraMultiplier(SPELL_AURA_MOD_HEALING_DONE_PERCENT);
- amount = int32(DoneActualBenefit);
-
- return amount;
- }
- break;
- default:
- break;
- }
- break;
case SPELL_AURA_MANA_SHIELD:
m_canBeRecalculated = false;
- if (!caster)
- break;
- // Mana Shield
- if (GetSpellInfo()->SpellFamilyName == SPELLFAMILY_MAGE && GetSpellInfo()->SpellFamilyFlags[0] & 0x8000 && m_spellInfo->SpellFamilyFlags[2] & 0x8)
- {
- // +80.7% from +spd bonus
- DoneActualBenefit += caster->SpellBaseDamageBonusDone(m_spellInfo->GetSchoolMask()) * 0.807f;
- }
- break;
- case SPELL_AURA_DUMMY:
- if (!caster)
- break;
- // Earth Shield
- if (GetSpellInfo()->SpellFamilyName == SPELLFAMILY_SHAMAN && m_spellInfo->SpellFamilyFlags[1] & 0x400)
- {
- amount = caster->SpellHealingBonusDone(GetBase()->GetUnitOwner(), GetSpellInfo(), amount, SPELL_DIRECT_DAMAGE);
- amount = GetBase()->GetUnitOwner()->SpellHealingBonusTaken(caster, GetSpellInfo(), amount, SPELL_DIRECT_DAMAGE);
- }
- break;
- case SPELL_AURA_PERIODIC_DAMAGE:
- if (!caster)
- break;
- // Rip
- if (GetSpellInfo()->SpellFamilyName == SPELLFAMILY_DRUID && m_spellInfo->SpellFamilyFlags[0] & 0x00800000)
- {
- m_canBeRecalculated = false;
- // 0.01*$AP*cp
- if (caster->GetTypeId() != TYPEID_PLAYER)
- break;
-
- uint8 cp = caster->ToPlayer()->GetComboPoints();
-
- // Idol of Feral Shadows. Cant be handled as SpellMod in SpellAura:Dummy due its dependency from CPs
- if (AuraEffect const* aurEff = caster->GetAuraEffect(34241, EFFECT_0))
- amount += cp * aurEff->GetAmount();
- // Idol of Worship. Cant be handled as SpellMod in SpellAura:Dummy due its dependency from CPs
- else if (AuraEffect const* aurEff = caster->GetAuraEffect(60774, EFFECT_0))
- amount += cp * aurEff->GetAmount();
-
- amount += uint32(CalculatePct(caster->GetTotalAttackPowerValue(BASE_ATTACK), cp));
- }
- // Rend
- else if (GetSpellInfo()->SpellFamilyName == SPELLFAMILY_WARRIOR && GetSpellInfo()->SpellFamilyFlags[0] & 0x20)
- {
- m_canBeRecalculated = false;
- // ${0.25 * 6 * (($MWB + $mwb) / 2 + $AP / 14 * $MWS)} bonus per tick
- float ap = caster->GetTotalAttackPowerValue(BASE_ATTACK);
- int32 mws = caster->GetAttackTime(BASE_ATTACK);
- float mwb_min = caster->GetWeaponDamageRange(BASE_ATTACK, MINDAMAGE);
- float mwb_max = caster->GetWeaponDamageRange(BASE_ATTACK, MAXDAMAGE);
- float mwb = ((mwb_min + mwb_max) / 2 + ap * mws / 14000) * 0.25f * 6.0f;
- amount += int32(caster->ApplyEffectModifiers(m_spellInfo, m_effIndex, mwb));
- }
- break;
- case SPELL_AURA_PERIODIC_ENERGIZE:
- switch (m_spellInfo->Id)
- {
case 57669: // Replenishment (0.2% from max)
amount = CalculatePct(GetBase()->GetUnitOwner()->GetMaxPower(POWER_MANA), amount);
break;
case 61782: // Infinite Replenishment
amount = GetBase()->GetUnitOwner()->GetMaxPower(POWER_MANA) * 0.0025f;
break;
- case 29166: // Innervate
- ApplyPct(amount, float(GetBase()->GetUnitOwner()->GetCreatePowers(POWER_MANA)) / GetTotalTicks());
- break;
- case 48391: // Owlkin Frenzy
- ApplyPct(amount, GetBase()->GetUnitOwner()->GetCreatePowers(POWER_MANA));
- break;
- default:
- break;
- }
- break;
- case SPELL_AURA_PERIODIC_HEAL:
- if (!caster)
- break;
- // Lightwell Renew
- if (GetSpellInfo()->SpellFamilyName == SPELLFAMILY_PRIEST && m_spellInfo->SpellFamilyFlags[2] & 0x4000)
- {
- if (caster->GetTypeId() == TYPEID_PLAYER)
- // Bonus from Glyph of Lightwell
- if (AuraEffect* modHealing = caster->GetAuraEffect(55673, 0))
- AddPct(amount, modHealing->GetAmount());
- }
- break;
- case SPELL_AURA_MOD_THREAT:
- {
- uint8 level_diff = 0;
- float multiplier = 0.0f;
- switch (GetId())
- {
- // Arcane Shroud
- case 26400:
- level_diff = GetBase()->GetUnitOwner()->getLevel() - 60;
- multiplier = 2;
- break;
- // The Eye of Diminution
- case 28862:
- level_diff = GetBase()->GetUnitOwner()->getLevel() - 60;
- multiplier = 1;
- break;
- }
- if (level_diff > 0)
- amount += int32(multiplier * level_diff);
- break;
- }
- case SPELL_AURA_MOD_INCREASE_HEALTH:
- // Vampiric Blood
- if (GetId() == 55233)
- amount = GetBase()->GetUnitOwner()->CountPctFromMaxHealth(amount);
- break;
- case SPELL_AURA_MOD_INCREASE_SPEED:
- // Dash - do not set speed if not in cat form
- if (GetSpellInfo()->SpellFamilyName == SPELLFAMILY_DRUID && GetSpellInfo()->SpellFamilyFlags[2] & 0x00000008)
- amount = GetBase()->GetUnitOwner()->GetShapeshiftForm() == FORM_CAT ? amount : 0;
break;
case SPELL_AURA_MOUNTED:
if (MountCapabilityEntry const* mountCapability = GetBase()->GetUnitOwner()->GetMountCapability(uint32(GetMiscValueB())))
@@ -751,11 +587,6 @@ int32 AuraEffect::CalculateAmount(Unit* caster)
default:
break;
}
- if (DoneActualBenefit != 0.0f)
- {
- DoneActualBenefit *= caster->CalculateLevelPenalty(GetSpellInfo());
- amount += (int32)DoneActualBenefit;
- }
GetBase()->CallScriptEffectCalcAmountHandlers(const_cast<AuraEffect const*>(this), amount, m_canBeRecalculated);
amount *= GetBase()->GetStackAmount();
@@ -845,32 +676,6 @@ void AuraEffect::CalculateSpellMod()
{
switch (GetAuraType())
{
- case SPELL_AURA_DUMMY:
- switch (GetSpellInfo()->SpellFamilyName)
- {
- case SPELLFAMILY_DRUID:
- switch (GetId())
- {
- case 34246: // Idol of the Emerald Queen
- case 60779: // Idol of Lush Moss
- {
- if (!m_spellmod)
- {
- m_spellmod = new SpellModifier(GetBase());
- m_spellmod->op = SPELLMOD_DOT;
- m_spellmod->type = SPELLMOD_FLAT;
- m_spellmod->spellId = GetId();
- m_spellmod->mask[1] = 0x0010;
- }
- m_spellmod->value = GetAmount()/7;
- }
- break;
- }
- break;
- default:
- break;
- }
- break;
case SPELL_AURA_ADD_FLAT_MODIFIER:
case SPELL_AURA_ADD_PCT_MODIFIER:
if (!m_spellmod)
@@ -879,7 +684,7 @@ void AuraEffect::CalculateSpellMod()
m_spellmod->op = SpellModOp(GetMiscValue());
ASSERT(m_spellmod->op < MAX_SPELLMOD);
- m_spellmod->type = SpellModType(GetAuraType()); // SpellModType value == spell aura types
+ m_spellmod->type = SpellModType(GetAuraType()); // SpellModType value == spell aura types
m_spellmod->spellId = GetId();
m_spellmod->mask = GetSpellInfo()->Effects[GetEffIndex()].SpellClassMask;
m_spellmod->charges = GetBase()->GetCharges();
@@ -4916,10 +4721,6 @@ void AuraEffect::HandleAuraDummy(AuraApplication const* aurApp, uint8 mode, bool
if (Aura* newAura = target->AddAura(71564, target))
newAura->SetStackAmount(newAura->GetSpellInfo()->StackAmount);
break;
- case 59628: // Tricks of the Trade
- if (caster && caster->GetMisdirectionTarget())
- target->SetReducedThreatPercent(100, caster->GetMisdirectionTarget()->GetGUID());
- break;
}
}
// AT REMOVE
@@ -5014,20 +4815,6 @@ void AuraEffect::HandleAuraDummy(AuraApplication const* aurApp, uint8 mode, bool
if (GetId() == 61777)
target->CastSpell(target, GetAmount(), true);
break;
- case SPELLFAMILY_ROGUE:
- // Tricks of the trade
- switch (GetId())
- {
- case 59628: //Tricks of the trade buff on rogue (6sec duration)
- target->SetReducedThreatPercent(0, 0);
- break;
- case 57934: //Tricks of the trade buff on rogue (30sec duration)
- if (aurApp->GetRemoveMode() == AURA_REMOVE_BY_EXPIRE || !caster->GetMisdirectionTarget())
- target->SetReducedThreatPercent(0, 0);
- else
- target->SetReducedThreatPercent(0, caster->GetMisdirectionTarget()->GetGUID());
- break;
- }
default:
break;
}
diff --git a/src/server/game/Spells/Auras/SpellAuras.cpp b/src/server/game/Spells/Auras/SpellAuras.cpp
index d578b3507c6..64b8d889519 100644
--- a/src/server/game/Spells/Auras/SpellAuras.cpp
+++ b/src/server/game/Spells/Auras/SpellAuras.cpp
@@ -1388,17 +1388,6 @@ void Aura::HandleAuraSpecificMods(AuraApplication const* aurApp, Unit* caster, b
// mods at aura apply or remove
switch (GetSpellInfo()->SpellFamilyName)
{
- case SPELLFAMILY_GENERIC:
- switch (GetId())
- {
- case 50720: // Vigilance
- if (apply)
- target->CastSpell(caster, 59665, true, 0, 0, caster->GetGUID());
- else
- target->SetReducedThreatPercent(0, 0);
- break;
- }
- break;
case SPELLFAMILY_DRUID:
// Enrage
if ((GetSpellInfo()->SpellFamilyFlags[0] & 0x80000) && GetSpellInfo()->SpellIconID == 961)
diff --git a/src/server/game/Spells/Spell.cpp b/src/server/game/Spells/Spell.cpp
index 2619ef0eeb6..88d23179712 100644
--- a/src/server/game/Spells/Spell.cpp
+++ b/src/server/game/Spells/Spell.cpp
@@ -491,7 +491,7 @@ SpellValue::SpellValue(SpellInfo const* proto)
Spell::Spell(Unit* caster, SpellInfo const* info, TriggerCastFlags triggerFlags, uint64 originalCasterGUID, bool skipCheck) :
m_spellInfo(sSpellMgr->GetSpellForDifficultyFromSpell(info, caster)),
m_caster((info->AttributesEx6 & SPELL_ATTR6_CAST_BY_CHARMER && caster->GetCharmerOrOwner()) ? caster->GetCharmerOrOwner() : caster)
-, m_spellValue(new SpellValue(m_spellInfo))
+, m_spellValue(new SpellValue(m_spellInfo)), m_preGeneratedPath(PathGenerator(m_caster))
{
m_customError = SPELL_CUSTOM_ERROR_NONE;
m_skipCheck = skipCheck;
@@ -611,6 +611,7 @@ Spell::~Spell()
if (m_caster && m_caster->GetTypeId() == TYPEID_PLAYER)
ASSERT(m_caster->ToPlayer()->m_spellModTakingSpell != this);
+
delete m_spellValue;
CheckEffectExecuteData();
@@ -1342,11 +1343,6 @@ void Spell::SelectImplicitAreaTargets(SpellEffIndex effIndex, SpellImplicitTarge
}
}
- // todo: move to scripts, but we must call it before resize list by MaxAffectedTargets
- // Intimidating Shout
- if (m_spellInfo->Id == 5246 && effIndex != EFFECT_0)
- unitTargets.remove(m_targets.GetUnitTarget());
-
// Other special target selection goes here
if (uint32 maxTargets = m_spellValue->MaxAffectedTargets)
Trinity::Containers::RandomResizeList(unitTargets, maxTargets);
@@ -5189,12 +5185,30 @@ SpellCastResult Spell::CheckCast(bool strict)
if (strict && m_caster->IsScriptOverriden(m_spellInfo, 6953))
m_caster->RemoveMovementImpairingAuras();
}
+
if (m_caster->HasUnitState(UNIT_STATE_ROOT))
return SPELL_FAILED_ROOTED;
+
+ Unit* target = m_targets.GetUnitTarget();
+
+ if (!target)
+ return SPELL_FAILED_DONT_REPORT;
+
if (m_caster->GetTypeId() == TYPEID_PLAYER)
- if (Unit* target = m_targets.GetUnitTarget())
- if (!target->isAlive())
- return SPELL_FAILED_BAD_TARGETS;
+ if (!target->isAlive())
+ return SPELL_FAILED_BAD_TARGETS;
+
+ Position pos;
+ target->GetContactPoint(m_caster, pos.m_positionX, pos.m_positionY, pos.m_positionZ);
+ target->GetFirstCollisionPosition(pos, CONTACT_DISTANCE, target->GetRelativeAngle(m_caster));
+
+ m_preGeneratedPath.SetPathLengthLimit(m_spellInfo->GetMaxRange(true) * 1.5f);
+ bool result = m_preGeneratedPath.CalculatePath(pos.m_positionX, pos.m_positionY, pos.m_positionZ + target->GetObjectSize());
+ if (m_preGeneratedPath.GetPathType() & PATHFIND_SHORT)
+ return SPELL_FAILED_OUT_OF_RANGE;
+ else if (!result)
+ return SPELL_FAILED_NOPATH;
+
break;
}
case SPELL_EFFECT_SKINNING:
diff --git a/src/server/game/Spells/Spell.h b/src/server/game/Spells/Spell.h
index c7415d4c9d3..27474645d77 100644
--- a/src/server/game/Spells/Spell.h
+++ b/src/server/game/Spells/Spell.h
@@ -23,6 +23,7 @@
#include "SharedDefines.h"
#include "ObjectMgr.h"
#include "SpellInfo.h"
+#include "PathGenerator.h"
class Unit;
class Player;
@@ -669,6 +670,7 @@ class Spell
bool m_skipCheck;
uint8 m_auraScaleMask;
+ PathGenerator m_preGeneratedPath;
ByteBuffer * m_effectExecuteData[MAX_SPELL_EFFECTS];
diff --git a/src/server/game/Spells/SpellEffects.cpp b/src/server/game/Spells/SpellEffects.cpp
index e86ac6ef97f..aac9240e387 100644
--- a/src/server/game/Spells/SpellEffects.cpp
+++ b/src/server/game/Spells/SpellEffects.cpp
@@ -63,6 +63,7 @@
#include "GameObjectAI.h"
#include "AccountMgr.h"
#include "InstanceScript.h"
+#include "PathGenerator.h"
#include "Guild.h"
#include "GuildMgr.h"
#include "ReputationMgr.h"
@@ -756,12 +757,6 @@ void Spell::EffectTriggerSpell(SpellEffIndex effIndex)
m_caster->CastSpell(unitTarget, spell->Id, true);
return;
}
- // Righteous Defense
- case 31980:
- {
- m_caster->CastSpell(unitTarget, 31790, true);
- return;
- }
// Cloak of Shadows
case 35729:
{
@@ -1012,32 +1007,8 @@ void Spell::EffectTeleportUnits(SpellEffIndex /*effIndex*/)
return;
// Pre effects
- uint8 uiMaxSafeLevel = 0;
switch (m_spellInfo->Id)
{
- case 48129: // Scroll of Recall
- uiMaxSafeLevel = 40;
- case 60320: // Scroll of Recall II
- if (!uiMaxSafeLevel)
- uiMaxSafeLevel = 70;
- case 60321: // Scroll of Recal III
- if (!uiMaxSafeLevel)
- uiMaxSafeLevel = 80;
-
- if (unitTarget->getLevel() > uiMaxSafeLevel)
- {
- unitTarget->AddAura(60444, unitTarget); //Apply Lost! Aura
-
- // ALLIANCE from 60323 to 60330 - HORDE from 60328 to 60335
- uint32 spellId = 60323;
- if (m_caster->ToPlayer()->GetTeam() == HORDE)
- spellId += 5;
-
- spellId += urand(0, 7);
- m_caster->CastSpell(m_caster, spellId, true);
- return;
- }
- break;
case 66550: // teleports outside (Isle of Conquest)
if (Player* target = unitTarget->ToPlayer())
{
@@ -1061,7 +1032,7 @@ void Spell::EffectTeleportUnits(SpellEffIndex /*effIndex*/)
// If not exist data for dest location - return
if (!m_targets.HasDst())
{
- sLog->outError(LOG_FILTER_SPELLS_AURAS, "Spell::EffectTeleportUnits - does not have destination for spell ID %u\n", m_spellInfo->Id);
+ sLog->outError(LOG_FILTER_SPELLS_AURAS, "Spell::EffectTeleportUnits - does not have destination for spellId %u.", m_spellInfo->Id);
return;
}
@@ -1432,10 +1403,6 @@ void Spell::EffectHealPct(SpellEffIndex /*effIndex*/)
if (!m_originalCaster)
return;
- // Rune Tap - Party
- if (m_spellInfo->Id == 59754 && unitTarget == m_caster)
- return;
-
uint32 heal = m_originalCaster->SpellHealingBonusDone(unitTarget, m_spellInfo, unitTarget->CountPctFromMaxHealth(damage), HEAL);
heal = unitTarget->SpellHealingBonusTaken(m_originalCaster, m_spellInfo, heal, HEAL);
@@ -3440,23 +3407,6 @@ void Spell::EffectScriptEffect(SpellEffIndex effIndex)
return;
unitTarget->RemoveAurasDueToSpell(m_spellInfo->Effects[effIndex].CalcValue());
break;
- // PX-238 Winter Wondervolt TRAP
- case 26275:
- {
- uint32 spells[4] = { 26272, 26157, 26273, 26274 };
-
- // check presence
- for (uint8 j = 0; j < 4; ++j)
- if (unitTarget->HasAuraEffect(spells[j], 0))
- return;
-
- // select spell
- uint32 iTmpSpellId = spells[urand(0, 3)];
-
- // cast
- unitTarget->CastSpell(unitTarget, iTmpSpellId, true);
- return;
- }
// Bending Shinbone
case 8856:
{
@@ -3502,14 +3452,6 @@ void Spell::EffectScriptEffect(SpellEffIndex effIndex)
m_caster->CastSpell(unitTarget, 22682, true);
return;
}
- // Piccolo of the Flaming Fire
- case 17512:
- {
- if (!unitTarget || unitTarget->GetTypeId() != TYPEID_PLAYER)
- return;
- unitTarget->HandleEmoteCommand(EMOTE_STATE_DANCE);
- return;
- }
// Decimate
case 28374:
case 54426:
@@ -3652,17 +3594,6 @@ void Spell::EffectScriptEffect(SpellEffIndex effIndex)
m_caster->MonsterTextEmote(buf, 0);
break;
}
- // Vigilance
- case 50725:
- {
- if (!unitTarget || unitTarget->GetTypeId() != TYPEID_PLAYER)
- return;
-
- // Remove Taunt cooldown
- unitTarget->ToPlayer()->RemoveSpellCooldown(355, true);
-
- return;
- }
// Death Knight Initiate Visual
case 51519:
{
@@ -3821,17 +3752,6 @@ void Spell::EffectScriptEffect(SpellEffIndex effIndex)
}
return;
}
- case 63845: // Create Lance
- {
- if (m_caster->GetTypeId() != TYPEID_PLAYER)
- return;
-
- if (m_caster->ToPlayer()->GetTeam() == ALLIANCE)
- m_caster->CastSpell(m_caster, 63914, true);
- else
- m_caster->CastSpell(m_caster, 63919, true);
- return;
- }
case 59317: // Teleporting
{
@@ -4025,46 +3945,6 @@ void Spell::EffectScriptEffect(SpellEffIndex effIndex)
return;
}
}
- case SPELLFAMILY_POTION:
- {
- switch (m_spellInfo->Id)
- {
- // Netherbloom
- case 28702:
- {
- if (!unitTarget)
- return;
- // 25% chance of casting a random buff
- if (roll_chance_i(75))
- return;
-
- // triggered spells are 28703 to 28707
- // Note: some sources say, that there was the possibility of
- // receiving a debuff. However, this seems to be removed by a patch.
- const uint32 spellid = 28703;
-
- // don't overwrite an existing aura
- for (uint8 i = 0; i < 5; ++i)
- if (unitTarget->HasAura(spellid + i))
- return;
- unitTarget->CastSpell(unitTarget, spellid+urand(0, 4), true);
- break;
- }
-
- // Nightmare Vine
- case 28720:
- {
- if (!unitTarget)
- return;
- // 25% chance of casting Nightmare Pollen
- if (roll_chance_i(75))
- return;
- unitTarget->CastSpell(unitTarget, 28721, true);
- break;
- }
- }
- break;
- }
case SPELLFAMILY_DEATHKNIGHT:
{
// Pestilence
@@ -4085,19 +3965,6 @@ void Spell::EffectScriptEffect(SpellEffIndex effIndex)
}
break;
}
- case SPELLFAMILY_WARRIOR:
- {
- // Shattering Throw
- if (m_spellInfo->SpellFamilyFlags[1] & 0x00400000)
- {
- if (!unitTarget)
- return;
- // remove shields, will still display immune to damage part
- unitTarget->RemoveAurasWithMechanic(1<<MECHANIC_IMMUNE_SHIELD, AURA_REMOVE_BY_ENEMY_SPELL);
- return;
- }
- break;
- }
}
// normal DB scripted effect
@@ -4580,45 +4447,12 @@ void Spell::EffectResurrect(SpellEffIndex effIndex)
if (effectHandleMode != SPELL_EFFECT_HANDLE_HIT_TARGET)
return;
- if (!unitTarget)
- return;
- if (unitTarget->GetTypeId() != TYPEID_PLAYER)
+ if (!unitTarget || unitTarget->GetTypeId() != TYPEID_PLAYER)
return;
- if (unitTarget->isAlive())
- return;
- if (!unitTarget->IsInWorld())
+ if (unitTarget->isAlive() || !unitTarget->IsInWorld())
return;
- switch (m_spellInfo->Id)
- {
- // Defibrillate (Goblin Jumper Cables) have 33% chance on success
- case 8342:
- if (roll_chance_i(67))
- {
- m_caster->CastSpell(m_caster, 8338, true, m_CastItem);
- return;
- }
- break;
- // Defibrillate (Goblin Jumper Cables XL) have 50% chance on success
- case 22999:
- if (roll_chance_i(50))
- {
- m_caster->CastSpell(m_caster, 23055, true, m_CastItem);
- return;
- }
- break;
- // Defibrillate (Gnomish Army Knife) have 67% chance on success_list
- case 54732:
- if (roll_chance_i(33))
- {
- return;
- }
- break;
- default:
- break;
- }
-
Player* target = unitTarget->ToPlayer();
if (target->IsRessurectRequested()) // already have one active request
@@ -4810,25 +4644,24 @@ void Spell::EffectSkinning(SpellEffIndex /*effIndex*/)
void Spell::EffectCharge(SpellEffIndex /*effIndex*/)
{
+ if (!unitTarget)
+ return;
+
if (effectHandleMode == SPELL_EFFECT_HANDLE_LAUNCH_TARGET)
{
- if (!unitTarget)
- return;
-
- float angle = unitTarget->GetRelativeAngle(m_caster);
- Position pos;
-
- unitTarget->GetContactPoint(m_caster, pos.m_positionX, pos.m_positionY, pos.m_positionZ);
- unitTarget->GetFirstCollisionPosition(pos, unitTarget->GetObjectSize(), angle);
-
- m_caster->GetMotionMaster()->MoveCharge(pos.m_positionX, pos.m_positionY, pos.m_positionZ + unitTarget->GetObjectSize());
+ if (m_preGeneratedPath.GetPathType() & PATHFIND_NOPATH)
+ {
+ Position pos;
+ unitTarget->GetContactPoint(m_caster, pos.m_positionX, pos.m_positionY, pos.m_positionZ);
+ unitTarget->GetFirstCollisionPosition(pos, unitTarget->GetObjectSize(), unitTarget->GetRelativeAngle(m_caster));
+ m_caster->GetMotionMaster()->MoveCharge(pos.m_positionX, pos.m_positionY, pos.m_positionZ);
+ }
+ else
+ m_caster->GetMotionMaster()->MoveCharge(m_preGeneratedPath);
}
if (effectHandleMode == SPELL_EFFECT_HANDLE_HIT_TARGET)
{
- if (!unitTarget)
- return;
-
// not all charge effects used in negative spells
if (!m_spellInfo->IsPositive() && m_caster->GetTypeId() == TYPEID_PLAYER)
m_caster->Attack(unitTarget, true);
@@ -4864,26 +4697,10 @@ void Spell::EffectKnockBack(SpellEffIndex effIndex)
if (creatureTarget->isWorldBoss() || creatureTarget->IsDungeonBoss())
return;
- // Spells with SPELL_EFFECT_KNOCK_BACK(like Thunderstorm) can't knoback target if target has ROOT/STUN
+ // Spells with SPELL_EFFECT_KNOCK_BACK (like Thunderstorm) can't knockback target if target has ROOT/STUN
if (unitTarget->HasUnitState(UNIT_STATE_ROOT | UNIT_STATE_STUNNED))
return;
- // Typhoon
- if (m_spellInfo->SpellFamilyName == SPELLFAMILY_DRUID && m_spellInfo->SpellFamilyFlags[1] & 0x01000000)
- {
- // Glyph of Typhoon
- if (m_caster->HasAura(62135))
- return;
- }
-
- // Thunderstorm
- if (m_spellInfo->SpellFamilyName == SPELLFAMILY_SHAMAN && m_spellInfo->SpellFamilyFlags[1] & 0x00002000)
- {
- // Glyph of Thunderstorm
- if (m_caster->HasAura(62132))
- return;
- }
-
// Instantly interrupt non melee spells being casted
if (unitTarget->IsNonMeleeSpellCasted(true))
unitTarget->InterruptNonMeleeSpells(true);
@@ -5687,7 +5504,7 @@ void Spell::EffectRedirectThreat(SpellEffIndex /*effIndex*/)
return;
if (unitTarget)
- m_caster->SetReducedThreatPercent((uint32)damage, unitTarget->GetGUID());
+ m_caster->SetRedirectThreat(unitTarget->GetGUID(), uint32(damage));
}
void Spell::EffectGameObjectDamage(SpellEffIndex /*effIndex*/)
diff --git a/src/server/game/World/World.cpp b/src/server/game/World/World.cpp
index 4b027e9ebbf..879f3865302 100644
--- a/src/server/game/World/World.cpp
+++ b/src/server/game/World/World.cpp
@@ -21,6 +21,7 @@
*/
#include "Common.h"
+#include "Memory.h"
#include "DatabaseEnv.h"
#include "Config.h"
#include "SystemConfig.h"
@@ -55,6 +56,7 @@
#include "TemporarySummon.h"
#include "WaypointMovementGenerator.h"
#include "VMapFactory.h"
+#include "MMapFactory.h"
#include "GameEventMgr.h"
#include "PoolMgr.h"
#include "GridNotifiersImpl.h"
@@ -137,6 +139,7 @@ World::~World()
delete command;
VMAP::VMapFactory::clear();
+ MMAP::MMapFactory::clear();
//TODO free addSessQueue
}
@@ -1143,6 +1146,15 @@ void World::LoadConfigSettings(bool reload)
if (dataPath.at(dataPath.length()-1) != '/' && dataPath.at(dataPath.length()-1) != '\\')
dataPath.push_back('/');
+#if PLATFORM == PLATFORM_UNIX || PLATFORM == PLATFORM_APPLE
+ if (dataPath[0] == '~')
+ {
+ const char* home = getenv("HOME");
+ if (home)
+ dataPath.replace(0, 1, home);
+ }
+#endif
+
if (reload)
{
if (dataPath != m_dataPath)
@@ -1154,22 +1166,23 @@ void World::LoadConfigSettings(bool reload)
sLog->outInfo(LOG_FILTER_SERVER_LOADING, "Using DataDir %s", m_dataPath.c_str());
}
+ m_bool_configs[CONFIG_ENABLE_MMAPS] = ConfigMgr::GetBoolDefault("mmap.enablePathFinding", false);
+ sLog->outInfo(LOG_FILTER_SERVER_LOADING, "WORLD: MMap data directory is: %smmaps", m_dataPath.c_str());
+
m_bool_configs[CONFIG_VMAP_INDOOR_CHECK] = ConfigMgr::GetBoolDefault("vmap.enableIndoorCheck", 0);
bool enableIndoor = ConfigMgr::GetBoolDefault("vmap.enableIndoorCheck", true);
bool enableLOS = ConfigMgr::GetBoolDefault("vmap.enableLOS", true);
bool enableHeight = ConfigMgr::GetBoolDefault("vmap.enableHeight", true);
- bool enablePetLOS = ConfigMgr::GetBoolDefault("vmap.petLOS", true);
if (!enableHeight)
sLog->outError(LOG_FILTER_SERVER_LOADING, "VMap height checking disabled! Creatures movements and other various things WILL be broken! Expect no support.");
VMAP::VMapFactory::createOrGetVMapManager()->setEnableLineOfSightCalc(enableLOS);
VMAP::VMapFactory::createOrGetVMapManager()->setEnableHeightCalc(enableHeight);
- sLog->outInfo(LOG_FILTER_SERVER_LOADING, "VMap support included. LineOfSight: %i, getHeight: %i, indoorCheck: %i PetLOS: %i", enableLOS, enableHeight, enableIndoor, enablePetLOS);
+ sLog->outInfo(LOG_FILTER_SERVER_LOADING, "VMap support included. LineOfSight: %i, getHeight: %i, indoorCheck: %i", enableLOS, enableHeight, enableIndoor);
sLog->outInfo(LOG_FILTER_SERVER_LOADING, "VMap data directory is: %svmaps", m_dataPath.c_str());
m_int_configs[CONFIG_MAX_WHO] = ConfigMgr::GetIntDefault("MaxWhoListReturns", 49);
- m_bool_configs[CONFIG_PET_LOS] = ConfigMgr::GetBoolDefault("vmap.petLOS", true);
m_bool_configs[CONFIG_START_ALL_SPELLS] = ConfigMgr::GetBoolDefault("PlayerStart.AllSpells", false);
if (m_bool_configs[CONFIG_START_ALL_SPELLS])
sLog->outWarn(LOG_FILTER_SERVER_LOADING, "PlayerStart.AllSpells enabled - may not function as intended!");
@@ -1245,6 +1258,7 @@ void World::LoadConfigSettings(bool reload)
// misc
m_bool_configs[CONFIG_PDUMP_NO_PATHS] = ConfigMgr::GetBoolDefault("PlayerDump.DisallowPaths", true);
m_bool_configs[CONFIG_PDUMP_NO_OVERWRITE] = ConfigMgr::GetBoolDefault("PlayerDump.DisallowOverwrite", true);
+ m_bool_configs[CONFIG_UI_QUESTLEVELS_IN_DIALOGS] = ConfigMgr::GetBoolDefault("UI.ShowQuestLevelsInDialogs", false);
// call ScriptMgr if we're reloading the configuration
m_bool_configs[CONFIG_WINTERGRASP_ENABLE] = ConfigMgr::GetBoolDefault("Wintergrasp.Enable", false);
@@ -1270,6 +1284,9 @@ void World::SetInitialWorldSettings()
///- Initialize the random number generator
srand((unsigned int)time(NULL));
+ ///- Initialize detour memory management
+ dtAllocSetCustom(dtCustomAlloc, dtCustomFree);
+
///- Initialize config settings
LoadConfigSettings();
@@ -1414,8 +1431,8 @@ void World::SetInitialWorldSettings()
sLog->outInfo(LOG_FILTER_SERVER_LOADING, "Loading Item Random Enchantments Table...");
LoadRandomEnchantmentsTable();
- sLog->outInfo(LOG_FILTER_SERVER_LOADING, "Loading Disables");
- DisableMgr::LoadDisables(); // must be before loading quests and items
+ sLog->outInfo(LOG_FILTER_SERVER_LOADING, "Loading Disables"); // must be before loading quests and items
+ DisableMgr::LoadDisables();
sLog->outInfo(LOG_FILTER_SERVER_LOADING, "Loading Items..."); // must be after LoadRandomEnchantmentsTable and LoadPageTexts
sObjectMgr->LoadItemTemplates();
@@ -1598,6 +1615,7 @@ void World::SetInitialWorldSettings()
///- Load dynamic data tables from the database
sLog->outInfo(LOG_FILTER_SERVER_LOADING, "Loading Item Auctions...");
sAuctionMgr->LoadAuctionItems();
+
sLog->outInfo(LOG_FILTER_SERVER_LOADING, "Loading Auctions...");
sAuctionMgr->LoadAuctions();
@@ -1607,6 +1625,7 @@ void World::SetInitialWorldSettings()
sLog->outInfo(LOG_FILTER_SERVER_LOADING, "Loading Guild rewards...");
sGuildMgr->LoadGuildRewards();
+ sLog->outInfo(LOG_FILTER_SERVER_LOADING, "Loading Guilds...");
sGuildMgr->LoadGuilds();
sGuildFinderMgr->LoadFromDB();
diff --git a/src/server/game/World/World.h b/src/server/game/World/World.h
index cca1ac39728..6c86057eefb 100644
--- a/src/server/game/World/World.h
+++ b/src/server/game/World/World.h
@@ -145,7 +145,6 @@ enum WorldBoolConfigs
CONFIG_ARENA_LOG_EXTENDED_INFO,
CONFIG_OFFHAND_CHECK_AT_SPELL_UNLEARN,
CONFIG_VMAP_INDOOR_CHECK,
- CONFIG_PET_LOS,
CONFIG_START_ALL_SPELLS,
CONFIG_START_ALL_EXPLORED,
CONFIG_START_ALL_REP,
@@ -171,8 +170,10 @@ enum WorldBoolConfigs
CONFIG_QUEST_IGNORE_AUTO_ACCEPT,
CONFIG_QUEST_IGNORE_AUTO_COMPLETE,
CONFIG_WARDEN_ENABLED,
+ CONFIG_ENABLE_MMAPS,
CONFIG_WINTERGRASP_ENABLE,
CONFIG_GUILD_LEVELING_ENABLED,
+ CONFIG_UI_QUESTLEVELS_IN_DIALOGS, // Should we add quest levels to the title in the NPC dialogs?
BOOL_CONFIG_VALUE_COUNT
};
diff --git a/src/server/scripts/CMakeLists.txt b/src/server/scripts/CMakeLists.txt
index 5ccd244ef7f..a32a42b8172 100644
--- a/src/server/scripts/CMakeLists.txt
+++ b/src/server/scripts/CMakeLists.txt
@@ -45,6 +45,8 @@ message("")
include_directories(
${CMAKE_BINARY_DIR}
+ ${CMAKE_SOURCE_DIR}/dep/recastnavigation/Detour
+ ${CMAKE_SOURCE_DIR}/dep/recastnavigation/Recast
${CMAKE_SOURCE_DIR}/dep/g3dlite/include
${CMAKE_SOURCE_DIR}/dep/SFMT
${CMAKE_SOURCE_DIR}/dep/zlib
diff --git a/src/server/scripts/Commands/CMakeLists.txt b/src/server/scripts/Commands/CMakeLists.txt
index 97e9b35e6cd..7b9e2444952 100644
--- a/src/server/scripts/Commands/CMakeLists.txt
+++ b/src/server/scripts/Commands/CMakeLists.txt
@@ -42,6 +42,7 @@ set(scripts_STAT_SRCS
Commands/cs_server.cpp
Commands/cs_titles.cpp
Commands/cs_wp.cpp
+ Commands/cs_mmaps.cpp
# Commands/cs_pdump.cpp
# Commands/cs_channel.cpp
# Commands/cs_pet.cpp
diff --git a/src/server/scripts/Commands/cs_disable.cpp b/src/server/scripts/Commands/cs_disable.cpp
index 37e282cac8e..34738777c85 100644
--- a/src/server/scripts/Commands/cs_disable.cpp
+++ b/src/server/scripts/Commands/cs_disable.cpp
@@ -48,6 +48,7 @@ public:
{ "achievement_criteria", SEC_ADMINISTRATOR, true, &HandleRemoveDisableAchievementCriteriaCommand, "", NULL },
{ "outdoorpvp", SEC_ADMINISTRATOR, true, &HandleRemoveDisableOutdoorPvPCommand, "", NULL },
{ "vmap", SEC_ADMINISTRATOR, true, &HandleRemoveDisableVmapCommand, "", NULL },
+ { "mmap", SEC_ADMINISTRATOR, true, &HandleRemoveDisableMMapCommand, "", NULL },
{ NULL, 0, false, NULL, "", NULL }
};
static ChatCommand addDisableCommandTable[] =
@@ -59,6 +60,7 @@ public:
{ "achievement_criteria", SEC_ADMINISTRATOR, true, &HandleAddDisableAchievementCriteriaCommand, "", NULL },
{ "outdoorpvp", SEC_ADMINISTRATOR, true, &HandleAddDisableOutdoorPvPCommand, "", NULL },
{ "vmap", SEC_ADMINISTRATOR, true, &HandleAddDisableVmapCommand, "", NULL },
+ { "mmap", SEC_ADMINISTRATOR, true, &HandleAddDisableMMapCommand, "", NULL },
{ NULL, 0, false, NULL, "", NULL }
};
static ChatCommand disableCommandTable[] =
@@ -172,6 +174,17 @@ public:
disableTypeStr = "vmap";
break;
}
+ case DISABLE_TYPE_MMAP:
+ {
+ if (!sMapStore.LookupEntry(entry))
+ {
+ handler->PSendSysMessage(LANG_COMMAND_NOMAPFOUND);
+ handler->SetSentErrorMessage(true);
+ return false;
+ }
+ disableTypeStr = "mmap";
+ break;
+ }
default:
break;
}
@@ -256,6 +269,14 @@ public:
return HandleAddDisables(handler, args, DISABLE_TYPE_VMAP);
}
+ static bool HandleAddDisableMMapCommand(ChatHandler* handler, char const* args)
+ {
+ if (!*args)
+ return false;
+
+ return HandleAddDisables(handler, args, DISABLE_TYPE_MMAP);
+ }
+
static bool HandleRemoveDisables(ChatHandler* handler, char const* args, uint8 disableType)
{
char* entryStr = strtok((char*)args, " ");
@@ -289,6 +310,9 @@ public:
case DISABLE_TYPE_VMAP:
disableTypeStr = "vmap";
break;
+ case DISABLE_TYPE_MMAP:
+ disableTypeStr = "mmap";
+ break;
}
PreparedStatement* stmt = NULL;
@@ -367,6 +391,14 @@ public:
return HandleRemoveDisables(handler, args, DISABLE_TYPE_VMAP);
}
+
+ static bool HandleRemoveDisableMMapCommand(ChatHandler* handler, char const* args)
+ {
+ if (!*args)
+ return false;
+
+ return HandleRemoveDisables(handler, args, DISABLE_TYPE_MMAP);
+ }
};
void AddSC_disable_commandscript()
diff --git a/src/server/scripts/Commands/cs_misc.cpp b/src/server/scripts/Commands/cs_misc.cpp
index a1098cff5d3..18dbeba8f89 100644
--- a/src/server/scripts/Commands/cs_misc.cpp
+++ b/src/server/scripts/Commands/cs_misc.cpp
@@ -33,6 +33,8 @@
#include "ace/INET_Addr.h"
#include "Player.h"
#include "Pet.h"
+#include "LFG.h"
+#include "GroupMgr.h"
class misc_commandscript : public CommandScript
{
@@ -46,6 +48,8 @@ public:
{ "leader", SEC_ADMINISTRATOR, false, &HandleGroupLeaderCommand, "", NULL },
{ "disband", SEC_ADMINISTRATOR, false, &HandleGroupDisbandCommand, "", NULL },
{ "remove", SEC_ADMINISTRATOR, false, &HandleGroupRemoveCommand, "", NULL },
+ { "join", SEC_ADMINISTRATOR, false, &HandleGroupJoinCommand, "", NULL },
+ { "list", SEC_ADMINISTRATOR, false, &HandleGroupListCommand, "", NULL },
{ NULL, 0, false, NULL, "", NULL }
};
static ChatCommand petCommandTable[] =
@@ -1734,6 +1738,29 @@ public:
else
handler->PSendSysMessage(LANG_PINFO_MAP_OFFLINE, map->name, areaName.c_str());
+ stmt = CharacterDatabase.GetPreparedStatement(CHAR_SEL_GUILD_MEMBER_EXTENDED);
+ stmt->setUInt32(0, GUID_LOPART(targetGuid));
+
+ result = CharacterDatabase.Query(stmt);
+ if (result)
+ {
+ uint32 guildId = 0;
+ std::string guildName = "";
+ std::string guildRank = "";
+ std::string note = "";
+ std::string officeNote = "";
+
+ Field* fields = result->Fetch();
+ guildId = fields[0].GetUInt32();
+ guildName = fields[1].GetString();
+ //rankId = fields[2].GetUInt8();
+ guildRank = fields[3].GetString();
+ note = fields[4].GetString();
+ officeNote = fields[5].GetString();
+
+ handler->PSendSysMessage(LANG_PINFO_GUILD_INFO, guildName.c_str(), guildId, guildRank.c_str(), note.c_str(), officeNote.c_str());
+ }
+
return true;
}
@@ -2723,6 +2750,133 @@ public:
return true;
}
+ static bool HandleGroupJoinCommand(ChatHandler* handler, char const* args)
+ {
+ if (!*args)
+ return false;
+
+ Player* playerSource = NULL;
+ Player* playerTarget = NULL;
+ Group* groupSource = NULL;
+ Group* groupTarget = NULL;
+ uint64 guidSource = 0;
+ uint64 guidTarget = 0;
+ char* nameplgrStr = strtok((char*)args, " ");
+ char* nameplStr = strtok(NULL, " ");
+
+ if (handler->GetPlayerGroupAndGUIDByName(nameplgrStr, playerSource, groupSource, guidSource, true))
+ {
+ if (groupSource)
+ {
+ if (handler->GetPlayerGroupAndGUIDByName(nameplStr, playerTarget, groupTarget, guidTarget, true))
+ {
+ if (!groupTarget && playerTarget->GetGroup() != groupSource)
+ {
+ if (!groupSource->IsFull())
+ {
+ groupSource->AddMember(playerTarget);
+ groupSource->BroadcastGroupUpdate();
+ handler->PSendSysMessage(LANG_GROUP_PLAYER_JOINED, playerTarget->GetName().c_str(), playerSource->GetName().c_str());
+ return true;
+ }
+ else
+ {
+ // group is full
+ handler->PSendSysMessage(LANG_GROUP_FULL);
+ return true;
+ }
+ }
+ else
+ {
+ // group is full or target player already in a group
+ handler->PSendSysMessage(LANG_GROUP_ALREADY_IN_GROUP, playerTarget->GetName().c_str());
+ return true;
+ }
+ }
+ }
+ else
+ {
+ // specified source player is not in a group
+ handler->PSendSysMessage(LANG_GROUP_NOT_IN_GROUP, playerSource->GetName().c_str());
+ return true;
+ }
+ }
+
+ return true;
+ }
+
+ static bool HandleGroupListCommand(ChatHandler* handler, char const* args)
+ {
+ Player* playerTarget;
+ uint64 guidTarget;
+ std::string nameTarget;
+
+ uint32 parseGUID = MAKE_NEW_GUID(atol((char*)args), 0, HIGHGUID_PLAYER);
+
+ if (sObjectMgr->GetPlayerNameByGUID(parseGUID, nameTarget))
+ {
+ playerTarget = sObjectMgr->GetPlayerByLowGUID(parseGUID);
+ guidTarget = parseGUID;
+ }
+ else if (!handler->extractPlayerTarget((char*)args, &playerTarget, &guidTarget, &nameTarget))
+ return false;
+
+ Group* groupTarget = NULL;
+ if (playerTarget)
+ groupTarget = playerTarget->GetGroup();
+
+ if (!groupTarget)
+ {
+ PreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_SEL_GROUP_MEMBER);
+ stmt->setUInt32(0, guidTarget);
+ PreparedQueryResult resultGroup = CharacterDatabase.Query(stmt);
+ if (resultGroup)
+ groupTarget = sGroupMgr->GetGroupByDbStoreId((*resultGroup)[0].GetUInt32());
+ }
+
+ if (groupTarget)
+ {
+ handler->PSendSysMessage(LANG_GROUP_TYPE, (groupTarget->isRaidGroup() ? "raid" : "party"));
+ Group::MemberSlotList const& members = groupTarget->GetMemberSlots();
+ Group::MemberSlotList::const_iterator itr;
+ for (itr = members.begin(); itr != members.end(); ++itr)
+ {
+ std::ostringstream flags, roles;
+ if ((*itr).flags & MEMBER_FLAG_ASSISTANT)
+ flags << "Assistant ";
+ if ((*itr).flags & MEMBER_FLAG_MAINTANK)
+ flags << "MainTank ";
+ if ((*itr).flags & MEMBER_FLAG_MAINASSIST)
+ flags << "MainAssist ";
+
+ if ((*itr).roles & PLAYER_ROLE_LEADER)
+ roles << "Leader ";
+ if ((*itr).roles & PLAYER_ROLE_TANK)
+ roles << "Tank ";
+ if ((*itr).roles & PLAYER_ROLE_HEALER)
+ roles << "Healer ";
+ if ((*itr).roles & PLAYER_ROLE_DAMAGE)
+ roles << "Damage ";
+
+ Player* p = ObjectAccessor::FindPlayer((*itr).guid);
+ const char* onlineState = (p && p->IsInWorld()) ? "online" : "offline";
+
+ std::string flagsStr = (flags.str().empty()) ? "None" : flags.str();
+ std::string rolesStr = (roles.str().empty()) ? "None" : roles.str();
+
+ handler->PSendSysMessage(LANG_GROUP_PLAYER_NAME_GUID, (*itr).name.c_str(), onlineState, GUID_LOPART((*itr).guid), flagsStr.c_str(), rolesStr.c_str());
+ }
+ return true;
+ }
+ else
+ {
+ handler->PSendSysMessage(LANG_GROUP_NOT_IN_GROUP, nameTarget.c_str());
+ return true;
+ }
+
+ return true;
+ }
+
static bool HandlePlayAllCommand(ChatHandler* handler, char const* args)
{
if (!*args)
diff --git a/src/server/scripts/Commands/cs_mmaps.cpp b/src/server/scripts/Commands/cs_mmaps.cpp
new file mode 100644
index 00000000000..97861133983
--- /dev/null
+++ b/src/server/scripts/Commands/cs_mmaps.cpp
@@ -0,0 +1,294 @@
+/*
+ * Copyright (C) 2008-2013 TrinityCore <http://www.trinitycore.org/>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+/**
+* @file cs_mmaps.cpp
+* @brief .mmap related commands
+*
+* This file contains the CommandScripts for all
+* mmap sub-commands
+*/
+
+#include "ScriptMgr.h"
+#include "Chat.h"
+#include "ObjectMgr.h"
+#include "Player.h"
+#include "PointMovementGenerator.h"
+#include "PathGenerator.h"
+#include "MMapFactory.h"
+#include "Map.h"
+#include "TargetedMovementGenerator.h"
+#include "GridNotifiers.h"
+#include "GridNotifiersImpl.h"
+#include "CellImpl.h"
+
+class mmaps_commandscript : public CommandScript
+{
+public:
+ mmaps_commandscript() : CommandScript("mmaps_commandscript") { }
+
+ ChatCommand* GetCommands() const
+ {
+ static ChatCommand mmapCommandTable[] =
+ {
+ { "path", SEC_ADMINISTRATOR, false, &HandleMmapPathCommand, "", NULL },
+ { "loc", SEC_ADMINISTRATOR, false, &HandleMmapLocCommand, "", NULL },
+ { "loadedtiles", SEC_ADMINISTRATOR, false, &HandleMmapLoadedTilesCommand, "", NULL },
+ { "stats", SEC_ADMINISTRATOR, false, &HandleMmapStatsCommand, "", NULL },
+ { "testarea", SEC_ADMINISTRATOR, false, &HandleMmapTestArea, "", NULL },
+ { NULL, 0, false, NULL, "", NULL }
+ };
+
+ static ChatCommand commandTable[] =
+ {
+ { "mmap", SEC_ADMINISTRATOR, true, NULL, "", mmapCommandTable },
+ { NULL, 0, false, NULL, "", NULL }
+ };
+ return commandTable;
+ }
+
+ static bool HandleMmapPathCommand(ChatHandler* handler, char const* args)
+ {
+ if (!MMAP::MMapFactory::createOrGetMMapManager()->GetNavMesh(handler->GetSession()->GetPlayer()->GetMapId()))
+ {
+ handler->PSendSysMessage("NavMesh not loaded for current map.");
+ return true;
+ }
+
+ handler->PSendSysMessage("mmap path:");
+
+ // units
+ Player* player = handler->GetSession()->GetPlayer();
+ Unit* target = handler->getSelectedUnit();
+ if (!player || !target)
+ {
+ handler->PSendSysMessage("Invalid target/source selection.");
+ return true;
+ }
+
+ char* para = strtok((char*)args, " ");
+
+ bool useStraightPath = false;
+ if (para && strcmp(para, "true") == 0)
+ useStraightPath = true;
+
+ // unit locations
+ float x, y, z;
+ player->GetPosition(x, y, z);
+
+ // path
+ PathGenerator path(target);
+ path.SetUseStraightPath(useStraightPath);
+ bool result = path.CalculatePath(x, y, z);
+
+ PointsArray pointPath = path.GetPath();
+ handler->PSendSysMessage("%s's path to %s:", target->GetName().c_str(), player->GetName().c_str());
+ handler->PSendSysMessage("Building: %s", useStraightPath ? "StraightPath" : "SmoothPath");
+ handler->PSendSysMessage("Result: %s - Length: "SIZEFMTD" - Type: %u", (result ? "true" : "false"), pointPath.size(), path.GetPathType());
+
+ Vector3 start = path.GetStartPosition();
+ Vector3 end = path.GetEndPosition();
+ Vector3 actualEnd = path.GetActualEndPosition();
+
+ handler->PSendSysMessage("StartPosition (%.3f, %.3f, %.3f)", start.x, start.y, start.z);
+ handler->PSendSysMessage("EndPosition (%.3f, %.3f, %.3f)", end.x, end.y, end.z);
+ handler->PSendSysMessage("ActualEndPosition (%.3f, %.3f, %.3f)", actualEnd.x, actualEnd.y, actualEnd.z);
+
+ if (!player->isGameMaster())
+ handler->PSendSysMessage("Enable GM mode to see the path points.");
+
+ for (uint32 i = 0; i < pointPath.size(); ++i)
+ player->SummonCreature(VISUAL_WAYPOINT, pointPath[i].x, pointPath[i].y, pointPath[i].z, 0, TEMPSUMMON_TIMED_DESPAWN, 9000);
+
+ return true;
+ }
+
+ static bool HandleMmapLocCommand(ChatHandler* handler, char const* /*args*/)
+ {
+ handler->PSendSysMessage("mmap tileloc:");
+
+ // grid tile location
+ Player* player = handler->GetSession()->GetPlayer();
+
+ int32 gx = 32 - player->GetPositionX() / SIZE_OF_GRIDS;
+ int32 gy = 32 - player->GetPositionY() / SIZE_OF_GRIDS;
+
+ handler->PSendSysMessage("%03u%02i%02i.mmtile", player->GetMapId(), gy, gx);
+ handler->PSendSysMessage("gridloc [%i,%i]", gx, gy);
+
+ // calculate navmesh tile location
+ dtNavMesh const* navmesh = MMAP::MMapFactory::createOrGetMMapManager()->GetNavMesh(handler->GetSession()->GetPlayer()->GetMapId());
+ dtNavMeshQuery const* navmeshquery = MMAP::MMapFactory::createOrGetMMapManager()->GetNavMeshQuery(handler->GetSession()->GetPlayer()->GetMapId(), player->GetInstanceId());
+ if (!navmesh || !navmeshquery)
+ {
+ handler->PSendSysMessage("NavMesh not loaded for current map.");
+ return true;
+ }
+
+ float const* min = navmesh->getParams()->orig;
+ float x, y, z;
+ player->GetPosition(x, y, z);
+ float location[VERTEX_SIZE] = {y, z, x};
+ float extents[VERTEX_SIZE] = {3.0f, 5.0f, 3.0f};
+
+ int32 tilex = int32((y - min[0]) / SIZE_OF_GRIDS);
+ int32 tiley = int32((x - min[2]) / SIZE_OF_GRIDS);
+
+ handler->PSendSysMessage("Calc [%02i,%02i]", tilex, tiley);
+
+ // navmesh poly -> navmesh tile location
+ dtQueryFilter filter = dtQueryFilter();
+ dtPolyRef polyRef = INVALID_POLYREF;
+ navmeshquery->findNearestPoly(location, extents, &filter, &polyRef, NULL);
+
+ if (polyRef == INVALID_POLYREF)
+ handler->PSendSysMessage("Dt [??,??] (invalid poly, probably no tile loaded)");
+ else
+ {
+ dtMeshTile const* tile;
+ dtPoly const* poly;
+ navmesh->getTileAndPolyByRef(polyRef, &tile, &poly);
+ if (tile)
+ handler->PSendSysMessage("Dt [%02i,%02i]", tile->header->x, tile->header->y);
+ else
+ handler->PSendSysMessage("Dt [??,??] (no tile loaded)");
+ }
+
+ return true;
+ }
+
+ static bool HandleMmapLoadedTilesCommand(ChatHandler* handler, char const* /*args*/)
+ {
+ uint32 mapid = handler->GetSession()->GetPlayer()->GetMapId();
+ dtNavMesh const* navmesh = MMAP::MMapFactory::createOrGetMMapManager()->GetNavMesh(mapid);
+ dtNavMeshQuery const* navmeshquery = MMAP::MMapFactory::createOrGetMMapManager()->GetNavMeshQuery(mapid, handler->GetSession()->GetPlayer()->GetInstanceId());
+ if (!navmesh || !navmeshquery)
+ {
+ handler->PSendSysMessage("NavMesh not loaded for current map.");
+ return true;
+ }
+
+ handler->PSendSysMessage("mmap loadedtiles:");
+
+ for (int32 i = 0; i < navmesh->getMaxTiles(); ++i)
+ {
+ dtMeshTile const* tile = navmesh->getTile(i);
+ if (!tile || !tile->header)
+ continue;
+
+ handler->PSendSysMessage("[%02i,%02i]", tile->header->x, tile->header->y);
+ }
+
+ return true;
+ }
+
+ static bool HandleMmapStatsCommand(ChatHandler* handler, char const* /*args*/)
+ {
+ uint32 mapId = handler->GetSession()->GetPlayer()->GetMapId();
+ handler->PSendSysMessage("mmap stats:");
+ handler->PSendSysMessage(" global mmap pathfinding is %sabled", MMAP::MMapFactory::IsPathfindingEnabled(mapId) ? "en" : "dis");
+
+ MMAP::MMapManager* manager = MMAP::MMapFactory::createOrGetMMapManager();
+ handler->PSendSysMessage(" %u maps loaded with %u tiles overall", manager->getLoadedMapsCount(), manager->getLoadedTilesCount());
+
+ dtNavMesh const* navmesh = manager->GetNavMesh(handler->GetSession()->GetPlayer()->GetMapId());
+ if (!navmesh)
+ {
+ handler->PSendSysMessage("NavMesh not loaded for current map.");
+ return true;
+ }
+
+ uint32 tileCount = 0;
+ uint32 nodeCount = 0;
+ uint32 polyCount = 0;
+ uint32 vertCount = 0;
+ uint32 triCount = 0;
+ uint32 triVertCount = 0;
+ uint32 dataSize = 0;
+ for (int32 i = 0; i < navmesh->getMaxTiles(); ++i)
+ {
+ dtMeshTile const* tile = navmesh->getTile(i);
+ if (!tile || !tile->header)
+ continue;
+
+ tileCount++;
+ nodeCount += tile->header->bvNodeCount;
+ polyCount += tile->header->polyCount;
+ vertCount += tile->header->vertCount;
+ triCount += tile->header->detailTriCount;
+ triVertCount += tile->header->detailVertCount;
+ dataSize += tile->dataSize;
+ }
+
+ handler->PSendSysMessage("Navmesh stats:");
+ handler->PSendSysMessage(" %u tiles loaded", tileCount);
+ handler->PSendSysMessage(" %u BVTree nodes", nodeCount);
+ handler->PSendSysMessage(" %u polygons (%u vertices)", polyCount, vertCount);
+ handler->PSendSysMessage(" %u triangles (%u vertices)", triCount, triVertCount);
+ handler->PSendSysMessage(" %.2f MB of data (not including pointers)", ((float)dataSize / sizeof(unsigned char)) / 1048576);
+
+ return true;
+ }
+
+ static bool HandleMmapTestArea(ChatHandler* handler, char const* /*args*/)
+ {
+ float radius = 40.0f;
+ WorldObject* object = handler->GetSession()->GetPlayer();
+
+ CellCoord pair(Trinity::ComputeCellCoord(object->GetPositionX(), object->GetPositionY()));
+ Cell cell(pair);
+ cell.SetNoCreate();
+
+ std::list<Creature*> creatureList;
+
+ Trinity::AnyUnitInObjectRangeCheck go_check(object, radius);
+ Trinity::CreatureListSearcher<Trinity::AnyUnitInObjectRangeCheck> go_search(object, creatureList, go_check);
+ TypeContainerVisitor<Trinity::CreatureListSearcher<Trinity::AnyUnitInObjectRangeCheck>, GridTypeMapContainer> go_visit(go_search);
+
+ // Get Creatures
+ cell.Visit(pair, go_visit, *(object->GetMap()), *object, radius);
+
+ if (!creatureList.empty())
+ {
+ handler->PSendSysMessage("Found "SIZEFMTD" Creatures.", creatureList.size());
+
+ uint32 paths = 0;
+ uint32 uStartTime = getMSTime();
+
+ float gx, gy, gz;
+ object->GetPosition(gx, gy, gz);
+ for (std::list<Creature*>::iterator itr = creatureList.begin(); itr != creatureList.end(); ++itr)
+ {
+ PathGenerator path(*itr);
+ path.CalculatePath(gx, gy, gz);
+ ++paths;
+ }
+
+ uint32 uPathLoadTime = getMSTimeDiff(uStartTime, getMSTime());
+ handler->PSendSysMessage("Generated %i paths in %i ms", paths, uPathLoadTime);
+ }
+ else
+ handler->PSendSysMessage("No creatures in %f yard range.", radius);
+
+ return true;
+ }
+};
+
+void AddSC_mmaps_commandscript()
+{
+ new mmaps_commandscript();
+}
diff --git a/src/server/scripts/Commands/cs_npc.cpp b/src/server/scripts/Commands/cs_npc.cpp
index 0217aea1149..6653439b703 100644
--- a/src/server/scripts/Commands/cs_npc.cpp
+++ b/src/server/scripts/Commands/cs_npc.cpp
@@ -33,6 +33,42 @@ EndScriptData */
#include "Player.h"
#include "Pet.h"
+struct NpcFlagText
+{
+ uint32 flag;
+ int32 text;
+};
+
+#define NPCFLAG_COUNT 24
+
+const NpcFlagText npcFlagTexts[NPCFLAG_COUNT] =
+{
+ { UNIT_NPC_FLAG_AUCTIONEER, LANG_NPCINFO_AUCTIONEER },
+ { UNIT_NPC_FLAG_BANKER, LANG_NPCINFO_BANKER },
+ { UNIT_NPC_FLAG_BATTLEMASTER, LANG_NPCINFO_BATTLEMASTER },
+ { UNIT_NPC_FLAG_FLIGHTMASTER, LANG_NPCINFO_FLIGHTMASTER },
+ { UNIT_NPC_FLAG_GOSSIP, LANG_NPCINFO_GOSSIP },
+ { UNIT_NPC_FLAG_GUILD_BANKER, LANG_NPCINFO_GUILD_BANKER },
+ { UNIT_NPC_FLAG_INNKEEPER, LANG_NPCINFO_INNKEEPER },
+ { UNIT_NPC_FLAG_PETITIONER, LANG_NPCINFO_PETITIONER },
+ { UNIT_NPC_FLAG_PLAYER_VEHICLE, LANG_NPCINFO_PLAYER_VEHICLE },
+ { UNIT_NPC_FLAG_QUESTGIVER, LANG_NPCINFO_QUESTGIVER },
+ { UNIT_NPC_FLAG_REPAIR, LANG_NPCINFO_REPAIR },
+ { UNIT_NPC_FLAG_SPELLCLICK, LANG_NPCINFO_SPELLCLICK },
+ { UNIT_NPC_FLAG_SPIRITGUIDE, LANG_NPCINFO_SPIRITGUIDE },
+ { UNIT_NPC_FLAG_SPIRITHEALER, LANG_NPCINFO_SPIRITHEALER },
+ { UNIT_NPC_FLAG_STABLEMASTER, LANG_NPCINFO_STABLEMASTER },
+ { UNIT_NPC_FLAG_TABARDDESIGNER, LANG_NPCINFO_TABARDDESIGNER },
+ { UNIT_NPC_FLAG_TRAINER, LANG_NPCINFO_TRAINER },
+ { UNIT_NPC_FLAG_TRAINER_CLASS, LANG_NPCINFO_TRAINER_CLASS },
+ { UNIT_NPC_FLAG_TRAINER_PROFESSION, LANG_NPCINFO_TRAINER_PROFESSION },
+ { UNIT_NPC_FLAG_VENDOR, LANG_NPCINFO_VENDOR },
+ { UNIT_NPC_FLAG_VENDOR_AMMO, LANG_NPCINFO_VENDOR_AMMO },
+ { UNIT_NPC_FLAG_VENDOR_FOOD, LANG_NPCINFO_VENDOR_FOOD },
+ { UNIT_NPC_FLAG_VENDOR_POISON, LANG_NPCINFO_VENDOR_POISON },
+ { UNIT_NPC_FLAG_VENDOR_REAGENT, LANG_NPCINFO_VENDOR_REAGENT }
+};
+
class npc_commandscript : public CommandScript
{
public:
@@ -623,11 +659,9 @@ public:
handler->PSendSysMessage(LANG_NPCINFO_POSITION, float(target->GetPositionX()), float(target->GetPositionY()), float(target->GetPositionZ()));
handler->PSendSysMessage(LANG_NPCINFO_AIINFO, target->GetAIName().c_str(), target->GetScriptName().c_str());
- if (npcflags & UNIT_NPC_FLAG_VENDOR)
- handler->SendSysMessage(LANG_NPCINFO_VENDOR);
-
- if (npcflags & UNIT_NPC_FLAG_TRAINER)
- handler->SendSysMessage(LANG_NPCINFO_TRAINER);
+ for (uint8 i = 0; i < NPCFLAG_COUNT; i++)
+ if (npcflags & npcFlagTexts[i].flag)
+ handler->PSendSysMessage(npcFlagTexts[i].text, npcFlagTexts[i].flag);
return true;
}
diff --git a/src/server/scripts/EasternKingdoms/Scholomance/boss_kirtonos_the_herald.cpp b/src/server/scripts/EasternKingdoms/Scholomance/boss_kirtonos_the_herald.cpp
index 58e130ce644..19660cec4af 100644
--- a/src/server/scripts/EasternKingdoms/Scholomance/boss_kirtonos_the_herald.cpp
+++ b/src/server/scripts/EasternKingdoms/Scholomance/boss_kirtonos_the_herald.cpp
@@ -66,8 +66,8 @@ enum eMisc
Position const PosMove[2] =
{
- { 299.4884f, 92.76137f, 105.6335f },
- { 314.8673f, 90.30210f, 101.6459f }
+ { 299.4884f, 92.76137f, 105.6335f, 0.0f },
+ { 314.8673f, 90.30210f, 101.6459f, 0.0f }
};
class boss_kirtonos_the_herald : public CreatureScript
diff --git a/src/server/scripts/Northrend/IcecrownCitadel/boss_blood_queen_lana_thel.cpp b/src/server/scripts/Northrend/IcecrownCitadel/boss_blood_queen_lana_thel.cpp
index c8caa3976e4..ab0c44aa6d0 100644
--- a/src/server/scripts/Northrend/IcecrownCitadel/boss_blood_queen_lana_thel.cpp
+++ b/src/server/scripts/Northrend/IcecrownCitadel/boss_blood_queen_lana_thel.cpp
@@ -46,6 +46,7 @@ enum Spells
SPELL_FRENZIED_BLOODTHIRST_VISUAL = 71949,
SPELL_VAMPIRIC_BITE = 71726,
SPELL_ESSENCE_OF_THE_BLOOD_QUEEN_PLR = 70879,
+ SPELL_ESSENCE_OF_THE_BLOOD_QUEEN_HEAL = 70872,
SPELL_FRENZIED_BLOODTHIRST = 70877,
SPELL_UNCONTROLLABLE_FRENZY = 70923,
SPELL_PRESENCE_OF_THE_DARKFALLEN = 71952,
@@ -698,6 +699,42 @@ class spell_blood_queen_bloodbolt : public SpellScriptLoader
}
};
+// 70871 - Essence of the Blood Queen
+class spell_blood_queen_essence_of_the_blood_queen : public SpellScriptLoader
+{
+ public:
+ spell_blood_queen_essence_of_the_blood_queen() : SpellScriptLoader("spell_blood_queen_essence_of_the_blood_queen") { }
+
+ class spell_blood_queen_essence_of_the_blood_queen_AuraScript : public AuraScript
+ {
+ PrepareAuraScript(spell_blood_queen_essence_of_the_blood_queen_AuraScript);
+
+ bool Validate(SpellInfo const* /*spellInfo*/)
+ {
+ if (!sSpellMgr->GetSpellInfo(SPELL_ESSENCE_OF_THE_BLOOD_QUEEN_HEAL))
+ return false;
+ return true;
+ }
+
+ void OnProc(AuraEffect const* aurEff, ProcEventInfo& eventInfo)
+ {
+ PreventDefaultAction();
+ int32 heal = CalculatePct(int32(eventInfo.GetDamageInfo()->GetDamage()), aurEff->GetAmount());
+ GetTarget()->CastCustomSpell(SPELL_ESSENCE_OF_THE_BLOOD_QUEEN_HEAL, SPELLVALUE_BASE_POINT0, heal, GetTarget(), TRIGGERED_FULL_MASK, NULL, aurEff);
+ }
+
+ void Register()
+ {
+ OnEffectProc += AuraEffectProcFn(spell_blood_queen_essence_of_the_blood_queen_AuraScript::OnProc, EFFECT_1, SPELL_AURA_DUMMY);
+ }
+ };
+
+ AuraScript* GetAuraScript() const
+ {
+ return new spell_blood_queen_essence_of_the_blood_queen_AuraScript();
+ }
+};
+
class spell_blood_queen_pact_of_the_darkfallen : public SpellScriptLoader
{
public:
@@ -849,6 +886,7 @@ void AddSC_boss_blood_queen_lana_thel()
new spell_blood_queen_vampiric_bite();
new spell_blood_queen_frenzied_bloodthirst();
new spell_blood_queen_bloodbolt();
+ new spell_blood_queen_essence_of_the_blood_queen();
new spell_blood_queen_pact_of_the_darkfallen();
new spell_blood_queen_pact_of_the_darkfallen_dmg();
new spell_blood_queen_pact_of_the_darkfallen_dmg_target();
diff --git a/src/server/scripts/Northrend/IcecrownCitadel/boss_deathbringer_saurfang.cpp b/src/server/scripts/Northrend/IcecrownCitadel/boss_deathbringer_saurfang.cpp
index ce1166663f3..59d69d658cc 100644
--- a/src/server/scripts/Northrend/IcecrownCitadel/boss_deathbringer_saurfang.cpp
+++ b/src/server/scripts/Northrend/IcecrownCitadel/boss_deathbringer_saurfang.cpp
@@ -415,6 +415,13 @@ class boss_deathbringer_saurfang : public CreatureScript
}
}
+ void SpellHit(Unit* /*caster*/, SpellInfo const* spell)
+ {
+ if (spell->Id == SPELL_BLOOD_LINK_POWER)
+ if (Aura* bloodPower = me->GetAura(SPELL_BLOOD_POWER))
+ bloodPower->RecalculateAmountOfEffects();
+ }
+
void UpdateAI(uint32 const diff)
{
if (!UpdateVictim() && !(events.GetPhaseMask() & PHASE_INTRO_MASK))
@@ -1004,8 +1011,6 @@ class spell_deathbringer_blood_link : public SpellScriptLoader
void HandleDummy(SpellEffIndex /*effIndex*/)
{
GetHitUnit()->CastCustomSpell(SPELL_BLOOD_LINK_POWER, SPELLVALUE_BASE_POINT0, GetEffectValue(), GetHitUnit(), true);
- if (Aura* bloodPower = GetHitUnit()->GetAura(SPELL_BLOOD_POWER))
- bloodPower->RecalculateAmountOfEffects();
PreventHitDefaultEffect(EFFECT_0);
}
@@ -1093,13 +1098,6 @@ class spell_deathbringer_blood_power : public SpellScriptLoader
DoEffectCalcAmount += AuraEffectCalcAmountFn(spell_deathbringer_blood_power_AuraScript::RecalculateHook, EFFECT_0, SPELL_AURA_MOD_SCALE);
DoEffectCalcAmount += AuraEffectCalcAmountFn(spell_deathbringer_blood_power_AuraScript::RecalculateHook, EFFECT_1, SPELL_AURA_MOD_DAMAGE_PERCENT_DONE);
}
-
- bool Load()
- {
- if (GetUnitOwner()->getPowerType() != POWER_ENERGY)
- return false;
- return true;
- }
};
SpellScript* GetSpellScript() const
diff --git a/src/server/scripts/Northrend/IcecrownCitadel/boss_lord_marrowgar.cpp b/src/server/scripts/Northrend/IcecrownCitadel/boss_lord_marrowgar.cpp
index 4c18821d2f7..e3ab6e0941f 100644
--- a/src/server/scripts/Northrend/IcecrownCitadel/boss_lord_marrowgar.cpp
+++ b/src/server/scripts/Northrend/IcecrownCitadel/boss_lord_marrowgar.cpp
@@ -53,7 +53,7 @@ enum Spells
SPELL_COLDFLAME_SUMMON = 69147,
};
-uint32 const boneSpikeSummonId[3] = {69062, 72669, 72670};
+uint32 const BoneSpikeSummonId[3] = {69062, 72669, 72670};
enum Events
{
@@ -514,6 +514,20 @@ class spell_marrowgar_bone_spike_graveyard : public SpellScriptLoader
{
PrepareSpellScript(spell_marrowgar_bone_spike_graveyard_SpellScript);
+ bool Validate(SpellInfo const* /*spell*/)
+ {
+ for (uint32 i = 0; i < 3; ++i)
+ if (!sSpellMgr->GetSpellInfo(BoneSpikeSummonId[i]))
+ return false;
+
+ return true;
+ }
+
+ bool Load()
+ {
+ return GetCaster()->GetTypeId() == TYPEID_UNIT && GetCaster()->IsAIEnabled;
+ }
+
SpellCastResult CheckCast()
{
return GetCaster()->GetAI()->SelectTarget(SELECT_TARGET_TOPAGGRO, 1, 0.0f, true, -SPELL_IMPALED) ? SPELL_CAST_OK : SPELL_FAILED_NO_VALID_TARGETS;
@@ -535,7 +549,7 @@ class spell_marrowgar_bone_spike_graveyard : public SpellScriptLoader
break;
didHit = true;
- target->CastCustomSpell(boneSpikeSummonId[i], SPELLVALUE_BASE_POINT0, 0, target, true);
+ target->CastCustomSpell(BoneSpikeSummonId[i], SPELLVALUE_BASE_POINT0, 0, target, true);
}
if (didHit)
diff --git a/src/server/scripts/Northrend/IcecrownCitadel/boss_the_lich_king.cpp b/src/server/scripts/Northrend/IcecrownCitadel/boss_the_lich_king.cpp
index 962e12a2461..2dd4323ad3b 100644
--- a/src/server/scripts/Northrend/IcecrownCitadel/boss_the_lich_king.cpp
+++ b/src/server/scripts/Northrend/IcecrownCitadel/boss_the_lich_king.cpp
@@ -145,6 +145,7 @@ enum Spells
SPELL_RESTORE_SOUL = 72595,
SPELL_RESTORE_SOULS = 73650, // Heroic
SPELL_DARK_HUNGER = 69383, // Passive proc healing
+ SPELL_DARK_HUNGER_HEAL = 69384,
SPELL_DESTROY_SOUL = 74086, // Used when Terenas Menethil dies
SPELL_SOUL_RIP = 69397, // Deals increasing damage
SPELL_SOUL_RIP_DAMAGE = 69398,
@@ -2989,6 +2990,41 @@ class spell_the_lich_king_restore_soul : public SpellScriptLoader
}
};
+class spell_the_lich_king_dark_hunger : public SpellScriptLoader
+{
+ public:
+ spell_the_lich_king_dark_hunger() : SpellScriptLoader("spell_the_lich_king_dark_hunger") { }
+
+ class spell_the_lich_king_dark_hunger_AuraScript : public AuraScript
+ {
+ PrepareAuraScript(spell_the_lich_king_dark_hunger_AuraScript);
+
+ bool Validate(SpellInfo const* /*spellInfo*/)
+ {
+ if (!sSpellMgr->GetSpellInfo(SPELL_DARK_HUNGER_HEAL))
+ return false;
+ return true;
+ }
+
+ void HandleProc(AuraEffect const* aurEff, ProcEventInfo& eventInfo)
+ {
+ PreventDefaultAction();
+ int32 heal = int32(eventInfo.GetDamageInfo()->GetDamage() / 2);
+ GetTarget()->CastCustomSpell(SPELL_DARK_HUNGER_HEAL, SPELLVALUE_BASE_POINT0, heal, GetTarget(), true, NULL, aurEff);
+ }
+
+ void Register()
+ {
+ OnEffectProc += AuraEffectProcFn(spell_the_lich_king_dark_hunger_AuraScript::HandleProc, EFFECT_0, SPELL_AURA_DUMMY);
+ }
+ };
+
+ AuraScript* GetAuraScript() const
+ {
+ return new spell_the_lich_king_dark_hunger_AuraScript();
+ }
+};
+
class spell_the_lich_king_in_frostmourne_room : public SpellScriptLoader
{
public:
@@ -3234,6 +3270,7 @@ void AddSC_boss_the_lich_king()
new spell_the_lich_king_lights_favor();
new spell_the_lich_king_soul_rip();
new spell_the_lich_king_restore_soul();
+ new spell_the_lich_king_dark_hunger();
new spell_the_lich_king_in_frostmourne_room();
new spell_the_lich_king_summon_spirit_bomb();
new spell_the_lich_king_trigger_vile_spirit();
diff --git a/src/server/scripts/Northrend/Ulduar/Ulduar/boss_algalon_the_observer.cpp b/src/server/scripts/Northrend/Ulduar/Ulduar/boss_algalon_the_observer.cpp
index 1f96848fa0a..13a4fe23690 100644
--- a/src/server/scripts/Northrend/Ulduar/Ulduar/boss_algalon_the_observer.cpp
+++ b/src/server/scripts/Northrend/Ulduar/Ulduar/boss_algalon_the_observer.cpp
@@ -343,7 +343,7 @@ class boss_algalon_the_observer : public CreatureScript
DoCast(me, SPELL_RIDE_THE_LIGHTNING, true);
me->GetMotionMaster()->MovePoint(POINT_ALGALON_LAND, AlgalonLandPos);
me->SetHomePosition(AlgalonLandPos);
- Movement::MoveSplineInit init(*me);
+ Movement::MoveSplineInit init(me);
init.MoveTo(AlgalonLandPos.GetPositionX(), AlgalonLandPos.GetPositionY(), AlgalonLandPos.GetPositionZ());
init.SetOrientationFixed(true);
init.Launch();
diff --git a/src/server/scripts/Outland/zone_shadowmoon_valley.cpp b/src/server/scripts/Outland/zone_shadowmoon_valley.cpp
index 0a016f0923c..a1bfc0a090a 100644
--- a/src/server/scripts/Outland/zone_shadowmoon_valley.cpp
+++ b/src/server/scripts/Outland/zone_shadowmoon_valley.cpp
@@ -661,6 +661,7 @@ class npc_karynaku : public CreatureScript
/*####
# npc_overlord_morghor
+# this whole script is wrong and needs a rewrite.even the illidan npc used is the wrong one.npc id 23467 may be the correct one
####*/
enum eOverlordData
{
@@ -766,7 +767,7 @@ public:
Player* player = Unit::GetPlayer(*me, PlayerGUID);
Creature* Illi = Creature::GetCreature(*me, IllidanGUID);
- if (!player || !Illi)
+ if (!player)
{
EnterEvadeMode();
return 0;
@@ -794,14 +795,21 @@ public:
return 2000;
break;
case 5:
- Illi->SetVisible(true);
- Illi->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE);
+ if (Illi)
+ {
+ Illi->SetVisible(true);
+ Illi->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE);
+ Illi->SetDisplayId(21526);
+ }
return 350;
break;
case 6:
- Illi->CastSpell(Illi, SPELL_ONE, true);
- Illi->SetTarget(me->GetGUID());
- me->SetTarget(IllidanGUID);
+ if (Illi)
+ {
+ Illi->CastSpell(Illi, SPELL_ONE, true);
+ Illi->SetTarget(me->GetGUID());
+ me->SetTarget(IllidanGUID);
+ }
return 2000;
break;
case 7:
@@ -810,10 +818,15 @@ public:
break;
case 8:
me->SetUInt32Value(UNIT_FIELD_BYTES_1, 8);
- return 9000;
+ return 2500;
+ break;
+ case 9:
+ // missing text "Lord Illidan, this is the Dragonmaw that I, and others, have told you about. He will lead us to victory!"
+ return 5000;
break;
case 10:
- Illi->AI()->Talk(LORD_ILLIDAN_SAY_1);
+ if (Illi)
+ Illi->AI()->Talk(LORD_ILLIDAN_SAY_1);
return 5000;
break;
case 11:
@@ -821,42 +834,53 @@ public:
return 6000;
break;
case 12:
- Illi->AI()->Talk(LORD_ILLIDAN_SAY_2);
+ if (Illi)
+ Illi->AI()->Talk(LORD_ILLIDAN_SAY_2);
return 5500;
break;
case 13:
- Illi->AI()->Talk(LORD_ILLIDAN_SAY_3);
+ if (Illi)
+ Illi->AI()->Talk(LORD_ILLIDAN_SAY_3);
return 4000;
break;
case 14:
- Illi->SetTarget(PlayerGUID);
+ if (Illi)
+ Illi->SetTarget(PlayerGUID);
return 1500;
break;
case 15:
- Illi->AI()->Talk(LORD_ILLIDAN_SAY_4);
+ if (Illi)
+ Illi->AI()->Talk(LORD_ILLIDAN_SAY_4);
return 1500;
break;
case 16:
- Illi->CastSpell(player, SPELL_TWO, true);
+ if (Illi)
+ Illi->CastSpell(player, SPELL_TWO, true);
player->RemoveAurasDueToSpell(SPELL_THREE);
player->RemoveAurasDueToSpell(SPELL_FOUR);
return 5000;
break;
case 17:
- Illi->AI()->Talk(LORD_ILLIDAN_SAY_5);
+ if (Illi)
+ Illi->AI()->Talk(LORD_ILLIDAN_SAY_5);
return 5000;
break;
case 18:
- Illi->AI()->Talk(LORD_ILLIDAN_SAY_6);
+ if (Illi)
+ Illi->AI()->Talk(LORD_ILLIDAN_SAY_6);
return 5000;
break;
case 19:
- Illi->AI()->Talk(LORD_ILLIDAN_SAY_7);
+ if (Illi)
+ Illi->AI()->Talk(LORD_ILLIDAN_SAY_7);
return 5000;
break;
case 20:
- Illi->HandleEmoteCommand(EMOTE_ONESHOT_LIFTOFF);
- Illi->SetDisableGravity(true);
+ if (Illi)
+ {
+ Illi->HandleEmoteCommand(EMOTE_ONESHOT_LIFTOFF);
+ Illi->SetDisableGravity(true);
+ }
return 500;
break;
case 21:
@@ -864,8 +888,11 @@ public:
return 500;
break;
case 22:
- Illi->SetVisible(false);
- Illi->setDeathState(JUST_DIED);
+ if (Illi)
+ {
+ Illi->SetVisible(false);
+ Illi->setDeathState(JUST_DIED);
+ }
return 1000;
break;
case 23:
@@ -886,7 +913,7 @@ public:
break;
case 27:
{
- Unit* Yarzill = me->FindNearestCreature(C_YARZILL, 50);
+ Unit* Yarzill = me->FindNearestCreature(C_YARZILL, 50.0f);
if (Yarzill)
Yarzill->SetTarget(PlayerGUID);
return 500;
@@ -921,9 +948,11 @@ public:
}
break;
case 32:
- me->GetMotionMaster()->MovePoint(0, -5085.77f, 577.231f, 86.6719f); return 5000;
+ me->GetMotionMaster()->MovePoint(0, -5085.77f, 577.231f, 86.6719f);
+ return 5000;
break;
case 33:
+ me->SetTarget(0);
Reset();
return 100;
break;
@@ -940,7 +969,7 @@ public:
if (ConversationTimer <= diff)
{
- if (Event && IllidanGUID && PlayerGUID)
+ if (Event && PlayerGUID)
ConversationTimer = NextStep(++Step);
} else ConversationTimer -= diff;
}
diff --git a/src/server/scripts/Spells/spell_dk.cpp b/src/server/scripts/Spells/spell_dk.cpp
index 5b43a46cb1f..f5a6bb61120 100644
--- a/src/server/scripts/Spells/spell_dk.cpp
+++ b/src/server/scripts/Spells/spell_dk.cpp
@@ -31,12 +31,14 @@ enum DeathKnightSpells
SPELL_DK_ANTI_MAGIC_SHELL_TALENT = 51052,
SPELL_DK_BLACK_ICE_R1 = 49140,
SPELL_DK_BLOOD_BOIL_TRIGGERED = 65658,
+ SPELL_DK_BLOOD_GORGED_HEAL = 50454,
SPELL_DK_CORPSE_EXPLOSION_TRIGGERED = 43999,
SPELL_DK_CORPSE_EXPLOSION_VISUAL = 51270,
SPELL_DK_DEATH_COIL_DAMAGE = 47632,
SPELL_DK_DEATH_COIL_HEAL = 47633,
SPELL_DK_DEATH_STRIKE_HEAL = 45470,
SPELL_DK_GHOUL_EXPLODE = 47496,
+ SPELL_DK_GLYPH_OF_ICEBOUND_FORTITUDE = 58625,
SPELL_DK_RUNIC_POWER_ENERGIZE = 49088,
SPELL_DK_SCOURGE_STRIKE_TRIGGERED = 70890,
SPELL_DK_WILL_OF_THE_NECROPOLIS_TALENT_R1 = 49189,
@@ -251,6 +253,58 @@ class spell_dk_blood_boil : public SpellScriptLoader
}
};
+// 50453 - Bloodworms Health Leech
+class spell_dk_blood_gorged : public SpellScriptLoader
+{
+ public:
+ spell_dk_blood_gorged() : SpellScriptLoader("spell_dk_blood_gorged") { }
+
+ class spell_dk_blood_gorged_AuraScript : public AuraScript
+ {
+ PrepareAuraScript(spell_dk_blood_gorged_AuraScript);
+
+ bool Validate(SpellInfo const* /*spellInfo*/)
+ {
+ if (!sSpellMgr->GetSpellInfo(SPELL_DK_BLOOD_GORGED_HEAL))
+ return false;
+ return true;
+ }
+
+ bool Load()
+ {
+ _procTarget = NULL;
+ return true;
+ }
+
+ bool CheckProc(ProcEventInfo& /*eventInfo*/)
+ {
+ _procTarget = GetTarget()->GetOwner();
+ return _procTarget;
+ }
+
+ void HandleProc(AuraEffect const* aurEff, ProcEventInfo& eventInfo)
+ {
+ PreventDefaultAction();
+ int32 bp = int32(eventInfo.GetDamageInfo()->GetDamage() * 1.5f);
+ GetTarget()->CastCustomSpell(SPELL_DK_BLOOD_GORGED_HEAL, SPELLVALUE_BASE_POINT0, bp, _procTarget, true, NULL, aurEff);
+ }
+
+ void Register()
+ {
+ DoCheckProc += AuraCheckProcFn(spell_dk_blood_gorged_AuraScript::CheckProc);
+ OnEffectProc += AuraEffectProcFn(spell_dk_blood_gorged_AuraScript::HandleProc, EFFECT_0, SPELL_AURA_DUMMY);
+ }
+
+ private:
+ Unit* _procTarget;
+ };
+
+ AuraScript* GetAuraScript() const
+ {
+ return new spell_dk_blood_gorged_AuraScript();
+ }
+};
+
// 49158 - Corpse Explosion (51325, 51326, 51327, 51328)
class spell_dk_corpse_explosion : public SpellScriptLoader
{
@@ -584,6 +638,55 @@ class spell_dk_ghoul_explode : public SpellScriptLoader
}
};
+// 48792 - Icebound Fortitude
+class spell_dk_icebound_fortitude : public SpellScriptLoader
+{
+ public:
+ spell_dk_icebound_fortitude() : SpellScriptLoader("spell_dk_icebound_fortitude") { }
+
+ class spell_dk_icebound_fortitude_AuraScript : public AuraScript
+ {
+ PrepareAuraScript(spell_dk_icebound_fortitude_AuraScript);
+
+ bool Load()
+ {
+ Unit* caster = GetCaster();
+ return caster && caster->GetTypeId() == TYPEID_PLAYER;
+ }
+
+ void CalculateAmount(AuraEffect const* /*aurEff*/, int32& amount, bool& /*canBeRecalculated*/)
+ {
+ if (Unit* caster = GetCaster())
+ {
+ int32 value = amount;
+ uint32 defValue = uint32(caster->ToPlayer()->GetSkillValue(SKILL_DEFENSE) + caster->ToPlayer()->GetRatingBonusValue(CR_DEFENSE_SKILL));
+
+ if (defValue > 400)
+ value -= int32((defValue - 400) * 0.15);
+
+ // Glyph of Icebound Fortitude
+ if (AuraEffect const* aurEff = caster->GetAuraEffect(SPELL_DK_GLYPH_OF_ICEBOUND_FORTITUDE, EFFECT_0))
+ {
+ int32 valMax = -aurEff->GetAmount();
+ if (value > valMax)
+ value = valMax;
+ }
+ amount = value;
+ }
+ }
+
+ void Register()
+ {
+ DoEffectCalcAmount += AuraEffectCalcAmountFn(spell_dk_icebound_fortitude_AuraScript::CalculateAmount, EFFECT_2, SPELL_AURA_MOD_DAMAGE_PERCENT_TAKEN);
+ }
+ };
+
+ AuraScript* GetAuraScript() const
+ {
+ return new spell_dk_icebound_fortitude_AuraScript();
+ }
+};
+
// 50365, 50371 - Improved Blood Presence
class spell_dk_improved_blood_presence : public SpellScriptLoader
{
@@ -677,6 +780,33 @@ class spell_dk_improved_unholy_presence : public SpellScriptLoader
}
};
+// 59754 Rune Tap - Party
+class spell_dk_rune_tap_party : public SpellScriptLoader
+{
+ public:
+ spell_dk_rune_tap_party() : SpellScriptLoader("spell_dk_rune_tap_party") { }
+
+ class spell_dk_rune_tap_party_SpellScript : public SpellScript
+ {
+ PrepareSpellScript(spell_dk_rune_tap_party_SpellScript);
+
+ void CheckTargets(std::list<WorldObject*>& targets)
+ {
+ targets.remove(GetCaster());
+ }
+
+ void Register()
+ {
+ OnObjectAreaTargetSelect += SpellObjectAreaTargetSelectFn(spell_dk_rune_tap_party_SpellScript::CheckTargets, EFFECT_0, TARGET_UNIT_CASTER_AREA_PARTY);
+ }
+ };
+
+ SpellScript* GetSpellScript() const
+ {
+ return new spell_dk_rune_tap_party_SpellScript();
+ }
+};
+
// 55090 - Scourge Strike (55265, 55270, 55271)
class spell_dk_scourge_strike : public SpellScriptLoader
{
@@ -784,6 +914,33 @@ class spell_dk_spell_deflection : public SpellScriptLoader
}
};
+// 55233 - Vampiric Blood
+class spell_dk_vampiric_blood : public SpellScriptLoader
+{
+ public:
+ spell_dk_vampiric_blood() : SpellScriptLoader("spell_dk_vampiric_blood") { }
+
+ class spell_dk_vampiric_blood_AuraScript : public AuraScript
+ {
+ PrepareAuraScript(spell_dk_vampiric_blood_AuraScript);
+
+ void CalculateAmount(AuraEffect const* /*aurEff*/, int32& amount, bool& /*canBeRecalculated*/)
+ {
+ amount = GetUnitOwner()->CountPctFromMaxHealth(amount);
+ }
+
+ void Register()
+ {
+ DoEffectCalcAmount += AuraEffectCalcAmountFn(spell_dk_vampiric_blood_AuraScript::CalculateAmount, EFFECT_1, SPELL_AURA_MOD_INCREASE_HEALTH);
+ }
+ };
+
+ AuraScript* GetAuraScript() const
+ {
+ return new spell_dk_vampiric_blood_AuraScript();
+ }
+};
+
// 52284 - Will of the Necropolis
class spell_dk_will_of_the_necropolis : public SpellScriptLoader
{
@@ -854,6 +1011,7 @@ void AddSC_deathknight_spell_scripts()
new spell_dk_anti_magic_shell_self();
new spell_dk_anti_magic_zone();
new spell_dk_blood_boil();
+ new spell_dk_blood_gorged();
new spell_dk_corpse_explosion();
new spell_dk_death_coil();
new spell_dk_death_gate();
@@ -861,9 +1019,12 @@ void AddSC_deathknight_spell_scripts()
new spell_dk_death_pact();
new spell_dk_death_strike();
new spell_dk_ghoul_explode();
+ new spell_dk_icebound_fortitude();
new spell_dk_improved_blood_presence();
new spell_dk_improved_unholy_presence();
+ new spell_dk_rune_tap_party();
new spell_dk_scourge_strike();
new spell_dk_spell_deflection();
+ new spell_dk_vampiric_blood();
new spell_dk_will_of_the_necropolis();
}
diff --git a/src/server/scripts/Spells/spell_druid.cpp b/src/server/scripts/Spells/spell_druid.cpp
index b5b4937a14c..8fd44544fb8 100644
--- a/src/server/scripts/Spells/spell_druid.cpp
+++ b/src/server/scripts/Spells/spell_druid.cpp
@@ -39,10 +39,15 @@ enum DruidSpells
SPELL_DRUID_SOLAR_ECLIPSE = 48517,
SPELL_DRUID_LUNAR_ECLIPSE = 48518,
SPELL_DRUID_ENRAGE_MOD_DAMAGE = 51185,
+ SPELL_DRUID_GLYPH_OF_TYPHOON = 62135,
+ SPELL_DRUID_IDOL_OF_FERAL_SHADOWS = 34241,
+ SPELL_DRUID_IDOL_OF_WORSHIP = 60774,
SPELL_DRUID_INCREASED_MOONFIRE_DURATION = 38414,
SPELL_DRUID_KING_OF_THE_JUNGLE = 48492,
SPELL_DRUID_LIFEBLOOM_ENERGIZE = 64372,
SPELL_DRUID_LIFEBLOOM_FINAL_HEAL = 33778,
+ SPELL_DRUID_LIVING_SEED_HEAL = 48503,
+ SPELL_DRUID_LIVING_SEED_PROC = 48504,
SPELL_DRUID_NATURES_SPLENDOR = 57865,
SPELL_DRUID_SURVIVAL_INSTINCTS = 50322,
SPELL_DRUID_SAVAGE_ROAR = 62071,
@@ -160,6 +165,35 @@ class spell_dru_eclipse_energize : public SpellScriptLoader
}
};
+// -1850 - Dash
+class spell_dru_dash : public SpellScriptLoader
+{
+ public:
+ spell_dru_dash() : SpellScriptLoader("spell_dru_dash") { }
+
+ class spell_dru_dash_AuraScript : public AuraScript
+ {
+ PrepareAuraScript(spell_dru_dash_AuraScript);
+
+ void CalculateAmount(AuraEffect const* /*aurEff*/, int32& amount, bool& /*canBeRecalculated*/)
+ {
+ // do not set speed if not in cat form
+ if (GetUnitOwner()->GetShapeshiftForm() != FORM_CAT)
+ amount = 0;
+ }
+
+ void Register()
+ {
+ DoEffectCalcAmount += AuraEffectCalcAmountFn(spell_dru_dash_AuraScript::CalculateAmount, EFFECT_0, SPELL_AURA_MOD_INCREASE_SPEED);
+ }
+ };
+
+ AuraScript* GetAuraScript() const
+ {
+ return new spell_dru_dash_AuraScript();
+ }
+};
+
// -5229 - Enrage
class spell_dru_enrage : public SpellScriptLoader
{
@@ -240,6 +274,69 @@ class spell_dru_glyph_of_starfire : public SpellScriptLoader
}
};
+// 34246 - Idol of the Emerald Queen
+// 60779 - Idol of Lush Moss
+class spell_dru_idol_lifebloom : public SpellScriptLoader
+{
+ public:
+ spell_dru_idol_lifebloom() : SpellScriptLoader("spell_dru_idol_lifebloom") { }
+
+ class spell_dru_idol_lifebloom_AuraScript : public AuraScript
+ {
+ PrepareAuraScript(spell_dru_idol_lifebloom_AuraScript);
+
+ void HandleEffectCalcSpellMod(AuraEffect const* aurEff, SpellModifier*& spellMod)
+ {
+ if (!spellMod)
+ {
+ spellMod = new SpellModifier(GetAura());
+ spellMod->op = SPELLMOD_DOT;
+ spellMod->type = SPELLMOD_FLAT;
+ spellMod->spellId = GetId();
+ spellMod->mask = GetSpellInfo()->Effects[aurEff->GetEffIndex()].SpellClassMask;
+ }
+ spellMod->value = aurEff->GetAmount() / 7;
+ }
+
+ void Register()
+ {
+ DoEffectCalcSpellMod += AuraEffectCalcSpellModFn(spell_dru_idol_lifebloom_AuraScript::HandleEffectCalcSpellMod, EFFECT_0, SPELL_AURA_DUMMY);
+ }
+ };
+
+ AuraScript* GetAuraScript() const
+ {
+ return new spell_dru_idol_lifebloom_AuraScript();
+ }
+};
+
+// 29166 - Innervate
+class spell_dru_innervate : public SpellScriptLoader
+{
+ public:
+ spell_dru_innervate() : SpellScriptLoader("spell_dru_innervate") { }
+
+ class spell_dru_innervate_AuraScript : public AuraScript
+ {
+ PrepareAuraScript(spell_dru_innervate_AuraScript);
+
+ void CalculateAmount(AuraEffect const* aurEff, int32& amount, bool& /*canBeRecalculated*/)
+ {
+ amount = CalculatePct(int32(GetUnitOwner()->GetCreatePowers(POWER_MANA) / aurEff->GetTotalTicks()), amount);
+ }
+
+ void Register()
+ {
+ DoEffectCalcAmount += AuraEffectCalcAmountFn(spell_dru_innervate_AuraScript::CalculateAmount, EFFECT_0, SPELL_AURA_PERIODIC_ENERGIZE);
+ }
+ };
+
+ AuraScript* GetAuraScript() const
+ {
+ return new spell_dru_innervate_AuraScript();
+ }
+};
+
// -5570 - Insect Swarm
class spell_dru_insect_swarm : public SpellScriptLoader
{
@@ -351,6 +448,77 @@ class spell_dru_lifebloom : public SpellScriptLoader
}
};
+// -48496 - Living Seed
+class spell_dru_living_seed : public SpellScriptLoader
+{
+ public:
+ spell_dru_living_seed() : SpellScriptLoader("spell_dru_living_seed") { }
+
+ class spell_dru_living_seed_AuraScript : public AuraScript
+ {
+ PrepareAuraScript(spell_dru_living_seed_AuraScript);
+
+ bool Validate(SpellInfo const* /*spellInfo*/)
+ {
+ if (!sSpellMgr->GetSpellInfo(SPELL_DRUID_LIVING_SEED_PROC))
+ return false;
+ return true;
+ }
+
+ void HandleProc(AuraEffect const* aurEff, ProcEventInfo& eventInfo)
+ {
+ PreventDefaultAction();
+ int32 amount = CalculatePct(eventInfo.GetHealInfo()->GetHeal(), aurEff->GetAmount());
+ GetTarget()->CastCustomSpell(SPELL_DRUID_LIVING_SEED_PROC, SPELLVALUE_BASE_POINT0, amount, eventInfo.GetProcTarget(), true, NULL, aurEff);
+ }
+
+ void Register()
+ {
+ OnEffectProc += AuraEffectProcFn(spell_dru_living_seed_AuraScript::HandleProc, EFFECT_0, SPELL_AURA_DUMMY);
+ }
+ };
+
+ AuraScript* GetAuraScript() const
+ {
+ return new spell_dru_living_seed_AuraScript();
+ }
+};
+
+// 48504 - Living Seed (Proc)
+class spell_dru_living_seed_proc : public SpellScriptLoader
+{
+ public:
+ spell_dru_living_seed_proc() : SpellScriptLoader("spell_dru_living_seed_proc") { }
+
+ class spell_dru_living_seed_proc_AuraScript : public AuraScript
+ {
+ PrepareAuraScript(spell_dru_living_seed_proc_AuraScript);
+
+ bool Validate(SpellInfo const* /*spellInfo*/)
+ {
+ if (!sSpellMgr->GetSpellInfo(SPELL_DRUID_LIVING_SEED_HEAL))
+ return false;
+ return true;
+ }
+
+ void HandleProc(AuraEffect const* aurEff, ProcEventInfo& /*eventInfo*/)
+ {
+ PreventDefaultAction();
+ GetTarget()->CastCustomSpell(SPELL_DRUID_LIVING_SEED_HEAL, SPELLVALUE_BASE_POINT0, aurEff->GetAmount(), GetTarget(), true, NULL, aurEff);
+ }
+
+ void Register()
+ {
+ OnEffectProc += AuraEffectProcFn(spell_dru_living_seed_proc_AuraScript::HandleProc, EFFECT_0, SPELL_AURA_DUMMY);
+ }
+ };
+
+ AuraScript* GetAuraScript() const
+ {
+ return new spell_dru_living_seed_proc_AuraScript();
+ }
+};
+
// 69366 - Moonkin Form passive
class spell_dru_moonkin_form_passive : public SpellScriptLoader
{
@@ -395,6 +563,33 @@ class spell_dru_moonkin_form_passive : public SpellScriptLoader
}
};
+// 48391 - Owlkin Frenzy
+class spell_dru_owlkin_frenzy : public SpellScriptLoader
+{
+ public:
+ spell_dru_owlkin_frenzy() : SpellScriptLoader("spell_dru_owlkin_frenzy") { }
+
+ class spell_dru_owlkin_frenzy_AuraScript : public AuraScript
+ {
+ PrepareAuraScript(spell_dru_owlkin_frenzy_AuraScript);
+
+ void CalculateAmount(AuraEffect const* /*aurEff*/, int32& amount, bool& /*canBeRecalculated*/)
+ {
+ amount = CalculatePct(GetUnitOwner()->GetCreatePowers(POWER_MANA), amount);
+ }
+
+ void Register()
+ {
+ DoEffectCalcAmount += AuraEffectCalcAmountFn(spell_dru_owlkin_frenzy_AuraScript::CalculateAmount, EFFECT_2, SPELL_AURA_PERIODIC_ENERGIZE);
+ }
+ };
+
+ AuraScript* GetAuraScript() const
+ {
+ return new spell_dru_owlkin_frenzy_AuraScript();
+ }
+};
+
// -16972 - Predatory Strikes
class spell_dru_predatory_strikes : public SpellScriptLoader
{
@@ -468,6 +663,54 @@ class spell_dru_primal_tenacity : public SpellScriptLoader
}
};
+// -1079 - Rip
+class spell_dru_rip : public SpellScriptLoader
+{
+ public:
+ spell_dru_rip() : SpellScriptLoader("spell_dru_rip") { }
+
+ class spell_dru_rip_AuraScript : public AuraScript
+ {
+ PrepareAuraScript(spell_dru_rip_AuraScript);
+
+ bool Load()
+ {
+ Unit* caster = GetCaster();
+ return caster && caster->GetTypeId() == TYPEID_PLAYER;
+ }
+
+ void CalculateAmount(AuraEffect const* /*aurEff*/, int32& amount, bool& canBeRecalculated)
+ {
+ canBeRecalculated = false;
+
+ if (Unit* caster = GetCaster())
+ {
+ // 0.01 * $AP * cp
+ uint8 cp = caster->ToPlayer()->GetComboPoints();
+
+ // Idol of Feral Shadows. Can't be handled as SpellMod due its dependency from CPs
+ if (AuraEffect const* idol = caster->GetAuraEffect(SPELL_DRUID_IDOL_OF_FERAL_SHADOWS, EFFECT_0))
+ amount += cp * idol->GetAmount();
+ // Idol of Worship. Can't be handled as SpellMod due its dependency from CPs
+ else if (AuraEffect const* idol = caster->GetAuraEffect(SPELL_DRUID_IDOL_OF_WORSHIP, EFFECT_0))
+ amount += cp * idol->GetAmount();
+
+ amount += int32(CalculatePct(caster->GetTotalAttackPowerValue(BASE_ATTACK), cp));
+ }
+ }
+
+ void Register()
+ {
+ DoEffectCalcAmount += AuraEffectCalcAmountFn(spell_dru_rip_AuraScript::CalculateAmount, EFFECT_0, SPELL_AURA_PERIODIC_DAMAGE);
+ }
+ };
+
+ AuraScript* GetAuraScript() const
+ {
+ return new spell_dru_rip_AuraScript();
+ }
+};
+
// 62606 - Savage Defense
class spell_dru_savage_defense : public SpellScriptLoader
{
@@ -777,6 +1020,35 @@ class spell_dru_tiger_s_fury : public SpellScriptLoader
}
};
+// -61391 - Typhoon
+class spell_dru_typhoon : public SpellScriptLoader
+{
+ public:
+ spell_dru_typhoon() : SpellScriptLoader("spell_dru_typhoon") { }
+
+ class spell_dru_typhoon_SpellScript : public SpellScript
+ {
+ PrepareSpellScript(spell_dru_typhoon_SpellScript);
+
+ void HandleKnockBack(SpellEffIndex effIndex)
+ {
+ // Glyph of Typhoon
+ if (GetCaster()->HasAura(SPELL_DRUID_GLYPH_OF_TYPHOON))
+ PreventHitDefaultEffect(effIndex);
+ }
+
+ void Register()
+ {
+ OnEffectHitTarget += SpellEffectFn(spell_dru_typhoon_SpellScript::HandleKnockBack, EFFECT_0, SPELL_EFFECT_KNOCK_BACK);
+ }
+ };
+
+ SpellScript* GetSpellScript() const
+ {
+ return new spell_dru_typhoon_SpellScript();
+ }
+};
+
// 70691 - Item T10 Restoration 4P Bonus
class spell_dru_t10_restoration_4p_bonus : public SpellScriptLoader
{
@@ -834,14 +1106,21 @@ class spell_dru_t10_restoration_4p_bonus : public SpellScriptLoader
void AddSC_druid_spell_scripts()
{
+ new spell_dru_dash();
new spell_dru_eclipse_energize();
new spell_dru_enrage();
new spell_dru_glyph_of_starfire();
+ new spell_dru_idol_lifebloom();
+ new spell_dru_innervate();
new spell_dru_insect_swarm();
new spell_dru_lifebloom();
+ new spell_dru_living_seed();
+ new spell_dru_living_seed_proc();
new spell_dru_moonkin_form_passive();
+ new spell_dru_owlkin_frenzy();
new spell_dru_predatory_strikes();
new spell_dru_primal_tenacity();
+ new spell_dru_rip();
new spell_dru_savage_defense();
new spell_dru_savage_roar();
new spell_dru_starfall_aoe();
@@ -849,5 +1128,6 @@ void AddSC_druid_spell_scripts()
new spell_dru_survival_instincts();
new spell_dru_swift_flight_passive();
new spell_dru_tiger_s_fury();
+ new spell_dru_typhoon();
new spell_dru_t10_restoration_4p_bonus();
}
diff --git a/src/server/scripts/Spells/spell_generic.cpp b/src/server/scripts/Spells/spell_generic.cpp
index d1d4f660172..acaf7f08f36 100644
--- a/src/server/scripts/Spells/spell_generic.cpp
+++ b/src/server/scripts/Spells/spell_generic.cpp
@@ -72,6 +72,97 @@ class spell_gen_absorb0_hitlimit1 : public SpellScriptLoader
}
};
+// 28764 - Adaptive Warding (Frostfire Regalia Set)
+enum AdaptiveWarding
+{
+ SPELL_GEN_ADAPTIVE_WARDING_FIRE = 28765,
+ SPELL_GEN_ADAPTIVE_WARDING_NATURE = 28768,
+ SPELL_GEN_ADAPTIVE_WARDING_FROST = 28766,
+ SPELL_GEN_ADAPTIVE_WARDING_SHADOW = 28769,
+ SPELL_GEN_ADAPTIVE_WARDING_ARCANE = 28770
+};
+
+class spell_gen_adaptive_warding : public SpellScriptLoader
+{
+ public:
+ spell_gen_adaptive_warding() : SpellScriptLoader("spell_gen_adaptive_warding") { }
+
+ class spell_gen_adaptive_warding_AuraScript : public AuraScript
+ {
+ PrepareAuraScript(spell_gen_adaptive_warding_AuraScript);
+
+ bool Validate(SpellInfo const* /*spellInfo*/)
+ {
+ if (!sSpellMgr->GetSpellInfo(SPELL_GEN_ADAPTIVE_WARDING_FIRE) ||
+ !sSpellMgr->GetSpellInfo(SPELL_GEN_ADAPTIVE_WARDING_NATURE) ||
+ !sSpellMgr->GetSpellInfo(SPELL_GEN_ADAPTIVE_WARDING_FROST) ||
+ !sSpellMgr->GetSpellInfo(SPELL_GEN_ADAPTIVE_WARDING_SHADOW) ||
+ !sSpellMgr->GetSpellInfo(SPELL_GEN_ADAPTIVE_WARDING_ARCANE))
+ return false;
+ return true;
+ }
+
+ bool CheckProc(ProcEventInfo& eventInfo)
+ {
+ if (eventInfo.GetDamageInfo()->GetSpellInfo()) // eventInfo.GetSpellInfo()
+ return false;
+
+ // find Mage Armor
+ if (!GetTarget()->GetAuraEffect(SPELL_AURA_MOD_MANA_REGEN_INTERRUPT, SPELLFAMILY_MAGE, 0x10000000, 0x0, 0x0))
+ return false;
+
+ switch (GetFirstSchoolInMask(eventInfo.GetSchoolMask()))
+ {
+ case SPELL_SCHOOL_NORMAL:
+ case SPELL_SCHOOL_HOLY:
+ return false;
+ default:
+ break;
+ }
+ return true;
+ }
+
+ void HandleProc(AuraEffect const* aurEff, ProcEventInfo& eventInfo)
+ {
+ PreventDefaultAction();
+
+ uint32 spellId = 0;
+ switch (GetFirstSchoolInMask(eventInfo.GetSchoolMask()))
+ {
+ case SPELL_SCHOOL_FIRE:
+ spellId = SPELL_GEN_ADAPTIVE_WARDING_FIRE;
+ break;
+ case SPELL_SCHOOL_NATURE:
+ spellId = SPELL_GEN_ADAPTIVE_WARDING_NATURE;
+ break;
+ case SPELL_SCHOOL_FROST:
+ spellId = SPELL_GEN_ADAPTIVE_WARDING_FROST;
+ break;
+ case SPELL_SCHOOL_SHADOW:
+ spellId = SPELL_GEN_ADAPTIVE_WARDING_SHADOW;
+ break;
+ case SPELL_SCHOOL_ARCANE:
+ spellId = SPELL_GEN_ADAPTIVE_WARDING_ARCANE;
+ break;
+ default:
+ return;
+ }
+ GetTarget()->CastSpell(GetTarget(), spellId, true, NULL, aurEff);
+ }
+
+ void Register()
+ {
+ DoCheckProc += AuraCheckProcFn(spell_gen_adaptive_warding_AuraScript::CheckProc);
+ OnEffectProc += AuraEffectProcFn(spell_gen_adaptive_warding_AuraScript::HandleProc, EFFECT_0, SPELL_AURA_DUMMY);
+ }
+ };
+
+ AuraScript* GetAuraScript() const
+ {
+ return new spell_gen_adaptive_warding_AuraScript();
+ }
+};
+
// 41337 Aura of Anger
class spell_gen_aura_of_anger : public SpellScriptLoader
{
@@ -226,6 +317,245 @@ class spell_gen_cannibalize : public SpellScriptLoader
}
};
+// 63845 - Create Lance
+enum CreateLanceSpells
+{
+ SPELL_CREATE_LANCE_ALLIANCE = 63914,
+ SPELL_CREATE_LANCE_HORDE = 63919
+};
+
+class spell_gen_create_lance : public SpellScriptLoader
+{
+ public:
+ spell_gen_create_lance() : SpellScriptLoader("spell_gen_create_lance") { }
+
+ class spell_gen_create_lance_SpellScript : public SpellScript
+ {
+ PrepareSpellScript(spell_gen_create_lance_SpellScript);
+
+ bool Validate(SpellInfo const* /*spellInfo*/)
+ {
+ if (!sSpellMgr->GetSpellInfo(SPELL_CREATE_LANCE_ALLIANCE) || !sSpellMgr->GetSpellInfo(SPELL_CREATE_LANCE_HORDE))
+ return false;
+ return true;
+ }
+
+ void HandleScript(SpellEffIndex effIndex)
+ {
+ PreventHitDefaultEffect(effIndex);
+
+ if (Player* target = GetHitPlayer())
+ {
+ if (target->GetTeam() == ALLIANCE)
+ GetCaster()->CastSpell(target, SPELL_CREATE_LANCE_ALLIANCE, true);
+ else
+ GetCaster()->CastSpell(target, SPELL_CREATE_LANCE_HORDE, true);
+ }
+ }
+
+ void Register()
+ {
+ OnEffectHitTarget += SpellEffectFn(spell_gen_create_lance_SpellScript::HandleScript, EFFECT_0, SPELL_EFFECT_SCRIPT_EFFECT);
+ }
+ };
+
+ SpellScript* GetSpellScript() const
+ {
+ return new spell_gen_create_lance_SpellScript();
+ }
+};
+
+// 28702 - Netherbloom
+enum Netherbloom
+{
+ SPELL_NETHERBLOOM_POLLEN_1 = 28703
+};
+
+class spell_gen_netherbloom : public SpellScriptLoader
+{
+ public:
+ spell_gen_netherbloom() : SpellScriptLoader("spell_gen_netherbloom") { }
+
+ class spell_gen_netherbloom_SpellScript : public SpellScript
+ {
+ PrepareSpellScript(spell_gen_netherbloom_SpellScript);
+
+ bool Validate(SpellInfo const* /*spellInfo*/)
+ {
+ for (uint8 i = 0; i < 5; ++i)
+ if (!sSpellMgr->GetSpellInfo(SPELL_NETHERBLOOM_POLLEN_1 + i))
+ return false;
+ return true;
+ }
+
+ void HandleScript(SpellEffIndex effIndex)
+ {
+ PreventHitDefaultEffect(effIndex);
+
+ if (Unit* target = GetHitUnit())
+ {
+ // 25% chance of casting a random buff
+ if (roll_chance_i(75))
+ return;
+
+ // triggered spells are 28703 to 28707
+ // Note: some sources say, that there was the possibility of
+ // receiving a debuff. However, this seems to be removed by a patch.
+
+ // don't overwrite an existing aura
+ for (uint8 i = 0; i < 5; ++i)
+ if (target->HasAura(SPELL_NETHERBLOOM_POLLEN_1 + i))
+ return;
+
+ target->CastSpell(target, SPELL_NETHERBLOOM_POLLEN_1 + urand(0, 4), true);
+ }
+ }
+
+ void Register()
+ {
+ OnEffectHitTarget += SpellEffectFn(spell_gen_netherbloom_SpellScript::HandleScript, EFFECT_0, SPELL_EFFECT_SCRIPT_EFFECT);
+ }
+ };
+
+ SpellScript* GetSpellScript() const
+ {
+ return new spell_gen_netherbloom_SpellScript();
+ }
+};
+
+// 28720 - Nightmare Vine
+enum NightmareVine
+{
+ SPELL_NIGHTMARE_POLLEN = 28721
+};
+
+class spell_gen_nightmare_vine : public SpellScriptLoader
+{
+ public:
+ spell_gen_nightmare_vine() : SpellScriptLoader("spell_gen_nightmare_vine") { }
+
+ class spell_gen_nightmare_vine_SpellScript : public SpellScript
+ {
+ PrepareSpellScript(spell_gen_nightmare_vine_SpellScript);
+
+ bool Validate(SpellInfo const* /*spellInfo*/)
+ {
+ if (!sSpellMgr->GetSpellInfo(SPELL_NIGHTMARE_POLLEN))
+ return false;
+ return true;
+ }
+
+ void HandleScript(SpellEffIndex effIndex)
+ {
+ PreventHitDefaultEffect(effIndex);
+
+ if (Unit* target = GetHitUnit())
+ {
+ // 25% chance of casting Nightmare Pollen
+ if (roll_chance_i(25))
+ target->CastSpell(target, SPELL_NIGHTMARE_POLLEN, true);
+ }
+ }
+
+ void Register()
+ {
+ OnEffectHitTarget += SpellEffectFn(spell_gen_nightmare_vine_SpellScript::HandleScript, EFFECT_0, SPELL_EFFECT_SCRIPT_EFFECT);
+ }
+ };
+
+ SpellScript* GetSpellScript() const
+ {
+ return new spell_gen_nightmare_vine_SpellScript();
+ }
+};
+
+// 27539 - Obsidian Armor
+enum ObsidianArmor
+{
+ SPELL_GEN_OBSIDIAN_ARMOR_HOLY = 27536,
+ SPELL_GEN_OBSIDIAN_ARMOR_FIRE = 27533,
+ SPELL_GEN_OBSIDIAN_ARMOR_NATURE = 27538,
+ SPELL_GEN_OBSIDIAN_ARMOR_FROST = 27534,
+ SPELL_GEN_OBSIDIAN_ARMOR_SHADOW = 27535,
+ SPELL_GEN_OBSIDIAN_ARMOR_ARCANE = 27540
+};
+
+class spell_gen_obsidian_armor : public SpellScriptLoader
+{
+ public:
+ spell_gen_obsidian_armor() : SpellScriptLoader("spell_gen_obsidian_armor") { }
+
+ class spell_gen_obsidian_armor_AuraScript : public AuraScript
+ {
+ PrepareAuraScript(spell_gen_obsidian_armor_AuraScript);
+
+ bool Validate(SpellInfo const* /*spellInfo*/)
+ {
+ if (!sSpellMgr->GetSpellInfo(SPELL_GEN_OBSIDIAN_ARMOR_HOLY) ||
+ !sSpellMgr->GetSpellInfo(SPELL_GEN_OBSIDIAN_ARMOR_FIRE) ||
+ !sSpellMgr->GetSpellInfo(SPELL_GEN_OBSIDIAN_ARMOR_NATURE) ||
+ !sSpellMgr->GetSpellInfo(SPELL_GEN_OBSIDIAN_ARMOR_FROST) ||
+ !sSpellMgr->GetSpellInfo(SPELL_GEN_OBSIDIAN_ARMOR_SHADOW) ||
+ !sSpellMgr->GetSpellInfo(SPELL_GEN_OBSIDIAN_ARMOR_ARCANE))
+ return false;
+ return true;
+ }
+
+ bool CheckProc(ProcEventInfo& eventInfo)
+ {
+ if (eventInfo.GetDamageInfo()->GetSpellInfo()) // eventInfo.GetSpellInfo()
+ return false;
+
+ if (GetFirstSchoolInMask(eventInfo.GetSchoolMask()) == SPELL_SCHOOL_NORMAL)
+ return false;
+
+ return true;
+ }
+
+ void OnProc(AuraEffect const* aurEff, ProcEventInfo& eventInfo)
+ {
+ PreventDefaultAction();
+
+ uint32 spellId = 0;
+ switch (GetFirstSchoolInMask(eventInfo.GetSchoolMask()))
+ {
+ case SPELL_SCHOOL_HOLY:
+ spellId = SPELL_GEN_OBSIDIAN_ARMOR_HOLY;
+ break;
+ case SPELL_SCHOOL_FIRE:
+ spellId = SPELL_GEN_OBSIDIAN_ARMOR_FIRE;
+ break;
+ case SPELL_SCHOOL_NATURE:
+ spellId = SPELL_GEN_OBSIDIAN_ARMOR_NATURE;
+ break;
+ case SPELL_SCHOOL_FROST:
+ spellId = SPELL_GEN_OBSIDIAN_ARMOR_FROST;
+ break;
+ case SPELL_SCHOOL_SHADOW:
+ spellId = SPELL_GEN_OBSIDIAN_ARMOR_SHADOW;
+ break;
+ case SPELL_SCHOOL_ARCANE:
+ spellId = SPELL_GEN_OBSIDIAN_ARMOR_ARCANE;
+ break;
+ default:
+ return;
+ }
+ GetTarget()->CastSpell(GetTarget(), spellId, true, NULL, aurEff);
+ }
+
+ void Register()
+ {
+ DoCheckProc += AuraCheckProcFn(spell_gen_obsidian_armor_AuraScript::CheckProc);
+ OnEffectProc += AuraEffectProcFn(spell_gen_obsidian_armor_AuraScript::OnProc, EFFECT_0, SPELL_AURA_DUMMY);
+ }
+ };
+
+ AuraScript* GetAuraScript() const
+ {
+ return new spell_gen_obsidian_armor_AuraScript();
+ }
+};
+
// 45472 Parachute
enum ParachuteSpells
{
@@ -3320,10 +3650,15 @@ class spell_gen_darkflight : public SpellScriptLoader
void AddSC_generic_spell_scripts()
{
new spell_gen_absorb0_hitlimit1();
+ new spell_gen_adaptive_warding();
new spell_gen_aura_of_anger();
new spell_gen_av_drekthar_presence();
new spell_gen_burn_brutallus();
new spell_gen_cannibalize();
+ new spell_gen_create_lance();
+ new spell_gen_netherbloom();
+ new spell_gen_nightmare_vine();
+ new spell_gen_obsidian_armor();
new spell_gen_parachute();
new spell_gen_pet_summoned();
new spell_gen_remove_flight_auras();
diff --git a/src/server/scripts/Spells/spell_holiday.cpp b/src/server/scripts/Spells/spell_holiday.cpp
index d883b4d7da7..dbfc2b44501 100644
--- a/src/server/scripts/Spells/spell_holiday.cpp
+++ b/src/server/scripts/Spells/spell_holiday.cpp
@@ -303,27 +303,10 @@ class spell_winter_veil_mistletoe : public SpellScriptLoader
void HandleScript(SpellEffIndex /*effIndex*/)
{
- Unit* caster = GetCaster();
-
if (Player* target = GetHitPlayer())
{
- uint32 spellId = 0;
- switch (urand(0, 2))
- {
- case 0:
- spellId = SPELL_CREATE_MISTLETOE;
- break;
- case 1:
- spellId = SPELL_CREATE_HOLLY;
- break;
- case 2:
- spellId = SPELL_CREATE_SNOWFLAKES;
- break;
- default:
- return;
- }
-
- caster->CastSpell(target, spellId, true);
+ uint32 spellId = RAND(SPELL_CREATE_HOLLY, SPELL_CREATE_MISTLETOE, SPELL_CREATE_SNOWFLAKES);
+ GetCaster()->CastSpell(target, spellId, true);
}
}
@@ -339,6 +322,71 @@ class spell_winter_veil_mistletoe : public SpellScriptLoader
}
};
+// 26275 - PX-238 Winter Wondervolt TRAP
+enum PX238WinterWondervolt
+{
+ SPELL_PX_238_WINTER_WONDERVOLT_TRANSFORM_1 = 26157,
+ SPELL_PX_238_WINTER_WONDERVOLT_TRANSFORM_2 = 26272,
+ SPELL_PX_238_WINTER_WONDERVOLT_TRANSFORM_3 = 26273,
+ SPELL_PX_238_WINTER_WONDERVOLT_TRANSFORM_4 = 26274
+};
+
+class spell_winter_veil_px_238_winter_wondervolt : public SpellScriptLoader
+{
+ public:
+ spell_winter_veil_px_238_winter_wondervolt() : SpellScriptLoader("spell_winter_veil_px_238_winter_wondervolt") { }
+
+ class spell_winter_veil_px_238_winter_wondervolt_SpellScript : public SpellScript
+ {
+ PrepareSpellScript(spell_winter_veil_px_238_winter_wondervolt_SpellScript);
+
+ bool Validate(SpellInfo const* /*spellInfo*/)
+ {
+ if (!sSpellMgr->GetSpellInfo(SPELL_PX_238_WINTER_WONDERVOLT_TRANSFORM_1) ||
+ !sSpellMgr->GetSpellInfo(SPELL_PX_238_WINTER_WONDERVOLT_TRANSFORM_2) ||
+ !sSpellMgr->GetSpellInfo(SPELL_PX_238_WINTER_WONDERVOLT_TRANSFORM_3) ||
+ !sSpellMgr->GetSpellInfo(SPELL_PX_238_WINTER_WONDERVOLT_TRANSFORM_4))
+ return false;
+ return true;
+ }
+
+ void HandleScript(SpellEffIndex effIndex)
+ {
+ PreventHitDefaultEffect(effIndex);
+
+ uint32 const spells[4] =
+ {
+ SPELL_PX_238_WINTER_WONDERVOLT_TRANSFORM_1,
+ SPELL_PX_238_WINTER_WONDERVOLT_TRANSFORM_2,
+ SPELL_PX_238_WINTER_WONDERVOLT_TRANSFORM_3,
+ SPELL_PX_238_WINTER_WONDERVOLT_TRANSFORM_4
+ };
+
+ if (Unit* target = GetHitUnit())
+ {
+ for (uint8 i = 0; i < 4; ++i)
+ if (target->HasAura(spells[i]))
+ return;
+
+ GetCaster()->CastSpell(target, spells[urand(0, 3)], true);
+ }
+ }
+
+ void Register()
+ {
+ OnEffectHitTarget += SpellEffectFn(spell_winter_veil_px_238_winter_wondervolt_SpellScript::HandleScript, EFFECT_0, SPELL_EFFECT_SCRIPT_EFFECT);
+ }
+
+ private:
+
+ };
+
+ SpellScript* GetSpellScript() const
+ {
+ return new spell_winter_veil_px_238_winter_wondervolt_SpellScript();
+ }
+};
+
void AddSC_holiday_spell_scripts()
{
// Love is in the Air
@@ -349,4 +397,5 @@ void AddSC_holiday_spell_scripts()
new spell_hallow_end_tricky_treat();
// Winter Veil
new spell_winter_veil_mistletoe();
+ new spell_winter_veil_px_238_winter_wondervolt();
}
diff --git a/src/server/scripts/Spells/spell_hunter.cpp b/src/server/scripts/Spells/spell_hunter.cpp
index a9b21807899..891a7daaa1f 100644
--- a/src/server/scripts/Spells/spell_hunter.cpp
+++ b/src/server/scripts/Spells/spell_hunter.cpp
@@ -33,12 +33,15 @@
enum HunterSpells
{
SPELL_HUNTER_ASPECT_OF_THE_BEAST_PET = 61669,
+ SPELL_HUNTER_ASPECT_OF_THE_VIPER_ENERGIZE = 34075,
SPELL_HUNTER_BESTIAL_WRATH = 19574,
SPELL_HUNTER_CHIMERA_SHOT_SERPENT = 53353,
SPELL_HUNTER_CHIMERA_SHOT_VIPER = 53358,
SPELL_HUNTER_CHIMERA_SHOT_SCORPID = 53359,
+ SPELL_HUNTER_GLYPH_OF_ASPECT_OF_THE_VIPER = 56851,
SPELL_HUNTER_INVIGORATION_TRIGGERED = 53398,
SPELL_HUNTER_MASTERS_CALL_TRIGGERED = 62305,
+ SPELL_HUNTER_MISDIRECTION_PROC = 35079,
SPELL_HUNTER_PET_LAST_STAND_TRIGGERED = 53479,
SPELL_HUNTER_PET_HEART_OF_THE_PHOENIX = 55709,
SPELL_HUNTER_PET_HEART_OF_THE_PHOENIX_TRIGGERED = 54114,
@@ -99,6 +102,50 @@ class spell_hun_aspect_of_the_beast : public SpellScriptLoader
}
};
+// 34074 - Aspect of the Viper
+class spell_hun_ascpect_of_the_viper : public SpellScriptLoader
+{
+ public:
+ spell_hun_ascpect_of_the_viper() : SpellScriptLoader("spell_hun_ascpect_of_the_viper") { }
+
+ class spell_hun_ascpect_of_the_viper_AuraScript : public AuraScript
+ {
+ PrepareAuraScript(spell_hun_ascpect_of_the_viper_AuraScript);
+
+ bool Validate(SpellInfo const* /*spellInfo*/)
+ {
+ if (!sSpellMgr->GetSpellInfo(SPELL_HUNTER_ASPECT_OF_THE_VIPER_ENERGIZE))
+ return false;
+ if (!sSpellMgr->GetSpellInfo(SPELL_HUNTER_GLYPH_OF_ASPECT_OF_THE_VIPER))
+ return false;
+ return true;
+ }
+
+ void HandleProc(AuraEffect const* aurEff, ProcEventInfo& /*eventInfo*/)
+ {
+ PreventDefaultAction();
+
+ uint32 maxMana = GetTarget()->GetMaxPower(POWER_MANA);
+ int32 mana = CalculatePct(maxMana, GetTarget()->GetAttackTime(RANGED_ATTACK) / 1000.0f);
+
+ if (AuraEffect const* glyph = GetTarget()->GetAuraEffect(SPELL_HUNTER_GLYPH_OF_ASPECT_OF_THE_VIPER, EFFECT_0))
+ AddPct(mana, glyph->GetAmount());
+
+ GetTarget()->CastCustomSpell(SPELL_HUNTER_ASPECT_OF_THE_VIPER_ENERGIZE, SPELLVALUE_BASE_POINT0, mana, GetTarget(), true, NULL, aurEff);
+ }
+
+ void Register()
+ {
+ OnEffectProc += AuraEffectProcFn(spell_hun_ascpect_of_the_viper_AuraScript::HandleProc, EFFECT_0, SPELL_AURA_OBS_MOD_POWER);
+ }
+ };
+
+ AuraScript* GetAuraScript() const
+ {
+ return new spell_hun_ascpect_of_the_viper_AuraScript();
+ }
+};
+
// 53209 - Chimera Shot
class spell_hun_chimera_shot : public SpellScriptLoader
{
@@ -358,16 +405,35 @@ class spell_hun_misdirection : public SpellScriptLoader
{
PrepareAuraScript(spell_hun_misdirection_AuraScript);
+ bool Validate(SpellInfo const* /*spellInfo*/)
+ {
+ if (!sSpellMgr->GetSpellInfo(SPELL_HUNTER_MISDIRECTION_PROC))
+ return false;
+ return true;
+ }
+
void OnRemove(AuraEffect const* /*aurEff*/, AuraEffectHandleModes /*mode*/)
{
- if (Unit* caster = GetCaster())
- if (GetTargetApplication()->GetRemoveMode() != AURA_REMOVE_BY_DEFAULT)
- caster->SetReducedThreatPercent(0, 0);
+ if (GetTargetApplication()->GetRemoveMode() != AURA_REMOVE_BY_DEFAULT)
+ GetTarget()->ResetRedirectThreat();
+ }
+
+ bool CheckProc(ProcEventInfo& /*eventInfo*/)
+ {
+ return GetTarget()->GetRedirectThreatTarget();
+ }
+
+ void HandleProc(AuraEffect const* aurEff, ProcEventInfo& /*eventInfo*/)
+ {
+ PreventDefaultAction();
+ GetTarget()->CastSpell(GetTarget(), SPELL_HUNTER_MISDIRECTION_PROC, true, NULL, aurEff);
}
void Register()
{
AfterEffectRemove += AuraEffectRemoveFn(spell_hun_misdirection_AuraScript::OnRemove, EFFECT_1, SPELL_AURA_DUMMY, AURA_EFFECT_HANDLE_REAL);
+ DoCheckProc += AuraCheckProcFn(spell_hun_misdirection_AuraScript::CheckProc);
+ OnEffectProc += AuraEffectProcFn(spell_hun_misdirection_AuraScript::HandleProc, EFFECT_1, SPELL_AURA_DUMMY);
}
};
@@ -377,7 +443,7 @@ class spell_hun_misdirection : public SpellScriptLoader
}
};
-// 35079 - Misdirection proc
+// 35079 - Misdirection (Proc)
class spell_hun_misdirection_proc : public SpellScriptLoader
{
public:
@@ -389,8 +455,7 @@ class spell_hun_misdirection_proc : public SpellScriptLoader
void OnRemove(AuraEffect const* /*aurEff*/, AuraEffectHandleModes /*mode*/)
{
- if (GetCaster())
- GetCaster()->SetReducedThreatPercent(0, 0);
+ GetTarget()->ResetRedirectThreat();
}
void Register()
@@ -740,6 +805,7 @@ class spell_hun_target_only_pet_and_owner : public SpellScriptLoader
void AddSC_hunter_spell_scripts()
{
new spell_hun_aspect_of_the_beast();
+ new spell_hun_ascpect_of_the_viper();
new spell_hun_chimera_shot();
new spell_hun_disengage();
new spell_hun_invigoration();
diff --git a/src/server/scripts/Spells/spell_item.cpp b/src/server/scripts/Spells/spell_item.cpp
index b4e06cb6b48..b8e17f4ecca 100644
--- a/src/server/scripts/Spells/spell_item.cpp
+++ b/src/server/scripts/Spells/spell_item.cpp
@@ -73,6 +73,150 @@ class spell_item_trigger_spell : public SpellScriptLoader
}
};
+// 26400 - Arcane Shroud
+class spell_item_arcane_shroud : public SpellScriptLoader
+{
+ public:
+ spell_item_arcane_shroud() : SpellScriptLoader("spell_item_arcane_shroud") { }
+
+ class spell_item_arcane_shroud_AuraScript : public AuraScript
+ {
+ PrepareAuraScript(spell_item_arcane_shroud_AuraScript);
+
+ void CalculateAmount(AuraEffect const* /*aurEff*/, int32& amount, bool& /*canBeRecalculated*/)
+ {
+ int32 diff = GetUnitOwner()->getLevel() - 60;
+ if (diff > 0)
+ amount += 2 * diff;
+ }
+
+ void Register()
+ {
+ DoEffectCalcAmount += AuraEffectCalcAmountFn(spell_item_arcane_shroud_AuraScript::CalculateAmount, EFFECT_0, SPELL_AURA_MOD_THREAT);
+ }
+ };
+
+ AuraScript* GetAuraScript() const
+ {
+ return new spell_item_arcane_shroud_AuraScript();
+ }
+};
+
+// 64411 - Blessing of Ancient Kings (Val'anyr, Hammer of Ancient Kings)
+enum BlessingOfAncientKings
+{
+ SPELL_PROTECTION_OF_ANCIENT_KINGS = 64413
+};
+
+class spell_item_blessing_of_ancient_kings : public SpellScriptLoader
+{
+ public:
+ spell_item_blessing_of_ancient_kings() : SpellScriptLoader("spell_item_blessing_of_ancient_kings") { }
+
+ class spell_item_blessing_of_ancient_kings_AuraScript : public AuraScript
+ {
+ PrepareAuraScript(spell_item_blessing_of_ancient_kings_AuraScript);
+
+ bool Validate(SpellInfo const* /*spellInfo*/)
+ {
+ if (!sSpellMgr->GetSpellInfo(SPELL_PROTECTION_OF_ANCIENT_KINGS))
+ return false;
+ return true;
+ }
+
+ bool CheckProc(ProcEventInfo& eventInfo)
+ {
+ return eventInfo.GetProcTarget();
+ }
+
+ void HandleProc(AuraEffect const* aurEff, ProcEventInfo& eventInfo)
+ {
+ PreventDefaultAction();
+
+ int32 absorb = int32(CalculatePct(eventInfo.GetHealInfo()->GetHeal(), 15.0f));
+ if (AuraEffect* protEff = eventInfo.GetProcTarget()->GetAuraEffect(SPELL_PROTECTION_OF_ANCIENT_KINGS, 0, eventInfo.GetActor()->GetGUID()))
+ {
+ // The shield can grow to a maximum size of 20,000 damage absorbtion
+ protEff->SetAmount(std::min<int32>(protEff->GetAmount() + absorb, 20000));
+
+ // Refresh and return to prevent replacing the aura
+ aurEff->GetBase()->RefreshDuration();
+ }
+ else
+ GetTarget()->CastCustomSpell(SPELL_PROTECTION_OF_ANCIENT_KINGS, SPELLVALUE_BASE_POINT0, absorb, eventInfo.GetProcTarget(), true, NULL, aurEff);
+ }
+
+ void Register()
+ {
+ DoCheckProc += AuraCheckProcFn(spell_item_blessing_of_ancient_kings_AuraScript::CheckProc);
+ OnEffectProc += AuraEffectProcFn(spell_item_blessing_of_ancient_kings_AuraScript::HandleProc, EFFECT_0, SPELL_AURA_DUMMY);
+ }
+ };
+
+ AuraScript* GetAuraScript() const
+ {
+ return new spell_item_blessing_of_ancient_kings_AuraScript();
+ }
+};
+
+// 8342 - Defibrillate (Goblin Jumper Cables) have 33% chance on success
+// 22999 - Defibrillate (Goblin Jumper Cables XL) have 50% chance on success
+// 54732 - Defibrillate (Gnomish Army Knife) have 67% chance on success
+enum Defibrillate
+{
+ SPELL_GOBLIN_JUMPER_CABLES_FAIL = 8338,
+ SPELL_GOBLIN_JUMPER_CABLES_XL_FAIL = 23055
+};
+
+class spell_item_defibrillate : public SpellScriptLoader
+{
+ public:
+ spell_item_defibrillate(char const* name, uint8 chance, uint32 failSpell = 0) : SpellScriptLoader(name), _chance(chance), _failSpell(failSpell) { }
+
+ class spell_item_defibrillate_SpellScript : public SpellScript
+ {
+ PrepareSpellScript(spell_item_defibrillate_SpellScript);
+
+ public:
+ spell_item_defibrillate_SpellScript(uint8 chance, uint32 failSpell) : SpellScript(), _chance(chance), _failSpell(failSpell) { }
+
+ bool Validate(SpellInfo const* /*spellInfo*/)
+ {
+ if (_failSpell && !sSpellMgr->GetSpellInfo(_failSpell))
+ return false;
+ return true;
+ }
+
+ void HandleScript(SpellEffIndex effIndex)
+ {
+ if (roll_chance_i(_chance))
+ {
+ PreventHitDefaultEffect(effIndex);
+ if (_failSpell)
+ GetCaster()->CastSpell(GetCaster(), _failSpell, true, GetCastItem());
+ }
+ }
+
+ void Register()
+ {
+ OnEffectHitTarget += SpellEffectFn(spell_item_defibrillate_SpellScript::HandleScript, EFFECT_0, SPELL_EFFECT_RESURRECT);
+ }
+
+ private:
+ uint8 _chance;
+ uint32 _failSpell;
+ };
+
+ SpellScript* GetSpellScript() const
+ {
+ return new spell_item_defibrillate_SpellScript(_chance, _failSpell);
+ }
+
+ private:
+ uint8 _chance;
+ uint32 _failSpell;
+};
+
// http://www.wowhead.com/item=6522 Deviate Fish
// 8063 Deviate Fish
enum DeviateFishSpells
@@ -357,6 +501,47 @@ class spell_item_mingos_fortune_generator : public SpellScriptLoader
}
};
+// 71875, 71877 - Item - Black Bruise: Necrotic Touch Proc
+enum NecroticTouch
+{
+ SPELL_ITEM_NECROTIC_TOUCH_PROC = 71879
+};
+
+class spell_item_necrotic_touch : public SpellScriptLoader
+{
+ public:
+ spell_item_necrotic_touch() : SpellScriptLoader("spell_item_necrotic_touch") { }
+
+ class spell_item_necrotic_touch_AuraScript : public AuraScript
+ {
+ PrepareAuraScript(spell_item_necrotic_touch_AuraScript);
+
+ bool Validate(SpellInfo const* /*spellInfo*/)
+ {
+ if (!sSpellMgr->GetSpellInfo(SPELL_ITEM_NECROTIC_TOUCH_PROC))
+ return false;
+ return true;
+ }
+
+ void HandleProc(AuraEffect const* aurEff, ProcEventInfo& eventInfo)
+ {
+ PreventDefaultAction();
+ int32 bp = CalculatePct(int32(eventInfo.GetDamageInfo()->GetDamage()), aurEff->GetAmount());
+ GetTarget()->CastCustomSpell(SPELL_ITEM_NECROTIC_TOUCH_PROC, SPELLVALUE_BASE_POINT0, bp, GetTarget(), true, NULL, aurEff);
+ }
+
+ void Register()
+ {
+ OnEffectProc += AuraEffectProcFn(spell_item_necrotic_touch_AuraScript::HandleProc, EFFECT_0, SPELL_AURA_DUMMY);
+ }
+ };
+
+ AuraScript* GetAuraScript() const
+ {
+ return new spell_item_necrotic_touch_AuraScript();
+ }
+};
+
// http://www.wowhead.com/item=10720 Gnomish Net-o-Matic Projector
// 13120 Net-o-Matic
enum NetOMaticSpells
@@ -464,6 +649,35 @@ class spell_item_noggenfogger_elixir : public SpellScriptLoader
}
};
+// 17512 - Piccolo of the Flaming Fire
+class spell_item_piccolo_of_the_flaming_fire : public SpellScriptLoader
+{
+ public:
+ spell_item_piccolo_of_the_flaming_fire() : SpellScriptLoader("spell_item_piccolo_of_the_flaming_fire") { }
+
+ class spell_item_piccolo_of_the_flaming_fire_SpellScript : public SpellScript
+ {
+ PrepareSpellScript(spell_item_piccolo_of_the_flaming_fire_SpellScript);
+
+ void HandleScript(SpellEffIndex effIndex)
+ {
+ PreventHitDefaultEffect(effIndex);
+ if (Player* target = GetHitPlayer())
+ target->HandleEmoteCommand(EMOTE_STATE_DANCE);
+ }
+
+ void Register()
+ {
+ OnEffectHitTarget += SpellEffectFn(spell_item_piccolo_of_the_flaming_fire_SpellScript::HandleScript, EFFECT_0, SPELL_EFFECT_SCRIPT_EFFECT);
+ }
+ };
+
+ SpellScript* GetSpellScript() const
+ {
+ return new spell_item_piccolo_of_the_flaming_fire_SpellScript();
+ }
+};
+
// http://www.wowhead.com/item=6657 Savory Deviate Delight
// 8213 Savory Deviate Delight
enum SavoryDeviateDelight
@@ -522,6 +736,262 @@ class spell_item_savory_deviate_delight : public SpellScriptLoader
}
};
+// 48129 - Scroll of Recall
+// 60320 - Scroll of Recall II
+// 60321 - Scroll of Recall III
+enum ScrollOfRecall
+{
+ SPELL_SCROLL_OF_RECALL_I = 48129,
+ SPELL_SCROLL_OF_RECALL_II = 60320,
+ SPELL_SCROLL_OF_RECALL_III = 60321,
+ SPELL_LOST = 60444,
+ SPELL_SCROLL_OF_RECALL_FAIL_ALLIANCE_1 = 60323,
+ SPELL_SCROLL_OF_RECALL_FAIL_HORDE_1 = 60328,
+};
+
+class spell_item_scroll_of_recall : public SpellScriptLoader
+{
+ public:
+ spell_item_scroll_of_recall() : SpellScriptLoader("spell_item_scroll_of_recall") { }
+
+ class spell_item_scroll_of_recall_SpellScript : public SpellScript
+ {
+ PrepareSpellScript(spell_item_scroll_of_recall_SpellScript);
+
+ bool Load()
+ {
+ return GetCaster()->GetTypeId() == TYPEID_PLAYER;
+ }
+
+ void HandleScript(SpellEffIndex effIndex)
+ {
+ Unit* caster = GetCaster();
+ uint8 maxSafeLevel = 0;
+ switch (GetSpellInfo()->Id)
+ {
+ case SPELL_SCROLL_OF_RECALL_I: // Scroll of Recall
+ maxSafeLevel = 40;
+ break;
+ case SPELL_SCROLL_OF_RECALL_II: // Scroll of Recall II
+ maxSafeLevel = 70;
+ break;
+ case SPELL_SCROLL_OF_RECALL_III: // Scroll of Recal III
+ maxSafeLevel = 80;
+ break;
+ default:
+ break;
+ }
+
+ if (caster->getLevel() > maxSafeLevel)
+ {
+ caster->CastSpell(caster, SPELL_LOST, true);
+
+ // ALLIANCE from 60323 to 60330 - HORDE from 60328 to 60335
+ uint32 spellId = SPELL_SCROLL_OF_RECALL_FAIL_ALLIANCE_1;
+ if (GetCaster()->ToPlayer()->GetTeam() == HORDE)
+ spellId = SPELL_SCROLL_OF_RECALL_FAIL_HORDE_1;
+
+ GetCaster()->CastSpell(GetCaster(), spellId + urand(0, 7), true);
+
+ PreventHitDefaultEffect(effIndex);
+ }
+ }
+
+ void Register()
+ {
+ OnEffectHitTarget += SpellEffectFn(spell_item_scroll_of_recall_SpellScript::HandleScript, EFFECT_0, SPELL_EFFECT_TELEPORT_UNITS);
+ }
+ };
+
+ SpellScript* GetSpellScript() const
+ {
+ return new spell_item_scroll_of_recall_SpellScript();
+ }
+};
+
+// 71169 - Shadow's Fate (Shadowmourne questline)
+enum ShadowsFate
+{
+ SPELL_SOUL_FEAST = 71203,
+ QUEST_A_FEAST_OF_SOULS = 24547
+};
+
+class spell_item_shadows_fate : public SpellScriptLoader
+{
+ public:
+ spell_item_shadows_fate() : SpellScriptLoader("spell_item_shadows_fate") { }
+
+ class spell_item_shadows_fate_AuraScript : public AuraScript
+ {
+ PrepareAuraScript(spell_item_shadows_fate_AuraScript);
+
+ bool Validate(SpellInfo const* /*spellInfo*/)
+ {
+ if (!sSpellMgr->GetSpellInfo(SPELL_SOUL_FEAST))
+ return false;
+ if (!sObjectMgr->GetQuestTemplate(QUEST_A_FEAST_OF_SOULS))
+ return false;
+ return true;
+ }
+
+ bool Load()
+ {
+ _procTarget = NULL;
+ return true;
+ }
+
+ bool CheckProc(ProcEventInfo& /*eventInfo*/)
+ {
+ _procTarget = GetCaster();
+ return _procTarget && _procTarget->GetTypeId() == TYPEID_PLAYER && _procTarget->ToPlayer()->GetQuestStatus(QUEST_A_FEAST_OF_SOULS) == QUEST_STATUS_INCOMPLETE;
+ }
+
+ void HandleProc(AuraEffect const* /*aurEff*/, ProcEventInfo& /*eventInfo*/)
+ {
+ PreventDefaultAction();
+ GetTarget()->CastSpell(_procTarget, SPELL_SOUL_FEAST, true);
+ }
+
+ void Register()
+ {
+ DoCheckProc += AuraCheckProcFn(spell_item_shadows_fate_AuraScript::CheckProc);
+ OnEffectProc += AuraEffectProcFn(spell_item_shadows_fate_AuraScript::HandleProc, EFFECT_0, SPELL_AURA_DUMMY);
+ }
+
+ private:
+ Unit* _procTarget;
+ };
+
+ AuraScript* GetAuraScript() const
+ {
+ return new spell_item_shadows_fate_AuraScript();
+ }
+};
+
+enum Shadowmourne
+{
+ SPELL_SHADOWMOURNE_CHAOS_BANE_DAMAGE = 71904,
+ SPELL_SHADOWMOURNE_SOUL_FRAGMENT = 71905,
+ SPELL_SHADOWMOURNE_VISUAL_LOW = 72521,
+ SPELL_SHADOWMOURNE_VISUAL_HIGH = 72523,
+ SPELL_SHADOWMOURNE_CHAOS_BANE_BUFF = 73422,
+};
+
+// 71903 - Item - Shadowmourne Legendary
+class spell_item_shadowmourne : public SpellScriptLoader
+{
+ public:
+ spell_item_shadowmourne() : SpellScriptLoader("spell_item_shadowmourne") { }
+
+ class spell_item_shadowmourne_AuraScript : public AuraScript
+ {
+ PrepareAuraScript(spell_item_shadowmourne_AuraScript);
+
+ bool Validate(SpellInfo const* /*spellInfo*/)
+ {
+ if (!sSpellMgr->GetSpellInfo(SPELL_SHADOWMOURNE_CHAOS_BANE_DAMAGE))
+ return false;
+ if (!sSpellMgr->GetSpellInfo(SPELL_SHADOWMOURNE_SOUL_FRAGMENT))
+ return false;
+ if (!sSpellMgr->GetSpellInfo(SPELL_SHADOWMOURNE_CHAOS_BANE_BUFF))
+ return false;
+ return true;
+ }
+
+ bool CheckProc(ProcEventInfo& eventInfo)
+ {
+ if (GetTarget()->HasAura(SPELL_SHADOWMOURNE_CHAOS_BANE_BUFF)) // cant collect shards while under effect of Chaos Bane buff
+ return false;
+ return eventInfo.GetProcTarget() && eventInfo.GetProcTarget()->isAlive();
+ }
+
+ void HandleProc(AuraEffect const* aurEff, ProcEventInfo& eventInfo)
+ {
+ PreventDefaultAction();
+ GetTarget()->CastSpell(GetTarget(), SPELL_SHADOWMOURNE_SOUL_FRAGMENT, true, NULL, aurEff);
+
+ // this can't be handled in AuraScript of SoulFragments because we need to know victim
+ if (Aura* soulFragments = GetTarget()->GetAura(SPELL_SHADOWMOURNE_SOUL_FRAGMENT))
+ {
+ if (soulFragments->GetStackAmount() >= 10)
+ {
+ GetTarget()->CastSpell(eventInfo.GetProcTarget(), SPELL_SHADOWMOURNE_CHAOS_BANE_DAMAGE, true, NULL, aurEff);
+ soulFragments->Remove();
+ }
+ }
+ }
+
+ void Register()
+ {
+ DoCheckProc += AuraCheckProcFn(spell_item_shadowmourne_AuraScript::CheckProc);
+ OnEffectProc += AuraEffectProcFn(spell_item_shadowmourne_AuraScript::HandleProc, EFFECT_0, SPELL_AURA_DUMMY);
+ }
+ };
+
+ AuraScript* GetAuraScript() const
+ {
+ return new spell_item_shadowmourne_AuraScript();
+ }
+};
+
+// 71905 - Soul Fragment
+class spell_item_shadowmourne_soul_fragment : public SpellScriptLoader
+{
+ public:
+ spell_item_shadowmourne_soul_fragment() : SpellScriptLoader("spell_item_shadowmourne_soul_fragment") { }
+
+ class spell_item_shadowmourne_soul_fragment_AuraScript : public AuraScript
+ {
+ PrepareAuraScript(spell_item_shadowmourne_soul_fragment_AuraScript);
+
+ bool Validate(SpellInfo const* /*spellInfo*/)
+ {
+ if (!sSpellMgr->GetSpellInfo(SPELL_SHADOWMOURNE_VISUAL_LOW) || !sSpellMgr->GetSpellInfo(SPELL_SHADOWMOURNE_VISUAL_HIGH) || !sSpellMgr->GetSpellInfo(SPELL_SHADOWMOURNE_CHAOS_BANE_BUFF))
+ return false;
+ return true;
+ }
+
+ void OnStackChange(AuraEffect const* /*aurEff*/, AuraEffectHandleModes /*mode*/)
+ {
+ Unit* target = GetTarget();
+ switch (GetStackAmount())
+ {
+ case 1:
+ target->CastSpell(target, SPELL_SHADOWMOURNE_VISUAL_LOW, true);
+ break;
+ case 6:
+ target->RemoveAurasDueToSpell(SPELL_SHADOWMOURNE_VISUAL_LOW);
+ target->CastSpell(target, SPELL_SHADOWMOURNE_VISUAL_HIGH, true);
+ break;
+ case 10:
+ target->RemoveAurasDueToSpell(SPELL_SHADOWMOURNE_VISUAL_HIGH);
+ target->CastSpell(target, SPELL_SHADOWMOURNE_CHAOS_BANE_BUFF, true);
+ break;
+ default:
+ break;
+ }
+ }
+
+ void OnRemove(AuraEffect const* /*aurEff*/, AuraEffectHandleModes /*mode*/)
+ {
+ Unit* target = GetTarget();
+ target->RemoveAurasDueToSpell(SPELL_SHADOWMOURNE_VISUAL_LOW);
+ target->RemoveAurasDueToSpell(SPELL_SHADOWMOURNE_VISUAL_HIGH);
+ }
+
+ void Register()
+ {
+ AfterEffectApply += AuraEffectApplyFn(spell_item_shadowmourne_soul_fragment_AuraScript::OnStackChange, EFFECT_0, SPELL_AURA_MOD_STAT, AuraEffectHandleModes(AURA_EFFECT_HANDLE_REAL | AURA_EFFECT_HANDLE_REAPPLY));
+ AfterEffectRemove += AuraEffectRemoveFn(spell_item_shadowmourne_soul_fragment_AuraScript::OnRemove, EFFECT_0, SPELL_AURA_MOD_STAT, AURA_EFFECT_HANDLE_REAL);
+ }
+ };
+
+ AuraScript* GetAuraScript() const
+ {
+ return new spell_item_shadowmourne_soul_fragment_AuraScript();
+ }
+};
+
// http://www.wowhead.com/item=7734 Six Demon Bag
// 14537 Six Demon Bag
enum SixDemonBagSpells
@@ -593,6 +1063,35 @@ class spell_item_six_demon_bag : public SpellScriptLoader
}
};
+// 28862 - The Eye of Diminution
+class spell_item_the_eye_of_diminution : public SpellScriptLoader
+{
+ public:
+ spell_item_the_eye_of_diminution() : SpellScriptLoader("spell_item_the_eye_of_diminution") { }
+
+ class spell_item_the_eye_of_diminution_AuraScript : public AuraScript
+ {
+ PrepareAuraScript(spell_item_the_eye_of_diminution_AuraScript);
+
+ void CalculateAmount(AuraEffect const* /*aurEff*/, int32& amount, bool& /*canBeRecalculated*/)
+ {
+ int32 diff = GetUnitOwner()->getLevel() - 60;
+ if (diff > 0)
+ amount += diff;
+ }
+
+ void Register()
+ {
+ DoEffectCalcAmount += AuraEffectCalcAmountFn(spell_item_the_eye_of_diminution_AuraScript::CalculateAmount, EFFECT_0, SPELL_AURA_MOD_THREAT);
+ }
+ };
+
+ AuraScript* GetAuraScript() const
+ {
+ return new spell_item_the_eye_of_diminution_AuraScript();
+ }
+};
+
// http://www.wowhead.com/item=44012 Underbelly Elixir
// 59640 Underbelly Elixir
enum UnderbellyElixirSpells
@@ -646,70 +1145,6 @@ class spell_item_underbelly_elixir : public SpellScriptLoader
}
};
-enum eShadowmourneVisuals
-{
- SPELL_SHADOWMOURNE_VISUAL_LOW = 72521,
- SPELL_SHADOWMOURNE_VISUAL_HIGH = 72523,
- SPELL_SHADOWMOURNE_CHAOS_BANE_BUFF = 73422,
-};
-
-class spell_item_shadowmourne : public SpellScriptLoader
-{
-public:
- spell_item_shadowmourne() : SpellScriptLoader("spell_item_shadowmourne") { }
-
- class spell_item_shadowmourne_AuraScript : public AuraScript
- {
- PrepareAuraScript(spell_item_shadowmourne_AuraScript);
-
- bool Validate(SpellInfo const* /*spellEntry*/)
- {
- if (!sSpellMgr->GetSpellInfo(SPELL_SHADOWMOURNE_VISUAL_LOW) || !sSpellMgr->GetSpellInfo(SPELL_SHADOWMOURNE_VISUAL_HIGH) || !sSpellMgr->GetSpellInfo(SPELL_SHADOWMOURNE_CHAOS_BANE_BUFF))
- return false;
- return true;
- }
-
- void OnStackChange(AuraEffect const* /*aurEff*/, AuraEffectHandleModes /*mode*/)
- {
- Unit* target = GetTarget();
- switch (GetStackAmount())
- {
- case 1:
- target->CastSpell(target, SPELL_SHADOWMOURNE_VISUAL_LOW, true);
- break;
- case 6:
- target->RemoveAurasDueToSpell(SPELL_SHADOWMOURNE_VISUAL_LOW);
- target->CastSpell(target, SPELL_SHADOWMOURNE_VISUAL_HIGH, true);
- break;
- case 10:
- target->RemoveAurasDueToSpell(SPELL_SHADOWMOURNE_VISUAL_HIGH);
- target->CastSpell(target, SPELL_SHADOWMOURNE_CHAOS_BANE_BUFF, true);
- break;
- default:
- break;
- }
- }
-
- void OnRemove(AuraEffect const* /*aurEff*/, AuraEffectHandleModes /*mode*/)
- {
- Unit* target = GetTarget();
- target->RemoveAurasDueToSpell(SPELL_SHADOWMOURNE_VISUAL_LOW);
- target->RemoveAurasDueToSpell(SPELL_SHADOWMOURNE_VISUAL_HIGH);
- }
-
- void Register()
- {
- AfterEffectApply += AuraEffectApplyFn(spell_item_shadowmourne_AuraScript::OnStackChange, EFFECT_0, SPELL_AURA_MOD_STAT, AuraEffectHandleModes(AURA_EFFECT_HANDLE_REAL | AURA_EFFECT_HANDLE_REAPPLY));
- AfterEffectRemove += AuraEffectRemoveFn(spell_item_shadowmourne_AuraScript::OnRemove, EFFECT_0, SPELL_AURA_MOD_STAT, AURA_EFFECT_HANDLE_REAL);
- }
- };
-
- AuraScript* GetAuraScript() const
- {
- return new spell_item_shadowmourne_AuraScript();
- }
-};
-
enum AirRifleSpells
{
SPELL_AIR_RIFLE_HOLD_VISUAL = 65582,
@@ -2030,17 +2465,28 @@ void AddSC_item_spell_scripts()
// 23075 Mithril Mechanical Dragonling
new spell_item_trigger_spell("spell_item_mithril_mechanical_dragonling", SPELL_MITHRIL_MECHANICAL_DRAGONLING);
+ new spell_item_arcane_shroud();
+ new spell_item_blessing_of_ancient_kings();
+ new spell_item_defibrillate("spell_item_goblin_jumper_cables", 67, SPELL_GOBLIN_JUMPER_CABLES_FAIL);
+ new spell_item_defibrillate("spell_item_goblin_jumper_cables_xl", 50, SPELL_GOBLIN_JUMPER_CABLES_XL_FAIL);
+ new spell_item_defibrillate("spell_item_gnomish_army_knife", 33);
new spell_item_deviate_fish();
new spell_item_flask_of_the_north();
new spell_item_gnomish_death_ray();
new spell_item_make_a_wish();
new spell_item_mingos_fortune_generator();
+ new spell_item_necrotic_touch();
new spell_item_net_o_matic();
new spell_item_noggenfogger_elixir();
+ new spell_item_piccolo_of_the_flaming_fire();
new spell_item_savory_deviate_delight();
+ new spell_item_scroll_of_recall();
+ new spell_item_shadows_fate();
+ new spell_item_shadowmourne();
+ new spell_item_shadowmourne_soul_fragment();
new spell_item_six_demon_bag();
+ new spell_item_the_eye_of_diminution();
new spell_item_underbelly_elixir();
- new spell_item_shadowmourne();
new spell_item_red_rider_air_rifle();
new spell_item_create_heart_candy();
diff --git a/src/server/scripts/Spells/spell_mage.cpp b/src/server/scripts/Spells/spell_mage.cpp
index 8c33117bb96..e14327b0f36 100644
--- a/src/server/scripts/Spells/spell_mage.cpp
+++ b/src/server/scripts/Spells/spell_mage.cpp
@@ -28,42 +28,43 @@
enum MageSpells
{
+ SPELL_MAGE_BURNOUT = 29077,
+ SPELL_MAGE_COLD_SNAP = 11958,
+ SPELL_MAGE_FOCUS_MAGIC_PROC = 54648,
+ SPELL_MAGE_FROST_WARDING_R1 = 11189,
+ SPELL_MAGE_FROST_WARDING_TRIGGERED = 57776,
+ SPELL_MAGE_INCANTERS_ABSORBTION_R1 = 44394,
+ SPELL_MAGE_INCANTERS_ABSORBTION_TRIGGERED = 44413,
+ SPELL_MAGE_IGNITE = 12654,
+ SPELL_MAGE_MASTER_OF_ELEMENTS_ENERGIZE = 29077,
+ SPELL_MAGE_SQUIRREL_FORM = 32813,
+ SPELL_MAGE_GIRAFFE_FORM = 32816,
+ SPELL_MAGE_SERPENT_FORM = 32817,
+ SPELL_MAGE_DRAGONHAWK_FORM = 32818,
+ SPELL_MAGE_WORGEN_FORM = 32819,
+ SPELL_MAGE_SHEEP_FORM = 32820,
+ SPELL_MAGE_GLYPH_OF_ETERNAL_WATER = 70937,
+ SPELL_MAGE_SUMMON_WATER_ELEMENTAL_PERMANENT = 70908,
+ SPELL_MAGE_SUMMON_WATER_ELEMENTAL_TEMPORARY = 70907,
+ SPELL_MAGE_GLYPH_OF_BLAST_WAVE = 62126,
+
SPELL_MAGE_FLAMESTRIKE = 2120,
SPELL_MAGE_CHILLED_R1 = 12484,
SPELL_MAGE_CHILLED_R2 = 12485,
- SPELL_MAGE_COLD_SNAP = 11958,
-
SPELL_MAGE_CONE_OF_COLD_AURA_R1 = 11190,
SPELL_MAGE_CONE_OF_COLD_AURA_R2 = 12489,
SPELL_MAGE_CONE_OF_COLD_TRIGGER_R1 = 83301,
SPELL_MAGE_CONE_OF_COLD_TRIGGER_R2 = 83302,
- SPELL_MAGE_FROST_WARDING_R1 = 28332,
- SPELL_MAGE_FROST_WARDING_TRIGGERED = 57776,
-
SPELL_MAGE_SHATTERED_BARRIER_R1 = 44745,
SPELL_MAGE_SHATTERED_BARRIER_R2 = 54787,
SPELL_MAGE_SHATTERED_BARRIER_FREEZE_R1 = 55080,
SPELL_MAGE_SHATTERED_BARRIER_FREEZE_R2 = 83073,
- SPELL_MAGE_INCANTER_S_ABSORPTION_TRIGGERED = 44413,
- SPELL_MAGE_INCANTER_S_ABSORPTION_KNOCKBACK = 86261,
-
- SPELL_MAGE_SQUIRREL_FORM = 32813,
- SPELL_MAGE_GIRAFFE_FORM = 32816,
- SPELL_MAGE_SERPENT_FORM = 32817,
- SPELL_MAGE_DRAGONHAWK_FORM = 32818,
- SPELL_MAGE_WORGEN_FORM = 32819,
- SPELL_MAGE_SHEEP_FORM = 32820,
-
SPELL_MAGE_IMPROVED_MANA_GEM_TRIGGERED = 83098,
- SPELL_MAGE_GLYPH_OF_ETERNAL_WATER = 70937,
- SPELL_MAGE_SUMMON_WATER_ELEMENTAL_PERMANENT = 70908,
- SPELL_MAGE_SUMMON_WATER_ELEMENTAL_TEMPORARY = 70907,
-
SPELL_MAGE_FINGERS_OF_FROST = 44544
};
@@ -76,6 +77,31 @@ enum MageIcons
ICON_MAGE_IMPROVED_MANA_GEM = 1036
};
+// Incanter's Absorbtion
+class spell_mage_incanters_absorbtion_base_AuraScript : public AuraScript
+{
+ public:
+ bool Validate(SpellInfo const* /*spellInfo*/)
+ {
+ if (!sSpellMgr->GetSpellInfo(SPELL_MAGE_INCANTERS_ABSORBTION_TRIGGERED))
+ return false;
+ if (!sSpellMgr->GetSpellInfo(SPELL_MAGE_INCANTERS_ABSORBTION_R1))
+ return false;
+ return true;
+ }
+
+ void Trigger(AuraEffect* aurEff, DamageInfo& /*dmgInfo*/, uint32& absorbAmount)
+ {
+ Unit* target = GetTarget();
+
+ if (AuraEffect* talentAurEff = target->GetAuraEffectOfRankedSpell(SPELL_MAGE_INCANTERS_ABSORBTION_R1, EFFECT_0))
+ {
+ int32 bp = CalculatePct(absorbAmount, talentAurEff->GetAmount());
+ target->CastCustomSpell(target, SPELL_MAGE_INCANTERS_ABSORBTION_TRIGGERED, &bp, NULL, NULL, true, NULL, aurEff);
+ }
+ }
+};
+
// 11113 - Blast Wave
class spell_mage_blast_wave : public SpellScriptLoader
{
@@ -130,6 +156,51 @@ class spell_mage_blast_wave : public SpellScriptLoader
}
};
+// -44449 - Burnout
+class spell_mage_burnout : public SpellScriptLoader
+{
+ public:
+ spell_mage_burnout() : SpellScriptLoader("spell_mage_burnout") { }
+
+ class spell_mage_burnout_AuraScript : public AuraScript
+ {
+ PrepareAuraScript(spell_mage_burnout_AuraScript);
+
+ bool Validate(SpellInfo const* /*spellInfo*/)
+ {
+ if (!sSpellMgr->GetSpellInfo(SPELL_MAGE_BURNOUT))
+ return false;
+ return true;
+ }
+
+ bool CheckProc(ProcEventInfo& eventInfo)
+ {
+ return eventInfo.GetDamageInfo()->GetSpellInfo(); // eventInfo.GetSpellInfo()
+ }
+
+ void HandleProc(AuraEffect const* aurEff, ProcEventInfo& eventInfo)
+ {
+ PreventDefaultAction();
+
+ int32 mana = int32(eventInfo.GetDamageInfo()->GetSpellInfo()->CalcPowerCost(GetTarget(), eventInfo.GetDamageInfo()->GetSchoolMask()));
+ mana = CalculatePct(mana, aurEff->GetAmount());
+
+ GetTarget()->CastCustomSpell(SPELL_MAGE_BURNOUT, SPELLVALUE_BASE_POINT0, mana, GetTarget(), true, NULL, aurEff);
+ }
+
+ void Register()
+ {
+ DoCheckProc += AuraCheckProcFn(spell_mage_burnout_AuraScript::CheckProc);
+ OnEffectProc += AuraEffectProcFn(spell_mage_burnout_AuraScript::HandleProc, EFFECT_1, SPELL_AURA_DUMMY);
+ }
+ };
+
+ AuraScript* GetAuraScript() const
+ {
+ return new spell_mage_burnout_AuraScript();
+ }
+};
+
// 42208 - Blizzard
/// Updated 4.3.4
class spell_mage_blizzard : public SpellScriptLoader
@@ -327,29 +398,47 @@ class spell_mage_conjure_refreshment : public SpellScriptLoader
}
};
-// -6143, -543 - Frost Warding
-class spell_mage_frost_warding_trigger : public SpellScriptLoader
+// -543 - Fire Ward
+// -6143 - Frost Ward
+class spell_mage_fire_frost_ward : public SpellScriptLoader
{
public:
- spell_mage_frost_warding_trigger() : SpellScriptLoader("spell_mage_frost_warding_trigger") { }
+ spell_mage_fire_frost_ward() : SpellScriptLoader("spell_mage_fire_frost_ward") { }
- class spell_mage_frost_warding_trigger_AuraScript : public AuraScript
+ class spell_mage_fire_frost_ward_AuraScript : public spell_mage_incanters_absorbtion_base_AuraScript
{
- PrepareAuraScript(spell_mage_frost_warding_trigger_AuraScript);
+ PrepareAuraScript(spell_mage_fire_frost_ward_AuraScript);
bool Validate(SpellInfo const* /*spellInfo*/)
{
- if (!sSpellMgr->GetSpellInfo(SPELL_MAGE_FROST_WARDING_TRIGGERED) || !sSpellMgr->GetSpellInfo(SPELL_MAGE_FROST_WARDING_R1))
+ if (!sSpellMgr->GetSpellInfo(SPELL_MAGE_FROST_WARDING_TRIGGERED))
+ return false;
+ if (!sSpellMgr->GetSpellInfo(SPELL_MAGE_FROST_WARDING_R1))
return false;
return true;
}
- void Absorb(AuraEffect* aurEff, DamageInfo & dmgInfo, uint32 & absorbAmount)
+ void CalculateAmount(AuraEffect const* /*aurEff*/, int32& amount, bool& canBeRecalculated)
+ {
+ canBeRecalculated = false;
+ if (Unit* caster = GetCaster())
+ {
+ // +80.68% from sp bonus
+ float bonus = 0.8068f;
+
+ bonus *= caster->SpellBaseHealingBonusDone(GetSpellInfo()->GetSchoolMask());
+ bonus *= caster->CalculateLevelPenalty(GetSpellInfo());
+
+ amount += int32(bonus);
+ }
+ }
+
+ void Absorb(AuraEffect* aurEff, DamageInfo& dmgInfo, uint32& absorbAmount)
{
Unit* target = GetTarget();
if (AuraEffect* talentAurEff = target->GetAuraEffectOfRankedSpell(SPELL_MAGE_FROST_WARDING_R1, EFFECT_0))
{
- int32 chance = talentAurEff->GetSpellInfo()->Effects[EFFECT_1].CalcValue();
+ int32 chance = talentAurEff->GetSpellInfo()->Effects[EFFECT_1].CalcValue(); // SPELL_EFFECT_DUMMY with NO_TARGET
if (roll_chance_i(chance))
{
@@ -364,13 +453,66 @@ class spell_mage_frost_warding_trigger : public SpellScriptLoader
void Register()
{
- OnEffectAbsorb += AuraEffectAbsorbFn(spell_mage_frost_warding_trigger_AuraScript::Absorb, EFFECT_0);
+ DoEffectCalcAmount += AuraEffectCalcAmountFn(spell_mage_fire_frost_ward_AuraScript::CalculateAmount, EFFECT_0, SPELL_AURA_SCHOOL_ABSORB);
+ OnEffectAbsorb += AuraEffectAbsorbFn(spell_mage_fire_frost_ward_AuraScript::Absorb, EFFECT_0);
+ AfterEffectAbsorb += AuraEffectAbsorbFn(spell_mage_fire_frost_ward_AuraScript::Trigger, EFFECT_0);
+ }
+ };
+
+ AuraScript* GetAuraScript() const
+ {
+ return new spell_mage_fire_frost_ward_AuraScript();
+ }
+};
+
+// 54646 - Focus Magic
+class spell_mage_focus_magic : public SpellScriptLoader
+{
+ public:
+ spell_mage_focus_magic() : SpellScriptLoader("spell_mage_focus_magic") { }
+
+ class spell_mage_focus_magic_AuraScript : public AuraScript
+ {
+ PrepareAuraScript(spell_mage_focus_magic_AuraScript);
+
+ bool Validate(SpellInfo const* /*spellInfo*/)
+ {
+ if (!sSpellMgr->GetSpellInfo(SPELL_MAGE_FOCUS_MAGIC_PROC))
+ return false;
+ return true;
+ }
+
+ bool Load()
+ {
+ _procTarget = NULL;
+ return true;
+ }
+
+ bool CheckProc(ProcEventInfo& /*eventInfo*/)
+ {
+ _procTarget = GetCaster();
+ return _procTarget && _procTarget->isAlive();
+ }
+
+ void HandleProc(AuraEffect const* aurEff, ProcEventInfo& /*eventInfo*/)
+ {
+ PreventDefaultAction();
+ GetTarget()->CastSpell(_procTarget, SPELL_MAGE_FOCUS_MAGIC_PROC, true, NULL, aurEff);
+ }
+
+ void Register()
+ {
+ DoCheckProc += AuraCheckProcFn(spell_mage_focus_magic_AuraScript::CheckProc);
+ OnEffectProc += AuraEffectProcFn(spell_mage_focus_magic_AuraScript::HandleProc, EFFECT_0, SPELL_AURA_MOD_SPELL_CRIT_CHANCE);
}
+
+ private:
+ Unit* _procTarget;
};
AuraScript* GetAuraScript() const
{
- return new spell_mage_frost_warding_trigger_AuraScript();
+ return new spell_mage_focus_magic_AuraScript();
}
};
@@ -483,16 +625,63 @@ class spell_mage_ice_barrier : public SpellScriptLoader
}
};
-// 1463 - Mana Shield
-/// Updated 4.3.4
-class spell_mage_mana_shield : public SpellScriptLoader
+// -11119 - Ignite
+class spell_mage_ignite : public SpellScriptLoader
{
public:
- spell_mage_mana_shield() : SpellScriptLoader("spell_mage_mana_shield") { }
+ spell_mage_ignite() : SpellScriptLoader("spell_mage_ignite") { }
- class spell_mage_mana_shield_AuraScript : public AuraScript
+ class spell_mage_ignite_AuraScript : public AuraScript
+ {
+ PrepareAuraScript(spell_mage_ignite_AuraScript);
+
+ bool Validate(SpellInfo const* /*spellInfo*/)
+ {
+ if (!sSpellMgr->GetSpellInfo(SPELL_MAGE_IGNITE))
+ return false;
+ return true;
+ }
+
+ bool CheckProc(ProcEventInfo& eventInfo)
+ {
+ return eventInfo.GetProcTarget();
+ }
+
+ void HandleProc(AuraEffect const* aurEff, ProcEventInfo& eventInfo)
+ {
+ PreventDefaultAction();
+
+ SpellInfo const* igniteDot = sSpellMgr->GetSpellInfo(SPELL_MAGE_IGNITE);
+ int32 pct = 8 * GetSpellInfo()->GetRank();
+
+ int32 amount = int32(CalculatePct(eventInfo.GetDamageInfo()->GetDamage(), pct) / igniteDot->GetMaxTicks());
+ amount += eventInfo.GetProcTarget()->GetRemainingPeriodicAmount(eventInfo.GetActor()->GetGUID(), SPELL_MAGE_IGNITE, SPELL_AURA_PERIODIC_DAMAGE);
+ GetTarget()->CastCustomSpell(SPELL_MAGE_IGNITE, SPELLVALUE_BASE_POINT0, amount, eventInfo.GetProcTarget(), true, NULL, aurEff);
+ }
+
+ void Register()
+ {
+ DoCheckProc += AuraCheckProcFn(spell_mage_ignite_AuraScript::CheckProc);
+ OnEffectProc += AuraEffectProcFn(spell_mage_ignite_AuraScript::HandleProc, EFFECT_0, SPELL_AURA_DUMMY);
+ }
+ };
+
+ AuraScript* GetAuraScript() const
+ {
+ return new spell_mage_ignite_AuraScript();
+ }
+};
+
+// 543 - Mage Ward
+/// Updated 4.3.4
+class spell_mage_mage_ward : public SpellScriptLoader
+{
+ public:
+ spell_mage_mage_ward() : SpellScriptLoader("spell_mage_mage_ward") { }
+
+ class spell_mage_mage_ward_AuraScript : public AuraScript
{
- PrepareAuraScript(spell_mage_mana_shield_AuraScript);
+ PrepareAuraScript(spell_mage_mage_ward_AuraScript);
void HandleAbsorb(AuraEffect* /*aurEff*/, DamageInfo & /*dmgInfo*/, uint32 & absorbAmount)
{
@@ -503,35 +692,28 @@ class spell_mage_mana_shield : public SpellScriptLoader
}
}
- void AfterRemove(AuraEffect const* /*aurEff*/, AuraEffectHandleModes /*mode*/)
- {
- if (GetTargetApplication()->GetRemoveMode() == AURA_REMOVE_BY_ENEMY_SPELL)
- GetTarget()->CastSpell(GetTarget(), SPELL_MAGE_INCANTER_S_ABSORPTION_KNOCKBACK, true);
- }
-
void Register()
{
- AfterEffectManaShield += AuraEffectManaShieldFn(spell_mage_mana_shield_AuraScript::HandleAbsorb, EFFECT_0);
- AfterEffectRemove += AuraEffectRemoveFn(spell_mage_mana_shield_AuraScript::AfterRemove, EFFECT_0, SPELL_AURA_MANA_SHIELD, AURA_EFFECT_HANDLE_REAL);
+ AfterEffectAbsorb += AuraEffectAbsorbFn(spell_mage_mage_ward_AuraScript::HandleAbsorb, EFFECT_0);
}
};
AuraScript* GetAuraScript() const
{
- return new spell_mage_mana_shield_AuraScript();
+ return new spell_mage_mage_ward_AuraScript();
}
};
-// 543 - Mage Ward
+// 1463 - Mana Shield
/// Updated 4.3.4
-class spell_mage_mage_ward : public SpellScriptLoader
+class spell_mage_mana_shield : public SpellScriptLoader
{
- public:
- spell_mage_mage_ward() : SpellScriptLoader("spell_mage_mage_ward") { }
+ public:
+ spell_mage_mana_shield() : SpellScriptLoader("spell_mage_mana_shield") { }
- class spell_mage_mage_ward_AuraScript : public AuraScript
+ class spell_mage_mana_shield_AuraScript : public AuraScript
{
- PrepareAuraScript(spell_mage_mage_ward_AuraScript);
+ PrepareAuraScript(spell_mage_mana_shield_AuraScript);
void HandleAbsorb(AuraEffect* /*aurEff*/, DamageInfo & /*dmgInfo*/, uint32 & absorbAmount)
{
@@ -542,18 +724,71 @@ class spell_mage_mage_ward : public SpellScriptLoader
}
}
+ void AfterRemove(AuraEffect const* /*aurEff*/, AuraEffectHandleModes /*mode*/)
+ {
+ if (GetTargetApplication()->GetRemoveMode() == AURA_REMOVE_BY_ENEMY_SPELL)
+ GetTarget()->CastSpell(GetTarget(), SPELL_MAGE_INCANTER_S_ABSORPTION_KNOCKBACK, true);
+ }
+
void Register()
{
- AfterEffectAbsorb += AuraEffectAbsorbFn(spell_mage_mage_ward_AuraScript::HandleAbsorb, EFFECT_0);
+ AfterEffectManaShield += AuraEffectManaShieldFn(spell_mage_mana_shield_AuraScript::HandleAbsorb, EFFECT_0);
+ AfterEffectRemove += AuraEffectRemoveFn(spell_mage_mana_shield_AuraScript::AfterRemove, EFFECT_0, SPELL_AURA_MANA_SHIELD, AURA_EFFECT_HANDLE_REAL);
}
};
AuraScript* GetAuraScript() const
{
- return new spell_mage_mage_ward_AuraScript();
+ return new spell_mage_mana_shield_AuraScript();
}
};
+// -29074 - Master of Elements
+class spell_mage_master_of_elements : public SpellScriptLoader
+{
+ public:
+ spell_mage_master_of_elements() : SpellScriptLoader("spell_mage_master_of_elements") { }
+
+ class spell_mage_master_of_elements_AuraScript : public AuraScript
+ {
+ PrepareAuraScript(spell_mage_master_of_elements_AuraScript);
+
+ bool Validate(SpellInfo const* /*spellInfo*/)
+ {
+ if (!sSpellMgr->GetSpellInfo(SPELL_MAGE_MASTER_OF_ELEMENTS_ENERGIZE))
+ return false;
+ return true;
+ }
+
+ bool CheckProc(ProcEventInfo& eventInfo)
+ {
+ return eventInfo.GetDamageInfo()->GetSpellInfo(); // eventInfo.GetSpellInfo()
+ }
+
+ void HandleProc(AuraEffect const* aurEff, ProcEventInfo& eventInfo)
+ {
+ PreventDefaultAction();
+
+ int32 mana = int32(eventInfo.GetDamageInfo()->GetSpellInfo()->CalcPowerCost(GetTarget(), eventInfo.GetDamageInfo()->GetSchoolMask()));
+ mana = CalculatePct(mana, aurEff->GetAmount());
+
+ if (mana > 0)
+ GetTarget()->CastCustomSpell(SPELL_MAGE_MASTER_OF_ELEMENTS_ENERGIZE, SPELLVALUE_BASE_POINT0, mana, GetTarget(), true, NULL, aurEff);
+ }
+
+ void Register()
+ {
+ DoCheckProc += AuraCheckProcFn(spell_mage_master_of_elements_AuraScript::CheckProc);
+ OnEffectProc += AuraEffectProcFn(spell_mage_master_of_elements_AuraScript::HandleProc, EFFECT_0, SPELL_AURA_DUMMY);
+ }
+ };
+
+ AuraScript* GetAuraScript() const
+ {
+ return new spell_mage_master_of_elements_AuraScript();
+ }
+};
+
enum SilvermoonPolymorph
{
NPC_AUROSALIA = 18744
@@ -748,15 +983,19 @@ void AddSC_mage_spell_scripts()
{
new spell_mage_blast_wave();
new spell_mage_blizzard();
+ new spell_mage_burnout();
new spell_mage_cold_snap();
new spell_mage_cone_of_cold();
new spell_mage_conjure_refreshment();
- new spell_mage_frost_warding_trigger();
+ new spell_mage_fire_frost_ward();
+ new spell_mage_focus_magic();
new spell_mage_frostbolt();
- new spell_mage_living_bomb();
new spell_mage_ice_barrier();
- new spell_mage_mana_shield();
+ new spell_mage_ignite();
+ new spell_mage_living_bomb();
new spell_mage_mage_ward();
+ new spell_mage_mana_shield();
+ new spell_mage_master_of_elements();
new spell_mage_polymorph_cast_visual();
new spell_mage_replenish_mana();
new spell_mage_summon_water_elemental();
diff --git a/src/server/scripts/Spells/spell_paladin.cpp b/src/server/scripts/Spells/spell_paladin.cpp
index 7625ed548ac..a581a6ee351 100644
--- a/src/server/scripts/Spells/spell_paladin.cpp
+++ b/src/server/scripts/Spells/spell_paladin.cpp
@@ -31,6 +31,7 @@ enum PaladinSpells
{
SPELL_PALADIN_DIVINE_PLEA = 54428,
SPELL_PALADIN_BLESSING_OF_SANCTUARY_BUFF = 67480,
+ SPELL_PALADIN_BLESSING_OF_SANCTUARY_ENERGIZE = 57319,
SPELL_PALADIN_HOLY_SHOCK_R1 = 20473,
SPELL_PALADIN_HOLY_SHOCK_R1_DAMAGE = 25912,
@@ -45,6 +46,8 @@ enum PaladinSpells
SPELL_PALADIN_DIVINE_STORM_DUMMY = 54171,
SPELL_PALADIN_DIVINE_STORM_HEAL = 54172,
+ SPELL_PALADIN_EYE_FOR_AN_EYE_DAMAGE = 25997,
+
SPELL_PALADIN_FORBEARANCE = 25771,
SPELL_PALADIN_AVENGING_WRATH_MARKER = 61987,
SPELL_PALADIN_IMMUNE_SHIELD_MARKER = 61988,
@@ -52,7 +55,16 @@ enum PaladinSpells
SPELL_PALADIN_HAND_OF_SACRIFICE = 6940,
SPELL_PALADIN_DIVINE_SACRIFICE = 64205,
- SPELL_PALADIN_DIVINE_PURPOSE_PROC = 90174
+ SPELL_PALADIN_DIVINE_PURPOSE_PROC = 90174,
+
+ SPELL_PALADIN_GLYPH_OF_SALVATION = 63225,
+
+ SPELL_PALADIN_RIGHTEOUS_DEFENSE_TAUNT = 31790,
+
+ SPELL_PALADIN_SEAL_OF_RIGHTEOUSNESS = 25742,
+
+ SPELL_GENERIC_ARENA_DAMPENING = 74410,
+ SPELL_GENERIC_BATTLEGROUND_DAMPENING = 74411
};
// 31850 - Ardent Defender
@@ -187,8 +199,8 @@ class spell_pal_blessing_of_faith : public SpellScriptLoader
}
};
-// 20911 Blessing of Sanctuary
-// 25899 Greater Blessing of Sanctuary
+// 20911 - Blessing of Sanctuary
+// 25899 - Greater Blessing of Sanctuary
class spell_pal_blessing_of_sanctuary : public SpellScriptLoader
{
public:
@@ -202,6 +214,8 @@ class spell_pal_blessing_of_sanctuary : public SpellScriptLoader
{
if (!sSpellMgr->GetSpellInfo(SPELL_PALADIN_BLESSING_OF_SANCTUARY_BUFF))
return false;
+ if (!sSpellMgr->GetSpellInfo(SPELL_PALADIN_BLESSING_OF_SANCTUARY_ENERGIZE))
+ return false;
return true;
}
@@ -218,10 +232,23 @@ class spell_pal_blessing_of_sanctuary : public SpellScriptLoader
target->RemoveAura(SPELL_PALADIN_BLESSING_OF_SANCTUARY_BUFF, GetCasterGUID());
}
+ bool CheckProc(ProcEventInfo& /*eventInfo*/)
+ {
+ return GetTarget()->getPowerType() == POWER_MANA;
+ }
+
+ void HandleProc(AuraEffect const* aurEff, ProcEventInfo& /*eventInfo*/)
+ {
+ PreventDefaultAction();
+ GetTarget()->CastSpell(GetTarget(), SPELL_PALADIN_BLESSING_OF_SANCTUARY_ENERGIZE, true, NULL, aurEff);
+ }
+
void Register()
{
AfterEffectApply += AuraEffectApplyFn(spell_pal_blessing_of_sanctuary_AuraScript::HandleEffectApply, EFFECT_0, SPELL_AURA_DUMMY, AURA_EFFECT_HANDLE_REAL_OR_REAPPLY_MASK);
AfterEffectRemove += AuraEffectRemoveFn(spell_pal_blessing_of_sanctuary_AuraScript::HandleEffectRemove, EFFECT_0, SPELL_AURA_DUMMY, AURA_EFFECT_HANDLE_REAL_OR_REAPPLY_MASK);
+ DoCheckProc += AuraCheckProcFn(spell_pal_blessing_of_sanctuary_AuraScript::CheckProc);
+ OnEffectProc += AuraEffectProcFn(spell_pal_blessing_of_sanctuary_AuraScript::HandleProc, EFFECT_0, SPELL_AURA_DUMMY);
}
};
@@ -412,6 +439,43 @@ class spell_pal_exorcism_and_holy_wrath_damage : public SpellScriptLoader
}
};
+// -9799 - Eye for an Eye
+class spell_pal_eye_for_an_eye : public SpellScriptLoader
+{
+ public:
+ spell_pal_eye_for_an_eye() : SpellScriptLoader("spell_pal_eye_for_an_eye") { }
+
+ class spell_pal_eye_for_an_eye_AuraScript : public AuraScript
+ {
+ PrepareAuraScript(spell_pal_eye_for_an_eye_AuraScript);
+
+ bool Validate(SpellInfo const* /*spellInfo*/)
+ {
+ if (!sSpellMgr->GetSpellInfo(SPELL_PALADIN_EYE_FOR_AN_EYE_DAMAGE))
+ return false;
+ return true;
+ }
+
+ void OnProc(AuraEffect const* aurEff, ProcEventInfo& eventInfo)
+ {
+ PreventDefaultAction();
+ // return damage % to attacker but < 50% own total health
+ int32 damage = int32(std::min(CalculatePct(eventInfo.GetDamageInfo()->GetDamage(), aurEff->GetAmount()), GetTarget()->GetMaxHealth() / 2));
+ GetTarget()->CastCustomSpell(SPELL_PALADIN_EYE_FOR_AN_EYE_DAMAGE, SPELLVALUE_BASE_POINT0, damage, eventInfo.GetProcTarget(), true, NULL, aurEff);
+ }
+
+ void Register()
+ {
+ OnEffectProc += AuraEffectProcFn(spell_pal_eye_for_an_eye_AuraScript::OnProc, EFFECT_0, SPELL_AURA_DUMMY);
+ }
+ };
+
+ AuraScript* GetAuraScript() const
+ {
+ return new spell_pal_eye_for_an_eye_AuraScript();
+ }
+};
+
// 63521 - Guarded by The Light
class spell_pal_guarded_by_the_light : public SpellScriptLoader
{
@@ -492,6 +556,39 @@ class spell_pal_hand_of_sacrifice : public SpellScriptLoader
}
};
+// 1038 - Hand of Salvation
+class spell_pal_hand_of_salvation : public SpellScriptLoader
+{
+ public:
+ spell_pal_hand_of_salvation() : SpellScriptLoader("spell_pal_hand_of_salvation") { }
+
+ class spell_pal_hand_of_salvation_AuraScript : public AuraScript
+ {
+ PrepareAuraScript(spell_pal_hand_of_salvation_AuraScript);
+
+ void CalculateAmount(AuraEffect const* /*aurEff*/, int32& amount, bool& /*canBeRecalculated*/)
+ {
+ if (Unit* caster = GetCaster())
+ {
+ // Glyph of Salvation
+ if (caster->GetGUID() == GetUnitOwner()->GetGUID())
+ if (AuraEffect const* aurEff = caster->GetAuraEffect(SPELL_PALADIN_GLYPH_OF_SALVATION, EFFECT_0))
+ amount -= aurEff->GetAmount();
+ }
+ }
+
+ void Register()
+ {
+ DoEffectCalcAmount += AuraEffectCalcAmountFn(spell_pal_hand_of_salvation_AuraScript::CalculateAmount, EFFECT_1, SPELL_AURA_MOD_DAMAGE_PERCENT_TAKEN);
+ }
+ };
+
+ AuraScript* GetAuraScript() const
+ {
+ return new spell_pal_hand_of_salvation_AuraScript();
+ }
+};
+
// -20473 - Holy Shock
class spell_pal_holy_shock : public SpellScriptLoader
{
@@ -658,6 +755,13 @@ class spell_pal_righteous_defense : public SpellScriptLoader
{
PrepareSpellScript(spell_pal_righteous_defense_SpellScript);
+ bool Validate(SpellInfo const* /*spellInfo*/)
+ {
+ if (!sSpellMgr->GetSpellInfo(SPELL_PALADIN_RIGHTEOUS_DEFENSE_TAUNT))
+ return false;
+ return true;
+ }
+
SpellCastResult CheckCast()
{
Unit* caster = GetCaster();
@@ -675,9 +779,27 @@ class spell_pal_righteous_defense : public SpellScriptLoader
return SPELL_CAST_OK;
}
+ void HandleTriggerSpellLaunch(SpellEffIndex effIndex)
+ {
+ PreventHitDefaultEffect(effIndex);
+ }
+
+ void HandleTriggerSpellHit(SpellEffIndex effIndex)
+ {
+ PreventHitDefaultEffect(effIndex);
+ if (Unit* target = GetHitUnit())
+ GetCaster()->CastSpell(target, SPELL_PALADIN_RIGHTEOUS_DEFENSE_TAUNT, true);
+ }
+
void Register()
{
OnCheckCast += SpellCheckCastFn(spell_pal_righteous_defense_SpellScript::CheckCast);
+ //! WORKAROUND
+ //! target select will be executed in hitphase of effect 0
+ //! so we must handle trigger spell also in hit phase (default execution in launch phase)
+ //! see issue #3718
+ OnEffectLaunchTarget += SpellEffectFn(spell_pal_righteous_defense_SpellScript::HandleTriggerSpellLaunch, EFFECT_1, SPELL_EFFECT_TRIGGER_SPELL);
+ OnEffectHitTarget += SpellEffectFn(spell_pal_righteous_defense_SpellScript::HandleTriggerSpellHit, EFFECT_1, SPELL_EFFECT_TRIGGER_SPELL);
}
};
@@ -789,19 +911,71 @@ class spell_pal_templar_s_verdict : public SpellScriptLoader
}
};
+// 20154, 21084 - Seal of Righteousness - melee proc dummy (addition ${$MWS*(0.022*$AP+0.044*$SPH)} damage)
+class spell_pal_seal_of_righteousness : public SpellScriptLoader
+{
+ public:
+ spell_pal_seal_of_righteousness() : SpellScriptLoader("spell_pal_seal_of_righteousness") { }
+
+ class spell_pal_seal_of_righteousness_AuraScript : public AuraScript
+ {
+ PrepareAuraScript(spell_pal_seal_of_righteousness_AuraScript);
+
+ bool Validate(SpellInfo const* /*spellInfo*/)
+ {
+ if (!sSpellMgr->GetSpellInfo(SPELL_PALADIN_SEAL_OF_RIGHTEOUSNESS))
+ return false;
+ return true;
+ }
+
+ bool CheckProc(ProcEventInfo& eventInfo)
+ {
+ return eventInfo.GetProcTarget();
+ }
+
+ void HandleProc(AuraEffect const* aurEff, ProcEventInfo& eventInfo)
+ {
+ PreventDefaultAction();
+
+ float ap = GetTarget()->GetTotalAttackPowerValue(BASE_ATTACK);
+ int32 holy = GetTarget()->SpellBaseDamageBonusDone(SPELL_SCHOOL_MASK_HOLY);
+ holy += eventInfo.GetProcTarget()->SpellBaseDamageBonusTaken(SPELL_SCHOOL_MASK_HOLY);
+ int32 bp = int32((ap * 0.022f + 0.044f * holy) * GetTarget()->GetAttackTime(BASE_ATTACK) / 1000);
+ GetTarget()->CastCustomSpell(SPELL_PALADIN_SEAL_OF_RIGHTEOUSNESS, SPELLVALUE_BASE_POINT0, bp, eventInfo.GetProcTarget(), true, NULL, aurEff);
+ }
+
+ void Register()
+ {
+ DoCheckProc += AuraCheckProcFn(spell_pal_seal_of_righteousness_AuraScript::CheckProc);
+ OnEffectProc += AuraEffectProcFn(spell_pal_seal_of_righteousness_AuraScript::HandleProc, EFFECT_0, SPELL_AURA_DUMMY);
+ }
+ };
+
+ AuraScript* GetAuraScript() const
+ {
+ return new spell_pal_seal_of_righteousness_AuraScript();
+ }
+};
+
+
void AddSC_paladin_spell_scripts()
{
//new spell_pal_ardent_defender();
new spell_pal_blessing_of_faith();
new spell_pal_blessing_of_sanctuary();
new spell_pal_divine_sacrifice();
+ new spell_pal_divine_storm();
+ new spell_pal_divine_storm_dummy();
new spell_pal_exorcism_and_holy_wrath_damage();
+ new spell_pal_eye_for_an_eye();
new spell_pal_guarded_by_the_light();
new spell_pal_hand_of_sacrifice();
+ new spell_pal_hand_of_salvation();
new spell_pal_holy_shock();
new spell_pal_judgement_of_command();
new spell_pal_lay_on_hands();
new spell_pal_righteous_defense();
new spell_pal_sacred_shield();
new spell_pal_templar_s_verdict();
+ new spell_pal_seal_of_righteousness();
}
diff --git a/src/server/scripts/Spells/spell_priest.cpp b/src/server/scripts/Spells/spell_priest.cpp
index b47eff816a3..94b12818626 100644
--- a/src/server/scripts/Spells/spell_priest.cpp
+++ b/src/server/scripts/Spells/spell_priest.cpp
@@ -29,23 +29,27 @@
enum PriestSpells
{
+ SPELL_PRIEST_DIVINE_AEGIS = 47753,
SPELL_PRIEST_EMPOWERED_RENEW = 63544,
+ SPELL_PRIEST_GLYPH_OF_LIGHTWELL = 55673,
+ SPELL_PRIEST_GLYPH_OF_PRAYER_OF_HEALING_HEAL = 56161,
SPELL_PRIEST_GLYPH_OF_SHADOW = 107906,
SPELL_PRIEST_GUARDIAN_SPIRIT_HEAL = 48153,
SPELL_PRIEST_LEAP_OF_FAITH = 73325,
- SPELL_PRIEST_LEAP_OF_FAITH_TRIGGERED = 92572,
- SPELL_PRIEST_LEAP_OF_FAITH_EFFECT_TRIGGER = 92833,
SPELL_PRIEST_LEAP_OF_FAITH_EFFECT = 92832,
+ SPELL_PRIEST_LEAP_OF_FAITH_EFFECT_TRIGGER = 92833,
+ SPELL_PRIEST_LEAP_OF_FAITH_TRIGGERED = 92572,
+ SPELL_PRIEST_MANA_LEECH_PROC = 34650,
SPELL_PRIEST_PENANCE_R1 = 47540,
SPELL_PRIEST_PENANCE_R1_DAMAGE = 47758,
SPELL_PRIEST_PENANCE_R1_HEAL = 47757,
- SPELL_PRIEST_REFLECTIVE_SHIELD_TRIGGERED = 33619,
SPELL_PRIEST_REFLECTIVE_SHIELD_R1 = 33201,
- SPELL_PRIEST_SHADOW_WORD_DEATH = 32409,
+ SPELL_PRIEST_REFLECTIVE_SHIELD_TRIGGERED = 33619,
SPELL_PRIEST_SHADOWFORM_VISUAL_WITHOUT_GLYPH = 107903,
SPELL_PRIEST_SHADOWFORM_VISUAL_WITH_GLYPH = 107904,
+ SPELL_PRIEST_SHADOW_WORD_DEATH = 32409,
SPELL_PRIEST_T9_HEALING_2P = 67201,
- SPELL_PRIEST_VAMPIRIC_TOUCH_DISPEL = 64085
+ SPELL_PRIEST_VAMPIRIC_TOUCH_DISPEL = 64085,
};
enum PriestSpellIcons
@@ -54,6 +58,94 @@ enum PriestSpellIcons
PRIEST_ICON_ID_PAIN_AND_SUFFERING = 2874
};
+// -47509 - Divine Aegis
+class spell_pri_divine_aegis : public SpellScriptLoader
+{
+ public:
+ spell_pri_divine_aegis() : SpellScriptLoader("spell_pri_divine_aegis") { }
+
+ class spell_pri_divine_aegis_AuraScript : public AuraScript
+ {
+ PrepareAuraScript(spell_pri_divine_aegis_AuraScript);
+
+ bool Validate(SpellInfo const* /*spellInfo*/)
+ {
+ if (!sSpellMgr->GetSpellInfo(SPELL_PRIEST_DIVINE_AEGIS))
+ return false;
+ return true;
+ }
+
+ bool CheckProc(ProcEventInfo& eventInfo)
+ {
+ return eventInfo.GetProcTarget();
+ }
+
+ void HandleProc(AuraEffect const* aurEff, ProcEventInfo& eventInfo)
+ {
+ PreventDefaultAction();
+
+ int32 absorb = CalculatePct(int32(eventInfo.GetHealInfo()->GetHeal()), aurEff->GetAmount());
+
+ // Multiple effects stack, so let's try to find this aura.
+ if (AuraEffect const* aegis = eventInfo.GetProcTarget()->GetAuraEffect(SPELL_PRIEST_DIVINE_AEGIS, EFFECT_0))
+ absorb += aegis->GetAmount();
+
+ absorb = std::min(absorb, eventInfo.GetProcTarget()->getLevel() * 125);
+
+ GetTarget()->CastCustomSpell(SPELL_PRIEST_DIVINE_AEGIS, SPELLVALUE_BASE_POINT0, absorb, eventInfo.GetProcTarget(), true, NULL, aurEff);
+ }
+
+ void Register()
+ {
+ DoCheckProc += AuraCheckProcFn(spell_pri_divine_aegis_AuraScript::CheckProc);
+ OnEffectProc += AuraEffectProcFn(spell_pri_divine_aegis_AuraScript::HandleProc, EFFECT_0, SPELL_AURA_DUMMY);
+ }
+ };
+
+ AuraScript* GetAuraScript() const
+ {
+ return new spell_pri_divine_aegis_AuraScript();
+ }
+};
+
+// 55680 - Glyph of Prayer of Healing
+class spell_pri_glyph_of_prayer_of_healing : public SpellScriptLoader
+{
+ public:
+ spell_pri_glyph_of_prayer_of_healing() : SpellScriptLoader("spell_pri_glyph_of_prayer_of_healing") { }
+
+ class spell_pri_glyph_of_prayer_of_healing_AuraScript : public AuraScript
+ {
+ PrepareAuraScript(spell_pri_glyph_of_prayer_of_healing_AuraScript);
+
+ bool Validate(SpellInfo const* /*spellInfo*/)
+ {
+ if (!sSpellMgr->GetSpellInfo(SPELL_PRIEST_GLYPH_OF_PRAYER_OF_HEALING_HEAL))
+ return false;
+ return true;
+ }
+
+ void HandleProc(AuraEffect const* aurEff, ProcEventInfo& eventInfo)
+ {
+ PreventDefaultAction();
+
+ SpellInfo const* triggeredSpellInfo = sSpellMgr->GetSpellInfo(SPELL_PRIEST_GLYPH_OF_PRAYER_OF_HEALING_HEAL);
+ int32 heal = int32(CalculatePct(int32(eventInfo.GetHealInfo()->GetHeal()), aurEff->GetAmount()) / triggeredSpellInfo->GetMaxTicks());
+ GetTarget()->CastCustomSpell(SPELL_PRIEST_GLYPH_OF_PRAYER_OF_HEALING_HEAL, SPELLVALUE_BASE_POINT0, heal, eventInfo.GetProcTarget(), true, NULL, aurEff);
+ }
+
+ void Register()
+ {
+ OnEffectProc += AuraEffectProcFn(spell_pri_glyph_of_prayer_of_healing_AuraScript::HandleProc, EFFECT_0, SPELL_AURA_DUMMY);
+ }
+ };
+
+ AuraScript* GetAuraScript() const
+ {
+ return new spell_pri_glyph_of_prayer_of_healing_AuraScript();
+ }
+};
+
// 47788 - Guardian Spirit
class spell_pri_guardian_spirit : public SpellScriptLoader
{
@@ -151,6 +243,38 @@ class spell_pri_leap_of_faith_effect_trigger : public SpellScriptLoader
}
};
+// -7001 - Lightwell Renew
+class spell_pri_lightwell_renew : public SpellScriptLoader
+{
+ public:
+ spell_pri_lightwell_renew() : SpellScriptLoader("spell_pri_lightwell_renew") { }
+
+ class spell_pri_lightwell_renew_AuraScript : public AuraScript
+ {
+ PrepareAuraScript(spell_pri_lightwell_renew_AuraScript);
+
+ void CalculateAmount(AuraEffect const* /*aurEff*/, int32& amount, bool& /*canBeRecalculated*/)
+ {
+ if (Unit* caster = GetCaster())
+ {
+ // Bonus from Glyph of Lightwell
+ if (AuraEffect* modHealing = caster->GetAuraEffect(SPELL_PRIEST_GLYPH_OF_LIGHTWELL, EFFECT_0))
+ AddPct(amount, modHealing->GetAmount());
+ }
+ }
+
+ void Register()
+ {
+ DoEffectCalcAmount += AuraEffectCalcAmountFn(spell_pri_lightwell_renew_AuraScript::CalculateAmount, EFFECT_0, SPELL_AURA_PERIODIC_HEAL);
+ }
+ };
+
+ AuraScript* GetAuraScript() const
+ {
+ return new spell_pri_lightwell_renew_AuraScript();
+ }
+};
+
// 8129 - Mana Burn
class spell_pri_mana_burn : public SpellScriptLoader
{
@@ -179,6 +303,57 @@ class spell_pri_mana_burn : public SpellScriptLoader
}
};
+// 28305 - Mana Leech (Passive) (Priest Pet Aura)
+class spell_pri_mana_leech : public SpellScriptLoader
+{
+ public:
+ spell_pri_mana_leech() : SpellScriptLoader("spell_pri_mana_leech") { }
+
+ class spell_pri_mana_leech_AuraScript : public AuraScript
+ {
+ PrepareAuraScript(spell_pri_mana_leech_AuraScript);
+
+ bool Validate(SpellInfo const* /*spellInfo*/)
+ {
+ if (!sSpellMgr->GetSpellInfo(SPELL_PRIEST_MANA_LEECH_PROC))
+ return false;
+ return true;
+ }
+
+ bool Load()
+ {
+ _procTarget = NULL;
+ return true;
+ }
+
+ bool CheckProc(ProcEventInfo& /*eventInfo*/)
+ {
+ _procTarget = GetTarget()->GetOwner();
+ return _procTarget;
+ }
+
+ void HandleProc(AuraEffect const* aurEff, ProcEventInfo& /*eventInfo*/)
+ {
+ PreventDefaultAction();
+ GetTarget()->CastSpell(_procTarget, SPELL_PRIEST_MANA_LEECH_PROC, true, NULL, aurEff);
+ }
+
+ void Register()
+ {
+ DoCheckProc += AuraCheckProcFn(spell_pri_mana_leech_AuraScript::CheckProc);
+ OnEffectProc += AuraEffectProcFn(spell_pri_mana_leech_AuraScript::HandleProc, EFFECT_0, SPELL_AURA_DUMMY);
+ }
+
+ private:
+ Unit* _procTarget;
+ };
+
+ AuraScript* GetAuraScript() const
+ {
+ return new spell_pri_mana_leech_AuraScript();
+ }
+};
+
// 49821 - Mind Sear
class spell_pri_mind_sear : public SpellScriptLoader
{
@@ -307,6 +482,82 @@ class spell_pri_penance : public SpellScriptLoader
}
};
+// -17 - Power Word: Shield
+class spell_pri_power_word_shield : public SpellScriptLoader
+{
+ public:
+ spell_pri_power_word_shield() : SpellScriptLoader("spell_pri_power_word_shield") { }
+
+ class spell_pri_power_word_shield_AuraScript : public AuraScript
+ {
+ PrepareAuraScript(spell_pri_power_word_shield_AuraScript);
+
+ bool Validate(SpellInfo const* /*spellInfo*/)
+ {
+ if (!sSpellMgr->GetSpellInfo(SPELL_PRIEST_REFLECTIVE_SHIELD_TRIGGERED))
+ return false;
+ if (!sSpellMgr->GetSpellInfo(SPELL_PRIEST_REFLECTIVE_SHIELD_R1))
+ return false;
+ return true;
+ }
+
+ void CalculateAmount(AuraEffect const* aurEff, int32& amount, bool& canBeRecalculated)
+ {
+ canBeRecalculated = false;
+ if (Unit* caster = GetCaster())
+ {
+ // +80.68% from sp bonus
+ float bonus = 0.8068f;
+
+ // Borrowed Time
+ if (AuraEffect const* borrowedTime = caster->GetDummyAuraEffect(SPELLFAMILY_PRIEST, PRIEST_ICON_ID_BORROWED_TIME, EFFECT_1))
+ bonus += CalculatePct(1.0f, borrowedTime->GetAmount());
+
+ bonus *= caster->SpellBaseHealingBonusDone(GetSpellInfo()->GetSchoolMask());
+
+ // Improved PW: Shield: its weird having a SPELLMOD_ALL_EFFECTS here but its blizzards doing :)
+ // Improved PW: Shield is only applied at the spell healing bonus because it was already applied to the base value in CalculateSpellDamage
+ bonus = caster->ApplyEffectModifiers(GetSpellInfo(), aurEff->GetEffIndex(), bonus);
+ bonus *= caster->CalculateLevelPenalty(GetSpellInfo());
+
+ amount += int32(bonus);
+
+ // Twin Disciplines
+ if (AuraEffect const* twinDisciplines = caster->GetAuraEffect(SPELL_AURA_ADD_PCT_MODIFIER, SPELLFAMILY_PRIEST, 0x400000, 0, 0, GetCasterGUID()))
+ AddPct(amount, twinDisciplines->GetAmount());
+
+ // Focused Power
+ amount *= caster->GetTotalAuraMultiplier(SPELL_AURA_MOD_HEALING_DONE_PERCENT);
+ }
+ }
+
+ void ReflectDamage(AuraEffect* aurEff, DamageInfo& dmgInfo, uint32& absorbAmount)
+ {
+ Unit* target = GetTarget();
+ if (dmgInfo.GetAttacker() == target)
+ return;
+
+ if (Unit* caster = GetCaster())
+ if (AuraEffect* talentAurEff = caster->GetAuraEffectOfRankedSpell(SPELL_PRIEST_REFLECTIVE_SHIELD_R1, EFFECT_0))
+ {
+ int32 bp = CalculatePct(absorbAmount, talentAurEff->GetAmount());
+ target->CastCustomSpell(dmgInfo.GetAttacker(), SPELL_PRIEST_REFLECTIVE_SHIELD_TRIGGERED, &bp, NULL, NULL, true, NULL, aurEff);
+ }
+ }
+
+ void Register()
+ {
+ DoEffectCalcAmount += AuraEffectCalcAmountFn(spell_pri_power_word_shield_AuraScript::CalculateAmount, EFFECT_0, SPELL_AURA_SCHOOL_ABSORB);
+ AfterEffectAbsorb += AuraEffectAbsorbFn(spell_pri_power_word_shield_AuraScript::ReflectDamage, EFFECT_0);
+ }
+ };
+
+ AuraScript* GetAuraScript() const
+ {
+ return new spell_pri_power_word_shield_AuraScript();
+ }
+};
+
// 33110 - Prayer of Mending Heal
class spell_pri_prayer_of_mending_heal : public SpellScriptLoader
{
@@ -545,12 +796,17 @@ class spell_pri_vampiric_touch : public SpellScriptLoader
void AddSC_priest_spell_scripts()
{
+ new spell_pri_divine_aegis();
+ new spell_pri_glyph_of_prayer_of_healing();
new spell_pri_guardian_spirit();
new spell_pri_leap_of_faith_effect_trigger();
+ new spell_pri_lightwell_renew();
new spell_pri_mana_burn();
+ new spell_pri_mana_leech();
new spell_pri_mind_sear();
new spell_pri_pain_and_suffering_proc();
new spell_pri_penance();
+ new spell_pri_power_word_shield();
new spell_pri_prayer_of_mending_heal();
new spell_pri_reflective_shield_trigger();
new spell_pri_renew();
diff --git a/src/server/scripts/Spells/spell_rogue.cpp b/src/server/scripts/Spells/spell_rogue.cpp
index 14d1c1a2f98..b19f5e2cbed 100644
--- a/src/server/scripts/Spells/spell_rogue.cpp
+++ b/src/server/scripts/Spells/spell_rogue.cpp
@@ -28,10 +28,13 @@
enum RogueSpells
{
+ SPELL_ROGUE_BLADE_FLURRY_EXTRA_ATTACK = 22482,
SPELL_ROGUE_CHEAT_DEATH_COOLDOWN = 31231,
SPELL_ROGUE_GLYPH_OF_PREPARATION = 56819,
SPELL_ROGUE_PREY_ON_THE_WEAK = 58670,
- SPELL_ROGUE_SHIV_TRIGGERED = 5940
+ SPELL_ROGUE_SHIV_TRIGGERED = 5940,
+ SPELL_ROGUE_TRICKS_OF_THE_TRADE_DMG_BOOST = 57933,
+ SPELL_ROGUE_TRICKS_OF_THE_TRADE_PROC = 59628,
};
enum RogueSpellIcons
@@ -39,6 +42,61 @@ enum RogueSpellIcons
ICON_ROGUE_IMPROVED_RECUPERATE = 4819
};
+// 13877, 33735, (check 51211, 65956) - Blade Flurry
+class spell_rog_blade_flurry : public SpellScriptLoader
+{
+ public:
+ spell_rog_blade_flurry() : SpellScriptLoader("spell_rog_blade_flurry") { }
+
+ class spell_rog_blade_flurry_AuraScript : public AuraScript
+ {
+ PrepareAuraScript(spell_rog_blade_flurry_AuraScript);
+
+ bool Validate(SpellInfo const* /*spellInfo*/)
+ {
+ if (!sSpellMgr->GetSpellInfo(SPELL_ROGUE_BLADE_FLURRY_EXTRA_ATTACK))
+ return false;
+ return true;
+ }
+
+ bool Load()
+ {
+ _procTarget = NULL;
+ return true;
+ }
+
+ bool CheckProc(ProcEventInfo& eventInfo)
+ {
+ _procTarget = eventInfo.GetActor()->SelectNearbyTarget(eventInfo.GetProcTarget());
+ return _procTarget;
+ }
+
+ void HandleProc(AuraEffect const* aurEff, ProcEventInfo& eventInfo)
+ {
+ PreventDefaultAction();
+ if (eventInfo.GetDamageInfo())
+ {
+ int32 damage = eventInfo.GetDamageInfo()->GetDamage();
+ GetTarget()->CastCustomSpell(SPELL_ROGUE_BLADE_FLURRY_EXTRA_ATTACK, SPELLVALUE_BASE_POINT0, damage, _procTarget, true, NULL, aurEff);
+ }
+ }
+
+ void Register()
+ {
+ DoCheckProc += AuraCheckProcFn(spell_rog_blade_flurry_AuraScript::CheckProc);
+ OnEffectProc += AuraEffectProcFn(spell_rog_blade_flurry_AuraScript::HandleProc, EFFECT_0, SPELL_AURA_MOD_MELEE_HASTE);
+ }
+
+ private:
+ Unit* _procTarget;
+ };
+
+ AuraScript* GetAuraScript() const
+ {
+ return new spell_rog_blade_flurry_AuraScript();
+ }
+};
+
// 31228 - Cheat Death
class spell_rog_cheat_death : public SpellScriptLoader
{
@@ -404,6 +462,58 @@ class spell_rog_recuperate : public SpellScriptLoader
}
};
+// -1943 - Rupture
+class spell_rog_rupture : public SpellScriptLoader
+{
+ public:
+ spell_rog_rupture() : SpellScriptLoader("spell_rog_rupture") { }
+
+ class spell_rog_rupture_AuraScript : public AuraScript
+ {
+ PrepareAuraScript(spell_rog_rupture_AuraScript);
+
+ bool Load()
+ {
+ Unit* caster = GetCaster();
+ return caster && caster->GetTypeId() == TYPEID_PLAYER;
+ }
+
+ void CalculateAmount(AuraEffect const* /*aurEff*/, int32& amount, bool& canBeRecalculated)
+ {
+ if (Unit* caster = GetCaster())
+ {
+ canBeRecalculated = false;
+
+ float const attackpowerPerCombo[6] =
+ {
+ 0.0f,
+ 0.015f, // 1 point: ${($m1 + $b1*1 + 0.015 * $AP) * 4} damage over 8 secs
+ 0.024f, // 2 points: ${($m1 + $b1*2 + 0.024 * $AP) * 5} damage over 10 secs
+ 0.03f, // 3 points: ${($m1 + $b1*3 + 0.03 * $AP) * 6} damage over 12 secs
+ 0.03428571f, // 4 points: ${($m1 + $b1*4 + 0.03428571 * $AP) * 7} damage over 14 secs
+ 0.0375f // 5 points: ${($m1 + $b1*5 + 0.0375 * $AP) * 8} damage over 16 secs
+ };
+
+ uint8 cp = caster->ToPlayer()->GetComboPoints();
+ if (cp > 5)
+ cp = 5;
+
+ amount += int32(caster->GetTotalAttackPowerValue(BASE_ATTACK) * attackpowerPerCombo[cp]);
+ }
+ }
+
+ void Register()
+ {
+ DoEffectCalcAmount += AuraEffectCalcAmountFn(spell_rog_rupture_AuraScript::CalculateAmount, EFFECT_0, SPELL_AURA_PERIODIC_DAMAGE);
+ }
+ };
+
+ AuraScript* GetAuraScript() const
+ {
+ return new spell_rog_rupture_AuraScript();
+ }
+};
+
// 5938 - Shiv
class spell_rog_shiv : public SpellScriptLoader
{
@@ -445,13 +555,108 @@ class spell_rog_shiv : public SpellScriptLoader
}
};
+// 57934 - Tricks of the Trade
+class spell_rog_tricks_of_the_trade : public SpellScriptLoader
+{
+ public:
+ spell_rog_tricks_of_the_trade() : SpellScriptLoader("spell_rog_tricks_of_the_trade") { }
+
+ class spell_rog_tricks_of_the_trade_AuraScript : public AuraScript
+ {
+ PrepareAuraScript(spell_rog_tricks_of_the_trade_AuraScript);
+
+ bool Validate(SpellInfo const* /*spellInfo*/)
+ {
+ if (!sSpellMgr->GetSpellInfo(SPELL_ROGUE_TRICKS_OF_THE_TRADE_DMG_BOOST))
+ return false;
+ if (!sSpellMgr->GetSpellInfo(SPELL_ROGUE_TRICKS_OF_THE_TRADE_PROC))
+ return false;
+ return true;
+ }
+
+ bool Load()
+ {
+ _redirectTarget = NULL;
+ return true;
+ }
+
+ void OnRemove(AuraEffect const* /*aurEff*/, AuraEffectHandleModes /*mode*/)
+ {
+ if (GetTargetApplication()->GetRemoveMode() != AURA_REMOVE_BY_DEFAULT)
+ GetTarget()->ResetRedirectThreat();
+ }
+
+ bool CheckProc(ProcEventInfo& /*eventInfo*/)
+ {
+ _redirectTarget = GetTarget()->GetRedirectThreatTarget();
+ return _redirectTarget;
+ }
+
+ void HandleProc(AuraEffect const* /*aurEff*/, ProcEventInfo& /*eventInfo*/)
+ {
+ PreventDefaultAction();
+
+ Unit* target = GetTarget();
+ target->CastSpell(_redirectTarget, SPELL_ROGUE_TRICKS_OF_THE_TRADE_DMG_BOOST, true);
+ target->CastSpell(target, SPELL_ROGUE_TRICKS_OF_THE_TRADE_PROC, true);
+ Remove(AURA_REMOVE_BY_DEFAULT); // maybe handle by proc charges
+ }
+
+ void Register()
+ {
+ AfterEffectRemove += AuraEffectRemoveFn(spell_rog_tricks_of_the_trade_AuraScript::OnRemove, EFFECT_1, SPELL_AURA_DUMMY, AURA_EFFECT_HANDLE_REAL);
+ DoCheckProc += AuraCheckProcFn(spell_rog_tricks_of_the_trade_AuraScript::CheckProc);
+ OnEffectProc += AuraEffectProcFn(spell_rog_tricks_of_the_trade_AuraScript::HandleProc, EFFECT_1, SPELL_AURA_DUMMY);
+ }
+
+ private:
+ Unit* _redirectTarget;
+ };
+
+ AuraScript* GetAuraScript() const
+ {
+ return new spell_rog_tricks_of_the_trade_AuraScript();
+ }
+};
+
+// 59628 - Tricks of the Trade (Proc)
+class spell_rog_tricks_of_the_trade_proc : public SpellScriptLoader
+{
+ public:
+ spell_rog_tricks_of_the_trade_proc() : SpellScriptLoader("spell_rog_tricks_of_the_trade_proc") { }
+
+ class spell_rog_tricks_of_the_trade_proc_AuraScript : public AuraScript
+ {
+ PrepareAuraScript(spell_rog_tricks_of_the_trade_proc_AuraScript);
+
+ void HandleRemove(AuraEffect const* /*aurEff*/, AuraEffectHandleModes /*mode*/)
+ {
+ GetTarget()->ResetRedirectThreat();
+ }
+
+ void Register()
+ {
+ AfterEffectRemove += AuraEffectRemoveFn(spell_rog_tricks_of_the_trade_proc_AuraScript::HandleRemove, EFFECT_0, SPELL_AURA_DUMMY, AURA_EFFECT_HANDLE_REAL);
+ }
+ };
+
+ AuraScript* GetAuraScript() const
+ {
+ return new spell_rog_tricks_of_the_trade_proc_AuraScript();
+ }
+};
+
void AddSC_rogue_spell_scripts()
{
+ new spell_rog_blade_flurry();
new spell_rog_cheat_death();
new spell_rog_deadly_poison();
new spell_rog_nerves_of_steel();
new spell_rog_preparation();
new spell_rog_prey_on_the_weak();
new spell_rog_recuperate();
+ new spell_rog_rupture();
new spell_rog_shiv();
+ new spell_rog_tricks_of_the_trade();
+ new spell_rog_tricks_of_the_trade_proc();
}
diff --git a/src/server/scripts/Spells/spell_shaman.cpp b/src/server/scripts/Spells/spell_shaman.cpp
index e2e3f5a52e7..045227a8f99 100644
--- a/src/server/scripts/Spells/spell_shaman.cpp
+++ b/src/server/scripts/Spells/spell_shaman.cpp
@@ -34,9 +34,14 @@ enum ShamanSpells
SPELL_MAGE_TEMPORAL_DISPLACEMENT = 80354,
SPELL_SHAMAN_ANCESTRAL_AWAKENING_PROC = 52752,
SPELL_SHAMAN_BIND_SIGHT = 6277,
+ SPELL_SHAMAN_EARTH_SHIELD_HEAL = 379,
SPELL_SHAMAN_EXHAUSTION = 57723,
SPELL_SHAMAN_FIRE_NOVA_TRIGGERED_R1 = 8349,
SPELL_SHAMAN_FLAME_SHOCK = 8050,
+ SPELL_SHAMAN_GLYPH_OF_EARTH_SHIELD = 63279,
+ SPELL_SHAMAN_GLYPH_OF_HEALING_STREAM_TOTEM = 55456,
+ SPELL_SHAMAN_GLYPH_OF_MANA_TIDE = 55441,
+ SPELL_SHAMAN_GLYPH_OF_THUNDERSTORM = 62132,
SPELL_SHAMAN_LAVA_FLOWS_R1 = 51480,
SPELL_SHAMAN_LAVA_FLOWS_TRIGGERED_R1 = 65264,
SPELL_SHAMAN_SATED = 57724,
@@ -193,6 +198,68 @@ class spell_sha_chain_heal : public SpellScriptLoader
}
};
+// -974 - Earth Shield
+class spell_sha_earth_shield : public SpellScriptLoader
+{
+ public:
+ spell_sha_earth_shield() : SpellScriptLoader("spell_sha_earth_shield") { }
+
+ class spell_sha_earth_shield_AuraScript : public AuraScript
+ {
+ PrepareAuraScript(spell_sha_earth_shield_AuraScript);
+
+ bool Validate(SpellInfo const* /*spellInfo*/)
+ {
+ if (!sSpellMgr->GetSpellInfo(SPELL_SHAMAN_EARTH_SHIELD_HEAL))
+ return false;
+ if (!sSpellMgr->GetSpellInfo(SPELL_SHAMAN_GLYPH_OF_EARTH_SHIELD))
+ return false;
+ return true;
+ }
+
+ void CalculateAmount(AuraEffect const* /*aurEff*/, int32& amount, bool & /*canBeRecalculated*/)
+ {
+ if (Unit* caster = GetCaster())
+ {
+ amount = caster->SpellHealingBonusDone(GetUnitOwner(), GetSpellInfo(), amount, HEAL);
+ amount = GetUnitOwner()->SpellHealingBonusTaken(caster, GetSpellInfo(), amount, HEAL);
+
+ // Glyph of Earth Shield
+ //! WORKAROUND
+ //! this glyph is a proc
+ if (AuraEffect* glyph = caster->GetAuraEffect(SPELL_SHAMAN_GLYPH_OF_EARTH_SHIELD, EFFECT_0))
+ AddPct(amount, glyph->GetAmount());
+ }
+ }
+
+ void HandleProc(AuraEffect const* aurEff, ProcEventInfo& /*eventInfo*/)
+ {
+ PreventDefaultAction();
+
+ //! HACK due to currenct proc system implementation
+ if (Player* player = GetTarget()->ToPlayer())
+ if (player->HasSpellCooldown(SPELL_SHAMAN_EARTH_SHIELD_HEAL))
+ return;
+
+ GetTarget()->CastCustomSpell(SPELL_SHAMAN_EARTH_SHIELD_HEAL, SPELLVALUE_BASE_POINT0, aurEff->GetAmount(), GetTarget(), true, NULL, aurEff, GetCasterGUID());
+
+ if (Player* player = GetTarget()->ToPlayer())
+ player->AddSpellCooldown(SPELL_SHAMAN_EARTH_SHIELD_HEAL, 0, time(NULL) + 3);
+ }
+
+ void Register()
+ {
+ DoEffectCalcAmount += AuraEffectCalcAmountFn(spell_sha_earth_shield_AuraScript::CalculateAmount, EFFECT_0, SPELL_AURA_DUMMY);
+ OnEffectProc += AuraEffectProcFn(spell_sha_earth_shield_AuraScript::HandleProc, EFFECT_0, SPELL_AURA_DUMMY);
+ }
+ };
+
+ AuraScript* GetAuraScript() const
+ {
+ return new spell_sha_earth_shield_AuraScript();
+ }
+};
+
// 6474 - Earthbind Totem - Fix Talent:Earthen Power, Earth's Grasp
/// Updated 4.3.4
class spell_sha_earthbind_totem : public SpellScriptLoader
@@ -549,11 +616,41 @@ class spell_sha_mana_tide_totem : public SpellScriptLoader
}
};
+// -51490 - Thunderstorm
+class spell_sha_thunderstorm : public SpellScriptLoader
+{
+ public:
+ spell_sha_thunderstorm() : SpellScriptLoader("spell_sha_thunderstorm") { }
+
+ class spell_sha_thunderstorm_SpellScript : public SpellScript
+ {
+ PrepareSpellScript(spell_sha_thunderstorm_SpellScript);
+
+ void HandleKnockBack(SpellEffIndex effIndex)
+ {
+ // Glyph of Thunderstorm
+ if (GetCaster()->HasAura(SPELL_SHAMAN_GLYPH_OF_THUNDERSTORM))
+ PreventHitDefaultEffect(effIndex);
+ }
+
+ void Register()
+ {
+ OnEffectHitTarget += SpellEffectFn(spell_sha_thunderstorm_SpellScript::HandleKnockBack, EFFECT_2, SPELL_EFFECT_KNOCK_BACK);
+ }
+ };
+
+ SpellScript* GetSpellScript() const
+ {
+ return new spell_sha_thunderstorm_SpellScript();
+ }
+};
+
void AddSC_shaman_spell_scripts()
{
new spell_sha_ancestral_awakening_proc();
new spell_sha_bloodlust();
new spell_sha_chain_heal();
+ new spell_sha_earth_shield();
new spell_sha_earthbind_totem();
new spell_sha_earthen_power();
new spell_sha_fire_nova();
@@ -562,4 +659,5 @@ void AddSC_shaman_spell_scripts()
new spell_sha_heroism();
new spell_sha_lava_lash();
new spell_sha_mana_tide_totem();
+ new spell_sha_thunderstorm();
}
diff --git a/src/server/scripts/Spells/spell_warlock.cpp b/src/server/scripts/Spells/spell_warlock.cpp
index 21dea0b726b..31833524861 100644
--- a/src/server/scripts/Spells/spell_warlock.cpp
+++ b/src/server/scripts/Spells/spell_warlock.cpp
@@ -37,6 +37,8 @@ enum WarlockSpells
SPELL_WARLOCK_DEMONIC_EMPOWERMENT_FELGUARD = 54508,
SPELL_WARLOCK_DEMONIC_EMPOWERMENT_FELHUNTER = 54509,
SPELL_WARLOCK_DEMONIC_EMPOWERMENT_IMP = 54444,
+ SPELL_WARLOCK_FEL_SYNERGY_HEAL = 54181,
+ SPELL_WARLOCK_GLYPH_OF_SIPHON_LIFE = 63106,
SPELL_WARLOCK_IMPROVED_HEALTHSTONE_R1 = 18692,
SPELL_WARLOCK_IMPROVED_HEALTHSTONE_R2 = 18693,
SPELL_WARLOCK_IMPROVED_HEALTH_FUNNEL_R1 = 18703,
@@ -48,6 +50,7 @@ enum WarlockSpells
SPELL_WARLOCK_LIFE_TAP_ENERGIZE = 31818,
SPELL_WARLOCK_LIFE_TAP_ENERGIZE_2 = 32553,
SPELL_WARLOCK_SOULSHATTER = 32835,
+ SPELL_WARLOCK_SIPHON_LIFE_HEAL = 63106,
SPELL_WARLOCK_UNSTABLE_AFFLICTION_DISPEL = 31117
};
@@ -426,6 +429,49 @@ class spell_warl_everlasting_affliction : public SpellScriptLoader
}
};
+// -47230 - Fel Synergy
+class spell_warl_fel_synergy : public SpellScriptLoader
+{
+ public:
+ spell_warl_fel_synergy() : SpellScriptLoader("spell_warl_fel_synergy") { }
+
+ class spell_warl_fel_synergy_AuraScript : public AuraScript
+ {
+ PrepareAuraScript(spell_warl_fel_synergy_AuraScript);
+
+ bool Validate(SpellInfo const* /*spellInfo*/)
+ {
+ if (!sSpellMgr->GetSpellInfo(SPELL_WARLOCK_FEL_SYNERGY_HEAL))
+ return false;
+ return true;
+ }
+
+ bool CheckProc(ProcEventInfo& eventInfo)
+ {
+ return GetTarget()->GetGuardianPet() && eventInfo.GetDamageInfo()->GetDamage();
+ }
+
+ void OnProc(AuraEffect const* aurEff, ProcEventInfo& eventInfo)
+ {
+ PreventDefaultAction();
+
+ int32 heal = CalculatePct(int32(eventInfo.GetDamageInfo()->GetDamage()), aurEff->GetAmount());
+ GetTarget()->CastCustomSpell(SPELL_WARLOCK_FEL_SYNERGY_HEAL, SPELLVALUE_BASE_POINT0, heal, (Unit*)NULL, true, NULL, aurEff); // TARGET_UNIT_PET
+ }
+
+ void Register()
+ {
+ DoCheckProc += AuraCheckProcFn(spell_warl_fel_synergy_AuraScript::CheckProc);
+ OnEffectProc += AuraEffectProcFn(spell_warl_fel_synergy_AuraScript::OnProc, EFFECT_0, SPELL_AURA_DUMMY);
+ }
+ };
+
+ AuraScript* GetAuraScript() const
+ {
+ return new spell_warl_fel_synergy_AuraScript();
+ }
+};
+
// 48181 - Haunt
/// Updated 4.3.4
class spell_warl_haunt : public SpellScriptLoader
@@ -630,6 +676,92 @@ class spell_warl_seed_of_corruption : public SpellScriptLoader
}
};
+// -7235 - Shadow Ward
+class spell_warl_shadow_ward : public SpellScriptLoader
+{
+ public:
+ spell_warl_shadow_ward() : SpellScriptLoader("spell_warl_shadow_ward") { }
+
+ class spell_warl_shadow_ward_AuraScript : public AuraScript
+ {
+ PrepareAuraScript(spell_warl_shadow_ward_AuraScript);
+
+ void CalculateAmount(AuraEffect const* /*aurEff*/, int32& amount, bool& canBeRecalculated)
+ {
+ canBeRecalculated = false;
+ if (Unit* caster = GetCaster())
+ {
+ // +80.68% from sp bonus
+ float bonus = 0.8068f;
+
+ bonus *= caster->SpellBaseHealingBonusDone(GetSpellInfo()->GetSchoolMask());
+ bonus *= caster->CalculateLevelPenalty(GetSpellInfo());
+
+ amount += int32(bonus);
+ }
+ }
+
+ void Register()
+ {
+ DoEffectCalcAmount += AuraEffectCalcAmountFn(spell_warl_shadow_ward_AuraScript::CalculateAmount, EFFECT_0, SPELL_AURA_SCHOOL_ABSORB);
+ }
+ };
+
+ AuraScript* GetAuraScript() const
+ {
+ return new spell_warl_shadow_ward_AuraScript();
+ }
+};
+
+// 63108 - Siphon Life
+class spell_warl_siphon_life : public SpellScriptLoader
+{
+ public:
+ spell_warl_siphon_life() : SpellScriptLoader("spell_warl_siphon_life") { }
+
+ class spell_warl_siphon_life_AuraScript : public AuraScript
+ {
+ PrepareAuraScript(spell_warl_siphon_life_AuraScript);
+
+ bool Validate(SpellInfo const* /*spellInfo*/)
+ {
+ if (!sSpellMgr->GetSpellInfo(SPELL_WARLOCK_SIPHON_LIFE_HEAL))
+ return false;
+ if (!sSpellMgr->GetSpellInfo(SPELL_WARLOCK_GLYPH_OF_SIPHON_LIFE))
+ return false;
+ return true;
+ }
+
+ bool CheckProc(ProcEventInfo& eventInfo)
+ {
+ return eventInfo.GetDamageInfo()->GetDamage();
+ }
+
+ void OnProc(AuraEffect const* aurEff, ProcEventInfo& eventInfo)
+ {
+ PreventDefaultAction();
+
+ int32 amount = int32(CalculatePct(eventInfo.GetDamageInfo()->GetDamage(), aurEff->GetAmount()));
+ // Glyph of Siphon Life
+ if (AuraEffect const* glyph = GetTarget()->GetAuraEffect(SPELL_WARLOCK_GLYPH_OF_SIPHON_LIFE, EFFECT_0))
+ AddPct(amount, glyph->GetAmount());
+
+ GetTarget()->CastCustomSpell(SPELL_WARLOCK_SIPHON_LIFE_HEAL, SPELLVALUE_BASE_POINT0, amount, GetTarget(), true, NULL, aurEff);
+ }
+
+ void Register()
+ {
+ DoCheckProc += AuraCheckProcFn(spell_warl_siphon_life_AuraScript::CheckProc);
+ OnEffectProc += AuraEffectProcFn(spell_warl_siphon_life_AuraScript::OnProc, EFFECT_0, SPELL_AURA_DUMMY);
+ }
+ };
+
+ AuraScript* GetAuraScript() const
+ {
+ return new spell_warl_siphon_life_AuraScript();
+ }
+};
+
// 29858 - Soulshatter
/// Updated 4.3.4
class spell_warl_soulshatter : public SpellScriptLoader
@@ -714,14 +846,19 @@ void AddSC_warlock_spell_scripts()
new spell_warl_bane_of_doom();
new spell_warl_banish();
new spell_warl_create_healthstone();
+ new spell_warl_curse_of_doom();
new spell_warl_demonic_circle_summon();
new spell_warl_demonic_circle_teleport();
new spell_warl_demonic_empowerment();
new spell_warl_everlasting_affliction();
+ new spell_warl_fel_synergy();
new spell_warl_haunt();
new spell_warl_health_funnel();
new spell_warl_life_tap();
+ new spell_warl_ritual_of_doom_effect();
new spell_warl_seed_of_corruption();
+ new spell_warl_shadow_ward();
+ new spell_warl_siphon_life();
new spell_warl_soulshatter();
new spell_warl_unstable_affliction();
}
diff --git a/src/server/scripts/Spells/spell_warrior.cpp b/src/server/scripts/Spells/spell_warrior.cpp
index 909e90beaad..c155c39ffdb 100644
--- a/src/server/scripts/Spells/spell_warrior.cpp
+++ b/src/server/scripts/Spells/spell_warrior.cpp
@@ -31,14 +31,32 @@ enum WarriorSpells
SPELL_WARRIOR_BLOODTHIRST = 23885,
SPELL_WARRIOR_BLOODTHIRST_DAMAGE = 23881,
SPELL_WARRIOR_CHARGE = 34846,
+ SPELL_WARRIOR_DAMAGE_SHIELD_DAMAGE = 59653,
SPELL_WARRIOR_DEEP_WOUNDS_RANK_1 = 12162,
SPELL_WARRIOR_DEEP_WOUNDS_RANK_2 = 12850,
SPELL_WARRIOR_DEEP_WOUNDS_RANK_3 = 12868,
SPELL_WARRIOR_DEEP_WOUNDS_RANK_PERIODIC = 12721,
+ SPELL_WARRIOR_EXECUTE = 20647,
+ SPELL_WARRIOR_GLYPH_OF_EXECUTION = 58367,
+ SPELL_WARRIOR_GLYPH_OF_VIGILANCE = 63326,
SPELL_WARRIOR_JUGGERNAUT_CRIT_BONUS_BUFF = 65156,
SPELL_WARRIOR_JUGGERNAUT_CRIT_BONUS_TALENT = 64976,
SPELL_WARRIOR_LAST_STAND_TRIGGERED = 12976,
- SPELL_WARRIOR_SLAM = 50782
+ SPELL_WARRIOR_SLAM = 50782,
+ SPELL_WARRIOR_SLAM = 50783,
+ SPELL_WARRIOR_SWEEPING_STRIKES_EXTRA_ATTACK = 26654,
+ SPELL_WARRIOR_TAUNT = 355,
+ SPELL_WARRIOR_UNRELENTING_ASSAULT_RANK_1 = 46859,
+ SPELL_WARRIOR_UNRELENTING_ASSAULT_RANK_2 = 46860,
+ SPELL_WARRIOR_UNRELENTING_ASSAULT_TRIGGER_1 = 64849,
+ SPELL_WARRIOR_UNRELENTING_ASSAULT_TRIGGER_2 = 64850,
+ SPELL_WARRIOR_VIGILANCE_PROC = 50725,
+ SPELL_WARRIOR_VIGILANCE_REDIRECT_THREAT = 59665,
+
+ SPELL_PALADIN_BLESSING_OF_SANCTUARY = 20911,
+ SPELL_PALADIN_GREATER_BLESSING_OF_SANCTUARY = 25899,
+ SPELL_PRIEST_RENEWED_HOPE = 63944,
+ SPELL_GEN_DAMAGE_REDUCTION_AURA = 68066,
};
enum WarriorSpellIcons
@@ -183,6 +201,44 @@ class spell_warr_concussion_blow : public SpellScriptLoader
}
};
+// -58872 - Damage Shield
+class spell_warr_damage_shield : public SpellScriptLoader
+{
+ public:
+ spell_warr_damage_shield() : SpellScriptLoader("spell_warr_damage_shield") { }
+
+ class spell_warr_damage_shield_AuraScript : public AuraScript
+ {
+ PrepareAuraScript(spell_warr_damage_shield_AuraScript);
+
+ bool Validate(SpellInfo const* /*spellInfo*/)
+ {
+ if (!sSpellMgr->GetSpellInfo(SPELL_WARRIOR_DAMAGE_SHIELD_DAMAGE))
+ return false;
+ return true;
+ }
+
+ void OnProc(AuraEffect const* aurEff, ProcEventInfo& eventInfo)
+ {
+ PreventDefaultAction();
+
+ // % of amount blocked
+ int32 damage = CalculatePct(int32(GetTarget()->GetShieldBlockValue()), aurEff->GetAmount());
+ GetTarget()->CastCustomSpell(SPELL_WARRIOR_DAMAGE_SHIELD_DAMAGE, SPELLVALUE_BASE_POINT0, damage, eventInfo.GetProcTarget(), true, NULL, aurEff);
+ }
+
+ void Register()
+ {
+ OnEffectProc += AuraEffectProcFn(spell_warr_damage_shield_AuraScript::OnProc, EFFECT_0, SPELL_AURA_DUMMY);
+ }
+ };
+
+ AuraScript* GetAuraScript() const
+ {
+ return new spell_warr_damage_shield_AuraScript();
+ }
+};
+
/// Updated 4.3.4
class spell_warr_deep_wounds : public SpellScriptLoader
{
@@ -286,6 +342,62 @@ class spell_warr_execute : public SpellScriptLoader
}
};
+// 59725 - Improved Spell Reflection
+class spell_warr_improved_spell_reflection : public SpellScriptLoader
+{
+ public:
+ spell_warr_improved_spell_reflection() : SpellScriptLoader("spell_warr_improved_spell_reflection") { }
+
+ class spell_warr_improved_spell_reflection_SpellScript : public SpellScript
+ {
+ PrepareSpellScript(spell_warr_improved_spell_reflection_SpellScript);
+
+ void FilterTargets(std::list<WorldObject*>& unitList)
+ {
+ if (GetCaster())
+ unitList.remove(GetCaster());
+ }
+
+ void Register()
+ {
+ OnObjectAreaTargetSelect += SpellObjectAreaTargetSelectFn(spell_warr_improved_spell_reflection_SpellScript::FilterTargets, EFFECT_0, TARGET_UNIT_CASTER_AREA_PARTY);
+ }
+ };
+
+ SpellScript* GetSpellScript() const
+ {
+ return new spell_warr_improved_spell_reflection_SpellScript();
+ }
+};
+
+// 5246 - Intimidating Shout
+class spell_warr_intimidating_shout : public SpellScriptLoader
+{
+ public:
+ spell_warr_intimidating_shout() : SpellScriptLoader("spell_warr_intimidating_shout") { }
+
+ class spell_warr_intimidating_shout_SpellScript : public SpellScript
+ {
+ PrepareSpellScript(spell_warr_intimidating_shout_SpellScript);
+
+ void FilterTargets(std::list<WorldObject*>& unitList)
+ {
+ unitList.remove(GetExplTargetWorldObject());
+ }
+
+ void Register()
+ {
+ OnObjectAreaTargetSelect += SpellObjectAreaTargetSelectFn(spell_warr_intimidating_shout_SpellScript::FilterTargets, EFFECT_1, TARGET_UNIT_SRC_AREA_ENEMY);
+ OnObjectAreaTargetSelect += SpellObjectAreaTargetSelectFn(spell_warr_intimidating_shout_SpellScript::FilterTargets, EFFECT_2, TARGET_UNIT_SRC_AREA_ENEMY);
+ }
+ };
+
+ SpellScript* GetSpellScript() const
+ {
+ return new spell_warr_intimidating_shout_SpellScript();
+ }
+};
+
/// Updated 4.3.4
class spell_warr_last_stand : public SpellScriptLoader
{
@@ -325,6 +437,121 @@ class spell_warr_last_stand : public SpellScriptLoader
}
};
+// 7384, 7887, 11584, 11585 - Overpower
+class spell_warr_overpower : public SpellScriptLoader
+{
+ public:
+ spell_warr_overpower() : SpellScriptLoader("spell_warr_overpower") { }
+
+ class spell_warr_overpower_SpellScript : public SpellScript
+ {
+ PrepareSpellScript(spell_warr_overpower_SpellScript);
+
+ void HandleEffect(SpellEffIndex /*effIndex*/)
+ {
+ uint32 spellId = 0;
+ if (GetCaster()->HasAura(SPELL_WARRIOR_UNRELENTING_ASSAULT_RANK_1))
+ spellId = SPELL_WARRIOR_UNRELENTING_ASSAULT_TRIGGER_1;
+ else if (GetCaster()->HasAura(SPELL_WARRIOR_UNRELENTING_ASSAULT_RANK_2))
+ spellId = SPELL_WARRIOR_UNRELENTING_ASSAULT_TRIGGER_2;
+
+ if (!spellId)
+ return;
+
+ if (Player* target = GetHitPlayer())
+ if (target->HasUnitState(UNIT_STATE_CASTING))
+ target->CastSpell(target, spellId, true);
+ }
+
+ void Register()
+ {
+ OnEffectHitTarget += SpellEffectFn(spell_warr_overpower_SpellScript::HandleEffect, EFFECT_0, SPELL_EFFECT_ANY);
+ }
+ };
+
+ SpellScript* GetSpellScript() const
+ {
+ return new spell_warr_overpower_SpellScript();
+ }
+};
+
+// -772 - Rend
+class spell_warr_rend : public SpellScriptLoader
+{
+ public:
+ spell_warr_rend() : SpellScriptLoader("spell_warr_rend") { }
+
+ class spell_warr_rend_AuraScript : public AuraScript
+ {
+ PrepareAuraScript(spell_warr_rend_AuraScript);
+
+ void CalculateAmount(AuraEffect const* aurEff, int32& amount, bool& canBeRecalculated)
+ {
+ if (Unit* caster = GetCaster())
+ {
+ canBeRecalculated = false;
+
+ // $0.2 * (($MWB + $mwb) / 2 + $AP / 14 * $MWS) bonus per tick
+ float ap = caster->GetTotalAttackPowerValue(BASE_ATTACK);
+ int32 mws = caster->GetAttackTime(BASE_ATTACK);
+ float mwbMin = caster->GetWeaponDamageRange(BASE_ATTACK, MINDAMAGE);
+ float mwbMax = caster->GetWeaponDamageRange(BASE_ATTACK, MAXDAMAGE);
+ float mwb = ((mwbMin + mwbMax) / 2 + ap * mws / 14000) * 0.2f;
+ amount += int32(caster->ApplyEffectModifiers(GetSpellInfo(), aurEff->GetEffIndex(), mwb));
+
+ // "If used while your target is above 75% health, Rend does 35% more damage."
+ // as for 3.1.3 only ranks above 9 (wrong tooltip?)
+ if (GetSpellInfo()->GetRank() >= 9)
+ {
+ if (GetUnitOwner()->HasAuraState(AURA_STATE_HEALTH_ABOVE_75_PERCENT, GetSpellInfo(), caster))
+ AddPct(amount, GetSpellInfo()->Effects[EFFECT_2].CalcValue(caster));
+ }
+ }
+ }
+
+ void Register()
+ {
+ DoEffectCalcAmount += AuraEffectCalcAmountFn(spell_warr_rend_AuraScript::CalculateAmount, EFFECT_0, SPELL_AURA_PERIODIC_DAMAGE);
+ }
+ };
+
+ AuraScript* GetAuraScript() const
+ {
+ return new spell_warr_rend_AuraScript();
+ }
+};
+
+// 64380, 65941 - Shattering Throw
+class spell_warr_shattering_throw : public SpellScriptLoader
+{
+ public:
+ spell_warr_shattering_throw() : SpellScriptLoader("spell_warr_shattering_throw") { }
+
+ class spell_warr_shattering_throw_SpellScript : public SpellScript
+ {
+ PrepareSpellScript(spell_warr_shattering_throw_SpellScript);
+
+ void HandleScript(SpellEffIndex effIndex)
+ {
+ PreventHitDefaultEffect(effIndex);
+
+ // remove shields, will still display immune to damage part
+ if (Unit* target = GetHitUnit())
+ target->RemoveAurasWithMechanic(1 << MECHANIC_IMMUNE_SHIELD, AURA_REMOVE_BY_ENEMY_SPELL);
+ }
+
+ void Register()
+ {
+ OnEffectHitTarget += SpellEffectFn(spell_warr_shattering_throw_SpellScript::HandleScript, EFFECT_0, SPELL_EFFECT_SCRIPT_EFFECT);
+ }
+ };
+
+ SpellScript* GetSpellScript() const
+ {
+ return new spell_warr_shattering_throw_SpellScript();
+ }
+};
+
/// Updated 4.3.4
class spell_warr_slam : public SpellScriptLoader
{
@@ -361,14 +588,199 @@ class spell_warr_slam : public SpellScriptLoader
}
};
+// 12328, 18765, 35429 - Sweeping Strikes
+class spell_warr_sweeping_strikes : public SpellScriptLoader
+{
+ public:
+ spell_warr_sweeping_strikes() : SpellScriptLoader("spell_warr_sweeping_strikes") { }
+
+ class spell_warr_sweeping_strikes_AuraScript : public AuraScript
+ {
+ PrepareAuraScript(spell_warr_sweeping_strikes_AuraScript);
+
+ bool Validate(SpellInfo const* /*spellInfo*/)
+ {
+ if (!sSpellMgr->GetSpellInfo(SPELL_WARRIOR_SWEEPING_STRIKES_EXTRA_ATTACK))
+ return false;
+ return true;
+ }
+
+ bool Load()
+ {
+ _procTarget = NULL;
+ return true;
+ }
+
+ bool CheckProc(ProcEventInfo& eventInfo)
+ {
+ _procTarget = eventInfo.GetActor()->SelectNearbyTarget(eventInfo.GetProcTarget());
+ return _procTarget;
+ }
+
+ void HandleProc(AuraEffect const* aurEff, ProcEventInfo& /*eventInfo*/)
+ {
+ PreventDefaultAction();
+ GetTarget()->CastSpell(_procTarget, SPELL_WARRIOR_SWEEPING_STRIKES_EXTRA_ATTACK, true, NULL, aurEff);
+ }
+
+ void Register()
+ {
+ DoCheckProc += AuraCheckProcFn(spell_warr_sweeping_strikes_AuraScript::CheckProc);
+ OnEffectProc += AuraEffectProcFn(spell_warr_sweeping_strikes_AuraScript::HandleProc, EFFECT_0, SPELL_AURA_DUMMY);
+ }
+
+ private:
+ Unit* _procTarget;
+ };
+
+ AuraScript* GetAuraScript() const
+ {
+ return new spell_warr_sweeping_strikes_AuraScript();
+ }
+};
+
+// 50720 - Vigilance
+class spell_warr_vigilance : public SpellScriptLoader
+{
+ public:
+ spell_warr_vigilance() : SpellScriptLoader("spell_warr_vigilance") { }
+
+ class spell_warr_vigilance_AuraScript : public AuraScript
+ {
+ PrepareAuraScript(spell_warr_vigilance_AuraScript);
+
+ bool Validate(SpellInfo const* /*spellInfo*/)
+ {
+ if (!sSpellMgr->GetSpellInfo(SPELL_WARRIOR_GLYPH_OF_VIGILANCE))
+ return false;
+ if (!sSpellMgr->GetSpellInfo(SPELL_WARRIOR_VIGILANCE_PROC))
+ return false;
+ if (!sSpellMgr->GetSpellInfo(SPELL_WARRIOR_VIGILANCE_REDIRECT_THREAT))
+ return false;
+ if (!sSpellMgr->GetSpellInfo(SPELL_GEN_DAMAGE_REDUCTION_AURA))
+ return false;
+ return true;
+ }
+
+ bool Load()
+ {
+ _procTarget = NULL;
+ return true;
+ }
+
+ void HandleApply(AuraEffect const* /*aurEff*/, AuraEffectHandleModes /*mode*/)
+ {
+ Unit* target = GetTarget();
+ target->CastSpell(target, SPELL_GEN_DAMAGE_REDUCTION_AURA, true);
+
+ if (Unit* caster = GetCaster())
+ target->CastSpell(caster, SPELL_WARRIOR_VIGILANCE_REDIRECT_THREAT, true);
+ }
+
+ void HandleAfterApply(AuraEffect const* /*aurEff*/, AuraEffectHandleModes /*mode*/)
+ {
+ //! WORKAROUND
+ //! this glyph is a proc
+ if (Unit* caster = GetCaster())
+ {
+ if (AuraEffect const* glyph = caster->GetAuraEffect(SPELL_WARRIOR_GLYPH_OF_VIGILANCE, EFFECT_0))
+ GetTarget()->ModifyRedirectThreat(glyph->GetAmount());
+ }
+ }
+
+ void HandleRemove(AuraEffect const* /*aurEff*/, AuraEffectHandleModes /*mode*/)
+ {
+ Unit* target = GetTarget();
+ if (target->HasAura(SPELL_GEN_DAMAGE_REDUCTION_AURA) &&
+ !(target->HasAura(SPELL_PALADIN_BLESSING_OF_SANCTUARY) ||
+ target->HasAura(SPELL_PALADIN_GREATER_BLESSING_OF_SANCTUARY) ||
+ target->HasAura(SPELL_PRIEST_RENEWED_HOPE)))
+ {
+ target->RemoveAurasDueToSpell(SPELL_GEN_DAMAGE_REDUCTION_AURA);
+ }
+
+ target->ResetRedirectThreat();
+ }
+
+ bool CheckProc(ProcEventInfo& /*eventInfo*/)
+ {
+ _procTarget = GetCaster();
+ return _procTarget;
+ }
+
+ void HandleProc(AuraEffect const* aurEff, ProcEventInfo& /*eventInfo*/)
+ {
+ PreventDefaultAction();
+ GetTarget()->CastSpell(_procTarget, SPELL_WARRIOR_VIGILANCE_PROC, true, NULL, aurEff);
+ }
+
+ void Register()
+ {
+ OnEffectApply += AuraEffectApplyFn(spell_warr_vigilance_AuraScript::HandleApply, EFFECT_0, SPELL_AURA_PROC_TRIGGER_SPELL, AURA_EFFECT_HANDLE_REAL_OR_REAPPLY_MASK);
+ AfterEffectApply += AuraEffectApplyFn(spell_warr_vigilance_AuraScript::HandleAfterApply, EFFECT_0, SPELL_AURA_PROC_TRIGGER_SPELL, AURA_EFFECT_HANDLE_REAL_OR_REAPPLY_MASK);
+ OnEffectRemove += AuraEffectRemoveFn(spell_warr_vigilance_AuraScript::HandleRemove, EFFECT_0, SPELL_AURA_PROC_TRIGGER_SPELL, AURA_EFFECT_HANDLE_REAL_OR_REAPPLY_MASK);
+ DoCheckProc += AuraCheckProcFn(spell_warr_vigilance_AuraScript::CheckProc);
+ OnEffectProc += AuraEffectProcFn(spell_warr_vigilance_AuraScript::HandleProc, EFFECT_0, SPELL_AURA_PROC_TRIGGER_SPELL);
+ }
+
+ private:
+ Unit* _procTarget;
+ };
+
+ AuraScript* GetAuraScript() const
+ {
+ return new spell_warr_vigilance_AuraScript();
+ }
+};
+
+// 50725 Vigilance
+class spell_warr_vigilance_trigger : public SpellScriptLoader
+{
+ public:
+ spell_warr_vigilance_trigger() : SpellScriptLoader("spell_warr_vigilance_trigger") { }
+
+ class spell_warr_vigilance_trigger_SpellScript : public SpellScript
+ {
+ PrepareSpellScript(spell_warr_vigilance_trigger_SpellScript);
+
+ void HandleScript(SpellEffIndex effIndex)
+ {
+ PreventHitDefaultEffect(effIndex);
+
+ // Remove Taunt cooldown
+ if (Player* target = GetHitPlayer())
+ target->RemoveSpellCooldown(SPELL_WARRIOR_TAUNT, true);
+ }
+
+ void Register()
+ {
+ OnEffectHitTarget += SpellEffectFn(spell_warr_vigilance_trigger_SpellScript::HandleScript, EFFECT_0, SPELL_EFFECT_SCRIPT_EFFECT);
+ }
+ };
+
+ SpellScript* GetSpellScript() const
+ {
+ return new spell_warr_vigilance_trigger_SpellScript();
+ }
+};
+
void AddSC_warrior_spell_scripts()
{
new spell_warr_bloodthirst();
new spell_warr_bloodthirst_heal();
new spell_warr_charge();
new spell_warr_concussion_blow();
+ new spell_warr_damage_shield();
new spell_warr_deep_wounds();
new spell_warr_execute();
+ new spell_warr_improved_spell_reflection();
+ new spell_warr_intimidating_shout();
new spell_warr_last_stand();
+ new spell_warr_overpower();
+ new spell_warr_rend();
+ new spell_warr_shattering_throw();
new spell_warr_slam();
+ new spell_warr_sweeping_strikes();
+ new spell_warr_vigilance();
+ new spell_warr_vigilance_trigger();
}
diff --git a/src/server/shared/CMakeLists.txt b/src/server/shared/CMakeLists.txt
index 86d0cbf613b..01ccf648b31 100644
--- a/src/server/shared/CMakeLists.txt
+++ b/src/server/shared/CMakeLists.txt
@@ -50,6 +50,7 @@ set(shared_STAT_SRCS
include_directories(
${CMAKE_BINARY_DIR}
+ ${CMAKE_SOURCE_DIR}/dep/recastnavigation/Detour
${CMAKE_SOURCE_DIR}/dep/SFMT
${CMAKE_SOURCE_DIR}/dep/sockets/include
${CMAKE_SOURCE_DIR}/dep/utf8cpp
diff --git a/src/server/shared/Database/DatabaseWorkerPool.h b/src/server/shared/Database/DatabaseWorkerPool.h
index 34b7c5083e3..9f93e99ab26 100644
--- a/src/server/shared/Database/DatabaseWorkerPool.h
+++ b/src/server/shared/Database/DatabaseWorkerPool.h
@@ -31,6 +31,9 @@
#include "QueryHolder.h"
#include "AdhocStatement.h"
+#define MIN_MYSQL_SERVER_VERSION 50100u
+#define MIN_MYSQL_CLIENT_VERSION 50100u
+
class PingOperation : public SQLOperation
{
//! Operation for idle delaythreads
@@ -53,6 +56,7 @@ class DatabaseWorkerPool
_connections.resize(IDX_SIZE);
WPFatal (mysql_thread_safe(), "Used MySQL library isn't thread-safe.");
+ WPFatal (mysql_get_client_version() >= MIN_MYSQL_CLIENT_VERSION, "TrinityCore does not support MySQL versions below 5.1");
}
~DatabaseWorkerPool()
@@ -73,6 +77,7 @@ class DatabaseWorkerPool
{
T* t = new T(_queue, _connectionInfo);
res &= t->Open();
+ WPFatal (mysql_get_server_version(t->GetHandle()) >= MIN_MYSQL_SERVER_VERSION, "TrinityCore does not support MySQL versions below 5.1");
_connections[IDX_ASYNC][i] = t;
++_connectionCount[IDX_ASYNC];
}
diff --git a/src/server/shared/Database/Implementation/CharacterDatabase.cpp b/src/server/shared/Database/Implementation/CharacterDatabase.cpp
index 64110c8a8ce..2bf1c26af0c 100644
--- a/src/server/shared/Database/Implementation/CharacterDatabase.cpp
+++ b/src/server/shared/Database/Implementation/CharacterDatabase.cpp
@@ -101,6 +101,7 @@ void CharacterDatabaseConnection::DoPrepareStatements()
PrepareStatement(CHAR_SEL_CHARACTER_SPELLCOOLDOWNS, "SELECT spell, item, time FROM character_spell_cooldown WHERE guid = ?", CONNECTION_ASYNC);
PrepareStatement(CHAR_SEL_CHARACTER_DECLINEDNAMES, "SELECT genitive, dative, accusative, instrumental, prepositional FROM character_declinedname WHERE guid = ?", CONNECTION_ASYNC);
PrepareStatement(CHAR_SEL_GUILD_MEMBER, "SELECT guildid, rank FROM guild_member WHERE guid = ?", CONNECTION_BOTH);
+ PrepareStatement(CHAR_SEL_GUILD_MEMBER_EXTENDED, "SELECT g.guildid, g.name, gm.rank, gr.rname, gm.pnote, gm.offnote FROM guild g JOIN guild_member gm ON g.guildid = gm.guildid JOIN guild_rank gr ON g.guildid = gr.guildid WHERE gm.guid = ?", CONNECTION_BOTH);
PrepareStatement(CHAR_SEL_CHARACTER_ACHIEVEMENTS, "SELECT achievement, date FROM character_achievement WHERE guid = ?", CONNECTION_ASYNC);
PrepareStatement(CHAR_SEL_CHARACTER_CRITERIAPROGRESS, "SELECT criteria, counter, date FROM character_achievement_progress WHERE guid = ?", CONNECTION_ASYNC);
PrepareStatement(CHAR_SEL_CHARACTER_EQUIPMENTSETS, "SELECT setguid, setindex, name, iconname, ignore_mask, item0, item1, item2, item3, item4, item5, item6, item7, item8, "
diff --git a/src/server/shared/Database/Implementation/CharacterDatabase.h b/src/server/shared/Database/Implementation/CharacterDatabase.h
index 74b56b1a437..98e9f6f93ad 100755
--- a/src/server/shared/Database/Implementation/CharacterDatabase.h
+++ b/src/server/shared/Database/Implementation/CharacterDatabase.h
@@ -105,6 +105,7 @@ enum CharacterDatabaseStatements
CHAR_SEL_CHARACTER_SPELLCOOLDOWNS,
CHAR_SEL_CHARACTER_DECLINEDNAMES,
CHAR_SEL_GUILD_MEMBER,
+ CHAR_SEL_GUILD_MEMBER_EXTENDED,
CHAR_SEL_CHARACTER_ARENAINFO,
CHAR_SEL_CHARACTER_ACHIEVEMENTS,
CHAR_SEL_CHARACTER_CRITERIAPROGRESS,
diff --git a/src/server/shared/Database/Implementation/LoginDatabase.cpp b/src/server/shared/Database/Implementation/LoginDatabase.cpp
index 70d509af6fe..3fc6649bd4d 100644
--- a/src/server/shared/Database/Implementation/LoginDatabase.cpp
+++ b/src/server/shared/Database/Implementation/LoginDatabase.cpp
@@ -22,7 +22,7 @@ void LoginDatabaseConnection::DoPrepareStatements()
if (!m_reconnecting)
m_stmts.resize(MAX_LOGINDATABASE_STATEMENTS);
- PrepareStatement(LOGIN_SEL_REALMLIST, "SELECT id, name, address, port, icon, flag, timezone, allowedSecurityLevel, population, gamebuild FROM realmlist WHERE flag <> 3 ORDER BY name", CONNECTION_SYNCH);
+ PrepareStatement(LOGIN_SEL_REALMLIST, "SELECT id, name, address, localAddress, localSubnetMask, port, icon, flag, timezone, allowedSecurityLevel, population, gamebuild FROM realmlist WHERE flag <> 3 ORDER BY name", CONNECTION_SYNCH);
PrepareStatement(LOGIN_DEL_EXPIRED_IP_BANS, "DELETE FROM ip_banned WHERE unbandate<>bandate AND unbandate<=UNIX_TIMESTAMP()", CONNECTION_ASYNC);
PrepareStatement(LOGIN_UPD_EXPIRED_ACCOUNT_BANS, "UPDATE account_banned SET active = 0 WHERE active = 1 AND unbandate<>bandate AND unbandate<=UNIX_TIMESTAMP()", CONNECTION_ASYNC);
PrepareStatement(LOGIN_SEL_IP_BANNED, "SELECT * FROM ip_banned WHERE ip = ?", CONNECTION_SYNCH);
diff --git a/src/server/shared/Database/Implementation/WorldDatabase.cpp b/src/server/shared/Database/Implementation/WorldDatabase.cpp
index 56e164b2ef1..899ed51da0d 100644
--- a/src/server/shared/Database/Implementation/WorldDatabase.cpp
+++ b/src/server/shared/Database/Implementation/WorldDatabase.cpp
@@ -60,7 +60,7 @@ void WorldDatabaseConnection::DoPrepareStatements()
PrepareStatement(WORLD_UPD_WAYPOINT_DATA_ALL_WPGUID, "UPDATE waypoint_data SET wpguid = 0", CONNECTION_ASYNC);
PrepareStatement(WORLD_SEL_WAYPOINT_DATA_BY_POS, "SELECT id, point FROM waypoint_data WHERE (abs(position_x - ?) <= ?) and (abs(position_y - ?) <= ?) and (abs(position_z - ?) <= ?)", CONNECTION_SYNCH);
PrepareStatement(WORLD_SEL_WAYPOINT_DATA_WPGUID_BY_ID, "SELECT wpguid FROM waypoint_data WHERE id = ? and wpguid <> 0", CONNECTION_SYNCH);
- PrepareStatement(WOLRD_SEL_WAYPOINT_DATA_ACTION, "SELECT DISTINCT action FROM waypoint_data", CONNECTION_SYNCH);
+ PrepareStatement(WORLD_SEL_WAYPOINT_DATA_ACTION, "SELECT DISTINCT action FROM waypoint_data", CONNECTION_SYNCH);
PrepareStatement(WORLD_SEL_WAYPOINT_SCRIPTS_MAX_ID, "SELECT MAX(guid) FROM waypoint_scripts", CONNECTION_SYNCH);
PrepareStatement(WORLD_INS_CREATURE_ADDON, "INSERT INTO creature_addon(guid, path_id) VALUES (?, ?)", CONNECTION_ASYNC);
PrepareStatement(WORLD_UPD_CREATURE_ADDON_PATH, "UPDATE creature_addon SET path_id = ? WHERE guid = ?", CONNECTION_ASYNC);
diff --git a/src/server/shared/Database/Implementation/WorldDatabase.h b/src/server/shared/Database/Implementation/WorldDatabase.h
index 30cc45c535a..032baf29dd9 100644
--- a/src/server/shared/Database/Implementation/WorldDatabase.h
+++ b/src/server/shared/Database/Implementation/WorldDatabase.h
@@ -80,7 +80,7 @@ enum WorldDatabaseStatements
WORLD_SEL_WAYPOINT_DATA_MAX_POINT,
WORLD_SEL_WAYPOINT_DATA_BY_POS,
WORLD_SEL_WAYPOINT_DATA_WPGUID_BY_ID,
- WOLRD_SEL_WAYPOINT_DATA_ACTION,
+ WORLD_SEL_WAYPOINT_DATA_ACTION,
WORLD_SEL_WAYPOINT_SCRIPTS_MAX_ID,
WORLD_UPD_CREATURE_ADDON_PATH,
WORLD_INS_CREATURE_ADDON,
diff --git a/src/server/shared/Debugging/Errors.h b/src/server/shared/Debugging/Errors.h
index 3d10740f149..10e94634e9a 100644
--- a/src/server/shared/Debugging/Errors.h
+++ b/src/server/shared/Debugging/Errors.h
@@ -24,7 +24,7 @@
#include <ace/Stack_Trace.h>
#include <ace/OS_NS_unistd.h>
-#define WPAssert(assertion) { if (!(assertion)) { ACE_Stack_Trace st; sLog->outError(LOG_FILTER_GENERAL, "\n%s:%i in %s ASSERTION FAILED:\n %s\n%s\n", __FILE__, __LINE__, __FUNCTION__, #assertion, st.c_str()); *((volatile int*)NULL) = 0; } }
+#define WPAssert(assertion) { if (!(assertion)) { ACE_Stack_Trace st; fprintf(stderr, "\n%s:%i in %s ASSERTION FAILED:\n %s\n%s\n", __FILE__, __LINE__, __FUNCTION__, #assertion, st.c_str()); *((volatile int*)NULL) = 0; } }
#define WPError(assertion, errmsg) { if (!(assertion)) { sLog->outError(LOG_FILTER_GENERAL, "%\n%s:%i in %s ERROR:\n %s\n", __FILE__, __LINE__, __FUNCTION__, (char *)errmsg); *((volatile int*)NULL) = 0; } }
#define WPWarning(assertion, errmsg) { if (!(assertion)) { sLog->outError(LOG_FILTER_GENERAL, "\n%s:%i in %s WARNING:\n %s\n", __FILE__, __LINE__, __FUNCTION__, (char *)errmsg); } }
#define WPFatal(assertion, errmsg) { if (!(assertion)) { sLog->outError(LOG_FILTER_GENERAL, "\n%s:%i in %s FATAL ERROR:\n %s\n", __FILE__, __LINE__, __FUNCTION__, (char *)errmsg); ACE_OS::sleep(10); *((volatile int*)NULL) = 0; } }
diff --git a/src/server/shared/Logging/Appender.h b/src/server/shared/Logging/Appender.h
index a8854a8abc6..08628948b90 100644
--- a/src/server/shared/Logging/Appender.h
+++ b/src/server/shared/Logging/Appender.h
@@ -123,6 +123,12 @@ struct LogMessage
std::string prefix;
std::string param1;
time_t mtime;
+
+ ///@ Returns size of the log message content in bytes
+ uint32 Size() const
+ {
+ return prefix.size() + text.size();
+ }
};
class Appender
diff --git a/src/server/shared/Logging/AppenderFile.cpp b/src/server/shared/Logging/AppenderFile.cpp
index 8189237bb4e..25141815de6 100644
--- a/src/server/shared/Logging/AppenderFile.cpp
+++ b/src/server/shared/Logging/AppenderFile.cpp
@@ -18,58 +18,76 @@
#include "AppenderFile.h"
#include "Common.h"
-AppenderFile::AppenderFile(uint8 id, std::string const& name, LogLevel level, const char* _filename, const char* _logDir, const char* _mode, AppenderFlags _flags)
- : Appender(id, name, APPENDER_FILE, level, _flags)
- , filename(_filename)
- , logDir(_logDir)
- , mode(_mode)
+AppenderFile::AppenderFile(uint8 id, std::string const& name, LogLevel level, const char* _filename, const char* _logDir, const char* _mode, AppenderFlags _flags, uint64 fileSize):
+ Appender(id, name, APPENDER_FILE, level, _flags),
+ filename(_filename),
+ logDir(_logDir),
+ mode(_mode),
+ maxFileSize(fileSize),
+ fileSize(0),
+ logfile(NULL)
{
dynamicName = std::string::npos != filename.find("%s");
backup = _flags & APPENDER_FLAGS_MAKE_FILE_BACKUP;
- logfile = !dynamicName ? OpenFile(_filename, _mode, backup) : NULL;
+ logfile = !dynamicName ? OpenFile(_filename, _mode, mode == "w" && backup) : NULL;
}
AppenderFile::~AppenderFile()
{
- if (logfile)
- {
- fclose(logfile);
- logfile = NULL;
- }
+ CloseFile();
}
void AppenderFile::_write(LogMessage const& message)
{
+ bool exceedMaxSize = maxFileSize > 0 && (fileSize + message.Size()) > maxFileSize;
+
if (dynamicName)
{
char namebuf[TRINITY_PATH_MAX];
snprintf(namebuf, TRINITY_PATH_MAX, filename.c_str(), message.param1.c_str());
- logfile = OpenFile(namebuf, mode, backup);
+ logfile = OpenFile(namebuf, mode, backup || exceedMaxSize);
}
+ else if (exceedMaxSize)
+ logfile = OpenFile(filename, "w", true);
- if (logfile)
- {
- fprintf(logfile, "%s%s", message.prefix.c_str(), message.text.c_str());
- fflush(logfile);
+ if (!logfile)
+ return;
- if (dynamicName)
- {
- fclose(logfile);
- logfile = NULL;
- }
- }
+ fprintf(logfile, "%s%s", message.prefix.c_str(), message.text.c_str());
+ fflush(logfile);
+ fileSize += message.Size();
+
+ if (dynamicName)
+ CloseFile();
}
FILE* AppenderFile::OpenFile(std::string const &filename, std::string const &mode, bool backup)
{
- if (mode == "w" && backup)
+ std::string fullName(logDir + filename);
+ if (backup)
{
- std::string newName(filename);
+ CloseFile();
+ std::string newName(fullName);
newName.push_back('.');
newName.append(LogMessage::getTimeStr(time(NULL)));
- rename(filename.c_str(), newName.c_str()); // no error handling... if we couldn't make a backup, just ignore
+ rename(fullName.c_str(), newName.c_str()); // no error handling... if we couldn't make a backup, just ignore
}
- return fopen((logDir + filename).c_str(), mode.c_str());
+ if (FILE* ret = fopen(fullName.c_str(), mode.c_str()))
+ {
+ fileSize = ftell(ret);
+ return ret;
+ }
+
+ return NULL;
+}
+
+void AppenderFile::CloseFile()
+{
+ if (logfile)
+ {
+ fclose(logfile);
+ logfile = NULL;
+ }
}
diff --git a/src/server/shared/Logging/AppenderFile.h b/src/server/shared/Logging/AppenderFile.h
index a3fe285cc7d..c15974799e1 100644
--- a/src/server/shared/Logging/AppenderFile.h
+++ b/src/server/shared/Logging/AppenderFile.h
@@ -23,11 +23,12 @@
class AppenderFile: public Appender
{
public:
- AppenderFile(uint8 _id, std::string const& _name, LogLevel level, const char* filename, const char* logDir, const char* mode, AppenderFlags flags);
+ AppenderFile(uint8 _id, std::string const& _name, LogLevel level, const char* filename, const char* logDir, const char* mode, AppenderFlags flags, uint64 maxSize);
~AppenderFile();
FILE* OpenFile(std::string const& _name, std::string const& _mode, bool _backup);
private:
+ void CloseFile();
void _write(LogMessage const& message);
FILE* logfile;
std::string filename;
@@ -35,6 +36,8 @@ class AppenderFile: public Appender
std::string mode;
bool dynamicName;
bool backup;
+ uint64 maxFileSize;
+ uint64 fileSize;
};
#endif
diff --git a/src/server/shared/Logging/Log.cpp b/src/server/shared/Logging/Log.cpp
index 96c72b5eb74..920ce4ce570 100644
--- a/src/server/shared/Logging/Log.cpp
+++ b/src/server/shared/Logging/Log.cpp
@@ -89,8 +89,9 @@ void Log::CreateAppenderFromConfig(const char* name)
options = ConfigMgr::GetStringDefault(options.c_str(), "");
Tokenizer tokens(options, ',');
Tokenizer::const_iterator iter = tokens.begin();
+ uint8 size = tokens.size();
- if (tokens.size() < 2)
+ if (size < 2)
{
fprintf(stderr, "Log::CreateAppenderFromConfig: Wrong configuration for appender %s. Config line: %s\n", name, options.c_str());
return;
@@ -98,16 +99,15 @@ void Log::CreateAppenderFromConfig(const char* name)
AppenderFlags flags = APPENDER_FLAGS_NONE;
AppenderType type = AppenderType(atoi(*iter));
- ++iter;
- LogLevel level = LogLevel(atoi(*iter));
+ LogLevel level = LogLevel(atoi(*(++iter)));
if (level > LOG_LEVEL_FATAL)
{
fprintf(stderr, "Log::CreateAppenderFromConfig: Wrong Log Level %d for appender %s\n", level, name);
return;
}
- if (++iter != tokens.end())
- flags = AppenderFlags(atoi(*iter));
+ if (size > 2)
+ flags = AppenderFlags(atoi(*(++iter)));
switch (type)
{
@@ -115,8 +115,8 @@ void Log::CreateAppenderFromConfig(const char* name)
{
AppenderConsole* appender = new AppenderConsole(NextAppenderId(), name, level, flags);
appenders[appender->getId()] = appender;
- if (++iter != tokens.end())
- appender->InitColors(*iter);
+ if (size > 3)
+ appender->InitColors(*(++iter));
//fprintf(stdout, "Log::CreateAppenderFromConfig: Created Appender %s (%u), Type CONSOLE, Mask %u\n", appender->getName().c_str(), appender->getId(), appender->getLogLevel()); // DEBUG - RemoveMe
break;
}
@@ -125,16 +125,16 @@ void Log::CreateAppenderFromConfig(const char* name)
std::string filename;
std::string mode = "a";
- if (++iter == tokens.end())
+ if (size < 4)
{
fprintf(stderr, "Log::CreateAppenderFromConfig: Missing file name for appender %s\n", name);
return;
}
- filename = *iter;
+ filename = *(++iter);
- if (++iter != tokens.end())
- mode = *iter;
+ if (size > 4)
+ mode = *(++iter);
if (flags & APPENDER_FLAGS_USE_TIMESTAMP)
{
@@ -145,8 +145,12 @@ void Log::CreateAppenderFromConfig(const char* name)
filename += m_logsTimestamp;
}
+ uint64 maxFileSize = 0;
+ if (size > 5)
+ maxFileSize = atoi(*(++iter));
+
uint8 id = NextAppenderId();
- appenders[id] = new AppenderFile(id, name, level, filename.c_str(), m_logsDir.c_str(), mode.c_str(), flags);
+ appenders[id] = new AppenderFile(id, name, level, filename.c_str(), m_logsDir.c_str(), mode.c_str(), flags, maxFileSize);
//fprintf(stdout, "Log::CreateAppenderFromConfig: Created Appender %s (%u), Type FILE, Mask %u, File %s, Mode %s\n", name, id, level, filename.c_str(), mode.c_str()); // DEBUG - RemoveMe
break;
}
diff --git a/src/server/shared/Memory.h b/src/server/shared/Memory.h
new file mode 100644
index 00000000000..25533638915
--- /dev/null
+++ b/src/server/shared/Memory.h
@@ -0,0 +1,19 @@
+
+
+#ifndef _MEMORY_H
+#define _MEMORY_H
+
+#include "DetourAlloc.h"
+
+// memory management
+inline void* dtCustomAlloc(int size, dtAllocHint /*hint*/)
+{
+ return (void*)new unsigned char[size];
+}
+
+inline void dtCustomFree(void* ptr)
+{
+ delete [] (unsigned char*)ptr;
+}
+
+#endif \ No newline at end of file
diff --git a/src/server/shared/Utilities/Util.cpp b/src/server/shared/Utilities/Util.cpp
index 8b6862fa760..32ff396e1c1 100644
--- a/src/server/shared/Utilities/Util.cpp
+++ b/src/server/shared/Utilities/Util.cpp
@@ -22,7 +22,6 @@
#include "SFMT.h"
#include "Errors.h" // for ASSERT
#include <ace/TSS_T.h>
-#include <ace/INET_Addr.h>
typedef ACE_TSS<SFMTRand> SFMTRandTSS;
static SFMTRandTSS sfmtRand;
@@ -239,6 +238,21 @@ bool IsIPAddress(char const* ipaddress)
return inet_addr(ipaddress) != INADDR_NONE;
}
+std::string GetAddressString(ACE_INET_Addr const& addr)
+{
+ char buf[ACE_MAX_FULLY_QUALIFIED_NAME_LEN + 16];
+ addr.addr_to_string(buf, ACE_MAX_FULLY_QUALIFIED_NAME_LEN + 16);
+ return buf;
+}
+
+bool IsIPAddrInNetwork(ACE_INET_Addr const& net, ACE_INET_Addr const& addr, ACE_INET_Addr const& subnetMask)
+{
+ uint32 mask = subnetMask.get_ip_address();
+ if ((net.get_ip_address() & mask) == (addr.get_ip_address() & mask))
+ return true;
+ return false;
+}
+
/// create PID file
uint32 CreatePIDFile(const std::string& filename)
{
diff --git a/src/server/shared/Utilities/Util.h b/src/server/shared/Utilities/Util.h
index 5a85e103e2a..5d1ce862d21 100644
--- a/src/server/shared/Utilities/Util.h
+++ b/src/server/shared/Utilities/Util.h
@@ -25,6 +25,7 @@
#include <string>
#include <vector>
#include <list>
+#include <ace/INET_Addr.h>
// Searcher for map of structs
template<typename T, class S> struct Finder
@@ -343,6 +344,13 @@ void utf8printf(FILE* out, const char *str, ...);
void vutf8printf(FILE* out, const char *str, va_list* ap);
bool IsIPAddress(char const* ipaddress);
+
+/// Checks if address belongs to the a network with specified submask
+bool IsIPAddrInNetwork(ACE_INET_Addr const& net, ACE_INET_Addr const& addr, ACE_INET_Addr const& subnetMask);
+
+/// Transforms ACE_INET_Addr address into string format "dotted_ip:port"
+std::string GetAddressString(ACE_INET_Addr const& addr);
+
uint32 CreatePIDFile(const std::string& filename);
std::string ByteArrayToHexStr(uint8 const* bytes, uint32 length, bool reverse = false);
diff --git a/src/server/worldserver/CMakeLists.txt b/src/server/worldserver/CMakeLists.txt
index 81442a28da2..16b48287ead 100644
--- a/src/server/worldserver/CMakeLists.txt
+++ b/src/server/worldserver/CMakeLists.txt
@@ -39,6 +39,7 @@ endif()
include_directories(
${CMAKE_BINARY_DIR}
${CMAKE_SOURCE_DIR}/dep/g3dlite/include
+ ${CMAKE_SOURCE_DIR}/dep/recastnavigation/Detour
${CMAKE_SOURCE_DIR}/dep/gsoap
${CMAKE_SOURCE_DIR}/dep/sockets/include
${CMAKE_SOURCE_DIR}/dep/SFMT
@@ -162,6 +163,7 @@ target_link_libraries(worldserver
collision
g3dlib
gsoap
+ Detour
${JEMALLOC_LIBRARY}
${READLINE_LIBRARY}
${TERMCAP_LIBRARY}
diff --git a/src/server/worldserver/worldserver.conf.dist b/src/server/worldserver/worldserver.conf.dist
index f241b4d1b23..40bd2a443f6 100644
--- a/src/server/worldserver/worldserver.conf.dist
+++ b/src/server/worldserver/worldserver.conf.dist
@@ -270,6 +270,14 @@ PlayerSave.Stats.MinLevel = 0
PlayerSave.Stats.SaveOnlyOnLogout = 1
#
+# mmap.enablePathFinding
+# Description: Enable/Disable pathfinding using mmaps - experimental
+# Default: 0 - (Disabled)
+# 1 - (Enabled)
+
+mmap.enablePathFinding = 0
+
+#
# vmap.enableLOS
# vmap.enableHeight
# Description: VMmap support for line of sight and height calculation.
@@ -281,14 +289,6 @@ vmap.enableLOS = 1
vmap.enableHeight = 1
#
-# vmap.petLOS
-# Description: Check line of sight for pets, to avoid them attacking through walls.
-# Default: 1 - (Enabled, each pet attack will be checked for line of sight)
-# 0 - (Disabled, somewhat less CPU usage)
-
-vmap.petLOS = 1
-
-#
# vmap.enableIndoorCheck
# Description: VMap based indoor check to remove outdoor-only auras (mounts etc.).
# Default: 1 - (Enabled)
@@ -2620,6 +2620,14 @@ PlayerDump.DisallowPaths = 1
PlayerDump.DisallowOverwrite = 1
#
+# UI.ShowQuestLevelsInDialogs
+# Description: Show quest levels next to quest titles in UI dialogs
+# Example: [13] Westfall Stew
+# Default: 0 (do not show)
+
+UI.ShowQuestLevelsInDialogs = 0
+
+#
###################################################################################################
###################################################################################################
@@ -2629,7 +2637,7 @@ PlayerDump.DisallowOverwrite = 1
# Appender config values: Given a appender "name"
# Appender.name
# Description: Defines 'where to log'
-# Format: Type,LogLevel,Flags,optional1,optional2
+# Format: Type,LogLevel,Flags,optional1,optional2,optional3
#
# Type
# 0 - (None)
@@ -2680,6 +2688,13 @@ PlayerDump.DisallowOverwrite = 1
# a - (Append)
# w - (Overwrite)
#
+# MaxFileSize: Maximum file size of the log file before creating a new log file
+# (read as optional3 if Type = File)
+# Size is measured in bytes expressed in a 64-bit unsigned integer.
+# Maximum value is 4294967295 (4 gb). Leave blank for no limit.
+# NOTE: Does not work with dynamic filenames.
+# Example: 536870912 (512 mb)
+#
Appender.Console=1,3,0
Appender.Server=2,2,0,Server.log,w