forked from teamnwah/openmw-tes3coop
Merge pull request #349 from OpenMW/master
Add OpenMW commits up to 28 Nov 2017
This commit is contained in:
commit
22521578eb
25 changed files with 292 additions and 94 deletions
|
@ -191,6 +191,7 @@ void CSMPrefs::State::declare()
|
||||||
setTooltip ("Acceleration factor during drag operations while holding down shift").
|
setTooltip ("Acceleration factor during drag operations while holding down shift").
|
||||||
setRange (0.001, 100.0);
|
setRange (0.001, 100.0);
|
||||||
declareDouble ("rotate-factor", "Free rotation factor", 0.007).setPrecision(4).setRange(0.0001, 0.1);
|
declareDouble ("rotate-factor", "Free rotation factor", 0.007).setPrecision(4).setRange(0.0001, 0.1);
|
||||||
|
declareDouble ("object-marker-alpha", "Object Marker Transparency", 0.5).setPrecision(2).setRange(0,1);
|
||||||
|
|
||||||
declareCategory ("Tooltips");
|
declareCategory ("Tooltips");
|
||||||
declareBool ("scene", "Show Tooltips in 3D scenes", true);
|
declareBool ("scene", "Show Tooltips in 3D scenes", true);
|
||||||
|
|
|
@ -3,6 +3,7 @@
|
||||||
#include <stdexcept>
|
#include <stdexcept>
|
||||||
#include <iostream>
|
#include <iostream>
|
||||||
|
|
||||||
|
#include <osg/Depth>
|
||||||
#include <osg/Group>
|
#include <osg/Group>
|
||||||
#include <osg/PositionAttitudeTransform>
|
#include <osg/PositionAttitudeTransform>
|
||||||
|
|
||||||
|
@ -21,6 +22,7 @@
|
||||||
#include "../../model/world/universalid.hpp"
|
#include "../../model/world/universalid.hpp"
|
||||||
#include "../../model/world/commandmacro.hpp"
|
#include "../../model/world/commandmacro.hpp"
|
||||||
#include "../../model/world/cellcoordinates.hpp"
|
#include "../../model/world/cellcoordinates.hpp"
|
||||||
|
#include "../../model/prefs/state.hpp"
|
||||||
|
|
||||||
#include <components/resource/scenemanager.hpp>
|
#include <components/resource/scenemanager.hpp>
|
||||||
#include <components/sceneutil/lightutil.hpp>
|
#include <components/sceneutil/lightutil.hpp>
|
||||||
|
@ -220,7 +222,7 @@ osg::ref_ptr<osg::Node> CSVRender::Object::makeMoveOrScaleMarker (int axis)
|
||||||
|
|
||||||
for (int i=0; i<2; ++i)
|
for (int i=0; i<2; ++i)
|
||||||
{
|
{
|
||||||
float length = i ? shaftLength : 0;
|
float length = i ? shaftLength : MarkerShaftWidth;
|
||||||
|
|
||||||
vertices->push_back (getMarkerPosition (-MarkerShaftWidth/2, -MarkerShaftWidth/2, length, axis));
|
vertices->push_back (getMarkerPosition (-MarkerShaftWidth/2, -MarkerShaftWidth/2, length, axis));
|
||||||
vertices->push_back (getMarkerPosition (-MarkerShaftWidth/2, MarkerShaftWidth/2, length, axis));
|
vertices->push_back (getMarkerPosition (-MarkerShaftWidth/2, MarkerShaftWidth/2, length, axis));
|
||||||
|
@ -285,15 +287,15 @@ osg::ref_ptr<osg::Node> CSVRender::Object::makeMoveOrScaleMarker (int axis)
|
||||||
|
|
||||||
for (int i=0; i<8; ++i)
|
for (int i=0; i<8; ++i)
|
||||||
colours->push_back (osg::Vec4f (axis==0 ? 1.0f : 0.2f, axis==1 ? 1.0f : 0.2f,
|
colours->push_back (osg::Vec4f (axis==0 ? 1.0f : 0.2f, axis==1 ? 1.0f : 0.2f,
|
||||||
axis==2 ? 1.0f : 0.2f, 1.0f));
|
axis==2 ? 1.0f : 0.2f, mMarkerTransparency));
|
||||||
|
|
||||||
for (int i=8; i<8+4+1; ++i)
|
for (int i=8; i<8+4+1; ++i)
|
||||||
colours->push_back (osg::Vec4f (axis==0 ? 1.0f : 0.0f, axis==1 ? 1.0f : 0.0f,
|
colours->push_back (osg::Vec4f (axis==0 ? 1.0f : 0.0f, axis==1 ? 1.0f : 0.0f,
|
||||||
axis==2 ? 1.0f : 0.0f, 1.0f));
|
axis==2 ? 1.0f : 0.0f, mMarkerTransparency));
|
||||||
|
|
||||||
geometry->setColorArray (colours, osg::Array::BIND_PER_VERTEX);
|
geometry->setColorArray (colours, osg::Array::BIND_PER_VERTEX);
|
||||||
|
|
||||||
geometry->getOrCreateStateSet()->setMode (GL_LIGHTING, osg::StateAttribute::OFF);
|
setupCommonMarkerState(geometry);
|
||||||
|
|
||||||
osg::ref_ptr<osg::Geode> geode (new osg::Geode);
|
osg::ref_ptr<osg::Geode> geode (new osg::Geode);
|
||||||
geode->addDrawable (geometry);
|
geode->addDrawable (geometry);
|
||||||
|
@ -305,11 +307,11 @@ osg::ref_ptr<osg::Node> CSVRender::Object::makeRotateMarker (int axis)
|
||||||
{
|
{
|
||||||
const float Pi = 3.14159265f;
|
const float Pi = 3.14159265f;
|
||||||
|
|
||||||
const float InnerRadius = mBaseNode->getBound().radius();
|
const float InnerRadius = std::max(MarkerShaftBaseLength, mBaseNode->getBound().radius());
|
||||||
const float OuterRadius = InnerRadius + MarkerShaftWidth;
|
const float OuterRadius = InnerRadius + MarkerShaftWidth;
|
||||||
|
|
||||||
const float SegmentDistance = 100.f;
|
const float SegmentDistance = 100.f;
|
||||||
const size_t SegmentCount = std::min(64, std::max(8, (int)(OuterRadius * 2 * Pi / SegmentDistance)));
|
const size_t SegmentCount = std::min(64, std::max(24, (int)(OuterRadius * 2 * Pi / SegmentDistance)));
|
||||||
const size_t VerticesPerSegment = 4;
|
const size_t VerticesPerSegment = 4;
|
||||||
const size_t IndicesPerSegment = 24;
|
const size_t IndicesPerSegment = 24;
|
||||||
|
|
||||||
|
@ -334,6 +336,9 @@ osg::ref_ptr<osg::Node> CSVRender::Object::makeRotateMarker (int axis)
|
||||||
osg::ref_ptr<osg::DrawElementsUShort> primitives = new osg::DrawElementsUShort(osg::PrimitiveSet::TRIANGLES,
|
osg::ref_ptr<osg::DrawElementsUShort> primitives = new osg::DrawElementsUShort(osg::PrimitiveSet::TRIANGLES,
|
||||||
IndexCount);
|
IndexCount);
|
||||||
|
|
||||||
|
// prevent some depth collision issues from overlaps
|
||||||
|
osg::Vec3f offset = getMarkerPosition(0, MarkerShaftWidth/4, 0, axis);
|
||||||
|
|
||||||
for (size_t i = 0; i < SegmentCount; ++i)
|
for (size_t i = 0; i < SegmentCount; ++i)
|
||||||
{
|
{
|
||||||
size_t index = i * VerticesPerSegment;
|
size_t index = i * VerticesPerSegment;
|
||||||
|
@ -344,13 +349,17 @@ osg::ref_ptr<osg::Node> CSVRender::Object::makeRotateMarker (int axis)
|
||||||
float outerX = OuterRadius * std::cos(i * Angle);
|
float outerX = OuterRadius * std::cos(i * Angle);
|
||||||
float outerY = OuterRadius * std::sin(i * Angle);
|
float outerY = OuterRadius * std::sin(i * Angle);
|
||||||
|
|
||||||
vertices->at(index++) = getMarkerPosition(innerX, innerY, MarkerShaftWidth / 2, axis);
|
vertices->at(index++) = getMarkerPosition(innerX, innerY, MarkerShaftWidth / 2, axis) + offset;
|
||||||
vertices->at(index++) = getMarkerPosition(innerX, innerY, -MarkerShaftWidth / 2, axis);
|
vertices->at(index++) = getMarkerPosition(innerX, innerY, -MarkerShaftWidth / 2, axis) + offset;
|
||||||
vertices->at(index++) = getMarkerPosition(outerX, outerY, MarkerShaftWidth / 2, axis);
|
vertices->at(index++) = getMarkerPosition(outerX, outerY, MarkerShaftWidth / 2, axis) + offset;
|
||||||
vertices->at(index++) = getMarkerPosition(outerX, outerY, -MarkerShaftWidth / 2, axis);
|
vertices->at(index++) = getMarkerPosition(outerX, outerY, -MarkerShaftWidth / 2, axis) + offset;
|
||||||
}
|
}
|
||||||
|
|
||||||
colors->at(0) = osg::Vec4f (axis==0 ? 1.0f : 0.2f, axis==1 ? 1.0f : 0.2f, axis==2 ? 1.0f : 0.2f, 1.0f);
|
colors->at(0) = osg::Vec4f (
|
||||||
|
axis==0 ? 1.0f : 0.2f,
|
||||||
|
axis==1 ? 1.0f : 0.2f,
|
||||||
|
axis==2 ? 1.0f : 0.2f,
|
||||||
|
mMarkerTransparency);
|
||||||
|
|
||||||
for (size_t i = 0; i < SegmentCount; ++i)
|
for (size_t i = 0; i < SegmentCount; ++i)
|
||||||
{
|
{
|
||||||
|
@ -374,7 +383,7 @@ osg::ref_ptr<osg::Node> CSVRender::Object::makeRotateMarker (int axis)
|
||||||
geometry->setColorArray(colors, osg::Array::BIND_OVERALL);
|
geometry->setColorArray(colors, osg::Array::BIND_OVERALL);
|
||||||
geometry->addPrimitiveSet(primitives);
|
geometry->addPrimitiveSet(primitives);
|
||||||
|
|
||||||
geometry->getOrCreateStateSet()->setMode (GL_LIGHTING, osg::StateAttribute::OFF);
|
setupCommonMarkerState(geometry);
|
||||||
|
|
||||||
osg::ref_ptr<osg::Geode> geode = new osg::Geode();
|
osg::ref_ptr<osg::Geode> geode = new osg::Geode();
|
||||||
geode->addDrawable (geometry);
|
geode->addDrawable (geometry);
|
||||||
|
@ -382,6 +391,15 @@ osg::ref_ptr<osg::Node> CSVRender::Object::makeRotateMarker (int axis)
|
||||||
return geode;
|
return geode;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void CSVRender::Object::setupCommonMarkerState(osg::ref_ptr<osg::Geometry> geometry)
|
||||||
|
{
|
||||||
|
osg::ref_ptr<osg::StateSet> state = geometry->getOrCreateStateSet();
|
||||||
|
state->setMode(GL_LIGHTING, osg::StateAttribute::OFF);
|
||||||
|
state->setMode(GL_BLEND, osg::StateAttribute::ON);
|
||||||
|
|
||||||
|
state->setRenderingHint(osg::StateSet::TRANSPARENT_BIN);
|
||||||
|
}
|
||||||
|
|
||||||
osg::Vec3f CSVRender::Object::getMarkerPosition (float x, float y, float z, int axis)
|
osg::Vec3f CSVRender::Object::getMarkerPosition (float x, float y, float z, int axis)
|
||||||
{
|
{
|
||||||
switch (axis)
|
switch (axis)
|
||||||
|
@ -399,7 +417,7 @@ osg::Vec3f CSVRender::Object::getMarkerPosition (float x, float y, float z, int
|
||||||
CSVRender::Object::Object (CSMWorld::Data& data, osg::Group* parentNode,
|
CSVRender::Object::Object (CSMWorld::Data& data, osg::Group* parentNode,
|
||||||
const std::string& id, bool referenceable, bool forceBaseToZero)
|
const std::string& id, bool referenceable, bool forceBaseToZero)
|
||||||
: mData (data), mBaseNode(0), mSelected(false), mParentNode(parentNode), mResourceSystem(data.getResourceSystem().get()), mForceBaseToZero (forceBaseToZero),
|
: mData (data), mBaseNode(0), mSelected(false), mParentNode(parentNode), mResourceSystem(data.getResourceSystem().get()), mForceBaseToZero (forceBaseToZero),
|
||||||
mScaleOverride (1), mOverrideFlags (0), mSubMode (-1)
|
mScaleOverride (1), mOverrideFlags (0), mSubMode (-1), mMarkerTransparency(0.5f)
|
||||||
{
|
{
|
||||||
mRootNode = new osg::PositionAttitudeTransform;
|
mRootNode = new osg::PositionAttitudeTransform;
|
||||||
|
|
||||||
|
@ -453,6 +471,7 @@ void CSVRender::Object::setSelected(bool selected)
|
||||||
else
|
else
|
||||||
mRootNode->addChild(mBaseNode);
|
mRootNode->addChild(mBaseNode);
|
||||||
|
|
||||||
|
mMarkerTransparency = CSMPrefs::get()["3D Scene Input"]["object-marker-alpha"].toDouble();
|
||||||
updateMarker();
|
updateMarker();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -629,6 +648,12 @@ void CSVRender::Object::setScale (float scale)
|
||||||
adjustTransform();
|
adjustTransform();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void CSVRender::Object::setMarkerTransparency(float value)
|
||||||
|
{
|
||||||
|
mMarkerTransparency = value;
|
||||||
|
updateMarker();
|
||||||
|
}
|
||||||
|
|
||||||
void CSVRender::Object::apply (CSMWorld::CommandMacro& commands)
|
void CSVRender::Object::apply (CSMWorld::CommandMacro& commands)
|
||||||
{
|
{
|
||||||
const CSMWorld::RefCollection& collection = mData.getReferences();
|
const CSMWorld::RefCollection& collection = mData.getReferences();
|
||||||
|
|
|
@ -4,6 +4,7 @@
|
||||||
#include <string>
|
#include <string>
|
||||||
|
|
||||||
#include <osg/ref_ptr>
|
#include <osg/ref_ptr>
|
||||||
|
#include <osg/Geometry>
|
||||||
#include <osg/Referenced>
|
#include <osg/Referenced>
|
||||||
|
|
||||||
#include <components/esm/defs.hpp>
|
#include <components/esm/defs.hpp>
|
||||||
|
@ -96,6 +97,7 @@ namespace CSVRender
|
||||||
int mOverrideFlags;
|
int mOverrideFlags;
|
||||||
osg::ref_ptr<osg::Node> mMarker[3];
|
osg::ref_ptr<osg::Node> mMarker[3];
|
||||||
int mSubMode;
|
int mSubMode;
|
||||||
|
float mMarkerTransparency;
|
||||||
|
|
||||||
/// Not implemented
|
/// Not implemented
|
||||||
Object (const Object&);
|
Object (const Object&);
|
||||||
|
@ -121,6 +123,9 @@ namespace CSVRender
|
||||||
osg::ref_ptr<osg::Node> makeMoveOrScaleMarker (int axis);
|
osg::ref_ptr<osg::Node> makeMoveOrScaleMarker (int axis);
|
||||||
osg::ref_ptr<osg::Node> makeRotateMarker (int axis);
|
osg::ref_ptr<osg::Node> makeRotateMarker (int axis);
|
||||||
|
|
||||||
|
/// Sets up a stateset with properties common to all marker types.
|
||||||
|
void setupCommonMarkerState(osg::ref_ptr<osg::Geometry> geometry);
|
||||||
|
|
||||||
osg::Vec3f getMarkerPosition (float x, float y, float z, int axis);
|
osg::Vec3f getMarkerPosition (float x, float y, float z, int axis);
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
@ -179,6 +184,8 @@ namespace CSVRender
|
||||||
/// Set override scale
|
/// Set override scale
|
||||||
void setScale (float scale);
|
void setScale (float scale);
|
||||||
|
|
||||||
|
void setMarkerTransparency(float value);
|
||||||
|
|
||||||
/// Apply override changes via command and end edit mode
|
/// Apply override changes via command and end edit mode
|
||||||
void apply (CSMWorld::CommandMacro& commands);
|
void apply (CSMWorld::CommandMacro& commands);
|
||||||
|
|
||||||
|
|
|
@ -51,6 +51,7 @@ CSVRender::WorldspaceWidget::WorldspaceWidget (CSMDoc::Document& document, QWidg
|
||||||
, mToolTipPos (-1, -1)
|
, mToolTipPos (-1, -1)
|
||||||
, mShowToolTips(false)
|
, mShowToolTips(false)
|
||||||
, mToolTipDelay(0)
|
, mToolTipDelay(0)
|
||||||
|
, mInConstructor(true)
|
||||||
{
|
{
|
||||||
setAcceptDrops(true);
|
setAcceptDrops(true);
|
||||||
|
|
||||||
|
@ -114,6 +115,8 @@ CSVRender::WorldspaceWidget::WorldspaceWidget (CSMDoc::Document& document, QWidg
|
||||||
|
|
||||||
CSMPrefs::Shortcut* abortShortcut = new CSMPrefs::Shortcut("scene-edit-abort", this);
|
CSMPrefs::Shortcut* abortShortcut = new CSMPrefs::Shortcut("scene-edit-abort", this);
|
||||||
connect(abortShortcut, SIGNAL(activated()), this, SLOT(abortDrag()));
|
connect(abortShortcut, SIGNAL(activated()), this, SLOT(abortDrag()));
|
||||||
|
|
||||||
|
mInConstructor = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
CSVRender::WorldspaceWidget::~WorldspaceWidget ()
|
CSVRender::WorldspaceWidget::~WorldspaceWidget ()
|
||||||
|
@ -128,6 +131,17 @@ void CSVRender::WorldspaceWidget::settingChanged (const CSMPrefs::Setting *setti
|
||||||
mDragWheelFactor = setting->toDouble();
|
mDragWheelFactor = setting->toDouble();
|
||||||
else if (*setting=="3D Scene Input/drag-shift-factor")
|
else if (*setting=="3D Scene Input/drag-shift-factor")
|
||||||
mDragShiftFactor = setting->toDouble();
|
mDragShiftFactor = setting->toDouble();
|
||||||
|
else if (*setting=="3D Scene Input/object-marker-alpha" && !mInConstructor)
|
||||||
|
{
|
||||||
|
float alpha = setting->toDouble();
|
||||||
|
// getSelection is virtual, thus this can not be called from the constructor
|
||||||
|
auto selection = getSelection(Mask_Reference);
|
||||||
|
for (osg::ref_ptr<TagBase> tag : selection)
|
||||||
|
{
|
||||||
|
if (auto objTag = dynamic_cast<ObjectTag*>(tag.get()))
|
||||||
|
objTag->mObject->setMarkerTransparency(alpha);
|
||||||
|
}
|
||||||
|
}
|
||||||
else if (*setting=="Tooltips/scene-delay")
|
else if (*setting=="Tooltips/scene-delay")
|
||||||
mToolTipDelay = setting->toInt();
|
mToolTipDelay = setting->toInt();
|
||||||
else if (*setting=="Tooltips/scene")
|
else if (*setting=="Tooltips/scene")
|
||||||
|
|
|
@ -65,6 +65,7 @@ namespace CSVRender
|
||||||
QPoint mToolTipPos;
|
QPoint mToolTipPos;
|
||||||
bool mShowToolTips;
|
bool mShowToolTips;
|
||||||
int mToolTipDelay;
|
int mToolTipDelay;
|
||||||
|
bool mInConstructor;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
|
||||||
|
|
|
@ -201,6 +201,9 @@ namespace MWBase
|
||||||
virtual void getObjectsInRange (const osg::Vec3f& position, float radius, std::vector<MWWorld::Ptr>& objects) = 0;
|
virtual void getObjectsInRange (const osg::Vec3f& position, float radius, std::vector<MWWorld::Ptr>& objects) = 0;
|
||||||
virtual void getActorsInRange(const osg::Vec3f &position, float radius, std::vector<MWWorld::Ptr> &objects) = 0;
|
virtual void getActorsInRange(const osg::Vec3f &position, float radius, std::vector<MWWorld::Ptr> &objects) = 0;
|
||||||
|
|
||||||
|
/// Check if there are actors in selected range
|
||||||
|
virtual bool isAnyActorInRange(const osg::Vec3f &position, float radius) = 0;
|
||||||
|
|
||||||
///Returns the list of actors which are siding with the given actor in fights
|
///Returns the list of actors which are siding with the given actor in fights
|
||||||
/**ie AiFollow or AiEscort is active and the target is the actor **/
|
/**ie AiFollow or AiEscort is active and the target is the actor **/
|
||||||
virtual std::list<MWWorld::Ptr> getActorsSidingWith(const MWWorld::Ptr& actor) = 0;
|
virtual std::list<MWWorld::Ptr> getActorsSidingWith(const MWWorld::Ptr& actor) = 0;
|
||||||
|
|
|
@ -8,7 +8,9 @@
|
||||||
#include "../mwbase/environment.hpp"
|
#include "../mwbase/environment.hpp"
|
||||||
#include "../mwbase/world.hpp"
|
#include "../mwbase/world.hpp"
|
||||||
#include "../mwbase/windowmanager.hpp"
|
#include "../mwbase/windowmanager.hpp"
|
||||||
|
|
||||||
#include "../mwworld/esmstore.hpp"
|
#include "../mwworld/esmstore.hpp"
|
||||||
|
#include "../mwworld/player.hpp"
|
||||||
|
|
||||||
#include "widgets.hpp"
|
#include "widgets.hpp"
|
||||||
|
|
||||||
|
@ -70,8 +72,14 @@ namespace MWGui
|
||||||
updateBirths();
|
updateBirths();
|
||||||
updateSpells();
|
updateSpells();
|
||||||
MWBase::Environment::get().getWindowManager()->setKeyFocusWidget(mBirthList);
|
MWBase::Environment::get().getWindowManager()->setKeyFocusWidget(mBirthList);
|
||||||
}
|
|
||||||
|
|
||||||
|
// Show the current birthsign by default
|
||||||
|
const std::string &signId =
|
||||||
|
MWBase::Environment::get().getWorld()->getPlayer().getBirthSign();
|
||||||
|
|
||||||
|
if (!signId.empty())
|
||||||
|
setBirthId(signId);
|
||||||
|
}
|
||||||
|
|
||||||
void BirthDialog::setBirthId(const std::string &birthId)
|
void BirthDialog::setBirthId(const std::string &birthId)
|
||||||
{
|
{
|
||||||
|
|
|
@ -7,6 +7,9 @@
|
||||||
#include "../mwbase/environment.hpp"
|
#include "../mwbase/environment.hpp"
|
||||||
#include "../mwbase/world.hpp"
|
#include "../mwbase/world.hpp"
|
||||||
#include "../mwbase/windowmanager.hpp"
|
#include "../mwbase/windowmanager.hpp"
|
||||||
|
|
||||||
|
#include "../mwmechanics/actorutil.hpp"
|
||||||
|
|
||||||
#include "../mwworld/esmstore.hpp"
|
#include "../mwworld/esmstore.hpp"
|
||||||
|
|
||||||
#include "tooltips.hpp"
|
#include "tooltips.hpp"
|
||||||
|
@ -131,8 +134,16 @@ namespace MWGui
|
||||||
updateClasses();
|
updateClasses();
|
||||||
updateStats();
|
updateStats();
|
||||||
MWBase::Environment::get().getWindowManager()->setKeyFocusWidget(mClassList);
|
MWBase::Environment::get().getWindowManager()->setKeyFocusWidget(mClassList);
|
||||||
}
|
|
||||||
|
|
||||||
|
// Show the current class by default
|
||||||
|
MWWorld::Ptr player = MWMechanics::getPlayer();
|
||||||
|
|
||||||
|
const std::string &classId =
|
||||||
|
player.get<ESM::NPC>()->mBase->mClass;
|
||||||
|
|
||||||
|
if (!classId.empty())
|
||||||
|
setClassId(classId);
|
||||||
|
}
|
||||||
|
|
||||||
void PickClassDialog::setClassId(const std::string &classId)
|
void PickClassDialog::setClassId(const std::string &classId)
|
||||||
{
|
{
|
||||||
|
|
|
@ -244,7 +244,10 @@ namespace MWInput
|
||||||
if (mControlSwitch["playercontrols"])
|
if (mControlSwitch["playercontrols"])
|
||||||
{
|
{
|
||||||
if (action == A_Use)
|
if (action == A_Use)
|
||||||
mPlayer->setAttackingOrSpell(currentValue != 0);
|
{
|
||||||
|
MWMechanics::DrawState_ state = MWBase::Environment::get().getWorld()->getPlayer().getDrawState();
|
||||||
|
mPlayer->setAttackingOrSpell(currentValue != 0 && state != MWMechanics::DrawState_Nothing);
|
||||||
|
}
|
||||||
else if (action == A_Jump)
|
else if (action == A_Jump)
|
||||||
mAttemptJump = (currentValue == 1.0 && previousValue == 0.0);
|
mAttemptJump = (currentValue == 1.0 && previousValue == 0.0);
|
||||||
}
|
}
|
||||||
|
|
|
@ -1847,6 +1847,17 @@ namespace MWMechanics
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool Actors::isAnyObjectInRange(const osg::Vec3f& position, float radius)
|
||||||
|
{
|
||||||
|
for (PtrActorMap::iterator iter = mActors.begin(); iter != mActors.end(); ++iter)
|
||||||
|
{
|
||||||
|
if ((iter->first.getRefData().getPosition().asVec3() - position).length2() <= radius*radius)
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
std::list<MWWorld::Ptr> Actors::getActorsSidingWith(const MWWorld::Ptr& actor)
|
std::list<MWWorld::Ptr> Actors::getActorsSidingWith(const MWWorld::Ptr& actor)
|
||||||
{
|
{
|
||||||
std::list<MWWorld::Ptr> list;
|
std::list<MWWorld::Ptr> list;
|
||||||
|
|
|
@ -134,6 +134,8 @@ namespace MWMechanics
|
||||||
|
|
||||||
void getObjectsInRange(const osg::Vec3f& position, float radius, std::vector<MWWorld::Ptr>& out);
|
void getObjectsInRange(const osg::Vec3f& position, float radius, std::vector<MWWorld::Ptr>& out);
|
||||||
|
|
||||||
|
bool isAnyObjectInRange(const osg::Vec3f& position, float radius);
|
||||||
|
|
||||||
void cleanupSummonedCreature (CreatureStats& casterStats, int creatureActorId);
|
void cleanupSummonedCreature (CreatureStats& casterStats, int creatureActorId);
|
||||||
|
|
||||||
///Returns the list of actors which are siding with the given actor in fights
|
///Returns the list of actors which are siding with the given actor in fights
|
||||||
|
|
|
@ -26,6 +26,7 @@
|
||||||
|
|
||||||
#include "../mwrender/animation.hpp"
|
#include "../mwrender/animation.hpp"
|
||||||
|
|
||||||
|
#include "pathgrid.hpp"
|
||||||
#include "creaturestats.hpp"
|
#include "creaturestats.hpp"
|
||||||
#include "steering.hpp"
|
#include "steering.hpp"
|
||||||
#include "movement.hpp"
|
#include "movement.hpp"
|
||||||
|
@ -440,7 +441,7 @@ namespace MWMechanics
|
||||||
int closestPointIndex = PathFinder::GetClosestPoint(pathgrid, localPos);
|
int closestPointIndex = PathFinder::GetClosestPoint(pathgrid, localPos);
|
||||||
for (int i = 0; i < static_cast<int>(pathgrid->mPoints.size()); i++)
|
for (int i = 0; i < static_cast<int>(pathgrid->mPoints.size()); i++)
|
||||||
{
|
{
|
||||||
if (i != closestPointIndex && storage.mCell->isPointConnected(closestPointIndex, i))
|
if (i != closestPointIndex && getPathGridGraph(storage.mCell).isPointConnected(closestPointIndex, i))
|
||||||
{
|
{
|
||||||
points.push_back(pathgrid->mPoints[static_cast<size_t>(i)]);
|
points.push_back(pathgrid->mPoints[static_cast<size_t>(i)]);
|
||||||
}
|
}
|
||||||
|
|
|
@ -14,6 +14,7 @@
|
||||||
#include "../mwworld/cellstore.hpp"
|
#include "../mwworld/cellstore.hpp"
|
||||||
#include "../mwworld/inventorystore.hpp"
|
#include "../mwworld/inventorystore.hpp"
|
||||||
|
|
||||||
|
#include "pathgrid.hpp"
|
||||||
#include "creaturestats.hpp"
|
#include "creaturestats.hpp"
|
||||||
#include "movement.hpp"
|
#include "movement.hpp"
|
||||||
#include "steering.hpp"
|
#include "steering.hpp"
|
||||||
|
@ -100,14 +101,23 @@ bool MWMechanics::AiPackage::pathTo(const MWWorld::Ptr& actor, const ESM::Pathgr
|
||||||
{
|
{
|
||||||
bool wasShortcutting = mIsShortcutting;
|
bool wasShortcutting = mIsShortcutting;
|
||||||
bool destInLOS = false;
|
bool destInLOS = false;
|
||||||
if (getTypeId() != TypeIdWander) // prohibit shortcuts for AiWander
|
|
||||||
mIsShortcutting = shortcutPath(start, dest, actor, &destInLOS); // try to shortcut first
|
const MWWorld::Class& actorClass = actor.getClass();
|
||||||
|
MWBase::World* world = MWBase::Environment::get().getWorld();
|
||||||
|
|
||||||
|
// check if actor can move along z-axis
|
||||||
|
bool actorCanMoveByZ = (actorClass.canSwim(actor) && MWBase::Environment::get().getWorld()->isSwimming(actor))
|
||||||
|
|| world->isFlying(actor);
|
||||||
|
|
||||||
|
// Prohibit shortcuts for AiWander, if the actor can not move in 3 dimensions.
|
||||||
|
if (actorCanMoveByZ || getTypeId() != TypeIdWander)
|
||||||
|
mIsShortcutting = shortcutPath(start, dest, actor, &destInLOS, actorCanMoveByZ); // try to shortcut first
|
||||||
|
|
||||||
if (!mIsShortcutting)
|
if (!mIsShortcutting)
|
||||||
{
|
{
|
||||||
if (wasShortcutting || doesPathNeedRecalc(dest, actor.getCell())) // if need to rebuild path
|
if (wasShortcutting || doesPathNeedRecalc(dest, actor.getCell())) // if need to rebuild path
|
||||||
{
|
{
|
||||||
mPathFinder.buildSyncedPath(start, dest, actor.getCell());
|
mPathFinder.buildSyncedPath(start, dest, actor.getCell(), getPathGridGraph(actor.getCell()));
|
||||||
mRotateOnTheRunChecks = 3;
|
mRotateOnTheRunChecks = 3;
|
||||||
|
|
||||||
// give priority to go directly on target if there is minimal opportunity
|
// give priority to go directly on target if there is minimal opportunity
|
||||||
|
@ -220,20 +230,23 @@ void MWMechanics::AiPackage::evadeObstacles(const MWWorld::Ptr& actor, float dur
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
bool MWMechanics::AiPackage::shortcutPath(const ESM::Pathgrid::Point& startPoint, const ESM::Pathgrid::Point& endPoint, const MWWorld::Ptr& actor, bool *destInLOS)
|
const MWMechanics::PathgridGraph& MWMechanics::AiPackage::getPathGridGraph(const MWWorld::CellStore *cell)
|
||||||
{
|
{
|
||||||
const MWWorld::Class& actorClass = actor.getClass();
|
const ESM::CellId& id = cell->getCell()->getCellId();
|
||||||
MWBase::World* world = MWBase::Environment::get().getWorld();
|
// static cache is OK for now, pathgrids can never change during runtime
|
||||||
|
typedef std::map<ESM::CellId, std::unique_ptr<MWMechanics::PathgridGraph> > CacheMap;
|
||||||
|
static CacheMap cache;
|
||||||
|
CacheMap::iterator found = cache.find(id);
|
||||||
|
if (found == cache.end())
|
||||||
|
{
|
||||||
|
cache.insert(std::make_pair(id, std::unique_ptr<MWMechanics::PathgridGraph>(new MWMechanics::PathgridGraph(cell))));
|
||||||
|
}
|
||||||
|
return *cache[id].get();
|
||||||
|
}
|
||||||
|
|
||||||
// check if actor can move along z-axis
|
bool MWMechanics::AiPackage::shortcutPath(const ESM::Pathgrid::Point& startPoint, const ESM::Pathgrid::Point& endPoint, const MWWorld::Ptr& actor, bool *destInLOS, bool isPathClear)
|
||||||
bool actorCanMoveByZ = (actorClass.canSwim(actor) && MWBase::Environment::get().getWorld()->isSwimming(actor))
|
{
|
||||||
|| world->isFlying(actor);
|
if (!mShortcutProhibited || (PathFinder::MakeOsgVec3(mShortcutFailPos) - PathFinder::MakeOsgVec3(startPoint)).length() >= PATHFIND_SHORTCUT_RETRY_DIST)
|
||||||
|
|
||||||
// don't use pathgrid when actor can move in 3 dimensions
|
|
||||||
bool isPathClear = actorCanMoveByZ;
|
|
||||||
|
|
||||||
if (!isPathClear
|
|
||||||
&& (!mShortcutProhibited || (PathFinder::MakeOsgVec3(mShortcutFailPos) - PathFinder::MakeOsgVec3(startPoint)).length() >= PATHFIND_SHORTCUT_RETRY_DIST))
|
|
||||||
{
|
{
|
||||||
// check if target is clearly visible
|
// check if target is clearly visible
|
||||||
isPathClear = !MWBase::Environment::get().getWorld()->castRay(
|
isPathClear = !MWBase::Environment::get().getWorld()->castRay(
|
||||||
|
|
|
@ -27,6 +27,7 @@ namespace MWMechanics
|
||||||
const float AI_REACTION_TIME = 0.25f;
|
const float AI_REACTION_TIME = 0.25f;
|
||||||
|
|
||||||
class CharacterController;
|
class CharacterController;
|
||||||
|
class PathgridGraph;
|
||||||
|
|
||||||
/// \brief Base class for AI packages
|
/// \brief Base class for AI packages
|
||||||
class AiPackage
|
class AiPackage
|
||||||
|
@ -110,7 +111,7 @@ namespace MWMechanics
|
||||||
/// If a shortcut is possible then path will be cleared and filled with the destination point.
|
/// If a shortcut is possible then path will be cleared and filled with the destination point.
|
||||||
/// \param destInLOS If not NULL function will return ray cast check result
|
/// \param destInLOS If not NULL function will return ray cast check result
|
||||||
/// \return If can shortcut the path
|
/// \return If can shortcut the path
|
||||||
bool shortcutPath(const ESM::Pathgrid::Point& startPoint, const ESM::Pathgrid::Point& endPoint, const MWWorld::Ptr& actor, bool *destInLOS);
|
bool shortcutPath(const ESM::Pathgrid::Point& startPoint, const ESM::Pathgrid::Point& endPoint, const MWWorld::Ptr& actor, bool *destInLOS, bool isPathClear);
|
||||||
|
|
||||||
/// Check if the way to the destination is clear, taking into account actor speed
|
/// Check if the way to the destination is clear, taking into account actor speed
|
||||||
bool checkWayIsClearForActor(const ESM::Pathgrid::Point& startPoint, const ESM::Pathgrid::Point& endPoint, const MWWorld::Ptr& actor);
|
bool checkWayIsClearForActor(const ESM::Pathgrid::Point& startPoint, const ESM::Pathgrid::Point& endPoint, const MWWorld::Ptr& actor);
|
||||||
|
@ -119,6 +120,8 @@ namespace MWMechanics
|
||||||
|
|
||||||
void evadeObstacles(const MWWorld::Ptr& actor, float duration, const ESM::Position& pos);
|
void evadeObstacles(const MWWorld::Ptr& actor, float duration, const ESM::Position& pos);
|
||||||
|
|
||||||
|
const PathgridGraph& getPathGridGraph(const MWWorld::CellStore* cell);
|
||||||
|
|
||||||
// TODO: all this does not belong here, move into temporary storage
|
// TODO: all this does not belong here, move into temporary storage
|
||||||
PathFinder mPathFinder;
|
PathFinder mPathFinder;
|
||||||
ObstacleCheck mObstacleCheck;
|
ObstacleCheck mObstacleCheck;
|
||||||
|
|
|
@ -17,6 +17,7 @@
|
||||||
#include "../mwworld/esmstore.hpp"
|
#include "../mwworld/esmstore.hpp"
|
||||||
#include "../mwworld/cellstore.hpp"
|
#include "../mwworld/cellstore.hpp"
|
||||||
|
|
||||||
|
#include "pathgrid.hpp"
|
||||||
#include "creaturestats.hpp"
|
#include "creaturestats.hpp"
|
||||||
#include "steering.hpp"
|
#include "steering.hpp"
|
||||||
#include "movement.hpp"
|
#include "movement.hpp"
|
||||||
|
@ -217,7 +218,7 @@ namespace MWMechanics
|
||||||
ESM::Pathgrid::Point dest(PathFinder::MakePathgridPoint(mDestination));
|
ESM::Pathgrid::Point dest(PathFinder::MakePathgridPoint(mDestination));
|
||||||
ESM::Pathgrid::Point start(PathFinder::MakePathgridPoint(pos));
|
ESM::Pathgrid::Point start(PathFinder::MakePathgridPoint(pos));
|
||||||
|
|
||||||
mPathFinder.buildSyncedPath(start, dest, actor.getCell());
|
mPathFinder.buildSyncedPath(start, dest, actor.getCell(), getPathGridGraph(actor.getCell()));
|
||||||
|
|
||||||
if (mPathFinder.isPathConstructed())
|
if (mPathFinder.isPathConstructed())
|
||||||
storage.setState(Wander_Walking);
|
storage.setState(Wander_Walking);
|
||||||
|
@ -264,9 +265,20 @@ namespace MWMechanics
|
||||||
getAllowedNodes(actor, currentCell->getCell(), storage);
|
getAllowedNodes(actor, currentCell->getCell(), storage);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool actorCanMoveByZ = (actor.getClass().canSwim(actor) && MWBase::Environment::get().getWorld()->isSwimming(actor))
|
||||||
|
|| MWBase::Environment::get().getWorld()->isFlying(actor);
|
||||||
|
|
||||||
|
if(actorCanMoveByZ && mDistance > 0) {
|
||||||
|
// Typically want to idle for a short time before the next wander
|
||||||
|
if (Misc::Rng::rollDice(100) >= 92 && storage.mState != Wander_Walking) {
|
||||||
|
wanderNearStart(actor, storage, mDistance);
|
||||||
|
}
|
||||||
|
|
||||||
|
storage.mCanWanderAlongPathGrid = false;
|
||||||
|
}
|
||||||
// If the package has a wander distance but no pathgrid is available,
|
// If the package has a wander distance but no pathgrid is available,
|
||||||
// randomly idle or wander near spawn point
|
// randomly idle or wander near spawn point
|
||||||
if(storage.mAllowedNodes.empty() && mDistance > 0 && !storage.mIsWanderingManually) {
|
else if(storage.mAllowedNodes.empty() && mDistance > 0 && !storage.mIsWanderingManually) {
|
||||||
// Typically want to idle for a short time before the next wander
|
// Typically want to idle for a short time before the next wander
|
||||||
if (Misc::Rng::rollDice(100) >= 96) {
|
if (Misc::Rng::rollDice(100) >= 96) {
|
||||||
wanderNearStart(actor, storage, mDistance);
|
wanderNearStart(actor, storage, mDistance);
|
||||||
|
@ -349,7 +361,7 @@ namespace MWMechanics
|
||||||
ESM::Pathgrid::Point start(PathFinder::MakePathgridPoint(pos));
|
ESM::Pathgrid::Point start(PathFinder::MakePathgridPoint(pos));
|
||||||
|
|
||||||
// don't take shortcuts for wandering
|
// don't take shortcuts for wandering
|
||||||
mPathFinder.buildSyncedPath(start, dest, actor.getCell());
|
mPathFinder.buildSyncedPath(start, dest, actor.getCell(), getPathGridGraph(actor.getCell()));
|
||||||
|
|
||||||
if (mPathFinder.isPathConstructed())
|
if (mPathFinder.isPathConstructed())
|
||||||
{
|
{
|
||||||
|
@ -372,7 +384,7 @@ namespace MWMechanics
|
||||||
do {
|
do {
|
||||||
// Determine a random location within radius of original position
|
// Determine a random location within radius of original position
|
||||||
const float pi = 3.14159265359f;
|
const float pi = 3.14159265359f;
|
||||||
const float wanderRadius = Misc::Rng::rollClosedProbability() * wanderDistance;
|
const float wanderRadius = (0.2f + Misc::Rng::rollClosedProbability() * 0.8f) * wanderDistance;
|
||||||
const float randomDirection = Misc::Rng::rollClosedProbability() * 2.0f * pi;
|
const float randomDirection = Misc::Rng::rollClosedProbability() * 2.0f * pi;
|
||||||
const float destinationX = mInitialActorPosition.x() + wanderRadius * std::cos(randomDirection);
|
const float destinationX = mInitialActorPosition.x() + wanderRadius * std::cos(randomDirection);
|
||||||
const float destinationY = mInitialActorPosition.y() + wanderRadius * std::sin(randomDirection);
|
const float destinationY = mInitialActorPosition.y() + wanderRadius * std::sin(randomDirection);
|
||||||
|
@ -383,7 +395,7 @@ namespace MWMechanics
|
||||||
// Check if land creature will walk onto water or if water creature will swim onto land
|
// Check if land creature will walk onto water or if water creature will swim onto land
|
||||||
if ((!isWaterCreature && !destinationIsAtWater(actor, mDestination)) ||
|
if ((!isWaterCreature && !destinationIsAtWater(actor, mDestination)) ||
|
||||||
(isWaterCreature && !destinationThroughGround(currentPositionVec3f, mDestination))) {
|
(isWaterCreature && !destinationThroughGround(currentPositionVec3f, mDestination))) {
|
||||||
mPathFinder.buildSyncedPath(currentPosition, destinationPosition, actor.getCell());
|
mPathFinder.buildSyncedPath(currentPosition, destinationPosition, actor.getCell(), getPathGridGraph(actor.getCell()));
|
||||||
mPathFinder.addPointToPath(destinationPosition);
|
mPathFinder.addPointToPath(destinationPosition);
|
||||||
|
|
||||||
if (mPathFinder.isPathConstructed())
|
if (mPathFinder.isPathConstructed())
|
||||||
|
@ -660,13 +672,14 @@ namespace MWMechanics
|
||||||
{
|
{
|
||||||
unsigned int randNode = Misc::Rng::rollDice(storage.mAllowedNodes.size());
|
unsigned int randNode = Misc::Rng::rollDice(storage.mAllowedNodes.size());
|
||||||
ESM::Pathgrid::Point dest(storage.mAllowedNodes[randNode]);
|
ESM::Pathgrid::Point dest(storage.mAllowedNodes[randNode]);
|
||||||
|
|
||||||
ToWorldCoordinates(dest, storage.mCell->getCell());
|
ToWorldCoordinates(dest, storage.mCell->getCell());
|
||||||
|
|
||||||
// actor position is already in world coordinates
|
// actor position is already in world coordinates
|
||||||
ESM::Pathgrid::Point start(PathFinder::MakePathgridPoint(actorPos));
|
ESM::Pathgrid::Point start(PathFinder::MakePathgridPoint(actorPos));
|
||||||
|
|
||||||
// don't take shortcuts for wandering
|
// don't take shortcuts for wandering
|
||||||
mPathFinder.buildSyncedPath(start, dest, actor.getCell());
|
mPathFinder.buildSyncedPath(start, dest, actor.getCell(), getPathGridGraph(actor.getCell()));
|
||||||
|
|
||||||
if (mPathFinder.isPathConstructed())
|
if (mPathFinder.isPathConstructed())
|
||||||
{
|
{
|
||||||
|
@ -799,20 +812,80 @@ namespace MWMechanics
|
||||||
|
|
||||||
int index = Misc::Rng::rollDice(storage.mAllowedNodes.size());
|
int index = Misc::Rng::rollDice(storage.mAllowedNodes.size());
|
||||||
ESM::Pathgrid::Point dest = storage.mAllowedNodes[index];
|
ESM::Pathgrid::Point dest = storage.mAllowedNodes[index];
|
||||||
state.moveIn(new AiWanderStorage());
|
ESM::Pathgrid::Point worldDest = dest;
|
||||||
|
ToWorldCoordinates(worldDest, actor.getCell()->getCell());
|
||||||
|
|
||||||
|
bool isPathGridOccupied = MWBase::Environment::get().getMechanicsManager()->isAnyActorInRange(PathFinder::MakeOsgVec3(worldDest), 60);
|
||||||
|
|
||||||
|
// add offset only if the selected pathgrid is occupied by another actor
|
||||||
|
if (isPathGridOccupied)
|
||||||
|
{
|
||||||
|
ESM::Pathgrid::PointList points;
|
||||||
|
getNeighbouringNodes(dest, actor.getCell(), points);
|
||||||
|
|
||||||
|
// there are no neighbouring nodes, nowhere to move
|
||||||
|
if (points.empty())
|
||||||
|
return;
|
||||||
|
|
||||||
|
int initialSize = points.size();
|
||||||
|
bool isOccupied = false;
|
||||||
|
// AI will try to move the NPC towards every neighboring node until suitable place will be found
|
||||||
|
for (int i = 0; i < initialSize; i++)
|
||||||
|
{
|
||||||
|
int randomIndex = Misc::Rng::rollDice(points.size());
|
||||||
|
ESM::Pathgrid::Point connDest = points[randomIndex];
|
||||||
|
|
||||||
|
// add an offset towards random neighboring node
|
||||||
|
osg::Vec3f dir = PathFinder::MakeOsgVec3(connDest) - PathFinder::MakeOsgVec3(dest);
|
||||||
|
float length = dir.length();
|
||||||
|
dir.normalize();
|
||||||
|
|
||||||
|
for (int j = 1; j <= 3; j++)
|
||||||
|
{
|
||||||
|
// move for 5-15% towards random neighboring node
|
||||||
|
dest = PathFinder::MakePathgridPoint(PathFinder::MakeOsgVec3(dest) + dir * (j * 5 * length / 100.f));
|
||||||
|
worldDest = dest;
|
||||||
|
ToWorldCoordinates(worldDest, actor.getCell()->getCell());
|
||||||
|
|
||||||
|
isOccupied = MWBase::Environment::get().getMechanicsManager()->isAnyActorInRange(PathFinder::MakeOsgVec3(worldDest), 60);
|
||||||
|
|
||||||
|
if (!isOccupied)
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!isOccupied)
|
||||||
|
break;
|
||||||
|
|
||||||
|
// Will try an another neighboring node
|
||||||
|
points.erase(points.begin()+randomIndex);
|
||||||
|
}
|
||||||
|
|
||||||
|
// there is no free space, nowhere to move
|
||||||
|
if (isOccupied)
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// place above to prevent moving inside objects, e.g. stairs, because a vector between pathgrids can be underground.
|
||||||
|
// Adding 20 in adjustPosition() is not enough.
|
||||||
|
dest.mZ += 60;
|
||||||
|
|
||||||
dest.mX += OffsetToPreventOvercrowding();
|
|
||||||
dest.mY += OffsetToPreventOvercrowding();
|
|
||||||
ToWorldCoordinates(dest, actor.getCell()->getCell());
|
ToWorldCoordinates(dest, actor.getCell()->getCell());
|
||||||
|
|
||||||
|
state.moveIn(new AiWanderStorage());
|
||||||
|
|
||||||
MWBase::Environment::get().getWorld()->moveObject(actor, static_cast<float>(dest.mX),
|
MWBase::Environment::get().getWorld()->moveObject(actor, static_cast<float>(dest.mX),
|
||||||
static_cast<float>(dest.mY), static_cast<float>(dest.mZ));
|
static_cast<float>(dest.mY), static_cast<float>(dest.mZ));
|
||||||
actor.getClass().adjustPosition(actor, false);
|
actor.getClass().adjustPosition(actor, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
int AiWander::OffsetToPreventOvercrowding()
|
void AiWander::getNeighbouringNodes(ESM::Pathgrid::Point dest, const MWWorld::CellStore* currentCell, ESM::Pathgrid::PointList& points)
|
||||||
{
|
{
|
||||||
return static_cast<int>(20 * (Misc::Rng::rollProbability() * 2.0f - 1.0f));
|
const ESM::Pathgrid *pathgrid =
|
||||||
|
MWBase::Environment::get().getWorld()->getStore().get<ESM::Pathgrid>().search(*currentCell->getCell());
|
||||||
|
|
||||||
|
int index = PathFinder::GetClosestPoint(pathgrid, PathFinder::MakeOsgVec3(dest));
|
||||||
|
|
||||||
|
getPathGridGraph(currentCell).getNeighbouringPoints(index, points);
|
||||||
}
|
}
|
||||||
|
|
||||||
void AiWander::getAllowedNodes(const MWWorld::Ptr& actor, const ESM::Cell* cell, AiWanderStorage& storage)
|
void AiWander::getAllowedNodes(const MWWorld::Ptr& actor, const ESM::Cell* cell, AiWanderStorage& storage)
|
||||||
|
@ -853,7 +926,7 @@ namespace MWMechanics
|
||||||
{
|
{
|
||||||
osg::Vec3f nodePos(PathFinder::MakeOsgVec3(pathgrid->mPoints[counter]));
|
osg::Vec3f nodePos(PathFinder::MakeOsgVec3(pathgrid->mPoints[counter]));
|
||||||
if((npcPos - nodePos).length2() <= mDistance * mDistance &&
|
if((npcPos - nodePos).length2() <= mDistance * mDistance &&
|
||||||
cellStore->isPointConnected(closestPointIndex, counter))
|
getPathGridGraph(cellStore).isPointConnected(closestPointIndex, counter))
|
||||||
{
|
{
|
||||||
storage.mAllowedNodes.push_back(pathgrid->mPoints[counter]);
|
storage.mAllowedNodes.push_back(pathgrid->mPoints[counter]);
|
||||||
pointIndex = counter;
|
pointIndex = counter;
|
||||||
|
|
|
@ -104,6 +104,8 @@ namespace MWMechanics
|
||||||
bool mHasDestination;
|
bool mHasDestination;
|
||||||
osg::Vec3f mDestination;
|
osg::Vec3f mDestination;
|
||||||
|
|
||||||
|
void getNeighbouringNodes(ESM::Pathgrid::Point dest, const MWWorld::CellStore* currentCell, ESM::Pathgrid::PointList& points);
|
||||||
|
|
||||||
void getAllowedNodes(const MWWorld::Ptr& actor, const ESM::Cell* cell, AiWanderStorage& storage);
|
void getAllowedNodes(const MWWorld::Ptr& actor, const ESM::Cell* cell, AiWanderStorage& storage);
|
||||||
|
|
||||||
void trimAllowedNodes(std::vector<ESM::Pathgrid::Point>& nodes, const PathFinder& pathfinder);
|
void trimAllowedNodes(std::vector<ESM::Pathgrid::Point>& nodes, const PathFinder& pathfinder);
|
||||||
|
|
|
@ -1338,7 +1338,16 @@ bool CharacterController::updateWeaponState()
|
||||||
bool animPlaying;
|
bool animPlaying;
|
||||||
if(mAttackingOrSpell)
|
if(mAttackingOrSpell)
|
||||||
{
|
{
|
||||||
|
MWWorld::Ptr player = getPlayer();
|
||||||
|
|
||||||
|
// We should reset player's idle animation in the first-person mode.
|
||||||
|
if (mPtr == player && MWBase::Environment::get().getWorld()->isFirstPerson())
|
||||||
mIdleState = CharState_None;
|
mIdleState = CharState_None;
|
||||||
|
|
||||||
|
// In other cases we should not break swim and sneak animations
|
||||||
|
if (mIdleState != CharState_IdleSneak && mIdleState != CharState_IdleSwim)
|
||||||
|
mIdleState = CharState_None;
|
||||||
|
|
||||||
if(mUpperBodyState == UpperCharState_WeapEquiped && (mHitState == CharState_None || mHitState == CharState_Block))
|
if(mUpperBodyState == UpperCharState_WeapEquiped && (mHitState == CharState_None || mHitState == CharState_Block))
|
||||||
{
|
{
|
||||||
MWBase::Environment::get().getWorld()->breakInvisibility(mPtr);
|
MWBase::Environment::get().getWorld()->breakInvisibility(mPtr);
|
||||||
|
@ -1348,7 +1357,7 @@ bool CharacterController::updateWeaponState()
|
||||||
// Unset casting flag, otherwise pressing the mouse button down would
|
// Unset casting flag, otherwise pressing the mouse button down would
|
||||||
// continue casting every frame if there is no animation
|
// continue casting every frame if there is no animation
|
||||||
mAttackingOrSpell = false;
|
mAttackingOrSpell = false;
|
||||||
if (mPtr == getPlayer())
|
if (mPtr == player)
|
||||||
{
|
{
|
||||||
MWBase::Environment::get().getWorld()->getPlayer().setAttackingOrSpell(false);
|
MWBase::Environment::get().getWorld()->getPlayer().setAttackingOrSpell(false);
|
||||||
}
|
}
|
||||||
|
@ -1358,7 +1367,7 @@ bool CharacterController::updateWeaponState()
|
||||||
// For the player, set the spell we want to cast
|
// For the player, set the spell we want to cast
|
||||||
// This has to be done at the start of the casting animation,
|
// This has to be done at the start of the casting animation,
|
||||||
// *not* when selecting a spell in the GUI (otherwise you could change the spell mid-animation)
|
// *not* when selecting a spell in the GUI (otherwise you could change the spell mid-animation)
|
||||||
if (mPtr == getPlayer())
|
if (mPtr == player)
|
||||||
{
|
{
|
||||||
std::string selectedSpell = MWBase::Environment::get().getWindowManager()->getSelectedSpell();
|
std::string selectedSpell = MWBase::Environment::get().getWindowManager()->getSelectedSpell();
|
||||||
stats.getSpells().setSelectedSpell(selectedSpell);
|
stats.getSpells().setSelectedSpell(selectedSpell);
|
||||||
|
|
|
@ -1635,6 +1635,11 @@ namespace MWMechanics
|
||||||
mActors.getObjectsInRange(position, radius, objects);
|
mActors.getObjectsInRange(position, radius, objects);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool MechanicsManager::isAnyActorInRange(const osg::Vec3f &position, float radius)
|
||||||
|
{
|
||||||
|
return mActors.isAnyObjectInRange(position, radius);
|
||||||
|
}
|
||||||
|
|
||||||
std::list<MWWorld::Ptr> MechanicsManager::getActorsSidingWith(const MWWorld::Ptr& actor)
|
std::list<MWWorld::Ptr> MechanicsManager::getActorsSidingWith(const MWWorld::Ptr& actor)
|
||||||
{
|
{
|
||||||
return mActors.getActorsSidingWith(actor);
|
return mActors.getActorsSidingWith(actor);
|
||||||
|
|
|
@ -168,6 +168,9 @@ namespace MWMechanics
|
||||||
virtual void getObjectsInRange (const osg::Vec3f& position, float radius, std::vector<MWWorld::Ptr>& objects);
|
virtual void getObjectsInRange (const osg::Vec3f& position, float radius, std::vector<MWWorld::Ptr>& objects);
|
||||||
virtual void getActorsInRange(const osg::Vec3f &position, float radius, std::vector<MWWorld::Ptr> &objects);
|
virtual void getActorsInRange(const osg::Vec3f &position, float radius, std::vector<MWWorld::Ptr> &objects);
|
||||||
|
|
||||||
|
/// Check if there are actors in selected range
|
||||||
|
virtual bool isAnyActorInRange(const osg::Vec3f &position, float radius);
|
||||||
|
|
||||||
virtual std::list<MWWorld::Ptr> getActorsSidingWith(const MWWorld::Ptr& actor);
|
virtual std::list<MWWorld::Ptr> getActorsSidingWith(const MWWorld::Ptr& actor);
|
||||||
virtual std::list<MWWorld::Ptr> getActorsFollowing(const MWWorld::Ptr& actor);
|
virtual std::list<MWWorld::Ptr> getActorsFollowing(const MWWorld::Ptr& actor);
|
||||||
virtual std::list<int> getActorsFollowingIndices(const MWWorld::Ptr& actor);
|
virtual std::list<int> getActorsFollowingIndices(const MWWorld::Ptr& actor);
|
||||||
|
|
|
@ -5,16 +5,16 @@
|
||||||
#include "../mwbase/world.hpp"
|
#include "../mwbase/world.hpp"
|
||||||
#include "../mwbase/environment.hpp"
|
#include "../mwbase/environment.hpp"
|
||||||
|
|
||||||
#include "../mwworld/esmstore.hpp"
|
|
||||||
#include "../mwworld/cellstore.hpp"
|
#include "../mwworld/cellstore.hpp"
|
||||||
|
|
||||||
|
#include "pathgrid.hpp"
|
||||||
#include "coordinateconverter.hpp"
|
#include "coordinateconverter.hpp"
|
||||||
|
|
||||||
namespace
|
namespace
|
||||||
{
|
{
|
||||||
// Chooses a reachable end pathgrid point. start is assumed reachable.
|
// Chooses a reachable end pathgrid point. start is assumed reachable.
|
||||||
std::pair<int, bool> getClosestReachablePoint(const ESM::Pathgrid* grid,
|
std::pair<int, bool> getClosestReachablePoint(const ESM::Pathgrid* grid,
|
||||||
const MWWorld::CellStore *cell,
|
const MWMechanics::PathgridGraph *graph,
|
||||||
const osg::Vec3f& pos, int start)
|
const osg::Vec3f& pos, int start)
|
||||||
{
|
{
|
||||||
assert(grid && !grid->mPoints.empty());
|
assert(grid && !grid->mPoints.empty());
|
||||||
|
@ -31,7 +31,7 @@ namespace
|
||||||
if (potentialDistBetween < closestDistanceReachable)
|
if (potentialDistBetween < closestDistanceReachable)
|
||||||
{
|
{
|
||||||
// found a closer one
|
// found a closer one
|
||||||
if (cell->isPointConnected(start, counter))
|
if (graph->isPointConnected(start, counter))
|
||||||
{
|
{
|
||||||
closestDistanceReachable = potentialDistBetween;
|
closestDistanceReachable = potentialDistBetween;
|
||||||
closestReachableIndex = counter;
|
closestReachableIndex = counter;
|
||||||
|
@ -45,7 +45,7 @@ namespace
|
||||||
}
|
}
|
||||||
|
|
||||||
// post-condition: start and endpoint must be connected
|
// post-condition: start and endpoint must be connected
|
||||||
assert(cell->isPointConnected(start, closestReachableIndex));
|
assert(graph->isPointConnected(start, closestReachableIndex));
|
||||||
|
|
||||||
// AiWander has logic that depends on whether a path was created, deleting
|
// AiWander has logic that depends on whether a path was created, deleting
|
||||||
// allowed nodes if not. Hence a path needs to be created even if the start
|
// allowed nodes if not. Hence a path needs to be created even if the start
|
||||||
|
@ -120,8 +120,8 @@ namespace MWMechanics
|
||||||
}
|
}
|
||||||
|
|
||||||
PathFinder::PathFinder()
|
PathFinder::PathFinder()
|
||||||
: mPathgrid(NULL),
|
: mPathgrid(NULL)
|
||||||
mCell(NULL)
|
, mCell(NULL)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -169,14 +169,15 @@ namespace MWMechanics
|
||||||
*/
|
*/
|
||||||
void PathFinder::buildPath(const ESM::Pathgrid::Point &startPoint,
|
void PathFinder::buildPath(const ESM::Pathgrid::Point &startPoint,
|
||||||
const ESM::Pathgrid::Point &endPoint,
|
const ESM::Pathgrid::Point &endPoint,
|
||||||
const MWWorld::CellStore* cell)
|
const MWWorld::CellStore* cell, const PathgridGraph& pathgridGraph)
|
||||||
{
|
{
|
||||||
mPath.clear();
|
mPath.clear();
|
||||||
|
|
||||||
|
// TODO: consider removing mCell / mPathgrid in favor of mPathgridGraph
|
||||||
if(mCell != cell || !mPathgrid)
|
if(mCell != cell || !mPathgrid)
|
||||||
{
|
{
|
||||||
mCell = cell;
|
mCell = cell;
|
||||||
mPathgrid = MWBase::Environment::get().getWorld()->getStore().get<ESM::Pathgrid>().search(*mCell->getCell());
|
mPathgrid = pathgridGraph.getPathgrid();
|
||||||
}
|
}
|
||||||
|
|
||||||
// Refer to AiWander reseach topic on openmw forums for some background.
|
// Refer to AiWander reseach topic on openmw forums for some background.
|
||||||
|
@ -200,7 +201,7 @@ namespace MWMechanics
|
||||||
int startNode = GetClosestPoint(mPathgrid, startPointInLocalCoords);
|
int startNode = GetClosestPoint(mPathgrid, startPointInLocalCoords);
|
||||||
|
|
||||||
osg::Vec3f endPointInLocalCoords(converter.toLocalVec3(endPoint));
|
osg::Vec3f endPointInLocalCoords(converter.toLocalVec3(endPoint));
|
||||||
std::pair<int, bool> endNode = getClosestReachablePoint(mPathgrid, cell,
|
std::pair<int, bool> endNode = getClosestReachablePoint(mPathgrid, &pathgridGraph,
|
||||||
endPointInLocalCoords,
|
endPointInLocalCoords,
|
||||||
startNode);
|
startNode);
|
||||||
|
|
||||||
|
@ -228,7 +229,7 @@ namespace MWMechanics
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
mPath = mCell->aStarSearch(startNode, endNode.first);
|
mPath = pathgridGraph.aStarSearch(startNode, endNode.first);
|
||||||
|
|
||||||
// convert supplied path to world coordinates
|
// convert supplied path to world coordinates
|
||||||
for (std::list<ESM::Pathgrid::Point>::iterator iter(mPath.begin()); iter != mPath.end(); ++iter)
|
for (std::list<ESM::Pathgrid::Point>::iterator iter(mPath.begin()); iter != mPath.end(); ++iter)
|
||||||
|
@ -301,18 +302,18 @@ namespace MWMechanics
|
||||||
// see header for the rationale
|
// see header for the rationale
|
||||||
void PathFinder::buildSyncedPath(const ESM::Pathgrid::Point &startPoint,
|
void PathFinder::buildSyncedPath(const ESM::Pathgrid::Point &startPoint,
|
||||||
const ESM::Pathgrid::Point &endPoint,
|
const ESM::Pathgrid::Point &endPoint,
|
||||||
const MWWorld::CellStore* cell)
|
const MWWorld::CellStore* cell, const MWMechanics::PathgridGraph& pathgridGraph)
|
||||||
{
|
{
|
||||||
if (mPath.size() < 2)
|
if (mPath.size() < 2)
|
||||||
{
|
{
|
||||||
// if path has one point, then it's the destination.
|
// if path has one point, then it's the destination.
|
||||||
// don't need to worry about bad path for this case
|
// don't need to worry about bad path for this case
|
||||||
buildPath(startPoint, endPoint, cell);
|
buildPath(startPoint, endPoint, cell, pathgridGraph);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
const ESM::Pathgrid::Point oldStart(*getPath().begin());
|
const ESM::Pathgrid::Point oldStart(*getPath().begin());
|
||||||
buildPath(startPoint, endPoint, cell);
|
buildPath(startPoint, endPoint, cell, pathgridGraph);
|
||||||
if (mPath.size() >= 2)
|
if (mPath.size() >= 2)
|
||||||
{
|
{
|
||||||
// if 2nd waypoint of new path == 1st waypoint of old,
|
// if 2nd waypoint of new path == 1st waypoint of old,
|
||||||
|
|
|
@ -14,6 +14,8 @@ namespace MWWorld
|
||||||
|
|
||||||
namespace MWMechanics
|
namespace MWMechanics
|
||||||
{
|
{
|
||||||
|
class PathgridGraph;
|
||||||
|
|
||||||
float distance(const ESM::Pathgrid::Point& point, float x, float y, float);
|
float distance(const ESM::Pathgrid::Point& point, float x, float y, float);
|
||||||
float distance(const ESM::Pathgrid::Point& a, const ESM::Pathgrid::Point& b);
|
float distance(const ESM::Pathgrid::Point& a, const ESM::Pathgrid::Point& b);
|
||||||
float getZAngleToDir(const osg::Vec3f& dir);
|
float getZAngleToDir(const osg::Vec3f& dir);
|
||||||
|
@ -54,7 +56,7 @@ namespace MWMechanics
|
||||||
void clearPath();
|
void clearPath();
|
||||||
|
|
||||||
void buildPath(const ESM::Pathgrid::Point &startPoint, const ESM::Pathgrid::Point &endPoint,
|
void buildPath(const ESM::Pathgrid::Point &startPoint, const ESM::Pathgrid::Point &endPoint,
|
||||||
const MWWorld::CellStore* cell);
|
const MWWorld::CellStore* cell, const PathgridGraph& pathgridGraph);
|
||||||
|
|
||||||
bool checkPathCompleted(float x, float y, float tolerance = PathTolerance);
|
bool checkPathCompleted(float x, float y, float tolerance = PathTolerance);
|
||||||
///< \Returns true if we are within \a tolerance units of the last path point.
|
///< \Returns true if we are within \a tolerance units of the last path point.
|
||||||
|
@ -89,7 +91,7 @@ namespace MWMechanics
|
||||||
Which results in NPC "running in a circle" back to the just passed waypoint.
|
Which results in NPC "running in a circle" back to the just passed waypoint.
|
||||||
*/
|
*/
|
||||||
void buildSyncedPath(const ESM::Pathgrid::Point &startPoint, const ESM::Pathgrid::Point &endPoint,
|
void buildSyncedPath(const ESM::Pathgrid::Point &startPoint, const ESM::Pathgrid::Point &endPoint,
|
||||||
const MWWorld::CellStore* cell);
|
const MWWorld::CellStore* cell, const PathgridGraph& pathgridGraph);
|
||||||
|
|
||||||
void addPointToPath(const ESM::Pathgrid::Point &point)
|
void addPointToPath(const ESM::Pathgrid::Point &point)
|
||||||
{
|
{
|
||||||
|
|
|
@ -49,7 +49,7 @@ namespace
|
||||||
|
|
||||||
namespace MWMechanics
|
namespace MWMechanics
|
||||||
{
|
{
|
||||||
PathgridGraph::PathgridGraph()
|
PathgridGraph::PathgridGraph(const MWWorld::CellStore *cell)
|
||||||
: mCell(NULL)
|
: mCell(NULL)
|
||||||
, mPathgrid(NULL)
|
, mPathgrid(NULL)
|
||||||
, mIsExterior(0)
|
, mIsExterior(0)
|
||||||
|
@ -58,6 +58,7 @@ namespace MWMechanics
|
||||||
, mSCCId(0)
|
, mSCCId(0)
|
||||||
, mSCCIndex(0)
|
, mSCCIndex(0)
|
||||||
{
|
{
|
||||||
|
load(cell);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -130,6 +131,11 @@ namespace MWMechanics
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const ESM::Pathgrid *PathgridGraph::getPathgrid() const
|
||||||
|
{
|
||||||
|
return mPathgrid;
|
||||||
|
}
|
||||||
|
|
||||||
// v is the pathgrid point index (some call them vertices)
|
// v is the pathgrid point index (some call them vertices)
|
||||||
void PathgridGraph::recursiveStrongConnect(int v)
|
void PathgridGraph::recursiveStrongConnect(int v)
|
||||||
{
|
{
|
||||||
|
@ -214,6 +220,16 @@ namespace MWMechanics
|
||||||
return (mGraph[start].componentId == mGraph[end].componentId);
|
return (mGraph[start].componentId == mGraph[end].componentId);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void PathgridGraph::getNeighbouringPoints(const int index, ESM::Pathgrid::PointList &nodes) const
|
||||||
|
{
|
||||||
|
for(int i = 0; i < static_cast<int> (mGraph[index].edges.size()); i++)
|
||||||
|
{
|
||||||
|
int neighbourIndex = mGraph[index].edges[i].index;
|
||||||
|
if (neighbourIndex != index)
|
||||||
|
nodes.push_back(mPathgrid->mPoints[neighbourIndex]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* NOTE: Based on buildPath2(), please check git history if interested
|
* NOTE: Based on buildPath2(), please check git history if interested
|
||||||
* Should consider using a 3rd party library version (e.g. boost)
|
* Should consider using a 3rd party library version (e.g. boost)
|
||||||
|
|
|
@ -20,14 +20,19 @@ namespace MWMechanics
|
||||||
class PathgridGraph
|
class PathgridGraph
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
PathgridGraph();
|
PathgridGraph(const MWWorld::CellStore* cell);
|
||||||
|
|
||||||
bool load(const MWWorld::CellStore *cell);
|
bool load(const MWWorld::CellStore *cell);
|
||||||
|
|
||||||
|
const ESM::Pathgrid* getPathgrid() const;
|
||||||
|
|
||||||
// returns true if end point is strongly connected (i.e. reachable
|
// returns true if end point is strongly connected (i.e. reachable
|
||||||
// from start point) both start and end are pathgrid point indexes
|
// from start point) both start and end are pathgrid point indexes
|
||||||
bool isPointConnected(const int start, const int end) const;
|
bool isPointConnected(const int start, const int end) const;
|
||||||
|
|
||||||
|
// get neighbouring nodes for index node and put them to "nodes" vector
|
||||||
|
void getNeighbouringPoints(const int index, ESM::Pathgrid::PointList &nodes) const;
|
||||||
|
|
||||||
// the input parameters are pathgrid point indexes
|
// the input parameters are pathgrid point indexes
|
||||||
// the output list is in local (internal cells) or world (external
|
// the output list is in local (internal cells) or world (external
|
||||||
// cells) coordinates
|
// cells) coordinates
|
||||||
|
|
|
@ -633,10 +633,6 @@ namespace MWWorld
|
||||||
loadRefs ();
|
loadRefs ();
|
||||||
|
|
||||||
mState = State_Loaded;
|
mState = State_Loaded;
|
||||||
|
|
||||||
// TODO: the pathgrid graph only needs to be loaded for active cells, so move this somewhere else.
|
|
||||||
// In a simple test, loading the graph for all cells in MW + expansions took 200 ms
|
|
||||||
mPathgridGraph.load(this);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1125,16 +1121,6 @@ namespace MWWorld
|
||||||
return !(left==right);
|
return !(left==right);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool CellStore::isPointConnected(const int start, const int end) const
|
|
||||||
{
|
|
||||||
return mPathgridGraph.isPointConnected(start, end);
|
|
||||||
}
|
|
||||||
|
|
||||||
std::list<ESM::Pathgrid::Point> CellStore::aStarSearch(const int start, const int end) const
|
|
||||||
{
|
|
||||||
return mPathgridGraph.aStarSearch(start, end);
|
|
||||||
}
|
|
||||||
|
|
||||||
void CellStore::setFog(ESM::FogState *fog)
|
void CellStore::setFog(ESM::FogState *fog)
|
||||||
{
|
{
|
||||||
mFogState.reset(fog);
|
mFogState.reset(fog);
|
||||||
|
|
|
@ -32,13 +32,12 @@
|
||||||
#include <components/esm/loadmisc.hpp>
|
#include <components/esm/loadmisc.hpp>
|
||||||
#include <components/esm/loadbody.hpp>
|
#include <components/esm/loadbody.hpp>
|
||||||
|
|
||||||
#include "../mwmechanics/pathgrid.hpp" // TODO: maybe belongs in mwworld
|
|
||||||
|
|
||||||
#include "timestamp.hpp"
|
#include "timestamp.hpp"
|
||||||
#include "ptr.hpp"
|
#include "ptr.hpp"
|
||||||
|
|
||||||
namespace ESM
|
namespace ESM
|
||||||
{
|
{
|
||||||
|
struct Cell;
|
||||||
struct CellState;
|
struct CellState;
|
||||||
struct FogState;
|
struct FogState;
|
||||||
struct CellId;
|
struct CellId;
|
||||||
|
@ -436,10 +435,6 @@ namespace MWWorld
|
||||||
void respawn ();
|
void respawn ();
|
||||||
///< Check mLastRespawn and respawn references if necessary. This is a no-op if the cell is not loaded.
|
///< Check mLastRespawn and respawn references if necessary. This is a no-op if the cell is not loaded.
|
||||||
|
|
||||||
bool isPointConnected(const int start, const int end) const;
|
|
||||||
|
|
||||||
std::list<ESM::Pathgrid::Point> aStarSearch(const int start, const int end) const;
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
||||||
/// Run through references and store IDs
|
/// Run through references and store IDs
|
||||||
|
@ -451,8 +446,6 @@ namespace MWWorld
|
||||||
///< Make case-adjustments to \a ref and insert it into the respective container.
|
///< Make case-adjustments to \a ref and insert it into the respective container.
|
||||||
///
|
///
|
||||||
/// Invalid \a ref objects are silently dropped.
|
/// Invalid \a ref objects are silently dropped.
|
||||||
|
|
||||||
MWMechanics::PathgridGraph mPathgridGraph;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
template<>
|
template<>
|
||||||
|
|
Loading…
Reference in a new issue