From 7cc55022a1d616b289d95a66ce0cd3d58f09611a Mon Sep 17 00:00:00 2001 From: Evil Eye Date: Mon, 19 Sep 2022 19:05:22 +0200 Subject: [PATCH] Implement sun damage based on the research on the wiki --- CHANGELOG.md | 1 + apps/openmw/mwbase/world.hpp | 3 +++ apps/openmw/mwmechanics/spelleffects.cpp | 10 ++-------- apps/openmw/mwworld/weather.cpp | 25 ++++++++++++++++++++++-- apps/openmw/mwworld/weather.hpp | 9 +++++++-- apps/openmw/mwworld/worldimp.cpp | 10 ++++++++++ apps/openmw/mwworld/worldimp.hpp | 3 +++ 7 files changed, 49 insertions(+), 12 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index d5641fd18c..923b58edf9 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -13,6 +13,7 @@ Bug #6949: Sun Damage effect doesn't work in quasi exteriors Bug #6964: Nerasa Dralor Won't Follow Bug #6974: Only harmful effects are reflected + Bug #6977: Sun damage implementation does not match research Bug #6986: Sound magic effect does not make noise Bug #6987: Set/Mod Blindness should not darken the screen Bug #6992: Crossbow reloading doesn't look the same as in Morrowind diff --git a/apps/openmw/mwbase/world.hpp b/apps/openmw/mwbase/world.hpp index a99adb771e..e6322dfda4 100644 --- a/apps/openmw/mwbase/world.hpp +++ b/apps/openmw/mwbase/world.hpp @@ -564,6 +564,9 @@ namespace MWBase // Allow NPCs to use torches? virtual bool useTorches() const = 0; + virtual float getSunVisibility() const = 0; + virtual float getSunPercentage() const = 0; + virtual bool findInteriorPositionInWorldSpace(const MWWorld::CellStore* cell, osg::Vec3f& result) = 0; /// Teleports \a ptr to the closest reference of \a id (e.g. DivineMarker, PrisonMarker, TempleMarker) diff --git a/apps/openmw/mwmechanics/spelleffects.cpp b/apps/openmw/mwmechanics/spelleffects.cpp index f83d76efbd..99d5dcce2b 100644 --- a/apps/openmw/mwmechanics/spelleffects.cpp +++ b/apps/openmw/mwmechanics/spelleffects.cpp @@ -664,15 +664,9 @@ void applyMagicEffect(const MWWorld::Ptr& target, const MWWorld::Ptr& caster, co // isInCell shouldn't be needed, but updateActor called during game start if (!target.isInCell() || !(target.getCell()->isExterior() || target.getCell()->isQuasiExterior()) || godmode) break; - float time = world->getTimeStamp().getHour(); - float timeDiff = std::clamp(std::abs(time - 13.f), 0.f, 7.f); - float damageScale = 1.f - timeDiff / 7.f; - // When cloudy, the sun damage effect is halved + const float sunRisen = world->getSunPercentage(); static float fMagicSunBlockedMult = world->getStore().get().find("fMagicSunBlockedMult")->mValue.getFloat(); - - int weather = world->getCurrentWeather(); - if (weather > 1) - damageScale *= fMagicSunBlockedMult; + const float damageScale = std::clamp(std::max(world->getSunVisibility() * sunRisen, fMagicSunBlockedMult * sunRisen), 0.f, 1.f); float damage = effect.mMagnitude * damageScale; adjustDynamicStat(target, 0, -damage); if (damage > 0.f) diff --git a/apps/openmw/mwworld/weather.cpp b/apps/openmw/mwworld/weather.cpp index 4a3690daf7..66c3b9f2d5 100644 --- a/apps/openmw/mwworld/weather.cpp +++ b/apps/openmw/mwworld/weather.cpp @@ -176,8 +176,8 @@ namespace , mParticleEffect(particleEffect) , mRainEffect(Fallback::Map::getBool("Weather_" + name + "_Using_Precip") ? "meshes\\raindrop.nif" : "") , mStormDirection(Weather::defaultDirection()) - , mTransitionDelta(Fallback::Map::getFloat("Weather_" + name + "_Transition_Delta")) , mCloudsMaximumPercent(Fallback::Map::getFloat("Weather_" + name + "_Clouds_Maximum_Percent")) + , mTransitionDelta(Fallback::Map::getFloat("Weather_" + name + "_Transition_Delta")) , mThunderFrequency(Fallback::Map::getFloat("Weather_" + name + "_Thunder_Frequency")) , mThunderThreshold(Fallback::Map::getFloat("Weather_" + name + "_Thunder_Threshold")) , mThunderSoundID() @@ -875,6 +875,27 @@ namespace return isDark && !mPrecipitation; } + float WeatherManager::getSunPercentage(float hour) const + { + if (hour <= mTimeSettings.mNightEnd || hour >= mTimeSettings.mNightStart) + return 0.f; + else if (hour <= mTimeSettings.mDayStart) + return (hour - mTimeSettings.mNightEnd) / mSunriseDuration; + else if (hour > mTimeSettings.mDayEnd) + return 1.f - ((hour - mTimeSettings.mDayEnd) / mSunsetDuration); + return 1.f; + } + + float WeatherManager::getSunVisibility() const + { + if (inTransition() && mTransitionFactor < mWeatherSettings[mNextWeather].mCloudsMaximumPercent) + { + float t = mTransitionFactor / mWeatherSettings[mNextWeather].mCloudsMaximumPercent; + return (1.f - t) * mWeatherSettings[mCurrentWeather].mGlareView + t * mWeatherSettings[mNextWeather].mGlareView; + } + return mWeatherSettings[mCurrentWeather].mGlareView; + } + void WeatherManager::write(ESM::ESMWriter& writer, Loading::Listener& progress) { ESM::WeatherState state; @@ -1072,7 +1093,7 @@ namespace mQueuedWeather = invalidWeatherID; } - inline bool WeatherManager::inTransition() + inline bool WeatherManager::inTransition() const { return mNextWeather != invalidWeatherID; } diff --git a/apps/openmw/mwworld/weather.hpp b/apps/openmw/mwworld/weather.hpp index 28723b828f..5b706f598c 100644 --- a/apps/openmw/mwworld/weather.hpp +++ b/apps/openmw/mwworld/weather.hpp @@ -193,6 +193,8 @@ namespace MWWorld osg::Vec3f mStormDirection; + float mCloudsMaximumPercent; + // Note: For Weather Blight, there is a "Disease Chance" (=0.1) setting. But according to MWSFD this feature // is broken in the vanilla game and was disabled. @@ -203,7 +205,6 @@ namespace MWWorld private: float mTransitionDelta; - float mCloudsMaximumPercent; // Note: In MW, only thunderstorms support these attributes, but in the interest of making weather more // flexible, these settings are imported for all weather types. Only thunderstorms will normally have any @@ -315,6 +316,10 @@ namespace MWWorld bool useTorches(float hour) const; + float getSunPercentage(float hour) const; + + float getSunVisibility() const; + void write(ESM::ESMWriter& writer, Loading::Listener& progress); bool readRecord(ESM::ESMReader& reader, uint32_t type); @@ -379,7 +384,7 @@ namespace MWWorld void updateWeatherTransitions(const float elapsedRealSeconds); void forceWeather(const int weatherID); - bool inTransition(); + bool inTransition() const; void addWeatherTransition(const int weatherID); void calculateWeatherResult(const float gameHour, const float elapsedSeconds, const bool isPaused); diff --git a/apps/openmw/mwworld/worldimp.cpp b/apps/openmw/mwworld/worldimp.cpp index e5be728360..e0d89acf40 100644 --- a/apps/openmw/mwworld/worldimp.cpp +++ b/apps/openmw/mwworld/worldimp.cpp @@ -3260,6 +3260,16 @@ namespace MWWorld } } + float World::getSunVisibility() const + { + return mWeatherManager->getSunVisibility(); + } + + float World::getSunPercentage() const + { + return mWeatherManager->getSunPercentage(getTimeStamp().getHour()); + } + bool World::findInteriorPositionInWorldSpace(const MWWorld::CellStore* cell, osg::Vec3f& result) { if (cell->isExterior()) diff --git a/apps/openmw/mwworld/worldimp.hpp b/apps/openmw/mwworld/worldimp.hpp index c6bde113f4..b62a7581c2 100644 --- a/apps/openmw/mwworld/worldimp.hpp +++ b/apps/openmw/mwworld/worldimp.hpp @@ -668,6 +668,9 @@ namespace MWWorld // Allow NPCs to use torches? bool useTorches() const override; + float getSunVisibility() const override; + float getSunPercentage() const override; + bool findInteriorPositionInWorldSpace(const MWWorld::CellStore* cell, osg::Vec3f& result) override; /// Teleports \a ptr to the closest reference of \a id (e.g. DivineMarker, PrisonMarker, TempleMarker)