From 286a200178dcbfcb67c3ce9f5c3e5b7e066a2e38 Mon Sep 17 00:00:00 2001 From: hondacrx Date: Thu, 23 Jul 2020 18:22:46 -0400 Subject: [PATCH] Core/Movement: Get zone/area IDs from vmap data in the liquid update Port From (https://github.com/TrinityCore/TrinityCore/commit/51ce3b1c1dc6a53938ed6f240bac00681d18a44f) --- Source/Framework/Constants/MapConst.cs | 6 +- .../Game/Collision/Management/VMapManager.cs | 70 ++++++++ Source/Game/Collision/Maps/MapTree.cs | 1 + Source/Game/Collision/Models/WorldModel.cs | 1 + Source/Game/Entities/Creature/Creature.cs | 2 +- Source/Game/Entities/Object/WorldObject.cs | 55 ++++-- Source/Game/Entities/Player/Player.Map.cs | 98 ++++------- Source/Game/Entities/Unit/Unit.Movement.cs | 62 +++---- Source/Game/Entities/Unit/Unit.cs | 1 - Source/Game/Maps/Map.cs | 166 +++++++++++++++--- 10 files changed, 325 insertions(+), 137 deletions(-) diff --git a/Source/Framework/Constants/MapConst.cs b/Source/Framework/Constants/MapConst.cs index 3758614ce..8505d7d5c 100644 --- a/Source/Framework/Constants/MapConst.cs +++ b/Source/Framework/Constants/MapConst.cs @@ -119,13 +119,17 @@ namespace Framework.Constants AllWorld = Player | Creature | Corpse | DynamicObject } + [Flags] public enum ZLiquidStatus { NoWater = 0x00, AboveWater = 0x01, WaterWalk = 0x02, InWater = 0x04, - UnderWater = 0x08 + UnderWater = 0x08, + + Swimming = InWater | UnderWater, + InContact = Swimming | WaterWalk } public enum EncounterFrameType diff --git a/Source/Game/Collision/Management/VMapManager.cs b/Source/Game/Collision/Management/VMapManager.cs index 41802cab2..28631e950 100644 --- a/Source/Game/Collision/Management/VMapManager.cs +++ b/Source/Game/Collision/Management/VMapManager.cs @@ -19,6 +19,7 @@ using Framework.Constants; using Framework.GameMath; using System; using System.Collections.Generic; +using Framework.Dynamic; namespace Game.Collision { @@ -240,6 +241,41 @@ namespace Game.Collision return false; } + public AreaAndLiquidData GetAreaAndLiquidData(uint mapId, float x, float y, float z, uint reqLiquidType) + { + var data = new AreaAndLiquidData(); + + if (!Global.DisableMgr.IsDisabledFor(DisableType.VMAP, mapId, null, DisableFlags.VmapLiquidStatus)) + { + data.floorZ = z; + int adtId, rootId, groupId; + uint flags; + if (GetAreaInfo(mapId, x, y, ref data.floorZ, out flags, out adtId, out rootId, out groupId)) + data.areaInfo.Set(new AreaAndLiquidData.AreaInfo(adtId, rootId, groupId, flags)); + return data; + } + var instanceTree = iInstanceMapTrees.LookupByKey(mapId); + if (instanceTree != null) + { + LocationInfo info = new LocationInfo(); + Vector3 pos = ConvertPositionToInternalRep(x, y, z); + if (instanceTree.GetLocationInfo(pos, info)) + { + data.floorZ = info.ground_Z; + uint liquidType = info.hitModel.GetLiquidType(); + float liquidLevel = 0; + if (reqLiquidType == 0 || Convert.ToBoolean(Global.DB2Mgr.GetLiquidFlags(liquidType) & reqLiquidType)) + if (info.hitInstance.GetLiquidLevel(pos, info, ref liquidLevel)) + data.liquidInfo.Set(new AreaAndLiquidData.LiquidInfo(liquidType, liquidLevel)); + + if (!Global.DisableMgr.IsDisabledFor(DisableType.VMAP, mapId, null, DisableFlags.VmapLiquidStatus)) + data.areaInfo.Set(new AreaAndLiquidData.AreaInfo(info.hitInstance.adtId, info.rootId, (int)info.hitModel.GetWmoID(), info.hitModel.GetMogpFlags())); + } + } + + return data; + } + public WorldModel AcquireModelInstance(string filename, uint flags = 0) { lock (LoadedModelFilesLock) @@ -350,4 +386,38 @@ namespace Game.Collision WorldModel iModel; int iRefCount; } + + public class AreaAndLiquidData + { + public struct AreaInfo + { + public int AdtId; + public int RootId; + public int GroupId; + public uint MogpFlags; + + public AreaInfo(int adtId, int rootId, int groupId, uint flags) + { + AdtId = adtId; + RootId = rootId; + GroupId = groupId; + MogpFlags = flags; + } + } + public struct LiquidInfo + { + public uint LiquidType; + public float Level; + + public LiquidInfo(uint type, float level) + { + LiquidType = type; + Level = level; + } + } + + public float floorZ = MapConst.VMAPInvalidHeightValue; + public Optional areaInfo; + public Optional liquidInfo; + } } diff --git a/Source/Game/Collision/Maps/MapTree.cs b/Source/Game/Collision/Maps/MapTree.cs index 8f69b01d7..5cf0614bc 100644 --- a/Source/Game/Collision/Maps/MapTree.cs +++ b/Source/Game/Collision/Maps/MapTree.cs @@ -30,6 +30,7 @@ namespace Game.Collision ground_Z = float.NegativeInfinity; } + public int rootId; public ModelInstance hitInstance; public GroupModel hitModel; public float ground_Z; diff --git a/Source/Game/Collision/Models/WorldModel.cs b/Source/Game/Collision/Models/WorldModel.cs index e7b09c375..079d1bae0 100644 --- a/Source/Game/Collision/Models/WorldModel.cs +++ b/Source/Game/Collision/Models/WorldModel.cs @@ -361,6 +361,7 @@ namespace Game.Collision groupTree.IntersectPoint(p, callback); if (callback.hit != null) { + info.rootId = (int)RootWMOID; info.hitModel = callback.hit; dist = callback.zDist; return true; diff --git a/Source/Game/Entities/Creature/Creature.cs b/Source/Game/Entities/Creature/Creature.cs index ecc3294b9..8b5e811ae 100644 --- a/Source/Game/Entities/Creature/Creature.cs +++ b/Source/Game/Entities/Creature/Creature.cs @@ -2688,7 +2688,7 @@ namespace Game.Entities 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 = (MathFunctions.fuzzyGt(GetPositionZMinusOffset(), ground + 0.05f) || MathFunctions.fuzzyLt(GetPositionZMinusOffset(), ground - 0.05f)); // Can be underground too, prevent the falling diff --git a/Source/Game/Entities/Object/WorldObject.cs b/Source/Game/Entities/Object/WorldObject.cs index 5d7c42185..358aeafaf 100644 --- a/Source/Game/Entities/Object/WorldObject.cs +++ b/Source/Game/Entities/Object/WorldObject.cs @@ -26,6 +26,7 @@ using Game.Networking.Packets; using Game.Scenarios; using System; using System.Collections.Generic; +using Game.DataStorage; namespace Game.Entities { @@ -48,6 +49,8 @@ namespace Game.Entities m_updateFlag.Clear(); m_objectData = new ObjectFieldData(); + + m_staticFloorZ = MapConst.VMAPInvalidHeightValue; } public virtual void Dispose() @@ -91,6 +94,8 @@ namespace Game.Entities IsInWorld = true; ClearUpdateMask(true); + + GetMap().GetZoneAndAreaId(_phaseShift, out m_zoneId, out m_areaId, GetPositionX(), GetPositionY(), GetPositionZ()); } public virtual void RemoveFromWorld() @@ -105,6 +110,25 @@ namespace Game.Entities ClearUpdateMask(true); } + public void UpdatePositionData() + { + PositionFullTerrainStatus data = new PositionFullTerrainStatus(); + GetMap().GetFullTerrainStatusForPosition(_phaseShift, GetPositionX(), GetPositionY(), GetPositionZ(), data); + ProcessPositionDataChanged(data); + } + + public virtual void ProcessPositionDataChanged(PositionFullTerrainStatus data) + { + m_zoneId = m_areaId = data.AreaId; + + var area = CliDB.AreaTableStorage.LookupByKey(m_areaId); + if (area != null) + if (area.Id != 0) + m_zoneId = area.Id; + + m_staticFloorZ = data.FloorZ; + } + public virtual void BuildCreateUpdateBlockForPlayer(UpdateData data, Player target) { if (!target) @@ -990,22 +1014,12 @@ namespace Game.Entities if (transport) transport.RemovePassenger(this); } + + public uint GetZoneId() { return m_zoneId; } + public uint GetAreaId() { return m_areaId; } - public uint GetZoneId() - { - return GetMap().GetZoneId(GetPhaseShift(), GetPositionX(), GetPositionY(), GetPositionZ()); - } - - public uint GetAreaId() - { - return GetMap().GetAreaId(GetPhaseShift(), GetPositionX(), GetPositionY(), GetPositionZ()); - } - - public void GetZoneAndAreaId(out uint zoneid, out uint areaid) - { - GetMap().GetZoneAndAreaId(GetPhaseShift(), out zoneid, out areaid, posX, posY, posZ); - } - + public void GetZoneAndAreaId(out uint zoneid, out uint areaid) { zoneid = m_zoneId; areaid = m_areaId; } + public bool IsInWorldPvpZone() { switch (GetZoneId()) @@ -2306,6 +2320,13 @@ namespace Game.Entities pos.SetOrientation(GetOrientation()); } + public float GetFloorZ() + { + if (!IsInWorld) + return m_staticFloorZ; + return Math.Max(m_staticFloorZ, GetMap().GetGameObjectFloor(GetPhaseShift(), GetPositionX(), GetPositionY(), GetPositionZ())); + } + public void SetLocationInstanceId(uint _instanceId) { instanceId = _instanceId; } #region Fields @@ -2321,6 +2342,10 @@ namespace Game.Entities bool m_objectUpdated; + uint m_zoneId; + uint m_areaId; + float m_staticFloorZ; + public MovementInfo m_movementInfo; string _name; protected bool m_isActive; diff --git a/Source/Game/Entities/Player/Player.Map.cs b/Source/Game/Entities/Player/Player.Map.cs index a9daf88c0..1f2e13538 100644 --- a/Source/Game/Entities/Player/Player.Map.cs +++ b/Source/Game/Entities/Player/Player.Map.cs @@ -24,6 +24,7 @@ using Game.Maps; using Game.Networking.Packets; using System; using System.Collections.Generic; +using Framework.Dynamic; namespace Game.Entities { @@ -712,77 +713,52 @@ namespace Game.Entities SendPacket(raidInstanceMessage); } - public override void UpdateUnderwaterState(Map m, float x, float y, float z) + public override void ProcessTerrainStatusUpdate(ZLiquidStatus status, Optional liquidData) { - LiquidData liquid_status; - ZLiquidStatus res = m.GetLiquidStatus(GetPhaseShift(), x, y, z, MapConst.MapAllLiquidTypes, out liquid_status); - if (res == 0) - { - m_MirrorTimerFlags &= ~(PlayerUnderwaterState.InWater | PlayerUnderwaterState.InLava | PlayerUnderwaterState.InSlime | PlayerUnderwaterState.InDarkWater); - if (_lastLiquid != null && _lastLiquid.SpellID != 0) - RemoveAurasDueToSpell(_lastLiquid.SpellID); - - _lastLiquid = null; + if (IsFlying()) return; - } - uint liqEntry = liquid_status.entry; - if (liqEntry != 0) - { - LiquidTypeRecord liquid = CliDB.LiquidTypeStorage.LookupByKey(liqEntry); - if (_lastLiquid != null && _lastLiquid.SpellID != 0 && _lastLiquid != liquid) - RemoveAurasDueToSpell(_lastLiquid.SpellID); - if (liquid != null && liquid.SpellID != 0) + // process liquid auras using generic unit code + base.ProcessTerrainStatusUpdate(status, liquidData); + + // player specific logic for mirror timers + if (status != 0 && liquidData.HasValue) + { + // Breath bar state (under water in any liquid type) + if (liquidData.Value.type_flags.HasAnyFlag(MapConst.MapAllLiquidTypes)) { - if (res.HasAnyFlag(ZLiquidStatus.UnderWater | ZLiquidStatus.InWater)) - { - if (!HasAura(liquid.SpellID)) - CastSpell(this, liquid.SpellID, true); - } + if (status.HasAnyFlag(ZLiquidStatus.UnderWater)) + m_MirrorTimerFlags |= PlayerUnderwaterState.InWater; else - RemoveAurasDueToSpell(liquid.SpellID); + m_MirrorTimerFlags &= ~PlayerUnderwaterState.InWater; } - _lastLiquid = liquid; - } - else if (_lastLiquid != null && _lastLiquid.SpellID != 0) - { - RemoveAurasDueToSpell(_lastLiquid.SpellID); - _lastLiquid = null; - } - - - // All liquids type - check under water position - if (liquid_status.type_flags.HasAnyFlag(MapConst.MapLiquidTypeWater | MapConst.MapLiquidTypeOcean | MapConst.MapLiquidTypeMagma | MapConst.MapLiquidTypeSlime)) - { - if (res.HasAnyFlag(ZLiquidStatus.UnderWater)) - m_MirrorTimerFlags |= PlayerUnderwaterState.InWater; + // Fatigue bar state (if not on flight path or transport) + if (liquidData.Value.type_flags.HasAnyFlag(MapConst.MapLiquidTypeDarkWater) && !IsInFlight() && !GetTransport()) + m_MirrorTimerFlags |= PlayerUnderwaterState.InDarkWater; else - m_MirrorTimerFlags &= ~PlayerUnderwaterState.InWater; - } + m_MirrorTimerFlags &= ~PlayerUnderwaterState.InDarkWater; - // Allow travel in dark water on taxi or transport - if (liquid_status.type_flags.HasAnyFlag(MapConst.MapLiquidTypeDarkWater) && !IsInFlight() && GetTransport() == null) - m_MirrorTimerFlags |= PlayerUnderwaterState.InDarkWater; + // Lava state (any contact) + if (liquidData.Value.type_flags.HasAnyFlag(MapConst.MapLiquidTypeMagma)) + { + if (status.HasAnyFlag(ZLiquidStatus.InContact)) + m_MirrorTimerFlags |= PlayerUnderwaterState.InLava; + else + m_MirrorTimerFlags &= ~PlayerUnderwaterState.InLava; + } + + // Slime state (any contact) + if (liquidData.Value.type_flags.HasAnyFlag(MapConst.MapLiquidTypeSlime)) + { + if (status.HasAnyFlag(ZLiquidStatus.InContact)) + m_MirrorTimerFlags |= PlayerUnderwaterState.InSlime; + else + m_MirrorTimerFlags &= ~PlayerUnderwaterState.InSlime; + } + } else - m_MirrorTimerFlags &= ~PlayerUnderwaterState.InDarkWater; - - // in lava check, anywhere in lava level - if (liquid_status.type_flags.HasAnyFlag(MapConst.MapLiquidTypeMagma)) - { - if (res.HasAnyFlag(ZLiquidStatus.UnderWater | ZLiquidStatus.InWater | ZLiquidStatus.WaterWalk)) - m_MirrorTimerFlags |= PlayerUnderwaterState.InLava; - else - m_MirrorTimerFlags &= ~PlayerUnderwaterState.InLava; - } - // in slime check, anywhere in slime level - if (liquid_status.type_flags.HasAnyFlag(MapConst.MapLiquidTypeSlime)) - { - if (res.HasAnyFlag(ZLiquidStatus.UnderWater | ZLiquidStatus.InWater | ZLiquidStatus.WaterWalk)) - m_MirrorTimerFlags |= PlayerUnderwaterState.InSlime; - else - m_MirrorTimerFlags &= ~PlayerUnderwaterState.InSlime; - } + m_MirrorTimerFlags &= ~(PlayerUnderwaterState.InWater | PlayerUnderwaterState.InLava | PlayerUnderwaterState.InSlime | PlayerUnderwaterState.InDarkWater); } } } diff --git a/Source/Game/Entities/Unit/Unit.Movement.cs b/Source/Game/Entities/Unit/Unit.Movement.cs index 8e066ce61..245829894 100644 --- a/Source/Game/Entities/Unit/Unit.Movement.cs +++ b/Source/Game/Entities/Unit/Unit.Movement.cs @@ -25,6 +25,7 @@ using Game.Networking.Packets; using System; using System.Collections.Generic; using Game.Spells; +using Framework.Dynamic; namespace Game.Entities { @@ -569,8 +570,7 @@ namespace Game.Entities else if (turn) UpdateOrientation(orientation); - // code block for underwater state update - UpdateUnderwaterState(GetMap(), x, y, z); + UpdatePositionData(); return (relocated || turn); } @@ -754,48 +754,34 @@ namespace Game.Entities return null; } - public virtual void UpdateUnderwaterState(Map m, float x, float y, float z) + public override void ProcessPositionDataChanged(PositionFullTerrainStatus data) { - if (IsFlying() || (!IsPet() && !IsVehicle())) + base.ProcessPositionDataChanged(data); + ProcessTerrainStatusUpdate(data.LiquidStatus, data.LiquidInfo); + } + + public virtual void ProcessTerrainStatusUpdate(ZLiquidStatus status, Optional liquidData) + { + if (IsFlying() || !IsControlledByPlayer()) return; - LiquidData liquid_status; - ZLiquidStatus res = m.GetLiquidStatus(GetPhaseShift(), x, y, z, MapConst.MapAllLiquidTypes, out liquid_status); - if (res == 0) + // remove appropriate auras if we are swimming/not swimming respectively + if (status.HasAnyFlag(ZLiquidStatus.Swimming)) + RemoveAurasWithInterruptFlags(SpellAuraInterruptFlags.NotAbovewater); + else + RemoveAurasWithInterruptFlags(SpellAuraInterruptFlags.NotUnderwater); + + // liquid aura handling + LiquidTypeRecord curLiquid = null; + if (status.HasAnyFlag(ZLiquidStatus.Swimming) && liquidData.HasValue) + curLiquid = CliDB.LiquidTypeStorage.LookupByKey(liquidData.Value.entry); + if (curLiquid != _lastLiquid) { if (_lastLiquid != null && _lastLiquid.SpellID != 0) RemoveAurasDueToSpell(_lastLiquid.SpellID); - - RemoveAurasWithInterruptFlags(SpellAuraInterruptFlags.NotUnderwater); - _lastLiquid = null; - return; - } - uint liqEntry = liquid_status.entry; - if (liqEntry != 0) - { - LiquidTypeRecord liquid = CliDB.LiquidTypeStorage.LookupByKey(liqEntry); - if (_lastLiquid != null && _lastLiquid.SpellID != 0 && _lastLiquid.Id != liqEntry) - RemoveAurasDueToSpell(_lastLiquid.SpellID); - - if (liquid != null && liquid.SpellID != 0) - { - if (res.HasAnyFlag(ZLiquidStatus.UnderWater | ZLiquidStatus.InWater)) - { - if (!HasAura(liquid.SpellID)) - CastSpell(this, liquid.SpellID, true); - } - else - RemoveAurasDueToSpell(liquid.SpellID); - } - - RemoveAurasWithInterruptFlags(SpellAuraInterruptFlags.NotAbovewater); - _lastLiquid = liquid; - } - else if (_lastLiquid != null && _lastLiquid.SpellID != 0) - { - RemoveAurasDueToSpell(_lastLiquid.SpellID); - RemoveAurasWithInterruptFlags(SpellAuraInterruptFlags.NotUnderwater); - _lastLiquid = null; + if (curLiquid != null && curLiquid.SpellID != 0) + CastSpell(this, curLiquid.SpellID, true); + _lastLiquid = curLiquid; } } diff --git a/Source/Game/Entities/Unit/Unit.cs b/Source/Game/Entities/Unit/Unit.cs index 50725fa28..1c7311f96 100644 --- a/Source/Game/Entities/Unit/Unit.cs +++ b/Source/Game/Entities/Unit/Unit.cs @@ -191,7 +191,6 @@ namespace Game.Entities UpdateSplineMovement(diff); GetMotionMaster().UpdateMotion(diff); - UpdateUnderwaterState(GetMap(), GetPositionX(), GetPositionY(), GetPositionZ()); } void _UpdateSpells(uint diff) { diff --git a/Source/Game/Maps/Map.cs b/Source/Game/Maps/Map.cs index 794590030..056fa12f0 100644 --- a/Source/Game/Maps/Map.cs +++ b/Source/Game/Maps/Map.cs @@ -17,6 +17,7 @@ using Framework.Constants; using Framework.Database; +using Framework.Dynamic; using Framework.GameMath; using Game.BattleGrounds; using Game.Collision; @@ -32,7 +33,6 @@ using System.Collections; using System.Collections.Generic; using System.IO; using System.Linq; -using System.Threading; namespace Game.Maps { @@ -850,7 +850,7 @@ namespace Game.Maps SendRemoveTransports(player); if (!inWorld) // if was in world, RemoveFromWorld() called DestroyForNearbyPlayers() - player.DestroyForNearbyPlayers(); // previous player->UpdateObjectVisibility(true) + player.DestroyForNearbyPlayers(); // previous player.UpdateObjectVisibility(true) Cell cell = player.GetCurrentCell(); RemoveFromGrid(player, cell); @@ -869,7 +869,7 @@ namespace Game.Maps RemoveFromActive(obj); if (!inWorld) // if was in world, RemoveFromWorld() called DestroyForNearbyPlayers() - obj.DestroyForNearbyPlayers(); // previous obj->UpdateObjectVisibility(true) + obj.DestroyForNearbyPlayers(); // previous obj.UpdateObjectVisibility(true) Cell cell = obj.GetCurrentCell(); RemoveFromGrid(obj, cell); @@ -950,6 +950,7 @@ namespace Game.Maps AddToGrid(player, newcell); } + player.UpdatePositionData(); player.UpdateObjectVisibility(false); } @@ -981,6 +982,7 @@ namespace Game.Maps if (creature.IsVehicle()) creature.GetVehicleKit().RelocatePassengers(); creature.UpdateObjectVisibility(false); + creature.UpdatePositionData(); RemoveCreatureFromMoveList(creature); } @@ -1010,6 +1012,7 @@ namespace Game.Maps { go.Relocate(x, y, z, orientation); go.UpdateModelPosition(); + go.UpdatePositionData(); go.UpdateObjectVisibility(false); RemoveGameObjectFromMoveList(go); } @@ -1040,6 +1043,7 @@ namespace Game.Maps else { dynObj.Relocate(x, y, z, orientation); + dynObj.UpdatePositionData(); dynObj.UpdateObjectVisibility(false); RemoveDynamicObjectFromMoveList(dynObj); } @@ -1186,6 +1190,7 @@ namespace Game.Maps creature.Relocate(creature._newPosition); if (creature.IsVehicle()) creature.GetVehicleKit().RelocatePassengers(); + creature.UpdatePositionData(); creature.UpdateObjectVisibility(false); } else @@ -1238,6 +1243,7 @@ namespace Game.Maps // update pos go.Relocate(go._newPosition); go.UpdateModelPosition(); + go.UpdatePositionData(); go.UpdateObjectVisibility(false); } else @@ -1284,6 +1290,7 @@ namespace Game.Maps { // update pos dynObj.Relocate(dynObj._newPosition); + dynObj.UpdatePositionData(); dynObj.UpdateObjectVisibility(false); } else @@ -1548,6 +1555,7 @@ namespace Game.Maps { c.Relocate(resp_x, resp_y, resp_z, resp_o); c.GetMotionMaster().Initialize(); // prevent possible problems with default move generators + c.UpdatePositionData(); c.UpdateObjectVisibility(false); return true; } @@ -1574,6 +1582,7 @@ namespace Game.Maps if (GameObjectCellRelocation(go, resp_cell)) { go.Relocate(resp_x, resp_y, resp_z, resp_o); + go.UpdatePositionData(); go.UpdateObjectVisibility(false); return true; } @@ -1705,18 +1714,6 @@ namespace Game.Maps _corpseBones.Clear(); } - private GridMap GetGridMap(float x, float y) - { - // half opt method - var gx = (uint)(MapConst.CenterGridId - x / MapConst.SizeofGrids); //grid x - var gy = (uint)(MapConst.CenterGridId - y / MapConst.SizeofGrids); //grid y - - // ensure GridMap is loaded - EnsureGridCreated(new GridCoord((MapConst.MaxGrids - 1) - gx, (MapConst.MaxGrids - 1) - gy)); - - return GridMaps[gx][gy]; - } - GridMap GetGridMap(uint mapId, float x, float y) { // half opt method @@ -1816,8 +1813,6 @@ namespace Game.Maps private bool IsOutdoorWMO(uint mogpFlags, int adtId, int rootId, int groupId, WMOAreaTableRecord wmoEntry, AreaTableRecord atEntry) { - bool outdoor = true; - if (wmoEntry != null && atEntry != null) { if (atEntry.Flags[0].HasAnyFlag(AreaFlags.Outside)) @@ -1826,7 +1821,7 @@ namespace Game.Maps return false; } - outdoor = Convert.ToBoolean(mogpFlags & 0x8); + bool outdoor = Convert.ToBoolean(mogpFlags & 0x8); if (wmoEntry != null) { @@ -1929,8 +1924,7 @@ namespace Game.Maps public uint GetAreaId(PhaseShift phaseShift, float x, float y, float z) { - bool throwaway; - return GetAreaId(phaseShift, x, y, z, out throwaway); + return GetAreaId(phaseShift, x, y, z, out _); } public uint GetAreaId(PhaseShift phaseShift, float x, float y, float z, out bool isOutdoors) @@ -2092,6 +2086,108 @@ namespace Game.Maps return result; } + public void GetFullTerrainStatusForPosition(PhaseShift phaseShift, float x, float y, float z, PositionFullTerrainStatus data, uint reqLiquidType = MapConst.MapAllLiquidTypes) + { + uint terrainMapId = PhasingHandler.GetTerrainMapId(phaseShift, this, x, y); + AreaAndLiquidData vmapData = Global.VMapMgr.GetAreaAndLiquidData(terrainMapId, x, y, z, reqLiquidType); + if (vmapData.areaInfo.HasValue) + data.areaInfo.Set(new PositionFullTerrainStatus.AreaInfo(vmapData.areaInfo.Value.AdtId, vmapData.areaInfo.Value.RootId, vmapData.areaInfo.Value.GroupId, vmapData.areaInfo.Value.MogpFlags)); + + GridMap gmap = GetGridMap(terrainMapId, x, y); + float mapHeight = gmap.GetHeight(x, y); + + // area lookup + AreaTableRecord areaEntry = null; + if (vmapData.areaInfo.HasValue && (z + 2.0f <= mapHeight || mapHeight <= vmapData.floorZ)) + { + WMOAreaTableRecord wmoEntry = Global.DB2Mgr.GetWMOAreaTable(vmapData.areaInfo.Value.RootId, vmapData.areaInfo.Value.AdtId, vmapData.areaInfo.Value.GroupId); + if (wmoEntry != null) + areaEntry = CliDB.AreaTableStorage.LookupByKey(wmoEntry.AreaTableID); + } + + if (areaEntry != null) + { + data.FloorZ = vmapData.floorZ; + data.AreaId = areaEntry.Id; + } + else + { + data.FloorZ = mapHeight; + if (gmap != null) + data.AreaId = gmap.GetArea(x, y); + else + data.AreaId = 0; + + if (data.AreaId == 0) + data.AreaId = i_mapRecord.AreaTableID; + + if (data.AreaId != 0) + areaEntry = CliDB.AreaTableStorage.LookupByKey(data.AreaId); + } + + // liquid processing + data.LiquidStatus = ZLiquidStatus.NoWater; + if (vmapData.liquidInfo.HasValue && vmapData.liquidInfo.Value.Level > vmapData.floorZ && z + 2.0f > vmapData.floorZ) + { + uint liquidType = vmapData.liquidInfo.Value.LiquidType; + if (GetId() == 530 && liquidType == 2) // gotta love blizzard hacks + liquidType = 15; + + uint liquidFlagType = 0; + LiquidTypeRecord liquidData = CliDB.LiquidTypeStorage.LookupByKey(liquidType); + if (liquidData != null) + liquidFlagType = liquidData.SoundBank; + + if (liquidType != 0 && liquidType < 21 && areaEntry != null) + { + uint overrideLiquid = areaEntry.LiquidTypeID[liquidFlagType]; + if (overrideLiquid == 0 && areaEntry.ParentAreaID != 0) + { + AreaTableRecord zoneEntry = CliDB.AreaTableStorage.LookupByKey(areaEntry.ParentAreaID); + if (zoneEntry != null) + overrideLiquid = zoneEntry.LiquidTypeID[liquidFlagType]; + } + + LiquidTypeRecord overrideData = CliDB.LiquidTypeStorage.LookupByKey(overrideLiquid); + if (overrideData != null) + { + liquidType = overrideLiquid; + liquidFlagType = overrideData.SoundBank; + } + } + + var liquidInfo = new LiquidData(); + liquidInfo.level = vmapData.liquidInfo.Value.Level; + liquidInfo.depth_level = vmapData.floorZ; + liquidInfo.entry = liquidType; + liquidInfo.type_flags = 1u << (int)liquidFlagType; + data.LiquidInfo.Set(liquidInfo); + + float delta = vmapData.liquidInfo.Value.Level - z; + if (delta > 2.0f) + data.LiquidStatus = ZLiquidStatus.UnderWater; + else if (delta > 0.0f) + data.LiquidStatus = ZLiquidStatus.InWater; + else if (delta > -0.1f) + data.LiquidStatus = ZLiquidStatus.WaterWalk; + else + data.LiquidStatus = ZLiquidStatus.AboveWater; + } + // look up liquid data from grid map + if (gmap != null && (data.LiquidStatus == ZLiquidStatus.AboveWater || data.LiquidStatus == ZLiquidStatus.NoWater)) + { + LiquidData gridMapLiquid = new LiquidData(); + ZLiquidStatus gridMapStatus = gmap.GetLiquidStatus(x, y, z, reqLiquidType, gridMapLiquid); + if (gridMapStatus != ZLiquidStatus.NoWater && (gridMapLiquid.level > vmapData.floorZ)) + { + if (GetId() == 530 && gridMapLiquid.entry == 2) + gridMapLiquid.entry = 15; + data.LiquidInfo.Set(gridMapLiquid); + data.LiquidStatus = gridMapStatus; + } + } + } + public float GetWaterLevel(PhaseShift phaseShift, float x, float y) { GridMap gmap = GetGridMap(PhasingHandler.GetTerrainMapId(phaseShift, this, x, y), x, y); @@ -3207,6 +3303,11 @@ namespace Game.Maps return _dynamicTree.Contains(model); } + public float GetGameObjectFloor(PhaseShift phaseShift, float x, float y, float z, float maxSearchDist = MapConst.DefaultHeightSearch) + { + return _dynamicTree.GetHeight(x, y, z, maxSearchDist, phaseShift); + } + public virtual uint GetOwnerGuildId(Team team = Team.Other) { return 0; @@ -4911,4 +5012,29 @@ namespace Game.Maps public uint OverrideLightId; public uint LightFadeInTime; } + + public struct PositionFullTerrainStatus + { + public struct AreaInfo + { + public int AdtId; + public int RootId; + public int GroupId; + public uint MogpFlags; + + public AreaInfo(int adtId, int rootId, int groupId, uint flags) + { + AdtId = adtId; + RootId = rootId; + GroupId = groupId; + MogpFlags = flags; + } + } + + public uint AreaId; + public float FloorZ; + public ZLiquidStatus LiquidStatus; + public Optional areaInfo; + public Optional LiquidInfo; + } } \ No newline at end of file