aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/common/Collision/Management/IVMapManager.h24
-rw-r--r--src/common/Collision/Management/VMapManager2.cpp31
-rw-r--r--src/common/Collision/Management/VMapManager2.h1
-rw-r--r--src/common/Collision/Maps/MapTree.h1
-rw-r--r--src/common/Collision/Models/WorldModel.cpp1
-rw-r--r--src/server/game/Entities/Creature/Creature.cpp2
-rw-r--r--src/server/game/Entities/Object/Object.cpp44
-rw-r--r--src/server/game/Entities/Object/Object.h25
-rw-r--r--src/server/game/Entities/Player/Player.cpp95
-rw-r--r--src/server/game/Entities/Player/Player.h2
-rw-r--r--src/server/game/Entities/Unit/Unit.cpp60
-rw-r--r--src/server/game/Entities/Unit/Unit.h4
-rw-r--r--src/server/game/Maps/Map.cpp125
-rw-r--r--src/server/game/Maps/Map.h33
-rw-r--r--src/server/game/Movement/PathGenerator.cpp4
-rw-r--r--src/server/game/Spells/Spell.cpp2
-rw-r--r--src/server/scripts/Commands/cs_misc.cpp2
17 files changed, 312 insertions, 144 deletions
diff --git a/src/common/Collision/Management/IVMapManager.h b/src/common/Collision/Management/IVMapManager.h
index 2188da1cadc..e77987a721d 100644
--- a/src/common/Collision/Management/IVMapManager.h
+++ b/src/common/Collision/Management/IVMapManager.h
@@ -22,6 +22,7 @@
#include <string>
#include "Define.h"
#include "ModelIgnoreFlags.h"
+#include "Common.h"
//===========================================================
@@ -49,6 +50,27 @@ 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
{
@@ -102,6 +124,8 @@ namespace VMAP
*/
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;
+ // get both area + liquid data in a single vmap lookup
+ virtual void getAreaAndLiquidData(unsigned int mapId, float x, float y, float z, uint8 reqLiquidType, AreaAndLiquidData& data) const=0;
};
}
diff --git a/src/common/Collision/Management/VMapManager2.cpp b/src/common/Collision/Management/VMapManager2.cpp
index 9981f722456..33bf7338616 100644
--- a/src/common/Collision/Management/VMapManager2.cpp
+++ b/src/common/Collision/Management/VMapManager2.cpp
@@ -279,6 +279,37 @@ namespace VMAP
return false;
}
+ void VMapManager2::getAreaAndLiquidData(unsigned int 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;
+ }
+ 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 = 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
diff --git a/src/common/Collision/Management/VMapManager2.h b/src/common/Collision/Management/VMapManager2.h
index fd325b16434..3fdc427d6eb 100644
--- a/src/common/Collision/Management/VMapManager2.h
+++ b/src/common/Collision/Management/VMapManager2.h
@@ -118,6 +118,7 @@ namespace VMAP
bool getAreaInfo(unsigned int pMapId, float x, float y, float& z, uint32& flags, int32& adtId, int32& rootId, int32& groupId) const override;
bool GetLiquidLevel(uint32 pMapId, float x, float y, float z, uint8 reqLiquidType, float& level, float& floor, uint32& type) const override;
+ void getAreaAndLiquidData(unsigned int 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);
diff --git a/src/common/Collision/Maps/MapTree.h b/src/common/Collision/Maps/MapTree.h
index f5c11dd2bce..bc18e07789b 100644
--- a/src/common/Collision/Maps/MapTree.h
+++ b/src/common/Collision/Maps/MapTree.h
@@ -35,6 +35,7 @@ namespace VMAP
struct TC_COMMON_API LocationInfo
{
LocationInfo(): hitInstance(nullptr), hitModel(nullptr), ground_Z(-G3D::finf()) { }
+ int32 rootId;
const ModelInstance* hitInstance;
const GroupModel* hitModel;
float ground_Z;
diff --git a/src/common/Collision/Models/WorldModel.cpp b/src/common/Collision/Models/WorldModel.cpp
index 19b40b6de18..d04bcf4d241 100644
--- a/src/common/Collision/Models/WorldModel.cpp
+++ b/src/common/Collision/Models/WorldModel.cpp
@@ -531,6 +531,7 @@ namespace VMAP
groupTree.intersectPoint(p, callback);
if (callback.hit != groupModels.end())
{
+ info.rootId = RootWMOID;
info.hitModel = &(*callback.hit);
dist = callback.zDist;
return true;
diff --git a/src/server/game/Entities/Creature/Creature.cpp b/src/server/game/Entities/Creature/Creature.cpp
index 8c8a816ac19..1f9fce51dcb 100644
--- a/src/server/game/Entities/Creature/Creature.cpp
+++ b/src/server/game/Entities/Creature/Creature.cpp
@@ -2914,7 +2914,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(GetPhaseMask(), 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
diff --git a/src/server/game/Entities/Object/Object.cpp b/src/server/game/Entities/Object/Object.cpp
index b2fc5314c8b..8eb18694c84 100644
--- a/src/server/game/Entities/Object/Object.cpp
+++ b/src/server/game/Entities/Object/Object.cpp
@@ -1000,7 +1000,7 @@ void MovementInfo::OutDebug()
WorldObject::WorldObject(bool isWorldObject) : WorldLocation(), LastUsedScriptID(0),
m_name(""), m_isActive(false), m_isWorldObject(isWorldObject), m_zoneScript(NULL),
-m_transport(NULL), m_currMap(NULL), m_InstanceId(0),
+m_transport(NULL), m_zoneId(0), m_areaId(0), m_staticFloorZ(VMAP_INVALID_HEIGHT), m_currMap(NULL), m_InstanceId(0),
m_phaseMask(PHASEMASK_NORMAL), m_notifyflags(0), m_executed_notifies(0)
{
m_serverSideVisibility.SetValue(SERVERSIDE_VISIBILITY_GHOST, GHOST_VISIBILITY_ALIVE | GHOST_VISIBILITY_GHOST);
@@ -1074,29 +1074,36 @@ void WorldObject::_Create(ObjectGuid::LowType guidlow, HighGuid guidhigh, uint32
m_phaseMask = phaseMask;
}
-void WorldObject::RemoveFromWorld()
+void WorldObject::UpdatePositionData()
{
- if (!IsInWorld())
- return;
-
- DestroyForNearbyPlayers();
-
- Object::RemoveFromWorld();
+ PositionFullTerrainStatus data;
+ GetMap()->GetFullTerrainStatusForPosition(GetPositionX(), GetPositionY(), GetPositionZ(), data);
+ ProcessPositionDataChanged(data);
}
-uint32 WorldObject::GetZoneId() const
+void WorldObject::ProcessPositionDataChanged(PositionFullTerrainStatus const& data)
{
- return GetBaseMap()->GetZoneId(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_staticFloorZ = data.floorZ;
}
-uint32 WorldObject::GetAreaId() const
+void WorldObject::AddToWorld()
{
- return GetBaseMap()->GetAreaId(m_positionX, m_positionY, m_positionZ);
+ Object::AddToWorld();
+ GetBaseMap()->GetZoneAndAreaId(m_zoneId, m_areaId, GetPositionX(), GetPositionY(), GetPositionZ());
}
-void WorldObject::GetZoneAndAreaId(uint32& zoneid, uint32& areaid) const
+void WorldObject::RemoveFromWorld()
{
- GetBaseMap()->GetZoneAndAreaId(zoneid, areaid, m_positionX, m_positionY, m_positionZ);
+ if (!IsInWorld())
+ return;
+
+ DestroyForNearbyPlayers();
+
+ Object::RemoveFromWorld();
}
InstanceScript* WorldObject::GetInstanceScript()
@@ -2290,7 +2297,7 @@ float NormalizeZforCollision(WorldObject* obj, float x, float y, float z)
return z;
}
LiquidData liquid_status;
- ZLiquidStatus res = obj->GetMap()->getLiquidStatus(x, y, z, MAP_ALL_LIQUIDS, &liquid_status);
+ ZLiquidStatus res = obj->GetMap()->GetLiquidStatus(x, y, z, MAP_ALL_LIQUIDS, &liquid_status);
if (res && liquid_status.level > helper) // water must be above ground
{
if (liquid_status.level > z) // z is underwater
@@ -2547,6 +2554,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(GetPhaseMask(), 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;
diff --git a/src/server/game/Entities/Object/Object.h b/src/server/game/Entities/Object/Object.h
index ffa7183a8b1..56842bd6d1e 100644
--- a/src/server/game/Entities/Object/Object.h
+++ b/src/server/game/Entities/Object/Object.h
@@ -436,7 +436,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() override;
+ 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;
@@ -462,9 +463,9 @@ class TC_GAME_API WorldObject : public Object, public WorldLocation
bool InSamePhase(WorldObject const* obj) const;
bool InSamePhase(uint32 phasemask) const { return (GetPhaseMask() & phasemask) != 0; }
- 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; }
InstanceScript* GetInstanceScript();
@@ -574,6 +575,7 @@ class TC_GAME_API WorldObject : public Object, public WorldLocation
{
UpdateObjectVisibility(true);
}
+ void UpdatePositionData();
void BuildUpdate(UpdateDataMapType&) override;
@@ -618,6 +620,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;
+
protected:
std::string m_name;
bool m_isActive;
@@ -627,6 +631,11 @@ 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;
+
//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!
@@ -639,11 +648,11 @@ class TC_GAME_API WorldObject : public Object, public WorldLocation
//difference from IsAlwaysVisibleFor: 1. after distance check; 2. use owner or charmer as seer
virtual bool IsAlwaysDetectableFor(WorldObject const* /*seer*/) const { return false; }
private:
- Map* m_currMap; //current object's Map location
+ Map* m_currMap; // current object's Map location
- //uint32 m_mapId; // object at map with map_id
- uint32 m_InstanceId; // in map copy with instance id
- uint32 m_phaseMask; // in area phase state
+ //uint32 m_mapId; // object at map with map_id
+ uint32 m_InstanceId; // in map copy with instance id
+ uint32 m_phaseMask; // in area phase state
uint16 m_notifyflags;
uint16 m_executed_notifies;
diff --git a/src/server/game/Entities/Player/Player.cpp b/src/server/game/Entities/Player/Player.cpp
index 1de2ad3de79..7d90e05a11d 100644
--- a/src/server/game/Entities/Player/Player.cpp
+++ b/src/server/game/Entities/Player/Player.cpp
@@ -24097,77 +24097,52 @@ 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(x, y, z, MAP_ALL_LIQUIDS, &liquid_status);
- if (!res)
- {
- m_MirrorTimerFlags &= ~(UNDERWATER_INWATER | UNDERWATER_INLAVA | UNDERWATER_INSLIME | UNDERWARER_INDARKWATER);
- if (_lastLiquid && _lastLiquid->SpellId)
- RemoveAurasDueToSpell(_lastLiquid->SpellId);
-
- _lastLiquid = nullptr;
+ if (IsFlying())
return;
- }
- if (uint32 liqEntry = liquid_status.entry)
- {
- LiquidTypeEntry const* liquid = sLiquidTypeStore.LookupEntry(liqEntry);
- if (_lastLiquid && _lastLiquid->SpellId && _lastLiquid->Id != liqEntry)
- RemoveAurasDueToSpell(_lastLiquid->SpellId);
+ // process liquid auras using generic unit code
+ Unit::ProcessTerrainStatusUpdate(status, liquidData);
- if (liquid && liquid->SpellId)
+ // player specific logic for mirror timers
+ if (status && liquidData)
+ {
+ // 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 |= UNDERWARER_INDARKWATER;
else
- m_MirrorTimerFlags &= ~UNDERWATER_INWATER;
- }
+ m_MirrorTimerFlags &= ~UNDERWARER_INDARKWATER;
- // 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;
+ // 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_INWATER | UNDERWATER_INLAVA | UNDERWATER_INSLIME | UNDERWARER_INDARKWATER);
}
void Player::SetCanParry(bool value)
diff --git a/src/server/game/Entities/Player/Player.h b/src/server/game/Entities/Player/Player.h
index 1b14046f7a6..c1ff1e01801 100644
--- a/src/server/game/Entities/Player/Player.h
+++ b/src/server/game/Entities/Player/Player.h
@@ -1808,7 +1808,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(const Position &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 const* data, bool self) override { SendMessageToSetInRange(data, GetVisibilityRange(), self); }
void SendMessageToSetInRange(WorldPacket const* data, float dist, bool self) override;
diff --git a/src/server/game/Entities/Unit/Unit.cpp b/src/server/game/Entities/Unit/Unit.cpp
index e1633edbeaa..dcfe56ed69c 100644
--- a/src/server/game/Entities/Unit/Unit.cpp
+++ b/src/server/game/Entities/Unit/Unit.cpp
@@ -470,7 +470,6 @@ void Unit::Update(uint32 p_time)
UpdateSplineMovement(p_time);
i_motionMaster->UpdateMotion(p_time);
- UpdateUnderwaterState(GetMap(), GetPositionX(), GetPositionY(), GetPositionZ());
}
bool Unit::haveOffhandWeapon() const
@@ -3353,48 +3352,34 @@ bool Unit::IsUnderWater() const
return GetBaseMap()->IsUnderWater(GetPositionX(), GetPositionY(), GetPositionZ());
}
-void Unit::UpdateUnderwaterState(Map* m, float x, float y, float z)
+void Unit::ProcessPositionDataChanged(PositionFullTerrainStatus const& data)
{
- if (IsFlying() || (!IsPet() && !IsVehicle()))
- return;
+ WorldObject::ProcessPositionDataChanged(data);
+ ProcessTerrainStatusUpdate(data.liquidStatus, data.liquidInfo);
+}
- LiquidData liquid_status;
- ZLiquidStatus res = m->getLiquidStatus(x, y, z, MAP_ALL_LIQUIDS, &liquid_status);
- if (!res)
- {
- if (_lastLiquid && _lastLiquid->SpellId)
- RemoveAurasDueToSpell(_lastLiquid->SpellId);
+void Unit::ProcessTerrainStatusUpdate(ZLiquidStatus status, Optional<LiquidData> const& liquidData)
+{
+ if (IsFlying() || (!IsControlledByPlayer()))
+ return;
+ // 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);
- _lastLiquid = NULL;
- return;
- }
- if (uint32 liqEntry = liquid_status.entry)
+ // liquid aura handling
+ LiquidTypeEntry const* curLiquid = nullptr;
+ if ((status & MAP_LIQUID_STATUS_SWIMMING) && liquidData)
+ curLiquid = sLiquidTypeStore.LookupEntry(liquidData->entry);
+ if (curLiquid != _lastLiquid)
{
- LiquidTypeEntry const* liquid = sLiquidTypeStore.LookupEntry(liqEntry);
- if (_lastLiquid && _lastLiquid->SpellId && _lastLiquid->Id != liqEntry)
+ if (_lastLiquid && _lastLiquid->SpellId)
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;
+ if (curLiquid && curLiquid->SpellId)
+ CastSpell(this, curLiquid->SpellId, true);
+ _lastLiquid = curLiquid;
}
}
@@ -13906,8 +13891,7 @@ 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);
+ UpdatePositionData();
return (relocated || turn);
}
diff --git a/src/server/game/Entities/Unit/Unit.h b/src/server/game/Entities/Unit/Unit.h
index 2c58b250b3c..61e1ad86c3e 100644
--- a/src/server/game/Entities/Unit/Unit.h
+++ b/src/server/game/Entities/Unit/Unit.h
@@ -1581,7 +1581,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);
@@ -2309,6 +2308,9 @@ 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);
diff --git a/src/server/game/Maps/Map.cpp b/src/server/game/Maps/Map.cpp
index b3eb7fa275d..4bac7b84669 100644
--- a/src/server/game/Maps/Map.cpp
+++ b/src/server/game/Maps/Map.cpp
@@ -993,6 +993,7 @@ void Map::PlayerRelocation(Player* player, float x, float y, float z, float orie
AddToGrid(player, new_cell);
}
+ player->UpdatePositionData();
player->UpdateObjectVisibility(false);
}
@@ -1027,6 +1028,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);
}
@@ -1057,6 +1059,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);
}
@@ -1089,6 +1092,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);
}
@@ -1182,6 +1186,7 @@ void Map::MoveAllCreaturesInMoveList()
if (c->IsVehicle())
c->GetVehicleKit()->RelocatePassengers();
//CreatureRelocationNotify(c, new_cell, new_cell.cellCoord());
+ c->UpdatePositionData();
c->UpdateObjectVisibility(false);
}
else
@@ -1236,6 +1241,7 @@ void Map::MoveAllGameObjectsInMoveList()
// update pos
go->Relocate(go->_newPosition);
go->UpdateModelPosition();
+ go->UpdatePositionData();
go->UpdateObjectVisibility(false);
}
else
@@ -1280,6 +1286,7 @@ void Map::MoveAllDynamicObjectsInMoveList()
{
// update pos
dynObj->Relocate(dynObj->_newPosition);
+ dynObj->UpdatePositionData();
dynObj->UpdateObjectVisibility(false);
}
else
@@ -1500,6 +1507,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;
}
@@ -1525,6 +1533,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;
}
@@ -2203,7 +2212,7 @@ uint8 GridMap::getTerrainType(float x, float y) const
}
// Get water state on map
-inline ZLiquidStatus GridMap::getLiquidStatus(float x, float y, float z, uint8 ReqLiquidType, LiquidData* data)
+inline ZLiquidStatus GridMap::GetLiquidStatus(float x, float y, float z, uint8 ReqLiquidType, LiquidData* data)
{
// Check water type (if no water return)
if (!_liquidType && !_liquidFlags)
@@ -2321,7 +2330,7 @@ float Map::GetWaterOrGroundLevel(uint32 phasemask, float x, float y, float z, fl
LiquidData liquid_status;
- ZLiquidStatus res = getLiquidStatus(x, y, ground_z, MAP_ALL_LIQUIDS, &liquid_status);
+ ZLiquidStatus res = GetLiquidStatus(x, y, ground_z, MAP_ALL_LIQUIDS, &liquid_status);
return res ? liquid_status.level : ground_z;
}
@@ -2480,11 +2489,6 @@ uint32 Map::GetAreaId(float x, float y, float z, bool *isOutdoors) const
return areaId;
}
-uint32 Map::GetAreaId(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);
@@ -2511,7 +2515,7 @@ uint8 Map::GetTerrainType(float x, float y) const
return 0;
}
-ZLiquidStatus Map::getLiquidStatus(float x, float y, float z, uint8 ReqLiquidType, LiquidData* data) const
+ZLiquidStatus Map::GetLiquidStatus(float x, float y, float z, uint8 ReqLiquidType, LiquidData* data) const
{
ZLiquidStatus result = LIQUID_MAP_NO_WATER;
VMAP::IVMapManager* vmgr = VMAP::VMapFactory::createOrGetVMapManager();
@@ -2520,7 +2524,7 @@ ZLiquidStatus Map::getLiquidStatus(float x, float y, float z, uint8 ReqLiquidTyp
uint32 liquid_type = 0;
if (vmgr->GetLiquidLevel(GetId(), x, y, z, ReqLiquidType, liquid_level, ground_level, liquid_type))
{
- TC_LOG_DEBUG("maps", "getLiquidStatus(): vmap liquid level: %f ground: %f type: %u", liquid_level, ground_level, liquid_type);
+ 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)
{
@@ -2578,7 +2582,7 @@ ZLiquidStatus Map::getLiquidStatus(float x, float y, float z, uint8 ReqLiquidTyp
if (GridMap* gmap = const_cast<Map*>(this)->GetGrid(x, y))
{
LiquidData map_data;
- ZLiquidStatus map_result = gmap->getLiquidStatus(x, y, z, ReqLiquidType, &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))
{
@@ -2596,6 +2600,103 @@ ZLiquidStatus Map::getLiquidStatus(float x, float y, float z, uint8 ReqLiquidTyp
return result;
}
+void Map::GetFullTerrainStatusForPosition(float x, float y, float z, PositionFullTerrainStatus& data, uint8 reqLiquidType) const
+{
+ VMAP::IVMapManager* vmgr = VMAP::VMapFactory::createOrGetVMapManager();
+ VMAP::AreaAndLiquidData vmapData;
+ vmgr->getAreaAndLiquidData(GetId(), x, y, z, reqLiquidType, vmapData);
+ if (vmapData.areaInfo)
+ data.areaInfo = boost::in_place(vmapData.areaInfo->adtId, vmapData.areaInfo->rootId, vmapData.areaInfo->groupId, vmapData.areaInfo->mogpFlags);
+
+ GridMap* gmap = const_cast<Map*>(this)->GetGrid(x, y);
+ float mapHeight = gmap->getHeight(x, y);
+
+ // area lookup
+ AreaTableEntry const* areaEntry = nullptr;
+ if (vmapData.areaInfo && (z + 2.0f <= mapHeight || mapHeight <= vmapData.floorZ))
+ if (WMOAreaTableEntry const* wmoEntry = GetWMOAreaTableEntryByTripple(vmapData.areaInfo->rootId, vmapData.areaInfo->adtId, vmapData.areaInfo->groupId))
+ areaEntry = sAreaTableStore.LookupEntry(wmoEntry->areaId);
+
+ if (areaEntry)
+ {
+ data.floorZ = vmapData.floorZ;
+ data.areaId = areaEntry->ID;
+ }
+ else
+ {
+ data.floorZ = mapHeight;
+ if (gmap)
+ data.areaId = gmap->getArea(x, y);
+ else
+ data.areaId = 0;
+
+ if (!data.areaId)
+ data.areaId = i_mapEntry->linked_zone;
+
+ if (data.areaId)
+ areaEntry = sAreaTableStore.LookupEntry(data.areaId);
+ }
+
+ // liquid processing
+ data.liquidStatus = LIQUID_MAP_NO_WATER;
+ if (vmapData.liquidInfo && vmapData.liquidInfo->level > vmapData.floorZ && z + 2.0f > 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 && (data.liquidStatus == LIQUID_MAP_ABOVE_WATER || data.liquidStatus == LIQUID_MAP_NO_WATER))
+ {
+ 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(float x, float y) const
{
if (GridMap* gmap = const_cast<Map*>(this)->GetGrid(x, y))
@@ -2633,12 +2734,12 @@ bool Map::IsInWater(float x, float y, float pZ, LiquidData* data) 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)) != 0;
+ return (GetLiquidStatus(x, y, pZ, MAP_ALL_LIQUIDS, liquid_ptr) & (LIQUID_MAP_IN_WATER | LIQUID_MAP_UNDER_WATER)) != 0;
}
bool Map::IsUnderWater(float x, float y, float z) const
{
- return (getLiquidStatus(x, y, z, MAP_LIQUID_TYPE_WATER | MAP_LIQUID_TYPE_OCEAN) & LIQUID_MAP_UNDER_WATER) != 0;
+ return (GetLiquidStatus(x, y, z, MAP_LIQUID_TYPE_WATER | MAP_LIQUID_TYPE_OCEAN) & LIQUID_MAP_UNDER_WATER) != 0;
}
bool Map::CheckGridIntegrity(Creature* c, bool moved) const
diff --git a/src/server/game/Maps/Map.h b/src/server/game/Maps/Map.h
index 600594d0861..b6509ceb9f3 100644
--- a/src/server/game/Maps/Map.h
+++ b/src/server/game/Maps/Map.h
@@ -136,6 +136,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
@@ -155,6 +158,24 @@ 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;
+ ZLiquidStatus liquidStatus;
+ Optional<AreaInfo> areaInfo;
+ Optional<LiquidData> liquidInfo;
+};
+
class TC_GAME_API GridMap
{
uint32 _flags;
@@ -213,7 +234,7 @@ public:
float getMinHeight(float x, float y) const;
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);
+ ZLiquidStatus GetLiquidStatus(float x, float y, float z, uint8 ReqLiquidType, LiquidData* data = 0);
};
#pragma pack(push, 1)
@@ -336,11 +357,11 @@ class TC_GAME_API Map : public GridRefManager<NGridType>
float GetHeight(float x, float y, float z, bool checkVMap = true, float maxSearchDist = DEFAULT_HEIGHT_SEARCH) const;
float GetMinHeight(float x, float y) const;
- ZLiquidStatus getLiquidStatus(float x, float y, float z, uint8 ReqLiquidType, LiquidData* data = nullptr) const;
+ void GetFullTerrainStatusForPosition(float x, float y, float z, PositionFullTerrainStatus& data, uint8 reqLiquidType = MAP_ALL_LIQUIDS) const;
+ ZLiquidStatus GetLiquidStatus(float x, float y, float z, uint8 ReqLiquidType, LiquidData* data = nullptr) const;
- 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;
- uint32 GetAreaId(float x, float y, float z) const;
+ uint32 GetAreaId(float x, float y, float z, bool *isOutdoors = nullptr) const;
uint32 GetZoneId(float x, float y, float z) const;
void GetZoneAndAreaId(uint32& zoneid, uint32& areaid, float x, float y, float z) const;
@@ -503,6 +524,10 @@ class TC_GAME_API Map : public GridRefManager<NGridType>
void RemoveGameObjectModel(const GameObjectModel& model) { _dynamicTree.remove(model); }
void InsertGameObjectModel(const GameObjectModel& model) { _dynamicTree.insert(model); }
bool ContainsGameObjectModel(const GameObjectModel& model) const { return _dynamicTree.contains(model);}
+ float GetGameObjectFloor(uint32 phasemask, float x, float y, float z, float maxSearchDist = DEFAULT_HEIGHT_SEARCH) const
+ {
+ return _dynamicTree.getHeight(x, y, z, phasemask, maxSearchDist);
+ }
bool getObjectHitPos(uint32 phasemask, float x1, float y1, float z1, float x2, float y2, float z2, float& rx, float &ry, float& rz, float modifyDist);
/*
diff --git a/src/server/game/Movement/PathGenerator.cpp b/src/server/game/Movement/PathGenerator.cpp
index 3f8e7d44ff2..6075b9352e8 100644
--- a/src/server/game/Movement/PathGenerator.cpp
+++ b/src/server/game/Movement/PathGenerator.cpp
@@ -184,7 +184,7 @@ void PathGenerator::BuildPolyPath(G3D::Vector3 const& startPos, G3D::Vector3 con
// Check both start and end points, if they're both in water, then we can *safely* let the creature move
for (uint32 i = 0; i < _pathPoints.size(); ++i)
{
- ZLiquidStatus status = _sourceUnit->GetBaseMap()->getLiquidStatus(_pathPoints[i].x, _pathPoints[i].y, _pathPoints[i].z, MAP_ALL_LIQUIDS, NULL);
+ ZLiquidStatus status = _sourceUnit->GetBaseMap()->GetLiquidStatus(_pathPoints[i].x, _pathPoints[i].y, _pathPoints[i].z, MAP_ALL_LIQUIDS, NULL);
// One of the points is not in the water, cancel movement.
if (status == LIQUID_MAP_NO_WATER)
{
@@ -647,7 +647,7 @@ void PathGenerator::UpdateFilter()
NavTerrain PathGenerator::GetNavTerrain(float x, float y, float z)
{
LiquidData data;
- ZLiquidStatus liquidStatus = _sourceUnit->GetBaseMap()->getLiquidStatus(x, y, z, MAP_ALL_LIQUIDS, &data);
+ ZLiquidStatus liquidStatus = _sourceUnit->GetBaseMap()->GetLiquidStatus(x, y, z, MAP_ALL_LIQUIDS, &data);
if (liquidStatus == LIQUID_MAP_NO_WATER)
return NAV_GROUND;
diff --git a/src/server/game/Spells/Spell.cpp b/src/server/game/Spells/Spell.cpp
index 4b08d3bf9c3..7b88ff487fd 100644
--- a/src/server/game/Spells/Spell.cpp
+++ b/src/server/game/Spells/Spell.cpp
@@ -1291,7 +1291,7 @@ void Spell::SelectImplicitCasterDestTargets(SpellEffIndex effIndex, SpellImplici
float ground = m_caster->GetMap()->GetHeight(m_caster->GetPhaseMask(), x, y, z, true, 50.0f);
float liquidLevel = VMAP_INVALID_HEIGHT_VALUE;
LiquidData liquidData;
- if (m_caster->GetMap()->getLiquidStatus(x, y, z, MAP_ALL_LIQUIDS, &liquidData))
+ if (m_caster->GetMap()->GetLiquidStatus(x, y, z, MAP_ALL_LIQUIDS, &liquidData))
liquidLevel = liquidData.level;
if (liquidLevel <= ground) // When there is no liquid Map::GetWaterOrGroundLevel returns ground level
diff --git a/src/server/scripts/Commands/cs_misc.cpp b/src/server/scripts/Commands/cs_misc.cpp
index fda4c1cb893..decb37757f8 100644
--- a/src/server/scripts/Commands/cs_misc.cpp
+++ b/src/server/scripts/Commands/cs_misc.cpp
@@ -278,7 +278,7 @@ public:
zoneX, zoneY, groundZ, floorZ, haveMap, haveVMap, haveMMap);
LiquidData liquidStatus;
- ZLiquidStatus status = map->getLiquidStatus(object->GetPositionX(), object->GetPositionY(), object->GetPositionZ(), MAP_ALL_LIQUIDS, &liquidStatus);
+ ZLiquidStatus status = map->GetLiquidStatus(object->GetPositionX(), object->GetPositionY(), object->GetPositionZ(), MAP_ALL_LIQUIDS, &liquidStatus);
if (status)
handler->PSendSysMessage(LANG_LIQUID_STATUS, liquidStatus.level, liquidStatus.depth_level, liquidStatus.entry, liquidStatus.type_flags, status);