Merge branch 'master' of https://github.com/zinnschlag/openmw.git into AICombat

This commit is contained in:
gus 2013-09-10 16:18:39 +02:00
commit f9bfbc8764
150 changed files with 2025 additions and 2092 deletions

View file

@ -19,7 +19,7 @@ include (OpenMWMacros)
# Version # Version
set (OPENMW_VERSION_MAJOR 0) set (OPENMW_VERSION_MAJOR 0)
set (OPENMW_VERSION_MINOR 25) set (OPENMW_VERSION_MINOR 26)
set (OPENMW_VERSION_RELEASE 0) set (OPENMW_VERSION_RELEASE 0)
set (OPENMW_VERSION "${OPENMW_VERSION_MAJOR}.${OPENMW_VERSION_MINOR}.${OPENMW_VERSION_RELEASE}") set (OPENMW_VERSION "${OPENMW_VERSION_MAJOR}.${OPENMW_VERSION_MINOR}.${OPENMW_VERSION_RELEASE}")

View file

@ -24,7 +24,6 @@ set(LAUNCHER_HEADER
graphicspage.hpp graphicspage.hpp
maindialog.hpp maindialog.hpp
playpage.hpp playpage.hpp
unshieldthread.hpp
textslotmsgbox.hpp textslotmsgbox.hpp
settings/gamesettings.hpp settings/gamesettings.hpp
@ -47,7 +46,6 @@ set(LAUNCHER_HEADER_MOC
graphicspage.hpp graphicspage.hpp
maindialog.hpp maindialog.hpp
playpage.hpp playpage.hpp
unshieldthread.hpp
textslotmsgbox.hpp textslotmsgbox.hpp
utils/checkablemessagebox.hpp utils/checkablemessagebox.hpp

View file

@ -3,6 +3,11 @@
#include <QDesktopWidget> #include <QDesktopWidget>
#include <QMessageBox> #include <QMessageBox>
#include <QDir> #include <QDir>
#ifdef __APPLE__
// We need to do this because of Qt: https://bugreports.qt-project.org/browse/QTBUG-22154
#define MAC_OS_X_VERSION_MIN_REQUIRED __ENVIRONMENT_MAC_OS_X_VERSION_MIN_REQUIRED__
#endif
#include <SDL.h> #include <SDL.h>
#include <cstdlib> #include <cstdlib>

View file

@ -3,6 +3,10 @@
#include <QDir> #include <QDir>
#include <QDebug> #include <QDebug>
#ifdef __APPLE__
// We need to do this because of Qt: https://bugreports.qt-project.org/browse/QTBUG-22154
#define MAC_OS_X_VERSION_MIN_REQUIRED __ENVIRONMENT_MAC_OS_X_VERSION_MIN_REQUIRED__
#endif
#include <SDL.h> #include <SDL.h>
#include "maindialog.hpp" #include "maindialog.hpp"

View file

@ -216,7 +216,12 @@ namespace
else else
{ {
if(copy) if(copy)
bfs::copy_file(dir->path(), to / dir->path().filename()); {
bfs::path dest = to / dir->path().filename();
if(bfs::exists(dest))
bfs::remove_all(dest);
bfs::copy_file(dir->path(), dest);
}
else else
bfs::rename(dir->path(), to / dir->path().filename()); bfs::rename(dir->path(), to / dir->path().filename());
} }
@ -481,6 +486,7 @@ void UnshieldThread::run()
UnshieldThread::UnshieldThread() UnshieldThread::UnshieldThread()
{ {
unshield_set_log_level(0);
mMorrowindDone = false; mMorrowindDone = false;
mTribunalDone = false; mTribunalDone = false;
mBloodmoonDone = false; mBloodmoonDone = false;

View file

@ -7,7 +7,6 @@
#include <libunshield.h> #include <libunshield.h>
class UnshieldThread : public QThread class UnshieldThread : public QThread
{ {
Q_OBJECT Q_OBJECT

View file

@ -135,7 +135,7 @@ if(WIN32)
set(QT_USE_QTMAIN TRUE) set(QT_USE_QTMAIN TRUE)
endif(WIN32) endif(WIN32)
find_package(Qt4 COMPONENTS QtCore QtGui QtXml QtXmlPatterns REQUIRED) find_package(Qt4 COMPONENTS QtCore QtGui QtNetwork QtXml QtXmlPatterns REQUIRED)
include(${QT_USE_FILE}) include(${QT_USE_FILE})
qt4_wrap_ui(OPENCS_UI_HDR ${OPENCS_UI}) qt4_wrap_ui(OPENCS_UI_HDR ${OPENCS_UI})

View file

@ -2,17 +2,24 @@
#include "editor.hpp" #include "editor.hpp"
#include <QApplication> #include <QApplication>
#include <QLocalServer>
#include <QLocalSocket>
#include "model/doc/document.hpp" #include "model/doc/document.hpp"
#include "model/world/data.hpp" #include "model/world/data.hpp"
CS::Editor::Editor() : mViewManager (mDocumentManager) CS::Editor::Editor() : mViewManager (mDocumentManager)
{ {
mIpcServerName = "org.openmw.OpenCS";
connect (&mViewManager, SIGNAL (newDocumentRequest ()), this, SLOT (createDocument ())); connect (&mViewManager, SIGNAL (newDocumentRequest ()), this, SLOT (createDocument ()));
connect (&mViewManager, SIGNAL (loadDocumentRequest ()), this, SLOT (loadDocument ())); connect (&mViewManager, SIGNAL (loadDocumentRequest ()), this, SLOT (loadDocument ()));
connect (&mViewManager, SIGNAL (editSettingsRequest()), this, SLOT (showSettings ()));
connect (&mStartup, SIGNAL (createDocument()), this, SLOT (createDocument ())); connect (&mStartup, SIGNAL (createGame()), this, SLOT (createDocument ())); /// \todo split
connect (&mStartup, SIGNAL (createAddon()), this, SLOT (createDocument ()));
connect (&mStartup, SIGNAL (loadDocument()), this, SLOT (loadDocument ())); connect (&mStartup, SIGNAL (loadDocument()), this, SLOT (loadDocument ()));
connect (&mStartup, SIGNAL (editConfig()), this, SLOT (showSettings ()));
connect (&mFileDialog, SIGNAL(openFiles()), this, SLOT(openFiles())); connect (&mFileDialog, SIGNAL(openFiles()), this, SLOT(openFiles()));
connect (&mFileDialog, SIGNAL(createNewFile()), this, SLOT(createNewFile())); connect (&mFileDialog, SIGNAL(createNewFile()), this, SLOT(createNewFile()));
@ -114,6 +121,44 @@ void CS::Editor::createNewFile()
mFileDialog.hide(); mFileDialog.hide();
} }
void CS::Editor::showStartup()
{
if(mStartup.isHidden())
mStartup.show();
mStartup.raise();
mStartup.activateWindow();
}
void CS::Editor::showSettings()
{
if (mSettings.isHidden())
mSettings.show();
mSettings.raise();
mSettings.activateWindow();
}
bool CS::Editor::makeIPCServer()
{
mServer = new QLocalServer(this);
if(mServer->listen(mIpcServerName))
{
connect(mServer, SIGNAL(newConnection()), this, SLOT(showStartup()));
return true;
}
mServer->close();
return false;
}
void CS::Editor::connectToIPCServer()
{
mClientSocket = new QLocalSocket(this);
mClientSocket->connectToServer(mIpcServerName);
mClientSocket->close();
}
int CS::Editor::run() int CS::Editor::run()
{ {
mStartup.show(); mStartup.show();

View file

@ -2,15 +2,22 @@
#define CS_EDITOR_H #define CS_EDITOR_H
#include <QObject> #include <QObject>
#include <QString>
#include <QLocalServer>
#include <QLocalSocket>
#ifndef Q_MOC_RUN #ifndef Q_MOC_RUN
#include <components/files/configurationmanager.hpp> #include <components/files/configurationmanager.hpp>
#endif #endif
#include "model/settings/usersettings.hpp"
#include "model/doc/documentmanager.hpp" #include "model/doc/documentmanager.hpp"
#include "view/doc/viewmanager.hpp" #include "view/doc/viewmanager.hpp"
#include "view/doc/startup.hpp" #include "view/doc/startup.hpp"
#include "view/doc/filedialog.hpp" #include "view/doc/filedialog.hpp"
#include "model/settings/usersettings.hpp"
#include "view/settings/usersettingsdialog.hpp"
namespace CS namespace CS
{ {
@ -22,6 +29,7 @@ namespace CS
CSMDoc::DocumentManager mDocumentManager; CSMDoc::DocumentManager mDocumentManager;
CSVDoc::ViewManager mViewManager; CSVDoc::ViewManager mViewManager;
CSVDoc::StartupDialogue mStartup; CSVDoc::StartupDialogue mStartup;
CSVSettings::UserSettingsDialog mSettings;
FileDialog mFileDialog; FileDialog mFileDialog;
Files::ConfigurationManager mCfgMgr; Files::ConfigurationManager mCfgMgr;
@ -35,6 +43,9 @@ namespace CS
Editor(); Editor();
bool makeIPCServer();
void connectToIPCServer();
int run(); int run();
///< \return error status ///< \return error status
@ -45,6 +56,16 @@ namespace CS
void loadDocument(); void loadDocument();
void openFiles(); void openFiles();
void createNewFile(); void createNewFile();
void showStartup();
void showSettings();
private:
QString mIpcServerName;
QLocalServer *mServer;
QLocalSocket *mClientSocket;
}; };
} }

View file

@ -39,5 +39,11 @@ int main(int argc, char *argv[])
CS::Editor editor; CS::Editor editor;
if(!editor.makeIPCServer())
{
editor.connectToIPCServer();
return 0;
}
return editor.run(); return editor.run();
} }

View file

@ -8,6 +8,8 @@
#include <components/misc/stringops.hpp> #include <components/misc/stringops.hpp>
#include "../world/columns.hpp" #include "../world/columns.hpp"
#include "../world/data.hpp"
#include "../world/idcollection.hpp"
#include "booleannode.hpp" #include "booleannode.hpp"
#include "ornode.hpp" #include "ornode.hpp"
@ -31,6 +33,7 @@ namespace CSMFilter
Type_OpenSquare, Type_OpenSquare,
Type_CloseSquare, Type_CloseSquare,
Type_Comma, Type_Comma,
Type_OneShot,
Type_Keyword_True, ///< \attention Keyword enums must be arranged continuously. Type_Keyword_True, ///< \attention Keyword enums must be arranged continuously.
Type_Keyword_False, Type_Keyword_False,
Type_Keyword_And, Type_Keyword_And,
@ -44,21 +47,33 @@ namespace CSMFilter
std::string mString; std::string mString;
double mNumber; double mNumber;
Token (Type type); Token (Type type = Type_None);
Token (Type type, const std::string& string);
///< Non-string type that can also be interpreted as a string.
Token (const std::string& string); Token (const std::string& string);
Token (double number); Token (double number);
operator bool() const; operator bool() const;
bool isString() const;
}; };
Token::Token (Type type) : mType (type) {} Token::Token (Type type) : mType (type) {}
Token::Token (Type type, const std::string& string) : mType (type), mString (string) {}
Token::Token (const std::string& string) : mType (Type_String), mString (string) {} Token::Token (const std::string& string) : mType (Type_String), mString (string) {}
Token::Token (double number) : mType (Type_Number), mNumber (number) {} Token::Token (double number) : mType (Type_Number), mNumber (number) {}
bool Token::isString() const
{
return mType==Type_String || mType>=Type_Keyword_True;
}
Token::operator bool() const Token::operator bool() const
{ {
return mType!=Type_None; return mType!=Type_None;
@ -89,7 +104,7 @@ CSMFilter::Token CSMFilter::Parser::getStringToken()
{ {
char c = mInput[mIndex]; char c = mInput[mIndex];
if (std::isalpha (c) || c=='_' || (!string.empty() && std::isdigit (c)) || c=='"' || if (std::isalpha (c) || c==':' || c=='_' || (!string.empty() && std::isdigit (c)) || c=='"' ||
(!string.empty() && string[0]=='"')) (!string.empty() && string[0]=='"'))
string += c; string += c;
else else
@ -117,7 +132,7 @@ CSMFilter::Token CSMFilter::Parser::getStringToken()
} }
if (string[0]=='"') if (string[0]=='"')
string = string.substr (1, string.size()-2); return string.substr (1, string.size()-2);
} }
return checkKeywords (string); return checkKeywords (string);
@ -171,15 +186,15 @@ CSMFilter::Token CSMFilter::Parser::checkKeywords (const Token& token)
{ {
"true", "false", "true", "false",
"and", "or", "not", "and", "or", "not",
"text", "value", "string", "value",
0 0
}; };
std::string string = Misc::StringUtils::lowerCase (token.mString); std::string string = Misc::StringUtils::lowerCase (token.mString);
for (int i=0; sKeywords[i]; ++i) for (int i=0; sKeywords[i]; ++i)
if (sKeywords[i]==string) if (sKeywords[i]==string || (string.size()==1 && sKeywords[i][0]==string[0]))
return Token (static_cast<Token::Type> (i+Token::Type_Keyword_True)); return Token (static_cast<Token::Type> (i+Token::Type_Keyword_True), token.mString);
return token; return token;
} }
@ -208,9 +223,10 @@ CSMFilter::Token CSMFilter::Parser::getNextToken()
case '[': ++mIndex; return Token (Token::Type_OpenSquare); case '[': ++mIndex; return Token (Token::Type_OpenSquare);
case ']': ++mIndex; return Token (Token::Type_CloseSquare); case ']': ++mIndex; return Token (Token::Type_CloseSquare);
case ',': ++mIndex; return Token (Token::Type_Comma); case ',': ++mIndex; return Token (Token::Type_Comma);
case '!': ++mIndex; return Token (Token::Type_OneShot);
} }
if (c=='"' || c=='_' || std::isalpha (c)) if (c=='"' || c=='_' || std::isalpha (c) || c==':')
return getStringToken(); return getStringToken();
if (c=='-' || c=='.' || std::isdigit (c)) if (c=='-' || c=='.' || std::isdigit (c))
@ -220,10 +236,14 @@ CSMFilter::Token CSMFilter::Parser::getNextToken()
return Token (Token::Type_None); return Token (Token::Type_None);
} }
boost::shared_ptr<CSMFilter::Node> CSMFilter::Parser::parseImp (bool allowEmpty) boost::shared_ptr<CSMFilter::Node> CSMFilter::Parser::parseImp (bool allowEmpty, bool ignoreOneShot)
{ {
if (Token token = getNextToken()) if (Token token = getNextToken())
{ {
if (token==Token (Token::Type_OneShot))
token = getNextToken();
if (token)
switch (token.mType) switch (token.mType)
{ {
case Token::Type_Keyword_True: case Token::Type_Keyword_True:
@ -343,7 +363,7 @@ boost::shared_ptr<CSMFilter::Node> CSMFilter::Parser::parseText()
if (static_cast<int> (token.mNumber)==token.mNumber) if (static_cast<int> (token.mNumber)==token.mNumber)
columnId = static_cast<int> (token.mNumber); columnId = static_cast<int> (token.mNumber);
} }
else if (token.mType==Token::Type_String) else if (token.isString())
{ {
columnId = CSMWorld::Columns::getId (token.mString); columnId = CSMWorld::Columns::getId (token.mString);
} }
@ -365,7 +385,7 @@ boost::shared_ptr<CSMFilter::Node> CSMFilter::Parser::parseText()
// parse text pattern // parse text pattern
token = getNextToken(); token = getNextToken();
if (token.mType!=Token::Type_String) if (!token.isString())
{ {
error(); error();
return boost::shared_ptr<Node>(); return boost::shared_ptr<Node>();
@ -407,7 +427,7 @@ boost::shared_ptr<CSMFilter::Node> CSMFilter::Parser::parseValue()
if (static_cast<int> (token.mNumber)==token.mNumber) if (static_cast<int> (token.mNumber)==token.mNumber)
columnId = static_cast<int> (token.mNumber); columnId = static_cast<int> (token.mNumber);
} }
else if (token.mType==Token::Type_String) else if (token.isString())
{ {
columnId = CSMWorld::Columns::getId (token.mString); columnId = CSMWorld::Columns::getId (token.mString);
} }
@ -429,22 +449,22 @@ boost::shared_ptr<CSMFilter::Node> CSMFilter::Parser::parseValue()
// parse value // parse value
double lower = 0; double lower = 0;
double upper = 0; double upper = 0;
bool min = false; ValueNode::Type lowerType = ValueNode::Type_Open;
bool max = false; ValueNode::Type upperType = ValueNode::Type_Open;
token = getNextToken(); token = getNextToken();
if (token.mType==Token::Type_Number) if (token.mType==Token::Type_Number)
{ {
// single value // single value
min = max = true;
lower = upper = token.mNumber; lower = upper = token.mNumber;
lowerType = upperType = ValueNode::Type_Closed;
} }
else else
{ {
// interval // interval
if (token.mType==Token::Type_OpenSquare) if (token.mType==Token::Type_OpenSquare)
min = true; lowerType = ValueNode::Type_Closed;
else if (token.mType!=Token::Type_CloseSquare && token.mType!=Token::Type_Open) else if (token.mType!=Token::Type_CloseSquare && token.mType!=Token::Type_Open)
{ {
error(); error();
@ -453,12 +473,8 @@ boost::shared_ptr<CSMFilter::Node> CSMFilter::Parser::parseValue()
token = getNextToken(); token = getNextToken();
if (token.mType!=Token::Type_Number) if (token.mType==Token::Type_Number)
{ {
error();
return boost::shared_ptr<Node>();
}
lower = token.mNumber; lower = token.mNumber;
token = getNextToken(); token = getNextToken();
@ -468,21 +484,33 @@ boost::shared_ptr<CSMFilter::Node> CSMFilter::Parser::parseValue()
error(); error();
return boost::shared_ptr<Node>(); return boost::shared_ptr<Node>();
} }
}
token = getNextToken(); else if (token.mType==Token::Type_Comma)
{
if (token.mType!=Token::Type_Number) lowerType = ValueNode::Type_Infinite;
}
else
{ {
error(); error();
return boost::shared_ptr<Node>(); return boost::shared_ptr<Node>();
} }
token = getNextToken();
if (token.mType==Token::Type_Number)
{
upper = token.mNumber; upper = token.mNumber;
token = getNextToken(); token = getNextToken();
}
else
upperType = ValueNode::Type_Infinite;
if (token.mType==Token::Type_CloseSquare) if (token.mType==Token::Type_CloseSquare)
max = true; {
if (upperType!=ValueNode::Type_Infinite)
upperType = ValueNode::Type_Closed;
}
else if (token.mType!=Token::Type_OpenSquare && token.mType!=Token::Type_Close) else if (token.mType!=Token::Type_OpenSquare && token.mType!=Token::Type_Close)
{ {
error(); error();
@ -498,7 +526,7 @@ boost::shared_ptr<CSMFilter::Node> CSMFilter::Parser::parseValue()
return boost::shared_ptr<Node>(); return boost::shared_ptr<Node>();
} }
return boost::shared_ptr<Node> (new ValueNode (columnId, lower, upper, min, max)); return boost::shared_ptr<Node> (new ValueNode (columnId, lowerType, upperType, lower, upper));
} }
void CSMFilter::Parser::error() void CSMFilter::Parser::error()
@ -506,9 +534,10 @@ void CSMFilter::Parser::error()
mError = true; mError = true;
} }
CSMFilter::Parser::Parser() : mIndex (0), mError (false) {} CSMFilter::Parser::Parser (const CSMWorld::Data& data)
: mIndex (0), mError (false), mData (data) {}
bool CSMFilter::Parser::parse (const std::string& filter) bool CSMFilter::Parser::parse (const std::string& filter, bool allowPredefined)
{ {
// reset // reset
mFilter.reset(); mFilter.reset();
@ -516,13 +545,23 @@ bool CSMFilter::Parser::parse (const std::string& filter)
mInput = filter; mInput = filter;
mIndex = 0; mIndex = 0;
boost::shared_ptr<Node> node = parseImp (true); Token token;
if (allowPredefined)
token = getNextToken();
if (!allowPredefined || token==Token (Token::Type_OneShot))
{
boost::shared_ptr<Node> node = parseImp (true, token!=Token (Token::Type_OneShot));
if (mError) if (mError)
return false; return false;
if (getNextToken()!=Token (Token::Type_EOS)) if (getNextToken()!=Token (Token::Type_EOS))
{
error();
return false; return false;
}
if (node) if (node)
mFilter = node; mFilter = node;
@ -533,6 +572,40 @@ bool CSMFilter::Parser::parse (const std::string& filter)
} }
return true; return true;
}
// We do not use isString() here, because there could be a pre-defined filter with an ID that is
// equal a filter keyword.
else if (token.mType==Token::Type_String && allowPredefined)
{
if (getNextToken()!=Token (Token::Type_EOS))
{
error();
return false;
}
int index = mData.getFilters().searchId (token.mString);
if (index==-1)
{
error();
return false;
}
const CSMWorld::Record<CSMFilter::Filter>& record = mData.getFilters().getRecord (index);
if (record.isDeleted())
{
error();
return false;
}
return parse (record.get().mFilter, false);
}
else
{
error();
return false;
}
} }
boost::shared_ptr<CSMFilter::Node> CSMFilter::Parser::getFilter() const boost::shared_ptr<CSMFilter::Node> CSMFilter::Parser::getFilter() const

View file

@ -5,6 +5,11 @@
#include "node.hpp" #include "node.hpp"
namespace CSMWorld
{
class Data;
}
namespace CSMFilter namespace CSMFilter
{ {
struct Token; struct Token;
@ -15,6 +20,7 @@ namespace CSMFilter
std::string mInput; std::string mInput;
int mIndex; int mIndex;
bool mError; bool mError;
const CSMWorld::Data& mData;
Token getStringToken(); Token getStringToken();
@ -25,7 +31,7 @@ namespace CSMFilter
Token checkKeywords (const Token& token); Token checkKeywords (const Token& token);
///< Turn string token into keyword token, if possible. ///< Turn string token into keyword token, if possible.
boost::shared_ptr<Node> parseImp (bool allowEmpty = false); boost::shared_ptr<Node> parseImp (bool allowEmpty = false, bool ignoreOneShot = false);
///< Will return a null-pointer, if there is nothing more to parse. ///< Will return a null-pointer, if there is nothing more to parse.
boost::shared_ptr<Node> parseNAry (const Token& keyword); boost::shared_ptr<Node> parseNAry (const Token& keyword);
@ -38,9 +44,9 @@ namespace CSMFilter
public: public:
Parser(); Parser (const CSMWorld::Data& data);
bool parse (const std::string& filter); bool parse (const std::string& filter, bool allowPredefined = true);
///< Discards any previous calls to parse ///< Discards any previous calls to parse
/// ///
/// \return Success? /// \return Success?

View file

@ -28,13 +28,34 @@ bool CSMFilter::TextNode::test (const CSMWorld::IdTable& table, int row,
QVariant data = table.data (index); QVariant data = table.data (index);
if (data.type()!=QVariant::String) QString string;
if (data.type()==QVariant::String)
{
string = data.toString();
}
else if (data.type()==QVariant::Int || data.type()==QVariant::UInt ||
CSMWorld::Columns::hasEnums (static_cast<CSMWorld::Columns::ColumnId> (mColumnId)))
{
int value = data.toInt();
std::vector<std::string> enums =
CSMWorld::Columns::getEnums (static_cast<CSMWorld::Columns::ColumnId> (mColumnId));
if (value>=0 && value<static_cast<int> (enums.size()))
string = QString::fromUtf8 (enums[value].c_str());
}
else if (data.type()==QVariant::Bool)
{
string = data.toBool() ? "true" : " false";
}
else
return false; return false;
/// \todo make pattern syntax configurable /// \todo make pattern syntax configurable
QRegExp regExp (QString::fromUtf8 (mText.c_str()), Qt::CaseInsensitive); QRegExp regExp (QString::fromUtf8 (mText.c_str()), Qt::CaseInsensitive);
return regExp.exactMatch (data.toString()); return regExp.exactMatch (string);
} }
std::vector<int> CSMFilter::TextNode::getReferencedColumns() const std::vector<int> CSMFilter::TextNode::getReferencedColumns() const

View file

@ -7,10 +7,9 @@
#include "../world/columns.hpp" #include "../world/columns.hpp"
#include "../world/idtable.hpp" #include "../world/idtable.hpp"
CSMFilter::ValueNode::ValueNode (int columnId, CSMFilter::ValueNode::ValueNode (int columnId, Type lowerType, Type upperType,
double lower, double upper, bool min, bool max) double lower, double upper)
: mColumnId (columnId), mLower (lower), mUpper (upper), mMin (min), mMax (max) : mColumnId (columnId), mLowerType (lowerType), mUpperType (upperType), mLower (lower), mUpper (upper){}
{}
bool CSMFilter::ValueNode::test (const CSMWorld::IdTable& table, int row, bool CSMFilter::ValueNode::test (const CSMWorld::IdTable& table, int row,
const std::map<int, int>& columns) const const std::map<int, int>& columns) const
@ -33,10 +32,21 @@ bool CSMFilter::ValueNode::test (const CSMWorld::IdTable& table, int row,
double value = data.toDouble(); double value = data.toDouble();
if (mLower==mUpper && mMin && mMax) switch (mLowerType)
return value==mLower; {
case Type_Closed: if (value<mLower) return false; break;
case Type_Open: if (value<=mLower) return false; break;
case Type_Infinite: break;
}
return (mMin ? value>=mLower : value>mLower) && (mMax ? value<=mUpper : value<mUpper); switch (mUpperType)
{
case Type_Closed: if (value>mUpper) return false; break;
case Type_Open: if (value>=mUpper) return false; break;
case Type_Infinite: break;
}
return true;
} }
std::vector<int> CSMFilter::ValueNode::getReferencedColumns() const std::vector<int> CSMFilter::ValueNode::getReferencedColumns() const
@ -60,10 +70,26 @@ std::string CSMFilter::ValueNode::toString (bool numericColumns) const
stream << ", \""; stream << ", \"";
if (mLower==mUpper && mMin && mMax) if (mLower==mUpper && mLowerType!=Type_Infinite && mUpperType!=Type_Infinite)
stream << mLower; stream << mLower;
else else
stream << (mMin ? "[" : "(") << mLower << ", " << mUpper << (mMax ? "]" : ")"); {
switch (mLowerType)
{
case Type_Closed: stream << "[" << mLower; break;
case Type_Open: stream << "(" << mLower; break;
case Type_Infinite: stream << "("; break;
}
stream << ", ";
switch (mUpperType)
{
case Type_Closed: stream << mUpper << "]"; break;
case Type_Open: stream << mUpper << ")"; break;
case Type_Infinite: stream << ")"; break;
}
}
stream << ")"; stream << ")";

View file

