diff --git a/.travis.yml b/.travis.yml index 5f592119a..ced20d7d8 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,7 +1,7 @@ os: - linux # - osx -#osx_image: xcode7.2 +osx_image: xcode7.2 language: cpp sudo: required dist: trusty diff --git a/apps/essimporter/converter.hpp b/apps/essimporter/converter.hpp index 11f966446..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); + 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 55aaad1c5..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) + 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; @@ -25,18 +25,28 @@ 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); + 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) { 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..1d2fdc87a 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, bool& teleportingEnabled, bool& levitationEnabled, 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..9f6b055c0 100644 --- a/apps/essimporter/importplayer.hpp +++ b/apps/essimporter/importplayer.hpp @@ -38,14 +38,20 @@ 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, + PlayerFlags_TeleportingDisabled = 0x40000, + PlayerFlags_LevitationDisabled = 0x80000 }; #pragma pack(push) @@ -62,8 +68,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 diff --git a/apps/opencs/model/doc/loader.cpp b/apps/opencs/model/doc/loader.cpp index 51b1b5884..44d6883ef 100644 --- a/apps/opencs/model/doc/loader.cpp +++ b/apps/opencs/model/doc/loader.cpp @@ -73,11 +73,11 @@ void CSMDoc::Loader::load() CSMWorld::UniversalId log (CSMWorld::UniversalId::Type_LoadErrorLog, 0); { // silence a g++ warning - for (CSMDoc::Messages::Iterator iter (messages.begin()); - iter!=messages.end(); ++iter) + for (CSMDoc::Messages::Iterator messageIter (messages.begin()); + messageIter!=messages.end(); ++messageIter) { - document->getReport (log)->add (*iter); - emit loadMessage (document, iter->mMessage); + document->getReport (log)->add (*messageIter); + emit loadMessage (document, messageIter->mMessage); } } diff --git a/apps/opencs/model/filter/parser.cpp b/apps/opencs/model/filter/parser.cpp index 7936a1ae2..c0c089169 100644 --- a/apps/opencs/model/filter/parser.cpp +++ b/apps/opencs/model/filter/parser.cpp @@ -313,7 +313,7 @@ boost::shared_ptr CSMFilter::Parser::parseNAry (const Token& ke nodes.push_back (node); - Token token = getNextToken(); + token = getNextToken(); if (!token || (token.mType!=Token::Type_Close && token.mType!=Token::Type_Comma)) { diff --git a/apps/opencs/model/world/infocollection.cpp b/apps/opencs/model/world/infocollection.cpp index f5ec4d458..be73aece6 100644 --- a/apps/opencs/model/world/infocollection.cpp +++ b/apps/opencs/model/world/infocollection.cpp @@ -19,8 +19,6 @@ void CSMWorld::InfoCollection::load (const Info& record, bool base) record2.mState = base ? RecordBase::State_BaseOnly : RecordBase::State_ModifiedOnly; (base ? record2.mBase : record2.mModified) = record; - int index = -1; - std::string topic = Misc::StringUtils::lowerCase (record2.get().mTopicId); if (!record2.get().mPrev.empty()) diff --git a/apps/opencs/model/world/resources.cpp b/apps/opencs/model/world/resources.cpp index b31e211ee..5fe9194d7 100644 --- a/apps/opencs/model/world/resources.cpp +++ b/apps/opencs/model/world/resources.cpp @@ -25,12 +25,12 @@ CSMWorld::Resources::Resources (const VFS::Manager* vfs, const std::string& base if (extensions) { - std::string::size_type index = filepath.find_last_of ('.'); + std::string::size_type extensionIndex = filepath.find_last_of ('.'); - if (index==std::string::npos) + if (extensionIndex==std::string::npos) continue; - std::string extension = filepath.substr (index+1); + std::string extension = filepath.substr (extensionIndex+1); int i = 0; diff --git a/apps/opencs/view/filter/filterbox.cpp b/apps/opencs/view/filter/filterbox.cpp index c6c6cc6cc..4c252e7d9 100644 --- a/apps/opencs/view/filter/filterbox.cpp +++ b/apps/opencs/view/filter/filterbox.cpp @@ -38,9 +38,9 @@ void CSVFilter::FilterBox::dropEvent (QDropEvent* event) if (!mime) // May happen when non-records (e.g. plain text) are dragged and dropped return; - std::vector data = mime->getData(); + std::vector universalIdData = mime->getData(); - emit recordDropped(data, event->proposedAction()); + emit recordDropped(universalIdData, event->proposedAction()); } void CSVFilter::FilterBox::dragEnterEvent (QDragEnterEvent* event) diff --git a/apps/opencs/view/render/cell.cpp b/apps/opencs/view/render/cell.cpp index 395fbf95f..adc038836 100644 --- a/apps/opencs/view/render/cell.cpp +++ b/apps/opencs/view/render/cell.cpp @@ -219,12 +219,12 @@ bool CSVRender::Cell::referenceDataChanged (const QModelIndex& topLeft, } // add new objects - for (std::map::iterator iter (ids.begin()); iter!=ids.end(); ++iter) + for (std::map::iterator mapIter (ids.begin()); mapIter!=ids.end(); ++mapIter) { - if (!iter->second) + if (!mapIter->second) { mObjects.insert (std::make_pair ( - iter->first, new Object (mData, mCellNode, iter->first, false))); + mapIter->first, new Object (mData, mCellNode, mapIter->first, false))); modified = true; } diff --git a/apps/opencs/view/render/instancemode.cpp b/apps/opencs/view/render/instancemode.cpp index cf51e93b7..3373daa4a 100644 --- a/apps/opencs/view/render/instancemode.cpp +++ b/apps/opencs/view/render/instancemode.cpp @@ -259,8 +259,8 @@ bool CSVRender::InstanceMode::primaryEditStartDrag (const QPoint& pos) mDragMode = DragMode_Scale; // Calculate scale factor - std::vector > selection = getWorldspaceWidget().getEdited (Mask_Reference); - osg::Vec3f center = getScreenCoords(getSelectionCenter(selection)); + std::vector > editedSelection = getWorldspaceWidget().getEdited (Mask_Reference); + osg::Vec3f center = getScreenCoords(getSelectionCenter(editedSelection)); int widgetHeight = getWorldspaceWidget().height(); diff --git a/apps/opencs/view/render/pagedworldspacewidget.cpp b/apps/opencs/view/render/pagedworldspacewidget.cpp index a9d71626d..261144f8f 100644 --- a/apps/opencs/view/render/pagedworldspacewidget.cpp +++ b/apps/opencs/view/render/pagedworldspacewidget.cpp @@ -558,18 +558,18 @@ std::pair< int, int > CSVRender::PagedWorldspaceWidget::getCoordinatesFromId (co } bool CSVRender::PagedWorldspaceWidget::handleDrop ( - const std::vector< CSMWorld::UniversalId >& data, DropType type) + const std::vector< CSMWorld::UniversalId >& universalIdData, DropType type) { - if (WorldspaceWidget::handleDrop (data, type)) + if (WorldspaceWidget::handleDrop (universalIdData, type)) return true; if (type!=Type_CellsExterior) return false; bool selectionChanged = false; - for (unsigned i = 0; i < data.size(); ++i) + for (unsigned i = 0; i < universalIdData.size(); ++i) { - std::pair coordinates(getCoordinatesFromId(data[i].getId())); + std::pair coordinates(getCoordinatesFromId(universalIdData[i].getId())); if (mSelection.add(CSMWorld::CellCoordinates(coordinates.first, coordinates.second))) { selectionChanged = true; diff --git a/apps/opencs/view/render/unpagedworldspacewidget.cpp b/apps/opencs/view/render/unpagedworldspacewidget.cpp index d9a85fe35..03a97bf1a 100644 --- a/apps/opencs/view/render/unpagedworldspacewidget.cpp +++ b/apps/opencs/view/render/unpagedworldspacewidget.cpp @@ -80,20 +80,20 @@ void CSVRender::UnpagedWorldspaceWidget::cellRowsAboutToBeRemoved (const QModelI emit closeRequest(); } -bool CSVRender::UnpagedWorldspaceWidget::handleDrop (const std::vector& data, DropType type) +bool CSVRender::UnpagedWorldspaceWidget::handleDrop (const std::vector& universalIdData, DropType type) { - if (WorldspaceWidget::handleDrop (data, type)) + if (WorldspaceWidget::handleDrop (universalIdData, type)) return true; if (type!=Type_CellsInterior) return false; - mCellId = data.begin()->getId(); + mCellId = universalIdData.begin()->getId(); mCell.reset (new Cell (getDocument().getData(), mRootNode, mCellId)); update(); - emit cellChanged(*data.begin()); + emit cellChanged(*universalIdData.begin()); return true; } diff --git a/apps/opencs/view/render/worldspacewidget.cpp b/apps/opencs/view/render/worldspacewidget.cpp index dd2ec1bdd..325fa5f6d 100644 --- a/apps/opencs/view/render/worldspacewidget.cpp +++ b/apps/opencs/view/render/worldspacewidget.cpp @@ -303,15 +303,15 @@ CSVRender::WorldspaceWidget::dropRequirments return ignored; } -bool CSVRender::WorldspaceWidget::handleDrop (const std::vector& data, +bool CSVRender::WorldspaceWidget::handleDrop (const std::vector& universalIdData, DropType type) { if (type==Type_DebugProfile) { if (mRun) { - for (std::vector::const_iterator iter (data.begin()); - iter!=data.end(); ++iter) + for (std::vector::const_iterator iter (universalIdData.begin()); + iter!=universalIdData.end(); ++iter) mRun->addProfile (iter->getId()); } @@ -402,9 +402,9 @@ CSVRender::WorldspaceHitResult CSVRender::WorldspaceWidget::mousePick (const QPo continue; } - for (std::vector::iterator it = intersection.nodePath.begin(); it != intersection.nodePath.end(); ++it) + for (std::vector::iterator nodeIter = intersection.nodePath.begin(); nodeIter != intersection.nodePath.end(); ++nodeIter) { - osg::Node* node = *it; + osg::Node* node = *nodeIter; if (osg::ref_ptr tag = dynamic_cast(node->getUserData())) { WorldspaceHitResult hit = { true, tag, 0, 0, 0, intersection.getWorldIntersectPoint() }; diff --git a/apps/opencs/view/world/dialoguesubview.cpp b/apps/opencs/view/world/dialoguesubview.cpp index 03d83f7da..87d5b3d7f 100644 --- a/apps/opencs/view/world/dialoguesubview.cpp +++ b/apps/opencs/view/world/dialoguesubview.cpp @@ -658,8 +658,7 @@ void CSVWorld::EditWidget::remake(int row) int displayRole = tree->nestedHeaderData (i, col, Qt::Horizontal, CSMWorld::ColumnBase::Role_Display).toInt(); - CSMWorld::ColumnBase::Display display = - static_cast (displayRole); + display = static_cast (displayRole); mNestedTableDispatcher->makeDelegate (display); diff --git a/apps/opencs/view/world/dragrecordtable.cpp b/apps/opencs/view/world/dragrecordtable.cpp index a5f933283..6d980e171 100644 --- a/apps/opencs/view/world/dragrecordtable.cpp +++ b/apps/opencs/view/world/dragrecordtable.cpp @@ -67,8 +67,8 @@ void CSVWorld::DragRecordTable::dropEvent(QDropEvent *event) CSMWorld::ColumnBase::Display display = getIndexDisplayType(index); if (CSVWorld::DragDropUtils::canAcceptData(*event, display)) { - const CSMWorld::TableMimeData *data = CSVWorld::DragDropUtils::getTableMimeData(*event); - if (data->fromDocument(mDocument)) + const CSMWorld::TableMimeData *tableMimeData = CSVWorld::DragDropUtils::getTableMimeData(*event); + if (tableMimeData->fromDocument(mDocument)) { CSMWorld::UniversalId id = CSVWorld::DragDropUtils::getAcceptedData(*event, display); QVariant newIndexData = QString::fromUtf8(id.getId().c_str()); diff --git a/apps/opencs/view/world/referenceablecreator.cpp b/apps/opencs/view/world/referenceablecreator.cpp index 1357ca46f..836e8ac7d 100644 --- a/apps/opencs/view/world/referenceablecreator.cpp +++ b/apps/opencs/view/world/referenceablecreator.cpp @@ -26,10 +26,10 @@ CSVWorld::ReferenceableCreator::ReferenceableCreator (CSMWorld::Data& data, QUnd for (std::vector::const_iterator iter (types.begin()); iter!=types.end(); ++iter) { - CSMWorld::UniversalId id (*iter, ""); + CSMWorld::UniversalId id2 (*iter, ""); - mType->addItem (QIcon (id.getIcon().c_str()), id.getTypeName().c_str(), - static_cast (id.getType())); + mType->addItem (QIcon (id2.getIcon().c_str()), id2.getTypeName().c_str(), + static_cast (id2.getType())); } insertBeforeButtons (mType, false); diff --git a/apps/opencs/view/world/scenesubview.cpp b/apps/opencs/view/world/scenesubview.cpp index c84818b37..b14d708da 100644 --- a/apps/opencs/view/world/scenesubview.cpp +++ b/apps/opencs/view/world/scenesubview.cpp @@ -187,18 +187,18 @@ void CSVWorld::SceneSubView::cellSelectionChanged (const CSMWorld::CellSelection emit updateTitle(); } -void CSVWorld::SceneSubView::handleDrop (const std::vector< CSMWorld::UniversalId >& data) +void CSVWorld::SceneSubView::handleDrop (const std::vector< CSMWorld::UniversalId >& universalIdData) { CSVRender::PagedWorldspaceWidget* pagedNewWidget = NULL; CSVRender::UnpagedWorldspaceWidget* unPagedNewWidget = NULL; CSVWidget::SceneToolbar* toolbar = NULL; - CSVRender::WorldspaceWidget::DropType type = CSVRender::WorldspaceWidget::getDropType (data); + CSVRender::WorldspaceWidget::DropType type = CSVRender::WorldspaceWidget::getDropType (universalIdData); switch (mScene->getDropRequirements (type)) { case CSVRender::WorldspaceWidget::canHandle: - mScene->handleDrop (data, type); + mScene->handleDrop (universalIdData, type); break; case CSVRender::WorldspaceWidget::needPaged: @@ -206,15 +206,15 @@ void CSVWorld::SceneSubView::handleDrop (const std::vector< CSMWorld::UniversalI toolbar = makeToolbar(pagedNewWidget, widget_Paged); makeConnections(pagedNewWidget); replaceToolbarAndWorldspace(pagedNewWidget, toolbar); - mScene->handleDrop (data, type); + mScene->handleDrop (universalIdData, type); break; case CSVRender::WorldspaceWidget::needUnpaged: - unPagedNewWidget = new CSVRender::UnpagedWorldspaceWidget(data.begin()->getId(), mDocument, this); + unPagedNewWidget = new CSVRender::UnpagedWorldspaceWidget(universalIdData.begin()->getId(), mDocument, this); toolbar = makeToolbar(unPagedNewWidget, widget_Unpaged); makeConnections(unPagedNewWidget); replaceToolbarAndWorldspace(unPagedNewWidget, toolbar); - cellSelectionChanged(*(data.begin())); + cellSelectionChanged(*(universalIdData.begin())); break; case CSVRender::WorldspaceWidget::ignored: diff --git a/apps/opencs/view/world/tablesubview.cpp b/apps/opencs/view/world/tablesubview.cpp index 1b25e1c08..fcf66ed81 100644 --- a/apps/opencs/view/world/tablesubview.cpp +++ b/apps/opencs/view/world/tablesubview.cpp @@ -148,14 +148,14 @@ bool CSVWorld::TableSubView::eventFilter (QObject* object, QEvent* event) { if (QDropEvent* drop = dynamic_cast(event)) { - const CSMWorld::TableMimeData* data = dynamic_cast(drop->mimeData()); - if (!data) // May happen when non-records (e.g. plain text) are dragged and dropped + const CSMWorld::TableMimeData* tableMimeData = dynamic_cast(drop->mimeData()); + if (!tableMimeData) // May happen when non-records (e.g. plain text) are dragged and dropped return false; - bool handled = data->holdsType(CSMWorld::UniversalId::Type_Filter); + bool handled = tableMimeData->holdsType(CSMWorld::UniversalId::Type_Filter); if (handled) { - mFilterBox->setRecordFilter(data->returnMatching(CSMWorld::UniversalId::Type_Filter).getId()); + mFilterBox->setRecordFilter(tableMimeData->returnMatching(CSMWorld::UniversalId::Type_Filter).getId()); } return handled; } 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/mwdialogue/journalimp.cpp b/apps/openmw/mwdialogue/journalimp.cpp index 8ea72e3ba..f11ec651d 100644 --- a/apps/openmw/mwdialogue/journalimp.cpp +++ b/apps/openmw/mwdialogue/journalimp.cpp @@ -187,12 +187,12 @@ namespace MWDialogue state.save (writer); writer.endRecord (ESM::REC_QUES); - for (Topic::TEntryIter iter (quest.begin()); iter!=quest.end(); ++iter) + for (Topic::TEntryIter entryIter (quest.begin()); entryIter!=quest.end(); ++entryIter) { ESM::JournalEntry entry; entry.mType = ESM::JournalEntry::Type_Quest; entry.mTopic = quest.getTopic(); - iter->write (entry); + entryIter->write (entry); writer.startRecord (ESM::REC_JOUR); entry.save (writer); writer.endRecord (ESM::REC_JOUR); @@ -213,12 +213,12 @@ namespace MWDialogue { const Topic& topic = iter->second; - for (Topic::TEntryIter iter (topic.begin()); iter!=topic.end(); ++iter) + for (Topic::TEntryIter entryIter (topic.begin()); entryIter!=topic.end(); ++entryIter) { ESM::JournalEntry entry; entry.mType = ESM::JournalEntry::Type_Topic; entry.mTopic = topic.getTopic(); - iter->write (entry); + entryIter->write (entry); writer.startRecord (ESM::REC_JOUR); entry.save (writer); writer.endRecord (ESM::REC_JOUR); diff --git a/apps/openmw/mwgui/debugwindow.cpp b/apps/openmw/mwgui/debugwindow.cpp index 37ea3470d..a29910f00 100644 --- a/apps/openmw/mwgui/debugwindow.cpp +++ b/apps/openmw/mwgui/debugwindow.cpp @@ -7,6 +7,8 @@ #include +#ifndef BT_NO_PROFILE + namespace { void bulletDumpRecursive(CProfileIterator* pit, int spacing, std::stringstream& os) @@ -71,6 +73,7 @@ namespace } } +#endif // BT_NO_PROFILE namespace MWGui { @@ -92,10 +95,13 @@ namespace MWGui MyGUI::IntSize viewSize = MyGUI::RenderManager::getInstance().getViewSize(); mMainWidget->setSize(viewSize); + + } void DebugWindow::onFrame(float dt) { +#ifndef BT_NO_PROFILE if (!isVisible()) return; @@ -115,6 +121,7 @@ namespace MWGui size_t previousPos = mBulletProfilerEdit->getVScrollPosition(); mBulletProfilerEdit->setCaption(stream.str()); mBulletProfilerEdit->setVScrollPosition(std::min(previousPos, mBulletProfilerEdit->getVScrollRange()-1)); +#endif } } diff --git a/apps/openmw/mwinput/inputmanagerimp.cpp b/apps/openmw/mwinput/inputmanagerimp.cpp index a4e0801fd..c172fd3e4 100644 --- a/apps/openmw/mwinput/inputmanagerimp.cpp +++ b/apps/openmw/mwinput/inputmanagerimp.cpp @@ -16,8 +16,13 @@ #include #include + #include +#include +#include +#include + #include "../mwbase/world.hpp" #include "../mwbase/windowmanager.hpp" #include "../mwbase/soundmanager.hpp" @@ -1576,6 +1581,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/mwphysics/physicssystem.cpp b/apps/openmw/mwphysics/physicssystem.cpp index 954d195dd..e442fbda1 100644 --- a/apps/openmw/mwphysics/physicssystem.cpp +++ b/apps/openmw/mwphysics/physicssystem.cpp @@ -14,6 +14,7 @@ #include #include #include + #include #include @@ -1363,8 +1364,10 @@ namespace MWPhysics for (std::set::iterator it = mAnimatedObjects.begin(); it != mAnimatedObjects.end(); ++it) (*it)->animateCollisionShapes(mCollisionWorld); +#ifndef BT_NO_PROFILE CProfileManager::Reset(); CProfileManager::Increment_Frame_Counter(); +#endif } void PhysicsSystem::debugDraw() diff --git a/apps/openmw/mwrender/animation.cpp b/apps/openmw/mwrender/animation.cpp index 6091bee71..c2761e25d 100644 --- a/apps/openmw/mwrender/animation.cpp +++ b/apps/openmw/mwrender/animation.cpp @@ -978,8 +978,8 @@ namespace MWRender { const NifOsg::TextKeyMap &keys = (*animiter)->getTextKeys(); - const AnimSource::ControllerMap& ctrls = (*animiter)->mControllerMap[0]; - for (AnimSource::ControllerMap::const_iterator it = ctrls.begin(); it != ctrls.end(); ++it) + const AnimSource::ControllerMap& ctrls2 = (*animiter)->mControllerMap[0]; + for (AnimSource::ControllerMap::const_iterator it = ctrls2.begin(); it != ctrls2.end(); ++it) { if (Misc::StringUtils::ciEqual(it->first, mAccumRoot->getName())) { diff --git a/apps/openmw/mwrender/globalmap.cpp b/apps/openmw/mwrender/globalmap.cpp index d5102b153..6663b8b29 100644 --- a/apps/openmw/mwrender/globalmap.cpp +++ b/apps/openmw/mwrender/globalmap.cpp @@ -172,37 +172,37 @@ namespace MWRender unsigned char r,g,b; - float y = 0; + float y2 = 0; if (landData) - y = (landData->mWnam[vertexY * 9 + vertexX] << 4) / 2048.f; + y2 = (landData->mWnam[vertexY * 9 + vertexX] << 4) / 2048.f; else - y = (SCHAR_MIN << 4) / 2048.f; - if (y < 0) + y2 = (SCHAR_MIN << 4) / 2048.f; + if (y2 < 0) { - r = static_cast(14 * y + 38); - g = static_cast(20 * y + 56); - b = static_cast(18 * y + 51); + r = static_cast(14 * y2 + 38); + g = static_cast(20 * y2 + 56); + b = static_cast(18 * y2 + 51); } - else if (y < 0.3f) + else if (y2 < 0.3f) { - if (y < 0.1f) - y *= 8.f; + if (y2 < 0.1f) + y2 *= 8.f; else { - y -= 0.1f; - y += 0.8f; + y2 -= 0.1f; + y2 += 0.8f; } - r = static_cast(66 - 32 * y); - g = static_cast(48 - 23 * y); - b = static_cast(33 - 16 * y); + r = static_cast(66 - 32 * y2); + g = static_cast(48 - 23 * y2); + b = static_cast(33 - 16 * y2); } else { - y -= 0.3f; - y *= 1.428f; - r = static_cast(34 - 29 * y); - g = static_cast(25 - 20 * y); - b = static_cast(17 - 12 * y); + y2 -= 0.3f; + y2 *= 1.428f; + r = static_cast(34 - 29 * y2); + g = static_cast(25 - 20 * y2); + b = static_cast(17 - 12 * y2); } data[texelY * mWidth * 3 + texelX * 3] = r; 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/apps/openmw/mwworld/cellstore.cpp b/apps/openmw/mwworld/cellstore.cpp index c062fc0af..7fdf8c71d 100644 --- a/apps/openmw/mwworld/cellstore.cpp +++ b/apps/openmw/mwworld/cellstore.cpp @@ -230,6 +230,14 @@ namespace MWWorld return (ref.mRef.mRefnum == pRefnum); } + Ptr CellStore::getCurrentPtr(LiveCellRefBase *ref) + { + MovedRefTracker::iterator found = mMovedToAnotherCell.find(ref); + if (found != mMovedToAnotherCell.end()) + return Ptr(ref, found->second); + return Ptr(ref, this); + } + void CellStore::moveFrom(const Ptr &object, CellStore *from) { if (mState != State_Loaded) @@ -1023,26 +1031,26 @@ namespace MWWorld mLastRespawn = MWBase::Environment::get().getWorld()->getTimeStamp(); for (CellRefList::List::iterator it (mContainers.mList.begin()); it!=mContainers.mList.end(); ++it) { - Ptr ptr (&*it, this); + Ptr ptr = getCurrentPtr(&*it); ptr.getClass().respawn(ptr); } } for (CellRefList::List::iterator it (mCreatures.mList.begin()); it!=mCreatures.mList.end(); ++it) { - Ptr ptr (&*it, this); + Ptr ptr = getCurrentPtr(&*it); clearCorpse(ptr); ptr.getClass().respawn(ptr); } for (CellRefList::List::iterator it (mNpcs.mList.begin()); it!=mNpcs.mList.end(); ++it) { - Ptr ptr (&*it, this); + Ptr ptr = getCurrentPtr(&*it); clearCorpse(ptr); ptr.getClass().respawn(ptr); } for (CellRefList::List::iterator it (mCreatureLists.mList.begin()); it!=mCreatureLists.mList.end(); ++it) { - Ptr ptr (&*it, this); + Ptr ptr = getCurrentPtr(&*it); // no need to clearCorpse, handled as part of mCreatures ptr.getClass().respawn(ptr); } diff --git a/apps/openmw/mwworld/cellstore.hpp b/apps/openmw/mwworld/cellstore.hpp index 45f4a6606..2cffa4c54 100644 --- a/apps/openmw/mwworld/cellstore.hpp +++ b/apps/openmw/mwworld/cellstore.hpp @@ -111,6 +111,9 @@ namespace MWWorld // Merged list of ref's currently in this cell - i.e. with added refs from mMovedHere, removed refs from mMovedToAnotherCell std::vector mMergedRefs; + // Get the Ptr for the given ref which originated from this cell (possibly moved to another cell at this point). + Ptr getCurrentPtr(MWWorld::LiveCellRefBase* ref); + /// Moves object from the given cell to this cell. void moveFrom(const MWWorld::Ptr& object, MWWorld::CellStore* from); diff --git a/apps/openmw/mwworld/containerstore.cpp b/apps/openmw/mwworld/containerstore.cpp index 54b612a1e..dbdec8081 100644 --- a/apps/openmw/mwworld/containerstore.cpp +++ b/apps/openmw/mwworld/containerstore.cpp @@ -450,10 +450,10 @@ void MWWorld::ContainerStore::addInitialItem (const std::string& id, const std:: } else { - std::string id = MWMechanics::getLevelledItem(ref.getPtr().get()->mBase, false); - if (id.empty()) + std::string itemId = MWMechanics::getLevelledItem(ref.getPtr().get()->mBase, false); + if (itemId.empty()) return; - addInitialItem(id, owner, count, false, levItemList->mId); + addInitialItem(itemId, owner, count, false, levItemList->mId); } } else diff --git a/apps/openmw/mwworld/inventorystore.cpp b/apps/openmw/mwworld/inventorystore.cpp index aa6880a49..98cbad742 100644 --- a/apps/openmw/mwworld/inventorystore.cpp +++ b/apps/openmw/mwworld/inventorystore.cpp @@ -6,6 +6,7 @@ #include #include #include +#include #include "../mwbase/environment.hpp" #include "../mwbase/world.hpp" @@ -214,36 +215,71 @@ MWWorld::ContainerStoreIterator MWWorld::InventoryStore::getSlot (int slot) return mSlots[slot]; } +bool MWWorld::InventoryStore::canActorAutoEquip(const MWWorld::Ptr& actor, const MWWorld::Ptr& item) +{ + if (!Settings::Manager::getBool("prevent merchant equipping", "Game")) + return true; + + // Only autoEquip if we are the original owner of the item. + // This stops merchants from auto equipping anything you sell to them. + // ...unless this is a companion, he should always equip items given to him. + if (!Misc::StringUtils::ciEqual(item.getCellRef().getOwner(), actor.getCellRef().getRefId()) && + (actor.getClass().getScript(actor).empty() || + !actor.getRefData().getLocals().getIntVar(actor.getClass().getScript(actor), "companion")) + && !actor.getClass().getCreatureStats(actor).isDead() // Corpses can be dressed up by the player as desired + ) + { + return false; + } + + return true; +} + void MWWorld::InventoryStore::autoEquip (const MWWorld::Ptr& actor) { + if (!actor.getClass().isNpc()) + // autoEquip is no-op for creatures + return; + + const MWBase::World *world = MWBase::Environment::get().getWorld(); + const MWWorld::Store &store = world->getStore().get(); + MWMechanics::NpcStats& stats = actor.getClass().getNpcStats(actor); + + static float fUnarmoredBase1 = store.find("fUnarmoredBase1")->getFloat(); + static float fUnarmoredBase2 = store.find("fUnarmoredBase2")->getFloat(); + int unarmoredSkill = stats.getSkill(ESM::Skill::Unarmored).getModified(); + + float unarmoredRating = static_cast((fUnarmoredBase1 * unarmoredSkill) * (fUnarmoredBase2 * unarmoredSkill)); + TSlots slots_; initSlots (slots_); // Disable model update during auto-equip mUpdatesEnabled = false; - for (ContainerStoreIterator iter (begin()); iter!=end(); ++iter) + // Autoequip clothing, armor and weapons. + // Equipping lights is handled in Actors::updateEquippedLight based on environment light. + + for (ContainerStoreIterator iter (begin(ContainerStore::Type_Clothing | ContainerStore::Type_Armor)); iter!=end(); ++iter) { Ptr test = *iter; - // Don't autoEquip lights. Handled in Actors::updateEquippedLight based on environment light. - if (test.getTypeName() == typeid(ESM::Light).name()) - { + if (!canActorAutoEquip(actor, test)) continue; + + switch(test.getClass().canBeEquipped (test, actor).first) + { + case 0: + continue; + default: + break; } - // Only autoEquip if we are the original owner of the item. - // This stops merchants from auto equipping anything you sell to them. - // ...unless this is a companion, he should always equip items given to him. - if (!Misc::StringUtils::ciEqual(test.getCellRef().getOwner(), actor.getCellRef().getRefId()) && - (actor.getClass().getScript(actor).empty() || - !actor.getRefData().getLocals().getIntVar(actor.getClass().getScript(actor), "companion")) - && !actor.getClass().getCreatureStats(actor).isDead() // Corpses can be dressed up by the player as desired - ) + if (iter.getType() == ContainerStore::Type_Armor && + test.getClass().getEffectiveArmorRating(test, actor) <= std::max(unarmoredRating, 0.f)) { continue; } - int testSkill = test.getClass().getEquipmentSkill (test); std::pair, bool> itemsSlots = iter->getClass().getEquipmentSlots (*iter); @@ -251,51 +287,35 @@ void MWWorld::InventoryStore::autoEquip (const MWWorld::Ptr& actor) for (std::vector::const_iterator iter2 (itemsSlots.first.begin()); iter2!=itemsSlots.first.end(); ++iter2) { - if (*iter2 == Slot_CarriedRight) // Items in right hand are situational use, so don't equip them. - // Equipping weapons is handled by AiCombat. Anything else (lockpicks, probes) can't be used by NPCs anyway (yet) - continue; - - if (iter.getType() == MWWorld::ContainerStore::Type_Weapon) - continue; - if (slots_.at (*iter2)!=end()) { Ptr old = *slots_.at (*iter2); - // check skill - int oldSkill = old.getClass().getEquipmentSkill (old); - - bool use = false; - if (testSkill!=-1 && oldSkill==-1) - use = true; - else if (testSkill!=-1 && oldSkill!=-1 && testSkill!=oldSkill) + if (iter.getType() == ContainerStore::Type_Armor) { - if (actor.getClass().getSkill(actor, oldSkill) > actor.getClass().getSkill (actor, testSkill)) - continue; // rejected, because old item better matched the NPC's skills. - - if (actor.getClass().getSkill(actor, oldSkill) < actor.getClass().getSkill (actor, testSkill)) - use = true; + if (old.getTypeName() == typeid(ESM::Armor).name()) + { + if (old.getClass().getEffectiveArmorRating(old, actor) >= test.getClass().getEffectiveArmorRating(test, actor)) + // old armor had better armor rating + continue; + } + // suitable armor should replace already equipped clothing } - - if (!use) + else if (iter.getType() == ContainerStore::Type_Clothing) { - // check value - if (old.getClass().getValue (old)>= - test.getClass().getValue (test)) + if (old.getTypeName() == typeid(ESM::Clothing).name()) { - continue; + // check value + if (old.getClass().getValue (old) > test.getClass().getValue (test)) + // old clothing was more valuable + continue; } + else + // suitable clothing should NOT replace already equipped armor + continue; } } - switch(test.getClass().canBeEquipped (test, actor).first) - { - case 0: - continue; - default: - break; - } - if (!itemsSlots.second) // if itemsSlots.second is true, item can stay stacked when equipped { // unstack item pointed to by iterator if required @@ -310,6 +330,99 @@ void MWWorld::InventoryStore::autoEquip (const MWWorld::Ptr& actor) } } + static const ESM::Skill::SkillEnum weaponSkills[] = + { + ESM::Skill::LongBlade, + ESM::Skill::Axe, + ESM::Skill::Spear, + ESM::Skill::ShortBlade, + ESM::Skill::Marksman, + ESM::Skill::BluntWeapon + }; + const size_t weaponSkillsLength = sizeof(weaponSkills) / sizeof(weaponSkills[0]); + + bool weaponSkillVisited[weaponSkillsLength] = { false }; + + for (int i = 0; i < static_cast(weaponSkillsLength); ++i) + { + int max = 0; + int maxWeaponSkill = -1; + + for (int j = 0; j < static_cast(weaponSkillsLength); ++j) + { + int skillValue = stats.getSkill(static_cast(weaponSkills[j])).getModified(); + + if (skillValue > max && !weaponSkillVisited[j]) + { + max = skillValue; + maxWeaponSkill = j; + } + } + + if (maxWeaponSkill == -1) + break; + + max = 0; + ContainerStoreIterator weapon(end()); + + for (ContainerStoreIterator iter(begin(ContainerStore::Type_Weapon)); iter!=end(); ++iter) + { + if (!canActorAutoEquip(actor, *iter)) + continue; + + const ESM::Weapon* esmWeapon = iter->get()->mBase; + + if (esmWeapon->mData.mType == ESM::Weapon::Arrow || esmWeapon->mData.mType == ESM::Weapon::Bolt) + continue; + + if (iter->getClass().getEquipmentSkill(*iter) == weaponSkills[maxWeaponSkill]) + { + if (esmWeapon->mData.mChop[1] >= max) + { + max = esmWeapon->mData.mChop[1]; + weapon = iter; + } + + if (esmWeapon->mData.mSlash[1] >= max) + { + max = esmWeapon->mData.mSlash[1]; + weapon = iter; + } + + if (esmWeapon->mData.mThrust[1] >= max) + { + max = esmWeapon->mData.mThrust[1]; + weapon = iter; + } + } + } + + if (weapon != end() && weapon->getClass().canBeEquipped(*weapon, actor).first) + { + std::pair, bool> itemsSlots = + weapon->getClass().getEquipmentSlots (*weapon); + + for (std::vector::const_iterator slot (itemsSlots.first.begin()); + slot!=itemsSlots.first.end(); ++slot) + { + if (!itemsSlots.second) + { + if (weapon->getRefData().getCount() > 1) + { + unstack(*weapon, actor); + } + } + + slots_[*slot] = weapon; + break; + } + + break; + } + + weaponSkillVisited[maxWeaponSkill] = true; + } + bool changed = false; for (std::size_t i=0; i::iterator it = state.mRegions.begin(); - if(it == state.mRegions.end()) - { - // When loading an imported save, the region modifiers aren't currently being set, so just reset them. - importRegions(); - } - else + importRegions(); + + for(std::map::iterator it = state.mRegions.begin(); it != state.mRegions.end(); ++it) { - for(; it != state.mRegions.end(); ++it) + std::map::iterator found = mRegions.find(it->first); + if (found != mRegions.end()) { - mRegions.insert(std::make_pair(it->first, RegionWeather(it->second))); + found->second = RegionWeather(it->second); } } } diff --git a/components/CMakeLists.txt b/components/CMakeLists.txt index 6bab3eebe..fa0a49395 100644 --- a/components/CMakeLists.txt +++ b/components/CMakeLists.txt @@ -79,7 +79,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, diff --git a/files/settings-default.cfg b/files/settings-default.cfg index 3d2cd49bf..9813cb166 100644 --- a/files/settings-default.cfg +++ b/files/settings-default.cfg @@ -145,6 +145,9 @@ difficulty = 0 # Show duration of magic effect and lights in the spells window. show effect duration = false +# Prevents merchants from equipping items that are sold to them. +prevent merchant equipping = false + [General] # Anisotropy reduces distortion in textures at low angles (e.g. 0 to 16). diff --git a/files/shaders/lighting.glsl b/files/shaders/lighting.glsl index 08b369b5b..d62b61b52 100644 --- a/files/shaders/lighting.glsl +++ b/files/shaders/lighting.glsl @@ -20,9 +20,7 @@ vec4 doLighting(vec3 viewPos, vec3 viewNormal, vec4 vertexColor) d = length(lightDir); lightDir = normalize(lightDir); - lightResult.xyz += ambient * gl_LightSource[i].ambient.xyz; - lightResult.xyz += diffuse.xyz * gl_LightSource[i].diffuse.xyz * clamp(1.0 / (gl_LightSource[i].constantAttenuation + gl_LightSource[i].linearAttenuation * d + gl_LightSource[i].quadraticAttenuation * d * d), 0.0, 1.0) - * max(dot(viewNormal.xyz, lightDir), 0.0); + lightResult.xyz += (ambient * gl_LightSource[i].ambient.xyz + diffuse.xyz * gl_LightSource[i].diffuse.xyz * max(dot(viewNormal.xyz, lightDir), 0.0)) * clamp(1.0 / (gl_LightSource[i].constantAttenuation + gl_LightSource[i].linearAttenuation * d + gl_LightSource[i].quadraticAttenuation * d * d), 0.0, 1.0); } lightResult.xyz += gl_LightModel.ambient.xyz * ambient;