Merge pull request #395 from OpenMW/master while resolving conflicts

# Conflicts:
#	apps/openmw/mwmechanics/actors.cpp
sol2-server-rewrite
David Cernat 7 years ago
commit ac82124a5d

@ -106,7 +106,7 @@ CSVDoc::StartupDialogue::StartupDialogue() : mWidth (0), mColumn (2)
/// \todo remove this label once we are feature complete and convinced that this thing is /// \todo remove this label once we are feature complete and convinced that this thing is
/// working properly. /// working properly.
QLabel *warning = new QLabel ("<font color=Red>WARNING: OpenMW-CS is in alpha stage.<p>The editor is not feature complete and not sufficiently tested.<br>In theory your data should be safe. But we strongly advice to make backups regularly if you are working with live data.</font color>"); QLabel *warning = new QLabel ("<font color=Red>WARNING: OpenMW-CS is in alpha stage.<p>The editor is not feature complete and not sufficiently tested.<br>In theory your data should be safe. But we strongly advise to make backups regularly if you are working with live data.</font color>");
QFont font; QFont font;
font.setPointSize (12); font.setPointSize (12);

@ -422,7 +422,7 @@ namespace MWBase
/// Cycle to next or previous weapon /// Cycle to next or previous weapon
virtual void cycleWeapon(bool next) = 0; virtual void cycleWeapon(bool next) = 0;
virtual void playSound(const std::string& soundId, float volume = 1.f, float pitch = 1.f) = 0; virtual void playSound(const std::string& soundId, bool preventOverlapping = false, float volume = 1.f, float pitch = 1.f) = 0;
// In WindowManager for now since there isn't a VFS singleton // In WindowManager for now since there isn't a VFS singleton
virtual std::string correctIconPath(const std::string& path) = 0; virtual std::string correctIconPath(const std::string& path) = 0;

@ -547,12 +547,14 @@ namespace MWBase
virtual void launchProjectile (MWWorld::Ptr actor, MWWorld::ConstPtr projectile, virtual void launchProjectile (MWWorld::Ptr actor, MWWorld::ConstPtr projectile,
const osg::Vec3f& worldPos, const osg::Quat& orient, MWWorld::Ptr bow, float speed, float attackStrength) = 0; const osg::Vec3f& worldPos, const osg::Quat& orient, MWWorld::Ptr bow, float speed, float attackStrength) = 0;
virtual void applyLoopingParticles(const MWWorld::Ptr& ptr) = 0;
virtual const std::vector<std::string>& getContentFiles() const = 0; virtual const std::vector<std::string>& getContentFiles() const = 0;
virtual void breakInvisibility (const MWWorld::Ptr& actor) = 0; virtual void breakInvisibility (const MWWorld::Ptr& actor) = 0;
// Are we in an exterior or pseudo-exterior cell and it's night? // Allow NPCs to use torches?
virtual bool isDark() const = 0; virtual bool useTorches() const = 0;
virtual bool findInteriorPositionInWorldSpace(const MWWorld::CellStore* cell, osg::Vec3f& result) = 0; virtual bool findInteriorPositionInWorldSpace(const MWWorld::CellStore* cell, osg::Vec3f& result) = 0;

@ -233,24 +233,6 @@ namespace MWClass
if (!(ref->mBase->mData.mFlags & ESM::Light::Carry)) if (!(ref->mBase->mData.mFlags & ESM::Light::Carry))
return std::make_pair(0,""); return std::make_pair(0,"");
const MWWorld::InventoryStore& invStore = npc.getClass().getInventoryStore(npc);
MWWorld::ConstContainerStoreIterator weapon = invStore.getSlot(MWWorld::InventoryStore::Slot_CarriedRight);
if(weapon == invStore.end())
return std::make_pair(1,"");
/// \todo the 2h check is repeated many times; put it in a function
if(weapon->getTypeName() == typeid(ESM::Weapon).name() &&
(weapon->get<ESM::Weapon>()->mBase->mData.mType == ESM::Weapon::LongBladeTwoHand ||
weapon->get<ESM::Weapon>()->mBase->mData.mType == ESM::Weapon::BluntTwoClose ||
weapon->get<ESM::Weapon>()->mBase->mData.mType == ESM::Weapon::BluntTwoWide ||
weapon->get<ESM::Weapon>()->mBase->mData.mType == ESM::Weapon::SpearTwoWide ||
weapon->get<ESM::Weapon>()->mBase->mData.mType == ESM::Weapon::AxeTwoHand ||
weapon->get<ESM::Weapon>()->mBase->mData.mType == ESM::Weapon::MarksmanBow ||
weapon->get<ESM::Weapon>()->mBase->mData.mType == ESM::Weapon::MarksmanCrossbow))
{
return std::make_pair(3,"");
}
return std::make_pair(1,""); return std::make_pair(1,"");
} }