@ -7,16 +7,25 @@ namespace CSMFilter
{ {
class ValueNode : public LeafNode class ValueNode : public LeafNode
{ {
public:
enum Type
{
Type_Closed, Type_Open, Type_Infinite
};
private:
int mColumnId; int mColumnId;
std::string mText; std::string mText;
double mLower; double mLower;
double mUpper; double mUpper;
bool mMin; Type mLowerType;
bool mMax; Type mUpperType;
public: public:
ValueNode (int columnId, double lower, double upper, bool min, bool max); ValueNode (int columnId, Type lowerType, Type upperType, double lower, double upper);
virtual bool test (const CSMWorld::IdTable& table, int row, virtual bool test (const CSMWorld::IdTable& table, int row,
const std::map<int, int>& columns) const; const std::map<int, int>& columns) const;

View file

@ -7,7 +7,7 @@ void CSMWorld::Cell::load (ESM::ESMReader &esm)
{ {
mName = mId; mName = mId;
ESM::Cell::load (esm, true); /// \todo set this to false, once the bug in ESM::Cell::load is fixed ESM::Cell::load (esm, false);
if (!(mData.mFlags & Interior)) if (!(mData.mFlags & Interior))
{ {

View file

@ -236,13 +236,14 @@ namespace CSMWorld
if (iter->second>=index+count) if (iter->second>=index+count)
{ {
iter->second -= count; iter->second -= count;
++iter;
} }
else else
{ {
mIndex.erase (iter++); mIndex.erase (iter++);
} }
} }
else
++iter; ++iter;
} }
} }

View file

@ -1191,6 +1191,31 @@ namespace CSMWorld
return true; return true;
} }
}; };
template<typename ESXRecordT>
struct FilterColumn : public Column<ESXRecordT>
{
FilterColumn() : Column<ESXRecordT> (Columns::ColumnId_Filter, ColumnBase::Display_String) {}
virtual QVariant get (const Record<ESXRecordT>& record) const
{
return QString::fromUtf8 (record.get().mFilter.c_str());
}
virtual void set (Record<ESXRecordT>& record, const QVariant& data)
{
ESXRecordT record2 = record.get();
record2.mFilter = data.toString().toUtf8().constData();
record.setModified (record2);
}
virtual bool isEditable() const
{
return true;
}
};
} }
#endif #endif

View file

@ -3,6 +3,8 @@
#include <components/misc/stringops.hpp> #include <components/misc/stringops.hpp>
#include "universalid.hpp"
namespace CSMWorld namespace CSMWorld
{ {
namespace Columns namespace Columns
@ -144,6 +146,7 @@ namespace CSMWorld
{ ColumnId_MaxThrust, "Max Thrust" }, { ColumnId_MaxThrust, "Max Thrust" },
{ ColumnId_Magical, "Magical" }, { ColumnId_Magical, "Magical" },
{ ColumnId_Silver, "Silver" }, { ColumnId_Silver, "Silver" },
{ ColumnId_Filter, "Filter" },
{ ColumnId_UseValue1, "Use value 1" }, { ColumnId_UseValue1, "Use value 1" },
{ ColumnId_UseValue2, "Use value 2" }, { ColumnId_UseValue2, "Use value 2" },
@ -196,3 +199,103 @@ int CSMWorld::Columns::getId (const std::string& name)
return -1; return -1;
} }
namespace
{
static const char *sSpecialisations[] =
{
"Combat", "Magic", "Stealth", 0
};
static const char *sAttributes[] =
{
"Strength", "Intelligence", "Willpower", "Agility", "Speed", "Endurance", "Personality",
"Luck", 0
};
static const char *sSpellTypes[] =
{
"Spell", "Ability", "Blight", "Disease", "Curse", "Power", 0
};
static const char *sApparatusTypes[] =
{
"Mortar & Pestle", "Albemic", "Calcinator", "Retort", 0
};
static const char *sArmorTypes[] =
{
"Helmet", "Cuirass", "Left Pauldron", "Right Pauldron", "Greaves", "Boots", "Left Gauntlet",
"Right Gauntlet", "Shield", "Left Bracer", "Right Bracer", 0
};
static const char *sClothingTypes[] =
{
"Pants", "Shoes", "Shirt", "Belt", "Robe", "Right Glove", "Left Glove", "Skirt", "Ring",
"Amulet", 0
};
static const char *sCreatureTypes[] =
{
"Creature", "Deadra", "Undead", "Humanoid", 0
};
static const char *sWeaponTypes[] =
{
"Short Blade 1H", "Long Blade 1H", "Long Blade 2H", "Blunt 1H", "Blunt 2H Close",
"Blunt 2H Wide", "Spear 2H", "Axe 1H", "Axe 2H", "Bow", "Crossbow", "Thrown", "Arrow",
"Bolt", 0
};
static const char *sModificationEnums[] =
{
"Base", "Modified", "Added", "Deleted", "Deleted", 0
};
static const char *sVarTypeEnums[] =
{
"unknown", "none", "short", "integer", "long", "float", "string", 0
};
const char **getEnumNames (CSMWorld::Columns::ColumnId column)
{
switch (column)
{
case CSMWorld::Columns::ColumnId_Specialisation: return sSpecialisations;
case CSMWorld::Columns::ColumnId_Attribute: return sAttributes;
case CSMWorld::Columns::ColumnId_SpellType: return sSpellTypes;
case CSMWorld::Columns::ColumnId_ApparatusType: return sApparatusTypes;
case CSMWorld::Columns::ColumnId_ArmorType: return sArmorTypes;
case CSMWorld::Columns::ColumnId_ClothingType: return sClothingTypes;
case CSMWorld::Columns::ColumnId_CreatureType: return sCreatureTypes;
case CSMWorld::Columns::ColumnId_WeaponType: return sWeaponTypes;
case CSMWorld::Columns::ColumnId_Modification: return sModificationEnums;
case CSMWorld::Columns::ColumnId_ValueType: return sVarTypeEnums;
default: return 0;
}
}
}
bool CSMWorld::Columns::hasEnums (ColumnId column)
{
return getEnumNames (column)!=0 || column==ColumnId_RecordType;
}
std::vector<std::string> CSMWorld::Columns::getEnums (ColumnId column)
{
std::vector<std::string> enums;
if (const char **table = getEnumNames (column))
for (int i=0; table[i]; ++i)
enums.push_back (table[i]);
else if (column==ColumnId_RecordType)
{
enums.push_back (""); // none
for (int i=UniversalId::Type_None+1; i<UniversalId::NumberOfTypes; ++i)
enums.push_back (UniversalId (static_cast<UniversalId::Type> (i)).getTypeName());
}
return enums;
}

View file

@ -2,6 +2,7 @@
#define CSM_WOLRD_COLUMNS_H #define CSM_WOLRD_COLUMNS_H
#include <string> #include <string>
#include <vector>
namespace CSMWorld namespace CSMWorld
{ {
@ -138,6 +139,7 @@ namespace CSMWorld
ColumnId_MaxThrust = 106, ColumnId_MaxThrust = 106,
ColumnId_Magical = 107, ColumnId_Magical = 107,
ColumnId_Silver = 108, ColumnId_Silver = 108,
ColumnId_Filter = 109,
// Allocated to a separate value range, so we don't get a collision should we ever need // Allocated to a separate value range, so we don't get a collision should we ever need
// to extend the number of use values. // to extend the number of use values.
@ -179,6 +181,11 @@ namespace CSMWorld
int getId (const std::string& name); int getId (const std::string& name);
///< Will return -1 for an invalid name. ///< Will return -1 for an invalid name.
bool hasEnums (ColumnId column);
std::vector<std::string> getEnums (ColumnId column);
///< Returns an empty vector, if \æ column isn't an enum type column.
} }
} }

View file

@ -69,7 +69,9 @@ CSMWorld::RevertCommand::~RevertCommand()
void CSMWorld::RevertCommand::redo() void CSMWorld::RevertCommand::redo()
{ {
QModelIndex index = mModel.getModelIndex (mId, 1); int column = mModel.findColumnIndex (Columns::ColumnId_Modification);
QModelIndex index = mModel.getModelIndex (mId, column);
RecordBase::State state = static_cast<RecordBase::State> (mModel.data (index).toInt()); RecordBase::State state = static_cast<RecordBase::State> (mModel.data (index).toInt());
if (state==RecordBase::State_ModifiedOnly) if (state==RecordBase::State_ModifiedOnly)
@ -102,7 +104,9 @@ CSMWorld::DeleteCommand::~DeleteCommand()
void CSMWorld::DeleteCommand::redo() void CSMWorld::DeleteCommand::redo()
{ {
QModelIndex index = mModel.getModelIndex (mId, 1); int column = mModel.findColumnIndex (Columns::ColumnId_Modification);
QModelIndex index = mModel.getModelIndex (mId, column);
RecordBase::State state = static_cast<RecordBase::State> (mModel.data (index).toInt()); RecordBase::State state = static_cast<RecordBase::State> (mModel.data (index).toInt());
if (state==RecordBase::State_ModifiedOnly) if (state==RecordBase::State_ModifiedOnly)

View file

@ -150,6 +150,7 @@ CSMWorld::Data::Data() : mRefs (mCells)
mFilters.addColumn (new StringIdColumn<CSMFilter::Filter>); mFilters.addColumn (new StringIdColumn<CSMFilter::Filter>);
mFilters.addColumn (new RecordStateColumn<CSMFilter::Filter>); mFilters.addColumn (new RecordStateColumn<CSMFilter::Filter>);
mFilters.addColumn (new FilterColumn<CSMFilter::Filter>);
mFilters.addColumn (new DescriptionColumn<CSMFilter::Filter>); mFilters.addColumn (new DescriptionColumn<CSMFilter::Filter>);
addModel (new IdTable (&mGlobals), UniversalId::Type_Globals, UniversalId::Type_Global); addModel (new IdTable (&mGlobals), UniversalId::Type_Globals, UniversalId::Type_Global);
@ -316,6 +317,16 @@ CSMWorld::RefCollection& CSMWorld::Data::getReferences()
return mRefs; return mRefs;
} }
const CSMWorld::IdCollection<CSMFilter::Filter>& CSMWorld::Data::getFilters() const
{
return mFilters;
}
CSMWorld::IdCollection<CSMFilter::Filter>& CSMWorld::Data::getFilters()
{
return mFilters;
}
QAbstractItemModel *CSMWorld::Data::getTableModel (const UniversalId& id) QAbstractItemModel *CSMWorld::Data::getTableModel (const UniversalId& id)
{ {
std::map<UniversalId::Type, QAbstractItemModel *>::iterator iter = mModelIndex.find (id.getType()); std::map<UniversalId::Type, QAbstractItemModel *>::iterator iter = mModelIndex.find (id.getType());

View file

@ -119,6 +119,10 @@ namespace CSMWorld
RefCollection& getReferences(); RefCollection& getReferences();
const IdCollection<CSMFilter::Filter>& getFilters() const;
IdCollection<CSMFilter::Filter>& getFilters();
QAbstractItemModel *getTableModel (const UniversalId& id); QAbstractItemModel *getTableModel (const UniversalId& id);
///< If no table model is available for \a id, an exception is thrown. ///< If no table model is available for \a id, an exception is thrown.
/// ///

View file

@ -8,8 +8,6 @@ void CSMWorld::CellRef::load (ESM::ESMReader &esm, Cell& cell, const std::string
mId = id; mId = id;
mCellId = cell.mId; mCellId = cell.mId;
cell.getNextRef (esm, *this);
if (!mDeleted) if (!mDeleted)
cell.addRef (mId); cell.addRef (mId);
} }

View file

@ -6,10 +6,6 @@
#include "ref.hpp" #include "ref.hpp"
#include "cell.hpp" #include "cell.hpp"
CSMWorld::RefCollection::RefCollection (Collection<Cell>& cells)
: mCells (cells), mNextId (0)
{}
void CSMWorld::RefCollection::load (ESM::ESMReader& reader, int cellIndex, bool base) void CSMWorld::RefCollection::load (ESM::ESMReader& reader, int cellIndex, bool base)
{ {
Record<Cell> cell = mCells.getRecord (cellIndex); Record<Cell> cell = mCells.getRecord (cellIndex);

View file

@ -16,8 +16,10 @@ namespace CSMWorld
int mNextId; int mNextId;
public: public:
// MSVC needs the constructor for a class inheriting a template to be defined in header
RefCollection (Collection<Cell>& cells); RefCollection (Collection<Cell>& cells)
: mCells (cells), mNextId (0)
{}
void load (ESM::ESMReader& reader, int cellIndex, bool base); void load (ESM::ESMReader& reader, int cellIndex, bool base);
///< Load a sequence of references. ///< Load a sequence of references.

View file

@ -80,7 +80,7 @@ namespace
{ CSMWorld::UniversalId::Class_RefRecord, CSMWorld::UniversalId::Type_Static, "Static", ":./static.png" }, { CSMWorld::UniversalId::Class_RefRecord, CSMWorld::UniversalId::Type_Static, "Static", ":./static.png" },
{ CSMWorld::UniversalId::Class_RefRecord, CSMWorld::UniversalId::Type_Weapon, "Weapon", ":./weapon.png" }, { CSMWorld::UniversalId::Class_RefRecord, CSMWorld::UniversalId::Type_Weapon, "Weapon", ":./weapon.png" },
{ CSMWorld::UniversalId::Class_SubRecord, CSMWorld::UniversalId::Type_Reference, "Reference", 0 }, { CSMWorld::UniversalId::Class_SubRecord, CSMWorld::UniversalId::Type_Reference, "Reference", 0 },
{ CSMWorld::UniversalId::Class_SubRecord, CSMWorld::UniversalId::Type_Filter, "Filter", 0 },
{ CSMWorld::UniversalId::Class_None, CSMWorld::UniversalId::Type_None, 0, 0 } // end marker { CSMWorld::UniversalId::Class_None, CSMWorld::UniversalId::Type_None, 0, 0 } // end marker
}; };
@ -90,8 +90,6 @@ namespace
{ CSMWorld::UniversalId::Class_None, CSMWorld::UniversalId::Type_None, 0, 0 } // end marker { CSMWorld::UniversalId::Class_None, CSMWorld::UniversalId::Type_None, 0, 0 } // end marker
}; };
static const unsigned int IDARG_SIZE = sizeof (sIdArg) / sizeof (TypeData);
} }
CSMWorld::UniversalId::UniversalId (const std::string& universalId) CSMWorld::UniversalId::UniversalId (const std::string& universalId)
@ -151,6 +149,22 @@ CSMWorld::UniversalId::UniversalId (Type type) : mArgumentType (ArgumentType_Non
return; return;
} }
for (int i=0; sIdArg[i].mName; ++i)
if (type==sIdArg[i].mType)
{
mArgumentType = ArgumentType_Id;
mClass = sIdArg[i].mClass;
return;
}
for (int i=0; sIndexArg[i].mName; ++i)
if (type==sIndexArg[i].mType)
{
mArgumentType = ArgumentType_Index;
mClass = sIndexArg[i].mClass;
return;
}
throw std::logic_error ("invalid argument-less UniversalId type"); throw std::logic_error ("invalid argument-less UniversalId type");
} }
@ -293,25 +307,6 @@ std::vector<CSMWorld::UniversalId::Type> CSMWorld::UniversalId::listReferenceabl
return list; return list;
} }
std::pair<int, const char *> CSMWorld::UniversalId::getIdArgPair (unsigned int index)
{
std::pair<int, const char *> retPair;
if ( index < IDARG_SIZE )
{
retPair.first = sIdArg[index].mType;
retPair.second = sIdArg[index].mName;
}
return retPair;
}
unsigned int CSMWorld::UniversalId::getIdArgSize()
{
return IDARG_SIZE;
}
bool CSMWorld::operator== (const CSMWorld::UniversalId& left, const CSMWorld::UniversalId& right) bool CSMWorld::operator== (const CSMWorld::UniversalId& left, const CSMWorld::UniversalId& right)
{ {
return left.isEqual (right); return left.isEqual (right);

View file

@ -34,7 +34,7 @@ namespace CSMWorld
enum Type enum Type
{ {
Type_None, Type_None = 0,
Type_Globals, Type_Globals,
Type_Global, Type_Global,
Type_VerificationResults, Type_VerificationResults,
@ -89,6 +89,8 @@ namespace CSMWorld
Type_Filters Type_Filters
}; };
enum { NumberOfTypes = Type_Filters+1 };
private: private:
Class mClass; Class mClass;
@ -102,7 +104,6 @@ namespace CSMWorld
UniversalId (const std::string& universalId); UniversalId (const std::string& universalId);
UniversalId (Type type = Type_None); UniversalId (Type type = Type_None);
///< Using a type for a non-argument-less UniversalId will throw an exception.
UniversalId (Type type, const std::string& id); UniversalId (Type type, const std::string& id);
///< Using a type for a non-ID-argument UniversalId will throw an exception. ///< Using a type for a non-ID-argument UniversalId will throw an exception.
@ -134,9 +135,6 @@ namespace CSMWorld
///< Will return an empty string, if no icon is available. ///< Will return an empty string, if no icon is available.
static std::vector<Type> listReferenceableTypes(); static std::vector<Type> listReferenceableTypes();
static std::pair<int, const char *> getIdArgPair (unsigned int index);
static unsigned int getIdArgSize ();
}; };
bool operator== (const UniversalId& left, const UniversalId& right); bool operator== (const UniversalId& left, const UniversalId& right);

View file

@ -3,21 +3,106 @@
#include <QApplication> #include <QApplication>
#include <QDesktopWidget> #include <QDesktopWidget>
#include <QPushButton> #include <QVBoxLayout>
#include <QHBoxLayout> #include <QHBoxLayout>
#include <QRect> #include <QRect>
#include <QGridLayout>
#include <QLabel>
#include <QIcon>
#include <QPushButton>
CSVDoc::StartupDialogue::StartupDialogue() QPushButton *CSVDoc::StartupDialogue::addButton (const QString& label, const QIcon& icon)
{ {
QHBoxLayout *layout = new QHBoxLayout (this); int column = mColumn--;
QPushButton *createDocument = new QPushButton ("new", this); QPushButton *button = new QPushButton (this);
connect (createDocument, SIGNAL (clicked()), this, SIGNAL (createDocument()));
layout->addWidget (createDocument);
QPushButton *loadDocument = new QPushButton ("load", this); button->setIcon (QIcon (icon));
button->setSizePolicy (QSizePolicy (QSizePolicy::Preferred, QSizePolicy::Preferred));
mLayout->addWidget (button, 0, column);
mLayout->addWidget (new QLabel (label, this), 1, column, Qt::AlignCenter);
int width = mLayout->itemAtPosition (1, column)->widget()->sizeHint().width();
if (width>mWidth)
mWidth = width;
return button;
}
QWidget *CSVDoc::StartupDialogue::createButtons()
{
QWidget *widget = new QWidget (this);
mLayout = new QGridLayout (widget);
/// \todo add icons
QPushButton *loadDocument = addButton ("Edit A Content File", QIcon (":startup/edit-content"));
connect (loadDocument, SIGNAL (clicked()), this, SIGNAL (loadDocument())); connect (loadDocument, SIGNAL (clicked()), this, SIGNAL (loadDocument()));
layout->addWidget (loadDocument);
QPushButton *createAddon = addButton ("Create A New Addon", QIcon (":startup/create-addon"));
connect (createAddon, SIGNAL (clicked()), this, SIGNAL (createAddon()));
QPushButton *createGame = addButton ("Create A New Game", QIcon (":startup/create-game"));
connect (createGame, SIGNAL (clicked()), this, SIGNAL (createGame()));
for (int i=0; i<3; ++i)
mLayout->setColumnMinimumWidth (i, mWidth);
mLayout->setRowMinimumHeight (0, mWidth);
mLayout->setSizeConstraint (QLayout::SetMinimumSize);
mLayout->setHorizontalSpacing (32);
mLayout->setContentsMargins (16, 16, 16, 8);
loadDocument->setIconSize (QSize (mWidth, mWidth));
createGame->setIconSize (QSize (mWidth, mWidth));
createAddon->setIconSize (QSize (mWidth, mWidth));
widget->setLayout (mLayout);
return widget;
}
QWidget *CSVDoc::StartupDialogue::createTools()
{
QWidget *widget = new QWidget (this);
QHBoxLayout *layout = new QHBoxLayout (widget);
layout->setDirection (QBoxLayout::RightToLeft);
layout->setContentsMargins (4, 4, 4, 4);
QPushButton *config = new QPushButton (widget);
config->setSizePolicy (QSizePolicy (QSizePolicy::Fixed, QSizePolicy::Fixed));
config->setIcon (QIcon (":startup/configure"));
layout->addWidget (config);
layout->addWidget (new QWidget, 1); // dummy widget; stops buttons from taking all the space
widget->setLayout (layout);
connect (config, SIGNAL (clicked()), this, SIGNAL (editConfig()));
return widget;
}
CSVDoc::StartupDialogue::StartupDialogue() : mWidth (0), mColumn (2)
{
setWindowTitle ("Open CS");
QVBoxLayout *layout = new QVBoxLayout (this);
layout->setContentsMargins (0, 0, 0, 0);
layout->addWidget (createButtons());
layout->addWidget (createTools());
setLayout (layout); setLayout (layout);

View file

@ -3,21 +3,43 @@
#include <QWidget> #include <QWidget>
class QGridLayout;
class QString;
class QPushButton;
class QWidget;
class QIcon;
namespace CSVDoc namespace CSVDoc
{ {
class StartupDialogue : public QWidget class StartupDialogue : public QWidget
{ {
Q_OBJECT Q_OBJECT
private:
int mWidth;
int mColumn;
QGridLayout *mLayout;
QPushButton *addButton (const QString& label, const QIcon& icon);
QWidget *createButtons();
QWidget *createTools();
public: public:
StartupDialogue(); StartupDialogue();
signals: signals:
void createDocument(); void createGame();
void createAddon();
void loadDocument(); void loadDocument();
void editConfig();
}; };
} }

View file

@ -67,7 +67,7 @@ void CSVDoc::View::setupEditMenu()
edit->addAction (mRedo); edit->addAction (mRedo);
QAction *userSettings = new QAction (tr ("&Preferences"), this); QAction *userSettings = new QAction (tr ("&Preferences"), this);
connect (userSettings, SIGNAL (triggered()), this, SLOT (showUserSettings())); connect (userSettings, SIGNAL (triggered()), this, SIGNAL (editSettingsRequest()));
edit->addAction (userSettings); edit->addAction (userSettings);
} }
@ -415,13 +415,6 @@ void CSVDoc::View::exit()
emit exitApplicationRequest (this); emit exitApplicationRequest (this);
} }
void CSVDoc::View::showUserSettings()
{
CSVSettings::UserSettingsDialog *settingsDialog = new CSVSettings::UserSettingsDialog(this);
settingsDialog->show();
}
void CSVDoc::View::resizeViewWidth (int width) void CSVDoc::View::resizeViewWidth (int width)
{ {
if (width >= 0) if (width >= 0)

View file

@ -112,6 +112,8 @@ namespace CSVDoc
void exitApplicationRequest (CSVDoc::View *view); void exitApplicationRequest (CSVDoc::View *view);
void editSettingsRequest();
public slots: public slots:
void addSubView (const CSMWorld::UniversalId& id); void addSubView (const CSMWorld::UniversalId& id);
@ -160,8 +162,6 @@ namespace CSVDoc
void addFiltersSubView(); void addFiltersSubView();
void showUserSettings();
void toggleShowStatusBar (bool show); void toggleShowStatusBar (bool show);
}; };
} }

View file

