mirror of
https://github.com/OpenMW/openmw.git
synced 2025-04-17 03:36:45 +00:00
Implement sun damage based on the research on the wiki
This commit is contained in:
parent
92680ab9cf
commit
7cc55022a1
7 changed files with 49 additions and 12 deletions
|
@ -13,6 +13,7 @@
|
||||||
Bug #6949: Sun Damage effect doesn't work in quasi exteriors
|
Bug #6949: Sun Damage effect doesn't work in quasi exteriors
|
||||||
Bug #6964: Nerasa Dralor Won't Follow
|
Bug #6964: Nerasa Dralor Won't Follow
|
||||||
Bug #6974: Only harmful effects are reflected
|
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 #6986: Sound magic effect does not make noise
|
||||||
Bug #6987: Set/Mod Blindness should not darken the screen
|
Bug #6987: Set/Mod Blindness should not darken the screen
|
||||||
Bug #6992: Crossbow reloading doesn't look the same as in Morrowind
|
Bug #6992: Crossbow reloading doesn't look the same as in Morrowind
|
||||||
|
|
|
@ -564,6 +564,9 @@ namespace MWBase
|
||||||
// Allow NPCs to use torches?
|
// Allow NPCs to use torches?
|
||||||
virtual bool useTorches() const = 0;
|
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;
|
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)
|
/// Teleports \a ptr to the closest reference of \a id (e.g. DivineMarker, PrisonMarker, TempleMarker)
|
||||||
|
|
|
@ -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
|
// isInCell shouldn't be needed, but updateActor called during game start
|
||||||
if (!target.isInCell() || !(target.getCell()->isExterior() || target.getCell()->isQuasiExterior()) || godmode)
|
if (!target.isInCell() || !(target.getCell()->isExterior() || target.getCell()->isQuasiExterior()) || godmode)
|
||||||
break;
|
break;
|
||||||
float time = world->getTimeStamp().getHour();
|
const float sunRisen = world->getSunPercentage();
|
||||||
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
|
|
||||||
static float fMagicSunBlockedMult = world->getStore().get<ESM::GameSetting>().find("fMagicSunBlockedMult")->mValue.getFloat();
|
static float fMagicSunBlockedMult = world->getStore().get<ESM::GameSetting>().find("fMagicSunBlockedMult")->mValue.getFloat();
|
||||||
|
const float damageScale = std::clamp(std::max(world->getSunVisibility() * sunRisen, fMagicSunBlockedMult * sunRisen), 0.f, 1.f);
|
||||||
int weather = world->getCurrentWeather();
|
|
||||||
if (weather > 1)
|
|
||||||
damageScale *= fMagicSunBlockedMult;
|
|
||||||
float damage = effect.mMagnitude * damageScale;
|
float damage = effect.mMagnitude * damageScale;
|
||||||
adjustDynamicStat(target, 0, -damage);
|
adjustDynamicStat(target, 0, -damage);
|
||||||
if (damage > 0.f)
|
if (damage > 0.f)
|
||||||
|
|
|
@ -176,8 +176,8 @@ namespace
|
||||||
, mParticleEffect(particleEffect)
|
, mParticleEffect(particleEffect)
|
||||||
, mRainEffect(Fallback::Map::getBool("Weather_" + name + "_Using_Precip") ? "meshes\\raindrop.nif" : "")
|
, mRainEffect(Fallback::Map::getBool("Weather_" + name + "_Using_Precip") ? "meshes\\raindrop.nif" : "")
|
||||||
, mStormDirection(Weather::defaultDirection())
|
, mStormDirection(Weather::defaultDirection())
|
||||||
, mTransitionDelta(Fallback::Map::getFloat("Weather_" + name + "_Transition_Delta"))
|
|
||||||
, mCloudsMaximumPercent(Fallback::Map::getFloat("Weather_" + name + "_Clouds_Maximum_Percent"))
|
, 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"))
|
, mThunderFrequency(Fallback::Map::getFloat("Weather_" + name + "_Thunder_Frequency"))
|
||||||
, mThunderThreshold(Fallback::Map::getFloat("Weather_" + name + "_Thunder_Threshold"))
|
, mThunderThreshold(Fallback::Map::getFloat("Weather_" + name + "_Thunder_Threshold"))
|
||||||
, mThunderSoundID()
|
, mThunderSoundID()
|
||||||
|
@ -875,6 +875,27 @@ namespace
|
||||||
return isDark && !mPrecipitation;
|
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)
|
void WeatherManager::write(ESM::ESMWriter& writer, Loading::Listener& progress)
|
||||||
{
|
{
|
||||||
ESM::WeatherState state;
|
ESM::WeatherState state;
|
||||||
|
@ -1072,7 +1093,7 @@ namespace
|
||||||
mQueuedWeather = invalidWeatherID;
|
mQueuedWeather = invalidWeatherID;
|
||||||
}
|
}
|
||||||
|
|
||||||
inline bool WeatherManager::inTransition()
|
inline bool WeatherManager::inTransition() const
|
||||||
{
|
{
|
||||||
return mNextWeather != invalidWeatherID;
|
return mNextWeather != invalidWeatherID;
|
||||||
}
|
}
|
||||||
|
|
|
@ -193,6 +193,8 @@ namespace MWWorld
|
||||||
|
|
||||||
osg::Vec3f mStormDirection;
|
osg::Vec3f mStormDirection;
|
||||||
|
|
||||||
|
float mCloudsMaximumPercent;
|
||||||
|
|
||||||
// Note: For Weather Blight, there is a "Disease Chance" (=0.1) setting. But according to MWSFD this feature
|
// 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.
|
// is broken in the vanilla game and was disabled.
|
||||||
|
|
||||||
|
@ -203,7 +205,6 @@ namespace MWWorld
|
||||||
|
|
||||||
private:
|
private:
|
||||||
float mTransitionDelta;
|
float mTransitionDelta;
|
||||||
float mCloudsMaximumPercent;
|
|
||||||
|
|
||||||
// Note: In MW, only thunderstorms support these attributes, but in the interest of making weather more
|
// 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
|
// 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;
|
bool useTorches(float hour) const;
|
||||||
|
|
||||||
|
float getSunPercentage(float hour) const;
|
||||||
|
|
||||||
|
float getSunVisibility() const;
|
||||||
|
|
||||||
void write(ESM::ESMWriter& writer, Loading::Listener& progress);
|
void write(ESM::ESMWriter& writer, Loading::Listener& progress);
|
||||||
|
|
||||||
bool readRecord(ESM::ESMReader& reader, uint32_t type);
|
bool readRecord(ESM::ESMReader& reader, uint32_t type);
|
||||||
|
@ -379,7 +384,7 @@ namespace MWWorld
|
||||||
void updateWeatherTransitions(const float elapsedRealSeconds);
|
void updateWeatherTransitions(const float elapsedRealSeconds);
|
||||||
void forceWeather(const int weatherID);
|
void forceWeather(const int weatherID);
|
||||||
|
|
||||||
bool inTransition();
|
bool inTransition() const;
|
||||||
void addWeatherTransition(const int weatherID);
|
void addWeatherTransition(const int weatherID);
|
||||||
|
|
||||||
void calculateWeatherResult(const float gameHour, const float elapsedSeconds, const bool isPaused);
|
void calculateWeatherResult(const float gameHour, const float elapsedSeconds, const bool isPaused);
|
||||||
|
|
|
@ -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)
|
bool World::findInteriorPositionInWorldSpace(const MWWorld::CellStore* cell, osg::Vec3f& result)
|
||||||
{
|
{
|
||||||
if (cell->isExterior())
|
if (cell->isExterior())
|
||||||
|
|
|
@ -668,6 +668,9 @@ namespace MWWorld
|
||||||
// Allow NPCs to use torches?
|
// Allow NPCs to use torches?
|
||||||
bool useTorches() const override;
|
bool useTorches() const override;
|
||||||
|
|
||||||
|
float getSunVisibility() const override;
|
||||||
|
float getSunPercentage() const override;
|
||||||
|
|
||||||
bool findInteriorPositionInWorldSpace(const MWWorld::CellStore* cell, osg::Vec3f& result) 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)
|
/// Teleports \a ptr to the closest reference of \a id (e.g. DivineMarker, PrisonMarker, TempleMarker)
|
||||||
|
|
Loading…
Reference in a new issue