Show marked position on map. Implement Detect X magic effects.

This commit is contained in:
scrawl 2014-01-01 22:37:52 +01:00
parent 9245faf2aa
commit 5729672262
11 changed files with 362 additions and 145 deletions

View file

@ -130,7 +130,7 @@ namespace MWBase
virtual Ogre::Vector2 getNorthVector (MWWorld::CellStore* cell) = 0; virtual Ogre::Vector2 getNorthVector (MWWorld::CellStore* cell) = 0;
///< get north vector (OGRE coordinates) for given interior cell ///< get north vector (OGRE coordinates) for given interior cell
virtual std::vector<DoorMarker> getDoorMarkers (MWWorld::CellStore* cell) = 0; virtual void getDoorMarkers (MWWorld::CellStore* cell, std::vector<DoorMarker>& out) = 0;
///< get a list of teleport door markers for a given cell, to be displayed on the local map ///< get a list of teleport door markers for a given cell, to be displayed on the local map
virtual void getInteriorMapPosition (Ogre::Vector2 position, float& nX, float& nY, int &x, int& y) = 0; virtual void getInteriorMapPosition (Ogre::Vector2 position, float& nX, float& nY, int &x, int& y) = 0;
@ -438,6 +438,18 @@ namespace MWBase
/// @note id must be lower case /// @note id must be lower case
virtual void teleportToClosestMarker (const MWWorld::Ptr& ptr, virtual void teleportToClosestMarker (const MWWorld::Ptr& ptr,
const std::string& id, Ogre::Vector3 worldPos) = 0; const std::string& id, Ogre::Vector3 worldPos) = 0;
enum DetectionType
{
Detect_Enchantment,
Detect_Key,
Detect_Creature
};
/// List all references (filtered by \a type) detected by \a ptr. The range
/// is determined by the current magnitude of the "Detect X" magic effect belonging to \a type.
/// @note This also works for references in containers.
virtual void listDetectedReferences (const MWWorld::Ptr& ptr, std::vector<MWWorld::Ptr>& out,
DetectionType type) = 0;
}; };
} }

View file

@ -252,4 +252,11 @@ namespace MWClass
return ref->mBase->mData.mWeight; return ref->mBase->mData.mWeight;
} }
bool Miscellaneous::isKey(const MWWorld::Ptr &ptr) const
{
MWWorld::LiveCellRef<ESM::Miscellaneous> *ref =
ptr.get<ESM::Miscellaneous>();
return ref->mBase->mData.mIsKey;
}
} }

View file

@ -57,6 +57,8 @@ namespace MWClass
virtual float getWeight (const MWWorld::Ptr& ptr) const; virtual float getWeight (const MWWorld::Ptr& ptr) const;
virtual bool canSell (const MWWorld::Ptr& item, int npcServices) const; virtual bool canSell (const MWWorld::Ptr& item, int npcServices) const;
virtual bool isKey (const MWWorld::Ptr &ptr) const;
}; };
} }

View file

