From f3f869e99a585554c52fcac1577108a5b3f5a052 Mon Sep 17 00:00:00 2001 From: scrawl Date: Sun, 7 Sep 2014 23:47:57 +0200 Subject: [PATCH 01/21] Don't produce NaN's for 0-length controllers in NifOgre::DefaultFunction --- components/nifogre/controller.hpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/components/nifogre/controller.hpp b/components/nifogre/controller.hpp index aa60482e3..cc750ea65 100644 --- a/components/nifogre/controller.hpp +++ b/components/nifogre/controller.hpp @@ -89,6 +89,9 @@ namespace NifOgre { if(mDeltaInput) { + if (mStopTime - mStartTime == 0.f) + return 0.f; + mDeltaCount += value*mFrequency; if(mDeltaCount < mStartTime) mDeltaCount = mStopTime - std::fmod(mStartTime - mDeltaCount, From 07d827c907fa73f1b27788e86504b3936fd60045 Mon Sep 17 00:00:00 2001 From: scrawl Date: Mon, 8 Sep 2014 15:22:33 +0200 Subject: [PATCH 02/21] Ignore invalid input in numeric EditBox (Fixes #1885) --- apps/openmw/mwgui/tradewindow.cpp | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/apps/openmw/mwgui/tradewindow.cpp b/apps/openmw/mwgui/tradewindow.cpp index ccfe6b1eb..8126a4ee8 100644 --- a/apps/openmw/mwgui/tradewindow.cpp +++ b/apps/openmw/mwgui/tradewindow.cpp @@ -436,6 +436,10 @@ namespace MWGui } catch (std::bad_cast&) { + if (_sender->getCaption().empty()) + mTotalBalance->setCaption("0"); + else + mTotalBalance->setCaption(boost::lexical_cast(std::abs(mCurrentBalance))); } } @@ -460,16 +464,19 @@ namespace MWGui mPlayerGold->setCaptionWithReplacing("#{sYourGold} " + boost::lexical_cast(playerGold)); + std::string balanceCaption; if (mCurrentBalance > 0) { mTotalBalanceLabel->setCaptionWithReplacing("#{sTotalSold}"); - mTotalBalance->setCaption(boost::lexical_cast(mCurrentBalance)); + balanceCaption = boost::lexical_cast(mCurrentBalance); } else { mTotalBalanceLabel->setCaptionWithReplacing("#{sTotalCost}"); - mTotalBalance->setCaption(boost::lexical_cast(-mCurrentBalance)); + balanceCaption = boost::lexical_cast(-mCurrentBalance); } + if (balanceCaption != mTotalBalance->getCaption().asUTF8()) // Don't reset text cursor if text doesn't need to be changed + mTotalBalance->setCaption(balanceCaption); mMerchantGold->setCaptionWithReplacing("#{sSellerGold} " + boost::lexical_cast(getMerchantGold())); } From 8b0cb239a932de4a8258b624eb1d8873b3505dda Mon Sep 17 00:00:00 2001 From: scrawl Date: Sun, 7 Sep 2014 04:29:39 +0200 Subject: [PATCH 03/21] Ignore text keys for zero-length animations (Fixes #1876) This fixes an issue where the Riekling's attack animation would trigger *two* hits on each swing. It has the "min hit" and "hit" keys at the same time, so the MinHitToHit segment a zero-length animation. This caused problems as the "hit" text key will be encountered twice; once when playing the "max attack to min hit" segment and once when playing the "min hit to hit" segment. --- apps/openmw/mwrender/animation.cpp | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/apps/openmw/mwrender/animation.cpp b/apps/openmw/mwrender/animation.cpp index a8b453e89..81b92dcbf 100644 --- a/apps/openmw/mwrender/animation.cpp +++ b/apps/openmw/mwrender/animation.cpp @@ -873,10 +873,13 @@ void Animation::play(const std::string &groupname, int priority, int groups, boo mStates[groupname] = state; NifOgre::TextKeyMap::const_iterator textkey(textkeys.lower_bound(state.mTime)); - while(textkey != textkeys.end() && textkey->first <= state.mTime) + if (state.mPlaying) { - handleTextKey(state, groupname, textkey, textkeys); - ++textkey; + while(textkey != textkeys.end() && textkey->first <= state.mTime) + { + handleTextKey(state, groupname, textkey, textkeys); + ++textkey; + } } if(state.mTime >= state.mLoopStopTime && state.mLoopCount > 0) @@ -887,7 +890,7 @@ void Animation::play(const std::string &groupname, int priority, int groups, boo if(state.mTime >= state.mLoopStopTime) break; - textkey = textkeys.lower_bound(state.mTime); + NifOgre::TextKeyMap::const_iterator textkey(textkeys.lower_bound(state.mTime)); while(textkey != textkeys.end() && textkey->first <= state.mTime) { handleTextKey(state, groupname, textkey, textkeys); From 6b06ab23aadd761d160ae640edd06b6c823d110d Mon Sep 17 00:00:00 2001 From: scrawl Date: Mon, 8 Sep 2014 15:30:43 +0200 Subject: [PATCH 04/21] Don't play sound for torches with OffDefault flag (Fixes #1884) --- apps/openmw/mwclass/light.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/openmw/mwclass/light.cpp b/apps/openmw/mwclass/light.cpp index 8c2decb72..eabebc72a 100644 --- a/apps/openmw/mwclass/light.cpp +++ b/apps/openmw/mwclass/light.cpp @@ -74,7 +74,7 @@ namespace MWClass if(!model.empty()) physics.addObject(ptr,ref->mBase->mData.mFlags & ESM::Light::Carry); - if (!ref->mBase->mSound.empty()) + if (!ref->mBase->mSound.empty() && !(ref->mBase->mData.mFlags & ESM::Light::OffDefault)) MWBase::Environment::get().getSoundManager()->playSound3D(ptr, ref->mBase->mSound, 1.0, 1.0, MWBase::SoundManager::Play_TypeSfx, MWBase::SoundManager::Play_Loop); From 3007af44eaf40e48af7e0397dc56725ab370e856 Mon Sep 17 00:00:00 2001 From: scrawl Date: Mon, 8 Sep 2014 20:52:15 +0200 Subject: [PATCH 05/21] Revert "Don't trigger CellChanged events when crossing exterior cell borders (Fixes #1874)" This reverts commit 0c67ff9ed0c2c20bd43195fe3d17f1ef07de5719. --- apps/openmw/mwworld/scene.cpp | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/apps/openmw/mwworld/scene.cpp b/apps/openmw/mwworld/scene.cpp index f01018ed0..80ad66743 100644 --- a/apps/openmw/mwworld/scene.cpp +++ b/apps/openmw/mwworld/scene.cpp @@ -259,10 +259,6 @@ namespace MWWorld void Scene::changeCell (int X, int Y, const ESM::Position& position, bool adjustPlayerPos) { - // CellChanged events should not trigger when crossing exterior cell borders - // TODO: check worldspace - bool cellChanged = !mCurrentCell || !mCurrentCell->isExterior(); - Loading::Listener* loadingListener = MWBase::Environment::get().getWindowManager()->getLoadingScreen(); Loading::ScopedLoad load(loadingListener); @@ -362,7 +358,7 @@ namespace MWWorld // Sky system MWBase::Environment::get().getWorld()->adjustSky(); - mCellChanged = cellChanged; + mCellChanged = true; } //We need the ogre renderer and a scene node. From 628600a0a55ab26501ef7244f5903f65a521d1a1 Mon Sep 17 00:00:00 2001 From: scrawl Date: Mon, 8 Sep 2014 23:57:16 +0200 Subject: [PATCH 06/21] Make PlaceItem place the item in the player's current worldspace --- .../mwscript/transformationextensions.cpp | 33 ++++++++++--------- 1 file changed, 17 insertions(+), 16 deletions(-) diff --git a/apps/openmw/mwscript/transformationextensions.cpp b/apps/openmw/mwscript/transformationextensions.cpp index 42f44512a..e74388eff 100644 --- a/apps/openmw/mwscript/transformationextensions.cpp +++ b/apps/openmw/mwscript/transformationextensions.cpp @@ -463,25 +463,26 @@ namespace MWScript Interpreter::Type_Float zRot = runtime[0].mFloat; runtime.pop(); - int cx,cy; - MWBase::Environment::get().getWorld()->positionToIndex(x,y,cx,cy); - MWWorld::CellStore* store = MWBase::Environment::get().getWorld()->getExterior(cx,cy); - if(store) + MWWorld::Ptr player = MWBase::Environment::get().getWorld()->getPlayerPtr(); + MWWorld::CellStore* store = NULL; + if (player.getCell()->isExterior()) { - ESM::Position pos; - pos.pos[0] = x; - pos.pos[1] = y; - pos.pos[2] = z; - pos.rot[0] = pos.rot[1] = 0; - pos.rot[2] = zRot; - MWWorld::ManualRef ref(MWBase::Environment::get().getWorld()->getStore(),itemID); - ref.getPtr().getCellRef().setPosition(pos); - MWBase::Environment::get().getWorld()->safePlaceObject(ref.getPtr(),store,pos); + int cx,cy; + MWBase::Environment::get().getWorld()->positionToIndex(x,y,cx,cy); + store = MWBase::Environment::get().getWorld()->getExterior(cx,cy); } else - { - throw std::runtime_error ("unknown cell"); - } + store = player.getCell(); + + ESM::Position pos; + pos.pos[0] = x; + pos.pos[1] = y; + pos.pos[2] = z; + pos.rot[0] = pos.rot[1] = 0; + pos.rot[2] = zRot; + MWWorld::ManualRef ref(MWBase::Environment::get().getWorld()->getStore(),itemID); + ref.getPtr().getCellRef().setPosition(pos); + MWBase::Environment::get().getWorld()->safePlaceObject(ref.getPtr(),store,pos); } }; From 457b96a8afa46375aeed6add3d5d201658dfb66d Mon Sep 17 00:00:00 2001 From: scrawl Date: Tue, 9 Sep 2014 00:00:55 +0200 Subject: [PATCH 07/21] Reset bounty and crime immediately when going to jail (Fixes #1892) --- apps/openmw/mwscript/miscextensions.cpp | 1 - apps/openmw/mwworld/worldimp.cpp | 22 ++++++++++++++-------- apps/openmw/mwworld/worldimp.hpp | 1 + 3 files changed, 15 insertions(+), 9 deletions(-) diff --git a/apps/openmw/mwscript/miscextensions.cpp b/apps/openmw/mwscript/miscextensions.cpp index 52957b00f..6da047196 100644 --- a/apps/openmw/mwscript/miscextensions.cpp +++ b/apps/openmw/mwscript/miscextensions.cpp @@ -871,7 +871,6 @@ namespace MWScript { MWBase::World* world = MWBase::Environment::get().getWorld(); world->goToJail(); - MWBase::Environment::get().getWorld()->getPlayer().recordCrimeId(); } }; diff --git a/apps/openmw/mwworld/worldimp.cpp b/apps/openmw/mwworld/worldimp.cpp index b8c83e09b..fdf1cff41 100644 --- a/apps/openmw/mwworld/worldimp.cpp +++ b/apps/openmw/mwworld/worldimp.cpp @@ -149,7 +149,7 @@ namespace MWWorld mActivationDistanceOverride (activationDistanceOverride), mFallback(fallbackMap), mTeleportEnabled(true), mLevitationEnabled(true), mGodMode(false), mContentFiles (contentFiles), - mGoToJail(false), + mGoToJail(false), mDaysInPrison(0), mStartCell (startCell), mStartupScript(startupScript) { mPhysics = new PhysicsSystem(renderer); @@ -2810,8 +2810,19 @@ namespace MWWorld { if (!mGoToJail) { - // Save for next update, since the player should be able to read the dialog text first + // Reset bounty and forget the crime now, but don't change cell yet (the player should be able to read the dialog text first) mGoToJail = true; + + MWWorld::Ptr player = getPlayerPtr(); + + int bounty = player.getClass().getNpcStats(player).getBounty(); + player.getClass().getNpcStats(player).setBounty(0); + mPlayer->recordCrimeId(); + confiscateStolenItems(player); + + int iDaysinPrisonMod = getStore().get().find("iDaysinPrisonMod")->getInt(); + mDaysInPrison = std::max(1, bounty / iDaysinPrisonMod); + return; } else @@ -2822,13 +2833,8 @@ namespace MWWorld MWWorld::Ptr player = getPlayerPtr(); teleportToClosestMarker(player, "prisonmarker"); - int bounty = player.getClass().getNpcStats(player).getBounty(); - player.getClass().getNpcStats(player).setBounty(0); - confiscateStolenItems(player); - - int iDaysinPrisonMod = getStore().get().find("iDaysinPrisonMod")->getInt(); - int days = std::max(1, bounty / iDaysinPrisonMod); + int days = mDaysInPrison; advanceTime(days * 24); for (int i=0; irest (true); diff --git a/apps/openmw/mwworld/worldimp.hpp b/apps/openmw/mwworld/worldimp.hpp index eddd056e0..dd7729331 100644 --- a/apps/openmw/mwworld/worldimp.hpp +++ b/apps/openmw/mwworld/worldimp.hpp @@ -143,6 +143,7 @@ namespace MWWorld bool mTeleportEnabled; bool mLevitationEnabled; bool mGoToJail; + int mDaysInPrison; float feetToGameUnits(float feet); From a9847c9453696a16ffb96b8d88d7699f126cf82f Mon Sep 17 00:00:00 2001 From: scrawl Date: Tue, 9 Sep 2014 00:27:25 +0200 Subject: [PATCH 08/21] Fix creature attacking flag not being reset after the attack starts (Fixes #1889) --- apps/openmw/mwmechanics/character.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/apps/openmw/mwmechanics/character.cpp b/apps/openmw/mwmechanics/character.cpp index d856b7389..c9e0f6759 100644 --- a/apps/openmw/mwmechanics/character.cpp +++ b/apps/openmw/mwmechanics/character.cpp @@ -716,6 +716,7 @@ bool CharacterController::updateCreatureState() 0.0f, 0); mUpperBodyState = UpperCharState_StartToMinAttack; } + stats.setAttackingOrSpell(false); } bool animPlaying = mAnimation->getInfo(mCurrentWeapon); From c54ab2e846920f57c3614a8dd582dc3e9d4a6897 Mon Sep 17 00:00:00 2001 From: scrawl Date: Tue, 9 Sep 2014 00:39:38 +0200 Subject: [PATCH 09/21] Don't allow talking to creatures that are in combat --- apps/openmw/mwclass/creature.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/apps/openmw/mwclass/creature.cpp b/apps/openmw/mwclass/creature.cpp index 6aa4d58ed..d5de39c9d 100644 --- a/apps/openmw/mwclass/creature.cpp +++ b/apps/openmw/mwclass/creature.cpp @@ -463,6 +463,8 @@ namespace MWClass if(getCreatureStats(ptr).isDead()) return boost::shared_ptr(new MWWorld::ActionOpen(ptr, true)); + if(ptr.getClass().getCreatureStats(ptr).getAiSequence().isInCombat()) + return boost::shared_ptr(new MWWorld::FailedAction("")); return boost::shared_ptr(new MWWorld::ActionTalk(ptr)); } From 780a48cd1e7a27e28ddda3c37090a49366cc60c0 Mon Sep 17 00:00:00 2001 From: scrawl Date: Tue, 9 Sep 2014 00:43:12 +0200 Subject: [PATCH 10/21] Don't greet dead actors in AiWander --- apps/openmw/mwmechanics/aiwander.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/apps/openmw/mwmechanics/aiwander.cpp b/apps/openmw/mwmechanics/aiwander.cpp index 2f51b6467..eafbdd59c 100644 --- a/apps/openmw/mwmechanics/aiwander.cpp +++ b/apps/openmw/mwmechanics/aiwander.cpp @@ -434,7 +434,8 @@ namespace MWMechanics if (mSaidGreeting == Greet_None) { - if ((playerDistSqr <= helloDistance*helloDistance) && MWBase::Environment::get().getWorld()->getLOS(player, actor) + if ((playerDistSqr <= helloDistance*helloDistance) && + !player.getClass().getCreatureStats(player).isDead() && MWBase::Environment::get().getWorld()->getLOS(player, actor) && MWBase::Environment::get().getMechanicsManager()->awarenessCheck(player, actor)) mGreetingTimer++; From f18d4b4ac45782fb8bc60749d398a7805cfbad86 Mon Sep 17 00:00:00 2001 From: scrawl Date: Tue, 9 Sep 2014 00:47:26 +0200 Subject: [PATCH 11/21] Don't show crosshair tooltips for actors in combat --- apps/openmw/mwclass/creature.cpp | 4 +--- apps/openmw/mwclass/npc.cpp | 4 +--- 2 files changed, 2 insertions(+), 6 deletions(-) diff --git a/apps/openmw/mwclass/creature.cpp b/apps/openmw/mwclass/creature.cpp index d5de39c9d..1523c7180 100644 --- a/apps/openmw/mwclass/creature.cpp +++ b/apps/openmw/mwclass/creature.cpp @@ -516,9 +516,7 @@ namespace MWClass bool Creature::hasToolTip (const MWWorld::Ptr& ptr) const { - /// \todo We don't want tooltips for Creatures in combat mode. - - return true; + return !ptr.getClass().getCreatureStats(ptr).getAiSequence().isInCombat(); } float Creature::getSpeed(const MWWorld::Ptr &ptr) const diff --git a/apps/openmw/mwclass/npc.cpp b/apps/openmw/mwclass/npc.cpp index f20850c96..0873480b1 100644 --- a/apps/openmw/mwclass/npc.cpp +++ b/apps/openmw/mwclass/npc.cpp @@ -1061,9 +1061,7 @@ namespace MWClass bool Npc::hasToolTip (const MWWorld::Ptr& ptr) const { - /// \todo We don't want tooltips for NPCs in combat mode. - - return true; + return !ptr.getClass().getCreatureStats(ptr).getAiSequence().isInCombat(); } MWGui::ToolTipInfo Npc::getToolTipInfo (const MWWorld::Ptr& ptr) const From d2ef0d362cfcc10f594a7ece17b40680a6d7a506 Mon Sep 17 00:00:00 2001 From: scrawl Date: Tue, 9 Sep 2014 01:52:48 +0200 Subject: [PATCH 12/21] Implement vanilla distance threshold for AI processing (Bug #1876) --- apps/openmw/mwmechanics/actors.cpp | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/apps/openmw/mwmechanics/actors.cpp b/apps/openmw/mwmechanics/actors.cpp index 9e11529dd..2abaf7591 100644 --- a/apps/openmw/mwmechanics/actors.cpp +++ b/apps/openmw/mwmechanics/actors.cpp @@ -1117,7 +1117,11 @@ namespace MWMechanics { updateActor(iter->first, duration); - if (MWBase::Environment::get().getMechanicsManager()->isAIActive()) + // AI processing is only done within distance of 7168 units to the player. Note the "AI distance" slider doesn't affect this + // (it only does some throttling for targets beyond the "AI distance", so doesn't give any guarantees as to whether AI will be enabled or not) + if (MWBase::Environment::get().getMechanicsManager()->isAIActive() && + Ogre::Vector3(player.getRefData().getPosition().pos).squaredDistance(Ogre::Vector3(iter->first.getRefData().getPosition().pos)) + <= 7168*7168) { if (timerUpdateAITargets == 0) { From cb916594d9793038aea996999bb7e49417c06e56 Mon Sep 17 00:00:00 2001 From: scrawl Date: Tue, 9 Sep 2014 02:12:44 +0200 Subject: [PATCH 13/21] Always show tooltips for dead actors --- apps/openmw/mwclass/creature.cpp | 2 +- apps/openmw/mwclass/npc.cpp | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/apps/openmw/mwclass/creature.cpp b/apps/openmw/mwclass/creature.cpp index 1523c7180..139f390f8 100644 --- a/apps/openmw/mwclass/creature.cpp +++ b/apps/openmw/mwclass/creature.cpp @@ -516,7 +516,7 @@ namespace MWClass bool Creature::hasToolTip (const MWWorld::Ptr& ptr) const { - return !ptr.getClass().getCreatureStats(ptr).getAiSequence().isInCombat(); + return !ptr.getClass().getCreatureStats(ptr).getAiSequence().isInCombat() || getCreatureStats(ptr).isDead(); } float Creature::getSpeed(const MWWorld::Ptr &ptr) const diff --git a/apps/openmw/mwclass/npc.cpp b/apps/openmw/mwclass/npc.cpp index 0873480b1..24332df75 100644 --- a/apps/openmw/mwclass/npc.cpp +++ b/apps/openmw/mwclass/npc.cpp @@ -1061,7 +1061,7 @@ namespace MWClass bool Npc::hasToolTip (const MWWorld::Ptr& ptr) const { - return !ptr.getClass().getCreatureStats(ptr).getAiSequence().isInCombat(); + return !ptr.getClass().getCreatureStats(ptr).getAiSequence().isInCombat() || getCreatureStats(ptr).isDead(); } MWGui::ToolTipInfo Npc::getToolTipInfo (const MWWorld::Ptr& ptr) const From 56cd0da52270a66b3bc5b0f17541fcaef565185b Mon Sep 17 00:00:00 2001 From: scrawl Date: Tue, 9 Sep 2014 04:44:14 +0200 Subject: [PATCH 14/21] Fix potential infinite recursion when an area effect spell is reflected (Fixes #1896) --- apps/openmw/mwmechanics/spellcasting.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/openmw/mwmechanics/spellcasting.cpp b/apps/openmw/mwmechanics/spellcasting.cpp index a1f0d994a..373ca7af9 100644 --- a/apps/openmw/mwmechanics/spellcasting.cpp +++ b/apps/openmw/mwmechanics/spellcasting.cpp @@ -519,7 +519,7 @@ namespace MWMechanics MWBase::Environment::get().getWorld()->explodeSpell(mHitPosition, effects, caster, mId, mSourceName); if (!reflectedEffects.mList.empty()) - inflict(caster, target, reflectedEffects, range, true); + inflict(caster, target, reflectedEffects, range, true, exploded); if (!appliedLastingEffects.empty()) { From dd5f4947d7d43113bb711d6e7c1a0e3d56f17e30 Mon Sep 17 00:00:00 2001 From: scrawl Date: Tue, 9 Sep 2014 05:05:07 +0200 Subject: [PATCH 15/21] Add a TODO comment --- apps/openmw/mwmechanics/character.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/apps/openmw/mwmechanics/character.cpp b/apps/openmw/mwmechanics/character.cpp index c9e0f6759..9d1e5e52f 100644 --- a/apps/openmw/mwmechanics/character.cpp +++ b/apps/openmw/mwmechanics/character.cpp @@ -912,6 +912,7 @@ bool CharacterController::updateWeaponState() else if(mWeaponType == WeapType_PickProbe) { MWWorld::Ptr item = *weapon; + // TODO: this will only work for the player, and needs to be fixed if NPCs should ever use lockpicks/probes. MWWorld::Ptr target = MWBase::Environment::get().getWorld()->getFacedObject(); std::string resultMessage, resultSound; From 616148e16863108067065d99168ff1b166251c84 Mon Sep 17 00:00:00 2001 From: scrawl Date: Tue, 9 Sep 2014 18:28:17 +0200 Subject: [PATCH 16/21] Fix "failed to open file" error when no startup script is given --- apps/openmw/mwworld/worldimp.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/apps/openmw/mwworld/worldimp.cpp b/apps/openmw/mwworld/worldimp.cpp index fdf1cff41..93253597c 100644 --- a/apps/openmw/mwworld/worldimp.cpp +++ b/apps/openmw/mwworld/worldimp.cpp @@ -259,7 +259,8 @@ namespace MWWorld mWeatherManager = 0; mWeatherManager = new MWWorld::WeatherManager(mRendering,&mFallback); - MWBase::Environment::get().getWindowManager()->executeInConsole(mStartupScript); + if (!mStartupScript.empty()) + MWBase::Environment::get().getWindowManager()->executeInConsole(mStartupScript); } void World::clear() From cf355d0fcb82799efd9cb17b8a6d4841fe1c49f8 Mon Sep 17 00:00:00 2001 From: scrawl Date: Wed, 10 Sep 2014 17:57:28 +0200 Subject: [PATCH 17/21] Change Always Run key default to Caps Lock, as in vanilla A poor choice, but it's still what players coming from vanilla MW will expect. --- apps/openmw/mwinput/inputmanagerimp.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/openmw/mwinput/inputmanagerimp.cpp b/apps/openmw/mwinput/inputmanagerimp.cpp index e1f7c31fc..6e182d6cd 100644 --- a/apps/openmw/mwinput/inputmanagerimp.cpp +++ b/apps/openmw/mwinput/inputmanagerimp.cpp @@ -894,7 +894,7 @@ namespace MWInput defaultKeyBindings[A_QuickKey10] = SDL_GetKeyFromScancode(SDL_SCANCODE_0); defaultKeyBindings[A_Screenshot] = SDL_GetKeyFromScancode(SDL_SCANCODE_F12); defaultKeyBindings[A_ToggleHUD] = SDL_GetKeyFromScancode(SDL_SCANCODE_F11); - defaultKeyBindings[A_AlwaysRun] = SDL_GetKeyFromScancode(SDL_SCANCODE_Y); + defaultKeyBindings[A_AlwaysRun] = SDL_GetKeyFromScancode(SDL_SCANCODE_CAPSLOCK); defaultKeyBindings[A_QuickSave] = SDL_GetKeyFromScancode(SDL_SCANCODE_F5); defaultKeyBindings[A_QuickLoad] = SDL_GetKeyFromScancode(SDL_SCANCODE_F9); From ebab911e440676bef16151b74335a89725ef373c Mon Sep 17 00:00:00 2001 From: scrawl Date: Wed, 10 Sep 2014 17:58:53 +0200 Subject: [PATCH 18/21] Add a hack to support binding the console to a printable key (Fixes #371) and change default console key to morrowind default (GRAVE) --- apps/openmw/mwinput/inputmanagerimp.cpp | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/apps/openmw/mwinput/inputmanagerimp.cpp b/apps/openmw/mwinput/inputmanagerimp.cpp index 6e182d6cd..2a0acf416 100644 --- a/apps/openmw/mwinput/inputmanagerimp.cpp +++ b/apps/openmw/mwinput/inputmanagerimp.cpp @@ -498,7 +498,14 @@ namespace MWInput void InputManager::keyPressed( const SDL_KeyboardEvent &arg ) { + // HACK: to make Morrowind's default keybinding for the console work without printing an extra "^" upon closing + // This assumes that SDL_TextInput events always come *after* the key event + // (which is somewhat reasonable, and hopefully true for all SDL platforms) OIS::KeyCode kc = mInputManager->sdl2OISKeyCode(arg.keysym.sym); + if (mInputBinder->getKeyBinding(mInputBinder->getControl(A_Console), ICS::Control::INCREASE) + == arg.keysym.sym + && MWBase::Environment::get().getWindowManager()->getMode() == MWGui::GM_Console) + SDL_StopTextInput(); bool consumed = false; if (kc != OIS::KC_UNASSIGNED) @@ -873,7 +880,7 @@ namespace MWInput defaultKeyBindings[A_ToggleWeapon] = SDL_GetKeyFromScancode(SDL_SCANCODE_F); defaultKeyBindings[A_ToggleSpell] = SDL_GetKeyFromScancode(SDL_SCANCODE_R); defaultKeyBindings[A_QuickKeysMenu] = SDL_GetKeyFromScancode(SDL_SCANCODE_F1); - defaultKeyBindings[A_Console] = SDL_GetKeyFromScancode(SDL_SCANCODE_F2); + defaultKeyBindings[A_Console] = SDL_GetKeyFromScancode(SDL_SCANCODE_GRAVE); defaultKeyBindings[A_Run] = SDL_GetKeyFromScancode(SDL_SCANCODE_LSHIFT); defaultKeyBindings[A_Sneak] = SDL_GetKeyFromScancode(SDL_SCANCODE_LCTRL); defaultKeyBindings[A_AutoMove] = SDL_GetKeyFromScancode(SDL_SCANCODE_Q); From 7fa3100993da31665e6f7e7a465e9e949efa542f Mon Sep 17 00:00:00 2001 From: scrawl Date: Thu, 11 Sep 2014 00:25:09 +0200 Subject: [PATCH 19/21] Refactor TradeWindow balance buttons to use ControllerRepeatClick --- apps/openmw/mwgui/tradewindow.cpp | 43 +++++++++++++------------- apps/openmw/mwgui/tradewindow.hpp | 13 ++------ apps/openmw/mwgui/windowmanagerimp.cpp | 1 - 3 files changed, 24 insertions(+), 33 deletions(-) diff --git a/apps/openmw/mwgui/tradewindow.cpp b/apps/openmw/mwgui/tradewindow.cpp index 8126a4ee8..67bdc14ac 100644 --- a/apps/openmw/mwgui/tradewindow.cpp +++ b/apps/openmw/mwgui/tradewindow.cpp @@ -22,6 +22,7 @@ #include "tradeitemmodel.hpp" #include "countdialog.hpp" #include "dialogue.hpp" +#include "controllers.hpp" namespace { @@ -44,8 +45,6 @@ namespace MWGui TradeWindow::TradeWindow() : WindowBase("openmw_trade_window.layout") , mCurrentBalance(0) - , mBalanceButtonsState(BBS_None) - , mBalanceChangePause(0.0) , mItemToSell(-1) , mTradeModel(NULL) , mSortModel(NULL) @@ -240,21 +239,6 @@ namespace MWGui } } - void TradeWindow::onFrame(float frameDuration) - { - if (!mMainWidget->getVisible() || mBalanceButtonsState == BBS_None) - return; - - mBalanceChangePause -= frameDuration; - if (mBalanceChangePause < 0.0) { - mBalanceChangePause += sBalanceChangeInterval; - if (mBalanceButtonsState == BBS_Increase) - onIncreaseButtonTriggered(); - else if (mBalanceButtonsState == BBS_Decrease) - onDecreaseButtonTriggered(); - } - } - void TradeWindow::onOfferButtonClicked(MyGUI::Widget* _sender) { TradeItemModel* playerItemModel = MWBase::Environment::get().getWindowManager()->getInventoryWindow()->getTradeModel(); @@ -407,23 +391,38 @@ namespace MWGui updateLabels(); } + void TradeWindow::addRepeatController(MyGUI::Widget *widget) + { + MyGUI::ControllerItem* item = MyGUI::ControllerManager::getInstance().createItem(Controllers::ControllerRepeatClick::getClassTypeName()); + Controllers::ControllerRepeatClick* controller = item->castType(); + controller->eventRepeatClick += MyGUI::newDelegate(this, &TradeWindow::onRepeatClick); + controller->setRepeat(sBalanceChangeInitialPause, sBalanceChangeInterval); + MyGUI::ControllerManager::getInstance().addItem(widget, controller); + } + void TradeWindow::onIncreaseButtonPressed(MyGUI::Widget* _sender, int _left, int _top, MyGUI::MouseButton _id) { - mBalanceButtonsState = BBS_Increase; - mBalanceChangePause = sBalanceChangeInitialPause; + addRepeatController(_sender); onIncreaseButtonTriggered(); } void TradeWindow::onDecreaseButtonPressed(MyGUI::Widget* _sender, int _left, int _top, MyGUI::MouseButton _id) { - mBalanceButtonsState = BBS_Decrease; - mBalanceChangePause = sBalanceChangeInitialPause; + addRepeatController(_sender); onDecreaseButtonTriggered(); } + void TradeWindow::onRepeatClick(MyGUI::Widget* widget, MyGUI::ControllerItem* controller) + { + if (widget == mIncreaseButton) + onIncreaseButtonTriggered(); + else if (widget == mDecreaseButton) + onDecreaseButtonTriggered(); + } + void TradeWindow::onBalanceButtonReleased(MyGUI::Widget *_sender, int _left, int _top, MyGUI::MouseButton _id) { - mBalanceButtonsState = BBS_None; + MyGUI::ControllerManager::getInstance().removeItem(_sender); } void TradeWindow::onBalanceEdited(MyGUI::EditBox *_sender) diff --git a/apps/openmw/mwgui/tradewindow.hpp b/apps/openmw/mwgui/tradewindow.hpp index 7baf0ce8e..b822331c3 100644 --- a/apps/openmw/mwgui/tradewindow.hpp +++ b/apps/openmw/mwgui/tradewindow.hpp @@ -28,8 +28,6 @@ namespace MWGui void startTrade(const MWWorld::Ptr& actor); - void onFrame(float frameDuration); - void borrowItem (int index, size_t count); void returnItem (int index, size_t count); @@ -71,14 +69,6 @@ namespace MWGui int mCurrentBalance; int mCurrentMerchantOffer; - enum BalanceButtonsState { - BBS_None, - BBS_Increase, - BBS_Decrease - } mBalanceButtonsState; - /// pause before next balance change will trigger while user holds +/- button pressed - float mBalanceChangePause; - void sellToNpc(const MWWorld::Ptr& item, int count, bool boughtItem); ///< only used for adjusting the gold balance void buyFromNpc(const MWWorld::Ptr& item, int count, bool soldItem); ///< only used for adjusting the gold balance @@ -93,6 +83,9 @@ namespace MWGui void onDecreaseButtonPressed(MyGUI::Widget* _sender, int _left, int _top, MyGUI::MouseButton _id); void onBalanceButtonReleased(MyGUI::Widget* _sender, int _left, int _top, MyGUI::MouseButton _id); void onBalanceEdited(MyGUI::EditBox* _sender); + void onRepeatClick(MyGUI::Widget* widget, MyGUI::ControllerItem* controller); + + void addRepeatController(MyGUI::Widget* widget); void onIncreaseButtonTriggered(); void onDecreaseButtonTriggered(); diff --git a/apps/openmw/mwgui/windowmanagerimp.cpp b/apps/openmw/mwgui/windowmanagerimp.cpp index a750e266c..f6ad6500c 100644 --- a/apps/openmw/mwgui/windowmanagerimp.cpp +++ b/apps/openmw/mwgui/windowmanagerimp.cpp @@ -848,7 +848,6 @@ namespace MWGui mHud->onFrame(frameDuration); mTrainingWindow->onFrame (frameDuration); - mTradeWindow->onFrame(frameDuration); mTrainingWindow->checkReferenceAvailable(); mDialogueWindow->checkReferenceAvailable(); From 36a90198e2586e8f7a3d29d48c5ca523affc12b8 Mon Sep 17 00:00:00 2001 From: scrawl Date: Thu, 11 Sep 2014 04:28:14 +0200 Subject: [PATCH 20/21] Add option to change screenshot image format --- apps/openmw/engine.cpp | 6 +++--- files/settings-default.cfg | 2 ++ libs/openengine/ogre/renderer.cpp | 4 ++-- libs/openengine/ogre/renderer.hpp | 2 +- 4 files changed, 8 insertions(+), 6 deletions(-) diff --git a/apps/openmw/engine.cpp b/apps/openmw/engine.cpp index fa4c69337..1247ceda1 100644 --- a/apps/openmw/engine.cpp +++ b/apps/openmw/engine.cpp @@ -509,7 +509,7 @@ void OMW::Engine::screenshot() int shotCount = 0; const std::string& screenshotPath = mCfgMgr.getUserDataPath().string(); - + std::string format = Settings::Manager::getString("screenshot format", "General"); // Find the first unused filename with a do-while std::ostringstream stream; do @@ -518,11 +518,11 @@ void OMW::Engine::screenshot() stream.str(""); stream.clear(); - stream << screenshotPath << "screenshot" << std::setw(3) << std::setfill('0') << shotCount++ << ".png"; + stream << screenshotPath << "screenshot" << std::setw(3) << std::setfill('0') << shotCount++ << "." << format; } while (boost::filesystem::exists(stream.str())); - mOgre->screenshot(stream.str()); + mOgre->screenshot(stream.str(), format); } void OMW::Engine::setCompileAll (bool all) diff --git a/files/settings-default.cfg b/files/settings-default.cfg index ab9de47a4..fc651f463 100644 --- a/files/settings-default.cfg +++ b/files/settings-default.cfg @@ -60,6 +60,8 @@ num mipmaps = 8 shader mode = +screenshot format = png + [Shadows] # Shadows are only supported when object shaders are on! enabled = false diff --git a/libs/openengine/ogre/renderer.cpp b/libs/openengine/ogre/renderer.cpp index 78eff6aee..fa98433ac 100644 --- a/libs/openengine/ogre/renderer.cpp +++ b/libs/openengine/ogre/renderer.cpp @@ -44,7 +44,7 @@ void OgreRenderer::update(float dt) { } -void OgreRenderer::screenshot(const std::string &file) +void OgreRenderer::screenshot(const std::string &file, const std::string& imageFormat) { /* Since Ogre uses narrow character interfaces, it does not support Unicode paths on Windows. Therefore we had to implement screenshot @@ -65,7 +65,7 @@ void OgreRenderer::screenshot(const std::string &file) ); mWindow->copyContentsToMemory(image.getPixelBox()); - Ogre::DataStreamPtr stream = image.encode("png"); + Ogre::DataStreamPtr stream = image.encode(imageFormat); Ogre::MemoryDataStream *mem = dynamic_cast(stream.get()); if (mem != 0) { // likely const char *ptr = reinterpret_cast(mem->getCurrentPtr()); diff --git a/libs/openengine/ogre/renderer.hpp b/libs/openengine/ogre/renderer.hpp index c7ec2ec44..5dba15b5a 100644 --- a/libs/openengine/ogre/renderer.hpp +++ b/libs/openengine/ogre/renderer.hpp @@ -108,7 +108,7 @@ namespace OEngine void update(float dt); /// Write a screenshot to file - void screenshot(const std::string &file); + void screenshot(const std::string &file, const std::string& imageFormat); float getFPS(); From f3d4b63aaf39d20ac9f9c10b9a376eb24b348cb7 Mon Sep 17 00:00:00 2001 From: scrawl Date: Thu, 11 Sep 2014 05:48:46 +0200 Subject: [PATCH 21/21] Fix AI moving load doors and throw an exception when trying to do this (Fixes #1907) --- apps/openmw/mwbase/world.hpp | 1 + apps/openmw/mwclass/door.cpp | 3 +++ apps/openmw/mwmechanics/aipackage.cpp | 2 +- apps/openmw/mwscript/miscextensions.cpp | 2 +- apps/openmw/mwworld/worldimp.hpp | 1 + 5 files changed, 7 insertions(+), 2 deletions(-) diff --git a/apps/openmw/mwbase/world.hpp b/apps/openmw/mwbase/world.hpp index f07bb3eb9..2055aeeae 100644 --- a/apps/openmw/mwbase/world.hpp +++ b/apps/openmw/mwbase/world.hpp @@ -396,6 +396,7 @@ namespace MWBase virtual void activateDoor(const MWWorld::Ptr& door) = 0; /// update movement state of a non-teleport door as specified /// @param state see MWClass::setDoorState + /// @note throws an exception when invoked on a teleport door virtual void activateDoor(const MWWorld::Ptr& door, int state) = 0; virtual bool getPlayerStandingOn (const MWWorld::Ptr& object) = 0; ///< @return true if the player is standing on \a object diff --git a/apps/openmw/mwclass/door.cpp b/apps/openmw/mwclass/door.cpp index 153432af6..fa9db9e16 100644 --- a/apps/openmw/mwclass/door.cpp +++ b/apps/openmw/mwclass/door.cpp @@ -324,6 +324,9 @@ namespace MWClass void Door::setDoorState (const MWWorld::Ptr &ptr, int state) const { + if (ptr.getCellRef().getTeleport()) + throw std::runtime_error("load doors can't be moved"); + ensureCustomData(ptr); DoorCustomData& customData = dynamic_cast(*ptr.getRefData().getCustomData()); customData.mDoorState = state; diff --git a/apps/openmw/mwmechanics/aipackage.cpp b/apps/openmw/mwmechanics/aipackage.cpp index ff0329341..f015bb8a4 100644 --- a/apps/openmw/mwmechanics/aipackage.cpp +++ b/apps/openmw/mwmechanics/aipackage.cpp @@ -97,7 +97,7 @@ bool MWMechanics::AiPackage::pathTo(const MWWorld::Ptr& actor, ESM::Pathgrid::Po MWWorld::Ptr door = getNearbyDoor(actor); if(door != MWWorld::Ptr()) // NOTE: checks interior cells only { - if(door.getCellRef().getTrap().empty() && door.getClass().getDoorState(door) == 0) { //Open the door if untrapped + if(!door.getCellRef().getTeleport() && door.getCellRef().getTrap().empty() && door.getClass().getDoorState(door) == 0) { //Open the door if untrapped MWBase::Environment::get().getWorld()->activateDoor(door, 1); } } diff --git a/apps/openmw/mwscript/miscextensions.cpp b/apps/openmw/mwscript/miscextensions.cpp index 6da047196..bd91943ad 100644 --- a/apps/openmw/mwscript/miscextensions.cpp +++ b/apps/openmw/mwscript/miscextensions.cpp @@ -148,7 +148,7 @@ namespace MWScript // Instantly reset door to closed state // This is done when using Lock in scripts, but not when using Lock spells. - if (ptr.getTypeName() == typeid(ESM::Door).name()) + if (ptr.getTypeName() == typeid(ESM::Door).name() && !ptr.getCellRef().getTeleport()) { MWBase::Environment::get().getWorld()->activateDoor(ptr, 0); MWBase::Environment::get().getWorld()->localRotateObject(ptr, 0, 0, 0); diff --git a/apps/openmw/mwworld/worldimp.hpp b/apps/openmw/mwworld/worldimp.hpp index dd7729331..4363f77fb 100644 --- a/apps/openmw/mwworld/worldimp.hpp +++ b/apps/openmw/mwworld/worldimp.hpp @@ -477,6 +477,7 @@ namespace MWWorld /// update movement state of a non-teleport door as specified /// @param state see MWClass::setDoorState + /// @note throws an exception when invoked on a teleport door virtual void activateDoor(const MWWorld::Ptr& door, int state); virtual bool getPlayerStandingOn (const MWWorld::Ptr& object); ///< @return true if the player is standing on \a object