diff --git a/apps/openmw/mwbase/world.hpp b/apps/openmw/mwbase/world.hpp index f42edafd4..311d072c5 100644 --- a/apps/openmw/mwbase/world.hpp +++ b/apps/openmw/mwbase/world.hpp @@ -521,6 +521,12 @@ namespace MWBase const MWWorld::Ptr& caster, const std::string& id, const std::string& sourceName) = 0; virtual void activate (const MWWorld::Ptr& object, const MWWorld::Ptr& actor) = 0; + + /// @see MWWorld::WeatherManager::isInStorm + virtual bool isInStorm() const = 0; + + /// @see MWWorld::WeatherManager::getStormDirection + virtual Ogre::Vector3 getStormDirection() const = 0; }; } diff --git a/apps/openmw/mwmechanics/character.cpp b/apps/openmw/mwmechanics/character.cpp index ddfba51ce..81183da3c 100644 --- a/apps/openmw/mwmechanics/character.cpp +++ b/apps/openmw/mwmechanics/character.cpp @@ -20,6 +20,7 @@ #include "character.hpp" #include +#include #include "movement.hpp" #include "npcstats.hpp" @@ -234,6 +235,8 @@ void CharacterController::refreshCurrentAnims(CharacterState idle, CharacterStat 1.0f, "start", "stop", 0.0f, ~0ul); } + updateIdleStormState(); + if(force && mJumpState != JumpState_None) { std::string jump; @@ -550,6 +553,45 @@ void CharacterController::updatePtr(const MWWorld::Ptr &ptr) mPtr = ptr; } +void CharacterController::updateIdleStormState() +{ + bool inStormDirection = false; + if (MWBase::Environment::get().getWorld()->isInStorm()) + { + Ogre::Vector3 stormDirection = MWBase::Environment::get().getWorld()->getStormDirection(); + Ogre::Vector3 characterDirection = mPtr.getRefData().getBaseNode()->getOrientation().yAxis(); + inStormDirection = stormDirection.angleBetween(characterDirection) < Ogre::Degree(40); + } + if (inStormDirection && mUpperBodyState == UpperCharState_Nothing && mAnimation->hasAnimation("idlestorm")) + { + float complete = 0; + mAnimation->getInfo("idlestorm", &complete); + + if (complete == 0) + mAnimation->play("idlestorm", Priority_Torch, MWRender::Animation::Group_RightArm, false, + 1.0f, "start", "loop start", 0.0f, 0); + else if (complete == 1) + mAnimation->play("idlestorm", Priority_Torch, MWRender::Animation::Group_RightArm, false, + 1.0f, "loop start", "loop stop", 0.0f, ~0ul); + } + else + { + if (mUpperBodyState == UpperCharState_Nothing) + { + if (mAnimation->isPlaying("idlestorm")) + { + if (mAnimation->getCurrentTime("idlestorm") < mAnimation->getTextKeyTime("idlestorm: loop stop")) + { + mAnimation->play("idlestorm", Priority_Torch, MWRender::Animation::Group_RightArm, true, + 1.0f, "loop stop", "stop", 0.0f, 0); + } + } + } + else + mAnimation->disable("idlestorm"); + } +} + bool CharacterController::updateCreatureState() { const MWWorld::Class &cls = mPtr.getClass(); diff --git a/apps/openmw/mwmechanics/character.hpp b/apps/openmw/mwmechanics/character.hpp index 5cefe13bc..59c20db8f 100644 --- a/apps/openmw/mwmechanics/character.hpp +++ b/apps/openmw/mwmechanics/character.hpp @@ -178,6 +178,7 @@ class CharacterController bool updateWeaponState(); bool updateCreatureState(); + void updateIdleStormState(); void updateVisibility(); diff --git a/apps/openmw/mwrender/sky.cpp b/apps/openmw/mwrender/sky.cpp index 545d34bdf..000a1d409 100644 --- a/apps/openmw/mwrender/sky.cpp +++ b/apps/openmw/mwrender/sky.cpp @@ -461,7 +461,7 @@ void SkyManager::setWeather(const MWWorld::WeatherResult& weather) { if (!mParticleNode) { - mParticleNode = mCamera->getParentSceneNode()->createChildSceneNode(); + mParticleNode = mCamera->getParentSceneNode()->createChildSceneNode(Ogre::Vector3(0,0,100)); mParticleNode->setInheritOrientation(false); } diff --git a/apps/openmw/mwworld/refdata.hpp b/apps/openmw/mwworld/refdata.hpp index 753230e7f..db66c091b 100644 --- a/apps/openmw/mwworld/refdata.hpp +++ b/apps/openmw/mwworld/refdata.hpp @@ -54,7 +54,7 @@ namespace MWWorld RefData(); /// @param cellRef Used to copy constant data such as position into this class where it can - /// be altered without effecting the original data. This makes it possible + /// be altered without affecting the original data. This makes it possible /// to reset the position as the orignal data is still held in the CellRef RefData (const ESM::CellRef& cellRef); diff --git a/apps/openmw/mwworld/weather.cpp b/apps/openmw/mwworld/weather.cpp index ab5ec0004..df78711ad 100644 --- a/apps/openmw/mwworld/weather.cpp +++ b/apps/openmw/mwworld/weather.cpp @@ -63,6 +63,8 @@ void WeatherManager::setFallbackWeather(Weather& weather,const std::string& name if (offset != std::string::npos) weather.mCloudTexture.replace(offset, weather.mCloudTexture.length() - offset, ".dds"); + weather.mIsStorm = (name == "ashstorm" || name == "blight"); + mWeatherSettings[name] = weather; } @@ -213,6 +215,8 @@ void WeatherManager::setResult(const String& weatherType) mResult.mAmbientLoopSoundID = current.mAmbientLoopSoundID; mResult.mSunColor = current.mSunDiscSunsetColor; + mResult.mIsStorm = current.mIsStorm; + mResult.mParticleEffect = current.mParticleEffect; mResult.mNight = (mHour < mSunriseTime || mHour > mNightStart - 1); @@ -318,6 +322,7 @@ void WeatherManager::transition(float factor) mResult.mNight = current.mNight; + mResult.mIsStorm = current.mIsStorm; mResult.mParticleEffect = current.mParticleEffect; } @@ -771,3 +776,13 @@ void WeatherManager::switchToNextWeather(bool instantly) } } } + +bool WeatherManager::isInStorm() const +{ + return mResult.mIsStorm; +} + +Ogre::Vector3 WeatherManager::getStormDirection() const +{ + return Ogre::Vector3(0,-1,0); +} diff --git a/apps/openmw/mwworld/weather.hpp b/apps/openmw/mwworld/weather.hpp index 4d0458249..8aa3d2635 100644 --- a/apps/openmw/mwworld/weather.hpp +++ b/apps/openmw/mwworld/weather.hpp @@ -57,6 +57,8 @@ namespace MWWorld bool mNight; // use night skybox float mNightFade; // fading factor for night skybox + bool mIsStorm; + std::string mAmbientLoopSoundID; std::string mParticleEffect; @@ -102,7 +104,7 @@ namespace MWWorld // Duration of weather transition (in days) float mTransitionDelta; - // No idea what this one is used for? + // Used by scripts to animate signs, etc based on the wind (GetWindSpeed) float mWindSpeed; // Cloud animation speed multiplier @@ -121,6 +123,12 @@ namespace MWWorld // Rain sound effect std::string mRainLoopSoundID; + // Is this an ash storm / blight storm? This controls two things: + // - The particle node will be oriented so that the particles appear to come from the Red Mountain. (not implemented yet) + // - Characters will animate their hand to protect eyes from the storm when looking in its direction (idlestorm animation) + // Possible effect on movement speed? + bool mIsStorm; + std::string mParticleEffect; // Note: For Weather Blight, there is a "Disease Chance" (=0.1) setting. But according to MWSFD this feature @@ -156,6 +164,11 @@ namespace MWWorld float getWindSpeed() const; + /// Are we in an ash or blight storm? + bool isInStorm() const; + + Ogre::Vector3 getStormDirection() const; + void advanceTime(double hours) { mTimePassed += hours*3600; diff --git a/apps/openmw/mwworld/worldimp.cpp b/apps/openmw/mwworld/worldimp.cpp index 30024d310..35042b3ff 100644 --- a/apps/openmw/mwworld/worldimp.cpp +++ b/apps/openmw/mwworld/worldimp.cpp @@ -1998,6 +1998,22 @@ namespace MWWorld return 0.f; } + bool World::isInStorm() const + { + if (isCellExterior() || isCellQuasiExterior()) + return mWeatherManager->isInStorm(); + else + return false; + } + + Ogre::Vector3 World::getStormDirection() const + { + if (isCellExterior() || isCellQuasiExterior()) + return mWeatherManager->getStormDirection(); + else + return Ogre::Vector3(0,1,0); + } + void World::getContainersOwnedBy (const MWWorld::Ptr& npc, std::vector& out) { const Scene::CellStoreCollection& collection = mWorldScene->getActiveCells(); @@ -2313,6 +2329,7 @@ namespace MWWorld { MWMechanics::CreatureStats& stats = actor.getClass().getCreatureStats(actor); + // TODO: this only works for the player MWWorld::Ptr target = getFacedObject(); std::string selectedSpell = stats.getSpells().getSelectedSpell(); diff --git a/apps/openmw/mwworld/worldimp.hpp b/apps/openmw/mwworld/worldimp.hpp index 8cb2ac18a..69b72b533 100644 --- a/apps/openmw/mwworld/worldimp.hpp +++ b/apps/openmw/mwworld/worldimp.hpp @@ -591,6 +591,12 @@ namespace MWWorld const MWWorld::Ptr& caster, const std::string& id, const std::string& sourceName); virtual void activate (const MWWorld::Ptr& object, const MWWorld::Ptr& actor); + + /// @see MWWorld::WeatherManager::isInStorm + virtual bool isInStorm() const; + + /// @see MWWorld::WeatherManager::getStormDirection + virtual Ogre::Vector3 getStormDirection() const; }; }