mirror of
https://github.com/TES3MP/openmw-tes3mp.git
synced 2025-01-16 18:49:58 +00:00
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.
This commit is contained in:
parent
076e7d8e16
commit
8f4506f5b6
14 changed files with 164 additions and 2 deletions
|
@ -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, const std::string& value) = 0;
|
||||||
virtual void setValue (const std::string& id, int 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;
|
virtual void setPlayerClass (const ESM::Class &class_) = 0;
|
||||||
///< set current class of player
|
///< set current class of player
|
||||||
|
|
||||||
|
@ -181,6 +185,9 @@ namespace MWBase
|
||||||
virtual void setInteriorMapTexture(const int x, const int y) = 0;
|
virtual void setInteriorMapTexture(const int x, const int y) = 0;
|
||||||
///< set the index of the map texture that should be used (for interiors)
|
///< 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
|
/// sets the visibility of the hud health/magicka/stamina bars
|
||||||
virtual void setHMSVisibility(bool visible) = 0;
|
virtual void setHMSVisibility(bool visible) = 0;
|
||||||
|
|
||||||
|
|
|
@ -323,6 +323,8 @@ namespace MWBase
|
||||||
|
|
||||||
virtual bool isFlying(const MWWorld::Ptr &ptr) const = 0;
|
virtual bool isFlying(const MWWorld::Ptr &ptr) const = 0;
|
||||||
virtual bool isSwimming(const MWWorld::Ptr &object) 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 isUnderwater(const MWWorld::Ptr::CellStore* cell, const Ogre::Vector3 &pos) const = 0;
|
||||||
virtual bool isOnGround(const MWWorld::Ptr &ptr) const = 0;
|
virtual bool isOnGround(const MWWorld::Ptr &ptr) const = 0;
|
||||||
|
|
||||||
|
|
|
@ -25,6 +25,8 @@ namespace MWGui
|
||||||
, mHealth(NULL)
|
, mHealth(NULL)
|
||||||
, mMagicka(NULL)
|
, mMagicka(NULL)
|
||||||
, mStamina(NULL)
|
, mStamina(NULL)
|
||||||
|
, mDrowning(NULL)
|
||||||
|
, mDrowningFrame(NULL)
|
||||||
, mWeapImage(NULL)
|
, mWeapImage(NULL)
|
||||||
, mSpellImage(NULL)
|
, mSpellImage(NULL)
|
||||||
, mWeapStatus(NULL)
|
, mWeapStatus(NULL)
|
||||||
|
@ -69,6 +71,11 @@ namespace MWGui
|
||||||
magickaFrame->eventMouseButtonClick += MyGUI::newDelegate(this, &HUD::onHMSClicked);
|
magickaFrame->eventMouseButtonClick += MyGUI::newDelegate(this, &HUD::onHMSClicked);
|
||||||
fatigueFrame->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();
|
const MyGUI::IntSize& viewSize = MyGUI::RenderManager::getInstance().getViewSize();
|
||||||
|
|
||||||
// Item and spell images and status bars
|
// 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)
|
void HUD::onWorldClicked(MyGUI::Widget* _sender)
|
||||||
{
|
{
|
||||||
if (!MWBase::Environment::get().getWindowManager ()->isGuiMode ())
|
if (!MWBase::Environment::get().getWindowManager ()->isGuiMode ())
|
||||||
|
|
|
@ -18,6 +18,11 @@ namespace MWGui
|
||||||
void setTriangleCount(unsigned int count);
|
void setTriangleCount(unsigned int count);
|
||||||
void setBatchCount(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 setHmsVisible(bool visible);
|
||||||
void setWeapVisible(bool visible);
|
void setWeapVisible(bool visible);
|
||||||
void setSpellVisible(bool visible);
|
void setSpellVisible(bool visible);
|
||||||
|
@ -50,7 +55,7 @@ namespace MWGui
|
||||||
void setEnemy(const MWWorld::Ptr& enemy);
|
void setEnemy(const MWWorld::Ptr& enemy);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
MyGUI::ProgressBar *mHealth, *mMagicka, *mStamina, *mEnemyHealth;
|
MyGUI::ProgressBar *mHealth, *mMagicka, *mStamina, *mEnemyHealth, *mDrowning;
|
||||||
MyGUI::Widget* mHealthFrame;
|
MyGUI::Widget* mHealthFrame;
|
||||||
MyGUI::Widget *mWeapBox, *mSpellBox, *mSneakBox;
|
MyGUI::Widget *mWeapBox, *mSpellBox, *mSneakBox;
|
||||||
MyGUI::ImageBox *mWeapImage, *mSpellImage;
|
MyGUI::ImageBox *mWeapImage, *mSpellImage;
|
||||||
|
@ -62,6 +67,7 @@ namespace MWGui
|
||||||
MyGUI::ImageBox* mCrosshair;
|
MyGUI::ImageBox* mCrosshair;
|
||||||
MyGUI::TextBox* mCellNameBox;
|
MyGUI::TextBox* mCellNameBox;
|
||||||
MyGUI::TextBox* mWeaponSpellBox;
|
MyGUI::TextBox* mWeaponSpellBox;
|
||||||
|
MyGUI::Widget* mDrowningFrame;
|
||||||
|
|
||||||
MyGUI::Widget* mDummy;
|
MyGUI::Widget* mDummy;
|
||||||
|
|
||||||
|
|
|
@ -599,6 +599,11 @@ namespace MWGui
|
||||||
mStatsWindow->setValue (id, value);
|
mStatsWindow->setValue (id, value);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void WindowManager::setDrowningTimeLeft (float time)
|
||||||
|
{
|
||||||
|
mHud->setDrowningTimeLeft(time);
|
||||||
|
}
|
||||||
|
|
||||||
void WindowManager::setPlayerClass (const ESM::Class &class_)
|
void WindowManager::setPlayerClass (const ESM::Class &class_)
|
||||||
{
|
{
|
||||||
mStatsWindow->setValue("class", class_.mName);
|
mStatsWindow->setValue("class", class_.mName);
|
||||||
|
@ -787,6 +792,11 @@ namespace MWGui
|
||||||
mHud->setPlayerDir(x,y);
|
mHud->setPlayerDir(x,y);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void WindowManager::setDrowningBarVisibility(bool visible)
|
||||||
|
{
|
||||||
|
mHud->setDrowningBarVisible(visible);
|
||||||
|
}
|
||||||
|
|
||||||
void WindowManager::setHMSVisibility(bool visible)
|
void WindowManager::setHMSVisibility(bool visible)
|
||||||
{
|
{
|
||||||
mHud->setHmsVisible (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, const std::string& value);
|
||||||
virtual void setValue (const std::string& id, int 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 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 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
|
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);
|
virtual void setInteriorMapTexture(const int x, const int y);
|
||||||
///< set the index of the map texture that should be used (for interiors)
|
///< 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
|
// sets the visibility of the hud health/magicka/stamina bars
|
||||||
virtual void setHMSVisibility(bool visible);
|
virtual void setHMSVisibility(bool visible);
|
||||||
// sets the visibility of the hud minimap
|
// sets the visibility of the hud minimap
|
||||||
|
|
|
@ -16,6 +16,7 @@
|
||||||
#include "../mwbase/environment.hpp"
|
#include "../mwbase/environment.hpp"
|
||||||
#include "../mwbase/windowmanager.hpp"
|
#include "../mwbase/windowmanager.hpp"
|
||||||
|
|
||||||
|
#include "npcstats.hpp"
|
||||||
#include "creaturestats.hpp"
|
#include "creaturestats.hpp"
|
||||||
#include "movement.hpp"
|
#include "movement.hpp"
|
||||||
|
|
||||||
|
@ -40,6 +41,8 @@ namespace MWMechanics
|
||||||
{
|
{
|
||||||
if (!paused && ptr.getRefData().getHandle()!="player")
|
if (!paused && ptr.getRefData().getHandle()!="player")
|
||||||
MWWorld::Class::get (ptr).getInventoryStore (ptr).autoEquip (ptr);
|
MWWorld::Class::get (ptr).getInventoryStore (ptr).autoEquip (ptr);
|
||||||
|
if(!paused)
|
||||||
|
updateDrowning(ptr,duration);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Actors::adjustMagicEffects (const MWWorld::Ptr& creature)
|
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) {}
|
Actors::Actors() : mDuration (0) {}
|
||||||
|
|
||||||
void Actors::addActor (const MWWorld::Ptr& ptr)
|
void Actors::addActor (const MWWorld::Ptr& ptr)
|
||||||
|
|
|
@ -44,6 +44,7 @@ namespace MWMechanics
|
||||||
|
|
||||||
void calculateRestoration (const MWWorld::Ptr& ptr, float duration);
|
void calculateRestoration (const MWWorld::Ptr& ptr, float duration);
|
||||||
|
|
||||||
|
void updateDrowning (const MWWorld::Ptr& ptr, float duration);
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
|
||||||
|
|
|
@ -254,6 +254,20 @@ namespace MWMechanics
|
||||||
MWBase::Environment::get().getWindowManager()->setValue(dynamicNames[2], stats.getFatigue());
|
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;
|
bool update = false;
|
||||||
|
|
||||||
//Loop over ESM::Skill::SkillEnum
|
//Loop over ESM::Skill::SkillEnum
|
||||||
|
|
|
@ -32,6 +32,8 @@ MWMechanics::NpcStats::NpcStats()
|
||||||
, mWerewolfKills (0)
|
, mWerewolfKills (0)
|
||||||
, mProfit(0)
|
, mProfit(0)
|
||||||
, mAttackStrength(0.0f)
|
, mAttackStrength(0.0f)
|
||||||
|
, mTimeToStartDrowning(20.0)
|
||||||
|
, mLastDrowningHit(0)
|
||||||
{
|
{
|
||||||
mSkillIncreases.resize (ESM::Attribute::Length);
|
mSkillIncreases.resize (ESM::Attribute::Length);
|
||||||
for (int i=0; i<ESM::Attribute::Length; ++i)
|
for (int i=0; i<ESM::Attribute::Length; ++i)
|
||||||
|
@ -382,3 +384,23 @@ void MWMechanics::NpcStats::modifyProfit(int diff)
|
||||||
{
|
{
|
||||||
mProfit += 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;
|
std::set<std::string> mUsedIds;
|
||||||
|
|
||||||
|
/// Countdown to getting damage while underwater
|
||||||
|
float mTimeToStartDrowning;
|
||||||
|
/// time since last hit from drowning
|
||||||
|
float mLastDrowningHit;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
|
||||||
NpcStats();
|
NpcStats();
|
||||||
|
@ -142,6 +147,16 @@ namespace MWMechanics
|
||||||
void setWerewolf (bool set);
|
void setWerewolf (bool set);
|
||||||
|
|
||||||
int getWerewolfKills() const;
|
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;
|
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
|
bool
|
||||||
World::isSwimming(const MWWorld::Ptr &object) const
|
World::isSwimming(const MWWorld::Ptr &object) const
|
||||||
{
|
{
|
||||||
|
|
|
@ -348,6 +348,8 @@ namespace MWWorld
|
||||||
virtual void processChangedSettings(const Settings::CategorySettingVector& settings);
|
virtual void processChangedSettings(const Settings::CategorySettingVector& settings);
|
||||||
|
|
||||||
virtual bool isFlying(const MWWorld::Ptr &ptr) const;
|
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 isSwimming(const MWWorld::Ptr &object) const;
|
||||||
virtual bool isUnderwater(const MWWorld::Ptr::CellStore* cell, const Ogre::Vector3 &pos) const;
|
virtual bool isUnderwater(const MWWorld::Ptr::CellStore* cell, const Ogre::Vector3 &pos) const;
|
||||||
virtual bool isOnGround(const MWWorld::Ptr &ptr) const;
|
virtual bool isOnGround(const MWWorld::Ptr &ptr) const;
|
||||||
|
|
|
@ -32,7 +32,21 @@
|
||||||
<Property key="NeedMouse" value="false"/>
|
<Property key="NeedMouse" value="false"/>
|
||||||
</Widget>
|
</Widget>
|
||||||
</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 -->
|
<!-- 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">
|
<Widget type="TextBox" skin="SandText" position="13 118 270 24" name="WeaponSpellName" align="Left Bottom HStretch">
|
||||||
<Property key="Visible" value="false"/>
|
<Property key="Visible" value="false"/>
|
||||||
|
|
Loading…
Reference in a new issue