Merge branch 'chancywind' into 'master'

Roll for each region sound

Closes #7872

See merge request OpenMW/openmw!3935
fix-osga-rotate-wildly
Alexei Kotov 10 months ago
commit 86a47acc39

@ -157,6 +157,7 @@
Bug #7840: First run of the launcher doesn't save viewing distance as the default value
Bug #7841: Editor: "Dirty" water heights are saved in modified CELLs
Bug #7859: AutoCalc flag is not used to calculate potion value
Bug #7872: Region sounds use wrong odds
Feature #2566: Handle NAM9 records for manual cell references
Feature #3537: Shader-based water ripples
Feature #5173: Support for NiFogProperty

@ -235,6 +235,7 @@ namespace CSMWorld
{ ColumnId_RegionSounds, "Sounds" },
{ ColumnId_SoundName, "Sound Name" },
{ ColumnId_SoundChance, "Chance" },
{ ColumnId_SoundProbability, "Probability" },
{ ColumnId_FactionReactions, "Reactions" },
{ ColumnId_FactionRanks, "Ranks" },

@ -349,6 +349,8 @@ namespace CSMWorld
ColumnId_SelectionGroupObjects = 316,
ColumnId_SoundProbability = 317,
// Allocated to a separate value range, so we don't get a collision should we ever need
// to extend the number of use values.
ColumnId_UseValue1 = 0x10000,

