Merge branch 'master' of https://github.com/OpenMW/openmw into osg

Conflicts:
	apps/opencs/CMakeLists.txt
	apps/opencs/main.cpp
	apps/openmw/mwworld/player.hpp
c++11
scrawl 10 years ago
commit a5670b5133

@ -41,9 +41,9 @@ namespace ESSImport
{
for (int i=0; i<ESM::Skill::Length; ++i)
{
npcStats.mSkills[i].mRegular.mMod = actorData.mSkills[i][1];
npcStats.mSkills[i].mRegular.mCurrent = actorData.mSkills[i][1];
npcStats.mSkills[i].mRegular.mBase = actorData.mSkills[i][0];
npcStats.mSkills[i].mMod = actorData.mSkills[i][1];
npcStats.mSkills[i].mCurrent = actorData.mSkills[i][1];
npcStats.mSkills[i].mBase = actorData.mSkills[i][0];
}
npcStats.mTimeToStartDrowning = actorData.mACDT.mBreathMeter;

@ -18,7 +18,7 @@ namespace ESSImport
for (int i=0; i<8; ++i)
out.mObject.mNpcStats.mSkillIncrease[i] = pcdt.mPNAM.mSkillIncreases[i];
for (int i=0; i<27; ++i)
out.mObject.mNpcStats.mSkills[i].mRegular.mProgress = pcdt.mPNAM.mSkillProgress[i];
out.mObject.mNpcStats.mSkills[i].mProgress = pcdt.mPNAM.mSkillProgress[i];
out.mObject.mNpcStats.mLevelProgress = pcdt.mPNAM.mLevelProgress;
if (pcdt.mPNAM.mDrawState & PCDT::DrawState_Weapon)

@ -70,11 +70,12 @@ opencs_units (view/world
opencs_units_noqt (view/world
subviews enumdelegate vartypedelegate recordstatusdelegate idtypedelegate datadisplaydelegate
scripthighlighter idvalidator dialoguecreator idcompletiondelegate
colordelegate
)
opencs_units (view/widget
scenetoolbar scenetool scenetoolmode pushbutton scenetooltoggle scenetoolrun modebutton
scenetooltoggle2 completerpopup
scenetooltoggle2 completerpopup coloreditor colorpickerpopup
)
opencs_units (view/render

@ -9,6 +9,8 @@
#include <QIcon>
#include <QMetaType>
#include "model/doc/messages.hpp"
#include "model/world/universalid.hpp"
#ifdef Q_OS_MAC
@ -51,6 +53,7 @@ int main(int argc, char *argv[])
qRegisterMetaType<std::string> ("std::string");
qRegisterMetaType<CSMWorld::UniversalId> ("CSMWorld::UniversalId");
qRegisterMetaType<CSMDoc::Message> ("CSMDoc::Message");
Application application (argc, argv);

@ -2302,8 +2302,8 @@ CSMDoc::Document::Document (const VFS::Manager* vfs, const Files::ConfigurationM
connect (&mSaving, SIGNAL (done (int, bool)), this, SLOT (operationDone (int, bool)));
connect (
&mSaving, SIGNAL (reportMessage (const CSMWorld::UniversalId&, const std::string&, const std::string&, int)),
this, SLOT (reportMessage (const CSMWorld::UniversalId&, const std::string&, const std::string&, int)));
&mSaving, SIGNAL (reportMessage (const CSMDoc::Message&, int)),
this, SLOT (reportMessage (const CSMDoc::Message&, int)));
connect (&mRunner, SIGNAL (runStateChanged()), this, SLOT (runStateChanged()));
}
@ -2404,11 +2404,10 @@ void CSMDoc::Document::modificationStateChanged (bool clean)
emit stateChanged (getState(), this);
}
void CSMDoc::Document::reportMessage (const CSMWorld::UniversalId& id, const std::string& message,
const std::string& hint, int type)
void CSMDoc::Document::reportMessage (const CSMDoc::Message& message, int type)
{
/// \todo find a better way to get these messages to the user.
std::cout << message << std::endl;
std::cout << message.mMessage << std::endl;
}
void CSMDoc::Document::operationDone (int type, bool failed)

@ -160,8 +160,7 @@ namespace CSMDoc
void modificationStateChanged (bool clean);
void reportMessage (const CSMWorld::UniversalId& id, const std::string& message,
const std::string& hint, int type);
void reportMessage (const CSMDoc::Message& message, int type);
void operationDone (int type, bool failed);

@ -52,7 +52,7 @@ void CSMDoc::Loader::load()
{
if (iter->second.mRecordsLeft)
{
CSMDoc::Messages messages;
Messages messages (Message::Severity_Error);
for (int i=0; i<batchingSize; ++i) // do not flood the system with update signals
if (document->getData().continueLoading (messages))
{
@ -68,7 +68,7 @@ void CSMDoc::Loader::load()
for (CSMDoc::Messages::Iterator iter (messages.begin());
iter!=messages.end(); ++iter)
{
document->getReport (log)->add (iter->mId, iter->mMessage);
document->getReport (log)->add (*iter);
emit loadMessage (document, iter->mMessage);
}
}

@ -1,15 +1,25 @@
#include "messages.hpp"
CSMDoc::Message::Message() {}
CSMDoc::Message::Message (const CSMWorld::UniversalId& id, const std::string& message,
const std::string& hint, Severity severity)
: mId (id), mMessage (message), mHint (hint), mSeverity (severity)
{}
CSMDoc::Messages::Messages (Message::Severity default_)
: mDefault (default_)
{}
void CSMDoc::Messages::add (const CSMWorld::UniversalId& id, const std::string& message,
const std::string& hint)
const std::string& hint, Message::Severity severity)
{
Message data;
data.mId = id;
data.mMessage = message;
data.mHint = hint;
mMessages.push_back (data);
if (severity==Message::Severity_Default)
severity = mDefault;
mMessages.push_back (Message (id, message, hint, severity));
}
void CSMDoc::Messages::push_back (const std::pair<CSMWorld::UniversalId, std::string>& data)

@ -4,20 +4,41 @@
#include <string>
#include <vector>
#include <QMetaType>
#include "../world/universalid.hpp"
namespace CSMDoc
{
struct Message
{
enum Severity
{
Severity_Info = 0, // no problem
Severity_Warning = 1, // a potential problem, but we are probably fine
Severity_Error = 2, // an error; we are not fine
Severity_SeriousError = 3, // an error so bad we can't even be sure if we are
// reporting it correctly
Severity_Default = 4
};
CSMWorld::UniversalId mId;
std::string mMessage;
std::string mHint;
Severity mSeverity;
Message();
Message (const CSMWorld::UniversalId& id, const std::string& message,
const std::string& hint, Severity severity);
};
class Messages
{
public:
struct Message
{
CSMWorld::UniversalId mId;
std::string mMessage;
std::string mHint;
};
// \deprecated Use CSMDoc::Message directly instead.
typedef CSMDoc::Message Message;
typedef std::vector<Message> Collection;
@ -26,11 +47,15 @@ namespace CSMDoc
private:
Collection mMessages;
Message::Severity mDefault;
public:
Messages (Message::Severity default_);
void add (const CSMWorld::UniversalId& id, const std::string& message,
const std::string& hint = "");
const std::string& hint = "",
Message::Severity severity = Message::Severity_Default);
/// \deprecated Use add instead.
void push_back (const std::pair<CSMWorld::UniversalId, std::string>& data);
@ -41,4 +66,6 @@ namespace CSMDoc
};
}
Q_DECLARE_METATYPE (CSMDoc::Message)
#endif

@ -7,6 +7,7 @@
#include <QTimer>
#include "../world/universalid.hpp"
#include "../settings/usersettings.hpp"
#include "state.hpp"
#include "stage.hpp"
@ -23,13 +24,17 @@ void CSMDoc::Operation::prepareStages()
{
iter->second = iter->first->setup();
mTotalSteps += iter->second;
for (std::map<QString, QStringList>::const_iterator iter2 (mSettings.begin()); iter2!=mSettings.end(); ++iter2)
iter->first->updateUserSetting (iter2->first, iter2->second);
}
}
CSMDoc::Operation::Operation (int type, bool ordered, bool finalAlways)
: mType (type), mStages(std::vector<std::pair<Stage *, int> >()), mCurrentStage(mStages.begin()),
mCurrentStep(0), mCurrentStepTotal(0), mTotalSteps(0), mOrdered (ordered),
mFinalAlways (finalAlways), mError(false), mConnected (false)
mFinalAlways (finalAlways), mError(false), mConnected (false), mPrepared (false),
mDefaultSeverity (Message::Severity_Error)
{
mTimer = new QTimer (this);
}
@ -49,8 +54,8 @@ void CSMDoc::Operation::run()
connect (mTimer, SIGNAL (timeout()), this, SLOT (executeStage()));
mConnected = true;
}
prepareStages();
mPrepared = false;
mTimer->start (0);
}
@ -60,6 +65,19 @@ void CSMDoc::Operation::appendStage (Stage *stage)
mStages.push_back (std::make_pair (stage, 0));
}
void CSMDoc::Operation::configureSettings (const std::vector<QString>& settings)
{
for (std::vector<QString>::const_iterator iter (settings.begin()); iter!=settings.end(); ++iter)
{
mSettings.insert (std::make_pair (*iter, CSMSettings::UserSettings::instance().definitions (*iter)));
}
}
void CSMDoc::Operation::setDefaultSeverity (Message::Severity severity)
{
mDefaultSeverity = severity;
}
bool CSMDoc::Operation::hasError() const
{
return mError;
@ -84,9 +102,23 @@ void CSMDoc::Operation::abort()
mCurrentStage = mStages.end();
}
void CSMDoc::Operation::updateUserSetting (const QString& name, const QStringList& value)
{
std::map<QString, QStringList>::iterator iter = mSettings.find (name);
if (iter!=mSettings.end())
iter->second = value;
}
void CSMDoc::Operation::executeStage()
{
Messages messages;
if (!mPrepared)
{
prepareStages();
mPrepared = true;
}
Messages messages (mDefaultSeverity);
while (mCurrentStage!=mStages.end())
{
@ -103,7 +135,7 @@ void CSMDoc::Operation::executeStage()
}
catch (const std::exception& e)
{
emit reportMessage (CSMWorld::UniversalId(), e.what(), "", mType);
emit reportMessage (Message (CSMWorld::UniversalId(), e.what(), "", Message::Severity_SeriousError), mType);
abort();
}
@ -115,7 +147,7 @@ void CSMDoc::Operation::executeStage()
emit progress (mCurrentStepTotal, mTotalSteps ? mTotalSteps : 1, mType);
for (Messages::Iterator iter (messages.begin()); iter!=messages.end(); ++iter)
emit reportMessage (iter->mId, iter->mMessage, iter->mHint, mType);
emit reportMessage (*iter, mType);
if (mCurrentStage==mStages.end())
operationDone();

@ -2,9 +2,13 @@
#define CSM_DOC_OPERATION_H
#include <vector>
#include <map>
#include <QObject>
#include <QTimer>
#include <QStringList>
#include "messages.hpp"
namespace CSMWorld
{
@ -30,6 +34,9 @@ namespace CSMDoc
bool mError;
bool mConnected;
QTimer *mTimer;
std::map<QString, QStringList> mSettings;
bool mPrepared;
Message::Severity mDefaultSeverity;
void prepareStages();
@ -46,14 +53,21 @@ namespace CSMDoc
///
/// \attention Do no call this function while this Operation is running.
/// Specify settings to be passed on to stages.
///
/// \attention Do no call this function while this Operation is running.
void configureSettings (const std::vector<QString>& settings);
/// \attention Do no call this function while this Operation is running.
void setDefaultSeverity (Message::Severity severity);
bool hasError() const;
signals:
void progress (int current, int max, int type);
void reportMessage (const CSMWorld::UniversalId& id, const std::string& message,
const std::string& hint, int type);
void reportMessage (const CSMDoc::Message& message, int type);
void done (int type, bool failed);
@ -63,6 +77,8 @@ namespace CSMDoc
void run();
void updateUserSetting (const QString& name, const QStringList& value);
private slots:
void executeStage();

@ -1,6 +1,8 @@
#include "operationholder.hpp"
#include "../settings/usersettings.hpp"
#include "operation.hpp"
CSMDoc::OperationHolder::OperationHolder (Operation *operation) : mRunning (false)
@ -19,8 +21,8 @@ void CSMDoc::OperationHolder::setOperation (Operation *operation)
this, SIGNAL (progress (int, int, int)));
connect (
mOperation, SIGNAL (reportMessage (const CSMWorld::UniversalId&, const std::string&, const std::string&, int)),
this, SIGNAL (reportMessage (const CSMWorld::UniversalId&, const std::string&, const std::string&, int)));
mOperation, SIGNAL (reportMessage (const CSMDoc::Message&, int)),
this, SIGNAL (reportMessage (const CSMDoc::Message&, int)));
connect (
mOperation, SIGNAL (done (int, bool)),
@ -29,6 +31,9 @@ void CSMDoc::OperationHolder::setOperation (Operation *operation)
connect (this, SIGNAL (abortSignal()), mOperation, SLOT (abort()));
connect (&mThread, SIGNAL (started()), mOperation, SLOT (run()));
connect (&CSMSettings::UserSettings::instance(), SIGNAL (userSettingUpdated (const QString&, const QStringList&)),
mOperation, SLOT (updateUserSetting (const QString&, const QStringList&)));
}
bool CSMDoc::OperationHolder::isRunning() const

