1
0
Fork 1
mirror of https://github.com/TES3MP/openmw-tes3mp.git synced 2025-02-01 21:15:33 +00:00

Merge remote-tracking branch 'refs/remotes/master/master' into NonTableFields

This commit is contained in:
Marek Kochanowicz 2014-06-30 20:06:44 +02:00
commit 172f1a1301
307 changed files with 7096 additions and 2714 deletions

2
.gitignore vendored
View file

@ -41,7 +41,7 @@ resources
## generated objects
apps/openmw/config.hpp
components/version/version.hpp
Docs/mainpage.hpp
docs/mainpage.hpp
moc_*.cxx
*.cxx_parameters
*qrc_launcher.cxx

View file

@ -56,7 +56,7 @@ include(OpenMWMacros)
# doxygen main page
configure_file ("${OpenMW_SOURCE_DIR}/Docs/mainpage.hpp.cmake" "${OpenMW_SOURCE_DIR}/Docs/mainpage.hpp")
configure_file ("${OpenMW_SOURCE_DIR}/docs/mainpage.hpp.cmake" "${OpenMW_SOURCE_DIR}/docs/mainpage.hpp")
option(MYGUI_STATIC "Link static build of Mygui into the binaries" FALSE)
option(OGRE_STATIC "Link static build of Ogre and Ogre Plugins into the binaries" FALSE)
@ -80,13 +80,6 @@ option(USE_FFMPEG "use ffmpeg for sound" ON)
# OS X deployment
option(OPENMW_OSX_DEPLOYMENT OFF)
if(UNIX AND NOT APPLE)
option(BUILD_WITH_DPKG "enable dpkg-based install for debian and debian derivatives" OFF)
if(BUILD_WITH_DPKG)
find_program(DPKG_PROGRAM dpkg DOC "dpkg program of Debian-based systems")
endif(BUILD_WITH_DPKG)
endif(UNIX AND NOT APPLE)
# Location of morrowind data files
if (APPLE)
set(MORROWIND_DATA_FILES "./data" CACHE PATH "location of Morrowind data files")
@ -395,46 +388,36 @@ if (CMAKE_COMPILER_IS_GNUCC)
endif (CMAKE_COMPILER_IS_GNUCC)
IF(NOT WIN32 AND NOT APPLE)
## Debian and non debian Linux building
# Linux building
# Paths
IF (DPKG_PROGRAM)
## Debian specific
SET(CMAKE_INSTALL_PREFIX "/usr")
SET(DATAROOTDIR "share" CACHE PATH "Sets the root of data directories to a non-default location")
SET(DATADIR "share/games/openmw" CACHE PATH "Sets the openmw data directories to a non-default location")
SET(ICONDIR "share/pixmaps" CACHE PATH "Set icon dir")
SET(SYSCONFDIR "../etc/openmw" CACHE PATH "Set config dir")
ELSE ()
## Non debian specific
SET(BINDIR "${CMAKE_INSTALL_PREFIX}/bin" CACHE PATH "Where to install binaries")
SET(DATAROOTDIR "${CMAKE_INSTALL_PREFIX}/share" CACHE PATH "Sets the root of data directories to a non-default location")
SET(DATADIR "${DATAROOTDIR}/games/openmw" CACHE PATH "Sets the openmw data directories to a non-default location")
SET(ICONDIR "${DATAROOTDIR}/pixmaps" CACHE PATH "Set icon dir")
SET(LICDIR "${DATAROOTDIR}/licenses/openmw" CACHE PATH "Sets the openmw license directory to a non-default location.")
SET(SYSCONFDIR "/etc/openmw" CACHE PATH "Set config dir")
SET(BINDIR "${CMAKE_INSTALL_PREFIX}/bin" CACHE PATH "Where to install binaries")
SET(DATAROOTDIR "${CMAKE_INSTALL_PREFIX}/share" CACHE PATH "Sets the root of data directories to a non-default location")
SET(DATADIR "${DATAROOTDIR}/games/openmw" CACHE PATH "Sets the openmw data directories to a non-default location")
SET(ICONDIR "${DATAROOTDIR}/pixmaps" CACHE PATH "Set icon dir")
SET(LICDIR "${DATAROOTDIR}/licenses/openmw" CACHE PATH "Sets the openmw license directory to a non-default location.")
SET(SYSCONFDIR "/etc/openmw" CACHE PATH "Set config dir")
# Install binaries
INSTALL(PROGRAMS "${OpenMW_BINARY_DIR}/openmw" DESTINATION "${BINDIR}" )
IF(BUILD_LAUNCHER)
INSTALL(PROGRAMS "${OpenMW_BINARY_DIR}/omwlauncher" DESTINATION "${BINDIR}" )
ENDIF(BUILD_LAUNCHER)
IF(BUILD_BSATOOL)
INSTALL(PROGRAMS "${OpenMW_BINARY_DIR}/bsatool" DESTINATION "${BINDIR}" )
ENDIF(BUILD_BSATOOL)
IF(BUILD_ESMTOOL)
INSTALL(PROGRAMS "${OpenMW_BINARY_DIR}/esmtool" DESTINATION "${BINDIR}" )
ENDIF(BUILD_ESMTOOL)
IF(BUILD_MWINIIMPORTER)
INSTALL(PROGRAMS "${OpenMW_BINARY_DIR}/mwiniimport" DESTINATION "${BINDIR}" )
ENDIF(BUILD_MWINIIMPORTER)
IF(BUILD_OPENCS)
INSTALL(PROGRAMS "${OpenMW_BINARY_DIR}/opencs" DESTINATION "${BINDIR}" )
ENDIF(BUILD_OPENCS)
# Install binaries
INSTALL(PROGRAMS "${OpenMW_BINARY_DIR}/openmw" DESTINATION "${BINDIR}" )
IF(BUILD_LAUNCHER)
INSTALL(PROGRAMS "${OpenMW_BINARY_DIR}/omwlauncher" DESTINATION "${BINDIR}" )
ENDIF(BUILD_LAUNCHER)
IF(BUILD_BSATOOL)
INSTALL(PROGRAMS "${OpenMW_BINARY_DIR}/bsatool" DESTINATION "${BINDIR}" )
ENDIF(BUILD_BSATOOL)
IF(BUILD_ESMTOOL)
INSTALL(PROGRAMS "${OpenMW_BINARY_DIR}/esmtool" DESTINATION "${BINDIR}" )
ENDIF(BUILD_ESMTOOL)
IF(BUILD_MWINIIMPORTER)
INSTALL(PROGRAMS "${OpenMW_BINARY_DIR}/mwiniimport" DESTINATION "${BINDIR}" )
ENDIF(BUILD_MWINIIMPORTER)
IF(BUILD_OPENCS)
INSTALL(PROGRAMS "${OpenMW_BINARY_DIR}/opencs" DESTINATION "${BINDIR}" )
ENDIF(BUILD_OPENCS)
# Install licenses
INSTALL(FILES "DejaVu Font License.txt" DESTINATION "${LICDIR}" )
INSTALL(FILES "extern/shiny/License.txt" DESTINATION "${LICDIR}" RENAME "Shiny License.txt" )
ENDIF (DPKG_PROGRAM)
# Install licenses
INSTALL(FILES "docs/license/DejaVu Font License.txt" DESTINATION "${LICDIR}" )
INSTALL(FILES "extern/shiny/License.txt" DESTINATION "${LICDIR}" RENAME "Shiny License.txt" )
# Install icon and desktop file
INSTALL(FILES "${OpenMW_BINARY_DIR}/openmw.desktop" DESTINATION "${DATAROOTDIR}/applications" PERMISSIONS OWNER_READ OWNER_WRITE GROUP_READ WORLD_READ COMPONENT "openmw")
@ -463,8 +446,8 @@ if(WIN32)
INSTALL(FILES "${OpenMW_BINARY_DIR}/openmw.cfg.install" DESTINATION "." RENAME "openmw.cfg")
INSTALL(FILES
"${OpenMW_SOURCE_DIR}/readme.txt"
"${OpenMW_SOURCE_DIR}/GPL3.txt"
"${OpenMW_SOURCE_DIR}/DejaVu Font License.txt"
"${OpenMW_SOURCE_DIR}/Docs/license/GPL3.txt"
"${OpenMW_SOURCE_DIR}/Docs/license/DejaVu Font License.txt"
"${OpenMW_BINARY_DIR}/settings-default.cfg"
"${OpenMW_BINARY_DIR}/transparency-overrides.cfg"
"${OpenMW_BINARY_DIR}/Release/openmw.exe"
@ -630,8 +613,10 @@ if (WIN32)
4127 # Conditional expression is constant
4242 # Storing value in a variable of a smaller type, possible loss of data
4244 # Storing value of one type in variable of another (size_t in int, for example)
4267 # Conversion from 'size_t' to 'int', possible loss of data
4305 # Truncating value (double to float, for example)
4309 # Variable overflow, trying to store 128 in a signed char for example
4351 # New behavior: elements of array 'array' will be default initialized (desired behavior)
4355 # Using 'this' in member initialization list
4505 # Unreferenced local function has been removed
4701 # Potentially uninitialized local variable used
@ -650,7 +635,9 @@ if (WIN32)
set(SHINY_OGRE_WARNINGS "${WARNINGS} /wd4101")
set_target_properties(shiny.OgrePlatform PROPERTIES COMPILE_FLAGS ${SHINY_OGRE_WARNINGS})
set_target_properties(sdl4ogre PROPERTIES COMPILE_FLAGS ${WARNINGS})
set_target_properties(oics PROPERTIES COMPILE_FLAGS ${WARNINGS})
# oics uses tinyxml, which has an initialized but unused variable
set(OICS_WARNINGS "${WARNINGS} /wd4189")
set_target_properties(oics PROPERTIES COMPILE_FLAGS ${OICS_WARNINGS})
set_target_properties(components PROPERTIES COMPILE_FLAGS ${WARNINGS})
if (BUILD_LAUNCHER)
set_target_properties(omwlauncher PROPERTIES COMPILE_FLAGS ${WARNINGS})

View file

@ -682,13 +682,11 @@ void Record<ESM::Faction>::print()
{
std::cout << " Name: " << mData.mName << std::endl;
std::cout << " Hidden: " << mData.mData.mIsHidden << std::endl;
if (mData.mData.mUnknown != -1)
std::cout << " Unknown: " << mData.mData.mUnknown << std::endl;
std::cout << " Attribute1: " << attributeLabel(mData.mData.mAttribute[0])
<< " (" << mData.mData.mAttribute[0] << ")" << std::endl;
std::cout << " Attribute2: " << attributeLabel(mData.mData.mAttribute[1])
<< " (" << mData.mData.mAttribute[1] << ")" << std::endl;
for (int i = 0; i != 6; i++)
for (int i = 0; i < 7; i++)
if (mData.mData.mSkills[i] != -1)
std::cout << " Skill: " << skillLabel(mData.mData.mSkills[i])
<< " (" << mData.mData.mSkills[i] << ")" << std::endl;

View file

@ -119,10 +119,6 @@ endif(NOT WIN32)
if(DPKG_PROGRAM)
INSTALL(TARGETS omwlauncher RUNTIME DESTINATION games COMPONENT omwlauncher)
endif()
if (BUILD_WITH_CODE_COVERAGE)
add_definitions (--coverage)
target_link_libraries(omwlauncher gcov)

View file

@ -22,8 +22,3 @@ if (BUILD_WITH_CODE_COVERAGE)
add_definitions (--coverage)
target_link_libraries(mwiniimport gcov)
endif()
if(DPKG_PROGRAM)
INSTALL(TARGETS mwiniimport RUNTIME DESTINATION games COMPONENT mwiniimport)
endif()

View file

@ -71,7 +71,7 @@ opencs_units (view/render
opencs_units_noqt (view/render
navigation navigation1st navigationfree navigationorbit lighting lightingday lightingnight
lightingbright
lightingbright object cell
)
opencs_units_noqt (view/world
@ -200,10 +200,6 @@ target_link_libraries(opencs
components
)
if(DPKG_PROGRAM)
INSTALL(TARGETS opencs RUNTIME DESTINATION games COMPONENT opencs)
endif()
if(APPLE)
INSTALL(TARGETS opencs BUNDLE DESTINATION OpenMW COMPONENT BUNDLE)
endif()

View file

@ -31,8 +31,8 @@ CSMDoc::DocumentManager::DocumentManager (const Files::ConfigurationManager& con
&mLoader, SLOT (loadDocument (CSMDoc::Document *)));
connect (&mLoader, SIGNAL (nextStage (CSMDoc::Document *, const std::string&, int)),
this, SIGNAL (nextStage (CSMDoc::Document *, const std::string&, int)));
connect (&mLoader, SIGNAL (nextRecord (CSMDoc::Document *)),
this, SIGNAL (nextRecord (CSMDoc::Document *)));
connect (&mLoader, SIGNAL (nextRecord (CSMDoc::Document *, int)),
this, SIGNAL (nextRecord (CSMDoc::Document *, int)));
connect (this, SIGNAL (cancelLoading (CSMDoc::Document *)),
&mLoader, SLOT (abortLoading (CSMDoc::Document *)));
connect (&mLoader, SIGNAL (loadMessage (CSMDoc::Document *, const std::string&)),

View file

@ -79,9 +79,10 @@ namespace CSMDoc
void loadingStopped (CSMDoc::Document *document, bool completed,
const std::string& error);
void nextStage (CSMDoc::Document *document, const std::string& name, int steps);
void nextStage (CSMDoc::Document *document, const std::string& name,
int totalRecords);
void nextRecord (CSMDoc::Document *document);
void nextRecord (CSMDoc::Document *document, int records);
void cancelLoading (CSMDoc::Document *document);

View file

@ -8,7 +8,7 @@
#include "document.hpp"
#include "state.hpp"
CSMDoc::Loader::Stage::Stage() : mFile (0), mRecordsLeft (false) {}
CSMDoc::Loader::Stage::Stage() : mFile (0), mRecordsLoaded (0), mRecordsLeft (false) {}
CSMDoc::Loader::Loader()
@ -39,13 +39,14 @@ void CSMDoc::Loader::load()
Document *document = iter->first;
int size = static_cast<int> (document->getContentFiles().size());
int editedIndex = size-1; // index of the file to be edited/created
if (document->isNew())
--size;
bool done = false;
const int batchingSize = 100;
const int batchingSize = 50;
try
{
@ -58,17 +59,21 @@ void CSMDoc::Loader::load()
iter->second.mRecordsLeft = false;
break;
}
else
++(iter->second.mRecordsLoaded);
CSMWorld::UniversalId log (CSMWorld::UniversalId::Type_LoadErrorLog, 0);
{ // silence a g++ warning
for (CSMDoc::Stage::Messages::const_iterator iter (messages.begin());
iter!=messages.end(); ++iter)
{
document->getReport (log)->add (iter->first, iter->second);
emit loadMessage (document, iter->second);
}
}
emit nextRecord (document);
emit nextRecord (document, iter->second.mRecordsLoaded);
return;
}
@ -77,17 +82,19 @@ void CSMDoc::Loader::load()
{
boost::filesystem::path path = document->getContentFiles()[iter->second.mFile];
int steps = document->getData().startLoading (path, iter->second.mFile<size-1, false);
int steps = document->getData().startLoading (path, iter->second.mFile!=editedIndex, false);
iter->second.mRecordsLeft = true;
iter->second.mRecordsLoaded = 0;
emit nextStage (document, path.filename().string(), steps/batchingSize);
emit nextStage (document, path.filename().string(), steps);
}
else if (iter->second.mFile==size)
{
int steps = document->getData().startLoading (document->getProjectPath(), false, true);
iter->second.mRecordsLeft = true;
iter->second.mRecordsLoaded = 0;
emit nextStage (document, "Project File", steps/batchingSize);
emit nextStage (document, "Project File", steps);
}
else
{

View file

@ -18,6 +18,7 @@ namespace CSMDoc
struct Stage
{
int mFile;
int mRecordsLoaded;
bool mRecordsLeft;
Stage();
@ -56,9 +57,10 @@ namespace CSMDoc
///< Document load has been interrupted either because of a call to abortLoading
/// or a problem during loading). In the former case error will be an empty string.
void nextStage (CSMDoc::Document *document, const std::string& name, int steps);
void nextStage (CSMDoc::Document *document, const std::string& name,
int totalRecords);
void nextRecord (CSMDoc::Document *document);
void nextRecord (CSMDoc::Document *document, int records);
///< \note This signal is only given once per group of records. The group size is
/// approximately the total number of records divided by the steps value of the
/// previous nextStage signal.

View file

@ -42,7 +42,7 @@ void CSMTools::FactionCheckStage::perform (int stage, Messages& messages)
// test for non-unique skill
std::map<int, int> skills; // ID, number of occurrences
for (int i=0; i<6; ++i)
for (int i=0; i<7; ++i)
if (faction.mData.mSkills[i]!=-1)
++skills[faction.mData.mSkills[i]];
@ -54,4 +54,4 @@ void CSMTools::FactionCheckStage::perform (int stage, Messages& messages)
}
/// \todo check data members that can't be edited in the table view
}
}

View file

@ -217,7 +217,7 @@ namespace CSMWorld
bool hasEnums (ColumnId column);
std::vector<std::string> getEnums (ColumnId column);
///< Returns an empty vector, if \æ column isn't an enum type column.
///< Returns an empty vector, if \a column isn't an enum type column.
}
}

View file

@ -1,6 +1,10 @@
#include "commanddispatcher.hpp"
#include <algorithm>
#include <components/misc/stringops.hpp>
#include "../doc/document.hpp"
#include "idtable.hpp"
@ -88,6 +92,13 @@ void CSMWorld::CommandDispatcher::setEditLock (bool locked)
void CSMWorld::CommandDispatcher::setSelection (const std::vector<std::string>& selection)
{
mSelection = selection;
std::for_each (mSelection.begin(), mSelection.end(), Misc::StringUtils::toLower);
std::sort (mSelection.begin(), mSelection.end());
}
void CSMWorld::CommandDispatcher::setExtendedTypes (const std::vector<UniversalId>& types)
{
mExtendedTypes = types;
}
bool CSMWorld::CommandDispatcher::canDelete() const
@ -106,6 +117,20 @@ bool CSMWorld::CommandDispatcher::canRevert() const
return getRevertableRecords().size()!=0;
}
std::vector<CSMWorld::UniversalId> CSMWorld::CommandDispatcher::getExtendedTypes() const
{
std::vector<CSMWorld::UniversalId> tables;
if (mId==UniversalId::Type_Cells)
{
tables.push_back (mId);
tables.push_back (UniversalId::Type_References);
/// \todo add other cell-specific types
}
return tables;
}
void CSMWorld::CommandDispatcher::executeDelete()
{
if (mLocked)
@ -163,3 +188,80 @@ void CSMWorld::CommandDispatcher::executeRevert()
if (rows.size()>1)
mDocument.getUndoStack().endMacro();
}
void CSMWorld::CommandDispatcher::executeExtendedDelete()
{
if (mExtendedTypes.size()>1)
mDocument.getUndoStack().beginMacro (tr ("Extended delete of multiple records"));
for (std::vector<UniversalId>::const_iterator iter (mExtendedTypes.begin());
iter!=mExtendedTypes.end(); ++iter)
{
if (*iter==mId)
executeDelete();
else if (*iter==UniversalId::Type_References)
{
IdTable& model = dynamic_cast<IdTable&> (
*mDocument.getData().getTableModel (*iter));
const RefCollection& collection = mDocument.getData().getReferences();
int size = collection.getSize();
for (int i=size-1; i>=0; --i)
{
const Record<CellRef>& record = collection.getRecord (i);
if (record.mState==RecordBase::State_Deleted)
continue;
if (!std::binary_search (mSelection.begin(), mSelection.end(),
Misc::StringUtils::lowerCase (record.get().mCell)))
continue;
mDocument.getUndoStack().push (
new CSMWorld::DeleteCommand (model, record.get().mId));
}
}
}
if (mExtendedTypes.size()>1)
mDocument.getUndoStack().endMacro();
}
void CSMWorld::CommandDispatcher::executeExtendedRevert()
{
if (mExtendedTypes.size()>1)
mDocument.getUndoStack().beginMacro (tr ("Extended revert of multiple records"));
for (std::vector<UniversalId>::const_iterator iter (mExtendedTypes.begin());
iter!=mExtendedTypes.end(); ++iter)
{
if (*iter==mId)
executeRevert();
else if (*iter==UniversalId::Type_References)
{
IdTable& model = dynamic_cast<IdTable&> (
*mDocument.getData().getTableModel (*iter));
const RefCollection& collection = mDocument.getData().getReferences();
int size = collection.getSize();
for (int i=size-1; i>=0; --i)
{
const Record<CellRef>& record = collection.getRecord (i);
if (!std::binary_search (mSelection.begin(), mSelection.end(),
Misc::StringUtils::lowerCase (record.get().mCell)))
continue;
mDocument.getUndoStack().push (
new CSMWorld::RevertCommand (model, record.get().mId));
}
}
}
if (mExtendedTypes.size()>1)
mDocument.getUndoStack().endMacro();
}

View file

@ -22,6 +22,7 @@ namespace CSMWorld
CSMDoc::Document& mDocument;
UniversalId mId;
std::vector<std::string> mSelection;
std::vector<UniversalId> mExtendedTypes;
std::vector<std::string> getDeletableRecords() const;
@ -37,16 +38,31 @@ namespace CSMWorld
void setSelection (const std::vector<std::string>& selection);
void setExtendedTypes (const std::vector<UniversalId>& types);
///< Set record lists selected by the user for extended operations.
bool canDelete() const;
bool canRevert() const;
/// Return IDs of the record collection that can also be affected when
/// operating on the record collection this dispatcher is used for.
///
/// \note The returned collection contains the ID of the record collection this
/// dispatcher is used for. However if that record collection does not support
/// the extended mode, the returned vector will be empty instead.
std::vector<UniversalId> getExtendedTypes() const;
public slots:
void executeDelete();
void executeRevert();
void executeExtendedDelete();
void executeExtendedRevert();
};
}

View file

@ -102,7 +102,7 @@ CSMWorld::Data::Data (ToUTF8::FromType encoding)
mFactions.addColumn (new AttributesColumn<ESM::Faction> (0));
mFactions.addColumn (new AttributesColumn<ESM::Faction> (1));
mFactions.addColumn (new HiddenColumn<ESM::Faction>);
for (int i=0; i<6; ++i)
for (int i=0; i<7; ++i)
mFactions.addColumn (new SkillsColumn<ESM::Faction> (i));
mRaces.addColumn (new StringIdColumn<ESM::Race>);
@ -742,4 +742,4 @@ void CSMWorld::Data::dataChanged (const QModelIndex& topLeft, const QModelIndex&
void CSMWorld::Data::rowsChanged (const QModelIndex& parent, int start, int end)
{
emit idListChanged();
}
}

