diff --git a/apps/openmw/mwclass/light.cpp b/apps/openmw/mwclass/light.cpp index 7eefc6167..906ae8a1c 100644 --- a/apps/openmw/mwclass/light.cpp +++ b/apps/openmw/mwclass/light.cpp @@ -16,12 +16,34 @@ #include "../mwworld/inventorystore.hpp" #include "../mwworld/cellstore.hpp" #include "../mwworld/physicssystem.hpp" +#include "../mwworld/customdata.hpp" #include "../mwgui/tooltips.hpp" #include "../mwrender/objects.hpp" #include "../mwrender/renderinginterface.hpp" +namespace +{ + struct CustomData : public MWWorld::CustomData + { + float mTime; + ///< Time remaining + + CustomData(MWWorld::Ptr ptr) + { + MWWorld::LiveCellRef *ref = ptr.get(); + mTime = ref->mBase->mData.mTime; + } + ///< Constructs this CustomData from the base values for Ptr. + + virtual MWWorld::CustomData *clone() const + { + return new CustomData (*this); + } + }; +} + namespace MWClass { void Light::insertObjectRendering (const MWWorld::Ptr& ptr, MWRender::RenderingInterface& renderingInterface) const @@ -182,6 +204,22 @@ namespace MWClass return action; } + void Light::setRemainingUsageTime (const MWWorld::Ptr& ptr, float duration) const + { + ensureCustomData(ptr); + + float &timeRemaining = dynamic_cast (*ptr.getRefData().getCustomData()).mTime; + timeRemaining = duration; + } + + float Light::getRemainingUsageTime (const MWWorld::Ptr& ptr) const + { + ensureCustomData(ptr); + + ESM::CellRef &ref = ptr.getCellRef(); + return dynamic_cast (*ptr.getRefData().getCustomData()).mTime; + } + MWWorld::Ptr Light::copyToCellImpl(const MWWorld::Ptr &ptr, MWWorld::CellStore &cell) const { @@ -191,6 +229,12 @@ namespace MWClass return MWWorld::Ptr(&cell.mLights.insert(*ref), &cell); } + void Light::ensureCustomData (const MWWorld::Ptr& ptr) const + { + if (!ptr.getRefData().getCustomData()) + ptr.getRefData().setCustomData(new CustomData(ptr)); + } + bool Light::canSell (const MWWorld::Ptr& item, int npcServices) const { return npcServices & ESM::NPC::Lights; diff --git a/apps/openmw/mwclass/light.hpp b/apps/openmw/mwclass/light.hpp index 79d662763..c15228a6a 100644 --- a/apps/openmw/mwclass/light.hpp +++ b/apps/openmw/mwclass/light.hpp @@ -10,6 +10,8 @@ namespace MWClass virtual MWWorld::Ptr copyToCellImpl(const MWWorld::Ptr &ptr, MWWorld::CellStore &cell) const; + void ensureCustomData (const MWWorld::Ptr& ptr) const; + public: virtual void insertObjectRendering (const MWWorld::Ptr& ptr, MWRender::RenderingInterface& renderingInterface) const; @@ -56,6 +58,12 @@ namespace MWClass const; ///< Generate action for using via inventory menu + virtual void setRemainingUsageTime (const MWWorld::Ptr& ptr, float duration) const; + ///< Sets the remaining duration of the object. + + virtual float getRemainingUsageTime (const MWWorld::Ptr& ptr) const; + ///< Returns the remaining duration of the object. + virtual std::string getModel(const MWWorld::Ptr &ptr) const; virtual float getWeight (const MWWorld::Ptr& ptr) const; diff --git a/apps/openmw/mwmechanics/actors.cpp b/apps/openmw/mwmechanics/actors.cpp index 70b820f8c..42851dea3 100644 --- a/apps/openmw/mwmechanics/actors.cpp +++ b/apps/openmw/mwmechanics/actors.cpp @@ -45,7 +45,10 @@ namespace MWMechanics void Actors::updateNpc (const MWWorld::Ptr& ptr, float duration, bool paused) { if(!paused) + { updateDrowning(ptr, duration); + updateEquippedLight(ptr, duration); + } } void Actors::adjustMagicEffects (const MWWorld::Ptr& creature) @@ -202,6 +205,49 @@ namespace MWMechanics stats.setTimeToStartDrowning(20); } + void Actors::updateEquippedLight (const MWWorld::Ptr& ptr, float duration) + { + //If holding a light... + MWWorld::InventoryStore &inventoryStore = MWWorld::Class::get(ptr).getInventoryStore(ptr); + MWWorld::ContainerStoreIterator heldIter = + inventoryStore.getSlot(MWWorld::InventoryStore::Slot_CarriedLeft); + + if(heldIter.getType() == MWWorld::ContainerStore::Type_Light) + { + // Use time from the player's light + bool isPlayer = ptr.getRefData().getHandle()=="player"; + if(isPlayer) + { + float timeRemaining = heldIter->getClass().getRemainingUsageTime(*heldIter); + + // -1 is infinite light source. Other negative values are treated as 0. + if(timeRemaining != -1.0f) + { + timeRemaining -= duration; + + if(timeRemaining > 0.0f) + heldIter->getClass().setRemainingUsageTime(*heldIter, timeRemaining); + else + { + heldIter->getRefData().setCount(0); // remove it + return; + } + } + } + + // Both NPC and player lights extinguish in water. + if(MWBase::Environment::get().getWorld()->isSwimming(ptr)) + { + heldIter->getRefData().setCount(0); // remove it + + // ...But, only the player makes a sound. + if(isPlayer) + MWBase::Environment::get().getSoundManager()->playSound("torch out", + 1.0, 1.0, MWBase::SoundManager::Play_TypeSfx, MWBase::SoundManager::Play_NoEnv); + } + } + } + Actors::Actors() : mDuration (0) {} void Actors::addActor (const MWWorld::Ptr& ptr) diff --git a/apps/openmw/mwmechanics/actors.hpp b/apps/openmw/mwmechanics/actors.hpp index 69878a000..a77e52ba3 100644 --- a/apps/openmw/mwmechanics/actors.hpp +++ b/apps/openmw/mwmechanics/actors.hpp @@ -44,6 +44,8 @@ namespace MWMechanics void updateDrowning (const MWWorld::Ptr& ptr, float duration); + void updateEquippedLight (const MWWorld::Ptr& ptr, float duration); + public: Actors(); diff --git a/apps/openmw/mwworld/class.cpp b/apps/openmw/mwworld/class.cpp index de5093547..d3d1aff49 100644 --- a/apps/openmw/mwworld/class.cpp +++ b/apps/openmw/mwworld/class.cpp @@ -132,6 +132,16 @@ namespace MWWorld throw std::runtime_error ("class does not support unlocking"); } + void Class::setRemainingUsageTime (const Ptr& ptr, float duration) const + { + throw std::runtime_error ("class does not support time-based uses"); + } + + float Class::getRemainingUsageTime (const Ptr& ptr) const + { + throw std::runtime_error ("class does not support time-based uses"); + } + std::string Class::getScript (const Ptr& ptr) const { return ""; diff --git a/apps/openmw/mwworld/class.hpp b/apps/openmw/mwworld/class.hpp index 1db09647e..2db293e68 100644 --- a/apps/openmw/mwworld/class.hpp +++ b/apps/openmw/mwworld/class.hpp @@ -156,6 +156,14 @@ namespace MWWorld virtual void unlock (const Ptr& ptr) const; ///< Unlock object (default implementation: throw an exception) + virtual void setRemainingUsageTime (const Ptr& ptr, float duration) const; + ///< Sets the remaining duration of the object, such as an equippable light + /// source. (default implementation: throw an exception) + + virtual float getRemainingUsageTime (const Ptr& ptr) const; + ///< Returns the remaining duration of the object, such as an equippable light + /// source. (default implementation: throw an exception) + virtual std::string getScript (const Ptr& ptr) const; ///< Return name of the script attached to ptr (default implementation: return an empty /// string).