@ -892,7 +892,7 @@ protected:
public: public:
typedef TypesetBookImpl::StyleImpl Style; typedef TypesetBookImpl::StyleImpl Style;
typedef std::map <TextFormat::Id, TextFormat*> ActiveTextFormats; typedef std::map <TextFormat::Id, std::unique_ptr<TextFormat>> ActiveTextFormats;
int mViewTop; int mViewTop;
int mViewBottom; int mViewBottom;
@ -1048,7 +1048,7 @@ public:
{ {
if (mNode != NULL) if (mNode != NULL)
i->second->destroyDrawItem (mNode); i->second->destroyDrawItem (mNode);
delete i->second; i->second.reset();
} }
mActiveTextFormats.clear (); mActiveTextFormats.clear ();
@ -1115,11 +1115,11 @@ public:
if (j == this_->mActiveTextFormats.end ()) if (j == this_->mActiveTextFormats.end ())
{ {
TextFormat * textFormat = new TextFormat (Font, this_); std::unique_ptr<TextFormat> textFormat(new TextFormat (Font, this_));
textFormat->mTexture = Font->getTextureFont (); textFormat->mTexture = Font->getTextureFont ();
j = this_->mActiveTextFormats.insert (std::make_pair (Font, textFormat)).first; j = this_->mActiveTextFormats.insert (std::make_pair (Font, std::move(textFormat))).first;
} }
j->second->mCountVertex += run.mPrintableChars * 6; j->second->mCountVertex += run.mPrintableChars * 6;

