From c34d85ffc2caf2240afbcf7fe3a9ab58fa9514f7 Mon Sep 17 00:00:00 2001 From: MiroslavR Date: Sun, 27 Nov 2016 21:19:52 +0100 Subject: [PATCH 01/46] Implement water sounds (Closes #451) --- apps/openmw/engine.cpp | 2 +- apps/openmw/mwsound/soundmanagerimp.cpp | 102 +++++++++++++++++++++++- apps/openmw/mwsound/soundmanagerimp.hpp | 15 +++- 3 files changed, 116 insertions(+), 3 deletions(-) diff --git a/apps/openmw/engine.cpp b/apps/openmw/engine.cpp index 62457cae6..03ec412d1 100644 --- a/apps/openmw/engine.cpp +++ b/apps/openmw/engine.cpp @@ -493,7 +493,7 @@ void OMW::Engine::prepareEngine (Settings::Manager & settings) mEnvironment.setWindowManager (window); // Create sound system - mEnvironment.setSoundManager (new MWSound::SoundManager(mVFS.get(), mUseSound)); + mEnvironment.setSoundManager (new MWSound::SoundManager(mVFS.get(), mFallbackMap, mUseSound)); if (!mSkipMenu) { diff --git a/apps/openmw/mwsound/soundmanagerimp.cpp b/apps/openmw/mwsound/soundmanagerimp.cpp index 663f88852..9b5fb1b3d 100644 --- a/apps/openmw/mwsound/soundmanagerimp.cpp +++ b/apps/openmw/mwsound/soundmanagerimp.cpp @@ -34,8 +34,9 @@ namespace MWSound { - SoundManager::SoundManager(const VFS::Manager* vfs, bool useSound) + SoundManager::SoundManager(const VFS::Manager* vfs, const std::map& fallbackMap, bool useSound) : mVFS(vfs) + , mFallback(fallbackMap) , mOutput(new DEFAULT_OUTPUT(*this)) , mMasterVolume(1.0f) , mSFXVolume(1.0f) @@ -61,6 +62,13 @@ namespace MWSound mFootstepsVolume = Settings::Manager::getFloat("footsteps volume", "Sound"); mFootstepsVolume = std::min(std::max(mFootstepsVolume, 0.0f), 1.0f); + mNearWaterRadius = mFallback.getFallbackInt("Water_NearWaterRadius"); + mNearWaterPoints = mFallback.getFallbackInt("Water_NearWaterPoints"); + mNearWaterIndoorTolerance = mFallback.getFallbackFloat("Water_NearWaterIndoorTolerance"); + mNearWaterOutdoorTolerance = mFallback.getFallbackFloat("Water_NearWaterOutdoorTolerance"); + mNearWaterIndoorID = mFallback.getFallbackString("Water_NearWaterIndoorID"); + mNearWaterOutdoorID = mFallback.getFallbackString("Water_NearWaterOutdoorID"); + mBufferCacheMin = std::max(Settings::Manager::getInt("buffer cache min", "Sound"), 1); mBufferCacheMax = std::max(Settings::Manager::getInt("buffer cache max", "Sound"), 1); mBufferCacheMax *= 1024*1024; @@ -796,6 +804,96 @@ namespace MWSound } } + void SoundManager::updateWaterSound(float /*duration*/) + { + MWBase::World* world = MWBase::Environment::get().getWorld(); + const MWWorld::ConstPtr player = world->getPlayerPtr(); + osg::Vec3f pos = player.getRefData().getPosition().asVec3(); + + float volume = 0.0f; + const std::string& soundId = player.getCell()->isExterior() ? mNearWaterOutdoorID : mNearWaterIndoorID; + + if (!mListenerUnderwater) + { + if (player.getCell()->getCell()->hasWater()) + { + float dist = std::abs(player.getCell()->getWaterLevel() - pos.z()); + + if (player.getCell()->isExterior() && dist < mNearWaterOutdoorTolerance) + { + volume = (mNearWaterOutdoorTolerance - dist) / mNearWaterOutdoorTolerance; + + if (mNearWaterPoints > 1) + { + int underwaterPoints = 0; + + float step = mNearWaterRadius * 2.0f / (mNearWaterPoints - 1); + + for (int x = 0; x < mNearWaterPoints; x++) + { + for (int y = 0; y < mNearWaterPoints; y++) + { + float height = world->getTerrainHeightAt( + osg::Vec3f(pos.x() - mNearWaterRadius + x*step, pos.y() - mNearWaterRadius + y*step, 0.0f)); + + if (height < 0) + underwaterPoints++; + } + } + + volume *= underwaterPoints * 2.0f / (mNearWaterPoints*mNearWaterPoints); + } + } + else if (!player.getCell()->isExterior() && dist < mNearWaterIndoorTolerance) + { + volume = (mNearWaterIndoorTolerance - dist) / mNearWaterIndoorTolerance; + } + } + } + else + volume = 1.0f; + + volume = std::min(volume, 1.0f); + + if (mNearWaterSound) + { + if (volume == 0.0f) + { + mOutput->finishSound(mNearWaterSound); + mNearWaterSound.reset(); + } + else + { + bool soundIdChanged = false; + + Sound_Buffer* sfx = lookupSound(Misc::StringUtils::lowerCase(soundId)); + + for (SoundMap::const_iterator snditer = mActiveSounds.begin(); snditer != mActiveSounds.end(); ++snditer) + { + for (SoundBufferRefPairList::const_iterator pairiter = snditer->second.begin(); pairiter != snditer->second.end(); ++pairiter) + { + if (pairiter->first == mNearWaterSound) + { + if (pairiter->second != sfx) + soundIdChanged = true; + break; + } + } + } + + if (soundIdChanged) + { + mOutput->finishSound(mNearWaterSound); + mNearWaterSound = playSound(soundId, volume, 1.0f, Play_TypeSfx, Play_Loop); + } + else if (sfx) + mNearWaterSound->setVolume(volume * sfx->mVolume); + } + } + else if (volume > 0.0f) + mNearWaterSound = playSound(soundId, volume, 1.0f, Play_TypeSfx, Play_Loop); + } + void SoundManager::updateSounds(float duration) { static float timePassed = 0.0; @@ -941,6 +1039,7 @@ namespace MWSound { updateSounds(duration); updateRegionSound(duration); + updateWaterSound(duration); } } @@ -1105,6 +1204,7 @@ namespace MWSound mOutput->finishStream(*trkiter); mActiveTracks.clear(); mUnderwaterSound.reset(); + mNearWaterSound.reset(); stopMusic(); } } diff --git a/apps/openmw/mwsound/soundmanagerimp.hpp b/apps/openmw/mwsound/soundmanagerimp.hpp index d499dce7d..abf5edb97 100644 --- a/apps/openmw/mwsound/soundmanagerimp.hpp +++ b/apps/openmw/mwsound/soundmanagerimp.hpp @@ -11,6 +11,8 @@ #include +#include + #include "../mwbase/soundmanager.hpp" namespace VFS @@ -44,6 +46,8 @@ namespace MWSound { const VFS::Manager* mVFS; + Fallback::Map mFallback; + std::auto_ptr mOutput; // Caches available music tracks by @@ -56,6 +60,13 @@ namespace MWSound float mVoiceVolume; float mFootstepsVolume; + int mNearWaterRadius; + int mNearWaterPoints; + float mNearWaterIndoorTolerance; + float mNearWaterOutdoorTolerance; + std::string mNearWaterIndoorID; + std::string mNearWaterOutdoorID; + typedef std::auto_ptr > SoundBufferList; // List of sound buffers, grown as needed. New enties are added to the // back, allowing existing Sound_Buffer references/pointers to remain @@ -94,6 +105,7 @@ namespace MWSound int mPausedSoundTypes; MWBase::SoundPtr mUnderwaterSound; + MWBase::SoundPtr mNearWaterSound; Sound_Buffer *insertSound(const std::string &soundId, const ESM::Sound *sound); @@ -108,6 +120,7 @@ namespace MWSound void streamMusicFull(const std::string& filename); void updateSounds(float duration); void updateRegionSound(float duration); + void updateWaterSound(float duration); float volumeFromType(PlayType type) const; @@ -119,7 +132,7 @@ namespace MWSound friend class OpenAL_Output; public: - SoundManager(const VFS::Manager* vfs, bool useSound); + SoundManager(const VFS::Manager* vfs, const std::map& fallbackMap, bool useSound); virtual ~SoundManager(); virtual void processChangedSettings(const Settings::CategorySettingVector& settings); From e0afd6d0f78aa2635ee49c2209f63115b9b25f0c Mon Sep 17 00:00:00 2001 From: scrawl Date: Fri, 2 Dec 2016 02:25:05 +0100 Subject: [PATCH 02/46] Movement solver: performance improvement for the minimum stepping distance check, no need to waste time doing a second stepMove if we did not hit a slope or the step was already large enough to begin with. --- apps/openmw/mwphysics/physicssystem.cpp | 34 +++++++++++++++---------- 1 file changed, 21 insertions(+), 13 deletions(-) diff --git a/apps/openmw/mwphysics/physicssystem.cpp b/apps/openmw/mwphysics/physicssystem.cpp index 246e5eb59..1a97fc6ff 100644 --- a/apps/openmw/mwphysics/physicssystem.cpp +++ b/apps/openmw/mwphysics/physicssystem.cpp @@ -69,7 +69,14 @@ namespace MWPhysics return osg::RadiansToDegrees(std::acos(normal * osg::Vec3f(0.f, 0.f, 1.f))); } - static bool stepMove(const btCollisionObject *colobj, osg::Vec3f &position, + enum StepMoveResult + { + Result_Blocked, // unable to move over obstacle + Result_MaxSlope, // unable to end movement on this slope + Result_Success + }; + + static StepMoveResult stepMove(const btCollisionObject *colobj, osg::Vec3f &position, const osg::Vec3f &toMove, float &remainingTime, const btCollisionWorld* collisionWorld) { /* @@ -120,7 +127,7 @@ namespace MWPhysics stepper.doTrace(colobj, position, position+osg::Vec3f(0.0f,0.0f,sStepSizeUp), collisionWorld); if(stepper.mFraction < std::numeric_limits::epsilon()) - return false; // didn't even move the smallest representable amount + return Result_Blocked; // didn't even move the smallest representable amount // (TODO: shouldn't this be larger? Why bother with such a small amount?) /* @@ -138,7 +145,7 @@ namespace MWPhysics */ tracer.doTrace(colobj, stepper.mEndPos, stepper.mEndPos + toMove, collisionWorld); if(tracer.mFraction < std::numeric_limits::epsilon()) - return false; // didn't even move the smallest representable amount + return Result_Blocked; // didn't even move the smallest representable amount /* * Try moving back down sStepSizeDown using stepper. @@ -156,22 +163,22 @@ namespace MWPhysics * ============================================== */ stepper.doTrace(colobj, tracer.mEndPos, tracer.mEndPos-osg::Vec3f(0.0f,0.0f,sStepSizeDown), collisionWorld); - if(stepper.mFraction < 1.0f && getSlope(stepper.mPlaneNormal) <= sMaxSlope) + if (getSlope(stepper.mPlaneNormal) > sMaxSlope) + return Result_MaxSlope; + if(stepper.mFraction < 1.0f) { // don't allow stepping up other actors if (stepper.mHitObject->getBroadphaseHandle()->m_collisionFilterGroup == CollisionType_Actor) - return false; + return Result_Blocked; // only step down onto semi-horizontal surfaces. don't step down onto the side of a house or a wall. // TODO: stepper.mPlaneNormal does not appear to be reliable - needs more testing // NOTE: caller's variables 'position' & 'remainingTime' are modified here position = stepper.mEndPos; remainingTime *= (1.0f-tracer.mFraction); // remaining time is proportional to remaining distance - return true; + return Result_Success; } - // moved between 0 and just under sStepSize distance but slope was too great, - // or moved full sStepSize distance (FIXME: is this a bug?) - return false; + return Result_Blocked; } @@ -361,14 +368,15 @@ namespace MWPhysics osg::Vec3f oldPosition = newPosition; // We hit something. Try to step up onto it. (NOTE: stepMove does not allow stepping over) // NOTE: stepMove modifies newPosition if successful - bool result = stepMove(colobj, newPosition, velocity*remainingTime, remainingTime, collisionWorld); - if (!result) // to make sure the maximum stepping distance isn't framerate-dependent or movement-speed dependent + const float minStep = 10.f; + StepMoveResult result = stepMove(colobj, newPosition, velocity*remainingTime, remainingTime, collisionWorld); + if (result == Result_MaxSlope && (velocity*remainingTime).length() < minStep) // to make sure the maximum stepping distance isn't framerate-dependent or movement-speed dependent { osg::Vec3f normalizedVelocity = velocity; normalizedVelocity.normalize(); - result = stepMove(colobj, newPosition, normalizedVelocity*10.f, remainingTime, collisionWorld); + result = stepMove(colobj, newPosition, normalizedVelocity*minStep, remainingTime, collisionWorld); } - if(result) + if(result == Result_Success) { // don't let pure water creatures move out of water after stepMove if (ptr.getClass().isPureWaterCreature(ptr) From 28639c3b2f484c1d3a87ad2654496705540f634f Mon Sep 17 00:00:00 2001 From: Kurnevsky Evgeny Date: Sat, 3 Dec 2016 17:13:31 +0300 Subject: [PATCH 03/46] Crash fix when item is disabled before it casts spell. --- apps/openmw/mwmechanics/spellcasting.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/apps/openmw/mwmechanics/spellcasting.cpp b/apps/openmw/mwmechanics/spellcasting.cpp index 5c5fc3899..5865c32b9 100644 --- a/apps/openmw/mwmechanics/spellcasting.cpp +++ b/apps/openmw/mwmechanics/spellcasting.cpp @@ -913,7 +913,7 @@ namespace MWMechanics MWRender::Animation* animation = MWBase::Environment::get().getWorld()->getAnimation(mCaster); - if (mCaster.getClass().isActor()) // TODO: Non-actors should also create a spell cast vfx + if (animation && mCaster.getClass().isActor()) // TODO: Non-actors should also create a spell cast vfx even if they are disabled (animation == NULL) { const ESM::Static* castStatic; @@ -927,7 +927,7 @@ namespace MWMechanics animation->addEffect("meshes\\" + castStatic->mModel, effect->mIndex, false, "", texture); } - if (!mCaster.getClass().isActor()) + if (animation && !mCaster.getClass().isActor()) animation->addSpellCastGlow(effect); static const std::string schools[] = { From 83945cf2800292cdc975bbf837bdf4ebddd92ed1 Mon Sep 17 00:00:00 2001 From: mrohrlach Date: Sat, 3 Dec 2016 15:24:21 -0700 Subject: [PATCH 04/46] Added reasonable approximation of magic bolt lights --- apps/openmw/mwworld/projectilemanager.cpp | 23 +++++++++++++++++++++-- 1 file changed, 21 insertions(+), 2 deletions(-) diff --git a/apps/openmw/mwworld/projectilemanager.cpp b/apps/openmw/mwworld/projectilemanager.cpp index 35df52a18..4b373dad0 100644 --- a/apps/openmw/mwworld/projectilemanager.cpp +++ b/apps/openmw/mwworld/projectilemanager.cpp @@ -2,6 +2,8 @@ #include +#include +#include #include #include @@ -142,8 +144,8 @@ namespace MWWorld state.mNode->setNodeMask(MWRender::Mask_Effect); state.mNode->setPosition(pos); state.mNode->setAttitude(orient); - - osg::Group* attachTo = state.mNode; + + osg::Group* attachTo = state.mNode; if (rotate) { @@ -167,6 +169,23 @@ namespace MWWorld mResourceSystem->getSceneManager()->getInstance("meshes\\" + weapon->mModel, findVisitor.mFoundNode); } + // Add projectile light + osg::ref_ptr projectileLight(new osg::Light); + projectileLight->setDiffuse(osg::Vec4(0.95f, 0.71f, 0.25f, 1.0f)); + projectileLight->setAmbient(osg::Vec4(0.32f, 0.08f, 0.01f, 1.0f)); + projectileLight->setSpecular(osg::Vec4(0, 0, 0, 0)); + projectileLight->setLinearAttenuation(0.5f / 15); + projectileLight->setPosition(osg::Vec4(pos, 1.0)); + + // Add projectile light source + SceneUtil::LightSource* projectileLightSource = new SceneUtil::LightSource; + projectileLightSource->setNodeMask(MWRender::Mask_Lighting); + projectileLightSource->setRadius(66.f); + + state.mNode->addChild(projectileLightSource); + projectileLightSource->setLight(projectileLight); + + SceneUtil::DisableFreezeOnCullVisitor disableFreezeOnCullVisitor; state.mNode->accept(disableFreezeOnCullVisitor); From 49ce80346c93f14456acb927b81bc0264874e20c Mon Sep 17 00:00:00 2001 From: mrohrlach Date: Sat, 3 Dec 2016 15:42:24 -0700 Subject: [PATCH 05/46] Changed methods slightly to ensure non-magic projectiles do not receive lights --- apps/openmw/mwworld/projectilemanager.cpp | 50 ++++++++++++----------- apps/openmw/mwworld/projectilemanager.hpp | 2 +- 2 files changed, 28 insertions(+), 24 deletions(-) diff --git a/apps/openmw/mwworld/projectilemanager.cpp b/apps/openmw/mwworld/projectilemanager.cpp index 4b373dad0..a81188046 100644 --- a/apps/openmw/mwworld/projectilemanager.cpp +++ b/apps/openmw/mwworld/projectilemanager.cpp @@ -138,7 +138,7 @@ namespace MWWorld }; - void ProjectileManager::createModel(State &state, const std::string &model, const osg::Vec3f& pos, const osg::Quat& orient, bool rotate, std::string texture) + void ProjectileManager::createModel(State &state, const std::string &model, const osg::Vec3f& pos, const osg::Quat& orient, bool rotate, bool isMagic, std::string texture) { state.mNode = new osg::PositionAttitudeTransform; state.mNode->setNodeMask(MWRender::Mask_Effect); @@ -169,21 +169,25 @@ namespace MWWorld mResourceSystem->getSceneManager()->getInstance("meshes\\" + weapon->mModel, findVisitor.mFoundNode); } - // Add projectile light - osg::ref_ptr projectileLight(new osg::Light); - projectileLight->setDiffuse(osg::Vec4(0.95f, 0.71f, 0.25f, 1.0f)); - projectileLight->setAmbient(osg::Vec4(0.32f, 0.08f, 0.01f, 1.0f)); - projectileLight->setSpecular(osg::Vec4(0, 0, 0, 0)); - projectileLight->setLinearAttenuation(0.5f / 15); - projectileLight->setPosition(osg::Vec4(pos, 1.0)); - - // Add projectile light source - SceneUtil::LightSource* projectileLightSource = new SceneUtil::LightSource; - projectileLightSource->setNodeMask(MWRender::Mask_Lighting); - projectileLightSource->setRadius(66.f); - - state.mNode->addChild(projectileLightSource); - projectileLightSource->setLight(projectileLight); + if (isMagic) + { + // Add magic bolt light + osg::ref_ptr projectileLight(new osg::Light); + projectileLight->setDiffuse(osg::Vec4(0.95f, 0.71f, 0.25f, 1.0f)); + projectileLight->setAmbient(osg::Vec4(0.32f, 0.08f, 0.01f, 1.0f)); + projectileLight->setSpecular(osg::Vec4(0, 0, 0, 0)); + projectileLight->setLinearAttenuation(0.5f / 15); + projectileLight->setPosition(osg::Vec4(pos, 1.0)); + + // Add magic bolt light source + SceneUtil::LightSource* projectileLightSource = new SceneUtil::LightSource; + projectileLightSource->setNodeMask(MWRender::Mask_Lighting); + projectileLightSource->setRadius(66.f); + + // Attach to scene node + state.mNode->addChild(projectileLightSource); + projectileLightSource->setLight(projectileLight); + } SceneUtil::DisableFreezeOnCullVisitor disableFreezeOnCullVisitor; @@ -248,7 +252,7 @@ namespace MWWorld MWWorld::ManualRef ref(MWBase::Environment::get().getWorld()->getStore(), state.mIdMagic.at(0)); MWWorld::Ptr ptr = ref.getPtr(); - createModel(state, ptr.getClass().getModel(ptr), pos, orient, true, texture); + createModel(state, ptr.getClass().getModel(ptr), pos, orient, true, true, texture); MWBase::SoundManager *sndMgr = MWBase::Environment::get().getSoundManager(); for (size_t it = 0; it != state.mSoundIds.size(); it++) @@ -272,7 +276,7 @@ namespace MWWorld MWWorld::ManualRef ref(MWBase::Environment::get().getWorld()->getStore(), projectile.getCellRef().getRefId()); MWWorld::Ptr ptr = ref.getPtr(); - createModel(state, ptr.getClass().getModel(ptr), pos, orient, false); + createModel(state, ptr.getClass().getModel(ptr), pos, orient, false, false); mProjectiles.push_back(state); } @@ -478,9 +482,9 @@ namespace MWWorld bool ProjectileManager::readRecord(ESM::ESMReader &reader, uint32_t type) { - if (type == ESM::REC_PROJ) + if (type == ESM::REC_PROJ) { - ESM::ProjectileState esm; + ESM::ProjectileState esm; esm.load(reader); ProjectileState state; @@ -502,14 +506,14 @@ namespace MWWorld return true; } - createModel(state, model, osg::Vec3f(esm.mPosition), osg::Quat(esm.mOrientation), false); + createModel(state, model, osg::Vec3f(esm.mPosition), osg::Quat(esm.mOrientation), false, false); mProjectiles.push_back(state); return true; } else if (type == ESM::REC_MPRJ) { - ESM::MagicBoltState esm; + ESM::MagicBoltState esm; esm.load(reader); MagicBoltState state; @@ -537,7 +541,7 @@ namespace MWWorld return true; } - createModel(state, model, osg::Vec3f(esm.mPosition), osg::Quat(esm.mOrientation), true, texture); + createModel(state, model, osg::Vec3f(esm.mPosition), osg::Quat(esm.mOrientation), true, true, texture); MWBase::SoundManager *sndMgr = MWBase::Environment::get().getSoundManager(); diff --git a/apps/openmw/mwworld/projectilemanager.hpp b/apps/openmw/mwworld/projectilemanager.hpp index a8769fcf9..d17e24b0c 100644 --- a/apps/openmw/mwworld/projectilemanager.hpp +++ b/apps/openmw/mwworld/projectilemanager.hpp @@ -122,7 +122,7 @@ namespace MWWorld void moveProjectiles(float dt); void moveMagicBolts(float dt); - void createModel (State& state, const std::string& model, const osg::Vec3f& pos, const osg::Quat& orient, bool rotate, std::string texture = ""); + void createModel (State& state, const std::string& model, const osg::Vec3f& pos, const osg::Quat& orient, bool rotate, bool isMagic, std::string texture = ""); void update (State& state, float duration); void operator=(const ProjectileManager&); From 61097d93b9d72f8c16db35b118e9cffe5ce7cd20 Mon Sep 17 00:00:00 2001 From: mrohrlach Date: Sat, 3 Dec 2016 19:09:03 -0700 Subject: [PATCH 06/46] Replaced tabs with spaces (oops) --- apps/openmw/mwworld/projectilemanager.cpp | 51 +++++++++++------------ 1 file changed, 25 insertions(+), 26 deletions(-) diff --git a/apps/openmw/mwworld/projectilemanager.cpp b/apps/openmw/mwworld/projectilemanager.cpp index a81188046..56a4b75fe 100644 --- a/apps/openmw/mwworld/projectilemanager.cpp +++ b/apps/openmw/mwworld/projectilemanager.cpp @@ -144,8 +144,8 @@ namespace MWWorld state.mNode->setNodeMask(MWRender::Mask_Effect); state.mNode->setPosition(pos); state.mNode->setAttitude(orient); - - osg::Group* attachTo = state.mNode; + + osg::Group* attachTo = state.mNode; if (rotate) { @@ -169,27 +169,26 @@ namespace MWWorld mResourceSystem->getSceneManager()->getInstance("meshes\\" + weapon->mModel, findVisitor.mFoundNode); } - if (isMagic) - { - // Add magic bolt light - osg::ref_ptr projectileLight(new osg::Light); - projectileLight->setDiffuse(osg::Vec4(0.95f, 0.71f, 0.25f, 1.0f)); - projectileLight->setAmbient(osg::Vec4(0.32f, 0.08f, 0.01f, 1.0f)); - projectileLight->setSpecular(osg::Vec4(0, 0, 0, 0)); - projectileLight->setLinearAttenuation(0.5f / 15); - projectileLight->setPosition(osg::Vec4(pos, 1.0)); - - // Add magic bolt light source - SceneUtil::LightSource* projectileLightSource = new SceneUtil::LightSource; - projectileLightSource->setNodeMask(MWRender::Mask_Lighting); - projectileLightSource->setRadius(66.f); - - // Attach to scene node - state.mNode->addChild(projectileLightSource); - projectileLightSource->setLight(projectileLight); - } - - + if (isMagic) + { + // Add magic bolt light + osg::ref_ptr projectileLight(new osg::Light); + projectileLight->setDiffuse(osg::Vec4(0.95f, 0.71f, 0.25f, 1.0f)); + projectileLight->setAmbient(osg::Vec4(0.32f, 0.08f, 0.01f, 1.0f)); + projectileLight->setSpecular(osg::Vec4(0, 0, 0, 0)); + projectileLight->setLinearAttenuation(0.5f / 15); + projectileLight->setPosition(osg::Vec4(pos, 1.0)); + + // Add magic bolt light source + SceneUtil::LightSource* projectileLightSource = new SceneUtil::LightSource; + projectileLightSource->setNodeMask(MWRender::Mask_Lighting); + projectileLightSource->setRadius(66.f); + + // Attach to scene node + state.mNode->addChild(projectileLightSource); + projectileLightSource->setLight(projectileLight); + } + SceneUtil::DisableFreezeOnCullVisitor disableFreezeOnCullVisitor; state.mNode->accept(disableFreezeOnCullVisitor); @@ -482,9 +481,9 @@ namespace MWWorld bool ProjectileManager::readRecord(ESM::ESMReader &reader, uint32_t type) { - if (type == ESM::REC_PROJ) + if (type == ESM::REC_PROJ) { - ESM::ProjectileState esm; + ESM::ProjectileState esm; esm.load(reader); ProjectileState state; @@ -513,7 +512,7 @@ namespace MWWorld } else if (type == ESM::REC_MPRJ) { - ESM::MagicBoltState esm; + ESM::MagicBoltState esm; esm.load(reader); MagicBoltState state; From 099e79edbec0d641399d14b2ab8fdb4edf56d3a5 Mon Sep 17 00:00:00 2001 From: mrohrlach Date: Sat, 3 Dec 2016 19:12:25 -0700 Subject: [PATCH 07/46] Changed a line that did not need to be changed apparently --- apps/openmw/mwworld/projectilemanager.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/openmw/mwworld/projectilemanager.cpp b/apps/openmw/mwworld/projectilemanager.cpp index 56a4b75fe..ba1104f93 100644 --- a/apps/openmw/mwworld/projectilemanager.cpp +++ b/apps/openmw/mwworld/projectilemanager.cpp @@ -144,7 +144,7 @@ namespace MWWorld state.mNode->setNodeMask(MWRender::Mask_Effect); state.mNode->setPosition(pos); state.mNode->setAttitude(orient); - + osg::Group* attachTo = state.mNode; if (rotate) From 3816d0f6dc0b6094765c0b44caf24e252d35c0fb Mon Sep 17 00:00:00 2001 From: mrohrlach Date: Sat, 3 Dec 2016 19:44:52 -0700 Subject: [PATCH 08/46] Changed light values to better match vanilla. Still need to pull diffusion properties from spells --- apps/openmw/mwworld/projectilemanager.cpp | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/apps/openmw/mwworld/projectilemanager.cpp b/apps/openmw/mwworld/projectilemanager.cpp index ba1104f93..0842f5d1d 100644 --- a/apps/openmw/mwworld/projectilemanager.cpp +++ b/apps/openmw/mwworld/projectilemanager.cpp @@ -173,10 +173,12 @@ namespace MWWorld { // Add magic bolt light osg::ref_ptr projectileLight(new osg::Light); - projectileLight->setDiffuse(osg::Vec4(0.95f, 0.71f, 0.25f, 1.0f)); - projectileLight->setAmbient(osg::Vec4(0.32f, 0.08f, 0.01f, 1.0f)); - projectileLight->setSpecular(osg::Vec4(0, 0, 0, 0)); - projectileLight->setLinearAttenuation(0.5f / 15); + projectileLight->setAmbient(osg::Vec4(1.0f, 1.0f, 1.0f, 1.0f)); + projectileLight->setDiffuse(osg::Vec4(0.814f, 0.682f, 0.652f, 1.0f)); + projectileLight->setSpecular(osg::Vec4(30.0f, 30.0f, 30.0f, 1.0f)); + projectileLight->setConstantAttenuation(0.f); + projectileLight->setLinearAttenuation(0.1f); + projectileLight->setQuadraticAttenuation(0.f); projectileLight->setPosition(osg::Vec4(pos, 1.0)); // Add magic bolt light source From 1e654ca4c3ad05f55e9fac6a0ae75de2728b05a9 Mon Sep 17 00:00:00 2001 From: scrawl Date: Sun, 4 Dec 2016 15:33:37 +0100 Subject: [PATCH 09/46] Update AUTHORS.md --- AUTHORS.md | 1 + 1 file changed, 1 insertion(+) diff --git a/AUTHORS.md b/AUTHORS.md index 7f1f91892..2a7ed1ed9 100644 --- a/AUTHORS.md +++ b/AUTHORS.md @@ -74,6 +74,7 @@ Programmers Karl-Felix Glatzer (k1ll) Kevin Poitra (PuppyKevin) Koncord + Kurnevsky Evgeny (kurnevsky) Lars Söderberg (Lazaroth) lazydev Leon Saunders (emoose) From ef5cf76ad81b344726d9869f9998818c708795a3 Mon Sep 17 00:00:00 2001 From: mrohrlach Date: Sun, 4 Dec 2016 16:11:21 -0700 Subject: [PATCH 10/46] Implemented retrieval of effect colors for lights, made recommended changes --- apps/openmw/mwworld/projectilemanager.cpp | 37 +++++++++++++++++++---- apps/openmw/mwworld/projectilemanager.hpp | 2 +- 2 files changed, 32 insertions(+), 7 deletions(-) diff --git a/apps/openmw/mwworld/projectilemanager.cpp b/apps/openmw/mwworld/projectilemanager.cpp index 0842f5d1d..1d290c8a1 100644 --- a/apps/openmw/mwworld/projectilemanager.cpp +++ b/apps/openmw/mwworld/projectilemanager.cpp @@ -2,8 +2,6 @@ #include -#include -#include #include #include @@ -138,7 +136,7 @@ namespace MWWorld }; - void ProjectileManager::createModel(State &state, const std::string &model, const osg::Vec3f& pos, const osg::Quat& orient, bool rotate, bool isMagic, std::string texture) + void ProjectileManager::createModel(State &state, const std::string &model, const osg::Vec3f& pos, const osg::Quat& orient, bool rotate, bool createLight, std::string texture) { state.mNode = new osg::PositionAttitudeTransform; state.mNode->setNodeMask(MWRender::Mask_Effect); @@ -169,13 +167,40 @@ namespace MWWorld mResourceSystem->getSceneManager()->getInstance("meshes\\" + weapon->mModel, findVisitor.mFoundNode); } - if (isMagic) + if (createLight) { + // Combine colors of individual effects + osg::Vec4 lightDiffuseColor; + if (state.mIdMagic.size() > 0) + { + float lightDiffuseRed = 0.0f; + float lightDiffuseGreen = 0.0f; + float lightDiffuseBlue = 0.0f; + for (std::vector::const_iterator it = ((MagicBoltState&)state).mEffects.mList.begin(); it != ((MagicBoltState&)state).mEffects.mList.end(); ++it) + { + const ESM::MagicEffect* magicEffect = MWBase::Environment::get().getWorld()->getStore().get().find( + it->mEffectID); + lightDiffuseRed += ((float) magicEffect->mData.mRed / 255.f); + lightDiffuseGreen += ((float) magicEffect->mData.mGreen / 255.f); + lightDiffuseBlue += ((float) magicEffect->mData.mBlue / 255.f); + } + int numberOfEffects = ((MagicBoltState&)state).mEffects.mList.size(); + lightDiffuseColor = osg::Vec4(lightDiffuseRed / numberOfEffects + , lightDiffuseGreen / numberOfEffects + , lightDiffuseBlue / numberOfEffects + , 1.0f); + printf("%f, %f, %f", (lightDiffuseRed / numberOfEffects), (lightDiffuseGreen / numberOfEffects), (lightDiffuseBlue / numberOfEffects)); + } + else + { + lightDiffuseColor = osg::Vec4(0.814f, 0.682f, 0.652f, 1.0f); + } + // Add magic bolt light osg::ref_ptr projectileLight(new osg::Light); projectileLight->setAmbient(osg::Vec4(1.0f, 1.0f, 1.0f, 1.0f)); - projectileLight->setDiffuse(osg::Vec4(0.814f, 0.682f, 0.652f, 1.0f)); - projectileLight->setSpecular(osg::Vec4(30.0f, 30.0f, 30.0f, 1.0f)); + projectileLight->setDiffuse(lightDiffuseColor); + projectileLight->setSpecular(osg::Vec4(0.0f, 0.0f, 0.0f, 0.0f)); projectileLight->setConstantAttenuation(0.f); projectileLight->setLinearAttenuation(0.1f); projectileLight->setQuadraticAttenuation(0.f); diff --git a/apps/openmw/mwworld/projectilemanager.hpp b/apps/openmw/mwworld/projectilemanager.hpp index d17e24b0c..db090eaef 100644 --- a/apps/openmw/mwworld/projectilemanager.hpp +++ b/apps/openmw/mwworld/projectilemanager.hpp @@ -122,7 +122,7 @@ namespace MWWorld void moveProjectiles(float dt); void moveMagicBolts(float dt); - void createModel (State& state, const std::string& model, const osg::Vec3f& pos, const osg::Quat& orient, bool rotate, bool isMagic, std::string texture = ""); + void createModel (State& state, const std::string& model, const osg::Vec3f& pos, const osg::Quat& orient, bool rotate, bool createLight, std::string texture = ""); void update (State& state, float duration); void operator=(const ProjectileManager&); From c2e5f24e981ecd4bc826075d274816469f75d4a4 Mon Sep 17 00:00:00 2001 From: mrohrlach Date: Sun, 4 Dec 2016 16:31:11 -0700 Subject: [PATCH 11/46] Tidying up --- apps/openmw/mwworld/projectilemanager.cpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/apps/openmw/mwworld/projectilemanager.cpp b/apps/openmw/mwworld/projectilemanager.cpp index 1d290c8a1..3d9c4df90 100644 --- a/apps/openmw/mwworld/projectilemanager.cpp +++ b/apps/openmw/mwworld/projectilemanager.cpp @@ -169,7 +169,7 @@ namespace MWWorld if (createLight) { - // Combine colors of individual effects + // Case: magical effects (combine colors of individual effects) osg::Vec4 lightDiffuseColor; if (state.mIdMagic.size() > 0) { @@ -189,14 +189,14 @@ namespace MWWorld , lightDiffuseGreen / numberOfEffects , lightDiffuseBlue / numberOfEffects , 1.0f); - printf("%f, %f, %f", (lightDiffuseRed / numberOfEffects), (lightDiffuseGreen / numberOfEffects), (lightDiffuseBlue / numberOfEffects)); } else { + // Case: no magical effects, but still creating light lightDiffuseColor = osg::Vec4(0.814f, 0.682f, 0.652f, 1.0f); } - // Add magic bolt light + // Add light osg::ref_ptr projectileLight(new osg::Light); projectileLight->setAmbient(osg::Vec4(1.0f, 1.0f, 1.0f, 1.0f)); projectileLight->setDiffuse(lightDiffuseColor); @@ -206,7 +206,7 @@ namespace MWWorld projectileLight->setQuadraticAttenuation(0.f); projectileLight->setPosition(osg::Vec4(pos, 1.0)); - // Add magic bolt light source + // Add light source SceneUtil::LightSource* projectileLightSource = new SceneUtil::LightSource; projectileLightSource->setNodeMask(MWRender::Mask_Lighting); projectileLightSource->setRadius(66.f); From 3ac66ec9d4d038e6b34facff5cb5020897deb01a Mon Sep 17 00:00:00 2001 From: scrawl Date: Mon, 5 Dec 2016 00:56:11 +0100 Subject: [PATCH 12/46] Update AUTHORS.md --- AUTHORS.md | 1 + 1 file changed, 1 insertion(+) diff --git a/AUTHORS.md b/AUTHORS.md index 2a7ed1ed9..83777df18 100644 --- a/AUTHORS.md +++ b/AUTHORS.md @@ -23,6 +23,7 @@ Programmers Alexander Olofsson (Ace) Allofich AnyOldName3 + Aussiemon Austin Salgat (Salgat) Artem Kotsynyak (greye) artemutin From 99bcf4716778a4e45bce60b02d1ea210c6928ef8 Mon Sep 17 00:00:00 2001 From: MiroslavR Date: Mon, 5 Dec 2016 21:31:17 +0100 Subject: [PATCH 13/46] Implement NiSphericalCollider (Closes #3644) --- components/nif/controlled.cpp | 9 +++++ components/nif/controlled.hpp | 10 +++++ components/nif/niffile.cpp | 1 + components/nif/record.hpp | 3 +- components/nifosg/nifloader.cpp | 7 ++++ components/nifosg/particle.cpp | 69 +++++++++++++++++++++++++++++++++ components/nifosg/particle.hpp | 18 +++++++++ 7 files changed, 116 insertions(+), 1 deletion(-) diff --git a/components/nif/controlled.cpp b/components/nif/controlled.cpp index 5c63094ce..52e7a7302 100644 --- a/components/nif/controlled.cpp +++ b/components/nif/controlled.cpp @@ -87,6 +87,15 @@ namespace Nif nif->skip(17); } + void NiSphericalCollider::read(NIFStream* nif) + { + Controlled::read(nif); + + mBounceFactor = nif->getFloat(); + mRadius = nif->getFloat(); + mCenter = nif->getVector3(); + } + diff --git a/components/nif/controlled.hpp b/components/nif/controlled.hpp index 4bd7ce1f9..5601474ac 100644 --- a/components/nif/controlled.hpp +++ b/components/nif/controlled.hpp @@ -111,6 +111,16 @@ public: float mPlaneDistance; }; +class NiSphericalCollider : public Controlled +{ +public: + float mBounceFactor; + float mRadius; + osg::Vec3f mCenter; + + void read(NIFStream *nif); +}; + class NiParticleRotation : public Controlled { public: diff --git a/components/nif/niffile.cpp b/components/nif/niffile.cpp index f6e489527..b4b1caefc 100644 --- a/components/nif/niffile.cpp +++ b/components/nif/niffile.cpp @@ -89,6 +89,7 @@ static std::map makeFactory() newFactory.insert(makeEntry("NiStringExtraData", &construct , RC_NiStringExtraData )); newFactory.insert(makeEntry("NiGravity", &construct , RC_NiGravity )); newFactory.insert(makeEntry("NiPlanarCollider", &construct , RC_NiPlanarCollider )); + newFactory.insert(makeEntry("NiSphericalCollider", &construct , RC_NiSphericalCollider )); newFactory.insert(makeEntry("NiParticleGrowFade", &construct , RC_NiParticleGrowFade )); newFactory.insert(makeEntry("NiParticleColorModifier", &construct , RC_NiParticleColorModifier )); newFactory.insert(makeEntry("NiParticleRotation", &construct , RC_NiParticleRotation )); diff --git a/components/nif/record.hpp b/components/nif/record.hpp index bcbdba115..605c4d76e 100644 --- a/components/nif/record.hpp +++ b/components/nif/record.hpp @@ -92,7 +92,8 @@ enum RecordType RC_NiSequenceStreamHelper, RC_NiSourceTexture, RC_NiSkinInstance, - RC_RootCollisionNode + RC_RootCollisionNode, + RC_NiSphericalCollider }; /// Base class for all records diff --git a/components/nifosg/nifloader.cpp b/components/nifosg/nifloader.cpp index 70ca82875..d4dabd2f9 100644 --- a/components/nifosg/nifloader.cpp +++ b/components/nifosg/nifloader.cpp @@ -871,6 +871,13 @@ namespace NifOsg const Nif::NiPlanarCollider* planarcollider = static_cast(colliders.getPtr()); program->addOperator(new PlanarCollider(planarcollider)); } + else if (colliders->recType == Nif::RC_NiSphericalCollider) + { + const Nif::NiSphericalCollider* sphericalcollider = static_cast(colliders.getPtr()); + program->addOperator(new SphericalCollider(sphericalcollider)); + } + else + std::cerr << "Unhandled particle collider " << colliders->recName << " in " << mFilename << std::endl; } } diff --git a/components/nifosg/particle.cpp b/components/nifosg/particle.cpp index f542cf379..0259b27e4 100644 --- a/components/nifosg/particle.cpp +++ b/components/nifosg/particle.cpp @@ -376,4 +376,73 @@ void PlanarCollider::operate(osgParticle::Particle *particle, double dt) } } +SphericalCollider::SphericalCollider(const Nif::NiSphericalCollider* collider) + : mBounceFactor(collider->mBounceFactor), + mSphere(collider->mCenter, collider->mRadius) +{ +} + +SphericalCollider::SphericalCollider() + : mBounceFactor(1.0f) +{ + +} + +SphericalCollider::SphericalCollider(const SphericalCollider& copy, const osg::CopyOp& copyop) + : osgParticle::Operator(copy, copyop) + , mBounceFactor(copy.mBounceFactor) + , mSphere(copy.mSphere) + , mSphereInParticleSpace(copy.mSphereInParticleSpace) +{ + +} + +void SphericalCollider::beginOperate(osgParticle::Program* program) +{ + mSphereInParticleSpace = mSphere; + if (program->getReferenceFrame() == osgParticle::ParticleProcessor::ABSOLUTE_RF) + mSphereInParticleSpace.center() = program->transformLocalToWorld(mSphereInParticleSpace.center()); +} + +void SphericalCollider::operate(osgParticle::Particle* particle, double dt) +{ + osg::Vec3f cent = (particle->getPosition() - mSphereInParticleSpace.center()); // vector from sphere center to particle + + bool insideSphere = cent.length2() <= mSphereInParticleSpace.radius2(); + + if (insideSphere + || (cent * particle->getVelocity() < 0.0f)) // if outside, make sure the particle is flying towards the sphere + { + // Collision test (finding point of contact) is performed by solving a quadratic equation: + // ||vec(cent) + vec(vel)*k|| = R /^2 + // k^2 + 2*k*(vec(cent)*vec(vel))/||vec(vel)||^2 + (||vec(cent)||^2 - R^2)/||vec(vel)||^2 = 0 + + float b = -(cent * particle->getVelocity()) / particle->getVelocity().length2(); + + osg::Vec3f u = cent + particle->getVelocity() * b; + + if (insideSphere + || (u.length2() < mSphereInParticleSpace.radius2())) + { + float d = (mSphereInParticleSpace.radius2() - u.length2()) / particle->getVelocity().length2(); + float k = insideSphere ? (std::sqrt(d) + b) : (b - std::sqrt(d)); + + if (k < dt) + { + // collision detected; reflect off the tangent plane + osg::Vec3f contact = particle->getPosition() + particle->getVelocity() * k; + + osg::Vec3 normal = (contact - mSphereInParticleSpace.center()); + normal.normalize(); + + float dotproduct = particle->getVelocity() * normal; + + osg::Vec3 reflectedVelocity = particle->getVelocity() - normal * (2 * dotproduct); + reflectedVelocity *= mBounceFactor; + particle->setVelocity(reflectedVelocity); + } + } + } +} + } diff --git a/components/nifosg/particle.hpp b/components/nifosg/particle.hpp index 6818aa7e0..f9c4abdac 100644 --- a/components/nifosg/particle.hpp +++ b/components/nifosg/particle.hpp @@ -16,6 +16,7 @@ namespace Nif { class NiGravity; class NiPlanarCollider; + class NiSphericalCollider; class NiColorData; } @@ -110,6 +111,23 @@ namespace NifOsg osg::Plane mPlaneInParticleSpace; }; + class SphericalCollider : public osgParticle::Operator + { + public: + SphericalCollider(const Nif::NiSphericalCollider* collider); + SphericalCollider(); + SphericalCollider(const SphericalCollider& copy, const osg::CopyOp& copyop); + + META_Object(NifOsg, SphericalCollider) + + virtual void beginOperate(osgParticle::Program* program); + virtual void operate(osgParticle::Particle* particle, double dt); + private: + float mBounceFactor; + osg::BoundingSphere mSphere; + osg::BoundingSphere mSphereInParticleSpace; + }; + class GrowFadeAffector : public osgParticle::Operator { public: From 6816e935f18aef75d50faf791b72266725333876 Mon Sep 17 00:00:00 2001 From: Allofich Date: Mon, 5 Dec 2016 20:12:13 +0900 Subject: [PATCH 14/46] Fix fortify maximum magicka expiration (Fixes #3648) --- apps/openmw/mwmechanics/actors.cpp | 10 ++++++---- apps/openmw/mwmechanics/spellcasting.cpp | 7 +++++-- apps/openmw/mwmechanics/spellcasting.hpp | 4 +++- 3 files changed, 14 insertions(+), 7 deletions(-) diff --git a/apps/openmw/mwmechanics/actors.cpp b/apps/openmw/mwmechanics/actors.cpp index 1a6a62fc3..2a5995e0c 100644 --- a/apps/openmw/mwmechanics/actors.cpp +++ b/apps/openmw/mwmechanics/actors.cpp @@ -512,8 +512,8 @@ namespace MWMechanics if (magnitude > 0 && remainingTime > 0 && remainingTime < mDuration) { CreatureStats& creatureStats = mActor.getClass().getCreatureStats(mActor); - effectTick(creatureStats, mActor, key, magnitude * remainingTime); - creatureStats.getMagicEffects().add(key, -magnitude); + if (effectTick(creatureStats, mActor, key, magnitude * remainingTime)) + creatureStats.getMagicEffects().add(key, -magnitude); } } }; @@ -527,8 +527,10 @@ namespace MWMechanics if (duration > 0) { - // apply correct magnitude for tickable effects that have just expired, - // in case duration > remaining time of effect + // Apply correct magnitude for tickable effects that have just expired, + // in case duration > remaining time of effect. + // One case where this will happen is when the player uses the rest/wait command + // while there is a tickable effect active that should expire before the end of the rest/wait. ExpiryVisitor visitor(ptr, duration); creatureStats.getActiveSpells().visitEffectSources(visitor); diff --git a/apps/openmw/mwmechanics/spellcasting.cpp b/apps/openmw/mwmechanics/spellcasting.cpp index 5865c32b9..72f0cddff 100644 --- a/apps/openmw/mwmechanics/spellcasting.cpp +++ b/apps/openmw/mwmechanics/spellcasting.cpp @@ -1009,10 +1009,10 @@ namespace MWMechanics creatureStats.setDynamic(index, stat); } - void effectTick(CreatureStats& creatureStats, const MWWorld::Ptr& actor, const EffectKey &effectKey, float magnitude) + bool effectTick(CreatureStats& creatureStats, const MWWorld::Ptr& actor, const EffectKey &effectKey, float magnitude) { if (magnitude == 0.f) - return; + return false; bool receivedMagicDamage = false; @@ -1144,10 +1144,13 @@ namespace MWMechanics case ESM::MagicEffect::RemoveCurse: actor.getClass().getCreatureStats(actor).getSpells().purgeCurses(); break; + default: + return false; } if (receivedMagicDamage && actor == getPlayer()) MWBase::Environment::get().getWindowManager()->activateHitOverlay(false); + return true; } } diff --git a/apps/openmw/mwmechanics/spellcasting.hpp b/apps/openmw/mwmechanics/spellcasting.hpp index 852ae79dc..6e25acf50 100644 --- a/apps/openmw/mwmechanics/spellcasting.hpp +++ b/apps/openmw/mwmechanics/spellcasting.hpp @@ -63,7 +63,9 @@ namespace MWMechanics int getEffectiveEnchantmentCastCost (float castCost, const MWWorld::Ptr& actor); - void effectTick(CreatureStats& creatureStats, const MWWorld::Ptr& actor, const MWMechanics::EffectKey& effectKey, float magnitude); + /// Apply a magic effect that is applied in tick intervals until its remaining time ends or it is removed + /// @return Was the effect a tickable effect with a magnitude? + bool effectTick(CreatureStats& creatureStats, const MWWorld::Ptr& actor, const MWMechanics::EffectKey& effectKey, float magnitude); class CastSpell { From a6dae51d87f2529a458c845144d1b6325c556070 Mon Sep 17 00:00:00 2001 From: Allofich Date: Tue, 6 Dec 2016 22:23:06 +0900 Subject: [PATCH 15/46] Require line of sight for AI attacks (Fixes #3646) --- apps/openmw/mwmechanics/aicombat.cpp | 54 +++++++++++++++------------- apps/openmw/mwmechanics/aicombat.hpp | 2 ++ 2 files changed, 32 insertions(+), 24 deletions(-) diff --git a/apps/openmw/mwmechanics/aicombat.cpp b/apps/openmw/mwmechanics/aicombat.cpp index 80b343d4f..21eaa0de5 100644 --- a/apps/openmw/mwmechanics/aicombat.cpp +++ b/apps/openmw/mwmechanics/aicombat.cpp @@ -60,30 +60,30 @@ namespace MWMechanics FleeState_RunToDestination }; FleeState mFleeState; - bool mFleeLOS; - float mFleeUpdateLOSTimer; + bool mLOS; + float mUpdateLOSTimer; float mFleeBlindRunTimer; ESM::Pathgrid::Point mFleeDest; AiCombatStorage(): - mAttackCooldown(0), + mAttackCooldown(0.0f), mTimerReact(AI_REACTION_TIME), - mTimerCombatMove(0), + mTimerCombatMove(0.0f), mReadyToAttack(false), mAttack(false), - mAttackRange(0), + mAttackRange(0.0f), mCombatMove(false), mLastTargetPos(0,0,0), mCell(NULL), mCurrentAction(), - mActionCooldown(0), + mActionCooldown(0.0f), mStrength(), mForceNoShortcut(false), mShortcutFailPos(), mMovement(), mFleeState(FleeState_None), - mFleeLOS(false), - mFleeUpdateLOSTimer(0.0f), + mLOS(false), + mUpdateLOSTimer(0.0f), mFleeBlindRunTimer(0.0f) {} @@ -181,10 +181,14 @@ namespace MWMechanics if (!storage.isFleeing()) { - if (storage.mCurrentAction.get()) // need to wait to init action with it's attack range + if (storage.mCurrentAction.get()) // need to wait to init action with its attack range { - //Update every frame - bool is_target_reached = pathTo(actor, target.getRefData().getPosition().pos, duration, storage.mAttackRange); + //Update every frame. UpdateLOS uses a timer, so the LOS check does not happen every frame. + updateLOS(actor, target, duration, storage); + float targetReachedTolerance = 0.0f; + if (storage.mLOS) + targetReachedTolerance = storage.mAttackRange; + bool is_target_reached = pathTo(actor, target.getRefData().getPosition().pos, duration, targetReachedTolerance); if (is_target_reached) storage.mReadyToAttack = true; } @@ -283,7 +287,7 @@ namespace MWMechanics osg::Vec3f vAimDir = MWBase::Environment::get().getWorld()->aimToTarget(actor, target); float distToTarget = MWBase::Environment::get().getWorld()->getHitDistance(actor, target); - storage.mReadyToAttack = (currentAction->isAttackingOrSpell() && distToTarget <= rangeAttack); + storage.mReadyToAttack = (currentAction->isAttackingOrSpell() && distToTarget <= rangeAttack && storage.mLOS); if (storage.mReadyToAttack) { @@ -309,18 +313,23 @@ namespace MWMechanics } } - void MWMechanics::AiCombat::updateFleeing(const MWWorld::Ptr& actor, const MWWorld::Ptr& target, float duration, MWMechanics::AiCombatStorage& storage) + void MWMechanics::AiCombat::updateLOS(const MWWorld::Ptr& actor, const MWWorld::Ptr& target, float duration, MWMechanics::AiCombatStorage& storage) { static const float LOS_UPDATE_DURATION = 0.5f; - static const float BLIND_RUN_DURATION = 1.0f; - - if (storage.mFleeUpdateLOSTimer <= 0.f) + if (storage.mUpdateLOSTimer <= 0.f) { - storage.mFleeLOS = MWBase::Environment::get().getWorld()->getLOS(actor, target); - storage.mFleeUpdateLOSTimer = LOS_UPDATE_DURATION; + storage.mLOS = MWBase::Environment::get().getWorld()->getLOS(actor, target); + storage.mUpdateLOSTimer = LOS_UPDATE_DURATION; } else - storage.mFleeUpdateLOSTimer -= duration; + storage.mUpdateLOSTimer -= duration; + } + + void MWMechanics::AiCombat::updateFleeing(const MWWorld::Ptr& actor, const MWWorld::Ptr& target, float duration, MWMechanics::AiCombatStorage& storage) + { + static const float BLIND_RUN_DURATION = 1.0f; + + updateLOS(actor, target, duration, storage); AiCombatStorage::FleeState& state = storage.mFleeState; switch (state) @@ -332,7 +341,7 @@ namespace MWMechanics { float triggerDist = getMaxAttackDistance(target); - if (storage.mFleeLOS && + if (storage.mLOS && (triggerDist >= 1000 || getDistanceMinusHalfExtents(actor, target) <= triggerDist)) { const ESM::Pathgrid* pathgrid = @@ -399,7 +408,7 @@ namespace MWMechanics static const float fFleeDistance = MWBase::Environment::get().getWorld()->getStore().get().find("fFleeDistance")->getFloat(); float dist = (actor.getRefData().getPosition().asVec3() - target.getRefData().getPosition().asVec3()).length(); - if ((dist > fFleeDistance && !storage.mFleeLOS) + if ((dist > fFleeDistance && !storage.mLOS) || pathTo(actor, storage.mFleeDest, duration)) { state = AiCombatStorage::FleeState_Idle; @@ -602,9 +611,6 @@ namespace MWMechanics mMovement.mPosition[2] = 0; mFleeState = FleeState_None; mFleeDest = ESM::Pathgrid::Point(0, 0, 0); - mFleeLOS = false; - mFleeUpdateLOSTimer = 0.0f; - mFleeUpdateLOSTimer = 0.0f; } bool AiCombatStorage::isFleeing() diff --git a/apps/openmw/mwmechanics/aicombat.hpp b/apps/openmw/mwmechanics/aicombat.hpp index 3f2bde776..a2e995cb3 100644 --- a/apps/openmw/mwmechanics/aicombat.hpp +++ b/apps/openmw/mwmechanics/aicombat.hpp @@ -61,6 +61,8 @@ namespace MWMechanics void attack(const MWWorld::Ptr& actor, const MWWorld::Ptr& target, AiCombatStorage& storage, CharacterController& characterController); + void updateLOS(const MWWorld::Ptr& actor, const MWWorld::Ptr& target, float duration, AiCombatStorage& storage); + void updateFleeing(const MWWorld::Ptr& actor, const MWWorld::Ptr& target, float duration, AiCombatStorage& storage); /// Transfer desired movement (from AiCombatStorage) to Actor From 3b0c7918922499b425230583a1fe51e4dbb19d84 Mon Sep 17 00:00:00 2001 From: mrohrlach Date: Fri, 9 Dec 2016 18:10:06 -0700 Subject: [PATCH 16/46] Removed bad casts and unnecessary comments --- apps/openmw/mwworld/projectilemanager.cpp | 81 +++++++++++++---------- apps/openmw/mwworld/projectilemanager.hpp | 3 +- 2 files changed, 48 insertions(+), 36 deletions(-) diff --git a/apps/openmw/mwworld/projectilemanager.cpp b/apps/openmw/mwworld/projectilemanager.cpp index 3d9c4df90..264b8424d 100644 --- a/apps/openmw/mwworld/projectilemanager.cpp +++ b/apps/openmw/mwworld/projectilemanager.cpp @@ -136,7 +136,8 @@ namespace MWWorld }; - void ProjectileManager::createModel(State &state, const std::string &model, const osg::Vec3f& pos, const osg::Quat& orient, bool rotate, bool createLight, std::string texture) + void ProjectileManager::createModel(State &state, const std::string &model, const osg::Vec3f& pos, const osg::Quat& orient, + bool rotate, bool createLight, osg::Vec4 lightDiffuseColor, std::string texture) { state.mNode = new osg::PositionAttitudeTransform; state.mNode->setNodeMask(MWRender::Mask_Effect); @@ -169,34 +170,6 @@ namespace MWWorld if (createLight) { - // Case: magical effects (combine colors of individual effects) - osg::Vec4 lightDiffuseColor; - if (state.mIdMagic.size() > 0) - { - float lightDiffuseRed = 0.0f; - float lightDiffuseGreen = 0.0f; - float lightDiffuseBlue = 0.0f; - for (std::vector::const_iterator it = ((MagicBoltState&)state).mEffects.mList.begin(); it != ((MagicBoltState&)state).mEffects.mList.end(); ++it) - { - const ESM::MagicEffect* magicEffect = MWBase::Environment::get().getWorld()->getStore().get().find( - it->mEffectID); - lightDiffuseRed += ((float) magicEffect->mData.mRed / 255.f); - lightDiffuseGreen += ((float) magicEffect->mData.mGreen / 255.f); - lightDiffuseBlue += ((float) magicEffect->mData.mBlue / 255.f); - } - int numberOfEffects = ((MagicBoltState&)state).mEffects.mList.size(); - lightDiffuseColor = osg::Vec4(lightDiffuseRed / numberOfEffects - , lightDiffuseGreen / numberOfEffects - , lightDiffuseBlue / numberOfEffects - , 1.0f); - } - else - { - // Case: no magical effects, but still creating light - lightDiffuseColor = osg::Vec4(0.814f, 0.682f, 0.652f, 1.0f); - } - - // Add light osg::ref_ptr projectileLight(new osg::Light); projectileLight->setAmbient(osg::Vec4(1.0f, 1.0f, 1.0f, 1.0f)); projectileLight->setDiffuse(lightDiffuseColor); @@ -206,12 +179,10 @@ namespace MWWorld projectileLight->setQuadraticAttenuation(0.f); projectileLight->setPosition(osg::Vec4(pos, 1.0)); - // Add light source SceneUtil::LightSource* projectileLightSource = new SceneUtil::LightSource; projectileLightSource->setNodeMask(MWRender::Mask_Lighting); projectileLightSource->setRadius(66.f); - // Attach to scene node state.mNode->addChild(projectileLightSource); projectileLightSource->setLight(projectileLight); } @@ -278,7 +249,26 @@ namespace MWWorld MWWorld::ManualRef ref(MWBase::Environment::get().getWorld()->getStore(), state.mIdMagic.at(0)); MWWorld::Ptr ptr = ref.getPtr(); - createModel(state, ptr.getClass().getModel(ptr), pos, orient, true, true, texture); + // Calculate combined light color from magical effects + osg::Vec4 lightDiffuseColor; + float lightDiffuseRed = 0.0f; + float lightDiffuseGreen = 0.0f; + float lightDiffuseBlue = 0.0f; + for (std::vector::const_iterator it = state.mEffects.mList.begin(); it != state.mEffects.mList.end(); ++it) + { + const ESM::MagicEffect* magicEffect = MWBase::Environment::get().getWorld()->getStore().get().find( + it->mEffectID); + lightDiffuseRed += (static_cast(magicEffect->mData.mRed) / 255.f); + lightDiffuseGreen += (static_cast(magicEffect->mData.mGreen) / 255.f); + lightDiffuseBlue += (static_cast(magicEffect->mData.mBlue) / 255.f); + } + int numberOfEffects = ((MagicBoltState&)state).mEffects.mList.size(); + lightDiffuseColor = osg::Vec4(lightDiffuseRed / numberOfEffects + , lightDiffuseGreen / numberOfEffects + , lightDiffuseBlue / numberOfEffects + , 1.0f); + + createModel(state, ptr.getClass().getModel(ptr), pos, orient, true, true, lightDiffuseColor, texture); MWBase::SoundManager *sndMgr = MWBase::Environment::get().getSoundManager(); for (size_t it = 0; it != state.mSoundIds.size(); it++) @@ -302,7 +292,8 @@ namespace MWWorld MWWorld::ManualRef ref(MWBase::Environment::get().getWorld()->getStore(), projectile.getCellRef().getRefId()); MWWorld::Ptr ptr = ref.getPtr(); - createModel(state, ptr.getClass().getModel(ptr), pos, orient, false, false); + osg::Vec4 lightDiffuseColor = osg::Vec4(0.814f, 0.682f, 0.652f, 1.0f); + createModel(state, ptr.getClass().getModel(ptr), pos, orient, false, false, lightDiffuseColor); mProjectiles.push_back(state); } @@ -532,7 +523,8 @@ namespace MWWorld return true; } - createModel(state, model, osg::Vec3f(esm.mPosition), osg::Quat(esm.mOrientation), false, false); + osg::Vec4 lightDiffuseColor = osg::Vec4(0.814f, 0.682f, 0.652f, 1.0f); + createModel(state, model, osg::Vec3f(esm.mPosition), osg::Quat(esm.mOrientation), false, false, lightDiffuseColor); mProjectiles.push_back(state); return true; @@ -567,7 +559,26 @@ namespace MWWorld return true; } - createModel(state, model, osg::Vec3f(esm.mPosition), osg::Quat(esm.mOrientation), true, true, texture); + // Calculate combined light color from magical effects + osg::Vec4 lightDiffuseColor; + float lightDiffuseRed = 0.0f; + float lightDiffuseGreen = 0.0f; + float lightDiffuseBlue = 0.0f; + for (std::vector::const_iterator it = state.mEffects.mList.begin(); it != state.mEffects.mList.end(); ++it) + { + const ESM::MagicEffect* magicEffect = MWBase::Environment::get().getWorld()->getStore().get().find( + it->mEffectID); + lightDiffuseRed += (static_cast(magicEffect->mData.mRed) / 255.f); + lightDiffuseGreen += (static_cast(magicEffect->mData.mGreen) / 255.f); + lightDiffuseBlue += (static_cast(magicEffect->mData.mBlue) / 255.f); + } + int numberOfEffects = ((MagicBoltState&)state).mEffects.mList.size(); + lightDiffuseColor = osg::Vec4(lightDiffuseRed / numberOfEffects + , lightDiffuseGreen / numberOfEffects + , lightDiffuseBlue / numberOfEffects + , 1.0f); + + createModel(state, model, osg::Vec3f(esm.mPosition), osg::Quat(esm.mOrientation), true, true, lightDiffuseColor, texture); MWBase::SoundManager *sndMgr = MWBase::Environment::get().getSoundManager(); diff --git a/apps/openmw/mwworld/projectilemanager.hpp b/apps/openmw/mwworld/projectilemanager.hpp index db090eaef..2289706d3 100644 --- a/apps/openmw/mwworld/projectilemanager.hpp +++ b/apps/openmw/mwworld/projectilemanager.hpp @@ -122,7 +122,8 @@ namespace MWWorld void moveProjectiles(float dt); void moveMagicBolts(float dt); - void createModel (State& state, const std::string& model, const osg::Vec3f& pos, const osg::Quat& orient, bool rotate, bool createLight, std::string texture = ""); + void createModel (State& state, const std::string& model, const osg::Vec3f& pos, const osg::Quat& orient, + bool rotate, bool createLight, osg::Vec4 lightDiffuseColor, std::string texture = ""); void update (State& state, float duration); void operator=(const ProjectileManager&); From f5da179a906ab6d46eae9be7ea51fa9f2f18a0ad Mon Sep 17 00:00:00 2001 From: mrohrlach Date: Fri, 9 Dec 2016 18:15:40 -0700 Subject: [PATCH 17/46] Removed two more bad casts --- apps/openmw/mwworld/projectilemanager.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/apps/openmw/mwworld/projectilemanager.cpp b/apps/openmw/mwworld/projectilemanager.cpp index 264b8424d..01fb8cf40 100644 --- a/apps/openmw/mwworld/projectilemanager.cpp +++ b/apps/openmw/mwworld/projectilemanager.cpp @@ -262,7 +262,7 @@ namespace MWWorld lightDiffuseGreen += (static_cast(magicEffect->mData.mGreen) / 255.f); lightDiffuseBlue += (static_cast(magicEffect->mData.mBlue) / 255.f); } - int numberOfEffects = ((MagicBoltState&)state).mEffects.mList.size(); + int numberOfEffects = state.mEffects.mList.size(); lightDiffuseColor = osg::Vec4(lightDiffuseRed / numberOfEffects , lightDiffuseGreen / numberOfEffects , lightDiffuseBlue / numberOfEffects @@ -572,7 +572,7 @@ namespace MWWorld lightDiffuseGreen += (static_cast(magicEffect->mData.mGreen) / 255.f); lightDiffuseBlue += (static_cast(magicEffect->mData.mBlue) / 255.f); } - int numberOfEffects = ((MagicBoltState&)state).mEffects.mList.size(); + int numberOfEffects = state.mEffects.mList.size(); lightDiffuseColor = osg::Vec4(lightDiffuseRed / numberOfEffects , lightDiffuseGreen / numberOfEffects , lightDiffuseBlue / numberOfEffects From 9624d8aade018e5d617bac029273013378c930da Mon Sep 17 00:00:00 2001 From: mrohrlach Date: Fri, 9 Dec 2016 19:48:56 -0700 Subject: [PATCH 18/46] Added new method and variable to track float remainders of disintegration effections --- apps/openmw/mwmechanics/spellcasting.cpp | 6 ++++-- apps/openmw/mwworld/cellref.cpp | 19 +++++++++++++++++++ apps/openmw/mwworld/cellref.hpp | 1 + apps/openmw/mwworld/manualref.cpp | 1 + components/esm/cellref.cpp | 1 + components/esm/cellref.hpp | 1 + 6 files changed, 27 insertions(+), 2 deletions(-) diff --git a/apps/openmw/mwmechanics/spellcasting.cpp b/apps/openmw/mwmechanics/spellcasting.cpp index 72f0cddff..6b1707218 100644 --- a/apps/openmw/mwmechanics/spellcasting.cpp +++ b/apps/openmw/mwmechanics/spellcasting.cpp @@ -980,8 +980,10 @@ namespace MWMechanics if (charge == 0) return false; - // FIXME: charge should be a float, not int so that damage < 1 per frame can be applied. - // This was also a bug in the original engine. + // Store remainder of disintegrate amount (automatically subtracted if > 1) + item->getCellRef().applyChargeRemainderToBeSubtracted(disintegrate - std::floor(disintegrate)); + + charge = item->getClass().getItemHealth(*item); charge -= std::min(static_cast(disintegrate), charge); diff --git a/apps/openmw/mwworld/cellref.cpp b/apps/openmw/mwworld/cellref.cpp index 0d81e0636..9180e9e20 100644 --- a/apps/openmw/mwworld/cellref.cpp +++ b/apps/openmw/mwworld/cellref.cpp @@ -93,6 +93,25 @@ namespace MWWorld } } + void CellRef::applyChargeRemainderToBeSubtracted(float chargeRemainder) + { + mCellRef.mChargeIntRemainder += std::abs(chargeRemainder); + if (mCellRef.mChargeIntRemainder > 1.0f) + { + float newChargeRemainder = (mCellRef.mChargeIntRemainder - std::floor(mCellRef.mChargeIntRemainder)); + if (mCellRef.mChargeInt <= static_cast(mCellRef.mChargeIntRemainder)) + { + mCellRef.mChargeInt = 0; + } + else + { + mCellRef.mChargeInt -= static_cast(mCellRef.mChargeIntRemainder); + } + + mCellRef.mChargeIntRemainder = newChargeRemainder; + } + } + float CellRef::getChargeFloat() const { return mCellRef.mChargeFloat; diff --git a/apps/openmw/mwworld/cellref.hpp b/apps/openmw/mwworld/cellref.hpp index b8e85f286..c8c4529e9 100644 --- a/apps/openmw/mwworld/cellref.hpp +++ b/apps/openmw/mwworld/cellref.hpp @@ -65,6 +65,7 @@ namespace MWWorld float getChargeFloat() const; // Implemented as union with int charge void setCharge(int charge); void setChargeFloat(float charge); + void applyChargeRemainderToBeSubtracted(float chargeRemainder); // The NPC that owns this object (and will get angry if you steal it) std::string getOwner() const; diff --git a/apps/openmw/mwworld/manualref.cpp b/apps/openmw/mwworld/manualref.cpp index c683f7e03..48270d224 100644 --- a/apps/openmw/mwworld/manualref.cpp +++ b/apps/openmw/mwworld/manualref.cpp @@ -16,6 +16,7 @@ namespace cellRef.mScale = 1; cellRef.mFactionRank = 0; cellRef.mChargeInt = -1; + cellRef.mChargeIntRemainder = 0.0f; cellRef.mGoldValue = 1; cellRef.mEnchantmentCharge = -1; cellRef.mTeleport = false; diff --git a/components/esm/cellref.cpp b/components/esm/cellref.cpp index 74d45bb0c..e41201d6e 100644 --- a/components/esm/cellref.cpp +++ b/components/esm/cellref.cpp @@ -196,6 +196,7 @@ void ESM::CellRef::blank() mFaction.clear(); mFactionRank = -2; mChargeInt = -1; + mChargeIntRemainder = 0.0f; mEnchantmentCharge = -1; mGoldValue = 0; mDestCell.clear(); diff --git a/components/esm/cellref.hpp b/components/esm/cellref.hpp index 3c646cc61..a3c56cf13 100644 --- a/components/esm/cellref.hpp +++ b/components/esm/cellref.hpp @@ -69,6 +69,7 @@ namespace ESM int mChargeInt; // Used by everything except lights float mChargeFloat; // Used only by lights }; + float mChargeIntRemainder; // Used by everythign except lights (amount of charge not applied to mChargeInt) // Remaining enchantment charge. This could be -1 if the charge was not touched yet (i.e. full). float mEnchantmentCharge; From f0f78c9d644ace8e555bd15ebc1dc496f32b38e5 Mon Sep 17 00:00:00 2001 From: mrohrlach Date: Fri, 9 Dec 2016 19:55:26 -0700 Subject: [PATCH 19/46] Slight adjustments to disintegration fix --- apps/openmw/mwworld/cellref.cpp | 1 - apps/openmw/mwworld/cellref.hpp | 2 +- components/esm/cellref.hpp | 2 +- 3 files changed, 2 insertions(+), 3 deletions(-) diff --git a/apps/openmw/mwworld/cellref.cpp b/apps/openmw/mwworld/cellref.cpp index 9180e9e20..72ee56e6a 100644 --- a/apps/openmw/mwworld/cellref.cpp +++ b/apps/openmw/mwworld/cellref.cpp @@ -107,7 +107,6 @@ namespace MWWorld { mCellRef.mChargeInt -= static_cast(mCellRef.mChargeIntRemainder); } - mCellRef.mChargeIntRemainder = newChargeRemainder; } } diff --git a/apps/openmw/mwworld/cellref.hpp b/apps/openmw/mwworld/cellref.hpp index c8c4529e9..7e27e6ef3 100644 --- a/apps/openmw/mwworld/cellref.hpp +++ b/apps/openmw/mwworld/cellref.hpp @@ -65,7 +65,7 @@ namespace MWWorld float getChargeFloat() const; // Implemented as union with int charge void setCharge(int charge); void setChargeFloat(float charge); - void applyChargeRemainderToBeSubtracted(float chargeRemainder); + void applyChargeRemainderToBeSubtracted(float chargeRemainder); // Stores remainders and applies if > 1 // The NPC that owns this object (and will get angry if you steal it) std::string getOwner() const; diff --git a/components/esm/cellref.hpp b/components/esm/cellref.hpp index a3c56cf13..f14617531 100644 --- a/components/esm/cellref.hpp +++ b/components/esm/cellref.hpp @@ -69,7 +69,7 @@ namespace ESM int mChargeInt; // Used by everything except lights float mChargeFloat; // Used only by lights }; - float mChargeIntRemainder; // Used by everythign except lights (amount of charge not applied to mChargeInt) + float mChargeIntRemainder; // Stores amount of charge not subtracted from mChargeInt // Remaining enchantment charge. This could be -1 if the charge was not touched yet (i.e. full). float mEnchantmentCharge; From 8c97ac269d5c08b8b0efa432bc601d7758e52983 Mon Sep 17 00:00:00 2001 From: MiroslavR Date: Sat, 10 Dec 2016 22:22:41 +0100 Subject: [PATCH 20/46] Remove item shadows properly (Fixes #3652) --- apps/openmw/mwgui/itemwidget.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/apps/openmw/mwgui/itemwidget.cpp b/apps/openmw/mwgui/itemwidget.cpp index 87fca941e..fe7cb79de 100644 --- a/apps/openmw/mwgui/itemwidget.cpp +++ b/apps/openmw/mwgui/itemwidget.cpp @@ -101,6 +101,8 @@ namespace MWGui { if (mFrame) mFrame->setImageTexture(""); + if (mItemShadow) + mItemShadow->setImageTexture(""); mItem->setImageTexture(""); mText->setCaption(""); return; From 76ee5845ac17b11b82d34e4b43fb0348c062499a Mon Sep 17 00:00:00 2001 From: MiroslavR Date: Sun, 11 Dec 2016 19:35:53 +0100 Subject: [PATCH 21/46] Fix swish sound ID and play swish sound effects for all creatures (Fixes #3653) --- apps/openmw/mwmechanics/character.cpp | 24 +++++++++++++++++------- apps/openmw/mwmechanics/character.hpp | 2 ++ 2 files changed, 19 insertions(+), 7 deletions(-) diff --git a/apps/openmw/mwmechanics/character.cpp b/apps/openmw/mwmechanics/character.cpp index d9cae3a90..c771d9fcc 100644 --- a/apps/openmw/mwmechanics/character.cpp +++ b/apps/openmw/mwmechanics/character.cpp @@ -1049,6 +1049,9 @@ bool CharacterController::updateCreatureState() mUpperBodyState = UpperCharState_StartToMinAttack; mAttackStrength = std::min(1.f, 0.1f + Misc::Rng::rollClosedProbability()); + + if (weapType == WeapType_HandToHand) + playSwishSound(0.0f); } } @@ -1370,13 +1373,7 @@ bool CharacterController::updateWeaponState() } else { - std::string sound = "SwishM"; - if(attackStrength < 0.5f) - sndMgr->playSound3D(mPtr, sound, 1.0f, 0.8f); //Weak attack - else if(attackStrength < 1.0f) - sndMgr->playSound3D(mPtr, sound, 1.0f, 1.0f); //Medium attack - else - sndMgr->playSound3D(mPtr, sound, 1.0f, 1.2f); //Strong attack + playSwishSound(attackStrength); } } mAttackStrength = attackStrength; @@ -2271,6 +2268,19 @@ void CharacterController::setHeadTrackTarget(const MWWorld::ConstPtr &target) mHeadTrackTarget = target; } +void CharacterController::playSwishSound(float attackStrength) +{ + MWBase::SoundManager *sndMgr = MWBase::Environment::get().getSoundManager(); + + std::string sound = "Weapon Swish"; + if(attackStrength < 0.5f) + sndMgr->playSound3D(mPtr, sound, 1.0f, 0.8f); //Weak attack + else if(attackStrength < 1.0f) + sndMgr->playSound3D(mPtr, sound, 1.0f, 1.0f); //Medium attack + else + sndMgr->playSound3D(mPtr, sound, 1.0f, 1.2f); //Strong attack +} + void CharacterController::updateHeadTracking(float duration) { const osg::Node* head = mAnimation->getNode("Bip01 Head"); diff --git a/apps/openmw/mwmechanics/character.hpp b/apps/openmw/mwmechanics/character.hpp index 3a84f0f78..f393f0619 100644 --- a/apps/openmw/mwmechanics/character.hpp +++ b/apps/openmw/mwmechanics/character.hpp @@ -281,6 +281,8 @@ public: /// Make this character turn its head towards \a target. To turn off head tracking, pass an empty Ptr. void setHeadTrackTarget(const MWWorld::ConstPtr& target); + + void playSwishSound(float attackStrength); }; MWWorld::ContainerStoreIterator getActiveWeapon(CreatureStats &stats, MWWorld::InventoryStore &inv, WeaponType *weaptype); From 2d928fac3660835aa80e8c8dd63c352c7992a652 Mon Sep 17 00:00:00 2001 From: jeffreyhaines Date: Tue, 13 Dec 2016 10:46:16 -0500 Subject: [PATCH 22/46] Minor spelling correction --- docs/source/openmw-cs/tour.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/source/openmw-cs/tour.rst b/docs/source/openmw-cs/tour.rst index 3ddeac4fa..0533529e4 100644 --- a/docs/source/openmw-cs/tour.rst +++ b/docs/source/openmw-cs/tour.rst @@ -5,7 +5,7 @@ In this first chapter we will create a mod that adds a new ring with a simple enchantment to the game. The ring will give its wearer a permanent Night Vision effect while being worn. You don't need prior knowledge about modding Morrowind, but you should be familiar with the game itself. There will be no -scripting necessary, we chan achieve everything using just what the base game +scripting necessary, we can achieve everything using just what the base game offers out of the box. Before continuing make sure that OpenMW is properly installed and playable. From d95a66351040b6ef68003d1534350517e4500eaa Mon Sep 17 00:00:00 2001 From: jeffreyhaines Date: Tue, 13 Dec 2016 11:11:21 -0500 Subject: [PATCH 23/46] Minor grammar and sentence changes --- docs/source/openmw-cs/tour.rst | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/docs/source/openmw-cs/tour.rst b/docs/source/openmw-cs/tour.rst index 3ddeac4fa..dee0ba3a9 100644 --- a/docs/source/openmw-cs/tour.rst +++ b/docs/source/openmw-cs/tour.rst @@ -3,8 +3,8 @@ A Tour through OpenMW CS: making a magic ring In this first chapter we will create a mod that adds a new ring with a simple enchantment to the game. The ring will give its wearer a permanent Night Vision -effect while being worn. You don't need prior knowledge about modding -Morrowind, but you should be familiar with the game itself. There will be no +effect while being worn. You do not need prior Morrowind modding experience, +but you should be familiar with the game itself. There will be no scripting necessary, we chan achieve everything using just what the base game offers out of the box. Before continuing make sure that OpenMW is properly installed and playable. @@ -13,7 +13,7 @@ installed and playable. Adding the ring to the game's records ************************************* -In this first section we will define what our new ring is, what it looks like +In this first section we will define what our new ring is, what it looks like, and what it does. Getting it to work is the first step before we go further. @@ -28,11 +28,11 @@ options: create a new game, create a new addon, edit a content file. :alt: Opening dialogue with three option and setting button (the wrench) The first option is for creating an entirely new game, that's not what we want. -We want to edit an existing game, so choose the second one. When you save your +We want to edit an existing game, so choose the second option. When you save your addon you can use the third option to open it again. -You will be presented with another window where you get to chose the content to -edit and the name of your project. We have to chose at least a base game, and +You will be presented with another window where you get to choose the content to +edit and the name of your project. Then we have to select at least the base game, and optionally a number of other addons we want to depend on. The name of the project is arbitrary, it will be used to identify the addon later in the OpenMW launcher. @@ -41,7 +41,7 @@ launcher. :alt: Creation dialogue for a new project, pick content modules and name Choose Morrowind as your content file and enter `Ring of Night Vision` as the -name. We could also chose further content files as dependencies if we wanted +name. We could also choose further content files as dependencies if we wanted to, but for this mod the base game is enough. Once the addon has been created you will be presented with a table. If you see @@ -58,7 +58,7 @@ detached panel can be re-attached to a window by dragging it by the title bar on top of the window. Now let's look at the panel itself: we have a filter text field, a very large -table and a status bar. The filter will be very useful when we want to find an +table, and a status bar. The filter will be very useful when we want to find an entry in the table, but for now it is irrelevant. The table you are looking at contains all objects in the game, these can be items, NPCs, creatures, whatever. Every object is an entry in that table, visible as a row. The columns @@ -95,7 +95,7 @@ holding Shift to edit it (this is a configurable shortcut), but there is a better way: right-click the row of our new record and chose *Edit Record*, a new panel will open. -We can right-click the row of our new record and chose *Edit Record*, a +We can right-click the row of our new record and choose *Edit Record*, a new panel will open. Alternatively we can also define a configurable shortcut instead of using the context menu; the default is double-clicking while holding down the shift key. From 2fe2b57faa7144d6a63e36a3c76856cc97f83909 Mon Sep 17 00:00:00 2001 From: jeffreyhaines Date: Tue, 13 Dec 2016 13:27:43 -0500 Subject: [PATCH 24/46] Replaced choose with select --- docs/source/openmw-cs/tour.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/source/openmw-cs/tour.rst b/docs/source/openmw-cs/tour.rst index dee0ba3a9..3dd627aa1 100644 --- a/docs/source/openmw-cs/tour.rst +++ b/docs/source/openmw-cs/tour.rst @@ -95,7 +95,7 @@ holding Shift to edit it (this is a configurable shortcut), but there is a better way: right-click the row of our new record and chose *Edit Record*, a new panel will open. -We can right-click the row of our new record and choose *Edit Record*, a +We can right-click the row of our new record and select *Edit Record*, a new panel will open. Alternatively we can also define a configurable shortcut instead of using the context menu; the default is double-clicking while holding down the shift key. From 6fadcc674848c85dd64acf667b9fa07ccc5e33b5 Mon Sep 17 00:00:00 2001 From: jeffreyhaines Date: Tue, 13 Dec 2016 13:29:22 -0500 Subject: [PATCH 25/46] Replaced "prior" with "previous" --- docs/source/openmw-cs/tour.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/source/openmw-cs/tour.rst b/docs/source/openmw-cs/tour.rst index 3dd627aa1..f1c72a65d 100644 --- a/docs/source/openmw-cs/tour.rst +++ b/docs/source/openmw-cs/tour.rst @@ -3,7 +3,7 @@ A Tour through OpenMW CS: making a magic ring In this first chapter we will create a mod that adds a new ring with a simple enchantment to the game. The ring will give its wearer a permanent Night Vision -effect while being worn. You do not need prior Morrowind modding experience, +effect while being worn. You do not need previous Morrowind modding experience, but you should be familiar with the game itself. There will be no scripting necessary, we chan achieve everything using just what the base game offers out of the box. Before continuing make sure that OpenMW is properly From 829f6848990312ab004cc0430d8065bcf3740328 Mon Sep 17 00:00:00 2001 From: jeffreyhaines Date: Tue, 13 Dec 2016 15:39:30 -0500 Subject: [PATCH 26/46] Removed Oxford comma --- docs/source/openmw-cs/tour.rst | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/docs/source/openmw-cs/tour.rst b/docs/source/openmw-cs/tour.rst index f1c72a65d..608a6c1ab 100644 --- a/docs/source/openmw-cs/tour.rst +++ b/docs/source/openmw-cs/tour.rst @@ -32,7 +32,7 @@ We want to edit an existing game, so choose the second option. When you save you addon you can use the third option to open it again. You will be presented with another window where you get to choose the content to -edit and the name of your project. Then we have to select at least the base game, and +edit and the name of your project. Then we have to select at least the base game and optionally a number of other addons we want to depend on. The name of the project is arbitrary, it will be used to identify the addon later in the OpenMW launcher. @@ -58,7 +58,7 @@ detached panel can be re-attached to a window by dragging it by the title bar on top of the window. Now let's look at the panel itself: we have a filter text field, a very large -table, and a status bar. The filter will be very useful when we want to find an +table and a status bar. The filter will be very useful when we want to find an entry in the table, but for now it is irrelevant. The table you are looking at contains all objects in the game, these can be items, NPCs, creatures, whatever. Every object is an entry in that table, visible as a row. The columns @@ -67,7 +67,7 @@ of the table are the attributes of each object. Morrowind uses something called a *relational database* for game data. If you are not familiar with the term, it means that every type of thing can be expressed as a *table*: there is a table for objects, a table for enchantments, -a table for icons, one for meshes, and so on. Properties of an entry must be +a table for icons, one for meshes and so on. Properties of an entry must be simple values, like numbers or text strings. If we want a more complicated property we need to reference an entry from another table. There are a few exceptions to this though, some tables do have subtables. The effects of From 71e74f5a931c57d5a305521bb8648c6426f25c5a Mon Sep 17 00:00:00 2001 From: mrohrlach Date: Tue, 13 Dec 2016 18:04:20 -0700 Subject: [PATCH 27/46] Moved projectile light calculation to separate method --- apps/openmw/mwworld/projectilemanager.cpp | 71 +++++++++-------------- 1 file changed, 29 insertions(+), 42 deletions(-) diff --git a/apps/openmw/mwworld/projectilemanager.cpp b/apps/openmw/mwworld/projectilemanager.cpp index 01fb8cf40..4d342336d 100644 --- a/apps/openmw/mwworld/projectilemanager.cpp +++ b/apps/openmw/mwworld/projectilemanager.cpp @@ -93,6 +93,31 @@ namespace } return projectileEffects; } + + osg::Vec4 getMagicBoltLightDiffuseColor(const ESM::EffectList& effects) + { + // Calculate combined light diffuse color from magical effects + osg::Vec4 lightDiffuseColor; + float lightDiffuseRed = 0.0f; + float lightDiffuseGreen = 0.0f; + float lightDiffuseBlue = 0.0f; + for (std::vector::const_iterator iter(effects.mList.begin()); + iter != effects.mList.end(); ++iter) + { + const ESM::MagicEffect *magicEffect = MWBase::Environment::get().getWorld()->getStore().get().find( + iter->mEffectID); + lightDiffuseRed += (static_cast(magicEffect->mData.mRed) / 255.f); + lightDiffuseGreen += (static_cast(magicEffect->mData.mGreen) / 255.f); + lightDiffuseBlue += (static_cast(magicEffect->mData.mBlue) / 255.f); + } + int numberOfEffects = effects.mList.size(); + lightDiffuseColor = osg::Vec4(lightDiffuseRed / numberOfEffects + , lightDiffuseGreen / numberOfEffects + , lightDiffuseBlue / numberOfEffects + , 1.0f); + + return lightDiffuseColor; + } } namespace MWWorld @@ -249,25 +274,7 @@ namespace MWWorld MWWorld::ManualRef ref(MWBase::Environment::get().getWorld()->getStore(), state.mIdMagic.at(0)); MWWorld::Ptr ptr = ref.getPtr(); - // Calculate combined light color from magical effects - osg::Vec4 lightDiffuseColor; - float lightDiffuseRed = 0.0f; - float lightDiffuseGreen = 0.0f; - float lightDiffuseBlue = 0.0f; - for (std::vector::const_iterator it = state.mEffects.mList.begin(); it != state.mEffects.mList.end(); ++it) - { - const ESM::MagicEffect* magicEffect = MWBase::Environment::get().getWorld()->getStore().get().find( - it->mEffectID); - lightDiffuseRed += (static_cast(magicEffect->mData.mRed) / 255.f); - lightDiffuseGreen += (static_cast(magicEffect->mData.mGreen) / 255.f); - lightDiffuseBlue += (static_cast(magicEffect->mData.mBlue) / 255.f); - } - int numberOfEffects = state.mEffects.mList.size(); - lightDiffuseColor = osg::Vec4(lightDiffuseRed / numberOfEffects - , lightDiffuseGreen / numberOfEffects - , lightDiffuseBlue / numberOfEffects - , 1.0f); - + osg::Vec4 lightDiffuseColor = getMagicBoltLightDiffuseColor(effects); createModel(state, ptr.getClass().getModel(ptr), pos, orient, true, true, lightDiffuseColor, texture); MWBase::SoundManager *sndMgr = MWBase::Environment::get().getSoundManager(); @@ -292,8 +299,7 @@ namespace MWWorld MWWorld::ManualRef ref(MWBase::Environment::get().getWorld()->getStore(), projectile.getCellRef().getRefId()); MWWorld::Ptr ptr = ref.getPtr(); - osg::Vec4 lightDiffuseColor = osg::Vec4(0.814f, 0.682f, 0.652f, 1.0f); - createModel(state, ptr.getClass().getModel(ptr), pos, orient, false, false, lightDiffuseColor); + createModel(state, ptr.getClass().getModel(ptr), pos, orient, false, false, osg::Vec4(0,0,0,0)); mProjectiles.push_back(state); } @@ -523,8 +529,7 @@ namespace MWWorld return true; } - osg::Vec4 lightDiffuseColor = osg::Vec4(0.814f, 0.682f, 0.652f, 1.0f); - createModel(state, model, osg::Vec3f(esm.mPosition), osg::Quat(esm.mOrientation), false, false, lightDiffuseColor); + createModel(state, model, osg::Vec3f(esm.mPosition), osg::Quat(esm.mOrientation), false, false, osg::Vec4(0,0,0,0)); mProjectiles.push_back(state); return true; @@ -559,25 +564,7 @@ namespace MWWorld return true; } - // Calculate combined light color from magical effects - osg::Vec4 lightDiffuseColor; - float lightDiffuseRed = 0.0f; - float lightDiffuseGreen = 0.0f; - float lightDiffuseBlue = 0.0f; - for (std::vector::const_iterator it = state.mEffects.mList.begin(); it != state.mEffects.mList.end(); ++it) - { - const ESM::MagicEffect* magicEffect = MWBase::Environment::get().getWorld()->getStore().get().find( - it->mEffectID); - lightDiffuseRed += (static_cast(magicEffect->mData.mRed) / 255.f); - lightDiffuseGreen += (static_cast(magicEffect->mData.mGreen) / 255.f); - lightDiffuseBlue += (static_cast(magicEffect->mData.mBlue) / 255.f); - } - int numberOfEffects = state.mEffects.mList.size(); - lightDiffuseColor = osg::Vec4(lightDiffuseRed / numberOfEffects - , lightDiffuseGreen / numberOfEffects - , lightDiffuseBlue / numberOfEffects - , 1.0f); - + osg::Vec4 lightDiffuseColor = getMagicBoltLightDiffuseColor(esm.mEffects); createModel(state, model, osg::Vec3f(esm.mPosition), osg::Quat(esm.mOrientation), true, true, lightDiffuseColor, texture); MWBase::SoundManager *sndMgr = MWBase::Environment::get().getSoundManager(); From c7b4b2cdd776e8626f9db9779ff0fec4f71fccb2 Mon Sep 17 00:00:00 2001 From: Leon Krieg Date: Wed, 14 Dec 2016 16:39:33 +0100 Subject: [PATCH 28/46] Fixed multiple spelling mistakes --- apps/essimporter/importscri.hpp | 2 +- apps/opencs/model/prefs/shortcut.hpp | 2 +- apps/opencs/model/tools/referenceablecheck.cpp | 4 ++-- apps/opencs/model/world/idtree.cpp | 6 +++--- apps/opencs/view/render/cellwater.cpp | 2 +- apps/opencs/view/render/pagedworldspacewidget.cpp | 2 +- apps/opencs/view/render/scenewidget.cpp | 2 +- apps/opencs/view/world/regionmap.hpp | 4 ++-- apps/openmw/mwbase/windowmanager.hpp | 2 +- apps/openmw/mwdialogue/dialoguemanagerimp.cpp | 2 +- apps/openmw/mwmechanics/aifollow.cpp | 2 +- apps/openmw/mwmechanics/mechanicsmanagerimp.cpp | 2 +- apps/openmw/mwmechanics/obstacle.hpp | 2 +- apps/openmw/mwmechanics/spellcasting.cpp | 2 +- apps/openmw/mwrender/animation.hpp | 2 +- apps/openmw/mwworld/weather.cpp | 2 +- apps/wizard/inisettings.cpp | 4 ++-- 17 files changed, 22 insertions(+), 22 deletions(-) diff --git a/apps/essimporter/importscri.hpp b/apps/essimporter/importscri.hpp index 5123f84aa..fe68e5051 100644 --- a/apps/essimporter/importscri.hpp +++ b/apps/essimporter/importscri.hpp @@ -13,7 +13,7 @@ namespace ESM namespace ESSImport { - /// Local variable assigments for a running script + /// Local variable assignments for a running script struct SCRI { std::string mScript; diff --git a/apps/opencs/model/prefs/shortcut.hpp b/apps/opencs/model/prefs/shortcut.hpp index 7a90a1d08..4fa6f8a1a 100644 --- a/apps/opencs/model/prefs/shortcut.hpp +++ b/apps/opencs/model/prefs/shortcut.hpp @@ -29,7 +29,7 @@ namespace CSMPrefs enum SecondaryMode { SM_Replace, ///< The secondary signal replaces the regular signal when the modifier is active - SM_Detach, ///< The secondary signal is emitted independant of the regular signal, even if not active + SM_Detach, ///< The secondary signal is emitted independent of the regular signal, even if not active SM_Ignore ///< The secondary signal will not ever be emitted }; diff --git a/apps/opencs/model/tools/referenceablecheck.cpp b/apps/opencs/model/tools/referenceablecheck.cpp index ce78e52b2..a360ed104 100644 --- a/apps/opencs/model/tools/referenceablecheck.cpp +++ b/apps/opencs/model/tools/referenceablecheck.cpp @@ -659,7 +659,7 @@ void CSMTools::ReferenceableCheckStage::npcCheck ( { if ((npc.mFlags & ESM::NPC::Autocalc) == 0) //0x0010 = autocalculated flag { - messages.push_back (std::make_pair (id, npc.mId + " mNpdtType or flags mismatch!")); //should not happend? + messages.push_back (std::make_pair (id, npc.mId + " mNpdtType or flags mismatch!")); //should not happen? return; } @@ -915,7 +915,7 @@ void CSMTools::ReferenceableCheckStage::inventoryListCheck( id + " contains non-existing item (" + itemName + ")")); else { - // Needs to accomodate Containers, Creatures, and NPCs + // Needs to accommodate containers, creatures, and NPCs switch (localIndex.second) { case CSMWorld::UniversalId::Type_Potion: diff --git a/apps/opencs/model/world/idtree.cpp b/apps/opencs/model/world/idtree.cpp index 7c4551a90..7f43a9201 100644 --- a/apps/opencs/model/world/idtree.cpp +++ b/apps/opencs/model/world/idtree.cpp @@ -198,12 +198,12 @@ QModelIndex CSMWorld::IdTree::parent (const QModelIndex& index) const return QModelIndex(); unsigned int id = index.internalId(); - const std::pair& adress(unfoldIndexAddress(id)); + const std::pair& address(unfoldIndexAddress(id)); - if (adress.first >= this->rowCount() || adress.second >= this->columnCount()) + if (address.first >= this->rowCount() || address.second >= this->columnCount()) throw "Parent index is not present in the model"; - return createIndex(adress.first, adress.second); + return createIndex(address.first, address.second); } unsigned int CSMWorld::IdTree::foldIndexAddress (const QModelIndex& index) const diff --git a/apps/opencs/view/render/cellwater.cpp b/apps/opencs/view/render/cellwater.cpp index b8975da49..15ea15cc4 100644 --- a/apps/opencs/view/render/cellwater.cpp +++ b/apps/opencs/view/render/cellwater.cpp @@ -50,7 +50,7 @@ namespace CSVRender updateCellData(mData.getCells().getRecord(cellIndex)); } - // Keep water existance/height up to date + // Keep water existence/height up to date QAbstractItemModel* cells = mData.getTableModel(CSMWorld::UniversalId::Type_Cells); connect(cells, SIGNAL(dataChanged(const QModelIndex&, const QModelIndex&)), this, SLOT(cellDataChanged(const QModelIndex&, const QModelIndex&))); diff --git a/apps/opencs/view/render/pagedworldspacewidget.cpp b/apps/opencs/view/render/pagedworldspacewidget.cpp index 261144f8f..901dadc85 100644 --- a/apps/opencs/view/render/pagedworldspacewidget.cpp +++ b/apps/opencs/view/render/pagedworldspacewidget.cpp @@ -516,7 +516,7 @@ void CSVRender::PagedWorldspaceWidget::useViewHint (const std::string& hint) // Current coordinate int x, y; - // Loop throught all the coordinates to add them to selection + // Loop through all the coordinates to add them to selection while (stream >> ignore1 >> ignore2 >> x >> y) selection.add (CSMWorld::CellCoordinates (x, y)); diff --git a/apps/opencs/view/render/scenewidget.cpp b/apps/opencs/view/render/scenewidget.cpp index 4655ee957..e5b61f5d3 100644 --- a/apps/opencs/view/render/scenewidget.cpp +++ b/apps/opencs/view/render/scenewidget.cpp @@ -214,7 +214,7 @@ SceneWidget::SceneWidget(boost::shared_ptr resourceSys SceneWidget::~SceneWidget() { - // Since we're holding on to the scene templates past the existance of this graphics context, we'll need to manually release the created objects + // Since we're holding on to the scene templates past the existence of this graphics context, we'll need to manually release the created objects mResourceSystem->getSceneManager()->releaseGLObjects(mView->getCamera()->getGraphicsContext()->getState()); } diff --git a/apps/opencs/view/world/regionmap.hpp b/apps/opencs/view/world/regionmap.hpp index 0097a16dc..ba773224f 100644 --- a/apps/opencs/view/world/regionmap.hpp +++ b/apps/opencs/view/world/regionmap.hpp @@ -45,8 +45,8 @@ namespace CSVWorld ///< \note Non-existent cells are not listed. QModelIndexList getSelectedCells (bool existent = true, bool nonExistent = false) const; - ///< \param existant Include existant cells. - /// \param nonExistant Include non-existant cells. + ///< \param existent Include existent cells. + /// \param nonExistent Include non-existent cells. QModelIndexList getMissingRegionCells() const; ///< Unselected cells within all regions that have at least one selected cell. diff --git a/apps/openmw/mwbase/windowmanager.hpp b/apps/openmw/mwbase/windowmanager.hpp index 77d740b6f..3a53c3253 100644 --- a/apps/openmw/mwbase/windowmanager.hpp +++ b/apps/openmw/mwbase/windowmanager.hpp @@ -233,7 +233,7 @@ namespace MWBase virtual void removeDialog(MWGui::Layout* dialog) = 0; ///Gracefully attempts to exit the topmost GUI mode - /** No guarentee of actually closing the window **/ + /** No guarantee of actually closing the window **/ virtual void exitCurrentGuiMode() = 0; virtual void messageBox (const std::string& message, enum MWGui::ShowInDialogueMode showInDialogueMode = MWGui::ShowInDialogueMode_IfPossible) = 0; diff --git a/apps/openmw/mwdialogue/dialoguemanagerimp.cpp b/apps/openmw/mwdialogue/dialoguemanagerimp.cpp index ee6e24938..3102354a6 100644 --- a/apps/openmw/mwdialogue/dialoguemanagerimp.cpp +++ b/apps/openmw/mwdialogue/dialoguemanagerimp.cpp @@ -174,7 +174,7 @@ namespace MWDialogue executeScript (info->mResultScript); mLastTopic = Misc::StringUtils::lowerCase(it->mId); - // update topics again to accomodate changes resulting from executeScript + // update topics again to accommodate changes resulting from executeScript updateTopics(); return; diff --git a/apps/openmw/mwmechanics/aifollow.cpp b/apps/openmw/mwmechanics/aifollow.cpp index c563ba37a..fb080d046 100644 --- a/apps/openmw/mwmechanics/aifollow.cpp +++ b/apps/openmw/mwmechanics/aifollow.cpp @@ -152,7 +152,7 @@ bool AiFollow::execute (const MWWorld::Ptr& actor, CharacterController& characte if (dist > 450) actor.getClass().getCreatureStats(actor).setMovementFlag(MWMechanics::CreatureStats::Flag_Run, true); //Make NPC run - else if (dist < 325) //Have a bit of a dead zone, otherwise npc will constantly flip between running and not when right on the edge of the running threshhold + else if (dist < 325) //Have a bit of a dead zone, otherwise npc will constantly flip between running and not when right on the edge of the running threshold actor.getClass().getCreatureStats(actor).setMovementFlag(MWMechanics::CreatureStats::Flag_Run, false); //make NPC walk } diff --git a/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp b/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp index 958869964..97fa98b3b 100644 --- a/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp +++ b/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp @@ -236,7 +236,7 @@ namespace MWMechanics : mWatchedTimeToStartDrowning(0), mWatchedStatsEmpty (true), mUpdatePlayer (true), mClassSelected (false), mRaceSelected (false), mAI(true) { - //buildPlayer no longer here, needs to be done explicitely after all subsystems are up and running + //buildPlayer no longer here, needs to be done explicitly after all subsystems are up and running } void MechanicsManager::add(const MWWorld::Ptr& ptr) diff --git a/apps/openmw/mwmechanics/obstacle.hpp b/apps/openmw/mwmechanics/obstacle.hpp index d2e1cfc2e..1d7cf1e0e 100644 --- a/apps/openmw/mwmechanics/obstacle.hpp +++ b/apps/openmw/mwmechanics/obstacle.hpp @@ -19,7 +19,7 @@ namespace MWMechanics bool proximityToDoor(const MWWorld::Ptr& actor, float minSqr = MIN_DIST_TO_DOOR_SQUARED); - /// Returns door pointer within range. No guarentee is given as too which one + /// Returns door pointer within range. No guarantee is given as to which one /** \return Pointer to the door, or NULL if none exists **/ MWWorld::Ptr getNearbyDoor(const MWWorld::Ptr& actor, float minSqr = MIN_DIST_TO_DOOR_SQUARED); diff --git a/apps/openmw/mwmechanics/spellcasting.cpp b/apps/openmw/mwmechanics/spellcasting.cpp index 6b1707218..43d77b99d 100644 --- a/apps/openmw/mwmechanics/spellcasting.cpp +++ b/apps/openmw/mwmechanics/spellcasting.cpp @@ -491,7 +491,7 @@ namespace MWMechanics appliedLastingEffects.push_back(effect); // For absorb effects, also apply the effect to the caster - but with a negative - // magnitude, since we're transfering stats from the target to the caster + // magnitude, since we're transferring stats from the target to the caster if (!caster.isEmpty() && caster.getClass().isActor()) { for (int i=0; i<5; ++i) diff --git a/apps/openmw/mwrender/animation.hpp b/apps/openmw/mwrender/animation.hpp index b99464014..584eca614 100644 --- a/apps/openmw/mwrender/animation.hpp +++ b/apps/openmw/mwrender/animation.hpp @@ -302,7 +302,7 @@ protected: /** Sets the root model of the object. * - * Note that you must make sure all animation sources are cleared before reseting the object + * Note that you must make sure all animation sources are cleared before resetting the object * root. All nodes previously retrieved with getNode will also become invalidated. * @param forceskeleton Wrap the object root in a Skeleton, even if it contains no skinned parts. Use this if you intend to add skinned parts manually. * @param baseonly If true, then any meshes or particle systems in the model are ignored diff --git a/apps/openmw/mwworld/weather.cpp b/apps/openmw/mwworld/weather.cpp index 7111edd7d..48ab1187f 100644 --- a/apps/openmw/mwworld/weather.cpp +++ b/apps/openmw/mwworld/weather.cpp @@ -1069,7 +1069,7 @@ inline void WeatherManager::calculateResult(const int weatherID, const float gam mResult.mSunDiscColor = lerp(osg::Vec4f(1,1,1,1), current.mSunDiscSunsetColor, factor); // The SunDiscSunsetColor in the INI isn't exactly the resulting color on screen, most likely because // MW applied the color to the ambient term as well. After the ambient and emissive terms are added together, the fixed pipeline - // would then clamp the total lighting to (1,1,1). A noticable change in color tone can be observed when only one of the color components gets clamped. + // would then clamp the total lighting to (1,1,1). A noticeable change in color tone can be observed when only one of the color components gets clamped. // Unfortunately that means we can't use the INI color as is, have to replicate the above nonsense. mResult.mSunDiscColor = mResult.mSunDiscColor + osg::componentMultiply(mResult.mSunDiscColor, mResult.mAmbientColor); for (int i=0; i<3; ++i) diff --git a/apps/wizard/inisettings.cpp b/apps/wizard/inisettings.cpp index 3711ba066..2367f5c4d 100644 --- a/apps/wizard/inisettings.cpp +++ b/apps/wizard/inisettings.cpp @@ -198,8 +198,8 @@ bool Wizard::IniSettings::parseInx(const QString &path) const QString section(array.left(index)); // Figure how many characters to read for the key - int lenght = array.indexOf("\x06", section.length() + 3) - (section.length() + 3); - const QString key(array.mid(section.length() + 3, lenght)); + int length = array.indexOf("\x06", section.length() + 3) - (section.length() + 3); + const QString key(array.mid(section.length() + 3, length)); QString value(array.mid(section.length() + key.length() + 6)); From 2eb6ef50ca614cc77f20169b2e1ef89d6e8f5932 Mon Sep 17 00:00:00 2001 From: scrawl Date: Wed, 14 Dec 2016 20:03:42 +0100 Subject: [PATCH 29/46] Revert "[OS X] Reenable CI" This reverts commit c99d9a47e8725f907e589a9b1a6cfbda6a8ede87. --- .travis.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index 574fe1ba8..4f811ee0f 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,6 +1,6 @@ os: - linux - - osx +# - osx osx_image: xcode7.2 language: cpp sudo: required From e30dfb13d3bb1771ebd5b963e1d07fa6ee27a503 Mon Sep 17 00:00:00 2001 From: Aussiemon Date: Wed, 14 Dec 2016 19:05:30 -0700 Subject: [PATCH 30/46] Added check before attempting to remove actor's collision object from world --- apps/openmw/mwphysics/actor.cpp | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/apps/openmw/mwphysics/actor.cpp b/apps/openmw/mwphysics/actor.cpp index 61022da28..dacffe22c 100644 --- a/apps/openmw/mwphysics/actor.cpp +++ b/apps/openmw/mwphysics/actor.cpp @@ -72,7 +72,10 @@ void Actor::enableCollisionBody(bool collision) void Actor::updateCollisionMask() { - mCollisionWorld->removeCollisionObject(mCollisionObject.get()); + if (mCollisionObject.get()->getWorldArrayIndex() >= 0) + { + mCollisionWorld->removeCollisionObject(mCollisionObject.get()); + } int collisionMask = CollisionType_World | CollisionType_HeightMap; if (mExternalCollisionMode) collisionMask |= CollisionType_Actor | CollisionType_Projectile | CollisionType_Door; From 7c2a088b34cf9acff43586d1c6d303f57bb82927 Mon Sep 17 00:00:00 2001 From: Aussiemon Date: Wed, 14 Dec 2016 20:13:23 -0700 Subject: [PATCH 31/46] Added check before removing water collision object from world --- apps/openmw/mwphysics/physicssystem.cpp | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/apps/openmw/mwphysics/physicssystem.cpp b/apps/openmw/mwphysics/physicssystem.cpp index 1a97fc6ff..1985dba18 100644 --- a/apps/openmw/mwphysics/physicssystem.cpp +++ b/apps/openmw/mwphysics/physicssystem.cpp @@ -1463,7 +1463,10 @@ namespace MWPhysics { if (mWaterCollisionObject.get()) { - mCollisionWorld->removeCollisionObject(mWaterCollisionObject.get()); + if (mWaterCollisionObject.get()->getWorldArrayIndex() >= 0) + { + mCollisionWorld->removeCollisionObject(mWaterCollisionObject.get()); + } } if (!mWaterEnabled) From 369272fc702f41bc725f2d875c7d17a496a7bbfd Mon Sep 17 00:00:00 2001 From: Aussiemon Date: Wed, 14 Dec 2016 21:08:20 -0700 Subject: [PATCH 32/46] Handle SDL event 0x302 by doing nothing --- components/sdlutil/sdlinputwrapper.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/components/sdlutil/sdlinputwrapper.cpp b/components/sdlutil/sdlinputwrapper.cpp index 647a65005..6482f378e 100644 --- a/components/sdlutil/sdlinputwrapper.cpp +++ b/components/sdlutil/sdlinputwrapper.cpp @@ -102,6 +102,8 @@ InputWrapper::InputWrapper(SDL_Window* window, osg::ref_ptr v if (evt.key.keysym.sym == SDLK_F3) mViewer->getEventQueue()->keyRelease(osgGA::GUIEventAdapter::KEY_F3); + break; + case SDL_TEXTEDITING: break; case SDL_TEXTINPUT: mKeyboardListener->textInput(evt.text); From 739cd5ba453f26a05ae8a8be9d677e387df19c66 Mon Sep 17 00:00:00 2001 From: Leon Krieg Date: Wed, 14 Dec 2016 22:11:22 +0100 Subject: [PATCH 33/46] Fixed more spelling mistakes --- apps/opencs/model/tools/referenceablecheck.cpp | 2 +- apps/opencs/model/world/idtable.hpp | 2 +- apps/opencs/model/world/idtree.hpp | 4 ++-- apps/opencs/model/world/refidadapter.hpp | 2 +- apps/openmw/doc.hpp | 2 +- apps/openmw/mwclass/door.cpp | 2 +- apps/openmw/mwclass/potion.cpp | 2 +- apps/openmw/mwmechanics/aicombat.cpp | 2 +- apps/openmw/mwmechanics/aipackage.hpp | 2 +- apps/openmw/mwmechanics/aiwander.cpp | 12 ++++++------ apps/openmw/mwmechanics/aiwander.hpp | 2 +- apps/openmw/mwmechanics/pathfinding.cpp | 12 ++++++------ apps/openmw/mwmechanics/pathfinding.hpp | 8 ++++---- apps/openmw/mwmechanics/pathgrid.cpp | 6 +++--- apps/openmw/mwmechanics/pathgrid.hpp | 2 +- apps/openmw/mwphysics/physicssystem.hpp | 2 +- apps/openmw/mwrender/sky.hpp | 2 +- apps/openmw/mwscript/compilercontext.hpp | 2 +- files/settings-default.cfg | 4 ++-- 19 files changed, 36 insertions(+), 36 deletions(-) diff --git a/apps/opencs/model/tools/referenceablecheck.cpp b/apps/opencs/model/tools/referenceablecheck.cpp index a360ed104..4dd3e1edf 100644 --- a/apps/opencs/model/tools/referenceablecheck.cpp +++ b/apps/opencs/model/tools/referenceablecheck.cpp @@ -425,7 +425,7 @@ void CSMTools::ReferenceableCheckStage::creatureCheck ( //stats checks if (creature.mData.mLevel < 1) - messages.push_back (std::make_pair (id, creature.mId + " has non-postive level")); + messages.push_back (std::make_pair (id, creature.mId + " has non-positive level")); if (creature.mData.mStrength < 0) messages.push_back (std::make_pair (id, creature.mId + " has negative strength")); diff --git a/apps/opencs/model/world/idtable.hpp b/apps/opencs/model/world/idtable.hpp index 8c2f8a46d..9faf64d71 100644 --- a/apps/opencs/model/world/idtable.hpp +++ b/apps/opencs/model/world/idtable.hpp @@ -65,7 +65,7 @@ namespace CSMWorld void setRecord (const std::string& id, const RecordBase& record, UniversalId::Type type = UniversalId::Type_None); - ///< Add record or overwrite existing recrod. + ///< Add record or overwrite existing record. const RecordBase& getRecord (const std::string& id) const; diff --git a/apps/opencs/model/world/idtree.hpp b/apps/opencs/model/world/idtree.hpp index 79e93fc3d..1539bd4a2 100644 --- a/apps/opencs/model/world/idtree.hpp +++ b/apps/opencs/model/world/idtree.hpp @@ -8,9 +8,9 @@ /*! \brief * Class for holding the model. Uses typical qt table abstraction/interface for granting access * to the individiual fields of the records, Some records are holding nested data (for instance - * inventory list of the npc). In casses like this, table model offers interface to access + * inventory list of the npc). In cases like this, table model offers interface to access * nested data in the qt way - that is specify parent. Since some of those nested data require - * multiple columns to represent informations, single int (default way to index model in the + * multiple columns to represent information, single int (default way to index model in the * qmodelindex) is not sufficiant. Therefore tablemodelindex class can hold two ints for the * sake of indexing two dimensions of the table. This model does not support multiple levels of * the nested data. Vast majority of methods makes sense only for the top level data. diff --git a/apps/opencs/model/world/refidadapter.hpp b/apps/opencs/model/world/refidadapter.hpp index ba9da577d..116adb69a 100644 --- a/apps/opencs/model/world/refidadapter.hpp +++ b/apps/opencs/model/world/refidadapter.hpp @@ -8,7 +8,7 @@ * Adapters acts as indirection layer, abstracting details of the record types (in the wrappers) from the higher levels of model. * Please notice that nested adaptor uses helper classes for actually performing any actions. Different record types require different helpers (needs to be created in the subclass and then fetched via member function). * - * Important point: don't forget to make sure that getData on the nestedColumn returns true (otherwise code will not treat the index pointing to the column as having childs! + * Important point: don't forget to make sure that getData on the nestedColumn returns true (otherwise code will not treat the index pointing to the column as having children! */ class QVariant; diff --git a/apps/openmw/doc.hpp b/apps/openmw/doc.hpp index ffeef94e1..5f9065013 100644 --- a/apps/openmw/doc.hpp +++ b/apps/openmw/doc.hpp @@ -41,4 +41,4 @@ /// \namespace MWScript /// \ingroup openmw -/// \brief MW-specific script extentions and integration of the script system into OpenMW +/// \brief MW-specific script extensions and integration of the script system into OpenMW diff --git a/apps/openmw/mwclass/door.cpp b/apps/openmw/mwclass/door.cpp index 7494d2b43..830ba258b 100644 --- a/apps/openmw/mwclass/door.cpp +++ b/apps/openmw/mwclass/door.cpp @@ -231,7 +231,7 @@ namespace MWClass if(lockLevel!=0) ptr.getCellRef().setLockLevel(abs(lockLevel)); //Changes lock to locklevel, in positive else - ptr.getCellRef().setLockLevel(abs(ptr.getCellRef().getLockLevel())); //No locklevel given, just flip the origional one + ptr.getCellRef().setLockLevel(abs(ptr.getCellRef().getLockLevel())); //No locklevel given, just flip the original one } void Door::unlock (const MWWorld::Ptr& ptr) const diff --git a/apps/openmw/mwclass/potion.cpp b/apps/openmw/mwclass/potion.cpp index c26b925f6..225175979 100644 --- a/apps/openmw/mwclass/potion.cpp +++ b/apps/openmw/mwclass/potion.cpp @@ -122,7 +122,7 @@ namespace MWClass info.effects = MWGui::Widgets::MWEffectList::effectListFromESM(&ref->mBase->mEffects); - // hide effects the player doesnt know about + // hide effects the player doesn't know about MWWorld::Ptr player = MWBase::Environment::get().getWorld ()->getPlayerPtr(); for (unsigned int i=0; igetCell()); - // actor position is already in world co-ordinates + // actor position is already in world coordinates ESM::Pathgrid::Point start(PathFinder::MakePathgridPoint(actorPos)); // don't take shortcuts for wandering @@ -693,8 +693,8 @@ namespace MWMechanics ESM::Pathgrid::Point pt = paths.back(); for(unsigned int j = 0; j < nodes.size(); j++) { - // FIXME: doesn't hadle a door with the same X/Y - // co-ordinates but with a different Z + // FIXME: doesn't handle a door with the same X/Y + // coordinates but with a different Z if(nodes[j].mX == pt.mX && nodes[j].mY == pt.mY) { nodes.erase(nodes.begin() + j); @@ -828,7 +828,7 @@ namespace MWMechanics // ... pathgrids don't usually include water, so swimmers ignore them if (mDistance && storage.mCanWanderAlongPathGrid && !actor.getClass().isPureWaterCreature(actor)) { - // get NPC's position in local (i.e. cell) co-ordinates + // get NPC's position in local (i.e. cell) coordinates osg::Vec3f npcPos(mInitialActorPosition); CoordinateConverter(cell).toLocal(npcPos); @@ -837,7 +837,7 @@ namespace MWMechanics // mAllowedNodes for this actor with pathgrid point indexes based on mDistance // and if the point is connected to the closest current point - // NOTE: mPoints and mAllowedNodes are in local co-ordinates + // NOTE: mPoints and mAllowedNodes are in local coordinates int pointIndex = 0; for(unsigned int counter = 0; counter < pathgrid->mPoints.size(); counter++) { diff --git a/apps/openmw/mwmechanics/aiwander.hpp b/apps/openmw/mwmechanics/aiwander.hpp index da7553ca0..f9b03ca5e 100644 --- a/apps/openmw/mwmechanics/aiwander.hpp +++ b/apps/openmw/mwmechanics/aiwander.hpp @@ -119,7 +119,7 @@ namespace MWMechanics GroupIndex_MaxIdle = 9 }; - /// convert point from local (i.e. cell) to world co-ordinates + /// convert point from local (i.e. cell) to world coordinates void ToWorldCoordinates(ESM::Pathgrid::Point& point, const ESM::Cell * cell); void SetCurrentNodeToClosestAllowedNode(osg::Vec3f npcPos, AiWanderStorage& storage); diff --git a/apps/openmw/mwmechanics/pathfinding.cpp b/apps/openmw/mwmechanics/pathfinding.cpp index 0c7e9cdba..b0bdce8f1 100644 --- a/apps/openmw/mwmechanics/pathfinding.cpp +++ b/apps/openmw/mwmechanics/pathfinding.cpp @@ -139,7 +139,7 @@ namespace MWMechanics * NOTE: It may be desirable to simply go directly to the endPoint if for * example there are no pathgrids in this cell. * - * NOTE: startPoint & endPoint are in world co-ordinates + * NOTE: startPoint & endPoint are in world coordinates * * Updates mPath using aStarSearch() or ray test (if shortcut allowed). * mPath consists of pathgrid points, except the last element which is @@ -148,7 +148,7 @@ namespace MWMechanics * pathgrid point (e.g. wander) then it may be worth while to call * pop_back() to remove the redundant entry. * - * NOTE: co-ordinates must be converted prior to calling GetClosestPoint() + * NOTE: coordinates must be converted prior to calling GetClosestPoint() * * | * | cell @@ -164,8 +164,8 @@ namespace MWMechanics * +----------------------------- * * i = x value of cell itself (multiply by ESM::Land::REAL_SIZE to convert) - * j = @.x in local co-ordinates (i.e. within the cell) - * k = @.x in world co-ordinates + * j = @.x in local coordinates (i.e. within the cell) + * k = @.x in world coordinates */ void PathFinder::buildPath(const ESM::Pathgrid::Point &startPoint, const ESM::Pathgrid::Point &endPoint, @@ -188,7 +188,7 @@ namespace MWMechanics return; } - // NOTE: GetClosestPoint expects local co-ordinates + // NOTE: GetClosestPoint expects local coordinates CoordinateConverter converter(mCell->getCell()); // NOTE: It is possible that GetClosestPoint returns a pathgrind point index @@ -230,7 +230,7 @@ namespace MWMechanics { mPath = mCell->aStarSearch(startNode, endNode.first); - // convert supplied path to world co-ordinates + // convert supplied path to world coordinates for (std::list::iterator iter(mPath.begin()); iter != mPath.end(); ++iter) { converter.toWorld(*iter); diff --git a/apps/openmw/mwmechanics/pathfinding.hpp b/apps/openmw/mwmechanics/pathfinding.hpp index 83c56ca7d..945a7f927 100644 --- a/apps/openmw/mwmechanics/pathfinding.hpp +++ b/apps/openmw/mwmechanics/pathfinding.hpp @@ -84,7 +84,7 @@ namespace MWMechanics /** Synchronize new path with old one to avoid visiting 1 waypoint 2 times @note BuildPath() takes closest PathGrid point to NPC as first point of path. - This is undesireable if NPC has just passed a Pathgrid point, as this + This is undesirable if NPC has just passed a Pathgrid point, as this makes the 2nd point of the new path == the 1st point of old path. Which results in NPC "running in a circle" back to the just passed waypoint. */ @@ -122,11 +122,11 @@ namespace MWMechanics return (MWMechanics::PathFinder::MakeOsgVec3(point) - pos).length2(); } - // Return the closest pathgrid point index from the specified position co - // -ordinates. NOTE: Does not check if there is a sensible way to get there + // Return the closest pathgrid point index from the specified position + // coordinates. NOTE: Does not check if there is a sensible way to get there // (e.g. a cliff in front). // - // NOTE: pos is expected to be in local co-ordinates, as is grid->mPoints + // NOTE: pos is expected to be in local coordinates, as is grid->mPoints // static int GetClosestPoint(const ESM::Pathgrid* grid, const osg::Vec3f& pos) { diff --git a/apps/openmw/mwmechanics/pathgrid.cpp b/apps/openmw/mwmechanics/pathgrid.cpp index 871baecdc..c557beadd 100644 --- a/apps/openmw/mwmechanics/pathgrid.cpp +++ b/apps/openmw/mwmechanics/pathgrid.cpp @@ -225,7 +225,7 @@ namespace MWMechanics * Should be possible to make this MT safe. * * Returns path which may be empty. path contains pathgrid points in local - * cell co-ordinates (indoors) or world co-ordinates (external). + * cell coordinates (indoors) or world coordinates (external). * * Input params: * start, goal - pathgrid point indexes (for this cell) @@ -239,7 +239,7 @@ namespace MWMechanics * TODO: An intersting exercise might be to cache the paths created for a * start/goal pair. To cache the results the paths need to be in * pathgrid points form (currently they are converted to world - * co-ordinates). Essentially trading speed w/ memory. + * coordinates). Essentially trading speed w/ memory. */ std::list PathgridGraph::aStarSearch(const int start, const int goal) const @@ -312,7 +312,7 @@ namespace MWMechanics if(current != goal) return path; // for some reason couldn't build a path - // reconstruct path to return, using local co-ordinates + // reconstruct path to return, using local coordinates while(graphParent[current] != -1) { path.push_front(mPathgrid->mPoints[current]); diff --git a/apps/openmw/mwmechanics/pathgrid.hpp b/apps/openmw/mwmechanics/pathgrid.hpp index ab418ae78..d90cb47cd 100644 --- a/apps/openmw/mwmechanics/pathgrid.hpp +++ b/apps/openmw/mwmechanics/pathgrid.hpp @@ -30,7 +30,7 @@ namespace MWMechanics // the input parameters are pathgrid point indexes // the output list is in local (internal cells) or world (external - // cells) co-ordinates + // cells) coordinates // // NOTE: if start equals end an empty path is returned std::list aStarSearch(const int start, diff --git a/apps/openmw/mwphysics/physicssystem.hpp b/apps/openmw/mwphysics/physicssystem.hpp index 215355316..d74631845 100644 --- a/apps/openmw/mwphysics/physicssystem.hpp +++ b/apps/openmw/mwphysics/physicssystem.hpp @@ -200,7 +200,7 @@ namespace MWPhysics typedef std::map CollisionMap; CollisionMap mStandingCollisions; - // replaces all occurences of 'old' in the map by 'updated', no matter if its a key or value + // replaces all occurrences of 'old' in the map by 'updated', no matter if it's a key or value void updateCollisionMapPtr(CollisionMap& map, const MWWorld::Ptr &old, const MWWorld::Ptr &updated); PtrVelocityList mMovementQueue; diff --git a/apps/openmw/mwrender/sky.hpp b/apps/openmw/mwrender/sky.hpp index 085eeb2be..e047a9832 100644 --- a/apps/openmw/mwrender/sky.hpp +++ b/apps/openmw/mwrender/sky.hpp @@ -211,7 +211,7 @@ namespace MWRender osg::Vec3f mStormDirection; - // remember some settings so we don't have to apply them again if they didnt change + // remember some settings so we don't have to apply them again if they didn't change std::string mClouds; std::string mNextClouds; float mCloudBlendFactor; diff --git a/apps/openmw/mwscript/compilercontext.hpp b/apps/openmw/mwscript/compilercontext.hpp index 010926f45..ca7efd77a 100644 --- a/apps/openmw/mwscript/compilercontext.hpp +++ b/apps/openmw/mwscript/compilercontext.hpp @@ -11,7 +11,7 @@ namespace MWScript enum Type { - Type_Full, // global, local, targetted + Type_Full, // global, local, targeted Type_Dialogue, Type_Console }; diff --git a/files/settings-default.cfg b/files/settings-default.cfg index 9813cb166..e17f0235b 100644 --- a/files/settings-default.cfg +++ b/files/settings-default.cfg @@ -188,13 +188,13 @@ clamp lighting = true # If this option is enabled, normal maps are automatically recognized and used if they are named appropriately # (see 'normal map pattern', e.g. for a base texture foo.dds, the normal map texture would have to be named foo_n.dds). -# If this option is disabled, normal maps are only used if they are explicitely listed within the mesh file (.nif or .osg file). +# If this option is disabled, normal maps are only used if they are explicitly listed within the mesh file (.nif or .osg file). # Affects objects. auto use object normal maps = false # If this option is enabled, specular maps are automatically recognized and used if they are named appropriately # (see 'specular map pattern', e.g. for a base texture foo.dds, the specular map texture would have to be named foo_spec.dds). -# If this option is disabled, normal maps are only used if they are explicitely listed within the mesh file (.osg file, not supported in .nif files). +# If this option is disabled, normal maps are only used if they are explicitly listed within the mesh file (.osg file, not supported in .nif files). # Affects objects. auto use object specular maps = false From 12c8c3276a5f39ea4c89e9e171d048fe2b7ce571 Mon Sep 17 00:00:00 2001 From: Leon Krieg Date: Thu, 15 Dec 2016 19:29:05 +0100 Subject: [PATCH 34/46] Disable NPC collision only when death animation has finished (#3666) --- apps/openmw/mwmechanics/actors.cpp | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/apps/openmw/mwmechanics/actors.cpp b/apps/openmw/mwmechanics/actors.cpp index 2a5995e0c..23a6f497f 100644 --- a/apps/openmw/mwmechanics/actors.cpp +++ b/apps/openmw/mwmechanics/actors.cpp @@ -1271,8 +1271,6 @@ namespace MWMechanics stats.getActiveSpells().clear(); calculateCreatureStatModifiers(iter->first, 0); - MWBase::Environment::get().getWorld()->enableActorCollision(iter->first, false); - if (cls.isEssential(iter->first)) MWBase::Environment::get().getWindowManager()->messageBox("#{sKilledEssential}"); } @@ -1290,6 +1288,11 @@ namespace MWMechanics //player's death animation is over MWBase::Environment::get().getStateManager()->askLoadRecent(); } + else + { + // NPC death animation is over, disable actor collision + MWBase::Environment::get().getWorld()->enableActorCollision(iter->first, false); + } // Play Death Music if it was the player dying if(iter->first == getPlayer()) From c0faeea938e9132cb548c9783004e85cf2c44a87 Mon Sep 17 00:00:00 2001 From: scrawl Date: Thu, 15 Dec 2016 22:39:21 +0100 Subject: [PATCH 35/46] RigGeometry check if mesh has normals (Fixes #3667) --- components/sceneutil/riggeometry.cpp | 18 ++++++++++++------ 1 file changed, 12 insertions(+), 6 deletions(-) diff --git a/components/sceneutil/riggeometry.cpp b/components/sceneutil/riggeometry.cpp index 3af5176f4..297dc6923 100644 --- a/components/sceneutil/riggeometry.cpp +++ b/components/sceneutil/riggeometry.cpp @@ -120,13 +120,17 @@ void RigGeometry::setSourceGeometry(osg::ref_ptr sourceGeometry) setVertexArray(vertexArray); } - osg::ref_ptr normalArray = osg::clone(from.getNormalArray(), osg::CopyOp::DEEP_COPY_ALL); - if (normalArray) + if (osg::Array* normals = from.getNormalArray()) { - normalArray->setVertexBufferObject(vbo); - setNormalArray(normalArray, osg::Array::BIND_PER_VERTEX); + osg::ref_ptr normalArray = osg::clone(normals, osg::CopyOp::DEEP_COPY_ALL); + if (normalArray) + { + normalArray->setVertexBufferObject(vbo); + setNormalArray(normalArray, osg::Array::BIND_PER_VERTEX); + } } + if (osg::Vec4Array* tangents = dynamic_cast(from.getTexCoordArray(7))) { mSourceTangents = tangents; @@ -273,7 +277,8 @@ void RigGeometry::update(osg::NodeVisitor* nv) { unsigned short vertex = *vertexIt; (*positionDst)[vertex] = resultMat.preMult((*positionSrc)[vertex]); - (*normalDst)[vertex] = osg::Matrix::transform3x3((*normalSrc)[vertex], resultMat); + if (normalDst) + (*normalDst)[vertex] = osg::Matrix::transform3x3((*normalSrc)[vertex], resultMat); if (tangentDst) { osg::Vec4f srcTangent = (*tangentSrc)[vertex]; @@ -284,7 +289,8 @@ void RigGeometry::update(osg::NodeVisitor* nv) } positionDst->dirty(); - normalDst->dirty(); + if (normalDst) + normalDst->dirty(); if (tangentDst) tangentDst->dirty(); } From 827c78a4cd4f11d26eb58dfa06c50f4e6ede525f Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Fri, 16 Dec 2016 12:28:09 +0100 Subject: [PATCH 36/46] added text column to ref id table (books) --- apps/opencs/model/world/columns.cpp | 2 ++ apps/opencs/model/world/columns.hpp | 2 ++ apps/opencs/model/world/refidadapterimp.cpp | 9 +++++++-- apps/opencs/model/world/refidadapterimp.hpp | 3 ++- apps/opencs/model/world/refidcollection.cpp | 5 ++++- 5 files changed, 17 insertions(+), 4 deletions(-) diff --git a/apps/opencs/model/world/columns.cpp b/apps/opencs/model/world/columns.cpp index c116ec4e5..028a759dc 100644 --- a/apps/opencs/model/world/columns.cpp +++ b/apps/opencs/model/world/columns.cpp @@ -330,6 +330,8 @@ namespace CSMWorld { ColumnId_WeatherName, "Type" }, { ColumnId_WeatherChance, "Percent Chance" }, + { ColumnId_Text, "Text" }, + { ColumnId_UseValue1, "Use value 1" }, { ColumnId_UseValue2, "Use value 2" }, { ColumnId_UseValue3, "Use value 3" }, diff --git a/apps/opencs/model/world/columns.hpp b/apps/opencs/model/world/columns.hpp index 05bedb77d..e3899af73 100644 --- a/apps/opencs/model/world/columns.hpp +++ b/apps/opencs/model/world/columns.hpp @@ -329,6 +329,8 @@ namespace CSMWorld ColumnId_WeatherName = 295, ColumnId_WeatherChance = 296, + ColumnId_Text = 297, + // 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, diff --git a/apps/opencs/model/world/refidadapterimp.cpp b/apps/opencs/model/world/refidadapterimp.cpp index 5f48b4315..086e95c34 100644 --- a/apps/opencs/model/world/refidadapterimp.cpp +++ b/apps/opencs/model/world/refidadapterimp.cpp @@ -301,9 +301,9 @@ void CSMWorld::ArmorRefIdAdapter::setData (const RefIdColumn *column, RefIdData& } CSMWorld::BookRefIdAdapter::BookRefIdAdapter (const EnchantableColumns& columns, - const RefIdColumn *scroll, const RefIdColumn *skill) + const RefIdColumn *scroll, const RefIdColumn *skill, const RefIdColumn *text) : EnchantableRefIdAdapter (UniversalId::Type_Book, columns), - mScroll (scroll), mSkill (skill) + mScroll (scroll), mSkill (skill), mText (text) {} QVariant CSMWorld::BookRefIdAdapter::getData (const RefIdColumn *column, @@ -318,6 +318,9 @@ QVariant CSMWorld::BookRefIdAdapter::getData (const RefIdColumn *column, if (column==mSkill) return record.get().mData.mSkillID; + if (column==mText) + return QString::fromUtf8 (record.get().mText.c_str()); + return EnchantableRefIdAdapter::getData (column, data, index); } @@ -333,6 +336,8 @@ void CSMWorld::BookRefIdAdapter::setData (const RefIdColumn *column, RefIdData& book.mData.mIsScroll = value.toInt(); else if (column==mSkill) book.mData.mSkillID = value.toInt(); + else if (column==mText) + book.mText = value.toString().toUtf8().data(); else { EnchantableRefIdAdapter::setData (column, data, index, value); diff --git a/apps/opencs/model/world/refidadapterimp.hpp b/apps/opencs/model/world/refidadapterimp.hpp index e828a7f4e..757a8ad77 100644 --- a/apps/opencs/model/world/refidadapterimp.hpp +++ b/apps/opencs/model/world/refidadapterimp.hpp @@ -696,11 +696,12 @@ namespace CSMWorld { const RefIdColumn *mScroll; const RefIdColumn *mSkill; + const RefIdColumn *mText; public: BookRefIdAdapter (const EnchantableColumns& columns, const RefIdColumn *scroll, - const RefIdColumn *skill); + const RefIdColumn *skill, const RefIdColumn *text); virtual QVariant getData (const RefIdColumn *column, const RefIdData& data, int index) const; diff --git a/apps/opencs/model/world/refidcollection.cpp b/apps/opencs/model/world/refidcollection.cpp index c4c8f8605..74867d626 100644 --- a/apps/opencs/model/world/refidcollection.cpp +++ b/apps/opencs/model/world/refidcollection.cpp @@ -297,6 +297,9 @@ CSMWorld::RefIdCollection::RefIdCollection() mColumns.push_back (RefIdColumn (Columns::ColumnId_Attribute, ColumnBase::Display_Attribute)); const RefIdColumn *attribute = &mColumns.back(); + mColumns.push_back (RefIdColumn (Columns::ColumnId_Text, ColumnBase::Display_LongString)); + const RefIdColumn *text = &mColumns.back(); + mColumns.push_back (RefIdColumn (Columns::ColumnId_ClothingType, ColumnBase::Display_ClothingType)); const RefIdColumn *clothingType = &mColumns.back(); @@ -656,7 +659,7 @@ CSMWorld::RefIdCollection::RefIdCollection() mAdapters.insert (std::make_pair (UniversalId::Type_Armor, new ArmorRefIdAdapter (enchantableColumns, armorType, health, armor, partRef))); mAdapters.insert (std::make_pair (UniversalId::Type_Book, - new BookRefIdAdapter (enchantableColumns, scroll, attribute))); + new BookRefIdAdapter (enchantableColumns, scroll, attribute, text))); mAdapters.insert (std::make_pair (UniversalId::Type_Clothing, new ClothingRefIdAdapter (enchantableColumns, clothingType, partRef))); mAdapters.insert (std::make_pair (UniversalId::Type_Container, From cca75499ee4b18a6a0facdb7888dddc7f3c7682b Mon Sep 17 00:00:00 2001 From: scrawl Date: Fri, 16 Dec 2016 20:09:20 +0100 Subject: [PATCH 37/46] Clear the Skeleton's bone cache when a node is added/removed (Fixes #3663) --- apps/openmw/mwrender/creatureanimation.cpp | 2 -- apps/openmw/mwrender/npcanimation.cpp | 2 -- components/sceneutil/skeleton.cpp | 12 ++++++++++++ components/sceneutil/skeleton.hpp | 6 ++++-- 4 files changed, 16 insertions(+), 6 deletions(-) diff --git a/apps/openmw/mwrender/creatureanimation.cpp b/apps/openmw/mwrender/creatureanimation.cpp index a095d5dd4..36a0f4085 100644 --- a/apps/openmw/mwrender/creatureanimation.cpp +++ b/apps/openmw/mwrender/creatureanimation.cpp @@ -110,8 +110,6 @@ void CreatureWeaponAnimation::updatePart(PartHolderPtr& scene, int slot) osg::ref_ptr node = mResourceSystem->getSceneManager()->getInstance(item.getClass().getModel(item)); osg::ref_ptr attached = SceneUtil::attach(node, mObjectRoot, bonename, bonename); mResourceSystem->getSceneManager()->notifyAttached(attached); - if (mSkeleton) - mSkeleton->markDirty(); scene.reset(new PartHolder(attached)); diff --git a/apps/openmw/mwrender/npcanimation.cpp b/apps/openmw/mwrender/npcanimation.cpp index d9dd1a89e..53eaf0996 100644 --- a/apps/openmw/mwrender/npcanimation.cpp +++ b/apps/openmw/mwrender/npcanimation.cpp @@ -671,8 +671,6 @@ PartHolderPtr NpcAnimation::insertBoundedPart(const std::string& model, const st { osg::ref_ptr instance = mResourceSystem->getSceneManager()->getInstance(model); osg::ref_ptr attached = SceneUtil::attach(instance, mObjectRoot, bonefilter, bonename); - if (mSkeleton) - mSkeleton->markDirty(); mResourceSystem->getSceneManager()->notifyAttached(attached); if (enchantedGlow) addGlow(attached, *glowColor); diff --git a/components/sceneutil/skeleton.cpp b/components/sceneutil/skeleton.cpp index 390a8e823..f3c2aef77 100644 --- a/components/sceneutil/skeleton.cpp +++ b/components/sceneutil/skeleton.cpp @@ -148,6 +148,8 @@ void Skeleton::markDirty() { mTraversedEvenFrame = false; mTraversedOddFrame = false; + mBoneCache.clear(); + mBoneCacheInit = false; } void Skeleton::traverse(osg::NodeVisitor& nv) @@ -160,6 +162,16 @@ void Skeleton::traverse(osg::NodeVisitor& nv) osg::Group::traverse(nv); } +void Skeleton::childInserted(unsigned int) +{ + markDirty(); +} + +void Skeleton::childRemoved(unsigned int, unsigned int) +{ + markDirty(); +} + Bone::Bone() : mNode(NULL) { diff --git a/components/sceneutil/skeleton.hpp b/components/sceneutil/skeleton.hpp index 764b7f645..24dcc6b3f 100644 --- a/components/sceneutil/skeleton.hpp +++ b/components/sceneutil/skeleton.hpp @@ -53,10 +53,12 @@ namespace SceneUtil bool getActive() const; - /// If a new RigGeometry is added after the Skeleton has already been rendered, you must call markDirty(). + void traverse(osg::NodeVisitor& nv); + void markDirty(); - void traverse(osg::NodeVisitor& nv); + virtual void childInserted(unsigned int); + virtual void childRemoved(unsigned int, unsigned int); private: // The root bone is not a "real" bone, it has no corresponding node in the scene graph. From f8690dcd2083e6ec0ab006d367c78bf2827c1430 Mon Sep 17 00:00:00 2001 From: scrawl Date: Fri, 16 Dec 2016 20:16:59 +0100 Subject: [PATCH 38/46] Set the drag-and-drop state after initiating the drag, not before (Fixes #3134) --- apps/openmw/mwgui/draganddrop.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/apps/openmw/mwgui/draganddrop.cpp b/apps/openmw/mwgui/draganddrop.cpp index 55aeb969c..6053a7fb0 100644 --- a/apps/openmw/mwgui/draganddrop.cpp +++ b/apps/openmw/mwgui/draganddrop.cpp @@ -36,7 +36,6 @@ void DragAndDrop::startDrag (int index, SortFilterItemModel* sortModel, ItemMode mSourceModel = sourceModel; mSourceView = sourceView; mSourceSortModel = sortModel; - mIsOnDragAndDrop = true; // If picking up an item that isn't from the player's inventory, the item gets added to player inventory backend // immediately, even though it's still floating beneath the mouse cursor. A bit counterintuitive, @@ -88,6 +87,8 @@ void DragAndDrop::startDrag (int index, SortFilterItemModel* sortModel, ItemMode sourceView->update(); MWBase::Environment::get().getWindowManager()->setDragDrop(true); + + mIsOnDragAndDrop = true; } void DragAndDrop::drop(ItemModel *targetModel, ItemView *targetView) From b794aa7c2f3c0621c8e3de7029efe4dcc1750909 Mon Sep 17 00:00:00 2001 From: Aussiemon Date: Fri, 16 Dec 2016 12:22:07 -0700 Subject: [PATCH 39/46] Helper methods for updateCollisionMask(), prevent water collision being removed twice, remove Bullet 2.8.5 methods --- apps/openmw/mwphysics/actor.cpp | 20 ++++++++++++++------ apps/openmw/mwphysics/actor.hpp | 2 ++ apps/openmw/mwphysics/physicssystem.cpp | 8 ++++---- 3 files changed, 20 insertions(+), 10 deletions(-) diff --git a/apps/openmw/mwphysics/actor.cpp b/apps/openmw/mwphysics/actor.cpp index dacffe22c..9be34495e 100644 --- a/apps/openmw/mwphysics/actor.cpp +++ b/apps/openmw/mwphysics/actor.cpp @@ -47,7 +47,7 @@ Actor::Actor(const MWWorld::Ptr& ptr, osg::ref_ptr updateScale(); updatePosition(); - updateCollisionMask(); + addCollisionMask(getCollisionMask()); } Actor::~Actor() @@ -70,18 +70,26 @@ void Actor::enableCollisionBody(bool collision) } } +void Actor::addCollisionMask(int collisionMask) +{ + mCollisionWorld->addCollisionObject(mCollisionObject.get(), CollisionType_Actor, collisionMask); +} + void Actor::updateCollisionMask() { - if (mCollisionObject.get()->getWorldArrayIndex() >= 0) - { - mCollisionWorld->removeCollisionObject(mCollisionObject.get()); - } + mCollisionWorld->removeCollisionObject(mCollisionObject.get()); + addCollisionMask(getCollisionMask()); +} + +int Actor::getCollisionMask() +{ int collisionMask = CollisionType_World | CollisionType_HeightMap; if (mExternalCollisionMode) collisionMask |= CollisionType_Actor | CollisionType_Projectile | CollisionType_Door; if (mCanWaterWalk) collisionMask |= CollisionType_Water; - mCollisionWorld->addCollisionObject(mCollisionObject.get(), CollisionType_Actor, collisionMask); + return collisionMask; + } void Actor::updatePosition() diff --git a/apps/openmw/mwphysics/actor.hpp b/apps/openmw/mwphysics/actor.hpp index b238547e1..a0bf5bfc0 100644 --- a/apps/openmw/mwphysics/actor.hpp +++ b/apps/openmw/mwphysics/actor.hpp @@ -139,6 +139,8 @@ namespace MWPhysics private: /// Removes then re-adds the collision object to the dynamics world void updateCollisionMask(); + void addCollisionMask(int collisionMask); + int getCollisionMask(); bool mCanWaterWalk; bool mWalkingOnWater; diff --git a/apps/openmw/mwphysics/physicssystem.cpp b/apps/openmw/mwphysics/physicssystem.cpp index 1985dba18..f94ee14b6 100644 --- a/apps/openmw/mwphysics/physicssystem.cpp +++ b/apps/openmw/mwphysics/physicssystem.cpp @@ -1463,14 +1463,14 @@ namespace MWPhysics { if (mWaterCollisionObject.get()) { - if (mWaterCollisionObject.get()->getWorldArrayIndex() >= 0) - { - mCollisionWorld->removeCollisionObject(mWaterCollisionObject.get()); - } + mCollisionWorld->removeCollisionObject(mWaterCollisionObject.get()); } if (!mWaterEnabled) + { + mWaterCollisionObject.reset(); return; + } mWaterCollisionObject.reset(new btCollisionObject()); mWaterCollisionShape.reset(new btStaticPlaneShape(btVector3(0,0,1), mWaterHeight)); From aafff1deb63e901d0037220132635e875774900a Mon Sep 17 00:00:00 2001 From: scrawl Date: Fri, 16 Dec 2016 20:40:15 +0100 Subject: [PATCH 40/46] Fix memory leak --- components/nifosg/nifloader.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/components/nifosg/nifloader.cpp b/components/nifosg/nifloader.cpp index d4dabd2f9..a0001d6fd 100644 --- a/components/nifosg/nifloader.cpp +++ b/components/nifosg/nifloader.cpp @@ -1159,10 +1159,11 @@ namespace NifOsg morphGeom->setUpdateCallback(NULL); morphGeom->setCullCallback(new UpdateMorphGeometry); morphGeom->setUseVertexBufferObjects(true); - morphGeom->getOrCreateVertexBufferObject()->setUsage(GL_DYNAMIC_DRAW_ARB); triShapeToGeometry(triShape, morphGeom, parentNode, composite, boundTextures, animflags); + morphGeom->getOrCreateVertexBufferObject()->setUsage(GL_DYNAMIC_DRAW_ARB); + const std::vector& morphs = morpher->data.getPtr()->mMorphs; if (morphs.empty()) return morphGeom; From 2b2a51d3b2b8aa085113ee700a18c93527a753ca Mon Sep 17 00:00:00 2001 From: scrawl Date: Fri, 16 Dec 2016 20:50:50 +0100 Subject: [PATCH 41/46] Update AUTHORS.md --- AUTHORS.md | 1 + 1 file changed, 1 insertion(+) diff --git a/AUTHORS.md b/AUTHORS.md index 83777df18..185b5ee66 100644 --- a/AUTHORS.md +++ b/AUTHORS.md @@ -78,6 +78,7 @@ Programmers Kurnevsky Evgeny (kurnevsky) Lars Söderberg (Lazaroth) lazydev + Leon Krieg (lkrieg) Leon Saunders (emoose) lohikaarme Lukasz Gromanowski (lgro) From 2f66b91ac50b34c8e3b26f2a14f88a6d9a5cf81b Mon Sep 17 00:00:00 2001 From: Aussiemon Date: Fri, 16 Dec 2016 15:18:28 -0700 Subject: [PATCH 42/46] Added check to prevent attempted wandering of empty paths --- apps/openmw/mwmechanics/aiwander.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/apps/openmw/mwmechanics/aiwander.cpp b/apps/openmw/mwmechanics/aiwander.cpp index e67c733f8..73ddce4b4 100644 --- a/apps/openmw/mwmechanics/aiwander.cpp +++ b/apps/openmw/mwmechanics/aiwander.cpp @@ -473,8 +473,8 @@ namespace MWMechanics void AiWander::onWalkingStatePerFrameActions(const MWWorld::Ptr& actor, float duration, AiWanderStorage& storage, ESM::Position& pos) { - // Are we there yet? - if (pathTo(actor, mPathFinder.getPath().back(), duration, DESTINATION_TOLERANCE)) + // Is there no destination or are we there yet? + if ((!mPathFinder.isPathConstructed()) || pathTo(actor, mPathFinder.getPath().back(), duration, DESTINATION_TOLERANCE)) { stopWalking(actor, storage); storage.setState(Wander_ChooseAction); From eae35af13d17d84efe4ed6c7e7812dadd71d1330 Mon Sep 17 00:00:00 2001 From: scrawl Date: Sat, 17 Dec 2016 00:23:22 +0100 Subject: [PATCH 43/46] Check if the bounding box changed before calling dirtyBound() --- components/sceneutil/riggeometry.cpp | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/components/sceneutil/riggeometry.cpp b/components/sceneutil/riggeometry.cpp index 297dc6923..92780bfe9 100644 --- a/components/sceneutil/riggeometry.cpp +++ b/components/sceneutil/riggeometry.cpp @@ -320,11 +320,14 @@ void RigGeometry::updateBounds(osg::NodeVisitor *nv) box.expandBy(bs); } - _boundingBox = box; - _boundingSphere = osg::BoundingSphere(_boundingBox); - _boundingSphereComputed = true; - for (unsigned int i=0; idirtyBound(); + if (box != _boundingBox) + { + _boundingBox = box; + _boundingSphere = osg::BoundingSphere(_boundingBox); + _boundingSphereComputed = true; + for (unsigned int i=0; idirtyBound(); + } } void RigGeometry::updateGeomToSkelMatrix(const osg::NodePath& nodePath) From c2d6e074c2201a2f8c674f218d075868b3928ff1 Mon Sep 17 00:00:00 2001 From: Leon Krieg Date: Sat, 17 Dec 2016 11:52:17 +0100 Subject: [PATCH 44/46] Handle SDL event 0x304 by doing nothing (#3670) --- components/sdlutil/sdlinputwrapper.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/components/sdlutil/sdlinputwrapper.cpp b/components/sdlutil/sdlinputwrapper.cpp index 6482f378e..2f0419d3a 100644 --- a/components/sdlutil/sdlinputwrapper.cpp +++ b/components/sdlutil/sdlinputwrapper.cpp @@ -108,6 +108,8 @@ InputWrapper::InputWrapper(SDL_Window* window, osg::ref_ptr v case SDL_TEXTINPUT: mKeyboardListener->textInput(evt.text); break; + case SDL_KEYMAPCHANGED: + break; case SDL_JOYHATMOTION: //As we manage everything with GameController, don't even bother with these. case SDL_JOYAXISMOTION: case SDL_JOYBUTTONDOWN: From 63e093bcd0702783503d0c6d61605dda46cc1b50 Mon Sep 17 00:00:00 2001 From: scrawl Date: Sat, 17 Dec 2016 12:04:03 +0100 Subject: [PATCH 45/46] Revert "Handle SDL event 0x304 by doing nothing (#3670)" --- components/sdlutil/sdlinputwrapper.cpp | 2 -- 1 file changed, 2 deletions(-) diff --git a/components/sdlutil/sdlinputwrapper.cpp b/components/sdlutil/sdlinputwrapper.cpp index 2f0419d3a..6482f378e 100644 --- a/components/sdlutil/sdlinputwrapper.cpp +++ b/components/sdlutil/sdlinputwrapper.cpp @@ -108,8 +108,6 @@ InputWrapper::InputWrapper(SDL_Window* window, osg::ref_ptr v case SDL_TEXTINPUT: mKeyboardListener->textInput(evt.text); break; - case SDL_KEYMAPCHANGED: - break; case SDL_JOYHATMOTION: //As we manage everything with GameController, don't even bother with these. case SDL_JOYAXISMOTION: case SDL_JOYBUTTONDOWN: From 170e723cc77ec0234cbca87f259850f980040764 Mon Sep 17 00:00:00 2001 From: Leon Krieg Date: Sat, 17 Dec 2016 11:52:17 +0100 Subject: [PATCH 46/46] Handle SDL event 0x304 by doing nothing (#3670) --- components/sdlutil/sdlinputwrapper.cpp | 5 +++++ components/sdlutil/sdlinputwrapper.hpp | 1 + 2 files changed, 6 insertions(+) diff --git a/components/sdlutil/sdlinputwrapper.cpp b/components/sdlutil/sdlinputwrapper.cpp index 6482f378e..e8a0823f8 100644 --- a/components/sdlutil/sdlinputwrapper.cpp +++ b/components/sdlutil/sdlinputwrapper.cpp @@ -108,6 +108,11 @@ InputWrapper::InputWrapper(SDL_Window* window, osg::ref_ptr v case SDL_TEXTINPUT: mKeyboardListener->textInput(evt.text); break; + +#if SDL_VERSION_ATLEAST(2, 0, 4) + case SDL_KEYMAPCHANGED: + break; +#endif case SDL_JOYHATMOTION: //As we manage everything with GameController, don't even bother with these. case SDL_JOYAXISMOTION: case SDL_JOYBUTTONDOWN: diff --git a/components/sdlutil/sdlinputwrapper.hpp b/components/sdlutil/sdlinputwrapper.hpp index a821b9012..62d6a565c 100644 --- a/components/sdlutil/sdlinputwrapper.hpp +++ b/components/sdlutil/sdlinputwrapper.hpp @@ -6,6 +6,7 @@ #include #include +#include #include "OISCompat.hpp" #include "events.hpp"