View file

@ -45,7 +45,7 @@ CSMWorld::RefIdCollection::RefIdCollection()
ColumnBase::Flag_Table | ColumnBase::Flag_Dialogue, false, false));
baseColumns.mId = &mColumns.back();
mColumns.push_back (RefIdColumn (Columns::ColumnId_Modification, ColumnBase::Display_RecordState,
ColumnBase::Flag_Table | ColumnBase::Flag_Dialogue, false, false));
ColumnBase::Flag_Table | ColumnBase::Flag_Dialogue, true, false));
baseColumns.mModified = &mColumns.back();
mColumns.push_back (RefIdColumn (Columns::ColumnId_RecordType, ColumnBase::Display_RefRecordType,
ColumnBase::Flag_Table | ColumnBase::Flag_Dialogue, false, false));

View file

@ -45,7 +45,7 @@ CSVDoc::LoadingDocument::LoadingDocument (CSMDoc::Document *document)
mFileProgress->setValue (0);
// record progress
mLayout->addWidget (new QLabel ("Records", this));
mLayout->addWidget (mRecords = new QLabel ("Records", this));
mRecordProgress = new QProgressBar (this);
@ -75,22 +75,30 @@ CSVDoc::LoadingDocument::LoadingDocument (CSMDoc::Document *document)
connect (mButtons, SIGNAL (rejected()), this, SLOT (cancel()));
}
void CSVDoc::LoadingDocument::nextStage (const std::string& name, int steps)
void CSVDoc::LoadingDocument::nextStage (const std::string& name, int totalRecords)
{
mFile->setText (QString::fromUtf8 (("Loading: " + name).c_str()));
mFileProgress->setValue (mFileProgress->value()+1);
mRecordProgress->setValue (0);
mRecordProgress->setMaximum (steps>0 ? steps : 1);
mRecordProgress->setMaximum (totalRecords>0 ? totalRecords : 1);
mTotalRecords = totalRecords;
}
void CSVDoc::LoadingDocument::nextRecord()
void CSVDoc::LoadingDocument::nextRecord (int records)
{
int value = mRecordProgress->value()+1;
if (records<=mTotalRecords)
{
mRecordProgress->setValue (records);
if (value<=mRecordProgress->maximum())
mRecordProgress->setValue (value);
std::ostringstream stream;
stream << "Records: " << records << " of " << mTotalRecords;
mRecords->setText (QString::fromUtf8 (stream.str().c_str()));
}
}
void CSVDoc::LoadingDocument::abort (const std::string& error)
@ -168,20 +176,21 @@ void CSVDoc::Loader::loadingStopped (CSMDoc::Document *document, bool completed,
}
}
void CSVDoc::Loader::nextStage (CSMDoc::Document *document, const std::string& name, int steps)
void CSVDoc::Loader::nextStage (CSMDoc::Document *document, const std::string& name,
int totalRecords)
{
std::map<CSMDoc::Document *, LoadingDocument *>::iterator iter = mDocuments.find (document);
if (iter!=mDocuments.end())
iter->second->nextStage (name, steps);
iter->second->nextStage (name, totalRecords);
}
void CSVDoc::Loader::nextRecord (CSMDoc::Document *document)
void CSVDoc::Loader::nextRecord (CSMDoc::Document *document, int records)
{
std::map<CSMDoc::Document *, LoadingDocument *>::iterator iter = mDocuments.find (document);
if (iter!=mDocuments.end())
iter->second->nextRecord();
iter->second->nextRecord (records);
}
void CSVDoc::Loader::loadMessage (CSMDoc::Document *document, const std::string& message)

View file

@ -26,6 +26,7 @@ namespace CSVDoc
CSMDoc::Document *mDocument;
QLabel *mFile;
QLabel *mRecords;
QProgressBar *mFileProgress;
QProgressBar *mRecordProgress;
bool mAborted;
@ -33,6 +34,7 @@ namespace CSVDoc
QLabel *mError;
QListWidget *mMessages;
QVBoxLayout *mLayout;
int mTotalRecords;
private:
@ -42,9 +44,9 @@ namespace CSVDoc
LoadingDocument (CSMDoc::Document *document);
void nextStage (const std::string& name, int steps);
void nextStage (const std::string& name, int totalRecords);
void nextRecord();
void nextRecord (int records);
void abort (const std::string& error);
@ -88,9 +90,9 @@ namespace CSVDoc
void loadingStopped (CSMDoc::Document *document, bool completed,
const std::string& error);
void nextStage (CSMDoc::Document *document, const std::string& name, int steps);
void nextStage (CSMDoc::Document *document, const std::string& name, int totalRecords);
void nextRecord (CSMDoc::Document *document);
void nextRecord (CSMDoc::Document *document, int records);
void loadMessage (CSMDoc::Document *document, const std::string& message);
};

View file

@ -97,8 +97,8 @@ CSVDoc::ViewManager::ViewManager (CSMDoc::DocumentManager& documentManager)
&mLoader, SLOT (nextStage (CSMDoc::Document *, const std::string&, int)));
connect (
&mDocumentManager, SIGNAL (nextRecord (CSMDoc::Document *)),
&mLoader, SLOT (nextRecord (CSMDoc::Document *)));
&mDocumentManager, SIGNAL (nextRecord (CSMDoc::Document *, int)),
&mLoader, SLOT (nextRecord (CSMDoc::Document *, int)));
connect (
&mDocumentManager, SIGNAL (loadMessage (CSMDoc::Document *, const std::string&)),

View file

@ -35,7 +35,11 @@ void CSVFilter::FilterBox::setRecordFilter (const std::string& filter)
void CSVFilter::FilterBox::dropEvent (QDropEvent* event)
{
std::vector<CSMWorld::UniversalId> data = dynamic_cast<const CSMWorld::TableMimeData*> (event->mimeData())->getData();
const CSMWorld::TableMimeData* mime = dynamic_cast<const CSMWorld::TableMimeData*> (event->mimeData());
if (!mime) // May happen when non-records (e.g. plain text) are dragged and dropped
return;
std::vector<CSMWorld::UniversalId> data = mime->getData();
emit recordDropped(data, event->proposedAction());
}
@ -54,4 +58,4 @@ void CSVFilter::FilterBox::createFilterRequest (std::vector< std::pair< std::str
Qt::DropAction action)
{
mRecordFilterBox->createFilterRequest(filterSource, action);
}
}

View file

@ -0,0 +1,201 @@
#include "cell.hpp"
#include <OgreSceneManager.h>
#include <OgreSceneNode.h>
#include <components/misc/stringops.hpp>
#include "../../model/world/idtable.hpp"
#include "../../model/world/columns.hpp"
#include "../../model/world/data.hpp"
bool CSVRender::Cell::removeObject (const std::string& id)
{
std::map<std::string, Object *>::iterator iter =
mObjects.find (Misc::StringUtils::lowerCase (id));
if (iter==mObjects.end())
return false;
delete iter->second;
mObjects.erase (iter);
return true;
}
bool CSVRender::Cell::addObjects (int start, int end)
{
CSMWorld::IdTable& references = dynamic_cast<CSMWorld::IdTable&> (
*mData.getTableModel (CSMWorld::UniversalId::Type_References));
int idColumn = references.findColumnIndex (CSMWorld::Columns::ColumnId_Id);
int cellColumn = references.findColumnIndex (CSMWorld::Columns::ColumnId_Cell);
int stateColumn = references.findColumnIndex (CSMWorld::Columns::ColumnId_Modification);
bool modified = false;
for (int i=start; i<=end; ++i)
{
std::string cell = Misc::StringUtils::lowerCase (references.data (
references.index (i, cellColumn)).toString().toUtf8().constData());
int state = references.data (references.index (i, stateColumn)).toInt();
if (cell==mId && state!=CSMWorld::RecordBase::State_Deleted)
{
std::string id = Misc::StringUtils::lowerCase (references.data (
references.index (i, idColumn)).toString().toUtf8().constData());
mObjects.insert (std::make_pair (id, new Object (mData, mCellNode, id, false)));
modified = true;
}
}
return modified;
}
CSVRender::Cell::Cell (CSMWorld::Data& data, Ogre::SceneManager *sceneManager,
const std::string& id, const Ogre::Vector3& origin)
: mData (data), mId (Misc::StringUtils::lowerCase (id))
{
mCellNode = sceneManager->getRootSceneNode()->createChildSceneNode();
mCellNode->setPosition (origin);
CSMWorld::IdTable& references = dynamic_cast<CSMWorld::IdTable&> (
*mData.getTableModel (CSMWorld::UniversalId::Type_References));
int rows = references.rowCount();
addObjects (0, rows-1);
}
CSVRender::Cell::~Cell()
{
for (std::map<std::string, Object *>::iterator iter (mObjects.begin());
iter!=mObjects.end(); ++iter)
delete iter->second;
mCellNode->getCreator()->destroySceneNode (mCellNode);
}
bool CSVRender::Cell::referenceableDataChanged (const QModelIndex& topLeft,
const QModelIndex& bottomRight)
{
bool modified = false;
for (std::map<std::string, Object *>::iterator iter (mObjects.begin());
iter!=mObjects.end(); ++iter)
if (iter->second->referenceableDataChanged (topLeft, bottomRight))
modified = true;
return modified;
}
bool CSVRender::Cell::referenceableAboutToBeRemoved (const QModelIndex& parent, int start,
int end)
{
if (parent.isValid())
return false;
bool modified = false;
for (std::map<std::string, Object *>::iterator iter (mObjects.begin());
iter!=mObjects.end(); ++iter)
if (iter->second->referenceableAboutToBeRemoved (parent, start, end))
modified = true;
return modified;
}
bool CSVRender::Cell::referenceDataChanged (const QModelIndex& topLeft,
const QModelIndex& bottomRight)
{
CSMWorld::IdTable& references = dynamic_cast<CSMWorld::IdTable&> (
*mData.getTableModel (CSMWorld::UniversalId::Type_References));
int idColumn = references.findColumnIndex (CSMWorld::Columns::ColumnId_Id);
int cellColumn = references.findColumnIndex (CSMWorld::Columns::ColumnId_Cell);
int stateColumn = references.findColumnIndex (CSMWorld::Columns::ColumnId_Modification);
// list IDs in cell
std::map<std::string, bool> ids; // id, deleted state
for (int i=topLeft.row(); i<=bottomRight.row(); ++i)
{
std::string cell = Misc::StringUtils::lowerCase (references.data (
references.index (i, cellColumn)).toString().toUtf8().constData());
if (cell==mId)
{
std::string id = Misc::StringUtils::lowerCase (references.data (
references.index (i, idColumn)).toString().toUtf8().constData());
int state = references.data (references.index (i, stateColumn)).toInt();
ids.insert (std::make_pair (id, state==CSMWorld::RecordBase::State_Deleted));
}
}
// perform update and remove where needed
bool modified = false;
for (std::map<std::string, Object *>::iterator iter (mObjects.begin());
iter!=mObjects.end(); ++iter)
{
if (iter->second->referenceDataChanged (topLeft, bottomRight))
modified = true;
std::map<std::string, bool>::iterator iter2 = ids.find (iter->first);
if (iter2!=ids.end())
{
if (iter2->second)
{
removeObject (iter->first);
modified = true;
}
ids.erase (iter2);
}
}
// add new objects
for (std::map<std::string, bool>::iterator iter (ids.begin()); iter!=ids.end(); ++iter)
{
mObjects.insert (std::make_pair (
iter->first, new Object (mData, mCellNode, iter->first, false)));
modified = true;
}
return modified;
}
bool CSVRender::Cell::referenceAboutToBeRemoved (const QModelIndex& parent, int start,
int end)
{
if (parent.isValid())
return false;
CSMWorld::IdTable& references = dynamic_cast<CSMWorld::IdTable&> (
*mData.getTableModel (CSMWorld::UniversalId::Type_References));
int idColumn = references.findColumnIndex (CSMWorld::Columns::ColumnId_Id);
bool modified = false;
for (int row = start; row<=end; ++row)
if (removeObject (references.data (
references.index (row, idColumn)).toString().toUtf8().constData()))
modified = true;
return modified;
}
bool CSVRender::Cell::referenceAdded (const QModelIndex& parent, int start, int end)
{
if (parent.isValid())
return false;
return addObjects (start, end);
}

View file

@ -0,0 +1,73 @@
#ifndef OPENCS_VIEW_CELL_H
#define OPENCS_VIEW_CELL_H
#include <string>
#include <map>
#include <OgreVector3.h>
#include "object.hpp"
class QModelIndex;
namespace Ogre
{
class SceneManager;
class SceneNode;
}
namespace CSMWorld
{
class Data;
}
namespace CSVRender
{
class Cell
{
CSMWorld::Data& mData;
std::string mId;
Ogre::SceneNode *mCellNode;
std::map<std::string, Object *> mObjects;
/// Ignored if cell does not have an object with the given ID.
///
/// \return Was the object deleted?
bool removeObject (const std::string& id);
/// Add objects from reference table that are within this cell.
///
/// \return Have any objects been added?
bool addObjects (int start, int end);
public:
Cell (CSMWorld::Data& data, Ogre::SceneManager *sceneManager,
const std::string& id, const Ogre::Vector3& origin = Ogre::Vector3 (0, 0, 0));
~Cell();
/// \return Did this call result in a modification of the visual representation of
/// this cell?
bool referenceableDataChanged (const QModelIndex& topLeft,
const QModelIndex& bottomRight);
/// \return Did this call result in a modification of the visual representation of
/// this cell?
bool referenceableAboutToBeRemoved (const QModelIndex& parent, int start, int end);
/// \return Did this call result in a modification of the visual representation of
/// this cell?
bool referenceDataChanged (const QModelIndex& topLeft, const QModelIndex& bottomRight);
/// \return Did this call result in a modification of the visual representation of
/// this cell?
bool referenceAboutToBeRemoved (const QModelIndex& parent, int start, int end);
/// \return Did this call result in a modification of the visual representation of
/// this cell?
bool referenceAdded (const QModelIndex& parent, int start, int end);
};
}
#endif

View file

@ -0,0 +1,213 @@
#include "object.hpp"
#include <OgreSceneManager.h>
#include <OgreSceneNode.h>
#include <OgreEntity.h>
#include "../../model/world/data.hpp"
#include "../../model/world/ref.hpp"
#include "../../model/world/refidcollection.hpp"
void CSVRender::Object::clearSceneNode (Ogre::SceneNode *node)
{
for (Ogre::SceneNode::ObjectIterator iter = node->getAttachedObjectIterator();
iter.hasMoreElements(); )
{
Ogre::MovableObject* object = dynamic_cast<Ogre::MovableObject*> (iter.getNext());
node->getCreator()->destroyMovableObject (object);
}
for (Ogre::SceneNode::ChildNodeIterator iter = node->getChildIterator();
iter.hasMoreElements(); )
{
Ogre::SceneNode* childNode = dynamic_cast<Ogre::SceneNode*> (iter.getNext());
clearSceneNode (childNode);
node->getCreator()->destroySceneNode (childNode);
}
}
void CSVRender::Object::clear()
{
mObject.setNull();
clearSceneNode (mBase);
}
void CSVRender::Object::update()
{
clear();
std::string model;
int error = 0; // 1 referemceanöe does not exist, 2 referenceable does not specify a mesh
const CSMWorld::RefIdCollection& referenceables = mData.getReferenceables();
int index = referenceables.searchId (mReferenceableId);
if (index==-1)
error = 1;
else
{
/// \todo check for Deleted state (error 1)
model = referenceables.getData (index,
referenceables.findColumnIndex (CSMWorld::Columns::ColumnId_Model)).
toString().toUtf8().constData();
if (model.empty())
error = 2;
}
if (error)
{
Ogre::Entity* entity = mBase->getCreator()->createEntity (Ogre::SceneManager::PT_CUBE);
entity->setMaterialName("BaseWhite"); /// \todo adjust material according to error
mBase->attachObject (entity);
}
else
{
mObject = NifOgre::Loader::createObjects (mBase, "Meshes\\" + model);
}
}
void CSVRender::Object::adjust()
{
if (mReferenceId.empty())
return;
const CSMWorld::CellRef& reference = getReference();
// position
if (!mForceBaseToZero)
mBase->setPosition (Ogre::Vector3 (
reference.mPos.pos[0], reference.mPos.pos[1], reference.mPos.pos[2]));
// orientation
Ogre::Quaternion xr (Ogre::Radian (-reference.mPos.rot[0]), Ogre::Vector3::UNIT_X);
Ogre::Quaternion yr (Ogre::Radian (-reference.mPos.rot[1]), Ogre::Vector3::UNIT_Y);
Ogre::Quaternion zr (Ogre::Radian (-reference.mPos.rot[2]), Ogre::Vector3::UNIT_Z);
mBase->setOrientation (xr*yr*zr);
// scale
mBase->setScale (reference.mScale, reference.mScale, reference.mScale);
}
const CSMWorld::CellRef& CSVRender::Object::getReference() const
{
if (mReferenceId.empty())
throw std::logic_error ("object does not represent a reference");
return mData.getReferences().getRecord (mReferenceId).get();
}
CSVRender::Object::Object (const CSMWorld::Data& data, Ogre::SceneNode *cellNode,
const std::string& id, bool referenceable, bool forceBaseToZero)
: mData (data), mBase (0), mForceBaseToZero (forceBaseToZero)
{
mBase = cellNode->createChildSceneNode();
if (referenceable)
{
mReferenceableId = id;
}
else
{
mReferenceId = id;
mReferenceableId = getReference().mRefID;
}
update();
adjust();
}
CSVRender::Object::~Object()
{
clear();
if (mBase)
mBase->getCreator()->destroySceneNode (mBase);
}
bool CSVRender::Object::referenceableDataChanged (const QModelIndex& topLeft,
const QModelIndex& bottomRight)
{
const CSMWorld::RefIdCollection& referenceables = mData.getReferenceables();
int index = referenceables.searchId (mReferenceableId);
if (index!=-1 && index>=topLeft.row() && index<=bottomRight.row())
{
update();
adjust();
return true;
}
return false;
}
bool CSVRender::Object::referenceableAboutToBeRemoved (const QModelIndex& parent, int start,
int end)
{
const CSMWorld::RefIdCollection& referenceables = mData.getReferenceables();
int index = referenceables.searchId (mReferenceableId);
if (index!=-1 && index>=start && index<=end)
{
// Deletion of referenceable-type objects is handled outside of Object.
if (!mReferenceId.empty())
{
update();
adjust();
return true;
}
}
return false;
}
bool CSVRender::Object::referenceDataChanged (const QModelIndex& topLeft,
const QModelIndex& bottomRight)
{
if (mReferenceId.empty())
return false;
const CSMWorld::RefCollection& references = mData.getReferences();
int index = references.searchId (mReferenceId);
if (index!=-1 && index>=topLeft.row() && index<=bottomRight.row())
{
int columnIndex =
references.findColumnIndex (CSMWorld::Columns::ColumnId_ReferenceableId);
if (columnIndex>=topLeft.column() && columnIndex<=bottomRight.row())
{
mReferenceableId =
references.getData (index, columnIndex).toString().toUtf8().constData();
update();
}
adjust();
return true;
}
return false;
}
std::string CSVRender::Object::getReferenceId() const
{
return mReferenceId;
}
std::string CSVRender::Object::getReferenceableId() const
{
return mReferenceableId;
}

View file

@ -0,0 +1,80 @@
#ifndef OPENCS_VIEW_OBJECT_H
#define OPENCS_VIEW_OBJECT_H
#include <components/nifogre/ogrenifloader.hpp>
class QModelIndex;
namespace Ogre
{
class SceneNode;
}
namespace CSMWorld
{
class Data;
class CellRef;
}
namespace CSVRender
{
class Object
{
const CSMWorld::Data& mData;
std::string mReferenceId;
std::string mReferenceableId;
Ogre::SceneNode *mBase;
NifOgre::ObjectScenePtr mObject;
bool mForceBaseToZero;
/// Not implemented
Object (const Object&);
/// Not implemented
Object& operator= (const Object&);
/// Destroy all scene nodes and movable objects attached to node.
static void clearSceneNode (Ogre::SceneNode *node);
/// Remove object from node (includes deleting)
void clear();
/// Update model
void update();
/// Adjust position, orientation and scale
void adjust();
/// Throws an exception if *this was constructed with referenceable
const CSMWorld::CellRef& getReference() const;
public:
Object (const CSMWorld::Data& data, Ogre::SceneNode *cellNode,
const std::string& id, bool referenceable, bool forceBaseToZero = false);
/// \param forceBaseToZero If this is a reference ignore the coordinates and place
/// it at 0, 0, 0 instead.
~Object();
/// \return Did this call result in a modification of the visual representation of
/// this object?
bool referenceableDataChanged (const QModelIndex& topLeft,
const QModelIndex& bottomRight);
/// \return Did this call result in a modification of the visual representation of
/// this object?
bool referenceableAboutToBeRemoved (const QModelIndex& parent, int start, int end);
/// \return Did this call result in a modification of the visual representation of
/// this object?
bool referenceDataChanged (const QModelIndex& topLeft, const QModelIndex& bottomRight);
/// Returns an empty string if this is a refereceable-type object.
std::string getReferenceId() const;
std::string getReferenceableId() const;
};
}
#endif

View file