@ -200,7 +200,7 @@ namespace MWGui
{ {
if ((mCurrentPage+1)*2 < mPages.size()) if ((mCurrentPage+1)*2 < mPages.size())
{ {
MWBase::Environment::get().getWindowManager()->playSound("book page2"); MWBase::Environment::get().getWindowManager()->playSound("book page2", true);
++mCurrentPage; ++mCurrentPage;
@ -211,7 +211,7 @@ namespace MWGui
{ {
if (mCurrentPage > 0) if (mCurrentPage > 0)
{ {
MWBase::Environment::get().getWindowManager()->playSound("book page"); MWBase::Environment::get().getWindowManager()->playSound("book page", true);
--mCurrentPage; --mCurrentPage;

@ -616,7 +616,7 @@ namespace
if (page+2 < book->pageCount()) if (page+2 < book->pageCount())
{ {
MWBase::Environment::get().getWindowManager()->playSound("book page"); MWBase::Environment::get().getWindowManager()->playSound("book page", true);
page += 2; page += 2;
updateShowingPages (); updateShowingPages ();
@ -634,7 +634,7 @@ namespace
if(page >= 2) if(page >= 2)
{ {
MWBase::Environment::get().getWindowManager()->playSound("book page"); MWBase::Environment::get().getWindowManager()->playSound("book page", true);
page -= 2; page -= 2;
updateShowingPages (); updateShowingPages ();

@ -2042,11 +2042,16 @@ namespace MWGui
mInventoryWindow->cycle(next); mInventoryWindow->cycle(next);
} }
void WindowManager::playSound(const std::string& soundId, float volume, float pitch) void WindowManager::playSound(const std::string& soundId, bool preventOverlapping, float volume, float pitch)
{ {
if (soundId.empty()) if (soundId.empty())
return; return;
MWBase::Environment::get().getSoundManager()->playSound(soundId, volume, pitch, MWSound::Type::Sfx, MWSound::PlayMode::NoEnv);
MWBase::SoundManager *sndmgr = MWBase::Environment::get().getSoundManager();
if (preventOverlapping && sndmgr->getSoundPlaying(MWWorld::Ptr(), soundId))
return;
sndmgr->playSound(soundId, volume, pitch, MWSound::Type::Sfx, MWSound::PlayMode::NoEnv);
} }
void WindowManager::updateSpellWindow() void WindowManager::updateSpellWindow()

@ -451,7 +451,7 @@ namespace MWGui
/// Cycle to next or previous weapon /// Cycle to next or previous weapon
virtual void cycleWeapon(bool next); virtual void cycleWeapon(bool next);
virtual void playSound(const std::string& soundId, float volume = 1.f, float pitch = 1.f); virtual void playSound(const std::string& soundId, bool preventOverlapping = false, float volume = 1.f, float pitch = 1.f);
// In WindowManager for now since there isn't a VFS singleton // In WindowManager for now since there isn't a VFS singleton
virtual std::string correctIconPath(const std::string& path); virtual std::string correctIconPath(const std::string& path);

@ -949,7 +949,7 @@ namespace MWMechanics
stats.setTimeToStartDrowning(fHoldBreathTime); stats.setTimeToStartDrowning(fHoldBreathTime);
} }
void Actors::updateEquippedLight (const MWWorld::Ptr& ptr, float duration) void Actors::updateEquippedLight (const MWWorld::Ptr& ptr, float duration, bool mayEquip)
{ {
bool isPlayer = (ptr == getPlayer()); bool isPlayer = (ptr == getPlayer());
@ -982,7 +982,7 @@ namespace MWMechanics
} }
} }
if (MWBase::Environment::get().getWorld()->isDark()) if (mayEquip)
{ {
if (torch != inventoryStore.end()) if (torch != inventoryStore.end())
{ {
@ -991,16 +991,11 @@ namespace MWMechanics
// For non-hostile NPCs, unequip whatever is in the left slot in favor of a light. // For non-hostile NPCs, unequip whatever is in the left slot in favor of a light.
if (heldIter != inventoryStore.end() && heldIter->getTypeName() != typeid(ESM::Light).name()) if (heldIter != inventoryStore.end() && heldIter->getTypeName() != typeid(ESM::Light).name())
inventoryStore.unequipItem(*heldIter, ptr); inventoryStore.unequipItem(*heldIter, ptr);
// Also unequip twohanded weapons which conflict with anything in CarriedLeft
if (torch->getClass().canBeEquipped(*torch, ptr).first == 3)
inventoryStore.unequipSlot(MWWorld::InventoryStore::Slot_CarriedRight, ptr);
} }
heldIter = inventoryStore.getSlot(MWWorld::InventoryStore::Slot_CarriedLeft); heldIter = inventoryStore.getSlot(MWWorld::InventoryStore::Slot_CarriedLeft);
// If we have a torch and can equip it (left slot free, no // If we have a torch and can equip it, then equip it now.
// twohanded weapon in right slot), then equip it now.
if (heldIter == inventoryStore.end() if (heldIter == inventoryStore.end()
&& torch->getClass().canBeEquipped(*torch, ptr).first == 1) && torch->getClass().canBeEquipped(*torch, ptr).first == 1)
{ {
@ -1057,7 +1052,7 @@ namespace MWMechanics
} }
} }
void Actors::updateCrimePersuit(const MWWorld::Ptr& ptr, float duration) void Actors::updateCrimePursuit(const MWWorld::Ptr& ptr, float duration)
{ {
MWWorld::Ptr player = getPlayer(); MWWorld::Ptr player = getPlayer();
if (ptr != player && ptr.getClass().isNpc()) if (ptr != player && ptr.getClass().isNpc())
@ -1293,6 +1288,9 @@ namespace MWMechanics
if (mTimerDisposeSummonsCorpses >= 0.2f) mTimerDisposeSummonsCorpses = 0; if (mTimerDisposeSummonsCorpses >= 0.2f) mTimerDisposeSummonsCorpses = 0;
if (timerUpdateEquippedLight >= updateEquippedLightInterval) timerUpdateEquippedLight = 0; if (timerUpdateEquippedLight >= updateEquippedLightInterval) timerUpdateEquippedLight = 0;
// show torches only when there are darkness and no precipitations
bool showTorches = MWBase::Environment::get().getWorld()->useTorches();
MWWorld::Ptr player = getPlayer(); MWWorld::Ptr player = getPlayer();
/// \todo move update logic to Actor class where appropriate /// \todo move update logic to Actor class where appropriate
@ -1438,7 +1436,7 @@ namespace MWMechanics
} }
if (iter->first.getClass().isNpc() && iter->first != player && (isLocalActor || isAIActive)) if (iter->first.getClass().isNpc() && iter->first != player && (isLocalActor || isAIActive))
updateCrimePersuit(iter->first, duration); updateCrimePursuit(iter->first, duration);
if (iter->first != player && (isLocalActor || isAIActive)) if (iter->first != player && (isLocalActor || isAIActive))
{ {
@ -1456,7 +1454,7 @@ namespace MWMechanics
updateNpc(iter->first, duration); updateNpc(iter->first, duration);
if (timerUpdateEquippedLight == 0) if (timerUpdateEquippedLight == 0)
updateEquippedLight(iter->first, updateEquippedLightInterval); updateEquippedLight(iter->first, updateEquippedLightInterval, showTorches);
} }
} }
} }

@ -39,9 +39,9 @@ namespace MWMechanics
void updateDrowning (const MWWorld::Ptr& ptr, float duration); void updateDrowning (const MWWorld::Ptr& ptr, float duration);
void updateEquippedLight (const MWWorld::Ptr& ptr, float duration); void updateEquippedLight (const MWWorld::Ptr& ptr, float duration, bool mayEquip);
void updateCrimePersuit (const MWWorld::Ptr& ptr, float duration); void updateCrimePursuit (const MWWorld::Ptr& ptr, float duration);
void killDeadActors (); void killDeadActors ();

@ -189,7 +189,7 @@ void MWMechanics::AiPackage::evadeObstacles(const MWWorld::Ptr& actor, float dur
static float distance = MWBase::Environment::get().getWorld()->getMaxActivationDistance(); static float distance = MWBase::Environment::get().getWorld()->getMaxActivationDistance();
MWWorld::Ptr door = getNearbyDoor(actor, distance); MWWorld::Ptr door = getNearbyDoor(actor, distance);
if (door != MWWorld::Ptr()) if (door != MWWorld::Ptr() && actor.getClass().isBipedal(actor))
{ {
// note: AiWander currently does not open doors // note: AiWander currently does not open doors
if (getTypeId() != TypeIdWander && !door.getCellRef().getTeleport() && door.getClass().getDoorState(door) == 0) if (getTypeId() != TypeIdWander && !door.getCellRef().getTeleport() && door.getClass().getDoorState(door) == 0)
@ -224,7 +224,7 @@ void MWMechanics::AiPackage::evadeObstacles(const MWWorld::Ptr& actor, float dur
MWBase::Environment::get().getWorld()->activate(door, actor); MWBase::Environment::get().getWorld()->activate(door, actor);
} }
} }
else // any other obstacle (NPC, crate, etc.) else
{ {
mObstacleCheck.takeEvasiveAction(movement); mObstacleCheck.takeEvasiveAction(movement);
} }

@ -40,7 +40,6 @@
#include "../mwrender/animation.hpp" #include "../mwrender/animation.hpp"
#include "magiceffects.hpp"
#include "npcstats.hpp" #include "npcstats.hpp"
#include "actorutil.hpp" #include "actorutil.hpp"
#include "aifollow.hpp" #include "aifollow.hpp"
@ -625,7 +624,6 @@ namespace MWMechanics
std::string texture = magicEffect->mParticle; std::string texture = magicEffect->mParticle;
// TODO: VFX are no longer active after saving/reloading the game
bool loop = (magicEffect->mData.mFlags & ESM::MagicEffect::ContinuousVfx) != 0; bool loop = (magicEffect->mData.mFlags & ESM::MagicEffect::ContinuousVfx) != 0;
// Note: in case of non actor, a free effect should be fine as well // Note: in case of non actor, a free effect should be fine as well
MWRender::Animation* anim = MWBase::Environment::get().getWorld()->getAnimation(target); MWRender::Animation* anim = MWBase::Environment::get().getWorld()->getAnimation(target);
@ -1383,4 +1381,24 @@ namespace MWMechanics
return MWBase::Environment::get().getWorld()->getStore().get<ESM::GameSetting>().find(it->second)->getString(); return MWBase::Environment::get().getWorld()->getStore().get<ESM::GameSetting>().find(it->second)->getString();
} }
void ApplyLoopingParticlesVisitor::visit (MWMechanics::EffectKey key,
const std::string& /*sourceName*/, const std::string& /*sourceId*/, int /*casterActorId*/,
float /*magnitude*/, float /*remainingTime*/, float /*totalTime*/)
{
const ESM::MagicEffect *magicEffect =
MWBase::Environment::get().getWorld()->getStore().get<ESM::MagicEffect>().find(key.mId);
const ESM::Static* castStatic;
if (!magicEffect->mHit.empty())
castStatic = MWBase::Environment::get().getWorld()->getStore().get<ESM::Static>().find (magicEffect->mHit);
else
castStatic = MWBase::Environment::get().getWorld()->getStore().get<ESM::Static>().find ("VFX_DefaultHit");
std::string texture = magicEffect->mParticle;
bool loop = (magicEffect->mData.mFlags & ESM::MagicEffect::ContinuousVfx) != 0;
MWRender::Animation* anim = MWBase::Environment::get().getWorld()->getAnimation(mActor);
if (anim && loop)
anim->addEffect("meshes\\" + castStatic->mModel, magicEffect->mIndex, loop, "", texture);
}
} }

