Implemented drowning.

Currently no visual effects on losing health, the breathing sound doesn't change (we don't have one),
the breath bar doesn't turn red when no breath left and it doesn't pulse from black to red.
actorid
PLkolek 12 years ago
parent 076e7d8e16
commit 8f4506f5b6

@ -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;

@ -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;

@ -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 ())

@ -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;

@ -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);

@ -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

@ -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)

@ -44,6 +44,7 @@ namespace MWMechanics
void calculateRestoration (const MWWorld::Ptr& ptr, float duration);
void updateDrowning (const MWWorld::Ptr& ptr, float duration);
public:

@ -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

@ -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<ESM::Attribute::Length; ++i)
@ -382,3 +384,23 @@ void MWMechanics::NpcStats::modifyProfit(int diff)
{
mProfit += diff;
}
float MWMechanics::NpcStats::getTimeToStartDrowning()
{
return mTimeToStartDrowning;
}
void MWMechanics::NpcStats::setTimeToStartDrowning(float time)
{
assert(time>=0 && time<=20);
mTimeToStartDrowning=time;
}
float MWMechanics::NpcStats::getLastDrowningHitTime()
{
return mLastDrowningHit;
}
void MWMechanics::NpcStats::setLastDrowningHitTime(float time)
{
mLastDrowningHit=time;
}

@ -62,6 +62,11 @@ namespace MWMechanics
std::set<std::string> 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);
};
}

@ -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
{

@ -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;

@ -32,7 +32,21 @@
<Property key="NeedMouse" value="false"/>
</Widget>
</Widget>
<!-- Drowning bar -->
<Widget type="Widget" skin="HUD_Box" position="0 36 220 56" align="Center Top" name="DrowningFrame">
<Property key="Visible" value="false"/>
<Widget type="TextBox" skin="SandText" position="0 8 220 24" name="DrowningTitle" align="Center Top HStretch">
<Property key="Caption" value="#{sBreath}"/>
<Property key="TextAlign" value="Center"/>
<Property key="TextShadow" value="true"/>
<Property key="TextShadowColour" value="0 0 0"/>
</Widget>
<Widget type="ProgressBar" skin="MW_Progress_Loading" position="12 36 196 8" align="Center Top" name="Drowning">
<Property key="NeedMouse" value="false"/>
</Widget>
</Widget>
<!-- Equipped weapon/selected spell name display for a few seconds after it changes -->
<Widget type="TextBox" skin="SandText" position="13 118 270 24" name="WeaponSpellName" align="Left Bottom HStretch">
<Property key="Visible" value="false"/>

Loading…
Cancel
Save