Core/Maps: Adjusted logic in GetFullTerrainStatusForPosition to closer match what the client does regarding being inside WMOs
Port From (https://github.com/TrinityCore/TrinityCore/commit/453b59de57b3502163adc99a6fc9cbeec0645dcf)
This commit is contained in:
@@ -26,6 +26,7 @@ namespace Game.Collision
|
||||
{
|
||||
public virtual void Invoke(Vector3 point, uint entry) { }
|
||||
public virtual void Invoke(Vector3 point, IModel entry) { }
|
||||
public virtual void Invoke(Vector3 point, GameObjectModel obj) { }
|
||||
public virtual bool Invoke(Ray ray, uint entry, ref float distance, bool pStopAtFirstHit) { return false; }
|
||||
public virtual bool Invoke(Ray r, IModel obj, ref float distance) { return false; }
|
||||
}
|
||||
@@ -106,10 +107,7 @@ namespace Game.Collision
|
||||
}
|
||||
public override bool Invoke(Ray ray, uint entry, ref float distance, bool pStopAtFirstHit)
|
||||
{
|
||||
bool result = IntersectTriangle(triangles[(int)entry], vertices, ray, ref distance);
|
||||
if (result)
|
||||
hit = true;
|
||||
|
||||
hit = IntersectTriangle(triangles[(int)entry], vertices, ray, ref distance) || hit;
|
||||
return hit;
|
||||
}
|
||||
|
||||
@@ -266,4 +264,25 @@ namespace Game.Collision
|
||||
PhaseShift _phaseShift;
|
||||
AreaInfo _areaInfo;
|
||||
}
|
||||
|
||||
public class DynamicTreeLocationInfoCallback : WorkerCallback
|
||||
{
|
||||
public DynamicTreeLocationInfoCallback(PhaseShift phaseShift)
|
||||
{
|
||||
_phaseShift = phaseShift;
|
||||
}
|
||||
|
||||
public override void Invoke(Vector3 p, GameObjectModel obj)
|
||||
{
|
||||
if (obj.GetLocationInfo(p, _locationInfo, _phaseShift))
|
||||
_hitModel = obj;
|
||||
}
|
||||
|
||||
public LocationInfo GetLocationInfo() { return _locationInfo; }
|
||||
public GameObjectModel GetHitModel() { return _hitModel; }
|
||||
|
||||
PhaseShift _phaseShift;
|
||||
LocationInfo _locationInfo;
|
||||
GameObjectModel _hitModel;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -148,6 +148,31 @@ namespace Game.Collision
|
||||
return false;
|
||||
}
|
||||
|
||||
public AreaAndLiquidData GetAreaAndLiquidData(float x, float y, float z, PhaseShift phaseShift, byte reqLiquidType)
|
||||
{
|
||||
AreaAndLiquidData data = new();
|
||||
|
||||
Vector3 v = new(x, y, z +0.5f);
|
||||
DynamicTreeLocationInfoCallback intersectionCallBack = new(phaseShift);
|
||||
impl.IntersectPoint(v, intersectionCallBack);
|
||||
if (intersectionCallBack.GetLocationInfo().hitModel != null)
|
||||
{
|
||||
data.floorZ = intersectionCallBack.GetLocationInfo().ground_Z;
|
||||
uint liquidType = intersectionCallBack.GetLocationInfo().hitModel.GetLiquidType();
|
||||
float liquidLevel = 0;
|
||||
if (reqLiquidType == 0 || (Global.DB2Mgr.GetLiquidFlags(liquidType) & reqLiquidType) != 0)
|
||||
if (intersectionCallBack.GetHitModel().GetLiquidLevel(v, intersectionCallBack.GetLocationInfo(), ref liquidLevel))
|
||||
data.liquidInfo.Set(new AreaAndLiquidData.LiquidInfo(liquidType, liquidLevel));
|
||||
|
||||
data.areaInfo.Set(new AreaAndLiquidData.AreaInfo(intersectionCallBack.GetHitModel().GetNameSetId(),
|
||||
intersectionCallBack.GetLocationInfo().rootId,
|
||||
(int)intersectionCallBack.GetLocationInfo().hitModel.GetWmoID(),
|
||||
intersectionCallBack.GetLocationInfo().hitModel.GetMogpFlags()));
|
||||
}
|
||||
|
||||
return data;
|
||||
}
|
||||
|
||||
DynTreeImpl impl;
|
||||
}
|
||||
|
||||
|
||||
@@ -225,7 +225,7 @@ namespace Game.Collision
|
||||
return false;
|
||||
}
|
||||
|
||||
public bool GetLiquidLevel(uint mapId, float x, float y, float z, uint reqLiquidType, ref float level, ref float floor, ref uint type)
|
||||
public bool GetLiquidLevel(uint mapId, float x, float y, float z, uint reqLiquidType, ref float level, ref float floor, ref uint type, ref uint mogpFlags)
|
||||
{
|
||||
if (!Global.DisableMgr.IsDisabledFor(DisableType.VMAP, mapId, null, (byte)DisableFlags.VmapLiquidStatus))
|
||||
{
|
||||
@@ -239,6 +239,7 @@ namespace Game.Collision
|
||||
floor = info.ground_Z;
|
||||
Cypher.Assert(floor < float.MaxValue);
|
||||
type = info.hitModel.GetLiquidType(); // entry from LiquidType.dbc
|
||||
mogpFlags = info.hitModel.GetMogpFlags();
|
||||
if (reqLiquidType != 0 && !Convert.ToBoolean(Global.DB2Mgr.GetLiquidFlags(type) & reqLiquidType))
|
||||
return false;
|
||||
if (info.hitInstance.GetLiquidLevel(pos, info, ref level))
|
||||
|
||||
@@ -139,6 +139,51 @@ namespace Game.Collision
|
||||
}
|
||||
}
|
||||
|
||||
public bool GetLocationInfo(Vector3 point, LocationInfo info, PhaseShift phaseShift)
|
||||
{
|
||||
if (!IsCollisionEnabled() || !owner.IsSpawned() || !IsMapObject())
|
||||
return false;
|
||||
|
||||
if (!owner.IsInPhase(phaseShift))
|
||||
return false;
|
||||
|
||||
if (!iBound.contains(point))
|
||||
return false;
|
||||
|
||||
// child bounds are defined in object space:
|
||||
Vector3 pModel = iInvRot * (point - iPos) * iInvScale;
|
||||
Vector3 zDirModel = iInvRot * new Vector3(0.0f, 0.0f, -1.0f);
|
||||
float zDist;
|
||||
if (iModel.GetLocationInfo(pModel, zDirModel, out zDist, info))
|
||||
{
|
||||
Vector3 modelGround = pModel + zDist * zDirModel;
|
||||
float world_Z = ((modelGround * iInvRot) * iScale + iPos).Z;
|
||||
if (info.ground_Z < world_Z)
|
||||
{
|
||||
info.ground_Z = world_Z;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
public bool GetLiquidLevel(Vector3 point, LocationInfo info, ref float liqHeight)
|
||||
{
|
||||
// child bounds are defined in object space:
|
||||
Vector3 pModel = iInvRot * (point - iPos) * iInvScale;
|
||||
//Vector3 zDirModel = iInvRot * Vector3(0.f, 0.f, -1.f);
|
||||
float zDist;
|
||||
if (info.hitModel.GetLiquidLevel(pModel, out zDist))
|
||||
{
|
||||
// calculate world height (zDist in model coords):
|
||||
// assume WMO not tilted (wouldn't make much sense anyway)
|
||||
liqHeight = zDist * iScale + iPos.Z;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public bool UpdatePosition()
|
||||
{
|
||||
if (iModel == null)
|
||||
@@ -177,7 +222,8 @@ namespace Game.Collision
|
||||
public void EnableCollision(bool enable) { _collisionEnabled = enable; }
|
||||
bool IsCollisionEnabled() { return _collisionEnabled; }
|
||||
public bool IsMapObject() { return isWmo; }
|
||||
|
||||
public byte GetNameSetId() { return owner.GetNameSetId(); }
|
||||
|
||||
public static void LoadGameObjectModelList()
|
||||
{
|
||||
uint oldMSTime = Time.GetMSTime();
|
||||
|
||||
@@ -3306,8 +3306,9 @@ namespace Game.Entities
|
||||
return;
|
||||
}
|
||||
|
||||
float halfHeight = GetCollisionHeight() * 0.5f;
|
||||
UpdateAllowedPositionZ(destx, desty, ref destz);
|
||||
bool col = Global.VMapMgr.GetObjectHitPos(PhasingHandler.GetTerrainMapId(GetPhaseShift(), GetMap(), pos.posX, pos.posY), pos.posX, pos.posY, pos.posZ, destx, desty, destz, out destx, out desty, out destz, -0.5f);
|
||||
bool col = Global.VMapMgr.GetObjectHitPos(PhasingHandler.GetTerrainMapId(GetPhaseShift(), GetMap(), pos.posX, pos.posY), pos.posX, pos.posY, pos.posZ + halfHeight, destx, desty, destz + halfHeight, out destx, out desty, out destz, -0.5f);
|
||||
|
||||
// collision occured
|
||||
if (col)
|
||||
@@ -3319,7 +3320,7 @@ namespace Game.Entities
|
||||
}
|
||||
|
||||
// check dynamic collision
|
||||
col = GetMap().GetObjectHitPos(GetPhaseShift(), pos.posX, pos.posY, pos.posZ, destx, desty, destz, out destx, out desty, out destz, -0.5f);
|
||||
col = GetMap().GetObjectHitPos(GetPhaseShift(), pos.posX, pos.posY, pos.posZ + halfHeight, destx, desty, destz + halfHeight, out destx, out desty, out destz, -0.5f);
|
||||
|
||||
// Collided with a gameobject
|
||||
if (col)
|
||||
@@ -3363,11 +3364,7 @@ namespace Game.Entities
|
||||
|
||||
float GetMapWaterOrGroundLevel(float x, float y, float z, ref float ground)
|
||||
{
|
||||
Unit unit = ToUnit();
|
||||
if (unit != null)
|
||||
return GetMap().GetWaterOrGroundLevel(GetPhaseShift(), x, y, z, ref ground, !unit.HasAuraType(AuraType.WaterWalk), GetCollisionHeight());
|
||||
|
||||
return z;
|
||||
return GetMap().GetWaterOrGroundLevel(GetPhaseShift(), x, y, z, ref ground, IsTypeMask(TypeMask.Unit) ? !ToUnit().HasAuraType(AuraType.WaterWalk) : false, GetCollisionHeight());
|
||||
}
|
||||
|
||||
public float GetMapHeight(float x, float y, float z, bool vmap = true, float distanceToSearch = MapConst.DefaultHeightSearch)
|
||||
|
||||
+41
-13
@@ -69,6 +69,12 @@ namespace Game.Maps
|
||||
return LoadResult.ReadFromFileFailed;
|
||||
}
|
||||
|
||||
if (header.holesSize != 0 && !LoadHolesData(reader, header.holesOffset))
|
||||
{
|
||||
Log.outError(LogFilter.Maps, "Error loading map holes data");
|
||||
return LoadResult.ReadFromFileFailed;
|
||||
}
|
||||
|
||||
return LoadResult.Success;
|
||||
}
|
||||
|
||||
@@ -207,6 +213,15 @@ namespace Game.Maps
|
||||
return true;
|
||||
}
|
||||
|
||||
bool LoadHolesData(BinaryReader reader, uint offset)
|
||||
{
|
||||
reader.BaseStream.Seek(offset, SeekOrigin.Begin);
|
||||
|
||||
_holes = reader.ReadArray<byte>(16 * 16 * 8);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public ushort GetArea(float x, float y)
|
||||
{
|
||||
if (_areaMap == null)
|
||||
@@ -239,6 +254,9 @@ namespace Game.Maps
|
||||
x_int &= (MapConst.MapResolution - 1);
|
||||
y_int &= (MapConst.MapResolution - 1);
|
||||
|
||||
if (IsHole(x_int, y_int))
|
||||
return MapConst.InvalidHeight;
|
||||
|
||||
float a, b, c;
|
||||
if (x + y < 1)
|
||||
{
|
||||
@@ -304,6 +322,10 @@ namespace Game.Maps
|
||||
y -= y_int;
|
||||
x_int &= (MapConst.MapResolution - 1);
|
||||
y_int &= (MapConst.MapResolution - 1);
|
||||
|
||||
if (IsHole(x_int, y_int))
|
||||
return MapConst.InvalidHeight;
|
||||
|
||||
int a, b, c;
|
||||
|
||||
unsafe
|
||||
@@ -377,6 +399,10 @@ namespace Game.Maps
|
||||
y -= y_int;
|
||||
x_int &= (MapConst.MapResolution - 1);
|
||||
y_int &= (MapConst.MapResolution - 1);
|
||||
|
||||
if (IsHole(x_int, y_int))
|
||||
return MapConst.InvalidHeight;
|
||||
|
||||
int a, b, c;
|
||||
unsafe
|
||||
{
|
||||
@@ -435,6 +461,19 @@ namespace Game.Maps
|
||||
}
|
||||
}
|
||||
|
||||
bool IsHole(int row, int col)
|
||||
{
|
||||
if (_holes == null)
|
||||
return false;
|
||||
|
||||
int cellRow = row / 8; // 8 squares per cell
|
||||
int cellCol = col / 8;
|
||||
int holeRow = row % 8;
|
||||
int holeCol = col % 8;
|
||||
|
||||
return (_holes[cellRow * 16 * 8 + cellCol * 8 + holeRow] & (1 << holeCol)) != 0;
|
||||
}
|
||||
|
||||
public float GetMinHeight(float x, float y)
|
||||
{
|
||||
if (_minHeightPlanes == null)
|
||||
@@ -485,19 +524,6 @@ namespace Game.Maps
|
||||
return _liquidMap[cx_int * _liquidWidth + cy_int];
|
||||
}
|
||||
|
||||
// Why does this return LIQUID data?
|
||||
public LiquidHeaderTypeFlags GetTerrainType(float x, float y)
|
||||
{
|
||||
if (_liquidFlags == null)
|
||||
return LiquidHeaderTypeFlags.NoWater;
|
||||
|
||||
x = 16 * (32 - x / MapConst.SizeofGrids);
|
||||
y = 16 * (32 - y / MapConst.SizeofGrids);
|
||||
int lx = (int)x & 15;
|
||||
int ly = (int)y & 15;
|
||||
return (LiquidHeaderTypeFlags)_liquidFlags[lx * 16 + ly];
|
||||
}
|
||||
|
||||
// Get water state on map
|
||||
public ZLiquidStatus GetLiquidStatus(float x, float y, float z, LiquidHeaderTypeFlags? reqLiquidType, LiquidData data, float collisionHeight)
|
||||
{
|
||||
@@ -625,6 +651,8 @@ namespace Game.Maps
|
||||
byte _liquidOffY;
|
||||
byte _liquidWidth;
|
||||
byte _liquidHeight;
|
||||
|
||||
byte[] _holes;
|
||||
#endregion
|
||||
}
|
||||
|
||||
|
||||
+129
-147
@@ -1713,7 +1713,7 @@ namespace Game.Maps
|
||||
if (gmap != null)
|
||||
{
|
||||
float gridHeight = gmap.GetHeight(x, y);
|
||||
if (z > gridHeight)
|
||||
if (MathFunctions.fuzzyGe(z, gridHeight - MapConst.GroundHeightTolerance))
|
||||
mapHeight = gridHeight;
|
||||
}
|
||||
|
||||
@@ -1763,50 +1763,14 @@ namespace Game.Maps
|
||||
return -500.0f;
|
||||
}
|
||||
|
||||
private bool IsOutdoorWMO(uint mogpFlags, WMOAreaTableRecord wmoEntry, AreaTableRecord atEntry)
|
||||
public static bool IsInWMOInterior(uint mogpFlags)
|
||||
{
|
||||
if (wmoEntry != null && atEntry != null)
|
||||
{
|
||||
if (atEntry.Flags.HasFlag(AreaFlags.Outside))
|
||||
return true;
|
||||
if (atEntry.Flags.HasFlag(AreaFlags.Inside))
|
||||
return false;
|
||||
}
|
||||
|
||||
if (wmoEntry != null)
|
||||
{
|
||||
if (Convert.ToBoolean(wmoEntry.Flags & 4))
|
||||
return true;
|
||||
if ((wmoEntry.Flags & 2) != 0)
|
||||
return false;
|
||||
}
|
||||
|
||||
return (mogpFlags & 0x8) != 0;
|
||||
return (mogpFlags & 0x2000) != 0;
|
||||
}
|
||||
|
||||
public bool IsOutdoors(PhaseShift phaseShift, float x, float y, float z)
|
||||
private bool GetAreaInfo(PhaseShift phaseShift, float x, float y, float z, out uint mogpflags, out int adtId, out int rootId, out int groupId)
|
||||
{
|
||||
uint mogpFlags;
|
||||
int adtId, rootId, groupId;
|
||||
|
||||
// no wmo found? . outside by default
|
||||
if (!GetAreaInfo(phaseShift, x, y, z, out mogpFlags, out adtId, out rootId, out groupId))
|
||||
return true;
|
||||
|
||||
AreaTableRecord atEntry = null;
|
||||
WMOAreaTableRecord wmoEntry = Global.DB2Mgr.GetWMOAreaTable(rootId, adtId, groupId);
|
||||
if (wmoEntry != null)
|
||||
{
|
||||
Log.outDebug(LogFilter.Maps, "Got WMOAreaTableEntry! flag {0}, areaid {1}", wmoEntry.Flags,
|
||||
wmoEntry.AreaTableID);
|
||||
atEntry = CliDB.AreaTableStorage.LookupByKey(wmoEntry.AreaTableID);
|
||||
}
|
||||
return IsOutdoorWMO(mogpFlags, wmoEntry, atEntry);
|
||||
}
|
||||
|
||||
private bool GetAreaInfo(PhaseShift phaseShift, float x, float y, float z, out uint flags, out int adtId, out int rootId, out int groupId)
|
||||
{
|
||||
flags = 0;
|
||||
mogpflags = 0;
|
||||
adtId = 0;
|
||||
rootId = 0;
|
||||
groupId = 0;
|
||||
@@ -1832,7 +1796,7 @@ namespace Game.Maps
|
||||
if (hasDynamicAreaInfo && dynamic_z > vmap_z)
|
||||
{
|
||||
check_z = dynamic_z;
|
||||
flags = dflags;
|
||||
mogpflags = dflags;
|
||||
adtId = dadtId;
|
||||
rootId = drootId;
|
||||
groupId = dgroupId;
|
||||
@@ -1840,7 +1804,7 @@ namespace Game.Maps
|
||||
else
|
||||
{
|
||||
check_z = vmap_z;
|
||||
flags = vflags;
|
||||
mogpflags = vflags;
|
||||
adtId = vadtId;
|
||||
rootId = vrootId;
|
||||
groupId = vgroupId;
|
||||
@@ -1849,7 +1813,7 @@ namespace Game.Maps
|
||||
else if (hasDynamicAreaInfo)
|
||||
{
|
||||
check_z = dynamic_z;
|
||||
flags = dflags;
|
||||
mogpflags = dflags;
|
||||
adtId = dadtId;
|
||||
rootId = drootId;
|
||||
groupId = dgroupId;
|
||||
@@ -1863,7 +1827,8 @@ namespace Game.Maps
|
||||
if (gmap != null)
|
||||
{
|
||||
float mapHeight = gmap.GetHeight(x, y);
|
||||
if (z > mapHeight && mapHeight > check_z)
|
||||
// z + 2.0f condition taken from GetHeight(), not sure if it's such a great choice...
|
||||
if (z + 2.0f > mapHeight && mapHeight > check_z)
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
@@ -1873,45 +1838,39 @@ namespace Game.Maps
|
||||
}
|
||||
|
||||
public uint GetAreaId(PhaseShift phaseShift, float x, float y, float z)
|
||||
{
|
||||
return GetAreaId(phaseShift, x, y, z, out _);
|
||||
}
|
||||
|
||||
public uint GetAreaId(PhaseShift phaseShift, float x, float y, float z, out bool isOutdoors)
|
||||
{
|
||||
uint mogpFlags;
|
||||
int adtId, rootId, groupId;
|
||||
WMOAreaTableRecord wmoEntry = null;
|
||||
AreaTableRecord atEntry = null;
|
||||
bool haveAreaInfo = false;
|
||||
float vmapZ = z;
|
||||
bool hasVmapArea = GetAreaInfo(phaseShift, x, y, vmapZ, out mogpFlags, out adtId, out rootId, out groupId);
|
||||
|
||||
uint gridAreaId = 0;
|
||||
float gridMapHeight = MapConst.InvalidHeight;
|
||||
GridMap gmap = GetGridMap(PhasingHandler.GetTerrainMapId(phaseShift, this, x, y), x, y);
|
||||
if (gmap != null)
|
||||
{
|
||||
gridAreaId = gmap.GetArea(x, y);
|
||||
gridMapHeight = gmap.GetHeight(x, y);
|
||||
}
|
||||
|
||||
uint areaId = 0;
|
||||
|
||||
if (GetAreaInfo(phaseShift, x, y, z, out mogpFlags, out adtId, out rootId, out groupId))
|
||||
// floor is the height we are closer to (but only if above)
|
||||
if (hasVmapArea && MathFunctions.fuzzyGe(z, vmapZ - MapConst.GroundHeightTolerance) && (MathFunctions.fuzzyLt(z, gridMapHeight - MapConst.GroundHeightTolerance) || vmapZ > gridMapHeight))
|
||||
{
|
||||
haveAreaInfo = true;
|
||||
wmoEntry = Global.DB2Mgr.GetWMOAreaTable(rootId, adtId, groupId);
|
||||
// wmo found
|
||||
var wmoEntry = Global.DB2Mgr.GetWMOAreaTable(rootId, adtId, groupId);
|
||||
if (wmoEntry != null)
|
||||
{
|
||||
areaId = wmoEntry.AreaTableID;
|
||||
atEntry = CliDB.AreaTableStorage.LookupByKey(wmoEntry.AreaTableID);
|
||||
}
|
||||
|
||||
if (areaId == 0)
|
||||
areaId = gridAreaId;
|
||||
}
|
||||
else
|
||||
areaId = gridAreaId;
|
||||
|
||||
if (areaId == 0)
|
||||
{
|
||||
GridMap gmap = GetGridMap(PhasingHandler.GetTerrainMapId(phaseShift, this, x, y), x, y);
|
||||
if (gmap != null)
|
||||
areaId = gmap.GetArea(x, y);
|
||||
|
||||
// this used while not all *.map files generated (instances)
|
||||
if (areaId == 0)
|
||||
areaId = i_mapRecord.AreaTableID;
|
||||
}
|
||||
|
||||
if (haveAreaInfo)
|
||||
isOutdoors = IsOutdoorWMO(mogpFlags, wmoEntry, atEntry);
|
||||
else
|
||||
isOutdoors = true;
|
||||
areaId = i_mapRecord.AreaTableID;
|
||||
|
||||
return areaId;
|
||||
}
|
||||
@@ -1942,15 +1901,6 @@ namespace Game.Maps
|
||||
|
||||
public void GetZoneAndAreaId(PhaseShift phaseShift, out uint zoneid, out uint areaid, Position pos) { GetZoneAndAreaId(phaseShift, out zoneid, out areaid, pos.GetPositionX(), pos.GetPositionY(), pos.GetPositionZ()); }
|
||||
|
||||
private LiquidHeaderTypeFlags GetTerrainType(PhaseShift phaseShift, float x, float y)
|
||||
{
|
||||
GridMap gmap = GetGridMap(PhasingHandler.GetTerrainMapId(phaseShift, this, x, y), x, y);
|
||||
if (gmap != null)
|
||||
return gmap.GetTerrainType(x, y);
|
||||
|
||||
return LiquidHeaderTypeFlags.NoWater;
|
||||
}
|
||||
|
||||
public ZLiquidStatus GetLiquidStatus(PhaseShift phaseShift, float x, float y, float z, LiquidHeaderTypeFlags reqLiquidType, float collisionHeight = MapConst.DefaultCollesionHeight)
|
||||
{
|
||||
return GetLiquidStatus(phaseShift, x, y, z, reqLiquidType, out _, collisionHeight);
|
||||
@@ -1963,13 +1913,17 @@ namespace Game.Maps
|
||||
float liquid_level = MapConst.InvalidHeight;
|
||||
float ground_level = MapConst.InvalidHeight;
|
||||
uint liquid_type = 0;
|
||||
uint mogpFlags = 0;
|
||||
bool useGridLiquid = true;
|
||||
uint terrainMapId = PhasingHandler.GetTerrainMapId(phaseShift, this, x, y);
|
||||
if (Global.VMapMgr.GetLiquidLevel(terrainMapId, x, y, z, (byte)reqLiquidType, ref liquid_level, ref ground_level, ref liquid_type))
|
||||
|
||||
if (Global.VMapMgr.GetLiquidLevel(terrainMapId, x, y, z, (byte)reqLiquidType, ref liquid_level, ref ground_level, ref liquid_type, ref mogpFlags))
|
||||
{
|
||||
useGridLiquid = !IsInWMOInterior(mogpFlags);
|
||||
Log.outDebug(LogFilter.Maps, "getLiquidStatus(): vmap liquid level: {0} ground: {1} type: {2}",
|
||||
liquid_level, ground_level, liquid_type);
|
||||
// Check water level and ground level
|
||||
if (liquid_level > ground_level && z > ground_level - 2)
|
||||
if (liquid_level > ground_level && MathFunctions.fuzzyGe(z, ground_level - MapConst.GroundHeightTolerance))
|
||||
{
|
||||
// All ok in water . store data
|
||||
// hardcoded in client like this
|
||||
@@ -2022,21 +1976,24 @@ namespace Game.Maps
|
||||
}
|
||||
}
|
||||
|
||||
GridMap gmap = GetGridMap(terrainMapId, x, y);
|
||||
if (gmap != null)
|
||||
if (useGridLiquid)
|
||||
{
|
||||
var map_data = new LiquidData();
|
||||
ZLiquidStatus map_result = gmap.GetLiquidStatus(x, y, z, reqLiquidType, map_data, collisionHeight);
|
||||
// Not override LIQUID_MAP_ABOVE_WATER with LIQUID_MAP_NO_WATER:
|
||||
if (map_result != ZLiquidStatus.NoWater && (map_data.level > ground_level))
|
||||
GridMap gmap = GetGridMap(terrainMapId, x, y);
|
||||
if (gmap != null)
|
||||
{
|
||||
// hardcoded in client like this
|
||||
if (GetId() == 530 && map_data.entry == 2)
|
||||
map_data.entry = 15;
|
||||
var map_data = new LiquidData();
|
||||
ZLiquidStatus map_result = gmap.GetLiquidStatus(x, y, z, reqLiquidType, map_data, collisionHeight);
|
||||
// Not override LIQUID_MAP_ABOVE_WATER with LIQUID_MAP_NO_WATER:
|
||||
if (map_result != ZLiquidStatus.NoWater && (map_data.level > ground_level))
|
||||
{
|
||||
// hardcoded in client like this
|
||||
if (GetId() == 530 && map_data.entry == 2)
|
||||
map_data.entry = 15;
|
||||
|
||||
data = map_data;
|
||||
data = map_data;
|
||||
|
||||
return map_result;
|
||||
return map_result;
|
||||
}
|
||||
}
|
||||
}
|
||||
return result;
|
||||
@@ -2045,66 +2002,92 @@ namespace Game.Maps
|
||||
public void GetFullTerrainStatusForPosition(PhaseShift phaseShift, float x, float y, float z, PositionFullTerrainStatus data, LiquidHeaderTypeFlags reqLiquidType, float collisionHeight = MapConst.DefaultCollesionHeight)
|
||||
{
|
||||
uint terrainMapId = PhasingHandler.GetTerrainMapId(phaseShift, this, x, y);
|
||||
AreaAndLiquidData vmapData = Global.VMapMgr.GetAreaAndLiquidData(terrainMapId, x, y, z, (byte)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));
|
||||
|
||||
float mapHeight = MapConst.InvalidHeight;
|
||||
GridMap gmap = GetGridMap(terrainMapId, x, y);
|
||||
AreaAndLiquidData vmapData = Global.VMapMgr.GetAreaAndLiquidData(terrainMapId, x, y, z, (byte)reqLiquidType);
|
||||
AreaAndLiquidData dynData = _dynamicTree.GetAreaAndLiquidData(x, y, z, phaseShift, (byte)reqLiquidType);
|
||||
|
||||
uint gridAreaId = 0;
|
||||
float gridMapHeight = MapConst.InvalidHeight;
|
||||
if (gmap != null)
|
||||
mapHeight = gmap.GetHeight(x, y);
|
||||
|
||||
// area lookup
|
||||
AreaTableRecord areaEntry = null;
|
||||
WMOAreaTableRecord wmoEntry = null;
|
||||
|
||||
// the vmap floor is our floor if either
|
||||
// - the vmap floor is above the gridmap floor
|
||||
// or
|
||||
// - we are below the gridmap floor
|
||||
if (vmapData.areaInfo.HasValue && (MathFunctions.fuzzyLt(z, mapHeight - MapConst.GroundHeightTolerance) || mapHeight <= vmapData.floorZ))
|
||||
{
|
||||
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);
|
||||
gridAreaId = gmap.GetArea(x, y);
|
||||
gridMapHeight = gmap.GetHeight(x, y);
|
||||
}
|
||||
|
||||
if (areaEntry != null)
|
||||
bool useGridLiquid = true;
|
||||
AreaAndLiquidData wmoData = null;
|
||||
|
||||
// floor is the height we are closer to (but only if above)
|
||||
data.FloorZ = MapConst.InvalidHeight;
|
||||
if (gridMapHeight > MapConst.InvalidHeight && MathFunctions.fuzzyGe(z, gridMapHeight - MapConst.GroundHeightTolerance))
|
||||
data.FloorZ = gridMapHeight;
|
||||
if (vmapData.floorZ > MapConst.InvalidHeight &&
|
||||
MathFunctions.fuzzyGe(z, vmapData.floorZ - MapConst.GroundHeightTolerance) &&
|
||||
(MathFunctions.fuzzyLt(z, gridMapHeight - MapConst.GroundHeightTolerance) || vmapData.floorZ > gridMapHeight))
|
||||
{
|
||||
data.AreaId = areaEntry.Id;
|
||||
data.FloorZ = vmapData.floorZ;
|
||||
wmoData = vmapData;
|
||||
}
|
||||
|
||||
// NOTE: Objects will not detect a case when a wmo providing area/liquid despawns from under them
|
||||
// but this is fine as these kind of objects are not meant to be spawned and despawned a lot
|
||||
// example: Lich King platform
|
||||
if (dynData.floorZ > MapConst.InvalidHeight &&
|
||||
MathFunctions.fuzzyGe(z, dynData.floorZ - MapConst.GroundHeightTolerance) &&
|
||||
(MathFunctions.fuzzyLt(z, gridMapHeight - MapConst.GroundHeightTolerance) || dynData.floorZ > gridMapHeight) &&
|
||||
(MathFunctions.fuzzyLt(z, vmapData.floorZ - MapConst.GroundHeightTolerance) || dynData.floorZ > vmapData.floorZ))
|
||||
{
|
||||
data.FloorZ = dynData.floorZ;
|
||||
wmoData = dynData;
|
||||
}
|
||||
|
||||
if (wmoData != null)
|
||||
{
|
||||
if (wmoData.areaInfo.HasValue)
|
||||
{
|
||||
data.areaInfo.Set(new PositionFullTerrainStatus.AreaInfo(wmoData.areaInfo.Value.AdtId, wmoData.areaInfo.Value.RootId, wmoData.areaInfo.Value.GroupId, wmoData.areaInfo.Value.MogpFlags));
|
||||
// wmo found
|
||||
var wmoEntry = Global.DB2Mgr.GetWMOAreaTable(wmoData.areaInfo.Value.RootId, wmoData.areaInfo.Value.AdtId, wmoData.areaInfo.Value.GroupId);
|
||||
data.outdoors = (wmoData.areaInfo.Value.MogpFlags & 0x8) != 0;
|
||||
if (wmoEntry != null)
|
||||
{
|
||||
data.AreaId = wmoEntry.AreaTableID;
|
||||
if ((wmoEntry.Flags & 4) != 0)
|
||||
data.outdoors = true;
|
||||
else if ((wmoEntry.Flags & 2) != 0)
|
||||
data.outdoors = false;
|
||||
}
|
||||
|
||||
if (data.AreaId == 0)
|
||||
data.AreaId = gridAreaId;
|
||||
|
||||
useGridLiquid = !IsInWMOInterior(wmoData.areaInfo.Value.MogpFlags);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
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);
|
||||
|
||||
data.FloorZ = mapHeight;
|
||||
data.outdoors = true;
|
||||
data.AreaId = gridAreaId;
|
||||
var areaEntry1 = CliDB.AreaTableStorage.LookupByKey(data.AreaId);
|
||||
if (areaEntry1 != null)
|
||||
data.outdoors = (areaEntry1.Flags & (AreaFlags.Inside | AreaFlags.Outside)) != AreaFlags.Inside;
|
||||
}
|
||||
|
||||
if (vmapData.areaInfo.HasValue)
|
||||
data.outdoors = IsOutdoorWMO(vmapData.areaInfo.Value.MogpFlags, wmoEntry, areaEntry);
|
||||
else
|
||||
data.outdoors = true; // @todo default true taken from old GetAreaId check, maybe review
|
||||
if (data.AreaId == 0)
|
||||
data.AreaId = i_mapRecord.AreaTableID;
|
||||
|
||||
var areaEntry = CliDB.AreaTableStorage.LookupByKey(data.AreaId);
|
||||
|
||||
// liquid processing
|
||||
data.LiquidStatus = ZLiquidStatus.NoWater;
|
||||
if (vmapData.liquidInfo.HasValue && vmapData.liquidInfo.Value.Level > vmapData.floorZ && z > vmapData.floorZ)
|
||||
if (wmoData != null && wmoData.liquidInfo.HasValue && wmoData.liquidInfo.Value.Level > wmoData.floorZ)
|
||||
{
|
||||
uint liquidType = vmapData.liquidInfo.Value.LiquidType;
|
||||
uint liquidType = wmoData.liquidInfo.Value.LiquidType;
|
||||
if (GetId() == 530 && liquidType == 2) // gotta love blizzard hacks
|
||||
liquidType = 15;
|
||||
|
||||
uint liquidFlagType = 0;
|
||||
LiquidTypeRecord liquidData = CliDB.LiquidTypeStorage.LookupByKey(liquidType);
|
||||
var liquidData = CliDB.LiquidTypeStorage.LookupByKey(liquidType);
|
||||
if (liquidData != null)
|
||||
liquidFlagType = liquidData.SoundBank;
|
||||
|
||||
@@ -2113,12 +2096,12 @@ namespace Game.Maps
|
||||
uint overrideLiquid = areaEntry.LiquidTypeID[liquidFlagType];
|
||||
if (overrideLiquid == 0 && areaEntry.ParentAreaID != 0)
|
||||
{
|
||||
AreaTableRecord zoneEntry = CliDB.AreaTableStorage.LookupByKey(areaEntry.ParentAreaID);
|
||||
var zoneEntry = CliDB.AreaTableStorage.LookupByKey(areaEntry.ParentAreaID);
|
||||
if (zoneEntry != null)
|
||||
overrideLiquid = zoneEntry.LiquidTypeID[liquidFlagType];
|
||||
}
|
||||
|
||||
LiquidTypeRecord overrideData = CliDB.LiquidTypeStorage.LookupByKey(overrideLiquid);
|
||||
var overrideData = CliDB.LiquidTypeStorage.LookupByKey(overrideLiquid);
|
||||
if (overrideData != null)
|
||||
{
|
||||
liquidType = overrideLiquid;
|
||||
@@ -2126,14 +2109,13 @@ namespace Game.Maps
|
||||
}
|
||||
}
|
||||
|
||||
var liquidInfo = new LiquidData();
|
||||
liquidInfo.level = vmapData.liquidInfo.Value.Level;
|
||||
liquidInfo.depth_level = vmapData.floorZ;
|
||||
liquidInfo.entry = liquidType;
|
||||
liquidInfo.type_flags = (LiquidHeaderTypeFlags)(1u << (int)liquidFlagType);
|
||||
data.LiquidInfo.Set(liquidInfo);
|
||||
data.LiquidInfo.HasValue = true;
|
||||
data.LiquidInfo.Value.level = wmoData.liquidInfo.Value.Level;
|
||||
data.LiquidInfo.Value.depth_level = wmoData.floorZ;
|
||||
data.LiquidInfo.Value.entry = liquidType;
|
||||
data.LiquidInfo.Value.type_flags = (LiquidHeaderTypeFlags)(1 << (int)liquidFlagType);
|
||||
|
||||
float delta = vmapData.liquidInfo.Value.Level - z;
|
||||
float delta = wmoData.liquidInfo.Value.Level - z;
|
||||
if (delta > collisionHeight)
|
||||
data.LiquidStatus = ZLiquidStatus.UnderWater;
|
||||
else if (delta > 0.0f)
|
||||
@@ -2144,11 +2126,11 @@ namespace Game.Maps
|
||||
data.LiquidStatus = ZLiquidStatus.AboveWater;
|
||||
}
|
||||
// look up liquid data from grid map
|
||||
if (gmap != null && (data.LiquidStatus == ZLiquidStatus.AboveWater || data.LiquidStatus == ZLiquidStatus.NoWater))
|
||||
if (gmap != null && useGridLiquid)
|
||||
{
|
||||
LiquidData gridMapLiquid = new();
|
||||
ZLiquidStatus gridMapStatus = gmap.GetLiquidStatus(x, y, z, reqLiquidType, gridMapLiquid, collisionHeight);
|
||||
if (gridMapStatus != ZLiquidStatus.NoWater && (gridMapLiquid.level > vmapData.floorZ))
|
||||
if (gridMapStatus != ZLiquidStatus.NoWater && (wmoData == null || gridMapLiquid.level > wmoData.floorZ))
|
||||
{
|
||||
if (GetId() == 530 && gridMapLiquid.entry == 2)
|
||||
gridMapLiquid.entry = 15;
|
||||
@@ -2629,7 +2611,7 @@ namespace Game.Maps
|
||||
else // value changed, update heap position
|
||||
{
|
||||
Cypher.Assert(now < next.respawnTime); // infinite loop guard
|
||||
//_respawnTimes.decrease(next->handle);
|
||||
//_respawnTimes.decrease(next.handle);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -774,7 +774,10 @@ namespace Game.Movement
|
||||
void NormalizePath()
|
||||
{
|
||||
for (uint i = 0; i < _pathPoints.Length; ++i)
|
||||
{
|
||||
_pathPoints[i].Z += _sourceUnit.GetCollisionHeight();
|
||||
_sourceUnit.UpdateAllowedPositionZ(_pathPoints[i].X, _pathPoints[i].Y, ref _pathPoints[i].Z);
|
||||
}
|
||||
}
|
||||
|
||||
void BuildShortcut()
|
||||
|
||||
@@ -1449,7 +1449,7 @@ namespace Scripts.Spells.Druid
|
||||
{
|
||||
SpellInfo spellInfo = Global.SpellMgr.GetSpellInfo(spell_id, difficulty);
|
||||
|
||||
if (requireOutdoors && !targetPlayer.GetMap().IsOutdoors(targetPlayer.GetPhaseShift(), targetPlayer.GetPositionX(), targetPlayer.GetPositionY(), targetPlayer.GetPositionZ()))
|
||||
if (requireOutdoors && !targetPlayer.IsOutdoors())
|
||||
return SpellCastResult.OnlyOutdoors;
|
||||
|
||||
return spellInfo.CheckLocation(targetPlayer.GetMapId(), targetPlayer.GetZoneId(), targetPlayer.GetAreaId(), targetPlayer);
|
||||
|
||||
Reference in New Issue
Block a user