aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/common/Collision/DynamicTree.cpp3
-rw-r--r--src/common/Collision/Management/IVMapManager.h12
-rw-r--r--src/common/Collision/Management/VMapManager2.cpp11
-rw-r--r--src/common/Collision/Management/VMapManager2.h6
-rw-r--r--src/common/Collision/Maps/MapTree.cpp48
-rw-r--r--src/common/Collision/Maps/MapTree.h8
-rw-r--r--src/common/Collision/Models/GameObjectModel.cpp4
-rw-r--r--src/common/Collision/Models/GameObjectModel.h3
-rw-r--r--src/common/Collision/Models/ModelIgnoreFlags.h34
-rw-r--r--src/common/Collision/Models/ModelInstance.cpp4
-rw-r--r--src/common/Collision/Models/ModelInstance.h3
-rw-r--r--src/common/Collision/Models/WorldModel.cpp12
-rw-r--r--src/common/Collision/Models/WorldModel.h4
-rw-r--r--src/common/Utilities/Util.h4
-rw-r--r--src/server/bnetserver/Server/Session.cpp8
-rw-r--r--src/server/database/Database/Implementation/CharacterDatabase.cpp1
-rw-r--r--src/server/database/Database/Implementation/CharacterDatabase.h1
-rw-r--r--src/server/game/AI/CoreAI/PetAI.cpp5
-rw-r--r--src/server/game/AI/CreatureAI.cpp1
-rw-r--r--src/server/game/AI/SmartScripts/SmartScript.cpp8
-rw-r--r--src/server/game/AI/SmartScripts/SmartScriptMgr.h3
-rw-r--r--src/server/game/Accounts/RBAC.h2
-rw-r--r--src/server/game/Achievements/AchievementMgr.cpp74
-rw-r--r--src/server/game/Combat/HostileRefManager.cpp20
-rw-r--r--src/server/game/Combat/HostileRefManager.h3
-rw-r--r--src/server/game/DataStores/DBCEnums.h2
-rw-r--r--src/server/game/Entities/Creature/Creature.cpp16
-rw-r--r--src/server/game/Entities/Creature/CreatureData.h3
-rw-r--r--src/server/game/Entities/Creature/GossipDef.cpp2
-rw-r--r--src/server/game/Entities/GameObject/GameObjectData.h1
-rw-r--r--src/server/game/Entities/Object/Object.cpp18
-rw-r--r--src/server/game/Entities/Object/Object.h5
-rw-r--r--src/server/game/Entities/Pet/Pet.cpp6
-rw-r--r--src/server/game/Entities/Player/Player.cpp37
-rw-r--r--src/server/game/Entities/Player/Player.h1
-rw-r--r--src/server/game/Entities/Unit/Unit.cpp25
-rw-r--r--src/server/game/Entities/Vehicle/Vehicle.cpp13
-rw-r--r--src/server/game/Entities/Vehicle/VehicleDefines.h2
-rw-r--r--src/server/game/Globals/ObjectMgr.cpp8
-rw-r--r--src/server/game/Groups/Group.cpp8
-rw-r--r--src/server/game/Handlers/ChatHandler.cpp2
-rw-r--r--src/server/game/Handlers/MovementHandler.cpp7
-rw-r--r--src/server/game/Handlers/PetHandler.cpp8
-rw-r--r--src/server/game/Handlers/TaxiHandler.cpp1
-rw-r--r--src/server/game/Instances/InstanceScript.cpp8
-rw-r--r--src/server/game/Loot/Loot.cpp8
-rw-r--r--src/server/game/Loot/Loot.h1
-rw-r--r--src/server/game/Maps/Map.cpp23
-rw-r--r--src/server/game/Maps/Map.h3
-rw-r--r--src/server/game/Miscellaneous/Language.h3
-rw-r--r--src/server/game/Movement/MovementGenerators/FleeingMovementGenerator.cpp2
-rwxr-xr-xsrc/server/game/Movement/MovementGenerators/WaypointMovementGenerator.cpp3
-rw-r--r--src/server/game/Scripting/ScriptMgr.cpp3
-rw-r--r--src/server/game/Spells/Spell.cpp36
-rw-r--r--src/server/game/Spells/Spell.h1
-rw-r--r--src/server/game/Spells/SpellInfo.h2
-rw-r--r--src/server/game/Spells/SpellMgr.cpp39
-rw-r--r--src/server/game/World/World.cpp12
-rw-r--r--src/server/game/World/World.h2
-rw-r--r--src/server/scripts/Commands/cs_character.cpp81
-rw-r--r--src/server/scripts/Commands/cs_npc.cpp3
-rw-r--r--src/server/scripts/Northrend/ChamberOfAspects/RubySanctum/boss_saviana_ragefire.cpp52
-rw-r--r--src/server/scripts/Northrend/IcecrownCitadel/boss_blood_prince_council.cpp4
-rw-r--r--src/server/worldserver/worldserver.conf.dist9
64 files changed, 551 insertions, 191 deletions
diff --git a/src/common/Collision/DynamicTree.cpp b/src/common/Collision/DynamicTree.cpp
index 2fbdfe05b52..0b525fc1ab6 100644
--- a/src/common/Collision/DynamicTree.cpp
+++ b/src/common/Collision/DynamicTree.cpp
@@ -21,6 +21,7 @@
#include "GameObjectModel.h"
#include "Log.h"
#include "MapTree.h"
+#include "ModelIgnoreFlags.h"
#include "ModelInstance.h"
#include "RegularGrid.h"
#include "Timer.h"
@@ -142,7 +143,7 @@ struct DynamicTreeIntersectionCallback
bool operator()(G3D::Ray const& r, GameObjectModel const& obj, float& distance)
{
- _didHit = obj.intersectRay(r, distance, true, _phaseShift);
+ _didHit = obj.intersectRay(r, distance, true, _phaseShift, VMAP::ModelIgnoreFlags::Nothing);
return _didHit;
}
diff --git a/src/common/Collision/Management/IVMapManager.h b/src/common/Collision/Management/IVMapManager.h
index cec5657f5ed..d8073e86b78 100644
--- a/src/common/Collision/Management/IVMapManager.h
+++ b/src/common/Collision/Management/IVMapManager.h
@@ -21,6 +21,7 @@
#include <string>
#include "Define.h"
+#include "ModelIgnoreFlags.h"
//===========================================================
@@ -38,6 +39,13 @@ namespace VMAP
VMAP_LOAD_RESULT_IGNORED
};
+ enum class LoadResult : uint8
+ {
+ Success,
+ FileNotFound,
+ VersionMismatch
+ };
+
#define VMAP_INVALID_HEIGHT -100000.0f // for check
#define VMAP_INVALID_HEIGHT_VALUE -200000.0f // real assigned value in unknown height case
@@ -55,12 +63,12 @@ namespace VMAP
virtual int loadMap(const char* pBasePath, unsigned int pMapId, int x, int y) = 0;
- virtual bool existsMap(const char* pBasePath, unsigned int pMapId, int x, int y) = 0;
+ virtual LoadResult existsMap(const char* pBasePath, unsigned int pMapId, int x, int y) = 0;
virtual void unloadMap(unsigned int pMapId, int x, int y) = 0;
virtual void unloadMap(unsigned int pMapId) = 0;
- virtual bool isInLineOfSight(unsigned int pMapId, float x1, float y1, float z1, float x2, float y2, float z2) = 0;
+ virtual bool isInLineOfSight(unsigned int pMapId, float x1, float y1, float z1, float x2, float y2, float z2, ModelIgnoreFlags ignoreFlags) = 0;
virtual float getHeight(unsigned int pMapId, float x, float y, float z, float maxSearchDist) = 0;
/**
test if we hit an object. return true if we hit one. rx, ry, rz will hold the hit position or the dest position, if no intersection was found
diff --git a/src/common/Collision/Management/VMapManager2.cpp b/src/common/Collision/Management/VMapManager2.cpp
index 163769f33a9..0ad872fe6c1 100644
--- a/src/common/Collision/Management/VMapManager2.cpp
+++ b/src/common/Collision/Management/VMapManager2.cpp
@@ -191,7 +191,7 @@ namespace VMAP
}
}
- bool VMapManager2::isInLineOfSight(unsigned int mapId, float x1, float y1, float z1, float x2, float y2, float z2)
+ bool VMapManager2::isInLineOfSight(unsigned int mapId, float x1, float y1, float z1, float x2, float y2, float z2, ModelIgnoreFlags ignoreFlags)
{
if (!isLineOfSightCalcEnabled() || IsVMAPDisabledForPtr(mapId, VMAP_DISABLE_LOS))
return true;
@@ -202,7 +202,7 @@ namespace VMAP
Vector3 pos1 = convertPositionToInternalRep(x1, y1, z1);
Vector3 pos2 = convertPositionToInternalRep(x2, y2, z2);
if (pos1 != pos2)
- return instanceTree->second->isInLineOfSight(pos1, pos2);
+ return instanceTree->second->isInLineOfSight(pos1, pos2, ignoreFlags);
}
return true;
@@ -306,7 +306,7 @@ namespace VMAP
return false;
}
- WorldModel* VMapManager2::acquireModelInstance(const std::string& basepath, const std::string& filename)
+ WorldModel* VMapManager2::acquireModelInstance(const std::string& basepath, const std::string& filename, uint32 flags/* Only used when creating the model */)
{
//! Critical section, thread safe access to iLoadedModelFiles
std::lock_guard<std::mutex> lock(LoadedModelFilesLock);
@@ -322,6 +322,9 @@ namespace VMAP
return NULL;
}
TC_LOG_DEBUG("maps", "VMapManager2: loading file '%s%s'", basepath.c_str(), filename.c_str());
+
+ worldmodel->Flags = flags;
+
model = iLoadedModelFiles.insert(std::pair<std::string, ManagedModel>(filename, ManagedModel())).first;
model->second.setModel(worldmodel);
}
@@ -348,7 +351,7 @@ namespace VMAP
}
}
- bool VMapManager2::existsMap(const char* basePath, unsigned int mapId, int x, int y)
+ LoadResult VMapManager2::existsMap(const char* basePath, unsigned int mapId, int x, int y)
{
return StaticMapTree::CanLoadMap(std::string(basePath), mapId, x, y, this);
}
diff --git a/src/common/Collision/Management/VMapManager2.h b/src/common/Collision/Management/VMapManager2.h
index 5bb556ccf64..c48a8e985a6 100644
--- a/src/common/Collision/Management/VMapManager2.h
+++ b/src/common/Collision/Management/VMapManager2.h
@@ -111,7 +111,7 @@ namespace VMAP
void unloadMap(unsigned int mapId) override;
void unloadSingleMap(uint32 mapId);
- bool isInLineOfSight(unsigned int mapId, float x1, float y1, float z1, float x2, float y2, float z2) override ;
+ bool isInLineOfSight(unsigned int mapId, float x1, float y1, float z1, float x2, float y2, float z2, ModelIgnoreFlags ignoreFlags) override ;
/**
fill the hit pos and return true, if an object was hit
*/
@@ -123,7 +123,7 @@ namespace VMAP
bool getAreaInfo(unsigned int pMapId, float x, float y, float& z, uint32& flags, int32& adtId, int32& rootId, int32& groupId) const override;
bool GetLiquidLevel(uint32 pMapId, float x, float y, float z, uint8 reqLiquidType, float& level, float& floor, uint32& type) const override;
- WorldModel* acquireModelInstance(const std::string& basepath, const std::string& filename);
+ WorldModel* acquireModelInstance(const std::string& basepath, const std::string& filename, uint32 flags = 0);
void releaseModelInstance(const std::string& filename);
// what's the use of this? o.O
@@ -131,7 +131,7 @@ namespace VMAP
{
return getMapFileName(mapId);
}
- virtual bool existsMap(const char* basePath, unsigned int mapId, int x, int y) override;
+ virtual LoadResult existsMap(const char* basePath, unsigned int mapId, int x, int y) override;
void getInstanceMapTree(InstanceTreeMap &instanceMapTree);
diff --git a/src/common/Collision/Maps/MapTree.cpp b/src/common/Collision/Maps/MapTree.cpp
index 3ba9c860d6f..9b735061c29 100644
--- a/src/common/Collision/Maps/MapTree.cpp
+++ b/src/common/Collision/Maps/MapTree.cpp
@@ -33,14 +33,13 @@ using G3D::Vector3;
namespace VMAP
{
-
class MapRayCallback
{
public:
- MapRayCallback(ModelInstance* val): prims(val), hit(false) { }
+ MapRayCallback(ModelInstance* val, ModelIgnoreFlags ignoreFlags): prims(val), hit(false), flags(ignoreFlags) { }
bool operator()(const G3D::Ray& ray, uint32 entry, float& distance, bool pStopAtFirstHit=true)
{
- bool result = prims[entry].intersectRay(ray, distance, pStopAtFirstHit);
+ bool result = prims[entry].intersectRay(ray, distance, pStopAtFirstHit, flags);
if (result)
hit = true;
return result;
@@ -49,6 +48,7 @@ namespace VMAP
protected:
ModelInstance* prims;
bool hit;
+ ModelIgnoreFlags flags;
};
class AreaInfoCallback
@@ -142,10 +142,10 @@ namespace VMAP
Else, pMaxDist is not modified and returns false;
*/
- bool StaticMapTree::getIntersectionTime(const G3D::Ray& pRay, float &pMaxDist, bool pStopAtFirstHit) const
+ bool StaticMapTree::getIntersectionTime(const G3D::Ray& pRay, float &pMaxDist, bool pStopAtFirstHit, ModelIgnoreFlags ignoreFlags) const
{
float distance = pMaxDist;
- MapRayCallback intersectionCallBack(iTreeValues);
+ MapRayCallback intersectionCallBack(iTreeValues, ignoreFlags);
iTree.intersectRay(pRay, intersectionCallBack, distance, pStopAtFirstHit);
if (intersectionCallBack.didHit())
pMaxDist = distance;
@@ -153,7 +153,7 @@ namespace VMAP
}
//=========================================================
- bool StaticMapTree::isInLineOfSight(const Vector3& pos1, const Vector3& pos2) const
+ bool StaticMapTree::isInLineOfSight(const Vector3& pos1, const Vector3& pos2, ModelIgnoreFlags ignoreFlag) const
{
float maxDist = (pos2 - pos1).magnitude();
// return false if distance is over max float, in case of cheater teleporting to the end of the universe
@@ -167,7 +167,7 @@ namespace VMAP
return true;
// direction with length of 1
G3D::Ray ray = G3D::Ray::fromOriginAndDirection(pos1, (pos2 - pos1)/maxDist);
- if (getIntersectionTime(ray, maxDist, true))
+ if (getIntersectionTime(ray, maxDist, true, ignoreFlag))
return false;
return true;
@@ -193,7 +193,7 @@ namespace VMAP
Vector3 dir = (pPos2 - pPos1)/maxDist; // direction with length of 1
G3D::Ray ray(pPos1, dir);
float dist = maxDist;
- if (getIntersectionTime(ray, dist, false))
+ if (getIntersectionTime(ray, dist, false, ModelIgnoreFlags::Nothing))
{
pResultHitPos = pPos1 + dir * dist;
if (pModifyDist < 0)
@@ -229,7 +229,7 @@ namespace VMAP
Vector3 dir = Vector3(0, 0, -1);
G3D::Ray ray(pPos, dir); // direction with length of 1
float maxDist = maxSearchDist;
- if (getIntersectionTime(ray, maxDist, false))
+ if (getIntersectionTime(ray, maxDist, false, ModelIgnoreFlags::Nothing))
{
height = pPos.z - maxDist;
}
@@ -255,35 +255,43 @@ namespace VMAP
}
//=========================================================
-
- bool StaticMapTree::CanLoadMap(const std::string &vmapPath, uint32 mapID, uint32 tileX, uint32 tileY, VMapManager2* vm)
+ LoadResult StaticMapTree::CanLoadMap(const std::string &vmapPath, uint32 mapID, uint32 tileX, uint32 tileY, VMapManager2* vm)
{
std::string basePath = vmapPath;
if (basePath.length() > 0 && basePath[basePath.length()-1] != '/' && basePath[basePath.length()-1] != '\\')
basePath.push_back('/');
std::string fullname = basePath + VMapManager2::getMapFileName(mapID);
- bool success = true;
+
+ LoadResult result = LoadResult::Success;
+
FILE* rf = fopen(fullname.c_str(), "rb");
if (!rf)
- return false;
+ return LoadResult::FileNotFound;
char chunk[8];
if (!readChunk(rf, chunk, VMAP_MAGIC, 8))
{
fclose(rf);
- return false;
+ return LoadResult::VersionMismatch;
}
FILE* tf = OpenMapTileFile(basePath, mapID, tileX, tileY, vm).File;
if (!tf)
- success = false;
+ return LoadResult::FileNotFound;
else
{
- if (!readChunk(tf, chunk, VMAP_MAGIC, 8))
- success = false;
- fclose(tf);
+ std::string tilefile = basePath + getTileFileName(mapID, tileX, tileY);
+ FILE* tf = fopen(tilefile.c_str(), "rb");
+ if (!tf)
+ result = LoadResult::FileNotFound;
+ else
+ {
+ if (!readChunk(tf, chunk, VMAP_MAGIC, 8))
+ result = LoadResult::VersionMismatch;
+ fclose(tf);
+ }
}
fclose(rf);
- return success;
+ return result;
}
//=========================================================
@@ -371,7 +379,7 @@ namespace VMAP
if (result)
{
// acquire model instance
- WorldModel* model = vm->acquireModelInstance(iBasePath, spawn.name);
+ WorldModel* model = vm->acquireModelInstance(iBasePath, spawn.name, spawn.flags);
if (!model)
TC_LOG_ERROR("misc", "StaticMapTree::LoadMapTile() : could not acquire WorldModel pointer [%u, %u]", tileX, tileY);
diff --git a/src/common/Collision/Maps/MapTree.h b/src/common/Collision/Maps/MapTree.h
index 122f5dc63eb..df1ce431109 100644
--- a/src/common/Collision/Maps/MapTree.h
+++ b/src/common/Collision/Maps/MapTree.h
@@ -28,6 +28,8 @@ namespace VMAP
class ModelInstance;
class GroupModel;
class VMapManager2;
+ enum class LoadResult : uint8;
+ enum class ModelIgnoreFlags : uint32;
struct TC_COMMON_API LocationInfo
{
@@ -65,18 +67,18 @@ namespace VMAP
private:
static TileFileOpenResult OpenMapTileFile(std::string const& basePath, uint32 mapID, uint32 tileX, uint32 tileY, VMapManager2* vm);
- bool getIntersectionTime(const G3D::Ray& pRay, float &pMaxDist, bool pStopAtFirstHit) const;
+ bool getIntersectionTime(const G3D::Ray& pRay, float &pMaxDist, bool pStopAtFirstHit, ModelIgnoreFlags ignoreFlags) const;
//bool containsLoadedMapTile(unsigned int pTileIdent) const { return(iLoadedMapTiles.containsKey(pTileIdent)); }
public:
static std::string getTileFileName(uint32 mapID, uint32 tileX, uint32 tileY);
static uint32 packTileID(uint32 tileX, uint32 tileY) { return tileX<<16 | tileY; }
static void unpackTileID(uint32 ID, uint32 &tileX, uint32 &tileY) { tileX = ID >> 16; tileY = ID & 0xFF; }
- static bool CanLoadMap(const std::string &basePath, uint32 mapID, uint32 tileX, uint32 tileY, VMapManager2* vm);
+ static LoadResult CanLoadMap(const std::string &basePath, uint32 mapID, uint32 tileX, uint32 tileY, VMapManager2* vm);
StaticMapTree(uint32 mapID, const std::string &basePath);
~StaticMapTree();
- bool isInLineOfSight(const G3D::Vector3& pos1, const G3D::Vector3& pos2) const;
+ bool isInLineOfSight(const G3D::Vector3& pos1, const G3D::Vector3& pos2, ModelIgnoreFlags ignoreFlags) const;
bool getObjectHitPos(const G3D::Vector3& pos1, const G3D::Vector3& pos2, G3D::Vector3& pResultHitPos, float pModifyDist) const;
float getHeight(const G3D::Vector3& pPos, float maxSearchDist) const;
bool getAreaInfo(G3D::Vector3 &pos, uint32 &flags, int32 &adtId, int32 &rootId, int32 &groupId) const;
diff --git a/src/common/Collision/Models/GameObjectModel.cpp b/src/common/Collision/Models/GameObjectModel.cpp
index 07c1ffe548c..8e4ba0a9679 100644
--- a/src/common/Collision/Models/GameObjectModel.cpp
+++ b/src/common/Collision/Models/GameObjectModel.cpp
@@ -161,7 +161,7 @@ GameObjectModel* GameObjectModel::Create(std::unique_ptr<GameObjectModelOwnerBas
return mdl;
}
-bool GameObjectModel::intersectRay(G3D::Ray const& ray, float& maxDist, bool stopAtFirstHit, PhaseShift const& phaseShift) const
+bool GameObjectModel::intersectRay(G3D::Ray const& ray, float& maxDist, bool stopAtFirstHit, PhaseShift const& phaseShift, VMAP::ModelIgnoreFlags ignoreFlags) const
{
if (!isCollisionEnabled() || !owner->IsSpawned())
return false;
@@ -177,7 +177,7 @@ bool GameObjectModel::intersectRay(G3D::Ray const& ray, float& maxDist, bool sto
Vector3 p = iInvRot * (ray.origin() - iPos) * iInvScale;
Ray modRay(p, iInvRot * ray.direction());
float distance = maxDist * iInvScale;
- bool hit = iModel->IntersectRay(modRay, distance, stopAtFirstHit);
+ bool hit = iModel->IntersectRay(modRay, distance, stopAtFirstHit, ignoreFlags);
if (hit)
{
distance *= iScale;
diff --git a/src/common/Collision/Models/GameObjectModel.h b/src/common/Collision/Models/GameObjectModel.h
index 287f93f87ca..0ea8bbbbcfb 100644
--- a/src/common/Collision/Models/GameObjectModel.h
+++ b/src/common/Collision/Models/GameObjectModel.h
@@ -31,6 +31,7 @@ namespace VMAP
{
class WorldModel;
struct AreaInfo;
+ enum class ModelIgnoreFlags : uint32;
}
class GameObject;
@@ -69,7 +70,7 @@ public:
bool isCollisionEnabled() const { return _collisionEnabled; }
bool isMapObject() const { return isWmo; }
- bool intersectRay(G3D::Ray const& ray, float& maxDist, bool stopAtFirstHit, PhaseShift const& phaseShift) const;
+ bool intersectRay(G3D::Ray const& ray, float& maxDist, bool stopAtFirstHit, PhaseShift const& phaseShift, VMAP::ModelIgnoreFlags ignoreFlags) const;
void intersectPoint(G3D::Vector3 const& point, VMAP::AreaInfo& info, PhaseShift const& phaseShift) const;
static GameObjectModel* Create(std::unique_ptr<GameObjectModelOwnerBase> modelOwner, std::string const& dataPath);
diff --git a/src/common/Collision/Models/ModelIgnoreFlags.h b/src/common/Collision/Models/ModelIgnoreFlags.h
new file mode 100644
index 00000000000..beb9f965523
--- /dev/null
+++ b/src/common/Collision/Models/ModelIgnoreFlags.h
@@ -0,0 +1,34 @@
+/*
+ * Copyright (C) 2008-2017 TrinityCore <http://www.trinitycore.org/>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef ModelIgnoreFlags_h__
+#define ModelIgnoreFlags_h__
+
+#include "Define.h"
+
+namespace VMAP
+{
+enum class ModelIgnoreFlags : uint32
+{
+ Nothing = 0x00,
+ M2 = 0x01
+};
+
+inline ModelIgnoreFlags operator&(ModelIgnoreFlags left, ModelIgnoreFlags right) { return ModelIgnoreFlags(uint32(left) & uint32(right)); }
+}
+
+#endif // ModelIgnoreFlags_h__
diff --git a/src/common/Collision/Models/ModelInstance.cpp b/src/common/Collision/Models/ModelInstance.cpp
index a3d90ef7dec..a2c62bc565d 100644
--- a/src/common/Collision/Models/ModelInstance.cpp
+++ b/src/common/Collision/Models/ModelInstance.cpp
@@ -31,7 +31,7 @@ namespace VMAP
iInvScale = 1.f/iScale;
}
- bool ModelInstance::intersectRay(const G3D::Ray& pRay, float& pMaxDist, bool pStopAtFirstHit) const
+ bool ModelInstance::intersectRay(const G3D::Ray& pRay, float& pMaxDist, bool pStopAtFirstHit, ModelIgnoreFlags ignoreFlags) const
{
if (!iModel)
{
@@ -55,7 +55,7 @@ namespace VMAP
Vector3 p = iInvRot * (pRay.origin() - iPos) * iInvScale;
Ray modRay(p, iInvRot * pRay.direction());
float distance = pMaxDist * iInvScale;
- bool hit = iModel->IntersectRay(modRay, distance, pStopAtFirstHit);
+ bool hit = iModel->IntersectRay(modRay, distance, pStopAtFirstHit, ignoreFlags);
if (hit)
{
distance *= iScale;
diff --git a/src/common/Collision/Models/ModelInstance.h b/src/common/Collision/Models/ModelInstance.h
index 04fe5b06c7b..0bdcbc29393 100644
--- a/src/common/Collision/Models/ModelInstance.h
+++ b/src/common/Collision/Models/ModelInstance.h
@@ -31,6 +31,7 @@ namespace VMAP
class WorldModel;
struct AreaInfo;
struct LocationInfo;
+ enum class ModelIgnoreFlags : uint32;
enum ModelFlags
{
@@ -66,7 +67,7 @@ namespace VMAP
ModelInstance(): iInvScale(0.0f), iModel(nullptr) { }
ModelInstance(const ModelSpawn &spawn, WorldModel* model);
void setUnloaded() { iModel = nullptr; }
- bool intersectRay(const G3D::Ray& pRay, float& pMaxDist, bool pStopAtFirstHit) const;
+ bool intersectRay(const G3D::Ray& pRay, float& pMaxDist, bool pStopAtFirstHit, ModelIgnoreFlags ignoreFlags) const;
void intersectPoint(const G3D::Vector3& p, AreaInfo &info) const;
bool GetLocationInfo(const G3D::Vector3& p, LocationInfo &info) const;
bool GetLiquidLevel(const G3D::Vector3& p, LocationInfo &info, float &liqHeight) const;
diff --git a/src/common/Collision/Models/WorldModel.cpp b/src/common/Collision/Models/WorldModel.cpp
index beab8f80a1c..ad416943861 100644
--- a/src/common/Collision/Models/WorldModel.cpp
+++ b/src/common/Collision/Models/WorldModel.cpp
@@ -19,6 +19,8 @@
#include "WorldModel.h"
#include "VMapDefinitions.h"
#include "MapTree.h"
+#include "ModelInstance.h"
+#include "ModelIgnoreFlags.h"
using G3D::Vector3;
using G3D::Ray;
@@ -472,8 +474,16 @@ namespace VMAP
bool hit;
};
- bool WorldModel::IntersectRay(const G3D::Ray &ray, float &distance, bool stopAtFirstHit) const
+ bool WorldModel::IntersectRay(const G3D::Ray &ray, float &distance, bool stopAtFirstHit, ModelIgnoreFlags ignoreFlags) const
{
+ // If the caller asked us to ignore certain objects we should check flags
+ if ((ignoreFlags & ModelIgnoreFlags::M2) != ModelIgnoreFlags::Nothing)
+ {
+ // M2 models are not taken into account for LoS calculation if caller requested their ignoring.
+ if (Flags & MOD_M2)
+ return false;
+ }
+
// small M2 workaround, maybe better make separate class with virtual intersection funcs
// in any case, there's no need to use a bound tree if we only have one submodel
if (groupModels.size() == 1)
diff --git a/src/common/Collision/Models/WorldModel.h b/src/common/Collision/Models/WorldModel.h
index 8951b3fdf89..64b15c8cba4 100644
--- a/src/common/Collision/Models/WorldModel.h
+++ b/src/common/Collision/Models/WorldModel.h
@@ -32,6 +32,7 @@ namespace VMAP
class TreeNode;
struct AreaInfo;
struct LocationInfo;
+ enum class ModelIgnoreFlags : uint32;
class TC_COMMON_API MeshTriangle
{
@@ -111,12 +112,13 @@ namespace VMAP
//! pass group models to WorldModel and create BIH. Passed vector is swapped with old geometry!
void setGroupModels(std::vector<GroupModel> &models);
void setRootWmoID(uint32 id) { RootWMOID = id; }
- bool IntersectRay(const G3D::Ray &ray, float &distance, bool stopAtFirstHit) const;
+ bool IntersectRay(const G3D::Ray &ray, float &distance, bool stopAtFirstHit, ModelIgnoreFlags ignoreFlags) const;
bool IntersectPoint(const G3D::Vector3 &p, const G3D::Vector3 &down, float &dist, AreaInfo &info) const;
bool GetLocationInfo(const G3D::Vector3 &p, const G3D::Vector3 &down, float &dist, LocationInfo &info) const;
bool writeFile(const std::string &filename);
bool readFile(const std::string &filename);
void getGroupModels(std::vector<GroupModel>& outGroupModels);
+ uint32 Flags;
protected:
uint32 RootWMOID;
std::vector<GroupModel> groupModels;
diff --git a/src/common/Utilities/Util.h b/src/common/Utilities/Util.h
index 2ce427ef991..ceba32fbf9f 100644
--- a/src/common/Utilities/Util.h
+++ b/src/common/Utilities/Util.h
@@ -333,9 +333,9 @@ class HookList final
typedef typename ContainerType::const_iterator const_iterator;
typedef typename ContainerType::iterator iterator;
- HookList<T>& operator+=(T t)
+ HookList<T>& operator+=(T&& t)
{
- _container.push_back(t);
+ _container.push_back(std::move(t));
return *this;
}
diff --git a/src/server/bnetserver/Server/Session.cpp b/src/server/bnetserver/Server/Session.cpp
index f52f0c2772f..6ddfabc3c60 100644
--- a/src/server/bnetserver/Server/Session.cpp
+++ b/src/server/bnetserver/Server/Session.cpp
@@ -245,11 +245,17 @@ uint32 Battlenet::Session::HandleLogon(authentication::v1::LogonRequest const* l
uint32 Battlenet::Session::HandleVerifyWebCredentials(authentication::v1::VerifyWebCredentialsRequest const* verifyWebCredentialsRequest, std::function<void(ServiceBase*, uint32, ::google::protobuf::Message const*)>& continuation)
{
- return VerifyWebCredentials(verifyWebCredentialsRequest->web_credentials(), continuation);
+ if (verifyWebCredentialsRequest->has_web_credentials())
+ return VerifyWebCredentials(verifyWebCredentialsRequest->web_credentials(), continuation);
+
+ return ERROR_DENIED;
}
uint32 Battlenet::Session::VerifyWebCredentials(std::string const& webCredentials, std::function<void(ServiceBase*, uint32, ::google::protobuf::Message const*)>& continuation)
{
+ if (webCredentials.empty())
+ return ERROR_DENIED;
+
PreparedStatement* stmt = LoginDatabase.GetPreparedStatement(LOGIN_SEL_BNET_ACCOUNT_INFO);
stmt->setString(0, webCredentials);
diff --git a/src/server/database/Database/Implementation/CharacterDatabase.cpp b/src/server/database/Database/Implementation/CharacterDatabase.cpp
index 62c64fd6d38..b822e4ecab3 100644
--- a/src/server/database/Database/Implementation/CharacterDatabase.cpp
+++ b/src/server/database/Database/Implementation/CharacterDatabase.cpp
@@ -196,6 +196,7 @@ void CharacterDatabaseConnection::DoPrepareStatements()
PrepareStatement(CHAR_DEL_GIFT, "DELETE FROM character_gifts WHERE item_guid = ?", CONNECTION_ASYNC);
PrepareStatement(CHAR_SEL_CHARACTER_GIFT_BY_ITEM, "SELECT entry, flags FROM character_gifts WHERE item_guid = ?", CONNECTION_SYNCH);
PrepareStatement(CHAR_SEL_ACCOUNT_BY_NAME, "SELECT account FROM characters WHERE name = ?", CONNECTION_SYNCH);
+ PrepareStatement(CHAR_UPD_ACCOUNT_BY_GUID, "UPDATE characters SET account = ? WHERE guid = ?", CONNECTION_SYNCH);
PrepareStatement(CHAR_DEL_ACCOUNT_INSTANCE_LOCK_TIMES, "DELETE FROM account_instance_times WHERE accountId = ?", CONNECTION_ASYNC);
PrepareStatement(CHAR_INS_ACCOUNT_INSTANCE_LOCK_TIMES, "INSERT INTO account_instance_times (accountId, instanceId, releaseTime) VALUES (?, ?, ?)", CONNECTION_ASYNC);
PrepareStatement(CHAR_SEL_MATCH_MAKER_RATING, "SELECT matchMakerRating FROM character_arena_stats WHERE guid = ? AND slot = ?", CONNECTION_SYNCH);
diff --git a/src/server/database/Database/Implementation/CharacterDatabase.h b/src/server/database/Database/Implementation/CharacterDatabase.h
index c4c081ab73a..2c31b819593 100644
--- a/src/server/database/Database/Implementation/CharacterDatabase.h
+++ b/src/server/database/Database/Implementation/CharacterDatabase.h
@@ -165,6 +165,7 @@ enum CharacterDatabaseStatements : uint32
CHAR_DEL_GIFT,
CHAR_SEL_CHARACTER_GIFT_BY_ITEM,
CHAR_SEL_ACCOUNT_BY_NAME,
+ CHAR_UPD_ACCOUNT_BY_GUID,
CHAR_DEL_ACCOUNT_INSTANCE_LOCK_TIMES,
CHAR_INS_ACCOUNT_INSTANCE_LOCK_TIMES,
CHAR_SEL_MATCH_MAKER_RATING,
diff --git a/src/server/game/AI/CoreAI/PetAI.cpp b/src/server/game/AI/CoreAI/PetAI.cpp
index f30b2369e91..cab622be0cb 100644
--- a/src/server/game/AI/CoreAI/PetAI.cpp
+++ b/src/server/game/AI/CoreAI/PetAI.cpp
@@ -50,6 +50,11 @@ bool PetAI::_needToStop()
if (me->IsCharmed() && me->GetVictim() == me->GetCharmer())
return true;
+ // dont allow pets to follow targets far away from owner
+ if (Unit* owner = me->GetCharmerOrOwner())
+ if (owner->GetExactDist(me) >= (owner->GetVisibilityRange()-10.0f))
+ return true;
+
return !me->IsValidAttackTarget(me->GetVictim());
}
diff --git a/src/server/game/AI/CreatureAI.cpp b/src/server/game/AI/CreatureAI.cpp
index 82cb9b893f7..6b3750325ca 100644
--- a/src/server/game/AI/CreatureAI.cpp
+++ b/src/server/game/AI/CreatureAI.cpp
@@ -280,6 +280,7 @@ bool CreatureAI::_EnterEvadeMode(EvadeReason /*why*/)
me->ResetPlayerDamageReq();
me->SetLastDamagedTime(0);
me->SetCannotReachTarget(false);
+ me->DoNotReacquireTarget();
if (me->IsInEvadeMode())
return false;
diff --git a/src/server/game/AI/SmartScripts/SmartScript.cpp b/src/server/game/AI/SmartScripts/SmartScript.cpp
index 17851adc4de..a19d01fceb0 100644
--- a/src/server/game/AI/SmartScripts/SmartScript.cpp
+++ b/src/server/game/AI/SmartScripts/SmartScript.cpp
@@ -1707,7 +1707,13 @@ void SmartScript::ProcessAction(SmartScriptHolder& e, Unit* unit, uint32 var0, u
me->GetMotionMaster()->MovePoint(e.action.MoveToPos.pointId, dest, e.action.MoveToPos.disablePathfinding == 0);
}
else
- me->GetMotionMaster()->MovePoint(e.action.MoveToPos.pointId, target->GetPositionX(), target->GetPositionY(), target->GetPositionZ(), e.action.MoveToPos.disablePathfinding == 0);
+ {
+ float x, y, z;
+ target->GetPosition(x, y, z);
+ if (e.action.MoveToPos.ContactDistance > 0)
+ target->GetContactPoint(me, x, y, z, e.action.MoveToPos.ContactDistance);
+ me->GetMotionMaster()->MovePoint(e.action.MoveToPos.pointId, x, y, z, e.action.MoveToPos.disablePathfinding == 0);
+ }
break;
}
case SMART_ACTION_RESPAWN_TARGET:
diff --git a/src/server/game/AI/SmartScripts/SmartScriptMgr.h b/src/server/game/AI/SmartScripts/SmartScriptMgr.h
index 7b9e1ff5f3d..ac765bfa47a 100644
--- a/src/server/game/AI/SmartScripts/SmartScriptMgr.h
+++ b/src/server/game/AI/SmartScripts/SmartScriptMgr.h
@@ -513,7 +513,7 @@ enum SMART_ACTION
SMART_ACTION_SET_ORIENTATION = 66, //
SMART_ACTION_CREATE_TIMED_EVENT = 67, // id, InitialMin, InitialMax, RepeatMin(only if it repeats), RepeatMax(only if it repeats), chance
SMART_ACTION_PLAYMOVIE = 68, // entry
- SMART_ACTION_MOVE_TO_POS = 69, // PointId, transport, disablePathfinding
+ SMART_ACTION_MOVE_TO_POS = 69, // PointId, transport, disablePathfinding, ContactDistance
SMART_ACTION_RESPAWN_TARGET = 70, //
SMART_ACTION_EQUIP = 71, // entry, slotmask slot1, slot2, slot3 , only slots with mask set will be sent to client, bits are 1, 2, 4, leaving mask 0 is defaulted to mask 7 (send all), slots1-3 are only used if no entry is set
SMART_ACTION_CLOSE_GOSSIP = 72, // none
@@ -997,6 +997,7 @@ struct SmartAction
uint32 pointId;
uint32 transport;
uint32 disablePathfinding;
+ uint32 ContactDistance;
} MoveToPos;
struct
diff --git a/src/server/game/Accounts/RBAC.h b/src/server/game/Accounts/RBAC.h
index 0c1cb84d270..018f4e0c73f 100644
--- a/src/server/game/Accounts/RBAC.h
+++ b/src/server/game/Accounts/RBAC.h
@@ -603,7 +603,7 @@ enum RBACPermissions
RBAC_PERM_COMMAND_RELOAD_SPELL_LOOT_TEMPLATE = 695,
RBAC_PERM_COMMAND_RELOAD_SPELL_LINKED_SPELL = 696,
RBAC_PERM_COMMAND_RELOAD_SPELL_PET_AURAS = 697,
- // 698 - reuse
+ RBAC_PERM_COMMAND_CHARACTER_CHANGEACCOUNT = 698,
RBAC_PERM_COMMAND_RELOAD_SPELL_PROC = 699,
RBAC_PERM_COMMAND_RELOAD_SPELL_SCRIPTS = 700,
RBAC_PERM_COMMAND_RELOAD_SPELL_TARGET_POSITION = 701,
diff --git a/src/server/game/Achievements/AchievementMgr.cpp b/src/server/game/Achievements/AchievementMgr.cpp
index d11e6f79b19..9531bdff1ed 100644
--- a/src/server/game/Achievements/AchievementMgr.cpp
+++ b/src/server/game/Achievements/AchievementMgr.cpp
@@ -1115,8 +1115,8 @@ void AchievementGlobalMgr::LoadRewards()
_achievementRewards.clear(); // need for reload case
- // 0 1 2 3 4 5 6 7
- QueryResult result = WorldDatabase.Query("SELECT entry, title_A, title_H, item, sender, subject, text, mailTemplate FROM achievement_reward");
+ // 0 1 2 3 4 5 6 7
+ QueryResult result = WorldDatabase.Query("SELECT ID, TitleA, TitleH, ItemID, Sender, Subject, Body, MailTemplateID FROM achievement_reward");
if (!result)
{
@@ -1124,16 +1124,14 @@ void AchievementGlobalMgr::LoadRewards()
return;
}
- uint32 count = 0;
-
do
{
Field* fields = result->Fetch();
- uint32 entry = fields[0].GetUInt32();
- AchievementEntry const* achievement = sAchievementStore.LookupEntry(entry);
+ uint32 id = fields[0].GetUInt32();
+ AchievementEntry const* achievement = sAchievementStore.LookupEntry(id);
if (!achievement)
{
- TC_LOG_ERROR("sql.sql", "Table `achievement_reward` contains a wrong achievement entry (Entry: %u), ignored.", entry);
+ TC_LOG_ERROR("sql.sql", "Table `achievement_reward` contains a wrong achievement ID (%u), ignored.", id);
continue;
}
@@ -1149,19 +1147,19 @@ void AchievementGlobalMgr::LoadRewards()
// must be title or mail at least
if (!reward.TitleId[0] && !reward.TitleId[1] && !reward.SenderCreatureId)
{
- TC_LOG_ERROR("sql.sql", "Table `achievement_reward` (Entry: %u) does not contain title or item reward data. Ignored.", entry);
+ TC_LOG_ERROR("sql.sql", "Table `achievement_reward` (ID: %u) does not contain title or item reward data. Ignored.", id);
continue;
}
if (achievement->Faction == ACHIEVEMENT_FACTION_ANY && (!reward.TitleId[0] ^ !reward.TitleId[1]))
- TC_LOG_ERROR("sql.sql", "Table `achievement_reward` (Entry: %u) contains the title (A: %u H: %u) for only one team.", entry, reward.TitleId[0], reward.TitleId[1]);
+ TC_LOG_ERROR("sql.sql", "Table `achievement_reward` (ID: %u) contains the title (A: %u H: %u) for only one team.", id, reward.TitleId[0], reward.TitleId[1]);
if (reward.TitleId[0])
{
CharTitlesEntry const* titleEntry = sCharTitlesStore.LookupEntry(reward.TitleId[0]);
if (!titleEntry)
{
- TC_LOG_ERROR("sql.sql", "Table `achievement_reward` (Entry: %u) contains an invalid title id (%u) in `title_A`, set to 0", entry, reward.TitleId[0]);
+ TC_LOG_ERROR("sql.sql", "Table `achievement_reward` (Entry: %u) contains an invalid title id (%u) in `title_A`, set to 0", id, reward.TitleId[0]);
reward.TitleId[0] = 0;
}
}
@@ -1171,7 +1169,7 @@ void AchievementGlobalMgr::LoadRewards()
CharTitlesEntry const* titleEntry = sCharTitlesStore.LookupEntry(reward.TitleId[1]);
if (!titleEntry)
{
- TC_LOG_ERROR("sql.sql", "Table `achievement_reward` (Entry: %u) contains an invalid title id (%u) in `title_H`, set to 0", entry, reward.TitleId[1]);
+ TC_LOG_ERROR("sql.sql", "Table `achievement_reward` (Entry: %u) contains an invalid title id (%u) in `title_H`, set to 0", id, reward.TitleId[1]);
reward.TitleId[1] = 0;
}
}
@@ -1181,51 +1179,49 @@ void AchievementGlobalMgr::LoadRewards()
{
if (!sObjectMgr->GetCreatureTemplate(reward.SenderCreatureId))
{
- TC_LOG_ERROR("sql.sql", "Table `achievement_reward` (Entry: %u) contains an invalid creature entry %u as sender, mail reward skipped.", entry, reward.SenderCreatureId);
+ TC_LOG_ERROR("sql.sql", "Table `achievement_reward` (ID: %u) contains an invalid creature ID %u as sender, mail reward skipped.", id, reward.SenderCreatureId);
reward.SenderCreatureId = 0;
}
}
else
{
if (reward.ItemId)
- TC_LOG_ERROR("sql.sql", "Table `achievement_reward` (Entry: %u) does not have sender data, but contains an item reward. Item will not be rewarded.", entry);
+ TC_LOG_ERROR("sql.sql", "Table `achievement_reward` (ID: %u) does not have sender data, but contains an item reward. Item will not be rewarded.", id);
if (!reward.Subject.empty())
- TC_LOG_ERROR("sql.sql", "Table `achievement_reward` (Entry: %u) does not have sender data, but contains a mail subject.", entry);
+ TC_LOG_ERROR("sql.sql", "Table `achievement_reward` (ID: %u) does not have sender data, but contains a mail subject.", id);
if (!reward.Body.empty())
- TC_LOG_ERROR("sql.sql", "Table `achievement_reward` (Entry: %u) does not have sender data, but contains mail text.", entry);
+ TC_LOG_ERROR("sql.sql", "Table `achievement_reward` (ID: %u) does not have sender data, but contains mail text.", id);
if (reward.MailTemplateId)
- TC_LOG_ERROR("sql.sql", "Table `achievement_reward` (Entry: %u) does not have sender data, but has a MailTemplateId.", entry);
+ TC_LOG_ERROR("sql.sql", "Table `achievement_reward` (ID: %u) does not have sender data, but has a MailTemplate.", id);
}
if (reward.MailTemplateId)
{
if (!sMailTemplateStore.LookupEntry(reward.MailTemplateId))
{
- TC_LOG_ERROR("sql.sql", "Table `achievement_reward` (Entry: %u) is using an invalid MailTemplateId (%u).", entry, reward.MailTemplateId);
+ TC_LOG_ERROR("sql.sql", "Table `achievement_reward` (ID: %u) is using an invalid MailTemplate (%u).", id, reward.MailTemplateId);
reward.MailTemplateId = 0;
}
else if (!reward.Subject.empty() || !reward.Body.empty())
- TC_LOG_ERROR("sql.sql", "Table `achievement_reward` (Entry: %u) is using MailTemplateId (%u) and mail subject/text.", entry, reward.MailTemplateId);
+ TC_LOG_ERROR("sql.sql", "Table `achievement_reward` (ID: %u) is using MailTemplate (%u) and mail subject/text.", id, reward.MailTemplateId);
}
if (reward.ItemId)
{
if (!sObjectMgr->GetItemTemplate(reward.ItemId))
{
- TC_LOG_ERROR("sql.sql", "Table `achievement_reward` (Entry: %u) contains an invalid item id %u, reward mail will not contain the rewarded item.", entry, reward.ItemId);
+ TC_LOG_ERROR("sql.sql", "Table `achievement_reward` (ID: %u) contains an invalid item id %u, reward mail will not contain the rewarded item.", id, reward.ItemId);
reward.ItemId = 0;
}
}
- _achievementRewards[entry] = reward;
- ++count;
- }
- while (result->NextRow());
+ _achievementRewards[id] = reward;
+ } while (result->NextRow());
- TC_LOG_INFO("server.loading", ">> Loaded %u achievement rewards in %u ms.", count, GetMSTimeDiffToNow(oldMSTime));
+ TC_LOG_INFO("server.loading", ">> Loaded %u achievement rewards in %u ms.", uint32(_achievementRewards.size()), GetMSTimeDiffToNow(oldMSTime));
}
void AchievementGlobalMgr::LoadRewardLocales()
@@ -1234,13 +1230,12 @@ void AchievementGlobalMgr::LoadRewardLocales()
_achievementRewardLocales.clear(); // need for reload case
- QueryResult result = WorldDatabase.Query("SELECT entry, subject_loc1, text_loc1, subject_loc2, text_loc2, subject_loc3, text_loc3, subject_loc4, text_loc4, "
- "subject_loc5, text_loc5, subject_loc6, text_loc6, subject_loc7, text_loc7, subject_loc8, text_loc8"
- " FROM locales_achievement_reward");
+ // 0 1 2 3
+ QueryResult result = WorldDatabase.Query("SELECT ID, Locale, Subject, Body FROM achievement_reward_locale");
if (!result)
{
- TC_LOG_INFO("server.loading", ">> Loaded 0 achievement reward locale strings. DB table `locales_achievement_reward` is empty.");
+ TC_LOG_INFO("server.loading", ">> Loaded 0 achievement reward locale strings. DB table `achievement_reward_locale` is empty.");
return;
}
@@ -1248,24 +1243,23 @@ void AchievementGlobalMgr::LoadRewardLocales()
{
Field* fields = result->Fetch();
- uint32 entry = fields[0].GetUInt32();
+ uint32 id = fields[0].GetUInt32();
+ std::string localeName = fields[1].GetString();
- if (_achievementRewards.find(entry) == _achievementRewards.end())
+ if (_achievementRewards.find(id) == _achievementRewards.end())
{
- TC_LOG_ERROR("sql.sql", "Table `locales_achievement_reward` (Entry: %u) contains locale strings for a non-existing achievement reward.", entry);
+ TC_LOG_ERROR("sql.sql", "Table `achievement_reward_locale` (ID: %u) contains locale strings for a non-existing achievement reward.", id);
continue;
}
- AchievementRewardLocale& data = _achievementRewardLocales[entry];
+ AchievementRewardLocale& data = _achievementRewardLocales[id];
+ LocaleConstant locale = GetLocaleByName(localeName);
+ if (locale == LOCALE_enUS)
+ continue;
- for (uint8 i = OLD_TOTAL_LOCALES - 1; i > 0; --i)
- {
- LocaleConstant locale = (LocaleConstant) i;
- ObjectMgr::AddLocaleString(fields[1 + 2 * (i - 1)].GetString(), locale, data.Subject);
- ObjectMgr::AddLocaleString(fields[1 + 2 * (i - 1) + 1].GetString(), locale, data.Body);
- }
- }
- while (result->NextRow());
+ ObjectMgr::AddLocaleString(fields[2].GetString(), locale, data.Subject);
+ ObjectMgr::AddLocaleString(fields[3].GetString(), locale, data.Body);
+ } while (result->NextRow());
TC_LOG_INFO("server.loading", ">> Loaded %u achievement reward locale strings in %u ms.", uint32(_achievementRewardLocales.size()), GetMSTimeDiffToNow(oldMSTime));
}
diff --git a/src/server/game/Combat/HostileRefManager.cpp b/src/server/game/Combat/HostileRefManager.cpp
index 98883f3ac70..bcea34d7e83 100644
--- a/src/server/game/Combat/HostileRefManager.cpp
+++ b/src/server/game/Combat/HostileRefManager.cpp
@@ -142,6 +142,26 @@ void HostileRefManager::deleteReferencesForFaction(uint32 faction)
}
//=================================================
+// delete all references out of specified range
+
+void HostileRefManager::deleteReferencesOutOfRange(float range)
+{
+ HostileReference* ref = getFirst();
+ range = range*range;
+ while (ref)
+ {
+ HostileReference* nextRef = ref->next();
+ Unit* owner = ref->GetSource()->GetOwner();
+ if (!owner->isActiveObject() && owner->GetExactDist2dSq(GetOwner()) > range)
+ {
+ ref->removeReference();
+ delete ref;
+ }
+ ref = nextRef;
+ }
+}
+
+//=================================================
// delete one reference, defined by Unit
void HostileRefManager::deleteReference(Unit* creature)
diff --git a/src/server/game/Combat/HostileRefManager.h b/src/server/game/Combat/HostileRefManager.h
index fc26d950e67..585d96b7443 100644
--- a/src/server/game/Combat/HostileRefManager.h
+++ b/src/server/game/Combat/HostileRefManager.h
@@ -53,6 +53,9 @@ class TC_GAME_API HostileRefManager : public RefManager<Unit, ThreatManager>
// Remove specific faction references
void deleteReferencesForFaction(uint32 faction);
+ // for combat bugs
+ void deleteReferencesOutOfRange(float range);
+
HostileReference* getFirst() { return ((HostileReference*) RefManager<Unit, ThreatManager>::getFirst()); }
void updateThreatTables();
diff --git a/src/server/game/DataStores/DBCEnums.h b/src/server/game/DataStores/DBCEnums.h
index d72ffa343ca..2655e0e0a12 100644
--- a/src/server/game/DataStores/DBCEnums.h
+++ b/src/server/game/DataStores/DBCEnums.h
@@ -1111,7 +1111,7 @@ enum VehicleSeatFlags
{
VEHICLE_SEAT_FLAG_HAS_LOWER_ANIM_FOR_ENTER = 0x00000001,
VEHICLE_SEAT_FLAG_HAS_LOWER_ANIM_FOR_RIDE = 0x00000002,
- VEHICLE_SEAT_FLAG_UNK3 = 0x00000004,
+ VEHICLE_SEAT_FLAG_DISABLE_GRAVITY = 0x00000004, // Passenger will not be affected by gravity
VEHICLE_SEAT_FLAG_SHOULD_USE_VEH_SEAT_EXIT_ANIM_ON_VOLUNTARY_EXIT = 0x00000008,
VEHICLE_SEAT_FLAG_UNK5 = 0x00000010,
VEHICLE_SEAT_FLAG_UNK6 = 0x00000020,
diff --git a/src/server/game/Entities/Creature/Creature.cpp b/src/server/game/Entities/Creature/Creature.cpp
index f521cdfd3b0..fde7d49a943 100644
--- a/src/server/game/Entities/Creature/Creature.cpp
+++ b/src/server/game/Entities/Creature/Creature.cpp
@@ -286,6 +286,10 @@ void Creature::RemoveCorpse(bool setSpawnTime)
if (setSpawnTime)
m_respawnTime = time(NULL) + respawnDelay;
+ // if corpse was removed during falling, the falling will continue and override relocation to respawn position
+ if (IsFalling())
+ StopMoving();
+
float x, y, z, o;
GetRespawnPosition(x, y, z, &o);
SetHomePosition(x, y, z, o);
@@ -2812,6 +2816,10 @@ void Creature::UpdateMovementFlags()
if (m_playerMovingMe)
return;
+ // Creatures with CREATURE_FLAG_EXTRA_NO_MOVE_FLAGS_UPDATE should control MovementFlags in your own scripts
+ if (GetCreatureTemplate()->flags_extra & CREATURE_FLAG_EXTRA_NO_MOVE_FLAGS_UPDATE)
+ return;
+
// Set the movement flags if the creature is in that mode. (Only fly if actually in air, only swim if in water, etc)
float ground = GetMap()->GetHeight(GetPhaseShift(), GetPositionX(), GetPositionY(), GetPositionZMinusOffset());
@@ -2842,8 +2850,8 @@ void Creature::SetObjectScale(float scale)
if (CreatureModelInfo const* minfo = sObjectMgr->GetCreatureModelInfo(GetDisplayId()))
{
- SetFloatValue(UNIT_FIELD_BOUNDINGRADIUS, minfo->bounding_radius * scale);
- SetFloatValue(UNIT_FIELD_COMBATREACH, minfo->combat_reach * scale);
+ SetFloatValue(UNIT_FIELD_BOUNDINGRADIUS, (IsPet() ? 1.0f : minfo->bounding_radius) * scale);
+ SetFloatValue(UNIT_FIELD_COMBATREACH, (IsPet() ? DEFAULT_COMBAT_REACH : minfo->combat_reach) * scale);
}
}
@@ -2853,8 +2861,8 @@ void Creature::SetDisplayId(uint32 modelId, float displayScale /*= 1.f*/)
if (CreatureModelInfo const* minfo = sObjectMgr->GetCreatureModelInfo(modelId))
{
- SetFloatValue(UNIT_FIELD_BOUNDINGRADIUS, minfo->bounding_radius * GetObjectScale());
- SetFloatValue(UNIT_FIELD_COMBATREACH, minfo->combat_reach * GetObjectScale());
+ SetFloatValue(UNIT_FIELD_BOUNDINGRADIUS, (IsPet() ? 1.0f : minfo->bounding_radius) * GetObjectScale());
+ SetFloatValue(UNIT_FIELD_COMBATREACH, (IsPet() ? DEFAULT_COMBAT_REACH : minfo->combat_reach) * GetObjectScale());
}
}
diff --git a/src/server/game/Entities/Creature/CreatureData.h b/src/server/game/Entities/Creature/CreatureData.h
index 813aaa27e27..02fdcfbff16 100644
--- a/src/server/game/Entities/Creature/CreatureData.h
+++ b/src/server/game/Entities/Creature/CreatureData.h
@@ -264,6 +264,7 @@ enum CreatureFlagsExtra
CREATURE_FLAG_EXTRA_NO_XP_AT_KILL = 0x00000040, // creature kill not provide XP
CREATURE_FLAG_EXTRA_TRIGGER = 0x00000080, // trigger creature
CREATURE_FLAG_EXTRA_NO_TAUNT = 0x00000100, // creature is immune to taunt auras and effect attack me
+ CREATURE_FLAG_EXTRA_NO_MOVE_FLAGS_UPDATE = 0x00000200, // creature won't update movement flags
CREATURE_FLAG_EXTRA_WORLDEVENT = 0x00004000, // custom flag for world event creatures (left room for merging)
CREATURE_FLAG_EXTRA_GUARD = 0x00008000, // Creature is guard
CREATURE_FLAG_EXTRA_NO_CRIT = 0x00020000, // creature can't do critical strikes
@@ -279,7 +280,7 @@ enum CreatureFlagsExtra
#define CREATURE_FLAG_EXTRA_DB_ALLOWED (CREATURE_FLAG_EXTRA_INSTANCE_BIND | CREATURE_FLAG_EXTRA_CIVILIAN | \
CREATURE_FLAG_EXTRA_NO_PARRY | CREATURE_FLAG_EXTRA_NO_PARRY_HASTEN | CREATURE_FLAG_EXTRA_NO_BLOCK | \
CREATURE_FLAG_EXTRA_NO_CRUSH | CREATURE_FLAG_EXTRA_NO_XP_AT_KILL | CREATURE_FLAG_EXTRA_TRIGGER | \
- CREATURE_FLAG_EXTRA_NO_TAUNT | CREATURE_FLAG_EXTRA_WORLDEVENT | CREATURE_FLAG_EXTRA_NO_CRIT | \
+ CREATURE_FLAG_EXTRA_NO_TAUNT | CREATURE_FLAG_EXTRA_NO_MOVE_FLAGS_UPDATE | CREATURE_FLAG_EXTRA_WORLDEVENT | CREATURE_FLAG_EXTRA_NO_CRIT | \
CREATURE_FLAG_EXTRA_NO_SKILLGAIN | CREATURE_FLAG_EXTRA_TAUNT_DIMINISH | CREATURE_FLAG_EXTRA_ALL_DIMINISH | \
CREATURE_FLAG_EXTRA_GUARD | CREATURE_FLAG_EXTRA_IGNORE_PATHFINDING | CREATURE_FLAG_EXTRA_NO_PLAYER_DAMAGE_REQ | CREATURE_FLAG_EXTRA_IMMUNITY_KNOCKBACK)
diff --git a/src/server/game/Entities/Creature/GossipDef.cpp b/src/server/game/Entities/Creature/GossipDef.cpp
index 89b553d0792..9f5b461ef8d 100644
--- a/src/server/game/Entities/Creature/GossipDef.cpp
+++ b/src/server/game/Entities/Creature/GossipDef.cpp
@@ -443,7 +443,7 @@ void PlayerMenu::SendQuestGiverQuestDetails(Quest const* quest, ObjectGuid npcGU
packet.PortraitTurnIn = quest->GetQuestTurnInPortrait();
packet.AutoLaunched = autoLaunched;
packet.DisplayPopup = displayPopup;
- packet.QuestFlags[0] = quest->GetFlags();
+ packet.QuestFlags[0] = quest->GetFlags() & (sWorld->getBoolConfig(CONFIG_QUEST_IGNORE_AUTO_ACCEPT) ? ~QUEST_FLAGS_AUTO_ACCEPT : ~0);
packet.QuestFlags[1] = quest->GetFlagsEx();
packet.SuggestedPartyMembers = quest->GetSuggestedPlayers();
diff --git a/src/server/game/Entities/GameObject/GameObjectData.h b/src/server/game/Entities/GameObject/GameObjectData.h
index 2bf4a423590..a699be4bcf7 100644
--- a/src/server/game/Entities/GameObject/GameObjectData.h
+++ b/src/server/game/Entities/GameObject/GameObjectData.h
@@ -19,6 +19,7 @@
#define GameObjectData_h__
#include "Common.h"
+#include "DBCEnums.h"
#include "SharedDefines.h"
#include <string>
#include <vector>
diff --git a/src/server/game/Entities/Object/Object.cpp b/src/server/game/Entities/Object/Object.cpp
index 9d8a17ecbd7..2921ddf673f 100644
--- a/src/server/game/Entities/Object/Object.cpp
+++ b/src/server/game/Entities/Object/Object.cpp
@@ -1693,7 +1693,7 @@ bool WorldObject::_IsWithinDist(WorldObject const* obj, float dist2compare, bool
return distsq < maxdist * maxdist;
}
-bool WorldObject::IsWithinLOSInMap(const WorldObject* obj) const
+bool WorldObject::IsWithinLOSInMap(const WorldObject* obj, VMAP::ModelIgnoreFlags ignoreFlags) const
{
if (!IsInMap(obj))
return false;
@@ -1704,7 +1704,7 @@ bool WorldObject::IsWithinLOSInMap(const WorldObject* obj) const
else
obj->GetHitSpherePointFor(GetPosition(), x, y, z);
- return IsWithinLOS(x, y, z);
+ return IsWithinLOS(x, y, z, ignoreFlags);
}
float WorldObject::GetDistance(const WorldObject* obj) const
@@ -1781,7 +1781,7 @@ bool WorldObject::IsWithinDistInMap(WorldObject const* obj, float dist2compare,
return obj && IsInMap(obj) && IsInPhase(obj) && _IsWithinDist(obj, dist2compare, is3D);
}
-bool WorldObject::IsWithinLOS(float ox, float oy, float oz) const
+bool WorldObject::IsWithinLOS(float ox, float oy, float oz, VMAP::ModelIgnoreFlags ignoreFlags) const
{
/*float x, y, z;
GetPosition(x, y, z);
@@ -1795,7 +1795,7 @@ bool WorldObject::IsWithinLOS(float ox, float oy, float oz) const
else
GetHitSpherePointFor({ ox, oy, oz }, x, y, z);
- return GetMap()->isInLineOfSight(GetPhaseShift(), x, y, z + 2.0f, ox, oy, oz + 2.0f);
+ return GetMap()->isInLineOfSight(GetPhaseShift(), x, y, z + 2.0f, ox, oy, oz + 2.0f, ignoreFlags);
}
return true;
@@ -2122,6 +2122,14 @@ bool WorldObject::CanSeeOrDetect(WorldObject const* obj, bool ignoreStealth, boo
corpseVisibility = true;
}
}
+
+ if (Unit const* target = obj->ToUnit())
+ {
+ // Don't allow to detect vehicle accessories if you can't see vehicle
+ if (Unit const* vehicle = target->GetVehicleBase())
+ if (!thisPlayer->HaveAtClient(vehicle))
+ return false;
+ }
}
WorldObject const* viewpoint = this;
@@ -2251,7 +2259,7 @@ bool WorldObject::CanDetectStealthOf(WorldObject const* obj, bool checkAlert) co
if (!HasInArc(float(M_PI), obj))
return false;
- GameObject const* go = ToGameObject();
+ GameObject const* go = obj->ToGameObject();
for (uint32 i = 0; i < TOTAL_STEALTH_TYPES; ++i)
{
if (!(obj->m_stealth.GetFlags() & (1 << i)))
diff --git a/src/server/game/Entities/Object/Object.h b/src/server/game/Entities/Object/Object.h
index 79420076f5b..17979a441a8 100644
--- a/src/server/game/Entities/Object/Object.h
+++ b/src/server/game/Entities/Object/Object.h
@@ -22,6 +22,7 @@
#include "Common.h"
#include "GridReference.h"
#include "GridRefManager.h"
+#include "ModelIgnoreFlags.h"
#include "MovementInfo.h"
#include "ObjectDefines.h"
#include "ObjectGuid.h"
@@ -476,8 +477,8 @@ class TC_GAME_API WorldObject : public Object, public WorldLocation
// use only if you will sure about placing both object at same map
bool IsWithinDist(WorldObject const* obj, float dist2compare, bool is3D = true) const;
bool IsWithinDistInMap(WorldObject const* obj, float dist2compare, bool is3D = true) const;
- bool IsWithinLOS(float x, float y, float z) const;
- bool IsWithinLOSInMap(WorldObject const* obj) const;
+ bool IsWithinLOS(float x, float y, float z, VMAP::ModelIgnoreFlags ignoreFlags = VMAP::ModelIgnoreFlags::Nothing) const;
+ bool IsWithinLOSInMap(WorldObject const* obj, VMAP::ModelIgnoreFlags ignoreFlags = VMAP::ModelIgnoreFlags::Nothing) const;
Position GetHitSpherePointFor(Position const& dest) const;
void GetHitSpherePointFor(Position const& dest, float& x, float& y, float& z) const;
bool GetDistanceOrder(WorldObject const* obj1, WorldObject const* obj2, bool is3D = true) const;
diff --git a/src/server/game/Entities/Pet/Pet.cpp b/src/server/game/Entities/Pet/Pet.cpp
index d8ab46e6b07..f16f234ef2a 100644
--- a/src/server/game/Entities/Pet/Pet.cpp
+++ b/src/server/game/Entities/Pet/Pet.cpp
@@ -853,8 +853,10 @@ bool Guardian::InitStatsForLevel(uint8 petlevel)
}
// Resistance
- for (uint8 i = SPELL_SCHOOL_HOLY; i < MAX_SPELL_SCHOOL; ++i)
- SetModifierValue(UnitMods(UNIT_MOD_RESISTANCE_START + i), BASE_VALUE, float(cinfo->resistance[i]));
+ // Hunters pet should not inherit resistances from creature_template, they have separate auras for that
+ if (!IsHunterPet())
+ for (uint8 i = SPELL_SCHOOL_HOLY; i < MAX_SPELL_SCHOOL; ++i)
+ SetModifierValue(UnitMods(UNIT_MOD_RESISTANCE_START + i), BASE_VALUE, float(cinfo->resistance[i]));
// Health, Mana or Power, Armor
PetLevelInfo const* pInfo = sObjectMgr->GetPetLevelInfo(creature_ID, petlevel);
diff --git a/src/server/game/Entities/Player/Player.cpp b/src/server/game/Entities/Player/Player.cpp
index ce02cdad3ce..f32bfb5d3e2 100644
--- a/src/server/game/Entities/Player/Player.cpp
+++ b/src/server/game/Entities/Player/Player.cpp
@@ -210,6 +210,7 @@ Player::Player(WorldSession* session) : Unit(true), m_sceneMgr(this)
m_MirrorTimerFlags = UNDERWATER_NONE;
m_MirrorTimerFlagsLast = UNDERWATER_NONE;
m_isInWater = false;
+ m_hostileReferenceCheckTimer = 0;
m_drunkTimer = 0;
m_deathTimer = 0;
m_deathExpireTime = 0;
@@ -1348,6 +1349,18 @@ void Player::Update(uint32 p_time)
//if (pet && !pet->IsWithinDistInMap(this, GetMap()->GetVisibilityDistance()) && (GetCharmGUID() && (pet->GetGUID() != GetCharmGUID())))
RemovePet(pet, PET_SAVE_NOT_IN_SLOT, true);
+ if (IsAlive())
+ {
+ if (m_hostileReferenceCheckTimer <= p_time)
+ {
+ m_hostileReferenceCheckTimer = 15 * IN_MILLISECONDS;
+ if (!GetMap()->IsDungeon())
+ getHostileRefManager().deleteReferencesOutOfRange(GetVisibilityRange());
+ }
+ else
+ m_hostileReferenceCheckTimer -= p_time;
+ }
+
//we should execute delayed teleports only for alive(!) players
//because we don't want player's ghost teleported from graveyard
if (IsHasDelayedTeleport() && IsAlive())
@@ -2268,6 +2281,7 @@ bool Player::IsGroupVisibleFor(Player const* p) const
default: return IsInSameGroupWith(p);
case 1: return IsInSameRaidWith(p);
case 2: return GetTeam() == p->GetTeam();
+ case 3: return false;
}
}
@@ -5877,7 +5891,6 @@ bool Player::UpdatePosition(float x, float y, float z, float orientation, bool t
// mover->RemoveAurasWithInterruptFlags(AURA_INTERRUPT_FLAG_MOVE);
//if (movementInfo.flags & MOVEMENTFLAG_TURNING)
// mover->RemoveAurasWithInterruptFlags(AURA_INTERRUPT_FLAG_TURNING);
- //AURA_INTERRUPT_FLAG_JUMP not sure
// group update
if (GetGroup())
@@ -22108,21 +22121,6 @@ bool Player::ActivateTaxiPathTo(std::vector<uint32> const& nodes, Creature* npc
return false;
}
- // check node starting pos data set case if provided
- if (node->Pos.X != 0.0f || node->Pos.Y != 0.0f || node->Pos.Z != 0.0f)
- {
- if (node->ContinentID != GetMapId() || !IsInDist(node->Pos.X, node->Pos.Y, node->Pos.Z, 2 * INTERACTION_DISTANCE))
- {
- GetSession()->SendActivateTaxiReply(ERR_TAXITOOFARAWAY);
- return false;
- }
- }
- // node must have pos if taxi master case (npc != NULL)
- else if (npc)
- {
- GetSession()->SendActivateTaxiReply(ERR_TAXIUNSPECIFIEDSERVERERROR);
- return false;
- }
// Prepare to flight start now
// stop combat at start taxi flight if any
@@ -25752,6 +25750,13 @@ void Player::StoreLootItem(uint8 lootSlot, Loot* loot, AELootResult* aeResult/*
return;
}
+ // dont allow protected item to be looted by someone else
+ if (!item->rollWinnerGUID.IsEmpty() && item->rollWinnerGUID != GetGUID())
+ {
+ SendLootRelease(GetLootGUID());
+ return;
+ }
+
ItemPosCountVec dest;
InventoryResult msg = CanStoreNewItem(NULL_BAG, NULL_SLOT, dest, item->itemid, item->count);
if (msg == EQUIP_ERR_OK)
diff --git a/src/server/game/Entities/Player/Player.h b/src/server/game/Entities/Player/Player.h
index d53dbf33db0..391fbb34be3 100644
--- a/src/server/game/Entities/Player/Player.h
+++ b/src/server/game/Entities/Player/Player.h
@@ -2587,6 +2587,7 @@ class TC_GAME_API Player : public Unit, public GridObject<Player>
bool m_SeasonalQuestChanged;
time_t m_lastDailyQuestTime;
+ uint32 m_hostileReferenceCheckTimer;
uint32 m_drunkTimer;
uint32 m_weaponChangeTimer;
diff --git a/src/server/game/Entities/Unit/Unit.cpp b/src/server/game/Entities/Unit/Unit.cpp
index 87d8bad3de6..8261a97c32a 100644
--- a/src/server/game/Entities/Unit/Unit.cpp
+++ b/src/server/game/Entities/Unit/Unit.cpp
@@ -7190,11 +7190,13 @@ bool Unit::IsImmunedToSpell(SpellInfo const* spellInfo, Unit* caster) const
SpellImmuneContainer const& schoolList = m_spellImmune[IMMUNITY_SCHOOL];
for (auto itr = schoolList.begin(); itr != schoolList.end(); ++itr)
{
+ if (!(itr->first & spellInfo->GetSchoolMask()))
+ continue;
+
SpellInfo const* immuneSpellInfo = sSpellMgr->GetSpellInfo(itr->second);
- if ((itr->first & spellInfo->GetSchoolMask())
- && !(immuneSpellInfo && immuneSpellInfo->IsPositive() && spellInfo->IsPositive() && IsFriendlyTo(caster))
- && !spellInfo->CanPierceImmuneAura(immuneSpellInfo))
- return true;
+ if (!(immuneSpellInfo && immuneSpellInfo->IsPositive() && spellInfo->IsPositive() && caster && IsFriendlyTo(caster)))
+ if (!spellInfo->CanPierceImmuneAura(immuneSpellInfo))
+ return true;
}
return false;
@@ -7523,6 +7525,11 @@ void Unit::Mount(uint32 mount, uint32 VehicleId, uint32 creatureEntry)
player->UnsummonPetTemporaryIfAny();
}
+ // if we have charmed npc, stun him also (everywhere)
+ if (Unit* charm = player->GetCharm())
+ if (charm->GetTypeId() == TYPEID_UNIT)
+ charm->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_STUNNED);
+
player->SendMovementSetCollisionHeight(player->GetCollisionHeight(true));
}
@@ -7565,6 +7572,11 @@ void Unit::Dismount()
}
else
player->ResummonPetTemporaryUnSummonedIfAny();
+
+ // if we have charmed npc, remove stun also
+ if (Unit* charm = player->GetCharm())
+ if (charm->GetTypeId() == TYPEID_UNIT && charm->HasFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_STUNNED) && !charm->HasUnitState(UNIT_STATE_STUNNED))
+ charm->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_STUNNED);
}
}
@@ -7775,6 +7787,8 @@ void Unit::SetInCombatState(bool PvP, Unit* enemy)
(*itr)->SetInCombatState(PvP, enemy);
(*itr)->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_PET_IN_COMBAT);
}
+
+ ProcSkillsAndAuras(enemy, PROC_FLAG_ENTER_COMBAT, PROC_FLAG_NONE, PROC_SPELL_TYPE_MASK_ALL, PROC_SPELL_PHASE_NONE, PROC_HIT_NONE, nullptr, nullptr, nullptr);
}
void Unit::ClearInCombat()
@@ -12881,7 +12895,8 @@ bool Unit::UpdatePosition(float x, float y, float z, float orientation, bool tel
return false;
}
- bool const turn = (GetOrientation() != orientation);
+ // Check if angular distance changed
+ bool const turn = G3D::fuzzyGt(M_PI - fabs(fabs(GetOrientation() - orientation) - M_PI), 0.0f);
// G3D::fuzzyEq won't help here, in some cases magnitudes differ by a little more than G3D::eps, but should be considered equal
bool const relocated = (teleport ||
diff --git a/src/server/game/Entities/Vehicle/Vehicle.cpp b/src/server/game/Entities/Vehicle/Vehicle.cpp
index 4b66e148fe5..e8366a48c79 100644
--- a/src/server/game/Entities/Vehicle/Vehicle.cpp
+++ b/src/server/game/Entities/Vehicle/Vehicle.cpp
@@ -208,6 +208,11 @@ void Vehicle::ApplyAllImmunities()
// why we need to apply this? we can simple add immunities to slow mechanic in DB
_me->ApplySpellImmune(0, IMMUNITY_STATE, SPELL_AURA_MOD_DECREASE_SPEED, true);
break;
+ case 335: // Salvaged Chopper
+ case 336: // Salvaged Siege Engine
+ case 338: // Salvaged Demolisher
+ _me->ApplySpellImmune(0, IMMUNITY_STATE, SPELL_AURA_MOD_DAMAGE_PERCENT_TAKEN, false); // Battering Ram
+ break;
default:
break;
}
@@ -480,6 +485,10 @@ Vehicle* Vehicle::RemovePassenger(Unit* unit)
if (seat->second.SeatInfo->CanEnterOrExit() && ++UsableSeatNum)
_me->SetFlag64(UNIT_NPC_FLAGS, (_me->GetTypeId() == TYPEID_PLAYER ? UNIT_NPC_FLAG_PLAYER_VEHICLE : UNIT_NPC_FLAG_SPELLCLICK));
+ // Enable gravity for passenger when he did not have it active before entering the vehicle
+ if (seat->second.SeatInfo->Flags & VEHICLE_SEAT_FLAG_DISABLE_GRAVITY && !seat->second.Passenger.IsGravityDisabled)
+ unit->SetDisableGravity(false);
+
// Remove UNIT_FLAG_NOT_SELECTABLE if passenger did not have it before entering vehicle
if (seat->second.SeatInfo->Flags & VEHICLE_SEAT_FLAG_PASSENGER_NOT_SELECTABLE && !seat->second.Passenger.IsUnselectable)
unit->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE);
@@ -760,6 +769,7 @@ bool VehicleJoinEvent::Execute(uint64, uint32)
Passenger->SetVehicle(Target);
Seat->second.Passenger.Guid = Passenger->GetGUID();
Seat->second.Passenger.IsUnselectable = Passenger->HasFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE);
+ Seat->second.Passenger.IsGravityDisabled = Passenger->HasUnitMovementFlag(MOVEMENTFLAG_DISABLE_GRAVITY);
if (Seat->second.SeatInfo->CanEnterOrExit())
{
ASSERT(Target->UsableSeatNum);
@@ -792,6 +802,9 @@ bool VehicleJoinEvent::Execute(uint64, uint32)
player->UnsummonPetTemporaryIfAny();
}
+ if (veSeat->Flags & VEHICLE_SEAT_FLAG_DISABLE_GRAVITY)
+ Passenger->SetDisableGravity(true);
+
if (Seat->second.SeatInfo->Flags & VEHICLE_SEAT_FLAG_PASSENGER_NOT_SELECTABLE)
Passenger->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE);
diff --git a/src/server/game/Entities/Vehicle/VehicleDefines.h b/src/server/game/Entities/Vehicle/VehicleDefines.h
index 95c244423c5..a4bdf647e27 100644
--- a/src/server/game/Entities/Vehicle/VehicleDefines.h
+++ b/src/server/game/Entities/Vehicle/VehicleDefines.h
@@ -80,11 +80,13 @@ struct PassengerInfo
{
ObjectGuid Guid;
bool IsUnselectable;
+ bool IsGravityDisabled;
void Reset()
{
Guid.Clear();
IsUnselectable = false;
+ IsGravityDisabled = false;
}
};
diff --git a/src/server/game/Globals/ObjectMgr.cpp b/src/server/game/Globals/ObjectMgr.cpp
index a9bbf7bbade..d0b70bf3d8a 100644
--- a/src/server/game/Globals/ObjectMgr.cpp
+++ b/src/server/game/Globals/ObjectMgr.cpp
@@ -1986,8 +1986,8 @@ void ObjectMgr::LoadCreatures()
int gx = (MAX_NUMBER_OF_GRIDS - 1) - gridCoord.x_coord;
int gy = (MAX_NUMBER_OF_GRIDS - 1) - gridCoord.y_coord;
- bool exists = vmgr->existsMap((sWorld->GetDataPath() + "vmaps").c_str(), data.mapid, gx, gy);
- if (!exists)
+ VMAP::LoadResult result = vmgr->existsMap((sWorld->GetDataPath() + "vmaps").c_str(), data.mapid, gx, gy);
+ if (result != VMAP::LoadResult::Success)
TC_LOG_ERROR("sql.sql", "Table `creature` has creature (GUID: " UI64FMTD " Entry: %u MapID: %u) spawned on a possible invalid position (X: %f Y: %f Z: %f)",
guid, data.id, data.mapid, data.posX, data.posY, data.posZ);
}
@@ -2345,8 +2345,8 @@ void ObjectMgr::LoadGameobjects()
int gx = (MAX_NUMBER_OF_GRIDS - 1) - gridCoord.x_coord;
int gy = (MAX_NUMBER_OF_GRIDS - 1) - gridCoord.y_coord;
- bool exists = vmgr->existsMap((sWorld->GetDataPath() + "vmaps").c_str(), data.mapid, gx, gy);
- if (!exists)
+ VMAP::LoadResult result = vmgr->existsMap((sWorld->GetDataPath() + "vmaps").c_str(), data.mapid, gx, gy);
+ if (result != VMAP::LoadResult::Success)
TC_LOG_ERROR("sql.sql", "Table `gameobject` has gameobject (GUID: " UI64FMTD " Entry: %u MapID: %u) spawned on a possible invalid position (X: %f Y: %f Z: %f)",
guid, data.id, data.mapid, data.posX, data.posY, data.posZ);
}
diff --git a/src/server/game/Groups/Group.cpp b/src/server/game/Groups/Group.cpp
index 184bd97e17d..7321244578c 100644
--- a/src/server/game/Groups/Group.cpp
+++ b/src/server/game/Groups/Group.cpp
@@ -1283,7 +1283,8 @@ void Group::CountTheRoll(Rolls::iterator rollI)
else
{
item->is_blocked = false;
- player->SendEquipError(msg, NULL, NULL, roll->itemid);
+ item->rollWinnerGUID = player->GetGUID();
+ player->SendEquipError(msg, nullptr, nullptr, roll->itemid);
}
}
}
@@ -1335,7 +1336,8 @@ void Group::CountTheRoll(Rolls::iterator rollI)
else
{
item->is_blocked = false;
- player->SendEquipError(msg, NULL, NULL, roll->itemid);
+ item->rollWinnerGUID = player->GetGUID();
+ player->SendEquipError(msg, nullptr, nullptr, roll->itemid);
}
}
else if (rollvote == DISENCHANT)
@@ -1360,7 +1362,7 @@ void Group::CountTheRoll(Rolls::iterator rollI)
for (uint32 i = 0; i < max_slot; ++i)
{
LootItem* lootItem = loot.LootItemInSlot(i, player);
- player->SendEquipError(msg, NULL, NULL, lootItem->itemid);
+ player->SendEquipError(msg, nullptr, nullptr, lootItem->itemid);
player->SendItemRetrievalMail(lootItem->itemid, lootItem->count);
}
}
diff --git a/src/server/game/Handlers/ChatHandler.cpp b/src/server/game/Handlers/ChatHandler.cpp
index cfafcb5427b..fb354886846 100644
--- a/src/server/game/Handlers/ChatHandler.cpp
+++ b/src/server/game/Handlers/ChatHandler.cpp
@@ -360,7 +360,7 @@ void WorldSession::HandleChatMessage(ChatMsg type, uint32 lang, std::string msg,
case CHAT_MSG_RAID_WARNING:
{
Group* group = GetPlayer()->GetGroup();
- if (!group || !group->isRaidGroup() || !(group->IsLeader(GetPlayer()->GetGUID()) || group->IsAssistant(GetPlayer()->GetGUID())) || group->isBGGroup())
+ if (!group || !(group->isRaidGroup() || sWorld->getBoolConfig(CONFIG_CHAT_PARTY_RAID_WARNINGS)) || !(group->IsLeader(GetPlayer()->GetGUID()) || group->IsAssistant(GetPlayer()->GetGUID())) || group->isBGGroup())
return;
sScriptMgr->OnPlayerChat(GetPlayer(), type, lang, msg, group);
diff --git a/src/server/game/Handlers/MovementHandler.cpp b/src/server/game/Handlers/MovementHandler.cpp
index 99828a84c46..ece5d077eb2 100644
--- a/src/server/game/Handlers/MovementHandler.cpp
+++ b/src/server/game/Handlers/MovementHandler.cpp
@@ -33,6 +33,7 @@
#include "Transport.h"
#include "Vehicle.h"
#include "WaypointMovementGenerator.h"
+#include "SpellMgr.h"
#define MOVEMENT_PACKET_TIME_DELAY 0
@@ -439,6 +440,12 @@ void WorldSession::HandleMovementOpcode(OpcodeClient opcode, MovementInfo& movem
}
else
plrMover->RemoveFlag(PLAYER_FLAGS, PLAYER_FLAGS_IS_OUT_OF_BOUNDS);
+
+ if (opcode == CMSG_MOVE_JUMP)
+ {
+ plrMover->RemoveAurasWithInterruptFlags(AURA_INTERRUPT_FLAG_JUMP, 605); // Mind Control
+ plrMover->ProcSkillsAndAuras(nullptr, PROC_FLAG_JUMP, PROC_FLAG_NONE, PROC_SPELL_TYPE_MASK_ALL, PROC_SPELL_PHASE_NONE, PROC_HIT_NONE, nullptr, nullptr, nullptr);
+ }
}
}
diff --git a/src/server/game/Handlers/PetHandler.cpp b/src/server/game/Handlers/PetHandler.cpp
index 3b1ff9b7d36..4d91ee2d11b 100644
--- a/src/server/game/Handlers/PetHandler.cpp
+++ b/src/server/game/Handlers/PetHandler.cpp
@@ -592,13 +592,11 @@ void WorldSession::HandlePetAbandon(WorldPackets::Pet::PetAbandon& packet)
if (!_player->IsInWorld())
return;
+ // pet/charmed
Creature* pet = ObjectAccessor::GetCreatureOrPetOrVehicle(*_player, packet.Pet);
- if (pet)
+ if (pet && pet->ToPet() && pet->ToPet()->getPetType() == HUNTER_PET)
{
- if (pet->IsPet())
- _player->RemovePet(pet->ToPet(), PET_SAVE_AS_DELETED);
- else if (pet->GetGUID() == _player->GetCharmGUID())
- _player->StopCastingCharm();
+ _player->RemovePet((Pet*)pet, PET_SAVE_AS_DELETED);
}
}
diff --git a/src/server/game/Handlers/TaxiHandler.cpp b/src/server/game/Handlers/TaxiHandler.cpp
index dbefda3cd11..4ec66720641 100644
--- a/src/server/game/Handlers/TaxiHandler.cpp
+++ b/src/server/game/Handlers/TaxiHandler.cpp
@@ -172,6 +172,7 @@ void WorldSession::HandleActivateTaxiOpcode(WorldPackets::Taxi::ActivateTaxi& ac
if (!unit)
{
TC_LOG_DEBUG("network", "WORLD: HandleActivateTaxiOpcode - %s not found or you can't interact with it.", activateTaxi.Vendor.ToString().c_str());
+ SendActivateTaxiReply(ERR_TAXITOOFARAWAY);
return;
}
diff --git a/src/server/game/Instances/InstanceScript.cpp b/src/server/game/Instances/InstanceScript.cpp
index 621f2a18e28..2443ba4c3d9 100644
--- a/src/server/game/Instances/InstanceScript.cpp
+++ b/src/server/game/Instances/InstanceScript.cpp
@@ -41,6 +41,7 @@
#include "WorldSession.h"
#include <sstream>
#include <cstdarg>
+#include "SpellMgr.h"
BossBoundaryData::~BossBoundaryData()
{
@@ -338,6 +339,13 @@ bool InstanceScript::SetBossState(uint32 id, EncounterState state)
uint32 resInterval = GetCombatResurrectionChargeInterval();
InitializeCombatResurrections(1, resInterval);
SendEncounterStart(1, 9, resInterval, resInterval);
+
+ Map::PlayerList const &playerList = instance->GetPlayers();
+ if (!playerList.isEmpty())
+ for (Map::PlayerList::const_iterator i = playerList.begin(); i != playerList.end(); ++i)
+ if (Player* player = i->GetSource())
+ if (player->IsAlive())
+ player->ProcSkillsAndAuras(nullptr, PROC_FLAG_ENCOUNTER_START, PROC_FLAG_NONE, PROC_SPELL_TYPE_MASK_ALL, PROC_SPELL_PHASE_NONE, PROC_HIT_NONE, nullptr, nullptr, nullptr);
break;
}
case FAIL:
diff --git a/src/server/game/Loot/Loot.cpp b/src/server/game/Loot/Loot.cpp
index 681f441ea84..e9a4e0c4757 100644
--- a/src/server/game/Loot/Loot.cpp
+++ b/src/server/game/Loot/Loot.cpp
@@ -55,6 +55,7 @@ LootItem::LootItem(LootStoreItem const& li)
is_blocked = 0;
is_underthreshold = 0;
is_counted = 0;
+ rollWinnerGUID = ObjectGuid::Empty;
canSave = true;
}
@@ -518,6 +519,13 @@ void Loot::BuildLootResponse(WorldPackets::Loot::LootResponse& packet, Player* v
// => item is lootable
slot_type = LOOT_SLOT_TYPE_ALLOW_LOOT;
}
+ else if (!items[i].rollWinnerGUID.IsEmpty())
+ {
+ if (items[i].rollWinnerGUID == viewer->GetGUID())
+ slot_type = LOOT_SLOT_TYPE_OWNER;
+ else
+ continue;
+ }
else
// item shall not be displayed.
continue;
diff --git a/src/server/game/Loot/Loot.h b/src/server/game/Loot/Loot.h
index a2c30e42a0c..f9da5537806 100644
--- a/src/server/game/Loot/Loot.h
+++ b/src/server/game/Loot/Loot.h
@@ -140,6 +140,7 @@ struct TC_GAME_API LootItem
uint8 context;
ConditionContainer conditions; // additional loot condition
GuidSet allowedGUIDs;
+ ObjectGuid rollWinnerGUID; // Stores the guid of person who won loot, if his bags are full only he can see the item in loot list!
uint8 count : 8;
bool is_looted : 1;
bool is_blocked : 1;
diff --git a/src/server/game/Maps/Map.cpp b/src/server/game/Maps/Map.cpp
index e840569672e..a0e7043532d 100644
--- a/src/server/game/Maps/Map.cpp
+++ b/src/server/game/Maps/Map.cpp
@@ -125,13 +125,20 @@ bool Map::ExistVMap(uint32 mapid, int gx, int gy)
{
if (vmgr->isMapLoadingEnabled())
{
- bool exists = vmgr->existsMap((sWorld->GetDataPath()+ "vmaps").c_str(), mapid, gx, gy);
- if (!exists)
+ VMAP::LoadResult result = vmgr->existsMap((sWorld->GetDataPath() + "vmaps").c_str(), mapid, gx, gy);
+ std::string name = vmgr->getDirFileName(mapid, gx, gy);
+ switch (result)
{
- std::string name = vmgr->getDirFileName(mapid, gx, gy);
- TC_LOG_ERROR("maps", "VMap file '%s' does not exist", (sWorld->GetDataPath()+"vmaps/"+name).c_str());
- TC_LOG_ERROR("maps", "Please place VMAP-files (*.vmtree and *.vmtile) in the vmap-directory (%s), or correct the DataDir setting in your worldserver.conf file.", (sWorld->GetDataPath()+"vmaps/").c_str());
- return false;
+ case VMAP::LoadResult::Success:
+ break;
+ case VMAP::LoadResult::FileNotFound:
+ TC_LOG_ERROR("maps", "VMap file '%s' does not exist", (sWorld->GetDataPath() + "vmaps/" + name).c_str());
+ TC_LOG_ERROR("maps", "Please place VMAP files (*.vmtree and *.vmtile) in the vmap directory (%s), or correct the DataDir setting in your worldserver.conf file.", (sWorld->GetDataPath() + "vmaps/").c_str());
+ return false;
+ case VMAP::LoadResult::VersionMismatch:
+ TC_LOG_ERROR("maps", "VMap file '%s' couldn't be loaded", (sWorld->GetDataPath() + "vmaps/" + name).c_str());
+ TC_LOG_ERROR("maps", "This is because the version of the VMap file and the version of this module are different, please re-extract the maps with the tools compiled with this module.");
+ return false;
}
}
}
@@ -2878,9 +2885,9 @@ float Map::GetWaterLevel(PhaseShift const& phaseShift, float x, float y) const
return 0;
}
-bool Map::isInLineOfSight(PhaseShift const& phaseShift, float x1, float y1, float z1, float x2, float y2, float z2) const
+bool Map::isInLineOfSight(PhaseShift const& phaseShift, float x1, float y1, float z1, float x2, float y2, float z2, VMAP::ModelIgnoreFlags ignoreFlags) const
{
- return VMAP::VMapFactory::createOrGetVMapManager()->isInLineOfSight(PhasingHandler::GetTerrainMapId(phaseShift, this, x1, y1), x1, y1, z1, x2, y2, z2)
+ return VMAP::VMapFactory::createOrGetVMapManager()->isInLineOfSight(PhasingHandler::GetTerrainMapId(phaseShift, this, x1, y1), x1, y1, z1, x2, y2, z2, ignoreFlags)
&& _dynamicTree.isInLineOfSight({ x1, y1, z1 }, { x2, y2, z2 }, phaseShift);
}
diff --git a/src/server/game/Maps/Map.h b/src/server/game/Maps/Map.h
index 7d453f0406a..5498b097b54 100644
--- a/src/server/game/Maps/Map.h
+++ b/src/server/game/Maps/Map.h
@@ -67,6 +67,7 @@ enum WeatherState : uint32;
namespace Trinity { struct ObjectUpdater; }
namespace G3D { class Plane; }
+namespace VMAP { enum class ModelIgnoreFlags : uint32; }
struct ScriptAction
{
@@ -493,7 +494,7 @@ class TC_GAME_API Map : public GridRefManager<NGridType>
float GetWaterOrGroundLevel(PhaseShift const& phaseShift, float x, float y, float z, float* ground = nullptr, bool swim = false) const;
float GetHeight(PhaseShift const& phaseShift, float x, float y, float z, bool vmap = true, float maxSearchDist = DEFAULT_HEIGHT_SEARCH) const;
- bool isInLineOfSight(PhaseShift const& phaseShift, float x1, float y1, float z1, float x2, float y2, float z2) const;
+ bool isInLineOfSight(PhaseShift const& phaseShift, float x1, float y1, float z1, float x2, float y2, float z2, VMAP::ModelIgnoreFlags ignoreFlags) const;
void Balance() { _dynamicTree.balance(); }
void RemoveGameObjectModel(const GameObjectModel& model) { _dynamicTree.remove(model); }
void InsertGameObjectModel(const GameObjectModel& model) { _dynamicTree.insert(model); }
diff --git a/src/server/game/Miscellaneous/Language.h b/src/server/game/Miscellaneous/Language.h
index 039c3b81604..820edc8adb9 100644
--- a/src/server/game/Miscellaneous/Language.h
+++ b/src/server/game/Miscellaneous/Language.h
@@ -927,7 +927,8 @@ enum TrinityStrings
LANG_ACCOUNT_BNET_NOT_LINKED = 1189,
LANG_DISALLOW_TICKETS_CONFIG = 1190,
LANG_BAN_EXISTS = 1191,
- // Room for more level 3 1192-1198 not used
+ LANG_CHANGEACCOUNT_SUCCESS = 1192,
+ // Room for more level 3 1193-1198 not used
// Debug commands
LANG_DEBUG_AREATRIGGER_LEFT = 1999,
diff --git a/src/server/game/Movement/MovementGenerators/FleeingMovementGenerator.cpp b/src/server/game/Movement/MovementGenerators/FleeingMovementGenerator.cpp
index c4cd065ccbf..f3e3f7db303 100644
--- a/src/server/game/Movement/MovementGenerators/FleeingMovementGenerator.cpp
+++ b/src/server/game/Movement/MovementGenerators/FleeingMovementGenerator.cpp
@@ -54,7 +54,7 @@ void FleeingMovementGenerator<T>::_setTargetLocation(T* owner)
Position mypos = owner->GetPosition();
bool isInLOS = VMAP::VMapFactory::createOrGetVMapManager()->isInLineOfSight(
PhasingHandler::GetTerrainMapId(owner->GetPhaseShift(), owner->GetMap(), mypos.m_positionX, mypos.m_positionY),
- mypos.m_positionX, mypos.m_positionY, mypos.m_positionZ + 2.0f, x, y, z + 2.0f);
+ mypos.m_positionX, mypos.m_positionY, mypos.m_positionZ + 2.0f, x, y, z + 2.0f, VMAP::ModelIgnoreFlags::Nothing);
if (!isInLOS)
{
i_nextCheckTime.Reset(200);
diff --git a/src/server/game/Movement/MovementGenerators/WaypointMovementGenerator.cpp b/src/server/game/Movement/MovementGenerators/WaypointMovementGenerator.cpp
index 51e54b3ba26..c9f75345754 100755
--- a/src/server/game/Movement/MovementGenerators/WaypointMovementGenerator.cpp
+++ b/src/server/game/Movement/MovementGenerators/WaypointMovementGenerator.cpp
@@ -120,6 +120,9 @@ bool WaypointMovementGenerator<Creature>::StartMove(Creature* creature)
if (!i_path || i_path->nodes.empty())
return false;
+ if (Stopped())
+ return true;
+
bool transportPath = creature->GetTransport() != nullptr;
if (IsArrivalDone)
diff --git a/src/server/game/Scripting/ScriptMgr.cpp b/src/server/game/Scripting/ScriptMgr.cpp
index 2367e26218c..c7e87633db0 100644
--- a/src/server/game/Scripting/ScriptMgr.cpp
+++ b/src/server/game/Scripting/ScriptMgr.cpp
@@ -402,7 +402,8 @@ class CreatureGameObjectAreaTriggerScriptRegistrySwapHooks
ASSERT(!creature->IsCharmed(),
"There is a disabled AI which is still loaded.");
- creature->AI()->EnterEvadeMode();
+ if (creature->IsAlive())
+ creature->AI()->EnterEvadeMode();
}
static void UnloadDestroyScript(Creature* creature)
diff --git a/src/server/game/Spells/Spell.cpp b/src/server/game/Spells/Spell.cpp
index 09d994e985d..d9b428c0598 100644
--- a/src/server/game/Spells/Spell.cpp
+++ b/src/server/game/Spells/Spell.cpp
@@ -1936,7 +1936,7 @@ void Spell::SearchChainTargets(std::list<WorldObject*>& targets, uint32 chainTar
if (Unit* unit = (*itr)->ToUnit())
{
uint32 deficit = unit->GetMaxHealth() - unit->GetHealth();
- if ((deficit > maxHPDeficit || foundItr == tempTargets.end()) && target->IsWithinDist(unit, jumpRadius) && target->IsWithinLOSInMap(unit))
+ if ((deficit > maxHPDeficit || foundItr == tempTargets.end()) && target->IsWithinDist(unit, jumpRadius) && target->IsWithinLOSInMap(unit, VMAP::ModelIgnoreFlags::M2))
{
foundItr = itr;
maxHPDeficit = deficit;
@@ -1951,10 +1951,10 @@ void Spell::SearchChainTargets(std::list<WorldObject*>& targets, uint32 chainTar
{
if (foundItr == tempTargets.end())
{
- if ((!isBouncingFar || target->IsWithinDist(*itr, jumpRadius)) && target->IsWithinLOSInMap(*itr))
+ if ((!isBouncingFar || target->IsWithinDist(*itr, jumpRadius)) && target->IsWithinLOSInMap(*itr, VMAP::ModelIgnoreFlags::M2))
foundItr = itr;
}
- else if (target->GetDistanceOrder(*itr, *foundItr) && target->IsWithinLOSInMap(*itr))
+ else if (target->GetDistanceOrder(*itr, *foundItr) && target->IsWithinLOSInMap(*itr, VMAP::ModelIgnoreFlags::M2))
foundItr = itr;
}
}
@@ -2020,7 +2020,6 @@ void Spell::prepareDataForTriggerSystem()
// For other spells trigger procflags are set in Spell::DoAllEffectOnTarget
// Because spell positivity is dependant on target
}
- m_hitMask = PROC_HIT_NONE;
// Hunter trap spells - activation proc for Lock and Load, Entrapment and Misdirection
if (m_spellInfo->SpellFamilyName == SPELLFAMILY_HUNTER &&
@@ -2842,6 +2841,9 @@ bool Spell::UpdateChanneledTargetList()
range = m_spellInfo->GetMaxRange(m_spellInfo->IsPositive());
if (Player* modOwner = m_caster->GetSpellModOwner())
modOwner->ApplySpellMod(m_spellInfo->Id, SPELLMOD_RANGE, range, this);
+
+ // add little tolerance level
+ range += std::min(MAX_SPELL_RANGE_TOLERANCE, range*0.1f); // 10% but no more than MAX_SPELL_RANGE_TOLERANCE
}
for (std::vector<TargetInfo>::iterator ihit = m_UniqueTargetInfo.begin(); ihit != m_UniqueTargetInfo.end(); ++ihit)
@@ -3380,8 +3382,14 @@ void Spell::handle_immediate()
// process immediate effects (items, ground, etc.) also initialize some variables
_handle_immediate_phase();
- for (std::vector<TargetInfo>::iterator ihit = m_UniqueTargetInfo.begin(); ihit != m_UniqueTargetInfo.end(); ++ihit)
- DoAllEffectOnTarget(&(*ihit));
+ // consider spell hit for some spells without target, so they may proc on finish phase correctly
+ if (m_UniqueTargetInfo.empty())
+ m_hitMask = PROC_HIT_NORMAL;
+ else
+ {
+ for (std::vector<TargetInfo>::iterator ihit = m_UniqueTargetInfo.begin(); ihit != m_UniqueTargetInfo.end(); ++ihit)
+ DoAllEffectOnTarget(&(*ihit));
+ }
for (std::vector<GOTargetInfo>::iterator ihit = m_UniqueGOTargetInfo.begin(); ihit != m_UniqueGOTargetInfo.end(); ++ihit)
DoAllEffectOnTarget(&(*ihit));
@@ -4999,7 +5007,7 @@ SpellCastResult Spell::CheckCast(bool strict, uint32* param1 /*= nullptr*/, uint
if (DynamicObject* dynObj = m_caster->GetDynObject(m_triggeredByAuraSpell->Id))
losTarget = dynObj;
- if (!m_spellInfo->HasAttribute(SPELL_ATTR2_CAN_TARGET_NOT_IN_LOS) && !DisableMgr::IsDisabledFor(DISABLE_TYPE_SPELL, m_spellInfo->Id, NULL, SPELL_DISABLE_LOS) && !target->IsWithinLOSInMap(losTarget))
+ if (!m_spellInfo->HasAttribute(SPELL_ATTR2_CAN_TARGET_NOT_IN_LOS) && !DisableMgr::IsDisabledFor(DISABLE_TYPE_SPELL, m_spellInfo->Id, NULL, SPELL_DISABLE_LOS) && !target->IsWithinLOSInMap(losTarget, VMAP::ModelIgnoreFlags::M2))
return SPELL_FAILED_LINE_OF_SIGHT;
}
}
@@ -5011,7 +5019,7 @@ SpellCastResult Spell::CheckCast(bool strict, uint32* param1 /*= nullptr*/, uint
float x, y, z;
m_targets.GetDstPos()->GetPosition(x, y, z);
- if (!m_spellInfo->HasAttribute(SPELL_ATTR2_CAN_TARGET_NOT_IN_LOS) && !DisableMgr::IsDisabledFor(DISABLE_TYPE_SPELL, m_spellInfo->Id, NULL, SPELL_DISABLE_LOS) && !m_caster->IsWithinLOS(x, y, z))
+ if (!m_spellInfo->HasAttribute(SPELL_ATTR2_CAN_TARGET_NOT_IN_LOS) && !DisableMgr::IsDisabledFor(DISABLE_TYPE_SPELL, m_spellInfo->Id, NULL, SPELL_DISABLE_LOS) && !m_caster->IsWithinLOS(x, y, z, VMAP::ModelIgnoreFlags::M2))
return SPELL_FAILED_LINE_OF_SIGHT;
}
@@ -5294,6 +5302,10 @@ SpellCastResult Spell::CheckCast(bool strict, uint32* param1 /*= nullptr*/, uint
if (!target)
return SPELL_FAILED_DONT_REPORT;
+ // first we must check to see if the target is in LoS. A path can usually be built but LoS matters for charge spells
+ if (!target->IsWithinLOSInMap(m_caster)) //Do full LoS/Path check. Don't exclude m2
+ return SPELL_FAILED_LINE_OF_SIGHT;
+
float objSize = target->GetObjectSize();
float range = m_spellInfo->GetMaxRange(true, m_caster, this) * 1.5f + objSize; // can't be overly strict
@@ -6045,6 +6057,10 @@ SpellCastResult Spell::CheckRange(bool strict) const
float minRange, maxRange;
std::tie(minRange, maxRange) = GetMinMaxRange(strict);
+ // dont check max_range to strictly after cast
+ if (m_spellInfo->RangeEntry && m_spellInfo->RangeEntry->Flags != SPELL_RANGE_MELEE && !strict)
+ maxRange += std::min(MAX_SPELL_RANGE_TOLERANCE, maxRange*0.1f); // 10% but no more than MAX_SPELL_RANGE_TOLERANCE
+
// get square values for sqr distance checks
minRange *= minRange;
maxRange *= maxRange;
@@ -6845,7 +6861,7 @@ bool Spell::CheckEffectTarget(Unit const* target, SpellEffectInfo const* effect,
/// @todo shit below shouldn't be here, but it's temporary
//Check targets for LOS visibility
if (losPosition)
- return target->IsWithinLOS(losPosition->GetPositionX(), losPosition->GetPositionY(), losPosition->GetPositionZ());
+ return target->IsWithinLOS(losPosition->GetPositionX(), losPosition->GetPositionY(), losPosition->GetPositionZ(), VMAP::ModelIgnoreFlags::M2);
else
{
// Get GO cast coordinates if original caster -> GO
@@ -6854,7 +6870,7 @@ bool Spell::CheckEffectTarget(Unit const* target, SpellEffectInfo const* effect,
caster = m_caster->GetMap()->GetGameObject(m_originalCasterGUID);
if (!caster)
caster = m_caster;
- if (target != m_caster && !target->IsWithinLOSInMap(caster))
+ if (target != m_caster && !target->IsWithinLOSInMap(caster, VMAP::ModelIgnoreFlags::M2))
return false;
}
diff --git a/src/server/game/Spells/Spell.h b/src/server/game/Spells/Spell.h
index cd4f3f51a08..c0a9dff527b 100644
--- a/src/server/game/Spells/Spell.h
+++ b/src/server/game/Spells/Spell.h
@@ -65,6 +65,7 @@ enum TriggerCastFlags : uint32;
enum WeaponAttackType : uint8;
#define SPELL_CHANNEL_UPDATE_INTERVAL (1 * IN_MILLISECONDS)
+#define MAX_SPELL_RANGE_TOLERANCE 3.0f
enum SpellCastFlags
{
diff --git a/src/server/game/Spells/SpellInfo.h b/src/server/game/Spells/SpellInfo.h
index 0e04e33937d..65aef5dca41 100644
--- a/src/server/game/Spells/SpellInfo.h
+++ b/src/server/game/Spells/SpellInfo.h
@@ -225,7 +225,7 @@ enum SpellAuraInterruptFlags : uint32
AURA_INTERRUPT_FLAG_CAST = 0x00000004, // 2 cast any spells
AURA_INTERRUPT_FLAG_MOVE = 0x00000008, // 3 removed by any movement
AURA_INTERRUPT_FLAG_TURNING = 0x00000010, // 4 removed by any turning
- AURA_INTERRUPT_FLAG_JUMP = 0x00000020, // 5 removed by entering combat
+ AURA_INTERRUPT_FLAG_JUMP = 0x00000020, // 5 removed by jumping
AURA_INTERRUPT_FLAG_NOT_MOUNTED = 0x00000040, // 6 removed by dismounting
AURA_INTERRUPT_FLAG_NOT_ABOVEWATER = 0x00000080, // 7 removed by entering water
AURA_INTERRUPT_FLAG_NOT_UNDERWATER = 0x00000100, // 8 removed by leaving water
diff --git a/src/server/game/Spells/SpellMgr.cpp b/src/server/game/Spells/SpellMgr.cpp
index 483f695283f..2bb498cf9af 100644
--- a/src/server/game/Spells/SpellMgr.cpp
+++ b/src/server/game/Spells/SpellMgr.cpp
@@ -1457,6 +1457,15 @@ void SpellMgr::LoadSpellProcs()
isTriggerAura[SPELL_AURA_MOD_SPELL_DAMAGE_FROM_CASTER] = true;
isTriggerAura[SPELL_AURA_MOD_SPELL_CRIT_CHANCE] = true;
isTriggerAura[SPELL_AURA_ABILITY_IGNORE_AURASTATE] = true;
+ isTriggerAura[SPELL_AURA_MOD_INVISIBILITY] = true;
+ isTriggerAura[SPELL_AURA_FORCE_REACTION] = true;
+ isTriggerAura[SPELL_AURA_MOD_TAUNT] = true;
+ isTriggerAura[SPELL_AURA_MOD_DETAUNT] = true;
+ isTriggerAura[SPELL_AURA_MOD_DAMAGE_PERCENT_DONE] = true;
+ isTriggerAura[SPELL_AURA_MOD_ATTACK_POWER_PCT] = true;
+ isTriggerAura[SPELL_AURA_MOD_HIT_CHANCE] = true;
+ isTriggerAura[SPELL_AURA_MOD_WEAPON_CRIT_PERCENT] = true;
+ isTriggerAura[SPELL_AURA_MOD_BLOCK_PERCENT] = true;
isTriggerAura[SPELL_AURA_MOD_ROOT_2] = true;
isAlwaysTriggeredAura[SPELL_AURA_OVERRIDE_CLASS_SCRIPTS] = true;
@@ -1466,6 +1475,7 @@ void SpellMgr::LoadSpellProcs()
isAlwaysTriggeredAura[SPELL_AURA_MOD_ROOT] = true;
isAlwaysTriggeredAura[SPELL_AURA_MOD_STUN] = true;
isAlwaysTriggeredAura[SPELL_AURA_TRANSFORM] = true;
+ isAlwaysTriggeredAura[SPELL_AURA_MOD_INVISIBILITY] = true;
isAlwaysTriggeredAura[SPELL_AURA_SPELL_MAGNET] = true;
isAlwaysTriggeredAura[SPELL_AURA_SCHOOL_ABSORB] = true;
isAlwaysTriggeredAura[SPELL_AURA_MOD_STEALTH] = true;
@@ -1478,6 +1488,7 @@ void SpellMgr::LoadSpellProcs()
spellTypeMask[SPELL_AURA_MOD_ROOT_2] = PROC_SPELL_TYPE_DAMAGE;
spellTypeMask[SPELL_AURA_MOD_STUN] = PROC_SPELL_TYPE_DAMAGE;
spellTypeMask[SPELL_AURA_TRANSFORM] = PROC_SPELL_TYPE_DAMAGE;
+ spellTypeMask[SPELL_AURA_MOD_INVISIBILITY] = PROC_SPELL_TYPE_DAMAGE;
// This generates default procs to retain compatibility with previous proc system
TC_LOG_INFO("server.loading", "Generating spell proc data from SpellMap...");
@@ -1561,14 +1572,30 @@ void SpellMgr::LoadSpellProcs()
procEntry.SpellPhaseMask = PROC_SPELL_PHASE_HIT;
procEntry.HitMask = PROC_HIT_NONE; // uses default proc @see SpellMgr::CanSpellTriggerProcOnEvent
- // Reflect auras should only proc off reflects
for (SpellEffectInfo const* effect : spellInfo->GetEffectsForDifficulty(DIFFICULTY_NONE))
{
- if (effect && (effect->IsAura(SPELL_AURA_REFLECT_SPELLS) || effect->IsAura(SPELL_AURA_REFLECT_SPELLS_SCHOOL)))
+ if (!effect || !effect->IsAura())
+ continue;
+
+ switch (effect->ApplyAuraName)
{
- procEntry.HitMask = PROC_HIT_REFLECT;
- break;
+ // Reflect auras should only proc off reflects
+ case SPELL_AURA_REFLECT_SPELLS:
+ case SPELL_AURA_REFLECT_SPELLS_SCHOOL:
+ procEntry.HitMask = PROC_HIT_REFLECT;
+ break;
+ // Only drop charge on crit
+ case SPELL_AURA_MOD_WEAPON_CRIT_PERCENT:
+ procEntry.HitMask = PROC_HIT_CRITICAL;
+ break;
+ // Only drop charge on block
+ case SPELL_AURA_MOD_BLOCK_PERCENT:
+ procEntry.HitMask = PROC_HIT_BLOCK;
+ break;
+ default:
+ continue;
}
+ break;
}
procEntry.AttributesMask = 0;
@@ -2850,7 +2877,9 @@ void SpellMgr::LoadSpellInfoCorrections()
ApplySpellFix({
50661, // Weakened Resolve
- 68979 // Unleashed Souls
+ 68979, // Unleashed Souls
+ 48714, // Compelled
+ 7853, // The Art of Being a Water Terror: Force Cast on Player
}, [](SpellInfo* spellInfo)
{
spellInfo->RangeEntry = sSpellRangeStore.LookupEntry(13); // 50000yd
diff --git a/src/server/game/World/World.cpp b/src/server/game/World/World.cpp
index a6cf260746d..cde18f19ffe 100644
--- a/src/server/game/World/World.cpp
+++ b/src/server/game/World/World.cpp
@@ -1484,6 +1484,9 @@ void World::LoadConfigSettings(bool reload)
// prevent character rename on character customization
m_bool_configs[CONFIG_PREVENT_RENAME_CUSTOMIZATION] = sConfigMgr->GetBoolDefault("PreventRenameCharacterOnCustomization", false);
+ // Allow 5-man parties to use raid warnings
+ m_bool_configs[CONFIG_CHAT_PARTY_RAID_WARNINGS] = sConfigMgr->GetBoolDefault("PartyRaidWarnings", false);
+
// Check Invalid Position
m_bool_configs[CONFIG_CREATURE_CHECK_INVALID_POSITION] = sConfigMgr->GetBoolDefault("Creature.CheckInvalidPosition", false);
m_bool_configs[CONFIG_GAME_OBJECT_CHECK_INVALID_POSITION] = sConfigMgr->GetBoolDefault("GameObject.CheckInvalidPosition", false);
@@ -3612,6 +3615,15 @@ void World::UpdateCharacterInfoLevel(ObjectGuid const& guid, uint8 level)
itr->second.Level = level;
}
+void World::UpdateCharacterInfoAccount(ObjectGuid const& guid, uint32 accountId)
+{
+ auto itr = _characterInfoStore.find(guid);
+ if (itr == _characterInfoStore.end())
+ return;
+
+ itr->second.AccountId = accountId;
+}
+
void World::UpdateCharacterInfoDeleted(ObjectGuid const& guid, bool deleted, std::string const* name /*= nullptr*/)
{
CharacterInfoContainer::iterator itr = _characterInfoStore.find(guid);
diff --git a/src/server/game/World/World.h b/src/server/game/World/World.h
index 972da5bfa89..1d0d01f4b1f 100644
--- a/src/server/game/World/World.h
+++ b/src/server/game/World/World.h
@@ -122,6 +122,7 @@ enum WorldBoolConfigs
CONFIG_SAVE_RESPAWN_TIME_IMMEDIATELY,
CONFIG_WEATHER,
CONFIG_QUEST_IGNORE_RAID,
+ CONFIG_CHAT_PARTY_RAID_WARNINGS,
CONFIG_DETECT_POS_COLLISION,
CONFIG_RESTRICTED_LFG_CHANNEL,
CONFIG_CHAT_FAKE_MESSAGE_PREVENTING,
@@ -803,6 +804,7 @@ class TC_GAME_API World
bool HasCharacterInfo(ObjectGuid const& guid) { return _characterInfoStore.find(guid) != _characterInfoStore.end(); }
void UpdateCharacterInfo(ObjectGuid const& guid, std::string const& name, uint8 gender = GENDER_NONE, uint8 race = RACE_NONE);
void UpdateCharacterInfoLevel(ObjectGuid const& guid, uint8 level);
+ void UpdateCharacterInfoAccount(ObjectGuid const& guid, uint32 accountId);
void UpdateCharacterInfoDeleted(ObjectGuid const& guid, bool deleted, std::string const* name = nullptr);
uint32 GetCleaningFlags() const { return m_CleaningFlags; }
diff --git a/src/server/scripts/Commands/cs_character.cpp b/src/server/scripts/Commands/cs_character.cpp
index 101d522e85b..e2a29b62bea 100644
--- a/src/server/scripts/Commands/cs_character.cpp
+++ b/src/server/scripts/Commands/cs_character.cpp
@@ -61,6 +61,7 @@ public:
{ "customize", rbac::RBAC_PERM_COMMAND_CHARACTER_CUSTOMIZE, true, &HandleCharacterCustomizeCommand, "", },
{ "changefaction", rbac::RBAC_PERM_COMMAND_CHARACTER_CHANGEFACTION, true, &HandleCharacterChangeFactionCommand, "", },
{ "changerace", rbac::RBAC_PERM_COMMAND_CHARACTER_CHANGERACE, true, &HandleCharacterChangeRaceCommand, "", },
+ { "changeaccount", rbac::RBAC_PERM_COMMAND_CHARACTER_CHANGEACCOUNT, true, &HandleCharacterChangeAccountCommand, "", },
{ "deleted", rbac::RBAC_PERM_COMMAND_CHARACTER_DELETED, true, NULL, "", characterDeletedCommandTable },
{ "erase", rbac::RBAC_PERM_COMMAND_CHARACTER_ERASE, true, &HandleCharacterEraseCommand, "", },
{ "level", rbac::RBAC_PERM_COMMAND_CHARACTER_LEVEL, true, &HandleCharacterLevelCommand, "", },
@@ -551,6 +552,86 @@ public:
return true;
}
+ static bool HandleCharacterChangeAccountCommand(ChatHandler* handler, char const* args)
+ {
+ char* playerNameStr;
+ char* accountNameStr;
+ handler->extractOptFirstArg(const_cast<char*>(args), &playerNameStr, &accountNameStr);
+ if (!accountNameStr)
+ return false;
+
+ ObjectGuid targetGuid;
+ std::string targetName;
+ if (!handler->extractPlayerTarget(playerNameStr, nullptr, &targetGuid, &targetName))
+ return false;
+
+ CharacterInfo const* characterInfo = sWorld->GetCharacterInfo(targetGuid);
+ if (!characterInfo)
+ {
+ handler->SendSysMessage(LANG_PLAYER_NOT_FOUND);
+ handler->SetSentErrorMessage(true);
+ return false;
+ }
+
+ uint32 oldAccountId = characterInfo->AccountId;
+ uint32 newAccountId = oldAccountId;
+
+ std::string accountName(accountNameStr);
+ if (!Utf8ToUpperOnlyLatin(accountName))
+ {
+ handler->PSendSysMessage(LANG_ACCOUNT_NOT_EXIST, accountName.c_str());
+ handler->SetSentErrorMessage(true);
+ return false;
+ }
+
+ PreparedStatement* stmt = LoginDatabase.GetPreparedStatement(LOGIN_SEL_ACCOUNT_ID_BY_NAME);
+ stmt->setString(0, accountName);
+ if (PreparedQueryResult result = LoginDatabase.Query(stmt))
+ newAccountId = (*result)[0].GetUInt32();
+ else
+ {
+ handler->PSendSysMessage(LANG_ACCOUNT_NOT_EXIST, accountName.c_str());
+ handler->SetSentErrorMessage(true);
+ return false;
+ }
+
+ // nothing to do :)
+ if (newAccountId == oldAccountId)
+ return true;
+
+ if (uint32 charCount = AccountMgr::GetCharactersCount(newAccountId))
+ {
+ if (charCount >= sWorld->getIntConfig(CONFIG_CHARACTERS_PER_REALM))
+ {
+ handler->PSendSysMessage(LANG_ACCOUNT_CHARACTER_LIST_FULL, accountName.c_str(), newAccountId);
+ handler->SetSentErrorMessage(true);
+ return false;
+ }
+ }
+
+ stmt = CharacterDatabase.GetPreparedStatement(CHAR_UPD_ACCOUNT_BY_GUID);
+ stmt->setUInt32(0, newAccountId);
+ stmt->setUInt32(1, targetGuid.GetCounter());
+ CharacterDatabase.DirectExecute(stmt);
+
+ sWorld->UpdateRealmCharCount(oldAccountId);
+ sWorld->UpdateRealmCharCount(newAccountId);
+
+ sWorld->UpdateCharacterInfoAccount(targetGuid, newAccountId);
+
+ handler->PSendSysMessage(LANG_CHANGEACCOUNT_SUCCESS, targetName.c_str(), accountName.c_str());
+
+ std::string logString = Trinity::StringFormat("changed ownership of player %s (%s) from account %u to account %u", targetName.c_str(), targetGuid.ToString().c_str(), oldAccountId, newAccountId);
+ if (WorldSession* session = handler->GetSession())
+ {
+ if (Player* player = session->GetPlayer())
+ sLog->outCommand(session->GetAccountId(), "GM %s (Account: %u) %s", player->GetName().c_str(), session->GetAccountId(), logString.c_str());
+ }
+ else
+ sLog->outCommand(0, "%s %s", handler->GetTrinityString(LANG_CONSOLE), logString.c_str());
+ return true;
+ }
+
static bool HandleCharacterReputationCommand(ChatHandler* handler, char const* args)
{
Player* target;
diff --git a/src/server/scripts/Commands/cs_npc.cpp b/src/server/scripts/Commands/cs_npc.cpp
index c72893c77a9..06ebeb5eb71 100644
--- a/src/server/scripts/Commands/cs_npc.cpp
+++ b/src/server/scripts/Commands/cs_npc.cpp
@@ -51,7 +51,7 @@ struct EnumName
#define CREATE_NAMED_ENUM(VALUE) { VALUE, STRINGIZE(VALUE) }
#define NPC_FLAG_COUNT 24
-#define FLAGS_EXTRA_COUNT 19
+#define FLAGS_EXTRA_COUNT 20
EnumName<NPCFlags, uint32> const npcFlagTexts[NPC_FLAG_COUNT] =
{
@@ -193,6 +193,7 @@ EnumName<CreatureFlagsExtra> const flagsExtra[FLAGS_EXTRA_COUNT] =
CREATE_NAMED_ENUM(CREATURE_FLAG_EXTRA_NO_XP_AT_KILL),
CREATE_NAMED_ENUM(CREATURE_FLAG_EXTRA_TRIGGER),
CREATE_NAMED_ENUM(CREATURE_FLAG_EXTRA_NO_TAUNT),
+ CREATE_NAMED_ENUM(CREATURE_FLAG_EXTRA_NO_MOVE_FLAGS_UPDATE),
CREATE_NAMED_ENUM(CREATURE_FLAG_EXTRA_WORLDEVENT),
CREATE_NAMED_ENUM(CREATURE_FLAG_EXTRA_GUARD),
CREATE_NAMED_ENUM(CREATURE_FLAG_EXTRA_NO_CRIT),
diff --git a/src/server/scripts/Northrend/ChamberOfAspects/RubySanctum/boss_saviana_ragefire.cpp b/src/server/scripts/Northrend/ChamberOfAspects/RubySanctum/boss_saviana_ragefire.cpp
index f43052ebb0a..79a0f293fb2 100644
--- a/src/server/scripts/Northrend/ChamberOfAspects/RubySanctum/boss_saviana_ragefire.cpp
+++ b/src/server/scripts/Northrend/ChamberOfAspects/RubySanctum/boss_saviana_ragefire.cpp
@@ -20,6 +20,7 @@
#include "MotionMaster.h"
#include "ruby_sanctum.h"
#include "ScriptedCreature.h"
+#include "SpellMgr.h"
#include "SpellScript.h"
enum Texts
@@ -76,14 +77,14 @@ class boss_saviana_ragefire : public CreatureScript
struct boss_saviana_ragefireAI : public BossAI
{
- boss_saviana_ragefireAI(Creature* creature) : BossAI(creature, DATA_SAVIANA_RAGEFIRE)
- {
- }
+ boss_saviana_ragefireAI(Creature* creature) : BossAI(creature, DATA_SAVIANA_RAGEFIRE) { }
void Reset() override
{
_Reset();
me->SetReactState(REACT_AGGRESSIVE);
+ me->SetCanFly(false);
+ me->SetDisableGravity(false);
}
void EnterCombat(Unit* /*who*/) override
@@ -91,15 +92,15 @@ class boss_saviana_ragefire : public CreatureScript
_EnterCombat();
Talk(SAY_AGGRO);
events.Reset();
- events.ScheduleEvent(EVENT_ENRAGE, 20000, EVENT_GROUP_LAND_PHASE);
- events.ScheduleEvent(EVENT_FLAME_BREATH, 14000, EVENT_GROUP_LAND_PHASE);
- events.ScheduleEvent(EVENT_FLIGHT, 60000);
+ events.ScheduleEvent(EVENT_ENRAGE, Seconds(20), EVENT_GROUP_LAND_PHASE);
+ events.ScheduleEvent(EVENT_FLAME_BREATH, Seconds(14), EVENT_GROUP_LAND_PHASE);
+ events.ScheduleEvent(EVENT_FLIGHT, Seconds(60), EVENT_GROUP_LAND_PHASE);
}
void JustDied(Unit* /*killer*/) override
{
_JustDied();
- me->PlayDirectSound(SOUND_ID_DEATH);
+ DoPlaySoundToSet(me, SOUND_ID_DEATH);
}
void MovementInform(uint32 type, uint32 point) override
@@ -110,32 +111,32 @@ class boss_saviana_ragefire : public CreatureScript
switch (point)
{
case POINT_FLIGHT:
- events.ScheduleEvent(EVENT_CONFLAGRATION, 1000);
+ events.ScheduleEvent(EVENT_CONFLAGRATION, Seconds(1));
Talk(SAY_CONFLAGRATION);
break;
case POINT_LAND:
- events.ScheduleEvent(EVENT_LAND_GROUND, 1);
+ events.ScheduleEvent(EVENT_LAND_GROUND, Milliseconds(1));
break;
case POINT_LAND_GROUND:
me->SetCanFly(false);
me->SetDisableGravity(false);
me->RemoveByteFlag(UNIT_FIELD_BYTES_1, UNIT_BYTES_1_OFFSET_ANIM_TIER, UNIT_BYTE1_FLAG_ALWAYS_STAND | UNIT_BYTE1_FLAG_HOVER);
me->SetReactState(REACT_AGGRESSIVE);
- DoStartMovement(me->GetVictim());
+ events.ScheduleEvent(EVENT_ENRAGE, Seconds(1), EVENT_GROUP_LAND_PHASE);
+ events.ScheduleEvent(EVENT_FLAME_BREATH, Seconds(2), Seconds(4), EVENT_GROUP_LAND_PHASE);
+ events.ScheduleEvent(EVENT_FLIGHT, Seconds(50), EVENT_GROUP_LAND_PHASE);
break;
case POINT_TAKEOFF:
- events.ScheduleEvent(EVENT_AIR_MOVEMENT, 1);
+ events.ScheduleEvent(EVENT_AIR_MOVEMENT, Milliseconds(1));
break;
default:
break;
}
}
- void JustReachedHome() override
+ void EnterEvadeMode(EvadeReason /*why*/) override
{
- _JustReachedHome();
- me->SetCanFly(false);
- me->SetDisableGravity(false);
+ _DespawnAtEvade();
}
void KilledUnit(Unit* victim) override
@@ -169,21 +170,20 @@ class boss_saviana_ragefire : public CreatureScript
pos.Relocate(me);
pos.m_positionZ += 10.0f;
me->GetMotionMaster()->MoveTakeoff(POINT_TAKEOFF, pos);
- events.ScheduleEvent(EVENT_FLIGHT, 50000);
- events.DelayEvents(12500, EVENT_GROUP_LAND_PHASE);
+ events.CancelEventGroup(EVENT_GROUP_LAND_PHASE);
break;
}
case EVENT_CONFLAGRATION:
- DoCast(me, SPELL_CONFLAGRATION, true);
+ DoCastSelf(SPELL_CONFLAGRATION, true);
break;
case EVENT_ENRAGE:
- DoCast(me, SPELL_ENRAGE);
+ DoCastSelf(SPELL_ENRAGE);
Talk(EMOTE_ENRAGED);
- events.ScheduleEvent(EVENT_ENRAGE, urand(15000, 20000), EVENT_GROUP_LAND_PHASE);
+ events.Repeat(Seconds(24));
break;
case EVENT_FLAME_BREATH:
DoCastVictim(SPELL_FLAME_BREATH);
- events.ScheduleEvent(EVENT_FLAME_BREATH, urand(20000, 30000), EVENT_GROUP_LAND_PHASE);
+ events.Repeat(Seconds(20), Seconds(30));
break;
case EVENT_AIR_MOVEMENT:
me->GetMotionMaster()->MovePoint(POINT_FLIGHT, SavianaRagefireFlyOutPos);
@@ -220,6 +220,7 @@ class ConflagrationTargetSelector
}
};
+// 74452 - Conflagration
class spell_saviana_conflagration_init : public SpellScriptLoader
{
public:
@@ -229,6 +230,14 @@ class spell_saviana_conflagration_init : public SpellScriptLoader
{
PrepareSpellScript(spell_saviana_conflagration_init_SpellScript);
+ bool Validate(SpellInfo const* /*spell*/) override
+ {
+ if (!sSpellMgr->GetSpellInfo(SPELL_FLAME_BEACON)
+ || !sSpellMgr->GetSpellInfo(SPELL_CONFLAGRATION_2))
+ return false;
+ return true;
+ }
+
void FilterTargets(std::list<WorldObject*>& targets)
{
targets.remove_if(ConflagrationTargetSelector());
@@ -257,6 +266,7 @@ class spell_saviana_conflagration_init : public SpellScriptLoader
}
};
+// 74455 - Conflagration
class spell_saviana_conflagration_throwback : public SpellScriptLoader
{
public:
diff --git a/src/server/scripts/Northrend/IcecrownCitadel/boss_blood_prince_council.cpp b/src/server/scripts/Northrend/IcecrownCitadel/boss_blood_prince_council.cpp
index a9c638c010d..f003260b8d1 100644
--- a/src/server/scripts/Northrend/IcecrownCitadel/boss_blood_prince_council.cpp
+++ b/src/server/scripts/Northrend/IcecrownCitadel/boss_blood_prince_council.cpp
@@ -252,10 +252,6 @@ class boss_blood_council_controller : public CreatureScript
void EnterEvadeMode(EvadeReason /*why*/) override
{
- // Avoid do set boss state to fail with hotswap
- if (instance->GetBossState(DATA_BLOOD_PRINCE_COUNCIL) == DONE)
- return;
-
for (uint32 bossData : PrincesData)
if (Creature* prince = ObjectAccessor::GetCreature(*me, instance->GetGuidData(bossData)))
instance->SendEncounterUnit(ENCOUNTER_FRAME_DISENGAGE, prince);
diff --git a/src/server/worldserver/worldserver.conf.dist b/src/server/worldserver/worldserver.conf.dist
index a99a85394c6..8c9fc12ea18 100644
--- a/src/server/worldserver/worldserver.conf.dist
+++ b/src/server/worldserver/worldserver.conf.dist
@@ -1836,6 +1836,14 @@ PreserveCustomChannels = 1
PreserveCustomChannelDuration = 14
#
+# PartyRaidWarnings
+# Description: Allow any user to use raid warnings when in a 5-man party.
+# Default: 0 - (Disabled, Blizzlike)
+# 1 - (Enabled)
+
+PartyRaidWarnings = 0
+
+#
###################################################################################################
###################################################################################################
@@ -1996,6 +2004,7 @@ Support.SuggestionsEnabled = 0
# Default: 1 - (Raid)
# 0 - (Party)
# 2 - (Faction)
+# 3 - (None)
Visibility.GroupMode = 1