diff --git a/apps/openmw/mwbase/windowmanager.hpp b/apps/openmw/mwbase/windowmanager.hpp index 81ef9ee79..2d923b63d 100644 --- a/apps/openmw/mwbase/windowmanager.hpp +++ b/apps/openmw/mwbase/windowmanager.hpp @@ -138,6 +138,10 @@ namespace MWBase virtual void setValue (const std::string& id, const std::string& value) = 0; virtual void setValue (const std::string& id, int value) = 0; + /// Set time left for the player to start drowning (update the drowning bar) + /// @param time value from [0,20] + virtual void setDrowningTimeLeft (float time) =0; + virtual void setPlayerClass (const ESM::Class &class_) = 0; ///< set current class of player @@ -181,6 +185,9 @@ namespace MWBase virtual void setInteriorMapTexture(const int x, const int y) = 0; ///< set the index of the map texture that should be used (for interiors) + /// sets the visibility of the drowning bar + virtual void setDrowningBarVisibility(bool visible) = 0; + /// sets the visibility of the hud health/magicka/stamina bars virtual void setHMSVisibility(bool visible) = 0; diff --git a/apps/openmw/mwbase/world.hpp b/apps/openmw/mwbase/world.hpp index 480bcf9cf..e36374941 100644 --- a/apps/openmw/mwbase/world.hpp +++ b/apps/openmw/mwbase/world.hpp @@ -323,6 +323,8 @@ namespace MWBase virtual bool isFlying(const MWWorld::Ptr &ptr) const = 0; virtual bool isSwimming(const MWWorld::Ptr &object) const = 0; + ///Is the head of the creature underwater? + virtual bool isSubmerged(const MWWorld::Ptr &object) const = 0; virtual bool isUnderwater(const MWWorld::Ptr::CellStore* cell, const Ogre::Vector3 &pos) const = 0; virtual bool isOnGround(const MWWorld::Ptr &ptr) const = 0; diff --git a/apps/openmw/mwgui/hud.cpp b/apps/openmw/mwgui/hud.cpp index f5cb12e05..f82fbda2b 100644 --- a/apps/openmw/mwgui/hud.cpp +++ b/apps/openmw/mwgui/hud.cpp @@ -25,6 +25,8 @@ namespace MWGui , mHealth(NULL) , mMagicka(NULL) , mStamina(NULL) + , mDrowning(NULL) + , mDrowningFrame(NULL) , mWeapImage(NULL) , mSpellImage(NULL) , mWeapStatus(NULL) @@ -69,6 +71,11 @@ namespace MWGui magickaFrame->eventMouseButtonClick += MyGUI::newDelegate(this, &HUD::onHMSClicked); fatigueFrame->eventMouseButtonClick += MyGUI::newDelegate(this, &HUD::onHMSClicked); + //Drowning bar + getWidget(mDrowningFrame, "DrowningFrame"); + getWidget(mDrowning, "Drowning"); + mDrowning->setProgressRange(200); + const MyGUI::IntSize& viewSize = MyGUI::RenderManager::getInstance().getViewSize(); // Item and spell images and status bars @@ -197,6 +204,16 @@ namespace MWGui } } + void HUD::setDrowningTimeLeft(float time) + { + mDrowning->setProgressPosition(time/20.0*200.0); + } + + void HUD::setDrowningBarVisible(bool visible) + { + mDrowningFrame->setVisible(visible); + } + void HUD::onWorldClicked(MyGUI::Widget* _sender) { if (!MWBase::Environment::get().getWindowManager ()->isGuiMode ()) diff --git a/apps/openmw/mwgui/hud.hpp b/apps/openmw/mwgui/hud.hpp index a3cab2c93..c40742a60 100644 --- a/apps/openmw/mwgui/hud.hpp +++ b/apps/openmw/mwgui/hud.hpp @@ -18,6 +18,11 @@ namespace MWGui void setTriangleCount(unsigned int count); void setBatchCount(unsigned int count); + /// Set time left for the player to start drowning + /// @param time value from [0,20] + void setDrowningTimeLeft(float time); + void setDrowningBarVisible(bool visible); + void setHmsVisible(bool visible); void setWeapVisible(bool visible); void setSpellVisible(bool visible); @@ -50,7 +55,7 @@ namespace MWGui void setEnemy(const MWWorld::Ptr& enemy); private: - MyGUI::ProgressBar *mHealth, *mMagicka, *mStamina, *mEnemyHealth; + MyGUI::ProgressBar *mHealth, *mMagicka, *mStamina, *mEnemyHealth, *mDrowning; MyGUI::Widget* mHealthFrame; MyGUI::Widget *mWeapBox, *mSpellBox, *mSneakBox; MyGUI::ImageBox *mWeapImage, *mSpellImage; @@ -62,6 +67,7 @@ namespace MWGui MyGUI::ImageBox* mCrosshair; MyGUI::TextBox* mCellNameBox; MyGUI::TextBox* mWeaponSpellBox; + MyGUI::Widget* mDrowningFrame; MyGUI::Widget* mDummy; diff --git a/apps/openmw/mwgui/windowmanagerimp.cpp b/apps/openmw/mwgui/windowmanagerimp.cpp index 792431038..7cf9eaa64 100644 --- a/apps/openmw/mwgui/windowmanagerimp.cpp +++ b/apps/openmw/mwgui/windowmanagerimp.cpp @@ -599,6 +599,11 @@ namespace MWGui mStatsWindow->setValue (id, value); } + void WindowManager::setDrowningTimeLeft (float time) + { + mHud->setDrowningTimeLeft(time); + } + void WindowManager::setPlayerClass (const ESM::Class &class_) { mStatsWindow->setValue("class", class_.mName); @@ -787,6 +792,11 @@ namespace MWGui mHud->setPlayerDir(x,y); } + void WindowManager::setDrowningBarVisibility(bool visible) + { + mHud->setDrowningBarVisible(visible); + } + void WindowManager::setHMSVisibility(bool visible) { mHud->setHmsVisible (visible); diff --git a/apps/openmw/mwgui/windowmanagerimp.hpp b/apps/openmw/mwgui/windowmanagerimp.hpp index a178dc621..8188946e1 100644 --- a/apps/openmw/mwgui/windowmanagerimp.hpp +++ b/apps/openmw/mwgui/windowmanagerimp.hpp @@ -148,6 +148,10 @@ namespace MWGui virtual void setValue (const std::string& id, const std::string& value); virtual void setValue (const std::string& id, int value); + /// Set time left for the player to start drowning (update the drowning bar) + /// @param time value from [0,20] + virtual void setDrowningTimeLeft (float time); + virtual void setPlayerClass (const ESM::Class &class_); ///< set current class of player virtual void configureSkills (const SkillList& major, const SkillList& minor); ///< configure skill groups, each set contains the skill ID for that group. virtual void setReputation (int reputation); ///< set the current reputation value @@ -173,6 +177,9 @@ namespace MWGui virtual void setInteriorMapTexture(const int x, const int y); ///< set the index of the map texture that should be used (for interiors) + /// sets the visibility of the drowning bar + virtual void setDrowningBarVisibility(bool visible); + // sets the visibility of the hud health/magicka/stamina bars virtual void setHMSVisibility(bool visible); // sets the visibility of the hud minimap diff --git a/apps/openmw/mwmechanics/actors.cpp b/apps/openmw/mwmechanics/actors.cpp index fb273c7c1..0d720ecac 100644 --- a/apps/openmw/mwmechanics/actors.cpp +++ b/apps/openmw/mwmechanics/actors.cpp @@ -16,6 +16,7 @@ #include "../mwbase/environment.hpp" #include "../mwbase/windowmanager.hpp" +#include "npcstats.hpp" #include "creaturestats.hpp" #include "movement.hpp" @@ -40,6 +41,8 @@ namespace MWMechanics { if (!paused && ptr.getRefData().getHandle()!="player") MWWorld::Class::get (ptr).getInventoryStore (ptr).autoEquip (ptr); + if(!paused) + updateDrowning(ptr,duration); } void Actors::adjustMagicEffects (const MWWorld::Ptr& creature) @@ -159,6 +162,37 @@ namespace MWMechanics } } + void Actors::updateDrowning(const MWWorld::Ptr& ptr, float duration) + { + Ogre::Vector3 pos(ptr.getRefData().getPosition().pos); + CreatureStats& creatureStats=MWWorld::Class::get(ptr).getCreatureStats(ptr); + NpcStats& stats=MWWorld::Class::get(ptr).getNpcStats(ptr); + bool waterBreathing=creatureStats.getMagicEffects().get(ESM::MagicEffect::WaterBreathing).mMagnitude>0; + if(MWBase::Environment::get().getWorld()->isSubmerged(ptr) && !waterBreathing) + { + if(creatureStats.getFatigue().getCurrent()==0) + stats.setTimeToStartDrowning(0); + float timeLeft=stats.getTimeToStartDrowning()-duration; + if(timeLeft<0) + timeLeft=0; + stats.setTimeToStartDrowning(timeLeft); + if(timeLeft==0) + stats.setLastDrowningHitTime(stats.getLastDrowningHitTime()+duration); + } + else + { + stats.setTimeToStartDrowning(20); + stats.setLastDrowningHitTime(0); + } + //if npc is drowning and it's time to hit, then hit + while(stats.getTimeToStartDrowning()==0.0 && stats.getLastDrowningHitTime()>0.33) + { + stats.setLastDrowningHitTime(stats.getLastDrowningHitTime()-0.33); + //fixme: replace it with something different once screen hit effects are implemented (blood on screen) + MWWorld::Class::get(ptr).setActorHealth(ptr, creatureStats.getHealth().getCurrent()-1.0); + } + } + 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 1369d783c..777fdbb9a 100644 --- a/apps/openmw/mwmechanics/actors.hpp +++ b/apps/openmw/mwmechanics/actors.hpp @@ -44,6 +44,7 @@ namespace MWMechanics void calculateRestoration (const MWWorld::Ptr& ptr, float duration); + void updateDrowning (const MWWorld::Ptr& ptr, float duration); public: diff --git a/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp b/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp index 7aa347d6e..cdcede507 100644 --- a/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp +++ b/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp @@ -254,6 +254,20 @@ namespace MWMechanics MWBase::Environment::get().getWindowManager()->setValue(dynamicNames[2], stats.getFatigue()); } + if(npcStats.getTimeToStartDrowning() != mWatchedNpc.getTimeToStartDrowning()) + { + mWatchedNpc.setTimeToStartDrowning(npcStats.getTimeToStartDrowning()); + if(npcStats.getTimeToStartDrowning()>=20.0) + { + MWBase::Environment::get().getWindowManager()->setDrowningBarVisibility(false); + } + else + { + MWBase::Environment::get().getWindowManager()->setDrowningBarVisibility(true); + MWBase::Environment::get().getWindowManager()->setDrowningTimeLeft(npcStats.getTimeToStartDrowning()); + } + } + bool update = false; //Loop over ESM::Skill::SkillEnum diff --git a/apps/openmw/mwmechanics/npcstats.cpp b/apps/openmw/mwmechanics/npcstats.cpp index 50c127856..69ba1c5cb 100644 --- a/apps/openmw/mwmechanics/npcstats.cpp +++ b/apps/openmw/mwmechanics/npcstats.cpp @@ -32,6 +32,8 @@ MWMechanics::NpcStats::NpcStats() , mWerewolfKills (0) , mProfit(0) , mAttackStrength(0.0f) +, mTimeToStartDrowning(20.0) +, mLastDrowningHit(0) { mSkillIncreases.resize (ESM::Attribute::Length); for (int i=0; i=0 && time<=20); + mTimeToStartDrowning=time; +} + +float MWMechanics::NpcStats::getLastDrowningHitTime() +{ + return mLastDrowningHit; +} + +void MWMechanics::NpcStats::setLastDrowningHitTime(float time) +{ + mLastDrowningHit=time; +} diff --git a/apps/openmw/mwmechanics/npcstats.hpp b/apps/openmw/mwmechanics/npcstats.hpp index 75fca0685..44ad575e4 100644 --- a/apps/openmw/mwmechanics/npcstats.hpp +++ b/apps/openmw/mwmechanics/npcstats.hpp @@ -62,6 +62,11 @@ namespace MWMechanics std::set mUsedIds; + /// Countdown to getting damage while underwater + float mTimeToStartDrowning; + /// time since last hit from drowning + float mLastDrowningHit; + public: NpcStats(); @@ -142,6 +147,16 @@ namespace MWMechanics void setWerewolf (bool set); int getWerewolfKills() const; + + float getTimeToStartDrowning(); + /// Sets time left for the creature to drown if it stays underwater. + /// @param time value from [0,20] + void setTimeToStartDrowning(float time); + + float getLastDrowningHitTime(); + /// Sets time since last hit caused by drowning. + /// @param time value from [0,0.33] + void setLastDrowningHitTime(float time); }; } diff --git a/apps/openmw/mwworld/worldimp.cpp b/apps/openmw/mwworld/worldimp.cpp index f396157a4..7703470b4 100644 --- a/apps/openmw/mwworld/worldimp.cpp +++ b/apps/openmw/mwworld/worldimp.cpp @@ -1566,6 +1566,17 @@ namespace MWWorld return false; } + bool World::isSubmerged(const MWWorld::Ptr &object) const + { + float *fpos = object.getRefData().getPosition().pos; + Ogre::Vector3 pos(fpos[0], fpos[1], fpos[2]); + + const OEngine::Physic::PhysicActor *actor = mPhysEngine->getCharacter(object.getRefData().getHandle()); + if(actor) pos.z += 1.85*actor->getHalfExtents().z; + + return isUnderwater(object.getCell(), pos); + } + bool World::isSwimming(const MWWorld::Ptr &object) const { diff --git a/apps/openmw/mwworld/worldimp.hpp b/apps/openmw/mwworld/worldimp.hpp index 6d8caad21..cb2e00e1f 100644 --- a/apps/openmw/mwworld/worldimp.hpp +++ b/apps/openmw/mwworld/worldimp.hpp @@ -348,6 +348,8 @@ namespace MWWorld virtual void processChangedSettings(const Settings::CategorySettingVector& settings); virtual bool isFlying(const MWWorld::Ptr &ptr) const; + ///Is the head of the creature underwater? + virtual bool isSubmerged(const MWWorld::Ptr &object) const; virtual bool isSwimming(const MWWorld::Ptr &object) const; virtual bool isUnderwater(const MWWorld::Ptr::CellStore* cell, const Ogre::Vector3 &pos) const; virtual bool isOnGround(const MWWorld::Ptr &ptr) const; diff --git a/files/mygui/openmw_hud.layout b/files/mygui/openmw_hud.layout index 16b9f2c20..9faa931c6 100644 --- a/files/mygui/openmw_hud.layout +++ b/files/mygui/openmw_hud.layout @@ -32,7 +32,21 @@ - + + + + + + + + + + + + + + +