mirror of
https://gitlab.com/OpenMW/openmw.git
synced 2025-03-14 01:19:59 +00:00
Merge remote-tracking branch 'scrawl/master'
This commit is contained in:
commit
a6e6411686
@ -99,8 +99,6 @@ set(OENGINE_BULLET
|
||||
${LIBDIR}/openengine/bullet/BtOgreExtras.h
|
||||
${LIBDIR}/openengine/bullet/BtOgreGP.h
|
||||
${LIBDIR}/openengine/bullet/BtOgrePG.h
|
||||
${LIBDIR}/openengine/bullet/CMotionState.cpp
|
||||
${LIBDIR}/openengine/bullet/CMotionState.h
|
||||
${LIBDIR}/openengine/bullet/physic.cpp
|
||||
${LIBDIR}/openengine/bullet/physic.hpp
|
||||
${LIBDIR}/openengine/bullet/BulletShapeLoader.cpp
|
||||
|
@ -130,7 +130,7 @@ namespace MWBase
|
||||
virtual Ogre::Vector2 getNorthVector (MWWorld::CellStore* cell) = 0;
|
||||
///< 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
|
||||
|
||||
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
|
||||
virtual void teleportToClosestMarker (const MWWorld::Ptr& ptr,
|
||||
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;
|
||||
};
|
||||
}
|
||||
|
||||
|
@ -291,6 +291,9 @@ namespace MWClass
|
||||
{
|
||||
MWWorld::InventoryStore& invStore = MWWorld::Class::get(npc).getInventoryStore(npc);
|
||||
|
||||
if (ptr.getCellRef().mCharge == 0)
|
||||
return std::make_pair(0, "#{sInventoryMessage1}");
|
||||
|
||||
// slots that this item can be equipped in
|
||||
std::pair<std::vector<int>, bool> slots_ = MWWorld::Class::get(ptr).getEquipmentSlots(ptr);
|
||||
|
||||
|
@ -252,4 +252,11 @@ namespace MWClass
|
||||
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;
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -57,6 +57,8 @@ namespace MWClass
|
||||
virtual float getWeight (const MWWorld::Ptr& ptr) const;
|
||||
|
||||
virtual bool canSell (const MWWorld::Ptr& item, int npcServices) const;
|
||||
|
||||
virtual bool isKey (const MWWorld::Ptr &ptr) const;
|
||||
};
|
||||
}
|
||||
|
||||
|
@ -493,6 +493,11 @@ namespace MWClass
|
||||
if (!MWBase::Environment::get().getWorld()->getGodModeState())
|
||||
weapon.getCellRef().mCharge -= std::min(std::max(1,
|
||||
(int)(damage * gmst.find("fWeaponDamageMult")->getFloat())), weapon.getCellRef().mCharge);
|
||||
|
||||
// Weapon broken? unequip it
|
||||
if (weapon.getCellRef().mCharge == 0)
|
||||
weapon = *inv.unequipItem(weapon, ptr);
|
||||
|
||||
}
|
||||
healthdmg = true;
|
||||
}
|
||||
@ -644,6 +649,11 @@ namespace MWClass
|
||||
armorref.mCharge = armor.get<ESM::Armor>()->mBase->mData.mHealth;
|
||||
armorref.mCharge -= std::min(std::max(1, (int)damagediff),
|
||||
armorref.mCharge);
|
||||
|
||||
// Armor broken? unequip it
|
||||
if (armorref.mCharge == 0)
|
||||
inv.unequipItem(armor, ptr);
|
||||
|
||||
switch(get(armor).getEquipmentSkill(armor))
|
||||
{
|
||||
case ESM::Skill::LightArmor:
|
||||
|
@ -388,6 +388,9 @@ namespace MWClass
|
||||
|
||||
std::pair<int, std::string> Weapon::canBeEquipped(const MWWorld::Ptr &ptr, const MWWorld::Ptr &npc) const
|
||||
{
|
||||
if (ptr.getCellRef().mCharge == 0)
|
||||
return std::make_pair(0, "#{sInventoryMessage1}");
|
||||
|
||||
std::pair<std::vector<int>, bool> slots_ = MWWorld::Class::get(ptr).getEquipmentSlots(ptr);
|
||||
|
||||
if (slots_.first.empty())
|
||||
|
@ -163,6 +163,14 @@ namespace MWGui
|
||||
MWWorld::Ptr object = item.mBase;
|
||||
int count = item.mCount;
|
||||
|
||||
// Bound items may not be moved
|
||||
if (item.mBase.getCellRef().mRefID.size() > 6
|
||||
&& item.mBase.getCellRef().mRefID.substr(0,6) == "bound_")
|
||||
{
|
||||
MWBase::Environment::get().getWindowManager()->messageBox("#{sBarterDialog12}");
|
||||
return;
|
||||
}
|
||||
|
||||
if (item.mType == ItemStack::Type_Equipped)
|
||||
{
|
||||
MWWorld::InventoryStore& invStore = MWWorld::Class::get(mPtr).getInventoryStore(mPtr);
|
||||
|
@ -103,27 +103,80 @@ namespace MWGui
|
||||
|
||||
void LocalMapBase::onMarkerFocused (MyGUI::Widget* w1, MyGUI::Widget* w2)
|
||||
{
|
||||
// Workaround to not make the marker visible if it's under fog of war
|
||||
applyFogOfWar ();
|
||||
}
|
||||
|
||||
void LocalMapBase::onMarkerUnfocused (MyGUI::Widget* w1, MyGUI::Widget* w2)
|
||||
{
|
||||
// Workaround to not make the marker visible if it's under fog of war
|
||||
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)
|
||||
{
|
||||
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
|
||||
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));
|
||||
}
|
||||
}
|
||||
|
||||
// Update the map textures
|
||||
for (int mx=0; mx<3; ++mx)
|
||||
{
|
||||
for (int my=0; my<3; ++my)
|
||||
@ -138,78 +191,57 @@ namespace MWGui
|
||||
box->setImageTexture(image);
|
||||
else
|
||||
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();
|
||||
|
||||
// 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)
|
||||
{
|
||||
updateMarkers();
|
||||
|
||||
if (x == mLastPositionX && y == mLastPositionY)
|
||||
return;
|
||||
|
||||
@ -255,6 +289,88 @@ namespace MWGui
|
||||
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)
|
||||
@ -319,7 +435,7 @@ namespace MWGui
|
||||
|
||||
static int _counter=0;
|
||||
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->setUserString("ToolTipType", "Layout");
|
||||
markerWidget->setUserString("ToolTipLayout", "TextToolTipOneLine");
|
||||
@ -385,7 +501,7 @@ namespace MWGui
|
||||
|
||||
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");
|
||||
}
|
||||
|
||||
|
@ -55,9 +55,16 @@ namespace MWGui
|
||||
void onMarkerFocused(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 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;
|
||||
|
||||
bool mMapDragAndDrop;
|
||||
|
@ -40,6 +40,14 @@ namespace MWGui
|
||||
for (size_t i = 0; i<mSourceModel->getItemCount(); ++i)
|
||||
{
|
||||
const ItemStack& item = mSourceModel->getItem(i);
|
||||
|
||||
// Bound items may not be stolen
|
||||
if (item.mBase.getCellRef().mRefID.size() > 6
|
||||
&& item.mBase.getCellRef().mRefID.substr(0,6) == "bound_")
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
if (std::find(mHiddenItems.begin(), mHiddenItems.end(), item) == mHiddenItems.end()
|
||||
&& item.mType != ItemStack::Type_Equipped)
|
||||
mItems.push_back(item);
|
||||
|
@ -154,6 +154,13 @@ namespace MWGui
|
||||
if(!MWWorld::Class::get(base).canSell(base, services))
|
||||
continue;
|
||||
|
||||
// Bound items may not be bought
|
||||
if (item.mBase.getCellRef().mRefID.size() > 6
|
||||
&& item.mBase.getCellRef().mRefID.substr(0,6) == "bound_")
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
// don't show equipped items
|
||||
if(mMerchant.getTypeName() == typeid(ESM::NPC).name())
|
||||
{
|
||||
|
@ -831,9 +831,11 @@ namespace MWInput
|
||||
|
||||
void InputManager::updateIdleTime(float dt)
|
||||
{
|
||||
static const float vanityDelay = MWBase::Environment::get().getWorld()->getStore().get<ESM::GameSetting>()
|
||||
.find("fVanityDelay")->getFloat();
|
||||
if (mTimeIdle >= 0.f)
|
||||
mTimeIdle += dt;
|
||||
if (mTimeIdle > 30.f) {
|
||||
if (mTimeIdle > vanityDelay) {
|
||||
MWBase::Environment::get().getWorld()->toggleVanityMode(true);
|
||||
mTimeIdle = -1.f;
|
||||
}
|
||||
|
@ -46,6 +46,44 @@ void adjustBoundItem (const std::string& item, bool bound, const MWWorld::Ptr& a
|
||||
}
|
||||
}
|
||||
|
||||
bool disintegrateSlot (MWWorld::Ptr ptr, int slot, float disintegrate)
|
||||
{
|
||||
// TODO: remove this check once creatures support inventory store
|
||||
if (ptr.getTypeName() == typeid(ESM::NPC).name())
|
||||
{
|
||||
MWWorld::InventoryStore& inv = ptr.getClass().getInventoryStore(ptr);
|
||||
MWWorld::ContainerStoreIterator item =
|
||||
inv.getSlot(slot);
|
||||
if (item != inv.end())
|
||||
{
|
||||
if (!item->getClass().hasItemHealth(*item))
|
||||
return false;
|
||||
if (item->getCellRef().mCharge == -1)
|
||||
item->getCellRef().mCharge = item->getClass().getItemMaxHealth(*item);
|
||||
|
||||
if (item->getCellRef().mCharge == 0)
|
||||
return false;
|
||||
|
||||
item->getCellRef().mCharge -=
|
||||
std::min(disintegrate,
|
||||
static_cast<float>(item->getCellRef().mCharge));
|
||||
|
||||
if (item->getCellRef().mCharge == 0)
|
||||
{
|
||||
// Will unequip the broken item and try to find a replacement
|
||||
if (ptr.getRefData().getHandle() != "player")
|
||||
inv.autoEquip(ptr);
|
||||
else
|
||||
inv.unequipItem(*item, ptr);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
namespace MWMechanics
|
||||
@ -241,6 +279,33 @@ namespace MWMechanics
|
||||
creatureStats.setDynamic(i, stat);
|
||||
}
|
||||
|
||||
// Apply disintegration (reduces item health)
|
||||
float disintegrateWeapon = effects.get(EffectKey(ESM::MagicEffect::DisintegrateWeapon)).mMagnitude;
|
||||
if (disintegrateWeapon > 0)
|
||||
disintegrateSlot(ptr, MWWorld::InventoryStore::Slot_CarriedRight, disintegrateWeapon*duration);
|
||||
float disintegrateArmor = effects.get(EffectKey(ESM::MagicEffect::DisintegrateArmor)).mMagnitude;
|
||||
if (disintegrateArmor > 0)
|
||||
{
|
||||
// According to UESP
|
||||
int priorities[] = {
|
||||
MWWorld::InventoryStore::Slot_CarriedLeft,
|
||||
MWWorld::InventoryStore::Slot_Cuirass,
|
||||
MWWorld::InventoryStore::Slot_LeftPauldron,
|
||||
MWWorld::InventoryStore::Slot_RightPauldron,
|
||||
MWWorld::InventoryStore::Slot_LeftGauntlet,
|
||||
MWWorld::InventoryStore::Slot_RightGauntlet,
|
||||
MWWorld::InventoryStore::Slot_Helmet,
|
||||
MWWorld::InventoryStore::Slot_Greaves,
|
||||
MWWorld::InventoryStore::Slot_Boots
|
||||
};
|
||||
|
||||
for (unsigned int i=0; i<sizeof(priorities)/sizeof(int); ++i)
|
||||
{
|
||||
if (disintegrateSlot(ptr, priorities[i], disintegrateArmor*duration))
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// Apply damage ticks
|
||||
int damageEffects[] = {
|
||||
ESM::MagicEffect::FireDamage, ESM::MagicEffect::ShockDamage, ESM::MagicEffect::FrostDamage, ESM::MagicEffect::Poison,
|
||||
@ -640,6 +705,11 @@ namespace MWMechanics
|
||||
|
||||
iter->second->kill();
|
||||
|
||||
// Reset magic effects and recalculate derived effects
|
||||
// One case where we need this is to make sure bound items are removed upon death
|
||||
stats.setMagicEffects(MWMechanics::MagicEffects());
|
||||
calculateCreatureStatModifiers(iter->first, 0);
|
||||
|
||||
++mDeathCount[cls.getId(iter->first)];
|
||||
|
||||
if(cls.isEssential(iter->first))
|
||||
|
@ -12,6 +12,8 @@
|
||||
#include "../mwworld/class.hpp"
|
||||
#include "../mwworld/player.hpp"
|
||||
|
||||
#include "spellcasting.hpp"
|
||||
|
||||
namespace MWMechanics
|
||||
{
|
||||
void MechanicsManager::buildPlayer()
|
||||
@ -123,6 +125,19 @@ namespace MWMechanics
|
||||
npcStats.getSkill (index).setBase (
|
||||
npcStats.getSkill (index).getBase() + bonus);
|
||||
}
|
||||
|
||||
if (i==1)
|
||||
{
|
||||
// Major skill - add starting spells for this skill if existing
|
||||
const MWWorld::ESMStore& store = MWBase::Environment::get().getWorld()->getStore();
|
||||
MWWorld::Store<ESM::Spell>::iterator it = store.get<ESM::Spell>().begin();
|
||||
for (; it != store.get<ESM::Spell>().end(); ++it)
|
||||
{
|
||||
if (it->mData.mFlags & ESM::Spell::F_PCStart
|
||||
&& spellSchoolToSkill(getSpellSchool(&*it, ptr)) == index)
|
||||
creatureStats.getSpells().add(it->mId);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -8,6 +8,7 @@
|
||||
|
||||
#include "../mwworld/containerstore.hpp"
|
||||
#include "../mwworld/player.hpp"
|
||||
#include "../mwworld/actionteleport.hpp"
|
||||
|
||||
#include "../mwrender/animation.hpp"
|
||||
|
||||
@ -250,26 +251,30 @@ namespace MWMechanics
|
||||
|
||||
if (effectId == ESM::MagicEffect::DivineIntervention)
|
||||
{
|
||||
MWBase::Environment::get().getWorld()->getPlayer().setTeleported(true);
|
||||
|
||||
MWBase::Environment::get().getWorld()->teleportToClosestMarker(target, "divinemarker", worldPos);
|
||||
MWBase::Environment::get().getWorld()->teleportToClosestMarker(target, "divinemarker", worldPos);
|
||||
}
|
||||
else if (effectId == ESM::MagicEffect::AlmsiviIntervention)
|
||||
{
|
||||
MWBase::Environment::get().getWorld()->getPlayer().setTeleported(true);
|
||||
|
||||
MWBase::Environment::get().getWorld()->teleportToClosestMarker(target, "templemarker", worldPos);
|
||||
}
|
||||
|
||||
else if (effectId == ESM::MagicEffect::Mark)
|
||||
{
|
||||
// TODO
|
||||
MWBase::Environment::get().getWorld()->getPlayer().markPosition(
|
||||
target.getCell(), target.getRefData().getPosition());
|
||||
}
|
||||
else if (effectId == ESM::MagicEffect::Recall)
|
||||
{
|
||||
MWBase::Environment::get().getWorld()->getPlayer().setTeleported(true);
|
||||
MWWorld::CellStore* markedCell = NULL;
|
||||
ESM::Position markedPosition;
|
||||
|
||||
// TODO
|
||||
MWBase::Environment::get().getWorld()->getPlayer().getMarkedPosition(markedCell, markedPosition);
|
||||
if (markedCell)
|
||||
{
|
||||
MWWorld::ActionTeleport action(markedCell->isExterior() ? "" : markedCell->mCell->mName,
|
||||
markedPosition);
|
||||
action.execute(target);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -280,6 +280,11 @@ namespace MWRender
|
||||
}
|
||||
}
|
||||
|
||||
float Camera::getCameraDistance() const
|
||||
{
|
||||
return mCamera->getPosition().z;
|
||||
}
|
||||
|
||||
void Camera::setCameraDistance(float dist, bool adjust, bool override)
|
||||
{
|
||||
if(mFirstPersonView && !mPreviewMode && !mVanity.enabled)
|
||||
|
@ -105,6 +105,8 @@ namespace MWRender
|
||||
/// Restore default camera distance for current mode.
|
||||
void setCameraDistance();
|
||||
|
||||
float getCameraDistance() const;
|
||||
|
||||
void setAnimation(NpcAnimation *anim);
|
||||
|
||||
/// Stores focal and camera world positions in passed arguments
|
||||
|
@ -225,64 +225,54 @@ void LocalMap::render(const float x, const float y,
|
||||
tex = TextureManager::getSingleton().getByName(texture);
|
||||
if (tex.isNull())
|
||||
{
|
||||
// try loading from disk
|
||||
//if (boost::filesystem::exists(texture+".jpg"))
|
||||
//{
|
||||
/// \todo
|
||||
//}
|
||||
//else
|
||||
// render
|
||||
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)
|
||||
{
|
||||
// render
|
||||
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");
|
||||
buffer[p] = (255 << 24);
|
||||
}
|
||||
|
||||
memcpy(tex2->getBuffer()->lock(HardwareBuffer::HBL_DISCARD), &buffer[0], sFogOfWarResolution*sFogOfWarResolution*4);
|
||||
tex2->getBuffer()->unlock();
|
||||
|
||||
mBuffers[texture] = buffer;
|
||||
}
|
||||
|
||||
mRenderingManager->enableLights(true);
|
||||
mLight->setVisible(false);
|
||||
|
||||
@ -339,8 +329,6 @@ void LocalMap::updatePlayer (const Ogre::Vector3& position, const Ogre::Quaterni
|
||||
|
||||
Vector3 playerdirection = mCameraRotNode->convertWorldToLocalOrientation(orientation).yAxis();
|
||||
|
||||
Vector2 min(mBounds.getMinimum().x, mBounds.getMinimum().y);
|
||||
|
||||
if (!mInterior)
|
||||
{
|
||||
x = std::ceil(pos.x / sSize)-1;
|
||||
|
@ -1026,4 +1026,9 @@ void RenderingManager::enableTerrain(bool enable)
|
||||
mTerrain->setVisible(false);
|
||||
}
|
||||
|
||||
float RenderingManager::getCameraDistance() const
|
||||
{
|
||||
return mCamera->getCameraDistance();
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
@ -90,6 +90,7 @@ public:
|
||||
|
||||
bool vanityRotateCamera(const float *rot);
|
||||
void setCameraDistance(float dist, bool adjust = false, bool override = true);
|
||||
float getCameraDistance() const;
|
||||
|
||||
void setupPlayer(const MWWorld::Ptr &ptr);
|
||||
void renderPlayer(const MWWorld::Ptr &ptr);
|
||||
|
@ -207,6 +207,10 @@ namespace MWScript
|
||||
virtual void execute (Interpreter::Runtime& runtime)
|
||||
{
|
||||
MWWorld::Ptr ptr = R()(runtime);
|
||||
|
||||
if (!ptr.isInCell())
|
||||
return;
|
||||
|
||||
if (ptr.getRefData().getHandle() == "player")
|
||||
{
|
||||
MWBase::Environment::get().getWorld()->getPlayer().setTeleported(true);
|
||||
@ -275,6 +279,10 @@ namespace MWScript
|
||||
virtual void execute (Interpreter::Runtime& runtime)
|
||||
{
|
||||
MWWorld::Ptr ptr = R()(runtime);
|
||||
|
||||
if (!ptr.isInCell())
|
||||
return;
|
||||
|
||||
if (ptr.getRefData().getHandle() == "player")
|
||||
{
|
||||
MWBase::Environment::get().getWorld()->getPlayer().setTeleported(true);
|
||||
@ -336,6 +344,10 @@ namespace MWScript
|
||||
virtual void execute (Interpreter::Runtime& runtime)
|
||||
{
|
||||
MWWorld::Ptr ptr = R()(runtime);
|
||||
|
||||
if (!ptr.isInCell())
|
||||
return;
|
||||
|
||||
if (ptr.getRefData().getHandle() == "player")
|
||||
{
|
||||
MWBase::Environment::get().getWorld()->getPlayer().setTeleported(true);
|
||||
@ -605,6 +617,10 @@ namespace MWScript
|
||||
virtual void execute (Interpreter::Runtime& runtime)
|
||||
{
|
||||
MWWorld::Ptr ptr = R()(runtime);
|
||||
|
||||
if (!ptr.isInCell())
|
||||
return;
|
||||
|
||||
ptr.getRefData().getLocalRotation().rot[0] = 0;
|
||||
ptr.getRefData().getLocalRotation().rot[1] = 0;
|
||||
ptr.getRefData().getLocalRotation().rot[2] = 0;
|
||||
@ -624,6 +640,9 @@ namespace MWScript
|
||||
{
|
||||
const MWWorld::Ptr& ptr = R()(runtime);
|
||||
|
||||
if (!ptr.isInCell())
|
||||
return;
|
||||
|
||||
std::string axis = runtime.getStringLiteral (runtime[0].mInteger);
|
||||
runtime.pop();
|
||||
Interpreter::Type_Float movement = (runtime[0].mFloat*MWBase::Environment::get().getFrameDuration());
|
||||
@ -659,6 +678,9 @@ namespace MWScript
|
||||
{
|
||||
MWWorld::Ptr ptr = R()(runtime);
|
||||
|
||||
if (!ptr.isInCell())
|
||||
return;
|
||||
|
||||
std::string axis = runtime.getStringLiteral (runtime[0].mInteger);
|
||||
runtime.pop();
|
||||
Interpreter::Type_Float movement = (runtime[0].mFloat*MWBase::Environment::get().getFrameDuration());
|
||||
|
@ -252,7 +252,7 @@ namespace MWSound
|
||||
float basevol = volumeFromType(Play_TypeVoice);
|
||||
std::string filePath = "Sound/"+filename;
|
||||
const ESM::Position &pos = ptr.getRefData().getPosition();
|
||||
const Ogre::Vector3 objpos(pos.pos[0], pos.pos[1], pos.pos[2]);
|
||||
const Ogre::Vector3 objpos(pos.pos);
|
||||
|
||||
MWBase::SoundPtr sound = mOutput->playSound3D(filePath, objpos, 1.0f, basevol, 1.0f,
|
||||
20.0f, 12750.0f, Play_Normal|Play_TypeVoice, 0);
|
||||
@ -354,7 +354,7 @@ namespace MWSound
|
||||
float min, max;
|
||||
std::string file = lookup(soundId, volume, min, max);
|
||||
const ESM::Position &pos = ptr.getRefData().getPosition();
|
||||
const Ogre::Vector3 objpos(pos.pos[0], pos.pos[1], pos.pos[2]);
|
||||
const Ogre::Vector3 objpos(pos.pos);
|
||||
|
||||
sound = mOutput->playSound3D(file, objpos, volume, basevol, pitch, min, max, mode|type, offset);
|
||||
if((mode&Play_NoTrack))
|
||||
@ -584,7 +584,7 @@ namespace MWSound
|
||||
if(!ptr.isEmpty())
|
||||
{
|
||||
const ESM::Position &pos = ptr.getRefData().getPosition();
|
||||
const Ogre::Vector3 objpos(pos.pos[0], pos.pos[1], pos.pos[2]);
|
||||
const Ogre::Vector3 objpos(pos.pos);
|
||||
snditer->first->setPosition(objpos);
|
||||
}
|
||||
//update fade out
|
||||
|
@ -4,7 +4,7 @@
|
||||
#include <vector>
|
||||
#include <string>
|
||||
|
||||
#include "refdata.hpp"
|
||||
#include "ptr.hpp"
|
||||
|
||||
namespace ESM
|
||||
{
|
||||
@ -18,13 +18,13 @@ namespace MWWorld
|
||||
{
|
||||
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)
|
||||
mHandles.push_back (handle);
|
||||
|
||||
data.setBaseNode(0);
|
||||
ptr.getRefData().setBaseNode(0);
|
||||
return true;
|
||||
}
|
||||
};
|
||||
|
@ -143,7 +143,7 @@ namespace MWWorld
|
||||
{
|
||||
if (!iter->mData.getCount())
|
||||
continue;
|
||||
if (!functor (iter->mRef, iter->mData))
|
||||
if (!functor (MWWorld::Ptr(&*iter, this)))
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
|
@ -290,6 +290,8 @@ namespace MWWorld
|
||||
|
||||
virtual bool isPersistent (const MWWorld::Ptr& ptr) const;
|
||||
|
||||
virtual bool isKey (const MWWorld::Ptr& ptr) const { return false; }
|
||||
|
||||
virtual Ptr
|
||||
copyToCell(const Ptr &ptr, CellStore &cell) const;
|
||||
|
||||
|
@ -577,10 +577,28 @@ namespace MWWorld
|
||||
|
||||
float oldHeight = iter->first.getRefData().getPosition().pos[2];
|
||||
|
||||
bool waterCollision = false;
|
||||
if (iter->first.getClass().getCreatureStats(iter->first).getMagicEffects()
|
||||
.get(ESM::MagicEffect::WaterWalking).mMagnitude
|
||||
&& cell->hasWater()
|
||||
&& !world->isUnderwater(iter->first.getCell(),
|
||||
Ogre::Vector3(iter->first.getRefData().getPosition().pos)))
|
||||
waterCollision = true;
|
||||
|
||||
btStaticPlaneShape planeShape(btVector3(0,0,1), waterlevel);
|
||||
btCollisionObject object;
|
||||
object.setCollisionShape(&planeShape);
|
||||
|
||||
if (waterCollision)
|
||||
mEngine->dynamicsWorld->addCollisionObject(&object);
|
||||
|
||||
Ogre::Vector3 newpos = MovementSolver::move(iter->first, iter->second, mTimeAccum,
|
||||
world->isFlying(iter->first),
|
||||
waterlevel, mEngine);
|
||||
|
||||
if (waterCollision)
|
||||
mEngine->dynamicsWorld->removeCollisionObject(&object);
|
||||
|
||||
float heightDiff = newpos.z - oldHeight;
|
||||
|
||||
if (heightDiff < 0)
|
||||
|
@ -21,7 +21,8 @@ namespace MWWorld
|
||||
mLastKnownExteriorPosition(0,0,0),
|
||||
mAutoMove(false),
|
||||
mForwardBackward (0),
|
||||
mTeleported(false)
|
||||
mTeleported(false),
|
||||
mMarkedCell(NULL)
|
||||
{
|
||||
mPlayer.mBase = player;
|
||||
mPlayer.mRef.mRefID = "player";
|
||||
@ -157,4 +158,17 @@ namespace MWWorld
|
||||
{
|
||||
mTeleported = teleported;
|
||||
}
|
||||
|
||||
void Player::markPosition(CellStore *markedCell, ESM::Position markedPosition)
|
||||
{
|
||||
mMarkedCell = markedCell;
|
||||
mMarkedPosition = markedPosition;
|
||||
}
|
||||
|
||||
void Player::getMarkedPosition(CellStore*& markedCell, ESM::Position &markedPosition) const
|
||||
{
|
||||
markedCell = mMarkedCell;
|
||||
if (mMarkedCell)
|
||||
markedPosition = mMarkedPosition;
|
||||
}
|
||||
}
|
||||
|
@ -32,6 +32,10 @@ namespace MWWorld
|
||||
|
||||
Ogre::Vector3 mLastKnownExteriorPosition;
|
||||
|
||||
ESM::Position mMarkedPosition;
|
||||
// If no position was marked, this is NULL
|
||||
CellStore* mMarkedCell;
|
||||
|
||||
bool mAutoMove;
|
||||
int mForwardBackward;
|
||||
bool mTeleported;
|
||||
@ -39,6 +43,10 @@ namespace MWWorld
|
||||
|
||||
Player(const ESM::NPC *player, const MWBase::World& world);
|
||||
|
||||
// For mark/recall magic effects
|
||||
void markPosition (CellStore* markedCell, ESM::Position markedPosition);
|
||||
void getMarkedPosition (CellStore*& markedCell, ESM::Position& markedPosition) const;
|
||||
|
||||
/// Interiors can not always be mapped to a world position. However
|
||||
/// world position is still required for divine / almsivi magic effects
|
||||
/// and the player arrow on the global map.
|
||||
|
@ -796,32 +796,9 @@ namespace MWWorld
|
||||
|
||||
MWWorld::Ptr World::getFacedObject()
|
||||
{
|
||||
std::pair<float, std::string> result;
|
||||
|
||||
if (!mRendering->occlusionQuerySupported())
|
||||
result = mPhysics->getFacedHandle (getMaxActivationDistance ());
|
||||
else
|
||||
result = std::make_pair (mFacedDistance, mFacedHandle);
|
||||
|
||||
if (result.second.empty())
|
||||
return MWWorld::Ptr ();
|
||||
|
||||
MWWorld::Ptr object = searchPtrViaHandle (result.second);
|
||||
if (object.isEmpty())
|
||||
return object;
|
||||
float ActivationDistance;
|
||||
|
||||
if (MWBase::Environment::get().getWindowManager()->isConsoleMode())
|
||||
ActivationDistance = getObjectActivationDistance ()*50;
|
||||
else if (object.getTypeName ().find("NPC") != std::string::npos)
|
||||
ActivationDistance = getNpcActivationDistance ();
|
||||
else
|
||||
ActivationDistance = getObjectActivationDistance ();
|
||||
|
||||
if (result.first > ActivationDistance)
|
||||
return MWWorld::Ptr ();
|
||||
|
||||
return object;
|
||||
if (mFacedHandle.empty())
|
||||
return MWWorld::Ptr();
|
||||
return searchPtrViaHandle(mFacedHandle);
|
||||
}
|
||||
|
||||
std::pair<MWWorld::Ptr,Ogre::Vector3> World::getHitContact(const MWWorld::Ptr &ptr, float distance)
|
||||
@ -934,7 +911,7 @@ namespace MWWorld
|
||||
ptr.getRefData().setCount(0);
|
||||
}
|
||||
}
|
||||
if (haveToMove)
|
||||
if (haveToMove && ptr.getRefData().getBaseNode())
|
||||
{
|
||||
mRendering->moveObject(ptr, vec);
|
||||
mPhysics->moveObject (ptr);
|
||||
@ -1063,7 +1040,7 @@ namespace MWWorld
|
||||
|
||||
void World::adjustPosition(const Ptr &ptr)
|
||||
{
|
||||
Ogre::Vector3 pos (ptr.getRefData().getPosition().pos[0], ptr.getRefData().getPosition().pos[1], ptr.getRefData().getPosition().pos[2]);
|
||||
Ogre::Vector3 pos (ptr.getRefData().getPosition().pos);
|
||||
|
||||
if(!ptr.getRefData().getBaseNode())
|
||||
{
|
||||
@ -1304,7 +1281,7 @@ namespace MWWorld
|
||||
if (mPlayer->getPlayer().getCell()->isExterior())
|
||||
{
|
||||
ESM::Position pos = mPlayer->getPlayer().getRefData().getPosition();
|
||||
mPlayer->setLastKnownExteriorPosition(Ogre::Vector3(pos.pos[0], pos.pos[1], pos.pos[2]));
|
||||
mPlayer->setLastKnownExteriorPosition(Ogre::Vector3(pos.pos));
|
||||
}
|
||||
}
|
||||
|
||||
@ -1346,6 +1323,14 @@ namespace MWWorld
|
||||
|
||||
void World::updateFacedHandle ()
|
||||
{
|
||||
float telekinesisRangeBonus =
|
||||
mPlayer->getPlayer().getClass().getCreatureStats(mPlayer->getPlayer()).getMagicEffects()
|
||||
.get(ESM::MagicEffect::Telekinesis).mMagnitude;
|
||||
telekinesisRangeBonus = feetToGameUnits(telekinesisRangeBonus);
|
||||
|
||||
float activationDistance = getMaxActivationDistance() + telekinesisRangeBonus;
|
||||
activationDistance += mRendering->getCameraDistance();
|
||||
|
||||
// send new query
|
||||
// figure out which object we want to test against
|
||||
std::vector < std::pair < float, std::string > > results;
|
||||
@ -1353,13 +1338,13 @@ namespace MWWorld
|
||||
{
|
||||
float x, y;
|
||||
MWBase::Environment::get().getWindowManager()->getMousePosition(x, y);
|
||||
results = mPhysics->getFacedHandles(x, y, getMaxActivationDistance ());
|
||||
results = mPhysics->getFacedHandles(x, y, activationDistance);
|
||||
if (MWBase::Environment::get().getWindowManager()->isConsoleMode())
|
||||
results = mPhysics->getFacedHandles(x, y, getMaxActivationDistance ()*50);
|
||||
}
|
||||
else
|
||||
{
|
||||
results = mPhysics->getFacedHandles(getMaxActivationDistance ());
|
||||
results = mPhysics->getFacedHandles(activationDistance);
|
||||
}
|
||||
|
||||
// ignore the player and other things we're not interested in
|
||||
@ -1442,10 +1427,8 @@ namespace MWWorld
|
||||
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;
|
||||
CellRefList<ESM::Door>::List& refList = doors.mList;
|
||||
for (CellRefList<ESM::Door>::List::iterator it = refList.begin(); it != refList.end(); ++it)
|
||||
@ -1461,11 +1444,9 @@ namespace MWWorld
|
||||
|
||||
newMarker.x = pos.pos[0];
|
||||
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)
|
||||
@ -1588,7 +1569,7 @@ namespace MWWorld
|
||||
pos.rot[1] = 0;
|
||||
|
||||
Ogre::Vector3 orig =
|
||||
Ogre::Vector3(pos.pos[0], pos.pos[1], pos.pos[2]);
|
||||
Ogre::Vector3(pos.pos);
|
||||
Ogre::Vector3 dir = Ogre::Vector3(0, 0, -1);
|
||||
|
||||
float len = (pos.pos[2] >= 0) ? pos.pos[2] : -pos.pos[2];
|
||||
@ -1829,9 +1810,9 @@ namespace MWWorld
|
||||
{
|
||||
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)
|
||||
mHandles.push_back(handle->getName());
|
||||
return true;
|
||||
@ -1940,17 +1921,8 @@ namespace MWWorld
|
||||
int y = ext->getGridY();
|
||||
indexToPosition(x, y, pos.pos[0], pos.pos[1], true);
|
||||
|
||||
ESM::Land* land = getStore().get<ESM::Land>().search(x, y);
|
||||
if (land) {
|
||||
if (!land->isDataLoaded(ESM::Land::DATA_VHGT)) {
|
||||
land->loadData(ESM::Land::DATA_VHGT);
|
||||
}
|
||||
pos.pos[2] = land->mLandData->mHeights[ESM::Land::LAND_NUM_VERTS / 2 + 1];
|
||||
}
|
||||
else {
|
||||
std::cerr << "Land data for cell at (" << x << ", " << y << ") not found\n";
|
||||
pos.pos[2] = 0;
|
||||
}
|
||||
// Note: Z pos will be adjusted by adjustPosition later
|
||||
pos.pos[2] = 0;
|
||||
|
||||
return true;
|
||||
}
|
||||
@ -2312,7 +2284,7 @@ namespace MWWorld
|
||||
if (ref.mRef.mTeleport && ref.mRef.mDestCell.empty())
|
||||
{
|
||||
ESM::Position pos = ref.mRef.mDoorDest;
|
||||
result = Ogre::Vector3(pos.pos[0], pos.pos[1], pos.pos[2]);
|
||||
result = Ogre::Vector3(pos.pos);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
@ -2333,7 +2305,7 @@ namespace MWWorld
|
||||
for (std::vector<MWWorld::Ptr>::iterator it = markers.begin(); it != markers.end(); ++it)
|
||||
{
|
||||
ESM::Position pos = it->getRefData().getPosition();
|
||||
Ogre::Vector3 markerPos = Ogre::Vector3(pos.pos[0], pos.pos[1], pos.pos[2]);
|
||||
Ogre::Vector3 markerPos = Ogre::Vector3(pos.pos);
|
||||
float distance = worldPos.squaredDistance(markerPos);
|
||||
if (distance < closestDistance)
|
||||
{
|
||||
@ -2357,4 +2329,91 @@ namespace MWWorld
|
||||
|
||||
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;
|
||||
|
||||
dist = feetToGameUnits(dist);
|
||||
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
float World::feetToGameUnits(float feet)
|
||||
{
|
||||
// Looks like there is no GMST for this. This factor was determined in experiments
|
||||
// with the Telekinesis effect.
|
||||
return feet * 22;
|
||||
}
|
||||
}
|
||||
|
@ -155,6 +155,8 @@ namespace MWWorld
|
||||
/// Called when \a object is moved to an inactive cell
|
||||
void objectLeftActiveCell (MWWorld::Ptr object, MWWorld::Ptr movedPtr);
|
||||
|
||||
float feetToGameUnits(float feet);
|
||||
|
||||
public:
|
||||
|
||||
World (OEngine::Render::OgreRenderer& renderer,
|
||||
@ -202,7 +204,7 @@ namespace MWWorld
|
||||
virtual Ogre::Vector2 getNorthVector (CellStore* 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
|
||||
|
||||
virtual void getInteriorMapPosition (Ogre::Vector2 position, float& nX, float& nY, int &x, int& y);
|
||||
@ -526,6 +528,12 @@ namespace MWWorld
|
||||
/// @note id must be lower case
|
||||
virtual void teleportToClosestMarker (const MWWorld::Ptr& ptr,
|
||||
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);
|
||||
};
|
||||
}
|
||||
|
||||
|
@ -20,7 +20,7 @@ namespace ESM
|
||||
public:
|
||||
|
||||
int mRefnum; // Reference number
|
||||
std::string mRefID; // ID of object being referenced
|
||||
std::string mRefID; // ID of object being referenced (must be lowercase)
|
||||
|
||||
float mScale; // Scale applied to mesh
|
||||
|
||||
@ -89,4 +89,4 @@ namespace ESM
|
||||
};
|
||||
}
|
||||
|
||||
#endif
|
||||
#endif
|
||||
|
@ -1,46 +0,0 @@
|
||||
#include "CMotionState.h"
|
||||
#include "physic.hpp"
|
||||
|
||||
#include <btBulletDynamicsCommon.h>
|
||||
#include <btBulletCollisionCommon.h>
|
||||
#include <components/nifbullet/bulletnifloader.hpp>
|
||||
|
||||
namespace OEngine {
|
||||
namespace Physic
|
||||
{
|
||||
|
||||
CMotionState::CMotionState(PhysicEngine* eng,std::string name)
|
||||
: isPC(false)
|
||||
, isNPC(true)
|
||||
{
|
||||
pEng = eng;
|
||||
tr.setIdentity();
|
||||
pName = name;
|
||||
}
|
||||
|
||||
void CMotionState::getWorldTransform(btTransform &worldTrans) const
|
||||
{
|
||||
worldTrans = tr;
|
||||
}
|
||||
|
||||
void CMotionState::setWorldTransform(const btTransform &worldTrans)
|
||||
{
|
||||
tr = worldTrans;
|
||||
|
||||
PhysicEvent evt;
|
||||
evt.isNPC = isNPC;
|
||||
evt.isPC = isPC;
|
||||
evt.newTransform = tr;
|
||||
evt.RigidBodyName = pName;
|
||||
|
||||
if(isPC)
|
||||
{
|
||||
pEng->PEventList.push_back(evt);
|
||||
}
|
||||
else
|
||||
{
|
||||
pEng->NPEventList.push_back(evt);
|
||||
}
|
||||
}
|
||||
|
||||
}}
|
@ -1,52 +0,0 @@
|
||||
#ifndef OENGINE_CMOTIONSTATE_H
|
||||
#define OENGINE_CMOTIONSTATE_H
|
||||
|
||||
#include <BulletDynamics/Dynamics/btRigidBody.h>
|
||||
#include <string>
|
||||
|
||||
namespace OEngine {
|
||||
namespace Physic
|
||||
{
|
||||
class PhysicEngine;
|
||||
|
||||
/**
|
||||
* A CMotionState is associated with a single RigidBody.
|
||||
* When the RigidBody is moved by bullet, bullet will call the function setWorldTransform.
|
||||
* for more info, see the bullet Wiki at btMotionState.
|
||||
*/
|
||||
class CMotionState:public btMotionState
|
||||
{
|
||||
public:
|
||||
|
||||
CMotionState(PhysicEngine* eng,std::string name);
|
||||
|
||||
/**
|
||||
* Return the position of the RigidBody.
|
||||
*/
|
||||
virtual void getWorldTransform(btTransform &worldTrans) const;
|
||||
|
||||
/**
|
||||
* Function called by bullet when the RigidBody is moved.
|
||||
* It add an event to the EventList of the PhysicEngine class.
|
||||
*/
|
||||
virtual void setWorldTransform(const btTransform &worldTrans);
|
||||
|
||||
protected:
|
||||
PhysicEngine* pEng;
|
||||
btTransform tr;
|
||||
bool isNPC;
|
||||
bool isPC;
|
||||
|
||||
std::string pName;
|
||||
};
|
||||
|
||||
struct PhysicEvent
|
||||
{
|
||||
bool isNPC;
|
||||
bool isPC;
|
||||
btTransform newTransform;
|
||||
std::string RigidBodyName;
|
||||
};
|
||||
|
||||
}}
|
||||
#endif
|
@ -3,7 +3,6 @@
|
||||
#include <btBulletCollisionCommon.h>
|
||||
#include <BulletCollision/CollisionShapes/btHeightfieldTerrainShape.h>
|
||||
#include <components/nifbullet/bulletnifloader.hpp>
|
||||
#include "CMotionState.h"
|
||||
#include "OgreRoot.h"
|
||||
#include "btKinematicCharacterController.h"
|
||||
#include "BtOgrePG.h"
|
||||
@ -318,9 +317,7 @@ namespace Physic
|
||||
btVector3 scl(triSize, triSize, 1);
|
||||
hfShape->setLocalScaling(scl);
|
||||
|
||||
CMotionState* newMotionState = new CMotionState(this,name);
|
||||
|
||||
btRigidBody::btRigidBodyConstructionInfo CI = btRigidBody::btRigidBodyConstructionInfo(0,newMotionState,hfShape);
|
||||
btRigidBody::btRigidBodyConstructionInfo CI = btRigidBody::btRigidBodyConstructionInfo(0,0,hfShape);
|
||||
RigidBody* body = new RigidBody(CI,name);
|
||||
body->getWorldTransform().setOrigin(btVector3( (x+0.5)*triSize*(sqrtVerts-1), (y+0.5)*triSize*(sqrtVerts-1), (maxh+minh)/2.f));
|
||||
|
||||
@ -401,12 +398,9 @@ namespace Physic
|
||||
else
|
||||
shape->mRaycastingShape->setLocalScaling( btVector3(scale,scale,scale));
|
||||
|
||||
//create the motionState
|
||||
CMotionState* newMotionState = new CMotionState(this,name);
|
||||
|
||||
//create the real body
|
||||
btRigidBody::btRigidBodyConstructionInfo CI = btRigidBody::btRigidBodyConstructionInfo
|
||||
(0,newMotionState, raycasting ? shape->mRaycastingShape : shape->mCollisionShape);
|
||||
(0,0, raycasting ? shape->mRaycastingShape : shape->mCollisionShape);
|
||||
RigidBody* body = new RigidBody(CI,name);
|
||||
body->mPlaceable = placeable;
|
||||
|
||||
|
@ -38,7 +38,6 @@ namespace MWWorld
|
||||
namespace OEngine {
|
||||
namespace Physic
|
||||
{
|
||||
class CMotionState;
|
||||
struct PhysicEvent;
|
||||
class PhysicEngine;
|
||||
class RigidBody;
|
||||
@ -157,17 +156,7 @@ namespace Physic
|
||||
private:
|
||||
void disableCollisionBody();
|
||||
void enableCollisionBody();
|
||||
public:
|
||||
//HACK: in Visual Studio 2010 and presumably above, this structures alignment
|
||||
// must be 16, but the built in operator new & delete don't properly
|
||||
// perform this alignment.
|
||||
#if _MSC_VER >= 1600
|
||||
void * operator new (size_t Size) { return _aligned_malloc (Size, 16); }
|
||||
void operator delete (void * Data) { _aligned_free (Data); }
|
||||
#endif
|
||||
|
||||
|
||||
private:
|
||||
OEngine::Physic::RigidBody* mBody;
|
||||
OEngine::Physic::RigidBody* mRaycastingBody;
|
||||
|
||||
@ -329,12 +318,6 @@ public:
|
||||
const btVector3 &origin,
|
||||
btCollisionObject *object);
|
||||
|
||||
//event list of non player object
|
||||
std::list<PhysicEvent> NPEventList;
|
||||
|
||||
//event list affecting the player
|
||||
std::list<PhysicEvent> PEventList;
|
||||
|
||||
//Bullet Stuff
|
||||
btOverlappingPairCache* pairCache;
|
||||
btBroadphaseInterface* broadphase;
|
||||
|
@ -25,7 +25,8 @@ void OgreRenderer::cleanup()
|
||||
delete mFader;
|
||||
mFader = NULL;
|
||||
|
||||
Ogre::Root::getSingleton().destroyRenderTarget(mWindow);
|
||||
if (mWindow)
|
||||
Ogre::Root::getSingleton().destroyRenderTarget(mWindow);
|
||||
mWindow = NULL;
|
||||
|
||||
delete mOgreInit;
|
||||
|
Loading…
x
Reference in New Issue
Block a user