@ -301,8 +301,8 @@ CSMWorld::Data::Data(ToUTF8::FromType encoding, const Files::PathContainer& data
mRegions.addColumn(new NestedParentColumn<ESM::Region>(Columns::ColumnId_RegionWeather));
index = mRegions.getColumns() - 1;
mRegions.addAdapter(std::make_pair(&mRegions.getColumn(index), new RegionWeatherAdapter()));
mRegions.getNestableColumn(index)->addColumn(
new NestedChildColumn(Columns::ColumnId_WeatherName, ColumnBase::Display_String, false));
mRegions.getNestableColumn(index)->addColumn(new NestedChildColumn(
Columns::ColumnId_WeatherName, ColumnBase::Display_String, ColumnBase::Flag_Dialogue, false));
mRegions.getNestableColumn(index)->addColumn(
new NestedChildColumn(Columns::ColumnId_WeatherChance, ColumnBase::Display_UnsignedInteger8));
// Region Sounds
@ -313,6 +313,8 @@ CSMWorld::Data::Data(ToUTF8::FromType encoding, const Files::PathContainer& data
new NestedChildColumn(Columns::ColumnId_SoundName, ColumnBase::Display_Sound));
mRegions.getNestableColumn(index)->addColumn(
new NestedChildColumn(Columns::ColumnId_SoundChance, ColumnBase::Display_UnsignedInteger8));
mRegions.getNestableColumn(index)->addColumn(new NestedChildColumn(
Columns::ColumnId_SoundProbability, ColumnBase::Display_String, ColumnBase::Flag_Dialogue, false));
mBirthsigns.addColumn(new StringIdColumn<ESM::BirthSign>);
mBirthsigns.addColumn(new RecordStateColumn<ESM::BirthSign>);

@ -414,20 +414,32 @@ namespace CSMWorld
QVariant RegionSoundListAdapter::getData(const Record<ESM::Region>& record, int subRowIndex, int subColIndex) const
{
ESM::Region region = record.get();
const ESM::Region& region = record.get();
std::vector<ESM::Region::SoundRef>& soundList = region.mSoundList;
const std::vector<ESM::Region::SoundRef>& soundList = region.mSoundList;
if (subRowIndex < 0 || subRowIndex >= static_cast<int>(soundList.size()))
const size_t index = static_cast<size_t>(subRowIndex);
if (subRowIndex < 0 || index >= soundList.size())
throw std::runtime_error("index out of range");
ESM::Region::SoundRef soundRef = soundList[subRowIndex];
const ESM::Region::SoundRef& soundRef = soundList[subRowIndex];
switch (subColIndex)
{
case 0:
return QString(soundRef.mSound.getRefIdString().c_str());
case 1:
return soundRef.mChance;
case 2:
{
float probability = 1.f;
for (size_t i = 0; i < index; ++i)
{
const float p = std::min(soundList[i].mChance / 100.f, 1.f);
probability *= 1.f - p;
}
probability *= std::min(soundRef.mChance / 100.f, 1.f) * 100.f;
return QString("%1%").arg(probability, 0, 'f', 2);
}
default:
throw std::runtime_error("Region sounds subcolumn index out of range");
}
@ -463,7 +475,7 @@ namespace CSMWorld
int RegionSoundListAdapter::getColumnsCount(const Record<ESM::Region>& record) const
{
return 2;
return 3;
}
int RegionSoundListAdapter::getRowsCount(const Record<ESM::Region>& record) const

@ -4,29 +4,18 @@
#include <components/fallback/fallback.hpp>
#include <components/misc/rng.hpp>
#include <algorithm>
#include <numeric>
#include "../mwbase/environment.hpp"
#include "../mwworld/esmstore.hpp"
namespace MWSound
{
namespace
{
int addChance(int result, const ESM::Region::SoundRef& v)
{
return result + v.mChance;
}
}
RegionSoundSelector::RegionSoundSelector()
: mMinTimeBetweenSounds(Fallback::Map::getFloat("Weather_Minimum_Time_Between_Environmental_Sounds"))
, mMaxTimeBetweenSounds(Fallback::Map::getFloat("Weather_Maximum_Time_Between_Environmental_Sounds"))
{
}
std::optional<ESM::RefId> RegionSoundSelector::getNextRandom(float duration, const ESM::RefId& regionName)
ESM::RefId RegionSoundSelector::getNextRandom(float duration, const ESM::RefId& regionName)
{
mTimePassed += duration;
@ -37,40 +26,17 @@ namespace MWSound
mTimeToNextEnvSound = mMinTimeBetweenSounds + (mMaxTimeBetweenSounds - mMinTimeBetweenSounds) * a;
mTimePassed = 0;
if (mLastRegionName != regionName)
{
mLastRegionName = regionName;
mSumChance = 0;
}
const ESM::Region* const region
= MWBase::Environment::get().getESMStore()->get<ESM::Region>().search(mLastRegionName);
= MWBase::Environment::get().getESMStore()->get<ESM::Region>().search(regionName);
if (region == nullptr)
return {};
if (mSumChance == 0)
for (const ESM::Region::SoundRef& sound : region->mSoundList)
{
mSumChance = std::accumulate(region->mSoundList.begin(), region->mSoundList.end(), 0, addChance);
if (mSumChance == 0)
return {};
if (Misc::Rng::roll0to99() < sound.mChance)
return sound.mSound;
}
const int r = Misc::Rng::rollDice(std::max(mSumChance, 100));
int pos = 0;
const auto isSelected = [&](const ESM::Region::SoundRef& sound) {
if (r - pos < sound.mChance)
return true;
pos += sound.mChance;
return false;
};
const auto it = std::find_if(region->mSoundList.begin(), region->mSoundList.end(), isSelected);
if (it == region->mSoundList.end())
return {};
return it->mSound;
return {};
}
}

@ -2,27 +2,18 @@
#define GAME_SOUND_REGIONSOUNDSELECTOR_H
#include <components/esm/refid.hpp>
#include <optional>
#include <string>
namespace MWBase
{
class World;
}
namespace MWSound
{
class RegionSoundSelector
{
public:
std::optional<ESM::RefId> getNextRandom(float duration, const ESM::RefId& regionName);
ESM::RefId getNextRandom(float duration, const ESM::RefId& regionName);
RegionSoundSelector();
private:
float mTimeToNextEnvSound = 0.0f;
int mSumChance = 0;
ESM::RefId mLastRegionName;
float mTimePassed = 0.0;
float mMinTimeBetweenSounds;
float mMaxTimeBetweenSounds;

@ -900,8 +900,9 @@ namespace MWSound
if (mCurrentRegionSound && mOutput->isSoundPlaying(mCurrentRegionSound))
return;
if (const auto next = mRegionSoundSelector.getNextRandom(duration, cell->getRegion()))
mCurrentRegionSound = playSound(*next, 1.0f, 1.0f);
ESM::RefId next = mRegionSoundSelector.getNextRandom(duration, cell->getRegion());
if (!next.empty())
mCurrentRegionSound = playSound(next, 1.0f, 1.0f);
}
void SoundManager::updateWaterSound()

Loading…
Cancel
Save