@ -103,27 +103,80 @@ namespace MWGui
void LocalMapBase::onMarkerFocused (MyGUI::Widget* w1, MyGUI::Widget* w2) void LocalMapBase::onMarkerFocused (MyGUI::Widget* w1, MyGUI::Widget* w2)
{ {
// Workaround to not make the marker visible if it's under fog of war
applyFogOfWar (); applyFogOfWar ();
} }
void LocalMapBase::onMarkerUnfocused (MyGUI::Widget* w1, MyGUI::Widget* w2) void LocalMapBase::onMarkerUnfocused (MyGUI::Widget* w1, MyGUI::Widget* w2)
{ {
// Workaround to not make the marker visible if it's under fog of war
applyFogOfWar (); applyFogOfWar ();
} }
MyGUI::IntPoint LocalMapBase::getMarkerPosition(float worldX, float worldY, MarkerPosition& markerPos)
{
MyGUI::IntPoint widgetPos;
// normalized cell coordinates
float nX,nY;
markerPos.interior = mInterior;
if (!mInterior)
{
int cellX, cellY;
MWBase::Environment::get().getWorld()->positionToIndex(worldX, worldY, cellX, cellY);
const int cellSize = 8192;
nX = (worldX - cellSize * cellX) / cellSize;
// Image space is -Y up, cells are Y up
nY = 1 - (worldY - cellSize * cellY) / cellSize;
float cellDx = cellX - mCurX;
float cellDy = cellY - mCurY;
markerPos.cellX = cellX;
markerPos.cellY = cellY;
widgetPos = MyGUI::IntPoint(nX * 512 + (1+cellDx) * 512,
nY * 512 - (cellDy-1) * 512);
}
else
{
int cellX, cellY;
Ogre::Vector2 worldPos (worldX, worldY);
MWBase::Environment::get().getWorld ()->getInteriorMapPosition (worldPos, nX, nY, cellX, cellY);
markerPos.cellX = cellX;
markerPos.cellY = cellY;
widgetPos = MyGUI::IntPoint(nX * 512 + (1+cellX-mCurX) * 512,
nY * 512 + (1+cellY-mCurY) * 512);
}
markerPos.nX = nX;
markerPos.nY = nY;
return widgetPos;
}
void LocalMapBase::setActiveCell(const int x, const int y, bool interior) void LocalMapBase::setActiveCell(const int x, const int y, bool interior)
{ {
if (x==mCurX && y==mCurY && mInterior==interior && !mChanged) return; // don't do anything if we're still in the same cell if (x==mCurX && y==mCurY && mInterior==interior && !mChanged)
return; // don't do anything if we're still in the same cell
mCurX = x;
mCurY = y;
mInterior = interior;
mChanged = false;
// clear all previous markers // clear all previous markers
for (unsigned int i=0; i< mLocalMap->getChildCount(); ++i) for (unsigned int i=0; i< mLocalMap->getChildCount(); ++i)
{ {
if (mLocalMap->getChildAt(i)->getName ().substr (0, 6) == "Marker") if (mLocalMap->getChildAt(i)->getName ().substr (0, 4) == "Door")
{ {
MyGUI::Gui::getInstance ().destroyWidget (mLocalMap->getChildAt(i)); MyGUI::Gui::getInstance ().destroyWidget (mLocalMap->getChildAt(i));
} }
} }
// Update the map textures
for (int mx=0; mx<3; ++mx) for (int mx=0; mx<3; ++mx)
{ {
for (int my=0; my<3; ++my) for (int my=0; my<3; ++my)
@ -138,78 +191,57 @@ namespace MWGui
box->setImageTexture(image); box->setImageTexture(image);
else else
box->setImageTexture("black.png"); box->setImageTexture("black.png");
// door markers
// interior map only consists of one cell, so handle the markers only once
if (interior && (mx != 2 || my != 2))
continue;
MWWorld::CellStore* cell;
if (interior)
cell = MWBase::Environment::get().getWorld ()->getInterior (mPrefix);
else
cell = MWBase::Environment::get().getWorld ()->getExterior (x+mx-1, y-(my-1));
std::vector<MWBase::World::DoorMarker> doors = MWBase::Environment::get().getWorld ()->getDoorMarkers (cell);
for (std::vector<MWBase::World::DoorMarker>::iterator it = doors.begin(); it != doors.end(); ++it)
{
MWBase::World::DoorMarker marker = *it;
// convert world coordinates to normalized cell coordinates
MyGUI::IntCoord widgetCoord;
float nX,nY;
int cellDx, cellDy;
if (!interior)
{
const int cellSize = 8192;
nX = (marker.x - cellSize * (x+mx-1)) / cellSize;
nY = 1 - (marker.y - cellSize * (y-(my-1))) / cellSize;
widgetCoord = MyGUI::IntCoord(nX * 512 - 4 + mx * 512, nY * 512 - 4 + my * 512, 8, 8);
}
else
{
Ogre::Vector2 position (marker.x, marker.y);
MWBase::Environment::get().getWorld ()->getInteriorMapPosition (position, nX, nY, cellDx, cellDy);
widgetCoord = MyGUI::IntCoord(nX * 512 - 4 + (1+cellDx-x) * 512, nY * 512 - 4 + (1+cellDy-y) * 512, 8, 8);
}
static int counter = 0;
++counter;
MyGUI::Button* markerWidget = mLocalMap->createWidget<MyGUI::Button>("ButtonImage",
widgetCoord, MyGUI::Align::Default, "Marker" + boost::lexical_cast<std::string>(counter));
markerWidget->setImageResource("DoorMarker");
markerWidget->setUserString("ToolTipType", "Layout");
markerWidget->setUserString("ToolTipLayout", "TextToolTipOneLine");
markerWidget->setUserString("Caption_TextOneLine", marker.name);
markerWidget->setUserString("IsMarker", "true");
markerWidget->eventMouseSetFocus += MyGUI::newDelegate(this, &LocalMapBase::onMarkerFocused);
markerWidget->eventMouseLostFocus += MyGUI::newDelegate(this, &LocalMapBase::onMarkerUnfocused);
MarkerPosition markerPos;
markerPos.interior = interior;
markerPos.cellX = interior ? cellDx : x + mx - 1;
markerPos.cellY = interior ? cellDy : y + ((my - 1)*-1);
markerPos.nX = nX;
markerPos.nY = nY;
markerWidget->setUserData(markerPos);
}
} }
} }
mInterior = interior;
mCurX = x;
mCurY = y;
mChanged = false;
// fog of war MWBase::World* world = MWBase::Environment::get().getWorld();
// Retrieve the door markers we want to show
std::vector<MWBase::World::DoorMarker> doors;
if (interior)
{
MWWorld::CellStore* cell = world->getInterior (mPrefix);
world->getDoorMarkers(cell, doors);
}
else
{
for (int dX=-1; dX<2; ++dX)
{
for (int dY=-1; dY<2; ++dY)
{
MWWorld::CellStore* cell = world->getExterior (mCurX+dX, mCurY+dY);
world->getDoorMarkers(cell, doors);
}
}
}
// Create a widget for each marker
int counter = 0;
for (std::vector<MWBase::World::DoorMarker>::iterator it = doors.begin(); it != doors.end(); ++it)
{
MWBase::World::DoorMarker marker = *it;
MarkerPosition markerPos;
MyGUI::IntPoint widgetPos = getMarkerPosition(marker.x, marker.y, markerPos);
MyGUI::IntCoord widgetCoord(widgetPos.left - 4,
widgetPos.top - 4,
8, 8);
++counter;
MyGUI::Button* markerWidget = mLocalMap->createWidget<MyGUI::Button>("ButtonImage",
widgetCoord, MyGUI::Align::Default, "Door" + boost::lexical_cast<std::string>(counter));
markerWidget->setImageResource("DoorMarker");
markerWidget->setUserString("ToolTipType", "Layout");
markerWidget->setUserString("ToolTipLayout", "TextToolTipOneLine");
markerWidget->setUserString("Caption_TextOneLine", marker.name);
markerWidget->eventMouseSetFocus += MyGUI::newDelegate(this, &LocalMapBase::onMarkerFocused);
markerWidget->eventMouseLostFocus += MyGUI::newDelegate(this, &LocalMapBase::onMarkerUnfocused);
// Used by tooltips to not show the tooltip if marker is hidden by fog of war
markerWidget->setUserString("IsMarker", "true");
markerWidget->setUserData(markerPos);
}
updateMarkers();
applyFogOfWar(); applyFogOfWar();
// set the compass texture again, because MyGUI determines sorting of ImageBox widgets // set the compass texture again, because MyGUI determines sorting of ImageBox widgets
@ -222,6 +254,8 @@ namespace MWGui
void LocalMapBase::setPlayerPos(const float x, const float y) void LocalMapBase::setPlayerPos(const float x, const float y)
{ {
updateMarkers();
if (x == mLastPositionX && y == mLastPositionY) if (x == mLastPositionX && y == mLastPositionY)
return; return;
@ -255,6 +289,88 @@ namespace MWGui
mLastDirectionY = y; mLastDirectionY = y;
} }
void LocalMapBase::addDetectionMarkers(int type)
{
std::vector<MWWorld::Ptr> markers;
MWBase::World* world = MWBase::Environment::get().getWorld();
world->listDetectedReferences(
world->getPlayer().getPlayer(),
markers, MWBase::World::DetectionType(type));
if (markers.empty())
return;
std::string markerTexture;
MyGUI::Colour markerColour;
if (type == MWBase::World::Detect_Creature)
{
markerTexture = "textures\\menu_map_dcreature.dds";
markerColour = MyGUI::Colour(1,0,0,1);
}
if (type == MWBase::World::Detect_Key)
{
markerTexture = "textures\\menu_map_dkey.dds";
markerColour = MyGUI::Colour(0,1,0,1);
}
if (type == MWBase::World::Detect_Enchantment)
{
markerTexture = "textures\\menu_map_dmagic.dds";
markerColour = MyGUI::Colour(0,0,1,1);
}
int counter = 0;
for (std::vector<MWWorld::Ptr>::iterator it = markers.begin(); it != markers.end(); ++it)
{
const ESM::Position& worldPos = it->getRefData().getPosition();
MarkerPosition markerPos;
MyGUI::IntPoint widgetPos = getMarkerPosition(worldPos.pos[0], worldPos.pos[1], markerPos);
MyGUI::IntCoord widgetCoord(widgetPos.left - 4,
widgetPos.top - 4,
8, 8);
++counter;
MyGUI::ImageBox* markerWidget = mLocalMap->createWidget<MyGUI::ImageBox>("ImageBox",
widgetCoord, MyGUI::Align::Default, "Marker" + boost::lexical_cast<std::string>(counter));
markerWidget->setImageTexture(markerTexture);
markerWidget->setUserString("IsMarker", "true");
markerWidget->setUserData(markerPos);
markerWidget->setColour(markerColour);
}
}
void LocalMapBase::updateMarkers()
{
// clear all previous markers
for (unsigned int i=0; i< mLocalMap->getChildCount(); ++i)
{
if (mLocalMap->getChildAt(i)->getName ().substr (0, 6) == "Marker")
{
MyGUI::Gui::getInstance ().destroyWidget (mLocalMap->getChildAt(i));
}
}
addDetectionMarkers(MWBase::World::Detect_Creature);
addDetectionMarkers(MWBase::World::Detect_Key);
addDetectionMarkers(MWBase::World::Detect_Enchantment);
// Add marker for the spot marked with Mark magic effect
MWWorld::CellStore* markedCell = NULL;
ESM::Position markedPosition;
MWBase::Environment::get().getWorld()->getPlayer().getMarkedPosition(markedCell, markedPosition);
if (markedCell && markedCell->isExterior() == !mInterior
&& (!mInterior || Misc::StringUtils::ciEqual(markedCell->mCell->mName, mPrefix)))
{
MarkerPosition markerPos;
MyGUI::IntPoint widgetPos = getMarkerPosition(markedPosition.pos[0], markedPosition.pos[1], markerPos);
MyGUI::IntCoord widgetCoord(widgetPos.left - 4,
widgetPos.top - 4,
8, 8);
MyGUI::ImageBox* markerWidget = mLocalMap->createWidget<MyGUI::ImageBox>("ImageBox",
widgetCoord, MyGUI::Align::Default, "MarkerMarked");
markerWidget->setImageTexture("textures\\menu_map_smark.dds");
markerWidget->setUserString("IsMarker", "true");
markerWidget->setUserData(markerPos);
}
}
// ------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------
MapWindow::MapWindow(const std::string& cacheDir) MapWindow::MapWindow(const std::string& cacheDir)
@ -319,7 +435,7 @@ namespace MWGui
static int _counter=0; static int _counter=0;
MyGUI::Button* markerWidget = mGlobalMapImage->createWidget<MyGUI::Button>("ButtonImage", MyGUI::Button* markerWidget = mGlobalMapImage->createWidget<MyGUI::Button>("ButtonImage",
widgetCoord, MyGUI::Align::Default, "Marker" + boost::lexical_cast<std::string>(_counter)); widgetCoord, MyGUI::Align::Default, "Door" + boost::lexical_cast<std::string>(_counter));
markerWidget->setImageResource("DoorMarker"); markerWidget->setImageResource("DoorMarker");
markerWidget->setUserString("ToolTipType", "Layout"); markerWidget->setUserString("ToolTipType", "Layout");
markerWidget->setUserString("ToolTipLayout", "TextToolTipOneLine"); markerWidget->setUserString("ToolTipLayout", "TextToolTipOneLine");
@ -385,7 +501,7 @@ namespace MWGui
for (unsigned int i=0; i<mGlobalMapImage->getChildCount (); ++i) for (unsigned int i=0; i<mGlobalMapImage->getChildCount (); ++i)
{ {
if (mGlobalMapImage->getChildAt (i)->getName().substr(0,6) == "Marker") if (mGlobalMapImage->getChildAt (i)->getName().substr(0,4) == "Door")
mGlobalMapImage->getChildAt (i)->castType<MyGUI::Button>()->setImageResource("DoorMarker"); mGlobalMapImage->getChildAt (i)->castType<MyGUI::Button>()->setImageResource("DoorMarker");
} }

