[10431] Correcting issues with flying creatures falling to ground at death.

Simplified the way FallGround works and death states are set in a more logical way when a mob is in fact DEAD_FALLING.
Visual will in some cases not be correct. Notes in code for details.

Thanks to Lynx fixing Map::GetHeight
It now return mapHeight as last resort, making FallGround work as expected.
This fix reveal one (known) bug, and therefore a temp hack is added in TargetedMovegen, to be sure Z is not the ground Z for a creature that are able to fly.
Other creatures will follow by the ground level Z (in other words, they will no longer follow in the air).
This commit is contained in:
NoFantasy 2010-09-01 00:30:45 +02:00
parent 7df3f06d87
commit 32e3e252fb
6 changed files with 57 additions and 28 deletions

View file

@ -561,15 +561,13 @@ void Creature::Update(uint32 diff)
} }
case DEAD_FALLING: case DEAD_FALLING:
{ {
if (!FallGround()) setDeathState(CORPSE);
setDeathState(JUST_DIED);
} }
default: default:
break; break;
} }
} }
void Creature::StartGroupLoot( Group* group, uint32 timer ) void Creature::StartGroupLoot( Group* group, uint32 timer )
{ {
m_groupLootId = group->GetId(); m_groupLootId = group->GetId();
@ -1379,13 +1377,8 @@ void Creature::setDeathState(DeathState s)
// always save boss respawn time at death to prevent crash cheating // always save boss respawn time at death to prevent crash cheating
if (sWorld.getConfig(CONFIG_BOOL_SAVE_RESPAWN_TIME_IMMEDIATLY) || isWorldBoss()) if (sWorld.getConfig(CONFIG_BOOL_SAVE_RESPAWN_TIME_IMMEDIATLY) || isWorldBoss())
SaveRespawnTime(); SaveRespawnTime();
if (canFly() && FallGround())
return;
if (!IsStopped())
StopMoving();
} }
Unit::setDeathState(s); Unit::setDeathState(s);
if (s == JUST_DIED) if (s == JUST_DIED)
@ -1393,17 +1386,19 @@ void Creature::setDeathState(DeathState s)
SetTargetGUID(0); // remove target selection in any cases (can be set at aura remove in Unit::setDeathState) SetTargetGUID(0); // remove target selection in any cases (can be set at aura remove in Unit::setDeathState)
SetUInt32Value(UNIT_NPC_FLAGS, UNIT_NPC_FLAG_NONE); SetUInt32Value(UNIT_NPC_FLAGS, UNIT_NPC_FLAG_NONE);
if (canFly() && FallGround())
return;
if (HasSearchedAssistance()) if (HasSearchedAssistance())
{ {
SetNoSearchAssistance(false); SetNoSearchAssistance(false);
UpdateSpeed(MOVE_RUN, false); UpdateSpeed(MOVE_RUN, false);
} }
// return, since we promote to DEAD_FALLING. DEAD_FALLING is promoted to CORPSE at next update.
if (canFly() && FallGround())
return;
Unit::setDeathState(CORPSE); Unit::setDeathState(CORPSE);
} }
if (s == JUST_ALIVED) if (s == JUST_ALIVED)
{ {
SetHealth(GetMaxHealth()); SetHealth(GetMaxHealth());
@ -1423,20 +1418,44 @@ void Creature::setDeathState(DeathState s)
bool Creature::FallGround() bool Creature::FallGround()
{ {
// Let's abort after we called this function one time // Only if state is JUST_DIED. DEAD_FALLING is set below and promoted to CORPSE later
if (getDeathState() == DEAD_FALLING) if (getDeathState() != JUST_DIED)
return false; return false;
// use larger distance for vmap height search than in most other cases // use larger distance for vmap height search than in most other cases
float tz = GetMap()->GetHeight(GetPositionX(), GetPositionY(), GetPositionZ(), true, MAX_FALL_DISTANCE); float tz = GetMap()->GetHeight(GetPositionX(), GetPositionY(), GetPositionZ(), true, MAX_FALL_DISTANCE);
if (tz < INVALID_HEIGHT)
{
DEBUG_LOG("FallGround: creature %u at map %u (x: %f, y: %f, z: %f), not able to retrive a proper GetHeight (z: %f).",
GetEntry(), GetMap()->GetId(), GetPositionX(), GetPositionX(), GetPositionZ(), tz);
}
// Abort too if the ground is very near // Abort too if the ground is very near
if (fabs(GetPositionZ() - tz) < 0.1f) if (fabs(GetPositionZ() - tz) < 0.1f)
return false; return false;
Unit::setDeathState(DEAD_FALLING); Unit::setDeathState(DEAD_FALLING);
GetMotionMaster()->MovePoint(0, GetPositionX(), GetPositionY(), tz);
Relocate(GetPositionX(), GetPositionY(), tz); float dz = tz - GetPositionZ();
float distance = sqrt(dz*dz);
// flight speed * 2 explicit, not verified though but result looks proper
double speed = GetSpeed(MOVE_FLIGHT) * 2;
speed *= 0.001; // to milliseconds
uint32 travelTime = uint32(distance/speed);
DEBUG_LOG("FallGround: traveltime: %u, distance: %f, speed: %f, from %f to %f", travelTime, distance, speed, GetPositionZ(), tz);
// For creatures that are moving towards target and dies, the visual effect is not nice.
// It is possibly caused by a xyz mismatch in DestinationHolder's GetLocationNow and the location
// of the mob in client. For mob that are already reached target or dies while not moving
// the visual appear to be fairly close to the expected.
GetMap()->CreatureRelocation(this, GetPositionX(), GetPositionY(), tz, GetOrientation());
SendMonsterMove(GetPositionX(), GetPositionY(), tz, SPLINETYPE_NORMAL, SPLINEFLAG_FALLING, travelTime);
return true; return true;
} }

View file

@ -1063,15 +1063,8 @@ float Map::GetHeight(float x, float y, float z, bool pUseVmaps, float maxSearchD
else else
return vmapHeight; // we have only vmapHeight (if have) return vmapHeight; // we have only vmapHeight (if have)
} }
else
{ return mapHeight;
if(!pUseVmaps)
return mapHeight; // explicitly use map data (if have)
else if(mapHeight > INVALID_HEIGHT && (z < mapHeight + 2 || z == MAX_HEIGHT))
return mapHeight; // explicitly use map data if original z < mapHeight but map found (z+2 > mapHeight)
else
return VMAP_INVALID_HEIGHT_VALUE; // we not have any height
}
} }
inline bool IsOutdoorWMO(uint32 mogpFlags, int32 adtId, int32 rootId, int32 groupId, inline bool IsOutdoorWMO(uint32 mogpFlags, int32 adtId, int32 rootId, int32 groupId,

View file

@ -74,6 +74,12 @@ void TargetedMovementGeneratorMedium<T,D>::_setTargetLocation(T &owner)
if( i_destinationHolder.HasDestination() && i_destinationHolder.GetDestinationDiff(x,y,z) < bothObjectSize ) if( i_destinationHolder.HasDestination() && i_destinationHolder.GetDestinationDiff(x,y,z) < bothObjectSize )
return; 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<T> traveller(owner); Traveller<T> traveller(owner);
i_destinationHolder.SetDestination(traveller, x, y, z); i_destinationHolder.SetDestination(traveller, x, y, z);

View file

@ -92,7 +92,7 @@ inline float Traveller<Creature>::GetMoveDestinationTo(float x, float y, float z
float dx = x - GetPositionX(); float dx = x - GetPositionX();
float dy = y - GetPositionY(); float dy = y - GetPositionY();
if(i_traveller.hasUnitState(UNIT_STAT_TAXI_FLIGHT)) if (i_traveller.canFly())
{ {
float dz = z - GetPositionZ(); float dz = z - GetPositionZ();
return sqrt((dx*dx) + (dy*dy) + (dz*dz)); return sqrt((dx*dx) + (dy*dy) + (dz*dz));

View file

@ -8217,7 +8217,18 @@ void Unit::setDeathState(DeathState s)
// after removing a Fearaura (in RemoveAllAurasOnDeath) // after removing a Fearaura (in RemoveAllAurasOnDeath)
// Unit::SetFeared is called and makes that creatures attack player again // Unit::SetFeared is called and makes that creatures attack player again
StopMoving(); if (GetTypeId() == TYPEID_UNIT)
{
clearUnitState(UNIT_STAT_MOVING);
GetMap()->CreatureRelocation((Creature*)this, GetPositionX(), GetPositionY(), GetPositionZ(), GetOrientation());
SendMonsterMove(GetPositionX(), GetPositionY(), GetPositionZ(), SPLINETYPE_NORMAL, SPLINEFLAG_WALKMODE, 0);
}
else
{
if (!IsStopped())
StopMoving();
}
ModifyAuraState(AURA_STATE_HEALTHLESS_20_PERCENT, false); ModifyAuraState(AURA_STATE_HEALTHLESS_20_PERCENT, false);
ModifyAuraState(AURA_STATE_HEALTHLESS_35_PERCENT, false); ModifyAuraState(AURA_STATE_HEALTHLESS_35_PERCENT, false);

View file

@ -1,4 +1,4 @@
#ifndef __REVISION_NR_H__ #ifndef __REVISION_NR_H__
#define __REVISION_NR_H__ #define __REVISION_NR_H__
#define REVISION_NR "10430" #define REVISION_NR "10431"
#endif // __REVISION_NR_H__ #endif // __REVISION_NR_H__