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:
hondacrx
2021-09-26 11:32:01 -04:00
parent 9d5cf1d4ae
commit 7befdbd11b
9 changed files with 275 additions and 174 deletions
+23 -4
View File
@@ -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;
}
}
+25
View File
@@ -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();
+4 -7
View File
@@ -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
View File
@@ -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
View File
@@ -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()
+1 -1
View File
@@ -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);