From d4b7b3e999a05cd26a5eaaf63406c64c3eae3e90 Mon Sep 17 00:00:00 2001 From: elsid Date: Sun, 25 Aug 2019 18:11:13 +0200 Subject: [PATCH 01/33] Check for AiPackage type before find nearby door --- apps/openmw/mwmechanics/aipackage.cpp | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/apps/openmw/mwmechanics/aipackage.cpp b/apps/openmw/mwmechanics/aipackage.cpp index 646b37669..97523f2d6 100644 --- a/apps/openmw/mwmechanics/aipackage.cpp +++ b/apps/openmw/mwmechanics/aipackage.cpp @@ -224,6 +224,10 @@ void MWMechanics::AiPackage::evadeObstacles(const MWWorld::Ptr& actor) void MWMechanics::AiPackage::openDoors(const MWWorld::Ptr& actor) { + // note: AiWander currently does not open doors + if (getTypeId() == TypeIdWander) + return; + MWBase::World* world = MWBase::Environment::get().getWorld(); static float distance = world->getMaxActivationDistance(); @@ -231,8 +235,7 @@ void MWMechanics::AiPackage::openDoors(const MWWorld::Ptr& actor) if (door == MWWorld::Ptr()) return; - // note: AiWander currently does not open doors - if (getTypeId() != TypeIdWander && !door.getCellRef().getTeleport() && door.getClass().getDoorState(door) == MWWorld::DoorState::Idle) + if (!door.getCellRef().getTeleport() && door.getClass().getDoorState(door) == MWWorld::DoorState::Idle) { if ((door.getCellRef().getTrap().empty() && door.getCellRef().getLockLevel() <= 0 )) { From 653a3910843a9e65e17b27630824a82ba710fc1b Mon Sep 17 00:00:00 2001 From: elsid Date: Sun, 25 Aug 2019 13:49:04 +0200 Subject: [PATCH 02/33] Do not open doors when actor has no path When actor is not going anywhere it doesn't require to go through doors so there is no need to open them. --- apps/openmw/mwmechanics/aipackage.cpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/apps/openmw/mwmechanics/aipackage.cpp b/apps/openmw/mwmechanics/aipackage.cpp index 97523f2d6..ef22d986a 100644 --- a/apps/openmw/mwmechanics/aipackage.cpp +++ b/apps/openmw/mwmechanics/aipackage.cpp @@ -228,6 +228,9 @@ void MWMechanics::AiPackage::openDoors(const MWWorld::Ptr& actor) if (getTypeId() == TypeIdWander) return; + if (mPathFinder.getPathSize() == 0) + return; + MWBase::World* world = MWBase::Environment::get().getWorld(); static float distance = world->getMaxActivationDistance(); From 209e33f5ceb778574aba3c304d6e43ca81d0adac Mon Sep 17 00:00:00 2001 From: elsid Date: Thu, 15 Aug 2019 19:19:04 +0200 Subject: [PATCH 03/33] Open door when it is on the way to a next path point --- apps/openmw/mwbase/world.hpp | 2 ++ apps/openmw/mwmechanics/aipackage.cpp | 18 ++++++++++++++++++ apps/openmw/mwworld/worldimp.cpp | 20 ++++++++++++++++++++ apps/openmw/mwworld/worldimp.hpp | 2 ++ 4 files changed, 42 insertions(+) diff --git a/apps/openmw/mwbase/world.hpp b/apps/openmw/mwbase/world.hpp index 955e77168..8c6829eb3 100644 --- a/apps/openmw/mwbase/world.hpp +++ b/apps/openmw/mwbase/world.hpp @@ -614,6 +614,8 @@ namespace MWBase /// Return physical half extents of the given actor to be used in pathfinding virtual osg::Vec3f getPathfindingHalfExtents(const MWWorld::ConstPtr& actor) const = 0; + + virtual bool hasCollisionWithDoor(const MWWorld::ConstPtr& door, const osg::Vec3f& position, const osg::Vec3f& destination) const = 0; }; } diff --git a/apps/openmw/mwmechanics/aipackage.cpp b/apps/openmw/mwmechanics/aipackage.cpp index ef22d986a..61538fb60 100644 --- a/apps/openmw/mwmechanics/aipackage.cpp +++ b/apps/openmw/mwmechanics/aipackage.cpp @@ -13,6 +13,8 @@ #include "../mwworld/cellstore.hpp" #include "../mwworld/inventorystore.hpp" +#include "../mwphysics/collisiontype.hpp" + #include "pathgrid.hpp" #include "creaturestats.hpp" #include "movement.hpp" @@ -222,6 +224,19 @@ void MWMechanics::AiPackage::evadeObstacles(const MWWorld::Ptr& actor) } } +namespace +{ + bool isDoorOnTheWay(const MWWorld::Ptr& actor, const MWWorld::Ptr& door, const osg::Vec3f& nextPathPoint) + { + const auto world = MWBase::Environment::get().getWorld(); + const auto halfExtents = world->getHalfExtents(actor); + const auto position = actor.getRefData().getPosition().asVec3() + osg::Vec3f(0, 0, halfExtents.z()); + const auto destination = nextPathPoint + osg::Vec3f(0, 0, halfExtents.z()); + + return world->hasCollisionWithDoor(door, position, destination); + } +} + void MWMechanics::AiPackage::openDoors(const MWWorld::Ptr& actor) { // note: AiWander currently does not open doors @@ -240,6 +255,9 @@ void MWMechanics::AiPackage::openDoors(const MWWorld::Ptr& actor) if (!door.getCellRef().getTeleport() && door.getClass().getDoorState(door) == MWWorld::DoorState::Idle) { + if (!isDoorOnTheWay(actor, door, mPathFinder.getPath().front())) + return; + if ((door.getCellRef().getTrap().empty() && door.getCellRef().getLockLevel() <= 0 )) { world->activate(door, actor); diff --git a/apps/openmw/mwworld/worldimp.cpp b/apps/openmw/mwworld/worldimp.cpp index 07680e76f..5c3bab9c3 100644 --- a/apps/openmw/mwworld/worldimp.cpp +++ b/apps/openmw/mwworld/worldimp.cpp @@ -15,6 +15,7 @@ #include #include #include +#include #include @@ -3851,4 +3852,23 @@ namespace MWWorld return getHalfExtents(actor); } + bool World::hasCollisionWithDoor(const MWWorld::ConstPtr& door, const osg::Vec3f& position, const osg::Vec3f& destination) const + { + const auto object = mPhysics->getObject(door); + + if (!object) + return false; + + btVector3 aabbMin; + btVector3 aabbMax; + object->getShapeInstance()->getCollisionShape()->getAabb(btTransform::getIdentity(), aabbMin, aabbMax); + + const auto toLocal = object->getCollisionObject()->getWorldTransform().inverse(); + const auto localFrom = toLocal(Misc::Convert::toBullet(position)); + const auto localTo = toLocal(Misc::Convert::toBullet(destination)); + + btScalar hitDistance = 1; + btVector3 hitNormal; + return btRayAabb(localFrom, localTo, aabbMin, aabbMax, hitDistance, hitNormal); + } } diff --git a/apps/openmw/mwworld/worldimp.hpp b/apps/openmw/mwworld/worldimp.hpp index 76d015477..bd34087ac 100644 --- a/apps/openmw/mwworld/worldimp.hpp +++ b/apps/openmw/mwworld/worldimp.hpp @@ -719,6 +719,8 @@ namespace MWWorld /// Return physical half extents of the given actor to be used in pathfinding osg::Vec3f getPathfindingHalfExtents(const MWWorld::ConstPtr& actor) const override; + + bool hasCollisionWithDoor(const MWWorld::ConstPtr& door, const osg::Vec3f& position, const osg::Vec3f& destination) const override; }; } From aeb0ccff90bbb6655dab2ad08b1a70d859dc25f8 Mon Sep 17 00:00:00 2001 From: Nelsson Huotari Date: Mon, 4 Nov 2019 12:16:08 +0200 Subject: [PATCH 04/33] Allow selecting cell edges everywhere --- apps/opencs/view/render/terrainshapemode.cpp | 23 ++++++++++++++++---- apps/opencs/view/render/terrainshapemode.hpp | 3 +++ 2 files changed, 22 insertions(+), 4 deletions(-) diff --git a/apps/opencs/view/render/terrainshapemode.cpp b/apps/opencs/view/render/terrainshapemode.cpp index af97e4d8f..d7b4684d6 100644 --- a/apps/opencs/view/render/terrainshapemode.cpp +++ b/apps/opencs/view/render/terrainshapemode.cpp @@ -1038,6 +1038,21 @@ bool CSVRender::TerrainShapeMode::isInCellSelection(int globalSelectionX, int gl return false; } +void CSVRender::TerrainShapeMode::handleSelection(int globalSelectionX, int globalSelectionY, std::vector>* selections) +{ + if (isInCellSelection(globalSelectionX, globalSelectionY)) selections->emplace_back(globalSelectionX, globalSelectionY); + else + { + int moduloX = globalSelectionX % (ESM::Land::LAND_SIZE - 1); + int moduloY = globalSelectionY % (ESM::Land::LAND_SIZE - 1); + bool xIsAtCellBorder = moduloX == 0; + bool yIsAtCellBorder = moduloY == 0; + if (isInCellSelection(globalSelectionX - 1, globalSelectionY) && xIsAtCellBorder && !yIsAtCellBorder) selections->emplace_back(globalSelectionX, globalSelectionY); + if (isInCellSelection(globalSelectionX, globalSelectionY - 1) && !xIsAtCellBorder && yIsAtCellBorder) selections->emplace_back(globalSelectionX, globalSelectionY); + if (isInCellSelection(globalSelectionX - 1, globalSelectionY - 1) && xIsAtCellBorder && yIsAtCellBorder) selections->emplace_back(globalSelectionX, globalSelectionY); + } +} + void CSVRender::TerrainShapeMode::selectTerrainShapes(const std::pair& vertexCoords, unsigned char selectMode, bool dragOperation) { int r = mBrushSize / 2; @@ -1045,7 +1060,7 @@ void CSVRender::TerrainShapeMode::selectTerrainShapes(const std::pair& if (mBrushShape == CSVWidget::BrushShape_Point) { - if (isInCellSelection(vertexCoords.first, vertexCoords.second)) selections.emplace_back(vertexCoords.first, vertexCoords.second); + handleSelection(vertexCoords.first, vertexCoords.second, &selections); } if (mBrushShape == CSVWidget::BrushShape_Square) @@ -1054,7 +1069,7 @@ void CSVRender::TerrainShapeMode::selectTerrainShapes(const std::pair& { for(int j = vertexCoords.second - r; j <= vertexCoords.second + r; ++j) { - if (isInCellSelection(i, j)) selections.emplace_back(i, j); + handleSelection(i, j, &selections); } } } @@ -1068,7 +1083,7 @@ void CSVRender::TerrainShapeMode::selectTerrainShapes(const std::pair& int distanceX = abs(i - vertexCoords.first); int distanceY = abs(j - vertexCoords.second); int distance = std::round(sqrt(pow(distanceX, 2)+pow(distanceY, 2))); - if (isInCellSelection(i, j) && distance <= r) selections.emplace_back(i, j); + if (distance <= r) handleSelection(i, j, &selections); } } } @@ -1081,7 +1096,7 @@ void CSVRender::TerrainShapeMode::selectTerrainShapes(const std::pair& { std::pair localVertexCoords (vertexCoords.first + value.first, vertexCoords.second + value.second); std::string cellId (CSMWorld::CellCoordinates::vertexGlobalToCellId(localVertexCoords)); - if (isInCellSelection(localVertexCoords.first, localVertexCoords.second)) selections.emplace_back(localVertexCoords); + handleSelection(localVertexCoords.first, localVertexCoords.second, &selections); } } } diff --git a/apps/opencs/view/render/terrainshapemode.hpp b/apps/opencs/view/render/terrainshapemode.hpp index 605827c9e..ce2ea5465 100644 --- a/apps/opencs/view/render/terrainshapemode.hpp +++ b/apps/opencs/view/render/terrainshapemode.hpp @@ -134,6 +134,9 @@ namespace CSVRender /// Check if global selection coordinate belongs to cell in view bool isInCellSelection(int globalSelectionX, int globalSelectionY); + /// Select vertex at global selection coordinate + void handleSelection(int globalSelectionX, int globalSelectionY, std::vector>* selections); + /// Handle brush mechanics for terrain shape selection void selectTerrainShapes (const std::pair& vertexCoords, unsigned char selectMode, bool dragOperation); From 45d43045eb0032c970e620bdaa3f882378f158c2 Mon Sep 17 00:00:00 2001 From: Nelsson Huotari Date: Mon, 4 Nov 2019 12:29:37 +0200 Subject: [PATCH 05/33] Remove unused std::string --- apps/opencs/view/render/terrainshapemode.cpp | 1 - 1 file changed, 1 deletion(-) diff --git a/apps/opencs/view/render/terrainshapemode.cpp b/apps/opencs/view/render/terrainshapemode.cpp index d7b4684d6..ee6492a87 100644 --- a/apps/opencs/view/render/terrainshapemode.cpp +++ b/apps/opencs/view/render/terrainshapemode.cpp @@ -1095,7 +1095,6 @@ void CSVRender::TerrainShapeMode::selectTerrainShapes(const std::pair& for(auto const& value: mCustomBrushShape) { std::pair localVertexCoords (vertexCoords.first + value.first, vertexCoords.second + value.second); - std::string cellId (CSMWorld::CellCoordinates::vertexGlobalToCellId(localVertexCoords)); handleSelection(localVertexCoords.first, localVertexCoords.second, &selections); } } From bafc0d9e90cd94c4b02588b29bf919f38af8bd16 Mon Sep 17 00:00:00 2001 From: Andrei Kortunov Date: Sat, 9 Nov 2019 12:51:12 +0400 Subject: [PATCH 06/33] Added support for texture fragment usage to the ImageButton --- components/widgets/imagebutton.cpp | 43 +++++++++++++++++++++++++----- components/widgets/imagebutton.hpp | 5 ++++ 2 files changed, 42 insertions(+), 6 deletions(-) diff --git a/components/widgets/imagebutton.cpp b/components/widgets/imagebutton.cpp index 2ea494ebd..0d1f798da 100644 --- a/components/widgets/imagebutton.cpp +++ b/components/widgets/imagebutton.cpp @@ -14,6 +14,8 @@ namespace Gui , mMouseFocus(false) , mMousePress(false) , mKeyFocus(false) + , mUseWholeTexture(true) + , mTextureRect(MyGUI::IntCoord(0, 0, 0, 0)) { setNeedKeyFocus(sDefaultNeedKeyFocus); } @@ -23,6 +25,13 @@ namespace Gui sDefaultNeedKeyFocus = enabled; } + void ImageButton::setTextureRect(MyGUI::IntCoord coord) + { + mTextureRect = coord; + mUseWholeTexture = (coord == MyGUI::IntCoord(0, 0, 0, 0)); + updateImage(); + } + void ImageButton::setPropertyOverride(const std::string &_key, const std::string &_value) { if (_key == "ImageHighlighted") @@ -37,6 +46,11 @@ namespace Gui } mImageNormal = _value; } + else if (_key == "TextureRect") + { + mTextureRect = MyGUI::IntCoord::parse(_value); + mUseWholeTexture = (mTextureRect == MyGUI::IntCoord(0, 0, 0, 0)); + } else ImageBox::setPropertyOverride(_key, _value); } @@ -66,12 +80,25 @@ namespace Gui void ImageButton::updateImage() { + std::string textureName = mImageNormal; if (mMousePress) - setImageTexture(mImagePushed); + textureName = mImagePushed; else if (mMouseFocus || mKeyFocus) - setImageTexture(mImageHighlighted); - else - setImageTexture(mImageNormal); + textureName = mImageHighlighted; + + if (!mUseWholeTexture) + { + int scale = 1.f; + MyGUI::ITexture* texture = MyGUI::RenderManager::getInstance().getTexture(textureName); + if (texture && getHeight() != 0) + scale = texture->getHeight() / getHeight(); + + setImageTile(MyGUI::IntSize(mTextureRect.width * scale, mTextureRect.height * scale)); + MyGUI::IntCoord scaledSize(mTextureRect.left * scale, mTextureRect.top * scale, mTextureRect.width * scale, mTextureRect.height * scale); + setImageCoord(scaledSize); + } + + setImageTexture(textureName); } MyGUI::IntSize ImageButton::getRequestedSize() @@ -82,7 +109,11 @@ namespace Gui Log(Debug::Error) << "ImageButton: can't find image " << mImageNormal; return MyGUI::IntSize(0,0); } - return MyGUI::IntSize (texture->getWidth(), texture->getHeight()); + + if (mUseWholeTexture) + return MyGUI::IntSize(texture->getWidth(), texture->getHeight()); + + return MyGUI::IntSize(mTextureRect.width, mTextureRect.height); } void ImageButton::setImage(const std::string &image) @@ -96,7 +127,7 @@ namespace Gui mImageHighlighted = imageNoExt + "_over" + ext; mImagePushed = imageNoExt + "_pressed" + ext; - setImageTexture(mImageNormal); + updateImage(); } void ImageButton::onMouseButtonReleased(int _left, int _top, MyGUI::MouseButton _id) diff --git a/components/widgets/imagebutton.hpp b/components/widgets/imagebutton.hpp index bfcff7997..bb2baa91f 100644 --- a/components/widgets/imagebutton.hpp +++ b/components/widgets/imagebutton.hpp @@ -23,6 +23,8 @@ namespace Gui /// Set mImageNormal, mImageHighlighted and mImagePushed based on file convention (image_idle.ext, image_over.ext and image_pressed.ext) void setImage(const std::string& image); + void setTextureRect(MyGUI::IntCoord coord); + private: void updateImage(); @@ -44,6 +46,9 @@ namespace Gui bool mMouseFocus; bool mMousePress; bool mKeyFocus; + bool mUseWholeTexture; + + MyGUI::IntCoord mTextureRect; }; } From bfc07afa28e509bb55316a6aafb1b5b67e8845ab Mon Sep 17 00:00:00 2001 From: Andrei Kortunov Date: Sat, 9 Nov 2019 12:51:59 +0400 Subject: [PATCH 07/33] Restore normal size of quests buttons in journal --- files/mygui/openmw_journal.layout | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/files/mygui/openmw_journal.layout b/files/mygui/openmw_journal.layout index cf81e22e4..3752897f9 100644 --- a/files/mygui/openmw_journal.layout +++ b/files/mygui/openmw_journal.layout @@ -65,12 +65,14 @@ - + + - + + From 6a625b1dac8b08a76611846bb4f5e4e68a9f6ad3 Mon Sep 17 00:00:00 2001 From: Andrei Kortunov Date: Sat, 9 Nov 2019 12:52:38 +0400 Subject: [PATCH 08/33] Scale magic items frames in the quick keys menu --- apps/openmw/mwgui/quickkeysmenu.cpp | 15 +++++++++++++-- files/mygui/openmw_quickkeys_menu.layout | 20 ++++++++++---------- 2 files changed, 23 insertions(+), 12 deletions(-) diff --git a/apps/openmw/mwgui/quickkeysmenu.cpp b/apps/openmw/mwgui/quickkeysmenu.cpp index 6ac1f2b63..e2e2e1ab1 100644 --- a/apps/openmw/mwgui/quickkeysmenu.cpp +++ b/apps/openmw/mwgui/quickkeysmenu.cpp @@ -4,6 +4,7 @@ #include #include #include +#include #include #include @@ -257,7 +258,12 @@ namespace MWGui mSelected->id = item.getCellRef().getRefId(); mSelected->name = item.getClass().getName(item); - mSelected->button->setFrame("textures\\menu_icon_select_magic_magic.dds", MyGUI::IntCoord(2, 2, 40, 40)); + float scale = 1.f; + MyGUI::ITexture* texture = MyGUI::RenderManager::getInstance().getTexture("textures\\menu_icon_select_magic_magic.dds"); + if (texture) + scale = texture->getHeight() / 64.f; + + mSelected->button->setFrame("textures\\menu_icon_select_magic_magic.dds", MyGUI::IntCoord(0, 0, 44*scale, 44*scale)); mSelected->button->setIcon(item); mSelected->button->setUserString("ToolTipType", "ItemPtr"); @@ -292,7 +298,12 @@ namespace MWGui path.insert(slashPos+1, "b_"); path = MWBase::Environment::get().getWindowManager()->correctIconPath(path); - mSelected->button->setFrame("textures\\menu_icon_select_magic.dds", MyGUI::IntCoord(2, 2, 40, 40)); + float scale = 1.f; + MyGUI::ITexture* texture = MyGUI::RenderManager::getInstance().getTexture("textures\\menu_icon_select_magic.dds"); + if (texture) + scale = texture->getHeight() / 64.f; + + mSelected->button->setFrame("textures\\menu_icon_select_magic.dds", MyGUI::IntCoord(0, 0, 44*scale, 44*scale)); mSelected->button->setIcon(path); if (mMagicSelectionDialog) diff --git a/files/mygui/openmw_quickkeys_menu.layout b/files/mygui/openmw_quickkeys_menu.layout index 3371b4f49..27bbbc190 100644 --- a/files/mygui/openmw_quickkeys_menu.layout +++ b/files/mygui/openmw_quickkeys_menu.layout @@ -17,16 +17,16 @@ - - - - - - - - - - + + + + + + + + + + From 1835a39c57c187c3b400b9783fa2bc9315ca3643 Mon Sep 17 00:00:00 2001 From: Andrei Kortunov Date: Sat, 9 Nov 2019 16:45:29 +0400 Subject: [PATCH 09/33] Do not show shields in the 1st-person view when shield sheathing is enabled --- apps/openmw/mwrender/actoranimation.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/openmw/mwrender/actoranimation.cpp b/apps/openmw/mwrender/actoranimation.cpp index 6d7da5d66..71811db68 100644 --- a/apps/openmw/mwrender/actoranimation.cpp +++ b/apps/openmw/mwrender/actoranimation.cpp @@ -113,7 +113,7 @@ bool ActorAnimation::updateCarriedLeftVisible(const int weaptype) const { SceneUtil::FindByNameVisitor findVisitor ("Bip01 AttachShield"); mObjectRoot->accept(findVisitor); - if (findVisitor.mFoundNode) + if (findVisitor.mFoundNode || (mPtr == MWMechanics::getPlayer() && mPtr.isInCell() && MWBase::Environment::get().getWorld()->isFirstPerson())) { const MWWorld::InventoryStore& inv = cls.getInventoryStore(mPtr); const MWWorld::ConstContainerStoreIterator weapon = inv.getSlot(MWWorld::InventoryStore::Slot_CarriedRight); From 51cfd070c64255b2d8818b42c6b3837d2c7d2d94 Mon Sep 17 00:00:00 2001 From: Andrei Kortunov Date: Sat, 9 Nov 2019 21:43:08 +0400 Subject: [PATCH 10/33] Use transformations of NiSwitchNode --- components/nifosg/nifloader.cpp | 32 +++++++++++++++----------------- 1 file changed, 15 insertions(+), 17 deletions(-) diff --git a/components/nifosg/nifloader.cpp b/components/nifosg/nifloader.cpp index f32224ca8..901dccc51 100644 --- a/components/nifosg/nifloader.cpp +++ b/components/nifosg/nifloader.cpp @@ -341,6 +341,7 @@ namespace NifOsg osg::ref_ptr switchNode (new osg::Switch); switchNode->setName(niSwitchNode->name); switchNode->setNewChildDefaultValue(false); + switchNode->setSingleChildOn(niSwitchNode->initialIndex); return switchNode; } @@ -433,7 +434,7 @@ namespace NifOsg osg::ref_ptr node; osg::Object::DataVariance dataVariance = osg::Object::UNSPECIFIED; - // TODO: it is unclear how to handle transformations of LOD and Switch nodes and controllers for them. + // TODO: it is unclear how to handle transformations of LOD nodes and controllers for them. switch (nifNode->recType) { case Nif::RC_NiLODNode: @@ -444,12 +445,6 @@ namespace NifOsg break; } case Nif::RC_NiSwitchNode: - { - const Nif::NiSwitchNode* niSwitchNode = static_cast(nifNode); - node = handleSwitchNode(niSwitchNode); - dataVariance = osg::Object::STATIC; - break; - } case Nif::RC_NiTriShape: case Nif::RC_NiTriStrips: case Nif::RC_NiAutoNormalParticles: @@ -625,6 +620,19 @@ namespace NifOsg && !nifNode->controller.empty() && node->getDataVariance() == osg::Object::DYNAMIC) handleNodeControllers(nifNode, static_cast(node.get()), animflags); + if (nifNode->recType == Nif::RC_NiSwitchNode) + { + const Nif::NiSwitchNode* niSwitchNode = static_cast(nifNode); + osg::ref_ptr switchNode = handleSwitchNode(niSwitchNode); + node->addChild(switchNode); + if (niSwitchNode->name == Constants::NightDayLabel && !SceneUtil::hasUserDescription(rootNode, Constants::NightDayLabel)) + rootNode->getOrCreateUserDataContainer()->addDescription(Constants::NightDayLabel); + else if (niSwitchNode->name == Constants::HerbalismLabel && !SceneUtil::hasUserDescription(rootNode, Constants::HerbalismLabel)) + rootNode->getOrCreateUserDataContainer()->addDescription(Constants::HerbalismLabel); + + node = switchNode; + } + const Nif::NiNode *ninode = dynamic_cast(nifNode); if(ninode) { @@ -643,16 +651,6 @@ namespace NifOsg } } - if (nifNode->recType == Nif::RC_NiSwitchNode) - { - const Nif::NiSwitchNode* niSwitchNode = static_cast(nifNode); - node->asSwitch()->setSingleChildOn(niSwitchNode->initialIndex); - if (niSwitchNode->name == Constants::NightDayLabel && !SceneUtil::hasUserDescription(rootNode, Constants::NightDayLabel)) - rootNode->getOrCreateUserDataContainer()->addDescription(Constants::NightDayLabel); - else if (niSwitchNode->name == Constants::HerbalismLabel && !SceneUtil::hasUserDescription(rootNode, Constants::HerbalismLabel)) - rootNode->getOrCreateUserDataContainer()->addDescription(Constants::HerbalismLabel); - } - return node; } From 9c78e8cc5698af9d17f9fa3eee7bbf4ce3e9384e Mon Sep 17 00:00:00 2001 From: Capostrophic Date: Tue, 12 Nov 2019 17:10:28 +0300 Subject: [PATCH 11/33] Make sure movement not controlled by animation has valid velocity Fixes erroneously always normalized movement speed in first person --- apps/openmw/mwmechanics/character.cpp | 24 +++++++++++++----------- 1 file changed, 13 insertions(+), 11 deletions(-) diff --git a/apps/openmw/mwmechanics/character.cpp b/apps/openmw/mwmechanics/character.cpp index 60da8b27d..e6223ac54 100644 --- a/apps/openmw/mwmechanics/character.cpp +++ b/apps/openmw/mwmechanics/character.cpp @@ -1906,6 +1906,17 @@ void CharacterController::update(float duration, bool animationOnly) bool isPlayer = mPtr == MWMechanics::getPlayer(); bool godmode = isPlayer && MWBase::Environment::get().getWorld()->getGodModeState(); + float scale = mPtr.getCellRef().getScale(); + + static const bool normalizeSpeed = Settings::Manager::getBool("normalise race speed", "Game"); + if (!normalizeSpeed && mPtr.getClass().isNpc()) + { + const ESM::NPC* npc = mPtr.get()->mBase; + const ESM::Race* race = world->getStore().get().find(npc->mRace); + float weight = npc->isMale() ? race->mData.mWeight.mMale : race->mData.mWeight.mFemale; + scale *= weight; + } + if(!cls.isActor()) updateAnimQueue(); else if(!cls.getCreatureStats(mPtr).isDead()) @@ -2132,6 +2143,8 @@ void CharacterController::update(float duration, bool animationOnly) jumpstate = mAnimation->isPlaying(mCurrentJump) ? JumpState_Landing : JumpState_None; + vec.x() *= scale; + vec.y() *= scale; vec.z() = 0.0f; inJump = false; @@ -2322,20 +2335,9 @@ void CharacterController::update(float duration, bool animationOnly) else moved = osg::Vec3f(0.f, 0.f, 0.f); - float scale = mPtr.getCellRef().getScale(); moved.x() *= scale; moved.y() *= scale; - static const bool normalizeSpeed = Settings::Manager::getBool("normalise race speed", "Game"); - if (mPtr.getClass().isNpc() && !normalizeSpeed) - { - const ESM::NPC* npc = mPtr.get()->mBase; - const ESM::Race* race = world->getStore().get().find(npc->mRace); - float weight = npc->isMale() ? race->mData.mWeight.mMale : race->mData.mWeight.mFemale; - moved.x() *= weight; - moved.y() *= weight; - } - // Ensure we're moving in generally the right direction... if(speed > 0.f) { From 1097c2cfc44d4707da1d9ce7b8496192cad21ce8 Mon Sep 17 00:00:00 2001 From: Capostrophic Date: Tue, 12 Nov 2019 17:50:06 +0300 Subject: [PATCH 12/33] Minor summoned creature cleanup fixes --- apps/openmw/mwmechanics/actors.cpp | 7 +++++++ apps/openmw/mwmechanics/summoning.cpp | 25 +++++-------------------- 2 files changed, 12 insertions(+), 20 deletions(-) diff --git a/apps/openmw/mwmechanics/actors.cpp b/apps/openmw/mwmechanics/actors.cpp index 486c8b31b..918c5c303 100644 --- a/apps/openmw/mwmechanics/actors.cpp +++ b/apps/openmw/mwmechanics/actors.cpp @@ -1884,6 +1884,13 @@ namespace MWMechanics if (fx) MWBase::Environment::get().getWorld()->spawnEffect("meshes\\" + fx->mModel, "", ptr.getRefData().getPosition().asVec3()); + + // Remove the summoned creature's summoned creatures as well + MWMechanics::CreatureStats& stats = ptr.getClass().getCreatureStats(ptr); + std::map& creatureMap = stats.getSummonedCreatureMap(); + for (const auto& creature : creatureMap) + cleanupSummonedCreature(stats, creature.second); + creatureMap.clear(); } else if (creatureActorId != -1) { diff --git a/apps/openmw/mwmechanics/summoning.cpp b/apps/openmw/mwmechanics/summoning.cpp index e2cbace70..86d0faa9d 100644 --- a/apps/openmw/mwmechanics/summoning.cpp +++ b/apps/openmw/mwmechanics/summoning.cpp @@ -86,10 +86,9 @@ namespace MWMechanics } // Update summon effects - bool casterDead = creatureStats.isDead(); for (std::map::iterator it = creatureMap.begin(); it != creatureMap.end(); ) { - bool found = !casterDead && mActiveEffects.find(it->first) != mActiveEffects.end(); + bool found = mActiveEffects.find(it->first) != mActiveEffects.end(); if (!found) { // Effect has ended @@ -100,25 +99,11 @@ namespace MWMechanics ++it; } - std::vector& graveyard = creatureStats.getSummonedCreatureGraveyard(); - for (std::vector::iterator it = graveyard.begin(); it != graveyard.end(); ) - { - MWWorld::Ptr ptr = MWBase::Environment::get().getWorld()->searchPtrViaActorId(*it); - if (!ptr.isEmpty()) - { - it = graveyard.erase(it); + std::vector graveyard = creatureStats.getSummonedCreatureGraveyard(); + creatureStats.getSummonedCreatureGraveyard().clear(); - const ESM::Static* fx = MWBase::Environment::get().getWorld()->getStore().get() - .search("VFX_Summon_End"); - if (fx) - MWBase::Environment::get().getWorld()->spawnEffect("meshes\\" + fx->mModel, - "", ptr.getRefData().getPosition().asVec3()); - - MWBase::Environment::get().getWorld()->deleteObject(ptr); - } - else - ++it; - } + for (const int creature : graveyard) + MWBase::Environment::get().getMechanicsManager()->cleanupSummonedCreature(mActor, creature); if (!cleanup) return; From ae1f456b0a0f0f202b5e6043203fd493617cb1a2 Mon Sep 17 00:00:00 2001 From: Capostrophic Date: Tue, 12 Nov 2019 18:22:18 +0300 Subject: [PATCH 13/33] Default setting value tweaks --- docs/source/reference/modding/settings/shadows.rst | 8 ++++---- docs/source/reference/modding/settings/terrain.rst | 4 ++-- files/settings-default.cfg | 10 +++++----- 3 files changed, 11 insertions(+), 11 deletions(-) diff --git a/docs/source/reference/modding/settings/shadows.rst b/docs/source/reference/modding/settings/shadows.rst index bf160e944..5854b6a91 100644 --- a/docs/source/reference/modding/settings/shadows.rst +++ b/docs/source/reference/modding/settings/shadows.rst @@ -85,11 +85,11 @@ compute tight scene bounds :Type: boolean :Range: True/False -:Default: False +:Default: True With this setting enabled, attempt to better use the shadow map(s) by making them cover a smaller area. This can be especially helpful when looking downwards with a high viewing distance but will be less useful with the default value. -The performance impact of this may be very large. +May have a minor to major performance impact. shadow map resolution --------------------- @@ -200,10 +200,10 @@ use front face culling :Type: boolean :Range: True/False -:Default: True +:Default: False Excludes theoretically unnecessary faces from shadow maps, slightly increasing performance. -In practice, Peter Panning can be much less visible with these faces included, so if you have high polygon offset values, disabling this may help minimise the side effects. +In practice, Peter Panning can be much less visible with these faces included, so if you have high polygon offset values, leaving this off may help minimise the side effects. split point uniform logarithmic ratio ------------------------------------- diff --git a/docs/source/reference/modding/settings/terrain.rst b/docs/source/reference/modding/settings/terrain.rst index c8ae2a227..824c27913 100644 --- a/docs/source/reference/modding/settings/terrain.rst +++ b/docs/source/reference/modding/settings/terrain.rst @@ -68,7 +68,7 @@ composite map level :Type: integer :Range: >= -3 -:Default: -2 +:Default: 0 Controls at which minimum size (in 2^value cell units) terrain chunks will start to use a composite map instead of the high-detail textures. With value -3 composite maps are used everywhere. @@ -76,7 +76,7 @@ With value -3 composite maps are used everywhere. A composite map is a pre-rendered texture that contains all the texture layers combined. Note that resolution of composite maps is currently always fixed at 'composite map resolution', regardless of the resolution of the underlying terrain textures. -If high-detail texture replacers are used, probably it is worth to increase 'composite map resolution' setting value. +If high resolution texture replacers are used, it is recommended to increase 'composite map resolution' setting value. composite map resolution ------------------------ diff --git a/files/settings-default.cfg b/files/settings-default.cfg index 71d44fdbb..43efbc01a 100644 --- a/files/settings-default.cfg +++ b/files/settings-default.cfg @@ -98,7 +98,7 @@ vertex lod mod = 0 # Controls when the distant terrain will flip to composited textures instead of high-detail textures, should be >= -3. # Higher value is more detailed textures. -composite map level = -2 +composite map level = 0 # Controls the resolution of composite maps. composite map resolution = 512 @@ -767,8 +767,8 @@ enable debug hud = false # Enable the debug overlay to see where each shadow map affects. enable debug overlay = false -# Attempt to better use the shadow map by making them cover a smaller area. Especially helpful when looking downwards with a high viewing distance. The performance impact of this may be very large. -compute tight scene bounds = false +# Attempt to better use the shadow map by making them cover a smaller area. Especially helpful when looking downwards. May have a minor to major performance impact. +compute tight scene bounds = true # How large to make the shadow map(s). Higher values increase GPU load, but can produce better-looking results. Power-of-two values may turn out to be faster on some GPU/driver combinations. shadow map resolution = 1024 @@ -785,8 +785,8 @@ polygon offset units = 4.0 # How far along the surface normal to project shadow coordinates. Higher values significantly reduce shadow flicker, usually with a lower increase of Peter Panning than the Polygon Offset settings. This value is in in-game units, so 1.0 is roughly 1.4 cm. normal offset distance = 1.0 -# Excludes theoretically unnecessary faces from shadow maps, slightly increasing performance. In practice, Peter Panning can be much less visible with these faces included, so if you have high polygon offset values, disabling this may help minimise the side effects. -use front face culling = true +# Excludes theoretically unnecessary faces from shadow maps, slightly increasing performance. In practice, Peter Panning can be much less visible with these faces included, so if you have high polygon offset values, leave this off to minimise the side effects. +use front face culling = false # Allow actors to cast shadows. Potentially decreases performance. actor shadows = false From 120b7dcd2fe5e964050b82f82bbddf68d20e8cff Mon Sep 17 00:00:00 2001 From: Capostrophic Date: Tue, 12 Nov 2019 21:44:46 +0300 Subject: [PATCH 14/33] Clean up summoned creatures when corpses are disposed --- apps/openmw/mwgui/container.cpp | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/apps/openmw/mwgui/container.cpp b/apps/openmw/mwgui/container.cpp index 6a303dfba..f0e025a33 100644 --- a/apps/openmw/mwgui/container.cpp +++ b/apps/openmw/mwgui/container.cpp @@ -248,6 +248,12 @@ namespace MWGui MWScript::InterpreterContext interpreterContext (&mPtr.getRefData().getLocals(), mPtr); MWBase::Environment::get().getScriptManager()->run (script, interpreterContext); } + + // Clean up summoned creatures as well + std::map& creatureMap = creatureStats.getSummonedCreatureMap(); + for (const auto& creature : creatureMap) + MWBase::Environment::get().getMechanicsManager()->cleanupSummonedCreature(mPtr, creature.second); + creatureMap.clear(); } MWBase::Environment::get().getWorld()->deleteObject(mPtr); From af41e9acc1a205b353bb9237c35c4120523cb138 Mon Sep 17 00:00:00 2001 From: Andrei Kortunov Date: Wed, 13 Nov 2019 14:47:29 +0400 Subject: [PATCH 15/33] Initialize variables to avoid undefined values --- apps/openmw/mwmechanics/enchanting.cpp | 1 + components/nifosg/controller.hpp | 2 +- components/terrain/chunkmanager.hpp | 3 --- 3 files changed, 2 insertions(+), 4 deletions(-) diff --git a/apps/openmw/mwmechanics/enchanting.cpp b/apps/openmw/mwmechanics/enchanting.cpp index e9ae64337..054560851 100644 --- a/apps/openmw/mwmechanics/enchanting.cpp +++ b/apps/openmw/mwmechanics/enchanting.cpp @@ -21,6 +21,7 @@ namespace MWMechanics Enchanting::Enchanting() : mCastStyle(ESM::Enchantment::CastOnce) , mSelfEnchanting(false) + , mWeaponType(-1) {} void Enchanting::setOldItem(const MWWorld::Ptr& oldItem) diff --git a/components/nifosg/controller.hpp b/components/nifosg/controller.hpp index d5fb56f0e..a16bb6b71 100644 --- a/components/nifosg/controller.hpp +++ b/components/nifosg/controller.hpp @@ -301,7 +301,7 @@ namespace NifOsg private: Vec3Interpolator mData; - TargetColor mTargetColor; + TargetColor mTargetColor = Ambient; }; class FlipController : public SceneUtil::StateSetUpdater, public SceneUtil::Controller diff --git a/components/terrain/chunkmanager.hpp b/components/terrain/chunkmanager.hpp index 2dea1cf92..be83e158c 100644 --- a/components/terrain/chunkmanager.hpp +++ b/components/terrain/chunkmanager.hpp @@ -36,7 +36,6 @@ namespace Terrain osg::ref_ptr getChunk(float size, const osg::Vec2f& center, unsigned char lod, unsigned int lodFlags); - void setCullingActive(bool active) { mCullingActive = active; } void setCompositeMapSize(unsigned int size) { mCompositeMapSize = size; } void setCompositeMapLevel(float level) { mCompositeMapLevel = level; } void setMaxCompositeGeometrySize(float maxCompGeometrySize) { mMaxCompGeometrySize = maxCompGeometrySize; } @@ -65,8 +64,6 @@ namespace Terrain unsigned int mCompositeMapSize; float mCompositeMapLevel; float mMaxCompGeometrySize; - - bool mCullingActive; }; } From ca2a524a5f0ba297415ce50ee7b82e2933483f16 Mon Sep 17 00:00:00 2001 From: Andrei Kortunov Date: Wed, 13 Nov 2019 14:50:42 +0400 Subject: [PATCH 16/33] Avoid null pointer dereference --- apps/openmw/mwrender/npcanimation.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/openmw/mwrender/npcanimation.cpp b/apps/openmw/mwrender/npcanimation.cpp index cde3b3041..abc2583d5 100644 --- a/apps/openmw/mwrender/npcanimation.cpp +++ b/apps/openmw/mwrender/npcanimation.cpp @@ -539,7 +539,7 @@ std::string NpcAnimation::getShieldMesh(MWWorld::ConstPtr shield) const { const ESM::BodyPart *bodypart = 0; bodypart = partStore.search(bodypartName); - if (bodypart->mData.mType != ESM::BodyPart::MT_Armor) + if (bodypart == nullptr || bodypart->mData.mType != ESM::BodyPart::MT_Armor) return ""; else if (!bodypart->mModel.empty()) mesh = "meshes\\" + bodypart->mModel; From 079c77ff22b76b18305e5ee51903fbed927a0a59 Mon Sep 17 00:00:00 2001 From: Andrei Kortunov Date: Wed, 13 Nov 2019 14:57:22 +0400 Subject: [PATCH 17/33] Avoid zero division --- apps/opencs/view/render/terraintexturemode.cpp | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/apps/opencs/view/render/terraintexturemode.cpp b/apps/opencs/view/render/terraintexturemode.cpp index 6d682150a..40dfc9474 100644 --- a/apps/opencs/view/render/terraintexturemode.cpp +++ b/apps/opencs/view/render/terraintexturemode.cpp @@ -730,8 +730,12 @@ void CSVRender::TerrainTextureMode::setBrushShape(int brushShape) selectionCenterY += value.second; ++selectionAmount; } - selectionCenterX /= selectionAmount; - selectionCenterY /= selectionAmount; + + if (selectionAmount != 0) + { + selectionCenterX /= selectionAmount; + selectionCenterY /= selectionAmount; + } mCustomBrushShape.clear(); for (auto const& value: terrainSelection) From 5c6ca82c4585209a349ddad002a4bd3e5de5b670 Mon Sep 17 00:00:00 2001 From: Andrei Kortunov Date: Wed, 13 Nov 2019 15:02:14 +0400 Subject: [PATCH 18/33] Clamp fallback value from config --- apps/openmw/mwrender/water.cpp | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/apps/openmw/mwrender/water.cpp b/apps/openmw/mwrender/water.cpp index 60e43b850..a1b4308ce 100644 --- a/apps/openmw/mwrender/water.cpp +++ b/apps/openmw/mwrender/water.cpp @@ -528,6 +528,8 @@ void Water::createSimpleWaterStateSet(osg::Node* node, float alpha) // Add animated textures std::vector > textures; int frameCount = Fallback::Map::getInt("Water_SurfaceFrameCount"); + frameCount = std::min(std::max(frameCount, 0), 320); + const std::string& texture = Fallback::Map::getString("Water_SurfaceTexture"); for (int i=0; i &textures) { int frameCount = Fallback::Map::getInt("Water_SurfaceFrameCount"); + frameCount = std::min(std::max(frameCount, 0), 320); + const std::string& texture = Fallback::Map::getString("Water_SurfaceTexture"); for (int i=0; i Date: Wed, 13 Nov 2019 15:07:36 +0400 Subject: [PATCH 19/33] Clamp number of shadow maps, as described in docs --- components/sceneutil/shadow.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/components/sceneutil/shadow.cpp b/components/sceneutil/shadow.cpp index 08581ee5a..902627023 100644 --- a/components/sceneutil/shadow.cpp +++ b/components/sceneutil/shadow.cpp @@ -66,6 +66,8 @@ namespace SceneUtil void ShadowManager::disableShadowsForStateSet(osg::ref_ptr stateset) { int numberOfShadowMapsPerLight = Settings::Manager::getInt("number of shadow maps", "Shadows"); + numberOfShadowMapsPerLight = std::max(1, std::min(numberOfShadowMapsPerLight, 8)); + int baseShadowTextureUnit = 8 - numberOfShadowMapsPerLight; osg::ref_ptr fakeShadowMapImage = new osg::Image(); From 238dcdbbd4d8a8cdde6170cad284b78d054d1c40 Mon Sep 17 00:00:00 2001 From: Andrei Kortunov Date: Wed, 13 Nov 2019 15:14:21 +0400 Subject: [PATCH 20/33] Fix copy-paste error --- apps/opencs/view/render/terrainshapemode.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/opencs/view/render/terrainshapemode.cpp b/apps/opencs/view/render/terrainshapemode.cpp index af97e4d8f..44f359c01 100644 --- a/apps/opencs/view/render/terrainshapemode.cpp +++ b/apps/opencs/view/render/terrainshapemode.cpp @@ -1227,7 +1227,7 @@ void CSVRender::TerrainShapeMode::createNewLandData(const CSMWorld::CellCoordina ++averageDivider; downCellSampleHeight = landDownShapePointer[ESM::Land::LAND_SIZE / 2]; - if(paged->getCellAlteredHeight(cellLeftCoords, ESM::Land::LAND_SIZE / 2, 0)) + if(paged->getCellAlteredHeight(cellDownCoords, ESM::Land::LAND_SIZE / 2, 0)) downCellSampleHeight += *paged->getCellAlteredHeight(cellDownCoords, ESM::Land::LAND_SIZE / 2, 0); } } From 5561eb541550a7ccbd4074235b89651472b9ad9e Mon Sep 17 00:00:00 2001 From: Andrei Kortunov Date: Wed, 13 Nov 2019 15:18:18 +0400 Subject: [PATCH 21/33] Do not discard division reminder --- apps/openmw/mwgui/windowbase.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/openmw/mwgui/windowbase.cpp b/apps/openmw/mwgui/windowbase.cpp index e7c975aa2..84e557fcd 100644 --- a/apps/openmw/mwgui/windowbase.cpp +++ b/apps/openmw/mwgui/windowbase.cpp @@ -149,7 +149,7 @@ float BookWindowBase::adjustButton (char const * name) Gui::ImageButton* button; WindowBase::getWidget (button, name); MyGUI::IntSize requested = button->getRequestedSize(); - float scale = requested.height / button->getSize().height; + float scale = float(requested.height) / button->getSize().height; MyGUI::IntSize newSize = requested; newSize.width /= scale; newSize.height /= scale; From 34873b6065729f1240984addee7de5d4a615bdaa Mon Sep 17 00:00:00 2001 From: Andrei Kortunov Date: Wed, 13 Nov 2019 15:29:18 +0400 Subject: [PATCH 22/33] Fix dead code --- apps/esmtool/labels.cpp | 2 +- components/compiler/exprparser.cpp | 2 -- 2 files changed, 1 insertion(+), 3 deletions(-) diff --git a/apps/esmtool/labels.cpp b/apps/esmtool/labels.cpp index a82a6ae80..6793e770c 100644 --- a/apps/esmtool/labels.cpp +++ b/apps/esmtool/labels.cpp @@ -712,7 +712,7 @@ std::string creatureFlags(int flags) if (flags & ESM::Creature::Respawn) properties += "Respawn "; if (flags & ESM::Creature::Weapon) properties += "Weapon "; if (flags & ESM::Creature::Essential) properties += "Essential "; - int unused = (0xFF ^ + int unused = (0xFFFFFFFF ^ (ESM::Creature::Base| ESM::Creature::Walks| ESM::Creature::Swims| diff --git a/components/compiler/exprparser.cpp b/components/compiler/exprparser.cpp index d2d43ceaf..20873385b 100644 --- a/components/compiler/exprparser.cpp +++ b/components/compiler/exprparser.cpp @@ -347,8 +347,6 @@ namespace Compiler scanner.putbackName (name, loc); return false; } - - return Parser::parseName (name, loc, scanner); } bool ExprParser::parseKeyword (int keyword, const TokenLoc& loc, Scanner& scanner) From 3970baeb84bba339e9aba3e5c554b855c9f89e83 Mon Sep 17 00:00:00 2001 From: Andrei Kortunov Date: Wed, 13 Nov 2019 15:46:49 +0400 Subject: [PATCH 23/33] Fix possible usage of destroyed variable --- apps/openmw/mwworld/esmstore.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/openmw/mwworld/esmstore.cpp b/apps/openmw/mwworld/esmstore.cpp index 0a7a7eddd..d366a5a68 100644 --- a/apps/openmw/mwworld/esmstore.cpp +++ b/apps/openmw/mwworld/esmstore.cpp @@ -49,7 +49,7 @@ void ESMStore::load(ESM::ESMReader &esm, Loading::Listener* listener) std::string fname = mast.name; int index = ~0; for (int i = 0; i < esm.getIndex(); i++) { - const std::string &candidate = allPlugins->at(i).getContext().filename; + const std::string candidate = allPlugins->at(i).getContext().filename; std::string fnamecandidate = boost::filesystem::path(candidate).filename().string(); if (Misc::StringUtils::ciEqual(fname, fnamecandidate)) { index = i; From 120583f443f5cec487f235dd2c07b0892d2ecf27 Mon Sep 17 00:00:00 2001 From: Nelsson Huotari Date: Thu, 14 Nov 2019 11:28:49 +0200 Subject: [PATCH 24/33] optimize isInCellSelection calls --- apps/opencs/view/render/terrainshapemode.cpp | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/apps/opencs/view/render/terrainshapemode.cpp b/apps/opencs/view/render/terrainshapemode.cpp index ee6492a87..e73887615 100644 --- a/apps/opencs/view/render/terrainshapemode.cpp +++ b/apps/opencs/view/render/terrainshapemode.cpp @@ -1047,9 +1047,16 @@ void CSVRender::TerrainShapeMode::handleSelection(int globalSelectionX, int glob int moduloY = globalSelectionY % (ESM::Land::LAND_SIZE - 1); bool xIsAtCellBorder = moduloX == 0; bool yIsAtCellBorder = moduloY == 0; - if (isInCellSelection(globalSelectionX - 1, globalSelectionY) && xIsAtCellBorder && !yIsAtCellBorder) selections->emplace_back(globalSelectionX, globalSelectionY); - if (isInCellSelection(globalSelectionX, globalSelectionY - 1) && !xIsAtCellBorder && yIsAtCellBorder) selections->emplace_back(globalSelectionX, globalSelectionY); - if (isInCellSelection(globalSelectionX - 1, globalSelectionY - 1) && xIsAtCellBorder && yIsAtCellBorder) selections->emplace_back(globalSelectionX, globalSelectionY); + if (!xIsAtCellBorder && !yIsAtCellBorder) + return; + int selectionX = globalSelectionX; + int selectionY = globalSelectionY; + if (xIsAtCellBorder) + selectionX--; + if (yIsAtCellBorder) + selectionY--; + if (isInCellSelection(selectionX, selectionY)) + selections->emplace_back(globalSelectionX, globalSelectionY); } } From b210e99abc047f9c448584c8b507d5e9dd7d2f66 Mon Sep 17 00:00:00 2001 From: Andrei Kortunov Date: Thu, 14 Nov 2019 17:43:21 +0400 Subject: [PATCH 25/33] Avoid divizion by zero --- apps/opencs/view/render/terrainshapemode.cpp | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/apps/opencs/view/render/terrainshapemode.cpp b/apps/opencs/view/render/terrainshapemode.cpp index 44f359c01..d356df8f3 100644 --- a/apps/opencs/view/render/terrainshapemode.cpp +++ b/apps/opencs/view/render/terrainshapemode.cpp @@ -1418,8 +1418,12 @@ void CSVRender::TerrainShapeMode::setBrushShape(CSVWidget::BrushShape brushShape selectionCenterY = selectionCenterY + value.second; ++selectionAmount; } - selectionCenterX = selectionCenterX / selectionAmount; - selectionCenterY = selectionCenterY / selectionAmount; + + if (selectionAmount != 0) + { + selectionCenterX /= selectionAmount; + selectionCenterY /= selectionAmount; + } mCustomBrushShape.clear(); std::pair differentialPos {}; From b21dc175388e4e6d8234aae439616fc46a5a5712 Mon Sep 17 00:00:00 2001 From: Andrei Kortunov Date: Thu, 14 Nov 2019 18:04:12 +0400 Subject: [PATCH 26/33] Attempt to shut up CoverityScan warnings about tainted values --- apps/openmw/mwrender/water.cpp | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/apps/openmw/mwrender/water.cpp b/apps/openmw/mwrender/water.cpp index a1b4308ce..6d230d36e 100644 --- a/apps/openmw/mwrender/water.cpp +++ b/apps/openmw/mwrender/water.cpp @@ -527,9 +527,7 @@ void Water::createSimpleWaterStateSet(osg::Node* node, float alpha) // Add animated textures std::vector > textures; - int frameCount = Fallback::Map::getInt("Water_SurfaceFrameCount"); - frameCount = std::min(std::max(frameCount, 0), 320); - + int frameCount = std::max(0, std::min(Fallback::Map::getInt("Water_SurfaceFrameCount"), 320)); const std::string& texture = Fallback::Map::getString("Water_SurfaceTexture"); for (int i=0; i &textures) { - int frameCount = Fallback::Map::getInt("Water_SurfaceFrameCount"); - frameCount = std::min(std::max(frameCount, 0), 320); - + int frameCount = std::max(0, std::min(Fallback::Map::getInt("Water_SurfaceFrameCount"), 320)); const std::string& texture = Fallback::Map::getString("Water_SurfaceTexture"); for (int i=0; i Date: Thu, 14 Nov 2019 19:50:59 +0300 Subject: [PATCH 27/33] Fix terrain shadows checkbox loading --- apps/launcher/graphicspage.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/launcher/graphicspage.cpp b/apps/launcher/graphicspage.cpp index d2d6bd4bc..4ba164698 100644 --- a/apps/launcher/graphicspage.cpp +++ b/apps/launcher/graphicspage.cpp @@ -135,7 +135,7 @@ bool Launcher::GraphicsPage::loadSettings() if (mEngineSettings.getBool("player shadows", "Shadows")) playerShadowsCheckBox->setCheckState(Qt::Checked); if (mEngineSettings.getBool("terrain shadows", "Shadows")) - objectShadowsCheckBox->setCheckState(Qt::Checked); + terrainShadowsCheckBox->setCheckState(Qt::Checked); if (mEngineSettings.getBool("object shadows", "Shadows")) objectShadowsCheckBox->setCheckState(Qt::Checked); if (mEngineSettings.getBool("enable indoor shadows", "Shadows")) From ad256e83435f23971f78a7777e04b3216f7ef37f Mon Sep 17 00:00:00 2001 From: Andrei Kortunov Date: Fri, 15 Nov 2019 11:15:04 +0400 Subject: [PATCH 28/33] Validate input bindings to avoid crashes --- extern/oics/ICSInputControlSystem.cpp | 33 +++++++++++++++++++++------ 1 file changed, 26 insertions(+), 7 deletions(-) diff --git a/extern/oics/ICSInputControlSystem.cpp b/extern/oics/ICSInputControlSystem.cpp index 1be8a8b37..4a646a3b2 100644 --- a/extern/oics/ICSInputControlSystem.cpp +++ b/extern/oics/ICSInputControlSystem.cpp @@ -97,6 +97,13 @@ namespace ICS xmlControl = xmlControl->NextSiblingElement("Control"); } + static const size_t channelsCountLimit = 65536; + if (controlChannelCount > channelsCountLimit) + { + ICS_LOG("Warning: requested channels count (" + ToString(controlChannelCount) + ") exceeds allowed maximum (" + ToString(channelsCountLimit) + "), clamping it"); + controlChannelCount = channelsCountLimit; + } + if(controlChannelCount > channelCount) { size_t dif = controlChannelCount - channelCount; @@ -116,7 +123,13 @@ namespace ICS TiXmlElement* xmlChannelFilter = xmlRoot->FirstChildElement("ChannelFilter"); while(xmlChannelFilter) { - int ch = FromString(xmlChannelFilter->Attribute("number")); + size_t ch = FromString(xmlChannelFilter->Attribute("number")); + if(ch >= controlChannelCount) + { + ICS_LOG("ERROR: channel number (ch) is out of range"); + xmlChannelFilter = xmlChannelFilter->NextSiblingElement("ChannelFilter"); + continue; + } TiXmlElement* xmlInterval = xmlChannelFilter->FirstChildElement("Interval"); while(xmlInterval) @@ -150,7 +163,6 @@ namespace ICS xmlInterval = xmlInterval->NextSiblingElement("Interval"); } - xmlChannelFilter = xmlChannelFilter->NextSiblingElement("ChannelFilter"); } @@ -264,14 +276,21 @@ namespace ICS } } - int chNumber = FromString(xmlChannel->Attribute("number")); - if(std::string(xmlChannel->Attribute("direction")) == "DIRECT") + size_t chNumber = FromString(xmlChannel->Attribute("number")); + if(chNumber >= controlChannelCount) { - mControls.back()->attachChannel(mChannels[ chNumber ],Channel::DIRECT, percentage); + ICS_LOG("ERROR: channel number (chNumber) is out of range"); } - else if(std::string(xmlChannel->Attribute("direction")) == "INVERSE") + else { - mControls.back()->attachChannel(mChannels[ chNumber ],Channel::INVERSE, percentage); + if(std::string(xmlChannel->Attribute("direction")) == "DIRECT") + { + mControls.back()->attachChannel(mChannels[ chNumber ],Channel::DIRECT, percentage); + } + else if(std::string(xmlChannel->Attribute("direction")) == "INVERSE") + { + mControls.back()->attachChannel(mChannels[ chNumber ],Channel::INVERSE, percentage); + } } xmlChannel = xmlChannel->NextSiblingElement("Channel"); From 8dbbe42f21d382a566eebac4177b492418e6d9c8 Mon Sep 17 00:00:00 2001 From: Andrei Kortunov Date: Sun, 17 Nov 2019 09:17:03 +0400 Subject: [PATCH 29/33] Add missing isNpc() check (bug #5206) --- CHANGELOG.md | 1 + apps/openmw/mwmechanics/actors.cpp | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 6d941cc3b..c2989b8a3 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -172,6 +172,7 @@ Bug #5186: Equipped item enchantments don't affect creatures Bug #5190: On-strike enchantments can be applied to and used with non-projectile ranged weapons Bug #5196: Dwarven ghosts do not use idle animations + Bug #5206: A "class does not have NPC stats" error when player's follower kills an enemy with damage spell Feature #1774: Handle AvoidNode Feature #2229: Improve pathfinding AI Feature #3025: Analogue gamepad movement controls diff --git a/apps/openmw/mwmechanics/actors.cpp b/apps/openmw/mwmechanics/actors.cpp index 486c8b31b..ce94fdf26 100644 --- a/apps/openmw/mwmechanics/actors.cpp +++ b/apps/openmw/mwmechanics/actors.cpp @@ -1017,7 +1017,7 @@ namespace MWMechanics { if (caster == player || playerFollowers.find(caster) != playerFollowers.end()) { - if (caster.getClass().getNpcStats(caster).isWerewolf()) + if (caster.getClass().isNpc() && caster.getClass().getNpcStats(caster).isWerewolf()) caster.getClass().getNpcStats(caster).addWerewolfKill(); MWBase::Environment::get().getMechanicsManager()->actorKilled(ptr, player); From d1e0fa575eb4ad0e84475f3b01bbc2a6e686b3b6 Mon Sep 17 00:00:00 2001 From: Andrei Kortunov Date: Sun, 17 Nov 2019 16:04:14 +0400 Subject: [PATCH 30/33] Take in account caster's race height when launch magic bolt (bug #5209) --- CHANGELOG.md | 1 + apps/openmw/mwworld/projectilemanager.cpp | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index c2989b8a3..b499323d7 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -173,6 +173,7 @@ Bug #5190: On-strike enchantments can be applied to and used with non-projectile ranged weapons Bug #5196: Dwarven ghosts do not use idle animations Bug #5206: A "class does not have NPC stats" error when player's follower kills an enemy with damage spell + Bug #5209: Spellcasting ignores race height Feature #1774: Handle AvoidNode Feature #2229: Improve pathfinding AI Feature #3025: Analogue gamepad movement controls diff --git a/apps/openmw/mwworld/projectilemanager.cpp b/apps/openmw/mwworld/projectilemanager.cpp index 2da8140f2..6004a34a6 100644 --- a/apps/openmw/mwworld/projectilemanager.cpp +++ b/apps/openmw/mwworld/projectilemanager.cpp @@ -262,7 +262,7 @@ namespace MWWorld { // Spawn at 0.75 * ActorHeight // Note: we ignore the collision box offset, this is required to make some flying creatures work as intended. - pos.z() += mPhysics->getHalfExtents(caster).z() * 2 * 0.75; + pos.z() += mPhysics->getRenderingHalfExtents(caster).z() * 2 * 0.75; } if (MWBase::Environment::get().getWorld()->isUnderwater(caster.getCell(), pos)) // Underwater casting not possible From f09d20434c78fdbfaeeb12ee0697431caa5f51e2 Mon Sep 17 00:00:00 2001 From: Andrei Kortunov Date: Sun, 17 Nov 2019 17:24:20 +0400 Subject: [PATCH 31/33] Clamp number of shadow maps --- components/sceneutil/shadow.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/components/sceneutil/shadow.cpp b/components/sceneutil/shadow.cpp index 902627023..6b88adaab 100644 --- a/components/sceneutil/shadow.cpp +++ b/components/sceneutil/shadow.cpp @@ -24,6 +24,8 @@ namespace SceneUtil mShadowSettings->setReceivesShadowTraversalMask(~0u); int numberOfShadowMapsPerLight = Settings::Manager::getInt("number of shadow maps", "Shadows"); + numberOfShadowMapsPerLight = std::max(1, std::min(numberOfShadowMapsPerLight, 8)); + mShadowSettings->setNumShadowMapsPerLight(numberOfShadowMapsPerLight); mShadowSettings->setBaseShadowTextureUnit(8 - numberOfShadowMapsPerLight); From 4118b20608b630b8d166d060a34c1234b80e378d Mon Sep 17 00:00:00 2001 From: Andrei Kortunov Date: Mon, 18 Nov 2019 12:41:11 +0400 Subject: [PATCH 32/33] Allow ActionOpen and ActionTalk only for player (bug #5210 --- CHANGELOG.md | 1 + apps/openmw/mwmechanics/aipursue.cpp | 3 ++- apps/openmw/mwworld/actionopen.cpp | 3 +++ apps/openmw/mwworld/actiontalk.cpp | 5 ++++- 4 files changed, 10 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index b499323d7..17acd5825 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -174,6 +174,7 @@ Bug #5196: Dwarven ghosts do not use idle animations Bug #5206: A "class does not have NPC stats" error when player's follower kills an enemy with damage spell Bug #5209: Spellcasting ignores race height + Bug #5210: AiActivate allows actors to open dialogue and inventory windows Feature #1774: Handle AvoidNode Feature #2229: Improve pathfinding AI Feature #3025: Analogue gamepad movement controls diff --git a/apps/openmw/mwmechanics/aipursue.cpp b/apps/openmw/mwmechanics/aipursue.cpp index d6824f2b1..1445a85d6 100644 --- a/apps/openmw/mwmechanics/aipursue.cpp +++ b/apps/openmw/mwmechanics/aipursue.cpp @@ -3,6 +3,7 @@ #include #include "../mwbase/environment.hpp" +#include "../mwbase/windowmanager.hpp" #include "../mwbase/world.hpp" #include "../mwworld/class.hpp" @@ -58,7 +59,7 @@ bool AiPursue::execute (const MWWorld::Ptr& actor, CharacterController& characte if (pathTo(actor, dest, duration, pathTolerance) && std::abs(dest.z() - actorPos.z()) < pathTolerance) // check the true distance in case the target is far away in Z-direction { - target.getClass().activate(target,actor).get()->execute(actor); //Arrest player when reached + MWBase::Environment::get().getWindowManager()->pushGuiMode(MWGui::GM_Dialogue, actor); //Arrest player when reached return true; } diff --git a/apps/openmw/mwworld/actionopen.cpp b/apps/openmw/mwworld/actionopen.cpp index f9866cd41..266ea4d95 100644 --- a/apps/openmw/mwworld/actionopen.cpp +++ b/apps/openmw/mwworld/actionopen.cpp @@ -18,6 +18,9 @@ namespace MWWorld if (!MWBase::Environment::get().getWindowManager()->isAllowed(MWGui::GW_Inventory)) return; + if (actor != MWMechanics::getPlayer()) + return; + if (!MWBase::Environment::get().getMechanicsManager()->onOpen(getTarget())) return; diff --git a/apps/openmw/mwworld/actiontalk.cpp b/apps/openmw/mwworld/actiontalk.cpp index c7bb6a26e..7fe623b8e 100644 --- a/apps/openmw/mwworld/actiontalk.cpp +++ b/apps/openmw/mwworld/actiontalk.cpp @@ -3,12 +3,15 @@ #include "../mwbase/environment.hpp" #include "../mwbase/windowmanager.hpp" +#include "../mwmechanics/actorutil.hpp" + namespace MWWorld { ActionTalk::ActionTalk (const Ptr& actor) : Action (false, actor) {} void ActionTalk::executeImp (const Ptr& actor) { - MWBase::Environment::get().getWindowManager()->pushGuiMode(MWGui::GM_Dialogue, getTarget()); + if (actor == MWMechanics::getPlayer()) + MWBase::Environment::get().getWindowManager()->pushGuiMode(MWGui::GM_Dialogue, getTarget()); } } From 73f43ba750fb0677d85780a44e8477ef6f0bbb9c Mon Sep 17 00:00:00 2001 From: Andrei Kortunov Date: Mon, 18 Nov 2019 22:10:31 +0400 Subject: [PATCH 33/33] Do not use screen fading during game loading if there is no current cell (bug #5211) --- CHANGELOG.md | 1 + apps/openmw/mwworld/scene.cpp | 13 ++++++------- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 17acd5825..d8c7ab517 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -175,6 +175,7 @@ Bug #5206: A "class does not have NPC stats" error when player's follower kills an enemy with damage spell Bug #5209: Spellcasting ignores race height Bug #5210: AiActivate allows actors to open dialogue and inventory windows + Bug #5211: Screen fades in if the first loaded save is in interior cell Feature #1774: Handle AvoidNode Feature #2229: Improve pathfinding AI Feature #3025: Analogue gamepad movement controls diff --git a/apps/openmw/mwworld/scene.cpp b/apps/openmw/mwworld/scene.cpp index f8b80663d..ddca61148 100644 --- a/apps/openmw/mwworld/scene.cpp +++ b/apps/openmw/mwworld/scene.cpp @@ -683,11 +683,9 @@ namespace MWWorld void Scene::changeToInteriorCell (const std::string& cellName, const ESM::Position& position, bool adjustPlayerPos, bool changeEvent) { CellStore *cell = MWBase::Environment::get().getWorld()->getInterior(cellName); - bool loadcell = (mCurrentCell == nullptr); - if(!loadcell) - loadcell = *mCurrentCell != *cell; - - MWBase::Environment::get().getWindowManager()->fadeScreenOut(0.5); + bool useFading = (mCurrentCell != nullptr); + if (useFading) + MWBase::Environment::get().getWindowManager()->fadeScreenOut(0.5); Loading::Listener* loadingListener = MWBase::Environment::get().getWindowManager()->getLoadingScreen(); int messagesCount = MWBase::Environment::get().getWindowManager()->getMessagesCount(); @@ -695,7 +693,7 @@ namespace MWWorld loadingListener->setLabel(loadingInteriorText, false, messagesCount > 0); Loading::ScopedLoad load(loadingListener); - if(!loadcell) + if(mCurrentCell != nullptr && *mCurrentCell == *cell) { MWBase::World *world = MWBase::Environment::get().getWorld(); world->moveObject(world->getPlayerPtr(), position.pos[0], position.pos[1], position.pos[2]); @@ -734,7 +732,8 @@ namespace MWWorld if (changeEvent) mCellChanged = true; - MWBase::Environment::get().getWindowManager()->fadeScreenIn(0.5); + if (useFading) + MWBase::Environment::get().getWindowManager()->fadeScreenIn(0.5); MWBase::Environment::get().getWindowManager()->changeCell(mCurrentCell); }