@ -3,14 +3,137 @@
#include <sstream>
#include <OgreCamera.h>
#include <QtGui/qevent.h>
#include <apps/opencs/model/world/tablemimedata.hpp>
#include "../../model/world/tablemimedata.hpp"
#include "../../model/world/idtable.hpp"
bool CSVRender::PagedWorldspaceWidget::adjustCells()
{
bool modified = false;
bool setCamera = false;
{
// remove
std::map<CSMWorld::CellCoordinates, Cell *>::iterator iter (mCells.begin());
while (iter!=mCells.end())
{
if (!mSelection.has (iter->first))
{
delete iter->second;
mCells.erase (iter++);
modified = true;
}
else
++iter;
}
}
if (mCells.begin()==mCells.end())
setCamera = true;
// add
for (CSMWorld::CellSelection::Iterator iter (mSelection.begin()); iter!=mSelection.end();
++iter)
{
if (mCells.find (*iter)==mCells.end())
{
if (setCamera)
{
setCamera = false;
getCamera()->setPosition (8192*iter->getX()+4096, 8192*iter->getY()+4096, 0);
}
mCells.insert (std::make_pair (*iter,
new Cell (mDocument.getData(), getSceneManager(),
iter->getId ("std::default"))));
modified = true;
}
}
return modified;
}
void CSVRender::PagedWorldspaceWidget::referenceableDataChanged (const QModelIndex& topLeft,
const QModelIndex& bottomRight)
{
for (std::map<CSMWorld::CellCoordinates, Cell *>::iterator iter (mCells.begin());
iter!=mCells.end(); ++iter)
if (iter->second->referenceableDataChanged (topLeft, bottomRight))
flagAsModified();
}
void CSVRender::PagedWorldspaceWidget::referenceableAboutToBeRemoved (
const QModelIndex& parent, int start, int end)
{
for (std::map<CSMWorld::CellCoordinates, Cell *>::iterator iter (mCells.begin());
iter!=mCells.end(); ++iter)
if (iter->second->referenceableAboutToBeRemoved (parent, start, end))
flagAsModified();
}
void CSVRender::PagedWorldspaceWidget::referenceableAdded (const QModelIndex& parent,
int start, int end)
{
CSMWorld::IdTable& referenceables = dynamic_cast<CSMWorld::IdTable&> (
*mDocument.getData().getTableModel (CSMWorld::UniversalId::Type_Referenceables));
for (std::map<CSMWorld::CellCoordinates, Cell *>::iterator iter (mCells.begin());
iter!=mCells.end(); ++iter)
{
QModelIndex topLeft = referenceables.index (start, 0);
QModelIndex bottomRight =
referenceables.index (end, referenceables.columnCount());
if (iter->second->referenceableDataChanged (topLeft, bottomRight))
flagAsModified();
}
}
void CSVRender::PagedWorldspaceWidget::referenceDataChanged (const QModelIndex& topLeft,
const QModelIndex& bottomRight)
{
for (std::map<CSMWorld::CellCoordinates, Cell *>::iterator iter (mCells.begin());
iter!=mCells.end(); ++iter)
if (iter->second->referenceDataChanged (topLeft, bottomRight))
flagAsModified();
}
void CSVRender::PagedWorldspaceWidget::referenceAboutToBeRemoved (const QModelIndex& parent,
int start, int end)
{
for (std::map<CSMWorld::CellCoordinates, Cell *>::iterator iter (mCells.begin());
iter!=mCells.end(); ++iter)
if (iter->second->referenceAboutToBeRemoved (parent, start, end))
flagAsModified();
}
void CSVRender::PagedWorldspaceWidget::referenceAdded (const QModelIndex& parent, int start,
int end)
{
for (std::map<CSMWorld::CellCoordinates, Cell *>::iterator iter (mCells.begin());
iter!=mCells.end(); ++iter)
if (iter->second->referenceAdded (parent, start, end))
flagAsModified();
}
CSVRender::PagedWorldspaceWidget::PagedWorldspaceWidget (QWidget* parent, CSMDoc::Document& document)
: WorldspaceWidget (document, parent)
: WorldspaceWidget (document, parent), mDocument (document)
{}
CSVRender::PagedWorldspaceWidget::~PagedWorldspaceWidget()
{
for (std::map<CSMWorld::CellCoordinates, Cell *>::iterator iter (mCells.begin());
iter!=mCells.end(); ++iter)
delete iter->second;
}
void CSVRender::PagedWorldspaceWidget::useViewHint (const std::string& hint)
{
if (!hint.empty())
@ -47,6 +170,10 @@ void CSVRender::PagedWorldspaceWidget::useViewHint (const std::string& hint)
void CSVRender::PagedWorldspaceWidget::setCellSelection (const CSMWorld::CellSelection& selection)
{
mSelection = selection;
if (adjustCells())
flagAsModified();
emit cellSelectionChanged (mSelection);
}
@ -72,6 +199,9 @@ void CSVRender::PagedWorldspaceWidget::handleDrop (const std::vector< CSMWorld::
}
if (selectionChanged)
{
if (adjustCells())
flagAsModified();
emit cellSelectionChanged(mSelection);
}
}

View file

@ -1,9 +1,12 @@
#ifndef OPENCS_VIEW_PAGEDWORLDSPACEWIDGET_H
#define OPENCS_VIEW_PAGEDWORLDSPACEWIDGET_H
#include <map>
#include "../../model/world/cellselection.hpp"
#include "worldspacewidget.hpp"
#include "cell.hpp"
namespace CSVRender
{
@ -11,12 +14,32 @@ namespace CSVRender
{
Q_OBJECT
CSMDoc::Document& mDocument;
CSMWorld::CellSelection mSelection;
std::map<CSMWorld::CellCoordinates, Cell *> mCells;
private:
std::pair<int, int> getCoordinatesFromId(const std::string& record) const;
/// Bring mCells into sync with mSelection again.
///
/// \return Any cells added or removed?
bool adjustCells();
virtual void referenceableDataChanged (const QModelIndex& topLeft,
const QModelIndex& bottomRight);
virtual void referenceableAboutToBeRemoved (const QModelIndex& parent, int start, int end);
virtual void referenceableAdded (const QModelIndex& index, int start, int end);
virtual void referenceDataChanged (const QModelIndex& topLeft, const QModelIndex& bottomRight);
virtual void referenceAboutToBeRemoved (const QModelIndex& parent, int start, int end);
virtual void referenceAdded (const QModelIndex& index, int start, int end);
public:
PagedWorldspaceWidget (QWidget *parent, CSMDoc::Document& document);
@ -24,6 +47,8 @@ namespace CSVRender
/// no cells are displayed. The cells to be displayed will be specified later through
/// hint system.
virtual ~PagedWorldspaceWidget();
void useViewHint (const std::string& hint);
void setCellSelection (const CSMWorld::CellSelection& selection);

View file

@ -7,194 +7,119 @@
#include "../../model/world/data.hpp"
#include "../../model/world/idtable.hpp"
void CSVRender::PreviewWidget::setup()
CSVRender::PreviewWidget::PreviewWidget (CSMWorld::Data& data,
const std::string& id, bool referenceable, QWidget *parent)
: SceneWidget (parent), mData (data),
mObject (data, getSceneManager()->getRootSceneNode(), id, referenceable, true)
{
setNavigation (&mOrbit);
mNode = getSceneManager()->getRootSceneNode()->createChildSceneNode();
mNode->setPosition (Ogre::Vector3 (0, 0, 0));
setModel();
QAbstractItemModel *referenceables =
mData.getTableModel (CSMWorld::UniversalId::Type_Referenceables);
connect (referenceables, SIGNAL (dataChanged (const QModelIndex&, const QModelIndex&)),
this, SLOT (ReferenceableDataChanged (const QModelIndex&, const QModelIndex&)));
this, SLOT (referenceableDataChanged (const QModelIndex&, const QModelIndex&)));
connect (referenceables, SIGNAL (rowsAboutToBeRemoved (const QModelIndex&, int, int)),
this, SLOT (ReferenceableAboutToBeRemoved (const QModelIndex&, int, int)));
}
this, SLOT (referenceableAboutToBeRemoved (const QModelIndex&, int, int)));
void CSVRender::PreviewWidget::setModel()
{
if (mNode)
if (!referenceable)
{
mObject.setNull();
QAbstractItemModel *references =
mData.getTableModel (CSMWorld::UniversalId::Type_References);
if (mReferenceableId.empty())
return;
int column =
mData.getReferenceables().findColumnIndex (CSMWorld::Columns::ColumnId_Model);
int row = mData.getReferenceables().searchId (mReferenceableId);
if (row==-1)
return;
QVariant value = mData.getReferenceables().getData (row, column);
if (!value.isValid())
return;
std::string model = value.toString().toUtf8().constData();
if (model.empty())
return;
mObject = NifOgre::Loader::createObjects (mNode, "Meshes\\" + model);
connect (references, SIGNAL (dataChanged (const QModelIndex&, const QModelIndex&)),
this, SLOT (referenceDataChanged (const QModelIndex&, const QModelIndex&)));
connect (references, SIGNAL (rowsAboutToBeRemoved (const QModelIndex&, int, int)),
this, SLOT (referenceAboutToBeRemoved (const QModelIndex&, int, int)));
}
}
void CSVRender::PreviewWidget::adjust()
{
if (mNode)
{
int row = mData.getReferences().getIndex (mReferenceId);
float scale = mData.getReferences().getData (row, mData.getReferences().
findColumnIndex (CSMWorld::Columns::ColumnId_Scale)).toFloat();
float rotX = mData.getReferences().getData (row, mData.getReferences().
findColumnIndex (CSMWorld::Columns::ColumnId_PositionXRot)).toFloat();
float rotY = mData.getReferences().getData (row, mData.getReferences().
findColumnIndex (CSMWorld::Columns::ColumnId_PositionYRot)).toFloat();
float rotZ = mData.getReferences().getData (row, mData.getReferences().
findColumnIndex (CSMWorld::Columns::ColumnId_PositionZRot)).toFloat();
mNode->setScale (scale, scale, scale);
Ogre::Quaternion xr (Ogre::Radian(-rotX), Ogre::Vector3::UNIT_X);
Ogre::Quaternion yr (Ogre::Radian(-rotY), Ogre::Vector3::UNIT_Y);
Ogre::Quaternion zr (Ogre::Radian(-rotZ), Ogre::Vector3::UNIT_Z);
mNode->setOrientation (xr*yr*zr);
}
}
CSVRender::PreviewWidget::PreviewWidget (CSMWorld::Data& data,
const std::string& referenceableId, QWidget *parent)
: SceneWidget (parent), mData (data), mNode (0), mReferenceableId (referenceableId)
{
setup();
}
CSVRender::PreviewWidget::PreviewWidget (CSMWorld::Data& data,
const std::string& referenceableId, const std::string& referenceId, QWidget *parent)
: SceneWidget (parent), mData (data), mReferenceableId (referenceableId),
mReferenceId (referenceId)
{
setup();
adjust();
QAbstractItemModel *references =
mData.getTableModel (CSMWorld::UniversalId::Type_References);
connect (references, SIGNAL (dataChanged (const QModelIndex&, const QModelIndex&)),
this, SLOT (ReferenceDataChanged (const QModelIndex&, const QModelIndex&)));
connect (references, SIGNAL (rowsAboutToBeRemoved (const QModelIndex&, int, int)),
this, SLOT (ReferenceAboutToBeRemoved (const QModelIndex&, int, int)));
}
void CSVRender::PreviewWidget::ReferenceableDataChanged (const QModelIndex& topLeft,
void CSVRender::PreviewWidget::referenceableDataChanged (const QModelIndex& topLeft,
const QModelIndex& bottomRight)
{
if (mReferenceableId.empty())
return;
CSMWorld::IdTable& referenceables = dynamic_cast<CSMWorld::IdTable&> (
*mData.getTableModel (CSMWorld::UniversalId::Type_Referenceables));
QModelIndex index = referenceables.getModelIndex (mReferenceableId, 0);
if (index.row()>=topLeft.row() && index.row()<=bottomRight.row())
{
/// \todo possible optimisation; check columns and only update if relevant columns have
/// changed
setModel();
if (mObject.referenceableDataChanged (topLeft, bottomRight))
flagAsModified();
if (mObject.getReferenceId().empty())
{
CSMWorld::IdTable& referenceables = dynamic_cast<CSMWorld::IdTable&> (
*mData.getTableModel (CSMWorld::UniversalId::Type_Referenceables));
QModelIndex index = referenceables.getModelIndex (mObject.getReferenceableId(),
referenceables.findColumnIndex (CSMWorld::Columns::ColumnId_Modification));
if (referenceables.data (index).toInt()==CSMWorld::RecordBase::State_Deleted)
emit closeRequest();
}
}
void CSVRender::PreviewWidget::ReferenceableAboutToBeRemoved (const QModelIndex& parent, int start,
void CSVRender::PreviewWidget::referenceableAboutToBeRemoved (const QModelIndex& parent, int start,
int end)
{
if (mReferenceableId.empty())
if (mObject.referenceableAboutToBeRemoved (parent, start, end))
flagAsModified();
if (mObject.getReferenceableId().empty())
return;
CSMWorld::IdTable& referenceables = dynamic_cast<CSMWorld::IdTable&> (
*mData.getTableModel (CSMWorld::UniversalId::Type_Referenceables));
QModelIndex index = referenceables.getModelIndex (mReferenceableId, 0);
QModelIndex index = referenceables.getModelIndex (mObject.getReferenceableId(), 0);
if (index.row()>=start && index.row()<=end)
{
if (mReferenceId.empty())
if (mObject.getReferenceId().empty())
{
// this is a preview for a referenceble
emit closeRequest();
}
else
{
// this is a preview for a reference
mObject.setNull();
flagAsModified();
}
}
}
void CSVRender::PreviewWidget::ReferenceDataChanged (const QModelIndex& topLeft,
void CSVRender::PreviewWidget::referenceDataChanged (const QModelIndex& topLeft,
const QModelIndex& bottomRight)
{
if (mReferenceId.empty())
if (mObject.referenceDataChanged (topLeft, bottomRight))
flagAsModified();
if (mObject.getReferenceId().empty())
return;
CSMWorld::IdTable& references = dynamic_cast<CSMWorld::IdTable&> (
*mData.getTableModel (CSMWorld::UniversalId::Type_References));
// check for deleted state
{
QModelIndex index = references.getModelIndex (mObject.getReferenceId(),
references.findColumnIndex (CSMWorld::Columns::ColumnId_Modification));
if (references.data (index).toInt()==CSMWorld::RecordBase::State_Deleted)
{
emit closeRequest();
return;
}
}
int columnIndex = references.findColumnIndex (CSMWorld::Columns::ColumnId_ReferenceableId);
QModelIndex index = references.getModelIndex (mReferenceId, columnIndex);
QModelIndex index = references.getModelIndex (mObject.getReferenceId(), columnIndex);
if (index.row()>=topLeft.row() && index.row()<=bottomRight.row())
{
/// \todo possible optimisation; check columns and only update if relevant columns have
/// changed
adjust();
if (index.column()>=topLeft.column() && index.column()<=bottomRight.row())
{
mReferenceableId = references.data (index).toString().toUtf8().constData();
emit referenceableIdChanged (mReferenceableId);
setModel();
}
flagAsModified();
}
emit referenceableIdChanged (mObject.getReferenceableId());
}
void CSVRender::PreviewWidget::ReferenceAboutToBeRemoved (const QModelIndex& parent, int start,
void CSVRender::PreviewWidget::referenceAboutToBeRemoved (const QModelIndex& parent, int start,
int end)
{
if (mReferenceId.empty())
if (mObject.getReferenceId().empty())
return;
CSMWorld::IdTable& references = dynamic_cast<CSMWorld::IdTable&> (
*mData.getTableModel (CSMWorld::UniversalId::Type_References));
QModelIndex index = references.getModelIndex (mReferenceId, 0);
QModelIndex index = references.getModelIndex (mObject.getReferenceId(), 0);
if (index.row()>=start && index.row()<=end)
emit closeRequest();

View file

@ -1,11 +1,10 @@
#ifndef OPENCS_VIEW_PREVIEWWIDGET_H
#define OPENCS_VIEW_PREVIEWWIDGET_H
#include <components/nifogre/ogrenifloader.hpp>
#include "scenewidget.hpp"
#include "navigationorbit.hpp"
#include "object.hpp"
class QModelIndex;
@ -22,26 +21,13 @@ namespace CSVRender
CSMWorld::Data& mData;
CSVRender::NavigationOrbit mOrbit;
NifOgre::ObjectScenePtr mObject;
Ogre::SceneNode *mNode;
std::string mReferenceId;
std::string mReferenceableId;
void setup();
void setModel();
void adjust();
///< Adjust referenceable preview according to the reference
Object mObject;
public:
PreviewWidget (CSMWorld::Data& data, const std::string& referenceableId,
PreviewWidget (CSMWorld::Data& data, const std::string& id, bool referenceable,
QWidget *parent = 0);
PreviewWidget (CSMWorld::Data& data, const std::string& referenceableId,
const std::string& referenceId, QWidget *parent = 0);
signals:
void closeRequest();
@ -50,14 +36,14 @@ namespace CSVRender
private slots:
void ReferenceableDataChanged (const QModelIndex& topLeft,
void referenceableDataChanged (const QModelIndex& topLeft,
const QModelIndex& bottomRight);
void ReferenceableAboutToBeRemoved (const QModelIndex& parent, int start, int end);
void referenceableAboutToBeRemoved (const QModelIndex& parent, int start, int end);
void ReferenceDataChanged (const QModelIndex& topLeft, const QModelIndex& bottomRight);
void referenceDataChanged (const QModelIndex& topLeft, const QModelIndex& bottomRight);
void ReferenceAboutToBeRemoved (const QModelIndex& parent, int start, int end);
void referenceAboutToBeRemoved (const QModelIndex& parent, int start, int end);
};
}

View file

@ -43,7 +43,7 @@ namespace CSVRender
mCamera->setPosition (300, 0, 0);
mCamera->lookAt (0, 0, 0);
mCamera->setNearClipDistance (0.1);
mCamera->setFarClipDistance (30000);
mCamera->setFarClipDistance (300000); ///< \todo make this configurable
mCamera->roll (Ogre::Degree (90));
setLighting (&mLightingDay);
@ -87,7 +87,7 @@ namespace CSVRender
std::stringstream windowHandle;
#ifdef WIN32
windowHandle << Ogre::StringConverter::toString((unsigned long)(this->winId()));
windowHandle << Ogre::StringConverter::toString((uintptr_t)(this->winId()));
#else
windowHandle << this->winId();
#endif
@ -137,6 +137,11 @@ namespace CSVRender
return mSceneMgr;
}
Ogre::Camera *SceneWidget::getCamera()
{
return mCamera;
}
void SceneWidget::flagAsModified()
{
mUpdate = true;

View file

@ -49,6 +49,8 @@ namespace CSVRender
Ogre::SceneManager *getSceneManager();
Ogre::Camera *getCamera();
void flagAsModified();
void setDefaultAmbient (const Ogre::ColourValue& colour);

View file

@ -21,6 +21,8 @@ void CSVRender::UnpagedWorldspaceWidget::update()
setDefaultAmbient (colour);
/// \todo deal with mSunlight and mFog/mForDensity
flagAsModified();
}
CSVRender::UnpagedWorldspaceWidget::UnpagedWorldspaceWidget (const std::string& cellId, CSMDoc::Document& document, QWidget* parent)
@ -29,12 +31,17 @@ CSVRender::UnpagedWorldspaceWidget::UnpagedWorldspaceWidget (const std::string&
mCellsModel = &dynamic_cast<CSMWorld::IdTable&> (
*document.getData().getTableModel (CSMWorld::UniversalId::Type_Cells));
mReferenceablesModel = &dynamic_cast<CSMWorld::IdTable&> (
*document.getData().getTableModel (CSMWorld::UniversalId::Type_Referenceables));
connect (mCellsModel, SIGNAL (dataChanged (const QModelIndex&, const QModelIndex&)),
this, SLOT (cellDataChanged (const QModelIndex&, const QModelIndex&)));
connect (mCellsModel, SIGNAL (rowsAboutToBeRemoved (const QModelIndex&, int, int)),
this, SLOT (cellRowsAboutToBeRemoved (const QModelIndex&, int, int)));
update();
mCell.reset (new Cell (document.getData(), getSceneManager(), mCellId));
}
void CSVRender::UnpagedWorldspaceWidget::cellDataChanged (const QModelIndex& topLeft,
@ -72,6 +79,62 @@ void CSVRender::UnpagedWorldspaceWidget::handleDrop (const std::vector< CSMWorld
mCellId = data.begin()->getId();
update();
emit cellChanged(*data.begin());
/// \todo replace mCell
}
void CSVRender::UnpagedWorldspaceWidget::referenceableDataChanged (const QModelIndex& topLeft,
const QModelIndex& bottomRight)
{
if (mCell.get())
if (mCell.get()->referenceableDataChanged (topLeft, bottomRight))
flagAsModified();
}
void CSVRender::UnpagedWorldspaceWidget::referenceableAboutToBeRemoved (
const QModelIndex& parent, int start, int end)
{
if (mCell.get())
if (mCell.get()->referenceableAboutToBeRemoved (parent, start, end))
flagAsModified();
}
void CSVRender::UnpagedWorldspaceWidget::referenceableAdded (const QModelIndex& parent,
int start, int end)
{
if (mCell.get())
{
QModelIndex topLeft = mReferenceablesModel->index (start, 0);
QModelIndex bottomRight =
mReferenceablesModel->index (end, mReferenceablesModel->columnCount());
if (mCell.get()->referenceableDataChanged (topLeft, bottomRight))
flagAsModified();
}
}
void CSVRender::UnpagedWorldspaceWidget::referenceDataChanged (const QModelIndex& topLeft,
const QModelIndex& bottomRight)
{
if (mCell.get())
if (mCell.get()->referenceDataChanged (topLeft, bottomRight))
flagAsModified();
}
void CSVRender::UnpagedWorldspaceWidget::referenceAboutToBeRemoved (const QModelIndex& parent,
int start, int end)
{
if (mCell.get())
if (mCell.get()->referenceAboutToBeRemoved (parent, start, end))
flagAsModified();
}
void CSVRender::UnpagedWorldspaceWidget::referenceAdded (const QModelIndex& parent, int start,
int end)
{
if (mCell.get())
if (mCell.get()->referenceAdded (parent, start, end))
flagAsModified();
}
CSVRender::WorldspaceWidget::dropRequirments CSVRender::UnpagedWorldspaceWidget::getDropRequirements (CSVRender::WorldspaceWidget::dropType type) const

View file

@ -2,8 +2,10 @@
#define OPENCS_VIEW_UNPAGEDWORLDSPACEWIDGET_H
#include <string>
#include <memory>
#include "worldspacewidget.hpp"
#include "cell.hpp"
class QModelIndex;
@ -25,6 +27,8 @@ namespace CSVRender
std::string mCellId;
CSMWorld::IdTable *mCellsModel;
CSMWorld::IdTable *mReferenceablesModel;
std::auto_ptr<Cell> mCell;
void update();
@ -37,6 +41,21 @@ namespace CSVRender
virtual void handleDrop(const std::vector<CSMWorld::UniversalId>& data);
private:
virtual void referenceableDataChanged (const QModelIndex& topLeft,
const QModelIndex& bottomRight);
virtual void referenceableAboutToBeRemoved (const QModelIndex& parent, int start, int end);
virtual void referenceableAdded (const QModelIndex& index, int start, int end);
virtual void referenceDataChanged (const QModelIndex& topLeft, const QModelIndex& bottomRight);
virtual void referenceAboutToBeRemoved (const QModelIndex& parent, int start, int end);
virtual void referenceAdded (const QModelIndex& index, int start, int end);
private slots:
void cellDataChanged (const QModelIndex& topLeft, const QModelIndex& bottomRight);

View file

@ -10,15 +10,30 @@
#include "../world/scenetoolmode.hpp"
#include <apps/opencs/model/world/universalid.hpp>
CSVRender::WorldspaceWidget::WorldspaceWidget (const CSMDoc::Document& document, QWidget* parent)
CSVRender::WorldspaceWidget::WorldspaceWidget (CSMDoc::Document& document, QWidget* parent)
: SceneWidget (parent), mDocument(document)
{
Ogre::Entity* ent = getSceneManager()->createEntity("cube", Ogre::SceneManager::PT_CUBE);
ent->setMaterialName("BaseWhite");
getSceneManager()->getRootSceneNode()->attachObject(ent);
setAcceptDrops(true);
QAbstractItemModel *referenceables =
document.getData().getTableModel (CSMWorld::UniversalId::Type_Referenceables);
connect (referenceables, SIGNAL (dataChanged (const QModelIndex&, const QModelIndex&)),
this, SLOT (referenceableDataChanged (const QModelIndex&, const QModelIndex&)));
connect (referenceables, SIGNAL (rowsAboutToBeRemoved (const QModelIndex&, int, int)),
this, SLOT (referenceableAboutToBeRemoved (const QModelIndex&, int, int)));
connect (referenceables, SIGNAL (rowsInserted (const QModelIndex&, int, int)),
this, SLOT (referenceableAdded (const QModelIndex&, int, int)));
QAbstractItemModel *references =
document.getData().getTableModel (CSMWorld::UniversalId::Type_References);
connect (references, SIGNAL (dataChanged (const QModelIndex&, const QModelIndex&)),
this, SLOT (referenceDataChanged (const QModelIndex&, const QModelIndex&)));
connect (references, SIGNAL (rowsAboutToBeRemoved (const QModelIndex&, int, int)),
this, SLOT (referenceAboutToBeRemoved (const QModelIndex&, int, int)));
connect (references, SIGNAL (rowsInserted (const QModelIndex&, int, int)),
this, SLOT (referenceAdded (const QModelIndex&, int, int)));
}
void CSVRender::WorldspaceWidget::selectNavigationMode (const std::string& mode)
@ -120,9 +135,11 @@ void CSVRender::WorldspaceWidget::dragMoveEvent(QDragMoveEvent *event)
void CSVRender::WorldspaceWidget::dropEvent (QDropEvent* event)
{
const CSMWorld::TableMimeData* mime = dynamic_cast<const CSMWorld::TableMimeData*> (event->mimeData());
if (!mime) // May happen when non-records (e.g. plain text) are dragged and dropped
return;
if (mime->fromDocument (mDocument))
{
emit dataDropped(mime->getData());
} //not handling drops from different documents at the moment
}
}

View file

@ -47,7 +47,7 @@ namespace CSVRender
ignored //either mixed cells, or not cells
};
WorldspaceWidget (const CSMDoc::Document& document, QWidget *parent = 0);
WorldspaceWidget (CSMDoc::Document& document, QWidget *parent = 0);
CSVWorld::SceneToolMode *makeNavigationSelector (CSVWorld::SceneToolbar *parent);
///< \attention The created tool is not added to the toolbar (via addTool). Doing that
@ -79,6 +79,19 @@ namespace CSVRender
void selectNavigationMode (const std::string& mode);
virtual void referenceableDataChanged (const QModelIndex& topLeft,
const QModelIndex& bottomRight) = 0;
virtual void referenceableAboutToBeRemoved (const QModelIndex& parent, int start, int end) = 0;
virtual void referenceableAdded (const QModelIndex& index, int start, int end) = 0;
virtual void referenceDataChanged (const QModelIndex& topLeft, const QModelIndex& bottomRight) = 0;
virtual void referenceAboutToBeRemoved (const QModelIndex& parent, int start, int end) = 0;
virtual void referenceAdded (const QModelIndex& index, int start, int end) = 0;
signals:
void closeRequest();

View file

@ -23,10 +23,10 @@ CSVWorld::PreviewSubView::PreviewSubView (const CSMWorld::UniversalId& id, CSMDo
referenceableIdChanged (referenceableId);
mScene =
new CSVRender::PreviewWidget (document.getData(), referenceableId, id.getId(), this);
new CSVRender::PreviewWidget (document.getData(), id.getId(), false, this);
}
else
mScene = new CSVRender::PreviewWidget (document.getData(), id.getId(), this);
mScene = new CSVRender::PreviewWidget (document.getData(), id.getId(), true, this);
SceneToolbar *toolbar = new SceneToolbar (48+6, this);

View file

@ -382,6 +382,9 @@ void CSVWorld::RegionMap::dropEvent (QDropEvent* event)
}
const CSMWorld::TableMimeData* mime = dynamic_cast<const CSMWorld::TableMimeData*> (event->mimeData());
if (!mime) // May happen when non-records (e.g. plain text) are dragged and dropped
return;
if (mime->fromDocument(mDocument) && mime->holdsType(CSMWorld::UniversalId::Type_Region))
{
CSMWorld::UniversalId record (mime->returnMatching (CSMWorld::UniversalId::Type_Region));
@ -402,4 +405,4 @@ void CSVWorld::RegionMap::dropEvent (QDropEvent* event)
mRegionId = record.getId();
}
}
}

View file

@ -45,19 +45,36 @@ CSVWorld::ScriptEdit::ScriptEdit (QWidget* parent, const CSMDoc::Document& docum
void CSVWorld::ScriptEdit::dragEnterEvent (QDragEnterEvent* event)
{
setTextCursor (cursorForPosition (event->pos()));
event->acceptProposedAction();
const CSMWorld::TableMimeData* mime = dynamic_cast<const CSMWorld::TableMimeData*> (event->mimeData());
if (!mime)
QTextEdit::dragEnterEvent(event);
else
{
setTextCursor (cursorForPosition (event->pos()));
event->acceptProposedAction();
}
}
void CSVWorld::ScriptEdit::dragMoveEvent (QDragMoveEvent* event)
{
setTextCursor (cursorForPosition (event->pos()));
event->accept();
const CSMWorld::TableMimeData* mime = dynamic_cast<const CSMWorld::TableMimeData*> (event->mimeData());
if (!mime)
QTextEdit::dragMoveEvent(event);
else
{
setTextCursor (cursorForPosition (event->pos()));
event->accept();
}
}
void CSVWorld::ScriptEdit::dropEvent (QDropEvent* event)
{
const CSMWorld::TableMimeData* mime = dynamic_cast<const CSMWorld::TableMimeData*> (event->mimeData());
if (!mime) // May happen when non-records (e.g. plain text) are dragged and dropped
{
QTextEdit::dropEvent(event);
return;
}
setTextCursor (cursorForPosition (event->pos()));

View file

@ -44,6 +44,10 @@ void CSVWorld::Table::contextMenuEvent (QContextMenuEvent *event)
mDispatcher->setSelection (records);
std::vector<CSMWorld::UniversalId> extendedTypes = mDispatcher->getExtendedTypes();
mDispatcher->setExtendedTypes (extendedTypes);
// create context menu
QMenu menu (this);
@ -63,11 +67,21 @@ void CSVWorld::Table::contextMenuEvent (QContextMenuEvent *event)
menu.addAction (mCreateAction);
if (mDispatcher->canRevert())
{
menu.addAction (mRevertAction);
if (!extendedTypes.empty())
menu.addAction (mExtendedRevertAction);
}
if (mDispatcher->canDelete())
{
menu.addAction (mDeleteAction);
if (!extendedTypes.empty())
menu.addAction (mExtendedDeleteAction);
}
if (mModel->getFeatures() & CSMWorld::IdTable::Feature_ReorderWithinTopic)
{
/// \todo allow reordering of multiple rows
@ -101,12 +115,12 @@ void CSVWorld::Table::contextMenuEvent (QContextMenuEvent *event)
if (selectedRows.size()==1)
{
int row = selectedRows.begin()->row();
row = mProxyModel->mapToSource (mProxyModel->index (row, 0)).row();
if (mModel->getFeatures() & CSMWorld::IdTable::Feature_View)
{
int row = selectedRows.begin()->row();
row = mProxyModel->mapToSource (mProxyModel->index (row, 0)).row();
CSMWorld::UniversalId id = mModel->view (row).first;
int index = mDocument.getData().getCells().searchId (id.getId());
@ -118,7 +132,16 @@ void CSVWorld::Table::contextMenuEvent (QContextMenuEvent *event)
}
if (mModel->getFeatures() & CSMWorld::IdTable::Feature_Preview)
menu.addAction (mPreviewAction);
{
QModelIndex index = mModel->index (row,
mModel->findColumnIndex (CSMWorld::Columns::ColumnId_Modification));
CSMWorld::RecordBase::State state = static_cast<CSMWorld::RecordBase::State> (
mModel->data (index).toInt());
if (state!=CSMWorld::RecordBase::State_Deleted)
menu.addAction (mPreviewAction);
}
}
menu.exec (event->globalPos());
@ -203,6 +226,18 @@ CSVWorld::Table::Table (const CSMWorld::UniversalId& id,
connect (mPreviewAction, SIGNAL (triggered()), this, SLOT (previewRecord()));
addAction (mPreviewAction);
/// \todo add a user option, that redirects the extended action to an input panel (in
/// the bottom bar) that lets the user select which record collections should be
/// modified.
mExtendedDeleteAction = new QAction (tr ("Extended Delete Record"), this);
connect (mExtendedDeleteAction, SIGNAL (triggered()), mDispatcher, SLOT (executeExtendedDelete()));
addAction (mExtendedDeleteAction);
mExtendedRevertAction = new QAction (tr ("Extended Revert Record"), this);
connect (mExtendedRevertAction, SIGNAL (triggered()), mDispatcher, SLOT (executeExtendedRevert()));
addAction (mExtendedRevertAction);
connect (mProxyModel, SIGNAL (rowsInserted (const QModelIndex&, int, int)),
this, SLOT (tableSizeUpdate()));
@ -351,7 +386,12 @@ void CSVWorld::Table::previewRecord()
{
std::string id = getUniversalId (selectedRows.begin()->row()).getId();
emit editRequest (CSMWorld::UniversalId (CSMWorld::UniversalId::Type_Preview, id) , "");
QModelIndex index = mModel->getModelIndex (id,
mModel->findColumnIndex (CSMWorld::Columns::ColumnId_Modification));
if (mModel->data (index)!=CSMWorld::RecordBase::State_Deleted)
emit editRequest (CSMWorld::UniversalId (CSMWorld::UniversalId::Type_Preview, id),
"");
}
}
@ -438,6 +478,9 @@ void CSVWorld::Table::dropEvent(QDropEvent *event)
}
const CSMWorld::TableMimeData* mime = dynamic_cast<const CSMWorld::TableMimeData*> (event->mimeData());
if (!mime) // May happen when non-records (e.g. plain text) are dragged and dropped
return;
if (mime->fromDocument (mDocument))
{
CSMWorld::ColumnBase::Display display = static_cast<CSMWorld::ColumnBase::Display>

View file

@ -46,6 +46,8 @@ namespace CSVWorld
QAction *mMoveDownAction;
QAction *mViewAction;
QAction *mPreviewAction;
QAction *mExtendedDeleteAction;
QAction *mExtendedRevertAction;
CSMWorld::IdTableProxyModel *mProxyModel;
CSMWorld::IdTable *mModel;
int mRecordStatusDisplay;

View file

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

View file

@ -256,6 +256,9 @@ void CSVWorld::DropLineEdit::dragMoveEvent(QDragMoveEvent *event)
void CSVWorld::DropLineEdit::dropEvent(QDropEvent *event)
{
const CSMWorld::TableMimeData* data(dynamic_cast<const CSMWorld::TableMimeData*>(event->mimeData()));
if (!data) // May happen when non-records (e.g. plain text) are dragged and dropped
return;
emit tableMimeDataDropped(data->getData(), data->getDocumentPtr());
//WIP
}

View file

@ -73,9 +73,9 @@ namespace CSVWorld
~CommandDelegateFactoryCollection();
void add (CSMWorld::ColumnBase::Display display, CommandDelegateFactory *factory);
///< The ownership of \æ factory is transferred to *this.
///< The ownership of \a factory is transferred to *this.
///
/// This function must not be called more than once per value of \æ display.
/// This function must not be called more than once per value of \a display.
CommandDelegate *makeDelegate (CSMWorld::ColumnBase::Display display, QUndoStack& undoStack,
QObject *parent) const;

View file

@ -15,7 +15,7 @@ add_openmw_dir (mwrender
renderingmanager debugging sky camera animation npcanimation creatureanimation activatoranimation
actors objects renderinginterface localmap occlusionquery water shadows
characterpreview globalmap videoplayer ripplesimulation refraction
terrainstorage renderconst effectmanager weaponanimation
terrainstorage renderconst effectmanager weaponanimation terraingrid
)
add_openmw_dir (mwinput
@ -142,10 +142,6 @@ if(APPLE)
endif()
endif(APPLE)
if(DPKG_PROGRAM)
INSTALL(TARGETS openmw RUNTIME DESTINATION games COMPONENT openmw)
endif(DPKG_PROGRAM)
if (BUILD_WITH_CODE_COVERAGE)
add_definitions (--coverage)
target_link_libraries(openmw gcov)

View file

@ -128,7 +128,7 @@ static void gdb_info(pid_t pid)
int fd;
/* Create a temp file to put gdb commands into */
strcpy(respfile, "gdb-respfile-XXXXXX");
strcpy(respfile, "/tmp/gdb-respfile-XXXXXX");
if((fd=mkstemp(respfile)) >= 0 && (f=fdopen(fd, "w")) != NULL)
{
fprintf(f, "attach %d\n"
@ -381,10 +381,7 @@ static void crash_handler(const char *logfile)
if(logfile)
{
char cwd[MAXPATHLEN];
getcwd(cwd, MAXPATHLEN);
std::string message = "OpenMW has encountered a fatal error.\nCrash log saved to '" + std::string(cwd) + "/" + std::string(logfile) + "'.\n Please report this to https://bugs.openmw.org !";
std::string message = "OpenMW has encountered a fatal error.\nCrash log saved to '" + std::string(logfile) + "'.\n Please report this to https://bugs.openmw.org !";
SDL_ShowSimpleMessageBox(0, "Fatal Error", message.c_str(), NULL);
}
exit(0);

View file

@ -91,7 +91,11 @@ bool OMW::Engine::frameRenderingQueued (const Ogre::FrameEvent& evt)
if (mUseSound)
MWBase::Environment::get().getSoundManager()->update(frametime);
bool paused = MWBase::Environment::get().getWindowManager()->isGuiMode();
// GUI active? Most game processing will be paused, but scripts still run.
bool guiActive = MWBase::Environment::get().getWindowManager()->isGuiMode();
// Main menu opened? Then scripts are also paused.
bool paused = MWBase::Environment::get().getWindowManager()->containsMode(MWGui::GM_MainMenu);
// update game state
MWBase::Environment::get().getStateManager()->update (frametime);
@ -99,15 +103,18 @@ bool OMW::Engine::frameRenderingQueued (const Ogre::FrameEvent& evt)
if (MWBase::Environment::get().getStateManager()->getState()==
MWBase::StateManager::State_Running)
{
// global scripts
MWBase::Environment::get().getScriptManager()->getGlobalScripts().run();
// local scripts
executeLocalScripts();
MWBase::Environment::get().getWorld()->markCellAsUnchanged();
if (!paused)
{
// global scripts
MWBase::Environment::get().getScriptManager()->getGlobalScripts().run();
// local scripts
executeLocalScripts();
MWBase::Environment::get().getWorld()->markCellAsUnchanged();
}
if (!guiActive)
MWBase::Environment::get().getWorld()->advanceTime(
frametime*MWBase::Environment::get().getWorld()->getTimeScaleFactor()/3600);
}
@ -118,14 +125,14 @@ bool OMW::Engine::frameRenderingQueued (const Ogre::FrameEvent& evt)
MWBase::StateManager::State_NoGame)
{
MWBase::Environment::get().getMechanicsManager()->update(frametime,
paused);
guiActive);
}
if (MWBase::Environment::get().getStateManager()->getState()==
MWBase::StateManager::State_Running)
{
MWWorld::Ptr player = mEnvironment.getWorld()->getPlayerPtr();
if(!paused && player.getClass().getCreatureStats(player).isDead())
if(!guiActive && player.getClass().getCreatureStats(player).isDead())
MWBase::Environment::get().getStateManager()->endGame();
}
@ -133,7 +140,7 @@ bool OMW::Engine::frameRenderingQueued (const Ogre::FrameEvent& evt)
if (MWBase::Environment::get().getStateManager()->getState()!=
MWBase::StateManager::State_NoGame)
{
MWBase::Environment::get().getWorld()->update(frametime, paused);
MWBase::Environment::get().getWorld()->update(frametime, guiActive);
}
// update GUI
@ -357,7 +364,7 @@ void OMW::Engine::prepareEngine (Settings::Manager & settings)
// 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.getUserConfigPath() / "input.xml").string();
std::string keybinderUser = (mCfgMgr.getUserConfigPath() / "input_v1.xml").string();
bool keybinderUserExists = boost::filesystem::exists(keybinderUser);
MWInput::InputManager* input = new MWInput::InputManager (*mOgre, *this, keybinderUser, keybinderUserExists, mGrab);
mEnvironment.setInputManager (input);
@ -489,24 +496,7 @@ void OMW::Engine::activate()
if (ptr.getClass().getName(ptr) == "") // objects without name presented to user can never be activated
return;
MWScript::InterpreterContext interpreterContext (&ptr.getRefData().getLocals(), ptr);
interpreterContext.activate (ptr);
std::string script = ptr.getClass().getScript (ptr);
MWBase::Environment::get().getWorld()->breakInvisibility(MWBase::Environment::get().getWorld()->getPlayerPtr());
if (!script.empty())
{
MWBase::Environment::get().getWorld()->getLocalScripts().setIgnore (ptr);
MWBase::Environment::get().getScriptManager()->run (script, interpreterContext);
}
if (!interpreterContext.hasActivationBeenHandled())
{
interpreterContext.executeActivation(ptr);
}
MWBase::Environment::get().getWorld()->activate(ptr, MWBase::Environment::get().getWorld()->getPlayerPtr());
}
void OMW::Engine::screenshot()

View file

@ -4,19 +4,20 @@
#include <components/version/version.hpp>
#include <components/files/configurationmanager.hpp>
#include <SDL.h>
#include <SDL_messagebox.h>
#include <SDL_main.h>
#include "engine.hpp"
#if defined(_WIN32) && !defined(_CONSOLE)
#include <boost/iostreams/concepts.hpp>
#include <boost/iostreams/stream_buffer.hpp>
#include <boost/filesystem/fstream.hpp>
#if defined(_WIN32)
// For OutputDebugString
#define WIN32_LEAN_AND_MEAN
#include <Windows.h>
// makes __argc and __argv available on windows
#include <cstdlib>
#endif
@ -253,58 +254,8 @@ bool parseOptions (int argc, char** argv, OMW::Engine& engine, Files::Configurat
return true;
}
int main(int argc, char**argv)
{
#if OGRE_PLATFORM == OGRE_PLATFORM_LINUX || OGRE_PLATFORM == OGRE_PLATFORM_APPLE
// Unix crash catcher
if ((argc == 2 && strcmp(argv[1], "--cc-handle-crash") == 0) || !is_debugger_attached())
{
int s[5] = { SIGSEGV, SIGILL, SIGFPE, SIGBUS, SIGABRT };
cc_install_handlers(argc, argv, 5, s, "crash.log", NULL);
std::cout << "Installing crash catcher" << std::endl;
}
else
std::cout << "Running in a debugger, not installing crash catcher" << std::endl;
#endif
#if defined(_WIN32) && defined(_DEBUG)
#if OGRE_PLATFORM == OGRE_PLATFORM_APPLE
// set current dir to bundle path
boost::filesystem::path bundlePath = boost::filesystem::path(Ogre::macBundlePath()).parent_path();
boost::filesystem::current_path(bundlePath);
#endif
try
{
Files::ConfigurationManager cfgMgr;
OMW::Engine engine(cfgMgr);
if (parseOptions(argc, argv, engine, cfgMgr))
{
engine.go();
}
}
catch (std::exception &e)
{
#if OGRE_PLATFORM == OGRE_PLATFORM_LINUX || OGRE_PLATFORM == OGRE_PLATFORM_APPLE
if (isatty(fileno(stdin)) || !SDL_WasInit(SDL_INIT_VIDEO))
std::cerr << "\nERROR: " << e.what() << std::endl;
else
#endif
SDL_ShowSimpleMessageBox(0, "OpenMW: Fatal error", e.what(), NULL);
return 1;
}
return 0;
}
// Platform specific for Windows when there is no console built into the executable.
// Windows will call the WinMain function instead of main in this case, the normal
// main function is then called with the __argc and __argv parameters.
// In addition if it is a debug build it will redirect cout to the debug console in Visual Studio
#if defined(_WIN32) && !defined(_CONSOLE)
#if defined(_DEBUG)
class DebugOutput : public boost::iostreams::sink
{
public:
@ -318,11 +269,11 @@ public:
}
};
#else
class Logger : public boost::iostreams::sink
class Tee : public boost::iostreams::sink
{
public:
Logger(std::ofstream &stream)
: out(stream)
Tee(std::ostream &stream, std::ostream &stream2)
: out(stream), out2(stream2)
{
}
@ -330,38 +281,107 @@ public:
{
out.write (str, size);
out.flush();
out2.write (str, size);
out2.flush();
return size;
}
private:
std::ofstream &out;
std::ostream &out;
std::ostream &out2;
};
#endif
int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nShowCmd)
int main(int argc, char**argv)
{
std::streambuf* old_rdbuf = std::cout.rdbuf ();
// Some objects used to redirect cout and cerr
// Scope must be here, so this still works inside the catch block for logging exceptions
std::streambuf* cout_rdbuf = std::cout.rdbuf ();
std::streambuf* cerr_rdbuf = std::cerr.rdbuf ();
#if !(defined(_WIN32) && defined(_DEBUG))
boost::iostreams::stream_buffer<Tee> coutsb;
boost::iostreams::stream_buffer<Tee> cerrsb;
#endif
std::ostream oldcout(cout_rdbuf);
std::ostream oldcerr(cerr_rdbuf);
boost::filesystem::ofstream logfile;
int ret = 0;
#if defined(_DEBUG)
// Redirect cout to VS debug output when running in debug mode
try
{
Files::ConfigurationManager cfgMgr;
#if defined(_WIN32) && defined(_DEBUG)
// Redirect cout and cerr to VS debug output when running in debug mode
boost::iostreams::stream_buffer<DebugOutput> sb;
sb.open(DebugOutput());
#else
// Redirect cout to openmw.log
std::ofstream logfile ("openmw.log");
{
boost::iostreams::stream_buffer<Logger> sb;
sb.open (Logger (logfile));
#endif
std::cout.rdbuf (&sb);
std::cerr.rdbuf (&sb);
#else
// Redirect cout and cerr to openmw.log
logfile.open (boost::filesystem::path(cfgMgr.getLogPath() / "/openmw.log"));
ret = main (__argc, __argv);
coutsb.open (Tee(logfile, oldcout));
cerrsb.open (Tee(logfile, oldcerr));
std::cout.rdbuf(old_rdbuf);
std::cout.rdbuf (&coutsb);
std::cerr.rdbuf (&cerrsb);
#endif
#if OGRE_PLATFORM == OGRE_PLATFORM_LINUX || OGRE_PLATFORM == OGRE_PLATFORM_APPLE
// Unix crash catcher
if ((argc == 2 && strcmp(argv[1], "--cc-handle-crash") == 0) || !is_debugger_attached())
{
int s[5] = { SIGSEGV, SIGILL, SIGFPE, SIGBUS, SIGABRT };
cc_install_handlers(argc, argv, 5, s, (cfgMgr.getLogPath() / "crash.log").string().c_str(), NULL);
std::cout << "Installing crash catcher" << std::endl;
}
else
std::cout << "Running in a debugger, not installing crash catcher" << std::endl;
#endif
#if OGRE_PLATFORM == OGRE_PLATFORM_APPLE
// set current dir to bundle path
boost::filesystem::path bundlePath = boost::filesystem::path(Ogre::macBundlePath()).parent_path();
boost::filesystem::current_path(bundlePath);
#endif
OMW::Engine engine(cfgMgr);
if (parseOptions(argc, argv, engine, cfgMgr))
{
engine.go();
}
}
catch (std::exception &e)
{
#if OGRE_PLATFORM == OGRE_PLATFORM_LINUX || OGRE_PLATFORM == OGRE_PLATFORM_APPLE
if (isatty(fileno(stdin)))
std::cerr << "\nERROR: " << e.what() << std::endl;
else
#endif
SDL_ShowSimpleMessageBox(0, "OpenMW: Fatal error", e.what(), NULL);
ret = 1;
}
// Restore cout and cerr
std::cout.rdbuf(cout_rdbuf);
std::cerr.rdbuf(cerr_rdbuf);
return ret;
}
// Platform specific for Windows when there is no console built into the executable.
// Windows will call the WinMain function instead of main in this case, the normal
// main function is then called with the __argc and __argv parameters.
#if defined(_WIN32) && !defined(_CONSOLE)
int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nShowCmd)
{
return main(__argc, __argv);
}
#endif

View file

@ -76,6 +76,9 @@ namespace MWBase
/// @return faction1's opinion of faction2
virtual int getFactionReaction (const std::string& faction1, const std::string& faction2) const = 0;
/// Removes the last added topic response for the given actor from the journal
virtual void clearInfoActor (const MWWorld::Ptr& actor) const = 0;
};
}

View file

@ -59,7 +59,12 @@ namespace MWBase
virtual int getJournalIndex (const std::string& id) const = 0;
///< Get the journal index.
virtual void addTopic (const std::string& topicId, const std::string& infoId, const std::string& actorName) = 0;
virtual void addTopic (const std::string& topicId, const std::string& infoId, const MWWorld::Ptr& actor) = 0;
/// \note topicId must be lowercase
virtual void removeLastAddedTopicResponse (const std::string& topicId, const std::string& actorName) = 0;
///< Removes the last topic response added for the given topicId and actor name.
/// \note topicId must be lowercase
virtual TEntryIter begin() const = 0;
///< Iterator pointing to the begin of the main journal.

View file

@ -4,6 +4,7 @@
#include <string>
#include <vector>
#include <list>
#include <stdint.h>
namespace Ogre
{
@ -13,6 +14,9 @@ namespace Ogre
namespace ESM
{
struct Class;
class ESMReader;
class ESMWriter;
}
namespace MWWorld
@ -21,6 +25,11 @@ namespace MWWorld
class CellStore;
}
namespace Loading
{
class Listener;
}
namespace MWBase
{
/// \brief Interface for game mechanics manager (implemented in MWMechanics)
@ -111,6 +120,7 @@ namespace MWBase
/**
* @brief Commit a crime. If any actors witness the crime and report it,
* reportCrime will be called automatically.
* @note victim may be empty
* @param arg Depends on \a type, e.g. for Theft, the value of the item that was stolen.
* @return was the crime reported?
*/
@ -174,6 +184,18 @@ namespace MWBase
virtual std::list<MWWorld::Ptr> getActorsFighting(const MWWorld::Ptr& actor) = 0;
virtual void playerLoaded() = 0;
virtual int countSavedGameRecords() const = 0;
virtual void write (ESM::ESMWriter& writer, Loading::Listener& listener) const = 0;
virtual void readRecord (ESM::ESMReader& reader, int32_t type) = 0;
virtual void clear() = 0;
/// @param bias Can be used to add an additional aggression bias towards the target,
/// making it more likely for the function to return true.
virtual bool isAggressive (const MWWorld::Ptr& ptr, const MWWorld::Ptr& target, int bias=0, bool ignoreDistance=false) = 0;
};
}

View file

@ -228,6 +228,7 @@ namespace MWBase
virtual void showCrosshair(bool show) = 0;
virtual bool getSubtitlesEnabled() = 0;
virtual void toggleHud() = 0;
virtual bool toggleGui() = 0;
virtual void disallowMouse() = 0;
virtual void allowMouse() = 0;
@ -328,6 +329,8 @@ namespace MWBase
/** Used when one Modal adds another Modal
\param input Pointer to the current modal, to ensure proper modal is removed **/
virtual void removeCurrentModal(MWGui::WindowModal* input) = 0;
virtual void pinWindow (MWGui::GuiWindow window) = 0;
};
}

View file

@ -274,6 +274,9 @@ namespace MWBase
virtual void adjustPosition (const MWWorld::Ptr& ptr) = 0;
///< Adjust position after load to be on ground. Must be called after model load.
virtual void fixPosition (const MWWorld::Ptr& actor) = 0;
///< Attempt to fix position so that the Ptr is no longer inside collision geometry.
virtual void deleteObject (const MWWorld::Ptr& ptr) = 0;
virtual void moveObject (const MWWorld::Ptr& ptr, float x, float y, float z) = 0;
@ -407,7 +410,7 @@ namespace MWBase
virtual void getItemsOwnedBy (const MWWorld::Ptr& npc, std::vector<MWWorld::Ptr>& out) = 0;
///< get all items in active cells owned by this Npc
virtual bool getLOS(const MWWorld::Ptr& npc,const MWWorld::Ptr& targetNpc) = 0;
virtual bool getLOS(const MWWorld::Ptr& actor,const MWWorld::Ptr& targetActor) = 0;
///< get Line of Sight (morrowind stupid implementation)
virtual float getDistToNearestRayHit(const Ogre::Vector3& from, const Ogre::Vector3& dir, float maxDist) = 0;
@ -470,7 +473,7 @@ namespace MWBase
virtual void launchMagicBolt (const std::string& model, const std::string& sound, const std::string& spellId,
float speed, bool stack, const ESM::EffectList& effects,
const MWWorld::Ptr& actor, const std::string& sourceName) = 0;
const MWWorld::Ptr& caster, const std::string& sourceName, const Ogre::Vector3& fallbackDirection) = 0;
virtual void launchProjectile (MWWorld::Ptr actor, MWWorld::Ptr projectile,
const Ogre::Vector3& worldPos, const Ogre::Quaternion& orient, MWWorld::Ptr bow, float speed) = 0;
@ -515,8 +518,18 @@ namespace MWBase
/// Spawn a blood effect for \a ptr at \a worldPosition
virtual void spawnBloodEffect (const MWWorld::Ptr& ptr, const Ogre::Vector3& worldPosition) = 0;
virtual void spawnEffect (const std::string& model, const std::string& textureOverride, const Ogre::Vector3& worldPos) = 0;
virtual void explodeSpell (const Ogre::Vector3& origin, const ESM::EffectList& effects,
const MWWorld::Ptr& caster, const std::string& id, const std::string& sourceName) = 0;
virtual void activate (const MWWorld::Ptr& object, const MWWorld::Ptr& actor) = 0;
/// @see MWWorld::WeatherManager::isInStorm
virtual bool isInStorm() const = 0;
/// @see MWWorld::WeatherManager::getStormDirection
virtual Ogre::Vector3 getStormDirection() const = 0;
};
}

View file

@ -124,7 +124,7 @@ namespace MWClass
std::string text;
text += "\n#{sQuality}: " + MWGui::ToolTips::toString(ref->mBase->mData.mQuality);
text += "\n#{sWeight}: " + MWGui::ToolTips::toString(ref->mBase->mData.mWeight);
text += MWGui::ToolTips::getValueString(getValue(ptr), "#{sValue}");
text += MWGui::ToolTips::getValueString(ref->mBase->mData.mValue, "#{sValue}");
if (MWBase::Environment::get().getWindowManager()->getFullHelp()) {
text += MWGui::ToolTips::getMiscString(ptr.getCellRef().getOwner(), "Owner");

View file

@ -168,7 +168,7 @@ namespace MWClass
MWWorld::LiveCellRef<ESM::Armor> *ref =
ptr.get<ESM::Armor>();
return ref->mBase->mData.mValue * (static_cast<float>(getItemHealth(ptr)) / getItemMaxHealth(ptr));
return ref->mBase->mData.mValue;
}
void Armor::registerSelf()
@ -244,7 +244,7 @@ namespace MWClass
+ MWGui::ToolTips::toString(ref->mBase->mData.mHealth);
text += "\n#{sWeight}: " + MWGui::ToolTips::toString(ref->mBase->mData.mWeight) + " (" + typeText + ")";
text += MWGui::ToolTips::getValueString(getValue(ptr), "#{sValue}");
text += MWGui::ToolTips::getValueString(ref->mBase->mData.mValue, "#{sValue}");
if (MWBase::Environment::get().getWindowManager()->getFullHelp()) {
text += MWGui::ToolTips::getMiscString(ptr.getCellRef().getOwner(), "Owner");

View file

@ -136,7 +136,7 @@ namespace MWClass
std::string text;
text += "\n#{sWeight}: " + MWGui::ToolTips::toString(ref->mBase->mData.mWeight);
text += MWGui::ToolTips::getValueString(getValue(ptr), "#{sValue}");
text += MWGui::ToolTips::getValueString(ref->mBase->mData.mValue, "#{sValue}");
if (MWBase::Environment::get().getWindowManager()->getFullHelp()) {
text += MWGui::ToolTips::getMiscString(ptr.getCellRef().getOwner(), "Owner");

View file

@ -190,7 +190,7 @@ namespace MWClass
std::string text;
text += "\n#{sWeight}: " + MWGui::ToolTips::toString(ref->mBase->mData.mWeight);
text += MWGui::ToolTips::getValueString(getValue(ptr), "#{sValue}");
text += MWGui::ToolTips::getValueString(ref->mBase->mData.mValue, "#{sValue}");
if (MWBase::Environment::get().getWindowManager()->getFullHelp()) {
text += MWGui::ToolTips::getMiscString(ptr.getCellRef().getOwner(), "Owner");

View file

@ -286,7 +286,12 @@ namespace MWClass
{
const ESM::ContainerState& state2 = dynamic_cast<const ESM::ContainerState&> (state);
ensureCustomData (ptr);
if (!ptr.getRefData().getCustomData())
{
// Create a CustomData, but don't fill it from ESM records (not needed)
std::auto_ptr<ContainerCustomData> data (new ContainerCustomData);
ptr.getRefData().setCustomData (data.release());
}
dynamic_cast<ContainerCustomData&> (*ptr.getRefData().getCustomData()).mContainerStore.
readState (state2.mInventory);

View file

@ -59,35 +59,38 @@ namespace
namespace MWClass
{
const Creature::GMST& Creature::getGmst()
{
static GMST gmst;
static bool inited = false;
if (!inited)
{
const MWBase::World *world = MWBase::Environment::get().getWorld();
const MWWorld::Store<ESM::GameSetting> &store = world->getStore().get<ESM::GameSetting>();
gmst.fMinWalkSpeedCreature = store.find("fMinWalkSpeedCreature");
gmst.fMaxWalkSpeedCreature = store.find("fMaxWalkSpeedCreature");
gmst.fEncumberedMoveEffect = store.find("fEncumberedMoveEffect");
gmst.fSneakSpeedMultiplier = store.find("fSneakSpeedMultiplier");
gmst.fAthleticsRunBonus = store.find("fAthleticsRunBonus");
gmst.fBaseRunMultiplier = store.find("fBaseRunMultiplier");
gmst.fMinFlySpeed = store.find("fMinFlySpeed");
gmst.fMaxFlySpeed = store.find("fMaxFlySpeed");
gmst.fSwimRunBase = store.find("fSwimRunBase");
gmst.fSwimRunAthleticsMult = store.find("fSwimRunAthleticsMult");
gmst.fKnockDownMult = store.find("fKnockDownMult");
gmst.iKnockDownOddsMult = store.find("iKnockDownOddsMult");
gmst.iKnockDownOddsBase = store.find("iKnockDownOddsBase");
inited = true;
}
return gmst;
}
void Creature::ensureCustomData (const MWWorld::Ptr& ptr) const
{
if (!ptr.getRefData().getCustomData())
{
std::auto_ptr<CreatureCustomData> data (new CreatureCustomData);
static bool inited = false;
if(!inited)
{
const MWBase::World *world = MWBase::Environment::get().getWorld();
const MWWorld::Store<ESM::GameSetting> &gmst = world->getStore().get<ESM::GameSetting>();
fMinWalkSpeedCreature = gmst.find("fMinWalkSpeedCreature");
fMaxWalkSpeedCreature = gmst.find("fMaxWalkSpeedCreature");
fEncumberedMoveEffect = gmst.find("fEncumberedMoveEffect");
fSneakSpeedMultiplier = gmst.find("fSneakSpeedMultiplier");
fAthleticsRunBonus = gmst.find("fAthleticsRunBonus");
fBaseRunMultiplier = gmst.find("fBaseRunMultiplier");
fMinFlySpeed = gmst.find("fMinFlySpeed");
fMaxFlySpeed = gmst.find("fMaxFlySpeed");
fSwimRunBase = gmst.find("fSwimRunBase");
fSwimRunAthleticsMult = gmst.find("fSwimRunAthleticsMult");
fKnockDownMult = gmst.find("fKnockDownMult");
iKnockDownOddsMult = gmst.find("iKnockDownOddsMult");
iKnockDownOddsBase = gmst.find("iKnockDownOddsBase");
inited = true;
}
MWWorld::LiveCellRef<ESM::Creature> *ref = ptr.get<ESM::Creature>();
// creature stats
@ -345,7 +348,9 @@ namespace MWClass
getCreatureStats(ptr).setAttacked(true);
// Self defense
if (!attacker.isEmpty() && ptr.getClass().getCreatureStats(ptr).getAiSetting(MWMechanics::CreatureStats::AI_Fight).getModified() < 80)
if (!attacker.isEmpty() && !MWBase::Environment::get().getMechanicsManager()->isAggressive(ptr, attacker)
&& (canWalk(ptr) || canFly(ptr) || canSwim(ptr))) // No retaliation for totally static creatures
// (they have no movement or attacks anyway)
MWBase::Environment::get().getMechanicsManager()->startCombat(ptr, attacker);
if(!successful)
@ -374,9 +379,9 @@ namespace MWClass
if (damage > 0.f)
{
// Check for knockdown
float agilityTerm = getCreatureStats(ptr).getAttribute(ESM::Attribute::Agility).getModified() * fKnockDownMult->getFloat();
float agilityTerm = getCreatureStats(ptr).getAttribute(ESM::Attribute::Agility).getModified() * getGmst().fKnockDownMult->getFloat();
float knockdownTerm = getCreatureStats(ptr).getAttribute(ESM::Attribute::Agility).getModified()
* iKnockDownOddsMult->getInt() * 0.01 + iKnockDownOddsBase->getInt();
* getGmst().iKnockDownOddsMult->getInt() * 0.01 + getGmst().iKnockDownOddsBase->getInt();
int roll = std::rand()/ (static_cast<double> (RAND_MAX) + 1) * 100; // [0, 99]
if (ishealth && agilityTerm <= damage && knockdownTerm <= roll)
{
@ -520,9 +525,10 @@ namespace MWClass
float Creature::getSpeed(const MWWorld::Ptr &ptr) const
{
MWMechanics::CreatureStats& stats = getCreatureStats(ptr);
const GMST& gmst = getGmst();
float walkSpeed = fMinWalkSpeedCreature->getFloat() + 0.01 * stats.getAttribute(ESM::Attribute::Speed).getModified()
* (fMaxWalkSpeedCreature->getFloat() - fMinWalkSpeedCreature->getFloat());
float walkSpeed = gmst.fMinWalkSpeedCreature->getFloat() + 0.01 * stats.getAttribute(ESM::Attribute::Speed).getModified()
* (gmst.fMaxWalkSpeedCreature->getFloat() - gmst.fMinWalkSpeedCreature->getFloat());
const MWBase::World *world = MWBase::Environment::get().getWorld();
const MWMechanics::MagicEffects &mageffects = stats.getMagicEffects();
@ -531,8 +537,8 @@ namespace MWClass
bool running = ptr.getClass().getCreatureStats(ptr).getStance(MWMechanics::CreatureStats::Stance_Run);
float runSpeed = walkSpeed*(0.01f * getSkill(ptr, ESM::Skill::Athletics) *
fAthleticsRunBonus->getFloat() + fBaseRunMultiplier->getFloat());
// The Run speed difference for creatures comes from the animation speed difference (see runStateToWalkState in character.cpp)
float runSpeed = walkSpeed;
float moveSpeed;
if(normalizedEncumbrance >= 1.0f)
@ -542,8 +548,8 @@ namespace MWClass
{
float flySpeed = 0.01f*(stats.getAttribute(ESM::Attribute::Speed).getModified() +
mageffects.get(ESM::MagicEffect::Levitate).mMagnitude);
flySpeed = fMinFlySpeed->getFloat() + flySpeed*(fMaxFlySpeed->getFloat() - fMinFlySpeed->getFloat());
flySpeed *= 1.0f - fEncumberedMoveEffect->getFloat() * normalizedEncumbrance;
flySpeed = gmst.fMinFlySpeed->getFloat() + flySpeed*(gmst.fMaxFlySpeed->getFloat() - gmst.fMinFlySpeed->getFloat());
flySpeed *= 1.0f - gmst.fEncumberedMoveEffect->getFloat() * normalizedEncumbrance;
flySpeed = std::max(0.0f, flySpeed);
moveSpeed = flySpeed;
}
@ -553,8 +559,8 @@ namespace MWClass
if(running)
swimSpeed = runSpeed;
swimSpeed *= 1.0f + 0.01f * mageffects.get(ESM::MagicEffect::SwiftSwim).mMagnitude;
swimSpeed *= fSwimRunBase->getFloat() + 0.01f*getSkill(ptr, ESM::Skill::Athletics) *
fSwimRunAthleticsMult->getFloat();
swimSpeed *= gmst.fSwimRunBase->getFloat() + 0.01f*getSkill(ptr, ESM::Skill::Athletics) *
gmst.fSwimRunAthleticsMult->getFloat();
moveSpeed = swimSpeed;
}
else if(running)
@ -711,7 +717,7 @@ namespace MWClass
MWWorld::LiveCellRef<ESM::Creature> *ref =
ptr.get<ESM::Creature>();
return ref->mBase->mFlags & ESM::Creature::Swims;
return ref->mBase->mFlags & ESM::Creature::Swims || ref->mBase->mFlags & ESM::Creature::Bipedal;
}
bool Creature::canWalk(const MWWorld::Ptr &ptr) const
@ -719,7 +725,7 @@ namespace MWClass
MWWorld::LiveCellRef<ESM::Creature> *ref =
ptr.get<ESM::Creature>();
return ref->mBase->mFlags & ESM::Creature::Walks;
return ref->mBase->mFlags & ESM::Creature::Walks || ref->mBase->mFlags & ESM::Creature::Bipedal;
}
int Creature::getSndGenTypeFromName(const MWWorld::Ptr &ptr, const std::string &name)
@ -796,7 +802,27 @@ namespace MWClass
{
const ESM::CreatureState& state2 = dynamic_cast<const ESM::CreatureState&> (state);
ensureCustomData (ptr);
ensureCustomData(ptr);
// If we do the following instead we get a sizable speedup, but this causes compatibility issues
// with 0.30 savegames, where some state in CreatureStats was not saved yet,
// and therefore needs to be loaded from ESM records. TODO: re-enable this in a future release.
/*
if (!ptr.getRefData().getCustomData())
{
// Create a CustomData, but don't fill it from ESM records (not needed)
std::auto_ptr<CreatureCustomData> data (new CreatureCustomData);
MWWorld::LiveCellRef<ESM::Creature> *ref = ptr.get<ESM::Creature>();
if (ref->mBase->mFlags & ESM::Creature::Weapon)
data->mContainerStore = new MWWorld::InventoryStore();
else
data->mContainerStore = new MWWorld::ContainerStore();
ptr.getRefData().setCustomData (data.release());
}
*/
CreatureCustomData& customData = dynamic_cast<CreatureCustomData&> (*ptr.getRefData().getCustomData());
@ -835,8 +861,7 @@ namespace MWClass
ptr.getRefData().setCount(1);
// Reset to original position
ESM::Position& pos = ptr.getRefData().getPosition();
pos = ptr.getCellRef().getPosition();
ptr.getRefData().setPosition(ptr.getCellRef().getPosition());
ptr.getRefData().setCustomData(NULL);
}
@ -850,19 +875,4 @@ namespace MWClass
MWWorld::ContainerStore& store = getContainerStore(ptr);
store.restock(list, ptr, ptr.getCellRef().getRefId(), ptr.getCellRef().getFaction());
}
const ESM::GameSetting* Creature::fMinWalkSpeedCreature;
const ESM::GameSetting* Creature::fMaxWalkSpeedCreature;
const ESM::GameSetting *Creature::fEncumberedMoveEffect;
const ESM::GameSetting *Creature::fSneakSpeedMultiplier;
const ESM::GameSetting *Creature::fAthleticsRunBonus;
const ESM::GameSetting *Creature::fBaseRunMultiplier;
const ESM::GameSetting *Creature::fMinFlySpeed;
const ESM::GameSetting *Creature::fMaxFlySpeed;
const ESM::GameSetting *Creature::fSwimRunBase;
const ESM::GameSetting *Creature::fSwimRunAthleticsMult;
const ESM::GameSetting *Creature::fKnockDownMult;
const ESM::GameSetting *Creature::iKnockDownOddsMult;
const ESM::GameSetting *Creature::iKnockDownOddsBase;
}

View file

@ -19,20 +19,25 @@ namespace MWClass
static int getSndGenTypeFromName(const MWWorld::Ptr &ptr, const std::string &name);
static const ESM::GameSetting *fMinWalkSpeedCreature;
static const ESM::GameSetting *fMaxWalkSpeedCreature;
static const ESM::GameSetting *fEncumberedMoveEffect;
static const ESM::GameSetting *fSneakSpeedMultiplier;
static const ESM::GameSetting *fAthleticsRunBonus;
static const ESM::GameSetting *fBaseRunMultiplier;
static const ESM::GameSetting *fMinFlySpeed;
static const ESM::GameSetting *fMaxFlySpeed;
static const ESM::GameSetting *fSwimRunBase;
static const ESM::GameSetting *fSwimRunAthleticsMult;
static const ESM::GameSetting *fKnockDownMult;
static const ESM::GameSetting *iKnockDownOddsMult;
static const ESM::GameSetting *iKnockDownOddsBase;
// cached GMSTs
struct GMST
{
const ESM::GameSetting *fMinWalkSpeedCreature;
const ESM::GameSetting *fMaxWalkSpeedCreature;
const ESM::GameSetting *fEncumberedMoveEffect;
const ESM::GameSetting *fSneakSpeedMultiplier;
const ESM::GameSetting *fAthleticsRunBonus;
const ESM::GameSetting *fBaseRunMultiplier;
const ESM::GameSetting *fMinFlySpeed;
const ESM::GameSetting *fMaxFlySpeed;
const ESM::GameSetting *fSwimRunBase;
const ESM::GameSetting *fSwimRunAthleticsMult;
const ESM::GameSetting *fKnockDownMult;
const ESM::GameSetting *iKnockDownOddsMult;
const ESM::GameSetting *iKnockDownOddsBase;
};
static const GMST& getGmst();
public:

View file

@ -57,11 +57,13 @@ namespace MWClass
physics.addObject(ptr);
// Resume the door's opening/closing animation if it wasn't finished
ensureCustomData(ptr);
const DoorCustomData& customData = dynamic_cast<const DoorCustomData&>(*ptr.getRefData().getCustomData());
if (customData.mDoorState > 0)
if (ptr.getRefData().getCustomData())
{
MWBase::Environment::get().getWorld()->activateDoor(ptr, customData.mDoorState == 1 ? true : false);
const DoorCustomData& customData = dynamic_cast<const DoorCustomData&>(*ptr.getRefData().getCustomData());
if (customData.mDoorState > 0)
{
MWBase::Environment::get().getWorld()->activateDoor(ptr, customData.mDoorState == 1 ? true : false);
}
}
}
@ -125,7 +127,7 @@ namespace MWClass
MWBase::Environment::get().getWindowManager()->messageBox(keyName + " #{sKeyUsed}");
unlock(ptr); //Call the function here. because that makes sense.
// using a key disarms the trap
ptr.getCellRef().getTrap() = "";
ptr.getCellRef().setTrap("");
}
if (!needKey || hasKey)

View file

@ -144,7 +144,7 @@ namespace MWClass
std::string text;
text += "\n#{sWeight}: " + MWGui::ToolTips::toString(ref->mBase->mData.mWeight);
text += MWGui::ToolTips::getValueString(getValue(ptr), "#{sValue}");
text += MWGui::ToolTips::getValueString(ref->mBase->mData.mValue, "#{sValue}");
if (MWBase::Environment::get().getWindowManager()->getFullHelp()) {
text += MWGui::ToolTips::getMiscString(ptr.getCellRef().getOwner(), "Owner");

View file

@ -184,7 +184,7 @@ namespace MWClass
std::string text;
text += "\n#{sWeight}: " + MWGui::ToolTips::toString(ref->mBase->mData.mWeight);
text += MWGui::ToolTips::getValueString(getValue(ptr), "#{sValue}");
text += MWGui::ToolTips::getValueString(ref->mBase->mData.mValue, "#{sValue}");
if (MWBase::Environment::get().getWindowManager()->getFullHelp()) {
text += MWGui::ToolTips::getMiscString(ptr.getCellRef().getOwner(), "Owner");

View file

@ -86,7 +86,7 @@ namespace MWClass
MWWorld::LiveCellRef<ESM::Lockpick> *ref =
ptr.get<ESM::Lockpick>();
return ref->mBase->mData.mValue * (static_cast<float>(getItemHealth(ptr)) / getItemMaxHealth(ptr));
return ref->mBase->mData.mValue;
}
void Lockpick::registerSelf()
@ -138,7 +138,7 @@ namespace MWClass
text += "\n#{sUses}: " + MWGui::ToolTips::toString(remainingUses);
text += "\n#{sQuality}: " + MWGui::ToolTips::toString(ref->mBase->mData.mQuality);
text += "\n#{sWeight}: " + MWGui::ToolTips::toString(ref->mBase->mData.mWeight);
text += MWGui::ToolTips::getValueString(getValue(ptr), "#{sValue}");
text += MWGui::ToolTips::getValueString(ref->mBase->mData.mValue, "#{sValue}");
if (MWBase::Environment::get().getWindowManager()->getFullHelp()) {
text += MWGui::ToolTips::getMiscString(ptr.getCellRef().getOwner(), "Owner");

View file

@ -228,38 +228,44 @@ namespace
namespace MWClass
{
void Npc::ensureCustomData (const MWWorld::Ptr& ptr) const
const Npc::GMST& Npc::getGmst()
{
static GMST gmst;
static bool inited = false;
if(!inited)
{
const MWBase::World *world = MWBase::Environment::get().getWorld();
const MWWorld::Store<ESM::GameSetting> &gmst = world->getStore().get<ESM::GameSetting>();
const MWWorld::Store<ESM::GameSetting> &store = world->getStore().get<ESM::GameSetting>();
fMinWalkSpeed = gmst.find("fMinWalkSpeed");
fMaxWalkSpeed = gmst.find("fMaxWalkSpeed");
fEncumberedMoveEffect = gmst.find("fEncumberedMoveEffect");
fSneakSpeedMultiplier = gmst.find("fSneakSpeedMultiplier");
fAthleticsRunBonus = gmst.find("fAthleticsRunBonus");
fBaseRunMultiplier = gmst.find("fBaseRunMultiplier");
fMinFlySpeed = gmst.find("fMinFlySpeed");
fMaxFlySpeed = gmst.find("fMaxFlySpeed");
fSwimRunBase = gmst.find("fSwimRunBase");
fSwimRunAthleticsMult = gmst.find("fSwimRunAthleticsMult");
fJumpEncumbranceBase = gmst.find("fJumpEncumbranceBase");
fJumpEncumbranceMultiplier = gmst.find("fJumpEncumbranceMultiplier");
fJumpAcrobaticsBase = gmst.find("fJumpAcrobaticsBase");
fJumpAcroMultiplier = gmst.find("fJumpAcroMultiplier");
fJumpRunMultiplier = gmst.find("fJumpRunMultiplier");
fWereWolfRunMult = gmst.find("fWereWolfRunMult");
fKnockDownMult = gmst.find("fKnockDownMult");
iKnockDownOddsMult = gmst.find("iKnockDownOddsMult");
iKnockDownOddsBase = gmst.find("iKnockDownOddsBase");
fDamageStrengthBase = gmst.find("fDamageStrengthBase");
fDamageStrengthMult = gmst.find("fDamageStrengthMult");
gmst.fMinWalkSpeed = store.find("fMinWalkSpeed");
gmst.fMaxWalkSpeed = store.find("fMaxWalkSpeed");
gmst.fEncumberedMoveEffect = store.find("fEncumberedMoveEffect");
gmst.fSneakSpeedMultiplier = store.find("fSneakSpeedMultiplier");
gmst.fAthleticsRunBonus = store.find("fAthleticsRunBonus");
gmst.fBaseRunMultiplier = store.find("fBaseRunMultiplier");
gmst.fMinFlySpeed = store.find("fMinFlySpeed");
gmst.fMaxFlySpeed = store.find("fMaxFlySpeed");
gmst.fSwimRunBase = store.find("fSwimRunBase");
gmst.fSwimRunAthleticsMult = store.find("fSwimRunAthleticsMult");
gmst.fJumpEncumbranceBase = store.find("fJumpEncumbranceBase");
gmst.fJumpEncumbranceMultiplier = store.find("fJumpEncumbranceMultiplier");
gmst.fJumpAcrobaticsBase = store.find("fJumpAcrobaticsBase");
gmst.fJumpAcroMultiplier = store.find("fJumpAcroMultiplier");
gmst.fJumpRunMultiplier = store.find("fJumpRunMultiplier");
gmst.fWereWolfRunMult = store.find("fWereWolfRunMult");
gmst.fKnockDownMult = store.find("fKnockDownMult");
gmst.iKnockDownOddsMult = store.find("iKnockDownOddsMult");
gmst.iKnockDownOddsBase = store.find("iKnockDownOddsBase");
gmst.fDamageStrengthBase = store.find("fDamageStrengthBase");
gmst.fDamageStrengthMult = store.find("fDamageStrengthMult");
inited = true;
}
return gmst;
}
void Npc::ensureCustomData (const MWWorld::Ptr& ptr) const
{
if (!ptr.getRefData().getCustomData())
{
std::auto_ptr<NpcCustomData> data(new NpcCustomData);
@ -404,11 +410,6 @@ namespace MWClass
ptr.get<ESM::NPC>();
assert(ref->mBase != NULL);
//std::string headID = ref->mBase->mHead;
//int end = headID.find_last_of("head_") - 4;
//std::string bodyRaceID = headID.substr(0, end);
std::string model = "meshes\\base_anim.nif";
const ESM::Race* race = MWBase::Environment::get().getWorld()->getStore().get<ESM::Race>().find(ref->mBase->mRace);
if(race->mData.mFlags & ESM::Race::Beast)
@ -423,9 +424,9 @@ namespace MWClass
if(getNpcStats(ptr).isWerewolf())
{
const MWBase::World *world = MWBase::Environment::get().getWorld();
const MWWorld::Store<ESM::GameSetting> &gmst = world->getStore().get<ESM::GameSetting>();
const MWWorld::Store<ESM::GameSetting> &store = world->getStore().get<ESM::GameSetting>();
return gmst.find("sWerewolfPopup")->getString();
return store.find("sWerewolfPopup")->getString();
}
MWWorld::LiveCellRef<ESM::NPC> *ref = ptr.get<ESM::NPC>();
@ -450,7 +451,9 @@ namespace MWClass
void Npc::hit(const MWWorld::Ptr& ptr, int type) const
{
MWBase::World *world = MWBase::Environment::get().getWorld();
const MWWorld::Store<ESM::GameSetting> &gmst = world->getStore().get<ESM::GameSetting>();
const GMST& gmst = getGmst();
const MWWorld::Store<ESM::GameSetting> &store = world->getStore().get<ESM::GameSetting>();
// Get the weapon used (if hand-to-hand, weapon = inv.end())
MWWorld::InventoryStore &inv = getInventoryStore(ptr);
@ -461,9 +464,9 @@ namespace MWClass
// Reduce fatigue
// somewhat of a guess, but using the weapon weight makes sense
const float fFatigueAttackBase = gmst.find("fFatigueAttackBase")->getFloat();
const float fFatigueAttackMult = gmst.find("fFatigueAttackMult")->getFloat();
const float fWeaponFatigueMult = gmst.find("fWeaponFatigueMult")->getFloat();
const float fFatigueAttackBase = store.find("fFatigueAttackBase")->getFloat();
const float fFatigueAttackMult = store.find("fFatigueAttackMult")->getFloat();
const float fWeaponFatigueMult = store.find("fWeaponFatigueMult")->getFloat();
MWMechanics::DynamicStat<float> fatigue = getCreatureStats(ptr).getFatigue();
const float normalizedEncumbrance = getEncumbrance(ptr) / getCapacity(ptr);
float fatigueLoss = fFatigueAttackBase + normalizedEncumbrance * fFatigueAttackMult;
@ -472,10 +475,10 @@ namespace MWClass
fatigue.setCurrent(fatigue.getCurrent() - fatigueLoss);
getCreatureStats(ptr).setFatigue(fatigue);
const float fCombatDistance = gmst.find("fCombatDistance")->getFloat();
const float fCombatDistance = store.find("fCombatDistance")->getFloat();
float dist = fCombatDistance * (!weapon.isEmpty() ?
weapon.get<ESM::Weapon>()->mBase->mData.mReach :
gmst.find("fHandToHandReach")->getFloat());
store.find("fHandToHandReach")->getFloat());
// TODO: Use second to work out the hit angle
std::pair<MWWorld::Ptr, Ogre::Vector3> result = world->getHitContact(ptr, dist);
@ -522,8 +525,8 @@ namespace MWClass
if(attack)
{
damage = attack[0] + ((attack[1]-attack[0])*stats.getAttackStrength());
damage *= fDamageStrengthBase->getFloat() +
(stats.getAttribute(ESM::Attribute::Strength).getModified() * fDamageStrengthMult->getFloat() * 0.1);
damage *= gmst.fDamageStrengthBase->getFloat() +
(stats.getAttribute(ESM::Attribute::Strength).getModified() * gmst.fDamageStrengthMult->getFloat() * 0.1);
if(weaphashealth)
{
int weapmaxhealth = weapon.getClass().getItemMaxHealth(weapon);
@ -535,7 +538,7 @@ namespace MWClass
{
// Reduce weapon charge by at least one, but cap at 0
weaphealth -= std::min(std::max(1,
(int)(damage * gmst.find("fWeaponDamageMult")->getFloat())), weaphealth);
(int)(damage * store.find("fWeaponDamageMult")->getFloat())), weaphealth);
weapon.getCellRef().setCharge(weaphealth);
}
@ -552,8 +555,8 @@ namespace MWClass
// Note: MCP contains an option to include Strength in hand-to-hand damage
// calculations. Some mods recommend using it, so we may want to include am
// option for it.
float minstrike = gmst.find("fMinHandToHandMult")->getFloat();
float maxstrike = gmst.find("fMaxHandToHandMult")->getFloat();
float minstrike = store.find("fMinHandToHandMult")->getFloat();
float maxstrike = store.find("fMaxHandToHandMult")->getFloat();
damage = stats.getSkill(weapskill).getModified();
damage *= minstrike + ((maxstrike-minstrike)*stats.getAttackStrength());
@ -567,7 +570,7 @@ namespace MWClass
damage *= glob.find("WerewolfClawMult")->mValue.getFloat();
}
if(healthdmg)
damage *= gmst.find("fHandtoHandHealthPer")->getFloat();
damage *= store.find("fHandtoHandHealthPer")->getFloat();
MWBase::SoundManager *sndMgr = MWBase::Environment::get().getSoundManager();
if(stats.isWerewolf())
@ -585,12 +588,12 @@ namespace MWClass
bool detected = MWBase::Environment::get().getMechanicsManager()->awarenessCheck(ptr, victim);
if(!detected)
{
damage *= gmst.find("fCombatCriticalStrikeMult")->getFloat();
damage *= store.find("fCombatCriticalStrikeMult")->getFloat();
MWBase::Environment::get().getWindowManager()->messageBox("#{sTargetCriticalStrike}");
MWBase::Environment::get().getSoundManager()->playSound3D(victim, "critical damage", 1.0f, 1.0f);
}
if (othercls.getCreatureStats(victim).getKnockedDown())
damage *= gmst.find("fCombatKODamageMult")->getFloat();
damage *= store.find("fCombatKODamageMult")->getFloat();
// Apply "On hit" enchanted weapons
std::string enchantmentName = !weapon.isEmpty() ? weapon.getClass().getEnchantment(weapon) : "";
@ -624,11 +627,12 @@ namespace MWClass
// NOTE: 'object' and/or 'attacker' may be empty.
// Attacking peaceful NPCs is a crime
// anything below 80 is considered peaceful (see Actors::updateActor)
if (!attacker.isEmpty() && !ptr.getClass().getCreatureStats(ptr).isHostile() &&
ptr.getClass().getCreatureStats(ptr).getAiSetting(MWMechanics::CreatureStats::AI_Fight).getModified() < 80)
!MWBase::Environment::get().getMechanicsManager()->isAggressive(ptr, attacker))
MWBase::Environment::get().getMechanicsManager()->commitCrime(attacker, ptr, MWBase::MechanicsManager::OT_Assault);
bool wasDead = getCreatureStats(ptr).isDead();
getCreatureStats(ptr).setAttacked(true);
if(!successful)
@ -660,6 +664,8 @@ namespace MWClass
// something, alert the character controller, scripts, etc.
const MWWorld::ESMStore &store = MWBase::Environment::get().getWorld()->getStore();
const GMST& gmst = getGmst();
int chance = store.get<ESM::GameSetting>().find("iVoiceHitOdds")->getInt();
int roll = std::rand()/ (static_cast<double> (RAND_MAX) + 1) * 100; // [0, 99]
if (roll < chance)
@ -668,9 +674,9 @@ namespace MWClass
}
// Check for knockdown
float agilityTerm = getCreatureStats(ptr).getAttribute(ESM::Attribute::Agility).getModified() * fKnockDownMult->getFloat();
float agilityTerm = getCreatureStats(ptr).getAttribute(ESM::Attribute::Agility).getModified() * gmst.fKnockDownMult->getFloat();
float knockdownTerm = getCreatureStats(ptr).getAttribute(ESM::Attribute::Agility).getModified()
* iKnockDownOddsMult->getInt() * 0.01 + iKnockDownOddsBase->getInt();
* gmst.iKnockDownOddsMult->getInt() * 0.01 + gmst.iKnockDownOddsBase->getInt();
roll = std::rand()/ (static_cast<double> (RAND_MAX) + 1) * 100; // [0, 99]
if (ishealth && agilityTerm <= damage && knockdownTerm <= roll)
{
@ -752,6 +758,22 @@ namespace MWClass
fatigue.setCurrent(fatigue.getCurrent() - damage, true);
getCreatureStats(ptr).setFatigue(fatigue);
}
if (!wasDead && getCreatureStats(ptr).isDead())
{
// NPC was killed
if (!attacker.isEmpty() && attacker.getClass().isNpc() && attacker.getClass().getNpcStats(attacker).isWerewolf())
{
attacker.getClass().getNpcStats(attacker).addWerewolfKill();
}
// Simple check for who attacked first: if the player attacked first, a crimeId should be set
// Doesn't handle possible edge case where no one reported the assault, but in such a case,
// for bystanders it is not possible to tell who attacked first, anyway.
MWWorld::Ptr player = MWBase::Environment::get().getWorld()->getPlayerPtr();
if (attacker == player && ptr.getClass().getNpcStats(ptr).getCrimeId() != -1 && ptr != player)
MWBase::Environment::get().getMechanicsManager()->commitCrime(player, ptr, MWBase::MechanicsManager::OT_Murder);
}
}
void Npc::block(const MWWorld::Ptr &ptr) const
@ -853,6 +875,8 @@ namespace MWClass
float Npc::getSpeed(const MWWorld::Ptr& ptr) const
{
const MWBase::World *world = MWBase::Environment::get().getWorld();
const GMST& gmst = getGmst();
const NpcCustomData *npcdata = static_cast<const NpcCustomData*>(ptr.getRefData().getCustomData());
const MWMechanics::MagicEffects &mageffects = npcdata->mNpcStats.getMagicEffects();
@ -861,17 +885,17 @@ namespace MWClass
bool sneaking = ptr.getClass().getCreatureStats(ptr).getStance(MWMechanics::CreatureStats::Stance_Sneak);
bool running = ptr.getClass().getCreatureStats(ptr).getStance(MWMechanics::CreatureStats::Stance_Run);
float walkSpeed = fMinWalkSpeed->getFloat() + 0.01f*npcdata->mNpcStats.getAttribute(ESM::Attribute::Speed).getModified()*
(fMaxWalkSpeed->getFloat() - fMinWalkSpeed->getFloat());
walkSpeed *= 1.0f - fEncumberedMoveEffect->getFloat()*normalizedEncumbrance;
float walkSpeed = gmst.fMinWalkSpeed->getFloat() + 0.01f*npcdata->mNpcStats.getAttribute(ESM::Attribute::Speed).getModified()*
(gmst.fMaxWalkSpeed->getFloat() - gmst.fMinWalkSpeed->getFloat());
walkSpeed *= 1.0f - gmst.fEncumberedMoveEffect->getFloat()*normalizedEncumbrance;
walkSpeed = std::max(0.0f, walkSpeed);
if(sneaking)
walkSpeed *= fSneakSpeedMultiplier->getFloat();
walkSpeed *= gmst.fSneakSpeedMultiplier->getFloat();
float runSpeed = walkSpeed*(0.01f * npcdata->mNpcStats.getSkill(ESM::Skill::Athletics).getModified() *
fAthleticsRunBonus->getFloat() + fBaseRunMultiplier->getFloat());
gmst.fAthleticsRunBonus->getFloat() + gmst.fBaseRunMultiplier->getFloat());
if(npcdata->mNpcStats.isWerewolf())
runSpeed *= fWereWolfRunMult->getFloat();
runSpeed *= gmst.fWereWolfRunMult->getFloat();
float moveSpeed;
if(normalizedEncumbrance >= 1.0f)
@ -881,8 +905,8 @@ namespace MWClass
{
float flySpeed = 0.01f*(npcdata->mNpcStats.getAttribute(ESM::Attribute::Speed).getModified() +
mageffects.get(ESM::MagicEffect::Levitate).mMagnitude);
flySpeed = fMinFlySpeed->getFloat() + flySpeed*(fMaxFlySpeed->getFloat() - fMinFlySpeed->getFloat());
flySpeed *= 1.0f - fEncumberedMoveEffect->getFloat() * normalizedEncumbrance;
flySpeed = gmst.fMinFlySpeed->getFloat() + flySpeed*(gmst.fMaxFlySpeed->getFloat() - gmst.fMinFlySpeed->getFloat());
flySpeed *= 1.0f - gmst.fEncumberedMoveEffect->getFloat() * normalizedEncumbrance;
flySpeed = std::max(0.0f, flySpeed);
moveSpeed = flySpeed;
}
@ -892,8 +916,8 @@ namespace MWClass
if(running)
swimSpeed = runSpeed;
swimSpeed *= 1.0f + 0.01f * mageffects.get(ESM::MagicEffect::SwiftSwim).mMagnitude;
swimSpeed *= fSwimRunBase->getFloat() + 0.01f*npcdata->mNpcStats.getSkill(ESM::Skill::Athletics).getModified()*
fSwimRunAthleticsMult->getFloat();
swimSpeed *= gmst.fSwimRunBase->getFloat() + 0.01f*npcdata->mNpcStats.getSkill(ESM::Skill::Athletics).getModified()*
gmst.fSwimRunAthleticsMult->getFloat();
moveSpeed = swimSpeed;
}
else if(running && !sneaking)
@ -909,9 +933,10 @@ namespace MWClass
float Npc::getJump(const MWWorld::Ptr &ptr) const
{
const NpcCustomData *npcdata = static_cast<const NpcCustomData*>(ptr.getRefData().getCustomData());
const GMST& gmst = getGmst();
const MWMechanics::MagicEffects &mageffects = npcdata->mNpcStats.getMagicEffects();
const float encumbranceTerm = fJumpEncumbranceBase->getFloat() +
fJumpEncumbranceMultiplier->getFloat() *
const float encumbranceTerm = gmst.fJumpEncumbranceBase->getFloat() +
gmst.fJumpEncumbranceMultiplier->getFloat() *
(1.0f - Npc::getEncumbrance(ptr)/Npc::getCapacity(ptr));
float a = npcdata->mNpcStats.getSkill(ESM::Skill::Acrobatics).getModified();
@ -922,14 +947,14 @@ namespace MWClass
a = 50.0f;
}
float x = fJumpAcrobaticsBase->getFloat() +
std::pow(a / 15.0f, fJumpAcroMultiplier->getFloat());
x += 3.0f * b * fJumpAcroMultiplier->getFloat();
float x = gmst.fJumpAcrobaticsBase->getFloat() +
std::pow(a / 15.0f, gmst.fJumpAcroMultiplier->getFloat());
x += 3.0f * b * gmst.fJumpAcroMultiplier->getFloat();
x += mageffects.get(ESM::MagicEffect::Jump).mMagnitude * 64;
x *= encumbranceTerm;
if(ptr.getClass().getCreatureStats(ptr).getStance(MWMechanics::CreatureStats::Stance_Run))
x *= fJumpRunMultiplier->getFloat();
x *= gmst.fJumpRunMultiplier->getFloat();
x *= npcdata->mNpcStats.getFatigueTerm();
x -= -627.2f;/*gravity constant*/
x /= 3.0f;
@ -940,19 +965,19 @@ namespace MWClass
float Npc::getFallDamage(const MWWorld::Ptr &ptr, float fallHeight) const
{
MWBase::World *world = MWBase::Environment::get().getWorld();
const MWWorld::Store<ESM::GameSetting> &gmst = world->getStore().get<ESM::GameSetting>();
const MWWorld::Store<ESM::GameSetting> &store = world->getStore().get<ESM::GameSetting>();
const float fallDistanceMin = gmst.find("fFallDamageDistanceMin")->getFloat();
const float fallDistanceMin = store.find("fFallDamageDistanceMin")->getFloat();
if (fallHeight >= fallDistanceMin)
{
const float acrobaticsSkill = ptr.getClass().getNpcStats (ptr).getSkill(ESM::Skill::Acrobatics).getModified();
const NpcCustomData *npcdata = static_cast<const NpcCustomData*>(ptr.getRefData().getCustomData());
const float jumpSpellBonus = npcdata->mNpcStats.getMagicEffects().get(ESM::MagicEffect::Jump).mMagnitude;
const float fallAcroBase = gmst.find("fFallAcroBase")->getFloat();
const float fallAcroMult = gmst.find("fFallAcroMult")->getFloat();
const float fallDistanceBase = gmst.find("fFallDistanceBase")->getFloat();
const float fallDistanceMult = gmst.find("fFallDistanceMult")->getFloat();
const float fallAcroBase = store.find("fFallAcroBase")->getFloat();
const float fallAcroMult = store.find("fFallAcroMult")->getFloat();
const float fallDistanceBase = store.find("fFallDistanceBase")->getFloat();
const float fallDistanceMult = store.find("fFallDistanceMult")->getFloat();
float x = fallHeight - fallDistanceMin;
x -= (1.5 * acrobaticsSkill) + jumpSpellBonus;
@ -1087,14 +1112,14 @@ namespace MWClass
float Npc::getArmorRating (const MWWorld::Ptr& ptr) const
{
const MWBase::World *world = MWBase::Environment::get().getWorld();
const MWWorld::Store<ESM::GameSetting> &gmst = world->getStore().get<ESM::GameSetting>();
const MWWorld::Store<ESM::GameSetting> &store = world->getStore().get<ESM::GameSetting>();
MWMechanics::NpcStats &stats = getNpcStats(ptr);
MWWorld::InventoryStore &invStore = getInventoryStore(ptr);
int iBaseArmorSkill = gmst.find("iBaseArmorSkill")->getInt();
float fUnarmoredBase1 = gmst.find("fUnarmoredBase1")->getFloat();
float fUnarmoredBase2 = gmst.find("fUnarmoredBase2")->getFloat();
int iBaseArmorSkill = store.find("iBaseArmorSkill")->getInt();
float fUnarmoredBase1 = store.find("fUnarmoredBase1")->getFloat();
float fUnarmoredBase2 = store.find("fUnarmoredBase2")->getFloat();
int unarmoredSkill = stats.getSkill(ESM::Skill::Unarmored).getModified();
int ratings[MWWorld::InventoryStore::Slots];
@ -1276,7 +1301,18 @@ namespace MWClass
{
const ESM::NpcState& state2 = dynamic_cast<const ESM::NpcState&> (state);
ensureCustomData (ptr);
ensureCustomData(ptr);
// If we do the following instead we get a sizable speedup, but this causes compatibility issues
// with 0.30 savegames, where some state in CreatureStats was not saved yet,
// and therefore needs to be loaded from ESM records. TODO: re-enable this in a future release.
/*
if (!ptr.getRefData().getCustomData())
{
// Create a CustomData, but don't fill it from ESM records (not needed)
std::auto_ptr<NpcCustomData> data (new NpcCustomData);
ptr.getRefData().setCustomData (data.release());
}
*/
NpcCustomData& customData = dynamic_cast<NpcCustomData&> (*ptr.getRefData().getCustomData());
@ -1325,8 +1361,7 @@ namespace MWClass
ptr.getRefData().setCount(1);
// Reset to original position
ESM::Position& pos = ptr.getRefData().getPosition();
pos = ptr.getCellRef().getPosition();
ptr.getRefData().setPosition(ptr.getCellRef().getPosition());
ptr.getRefData().setCustomData(NULL);
}
@ -1340,27 +1375,4 @@ namespace MWClass
MWWorld::ContainerStore& store = getContainerStore(ptr);
store.restock(list, ptr, ptr.getCellRef().getRefId(), ptr.getCellRef().getFaction());
}
const ESM::GameSetting *Npc::fMinWalkSpeed;
const ESM::GameSetting *Npc::fMaxWalkSpeed;
const ESM::GameSetting *Npc::fEncumberedMoveEffect;
const ESM::GameSetting *Npc::fSneakSpeedMultiplier;
const ESM::GameSetting *Npc::fAthleticsRunBonus;
const ESM::GameSetting *Npc::fBaseRunMultiplier;
const ESM::GameSetting *Npc::fMinFlySpeed;
const ESM::GameSetting *Npc::fMaxFlySpeed;
const ESM::GameSetting *Npc::fSwimRunBase;
const ESM::GameSetting *Npc::fSwimRunAthleticsMult;
const ESM::GameSetting *Npc::fJumpEncumbranceBase;
const ESM::GameSetting *Npc::fJumpEncumbranceMultiplier;
const ESM::GameSetting *Npc::fJumpAcrobaticsBase;
const ESM::GameSetting *Npc::fJumpAcroMultiplier;
const ESM::GameSetting *Npc::fJumpRunMultiplier;
const ESM::GameSetting *Npc::fWereWolfRunMult;
const ESM::GameSetting *Npc::fKnockDownMult;
const ESM::GameSetting *Npc::iKnockDownOddsMult;
const ESM::GameSetting *Npc::iKnockDownOddsBase;
const ESM::GameSetting *Npc::fDamageStrengthBase;
const ESM::GameSetting *Npc::fDamageStrengthMult;
}

View file

@ -17,27 +17,32 @@ namespace MWClass
virtual MWWorld::Ptr
copyToCellImpl(const MWWorld::Ptr &ptr, MWWorld::CellStore &cell) const;
static const ESM::GameSetting *fMinWalkSpeed;
static const ESM::GameSetting *fMaxWalkSpeed;
static const ESM::GameSetting *fEncumberedMoveEffect;
static const ESM::GameSetting *fSneakSpeedMultiplier;
static const ESM::GameSetting *fAthleticsRunBonus;
static const ESM::GameSetting *fBaseRunMultiplier;
static const ESM::GameSetting *fMinFlySpeed;
static const ESM::GameSetting *fMaxFlySpeed;
static const ESM::GameSetting *fSwimRunBase;
static const ESM::GameSetting *fSwimRunAthleticsMult;
static const ESM::GameSetting *fJumpEncumbranceBase;
static const ESM::GameSetting *fJumpEncumbranceMultiplier;
static const ESM::GameSetting *fJumpAcrobaticsBase;
static const ESM::GameSetting *fJumpAcroMultiplier;
static const ESM::GameSetting *fJumpRunMultiplier;
static const ESM::GameSetting *fWereWolfRunMult;
static const ESM::GameSetting *fKnockDownMult;
static const ESM::GameSetting *iKnockDownOddsMult;
static const ESM::GameSetting *iKnockDownOddsBase;
static const ESM::GameSetting *fDamageStrengthBase;
static const ESM::GameSetting *fDamageStrengthMult;
struct GMST
{
const ESM::GameSetting *fMinWalkSpeed;
const ESM::GameSetting *fMaxWalkSpeed;
const ESM::GameSetting *fEncumberedMoveEffect;
const ESM::GameSetting *fSneakSpeedMultiplier;
const ESM::GameSetting *fAthleticsRunBonus;
const ESM::GameSetting *fBaseRunMultiplier;
const ESM::GameSetting *fMinFlySpeed;
const ESM::GameSetting *fMaxFlySpeed;
const ESM::GameSetting *fSwimRunBase;
const ESM::GameSetting *fSwimRunAthleticsMult;
const ESM::GameSetting *fJumpEncumbranceBase;
const ESM::GameSetting *fJumpEncumbranceMultiplier;
const ESM::GameSetting *fJumpAcrobaticsBase;
const ESM::GameSetting *fJumpAcroMultiplier;
const ESM::GameSetting *fJumpRunMultiplier;
const ESM::GameSetting *fWereWolfRunMult;
const ESM::GameSetting *fKnockDownMult;
const ESM::GameSetting *iKnockDownOddsMult;
const ESM::GameSetting *iKnockDownOddsBase;
const ESM::GameSetting *fDamageStrengthBase;
const ESM::GameSetting *fDamageStrengthMult;
};
static const GMST& getGmst();
public:

View file

@ -127,7 +127,7 @@ namespace MWClass
std::string text;
text += "\n#{sWeight}: " + MWGui::ToolTips::toString(ref->mBase->mData.mWeight);
text += MWGui::ToolTips::getValueString(getValue(ptr), "#{sValue}");
text += MWGui::ToolTips::getValueString(ref->mBase->mData.mValue, "#{sValue}");
info.effects = MWGui::Widgets::MWEffectList::effectListFromESM(&ref->mBase->mEffects);
@ -166,13 +166,8 @@ namespace MWClass
MWWorld::LiveCellRef<ESM::Potion> *ref =
ptr.get<ESM::Potion>();
MWWorld::Ptr actor = MWBase::Environment::get().getWorld()->getPlayerPtr();
// remove used potion (assume it is present in inventory)
ptr.getContainerStore()->remove(ptr, 1, actor);
boost::shared_ptr<MWWorld::Action> action (
new MWWorld::ActionApply (actor, ref->mBase->mId));
new MWWorld::ActionApply (ptr, ref->mBase->mId));
action->setSound ("Drink");

View file

@ -85,7 +85,7 @@ namespace MWClass
MWWorld::LiveCellRef<ESM::Probe> *ref =
ptr.get<ESM::Probe>();
return ref->mBase->mData.mValue * (static_cast<float>(getItemHealth(ptr)) / getItemMaxHealth(ptr));
return ref->mBase->mData.mValue;
}
void Probe::registerSelf()
@ -137,7 +137,7 @@ namespace MWClass
text += "\n#{sUses}: " + MWGui::ToolTips::toString(remainingUses);
text += "\n#{sQuality}: " + MWGui::ToolTips::toString(ref->mBase->mData.mQuality);
text += "\n#{sWeight}: " + MWGui::ToolTips::toString(ref->mBase->mData.mWeight);
text += MWGui::ToolTips::getValueString(getValue(ptr), "#{sValue}");
text += MWGui::ToolTips::getValueString(ref->mBase->mData.mValue, "#{sValue}");
if (MWBase::Environment::get().getWindowManager()->getFullHelp()) {
text += MWGui::ToolTips::getMiscString(ptr.getCellRef().getOwner(), "Owner");

View file

@ -76,7 +76,7 @@ namespace MWClass
MWWorld::LiveCellRef<ESM::Repair> *ref =
ptr.get<ESM::Repair>();
return ref->mBase->mData.mValue * (static_cast<float>(getItemHealth(ptr)) / getItemMaxHealth(ptr));
return ref->mBase->mData.mValue;
}
void Repair::registerSelf()
@ -141,7 +141,7 @@ namespace MWClass
text += "\n#{sUses}: " + MWGui::ToolTips::toString(remainingUses);
text += "\n#{sQuality}: " + MWGui::ToolTips::toString(ref->mBase->mData.mQuality);
text += "\n#{sWeight}: " + MWGui::ToolTips::toString(ref->mBase->mData.mWeight);
text += MWGui::ToolTips::getValueString(getValue(ptr), "#{sValue}");
text += MWGui::ToolTips::getValueString(ref->mBase->mData.mValue, "#{sValue}");
if (MWBase::Environment::get().getWindowManager()->getFullHelp()) {
text += MWGui::ToolTips::getMiscString(ptr.getCellRef().getOwner(), "Owner");

View file

@ -14,9 +14,12 @@ namespace MWClass
{
void Static::insertObjectRendering (const MWWorld::Ptr& ptr, MWRender::RenderingInterface& renderingInterface) const
{
MWWorld::LiveCellRef<ESM::Static> *ref =
ptr.get<ESM::Static>();
const std::string model = getModel(ptr);
if (!model.empty()) {
renderingInterface.getObjects().insertModel(ptr, model);
renderingInterface.getObjects().insertModel(ptr, model, !ref->mBase->mPersistent);
}
}

View file

@ -154,7 +154,7 @@ namespace MWClass
MWWorld::LiveCellRef<ESM::Weapon> *ref =
ptr.get<ESM::Weapon>();
return ref->mBase->mData.mValue * (static_cast<float>(getItemHealth(ptr)) / getItemMaxHealth(ptr));
return ref->mBase->mData.mValue;
}
void Weapon::registerSelf()
@ -343,7 +343,7 @@ namespace MWClass
}
text += "\n#{sWeight}: " + MWGui::ToolTips::toString(ref->mBase->mData.mWeight);
text += MWGui::ToolTips::getValueString(getValue(ptr), "#{sValue}");
text += MWGui::ToolTips::getValueString(ref->mBase->mData.mValue, "#{sValue}");
info.enchant = ref->mBase->mEnchant;

View file

@ -125,6 +125,10 @@ namespace MWDialogue
void DialogueManager::startDialogue (const MWWorld::Ptr& actor)
{
// Dialogue with dead actor (e.g. through script) should not be allowed.
if (actor.getClass().getCreatureStats(actor).isDead())
return;
mLastTopic = "";
mPermanentDispositionChange = 0;
mTemporaryDispositionChange = 0;
@ -140,7 +144,11 @@ namespace MWDialogue
mActorKnownTopics.clear();
MWGui::DialogueWindow* win = MWBase::Environment::get().getWindowManager()->getDialogueWindow();
win->startDialogue(actor, actor.getClass().getName (actor));
// If the dialogue window was already open, keep the existing history
bool resetHistory = (!MWBase::Environment::get().getWindowManager()->containsMode(MWGui::GM_Dialogue));
win->startDialogue(actor, actor.getClass().getName (actor), resetHistory);
//setup the list of topics known by the actor. Topics who are also on the knownTopics list will be added to the GUI
updateTopics();
@ -174,10 +182,20 @@ namespace MWDialogue
win->addResponse (Interpreter::fixDefinesDialog(info->mResponse, interpreterContext));
executeScript (info->mResultScript);
mLastTopic = Misc::StringUtils::lowerCase(it->mId);
break;
return;
}
}
}
// No greetings found. The dialogue window should not be shown.
// If this is a companion, we must show the companion window directly (used by BM_bear_be_unique).
bool isCompanion = !mActor.getClass().getScript(mActor).empty()
&& mActor.getRefData().getLocals().getIntVar(mActor.getClass().getScript(mActor), "companion");
if (isCompanion)
{
MWBase::Environment::get().getWindowManager()->pushGuiMode(MWGui::GM_Companion);
MWBase::Environment::get().getWindowManager()->showCompanionWindow(mActor);
}
}
bool DialogueManager::compile (const std::string& cmd,std::vector<Interpreter::Type_Code>& code)
@ -294,7 +312,7 @@ namespace MWDialogue
{
if (iter->mId == info->mId)
{
MWBase::Environment::get().getJournal()->addTopic (topic, info->mId, mActor.getClass().getName(mActor));
MWBase::Environment::get().getJournal()->addTopic (topic, info->mId, mActor);
break;
}
}
@ -398,7 +416,7 @@ namespace MWDialogue
win->setServices (windowServices);
// sort again, because the previous sort was case-sensitive
keywordList.sort(Misc::StringUtils::ciEqual);
keywordList.sort(Misc::StringUtils::ciLess);
win->setKeywords(keywordList);
mChoice = choice;
@ -472,7 +490,7 @@ namespace MWDialogue
{
if (iter->mId == info->mId)
{
MWBase::Environment::get().getJournal()->addTopic (mLastTopic, info->mId, mActor.getClass().getName(mActor));
MWBase::Environment::get().getJournal()->addTopic (mLastTopic, info->mId, mActor);
break;
}
}
@ -694,6 +712,15 @@ namespace MWDialogue
return diff;
}
void DialogueManager::clearInfoActor(const MWWorld::Ptr &actor) const
{
if (actor == mActor && !mLastTopic.empty())
{
MWBase::Environment::get().getJournal()->removeLastAddedTopicResponse(
mLastTopic, actor.getClass().getName(actor));
}
}
std::vector<HyperTextToken> ParseHyperText(const std::string& text)
{
std::vector<HyperTextToken> result;

View file

@ -40,7 +40,7 @@ namespace MWDialogue
bool mTalkedTo;
int mChoice;
std::string mLastTopic;
std::string mLastTopic; // last topic ID, lowercase
bool mIsInChoice;
float mTemporaryDispositionChange;
@ -99,6 +99,9 @@ namespace MWDialogue
/// @return faction1's opinion of faction2
virtual int getFactionReaction (const std::string& faction1, const std::string& faction2) const;
/// Removes the last added topic response for the given actor from the journal
virtual void clearInfoActor (const MWWorld::Ptr& actor) const;
};