@ -6,6 +6,8 @@
#include "../mwworld/ptr.hpp" #include "../mwworld/ptr.hpp"
#include "magiceffects.hpp"
namespace ESM namespace ESM
{ {
struct Spell; struct Spell;
@ -119,6 +121,21 @@ namespace MWMechanics
bool applyInstantEffect (const MWWorld::Ptr& target, const MWWorld::Ptr& caster, const MWMechanics::EffectKey& effect, float magnitude); bool applyInstantEffect (const MWWorld::Ptr& target, const MWWorld::Ptr& caster, const MWMechanics::EffectKey& effect, float magnitude);
}; };
class ApplyLoopingParticlesVisitor : public EffectSourceVisitor
{
private:
MWWorld::Ptr mActor;
public:
ApplyLoopingParticlesVisitor(const MWWorld::Ptr& actor)
: mActor(actor)
{
}
virtual void visit (MWMechanics::EffectKey key,
const std::string& /*sourceName*/, const std::string& /*sourceId*/, int /*casterActorId*/,
float /*magnitude*/, float /*remainingTime*/ = -1, float /*totalTime*/ = -1);
};
} }
#endif #endif

@ -13,7 +13,6 @@
#include <BulletCollision/CollisionDispatch/btCollisionObject.h> #include <BulletCollision/CollisionDispatch/btCollisionObject.h>
#include <BulletCollision/CollisionDispatch/btCollisionWorld.h> #include <BulletCollision/CollisionDispatch/btCollisionWorld.h>
#include <BulletCollision/CollisionDispatch/btDefaultCollisionConfiguration.h> #include <BulletCollision/CollisionDispatch/btDefaultCollisionConfiguration.h>
#include <BulletCollision/CollisionDispatch/btCollisionWorld.h>
#include <BulletCollision/BroadphaseCollision/btDbvtBroadphase.h> #include <BulletCollision/BroadphaseCollision/btDbvtBroadphase.h>
#include <LinearMath/btQuickprof.h> #include <LinearMath/btQuickprof.h>

