diff --git a/CHANGELOG.md b/CHANGELOG.md index 9bcf6f1d2..557fdda45 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -14,6 +14,7 @@ Feature #3442: Default values for fallbacks from ini file Feature #3610: Option to invert X axis Feature #4673: Weapon sheathing + Feature #4730: Native animated containers support Task #4686: Upgrade media decoder to a more current FFmpeg API 0.45.0 diff --git a/apps/openmw/mwbase/mechanicsmanager.hpp b/apps/openmw/mwbase/mechanicsmanager.hpp index 056628211..1bdd8f8b5 100644 --- a/apps/openmw/mwbase/mechanicsmanager.hpp +++ b/apps/openmw/mwbase/mechanicsmanager.hpp @@ -237,6 +237,9 @@ namespace MWBase virtual float getActorsProcessingRange() const = 0; + virtual bool onOpen(const MWWorld::Ptr& ptr) = 0; + virtual void onClose(const MWWorld::Ptr& ptr) = 0; + /// 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) = 0; diff --git a/apps/openmw/mwbase/world.hpp b/apps/openmw/mwbase/world.hpp index ffacb267c..dfae5700b 100644 --- a/apps/openmw/mwbase/world.hpp +++ b/apps/openmw/mwbase/world.hpp @@ -303,6 +303,8 @@ namespace MWBase ///< Queues movement for \a ptr (in local space), to be applied in the next call to /// doPhysics. + virtual void updateAnimatedCollisionShape(const MWWorld::Ptr &ptr) = 0; + virtual bool castRay (float x1, float y1, float z1, float x2, float y2, float z2, int mask) = 0; ///< cast a Ray and return true if there is an object in the ray path. diff --git a/apps/openmw/mwgui/container.cpp b/apps/openmw/mwgui/container.cpp index 2f9643f74..51c0603ca 100644 --- a/apps/openmw/mwgui/container.cpp +++ b/apps/openmw/mwgui/container.cpp @@ -162,6 +162,8 @@ namespace MWGui if (mModel) mModel->onClose(); + + MWBase::Environment::get().getMechanicsManager()->onClose(mPtr); } void ContainerWindow::onCloseButtonClicked(MyGUI::Widget* _sender) diff --git a/apps/openmw/mwmechanics/character.cpp b/apps/openmw/mwmechanics/character.cpp index 07a6aa3b1..0a1a9810a 100644 --- a/apps/openmw/mwmechanics/character.cpp +++ b/apps/openmw/mwmechanics/character.cpp @@ -419,6 +419,43 @@ void CharacterController::refreshJumpAnims(const WeaponInfo* weap, JumpingState } } +bool CharacterController::onOpen() +{ + if (mPtr.getTypeName() == typeid(ESM::Container).name()) + { + if (!mAnimation->hasAnimation("containeropen")) + return true; + + if (mAnimation->isPlaying("containeropen")) + return false; + + if (mAnimation->isPlaying("containerclose")) + return false; + + mAnimation->play("containeropen", Priority_Persistent, MWRender::Animation::BlendMask_All, false, 1.0f, "start", "stop", 0.f, 0); + if (mAnimation->isPlaying("containeropen")) + return false; + } + + return true; +} + +void CharacterController::onClose() +{ + if (mPtr.getTypeName() == typeid(ESM::Container).name()) + { + if (!mAnimation->hasAnimation("containerclose")) + return; + + float complete, startPoint = 0.f; + bool animPlaying = mAnimation->getInfo("containeropen", &complete); + if (animPlaying) + startPoint = 1.f - complete; + + mAnimation->play("containerclose", Priority_Persistent, MWRender::Animation::BlendMask_All, false, 1.0f, "start", "stop", startPoint, 0); + } +} + void CharacterController::refreshMovementAnims(const WeaponInfo* weap, CharacterState movement, CharacterState& idle, bool force) { if (movement == mMovementState && idle == mIdleState && !force) @@ -1079,6 +1116,8 @@ void CharacterController::handleTextKey(const std::string &groupname, const std: else if (groupname == "shield" && evt.compare(off, len, "block hit") == 0) mPtr.getClass().block(mPtr); + else if (groupname == "containeropen" && evt.compare(off, len, "loot") == 0) + MWBase::Environment::get().getWindowManager()->pushGuiMode(MWGui::GM_Container, mPtr); } void CharacterController::updatePtr(const MWWorld::Ptr &ptr) diff --git a/apps/openmw/mwmechanics/character.hpp b/apps/openmw/mwmechanics/character.hpp index 0f4b3aa90..7e6e82c07 100644 --- a/apps/openmw/mwmechanics/character.hpp +++ b/apps/openmw/mwmechanics/character.hpp @@ -259,6 +259,9 @@ public: void update(float duration, bool animationOnly=false); + bool onOpen(); + void onClose(); + void persistAnimationState(); void unpersistAnimationState(); diff --git a/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp b/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp index a907fb89f..43a082348 100644 --- a/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp +++ b/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp @@ -845,6 +845,20 @@ namespace MWMechanics return false; } + bool MechanicsManager::onOpen(const MWWorld::Ptr& ptr) + { + if(ptr.getClass().isActor()) + return true; + else + return mObjects.onOpen(ptr); + } + + void MechanicsManager::onClose(const MWWorld::Ptr& ptr) + { + if(!ptr.getClass().isActor()) + mObjects.onClose(ptr); + } + void MechanicsManager::persistAnimationStates() { mActors.persistAnimationStates(); diff --git a/apps/openmw/mwmechanics/mechanicsmanagerimp.hpp b/apps/openmw/mwmechanics/mechanicsmanagerimp.hpp index 7b6bbc636..a1fce4fa9 100644 --- a/apps/openmw/mwmechanics/mechanicsmanagerimp.hpp +++ b/apps/openmw/mwmechanics/mechanicsmanagerimp.hpp @@ -182,6 +182,9 @@ namespace MWMechanics virtual void playerLoaded() override; + virtual bool onOpen(const MWWorld::Ptr& ptr) override; + virtual void onClose(const MWWorld::Ptr& ptr) override; + virtual int countSavedGameRecords() const override; virtual void write (ESM::ESMWriter& writer, Loading::Listener& listener) const override; diff --git a/apps/openmw/mwmechanics/objects.cpp b/apps/openmw/mwmechanics/objects.cpp index e95c0a704..726508161 100644 --- a/apps/openmw/mwmechanics/objects.cpp +++ b/apps/openmw/mwmechanics/objects.cpp @@ -1,8 +1,10 @@ #include "objects.hpp" #include +#include #include "../mwbase/environment.hpp" +#include "../mwbase/windowmanager.hpp" #include "../mwbase/world.hpp" #include "movement.hpp" @@ -77,6 +79,40 @@ void Objects::update(float duration, bool paused) for(PtrControllerMap::iterator iter(mObjects.begin());iter != mObjects.end();++iter) iter->second->update(duration); } + else + { + // We still should play container opening animation in the Container GUI mode. + MWGui::GuiMode mode = MWBase::Environment::get().getWindowManager()->getMode(); + if(mode != MWGui::GM_Container) + return; + + for(PtrControllerMap::iterator iter(mObjects.begin());iter != mObjects.end();++iter) + { + if (iter->first.getTypeName() != typeid(ESM::Container).name()) + continue; + + if (iter->second->isAnimPlaying("containeropen")) + { + iter->second->update(duration); + MWBase::Environment::get().getWorld()->updateAnimatedCollisionShape(iter->first); + } + } + } +} + +bool Objects::onOpen(const MWWorld::Ptr& ptr) +{ + PtrControllerMap::iterator iter = mObjects.find(ptr); + if(iter != mObjects.end()) + return iter->second->onOpen(); + return false; +} + +void Objects::onClose(const MWWorld::Ptr& ptr) +{ + PtrControllerMap::iterator iter = mObjects.find(ptr); + if(iter != mObjects.end()) + iter->second->onClose(); } bool Objects::playAnimationGroup(const MWWorld::Ptr& ptr, const std::string& groupName, int mode, int number, bool persist) diff --git a/apps/openmw/mwmechanics/objects.hpp b/apps/openmw/mwmechanics/objects.hpp index 1efebafbe..81b95baf8 100644 --- a/apps/openmw/mwmechanics/objects.hpp +++ b/apps/openmw/mwmechanics/objects.hpp @@ -38,6 +38,9 @@ namespace MWMechanics void update(float duration, bool paused); ///< Update object animations + bool onOpen(const MWWorld::Ptr& ptr); + void onClose(const MWWorld::Ptr& ptr); + bool playAnimationGroup(const MWWorld::Ptr& ptr, const std::string& groupName, int mode, int number, bool persist=false); void skipAnimation(const MWWorld::Ptr& ptr); void persistAnimationStates(); diff --git a/apps/openmw/mwphysics/physicssystem.cpp b/apps/openmw/mwphysics/physicssystem.cpp index 57b6d348b..836370255 100644 --- a/apps/openmw/mwphysics/physicssystem.cpp +++ b/apps/openmw/mwphysics/physicssystem.cpp @@ -1363,6 +1363,13 @@ namespace MWPhysics #endif } + void PhysicsSystem::updateAnimatedCollisionShape(const MWWorld::Ptr& object) + { + ObjectMap::iterator found = mObjects.find(object); + if (found != mObjects.end()) + found->second->animateCollisionShapes(mCollisionWorld); + } + void PhysicsSystem::debugDraw() { if (mDebugDrawer.get()) diff --git a/apps/openmw/mwphysics/physicssystem.hpp b/apps/openmw/mwphysics/physicssystem.hpp index d4829f623..7d7f5a33c 100644 --- a/apps/openmw/mwphysics/physicssystem.hpp +++ b/apps/openmw/mwphysics/physicssystem.hpp @@ -178,6 +178,8 @@ namespace MWPhysics bool isOnSolidGround (const MWWorld::Ptr& actor) const; + void updateAnimatedCollisionShape(const MWWorld::Ptr& object); + template void forEachAnimatedObject(Function&& function) const { diff --git a/apps/openmw/mwworld/actionopen.cpp b/apps/openmw/mwworld/actionopen.cpp index 7ff6dd068..f678037ce 100644 --- a/apps/openmw/mwworld/actionopen.cpp +++ b/apps/openmw/mwworld/actionopen.cpp @@ -1,6 +1,7 @@ #include "actionopen.hpp" #include "../mwbase/environment.hpp" +#include "../mwbase/mechanicsmanager.hpp" #include "../mwbase/windowmanager.hpp" #include "../mwmechanics/disease.hpp" @@ -20,6 +21,9 @@ namespace MWWorld if (!MWBase::Environment::get().getWindowManager()->isAllowed(MWGui::GW_Inventory)) return; + if (!MWBase::Environment::get().getMechanicsManager()->onOpen(getTarget())) + return; + MWMechanics::diseaseContact(actor, getTarget()); MWBase::Environment::get().getWindowManager()->pushGuiMode(MWGui::GM_Container, getTarget()); diff --git a/apps/openmw/mwworld/worldimp.cpp b/apps/openmw/mwworld/worldimp.cpp index 8a5e23ed9..cb5ded593 100644 --- a/apps/openmw/mwworld/worldimp.cpp +++ b/apps/openmw/mwworld/worldimp.cpp @@ -1527,6 +1527,11 @@ namespace MWWorld mPhysics->queueObjectMovement(ptr, velocity); } + void World::updateAnimatedCollisionShape(const Ptr &ptr) + { + mPhysics->updateAnimatedCollisionShape(ptr); + } + void World::doPhysics(float duration) { mPhysics->stepSimulation(duration); diff --git a/apps/openmw/mwworld/worldimp.hpp b/apps/openmw/mwworld/worldimp.hpp index 8b3be2013..51953cd40 100644 --- a/apps/openmw/mwworld/worldimp.hpp +++ b/apps/openmw/mwworld/worldimp.hpp @@ -412,6 +412,8 @@ namespace MWWorld ///< Queues movement for \a ptr (in local space), to be applied in the next call to /// doPhysics. + void updateAnimatedCollisionShape(const Ptr &ptr) override; + bool castRay (float x1, float y1, float z1, float x2, float y2, float z2, int mask) override; ///< cast a Ray and return true if there is an object in the ray path.