From 15bf05215e4dee7053728085bfa495a4e83e4229 Mon Sep 17 00:00:00 2001 From: capostrophic Date: Mon, 29 Jul 2019 16:13:52 +0300 Subject: [PATCH 01/20] Revert questionable input manager decisions Remove Options Menu shortcut Revert to more pleasant 0.45.0 Escape behavior Re-enable keyboard GUI arrow conversion feature Remove gamepad button release handling --- apps/openmw/mwinput/inputmanagerimp.cpp | 64 ++++++++----------------- apps/openmw/mwinput/inputmanagerimp.hpp | 5 +- 2 files changed, 20 insertions(+), 49 deletions(-) diff --git a/apps/openmw/mwinput/inputmanagerimp.cpp b/apps/openmw/mwinput/inputmanagerimp.cpp index 581a96e7b..0c6d19200 100644 --- a/apps/openmw/mwinput/inputmanagerimp.cpp +++ b/apps/openmw/mwinput/inputmanagerimp.cpp @@ -197,6 +197,11 @@ namespace MWInput void InputManager::handleGuiArrowKey(int action) { + // This is currently keyboard-specific code + // TODO: see if GUI controls can be refactored into a single function + if (mJoystickLastUsed) + return; + if (SDL_IsTextInputActive()) return; @@ -224,13 +229,10 @@ namespace MWInput MWBase::Environment::get().getWindowManager()->injectKeyPress(key, 0, false); } - bool InputManager::gamepadToGuiControl(const SDL_ControllerButtonEvent &arg, bool release=false) + bool InputManager::gamepadToGuiControl(const SDL_ControllerButtonEvent &arg) { // Presumption of GUI mode will be removed in the future. // MyGUI KeyCodes *may* change. - // Currently button releases are ignored. - if (release) - return false; MyGUI::KeyCode key = MyGUI::KeyCode::None; switch (arg.button) @@ -381,9 +383,6 @@ namespace MWInput case A_GameMenu: toggleMainMenu (); break; - case A_OptionsMenu: - toggleOptionsMenu(); - break; case A_Screenshot: screenshot(); break; @@ -401,8 +400,7 @@ namespace MWInput case A_MoveRight: case A_MoveForward: case A_MoveBackward: - // Temporary shut-down of this function until deemed necessary. - //handleGuiArrowKey(action); + handleGuiArrowKey(action); break; case A_Journal: toggleJournal (); @@ -1000,9 +998,9 @@ namespace MWInput mJoystickLastUsed = true; if (MWBase::Environment::get().getWindowManager()->isGuiMode()) { - if (gamepadToGuiControl(arg, false)) + if (gamepadToGuiControl(arg)) return; - else if (mGamepadGuiCursorEnabled) + if (mGamepadGuiCursorEnabled) { // Temporary mouse binding until keyboard controls are available: if (arg.button == SDL_CONTROLLER_BUTTON_A) // We'll pretend that A is left click. @@ -1043,9 +1041,7 @@ namespace MWInput mJoystickLastUsed = true; if (MWBase::Environment::get().getWindowManager()->isGuiMode()) { - if (gamepadToGuiControl(arg, true)) - return; - else if (mGamepadGuiCursorEnabled) + if (mGamepadGuiCursorEnabled) { // Temporary mouse binding until keyboard controls are available: if (arg.button == SDL_CONTROLLER_BUTTON_A) // We'll pretend that A is left click. @@ -1144,37 +1140,19 @@ namespace MWInput } if (MWBase::Environment::get().getWindowManager()->isConsoleMode()) - return; - - bool inGame = MWBase::Environment::get().getStateManager()->getState() != MWBase::StateManager::State_NoGame; - MWGui::GuiMode mode = MWBase::Environment::get().getWindowManager()->getMode(); - - if ((inGame && mode == MWGui::GM_MainMenu) || mode == MWGui::GM_Settings) - MWBase::Environment::get().getWindowManager()->popGuiMode(); - - if (inGame && mode != MWGui::GM_MainMenu) - MWBase::Environment::get().getWindowManager()->pushGuiMode(MWGui::GM_MainMenu); - } - - void InputManager::toggleOptionsMenu() - { - if (MyGUI::InputManager::getInstance().isModalAny()) { - MWBase::Environment::get().getWindowManager()->exitCurrentModal(); + MWBase::Environment::get().getWindowManager()->toggleConsole(); return; } - if (MWBase::Environment::get().getWindowManager()->isConsoleMode()) - return; - - MWGui::GuiMode mode = MWBase::Environment::get().getWindowManager()->getMode(); - bool inGame = MWBase::Environment::get().getStateManager()->getState() != MWBase::StateManager::State_NoGame; - - if ((inGame && mode == MWGui::GM_MainMenu) || mode == MWGui::GM_Settings) - MWBase::Environment::get().getWindowManager()->popGuiMode(); - - if (inGame && mode != MWGui::GM_Settings) - MWBase::Environment::get().getWindowManager()->pushGuiMode(MWGui::GM_Settings); + if (!MWBase::Environment::get().getWindowManager()->isGuiMode()) //No open GUIs, open up the MainMenu + { + MWBase::Environment::get().getWindowManager()->pushGuiMode (MWGui::GM_MainMenu); + } + else //Close current GUI + { + MWBase::Environment::get().getWindowManager()->exitCurrentGuiMode(); + } } void InputManager::quickLoad() { @@ -1529,7 +1507,6 @@ namespace MWInput defaultButtonBindings[A_TogglePOV] = SDL_CONTROLLER_BUTTON_RIGHTSTICK; defaultButtonBindings[A_Inventory] = SDL_CONTROLLER_BUTTON_B; defaultButtonBindings[A_GameMenu] = SDL_CONTROLLER_BUTTON_START; - defaultButtonBindings[A_OptionsMenu] = SDL_CONTROLLER_BUTTON_BACK; defaultButtonBindings[A_QuickSave] = SDL_CONTROLLER_BUTTON_GUIDE; defaultButtonBindings[A_MoveForward] = SDL_CONTROLLER_BUTTON_DPAD_UP; defaultButtonBindings[A_MoveLeft] = SDL_CONTROLLER_BUTTON_DPAD_LEFT; @@ -1610,7 +1587,6 @@ namespace MWInput descriptions[A_Journal] = "sJournal"; descriptions[A_Rest] = "sRestKey"; descriptions[A_Inventory] = "sInventory"; - descriptions[A_OptionsMenu] = "sPreferences"; descriptions[A_TogglePOV] = "sTogglePOVCmd"; descriptions[A_QuickKeysMenu] = "sQuickMenu"; descriptions[A_QuickKey1] = "sQuick1Cmd"; @@ -1748,7 +1724,6 @@ namespace MWInput ret.push_back(A_Inventory); ret.push_back(A_Journal); ret.push_back(A_Rest); - ret.push_back(A_OptionsMenu); ret.push_back(A_Console); ret.push_back(A_QuickSave); ret.push_back(A_QuickLoad); @@ -1781,7 +1756,6 @@ namespace MWInput ret.push_back(A_Inventory); ret.push_back(A_Journal); ret.push_back(A_Rest); - ret.push_back(A_OptionsMenu); ret.push_back(A_QuickSave); ret.push_back(A_QuickLoad); ret.push_back(A_Screenshot); diff --git a/apps/openmw/mwinput/inputmanagerimp.hpp b/apps/openmw/mwinput/inputmanagerimp.hpp index caf57681d..8762047ec 100644 --- a/apps/openmw/mwinput/inputmanagerimp.hpp +++ b/apps/openmw/mwinput/inputmanagerimp.hpp @@ -225,7 +225,7 @@ namespace MWInput void setPlayerControlsEnabled(bool enabled); void handleGuiArrowKey(int action); // Return true if GUI consumes input. - bool gamepadToGuiControl(const SDL_ControllerButtonEvent &arg, bool release); + bool gamepadToGuiControl(const SDL_ControllerButtonEvent &arg); bool gamepadToGuiControl(const SDL_ControllerAxisEvent &arg); void updateCursorMode(); @@ -234,7 +234,6 @@ namespace MWInput private: void toggleMainMenu(); - void toggleOptionsMenu(); void toggleSpell(); void toggleWeapon(); void toggleInventory(); @@ -327,8 +326,6 @@ namespace MWInput A_MoveForwardBackward, A_MoveLeftRight, - A_OptionsMenu, - A_Last // Marker for the last item }; }; From c32872fb16fe826c5409e31111bd50466595abf5 Mon Sep 17 00:00:00 2001 From: elsid Date: Thu, 15 Aug 2019 19:19:04 +0200 Subject: [PATCH 02/20] 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/mwmechanics/aipackage.hpp | 2 ++ apps/openmw/mwworld/worldimp.cpp | 9 +++++++-- apps/openmw/mwworld/worldimp.hpp | 2 ++ 5 files changed, 31 insertions(+), 2 deletions(-) diff --git a/apps/openmw/mwbase/world.hpp b/apps/openmw/mwbase/world.hpp index 256c8b1d5..08642eb7f 100644 --- a/apps/openmw/mwbase/world.hpp +++ b/apps/openmw/mwbase/world.hpp @@ -306,6 +306,8 @@ namespace MWBase virtual bool castRay (float x1, float y1, float z1, float x2, float y2, float z2) = 0; + virtual MWWorld::Ptr castRay(const osg::Vec3f& from, const osg::Vec3f& to, int mask) const = 0; + virtual void setActorCollisionMode(const MWWorld::Ptr& ptr, bool internal, bool external) = 0; virtual bool isActorCollisionEnabled(const MWWorld::Ptr& ptr) = 0; diff --git a/apps/openmw/mwmechanics/aipackage.cpp b/apps/openmw/mwmechanics/aipackage.cpp index 598292fc3..4395f1e4b 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" @@ -234,6 +236,9 @@ void MWMechanics::AiPackage::openDoors(const MWWorld::Ptr& actor) // note: AiWander currently does not open doors if (getTypeId() != TypeIdWander && !door.getCellRef().getTeleport() && door.getClass().getDoorState(door) == 0) { + if (!isDoorOnTheWay(actor, door)) + return; + if ((door.getCellRef().getTrap().empty() && door.getCellRef().getLockLevel() <= 0 )) { world->activate(door, actor); @@ -402,3 +407,16 @@ DetourNavigator::Flags MWMechanics::AiPackage::getNavigatorFlags(const MWWorld:: return result; } + +bool MWMechanics::AiPackage::isDoorOnTheWay(const MWWorld::Ptr& actor, const MWWorld::Ptr& door) const +{ + if (mPathFinder.getPathSize() == 0) + return false; + + 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 = mPathFinder.getPath().front() + osg::Vec3f(0, 0, halfExtents.z()); + + return world->castRay(position, destination, MWPhysics::CollisionType_Door) == door; +} diff --git a/apps/openmw/mwmechanics/aipackage.hpp b/apps/openmw/mwmechanics/aipackage.hpp index 6bb12342a..0f7b5cf1d 100644 --- a/apps/openmw/mwmechanics/aipackage.hpp +++ b/apps/openmw/mwmechanics/aipackage.hpp @@ -147,6 +147,8 @@ namespace MWMechanics private: bool isNearInactiveCell(osg::Vec3f position); + + bool isDoorOnTheWay(const MWWorld::Ptr& actor, const MWWorld::Ptr& door) const; }; } diff --git a/apps/openmw/mwworld/worldimp.cpp b/apps/openmw/mwworld/worldimp.cpp index ce253b8ba..d285d04ca 100644 --- a/apps/openmw/mwworld/worldimp.cpp +++ b/apps/openmw/mwworld/worldimp.cpp @@ -1610,8 +1610,13 @@ namespace MWWorld osg::Vec3f a(x1,y1,z1); osg::Vec3f b(x2,y2,z2); - MWPhysics::PhysicsSystem::RayResult result = mPhysics->castRay(a, b, MWWorld::Ptr(), std::vector(), mask); - return result.mHit; + return !castRay(a, b, mask).isEmpty(); + } + + MWWorld::Ptr World::castRay(const osg::Vec3f& from, const osg::Vec3f& to, int mask) const + { + const auto result = mPhysics->castRay(from, to, MWWorld::Ptr(), std::vector(), mask); + return result.mHit ? result.mHitObject : MWWorld::Ptr(); } void World::processDoors(float duration) diff --git a/apps/openmw/mwworld/worldimp.hpp b/apps/openmw/mwworld/worldimp.hpp index dd915c8bd..0acbc5926 100644 --- a/apps/openmw/mwworld/worldimp.hpp +++ b/apps/openmw/mwworld/worldimp.hpp @@ -420,6 +420,8 @@ namespace MWWorld bool castRay (float x1, float y1, float z1, float x2, float y2, float z2) override; + MWWorld::Ptr castRay (const osg::Vec3f& from, const osg::Vec3f& to, int mask) const override; + void setActorCollisionMode(const Ptr& ptr, bool internal, bool external) override; bool isActorCollisionEnabled(const Ptr& ptr) override; From cec9e2590264b2cfb906c534d5f8db6a076e643f Mon Sep 17 00:00:00 2001 From: Alexei Dobrohotov Date: Sun, 18 Aug 2019 21:47:45 +0300 Subject: [PATCH 03/20] Fix changelog --- CHANGELOG.md | 1 - 1 file changed, 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 74ad52cd7..65adf8add 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -132,7 +132,6 @@ Bug #5124: Arrow remains attached to actor if pulling animation was cancelled Bug #5126: Swimming creatures without RunForward animations are motionless during combat Bug #5134: Doors rotation by "Lock" console command is inconsistent - Bug #5126: Swimming creatures without RunForward animations are motionless during combat Bug #5137: Textures with Clamp Mode set to Clamp instead of Wrap are too dark outside the boundaries Feature #1774: Handle AvoidNode Feature #2229: Improve pathfinding AI From 64fde2d7c24990558097d2e5ac2c22c575400e5f Mon Sep 17 00:00:00 2001 From: Alexei Dobrohotov Date: Sat, 24 Aug 2019 22:34:56 +0300 Subject: [PATCH 04/20] Fix crash when NiGeometry lacks NiGeometryData --- components/nifosg/nifloader.cpp | 36 ++++++++++++++++++--------------- 1 file changed, 20 insertions(+), 16 deletions(-) diff --git a/components/nifosg/nifloader.cpp b/components/nifosg/nifloader.cpp index 31dcd2a55..e199a3b72 100644 --- a/components/nifosg/nifloader.cpp +++ b/components/nifosg/nifloader.cpp @@ -1072,28 +1072,32 @@ namespace NifOsg if (nifNode->recType == Nif::RC_NiTriShape) { const Nif::NiTriShape* triShape = static_cast(nifNode); - const Nif::NiTriShapeData* data = triShape->data.getPtr(); - vertexColorsPresent = !data->colors.empty(); - triCommonToGeometry(geometry, data->vertices, data->normals, data->uvlist, data->colors, boundTextures, triShape->name); - if (!data->triangles.empty()) - geometry->addPrimitiveSet(new osg::DrawElementsUShort(osg::PrimitiveSet::TRIANGLES, data->triangles.size(), - (unsigned short*)data->triangles.data())); + if (const Nif::NiTriShapeData* data = triShape->data.getPtr()) + { + vertexColorsPresent = !data->colors.empty(); + triCommonToGeometry(geometry, data->vertices, data->normals, data->uvlist, data->colors, boundTextures, triShape->name); + if (!data->triangles.empty()) + geometry->addPrimitiveSet(new osg::DrawElementsUShort(osg::PrimitiveSet::TRIANGLES, data->triangles.size(), + (unsigned short*)data->triangles.data())); + } } else { const Nif::NiTriStrips* triStrips = static_cast(nifNode); - const Nif::NiTriStripsData* data = triStrips->data.getPtr(); - vertexColorsPresent = !data->colors.empty(); - triCommonToGeometry(geometry, data->vertices, data->normals, data->uvlist, data->colors, boundTextures, triStrips->name); - if (!data->strips.empty()) + if (const Nif::NiTriStripsData* data = triStrips->data.getPtr()) { - for (const std::vector& strip : data->strips) + vertexColorsPresent = !data->colors.empty(); + triCommonToGeometry(geometry, data->vertices, data->normals, data->uvlist, data->colors, boundTextures, triStrips->name); + if (!data->strips.empty()) { - // Can't make a triangle from less than three vertices. - if (strip.size() < 3) - continue; - geometry->addPrimitiveSet(new osg::DrawElementsUShort(osg::PrimitiveSet::TRIANGLE_STRIP, strip.size(), - (unsigned short*)strip.data())); + for (const std::vector& strip : data->strips) + { + // Can't make a triangle from less than three vertices. + if (strip.size() < 3) + continue; + geometry->addPrimitiveSet(new osg::DrawElementsUShort(osg::PrimitiveSet::TRIANGLE_STRIP, strip.size(), + (unsigned short*)strip.data())); + } } } } From 16170131b7442f7e568a98cd8663c6066911475b Mon Sep 17 00:00:00 2001 From: elsid Date: Sun, 25 Aug 2019 15:20:14 +0200 Subject: [PATCH 05/20] Add enum type for door state --- apps/openmw/mwbase/world.hpp | 3 ++- apps/openmw/mwclass/door.cpp | 22 +++++++++--------- apps/openmw/mwclass/door.hpp | 5 ++--- apps/openmw/mwmechanics/aiavoiddoor.cpp | 2 +- apps/openmw/mwmechanics/aipackage.cpp | 2 +- apps/openmw/mwmechanics/obstacle.cpp | 4 ++-- apps/openmw/mwscript/miscextensions.cpp | 2 +- apps/openmw/mwworld/class.cpp | 4 ++-- apps/openmw/mwworld/class.hpp | 8 +++---- apps/openmw/mwworld/doorstate.hpp | 14 ++++++++++++ apps/openmw/mwworld/worldimp.cpp | 30 ++++++++++++------------- apps/openmw/mwworld/worldimp.hpp | 6 ++--- 12 files changed, 58 insertions(+), 44 deletions(-) create mode 100644 apps/openmw/mwworld/doorstate.hpp diff --git a/apps/openmw/mwbase/world.hpp b/apps/openmw/mwbase/world.hpp index 63f69ab65..955e77168 100644 --- a/apps/openmw/mwbase/world.hpp +++ b/apps/openmw/mwbase/world.hpp @@ -9,6 +9,7 @@ #include #include "../mwworld/ptr.hpp" +#include "../mwworld/doorstate.hpp" #include "../mwrender/rendermode.hpp" @@ -419,7 +420,7 @@ namespace MWBase /// update movement state of a non-teleport door as specified /// @param state see MWClass::setDoorState /// @note throws an exception when invoked on a teleport door - virtual void activateDoor(const MWWorld::Ptr& door, int state) = 0; + virtual void activateDoor(const MWWorld::Ptr& door, MWWorld::DoorState state) = 0; virtual void getActorsStandingOn (const MWWorld::ConstPtr& object, std::vector &actors) = 0; ///< get a list of actors standing on \a object virtual bool getPlayerStandingOn (const MWWorld::ConstPtr& object) = 0; ///< @return true if the player is standing on \a object diff --git a/apps/openmw/mwclass/door.cpp b/apps/openmw/mwclass/door.cpp index 89b628d91..4f144e1f7 100644 --- a/apps/openmw/mwclass/door.cpp +++ b/apps/openmw/mwclass/door.cpp @@ -34,7 +34,7 @@ namespace MWClass class DoorCustomData : public MWWorld::CustomData { public: - int mDoorState; // 0 = nothing, 1 = opening, 2 = closing + MWWorld::DoorState mDoorState; virtual MWWorld::CustomData *clone() const; @@ -71,7 +71,7 @@ namespace MWClass if (ptr.getRefData().getCustomData()) { const DoorCustomData& customData = ptr.getRefData().getCustomData()->asDoorCustomData(); - if (customData.mDoorState > 0) + if (customData.mDoorState != MWWorld::DoorState::Idle) { MWBase::Environment::get().getWorld()->activateDoor(ptr, customData.mDoorState); } @@ -201,12 +201,12 @@ namespace MWClass { // animated door std::shared_ptr action(new MWWorld::ActionDoor(ptr)); - int doorstate = getDoorState(ptr); + const auto doorState = getDoorState(ptr); bool opening = true; float doorRot = ptr.getRefData().getPosition().rot[2] - ptr.getCellRef().getPosition().rot[2]; - if (doorstate == 1) + if (doorState == MWWorld::DoorState::Opening) opening = false; - if (doorstate == 0 && doorRot != 0) + if (doorState == MWWorld::DoorState::Idle && doorRot != 0) opening = false; if (opening) @@ -365,20 +365,20 @@ namespace MWClass { std::unique_ptr data(new DoorCustomData); - data->mDoorState = 0; + data->mDoorState = MWWorld::DoorState::Idle; ptr.getRefData().setCustomData(data.release()); } } - int Door::getDoorState (const MWWorld::ConstPtr &ptr) const + MWWorld::DoorState Door::getDoorState (const MWWorld::ConstPtr &ptr) const { if (!ptr.getRefData().getCustomData()) - return 0; + return MWWorld::DoorState::Idle; const DoorCustomData& customData = ptr.getRefData().getCustomData()->asDoorCustomData(); return customData.mDoorState; } - void Door::setDoorState (const MWWorld::Ptr &ptr, int state) const + void Door::setDoorState (const MWWorld::Ptr &ptr, MWWorld::DoorState state) const { if (ptr.getCellRef().getTeleport()) throw std::runtime_error("load doors can't be moved"); @@ -396,7 +396,7 @@ namespace MWClass DoorCustomData& customData = ptr.getRefData().getCustomData()->asDoorCustomData(); const ESM::DoorState& state2 = dynamic_cast(state); - customData.mDoorState = state2.mDoorState; + customData.mDoorState = static_cast(state2.mDoorState); } void Door::writeAdditionalState (const MWWorld::ConstPtr& ptr, ESM::ObjectState& state) const @@ -409,7 +409,7 @@ namespace MWClass const DoorCustomData& customData = ptr.getRefData().getCustomData()->asDoorCustomData(); ESM::DoorState& state2 = dynamic_cast(state); - state2.mDoorState = customData.mDoorState; + state2.mDoorState = static_cast(customData.mDoorState); } } diff --git a/apps/openmw/mwclass/door.hpp b/apps/openmw/mwclass/door.hpp index 57e475382..b3e4e383c 100644 --- a/apps/openmw/mwclass/door.hpp +++ b/apps/openmw/mwclass/door.hpp @@ -59,10 +59,9 @@ namespace MWClass virtual std::string getModel(const MWWorld::ConstPtr &ptr) const; - /// 0 = nothing, 1 = opening, 2 = closing - virtual int getDoorState (const MWWorld::ConstPtr &ptr) const; + virtual MWWorld::DoorState getDoorState (const MWWorld::ConstPtr &ptr) const; /// This does not actually cause the door to move. Use World::activateDoor instead. - virtual void setDoorState (const MWWorld::Ptr &ptr, int state) const; + virtual void setDoorState (const MWWorld::Ptr &ptr, MWWorld::DoorState state) const; virtual void readAdditionalState (const MWWorld::Ptr& ptr, const ESM::ObjectState& state) diff --git a/apps/openmw/mwmechanics/aiavoiddoor.cpp b/apps/openmw/mwmechanics/aiavoiddoor.cpp index 8fc35de49..793bd89ea 100644 --- a/apps/openmw/mwmechanics/aiavoiddoor.cpp +++ b/apps/openmw/mwmechanics/aiavoiddoor.cpp @@ -44,7 +44,7 @@ bool MWMechanics::AiAvoidDoor::execute (const MWWorld::Ptr& actor, CharacterCont return true; // We have tried backing up for more than one second, we've probably cleared it } - if (!mDoorPtr.getClass().getDoorState(mDoorPtr)) + if (mDoorPtr.getClass().getDoorState(mDoorPtr) == MWWorld::DoorState::Idle) return true; //Door is no longer opening ESM::Position tPos = mDoorPtr.getRefData().getPosition(); //Position of the door diff --git a/apps/openmw/mwmechanics/aipackage.cpp b/apps/openmw/mwmechanics/aipackage.cpp index 598292fc3..646b37669 100644 --- a/apps/openmw/mwmechanics/aipackage.cpp +++ b/apps/openmw/mwmechanics/aipackage.cpp @@ -232,7 +232,7 @@ void MWMechanics::AiPackage::openDoors(const MWWorld::Ptr& actor) return; // note: AiWander currently does not open doors - if (getTypeId() != TypeIdWander && !door.getCellRef().getTeleport() && door.getClass().getDoorState(door) == 0) + if (getTypeId() != TypeIdWander && !door.getCellRef().getTeleport() && door.getClass().getDoorState(door) == MWWorld::DoorState::Idle) { if ((door.getCellRef().getTrap().empty() && door.getCellRef().getLockLevel() <= 0 )) { diff --git a/apps/openmw/mwmechanics/obstacle.cpp b/apps/openmw/mwmechanics/obstacle.cpp index b8676a883..c3da92e31 100644 --- a/apps/openmw/mwmechanics/obstacle.cpp +++ b/apps/openmw/mwmechanics/obstacle.cpp @@ -52,10 +52,10 @@ namespace MWMechanics // FIXME: cast const MWWorld::Ptr doorPtr = MWWorld::Ptr(&const_cast &>(ref), actor.getCell()); - int doorState = doorPtr.getClass().getDoorState(doorPtr); + const auto doorState = doorPtr.getClass().getDoorState(doorPtr); float doorRot = ref.mData.getPosition().rot[2] - doorPtr.getCellRef().getPosition().rot[2]; - if (doorState != 0 || doorRot != 0) + if (doorState != MWWorld::DoorState::Idle || doorRot != 0) continue; // the door is already opened/opening doorPos.z() = 0; diff --git a/apps/openmw/mwscript/miscextensions.cpp b/apps/openmw/mwscript/miscextensions.cpp index 47873a3b6..29a25c997 100644 --- a/apps/openmw/mwscript/miscextensions.cpp +++ b/apps/openmw/mwscript/miscextensions.cpp @@ -188,7 +188,7 @@ namespace MWScript // This is done when using Lock in scripts, but not when using Lock spells. if (ptr.getTypeName() == typeid(ESM::Door).name() && !ptr.getCellRef().getTeleport()) { - MWBase::Environment::get().getWorld()->activateDoor(ptr, 0); + MWBase::Environment::get().getWorld()->activateDoor(ptr, MWWorld::DoorState::Idle); } } }; diff --git a/apps/openmw/mwworld/class.cpp b/apps/openmw/mwworld/class.cpp index f84c7bb8b..191552bc5 100644 --- a/apps/openmw/mwworld/class.cpp +++ b/apps/openmw/mwworld/class.cpp @@ -460,12 +460,12 @@ namespace MWWorld return false; } - int Class::getDoorState (const MWWorld::ConstPtr &ptr) const + MWWorld::DoorState Class::getDoorState (const MWWorld::ConstPtr &ptr) const { throw std::runtime_error("this is not a door"); } - void Class::setDoorState (const MWWorld::Ptr &ptr, int state) const + void Class::setDoorState (const MWWorld::Ptr &ptr, MWWorld::DoorState state) const { throw std::runtime_error("this is not a door"); } diff --git a/apps/openmw/mwworld/class.hpp b/apps/openmw/mwworld/class.hpp index 8e5cfb981..964ef19a5 100644 --- a/apps/openmw/mwworld/class.hpp +++ b/apps/openmw/mwworld/class.hpp @@ -9,6 +9,7 @@ #include #include "ptr.hpp" +#include "doorstate.hpp" namespace ESM { @@ -298,7 +299,7 @@ namespace MWWorld virtual bool allowTelekinesis(const MWWorld::ConstPtr& ptr) const { return true; } ///< Return whether this class of object can be activated with telekinesis - + /// Get a blood texture suitable for \a ptr (see Blood Texture 0-2 in Morrowind.ini) virtual int getBloodTexture (const MWWorld::ConstPtr& ptr) const; @@ -350,10 +351,9 @@ namespace MWWorld virtual bool isClass(const MWWorld::ConstPtr& ptr, const std::string &className) const; - /// 0 = nothing, 1 = opening, 2 = closing - virtual int getDoorState (const MWWorld::ConstPtr &ptr) const; + virtual DoorState getDoorState (const MWWorld::ConstPtr &ptr) const; /// This does not actually cause the door to move. Use World::activateDoor instead. - virtual void setDoorState (const MWWorld::Ptr &ptr, int state) const; + virtual void setDoorState (const MWWorld::Ptr &ptr, DoorState state) const; virtual void respawn (const MWWorld::Ptr& ptr) const {} diff --git a/apps/openmw/mwworld/doorstate.hpp b/apps/openmw/mwworld/doorstate.hpp new file mode 100644 index 000000000..aeafa7d8c --- /dev/null +++ b/apps/openmw/mwworld/doorstate.hpp @@ -0,0 +1,14 @@ +#ifndef GAME_MWWORLD_DOORSTATE_H +#define GAME_MWWORLD_DOORSTATE_H + +namespace MWWorld +{ + enum class DoorState + { + Idle = 0, + Opening = 1, + Closing = 2, + }; +} + +#endif diff --git a/apps/openmw/mwworld/worldimp.cpp b/apps/openmw/mwworld/worldimp.cpp index 5babc57be..3ea994683 100644 --- a/apps/openmw/mwworld/worldimp.cpp +++ b/apps/openmw/mwworld/worldimp.cpp @@ -1617,7 +1617,7 @@ namespace MWWorld return result.mHit; } - bool World::rotateDoor(const Ptr door, int state, float duration) + bool World::rotateDoor(const Ptr door, MWWorld::DoorState state, float duration) { const ESM::Position& objPos = door.getRefData().getPosition(); float oldRot = objPos.rot[2]; @@ -1626,10 +1626,10 @@ namespace MWWorld float maxRot = minRot + osg::DegreesToRadians(90.f); float diff = duration * osg::DegreesToRadians(90.f); - float targetRot = std::min(std::max(minRot, oldRot + diff * (state == 1 ? 1 : -1)), maxRot); + float targetRot = std::min(std::max(minRot, oldRot + diff * (state == MWWorld::DoorState::Opening ? 1 : -1)), maxRot); rotateObject(door, objPos.rot[0], objPos.rot[1], targetRot); - bool reached = (targetRot == maxRot && state) || targetRot == minRot; + bool reached = (targetRot == maxRot && state != MWWorld::DoorState::Idle) || targetRot == minRot; /// \todo should use convexSweepTest here std::vector collisions = mPhysics->getCollisions(door, MWPhysics::CollisionType_Door, MWPhysics::CollisionType_Actor); @@ -1658,7 +1658,7 @@ namespace MWWorld void World::processDoors(float duration) { - std::map::iterator it = mDoorStates.begin(); + auto it = mDoorStates.begin(); while (it != mDoorStates.end()) { if (!mWorldScene->isCellActive(*it->first.getCell()) || !it->first.getRefData().getBaseNode()) @@ -1675,7 +1675,7 @@ namespace MWWorld if (reached) { // Mark as non-moving - it->first.getClass().setDoorState(it->first, 0); + it->first.getClass().setDoorState(it->first, MWWorld::DoorState::Idle); mDoorStates.erase(it++); } else @@ -2510,32 +2510,32 @@ namespace MWWorld void World::activateDoor(const MWWorld::Ptr& door) { - int state = door.getClass().getDoorState(door); + auto state = door.getClass().getDoorState(door); switch (state) { - case 0: + case MWWorld::DoorState::Idle: if (door.getRefData().getPosition().rot[2] == door.getCellRef().getPosition().rot[2]) - state = 1; // if closed, then open + state = MWWorld::DoorState::Opening; // if closed, then open else - state = 2; // if open, then close + state = MWWorld::DoorState::Closing; // if open, then close break; - case 2: - state = 1; // if closing, then open + case MWWorld::DoorState::Closing: + state = MWWorld::DoorState::Opening; // if closing, then open break; - case 1: + case MWWorld::DoorState::Opening: default: - state = 2; // if opening, then close + state = MWWorld::DoorState::Closing; // if opening, then close break; } door.getClass().setDoorState(door, state); mDoorStates[door] = state; } - void World::activateDoor(const Ptr &door, int state) + void World::activateDoor(const Ptr &door, MWWorld::DoorState state) { door.getClass().setDoorState(door, state); mDoorStates[door] = state; - if (state == 0) + if (state == MWWorld::DoorState::Idle) { mDoorStates.erase(door); rotateDoor(door, state, 1); diff --git a/apps/openmw/mwworld/worldimp.hpp b/apps/openmw/mwworld/worldimp.hpp index 0f090bf8d..76d015477 100644 --- a/apps/openmw/mwworld/worldimp.hpp +++ b/apps/openmw/mwworld/worldimp.hpp @@ -118,7 +118,7 @@ namespace MWWorld int mActivationDistanceOverride; - std::map mDoorStates; + std::map mDoorStates; ///< only holds doors that are currently moving. 1 = opening, 2 = closing std::string mStartCell; @@ -146,7 +146,7 @@ namespace MWWorld private: void PCDropped (const Ptr& item); - bool rotateDoor(const Ptr door, int state, float duration); + bool rotateDoor(const Ptr door, DoorState state, float duration); void processDoors(float duration); ///< Run physics simulation and modify \a world accordingly. @@ -542,7 +542,7 @@ namespace MWWorld /// update movement state of a non-teleport door as specified /// @param state see MWClass::setDoorState /// @note throws an exception when invoked on a teleport door - void activateDoor(const MWWorld::Ptr& door, int state) override; + void activateDoor(const MWWorld::Ptr& door, MWWorld::DoorState state) override; void getActorsStandingOn (const MWWorld::ConstPtr& object, std::vector &actors) override; ///< get a list of actors standing on \a object bool getPlayerStandingOn (const MWWorld::ConstPtr& object) override; ///< @return true if the player is standing on \a object From c0438a0c6ba18f72ae815e7046ad36d6f00434d7 Mon Sep 17 00:00:00 2001 From: Capostrophic Date: Mon, 26 Aug 2019 22:59:51 +0300 Subject: [PATCH 06/20] Avoid using getPtr on empty geometry data --- components/nifosg/nifloader.cpp | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/components/nifosg/nifloader.cpp b/components/nifosg/nifloader.cpp index e199a3b72..568286a4d 100644 --- a/components/nifosg/nifloader.cpp +++ b/components/nifosg/nifloader.cpp @@ -1072,8 +1072,9 @@ namespace NifOsg if (nifNode->recType == Nif::RC_NiTriShape) { const Nif::NiTriShape* triShape = static_cast(nifNode); - if (const Nif::NiTriShapeData* data = triShape->data.getPtr()) + if (!triShape->data.empty()) { + const Nif::NiTriShapeData* data = triShape->data.getPtr(); vertexColorsPresent = !data->colors.empty(); triCommonToGeometry(geometry, data->vertices, data->normals, data->uvlist, data->colors, boundTextures, triShape->name); if (!data->triangles.empty()) @@ -1084,8 +1085,9 @@ namespace NifOsg else { const Nif::NiTriStrips* triStrips = static_cast(nifNode); - if (const Nif::NiTriStripsData* data = triStrips->data.getPtr()) + if (!triStrips->data.empty()) { + const Nif::NiTriStripsData* data = triStrips->data.getPtr(); vertexColorsPresent = !data->colors.empty(); triCommonToGeometry(geometry, data->vertices, data->normals, data->uvlist, data->colors, boundTextures, triStrips->name); if (!data->strips.empty()) From c059bf04cc01737f82470dbf15fef5dc73830ac7 Mon Sep 17 00:00:00 2001 From: Andrei Kortunov Date: Tue, 27 Aug 2019 09:55:02 +0400 Subject: [PATCH 07/20] Rename getWeaponPart() function --- apps/openmw/mwrender/actoranimation.cpp | 6 +++--- apps/openmw/mwrender/actoranimation.hpp | 6 +++--- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/apps/openmw/mwrender/actoranimation.cpp b/apps/openmw/mwrender/actoranimation.cpp index abc2e4eb3..d05215b72 100644 --- a/apps/openmw/mwrender/actoranimation.cpp +++ b/apps/openmw/mwrender/actoranimation.cpp @@ -64,7 +64,7 @@ ActorAnimation::~ActorAnimation() mScabbard.reset(); } -PartHolderPtr ActorAnimation::getWeaponPart(const std::string& model, const std::string& bonename, bool enchantedGlow, osg::Vec4f* glowColor) +PartHolderPtr ActorAnimation::attachMesh(const std::string& model, const std::string& bonename, bool enchantedGlow, osg::Vec4f* glowColor) { osg::Group* parent = getBoneByName(bonename); if (!parent) @@ -160,7 +160,7 @@ void ActorAnimation::updateHolsteredWeapon(bool showHolsteredWeapons) if (showHolsteredWeapons) { osg::Vec4f glowColor = weapon->getClass().getEnchantmentColor(*weapon); - mScabbard = getWeaponPart(mesh, boneName, isEnchanted, &glowColor); + mScabbard = attachMesh(mesh, boneName, isEnchanted, &glowColor); if (mScabbard) resetControllers(mScabbard->getNode()); } @@ -168,7 +168,7 @@ void ActorAnimation::updateHolsteredWeapon(bool showHolsteredWeapons) return; } - mScabbard = getWeaponPart(scabbardName, boneName); + mScabbard = attachMesh(scabbardName, boneName); osg::Group* weaponNode = getBoneByName("Bip01 Weapon"); if (!weaponNode) diff --git a/apps/openmw/mwrender/actoranimation.hpp b/apps/openmw/mwrender/actoranimation.hpp index f1f6f6ca8..038dcde6d 100644 --- a/apps/openmw/mwrender/actoranimation.hpp +++ b/apps/openmw/mwrender/actoranimation.hpp @@ -44,11 +44,11 @@ class ActorAnimation : public Animation, public MWWorld::ContainerStoreListener virtual void updateHolsteredWeapon(bool showHolsteredWeapons); virtual void updateQuiver(); virtual std::string getHolsteredWeaponBoneName(const MWWorld::ConstPtr& weapon); - virtual PartHolderPtr getWeaponPart(const std::string& model, const std::string& bonename, bool enchantedGlow, osg::Vec4f* glowColor); - virtual PartHolderPtr getWeaponPart(const std::string& model, const std::string& bonename) + virtual PartHolderPtr attachMesh(const std::string& model, const std::string& bonename, bool enchantedGlow, osg::Vec4f* glowColor); + virtual PartHolderPtr attachMesh(const std::string& model, const std::string& bonename) { osg::Vec4f stubColor = osg::Vec4f(0,0,0,0); - return getWeaponPart(model, bonename, false, &stubColor); + return attachMesh(model, bonename, false, &stubColor); }; PartHolderPtr mScabbard; From b6044d231a1b6bf7a49faddb5a6e173bfd5c6473 Mon Sep 17 00:00:00 2001 From: Andrei Kortunov Date: Tue, 27 Aug 2019 22:42:41 +0400 Subject: [PATCH 08/20] Handle death event manually before disposing a corpse if a death animation was not finished yet (feature #5146) --- CHANGELOG.md | 1 + apps/openmw/mwbase/mechanicsmanager.hpp | 2 ++ apps/openmw/mwgui/container.cpp | 22 +++++++++++++++++++ apps/openmw/mwmechanics/actors.cpp | 11 +++++++--- apps/openmw/mwmechanics/actors.hpp | 2 ++ .../mwmechanics/mechanicsmanagerimp.cpp | 5 +++++ .../mwmechanics/mechanicsmanagerimp.hpp | 2 ++ .../reference/modding/settings/game.rst | 7 ++---- files/ui/advancedpage.ui | 2 +- 9 files changed, 45 insertions(+), 9 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 65adf8add..21ce44a2a 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -176,6 +176,7 @@ Feature #5122: Use magic glow for enchanted arrows Feature #5131: Custom skeleton bones Feature #5132: Unique animations for different weapon types + Feature #5146: Safe Dispose corpse Task #4686: Upgrade media decoder to a more current FFmpeg API Task #4695: Optimize Distant Terrain memory consumption Task #4789: Optimize cell transitions diff --git a/apps/openmw/mwbase/mechanicsmanager.hpp b/apps/openmw/mwbase/mechanicsmanager.hpp index 5c5821bca..56386d4a1 100644 --- a/apps/openmw/mwbase/mechanicsmanager.hpp +++ b/apps/openmw/mwbase/mechanicsmanager.hpp @@ -237,6 +237,8 @@ namespace MWBase virtual float getActorsProcessingRange() const = 0; + virtual void notifyDied(const MWWorld::Ptr& actor) = 0; + virtual bool onOpen(const MWWorld::Ptr& ptr) = 0; virtual void onClose(const MWWorld::Ptr& ptr) = 0; diff --git a/apps/openmw/mwgui/container.cpp b/apps/openmw/mwgui/container.cpp index bfe93f6ed..6a303dfba 100644 --- a/apps/openmw/mwgui/container.cpp +++ b/apps/openmw/mwgui/container.cpp @@ -7,12 +7,15 @@ #include "../mwbase/world.hpp" #include "../mwbase/windowmanager.hpp" #include "../mwbase/mechanicsmanager.hpp" +#include "../mwbase/scriptmanager.hpp" #include "../mwworld/class.hpp" #include "../mwworld/inventorystore.hpp" #include "../mwmechanics/creaturestats.hpp" +#include "../mwscript/interpretercontext.hpp" + #include "countdialog.hpp" #include "inventorywindow.hpp" @@ -229,7 +232,26 @@ namespace MWGui if (mPtr.getClass().isPersistent(mPtr)) MWBase::Environment::get().getWindowManager()->messageBox("#{sDisposeCorpseFail}"); else + { + MWMechanics::CreatureStats& creatureStats = mPtr.getClass().getCreatureStats(mPtr); + + // If we dispose corpse before end of death animation, we should update death counter counter manually. + // Also we should run actor's script - it may react on actor's death. + if (creatureStats.isDead() && !creatureStats.isDeathAnimationFinished()) + { + creatureStats.setDeathAnimationFinished(true); + MWBase::Environment::get().getMechanicsManager()->notifyDied(mPtr); + + const std::string script = mPtr.getClass().getScript(mPtr); + if (!script.empty() && MWBase::Environment::get().getWorld()->getScriptsEnabled()) + { + MWScript::InterpreterContext interpreterContext (&mPtr.getRefData().getLocals(), mPtr); + MWBase::Environment::get().getScriptManager()->run (script, interpreterContext); + } + } + MWBase::Environment::get().getWorld()->deleteObject(mPtr); + } mPtr = MWWorld::Ptr(); } diff --git a/apps/openmw/mwmechanics/actors.cpp b/apps/openmw/mwmechanics/actors.cpp index 929560ef1..ff59ba4b9 100644 --- a/apps/openmw/mwmechanics/actors.cpp +++ b/apps/openmw/mwmechanics/actors.cpp @@ -1630,6 +1630,13 @@ namespace MWMechanics updateCombatMusic(); } + void Actors::notifyDied(const MWWorld::Ptr &actor) + { + actor.getClass().getCreatureStats(actor).notifyDied(); + + ++mDeathCount[Misc::StringUtils::lowerCase(actor.getCellRef().getRefId())]; + } + void Actors::killDeadActors() { for(PtrActorMap::iterator iter(mActors.begin()); iter != mActors.end(); ++iter) @@ -1673,9 +1680,7 @@ namespace MWMechanics } else if (killResult == CharacterController::Result_DeathAnimJustFinished) { - iter->first.getClass().getCreatureStats(iter->first).notifyDied(); - - ++mDeathCount[Misc::StringUtils::lowerCase(iter->first.getCellRef().getRefId())]; + notifyDied(iter->first); // Reset magic effects and recalculate derived effects // One case where we need this is to make sure bound items are removed upon death diff --git a/apps/openmw/mwmechanics/actors.hpp b/apps/openmw/mwmechanics/actors.hpp index 07e60e1d1..9621a8619 100644 --- a/apps/openmw/mwmechanics/actors.hpp +++ b/apps/openmw/mwmechanics/actors.hpp @@ -71,6 +71,8 @@ namespace MWMechanics PtrActorMap::const_iterator begin() { return mActors.begin(); } PtrActorMap::const_iterator end() { return mActors.end(); } + void notifyDied(const MWWorld::Ptr &actor); + /// Check if the target actor was detected by an observer /// If the observer is a non-NPC, check all actors in AI processing distance as observers bool isActorDetected(const MWWorld::Ptr& actor, const MWWorld::Ptr& observer); diff --git a/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp b/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp index fe5f60ec4..7f58ebc46 100644 --- a/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp +++ b/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp @@ -455,6 +455,11 @@ namespace MWMechanics } } + void MechanicsManager::notifyDied(const MWWorld::Ptr& actor) + { + mActors.notifyDied(actor); + } + float MechanicsManager::getActorsProcessingRange() const { return mActors.getProcessingRange(); diff --git a/apps/openmw/mwmechanics/mechanicsmanagerimp.hpp b/apps/openmw/mwmechanics/mechanicsmanagerimp.hpp index a81a6bd75..e0ab039c8 100644 --- a/apps/openmw/mwmechanics/mechanicsmanagerimp.hpp +++ b/apps/openmw/mwmechanics/mechanicsmanagerimp.hpp @@ -211,6 +211,8 @@ namespace MWMechanics virtual float getActorsProcessingRange() const override; + virtual void notifyDied(const MWWorld::Ptr& actor) override; + /// Check if the target actor was detected by an observer /// If the observer is a non-NPC, check all actors in AI processing distance as observers virtual bool isActorDetected(const MWWorld::Ptr& actor, const MWWorld::Ptr& observer) override; diff --git a/docs/source/reference/modding/settings/game.rst b/docs/source/reference/modding/settings/game.rst index 4e397e9c9..7bfa60c6c 100644 --- a/docs/source/reference/modding/settings/game.rst +++ b/docs/source/reference/modding/settings/game.rst @@ -72,13 +72,10 @@ can loot during death animation :Default: True If this setting is true, the player is allowed to loot actors (e.g. summoned creatures) during death animation, -if they are not in combat. However disposing corpses during death animation is not recommended - -death counter may not be incremented, and this behaviour can break quests. -This is how Morrowind behaves. +if they are not in combat. In this case we have to increment death counter and run disposed actor's script instantly. If this setting is false, player has to wait until end of death animation in all cases. -This case is more safe, but makes using of summoned creatures exploit -(looting summoned Dremoras and Golden Saints for expensive weapons) a lot harder. +Makes using of summoned creatures exploit (looting summoned Dremoras and Golden Saints for expensive weapons) a lot harder. Conflicts with mannequin mods, which use SkipAnim to prevent end of death animation. This setting can be toggled in Advanced tab of the launcher. diff --git a/files/ui/advancedpage.ui b/files/ui/advancedpage.ui index f7575cd2b..152ab6411 100644 --- a/files/ui/advancedpage.ui +++ b/files/ui/advancedpage.ui @@ -19,7 +19,7 @@ - <html><head/><body><p>If this setting is true, the player is allowed to loot actors (e.g. summoned creatures) during death animation, if they are not in combat. However disposing corpses during death animation is not recommended - death counter may not be incremented, and this behaviour can break quests. This is how original Morrowind behaves.</p><p>If this setting is false, player has to wait until end of death animation in all cases. This case is more safe, but makes using of summoned creatures exploit (looting summoned Dremoras and Golden Saints for expensive weapons) a lot harder.</p></body></html> + <html><head/><body><p>If this setting is true, the player is allowed to loot actors (e.g. summoned creatures) during death animation, if they are not in combat. In this case we have to increment death counter and run disposed actor's script instantly.</p><p>If this setting is false, player has to wait until end of death animation in all cases. Makes using of summoned creatures exploit (looting summoned Dremoras and Golden Saints for expensive weapons) a lot harder. Conflicts with mannequin mods, which use SkipAnim to prevent end of death animation.</p></body></html> Can loot during death animation From 69b4fe8545264efeeedf5925e10b10f0f7faf236 Mon Sep 17 00:00:00 2001 From: elsid Date: Tue, 27 Aug 2019 20:49:07 +0200 Subject: [PATCH 09/20] Revert "Open door when it is on the way to a next path point" This reverts commit c32872fb16fe826c5409e31111bd50466595abf5. --- apps/openmw/mwbase/world.hpp | 2 -- apps/openmw/mwmechanics/aipackage.cpp | 18 ------------------ apps/openmw/mwmechanics/aipackage.hpp | 2 -- apps/openmw/mwworld/worldimp.cpp | 9 ++------- apps/openmw/mwworld/worldimp.hpp | 2 -- 5 files changed, 2 insertions(+), 31 deletions(-) diff --git a/apps/openmw/mwbase/world.hpp b/apps/openmw/mwbase/world.hpp index 08642eb7f..256c8b1d5 100644 --- a/apps/openmw/mwbase/world.hpp +++ b/apps/openmw/mwbase/world.hpp @@ -306,8 +306,6 @@ namespace MWBase virtual bool castRay (float x1, float y1, float z1, float x2, float y2, float z2) = 0; - virtual MWWorld::Ptr castRay(const osg::Vec3f& from, const osg::Vec3f& to, int mask) const = 0; - virtual void setActorCollisionMode(const MWWorld::Ptr& ptr, bool internal, bool external) = 0; virtual bool isActorCollisionEnabled(const MWWorld::Ptr& ptr) = 0; diff --git a/apps/openmw/mwmechanics/aipackage.cpp b/apps/openmw/mwmechanics/aipackage.cpp index 4395f1e4b..598292fc3 100644 --- a/apps/openmw/mwmechanics/aipackage.cpp +++ b/apps/openmw/mwmechanics/aipackage.cpp @@ -13,8 +13,6 @@ #include "../mwworld/cellstore.hpp" #include "../mwworld/inventorystore.hpp" -#include "../mwphysics/collisiontype.hpp" - #include "pathgrid.hpp" #include "creaturestats.hpp" #include "movement.hpp" @@ -236,9 +234,6 @@ void MWMechanics::AiPackage::openDoors(const MWWorld::Ptr& actor) // note: AiWander currently does not open doors if (getTypeId() != TypeIdWander && !door.getCellRef().getTeleport() && door.getClass().getDoorState(door) == 0) { - if (!isDoorOnTheWay(actor, door)) - return; - if ((door.getCellRef().getTrap().empty() && door.getCellRef().getLockLevel() <= 0 )) { world->activate(door, actor); @@ -407,16 +402,3 @@ DetourNavigator::Flags MWMechanics::AiPackage::getNavigatorFlags(const MWWorld:: return result; } - -bool MWMechanics::AiPackage::isDoorOnTheWay(const MWWorld::Ptr& actor, const MWWorld::Ptr& door) const -{ - if (mPathFinder.getPathSize() == 0) - return false; - - 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 = mPathFinder.getPath().front() + osg::Vec3f(0, 0, halfExtents.z()); - - return world->castRay(position, destination, MWPhysics::CollisionType_Door) == door; -} diff --git a/apps/openmw/mwmechanics/aipackage.hpp b/apps/openmw/mwmechanics/aipackage.hpp index 0f7b5cf1d..6bb12342a 100644 --- a/apps/openmw/mwmechanics/aipackage.hpp +++ b/apps/openmw/mwmechanics/aipackage.hpp @@ -147,8 +147,6 @@ namespace MWMechanics private: bool isNearInactiveCell(osg::Vec3f position); - - bool isDoorOnTheWay(const MWWorld::Ptr& actor, const MWWorld::Ptr& door) const; }; } diff --git a/apps/openmw/mwworld/worldimp.cpp b/apps/openmw/mwworld/worldimp.cpp index d285d04ca..ce253b8ba 100644 --- a/apps/openmw/mwworld/worldimp.cpp +++ b/apps/openmw/mwworld/worldimp.cpp @@ -1610,13 +1610,8 @@ namespace MWWorld osg::Vec3f a(x1,y1,z1); osg::Vec3f b(x2,y2,z2); - return !castRay(a, b, mask).isEmpty(); - } - - MWWorld::Ptr World::castRay(const osg::Vec3f& from, const osg::Vec3f& to, int mask) const - { - const auto result = mPhysics->castRay(from, to, MWWorld::Ptr(), std::vector(), mask); - return result.mHit ? result.mHitObject : MWWorld::Ptr(); + MWPhysics::PhysicsSystem::RayResult result = mPhysics->castRay(a, b, MWWorld::Ptr(), std::vector(), mask); + return result.mHit; } void World::processDoors(float duration) diff --git a/apps/openmw/mwworld/worldimp.hpp b/apps/openmw/mwworld/worldimp.hpp index 0acbc5926..dd915c8bd 100644 --- a/apps/openmw/mwworld/worldimp.hpp +++ b/apps/openmw/mwworld/worldimp.hpp @@ -420,8 +420,6 @@ namespace MWWorld bool castRay (float x1, float y1, float z1, float x2, float y2, float z2) override; - MWWorld::Ptr castRay (const osg::Vec3f& from, const osg::Vec3f& to, int mask) const override; - void setActorCollisionMode(const Ptr& ptr, bool internal, bool external) override; bool isActorCollisionEnabled(const Ptr& ptr) override; From 389f5dfb9b834e012d464abf41c578d1c03ffe7d Mon Sep 17 00:00:00 2001 From: elsid Date: Sun, 25 Aug 2019 18:11:13 +0200 Subject: [PATCH 10/20] 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 97cd9d434a8cbcf689dd046afb0fb216451d29f8 Mon Sep 17 00:00:00 2001 From: elsid Date: Sun, 25 Aug 2019 13:49:04 +0200 Subject: [PATCH 11/20] 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 b4ec4440573979b222a5c8be5296e8fb80772282 Mon Sep 17 00:00:00 2001 From: elsid Date: Thu, 15 Aug 2019 19:19:04 +0200 Subject: [PATCH 12/20] Open door when it is on the way to a next path point --- apps/openmw/mwbase/world.hpp | 2 ++ apps/openmw/mwmechanics/aipackage.cpp | 15 +++++++++++++++ apps/openmw/mwmechanics/aipackage.hpp | 2 ++ apps/openmw/mwworld/worldimp.cpp | 20 ++++++++++++++++++++ apps/openmw/mwworld/worldimp.hpp | 2 ++ 5 files changed, 41 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..c834f6984 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" @@ -240,6 +242,9 @@ void MWMechanics::AiPackage::openDoors(const MWWorld::Ptr& actor) if (!door.getCellRef().getTeleport() && door.getClass().getDoorState(door) == MWWorld::DoorState::Idle) { + if (!isDoorOnTheWay(actor, door)) + return; + if ((door.getCellRef().getTrap().empty() && door.getCellRef().getLockLevel() <= 0 )) { world->activate(door, actor); @@ -408,3 +413,13 @@ DetourNavigator::Flags MWMechanics::AiPackage::getNavigatorFlags(const MWWorld:: return result; } + +bool MWMechanics::AiPackage::isDoorOnTheWay(const MWWorld::Ptr& actor, const MWWorld::Ptr& door) const +{ + 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 = mPathFinder.getPath().front() + osg::Vec3f(0, 0, halfExtents.z()); + + return world->hasCollisionWithDoor(door, position, destination); +} diff --git a/apps/openmw/mwmechanics/aipackage.hpp b/apps/openmw/mwmechanics/aipackage.hpp index 6bb12342a..0f7b5cf1d 100644 --- a/apps/openmw/mwmechanics/aipackage.hpp +++ b/apps/openmw/mwmechanics/aipackage.hpp @@ -147,6 +147,8 @@ namespace MWMechanics private: bool isNearInactiveCell(osg::Vec3f position); + + bool isDoorOnTheWay(const MWWorld::Ptr& actor, const MWWorld::Ptr& door) const; }; } diff --git a/apps/openmw/mwworld/worldimp.cpp b/apps/openmw/mwworld/worldimp.cpp index 3ea994683..908e5c052 100644 --- a/apps/openmw/mwworld/worldimp.cpp +++ b/apps/openmw/mwworld/worldimp.cpp @@ -15,6 +15,7 @@ #include #include #include +#include #include @@ -3829,4 +3830,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 41ad23ebdca2b90841210f45c34d365062483999 Mon Sep 17 00:00:00 2001 From: Roman Siromakha Date: Tue, 27 Aug 2019 20:55:03 +0200 Subject: [PATCH 13/20] Revert "[WIP] Open door when it is on the way to a next path point (bug #5073)" --- apps/openmw/mwbase/world.hpp | 2 -- apps/openmw/mwmechanics/aipackage.cpp | 25 ++----------------------- apps/openmw/mwmechanics/aipackage.hpp | 2 -- apps/openmw/mwworld/worldimp.cpp | 20 -------------------- apps/openmw/mwworld/worldimp.hpp | 2 -- 5 files changed, 2 insertions(+), 49 deletions(-) diff --git a/apps/openmw/mwbase/world.hpp b/apps/openmw/mwbase/world.hpp index 8c6829eb3..955e77168 100644 --- a/apps/openmw/mwbase/world.hpp +++ b/apps/openmw/mwbase/world.hpp @@ -614,8 +614,6 @@ 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 c834f6984..646b37669 100644 --- a/apps/openmw/mwmechanics/aipackage.cpp +++ b/apps/openmw/mwmechanics/aipackage.cpp @@ -13,8 +13,6 @@ #include "../mwworld/cellstore.hpp" #include "../mwworld/inventorystore.hpp" -#include "../mwphysics/collisiontype.hpp" - #include "pathgrid.hpp" #include "creaturestats.hpp" #include "movement.hpp" @@ -226,13 +224,6 @@ 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; - - if (mPathFinder.getPathSize() == 0) - return; - MWBase::World* world = MWBase::Environment::get().getWorld(); static float distance = world->getMaxActivationDistance(); @@ -240,11 +231,9 @@ void MWMechanics::AiPackage::openDoors(const MWWorld::Ptr& actor) if (door == MWWorld::Ptr()) return; - if (!door.getCellRef().getTeleport() && door.getClass().getDoorState(door) == MWWorld::DoorState::Idle) + // note: AiWander currently does not open doors + if (getTypeId() != TypeIdWander && !door.getCellRef().getTeleport() && door.getClass().getDoorState(door) == MWWorld::DoorState::Idle) { - if (!isDoorOnTheWay(actor, door)) - return; - if ((door.getCellRef().getTrap().empty() && door.getCellRef().getLockLevel() <= 0 )) { world->activate(door, actor); @@ -413,13 +402,3 @@ DetourNavigator::Flags MWMechanics::AiPackage::getNavigatorFlags(const MWWorld:: return result; } - -bool MWMechanics::AiPackage::isDoorOnTheWay(const MWWorld::Ptr& actor, const MWWorld::Ptr& door) const -{ - 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 = mPathFinder.getPath().front() + osg::Vec3f(0, 0, halfExtents.z()); - - return world->hasCollisionWithDoor(door, position, destination); -} diff --git a/apps/openmw/mwmechanics/aipackage.hpp b/apps/openmw/mwmechanics/aipackage.hpp index 0f7b5cf1d..6bb12342a 100644 --- a/apps/openmw/mwmechanics/aipackage.hpp +++ b/apps/openmw/mwmechanics/aipackage.hpp @@ -147,8 +147,6 @@ namespace MWMechanics private: bool isNearInactiveCell(osg::Vec3f position); - - bool isDoorOnTheWay(const MWWorld::Ptr& actor, const MWWorld::Ptr& door) const; }; } diff --git a/apps/openmw/mwworld/worldimp.cpp b/apps/openmw/mwworld/worldimp.cpp index 908e5c052..3ea994683 100644 --- a/apps/openmw/mwworld/worldimp.cpp +++ b/apps/openmw/mwworld/worldimp.cpp @@ -15,7 +15,6 @@ #include #include #include -#include #include @@ -3830,23 +3829,4 @@ 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 bd34087ac..76d015477 100644 --- a/apps/openmw/mwworld/worldimp.hpp +++ b/apps/openmw/mwworld/worldimp.hpp @@ -719,8 +719,6 @@ 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 1cd1bfca741ac5fc1a90987b4d8398d118af8052 Mon Sep 17 00:00:00 2001 From: James Stephens Date: Mon, 2 Sep 2019 16:49:29 +0200 Subject: [PATCH 14/20] Fixes bug #4650 --- AUTHORS.md | 1 + CHANGELOG.md | 1 + apps/openmw/mwgui/confirmationdialog.cpp | 3 +-- 3 files changed, 3 insertions(+), 2 deletions(-) diff --git a/AUTHORS.md b/AUTHORS.md index c64b83dab..a18fb42a1 100644 --- a/AUTHORS.md +++ b/AUTHORS.md @@ -86,6 +86,7 @@ Programmers Jacob Essex (Yacoby) Jake Westrip (16bitint) James Carty (MrTopCat) + James Stephens (james-h-stephens) Jan-Peter Nilsson (peppe) Jan Borsodi (am0s) Jason Hooks (jhooks) diff --git a/CHANGELOG.md b/CHANGELOG.md index 21ce44a2a..345973314 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -27,6 +27,7 @@ Bug #4540: Rain delay when exiting water Bug #4600: Crash when no sound output is available or --no-sound is used. Bug #4639: Black screen after completing first mages guild mission + training + Bug #4650: Focus is lost after pressing ESC in confirmation dialog inside savegame dialog Bug #4701: PrisonMarker record is not hardcoded like other markers Bug #4703: Editor: it's possible to preview levelled list records Bug #4705: Editor: unable to open exterior cell views from Instances table diff --git a/apps/openmw/mwgui/confirmationdialog.cpp b/apps/openmw/mwgui/confirmationdialog.cpp index 65b079d85..9ebaf3919 100644 --- a/apps/openmw/mwgui/confirmationdialog.cpp +++ b/apps/openmw/mwgui/confirmationdialog.cpp @@ -40,14 +40,13 @@ namespace MWGui bool ConfirmationDialog::exit() { + setVisible(false); eventCancelClicked(); return true; } void ConfirmationDialog::onCancelButtonClicked(MyGUI::Widget* _sender) { - setVisible(false); - exit(); } From b33429001cae9a85a3edb946e74788fb2929cad1 Mon Sep 17 00:00:00 2001 From: James Stephens Date: Mon, 2 Sep 2019 17:13:56 +0000 Subject: [PATCH 15/20] Fixes the offset question mark in the alchemy tooltip when the effect is not known --- CHANGELOG.md | 1 + apps/openmw/mwgui/widgets.cpp | 5 +++-- apps/openmw/mwgui/widgets.hpp | 3 ++- 3 files changed, 6 insertions(+), 3 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 345973314..64af4b849 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -129,6 +129,7 @@ Bug #5106: Still can jump even when encumbered Bug #5110: ModRegion with a redundant numerical argument breaks script execution Bug #5112: Insufficient magicka for current spell not reflected on HUD icon + Bug #5113: Unknown alchemy question mark not centered Bug #5123: Script won't run on respawn Bug #5124: Arrow remains attached to actor if pulling animation was cancelled Bug #5126: Swimming creatures without RunForward animations are motionless during combat diff --git a/apps/openmw/mwgui/widgets.cpp b/apps/openmw/mwgui/widgets.cpp index 6e3e081a9..0568efeb4 100644 --- a/apps/openmw/mwgui/widgets.cpp +++ b/apps/openmw/mwgui/widgets.cpp @@ -375,7 +375,8 @@ namespace MWGui if (!mEffectParams.mKnown) { mTextWidget->setCaption ("?"); - mRequestedWidth = mTextWidget->getTextSize().width + 24; + mTextWidget->setCoord(sIconOffset / 2, mTextWidget->getCoord().top, mTextWidget->getCoord().width, mTextWidget->getCoord().height); // Compensates for the missing image when effect is not known + mRequestedWidth = mTextWidget->getTextSize().width + sIconOffset; mImageWidget->setImageTexture (""); return; } @@ -466,7 +467,7 @@ namespace MWGui } mTextWidget->setCaptionWithReplacing(spellLine); - mRequestedWidth = mTextWidget->getTextSize().width + 24; + mRequestedWidth = mTextWidget->getTextSize().width + sIconOffset; mImageWidget->setImageTexture(MWBase::Environment::get().getWindowManager()->correctIconPath(magicEffect->mIcon)); } diff --git a/apps/openmw/mwgui/widgets.hpp b/apps/openmw/mwgui/widgets.hpp index 6eab431d6..4b42b888a 100644 --- a/apps/openmw/mwgui/widgets.hpp +++ b/apps/openmw/mwgui/widgets.hpp @@ -268,7 +268,8 @@ namespace MWGui virtual void initialiseOverride(); private: - + static const int sIconOffset = 24; + void updateWidgets(); SpellEffectParams mEffectParams; From 7d3f6e1cd91093f2d61ac42feb828d3c8b4a11ca Mon Sep 17 00:00:00 2001 From: James Stephens Date: Mon, 2 Sep 2019 17:18:56 +0000 Subject: [PATCH 16/20] Altered process so that cost only appears on spell purchase window. Added myself to authors --- CHANGELOG.md | 1 + apps/openmw/mwgui/spellbuyingwindow.cpp | 1 + apps/openmw/mwgui/tooltips.cpp | 3 +++ 3 files changed, 5 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 64af4b849..46f44ea06 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -179,6 +179,7 @@ Feature #5131: Custom skeleton bones Feature #5132: Unique animations for different weapon types Feature #5146: Safe Dispose corpse + Feature #5147: Show spell magicka cost in spell buying window Task #4686: Upgrade media decoder to a more current FFmpeg API Task #4695: Optimize Distant Terrain memory consumption Task #4789: Optimize cell transitions diff --git a/apps/openmw/mwgui/spellbuyingwindow.cpp b/apps/openmw/mwgui/spellbuyingwindow.cpp index 5fb361579..eea98a768 100644 --- a/apps/openmw/mwgui/spellbuyingwindow.cpp +++ b/apps/openmw/mwgui/spellbuyingwindow.cpp @@ -70,6 +70,7 @@ namespace MWGui toAdd->eventMouseWheel += MyGUI::newDelegate(this, &SpellBuyingWindow::onMouseWheel); toAdd->setUserString("ToolTipType", "Spell"); toAdd->setUserString("Spell", spell.mId); + toAdd->setUserString("SpellCost", std::to_string(spell.mData.mCost)); toAdd->eventMouseButtonClick += MyGUI::newDelegate(this, &SpellBuyingWindow::onSpellButtonClick); mSpellsWidgetMap.insert(std::make_pair (toAdd, spell.mId)); } diff --git a/apps/openmw/mwgui/tooltips.cpp b/apps/openmw/mwgui/tooltips.cpp index 7d8a07c21..3891cf8a2 100644 --- a/apps/openmw/mwgui/tooltips.cpp +++ b/apps/openmw/mwgui/tooltips.cpp @@ -249,6 +249,9 @@ namespace MWGui int school = MWMechanics::getSpellSchool(spell, player); info.text = "#{sSchool}: " + sSchoolNames[school]; } + std::string cost = focus->getUserString("SpellCost"); + if (cost != "" && cost != "0") + info.text += MWGui::ToolTips::getValueString(spell->mData.mCost, "#{sCastCost}"); info.effects = effects; tooltipSize = createToolTip(info); } From 2daecc633e758ef03118f8a2449f5c98e6804cc6 Mon Sep 17 00:00:00 2001 From: Alexei Dobrohotov Date: Wed, 4 Sep 2019 16:42:34 +0300 Subject: [PATCH 17/20] Revert Vampirism behavior upon death to 0.45.0-like state Until we figure out the better way to handle vampire stuff tangled together with post-death animation magic effect reset. --- apps/openmw/mwmechanics/character.cpp | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/apps/openmw/mwmechanics/character.cpp b/apps/openmw/mwmechanics/character.cpp index 1b5c193c4..9b6c1e0c3 100644 --- a/apps/openmw/mwmechanics/character.cpp +++ b/apps/openmw/mwmechanics/character.cpp @@ -2580,11 +2580,15 @@ void CharacterController::updateMagicEffects() if (!mPtr.getClass().isActor()) return; - bool vampire = mPtr.getClass().getCreatureStats(mPtr).getMagicEffects().get(ESM::MagicEffect::Vampirism).getMagnitude() > 0.0f; - mAnimation->setVampire(vampire); - float light = mPtr.getClass().getCreatureStats(mPtr).getMagicEffects().get(ESM::MagicEffect::Light).getMagnitude(); mAnimation->setLightEffect(light); + + // If you're dead you don't care about whether you've started/stopped being a vampire or not + if (mPtr.getClass().getCreatureStats(mPtr).isDead()) + return; + + bool vampire = mPtr.getClass().getCreatureStats(mPtr).getMagicEffects().get(ESM::MagicEffect::Vampirism).getMagnitude() > 0.0f; + mAnimation->setVampire(vampire); } void CharacterController::setVisibility(float visibility) From bafbc0a0559b0c0c8cf0f0b95c5ce690731b7e2e Mon Sep 17 00:00:00 2001 From: James Stephens Date: Thu, 5 Sep 2019 07:49:53 +0000 Subject: [PATCH 18/20] Cancel door sound if collision is detected and the sound is playing --- CHANGELOG.md | 1 + apps/openmw/mwworld/worldimp.cpp | 22 ++++++++++++++++++++++ 2 files changed, 23 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 46f44ea06..42565e87d 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -18,6 +18,7 @@ Bug #3894: Hostile spell effects not detected/present on first frame of OnPCHitMe Bug #4202: Open .omwaddon files without needing toopen openmw-cs first Bug #4240: Ash storm origin coordinates and hand shielding animation behavior are incorrect + Bug #4270: Closing doors while they are obstructed desyncs closing sfx Bug #4276: Resizing character window differs from vanilla Bug #4329: Removed birthsign abilities are restored after reloading the save Bug #4341: Error message about missing GDB is too vague diff --git a/apps/openmw/mwworld/worldimp.cpp b/apps/openmw/mwworld/worldimp.cpp index 3ea994683..07680e76f 100644 --- a/apps/openmw/mwworld/worldimp.cpp +++ b/apps/openmw/mwworld/worldimp.cpp @@ -1632,11 +1632,14 @@ namespace MWWorld bool reached = (targetRot == maxRot && state != MWWorld::DoorState::Idle) || targetRot == minRot; /// \todo should use convexSweepTest here + bool collisionWithActor = false; std::vector collisions = mPhysics->getCollisions(door, MWPhysics::CollisionType_Door, MWPhysics::CollisionType_Actor); for (MWWorld::Ptr& ptr : collisions) { if (ptr.getClass().isActor()) { + collisionWithActor = true; + // Collided with actor, ask actor to try to avoid door if(ptr != getPlayerPtr() ) { @@ -1651,6 +1654,25 @@ namespace MWWorld } } + // Cancel door closing sound if collision with actor is detected + if (collisionWithActor) + { + const ESM::Door* ref = door.get()->mBase; + + if (state == MWWorld::DoorState::Opening) + { + const std::string& openSound = ref->mOpenSound; + if (!openSound.empty() && MWBase::Environment::get().getSoundManager()->getSoundPlaying(door, openSound)) + MWBase::Environment::get().getSoundManager()->stopSound3D(door, openSound); + } + else if (state == MWWorld::DoorState::Closing) + { + const std::string& closeSound = ref->mCloseSound; + if (!closeSound.empty() && MWBase::Environment::get().getSoundManager()->getSoundPlaying(door, closeSound)) + MWBase::Environment::get().getSoundManager()->stopSound3D(door, closeSound); + } + } + // the rotation order we want to use mWorldScene->updateObjectRotation(door, false); return reached; From 8317dc07099827d287450e90bc0e2a761f3bf6a9 Mon Sep 17 00:00:00 2001 From: Capostrophic Date: Wed, 4 Sep 2019 00:39:12 +0300 Subject: [PATCH 19/20] Make sure failed pick/trap attempts are a crime (bug #5149) --- CHANGELOG.md | 1 + apps/openmw/mwmechanics/security.cpp | 4 ++-- apps/openmw/mwmechanics/spellcasting.cpp | 8 +++++--- 3 files changed, 8 insertions(+), 5 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 46f44ea06..3a10198d8 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -135,6 +135,7 @@ Bug #5126: Swimming creatures without RunForward animations are motionless during combat Bug #5134: Doors rotation by "Lock" console command is inconsistent Bug #5137: Textures with Clamp Mode set to Clamp instead of Wrap are too dark outside the boundaries + Bug #5149: Failing lock pick attempts isn't always a crime Feature #1774: Handle AvoidNode Feature #2229: Improve pathfinding AI Feature #3025: Analogue gamepad movement controls diff --git a/apps/openmw/mwmechanics/security.cpp b/apps/openmw/mwmechanics/security.cpp index f1aa6bf8e..749d654b3 100644 --- a/apps/openmw/mwmechanics/security.cpp +++ b/apps/openmw/mwmechanics/security.cpp @@ -48,7 +48,6 @@ namespace MWMechanics resultMessage = "#{sLockImpossible}"; else { - MWBase::Environment::get().getMechanicsManager()->objectOpened(mActor, lock); if (Misc::Rng::roll0to99() <= x) { lock.getClass().unlock(lock); @@ -60,6 +59,7 @@ namespace MWMechanics resultMessage = "#{sLockFail}"; } + MWBase::Environment::get().getMechanicsManager()->objectOpened(mActor, lock); int uses = lockpick.getClass().getItemHealth(lockpick); --uses; lockpick.getCellRef().setCharge(uses); @@ -89,7 +89,6 @@ namespace MWMechanics resultMessage = "#{sTrapImpossible}"; else { - MWBase::Environment::get().getMechanicsManager()->objectOpened(mActor, trap); if (Misc::Rng::roll0to99() <= x) { trap.getCellRef().setTrap(""); @@ -102,6 +101,7 @@ namespace MWMechanics resultMessage = "#{sTrapFail}"; } + MWBase::Environment::get().getMechanicsManager()->objectOpened(mActor, trap); int uses = probe.getClass().getItemHealth(probe); --uses; probe.getCellRef().setCharge(uses); diff --git a/apps/openmw/mwmechanics/spellcasting.cpp b/apps/openmw/mwmechanics/spellcasting.cpp index f8dd11a0e..e16c1bf09 100644 --- a/apps/openmw/mwmechanics/spellcasting.cpp +++ b/apps/openmw/mwmechanics/spellcasting.cpp @@ -712,9 +712,6 @@ namespace MWMechanics if (target.getCellRef().getLockLevel() > 0) { MWBase::Environment::get().getSoundManager()->playSound3D(target, "Open Lock", 1.f, 1.f); - if (!caster.isEmpty()) - MWBase::Environment::get().getMechanicsManager()->objectOpened(getPlayer(), target); - // Use the player instead of the caster for vanilla crime compatibility if (caster == getPlayer()) MWBase::Environment::get().getWindowManager()->messageBox("#{sMagicOpenSuccess}"); @@ -723,6 +720,11 @@ namespace MWMechanics } else MWBase::Environment::get().getSoundManager()->playSound3D(target, "Open Lock Fail", 1.f, 1.f); + + // Failed attempt is a crime too + if (!caster.isEmpty()) + MWBase::Environment::get().getMechanicsManager()->objectOpened(getPlayer(), target); + // Use the player instead of the caster for vanilla crime compatibility return true; } } From c89c14bb6812c5a30b13963a87bb171233bee1bb Mon Sep 17 00:00:00 2001 From: Capostrophic Date: Thu, 5 Sep 2019 17:36:49 +0300 Subject: [PATCH 20/20] Rename objectOpened() to make its role more clear --- apps/openmw/mwbase/mechanicsmanager.hpp | 4 ++-- apps/openmw/mwmechanics/mechanicsmanagerimp.cpp | 2 +- apps/openmw/mwmechanics/mechanicsmanagerimp.hpp | 4 ++-- apps/openmw/mwmechanics/security.cpp | 4 ++-- apps/openmw/mwmechanics/spellcasting.cpp | 3 +-- 5 files changed, 8 insertions(+), 9 deletions(-) diff --git a/apps/openmw/mwbase/mechanicsmanager.hpp b/apps/openmw/mwbase/mechanicsmanager.hpp index 56386d4a1..aecff2cc6 100644 --- a/apps/openmw/mwbase/mechanicsmanager.hpp +++ b/apps/openmw/mwbase/mechanicsmanager.hpp @@ -143,8 +143,8 @@ namespace MWBase /// @param container The container the item is in; may be empty for an item in the world virtual void itemTaken (const MWWorld::Ptr& ptr, const MWWorld::Ptr& item, const MWWorld::Ptr& container, int count, bool alarm = true) = 0; - /// Utility to check if opening (i.e. unlocking) this object is illegal and calling commitCrime if so - virtual void objectOpened (const MWWorld::Ptr& ptr, const MWWorld::Ptr& item) = 0; + /// Utility to check if unlocking this object is illegal and calling commitCrime if so + virtual void unlockAttempted (const MWWorld::Ptr& ptr, const MWWorld::Ptr& item) = 0; /// Attempt sleeping in a bed. If this is illegal, call commitCrime. /// @return was it illegal, and someone saw you doing it? virtual bool sleepInBed (const MWWorld::Ptr& ptr, const MWWorld::Ptr& bed) = 0; diff --git a/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp b/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp index 7f58ebc46..c39487493 100644 --- a/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp +++ b/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp @@ -1034,7 +1034,7 @@ namespace MWMechanics return false; } - void MechanicsManager::objectOpened(const MWWorld::Ptr &ptr, const MWWorld::Ptr &item) + void MechanicsManager::unlockAttempted(const MWWorld::Ptr &ptr, const MWWorld::Ptr &item) { MWWorld::Ptr victim; if (isAllowedToUse(ptr, item, victim)) diff --git a/apps/openmw/mwmechanics/mechanicsmanagerimp.hpp b/apps/openmw/mwmechanics/mechanicsmanagerimp.hpp index e0ab039c8..5a8826a6a 100644 --- a/apps/openmw/mwmechanics/mechanicsmanagerimp.hpp +++ b/apps/openmw/mwmechanics/mechanicsmanagerimp.hpp @@ -142,8 +142,8 @@ namespace MWMechanics /// @param container The container the item is in; may be empty for an item in the world virtual void itemTaken (const MWWorld::Ptr& ptr, const MWWorld::Ptr& item, const MWWorld::Ptr& container, int count, bool alarm = true) override; - /// Utility to check if opening (i.e. unlocking) this object is illegal and calling commitCrime if so - virtual void objectOpened (const MWWorld::Ptr& ptr, const MWWorld::Ptr& item) override; + /// Utility to check if unlocking this object is illegal and calling commitCrime if so + virtual void unlockAttempted (const MWWorld::Ptr& ptr, const MWWorld::Ptr& item) override; /// Attempt sleeping in a bed. If this is illegal, call commitCrime. /// @return was it illegal, and someone saw you doing it? Also returns fail when enemies are nearby virtual bool sleepInBed (const MWWorld::Ptr& ptr, const MWWorld::Ptr& bed) override; diff --git a/apps/openmw/mwmechanics/security.cpp b/apps/openmw/mwmechanics/security.cpp index 749d654b3..d09355cca 100644 --- a/apps/openmw/mwmechanics/security.cpp +++ b/apps/openmw/mwmechanics/security.cpp @@ -59,7 +59,7 @@ namespace MWMechanics resultMessage = "#{sLockFail}"; } - MWBase::Environment::get().getMechanicsManager()->objectOpened(mActor, lock); + MWBase::Environment::get().getMechanicsManager()->unlockAttempted(mActor, lock); int uses = lockpick.getClass().getItemHealth(lockpick); --uses; lockpick.getCellRef().setCharge(uses); @@ -101,7 +101,7 @@ namespace MWMechanics resultMessage = "#{sTrapFail}"; } - MWBase::Environment::get().getMechanicsManager()->objectOpened(mActor, trap); + MWBase::Environment::get().getMechanicsManager()->unlockAttempted(mActor, trap); int uses = probe.getClass().getItemHealth(probe); --uses; probe.getCellRef().setCharge(uses); diff --git a/apps/openmw/mwmechanics/spellcasting.cpp b/apps/openmw/mwmechanics/spellcasting.cpp index e16c1bf09..359e74fc6 100644 --- a/apps/openmw/mwmechanics/spellcasting.cpp +++ b/apps/openmw/mwmechanics/spellcasting.cpp @@ -721,9 +721,8 @@ namespace MWMechanics else MWBase::Environment::get().getSoundManager()->playSound3D(target, "Open Lock Fail", 1.f, 1.f); - // Failed attempt is a crime too if (!caster.isEmpty()) - MWBase::Environment::get().getMechanicsManager()->objectOpened(getPlayer(), target); + MWBase::Environment::get().getMechanicsManager()->unlockAttempted(getPlayer(), target); // Use the player instead of the caster for vanilla crime compatibility return true; }