From 301dd77efb444da863aea35fdca93e5899e52471 Mon Sep 17 00:00:00 2001 From: MiroslavR Date: Thu, 20 Oct 2016 02:12:01 +0200 Subject: [PATCH 1/3] Save controls state (Fixes #3598) --- apps/openmw/mwbase/inputmanager.hpp | 17 ++++++++++ apps/openmw/mwinput/inputmanagerimp.cpp | 41 +++++++++++++++++++++++ apps/openmw/mwinput/inputmanagerimp.hpp | 4 +++ apps/openmw/mwstate/statemanagerimp.cpp | 8 ++++- components/CMakeLists.txt | 2 +- components/esm/controlsstate.cpp | 43 +++++++++++++++++++++++++ components/esm/controlsstate.hpp | 39 ++++++++++++++++++++++ components/esm/defs.hpp | 1 + 8 files changed, 153 insertions(+), 2 deletions(-) create mode 100644 components/esm/controlsstate.cpp create mode 100644 components/esm/controlsstate.hpp diff --git a/apps/openmw/mwbase/inputmanager.hpp b/apps/openmw/mwbase/inputmanager.hpp index 75c55e028..0eb06ee3d 100644 --- a/apps/openmw/mwbase/inputmanager.hpp +++ b/apps/openmw/mwbase/inputmanager.hpp @@ -5,6 +5,19 @@ #include #include +#include + +namespace Loading +{ + class Listener; +} + +namespace ESM +{ + class ESMReader; + class ESMWriter; +} + namespace MWBase { /// \brief Interface for input manager (implemented in MWInput) @@ -56,6 +69,10 @@ namespace MWBase /// Returns if the last used input device was a joystick or a keyboard /// @return true if joystick, false otherwise virtual bool joystickLastUsed() = 0; + + virtual int countSavedGameRecords() const = 0; + virtual void write(ESM::ESMWriter& writer, Loading::Listener& progress) = 0; + virtual void readRecord(ESM::ESMReader& reader, uint32_t type) = 0; }; } diff --git a/apps/openmw/mwinput/inputmanagerimp.cpp b/apps/openmw/mwinput/inputmanagerimp.cpp index 6c2e695e6..2f49d3463 100644 --- a/apps/openmw/mwinput/inputmanagerimp.cpp +++ b/apps/openmw/mwinput/inputmanagerimp.cpp @@ -16,6 +16,9 @@ #include #include +#include +#include +#include #include "../mwbase/world.hpp" #include "../mwbase/windowmanager.hpp" @@ -1574,6 +1577,44 @@ namespace MWInput mInputBinder->removeJoystickButtonBinding (mFakeDeviceID, mInputBinder->getJoystickButtonBinding (control, mFakeDeviceID, ICS::Control::INCREASE)); } + int InputManager::countSavedGameRecords() const + { + return 1; + } + + void InputManager::write(ESM::ESMWriter& writer, Loading::Listener& /*progress*/) + { + ESM::ControlsState controls; + controls.mViewSwitchDisabled = !getControlSwitch("playerviewswitch"); + controls.mControlsDisabled = !getControlSwitch("playercontrols"); + controls.mJumpingDisabled = !getControlSwitch("playerjumping"); + controls.mLookingDisabled = !getControlSwitch("playerlooking"); + controls.mVanityModeDisabled = !getControlSwitch("vanitymode"); + controls.mWeaponDrawingDisabled = !getControlSwitch("playerfighting"); + controls.mSpellDrawingDisabled = !getControlSwitch("playermagic"); + + writer.startRecord (ESM::REC_INPU); + controls.save(writer); + writer.endRecord (ESM::REC_INPU); + } + + void InputManager::readRecord(ESM::ESMReader& reader, uint32_t type) + { + if (type == ESM::REC_INPU) + { + ESM::ControlsState controls; + controls.load(reader); + + toggleControlSwitch("playerviewswitch", !controls.mViewSwitchDisabled); + toggleControlSwitch("playercontrols", !controls.mControlsDisabled); + toggleControlSwitch("playerjumping", !controls.mJumpingDisabled); + toggleControlSwitch("playerlooking", !controls.mLookingDisabled); + toggleControlSwitch("vanitymode", !controls.mVanityModeDisabled); + toggleControlSwitch("playerfighting", !controls.mWeaponDrawingDisabled); + toggleControlSwitch("playermagic", !controls.mSpellDrawingDisabled); + } + } + void InputManager::resetToDefaultKeyBindings() { loadKeyDefaults(true); diff --git a/apps/openmw/mwinput/inputmanagerimp.hpp b/apps/openmw/mwinput/inputmanagerimp.hpp index 644391688..8809f44cd 100644 --- a/apps/openmw/mwinput/inputmanagerimp.hpp +++ b/apps/openmw/mwinput/inputmanagerimp.hpp @@ -149,6 +149,10 @@ namespace MWInput void clearAllKeyBindings (ICS::Control* control); void clearAllControllerBindings (ICS::Control* control); + virtual int countSavedGameRecords() const; + virtual void write(ESM::ESMWriter& writer, Loading::Listener& progress); + virtual void readRecord(ESM::ESMReader& reader, uint32_t type); + private: SDL_Window* mWindow; bool mWindowVisible; diff --git a/apps/openmw/mwstate/statemanagerimp.cpp b/apps/openmw/mwstate/statemanagerimp.cpp index 48cc37935..58d85fe5b 100644 --- a/apps/openmw/mwstate/statemanagerimp.cpp +++ b/apps/openmw/mwstate/statemanagerimp.cpp @@ -249,7 +249,8 @@ void MWState::StateManager::saveGame (const std::string& description, const Slot +MWBase::Environment::get().getScriptManager()->getGlobalScripts().countSavedGameRecords() +MWBase::Environment::get().getDialogueManager()->countSavedGameRecords() +MWBase::Environment::get().getWindowManager()->countSavedGameRecords() - +MWBase::Environment::get().getMechanicsManager()->countSavedGameRecords(); + +MWBase::Environment::get().getMechanicsManager()->countSavedGameRecords() + +MWBase::Environment::get().getInputManager()->countSavedGameRecords(); writer.setRecordCount (recordCount); writer.save (stream); @@ -271,6 +272,7 @@ void MWState::StateManager::saveGame (const std::string& description, const Slot MWBase::Environment::get().getScriptManager()->getGlobalScripts().write (writer, listener); MWBase::Environment::get().getWindowManager()->write(writer, listener); MWBase::Environment::get().getMechanicsManager()->write(writer, listener); + MWBase::Environment::get().getInputManager()->write(writer, listener); // Ensure we have written the number of records that was estimated if (writer.getRecordCount() != recordCount+1) // 1 extra for TES3 record @@ -462,6 +464,10 @@ void MWState::StateManager::loadGame (const Character *character, const std::str MWBase::Environment::get().getMechanicsManager()->readRecord(reader, n.intval); break; + case ESM::REC_INPU: + MWBase::Environment::get().getInputManager()->readRecord(reader, n.intval); + break; + default: // ignore invalid records diff --git a/components/CMakeLists.txt b/components/CMakeLists.txt index d6063c230..51faaba1d 100644 --- a/components/CMakeLists.txt +++ b/components/CMakeLists.txt @@ -77,7 +77,7 @@ add_component_dir (esm loadweap records aipackage effectlist spelllist variant variantimp loadtes3 cellref filter savedgame journalentry queststate locals globalscript player objectstate cellid cellstate globalmap inventorystate containerstate npcstate creaturestate dialoguestate statstate npcstats creaturestats weatherstate quickkeys fogstate spellstate activespells creaturelevliststate doorstate projectilestate debugprofile - aisequence magiceffects util custommarkerstate stolenitems transport animationstate + aisequence magiceffects util custommarkerstate stolenitems transport animationstate controlsstate ) add_component_dir (esmterrain diff --git a/components/esm/controlsstate.cpp b/components/esm/controlsstate.cpp new file mode 100644 index 000000000..ae4e1dff1 --- /dev/null +++ b/components/esm/controlsstate.cpp @@ -0,0 +1,43 @@ +#include "controlsstate.hpp" + +#include "esmreader.hpp" +#include "esmwriter.hpp" + +ESM::ControlsState::ControlsState() + : mViewSwitchDisabled(false), + mControlsDisabled(false), + mJumpingDisabled(false), + mLookingDisabled(false), + mVanityModeDisabled(false), + mWeaponDrawingDisabled(false), + mSpellDrawingDisabled(false) +{ +} + +void ESM::ControlsState::load(ESM::ESMReader& esm) +{ + int flags; + esm.getHNT(flags, "CFLG"); + + mViewSwitchDisabled = flags & ViewSwitchDisabled; + mControlsDisabled = flags & ControlsDisabled; + mJumpingDisabled = flags & JumpingDisabled; + mLookingDisabled = flags & LookingDisabled; + mVanityModeDisabled = flags & VanityModeDisabled; + mWeaponDrawingDisabled = flags & WeaponDrawingDisabled; + mSpellDrawingDisabled = flags & SpellDrawingDisabled; +} + +void ESM::ControlsState::save(ESM::ESMWriter& esm) const +{ + int flags = 0; + if (mViewSwitchDisabled) flags |= ViewSwitchDisabled; + if (mControlsDisabled) flags |= ControlsDisabled; + if (mJumpingDisabled) flags |= JumpingDisabled; + if (mLookingDisabled) flags |= LookingDisabled; + if (mVanityModeDisabled) flags |= VanityModeDisabled; + if (mWeaponDrawingDisabled) flags |= WeaponDrawingDisabled; + if (mSpellDrawingDisabled) flags |= SpellDrawingDisabled; + + esm.writeHNT("CFLG", flags); +} diff --git a/components/esm/controlsstate.hpp b/components/esm/controlsstate.hpp new file mode 100644 index 000000000..b9654ea1a --- /dev/null +++ b/components/esm/controlsstate.hpp @@ -0,0 +1,39 @@ +#ifndef OPENMW_ESM_CONTROLSSTATE_H +#define OPENMW_ESM_CONTROLSSTATE_H + +namespace ESM +{ + class ESMReader; + class ESMWriter; + + // format 0, saved games only + + struct ControlsState + { + ControlsState(); + + enum Flags + { + ViewSwitchDisabled = 0x1, + ControlsDisabled = 0x4, + JumpingDisabled = 0x1000, + LookingDisabled = 0x2000, + VanityModeDisabled = 0x4000, + WeaponDrawingDisabled = 0x8000, + SpellDrawingDisabled = 0x10000 + }; + + bool mViewSwitchDisabled; + bool mControlsDisabled; + bool mJumpingDisabled; + bool mLookingDisabled; + bool mVanityModeDisabled; + bool mWeaponDrawingDisabled; + bool mSpellDrawingDisabled; + + void load (ESMReader &esm); + void save (ESMWriter &esm) const; + }; +} + +#endif diff --git a/components/esm/defs.hpp b/components/esm/defs.hpp index 8066b622a..0f0478faa 100644 --- a/components/esm/defs.hpp +++ b/components/esm/defs.hpp @@ -127,6 +127,7 @@ enum RecNameInts REC_ENAB = FourCC<'E','N','A','B'>::value, REC_CAM_ = FourCC<'C','A','M','_'>::value, REC_STLN = FourCC<'S','T','L','N'>::value, + REC_INPU = FourCC<'I','N','P','U'>::value, // format 1 REC_FILT = FourCC<'F','I','L','T'>::value, From f3ce0840be09f1efff55b7768a5a690c5eaeece6 Mon Sep 17 00:00:00 2001 From: MiroslavR Date: Thu, 20 Oct 2016 02:14:36 +0200 Subject: [PATCH 2/3] Import controls state from vanilla savegames --- apps/essimporter/converter.hpp | 2 +- apps/essimporter/convertplayer.cpp | 16 ++++++++++++---- apps/essimporter/convertplayer.hpp | 3 ++- apps/essimporter/importer.cpp | 4 ++++ apps/essimporter/importercontext.hpp | 3 +++ apps/essimporter/importplayer.hpp | 21 ++++++++++++--------- 6 files changed, 34 insertions(+), 15 deletions(-) diff --git a/apps/essimporter/converter.hpp b/apps/essimporter/converter.hpp index 11f966446..5e46e4309 100644 --- a/apps/essimporter/converter.hpp +++ b/apps/essimporter/converter.hpp @@ -278,7 +278,7 @@ public: PCDT pcdt; pcdt.load(esm); - convertPCDT(pcdt, mContext->mPlayer, mContext->mDialogueState.mKnownTopics, mFirstPersonCam); + convertPCDT(pcdt, mContext->mPlayer, mContext->mDialogueState.mKnownTopics, mFirstPersonCam, mContext->mControlsState); } virtual void write(ESM::ESMWriter &esm) { diff --git a/apps/essimporter/convertplayer.cpp b/apps/essimporter/convertplayer.cpp index 55aaad1c5..c7bd8526c 100644 --- a/apps/essimporter/convertplayer.cpp +++ b/apps/essimporter/convertplayer.cpp @@ -5,7 +5,7 @@ namespace ESSImport { - void convertPCDT(const PCDT& pcdt, ESM::Player& out, std::vector& outDialogueTopics, bool& firstPersonCam) + void convertPCDT(const PCDT& pcdt, ESM::Player& out, std::vector& outDialogueTopics, bool& firstPersonCam, ESM::ControlsState& controls) { out.mBirthsign = pcdt.mBirthsign; out.mObject.mNpcStats.mBounty = pcdt.mBounty; @@ -25,18 +25,26 @@ namespace ESSImport out.mObject.mNpcStats.mSkills[i].mProgress = pcdt.mPNAM.mSkillProgress[i]; out.mObject.mNpcStats.mLevelProgress = pcdt.mPNAM.mLevelProgress; - if (pcdt.mPNAM.mDrawState & PCDT::DrawState_Weapon) + if (pcdt.mPNAM.mPlayerFlags & PCDT::PlayerFlags_WeaponDrawn) out.mObject.mCreatureStats.mDrawState = 1; - if (pcdt.mPNAM.mDrawState & PCDT::DrawState_Spell) + if (pcdt.mPNAM.mPlayerFlags & PCDT::PlayerFlags_SpellDrawn) out.mObject.mCreatureStats.mDrawState = 2; - firstPersonCam = !(pcdt.mPNAM.mCameraFlags & PCDT::CameraFlag_ThirdPerson); + firstPersonCam = !(pcdt.mPNAM.mPlayerFlags & PCDT::PlayerFlags_ThirdPerson); for (std::vector::const_iterator it = pcdt.mKnownDialogueTopics.begin(); it != pcdt.mKnownDialogueTopics.end(); ++it) { outDialogueTopics.push_back(Misc::StringUtils::lowerCase(*it)); } + + controls.mViewSwitchDisabled = pcdt.mPNAM.mPlayerFlags & PCDT::PlayerFlags_ViewSwitchDisabled; + controls.mControlsDisabled = pcdt.mPNAM.mPlayerFlags & PCDT::PlayerFlags_ControlsDisabled; + controls.mJumpingDisabled = pcdt.mPNAM.mPlayerFlags & PCDT::PlayerFlags_JumpingDisabled; + controls.mLookingDisabled = pcdt.mPNAM.mPlayerFlags & PCDT::PlayerFlags_LookingDisabled; + controls.mVanityModeDisabled = pcdt.mPNAM.mPlayerFlags & PCDT::PlayerFlags_VanityModeDisabled; + controls.mWeaponDrawingDisabled = pcdt.mPNAM.mPlayerFlags & PCDT::PlayerFlags_WeaponDrawingDisabled; + controls.mSpellDrawingDisabled = pcdt.mPNAM.mPlayerFlags & PCDT::PlayerFlags_SpellDrawingDisabled; } } diff --git a/apps/essimporter/convertplayer.hpp b/apps/essimporter/convertplayer.hpp index f6731eed7..2e4565d8d 100644 --- a/apps/essimporter/convertplayer.hpp +++ b/apps/essimporter/convertplayer.hpp @@ -4,11 +4,12 @@ #include "importplayer.hpp" #include +#include namespace ESSImport { - void convertPCDT(const PCDT& pcdt, ESM::Player& out, std::vector& outDialogueTopics, bool& firstPersonCam); + void convertPCDT(const PCDT& pcdt, ESM::Player& out, std::vector& outDialogueTopics, bool& firstPersonCam, ESM::ControlsState& controls); } diff --git a/apps/essimporter/importer.cpp b/apps/essimporter/importer.cpp index f17db309f..1c255c56f 100644 --- a/apps/essimporter/importer.cpp +++ b/apps/essimporter/importer.cpp @@ -422,6 +422,10 @@ namespace ESSImport writer.startRecord (ESM::REC_DIAS); context.mDialogueState.save(writer); writer.endRecord(ESM::REC_DIAS); + + writer.startRecord(ESM::REC_INPU); + context.mControlsState.save(writer); + writer.endRecord(ESM::REC_INPU); } diff --git a/apps/essimporter/importercontext.hpp b/apps/essimporter/importercontext.hpp index c93dff269..fde247ebf 100644 --- a/apps/essimporter/importercontext.hpp +++ b/apps/essimporter/importercontext.hpp @@ -9,6 +9,7 @@ #include #include #include +#include #include "importnpcc.hpp" #include "importcrec.hpp" @@ -32,6 +33,8 @@ namespace ESSImport ESM::DialogueState mDialogueState; + ESM::ControlsState mControlsState; + // cells which should show an explored overlay on the global map std::set > mExploredCells; diff --git a/apps/essimporter/importplayer.hpp b/apps/essimporter/importplayer.hpp index 3baab1cd8..42881fcfd 100644 --- a/apps/essimporter/importplayer.hpp +++ b/apps/essimporter/importplayer.hpp @@ -38,14 +38,18 @@ struct PCDT std::vector mKnownDialogueTopics; - enum DrawState_ + enum PlayerFlags { - DrawState_Weapon = 0x80, - DrawState_Spell = 0x100 - }; - enum CameraFlags - { - CameraFlag_ThirdPerson = 0x2 + PlayerFlags_ViewSwitchDisabled = 0x1, + PlayerFlags_ControlsDisabled = 0x4, + PlayerFlags_WeaponDrawn = 0x80, + PlayerFlags_SpellDrawn = 0x100, + PlayerFlags_JumpingDisabled = 0x1000, + PlayerFlags_LookingDisabled = 0x2000, + PlayerFlags_VanityModeDisabled = 0x4000, + PlayerFlags_WeaponDrawingDisabled = 0x8000, + PlayerFlags_SpellDrawingDisabled = 0x10000, + PlayerFlags_ThirdPerson = 0x20000 }; #pragma pack(push) @@ -62,8 +66,7 @@ struct PCDT struct PNAM { - short mDrawState; // DrawState - short mCameraFlags; // CameraFlags + int mPlayerFlags; // controls, camera and draw state unsigned int mLevelProgress; float mSkillProgress[27]; // skill progress, non-uniform scaled unsigned char mSkillIncreases[8]; // number of skill increases for each attribute From cd9de94c0cfc6576c4a18121204f70f204d0f81d Mon Sep 17 00:00:00 2001 From: MiroslavR Date: Thu, 20 Oct 2016 14:38:18 +0200 Subject: [PATCH 3/3] Import teleporting and levitation disabled state from vanilla savegames (Fixes #3420) --- apps/essimporter/converter.hpp | 15 +++++++++++++-- apps/essimporter/convertplayer.cpp | 4 +++- apps/essimporter/convertplayer.hpp | 2 +- apps/essimporter/importplayer.hpp | 4 +++- 4 files changed, 20 insertions(+), 5 deletions(-) diff --git a/apps/essimporter/converter.hpp b/apps/essimporter/converter.hpp index 5e46e4309..b05337aea 100644 --- a/apps/essimporter/converter.hpp +++ b/apps/essimporter/converter.hpp @@ -271,23 +271,34 @@ private: class ConvertPCDT : public Converter { public: - ConvertPCDT() : mFirstPersonCam(true) {} + ConvertPCDT() + : mFirstPersonCam(true), + mTeleportingEnabled(true), + mLevitationEnabled(true) + {} virtual void read(ESM::ESMReader &esm) { PCDT pcdt; pcdt.load(esm); - convertPCDT(pcdt, mContext->mPlayer, mContext->mDialogueState.mKnownTopics, mFirstPersonCam, mContext->mControlsState); + convertPCDT(pcdt, mContext->mPlayer, mContext->mDialogueState.mKnownTopics, mFirstPersonCam, mTeleportingEnabled, mLevitationEnabled, mContext->mControlsState); } virtual void write(ESM::ESMWriter &esm) { + esm.startRecord(ESM::REC_ENAB); + esm.writeHNT("TELE", mTeleportingEnabled); + esm.writeHNT("LEVT", mLevitationEnabled); + esm.endRecord(ESM::REC_ENAB); + esm.startRecord(ESM::REC_CAM_); esm.writeHNT("FIRS", mFirstPersonCam); esm.endRecord(ESM::REC_CAM_); } private: bool mFirstPersonCam; + bool mTeleportingEnabled; + bool mLevitationEnabled; }; class ConvertCNTC : public Converter diff --git a/apps/essimporter/convertplayer.cpp b/apps/essimporter/convertplayer.cpp index c7bd8526c..9d82af022 100644 --- a/apps/essimporter/convertplayer.cpp +++ b/apps/essimporter/convertplayer.cpp @@ -5,7 +5,7 @@ namespace ESSImport { - void convertPCDT(const PCDT& pcdt, ESM::Player& out, std::vector& outDialogueTopics, bool& firstPersonCam, ESM::ControlsState& controls) + void convertPCDT(const PCDT& pcdt, ESM::Player& out, std::vector& outDialogueTopics, bool& firstPersonCam, bool& teleportingEnabled, bool& levitationEnabled, ESM::ControlsState& controls) { out.mBirthsign = pcdt.mBirthsign; out.mObject.mNpcStats.mBounty = pcdt.mBounty; @@ -31,6 +31,8 @@ namespace ESSImport out.mObject.mCreatureStats.mDrawState = 2; firstPersonCam = !(pcdt.mPNAM.mPlayerFlags & PCDT::PlayerFlags_ThirdPerson); + teleportingEnabled = !(pcdt.mPNAM.mPlayerFlags & PCDT::PlayerFlags_TeleportingDisabled); + levitationEnabled = !(pcdt.mPNAM.mPlayerFlags & PCDT::PlayerFlags_LevitationDisabled); for (std::vector::const_iterator it = pcdt.mKnownDialogueTopics.begin(); it != pcdt.mKnownDialogueTopics.end(); ++it) diff --git a/apps/essimporter/convertplayer.hpp b/apps/essimporter/convertplayer.hpp index 2e4565d8d..1d2fdc87a 100644 --- a/apps/essimporter/convertplayer.hpp +++ b/apps/essimporter/convertplayer.hpp @@ -9,7 +9,7 @@ namespace ESSImport { - void convertPCDT(const PCDT& pcdt, ESM::Player& out, std::vector& outDialogueTopics, bool& firstPersonCam, ESM::ControlsState& controls); + void convertPCDT(const PCDT& pcdt, ESM::Player& out, std::vector& outDialogueTopics, bool& firstPersonCam, bool& teleportingEnabled, bool& levitationEnabled, ESM::ControlsState& controls); } diff --git a/apps/essimporter/importplayer.hpp b/apps/essimporter/importplayer.hpp index 42881fcfd..9f6b055c0 100644 --- a/apps/essimporter/importplayer.hpp +++ b/apps/essimporter/importplayer.hpp @@ -49,7 +49,9 @@ struct PCDT PlayerFlags_VanityModeDisabled = 0x4000, PlayerFlags_WeaponDrawingDisabled = 0x8000, PlayerFlags_SpellDrawingDisabled = 0x10000, - PlayerFlags_ThirdPerson = 0x20000 + PlayerFlags_ThirdPerson = 0x20000, + PlayerFlags_TeleportingDisabled = 0x40000, + PlayerFlags_LevitationDisabled = 0x80000 }; #pragma pack(push)