diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/common/Collision/Management/IVMapManager.h | 24 | ||||
-rw-r--r-- | src/common/Collision/Management/VMapManager2.cpp | 31 | ||||
-rw-r--r-- | src/common/Collision/Management/VMapManager2.h | 1 | ||||
-rw-r--r-- | src/common/Collision/Maps/MapTree.h | 1 | ||||
-rw-r--r-- | src/common/Collision/Models/WorldModel.cpp | 1 | ||||
-rw-r--r-- | src/server/game/Entities/Creature/Creature.cpp | 2 | ||||
-rw-r--r-- | src/server/game/Entities/Object/Object.cpp | 44 | ||||
-rw-r--r-- | src/server/game/Entities/Object/Object.h | 25 | ||||
-rw-r--r-- | src/server/game/Entities/Player/Player.cpp | 95 | ||||
-rw-r--r-- | src/server/game/Entities/Player/Player.h | 2 | ||||
-rw-r--r-- | src/server/game/Entities/Unit/Unit.cpp | 60 | ||||
-rw-r--r-- | src/server/game/Entities/Unit/Unit.h | 4 | ||||
-rw-r--r-- | src/server/game/Maps/Map.cpp | 125 | ||||
-rw-r--r-- | src/server/game/Maps/Map.h | 33 | ||||
-rw-r--r-- | src/server/game/Movement/PathGenerator.cpp | 4 | ||||
-rw-r--r-- | src/server/game/Spells/Spell.cpp | 2 | ||||
-rw-r--r-- | src/server/scripts/Commands/cs_misc.cpp | 2 |
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); |