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:
parent
909c3e5799
commit
a8c0a2cc89
47 changed files with 1086 additions and 883 deletions
|
|
@ -8,9 +8,14 @@
|
|||
#include "BoundingIntervalHierarchyWrapper.h"
|
||||
#include "GameObjectModel.h"
|
||||
#include "Log.h"
|
||||
#include "MapTree.h"
|
||||
#include "ModelInstance.h"
|
||||
#include "RegularGrid.h"
|
||||
#include "Timer.h"
|
||||
#include "VMapFactory.h"
|
||||
#include "VMapManager2.h"
|
||||
#include "WorldModel.h"
|
||||
|
||||
#include <G3D/AABox.h>
|
||||
#include <G3D/Ray.h>
|
||||
#include <G3D/Vector3.h>
|
||||
|
|
@ -145,6 +150,52 @@ struct DynamicTreeIntersectionCallback
|
|||
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,
|
||||
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();
|
||||
}
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
namespace VMAP
|
||||
{
|
||||
struct AreaAndLiquidData;
|
||||
}
|
||||
|
||||
class GameObjectModel;
|
||||
struct DynTreeImpl;
|
||||
|
||||
|
|
@ -32,6 +37,9 @@ public:
|
|||
bool GetIntersectionTime(uint32 phasemask, const G3D::Ray& ray,
|
||||
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,
|
||||
const G3D::Vector3& pPos2, G3D::Vector3& pResultHitPos,
|
||||
float pModifyDist) const;
|
||||
|
|
|
|||
|
|
@ -8,6 +8,7 @@
|
|||
#define _IVMAPMANAGER_H
|
||||
|
||||
#include "Define.h"
|
||||
#include "Optional.h"
|
||||
#include <string>
|
||||
|
||||
//===========================================================
|
||||
|
|
@ -25,8 +26,33 @@ namespace VMAP
|
|||
VMAP_LOAD_RESULT_IGNORED
|
||||
};
|
||||
|
||||
#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 -100000.0f // for check
|
||||
#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
|
||||
|
|
@ -79,8 +105,10 @@ namespace VMAP
|
|||
Query world model area info.
|
||||
\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 GetLiquidLevel(uint32 pMapId, float x, float y, float z, uint8 ReqLiquidType, float& level, float& floor, uint32& type) 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, 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;
|
||||
}
|
||||
|
||||
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 (!IsVMAPDisabledForPtr(mapId, VMAP_DISABLE_AREAFLAG))
|
||||
|
|
@ -275,7 +275,7 @@ namespace VMAP
|
|||
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 (!IsVMAPDisabledForPtr(mapId, VMAP_DISABLE_LIQUIDSTATUS))
|
||||
|
|
@ -291,6 +291,7 @@ namespace VMAP
|
|||
floor = info.ground_Z;
|
||||
ASSERT(floor < std::numeric_limits<float>::max());
|
||||
type = info.hitModel->GetLiquidType(); // entry from LiquidType.dbc
|
||||
mogpFlags = info.hitModel->GetMogpFlags();
|
||||
if (reqLiquidType && !(GetLiquidFlagsPtr(type) & reqLiquidType))
|
||||
{
|
||||
return false;
|
||||
|
|
@ -306,6 +307,38 @@ namespace VMAP
|
|||
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)
|
||||
{
|
||||
//! 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 GetAreaInfo(unsigned int pMapId, float x, float y, float& z, uint32& flags, int32& adtId, int32& rootId, int32& groupId) const override;
|
||||
bool GetLiquidLevel(uint32 pMapId, float x, float y, float z, uint8 reqLiquidType, float& level, float& floor, uint32& type) const override;
|
||||
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, 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);
|
||||
void releaseModelInstance(const std::string& filename);
|
||||
|
|
|
|||
|
|
@ -23,6 +23,7 @@ namespace VMAP
|
|||
const ModelInstance* hitInstance{nullptr};
|
||||
const GroupModel* hitModel{nullptr};
|
||||
float ground_Z;
|
||||
int32 rootId = -1;
|
||||
};
|
||||
|
||||
class StaticMapTree
|
||||
|
|
|
|||
|
|
@ -6,6 +6,7 @@
|
|||
|
||||
#include "GameObjectModel.h"
|
||||
#include "Log.h"
|
||||
#include "MapTree.h"
|
||||
#include "Timer.h"
|
||||
#include "VMapDefinitions.h"
|
||||
#include "VMapFactory.h"
|
||||
|
|
@ -146,6 +147,7 @@ bool GameObjectModel::initialize(std::unique_ptr<GameObjectModelOwnerBase> model
|
|||
#endif
|
||||
|
||||
owner = std::move(modelOwner);
|
||||
isWmo = it->second.isWmo;
|
||||
return true;
|
||||
}
|
||||
|
||||
|
|
@ -187,6 +189,69 @@ bool GameObjectModel::intersectRay(const G3D::Ray& ray, float& MaxDist, bool Sto
|
|||
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()
|
||||
{
|
||||
if (!iModel)
|
||||
|
|
|
|||
|
|
@ -16,6 +16,8 @@
|
|||
namespace VMAP
|
||||
{
|
||||
class WorldModel;
|
||||
struct AreaInfo;
|
||||
struct LocationInfo;
|
||||
}
|
||||
|
||||
class GameObject;
|
||||
|
|
@ -37,7 +39,7 @@ public:
|
|||
|
||||
class GameObjectModel
|
||||
{
|
||||
GameObjectModel() : phasemask(0), iInvScale(0), iScale(0), iModel(nullptr) { }
|
||||
GameObjectModel() : phasemask(0), iInvScale(0), iScale(0), iModel(nullptr), isWmo(false) { }
|
||||
|
||||
public:
|
||||
std::string name;
|
||||
|
|
@ -53,8 +55,12 @@ public:
|
|||
void enable(uint32 ph_mask) { phasemask = ph_mask; }
|
||||
|
||||
[[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;
|
||||
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);
|
||||
|
||||
|
|
@ -71,6 +77,7 @@ private:
|
|||
float iScale;
|
||||
VMAP::WorldModel* iModel;
|
||||
std::unique_ptr<GameObjectModelOwnerBase> owner;
|
||||
bool isWmo;
|
||||
};
|
||||
|
||||
void LoadGameObjectModelList(std::string const& dataPath);
|
||||
|
|
|
|||
|
|
@ -412,7 +412,6 @@ namespace VMAP
|
|||
{
|
||||
return false;
|
||||
}
|
||||
GModelRayCallback callback(triangles, vertices);
|
||||
Vector3 rPos = pos - 0.1f * down;
|
||||
float dist = G3D::inf();
|
||||
G3D::Ray ray(rPos, down);
|
||||
|
|
@ -554,6 +553,7 @@ namespace VMAP
|
|||
groupTree.intersectPoint(p, callback);
|
||||
if (callback.hit != groupModels.end())
|
||||
{
|
||||
info.rootId = RootWMOID;
|
||||
info.hitModel = &(*callback.hit);
|
||||
dist = callback.zDist;
|
||||
return true;
|
||||
|
|
|
|||
|
|
@ -531,7 +531,7 @@ void BattlefieldWG::OnCreatureCreate(Creature* creature)
|
|||
case NPC_TAUNKA_SPIRIT_GUIDE:
|
||||
{
|
||||
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
|
||||
if (creature->IsWithinDist2d(5103.0f, 3461.5f, 5.0f))
|
||||
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,
|
||||
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),
|
||||
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)));
|
||||
|
|
|
|||
|
|
@ -519,8 +519,6 @@ bool Creature::UpdateEntry(uint32 Entry, const CreatureData* data, bool changele
|
|||
SetControlled(true, UNIT_STATE_ROOT);
|
||||
}
|
||||
|
||||
UpdateEnvironmentIfNeeded(3);
|
||||
|
||||
SetDetectionDistance(cInfo->detection_range);
|
||||
|
||||
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
|
||||
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())
|
||||
{
|
||||
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;
|
||||
}
|
||||
|
||||
// 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)
|
||||
{
|
||||
case CREATURE_ELITE_RARE:
|
||||
|
|
@ -1812,6 +1817,8 @@ void Creature::setDeathState(DeathState s, bool despawn)
|
|||
if (HasUnitMovementFlag(MOVEMENTFLAG_FALLING))
|
||||
RemoveUnitMovementFlag(MOVEMENTFLAG_FALLING);
|
||||
|
||||
UpdateMovementFlags();
|
||||
|
||||
SetUInt32Value(UNIT_NPC_FLAGS, cinfo->npcflag);
|
||||
ClearUnitState(uint32(UNIT_STATE_ALL_STATE & ~(UNIT_STATE_IGNORE_PATHFINDING | UNIT_STATE_NO_ENVIRONMENT_UPD)));
|
||||
SetMeleeDamageSchool(SpellSchools(cinfo->dmgschool));
|
||||
|
|
@ -1822,8 +1829,6 @@ void Creature::setDeathState(DeathState s, bool despawn)
|
|||
LoadCreaturesAddon(true);
|
||||
if (GetCreatureData() && GetPhaseMask() != GetCreatureData()->phaseMask)
|
||||
SetPhaseMask(GetCreatureData()->phaseMask, false);
|
||||
|
||||
UpdateEnvironmentIfNeeded(3);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -2866,16 +2871,13 @@ void Creature::applyInhabitFlags()
|
|||
if (IsLevitating())
|
||||
{
|
||||
SetByteValue(UNIT_FIELD_BYTES_1, UNIT_BYTES_1_OFFSET_ANIM_TIER, UNIT_BYTE1_FLAG_FLY);
|
||||
return;
|
||||
}
|
||||
|
||||
if (IsHovering())
|
||||
else if (IsHovering())
|
||||
{
|
||||
SetByteValue(UNIT_FIELD_BYTES_1, UNIT_BYTES_1_OFFSET_ANIM_TIER, UNIT_BYTE1_FLAG_HOVER);
|
||||
return;
|
||||
}
|
||||
|
||||
SetByteValue(UNIT_FIELD_BYTES_1, UNIT_BYTES_1_OFFSET_ANIM_TIER, UNIT_BYTE1_FLAG_GROUND);
|
||||
else
|
||||
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);
|
||||
}
|
||||
|
||||
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)
|
||||
{
|
||||
Unit::SetObjectScale(scale);
|
||||
|
|
|
|||
|
|
@ -151,6 +151,8 @@ public:
|
|||
|
||||
[[nodiscard]] bool HasSpell(uint32 spellID) const override;
|
||||
|
||||
void UpdateMovementFlags();
|
||||
|
||||
bool UpdateEntry(uint32 entry, const CreatureData* data = nullptr, bool changelevel = true );
|
||||
bool UpdateStats(Stats stat) 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_TRIGGER = 0x00000080, // trigger creature
|
||||
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_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
|
||||
|
|
@ -65,8 +65,7 @@ enum CreatureFlagsExtra : uint32
|
|||
CREATURE_FLAG_EXTRA_UNUSED_32 = 0x80000000,
|
||||
|
||||
// Masks
|
||||
CREATURE_FLAG_EXTRA_UNUSED = (CREATURE_FLAG_EXTRA_UNUSED_10 | CREATURE_FLAG_EXTRA_UNUSED_12 |
|
||||
CREATURE_FLAG_EXTRA_UNUSED_25 | CREATURE_FLAG_EXTRA_UNUSED_26 |
|
||||
CREATURE_FLAG_EXTRA_UNUSED = (CREATURE_FLAG_EXTRA_UNUSED_12 | 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_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());
|
||||
|
||||
UpdatePositionData();
|
||||
|
||||
SetEntry(spellId);
|
||||
SetObjectScale(1);
|
||||
SetGuidValue(DYNAMICOBJECT_CASTER, caster->GetGUID());
|
||||
|
|
|
|||
|
|
@ -241,6 +241,8 @@ bool GameObject::Create(ObjectGuid::LowType guidlow, uint32 name_id, Map* map, u
|
|||
|
||||
SetPhaseMask(phaseMask, false);
|
||||
|
||||
UpdatePositionData();
|
||||
|
||||
SetZoneScript();
|
||||
if (m_zoneScript)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -950,8 +950,8 @@ WorldObject::WorldObject(bool isWorldObject) : WorldLocation(),
|
|||
elunaEvents(nullptr),
|
||||
#endif
|
||||
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),
|
||||
m_phaseMask(PHASEMASK_NORMAL), m_useCombinedPhases(true), m_notifyflags(0), m_executed_notifies(0)
|
||||
_zoneId(0), _areaId(0), _floorZ(INVALID_HEIGHT), _outdoors(false), _liquidData(), _updatePositionData(false), m_transport(nullptr),
|
||||
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_serverSideVisibilityDetect.SetValue(SERVERSIDE_VISIBILITY_GHOST, GHOST_VISIBILITY_ALIVE);
|
||||
|
|
@ -1040,19 +1040,51 @@ void WorldObject::_Create(ObjectGuid::LowType guidlow, HighGuid guidhigh, uint32
|
|||
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()
|
||||
|
|
@ -1470,7 +1502,7 @@ void WorldObject::UpdateAllowedPositionZ(float x, float y, float& z, float* grou
|
|||
|
||||
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
|
||||
// water level while swimming
|
||||
|
|
@ -2137,12 +2169,6 @@ void WorldObject::ResetMap()
|
|||
//m_InstanceId = 0;
|
||||
}
|
||||
|
||||
Map const* WorldObject::GetBaseMap() const
|
||||
{
|
||||
ASSERT(m_currMap);
|
||||
return m_currMap->GetParent();
|
||||
}
|
||||
|
||||
void WorldObject::AddObjectToRemoveList()
|
||||
{
|
||||
ASSERT(m_uint32Values);
|
||||
|
|
@ -2307,7 +2333,7 @@ void WorldObject::SetZoneScript()
|
|||
m_zoneScript = (ZoneScript*)map->ToInstanceMap()->GetInstanceScript();
|
||||
else if (!map->IsBattlegroundOrArena())
|
||||
{
|
||||
uint32 zoneId = GetZoneId(true);
|
||||
uint32 zoneId = GetZoneId();
|
||||
if (Battlefield* bf = sBattlefieldMgr->GetBattlefieldToZoneId(zoneId))
|
||||
m_zoneScript = bf;
|
||||
else
|
||||
|
|
@ -3031,10 +3057,54 @@ float WorldObject::GetMapWaterOrGroundLevel(float x, float y, float z, float* gr
|
|||
|
||||
float WorldObject::GetFloorZ() const
|
||||
{
|
||||
if (!IsInWorld())
|
||||
return m_staticFloorZ;
|
||||
if (_updatePositionData)
|
||||
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)
|
||||
|
|
|
|||
|
|
@ -69,6 +69,8 @@ class Transport;
|
|||
class StaticTransport;
|
||||
class MotionTransport;
|
||||
|
||||
struct PositionFullTerrainStatus;
|
||||
|
||||
typedef std::unordered_map<Player*, UpdateData> UpdateDataMapType;
|
||||
typedef GuidUnorderedSet UpdatePlayerSet;
|
||||
|
||||
|
|
@ -750,15 +752,8 @@ public:
|
|||
#endif
|
||||
void _Create(ObjectGuid::LowType guidlow, HighGuid guidhigh, uint32 phaseMask);
|
||||
|
||||
void RemoveFromWorld() override
|
||||
{
|
||||
if (!IsInWorld())
|
||||
return;
|
||||
|
||||
DestroyForNearbyPlayers();
|
||||
|
||||
Object::RemoveFromWorld();
|
||||
}
|
||||
void AddToWorld() override;
|
||||
void RemoveFromWorld() override;
|
||||
|
||||
#ifdef ELUNA
|
||||
ElunaEventProcessor* elunaEvents;
|
||||
|
|
@ -817,9 +812,11 @@ public:
|
|||
bool InSamePhase(WorldObject const* obj) const { return InSamePhase(obj->GetPhaseMask()); }
|
||||
[[nodiscard]] bool InSamePhase(uint32 phasemask) const { return m_useCombinedPhases ? GetPhaseMask() & phasemask : GetPhaseMask() == phasemask; }
|
||||
|
||||
[[nodiscard]] virtual uint32 GetZoneId(bool forceRecalc = false) const;
|
||||
[[nodiscard]] virtual uint32 GetAreaId(bool forceRecalc = false) const;
|
||||
virtual void GetZoneAndAreaId(uint32& zoneid, uint32& areaid, bool forceRecalc = false) const;
|
||||
[[nodiscard]] uint32 GetZoneId() const;
|
||||
[[nodiscard]] uint32 GetAreaId() const;
|
||||
void GetZoneAndAreaId(uint32& zoneid, uint32& areaid) const;
|
||||
[[nodiscard]] bool IsOutdoors() const;
|
||||
LiquidData const& GetLiquidData() const;
|
||||
|
||||
InstanceScript* GetInstanceScript();
|
||||
|
||||
|
|
@ -948,9 +945,6 @@ public:
|
|||
[[nodiscard]] Map* FindMap() const { return m_currMap; }
|
||||
//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 ClearZoneScript();
|
||||
[[nodiscard]] ZoneScript* GetZoneScript() const { return m_zoneScript; }
|
||||
|
|
@ -984,6 +978,9 @@ public:
|
|||
void BuildUpdate(UpdateDataMapType& data_map, UpdatePlayerSet& player_set) override;
|
||||
void GetCreaturesWithEntryInRange(std::list<Creature*>& creatureList, float radius, uint32 entry);
|
||||
|
||||
void SetPositionDataUpdate();
|
||||
void UpdatePositionData();
|
||||
|
||||
void AddToObjectUpdate() override;
|
||||
void RemoveFromObjectUpdate() override;
|
||||
|
||||
|
|
@ -1060,7 +1057,13 @@ protected:
|
|||
const bool m_isWorldObject;
|
||||
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
|
||||
Transport* m_transport;
|
||||
|
|
|
|||
|
|
@ -666,6 +666,8 @@ bool Pet::CreateBaseAtCreature(Creature* creature)
|
|||
|
||||
SetDisplayId(creature->GetDisplayId());
|
||||
|
||||
UpdatePositionData();
|
||||
|
||||
if (CreatureFamilyEntry const* cFamily = sCreatureFamilyStore.LookupEntry(cinfo->family))
|
||||
SetName(cFamily->Name[sWorld->GetDefaultDbcLocale()]);
|
||||
else
|
||||
|
|
@ -684,6 +686,8 @@ bool Pet::CreateBaseAtCreatureInfo(CreatureTemplate const* cinfo, Unit* owner)
|
|||
|
||||
Relocate(owner->GetPositionX(), owner->GetPositionY(), owner->GetPositionZ(), owner->GetOrientation());
|
||||
|
||||
UpdatePositionData();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -591,6 +591,8 @@ bool Player::Create(ObjectGuid::LowType guidlow, CharacterCreateInfo* createInfo
|
|||
InitTalentForLevel();
|
||||
InitPrimaryProfessions(); // to max set before any spell added
|
||||
|
||||
UpdatePositionData();
|
||||
|
||||
// apply original stats mods before spell loading or item equipment that call before equip _RemoveStatsMods()
|
||||
UpdateMaxHealth(); // Update max Health (for add bonus from stamina)
|
||||
SetFullHealth();
|
||||
|
|
@ -876,7 +878,7 @@ void Player::HandleDrowning(uint32 time_diff)
|
|||
}
|
||||
|
||||
// In dark water
|
||||
if (m_MirrorTimerFlags & UNDERWARER_INDARKWATER)
|
||||
if (m_MirrorTimerFlags & UNDERWATER_INDARKWATER)
|
||||
{
|
||||
// Fatigue timer not activated - activate it
|
||||
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
|
||||
RepopAtGraveyard();
|
||||
}
|
||||
else if (!(m_MirrorTimerFlagsLast & UNDERWARER_INDARKWATER))
|
||||
else if (!(m_MirrorTimerFlagsLast & UNDERWATER_INDARKWATER))
|
||||
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;
|
||||
if (m_MirrorTimer[FATIGUE_TIMER] >= DarkWaterTime || !IsAlive())
|
||||
StopMirrorTimer(FATIGUE_TIMER);
|
||||
else if (m_MirrorTimerFlagsLast & UNDERWARER_INDARKWATER)
|
||||
else if (m_MirrorTimerFlagsLast & UNDERWATER_INDARKWATER)
|
||||
SendMirrorTimer(FATIGUE_TIMER, DarkWaterTime, m_MirrorTimer[FATIGUE_TIMER], 10);
|
||||
}
|
||||
|
||||
|
|
@ -2066,31 +2068,6 @@ GameObject* Player::GetGameObjectIfCanInteractWith(ObjectGuid guid, GameobjectTy
|
|||
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
|
||||
{
|
||||
// Xinef: Added !IsInFlight check
|
||||
|
|
@ -4355,7 +4332,7 @@ void Player::ResurrectPlayer(float restore_percent, bool applySickness)
|
|||
|
||||
// trigger update zone for alive state zone updates
|
||||
uint32 newzone, newarea;
|
||||
GetZoneAndAreaId(newzone, newarea, true);
|
||||
GetZoneAndAreaId(newzone, newarea);
|
||||
UpdateZone(newzone, newarea);
|
||||
sOutdoorPvPMgr->HandlePlayerResurrects(this, newzone);
|
||||
|
||||
|
|
@ -4508,6 +4485,8 @@ Corpse* Player::CreateCorpse()
|
|||
// register for player, but not show
|
||||
GetMap()->AddCorpse(corpse);
|
||||
|
||||
UpdatePositionData();
|
||||
|
||||
// we do not need to save corpses for BG/arenas
|
||||
if (!GetMap()->IsBattlegroundOrArena())
|
||||
corpse->SaveToDB();
|
||||
|
|
@ -5563,7 +5542,7 @@ void Player::CheckAreaExploreAndOutdoor()
|
|||
return;
|
||||
|
||||
bool isOutdoor = IsOutdoors();
|
||||
uint32 areaId = GetBaseMap()->GetAreaId(GetPositionX(), GetPositionY(), GetPositionZ(), &isOutdoor);
|
||||
uint32 areaId = GetAreaId();
|
||||
AreaTableEntry const* areaEntry = sAreaTableStore.LookupEntry(areaId);
|
||||
|
||||
if (sWorld->getBoolConfig(CONFIG_VMAP_INDOOR_CHECK) && !isOutdoor)
|
||||
|
|
@ -6159,7 +6138,7 @@ uint32 Player::GetZoneIdFromDB(ObjectGuid guid)
|
|||
if (!sMapStore.LookupEntry(map))
|
||||
return 0;
|
||||
|
||||
zone = sMapMgr->GetZoneId(map, posx, posy, posz);
|
||||
zone = sMapMgr->GetZoneId(PHASEMASK_NORMAL, map, posx, posy, posz);
|
||||
|
||||
if (zone > 0)
|
||||
{
|
||||
|
|
@ -6184,36 +6163,6 @@ uint32 Player::GetLevelFromStorage(ObjectGuid::LowType guid)
|
|||
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
|
||||
void Player::CheckDuelDistance(time_t currTime)
|
||||
{
|
||||
|
|
@ -10849,7 +10798,7 @@ void Player::SendInitialPacketsAfterAddToMap()
|
|||
|
||||
// update zone
|
||||
uint32 newzone, newarea;
|
||||
GetZoneAndAreaId(newzone, newarea, true);
|
||||
GetZoneAndAreaId(newzone, newarea);
|
||||
UpdateZone(newzone, newarea); // also call SendInitWorldStates();
|
||||
|
||||
if (HasAuraType(SPELL_AURA_MOD_STUN))
|
||||
|
|
@ -13758,7 +13707,7 @@ void Player::_SaveCharacter(bool create, CharacterDatabaseTransaction trans)
|
|||
stmt->setUInt16(index++, (uint16)m_ExtraFlags);
|
||||
stmt->setUInt8(index++, m_stableSlots);
|
||||
stmt->setUInt16(index++, (uint16)m_atLoginFlags);
|
||||
stmt->setUInt16(index++, GetZoneId(true));
|
||||
stmt->setUInt16(index++, GetZoneId());
|
||||
stmt->setUInt32(index++, uint32(m_deathExpireTime));
|
||||
|
||||
ss.str("");
|
||||
|
|
@ -13896,7 +13845,7 @@ void Player::_SaveCharacter(bool create, CharacterDatabaseTransaction trans)
|
|||
stmt->setUInt16(index++, (uint16)m_ExtraFlags);
|
||||
stmt->setUInt8(index++, m_stableSlots);
|
||||
stmt->setUInt16(index++, (uint16)m_atLoginFlags);
|
||||
stmt->setUInt16(index++, GetZoneId(true));
|
||||
stmt->setUInt16(index++, GetZoneId());
|
||||
stmt->setUInt32(index++, uint32(m_deathExpireTime));
|
||||
|
||||
ss.str("");
|
||||
|
|
|
|||
|
|
@ -85,7 +85,7 @@ enum PlayerUnderwaterState
|
|||
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_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
|
||||
};
|
||||
|
|
@ -1021,8 +1021,7 @@ public:
|
|||
|
||||
void SetInWater(bool apply);
|
||||
|
||||
[[nodiscard]] bool IsInWater(bool allowAbove = false) const override;
|
||||
[[nodiscard]] bool IsUnderWater() const override;
|
||||
[[nodiscard]] bool IsInWater() const override { return m_isInWater; }
|
||||
[[nodiscard]] bool IsFalling() const;
|
||||
bool IsInAreaTriggerRadius(const AreaTrigger* trigger) const;
|
||||
|
||||
|
|
@ -1737,10 +1736,6 @@ public:
|
|||
void UpdateZone(uint32 newZone, 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 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(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 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);
|
||||
StoreRaidMapDifficulty();
|
||||
|
||||
UpdatePositionData();
|
||||
|
||||
SaveRecallPosition();
|
||||
|
||||
time_t now = time(nullptr);
|
||||
|
|
@ -5772,7 +5774,7 @@ void Player::_LoadInventory(PreparedQueryResult result, uint32 timeDiff)
|
|||
|
||||
if (result)
|
||||
{
|
||||
uint32 zoneId = GetZoneId(true);
|
||||
uint32 zoneId = GetZoneId();
|
||||
|
||||
std::map<ObjectGuid::LowType, Bag*> bagMap; // 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;
|
||||
GetZoneAndAreaId(newzone, newarea, true);
|
||||
m_last_zone_id = newzone;
|
||||
m_last_area_id = newarea;
|
||||
GetZoneAndAreaId(newzone, newarea);
|
||||
|
||||
if (m_zoneUpdateId != newzone)
|
||||
UpdateZone(newzone, newarea); // also update area
|
||||
|
|
@ -354,7 +352,7 @@ void Player::Update(uint32 p_time)
|
|||
}
|
||||
|
||||
// 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))
|
||||
{
|
||||
if (p_time >= m_deathTimer)
|
||||
|
|
@ -1975,96 +1973,6 @@ void Player::UpdateCorpseReclaimDelay()
|
|||
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()
|
||||
{
|
||||
// Xinef: maybe passed as argument?
|
||||
|
|
@ -2361,3 +2269,58 @@ void Player::SendUpdateWorldState(uint32 Field, uint32 Value)
|
|||
data << Value;
|
||||
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);
|
||||
|
||||
m_model = CreateModel();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
|
@ -676,6 +677,8 @@ bool StaticTransport::Create(ObjectGuid::LowType guidlow, uint32 name_id, Map* m
|
|||
|
||||
SetPhaseMask(phaseMask, false);
|
||||
|
||||
UpdatePositionData();
|
||||
|
||||
SetZoneScript();
|
||||
if (m_zoneScript)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -284,18 +284,6 @@ Unit::Unit(bool isWorldObject) : WorldObject(isWorldObject),
|
|||
m_delayed_unit_relocation_timer = 0;
|
||||
m_delayed_unit_ai_notify_timer = 0;
|
||||
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;
|
||||
_instantCast = false;
|
||||
|
|
@ -528,8 +516,13 @@ void Unit::UpdateSplineMovement(uint32 t_diff)
|
|||
bool arrived = movespline->Finalized();
|
||||
|
||||
if (arrived)
|
||||
{
|
||||
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
|
||||
//m_movesplineTimer.Update(t_diff);
|
||||
//if (m_movesplineTimer.Passed() || arrived)
|
||||
|
|
@ -3636,230 +3629,48 @@ bool Unit::isInAccessiblePlaceFor(Creature const* c) const
|
|||
if (IsInWater())
|
||||
return IsUnderWater() ? c->CanEnterWater() : (c->CanEnterWater() || c->CanFly());
|
||||
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;
|
||||
|
||||
if (GetTypeId() != TYPEID_UNIT || !IsAlive() || (!IsInWorld() && option != 3) || !FindMap() || IsDuringRemoveFromWorld() || !IsPositionValid())
|
||||
return;
|
||||
LiquidData const& liquidData = GetLiquidData();
|
||||
|
||||
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)
|
||||
m_last_environment_position.Relocate(-5000.0f, -5000.0f, -5000.0f, 0.0f);
|
||||
return;
|
||||
if (_lastLiquid && _lastLiquid->SpellId)
|
||||
RemoveAurasDueToSpell(_lastLiquid->SpellId);
|
||||
|
||||
// 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()
|
||||
|
|
@ -3906,20 +3717,14 @@ void Unit::HandleSafeUnitPointersOnDelete(Unit* thisUnit)
|
|||
thisUnit->SafeUnitPointerSet.clear();
|
||||
}
|
||||
|
||||
bool Unit::IsInWater(bool allowAbove) const
|
||||
bool Unit::IsInWater() const
|
||||
{
|
||||
const_cast<Unit*>(this)->UpdateEnvironmentIfNeeded(1);
|
||||
return m_last_isinwater_status || (allowAbove && m_last_islittleabovewater_status);
|
||||
return (GetLiquidData().Status & MAP_LIQUID_STATUS_SWIMMING) != 0;
|
||||
}
|
||||
|
||||
bool Unit::IsUnderWater() const
|
||||
{
|
||||
const_cast<Unit*>(this)->UpdateEnvironmentIfNeeded(1);
|
||||
return m_last_isunderwater_status;
|
||||
}
|
||||
|
||||
void Unit::UpdateUnderwaterState(Map* /*m*/, float /*x*/, float /*y*/, float /*z*/)
|
||||
{
|
||||
return GetLiquidData().Status == LIQUID_MAP_UNDER_WATER;
|
||||
}
|
||||
|
||||
void Unit::DeMorph()
|
||||
|
|
@ -12996,8 +12801,6 @@ void Unit::SetInCombatState(bool PvP, Unit* enemy, uint32 duration)
|
|||
|
||||
if (Creature* creature = ToCreature())
|
||||
{
|
||||
creature->UpdateEnvironmentIfNeeded(2);
|
||||
|
||||
// Set home position at place of engaging combat for escorted creatures
|
||||
if ((IsAIEnabled && creature->AI()->IsEscorted()) ||
|
||||
GetMotionMaster()->GetCurrentMovementGeneratorType() == WAYPOINT_MOTION_TYPE ||
|
||||
|
|
@ -19584,62 +19387,6 @@ bool ConflagrateAuraStateDelayEvent::Execute(uint64 /*e_time*/, uint32 /*p_time
|
|||
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()
|
||||
{
|
||||
this->RemoveFromNotify(NOTIFY_VISIBILITY_CHANGED);
|
||||
|
|
|
|||
|
|
@ -1772,10 +1772,8 @@ public:
|
|||
bool IsValidAssistTarget(Unit const* target) const;
|
||||
bool _IsValidAssistTarget(Unit const* target, SpellInfo const* bySpell) const;
|
||||
|
||||
void UpdateEnvironmentIfNeeded(const uint8 option);
|
||||
[[nodiscard]] virtual bool IsInWater(bool allowAbove = false) const;
|
||||
[[nodiscard]] virtual bool IsInWater() const;
|
||||
[[nodiscard]] virtual bool IsUnderWater() const;
|
||||
virtual void UpdateUnderwaterState(Map* m, float x, float y, float z);
|
||||
bool isInAccessiblePlaceFor(Creature const* c) const;
|
||||
|
||||
void SendHealSpellLog(Unit* victim, uint32 SpellID, uint32 Damage, uint32 OverHeal, uint32 Absorb, bool critical = false);
|
||||
|
|
@ -2454,25 +2452,6 @@ public:
|
|||
bool bRequestForcedVisibilityUpdate;
|
||||
void ExecuteDelayedUnitRelocationEvent();
|
||||
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
|
||||
[[nodiscard]] virtual bool HasSpellCooldown(uint32 /*spell_id*/) const { return false; }
|
||||
|
|
@ -2503,6 +2482,9 @@ public:
|
|||
[[nodiscard]] float GetCollisionWidth() const override;
|
||||
[[nodiscard]] float GetCollisionRadius() const override;
|
||||
|
||||
void ProcessPositionDataChanged(PositionFullTerrainStatus const& data) override;
|
||||
virtual void ProcessTerrainStatusUpdate();
|
||||
|
||||
protected:
|
||||
explicit Unit (bool isWorldObject);
|
||||
|
||||
|
|
|
|||
|
|
@ -1955,8 +1955,8 @@ void ObjectMgr::LoadCreatures()
|
|||
|
||||
if (sWorld->getBoolConfig(CONFIG_CALCULATE_CREATURE_ZONE_AREA_DATA))
|
||||
{
|
||||
uint32 zoneId = sMapMgr->GetZoneId(data.mapid, data.posX, data.posY, data.posZ);
|
||||
uint32 areaId = sMapMgr->GetAreaId(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.phaseMask, data.mapid, data.posX, data.posY, data.posZ);
|
||||
|
||||
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))
|
||||
{
|
||||
uint32 zoneId = sMapMgr->GetZoneId(data.mapid, data.posX, data.posY, data.posZ);
|
||||
uint32 areaId = sMapMgr->GetAreaId(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.phaseMask, data.mapid, data.posX, data.posY, data.posZ);
|
||||
|
||||
WorldDatabasePreparedStatement* stmt = WorldDatabase.GetPreparedStatement(WORLD_UPD_GAMEOBJECT_ZONE_AREA_DATA);
|
||||
|
||||
|
|
|
|||
|
|
@ -1135,7 +1135,7 @@ void WorldSession::HandlePlayerLoginToCharInWorld(Player* pCurrChar)
|
|||
pCurrChar->CleanupChannels();
|
||||
pCurrChar->SendInitialPacketsAfterAddToMap();
|
||||
uint32 currZone, currArea;
|
||||
pCurrChar->GetZoneAndAreaId(currZone, currArea, false);
|
||||
pCurrChar->GetZoneAndAreaId(currZone, currArea);
|
||||
pCurrChar->SendInitWorldStates(currZone, currArea);
|
||||
pCurrChar->SetInGameTime(World::GetGameTimeMS());
|
||||
|
||||
|
|
|
|||
|
|
@ -511,7 +511,7 @@ void WorldSession::HandleZoneUpdateOpcode(WorldPacket& recv_data)
|
|||
|
||||
// use server size data
|
||||
uint32 newzone, newarea;
|
||||
GetPlayer()->GetZoneAndAreaId(newzone, newarea, true);
|
||||
GetPlayer()->GetZoneAndAreaId(newzone, newarea);
|
||||
GetPlayer()->UpdateZone(newzone, newarea);
|
||||
//GetPlayer()->SendInitWorldStates(true, newZone);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -90,6 +90,8 @@ void WorldSession::HandleMoveWorldportAck()
|
|||
GetPlayer()->ResetMap();
|
||||
GetPlayer()->SetMap(newMap);
|
||||
|
||||
GetPlayer()->UpdatePositionData();
|
||||
|
||||
GetPlayer()->SendInitialPacketsBeforeAddToMap();
|
||||
if (!GetPlayer()->GetMap()->AddPlayerToMap(GetPlayer()))
|
||||
{
|
||||
|
|
@ -216,7 +218,7 @@ void WorldSession::HandleMoveWorldportAck()
|
|||
|
||||
// update zone immediately, otherwise leave channel will cause crash in mtmap
|
||||
uint32 newzone, newarea;
|
||||
GetPlayer()->GetZoneAndAreaId(newzone, newarea, true);
|
||||
GetPlayer()->GetZoneAndAreaId(newzone, newarea);
|
||||
GetPlayer()->UpdateZone(newzone, newarea);
|
||||
|
||||
// honorless target
|
||||
|
|
@ -273,7 +275,7 @@ void WorldSession::HandleMoveTeleportAck(WorldPacket& recvData)
|
|||
if (oldPos.GetExactDist2d(plMover) > 100.0f)
|
||||
{
|
||||
uint32 newzone, newarea;
|
||||
plMover->GetZoneAndAreaId(newzone, newarea, true);
|
||||
plMover->GetZoneAndAreaId(newzone, newarea);
|
||||
plMover->UpdateZone(newzone, newarea);
|
||||
|
||||
// new zone
|
||||
|
|
@ -482,7 +484,8 @@ void WorldSession::HandleMovementOpcodes(WorldPacket& recvData)
|
|||
if (plrMover && ((movementInfo.flags & MOVEMENTFLAG_SWIMMING) != 0) != plrMover->IsInWater())
|
||||
{
|
||||
// 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;
|
||||
|
|
|
|||
|
|
@ -175,6 +175,7 @@ uint8 WorldSession::HandleLoadPetFromDBFirstCallback(PreparedQueryResult result,
|
|||
|
||||
if (pet->IsCritter())
|
||||
{
|
||||
pet->UpdatePositionData();
|
||||
map->AddToMap(pet->ToCreature(), true);
|
||||
pet->SetLoading(false); // xinef, mine
|
||||
return PET_LOAD_OK;
|
||||
|
|
@ -186,6 +187,7 @@ uint8 WorldSession::HandleLoadPetFromDBFirstCallback(PreparedQueryResult result,
|
|||
pet->GetCharmInfo()->SetPetNumber(pet_number, false);
|
||||
|
||||
pet->SetDisplayId(fields[3].GetUInt32());
|
||||
pet->UpdatePositionData();
|
||||
pet->SetNativeDisplayId(fields[3].GetUInt32());
|
||||
pet->SetUInt32Value(UNIT_NPC_FLAGS, UNIT_NPC_FLAG_NONE);
|
||||
pet->SetName(fields[8].GetString());
|
||||
|
|
|
|||
|
|
@ -43,6 +43,9 @@ u_map_magic MapAreaMagic = { {'A', 'R', 'E', 'A'} };
|
|||
u_map_magic MapHeightMagic = { {'M', 'H', 'G', 'T'} };
|
||||
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()
|
||||
{
|
||||
// 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);
|
||||
if (player->IsVehicle())
|
||||
player->GetVehicleKit()->RelocatePassengers();
|
||||
|
||||
player->UpdatePositionData();
|
||||
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);
|
||||
if (creature->IsVehicle())
|
||||
creature->GetVehicleKit()->RelocatePassengers();
|
||||
|
||||
creature->UpdatePositionData();
|
||||
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->UpdateModelPosition();
|
||||
|
||||
go->SetPositionDataUpdate();
|
||||
go->UpdateObjectVisibility(false);
|
||||
}
|
||||
|
||||
|
|
@ -1043,7 +1046,7 @@ void Map::DynamicObjectRelocation(DynamicObject* dynObj, float x, float y, float
|
|||
RemoveDynamicObjectFromMoveList(dynObj);
|
||||
|
||||
dynObj->Relocate(x, y, z, o);
|
||||
|
||||
dynObj->SetPositionDataUpdate();
|
||||
dynObj->UpdateObjectVisibility(false);
|
||||
}
|
||||
|
||||
|
|
@ -1307,6 +1310,7 @@ GridMap::GridMap()
|
|||
_liquidEntry = nullptr;
|
||||
_liquidFlags = nullptr;
|
||||
_liquidMap = nullptr;
|
||||
_holes = nullptr;
|
||||
}
|
||||
|
||||
GridMap::~GridMap()
|
||||
|
|
@ -1354,6 +1358,13 @@ bool GridMap::loadData(char* filename)
|
|||
fclose(in);
|
||||
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);
|
||||
return true;
|
||||
}
|
||||
|
|
@ -1372,6 +1383,7 @@ void GridMap::unloadData()
|
|||
delete[] _liquidEntry;
|
||||
delete[] _liquidFlags;
|
||||
delete[] _liquidMap;
|
||||
delete[] _holes;
|
||||
_areaMap = nullptr;
|
||||
m_V9 = nullptr;
|
||||
m_V8 = nullptr;
|
||||
|
|
@ -1380,6 +1392,7 @@ void GridMap::unloadData()
|
|||
_liquidEntry = nullptr;
|
||||
_liquidFlags = nullptr;
|
||||
_liquidMap = nullptr;
|
||||
_holes = nullptr;
|
||||
_gridGetHeight = &GridMap::getHeightFromFlat;
|
||||
}
|
||||
|
||||
|
|
@ -1491,6 +1504,18 @@ bool GridMap::loadLiquidData(FILE* in, uint32 offset, uint32 /*size*/)
|
|||
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
|
||||
{
|
||||
if (!_areaMap)
|
||||
|
|
@ -1523,6 +1548,9 @@ float GridMap::getHeightFromFloat(float x, float y) const
|
|||
x_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
|
||||
// +--------------> X
|
||||
// | h1-------h2 Coordinates is:
|
||||
|
|
@ -1605,6 +1633,9 @@ float GridMap::getHeightFromUint8(float x, float y) const
|
|||
x_int &= (MAP_RESOLUTION - 1);
|
||||
y_int &= (MAP_RESOLUTION - 1);
|
||||
|
||||
if (isHole(x_int, y_int))
|
||||
return INVALID_HEIGHT;
|
||||
|
||||
int32 a, b, c;
|
||||
uint8* V9_h1_ptr = &m_uint8_V9[x_int * 128 + x_int + y_int];
|
||||
if (x + y < 1)
|
||||
|
|
@ -1672,6 +1703,9 @@ float GridMap::getHeightFromUint16(float x, float y) const
|
|||
x_int &= (MAP_RESOLUTION - 1);
|
||||
y_int &= (MAP_RESOLUTION - 1);
|
||||
|
||||
if (isHole(x_int, y_int))
|
||||
return INVALID_HEIGHT;
|
||||
|
||||
int32 a, b, c;
|
||||
uint16* V9_h1_ptr = &m_uint16_V9[x_int * 128 + x_int + y_int];
|
||||
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;
|
||||
}
|
||||
|
||||
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
|
||||
{
|
||||
if (!_minHeight)
|
||||
|
|
@ -1803,113 +1852,96 @@ float GridMap::getLiquidLevel(float x, float y) const
|
|||
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
|
||||
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)
|
||||
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 (_liquidType || _liquidFlags)
|
||||
{
|
||||
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)))
|
||||
{
|
||||
uint32 overrideLiquid = area->LiquidTypeOverride[liquidEntry->Type];
|
||||
if (!overrideLiquid && area->zone)
|
||||
{
|
||||
area = sAreaTableStore.LookupEntry(area->zone);
|
||||
if (area)
|
||||
overrideLiquid = area->LiquidTypeOverride[liquidEntry->Type];
|
||||
}
|
||||
// Get cell
|
||||
float cx = MAP_RESOLUTION * (32 - x / SIZE_OF_GRIDS);
|
||||
float cy = MAP_RESOLUTION * (32 - y / SIZE_OF_GRIDS);
|
||||
|
||||
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;
|
||||
liqTypeIdx = liq->Type;
|
||||
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))
|
||||
{
|
||||
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 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;
|
||||
return liquidData;
|
||||
}
|
||||
|
||||
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)
|
||||
*ground = ground_z;
|
||||
|
||||
LiquidData liquid_status;
|
||||
|
||||
ZLiquidStatus res = getLiquidStatus(x, y, ground_z, MAP_ALL_LIQUIDS, &liquid_status, collisionHeight);
|
||||
switch (res)
|
||||
LiquidData const& liquidData = const_cast<Map*>(this)->GetLiquidData(phasemask, x, y, ground_z, collisionHeight, MAP_ALL_LIQUIDS);
|
||||
switch (liquidData.Status)
|
||||
{
|
||||
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:
|
||||
return ground_z;
|
||||
default:
|
||||
return liquid_status.level;
|
||||
return liquidData.Level;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -2030,115 +2060,99 @@ float Map::GetMinHeight(float x, float y) const
|
|||
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;
|
||||
|
||||
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;
|
||||
return (mogpFlags & 0x2000) != 0;
|
||||
}
|
||||
|
||||
bool Map::IsOutdoors(float x, float y, float z) 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
|
||||
bool Map::GetAreaInfo(uint32 phaseMask, float x, float y, float z, uint32& flags, int32& adtId, int32& rootId, int32& groupId) const
|
||||
{
|
||||
float vmap_z = z;
|
||||
float dynamic_z = z;
|
||||
float check_z = z;
|
||||
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
|
||||
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...
|
||||
if (z + 2.0f > _mapheight && _mapheight > vmap_z)
|
||||
if (z + 2.0f > mapHeight && mapHeight > check_z)
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
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;
|
||||
int32 adtId, rootId, groupId;
|
||||
WMOAreaTableEntry const* wmoEntry = 0;
|
||||
AreaTableEntry const* atEntry = 0;
|
||||
bool haveAreaInfo = false;
|
||||
float vmapZ = 0.f;
|
||||
bool hasVmapArea = GetAreaInfo(phaseMask, x, y, vmapZ, mogpFlags, adtId, rootId, groupId);
|
||||
|
||||
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;
|
||||
wmoEntry = GetWMOAreaTableEntryByTripple(rootId, adtId, groupId);
|
||||
if (wmoEntry)
|
||||
atEntry = sAreaTableStore.LookupEntry(wmoEntry->areaId);
|
||||
gridAreaId = gmap->getArea(x, y);
|
||||
gridMapHeight = gmap->getHeight(x, y);
|
||||
}
|
||||
|
||||
uint16 areaId = 0;
|
||||
|
||||
if (atEntry)
|
||||
areaId = atEntry->ID;
|
||||
else
|
||||
// floor is the height we are closer to (but only if above)
|
||||
if (hasVmapArea && G3D::fuzzyGe(z, vmapZ - GROUND_HEIGHT_TOLERANCE) && (G3D::fuzzyLt(z, gridMapHeight - GROUND_HEIGHT_TOLERANCE) || vmapZ > gridMapHeight))
|
||||
{
|
||||
if (GridMap* gmap = const_cast<Map*>(this)->GetGrid(x, y))
|
||||
areaId = gmap->getArea(x, y);
|
||||
// this used while not all *.map files generated (instances)
|
||||
if (!areaId)
|
||||
areaId = i_mapEntry->linked_zone;
|
||||
}
|
||||
// wmo found
|
||||
if (WMOAreaTableEntry const* wmoEntry = GetWMOAreaTableEntryByTripple(rootId, adtId, groupId))
|
||||
areaId = wmoEntry->areaId;
|
||||
|
||||
if (isOutdoors)
|
||||
{
|
||||
if (haveAreaInfo)
|
||||
*isOutdoors = IsOutdoorWMO(mogpFlags, adtId, rootId, groupId, wmoEntry, atEntry);
|
||||
else
|
||||
*isOutdoors = true;
|
||||
if (!areaId)
|
||||
areaId = gridAreaId;
|
||||
}
|
||||
else
|
||||
areaId = gridAreaId;
|
||||
|
||||
if (!areaId)
|
||||
areaId = i_mapEntry->linked_zone;
|
||||
|
||||
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 Map::GetZoneId(float x, float y, float z) const
|
||||
{
|
||||
uint32 areaId = GetAreaId(x, y, z);
|
||||
uint32 areaId = GetAreaId(phaseMask, x, y, z);
|
||||
if (AreaTableEntry const* area = sAreaTableStore.LookupEntry(areaId))
|
||||
if (area->zone)
|
||||
return area->zone;
|
||||
|
|
@ -2146,105 +2160,239 @@ uint32 Map::GetZoneId(float x, float y, float z) const
|
|||
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 (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))
|
||||
return gmap->getTerrainType(x, y);
|
||||
else
|
||||
return 0;
|
||||
}
|
||||
LiquidData liquidData;
|
||||
|
||||
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();
|
||||
float liquid_level = INVALID_HEIGHT;
|
||||
float ground_level = INVALID_HEIGHT;
|
||||
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
|
||||
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
|
||||
if (data)
|
||||
// hardcoded in client like this
|
||||
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 (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(phaseMask, x, y, z)))
|
||||
{
|
||||
if (AreaTableEntry const* area = sAreaTableStore.LookupEntry(GetAreaId(x, y, z)))
|
||||
uint32 overrideLiquid = area->LiquidTypeOverride[liquidFlagType];
|
||||
if (!overrideLiquid && area->zone)
|
||||
{
|
||||
uint32 overrideLiquid = area->LiquidTypeOverride[liquidFlagType];
|
||||
if (!overrideLiquid && area->zone)
|
||||
{
|
||||
area = sAreaTableStore.LookupEntry(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))
|
||||
{
|
||||
liquid_type = overrideLiquid;
|
||||
liquidFlagType = liq->Type;
|
||||
}
|
||||
if (LiquidTypeEntry const* liq = sLiquidTypeStore.LookupEntry(overrideLiquid))
|
||||
{
|
||||
liquid_type = overrideLiquid;
|
||||
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;
|
||||
|
||||
// Get position delta
|
||||
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;
|
||||
result = LIQUID_MAP_ABOVE_WATER;
|
||||
liquidData.Level = liquid_level;
|
||||
liquidData.DepthLevel = ground_level;
|
||||
liquidData.Entry = liquid_type;
|
||||
liquidData.Flags = 1 << liquidFlagType;
|
||||
}
|
||||
|
||||
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;
|
||||
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 (GridMap* gmap = const_cast<Map*>(this)->GetGrid(x, y))
|
||||
{
|
||||
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
|
||||
if (GetId() == 530 && map_data.entry == 2)
|
||||
map_data.entry = 15;
|
||||
uint32 liquidEntry = map_data.Entry;
|
||||
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
|
||||
|
|
@ -2288,30 +2436,28 @@ float Map::GetHeight(uint32 phasemask, float x, float y, float z, bool vmap/*=tr
|
|||
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* liquid_ptr = data ? data : &liquid_status;
|
||||
return getLiquidStatus(x, y, pZ, MAP_ALL_LIQUIDS, liquid_ptr) & (LIQUID_MAP_IN_WATER | LIQUID_MAP_UNDER_WATER);
|
||||
LiquidData const& liquidData = const_cast<Map*>(this)->GetLiquidData(phaseMask, x, y, pZ, collisionHeight, MAP_ALL_LIQUIDS);
|
||||
return (liquidData.Status & MAP_LIQUID_STATUS_SWIMMING) != 0;
|
||||
}
|
||||
|
||||
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
|
||||
{
|
||||
LiquidData liquidData;
|
||||
liquidData.level = INVALID_HEIGHT;
|
||||
ZLiquidStatus liquidStatus = getLiquidStatus(x, y, z, MAP_ALL_LIQUIDS, &liquidData);
|
||||
return (liquidStatus & (LIQUID_MAP_IN_WATER | LIQUID_MAP_UNDER_WATER)) && HasEnoughWater(searcher, liquidData);
|
||||
LiquidData const& liquidData = const_cast<Map*>(this)->GetLiquidData(searcher->GetPhaseMask(), x, y, z, searcher->GetCollisionHeight(), MAP_ALL_LIQUIDS);
|
||||
return (liquidData.Status & MAP_LIQUID_STATUS_SWIMMING) != 0 && 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();
|
||||
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
|
||||
|
|
@ -3421,6 +3567,8 @@ Corpse* Map::ConvertCorpseToBones(ObjectGuid const ownerGuid, bool insignia /*=
|
|||
|
||||
AddCorpse(bones);
|
||||
|
||||
bones->UpdatePositionData();
|
||||
|
||||
// add bones in grid store if grid loaded where corpse placed
|
||||
AddToMap(bones);
|
||||
}
|
||||
|
|
@ -3459,7 +3607,7 @@ void Map::RemoveOldCorpses()
|
|||
|
||||
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);
|
||||
if (itr == _zoneDynamicInfo.end())
|
||||
return;
|
||||
|
|
@ -3671,7 +3819,7 @@ bool Map::CheckCollisionAndGetValidCoords(const WorldObject* source, float start
|
|||
return false;
|
||||
}
|
||||
|
||||
bool isWaterNext = IsInWater(destX, destY, destZ);
|
||||
bool isWaterNext = IsInWater(source->GetPhaseMask(), destX, destY, destZ, source->GetCollisionHeight());
|
||||
|
||||
PathGenerator path(source);
|
||||
|
||||
|
|
@ -3784,6 +3932,8 @@ void Map::LoadCorpseData()
|
|||
}
|
||||
|
||||
AddCorpse(corpse);
|
||||
|
||||
corpse->UpdatePositionData();
|
||||
} while (result->NextRow());
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -76,6 +76,8 @@ struct map_fileheader
|
|||
uint32 heightMapSize;
|
||||
uint32 liquidMapOffset;
|
||||
uint32 liquidMapSize;
|
||||
uint32 holesOffset;
|
||||
uint32 holesSize;
|
||||
};
|
||||
|
||||
#define MAP_AREA_NO_AREA 0x0001
|
||||
|
|
@ -115,7 +117,7 @@ struct map_liquidHeader
|
|||
float liquidLevel;
|
||||
};
|
||||
|
||||
enum ZLiquidStatus
|
||||
enum LiquidStatus
|
||||
{
|
||||
LIQUID_MAP_NO_WATER = 0x00000000,
|
||||
LIQUID_MAP_ABOVE_WATER = 0x00000001,
|
||||
|
|
@ -124,6 +126,9 @@ enum ZLiquidStatus
|
|||
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_WATER 0x01
|
||||
#define MAP_LIQUID_TYPE_OCEAN 0x02
|
||||
|
|
@ -135,12 +140,30 @@ enum ZLiquidStatus
|
|||
#define MAP_LIQUID_TYPE_DARK_WATER 0x10
|
||||
#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
|
||||
{
|
||||
uint32 type_flags;
|
||||
uint32 entry;
|
||||
float level;
|
||||
float depth_level;
|
||||
LiquidData() : Entry(0), Flags(0), Level(INVALID_HEIGHT), DepthLevel(INVALID_HEIGHT), Status(LIQUID_MAP_NO_WATER) { }
|
||||
|
||||
uint32 Entry;
|
||||
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
|
||||
|
|
@ -186,10 +209,13 @@ class GridMap
|
|||
uint8 _liquidOffY;
|
||||
uint8 _liquidWidth;
|
||||
uint8 _liquidHeight;
|
||||
uint16* _holes;
|
||||
|
||||
bool loadAreaData(FILE* in, uint32 offset, uint32 size);
|
||||
bool loadHeightData(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
|
||||
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]] float getMinHeight(float x, float y) const;
|
||||
[[nodiscard]] float getLiquidLevel(float x, float y) const;
|
||||
[[nodiscard]] uint8 getTerrainType(float x, float y) const;
|
||||
ZLiquidStatus getLiquidStatus(float x, float y, float z, uint8 ReqLiquidType, float collisionHeight, LiquidData* data = nullptr);
|
||||
LiquidData const GetLiquidData(float x, float y, float z, float collisionHeight, uint8 ReqLiquidType) const;
|
||||
};
|
||||
|
||||
// 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)
|
||||
#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::unordered_map<uint32 /*zoneId*/, ZoneDynamicInfo> ZoneDynamicInfoMap;
|
||||
typedef std::set<MotionTransport*> TransportsContainer;
|
||||
|
|
@ -352,22 +371,19 @@ public:
|
|||
[[nodiscard]] float GetMinHeight(float x, float y) const;
|
||||
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;
|
||||
bool GetAreaInfo(float x, float y, float z, uint32& mogpflags, int32& adtId, int32& rootId, int32& groupId) const;
|
||||
[[nodiscard]] uint32 GetAreaId(float x, float y, float z) const;
|
||||
[[nodiscard]] uint32 GetZoneId(float x, float y, float z) const;
|
||||
void GetZoneAndAreaId(uint32& zoneid, uint32& areaid, float x, float y, float z) const;
|
||||
[[nodiscard]] bool GetAreaInfo(uint32 phaseMask, 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 GetZoneId(uint32 phaseMask, float x, float y, float z) const;
|
||||
void GetZoneAndAreaId(uint32 phaseMask, 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;
|
||||
bool IsInWater(float x, float y, float z, LiquidData* data = nullptr) const;
|
||||
[[nodiscard]] bool IsUnderWater(float x, float y, float z) const;
|
||||
bool IsInWater(uint32 phaseMask, float x, float y, float z, float collisionHeight) 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, LiquidData liquidData) const;
|
||||
[[nodiscard]] bool HasEnoughWater(WorldObject const* searcher, LiquidData const& liquidData) const;
|
||||
|
||||
void MoveAllCreaturesInMoveList();
|
||||
void MoveAllGameObjectsInMoveList();
|
||||
|
|
|
|||
|
|
@ -37,26 +37,26 @@ public:
|
|||
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);
|
||||
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(WorldLocation const& loc) const { return GetAreaId(loc.GetMapId(), loc); }
|
||||
[[nodiscard]] uint32 GetAreaId(uint32 phaseMask, uint32 mapid, Position const& pos) const { return GetAreaId(phaseMask, mapid, pos.GetPositionX(), pos.GetPositionY(), pos.GetPositionZ()); }
|
||||
[[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);
|
||||
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(WorldLocation const& loc) const { return GetZoneId(loc.GetMapId(), loc); }
|
||||
[[nodiscard]] uint32 GetZoneId(uint32 phaseMask, uint32 mapid, Position const& pos) const { return GetZoneId(phaseMask, mapid, pos.GetPositionX(), pos.GetPositionY(), pos.GetPositionZ()); }
|
||||
[[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);
|
||||
m->GetZoneAndAreaId(zoneid, areaid, x, y, z);
|
||||
m->GetZoneAndAreaId(phaseMask, zoneid, areaid, x, y, z);
|
||||
}
|
||||
|
||||
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)
|
||||
{
|
||||
// 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)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -132,11 +132,6 @@ void MotionMaster::UpdateMotion(uint32 diff)
|
|||
}
|
||||
|
||||
_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)
|
||||
|
|
|
|||
|
|
@ -26,7 +26,7 @@ void ConfusedMovementGenerator<T>::DoInitialize(T* unit)
|
|||
float y = unit->GetPositionY();
|
||||
float z = unit->GetPositionZ();
|
||||
|
||||
Map const* map = unit->GetBaseMap();
|
||||
Map const* map = unit->GetMap();
|
||||
|
||||
bool 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))
|
||||
{
|
||||
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))
|
||||
{
|
||||
|
|
|
|||
|
|
@ -48,7 +48,7 @@ bool FleeingMovementGenerator<T>::_getPoint(T* owner, float& x, float& y, float&
|
|||
if (!owner)
|
||||
return false;
|
||||
|
||||
const Map* _map = owner->GetBaseMap();
|
||||
const Map* _map = owner->GetMap();
|
||||
|
||||
x = owner->GetPositionX();
|
||||
y = owner->GetPositionY();
|
||||
|
|
|
|||
|
|
@ -29,8 +29,6 @@ void HomeMovementGenerator<Creature>::DoFinalize(Creature* owner)
|
|||
|
||||
if (!owner->HasSwimmingFlagOutOfCombat())
|
||||
owner->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_SWIMMING);
|
||||
|
||||
owner->UpdateEnvironmentIfNeeded(2);
|
||||
}
|
||||
|
||||
void HomeMovementGenerator<Creature>::DoReset(Creature*)
|
||||
|
|
|
|||
|
|
@ -197,8 +197,8 @@ void PathGenerator::BuildPolyPath(G3D::Vector3 const& startPos, G3D::Vector3 con
|
|||
{
|
||||
bool buildShotrcut = false;
|
||||
|
||||
bool isUnderWaterStart = _source->GetMap()->IsUnderWater(startPos.x, startPos.y, startPos.z);
|
||||
bool isUnderWaterEnd = _source->GetMap()->IsUnderWater(endPos.x, endPos.y, endPos.z);
|
||||
bool isUnderWaterStart = _source->GetMap()->IsUnderWater(_source->GetPhaseMask(), startPos.x, startPos.y, startPos.z, _source->GetCollisionHeight());
|
||||
bool isUnderWaterEnd = _source->GetMap()->IsUnderWater(_source->GetPhaseMask(), endPos.x, endPos.y, endPos.z, _source->GetCollisionHeight());
|
||||
bool isFarUnderWater = startFarFromPoly ? isUnderWaterStart : isUnderWaterEnd;
|
||||
|
||||
Unit const* _sourceUnit = _source->ToUnit();
|
||||
|
|
@ -565,9 +565,9 @@ void PathGenerator::BuildPointPath(const float* startPoint, const float* endPoin
|
|||
uint32 newPointCount = 0;
|
||||
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]);
|
||||
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
|
||||
if (status == LIQUID_MAP_UNDER_WATER)
|
||||
if (liquidData.Status == LIQUID_MAP_UNDER_WATER)
|
||||
{
|
||||
// if the first point is under water
|
||||
// then set a proper z for it
|
||||
|
|
@ -699,11 +699,11 @@ void PathGenerator::UpdateFilter()
|
|||
NavTerrain PathGenerator::GetNavTerrain(float x, float y, float z) const
|
||||
{
|
||||
LiquidData data;
|
||||
ZLiquidStatus liquidStatus = _source->GetMap()->getLiquidStatus(x, y, z, MAP_ALL_LIQUIDS, &data);
|
||||
if (liquidStatus == LIQUID_MAP_NO_WATER)
|
||||
LiquidData const& liquidData = _source->GetMap()->GetLiquidData(_source->GetPhaseMask(), x, y, z, _source->GetCollisionHeight(), MAP_ALL_LIQUIDS);
|
||||
if (liquidData.Status == LIQUID_MAP_NO_WATER)
|
||||
return NAV_GROUND;
|
||||
|
||||
switch (data.type_flags)
|
||||
switch (data.Flags)
|
||||
{
|
||||
case MAP_LIQUID_TYPE_WATER:
|
||||
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
|
||||
{
|
||||
Creature const* _sourceCreature = _source->ToCreature();
|
||||
return _source->GetMap()->IsInWater(x, y, z) &&
|
||||
_source->GetMap()->IsInWater(destX, destY, destZ) &&
|
||||
return _source->GetMap()->IsInWater(_source->GetPhaseMask(), x, y, z, _source->GetCollisionHeight()) &&
|
||||
_source->GetMap()->IsInWater(_source->GetPhaseMask(), destX, destY, destZ, _source->GetCollisionHeight()) &&
|
||||
(!checkSwim || !_sourceCreature || _sourceCreature->CanSwim());
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -110,6 +110,9 @@ namespace Movement
|
|||
[[nodiscard]] Vector3 CurrentDestination() const { return Initialized() ? spline.getPoint(point_Idx + 1, false) : Vector3(); }
|
||||
[[nodiscard]] int32 currentPathIdx() const;
|
||||
|
||||
[[nodiscard]] bool HasAnimation() const { return splineflags.animation; }
|
||||
[[nodiscard]] uint8 GetAnimationType() const { return splineflags.animId; }
|
||||
|
||||
bool onTransport;
|
||||
[[nodiscard]] std::string ToString() const;
|
||||
[[nodiscard]] bool HasStarted() const
|
||||
|
|
|
|||
|
|
@ -5784,7 +5784,7 @@ void AuraEffect::HandlePreventResurrection(AuraApplication const* aurApp, uint8
|
|||
|
||||
if (apply)
|
||||
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);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1327,9 +1327,9 @@ void Spell::SelectImplicitCasterDestTargets(SpellEffIndex effIndex, SpellImplici
|
|||
|
||||
float ground = m_caster->GetMapHeight(x, y, z, true);
|
||||
float liquidLevel = VMAP_INVALID_HEIGHT_VALUE;
|
||||
LiquidData liquidData;
|
||||
if (m_caster->GetMap()->getLiquidStatus(x, y, z, MAP_ALL_LIQUIDS, &liquidData, m_caster->GetCollisionHeight()))
|
||||
liquidLevel = liquidData.level;
|
||||
LiquidData const& liquidData = m_caster->GetMap()->GetLiquidData(m_caster->GetPhaseMask(), x, y, z, m_caster->GetCollisionHeight(), MAP_ALL_LIQUIDS);
|
||||
if (liquidData.Status)
|
||||
liquidLevel = liquidData.Level;
|
||||
|
||||
if (liquidLevel <= ground) // When there is no liquid Map::GetWaterOrGroundLevel returns ground level
|
||||
{
|
||||
|
|
|
|||
|
|
@ -444,7 +444,6 @@ public:
|
|||
|
||||
Map2ZoneCoordinates(zoneX, zoneY, zoneId);
|
||||
|
||||
Map const* map = object->GetMap();
|
||||
float groundZ = object->GetMapHeight(object->GetPositionX(), object->GetPositionY(), MAX_HEIGHT);
|
||||
float floorZ = object->GetMapHeight(object->GetPositionX(), object->GetPositionY(), object->GetPositionZ());
|
||||
|
||||
|
|
@ -459,7 +458,7 @@ public:
|
|||
|
||||
if (haveVMap)
|
||||
{
|
||||
if (map->IsOutdoors(object->GetPositionX(), object->GetPositionY(), object->GetPositionZ()))
|
||||
if (object->IsOutdoors())
|
||||
handler->PSendSysMessage("You are outdoors");
|
||||
else
|
||||
handler->PSendSysMessage("You are indoors");
|
||||
|
|
@ -476,11 +475,11 @@ public:
|
|||
cell.GridX(), cell.GridY(), cell.CellX(), cell.CellY(), object->GetInstanceId(),
|
||||
zoneX, zoneY, groundZ, floorZ, haveMap, haveVMap);
|
||||
|
||||
LiquidData liquidStatus;
|
||||
ZLiquidStatus status = map->getLiquidStatus(object->GetPositionX(), object->GetPositionY(), object->GetPositionZ(), MAP_ALL_LIQUIDS, &liquidStatus);
|
||||
LiquidData const& liquidData = object->GetLiquidData();
|
||||
|
||||
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())
|
||||
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());
|
||||
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;
|
||||
|
|
|
|||
|
|
@ -2171,7 +2171,7 @@ public:
|
|||
Position pos;
|
||||
caster->GetPosition(&pos);
|
||||
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;
|
||||
caster->SendMeleeAttackStop(caster->GetVictim());
|
||||
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)));
|
||||
}
|
||||
[[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
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue