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

# Conflicts:
#	.travis.yml
#	apps/openmw/mwinput/inputmanagerimp.cpp
This commit is contained in:
David Cernat 2016-10-24 09:18:21 +03:00
commit 47ebd24b4a
43 changed files with 477 additions and 159 deletions

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

@ -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()))
{ {

View file

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

View file

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

View file

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

View file

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

View file

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

View file

@ -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,49 +287,33 @@ 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 (actor.getClass().getSkill(actor, oldSkill) < actor.getClass().getSkill (actor, testSkill))
use = true;
}
if (!use)
{
// check value
if (old.getClass().getValue (old)>=
test.getClass().getValue (test))
{ {
continue; 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
}
else if (iter.getType() == ContainerStore::Type_Clothing)
{
if (old.getTypeName() == typeid(ESM::Clothing).name())
{
// 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
@ -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)

View file

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

View file

@ -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. std::map<std::string, RegionWeather>::iterator found = mRegions.find(it->first);
importRegions(); if (found != mRegions.end())
}
else
{
for(; it != state.mRegions.end(); ++it)
{ {
mRegions.insert(std::make_pair(it->first, RegionWeather(it->second))); found->second = RegionWeather(it->second);
} }
} }
} }

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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