View file

@ -530,7 +530,8 @@ bool MWDialogue::Filter::getSelectStructBoolean (const SelectWrapper& select) co
case SelectWrapper::Function_ShouldAttack:
return mActor.getClass().getCreatureStats(mActor).getAiSetting(MWMechanics::CreatureStats::AI_Fight).getModified() >= 80;
return MWBase::Environment::get().getMechanicsManager()->isAggressive(mActor,
MWBase::Environment::get().getWorld()->getPlayerPtr());
case SelectWrapper::Function_CreatureTargetted:

View file

@ -5,16 +5,21 @@
#include <components/esm/journalentry.hpp>
#include <components/interpreter/defines.hpp>
#include "../mwbase/environment.hpp"
#include "../mwbase/world.hpp"
#include "../mwworld/esmstore.hpp"
#include "../mwscript/interpretercontext.hpp"
namespace MWDialogue
{
Entry::Entry() {}
Entry::Entry (const std::string& topic, const std::string& infoId)
Entry::Entry (const std::string& topic, const std::string& infoId, const MWWorld::Ptr& actor)
: mInfoId (infoId)
{
const ESM::Dialogue *dialogue =
@ -24,8 +29,17 @@ namespace MWDialogue
iter!=dialogue->mInfo.end(); ++iter)
if (iter->mId == mInfoId)
{
/// \todo text replacement
mText = iter->mResponse;
if (actor.isEmpty())
{
MWScript::InterpreterContext interpreterContext(NULL,MWWorld::Ptr());
mText = Interpreter::fixDefinesDialog(iter->mResponse, interpreterContext);
}
else
{
MWScript::InterpreterContext interpreterContext(&actor.getRefData().getLocals(),actor);
mText = Interpreter::fixDefinesDialog(iter->mResponse, interpreterContext);
}
return;
}
@ -49,8 +63,8 @@ namespace MWDialogue
JournalEntry::JournalEntry() {}
JournalEntry::JournalEntry (const std::string& topic, const std::string& infoId)
: Entry (topic, infoId), mTopic (topic)
JournalEntry::JournalEntry (const std::string& topic, const std::string& infoId, const MWWorld::Ptr& actor)
: Entry (topic, infoId, actor), mTopic (topic)
{}
JournalEntry::JournalEntry (const ESM::JournalEntry& record)
@ -65,7 +79,7 @@ namespace MWDialogue
JournalEntry JournalEntry::makeFromQuest (const std::string& topic, int index)
{
return JournalEntry (topic, idFromIndex (topic, index));
return JournalEntry (topic, idFromIndex (topic, index), MWWorld::Ptr());
}
std::string JournalEntry::idFromIndex (const std::string& topic, int index)
@ -90,7 +104,7 @@ namespace MWDialogue
StampedJournalEntry::StampedJournalEntry (const std::string& topic, const std::string& infoId,
int day, int month, int dayOfMonth)
: JournalEntry (topic, infoId), mDay (day), mMonth (month), mDayOfMonth (dayOfMonth)
: JournalEntry (topic, infoId, MWWorld::Ptr()), mDay (day), mMonth (month), mDayOfMonth (dayOfMonth)
{}
StampedJournalEntry::StampedJournalEntry (const ESM::JournalEntry& record)

View file

@ -8,6 +8,11 @@ namespace ESM
struct JournalEntry;
}
namespace MWWorld
{
class Ptr;
}
namespace MWDialogue
{
/// \brief Basic quest/dialogue/topic entry
@ -19,7 +24,8 @@ namespace MWDialogue
Entry();
Entry (const std::string& topic, const std::string& infoId);
/// actor is optional
Entry (const std::string& topic, const std::string& infoId, const MWWorld::Ptr& actor);
Entry (const ESM::JournalEntry& record);
@ -37,7 +43,7 @@ namespace MWDialogue
JournalEntry();
JournalEntry (const std::string& topic, const std::string& infoId);
JournalEntry (const std::string& topic, const std::string& infoId, const MWWorld::Ptr& actor);
JournalEntry (const ESM::JournalEntry& record);

View file

@ -9,6 +9,7 @@
#include <components/esm/journalentry.hpp>
#include "../mwworld/esmstore.hpp"
#include "../mwworld/class.hpp"
#include "../mwbase/environment.hpp"
#include "../mwbase/world.hpp"
@ -103,15 +104,25 @@ namespace MWDialogue
quest.setIndex (index);
}
void Journal::addTopic (const std::string& topicId, const std::string& infoId, const std::string& actorName)
void Journal::addTopic (const std::string& topicId, const std::string& infoId, const MWWorld::Ptr& actor)
{
Topic& topic = getTopic (topicId);
JournalEntry entry(topicId, infoId);
entry.mActorName = actorName;
JournalEntry entry(topicId, infoId, actor);
entry.mActorName = actor.getClass().getName(actor);
topic.addEntry (entry);
}
void Journal::removeLastAddedTopicResponse(const std::string &topicId, const std::string &actorName)
{
Topic& topic = getTopic (topicId);
topic.removeLastAddedResponse(actorName);
if (topic.begin() == topic.end())
mTopics.erase(mTopics.find(topicId)); // All responses removed -> remove topic
}
int Journal::getJournalIndex (const std::string& id) const
{
TQuestContainer::const_iterator iter = mQuests.find (id);

View file

@ -38,7 +38,12 @@ namespace MWDialogue
virtual int getJournalIndex (const std::string& id) const;
///< Get the journal index.
virtual void addTopic (const std::string& topicId, const std::string& infoId, const std::string& actorName);
virtual void addTopic (const std::string& topicId, const std::string& infoId, const MWWorld::Ptr& actor);
/// \note topicId must be lowercase
virtual void removeLastAddedTopicResponse (const std::string& topicId, const std::string& actorName);
///< Removes the last topic response added for the given topicId and actor name.
/// \note topicId must be lowercase
virtual TEntryIter begin() const;
///< Iterator pointing to the begin of the main journal.

View file

@ -59,8 +59,16 @@ namespace MWDialogue
return mEntries.end();
}
JournalEntry Topic::getEntry (const std::string& infoId) const
void Topic::removeLastAddedResponse (const std::string& actorName)
{
return JournalEntry (mTopic, infoId);
for (std::vector<MWDialogue::Entry>::reverse_iterator it = mEntries.rbegin();
it != mEntries.rend(); ++it)
{
if (it->mActorName == actorName)
{
mEntries.erase( (++it).base() ); // erase doesn't take a reverse_iterator
return;
}
}
}
}

