diff --git a/common/ruletypes.h b/common/ruletypes.h index 945c2625a..b97c061bd 100644 --- a/common/ruletypes.h +++ b/common/ruletypes.h @@ -275,6 +275,7 @@ RULE_BOOL(Map, FixPathingZAtWaypoints, false) //alternative to `WhenLoading`, ac RULE_BOOL(Map, FixPathingZWhenMoving, false) //very CPU intensive, but helps hopping with widely spaced waypoints. RULE_BOOL(Map, FixPathingZOnSendTo, false) //try to repair Z coords in the SendTo routine as well. RULE_BOOL(Map, FixZWhenMoving, true) // Automatically fix NPC Z coordinates when moving/pathing/engaged (Far less CPU intensive than its predecessor) +RULE_BOOL(Map, MobZVisualDebug, false) // Displays spell effects determining whether or not NPC is hitting Best Z calcs (blue for hit, red for miss) RULE_REAL(Map, FixPathingZMaxDeltaMoving, 20) //at runtime while pathing: max change in Z to allow the BestZ code to apply. RULE_REAL(Map, FixPathingZMaxDeltaWaypoint, 20) //at runtime at each waypoint: max change in Z to allow the BestZ code to apply. RULE_REAL(Map, FixPathingZMaxDeltaSendTo, 20) //at runtime in SendTo: max change in Z to allow the BestZ code to apply. diff --git a/zone/attack.cpp b/zone/attack.cpp index 04cb65c9a..b681745e7 100644 --- a/zone/attack.cpp +++ b/zone/attack.cpp @@ -2392,7 +2392,13 @@ bool NPC::Death(Mob* killer_mob, int32 damage, uint16 spell, EQEmu::skills::Skil glm::vec3 dest(m_Position.x, m_Position.y, m_Position.z); float new_z = zone->zonemap->FindBestZ(dest, nullptr); corpse->SetFlyMode(1); - corpse->GMMove(m_Position.x, m_Position.y, new_z + 5, m_Position.w); + float size = GetSize(); + if (size > 10) + size = 10; + + new_z += size / 2; + + corpse->GMMove(m_Position.x, m_Position.y, new_z, m_Position.w); this->SetID(0); diff --git a/zone/bonuses.cpp b/zone/bonuses.cpp index 232b74b2a..22a323a81 100644 --- a/zone/bonuses.cpp +++ b/zone/bonuses.cpp @@ -48,6 +48,14 @@ void Mob::CalcBonuses() SetAttackTimer(); CalcAC(); + /* Fast walking NPC's are prone to disappear into walls/hills + We set this here because NPC's can cast spells to change walkspeed/runspeed + */ + float get_walk_speed = static_cast(0.025f * this->GetWalkspeed()); + if (get_walk_speed >= 0.9 && this->fix_z_timer.GetDuration() != 100) { + this->fix_z_timer.SetTimer(100); + } + rooted = FindType(SE_Root); } diff --git a/zone/mob.cpp b/zone/mob.cpp index c411f6a3c..7e04221c3 100644 --- a/zone/mob.cpp +++ b/zone/mob.cpp @@ -113,7 +113,7 @@ Mob::Mob(const char* in_name, tmHidden(-1), mitigation_ac(0), m_specialattacks(eSpecialAttacks::None), - fix_z_timer(1000), + fix_z_timer(300), fix_z_timer_engaged(100) { targeted = 0; @@ -121,6 +121,8 @@ Mob::Mob(const char* in_name, tar_vector=0; currently_fleeing = false; + last_z = 0; + AI_Init(); SetMoving(false); moved=false; diff --git a/zone/mob.h b/zone/mob.h index 109cd3656..bb07679c8 100644 --- a/zone/mob.h +++ b/zone/mob.h @@ -1067,6 +1067,8 @@ public: int GetWeaponDamage(Mob *against, const EQEmu::ItemData *weapon_item); int GetWeaponDamage(Mob *against, const EQEmu::ItemInstance *weapon_item, uint32 *hate = nullptr); + float last_z; + // Bots HealRotation methods #ifdef BOTS bool IsHealRotationTarget() { return (m_target_of_heal_rotation.use_count() && m_target_of_heal_rotation.get()); } diff --git a/zone/waypoints.cpp b/zone/waypoints.cpp index 6ceee481e..2271bced0 100644 --- a/zone/waypoints.cpp +++ b/zone/waypoints.cpp @@ -870,6 +870,7 @@ void Mob::SendToFixZ(float new_x, float new_y, float new_z) { } void Mob::FixZ() { + BenchTimer timer; timer.reset(); @@ -878,9 +879,8 @@ void Mob::FixZ() { if (!RuleB(Watermap, CheckForWaterWhenMoving) || !zone->HasWaterMap() || (zone->HasWaterMap() && !zone->watermap->InWater(glm::vec3(m_Position)))) { - glm::vec3 dest(m_Position.x, m_Position.y, m_Position.z); - float new_z = zone->zonemap->FindBestZ(dest, nullptr); + float new_z = this->FindGroundZ(m_Position.x, m_Position.y, 10); auto duration = timer.elapsed(); @@ -896,8 +896,26 @@ void Mob::FixZ() { duration ); - if ((new_z > -2000) && std::abs(new_z - dest.z) < RuleR(Map, FixPathingZMaxDeltaMoving)) - m_Position.z = new_z + 1; + float size = GetSize(); + if (size > 10) + size = 10; + + new_z += size / 2; + + if ((new_z > -2000) && std::abs(m_Position.z - new_z) < 35) { + if (RuleB(Map, MobZVisualDebug)) + this->SendAppearanceEffect(78, 0, 0, 0, 0); + + m_Position.z = new_z; + } + else { + if (RuleB(Map, MobZVisualDebug)) + this->SendAppearanceEffect(103, 0, 0, 0, 0); + + Log(Logs::General, Logs::Debug, "%s is failing to find Z %f", this->GetCleanName(), std::abs(m_Position.z - new_z)); + } + + last_z = m_Position.z; } } }