@ -8,6 +8,7 @@
#include "../../model/doc/documentmanager.hpp" #include "../../model/doc/documentmanager.hpp"
#include "../../model/doc/document.hpp" #include "../../model/doc/document.hpp"
#include "../../model/world/columns.hpp"
#include "../world/util.hpp" #include "../world/util.hpp"
#include "../world/enumdelegate.hpp" #include "../world/enumdelegate.hpp"
@ -43,51 +44,6 @@ void CSVDoc::ViewManager::updateIndices()
CSVDoc::ViewManager::ViewManager (CSMDoc::DocumentManager& documentManager) CSVDoc::ViewManager::ViewManager (CSMDoc::DocumentManager& documentManager)
: mDocumentManager (documentManager), mExitOnSaveStateChange(false), mUserWarned(false) : mDocumentManager (documentManager), mExitOnSaveStateChange(false), mUserWarned(false)
{ {
static const char *sSpecialisations[] =
{
"Combat", "Magic", "Stealth", 0
};
static const char *sAttributes[] =
{
"Strength", "Intelligence", "Willpower", "Agility", "Speed", "Endurance", "Personality",
"Luck", 0
};
static const char *sSpellTypes[] =
{
"Spell", "Ability", "Blight", "Disease", "Curse", "Power", 0
};
static const char *sApparatusTypes[] =
{
"Mortar & Pestle", "Albemic", "Calcinator", "Retort", 0
};
static const char *sArmorTypes[] =
{
"Helmet", "Cuirass", "Left Pauldron", "Right Pauldron", "Greaves", "Boots", "Left Gauntlet",
"Right Gauntlet", "Shield", "Left Bracer", "Right Bracer", 0
};
static const char *sClothingTypes[] =
{
"Pants", "Shoes", "Shirt", "Belt", "Robe", "Right Glove", "Left Glove", "Skirt", "Ring",
"Amulet", 0
};
static const char *sCreatureTypes[] =
{
"Creature", "Deadra", "Undead", "Humanoid", 0
};
static const char *sWeaponTypes[] =
{
"Short Blade 1H", "Long Blade 1H", "Long Blade 2H", "Blunt 1H", "Blunt 2H Close",
"Blunt 2H Wide", "Spear 2H", "Axe 1H", "Axe 2H", "Bow", "Crossbow", "Thrown", "Arrow",
"Bolt", 0
};
mDelegateFactories = new CSVWorld::CommandDelegateFactoryCollection; mDelegateFactories = new CSVWorld::CommandDelegateFactoryCollection;
mDelegateFactories->add (CSMWorld::ColumnBase::Display_GmstVarType, mDelegateFactories->add (CSMWorld::ColumnBase::Display_GmstVarType,
@ -96,35 +52,34 @@ CSVDoc::ViewManager::ViewManager (CSMDoc::DocumentManager& documentManager)
mDelegateFactories->add (CSMWorld::ColumnBase::Display_GlobalVarType, mDelegateFactories->add (CSMWorld::ColumnBase::Display_GlobalVarType,
new CSVWorld::VarTypeDelegateFactory (ESM::VT_Short, ESM::VT_Long, ESM::VT_Float)); new CSVWorld::VarTypeDelegateFactory (ESM::VT_Short, ESM::VT_Long, ESM::VT_Float));
mDelegateFactories->add (CSMWorld::ColumnBase::Display_Specialisation,
new CSVWorld::EnumDelegateFactory (sSpecialisations));
mDelegateFactories->add (CSMWorld::ColumnBase::Display_Attribute,
new CSVWorld::EnumDelegateFactory (sAttributes, true));
mDelegateFactories->add (CSMWorld::ColumnBase::Display_SpellType,
new CSVWorld::EnumDelegateFactory (sSpellTypes));
mDelegateFactories->add (CSMWorld::ColumnBase::Display_ApparatusType,
new CSVWorld::EnumDelegateFactory (sApparatusTypes));
mDelegateFactories->add (CSMWorld::ColumnBase::Display_ArmorType,
new CSVWorld::EnumDelegateFactory (sArmorTypes));
mDelegateFactories->add (CSMWorld::ColumnBase::Display_ClothingType,
new CSVWorld::EnumDelegateFactory (sClothingTypes));
mDelegateFactories->add (CSMWorld::ColumnBase::Display_CreatureType,
new CSVWorld::EnumDelegateFactory (sCreatureTypes));
mDelegateFactories->add (CSMWorld::ColumnBase::Display_WeaponType,
new CSVWorld::EnumDelegateFactory (sWeaponTypes));
mDelegateFactories->add (CSMWorld::ColumnBase::Display_RecordState, mDelegateFactories->add (CSMWorld::ColumnBase::Display_RecordState,
new CSVWorld::RecordStatusDelegateFactory() ); new CSVWorld::RecordStatusDelegateFactory());
mDelegateFactories->add (CSMWorld::ColumnBase::Display_RefRecordType, mDelegateFactories->add (CSMWorld::ColumnBase::Display_RefRecordType,
new CSVWorld::RefIdTypeDelegateFactory() ); new CSVWorld::RefIdTypeDelegateFactory());
struct Mapping
{
CSMWorld::ColumnBase::Display mDisplay;
CSMWorld::Columns::ColumnId mColumnId;
bool mAllowNone;
};
static const Mapping sMapping[] =
{
{ CSMWorld::ColumnBase::Display_Specialisation, CSMWorld::Columns::ColumnId_Specialisation, false },
{ CSMWorld::ColumnBase::Display_Attribute, CSMWorld::Columns::ColumnId_Attribute, true },
{ CSMWorld::ColumnBase::Display_SpellType, CSMWorld::Columns::ColumnId_SpellType, false },
{ CSMWorld::ColumnBase::Display_ApparatusType, CSMWorld::Columns::ColumnId_ApparatusType, false },
{ CSMWorld::ColumnBase::Display_ArmorType, CSMWorld::Columns::ColumnId_ArmorType, false },
{ CSMWorld::ColumnBase::Display_ClothingType, CSMWorld::Columns::ColumnId_ClothingType, false },
{ CSMWorld::ColumnBase::Display_CreatureType, CSMWorld::Columns::ColumnId_CreatureType, false },
{ CSMWorld::ColumnBase::Display_WeaponType, CSMWorld::Columns::ColumnId_WeaponType, false }
};
for (std::size_t i=0; i<sizeof (sMapping)/sizeof (Mapping); ++i)
mDelegateFactories->add (sMapping[i].mDisplay, new CSVWorld::EnumDelegateFactory (
CSMWorld::Columns::getEnums (sMapping[i].mColumnId), sMapping[i].mAllowNone));
connect (&CSMSettings::UserSettings::instance(), SIGNAL (signalUpdateEditorSetting (const QString &, const QString &)), connect (&CSMSettings::UserSettings::instance(), SIGNAL (signalUpdateEditorSetting (const QString &, const QString &)),
this, SLOT (slotUpdateEditorSetting (const QString &, const QString &))); this, SLOT (slotUpdateEditorSetting (const QString &, const QString &)));
@ -159,6 +114,7 @@ CSVDoc::View *CSVDoc::ViewManager::addView (CSMDoc::Document *document)
connect (view, SIGNAL (newDocumentRequest ()), this, SIGNAL (newDocumentRequest())); connect (view, SIGNAL (newDocumentRequest ()), this, SIGNAL (newDocumentRequest()));
connect (view, SIGNAL (loadDocumentRequest ()), this, SIGNAL (loadDocumentRequest())); connect (view, SIGNAL (loadDocumentRequest ()), this, SIGNAL (loadDocumentRequest()));
connect (view, SIGNAL (editSettingsRequest()), this, SIGNAL (editSettingsRequest()));
updateIndices(); updateIndices();

View file

@ -61,6 +61,8 @@ namespace CSVDoc
void closeMessageBox(); void closeMessageBox();
void editSettingsRequest();
public slots: public slots:
void exitApplication (CSVDoc::View *view); void exitApplication (CSVDoc::View *view);

View file

@ -1,11 +1,27 @@
#include "editwidget.hpp" #include "editwidget.hpp"
CSVFilter::EditWidget::EditWidget (QWidget *parent) #include <QAbstractItemModel>
: QLineEdit (parent)
#include "../../model/world/data.hpp"
CSVFilter::EditWidget::EditWidget (CSMWorld::Data& data, QWidget *parent)
: QLineEdit (parent), mParser (data)
{ {
mPalette = palette(); mPalette = palette();
connect (this, SIGNAL (textChanged (const QString&)), this, SLOT (textChanged (const QString&))); connect (this, SIGNAL (textChanged (const QString&)), this, SLOT (textChanged (const QString&)));
QAbstractItemModel *model = data.getTableModel (CSMWorld::UniversalId::Type_Filters);
connect (model, SIGNAL (dataChanged (const QModelIndex &, const QModelIndex&)),
this, SLOT (filterDataChanged (const QModelIndex &, const QModelIndex&)),
Qt::QueuedConnection);
connect (model, SIGNAL (rowsRemoved (const QModelIndex&, int, int)),
this, SLOT (filterRowsRemoved (const QModelIndex&, int, int)),
Qt::QueuedConnection);
connect (model, SIGNAL (rowsInserted (const QModelIndex&, int, int)),
this, SLOT (filterRowsInserted (const QModelIndex&, int, int)),
Qt::QueuedConnection);
} }
void CSVFilter::EditWidget::textChanged (const QString& text) void CSVFilter::EditWidget::textChanged (const QString& text)
@ -24,3 +40,19 @@ void CSVFilter::EditWidget::textChanged (const QString& text)
/// \todo improve error reporting; mark only the faulty part /// \todo improve error reporting; mark only the faulty part
} }
} }
void CSVFilter::EditWidget::filterDataChanged (const QModelIndex& topLeft,
const QModelIndex& bottomRight)
{
textChanged (text());
}
void CSVFilter::EditWidget::filterRowsRemoved (const QModelIndex& parent, int start, int end)
{
textChanged (text());
}
void CSVFilter::EditWidget::filterRowsInserted (const QModelIndex& parent, int start, int end)
{
textChanged (text());
}

View file

@ -9,6 +9,13 @@
#include "../../model/filter/parser.hpp" #include "../../model/filter/parser.hpp"
#include "../../model/filter/node.hpp" #include "../../model/filter/node.hpp"
class QModelIndex;
namespace CSMWorld
{
class Data;
}
namespace CSVFilter namespace CSVFilter
{ {
class EditWidget : public QLineEdit class EditWidget : public QLineEdit
@ -20,7 +27,7 @@ namespace CSVFilter
public: public:
EditWidget (QWidget *parent = 0); EditWidget (CSMWorld::Data& data, QWidget *parent = 0);
signals: signals:
@ -29,6 +36,12 @@ namespace CSVFilter
private slots: private slots:
void textChanged (const QString& text); void textChanged (const QString& text);
void filterDataChanged (const QModelIndex& topLeft, const QModelIndex& bottomRight);
void filterRowsRemoved (const QModelIndex& parent, int start, int end);
void filterRowsInserted (const QModelIndex& parent, int start, int end);
}; };
} }

View file

