mirror of
https://github.com/TES3MP/openmw-tes3mp.git
synced 2025-01-16 04:19:55 +00:00
91a4d9a2eb
Added method in WeatherManger and World which returns true if it is night. This method is used later in character controller to show torches (or other sources of light) at night and hide them at day. Signed-off-by: Lukasz Gromanowski <lgromanowski@gmail.com>
714 lines
25 KiB
C++
714 lines
25 KiB
C++
#include "weather.hpp"
|
|
|
|
#include <boost/algorithm/string.hpp>
|
|
#include "../mwbase/environment.hpp"
|
|
#include "../mwbase/world.hpp"
|
|
#include "../mwbase/soundmanager.hpp"
|
|
|
|
#include "../mwrender/renderingmanager.hpp"
|
|
|
|
#include "player.hpp"
|
|
#include "esmstore.hpp"
|
|
#include "fallback.hpp"
|
|
|
|
using namespace Ogre;
|
|
using namespace MWWorld;
|
|
using namespace MWSound;
|
|
|
|
namespace
|
|
{
|
|
float lerp (float x, float y, float factor)
|
|
{
|
|
return x * (1-factor) + y * factor;
|
|
}
|
|
|
|
Ogre::ColourValue lerp (const Ogre::ColourValue& x, const Ogre::ColourValue& y, float factor)
|
|
{
|
|
return x * (1-factor) + y * factor;
|
|
}
|
|
}
|
|
|
|
void WeatherManager::setFallbackWeather(Weather& weather,const std::string& name)
|
|
{
|
|
std::string upper=name;
|
|
upper[0]=toupper(name[0]);
|
|
weather.mCloudsMaximumPercent = mFallback->getFallbackFloat("Weather_"+upper+"_Clouds_Maximum_Percent");
|
|
weather.mTransitionDelta = mFallback->getFallbackFloat("Weather_"+upper+"_Transition_Delta");
|
|
weather.mSkySunriseColor=mFallback->getFallbackColour("Weather_"+upper+"_Sky_Sunrise_Color");
|
|
weather.mSkyDayColor = mFallback->getFallbackColour("Weather_"+upper+"_Sky_Day_Color");
|
|
weather.mSkySunsetColor = mFallback->getFallbackColour("Weather_"+upper+"_Sky_Sunset_Color");
|
|
weather.mSkyNightColor = mFallback->getFallbackColour("Weather_"+upper+"_Sky_Night_Color");
|
|
weather.mFogSunriseColor = mFallback->getFallbackColour("Weather_"+upper+"_Fog_Sunrise_Color");
|
|
weather.mFogDayColor = mFallback->getFallbackColour("Weather_"+upper+"_Fog_Day_Color");
|
|
weather.mFogSunsetColor = mFallback->getFallbackColour("Weather_"+upper+"_Fog_Sunset_Color");
|
|
weather.mFogNightColor = mFallback->getFallbackColour("Weather_"+upper+"_Fog_Night_Color");
|
|
weather.mAmbientSunriseColor = mFallback->getFallbackColour("Weather_"+upper+"_Ambient_Sunrise_Color");
|
|
weather.mAmbientDayColor = mFallback->getFallbackColour("Weather_"+upper+"_Ambient_Day_Color");
|
|
weather.mAmbientSunsetColor = mFallback->getFallbackColour("Weather_"+upper+"_Ambient_Sunset_Color");
|
|
weather.mAmbientNightColor = mFallback->getFallbackColour("Weather_"+upper+"_Ambient_Night_Color");
|
|
weather.mSunSunriseColor = mFallback->getFallbackColour("Weather_"+upper+"_Sun_Sunrise_Color");
|
|
weather.mSunDayColor = mFallback->getFallbackColour("Weather_"+upper+"_Sun_Day_Color");
|
|
weather.mSunSunsetColor = mFallback->getFallbackColour("Weather_"+upper+"_Sun_Sunset_Color");
|
|
weather.mSunNightColor = mFallback->getFallbackColour("Weather_"+upper+"_Sun_Night_Color");
|
|
weather.mSunDiscSunsetColor = mFallback->getFallbackColour("Weather_"+upper+"_Sun_Disc_Sunset_Color");
|
|
weather.mLandFogDayDepth = mFallback->getFallbackFloat("Weather_"+upper+"_Land_Fog_Day_Depth");
|
|
weather.mLandFogNightDepth = mFallback->getFallbackFloat("Weather_"+upper+"_Land_Fog_Night_Depth");
|
|
weather.mWindSpeed = mFallback->getFallbackFloat("Weather_"+upper+"_Wind_Speed");
|
|
weather.mCloudSpeed = mFallback->getFallbackFloat("Weather_"+upper+"_Cloud_Speed");
|
|
weather.mGlareView = mFallback->getFallbackFloat("Weather_"+upper+"_Glare_View");
|
|
mWeatherSettings[name] = weather;
|
|
}
|
|
|
|
|
|
float WeatherManager::calculateHourFade (const std::string& moonName) const
|
|
{
|
|
float fadeOutStart=mFallback->getFallbackFloat("Moons_"+moonName+"_Fade_Out_Start");
|
|
float fadeOutFinish=mFallback->getFallbackFloat("Moons_"+moonName+"_Fade_Out_Finish");
|
|
float fadeInStart=mFallback->getFallbackFloat("Moons_"+moonName+"_Fade_In_Start");
|
|
float fadeInFinish=mFallback->getFallbackFloat("Moons_"+moonName+"_Fade_In_Finish");
|
|
|
|
if (mHour >= fadeOutStart && mHour <= fadeOutFinish)
|
|
return (1 - ((mHour - fadeOutStart) / (fadeOutFinish - fadeOutStart)));
|
|
if (mHour >= fadeInStart && mHour <= fadeInFinish)
|
|
return (1 - ((mHour - fadeInStart) / (fadeInFinish - fadeInStart)));
|
|
else
|
|
return 1;
|
|
}
|
|
|
|
float WeatherManager::calculateAngleFade (const std::string& moonName, float angle) const
|
|
{
|
|
float endAngle=mFallback->getFallbackFloat("Moons_"+moonName+"_Fade_End_Angle");
|
|
float startAngle=mFallback->getFallbackFloat("Moons_"+moonName+"_Fade_Start_Angle");
|
|
if (angle <= startAngle && angle >= endAngle)
|
|
return (1 - ((angle - endAngle)/(startAngle-endAngle)));
|
|
else if (angle > startAngle)
|
|
return 0.f;
|
|
else
|
|
return 1.f;
|
|
}
|
|
|
|
WeatherManager::WeatherManager(MWRender::RenderingManager* rendering,MWWorld::Fallback* fallback) :
|
|
mHour(14), mCurrentWeather("clear"), mNextWeather(""), mFirstUpdate(true),
|
|
mWeatherUpdateTime(0), mThunderFlash(0), mThunderChance(0),
|
|
mThunderChanceNeeded(50), mThunderSoundDelay(0), mRemainingTransitionTime(0),
|
|
mMonth(0), mDay(0), mTimePassed(0), mFallback(fallback), mWindSpeed(0.f),
|
|
mRendering(rendering)
|
|
{
|
|
//Globals
|
|
mThunderSoundID0 = mFallback->getFallbackString("Weather_Thunderstorm_Thunder_Sound_ID_0");
|
|
mThunderSoundID1 = mFallback->getFallbackString("Weather_Thunderstorm_Thunder_Sound_ID_1");
|
|
mThunderSoundID2 = mFallback->getFallbackString("Weather_Thunderstorm_Thunder_Sound_ID_2");
|
|
mThunderSoundID3 = mFallback->getFallbackString("Weather_Thunderstorm_Thunder_Sound_ID_3");
|
|
mSunriseTime = mFallback->getFallbackFloat("Weather_Sunrise_Time");
|
|
mSunsetTime = mFallback->getFallbackFloat("Weather_Sunset_Time");
|
|
mSunriseDuration = mFallback->getFallbackFloat("Weather_Sunrise_Duration");
|
|
mSunsetDuration = mFallback->getFallbackFloat("Weather_Sunset_Duration");
|
|
mHoursBetweenWeatherChanges = mFallback->getFallbackFloat("Weather_Hours_Between_Weather_Changes");
|
|
mWeatherUpdateTime = mHoursBetweenWeatherChanges * 3600;
|
|
mThunderFrequency = mFallback->getFallbackFloat("Weather_Thunderstorm_Thunder_Frequency");
|
|
mThunderThreshold = mFallback->getFallbackFloat("Weather_Thunderstorm_Thunder_Threshold");
|
|
mThunderSoundDelay = 0.25;
|
|
|
|
//Some useful values
|
|
/* TODO: Use pre-sunrise_time, pre-sunset_time,
|
|
* post-sunrise_time, and post-sunset_time to better
|
|
* describe sunrise/sunset time.
|
|
* These values are fallbacks attached to weather.
|
|
*/
|
|
mNightStart = mSunsetTime + mSunsetDuration;
|
|
mNightEnd = mSunriseTime - 0.5;
|
|
mDayStart = mSunriseTime + mSunriseDuration;
|
|
mDayEnd = mSunsetTime;
|
|
|
|
//Weather
|
|
Weather clear;
|
|
clear.mCloudTexture = "tx_sky_clear.dds";
|
|
setFallbackWeather(clear,"clear");
|
|
|
|
Weather cloudy;
|
|
cloudy.mCloudTexture = "tx_sky_cloudy.dds";
|
|
setFallbackWeather(cloudy,"cloudy");
|
|
|
|
Weather foggy;
|
|
foggy.mCloudTexture = "tx_sky_foggy.dds";
|
|
setFallbackWeather(foggy,"foggy");
|
|
|
|
Weather thunderstorm;
|
|
thunderstorm.mCloudTexture = "tx_sky_thunder.dds";
|
|
thunderstorm.mRainLoopSoundID = "rain heavy";
|
|
setFallbackWeather(thunderstorm,"thunderstorm");
|
|
|
|
Weather rain;
|
|
rain.mCloudTexture = "tx_sky_rainy.dds";
|
|
rain.mRainLoopSoundID = "rain";
|
|
setFallbackWeather(rain,"rain");
|
|
|
|
Weather overcast;
|
|
overcast.mCloudTexture = "tx_sky_overcast.dds";
|
|
setFallbackWeather(overcast,"overcast");
|
|
|
|
Weather ashstorm;
|
|
ashstorm.mCloudTexture = "tx_sky_ashstorm.dds";
|
|
ashstorm.mAmbientLoopSoundID = "ashstorm";
|
|
setFallbackWeather(ashstorm,"ashstorm");
|
|
|
|
Weather blight;
|
|
blight.mCloudTexture = "tx_sky_blight.dds";
|
|
blight.mAmbientLoopSoundID = "blight";
|
|
setFallbackWeather(blight,"blight");
|
|
|
|
Weather snow;
|
|
snow.mCloudTexture = "tx_bm_sky_snow.dds";
|
|
setFallbackWeather(snow, "snow");
|
|
|
|
Weather blizzard;
|
|
blizzard.mCloudTexture = "tx_bm_sky_blizzard.dds";
|
|
blizzard.mAmbientLoopSoundID = "BM Blizzard";
|
|
setFallbackWeather(blizzard,"blizzard");
|
|
}
|
|
|
|
WeatherManager::~WeatherManager()
|
|
{
|
|
stopSounds(true);
|
|
}
|
|
|
|
void WeatherManager::setWeather(const String& weather, bool instant)
|
|
{
|
|
if (weather == mCurrentWeather && mNextWeather == "")
|
|
{
|
|
mFirstUpdate = false;
|
|
return;
|
|
}
|
|
|
|
if (instant || mFirstUpdate)
|
|
{
|
|
mNextWeather = "";
|
|
mCurrentWeather = weather;
|
|
}
|
|
else
|
|
{
|
|
if (mNextWeather != "")
|
|
{
|
|
// transition more than 50% finished?
|
|
if (mRemainingTransitionTime/(mWeatherSettings[mCurrentWeather].mTransitionDelta * 24.f * 3600) <= 0.5)
|
|
mCurrentWeather = mNextWeather;
|
|
}
|
|
|
|
mNextWeather = weather;
|
|
mRemainingTransitionTime = mWeatherSettings[mCurrentWeather].mTransitionDelta * 24.f * 3600;
|
|
}
|
|
mFirstUpdate = false;
|
|
}
|
|
|
|
void WeatherManager::setResult(const String& weatherType)
|
|
{
|
|
const Weather& current = mWeatherSettings[weatherType];
|
|
|
|
mResult.mCloudTexture = current.mCloudTexture;
|
|
mResult.mCloudBlendFactor = 0;
|
|
mResult.mCloudOpacity = current.mCloudsMaximumPercent;
|
|
mResult.mWindSpeed = current.mWindSpeed;
|
|
mResult.mCloudSpeed = current.mCloudSpeed;
|
|
mResult.mGlareView = current.mGlareView;
|
|
mResult.mAmbientLoopSoundID = current.mAmbientLoopSoundID;
|
|
mResult.mSunColor = current.mSunDiscSunsetColor;
|
|
|
|
mResult.mNight = (mHour < mSunriseTime || mHour > mNightStart - 1);
|
|
|
|
mResult.mFogDepth = mResult.mNight ? current.mLandFogNightDepth : current.mLandFogDayDepth;
|
|
|
|
// night
|
|
if (mHour <= mNightEnd || mHour >= mNightStart + 1)
|
|
{
|
|
mResult.mFogColor = current.mFogNightColor;
|
|
mResult.mAmbientColor = current.mAmbientNightColor;
|
|
mResult.mSunColor = current.mSunNightColor;
|
|
mResult.mSkyColor = current.mSkyNightColor;
|
|
mResult.mNightFade = 1.f;
|
|
}
|
|
|
|
// sunrise
|
|
else if (mHour >= mNightEnd && mHour <= mDayStart + 1)
|
|
{
|
|
if (mHour <= mSunriseTime)
|
|
{
|
|
// fade in
|
|
float advance = mSunriseTime - mHour;
|
|
float factor = advance / 0.5f;
|
|
mResult.mFogColor = lerp(current.mFogSunriseColor, current.mFogNightColor, factor);
|
|
mResult.mAmbientColor = lerp(current.mAmbientSunriseColor, current.mAmbientNightColor, factor);
|
|
mResult.mSunColor = lerp(current.mSunSunriseColor, current.mSunNightColor, factor);
|
|
mResult.mSkyColor = lerp(current.mSkySunriseColor, current.mSkyNightColor, factor);
|
|
mResult.mNightFade = factor;
|
|
}
|
|
else //if (mHour >= 6)
|
|
{
|
|
// fade out
|
|
float advance = mHour - mSunriseTime;
|
|
float factor = advance / 3.f;
|
|
mResult.mFogColor = lerp(current.mFogSunriseColor, current.mFogDayColor, factor);
|
|
mResult.mAmbientColor = lerp(current.mAmbientSunriseColor, current.mAmbientDayColor, factor);
|
|
mResult.mSunColor = lerp(current.mSunSunriseColor, current.mSunDayColor, factor);
|
|
mResult.mSkyColor = lerp(current.mSkySunriseColor, current.mSkyDayColor, factor);
|
|
}
|
|
}
|
|
|
|
// day
|
|
else if (mHour >= mDayStart + 1 && mHour <= mDayEnd - 1)
|
|
{
|
|
mResult.mFogColor = current.mFogDayColor;
|
|
mResult.mAmbientColor = current.mAmbientDayColor;
|
|
mResult.mSunColor = current.mSunDayColor;
|
|
mResult.mSkyColor = current.mSkyDayColor;
|
|
}
|
|
|
|
// sunset
|
|
else if (mHour >= mDayEnd - 1 && mHour <= mNightStart + 1)
|
|
{
|
|
if (mHour <= mDayEnd + 1)
|
|
{
|
|
// fade in
|
|
float advance = (mDayEnd + 1) - mHour;
|
|
float factor = (advance / 2);
|
|
mResult.mFogColor = lerp(current.mFogSunsetColor, current.mFogDayColor, factor);
|
|
mResult.mAmbientColor = lerp(current.mAmbientSunsetColor, current.mAmbientDayColor, factor);
|
|
mResult.mSunColor = lerp(current.mSunSunsetColor, current.mSunDayColor, factor);
|
|
mResult.mSkyColor = lerp(current.mSkySunsetColor, current.mSkyDayColor, factor);
|
|
}
|
|
else //if (mHour >= 19)
|
|
{
|
|
// fade out
|
|
float advance = mHour - (mDayEnd + 1);
|
|
float factor = advance / 2.f;
|
|
mResult.mFogColor = lerp(current.mFogSunsetColor, current.mFogNightColor, factor);
|
|
mResult.mAmbientColor = lerp(current.mAmbientSunsetColor, current.mAmbientNightColor, factor);
|
|
mResult.mSunColor = lerp(current.mSunSunsetColor, current.mSunNightColor, factor);
|
|
mResult.mSkyColor = lerp(current.mSkySunsetColor, current.mSkyNightColor, factor);
|
|
mResult.mNightFade = factor;
|
|
}
|
|
}
|
|
}
|
|
|
|
void WeatherManager::transition(float factor)
|
|
{
|
|
setResult(mCurrentWeather);
|
|
const WeatherResult current = mResult;
|
|
setResult(mNextWeather);
|
|
const WeatherResult other = mResult;
|
|
|
|
mResult.mCloudTexture = current.mCloudTexture;
|
|
mResult.mNextCloudTexture = other.mCloudTexture;
|
|
mResult.mCloudBlendFactor = factor;
|
|
|
|
mResult.mCloudOpacity = lerp(current.mCloudOpacity, other.mCloudOpacity, factor);
|
|
mResult.mFogColor = lerp(current.mFogColor, other.mFogColor, factor);
|
|
mResult.mSunColor = lerp(current.mSunColor, other.mSunColor, factor);
|
|
mResult.mSkyColor = lerp(current.mSkyColor, other.mSkyColor, factor);
|
|
|
|
mResult.mAmbientColor = lerp(current.mAmbientColor, other.mAmbientColor, factor);
|
|
mResult.mSunDiscColor = lerp(current.mSunDiscColor, other.mSunDiscColor, factor);
|
|
mResult.mFogDepth = lerp(current.mFogDepth, other.mFogDepth, factor);
|
|
mResult.mWindSpeed = lerp(current.mWindSpeed, other.mWindSpeed, factor);
|
|
mResult.mCloudSpeed = lerp(current.mCloudSpeed, other.mCloudSpeed, factor);
|
|
mResult.mCloudOpacity = lerp(current.mCloudOpacity, other.mCloudOpacity, factor);
|
|
mResult.mGlareView = lerp(current.mGlareView, other.mGlareView, factor);
|
|
mResult.mNightFade = lerp(current.mNightFade, other.mNightFade, factor);
|
|
|
|
mResult.mNight = current.mNight;
|
|
}
|
|
|
|
void WeatherManager::update(float duration)
|
|
{
|
|
float timePassed = mTimePassed;
|
|
mTimePassed = 0;
|
|
|
|
mWeatherUpdateTime -= timePassed;
|
|
|
|
const bool exterior = (MWBase::Environment::get().getWorld()->isCellExterior() || MWBase::Environment::get().getWorld()->isCellQuasiExterior());
|
|
if (!exterior)
|
|
{
|
|
mRendering->sunDisable(false);
|
|
mRendering->skyDisable();
|
|
mRendering->getSkyManager()->setLightningStrength(0.f);
|
|
stopSounds(true);
|
|
return;
|
|
}
|
|
|
|
// Exterior
|
|
std::string regionstr = Misc::StringUtils::lowerCase(MWBase::Environment::get().getWorld()->getPlayer().getPlayer().getCell()->mCell->mRegion);
|
|
|
|
if (mWeatherUpdateTime <= 0 || regionstr != mCurrentRegion)
|
|
{
|
|
mCurrentRegion = regionstr;
|
|
mWeatherUpdateTime = mHoursBetweenWeatherChanges * 3600;
|
|
|
|
std::string weatherType = "clear";
|
|
|
|
if (mRegionOverrides.find(regionstr) != mRegionOverrides.end())
|
|
weatherType = mRegionOverrides[regionstr];
|
|
else
|
|
{
|
|
// get weather probabilities for the current region
|
|
const ESM::Region *region =
|
|
MWBase::Environment::get().getWorld()->getStore().get<ESM::Region>().search (regionstr);
|
|
|
|
if (region != 0)
|
|
{
|
|
weatherType = nextWeather(region);
|
|
}
|
|
}
|
|
|
|
setWeather(weatherType, false);
|
|
}
|
|
|
|
if (mNextWeather != "")
|
|
{
|
|
mRemainingTransitionTime -= timePassed;
|
|
if (mRemainingTransitionTime < 0)
|
|
{
|
|
mCurrentWeather = mNextWeather;
|
|
mNextWeather = "";
|
|
}
|
|
}
|
|
|
|
if (mNextWeather != "")
|
|
transition(1 - (mRemainingTransitionTime / (mWeatherSettings[mCurrentWeather].mTransitionDelta * 24.f * 3600)));
|
|
else
|
|
setResult(mCurrentWeather);
|
|
|
|
mWindSpeed = mResult.mWindSpeed;
|
|
|
|
mRendering->configureFog(mResult.mFogDepth, mResult.mFogColor);
|
|
|
|
// disable sun during night
|
|
if (mHour >= mNightStart || mHour <= mSunriseTime)
|
|
mRendering->getSkyManager()->sunDisable();
|
|
else
|
|
mRendering->getSkyManager()->sunEnable();
|
|
|
|
// sun angle
|
|
float height;
|
|
|
|
//Day duration
|
|
float dayDuration = (mNightStart - 1) - mSunriseTime;
|
|
|
|
// rise at 6, set at 20
|
|
if (mHour >= mSunriseTime && mHour <= mNightStart)
|
|
height = 1 - std::abs(((mHour - dayDuration) / 7.f));
|
|
else if (mHour > mNightStart)
|
|
height = (mHour - mNightStart) / 4.f;
|
|
else //if (mHour > 0 && mHour < 6)
|
|
height = 1 - (mHour / mSunriseTime);
|
|
|
|
int facing = (mHour > 13.f) ? 1 : -1;
|
|
|
|
Vector3 final(
|
|
(height - 1) * facing,
|
|
(height - 1) * facing,
|
|
height);
|
|
mRendering->setSunDirection(final);
|
|
|
|
/*
|
|
* TODO: import separated fadeInStart/Finish, fadeOutStart/Finish
|
|
* for masser and secunda
|
|
*/
|
|
|
|
float fadeOutFinish=mFallback->getFallbackFloat("Moons_Masser_Fade_Out_Finish");
|
|
float fadeInStart=mFallback->getFallbackFloat("Moons_Masser_Fade_In_Start");
|
|
|
|
//moon calculations
|
|
float moonHeight;
|
|
if (mHour >= fadeInStart)
|
|
moonHeight = mHour - fadeInStart;
|
|
else if (mHour <= fadeOutFinish)
|
|
moonHeight = mHour + fadeOutFinish;
|
|
else
|
|
moonHeight = 0;
|
|
|
|
moonHeight /= (24.f - (fadeInStart - fadeOutFinish));
|
|
|
|
if (moonHeight != 0)
|
|
{
|
|
int facing = (moonHeight <= 1) ? 1 : -1;
|
|
Vector3 masser(
|
|
(moonHeight - 1) * facing,
|
|
(1 - moonHeight) * facing,
|
|
moonHeight);
|
|
|
|
Vector3 secunda(
|
|
(moonHeight - 1) * facing * 1.25,
|
|
(1 - moonHeight) * facing * 0.8,
|
|
moonHeight);
|
|
|
|
mRendering->getSkyManager()->setMasserDirection(masser);
|
|
mRendering->getSkyManager()->setSecundaDirection(secunda);
|
|
mRendering->getSkyManager()->masserEnable();
|
|
mRendering->getSkyManager()->secundaEnable();
|
|
|
|
float angle = (1-moonHeight) * 90.f * facing;
|
|
float masserHourFade = calculateHourFade("Masser");
|
|
float secundaHourFade = calculateHourFade("Secunda");
|
|
float masserAngleFade = calculateAngleFade("Masser", angle);
|
|
float secundaAngleFade = calculateAngleFade("Secunda", angle);
|
|
|
|
masserAngleFade *= masserHourFade;
|
|
secundaAngleFade *= secundaHourFade;
|
|
|
|
mRendering->getSkyManager()->setMasserFade(masserAngleFade);
|
|
mRendering->getSkyManager()->setSecundaFade(secundaAngleFade);
|
|
}
|
|
else
|
|
{
|
|
mRendering->getSkyManager()->masserDisable();
|
|
mRendering->getSkyManager()->secundaDisable();
|
|
}
|
|
|
|
if (mCurrentWeather == "thunderstorm" && mNextWeather == "")
|
|
{
|
|
if (mThunderFlash > 0)
|
|
{
|
|
// play the sound after a delay
|
|
mThunderSoundDelay -= duration;
|
|
if (mThunderSoundDelay <= 0)
|
|
{
|
|
// pick a random sound
|
|
int sound = rand() % 4;
|
|
std::string* soundName = NULL;
|
|
if (sound == 0) soundName = &mThunderSoundID0;
|
|
else if (sound == 1) soundName = &mThunderSoundID1;
|
|
else if (sound == 2) soundName = &mThunderSoundID2;
|
|
else if (sound == 3) soundName = &mThunderSoundID3;
|
|
MWBase::Environment::get().getSoundManager()->playSound(*soundName, 1.0, 1.0);
|
|
mThunderSoundDelay = 1000;
|
|
}
|
|
|
|
mThunderFlash -= duration;
|
|
if (mThunderFlash > 0)
|
|
mRendering->getSkyManager()->setLightningStrength( mThunderFlash / mThunderThreshold );
|
|
else
|
|
{
|
|
mThunderChanceNeeded = rand() % 100;
|
|
mThunderChance = 0;
|
|
mRendering->getSkyManager()->setLightningStrength( 0.f );
|
|
}
|
|
}
|
|
else
|
|
{
|
|
// no thunder active
|
|
mThunderChance += duration*4; // chance increases by 4 percent every second
|
|
if (mThunderChance >= mThunderChanceNeeded)
|
|
{
|
|
mThunderFlash = mThunderThreshold;
|
|
|
|
mRendering->getSkyManager()->setLightningStrength( mThunderFlash / mThunderThreshold );
|
|
|
|
mThunderSoundDelay = 0.25;
|
|
}
|
|
}
|
|
}
|
|
else
|
|
mRendering->getSkyManager()->setLightningStrength(0.f);
|
|
|
|
mRendering->setAmbientColour(mResult.mAmbientColor);
|
|
mRendering->sunEnable(false);
|
|
mRendering->setSunColour(mResult.mSunColor);
|
|
|
|
mRendering->getSkyManager()->setWeather(mResult);
|
|
|
|
|
|
// Play sounds
|
|
if (mNextWeather == "")
|
|
{
|
|
std::string ambientSnd = mWeatherSettings[mCurrentWeather].mAmbientLoopSoundID;
|
|
if (!ambientSnd.empty() && std::find(mSoundsPlaying.begin(), mSoundsPlaying.end(), ambientSnd) == mSoundsPlaying.end())
|
|
{
|
|
mSoundsPlaying.push_back(ambientSnd);
|
|
MWBase::Environment::get().getSoundManager()->playSound(ambientSnd, 1.0, 1.0, MWBase::SoundManager::Play_TypeSfx, MWBase::SoundManager::Play_Loop);
|
|
}
|
|
|
|
std::string rainSnd = mWeatherSettings[mCurrentWeather].mRainLoopSoundID;
|
|
if (!rainSnd.empty() && std::find(mSoundsPlaying.begin(), mSoundsPlaying.end(), rainSnd) == mSoundsPlaying.end())
|
|
{
|
|
mSoundsPlaying.push_back(rainSnd);
|
|
MWBase::Environment::get().getSoundManager()->playSound(rainSnd, 1.0, 1.0, MWBase::SoundManager::Play_TypeSfx, MWBase::SoundManager::Play_Loop);
|
|
}
|
|
}
|
|
|
|
stopSounds(false);
|
|
}
|
|
|
|
void WeatherManager::stopSounds(bool stopAll)
|
|
{
|
|
std::vector<std::string>::iterator it = mSoundsPlaying.begin();
|
|
while (it!=mSoundsPlaying.end())
|
|
{
|
|
if (stopAll ||
|
|
!((*it == mWeatherSettings[mCurrentWeather].mAmbientLoopSoundID) ||
|
|
(*it == mWeatherSettings[mCurrentWeather].mRainLoopSoundID)))
|
|
{
|
|
MWBase::Environment::get().getSoundManager()->stopSound(*it);
|
|
it = mSoundsPlaying.erase(it);
|
|
}
|
|
else
|
|
++it;
|
|
}
|
|
}
|
|
|
|
Ogre::String WeatherManager::nextWeather(const ESM::Region* region) const
|
|
{
|
|
std::vector<char> probability;
|
|
|
|
RegionModMap::const_iterator iter = mRegionMods.find(Misc::StringUtils::lowerCase(region->mId));
|
|
if(iter != mRegionMods.end())
|
|
probability = iter->second;
|
|
else
|
|
{
|
|
probability.reserve(10);
|
|
probability.push_back(region->mData.mClear);
|
|
probability.push_back(region->mData.mCloudy);
|
|
probability.push_back(region->mData.mFoggy);
|
|
probability.push_back(region->mData.mOvercast);
|
|
probability.push_back(region->mData.mRain);
|
|
probability.push_back(region->mData.mThunder);
|
|
probability.push_back(region->mData.mAsh);
|
|
probability.push_back(region->mData.mBlight);
|
|
probability.push_back(region->mData.mA);
|
|
probability.push_back(region->mData.mB);
|
|
}
|
|
|
|
/*
|
|
* All probabilities must add to 100 (responsibility of the user).
|
|
* If chances A and B has values 30 and 70 then by generating
|
|
* 100 numbers 1..100, 30% will be lesser or equal 30 and
|
|
* 70% will be greater than 30 (in theory).
|
|
*/
|
|
|
|
int chance = (rand() % 100) + 1; // 1..100
|
|
int sum = 0;
|
|
unsigned int i = 0;
|
|
for (; i < probability.size(); ++i)
|
|
{
|
|
sum += probability[i];
|
|
if (chance < sum)
|
|
break;
|
|
}
|
|
|
|
switch (i)
|
|
{
|
|
case 1:
|
|
return "cloudy";
|
|
case 2:
|
|
return "foggy";
|
|
case 3:
|
|
return "overcast";
|
|
case 4:
|
|
return "rain";
|
|
case 5:
|
|
return "thunderstorm";
|
|
case 6:
|
|
return "ashstorm";
|
|
case 7:
|
|
return "blight";
|
|
case 8:
|
|
return "snow";
|
|
case 9:
|
|
return "blizzard";
|
|
default: // case 0
|
|
return "clear";
|
|
}
|
|
}
|
|
|
|
void WeatherManager::setHour(const float hour)
|
|
{
|
|
mHour = hour;
|
|
}
|
|
|
|
void WeatherManager::setDate(const int day, const int month)
|
|
{
|
|
mDay = day;
|
|
mMonth = month;
|
|
}
|
|
|
|
unsigned int WeatherManager::getWeatherID() const
|
|
{
|
|
// Source: http://www.uesp.net/wiki/Tes3Mod:GetCurrentWeather
|
|
|
|
if (mCurrentWeather == "clear")
|
|
return 0;
|
|
else if (mCurrentWeather == "cloudy")
|
|
return 1;
|
|
else if (mCurrentWeather == "foggy")
|
|
return 2;
|
|
else if (mCurrentWeather == "overcast")
|
|
return 3;
|
|
else if (mCurrentWeather == "rain")
|
|
return 4;
|
|
else if (mCurrentWeather == "thunderstorm")
|
|
return 5;
|
|
else if (mCurrentWeather == "ashstorm")
|
|
return 6;
|
|
else if (mCurrentWeather == "blight")
|
|
return 7;
|
|
else if (mCurrentWeather == "snow")
|
|
return 8;
|
|
else if (mCurrentWeather == "blizzard")
|
|
return 9;
|
|
|
|
else
|
|
return 0;
|
|
}
|
|
|
|
void WeatherManager::changeWeather(const std::string& region, const unsigned int id)
|
|
{
|
|
// make sure this region exists
|
|
MWBase::Environment::get().getWorld()->getStore().get<ESM::Region>().find(region);
|
|
|
|
std::string weather;
|
|
if (id==0)
|
|
weather = "clear";
|
|
else if (id==1)
|
|
weather = "cloudy";
|
|
else if (id==2)
|
|
weather = "foggy";
|
|
else if (id==3)
|
|
weather = "overcast";
|
|
else if (id==4)
|
|
weather = "rain";
|
|
else if (id==5)
|
|
weather = "thunderstorm";
|
|
else if (id==6)
|
|
weather = "ashstorm";
|
|
else if (id==7)
|
|
weather = "blight";
|
|
else if (id==8)
|
|
weather = "snow";
|
|
else if (id==9)
|
|
weather = "blizzard";
|
|
else
|
|
weather = "clear";
|
|
|
|
mRegionOverrides[Misc::StringUtils::lowerCase(region)] = weather;
|
|
|
|
std::string playerRegion = MWBase::Environment::get().getWorld()->getPlayer().getPlayer().getCell()->mCell->mRegion;
|
|
if (Misc::StringUtils::ciEqual(region, playerRegion))
|
|
setWeather(weather);
|
|
}
|
|
|
|
void WeatherManager::modRegion(const std::string ®ionid, const std::vector<char> &chances)
|
|
{
|
|
mRegionMods[Misc::StringUtils::lowerCase(regionid)] = chances;
|
|
// Start transitioning right away if the region no longer supports the current weather type
|
|
unsigned int current = getWeatherID();
|
|
if(current >= chances.size() || chances[current] == 0)
|
|
mWeatherUpdateTime = 0.0f;
|
|
}
|
|
|
|
float WeatherManager::getWindSpeed() const
|
|
{
|
|
return mWindSpeed;
|
|
}
|
|
|
|
bool WeatherManager::isNight() const
|
|
{
|
|
return (mHour < mSunriseTime || mHour > mNightStart - 1);
|
|
}
|