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

# Conflicts:
#	.travis.yml
#	apps/openmw/mwinput/inputmanagerimp.cpp
coverity_scan^2
David Cernat 8 years ago
commit 47ebd24b4a

@ -1,7 +1,7 @@
os: os:
- linux - linux
# - osx # - osx
#osx_image: xcode7.2 osx_image: xcode7.2
language: cpp language: cpp
sudo: required sudo: required
dist: trusty dist: trusty

@ -271,23 +271,34 @@ private:
class ConvertPCDT : public Converter class ConvertPCDT : public Converter
{ {
public: public:
ConvertPCDT() : mFirstPersonCam(true) {} ConvertPCDT()
: mFirstPersonCam(true),
mTeleportingEnabled(true),
mLevitationEnabled(true)
{}
virtual void read(ESM::ESMReader &esm) virtual void read(ESM::ESMReader &esm)
{ {
PCDT pcdt; PCDT pcdt;
pcdt.load(esm); 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) 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.startRecord(ESM::REC_CAM_);
esm.writeHNT("FIRS", mFirstPersonCam); esm.writeHNT("FIRS", mFirstPersonCam);
esm.endRecord(ESM::REC_CAM_); esm.endRecord(ESM::REC_CAM_);
} }
private: private:
bool mFirstPersonCam; bool mFirstPersonCam;
bool mTeleportingEnabled;
bool mLevitationEnabled;
}; };
class ConvertCNTC : public Converter class ConvertCNTC : public Converter