@ -4,6 +4,8 @@
#include <QObject>
#include <QThread>
#include "messages.hpp"
namespace CSMWorld
{
class UniversalId;
@ -44,8 +46,7 @@ namespace CSMDoc
void progress (int current, int max, int type);
void reportMessage (const CSMWorld::UniversalId& id, const std::string& message,
const std::string& hint, int type);
void reportMessage (const CSMDoc::Message& message, int type);
void done (int type, bool failed);

@ -2,3 +2,5 @@
#include "stage.hpp"
CSMDoc::Stage::~Stage() {}
void CSMDoc::Stage::updateUserSetting (const QString& name, const QStringList& value) {}

@ -8,6 +8,8 @@
#include "messages.hpp"
class QString;
namespace CSMDoc
{
class Stage
@ -21,6 +23,9 @@ namespace CSMDoc
virtual void perform (int stage, Messages& messages) = 0;
///< Messages resulting from this stage will be appended to \a messages.
/// Default-implementation: ignore
virtual void updateUserSetting (const QString& name, const QStringList& value);
};
}

@ -217,6 +217,47 @@ void CSMSettings::UserSettings::buildSettingModelDefaults()
jumpToAdded->setDeclaredValues (jumpValues);
}
declareSection ("report-input", "Report Input");
{
QString none ("None");
QString edit ("Edit");
QString remove ("Remove");
QString editAndRemove ("Edit And Remove");
QStringList values;
values << none << edit << remove << editAndRemove;
QString toolTip = "<ul>"
"<li>None</li>"
"<li>Edit: Open a table or dialogue suitable for addressing the listed report</li>"
"<li>Remove: Remove the report from the report table</li>"
"<li>Edit and Remove: Open a table or dialogue suitable for addressing the listed report, then remove the report from the report table</li>"
"</ul>";
Setting *doubleClick = createSetting (Type_ComboBox, "double", "Double Click");
doubleClick->setDeclaredValues (values);
doubleClick->setDefaultValue (edit);
doubleClick->setToolTip ("Action on double click in report table:<p>" + toolTip);
Setting *shiftDoubleClick = createSetting (Type_ComboBox, "double-s",
"Shift Double Click");
shiftDoubleClick->setDeclaredValues (values);
shiftDoubleClick->setDefaultValue (remove);
shiftDoubleClick->setToolTip ("Action on shift double click in report table:<p>" + toolTip);
Setting *ctrlDoubleClick = createSetting (Type_ComboBox, "double-c",
"Control Double Click");
ctrlDoubleClick->setDeclaredValues (values);
ctrlDoubleClick->setDefaultValue (editAndRemove);
ctrlDoubleClick->setToolTip ("Action on control double click in report table:<p>" + toolTip);
Setting *shiftCtrlDoubleClick = createSetting (Type_ComboBox, "double-sc",
"Shift Control Double Click");
shiftCtrlDoubleClick->setDeclaredValues (values);
shiftCtrlDoubleClick->setDefaultValue (none);
shiftCtrlDoubleClick->setToolTip ("Action on shift control double click in report table:<p>" + toolTip);
}
declareSection ("search", "Search & Replace");
{
Setting *before = createSetting (Type_SpinBox, "char-before",
@ -235,7 +276,7 @@ void CSMSettings::UserSettings::buildSettingModelDefaults()
autoDelete->setDefaultValue ("true");
}
declareSection ("script-editor", "Script Editor");
declareSection ("script-editor", "Scripts");
{
Setting *lineNum = createSetting (Type_CheckBox, "show-linenum", "Show Line Numbers");
lineNum->setDefaultValue ("true");
@ -254,6 +295,21 @@ void CSMSettings::UserSettings::buildSettingModelDefaults()
"\nA name from the list of colors defined in the list of SVG color keyword names."
"\nX11 color names may also work.";
QString modeNormal ("Normal");
QStringList modes;
modes << "Ignore" << modeNormal << "Strict";
Setting *warnings = createSetting (Type_ComboBox, "warnings",
"Warning Mode");
warnings->setDeclaredValues (modes);
warnings->setDefaultValue (modeNormal);
warnings->setToolTip ("<ul>How to handle warning messages during compilation:<p>"
"<li>Ignore: Do not report warning</li>"
"<li>Normal: Report warning as a warning</li>"
"<li>Strict: Promote warning to an error</li>"
"</ul>");
Setting *formatInt = createSetting (Type_LineEdit, "colour-int", "Highlight Colour: Int");
formatInt->setDefaultValues (QStringList() << "Dark magenta");
formatInt->setToolTip ("(Default: Green) Use one of the following formats:" + tooltip);

@ -6,24 +6,18 @@
#include "../world/columns.hpp"
CSMTools::ReportModel::Line::Line (const CSMWorld::UniversalId& id, const std::string& message,
const std::string& hint)
: mId (id), mMessage (message), mHint (hint)
{}
CSMTools::ReportModel::ReportModel (bool fieldColumn)
CSMTools::ReportModel::ReportModel (bool fieldColumn, bool severityColumn)
: mColumnField (-1), mColumnSeverity (-1)
{
int index = 3;
if (severityColumn)
mColumnSeverity = index++;
if (fieldColumn)
{
mColumnField = 3;
mColumnDescription = 4;
}
else
{
mColumnDescription = 3;
mColumnField = index++;
mColumnField = -1;
}
mColumnDescription = index;
}
int CSMTools::ReportModel::rowCount (const QModelIndex & parent) const
@ -88,6 +82,18 @@ QVariant CSMTools::ReportModel::data (const QModelIndex & index, int role) const
return QString::fromUtf8 (field.c_str());
}
if (index.column()==mColumnSeverity)
{
switch (mRows.at (index.row()).mSeverity)
{
case CSMDoc::Message::Severity_Info: return "Information";
case CSMDoc::Message::Severity_Warning: return "Warning";
case CSMDoc::Message::Severity_Error: return "Error";
case CSMDoc::Message::Severity_SeriousError: return "Serious Error";
case CSMDoc::Message::Severity_Default: break;
}
}
return QVariant();
}
@ -112,6 +118,9 @@ QVariant CSMTools::ReportModel::headerData (int section, Qt::Orientation orienta
if (section==mColumnField)
return "Field";
if (section==mColumnSeverity)
return "Severity";
return "-";
}
@ -132,19 +141,18 @@ bool CSMTools::ReportModel::removeRows (int row, int count, const QModelIndex& p
return true;
}
void CSMTools::ReportModel::add (const CSMWorld::UniversalId& id, const std::string& message,
const std::string& hint)
void CSMTools::ReportModel::add (const CSMDoc::Message& message)
{
beginInsertRows (QModelIndex(), mRows.size(), mRows.size());
mRows.push_back (Line (id, message, hint));
mRows.push_back (message);
endInsertRows();
}
void CSMTools::ReportModel::flagAsReplaced (int index)
{
Line& line = mRows.at (index);
CSMDoc::Message& line = mRows.at (index);
std::string hint = line.mHint;
if (hint.empty() || hint[0]!='R')
@ -176,3 +184,16 @@ void CSMTools::ReportModel::clear()
endRemoveRows();
}
}
int CSMTools::ReportModel::countErrors() const
{
int count = 0;
for (std::vector<CSMDoc::Messages::Message>::const_iterator iter (mRows.begin());
iter!=mRows.end(); ++iter)
if (iter->mSeverity==CSMDoc::Message::Severity_Error ||
iter->mSeverity==CSMDoc::Message::Severity_SeriousError)
++count;
return count;
}

@ -6,6 +6,8 @@
#include <QAbstractTableModel>
#include "../doc/messages.hpp"
#include "../world/universalid.hpp"
namespace CSMTools
@ -14,17 +16,7 @@ namespace CSMTools
{
Q_OBJECT
struct Line
{
Line (const CSMWorld::UniversalId& id, const std::string& message,
const std::string& hint);
CSMWorld::UniversalId mId;
std::string mMessage;
std::string mHint;
};
std::vector<Line> mRows;
std::vector<CSMDoc::Messages::Message> mRows;
// Fixed columns
enum Columns
@ -35,10 +27,11 @@ namespace CSMTools
// Configurable columns
int mColumnDescription;
int mColumnField;
int mColumnSeverity;
public:
ReportModel (bool fieldColumn = false);
ReportModel (bool fieldColumn = false, bool severityColumn = true);
virtual int rowCount (const QModelIndex & parent = QModelIndex()) const;
@ -50,8 +43,7 @@ namespace CSMTools
virtual bool removeRows (int row, int count, const QModelIndex& parent = QModelIndex());
void add (const CSMWorld::UniversalId& id, const std::string& message,
const std::string& hint = "");
void add (const CSMDoc::Message& message);
void flagAsReplaced (int index);
@ -60,6 +52,9 @@ namespace CSMTools
std::string getHint (int row) const;
void clear();
// Return number of messages with Error or SeriousError severity.
int countErrors() const;
};
}

@ -11,6 +11,17 @@
#include "../world/data.hpp"
CSMDoc::Message::Severity CSMTools::ScriptCheckStage::getSeverity (Type type)
{
switch (type)
{
case WarningMessage: return CSMDoc::Message::Severity_Warning;
case ErrorMessage: return CSMDoc::Message::Severity_Error;
}
return CSMDoc::Message::Severity_SeriousError;
}
void CSMTools::ScriptCheckStage::report (const std::string& message, const Compiler::TokenLoc& loc,
Type type)
{
@ -18,11 +29,6 @@ void CSMTools::ScriptCheckStage::report (const std::string& message, const Compi
CSMWorld::UniversalId id (CSMWorld::UniversalId::Type_Script, mId);
if (type==ErrorMessage)
stream << "error ";
else
stream << "warning ";
stream
<< "script " << mFile
<< ", line " << loc.mLine << ", column " << loc.mColumn
@ -32,19 +38,21 @@ void CSMTools::ScriptCheckStage::report (const std::string& message, const Compi
hintStream << "l:" << loc.mLine << " " << loc.mColumn;
mMessages->add (id, stream.str(), hintStream.str());
mMessages->add (id, stream.str(), hintStream.str(), getSeverity (type));
}
void CSMTools::ScriptCheckStage::report (const std::string& message, Type type)
{
CSMWorld::UniversalId id (CSMWorld::UniversalId::Type_Script, mId);
mMessages->push_back (std::make_pair (id,
(type==ErrorMessage ? "error: " : "warning: ") + message));
std::ostringstream stream;
stream << "script " << mFile << ": " << message;
mMessages->add (id, stream.str(), "", getSeverity (type));
}
CSMTools::ScriptCheckStage::ScriptCheckStage (const CSMDoc::Document& document)
: mDocument (document), mContext (document.getData()), mMessages (0)
: mDocument (document), mContext (document.getData()), mMessages (0), mWarningMode (Mode_Ignore)
{
/// \todo add an option to configure warning mode
setWarningsMode (0);
@ -58,6 +66,7 @@ int CSMTools::ScriptCheckStage::setup()
mContext.clear();
mMessages = 0;
mId.clear();
Compiler::ErrorHandler::reset();
return mDocument.getData().getScripts().getSize();
}
@ -72,6 +81,13 @@ void CSMTools::ScriptCheckStage::perform (int stage, CSMDoc::Messages& messages)
mMessages = &messages;
switch (mWarningMode)
{
case Mode_Ignore: setWarningsMode (0); break;
case Mode_Normal: setWarningsMode (1); break;
case Mode_Strict: setWarningsMode (2); break;
}
try
{
const CSMWorld::Data& data = mDocument.getData();
@ -93,9 +109,24 @@ void CSMTools::ScriptCheckStage::perform (int stage, CSMDoc::Messages& messages)
{
CSMWorld::UniversalId id (CSMWorld::UniversalId::Type_Script, mId);
messages.push_back (std::make_pair (id,
std::string ("Critical compile error: ") + error.what()));
std::ostringstream stream;
stream << "script " << mFile << ": " << error.what();
messages.add (id, stream.str(), "", CSMDoc::Message::Severity_SeriousError);
}
mMessages = 0;
}
void CSMTools::ScriptCheckStage::updateUserSetting (const QString& name, const QStringList& value)
{
if (name=="script-editor/warnings")
{
if (value.at (0)=="Ignore")
mWarningMode = Mode_Ignore;
else if (value.at (0)=="Normal")
mWarningMode = Mode_Normal;
else if (value.at (0)=="Strict")
mWarningMode = Mode_Strict;
}
}

@ -18,13 +18,23 @@ namespace CSMTools
/// \brief VerifyStage: make sure that scripts compile
class ScriptCheckStage : public CSMDoc::Stage, private Compiler::ErrorHandler
{
enum WarningMode
{
Mode_Ignore,
Mode_Normal,
Mode_Strict
};
const CSMDoc::Document& mDocument;
Compiler::Extensions mExtensions;
CSMWorld::ScriptContext mContext;
std::string mId;
std::string mFile;
CSMDoc::Messages *mMessages;
WarningMode mWarningMode;
CSMDoc::Message::Severity getSeverity (Type type);
virtual void report (const std::string& message, const Compiler::TokenLoc& loc, Type type);
///< Report error to the user.
@ -40,6 +50,8 @@ namespace CSMTools
virtual void perform (int stage, CSMDoc::Messages& messages);
///< Messages resulting from this tage will be appended to \a messages.
virtual void updateUserSetting (const QString& name, const QStringList& value);
};
}

@ -280,7 +280,7 @@ void CSMTools::Search::replace (CSMDoc::Document& document, CSMWorld::IdTableBas
bool CSMTools::Search::verify (CSMDoc::Document& document, CSMWorld::IdTableBase *model,
const CSMWorld::UniversalId& id, const std::string& messageHint) const
{
CSMDoc::Messages messages;
CSMDoc::Messages messages (CSMDoc::Message::Severity_Info);
int row = model->getModelIndex (id.getId(),
model->findColumnIndex (CSMWorld::Columns::ColumnId_Id)).row();

@ -21,6 +21,8 @@ CSMTools::SearchOperation::SearchOperation (CSMDoc::Document& document)
iter!=types.end(); ++iter)
appendStage (new SearchStage (&dynamic_cast<CSMWorld::IdTableBase&> (
*document.getData().getTableModel (*iter))));
setDefaultSeverity (CSMDoc::Message::Severity_Info);
}
void CSMTools::SearchOperation::configure (const Search& search)

@ -51,11 +51,15 @@ CSMDoc::OperationHolder *CSMTools::Tools::getVerifier()
{
mVerifierOperation = new CSMDoc::Operation (CSMDoc::State_Verifying, false);
std::vector<QString> settings;
settings.push_back ("script-editor/warnings");
mVerifierOperation->configureSettings (settings);
connect (&mVerifier, SIGNAL (progress (int, int, int)), this, SIGNAL (progress (int, int, int)));
connect (&mVerifier, SIGNAL (done (int, bool)), this, SIGNAL (done (int, bool)));
connect (&mVerifier,
SIGNAL (reportMessage (const CSMWorld::UniversalId&, const std::string&, const std::string&, int)),
this, SLOT (verifierMessage (const CSMWorld::UniversalId&, const std::string&, const std::string&, int)));
connect (&mVerifier, SIGNAL (reportMessage (const CSMDoc::Message&, int)),
this, SLOT (verifierMessage (const CSMDoc::Message&, int)));
std::vector<std::string> mandatoryIds; // I want C++11, damn it!
mandatoryIds.push_back ("Day");
@ -120,9 +124,8 @@ CSMTools::Tools::Tools (CSMDoc::Document& document)
connect (&mSearch, SIGNAL (progress (int, int, int)), this, SIGNAL (progress (int, int, int)));
connect (&mSearch, SIGNAL (done (int, bool)), this, SIGNAL (done (int, bool)));
connect (&mSearch,
SIGNAL (reportMessage (const CSMWorld::UniversalId&, const std::string&, const std::string&, int)),
this, SLOT (verifierMessage (const CSMWorld::UniversalId&, const std::string&, const std::string&, int)));
connect (&mSearch, SIGNAL (reportMessage (const CSMDoc::Message&, int)),
this, SLOT (verifierMessage (const CSMDoc::Message&, int)));
}
CSMTools::Tools::~Tools()
@ -155,7 +158,7 @@ CSMWorld::UniversalId CSMTools::Tools::runVerifier()
CSMWorld::UniversalId CSMTools::Tools::newSearch()
{
mReports.insert (std::make_pair (mNextReportNumber++, new ReportModel (true)));
mReports.insert (std::make_pair (mNextReportNumber++, new ReportModel (true, false)));
return CSMWorld::UniversalId (CSMWorld::UniversalId::Type_Search, mNextReportNumber-1);
}
@ -210,12 +213,11 @@ CSMTools::ReportModel *CSMTools::Tools::getReport (const CSMWorld::UniversalId&
return mReports.at (id.getIndex());
}
void CSMTools::Tools::verifierMessage (const CSMWorld::UniversalId& id, const std::string& message,
const std::string& hint, int type)
void CSMTools::Tools::verifierMessage (const CSMDoc::Message& message, int type)
{
std::map<int, int>::iterator iter = mActiveReports.find (type);
if (iter!=mActiveReports.end())
mReports[iter->second]->add (id, message, hint);
mReports[iter->second]->add (message);
}

@ -75,8 +75,7 @@ namespace CSMTools
private slots:
void verifierMessage (const CSMWorld::UniversalId& id, const std::string& message,
const std::string& hint, int type);
void verifierMessage (const CSMDoc::Message& message, int type);
signals:

@ -694,7 +694,7 @@ namespace CSMWorld
QColor colour = data.value<QColor>();
record2.mMapColor = colour.rgb() & 0xffffff;
record2.mMapColor = (colour.blue() << 16) | (colour.green() << 8) | colour.red();
record.setModified (record2);
}

@ -933,7 +933,7 @@ bool CSMWorld::Data::continueLoading (CSMDoc::Messages& messages)
{
// log an error and continue loading the refs to the last loaded cell
CSMWorld::UniversalId id (CSMWorld::UniversalId::Type_None);
messages.add (id, "Logic error: cell index out of bounds");
messages.add (id, "Logic error: cell index out of bounds", "", CSMDoc::Message::Severity_Error);
index = mCells.getSize()-1;
}
std::string cellId = Misc::StringUtils::lowerCase (mCells.getId (index));
@ -994,7 +994,8 @@ bool CSMWorld::Data::continueLoading (CSMDoc::Messages& messages)
else
{
messages.add (UniversalId::Type_None,
"Trying to delete dialogue record " + id + " which does not exist");
"Trying to delete dialogue record " + id + " which does not exist",
"", CSMDoc::Message::Severity_Warning);
}
}
else
@ -1011,7 +1012,7 @@ bool CSMWorld::Data::continueLoading (CSMDoc::Messages& messages)
if (!mDialogue)
{
messages.add (UniversalId::Type_None,
"Found info record not following a dialogue record");
"Found info record not following a dialogue record", "", CSMDoc::Message::Severity_Error);
mReader->skipRecord();
break;
@ -1054,7 +1055,8 @@ bool CSMWorld::Data::continueLoading (CSMDoc::Messages& messages)
if (unhandledRecord)
{
messages.add (UniversalId::Type_None, "Unsupported record type: " + n.toString());
messages.add (UniversalId::Type_None, "Unsupported record type: " + n.toString(), "",
CSMDoc::Message::Severity_Error);
mReader->skipRecord();
}

@ -24,6 +24,7 @@ namespace
types[CSMWorld::ColumnBase::Display_Faction ] = CSMWorld::UniversalId::Type_Faction;
types[CSMWorld::ColumnBase::Display_GlobalVariable ] = CSMWorld::UniversalId::Type_Global;
types[CSMWorld::ColumnBase::Display_Icon ] = CSMWorld::UniversalId::Type_Icon;
types[CSMWorld::ColumnBase::Display_Journal ] = CSMWorld::UniversalId::Type_Journal;
types[CSMWorld::ColumnBase::Display_Mesh ] = CSMWorld::UniversalId::Type_Mesh;
types[CSMWorld::ColumnBase::Display_Miscellaneous ] = CSMWorld::UniversalId::Type_Referenceable;
types[CSMWorld::ColumnBase::Display_Npc ] = CSMWorld::UniversalId::Type_Referenceable;
@ -37,6 +38,7 @@ namespace
types[CSMWorld::ColumnBase::Display_Spell ] = CSMWorld::UniversalId::Type_Spell;
types[CSMWorld::ColumnBase::Display_Static ] = CSMWorld::UniversalId::Type_Referenceable;
types[CSMWorld::ColumnBase::Display_Texture ] = CSMWorld::UniversalId::Type_Texture;
types[CSMWorld::ColumnBase::Display_Topic ] = CSMWorld::UniversalId::Type_Topic;
types[CSMWorld::ColumnBase::Display_Weapon ] = CSMWorld::UniversalId::Type_Referenceable;
return types;