@ -90,6 +90,9 @@ namespace
if (ptr.getClass().isActor()) if (ptr.getClass().isActor())
rendering.addWaterRippleEmitter(ptr); rendering.addWaterRippleEmitter(ptr);
// Restore effect particles
MWBase::Environment::get().getWorld()->applyLoopingParticles(ptr);
} }
void updateObjectRotation (const MWWorld::Ptr& ptr, MWPhysics::PhysicsSystem& physics, void updateObjectRotation (const MWWorld::Ptr& ptr, MWPhysics::PhysicsSystem& physics,

@ -9,7 +9,6 @@
#include <components/fallback/fallback.hpp> #include <components/fallback/fallback.hpp>
#include "../mwbase/environment.hpp" #include "../mwbase/environment.hpp"
#include "../mwbase/world.hpp"
#include "../mwbase/soundmanager.hpp" #include "../mwbase/soundmanager.hpp"
#include "../mwmechanics/actorutil.hpp" #include "../mwmechanics/actorutil.hpp"
@ -520,6 +519,7 @@ WeatherManager::WeatherManager(MWRender::RenderingManager& rendering, const Fall
, mSecunda("Secunda", fallback) , mSecunda("Secunda", fallback)
, mWindSpeed(0.f) , mWindSpeed(0.f)
, mIsStorm(false) , mIsStorm(false)
, mPrecipitation(false)
, mStormDirection(0,1,0) , mStormDirection(0,1,0)
, mCurrentRegion() , mCurrentRegion()
, mTimePassed(0) , mTimePassed(0)
@ -608,14 +608,11 @@ void WeatherManager::modRegion(const std::string& regionID, const std::vector<ch
} }
} }
void WeatherManager::playerTeleported() void WeatherManager::playerTeleported(const std::string& playerRegion, bool isExterior)
{ {
// If the player teleports to an outdoors cell in a new region (for instance, by travelling), the weather needs to // If the player teleports to an outdoors cell in a new region (for instance, by travelling), the weather needs to
// be changed immediately, and any transitions for the previous region discarded. // be changed immediately, and any transitions for the previous region discarded.
MWBase::World* world = MWBase::Environment::get().getWorld();
if(world->isCellExterior() || world->isCellQuasiExterior())
{ {
std::string playerRegion = Misc::StringUtils::lowerCase(world->getPlayerPtr().getCell()->getCell()->mRegion);
std::map<std::string, RegionWeather>::iterator it = mRegions.find(playerRegion); std::map<std::string, RegionWeather>::iterator it = mRegions.find(playerRegion);
if(it != mRegions.end() && playerRegion != mCurrentRegion) if(it != mRegions.end() && playerRegion != mCurrentRegion)
{ {
@ -625,11 +622,9 @@ void WeatherManager::playerTeleported()
} }
} }
void WeatherManager::update(float duration, bool paused) void WeatherManager::update(float duration, bool paused, const TimeStamp& time, bool isExterior)
{ {
MWWorld::ConstPtr player = MWMechanics::getPlayer(); MWWorld::ConstPtr player = MWMechanics::getPlayer();
MWBase::World& world = *MWBase::Environment::get().getWorld();
TimeStamp time = world.getTimeStamp();
if(!paused || mFastForward) if(!paused || mFastForward)
{ {
@ -647,8 +642,7 @@ void WeatherManager::update(float duration, bool paused)
updateWeatherTransitions(duration); updateWeatherTransitions(duration);
} }
const bool exterior = (world.isCellExterior() || world.isCellQuasiExterior()); if(!isExterior)
if(!exterior)
{ {
mRendering.setSkyEnabled(false); mRendering.setSkyEnabled(false);
stopSounds(); stopSounds();
@ -660,6 +654,10 @@ void WeatherManager::update(float duration, bool paused)
mWindSpeed = mResult.mWindSpeed; mWindSpeed = mResult.mWindSpeed;
mIsStorm = mResult.mIsStorm; mIsStorm = mResult.mIsStorm;
// For some reason Ash Storm is not considered as a precipitation weather in game
mPrecipitation = !(mResult.mParticleEffect.empty() && mResult.mRainEffect.empty())
&& mResult.mParticleEffect != "meshes\\ashcloud.nif";
if (mIsStorm) if (mIsStorm)
{ {
osg::Vec3f playerPos (player.getRefData().getPosition().asVec3()); osg::Vec3f playerPos (player.getRefData().getPosition().asVec3());
@ -777,12 +775,11 @@ unsigned int WeatherManager::getWeatherID() const
return mCurrentWeather; return mCurrentWeather;
} }
bool WeatherManager::isDark() const bool WeatherManager::useTorches(float hour) const
{ {
TimeStamp time = MWBase::Environment::get().getWorld()->getTimeStamp(); bool isDark = hour < mSunriseTime || hour > mTimeSettings.mNightStart - 1;
bool exterior = (MWBase::Environment::get().getWorld()->isCellExterior()
|| MWBase::Environment::get().getWorld()->isCellQuasiExterior()); return isDark && !mPrecipitation;
return exterior && (time.getHour() < mSunriseTime || time.getHour() > mTimeSettings.mNightStart - 1);
} }
void WeatherManager::write(ESM::ESMWriter& writer, Loading::Listener& progress) void WeatherManager::write(ESM::ESMWriter& writer, Loading::Listener& progress)

@ -218,14 +218,14 @@ namespace MWWorld
*/ */
void changeWeather(const std::string& regionID, const unsigned int weatherID); void changeWeather(const std::string& regionID, const unsigned int weatherID);
void modRegion(const std::string& regionID, const std::vector<char>& chances); void modRegion(const std::string& regionID, const std::vector<char>& chances);
void playerTeleported(); void playerTeleported(const std::string& playerRegion, bool isExterior);
/** /**
* Per-frame update * Per-frame update
* @param duration * @param duration
* @param paused * @param paused
*/ */
void update(float duration, bool paused = false); void update(float duration, bool paused, const TimeStamp& time, bool isExterior);
void stopSounds(); void stopSounds();
@ -240,8 +240,7 @@ namespace MWWorld
unsigned int getWeatherID() const; unsigned int getWeatherID() const;
/// @see World::isDark bool useTorches(float hour) const;
bool isDark() const;
void write(ESM::ESMWriter& writer, Loading::Listener& progress); void write(ESM::ESMWriter& writer, Loading::Listener& progress);
@ -275,6 +274,7 @@ namespace MWWorld
float mWindSpeed; float mWindSpeed;
bool mIsStorm; bool mIsStorm;
bool mPrecipitation;
osg::Vec3f mStormDirection; osg::Vec3f mStormDirection;
std::string mCurrentRegion; std::string mCurrentRegion;

@ -2357,6 +2357,8 @@ namespace MWWorld
model = Misc::ResourceHelpers::correctActorModelPath(model, mResourceSystem->getVFS()); model = Misc::ResourceHelpers::correctActorModelPath(model, mResourceSystem->getVFS());
mPhysics->remove(getPlayerPtr()); mPhysics->remove(getPlayerPtr());
mPhysics->addActor(getPlayerPtr(), model); mPhysics->addActor(getPlayerPtr(), model);
applyLoopingParticles(player);
} }
int World::canRest () int World::canRest ()
@ -3017,6 +3019,19 @@ namespace MWWorld
mProjectileManager->launchMagicBolt(spellId, caster, fallbackDirection); mProjectileManager->launchMagicBolt(spellId, caster, fallbackDirection);
} }
void World::applyLoopingParticles(const MWWorld::Ptr& ptr)
{
const MWWorld::Class &cls = ptr.getClass();
if (cls.isActor())
{
MWMechanics::ApplyLoopingParticlesVisitor visitor(ptr);
cls.getCreatureStats(ptr).getActiveSpells().visitEffectSources(visitor);
cls.getCreatureStats(ptr).getSpells().visitEffectSources(visitor);
if (cls.hasInventoryStore(ptr))
cls.getInventoryStore(ptr).visitEffectSources(visitor);
}
}
const std::vector<std::string>& World::getContentFiles() const const std::vector<std::string>& World::getContentFiles() const
{ {
return mContentFiles; return mContentFiles;
@ -3033,11 +3048,17 @@ namespace MWWorld
MWBase::Environment::get().getMechanicsManager()->updateMagicEffects(actor); MWBase::Environment::get().getMechanicsManager()->updateMagicEffects(actor);
} }
bool World::isDark() const bool World::useTorches() const
{ {
// If we are in exterior, check the weather manager.
// In interiors there are no precipitations and sun, so check the ambient
// Looks like pseudo-exteriors considered as interiors in this case
MWWorld::CellStore* cell = mPlayer->getPlayer().getCell(); MWWorld::CellStore* cell = mPlayer->getPlayer().getCell();
if (cell->isExterior()) if (cell->isExterior())
return mWeatherManager->isDark(); {
float hour = getTimeStamp().getHour();
return mWeatherManager->useTorches(hour);
}
else else
{ {
uint32_t ambient = cell->getCell()->mAmbi.mAmbient; uint32_t ambient = cell->getCell()->mAmbi.mAmbient;
@ -3198,13 +3219,17 @@ namespace MWWorld
void World::updateWeather(float duration, bool paused) void World::updateWeather(float duration, bool paused)
{ {
bool isExterior = isCellExterior() || isCellQuasiExterior();
if (mPlayer->wasTeleported()) if (mPlayer->wasTeleported())
{ {
mPlayer->setTeleported(false); mPlayer->setTeleported(false);
mWeatherManager->playerTeleported();
const std::string playerRegion = Misc::StringUtils::lowerCase(getPlayerPtr().getCell()->getCell()->mRegion);
mWeatherManager->playerTeleported(playerRegion, isExterior);
} }
mWeatherManager->update(duration, paused); const TimeStamp time = getTimeStamp();
mWeatherManager->update(duration, paused, time, isExterior);
} }
struct AddDetectedReferenceVisitor struct AddDetectedReferenceVisitor

@ -658,12 +658,13 @@ namespace MWWorld
void launchProjectile (MWWorld::Ptr actor, MWWorld::ConstPtr projectile, void launchProjectile (MWWorld::Ptr actor, MWWorld::ConstPtr projectile,
const osg::Vec3f& worldPos, const osg::Quat& orient, MWWorld::Ptr bow, float speed, float attackStrength) override; const osg::Vec3f& worldPos, const osg::Quat& orient, MWWorld::Ptr bow, float speed, float attackStrength) override;
void applyLoopingParticles(const MWWorld::Ptr& ptr);
const std::vector<std::string>& getContentFiles() const override; const std::vector<std::string>& getContentFiles() const override;
void breakInvisibility (const MWWorld::Ptr& actor) override; void breakInvisibility (const MWWorld::Ptr& actor) override;
// Are we in an exterior or pseudo-exterior cell and it's night?
bool isDark() const override; // Allow NPCs to use torches?
bool useTorches() const override;
bool findInteriorPositionInWorldSpace(const MWWorld::CellStore* cell, osg::Vec3f& result) override; bool findInteriorPositionInWorldSpace(const MWWorld::CellStore* cell, osg::Vec3f& result) override;

@ -1,7 +1,7 @@
find_package(GTest REQUIRED) find_package(GTest REQUIRED)
if (GTEST_FOUND) if (GTEST_FOUND)
include_directories(${GTEST_INCLUDE_DIRS}) include_directories(SYSTEM ${GTEST_INCLUDE_DIRS})
file(GLOB UNITTEST_SRC_FILES file(GLOB UNITTEST_SRC_FILES
../openmw/mwworld/store.cpp ../openmw/mwworld/store.cpp

@ -1,5 +1,7 @@
#include "fallback.hpp" #include "fallback.hpp"
#include <iostream>
#include <boost/lexical_cast.hpp> #include <boost/lexical_cast.hpp>
@ -17,6 +19,7 @@ namespace Fallback
std::map<std::string,std::string>::const_iterator it; std::map<std::string,std::string>::const_iterator it;
if((it = mFallbackMap.find(fall)) == mFallbackMap.end()) if((it = mFallbackMap.find(fall)) == mFallbackMap.end())
{ {
std::cerr << "Warning: fallback value " << fall << " not found." << std::endl;
return ""; return "";
} }
return it->second; return it->second;
@ -25,7 +28,7 @@ namespace Fallback
float Map::getFallbackFloat(const std::string& fall) const float Map::getFallbackFloat(const std::string& fall) const
{ {
std::string fallback=getFallbackString(fall); std::string fallback=getFallbackString(fall);
if(fallback.empty()) if (fallback.empty())
return 0; return 0;
else else
return boost::lexical_cast<float>(fallback); return boost::lexical_cast<float>(fallback);
@ -34,7 +37,7 @@ namespace Fallback
int Map::getFallbackInt(const std::string& fall) const int Map::getFallbackInt(const std::string& fall) const
{ {
std::string fallback=getFallbackString(fall); std::string fallback=getFallbackString(fall);
if(fallback.empty()) if (fallback.empty())
return 0; return 0;
else else
return std::stoi(fallback); return std::stoi(fallback);
@ -43,7 +46,7 @@ namespace Fallback
bool Map::getFallbackBool(const std::string& fall) const bool Map::getFallbackBool(const std::string& fall) const
{ {
std::string fallback=getFallbackString(fall); std::string fallback=getFallbackString(fall);
if(fallback.empty()) if (fallback.empty())
return false; return false;
else else
return stob(fallback); return stob(fallback);
@ -52,8 +55,8 @@ namespace Fallback
osg::Vec4f Map::getFallbackColour(const std::string& fall) const osg::Vec4f Map::getFallbackColour(const std::string& fall) const
{ {
std::string sum=getFallbackString(fall); std::string sum=getFallbackString(fall);
if(sum.empty()) if (sum.empty())
return osg::Vec4f(0.f,0.f,0.f,1.f); return osg::Vec4f(0.5f,0.5f,0.5f,1.f);
else else
{ {
std::string ret[3]; std::string ret[3];

Loading…
Cancel
Save