fix(Core/Movement): (#7008)
- Get zone/area IDs from vmap data in the liquid update - Add new method Map::getFullVMapDataForPosition to get area info and liquid info in a single vmap lookup - Adjust GetZoneId/GetAreaId on WorldObject to always return these cached fields. - Clean up liquid state handling on Unit and Player - Implemented getting area id from gameobject spawns. - Removed old core related to getting movement flags dependent on environment. - Movement flags are now processed more precisely and dynamically. Original source: TrinityCore. - Closes #5086 - Updates #2208.
This commit is contained in:
@@ -8,9 +8,14 @@
|
|||||||
#include "BoundingIntervalHierarchyWrapper.h"
|
#include "BoundingIntervalHierarchyWrapper.h"
|
||||||
#include "GameObjectModel.h"
|
#include "GameObjectModel.h"
|
||||||
#include "Log.h"
|
#include "Log.h"
|
||||||
|
#include "MapTree.h"
|
||||||
#include "ModelInstance.h"
|
#include "ModelInstance.h"
|
||||||
#include "RegularGrid.h"
|
#include "RegularGrid.h"
|
||||||
#include "Timer.h"
|
#include "Timer.h"
|
||||||
|
#include "VMapFactory.h"
|
||||||
|
#include "VMapManager2.h"
|
||||||
|
#include "WorldModel.h"
|
||||||
|
|
||||||
#include <G3D/AABox.h>
|
#include <G3D/AABox.h>
|
||||||
#include <G3D/Ray.h>
|
#include <G3D/Ray.h>
|
||||||
#include <G3D/Vector3.h>
|
#include <G3D/Vector3.h>
|
||||||
@@ -145,6 +150,52 @@ struct DynamicTreeIntersectionCallback
|
|||||||
bool didHit() const { return did_hit;}
|
bool didHit() const { return did_hit;}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct DynamicTreeAreaInfoCallback
|
||||||
|
{
|
||||||
|
DynamicTreeAreaInfoCallback(uint32 phaseMask)
|
||||||
|
: _phaseMask(phaseMask) {}
|
||||||
|
|
||||||
|
void operator()(G3D::Vector3 const& p, GameObjectModel const& obj)
|
||||||
|
{
|
||||||
|
obj.IntersectPoint(p, _areaInfo, _phaseMask);
|
||||||
|
}
|
||||||
|
|
||||||
|
VMAP::AreaInfo const& GetAreaInfo() const
|
||||||
|
{
|
||||||
|
return _areaInfo;
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
uint32 _phaseMask;
|
||||||
|
VMAP::AreaInfo _areaInfo;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct DynamicTreeLocationInfoCallback
|
||||||
|
{
|
||||||
|
DynamicTreeLocationInfoCallback(uint32 phaseMask)
|
||||||
|
: _phaseMask(phaseMask), _hitModel(nullptr) {}
|
||||||
|
|
||||||
|
void operator()(G3D::Vector3 const& p, GameObjectModel const& obj)
|
||||||
|
{
|
||||||
|
if (obj.GetLocationInfo(p, _locationInfo, _phaseMask))
|
||||||
|
_hitModel = &obj;
|
||||||
|
}
|
||||||
|
|
||||||
|
VMAP::LocationInfo& GetLocationInfo()
|
||||||
|
{
|
||||||
|
return _locationInfo;
|
||||||
|
}
|
||||||
|
GameObjectModel const* GetHitModel() const
|
||||||
|
{
|
||||||
|
return _hitModel;
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
uint32 _phaseMask;
|
||||||
|
VMAP::LocationInfo _locationInfo;
|
||||||
|
GameObjectModel const* _hitModel;
|
||||||
|
};
|
||||||
|
|
||||||
bool DynamicMapTree::GetIntersectionTime(const uint32 phasemask, const G3D::Ray& ray,
|
bool DynamicMapTree::GetIntersectionTime(const uint32 phasemask, const G3D::Ray& ray,
|
||||||
const G3D::Vector3& endPos, float& maxDist) const
|
const G3D::Vector3& endPos, float& maxDist) const
|
||||||
{
|
{
|
||||||
@@ -238,3 +289,41 @@ float DynamicMapTree::getHeight(float x, float y, float z, float maxSearchDist,
|
|||||||
return -G3D::finf();
|
return -G3D::finf();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool DynamicMapTree::GetAreaInfo(float x, float y, float& z, uint32 phasemask, uint32& flags, int32& adtId, int32& rootId, int32& groupId) const
|
||||||
|
{
|
||||||
|
G3D::Vector3 v(x, y, z + 0.5f);
|
||||||
|
DynamicTreeAreaInfoCallback intersectionCallBack(phasemask);
|
||||||
|
impl->intersectPoint(v, intersectionCallBack);
|
||||||
|
if (intersectionCallBack.GetAreaInfo().result)
|
||||||
|
{
|
||||||
|
flags = intersectionCallBack.GetAreaInfo().flags;
|
||||||
|
adtId = intersectionCallBack.GetAreaInfo().adtId;
|
||||||
|
rootId = intersectionCallBack.GetAreaInfo().rootId;
|
||||||
|
groupId = intersectionCallBack.GetAreaInfo().groupId;
|
||||||
|
z = intersectionCallBack.GetAreaInfo().ground_Z;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
void DynamicMapTree::GetAreaAndLiquidData(float x, float y, float z, uint32 phasemask, uint8 reqLiquidType, VMAP::AreaAndLiquidData& data) const
|
||||||
|
{
|
||||||
|
G3D::Vector3 v(x, y, z + 0.5f);
|
||||||
|
DynamicTreeLocationInfoCallback intersectionCallBack(phasemask);
|
||||||
|
impl->intersectPoint(v, intersectionCallBack);
|
||||||
|
if (intersectionCallBack.GetLocationInfo().hitModel)
|
||||||
|
{
|
||||||
|
data.floorZ = intersectionCallBack.GetLocationInfo().ground_Z;
|
||||||
|
uint32 liquidType = intersectionCallBack.GetLocationInfo().hitModel->GetLiquidType();
|
||||||
|
float liquidLevel;
|
||||||
|
if (!reqLiquidType || (dynamic_cast<VMAP::VMapManager2*>(VMAP::VMapFactory::createOrGetVMapManager())->GetLiquidFlagsPtr(liquidType) & reqLiquidType))
|
||||||
|
if (intersectionCallBack.GetHitModel()->GetLiquidLevel(v, intersectionCallBack.GetLocationInfo(), liquidLevel))
|
||||||
|
data.liquidInfo.emplace(liquidType, liquidLevel);
|
||||||
|
|
||||||
|
data.areaInfo.emplace(0,
|
||||||
|
intersectionCallBack.GetLocationInfo().rootId,
|
||||||
|
intersectionCallBack.GetLocationInfo().hitModel->GetWmoID(),
|
||||||
|
intersectionCallBack.GetLocationInfo().hitModel->GetMogpFlags());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@@ -15,6 +15,11 @@ namespace G3D
|
|||||||
class Vector3;
|
class Vector3;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
namespace VMAP
|
||||||
|
{
|
||||||
|
struct AreaAndLiquidData;
|
||||||
|
}
|
||||||
|
|
||||||
class GameObjectModel;
|
class GameObjectModel;
|
||||||
struct DynTreeImpl;
|
struct DynTreeImpl;
|
||||||
|
|
||||||
@@ -32,6 +37,9 @@ public:
|
|||||||
bool GetIntersectionTime(uint32 phasemask, const G3D::Ray& ray,
|
bool GetIntersectionTime(uint32 phasemask, const G3D::Ray& ray,
|
||||||
const G3D::Vector3& endPos, float& maxDist) const;
|
const G3D::Vector3& endPos, float& maxDist) const;
|
||||||
|
|
||||||
|
bool GetAreaInfo(float x, float y, float& z, uint32 phasemask, uint32& flags, int32& adtId, int32& rootId, int32& groupId) const;
|
||||||
|
void GetAreaAndLiquidData(float x, float y, float z, uint32 phasemask, uint8 reqLiquidType, VMAP::AreaAndLiquidData& data) const;
|
||||||
|
|
||||||
bool GetObjectHitPos(uint32 phasemask, const G3D::Vector3& pPos1,
|
bool GetObjectHitPos(uint32 phasemask, const G3D::Vector3& pPos1,
|
||||||
const G3D::Vector3& pPos2, G3D::Vector3& pResultHitPos,
|
const G3D::Vector3& pPos2, G3D::Vector3& pResultHitPos,
|
||||||
float pModifyDist) const;
|
float pModifyDist) const;
|
||||||
|
|||||||
@@ -8,6 +8,7 @@
|
|||||||
#define _IVMAPMANAGER_H
|
#define _IVMAPMANAGER_H
|
||||||
|
|
||||||
#include "Define.h"
|
#include "Define.h"
|
||||||
|
#include "Optional.h"
|
||||||
#include <string>
|
#include <string>
|
||||||
|
|
||||||
//===========================================================
|
//===========================================================
|
||||||
@@ -25,8 +26,33 @@ namespace VMAP
|
|||||||
VMAP_LOAD_RESULT_IGNORED
|
VMAP_LOAD_RESULT_IGNORED
|
||||||
};
|
};
|
||||||
|
|
||||||
#define VMAP_INVALID_HEIGHT -100000.0f // for check
|
#define VMAP_INVALID_HEIGHT -100000.0f // for check
|
||||||
#define VMAP_INVALID_HEIGHT_VALUE -200000.0f // real assigned value in unknown height case
|
#define VMAP_INVALID_HEIGHT_VALUE -200000.0f // real assigned value in unknown height case
|
||||||
|
|
||||||
|
struct AreaAndLiquidData
|
||||||
|
{
|
||||||
|
struct AreaInfo
|
||||||
|
{
|
||||||
|
AreaInfo(int32 _adtId, int32 _rootId, int32 _groupId, uint32 _flags)
|
||||||
|
: adtId(_adtId), rootId(_rootId), groupId(_groupId), mogpFlags(_flags) { }
|
||||||
|
int32 const adtId;
|
||||||
|
int32 const rootId;
|
||||||
|
int32 const groupId;
|
||||||
|
uint32 const mogpFlags;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct LiquidInfo
|
||||||
|
{
|
||||||
|
LiquidInfo(uint32 _type, float _level)
|
||||||
|
: type(_type), level(_level) {}
|
||||||
|
uint32 const type;
|
||||||
|
float const level;
|
||||||
|
};
|
||||||
|
|
||||||
|
float floorZ = VMAP_INVALID_HEIGHT;
|
||||||
|
Optional<AreaInfo> areaInfo;
|
||||||
|
Optional<LiquidInfo> liquidInfo;
|
||||||
|
};
|
||||||
|
|
||||||
//===========================================================
|
//===========================================================
|
||||||
class IVMapManager
|
class IVMapManager
|
||||||
@@ -79,8 +105,10 @@ namespace VMAP
|
|||||||
Query world model area info.
|
Query world model area info.
|
||||||
\param z gets adjusted to the ground height for which this are info is valid
|
\param z gets adjusted to the ground height for which this are info is valid
|
||||||
*/
|
*/
|
||||||
virtual bool GetAreaInfo(unsigned int pMapId, float x, float y, float& z, uint32& flags, int32& adtId, int32& rootId, int32& groupId) const = 0;
|
virtual bool GetAreaInfo(uint32 pMapId, float x, float y, float& z, uint32& flags, int32& adtId, int32& rootId, int32& groupId) const = 0;
|
||||||
virtual bool GetLiquidLevel(uint32 pMapId, float x, float y, float z, uint8 ReqLiquidType, float& level, float& floor, uint32& type) const = 0;
|
virtual bool GetLiquidLevel(uint32 pMapId, float x, float y, float z, uint8 ReqLiquidType, float& level, float& floor, uint32& type, uint32& mogpFlags) const = 0;
|
||||||
|
// get both area + liquid data in a single vmap lookup
|
||||||
|
virtual void GetAreaAndLiquidData(uint32 mapId, float x, float y, float z, uint8 reqLiquidType, AreaAndLiquidData& data) const = 0;
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -255,7 +255,7 @@ namespace VMAP
|
|||||||
return VMAP_INVALID_HEIGHT_VALUE;
|
return VMAP_INVALID_HEIGHT_VALUE;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool VMapManager2::GetAreaInfo(unsigned int mapId, float x, float y, float& z, uint32& flags, int32& adtId, int32& rootId, int32& groupId) const
|
bool VMapManager2::GetAreaInfo(uint32 mapId, float x, float y, float& z, uint32& flags, int32& adtId, int32& rootId, int32& groupId) const
|
||||||
{
|
{
|
||||||
#if defined(ENABLE_VMAP_CHECKS)
|
#if defined(ENABLE_VMAP_CHECKS)
|
||||||
if (!IsVMAPDisabledForPtr(mapId, VMAP_DISABLE_AREAFLAG))
|
if (!IsVMAPDisabledForPtr(mapId, VMAP_DISABLE_AREAFLAG))
|
||||||
@@ -275,7 +275,7 @@ namespace VMAP
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool VMapManager2::GetLiquidLevel(uint32 mapId, float x, float y, float z, uint8 reqLiquidType, float& level, float& floor, uint32& type) const
|
bool VMapManager2::GetLiquidLevel(uint32 mapId, float x, float y, float z, uint8 reqLiquidType, float& level, float& floor, uint32& type, uint32& mogpFlags) const
|
||||||
{
|
{
|
||||||
#if defined(ENABLE_VMAP_CHECKS)
|
#if defined(ENABLE_VMAP_CHECKS)
|
||||||
if (!IsVMAPDisabledForPtr(mapId, VMAP_DISABLE_LIQUIDSTATUS))
|
if (!IsVMAPDisabledForPtr(mapId, VMAP_DISABLE_LIQUIDSTATUS))
|
||||||
@@ -291,6 +291,7 @@ namespace VMAP
|
|||||||
floor = info.ground_Z;
|
floor = info.ground_Z;
|
||||||
ASSERT(floor < std::numeric_limits<float>::max());
|
ASSERT(floor < std::numeric_limits<float>::max());
|
||||||
type = info.hitModel->GetLiquidType(); // entry from LiquidType.dbc
|
type = info.hitModel->GetLiquidType(); // entry from LiquidType.dbc
|
||||||
|
mogpFlags = info.hitModel->GetMogpFlags();
|
||||||
if (reqLiquidType && !(GetLiquidFlagsPtr(type) & reqLiquidType))
|
if (reqLiquidType && !(GetLiquidFlagsPtr(type) & reqLiquidType))
|
||||||
{
|
{
|
||||||
return false;
|
return false;
|
||||||
@@ -306,6 +307,38 @@ namespace VMAP
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void VMapManager2::GetAreaAndLiquidData(uint32 mapId, float x, float y, float z, uint8 reqLiquidType, AreaAndLiquidData& data) const
|
||||||
|
{
|
||||||
|
if (IsVMAPDisabledForPtr(mapId, VMAP_DISABLE_LIQUIDSTATUS))
|
||||||
|
{
|
||||||
|
data.floorZ = z;
|
||||||
|
int32 adtId, rootId, groupId;
|
||||||
|
uint32 flags;
|
||||||
|
if (GetAreaInfo(mapId, x, y, data.floorZ, flags, adtId, rootId, groupId))
|
||||||
|
data.areaInfo.emplace(adtId, rootId, groupId, flags);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
InstanceTreeMap::const_iterator instanceTree = GetMapTree(mapId);
|
||||||
|
if (instanceTree != iInstanceMapTrees.end())
|
||||||
|
{
|
||||||
|
LocationInfo info;
|
||||||
|
Vector3 pos = convertPositionToInternalRep(x, y, z);
|
||||||
|
if (instanceTree->second->GetLocationInfo(pos, info))
|
||||||
|
{
|
||||||
|
data.floorZ = info.ground_Z;
|
||||||
|
uint32 liquidType = info.hitModel->GetLiquidType();
|
||||||
|
float liquidLevel;
|
||||||
|
if (!reqLiquidType || (GetLiquidFlagsPtr(liquidType) & reqLiquidType))
|
||||||
|
if (info.hitInstance->GetLiquidLevel(pos, info, liquidLevel))
|
||||||
|
data.liquidInfo.emplace(liquidType, liquidLevel);
|
||||||
|
|
||||||
|
if (!IsVMAPDisabledForPtr(mapId, VMAP_DISABLE_AREAFLAG))
|
||||||
|
data.areaInfo.emplace(info.hitInstance->adtId, info.rootId, info.hitModel->GetWmoID(), info.hitModel->GetMogpFlags());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
WorldModel* VMapManager2::acquireModelInstance(const std::string& basepath, const std::string& filename)
|
WorldModel* VMapManager2::acquireModelInstance(const std::string& basepath, const std::string& filename)
|
||||||
{
|
{
|
||||||
//! Critical section, thread safe access to iLoadedModelFiles
|
//! Critical section, thread safe access to iLoadedModelFiles
|
||||||
|
|||||||
@@ -117,8 +117,9 @@ namespace VMAP
|
|||||||
|
|
||||||
bool processCommand(char* /*command*/) override { return false; } // for debug and extensions
|
bool processCommand(char* /*command*/) override { return false; } // for debug and extensions
|
||||||
|
|
||||||
bool GetAreaInfo(unsigned int pMapId, float x, float y, float& z, uint32& flags, int32& adtId, int32& rootId, int32& groupId) const override;
|
bool GetAreaInfo(uint32 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;
|
bool GetLiquidLevel(uint32 pMapId, float x, float y, float z, uint8 reqLiquidType, float& level, float& floor, uint32& type, uint32& mogpFlags) const override;
|
||||||
|
void GetAreaAndLiquidData(uint32 mapId, float x, float y, float z, uint8 reqLiquidType, AreaAndLiquidData& data) const override;
|
||||||
|
|
||||||
WorldModel* acquireModelInstance(const std::string& basepath, const std::string& filename);
|
WorldModel* acquireModelInstance(const std::string& basepath, const std::string& filename);
|
||||||
void releaseModelInstance(const std::string& filename);
|
void releaseModelInstance(const std::string& filename);
|
||||||
|
|||||||
@@ -23,6 +23,7 @@ namespace VMAP
|
|||||||
const ModelInstance* hitInstance{nullptr};
|
const ModelInstance* hitInstance{nullptr};
|
||||||
const GroupModel* hitModel{nullptr};
|
const GroupModel* hitModel{nullptr};
|
||||||
float ground_Z;
|
float ground_Z;
|
||||||
|
int32 rootId = -1;
|
||||||
};
|
};
|
||||||
|
|
||||||
class StaticMapTree
|
class StaticMapTree
|
||||||
|
|||||||
@@ -6,6 +6,7 @@
|
|||||||
|
|
||||||
#include "GameObjectModel.h"
|
#include "GameObjectModel.h"
|
||||||
#include "Log.h"
|
#include "Log.h"
|
||||||
|
#include "MapTree.h"
|
||||||
#include "Timer.h"
|
#include "Timer.h"
|
||||||
#include "VMapDefinitions.h"
|
#include "VMapDefinitions.h"
|
||||||
#include "VMapFactory.h"
|
#include "VMapFactory.h"
|
||||||
@@ -146,6 +147,7 @@ bool GameObjectModel::initialize(std::unique_ptr<GameObjectModelOwnerBase> model
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
owner = std::move(modelOwner);
|
owner = std::move(modelOwner);
|
||||||
|
isWmo = it->second.isWmo;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -187,6 +189,69 @@ bool GameObjectModel::intersectRay(const G3D::Ray& ray, float& MaxDist, bool Sto
|
|||||||
return hit;
|
return hit;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void GameObjectModel::IntersectPoint(G3D::Vector3 const& point, VMAP::AreaInfo& info, uint32 ph_mask) const
|
||||||
|
{
|
||||||
|
if (!(phasemask & ph_mask) || !owner->IsSpawned() || !IsMapObject())
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (!iBound.contains(point))
|
||||||
|
return;
|
||||||
|
|
||||||
|
// child bounds are defined in object space:
|
||||||
|
Vector3 pModel = iInvRot * (point - iPos) * iInvScale;
|
||||||
|
Vector3 zDirModel = iInvRot * Vector3(0.f, 0.f, -1.f);
|
||||||
|
float zDist;
|
||||||
|
if (iModel->IntersectPoint(pModel, zDirModel, zDist, info))
|
||||||
|
{
|
||||||
|
Vector3 modelGround = pModel + zDist * zDirModel;
|
||||||
|
float world_Z = ((modelGround * iInvRot) * iScale + iPos).z;
|
||||||
|
if (info.ground_Z < world_Z)
|
||||||
|
info.ground_Z = world_Z;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool GameObjectModel::GetLocationInfo(G3D::Vector3 const& point, VMAP::LocationInfo& info, uint32 ph_mask) const
|
||||||
|
{
|
||||||
|
if (!(phasemask & ph_mask) || !owner->IsSpawned() || !IsMapObject())
|
||||||
|
return false;
|
||||||
|
|
||||||
|
if (!iBound.contains(point))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
// child bounds are defined in object space:
|
||||||
|
Vector3 pModel = iInvRot * (point - iPos) * iInvScale;
|
||||||
|
Vector3 zDirModel = iInvRot * Vector3(0.f, 0.f, -1.f);
|
||||||
|
float zDist;
|
||||||
|
if (iModel->GetLocationInfo(pModel, zDirModel, zDist, info))
|
||||||
|
{
|
||||||
|
Vector3 modelGround = pModel + zDist * zDirModel;
|
||||||
|
float world_Z = ((modelGround * iInvRot) * iScale + iPos).z;
|
||||||
|
if (info.ground_Z < world_Z)
|
||||||
|
{
|
||||||
|
info.ground_Z = world_Z;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool GameObjectModel::GetLiquidLevel(G3D::Vector3 const& point, VMAP::LocationInfo& info, float& liqHeight) const
|
||||||
|
{
|
||||||
|
// child bounds are defined in object space:
|
||||||
|
Vector3 pModel = iInvRot * (point - iPos) * iInvScale;
|
||||||
|
//Vector3 zDirModel = iInvRot * Vector3(0.f, 0.f, -1.f);
|
||||||
|
float zDist;
|
||||||
|
if (info.hitModel->GetLiquidLevel(pModel, zDist))
|
||||||
|
{
|
||||||
|
// calculate world height (zDist in model coords):
|
||||||
|
// assume WMO not tilted (wouldn't make much sense anyway)
|
||||||
|
liqHeight = zDist * iScale + iPos.z;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
bool GameObjectModel::UpdatePosition()
|
bool GameObjectModel::UpdatePosition()
|
||||||
{
|
{
|
||||||
if (!iModel)
|
if (!iModel)
|
||||||
|
|||||||
@@ -16,6 +16,8 @@
|
|||||||
namespace VMAP
|
namespace VMAP
|
||||||
{
|
{
|
||||||
class WorldModel;
|
class WorldModel;
|
||||||
|
struct AreaInfo;
|
||||||
|
struct LocationInfo;
|
||||||
}
|
}
|
||||||
|
|
||||||
class GameObject;
|
class GameObject;
|
||||||
@@ -37,7 +39,7 @@ public:
|
|||||||
|
|
||||||
class GameObjectModel
|
class GameObjectModel
|
||||||
{
|
{
|
||||||
GameObjectModel() : phasemask(0), iInvScale(0), iScale(0), iModel(nullptr) { }
|
GameObjectModel() : phasemask(0), iInvScale(0), iScale(0), iModel(nullptr), isWmo(false) { }
|
||||||
|
|
||||||
public:
|
public:
|
||||||
std::string name;
|
std::string name;
|
||||||
@@ -53,8 +55,12 @@ public:
|
|||||||
void enable(uint32 ph_mask) { phasemask = ph_mask; }
|
void enable(uint32 ph_mask) { phasemask = ph_mask; }
|
||||||
|
|
||||||
[[nodiscard]] bool isEnabled() const { return phasemask != 0; }
|
[[nodiscard]] bool isEnabled() const { return phasemask != 0; }
|
||||||
|
[[nodiscard]] bool IsMapObject() const { return isWmo; }
|
||||||
|
|
||||||
bool intersectRay(const G3D::Ray& Ray, float& MaxDist, bool StopAtFirstHit, uint32 ph_mask) const;
|
bool intersectRay(const G3D::Ray& Ray, float& MaxDist, bool StopAtFirstHit, uint32 ph_mask) const;
|
||||||
|
void IntersectPoint(G3D::Vector3 const& point, VMAP::AreaInfo& info, uint32 ph_mask) const;
|
||||||
|
bool GetLocationInfo(G3D::Vector3 const& point, VMAP::LocationInfo& info, uint32 ph_mask) const;
|
||||||
|
bool GetLiquidLevel(G3D::Vector3 const& point, VMAP::LocationInfo& info, float& liqHeight) const;
|
||||||
|
|
||||||
static GameObjectModel* Create(std::unique_ptr<GameObjectModelOwnerBase> modelOwner, std::string const& dataPath);
|
static GameObjectModel* Create(std::unique_ptr<GameObjectModelOwnerBase> modelOwner, std::string const& dataPath);
|
||||||
|
|
||||||
@@ -71,6 +77,7 @@ private:
|
|||||||
float iScale;
|
float iScale;
|
||||||
VMAP::WorldModel* iModel;
|
VMAP::WorldModel* iModel;
|
||||||
std::unique_ptr<GameObjectModelOwnerBase> owner;
|
std::unique_ptr<GameObjectModelOwnerBase> owner;
|
||||||
|
bool isWmo;
|
||||||
};
|
};
|
||||||
|
|
||||||
void LoadGameObjectModelList(std::string const& dataPath);
|
void LoadGameObjectModelList(std::string const& dataPath);
|
||||||
|
|||||||
@@ -412,7 +412,6 @@ namespace VMAP
|
|||||||
{
|
{
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
GModelRayCallback callback(triangles, vertices);
|
|
||||||
Vector3 rPos = pos - 0.1f * down;
|
Vector3 rPos = pos - 0.1f * down;
|
||||||
float dist = G3D::inf();
|
float dist = G3D::inf();
|
||||||
G3D::Ray ray(rPos, down);
|
G3D::Ray ray(rPos, down);
|
||||||
@@ -554,6 +553,7 @@ namespace VMAP
|
|||||||
groupTree.intersectPoint(p, callback);
|
groupTree.intersectPoint(p, callback);
|
||||||
if (callback.hit != groupModels.end())
|
if (callback.hit != groupModels.end())
|
||||||
{
|
{
|
||||||
|
info.rootId = RootWMOID;
|
||||||
info.hitModel = &(*callback.hit);
|
info.hitModel = &(*callback.hit);
|
||||||
dist = callback.zDist;
|
dist = callback.zDist;
|
||||||
return true;
|
return true;
|
||||||
|
|||||||
@@ -531,7 +531,7 @@ void BattlefieldWG::OnCreatureCreate(Creature* creature)
|
|||||||
case NPC_TAUNKA_SPIRIT_GUIDE:
|
case NPC_TAUNKA_SPIRIT_GUIDE:
|
||||||
{
|
{
|
||||||
TeamId teamId = (creature->GetEntry() == NPC_DWARVEN_SPIRIT_GUIDE ? TEAM_ALLIANCE : TEAM_HORDE);
|
TeamId teamId = (creature->GetEntry() == NPC_DWARVEN_SPIRIT_GUIDE ? TEAM_ALLIANCE : TEAM_HORDE);
|
||||||
uint8 graveyardId = GetSpiritGraveyardId(creature->GetAreaId(true));
|
uint8 graveyardId = GetSpiritGraveyardId(creature->GetAreaId());
|
||||||
// xinef: little workaround, there are 2 spirit guides in same area
|
// xinef: little workaround, there are 2 spirit guides in same area
|
||||||
if (creature->IsWithinDist2d(5103.0f, 3461.5f, 5.0f))
|
if (creature->IsWithinDist2d(5103.0f, 3461.5f, 5.0f))
|
||||||
graveyardId = BATTLEFIELD_WG_GY_WORKSHOP_NW;
|
graveyardId = BATTLEFIELD_WG_GY_WORKSHOP_NW;
|
||||||
|
|||||||
@@ -1004,7 +1004,7 @@ namespace lfg
|
|||||||
|
|
||||||
currInternalInfoMap[sitr->first] = RBInternalInfo(guid, sitr->second.comment, !groupGuid.IsEmpty(), groupGuid, sitr->second.roles, encounterMask, instanceGuid,
|
currInternalInfoMap[sitr->first] = RBInternalInfo(guid, sitr->second.comment, !groupGuid.IsEmpty(), groupGuid, sitr->second.roles, encounterMask, instanceGuid,
|
||||||
1, p->getLevel(), p->getClass(), p->getRace(), p->GetAverageItemLevel(),
|
1, p->getLevel(), p->getClass(), p->getRace(), p->GetAverageItemLevel(),
|
||||||
talents, p->m_last_area_id, p->GetArmor(), (uint32)std::max<int32>(0, spellDamage), (uint32)std::max<int32>(0, spellHeal),
|
talents, p->GetAreaId(), p->GetArmor(), (uint32)std::max<int32>(0, spellDamage), (uint32)std::max<int32>(0, spellHeal),
|
||||||
p->GetUInt32Value(PLAYER_FIELD_COMBAT_RATING_1 + static_cast<uint16>(CR_CRIT_MELEE)), p->GetUInt32Value(PLAYER_FIELD_COMBAT_RATING_1 + static_cast<uint16>(CR_CRIT_RANGED)), p->GetUInt32Value(PLAYER_FIELD_COMBAT_RATING_1 + static_cast<uint16>(CR_CRIT_SPELL)), std::max<float>(0.0f, mp5), std::max<float>(0.0f, mp5combat),
|
p->GetUInt32Value(PLAYER_FIELD_COMBAT_RATING_1 + static_cast<uint16>(CR_CRIT_MELEE)), p->GetUInt32Value(PLAYER_FIELD_COMBAT_RATING_1 + static_cast<uint16>(CR_CRIT_RANGED)), p->GetUInt32Value(PLAYER_FIELD_COMBAT_RATING_1 + static_cast<uint16>(CR_CRIT_SPELL)), std::max<float>(0.0f, mp5), std::max<float>(0.0f, mp5combat),
|
||||||
std::max<uint32>(baseAP, rangedAP), (uint32)p->GetStat(STAT_AGILITY), p->GetMaxHealth(), maxPower, p->GetDefenseSkillValue(),
|
std::max<uint32>(baseAP, rangedAP), (uint32)p->GetStat(STAT_AGILITY), p->GetMaxHealth(), maxPower, p->GetDefenseSkillValue(),
|
||||||
p->GetUInt32Value(PLAYER_FIELD_COMBAT_RATING_1 + static_cast<uint16>(CR_DODGE)), p->GetUInt32Value(PLAYER_FIELD_COMBAT_RATING_1 + static_cast<uint16>(CR_BLOCK)), p->GetUInt32Value(PLAYER_FIELD_COMBAT_RATING_1 + static_cast<uint16>(CR_PARRY)), p->GetUInt32Value(PLAYER_FIELD_COMBAT_RATING_1 + static_cast<uint16>(CR_HASTE_SPELL)), p->GetUInt32Value(PLAYER_FIELD_COMBAT_RATING_1 + static_cast<uint16>(CR_EXPERTISE)));
|
p->GetUInt32Value(PLAYER_FIELD_COMBAT_RATING_1 + static_cast<uint16>(CR_DODGE)), p->GetUInt32Value(PLAYER_FIELD_COMBAT_RATING_1 + static_cast<uint16>(CR_BLOCK)), p->GetUInt32Value(PLAYER_FIELD_COMBAT_RATING_1 + static_cast<uint16>(CR_PARRY)), p->GetUInt32Value(PLAYER_FIELD_COMBAT_RATING_1 + static_cast<uint16>(CR_HASTE_SPELL)), p->GetUInt32Value(PLAYER_FIELD_COMBAT_RATING_1 + static_cast<uint16>(CR_EXPERTISE)));
|
||||||
|
|||||||
@@ -519,8 +519,6 @@ bool Creature::UpdateEntry(uint32 Entry, const CreatureData* data, bool changele
|
|||||||
SetControlled(true, UNIT_STATE_ROOT);
|
SetControlled(true, UNIT_STATE_ROOT);
|
||||||
}
|
}
|
||||||
|
|
||||||
UpdateEnvironmentIfNeeded(3);
|
|
||||||
|
|
||||||
SetDetectionDistance(cInfo->detection_range);
|
SetDetectionDistance(cInfo->detection_range);
|
||||||
|
|
||||||
LoadSpellTemplateImmunity();
|
LoadSpellTemplateImmunity();
|
||||||
@@ -959,16 +957,23 @@ bool Creature::Create(ObjectGuid::LowType guidlow, Map* map, uint32 phaseMask, u
|
|||||||
//! returning correct zone id for selecting OutdoorPvP/Battlefield script
|
//! returning correct zone id for selecting OutdoorPvP/Battlefield script
|
||||||
Relocate(x, y, z, ang);
|
Relocate(x, y, z, ang);
|
||||||
|
|
||||||
//oX = x; oY = y; dX = x; dY = y; m_moveTime = 0; m_startMove = 0;
|
|
||||||
if (!CreateFromProto(guidlow, Entry, vehId, data))
|
|
||||||
return false;
|
|
||||||
|
|
||||||
if (!IsPositionValid())
|
if (!IsPositionValid())
|
||||||
{
|
{
|
||||||
LOG_ERROR("entities.unit", "Creature::Create(): given coordinates for creature (guidlow %d, entry %d) are not valid (X: %f, Y: %f, Z: %f, O: %f)", guidlow, Entry, x, y, z, ang);
|
LOG_ERROR("entities.unit", "Creature::Create(): given coordinates for creature (guidlow %d, entry %d) are not valid (X: %f, Y: %f, Z: %f, O: %f)", guidlow, Entry, x, y, z, ang);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// area/zone id is needed immediately for ZoneScript::GetCreatureEntry hook before it is known which creature template to load (no model/scale available yet)
|
||||||
|
PositionFullTerrainStatus terrainData;
|
||||||
|
GetMap()->GetFullTerrainStatusForPosition(GetPhaseMask(), GetPositionX(), GetPositionY(), GetPositionZ(), DEFAULT_COLLISION_HEIGHT, terrainData);
|
||||||
|
ProcessPositionDataChanged(terrainData);
|
||||||
|
|
||||||
|
//oX = x; oY = y; dX = x; dY = y; m_moveTime = 0; m_startMove = 0;
|
||||||
|
if (!CreateFromProto(guidlow, Entry, vehId, data))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
UpdateMovementFlags();
|
||||||
|
|
||||||
switch (GetCreatureTemplate()->rank)
|
switch (GetCreatureTemplate()->rank)
|
||||||
{
|
{
|
||||||
case CREATURE_ELITE_RARE:
|
case CREATURE_ELITE_RARE:
|
||||||
@@ -1812,6 +1817,8 @@ void Creature::setDeathState(DeathState s, bool despawn)
|
|||||||
if (HasUnitMovementFlag(MOVEMENTFLAG_FALLING))
|
if (HasUnitMovementFlag(MOVEMENTFLAG_FALLING))
|
||||||
RemoveUnitMovementFlag(MOVEMENTFLAG_FALLING);
|
RemoveUnitMovementFlag(MOVEMENTFLAG_FALLING);
|
||||||
|
|
||||||
|
UpdateMovementFlags();
|
||||||
|
|
||||||
SetUInt32Value(UNIT_NPC_FLAGS, cinfo->npcflag);
|
SetUInt32Value(UNIT_NPC_FLAGS, cinfo->npcflag);
|
||||||
ClearUnitState(uint32(UNIT_STATE_ALL_STATE & ~(UNIT_STATE_IGNORE_PATHFINDING | UNIT_STATE_NO_ENVIRONMENT_UPD)));
|
ClearUnitState(uint32(UNIT_STATE_ALL_STATE & ~(UNIT_STATE_IGNORE_PATHFINDING | UNIT_STATE_NO_ENVIRONMENT_UPD)));
|
||||||
SetMeleeDamageSchool(SpellSchools(cinfo->dmgschool));
|
SetMeleeDamageSchool(SpellSchools(cinfo->dmgschool));
|
||||||
@@ -1822,8 +1829,6 @@ void Creature::setDeathState(DeathState s, bool despawn)
|
|||||||
LoadCreaturesAddon(true);
|
LoadCreaturesAddon(true);
|
||||||
if (GetCreatureData() && GetPhaseMask() != GetCreatureData()->phaseMask)
|
if (GetCreatureData() && GetPhaseMask() != GetCreatureData()->phaseMask)
|
||||||
SetPhaseMask(GetCreatureData()->phaseMask, false);
|
SetPhaseMask(GetCreatureData()->phaseMask, false);
|
||||||
|
|
||||||
UpdateEnvironmentIfNeeded(3);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -2866,16 +2871,13 @@ void Creature::applyInhabitFlags()
|
|||||||
if (IsLevitating())
|
if (IsLevitating())
|
||||||
{
|
{
|
||||||
SetByteValue(UNIT_FIELD_BYTES_1, UNIT_BYTES_1_OFFSET_ANIM_TIER, UNIT_BYTE1_FLAG_FLY);
|
SetByteValue(UNIT_FIELD_BYTES_1, UNIT_BYTES_1_OFFSET_ANIM_TIER, UNIT_BYTE1_FLAG_FLY);
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
|
else if (IsHovering())
|
||||||
if (IsHovering())
|
|
||||||
{
|
{
|
||||||
SetByteValue(UNIT_FIELD_BYTES_1, UNIT_BYTES_1_OFFSET_ANIM_TIER, UNIT_BYTE1_FLAG_HOVER);
|
SetByteValue(UNIT_FIELD_BYTES_1, UNIT_BYTES_1_OFFSET_ANIM_TIER, UNIT_BYTE1_FLAG_HOVER);
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
|
else
|
||||||
SetByteValue(UNIT_FIELD_BYTES_1, UNIT_BYTES_1_OFFSET_ANIM_TIER, UNIT_BYTE1_FLAG_GROUND);
|
SetByteValue(UNIT_FIELD_BYTES_1, UNIT_BYTES_1_OFFSET_ANIM_TIER, UNIT_BYTE1_FLAG_GROUND);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -3042,6 +3044,84 @@ float Creature::GetAggroRange(Unit const* target) const
|
|||||||
return (aggroRadius * aggroRate);
|
return (aggroRadius * aggroRate);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void Creature::UpdateMovementFlags()
|
||||||
|
{
|
||||||
|
// Do not update movement flags if creature is controlled by a player (charm/vehicle)
|
||||||
|
if (m_movedByPlayer)
|
||||||
|
return;
|
||||||
|
|
||||||
|
CreatureTemplate const* info = GetCreatureTemplate();
|
||||||
|
if (!info)
|
||||||
|
return;
|
||||||
|
|
||||||
|
// Creatures with CREATURE_FLAG_EXTRA_NO_MOVE_FLAGS_UPDATE should control MovementFlags in your own scripts
|
||||||
|
if (info->flags_extra & CREATURE_FLAG_EXTRA_NO_MOVE_FLAGS_UPDATE)
|
||||||
|
return;
|
||||||
|
|
||||||
|
float z = GetPositionZ();
|
||||||
|
float ground = GetFloorZ();
|
||||||
|
|
||||||
|
bool isInAir = false;
|
||||||
|
bool Swim = false;
|
||||||
|
|
||||||
|
bool canHover = CanHover();
|
||||||
|
|
||||||
|
LiquidData const& liquidData = GetLiquidData();
|
||||||
|
if (liquidData.Status == LIQUID_MAP_NO_WATER)
|
||||||
|
{
|
||||||
|
if (ground > INVALID_HEIGHT)
|
||||||
|
isInAir = G3D::fuzzyGt(z, ground + (canHover ? GetFloatValue(UNIT_FIELD_HOVERHEIGHT) : 0.0f) + GROUND_HEIGHT_TOLERANCE) || G3D::fuzzyLt(z, ground - GROUND_HEIGHT_TOLERANCE); // Can be underground too, prevent the falling
|
||||||
|
else
|
||||||
|
isInAir = true;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
switch (liquidData.Status)
|
||||||
|
{
|
||||||
|
case LIQUID_MAP_ABOVE_WATER:
|
||||||
|
isInAir = true;
|
||||||
|
break;
|
||||||
|
case LIQUID_MAP_WATER_WALK:
|
||||||
|
isInAir = true;
|
||||||
|
[[fallthrough]];
|
||||||
|
case LIQUID_MAP_IN_WATER:
|
||||||
|
Swim = z - liquidData.DepthLevel > GetCollisionHeight() * 0.75f; // Shallow water at ~75% of collision height
|
||||||
|
break;
|
||||||
|
case LIQUID_MAP_UNDER_WATER:
|
||||||
|
Swim = true;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
SetSwim(CanSwim() && Swim);
|
||||||
|
|
||||||
|
if (info->InhabitType & INHABIT_AIR)
|
||||||
|
{
|
||||||
|
if (isInAir && !IsFalling())
|
||||||
|
{
|
||||||
|
if (info->InhabitType & INHABIT_GROUND)
|
||||||
|
SetCanFly(true);
|
||||||
|
else
|
||||||
|
SetDisableGravity(true);
|
||||||
|
|
||||||
|
if (!HasAuraType(SPELL_AURA_HOVER))
|
||||||
|
SetHover(false);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
SetCanFly(false);
|
||||||
|
SetDisableGravity(false);
|
||||||
|
|
||||||
|
if (IsAlive() && (CanHover() || HasAuraType(SPELL_AURA_HOVER)))
|
||||||
|
SetHover(true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (!HasUnitMovementFlag(MOVEMENTFLAG_CAN_FLY | MOVEMENTFLAG_DISABLE_GRAVITY) && IsAlive() && (CanHover() || HasAuraType(SPELL_AURA_HOVER)))
|
||||||
|
SetHover(true);
|
||||||
|
}
|
||||||
|
|
||||||
void Creature::SetObjectScale(float scale)
|
void Creature::SetObjectScale(float scale)
|
||||||
{
|
{
|
||||||
Unit::SetObjectScale(scale);
|
Unit::SetObjectScale(scale);
|
||||||
|
|||||||
@@ -151,6 +151,8 @@ public:
|
|||||||
|
|
||||||
[[nodiscard]] bool HasSpell(uint32 spellID) const override;
|
[[nodiscard]] bool HasSpell(uint32 spellID) const override;
|
||||||
|
|
||||||
|
void UpdateMovementFlags();
|
||||||
|
|
||||||
bool UpdateEntry(uint32 entry, const CreatureData* data = nullptr, bool changelevel = true );
|
bool UpdateEntry(uint32 entry, const CreatureData* data = nullptr, bool changelevel = true );
|
||||||
bool UpdateStats(Stats stat) override;
|
bool UpdateStats(Stats stat) override;
|
||||||
bool UpdateAllStats() override;
|
bool UpdateAllStats() override;
|
||||||
|
|||||||
@@ -40,7 +40,7 @@ enum CreatureFlagsExtra : uint32
|
|||||||
CREATURE_FLAG_EXTRA_NO_XP = 0x00000040, // creature kill does not provide XP
|
CREATURE_FLAG_EXTRA_NO_XP = 0x00000040, // creature kill does not provide XP
|
||||||
CREATURE_FLAG_EXTRA_TRIGGER = 0x00000080, // trigger creature
|
CREATURE_FLAG_EXTRA_TRIGGER = 0x00000080, // trigger creature
|
||||||
CREATURE_FLAG_EXTRA_NO_TAUNT = 0x00000100, // creature is immune to taunt auras and 'attack me' effects
|
CREATURE_FLAG_EXTRA_NO_TAUNT = 0x00000100, // creature is immune to taunt auras and 'attack me' effects
|
||||||
CREATURE_FLAG_EXTRA_UNUSED_10 = 0x00000200, // TODO: Implement CREATURE_FLAG_EXTRA_NO_MOVE_FLAGS_UPDATE (creature won't update movement flags)
|
CREATURE_FLAG_EXTRA_NO_MOVE_FLAGS_UPDATE = 0x00000200, // creature won't update movement flags
|
||||||
CREATURE_FLAG_EXTRA_GHOST_VISIBILITY = 0x00000400, // creature will only be visible to dead players
|
CREATURE_FLAG_EXTRA_GHOST_VISIBILITY = 0x00000400, // creature will only be visible to dead players
|
||||||
CREATURE_FLAG_EXTRA_UNUSED_12 = 0x00000800, // TODO: Implement CREATURE_FLAG_EXTRA_USE_OFFHAND_ATTACK (creature will use offhand attacks)
|
CREATURE_FLAG_EXTRA_UNUSED_12 = 0x00000800, // TODO: Implement CREATURE_FLAG_EXTRA_USE_OFFHAND_ATTACK (creature will use offhand attacks)
|
||||||
CREATURE_FLAG_EXTRA_NO_SELL_VENDOR = 0x00001000, // players can't sell items to this vendor
|
CREATURE_FLAG_EXTRA_NO_SELL_VENDOR = 0x00001000, // players can't sell items to this vendor
|
||||||
@@ -65,8 +65,7 @@ enum CreatureFlagsExtra : uint32
|
|||||||
CREATURE_FLAG_EXTRA_UNUSED_32 = 0x80000000,
|
CREATURE_FLAG_EXTRA_UNUSED_32 = 0x80000000,
|
||||||
|
|
||||||
// Masks
|
// Masks
|
||||||
CREATURE_FLAG_EXTRA_UNUSED = (CREATURE_FLAG_EXTRA_UNUSED_10 | CREATURE_FLAG_EXTRA_UNUSED_12 |
|
CREATURE_FLAG_EXTRA_UNUSED = (CREATURE_FLAG_EXTRA_UNUSED_12 | CREATURE_FLAG_EXTRA_UNUSED_25 | CREATURE_FLAG_EXTRA_UNUSED_26 |
|
||||||
CREATURE_FLAG_EXTRA_UNUSED_25 | CREATURE_FLAG_EXTRA_UNUSED_26 |
|
|
||||||
CREATURE_FLAG_EXTRA_UNUSED_27 | CREATURE_FLAG_EXTRA_UNUSED_28 | CREATURE_FLAG_EXTRA_UNUSED_32),
|
CREATURE_FLAG_EXTRA_UNUSED_27 | CREATURE_FLAG_EXTRA_UNUSED_28 | CREATURE_FLAG_EXTRA_UNUSED_32),
|
||||||
CREATURE_FLAG_EXTRA_DB_ALLOWED = (0xFFFFFFFF & ~(CREATURE_FLAG_EXTRA_UNUSED | CREATURE_FLAG_EXTRA_DUNGEON_BOSS))
|
CREATURE_FLAG_EXTRA_DB_ALLOWED = (0xFFFFFFFF & ~(CREATURE_FLAG_EXTRA_UNUSED | CREATURE_FLAG_EXTRA_DUNGEON_BOSS))
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -97,6 +97,8 @@ bool DynamicObject::CreateDynamicObject(ObjectGuid::LowType guidlow, Unit* caste
|
|||||||
|
|
||||||
WorldObject::_Create(guidlow, HighGuid::DynamicObject, caster->GetPhaseMask());
|
WorldObject::_Create(guidlow, HighGuid::DynamicObject, caster->GetPhaseMask());
|
||||||
|
|
||||||
|
UpdatePositionData();
|
||||||
|
|
||||||
SetEntry(spellId);
|
SetEntry(spellId);
|
||||||
SetObjectScale(1);
|
SetObjectScale(1);
|
||||||
SetGuidValue(DYNAMICOBJECT_CASTER, caster->GetGUID());
|
SetGuidValue(DYNAMICOBJECT_CASTER, caster->GetGUID());
|
||||||
|
|||||||
@@ -241,6 +241,8 @@ bool GameObject::Create(ObjectGuid::LowType guidlow, uint32 name_id, Map* map, u
|
|||||||
|
|
||||||
SetPhaseMask(phaseMask, false);
|
SetPhaseMask(phaseMask, false);
|
||||||
|
|
||||||
|
UpdatePositionData();
|
||||||
|
|
||||||
SetZoneScript();
|
SetZoneScript();
|
||||||
if (m_zoneScript)
|
if (m_zoneScript)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -950,8 +950,8 @@ WorldObject::WorldObject(bool isWorldObject) : WorldLocation(),
|
|||||||
elunaEvents(nullptr),
|
elunaEvents(nullptr),
|
||||||
#endif
|
#endif
|
||||||
LastUsedScriptID(0), m_name(""), m_isActive(false), m_isVisibilityDistanceOverride(false), m_isWorldObject(isWorldObject), m_zoneScript(nullptr),
|
LastUsedScriptID(0), m_name(""), m_isActive(false), m_isVisibilityDistanceOverride(false), m_isWorldObject(isWorldObject), m_zoneScript(nullptr),
|
||||||
m_staticFloorZ(INVALID_HEIGHT), m_transport(nullptr), m_currMap(nullptr), m_InstanceId(0),
|
_zoneId(0), _areaId(0), _floorZ(INVALID_HEIGHT), _outdoors(false), _liquidData(), _updatePositionData(false), m_transport(nullptr),
|
||||||
m_phaseMask(PHASEMASK_NORMAL), m_useCombinedPhases(true), m_notifyflags(0), m_executed_notifies(0)
|
m_currMap(nullptr), m_InstanceId(0), m_phaseMask(PHASEMASK_NORMAL), m_useCombinedPhases(true), m_notifyflags(0), m_executed_notifies(0)
|
||||||
{
|
{
|
||||||
m_serverSideVisibility.SetValue(SERVERSIDE_VISIBILITY_GHOST, GHOST_VISIBILITY_ALIVE | GHOST_VISIBILITY_GHOST);
|
m_serverSideVisibility.SetValue(SERVERSIDE_VISIBILITY_GHOST, GHOST_VISIBILITY_ALIVE | GHOST_VISIBILITY_GHOST);
|
||||||
m_serverSideVisibilityDetect.SetValue(SERVERSIDE_VISIBILITY_GHOST, GHOST_VISIBILITY_ALIVE);
|
m_serverSideVisibilityDetect.SetValue(SERVERSIDE_VISIBILITY_GHOST, GHOST_VISIBILITY_ALIVE);
|
||||||
@@ -1040,19 +1040,51 @@ void WorldObject::_Create(ObjectGuid::LowType guidlow, HighGuid guidhigh, uint32
|
|||||||
SetPhaseMask(phaseMask, false);
|
SetPhaseMask(phaseMask, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
uint32 WorldObject::GetZoneId(bool /*forceRecalc*/) const
|
void WorldObject::SetPositionDataUpdate()
|
||||||
{
|
{
|
||||||
return GetBaseMap()->GetZoneId(m_positionX, m_positionY, m_positionZ);
|
_updatePositionData = true;
|
||||||
|
|
||||||
|
// Calls immediately for charmed units
|
||||||
|
if (GetTypeId() == TYPEID_UNIT && ToUnit()->IsCharmedOwnedByPlayerOrPlayer())
|
||||||
|
UpdatePositionData();
|
||||||
}
|
}
|
||||||
|
|
||||||
uint32 WorldObject::GetAreaId(bool /*forceRecalc*/) const
|
void WorldObject::UpdatePositionData()
|
||||||
{
|
{
|
||||||
return GetBaseMap()->GetAreaId(m_positionX, m_positionY, m_positionZ);
|
_updatePositionData = false;
|
||||||
|
|
||||||
|
PositionFullTerrainStatus data;
|
||||||
|
GetMap()->GetFullTerrainStatusForPosition(GetPhaseMask(), GetPositionX(), GetPositionY(), GetPositionZ(), GetCollisionHeight(), data);
|
||||||
|
ProcessPositionDataChanged(data);
|
||||||
}
|
}
|
||||||
|
|
||||||
void WorldObject::GetZoneAndAreaId(uint32& zoneid, uint32& areaid, bool /*forceRecalc*/) const
|
void WorldObject::ProcessPositionDataChanged(PositionFullTerrainStatus const& data)
|
||||||
{
|
{
|
||||||
GetBaseMap()->GetZoneAndAreaId(zoneid, areaid, m_positionX, m_positionY, m_positionZ);
|
_zoneId = _areaId = data.areaId;
|
||||||
|
|
||||||
|
if (AreaTableEntry const* area = sAreaTableStore.LookupEntry(_areaId))
|
||||||
|
if (area->zone)
|
||||||
|
_zoneId = area->zone;
|
||||||
|
|
||||||
|
_outdoors = data.outdoors;
|
||||||
|
_floorZ = data.floorZ;
|
||||||
|
_liquidData = data.liquidInfo;
|
||||||
|
}
|
||||||
|
|
||||||
|
void WorldObject::AddToWorld()
|
||||||
|
{
|
||||||
|
Object::AddToWorld();
|
||||||
|
GetMap()->GetZoneAndAreaId(GetPhaseMask(), _zoneId, _areaId, GetPositionX(), GetPositionY(), GetPositionZ());
|
||||||
|
}
|
||||||
|
|
||||||
|
void WorldObject::RemoveFromWorld()
|
||||||
|
{
|
||||||
|
if (!IsInWorld())
|
||||||
|
return;
|
||||||
|
|
||||||
|
DestroyForNearbyPlayers();
|
||||||
|
|
||||||
|
Object::RemoveFromWorld();
|
||||||
}
|
}
|
||||||
|
|
||||||
InstanceScript* WorldObject::GetInstanceScript()
|
InstanceScript* WorldObject::GetInstanceScript()
|
||||||
@@ -1470,7 +1502,7 @@ void WorldObject::UpdateAllowedPositionZ(float x, float y, float& z, float* grou
|
|||||||
|
|
||||||
if (max_z > INVALID_HEIGHT)
|
if (max_z > INVALID_HEIGHT)
|
||||||
{
|
{
|
||||||
if (canSwim && unit->GetMap()->IsInWater(x, y, max_z - Z_OFFSET_FIND_HEIGHT))
|
if (canSwim && unit->GetMap()->IsInWater(unit->GetPhaseMask(), x, y, max_z - Z_OFFSET_FIND_HEIGHT, unit->GetCollisionHeight()))
|
||||||
{
|
{
|
||||||
// do not allow creatures to walk on
|
// do not allow creatures to walk on
|
||||||
// water level while swimming
|
// water level while swimming
|
||||||
@@ -2137,12 +2169,6 @@ void WorldObject::ResetMap()
|
|||||||
//m_InstanceId = 0;
|
//m_InstanceId = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
Map const* WorldObject::GetBaseMap() const
|
|
||||||
{
|
|
||||||
ASSERT(m_currMap);
|
|
||||||
return m_currMap->GetParent();
|
|
||||||
}
|
|
||||||
|
|
||||||
void WorldObject::AddObjectToRemoveList()
|
void WorldObject::AddObjectToRemoveList()
|
||||||
{
|
{
|
||||||
ASSERT(m_uint32Values);
|
ASSERT(m_uint32Values);
|
||||||
@@ -2307,7 +2333,7 @@ void WorldObject::SetZoneScript()
|
|||||||
m_zoneScript = (ZoneScript*)map->ToInstanceMap()->GetInstanceScript();
|
m_zoneScript = (ZoneScript*)map->ToInstanceMap()->GetInstanceScript();
|
||||||
else if (!map->IsBattlegroundOrArena())
|
else if (!map->IsBattlegroundOrArena())
|
||||||
{
|
{
|
||||||
uint32 zoneId = GetZoneId(true);
|
uint32 zoneId = GetZoneId();
|
||||||
if (Battlefield* bf = sBattlefieldMgr->GetBattlefieldToZoneId(zoneId))
|
if (Battlefield* bf = sBattlefieldMgr->GetBattlefieldToZoneId(zoneId))
|
||||||
m_zoneScript = bf;
|
m_zoneScript = bf;
|
||||||
else
|
else
|
||||||
@@ -3031,10 +3057,54 @@ float WorldObject::GetMapWaterOrGroundLevel(float x, float y, float z, float* gr
|
|||||||
|
|
||||||
float WorldObject::GetFloorZ() const
|
float WorldObject::GetFloorZ() const
|
||||||
{
|
{
|
||||||
if (!IsInWorld())
|
if (_updatePositionData)
|
||||||
return m_staticFloorZ;
|
const_cast<WorldObject*>(this)->UpdatePositionData();
|
||||||
|
|
||||||
return std::max<float>(m_staticFloorZ, GetMap()->GetGameObjectFloor(GetPhaseMask(), GetPositionX(), GetPositionY(), GetPositionZ() + std::max(GetCollisionHeight(), Z_OFFSET_FIND_HEIGHT)));
|
if (!IsInWorld())
|
||||||
|
return _floorZ;
|
||||||
|
|
||||||
|
return std::max<float>(_floorZ, GetMap()->GetGameObjectFloor(GetPhaseMask(), GetPositionX(), GetPositionY(), GetPositionZ() + std::max(GetCollisionHeight(), Z_OFFSET_FIND_HEIGHT)));
|
||||||
|
}
|
||||||
|
|
||||||
|
uint32 WorldObject::GetZoneId() const
|
||||||
|
{
|
||||||
|
if (_updatePositionData)
|
||||||
|
const_cast<WorldObject*>(this)->UpdatePositionData();
|
||||||
|
|
||||||
|
return _zoneId;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint32 WorldObject::GetAreaId() const
|
||||||
|
{
|
||||||
|
if (_updatePositionData)
|
||||||
|
const_cast<WorldObject*>(this)->UpdatePositionData();
|
||||||
|
|
||||||
|
return _areaId;
|
||||||
|
}
|
||||||
|
|
||||||
|
void WorldObject::GetZoneAndAreaId(uint32& zoneid, uint32& areaid) const
|
||||||
|
{
|
||||||
|
if (_updatePositionData)
|
||||||
|
const_cast<WorldObject*>(this)->UpdatePositionData();
|
||||||
|
|
||||||
|
zoneid = _zoneId;
|
||||||
|
areaid = _areaId;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool WorldObject::IsOutdoors() const
|
||||||
|
{
|
||||||
|
if (_updatePositionData)
|
||||||
|
const_cast<WorldObject*>(this)->UpdatePositionData();
|
||||||
|
|
||||||
|
return _outdoors;
|
||||||
|
}
|
||||||
|
|
||||||
|
LiquidData const& WorldObject::GetLiquidData() const
|
||||||
|
{
|
||||||
|
if (_updatePositionData)
|
||||||
|
const_cast<WorldObject*>(this)->UpdatePositionData();
|
||||||
|
|
||||||
|
return _liquidData;
|
||||||
}
|
}
|
||||||
|
|
||||||
void WorldObject::AddAllowedLooter(ObjectGuid guid)
|
void WorldObject::AddAllowedLooter(ObjectGuid guid)
|
||||||
|
|||||||
@@ -69,6 +69,8 @@ class Transport;
|
|||||||
class StaticTransport;
|
class StaticTransport;
|
||||||
class MotionTransport;
|
class MotionTransport;
|
||||||
|
|
||||||
|
struct PositionFullTerrainStatus;
|
||||||
|
|
||||||
typedef std::unordered_map<Player*, UpdateData> UpdateDataMapType;
|
typedef std::unordered_map<Player*, UpdateData> UpdateDataMapType;
|
||||||
typedef GuidUnorderedSet UpdatePlayerSet;
|
typedef GuidUnorderedSet UpdatePlayerSet;
|
||||||
|
|
||||||
@@ -750,15 +752,8 @@ public:
|
|||||||
#endif
|
#endif
|
||||||
void _Create(ObjectGuid::LowType guidlow, HighGuid guidhigh, uint32 phaseMask);
|
void _Create(ObjectGuid::LowType guidlow, HighGuid guidhigh, uint32 phaseMask);
|
||||||
|
|
||||||
void RemoveFromWorld() override
|
void AddToWorld() override;
|
||||||
{
|
void RemoveFromWorld() override;
|
||||||
if (!IsInWorld())
|
|
||||||
return;
|
|
||||||
|
|
||||||
DestroyForNearbyPlayers();
|
|
||||||
|
|
||||||
Object::RemoveFromWorld();
|
|
||||||
}
|
|
||||||
|
|
||||||
#ifdef ELUNA
|
#ifdef ELUNA
|
||||||
ElunaEventProcessor* elunaEvents;
|
ElunaEventProcessor* elunaEvents;
|
||||||
@@ -817,9 +812,11 @@ public:
|
|||||||
bool InSamePhase(WorldObject const* obj) const { return InSamePhase(obj->GetPhaseMask()); }
|
bool InSamePhase(WorldObject const* obj) const { return InSamePhase(obj->GetPhaseMask()); }
|
||||||
[[nodiscard]] bool InSamePhase(uint32 phasemask) const { return m_useCombinedPhases ? GetPhaseMask() & phasemask : GetPhaseMask() == phasemask; }
|
[[nodiscard]] bool InSamePhase(uint32 phasemask) const { return m_useCombinedPhases ? GetPhaseMask() & phasemask : GetPhaseMask() == phasemask; }
|
||||||
|
|
||||||
[[nodiscard]] virtual uint32 GetZoneId(bool forceRecalc = false) const;
|
[[nodiscard]] uint32 GetZoneId() const;
|
||||||
[[nodiscard]] virtual uint32 GetAreaId(bool forceRecalc = false) const;
|
[[nodiscard]] uint32 GetAreaId() const;
|
||||||
virtual void GetZoneAndAreaId(uint32& zoneid, uint32& areaid, bool forceRecalc = false) const;
|
void GetZoneAndAreaId(uint32& zoneid, uint32& areaid) const;
|
||||||
|
[[nodiscard]] bool IsOutdoors() const;
|
||||||
|
LiquidData const& GetLiquidData() const;
|
||||||
|
|
||||||
InstanceScript* GetInstanceScript();
|
InstanceScript* GetInstanceScript();
|
||||||
|
|
||||||
@@ -948,9 +945,6 @@ public:
|
|||||||
[[nodiscard]] Map* FindMap() const { return m_currMap; }
|
[[nodiscard]] Map* FindMap() const { return m_currMap; }
|
||||||
//used to check all object's GetMap() calls when object is not in world!
|
//used to check all object's GetMap() calls when object is not in world!
|
||||||
|
|
||||||
//this function should be removed in nearest time...
|
|
||||||
[[nodiscard]] Map const* GetBaseMap() const;
|
|
||||||
|
|
||||||
void SetZoneScript();
|
void SetZoneScript();
|
||||||
void ClearZoneScript();
|
void ClearZoneScript();
|
||||||
[[nodiscard]] ZoneScript* GetZoneScript() const { return m_zoneScript; }
|
[[nodiscard]] ZoneScript* GetZoneScript() const { return m_zoneScript; }
|
||||||
@@ -984,6 +978,9 @@ public:
|
|||||||
void BuildUpdate(UpdateDataMapType& data_map, UpdatePlayerSet& player_set) override;
|
void BuildUpdate(UpdateDataMapType& data_map, UpdatePlayerSet& player_set) override;
|
||||||
void GetCreaturesWithEntryInRange(std::list<Creature*>& creatureList, float radius, uint32 entry);
|
void GetCreaturesWithEntryInRange(std::list<Creature*>& creatureList, float radius, uint32 entry);
|
||||||
|
|
||||||
|
void SetPositionDataUpdate();
|
||||||
|
void UpdatePositionData();
|
||||||
|
|
||||||
void AddToObjectUpdate() override;
|
void AddToObjectUpdate() override;
|
||||||
void RemoveFromObjectUpdate() override;
|
void RemoveFromObjectUpdate() override;
|
||||||
|
|
||||||
@@ -1060,7 +1057,13 @@ protected:
|
|||||||
const bool m_isWorldObject;
|
const bool m_isWorldObject;
|
||||||
ZoneScript* m_zoneScript;
|
ZoneScript* m_zoneScript;
|
||||||
|
|
||||||
float m_staticFloorZ;
|
virtual void ProcessPositionDataChanged(PositionFullTerrainStatus const& data);
|
||||||
|
uint32 _zoneId;
|
||||||
|
uint32 _areaId;
|
||||||
|
float _floorZ;
|
||||||
|
bool _outdoors;
|
||||||
|
LiquidData _liquidData;
|
||||||
|
bool _updatePositionData;
|
||||||
|
|
||||||
// transports
|
// transports
|
||||||
Transport* m_transport;
|
Transport* m_transport;
|
||||||
|
|||||||
@@ -666,6 +666,8 @@ bool Pet::CreateBaseAtCreature(Creature* creature)
|
|||||||
|
|
||||||
SetDisplayId(creature->GetDisplayId());
|
SetDisplayId(creature->GetDisplayId());
|
||||||
|
|
||||||
|
UpdatePositionData();
|
||||||
|
|
||||||
if (CreatureFamilyEntry const* cFamily = sCreatureFamilyStore.LookupEntry(cinfo->family))
|
if (CreatureFamilyEntry const* cFamily = sCreatureFamilyStore.LookupEntry(cinfo->family))
|
||||||
SetName(cFamily->Name[sWorld->GetDefaultDbcLocale()]);
|
SetName(cFamily->Name[sWorld->GetDefaultDbcLocale()]);
|
||||||
else
|
else
|
||||||
@@ -684,6 +686,8 @@ bool Pet::CreateBaseAtCreatureInfo(CreatureTemplate const* cinfo, Unit* owner)
|
|||||||
|
|
||||||
Relocate(owner->GetPositionX(), owner->GetPositionY(), owner->GetPositionZ(), owner->GetOrientation());
|
Relocate(owner->GetPositionX(), owner->GetPositionY(), owner->GetPositionZ(), owner->GetOrientation());
|
||||||
|
|
||||||
|
UpdatePositionData();
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -591,6 +591,8 @@ bool Player::Create(ObjectGuid::LowType guidlow, CharacterCreateInfo* createInfo
|
|||||||
InitTalentForLevel();
|
InitTalentForLevel();
|
||||||
InitPrimaryProfessions(); // to max set before any spell added
|
InitPrimaryProfessions(); // to max set before any spell added
|
||||||
|
|
||||||
|
UpdatePositionData();
|
||||||
|
|
||||||
// apply original stats mods before spell loading or item equipment that call before equip _RemoveStatsMods()
|
// apply original stats mods before spell loading or item equipment that call before equip _RemoveStatsMods()
|
||||||
UpdateMaxHealth(); // Update max Health (for add bonus from stamina)
|
UpdateMaxHealth(); // Update max Health (for add bonus from stamina)
|
||||||
SetFullHealth();
|
SetFullHealth();
|
||||||
@@ -876,7 +878,7 @@ void Player::HandleDrowning(uint32 time_diff)
|
|||||||
}
|
}
|
||||||
|
|
||||||
// In dark water
|
// In dark water
|
||||||
if (m_MirrorTimerFlags & UNDERWARER_INDARKWATER)
|
if (m_MirrorTimerFlags & UNDERWATER_INDARKWATER)
|
||||||
{
|
{
|
||||||
// Fatigue timer not activated - activate it
|
// Fatigue timer not activated - activate it
|
||||||
if (m_MirrorTimer[FATIGUE_TIMER] == DISABLED_MIRROR_TIMER)
|
if (m_MirrorTimer[FATIGUE_TIMER] == DISABLED_MIRROR_TIMER)
|
||||||
@@ -899,7 +901,7 @@ void Player::HandleDrowning(uint32 time_diff)
|
|||||||
else if (HasFlag(PLAYER_FLAGS, PLAYER_FLAGS_GHOST)) // Teleport ghost to graveyard
|
else if (HasFlag(PLAYER_FLAGS, PLAYER_FLAGS_GHOST)) // Teleport ghost to graveyard
|
||||||
RepopAtGraveyard();
|
RepopAtGraveyard();
|
||||||
}
|
}
|
||||||
else if (!(m_MirrorTimerFlagsLast & UNDERWARER_INDARKWATER))
|
else if (!(m_MirrorTimerFlagsLast & UNDERWATER_INDARKWATER))
|
||||||
SendMirrorTimer(FATIGUE_TIMER, getMaxTimer(FATIGUE_TIMER), m_MirrorTimer[FATIGUE_TIMER], -1);
|
SendMirrorTimer(FATIGUE_TIMER, getMaxTimer(FATIGUE_TIMER), m_MirrorTimer[FATIGUE_TIMER], -1);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -909,7 +911,7 @@ void Player::HandleDrowning(uint32 time_diff)
|
|||||||
m_MirrorTimer[FATIGUE_TIMER] += 10 * time_diff;
|
m_MirrorTimer[FATIGUE_TIMER] += 10 * time_diff;
|
||||||
if (m_MirrorTimer[FATIGUE_TIMER] >= DarkWaterTime || !IsAlive())
|
if (m_MirrorTimer[FATIGUE_TIMER] >= DarkWaterTime || !IsAlive())
|
||||||
StopMirrorTimer(FATIGUE_TIMER);
|
StopMirrorTimer(FATIGUE_TIMER);
|
||||||
else if (m_MirrorTimerFlagsLast & UNDERWARER_INDARKWATER)
|
else if (m_MirrorTimerFlagsLast & UNDERWATER_INDARKWATER)
|
||||||
SendMirrorTimer(FATIGUE_TIMER, DarkWaterTime, m_MirrorTimer[FATIGUE_TIMER], 10);
|
SendMirrorTimer(FATIGUE_TIMER, DarkWaterTime, m_MirrorTimer[FATIGUE_TIMER], 10);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -2066,31 +2068,6 @@ GameObject* Player::GetGameObjectIfCanInteractWith(ObjectGuid guid, GameobjectTy
|
|||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Player::IsInWater(bool allowAbove) const
|
|
||||||
{
|
|
||||||
if (m_isInWater || !allowAbove)
|
|
||||||
return m_isInWater;
|
|
||||||
|
|
||||||
float distsq = GetExactDistSq(&m_last_environment_position);
|
|
||||||
if (distsq < 3.0f * 3.0f)
|
|
||||||
return m_last_islittleabovewater_status;
|
|
||||||
else
|
|
||||||
{
|
|
||||||
LiquidData liqData;
|
|
||||||
liqData.level = INVALID_HEIGHT;
|
|
||||||
const_cast<Position*>(&m_last_environment_position)->Relocate(GetPositionX(), GetPositionY(), GetPositionZ());
|
|
||||||
bool inWater = GetBaseMap()->IsInWater(GetPositionX(), GetPositionY(), GetPositionZ(), &liqData);
|
|
||||||
*(const_cast<bool*>(&m_last_islittleabovewater_status)) = inWater || (liqData.level > INVALID_HEIGHT && liqData.level > liqData.depth_level && liqData.level <= GetPositionZ() + 3.0f && liqData.level > GetPositionZ() - 1.0f);
|
|
||||||
return m_last_islittleabovewater_status;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
bool Player::IsUnderWater() const
|
|
||||||
{
|
|
||||||
return IsInWater() &&
|
|
||||||
GetPositionZ() < GetBaseMap()->GetWaterLevel(GetPositionX(), GetPositionY()) - GetCollisionHeight();
|
|
||||||
}
|
|
||||||
|
|
||||||
bool Player::IsFalling() const
|
bool Player::IsFalling() const
|
||||||
{
|
{
|
||||||
// Xinef: Added !IsInFlight check
|
// Xinef: Added !IsInFlight check
|
||||||
@@ -4355,7 +4332,7 @@ void Player::ResurrectPlayer(float restore_percent, bool applySickness)
|
|||||||
|
|
||||||
// trigger update zone for alive state zone updates
|
// trigger update zone for alive state zone updates
|
||||||
uint32 newzone, newarea;
|
uint32 newzone, newarea;
|
||||||
GetZoneAndAreaId(newzone, newarea, true);
|
GetZoneAndAreaId(newzone, newarea);
|
||||||
UpdateZone(newzone, newarea);
|
UpdateZone(newzone, newarea);
|
||||||
sOutdoorPvPMgr->HandlePlayerResurrects(this, newzone);
|
sOutdoorPvPMgr->HandlePlayerResurrects(this, newzone);
|
||||||
|
|
||||||
@@ -4508,6 +4485,8 @@ Corpse* Player::CreateCorpse()
|
|||||||
// register for player, but not show
|
// register for player, but not show
|
||||||
GetMap()->AddCorpse(corpse);
|
GetMap()->AddCorpse(corpse);
|
||||||
|
|
||||||
|
UpdatePositionData();
|
||||||
|
|
||||||
// we do not need to save corpses for BG/arenas
|
// we do not need to save corpses for BG/arenas
|
||||||
if (!GetMap()->IsBattlegroundOrArena())
|
if (!GetMap()->IsBattlegroundOrArena())
|
||||||
corpse->SaveToDB();
|
corpse->SaveToDB();
|
||||||
@@ -5563,7 +5542,7 @@ void Player::CheckAreaExploreAndOutdoor()
|
|||||||
return;
|
return;
|
||||||
|
|
||||||
bool isOutdoor = IsOutdoors();
|
bool isOutdoor = IsOutdoors();
|
||||||
uint32 areaId = GetBaseMap()->GetAreaId(GetPositionX(), GetPositionY(), GetPositionZ(), &isOutdoor);
|
uint32 areaId = GetAreaId();
|
||||||
AreaTableEntry const* areaEntry = sAreaTableStore.LookupEntry(areaId);
|
AreaTableEntry const* areaEntry = sAreaTableStore.LookupEntry(areaId);
|
||||||
|
|
||||||
if (sWorld->getBoolConfig(CONFIG_VMAP_INDOOR_CHECK) && !isOutdoor)
|
if (sWorld->getBoolConfig(CONFIG_VMAP_INDOOR_CHECK) && !isOutdoor)
|
||||||
@@ -6159,7 +6138,7 @@ uint32 Player::GetZoneIdFromDB(ObjectGuid guid)
|
|||||||
if (!sMapStore.LookupEntry(map))
|
if (!sMapStore.LookupEntry(map))
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
zone = sMapMgr->GetZoneId(map, posx, posy, posz);
|
zone = sMapMgr->GetZoneId(PHASEMASK_NORMAL, map, posx, posy, posz);
|
||||||
|
|
||||||
if (zone > 0)
|
if (zone > 0)
|
||||||
{
|
{
|
||||||
@@ -6184,36 +6163,6 @@ uint32 Player::GetLevelFromStorage(ObjectGuid::LowType guid)
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
uint32 Player::GetZoneId(bool forceRecalc) const
|
|
||||||
{
|
|
||||||
if (forceRecalc)
|
|
||||||
*(const_cast<uint32*>(&m_last_zone_id)) = WorldObject::GetZoneId();
|
|
||||||
|
|
||||||
return m_last_zone_id;
|
|
||||||
}
|
|
||||||
|
|
||||||
uint32 Player::GetAreaId(bool forceRecalc) const
|
|
||||||
{
|
|
||||||
if (forceRecalc)
|
|
||||||
*(const_cast<uint32*>(&m_last_area_id)) = WorldObject::GetAreaId();
|
|
||||||
|
|
||||||
return m_last_area_id;
|
|
||||||
}
|
|
||||||
|
|
||||||
void Player::GetZoneAndAreaId(uint32& zoneid, uint32& areaid, bool forceRecalc) const
|
|
||||||
{
|
|
||||||
if (forceRecalc)
|
|
||||||
{
|
|
||||||
WorldObject::GetZoneAndAreaId(zoneid, areaid);
|
|
||||||
*(const_cast<uint32*>(&m_last_zone_id)) = zoneid;
|
|
||||||
*(const_cast<uint32*>(&m_last_area_id)) = areaid;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
zoneid = m_last_zone_id;
|
|
||||||
areaid = m_last_area_id;
|
|
||||||
}
|
|
||||||
|
|
||||||
//If players are too far away from the duel flag... they lose the duel
|
//If players are too far away from the duel flag... they lose the duel
|
||||||
void Player::CheckDuelDistance(time_t currTime)
|
void Player::CheckDuelDistance(time_t currTime)
|
||||||
{
|
{
|
||||||
@@ -10849,7 +10798,7 @@ void Player::SendInitialPacketsAfterAddToMap()
|
|||||||
|
|
||||||
// update zone
|
// update zone
|
||||||
uint32 newzone, newarea;
|
uint32 newzone, newarea;
|
||||||
GetZoneAndAreaId(newzone, newarea, true);
|
GetZoneAndAreaId(newzone, newarea);
|
||||||
UpdateZone(newzone, newarea); // also call SendInitWorldStates();
|
UpdateZone(newzone, newarea); // also call SendInitWorldStates();
|
||||||
|
|
||||||
if (HasAuraType(SPELL_AURA_MOD_STUN))
|
if (HasAuraType(SPELL_AURA_MOD_STUN))
|
||||||
@@ -13758,7 +13707,7 @@ void Player::_SaveCharacter(bool create, CharacterDatabaseTransaction trans)
|
|||||||
stmt->setUInt16(index++, (uint16)m_ExtraFlags);
|
stmt->setUInt16(index++, (uint16)m_ExtraFlags);
|
||||||
stmt->setUInt8(index++, m_stableSlots);
|
stmt->setUInt8(index++, m_stableSlots);
|
||||||
stmt->setUInt16(index++, (uint16)m_atLoginFlags);
|
stmt->setUInt16(index++, (uint16)m_atLoginFlags);
|
||||||
stmt->setUInt16(index++, GetZoneId(true));
|
stmt->setUInt16(index++, GetZoneId());
|
||||||
stmt->setUInt32(index++, uint32(m_deathExpireTime));
|
stmt->setUInt32(index++, uint32(m_deathExpireTime));
|
||||||
|
|
||||||
ss.str("");
|
ss.str("");
|
||||||
@@ -13896,7 +13845,7 @@ void Player::_SaveCharacter(bool create, CharacterDatabaseTransaction trans)
|
|||||||
stmt->setUInt16(index++, (uint16)m_ExtraFlags);
|
stmt->setUInt16(index++, (uint16)m_ExtraFlags);
|
||||||
stmt->setUInt8(index++, m_stableSlots);
|
stmt->setUInt8(index++, m_stableSlots);
|
||||||
stmt->setUInt16(index++, (uint16)m_atLoginFlags);
|
stmt->setUInt16(index++, (uint16)m_atLoginFlags);
|
||||||
stmt->setUInt16(index++, GetZoneId(true));
|
stmt->setUInt16(index++, GetZoneId());
|
||||||
stmt->setUInt32(index++, uint32(m_deathExpireTime));
|
stmt->setUInt32(index++, uint32(m_deathExpireTime));
|
||||||
|
|
||||||
ss.str("");
|
ss.str("");
|
||||||
|
|||||||
@@ -85,7 +85,7 @@ enum PlayerUnderwaterState
|
|||||||
UNDERWATER_INWATER = 0x01, // terrain type is water and player is afflicted by it
|
UNDERWATER_INWATER = 0x01, // terrain type is water and player is afflicted by it
|
||||||
UNDERWATER_INLAVA = 0x02, // terrain type is lava and player is afflicted by it
|
UNDERWATER_INLAVA = 0x02, // terrain type is lava and player is afflicted by it
|
||||||
UNDERWATER_INSLIME = 0x04, // terrain type is lava and player is afflicted by it
|
UNDERWATER_INSLIME = 0x04, // terrain type is lava and player is afflicted by it
|
||||||
UNDERWARER_INDARKWATER = 0x08, // terrain type is dark water and player is afflicted by it
|
UNDERWATER_INDARKWATER = 0x08, // terrain type is dark water and player is afflicted by it
|
||||||
|
|
||||||
UNDERWATER_EXIST_TIMERS = 0x10
|
UNDERWATER_EXIST_TIMERS = 0x10
|
||||||
};
|
};
|
||||||
@@ -1021,8 +1021,7 @@ public:
|
|||||||
|
|
||||||
void SetInWater(bool apply);
|
void SetInWater(bool apply);
|
||||||
|
|
||||||
[[nodiscard]] bool IsInWater(bool allowAbove = false) const override;
|
[[nodiscard]] bool IsInWater() const override { return m_isInWater; }
|
||||||
[[nodiscard]] bool IsUnderWater() const override;
|
|
||||||
[[nodiscard]] bool IsFalling() const;
|
[[nodiscard]] bool IsFalling() const;
|
||||||
bool IsInAreaTriggerRadius(const AreaTrigger* trigger) const;
|
bool IsInAreaTriggerRadius(const AreaTrigger* trigger) const;
|
||||||
|
|
||||||
@@ -1737,10 +1736,6 @@ public:
|
|||||||
void UpdateZone(uint32 newZone, uint32 newArea);
|
void UpdateZone(uint32 newZone, uint32 newArea);
|
||||||
void UpdateArea(uint32 newArea);
|
void UpdateArea(uint32 newArea);
|
||||||
|
|
||||||
[[nodiscard]] uint32 GetZoneId(bool forceRecalc = false) const override;
|
|
||||||
[[nodiscard]] uint32 GetAreaId(bool forceRecalc = false) const override;
|
|
||||||
void GetZoneAndAreaId(uint32& zoneid, uint32& areaid, bool forceRecalc = false) const override;
|
|
||||||
|
|
||||||
void UpdateZoneDependentAuras(uint32 zone_id); // zones
|
void UpdateZoneDependentAuras(uint32 zone_id); // zones
|
||||||
void UpdateAreaDependentAuras(uint32 area_id); // subzones
|
void UpdateAreaDependentAuras(uint32 area_id); // subzones
|
||||||
|
|
||||||
@@ -1905,7 +1900,8 @@ public:
|
|||||||
|
|
||||||
bool UpdatePosition(float x, float y, float z, float orientation, bool teleport = false) override;
|
bool UpdatePosition(float x, float y, float z, float orientation, bool teleport = false) override;
|
||||||
bool UpdatePosition(const Position& pos, bool teleport = false) { return UpdatePosition(pos.GetPositionX(), pos.GetPositionY(), pos.GetPositionZ(), pos.GetOrientation(), teleport); }
|
bool UpdatePosition(const Position& pos, bool teleport = false) { return UpdatePosition(pos.GetPositionX(), pos.GetPositionY(), pos.GetPositionZ(), pos.GetOrientation(), teleport); }
|
||||||
void UpdateUnderwaterState(Map* m, float x, float y, float z) override;
|
|
||||||
|
void ProcessTerrainStatusUpdate() override;
|
||||||
|
|
||||||
void SendMessageToSet(WorldPacket* data, bool self) override { SendMessageToSetInRange(data, GetVisibilityRange(), self, true); } // pussywizard!
|
void SendMessageToSet(WorldPacket* data, bool self) override { SendMessageToSetInRange(data, GetVisibilityRange(), self, true); } // pussywizard!
|
||||||
void SendMessageToSetInRange(WorldPacket* data, float dist, bool self, bool includeMargin = false, Player const* skipped_rcvr = nullptr) override; // pussywizard!
|
void SendMessageToSetInRange(WorldPacket* data, float dist, bool self, bool includeMargin = false, Player const* skipped_rcvr = nullptr) override; // pussywizard!
|
||||||
|
|||||||
@@ -5241,6 +5241,8 @@ bool Player::LoadFromDB(ObjectGuid playerGuid, CharacterDatabaseQueryHolder cons
|
|||||||
SetMap(map);
|
SetMap(map);
|
||||||
StoreRaidMapDifficulty();
|
StoreRaidMapDifficulty();
|
||||||
|
|
||||||
|
UpdatePositionData();
|
||||||
|
|
||||||
SaveRecallPosition();
|
SaveRecallPosition();
|
||||||
|
|
||||||
time_t now = time(nullptr);
|
time_t now = time(nullptr);
|
||||||
@@ -5772,7 +5774,7 @@ void Player::_LoadInventory(PreparedQueryResult result, uint32 timeDiff)
|
|||||||
|
|
||||||
if (result)
|
if (result)
|
||||||
{
|
{
|
||||||
uint32 zoneId = GetZoneId(true);
|
uint32 zoneId = GetZoneId();
|
||||||
|
|
||||||
std::map<ObjectGuid::LowType, Bag*> bagMap; // fast guid lookup for bags
|
std::map<ObjectGuid::LowType, Bag*> bagMap; // fast guid lookup for bags
|
||||||
std::map<ObjectGuid::LowType, Item*> invalidBagMap; // fast guid lookup for bags
|
std::map<ObjectGuid::LowType, Item*> invalidBagMap; // fast guid lookup for bags
|
||||||
|
|||||||
@@ -268,9 +268,7 @@ void Player::Update(uint32 p_time)
|
|||||||
}
|
}
|
||||||
|
|
||||||
uint32 newzone, newarea;
|
uint32 newzone, newarea;
|
||||||
GetZoneAndAreaId(newzone, newarea, true);
|
GetZoneAndAreaId(newzone, newarea);
|
||||||
m_last_zone_id = newzone;
|
|
||||||
m_last_area_id = newarea;
|
|
||||||
|
|
||||||
if (m_zoneUpdateId != newzone)
|
if (m_zoneUpdateId != newzone)
|
||||||
UpdateZone(newzone, newarea); // also update area
|
UpdateZone(newzone, newarea); // also update area
|
||||||
@@ -354,7 +352,7 @@ void Player::Update(uint32 p_time)
|
|||||||
}
|
}
|
||||||
|
|
||||||
// not auto-free ghost from body in instances
|
// not auto-free ghost from body in instances
|
||||||
if (m_deathTimer > 0 && !GetBaseMap()->Instanceable() &&
|
if (m_deathTimer > 0 && !GetMap()->Instanceable() &&
|
||||||
!HasAuraType(SPELL_AURA_PREVENT_RESURRECTION))
|
!HasAuraType(SPELL_AURA_PREVENT_RESURRECTION))
|
||||||
{
|
{
|
||||||
if (p_time >= m_deathTimer)
|
if (p_time >= m_deathTimer)
|
||||||
@@ -1975,96 +1973,6 @@ void Player::UpdateCorpseReclaimDelay()
|
|||||||
m_deathExpireTime = now + DEATH_EXPIRE_STEP;
|
m_deathExpireTime = now + DEATH_EXPIRE_STEP;
|
||||||
}
|
}
|
||||||
|
|
||||||
void Player::UpdateUnderwaterState(Map* m, float x, float y, float z)
|
|
||||||
{
|
|
||||||
// pussywizard: optimization
|
|
||||||
if (GetExactDistSq(&m_last_underwaterstate_position) < 3.0f * 3.0f)
|
|
||||||
return;
|
|
||||||
|
|
||||||
m_last_underwaterstate_position.Relocate(m_positionX, m_positionY,
|
|
||||||
m_positionZ);
|
|
||||||
|
|
||||||
if (!IsPositionValid()) // pussywizard: crashfix if calculated grid coords
|
|
||||||
// would be out of range 0-64
|
|
||||||
return;
|
|
||||||
|
|
||||||
LiquidData liquid_status;
|
|
||||||
ZLiquidStatus res = m->getLiquidStatus(
|
|
||||||
x, y, z, MAP_ALL_LIQUIDS, &liquid_status, GetCollisionHeight());
|
|
||||||
if (!res)
|
|
||||||
{
|
|
||||||
m_MirrorTimerFlags &= ~(UNDERWATER_INWATER | UNDERWATER_INLAVA |
|
|
||||||
UNDERWATER_INSLIME | UNDERWARER_INDARKWATER);
|
|
||||||
if (_lastLiquid && _lastLiquid->SpellId)
|
|
||||||
RemoveAurasDueToSpell(_lastLiquid->SpellId);
|
|
||||||
|
|
||||||
_lastLiquid = nullptr;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (uint32 liqEntry = liquid_status.entry)
|
|
||||||
{
|
|
||||||
LiquidTypeEntry const* liquid = sLiquidTypeStore.LookupEntry(liqEntry);
|
|
||||||
if (_lastLiquid && _lastLiquid->SpellId && _lastLiquid->Id != liqEntry)
|
|
||||||
RemoveAurasDueToSpell(_lastLiquid->SpellId);
|
|
||||||
|
|
||||||
if (liquid && liquid->SpellId)
|
|
||||||
{
|
|
||||||
if (res & (LIQUID_MAP_UNDER_WATER | LIQUID_MAP_IN_WATER))
|
|
||||||
{
|
|
||||||
if (!HasAura(liquid->SpellId))
|
|
||||||
CastSpell(this, liquid->SpellId, true);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
RemoveAurasDueToSpell(liquid->SpellId);
|
|
||||||
}
|
|
||||||
|
|
||||||
_lastLiquid = liquid;
|
|
||||||
}
|
|
||||||
else if (_lastLiquid && _lastLiquid->SpellId)
|
|
||||||
{
|
|
||||||
RemoveAurasDueToSpell(_lastLiquid->SpellId);
|
|
||||||
_lastLiquid = nullptr;
|
|
||||||
}
|
|
||||||
|
|
||||||
// All liquids type - check under water position
|
|
||||||
if (liquid_status.type_flags &
|
|
||||||
(MAP_LIQUID_TYPE_WATER | MAP_LIQUID_TYPE_OCEAN | MAP_LIQUID_TYPE_MAGMA |
|
|
||||||
MAP_LIQUID_TYPE_SLIME))
|
|
||||||
{
|
|
||||||
if (res & LIQUID_MAP_UNDER_WATER)
|
|
||||||
m_MirrorTimerFlags |= UNDERWATER_INWATER;
|
|
||||||
else
|
|
||||||
m_MirrorTimerFlags &= ~UNDERWATER_INWATER;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Allow travel in dark water on taxi or transport
|
|
||||||
if ((liquid_status.type_flags & MAP_LIQUID_TYPE_DARK_WATER) &&
|
|
||||||
!IsInFlight() && !GetTransport())
|
|
||||||
m_MirrorTimerFlags |= UNDERWARER_INDARKWATER;
|
|
||||||
else
|
|
||||||
m_MirrorTimerFlags &= ~UNDERWARER_INDARKWATER;
|
|
||||||
|
|
||||||
// in lava check, anywhere in lava level
|
|
||||||
if (liquid_status.type_flags & MAP_LIQUID_TYPE_MAGMA)
|
|
||||||
{
|
|
||||||
if (res & (LIQUID_MAP_UNDER_WATER | LIQUID_MAP_IN_WATER |
|
|
||||||
LIQUID_MAP_WATER_WALK))
|
|
||||||
m_MirrorTimerFlags |= UNDERWATER_INLAVA;
|
|
||||||
else
|
|
||||||
m_MirrorTimerFlags &= ~UNDERWATER_INLAVA;
|
|
||||||
}
|
|
||||||
// in slime check, anywhere in slime level
|
|
||||||
if (liquid_status.type_flags & MAP_LIQUID_TYPE_SLIME)
|
|
||||||
{
|
|
||||||
if (res & (LIQUID_MAP_UNDER_WATER | LIQUID_MAP_IN_WATER |
|
|
||||||
LIQUID_MAP_WATER_WALK))
|
|
||||||
m_MirrorTimerFlags |= UNDERWATER_INSLIME;
|
|
||||||
else
|
|
||||||
m_MirrorTimerFlags &= ~UNDERWATER_INSLIME;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void Player::UpdateCharmedAI()
|
void Player::UpdateCharmedAI()
|
||||||
{
|
{
|
||||||
// Xinef: maybe passed as argument?
|
// Xinef: maybe passed as argument?
|
||||||
@@ -2361,3 +2269,58 @@ void Player::SendUpdateWorldState(uint32 Field, uint32 Value)
|
|||||||
data << Value;
|
data << Value;
|
||||||
GetSession()->SendPacket(&data);
|
GetSession()->SendPacket(&data);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void Player::ProcessTerrainStatusUpdate()
|
||||||
|
{
|
||||||
|
// process liquid auras using generic unit code
|
||||||
|
Unit::ProcessTerrainStatusUpdate();
|
||||||
|
|
||||||
|
LiquidData const& liquidData = GetLiquidData();
|
||||||
|
|
||||||
|
// player specific logic for mirror timers
|
||||||
|
if (liquidData.Status != LIQUID_MAP_NO_WATER)
|
||||||
|
{
|
||||||
|
// Breath bar state (under water in any liquid type)
|
||||||
|
if ((liquidData.Flags & MAP_ALL_LIQUIDS) != 0)
|
||||||
|
{
|
||||||
|
if ((liquidData.Status & LIQUID_MAP_UNDER_WATER) != 0)
|
||||||
|
m_MirrorTimerFlags |= UNDERWATER_INWATER;
|
||||||
|
else
|
||||||
|
m_MirrorTimerFlags &= ~UNDERWATER_INWATER;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Fatigue bar state (if not on flight path or transport)
|
||||||
|
if ((liquidData.Flags & MAP_LIQUID_TYPE_DARK_WATER) && !IsInFlight() && !GetTransport())
|
||||||
|
{
|
||||||
|
// Exclude also uncontrollable vehicles
|
||||||
|
Vehicle* vehicle = GetVehicle();
|
||||||
|
VehicleSeatEntry const* vehicleSeat = vehicle ? vehicle->GetSeatForPassenger(this) : nullptr;
|
||||||
|
if (!vehicleSeat || vehicleSeat->CanControl())
|
||||||
|
m_MirrorTimerFlags |= UNDERWATER_INDARKWATER;
|
||||||
|
else
|
||||||
|
m_MirrorTimerFlags &= ~UNDERWATER_INDARKWATER;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
m_MirrorTimerFlags &= ~UNDERWATER_INDARKWATER;
|
||||||
|
|
||||||
|
// Lava state (any contact)
|
||||||
|
if (liquidData.Flags & MAP_LIQUID_TYPE_MAGMA)
|
||||||
|
{
|
||||||
|
if (liquidData.Status & MAP_LIQUID_STATUS_IN_CONTACT)
|
||||||
|
m_MirrorTimerFlags |= UNDERWATER_INLAVA;
|
||||||
|
else
|
||||||
|
m_MirrorTimerFlags &= ~UNDERWATER_INLAVA;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Slime state (any contact)
|
||||||
|
if (liquidData.Flags & MAP_LIQUID_TYPE_SLIME)
|
||||||
|
{
|
||||||
|
if (liquidData.Status & MAP_LIQUID_STATUS_IN_CONTACT)
|
||||||
|
m_MirrorTimerFlags |= UNDERWATER_INSLIME;
|
||||||
|
else
|
||||||
|
m_MirrorTimerFlags &= ~UNDERWATER_INSLIME;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
m_MirrorTimerFlags &= ~(UNDERWATER_INWATER | UNDERWATER_INLAVA | UNDERWATER_INSLIME | UNDERWATER_INDARKWATER);
|
||||||
|
}
|
||||||
|
|||||||
@@ -91,6 +91,7 @@ bool MotionTransport::CreateMoTrans(ObjectGuid::LowType guidlow, uint32 entry, u
|
|||||||
SetTransportPathRotation(0.0f, 0.0f, 0.0f, 1.0f);
|
SetTransportPathRotation(0.0f, 0.0f, 0.0f, 1.0f);
|
||||||
|
|
||||||
m_model = CreateModel();
|
m_model = CreateModel();
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -676,6 +677,8 @@ bool StaticTransport::Create(ObjectGuid::LowType guidlow, uint32 name_id, Map* m
|
|||||||
|
|
||||||
SetPhaseMask(phaseMask, false);
|
SetPhaseMask(phaseMask, false);
|
||||||
|
|
||||||
|
UpdatePositionData();
|
||||||
|
|
||||||
SetZoneScript();
|
SetZoneScript();
|
||||||
if (m_zoneScript)
|
if (m_zoneScript)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -284,18 +284,6 @@ Unit::Unit(bool isWorldObject) : WorldObject(isWorldObject),
|
|||||||
m_delayed_unit_relocation_timer = 0;
|
m_delayed_unit_relocation_timer = 0;
|
||||||
m_delayed_unit_ai_notify_timer = 0;
|
m_delayed_unit_ai_notify_timer = 0;
|
||||||
bRequestForcedVisibilityUpdate = false;
|
bRequestForcedVisibilityUpdate = false;
|
||||||
m_last_underwaterstate_position.Relocate(-5000.0f, -5000.0f, -5000.0f, 0.0f);
|
|
||||||
m_last_environment_position.Relocate(-5000.0f, -5000.0f, -5000.0f, 0.0f);
|
|
||||||
m_last_isinwater_status = false;
|
|
||||||
m_last_islittleabovewater_status = false;
|
|
||||||
m_last_isunderwater_status = false;
|
|
||||||
m_is_updating_environment = false;
|
|
||||||
m_last_area_position.Relocate(-5000.0f, -5000.0f, -5000.0f, 0.0f);
|
|
||||||
m_last_zone_position.Relocate(-5000.0f, -5000.0f, -5000.0f, 0.0f);
|
|
||||||
m_last_area_id = 0;
|
|
||||||
m_last_zone_id = 0;
|
|
||||||
m_last_outdoors_position.Relocate(-5000.0f, -5000.0f, -5000.0f, 0.0f);
|
|
||||||
m_last_outdoors_status = true; // true by default
|
|
||||||
|
|
||||||
m_applyResilience = false;
|
m_applyResilience = false;
|
||||||
_instantCast = false;
|
_instantCast = false;
|
||||||
@@ -528,8 +516,13 @@ void Unit::UpdateSplineMovement(uint32 t_diff)
|
|||||||
bool arrived = movespline->Finalized();
|
bool arrived = movespline->Finalized();
|
||||||
|
|
||||||
if (arrived)
|
if (arrived)
|
||||||
|
{
|
||||||
DisableSpline();
|
DisableSpline();
|
||||||
|
|
||||||
|
if (movespline->HasAnimation() && GetTypeId() == TYPEID_UNIT && IsAlive())
|
||||||
|
SetByteValue(UNIT_FIELD_BYTES_1, UNIT_BYTES_1_OFFSET_ANIM_TIER, movespline->GetAnimationType());
|
||||||
|
}
|
||||||
|
|
||||||
// pussywizard: update always! not every 400ms, because movement generators need the actual position
|
// pussywizard: update always! not every 400ms, because movement generators need the actual position
|
||||||
//m_movesplineTimer.Update(t_diff);
|
//m_movesplineTimer.Update(t_diff);
|
||||||
//if (m_movesplineTimer.Passed() || arrived)
|
//if (m_movesplineTimer.Passed() || arrived)
|
||||||
@@ -3636,230 +3629,48 @@ bool Unit::isInAccessiblePlaceFor(Creature const* c) const
|
|||||||
if (IsInWater())
|
if (IsInWater())
|
||||||
return IsUnderWater() ? c->CanEnterWater() : (c->CanEnterWater() || c->CanFly());
|
return IsUnderWater() ? c->CanEnterWater() : (c->CanEnterWater() || c->CanFly());
|
||||||
else
|
else
|
||||||
return c->CanWalk() || c->CanFly() || (c->CanSwim() && IsInWater(true));
|
return c->CanWalk() || c->CanFly() || (c->CanSwim() && IsInWater());
|
||||||
}
|
}
|
||||||
|
|
||||||
void Unit::UpdateEnvironmentIfNeeded(const uint8 option)
|
void Unit::ProcessPositionDataChanged(PositionFullTerrainStatus const& data)
|
||||||
{
|
{
|
||||||
if (m_is_updating_environment)
|
WorldObject::ProcessPositionDataChanged(data);
|
||||||
|
ProcessTerrainStatusUpdate();
|
||||||
|
}
|
||||||
|
|
||||||
|
void Unit::ProcessTerrainStatusUpdate()
|
||||||
|
{
|
||||||
|
if (GetTypeId() == TYPEID_UNIT)
|
||||||
|
ToCreature()->UpdateMovementFlags();
|
||||||
|
|
||||||
|
if (IsFlying() || (!IsControlledByPlayer()))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
if (GetTypeId() != TYPEID_UNIT || !IsAlive() || (!IsInWorld() && option != 3) || !FindMap() || IsDuringRemoveFromWorld() || !IsPositionValid())
|
LiquidData const& liquidData = GetLiquidData();
|
||||||
return;
|
|
||||||
|
|
||||||
if (option <= 2 && GetMotionMaster()->GetCleanFlags() != MMCF_NONE)
|
// remove appropriate auras if we are swimming/not swimming respectively
|
||||||
|
if (liquidData.Status & MAP_LIQUID_STATUS_SWIMMING)
|
||||||
|
RemoveAurasWithInterruptFlags(AURA_INTERRUPT_FLAG_NOT_ABOVEWATER);
|
||||||
|
else
|
||||||
|
RemoveAurasWithInterruptFlags(AURA_INTERRUPT_FLAG_NOT_UNDERWATER);
|
||||||
|
|
||||||
|
// liquid aura handling
|
||||||
|
LiquidTypeEntry const* curLiquid = nullptr;
|
||||||
|
if ((liquidData.Status & MAP_LIQUID_STATUS_SWIMMING))
|
||||||
|
curLiquid = sLiquidTypeStore.LookupEntry(liquidData.Entry);
|
||||||
|
|
||||||
|
if (curLiquid != _lastLiquid)
|
||||||
{
|
{
|
||||||
if (option == 2)
|
if (_lastLiquid && _lastLiquid->SpellId)
|
||||||
m_last_environment_position.Relocate(-5000.0f, -5000.0f, -5000.0f, 0.0f);
|
RemoveAurasDueToSpell(_lastLiquid->SpellId);
|
||||||
return;
|
|
||||||
|
// Set _lastLiquid before casting liquid spell to avoid infinite loops
|
||||||
|
_lastLiquid = curLiquid;
|
||||||
|
|
||||||
|
Player* player = GetCharmerOrOwnerPlayerOrPlayerItself();
|
||||||
|
if (curLiquid && curLiquid->SpellId && (!player || !player->IsGameMaster()))
|
||||||
|
CastSpell(this, curLiquid->SpellId, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
// run environment checks everytime the unit moves
|
|
||||||
// more than it's average radius
|
|
||||||
// TODO: find better solution here
|
|
||||||
float radiusWidth = GetCollisionRadius();
|
|
||||||
float radiusHeight = GetCollisionHeight() / 2;
|
|
||||||
float radiusAvg = (radiusWidth + radiusHeight) / 2;
|
|
||||||
if (option <= 1 && GetExactDistSq(&m_last_environment_position) < radiusAvg * radiusAvg)
|
|
||||||
return;
|
|
||||||
|
|
||||||
m_last_environment_position.Relocate(GetPositionX(), GetPositionY(), GetPositionZ());
|
|
||||||
m_staticFloorZ = GetMap()->GetHeight(GetPhaseMask(), GetPositionX(), GetPositionY(), GetPositionZ());
|
|
||||||
|
|
||||||
m_is_updating_environment = true;
|
|
||||||
|
|
||||||
bool changed = false;
|
|
||||||
Map* baseMap = const_cast<Map*>(GetBaseMap());
|
|
||||||
Creature* c = this->ToCreature();
|
|
||||||
if (!c || !baseMap)
|
|
||||||
{
|
|
||||||
m_is_updating_environment = false;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool canChangeFlying = option == 3 || ((c->GetScriptId() == 0 || GetInstanceId() == 0) && GetMotionMaster()->GetMotionSlotType(MOTION_SLOT_CONTROLLED) == NULL_MOTION_TYPE);
|
|
||||||
bool canFallGround = option == 0 && canChangeFlying && GetInstanceId() == 0 && !IsInCombat() && !GetVehicle() && !GetTransport() && !HasUnitMovementFlag(MOVEMENTFLAG_ONTRANSPORT) && !c->IsTrigger() && !c->HasFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE) && GetMotionMaster()->GetCurrentMovementGeneratorType() <= RANDOM_MOTION_TYPE && !HasUnitState(UNIT_STATE_EVADE) && !IsControlledByPlayer();
|
|
||||||
float x = GetPositionX(), y = GetPositionY(), z = GetPositionZ();
|
|
||||||
bool isInAir = true;
|
|
||||||
float ground_z = z;
|
|
||||||
LiquidData liquidData;
|
|
||||||
liquidData.level = INVALID_HEIGHT;
|
|
||||||
ZLiquidStatus liquidStatus = baseMap->getLiquidStatus(x, y, z, MAP_ALL_LIQUIDS, &liquidData);
|
|
||||||
// IsInWater
|
|
||||||
bool enoughWater = baseMap->HasEnoughWater(this, liquidData);
|
|
||||||
m_last_isinwater_status = (liquidStatus & (LIQUID_MAP_IN_WATER | LIQUID_MAP_UNDER_WATER)) && enoughWater;
|
|
||||||
m_last_islittleabovewater_status = (liquidData.level > INVALID_HEIGHT && liquidData.level > liquidData.depth_level && liquidData.level <= z + 3.0f && liquidData.level > z - 1.0f);
|
|
||||||
|
|
||||||
// IsUnderWater
|
|
||||||
m_last_isunderwater_status = (liquidStatus & LIQUID_MAP_UNDER_WATER) && enoughWater;
|
|
||||||
|
|
||||||
// UpdateUnderwaterState
|
|
||||||
if (IsPet() || IsVehicle())
|
|
||||||
{
|
|
||||||
if (option == 1) // Unit::IsInWater, Unit::IsUnderwater, adding/removing auras can cause crashes (eg threat change while iterating threat table), so skip
|
|
||||||
m_last_environment_position.Relocate(-5000.0f, -5000.0f, -5000.0f, 0.0f);
|
|
||||||
else
|
|
||||||
{
|
|
||||||
if (!liquidStatus)
|
|
||||||
{
|
|
||||||
if (_lastLiquid && _lastLiquid->SpellId)
|
|
||||||
RemoveAurasDueToSpell(_lastLiquid->SpellId);
|
|
||||||
|
|
||||||
RemoveAurasWithInterruptFlags(AURA_INTERRUPT_FLAG_NOT_UNDERWATER);
|
|
||||||
_lastLiquid = nullptr;
|
|
||||||
}
|
|
||||||
else if (uint32 liqEntry = liquidData.entry)
|
|
||||||
{
|
|
||||||
LiquidTypeEntry const* liquid = sLiquidTypeStore.LookupEntry(liqEntry);
|
|
||||||
if (_lastLiquid && _lastLiquid->SpellId && _lastLiquid->Id != liqEntry)
|
|
||||||
RemoveAurasDueToSpell(_lastLiquid->SpellId);
|
|
||||||
|
|
||||||
if (liquid && liquid->SpellId)
|
|
||||||
{
|
|
||||||
if (liquidStatus & (LIQUID_MAP_UNDER_WATER | LIQUID_MAP_IN_WATER))
|
|
||||||
{
|
|
||||||
if (!HasAura(liquid->SpellId))
|
|
||||||
CastSpell(this, liquid->SpellId, true);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
RemoveAurasDueToSpell(liquid->SpellId);
|
|
||||||
}
|
|
||||||
|
|
||||||
RemoveAurasWithInterruptFlags(AURA_INTERRUPT_FLAG_NOT_ABOVEWATER);
|
|
||||||
_lastLiquid = liquid;
|
|
||||||
}
|
|
||||||
else if (_lastLiquid && _lastLiquid->SpellId)
|
|
||||||
{
|
|
||||||
RemoveAurasDueToSpell(_lastLiquid->SpellId);
|
|
||||||
RemoveAurasWithInterruptFlags(AURA_INTERRUPT_FLAG_NOT_UNDERWATER);
|
|
||||||
_lastLiquid = nullptr;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
bool canUpdateEnvironment = !HasUnitState(UNIT_STATE_NO_ENVIRONMENT_UPD);
|
|
||||||
|
|
||||||
bool flyingBarelyInWater = false;
|
|
||||||
// Refresh being in water
|
|
||||||
if (m_last_isinwater_status)
|
|
||||||
{
|
|
||||||
if (!c->CanFly() || enoughWater)
|
|
||||||
{
|
|
||||||
if (canUpdateEnvironment && c->CanSwim() && (!HasUnitMovementFlag(MOVEMENTFLAG_SWIMMING) || !HasUnitMovementFlag(MOVEMENTFLAG_DISABLE_GRAVITY)))
|
|
||||||
{
|
|
||||||
SetSwim(true);
|
|
||||||
changed = true;
|
|
||||||
}
|
|
||||||
isInAir = false;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
m_last_isinwater_status = false;
|
|
||||||
flyingBarelyInWater = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!m_last_isinwater_status)
|
|
||||||
{
|
|
||||||
if (canUpdateEnvironment && c->CanWalk() && HasUnitMovementFlag(MOVEMENTFLAG_SWIMMING))
|
|
||||||
{
|
|
||||||
SetSwim(false);
|
|
||||||
changed = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// if not in water, check whether in air or not
|
|
||||||
if (isInAir)
|
|
||||||
{
|
|
||||||
if (GetMap()->GetGrid(x, y))
|
|
||||||
{
|
|
||||||
float temp = GetFloorZ();
|
|
||||||
if (temp > INVALID_HEIGHT)
|
|
||||||
{
|
|
||||||
ground_z = (c->CanSwim() && liquidData.level > INVALID_HEIGHT) ? liquidData.level : temp;
|
|
||||||
bool canHover = c->CanHover();
|
|
||||||
isInAir = flyingBarelyInWater || (G3D::fuzzyGt(GetPositionZ(), ground_z + (canHover ? GetFloatValue(UNIT_FIELD_HOVERHEIGHT) : 0.0f) + GROUND_HEIGHT_TOLERANCE) || G3D::fuzzyLt(GetPositionZ(), ground_z - GROUND_HEIGHT_TOLERANCE)); // Can be underground too, prevent the falling
|
|
||||||
}
|
|
||||||
else
|
|
||||||
isInAir = true;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
m_is_updating_environment = false;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (canUpdateEnvironment && canChangeFlying)
|
|
||||||
{
|
|
||||||
// xinef: summoned vehicles are treated as always in air, fixes flying on such units
|
|
||||||
if (IsVehicle() && !c->GetSpawnId())
|
|
||||||
isInAir = true;
|
|
||||||
|
|
||||||
// xinef: triggers with inhabit type air are treated as always in air
|
|
||||||
if (c->IsTrigger() && c->CanFly())
|
|
||||||
isInAir = true;
|
|
||||||
|
|
||||||
if (c->GetOwnerGUID().IsPlayer() && c->CanFly() && IsVehicle() && !c->GetSpawnId()) // mainly for oculus drakes
|
|
||||||
{
|
|
||||||
if (!HasUnitMovementFlag(MOVEMENTFLAG_CAN_FLY) || !HasUnitMovementFlag(MOVEMENTFLAG_DISABLE_GRAVITY))
|
|
||||||
{
|
|
||||||
SetCanFly(true);
|
|
||||||
SetDisableGravity(true);
|
|
||||||
changed = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else if (c->CanFly() && isInAir && !c->IsFalling())
|
|
||||||
{
|
|
||||||
if (!HasUnitMovementFlag(MOVEMENTFLAG_CAN_FLY) || !HasUnitMovementFlag(MOVEMENTFLAG_DISABLE_GRAVITY))
|
|
||||||
{
|
|
||||||
SetCanFly(true);
|
|
||||||
SetDisableGravity(true);
|
|
||||||
changed = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (IsHovering() && !HasAuraType(SPELL_AURA_HOVER))
|
|
||||||
{
|
|
||||||
SetHover(false);
|
|
||||||
changed = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
if (HasUnitMovementFlag(MOVEMENTFLAG_CAN_FLY) || HasUnitMovementFlag(MOVEMENTFLAG_FLYING))
|
|
||||||
{
|
|
||||||
SetCanFly(false);
|
|
||||||
RemoveUnitMovementFlag(MOVEMENTFLAG_FLYING);
|
|
||||||
changed = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!IsHovering() && IsAlive() && (c->CanHover() || HasAuraType(SPELL_AURA_HOVER)))
|
|
||||||
{
|
|
||||||
SetHover(true);
|
|
||||||
changed = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (HasUnitMovementFlag(MOVEMENTFLAG_DISABLE_GRAVITY) && !HasUnitMovementFlag(MOVEMENTFLAG_SWIMMING))
|
|
||||||
{
|
|
||||||
SetDisableGravity(false);
|
|
||||||
changed = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (isInAir && !c->CanFly() && option >= 2)
|
|
||||||
m_last_environment_position.Relocate(-5000.0f, -5000.0f, -5000.0f, 0.0f);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!isInAir && HasUnitMovementFlag(MOVEMENTFLAG_FALLING))
|
|
||||||
RemoveUnitMovementFlag(MOVEMENTFLAG_FALLING);
|
|
||||||
|
|
||||||
if (changed)
|
|
||||||
propagateSpeedChange();
|
|
||||||
|
|
||||||
if (canUpdateEnvironment && canFallGround && !c->CanFly() && !c->IsFalling() && !m_last_isinwater_status && (c->GetUnitMovementFlags() & (MOVEMENTFLAG_CAN_FLY | MOVEMENTFLAG_DISABLE_GRAVITY | MOVEMENTFLAG_HOVER | MOVEMENTFLAG_SWIMMING)) == 0 && z - ground_z > 5.0f && z - ground_z < 80.0f)
|
|
||||||
GetMotionMaster()->MoveFall();
|
|
||||||
|
|
||||||
m_is_updating_environment = false;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
SafeUnitPointer::~SafeUnitPointer()
|
SafeUnitPointer::~SafeUnitPointer()
|
||||||
@@ -3906,20 +3717,14 @@ void Unit::HandleSafeUnitPointersOnDelete(Unit* thisUnit)
|
|||||||
thisUnit->SafeUnitPointerSet.clear();
|
thisUnit->SafeUnitPointerSet.clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Unit::IsInWater(bool allowAbove) const
|
bool Unit::IsInWater() const
|
||||||
{
|
{
|
||||||
const_cast<Unit*>(this)->UpdateEnvironmentIfNeeded(1);
|
return (GetLiquidData().Status & MAP_LIQUID_STATUS_SWIMMING) != 0;
|
||||||
return m_last_isinwater_status || (allowAbove && m_last_islittleabovewater_status);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Unit::IsUnderWater() const
|
bool Unit::IsUnderWater() const
|
||||||
{
|
{
|
||||||
const_cast<Unit*>(this)->UpdateEnvironmentIfNeeded(1);
|
return GetLiquidData().Status == LIQUID_MAP_UNDER_WATER;
|
||||||
return m_last_isunderwater_status;
|
|
||||||
}
|
|
||||||
|
|
||||||
void Unit::UpdateUnderwaterState(Map* /*m*/, float /*x*/, float /*y*/, float /*z*/)
|
|
||||||
{
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void Unit::DeMorph()
|
void Unit::DeMorph()
|
||||||
@@ -12996,8 +12801,6 @@ void Unit::SetInCombatState(bool PvP, Unit* enemy, uint32 duration)
|
|||||||
|
|
||||||
if (Creature* creature = ToCreature())
|
if (Creature* creature = ToCreature())
|
||||||
{
|
{
|
||||||
creature->UpdateEnvironmentIfNeeded(2);
|
|
||||||
|
|
||||||
// Set home position at place of engaging combat for escorted creatures
|
// Set home position at place of engaging combat for escorted creatures
|
||||||
if ((IsAIEnabled && creature->AI()->IsEscorted()) ||
|
if ((IsAIEnabled && creature->AI()->IsEscorted()) ||
|
||||||
GetMotionMaster()->GetCurrentMovementGeneratorType() == WAYPOINT_MOTION_TYPE ||
|
GetMotionMaster()->GetCurrentMovementGeneratorType() == WAYPOINT_MOTION_TYPE ||
|
||||||
@@ -19584,62 +19387,6 @@ bool ConflagrateAuraStateDelayEvent::Execute(uint64 /*e_time*/, uint32 /*p_time
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
uint32 Unit::GetZoneId(bool forceRecalc) const
|
|
||||||
{
|
|
||||||
// xinef: optimization, zone calculated every few yards
|
|
||||||
if (!forceRecalc && GetExactDistSq(&m_last_zone_position) < 4.0f * 4.0f)
|
|
||||||
return m_last_zone_id;
|
|
||||||
else
|
|
||||||
{
|
|
||||||
const_cast<Position*>(&m_last_zone_position)->Relocate(GetPositionX(), GetPositionY(), GetPositionZ());
|
|
||||||
*(const_cast<uint32*>(&m_last_zone_id)) = WorldObject::GetZoneId();
|
|
||||||
return m_last_zone_id;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
uint32 Unit::GetAreaId(bool forceRecalc) const
|
|
||||||
{
|
|
||||||
// xinef: optimization, area calculated every few yards
|
|
||||||
if (!forceRecalc && GetExactDistSq(&m_last_area_position) < 4.0f * 4.0f)
|
|
||||||
return m_last_area_id;
|
|
||||||
else
|
|
||||||
{
|
|
||||||
const_cast<Position*>(&m_last_area_position)->Relocate(GetPositionX(), GetPositionY(), GetPositionZ());
|
|
||||||
*(const_cast<uint32*>(&m_last_area_id)) = WorldObject::GetAreaId();
|
|
||||||
return m_last_area_id;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void Unit::GetZoneAndAreaId(uint32& zoneid, uint32& areaid, bool forceRecalc) const
|
|
||||||
{
|
|
||||||
// xinef: optimization, zone and area calculated every few yards
|
|
||||||
if (!forceRecalc && GetExactDistSq(&m_last_area_position) < 4.0f * 4.0f && GetExactDistSq(&m_last_zone_position) < 4.0f * 4.0f)
|
|
||||||
{
|
|
||||||
zoneid = m_last_zone_id;
|
|
||||||
areaid = m_last_area_id;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
const_cast<Position*>(&m_last_zone_position)->Relocate(GetPositionX(), GetPositionY(), GetPositionZ());
|
|
||||||
const_cast<Position*>(&m_last_area_position)->Relocate(GetPositionX(), GetPositionY(), GetPositionZ());
|
|
||||||
WorldObject::GetZoneAndAreaId(zoneid, areaid);
|
|
||||||
*(const_cast<uint32*>(&m_last_zone_id)) = zoneid;
|
|
||||||
*(const_cast<uint32*>(&m_last_area_id)) = areaid;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool Unit::IsOutdoors() const
|
|
||||||
{
|
|
||||||
// xinef: optimization, outdoor status calculated every few yards
|
|
||||||
if (GetExactDistSq(&m_last_outdoors_position) < 4.0f * 4.0f)
|
|
||||||
return m_last_outdoors_status;
|
|
||||||
else
|
|
||||||
{
|
|
||||||
const_cast<Position*>(&m_last_outdoors_position)->Relocate(GetPositionX(), GetPositionY(), GetPositionZ());
|
|
||||||
*(const_cast<bool*>(&m_last_outdoors_status)) = GetMap()->IsOutdoors(GetPositionX(), GetPositionY(), GetPositionZ());
|
|
||||||
return m_last_outdoors_status;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void Unit::ExecuteDelayedUnitRelocationEvent()
|
void Unit::ExecuteDelayedUnitRelocationEvent()
|
||||||
{
|
{
|
||||||
this->RemoveFromNotify(NOTIFY_VISIBILITY_CHANGED);
|
this->RemoveFromNotify(NOTIFY_VISIBILITY_CHANGED);
|
||||||
|
|||||||
@@ -1772,10 +1772,8 @@ public:
|
|||||||
bool IsValidAssistTarget(Unit const* target) const;
|
bool IsValidAssistTarget(Unit const* target) const;
|
||||||
bool _IsValidAssistTarget(Unit const* target, SpellInfo const* bySpell) const;
|
bool _IsValidAssistTarget(Unit const* target, SpellInfo const* bySpell) const;
|
||||||
|
|
||||||
void UpdateEnvironmentIfNeeded(const uint8 option);
|
[[nodiscard]] virtual bool IsInWater() const;
|
||||||
[[nodiscard]] virtual bool IsInWater(bool allowAbove = false) const;
|
|
||||||
[[nodiscard]] virtual bool IsUnderWater() const;
|
[[nodiscard]] virtual bool IsUnderWater() const;
|
||||||
virtual void UpdateUnderwaterState(Map* m, float x, float y, float z);
|
|
||||||
bool isInAccessiblePlaceFor(Creature const* c) const;
|
bool isInAccessiblePlaceFor(Creature const* c) const;
|
||||||
|
|
||||||
void SendHealSpellLog(Unit* victim, uint32 SpellID, uint32 Damage, uint32 OverHeal, uint32 Absorb, bool critical = false);
|
void SendHealSpellLog(Unit* victim, uint32 SpellID, uint32 Damage, uint32 OverHeal, uint32 Absorb, bool critical = false);
|
||||||
@@ -2454,25 +2452,6 @@ public:
|
|||||||
bool bRequestForcedVisibilityUpdate;
|
bool bRequestForcedVisibilityUpdate;
|
||||||
void ExecuteDelayedUnitRelocationEvent();
|
void ExecuteDelayedUnitRelocationEvent();
|
||||||
void ExecuteDelayedUnitAINotifyEvent();
|
void ExecuteDelayedUnitAINotifyEvent();
|
||||||
// IsInWater, UpdateUnderwaterState, etc. optimizations
|
|
||||||
Position m_last_underwaterstate_position;
|
|
||||||
Position m_last_environment_position;
|
|
||||||
bool m_last_isinwater_status;
|
|
||||||
bool m_last_islittleabovewater_status;
|
|
||||||
bool m_last_isunderwater_status;
|
|
||||||
bool m_is_updating_environment;
|
|
||||||
// GetZone / GetArea optimization
|
|
||||||
Position m_last_area_position;
|
|
||||||
Position m_last_zone_position;
|
|
||||||
uint32 m_last_area_id;
|
|
||||||
uint32 m_last_zone_id;
|
|
||||||
Position m_last_outdoors_position;
|
|
||||||
bool m_last_outdoors_status;
|
|
||||||
[[nodiscard]] bool IsOutdoors() const;
|
|
||||||
|
|
||||||
[[nodiscard]] uint32 GetZoneId(bool forceRecalc = false) const override;
|
|
||||||
[[nodiscard]] uint32 GetAreaId(bool forceRecalc = false) const override;
|
|
||||||
void GetZoneAndAreaId(uint32& zoneid, uint32& areaid, bool forceRecalc = false) const override;
|
|
||||||
|
|
||||||
// cooldowns
|
// cooldowns
|
||||||
[[nodiscard]] virtual bool HasSpellCooldown(uint32 /*spell_id*/) const { return false; }
|
[[nodiscard]] virtual bool HasSpellCooldown(uint32 /*spell_id*/) const { return false; }
|
||||||
@@ -2503,6 +2482,9 @@ public:
|
|||||||
[[nodiscard]] float GetCollisionWidth() const override;
|
[[nodiscard]] float GetCollisionWidth() const override;
|
||||||
[[nodiscard]] float GetCollisionRadius() const override;
|
[[nodiscard]] float GetCollisionRadius() const override;
|
||||||
|
|
||||||
|
void ProcessPositionDataChanged(PositionFullTerrainStatus const& data) override;
|
||||||
|
virtual void ProcessTerrainStatusUpdate();
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
explicit Unit (bool isWorldObject);
|
explicit Unit (bool isWorldObject);
|
||||||
|
|
||||||
|
|||||||
@@ -1955,8 +1955,8 @@ void ObjectMgr::LoadCreatures()
|
|||||||
|
|
||||||
if (sWorld->getBoolConfig(CONFIG_CALCULATE_CREATURE_ZONE_AREA_DATA))
|
if (sWorld->getBoolConfig(CONFIG_CALCULATE_CREATURE_ZONE_AREA_DATA))
|
||||||
{
|
{
|
||||||
uint32 zoneId = sMapMgr->GetZoneId(data.mapid, data.posX, data.posY, data.posZ);
|
uint32 zoneId = sMapMgr->GetZoneId(data.phaseMask, data.mapid, data.posX, data.posY, data.posZ);
|
||||||
uint32 areaId = sMapMgr->GetAreaId(data.mapid, data.posX, data.posY, data.posZ);
|
uint32 areaId = sMapMgr->GetAreaId(data.phaseMask, data.mapid, data.posX, data.posY, data.posZ);
|
||||||
|
|
||||||
WorldDatabasePreparedStatement* stmt = WorldDatabase.GetPreparedStatement(WORLD_UPD_CREATURE_ZONE_AREA_DATA);
|
WorldDatabasePreparedStatement* stmt = WorldDatabase.GetPreparedStatement(WORLD_UPD_CREATURE_ZONE_AREA_DATA);
|
||||||
|
|
||||||
@@ -2256,8 +2256,8 @@ void ObjectMgr::LoadGameobjects()
|
|||||||
|
|
||||||
if (sWorld->getBoolConfig(CONFIG_CALCULATE_GAMEOBJECT_ZONE_AREA_DATA))
|
if (sWorld->getBoolConfig(CONFIG_CALCULATE_GAMEOBJECT_ZONE_AREA_DATA))
|
||||||
{
|
{
|
||||||
uint32 zoneId = sMapMgr->GetZoneId(data.mapid, data.posX, data.posY, data.posZ);
|
uint32 zoneId = sMapMgr->GetZoneId(data.phaseMask, data.mapid, data.posX, data.posY, data.posZ);
|
||||||
uint32 areaId = sMapMgr->GetAreaId(data.mapid, data.posX, data.posY, data.posZ);
|
uint32 areaId = sMapMgr->GetAreaId(data.phaseMask, data.mapid, data.posX, data.posY, data.posZ);
|
||||||
|
|
||||||
WorldDatabasePreparedStatement* stmt = WorldDatabase.GetPreparedStatement(WORLD_UPD_GAMEOBJECT_ZONE_AREA_DATA);
|
WorldDatabasePreparedStatement* stmt = WorldDatabase.GetPreparedStatement(WORLD_UPD_GAMEOBJECT_ZONE_AREA_DATA);
|
||||||
|
|
||||||
|
|||||||
@@ -1135,7 +1135,7 @@ void WorldSession::HandlePlayerLoginToCharInWorld(Player* pCurrChar)
|
|||||||
pCurrChar->CleanupChannels();
|
pCurrChar->CleanupChannels();
|
||||||
pCurrChar->SendInitialPacketsAfterAddToMap();
|
pCurrChar->SendInitialPacketsAfterAddToMap();
|
||||||
uint32 currZone, currArea;
|
uint32 currZone, currArea;
|
||||||
pCurrChar->GetZoneAndAreaId(currZone, currArea, false);
|
pCurrChar->GetZoneAndAreaId(currZone, currArea);
|
||||||
pCurrChar->SendInitWorldStates(currZone, currArea);
|
pCurrChar->SendInitWorldStates(currZone, currArea);
|
||||||
pCurrChar->SetInGameTime(World::GetGameTimeMS());
|
pCurrChar->SetInGameTime(World::GetGameTimeMS());
|
||||||
|
|
||||||
|
|||||||
@@ -511,7 +511,7 @@ void WorldSession::HandleZoneUpdateOpcode(WorldPacket& recv_data)
|
|||||||
|
|
||||||
// use server size data
|
// use server size data
|
||||||
uint32 newzone, newarea;
|
uint32 newzone, newarea;
|
||||||
GetPlayer()->GetZoneAndAreaId(newzone, newarea, true);
|
GetPlayer()->GetZoneAndAreaId(newzone, newarea);
|
||||||
GetPlayer()->UpdateZone(newzone, newarea);
|
GetPlayer()->UpdateZone(newzone, newarea);
|
||||||
//GetPlayer()->SendInitWorldStates(true, newZone);
|
//GetPlayer()->SendInitWorldStates(true, newZone);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -90,6 +90,8 @@ void WorldSession::HandleMoveWorldportAck()
|
|||||||
GetPlayer()->ResetMap();
|
GetPlayer()->ResetMap();
|
||||||
GetPlayer()->SetMap(newMap);
|
GetPlayer()->SetMap(newMap);
|
||||||
|
|
||||||
|
GetPlayer()->UpdatePositionData();
|
||||||
|
|
||||||
GetPlayer()->SendInitialPacketsBeforeAddToMap();
|
GetPlayer()->SendInitialPacketsBeforeAddToMap();
|
||||||
if (!GetPlayer()->GetMap()->AddPlayerToMap(GetPlayer()))
|
if (!GetPlayer()->GetMap()->AddPlayerToMap(GetPlayer()))
|
||||||
{
|
{
|
||||||
@@ -216,7 +218,7 @@ void WorldSession::HandleMoveWorldportAck()
|
|||||||
|
|
||||||
// update zone immediately, otherwise leave channel will cause crash in mtmap
|
// update zone immediately, otherwise leave channel will cause crash in mtmap
|
||||||
uint32 newzone, newarea;
|
uint32 newzone, newarea;
|
||||||
GetPlayer()->GetZoneAndAreaId(newzone, newarea, true);
|
GetPlayer()->GetZoneAndAreaId(newzone, newarea);
|
||||||
GetPlayer()->UpdateZone(newzone, newarea);
|
GetPlayer()->UpdateZone(newzone, newarea);
|
||||||
|
|
||||||
// honorless target
|
// honorless target
|
||||||
@@ -273,7 +275,7 @@ void WorldSession::HandleMoveTeleportAck(WorldPacket& recvData)
|
|||||||
if (oldPos.GetExactDist2d(plMover) > 100.0f)
|
if (oldPos.GetExactDist2d(plMover) > 100.0f)
|
||||||
{
|
{
|
||||||
uint32 newzone, newarea;
|
uint32 newzone, newarea;
|
||||||
plMover->GetZoneAndAreaId(newzone, newarea, true);
|
plMover->GetZoneAndAreaId(newzone, newarea);
|
||||||
plMover->UpdateZone(newzone, newarea);
|
plMover->UpdateZone(newzone, newarea);
|
||||||
|
|
||||||
// new zone
|
// new zone
|
||||||
@@ -482,7 +484,8 @@ void WorldSession::HandleMovementOpcodes(WorldPacket& recvData)
|
|||||||
if (plrMover && ((movementInfo.flags & MOVEMENTFLAG_SWIMMING) != 0) != plrMover->IsInWater())
|
if (plrMover && ((movementInfo.flags & MOVEMENTFLAG_SWIMMING) != 0) != plrMover->IsInWater())
|
||||||
{
|
{
|
||||||
// now client not include swimming flag in case jumping under water
|
// now client not include swimming flag in case jumping under water
|
||||||
plrMover->SetInWater(!plrMover->IsInWater() || plrMover->GetBaseMap()->IsUnderWater(movementInfo.pos.GetPositionX(), movementInfo.pos.GetPositionY(), movementInfo.pos.GetPositionZ()));
|
plrMover->SetInWater(!plrMover->IsInWater() || plrMover->GetMap()->IsUnderWater(plrMover->GetPhaseMask(), movementInfo.pos.GetPositionX(),
|
||||||
|
movementInfo.pos.GetPositionY(), movementInfo.pos.GetPositionZ(), plrMover->GetCollisionHeight()));
|
||||||
}
|
}
|
||||||
|
|
||||||
bool jumpopcode = false;
|
bool jumpopcode = false;
|
||||||
|
|||||||
@@ -175,6 +175,7 @@ uint8 WorldSession::HandleLoadPetFromDBFirstCallback(PreparedQueryResult result,
|
|||||||
|
|
||||||
if (pet->IsCritter())
|
if (pet->IsCritter())
|
||||||
{
|
{
|
||||||
|
pet->UpdatePositionData();
|
||||||
map->AddToMap(pet->ToCreature(), true);
|
map->AddToMap(pet->ToCreature(), true);
|
||||||
pet->SetLoading(false); // xinef, mine
|
pet->SetLoading(false); // xinef, mine
|
||||||
return PET_LOAD_OK;
|
return PET_LOAD_OK;
|
||||||
@@ -186,6 +187,7 @@ uint8 WorldSession::HandleLoadPetFromDBFirstCallback(PreparedQueryResult result,
|
|||||||
pet->GetCharmInfo()->SetPetNumber(pet_number, false);
|
pet->GetCharmInfo()->SetPetNumber(pet_number, false);
|
||||||
|
|
||||||
pet->SetDisplayId(fields[3].GetUInt32());
|
pet->SetDisplayId(fields[3].GetUInt32());
|
||||||
|
pet->UpdatePositionData();
|
||||||
pet->SetNativeDisplayId(fields[3].GetUInt32());
|
pet->SetNativeDisplayId(fields[3].GetUInt32());
|
||||||
pet->SetUInt32Value(UNIT_NPC_FLAGS, UNIT_NPC_FLAG_NONE);
|
pet->SetUInt32Value(UNIT_NPC_FLAGS, UNIT_NPC_FLAG_NONE);
|
||||||
pet->SetName(fields[8].GetString());
|
pet->SetName(fields[8].GetString());
|
||||||
|
|||||||
+409
-259
@@ -43,6 +43,9 @@ u_map_magic MapAreaMagic = { {'A', 'R', 'E', 'A'} };
|
|||||||
u_map_magic MapHeightMagic = { {'M', 'H', 'G', 'T'} };
|
u_map_magic MapHeightMagic = { {'M', 'H', 'G', 'T'} };
|
||||||
u_map_magic MapLiquidMagic = { {'M', 'L', 'I', 'Q'} };
|
u_map_magic MapLiquidMagic = { {'M', 'L', 'I', 'Q'} };
|
||||||
|
|
||||||
|
static uint16 const holetab_h[4] = { 0x1111, 0x2222, 0x4444, 0x8888 };
|
||||||
|
static uint16 const holetab_v[4] = { 0x000F, 0x00F0, 0x0F00, 0xF000 };
|
||||||
|
|
||||||
Map::~Map()
|
Map::~Map()
|
||||||
{
|
{
|
||||||
// UnloadAll must be called before deleting the map
|
// UnloadAll must be called before deleting the map
|
||||||
@@ -980,7 +983,7 @@ void Map::PlayerRelocation(Player* player, float x, float y, float z, float o)
|
|||||||
player->Relocate(x, y, z, o);
|
player->Relocate(x, y, z, o);
|
||||||
if (player->IsVehicle())
|
if (player->IsVehicle())
|
||||||
player->GetVehicleKit()->RelocatePassengers();
|
player->GetVehicleKit()->RelocatePassengers();
|
||||||
|
player->UpdatePositionData();
|
||||||
player->UpdateObjectVisibility(false);
|
player->UpdateObjectVisibility(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1002,7 +1005,7 @@ void Map::CreatureRelocation(Creature* creature, float x, float y, float z, floa
|
|||||||
creature->Relocate(x, y, z, o);
|
creature->Relocate(x, y, z, o);
|
||||||
if (creature->IsVehicle())
|
if (creature->IsVehicle())
|
||||||
creature->GetVehicleKit()->RelocatePassengers();
|
creature->GetVehicleKit()->RelocatePassengers();
|
||||||
|
creature->UpdatePositionData();
|
||||||
creature->UpdateObjectVisibility(false);
|
creature->UpdateObjectVisibility(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1023,7 +1026,7 @@ void Map::GameObjectRelocation(GameObject* go, float x, float y, float z, float
|
|||||||
|
|
||||||
go->Relocate(x, y, z, o);
|
go->Relocate(x, y, z, o);
|
||||||
go->UpdateModelPosition();
|
go->UpdateModelPosition();
|
||||||
|
go->SetPositionDataUpdate();
|
||||||
go->UpdateObjectVisibility(false);
|
go->UpdateObjectVisibility(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1043,7 +1046,7 @@ void Map::DynamicObjectRelocation(DynamicObject* dynObj, float x, float y, float
|
|||||||
RemoveDynamicObjectFromMoveList(dynObj);
|
RemoveDynamicObjectFromMoveList(dynObj);
|
||||||
|
|
||||||
dynObj->Relocate(x, y, z, o);
|
dynObj->Relocate(x, y, z, o);
|
||||||
|
dynObj->SetPositionDataUpdate();
|
||||||
dynObj->UpdateObjectVisibility(false);
|
dynObj->UpdateObjectVisibility(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1307,6 +1310,7 @@ GridMap::GridMap()
|
|||||||
_liquidEntry = nullptr;
|
_liquidEntry = nullptr;
|
||||||
_liquidFlags = nullptr;
|
_liquidFlags = nullptr;
|
||||||
_liquidMap = nullptr;
|
_liquidMap = nullptr;
|
||||||
|
_holes = nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
GridMap::~GridMap()
|
GridMap::~GridMap()
|
||||||
@@ -1354,6 +1358,13 @@ bool GridMap::loadData(char* filename)
|
|||||||
fclose(in);
|
fclose(in);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
// loadup holes data (if any. check header.holesOffset)
|
||||||
|
if (header.holesSize && !loadHolesData(in, header.holesOffset, header.holesSize))
|
||||||
|
{
|
||||||
|
LOG_ERROR("maps", "Error loading map holes data\n");
|
||||||
|
fclose(in);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
fclose(in);
|
fclose(in);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@@ -1372,6 +1383,7 @@ void GridMap::unloadData()
|
|||||||
delete[] _liquidEntry;
|
delete[] _liquidEntry;
|
||||||
delete[] _liquidFlags;
|
delete[] _liquidFlags;
|
||||||
delete[] _liquidMap;
|
delete[] _liquidMap;
|
||||||
|
delete[] _holes;
|
||||||
_areaMap = nullptr;
|
_areaMap = nullptr;
|
||||||
m_V9 = nullptr;
|
m_V9 = nullptr;
|
||||||
m_V8 = nullptr;
|
m_V8 = nullptr;
|
||||||
@@ -1380,6 +1392,7 @@ void GridMap::unloadData()
|
|||||||
_liquidEntry = nullptr;
|
_liquidEntry = nullptr;
|
||||||
_liquidFlags = nullptr;
|
_liquidFlags = nullptr;
|
||||||
_liquidMap = nullptr;
|
_liquidMap = nullptr;
|
||||||
|
_holes = nullptr;
|
||||||
_gridGetHeight = &GridMap::getHeightFromFlat;
|
_gridGetHeight = &GridMap::getHeightFromFlat;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1491,6 +1504,18 @@ bool GridMap::loadLiquidData(FILE* in, uint32 offset, uint32 /*size*/)
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool GridMap::loadHolesData(FILE* in, uint32 offset, uint32 /*size*/)
|
||||||
|
{
|
||||||
|
if (fseek(in, offset, SEEK_SET) != 0)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
_holes = new uint16[16 * 16];
|
||||||
|
if (fread(_holes, sizeof(uint16), 16 * 16, in) != 16 * 16)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
uint16 GridMap::getArea(float x, float y) const
|
uint16 GridMap::getArea(float x, float y) const
|
||||||
{
|
{
|
||||||
if (!_areaMap)
|
if (!_areaMap)
|
||||||
@@ -1523,6 +1548,9 @@ float GridMap::getHeightFromFloat(float x, float y) const
|
|||||||
x_int &= (MAP_RESOLUTION - 1);
|
x_int &= (MAP_RESOLUTION - 1);
|
||||||
y_int &= (MAP_RESOLUTION - 1);
|
y_int &= (MAP_RESOLUTION - 1);
|
||||||
|
|
||||||
|
if (isHole(x_int, y_int))
|
||||||
|
return INVALID_HEIGHT;
|
||||||
|
|
||||||
// Height stored as: h5 - its v8 grid, h1-h4 - its v9 grid
|
// Height stored as: h5 - its v8 grid, h1-h4 - its v9 grid
|
||||||
// +--------------> X
|
// +--------------> X
|
||||||
// | h1-------h2 Coordinates is:
|
// | h1-------h2 Coordinates is:
|
||||||
@@ -1605,6 +1633,9 @@ float GridMap::getHeightFromUint8(float x, float y) const
|
|||||||
x_int &= (MAP_RESOLUTION - 1);
|
x_int &= (MAP_RESOLUTION - 1);
|
||||||
y_int &= (MAP_RESOLUTION - 1);
|
y_int &= (MAP_RESOLUTION - 1);
|
||||||
|
|
||||||
|
if (isHole(x_int, y_int))
|
||||||
|
return INVALID_HEIGHT;
|
||||||
|
|
||||||
int32 a, b, c;
|
int32 a, b, c;
|
||||||
uint8* V9_h1_ptr = &m_uint8_V9[x_int * 128 + x_int + y_int];
|
uint8* V9_h1_ptr = &m_uint8_V9[x_int * 128 + x_int + y_int];
|
||||||
if (x + y < 1)
|
if (x + y < 1)
|
||||||
@@ -1672,6 +1703,9 @@ float GridMap::getHeightFromUint16(float x, float y) const
|
|||||||
x_int &= (MAP_RESOLUTION - 1);
|
x_int &= (MAP_RESOLUTION - 1);
|
||||||
y_int &= (MAP_RESOLUTION - 1);
|
y_int &= (MAP_RESOLUTION - 1);
|
||||||
|
|
||||||
|
if (isHole(x_int, y_int))
|
||||||
|
return INVALID_HEIGHT;
|
||||||
|
|
||||||
int32 a, b, c;
|
int32 a, b, c;
|
||||||
uint16* V9_h1_ptr = &m_uint16_V9[x_int * 128 + x_int + y_int];
|
uint16* V9_h1_ptr = &m_uint16_V9[x_int * 128 + x_int + y_int];
|
||||||
if (x + y < 1)
|
if (x + y < 1)
|
||||||
@@ -1724,6 +1758,21 @@ float GridMap::getHeightFromUint16(float x, float y) const
|
|||||||
return (float)((a * x) + (b * y) + c) * _gridIntHeightMultiplier + _gridHeight;
|
return (float)((a * x) + (b * y) + c) * _gridIntHeightMultiplier + _gridHeight;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool GridMap::isHole(int row, int col) const
|
||||||
|
{
|
||||||
|
if (!_holes)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
int cellRow = row / 8; // 8 squares per cell
|
||||||
|
int cellCol = col / 8;
|
||||||
|
int holeRow = row % 8 / 2;
|
||||||
|
int holeCol = (col - (cellCol * 8)) / 2;
|
||||||
|
|
||||||
|
uint16 hole = _holes[cellRow * 16 + cellCol];
|
||||||
|
|
||||||
|
return (hole & holetab_h[holeCol] & holetab_v[holeRow]) != 0;
|
||||||
|
}
|
||||||
|
|
||||||
float GridMap::getMinHeight(float x, float y) const
|
float GridMap::getMinHeight(float x, float y) const
|
||||||
{
|
{
|
||||||
if (!_minHeight)
|
if (!_minHeight)
|
||||||
@@ -1803,113 +1852,96 @@ float GridMap::getLiquidLevel(float x, float y) const
|
|||||||
return _liquidMap[cx_int * _liquidWidth + cy_int];
|
return _liquidMap[cx_int * _liquidWidth + cy_int];
|
||||||
}
|
}
|
||||||
|
|
||||||
// Why does this return LIQUID data?
|
|
||||||
uint8 GridMap::getTerrainType(float x, float y) const
|
|
||||||
{
|
|
||||||
if (!_liquidFlags)
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
x = 16 * (32 - x / SIZE_OF_GRIDS);
|
|
||||||
y = 16 * (32 - y / SIZE_OF_GRIDS);
|
|
||||||
int lx = (int)x & 15;
|
|
||||||
int ly = (int)y & 15;
|
|
||||||
return _liquidFlags[lx * 16 + ly];
|
|
||||||
}
|
|
||||||
|
|
||||||
// Get water state on map
|
// Get water state on map
|
||||||
inline ZLiquidStatus GridMap::getLiquidStatus(float x, float y, float z, uint8 ReqLiquidType, float collisionHeight, LiquidData* data)
|
inline LiquidData const GridMap::GetLiquidData(float x, float y, float z, float collisionHeight, uint8 ReqLiquidType) const
|
||||||
{
|
{
|
||||||
|
LiquidData liquidData;
|
||||||
|
|
||||||
// Check water type (if no water return)
|
// Check water type (if no water return)
|
||||||
if (!_liquidType && !_liquidFlags)
|
if (_liquidType || _liquidFlags)
|
||||||
return LIQUID_MAP_NO_WATER;
|
|
||||||
|
|
||||||
// Get cell
|
|
||||||
float cx = MAP_RESOLUTION * (32 - x / SIZE_OF_GRIDS);
|
|
||||||
float cy = MAP_RESOLUTION * (32 - y / SIZE_OF_GRIDS);
|
|
||||||
|
|
||||||
int x_int = (int)cx & (MAP_RESOLUTION - 1);
|
|
||||||
int y_int = (int)cy & (MAP_RESOLUTION - 1);
|
|
||||||
|
|
||||||
// Check water type in cell
|
|
||||||
int idx = (x_int >> 3) * 16 + (y_int >> 3);
|
|
||||||
uint8 type = _liquidFlags ? _liquidFlags[idx] : _liquidType;
|
|
||||||
uint32 entry = 0;
|
|
||||||
if (_liquidEntry)
|
|
||||||
{
|
{
|
||||||
if (LiquidTypeEntry const* liquidEntry = sLiquidTypeStore.LookupEntry(_liquidEntry[idx]))
|
// Get cell
|
||||||
{
|
float cx = MAP_RESOLUTION * (32 - x / SIZE_OF_GRIDS);
|
||||||
entry = liquidEntry->Id;
|
float cy = MAP_RESOLUTION * (32 - y / SIZE_OF_GRIDS);
|
||||||
type &= MAP_LIQUID_TYPE_DARK_WATER;
|
|
||||||
uint32 liqTypeIdx = liquidEntry->Type;
|
|
||||||
if (entry < 21)
|
|
||||||
{
|
|
||||||
if (AreaTableEntry const* area = sAreaTableStore.LookupEntry(getArea(x, y)))
|
|
||||||
{
|
|
||||||
uint32 overrideLiquid = area->LiquidTypeOverride[liquidEntry->Type];
|
|
||||||
if (!overrideLiquid && area->zone)
|
|
||||||
{
|
|
||||||
area = sAreaTableStore.LookupEntry(area->zone);
|
|
||||||
if (area)
|
|
||||||
overrideLiquid = area->LiquidTypeOverride[liquidEntry->Type];
|
|
||||||
}
|
|
||||||
|
|
||||||
if (LiquidTypeEntry const* liq = sLiquidTypeStore.LookupEntry(overrideLiquid))
|
int x_int = (int) cx & (MAP_RESOLUTION - 1);
|
||||||
|
int y_int = (int) cy & (MAP_RESOLUTION - 1);
|
||||||
|
|
||||||
|
// Check water type in cell
|
||||||
|
int idx = (x_int >> 3) * 16 + (y_int >> 3);
|
||||||
|
uint8 type = _liquidFlags ? _liquidFlags[idx] : _liquidType;
|
||||||
|
uint32 entry = 0;
|
||||||
|
if (_liquidEntry)
|
||||||
|
{
|
||||||
|
if (LiquidTypeEntry const* liquidEntry = sLiquidTypeStore.LookupEntry(_liquidEntry[idx]))
|
||||||
|
{
|
||||||
|
entry = liquidEntry->Id;
|
||||||
|
type &= MAP_LIQUID_TYPE_DARK_WATER;
|
||||||
|
uint32 liqTypeIdx = liquidEntry->Type;
|
||||||
|
if (entry < 21)
|
||||||
|
{
|
||||||
|
if (AreaTableEntry const* area = sAreaTableStore.LookupEntry(getArea(x, y)))
|
||||||
{
|
{
|
||||||
entry = overrideLiquid;
|
uint32 overrideLiquid = area->LiquidTypeOverride[liquidEntry->Type];
|
||||||
liqTypeIdx = liq->Type;
|
if (!overrideLiquid && area->zone)
|
||||||
|
{
|
||||||
|
area = sAreaTableStore.LookupEntry(area->zone);
|
||||||
|
if (area)
|
||||||
|
overrideLiquid = area->LiquidTypeOverride[liquidEntry->Type];
|
||||||
|
}
|
||||||
|
|
||||||
|
if (LiquidTypeEntry const* liq = sLiquidTypeStore.LookupEntry(overrideLiquid))
|
||||||
|
{
|
||||||
|
entry = overrideLiquid;
|
||||||
|
liqTypeIdx = liq->Type;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
type |= 1 << liqTypeIdx;
|
type |= 1 << liqTypeIdx;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check req liquid type mask
|
||||||
|
if (type != 0 && (!ReqLiquidType || (ReqLiquidType & type) != 0))
|
||||||
|
{
|
||||||
|
// Check water level:
|
||||||
|
// Check water height map
|
||||||
|
int lx_int = x_int - _liquidOffY;
|
||||||
|
int ly_int = y_int - _liquidOffX;
|
||||||
|
if (lx_int >= 0 && lx_int < _liquidHeight && ly_int >= 0 && ly_int < _liquidWidth)
|
||||||
|
{
|
||||||
|
// Get water level
|
||||||
|
float liquid_level = _liquidMap ? _liquidMap[lx_int * _liquidWidth + ly_int] : _liquidLevel;
|
||||||
|
// Get ground level (sub 0.2 for fix some errors)
|
||||||
|
float ground_level = getHeight(x, y);
|
||||||
|
|
||||||
|
// Check water level and ground level
|
||||||
|
if (liquid_level >= ground_level && z >= ground_level - 2)
|
||||||
|
{
|
||||||
|
// All ok in water -> store data
|
||||||
|
liquidData.Entry = entry;
|
||||||
|
liquidData.Flags = type;
|
||||||
|
liquidData.Level = liquid_level;
|
||||||
|
liquidData.DepthLevel = ground_level;
|
||||||
|
|
||||||
|
// For speed check as int values
|
||||||
|
float delta = liquid_level - z;
|
||||||
|
|
||||||
|
if (delta > collisionHeight)
|
||||||
|
liquidData.Status = LIQUID_MAP_UNDER_WATER;
|
||||||
|
else if (delta > 0.2f)
|
||||||
|
liquidData.Status = LIQUID_MAP_IN_WATER;
|
||||||
|
else if (delta > -0.2f)
|
||||||
|
liquidData.Status = LIQUID_MAP_WATER_WALK;
|
||||||
|
else
|
||||||
|
liquidData.Status = LIQUID_MAP_ABOVE_WATER;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (type == 0)
|
return liquidData;
|
||||||
return LIQUID_MAP_NO_WATER;
|
|
||||||
|
|
||||||
// Check req liquid type mask
|
|
||||||
if (ReqLiquidType && !(ReqLiquidType & type))
|
|
||||||
return LIQUID_MAP_NO_WATER;
|
|
||||||
|
|
||||||
// Check water level:
|
|
||||||
// Check water height map
|
|
||||||
int lx_int = x_int - _liquidOffY;
|
|
||||||
int ly_int = y_int - _liquidOffX;
|
|
||||||
if (lx_int < 0 || lx_int >= _liquidHeight)
|
|
||||||
return LIQUID_MAP_NO_WATER;
|
|
||||||
if (ly_int < 0 || ly_int >= _liquidWidth)
|
|
||||||
return LIQUID_MAP_NO_WATER;
|
|
||||||
|
|
||||||
// Get water level
|
|
||||||
float liquid_level = _liquidMap ? _liquidMap[lx_int * _liquidWidth + ly_int] : _liquidLevel;
|
|
||||||
// Get ground level (sub 0.2 for fix some errors)
|
|
||||||
float ground_level = getHeight(x, y);
|
|
||||||
|
|
||||||
// Check water level and ground level
|
|
||||||
if (liquid_level < ground_level || z < ground_level - 2)
|
|
||||||
return LIQUID_MAP_NO_WATER;
|
|
||||||
|
|
||||||
// All ok in water -> store data
|
|
||||||
if (data)
|
|
||||||
{
|
|
||||||
data->entry = entry;
|
|
||||||
data->type_flags = type;
|
|
||||||
data->level = liquid_level;
|
|
||||||
data->depth_level = ground_level;
|
|
||||||
}
|
|
||||||
|
|
||||||
// For speed check as int values
|
|
||||||
float delta = liquid_level - z;
|
|
||||||
|
|
||||||
if (delta > collisionHeight) // Under water
|
|
||||||
return LIQUID_MAP_UNDER_WATER;
|
|
||||||
if (delta > 0.0f) // In water
|
|
||||||
return LIQUID_MAP_IN_WATER;
|
|
||||||
if (delta > -0.1f) // Walk on water
|
|
||||||
return LIQUID_MAP_WATER_WALK;
|
|
||||||
// Above water
|
|
||||||
return LIQUID_MAP_ABOVE_WATER;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
GridMap* Map::GetGrid(float x, float y)
|
GridMap* Map::GetGrid(float x, float y)
|
||||||
@@ -1933,17 +1965,15 @@ float Map::GetWaterOrGroundLevel(uint32 phasemask, float x, float y, float z, fl
|
|||||||
if (ground)
|
if (ground)
|
||||||
*ground = ground_z;
|
*ground = ground_z;
|
||||||
|
|
||||||
LiquidData liquid_status;
|
LiquidData const& liquidData = const_cast<Map*>(this)->GetLiquidData(phasemask, x, y, ground_z, collisionHeight, MAP_ALL_LIQUIDS);
|
||||||
|
switch (liquidData.Status)
|
||||||
ZLiquidStatus res = getLiquidStatus(x, y, ground_z, MAP_ALL_LIQUIDS, &liquid_status, collisionHeight);
|
|
||||||
switch (res)
|
|
||||||
{
|
{
|
||||||
case LIQUID_MAP_ABOVE_WATER:
|
case LIQUID_MAP_ABOVE_WATER:
|
||||||
return std::max<float>(liquid_status.level, ground_z);
|
return std::max<float>(liquidData.Level, ground_z);
|
||||||
case LIQUID_MAP_NO_WATER:
|
case LIQUID_MAP_NO_WATER:
|
||||||
return ground_z;
|
return ground_z;
|
||||||
default:
|
default:
|
||||||
return liquid_status.level;
|
return liquidData.Level;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -2030,115 +2060,99 @@ float Map::GetMinHeight(float x, float y) const
|
|||||||
return -500.0f;
|
return -500.0f;
|
||||||
}
|
}
|
||||||
|
|
||||||
inline bool IsOutdoorWMO(uint32 mogpFlags, int32 /*adtId*/, int32 /*rootId*/, int32 /*groupId*/, WMOAreaTableEntry const* wmoEntry, AreaTableEntry const* atEntry)
|
static inline bool IsInWMOInterior(uint32 mogpFlags)
|
||||||
{
|
{
|
||||||
bool outdoor = true;
|
return (mogpFlags & 0x2000) != 0;
|
||||||
|
|
||||||
if (wmoEntry && atEntry)
|
|
||||||
{
|
|
||||||
if (atEntry->flags & AREA_FLAG_OUTSIDE)
|
|
||||||
return true;
|
|
||||||
if (atEntry->flags & AREA_FLAG_INSIDE)
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
outdoor = mogpFlags & 0x8;
|
|
||||||
|
|
||||||
if (wmoEntry)
|
|
||||||
{
|
|
||||||
if (wmoEntry->Flags & 4)
|
|
||||||
return true;
|
|
||||||
if ((wmoEntry->Flags & 2) != 0)
|
|
||||||
outdoor = false;
|
|
||||||
}
|
|
||||||
return outdoor;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Map::IsOutdoors(float x, float y, float z) const
|
bool Map::GetAreaInfo(uint32 phaseMask, float x, float y, float z, uint32& flags, int32& adtId, int32& rootId, int32& groupId) const
|
||||||
{
|
|
||||||
uint32 mogpFlags;
|
|
||||||
int32 adtId, rootId, groupId;
|
|
||||||
|
|
||||||
// no wmo found? -> outside by default
|
|
||||||
if (!GetAreaInfo(x, y, z, mogpFlags, adtId, rootId, groupId))
|
|
||||||
return true;
|
|
||||||
|
|
||||||
AreaTableEntry const* atEntry = 0;
|
|
||||||
WMOAreaTableEntry const* wmoEntry = GetWMOAreaTableEntryByTripple(rootId, adtId, groupId);
|
|
||||||
if (wmoEntry)
|
|
||||||
{
|
|
||||||
LOG_DEBUG("maps", "Got WMOAreaTableEntry! flag %u, areaid %u", wmoEntry->Flags, wmoEntry->areaId);
|
|
||||||
atEntry = sAreaTableStore.LookupEntry(wmoEntry->areaId);
|
|
||||||
}
|
|
||||||
return IsOutdoorWMO(mogpFlags, adtId, rootId, groupId, wmoEntry, atEntry);
|
|
||||||
}
|
|
||||||
|
|
||||||
bool Map::GetAreaInfo(float x, float y, float z, uint32& flags, int32& adtId, int32& rootId, int32& groupId) const
|
|
||||||
{
|
{
|
||||||
float vmap_z = z;
|
float vmap_z = z;
|
||||||
|
float dynamic_z = z;
|
||||||
|
float check_z = z;
|
||||||
VMAP::IVMapManager* vmgr = VMAP::VMapFactory::createOrGetVMapManager();
|
VMAP::IVMapManager* vmgr = VMAP::VMapFactory::createOrGetVMapManager();
|
||||||
if (vmgr->GetAreaInfo(GetId(), x, y, vmap_z, flags, adtId, rootId, groupId))
|
uint32 vflags;
|
||||||
|
int32 vadtId;
|
||||||
|
int32 vrootId;
|
||||||
|
int32 vgroupId;
|
||||||
|
uint32 dflags;
|
||||||
|
int32 dadtId;
|
||||||
|
int32 drootId;
|
||||||
|
int32 dgroupId;
|
||||||
|
|
||||||
|
bool hasVmapAreaInfo = vmgr->GetAreaInfo(GetId(), x, y, vmap_z, vflags, vadtId, vrootId, vgroupId);
|
||||||
|
bool hasDynamicAreaInfo = _dynamicTree.GetAreaInfo(x, y, dynamic_z, phaseMask, dflags, dadtId, drootId, dgroupId);
|
||||||
|
auto useVmap = [&]() { check_z = vmap_z; flags = vflags; adtId = vadtId; rootId = vrootId; groupId = vgroupId; };
|
||||||
|
auto useDyn = [&]() { check_z = dynamic_z; flags = dflags; adtId = dadtId; rootId = drootId; groupId = dgroupId; };
|
||||||
|
|
||||||
|
if (hasVmapAreaInfo)
|
||||||
|
{
|
||||||
|
if (hasDynamicAreaInfo && dynamic_z > vmap_z)
|
||||||
|
useDyn();
|
||||||
|
else
|
||||||
|
useVmap();
|
||||||
|
}
|
||||||
|
else if (hasDynamicAreaInfo)
|
||||||
|
{
|
||||||
|
useDyn();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (hasVmapAreaInfo || hasDynamicAreaInfo)
|
||||||
{
|
{
|
||||||
// check if there's terrain between player height and object height
|
// check if there's terrain between player height and object height
|
||||||
if (GridMap* gmap = const_cast<Map*>(this)->GetGrid(x, y))
|
if (GridMap* gmap = const_cast<Map*>(this)->GetGrid(x, y))
|
||||||
{
|
{
|
||||||
float _mapheight = gmap->getHeight(x, y);
|
float mapHeight = gmap->getHeight(x, y);
|
||||||
// z + 2.0f condition taken from GetHeight(), not sure if it's such a great choice...
|
// z + 2.0f condition taken from GetHeight(), not sure if it's such a great choice...
|
||||||
if (z + 2.0f > _mapheight && _mapheight > vmap_z)
|
if (z + 2.0f > mapHeight && mapHeight > check_z)
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
uint32 Map::GetAreaId(float x, float y, float z, bool* isOutdoors) const
|
uint32 Map::GetAreaId(uint32 phaseMask, float x, float y, float z) const
|
||||||
{
|
{
|
||||||
uint32 mogpFlags;
|
uint32 mogpFlags;
|
||||||
int32 adtId, rootId, groupId;
|
int32 adtId, rootId, groupId;
|
||||||
WMOAreaTableEntry const* wmoEntry = 0;
|
float vmapZ = 0.f;
|
||||||
AreaTableEntry const* atEntry = 0;
|
bool hasVmapArea = GetAreaInfo(phaseMask, x, y, vmapZ, mogpFlags, adtId, rootId, groupId);
|
||||||
bool haveAreaInfo = false;
|
|
||||||
|
|
||||||
if (GetAreaInfo(x, y, z, mogpFlags, adtId, rootId, groupId))
|
uint32 gridAreaId = 0;
|
||||||
|
float gridMapHeight = INVALID_HEIGHT;
|
||||||
|
if (GridMap* gmap = const_cast<Map*>(this)->GetGrid(x, y))
|
||||||
{
|
{
|
||||||
haveAreaInfo = true;
|
gridAreaId = gmap->getArea(x, y);
|
||||||
wmoEntry = GetWMOAreaTableEntryByTripple(rootId, adtId, groupId);
|
gridMapHeight = gmap->getHeight(x, y);
|
||||||
if (wmoEntry)
|
|
||||||
atEntry = sAreaTableStore.LookupEntry(wmoEntry->areaId);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
uint16 areaId = 0;
|
uint16 areaId = 0;
|
||||||
|
|
||||||
if (atEntry)
|
// floor is the height we are closer to (but only if above)
|
||||||
areaId = atEntry->ID;
|
if (hasVmapArea && G3D::fuzzyGe(z, vmapZ - GROUND_HEIGHT_TOLERANCE) && (G3D::fuzzyLt(z, gridMapHeight - GROUND_HEIGHT_TOLERANCE) || vmapZ > gridMapHeight))
|
||||||
else
|
|
||||||
{
|
{
|
||||||
if (GridMap* gmap = const_cast<Map*>(this)->GetGrid(x, y))
|
// wmo found
|
||||||
areaId = gmap->getArea(x, y);
|
if (WMOAreaTableEntry const* wmoEntry = GetWMOAreaTableEntryByTripple(rootId, adtId, groupId))
|
||||||
// this used while not all *.map files generated (instances)
|
areaId = wmoEntry->areaId;
|
||||||
if (!areaId)
|
|
||||||
areaId = i_mapEntry->linked_zone;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (isOutdoors)
|
if (!areaId)
|
||||||
{
|
areaId = gridAreaId;
|
||||||
if (haveAreaInfo)
|
|
||||||
*isOutdoors = IsOutdoorWMO(mogpFlags, adtId, rootId, groupId, wmoEntry, atEntry);
|
|
||||||
else
|
|
||||||
*isOutdoors = true;
|
|
||||||
}
|
}
|
||||||
|
else
|
||||||
|
areaId = gridAreaId;
|
||||||
|
|
||||||
|
if (!areaId)
|
||||||
|
areaId = i_mapEntry->linked_zone;
|
||||||
|
|
||||||
return areaId;
|
return areaId;
|
||||||
}
|
}
|
||||||
|
|
||||||
uint32 Map::GetAreaId(float x, float y, float z) const
|
uint32 Map::GetZoneId(uint32 phaseMask, float x, float y, float z) const
|
||||||
{
|
{
|
||||||
return GetAreaId(x, y, z, nullptr);
|
uint32 areaId = GetAreaId(phaseMask, x, y, z);
|
||||||
}
|
|
||||||
|
|
||||||
uint32 Map::GetZoneId(float x, float y, float z) const
|
|
||||||
{
|
|
||||||
uint32 areaId = GetAreaId(x, y, z);
|
|
||||||
if (AreaTableEntry const* area = sAreaTableStore.LookupEntry(areaId))
|
if (AreaTableEntry const* area = sAreaTableStore.LookupEntry(areaId))
|
||||||
if (area->zone)
|
if (area->zone)
|
||||||
return area->zone;
|
return area->zone;
|
||||||
@@ -2146,105 +2160,239 @@ uint32 Map::GetZoneId(float x, float y, float z) const
|
|||||||
return areaId;
|
return areaId;
|
||||||
}
|
}
|
||||||
|
|
||||||
void Map::GetZoneAndAreaId(uint32& zoneid, uint32& areaid, float x, float y, float z) const
|
void Map::GetZoneAndAreaId(uint32 phaseMask, uint32& zoneid, uint32& areaid, float x, float y, float z) const
|
||||||
{
|
{
|
||||||
areaid = zoneid = GetAreaId(x, y, z);
|
areaid = zoneid = GetAreaId(phaseMask, x, y, z);
|
||||||
if (AreaTableEntry const* area = sAreaTableStore.LookupEntry(areaid))
|
if (AreaTableEntry const* area = sAreaTableStore.LookupEntry(areaid))
|
||||||
if (area->zone)
|
if (area->zone)
|
||||||
zoneid = area->zone;
|
zoneid = area->zone;
|
||||||
}
|
}
|
||||||
|
|
||||||
uint8 Map::GetTerrainType(float x, float y) const
|
LiquidData const Map::GetLiquidData(uint32 phaseMask, float x, float y, float z, float collisionHeight, uint8 ReqLiquidType)
|
||||||
{
|
{
|
||||||
if (GridMap* gmap = const_cast<Map*>(this)->GetGrid(x, y))
|
LiquidData liquidData;
|
||||||
return gmap->getTerrainType(x, y);
|
|
||||||
else
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
ZLiquidStatus Map::getLiquidStatus(float x, float y, float z, uint8 ReqLiquidType, LiquidData* data, float collisionHeight) const
|
|
||||||
{
|
|
||||||
ZLiquidStatus result = LIQUID_MAP_NO_WATER;
|
|
||||||
VMAP::IVMapManager* vmgr = VMAP::VMapFactory::createOrGetVMapManager();
|
VMAP::IVMapManager* vmgr = VMAP::VMapFactory::createOrGetVMapManager();
|
||||||
float liquid_level = INVALID_HEIGHT;
|
float liquid_level = INVALID_HEIGHT;
|
||||||
float ground_level = INVALID_HEIGHT;
|
float ground_level = INVALID_HEIGHT;
|
||||||
uint32 liquid_type = 0;
|
uint32 liquid_type = 0;
|
||||||
if (vmgr->GetLiquidLevel(GetId(), x, y, z, ReqLiquidType, liquid_level, ground_level, liquid_type))
|
uint32 mogpFlags = 0;
|
||||||
|
bool useGridLiquid = true;
|
||||||
|
if (vmgr->GetLiquidLevel(GetId(), x, y, z, ReqLiquidType, liquid_level, ground_level, liquid_type, mogpFlags))
|
||||||
{
|
{
|
||||||
LOG_DEBUG("maps", "getLiquidStatus(): vmap liquid level: %f ground: %f type: %u", liquid_level, ground_level, liquid_type);
|
useGridLiquid = !IsInWMOInterior(mogpFlags);
|
||||||
|
LOG_DEBUG("maps", "GetLiquidStatus(): vmap liquid level: %f ground: %f type: %u", liquid_level, ground_level, liquid_type);
|
||||||
// Check water level and ground level
|
// Check water level and ground level
|
||||||
if (liquid_level > ground_level && z > ground_level - 2)
|
if (liquid_level > ground_level && G3D::fuzzyGe(z, ground_level - GROUND_HEIGHT_TOLERANCE))
|
||||||
{
|
{
|
||||||
// All ok in water -> store data
|
// hardcoded in client like this
|
||||||
if (data)
|
if (GetId() == 530 && liquid_type == 2)
|
||||||
|
liquid_type = 15;
|
||||||
|
|
||||||
|
uint32 liquidFlagType = 0;
|
||||||
|
if (LiquidTypeEntry const* liq = sLiquidTypeStore.LookupEntry(liquid_type))
|
||||||
|
liquidFlagType = liq->Type;
|
||||||
|
|
||||||
|
if (liquid_type && liquid_type < 21)
|
||||||
{
|
{
|
||||||
// hardcoded in client like this
|
if (AreaTableEntry const* area = sAreaTableStore.LookupEntry(GetAreaId(phaseMask, x, y, z)))
|
||||||
if (GetId() == 530 && liquid_type == 2)
|
|
||||||
liquid_type = 15;
|
|
||||||
|
|
||||||
uint32 liquidFlagType = 0;
|
|
||||||
if (LiquidTypeEntry const* liq = sLiquidTypeStore.LookupEntry(liquid_type))
|
|
||||||
liquidFlagType = liq->Type;
|
|
||||||
|
|
||||||
if (liquid_type && liquid_type < 21)
|
|
||||||
{
|
{
|
||||||
if (AreaTableEntry const* area = sAreaTableStore.LookupEntry(GetAreaId(x, y, z)))
|
uint32 overrideLiquid = area->LiquidTypeOverride[liquidFlagType];
|
||||||
|
if (!overrideLiquid && area->zone)
|
||||||
{
|
{
|
||||||
uint32 overrideLiquid = area->LiquidTypeOverride[liquidFlagType];
|
area = sAreaTableStore.LookupEntry(area->zone);
|
||||||
if (!overrideLiquid && area->zone)
|
if (area)
|
||||||
{
|
overrideLiquid = area->LiquidTypeOverride[liquidFlagType];
|
||||||
area = sAreaTableStore.LookupEntry(area->zone);
|
}
|
||||||
if (area)
|
|
||||||
overrideLiquid = area->LiquidTypeOverride[liquidFlagType];
|
|
||||||
}
|
|
||||||
|
|
||||||
if (LiquidTypeEntry const* liq = sLiquidTypeStore.LookupEntry(overrideLiquid))
|
if (LiquidTypeEntry const* liq = sLiquidTypeStore.LookupEntry(overrideLiquid))
|
||||||
{
|
{
|
||||||
liquid_type = overrideLiquid;
|
liquid_type = overrideLiquid;
|
||||||
liquidFlagType = liq->Type;
|
liquidFlagType = liq->Type;
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
data->level = liquid_level;
|
|
||||||
data->depth_level = ground_level;
|
|
||||||
|
|
||||||
data->entry = liquid_type;
|
|
||||||
data->type_flags = 1 << liquidFlagType;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
float delta = liquid_level - z;
|
liquidData.Level = liquid_level;
|
||||||
|
liquidData.DepthLevel = ground_level;
|
||||||
// Get position delta
|
liquidData.Entry = liquid_type;
|
||||||
if (delta > collisionHeight) // Under water
|
liquidData.Flags = 1 << liquidFlagType;
|
||||||
return LIQUID_MAP_UNDER_WATER;
|
|
||||||
if (delta > 0.0f) // In water
|
|
||||||
return LIQUID_MAP_IN_WATER;
|
|
||||||
if (delta > -0.1f) // Walk on water
|
|
||||||
return LIQUID_MAP_WATER_WALK;
|
|
||||||
result = LIQUID_MAP_ABOVE_WATER;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
float delta = liquid_level - z;
|
||||||
|
|
||||||
|
// Get position delta
|
||||||
|
if (delta > collisionHeight)
|
||||||
|
liquidData.Status = LIQUID_MAP_UNDER_WATER;
|
||||||
|
if (delta > 0.2f)
|
||||||
|
liquidData.Status = LIQUID_MAP_IN_WATER;
|
||||||
|
if (delta > -0.2f)
|
||||||
|
liquidData.Status = LIQUID_MAP_WATER_WALK;
|
||||||
|
else
|
||||||
|
liquidData.Status = LIQUID_MAP_ABOVE_WATER;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (GridMap* gmap = const_cast<Map*>(this)->GetGrid(x, y))
|
if (useGridLiquid)
|
||||||
{
|
{
|
||||||
LiquidData map_data;
|
if (GridMap* gmap = const_cast<Map*>(this)->GetGrid(x, y))
|
||||||
ZLiquidStatus map_result = gmap->getLiquidStatus(x, y, z, ReqLiquidType, collisionHeight, &map_data);
|
|
||||||
// Not override LIQUID_MAP_ABOVE_WATER with LIQUID_MAP_NO_WATER:
|
|
||||||
if (map_result != LIQUID_MAP_NO_WATER && (map_data.level > ground_level))
|
|
||||||
{
|
{
|
||||||
if (data)
|
LiquidData const& map_data = gmap->GetLiquidData(x, y, z, collisionHeight, ReqLiquidType);
|
||||||
|
// Not override LIQUID_MAP_ABOVE_WATER with LIQUID_MAP_NO_WATER:
|
||||||
|
if (map_data.Status != LIQUID_MAP_NO_WATER && (map_data.Level > ground_level))
|
||||||
{
|
{
|
||||||
// hardcoded in client like this
|
// hardcoded in client like this
|
||||||
if (GetId() == 530 && map_data.entry == 2)
|
uint32 liquidEntry = map_data.Entry;
|
||||||
map_data.entry = 15;
|
if (GetId() == 530 && liquidEntry == 2)
|
||||||
|
liquidEntry = 15;
|
||||||
|
|
||||||
*data = map_data;
|
liquidData = map_data;
|
||||||
|
liquidData.Entry = liquidEntry;
|
||||||
}
|
}
|
||||||
return map_result;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return result;
|
|
||||||
|
return liquidData;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Map::GetFullTerrainStatusForPosition(uint32 phaseMask, float x, float y, float z, float collisionHeight, PositionFullTerrainStatus& data, uint8 reqLiquidType)
|
||||||
|
{
|
||||||
|
GridMap* gmap = GetGrid(x, y);
|
||||||
|
|
||||||
|
VMAP::IVMapManager* vmgr = VMAP::VMapFactory::createOrGetVMapManager();
|
||||||
|
VMAP::AreaAndLiquidData vmapData;
|
||||||
|
VMAP::AreaAndLiquidData dynData;
|
||||||
|
VMAP::AreaAndLiquidData* wmoData = nullptr;
|
||||||
|
vmgr->GetAreaAndLiquidData(GetId(), x, y, z, reqLiquidType, vmapData);
|
||||||
|
_dynamicTree.GetAreaAndLiquidData(x, y, z, phaseMask, reqLiquidType, dynData);
|
||||||
|
|
||||||
|
uint32 gridAreaId = 0;
|
||||||
|
float gridMapHeight = INVALID_HEIGHT;
|
||||||
|
if (gmap)
|
||||||
|
{
|
||||||
|
gridAreaId = gmap->getArea(x, y);
|
||||||
|
gridMapHeight = gmap->getHeight(x, y);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool useGridLiquid = true;
|
||||||
|
|
||||||
|
// floor is the height we are closer to (but only if above)
|
||||||
|
data.floorZ = VMAP_INVALID_HEIGHT;
|
||||||
|
if (gridMapHeight > INVALID_HEIGHT && G3D::fuzzyGe(z, gridMapHeight - GROUND_HEIGHT_TOLERANCE))
|
||||||
|
data.floorZ = gridMapHeight;
|
||||||
|
|
||||||
|
if (vmapData.floorZ > VMAP_INVALID_HEIGHT && G3D::fuzzyGe(z, vmapData.floorZ - GROUND_HEIGHT_TOLERANCE) &&
|
||||||
|
(G3D::fuzzyLt(z, gridMapHeight - GROUND_HEIGHT_TOLERANCE) || vmapData.floorZ > gridMapHeight))
|
||||||
|
{
|
||||||
|
data.floorZ = vmapData.floorZ;
|
||||||
|
wmoData = &vmapData;
|
||||||
|
}
|
||||||
|
|
||||||
|
// NOTE: Objects will not detect a case when a wmo providing area/liquid despawns from under them
|
||||||
|
// but this is fine as these kind of objects are not meant to be spawned and despawned a lot
|
||||||
|
// example: Lich King platform
|
||||||
|
if (dynData.floorZ > VMAP_INVALID_HEIGHT && G3D::fuzzyGe(z, dynData.floorZ - GROUND_HEIGHT_TOLERANCE) &&
|
||||||
|
(G3D::fuzzyLt(z, gridMapHeight - GROUND_HEIGHT_TOLERANCE) || dynData.floorZ > gridMapHeight) &&
|
||||||
|
(G3D::fuzzyLt(z, vmapData.floorZ - GROUND_HEIGHT_TOLERANCE) || dynData.floorZ > vmapData.floorZ))
|
||||||
|
{
|
||||||
|
data.floorZ = dynData.floorZ;
|
||||||
|
wmoData = &dynData;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (wmoData)
|
||||||
|
{
|
||||||
|
if (wmoData->areaInfo)
|
||||||
|
{
|
||||||
|
// wmo found
|
||||||
|
WMOAreaTableEntry const* wmoEntry = GetWMOAreaTableEntryByTripple(wmoData->areaInfo->rootId, wmoData->areaInfo->adtId, wmoData->areaInfo->groupId);
|
||||||
|
data.outdoors = (wmoData->areaInfo->mogpFlags & 0x8) != 0;
|
||||||
|
if (wmoEntry)
|
||||||
|
{
|
||||||
|
data.areaId = wmoEntry->areaId;
|
||||||
|
if (wmoEntry->Flags & 4)
|
||||||
|
data.outdoors = true;
|
||||||
|
else if (wmoEntry->Flags & 2)
|
||||||
|
data.outdoors = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!data.areaId)
|
||||||
|
data.areaId = gridAreaId;
|
||||||
|
|
||||||
|
useGridLiquid = !IsInWMOInterior(wmoData->areaInfo->mogpFlags);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
data.outdoors = true;
|
||||||
|
data.areaId = gridAreaId;
|
||||||
|
if (AreaTableEntry const* areaEntry = sAreaTableStore.LookupEntry(data.areaId))
|
||||||
|
data.outdoors = (areaEntry->flags & (AREA_FLAG_INSIDE | AREA_FLAG_OUTSIDE)) != AREA_FLAG_INSIDE;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!data.areaId)
|
||||||
|
data.areaId = i_mapEntry->linked_zone;
|
||||||
|
|
||||||
|
AreaTableEntry const* areaEntry = sAreaTableStore.LookupEntry(data.areaId);
|
||||||
|
|
||||||
|
// liquid processing
|
||||||
|
if (wmoData && wmoData->liquidInfo && wmoData->liquidInfo->level > wmoData->floorZ)
|
||||||
|
{
|
||||||
|
uint32 liquidType = wmoData->liquidInfo->type;
|
||||||
|
if (GetId() == 530 && liquidType == 2) // gotta love blizzard hacks
|
||||||
|
liquidType = 15;
|
||||||
|
|
||||||
|
uint32 liquidFlagType = 0;
|
||||||
|
if (LiquidTypeEntry const* liquidData = sLiquidTypeStore.LookupEntry(liquidType))
|
||||||
|
liquidFlagType = liquidData->Type;
|
||||||
|
|
||||||
|
if (liquidType && liquidType < 21 && areaEntry)
|
||||||
|
{
|
||||||
|
uint32 overrideLiquid = areaEntry->LiquidTypeOverride[liquidFlagType];
|
||||||
|
if (!overrideLiquid && areaEntry->zone)
|
||||||
|
{
|
||||||
|
AreaTableEntry const* zoneEntry = sAreaTableStore.LookupEntry(areaEntry->zone);
|
||||||
|
if (zoneEntry)
|
||||||
|
overrideLiquid = zoneEntry->LiquidTypeOverride[liquidFlagType];
|
||||||
|
}
|
||||||
|
|
||||||
|
if (LiquidTypeEntry const* overrideData = sLiquidTypeStore.LookupEntry(overrideLiquid))
|
||||||
|
{
|
||||||
|
liquidType = overrideLiquid;
|
||||||
|
liquidFlagType = overrideData->Type;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
data.liquidInfo.Level = wmoData->liquidInfo->level;
|
||||||
|
data.liquidInfo.DepthLevel = wmoData->floorZ;
|
||||||
|
data.liquidInfo.Entry = liquidType;
|
||||||
|
data.liquidInfo.Flags = 1 << liquidFlagType;
|
||||||
|
|
||||||
|
// Get position delta
|
||||||
|
float delta = wmoData->liquidInfo->level - z;
|
||||||
|
|
||||||
|
if (delta > collisionHeight)
|
||||||
|
data.liquidInfo.Status = LIQUID_MAP_UNDER_WATER;
|
||||||
|
else if (delta > 0.2f)
|
||||||
|
data.liquidInfo.Status = LIQUID_MAP_IN_WATER;
|
||||||
|
else if (delta > -0.2f)
|
||||||
|
data.liquidInfo.Status = LIQUID_MAP_WATER_WALK;
|
||||||
|
else
|
||||||
|
data.liquidInfo.Status = LIQUID_MAP_ABOVE_WATER;
|
||||||
|
}
|
||||||
|
|
||||||
|
// look up liquid data from grid map
|
||||||
|
if (gmap && useGridLiquid)
|
||||||
|
{
|
||||||
|
LiquidData const& gridLiquidData = gmap->GetLiquidData(x, y, z, collisionHeight, reqLiquidType);
|
||||||
|
if (gridLiquidData.Status != LIQUID_MAP_NO_WATER && (!wmoData || gridLiquidData.Level > wmoData->floorZ))
|
||||||
|
{
|
||||||
|
uint32 liquidEntry = gridLiquidData.Entry;
|
||||||
|
if (GetId() == 530 && liquidEntry == 2)
|
||||||
|
liquidEntry = 15;
|
||||||
|
|
||||||
|
data.liquidInfo = gridLiquidData;
|
||||||
|
data.liquidInfo.Entry = liquidEntry;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
float Map::GetWaterLevel(float x, float y) const
|
float Map::GetWaterLevel(float x, float y) const
|
||||||
@@ -2288,30 +2436,28 @@ float Map::GetHeight(uint32 phasemask, float x, float y, float z, bool vmap/*=tr
|
|||||||
return std::max<float>(h1, h2);
|
return std::max<float>(h1, h2);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Map::IsInWater(float x, float y, float pZ, LiquidData* data) const
|
bool Map::IsInWater(uint32 phaseMask, float x, float y, float pZ, float collisionHeight) const
|
||||||
{
|
{
|
||||||
LiquidData liquid_status;
|
LiquidData const& liquidData = const_cast<Map*>(this)->GetLiquidData(phaseMask, x, y, pZ, collisionHeight, MAP_ALL_LIQUIDS);
|
||||||
LiquidData* liquid_ptr = data ? data : &liquid_status;
|
return (liquidData.Status & MAP_LIQUID_STATUS_SWIMMING) != 0;
|
||||||
return getLiquidStatus(x, y, pZ, MAP_ALL_LIQUIDS, liquid_ptr) & (LIQUID_MAP_IN_WATER | LIQUID_MAP_UNDER_WATER);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Map::IsUnderWater(float x, float y, float z) const
|
bool Map::IsUnderWater(uint32 phaseMask, float x, float y, float z, float collisionHeight) const
|
||||||
{
|
{
|
||||||
return getLiquidStatus(x, y, z, MAP_LIQUID_TYPE_WATER | MAP_LIQUID_TYPE_OCEAN) & LIQUID_MAP_UNDER_WATER;
|
LiquidData const& liquidData = const_cast<Map*>(this)->GetLiquidData(phaseMask, x, y, z, collisionHeight, MAP_LIQUID_TYPE_WATER | MAP_LIQUID_TYPE_OCEAN);
|
||||||
|
return liquidData.Status == LIQUID_MAP_UNDER_WATER;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Map::HasEnoughWater(WorldObject const* searcher, float x, float y, float z) const
|
bool Map::HasEnoughWater(WorldObject const* searcher, float x, float y, float z) const
|
||||||
{
|
{
|
||||||
LiquidData liquidData;
|
LiquidData const& liquidData = const_cast<Map*>(this)->GetLiquidData(searcher->GetPhaseMask(), x, y, z, searcher->GetCollisionHeight(), MAP_ALL_LIQUIDS);
|
||||||
liquidData.level = INVALID_HEIGHT;
|
return (liquidData.Status & MAP_LIQUID_STATUS_SWIMMING) != 0 && HasEnoughWater(searcher, liquidData);
|
||||||
ZLiquidStatus liquidStatus = getLiquidStatus(x, y, z, MAP_ALL_LIQUIDS, &liquidData);
|
|
||||||
return (liquidStatus & (LIQUID_MAP_IN_WATER | LIQUID_MAP_UNDER_WATER)) && HasEnoughWater(searcher, liquidData);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Map::HasEnoughWater(WorldObject const* searcher, LiquidData liquidData) const
|
bool Map::HasEnoughWater(WorldObject const* searcher, LiquidData const& liquidData) const
|
||||||
{
|
{
|
||||||
float minHeightInWater = searcher->GetMinHeightInWater();
|
float minHeightInWater = searcher->GetMinHeightInWater();
|
||||||
return liquidData.level > INVALID_HEIGHT && liquidData.level > liquidData.depth_level && liquidData.level - liquidData.depth_level >= minHeightInWater;
|
return liquidData.Level > INVALID_HEIGHT && liquidData.Level > liquidData.DepthLevel && liquidData.Level - liquidData.DepthLevel >= minHeightInWater;
|
||||||
}
|
}
|
||||||
|
|
||||||
char const* Map::GetMapName() const
|
char const* Map::GetMapName() const
|
||||||
@@ -3421,6 +3567,8 @@ Corpse* Map::ConvertCorpseToBones(ObjectGuid const ownerGuid, bool insignia /*=
|
|||||||
|
|
||||||
AddCorpse(bones);
|
AddCorpse(bones);
|
||||||
|
|
||||||
|
bones->UpdatePositionData();
|
||||||
|
|
||||||
// add bones in grid store if grid loaded where corpse placed
|
// add bones in grid store if grid loaded where corpse placed
|
||||||
AddToMap(bones);
|
AddToMap(bones);
|
||||||
}
|
}
|
||||||
@@ -3459,7 +3607,7 @@ void Map::RemoveOldCorpses()
|
|||||||
|
|
||||||
void Map::SendZoneDynamicInfo(Player* player)
|
void Map::SendZoneDynamicInfo(Player* player)
|
||||||
{
|
{
|
||||||
uint32 zoneId = GetZoneId(player->GetPositionX(), player->GetPositionY(), player->GetPositionZ());
|
uint32 zoneId = player->GetZoneId();
|
||||||
ZoneDynamicInfoMap::const_iterator itr = _zoneDynamicInfo.find(zoneId);
|
ZoneDynamicInfoMap::const_iterator itr = _zoneDynamicInfo.find(zoneId);
|
||||||
if (itr == _zoneDynamicInfo.end())
|
if (itr == _zoneDynamicInfo.end())
|
||||||
return;
|
return;
|
||||||
@@ -3671,7 +3819,7 @@ bool Map::CheckCollisionAndGetValidCoords(const WorldObject* source, float start
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool isWaterNext = IsInWater(destX, destY, destZ);
|
bool isWaterNext = IsInWater(source->GetPhaseMask(), destX, destY, destZ, source->GetCollisionHeight());
|
||||||
|
|
||||||
PathGenerator path(source);
|
PathGenerator path(source);
|
||||||
|
|
||||||
@@ -3784,6 +3932,8 @@ void Map::LoadCorpseData()
|
|||||||
}
|
}
|
||||||
|
|
||||||
AddCorpse(corpse);
|
AddCorpse(corpse);
|
||||||
|
|
||||||
|
corpse->UpdatePositionData();
|
||||||
} while (result->NextRow());
|
} while (result->NextRow());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+41
-25
@@ -76,6 +76,8 @@ struct map_fileheader
|
|||||||
uint32 heightMapSize;
|
uint32 heightMapSize;
|
||||||
uint32 liquidMapOffset;
|
uint32 liquidMapOffset;
|
||||||
uint32 liquidMapSize;
|
uint32 liquidMapSize;
|
||||||
|
uint32 holesOffset;
|
||||||
|
uint32 holesSize;
|
||||||
};
|
};
|
||||||
|
|
||||||
#define MAP_AREA_NO_AREA 0x0001
|
#define MAP_AREA_NO_AREA 0x0001
|
||||||
@@ -115,7 +117,7 @@ struct map_liquidHeader
|
|||||||
float liquidLevel;
|
float liquidLevel;
|
||||||
};
|
};
|
||||||
|
|
||||||
enum ZLiquidStatus
|
enum LiquidStatus
|
||||||
{
|
{
|
||||||
LIQUID_MAP_NO_WATER = 0x00000000,
|
LIQUID_MAP_NO_WATER = 0x00000000,
|
||||||
LIQUID_MAP_ABOVE_WATER = 0x00000001,
|
LIQUID_MAP_ABOVE_WATER = 0x00000001,
|
||||||
@@ -124,6 +126,9 @@ enum ZLiquidStatus
|
|||||||
LIQUID_MAP_UNDER_WATER = 0x00000008
|
LIQUID_MAP_UNDER_WATER = 0x00000008
|
||||||
};
|
};
|
||||||
|
|
||||||
|
#define MAP_LIQUID_STATUS_SWIMMING (LIQUID_MAP_IN_WATER | LIQUID_MAP_UNDER_WATER)
|
||||||
|
#define MAP_LIQUID_STATUS_IN_CONTACT (MAP_LIQUID_STATUS_SWIMMING | LIQUID_MAP_WATER_WALK)
|
||||||
|
|
||||||
#define MAP_LIQUID_TYPE_NO_WATER 0x00
|
#define MAP_LIQUID_TYPE_NO_WATER 0x00
|
||||||
#define MAP_LIQUID_TYPE_WATER 0x01
|
#define MAP_LIQUID_TYPE_WATER 0x01
|
||||||
#define MAP_LIQUID_TYPE_OCEAN 0x02
|
#define MAP_LIQUID_TYPE_OCEAN 0x02
|
||||||
@@ -135,12 +140,30 @@ enum ZLiquidStatus
|
|||||||
#define MAP_LIQUID_TYPE_DARK_WATER 0x10
|
#define MAP_LIQUID_TYPE_DARK_WATER 0x10
|
||||||
#define MAP_LIQUID_TYPE_WMO_WATER 0x20
|
#define MAP_LIQUID_TYPE_WMO_WATER 0x20
|
||||||
|
|
||||||
|
#define MAX_HEIGHT 100000.0f // can be use for find ground height at surface
|
||||||
|
#define INVALID_HEIGHT -100000.0f // for check, must be equal to VMAP_INVALID_HEIGHT, real value for unknown height is VMAP_INVALID_HEIGHT_VALUE
|
||||||
|
#define MAX_FALL_DISTANCE 250000.0f // "unlimited fall" to find VMap ground if it is available, just larger than MAX_HEIGHT - INVALID_HEIGHT
|
||||||
|
#define DEFAULT_HEIGHT_SEARCH 50.0f // default search distance to find height at nearby locations
|
||||||
|
#define MIN_UNLOAD_DELAY 1 // immediate unload
|
||||||
|
|
||||||
struct LiquidData
|
struct LiquidData
|
||||||
{
|
{
|
||||||
uint32 type_flags;
|
LiquidData() : Entry(0), Flags(0), Level(INVALID_HEIGHT), DepthLevel(INVALID_HEIGHT), Status(LIQUID_MAP_NO_WATER) { }
|
||||||
uint32 entry;
|
|
||||||
float level;
|
uint32 Entry;
|
||||||
float depth_level;
|
uint32 Flags;
|
||||||
|
float Level;
|
||||||
|
float DepthLevel;
|
||||||
|
LiquidStatus Status;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct PositionFullTerrainStatus
|
||||||
|
{
|
||||||
|
PositionFullTerrainStatus() : areaId(0), floorZ(INVALID_HEIGHT), outdoors(false) { }
|
||||||
|
uint32 areaId;
|
||||||
|
float floorZ;
|
||||||
|
bool outdoors;
|
||||||
|
LiquidData liquidInfo;
|
||||||
};
|
};
|
||||||
|
|
||||||
enum LineOfSightChecks
|
enum LineOfSightChecks
|
||||||
@@ -186,10 +209,13 @@ class GridMap
|
|||||||
uint8 _liquidOffY;
|
uint8 _liquidOffY;
|
||||||
uint8 _liquidWidth;
|
uint8 _liquidWidth;
|
||||||
uint8 _liquidHeight;
|
uint8 _liquidHeight;
|
||||||
|
uint16* _holes;
|
||||||
|
|
||||||
bool loadAreaData(FILE* in, uint32 offset, uint32 size);
|
bool loadAreaData(FILE* in, uint32 offset, uint32 size);
|
||||||
bool loadHeightData(FILE* in, uint32 offset, uint32 size);
|
bool loadHeightData(FILE* in, uint32 offset, uint32 size);
|
||||||
bool loadLiquidData(FILE* in, uint32 offset, uint32 size);
|
bool loadLiquidData(FILE* in, uint32 offset, uint32 size);
|
||||||
|
bool loadHolesData(FILE* in, uint32 offset, uint32 size);
|
||||||
|
bool isHole(int row, int col) const;
|
||||||
|
|
||||||
// Get height functions and pointers
|
// Get height functions and pointers
|
||||||
typedef float (GridMap::*GetHeightPtr) (float x, float y) const;
|
typedef float (GridMap::*GetHeightPtr) (float x, float y) const;
|
||||||
@@ -209,8 +235,7 @@ public:
|
|||||||
[[nodiscard]] inline float getHeight(float x, float y) const {return (this->*_gridGetHeight)(x, y);}
|
[[nodiscard]] inline float getHeight(float x, float y) const {return (this->*_gridGetHeight)(x, y);}
|
||||||
[[nodiscard]] float getMinHeight(float x, float y) const;
|
[[nodiscard]] float getMinHeight(float x, float y) const;
|
||||||
[[nodiscard]] float getLiquidLevel(float x, float y) const;
|
[[nodiscard]] float getLiquidLevel(float x, float y) const;
|
||||||
[[nodiscard]] uint8 getTerrainType(float x, float y) const;
|
LiquidData const GetLiquidData(float x, float y, float z, float collisionHeight, uint8 ReqLiquidType) const;
|
||||||
ZLiquidStatus getLiquidStatus(float x, float y, float z, uint8 ReqLiquidType, float collisionHeight, LiquidData* data = nullptr);
|
|
||||||
};
|
};
|
||||||
|
|
||||||
// GCC have alternative #pragma pack(N) syntax and old gcc version not support pack(push, N), also any gcc version not support it at some platform
|
// GCC have alternative #pragma pack(N) syntax and old gcc version not support pack(push, N), also any gcc version not support it at some platform
|
||||||
@@ -249,12 +274,6 @@ struct ZoneDynamicInfo
|
|||||||
#pragma pack(pop)
|
#pragma pack(pop)
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#define MAX_HEIGHT 100000.0f // can be use for find ground height at surface
|
|
||||||
#define INVALID_HEIGHT -100000.0f // for check, must be equal to VMAP_INVALID_HEIGHT, real value for unknown height is VMAP_INVALID_HEIGHT_VALUE
|
|
||||||
#define MAX_FALL_DISTANCE 250000.0f // "unlimited fall" to find VMap ground if it is available, just larger than MAX_HEIGHT - INVALID_HEIGHT
|
|
||||||
#define DEFAULT_HEIGHT_SEARCH 50.0f // default search distance to find height at nearby locations
|
|
||||||
#define MIN_UNLOAD_DELAY 1 // immediate unload
|
|
||||||
|
|
||||||
typedef std::map<uint32/*leaderDBGUID*/, CreatureGroup*> CreatureGroupHolderType;
|
typedef std::map<uint32/*leaderDBGUID*/, CreatureGroup*> CreatureGroupHolderType;
|
||||||
typedef std::unordered_map<uint32 /*zoneId*/, ZoneDynamicInfo> ZoneDynamicInfoMap;
|
typedef std::unordered_map<uint32 /*zoneId*/, ZoneDynamicInfo> ZoneDynamicInfoMap;
|
||||||
typedef std::set<MotionTransport*> TransportsContainer;
|
typedef std::set<MotionTransport*> TransportsContainer;
|
||||||
@@ -352,22 +371,19 @@ public:
|
|||||||
[[nodiscard]] float GetMinHeight(float x, float y) const;
|
[[nodiscard]] float GetMinHeight(float x, float y) const;
|
||||||
Transport* GetTransportForPos(uint32 phase, float x, float y, float z, WorldObject* worldobject = nullptr);
|
Transport* GetTransportForPos(uint32 phase, float x, float y, float z, WorldObject* worldobject = nullptr);
|
||||||
|
|
||||||
ZLiquidStatus getLiquidStatus(float x, float y, float z, uint8 ReqLiquidType, LiquidData* data = nullptr, float collisionHeight = DEFAULT_COLLISION_HEIGHT) const;
|
void GetFullTerrainStatusForPosition(uint32 phaseMask, float x, float y, float z, float collisionHeight, PositionFullTerrainStatus& data, uint8 reqLiquidType = MAP_ALL_LIQUIDS);
|
||||||
|
LiquidData const GetLiquidData(uint32 phaseMask, float x, float y, float z, float collisionHeight, uint8 ReqLiquidType);
|
||||||
|
|
||||||
uint32 GetAreaId(float x, float y, float z, bool* isOutdoors) const;
|
[[nodiscard]] bool GetAreaInfo(uint32 phaseMask, float x, float y, float z, uint32& mogpflags, int32& adtId, int32& rootId, int32& groupId) const;
|
||||||
bool GetAreaInfo(float x, float y, float z, uint32& mogpflags, int32& adtId, int32& rootId, int32& groupId) const;
|
[[nodiscard]] uint32 GetAreaId(uint32 phaseMask, float x, float y, float z) const;
|
||||||
[[nodiscard]] uint32 GetAreaId(float x, float y, float z) const;
|
[[nodiscard]] uint32 GetZoneId(uint32 phaseMask, float x, float y, float z) const;
|
||||||
[[nodiscard]] uint32 GetZoneId(float x, float y, float z) const;
|
void GetZoneAndAreaId(uint32 phaseMask, uint32& zoneid, uint32& areaid, float x, float y, float z) const;
|
||||||
void GetZoneAndAreaId(uint32& zoneid, uint32& areaid, float x, float y, float z) const;
|
|
||||||
|
|
||||||
[[nodiscard]] bool IsOutdoors(float x, float y, float z) const;
|
|
||||||
|
|
||||||
[[nodiscard]] uint8 GetTerrainType(float x, float y) const;
|
|
||||||
[[nodiscard]] float GetWaterLevel(float x, float y) const;
|
[[nodiscard]] float GetWaterLevel(float x, float y) const;
|
||||||
bool IsInWater(float x, float y, float z, LiquidData* data = nullptr) const;
|
bool IsInWater(uint32 phaseMask, float x, float y, float z, float collisionHeight) const;
|
||||||
[[nodiscard]] bool IsUnderWater(float x, float y, float z) const;
|
[[nodiscard]] bool IsUnderWater(uint32 phaseMask, float x, float y, float z, float collisionHeight) const;
|
||||||
[[nodiscard]] bool HasEnoughWater(WorldObject const* searcher, float x, float y, float z) const;
|
[[nodiscard]] bool HasEnoughWater(WorldObject const* searcher, float x, float y, float z) const;
|
||||||
[[nodiscard]] bool HasEnoughWater(WorldObject const* searcher, LiquidData liquidData) const;
|
[[nodiscard]] bool HasEnoughWater(WorldObject const* searcher, LiquidData const& liquidData) const;
|
||||||
|
|
||||||
void MoveAllCreaturesInMoveList();
|
void MoveAllCreaturesInMoveList();
|
||||||
void MoveAllGameObjectsInMoveList();
|
void MoveAllGameObjectsInMoveList();
|
||||||
|
|||||||
@@ -37,26 +37,26 @@ public:
|
|||||||
return (iter == i_maps.end() ? nullptr : iter->second);
|
return (iter == i_maps.end() ? nullptr : iter->second);
|
||||||
}
|
}
|
||||||
|
|
||||||
[[nodiscard]] uint32 GetAreaId(uint32 mapid, float x, float y, float z) const
|
[[nodiscard]] uint32 GetAreaId(uint32 phaseMask, uint32 mapid, float x, float y, float z) const
|
||||||
{
|
{
|
||||||
Map const* m = const_cast<MapManager*>(this)->CreateBaseMap(mapid);
|
Map const* m = const_cast<MapManager*>(this)->CreateBaseMap(mapid);
|
||||||
return m->GetAreaId(x, y, z);
|
return m->GetAreaId(phaseMask, x, y, z);
|
||||||
}
|
}
|
||||||
[[nodiscard]] uint32 GetAreaId(uint32 mapid, Position const& pos) const { return GetAreaId(mapid, pos.GetPositionX(), pos.GetPositionY(), pos.GetPositionZ()); }
|
[[nodiscard]] uint32 GetAreaId(uint32 phaseMask, uint32 mapid, Position const& pos) const { return GetAreaId(phaseMask, mapid, pos.GetPositionX(), pos.GetPositionY(), pos.GetPositionZ()); }
|
||||||
[[nodiscard]] uint32 GetAreaId(WorldLocation const& loc) const { return GetAreaId(loc.GetMapId(), loc); }
|
[[nodiscard]] uint32 GetAreaId(uint32 phaseMask, WorldLocation const& loc) const { return GetAreaId(phaseMask, loc.GetMapId(), loc); }
|
||||||
|
|
||||||
[[nodiscard]] uint32 GetZoneId(uint32 mapid, float x, float y, float z) const
|
[[nodiscard]] uint32 GetZoneId(uint32 phaseMask, uint32 mapid, float x, float y, float z) const
|
||||||
{
|
{
|
||||||
Map const* m = const_cast<MapManager*>(this)->CreateBaseMap(mapid);
|
Map const* m = const_cast<MapManager*>(this)->CreateBaseMap(mapid);
|
||||||
return m->GetZoneId(x, y, z);
|
return m->GetZoneId(phaseMask, x, y, z);
|
||||||
}
|
}
|
||||||
[[nodiscard]] uint32 GetZoneId(uint32 mapid, Position const& pos) const { return GetZoneId(mapid, pos.GetPositionX(), pos.GetPositionY(), pos.GetPositionZ()); }
|
[[nodiscard]] uint32 GetZoneId(uint32 phaseMask, uint32 mapid, Position const& pos) const { return GetZoneId(phaseMask, mapid, pos.GetPositionX(), pos.GetPositionY(), pos.GetPositionZ()); }
|
||||||
[[nodiscard]] uint32 GetZoneId(WorldLocation const& loc) const { return GetZoneId(loc.GetMapId(), loc); }
|
[[nodiscard]] uint32 GetZoneId(uint32 phaseMask, WorldLocation const& loc) const { return GetZoneId(phaseMask, loc.GetMapId(), loc); }
|
||||||
|
|
||||||
void GetZoneAndAreaId(uint32& zoneid, uint32& areaid, uint32 mapid, float x, float y, float z)
|
void GetZoneAndAreaId(uint32 phaseMask, uint32& zoneid, uint32& areaid, uint32 mapid, float x, float y, float z)
|
||||||
{
|
{
|
||||||
Map const* m = const_cast<MapManager*>(this)->CreateBaseMap(mapid);
|
Map const* m = const_cast<MapManager*>(this)->CreateBaseMap(mapid);
|
||||||
m->GetZoneAndAreaId(zoneid, areaid, x, y, z);
|
m->GetZoneAndAreaId(phaseMask, zoneid, areaid, x, y, z);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Initialize(void);
|
void Initialize(void);
|
||||||
|
|||||||
@@ -83,7 +83,7 @@ GraveyardStruct const* Graveyard::GetDefaultGraveyard(TeamId teamId)
|
|||||||
GraveyardStruct const* Graveyard::GetClosestGraveyard(float x, float y, float z, uint32 MapId, TeamId teamId)
|
GraveyardStruct const* Graveyard::GetClosestGraveyard(float x, float y, float z, uint32 MapId, TeamId teamId)
|
||||||
{
|
{
|
||||||
// search for zone associated closest graveyard
|
// search for zone associated closest graveyard
|
||||||
uint32 zoneId = sMapMgr->GetZoneId(MapId, x, y, z);
|
uint32 zoneId = sMapMgr->GetZoneId(PHASEMASK_NORMAL, MapId, x, y, z);
|
||||||
|
|
||||||
if (!zoneId)
|
if (!zoneId)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -132,11 +132,6 @@ void MotionMaster::UpdateMotion(uint32 diff)
|
|||||||
}
|
}
|
||||||
|
|
||||||
_cleanFlag &= ~MMCF_INUSE;
|
_cleanFlag &= ~MMCF_INUSE;
|
||||||
|
|
||||||
if (_owner->GetTypeId() == TYPEID_PLAYER)
|
|
||||||
_owner->UpdateUnderwaterState(_owner->GetMap(), _owner->GetPositionX(), _owner->GetPositionY(), _owner->GetPositionZ());
|
|
||||||
else
|
|
||||||
_owner->UpdateEnvironmentIfNeeded(0);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void MotionMaster::DirectClean(bool reset)
|
void MotionMaster::DirectClean(bool reset)
|
||||||
|
|||||||
@@ -26,7 +26,7 @@ void ConfusedMovementGenerator<T>::DoInitialize(T* unit)
|
|||||||
float y = unit->GetPositionY();
|
float y = unit->GetPositionY();
|
||||||
float z = unit->GetPositionZ();
|
float z = unit->GetPositionZ();
|
||||||
|
|
||||||
Map const* map = unit->GetBaseMap();
|
Map const* map = unit->GetMap();
|
||||||
|
|
||||||
bool is_water_ok, is_land_ok;
|
bool is_water_ok, is_land_ok;
|
||||||
_InitSpecific(unit, is_water_ok, is_land_ok);
|
_InitSpecific(unit, is_water_ok, is_land_ok);
|
||||||
@@ -50,7 +50,7 @@ void ConfusedMovementGenerator<T>::DoInitialize(T* unit)
|
|||||||
}
|
}
|
||||||
else if (unit->IsWithinLOS(wanderX, wanderY, z))
|
else if (unit->IsWithinLOS(wanderX, wanderY, z))
|
||||||
{
|
{
|
||||||
bool is_water = map->IsInWater(wanderX, wanderY, z);
|
bool is_water = map->IsInWater(unit->GetPhaseMask(), wanderX, wanderY, z, unit->GetCollisionHeight());
|
||||||
|
|
||||||
if ((is_water && !is_water_ok) || (!is_water && !is_land_ok))
|
if ((is_water && !is_water_ok) || (!is_water && !is_land_ok))
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -48,7 +48,7 @@ bool FleeingMovementGenerator<T>::_getPoint(T* owner, float& x, float& y, float&
|
|||||||
if (!owner)
|
if (!owner)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
const Map* _map = owner->GetBaseMap();
|
const Map* _map = owner->GetMap();
|
||||||
|
|
||||||
x = owner->GetPositionX();
|
x = owner->GetPositionX();
|
||||||
y = owner->GetPositionY();
|
y = owner->GetPositionY();
|
||||||
|
|||||||
@@ -29,8 +29,6 @@ void HomeMovementGenerator<Creature>::DoFinalize(Creature* owner)
|
|||||||
|
|
||||||
if (!owner->HasSwimmingFlagOutOfCombat())
|
if (!owner->HasSwimmingFlagOutOfCombat())
|
||||||
owner->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_SWIMMING);
|
owner->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_SWIMMING);
|
||||||
|
|
||||||
owner->UpdateEnvironmentIfNeeded(2);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void HomeMovementGenerator<Creature>::DoReset(Creature*)
|
void HomeMovementGenerator<Creature>::DoReset(Creature*)
|
||||||
|
|||||||
@@ -197,8 +197,8 @@ void PathGenerator::BuildPolyPath(G3D::Vector3 const& startPos, G3D::Vector3 con
|
|||||||
{
|
{
|
||||||
bool buildShotrcut = false;
|
bool buildShotrcut = false;
|
||||||
|
|
||||||
bool isUnderWaterStart = _source->GetMap()->IsUnderWater(startPos.x, startPos.y, startPos.z);
|
bool isUnderWaterStart = _source->GetMap()->IsUnderWater(_source->GetPhaseMask(), startPos.x, startPos.y, startPos.z, _source->GetCollisionHeight());
|
||||||
bool isUnderWaterEnd = _source->GetMap()->IsUnderWater(endPos.x, endPos.y, endPos.z);
|
bool isUnderWaterEnd = _source->GetMap()->IsUnderWater(_source->GetPhaseMask(), endPos.x, endPos.y, endPos.z, _source->GetCollisionHeight());
|
||||||
bool isFarUnderWater = startFarFromPoly ? isUnderWaterStart : isUnderWaterEnd;
|
bool isFarUnderWater = startFarFromPoly ? isUnderWaterStart : isUnderWaterEnd;
|
||||||
|
|
||||||
Unit const* _sourceUnit = _source->ToUnit();
|
Unit const* _sourceUnit = _source->ToUnit();
|
||||||
@@ -565,9 +565,9 @@ void PathGenerator::BuildPointPath(const float* startPoint, const float* endPoin
|
|||||||
uint32 newPointCount = 0;
|
uint32 newPointCount = 0;
|
||||||
for (uint32 i = 0; i < pointCount; ++i) {
|
for (uint32 i = 0; i < pointCount; ++i) {
|
||||||
G3D::Vector3 vector = G3D::Vector3(pathPoints[i * VERTEX_SIZE + 2], pathPoints[i * VERTEX_SIZE], pathPoints[i * VERTEX_SIZE + 1]);
|
G3D::Vector3 vector = G3D::Vector3(pathPoints[i * VERTEX_SIZE + 2], pathPoints[i * VERTEX_SIZE], pathPoints[i * VERTEX_SIZE + 1]);
|
||||||
ZLiquidStatus status = _source->GetMap()->getLiquidStatus(vector.x, vector.y, vector.z, MAP_ALL_LIQUIDS, nullptr);
|
LiquidData const& liquidData = _source->GetMap()->GetLiquidData(_source->GetPhaseMask(), vector.x, vector.y, vector.z, _source->GetCollisionHeight(), MAP_ALL_LIQUIDS);
|
||||||
// One of the points is not in the water
|
// One of the points is not in the water
|
||||||
if (status == LIQUID_MAP_UNDER_WATER)
|
if (liquidData.Status == LIQUID_MAP_UNDER_WATER)
|
||||||
{
|
{
|
||||||
// if the first point is under water
|
// if the first point is under water
|
||||||
// then set a proper z for it
|
// then set a proper z for it
|
||||||
@@ -699,11 +699,11 @@ void PathGenerator::UpdateFilter()
|
|||||||
NavTerrain PathGenerator::GetNavTerrain(float x, float y, float z) const
|
NavTerrain PathGenerator::GetNavTerrain(float x, float y, float z) const
|
||||||
{
|
{
|
||||||
LiquidData data;
|
LiquidData data;
|
||||||
ZLiquidStatus liquidStatus = _source->GetMap()->getLiquidStatus(x, y, z, MAP_ALL_LIQUIDS, &data);
|
LiquidData const& liquidData = _source->GetMap()->GetLiquidData(_source->GetPhaseMask(), x, y, z, _source->GetCollisionHeight(), MAP_ALL_LIQUIDS);
|
||||||
if (liquidStatus == LIQUID_MAP_NO_WATER)
|
if (liquidData.Status == LIQUID_MAP_NO_WATER)
|
||||||
return NAV_GROUND;
|
return NAV_GROUND;
|
||||||
|
|
||||||
switch (data.type_flags)
|
switch (data.Flags)
|
||||||
{
|
{
|
||||||
case MAP_LIQUID_TYPE_WATER:
|
case MAP_LIQUID_TYPE_WATER:
|
||||||
case MAP_LIQUID_TYPE_OCEAN:
|
case MAP_LIQUID_TYPE_OCEAN:
|
||||||
@@ -1149,8 +1149,8 @@ bool PathGenerator::IsSwimmableSegment(float const* v1, float const* v2, bool ch
|
|||||||
bool PathGenerator::IsSwimmableSegment(float x, float y, float z, float destX, float destY, float destZ, bool checkSwim) const
|
bool PathGenerator::IsSwimmableSegment(float x, float y, float z, float destX, float destY, float destZ, bool checkSwim) const
|
||||||
{
|
{
|
||||||
Creature const* _sourceCreature = _source->ToCreature();
|
Creature const* _sourceCreature = _source->ToCreature();
|
||||||
return _source->GetMap()->IsInWater(x, y, z) &&
|
return _source->GetMap()->IsInWater(_source->GetPhaseMask(), x, y, z, _source->GetCollisionHeight()) &&
|
||||||
_source->GetMap()->IsInWater(destX, destY, destZ) &&
|
_source->GetMap()->IsInWater(_source->GetPhaseMask(), destX, destY, destZ, _source->GetCollisionHeight()) &&
|
||||||
(!checkSwim || !_sourceCreature || _sourceCreature->CanSwim());
|
(!checkSwim || !_sourceCreature || _sourceCreature->CanSwim());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -110,6 +110,9 @@ namespace Movement
|
|||||||
[[nodiscard]] Vector3 CurrentDestination() const { return Initialized() ? spline.getPoint(point_Idx + 1, false) : Vector3(); }
|
[[nodiscard]] Vector3 CurrentDestination() const { return Initialized() ? spline.getPoint(point_Idx + 1, false) : Vector3(); }
|
||||||
[[nodiscard]] int32 currentPathIdx() const;
|
[[nodiscard]] int32 currentPathIdx() const;
|
||||||
|
|
||||||
|
[[nodiscard]] bool HasAnimation() const { return splineflags.animation; }
|
||||||
|
[[nodiscard]] uint8 GetAnimationType() const { return splineflags.animId; }
|
||||||
|
|
||||||
bool onTransport;
|
bool onTransport;
|
||||||
[[nodiscard]] std::string ToString() const;
|
[[nodiscard]] std::string ToString() const;
|
||||||
[[nodiscard]] bool HasStarted() const
|
[[nodiscard]] bool HasStarted() const
|
||||||
|
|||||||
@@ -5784,7 +5784,7 @@ void AuraEffect::HandlePreventResurrection(AuraApplication const* aurApp, uint8
|
|||||||
|
|
||||||
if (apply)
|
if (apply)
|
||||||
aurApp->GetTarget()->RemoveByteFlag(PLAYER_FIELD_BYTES, 0, PLAYER_FIELD_BYTE_RELEASE_TIMER);
|
aurApp->GetTarget()->RemoveByteFlag(PLAYER_FIELD_BYTES, 0, PLAYER_FIELD_BYTE_RELEASE_TIMER);
|
||||||
else if (!aurApp->GetTarget()->GetBaseMap()->Instanceable())
|
else if (!aurApp->GetTarget()->GetMap()->Instanceable())
|
||||||
aurApp->GetTarget()->SetByteFlag(PLAYER_FIELD_BYTES, 0, PLAYER_FIELD_BYTE_RELEASE_TIMER);
|
aurApp->GetTarget()->SetByteFlag(PLAYER_FIELD_BYTES, 0, PLAYER_FIELD_BYTE_RELEASE_TIMER);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1327,9 +1327,9 @@ void Spell::SelectImplicitCasterDestTargets(SpellEffIndex effIndex, SpellImplici
|
|||||||
|
|
||||||
float ground = m_caster->GetMapHeight(x, y, z, true);
|
float ground = m_caster->GetMapHeight(x, y, z, true);
|
||||||
float liquidLevel = VMAP_INVALID_HEIGHT_VALUE;
|
float liquidLevel = VMAP_INVALID_HEIGHT_VALUE;
|
||||||
LiquidData liquidData;
|
LiquidData const& liquidData = m_caster->GetMap()->GetLiquidData(m_caster->GetPhaseMask(), x, y, z, m_caster->GetCollisionHeight(), MAP_ALL_LIQUIDS);
|
||||||
if (m_caster->GetMap()->getLiquidStatus(x, y, z, MAP_ALL_LIQUIDS, &liquidData, m_caster->GetCollisionHeight()))
|
if (liquidData.Status)
|
||||||
liquidLevel = liquidData.level;
|
liquidLevel = liquidData.Level;
|
||||||
|
|
||||||
if (liquidLevel <= ground) // When there is no liquid Map::GetWaterOrGroundLevel returns ground level
|
if (liquidLevel <= ground) // When there is no liquid Map::GetWaterOrGroundLevel returns ground level
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -444,7 +444,6 @@ public:
|
|||||||
|
|
||||||
Map2ZoneCoordinates(zoneX, zoneY, zoneId);
|
Map2ZoneCoordinates(zoneX, zoneY, zoneId);
|
||||||
|
|
||||||
Map const* map = object->GetMap();
|
|
||||||
float groundZ = object->GetMapHeight(object->GetPositionX(), object->GetPositionY(), MAX_HEIGHT);
|
float groundZ = object->GetMapHeight(object->GetPositionX(), object->GetPositionY(), MAX_HEIGHT);
|
||||||
float floorZ = object->GetMapHeight(object->GetPositionX(), object->GetPositionY(), object->GetPositionZ());
|
float floorZ = object->GetMapHeight(object->GetPositionX(), object->GetPositionY(), object->GetPositionZ());
|
||||||
|
|
||||||
@@ -459,7 +458,7 @@ public:
|
|||||||
|
|
||||||
if (haveVMap)
|
if (haveVMap)
|
||||||
{
|
{
|
||||||
if (map->IsOutdoors(object->GetPositionX(), object->GetPositionY(), object->GetPositionZ()))
|
if (object->IsOutdoors())
|
||||||
handler->PSendSysMessage("You are outdoors");
|
handler->PSendSysMessage("You are outdoors");
|
||||||
else
|
else
|
||||||
handler->PSendSysMessage("You are indoors");
|
handler->PSendSysMessage("You are indoors");
|
||||||
@@ -476,11 +475,11 @@ public:
|
|||||||
cell.GridX(), cell.GridY(), cell.CellX(), cell.CellY(), object->GetInstanceId(),
|
cell.GridX(), cell.GridY(), cell.CellX(), cell.CellY(), object->GetInstanceId(),
|
||||||
zoneX, zoneY, groundZ, floorZ, haveMap, haveVMap);
|
zoneX, zoneY, groundZ, floorZ, haveMap, haveVMap);
|
||||||
|
|
||||||
LiquidData liquidStatus;
|
LiquidData const& liquidData = object->GetLiquidData();
|
||||||
ZLiquidStatus status = map->getLiquidStatus(object->GetPositionX(), object->GetPositionY(), object->GetPositionZ(), MAP_ALL_LIQUIDS, &liquidStatus);
|
|
||||||
|
if (liquidData.Status)
|
||||||
|
handler->PSendSysMessage(LANG_LIQUID_STATUS, liquidData.Level, liquidData.DepthLevel, liquidData.Entry, liquidData.Flags, liquidData.Status);
|
||||||
|
|
||||||
if (status)
|
|
||||||
handler->PSendSysMessage(LANG_LIQUID_STATUS, liquidStatus.level, liquidStatus.depth_level, liquidStatus.entry, liquidStatus.type_flags, status);
|
|
||||||
if (object->GetTransport())
|
if (object->GetTransport())
|
||||||
handler->PSendSysMessage("Transport offset: %.2f, %.2f, %.2f, %.2f", object->m_movementInfo.transport.pos.GetPositionX(), object->m_movementInfo.transport.pos.GetPositionY(), object->m_movementInfo.transport.pos.GetPositionZ(), object->m_movementInfo.transport.pos.GetOrientation());
|
handler->PSendSysMessage("Transport offset: %.2f, %.2f, %.2f, %.2f", object->m_movementInfo.transport.pos.GetPositionX(), object->m_movementInfo.transport.pos.GetPositionY(), object->m_movementInfo.transport.pos.GetPositionZ(), object->m_movementInfo.transport.pos.GetOrientation());
|
||||||
|
|
||||||
|
|||||||
@@ -191,7 +191,7 @@ public:
|
|||||||
|
|
||||||
handler->PSendSysMessage(LANG_TELEPORTING_TO, nameLink.c_str(), handler->GetAcoreString(LANG_OFFLINE), tele->name.c_str());
|
handler->PSendSysMessage(LANG_TELEPORTING_TO, nameLink.c_str(), handler->GetAcoreString(LANG_OFFLINE), tele->name.c_str());
|
||||||
Player::SavePositionInDB(tele->mapId, tele->position_x, tele->position_y, tele->position_z, tele->orientation,
|
Player::SavePositionInDB(tele->mapId, tele->position_x, tele->position_y, tele->position_z, tele->orientation,
|
||||||
sMapMgr->GetZoneId(tele->mapId, tele->position_x, tele->position_y, tele->position_z), target_guid);
|
sMapMgr->GetZoneId(PHASEMASK_NORMAL, tele->mapId, tele->position_x, tele->position_y, tele->position_z), target_guid);
|
||||||
}
|
}
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
|
|||||||
@@ -2171,7 +2171,7 @@ public:
|
|||||||
Position pos;
|
Position pos;
|
||||||
caster->GetPosition(&pos);
|
caster->GetPosition(&pos);
|
||||||
caster->GetNearPosition(pos, 5.0f, 0.0f);
|
caster->GetNearPosition(pos, 5.0f, 0.0f);
|
||||||
pos.m_positionZ = caster->GetBaseMap()->GetHeight(caster->GetPhaseMask(), pos.GetPositionX(), pos.GetPositionY(), caster->GetPositionZ(), true, 50.0f);
|
pos.m_positionZ = caster->GetMap()->GetHeight(caster->GetPhaseMask(), pos.GetPositionX(), pos.GetPositionY(), caster->GetPositionZ(), true, 50.0f);
|
||||||
pos.m_positionZ += 0.1f;
|
pos.m_positionZ += 0.1f;
|
||||||
caster->SendMeleeAttackStop(caster->GetVictim());
|
caster->SendMeleeAttackStop(caster->GetVictim());
|
||||||
caster->GetMotionMaster()->MoveLand(POINT_LAND, pos, 7.0f);
|
caster->GetMotionMaster()->MoveLand(POINT_LAND, pos, 7.0f);
|
||||||
|
|||||||
@@ -2004,6 +2004,7 @@ struct VehicleSeatEntry
|
|||||||
VEHICLE_SEAT_FLAG_B_USABLE_FORCED_3 | VEHICLE_SEAT_FLAG_B_USABLE_FORCED_4)));
|
VEHICLE_SEAT_FLAG_B_USABLE_FORCED_3 | VEHICLE_SEAT_FLAG_B_USABLE_FORCED_4)));
|
||||||
}
|
}
|
||||||
[[nodiscard]] bool IsEjectable() const { return m_flagsB & VEHICLE_SEAT_FLAG_B_EJECTABLE; }
|
[[nodiscard]] bool IsEjectable() const { return m_flagsB & VEHICLE_SEAT_FLAG_B_EJECTABLE; }
|
||||||
|
[[nodiscard]] bool CanControl() const { return (m_flags & VEHICLE_SEAT_FLAG_CAN_CONTROL) != 0; }
|
||||||
};
|
};
|
||||||
|
|
||||||
struct WMOAreaTableEntry
|
struct WMOAreaTableEntry
|
||||||
|
|||||||
Reference in New Issue
Block a user