@ -21,6 +21,7 @@
#include "../world/recordstatusdelegate.hpp"
#include "../world/idtypedelegate.hpp"
#include "../world/idcompletiondelegate.hpp"
#include "../world/colordelegate.hpp"
#include "../../model/settings/usersettings.hpp"
@ -61,6 +62,9 @@ CSVDoc::ViewManager::ViewManager (CSMDoc::DocumentManager& documentManager)
mDelegateFactories->add (CSMWorld::ColumnBase::Display_RefRecordType,
new CSVWorld::IdTypeDelegateFactory());
mDelegateFactories->add (CSMWorld::ColumnBase::Display_Colour,
new CSVWorld::ColorDelegateFactory());
std::vector<CSMWorld::ColumnBase::Display> idCompletionColumns = CSMWorld::IdCompletionManager::getDisplayTypes();
for (std::vector<CSMWorld::ColumnBase::Display>::const_iterator current = idCompletionColumns.begin();
current != idCompletionColumns.end();

@ -96,21 +96,35 @@ void CSVTools::ReportTable::mouseDoubleClickEvent (QMouseEvent *event)
selectionModel()->select (index,
QItemSelectionModel::Clear | QItemSelectionModel::Select | QItemSelectionModel::Rows);
switch (modifiers)
std::map<Qt::KeyboardModifiers, DoubleClickAction>::iterator iter =
mDoubleClickActions.find (modifiers);
if (iter==mDoubleClickActions.end())
{
event->accept();
return;
}
switch (iter->second)
{
case 0:
case Action_None:
event->accept();
break;
case Action_Edit:
event->accept();
showSelection();
break;
case Qt::ShiftModifier:
case Action_Remove:
event->accept();
removeSelection();
break;
case Qt::ControlModifier:
case Action_EditAndRemove:
event->accept();
showSelection();
@ -155,7 +169,11 @@ CSVTools::ReportTable::ReportTable (CSMDoc::Document& document,
mReplaceAction = new QAction (tr ("Replace"), this);
connect (mReplaceAction, SIGNAL (triggered()), this, SIGNAL (replaceRequest()));
addAction (mReplaceAction);
addAction (mReplaceAction);
mDoubleClickActions.insert (std::make_pair (Qt::NoModifier, Action_Edit));
mDoubleClickActions.insert (std::make_pair (Qt::ShiftModifier, Action_Remove));
mDoubleClickActions.insert (std::make_pair (Qt::ControlModifier, Action_EditAndRemove));
}
std::vector<CSMWorld::UniversalId> CSVTools::ReportTable::getDraggedRecords() const
@ -176,6 +194,35 @@ std::vector<CSMWorld::UniversalId> CSVTools::ReportTable::getDraggedRecords() co
void CSVTools::ReportTable::updateUserSetting (const QString& name, const QStringList& list)
{
mIdTypeDelegate->updateUserSetting (name, list);
QString base ("report-input/double");
if (name.startsWith (base))
{
QString modifierString = name.mid (base.size());
Qt::KeyboardModifiers modifiers = 0;
if (modifierString=="-s")
modifiers = Qt::ShiftModifier;
else if (modifierString=="-c")
modifiers = Qt::ControlModifier;
else if (modifierString=="-sc")
modifiers = Qt::ShiftModifier | Qt::ControlModifier;
DoubleClickAction action = Action_None;
QString value = list.at (0);
if (value=="Edit")
action = Action_Edit;
else if (value=="Remove")
action = Action_Remove;
else if (value=="Edit And Remove")
action = Action_EditAndRemove;
mDoubleClickActions[modifiers] = action;
return;
}
}
std::vector<int> CSVTools::ReportTable::getReplaceIndices (bool selection) const

@ -1,6 +1,8 @@
#ifndef CSV_TOOLS_REPORTTABLE_H
#define CSV_TOOLS_REPORTTABLE_H
#include <map>
#include "../world/dragrecordtable.hpp"
class QAction;
@ -21,11 +23,20 @@ namespace CSVTools
{
Q_OBJECT
enum DoubleClickAction
{
Action_None,
Action_Edit,
Action_Remove,
Action_EditAndRemove
};
CSMTools::ReportModel *mModel;
CSVWorld::CommandDelegate *mIdTypeDelegate;
QAction *mShowAction;
QAction *mRemoveAction;
QAction *mReplaceAction;
std::map<Qt::KeyboardModifiers, DoubleClickAction> mDoubleClickActions;
private:

@ -0,0 +1,113 @@
#include "coloreditor.hpp"
#include <QApplication>
#include <QColor>
#include <QColorDialog>
#include <QDesktopWidget>
#include <QPainter>
#include <QRect>
#include <QShowEvent>
#include "colorpickerpopup.hpp"
CSVWidget::ColorEditor::ColorEditor(const QColor &color, QWidget *parent, bool popupOnStart)
: QPushButton(parent),
mColor(color),
mColorPicker(new ColorPickerPopup(this)),
mPopupOnStart(popupOnStart)
{
setCheckable(true);
connect(this, SIGNAL(clicked()), this, SLOT(showPicker()));
connect(mColorPicker, SIGNAL(hid()), this, SLOT(pickerHid()));
connect(mColorPicker, SIGNAL(colorChanged(const QColor &)), this, SLOT(pickerColorChanged(const QColor &)));
}
void CSVWidget::ColorEditor::paintEvent(QPaintEvent *event)
{
QPushButton::paintEvent(event);
QRect buttonRect = rect();
QRect coloredRect(buttonRect.x() + qRound(buttonRect.width() / 4.0),
buttonRect.y() + qRound(buttonRect.height() / 4.0),
buttonRect.width() / 2,
buttonRect.height() / 2);
QPainter painter(this);
painter.fillRect(coloredRect, mColor);
painter.setPen(Qt::black);
painter.drawRect(coloredRect);
}
void CSVWidget::ColorEditor::showEvent(QShowEvent *event)
{
QPushButton::showEvent(event);
if (isVisible() && mPopupOnStart)
{
setChecked(true);
showPicker();
mPopupOnStart = false;
}
}
QColor CSVWidget::ColorEditor::color() const
{
return mColor;
}
void CSVWidget::ColorEditor::setColor(const QColor &color)
{
mColor = color;
update();
}
void CSVWidget::ColorEditor::showPicker()
{
if (isChecked())
{
mColorPicker->showPicker(calculatePopupPosition(), mColor);
}
else
{
mColorPicker->hide();
}
}
void CSVWidget::ColorEditor::pickerHid()
{
setChecked(false);
emit pickingFinished();
}
void CSVWidget::ColorEditor::pickerColorChanged(const QColor &color)
{
mColor = color;
update();
}
QPoint CSVWidget::ColorEditor::calculatePopupPosition()
{
QRect editorGeometry = geometry();
QRect popupGeometry = mColorPicker->geometry();
QRect screenGeometry = QApplication::desktop()->screenGeometry();
// Center the popup horizontally relative to the editor
int localPopupX = (editorGeometry.width() - popupGeometry.width()) / 2;
// Popup position need to be specified in global coords
QPoint popupPosition = mapToGlobal(QPoint(localPopupX, editorGeometry.height()));
// Make sure that the popup isn't out of the screen
if (popupPosition.x() < screenGeometry.left())
{
popupPosition.setX(screenGeometry.left() + 1);
}
else if (popupPosition.x() + popupGeometry.width() > screenGeometry.right())
{
popupPosition.setX(screenGeometry.right() - popupGeometry.width() - 1);
}
if (popupPosition.y() + popupGeometry.height() > screenGeometry.bottom())
{
// Place the popup above the editor
popupPosition.setY(popupPosition.y() - popupGeometry.height() - editorGeometry.height() - 1);
}
return popupPosition;
}

@ -0,0 +1,44 @@
#ifndef CSV_WIDGET_COLOREDITOR_HPP
#define CSV_WIDGET_COLOREDITOR_HPP
#include <QPushButton>
class QColor;
class QPoint;
class QSize;
namespace CSVWidget
{
class ColorPickerPopup;
class ColorEditor : public QPushButton
{
Q_OBJECT
QColor mColor;
ColorPickerPopup *mColorPicker;
bool mPopupOnStart;
QPoint calculatePopupPosition();
public:
ColorEditor(const QColor &color, QWidget *parent = 0, bool popupOnStart = false);
QColor color() const;
void setColor(const QColor &color);
protected:
virtual void paintEvent(QPaintEvent *event);
virtual void showEvent(QShowEvent *event);
private slots:
void showPicker();
void pickerHid();
void pickerColorChanged(const QColor &color);
signals:
void pickingFinished();
};
}
#endif

@ -0,0 +1,86 @@
#include "colorpickerpopup.hpp"
#include <QColorDialog>
#include <QPushButton>
#include <QEvent>
#include <QKeyEvent>
#include <QMouseEvent>
#include <QLayout>
#include <QStyleOption>
CSVWidget::ColorPickerPopup::ColorPickerPopup(QWidget *parent)
: QFrame(parent)
{
setWindowFlags(Qt::Popup);
setFrameStyle(QFrame::Box | QFrame::Plain);
hide();
mColorPicker = new QColorDialog(this);
mColorPicker->setWindowFlags(Qt::Widget);
mColorPicker->setOptions(QColorDialog::NoButtons | QColorDialog::DontUseNativeDialog);
mColorPicker->installEventFilter(this);
mColorPicker->open();
connect(mColorPicker,
SIGNAL(currentColorChanged(const QColor &)),
this,
SIGNAL(colorChanged(const QColor &)));
QVBoxLayout *layout = new QVBoxLayout(this);
layout->addWidget(mColorPicker);
layout->setAlignment(Qt::AlignTop | Qt::AlignLeft);
layout->setContentsMargins(0, 0, 0, 0);
setLayout(layout);
setFixedSize(mColorPicker->size());
}
void CSVWidget::ColorPickerPopup::showPicker(const QPoint &position, const QColor &initialColor)
{
QRect geometry = this->geometry();
geometry.moveTo(position);
setGeometry(geometry);
mColorPicker->setCurrentColor(initialColor);
show();
}
void CSVWidget::ColorPickerPopup::mousePressEvent(QMouseEvent *event)
{
QPushButton *button = qobject_cast<QPushButton *>(parentWidget());
if (button != NULL)
{
QStyleOptionButton option;
option.init(button);
QRect buttonRect = option.rect;
buttonRect.moveTo(button->mapToGlobal(buttonRect.topLeft()));
// If the mouse is pressed above the pop-up parent,
// the pop-up will be hidden and the pressed signal won't be repeated for the parent
if (buttonRect.contains(event->globalPos()) || buttonRect.contains(event->pos()))
{
setAttribute(Qt::WA_NoMouseReplay);
}
}
QFrame::mousePressEvent(event);
}
void CSVWidget::ColorPickerPopup::hideEvent(QHideEvent *event)
{
QFrame::hideEvent(event);
emit hid();
}
bool CSVWidget::ColorPickerPopup::eventFilter(QObject *object, QEvent *event)
{
if (object == mColorPicker && event->type() == QEvent::KeyPress)
{
QKeyEvent *keyEvent = static_cast<QKeyEvent *>(event);
// Prevent QColorDialog from closing when Escape is pressed.
// Instead, hide the popup.
if (keyEvent->key() == Qt::Key_Escape)
{
hide();
return true;
}
}
return QFrame::eventFilter(object, event);
}

@ -0,0 +1,32 @@
#ifndef CSVWIDGET_COLORPICKERPOPUP_HPP
#define CSVWIDGET_COLORPICKERPOPUP_HPP
#include <QFrame>
class QColorDialog;
namespace CSVWidget
{
class ColorPickerPopup : public QFrame
{
Q_OBJECT
QColorDialog *mColorPicker;
public:
explicit ColorPickerPopup(QWidget *parent);
void showPicker(const QPoint &position, const QColor &initialColor);
protected:
virtual void mousePressEvent(QMouseEvent *event);
virtual void hideEvent(QHideEvent *event);
virtual bool eventFilter(QObject *object, QEvent *event);
signals:
void hid();
void colorChanged(const QColor &color);
};
}
#endif

@ -0,0 +1,36 @@
#include "colordelegate.hpp"
#include <QPainter>
#include <QPushButton>
#include "../widget/coloreditor.hpp"
CSVWorld::ColorDelegate::ColorDelegate(CSMWorld::CommandDispatcher *dispatcher,
CSMDoc::Document& document,
QObject *parent)
: CommandDelegate(dispatcher, document, parent)
{}
void CSVWorld::ColorDelegate::paint(QPainter *painter,
const QStyleOptionViewItem &option,
const QModelIndex &index) const
{
QRect coloredRect(option.rect.x() + qRound(option.rect.width() / 4.0),
option.rect.y() + qRound(option.rect.height() / 4.0),
option.rect.width() / 2,
option.rect.height() / 2);
painter->save();
painter->fillRect(coloredRect, index.data().value<QColor>());
painter->setPen(Qt::black);
painter->drawRect(coloredRect);
painter->restore();
}
CSVWorld::CommandDelegate *CSVWorld::ColorDelegateFactory::makeDelegate(CSMWorld::CommandDispatcher *dispatcher,
CSMDoc::Document &document,
QObject *parent) const
{
return new ColorDelegate(dispatcher, document, parent);
}

@ -0,0 +1,37 @@
#ifndef CSV_WORLD_COLORDELEGATE_HPP
#define CSV_WORLD_COLORDELEGATE_HPP
#include "util.hpp"
class QRect;
namespace CSVWidget
{
class ColorEditButton;
}
namespace CSVWorld
{
class ColorDelegate : public CommandDelegate
{
public:
ColorDelegate(CSMWorld::CommandDispatcher *dispatcher,
CSMDoc::Document& document,
QObject *parent);
virtual void paint(QPainter *painter,
const QStyleOptionViewItem &option,
const QModelIndex &index) const;
};
class ColorDelegateFactory : public CommandDelegateFactory
{
public:
virtual CommandDelegate *makeDelegate(CSMWorld::CommandDispatcher *dispatcher,
CSMDoc::Document &document,
QObject *parent) const;
///< The ownership of the returned CommandDelegate is transferred to the caller.
};
}
#endif

@ -15,8 +15,8 @@ void CSVWorld::Creator::setScope (unsigned int scope)
CSVWorld::CreatorFactoryBase::~CreatorFactoryBase() {}
CSVWorld::Creator *CSVWorld::NullCreatorFactory::makeCreator (CSMWorld::Data& data,
QUndoStack& undoStack, const CSMWorld::UniversalId& id) const
CSVWorld::Creator *CSVWorld::NullCreatorFactory::makeCreator (CSMDoc::Document& document,
const CSMWorld::UniversalId& id) const
{
return 0;
}

@ -5,16 +5,14 @@
#include <QWidget>
#include "../../model/world/universalid.hpp"
#include "../../model/doc/document.hpp"
#include "../../model/world/scope.hpp"
#include "../../model/world/universalid.hpp"
class QUndoStack;
namespace CSMWorld
namespace CSMDoc
{
class Data;
class UniversalId;
class Document;
}
namespace CSVWorld
@ -59,8 +57,7 @@ namespace CSVWorld
virtual ~CreatorFactoryBase();
virtual Creator *makeCreator (CSMWorld::Data& data, QUndoStack& undoStack,
const CSMWorld::UniversalId& id) const = 0;
virtual Creator *makeCreator (CSMDoc::Document& document, const CSMWorld::UniversalId& id) const = 0;
///< The ownership of the returned Creator is transferred to the caller.
///
/// \note The function can return a 0-pointer, which means no UI for creating/deleting
@ -72,8 +69,7 @@ namespace CSVWorld
{
public:
virtual Creator *makeCreator (CSMWorld::Data& data, QUndoStack& undoStack,
const CSMWorld::UniversalId& id) const;
virtual Creator *makeCreator (CSMDoc::Document& document, const CSMWorld::UniversalId& id) const;
///< The ownership of the returned Creator is transferred to the caller.
///
/// \note The function always returns 0.
@ -84,8 +80,7 @@ namespace CSVWorld
{
public:
virtual Creator *makeCreator (CSMWorld::Data& data, QUndoStack& undoStack,
const CSMWorld::UniversalId& id) const;
virtual Creator *makeCreator (CSMDoc::Document& document, const CSMWorld::UniversalId& id) const;
///< The ownership of the returned Creator is transferred to the caller.
///
/// \note The function can return a 0-pointer, which means no UI for creating/deleting
@ -93,10 +88,10 @@ namespace CSVWorld
};
template<class CreatorT, unsigned int scope>
Creator *CreatorFactory<CreatorT, scope>::makeCreator (CSMWorld::Data& data, QUndoStack& undoStack,
const CSMWorld::UniversalId& id) const
Creator *CreatorFactory<CreatorT, scope>::makeCreator (CSMDoc::Document& document,
const CSMWorld::UniversalId& id) const
{
std::auto_ptr<CreatorT> creator (new CreatorT (data, undoStack, id));
std::auto_ptr<CreatorT> creator (new CreatorT (document.getData(), document.getUndoStack(), id));
creator->setScope (scope);

@ -3,6 +3,8 @@
#include <components/esm/loaddial.hpp>
#include "../../model/doc/document.hpp"
#include "../../model/world/data.hpp"
#include "../../model/world/commands.hpp"
#include "../../model/world/columns.hpp"
@ -22,14 +24,14 @@ CSVWorld::DialogueCreator::DialogueCreator (CSMWorld::Data& data, QUndoStack& un
: GenericCreator (data, undoStack, id, true), mType (type)
{}
CSVWorld::Creator *CSVWorld::TopicCreatorFactory::makeCreator (CSMWorld::Data& data,
QUndoStack& undoStack, const CSMWorld::UniversalId& id) const
CSVWorld::Creator *CSVWorld::TopicCreatorFactory::makeCreator (CSMDoc::Document& document,
const CSMWorld::UniversalId& id) const
{
return new DialogueCreator (data, undoStack, id, ESM::Dialogue::Topic);
return new DialogueCreator (document.getData(), document.getUndoStack(), id, ESM::Dialogue::Topic);
}
CSVWorld::Creator *CSVWorld::JournalCreatorFactory::makeCreator (CSMWorld::Data& data,
QUndoStack& undoStack, const CSMWorld::UniversalId& id) const
CSVWorld::Creator *CSVWorld::JournalCreatorFactory::makeCreator (CSMDoc::Document& document,
const CSMWorld::UniversalId& id) const
{
return new DialogueCreator (data, undoStack, id, ESM::Dialogue::Journal);
return new DialogueCreator (document.getData(), document.getUndoStack(), id, ESM::Dialogue::Journal);
}

@ -23,8 +23,7 @@ namespace CSVWorld
{
public:
virtual Creator *makeCreator (CSMWorld::Data& data, QUndoStack& undoStack,
const CSMWorld::UniversalId& id) const;
virtual Creator *makeCreator (CSMDoc::Document& document, const CSMWorld::UniversalId& id) const;
///< The ownership of the returned Creator is transferred to the caller.
};
@ -32,8 +31,7 @@ namespace CSVWorld
{
public:
virtual Creator *makeCreator (CSMWorld::Data& data, QUndoStack& undoStack,
const CSMWorld::UniversalId& id) const;
virtual Creator *makeCreator (CSMDoc::Document& document, const CSMWorld::UniversalId& id) const;
///< The ownership of the returned Creator is transferred to the caller.
};
}

@ -33,6 +33,8 @@
#include "../../model/world/commands.hpp"
#include "../../model/doc/document.hpp"
#include "../widget/coloreditor.hpp"
#include "recordstatusdelegate.hpp"
#include "util.hpp"
#include "tablebottombox.hpp"
@ -331,6 +333,10 @@ QWidget* CSVWorld::DialogueDelegateDispatcher::makeEditor(CSMWorld::ColumnBase::
{
connect(editor, SIGNAL(editingFinished()), proxy, SLOT(editorDataCommited()));
}
else if (qobject_cast<CSVWidget::ColorEditor *>(editor))
{
connect(editor, SIGNAL(pickingFinished()), proxy, SLOT(editorDataCommited()));
}
else // throw an exception because this is a coding error
throw std::logic_error ("Dialogue editor type missing");
@ -679,8 +685,7 @@ CSVWorld::DialogueSubView::DialogueSubView (const CSMWorld::UniversalId& id, CSM
mMainLayout->addWidget(mEditWidget);
mEditWidget->setSizePolicy(QSizePolicy::MinimumExpanding, QSizePolicy::MinimumExpanding);
mMainLayout->addWidget (mBottom =
new TableBottomBox (creatorFactory, document.getData(), document.getUndoStack(), id, this));
mMainLayout->addWidget (mBottom = new TableBottomBox (creatorFactory, document, id, this));
mBottom->setSizePolicy(QSizePolicy::Ignored, QSizePolicy::Fixed);

@ -133,6 +133,15 @@ CSVWorld::GenericCreator::GenericCreator (CSMWorld::Data& data, QUndoStack& undo
mClonedType (CSMWorld::UniversalId::Type_None), mScopes (CSMWorld::Scope_Content), mScope (0),
mScopeLabel (0), mCloneMode (false)
{
// If the collection ID has a parent type, use it instead.
// It will change IDs with Record/SubRecord class (used for creators in Dialogue subviews)
// to IDs with general RecordList class (used for creators in Table subviews).
CSMWorld::UniversalId::Type listParentType = CSMWorld::UniversalId::getParentType(mListId.getType());
if (listParentType != CSMWorld::UniversalId::Type_None)
{
mListId = listParentType;
}
mLayout = new QHBoxLayout;
mLayout->setContentsMargins (0, 0, 0, 0);

@ -13,10 +13,12 @@ class QLineEdit;
class QHBoxLayout;
class QComboBox;
class QLabel;
class QUndoStack;
namespace CSMWorld
{
class CreateCommand;
class Data;
}
namespace CSVWorld

@ -9,10 +9,13 @@
#include <components/misc/stringops.hpp>
#include "../../model/doc/document.hpp"
#include "../../model/world/data.hpp"
#include "../../model/world/commands.hpp"
#include "../../model/world/columns.hpp"
#include "../../model/world/idtable.hpp"
#include "../../model/world/idcompletionmanager.hpp"
std::string CSVWorld::InfoCreator::getId() const
{
@ -39,13 +42,19 @@ void CSVWorld::InfoCreator::configureCreateCommand (CSMWorld::CreateCommand& com
}
CSVWorld::InfoCreator::InfoCreator (CSMWorld::Data& data, QUndoStack& undoStack,
const CSMWorld::UniversalId& id)
const CSMWorld::UniversalId& id, CSMWorld::IdCompletionManager& completionManager)
: GenericCreator (data, undoStack, id)
{
QLabel *label = new QLabel ("Topic", this);
insertBeforeButtons (label, false);
mTopic = new QLineEdit (this);
CSMWorld::ColumnBase::Display displayType = CSMWorld::ColumnBase::Display_Topic;
if (getCollectionId().getType() == CSMWorld::UniversalId::Type_JournalInfos)
{
displayType = CSMWorld::ColumnBase::Display_Journal;
}
mTopic->setCompleter(completionManager.getCompleter(displayType).get());
insertBeforeButtons (mTopic, true);
setManualEditing (false);
@ -100,3 +109,12 @@ void CSVWorld::InfoCreator::topicChanged()
{
update();
}
CSVWorld::Creator *CSVWorld::InfoCreatorFactory::makeCreator(CSMDoc::Document& document,
const CSMWorld::UniversalId& id) const
{
return new InfoCreator(document.getData(),
document.getUndoStack(),
id,
document.getIdCompletionManager());
}

@ -8,6 +8,7 @@ class QLineEdit;
namespace CSMWorld
{
class InfoCollection;
class IdCompletionManager;
}
namespace CSVWorld
@ -25,7 +26,7 @@ namespace CSVWorld
public:
InfoCreator (CSMWorld::Data& data, QUndoStack& undoStack,
const CSMWorld::UniversalId& id);
const CSMWorld::UniversalId& id, CSMWorld::IdCompletionManager& completionManager);
virtual void cloneMode (const std::string& originId,
const CSMWorld::UniversalId::Type type);
@ -43,6 +44,14 @@ namespace CSVWorld
void topicChanged();
};
class InfoCreatorFactory : public CreatorFactoryBase
{
public:
virtual Creator *makeCreator (CSMDoc::Document& document, const CSMWorld::UniversalId& id) const;
///< The ownership of the returned Creator is transferred to the caller.
};
}
#endif

@ -4,10 +4,13 @@
#include <QLabel>
#include <QLineEdit>
#include "../../model/doc/document.hpp"
#include "../../model/world/data.hpp"
#include "../../model/world/commands.hpp"
#include "../../model/world/columns.hpp"
#include "../../model/world/idtable.hpp"
#include "../../model/world/idcompletionmanager.hpp"
std::string CSVWorld::ReferenceCreator::getId() const
{
@ -71,13 +74,14 @@ int CSVWorld::ReferenceCreator::getRefNumCount() const
}
CSVWorld::ReferenceCreator::ReferenceCreator (CSMWorld::Data& data, QUndoStack& undoStack,
const CSMWorld::UniversalId& id)
const CSMWorld::UniversalId& id, CSMWorld::IdCompletionManager &completionManager)
: GenericCreator (data, undoStack, id)
{
QLabel *label = new QLabel ("Cell", this);
insertBeforeButtons (label, false);
mCell = new QLineEdit (this);
mCell->setCompleter(completionManager.getCompleter(CSMWorld::ColumnBase::Display_Cell).get());
insertBeforeButtons (mCell, true);
setManualEditing (false);
@ -142,3 +146,12 @@ void CSVWorld::ReferenceCreator::cloneMode(const std::string& originId,
CSVWorld::GenericCreator::cloneMode(originId, type);
cellChanged(); //otherwise ok button will remain disabled
}
CSVWorld::Creator *CSVWorld::ReferenceCreatorFactory::makeCreator (CSMDoc::Document& document,
const CSMWorld::UniversalId& id) const
{
return new ReferenceCreator(document.getData(),
document.getUndoStack(),
id,
document.getIdCompletionManager());
}

@ -5,8 +5,14 @@
class QLineEdit;
namespace CSMWorld
{
class IdCompletionManager;
}
namespace CSVWorld
{
class ReferenceCreator : public GenericCreator
{
Q_OBJECT
@ -28,7 +34,7 @@ namespace CSVWorld
public:
ReferenceCreator (CSMWorld::Data& data, QUndoStack& undoStack,
const CSMWorld::UniversalId& id);
const CSMWorld::UniversalId& id, CSMWorld::IdCompletionManager &completionManager);
virtual void cloneMode(const std::string& originId,
const CSMWorld::UniversalId::Type type);
@ -46,6 +52,14 @@ namespace CSVWorld
void cellChanged();
};
class ReferenceCreatorFactory : public CreatorFactoryBase
{
public:
virtual Creator *makeCreator (CSMDoc::Document& document, const CSMWorld::UniversalId& id) const;
///< The ownership of the returned Creator is transferred to the caller.
};
}
#endif

@ -33,9 +33,7 @@ CSVWorld::SceneSubView::SceneSubView (const CSMWorld::UniversalId& id, CSMDoc::D
layout->setContentsMargins (QMargins (0, 0, 0, 0));
layout->addWidget (mBottom =
new TableBottomBox (NullCreatorFactory(), document.getData(), document.getUndoStack(), id,
this), 0);
layout->addWidget (mBottom = new TableBottomBox (NullCreatorFactory(), document, id, this), 0);
mLayout->setContentsMargins (QMargins (0, 0, 0, 0));

@ -59,7 +59,7 @@ void CSVWorld::addSubViewFactories (CSVDoc::SubViewFactoryManager& manager)
new CSVDoc::SubViewFactoryWithCreator<TableSubView, CreatorFactory<ReferenceableCreator> >);
manager.add (CSMWorld::UniversalId::Type_References,
new CSVDoc::SubViewFactoryWithCreator<TableSubView, CreatorFactory<ReferenceCreator> >);
new CSVDoc::SubViewFactoryWithCreator<TableSubView, ReferenceCreatorFactory>);
manager.add (CSMWorld::UniversalId::Type_Topics,
new CSVDoc::SubViewFactoryWithCreator<TableSubView, TopicCreatorFactory>);
@ -68,10 +68,10 @@ void CSVWorld::addSubViewFactories (CSVDoc::SubViewFactoryManager& manager)
new CSVDoc::SubViewFactoryWithCreator<TableSubView, JournalCreatorFactory>);
manager.add (CSMWorld::UniversalId::Type_TopicInfos,
new CSVDoc::SubViewFactoryWithCreator<TableSubView, CreatorFactory<InfoCreator> >);
new CSVDoc::SubViewFactoryWithCreator<TableSubView, InfoCreatorFactory>);
manager.add (CSMWorld::UniversalId::Type_JournalInfos,
new CSVDoc::SubViewFactoryWithCreator<TableSubView, CreatorFactory<InfoCreator> >);
new CSVDoc::SubViewFactoryWithCreator<TableSubView, InfoCreatorFactory>);
// Subviews for resources tables
manager.add (CSMWorld::UniversalId::Type_Meshes,
@ -147,16 +147,16 @@ void CSVWorld::addSubViewFactories (CSVDoc::SubViewFactoryManager& manager)
new CSVDoc::SubViewFactoryWithCreator<DialogueSubView, CreatorFactory<ReferenceableCreator> > (false));
manager.add (CSMWorld::UniversalId::Type_Reference,
new CSVDoc::SubViewFactoryWithCreator<DialogueSubView, CreatorFactory<ReferenceCreator> > (false));
new CSVDoc::SubViewFactoryWithCreator<DialogueSubView, ReferenceCreatorFactory> (false));
manager.add (CSMWorld::UniversalId::Type_Cell,
new CSVDoc::SubViewFactoryWithCreator<DialogueSubView, CreatorFactory<CellCreator> > (false));
manager.add (CSMWorld::UniversalId::Type_JournalInfo,
new CSVDoc::SubViewFactoryWithCreator<DialogueSubView, CreatorFactory<InfoCreator> > (false));
new CSVDoc::SubViewFactoryWithCreator<DialogueSubView, InfoCreatorFactory> (false));
manager.add (CSMWorld::UniversalId::Type_TopicInfo,
new CSVDoc::SubViewFactoryWithCreator<DialogueSubView, CreatorFactory<InfoCreator> >(false));
new CSVDoc::SubViewFactoryWithCreator<DialogueSubView, InfoCreatorFactory>(false));
manager.add (CSMWorld::UniversalId::Type_Topic,
new CSVDoc::SubViewFactoryWithCreator<DialogueSubView, TopicCreatorFactory> (false));

