diff --git a/apps/openmw/mwmechanics/aipackage.cpp b/apps/openmw/mwmechanics/aipackage.cpp index 646b37669..37f5f5bf7 100644 --- a/apps/openmw/mwmechanics/aipackage.cpp +++ b/apps/openmw/mwmechanics/aipackage.cpp @@ -133,7 +133,7 @@ bool MWMechanics::AiPackage::pathTo(const MWWorld::Ptr& actor, const osg::Vec3f& if (!mIsShortcutting) { - if (wasShortcutting || doesPathNeedRecalc(dest, actor.getCell())) // if need to rebuild path + if (wasShortcutting || doesPathNeedRecalc(dest, actor)) // if need to rebuild path { const auto pathfindingHalfExtents = world->getPathfindingHalfExtents(actor); mPathFinder.buildPath(actor, position, dest, actor.getCell(), getPathGridGraph(actor.getCell()), @@ -328,11 +328,11 @@ bool MWMechanics::AiPackage::checkWayIsClearForActor(const osg::Vec3f& startPoin return false; } -bool MWMechanics::AiPackage::doesPathNeedRecalc(const osg::Vec3f& newDest, const MWWorld::CellStore* currentCell) +bool MWMechanics::AiPackage::doesPathNeedRecalc(const osg::Vec3f& newDest, const MWWorld::Ptr& actor) const { return mPathFinder.getPath().empty() - || (distance(mPathFinder.getPath().back(), newDest) > 10) - || mPathFinder.getPathCell() != currentCell; + || getPathDistance(actor, mPathFinder.getPath().back(), newDest) > 10 + || mPathFinder.getPathCell() != actor.getCell(); } bool MWMechanics::AiPackage::isNearInactiveCell(osg::Vec3f position) diff --git a/apps/openmw/mwmechanics/aipackage.hpp b/apps/openmw/mwmechanics/aipackage.hpp index 6bb12342a..20b4c390e 100644 --- a/apps/openmw/mwmechanics/aipackage.hpp +++ b/apps/openmw/mwmechanics/aipackage.hpp @@ -120,7 +120,7 @@ namespace MWMechanics /// Check if the way to the destination is clear, taking into account actor speed bool checkWayIsClearForActor(const osg::Vec3f& startPoint, const osg::Vec3f& endPoint, const MWWorld::Ptr& actor); - bool doesPathNeedRecalc(const osg::Vec3f& newDest, const MWWorld::CellStore* currentCell); + bool doesPathNeedRecalc(const osg::Vec3f& newDest, const MWWorld::Ptr& actor) const; void evadeObstacles(const MWWorld::Ptr& actor); diff --git a/apps/openmw/mwmechanics/combat.cpp b/apps/openmw/mwmechanics/combat.cpp index 9258c6b2d..27dc0b473 100644 --- a/apps/openmw/mwmechanics/combat.cpp +++ b/apps/openmw/mwmechanics/combat.cpp @@ -20,6 +20,7 @@ #include "spellcasting.hpp" #include "difficultyscaling.hpp" #include "actorutil.hpp" +#include "pathfinding.hpp" namespace { @@ -467,13 +468,8 @@ namespace MWMechanics { osg::Vec3f pos1 (actor1.getRefData().getPosition().asVec3()); osg::Vec3f pos2 (actor2.getRefData().getPosition().asVec3()); - if (canActorMoveByZAxis(actor2)) - { - pos1.z() = 0.f; - pos2.z() = 0.f; - } - float d = (pos1 - pos2).length(); + float d = getAggroDistance(actor2, pos1, pos2); static const int iFightDistanceBase = MWBase::Environment::get().getWorld()->getStore().get().find( "iFightDistanceBase")->mValue.getInteger(); @@ -489,4 +485,11 @@ namespace MWMechanics return (magicEffects.get(ESM::MagicEffect::Invisibility).getMagnitude() > 0) || (magicEffects.get(ESM::MagicEffect::Chameleon).getMagnitude() > 75); } + + float getAggroDistance(const MWWorld::Ptr& actor, const osg::Vec3f& lhs, const osg::Vec3f& rhs) + { + if (canActorMoveByZAxis(actor)) + return distanceIgnoreZ(lhs, rhs); + return distance(lhs, rhs); + } } diff --git a/apps/openmw/mwmechanics/combat.hpp b/apps/openmw/mwmechanics/combat.hpp index fd2717b19..3d4a1bd77 100644 --- a/apps/openmw/mwmechanics/combat.hpp +++ b/apps/openmw/mwmechanics/combat.hpp @@ -55,6 +55,9 @@ void applyFatigueLoss(const MWWorld::Ptr& attacker, const MWWorld::Ptr& weapon, float getFightDistanceBias(const MWWorld::Ptr& actor1, const MWWorld::Ptr& actor2); bool isTargetMagicallyHidden(const MWWorld::Ptr& target); + +float getAggroDistance(const MWWorld::Ptr& actor, const osg::Vec3f& lhs, const osg::Vec3f& rhs); + } #endif diff --git a/apps/openmw/mwmechanics/pathfinding.cpp b/apps/openmw/mwmechanics/pathfinding.cpp index 900f97a67..f7e7c277c 100644 --- a/apps/openmw/mwmechanics/pathfinding.cpp +++ b/apps/openmw/mwmechanics/pathfinding.cpp @@ -18,6 +18,7 @@ #include "pathgrid.hpp" #include "coordinateconverter.hpp" +#include "actorutil.hpp" namespace { @@ -80,10 +81,24 @@ namespace const auto realHalfExtents = world->getHalfExtents(actor); return 2 * std::max(realHalfExtents.x(), realHalfExtents.y()); } + + float getHeight(const MWWorld::ConstPtr& actor) + { + const auto world = MWBase::Environment::get().getWorld(); + const auto halfExtents = world->getHalfExtents(actor); + return 2.0 * halfExtents.z(); + } } namespace MWMechanics { + float getPathDistance(const MWWorld::Ptr& actor, const osg::Vec3f& lhs, const osg::Vec3f& rhs) + { + if (std::abs(lhs.z() - rhs.z()) > getHeight(actor) || canActorMoveByZAxis(actor)) + return distance(lhs, rhs); + return distanceIgnoreZ(lhs, rhs); + } + bool checkWayIsClear(const osg::Vec3f& from, const osg::Vec3f& to, float offsetXY) { osg::Vec3f dir = to - from; diff --git a/apps/openmw/mwmechanics/pathfinding.hpp b/apps/openmw/mwmechanics/pathfinding.hpp index f762b6f18..b413810f4 100644 --- a/apps/openmw/mwmechanics/pathfinding.hpp +++ b/apps/openmw/mwmechanics/pathfinding.hpp @@ -13,17 +13,29 @@ namespace MWWorld { class CellStore; class ConstPtr; + class Ptr; } namespace MWMechanics { class PathgridGraph; - inline float distance(const osg::Vec3f& lhs, const osg::Vec3f& rhs) + template + inline float distance(const T& lhs, const T& rhs) { + static_assert(std::is_same::value + || std::is_same::value, + "T is not a position"); return (lhs - rhs).length(); } + inline float distanceIgnoreZ(const osg::Vec3f& lhs, const osg::Vec3f& rhs) + { + return distance(osg::Vec2f(lhs.x(), lhs.y()), osg::Vec2f(rhs.x(), rhs.y())); + } + + float getPathDistance(const MWWorld::Ptr& actor, const osg::Vec3f& lhs, const osg::Vec3f& rhs); + inline float getZAngleToDir(const osg::Vec3f& dir) { return std::atan2(dir.x(), dir.y()); diff --git a/docs/source/reference/modding/settings/navigator.rst b/docs/source/reference/modding/settings/navigator.rst index 42494a476..db2ad66cf 100644 --- a/docs/source/reference/modding/settings/navigator.rst +++ b/docs/source/reference/modding/settings/navigator.rst @@ -176,12 +176,12 @@ recast scale factor :Type: floating point :Range: > 0.0 -:Default: 0.017647058823529415 +:Default: 0.023529411764705882 Scale of nav mesh coordinates to world coordinates. Recastnavigation builds voxels for world geometry. Basically voxel size is 1 / "cell size". To reduce amount of voxels we apply scale factor, to make voxel size "recast scale factor" / "cell size". Default value calculates by this equation: -sStepSizeUp * "recast scale factor" / "cell size" = 3 (max climb height should be equal to 3 voxels). +sStepSizeUp * "recast scale factor" / "cell size" = 4 (max climb height should be equal to 4 voxels). Changing this value will change generated nav mesh. Some locations may become unavailable for NPC and creatures. Pay attention to slopes and roofs when change it. Increasing this value will reduce nav mesh update latency. diff --git a/files/settings-default.cfg b/files/settings-default.cfg index f8c31eed7..f999cbb01 100644 --- a/files/settings-default.cfg +++ b/files/settings-default.cfg @@ -642,8 +642,8 @@ enable = true # Scale of NavMesh coordinates to world coordinates (value > 0.0). Recastnavigation builds voxels for world geometry. # Basically voxel size is 1 / "cell size". To reduce amount of voxels we apply scale factor, to make voxel size # "recast scale factor" / "cell size". Default value calculates by this equation: -# sStepSizeUp * "recast scale factor" / "cell size" = 3 (max climb height should be equal to 3 voxels) -recast scale factor = 0.017647058823529415 +# sStepSizeUp * "recast scale factor" / "cell size" = 4 (max climb height should be equal to 4 voxels) +recast scale factor = 0.023529411764705882 # The z-axis cell size to use for fields. (value > 0.0) # Defines voxel/grid/cell size. So their values have significant @@ -711,12 +711,6 @@ max smooth path size = 1024 # Maximum number of triangles in each node of mesh AABB tree (value > 0) triangles per chunk = 256 -# Enable debug log (true, false) -enable log = false - -# Write debug log to this file -log path = detournavigator.log - # Write recast mesh to file in .obj format for each use to update nav mesh (true, false) enable write recast mesh to file = false