@ -5,14 +5,14 @@
#include "recordfilterbox.hpp" #include "recordfilterbox.hpp"
CSVFilter::FilterBox::FilterBox (QWidget *parent) CSVFilter::FilterBox::FilterBox (CSMWorld::Data& data, QWidget *parent)
: QWidget (parent) : QWidget (parent)
{ {
QHBoxLayout *layout = new QHBoxLayout (this); QHBoxLayout *layout = new QHBoxLayout (this);
layout->setContentsMargins (0, 0, 0, 0); layout->setContentsMargins (0, 0, 0, 0);
RecordFilterBox *recordFilterBox = new RecordFilterBox (this); RecordFilterBox *recordFilterBox = new RecordFilterBox (data, this);
layout->addWidget (recordFilterBox); layout->addWidget (recordFilterBox);

View file

@ -5,6 +5,11 @@
#include "../../model/filter/node.hpp" #include "../../model/filter/node.hpp"
namespace CSMWorld
{
class Data;
}
namespace CSVFilter namespace CSVFilter
{ {
class FilterBox : public QWidget class FilterBox : public QWidget
@ -13,7 +18,7 @@ namespace CSVFilter
public: public:
FilterBox (QWidget *parent = 0); FilterBox (CSMWorld::Data& data, QWidget *parent = 0);
signals: signals:

View file

@ -6,7 +6,7 @@
#include "editwidget.hpp" #include "editwidget.hpp"
CSVFilter::RecordFilterBox::RecordFilterBox (QWidget *parent) CSVFilter::RecordFilterBox::RecordFilterBox (CSMWorld::Data& data, QWidget *parent)
: QWidget (parent) : QWidget (parent)
{ {
QHBoxLayout *layout = new QHBoxLayout (this); QHBoxLayout *layout = new QHBoxLayout (this);
@ -15,7 +15,7 @@ CSVFilter::RecordFilterBox::RecordFilterBox (QWidget *parent)
layout->addWidget (new QLabel ("Record Filter", this)); layout->addWidget (new QLabel ("Record Filter", this));
EditWidget *editWidget = new EditWidget (this); EditWidget *editWidget = new EditWidget (data, this);
layout->addWidget (editWidget); layout->addWidget (editWidget);

View file

@ -9,6 +9,11 @@
#include "../../model/filter/node.hpp" #include "../../model/filter/node.hpp"
namespace CSMWorld
{
class Data;
}
namespace CSVFilter namespace CSVFilter
{ {
class RecordFilterBox : public QWidget class RecordFilterBox : public QWidget
@ -17,7 +22,7 @@ namespace CSVFilter
public: public:
RecordFilterBox (QWidget *parent = 0); RecordFilterBox (CSMWorld::Data& data, QWidget *parent = 0);
signals: signals:

View file

@ -1,5 +1,7 @@
#include "usersettingsdialog.hpp" #include "usersettingsdialog.hpp"
#include <boost/filesystem/path.hpp>
#include <QApplication> #include <QApplication>
#include <QDesktopWidget> #include <QDesktopWidget>
#include <QWidget> #include <QWidget>
@ -9,14 +11,14 @@
#include <QFile> #include <QFile>
#include <QPushButton> #include <QPushButton>
#include <QDockWidget> #include <QDockWidget>
#include <QGridLayout> #include <QGridLayout>
#include <QApplication>
#include <QDesktopWidget>
#include "../../model/settings/support.hpp"
#include "datadisplayformatpage.hpp" #include "datadisplayformatpage.hpp"
#include "windowpage.hpp" #include "windowpage.hpp"
#include "../../model/settings/support.hpp"
#include <boost/filesystem/path.hpp>
#include "settingwidget.hpp" #include "settingwidget.hpp"
CSVSettings::UserSettingsDialog::UserSettingsDialog(QMainWindow *parent) : CSVSettings::UserSettingsDialog::UserSettingsDialog(QMainWindow *parent) :
@ -30,6 +32,10 @@ CSVSettings::UserSettingsDialog::UserSettingsDialog(QMainWindow *parent) :
SIGNAL (currentItemChanged(QListWidgetItem*, QListWidgetItem*)), SIGNAL (currentItemChanged(QListWidgetItem*, QListWidgetItem*)),
this, this,
SLOT (slotChangePage (QListWidgetItem*, QListWidgetItem*))); SLOT (slotChangePage (QListWidgetItem*, QListWidgetItem*)));
QRect scr = QApplication::desktop()->screenGeometry();
QRect rect = geometry();
move (scr.center().x() - rect.center().x(), scr.center().y() - rect.center().y());
} }
CSVSettings::UserSettingsDialog::~UserSettingsDialog() CSVSettings::UserSettingsDialog::~UserSettingsDialog()

View file

@ -109,6 +109,18 @@ CSVWorld::EnumDelegateFactory::EnumDelegateFactory (const char **names, bool all
add (i, names[i]); add (i, names[i]);
} }
CSVWorld::EnumDelegateFactory::EnumDelegateFactory (const std::vector<std::string>& names,
bool allowNone)
{
if (allowNone)
add (-1, "");
int size = static_cast<int> (names.size());
for (int i=0; i<size; ++i)
add (i, names[i].c_str());
}
CSVWorld::CommandDelegate *CSVWorld::EnumDelegateFactory::makeDelegate (QUndoStack& undoStack, CSVWorld::CommandDelegate *CSVWorld::EnumDelegateFactory::makeDelegate (QUndoStack& undoStack,
QObject *parent) const QObject *parent) const
{ {

View file

@ -54,6 +54,9 @@ namespace CSVWorld
///< \param names Array of char pointer with a 0-pointer as end mark ///< \param names Array of char pointer with a 0-pointer as end mark
/// \param allowNone Use value of -1 for "none selected" (empty string) /// \param allowNone Use value of -1 for "none selected" (empty string)
EnumDelegateFactory (const std::vector<std::string>& names, bool allowNone = false);
/// \param allowNone Use value of -1 for "none selected" (empty string)
virtual CommandDelegate *makeDelegate (QUndoStack& undoStack, QObject *parent) const; virtual CommandDelegate *makeDelegate (QUndoStack& undoStack, QObject *parent) const;
///< The ownership of the returned CommandDelegate is transferred to the caller. ///< The ownership of the returned CommandDelegate is transferred to the caller.

View file

@ -1,8 +1,11 @@
#include "recordstatusdelegate.hpp" #include "recordstatusdelegate.hpp"
#include <QPainter> #include <QPainter>
#include <QApplication> #include <QApplication>
#include <QUndoStack> #include <QUndoStack>
#include "../../model/settings/usersettings.hpp" #include "../../model/settings/usersettings.hpp"
#include "../../model/world/columns.hpp"
CSVWorld::RecordStatusDelegate::RecordStatusDelegate(const ValueList& values, CSVWorld::RecordStatusDelegate::RecordStatusDelegate(const ValueList& values,
const IconList & icons, const IconList & icons,
@ -37,9 +40,14 @@ bool CSVWorld::RecordStatusDelegate::updateEditorSetting (const QString &setting
CSVWorld::RecordStatusDelegateFactory::RecordStatusDelegateFactory() CSVWorld::RecordStatusDelegateFactory::RecordStatusDelegateFactory()
{ {
DataDisplayDelegateFactory::add ( CSMWorld::RecordBase::State_BaseOnly, "Base", ":./base.png"); std::vector<std::string> enums =
DataDisplayDelegateFactory::add ( CSMWorld::RecordBase::State_Deleted, "Deleted", ":./removed.png"); CSMWorld::Columns::getEnums (CSMWorld::Columns::ColumnId_Modification);
DataDisplayDelegateFactory::add ( CSMWorld::RecordBase::State_Erased, "Deleted", ":./removed.png");
DataDisplayDelegateFactory::add ( CSMWorld::RecordBase::State_Modified, "Modified", ":./modified.png"); static const char *sIcons[] =
DataDisplayDelegateFactory::add ( CSMWorld::RecordBase::State_ModifiedOnly, "Added", ":./added.png"); {
":./base.png", ":./modified.png", ":./added.png", ":./removed.png", ":./removed.png", 0
};
for (int i=0; sIcons[i]; ++i)
add (i, enums.at (i).c_str(), sIcons[i]);
} }

View file

@ -1,4 +1,5 @@
#include "refidtypedelegate.hpp" #include "refidtypedelegate.hpp"
#include "../../model/world/universalid.hpp" #include "../../model/world/universalid.hpp"
CSVWorld::RefIdTypeDelegate::RefIdTypeDelegate CSVWorld::RefIdTypeDelegate::RefIdTypeDelegate
@ -6,6 +7,26 @@ CSVWorld::RefIdTypeDelegate::RefIdTypeDelegate
: DataDisplayDelegate (values, icons, undoStack, parent) : DataDisplayDelegate (values, icons, undoStack, parent)
{} {}
bool CSVWorld::RefIdTypeDelegate::updateEditorSetting (const QString &settingName, const QString &settingValue)
{
if (settingName == "Referenceable ID Type Display")
{
if (settingValue == "Icon and Text")
mDisplayMode = Mode_IconAndText;
else if (settingValue == "Icon Only")
mDisplayMode = Mode_IconOnly;
else if (settingValue == "Text Only")
mDisplayMode = Mode_TextOnly;
return true;
}
return false;
}
CSVWorld::RefIdTypeDelegateFactory::RefIdTypeDelegateFactory() CSVWorld::RefIdTypeDelegateFactory::RefIdTypeDelegateFactory()
{ {
UidTypeList uIdList = buildUidTypeList(); UidTypeList uIdList = buildUidTypeList();
@ -39,22 +60,3 @@ CSVWorld::RefIdTypeDelegateFactory::UidTypeList CSVWorld::RefIdTypeDelegateFacto
return list; return list;
} }
bool CSVWorld::RefIdTypeDelegate::updateEditorSetting (const QString &settingName, const QString &settingValue)
{
if (settingName == "Referenceable ID Type Display")
{
if (settingValue == "Icon and Text")
mDisplayMode = Mode_IconAndText;
else if (settingValue == "Icon Only")
mDisplayMode = Mode_IconOnly;
else if (settingValue == "Text Only")
mDisplayMode = Mode_TextOnly;
return true;
}
return false;
}

View file

@ -1,25 +0,0 @@
#include "refrecordtypedelegate.hpp"
#include "../../model/world/universalid.hpp"
CSVWorld::RefRecordTypeDelegate::RefRecordTypeDelegate
(const std::vector<std::pair<int, QString> > &values, QUndoStack& undoStack, QObject *parent)
: EnumDelegate (values, undoStack, parent)
{}
CSVWorld::RefRecordTypeDelegateFactory::RefRecordTypeDelegateFactory()
{
unsigned int argSize = CSMWorld::UniversalId::getIdArgSize();
for (unsigned int i = 0; i < argSize; i++)
{
std::pair<int, const char *> idPair = CSMWorld::UniversalId::getIdArgPair(i);
mValues.push_back (std::pair<int, QString>(idPair.first, QString::fromUtf8(idPair.second)));
}
}
CSVWorld::CommandDelegate *CSVWorld::RefRecordTypeDelegateFactory::makeDelegate (QUndoStack& undoStack,
QObject *parent) const
{
return new RefRecordTypeDelegate (mValues, undoStack, parent);
}

View file

@ -1,58 +0,0 @@
#ifndef REFRECORDTYPEDELEGATE_HPP
#define REFRECORDTYPEDELEGATE_HPP
#include "enumdelegate.hpp"
#include "util.hpp"
namespace CSVWorld
{
class RefRecordTypeDelegate : public EnumDelegate
{
public:
RefRecordTypeDelegate (const std::vector<std::pair<int, QString> > &mValues, QUndoStack& undoStack, QObject *parent);
};
class RefRecordTypeDelegateFactory : public CommandDelegateFactory
{
std::vector<std::pair<int, QString> > mValues;
public:
RefRecordTypeDelegateFactory();
virtual CommandDelegate *makeDelegate (QUndoStack& undoStack, QObject *parent) const;
///< The ownership of the returned CommandDelegate is transferred to the caller.
};
}
/*
class VarTypeDelegate : public EnumDelegate
{
private:
virtual void addCommands (QAbstractItemModel *model,
const QModelIndex& index, int type) const;
public:
VarTypeDelegate (const std::vector<std::pair<int, QString> >& values,
QUndoStack& undoStack, QObject *parent);
};
class VarTypeDelegateFactory : public CommandDelegateFactory
{
std::vector<std::pair<int, QString> > mValues;
public:
VarTypeDelegateFactory (ESM::VarType type0 = ESM::VT_Unknown,
ESM::VarType type1 = ESM::VT_Unknown, ESM::VarType type2 = ESM::VT_Unknown,
ESM::VarType type3 = ESM::VT_Unknown);
virtual CommandDelegate *makeDelegate (QUndoStack& undoStack, QObject *parent) const;
///< The ownership of the returned CommandDelegate is transferred to the caller.
void add (ESM::VarType type);
};
*/
#endif // REFRECORDTYPEDELEGATE_HPP

View file

@ -25,7 +25,7 @@ CSVWorld::TableSubView::TableSubView (const CSMWorld::UniversalId& id, CSMDoc::D
layout->insertWidget (0, mTable = layout->insertWidget (0, mTable =
new Table (id, document.getData(), document.getUndoStack(), mBottom->canCreateAndDelete()), 2); new Table (id, document.getData(), document.getUndoStack(), mBottom->canCreateAndDelete()), 2);
CSVFilter::FilterBox *filterBox = new CSVFilter::FilterBox (this); CSVFilter::FilterBox *filterBox = new CSVFilter::FilterBox (document.getData(), this);
layout->insertWidget (0, filterBox); layout->insertWidget (0, filterBox);

View file

@ -4,6 +4,7 @@
#include <QUndoStack> #include <QUndoStack>
#include "../../model/world/commands.hpp" #include "../../model/world/commands.hpp"
#include "../../model/world/columns.hpp"
void CSVWorld::VarTypeDelegate::addCommands (QAbstractItemModel *model, const QModelIndex& index, int type) void CSVWorld::VarTypeDelegate::addCommands (QAbstractItemModel *model, const QModelIndex& index, int type)
const const
@ -75,29 +76,11 @@ CSVWorld::CommandDelegate *CSVWorld::VarTypeDelegateFactory::makeDelegate (QUndo
void CSVWorld::VarTypeDelegateFactory::add (ESM::VarType type) void CSVWorld::VarTypeDelegateFactory::add (ESM::VarType type)
{ {
struct Name std::vector<std::string> enums =
{ CSMWorld::Columns::getEnums (CSMWorld::Columns::ColumnId_ValueType);
ESM::VarType mType;
const char *mName;
};
static const Name sNames[] =
{
{ ESM::VT_None, "empty" },
{ ESM::VT_Short, "short" },
{ ESM::VT_Int, "integer" },
{ ESM::VT_Long, "long" },
{ ESM::VT_Float, "float" },
{ ESM::VT_String, "string" },
{ ESM::VT_Unknown, 0 } // end marker
};
for (int i=0; sNames[i].mName; ++i)
if (sNames[i].mType==type)
{
mValues.push_back (std::make_pair (type, sNames[i].mName));
return;
}
if (type<0 && type>=enums.size())
throw std::logic_error ("Unsupported variable type"); throw std::logic_error ("Unsupported variable type");
mValues.push_back (std::make_pair (type, QString::fromUtf8 (enums[type].c_str())));
} }

View file

@ -123,6 +123,7 @@ bool OMW::Engine::frameRenderingQueued (const Ogre::FrameEvent& evt)
MWBase::Environment::get().getWindowManager()->wmUpdateFps(window->getLastFPS(), tri, batch); MWBase::Environment::get().getWindowManager()->wmUpdateFps(window->getLastFPS(), tri, batch);
MWBase::Environment::get().getWindowManager()->onFrame(frametime); MWBase::Environment::get().getWindowManager()->onFrame(frametime);
MWBase::Environment::get().getWindowManager()->update();
} }
catch (const std::exception& e) catch (const std::exception& e)
{ {
@ -385,26 +386,39 @@ void OMW::Engine::prepareEngine (Settings::Manager & settings)
loadBSA(); loadBSA();
// Create input and UI first to set up a bootstrapping environment for
// showing a loading screen and keeping the window responsive while doing so
std::string keybinderUser = (mCfgMgr.getUserPath() / "input.xml").string();
bool keybinderUserExists = boost::filesystem::exists(keybinderUser);
MWInput::InputManager* input = new MWInput::InputManager (*mOgre, *this, keybinderUser, keybinderUserExists);
mEnvironment.setInputManager (input);
MWGui::WindowManager* window = new MWGui::WindowManager(
mExtensions, mFpsLevel, mOgre, mCfgMgr.getLogPath().string() + std::string("/"),
mCfgMgr.getCachePath ().string(), mScriptConsoleMode, mTranslationDataStorage, mEncoding);
mEnvironment.setWindowManager (window);
if (mNewGame)
mEnvironment.getWindowManager()->setNewGame(true);
// Create the world // Create the world
mEnvironment.setWorld( new MWWorld::World (*mOgre, mFileCollections, mMaster, mPlugins, mEnvironment.setWorld( new MWWorld::World (*mOgre, mFileCollections, mMaster, mPlugins,
mResDir, mCfgMgr.getCachePath(), mEncoder, mFallbackMap, mResDir, mCfgMgr.getCachePath(), mEncoder, mFallbackMap,
mActivationDistanceOverride)); mActivationDistanceOverride));
MWBase::Environment::get().getWorld()->setupPlayer(); MWBase::Environment::get().getWorld()->setupPlayer();
input->setPlayer(&mEnvironment.getWorld()->getPlayer());
window->initUI();
window->renderWorldMap();
//Load translation data //Load translation data
mTranslationDataStorage.setEncoder(mEncoder); mTranslationDataStorage.setEncoder(mEncoder);
for (size_t i = 0; i < mMaster.size(); i++) for (size_t i = 0; i < mMaster.size(); i++)
mTranslationDataStorage.loadTranslationData(mFileCollections, mMaster[i]); mTranslationDataStorage.loadTranslationData(mFileCollections, mMaster[i]);
// Create window manager - this manages all the MW-specific GUI windows
Compiler::registerExtensions (mExtensions); Compiler::registerExtensions (mExtensions);
mEnvironment.setWindowManager (new MWGui::WindowManager(
mExtensions, mFpsLevel, mOgre, mCfgMgr.getLogPath().string() + std::string("/"),
mCfgMgr.getCachePath ().string(), mScriptConsoleMode, mTranslationDataStorage, mEncoding));
if (mNewGame)
mEnvironment.getWindowManager()->setNewGame(true);
// Create sound system // Create sound system
mEnvironment.setSoundManager (new MWSound::SoundManager(mUseSound)); mEnvironment.setSoundManager (new MWSound::SoundManager(mUseSound));
@ -422,16 +436,6 @@ void OMW::Engine::prepareEngine (Settings::Manager & settings)
mEnvironment.setJournal (new MWDialogue::Journal); mEnvironment.setJournal (new MWDialogue::Journal);
mEnvironment.setDialogueManager (new MWDialogue::DialogueManager (mExtensions, mVerboseScripts, mTranslationDataStorage)); mEnvironment.setDialogueManager (new MWDialogue::DialogueManager (mExtensions, mVerboseScripts, mTranslationDataStorage));
// Sets up the input system
// Get the path for the keybinder xml file
std::string keybinderUser = (mCfgMgr.getUserPath() / "input.xml").string();
bool keybinderUserExists = boost::filesystem::exists(keybinderUser);
mEnvironment.setInputManager (new MWInput::InputManager (*mOgre,
MWBase::Environment::get().getWorld()->getPlayer(),
*MWBase::Environment::get().getWindowManager(), *this, keybinderUser, keybinderUserExists));
mEnvironment.getWorld()->renderPlayer(); mEnvironment.getWorld()->renderPlayer();
if (!mNewGame) if (!mNewGame)

View file

@ -39,9 +39,11 @@ namespace MWBase
Play_Normal = 0, /* tracked, non-looping, multi-instance, environment */ Play_Normal = 0, /* tracked, non-looping, multi-instance, environment */
Play_Loop = 1<<0, /* Sound will continually loop until explicitly stopped */ Play_Loop = 1<<0, /* Sound will continually loop until explicitly stopped */
Play_NoEnv = 1<<1, /* Do not apply environment effects (eg, underwater filters) */ Play_NoEnv = 1<<1, /* Do not apply environment effects (eg, underwater filters) */
Play_NoTrack = 1<<2 /* (3D only) Play the sound at the given object's position Play_NoTrack = 1<<2, /* (3D only) Play the sound at the given object's position
* but do not keep it updated (the sound will not move with * but do not keep it updated (the sound will not move with
* the object and will not stop when the object is deleted. */ * the object and will not stop when the object is deleted. */
Play_LoopNoEnv = Play_Loop | Play_NoEnv
}; };
enum PlayType { enum PlayType {
Play_TypeSfx = 1<<3, /* Normal SFX sound */ Play_TypeSfx = 1<<3, /* Normal SFX sound */

View file

@ -9,6 +9,8 @@
#include <components/translation/translation.hpp> #include <components/translation/translation.hpp>
#include <components/loadinglistener/loadinglistener.hpp>
#include "../mwmechanics/stat.hpp" #include "../mwmechanics/stat.hpp"
#include "../mwgui/mode.hpp" #include "../mwgui/mode.hpp"
@ -253,9 +255,6 @@ namespace MWBase
virtual void executeInConsole (const std::string& path) = 0; virtual void executeInConsole (const std::string& path) = 0;
virtual void setLoadingProgress (const std::string& stage, int depth, int current, int total) = 0;
virtual void loadingDone() = 0;
virtual void enableRest() = 0; virtual void enableRest() = 0;
virtual bool getRestEnabled() = 0; virtual bool getRestEnabled() = 0;
virtual bool getJournalAllowed() = 0; virtual bool getJournalAllowed() = 0;
@ -282,6 +281,8 @@ namespace MWBase
virtual const Translation::Storage& getTranslationDataStorage() const = 0; virtual const Translation::Storage& getTranslationDataStorage() const = 0;
virtual void setKeyFocusWidget (MyGUI::Widget* widget) = 0; virtual void setKeyFocusWidget (MyGUI::Widget* widget) = 0;
virtual Loading::Listener* getLoadingScreen() = 0;
}; };
} }

View file

@ -6,16 +6,23 @@
#include "../mwbase/environment.hpp" #include "../mwbase/environment.hpp"
#include "../mwbase/windowmanager.hpp" #include "../mwbase/windowmanager.hpp"
#include "../mwbase/mechanicsmanager.hpp" #include "../mwbase/mechanicsmanager.hpp"
#include "../mwbase/world.hpp"
#include "../mwworld//cellstore.hpp" #include "../mwworld//cellstore.hpp"
#include "../mwworld/ptr.hpp" #include "../mwworld/ptr.hpp"
#include "../mwworld/physicssystem.hpp" #include "../mwworld/physicssystem.hpp"
#include "../mwworld/action.hpp"
#include "../mwworld/failedaction.hpp"
#include "../mwworld/nullaction.hpp"
#include "../mwrender/actors.hpp" #include "../mwrender/actors.hpp"
#include "../mwrender/renderinginterface.hpp" #include "../mwrender/renderinginterface.hpp"
#include "../mwgui/tooltips.hpp" #include "../mwgui/tooltips.hpp"
#include "../mwmechanics/npcstats.hpp"
namespace MWClass namespace MWClass
{ {
void Activator::insertObjectRendering (const MWWorld::Ptr& ptr, MWRender::RenderingInterface& renderingInterface) const void Activator::insertObjectRendering (const MWWorld::Ptr& ptr, MWRender::RenderingInterface& renderingInterface) const
@ -95,6 +102,22 @@ namespace MWClass
return info; return info;
} }
boost::shared_ptr<MWWorld::Action> Activator::activate(const MWWorld::Ptr &ptr, const MWWorld::Ptr &actor) const
{
if(get(actor).isNpc() && get(actor).getNpcStats(actor).isWerewolf())
{
const MWWorld::ESMStore &store = MWBase::Environment::get().getWorld()->getStore();
const ESM::Sound *sound = store.get<ESM::Sound>().searchRandom("WolfActivator");
boost::shared_ptr<MWWorld::Action> action(new MWWorld::FailedAction("#{sWerewolfRefusal}"));
if(sound) action->setSound(sound->mId);
return action;
}
return boost::shared_ptr<MWWorld::Action>(new MWWorld::NullAction);
}
MWWorld::Ptr MWWorld::Ptr
Activator::copyToCellImpl(const MWWorld::Ptr &ptr, MWWorld::CellStore &cell) const Activator::copyToCellImpl(const MWWorld::Ptr &ptr, MWWorld::CellStore &cell) const
{ {

View file

@ -31,6 +31,9 @@ namespace MWClass
virtual std::string getScript (const MWWorld::Ptr& ptr) const; virtual std::string getScript (const MWWorld::Ptr& ptr) const;
///< Return name of the script attached to ptr ///< Return name of the script attached to ptr
virtual boost::shared_ptr<MWWorld::Action> activate (const MWWorld::Ptr& ptr, const MWWorld::Ptr& actor) const;
///< Generate action for activation
static void registerSelf(); static void registerSelf();
virtual std::string getModel(const MWWorld::Ptr &ptr) const; virtual std::string getModel(const MWWorld::Ptr &ptr) const;

View file

@ -19,20 +19,16 @@ namespace MWGui
: mSceneMgr(sceneMgr) : mSceneMgr(sceneMgr)
, mWindow(rw) , mWindow(rw)
, WindowBase("openmw_loading_screen.layout") , WindowBase("openmw_loading_screen.layout")
, mLoadingOn(false)
, mLastRenderTime(0.f) , mLastRenderTime(0.f)
, mLastWallpaperChangeTime(0.f) , mLastWallpaperChangeTime(0.f)
, mFirstLoad(true) , mFirstLoad(true)
, mTotalRefsLoading(0) , mProgress(0)
, mCurrentCellLoading(0)
, mTotalCellsLoading(0)
, mCurrentRefLoading(0)
, mCurrentRefList(0)
{ {
getWidget(mLoadingText, "LoadingText"); getWidget(mLoadingText, "LoadingText");
getWidget(mProgressBar, "ProgressBar"); getWidget(mProgressBar, "ProgressBar");
getWidget(mBackgroundImage, "BackgroundImage"); getWidget(mBackgroundImage, "BackgroundImage");
mProgressBar->setScrollViewPage(1);
mBackgroundMaterial = Ogre::MaterialManager::getSingleton().create("BackgroundMaterial", Ogre::ResourceGroupManager::DEFAULT_RESOURCE_GROUP_NAME); mBackgroundMaterial = Ogre::MaterialManager::getSingleton().create("BackgroundMaterial", Ogre::ResourceGroupManager::DEFAULT_RESOURCE_GROUP_NAME);
mBackgroundMaterial->getTechnique(0)->getPass(0)->setLightingEnabled(false); mBackgroundMaterial->getTechnique(0)->getPass(0)->setLightingEnabled(false);
@ -54,6 +50,11 @@ namespace MWGui
mRectangle->setVisible(false); mRectangle->setVisible(false);
} }
void LoadingScreen::setLabel(const std::string &label)
{
mLoadingText->setCaptionWithReplacing(label);
}
LoadingScreen::~LoadingScreen() LoadingScreen::~LoadingScreen()
{ {
delete mRectangle; delete mRectangle;
@ -64,149 +65,25 @@ namespace MWGui
setCoord(0,0,w,h); setCoord(0,0,w,h);
} }
void LoadingScreen::setLoadingProgress (const std::string& stage, int depth, int current, int total)
{
if (!mLoadingOn)
loadingOn();
const int numRefLists = 20;
if (depth == 0)
{
mCurrentCellLoading = current;
mTotalCellsLoading = total;
mCurrentRefLoading = 0;
mCurrentRefList = 0;
}
else if (depth == 1)
{
mCurrentRefLoading = current;
mTotalRefsLoading = total;
}
assert (mTotalCellsLoading != 0);
float refProgress;
if (mTotalRefsLoading <= 1)
refProgress = 1;
else
refProgress = float(mCurrentRefLoading) / float(mTotalRefsLoading-1);
refProgress += mCurrentRefList;
refProgress /= numRefLists;
assert(refProgress <= 1 && refProgress >= 0);
if (depth == 1 && mCurrentRefLoading == mTotalRefsLoading-1)
++mCurrentRefList;
float progress = (float(mCurrentCellLoading)+refProgress) / float(mTotalCellsLoading);
assert(progress <= 1 && progress >= 0);
mLoadingText->setCaption(stage);
mProgressBar->setProgressPosition (static_cast<size_t>(progress * 1000));
static float loadingScreenFps = 30.f;
if (mTimer.getMilliseconds () > mLastRenderTime + (1.f/loadingScreenFps) * 1000.f)
{
float dt = mTimer.getMilliseconds () - mLastRenderTime;
mLastRenderTime = mTimer.getMilliseconds ();
if (mFirstLoad && mTimer.getMilliseconds () > mLastWallpaperChangeTime + 3000*1)
{
mLastWallpaperChangeTime = mTimer.getMilliseconds ();
changeWallpaper();
}
// Turn off rendering except the GUI
mSceneMgr->clearSpecialCaseRenderQueues();
// SCRQM_INCLUDE with RENDER_QUEUE_OVERLAY does not work.
for (int i = 0; i < Ogre::RENDER_QUEUE_MAX; ++i)
{
if (i > 0 && i < 96)
mSceneMgr->addSpecialCaseRenderQueue(i);
}
mSceneMgr->setSpecialCaseRenderQueueMode(Ogre::SceneManager::SCRQM_EXCLUDE);
// always update input before rendering something, otherwise mygui goes crazy when something was entered in the frame before
// (e.g. when using "coc" console command, it would enter an infinite loop and crash due to overflow)
MWBase::Environment::get().getInputManager()->update(0, true);
Ogre::CompositorChain* chain = Ogre::CompositorManager::getSingleton().getCompositorChain(mWindow->getViewport(0));
bool hasCompositor = chain->getCompositor ("gbufferFinalizer");
if (!hasCompositor)
{
mWindow->getViewport(0)->setClearEveryFrame(false);
}
else
{
if (!mFirstLoad)
{
mBackgroundMaterial->getTechnique(0)->getPass(0)->getTextureUnitState(0)->setTextureName(chain->getCompositor ("gbufferFinalizer")->getTextureInstance ("no_mrt_output", 0)->getName());
mRectangle->setVisible(true);
}
for (unsigned int i = 0; i<chain->getNumCompositors(); ++i)
{
Ogre::CompositorManager::getSingleton().setCompositorEnabled(mWindow->getViewport(0), chain->getCompositor(i)->getCompositor()->getName(), false);
}
}
MWBase::Environment::get().getWorld ()->getFader ()->update (dt);
mWindow->update();
if (!hasCompositor)
mWindow->getViewport(0)->setClearEveryFrame(true);
else
{
for (unsigned int i = 0; i<chain->getNumCompositors(); ++i)
{
Ogre::CompositorManager::getSingleton().setCompositorEnabled(mWindow->getViewport(0), chain->getCompositor(i)->getCompositor()->getName(), true);
}
}
mRectangle->setVisible(false);
// resume 3d rendering
mSceneMgr->clearSpecialCaseRenderQueues();
mSceneMgr->setSpecialCaseRenderQueueMode(Ogre::SceneManager::SCRQM_EXCLUDE);
}
}
void LoadingScreen::loadingDone()
{
loadingOff();
}
void LoadingScreen::loadingOn() void LoadingScreen::loadingOn()
{ {
setVisible(true); setVisible(true);
mLoadingOn = true;
if (mFirstLoad) if (mFirstLoad)
{ {
changeWallpaper(); changeWallpaper();
MWBase::Environment::get().getWindowManager()->pushGuiMode(GM_LoadingWallpaper);
} }
else else
{ {
mBackgroundImage->setImageTexture(""); mBackgroundImage->setImageTexture("");
MWBase::Environment::get().getWindowManager()->pushGuiMode(GM_Loading);
}
} }
MWBase::Environment::get().getWindowManager()->pushGuiMode(mFirstLoad ? GM_LoadingWallpaper : GM_Loading);
}
void LoadingScreen::loadingOff() void LoadingScreen::loadingOff()
{ {
setVisible(false); setVisible(false);
mLoadingOn = false;
mFirstLoad = false;
MWBase::Environment::get().getWindowManager()->removeGuiMode(GM_Loading); MWBase::Environment::get().getWindowManager()->removeGuiMode(GM_Loading);
MWBase::Environment::get().getWindowManager()->removeGuiMode(GM_LoadingWallpaper); MWBase::Environment::get().getWindowManager()->removeGuiMode(GM_LoadingWallpaper);
@ -235,4 +112,124 @@ namespace MWGui
else else
std::cerr << "No loading screens found!" << std::endl; std::cerr << "No loading screens found!" << std::endl;
} }
void LoadingScreen::setProgressRange (size_t range)
{
mProgressBar->setScrollRange(range+1);
mProgressBar->setScrollPosition(0);
mProgressBar->setTrackSize(0);
mProgress = 0;
}
void LoadingScreen::setProgress (size_t value)
{
assert(value < mProgressBar->getScrollRange());
if (value - mProgress < mProgressBar->getScrollRange()/100.f)
return;
mProgress = value;
mProgressBar->setScrollPosition(0);
mProgressBar->setTrackSize(value / (float)(mProgressBar->getScrollRange()) * mProgressBar->getLineSize());
draw();
}
void LoadingScreen::increaseProgress (size_t increase)
{
mProgressBar->setScrollPosition(0);
size_t value = mProgress + increase;
mProgress = value;
assert(mProgress < mProgressBar->getScrollRange());
mProgressBar->setTrackSize(value / (float)(mProgressBar->getScrollRange()) * mProgressBar->getLineSize());
draw();
}
void LoadingScreen::indicateProgress()
{
float time = (mTimer.getMilliseconds() % 2001) / 1000.f;
if (time > 1)
time = (time-2)*-1;
mProgressBar->setTrackSize(50);
mProgressBar->setScrollPosition(time * (mProgressBar->getScrollRange()-1));
draw();
}
void LoadingScreen::removeWallpaper()
{
mFirstLoad = false;
}
void LoadingScreen::draw()
{
const float loadingScreenFps = 20.f;
if (mTimer.getMilliseconds () > mLastRenderTime + (1.f/loadingScreenFps) * 1000.f)
{
mLastRenderTime = mTimer.getMilliseconds ();
if (mFirstLoad && mTimer.getMilliseconds () > mLastWallpaperChangeTime + 5000*1)
{
mLastWallpaperChangeTime = mTimer.getMilliseconds ();
changeWallpaper();
}
// Turn off rendering except the GUI
mSceneMgr->clearSpecialCaseRenderQueues();
// SCRQM_INCLUDE with RENDER_QUEUE_OVERLAY does not work.
for (int i = 0; i < Ogre::RENDER_QUEUE_MAX; ++i)
{
if (i > 0 && i < 96)
mSceneMgr->addSpecialCaseRenderQueue(i);
}
mSceneMgr->setSpecialCaseRenderQueueMode(Ogre::SceneManager::SCRQM_EXCLUDE);
MWBase::Environment::get().getInputManager()->update(0, true);
Ogre::CompositorChain* chain = Ogre::CompositorManager::getSingleton().getCompositorChain(mWindow->getViewport(0));
bool hasCompositor = chain->getCompositor ("gbufferFinalizer");
if (!hasCompositor)
{
mWindow->getViewport(0)->setClearEveryFrame(false);
}
else
{
if (!mFirstLoad)
{
mBackgroundMaterial->getTechnique(0)->getPass(0)->getTextureUnitState(0)->setTextureName(chain->getCompositor ("gbufferFinalizer")->getTextureInstance ("no_mrt_output", 0)->getName());
mRectangle->setVisible(true);
}
for (unsigned int i = 0; i<chain->getNumCompositors(); ++i)
{
Ogre::CompositorManager::getSingleton().setCompositorEnabled(mWindow->getViewport(0), chain->getCompositor(i)->getCompositor()->getName(), false);
}
}
// First, swap buffers from last draw, then, queue an update of the
// window contents, but don't swap buffers (which would have
// caused a sync / flush and would be expensive).
// We're doing this so we can do some actual loading while the GPU is busy with the render.
// This means the render is lagging a frame behind, but this is hardly noticable.
mWindow->swapBuffers(false); // never Vsync, makes no sense here
mWindow->update(false);
if (!hasCompositor)
mWindow->getViewport(0)->setClearEveryFrame(true);
else
{
for (unsigned int i = 0; i<chain->getNumCompositors(); ++i)
{
Ogre::CompositorManager::getSingleton().setCompositorEnabled(mWindow->getViewport(0), chain->getCompositor(i)->getCompositor()->getName(), true);
}
}
mRectangle->setVisible(false);
// resume 3d rendering
mSceneMgr->clearSpecialCaseRenderQueues();
mSceneMgr->setSpecialCaseRenderQueueMode(Ogre::SceneManager::SCRQM_EXCLUDE);
}
}
} }

View file

@ -5,11 +5,27 @@
#include "windowbase.hpp" #include "windowbase.hpp"
#include <components/loadinglistener/loadinglistener.hpp>
namespace MWGui namespace MWGui
{ {
class LoadingScreen : public WindowBase class LoadingScreen : public WindowBase, public Loading::Listener
{ {
public: public:
virtual void setLabel (const std::string& label);
/// Indicate that some progress has been made, without specifying how much
virtual void indicateProgress ();
virtual void loadingOn();
virtual void loadingOff();
virtual void setProgressRange (size_t range);
virtual void setProgress (size_t value);
virtual void increaseProgress (size_t increase);
virtual void removeWallpaper();
LoadingScreen(Ogre::SceneManager* sceneMgr, Ogre::RenderWindow* rw); LoadingScreen(Ogre::SceneManager* sceneMgr, Ogre::RenderWindow* rw);
virtual ~LoadingScreen(); virtual ~LoadingScreen();
@ -30,27 +46,20 @@ namespace MWGui
unsigned long mLastRenderTime; unsigned long mLastRenderTime;
Ogre::Timer mTimer; Ogre::Timer mTimer;
MyGUI::TextBox* mLoadingText; size_t mProgress;
MyGUI::ProgressBar* mProgressBar;
MyGUI::ImageBox* mBackgroundImage;
int mCurrentCellLoading; MyGUI::TextBox* mLoadingText;
int mTotalCellsLoading; MyGUI::ScrollBar* mProgressBar;
int mCurrentRefLoading; MyGUI::ImageBox* mBackgroundImage;
int mTotalRefsLoading;
int mCurrentRefList;
Ogre::Rectangle2D* mRectangle; Ogre::Rectangle2D* mRectangle;
Ogre::MaterialPtr mBackgroundMaterial; Ogre::MaterialPtr mBackgroundMaterial;
Ogre::StringVector mResources; Ogre::StringVector mResources;
bool mLoadingOn;
void loadingOn();
void loadingOff();
void changeWallpaper(); void changeWallpaper();
void draw();
}; };
} }

View file

@ -260,12 +260,10 @@ namespace MWGui
MapWindow::MapWindow(const std::string& cacheDir) MapWindow::MapWindow(const std::string& cacheDir)
: MWGui::WindowPinnableBase("openmw_map_window.layout") : MWGui::WindowPinnableBase("openmw_map_window.layout")
, mGlobal(false) , mGlobal(false)
, mGlobalMap(0)
{ {
setCoord(500,0,320,300); setCoord(500,0,320,300);
mGlobalMapRender = new MWRender::GlobalMap(cacheDir);
mGlobalMapRender->render();
getWidget(mLocalMap, "LocalMap"); getWidget(mLocalMap, "LocalMap");
getWidget(mGlobalMap, "GlobalMap"); getWidget(mGlobalMap, "GlobalMap");
getWidget(mGlobalMapImage, "GlobalMapImage"); getWidget(mGlobalMapImage, "GlobalMapImage");
@ -273,9 +271,6 @@ namespace MWGui
getWidget(mPlayerArrowLocal, "CompassLocal"); getWidget(mPlayerArrowLocal, "CompassLocal");
getWidget(mPlayerArrowGlobal, "CompassGlobal"); getWidget(mPlayerArrowGlobal, "CompassGlobal");
mGlobalMapImage->setImageTexture("GlobalMap.png");
mGlobalMapOverlay->setImageTexture("GlobalMapOverlay");
mGlobalMap->setVisible (false); mGlobalMap->setVisible (false);
getWidget(mButton, "WorldButton"); getWidget(mButton, "WorldButton");
@ -292,6 +287,14 @@ namespace MWGui
LocalMapBase::init(mLocalMap, mPlayerArrowLocal, this); LocalMapBase::init(mLocalMap, mPlayerArrowLocal, this);
} }
void MapWindow::renderGlobalMap(Loading::Listener* loadingListener)
{
mGlobalMapRender = new MWRender::GlobalMap("");
mGlobalMapRender->render(loadingListener);
mGlobalMapImage->setImageTexture("GlobalMap.png");
mGlobalMapOverlay->setImageTexture("GlobalMapOverlay");
}
MapWindow::~MapWindow() MapWindow::~MapWindow()
{ {
delete mGlobalMapRender; delete mGlobalMapRender;

View file

@ -8,6 +8,11 @@ namespace MWRender
class GlobalMap; class GlobalMap;
} }
namespace Loading
{
class Listener;
}
namespace MWGui namespace MWGui
{ {
class LocalMapBase class LocalMapBase
@ -71,6 +76,8 @@ namespace MWGui
void setCellName(const std::string& cellName); void setCellName(const std::string& cellName);
void renderGlobalMap(Loading::Listener* loadingListener);
void addVisitedLocation(const std::string& name, int x, int y); // adds the marker to the global map void addVisitedLocation(const std::string& name, int x, int y); // adds the marker to the global map
void cellExplored(int x, int y); void cellExplored(int x, int y);

View file

@ -62,6 +62,7 @@ namespace MWGui
const std::string& logpath, const std::string& cacheDir, bool consoleOnlyScripts, const std::string& logpath, const std::string& cacheDir, bool consoleOnlyScripts,
Translation::Storage& translationDataStorage, ToUTF8::FromType encoding) Translation::Storage& translationDataStorage, ToUTF8::FromType encoding)
: mGuiManager(NULL) : mGuiManager(NULL)
, mConsoleOnlyScripts(consoleOnlyScripts)
, mRendering(ogre) , mRendering(ogre)
, mHud(NULL) , mHud(NULL)
, mMap(NULL) , mMap(NULL)
@ -156,7 +157,28 @@ namespace MWGui
MyGUI::LanguageManager::getInstance().eventRequestTag = MyGUI::newDelegate(this, &WindowManager::onRetrieveTag); MyGUI::LanguageManager::getInstance().eventRequestTag = MyGUI::newDelegate(this, &WindowManager::onRetrieveTag);
// Get size info from the Gui object // Get size info from the Gui object
assert(mGui); int w = MyGUI::RenderManager::getInstance().getViewSize().width;
int h = MyGUI::RenderManager::getInstance().getViewSize().height;
mLoadingScreen = new LoadingScreen(mRendering->getScene (), mRendering->getWindow ());
mLoadingScreen->onResChange (w,h);
//set up the hardware cursor manager
mSoftwareCursor = new Cursor();
mCursorManager = new SFO::SDLCursorManager();
MyGUI::PointerManager::getInstance().eventChangeMousePointer += MyGUI::newDelegate(this, &WindowManager::onCursorChange);
MyGUI::InputManager::getInstance().eventChangeKeyFocus += MyGUI::newDelegate(this, &WindowManager::onKeyFocusChanged);
setUseHardwareCursors(mUseHardwareCursors);
onCursorChange(MyGUI::PointerManager::getInstance().getDefaultPointer());
mCursorManager->cursorVisibilityChange(false);
}
void WindowManager::initUI()
{
// Get size info from the Gui object
int w = MyGUI::RenderManager::getInstance().getViewSize().width; int w = MyGUI::RenderManager::getInstance().getViewSize().width;
int h = MyGUI::RenderManager::getInstance().getViewSize().height; int h = MyGUI::RenderManager::getInstance().getViewSize().height;
@ -169,9 +191,9 @@ namespace MWGui
mDragAndDrop->mDragAndDropWidget = dragAndDropWidget; mDragAndDrop->mDragAndDropWidget = dragAndDropWidget;
mMenu = new MainMenu(w,h); mMenu = new MainMenu(w,h);
mMap = new MapWindow(cacheDir); mMap = new MapWindow("");
mStatsWindow = new StatsWindow(); mStatsWindow = new StatsWindow();
mConsole = new Console(w,h, consoleOnlyScripts); mConsole = new Console(w,h, mConsoleOnlyScripts);
mJournal = JournalWindow::create(JournalViewModel::create ()); mJournal = JournalWindow::create(JournalViewModel::create ());
mMessageBoxManager = new MessageBoxManager(); mMessageBoxManager = new MessageBoxManager();
mInventoryWindow = new InventoryWindow(mDragAndDrop); mInventoryWindow = new InventoryWindow(mDragAndDrop);
@ -200,13 +222,8 @@ namespace MWGui
mSoulgemDialog = new SoulgemDialog(mMessageBoxManager); mSoulgemDialog = new SoulgemDialog(mMessageBoxManager);
mCompanionWindow = new CompanionWindow(mDragAndDrop, mMessageBoxManager); mCompanionWindow = new CompanionWindow(mDragAndDrop, mMessageBoxManager);
mLoadingScreen = new LoadingScreen(mRendering->getScene (), mRendering->getWindow ());
mLoadingScreen->onResChange (w,h);
mInputBlocker = mGui->createWidget<MyGUI::Widget>("",0,0,w,h,MyGUI::Align::Default,"Windows",""); mInputBlocker = mGui->createWidget<MyGUI::Widget>("",0,0,w,h,MyGUI::Align::Default,"Windows","");
mSoftwareCursor = new Cursor();
mHud->setVisible(mHudEnabled); mHud->setVisible(mHudEnabled);
mCharGen = new CharacterCreation(); mCharGen = new CharacterCreation();
@ -225,19 +242,15 @@ namespace MWGui
unsetSelectedSpell(); unsetSelectedSpell();
unsetSelectedWeapon(); unsetSelectedWeapon();
//set up the hardware cursor manager
mCursorManager = new SFO::SDLCursorManager();
MyGUI::PointerManager::getInstance().eventChangeMousePointer += MyGUI::newDelegate(this, &WindowManager::onCursorChange);
MyGUI::InputManager::getInstance().eventChangeKeyFocus += MyGUI::newDelegate(this, &WindowManager::onKeyFocusChanged);
setUseHardwareCursors(mUseHardwareCursors);
onCursorChange(MyGUI::PointerManager::getInstance().getDefaultPointer());
mCursorManager->cursorVisibilityChange(false);
// Set up visibility // Set up visibility
updateVisible(); updateVisible();
MWBase::Environment::get().getInputManager()->changeInputMode(false);
}
void WindowManager::renderWorldMap()
{
mMap->renderGlobalMap(mLoadingScreen);
} }
void WindowManager::setNewGame(bool newgame) void WindowManager::setNewGame(bool newgame)
@ -329,6 +342,8 @@ namespace MWGui
void WindowManager::updateVisible() void WindowManager::updateVisible()
{ {
if (!mMap)
return; // UI not created yet
// Start out by hiding everything except the HUD // Start out by hiding everything except the HUD
mMap->setVisible(false); mMap->setVisible(false);
mMenu->setVisible(false); mMenu->setVisible(false);
@ -914,6 +929,10 @@ namespace MWGui
void WindowManager::windowResized(int x, int y) void WindowManager::windowResized(int x, int y)
{ {
mGuiManager->windowResized();
mLoadingScreen->onResChange (x,y);
if (!mHud)
return; // UI not initialized yet
mHud->onResChange(x, y); mHud->onResChange(x, y);
mConsole->onResChange(x, y); mConsole->onResChange(x, y);
mMenu->onResChange(x, y); mMenu->onResChange(x, y);
@ -923,10 +942,8 @@ namespace MWGui
mBookWindow->center(); mBookWindow->center();
mQuickKeysMenu->center(); mQuickKeysMenu->center();
mSpellBuyingWindow->center(); mSpellBuyingWindow->center();
mLoadingScreen->onResChange (x,y);
mDragAndDrop->mDragAndDropWidget->setSize(MyGUI::IntSize(x, y)); mDragAndDrop->mDragAndDropWidget->setSize(MyGUI::IntSize(x, y));
mInputBlocker->setSize(MyGUI::IntSize(x,y)); mInputBlocker->setSize(MyGUI::IntSize(x,y));
mGuiManager->windowResized();
} }
void WindowManager::pushGuiMode(GuiMode mode) void WindowManager::pushGuiMode(GuiMode mode)
@ -1148,7 +1165,7 @@ namespace MWGui
bool WindowManager::isGuiMode() const bool WindowManager::isGuiMode() const
{ {
return !mGuiModes.empty() || mMessageBoxManager->isInteractiveMessageBox(); return !mGuiModes.empty() || (mMessageBoxManager && mMessageBoxManager->isInteractiveMessageBox());
} }
bool WindowManager::isConsoleMode() const bool WindowManager::isConsoleMode() const
@ -1211,6 +1228,7 @@ namespace MWGui
void WindowManager::showCrosshair (bool show) void WindowManager::showCrosshair (bool show)
{ {
if (mHud)
mHud->setCrosshairVisible (show && mCrosshairEnabled); mHud->setCrosshairVisible (show && mCrosshairEnabled);
} }
@ -1230,15 +1248,6 @@ namespace MWGui
mHud->setVisible (mHudEnabled); mHud->setVisible (mHudEnabled);
} }
void WindowManager::setLoadingProgress (const std::string& stage, int depth, int current, int total)
{
mLoadingScreen->setLoadingProgress (stage, depth, current, total);
}
void WindowManager::loadingDone ()
{
mLoadingScreen->loadingDone ();
}
bool WindowManager::getRestEnabled() bool WindowManager::getRestEnabled()
{ {
//Enable rest dialogue if character creation finished //Enable rest dialogue if character creation finished
@ -1345,4 +1354,9 @@ namespace MWGui
mHud->setEnemy(enemy); mHud->setEnemy(enemy);
} }
Loading::Listener* WindowManager::getLoadingScreen()
{
return mLoadingScreen;
}
} }

View file

@ -91,6 +91,11 @@ namespace MWGui
Translation::Storage& translationDataStorage, ToUTF8::FromType encoding); Translation::Storage& translationDataStorage, ToUTF8::FromType encoding);
virtual ~WindowManager(); virtual ~WindowManager();
void initUI();
void renderWorldMap();
virtual Loading::Listener* getLoadingScreen();
/** /**
* Should be called each frame to update windows/gui elements. * Should be called each frame to update windows/gui elements.
* This could mean updating sizes of gui elements or opening * This could mean updating sizes of gui elements or opening
@ -241,9 +246,6 @@ namespace MWGui
virtual void executeInConsole (const std::string& path); virtual void executeInConsole (const std::string& path);
virtual void setLoadingProgress (const std::string& stage, int depth, int current, int total);
virtual void loadingDone();
virtual void enableRest() { mRestAllowed = true; } virtual void enableRest() { mRestAllowed = true; }
virtual bool getRestEnabled(); virtual bool getRestEnabled();
@ -275,6 +277,8 @@ namespace MWGui
void onSoulgemDialogButtonPressed (int button); void onSoulgemDialogButtonPressed (int button);
private: private:
bool mConsoleOnlyScripts;
OEngine::GUI::MyGUIManager *mGuiManager; OEngine::GUI::MyGUIManager *mGuiManager;
OEngine::Render::OgreRenderer *mRendering; OEngine::Render::OgreRenderer *mRendering;
HUD *mHud; HUD *mHud;

View file

@ -86,13 +86,10 @@ namespace
namespace MWInput namespace MWInput
{ {
InputManager::InputManager(OEngine::Render::OgreRenderer &ogre, InputManager::InputManager(OEngine::Render::OgreRenderer &ogre,
MWWorld::Player& player,
MWBase::WindowManager &windows,
OMW::Engine& engine, OMW::Engine& engine,
const std::string& userFile, bool userFileExists) const std::string& userFile, bool userFileExists)
: mOgre(ogre) : mOgre(ogre)
, mPlayer(player) , mPlayer(NULL)
, mWindows(windows)
, mEngine(engine) , mEngine(engine)
, mMouseLookEnabled(true) , mMouseLookEnabled(true)
, mMouseX(ogre.getWindow()->getWidth ()/2.f) , mMouseX(ogre.getWindow()->getWidth ()/2.f)
@ -124,8 +121,6 @@ namespace MWInput
adjustMouseRegion (window->getWidth(), window->getHeight()); adjustMouseRegion (window->getWidth(), window->getHeight());
MyGUI::InputManager::getInstance().injectMouseMove(mMouseX, mMouseY, 0);
loadKeyDefaults(); loadKeyDefaults();
for (int i = 0; i < A_Last; ++i) for (int i = 0; i < A_Last; ++i)
@ -140,8 +135,6 @@ namespace MWInput
mControlSwitch["playermagic"] = true; mControlSwitch["playermagic"] = true;
mControlSwitch["playerviewswitch"] = true; mControlSwitch["playerviewswitch"] = true;
mControlSwitch["vanitymode"] = true; mControlSwitch["vanitymode"] = true;
changeInputMode(false);
} }
InputManager::~InputManager() InputManager::~InputManager()
@ -164,7 +157,7 @@ namespace MWInput
if (action == A_Use) if (action == A_Use)
{ {
MWWorld::Class::get(mPlayer.getPlayer()).getCreatureStats(mPlayer.getPlayer()).setAttackingOrSpell(currentValue); MWWorld::Class::get(mPlayer->getPlayer()).getCreatureStats(mPlayer->getPlayer()).setAttackingOrSpell(currentValue);
if (currentValue == 1) if (currentValue == 1)
{ {
int type = MWMechanics::CreatureStats::AT_Chop; int type = MWMechanics::CreatureStats::AT_Chop;
@ -177,7 +170,7 @@ namespace MWInput
if (forward && !side) if (forward && !side)
type = MWMechanics::CreatureStats::AT_Thrust; type = MWMechanics::CreatureStats::AT_Thrust;
MWWorld::Class::get(mPlayer.getPlayer()).getCreatureStats(mPlayer.getPlayer()).setAttackType(type); MWWorld::Class::get(mPlayer->getPlayer()).getCreatureStats(mPlayer->getPlayer()).setAttackType(type);
} }
} }
@ -204,9 +197,9 @@ namespace MWInput
case A_Activate: case A_Activate:
resetIdleTime(); resetIdleTime();
if (mWindows.isGuiMode()) if (MWBase::Environment::get().getWindowManager()->isGuiMode())
{ {
if (mWindows.getMode() == MWGui::GM_Container) if (MWBase::Environment::get().getWindowManager()->getMode() == MWGui::GM_Container)
toggleContainer (); toggleContainer ();
else else
MWBase::Environment::get().getWindowManager()->activateKeyPressed(); MWBase::Environment::get().getWindowManager()->activateKeyPressed();
@ -266,7 +259,7 @@ namespace MWInput
showQuickKeysMenu(); showQuickKeysMenu();
break; break;
case A_ToggleHUD: case A_ToggleHUD:
mWindows.toggleHud(); MWBase::Environment::get().getWindowManager()->toggleHud();
break; break;
} }
} }
@ -274,8 +267,7 @@ namespace MWInput
void InputManager::update(float dt, bool loading) void InputManager::update(float dt, bool loading)
{ {
// Tell OIS to handle all input events mInputManager->capture(loading);
mInputManager->capture();
// inject some fake mouse movement to force updating MyGUI's widget states // inject some fake mouse movement to force updating MyGUI's widget states
// this shouldn't do any harm since we're moving back to the original position afterwards // this shouldn't do any harm since we're moving back to the original position afterwards
MyGUI::InputManager::getInstance().injectMouseMove( int(mMouseX+1), int(mMouseY+1), mMouseWheel); MyGUI::InputManager::getInstance().injectMouseMove( int(mMouseX+1), int(mMouseY+1), mMouseWheel);
@ -285,18 +277,10 @@ namespace MWInput
if (!loading) if (!loading)
mInputBinder->update(dt); mInputBinder->update(dt);
// Update windows/gui as a result of input events bool main_menu = MWBase::Environment::get().getWindowManager()->containsMode(MWGui::GM_MainMenu);
// For instance this could mean opening a new window/dialog,
// by doing this after the input events are handled we
// ensure that window/gui changes appear quickly while
// avoiding that window/gui changes does not happen in
// event callbacks (which may crash)
mWindows.update();
bool main_menu = mWindows.containsMode(MWGui::GM_MainMenu);
bool was_relative = mInputManager->getMouseRelative(); bool was_relative = mInputManager->getMouseRelative();
bool is_relative = !mWindows.isGuiMode(); bool is_relative = !MWBase::Environment::get().getWindowManager()->isGuiMode();
// don't keep the pointer away from the window edge in gui mode // don't keep the pointer away from the window edge in gui mode
// stop using raw mouse motions and switch to system cursor movements // stop using raw mouse motions and switch to system cursor movements
@ -312,8 +296,11 @@ namespace MWInput
mInputManager->warpMouse(mMouseX, mMouseY); mInputManager->warpMouse(mMouseX, mMouseY);
} }
if (loading)
return;
// Disable movement in Gui mode // Disable movement in Gui mode
if (mWindows.isGuiMode()) return; if (MWBase::Environment::get().getWindowManager()->isGuiMode()) return;
// Configure player movement according to keyboard input. Actual movement will // Configure player movement according to keyboard input. Actual movement will
@ -324,45 +311,45 @@ namespace MWInput
if (actionIsActive(A_MoveLeft)) if (actionIsActive(A_MoveLeft))
{ {
triedToMove = true; triedToMove = true;
mPlayer.setLeftRight (-1); mPlayer->setLeftRight (-1);
} }
else if (actionIsActive(A_MoveRight)) else if (actionIsActive(A_MoveRight))
{ {
triedToMove = true; triedToMove = true;
mPlayer.setLeftRight (1); mPlayer->setLeftRight (1);
} }
if (actionIsActive(A_MoveForward)) if (actionIsActive(A_MoveForward))
{ {
triedToMove = true; triedToMove = true;
mPlayer.setAutoMove (false); mPlayer->setAutoMove (false);
mPlayer.setForwardBackward (1); mPlayer->setForwardBackward (1);
} }
else if (actionIsActive(A_MoveBackward)) else if (actionIsActive(A_MoveBackward))
{ {
triedToMove = true; triedToMove = true;
mPlayer.setAutoMove (false); mPlayer->setAutoMove (false);
mPlayer.setForwardBackward (-1); mPlayer->setForwardBackward (-1);
} }
else if(mPlayer.getAutoMove()) else if(mPlayer->getAutoMove())
{ {
triedToMove = true; triedToMove = true;
mPlayer.setForwardBackward (1); mPlayer->setForwardBackward (1);
} }
mPlayer.setSneak(actionIsActive(A_Sneak)); mPlayer->setSneak(actionIsActive(A_Sneak));
if (actionIsActive(A_Jump) && mControlSwitch["playerjumping"]) if (actionIsActive(A_Jump) && mControlSwitch["playerjumping"])
{ {
mPlayer.setUpDown (1); mPlayer->setUpDown (1);
triedToMove = true; triedToMove = true;
} }
if (mAlwaysRunActive) if (mAlwaysRunActive)
mPlayer.setRunState(!actionIsActive(A_Run)); mPlayer->setRunState(!actionIsActive(A_Run));
else else
mPlayer.setRunState(actionIsActive(A_Run)); mPlayer->setRunState(actionIsActive(A_Run));
// if player tried to start moving, but can't (due to being overencumbered), display a notification. // if player tried to start moving, but can't (due to being overencumbered), display a notification.
if (triedToMove) if (triedToMove)
@ -371,7 +358,7 @@ namespace MWInput
mOverencumberedMessageDelay -= dt; mOverencumberedMessageDelay -= dt;
if (MWWorld::Class::get(player).getEncumbrance(player) >= MWWorld::Class::get(player).getCapacity(player)) if (MWWorld::Class::get(player).getEncumbrance(player) >= MWWorld::Class::get(player).getCapacity(player))
{ {
mPlayer.setAutoMove (false); mPlayer->setAutoMove (false);
if (mOverencumberedMessageDelay <= 0) if (mOverencumberedMessageDelay <= 0)
{ {
MWBase::Environment::get().getWindowManager ()->messageBox("#{sNotifyMessage59}"); MWBase::Environment::get().getWindowManager ()->messageBox("#{sNotifyMessage59}");
@ -425,8 +412,8 @@ namespace MWInput
mGuiCursorEnabled = guiMode; mGuiCursorEnabled = guiMode;
mMouseLookEnabled = !guiMode; mMouseLookEnabled = !guiMode;
if (guiMode) if (guiMode)
mWindows.showCrosshair(false); MWBase::Environment::get().getWindowManager()->showCrosshair(false);
mWindows.setCursorVisible(guiMode); MWBase::Environment::get().getWindowManager()->setCursorVisible(guiMode);
// if not in gui mode, the camera decides whether to show crosshair or not. // if not in gui mode, the camera decides whether to show crosshair or not.
} }
@ -459,13 +446,13 @@ namespace MWInput
} }
/// \note 7 switches at all, if-else is relevant /// \note 7 switches at all, if-else is relevant
if (sw == "playercontrols" && !value) { if (sw == "playercontrols" && !value) {
mPlayer.setLeftRight(0); mPlayer->setLeftRight(0);
mPlayer.setForwardBackward(0); mPlayer->setForwardBackward(0);
mPlayer.setAutoMove(false); mPlayer->setAutoMove(false);
mPlayer.setUpDown(0); mPlayer->setUpDown(0);
} else if (sw == "playerjumping" && !value) { } else if (sw == "playerjumping" && !value) {
/// \fixme maybe crouching at this time /// \fixme maybe crouching at this time
mPlayer.setUpDown(0); mPlayer->setUpDown(0);
} else if (sw == "vanitymode") { } else if (sw == "vanitymode") {
MWBase::Environment::get().getWorld()->allowVanityMode(value); MWBase::Environment::get().getWorld()->allowVanityMode(value);
} else if (sw == "playerlooking") { } else if (sw == "playerlooking") {
@ -594,8 +581,8 @@ namespace MWInput
// Only actually turn player when we're not in vanity mode // Only actually turn player when we're not in vanity mode
if(!MWBase::Environment::get().getWorld()->vanityRotateCamera(rot)) if(!MWBase::Environment::get().getWorld()->vanityRotateCamera(rot))
{ {
mPlayer.yaw(x/scale); mPlayer->yaw(x/scale);
mPlayer.pitch(-y/scale); mPlayer->pitch(-y/scale);
} }
if (arg.zrel) if (arg.zrel)
@ -627,51 +614,51 @@ namespace MWInput
if (MyGUI::InputManager::getInstance ().isModalAny()) if (MyGUI::InputManager::getInstance ().isModalAny())
return; return;
if (mWindows.isGuiMode () && mWindows.getMode () == MWGui::GM_Video) if (MWBase::Environment::get().getWindowManager()->isGuiMode () && MWBase::Environment::get().getWindowManager()->getMode () == MWGui::GM_Video)
MWBase::Environment::get().getWorld ()->stopVideo (); MWBase::Environment::get().getWorld ()->stopVideo ();
else if (mWindows.containsMode(MWGui::GM_MainMenu)) else if (MWBase::Environment::get().getWindowManager()->containsMode(MWGui::GM_MainMenu))
mWindows.popGuiMode(); MWBase::Environment::get().getWindowManager()->popGuiMode();
else else
mWindows.pushGuiMode (MWGui::GM_MainMenu); MWBase::Environment::get().getWindowManager()->pushGuiMode (MWGui::GM_MainMenu);
} }
void InputManager::toggleSpell() void InputManager::toggleSpell()
{ {
if (mWindows.isGuiMode()) return; if (MWBase::Environment::get().getWindowManager()->isGuiMode()) return;
// Not allowed before the magic window is accessible // Not allowed before the magic window is accessible
if (!mWindows.isAllowed(MWGui::GW_Magic)) if (!MWBase::Environment::get().getWindowManager()->isAllowed(MWGui::GW_Magic))
return; return;
MWMechanics::DrawState_ state = mPlayer.getDrawState(); MWMechanics::DrawState_ state = mPlayer->getDrawState();
if (state == MWMechanics::DrawState_Weapon || state == MWMechanics::DrawState_Nothing) if (state == MWMechanics::DrawState_Weapon || state == MWMechanics::DrawState_Nothing)
mPlayer.setDrawState(MWMechanics::DrawState_Spell); mPlayer->setDrawState(MWMechanics::DrawState_Spell);
else else
mPlayer.setDrawState(MWMechanics::DrawState_Nothing); mPlayer->setDrawState(MWMechanics::DrawState_Nothing);
} }
void InputManager::toggleWeapon() void InputManager::toggleWeapon()
{ {
if (mWindows.isGuiMode()) return; if (MWBase::Environment::get().getWindowManager()->isGuiMode()) return;
// Not allowed before the inventory window is accessible // Not allowed before the inventory window is accessible
if (!mWindows.isAllowed(MWGui::GW_Inventory)) if (!MWBase::Environment::get().getWindowManager()->isAllowed(MWGui::GW_Inventory))
return; return;
MWMechanics::DrawState_ state = mPlayer.getDrawState(); MWMechanics::DrawState_ state = mPlayer->getDrawState();
if (state == MWMechanics::DrawState_Spell || state == MWMechanics::DrawState_Nothing) if (state == MWMechanics::DrawState_Spell || state == MWMechanics::DrawState_Nothing)
mPlayer.setDrawState(MWMechanics::DrawState_Weapon); mPlayer->setDrawState(MWMechanics::DrawState_Weapon);
else else
mPlayer.setDrawState(MWMechanics::DrawState_Nothing); mPlayer->setDrawState(MWMechanics::DrawState_Nothing);
} }
void InputManager::rest() void InputManager::rest()
{ {
if (!mWindows.getRestEnabled () || mWindows.isGuiMode ()) if (!MWBase::Environment::get().getWindowManager()->getRestEnabled () || MWBase::Environment::get().getWindowManager()->isGuiMode ())
return; return;
/// \todo check if resting is currently allowed (enemies nearby?) /// \todo check if resting is currently allowed (enemies nearby?)
mWindows.pushGuiMode (MWGui::GM_Rest); MWBase::Environment::get().getWindowManager()->pushGuiMode (MWGui::GM_Rest);
} }
void InputManager::screenshot() void InputManager::screenshot()
@ -679,7 +666,7 @@ namespace MWInput
mEngine.screenshot(); mEngine.screenshot();
std::vector<std::string> empty; std::vector<std::string> empty;
mWindows.messageBox ("Screenshot saved", empty); MWBase::Environment::get().getWindowManager()->messageBox ("Screenshot saved", empty);
} }
void InputManager::toggleInventory() void InputManager::toggleInventory()
@ -688,13 +675,13 @@ namespace MWInput
return; return;
// Toggle between game mode and inventory mode // Toggle between game mode and inventory mode
if(!mWindows.isGuiMode()) if(!MWBase::Environment::get().getWindowManager()->isGuiMode())
mWindows.pushGuiMode(MWGui::GM_Inventory); MWBase::Environment::get().getWindowManager()->pushGuiMode(MWGui::GM_Inventory);
else else
{ {
MWGui::GuiMode mode = mWindows.getMode(); MWGui::GuiMode mode = MWBase::Environment::get().getWindowManager()->getMode();
if(mode == MWGui::GM_Inventory || mode == MWGui::GM_Container) if(mode == MWGui::GM_Inventory || mode == MWGui::GM_Container)
mWindows.popGuiMode(); MWBase::Environment::get().getWindowManager()->popGuiMode();
} }
// .. but don't touch any other mode, except container. // .. but don't touch any other mode, except container.
@ -705,12 +692,12 @@ namespace MWInput
if (MyGUI::InputManager::getInstance ().isModalAny()) if (MyGUI::InputManager::getInstance ().isModalAny())
return; return;
if(mWindows.isGuiMode()) if(MWBase::Environment::get().getWindowManager()->isGuiMode())
{ {
if (mWindows.getMode() == MWGui::GM_Container) if (MWBase::Environment::get().getWindowManager()->getMode() == MWGui::GM_Container)
mWindows.popGuiMode(); MWBase::Environment::get().getWindowManager()->popGuiMode();
else else
mWindows.pushGuiMode(MWGui::GM_Container); MWBase::Environment::get().getWindowManager()->pushGuiMode(MWGui::GM_Container);
} }
} }
@ -722,15 +709,15 @@ namespace MWInput
// Switch to console mode no matter what mode we are currently // Switch to console mode no matter what mode we are currently
// in, except of course if we are already in console mode // in, except of course if we are already in console mode
if (mWindows.isGuiMode()) if (MWBase::Environment::get().getWindowManager()->isGuiMode())
{ {
if (mWindows.getMode() == MWGui::GM_Console) if (MWBase::Environment::get().getWindowManager()->getMode() == MWGui::GM_Console)
mWindows.popGuiMode(); MWBase::Environment::get().getWindowManager()->popGuiMode();
else else
mWindows.pushGuiMode(MWGui::GM_Console); MWBase::Environment::get().getWindowManager()->pushGuiMode(MWGui::GM_Console);
} }
else else
mWindows.pushGuiMode(MWGui::GM_Console); MWBase::Environment::get().getWindowManager()->pushGuiMode(MWGui::GM_Console);
} }
void InputManager::toggleJournal() void InputManager::toggleJournal()
@ -739,31 +726,31 @@ namespace MWInput
return; return;
// Toggle between game mode and journal mode // Toggle between game mode and journal mode
if(!mWindows.isGuiMode() && MWBase::Environment::get().getWindowManager ()->getJournalAllowed()) if(!MWBase::Environment::get().getWindowManager()->isGuiMode() && MWBase::Environment::get().getWindowManager ()->getJournalAllowed())
{ {
MWBase::Environment::get().getSoundManager()->playSound ("book open", 1.0, 1.0); MWBase::Environment::get().getSoundManager()->playSound ("book open", 1.0, 1.0);
mWindows.pushGuiMode(MWGui::GM_Journal); MWBase::Environment::get().getWindowManager()->pushGuiMode(MWGui::GM_Journal);
} }
else if(mWindows.getMode() == MWGui::GM_Journal) else if(MWBase::Environment::get().getWindowManager()->getMode() == MWGui::GM_Journal)
{ {
MWBase::Environment::get().getSoundManager()->playSound ("book close", 1.0, 1.0); MWBase::Environment::get().getSoundManager()->playSound ("book close", 1.0, 1.0);
mWindows.popGuiMode(); MWBase::Environment::get().getWindowManager()->popGuiMode();
} }
// .. but don't touch any other mode. // .. but don't touch any other mode.
} }
void InputManager::quickKey (int index) void InputManager::quickKey (int index)
{ {
if (!mWindows.isGuiMode()) if (!MWBase::Environment::get().getWindowManager()->isGuiMode())
mWindows.activateQuickKey (index); MWBase::Environment::get().getWindowManager()->activateQuickKey (index);
} }
void InputManager::showQuickKeysMenu() void InputManager::showQuickKeysMenu()
{ {
if (!mWindows.isGuiMode ()) if (!MWBase::Environment::get().getWindowManager()->isGuiMode ())
mWindows.pushGuiMode (MWGui::GM_QuickKeysMenu); MWBase::Environment::get().getWindowManager()->pushGuiMode (MWGui::GM_QuickKeysMenu);
else if (mWindows.getMode () == MWGui::GM_QuickKeysMenu) else if (MWBase::Environment::get().getWindowManager()->getMode () == MWGui::GM_QuickKeysMenu)
mWindows.removeGuiMode (MWGui::GM_QuickKeysMenu); MWBase::Environment::get().getWindowManager()->removeGuiMode (MWGui::GM_QuickKeysMenu);
} }
void InputManager::activate() void InputManager::activate()
@ -774,22 +761,22 @@ namespace MWInput
void InputManager::toggleAutoMove() void InputManager::toggleAutoMove()
{ {
if (mWindows.isGuiMode()) return; if (MWBase::Environment::get().getWindowManager()->isGuiMode()) return;
if (mControlSwitch["playercontrols"]) if (mControlSwitch["playercontrols"])
mPlayer.setAutoMove (!mPlayer.getAutoMove()); mPlayer->setAutoMove (!mPlayer->getAutoMove());
} }
void InputManager::toggleWalking() void InputManager::toggleWalking()
{ {
if (mWindows.isGuiMode()) return; if (MWBase::Environment::get().getWindowManager()->isGuiMode()) return;
mAlwaysRunActive = !mAlwaysRunActive; mAlwaysRunActive = !mAlwaysRunActive;
} }
// Exit program now button (which is disabled in GUI mode) // Exit program now button (which is disabled in GUI mode)
void InputManager::exitNow() void InputManager::exitNow()
{ {
if(!mWindows.isGuiMode()) if(!MWBase::Environment::get().getWindowManager()->isGuiMode())
Ogre::Root::getSingleton().queueEndRendering (); Ogre::Root::getSingleton().queueEndRendering ();
} }

View file

@ -60,8 +60,6 @@ namespace MWInput
{ {
public: public:
InputManager(OEngine::Render::OgreRenderer &_ogre, InputManager(OEngine::Render::OgreRenderer &_ogre,
MWWorld::Player&_player,
MWBase::WindowManager &_windows,
OMW::Engine& engine, OMW::Engine& engine,
const std::string& userFile, bool userFileExists); const std::string& userFile, bool userFileExists);
@ -69,6 +67,8 @@ namespace MWInput
virtual void update(float dt, bool loading); virtual void update(float dt, bool loading);
void setPlayer (MWWorld::Player* player) { mPlayer = player; }
virtual void changeInputMode(bool guiMode); virtual void changeInputMode(bool guiMode);
virtual void processChangedSettings(const Settings::CategorySettingVector& changed); virtual void processChangedSettings(const Settings::CategorySettingVector& changed);
@ -125,8 +125,7 @@ namespace MWInput
private: private:
OEngine::Render::OgreRenderer &mOgre; OEngine::Render::OgreRenderer &mOgre;
MWWorld::Player& mPlayer; MWWorld::Player* mPlayer;
MWBase::WindowManager &mWindows;
OMW::Engine& mEngine; OMW::Engine& mEngine;
ICS::InputControlSystem* mInputBinder; ICS::InputControlSystem* mInputBinder;

View file

@ -11,10 +11,12 @@
#include "../mwworld/class.hpp" #include "../mwworld/class.hpp"
#include "../mwworld/inventorystore.hpp" #include "../mwworld/inventorystore.hpp"
#include "../mwworld/player.hpp"
#include "../mwbase/world.hpp" #include "../mwbase/world.hpp"
#include "../mwbase/environment.hpp" #include "../mwbase/environment.hpp"
#include "../mwbase/windowmanager.hpp" #include "../mwbase/windowmanager.hpp"
#include "../mwbase/soundmanager.hpp"
#include "npcstats.hpp" #include "npcstats.hpp"
#include "creaturestats.hpp" #include "creaturestats.hpp"
@ -68,22 +70,24 @@ namespace MWMechanics
{ {
CreatureStats& creatureStats = MWWorld::Class::get (ptr).getCreatureStats (ptr); CreatureStats& creatureStats = MWWorld::Class::get (ptr).getCreatureStats (ptr);
int strength = creatureStats.getAttribute(0).getBase(); int strength = creatureStats.getAttribute(ESM::Attribute::Strength).getBase();
int intelligence = creatureStats.getAttribute(1).getBase(); int intelligence = creatureStats.getAttribute(ESM::Attribute::Intelligence).getBase();
int willpower = creatureStats.getAttribute(2).getBase(); int willpower = creatureStats.getAttribute(ESM::Attribute::Willpower).getBase();
int agility = creatureStats.getAttribute(3).getBase(); int agility = creatureStats.getAttribute(ESM::Attribute::Agility).getBase();
int endurance = creatureStats.getAttribute(5).getBase(); int endurance = creatureStats.getAttribute(ESM::Attribute::Endurance).getBase();
double magickaFactor = double magickaFactor =
creatureStats.getMagicEffects().get (EffectKey (ESM::MagicEffect::FortifyMaximumMagicka)).mMagnitude * 0.1 + 0.5; creatureStats.getMagicEffects().get (EffectKey (ESM::MagicEffect::FortifyMaximumMagicka)).mMagnitude * 0.1 + 0.5;
DynamicStat<float> magicka = creatureStats.getMagicka(); DynamicStat<float> magicka = creatureStats.getMagicka();
magicka.setBase (static_cast<int> (intelligence + magickaFactor * intelligence)); float diff = (static_cast<int>(intelligence + magickaFactor*intelligence)) - magicka.getBase();
creatureStats.setMagicka (magicka); magicka.modify(diff);
creatureStats.setMagicka(magicka);
DynamicStat<float> fatigue = creatureStats.getFatigue(); DynamicStat<float> fatigue = creatureStats.getFatigue();
fatigue.setBase (strength+willpower+agility+endurance); diff = (strength+willpower+agility+endurance) - fatigue.getBase();
creatureStats.setFatigue (fatigue); fatigue.modify(diff);
creatureStats.setFatigue(fatigue);
} }
void Actors::calculateRestoration (const MWWorld::Ptr& ptr, float duration) void Actors::calculateRestoration (const MWWorld::Ptr& ptr, float duration)
@ -133,63 +137,64 @@ namespace MWMechanics
void Actors::calculateCreatureStatModifiers (const MWWorld::Ptr& ptr) void Actors::calculateCreatureStatModifiers (const MWWorld::Ptr& ptr)
{ {
CreatureStats& creatureStats = MWWorld::Class::get (ptr).getCreatureStats (ptr); CreatureStats &creatureStats = MWWorld::Class::get(ptr).getCreatureStats(ptr);
const MagicEffects &effects = creatureStats.getMagicEffects();
// attributes // attributes
for (int i=0; i<8; ++i) for(int i = 0;i < ESM::Attribute::Length;++i)
{ {
int modifier = Stat<int> stat = creatureStats.getAttribute(i);
creatureStats.getMagicEffects().get (EffectKey (ESM::MagicEffect::FortifyAttribute, i)).mMagnitude; stat.setModifier(effects.get(EffectKey(ESM::MagicEffect::FortifyAttribute, i)).mMagnitude -
effects.get(EffectKey(ESM::MagicEffect::DrainAttribute, i)).mMagnitude);
modifier -= creatureStats.getMagicEffects().get (EffectKey (ESM::MagicEffect::DrainAttribute, i)).mMagnitude; creatureStats.setAttribute(i, stat);
creatureStats.getAttribute(i).setModifier (modifier);
} }
// dynamic stats // dynamic stats
MagicEffects effects = creatureStats.getMagicEffects(); for(int i = 0;i < 3;++i)
for (int i=0; i<3; ++i)
{ {
DynamicStat<float> stat = creatureStats.getDynamic (i); DynamicStat<float> stat = creatureStats.getDynamic(i);
stat.setModifier(effects.get(EffectKey(80+i)).mMagnitude -
effects.get(EffectKey(18+i)).mMagnitude);
stat.setModifier ( creatureStats.setDynamic(i, stat);
effects.get (EffectKey(80+i)).mMagnitude - effects.get (EffectKey(18+i)).mMagnitude);
creatureStats.setDynamic (i, stat);
} }
} }
void Actors::updateDrowning(const MWWorld::Ptr& ptr, float duration) void Actors::updateDrowning(const MWWorld::Ptr& ptr, float duration)
{ {
NpcStats &stats = MWWorld::Class::get(ptr).getNpcStats(ptr); MWBase::World *world = MWBase::Environment::get().getWorld();
if(MWBase::Environment::get().getWorld()->isSubmerged(ptr) && NpcStats &stats = ptr.getClass().getNpcStats(ptr);
if(world->isSubmerged(ptr) &&
stats.getMagicEffects().get(ESM::MagicEffect::WaterBreathing).mMagnitude == 0) stats.getMagicEffects().get(ESM::MagicEffect::WaterBreathing).mMagnitude == 0)
{ {
float timeLeft = 0.0f;
if(stats.getFatigue().getCurrent() == 0) if(stats.getFatigue().getCurrent() == 0)
stats.setTimeToStartDrowning(0); stats.setTimeToStartDrowning(0);
float timeLeft = stats.getTimeToStartDrowning()-duration;
if(timeLeft < 0.0f)
timeLeft = 0.0f;
stats.setTimeToStartDrowning(timeLeft);
if(timeLeft == 0.0f)
stats.setLastDrowningHitTime(stats.getLastDrowningHitTime()+duration);
}
else else
{ {
stats.setTimeToStartDrowning(20); timeLeft = stats.getTimeToStartDrowning() - duration;
stats.setLastDrowningHitTime(0); if(timeLeft < 0.0f)
timeLeft = 0.0f;
stats.setTimeToStartDrowning(timeLeft);
} }
//if npc is drowning and it's time to hit, then hit if(timeLeft == 0.0f)
while(stats.getTimeToStartDrowning() == 0.0f && stats.getLastDrowningHitTime() > 0.33f)
{ {
stats.setLastDrowningHitTime(stats.getLastDrowningHitTime()-0.33f); // If drowning, apply 3 points of damage per second
//fixme: replace it with something different once screen hit effects are implemented (blood on screen) ptr.getClass().setActorHealth(ptr, stats.getHealth().getCurrent() - 3.0f*duration);
MWWorld::Class::get(ptr).setActorHealth(ptr, stats.getHealth().getCurrent()-1.0f);
// Play a drowning sound as necessary for the player
if(ptr == world->getPlayer().getPlayer())
{
MWBase::SoundManager *sndmgr = MWBase::Environment::get().getSoundManager();
if(!sndmgr->getSoundPlaying(MWWorld::Ptr(), "drown"))
sndmgr->playSound("drown", 1.0f, 1.0f);
} }
} }
}
else
stats.setTimeToStartDrowning(20);
}
Actors::Actors() : mDuration (0) {} Actors::Actors() : mDuration (0) {}

View file

@ -33,46 +33,48 @@ namespace MWMechanics
bool AiTravel::execute (const MWWorld::Ptr& actor) bool AiTravel::execute (const MWWorld::Ptr& actor)
{ {
MWWorld::Ptr player = MWBase::Environment::get().getWorld()->getPlayer().getPlayer(); MWBase::World *world = MWBase::Environment::get().getWorld();
ESM::Position pos = actor.getRefData().getPosition(); ESM::Position pos = actor.getRefData().getPosition();
bool cellChange = actor.getCell()->mCell->mData.mX != cellX || actor.getCell()->mCell->mData.mY != cellY; Movement &movement = actor.getClass().getMovementSettings(actor);
const ESM::Pathgrid *pathgrid = const ESM::Cell *cell = actor.getCell()->mCell;
MWBase::Environment::get().getWorld()->getStore().get<ESM::Pathgrid>().search(*actor.getCell()->mCell);
if(actor.getCell()->mCell->mData.mX != player.getCell()->mCell->mData.mX) MWWorld::Ptr player = world->getPlayer().getPlayer();
if(cell->mData.mX != player.getCell()->mCell->mData.mX)
{ {
int sideX = sgn(actor.getCell()->mCell->mData.mX - player.getCell()->mCell->mData.mX); int sideX = sgn(cell->mData.mX - player.getCell()->mCell->mData.mX);
//check if actor is near the border of an inactive cell. If so, disable aitravel. //check if actor is near the border of an inactive cell. If so, stop walking.
if(sideX * (pos.pos[0] - actor.getCell()->mCell->mData.mX * ESM::Land::REAL_SIZE) > sideX * (ESM::Land::REAL_SIZE / if(sideX * (pos.pos[0] - cell->mData.mX*ESM::Land::REAL_SIZE) >
2.0 - 200)) sideX * (ESM::Land::REAL_SIZE/2.0f - 200.0f))
{ {
MWWorld::Class::get(actor).getMovementSettings(actor).mPosition[1] = 0; movement.mPosition[1] = 0;
return true; return false;
} }
} }
if(actor.getCell()->mCell->mData.mY != player.getCell()->mCell->mData.mY) if(cell->mData.mY != player.getCell()->mCell->mData.mY)
{ {
int sideY = sgn(actor.getCell()->mCell->mData.mY - player.getCell()->mCell->mData.mY); int sideY = sgn(cell->mData.mY - player.getCell()->mCell->mData.mY);
//check if actor is near the border of an inactive cell. If so, disable aitravel. //check if actor is near the border of an inactive cell. If so, stop walking.
if(sideY * (pos.pos[1] - actor.getCell()->mCell->mData.mY * ESM::Land::REAL_SIZE) > sideY * (ESM::Land::REAL_SIZE / if(sideY * (pos.pos[1] - cell->mData.mY*ESM::Land::REAL_SIZE) >
2.0 - 200)) sideY * (ESM::Land::REAL_SIZE/2.0f - 200.0f))
{ {
MWWorld::Class::get(actor).getMovementSettings(actor).mPosition[1] = 0; movement.mPosition[1] = 0;
return true; return false;
} }
} }
const ESM::Pathgrid *pathgrid = world->getStore().get<ESM::Pathgrid>().search(*cell);
bool cellChange = cell->mData.mX != cellX || cell->mData.mY != cellY;
if(!mPathFinder.isPathConstructed() || cellChange) if(!mPathFinder.isPathConstructed() || cellChange)
{ {
cellX = actor.getCell()->mCell->mData.mX; cellX = cell->mData.mX;
cellY = actor.getCell()->mCell->mData.mY; cellY = cell->mData.mY;
float xCell = 0; float xCell = 0;
float yCell = 0; float yCell = 0;
if (actor.getCell()->mCell->isExterior()) if(cell->isExterior())
{ {
xCell = actor.getCell()->mCell->mData.mX * ESM::Land::REAL_SIZE; xCell = cell->mData.mX * ESM::Land::REAL_SIZE;
yCell = actor.getCell()->mCell->mData.mY * ESM::Land::REAL_SIZE; yCell = cell->mData.mY * ESM::Land::REAL_SIZE;
} }
ESM::Pathgrid::Point dest; ESM::Pathgrid::Point dest;
@ -90,13 +92,13 @@ namespace MWMechanics
if(mPathFinder.checkPathCompleted(pos.pos[0], pos.pos[1], pos.pos[2])) if(mPathFinder.checkPathCompleted(pos.pos[0], pos.pos[1], pos.pos[2]))
{ {
MWWorld::Class::get(actor).getMovementSettings(actor).mPosition[1] = 0; movement.mPosition[1] = 0;
return true; return true;
} }
float zAngle = mPathFinder.getZAngleToNext(pos.pos[0], pos.pos[1]); float zAngle = mPathFinder.getZAngleToNext(pos.pos[0], pos.pos[1]);
MWBase::Environment::get().getWorld()->rotateObject(actor, 0, 0, zAngle, false); world->rotateObject(actor, 0, 0, zAngle, false);
MWWorld::Class::get(actor).getMovementSettings(actor).mPosition[1] = 1; movement.mPosition[1] = 1;
return false; return false;
} }

View file

@ -65,10 +65,11 @@ namespace MWMechanics
bool AiWander::execute (const MWWorld::Ptr& actor) bool AiWander::execute (const MWWorld::Ptr& actor)
{ {
MWBase::World *world = MWBase::Environment::get().getWorld();
if(mDuration) if(mDuration)
{ {
// End package if duration is complete or mid-night hits: // End package if duration is complete or mid-night hits:
MWWorld::TimeStamp currentTime = MWBase::Environment::get().getWorld()->getTimeStamp(); MWWorld::TimeStamp currentTime = world->getTimeStamp();
if(currentTime.getHour() >= mStartTime.getHour() + mDuration) if(currentTime.getHour() >= mStartTime.getHour() + mDuration)
{ {
if(!mRepeat) if(!mRepeat)
@ -96,8 +97,7 @@ namespace MWMechanics
if(!mStoredAvailableNodes) if(!mStoredAvailableNodes)
{ {
mStoredAvailableNodes = true; mStoredAvailableNodes = true;
mPathgrid = mPathgrid = world->getStore().get<ESM::Pathgrid>().search(*actor.getCell()->mCell);
MWBase::Environment::get().getWorld()->getStore().get<ESM::Pathgrid>().search(*actor.getCell()->mCell);
mCellX = actor.getCell()->mCell->mData.mX; mCellX = actor.getCell()->mCell->mData.mX;
mCellY = actor.getCell()->mCell->mData.mY; mCellY = actor.getCell()->mCell->mData.mY;
@ -150,37 +150,8 @@ namespace MWMechanics
} }
} }
MWWorld::Ptr player = MWBase::Environment::get().getWorld()->getPlayer().getPlayer();
bool cellChange = actor.getCell()->mCell->mData.mX != mCellX || actor.getCell()->mCell->mData.mY != mCellY;
if(actor.getCell()->mCell->mData.mX != player.getCell()->mCell->mData.mX)
{
int sideX = sgn(actor.getCell()->mCell->mData.mX - player.getCell()->mCell->mData.mX);
// Check if actor is near the border of an inactive cell. If so, disable AiWander.
// FIXME: This *should* pause the AiWander package instead of terminating it.
if(sideX * (pos.pos[0] - actor.getCell()->mCell->mData.mX * ESM::Land::REAL_SIZE) > sideX * (ESM::Land::REAL_SIZE /
2.0 - 200))
{
stopWalking(actor);
return true;
}
}
if(actor.getCell()->mCell->mData.mY != player.getCell()->mCell->mData.mY)
{
int sideY = sgn(actor.getCell()->mCell->mData.mY - player.getCell()->mCell->mData.mY);
// Check if actor is near the border of an inactive cell. If so, disable AiWander.
// FIXME: This *should* pause the AiWander package instead of terminating it.
if(sideY * (pos.pos[1] - actor.getCell()->mCell->mData.mY * ESM::Land::REAL_SIZE) > sideY * (ESM::Land::REAL_SIZE /
2.0 - 200))
{
stopWalking(actor);
return true;
}
}
// Don't try to move if you are in a new cell (ie: positioncell command called) but still play idles. // Don't try to move if you are in a new cell (ie: positioncell command called) but still play idles.
if(mDistance && (cellChange || (mCellX != actor.getCell()->mCell->mData.mX || mCellY != actor.getCell()->mCell->mData.mY))) if(mDistance && (mCellX != actor.getCell()->mCell->mData.mX || mCellY != actor.getCell()->mCell->mData.mY))
mDistance = 0; mDistance = 0;
if(mChooseAction) if(mChooseAction)
@ -207,7 +178,7 @@ namespace MWMechanics
else else
{ {
// Play idle animation and recreate vanilla (broken?) behavior of resetting start time of AIWander: // Play idle animation and recreate vanilla (broken?) behavior of resetting start time of AIWander:
MWWorld::TimeStamp currentTime = MWBase::Environment::get().getWorld()->getTimeStamp(); MWWorld::TimeStamp currentTime = world->getTimeStamp();
mStartTime = currentTime; mStartTime = currentTime;
playIdle(actor, mPlayedIdle); playIdle(actor, mPlayedIdle);
mChooseAction = false; mChooseAction = false;
@ -264,18 +235,10 @@ namespace MWMechanics
if(mWalking) if(mWalking)
{ {
float zAngle = mPathFinder.getZAngleToNext(pos.pos[0], pos.pos[1]); float zAngle = mPathFinder.getZAngleToNext(pos.pos[0], pos.pos[1]);
MWBase::Environment::get().getWorld()->rotateObject(actor, 0, 0, zAngle,false); world->rotateObject(actor, 0, 0, zAngle, false);
MWWorld::Class::get(actor).getMovementSettings(actor).mPosition[1] = 1; MWWorld::Class::get(actor).getMovementSettings(actor).mPosition[1] = 1;
// Unclog path nodes by allowing the NPC to be a small distance away from the center. This way two NPCs can be if(mPathFinder.checkPathCompleted(pos.pos[0], pos.pos[1], pos.pos[2]))
// at the same path node at the same time and both will complete instead of endlessly walking into eachother:
Ogre::Vector3 destNodePos(mCurrentNode.mX, mCurrentNode.mY, mCurrentNode.mZ);
Ogre::Vector3 actorPos(actor.getRefData().getPosition().pos);
actorPos[0] = actorPos[0] - mXCell;
actorPos[1] = actorPos[1] - mYCell;
float distance = actorPos.squaredDistance(destNodePos);
if(distance < 1200 || mPathFinder.checkPathCompleted(pos.pos[0], pos.pos[1], pos.pos[2]))
{ {
stopWalking(actor); stopWalking(actor);
mMoveNow = false; mMoveNow = false;

View file

@ -8,7 +8,6 @@
#include "../mwbase/world.hpp" #include "../mwbase/world.hpp"
#include "../mwbase/windowmanager.hpp" #include "../mwbase/windowmanager.hpp"
#include "../mwbase/dialoguemanager.hpp" #include "../mwbase/dialoguemanager.hpp"
#include "../mwbase/soundmanager.hpp"
#include "../mwworld/class.hpp" #include "../mwworld/class.hpp"
#include "../mwworld/player.hpp" #include "../mwworld/player.hpp"
@ -189,6 +188,9 @@ namespace MWMechanics
void MechanicsManager::updateCell(const MWWorld::Ptr &old, const MWWorld::Ptr &ptr) void MechanicsManager::updateCell(const MWWorld::Ptr &old, const MWWorld::Ptr &ptr)
{ {
if(old == mWatched)
mWatched = ptr;
if(MWWorld::Class::get(ptr).isActor()) if(MWWorld::Class::get(ptr).isActor())
mActors.updateActor(old, ptr); mActors.updateActor(old, ptr);
else else
@ -213,98 +215,76 @@ namespace MWMechanics
void MechanicsManager::update(float duration, bool paused) void MechanicsManager::update(float duration, bool paused)
{ {
if (!mWatched.isEmpty()) if(!mWatched.isEmpty())
{ {
MWMechanics::CreatureStats& stats = MWBase::WindowManager *winMgr = MWBase::Environment::get().getWindowManager();
MWWorld::Class::get (mWatched).getCreatureStats (mWatched); const MWMechanics::NpcStats &stats = mWatched.getClass().getNpcStats(mWatched);
for(int i = 0;i < ESM::Attribute::Length;++i)
MWMechanics::NpcStats& npcStats =
MWWorld::Class::get (mWatched).getNpcStats (mWatched);
static const char *attributeNames[8] =
{ {
"AttribVal1", "AttribVal2", "AttribVal3", "AttribVal4", "AttribVal5", if(stats.getAttribute(i) != mWatchedStats.getAttribute(i))
"AttribVal6", "AttribVal7", "AttribVal8"
};
static const char *dynamicNames[3] =
{ {
"HBar", "MBar", "FBar" std::stringstream attrname;
}; attrname << "AttribVal"<<(i+1);
for (int i=0; i<8; ++i) mWatchedStats.setAttribute(i, stats.getAttribute(i));
{ winMgr->setValue(attrname.str(), stats.getAttribute(i));
if (stats.getAttribute(i)!=mWatchedCreature.getAttribute(i))
{
mWatchedCreature.setAttribute(i, stats.getAttribute(i));
MWBase::Environment::get().getWindowManager()->setValue (attributeNames[i], stats.getAttribute(i));
} }
} }
if (stats.getHealth() != mWatchedCreature.getHealth()) { if(stats.getHealth() != mWatchedStats.getHealth())
mWatchedCreature.setHealth(stats.getHealth()); {
MWBase::Environment::get().getWindowManager()->setValue(dynamicNames[0], stats.getHealth()); static const std::string hbar("HBar");
mWatchedStats.setHealth(stats.getHealth());
winMgr->setValue(hbar, stats.getHealth());
} }
if (stats.getMagicka() != mWatchedCreature.getMagicka()) { if(stats.getMagicka() != mWatchedStats.getMagicka())
mWatchedCreature.setMagicka(stats.getMagicka()); {
MWBase::Environment::get().getWindowManager()->setValue(dynamicNames[1], stats.getMagicka()); static const std::string mbar("MBar");
mWatchedStats.setMagicka(stats.getMagicka());
winMgr->setValue(mbar, stats.getMagicka());
} }
if (stats.getFatigue() != mWatchedCreature.getFatigue()) { if(stats.getFatigue() != mWatchedStats.getFatigue())
mWatchedCreature.setFatigue(stats.getFatigue()); {
MWBase::Environment::get().getWindowManager()->setValue(dynamicNames[2], stats.getFatigue()); static const std::string fbar("FBar");
mWatchedStats.setFatigue(stats.getFatigue());
winMgr->setValue(fbar, stats.getFatigue());
} }
if(npcStats.getTimeToStartDrowning() != mWatchedNpc.getTimeToStartDrowning()) if(stats.getTimeToStartDrowning() != mWatchedStats.getTimeToStartDrowning())
{ {
mWatchedNpc.setTimeToStartDrowning(npcStats.getTimeToStartDrowning()); mWatchedStats.setTimeToStartDrowning(stats.getTimeToStartDrowning());
if(npcStats.getTimeToStartDrowning()>=20.0) if(stats.getTimeToStartDrowning() >= 20.0f)
{ winMgr->setDrowningBarVisibility(false);
MWBase::Environment::get().getWindowManager()->setDrowningBarVisibility(false);
}
else else
{ {
MWBase::Environment::get().getWindowManager()->setDrowningBarVisibility(true); winMgr->setDrowningBarVisibility(true);
MWBase::Environment::get().getWindowManager()->setDrowningTimeLeft(npcStats.getTimeToStartDrowning()); winMgr->setDrowningTimeLeft(stats.getTimeToStartDrowning());
} }
} }
bool update = false; bool update = false;
//Loop over ESM::Skill::SkillEnum //Loop over ESM::Skill::SkillEnum
for(int i = 0; i < 27; ++i) for(int i = 0; i < ESM::Skill::Length; ++i)
{ {
if(npcStats.getSkill (i) != mWatchedNpc.getSkill (i)) if(stats.getSkill(i) != mWatchedStats.getSkill(i))
{ {
update = true; update = true;
mWatchedNpc.getSkill (i) = npcStats.getSkill (i); mWatchedStats.getSkill(i) = stats.getSkill(i);
MWBase::Environment::get().getWindowManager()->setValue((ESM::Skill::SkillEnum)i, npcStats.getSkill (i)); winMgr->setValue((ESM::Skill::SkillEnum)i, stats.getSkill(i));
} }
} }
if (update) if(update)
MWBase::Environment::get().getWindowManager()->updateSkillArea(); winMgr->updateSkillArea();
MWBase::Environment::get().getWindowManager()->setValue ("level", stats.getLevel()); winMgr->setValue("level", stats.getLevel());
}
//update drowning sound
MWBase::World *world = MWBase::Environment::get().getWorld();
MWBase::SoundManager * sndmgr = MWBase::Environment::get().getSoundManager();
MWWorld::Ptr playerPtr = world->getPlayer().getPlayer();
NpcStats& playerStats = MWWorld::Class::get(playerPtr).getNpcStats(playerPtr);
if(!sndmgr->getSoundPlaying(MWWorld::Ptr(), "drown") && playerStats.getTimeToStartDrowning()==0.0)
{
sndmgr->playSound("drown",1.0,1.0,MWBase::SoundManager::Play_TypeSfx,MWBase::SoundManager::Play_Loop);
}
if(playerStats.getTimeToStartDrowning()>0.0)
{
//no need to check if it's playing, stop sound does nothing in that case
sndmgr->stopSound("drown");
} }
if (mUpdatePlayer) if (mUpdatePlayer)
{ {
MWBase::World *world = MWBase::Environment::get().getWorld();
// basic player profile; should not change anymore after the creation phase is finished. // basic player profile; should not change anymore after the creation phase is finished.
MWBase::WindowManager *winMgr = MWBase::WindowManager *winMgr =
MWBase::Environment::get().getWindowManager(); MWBase::Environment::get().getWindowManager();

View file

@ -25,8 +25,7 @@ namespace MWMechanics
class MechanicsManager : public MWBase::MechanicsManager class MechanicsManager : public MWBase::MechanicsManager
{ {
MWWorld::Ptr mWatched; MWWorld::Ptr mWatched;
CreatureStats mWatchedCreature; NpcStats mWatchedStats;
NpcStats mWatchedNpc;
bool mUpdatePlayer; bool mUpdatePlayer;
bool mClassSelected; bool mClassSelected;
bool mRaceSelected; bool mRaceSelected;

View file

@ -422,7 +422,7 @@ void MWMechanics::NpcStats::modifyProfit(int diff)
mProfit += diff; mProfit += diff;
} }
float MWMechanics::NpcStats::getTimeToStartDrowning() float MWMechanics::NpcStats::getTimeToStartDrowning() const
{ {
return mTimeToStartDrowning; return mTimeToStartDrowning;
} }
@ -431,13 +431,3 @@ void MWMechanics::NpcStats::setTimeToStartDrowning(float time)
assert(time>=0 && time<=20); assert(time>=0 && time<=20);
mTimeToStartDrowning=time; mTimeToStartDrowning=time;
} }
float MWMechanics::NpcStats::getLastDrowningHitTime()
{
return mLastDrowningHit;
}
void MWMechanics::NpcStats::setLastDrowningHitTime(float time)
{
mLastDrowningHit=time;
}

View file

@ -147,15 +147,10 @@ namespace MWMechanics
int getWerewolfKills() const; int getWerewolfKills() const;
float getTimeToStartDrowning(); float getTimeToStartDrowning() const;
/// Sets time left for the creature to drown if it stays underwater. /// Sets time left for the creature to drown if it stays underwater.
/// @param time value from [0,20] /// @param time value from [0,20]
void setTimeToStartDrowning(float time); void setTimeToStartDrowning(float time);
float getLastDrowningHitTime();
/// Sets time since last hit caused by drowning.
/// @param time value from [0,0.33]
void setLastDrowningHitTime(float time);
}; };
} }

View file

@ -147,13 +147,13 @@ namespace MWMechanics
mIsPathConstructed = false; mIsPathConstructed = false;
} }
void PathFinder::buildPath(ESM::Pathgrid::Point startPoint, ESM::Pathgrid::Point endPoint, void PathFinder::buildPath(const ESM::Pathgrid::Point &startPoint, const ESM::Pathgrid::Point &endPoint,
const ESM::Pathgrid* pathGrid, float xCell, float yCell, bool allowShortcuts) const ESM::Pathgrid *pathGrid, float xCell, float yCell, bool allowShortcuts)
{ {
if(allowShortcuts) if(allowShortcuts)
{ {
if(MWBase::Environment::get().getWorld()->castRay(startPoint.mX, startPoint.mY, startPoint.mZ, endPoint.mX, endPoint.mY, if(MWBase::Environment::get().getWorld()->castRay(startPoint.mX, startPoint.mY, startPoint.mZ,
endPoint.mZ)) endPoint.mX, endPoint.mY, endPoint.mZ))
allowShortcuts = false; allowShortcuts = false;
} }
@ -184,14 +184,14 @@ namespace MWMechanics
mIsPathConstructed = false; mIsPathConstructed = false;
} }
float PathFinder::getZAngleToNext(float x, float y) float PathFinder::getZAngleToNext(float x, float y) const
{ {
// This should never happen (programmers should have an if statement checking mIsPathConstructed that prevents this call // This should never happen (programmers should have an if statement checking mIsPathConstructed that prevents this call
// if otherwise). // if otherwise).
if(mPath.empty()) if(mPath.empty())
return 0; return 0;
ESM::Pathgrid::Point nextPoint = *mPath.begin(); const ESM::Pathgrid::Point &nextPoint = *mPath.begin();
float directionX = nextPoint.mX - x; float directionX = nextPoint.mX - x;
float directionY = nextPoint.mY - y; float directionY = nextPoint.mY - y;
float directionResult = sqrt(directionX * directionX + directionY * directionY); float directionResult = sqrt(directionX * directionX + directionY * directionY);
@ -205,7 +205,7 @@ namespace MWMechanics
return true; return true;
ESM::Pathgrid::Point nextPoint = *mPath.begin(); ESM::Pathgrid::Point nextPoint = *mPath.begin();
if(distanceZCorrected(nextPoint, x, y, z) < 40) if(distanceZCorrected(nextPoint, x, y, z) < 64)
{ {
mPath.pop_front(); mPath.pop_front();
if(mPath.empty()) if(mPath.empty())
@ -217,15 +217,5 @@ namespace MWMechanics
return false; return false;
} }
std::list<ESM::Pathgrid::Point> PathFinder::getPath()
{
return mPath;
}
bool PathFinder::isPathConstructed()
{
return mIsPathConstructed;
}
} }

View file

@ -12,15 +12,18 @@ namespace MWMechanics
PathFinder(); PathFinder();
void clearPath(); void clearPath();
void buildPath(ESM::Pathgrid::Point startPoint, ESM::Pathgrid::Point endPoint, void buildPath(const ESM::Pathgrid::Point &startPoint, const ESM::Pathgrid::Point &endPoint,
const ESM::Pathgrid* pathGrid, float xCell = 0, float yCell = 0, bool allowShortcuts = 1); const ESM::Pathgrid* pathGrid, float xCell = 0, float yCell = 0,
bool allowShortcuts = true);
bool checkPathCompleted(float x, float y, float z); bool checkPathCompleted(float x, float y, float z);
///< \Returns true if the last point of the path has been reached. ///< \Returns true if the last point of the path has been reached.
float getZAngleToNext(float x, float y); float getZAngleToNext(float x, float y) const;
std::list<ESM::Pathgrid::Point> getPath(); bool isPathConstructed() const
bool isPathConstructed(); {
return mIsPathConstructed;
}
private: private:
std::list<ESM::Pathgrid::Point> mPath; std::list<ESM::Pathgrid::Point> mPath;

View file

@ -42,6 +42,18 @@ namespace MWMechanics
mBase = mModified = value; mBase = mModified = value;
} }
void modify(const T& diff)
{
mBase += diff;
if(mBase >= static_cast<T>(0))
mModified += diff;
else
{
mModified += diff - mBase;
mBase = static_cast<T>(0);
}
}
/// Set base and adjust modified accordingly. /// Set base and adjust modified accordingly.
void setBase (const T& value) void setBase (const T& value)
{ {

View file

@ -10,6 +10,8 @@
#include <OgreRoot.h> #include <OgreRoot.h>
#include <OgreHardwarePixelBuffer.h> #include <OgreHardwarePixelBuffer.h>
#include <components/loadinglistener/loadinglistener.hpp>
#include "../mwbase/environment.hpp" #include "../mwbase/environment.hpp"
#include "../mwbase/world.hpp" #include "../mwbase/world.hpp"
@ -28,7 +30,7 @@ namespace MWRender
} }
void GlobalMap::render () void GlobalMap::render (Loading::Listener* loadingListener)
{ {
Ogre::TexturePtr tex; Ogre::TexturePtr tex;
@ -53,6 +55,11 @@ namespace MWRender
mWidth = cellSize*(mMaxX-mMinX+1); mWidth = cellSize*(mMaxX-mMinX+1);
mHeight = cellSize*(mMaxY-mMinY+1); mHeight = cellSize*(mMaxY-mMinY+1);
loadingListener->loadingOn();
loadingListener->setLabel("Creating map");
loadingListener->setProgressRange((mMaxX-mMinX+1) * (mMaxY-mMinY+1));
loadingListener->setProgress(0);
mExploredBuffer.resize((mMaxX-mMinX+1) * (mMaxY-mMinY+1) * 4); mExploredBuffer.resize((mMaxX-mMinX+1) * (mMaxY-mMinY+1) * 4);
//if (!boost::filesystem::exists(mCacheDir + "/GlobalMap.png")) //if (!boost::filesystem::exists(mCacheDir + "/GlobalMap.png"))
@ -147,6 +154,7 @@ namespace MWRender
data[texelY * mWidth * 3 + texelX * 3+2] = b; data[texelY * mWidth * 3 + texelX * 3+2] = b;
} }
} }
loadingListener->increaseProgress(1);
} }
} }
@ -177,6 +185,8 @@ namespace MWRender
memcpy(mOverlayTexture->getBuffer()->lock(Ogre::HardwareBuffer::HBL_DISCARD), &buffer[0], mWidth*mHeight*4); memcpy(mOverlayTexture->getBuffer()->lock(Ogre::HardwareBuffer::HBL_DISCARD), &buffer[0], mWidth*mHeight*4);
mOverlayTexture->getBuffer()->unlock(); mOverlayTexture->getBuffer()->unlock();
loadingListener->loadingOff();
} }
void GlobalMap::worldPosToImageSpace(float x, float z, float& imageX, float& imageY) void GlobalMap::worldPosToImageSpace(float x, float z, float& imageX, float& imageY)

View file

@ -5,6 +5,11 @@
#include <OgreTexture.h> #include <OgreTexture.h>
namespace Loading
{
class Listener;
}
namespace MWRender namespace MWRender
{ {
@ -13,7 +18,7 @@ namespace MWRender
public: public:
GlobalMap(const std::string& cacheDir); GlobalMap(const std::string& cacheDir);
void render(); void render(Loading::Listener* loadingListener);
int getWidth() { return mWidth; } int getWidth() { return mWidth; }
int getHeight() { return mHeight; } int getHeight() { return mHeight; }

View file

@ -370,8 +370,8 @@ void LocalMap::updatePlayer (const Ogre::Vector3& position, const Ogre::Quaterni
MWBase::Environment::get().getWindowManager()->setPlayerDir(playerdirection.x, playerdirection.y); MWBase::Environment::get().getWindowManager()->setPlayerDir(playerdirection.x, playerdirection.y);
// explore radius (squared) // explore radius (squared)
const float sqrExploreRadius = (mInterior ? 0.01 : 0.09) * sFogOfWarResolution*sFogOfWarResolution; const float exploreRadius = (mInterior ? 0.1 : 0.3) * (sFogOfWarResolution-1); // explore radius from 0 to sFogOfWarResolution-1
const float exploreRadius = (mInterior ? 0.1 : 0.3) * sFogOfWarResolution; // explore radius from 0 to sFogOfWarResolution const float sqrExploreRadius = Math::Sqr(exploreRadius);
const float exploreRadiusUV = exploreRadius / sFogOfWarResolution; // explore radius from 0 to 1 (UV space) const float exploreRadiusUV = exploreRadius / sFogOfWarResolution; // explore radius from 0 to 1 (UV space)
// change the affected fog of war textures (in a 3x3 grid around the player) // change the affected fog of war textures (in a 3x3 grid around the player)
@ -406,11 +406,8 @@ void LocalMap::updatePlayer (const Ogre::Vector3& position, const Ogre::Quaterni
{ {
for (int texU = 0; texU<sFogOfWarResolution; ++texU) for (int texU = 0; texU<sFogOfWarResolution; ++texU)
{ {
// fix into range of 0 ... sFogOfWarResolution float sqrDist = Math::Sqr((texU + mx*(sFogOfWarResolution-1)) - u*(sFogOfWarResolution-1))
int _texU = texU * (float(sFogOfWarResolution+1) / float(sFogOfWarResolution)); + Math::Sqr((texV + my*(sFogOfWarResolution-1)) - v*(sFogOfWarResolution-1));
int _texV = texV * (float(sFogOfWarResolution+1) / float(sFogOfWarResolution));
float sqrDist = Math::Sqr((_texU + mx*sFogOfWarResolution) - u*sFogOfWarResolution) + Math::Sqr((_texV + my*sFogOfWarResolution) - v*sFogOfWarResolution);
uint32 clr = mBuffers[texName][i]; uint32 clr = mBuffers[texName][i];
uint8 alpha = (clr >> 24); uint8 alpha = (clr >> 24);
alpha = std::min( alpha, (uint8) (std::max(0.f, std::min(1.f, (sqrDist/sqrExploreRadius)))*255) ); alpha = std::min( alpha, (uint8) (std::max(0.f, std::min(1.f, (sqrDist/sqrExploreRadius)))*255) );

View file

@ -25,7 +25,7 @@
#include <components/esm/loadstat.hpp> #include <components/esm/loadstat.hpp>
#include <components/settings/settings.hpp> #include <components/settings/settings.hpp>
#include <components/terrain/terrain.hpp> #include <components/terrain/world.hpp>
#include "../mwworld/esmstore.hpp" #include "../mwworld/esmstore.hpp"
#include "../mwworld/class.hpp" #include "../mwworld/class.hpp"
@ -82,7 +82,7 @@ RenderingManager::RenderingManager(OEngine::Render::OgreRenderer& _rend, const b
Settings::Manager::setString("shader mode", "General", openGL ? (glES ? "glsles" : "glsl") : "hlsl"); Settings::Manager::setString("shader mode", "General", openGL ? (glES ? "glsles" : "glsl") : "hlsl");
} }
mRendering.createScene("PlayerCam", Settings::Manager::getFloat("field of view", "General"), 5); mRendering.adjustCamera(Settings::Manager::getFloat("field of view", "General"), 5);
mRendering.getWindow()->addListener(this); mRendering.getWindow()->addListener(this);
mRendering.setWindowListener(this); mRendering.setWindowListener(this);
@ -1018,12 +1018,15 @@ void RenderingManager::enableTerrain(bool enable)
{ {
if (!mTerrain) if (!mTerrain)
{ {
mTerrain = new Terrain::Terrain(mRendering.getScene(), new MWRender::TerrainStorage(), RV_Terrain, Loading::Listener* listener = MWBase::Environment::get().getWindowManager()->getLoadingScreen();
Loading::ScopedLoad load(listener);
mTerrain = new Terrain::World(listener, mRendering.getScene(), new MWRender::TerrainStorage(), RV_Terrain,
Settings::Manager::getBool("distant land", "Terrain"), Settings::Manager::getBool("distant land", "Terrain"),
Settings::Manager::getBool("shader", "Terrain")); Settings::Manager::getBool("shader", "Terrain"));
mTerrain->applyMaterials(Settings::Manager::getBool("enabled", "Shadows"), mTerrain->applyMaterials(Settings::Manager::getBool("enabled", "Shadows"),
Settings::Manager::getBool("split", "Shadows")); Settings::Manager::getBool("split", "Shadows"));
mTerrain->update(mRendering.getCamera()->getRealPosition()); mTerrain->update(mRendering.getCamera()->getRealPosition());
mTerrain->setLoadingListener(NULL);
} }
mTerrain->setVisible(true); mTerrain->setVisible(true);
} }

View file

@ -40,7 +40,7 @@ namespace sh
namespace Terrain namespace Terrain
{ {
class Terrain; class World;
} }
namespace MWRender namespace MWRender
@ -234,7 +234,7 @@ private:
OcclusionQuery* mOcclusionQuery; OcclusionQuery* mOcclusionQuery;
Terrain::Terrain* mTerrain; Terrain::World* mTerrain;
MWRender::Water *mWater; MWRender::Water *mWater;

View file

@ -1037,7 +1037,6 @@ public:
VideoPlayer::VideoPlayer(Ogre::SceneManager* sceneMgr, Ogre::RenderWindow* window) VideoPlayer::VideoPlayer(Ogre::SceneManager* sceneMgr, Ogre::RenderWindow* window)
: mState(NULL) : mState(NULL)
, mSceneMgr(sceneMgr) , mSceneMgr(sceneMgr)
, mVideoMaterial(NULL)
, mRectangle(NULL) , mRectangle(NULL)
, mNode(NULL) , mNode(NULL)
, mAllowSkipping(false) , mAllowSkipping(false)

View file

@ -4,11 +4,10 @@
#include <algorithm> #include <algorithm>
#include <map> #include <map>
#include "../mwworld/esmstore.hpp"
#include "../mwbase/environment.hpp" #include "../mwbase/environment.hpp"
#include "../mwbase/world.hpp" #include "../mwbase/world.hpp"
#include "../mwworld/esmstore.hpp"
#include "../mwworld/player.hpp" #include "../mwworld/player.hpp"
#include "sound_output.hpp" #include "sound_output.hpp"
@ -103,6 +102,7 @@ namespace MWSound
SoundManager::~SoundManager() SoundManager::~SoundManager()
{ {
mUnderwaterSound.reset();
mActiveSounds.clear(); mActiveSounds.clear();
mMusic.reset(); mMusic.reset();
mOutput.reset(); mOutput.reset();
@ -474,27 +474,32 @@ namespace MWSound
void SoundManager::updateRegionSound(float duration) void SoundManager::updateRegionSound(float duration)
{ {
MWWorld::Ptr::CellStore *current = MWBase::Environment::get().getWorld()->getPlayer().getPlayer().getCell(); static float sTimeToNextEnvSound = 0.0f;
static int total = 0; static int total = 0;
static std::string regionName = ""; static std::string regionName = "";
static float timePassed = 0.0; static float sTimePassed = 0.0;
MWBase::World *world = MWBase::Environment::get().getWorld();
const MWWorld::Ptr player = world->getPlayer().getPlayer();
const ESM::Cell *cell = player.getCell()->mCell;
//If the region has changed sTimePassed += duration;
timePassed += duration; if(!cell->isExterior() || sTimePassed < sTimeToNextEnvSound)
if(!current->mCell->isExterior() || timePassed < 10)
return; return;
timePassed = 0;
if(regionName != current->mCell->mRegion) float a = std::rand() / (double)RAND_MAX;
// NOTE: We should use the "Minimum Time Between Environmental Sounds" and
// "Maximum Time Between Environmental Sounds" fallback settings here.
sTimeToNextEnvSound = 5.0f*a + 15.0f*(1.0f-a);
sTimePassed = 0;
if(regionName != cell->mRegion)
{ {
regionName = current->mCell->mRegion; regionName = cell->mRegion;
total = 0; total = 0;
} }
const ESM::Region *regn = const ESM::Region *regn = world->getStore().get<ESM::Region>().search(regionName);
MWBase::Environment::get().getWorld()->getStore().get<ESM::Region>().search(regionName); if(regn == NULL)
if (regn == NULL)
return; return;
std::vector<ESM::Region::SoundRef>::const_iterator soundIter; std::vector<ESM::Region::SoundRef>::const_iterator soundIter;
@ -550,15 +555,13 @@ namespace MWSound
{ {
env = Env_Underwater; env = Env_Underwater;
//play underwater sound //play underwater sound
//HACK: this sound is always played underwater, so set volume and pitch higher (it's then lowered) if(!(mUnderwaterSound && mUnderwaterSound->isPlaying()))
//Currently not possible to play looping sound with no environment mUnderwaterSound = playSound("Underwater", 1.0f, 1.0f, Play_TypeSfx, Play_LoopNoEnv);
if(!getSoundPlaying(MWWorld::Ptr(), "Underwater"))
playSound("Underwater", 1.11, 1.42 ,Play_TypeSfx, Play_Loop );
} }
else else if(mUnderwaterSound)
{ {
//no need to check if it's playing, stop sound does nothing in that case mUnderwaterSound->stop();
stopSound("Underwater"); mUnderwaterSound.reset();
} }
mOutput->updateListener( mOutput->updateListener(

View file

@ -44,6 +44,8 @@ namespace MWSound
typedef std::map<MWBase::SoundPtr,PtrIDPair> SoundMap; typedef std::map<MWBase::SoundPtr,PtrIDPair> SoundMap;
SoundMap mActiveSounds; SoundMap mActiveSounds;
MWBase::SoundPtr mUnderwaterSound;
Ogre::Vector3 mListenerPos; Ogre::Vector3 mListenerPos;
Ogre::Vector3 mListenerDir; Ogre::Vector3 mListenerDir;
Ogre::Vector3 mListenerUp; Ogre::Vector3 mListenerUp;

View file

@ -80,7 +80,7 @@ MWWorld::ContainerStoreIterator MWWorld::ContainerStore::end()
bool MWWorld::ContainerStore::stacks(const Ptr& ptr1, const Ptr& ptr2) bool MWWorld::ContainerStore::stacks(const Ptr& ptr1, const Ptr& ptr2)
{ {
/// \todo add current enchantment charge here when it is implemented /// \todo add current enchantment charge here when it is implemented
if ( ptr1.getCellRef().mRefID == ptr2.getCellRef().mRefID if ( Misc::StringUtils::ciEqual(ptr1.getCellRef().mRefID, ptr2.getCellRef().mRefID)
&& MWWorld::Class::get(ptr1).getScript(ptr1) == "" // item with a script never stacks && MWWorld::Class::get(ptr1).getScript(ptr1) == "" // item with a script never stacks
&& MWWorld::Class::get(ptr1).getEnchantment(ptr1) == "" // item with enchantment never stacks (we could revisit this later, but for now it makes selecting items in the spell window much easier) && MWWorld::Class::get(ptr1).getEnchantment(ptr1) == "" // item with enchantment never stacks (we could revisit this later, but for now it makes selecting items in the spell window much easier)
&& ptr1.getCellRef().mOwner == ptr2.getCellRef().mOwner && ptr1.getCellRef().mOwner == ptr2.getCellRef().mOwner

View file

@ -5,6 +5,8 @@
#include <boost/filesystem/operations.hpp> #include <boost/filesystem/operations.hpp>
#include <components/loadinglistener/loadinglistener.hpp>
namespace MWWorld namespace MWWorld
{ {
@ -21,8 +23,10 @@ static bool isCacheableRecord(int id)
return false; return false;
} }
void ESMStore::load(ESM::ESMReader &esm) void ESMStore::load(ESM::ESMReader &esm, Loading::Listener* listener)
{ {
listener->setProgressRange(1000);
std::set<std::string> missing; std::set<std::string> missing;
ESM::Dialogue *dialogue = 0; ESM::Dialogue *dialogue = 0;
@ -109,6 +113,7 @@ void ESMStore::load(ESM::ESMReader &esm)
mIds[id] = n.val; mIds[id] = n.val;
} }
} }
listener->setProgress(esm.getFileOffset() / (float)esm.getFileSize() * 1000);
} }
/* This information isn't needed on screen. But keep the code around /* This information isn't needed on screen. But keep the code around

View file

@ -6,6 +6,11 @@
#include <components/esm/records.hpp> #include <components/esm/records.hpp>
#include "store.hpp" #include "store.hpp"
namespace Loading
{
class Listener;
}
namespace MWWorld namespace MWWorld
{ {
class ESMStore class ESMStore
@ -158,7 +163,7 @@ namespace MWWorld
mNpcs.insert(mPlayerTemplate); mNpcs.insert(mPlayerTemplate);
} }
void load(ESM::ESMReader &esm); void load(ESM::ESMReader &esm, Loading::Listener* listener);
template <class T> template <class T>
const Store<T> &get() const { const Store<T> &get() const {

View file

@ -25,13 +25,12 @@ namespace
template<typename T> template<typename T>
void insertCellRefList(MWRender::RenderingManager& rendering, void insertCellRefList(MWRender::RenderingManager& rendering,
T& cellRefList, MWWorld::CellStore &cell, MWWorld::PhysicsSystem& physics, bool rescale) T& cellRefList, MWWorld::CellStore &cell, MWWorld::PhysicsSystem& physics, bool rescale, Loading::Listener* loadingListener)
{ {
if (!cellRefList.mList.empty()) if (!cellRefList.mList.empty())
{ {
const MWWorld::Class& class_ = const MWWorld::Class& class_ =
MWWorld::Class::get (MWWorld::Ptr (&*cellRefList.mList.begin(), &cell)); MWWorld::Class::get (MWWorld::Ptr (&*cellRefList.mList.begin(), &cell));
int current = 0;
for (typename T::List::iterator it = cellRefList.mList.begin(); for (typename T::List::iterator it = cellRefList.mList.begin();
it != cellRefList.mList.end(); it++) it != cellRefList.mList.end(); it++)
{ {
@ -43,8 +42,6 @@ namespace
it->mRef.mScale = 2; it->mRef.mScale = 2;
} }
++current;
if (it->mData.getCount() && it->mData.isEnabled()) if (it->mData.getCount() && it->mData.isEnabled())
{ {
MWWorld::Ptr ptr (&*it, &cell); MWWorld::Ptr ptr (&*it, &cell);
@ -68,6 +65,8 @@ namespace
std::cerr << error + e.what() << std::endl; std::cerr << error + e.what() << std::endl;
} }
} }
loadingListener->increaseProgress(1);
} }
} }
} }
@ -117,7 +116,7 @@ namespace MWWorld
mActiveCells.erase(*iter); mActiveCells.erase(*iter);
} }
void Scene::loadCell (Ptr::CellStore *cell) void Scene::loadCell (Ptr::CellStore *cell, Loading::Listener* loadingListener)
{ {
// register local scripts // register local scripts
MWBase::Environment::get().getWorld()->getLocalScripts().addCell (cell); MWBase::Environment::get().getWorld()->getLocalScripts().addCell (cell);
@ -150,7 +149,7 @@ namespace MWWorld
// ... then references. This is important for adjustPosition to work correctly. // ... then references. This is important for adjustPosition to work correctly.
/// \todo rescale depending on the state of a new GMST /// \todo rescale depending on the state of a new GMST
insertCell (*cell, true); insertCell (*cell, true, loadingListener);
mRendering.cellAdded (cell); mRendering.cellAdded (cell);
@ -200,17 +199,15 @@ namespace MWWorld
void Scene::changeCell (int X, int Y, const ESM::Position& position, bool adjustPlayerPos) void Scene::changeCell (int X, int Y, const ESM::Position& position, bool adjustPlayerPos)
{ {
Nif::NIFFile::CacheLock cachelock; Nif::NIFFile::CacheLock cachelock;
const MWWorld::Store<ESM::GameSetting> &gmst =
MWBase::Environment::get().getWorld()->getStore().get<ESM::GameSetting>();
mRendering.preCellChange(mCurrentCell); Loading::Listener* loadingListener = MWBase::Environment::get().getWindowManager()->getLoadingScreen();
Loading::ScopedLoad load(loadingListener);
// remove active // remove active
MWBase::Environment::get().getMechanicsManager()->remove(MWBase::Environment::get().getWorld()->getPlayer().getPlayer()); MWBase::Environment::get().getMechanicsManager()->remove(MWBase::Environment::get().getWorld()->getPlayer().getPlayer());
std::string loadingExteriorText; std::string loadingExteriorText = "#{sLoadingMessage3}";
loadingListener->setLabel(loadingExteriorText);
loadingExteriorText = gmst.find ("sLoadingMessage3")->getString();
CellStoreCollection::iterator active = mActiveCells.begin(); CellStoreCollection::iterator active = mActiveCells.begin();
@ -232,7 +229,6 @@ namespace MWWorld
++numUnload; ++numUnload;
} }
int current = 0;
active = mActiveCells.begin(); active = mActiveCells.begin();
while (active!=mActiveCells.end()) while (active!=mActiveCells.end())
{ {
@ -247,11 +243,10 @@ namespace MWWorld
} }
} }
unloadCell (active++); unloadCell (active++);
++current;
} }
int numLoad = 0; int refsToLoad = 0;
// get the number of cells to load // get the number of refs to load
for (int x=X-1; x<=X+1; ++x) for (int x=X-1; x<=X+1; ++x)
for (int y=Y-1; y<=Y+1; ++y) for (int y=Y-1; y<=Y+1; ++y)
{ {
@ -269,11 +264,12 @@ namespace MWWorld
} }
if (iter==mActiveCells.end()) if (iter==mActiveCells.end())
++numLoad; refsToLoad += countRefs(*MWBase::Environment::get().getWorld()->getExterior(x, y));
} }
loadingListener->setProgressRange(refsToLoad);
// Load cells // Load cells
current = 0;
for (int x=X-1; x<=X+1; ++x) for (int x=X-1; x<=X+1; ++x)
for (int y=Y-1; y<=Y+1; ++y) for (int y=Y-1; y<=Y+1; ++y)
{ {
@ -294,11 +290,7 @@ namespace MWWorld
{ {
CellStore *cell = MWBase::Environment::get().getWorld()->getExterior(x, y); CellStore *cell = MWBase::Environment::get().getWorld()->getExterior(x, y);
//Loading Exterior loading text loadCell (cell, loadingListener);
MWBase::Environment::get().getWindowManager ()->setLoadingProgress (loadingExteriorText, 0, current, numLoad);
loadCell (cell);
++current;
} }
} }
@ -330,7 +322,7 @@ namespace MWWorld
mCellChanged = true; mCellChanged = true;
MWBase::Environment::get().getWindowManager ()->loadingDone (); loadingListener->removeWallpaper();
} }
//We need the ogre renderer and a scene node. //We need the ogre renderer and a scene node.
@ -356,13 +348,14 @@ namespace MWWorld
void Scene::changeToInteriorCell (const std::string& cellName, const ESM::Position& position) void Scene::changeToInteriorCell (const std::string& cellName, const ESM::Position& position)
{ {
MWBase::Environment::get().getWorld ()->getFader ()->fadeOut(0.5); MWBase::Environment::get().getWorld ()->getFader ()->fadeOut(0.5);
const MWWorld::Store<ESM::GameSetting> &gmst =
MWBase::Environment::get().getWorld()->getStore().get<ESM::GameSetting>();
mRendering.enableTerrain(false); mRendering.enableTerrain(false);
std::string loadingInteriorText; Loading::Listener* loadingListener = MWBase::Environment::get().getWindowManager()->getLoadingScreen();
loadingInteriorText = gmst.find ("sLoadingMessage2")->getString(); Loading::ScopedLoad load(loadingListener);
std::string loadingInteriorText = "#{sLoadingMessage2}";
loadingListener->setLabel(loadingInteriorText);
CellStore *cell = MWBase::Environment::get().getWorld()->getInterior(cellName); CellStore *cell = MWBase::Environment::get().getWorld()->getInterior(cellName);
bool loadcell = (mCurrentCell == NULL); bool loadcell = (mCurrentCell == NULL);
@ -406,13 +399,15 @@ namespace MWWorld
++current; ++current;
} }
int refsToLoad = countRefs(*cell);
loadingListener->setProgressRange(refsToLoad);
// Load cell. // Load cell.
std::cout << "cellName: " << cell->mCell->mName << std::endl; std::cout << "cellName: " << cell->mCell->mName << std::endl;
//Loading Interior loading text //Loading Interior loading text
MWBase::Environment::get().getWindowManager ()->setLoadingProgress (loadingInteriorText, 0, 0, 1);
loadCell (cell); loadCell (cell, loadingListener);
mCurrentCell = cell; mCurrentCell = cell;
@ -429,7 +424,7 @@ namespace MWWorld
mCellChanged = true; mCellChanged = true;
MWBase::Environment::get().getWorld ()->getFader ()->fadeIn(0.5); MWBase::Environment::get().getWorld ()->getFader ()->fadeIn(0.5);
MWBase::Environment::get().getWindowManager ()->loadingDone (); loadingListener->removeWallpaper();
} }
void Scene::changeToExteriorCell (const ESM::Position& position) void Scene::changeToExteriorCell (const ESM::Position& position)
@ -454,30 +449,54 @@ namespace MWWorld
mCellChanged = false; mCellChanged = false;
} }
void Scene::insertCell (Ptr::CellStore &cell, bool rescale) int Scene::countRefs (const Ptr::CellStore& cell)
{
return cell.mActivators.mList.size()
+ cell.mPotions.mList.size()
+ cell.mAppas.mList.size()
+ cell.mArmors.mList.size()
+ cell.mBooks.mList.size()
+ cell.mClothes.mList.size()
+ cell.mContainers.mList.size()
+ cell.mDoors.mList.size()
+ cell.mIngreds.mList.size()
+ cell.mCreatureLists.mList.size()
+ cell.mItemLists.mList.size()
+ cell.mLights.mList.size()
+ cell.mLockpicks.mList.size()
+ cell.mMiscItems.mList.size()
+ cell.mProbes.mList.size()
+ cell.mRepairs.mList.size()
+ cell.mStatics.mList.size()
+ cell.mWeapons.mList.size()
+ cell.mCreatures.mList.size()
+ cell.mNpcs.mList.size();
}
void Scene::insertCell (Ptr::CellStore &cell, bool rescale, Loading::Listener* loadingListener)
{ {
// Loop through all references in the cell // Loop through all references in the cell
insertCellRefList(mRendering, cell.mActivators, cell, *mPhysics, rescale); insertCellRefList(mRendering, cell.mActivators, cell, *mPhysics, rescale, loadingListener);
insertCellRefList(mRendering, cell.mPotions, cell, *mPhysics, rescale); insertCellRefList(mRendering, cell.mPotions, cell, *mPhysics, rescale, loadingListener);
insertCellRefList(mRendering, cell.mAppas, cell, *mPhysics, rescale); insertCellRefList(mRendering, cell.mAppas, cell, *mPhysics, rescale, loadingListener);
insertCellRefList(mRendering, cell.mArmors, cell, *mPhysics, rescale); insertCellRefList(mRendering, cell.mArmors, cell, *mPhysics, rescale, loadingListener);
insertCellRefList(mRendering, cell.mBooks, cell, *mPhysics, rescale); insertCellRefList(mRendering, cell.mBooks, cell, *mPhysics, rescale, loadingListener);
insertCellRefList(mRendering, cell.mClothes, cell, *mPhysics, rescale); insertCellRefList(mRendering, cell.mClothes, cell, *mPhysics, rescale, loadingListener);
insertCellRefList(mRendering, cell.mContainers, cell, *mPhysics, rescale); insertCellRefList(mRendering, cell.mContainers, cell, *mPhysics, rescale, loadingListener);
insertCellRefList(mRendering, cell.mDoors, cell, *mPhysics, rescale); insertCellRefList(mRendering, cell.mDoors, cell, *mPhysics, rescale, loadingListener);
insertCellRefList(mRendering, cell.mIngreds, cell, *mPhysics, rescale); insertCellRefList(mRendering, cell.mIngreds, cell, *mPhysics, rescale, loadingListener);
insertCellRefList(mRendering, cell.mCreatureLists, cell, *mPhysics, rescale); insertCellRefList(mRendering, cell.mCreatureLists, cell, *mPhysics, rescale, loadingListener);
insertCellRefList(mRendering, cell.mItemLists, cell, *mPhysics, rescale); insertCellRefList(mRendering, cell.mItemLists, cell, *mPhysics, rescale, loadingListener);
insertCellRefList(mRendering, cell.mLights, cell, *mPhysics, rescale); insertCellRefList(mRendering, cell.mLights, cell, *mPhysics, rescale, loadingListener);
insertCellRefList(mRendering, cell.mLockpicks, cell, *mPhysics, rescale); insertCellRefList(mRendering, cell.mLockpicks, cell, *mPhysics, rescale, loadingListener);
insertCellRefList(mRendering, cell.mMiscItems, cell, *mPhysics, rescale); insertCellRefList(mRendering, cell.mMiscItems, cell, *mPhysics, rescale, loadingListener);
insertCellRefList(mRendering, cell.mProbes, cell, *mPhysics, rescale); insertCellRefList(mRendering, cell.mProbes, cell, *mPhysics, rescale, loadingListener);
insertCellRefList(mRendering, cell.mRepairs, cell, *mPhysics, rescale); insertCellRefList(mRendering, cell.mRepairs, cell, *mPhysics, rescale, loadingListener);
insertCellRefList(mRendering, cell.mStatics, cell, *mPhysics, rescale); insertCellRefList(mRendering, cell.mStatics, cell, *mPhysics, rescale, loadingListener);
insertCellRefList(mRendering, cell.mWeapons, cell, *mPhysics, rescale); insertCellRefList(mRendering, cell.mWeapons, cell, *mPhysics, rescale, loadingListener);
// Load NPCs and creatures _after_ everything else (important for adjustPosition to work correctly) // Load NPCs and creatures _after_ everything else (important for adjustPosition to work correctly)
insertCellRefList(mRendering, cell.mCreatures, cell, *mPhysics, rescale); insertCellRefList(mRendering, cell.mCreatures, cell, *mPhysics, rescale, loadingListener);
insertCellRefList(mRendering, cell.mNpcs, cell, *mPhysics, rescale); insertCellRefList(mRendering, cell.mNpcs, cell, *mPhysics, rescale, loadingListener);
} }
void Scene::addObjectToScene (const Ptr& ptr) void Scene::addObjectToScene (const Ptr& ptr)

View file

@ -56,7 +56,9 @@ namespace MWWorld
void playerCellChange (CellStore *cell, const ESM::Position& position, void playerCellChange (CellStore *cell, const ESM::Position& position,
bool adjustPlayerPos = true); bool adjustPlayerPos = true);
void insertCell (Ptr::CellStore &cell, bool rescale); void insertCell (Ptr::CellStore &cell, bool rescale, Loading::Listener* loadingListener);
int countRefs (const Ptr::CellStore& cell);
public: public:
@ -66,7 +68,7 @@ namespace MWWorld
void unloadCell (CellStoreCollection::iterator iter); void unloadCell (CellStoreCollection::iterator iter);
void loadCell (CellStore *cell); void loadCell (CellStore *cell, Loading::Listener* loadingListener);
void changeCell (int X, int Y, const ESM::Position& position, bool adjustPlayerPos); void changeCell (int X, int Y, const ESM::Position& position, bool adjustPlayerPos);
///< Move from exterior to interior or from interior cell to a different ///< Move from exterior to interior or from interior cell to a different

View file

@ -167,6 +167,11 @@ WeatherManager::WeatherManager(MWRender::RenderingManager* rendering,MWWorld::Fa
setFallbackWeather(blizzard,"blizzard"); setFallbackWeather(blizzard,"blizzard");
} }
WeatherManager::~WeatherManager()
{
stopSounds(true);
}
void WeatherManager::setWeather(const String& weather, bool instant) void WeatherManager::setWeather(const String& weather, bool instant)
{ {
if (weather == mCurrentWeather && mNextWeather == "") if (weather == mCurrentWeather && mNextWeather == "")

View file

@ -120,6 +120,7 @@ namespace MWWorld
{ {
public: public:
WeatherManager(MWRender::RenderingManager*,MWWorld::Fallback* fallback); WeatherManager(MWRender::RenderingManager*,MWWorld::Fallback* fallback);
~WeatherManager();
/** /**
* Change the weather in the specified region * Change the weather in the specified region

View file

@ -184,11 +184,14 @@ namespace MWWorld
int idx = 0; int idx = 0;
// NOTE: We might need to reserve one more for the running game / save. // NOTE: We might need to reserve one more for the running game / save.
mEsm.resize(master.size() + plugins.size()); mEsm.resize(master.size() + plugins.size());
Loading::Listener* listener = MWBase::Environment::get().getWindowManager()->getLoadingScreen();
listener->loadingOn();
for (std::vector<std::string>::size_type i = 0; i < master.size(); i++, idx++) for (std::vector<std::string>::size_type i = 0; i < master.size(); i++, idx++)
{ {
boost::filesystem::path masterPath (fileCollections.getCollection (".esm").getPath (master[i])); boost::filesystem::path masterPath (fileCollections.getCollection (".esm").getPath (master[i]));
std::cout << "Loading ESM " << masterPath.string() << "\n"; std::cout << "Loading ESM " << masterPath.string() << "\n";
listener->setLabel(masterPath.filename().string());
// This parses the ESM file // This parses the ESM file
ESM::ESMReader lEsm; ESM::ESMReader lEsm;
@ -197,7 +200,7 @@ namespace MWWorld
lEsm.setGlobalReaderList(&mEsm); lEsm.setGlobalReaderList(&mEsm);
lEsm.open (masterPath.string()); lEsm.open (masterPath.string());
mEsm[idx] = lEsm; mEsm[idx] = lEsm;
mStore.load (mEsm[idx]); mStore.load (mEsm[idx], listener);
} }
for (std::vector<std::string>::size_type i = 0; i < plugins.size(); i++, idx++) for (std::vector<std::string>::size_type i = 0; i < plugins.size(); i++, idx++)
@ -205,6 +208,7 @@ namespace MWWorld
boost::filesystem::path pluginPath (fileCollections.getCollection (".esp").getPath (plugins[i])); boost::filesystem::path pluginPath (fileCollections.getCollection (".esp").getPath (plugins[i]));
std::cout << "Loading ESP " << pluginPath.string() << "\n"; std::cout << "Loading ESP " << pluginPath.string() << "\n";
listener->setLabel(pluginPath.filename().string());
// This parses the ESP file // This parses the ESP file
ESM::ESMReader lEsm; ESM::ESMReader lEsm;
@ -213,8 +217,9 @@ namespace MWWorld
lEsm.setGlobalReaderList(&mEsm); lEsm.setGlobalReaderList(&mEsm);
lEsm.open (pluginPath.string()); lEsm.open (pluginPath.string());
mEsm[idx] = lEsm; mEsm[idx] = lEsm;
mStore.load (mEsm[idx]); mStore.load (mEsm[idx], listener);
} }
listener->loadingOff();
// insert records that may not be present in all versions of MW // insert records that may not be present in all versions of MW
if (mEsm[0].getFormat() == 0) if (mEsm[0].getFormat() == 0)

View file

@ -11,14 +11,15 @@ if (GTEST_FOUND AND GMOCK_FOUND)
include_directories(${GMOCK_INCLUDE_DIRS}) include_directories(${GMOCK_INCLUDE_DIRS})
file(GLOB UNITTEST_SRC_FILES file(GLOB UNITTEST_SRC_FILES
components/misc/*.cpp components/misc/test_*.cpp
components/file_finder/test_*.cpp
) )
source_group(apps\\openmw_test_suite FILES openmw_test_suite.cpp ${UNITTEST_SRC_FILES}) source_group(apps\\openmw_test_suite FILES openmw_test_suite.cpp ${UNITTEST_SRC_FILES})
add_executable(openmw_test_suite openmw_test_suite.cpp ${UNITTEST_SRC_FILES}) add_executable(openmw_test_suite openmw_test_suite.cpp ${UNITTEST_SRC_FILES})
target_link_libraries(openmw_test_suite ${GMOCK_BOTH_LIBRARIES} ${GTEST_BOTH_LIBRARIES}) target_link_libraries(openmw_test_suite ${GMOCK_BOTH_LIBRARIES} ${GTEST_BOTH_LIBRARIES} components)
# Fix for not visible pthreads functions for linker with glibc 2.15 # Fix for not visible pthreads functions for linker with glibc 2.15
if (UNIX AND NOT APPLE) if (UNIX AND NOT APPLE)
target_link_libraries(openmw_test_suite ${CMAKE_THREAD_LIBS_INIT}) target_link_libraries(openmw_test_suite ${CMAKE_THREAD_LIBS_INIT})

View file

@ -0,0 +1,66 @@
#include <gtest/gtest.h>
#include <fstream>
#include "components/file_finder/file_finder.hpp"
struct FileFinderTest : public ::testing::Test
{
protected:
FileFinderTest()
: mTestDir("./filefinder_test_dir/")
, mTestFile("test.txt")
, mTestFileUppercase("TEST.TXT")
, mTestFileNotFound("foobarbaz.txt")
{
}
virtual void SetUp()
{
boost::filesystem::create_directory(boost::filesystem::path(mTestDir));
std::ofstream ofs(std::string(mTestDir + mTestFile).c_str(), std::ofstream::out);
ofs << std::endl;
ofs.close();
}
virtual void TearDown()
{
boost::filesystem::remove_all(boost::filesystem::path(mTestDir));
}
std::string mTestDir;
std::string mTestFile;
std::string mTestFileUppercase;
std::string mTestFileNotFound;
};
TEST_F(FileFinderTest, FileFinder_has_file)
{
FileFinder::FileFinder fileFinder(mTestDir);
ASSERT_TRUE(fileFinder.has(mTestFile));
ASSERT_TRUE(fileFinder.has(mTestFileUppercase));
ASSERT_TRUE(fileFinder.lookup(mTestFile) == std::string(mTestDir + mTestFile));
ASSERT_TRUE(fileFinder.lookup(mTestFileUppercase) == std::string(mTestDir + mTestFile));
}
TEST_F(FileFinderTest, FileFinder_does_not_have_file)
{
FileFinder::FileFinder fileFinder(mTestDir);
ASSERT_FALSE(fileFinder.has(mTestFileNotFound));
ASSERT_TRUE(fileFinder.lookup(mTestFileNotFound).empty());
}
TEST_F(FileFinderTest, FileFinderStrict_has_file)
{
FileFinder::FileFinderStrict fileFinder(mTestDir);
ASSERT_TRUE(fileFinder.has(mTestFile));
ASSERT_FALSE(fileFinder.has(mTestFileUppercase));
ASSERT_TRUE(fileFinder.lookup(mTestFile) == std::string(mTestDir + mTestFile));
ASSERT_FALSE(fileFinder.lookup(mTestFileUppercase) == std::string(mTestDir + mTestFile));
}
TEST_F(FileFinderTest, FileFinderStrict_does_not_have_file)
{
FileFinder::FileFinderStrict fileFinder(mTestDir);
ASSERT_FALSE(fileFinder.has(mTestFileNotFound));
ASSERT_TRUE(fileFinder.lookup(mTestFileNotFound).empty());
}

View file

@ -0,0 +1,74 @@
#include <gtest/gtest.h>
#include <boost/filesystem.hpp>
#include <fstream>
#include "components/file_finder/search.hpp"
struct SearchTest : public ::testing::Test
{
protected:
SearchTest()
: mTestDir("./search_test_dir/")
{
}
virtual void SetUp()
{
boost::filesystem::create_directory(boost::filesystem::path(mTestDir));
std::ofstream ofs(std::string(mTestDir + "test2.txt").c_str(), std::ofstream::out);
ofs << std::endl;
ofs.close();
}
virtual void TearDown()
{
boost::filesystem::remove_all(boost::filesystem::path(mTestDir));
}
std::string mTestDir;
};
TEST_F(SearchTest, file_not_found)
{
struct Result : public FileFinder::ReturnPath
{
Result(const boost::filesystem::path& expectedPath)
: mExpectedPath(expectedPath)
{
}
void add(const boost::filesystem::path& p)
{
ASSERT_FALSE(p == mExpectedPath);
}
private:
boost::filesystem::path mExpectedPath;
} r(boost::filesystem::path(mTestDir + "test.txt"));
FileFinder::find(mTestDir, r, false);
}
TEST_F(SearchTest, file_found)
{
struct Result : public FileFinder::ReturnPath
{
Result(const boost::filesystem::path& expectedPath)
: mExpectedPath(expectedPath)
{
}
void add(const boost::filesystem::path& p)
{
ASSERT_TRUE(p == mExpectedPath);
}
private:
boost::filesystem::path mExpectedPath;
} r(boost::filesystem::path(mTestDir + "test2.txt"));
FileFinder::find(mTestDir, r, false);
}

View file

@ -0,0 +1,33 @@
#include <gtest/gtest.h>
#include "components/misc/slice_array.hpp"
struct SliceArrayTest : public ::testing::Test
{
protected:
virtual void SetUp()
{
}
virtual void TearDown()
{
}
};
TEST_F(SliceArrayTest, hello_string)
{
Misc::SString s("hello");
ASSERT_EQ(sizeof("hello") - 1, s.length);
ASSERT_FALSE(s=="hel");
ASSERT_FALSE(s=="hell");
ASSERT_TRUE(s=="hello");
}
TEST_F(SliceArrayTest, othello_string_with_offset_2_and_size_4)
{
Misc::SString s("othello" + 2, 4);
ASSERT_EQ(sizeof("hell") - 1, s.length);
ASSERT_FALSE(s=="hel");
ASSERT_TRUE(s=="hell");
ASSERT_FALSE(s=="hello");
}

View file

@ -1,7 +1,79 @@
#include <gtest/gtest.h> #include <gtest/gtest.h>
#include "components/misc/stringops.hpp"
TEST(simple_test, dummy) struct StringOpsTest : public ::testing::Test
{ {
EXPECT_EQ(true, true); protected:
virtual void SetUp()
{
}
virtual void TearDown()
{
}
};
TEST_F(StringOpsTest, begins_matching)
{
ASSERT_TRUE(Misc::begins("abc", "a"));
ASSERT_TRUE(Misc::begins("abc", "ab"));
ASSERT_TRUE(Misc::begins("abc", "abc"));
ASSERT_TRUE(Misc::begins("abcd", "abc"));
}
TEST_F(StringOpsTest, begins_not_matching)
{
ASSERT_FALSE(Misc::begins("abc", "b"));
ASSERT_FALSE(Misc::begins("abc", "bc"));
ASSERT_FALSE(Misc::begins("abc", "bcd"));
ASSERT_FALSE(Misc::begins("abc", "abcd"));
}
TEST_F(StringOpsTest, ibegins_matching)
{
ASSERT_TRUE(Misc::ibegins("Abc", "a"));
ASSERT_TRUE(Misc::ibegins("aBc", "ab"));
ASSERT_TRUE(Misc::ibegins("abC", "abc"));
ASSERT_TRUE(Misc::ibegins("abcD", "abc"));
}
TEST_F(StringOpsTest, ibegins_not_matching)
{
ASSERT_FALSE(Misc::ibegins("abc", "b"));
ASSERT_FALSE(Misc::ibegins("abc", "bc"));
ASSERT_FALSE(Misc::ibegins("abc", "bcd"));
ASSERT_FALSE(Misc::ibegins("abc", "abcd"));
}
TEST_F(StringOpsTest, ends_matching)
{
ASSERT_TRUE(Misc::ends("abc", "c"));
ASSERT_TRUE(Misc::ends("abc", "bc"));
ASSERT_TRUE(Misc::ends("abc", "abc"));
ASSERT_TRUE(Misc::ends("abcd", "abcd"));
}
TEST_F(StringOpsTest, ends_not_matching)
{
ASSERT_FALSE(Misc::ends("abc", "b"));
ASSERT_FALSE(Misc::ends("abc", "ab"));
ASSERT_FALSE(Misc::ends("abc", "bcd"));
ASSERT_FALSE(Misc::ends("abc", "abcd"));
}
TEST_F(StringOpsTest, iends_matching)
{
ASSERT_TRUE(Misc::iends("Abc", "c"));
ASSERT_TRUE(Misc::iends("aBc", "bc"));
ASSERT_TRUE(Misc::iends("abC", "abc"));
ASSERT_TRUE(Misc::iends("abcD", "abcd"));
}
TEST_F(StringOpsTest, iends_not_matching)
{
ASSERT_FALSE(Misc::iends("abc", "b"));
ASSERT_FALSE(Misc::iends("abc", "ab"));
ASSERT_FALSE(Misc::iends("abc", "bcd"));
ASSERT_FALSE(Misc::iends("abc", "abcd"));
} }

View file

@ -5,7 +5,7 @@
int main(int argc, char** argv) { int main(int argc, char** argv) {
// The following line causes Google Mock to throw an exception on failure, // The following line causes Google Mock to throw an exception on failure,
// which will be interpreted by your testing framework as a test failure. // which will be interpreted by your testing framework as a test failure.
::testing::GTEST_FLAG(throw_on_failure) = true; ::testing::GTEST_FLAG(throw_on_failure) = false;
::testing::InitGoogleMock(&argc, argv); ::testing::InitGoogleMock(&argc, argv);
return RUN_ALL_TESTS(); return RUN_ALL_TESTS();

View file

@ -67,7 +67,11 @@ add_component_dir (translation
) )
add_component_dir (terrain add_component_dir (terrain
quadtreenode chunk terrain storage material quadtreenode chunk world storage material
)
add_component_dir (loadinglistener
loadinglistener
) )
find_package(Qt4 COMPONENTS QtCore QtGui) find_package(Qt4 COMPONENTS QtCore QtGui)

View file

@ -70,6 +70,11 @@ public:
void openRaw(const std::string &file); void openRaw(const std::string &file);
/// Get the file size. Make sure that the file has been opened!
size_t getFileSize() { return mEsm->size(); }
/// Get the current position in the file. Make sure that the file has been opened!
size_t getFileOffset() { return mEsm->tell(); }
// This is a quick hack for multiple esm/esp files. Each plugin introduces its own // This is a quick hack for multiple esm/esp files. Each plugin introduces its own
// terrain palette, but ESMReader does not pass a reference to the correct plugin // terrain palette, but ESMReader does not pass a reference to the correct plugin
// to the individual load() methods. This hack allows to pass this reference // to the individual load() methods. This hack allows to pass this reference

View file

@ -11,7 +11,7 @@ namespace ESM
enum VarType enum VarType
{ {
VT_Unknown, VT_Unknown = 0,
VT_None, VT_None,
VT_Short, // stored as a float, kinda VT_Short, // stored as a float, kinda
VT_Int, VT_Int,

View file

@ -0,0 +1,35 @@
#ifndef COMPONENTS_LOADINGLISTENER_H
#define COMPONENTS_LOADINGLISTENER_H
namespace Loading
{
class Listener
{
public:
virtual void setLabel (const std::string& label) = 0;
// Use ScopedLoad instead of using these directly
virtual void loadingOn() = 0;
virtual void loadingOff() = 0;
/// Indicate that some progress has been made, without specifying how much
virtual void indicateProgress () = 0;
virtual void setProgressRange (size_t range) = 0;
virtual void setProgress (size_t value) = 0;
virtual void increaseProgress (size_t increase) = 0;
/// Indicate the scene is now ready to be shown
virtual void removeWallpaper() = 0;
};
// Used for stopping a loading sequence when the object goes out of scope
struct ScopedLoad
{
ScopedLoad(Listener* l) : mListener(l) { mListener->loadingOn(); }
~ScopedLoad() { mListener->loadingOff(); }
Listener* mListener;
};
}
#endif

View file

@ -4,7 +4,7 @@
#include <OgreHardwareBufferManager.h> #include <OgreHardwareBufferManager.h>
#include "quadtreenode.hpp" #include "quadtreenode.hpp"
#include "terrain.hpp" #include "world.hpp"
#include "storage.hpp" #include "storage.hpp"
namespace Terrain namespace Terrain

View file

@ -3,7 +3,7 @@
#include <OgreSceneManager.h> #include <OgreSceneManager.h>
#include <OgreManualObject.h> #include <OgreManualObject.h>
#include "terrain.hpp" #include "world.hpp"
#include "chunk.hpp" #include "chunk.hpp"
#include "storage.hpp" #include "storage.hpp"
@ -13,6 +13,13 @@ using namespace Terrain;
namespace namespace
{ {
int Log2( int n )
{
assert(n > 0);
int targetlevel = 0;
while (n >>= 1) ++targetlevel;
return targetlevel;
}
// Utility functions for neighbour finding algorithm // Utility functions for neighbour finding algorithm
ChildDirection reflect(ChildDirection dir, Direction dir2) ChildDirection reflect(ChildDirection dir, Direction dir2)
@ -132,7 +139,7 @@ namespace
} }
} }
QuadTreeNode::QuadTreeNode(Terrain* terrain, ChildDirection dir, float size, const Ogre::Vector2 &center, QuadTreeNode* parent) QuadTreeNode::QuadTreeNode(World* terrain, ChildDirection dir, float size, const Ogre::Vector2 &center, QuadTreeNode* parent)
: mSize(size) : mSize(size)
, mCenter(center) , mCenter(center)
, mParent(parent) , mParent(parent)
@ -161,7 +168,7 @@ QuadTreeNode::QuadTreeNode(Terrain* terrain, ChildDirection dir, float size, con
pos = mCenter - pos; pos = mCenter - pos;
mSceneNode->setPosition(Ogre::Vector3(pos.x*8192, pos.y*8192, 0)); mSceneNode->setPosition(Ogre::Vector3(pos.x*8192, pos.y*8192, 0));
mLodLevel = log2(mSize); mLodLevel = Log2(mSize);
mMaterialGenerator = new MaterialGenerator(mTerrain->getShadersEnabled()); mMaterialGenerator = new MaterialGenerator(mTerrain->getShadersEnabled());
} }
@ -220,7 +227,7 @@ const Ogre::AxisAlignedBox& QuadTreeNode::getBoundingBox()
return mBounds; return mBounds;
} }
void QuadTreeNode::update(const Ogre::Vector3 &cameraPos) void QuadTreeNode::update(const Ogre::Vector3 &cameraPos, Loading::Listener* loadingListener)
{ {
const Ogre::AxisAlignedBox& bounds = getBoundingBox(); const Ogre::AxisAlignedBox& bounds = getBoundingBox();
if (bounds.isNull()) if (bounds.isNull())
@ -254,6 +261,9 @@ void QuadTreeNode::update(const Ogre::Vector3 &cameraPos)
bool hadChunk = hasChunk(); bool hadChunk = hasChunk();
if (loadingListener)
loadingListener->indicateProgress();
if (!distantLand && dist > 8192*2) if (!distantLand && dist > 8192*2)
{ {
if (mIsActive) if (mIsActive)
@ -341,7 +351,7 @@ void QuadTreeNode::update(const Ogre::Vector3 &cameraPos)
} }
assert(hasChildren() && "Leaf node's LOD needs to be 0"); assert(hasChildren() && "Leaf node's LOD needs to be 0");
for (int i=0; i<4; ++i) for (int i=0; i<4; ++i)
mChildren[i]->update(cameraPos); mChildren[i]->update(cameraPos, loadingListener);
} }
} }

Some files were not shown because too many files have changed in this diff Show more