View file

@ -55,9 +55,16 @@ namespace MWGui
void onMarkerFocused(MyGUI::Widget* w1, MyGUI::Widget* w2); void onMarkerFocused(MyGUI::Widget* w1, MyGUI::Widget* w2);
void onMarkerUnfocused(MyGUI::Widget* w1, MyGUI::Widget* w2); void onMarkerUnfocused(MyGUI::Widget* w1, MyGUI::Widget* w2);
MyGUI::IntPoint getMarkerPosition (float worldX, float worldY, MarkerPosition& markerPos);
virtual void notifyPlayerUpdate() {} virtual void notifyPlayerUpdate() {}
virtual void notifyMapChanged() {} virtual void notifyMapChanged() {}
// Update markers (Detect X effects, Mark/Recall effects)
// Note, door markers handled in setActiveCell
void updateMarkers();
void addDetectionMarkers(int type);
OEngine::GUI::Layout* mLayout; OEngine::GUI::Layout* mLayout;
bool mMapDragAndDrop; bool mMapDragAndDrop;

View file

@ -225,64 +225,54 @@ void LocalMap::render(const float x, const float y,
tex = TextureManager::getSingleton().getByName(texture); tex = TextureManager::getSingleton().getByName(texture);
if (tex.isNull()) if (tex.isNull())
{ {
// try loading from disk // render
//if (boost::filesystem::exists(texture+".jpg")) tex = TextureManager::getSingleton().createManual(
//{ texture,
/// \todo ResourceGroupManager::DEFAULT_RESOURCE_GROUP_NAME,
//} TEX_TYPE_2D,
//else xw*sMapResolution/sSize, yw*sMapResolution/sSize,
0,
PF_R8G8B8,
TU_RENDERTARGET);
RenderTarget* rtt = tex->getBuffer()->getRenderTarget();
rtt->setAutoUpdated(false);
Viewport* vp = rtt->addViewport(mCellCamera);
vp->setOverlaysEnabled(false);
vp->setShadowsEnabled(false);
vp->setBackgroundColour(ColourValue(0, 0, 0));
vp->setVisibilityMask(RV_Map);
vp->setMaterialScheme("local_map");
rtt->update();
// create "fog of war" texture
TexturePtr tex2 = TextureManager::getSingleton().createManual(
texture + "_fog",
ResourceGroupManager::DEFAULT_RESOURCE_GROUP_NAME,
TEX_TYPE_2D,
xw*sFogOfWarResolution/sSize, yw*sFogOfWarResolution/sSize,
0,
PF_A8R8G8B8,
TU_DYNAMIC_WRITE_ONLY_DISCARDABLE);
// create a buffer to use for dynamic operations
std::vector<uint32> buffer;
buffer.resize(sFogOfWarResolution*sFogOfWarResolution);
// initialize to (0, 0, 0, 1)
for (int p=0; p<sFogOfWarResolution*sFogOfWarResolution; ++p)
{ {
// render buffer[p] = (255 << 24);
tex = TextureManager::getSingleton().createManual(
texture,
ResourceGroupManager::DEFAULT_RESOURCE_GROUP_NAME,
TEX_TYPE_2D,
xw*sMapResolution/sSize, yw*sMapResolution/sSize,
0,
PF_R8G8B8,
TU_RENDERTARGET);
RenderTarget* rtt = tex->getBuffer()->getRenderTarget();
rtt->setAutoUpdated(false);
Viewport* vp = rtt->addViewport(mCellCamera);
vp->setOverlaysEnabled(false);
vp->setShadowsEnabled(false);
vp->setBackgroundColour(ColourValue(0, 0, 0));
vp->setVisibilityMask(RV_Map);
vp->setMaterialScheme("local_map");
rtt->update();
// create "fog of war" texture
TexturePtr tex2 = TextureManager::getSingleton().createManual(
texture + "_fog",
ResourceGroupManager::DEFAULT_RESOURCE_GROUP_NAME,
TEX_TYPE_2D,
xw*sFogOfWarResolution/sSize, yw*sFogOfWarResolution/sSize,
0,
PF_A8R8G8B8,
TU_DYNAMIC_WRITE_ONLY_DISCARDABLE);
// create a buffer to use for dynamic operations
std::vector<uint32> buffer;
buffer.resize(sFogOfWarResolution*sFogOfWarResolution);
// initialize to (0, 0, 0, 1)
for (int p=0; p<sFogOfWarResolution*sFogOfWarResolution; ++p)
{
buffer[p] = (255 << 24);
}
memcpy(tex2->getBuffer()->lock(HardwareBuffer::HBL_DISCARD), &buffer[0], sFogOfWarResolution*sFogOfWarResolution*4);
tex2->getBuffer()->unlock();
mBuffers[texture] = buffer;
// save to cache for next time
//rtt->writeContentsToFile("./" + texture + ".jpg");
} }
memcpy(tex2->getBuffer()->lock(HardwareBuffer::HBL_DISCARD), &buffer[0], sFogOfWarResolution*sFogOfWarResolution*4);
tex2->getBuffer()->unlock();
mBuffers[texture] = buffer;
} }
mRenderingManager->enableLights(true); mRenderingManager->enableLights(true);
mLight->setVisible(false); mLight->setVisible(false);
@ -339,8 +329,6 @@ void LocalMap::updatePlayer (const Ogre::Vector3& position, const Ogre::Quaterni
Vector3 playerdirection = mCameraRotNode->convertWorldToLocalOrientation(orientation).yAxis(); Vector3 playerdirection = mCameraRotNode->convertWorldToLocalOrientation(orientation).yAxis();
Vector2 min(mBounds.getMinimum().x, mBounds.getMinimum().y);
if (!mInterior) if (!mInterior)
{ {
x = std::ceil(pos.x / sSize)-1; x = std::ceil(pos.x / sSize)-1;

View file

@ -4,7 +4,7 @@
#include <vector> #include <vector>
#include <string> #include <string>
#include "refdata.hpp" #include "ptr.hpp"
namespace ESM namespace ESM
{ {
@ -18,13 +18,13 @@ namespace MWWorld
{ {
std::vector<Ogre::SceneNode*> mHandles; std::vector<Ogre::SceneNode*> mHandles;
bool operator() (ESM::CellRef& ref, RefData& data) bool operator() (MWWorld::Ptr ptr)
{ {
Ogre::SceneNode* handle = data.getBaseNode(); Ogre::SceneNode* handle = ptr.getRefData().getBaseNode();
if (handle) if (handle)
mHandles.push_back (handle); mHandles.push_back (handle);
data.setBaseNode(0); ptr.getRefData().setBaseNode(0);
return true; return true;
} }
}; };

View file

@ -143,7 +143,7 @@ namespace MWWorld
{ {
if (!iter->mData.getCount()) if (!iter->mData.getCount())
continue; continue;
if (!functor (iter->mRef, iter->mData)) if (!functor (MWWorld::Ptr(&*iter, this)))
return false; return false;
} }
return true; return true;

View file

@ -290,6 +290,8 @@ namespace MWWorld
virtual bool isPersistent (const MWWorld::Ptr& ptr) const; virtual bool isPersistent (const MWWorld::Ptr& ptr) const;
virtual bool isKey (const MWWorld::Ptr& ptr) const { return false; }
virtual Ptr virtual Ptr
copyToCell(const Ptr &ptr, CellStore &cell) const; copyToCell(const Ptr &ptr, CellStore &cell) const;

View file

@ -1442,10 +1442,8 @@ namespace MWWorld
return d; return d;
} }
std::vector<World::DoorMarker> World::getDoorMarkers (CellStore* cell) void World::getDoorMarkers (CellStore* cell, std::vector<World::DoorMarker>& out)
{ {
std::vector<World::DoorMarker> result;
MWWorld::CellRefList<ESM::Door>& doors = cell->mDoors; MWWorld::CellRefList<ESM::Door>& doors = cell->mDoors;
CellRefList<ESM::Door>::List& refList = doors.mList; CellRefList<ESM::Door>::List& refList = doors.mList;
for (CellRefList<ESM::Door>::List::iterator it = refList.begin(); it != refList.end(); ++it) for (CellRefList<ESM::Door>::List::iterator it = refList.begin(); it != refList.end(); ++it)
@ -1461,11 +1459,9 @@ namespace MWWorld
newMarker.x = pos.pos[0]; newMarker.x = pos.pos[0];
newMarker.y = pos.pos[1]; newMarker.y = pos.pos[1];
result.push_back(newMarker); out.push_back(newMarker);
} }
} }
return result;
} }
void World::getInteriorMapPosition (Ogre::Vector2 position, float& nX, float& nY, int &x, int& y) void World::getInteriorMapPosition (Ogre::Vector2 position, float& nX, float& nY, int &x, int& y)
@ -1829,9 +1825,9 @@ namespace MWWorld
{ {
std::vector<std::string> mHandles; std::vector<std::string> mHandles;
bool operator() (ESM::CellRef& ref, RefData& data) bool operator() (Ptr ptr)
{ {
Ogre::SceneNode* handle = data.getBaseNode(); Ogre::SceneNode* handle = ptr.getRefData().getBaseNode();
if (handle) if (handle)
mHandles.push_back(handle->getName()); mHandles.push_back(handle->getName());
return true; return true;
@ -2348,4 +2344,85 @@ namespace MWWorld
mWeatherManager->update(duration); mWeatherManager->update(duration);
} }
struct AddDetectedReference
{
AddDetectedReference(std::vector<Ptr>& out, Ptr detector, World::DetectionType type, float squaredDist)
: mOut(out), mDetector(detector), mType(type), mSquaredDist(squaredDist)
{
}
std::vector<Ptr>& mOut;
Ptr mDetector;
float mSquaredDist;
World::DetectionType mType;
bool operator() (MWWorld::Ptr ptr)
{
if (Ogre::Vector3(ptr.getRefData().getPosition().pos).squaredDistance(
Ogre::Vector3(mDetector.getRefData().getPosition().pos)) >= mSquaredDist)
return true;
if (!ptr.getRefData().isEnabled())
return true;
// Consider references inside containers as well
if (ptr.getClass().isActor() || ptr.getClass().getTypeName() == typeid(ESM::Container).name())
{
MWWorld::ContainerStore& store = ptr.getClass().getContainerStore(ptr);
{
for (MWWorld::ContainerStoreIterator it = store.begin(); it != store.end(); ++it)
{
if (needToAdd(*it))
{
mOut.push_back(ptr);
return true;
}
}
}
}
if (needToAdd(ptr))
mOut.push_back(ptr);
return true;
}
bool needToAdd (MWWorld::Ptr ptr)
{
if (mType == World::Detect_Creature && ptr.getClass().getTypeName() != typeid(ESM::Creature).name())
return false;
if (mType == World::Detect_Key && !ptr.getClass().isKey(ptr))
return false;
if (mType == World::Detect_Enchantment && ptr.getClass().getEnchantment(ptr).empty())
return false;
return true;
}
};
void World::listDetectedReferences(const Ptr &ptr, std::vector<Ptr> &out, DetectionType type)
{
const MWMechanics::MagicEffects& effects = ptr.getClass().getCreatureStats(ptr).getMagicEffects();
float dist=0;
if (type == World::Detect_Creature)
dist = effects.get(MWMechanics::EffectKey(ESM::MagicEffect::DetectAnimal)).mMagnitude;
else if (type == World::Detect_Key)
dist = effects.get(MWMechanics::EffectKey(ESM::MagicEffect::DetectKey)).mMagnitude;
else if (type == World::Detect_Enchantment)
dist = effects.get(MWMechanics::EffectKey(ESM::MagicEffect::DetectEnchantment)).mMagnitude;
if (!dist)
return;
// TODO: "1 foot" = 20 game units?
dist *= 20;
AddDetectedReference functor (out, ptr, type, dist*dist);
const Scene::CellStoreCollection& active = mWorldScene->getActiveCells();
for (Scene::CellStoreCollection::const_iterator it = active.begin(); it != active.end(); ++it)
{
MWWorld::CellStore* cellStore = *it;
cellStore->forEach(functor);
}
}
} }