@ -5,7 +5,7 @@
namespace ESSImport namespace ESSImport
{ {
void convertPCDT(const PCDT& pcdt, ESM::Player& out, std::vector<std::string>& outDialogueTopics, bool& firstPersonCam) void convertPCDT(const PCDT& pcdt, ESM::Player& out, std::vector<std::string>& outDialogueTopics, bool& firstPersonCam, bool& teleportingEnabled, bool& levitationEnabled, ESM::ControlsState& controls)
{ {
out.mBirthsign = pcdt.mBirthsign; out.mBirthsign = pcdt.mBirthsign;
out.mObject.mNpcStats.mBounty = pcdt.mBounty; 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.mSkills[i].mProgress = pcdt.mPNAM.mSkillProgress[i];
out.mObject.mNpcStats.mLevelProgress = pcdt.mPNAM.mLevelProgress; 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; out.mObject.mCreatureStats.mDrawState = 1;
if (pcdt.mPNAM.mDrawState & PCDT::DrawState_Spell) if (pcdt.mPNAM.mPlayerFlags & PCDT::PlayerFlags_SpellDrawn)
out.mObject.mCreatureStats.mDrawState = 2; 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<std::string>::const_iterator it = pcdt.mKnownDialogueTopics.begin(); for (std::vector<std::string>::const_iterator it = pcdt.mKnownDialogueTopics.begin();
it != pcdt.mKnownDialogueTopics.end(); ++it) it != pcdt.mKnownDialogueTopics.end(); ++it)
{ {
outDialogueTopics.push_back(Misc::StringUtils::lowerCase(*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;
} }
} }

@ -4,11 +4,12 @@
#include "importplayer.hpp" #include "importplayer.hpp"
#include <components/esm/player.hpp> #include <components/esm/player.hpp>
#include <components/esm/controlsstate.hpp>
namespace ESSImport namespace ESSImport
{ {
void convertPCDT(const PCDT& pcdt, ESM::Player& out, std::vector<std::string>& outDialogueTopics, bool& firstPersonCam); void convertPCDT(const PCDT& pcdt, ESM::Player& out, std::vector<std::string>& outDialogueTopics, bool& firstPersonCam, bool& teleportingEnabled, bool& levitationEnabled, ESM::ControlsState& controls);
} }

@ -422,6 +422,10 @@ namespace ESSImport
writer.startRecord (ESM::REC_DIAS); writer.startRecord (ESM::REC_DIAS);
context.mDialogueState.save(writer); context.mDialogueState.save(writer);
writer.endRecord(ESM::REC_DIAS); writer.endRecord(ESM::REC_DIAS);
writer.startRecord(ESM::REC_INPU);
context.mControlsState.save(writer);
writer.endRecord(ESM::REC_INPU);
} }

@ -9,6 +9,7 @@
#include <components/esm/globalmap.hpp> #include <components/esm/globalmap.hpp>
#include <components/esm/loadcrea.hpp> #include <components/esm/loadcrea.hpp>
#include <components/esm/loadnpc.hpp> #include <components/esm/loadnpc.hpp>
#include <components/esm/controlsstate.hpp>
#include "importnpcc.hpp" #include "importnpcc.hpp"
#include "importcrec.hpp" #include "importcrec.hpp"
@ -32,6 +33,8 @@ namespace ESSImport
ESM::DialogueState mDialogueState; ESM::DialogueState mDialogueState;
ESM::ControlsState mControlsState;
// cells which should show an explored overlay on the global map // cells which should show an explored overlay on the global map
std::set<std::pair<int, int> > mExploredCells; std::set<std::pair<int, int> > mExploredCells;

@ -38,14 +38,20 @@ struct PCDT
std::vector<std::string> mKnownDialogueTopics; std::vector<std::string> mKnownDialogueTopics;
enum DrawState_ enum PlayerFlags
{ {
DrawState_Weapon = 0x80, PlayerFlags_ViewSwitchDisabled = 0x1,
DrawState_Spell = 0x100 PlayerFlags_ControlsDisabled = 0x4,
}; PlayerFlags_WeaponDrawn = 0x80,
enum CameraFlags PlayerFlags_SpellDrawn = 0x100,
{ PlayerFlags_JumpingDisabled = 0x1000,
CameraFlag_ThirdPerson = 0x2 PlayerFlags_LookingDisabled = 0x2000,
PlayerFlags_VanityModeDisabled = 0x4000,
PlayerFlags_WeaponDrawingDisabled = 0x8000,
PlayerFlags_SpellDrawingDisabled = 0x10000,
PlayerFlags_ThirdPerson = 0x20000,
PlayerFlags_TeleportingDisabled = 0x40000,
PlayerFlags_LevitationDisabled = 0x80000
}; };
#pragma pack(push) #pragma pack(push)
@ -62,8 +68,7 @@ struct PCDT
struct PNAM struct PNAM
{ {
short mDrawState; // DrawState int mPlayerFlags; // controls, camera and draw state
short mCameraFlags; // CameraFlags
unsigned int mLevelProgress; unsigned int mLevelProgress;
float mSkillProgress[27]; // skill progress, non-uniform scaled float mSkillProgress[27]; // skill progress, non-uniform scaled
unsigned char mSkillIncreases[8]; // number of skill increases for each attribute unsigned char mSkillIncreases[8]; // number of skill increases for each attribute

@ -73,11 +73,11 @@ void CSMDoc::Loader::load()
CSMWorld::UniversalId log (CSMWorld::UniversalId::Type_LoadErrorLog, 0); CSMWorld::UniversalId log (CSMWorld::UniversalId::Type_LoadErrorLog, 0);
{ // silence a g++ warning { // silence a g++ warning
for (CSMDoc::Messages::Iterator iter (messages.begin()); for (CSMDoc::Messages::Iterator messageIter (messages.begin());
iter!=messages.end(); ++iter) messageIter!=messages.end(); ++messageIter)
{ {
document->getReport (log)->add (*iter); document->getReport (log)->add (*messageIter);
emit loadMessage (document, iter->mMessage); emit loadMessage (document, messageIter->mMessage);
} }
} }

@ -313,7 +313,7 @@ boost::shared_ptr<CSMFilter::Node> CSMFilter::Parser::parseNAry (const Token& ke
nodes.push_back (node); nodes.push_back (node);
Token token = getNextToken(); token = getNextToken();
if (!token || (token.mType!=Token::Type_Close && token.mType!=Token::Type_Comma)) if (!token || (token.mType!=Token::Type_Close && token.mType!=Token::Type_Comma))
{ {

@ -19,8 +19,6 @@ void CSMWorld::InfoCollection::load (const Info& record, bool base)
record2.mState = base ? RecordBase::State_BaseOnly : RecordBase::State_ModifiedOnly; record2.mState = base ? RecordBase::State_BaseOnly : RecordBase::State_ModifiedOnly;
(base ? record2.mBase : record2.mModified) = record; (base ? record2.mBase : record2.mModified) = record;
int index = -1;
std::string topic = Misc::StringUtils::lowerCase (record2.get().mTopicId); std::string topic = Misc::StringUtils::lowerCase (record2.get().mTopicId);
if (!record2.get().mPrev.empty()) if (!record2.get().mPrev.empty())

@ -25,12 +25,12 @@ CSMWorld::Resources::Resources (const VFS::Manager* vfs, const std::string& base
if (extensions) 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; continue;
std::string extension = filepath.substr (index+1); std::string extension = filepath.substr (extensionIndex+1);
int i = 0; int i = 0;

@ -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 if (!mime) // May happen when non-records (e.g. plain text) are dragged and dropped
return; return;
std::vector<CSMWorld::UniversalId> data = mime->getData(); std::vector<CSMWorld::UniversalId> universalIdData = mime->getData();
emit recordDropped(data, event->proposedAction()); emit recordDropped(universalIdData, event->proposedAction());
} }
void CSVFilter::FilterBox::dragEnterEvent (QDragEnterEvent* event) void CSVFilter::FilterBox::dragEnterEvent (QDragEnterEvent* event)

@ -219,12 +219,12 @@ bool CSVRender::Cell::referenceDataChanged (const QModelIndex& topLeft,
} }
// add new objects // add new objects
for (std::map<std::string, bool>::iterator iter (ids.begin()); iter!=ids.end(); ++iter) for (std::map<std::string, bool>::iterator mapIter (ids.begin()); mapIter!=ids.end(); ++mapIter)
{ {
if (!iter->second) if (!mapIter->second)
{ {
mObjects.insert (std::make_pair ( 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; modified = true;
} }

@ -259,8 +259,8 @@ bool CSVRender::InstanceMode::primaryEditStartDrag (const QPoint& pos)
mDragMode = DragMode_Scale; mDragMode = DragMode_Scale;
// Calculate scale factor // Calculate scale factor
std::vector<osg::ref_ptr<TagBase> > selection = getWorldspaceWidget().getEdited (Mask_Reference); std::vector<osg::ref_ptr<TagBase> > editedSelection = getWorldspaceWidget().getEdited (Mask_Reference);
osg::Vec3f center = getScreenCoords(getSelectionCenter(selection)); osg::Vec3f center = getScreenCoords(getSelectionCenter(editedSelection));
int widgetHeight = getWorldspaceWidget().height(); int widgetHeight = getWorldspaceWidget().height();

@ -558,18 +558,18 @@ std::pair< int, int > CSVRender::PagedWorldspaceWidget::getCoordinatesFromId (co
} }
bool CSVRender::PagedWorldspaceWidget::handleDrop ( 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; return true;
if (type!=Type_CellsExterior) if (type!=Type_CellsExterior)
return false; return false;
bool selectionChanged = false; bool selectionChanged = false;
for (unsigned i = 0; i < data.size(); ++i) for (unsigned i = 0; i < universalIdData.size(); ++i)
{ {
std::pair<int, int> coordinates(getCoordinatesFromId(data[i].getId())); std::pair<int, int> coordinates(getCoordinatesFromId(universalIdData[i].getId()));
if (mSelection.add(CSMWorld::CellCoordinates(coordinates.first, coordinates.second))) if (mSelection.add(CSMWorld::CellCoordinates(coordinates.first, coordinates.second)))
{ {
selectionChanged = true; selectionChanged = true;

@ -80,20 +80,20 @@ void CSVRender::UnpagedWorldspaceWidget::cellRowsAboutToBeRemoved (const QModelI
emit closeRequest(); emit closeRequest();
} }
bool CSVRender::UnpagedWorldspaceWidget::handleDrop (const std::vector<CSMWorld::UniversalId>& data, DropType type) bool CSVRender::UnpagedWorldspaceWidget::handleDrop (const std::vector<CSMWorld::UniversalId>& universalIdData, DropType type)
{ {
if (WorldspaceWidget::handleDrop (data, type)) if (WorldspaceWidget::handleDrop (universalIdData, type))
return true; return true;
if (type!=Type_CellsInterior) if (type!=Type_CellsInterior)
return false; return false;
mCellId = data.begin()->getId(); mCellId = universalIdData.begin()->getId();
mCell.reset (new Cell (getDocument().getData(), mRootNode, mCellId)); mCell.reset (new Cell (getDocument().getData(), mRootNode, mCellId));
update(); update();
emit cellChanged(*data.begin()); emit cellChanged(*universalIdData.begin());
return true; return true;
} }

@ -303,15 +303,15 @@ CSVRender::WorldspaceWidget::dropRequirments
return ignored; return ignored;
} }
bool CSVRender::WorldspaceWidget::handleDrop (const std::vector<CSMWorld::UniversalId>& data, bool CSVRender::WorldspaceWidget::handleDrop (const std::vector<CSMWorld::UniversalId>& universalIdData,
DropType type) DropType type)
{ {
if (type==Type_DebugProfile) if (type==Type_DebugProfile)
{ {
if (mRun) if (mRun)
{ {
for (std::vector<CSMWorld::UniversalId>::const_iterator iter (data.begin()); for (std::vector<CSMWorld::UniversalId>::const_iterator iter (universalIdData.begin());
iter!=data.end(); ++iter) iter!=universalIdData.end(); ++iter)
mRun->addProfile (iter->getId()); mRun->addProfile (iter->getId());
} }
@ -402,9 +402,9 @@ CSVRender::WorldspaceHitResult CSVRender::WorldspaceWidget::mousePick (const QPo
continue; continue;
} }
for (std::vector<osg::Node*>::iterator it = intersection.nodePath.begin(); it != intersection.nodePath.end(); ++it) for (std::vector<osg::Node*>::iterator nodeIter = intersection.nodePath.begin(); nodeIter != intersection.nodePath.end(); ++nodeIter)
{ {
osg::Node* node = *it; osg::Node* node = *nodeIter;
if (osg::ref_ptr<CSVRender::TagBase> tag = dynamic_cast<CSVRender::TagBase *>(node->getUserData())) if (osg::ref_ptr<CSVRender::TagBase> tag = dynamic_cast<CSVRender::TagBase *>(node->getUserData()))
{ {
WorldspaceHitResult hit = { true, tag, 0, 0, 0, intersection.getWorldIntersectPoint() }; WorldspaceHitResult hit = { true, tag, 0, 0, 0, intersection.getWorldIntersectPoint() };

@ -658,8 +658,7 @@ void CSVWorld::EditWidget::remake(int row)
int displayRole = tree->nestedHeaderData (i, col, int displayRole = tree->nestedHeaderData (i, col,
Qt::Horizontal, CSMWorld::ColumnBase::Role_Display).toInt(); Qt::Horizontal, CSMWorld::ColumnBase::Role_Display).toInt();
CSMWorld::ColumnBase::Display display = display = static_cast<CSMWorld::ColumnBase::Display> (displayRole);
static_cast<CSMWorld::ColumnBase::Display> (displayRole);
mNestedTableDispatcher->makeDelegate (display); mNestedTableDispatcher->makeDelegate (display);

@ -67,8 +67,8 @@ void CSVWorld::DragRecordTable::dropEvent(QDropEvent *event)
CSMWorld::ColumnBase::Display display = getIndexDisplayType(index); CSMWorld::ColumnBase::Display display = getIndexDisplayType(index);
if (CSVWorld::DragDropUtils::canAcceptData(*event, display)) if (CSVWorld::DragDropUtils::canAcceptData(*event, display))
{ {
const CSMWorld::TableMimeData *data = CSVWorld::DragDropUtils::getTableMimeData(*event); const CSMWorld::TableMimeData *tableMimeData = CSVWorld::DragDropUtils::getTableMimeData(*event);
if (data->fromDocument(mDocument)) if (tableMimeData->fromDocument(mDocument))
{ {
CSMWorld::UniversalId id = CSVWorld::DragDropUtils::getAcceptedData(*event, display); CSMWorld::UniversalId id = CSVWorld::DragDropUtils::getAcceptedData(*event, display);
QVariant newIndexData = QString::fromUtf8(id.getId().c_str()); QVariant newIndexData = QString::fromUtf8(id.getId().c_str());

@ -26,10 +26,10 @@ CSVWorld::ReferenceableCreator::ReferenceableCreator (CSMWorld::Data& data, QUnd
for (std::vector<CSMWorld::UniversalId::Type>::const_iterator iter (types.begin()); for (std::vector<CSMWorld::UniversalId::Type>::const_iterator iter (types.begin());
iter!=types.end(); ++iter) iter!=types.end(); ++iter)
{ {
CSMWorld::UniversalId id (*iter, ""); CSMWorld::UniversalId id2 (*iter, "");
mType->addItem (QIcon (id.getIcon().c_str()), id.getTypeName().c_str(), mType->addItem (QIcon (id2.getIcon().c_str()), id2.getTypeName().c_str(),
static_cast<int> (id.getType())); static_cast<int> (id2.getType()));
} }
insertBeforeButtons (mType, false); insertBeforeButtons (mType, false);

@ -187,18 +187,18 @@ void CSVWorld::SceneSubView::cellSelectionChanged (const CSMWorld::CellSelection
emit updateTitle(); 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::PagedWorldspaceWidget* pagedNewWidget = NULL;
CSVRender::UnpagedWorldspaceWidget* unPagedNewWidget = NULL; CSVRender::UnpagedWorldspaceWidget* unPagedNewWidget = NULL;
CSVWidget::SceneToolbar* toolbar = 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)) switch (mScene->getDropRequirements (type))
{ {
case CSVRender::WorldspaceWidget::canHandle: case CSVRender::WorldspaceWidget::canHandle:
mScene->handleDrop (data, type); mScene->handleDrop (universalIdData, type);
break; break;
case CSVRender::WorldspaceWidget::needPaged: case CSVRender::WorldspaceWidget::needPaged:
@ -206,15 +206,15 @@ void CSVWorld::SceneSubView::handleDrop (const std::vector< CSMWorld::UniversalI
toolbar = makeToolbar(pagedNewWidget, widget_Paged); toolbar = makeToolbar(pagedNewWidget, widget_Paged);
makeConnections(pagedNewWidget); makeConnections(pagedNewWidget);
replaceToolbarAndWorldspace(pagedNewWidget, toolbar); replaceToolbarAndWorldspace(pagedNewWidget, toolbar);
mScene->handleDrop (data, type); mScene->handleDrop (universalIdData, type);
break; break;
case CSVRender::WorldspaceWidget::needUnpaged: 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); toolbar = makeToolbar(unPagedNewWidget, widget_Unpaged);
makeConnections(unPagedNewWidget); makeConnections(unPagedNewWidget);
replaceToolbarAndWorldspace(unPagedNewWidget, toolbar); replaceToolbarAndWorldspace(unPagedNewWidget, toolbar);
cellSelectionChanged(*(data.begin())); cellSelectionChanged(*(universalIdData.begin()));
break; break;
case CSVRender::WorldspaceWidget::ignored: case CSVRender::WorldspaceWidget::ignored:

@ -148,14 +148,14 @@ bool CSVWorld::TableSubView::eventFilter (QObject* object, QEvent* event)
{ {
if (QDropEvent* drop = dynamic_cast<QDropEvent*>(event)) if (QDropEvent* drop = dynamic_cast<QDropEvent*>(event))
{ {
const CSMWorld::TableMimeData* data = dynamic_cast<const CSMWorld::TableMimeData*>(drop->mimeData()); const CSMWorld::TableMimeData* tableMimeData = dynamic_cast<const CSMWorld::TableMimeData*>(drop->mimeData());
if (!data) // May happen when non-records (e.g. plain text) are dragged and dropped if (!tableMimeData) // May happen when non-records (e.g. plain text) are dragged and dropped
return false; return false;
bool handled = data->holdsType(CSMWorld::UniversalId::Type_Filter); bool handled = tableMimeData->holdsType(CSMWorld::UniversalId::Type_Filter);
if (handled) if (handled)
{ {
mFilterBox->setRecordFilter(data->returnMatching(CSMWorld::UniversalId::Type_Filter).getId()); mFilterBox->setRecordFilter(tableMimeData->returnMatching(CSMWorld::UniversalId::Type_Filter).getId());
} }
return handled; return handled;
} }

@ -5,6 +5,19 @@
#include <set> #include <set>
#include <vector> #include <vector>
#include <stdint.h>
namespace Loading
{
class Listener;
}
namespace ESM
{
class ESMReader;
class ESMWriter;
}
namespace MWBase namespace MWBase
{ {
/// \brief Interface for input manager (implemented in MWInput) /// \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 /// Returns if the last used input device was a joystick or a keyboard
/// @return true if joystick, false otherwise /// @return true if joystick, false otherwise
virtual bool joystickLastUsed() = 0; 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;
}; };
} }

@ -187,12 +187,12 @@ namespace MWDialogue
state.save (writer); state.save (writer);
writer.endRecord (ESM::REC_QUES); 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; ESM::JournalEntry entry;
entry.mType = ESM::JournalEntry::Type_Quest; entry.mType = ESM::JournalEntry::Type_Quest;
entry.mTopic = quest.getTopic(); entry.mTopic = quest.getTopic();
iter->write (entry); entryIter->write (entry);
writer.startRecord (ESM::REC_JOUR); writer.startRecord (ESM::REC_JOUR);
entry.save (writer); entry.save (writer);
writer.endRecord (ESM::REC_JOUR); writer.endRecord (ESM::REC_JOUR);
@ -213,12 +213,12 @@ namespace MWDialogue
{ {
const Topic& topic = iter->second; 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; ESM::JournalEntry entry;
entry.mType = ESM::JournalEntry::Type_Topic; entry.mType = ESM::JournalEntry::Type_Topic;
entry.mTopic = topic.getTopic(); entry.mTopic = topic.getTopic();
iter->write (entry); entryIter->write (entry);
writer.startRecord (ESM::REC_JOUR); writer.startRecord (ESM::REC_JOUR);
entry.save (writer); entry.save (writer);
writer.endRecord (ESM::REC_JOUR); writer.endRecord (ESM::REC_JOUR);

@ -7,6 +7,8 @@
#include <LinearMath/btQuickprof.h> #include <LinearMath/btQuickprof.h>
#ifndef BT_NO_PROFILE
namespace namespace
{ {
void bulletDumpRecursive(CProfileIterator* pit, int spacing, std::stringstream& os) void bulletDumpRecursive(CProfileIterator* pit, int spacing, std::stringstream& os)
@ -71,6 +73,7 @@ namespace
} }
} }
#endif // BT_NO_PROFILE
namespace MWGui namespace MWGui
{ {
@ -92,10 +95,13 @@ namespace MWGui
MyGUI::IntSize viewSize = MyGUI::RenderManager::getInstance().getViewSize(); MyGUI::IntSize viewSize = MyGUI::RenderManager::getInstance().getViewSize();
mMainWidget->setSize(viewSize); mMainWidget->setSize(viewSize);
} }
void DebugWindow::onFrame(float dt) void DebugWindow::onFrame(float dt)
{ {
#ifndef BT_NO_PROFILE
if (!isVisible()) if (!isVisible())
return; return;
@ -115,6 +121,7 @@ namespace MWGui
size_t previousPos = mBulletProfilerEdit->getVScrollPosition(); size_t previousPos = mBulletProfilerEdit->getVScrollPosition();
mBulletProfilerEdit->setCaption(stream.str()); mBulletProfilerEdit->setCaption(stream.str());
mBulletProfilerEdit->setVScrollPosition(std::min(previousPos, mBulletProfilerEdit->getVScrollRange()-1)); mBulletProfilerEdit->setVScrollPosition(std::min(previousPos, mBulletProfilerEdit->getVScrollRange()-1));
#endif
} }
} }

@ -16,8 +16,13 @@
#include <components/sdlutil/sdlinputwrapper.hpp> #include <components/sdlutil/sdlinputwrapper.hpp>
#include <components/sdlutil/sdlvideowrapper.hpp> #include <components/sdlutil/sdlvideowrapper.hpp>
#include <apps/openmw/mwmp/Main.hpp> #include <apps/openmw/mwmp/Main.hpp>
#include <components/esm/esmwriter.hpp>
#include <components/esm/esmreader.hpp>
#include <components/esm/controlsstate.hpp>
#include "../mwbase/world.hpp" #include "../mwbase/world.hpp"
#include "../mwbase/windowmanager.hpp" #include "../mwbase/windowmanager.hpp"
#include "../mwbase/soundmanager.hpp" #include "../mwbase/soundmanager.hpp"
@ -1576,6 +1581,44 @@ namespace MWInput
mInputBinder->removeJoystickButtonBinding (mFakeDeviceID, mInputBinder->getJoystickButtonBinding (control, mFakeDeviceID, ICS::Control::INCREASE)); 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() void InputManager::resetToDefaultKeyBindings()
{ {
loadKeyDefaults(true); loadKeyDefaults(true);

@ -149,6 +149,10 @@ namespace MWInput
void clearAllKeyBindings (ICS::Control* control); void clearAllKeyBindings (ICS::Control* control);
void clearAllControllerBindings (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: private:
SDL_Window* mWindow; SDL_Window* mWindow;
bool mWindowVisible; bool mWindowVisible;

@ -14,6 +14,7 @@
#include <BulletCollision/CollisionDispatch/btDefaultCollisionConfiguration.h> #include <BulletCollision/CollisionDispatch/btDefaultCollisionConfiguration.h>
#include <BulletCollision/CollisionDispatch/btCollisionWorld.h> #include <BulletCollision/CollisionDispatch/btCollisionWorld.h>
#include <BulletCollision/BroadphaseCollision/btDbvtBroadphase.h> #include <BulletCollision/BroadphaseCollision/btDbvtBroadphase.h>
#include <LinearMath/btQuickprof.h> #include <LinearMath/btQuickprof.h>
#include <components/nifbullet/bulletnifloader.hpp> #include <components/nifbullet/bulletnifloader.hpp>
@ -1363,8 +1364,10 @@ namespace MWPhysics
for (std::set<Object*>::iterator it = mAnimatedObjects.begin(); it != mAnimatedObjects.end(); ++it) for (std::set<Object*>::iterator it = mAnimatedObjects.begin(); it != mAnimatedObjects.end(); ++it)
(*it)->animateCollisionShapes(mCollisionWorld); (*it)->animateCollisionShapes(mCollisionWorld);
#ifndef BT_NO_PROFILE
CProfileManager::Reset(); CProfileManager::Reset();
CProfileManager::Increment_Frame_Counter(); CProfileManager::Increment_Frame_Counter();
#endif
} }
void PhysicsSystem::debugDraw() void PhysicsSystem::debugDraw()

@ -978,8 +978,8 @@ namespace MWRender
{ {
const NifOsg::TextKeyMap &keys = (*animiter)->getTextKeys(); const NifOsg::TextKeyMap &keys = (*animiter)->getTextKeys();
const AnimSource::ControllerMap& ctrls = (*animiter)->mControllerMap[0]; const AnimSource::ControllerMap& ctrls2 = (*animiter)->mControllerMap[0];
for (AnimSource::ControllerMap::const_iterator it = ctrls.begin(); it != ctrls.end(); ++it) for (AnimSource::ControllerMap::const_iterator it = ctrls2.begin(); it != ctrls2.end(); ++it)
{ {
if (Misc::StringUtils::ciEqual(it->first, mAccumRoot->getName())) if (Misc::StringUtils::ciEqual(it->first, mAccumRoot->getName()))
{ {

@ -172,37 +172,37 @@ namespace MWRender
unsigned char r,g,b; unsigned char r,g,b;
float y = 0; float y2 = 0;
if (landData) if (landData)
y = (landData->mWnam[vertexY * 9 + vertexX] << 4) / 2048.f; y2 = (landData->mWnam[vertexY * 9 + vertexX] << 4) / 2048.f;
else else
y = (SCHAR_MIN << 4) / 2048.f; y2 = (SCHAR_MIN << 4) / 2048.f;
if (y < 0) if (y2 < 0)
{ {
r = static_cast<unsigned char>(14 * y + 38); r = static_cast<unsigned char>(14 * y2 + 38);
g = static_cast<unsigned char>(20 * y + 56); g = static_cast<unsigned char>(20 * y2 + 56);
b = static_cast<unsigned char>(18 * y + 51); b = static_cast<unsigned char>(18 * y2 + 51);
} }
else if (y < 0.3f) else if (y2 < 0.3f)
{ {
if (y < 0.1f) if (y2 < 0.1f)
y *= 8.f; y2 *= 8.f;
else else
{ {
y -= 0.1f; y2 -= 0.1f;
y += 0.8f; y2 += 0.8f;
} }
r = static_cast<unsigned char>(66 - 32 * y); r = static_cast<unsigned char>(66 - 32 * y2);
g = static_cast<unsigned char>(48 - 23 * y); g = static_cast<unsigned char>(48 - 23 * y2);
b = static_cast<unsigned char>(33 - 16 * y); b = static_cast<unsigned char>(33 - 16 * y2);
} }
else else
{ {
y -= 0.3f; y2 -= 0.3f;
y *= 1.428f; y2 *= 1.428f;
r = static_cast<unsigned char>(34 - 29 * y); r = static_cast<unsigned char>(34 - 29 * y2);
g = static_cast<unsigned char>(25 - 20 * y); g = static_cast<unsigned char>(25 - 20 * y2);
b = static_cast<unsigned char>(17 - 12 * y); b = static_cast<unsigned char>(17 - 12 * y2);
} }
data[texelY * mWidth * 3 + texelX * 3] = r; data[texelY * mWidth * 3 + texelX * 3] = r;

@ -249,7 +249,8 @@ void MWState::StateManager::saveGame (const std::string& description, const Slot
+MWBase::Environment::get().getScriptManager()->getGlobalScripts().countSavedGameRecords() +MWBase::Environment::get().getScriptManager()->getGlobalScripts().countSavedGameRecords()
+MWBase::Environment::get().getDialogueManager()->countSavedGameRecords() +MWBase::Environment::get().getDialogueManager()->countSavedGameRecords()
+MWBase::Environment::get().getWindowManager()->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.setRecordCount (recordCount);
writer.save (stream); 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().getScriptManager()->getGlobalScripts().write (writer, listener);
MWBase::Environment::get().getWindowManager()->write(writer, listener); MWBase::Environment::get().getWindowManager()->write(writer, listener);
MWBase::Environment::get().getMechanicsManager()->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 // Ensure we have written the number of records that was estimated
if (writer.getRecordCount() != recordCount+1) // 1 extra for TES3 record 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); MWBase::Environment::get().getMechanicsManager()->readRecord(reader, n.intval);
break; break;
case ESM::REC_INPU:
MWBase::Environment::get().getInputManager()->readRecord(reader, n.intval);
break;
default: default:
// ignore invalid records // ignore invalid records

@ -230,6 +230,14 @@ namespace MWWorld
return (ref.mRef.mRefnum == pRefnum); 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) void CellStore::moveFrom(const Ptr &object, CellStore *from)
{ {
if (mState != State_Loaded) if (mState != State_Loaded)
@ -1023,26 +1031,26 @@ namespace MWWorld
mLastRespawn = MWBase::Environment::get().getWorld()->getTimeStamp(); mLastRespawn = MWBase::Environment::get().getWorld()->getTimeStamp();
for (CellRefList<ESM::Container>::List::iterator it (mContainers.mList.begin()); it!=mContainers.mList.end(); ++it) for (CellRefList<ESM::Container>::List::iterator it (mContainers.mList.begin()); it!=mContainers.mList.end(); ++it)
{ {
Ptr ptr (&*it, this); Ptr ptr = getCurrentPtr(&*it);
ptr.getClass().respawn(ptr); ptr.getClass().respawn(ptr);
} }
} }
for (CellRefList<ESM::Creature>::List::iterator it (mCreatures.mList.begin()); it!=mCreatures.mList.end(); ++it) for (CellRefList<ESM::Creature>::List::iterator it (mCreatures.mList.begin()); it!=mCreatures.mList.end(); ++it)
{ {
Ptr ptr (&*it, this); Ptr ptr = getCurrentPtr(&*it);
clearCorpse(ptr); clearCorpse(ptr);
ptr.getClass().respawn(ptr); ptr.getClass().respawn(ptr);
} }
for (CellRefList<ESM::NPC>::List::iterator it (mNpcs.mList.begin()); it!=mNpcs.mList.end(); ++it) for (CellRefList<ESM::NPC>::List::iterator it (mNpcs.mList.begin()); it!=mNpcs.mList.end(); ++it)
{ {
Ptr ptr (&*it, this); Ptr ptr = getCurrentPtr(&*it);
clearCorpse(ptr); clearCorpse(ptr);
ptr.getClass().respawn(ptr); ptr.getClass().respawn(ptr);
} }
for (CellRefList<ESM::CreatureLevList>::List::iterator it (mCreatureLists.mList.begin()); it!=mCreatureLists.mList.end(); ++it) for (CellRefList<ESM::CreatureLevList>::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 // no need to clearCorpse, handled as part of mCreatures
ptr.getClass().respawn(ptr); ptr.getClass().respawn(ptr);
} }

@ -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 // Merged list of ref's currently in this cell - i.e. with added refs from mMovedHere, removed refs from mMovedToAnotherCell
std::vector<LiveCellRefBase*> mMergedRefs; std::vector<LiveCellRefBase*> 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. /// Moves object from the given cell to this cell.
void moveFrom(const MWWorld::Ptr& object, MWWorld::CellStore* from); void moveFrom(const MWWorld::Ptr& object, MWWorld::CellStore* from);

@ -450,10 +450,10 @@ void MWWorld::ContainerStore::addInitialItem (const std::string& id, const std::
} }
else else
{ {
std::string id = MWMechanics::getLevelledItem(ref.getPtr().get<ESM::ItemLevList>()->mBase, false); std::string itemId = MWMechanics::getLevelledItem(ref.getPtr().get<ESM::ItemLevList>()->mBase, false);
if (id.empty()) if (itemId.empty())
return; return;
addInitialItem(id, owner, count, false, levItemList->mId); addInitialItem(itemId, owner, count, false, levItemList->mId);
} }
} }
else else

@ -6,6 +6,7 @@
#include <components/esm/loadench.hpp> #include <components/esm/loadench.hpp>
#include <components/esm/inventorystate.hpp> #include <components/esm/inventorystate.hpp>
#include <components/misc/rng.hpp> #include <components/misc/rng.hpp>
#include <components/settings/settings.hpp>
#include "../mwbase/environment.hpp" #include "../mwbase/environment.hpp"
#include "../mwbase/world.hpp" #include "../mwbase/world.hpp"
@ -214,36 +215,71 @@ MWWorld::ContainerStoreIterator MWWorld::InventoryStore::getSlot (int slot)
return mSlots[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) 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<ESM::GameSetting> &store = world->getStore().get<ESM::GameSetting>();
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<int>((fUnarmoredBase1 * unarmoredSkill) * (fUnarmoredBase2 * unarmoredSkill));
TSlots slots_; TSlots slots_;
initSlots (slots_); initSlots (slots_);
// Disable model update during auto-equip // Disable model update during auto-equip
mUpdatesEnabled = false; 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; Ptr test = *iter;
// Don't autoEquip lights. Handled in Actors::updateEquippedLight based on environment light. if (!canActorAutoEquip(actor, test))
if (test.getTypeName() == typeid(ESM::Light).name())
{
continue; continue;
switch(test.getClass().canBeEquipped (test, actor).first)
{
case 0:
continue;
default:
break;
} }
// Only autoEquip if we are the original owner of the item. if (iter.getType() == ContainerStore::Type_Armor &&
// This stops merchants from auto equipping anything you sell to them. test.getClass().getEffectiveArmorRating(test, actor) <= std::max(unarmoredRating, 0.f))
// ...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
)
{ {
continue; continue;
} }
int testSkill = test.getClass().getEquipmentSkill (test);
std::pair<std::vector<int>, bool> itemsSlots = std::pair<std::vector<int>, bool> itemsSlots =
iter->getClass().getEquipmentSlots (*iter); iter->getClass().getEquipmentSlots (*iter);
@ -251,51 +287,35 @@ void MWWorld::InventoryStore::autoEquip (const MWWorld::Ptr& actor)
for (std::vector<int>::const_iterator iter2 (itemsSlots.first.begin()); for (std::vector<int>::const_iterator iter2 (itemsSlots.first.begin());
iter2!=itemsSlots.first.end(); ++iter2) 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()) if (slots_.at (*iter2)!=end())
{ {
Ptr old = *slots_.at (*iter2); Ptr old = *slots_.at (*iter2);
// check skill if (iter.getType() == ContainerStore::Type_Armor)
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 (actor.getClass().getSkill(actor, oldSkill) > actor.getClass().getSkill (actor, testSkill)) if (old.getTypeName() == typeid(ESM::Armor).name())
continue; // rejected, because old item better matched the NPC's skills. {
if (old.getClass().getEffectiveArmorRating(old, actor) >= test.getClass().getEffectiveArmorRating(test, actor))
if (actor.getClass().getSkill(actor, oldSkill) < actor.getClass().getSkill (actor, testSkill)) // old armor had better armor rating
use = true; continue;
}
// suitable armor should replace already equipped clothing
} }
else if (iter.getType() == ContainerStore::Type_Clothing)
if (!use)
{ {
// check value if (old.getTypeName() == typeid(ESM::Clothing).name())
if (old.getClass().getValue (old)>=
test.getClass().getValue (test))
{ {
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 if (!itemsSlots.second) // if itemsSlots.second is true, item can stay stacked when equipped
{ {
// unstack item pointed to by iterator if required // 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<int>(weaponSkillsLength); ++i)
{
int max = 0;
int maxWeaponSkill = -1;
for (int j = 0; j < static_cast<int>(weaponSkillsLength); ++j)
{
int skillValue = stats.getSkill(static_cast<int>(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<ESM::Weapon>()->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<std::vector<int>, bool> itemsSlots =
weapon->getClass().getEquipmentSlots (*weapon);
for (std::vector<int>::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; bool changed = false;
for (std::size_t i=0; i<slots_.size(); ++i) for (std::size_t i=0; i<slots_.size(); ++i)

@ -115,6 +115,8 @@ namespace MWWorld
virtual void storeEquipmentState (const MWWorld::LiveCellRefBase& ref, int index, ESM::InventoryState& inventory) const; virtual void storeEquipmentState (const MWWorld::LiveCellRefBase& ref, int index, ESM::InventoryState& inventory) const;
virtual void readEquipmentState (const MWWorld::ContainerStoreIterator& iter, int index, const ESM::InventoryState& inventory); virtual void readEquipmentState (const MWWorld::ContainerStoreIterator& iter, int index, const ESM::InventoryState& inventory);
bool canActorAutoEquip(const MWWorld::Ptr& actor, const MWWorld::Ptr& item);
public: public:
InventoryStore(); InventoryStore();

@ -832,17 +832,14 @@ bool WeatherManager::readRecord(ESM::ESMReader& reader, uint32_t type)
mQueuedWeather = state.mQueuedWeather; mQueuedWeather = state.mQueuedWeather;
mRegions.clear(); mRegions.clear();
std::map<std::string, ESM::RegionWeatherState>::iterator it = state.mRegions.begin(); importRegions();
if(it == state.mRegions.end())
{ for(std::map<std::string, ESM::RegionWeatherState>::iterator it = state.mRegions.begin(); it != state.mRegions.end(); ++it)
// When loading an imported save, the region modifiers aren't currently being set, so just reset them.
importRegions();
}
else
{ {
for(; it != state.mRegions.end(); ++it) std::map<std::string, RegionWeather>::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);
} }
} }
} }

@ -79,7 +79,7 @@ add_component_dir (esm
loadweap records aipackage effectlist spelllist variant variantimp loadtes3 cellref filter 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 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 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 add_component_dir (esmterrain

@ -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);
}

@ -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

@ -127,6 +127,7 @@ enum RecNameInts
REC_ENAB = FourCC<'E','N','A','B'>::value, REC_ENAB = FourCC<'E','N','A','B'>::value,
REC_CAM_ = FourCC<'C','A','M','_'>::value, REC_CAM_ = FourCC<'C','A','M','_'>::value,
REC_STLN = FourCC<'S','T','L','N'>::value, REC_STLN = FourCC<'S','T','L','N'>::value,
REC_INPU = FourCC<'I','N','P','U'>::value,
// format 1 // format 1
REC_FILT = FourCC<'F','I','L','T'>::value, REC_FILT = FourCC<'F','I','L','T'>::value,

@ -145,6 +145,9 @@ difficulty = 0
# Show duration of magic effect and lights in the spells window. # Show duration of magic effect and lights in the spells window.
show effect duration = false show effect duration = false
# Prevents merchants from equipping items that are sold to them.
prevent merchant equipping = false
[General] [General]
# Anisotropy reduces distortion in textures at low angles (e.g. 0 to 16). # Anisotropy reduces distortion in textures at low angles (e.g. 0 to 16).

@ -20,9 +20,7 @@ vec4 doLighting(vec3 viewPos, vec3 viewNormal, vec4 vertexColor)
d = length(lightDir); d = length(lightDir);
lightDir = normalize(lightDir); lightDir = normalize(lightDir);
lightResult.xyz += ambient * gl_LightSource[i].ambient.xyz; 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 += 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 += gl_LightModel.ambient.xyz * ambient; lightResult.xyz += gl_LightModel.ambient.xyz * ambient;

Loading…
Cancel
Save