View file

@ -48,13 +48,13 @@ namespace MWDialogue
virtual std::string getName() const;
void removeLastAddedResponse (const std::string& actorName);
TEntryIter begin() const;
///< Iterator pointing to the begin of the journal for this topic.
TEntryIter end() const;
///< Iterator pointing past the end of the journal for this topic.
JournalEntry getEntry (const std::string& infoId) const;
};
}

View file

@ -360,10 +360,16 @@ struct TypesetBookImpl::Typesetter : BookTypesetter
int spaceLeft = mPageHeight - (curPageStop - curPageStart);
int sectionHeight = i->mRect.height ();
if (sectionHeight <= mPageHeight)
// This is NOT equal to i->mRect.height(), which doesn't account for section breaks.
int spaceRequired = (i->mRect.bottom - curPageStop);
if (curPageStart == curPageStop) // If this is a new page, the section break is not needed
spaceRequired = i->mRect.height();
if (spaceRequired <= mPageHeight)
{
if (sectionHeight > spaceLeft)
if (spaceRequired > spaceLeft)
{
// The section won't completely fit on the current page. Finish the current page and start a new one.
assert (curPageStart != curPageStop);
mBook->mPages.push_back (Page (curPageStart, curPageStop));

View file

@ -30,9 +30,9 @@ namespace MWGui
void ConfirmationDialog::exit()
{
eventCancelClicked();
setVisible(false);
eventCancelClicked();
}
void ConfirmationDialog::onCancelButtonClicked(MyGUI::Widget* _sender)
@ -42,8 +42,8 @@ namespace MWGui
void ConfirmationDialog::onOkButtonClicked(MyGUI::Widget* _sender)
{
eventOkClicked();
setVisible(false);
eventOkClicked();
}
}

View file

@ -435,4 +435,10 @@ namespace MWGui
{
setSelectedObject(MWWorld::Ptr());
}
void Console::resetReference()
{
ReferenceInterface::resetReference();
setSelectedObject(MWWorld::Ptr());
}
}

View file

@ -66,6 +66,8 @@ namespace MWGui
void executeFile (const std::string& path);
virtual void resetReference ();
protected:
virtual void onReferenceUnavailable();

View file

@ -38,6 +38,32 @@ namespace MWGui
mIsOnDragAndDrop = true;
mDragAndDropWidget->setVisible(true);
// If picking up an item that isn't from the player's inventory, the item gets added to player inventory backend
// immediately, even though it's still floating beneath the mouse cursor. A bit counterintuitive,
// but this is how it works in vanilla, and not doing so would break quests (BM_beasts for instance).
ItemModel* playerModel = MWBase::Environment::get().getWindowManager()->getInventoryWindow()->getModel();
if (mSourceModel != playerModel)
{
MWWorld::Ptr item = mSourceModel->moveItem(mItem, mDraggedCount, playerModel);
playerModel->update();
ItemModel::ModelIndex newIndex = -1;
for (unsigned int i=0; i<playerModel->getItemCount(); ++i)
{
if (playerModel->getItem(i).mBase == item)
{
newIndex = i;
break;
}
}
mItem = playerModel->getItem(newIndex);
mSourceModel = playerModel;
SortFilterItemModel* playerFilterModel = MWBase::Environment::get().getWindowManager()->getInventoryWindow()->getSortFilterModel();
mSourceSortModel = playerFilterModel;
}
std::string sound = mItem.mBase.getClass().getUpSoundId(mItem.mBase);
MWBase::Environment::get().getSoundManager()->playSound (sound, 1.0, 1.0);

View file

@ -366,10 +366,11 @@ namespace MWGui
}
}
void DialogueWindow::startDialogue(MWWorld::Ptr actor, std::string npcName)
void DialogueWindow::startDialogue(MWWorld::Ptr actor, std::string npcName, bool resetHistory)
{
mGoodbye = false;
mEnabled = true;
bool sameActor = (mPtr == actor);
mPtr = actor;
mTopicsList->setEnabled(true);
setTitle(npcName);
@ -378,9 +379,12 @@ namespace MWGui
mTopicsList->clear();
for (std::vector<DialogueText*>::iterator it = mHistoryContents.begin(); it != mHistoryContents.end(); ++it)
delete (*it);
mHistoryContents.clear();
if (resetHistory || !sameActor)
{
for (std::vector<DialogueText*>::iterator it = mHistoryContents.begin(); it != mHistoryContents.end(); ++it)
delete (*it);
mHistoryContents.clear();
}
for (std::vector<Link*>::iterator it = mLinks.begin(); it != mLinks.end(); ++it)
delete (*it);
@ -582,13 +586,32 @@ namespace MWGui
//Clear the list of topics
mTopicsList->clear();
if (mPtr.getTypeName() == typeid(ESM::NPC).name())
bool dispositionVisible = false;
if (mPtr.getClass().isNpc())
{
dispositionVisible = true;
mDispositionBar->setProgressRange(100);
mDispositionBar->setProgressPosition(MWBase::Environment::get().getMechanicsManager()->getDerivedDisposition(mPtr));
mDispositionText->eraseText(0, mDispositionText->getTextLength());
mDispositionText->addText("#B29154"+boost::lexical_cast<std::string>(MWBase::Environment::get().getMechanicsManager()->getDerivedDisposition(mPtr))+std::string("/100")+"#B29154");
}
bool dispositionWasVisible = mDispositionBar->getVisible();
if (dispositionVisible && !dispositionWasVisible)
{
mDispositionBar->setVisible(true);
float offset = mDispositionBar->getHeight()+5;
mTopicsList->setCoord(mTopicsList->getCoord() + MyGUI::IntCoord(0,offset,0,-offset));
mTopicsList->adjustSize();
}
else if (!dispositionVisible && dispositionWasVisible)
{
mDispositionBar->setVisible(false);
float offset = mDispositionBar->getHeight()+5;
mTopicsList->setCoord(mTopicsList->getCoord() - MyGUI::IntCoord(0,offset,0,-offset));
mTopicsList->adjustSize();
}
}
void DialogueWindow::goodbye()

View file

@ -111,7 +111,7 @@ namespace MWGui
void notifyLinkClicked (TypesetBook::InteractiveId link);
void startDialogue(MWWorld::Ptr actor, std::string npcName);
void startDialogue(MWWorld::Ptr actor, std::string npcName, bool resetHistory);
void setKeywords(std::list<std::string> keyWord);
void addResponse (const std::string& text, const std::string& title="");
@ -170,7 +170,7 @@ namespace MWGui
BookPage* mHistory;
Widgets::MWList* mTopicsList;
MyGUI::ScrollBar* mScrollBar;
MyGUI::ProgressPtr mDispositionBar;
MyGUI::Progress* mDispositionBar;
MyGUI::EditBox* mDispositionText;
PersuasionDialog mPersuasionDialog;

View file

@ -258,12 +258,16 @@ namespace MWGui
code->addAttribute("bearing", MyGUI::utility::toString(data[i].kerning) + " "
+ MyGUI::utility::toString((fontSize-data[i].ascent)));
// More hacks! The french game uses U+2019, which is nowhere to be found in
// the CP437 encoding of the font. Fall back to 39 (regular apostrophe)
if (i == 39 && mEncoding == ToUTF8::CP437)
// More hacks! The french game uses several win1252 characters that are not included
// in the cp437 encoding of the font. Fall back to similar available characters.
// Same for U+2013
std::map<int, int> additional;
additional[39] = 0x2019; // apostrophe
additional[45] = 0x2013; // dash
if (additional.find(i) != additional.end() && mEncoding == ToUTF8::CP437)
{
MyGUI::xml::ElementPtr code = codes->createChild("Code");
code->addAttribute("index", 0x2019);
code->addAttribute("index", additional[i]);
code->addAttribute("coord", MyGUI::utility::toString(x1) + " "
+ MyGUI::utility::toString(y1) + " "
+ MyGUI::utility::toString(w) + " "

View file

@ -384,6 +384,8 @@ namespace MWGui
void HUD::onFrame(float dt)
{
LocalMapBase::onFrame(dt);
mCellNameTimer -= dt;
mWeaponSpellTimer -= dt;
if (mCellNameTimer < 0)

View file

@ -132,6 +132,11 @@ namespace MWGui
adjustPanes();
}
SortFilterItemModel* InventoryWindow::getSortFilterModel()
{
return mSortModel;
}
TradeItemModel* InventoryWindow::getTradeModel()
{
return mTradeModel;

View file

@ -37,6 +37,7 @@ namespace MWGui
mPreview->rebuild();
}
SortFilterItemModel* getSortFilterModel();
TradeItemModel* getTradeModel();
ItemModel* getModel();

View file

@ -33,12 +33,26 @@ namespace MWGui
void ItemWidget::setIcon(const std::string &icon)
{
// HACK HACK HACK: Don't setImageTexture if it hasn't changed.
// There is a leak in MyGUI for each setImageTexture on the same widget.
// http://www.ogre3d.org/addonforums/viewtopic.php?f=17&t=30251
if (mCurrentItemTexture == icon)
return;
mCurrentItemTexture = icon;
if (mItem)
mItem->setImageTexture(icon);
}
void ItemWidget::setFrame(const std::string &frame, const MyGUI::IntCoord &coord)
{
// HACK HACK HACK: Don't setImageTexture if it hasn't changed.
// There is a leak in MyGUI for each setImageTexture on the same widget.
// http://www.ogre3d.org/addonforums/viewtopic.php?f=17&t=30251
if (mCurrentFrameTexture == frame)
return;
mCurrentFrameTexture = frame;
if (mFrame)
{
mFrame->setImageTexture(frame);
@ -69,8 +83,21 @@ namespace MWGui
if (ptr.isEmpty())
{
if (mFrame)
mFrame->setImageTexture("");
mItem->setImageTexture("");
{
// HACK HACK HACK: Don't setImageTexture if it hasn't changed.
// There is a leak in MyGUI for each setImageTexture on the same widget.
// http://www.ogre3d.org/addonforums/viewtopic.php?f=17&t=30251
if (!mCurrentFrameTexture.empty())
{
mFrame->setImageTexture("");
mCurrentFrameTexture = "";
}
}
if (!mCurrentItemTexture.empty())
{
mCurrentItemTexture = "";
mItem->setImageTexture("");
}
return;
}

View file

@ -42,6 +42,9 @@ namespace MWGui
MyGUI::ImageBox* mItem;
MyGUI::ImageBox* mFrame;
std::string mCurrentItemTexture;
std::string mCurrentFrameTexture;
};
}

View file

@ -104,9 +104,10 @@ namespace MWGui
int attribute = mSpentAttributes[i];
int xdiff = mAttributeMultipliers[attribute]->getCaption() == "" ? 0 : 30;
int xdiff = mAttributeMultipliers[attribute]->getCaption() == "" ? 0 : 20;
MyGUI::IntPoint pos = mAttributes[attribute]->getAbsolutePosition() - mMainWidget->getAbsolutePosition() - MyGUI::IntPoint(24+xdiff,-4);
MyGUI::IntPoint pos = mAttributes[attribute]->getAbsolutePosition() - mMainWidget->getAbsolutePosition() - MyGUI::IntPoint(22+xdiff,0);
pos.top += (mAttributes[attribute]->getHeight() - image->getHeight())/2;
image->setPosition(pos);
}

View file

@ -101,7 +101,7 @@ namespace MWGui
size_t viewRange = mScrollView->getCanvasSize().height;
if(viewPosition > viewRange)
viewPosition = viewRange;
mScrollView->setViewOffset(MyGUI::IntPoint(0, -viewPosition));
mScrollView->setViewOffset(MyGUI::IntPoint(0, viewPosition * -1));
}
void MWList::setPropertyOverride(const std::string &_key, const std::string &_value)

View file

@ -136,7 +136,7 @@ namespace MWGui
Ogre::StringVector groups = Ogre::ResourceGroupManager::getSingleton().getResourceGroups ();
for (Ogre::StringVector::iterator it = groups.begin(); it != groups.end(); ++it)
{
Ogre::StringVectorPtr resourcesInThisGroup = Ogre::ResourceGroupManager::getSingleton ().findResourceNames (*it, "Splash_*.tga");
Ogre::StringVectorPtr resourcesInThisGroup = Ogre::ResourceGroupManager::getSingleton ().findResourceNames (*it, "Splash/*.tga");
mResources.insert(mResources.end(), resourcesInThisGroup->begin(), resourcesInThisGroup->end());
}
}

View file

@ -68,10 +68,10 @@ namespace MWGui
{
if (visible)
updateMenu();
else
showBackground(
MWBase::Environment::get().getWindowManager()->containsMode(MWGui::GM_MainMenu) &&
MWBase::Environment::get().getStateManager()->getState() == MWBase::StateManager::State_NoGame);
showBackground(
MWBase::Environment::get().getWindowManager()->containsMode(MWGui::GM_MainMenu) &&
MWBase::Environment::get().getStateManager()->getState() == MWBase::StateManager::State_NoGame);
OEngine::GUI::Layout::setVisible (visible);
}
@ -167,7 +167,7 @@ namespace MWGui
mVideo = mVideoBackground->createWidget<VideoWidget>("ImageBox", 0,0,1,1,
MyGUI::Align::Stretch, "Menu");
mVideo->playVideo("video\\menu_background.bik", false);
mVideo->playVideo("video\\menu_background.bik");
}
MyGUI::IntSize viewSize = MyGUI::RenderManager::getInstance().getViewSize();
@ -204,7 +204,7 @@ namespace MWGui
if (!mVideo->update())
{
// If finished playing, start again
mVideo->playVideo("video\\menu_background.bik", 0);
mVideo->playVideo("video\\menu_background.bik");
}
}
}
@ -220,7 +220,6 @@ namespace MWGui
MWBase::StateManager::State state = MWBase::Environment::get().getStateManager()->getState();
showBackground(state == MWBase::StateManager::State_NoGame);
mVersionText->setVisible(state == MWBase::StateManager::State_NoGame);
std::vector<std::string> buttons;

View file

@ -36,6 +36,7 @@ namespace MWGui
, mLastDirectionX(0.0f)
, mLastDirectionY(0.0f)
, mCompass(NULL)
, mMarkerUpdateTimer(0.0f)
{
}
@ -345,6 +346,18 @@ namespace MWGui
markerWidget->setUserString("IsMarker", "true");
markerWidget->setUserData(markerPos);
markerWidget->setColour(markerColour);
mMarkerWidgets.push_back(markerWidget);
}
}
void LocalMapBase::onFrame(float dt)
{
mMarkerUpdateTimer += dt;
if (mMarkerUpdateTimer >= 0.25)
{
mMarkerUpdateTimer = 0;
updateMarkers();
}
}
@ -418,6 +431,9 @@ namespace MWGui
{
mGlobalMapRender = new MWRender::GlobalMap("");
mGlobalMapRender->render(loadingListener);
mGlobalMap->setCanvasSize (mGlobalMapRender->getWidth(), mGlobalMapRender->getHeight());
mGlobalMapImage->setSize(mGlobalMapRender->getWidth(), mGlobalMapRender->getHeight());
mGlobalMapImage->setImageTexture("GlobalMap.png");
mGlobalMapOverlay->setImageTexture("GlobalMapOverlay");
}
@ -471,6 +487,8 @@ namespace MWGui
void MapWindow::onFrame(float dt)
{
LocalMapBase::onFrame(dt);
for (std::vector<CellId>::iterator it = mQueuedToExplore.begin(); it != mQueuedToExplore.end(); ++it)
{
mGlobalMapRender->exploreCell(it->first, it->second);
@ -497,7 +515,6 @@ namespace MWGui
else
mGlobalMap->setViewOffset( mGlobalMap->getViewOffset() + diff );
mLastDragPos = MyGUI::IntPoint(_left, _top);
}
@ -521,9 +538,6 @@ namespace MWGui
void MapWindow::open()
{
mGlobalMap->setCanvasSize (mGlobalMapRender->getWidth(), mGlobalMapRender->getHeight());
mGlobalMapImage->setSize(mGlobalMapRender->getWidth(), mGlobalMapRender->getHeight());
// force markers to foreground
for (unsigned int i=0; i<mGlobalMapOverlay->getChildCount (); ++i)
{

View file

@ -35,6 +35,8 @@ namespace MWGui
void setPlayerDir(const float x, const float y);
void setPlayerPos(const float x, const float y);
void onFrame(float dt);
bool toggleFogOfWar();
struct MarkerPosition
@ -73,12 +75,14 @@ namespace MWGui
virtual void notifyMapChanged() {}
// Update markers (Detect X effects, Mark/Recall effects)
// Note, door markers handled in setActiveCell
// Note, door markers are handled in setActiveCell
void updateMarkers();
void addDetectionMarkers(int type);
OEngine::GUI::Layout* mLayout;
float mMarkerUpdateTimer;
bool mMapDragAndDrop;
float mLastPositionX;

View file

@ -25,6 +25,23 @@ namespace MWGui
}
}
void MessageBoxManager::clear()
{
delete mInterMessageBoxe;
mInterMessageBoxe = NULL;
std::vector<MessageBox*>::iterator it(mMessageBoxes.begin());
for (; it != mMessageBoxes.end(); ++it)
{
if (*it == mStaticMessageBox)
mStaticMessageBox = NULL;
delete *it;
}
mMessageBoxes.clear();
mLastButtonPressed = -1;
}
void MessageBoxManager::onFrame (float frameDuration)
{
std::vector<MessageBox*>::iterator it;

View file

@ -30,6 +30,9 @@ namespace MWGui
bool createInteractiveMessageBox (const std::string& message, const std::vector<std::string>& buttons);
bool isInteractiveMessageBox ();
/// Remove all message boxes
void clear();
bool removeMessageBox (MessageBox *msgbox);
void setMessageBoxSpeed (int speed);

View file

@ -24,6 +24,7 @@
#include "spellwindow.hpp"
#include "itemwidget.hpp"
#include "sortfilteritemmodel.hpp"
namespace MWGui
@ -134,6 +135,7 @@ namespace MWGui
}
mItemSelectionDialog->setVisible(true);
mItemSelectionDialog->openContainer(MWBase::Environment::get().getWorld()->getPlayerPtr());
mItemSelectionDialog->setFilter(SortFilterItemModel::Filter_OnlyUsableItems);
mAssignDialog->setVisible (false);
}
@ -162,7 +164,7 @@ namespace MWGui
void QuickKeysMenu::onAssignItem(MWWorld::Ptr item)
{
assert (mSelectedIndex > 0);
assert (mSelectedIndex >= 0);
ItemWidget* button = mQuickKeyButtons[mSelectedIndex];
while (button->getChildCount()) // Destroy number label
MyGUI::Gui::getInstance().destroyWidget(button->getChildAt(0));
@ -184,7 +186,7 @@ namespace MWGui
void QuickKeysMenu::onAssignMagicItem (MWWorld::Ptr item)
{
assert (mSelectedIndex > 0);
assert (mSelectedIndex >= 0);
ItemWidget* button = mQuickKeyButtons[mSelectedIndex];
while (button->getChildCount()) // Destroy number label
MyGUI::Gui::getInstance().destroyWidget(button->getChildAt(0));
@ -203,7 +205,7 @@ namespace MWGui
void QuickKeysMenu::onAssignMagic (const std::string& spellId)
{
assert (mSelectedIndex > 0);
assert (mSelectedIndex >= 0);
ItemWidget* button = mQuickKeyButtons[mSelectedIndex];
while (button->getChildCount()) // Destroy number label
MyGUI::Gui::getInstance().destroyWidget(button->getChildAt(0));
@ -245,7 +247,7 @@ namespace MWGui
void QuickKeysMenu::activateQuickKey(int index)
{
assert (index-1 > 0);
assert (index-1 >= 0);
ItemWidget* button = mQuickKeyButtons[index-1];
QuickKeyType type = mAssigned[index-1];

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