From 2170c9c91961804dc0bb7cab578e5e9d49add027 Mon Sep 17 00:00:00 2001 From: VladimirMangos Date: Sat, 25 Sep 2010 07:31:29 +0400 Subject: [PATCH] [10529] Water level in movement use fixes. * Move selection allowed upper and lower heights for target point into near point core function used for contact/close point selection. Selection base at possibility target point searcher fly/swim(or walk by water bottom). * Use vamp water level data so have proper water level in instances in movements. * Use increased ground search distance for water level case. --- src/game/ConfusedMovementGenerator.cpp | 2 +- src/game/Level1.cpp | 2 +- src/game/Map.cpp | 59 +++++++++++-- src/game/Map.h | 6 +- src/game/Object.cpp | 111 ++++++++++++++++++++++--- src/game/Object.h | 7 +- src/game/Pet.cpp | 2 +- src/game/Player.cpp | 5 +- src/game/RandomMovementGenerator.cpp | 5 +- src/game/SpellEffects.cpp | 2 +- src/game/TargetedMovementGenerator.cpp | 7 +- src/game/Unit.cpp | 2 +- src/shared/revision_nr.h | 2 +- 13 files changed, 171 insertions(+), 41 deletions(-) diff --git a/src/game/ConfusedMovementGenerator.cpp b/src/game/ConfusedMovementGenerator.cpp index 764436161..e1048a430 100644 --- a/src/game/ConfusedMovementGenerator.cpp +++ b/src/game/ConfusedMovementGenerator.cpp @@ -59,7 +59,7 @@ ConfusedMovementGenerator::Initialize(T &unit) i_waypoints[idx][1] = idx > 0 ? i_waypoints[idx-1][1] : y; } - unit.UpdateGroundPositionZ(i_waypoints[idx][0],i_waypoints[idx][1],z); + unit.UpdateAllowedPositionZ(i_waypoints[idx][0],i_waypoints[idx][1],z); i_waypoints[idx][2] = z; } diff --git a/src/game/Level1.cpp b/src/game/Level1.cpp index ca12a6266..208021a53 100644 --- a/src/game/Level1.cpp +++ b/src/game/Level1.cpp @@ -2027,7 +2027,7 @@ bool ChatHandler::HandleGoHelper( Player* player, uint32 mapid, float x, float y } Map const *map = sMapMgr.CreateBaseMap(mapid); - z = std::max(map->GetHeight(x, y, MAX_HEIGHT), map->GetWaterLevel(x, y)); + z = map->GetWaterOrGroundLevel(x, y, MAX_HEIGHT); } // stop flight if need diff --git a/src/game/Map.cpp b/src/game/Map.cpp index 0b8e881d4..f4a4fa685 100644 --- a/src/game/Map.cpp +++ b/src/game/Map.cpp @@ -1233,14 +1233,6 @@ GridMapLiquidStatus Map::getLiquidStatus(float x, float y, float z, uint8 ReqLiq return result; } -float Map::GetWaterLevel(float x, float y ) const -{ - if(GridMap* gmap = const_cast(this)->GetGrid(x, y)) - return gmap->getLiquidLevel(x, y); - else - return 0; -} - uint32 Map::GetAreaIdByAreaFlag(uint16 areaflag,uint32 map_id) { AreaTableEntry const *entry = GetAreaEntryByAreaFlagAndMap(areaflag,map_id); @@ -1295,6 +1287,57 @@ bool Map::IsUnderWater(float x, float y, float z) const return false; } +/** + * Function find higher form water or ground height for current floor + * + * @param x, y, z Coordinates original point at floor level + * + * @param pGround optional arg for retrun calculated by function work ground height, it let avoid in caller code recalculate height for point if it need + * + * @param swim z coordinate can be calculated for select above/at or under z coordinate (for fly or swim/walking by bottom) + * in last cases for in water returned under water height for avoid client set swimming unit as saty at water. + * + * @return calculated z coordinate + */ +float Map::GetWaterOrGroundLevel(float x, float y, float z, float* pGround /*= NULL*/, bool swim /*= false*/) const +{ + if (const_cast(this)->GetGrid(x, y)) + { + // we need ground level (including grid height version) for proper return water level in point + float ground_z = GetHeight(x, y, z, true, DEFAULT_WATER_SEARCH); + if (pGround) + *pGround = ground_z; + + GridMapLiquidData liquid_status; + + GridMapLiquidStatus res = getLiquidStatus(x, y, ground_z, MAP_ALL_LIQUIDS, &liquid_status); + return res ? ( swim ? liquid_status.level - 2.0f : liquid_status.level) : ground_z; + } + + return VMAP_INVALID_HEIGHT_VALUE; +} + +float Map::GetWaterLevel(float x, float y, float z, float* pGround /*= NULL*/) const +{ + if (const_cast(this)->GetGrid(x, y)) + { + // we need ground level (including grid height version) for proper return water level in point + float ground_z = GetHeight(x, y, z, true, DEFAULT_WATER_SEARCH); + if (pGround) + *pGround = ground_z; + + GridMapLiquidData liquid_status; + + GridMapLiquidStatus res = getLiquidStatus(x, y, ground_z, MAP_ALL_LIQUIDS, &liquid_status); + if (!res) + return VMAP_INVALID_HEIGHT_VALUE; + + return liquid_status.level; + } + + return VMAP_INVALID_HEIGHT_VALUE; +} + bool Map::CheckGridIntegrity(Creature* c, bool moved) const { Cell const& cur_cell = c->GetCurrentCell(); diff --git a/src/game/Map.h b/src/game/Map.h index a79524ea6..661ff1487 100644 --- a/src/game/Map.h +++ b/src/game/Map.h @@ -82,6 +82,7 @@ enum LevelRequirementVsMode #define INVALID_HEIGHT -100000.0f // for check, must be equal to VMAP_INVALID_HEIGHT, real value for unknown height is VMAP_INVALID_HEIGHT_VALUE #define MAX_FALL_DISTANCE 250000.0f // "unlimited fall" to find VMap ground if it is available, just larger than MAX_HEIGHT - INVALID_HEIGHT #define DEFAULT_HEIGHT_SEARCH 10.0f // default search distance to find height at nearby locations +#define DEFAULT_WATER_SEARCH 50.0f // default search distance to case detection water level #define MIN_UNLOAD_DELAY 1 // immediate unload class MANGOS_DLL_SPEC Map : public GridRefManager, public MaNGOS::ObjectLevelLockable @@ -154,14 +155,15 @@ class MANGOS_DLL_SPEC Map : public GridRefManager, public MaNGOS::Obj // some calls like isInWater should not use vmaps due to processor power // can return INVALID_HEIGHT if under z+2 z coord not found height float GetHeight(float x, float y, float z, bool pCheckVMap=true, float maxSearchDist=DEFAULT_HEIGHT_SEARCH) const; + float GetWaterLevel(float x, float y, float z, float* pGround = NULL) const; + float GetWaterOrGroundLevel(float x, float y, float z, float* pGround = NULL, bool swim = false) const; bool IsInWater(float x, float y, float z, GridMapLiquidData *data = 0) const; + bool IsUnderWater(float x, float y, float z) const; GridMapLiquidStatus getLiquidStatus(float x, float y, float z, uint8 ReqLiquidType, GridMapLiquidData *data = 0) const; uint16 GetAreaFlag(float x, float y, float z, bool *isOutdoors=0) const; uint8 GetTerrainType(float x, float y ) const; - float GetWaterLevel(float x, float y ) const; - bool IsUnderWater(float x, float y, float z) const; static uint32 GetAreaIdByAreaFlag(uint16 areaflag,uint32 map_id); static uint32 GetZoneIdByAreaFlag(uint16 areaflag,uint32 map_id); diff --git a/src/game/Object.cpp b/src/game/Object.cpp index dfb6c9560..605ca7003 100644 --- a/src/game/Object.cpp +++ b/src/game/Object.cpp @@ -1436,6 +1436,70 @@ void WorldObject::UpdateGroundPositionZ(float x, float y, float &z) const z = new_z+ 0.05f; // just to be sure that we are not a few pixel under the surface } +void WorldObject::UpdateAllowedPositionZ(float x, float y, float &z) const +{ + switch (GetTypeId()) + { + case TYPEID_UNIT: + { + // non fly unit don't must be in air + // non swim unit must be at ground (mostly speedup, because it don't must be in water and water level check less fast + if (!((Creature const*)this)->canFly()) + { + bool canSwim = ((Creature const*)this)->canSwim(); + float ground_z = z; + float max_z = canSwim + ? GetBaseMap()->GetWaterOrGroundLevel(x, y, z, &ground_z, !((Unit const*)this)->HasAuraType(SPELL_AURA_WATER_WALK)) + : ((ground_z = GetBaseMap()->GetHeight(x, y, z, true))); + if (max_z > INVALID_HEIGHT) + { + if (z > max_z) + z = max_z; + else if (z < ground_z) + z = ground_z; + } + } + else + { + float ground_z = GetBaseMap()->GetHeight(x, y, z, true); + if (z < ground_z) + z = ground_z; + } + break; + } + case TYPEID_PLAYER: + { + // for server controlled moves playr work same as creature (but it can always swim) + if (!((Player const*)this)->CanFly()) + { + float ground_z = z; + float max_z = GetBaseMap()->GetWaterOrGroundLevel(x, y, z, &ground_z, !((Unit const*)this)->HasAuraType(SPELL_AURA_WATER_WALK)); + if (max_z > INVALID_HEIGHT) + { + if (z > max_z) + z = max_z; + else if (z < ground_z) + z = ground_z; + } + } + else + { + float ground_z = GetBaseMap()->GetHeight(x, y, z, true); + if (z < ground_z) + z = ground_z; + } + break; + } + default: + { + float ground_z = GetBaseMap()->GetHeight(x, y, z, true); + if(ground_z > INVALID_HEIGHT) + z = ground_z; + break; + } + } +} + bool WorldObject::IsPositionValid() const { return MaNGOS::IsValidMapCoord(m_positionX,m_positionY,m_positionZ,m_orientation); @@ -1759,7 +1823,10 @@ void WorldObject::GetNearPoint(WorldObject const* searcher, float &x, float &y, // if detection disabled, return first point if(!sWorld.getConfig(CONFIG_BOOL_DETECT_POS_COLLISION)) { - UpdateGroundPositionZ(x,y,z); // update to LOS height if available + if (searcher) + searcher->UpdateAllowedPositionZ(x,y,z); // update to LOS height if available + else + UpdateGroundPositionZ(x,y,z); return; } @@ -1782,7 +1849,10 @@ void WorldObject::GetNearPoint(WorldObject const* searcher, float &x, float &y, // maybe can just place in primary position if( selector.CheckOriginal() ) { - UpdateGroundPositionZ(x,y,z); // update to LOS height if available + if (searcher) + searcher->UpdateAllowedPositionZ(x,y,z); // update to LOS height if available + else + UpdateGroundPositionZ(x,y,z); if(IsWithinLOS(x,y,z)) return; @@ -1797,7 +1867,11 @@ void WorldObject::GetNearPoint(WorldObject const* searcher, float &x, float &y, { GetNearPoint2D(x,y,distance2d,absAngle+angle); z = GetPositionZ(); - UpdateGroundPositionZ(x,y,z); // update to LOS height if available + + if (searcher) + searcher->UpdateAllowedPositionZ(x,y,z); // update to LOS height if available + else + UpdateGroundPositionZ(x,y,z); if(IsWithinLOS(x,y,z)) return; @@ -1811,7 +1885,11 @@ void WorldObject::GetNearPoint(WorldObject const* searcher, float &x, float &y, { GetNearPoint2D(x,y,distance2d,absAngle+angle); z = GetPositionZ(); - UpdateGroundPositionZ(x,y,z); // update to LOS height if available + + if (searcher) + searcher->UpdateAllowedPositionZ(x,y,z); // update to LOS height if available + else + UpdateGroundPositionZ(x,y,z); if(IsWithinLOS(x,y,z)) return; @@ -1825,7 +1903,10 @@ void WorldObject::GetNearPoint(WorldObject const* searcher, float &x, float &y, x = first_x; y = first_y; - UpdateGroundPositionZ(x,y,z); // update to LOS height if available + if (searcher) + searcher->UpdateAllowedPositionZ(x,y,z); // update to LOS height if available + else + UpdateGroundPositionZ(x,y,z); return; } @@ -1836,7 +1917,11 @@ void WorldObject::GetNearPoint(WorldObject const* searcher, float &x, float &y, { GetNearPoint2D(x,y,distance2d,absAngle+angle); z = GetPositionZ(); - UpdateGroundPositionZ(x,y,z); // update to LOS height if available + + if (searcher) + searcher->UpdateAllowedPositionZ(x,y,z); // update to LOS height if available + else + UpdateGroundPositionZ(x,y,z); if(IsWithinLOS(x,y,z)) return; @@ -1851,7 +1936,11 @@ void WorldObject::GetNearPoint(WorldObject const* searcher, float &x, float &y, { GetNearPoint2D(x,y,distance2d,absAngle+angle); z = GetPositionZ(); - UpdateGroundPositionZ(x,y,z); // update to LOS height if available + + if (searcher) + searcher->UpdateAllowedPositionZ(x,y,z); // update to LOS height if available + else + UpdateGroundPositionZ(x,y,z); if(IsWithinLOS(x,y,z)) return; @@ -1861,7 +1950,10 @@ void WorldObject::GetNearPoint(WorldObject const* searcher, float &x, float &y, x = first_x; y = first_y; - UpdateGroundPositionZ(x,y,z); // update to LOS height if available + if (searcher) + searcher->UpdateAllowedPositionZ(x,y,z); // update to LOS height if available + else + UpdateGroundPositionZ(x,y,z); } void WorldObject::SetPhaseMask(uint32 newPhaseMask, bool update) @@ -1963,5 +2055,4 @@ bool WorldObject::IsControlledByPlayer() const default: return false; } -} - +} \ No newline at end of file diff --git a/src/game/Object.h b/src/game/Object.h index ef8e8f98d..336d123b2 100644 --- a/src/game/Object.h +++ b/src/game/Object.h @@ -360,10 +360,10 @@ class MANGOS_DLL_SPEC WorldObject : public Object float GetOrientation( ) const { return m_orientation; } void GetNearPoint2D( float &x, float &y, float distance, float absAngle) const; void GetNearPoint(WorldObject const* searcher, float &x, float &y, float &z, float searcher_bounding_radius, float distance2d, float absAngle) const; - void GetClosePoint(float &x, float &y, float &z, float bounding_radius, float distance2d = 0, float angle = 0) const + void GetClosePoint(float &x, float &y, float &z, float bounding_radius, float distance2d = 0, float angle = 0, const WorldObject* obj = NULL ) const { // angle calculated from current orientation - GetNearPoint(NULL, x, y, z, bounding_radius, distance2d, GetOrientation() + angle); + GetNearPoint(obj, x, y, z, bounding_radius, distance2d, GetOrientation() + angle); } void GetContactPoint( const WorldObject* obj, float &x, float &y, float &z, float distance2d = CONTACT_DISTANCE) const { @@ -375,6 +375,7 @@ class MANGOS_DLL_SPEC WorldObject : public Object bool IsPositionValid() const; void UpdateGroundPositionZ(float x, float y, float &z) const; + void UpdateAllowedPositionZ(float x, float y, float &z) const; void GetRandomPoint( float x, float y, float z, float distance, float &rand_x, float &rand_y, float &rand_z ) const; @@ -517,4 +518,4 @@ class MANGOS_DLL_SPEC WorldObject : public Object ViewPoint m_viewPoint; }; -#endif +#endif \ No newline at end of file diff --git a/src/game/Pet.cpp b/src/game/Pet.cpp index 2e97aee60..06d048ab7 100644 --- a/src/game/Pet.cpp +++ b/src/game/Pet.cpp @@ -164,7 +164,7 @@ bool Pet::LoadPetFromDB( Player* owner, uint32 petentry, uint32 petnumber, bool } float px, py, pz; - owner->GetClosePoint(px, py, pz, GetObjectBoundingRadius(), PET_FOLLOW_DIST, PET_FOLLOW_ANGLE); + owner->GetClosePoint(px, py, pz, GetObjectBoundingRadius(), PET_FOLLOW_DIST, PET_FOLLOW_ANGLE, this); Relocate(px, py, pz, owner->GetOrientation()); diff --git a/src/game/Player.cpp b/src/game/Player.cpp index 79ecd2537..051936e88 100644 --- a/src/game/Player.cpp +++ b/src/game/Player.cpp @@ -2330,8 +2330,7 @@ GameObject* Player::GetGameObjectIfCanInteractWith(ObjectGuid guid, uint32 gameo bool Player::IsUnderWater() const { - return IsInWater() && - GetPositionZ() < (GetBaseMap()->GetWaterLevel(GetPositionX(),GetPositionY())-2); + return GetBaseMap()->IsUnderWater(GetPositionX(), GetPositionY(), GetPositionZ()+2); } void Player::SetInWater(bool apply) @@ -21323,7 +21322,7 @@ void Player::HandleFall(MovementInfo const& movementInfo) uint32 damage = (uint32)(damageperc * GetMaxHealth()*sWorld.getConfig(CONFIG_FLOAT_RATE_DAMAGE_FALL)); float height = movementInfo.GetPos()->z; - UpdateGroundPositionZ(movementInfo.GetPos()->x, movementInfo.GetPos()->y, height); + UpdateAllowedPositionZ(movementInfo.GetPos()->x, movementInfo.GetPos()->y, height); if (damage > 0) { diff --git a/src/game/RandomMovementGenerator.cpp b/src/game/RandomMovementGenerator.cpp index 4ada553a6..5b3e6eab5 100644 --- a/src/game/RandomMovementGenerator.cpp +++ b/src/game/RandomMovementGenerator.cpp @@ -58,11 +58,10 @@ RandomMovementGenerator::_setRandomLocation(Creature &creature) // Limit height change const float distanceZ = rand_norm_f() * sqrtf(dist)/2.0f; nz = Z + distanceZ; - float tz = map->GetHeight(nx, ny, nz-2.0f, false); // Map check only, vmap needed here but need to alter vmaps checks for height. - float wz = map->GetWaterLevel(nx, ny); + float tz = map->GetWaterOrGroundLevel(nx, ny, nz-2.0f); // Problem here, we must fly above the ground and water, not under. Let's try on next tick - if (tz >= nz || wz >= nz) + if (tz >= nz) return; } //else if (is_water_ok) // 3D system under water and above ground (swimming mode) diff --git a/src/game/SpellEffects.cpp b/src/game/SpellEffects.cpp index cc27aca28..f4e638164 100644 --- a/src/game/SpellEffects.cpp +++ b/src/game/SpellEffects.cpp @@ -7198,7 +7198,7 @@ void Spell::EffectLeapForward(SpellEffectIndex eff_idx) fx = fx2; fy = fy2; fz = fz2; - unitTarget->UpdateGroundPositionZ(fx, fy, fz); + unitTarget->UpdateAllowedPositionZ(fx, fy, fz); } unitTarget->NearTeleportTo(fx, fy, fz, unitTarget->GetOrientation(), unitTarget == m_caster); diff --git a/src/game/TargetedMovementGenerator.cpp b/src/game/TargetedMovementGenerator.cpp index 29877ac07..adfe0909c 100644 --- a/src/game/TargetedMovementGenerator.cpp +++ b/src/game/TargetedMovementGenerator.cpp @@ -55,7 +55,7 @@ void TargetedMovementGeneratorMedium::_setTargetLocation(T &owner) else { // to at i_offset distance from target and i_angle from target facing - i_target->GetClosePoint(x, y, z, owner.GetObjectBoundingRadius(), i_offset, i_angle); + i_target->GetClosePoint(x, y, z, owner.GetObjectBoundingRadius(), i_offset, i_angle, &owner); } /* @@ -75,11 +75,6 @@ void TargetedMovementGeneratorMedium::_setTargetLocation(T &owner) return; */ - // Just a temp hack, GetContactPoint/GetClosePoint in above code use UpdateGroundPositionZ (in GetNearPoint) - // and then has the wrong z to use when creature try follow unit in the air. - if (owner.GetTypeId() == TYPEID_UNIT && ((Creature*)&owner)->canFly()) - z = i_target->GetPositionZ(); - Traveller traveller(owner); i_destinationHolder.SetDestination(traveller, x, y, z); diff --git a/src/game/Unit.cpp b/src/game/Unit.cpp index 48af00943..6a80cfe57 100644 --- a/src/game/Unit.cpp +++ b/src/game/Unit.cpp @@ -10506,7 +10506,7 @@ void Unit::KnockBackFrom(Unit* target, float horizontalSpeed, float verticalSpee fz = fz2; } - UpdateGroundPositionZ(fx, fy, fz); + UpdateAllowedPositionZ(fx, fy, fz); //FIXME: this mostly hack, must exist some packet for proper creature move at client side // with CreatureRelocation at server side diff --git a/src/shared/revision_nr.h b/src/shared/revision_nr.h index 9f82e9183..0d21fc040 100644 --- a/src/shared/revision_nr.h +++ b/src/shared/revision_nr.h @@ -1,4 +1,4 @@ #ifndef __REVISION_NR_H__ #define __REVISION_NR_H__ - #define REVISION_NR "10528" + #define REVISION_NR "10529" #endif // __REVISION_NR_H__