From c94653dc49156421c0b1b63e7d3dd3d8f317b4c1 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sat, 27 Jul 2013 07:10:18 -0700 Subject: [PATCH] Implement the ModRegion script function --- apps/openmw/mwbase/world.hpp | 2 ++ apps/openmw/mwscript/docs/vmformat.txt | 3 +- apps/openmw/mwscript/skyextensions.cpp | 25 ++++++++++++++ apps/openmw/mwworld/weather.cpp | 48 ++++++++++++++++++-------- apps/openmw/mwworld/weather.hpp | 5 +++ apps/openmw/mwworld/worldimp.cpp | 5 +++ apps/openmw/mwworld/worldimp.hpp | 2 ++ 7 files changed, 74 insertions(+), 16 deletions(-) diff --git a/apps/openmw/mwbase/world.hpp b/apps/openmw/mwbase/world.hpp index dd069bfa93..480bcf9cf4 100644 --- a/apps/openmw/mwbase/world.hpp +++ b/apps/openmw/mwbase/world.hpp @@ -201,6 +201,8 @@ namespace MWBase virtual void setMoonColour (bool red) = 0; + virtual void modRegion(const std::string ®ionid, const std::vector &chances) = 0; + virtual float getTimeScaleFactor() const = 0; virtual void changeToInteriorCell (const std::string& cellName, diff --git a/apps/openmw/mwscript/docs/vmformat.txt b/apps/openmw/mwscript/docs/vmformat.txt index 772069d05e..59d988410b 100644 --- a/apps/openmw/mwscript/docs/vmformat.txt +++ b/apps/openmw/mwscript/docs/vmformat.txt @@ -51,7 +51,8 @@ op 0x20022: AiFollow op 0x20023: AiFollow, explicit reference op 0x20024: AiFollowCell op 0x20025: AiFollowCell, explicit reference -op s 0x20026-0x3ffff unused +op 0x20026: ModRegion +opcodes 0x20027-0x3ffff unused Segment 4: (not implemented yet) diff --git a/apps/openmw/mwscript/skyextensions.cpp b/apps/openmw/mwscript/skyextensions.cpp index e16c2ec233..393c9c55b8 100644 --- a/apps/openmw/mwscript/skyextensions.cpp +++ b/apps/openmw/mwscript/skyextensions.cpp @@ -96,6 +96,28 @@ namespace MWScript } }; + class OpModRegion : public Interpreter::Opcode1 + { + public: + + virtual void execute (Interpreter::Runtime& runtime, unsigned int arg0) + { + std::string region = runtime.getStringLiteral (runtime[0].mInteger); + runtime.pop(); + + std::vector chances; + chances.reserve(10); + while(arg0 > 0) + { + chances.push_back(std::max(0, std::min(127, runtime[0].mInteger))); + runtime.pop(); + arg0--; + } + + MWBase::Environment::get().getWorld()->modRegion(region, chances); + } + }; + const int opcodeToggleSky = 0x2000021; const int opcodeTurnMoonWhite = 0x2000022; const int opcodeTurnMoonRed = 0x2000023; @@ -103,6 +125,7 @@ namespace MWScript const int opcodeGetSecundaPhase = 0x2000025; const int opcodeGetCurrentWeather = 0x200013f; const int opcodeChangeWeather = 0x2000140; + const int opcodeModRegion = 0x20026; void registerExtensions (Compiler::Extensions& extensions) { @@ -114,6 +137,7 @@ namespace MWScript extensions.registerFunction ("getmasserphase", 'l', "", opcodeGetMasserPhase); extensions.registerFunction ("getsecundaphase", 'l', "", opcodeGetSecundaPhase); extensions.registerFunction ("getcurrentweather", 'l', "", opcodeGetCurrentWeather); + extensions.registerInstruction ("modregion", "S/llllllllll", opcodeModRegion); } void installOpcodes (Interpreter::Interpreter& interpreter) @@ -125,6 +149,7 @@ namespace MWScript interpreter.installSegment5 (opcodeGetSecundaPhase, new OpGetSecundaPhase); interpreter.installSegment5 (opcodeGetCurrentWeather, new OpGetCurrentWeather); interpreter.installSegment5 (opcodeChangeWeather, new OpChangeWeather); + interpreter.installSegment3 (opcodeModRegion, new OpModRegion); } } } diff --git a/apps/openmw/mwworld/weather.cpp b/apps/openmw/mwworld/weather.cpp index 6cdb131471..c8283fe0db 100644 --- a/apps/openmw/mwworld/weather.cpp +++ b/apps/openmw/mwworld/weather.cpp @@ -537,8 +537,8 @@ void WeatherManager::stopSounds(bool stopAll) std::vector::iterator it = mSoundsPlaying.begin(); while (it!=mSoundsPlaying.end()) { - if (stopAll || \ - !((*it == mWeatherSettings[mCurrentWeather].mAmbientLoopSoundID) || \ + if (stopAll || + !((*it == mWeatherSettings[mCurrentWeather].mAmbientLoopSoundID) || (*it == mWeatherSettings[mCurrentWeather].mRainLoopSoundID))) { MWBase::Environment::get().getSoundManager()->stopSound(*it); @@ -551,29 +551,38 @@ void WeatherManager::stopSounds(bool stopAll) Ogre::String WeatherManager::nextWeather(const ESM::Region* region) const { + const MWBase::World *world = MWBase::Environment::get().getWorld(); + std::vector 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). */ - const int probability[] = { - region->mData.mClear, - region->mData.mCloudy, - region->mData.mFoggy, - region->mData.mOvercast, - region->mData.mRain, - region->mData.mThunder, - region->mData.mAsh, - region->mData.mBlight, - region->mData.mA, - region->mData.mB - }; // 10 elements int chance = (rand() % 100) + 1; // 1..100 int sum = 0; int i = 0; - for (; i < 10; ++i) + for (; i < probability.size(); ++i) { sum += probability[i]; if (chance < sum) @@ -681,6 +690,15 @@ void WeatherManager::changeWeather(const std::string& region, const unsigned int setWeather(weather); } +void WeatherManager::modRegion(const std::string ®ionid, const std::vector &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; diff --git a/apps/openmw/mwworld/weather.hpp b/apps/openmw/mwworld/weather.hpp index 1a787aae8f..a2a07cec79 100644 --- a/apps/openmw/mwworld/weather.hpp +++ b/apps/openmw/mwworld/weather.hpp @@ -149,6 +149,8 @@ namespace MWWorld unsigned int getWeatherID() const; + void modRegion(const std::string ®ionid, const std::vector &chances); + private: float mHour; int mDay, mMonth; @@ -188,6 +190,9 @@ namespace MWWorld Ogre::String nextWeather(const ESM::Region* region) const; WeatherResult mResult; + typedef std::map > RegionModMap; + RegionModMap mRegionMods; + float mSunriseTime; float mSunsetTime; float mSunriseDuration; diff --git a/apps/openmw/mwworld/worldimp.cpp b/apps/openmw/mwworld/worldimp.cpp index 70eda24290..33d4719c09 100644 --- a/apps/openmw/mwworld/worldimp.cpp +++ b/apps/openmw/mwworld/worldimp.cpp @@ -1374,6 +1374,11 @@ namespace MWWorld mWeatherManager->changeWeather(region, id); } + void World::modRegion(const std::string ®ionid, const std::vector &chances) + { + mWeatherManager->modRegion(regionid, chances); + } + OEngine::Render::Fader* World::getFader() { return mRendering->getFader(); diff --git a/apps/openmw/mwworld/worldimp.hpp b/apps/openmw/mwworld/worldimp.hpp index 8a30e970d7..252248e406 100644 --- a/apps/openmw/mwworld/worldimp.hpp +++ b/apps/openmw/mwworld/worldimp.hpp @@ -237,6 +237,8 @@ namespace MWWorld virtual void setMoonColour (bool red); + virtual void modRegion(const std::string ®ionid, const std::vector &chances); + virtual float getTimeScaleFactor() const; virtual void changeToInteriorCell (const std::string& cellName,