Core/Maps: fixed several issues with liquids by merging some 335 branch commits that are taking mopg flags into account
This commit is contained in:
1 parent
2008854f56
commit
3f53afd39e
17 files changed
+435
-272
No files matched your search
@@ -50,6 +50,28 @@ namespace VMAP
|
||||
#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 TC_COMMON_API IVMapManager
|
||||
{
|
||||
@@ -101,8 +123,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 mapId, float x, float y, float &z, uint32 &flags, int32 &adtId, int32 &rootId, int32 &groupId) const = 0;
|
||||
virtual bool GetLiquidLevel(uint32 mapId, float x, float y, float z, uint8 reqLiquidType, float& level, float& floor, uint32 &type, uint32& mogpFlagss) 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;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
@@ -261,7 +261,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 (!IsVMAPDisabledForPtr(mapId, VMAP_DISABLE_AREAFLAG))
|
||||
{
|
||||
@@ -279,7 +279,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 (!IsVMAPDisabledForPtr(mapId, VMAP_DISABLE_LIQUIDSTATUS))
|
||||
{
|
||||
@@ -294,6 +294,7 @@ namespace VMAP
|
||||
ASSERT(floor < std::numeric_limits<float>::max());
|
||||
ASSERT(info.hitModel);
|
||||
type = info.hitModel->GetLiquidType(); // entry from LiquidType.dbc
|
||||
mogpFlags = info.hitModel->GetMogpFlags();
|
||||
if (reqLiquidType && !(GetLiquidFlagsPtr(type) & reqLiquidType))
|
||||
return false;
|
||||
ASSERT(info.hitInstance);
|
||||
@@ -306,6 +307,39 @@ 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 = boost::in_place(adtId, rootId, groupId, flags);
|
||||
return;
|
||||
}
|
||||
auto instanceTree = GetMapTree(mapId);
|
||||
if (instanceTree != iInstanceMapTrees.end())
|
||||
{
|
||||
LocationInfo info;
|
||||
Vector3 pos = convertPositionToInternalRep(x, y, z);
|
||||
if (instanceTree->second->GetLocationInfo(pos, info))
|
||||
{
|
||||
ASSERT(info.hitModel);
|
||||
ASSERT(info.hitInstance);
|
||||
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 = boost::in_place(liquidType, liquidLevel);
|
||||
|
||||
if (!IsVMAPDisabledForPtr(mapId, VMAP_DISABLE_AREAFLAG))
|
||||
data.areaInfo = boost::in_place(info.hitInstance->adtId, info.rootId, info.hitModel->GetWmoID(), info.hitModel->GetMogpFlags());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
WorldModel* VMapManager2::acquireModelInstance(const std::string& basepath, const std::string& filename, uint32 flags/* Only used when creating the model */)
|
||||
{
|
||||
//! Critical section, thread safe access to iLoadedModelFiles
|
||||
|
||||
@@ -120,8 +120,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 mapId, float x, float y, float& z, uint32& flags, int32& adtId, int32& rootId, int32& groupId) const override;
|
||||
bool GetLiquidLevel(uint32 mapId, 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, uint32 flags = 0);
|
||||
void releaseModelInstance(const std::string& filename);
|
||||
|
||||
@@ -34,7 +34,8 @@ namespace VMAP
|
||||
|
||||
struct TC_COMMON_API LocationInfo
|
||||
{
|
||||
LocationInfo(): hitInstance(nullptr), hitModel(nullptr), ground_Z(-G3D::finf()) { }
|
||||
LocationInfo(): rootId(-1), hitInstance(nullptr), hitModel(nullptr), ground_Z(-G3D::finf()) { }
|
||||
int32 rootId;
|
||||
const ModelInstance* hitInstance;
|
||||
const GroupModel* hitModel;
|
||||
float ground_Z;
|
||||
|
||||
@@ -399,8 +399,7 @@ namespace VMAP
|
||||
vertices(vert.begin()), triangles(tris.begin()), hit(false) { }
|
||||
bool operator()(const G3D::Ray& ray, uint32 entry, float& distance, bool /*pStopAtFirstHit*/)
|
||||
{
|
||||
bool result = IntersectTriangle(triangles[entry], vertices, ray, distance);
|
||||
if (result) hit=true;
|
||||
hit = IntersectTriangle(triangles[entry], vertices, ray, distance) || hit;
|
||||
return hit;
|
||||
}
|
||||
std::vector<Vector3>::const_iterator vertices;
|
||||
@@ -422,7 +421,6 @@ namespace VMAP
|
||||
{
|
||||
if (triangles.empty() || !iBound.contains(pos))
|
||||
return false;
|
||||
GModelRayCallback callback(triangles, vertices);
|
||||
Vector3 rPos = pos - 0.1f * down;
|
||||
float dist = G3D::finf();
|
||||
G3D::Ray ray(rPos, down);
|
||||
@@ -559,6 +557,7 @@ namespace VMAP
|
||||
groupTree.intersectPoint(p, callback);
|
||||
if (callback.hit != groupModels.end())
|
||||
{
|
||||
info.rootId = RootWMOID;
|
||||
info.hitModel = &(*callback.hit);
|
||||
dist = callback.zDist;
|
||||
return true;
|
||||
|
||||
@@ -2858,7 +2858,7 @@ void Creature::UpdateMovementFlags()
|
||||
return;
|
||||
|
||||
// Set the movement flags if the creature is in that mode. (Only fly if actually in air, only swim if in water, etc)
|
||||
float ground = GetMap()->GetHeight(GetPhaseShift(), GetPositionX(), GetPositionY(), GetPositionZMinusOffset());
|
||||
float ground = GetFloorZ();
|
||||
|
||||
bool isInAir = (G3D::fuzzyGt(GetPositionZMinusOffset(), ground + 0.05f) || G3D::fuzzyLt(GetPositionZMinusOffset(), ground - 0.05f)); // Can be underground too, prevent the falling
|
||||
|
||||
|
||||
@@ -1228,8 +1228,9 @@ void MovementInfo::OutDebug()
|
||||
|
||||
WorldObject::WorldObject(bool isWorldObject) : WorldLocation(), LastUsedScriptID(0),
|
||||
m_name(""), m_isActive(false), m_isFarVisible(false), m_isWorldObject(isWorldObject), m_zoneScript(nullptr),
|
||||
m_transport(nullptr), m_currMap(nullptr), m_InstanceId(0), m_phaseMask(PHASEMASK_NORMAL), _dbPhase(0),
|
||||
m_notifyflags(0), m_executed_notifies(0), m_aiAnimKitId(0), m_movementAnimKitId(0), m_meleeAnimKitId(0)
|
||||
m_transport(nullptr), m_zoneId(0), m_areaId(0), m_staticFloorZ(VMAP_INVALID_HEIGHT), m_currMap(nullptr), m_InstanceId(0),
|
||||
m_phaseMask(PHASEMASK_NORMAL), _dbPhase(0), m_notifyflags(0), m_executed_notifies(0),
|
||||
m_aiAnimKitId(0), m_movementAnimKitId(0), m_meleeAnimKitId(0)
|
||||
{
|
||||
m_serverSideVisibility.SetValue(SERVERSIDE_VISIBILITY_GHOST, GHOST_VISIBILITY_ALIVE | GHOST_VISIBILITY_GHOST);
|
||||
m_serverSideVisibilityDetect.SetValue(SERVERSIDE_VISIBILITY_GHOST, GHOST_VISIBILITY_ALIVE);
|
||||
@@ -1310,21 +1311,28 @@ void WorldObject::_Create(ObjectGuid::LowType guidlow, HighGuid guidhigh, uint32
|
||||
m_phaseMask = phaseMask;
|
||||
}
|
||||
|
||||
uint32 WorldObject::GetZoneId() const
|
||||
void WorldObject::UpdatePositionData()
|
||||
{
|
||||
return GetBaseMap()->GetZoneId(GetPhaseShift(), m_positionX, m_positionY, m_positionZ);
|
||||
PositionFullTerrainStatus data;
|
||||
GetMap()->GetFullTerrainStatusForPosition(GetPhaseShift(), GetPositionX(), GetPositionY(), GetPositionZ(), data);
|
||||
ProcessPositionDataChanged(data);
|
||||
}
|
||||
|
||||
uint32 WorldObject::GetAreaId() const
|
||||
void WorldObject::ProcessPositionDataChanged(PositionFullTerrainStatus const& data)
|
||||
{
|
||||
return GetBaseMap()->GetAreaId(GetPhaseShift(), m_positionX, m_positionY, m_positionZ);
|
||||
m_zoneId = m_areaId = data.areaId;
|
||||
if (AreaTableEntry const* area = sAreaTableStore.LookupEntry(m_areaId))
|
||||
if (area->zone)
|
||||
m_zoneId = area->zone;
|
||||
m_outdoors = data.outdoors;
|
||||
m_staticFloorZ = data.floorZ;
|
||||
}
|
||||
|
||||
void WorldObject::GetZoneAndAreaId(uint32& zoneid, uint32& areaid) const
|
||||
void WorldObject::AddToWorld()
|
||||
{
|
||||
GetBaseMap()->GetZoneAndAreaId(GetPhaseShift(), zoneid, areaid, m_positionX, m_positionY, m_positionZ);
|
||||
Object::AddToWorld();
|
||||
GetMap()->GetZoneAndAreaId(GetPhaseShift(), m_zoneId, m_areaId, GetPositionX(), GetPositionY(), GetPositionZ());
|
||||
}
|
||||
|
||||
void WorldObject::RemoveFromWorld()
|
||||
{
|
||||
if (!IsInWorld())
|
||||
@@ -2748,6 +2756,13 @@ ObjectGuid WorldObject::GetTransGUID() const
|
||||
return ObjectGuid::Empty;
|
||||
}
|
||||
|
||||
float WorldObject::GetFloorZ() const
|
||||
{
|
||||
if (!IsInWorld())
|
||||
return m_staticFloorZ;
|
||||
return std::max<float>(m_staticFloorZ, GetMap()->GetGameObjectFloor(GetPhaseShift(), GetPositionX(), GetPositionY(), GetPositionZ()));
|
||||
}
|
||||
|
||||
template TC_GAME_API void WorldObject::GetGameObjectListWithEntryInGrid(std::list<GameObject*>&, uint32, float) const;
|
||||
template TC_GAME_API void WorldObject::GetGameObjectListWithEntryInGrid(std::deque<GameObject*>&, uint32, float) const;
|
||||
template TC_GAME_API void WorldObject::GetGameObjectListWithEntryInGrid(std::vector<GameObject*>&, uint32, float) const;
|
||||
|
||||
@@ -275,7 +275,8 @@ class TC_GAME_API WorldObject : public Object, public WorldLocation
|
||||
virtual void Update (uint32 /*time_diff*/) { }
|
||||
|
||||
void _Create(ObjectGuid::LowType guidlow, HighGuid guidhigh, uint32 phaseMask);
|
||||
virtual void RemoveFromWorld();
|
||||
void AddToWorld() override;
|
||||
void RemoveFromWorld() override;
|
||||
|
||||
void GetNearPoint2D(float &x, float &y, float distance, float absAngle) const;
|
||||
void GetNearPoint(WorldObject const* searcher, float &x, float &y, float &z, float searcher_size, float distance2d, float absAngle) const;
|
||||
@@ -312,9 +313,10 @@ class TC_GAME_API WorldObject : public Object, public WorldLocation
|
||||
// if negative it is used as PhaseGroupId
|
||||
void SetDBPhase(int32 p) { _dbPhase = p; }
|
||||
|
||||
uint32 GetZoneId() const;
|
||||
uint32 GetAreaId() const;
|
||||
void GetZoneAndAreaId(uint32& zoneid, uint32& areaid) const;
|
||||
uint32 GetZoneId() const { return m_zoneId; }
|
||||
uint32 GetAreaId() const { return m_areaId; }
|
||||
void GetZoneAndAreaId(uint32& zoneid, uint32& areaid) const { zoneid = m_zoneId, areaid = m_areaId; }
|
||||
bool IsOutdoors() const { return m_outdoors; }
|
||||
|
||||
InstanceScript* GetInstanceScript() const;
|
||||
|
||||
@@ -420,10 +422,8 @@ class TC_GAME_API WorldObject : public Object, public WorldLocation
|
||||
|
||||
void DestroyForNearbyPlayers();
|
||||
virtual void UpdateObjectVisibility(bool forced = true);
|
||||
virtual void UpdateObjectVisibilityOnCreate()
|
||||
{
|
||||
UpdateObjectVisibility(true);
|
||||
}
|
||||
virtual void UpdateObjectVisibilityOnCreate() { UpdateObjectVisibility(true); }
|
||||
void UpdatePositionData();
|
||||
|
||||
void BuildUpdate(UpdateDataMapType&) override;
|
||||
|
||||
@@ -467,6 +467,8 @@ class TC_GAME_API WorldObject : public Object, public WorldLocation
|
||||
virtual float GetStationaryZ() const { return GetPositionZ(); }
|
||||
virtual float GetStationaryO() const { return GetOrientation(); }
|
||||
|
||||
float GetFloorZ() const;
|
||||
|
||||
uint16 GetAIAnimKitId() const { return m_aiAnimKitId; }
|
||||
void SetAIAnimKitId(uint16 animKitId);
|
||||
uint16 GetMovementAnimKitId() const { return m_movementAnimKitId; }
|
||||
@@ -484,6 +486,12 @@ class TC_GAME_API WorldObject : public Object, public WorldLocation
|
||||
// transports
|
||||
Transport* m_transport;
|
||||
|
||||
virtual void ProcessPositionDataChanged(PositionFullTerrainStatus const& data);
|
||||
uint32 m_zoneId;
|
||||
uint32 m_areaId;
|
||||
float m_staticFloorZ;
|
||||
bool m_outdoors;
|
||||
|
||||
//these functions are used mostly for Relocate() and Corpse/Player specific stuff...
|
||||
//use them ONLY in LoadFromDB()/Create() funcs and nowhere else!
|
||||
//mapId/instanceId should be set in SetMap() function!
|
||||
|
||||
@@ -6438,15 +6438,11 @@ void Player::CheckAreaExploreAndOutdoor()
|
||||
if (IsInFlight())
|
||||
return;
|
||||
|
||||
bool isOutdoor;
|
||||
uint32 areaId = GetBaseMap()->GetAreaId(GetPhaseShift(), GetPositionX(), GetPositionY(), GetPositionZ(), &isOutdoor);
|
||||
AreaTableEntry const* areaEntry = sAreaTableStore.LookupEntry(areaId);
|
||||
|
||||
if (sWorld->getBoolConfig(CONFIG_VMAP_INDOOR_CHECK) && !isOutdoor)
|
||||
if (sWorld->getBoolConfig(CONFIG_VMAP_INDOOR_CHECK) && !IsOutdoors())
|
||||
RemoveAurasWithAttribute(SPELL_ATTR0_OUTDOORS_ONLY);
|
||||
|
||||
if (!areaId)
|
||||
return;
|
||||
uint32 const areaId = GetAreaId();
|
||||
AreaTableEntry const* areaEntry = sAreaTableStore.LookupEntry(areaId);
|
||||
|
||||
if (!areaEntry)
|
||||
{
|
||||
@@ -25276,77 +25272,53 @@ void Player::SetOriginalGroup(Group* group, int8 subgroup)
|
||||
}
|
||||
}
|
||||
|
||||
void Player::UpdateUnderwaterState(Map* m, float x, float y, float z)
|
||||
void Player::ProcessTerrainStatusUpdate(ZLiquidStatus status, Optional<LiquidData> const& liquidData)
|
||||
{
|
||||
LiquidData liquid_status;
|
||||
ZLiquidStatus res = m->GetLiquidStatus(GetPhaseShift(), x, y, z, MAP_ALL_LIQUIDS, &liquid_status);
|
||||
if (!res)
|
||||
{
|
||||
m_MirrorTimerFlags &= ~(UNDERWATER_INWATER | UNDERWATER_INLAVA | UNDERWATER_INSLIME | UNDERWATER_INDARKWATER);
|
||||
if (_lastLiquid && _lastLiquid->SpellId)
|
||||
RemoveAurasDueToSpell(_lastLiquid->SpellId);
|
||||
|
||||
_lastLiquid = nullptr;
|
||||
if (IsFlying())
|
||||
return;
|
||||
}
|
||||
|
||||
if (uint32 liqEntry = liquid_status.entry)
|
||||
// process liquid auras using generic unit code
|
||||
Unit::ProcessTerrainStatusUpdate(status, liquidData);
|
||||
|
||||
// player specific logic for mirror timers
|
||||
if (status && liquidData)
|
||||
{
|
||||
LiquidTypeEntry const* liquid = sLiquidTypeStore.LookupEntry(liqEntry);
|
||||
if (_lastLiquid && _lastLiquid->SpellId && _lastLiquid != liquid)
|
||||
RemoveAurasDueToSpell(_lastLiquid->SpellId);
|
||||
|
||||
if (liquid && liquid->SpellId)
|
||||
// Breath bar state (under water in any liquid type)
|
||||
if (liquidData->type_flags & MAP_ALL_LIQUIDS)
|
||||
{
|
||||
if (res & (LIQUID_MAP_UNDER_WATER | LIQUID_MAP_IN_WATER))
|
||||
{
|
||||
if (!HasAura(liquid->SpellId))
|
||||
CastSpell(this, liquid->SpellId, true);
|
||||
}
|
||||
if (status & LIQUID_MAP_UNDER_WATER)
|
||||
m_MirrorTimerFlags |= UNDERWATER_INWATER;
|
||||
else
|
||||
RemoveAurasDueToSpell(liquid->SpellId);
|
||||
m_MirrorTimerFlags &= ~UNDERWATER_INWATER;
|
||||
}
|
||||
|
||||
_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;
|
||||
// Fatigue bar state (if not on flight path or transport)
|
||||
if ((liquidData->type_flags & MAP_LIQUID_TYPE_DARK_WATER) && !IsInFlight() && !GetTransport())
|
||||
m_MirrorTimerFlags |= UNDERWATER_INDARKWATER;
|
||||
else
|
||||
m_MirrorTimerFlags &= ~UNDERWATER_INWATER;
|
||||
}
|
||||
m_MirrorTimerFlags &= ~UNDERWATER_INDARKWATER;
|
||||
|
||||
// Allow travel in dark water on taxi or transport
|
||||
if ((liquid_status.type_flags & MAP_LIQUID_TYPE_DARK_WATER) && !IsInFlight() && !GetTransport())
|
||||
m_MirrorTimerFlags |= UNDERWATER_INDARKWATER;
|
||||
// Lava state (any contact)
|
||||
if (liquidData->type_flags & MAP_LIQUID_TYPE_MAGMA)
|
||||
{
|
||||
if (status & MAP_LIQUID_STATUS_IN_CONTACT)
|
||||
m_MirrorTimerFlags |= UNDERWATER_INLAVA;
|
||||
else
|
||||
m_MirrorTimerFlags &= ~UNDERWATER_INLAVA;
|
||||
}
|
||||
|
||||
// Slime state (any contact)
|
||||
if (liquidData->type_flags & MAP_LIQUID_TYPE_SLIME)
|
||||
{
|
||||
if (status & MAP_LIQUID_STATUS_IN_CONTACT)
|
||||
m_MirrorTimerFlags |= UNDERWATER_INSLIME;
|
||||
else
|
||||
m_MirrorTimerFlags &= ~UNDERWATER_INSLIME;
|
||||
}
|
||||
}
|
||||
else
|
||||
m_MirrorTimerFlags &= ~UNDERWATER_INDARKWATER;
|
||||
m_MirrorTimerFlags &= ~(UNDERWATER_INWATER | UNDERWATER_INLAVA | UNDERWATER_INSLIME | UNDERWATER_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::SetCanParry(bool value)
|
||||
|
||||
@@ -1867,7 +1867,7 @@ class TC_GAME_API Player : public Unit, public GridObject<Player>
|
||||
|
||||
bool UpdatePosition(float x, float y, float z, float orientation, bool teleport = false) override;
|
||||
bool UpdatePosition(Position const& pos, bool teleport = false) override { return UpdatePosition(pos.GetPositionX(), pos.GetPositionY(), pos.GetPositionZ(), pos.GetOrientation(), teleport); }
|
||||
void UpdateUnderwaterState(Map* m, float x, float y, float z) override;
|
||||
void ProcessTerrainStatusUpdate(ZLiquidStatus status, Optional<LiquidData> const& liquidData) override;
|
||||
|
||||
void SendMessageToSet(WorldPacket* data, bool self) override { SendMessageToSetInRange(data, GetVisibilityRange(), self); }
|
||||
void SendMessageToSetInRange(WorldPacket* data, float dist, bool self) override;
|
||||
|
||||
@@ -485,7 +485,6 @@ void Unit::Update(uint32 p_time)
|
||||
|
||||
UpdateSplineMovement(p_time);
|
||||
i_motionMaster->UpdateMotion(p_time);
|
||||
UpdateUnderwaterState(GetMap(), GetPositionX(), GetPositionY(), GetPositionZ());
|
||||
}
|
||||
|
||||
bool Unit::haveOffhandWeapon() const
|
||||
@@ -3207,51 +3206,37 @@ bool Unit::IsUnderWater() const
|
||||
return GetBaseMap()->IsUnderWater(GetPhaseShift(), GetPositionX(), GetPositionY(), GetPositionZ());
|
||||
}
|
||||
|
||||
void Unit::UpdateUnderwaterState(Map* m, float x, float y, float z)
|
||||
void Unit::ProcessPositionDataChanged(PositionFullTerrainStatus const& data)
|
||||
{
|
||||
if (IsFlying() || (!IsPet() && !IsVehicle()))
|
||||
WorldObject::ProcessPositionDataChanged(data);
|
||||
ProcessTerrainStatusUpdate(data.liquidStatus, data.liquidInfo);
|
||||
}
|
||||
|
||||
void Unit::ProcessTerrainStatusUpdate(ZLiquidStatus status, Optional<LiquidData> const& liquidData)
|
||||
{
|
||||
if (IsFlying() || (!IsControlledByPlayer()))
|
||||
return;
|
||||
|
||||
LiquidData liquid_status;
|
||||
ZLiquidStatus res = m->GetLiquidStatus(GetPhaseShift(), x, y, z, MAP_ALL_LIQUIDS, &liquid_status);
|
||||
if (!res)
|
||||
// remove appropriate auras if we are swimming/not swimming respectively
|
||||
if (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 ((status & MAP_LIQUID_STATUS_SWIMMING) && liquidData)
|
||||
curLiquid = sLiquidTypeStore.LookupEntry(liquidData->entry);
|
||||
if (curLiquid != _lastLiquid)
|
||||
{
|
||||
if (_lastLiquid && _lastLiquid->SpellId)
|
||||
RemoveAurasDueToSpell(_lastLiquid->SpellId);
|
||||
|
||||
RemoveAurasWithInterruptFlags(AURA_INTERRUPT_FLAG_NOT_UNDERWATER);
|
||||
_lastLiquid = NULL;
|
||||
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);
|
||||
}
|
||||
|
||||
RemoveAurasWithInterruptFlags(AURA_INTERRUPT_FLAG_NOT_ABOVEWATER);
|
||||
_lastLiquid = liquid;
|
||||
}
|
||||
else if (_lastLiquid && _lastLiquid->SpellId)
|
||||
{
|
||||
RemoveAurasDueToSpell(_lastLiquid->SpellId);
|
||||
RemoveAurasWithInterruptFlags(AURA_INTERRUPT_FLAG_NOT_UNDERWATER);
|
||||
_lastLiquid = NULL;
|
||||
Player* player = GetCharmerOrOwnerPlayerOrPlayerItself();
|
||||
if (curLiquid && curLiquid->SpellId && (!player || !player->IsGameMaster()))
|
||||
CastSpell(this, curLiquid->SpellId, true);
|
||||
_lastLiquid = curLiquid;
|
||||
}
|
||||
}
|
||||
|
||||
void Unit::DeMorph()
|
||||
{
|
||||
SetDisplayId(GetNativeDisplayId());
|
||||
@@ -13849,9 +13834,6 @@ bool Unit::UpdatePosition(float x, float y, float z, float orientation, bool tel
|
||||
else if (turn)
|
||||
UpdateOrientation(orientation);
|
||||
|
||||
// code block for underwater state update
|
||||
UpdateUnderwaterState(GetMap(), x, y, z);
|
||||
|
||||
return (relocated || turn);
|
||||
}
|
||||
|
||||
|
||||
@@ -1260,7 +1260,6 @@ class TC_GAME_API Unit : public WorldObject
|
||||
|
||||
virtual bool IsInWater() const;
|
||||
virtual bool IsUnderWater() const;
|
||||
virtual void UpdateUnderwaterState(Map* m, float x, float y, float z);
|
||||
bool isInAccessiblePlaceFor(Creature const* c) const;
|
||||
|
||||
void SendHealSpellLog(HealInfo& healInfo, bool critical = false);
|
||||
@@ -1980,6 +1979,8 @@ class TC_GAME_API Unit : public WorldObject
|
||||
|
||||
void DisableSpline();
|
||||
|
||||
void ProcessPositionDataChanged(PositionFullTerrainStatus const& data) override;
|
||||
virtual void ProcessTerrainStatusUpdate(ZLiquidStatus status, Optional<LiquidData> const& liquidData);
|
||||
private:
|
||||
|
||||
void UpdateSplineMovement(uint32 t_diff);
|
||||
|
||||
+227
-119
@@ -56,6 +56,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 };
|
||||
|
||||
#define DEFAULT_GRID_EXPIRY 300
|
||||
#define MAX_GRID_LOAD_TIME 50
|
||||
#define MAX_CREATURE_ATTACK_RADIUS (45.0f * sWorld->getRate(RATE_CREATURE_AGGRO))
|
||||
@@ -1122,6 +1125,7 @@ void Map::PlayerRelocation(Player* player, float x, float y, float z, float orie
|
||||
AddToGrid(player, new_cell);
|
||||
}
|
||||
|
||||
player->UpdatePositionData();
|
||||
player->UpdateObjectVisibility(false);
|
||||
}
|
||||
|
||||
@@ -1156,6 +1160,7 @@ void Map::CreatureRelocation(Creature* creature, float x, float y, float z, floa
|
||||
if (creature->IsVehicle())
|
||||
creature->GetVehicleKit()->RelocatePassengers();
|
||||
creature->UpdateObjectVisibility(false);
|
||||
creature->UpdatePositionData();
|
||||
RemoveCreatureFromMoveList(creature);
|
||||
}
|
||||
|
||||
@@ -1186,6 +1191,7 @@ void Map::GameObjectRelocation(GameObject* go, float x, float y, float z, float
|
||||
{
|
||||
go->Relocate(x, y, z, orientation);
|
||||
go->UpdateModelPosition();
|
||||
go->UpdatePositionData();
|
||||
go->UpdateObjectVisibility(false);
|
||||
RemoveGameObjectFromMoveList(go);
|
||||
}
|
||||
@@ -1218,6 +1224,7 @@ void Map::DynamicObjectRelocation(DynamicObject* dynObj, float x, float y, float
|
||||
else
|
||||
{
|
||||
dynObj->Relocate(x, y, z, orientation);
|
||||
dynObj->UpdatePositionData();
|
||||
dynObj->UpdateObjectVisibility(false);
|
||||
RemoveDynamicObjectFromMoveList(dynObj);
|
||||
}
|
||||
@@ -1311,6 +1318,7 @@ void Map::MoveAllCreaturesInMoveList()
|
||||
if (c->IsVehicle())
|
||||
c->GetVehicleKit()->RelocatePassengers();
|
||||
//CreatureRelocationNotify(c, new_cell, new_cell.cellCoord());
|
||||
c->UpdatePositionData();
|
||||
c->UpdateObjectVisibility(false);
|
||||
}
|
||||
else
|
||||
@@ -1365,6 +1373,7 @@ void Map::MoveAllGameObjectsInMoveList()
|
||||
// update pos
|
||||
go->Relocate(go->_newPosition);
|
||||
go->UpdateModelPosition();
|
||||
go->UpdatePositionData();
|
||||
go->UpdateObjectVisibility(false);
|
||||
}
|
||||
else
|
||||
@@ -1409,6 +1418,7 @@ void Map::MoveAllDynamicObjectsInMoveList()
|
||||
{
|
||||
// update pos
|
||||
dynObj->Relocate(dynObj->_newPosition);
|
||||
dynObj->UpdatePositionData();
|
||||
dynObj->UpdateObjectVisibility(false);
|
||||
}
|
||||
else
|
||||
@@ -1629,6 +1639,7 @@ bool Map::CreatureRespawnRelocation(Creature* c, bool diffGridOnly)
|
||||
c->Relocate(resp_x, resp_y, resp_z, resp_o);
|
||||
c->GetMotionMaster()->Initialize(); // prevent possible problems with default move generators
|
||||
//CreatureRelocationNotify(c, resp_cell, resp_cell.GetCellCoord());
|
||||
c->UpdatePositionData();
|
||||
c->UpdateObjectVisibility(false);
|
||||
return true;
|
||||
}
|
||||
@@ -1654,6 +1665,7 @@ bool Map::GameObjectRespawnRelocation(GameObject* go, bool diffGridOnly)
|
||||
if (GameObjectCellRelocation(go, resp_cell))
|
||||
{
|
||||
go->Relocate(resp_x, resp_y, resp_z, resp_o);
|
||||
go->UpdatePositionData();
|
||||
go->UpdateObjectVisibility(false);
|
||||
return true;
|
||||
}
|
||||
@@ -1809,6 +1821,7 @@ GridMap::GridMap()
|
||||
_liquidEntry = nullptr;
|
||||
_liquidFlags = nullptr;
|
||||
_liquidMap = nullptr;
|
||||
_holes = nullptr;
|
||||
_fileExists = false;
|
||||
}
|
||||
|
||||
@@ -1859,6 +1872,13 @@ bool GridMap::loadData(char const* filename)
|
||||
fclose(in);
|
||||
return false;
|
||||
}
|
||||
// loadup holes data (if any. check header.holesOffset)
|
||||
if (header.holesSize && !loadHolesData(in, header.holesOffset, header.holesSize))
|
||||
{
|
||||
TC_LOG_ERROR("maps", "Error loading map holes data\n");
|
||||
fclose(in);
|
||||
return false;
|
||||
}
|
||||
fclose(in);
|
||||
return true;
|
||||
}
|
||||
@@ -1877,12 +1897,14 @@ void GridMap::unloadData()
|
||||
delete[] _liquidEntry;
|
||||
delete[] _liquidFlags;
|
||||
delete[] _liquidMap;
|
||||
delete[] _holes;
|
||||
_areaMap = nullptr;
|
||||
m_V9 = nullptr;
|
||||
m_V8 = nullptr;
|
||||
_liquidEntry = nullptr;
|
||||
_liquidFlags = nullptr;
|
||||
_liquidMap = nullptr;
|
||||
_holes = nullptr;
|
||||
_gridGetHeight = &GridMap::getHeightFromFlat;
|
||||
_fileExists = false;
|
||||
}
|
||||
@@ -1987,6 +2009,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)
|
||||
@@ -2019,6 +2053,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:
|
||||
@@ -2101,6 +2138,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)
|
||||
@@ -2168,6 +2208,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)
|
||||
@@ -2220,6 +2263,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::getLiquidLevel(float x, float y) const
|
||||
{
|
||||
if (!_liquidMap)
|
||||
@@ -2239,19 +2297,6 @@ 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 * (CENTER_GRID_ID - x/SIZE_OF_GRIDS);
|
||||
y = 16 * (CENTER_GRID_ID - 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, LiquidData* data)
|
||||
{
|
||||
@@ -2410,7 +2455,7 @@ float Map::GetStaticHeight(PhaseShift const& phaseShift, float x, float y, float
|
||||
{
|
||||
float gridHeight = gmap->getHeight(x, y);
|
||||
// look from a bit higher pos to find the floor, ignore under surface case
|
||||
if (z + 2.0f > gridHeight)
|
||||
if (G3D::fuzzyGe(z, gridHeight - GROUND_HEIGHT_TOLERANCE))
|
||||
mapHeight = gridHeight;
|
||||
}
|
||||
|
||||
@@ -2444,107 +2489,45 @@ float Map::GetStaticHeight(PhaseShift const& phaseShift, float x, float y, float
|
||||
return mapHeight; // explicitly use map data
|
||||
}
|
||||
|
||||
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) != 0;
|
||||
|
||||
if (wmoEntry)
|
||||
{
|
||||
if (wmoEntry->Flags & 4)
|
||||
return true;
|
||||
if (wmoEntry->Flags & 2)
|
||||
outdoor = false;
|
||||
}
|
||||
return outdoor;
|
||||
return (mogpFlags & 0x2000) != 0;
|
||||
}
|
||||
|
||||
bool Map::IsOutdoors(PhaseShift const& phaseShift, float x, float y, float z) const
|
||||
uint32 Map::GetAreaId(PhaseShift const& phaseShift, float x, float y, float z) const
|
||||
{
|
||||
uint32 mogpFlags;
|
||||
int32 adtId, rootId, groupId;
|
||||
|
||||
// no wmo found? -> outside by default
|
||||
if (!GetAreaInfo(phaseShift, x, y, z, mogpFlags, adtId, rootId, groupId))
|
||||
return true;
|
||||
|
||||
AreaTableEntry const* atEntry = nullptr;
|
||||
WMOAreaTableEntry const* wmoEntry= GetWMOAreaTableEntryByTripple(rootId, adtId, groupId);
|
||||
if (wmoEntry)
|
||||
{
|
||||
TC_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(PhaseShift const& phaseShift, float x, float y, float z, uint32 &flags, int32 &adtId, int32 &rootId, int32 &groupId) const
|
||||
{
|
||||
float vmap_z = z;
|
||||
float vmapZ;
|
||||
uint32 terrainMapId = PhasingHandler::GetTerrainMapId(phaseShift, this, x, y);
|
||||
VMAP::IVMapManager* vmgr = VMAP::VMapFactory::createOrGetVMapManager();
|
||||
if (vmgr->getAreaInfo(terrainMapId, x, y, vmap_z, flags, adtId, rootId, groupId))
|
||||
{
|
||||
// check if there's terrain between player height and object height
|
||||
if (GridMap* gmap = m_parentTerrainMap->GetGrid(terrainMapId, 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)
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
bool hasVmapArea = VMAP::VMapFactory::createOrGetVMapManager()->getAreaInfo(terrainMapId, x, y, vmapZ, mogpFlags, adtId, rootId, groupId);
|
||||
|
||||
uint32 gridAreaId = 0;
|
||||
float gridMapHeight = INVALID_HEIGHT;
|
||||
if (GridMap* gmap = m_parentTerrainMap->GetGrid(terrainMapId, x, y))
|
||||
{
|
||||
gridAreaId = gmap->getArea(x, y);
|
||||
gridMapHeight = gmap->getHeight(x, y);
|
||||
}
|
||||
|
||||
uint32 Map::GetAreaId(PhaseShift const& phaseShift, float x, float y, float z, bool *isOutdoors) const
|
||||
{
|
||||
uint32 mogpFlags;
|
||||
int32 adtId, rootId, groupId;
|
||||
WMOAreaTableEntry const* wmoEntry = nullptr;
|
||||
AreaTableEntry const* atEntry = nullptr;
|
||||
bool haveAreaInfo = false;
|
||||
uint32 areaId = 0;
|
||||
|
||||
if (GetAreaInfo(phaseShift, x, y, z, mogpFlags, adtId, rootId, groupId))
|
||||
// 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))
|
||||
{
|
||||
haveAreaInfo = true;
|
||||
wmoEntry = GetWMOAreaTableEntryByTripple(rootId, adtId, groupId);
|
||||
if (wmoEntry)
|
||||
{
|
||||
// wmo found
|
||||
if (WMOAreaTableEntry const* wmoEntry = GetWMOAreaTableEntryByTripple(rootId, adtId, groupId))
|
||||
areaId = wmoEntry->areaId;
|
||||
atEntry = sAreaTableStore.LookupEntry(wmoEntry->areaId);
|
||||
|
||||
}
|
||||
if (!areaId)
|
||||
areaId = gridAreaId;
|
||||
}
|
||||
else
|
||||
areaId = gridAreaId;
|
||||
|
||||
if (!areaId)
|
||||
{
|
||||
if (GridMap* gmap = m_parentTerrainMap->GetGrid(PhasingHandler::GetTerrainMapId(phaseShift, this, x, y), x, y))
|
||||
areaId = gmap->getArea(x, y);
|
||||
areaId = i_mapEntry->linked_zone;
|
||||
|
||||
// this used while not all *.map files generated (instances)
|
||||
if (!areaId)
|
||||
areaId = i_mapEntry->linked_zone;
|
||||
}
|
||||
|
||||
if (isOutdoors)
|
||||
{
|
||||
if (haveAreaInfo)
|
||||
*isOutdoors = IsOutdoorWMO(mogpFlags, adtId, rootId, groupId, wmoEntry, atEntry);
|
||||
else
|
||||
*isOutdoors = true;
|
||||
}
|
||||
return areaId;
|
||||
}
|
||||
|
||||
@@ -2566,14 +2549,6 @@ void Map::GetZoneAndAreaId(PhaseShift const& phaseShift, uint32& zoneid, uint32&
|
||||
zoneid = area->zone;
|
||||
}
|
||||
|
||||
uint8 Map::GetTerrainType(PhaseShift const& phaseShift, float x, float y) const
|
||||
{
|
||||
if (GridMap* gmap = m_parentTerrainMap->GetGrid(PhasingHandler::GetTerrainMapId(phaseShift, this, x, y), x, y))
|
||||
return gmap->getTerrainType(x, y);
|
||||
else
|
||||
return 0;
|
||||
}
|
||||
|
||||
ZLiquidStatus Map::GetLiquidStatus(PhaseShift const& phaseShift, float x, float y, float z, uint8 ReqLiquidType, LiquidData* data) const
|
||||
{
|
||||
ZLiquidStatus result = LIQUID_MAP_NO_WATER;
|
||||
@@ -2582,11 +2557,14 @@ ZLiquidStatus Map::GetLiquidStatus(PhaseShift const& phaseShift, float x, float
|
||||
float ground_level = INVALID_HEIGHT;
|
||||
uint32 liquid_type = 0;
|
||||
uint32 terrainMapId = PhasingHandler::GetTerrainMapId(phaseShift, this, x, y);
|
||||
if (vmgr->GetLiquidLevel(terrainMapId, x, y, z, ReqLiquidType, liquid_level, ground_level, liquid_type))
|
||||
uint32 mogpFlags = 0;
|
||||
bool useGridLiquid = true;
|
||||
if (vmgr->GetLiquidLevel(terrainMapId, x, y, z, ReqLiquidType, liquid_level, ground_level, liquid_type, mogpFlags))
|
||||
{
|
||||
useGridLiquid = !IsInWMOInterior(mogpFlags);
|
||||
TC_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)
|
||||
@@ -2639,27 +2617,157 @@ ZLiquidStatus Map::GetLiquidStatus(PhaseShift const& phaseShift, float x, float
|
||||
}
|
||||
}
|
||||
|
||||
if (GridMap* gmap = m_parentTerrainMap->GetGrid(terrainMapId, x, y))
|
||||
if (useGridLiquid)
|
||||
{
|
||||
LiquidData map_data;
|
||||
ZLiquidStatus map_result = gmap->GetLiquidStatus(x, y, z, ReqLiquidType, &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 = m_parentTerrainMap->GetGrid(terrainMapId, x, y))
|
||||
{
|
||||
if (data)
|
||||
LiquidData map_data;
|
||||
ZLiquidStatus map_result = gmap->GetLiquidStatus(x, y, z, ReqLiquidType, &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))
|
||||
{
|
||||
// hardcoded in client like this
|
||||
if (GetId() == 530 && map_data.entry == 2)
|
||||
map_data.entry = 15;
|
||||
if (data)
|
||||
{
|
||||
// hardcoded in client like this
|
||||
if (GetId() == 530 && map_data.entry == 2)
|
||||
map_data.entry = 15;
|
||||
|
||||
*data = map_data;
|
||||
*data = map_data;
|
||||
}
|
||||
return map_result;
|
||||
}
|
||||
return map_result;
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
void Map::GetFullTerrainStatusForPosition(PhaseShift const& phaseShift, float x, float y, float z, PositionFullTerrainStatus& data, uint8 reqLiquidType) const
|
||||
{
|
||||
VMAP::IVMapManager* vmgr = VMAP::VMapFactory::createOrGetVMapManager();
|
||||
VMAP::AreaAndLiquidData vmapData;
|
||||
uint32 terrainMapId = PhasingHandler::GetTerrainMapId(phaseShift, this, x, y);
|
||||
GridMap* gmap = m_parentTerrainMap->GetGrid(terrainMapId, x, y);
|
||||
vmgr->getAreaAndLiquidData(terrainMapId, x, y, z, reqLiquidType, vmapData);
|
||||
|
||||
uint32 gridAreaId = 0;
|
||||
float gridMapHeight = INVALID_HEIGHT;
|
||||
if (gmap)
|
||||
{
|
||||
gridAreaId = gmap->getArea(x, y);
|
||||
gridMapHeight = gmap->getHeight(x, y);
|
||||
}
|
||||
|
||||
bool vmapLocation = false;
|
||||
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;
|
||||
vmapLocation = true;
|
||||
}
|
||||
|
||||
if (vmapLocation)
|
||||
{
|
||||
if (vmapData.areaInfo)
|
||||
{
|
||||
data.areaInfo = boost::in_place(vmapData.areaInfo->adtId, vmapData.areaInfo->rootId, vmapData.areaInfo->groupId, vmapData.areaInfo->mogpFlags);
|
||||
// wmo found
|
||||
WMOAreaTableEntry const* wmoEntry = GetWMOAreaTableEntryByTripple(vmapData.areaInfo->rootId, vmapData.areaInfo->adtId, vmapData.areaInfo->groupId);
|
||||
data.outdoors = (vmapData.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(vmapData.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
|
||||
data.liquidStatus = LIQUID_MAP_NO_WATER;
|
||||
if (vmapLocation && vmapData.liquidInfo && vmapData.liquidInfo->level > vmapData.floorZ)
|
||||
{
|
||||
uint32 liquidType = vmapData.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 = boost::in_place();
|
||||
data.liquidInfo->level = vmapData.liquidInfo->level;
|
||||
data.liquidInfo->depth_level = vmapData.floorZ;
|
||||
data.liquidInfo->entry = liquidType;
|
||||
data.liquidInfo->type_flags = 1 << liquidFlagType;
|
||||
|
||||
float delta = vmapData.liquidInfo->level - z;
|
||||
if (delta > 2.0f)
|
||||
data.liquidStatus = LIQUID_MAP_UNDER_WATER;
|
||||
else if (delta > 0.0f)
|
||||
data.liquidStatus = LIQUID_MAP_IN_WATER;
|
||||
else if (delta > -0.1f)
|
||||
data.liquidStatus = LIQUID_MAP_WATER_WALK;
|
||||
else
|
||||
data.liquidStatus = LIQUID_MAP_ABOVE_WATER;
|
||||
}
|
||||
// look up liquid data from grid map
|
||||
if (gmap && useGridLiquid)
|
||||
{
|
||||
LiquidData gridMapLiquid;
|
||||
ZLiquidStatus gridMapStatus = gmap->GetLiquidStatus(x, y, z, reqLiquidType, &gridMapLiquid);
|
||||
if (gridMapStatus != LIQUID_MAP_NO_WATER && (gridMapLiquid.level > vmapData.floorZ))
|
||||
{
|
||||
if (GetId() == 530 && gridMapLiquid.entry == 2)
|
||||
gridMapLiquid.entry = 15;
|
||||
data.liquidInfo = gridMapLiquid;
|
||||
data.liquidStatus = gridMapStatus;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
float Map::GetWaterLevel(PhaseShift const& phaseShift, float x, float y) const
|
||||
{
|
||||
if (GridMap* gmap = m_parentTerrainMap->GetGrid(PhasingHandler::GetTerrainMapId(phaseShift, this, x, y), x, y))
|
||||
|
||||
+29
-13
@@ -145,6 +145,9 @@ enum ZLiquidStatus : uint32
|
||||
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
|
||||
@@ -163,6 +166,25 @@ struct LiquidData
|
||||
float depth_level;
|
||||
};
|
||||
|
||||
struct PositionFullTerrainStatus
|
||||
{
|
||||
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;
|
||||
};
|
||||
|
||||
uint32 areaId;
|
||||
float floorZ;
|
||||
bool outdoors;
|
||||
ZLiquidStatus liquidStatus;
|
||||
Optional<AreaInfo> areaInfo;
|
||||
Optional<LiquidData> liquidInfo;
|
||||
};
|
||||
|
||||
class TC_GAME_API GridMap
|
||||
{
|
||||
uint32 _flags;
|
||||
@@ -195,11 +217,16 @@ class TC_GAME_API GridMap
|
||||
uint8 _liquidOffY;
|
||||
uint8 _liquidWidth;
|
||||
uint8 _liquidHeight;
|
||||
|
||||
uint16* _holes;
|
||||
|
||||
bool _fileExists;
|
||||
|
||||
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;
|
||||
@@ -218,7 +245,6 @@ public:
|
||||
uint16 getArea(float x, float y) const;
|
||||
inline float getHeight(float x, float y) const {return (this->*_gridGetHeight)(x, y);}
|
||||
float getLiquidLevel(float x, float y) const;
|
||||
uint8 getTerrainType(float x, float y) const;
|
||||
ZLiquidStatus GetLiquidStatus(float x, float y, float z, uint8 ReqLiquidType, LiquidData* data = 0);
|
||||
bool fileExists() const { return _fileExists; }
|
||||
};
|
||||
@@ -370,17 +396,10 @@ class TC_GAME_API Map : public GridRefManager<NGridType>
|
||||
// can return INVALID_HEIGHT if under z+2 z coord not found height
|
||||
float GetStaticHeight(PhaseShift const& phaseShift, float x, float y, float z, bool checkVMap = true, float maxSearchDist = DEFAULT_HEIGHT_SEARCH) const;
|
||||
|
||||
void GetFullTerrainStatusForPosition(PhaseShift const& phaseShift, float x, float y, float z, PositionFullTerrainStatus& data, uint8 reqLiquidType = MAP_ALL_LIQUIDS) const;
|
||||
ZLiquidStatus GetLiquidStatus(PhaseShift const& phaseShift, float x, float y, float z, uint8 ReqLiquidType, LiquidData* data = nullptr) const;
|
||||
|
||||
bool GetAreaInfo(PhaseShift const& phaseShift, float x, float y, float z, uint32& mogpflags, int32& adtId, int32& rootId, int32& groupId) const;
|
||||
|
||||
|
||||
uint32 GetAreaId(PhaseShift const& phaseShift, float x, float y, float z, bool *isOutdoors) const;
|
||||
uint32 GetAreaId(PhaseShift const& phaseShift, float x, float y, float z) const
|
||||
{
|
||||
return GetAreaId(phaseShift, x, y, z, nullptr);
|
||||
}
|
||||
|
||||
uint32 GetAreaId(PhaseShift const& phaseShift, float x, float y, float z) const;
|
||||
uint32 GetAreaId(PhaseShift const& phaseShift, Position const& pos) const
|
||||
{
|
||||
return GetAreaId(phaseShift, pos.GetPositionX(), pos.GetPositionY(), pos.GetPositionZ());
|
||||
@@ -398,9 +417,6 @@ class TC_GAME_API Map : public GridRefManager<NGridType>
|
||||
GetZoneAndAreaId(phaseShift, zoneid, areaid, pos.GetPositionX(), pos.GetPositionY(), pos.GetPositionZ());
|
||||
}
|
||||
|
||||
bool IsOutdoors(PhaseShift const& phaseShift, float x, float y, float z) const;
|
||||
|
||||
uint8 GetTerrainType(PhaseShift const& phaseShift, float x, float y) const;
|
||||
float GetWaterLevel(PhaseShift const& phaseShift, float x, float y) const;
|
||||
bool IsInWater(PhaseShift const& phaseShift, float x, float y, float z, LiquidData* data = nullptr) const;
|
||||
bool IsUnderWater(PhaseShift const& phaseShift, float x, float y, float z) const;
|
||||
|
||||
@@ -22,6 +22,8 @@
|
||||
#include "Define.h"
|
||||
#include "DetourNavMesh.h"
|
||||
|
||||
float const GROUND_HEIGHT_TOLERANCE = 0.05f; // Extra tolerance to z position to check if it is in air or on ground.
|
||||
|
||||
enum SpellEffIndex : uint8
|
||||
{
|
||||
EFFECT_0 = 0,
|
||||
|
||||
@@ -5095,11 +5095,11 @@ SpellCastResult Spell::CheckCast(bool strict, uint32* param1 /*= nullptr*/, uint
|
||||
if (m_caster->GetTypeId() == TYPEID_PLAYER && VMAP::VMapFactory::createOrGetVMapManager()->isLineOfSightCalcEnabled())
|
||||
{
|
||||
if (m_spellInfo->HasAttribute(SPELL_ATTR0_OUTDOORS_ONLY) &&
|
||||
!m_caster->GetMap()->IsOutdoors(m_caster->GetPhaseShift(), m_caster->GetPositionX(), m_caster->GetPositionY(), m_caster->GetPositionZ()))
|
||||
!m_caster->IsOutdoors())
|
||||
return SPELL_FAILED_ONLY_OUTDOORS;
|
||||
|
||||
if (m_spellInfo->HasAttribute(SPELL_ATTR0_INDOORS_ONLY) &&
|
||||
m_caster->GetMap()->IsOutdoors(m_caster->GetPhaseShift(), m_caster->GetPositionX(), m_caster->GetPositionY(), m_caster->GetPositionZ()))
|
||||
!m_caster->IsOutdoors())
|
||||
return SPELL_FAILED_ONLY_INDOORS;
|
||||
}
|
||||
|
||||
|
||||
@@ -265,7 +265,7 @@ public:
|
||||
|
||||
if (haveVMap)
|
||||
{
|
||||
if (map->IsOutdoors(object->GetPhaseShift(), object->GetPositionX(), object->GetPositionY(), object->GetPositionZ()))
|
||||
if (object->IsOutdoors())
|
||||
handler->PSendSysMessage(LANG_GPS_POSITION_OUTDOORS);
|
||||
else
|
||||
handler->PSendSysMessage(LANG_GPS_POSITION_INDOORS);
|
||||
|
||||
Reference in new issue
Block a user