@ -39,8 +39,10 @@ void CSVWorld::TableBottomBox::updateStatus()
}
}
CSVWorld::TableBottomBox::TableBottomBox (const CreatorFactoryBase& creatorFactory,
CSMWorld::Data& data, QUndoStack& undoStack, const CSMWorld::UniversalId& id, QWidget *parent)
CSVWorld::TableBottomBox::TableBottomBox (const CreatorFactoryBase& creatorFactory,
CSMDoc::Document& document,
const CSMWorld::UniversalId& id,
QWidget *parent)
: QWidget (parent), mShowStatusBar (false), mCreating (false)
{
for (int i=0; i<4; ++i)
@ -61,7 +63,7 @@ CSVWorld::TableBottomBox::TableBottomBox (const CreatorFactoryBase& creatorFacto
setLayout (mLayout);
mCreator = creatorFactory.makeCreator (data, undoStack, id);
mCreator = creatorFactory.makeCreator (document, id);
if (mCreator)
{

@ -9,10 +9,9 @@ class QStackedLayout;
class QStatusBar;
class QUndoStack;
namespace CSMWorld
namespace CSMDoc
{
class Data;
class UniversalId;
class Document;
}
namespace CSVWorld
@ -42,8 +41,10 @@ namespace CSVWorld
public:
TableBottomBox (const CreatorFactoryBase& creatorFactory, CSMWorld::Data& data,
QUndoStack& undoStack, const CSMWorld::UniversalId& id, QWidget *parent = 0);
TableBottomBox (const CreatorFactoryBase& creatorFactory,
CSMDoc::Document& document,
const CSMWorld::UniversalId& id,
QWidget *parent = 0);
virtual ~TableBottomBox();

@ -26,7 +26,7 @@ CSVWorld::TableSubView::TableSubView (const CSMWorld::UniversalId& id, CSMDoc::D
layout->setContentsMargins (QMargins (0, 0, 0, 0));
layout->addWidget (mBottom =
new TableBottomBox (creatorFactory, document.getData(), document.getUndoStack(), id, this), 0);
new TableBottomBox (creatorFactory, document, id, this), 0);
layout->insertWidget (0, mTable =
new Table (id, mBottom->canCreateAndDelete(), sorting, document), 2);

@ -17,6 +17,7 @@
#include "../../model/world/commands.hpp"
#include "../../model/world/tablemimedata.hpp"
#include "../../model/world/commanddispatcher.hpp"
#include "../widget/coloreditor.hpp"
#include "dialoguespinbox.hpp"
#include "scriptedit.hpp"
@ -123,10 +124,19 @@ void CSVWorld::CommandDelegate::setModelDataImp (QWidget *editor, QAbstractItemM
if (!mCommandDispatcher)
return;
NastyTableModelHack hack (*model);
QStyledItemDelegate::setModelData (editor, &hack, index);
QVariant new_ = hack.getData();
QVariant new_;
// Color columns use a custom editor, so we need explicitly extract a data from it
CSVWidget::ColorEditor *colorEditor = qobject_cast<CSVWidget::ColorEditor *>(editor);
if (colorEditor != NULL)
{
new_ = colorEditor->color();
}
else
{
NastyTableModelHack hack (*model);
QStyledItemDelegate::setModelData (editor, &hack, index);
new_ = hack.getData();
}
if ((model->data (index)!=new_) && (model->flags(index) & Qt::ItemIsEditable))
mCommandDispatcher->executeModify (model, index, new_);
@ -162,6 +172,12 @@ QWidget *CSVWorld::CommandDelegate::createEditor (QWidget *parent, const QStyleO
{
return QStyledItemDelegate::createEditor(parent, option, index);
}
// For tables the pop-up of the color editor should appear immediately after the editor creation
// (the third parameter of ColorEditor's constructor)
else if (display == CSMWorld::ColumnBase::Display_Colour)
{
return new CSVWidget::ColorEditor(index.data().value<QColor>(), parent, true);
}
return createEditor (parent, option, index, display);
}
@ -184,7 +200,7 @@ QWidget *CSVWorld::CommandDelegate::createEditor (QWidget *parent, const QStyleO
{
case CSMWorld::ColumnBase::Display_Colour:
return new QLineEdit(parent);
return new CSVWidget::ColorEditor(index.data().value<QColor>(), parent);
case CSMWorld::ColumnBase::Display_Integer:
{
@ -284,6 +300,14 @@ void CSVWorld::CommandDelegate::setEditorData (QWidget *editor, const QModelInde
}
}
// Color columns use a custom editor, so we need explicitly set a data for it
CSVWidget::ColorEditor *colorEditor = qobject_cast<CSVWidget::ColorEditor *>(editor);
if (colorEditor != NULL)
{
colorEditor->setColor(index.data().value<QColor>());
return;
}
QByteArray n = editor->metaObject()->userProperty().name();
if (n == "dateTime") {

@ -641,9 +641,6 @@ namespace MWMechanics
if (mAllowedNodes.empty())
return;
if (actor.getClass().isPureWaterCreature(actor))
return;
state.moveIn(new AiWanderStorage());
int index = Misc::Rng::rollDice(mAllowedNodes.size());
@ -690,7 +687,8 @@ namespace MWMechanics
// actor can wander from the spawn position. AiWander assumes that
// pathgrid points are available, and uses them to randomly select wander
// destinations within the allowed set of pathgrid points (nodes).
if(mDistance)
// ... pathgrids don't usually include water, so swimmers ignore them
if (mDistance && !actor.getClass().isPureWaterCreature(actor))
{
float cellXOffset = 0;
float cellYOffset = 0;

@ -20,7 +20,7 @@ namespace MWMechanics
mKnockdown(false), mKnockdownOneFrame(false), mKnockdownOverOneFrame(false),
mHitRecovery(false), mBlock(false), mMovementFlags(0), mAttackStrength(0.f),
mFallHeight(0), mRecalcMagicka(false), mLastRestock(0,0), mGoldPool(0), mActorId(-1),
mDeathAnimation(0), mIsWerewolf(false), mLevel (0)
mDeathAnimation(0), mLevel (0)
{
for (int i=0; i<4; ++i)
mAiSettings[i] = 0;
@ -55,7 +55,7 @@ namespace MWMechanics
if (index < 0 || index > 7) {
throw std::runtime_error("attribute index is out of range");
}
return (!mIsWerewolf ? mAttributes[index] : mWerewolfAttributes[index]);
return mAttributes[index];
}
const DynamicStat<float> &CreatureStats::getHealth() const
@ -139,14 +139,11 @@ namespace MWMechanics
throw std::runtime_error("attribute index is out of range");
}
const AttributeValue& currentValue = !mIsWerewolf ? mAttributes[index] : mWerewolfAttributes[index];
const AttributeValue& currentValue = mAttributes[index];
if (value != currentValue)
{
if(!mIsWerewolf)
mAttributes[index] = value;
else
mWerewolfAttributes[index] = value;
mAttributes[index] = value;
if (index == ESM::Attribute::Intelligence)
mRecalcMagicka = true;

@ -77,10 +77,6 @@ namespace MWMechanics
std::vector<int> mSummonGraveyard;
protected:
// These two are only set by NpcStats, but they are declared in CreatureStats to prevent using virtual methods.
bool mIsWerewolf;
AttributeValue mWerewolfAttributes[8];
int mLevel;
public:

@ -32,6 +32,7 @@ MWMechanics::NpcStats::NpcStats()
, mWerewolfKills (0)
, mLevelProgress(0)
, mTimeToStartDrowning(20.0)
, mIsWerewolf(false)
{
mSkillIncreases.resize (ESM::Attribute::Length, 0);
}
@ -51,7 +52,7 @@ const MWMechanics::SkillValue& MWMechanics::NpcStats::getSkill (int index) const
if (index<0 || index>=ESM::Skill::Length)
throw std::runtime_error ("skill index out of range");
return (!mIsWerewolf ? mSkill[index] : mWerewolfSkill[index]);
return mSkill[index];
}
MWMechanics::SkillValue& MWMechanics::NpcStats::getSkill (int index)
@ -59,7 +60,15 @@ MWMechanics::SkillValue& MWMechanics::NpcStats::getSkill (int index)
if (index<0 || index>=ESM::Skill::Length)
throw std::runtime_error ("skill index out of range");
return (!mIsWerewolf ? mSkill[index] : mWerewolfSkill[index]);
return mSkill[index];
}
void MWMechanics::NpcStats::setSkill(int index, const MWMechanics::SkillValue &value)
{
if (index<0 || index>=ESM::Skill::Length)
throw std::runtime_error ("skill index out of range");
mSkill[index] = value;
}
const std::map<std::string, int>& MWMechanics::NpcStats::getFactionRanks() const
@ -188,10 +197,6 @@ float MWMechanics::NpcStats::getSkillProgressRequirement (int skillIndex, const
void MWMechanics::NpcStats::useSkill (int skillIndex, const ESM::Class& class_, int usageType, float extraFactor)
{
// Don't increase skills as a werewolf
if(mIsWerewolf)
return;
const ESM::Skill *skill =
MWBase::Environment::get().getWorld()->getStore().get<ESM::Skill>().find (skillIndex);
float skillGain = 1;
@ -403,34 +408,12 @@ bool MWMechanics::NpcStats::isWerewolf() const
void MWMechanics::NpcStats::setWerewolf (bool set)
{
if (mIsWerewolf == set)
return;
if(set != false)
{
const MWWorld::Store<ESM::GameSetting> &gmst = MWBase::Environment::get().getWorld()->getStore().get<ESM::GameSetting>();
mWerewolfKills = 0;
for(size_t i = 0;i < ESM::Attribute::Length;i++)
{
mWerewolfAttributes[i] = getAttribute(i);
// Oh, Bethesda. It's "Intelligence".
std::string name = "fWerewolf"+((i==ESM::Attribute::Intelligence) ? std::string("Intellegence") :
ESM::Attribute::sAttributeNames[i]);
mWerewolfAttributes[i].setBase(int(gmst.find(name)->getFloat()));
}
for(size_t i = 0;i < ESM::Skill::Length;i++)
{
mWerewolfSkill[i] = getSkill(i);
// Acrobatics is set separately for some reason.
if(i == ESM::Skill::Acrobatics)
continue;
// "Mercantile"! >_<
std::string name = "fWerewolf"+((i==ESM::Skill::Mercantile) ? std::string("Merchantile") :
ESM::Skill::sSkillNames[i]);
mWerewolfSkill[i].setBase(int(gmst.find(name)->getFloat()));
}
}
mIsWerewolf = set;
}
@ -464,14 +447,8 @@ void MWMechanics::NpcStats::writeState (ESM::NpcStats& state) const
state.mDisposition = mDisposition;
for (int i=0; i<ESM::Skill::Length; ++i)
{
mSkill[i].writeState (state.mSkills[i].mRegular);
mWerewolfSkill[i].writeState (state.mSkills[i].mWerewolf);
}
for (int i=0; i<ESM::Attribute::Length; ++i)
{
mWerewolfAttributes[i].writeState (state.mWerewolfAttributes[i]);
}
mSkill[i].writeState (state.mSkills[i]);
state.mIsWerewolf = mIsWerewolf;
state.mCrimeId = mCrimeId;
@ -519,14 +496,7 @@ void MWMechanics::NpcStats::readState (const ESM::NpcStats& state)
mDisposition = state.mDisposition;
for (int i=0; i<ESM::Skill::Length; ++i)
{
mSkill[i].readState (state.mSkills[i].mRegular);
mWerewolfSkill[i].readState (state.mSkills[i].mWerewolf);
}
for (int i=0; i<ESM::Attribute::Length; ++i)
{
mWerewolfAttributes[i].readState (state.mWerewolfAttributes[i]);
}
mSkill[i].readState (state.mSkills[i]);
mIsWerewolf = state.mIsWerewolf;

@ -22,7 +22,7 @@ namespace MWMechanics
{
int mDisposition;
SkillValue mSkill[ESM::Skill::Length]; // SkillValue.mProgress used by the player only
SkillValue mWerewolfSkill[ESM::Skill::Length];
int mReputation;
int mCrimeId;
@ -41,6 +41,8 @@ namespace MWMechanics
/// Countdown to getting damage while underwater
float mTimeToStartDrowning;
bool mIsWerewolf;
public:
NpcStats();
@ -56,6 +58,7 @@ namespace MWMechanics
const SkillValue& getSkill (int index) const;
SkillValue& getSkill (int index);
void setSkill(int index, const SkillValue& value);
const std::map<std::string, int>& getFactionRanks() const;
/// Increase the rank in this faction by 1, if such a rank exists.

@ -48,6 +48,55 @@ namespace MWWorld
mPlayer.mData.setPosition(playerPos);
}
void Player::saveSkillsAttributes()
{
MWMechanics::NpcStats& stats = getPlayer().getClass().getNpcStats(getPlayer());
for (int i=0; i<ESM::Skill::Length; ++i)
mSaveSkills[i] = stats.getSkill(i);
for (int i=0; i<ESM::Attribute::Length; ++i)
mSaveAttributes[i] = stats.getAttribute(i);
}
void Player::restoreSkillsAttributes()
{
MWMechanics::NpcStats& stats = getPlayer().getClass().getNpcStats(getPlayer());
for (int i=0; i<ESM::Skill::Length; ++i)
stats.setSkill(i, mSaveSkills[i]);
for (int i=0; i<ESM::Attribute::Length; ++i)
stats.setAttribute(i, mSaveAttributes[i]);
}
void Player::setWerewolfSkillsAttributes()
{
const MWWorld::Store<ESM::GameSetting>& gmst = MWBase::Environment::get().getWorld()->getStore().get<ESM::GameSetting>();
MWMechanics::NpcStats& stats = getPlayer().getClass().getNpcStats(getPlayer());
for(size_t i = 0;i < ESM::Attribute::Length;++i)
{
// Oh, Bethesda. It's "Intelligence".
std::string name = "fWerewolf"+((i==ESM::Attribute::Intelligence) ? std::string("Intellegence") :
ESM::Attribute::sAttributeNames[i]);
MWMechanics::AttributeValue value = stats.getAttribute(i);
value.setBase(int(gmst.find(name)->getFloat()));
stats.setAttribute(i, value);
}
for(size_t i = 0;i < ESM::Skill::Length;i++)
{
// Acrobatics is set separately for some reason.
if(i == ESM::Skill::Acrobatics)
continue;
// "Mercantile"! >_<
std::string name = "fWerewolf"+((i==ESM::Skill::Mercantile) ? std::string("Merchantile") :
ESM::Skill::sSkillNames[i]);
MWMechanics::SkillValue value = stats.getSkill(i);
value.setBase(int(gmst.find(name)->getFloat()));
stats.setSkill(i, value);
}
}
void Player::set(const ESM::NPC *player)
{
mPlayer.mBase = player;
@ -221,6 +270,11 @@ namespace MWWorld
player.mAutoMove = mAutoMove ? 1 : 0;
for (int i=0; i<ESM::Attribute::Length; ++i)
mSaveAttributes[i].writeState(player.mSaveAttributes[i]);
for (int i=0; i<ESM::Skill::Length; ++i)
mSaveSkills[i].writeState(player.mSaveSkills[i]);
writer.startRecord (ESM::REC_PLAY);
player.save (writer);
writer.endRecord (ESM::REC_PLAY);
@ -241,6 +295,17 @@ namespace MWWorld
mPlayer.load (player.mObject);
for (int i=0; i<ESM::Attribute::Length; ++i)
mSaveAttributes[i].readState(player.mSaveAttributes[i]);
for (int i=0; i<ESM::Skill::Length; ++i)
mSaveSkills[i].readState(player.mSaveSkills[i]);
if (player.mObject.mNpcStats.mWerewolfDeprecatedData && player.mObject.mNpcStats.mIsWerewolf)
{
saveSkillsAttributes();
setWerewolfSkillsAttributes();
}
getPlayer().getClass().getCreatureStats(getPlayer()).getAiSequence().clear();
MWBase::World& world = *MWBase::Environment::get().getWorld();

@ -5,6 +5,10 @@
#include "../mwworld/livecellref.hpp"
#include "../mwmechanics/drawstate.hpp"
#include "../mwmechanics/stat.hpp"
#include <components/esm/loadskil.hpp>
#include <components/esm/attr.hpp>
namespace ESM
{
@ -48,10 +52,18 @@ namespace MWWorld
int mCurrentCrimeId; // the id assigned witnesses
int mPaidCrimeId; // the last id paid off (0 bounty)
// Saved skills and attributes prior to becoming a werewolf
MWMechanics::SkillValue mSaveSkills[ESM::Skill::Length];
MWMechanics::AttributeValue mSaveAttributes[ESM::Attribute::Length];
public:
Player(const ESM::NPC *player, const MWBase::World& world);
void saveSkillsAttributes();
void restoreSkillsAttributes();
void setWerewolfSkillsAttributes();
// For mark/recall magic effects
void markPosition (CellStore* markedCell, ESM::Position markedPosition);
void getMarkedPosition (CellStore*& markedCell, ESM::Position& markedPosition) const;

@ -2432,6 +2432,17 @@ namespace MWWorld
if (npcStats.isWerewolf() == werewolf)
return;
if (actor == getPlayerPtr())
{
if (werewolf)
{
mPlayer->saveSkillsAttributes();
mPlayer->setWerewolfSkillsAttributes();
}
else
mPlayer->restoreSkillsAttributes();
}
npcStats.setWerewolf(werewolf);
// This is a bit dangerous. Equipped items other than WerewolfRobe may reference

@ -176,6 +176,17 @@ bool ESMReader::isNextSub(const char* name)
return !mCtx.subCached;
}
bool ESMReader::peekNextSub(const char *name)
{
if (!mCtx.leftRec)
return false;
getSubName();
mCtx.subCached = true;
return mCtx.subName == name;
}
// Read subrecord name. This gets called a LOT, so I've optimized it
// slightly.
void ESMReader::getSubName()

@ -183,6 +183,8 @@ public:
*/
bool isNextSub(const char* name);
bool peekNextSub(const char* name);
// Read subrecord name. This gets called a LOT, so I've optimized it
// slightly.
void getSubName();

@ -1,4 +1,3 @@
#include "npcstats.hpp"
#include "esmreader.hpp"
@ -31,18 +30,43 @@ void ESM::NpcStats::load (ESMReader &esm)
esm.getHNOT (mDisposition, "DISP");
for (int i=0; i<27; ++i)
mSkills[i].load (esm);
if (esm.peekNextSub("STBA"))
{
mSkills[i].mRegular.load (esm);
mSkills[i].mWerewolf.load (esm);
// we have deprecated werewolf skills, stored interleaved
// Load into one big vector, then remove every 2nd value
mWerewolfDeprecatedData = true;
std::vector<ESM::StatState<int> > skills(mSkills, mSkills + sizeof(mSkills)/sizeof(mSkills[0]));
for (int i=0; i<27; ++i)
{
ESM::StatState<int> skill;
skill.load(esm);
skills.push_back(skill);
}
int i=0;
for (std::vector<ESM::StatState<int> >::iterator it = skills.begin(); it != skills.end(); ++i)
{
if (i%2 == 1)
it = skills.erase(it);
else
++it;
}
assert(skills.size() == 27);
std::copy(skills.begin(), skills.end(), mSkills);
}
// No longer used
bool hasWerewolfAttributes = false;
esm.getHNOT (hasWerewolfAttributes, "HWAT");
if (hasWerewolfAttributes)
{
ESM::StatState<int> dummy;
for (int i=0; i<8; ++i)
mWerewolfAttributes[i].load (esm);
dummy.load(esm);
mWerewolfDeprecatedData = true;
}
mIsWerewolf = false;
@ -112,14 +136,7 @@ void ESM::NpcStats::save (ESMWriter &esm) const
esm.writeHNT ("DISP", mDisposition);
for (int i=0; i<27; ++i)
{
mSkills[i].mRegular.save (esm);
mSkills[i].mWerewolf.save (esm);
}
esm.writeHNT ("HWAT", true);
for (int i=0; i<8; ++i)
mWerewolfAttributes[i].save (esm);
mSkills[i].save (esm);
if (mIsWerewolf)
esm.writeHNT ("WOLF", mIsWerewolf);
@ -151,6 +168,7 @@ void ESM::NpcStats::save (ESMWriter &esm) const
void ESM::NpcStats::blank()
{
mWerewolfDeprecatedData = false;
mIsWerewolf = false;
mDisposition = 0;
mBounty = 0;

@ -16,12 +16,6 @@ namespace ESM
struct NpcStats
{
struct Skill
{
StatState<int> mRegular;
StatState<int> mWerewolf;
};
struct Faction
{
bool mExpelled;
@ -31,12 +25,13 @@ namespace ESM
Faction();
};
StatState<int> mWerewolfAttributes[8];
bool mIsWerewolf;
bool mWerewolfDeprecatedData;
std::map<std::string, Faction> mFactions; // lower case IDs
int mDisposition;
Skill mSkills[27];
StatState<int> mSkills[27];
int mBounty;
int mReputation;
int mWerewolfKills;

@ -31,6 +31,14 @@ void ESM::Player::load (ESMReader &esm)
esm.getHNOT (mCurrentCrimeId, "CURD");
mPaidCrimeId = -1;
esm.getHNOT (mPaidCrimeId, "PAYD");
if (esm.hasMoreSubs())
{
for (int i=0; i<ESM::Attribute::Length; ++i)
mSaveAttributes[i].load(esm);
for (int i=0; i<ESM::Skill::Length; ++i)
mSaveSkills[i].load(esm);
}
}
void ESM::Player::save (ESMWriter &esm) const
@ -54,4 +62,9 @@ void ESM::Player::save (ESMWriter &esm) const
esm.writeHNT ("CURD", mCurrentCrimeId);
esm.writeHNT ("PAYD", mPaidCrimeId);
for (int i=0; i<ESM::Attribute::Length; ++i)
mSaveAttributes[i].save(esm);
for (int i=0; i<ESM::Skill::Length; ++i)
mSaveSkills[i].save(esm);
}

@ -7,6 +7,9 @@
#include "cellid.hpp"
#include "defs.hpp"
#include "loadskil.hpp"
#include "attr.hpp"
namespace ESM
{
class ESMReader;
@ -28,6 +31,9 @@ namespace ESM
int mCurrentCrimeId;
int mPaidCrimeId;
StatState<int> mSaveAttributes[ESM::Attribute::Length];
StatState<int> mSaveSkills[ESM::Skill::Length];
void load (ESMReader &esm);
void save (ESMWriter &esm) const;
};

Loading…
Cancel
Save