View file

@ -202,7 +202,7 @@ namespace MWWorld
virtual Ogre::Vector2 getNorthVector (CellStore* cell); virtual Ogre::Vector2 getNorthVector (CellStore* cell);
///< get north vector (OGRE coordinates) for given interior cell ///< get north vector (OGRE coordinates) for given interior cell
virtual std::vector<DoorMarker> getDoorMarkers (MWWorld::CellStore* cell); virtual void getDoorMarkers (MWWorld::CellStore* cell, std::vector<DoorMarker>& out);
///< get a list of teleport door markers for a given cell, to be displayed on the local map ///< get a list of teleport door markers for a given cell, to be displayed on the local map
virtual void getInteriorMapPosition (Ogre::Vector2 position, float& nX, float& nY, int &x, int& y); virtual void getInteriorMapPosition (Ogre::Vector2 position, float& nX, float& nY, int &x, int& y);
@ -526,6 +526,12 @@ namespace MWWorld
/// @note id must be lower case /// @note id must be lower case
virtual void teleportToClosestMarker (const MWWorld::Ptr& ptr, virtual void teleportToClosestMarker (const MWWorld::Ptr& ptr,
const std::string& id, Ogre::Vector3 worldPos); const std::string& id, Ogre::Vector3 worldPos);
/// List all references (filtered by \a type) detected by \a ptr. The range
/// is determined by the current magnitude of the "Detect X" magic effect belonging to \a type.
/// @note This also works for references in containers.
virtual void listDetectedReferences (const MWWorld::Ptr& ptr, std::vector<MWWorld::Ptr>& out,
DetectionType type);
}; };
} }