diff --git a/apps/openmw/mwmechanics/actorutil.cpp b/apps/openmw/mwmechanics/actorutil.cpp index dc37705563..537f271974 100644 --- a/apps/openmw/mwmechanics/actorutil.cpp +++ b/apps/openmw/mwmechanics/actorutil.cpp @@ -3,10 +3,17 @@ #include "../mwbase/world.hpp" #include "../mwbase/environment.hpp" +#include "../mwworld/player.hpp" + namespace MWMechanics { MWWorld::Ptr getPlayer() { return MWBase::Environment::get().getWorld()->getPlayerPtr(); } + + bool isPlayerInCombat() + { + return MWBase::Environment::get().getWorld()->getPlayer().isInCombat(); + } } diff --git a/apps/openmw/mwmechanics/actorutil.hpp b/apps/openmw/mwmechanics/actorutil.hpp index 95172b9f91..510e41db35 100644 --- a/apps/openmw/mwmechanics/actorutil.hpp +++ b/apps/openmw/mwmechanics/actorutil.hpp @@ -1,14 +1,12 @@ #ifndef OPENMW_MWMECHANICS_ACTORUTIL_H #define OPENMW_MWMECHANICS_ACTORUTIL_H -namespace MWWorld -{ - class Ptr; -} +#include "../mwworld/ptr.hpp" namespace MWMechanics { MWWorld::Ptr getPlayer(); + bool isPlayerInCombat(); } #endif diff --git a/apps/openmw/mwmechanics/aipackage.cpp b/apps/openmw/mwmechanics/aipackage.cpp index b6b2408338..1af0f1c5a3 100644 --- a/apps/openmw/mwmechanics/aipackage.cpp +++ b/apps/openmw/mwmechanics/aipackage.cpp @@ -16,6 +16,7 @@ #include "steering.hpp" #include "actorutil.hpp" +#include "coordinateconverter.hpp" MWMechanics::AiPackage::~AiPackage() {} @@ -32,45 +33,24 @@ bool MWMechanics::AiPackage::pathTo(const MWWorld::Ptr& actor, ESM::Pathgrid::Po ESM::Position pos = actor.getRefData().getPosition(); //position of the actor /// Stops the actor when it gets too close to a unloaded cell - const ESM::Cell *cell = actor.getCell()->getCell(); + //... At current time, this test is unnecessary. AI shuts down when actor is more than 7168 + //... units from player, and exterior cells are 8192 units long and wide. + //... But AI processing distance may increase in the future. + if (isNearInactiveCell(pos)) { - MWWorld::Ptr player = getPlayer(); - Movement &movement = actor.getClass().getMovementSettings(actor); - - //Ensure pursuer doesn't leave loaded cells - if(cell->mData.mX != player.getCell()->getCell()->mData.mX) - { - int sideX = PathFinder::sgn(cell->mData.mX - player.getCell()->getCell()->mData.mX); - //check if actor is near the border of an inactive cell. If so, stop walking. - if(sideX * (pos.pos[0] - cell->mData.mX*ESM::Land::REAL_SIZE) > sideX * (ESM::Land::REAL_SIZE/2.0f - 200.0f)) - { - movement.mPosition[1] = 0; - return false; - } - } - if(cell->mData.mY != player.getCell()->getCell()->mData.mY) - { - int sideY = PathFinder::sgn(cell->mData.mY - player.getCell()->getCell()->mData.mY); - //check if actor is near the border of an inactive cell. If so, stop walking. - if(sideY * (pos.pos[1] - cell->mData.mY*ESM::Land::REAL_SIZE) > sideY * (ESM::Land::REAL_SIZE/2.0f - 200.0f)) - { - movement.mPosition[1] = 0; - return false; - } - } + actor.getClass().getMovementSettings(actor).mPosition[1] = 0; + return false; } - //Start position - ESM::Pathgrid::Point start = pos.pos; - //*********************** /// Checks if you can't get to the end position at all, adds end position to end of path /// Rebuilds path every quarter of a second, in case the target has moved //*********************** if(mTimer > 0.25) { + const ESM::Cell *cell = actor.getCell()->getCell(); if (doesPathNeedRecalc(dest, cell)) { //Only rebuild path if it's moved - mPathFinder.buildSyncedPath(start, dest, actor.getCell(), true); //Rebuild path, in case the target has moved + mPathFinder.buildSyncedPath(pos.pos, dest, actor.getCell(), true); //Rebuild path, in case the target has moved mPrevDest = dest; } @@ -133,3 +113,27 @@ bool MWMechanics::AiPackage::isTargetMagicallyHidden(const MWWorld::Ptr& target) return (magicEffects.get(ESM::MagicEffect::Invisibility).getMagnitude() > 0) || (magicEffects.get(ESM::MagicEffect::Chameleon).getMagnitude() > 75); } + +bool MWMechanics::AiPackage::isNearInactiveCell(const ESM::Position& actorPos) +{ + const ESM::Cell* playerCell(getPlayer().getCell()->getCell()); + if (playerCell->isExterior()) + { + // get actor's distance from origin of center cell + osg::Vec3f actorOffset(actorPos.asVec3()); + CoordinateConverter(playerCell).toLocal(actorOffset); + + // currently assumes 3 x 3 grid for exterior cells, with player at center cell. + // ToDo: (Maybe) use "exterior cell load distance" setting to get count of actual active cells + // While AI Process distance is 7168, AI shuts down actors before they reach edges of 3 x 3 grid. + const float distanceFromEdge = 200.0; + float minThreshold = (-1.0f * ESM::Land::REAL_SIZE) + distanceFromEdge; + float maxThreshold = (2.0f * ESM::Land::REAL_SIZE) - distanceFromEdge; + return (actorOffset[0] < minThreshold) || (maxThreshold < actorOffset[0]) + || (actorOffset[1] < minThreshold) || (maxThreshold < actorOffset[1]); + } + else + { + return false; + } +} diff --git a/apps/openmw/mwmechanics/aipackage.hpp b/apps/openmw/mwmechanics/aipackage.hpp index 4f919edbc6..e16d66dbe6 100644 --- a/apps/openmw/mwmechanics/aipackage.hpp +++ b/apps/openmw/mwmechanics/aipackage.hpp @@ -88,6 +88,7 @@ namespace MWMechanics private: void evadeObstacles(const MWWorld::Ptr& actor, float duration, ESM::Position& pos); + bool isNearInactiveCell(const ESM::Position& actorPos); }; } diff --git a/apps/openmw/mwmechanics/aiwander.cpp b/apps/openmw/mwmechanics/aiwander.cpp index b789c44286..a3fdc69ccc 100644 --- a/apps/openmw/mwmechanics/aiwander.cpp +++ b/apps/openmw/mwmechanics/aiwander.cpp @@ -588,7 +588,7 @@ namespace MWMechanics void AiWander::ToWorldCoordinates(ESM::Pathgrid::Point& point, const ESM::Cell * cell) { - CoordinateConverter(cell).ToWorld(point); + CoordinateConverter(cell).toWorld(point); } void AiWander::trimAllowedNodes(std::vector& nodes, @@ -746,7 +746,7 @@ namespace MWMechanics { // get NPC's position in local (i.e. cell) co-ordinates osg::Vec3f npcPos(mInitialActorPosition); - CoordinateConverter(cell).ToLocal(npcPos); + CoordinateConverter(cell).toLocal(npcPos); // mAllowedNodes for this actor with pathgrid point indexes based on mDistance // NOTE: mPoints and mAllowedNodes are in local co-ordinates diff --git a/apps/openmw/mwmechanics/coordinateconverter.cpp b/apps/openmw/mwmechanics/coordinateconverter.cpp index 583ac41c52..0a2d99f924 100644 --- a/apps/openmw/mwmechanics/coordinateconverter.cpp +++ b/apps/openmw/mwmechanics/coordinateconverter.cpp @@ -15,25 +15,25 @@ namespace MWMechanics } } - void CoordinateConverter::ToWorld(ESM::Pathgrid::Point& point) + void CoordinateConverter::toWorld(ESM::Pathgrid::Point& point) { point.mX += mCellX; point.mY += mCellY; } - void CoordinateConverter::ToWorld(osg::Vec3f& point) + void CoordinateConverter::toWorld(osg::Vec3f& point) { point.x() += static_cast(mCellX); point.y() += static_cast(mCellY); } - void CoordinateConverter::ToLocal(osg::Vec3f& point) + void CoordinateConverter::toLocal(osg::Vec3f& point) { point.x() -= static_cast(mCellX); point.y() -= static_cast(mCellY); } - osg::Vec3f CoordinateConverter::ToLocalVec3(const ESM::Pathgrid::Point& point) + osg::Vec3f CoordinateConverter::toLocalVec3(const ESM::Pathgrid::Point& point) { return osg::Vec3f( static_cast(point.mX - mCellX), diff --git a/apps/openmw/mwmechanics/coordinateconverter.hpp b/apps/openmw/mwmechanics/coordinateconverter.hpp index 2c4d3d3ba8..cd855e84a2 100644 --- a/apps/openmw/mwmechanics/coordinateconverter.hpp +++ b/apps/openmw/mwmechanics/coordinateconverter.hpp @@ -18,15 +18,15 @@ namespace MWMechanics CoordinateConverter(const ESM::Cell* cell); /// in-place conversion from local to world - void ToWorld(ESM::Pathgrid::Point& point); + void toWorld(ESM::Pathgrid::Point& point); /// in-place conversion from local to world - void ToWorld(osg::Vec3f& point); + void toWorld(osg::Vec3f& point); /// in-place conversion from world to local - void ToLocal(osg::Vec3f& point); + void toLocal(osg::Vec3f& point); - osg::Vec3f ToLocalVec3(const ESM::Pathgrid::Point& point); + osg::Vec3f toLocalVec3(const ESM::Pathgrid::Point& point); private: int mCellX; diff --git a/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp b/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp index 711ecdbd28..12927101d8 100644 --- a/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp +++ b/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp @@ -927,7 +927,7 @@ namespace MWMechanics return true; } - if(MWBase::Environment::get().getWorld()->getPlayer().isInCombat()) { + if(MWMechanics::isPlayerInCombat()) { MWBase::Environment::get().getWindowManager()->messageBox("#{sNotifyMessage2}"); return true; } diff --git a/apps/openmw/mwmechanics/pathfinding.cpp b/apps/openmw/mwmechanics/pathfinding.cpp index daab321367..f26d3e109a 100644 --- a/apps/openmw/mwmechanics/pathfinding.cpp +++ b/apps/openmw/mwmechanics/pathfinding.cpp @@ -207,10 +207,10 @@ namespace MWMechanics // outside an area enclosed by walls, but there is a pathgrid // point right behind the wall that is closer than any pathgrid // point outside the wall - osg::Vec3f startPointInLocalCoords(converter.ToLocalVec3(startPoint)); + osg::Vec3f startPointInLocalCoords(converter.toLocalVec3(startPoint)); int startNode = getClosestPoint(mPathgrid, startPointInLocalCoords); - osg::Vec3f endPointInLocalCoords(converter.ToLocalVec3(endPoint)); + osg::Vec3f endPointInLocalCoords(converter.toLocalVec3(endPoint)); std::pair endNode = getClosestReachablePoint(mPathgrid, cell, endPointInLocalCoords, startNode); @@ -223,7 +223,7 @@ namespace MWMechanics if(startNode == endNode.first) { ESM::Pathgrid::Point temp(mPathgrid->mPoints[startNode]); - converter.ToWorld(temp); + converter.toWorld(temp); mPath.push_back(temp); } else @@ -233,7 +233,7 @@ namespace MWMechanics // convert supplied path to world co-ordinates for (std::list::iterator iter(mPath.begin()); iter != mPath.end(); ++iter) { - converter.ToWorld(*iter); + converter.toWorld(*iter); } } diff --git a/apps/openmw/mwrender/pathgrid.cpp b/apps/openmw/mwrender/pathgrid.cpp index bd22446dea..ae8bda1fb7 100644 --- a/apps/openmw/mwrender/pathgrid.cpp +++ b/apps/openmw/mwrender/pathgrid.cpp @@ -208,7 +208,7 @@ void Pathgrid::enableCellPathgrid(const MWWorld::CellStore *store) if (!pathgrid) return; osg::Vec3f cellPathGridPos(0, 0, 0); - MWMechanics::CoordinateConverter(store->getCell()).ToWorld(cellPathGridPos); + MWMechanics::CoordinateConverter(store->getCell()).toWorld(cellPathGridPos); osg::ref_ptr cellPathGrid = new osg::PositionAttitudeTransform; cellPathGrid->setPosition(cellPathGridPos); diff --git a/apps/openmw/mwworld/actionalchemy.cpp b/apps/openmw/mwworld/actionalchemy.cpp index f413f1aed8..53ed1ad848 100644 --- a/apps/openmw/mwworld/actionalchemy.cpp +++ b/apps/openmw/mwworld/actionalchemy.cpp @@ -5,15 +5,16 @@ #include "../mwbase/world.hpp" #include "../mwworld/player.hpp" +#include "../mwmechanics/actorutil.hpp" namespace MWWorld { void ActionAlchemy::executeImp (const Ptr& actor) { - if (actor != MWBase::Environment::get().getWorld()->getPlayerPtr()) + if (actor != MWMechanics::getPlayer()) return; - if(MWBase::Environment::get().getWorld()->getPlayer().isInCombat()) { //Ensure we're not in combat + if(MWMechanics::isPlayerInCombat()) { //Ensure we're not in combat MWBase::Environment::get().getWindowManager()->messageBox("#{sInventoryMessage3}"); return; } diff --git a/apps/openmw/mwworld/actionapply.cpp b/apps/openmw/mwworld/actionapply.cpp index 42757a41a1..e3699a6ac3 100644 --- a/apps/openmw/mwworld/actionapply.cpp +++ b/apps/openmw/mwworld/actionapply.cpp @@ -7,6 +7,8 @@ #include "../mwworld/containerstore.hpp" +#include "../mwmechanics/actorutil.hpp" + namespace MWWorld { ActionApply::ActionApply (const Ptr& object, const std::string& id) @@ -32,7 +34,7 @@ namespace MWWorld { MWBase::Environment::get().getWorld()->breakInvisibility(actor); - if (actor.getClass().apply (actor, mId, actor) && mUsageType!=-1 && actor == MWBase::Environment::get().getWorld()->getPlayerPtr()) + if (actor.getClass().apply (actor, mId, actor) && mUsageType!=-1 && actor == MWMechanics::getPlayer()) actor.getClass().skillUsageSucceeded (actor, mSkillIndex, mUsageType); actor.getClass().getContainerStore(actor).remove(getTarget(), 1, actor); diff --git a/apps/openmw/mwworld/actioneat.cpp b/apps/openmw/mwworld/actioneat.cpp index 5339a113e5..82c7fb80e4 100644 --- a/apps/openmw/mwworld/actioneat.cpp +++ b/apps/openmw/mwworld/actioneat.cpp @@ -7,6 +7,8 @@ #include "../mwworld/containerstore.hpp" +#include "../mwmechanics/actorutil.hpp" + #include "class.hpp" namespace MWWorld @@ -19,7 +21,7 @@ namespace MWWorld // apply to actor std::string id = getTarget().getClass().getId (getTarget()); - if (actor.getClass().apply (actor, id, actor) && actor == MWBase::Environment::get().getWorld()->getPlayerPtr()) + if (actor.getClass().apply (actor, id, actor) && actor == MWMechanics::getPlayer()) actor.getClass().skillUsageSucceeded (actor, ESM::Skill::Alchemy, 1); } diff --git a/apps/openmw/mwworld/actionread.cpp b/apps/openmw/mwworld/actionread.cpp index d77ca73fda..90e9a375b3 100644 --- a/apps/openmw/mwworld/actionread.cpp +++ b/apps/openmw/mwworld/actionread.cpp @@ -5,6 +5,7 @@ #include "../mwbase/world.hpp" #include "../mwmechanics/npcstats.hpp" +#include "../mwmechanics/actorutil.hpp" #include "player.hpp" #include "class.hpp" @@ -18,11 +19,11 @@ namespace MWWorld void ActionRead::executeImp (const MWWorld::Ptr& actor) { - if (actor != MWBase::Environment::get().getWorld()->getPlayerPtr()) + if (actor != MWMechanics::getPlayer()) return; //Ensure we're not in combat - if(MWBase::Environment::get().getWorld()->getPlayer().isInCombat() + if(MWMechanics::isPlayerInCombat() // Reading in combat is still allowed if the scroll/book is not in the player inventory yet // (since otherwise, there would be no way to pick it up) && getTarget().getContainerStore() == &actor.getClass().getContainerStore(actor) diff --git a/apps/openmw/mwworld/actionrepair.cpp b/apps/openmw/mwworld/actionrepair.cpp index 993f32cdeb..8e19927b80 100644 --- a/apps/openmw/mwworld/actionrepair.cpp +++ b/apps/openmw/mwworld/actionrepair.cpp @@ -4,6 +4,7 @@ #include "../mwbase/windowmanager.hpp" #include "../mwbase/world.hpp" #include "../mwworld/player.hpp" +#include "../mwmechanics/actorutil.hpp" namespace MWWorld { @@ -14,10 +15,10 @@ namespace MWWorld void ActionRepair::executeImp (const Ptr& actor) { - if (actor != MWBase::Environment::get().getWorld()->getPlayerPtr()) + if (actor != MWMechanics::getPlayer()) return; - if(MWBase::Environment::get().getWorld()->getPlayer().isInCombat()) { + if(MWMechanics::isPlayerInCombat()) { MWBase::Environment::get().getWindowManager()->messageBox("#{sInventoryMessage2}"); return; } diff --git a/apps/openmw/mwworld/actionsoulgem.cpp b/apps/openmw/mwworld/actionsoulgem.cpp index f87c16482f..98fe8ee34d 100644 --- a/apps/openmw/mwworld/actionsoulgem.cpp +++ b/apps/openmw/mwworld/actionsoulgem.cpp @@ -4,6 +4,7 @@ #include "../mwbase/environment.hpp" #include "../mwbase/world.hpp" #include "../mwworld/player.hpp" +#include "../mwmechanics/actorutil.hpp" namespace MWWorld { @@ -16,10 +17,10 @@ namespace MWWorld void ActionSoulgem::executeImp(const Ptr &actor) { - if (actor != MWBase::Environment::get().getWorld()->getPlayerPtr()) + if (actor != MWMechanics::getPlayer()) return; - if(MWBase::Environment::get().getWorld()->getPlayer().isInCombat()) { //Ensure we're not in combat + if(MWMechanics::isPlayerInCombat()) { //Ensure we're not in combat MWBase::Environment::get().getWindowManager()->messageBox("#{sInventoryMessage5}"); return; }