mirror of
https://github.com/OpenMW/openmw.git
synced 2025-02-05 10:45:35 +00:00
Merge remote-tracking branch 'upstream/master' into wizard
This commit is contained in:
commit
8fe837ae6e
168 changed files with 3592 additions and 1538 deletions
|
@ -7,7 +7,6 @@ branches:
|
|||
- /openmw-.*$/
|
||||
before_install:
|
||||
- pwd
|
||||
- git fetch --tags
|
||||
- echo "yes" | sudo add-apt-repository "deb http://archive.ubuntu.com/ubuntu `lsb_release -sc` main universe restricted multiverse"
|
||||
- echo "yes" | sudo apt-add-repository ppa:openmw/openmw
|
||||
- sudo apt-get update -qq
|
||||
|
|
|
@ -6,34 +6,63 @@ if (APPLE)
|
|||
set(APP_BUNDLE_DIR "${OpenMW_BINARY_DIR}/${APP_BUNDLE_NAME}")
|
||||
endif (APPLE)
|
||||
|
||||
# Macros
|
||||
|
||||
set(CMAKE_MODULE_PATH ${CMAKE_SOURCE_DIR}/cmake/)
|
||||
|
||||
include(OpenMWMacros)
|
||||
|
||||
# Version
|
||||
message(STATUS "Configuring OpenMW...")
|
||||
|
||||
include(GetGitRevisionDescription)
|
||||
set(OPENMW_VERSION_MAJOR 0)
|
||||
set(OPENMW_VERSION_MINOR 29)
|
||||
set(OPENMW_VERSION_RELEASE 0)
|
||||
|
||||
get_git_tag_revision(TAGHASH --tags --max-count=1 "HEAD...")
|
||||
get_git_head_revision(REFSPEC COMMITHASH)
|
||||
git_describe(VERSION --tags ${TAGHASH})
|
||||
set(OPENMW_VERSION_COMMITHASH "")
|
||||
set(OPENMW_VERSION_TAGHASH "")
|
||||
|
||||
string(REGEX MATCH "^openmw-[^0-9]*[0-9]+\\.[0-9]+\\.[0-9]+.*" MATCH "${VERSION}")
|
||||
if (MATCH)
|
||||
string(REGEX REPLACE "^openmw-([0-9]+)\\..*" "\\1" OPENMW_VERSION_MAJOR "${VERSION}")
|
||||
string(REGEX REPLACE "^openmw-[0-9]+\\.([0-9]+).*" "\\1" OPENMW_VERSION_MINOR "${VERSION}")
|
||||
string(REGEX REPLACE "^openmw-[0-9]+\\.[0-9]+\\.([0-9]+).*" "\\1" OPENMW_VERSION_RELEASE "${VERSION}")
|
||||
set(OPENMW_VERSION "${OPENMW_VERSION_MAJOR}.${OPENMW_VERSION_MINOR}.${OPENMW_VERSION_RELEASE}")
|
||||
|
||||
set(OPENMW_VERSION "${OPENMW_VERSION_MAJOR}.${OPENMW_VERSION_MINOR}.${OPENMW_VERSION_RELEASE}")
|
||||
set(OPENMW_VERSION_COMMITHASH "${COMMITHASH}")
|
||||
set(OPENMW_VERSION_TAGHASH "${TAGHASH}")
|
||||
if(EXISTS ${PROJECT_SOURCE_DIR}/.git)
|
||||
if(NOT EXISTS ${PROJECT_SOURCE_DIR}/.git/shallow)
|
||||
find_package(Git)
|
||||
|
||||
message(STATUS "Configuring OpenMW ${OPENMW_VERSION}...")
|
||||
else (MATCH)
|
||||
message(FATAL_ERROR "Failed to get valid version information from Git")
|
||||
endif (MATCH)
|
||||
if(GIT_FOUND)
|
||||
include(GetGitRevisionDescription)
|
||||
get_git_tag_revision(TAGHASH --tags --max-count=1)
|
||||
get_git_head_revision(REFSPEC COMMITHASH)
|
||||
git_describe(VERSION --tags ${TAGHASH})
|
||||
|
||||
string(REGEX MATCH "^openmw-[^0-9]*[0-9]+\\.[0-9]+\\.[0-9]+.*" MATCH "${VERSION}")
|
||||
if(MATCH)
|
||||
string(REGEX REPLACE "^openmw-([0-9]+)\\..*" "\\1" GIT_VERSION_MAJOR "${VERSION}")
|
||||
string(REGEX REPLACE "^openmw-[0-9]+\\.([0-9]+).*" "\\1" GIT_VERSION_MINOR "${VERSION}")
|
||||
string(REGEX REPLACE "^openmw-[0-9]+\\.[0-9]+\\.([0-9]+).*" "\\1" GIT_VERSION_RELEASE "${VERSION}")
|
||||
|
||||
set(GIT_VERSION "${GIT_VERSION_MAJOR}.${GIT_VERSION_MINOR}.${GIT_VERSION_RELEASE}")
|
||||
|
||||
if(NOT ${OPENMW_VERSION} STREQUAL ${GIT_VERSION})
|
||||
message(FATAL_ERROR "Silly Zini forgot to update the version again...")
|
||||
else(NOT ${OPENMW_VERSION} STREQUAL ${GIT_VERSION})
|
||||
set(OPENMW_VERSION_MAJOR ${GIT_VERSION_MAJOR})
|
||||
set(OPENMW_VERSION_MINOR ${GIT_VERSION_MINOR})
|
||||
set(OPENMW_VERSION_RELEASE ${GIT_VERSION_RELEASE})
|
||||
|
||||
set(OPENMW_VERSION_COMMITHASH "${COMMITHASH}")
|
||||
set(OPENMW_VERSION_TAGHASH "${TAGHASH}")
|
||||
endif(NOT ${OPENMW_VERSION} STREQUAL ${GIT_VERSION})
|
||||
|
||||
message(STATUS "OpenMW version ${OPENMW_VERSION}")
|
||||
else(MATCH)
|
||||
message(WARNING "Failed to get valid version information from Git")
|
||||
endif(MATCH)
|
||||
else(GIT_FOUND)
|
||||
message(WARNING "Git executable not found")
|
||||
endif(GIT_FOUND)
|
||||
else(NOT EXISTS ${PROJECT_SOURCE_DIR}/.git/shallow)
|
||||
message(STATUS "Shallow Git clone detected, not attempting to retrieve version info")
|
||||
endif(NOT EXISTS ${PROJECT_SOURCE_DIR}/.git/shallow)
|
||||
endif(EXISTS ${PROJECT_SOURCE_DIR}/.git)
|
||||
|
||||
# Macros
|
||||
include(OpenMWMacros)
|
||||
|
||||
# doxygen main page
|
||||
|
||||
|
@ -210,6 +239,14 @@ if (UNIX AND NOT APPLE)
|
|||
find_package (Threads)
|
||||
endif()
|
||||
|
||||
# Look for stdint.h
|
||||
include(CheckIncludeFile)
|
||||
check_include_file(stdint.h HAVE_STDINT_H)
|
||||
if(NOT HAVE_STDINT_H)
|
||||
unset(HAVE_STDINT_H CACHE)
|
||||
message(FATAL_ERROR "stdint.h was not found" )
|
||||
endif()
|
||||
|
||||
include (CheckIncludeFileCXX)
|
||||
check_include_file_cxx(unordered_map HAVE_UNORDERED_MAP)
|
||||
if (HAVE_UNORDERED_MAP)
|
||||
|
|
|
@ -79,17 +79,20 @@ Launcher::MainDialog::MainDialog(QWidget *parent)
|
|||
QString revision(OPENMW_VERSION_COMMITHASH);
|
||||
QString tag(OPENMW_VERSION_TAGHASH);
|
||||
|
||||
if (revision == tag) {
|
||||
versionLabel->setText(tr("OpenMW %0 release").arg(OPENMW_VERSION));
|
||||
} else {
|
||||
versionLabel->setText(tr("OpenMW development (%0)").arg(revision.left(10)));
|
||||
}
|
||||
if (!revision.isEmpty() && !tag.isEmpty())
|
||||
{
|
||||
if (revision == tag) {
|
||||
versionLabel->setText(tr("OpenMW %0 release").arg(OPENMW_VERSION));
|
||||
} else {
|
||||
versionLabel->setText(tr("OpenMW development (%0)").arg(revision.left(10)));
|
||||
}
|
||||
|
||||
// Add the compile date and time
|
||||
versionLabel->setToolTip(tr("Compiled on %0 %1").arg(QLocale(QLocale::C).toDate(QString(__DATE__).simplified(),
|
||||
QLatin1String("MMM d yyyy")).toString(Qt::SystemLocaleLongDate),
|
||||
QLocale(QLocale::C).toTime(QString(__TIME__).simplified(),
|
||||
QLatin1String("hh:mm:ss")).toString(Qt::SystemLocaleShortDate)));
|
||||
// Add the compile date and time
|
||||
versionLabel->setToolTip(tr("Compiled on %0 %1").arg(QLocale(QLocale::C).toDate(QString(__DATE__).simplified(),
|
||||
QLatin1String("MMM d yyyy")).toString(Qt::SystemLocaleLongDate),
|
||||
QLocale(QLocale::C).toTime(QString(__TIME__).simplified(),
|
||||
QLatin1String("hh:mm:ss")).toString(Qt::SystemLocaleShortDate)));
|
||||
}
|
||||
|
||||
createIcons();
|
||||
}
|
||||
|
|
|
@ -64,8 +64,12 @@ opencs_units (view/world
|
|||
)
|
||||
|
||||
opencs_units (view/render
|
||||
scenewidget
|
||||
)
|
||||
scenewidget worldspacewidget pagedworldspacewidget unpagedworldspacewidget
|
||||
)
|
||||
|
||||
opencs_units_noqt (view/render
|
||||
navigation navigation1st navigationfree navigationorbit
|
||||
)
|
||||
|
||||
opencs_units_noqt (view/world
|
||||
dialoguesubview subviews
|
||||
|
|
|
@ -9,15 +9,22 @@
|
|||
#include <OgreRoot.h>
|
||||
#include <OgreRenderWindow.h>
|
||||
|
||||
#include <components/ogreinit/ogreinit.hpp>
|
||||
|
||||
#include "model/doc/document.hpp"
|
||||
#include "model/world/data.hpp"
|
||||
|
||||
CS::Editor::Editor()
|
||||
: mDocumentManager (mCfgMgr), mViewManager (mDocumentManager)
|
||||
CS::Editor::Editor (OgreInit::OgreInit& ogreInit)
|
||||
: mDocumentManager (mCfgMgr), mViewManager (mDocumentManager),
|
||||
mIpcServerName ("org.openmw.OpenCS")
|
||||
{
|
||||
mIpcServerName = "org.openmw.OpenCS";
|
||||
Files::PathContainer dataDirs = readConfig();
|
||||
|
||||
setupDataFiles();
|
||||
setupDataFiles (dataDirs);
|
||||
|
||||
CSMSettings::UserSettings::instance().loadSettings ("opencs.cfg");
|
||||
|
||||
ogreInit.init ((mCfgMgr.getUserConfigPath() / "opencsOgre.log").string());
|
||||
|
||||
mNewGame.setLocalData (mLocal);
|
||||
mFileDialog.setLocalData (mLocal);
|
||||
|
@ -42,7 +49,16 @@ CS::Editor::Editor()
|
|||
this, SLOT (createNewGame (const boost::filesystem::path&)));
|
||||
}
|
||||
|
||||
void CS::Editor::setupDataFiles()
|
||||
void CS::Editor::setupDataFiles (const Files::PathContainer& dataDirs)
|
||||
{
|
||||
for (Files::PathContainer::const_iterator iter = dataDirs.begin(); iter != dataDirs.end(); ++iter)
|
||||
{
|
||||
QString path = QString::fromStdString(iter->string());
|
||||
mFileDialog.addFiles(path);
|
||||
}
|
||||
}
|
||||
|
||||
Files::PathContainer CS::Editor::readConfig()
|
||||
{
|
||||
boost::program_options::variables_map variables;
|
||||
boost::program_options::options_description desc("Syntax: opencs <options>\nAllowed options");
|
||||
|
@ -58,6 +74,8 @@ void CS::Editor::setupDataFiles()
|
|||
|
||||
mCfgMgr.readConfiguration(variables, desc);
|
||||
|
||||
mDocumentManager.setResourceDir (variables["resources"].as<std::string>());
|
||||
|
||||
Files::PathContainer dataDirs, dataLocal;
|
||||
if (!variables["data"].empty()) {
|
||||
dataDirs = Files::PathContainer(variables["data"].as<Files::PathContainer>());
|
||||
|
@ -83,23 +101,11 @@ void CS::Editor::setupDataFiles()
|
|||
messageBox.exec();
|
||||
|
||||
QApplication::exit (1);
|
||||
return;
|
||||
}
|
||||
|
||||
dataDirs.insert (dataDirs.end(), dataLocal.begin(), dataLocal.end());
|
||||
|
||||
mDocumentManager.setResourceDir (variables["resources"].as<std::string>());
|
||||
|
||||
for (Files::PathContainer::const_iterator iter = dataDirs.begin(); iter != dataDirs.end(); ++iter)
|
||||
{
|
||||
|
||||
QString path = QString::fromStdString(iter->string());
|
||||
mFileDialog.addFiles(path);
|
||||
}
|
||||
|
||||
//load the settings into the userSettings instance.
|
||||
const QString settingFileName = "opencs.cfg";
|
||||
CSMSettings::UserSettings::instance().loadSettings(settingFileName);
|
||||
return dataDirs;
|
||||
}
|
||||
|
||||
void CS::Editor::createGame()
|
||||
|
@ -210,8 +216,6 @@ int CS::Editor::run()
|
|||
if (mLocal.empty())
|
||||
return 1;
|
||||
|
||||
// temporarily disable OGRE-integration (need to fix path problem first)
|
||||
#if 0
|
||||
// TODO: setting
|
||||
Ogre::Root::getSingleton().setRenderSystem(Ogre::Root::getSingleton().getRenderSystemByName("OpenGL Rendering Subsystem"));
|
||||
|
||||
|
@ -228,7 +232,6 @@ int CS::Editor::run()
|
|||
#endif
|
||||
Ogre::RenderWindow* hiddenWindow = Ogre::Root::getSingleton().createRenderWindow("InactiveHidden", 1, 1, false, ¶ms);
|
||||
hiddenWindow->setActive(false);
|
||||
#endif
|
||||
|
||||
mStartup.show();
|
||||
|
||||
|
|
|
@ -10,6 +10,8 @@
|
|||
#include <components/files/configurationmanager.hpp>
|
||||
#endif
|
||||
|
||||
#include <components/files/multidircollection.hpp>
|
||||
|
||||
#include "model/settings/usersettings.hpp"
|
||||
#include "model/doc/documentmanager.hpp"
|
||||
|
||||
|
@ -20,6 +22,11 @@
|
|||
|
||||
#include "view/settings/usersettingsdialog.hpp"
|
||||
|
||||
namespace OgreInit
|
||||
{
|
||||
class OgreInit;
|
||||
}
|
||||
|
||||
namespace CS
|
||||
{
|
||||
class Editor : public QObject
|
||||
|
@ -37,7 +44,10 @@ namespace CS
|
|||
|
||||
boost::filesystem::path mLocal;
|
||||
|
||||
void setupDataFiles();
|
||||
void setupDataFiles (const Files::PathContainer& dataDirs);
|
||||
|
||||
Files::PathContainer readConfig();
|
||||
///< \return data paths
|
||||
|
||||
// not implemented
|
||||
Editor (const Editor&);
|
||||
|
@ -45,7 +55,7 @@ namespace CS
|
|||
|
||||
public:
|
||||
|
||||
Editor();
|
||||
Editor (OgreInit::OgreInit& ogreInit);
|
||||
|
||||
bool makeIPCServer();
|
||||
void connectToIPCServer();
|
||||
|
|
|
@ -40,15 +40,9 @@ int main(int argc, char *argv[])
|
|||
{
|
||||
Q_INIT_RESOURCE (resources);
|
||||
|
||||
// TODO: Ogre startup shouldn't be here, but it currently has to:
|
||||
// SceneWidget destructor will delete the created render window, which would be called _after_ Root has shut down :(
|
||||
|
||||
Application mApplication (argc, argv);
|
||||
// temporarily disable OGRE-integration (need to fix path problem first)
|
||||
#if 0
|
||||
OgreInit::OgreInit ogreInit;
|
||||
ogreInit.init("./opencsOgre.log"); // TODO log path?
|
||||
#endif
|
||||
|
||||
Application application (argc, argv);
|
||||
|
||||
#ifdef Q_OS_MAC
|
||||
QDir dir(QCoreApplication::applicationDirPath());
|
||||
|
@ -66,12 +60,12 @@ int main(int argc, char *argv[])
|
|||
|
||||
QStringList libraryPaths;
|
||||
libraryPaths << pluginsPath.path() << QCoreApplication::applicationDirPath();
|
||||
mApplication.setLibraryPaths(libraryPaths);
|
||||
application.setLibraryPaths(libraryPaths);
|
||||
#endif
|
||||
|
||||
mApplication.setWindowIcon (QIcon (":./opencs.png"));
|
||||
application.setWindowIcon (QIcon (":./opencs.png"));
|
||||
|
||||
CS::Editor editor;
|
||||
CS::Editor editor (ogreInit);
|
||||
|
||||
if(!editor.makeIPCServer())
|
||||
{
|
||||
|
|
|
@ -98,7 +98,7 @@ namespace CSMWorld
|
|||
UniversalId::Type type = UniversalId::Type_None);
|
||||
///< \param type Will be ignored, unless the collection supports multiple record types
|
||||
|
||||
virtual void cloneRecord(const std::string& origin,
|
||||
virtual void cloneRecord(const std::string& origin,
|
||||
const std::string& destination,
|
||||
const UniversalId::Type type);
|
||||
|
||||
|
@ -198,7 +198,7 @@ namespace CSMWorld
|
|||
}
|
||||
|
||||
template<typename ESXRecordT, typename IdAccessorT>
|
||||
void Collection<ESXRecordT, IdAccessorT>::cloneRecord(const std::string& origin,
|
||||
void Collection<ESXRecordT, IdAccessorT>::cloneRecord(const std::string& origin,
|
||||
const std::string& destination,
|
||||
const UniversalId::Type type)
|
||||
{
|
||||
|
|
|
@ -74,7 +74,7 @@ namespace CSMWorld
|
|||
UniversalId::Type type = UniversalId::Type_None) = 0;
|
||||
///< If the record type does not match, an exception is thrown.
|
||||
|
||||
virtual void cloneRecord(const std::string& origin,
|
||||
virtual void cloneRecord(const std::string& origin,
|
||||
const std::string& destination,
|
||||
const UniversalId::Type type) = 0;
|
||||
|
||||
|
|
|
@ -247,12 +247,12 @@ CSMWorld::Data::Data() : mRefs (mCells)
|
|||
addModel (new IdTable (&mSpells), UniversalId::Type_Spells, UniversalId::Type_Spell);
|
||||
addModel (new IdTable (&mTopics), UniversalId::Type_Topics, UniversalId::Type_Topic);
|
||||
addModel (new IdTable (&mJournals), UniversalId::Type_Journals, UniversalId::Type_Journal);
|
||||
addModel (new IdTable (&mTopicInfos), UniversalId::Type_TopicInfos, UniversalId::Type_TopicInfo);
|
||||
addModel (new IdTable (&mJournalInfos), UniversalId::Type_JournalInfos, UniversalId::Type_JournalInfo);
|
||||
addModel (new IdTable (&mCells), UniversalId::Type_Cells, UniversalId::Type_Cell);
|
||||
addModel (new IdTable (&mTopicInfos, IdTable::Reordering_WithinTopic), UniversalId::Type_TopicInfos, UniversalId::Type_TopicInfo);
|
||||
addModel (new IdTable (&mJournalInfos, IdTable::Reordering_WithinTopic), UniversalId::Type_JournalInfos, UniversalId::Type_JournalInfo);
|
||||
addModel (new IdTable (&mCells, IdTable::Reordering_None, IdTable::Viewing_Id), UniversalId::Type_Cells, UniversalId::Type_Cell);
|
||||
addModel (new IdTable (&mReferenceables), UniversalId::Type_Referenceables,
|
||||
UniversalId::Type_Referenceable);
|
||||
addModel (new IdTable (&mRefs), UniversalId::Type_References, UniversalId::Type_Reference, false);
|
||||
addModel (new IdTable (&mRefs, IdTable::Reordering_None, IdTable::Viewing_Cell), UniversalId::Type_References, UniversalId::Type_Reference, false);
|
||||
addModel (new IdTable (&mFilters), UniversalId::Type_Filters, UniversalId::Type_Filter, false);
|
||||
}
|
||||
|
||||
|
|
|
@ -4,8 +4,9 @@
|
|||
#include "collectionbase.hpp"
|
||||
#include "columnbase.hpp"
|
||||
|
||||
CSMWorld::IdTable::IdTable (CollectionBase *idCollection, Reordering reordering)
|
||||
: mIdCollection (idCollection), mReordering (reordering)
|
||||
CSMWorld::IdTable::IdTable (CollectionBase *idCollection, Reordering reordering,
|
||||
Viewing viewing)
|
||||
: mIdCollection (idCollection), mReordering (reordering), mViewing (viewing)
|
||||
{}
|
||||
|
||||
CSMWorld::IdTable::~IdTable()
|
||||
|
@ -188,4 +189,45 @@ void CSMWorld::IdTable::reorderRows (int baseIndex, const std::vector<int>& newO
|
|||
CSMWorld::IdTable::Reordering CSMWorld::IdTable::getReordering() const
|
||||
{
|
||||
return mReordering;
|
||||
}
|
||||
|
||||
CSMWorld::IdTable::Viewing CSMWorld::IdTable::getViewing() const
|
||||
{
|
||||
return mViewing;
|
||||
}
|
||||
|
||||
std::pair<CSMWorld::UniversalId, std::string> CSMWorld::IdTable::view (int row) const
|
||||
{
|
||||
std::string id;
|
||||
std::string hint;
|
||||
|
||||
if (mViewing==Viewing_Cell)
|
||||
{
|
||||
int cellColumn = mIdCollection->searchColumnIndex (Columns::ColumnId_Cell);
|
||||
int idColumn = mIdCollection->searchColumnIndex (Columns::ColumnId_Id);
|
||||
|
||||
if (cellColumn!=-1 && idColumn!=-1)
|
||||
{
|
||||
id = mIdCollection->getData (row, cellColumn).toString().toUtf8().constData();
|
||||
hint = "r:" + std::string (mIdCollection->getData (row, idColumn).toString().toUtf8().constData());
|
||||
}
|
||||
}
|
||||
else if (mViewing==Viewing_Id)
|
||||
{
|
||||
int column = mIdCollection->searchColumnIndex (Columns::ColumnId_Id);
|
||||
|
||||
if (column!=-1)
|
||||
{
|
||||
id = mIdCollection->getData (row, column).toString().toUtf8().constData();
|
||||
hint = "c:" + id;
|
||||
}
|
||||
}
|
||||
|
||||
if (id.empty())
|
||||
return std::make_pair (UniversalId::Type_None, "");
|
||||
|
||||
if (id[0]=='#')
|
||||
id = "sys::default";
|
||||
|
||||
return std::make_pair (UniversalId (UniversalId::Type_Scene, id), hint);
|
||||
}
|
|
@ -25,10 +25,20 @@ namespace CSMWorld
|
|||
Reordering_WithinTopic
|
||||
};
|
||||
|
||||
enum Viewing
|
||||
{
|
||||
Viewing_None,
|
||||
Viewing_Id, // use ID column to generate view request (ID is transformed into
|
||||
// worldspace and original ID is passed as hint with c: prefix)
|
||||
Viewing_Cell // use cell column to generate view request (cell ID is transformed
|
||||
// into worldspace and record ID is passed as hint with r: prefix)
|
||||
};
|
||||
|
||||
private:
|
||||
|
||||
CollectionBase *mIdCollection;
|
||||
Reordering mReordering;
|
||||
Viewing mViewing;
|
||||
|
||||
// not implemented
|
||||
IdTable (const IdTable&);
|
||||
|
@ -36,7 +46,8 @@ namespace CSMWorld
|
|||
|
||||
public:
|
||||
|
||||
IdTable (CollectionBase *idCollection, Reordering reordering = Reordering_WithinTopic);
|
||||
IdTable (CollectionBase *idCollection, Reordering reordering = Reordering_None,
|
||||
Viewing viewing = Viewing_None);
|
||||
///< The ownership of \a idCollection is not transferred.
|
||||
|
||||
virtual ~IdTable();
|
||||
|
@ -63,8 +74,8 @@ namespace CSMWorld
|
|||
void addRecord (const std::string& id, UniversalId::Type type = UniversalId::Type_None);
|
||||
///< \param type Will be ignored, unless the collection supports multiple record types
|
||||
|
||||
void cloneRecord(const std::string& origin,
|
||||
const std::string& destination,
|
||||
void cloneRecord(const std::string& origin,
|
||||
const std::string& destination,
|
||||
UniversalId::Type type = UniversalId::Type_None);
|
||||
|
||||
QModelIndex getModelIndex (const std::string& id, int column) const;
|
||||
|
@ -86,6 +97,12 @@ namespace CSMWorld
|
|||
/// given in \a newOrder (baseIndex+newOrder[0] specifies the new index of row baseIndex).
|
||||
|
||||
Reordering getReordering() const;
|
||||
|
||||
Viewing getViewing() const;
|
||||
|
||||
std::pair<UniversalId, std::string> view (int row) const;
|
||||
///< Return the UniversalId and the hint for viewing \a row. If viewing is not
|
||||
/// supported by this table, return (UniversalId::Type_None, "").
|
||||
};
|
||||
}
|
||||
|
||||
|
|
|
@ -90,14 +90,14 @@ namespace
|
|||
{ CSMWorld::UniversalId::Class_RefRecord, CSMWorld::UniversalId::Type_Weapon, "Weapon", ":./weapon.png" },
|
||||
{ CSMWorld::UniversalId::Class_SubRecord, CSMWorld::UniversalId::Type_Reference, "Reference", 0 },
|
||||
{ CSMWorld::UniversalId::Class_SubRecord, CSMWorld::UniversalId::Type_Filter, "Filter", ":./filter.png" },
|
||||
{ CSMWorld::UniversalId::Class_Collection, CSMWorld::UniversalId::Type_Scene, "Scene", 0 },
|
||||
|
||||
{ CSMWorld::UniversalId::Class_None, CSMWorld::UniversalId::Type_None, 0, 0 } // end marker
|
||||
};
|
||||
|
||||
static const TypeData sIndexArg[] =
|
||||
{
|
||||
{ CSMWorld::UniversalId::Class_Transient, CSMWorld::UniversalId::Type_VerificationResults, "Verification Results", 0 },
|
||||
{ CSMWorld::UniversalId::Class_Collection, CSMWorld::UniversalId::Type_Scene, "Scene", 0 },
|
||||
|
||||
{ CSMWorld::UniversalId::Class_None, CSMWorld::UniversalId::Type_None, 0, 0 } // end marker
|
||||
};
|
||||
}
|
||||
|
|
|
@ -16,4 +16,6 @@ void CSVDoc::SubView::updateEditorSetting (const QString &settingName, const QSt
|
|||
{
|
||||
}
|
||||
|
||||
void CSVDoc::SubView::setStatusBar (bool show) {}
|
||||
void CSVDoc::SubView::setStatusBar (bool show) {}
|
||||
|
||||
void CSVDoc::SubView::useHint (const std::string& hint) {}
|
|
@ -40,9 +40,12 @@ namespace CSVDoc
|
|||
virtual void setStatusBar (bool show);
|
||||
///< Default implementation: ignored
|
||||
|
||||
virtual void useHint (const std::string& hint);
|
||||
///< Default implementation: ignored
|
||||
|
||||
signals:
|
||||
|
||||
void focusId (const CSMWorld::UniversalId& universalId);
|
||||
void focusId (const CSMWorld::UniversalId& universalId, const std::string& hint);
|
||||
};
|
||||
}
|
||||
|
||||
|
|
|
@ -115,10 +115,6 @@ void CSVDoc::View::setupWorldMenu()
|
|||
|
||||
world->addSeparator(); // items that don't represent single record lists follow here
|
||||
|
||||
QAction *scene = new QAction (tr ("Scene"), this);
|
||||
connect (scene, SIGNAL (triggered()), this, SLOT (addSceneSubView()));
|
||||
world->addAction (scene);
|
||||
|
||||
QAction *regionMap = new QAction (tr ("Region Map"), this);
|
||||
connect (regionMap, SIGNAL (triggered()), this, SLOT (addRegionMapSubView()));
|
||||
world->addAction (regionMap);
|
||||
|
@ -310,7 +306,7 @@ void CSVDoc::View::updateProgress (int current, int max, int type, int threads)
|
|||
mOperations->setProgress (current, max, type, threads);
|
||||
}
|
||||
|
||||
void CSVDoc::View::addSubView (const CSMWorld::UniversalId& id)
|
||||
void CSVDoc::View::addSubView (const CSMWorld::UniversalId& id, const std::string& hint)
|
||||
{
|
||||
/// \todo add an user setting for limiting the number of sub views per top level view. Automatically open a new top level view if this
|
||||
/// number is exceeded
|
||||
|
@ -322,12 +318,15 @@ void CSVDoc::View::addSubView (const CSMWorld::UniversalId& id)
|
|||
|
||||
SubView *view = mSubViewFactory.makeSubView (id, *mDocument);
|
||||
|
||||
if (!hint.empty())
|
||||
view->useHint (hint);
|
||||
|
||||
view->setStatusBar (mShowStatusBar->isChecked());
|
||||
|
||||
mSubViewWindow.addDockWidget (Qt::TopDockWidgetArea, view);
|
||||
|
||||
connect (view, SIGNAL (focusId (const CSMWorld::UniversalId&)), this,
|
||||
SLOT (addSubView (const CSMWorld::UniversalId&)));
|
||||
connect (view, SIGNAL (focusId (const CSMWorld::UniversalId&, const std::string&)), this,
|
||||
SLOT (addSubView (const CSMWorld::UniversalId&, const std::string&)));
|
||||
|
||||
CSMSettings::UserSettings::instance().updateSettings("Display Format");
|
||||
|
||||
|
@ -429,11 +428,6 @@ void CSVDoc::View::addFiltersSubView()
|
|||
addSubView (CSMWorld::UniversalId::Type_Filters);
|
||||
}
|
||||
|
||||
void CSVDoc::View::addSceneSubView()
|
||||
{
|
||||
addSubView (CSMWorld::UniversalId::Type_Scene);
|
||||
}
|
||||
|
||||
void CSVDoc::View::addTopicsSubView()
|
||||
{
|
||||
addSubView (CSMWorld::UniversalId::Type_Topics);
|
||||
|
|
|
@ -120,7 +120,9 @@ namespace CSVDoc
|
|||
|
||||
public slots:
|
||||
|
||||
void addSubView (const CSMWorld::UniversalId& id);
|
||||
void addSubView (const CSMWorld::UniversalId& id, const std::string& hint = "");
|
||||
///< \param hint Suggested view point (e.g. coordinates in a 3D scene or a line number
|
||||
/// in a script).
|
||||
|
||||
void abortOperation (int type);
|
||||
|
||||
|
@ -166,8 +168,6 @@ namespace CSVDoc
|
|||
|
||||
void addFiltersSubView();
|
||||
|
||||
void addSceneSubView();
|
||||
|
||||
void addTopicsSubView();
|
||||
|
||||
void addJournalsSubView();
|
||||
|
|
19
apps/opencs/view/render/navigation.cpp
Normal file
19
apps/opencs/view/render/navigation.cpp
Normal file
|
@ -0,0 +1,19 @@
|
|||
|
||||
#include "navigation.hpp"
|
||||
|
||||
float CSVRender::Navigation::getFactor (bool mouse) const
|
||||
{
|
||||
float factor = mFastModeFactor;
|
||||
|
||||
if (mouse)
|
||||
factor /= 2; /// \todo make this configurable
|
||||
|
||||
return factor;
|
||||
}
|
||||
|
||||
CSVRender::Navigation::~Navigation() {}
|
||||
|
||||
void CSVRender::Navigation::setFastModeFactor (float factor)
|
||||
{
|
||||
mFastModeFactor = factor;
|
||||
}
|
46
apps/opencs/view/render/navigation.hpp
Normal file
46
apps/opencs/view/render/navigation.hpp
Normal file
|
@ -0,0 +1,46 @@
|
|||
#ifndef OPENCS_VIEW_NAVIGATION_H
|
||||
#define OPENCS_VIEW_NAVIGATION_H
|
||||
|
||||
class QPoint;
|
||||
|
||||
namespace Ogre
|
||||
{
|
||||
class Camera;
|
||||
}
|
||||
|
||||
namespace CSVRender
|
||||
{
|
||||
class Navigation
|
||||
{
|
||||
float mFastModeFactor;
|
||||
|
||||
protected:
|
||||
|
||||
float getFactor (bool mouse) const;
|
||||
|
||||
public:
|
||||
|
||||
virtual ~Navigation();
|
||||
|
||||
void setFastModeFactor (float factor);
|
||||
///< Set currently applying fast mode factor.
|
||||
|
||||
virtual bool activate (Ogre::Camera *camera) = 0;
|
||||
///< \return Update required?
|
||||
|
||||
virtual bool wheelMoved (int delta) = 0;
|
||||
///< \return Update required?
|
||||
|
||||
virtual bool mouseMoved (const QPoint& delta, int mode) = 0;
|
||||
///< \param mode: 0: default mouse key, 1: default mouse key and modifier key 1
|
||||
/// \return Update required?
|
||||
|
||||
virtual bool handleMovementKeys (int vertical, int horizontal) = 0;
|
||||
///< \return Update required?
|
||||
|
||||
virtual bool handleRollKeys (int delta) = 0;
|
||||
///< \return Update required?
|
||||
};
|
||||
}
|
||||
|
||||
#endif
|
85
apps/opencs/view/render/navigation1st.cpp
Normal file
85
apps/opencs/view/render/navigation1st.cpp
Normal file
|
@ -0,0 +1,85 @@
|
|||
|
||||
#include "navigation1st.hpp"
|
||||
|
||||
#include <OgreCamera.h>
|
||||
|
||||
#include <QPoint>
|
||||
|
||||
CSVRender::Navigation1st::Navigation1st() : mCamera (0) {}
|
||||
|
||||
bool CSVRender::Navigation1st::activate (Ogre::Camera *camera)
|
||||
{
|
||||
mCamera = camera;
|
||||
mCamera->setFixedYawAxis (true);
|
||||
|
||||
Ogre::Radian pitch = mCamera->getOrientation().getPitch();
|
||||
|
||||
Ogre::Radian limit (Ogre::Math::PI/2-0.5);
|
||||
|
||||
if (pitch>limit)
|
||||
mCamera->pitch (-(pitch-limit));
|
||||
else if (pitch<-limit)
|
||||
mCamera->pitch (pitch-limit);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool CSVRender::Navigation1st::wheelMoved (int delta)
|
||||
{
|
||||
mCamera->move (getFactor (true) * mCamera->getDirection() * delta);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool CSVRender::Navigation1st::mouseMoved (const QPoint& delta, int mode)
|
||||
{
|
||||
if (mode==0)
|
||||
{
|
||||
// turn camera
|
||||
if (delta.x())
|
||||
mCamera->yaw (Ogre::Degree (getFactor (true) * delta.x()));
|
||||
|
||||
if (delta.y())
|
||||
{
|
||||
Ogre::Radian oldPitch = mCamera->getOrientation().getPitch();
|
||||
float deltaPitch = getFactor (true) * delta.y();
|
||||
Ogre::Radian newPitch = oldPitch + Ogre::Degree (deltaPitch);
|
||||
|
||||
Ogre::Radian limit (Ogre::Math::PI/2-0.5);
|
||||
|
||||
if ((deltaPitch>0 && newPitch<limit) || (deltaPitch<0 && newPitch>-limit))
|
||||
mCamera->pitch (Ogre::Degree (deltaPitch));
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
else if (mode==1)
|
||||
{
|
||||
// pan camera
|
||||
if (delta.x())
|
||||
mCamera->move (getFactor (true) * mCamera->getDerivedRight() * delta.x());
|
||||
|
||||
if (delta.y())
|
||||
mCamera->move (getFactor (true) * -mCamera->getDerivedUp() * delta.y());
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool CSVRender::Navigation1st::handleMovementKeys (int vertical, int horizontal)
|
||||
{
|
||||
if (vertical)
|
||||
mCamera->move (getFactor (false) * mCamera->getDirection() * vertical);
|
||||
|
||||
if (horizontal)
|
||||
mCamera->move (getFactor (true) * mCamera->getDerivedRight() * horizontal);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool CSVRender::Navigation1st::handleRollKeys (int delta)
|
||||
{
|
||||
// we don't roll this way in 1st person mode
|
||||
return false;
|
||||
}
|
35
apps/opencs/view/render/navigation1st.hpp
Normal file
35
apps/opencs/view/render/navigation1st.hpp
Normal file
|
@ -0,0 +1,35 @@
|
|||
#ifndef OPENCS_VIEW_NAVIGATION1ST_H
|
||||
#define OPENCS_VIEW_NAVIGATION1ST_H
|
||||
|
||||
#include "navigation.hpp"
|
||||
|
||||
namespace CSVRender
|
||||
{
|
||||
/// \brief First person-like camera controls
|
||||
class Navigation1st : public Navigation
|
||||
{
|
||||
Ogre::Camera *mCamera;
|
||||
|
||||
public:
|
||||
|
||||
Navigation1st();
|
||||
|
||||
virtual bool activate (Ogre::Camera *camera);
|
||||
///< \return Update required?
|
||||
|
||||
virtual bool wheelMoved (int delta);
|
||||
///< \return Update required?
|
||||
|
||||
virtual bool mouseMoved (const QPoint& delta, int mode);
|
||||
///< \param mode: 0: default mouse key, 1: default mouse key and modifier key 1
|
||||
/// \return Update required?
|
||||
|
||||
virtual bool handleMovementKeys (int vertical, int horizontal);
|
||||
///< \return Update required?
|
||||
|
||||
virtual bool handleRollKeys (int delta);
|
||||
///< \return Update required?
|
||||
};
|
||||
}
|
||||
|
||||
#endif
|
66
apps/opencs/view/render/navigationfree.cpp
Normal file
66
apps/opencs/view/render/navigationfree.cpp
Normal file
|
@ -0,0 +1,66 @@
|
|||
|
||||
#include "navigationfree.hpp"
|
||||
|
||||
#include <OgreCamera.h>
|
||||
|
||||
#include <QPoint>
|
||||
|
||||
CSVRender::NavigationFree::NavigationFree() : mCamera (0) {}
|
||||
|
||||
bool CSVRender::NavigationFree::activate (Ogre::Camera *camera)
|
||||
{
|
||||
mCamera = camera;
|
||||
mCamera->setFixedYawAxis (false);
|
||||
return false;
|
||||
}
|
||||
|
||||
bool CSVRender::NavigationFree::wheelMoved (int delta)
|
||||
{
|
||||
mCamera->move (getFactor (true) * mCamera->getDirection() * delta);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool CSVRender::NavigationFree::mouseMoved (const QPoint& delta, int mode)
|
||||
{
|
||||
if (mode==0)
|
||||
{
|
||||
// turn camera
|
||||
if (delta.x())
|
||||
mCamera->yaw (Ogre::Degree (getFactor (true) * delta.x()));
|
||||
|
||||
if (delta.y())
|
||||
mCamera->pitch (Ogre::Degree (getFactor (true) * delta.y()));
|
||||
|
||||
return true;
|
||||
}
|
||||
else if (mode==1)
|
||||
{
|
||||
// pan camera
|
||||
if (delta.x())
|
||||
mCamera->move (getFactor (true) * mCamera->getDerivedRight() * delta.x());
|
||||
|
||||
if (delta.y())
|
||||
mCamera->move (getFactor (true) * -mCamera->getDerivedUp() * delta.y());
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool CSVRender::NavigationFree::handleMovementKeys (int vertical, int horizontal)
|
||||
{
|
||||
if (vertical)
|
||||
mCamera->move (getFactor (false) * mCamera->getDerivedUp() * vertical);
|
||||
|
||||
if (horizontal)
|
||||
mCamera->move (getFactor (true) * mCamera->getDerivedRight() * horizontal);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool CSVRender::NavigationFree::handleRollKeys (int delta)
|
||||
{
|
||||
mCamera->roll (Ogre::Degree (getFactor (false) * delta));
|
||||
return true;
|
||||
}
|
35
apps/opencs/view/render/navigationfree.hpp
Normal file
35
apps/opencs/view/render/navigationfree.hpp
Normal file
|
@ -0,0 +1,35 @@
|
|||
#ifndef OPENCS_VIEW_NAVIGATIONFREE_H
|
||||
#define OPENCS_VIEW_NAVIGATIONFREE_H
|
||||
|
||||
#include "navigation.hpp"
|
||||
|
||||
namespace CSVRender
|
||||
{
|
||||
/// \brief Free camera controls
|
||||
class NavigationFree : public Navigation
|
||||
{
|
||||
Ogre::Camera *mCamera;
|
||||
|
||||
public:
|
||||
|
||||
NavigationFree();
|
||||
|
||||
virtual bool activate (Ogre::Camera *camera);
|
||||
///< \return Update required?
|
||||
|
||||
virtual bool wheelMoved (int delta);
|
||||
///< \return Update required?
|
||||
|
||||
virtual bool mouseMoved (const QPoint& delta, int mode);
|
||||
///< \param mode: 0: default mouse key, 1: default mouse key and modifier key 1
|
||||
/// \return Update required?
|
||||
|
||||
virtual bool handleMovementKeys (int vertical, int horizontal);
|
||||
///< \return Update required?
|
||||
|
||||
virtual bool handleRollKeys (int delta);
|
||||
///< \return Update required?
|
||||
};
|
||||
}
|
||||
|
||||
#endif
|
100
apps/opencs/view/render/navigationorbit.cpp
Normal file
100
apps/opencs/view/render/navigationorbit.cpp
Normal file
|
@ -0,0 +1,100 @@
|
|||
|
||||
#include "navigationorbit.hpp"
|
||||
|
||||
#include <OgreCamera.h>
|
||||
|
||||
#include <QPoint>
|
||||
|
||||
void CSVRender::NavigationOrbit::rotateCamera (const Ogre::Vector3& diff)
|
||||
{
|
||||
Ogre::Vector3 pos = mCamera->getPosition();
|
||||
|
||||
float distance = (pos-mCentre).length();
|
||||
|
||||
Ogre::Vector3 direction = (pos+diff)-mCentre;
|
||||
direction.normalise();
|
||||
|
||||
mCamera->setPosition (mCentre + direction*distance);
|
||||
mCamera->lookAt (mCentre);
|
||||
}
|
||||
|
||||
CSVRender::NavigationOrbit::NavigationOrbit() : mCamera (0), mCentre (0, 0, 0), mDistance (100)
|
||||
{}
|
||||
|
||||
bool CSVRender::NavigationOrbit::activate (Ogre::Camera *camera)
|
||||
{
|
||||
mCamera = camera;
|
||||
mCamera->setFixedYawAxis (false);
|
||||
|
||||
if ((mCamera->getPosition()-mCentre).length()<mDistance)
|
||||
{
|
||||
// move camera out of the centre area
|
||||
Ogre::Vector3 direction = mCentre-mCamera->getPosition();
|
||||
direction.normalise();
|
||||
|
||||
if (direction.length()==0)
|
||||
direction = Ogre::Vector3 (1, 0, 0);
|
||||
|
||||
mCamera->setPosition (mCentre - direction * mDistance);
|
||||
}
|
||||
|
||||
mCamera->lookAt (mCentre);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool CSVRender::NavigationOrbit::wheelMoved (int delta)
|
||||
{
|
||||
Ogre::Vector3 diff = getFactor (true) * mCamera->getDirection() * delta;
|
||||
|
||||
Ogre::Vector3 pos = mCamera->getPosition();
|
||||
|
||||
if (delta>0 && diff.length()>=(pos-mCentre).length()-mDistance)
|
||||
{
|
||||
pos = mCentre-(mCamera->getDirection() * mDistance);
|
||||
}
|
||||
else
|
||||
{
|
||||
pos += diff;
|
||||
}
|
||||
|
||||
mCamera->setPosition (pos);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool CSVRender::NavigationOrbit::mouseMoved (const QPoint& delta, int mode)
|
||||
{
|
||||
Ogre::Vector3 diff =
|
||||
getFactor (true) * -mCamera->getDerivedRight() * delta.x()
|
||||
+ getFactor (true) * mCamera->getDerivedUp() * delta.y();
|
||||
|
||||
if (mode==0)
|
||||
{
|
||||
rotateCamera (diff);
|
||||
return true;
|
||||
}
|
||||
else if (mode==1)
|
||||
{
|
||||
mCamera->move (diff);
|
||||
mCentre += diff;
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool CSVRender::NavigationOrbit::handleMovementKeys (int vertical, int horizontal)
|
||||
{
|
||||
rotateCamera (
|
||||
- getFactor (false) * -mCamera->getDerivedRight() * horizontal
|
||||
+ getFactor (false) * mCamera->getDerivedUp() * vertical);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool CSVRender::NavigationOrbit::handleRollKeys (int delta)
|
||||
{
|
||||
mCamera->roll (Ogre::Degree (getFactor (false) * delta));
|
||||
return true;
|
||||
}
|
42
apps/opencs/view/render/navigationorbit.hpp
Normal file
42
apps/opencs/view/render/navigationorbit.hpp
Normal file
|
@ -0,0 +1,42 @@
|
|||
#ifndef OPENCS_VIEW_NAVIGATIONORBIT_H
|
||||
#define OPENCS_VIEW_NAVIGATIONORBIT_H
|
||||
|
||||
#include "navigation.hpp"
|
||||
|
||||
#include <OgreVector3.h>
|
||||
|
||||
namespace CSVRender
|
||||
{
|
||||
/// \brief Orbiting camera controls
|
||||
class NavigationOrbit : public Navigation
|
||||
{
|
||||
Ogre::Camera *mCamera;
|
||||
Ogre::Vector3 mCentre;
|
||||
int mDistance;
|
||||
|
||||
void rotateCamera (const Ogre::Vector3& diff);
|
||||
///< Rotate camera around centre.
|
||||
|
||||
public:
|
||||
|
||||
NavigationOrbit();
|
||||
|
||||
virtual bool activate (Ogre::Camera *camera);
|
||||
///< \return Update required?
|
||||
|
||||
virtual bool wheelMoved (int delta);
|
||||
///< \return Update required?
|
||||
|
||||
virtual bool mouseMoved (const QPoint& delta, int mode);
|
||||
///< \param mode: 0: default mouse key, 1: default mouse key and modifier key 1
|
||||
/// \return Update required?
|
||||
|
||||
virtual bool handleMovementKeys (int vertical, int horizontal);
|
||||
///< \return Update required?
|
||||
|
||||
virtual bool handleRollKeys (int delta);
|
||||
///< \return Update required?
|
||||
};
|
||||
}
|
||||
|
||||
#endif
|
6
apps/opencs/view/render/pagedworldspacewidget.cpp
Normal file
6
apps/opencs/view/render/pagedworldspacewidget.cpp
Normal file
|
@ -0,0 +1,6 @@
|
|||
|
||||
#include "pagedworldspacewidget.hpp"
|
||||
|
||||
CSVRender::PagedWorldspaceWidget::PagedWorldspaceWidget (QWidget *parent)
|
||||
: WorldspaceWidget (parent)
|
||||
{}
|
18
apps/opencs/view/render/pagedworldspacewidget.hpp
Normal file
18
apps/opencs/view/render/pagedworldspacewidget.hpp
Normal file
|
@ -0,0 +1,18 @@
|
|||
#ifndef OPENCS_VIEW_PAGEDWORLDSPACEWIDGET_H
|
||||
#define OPENCS_VIEW_PAGEDWORLDSPACEWIDGET_H
|
||||
|
||||
#include "worldspacewidget.hpp"
|
||||
|
||||
namespace CSVRender
|
||||
{
|
||||
class PagedWorldspaceWidget : public WorldspaceWidget
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
|
||||
PagedWorldspaceWidget (QWidget *parent);
|
||||
};
|
||||
}
|
||||
|
||||
#endif
|
|
@ -2,24 +2,34 @@
|
|||
|
||||
#include <QEvent>
|
||||
#include <QResizeEvent>
|
||||
#include <QTimer>
|
||||
|
||||
#include <OgreRoot.h>
|
||||
#include <OgreRenderWindow.h>
|
||||
#include <OgreEntity.h>
|
||||
#include <OgreCamera.h>
|
||||
#include <OgreSceneNode.h>
|
||||
#include <OgreViewport.h>
|
||||
|
||||
#include "navigation.hpp"
|
||||
|
||||
namespace CSVRender
|
||||
{
|
||||
|
||||
SceneWidget::SceneWidget(QWidget *parent)
|
||||
: QWidget(parent)
|
||||
, mWindow(NULL)
|
||||
, mCamera(NULL)
|
||||
, mSceneMgr(NULL)
|
||||
, mSceneMgr(NULL), mNavigation (0), mUpdate (false)
|
||||
, mKeyForward (false), mKeyBackward (false), mKeyLeft (false), mKeyRight (false)
|
||||
, mKeyRollLeft (false), mKeyRollRight (false)
|
||||
, mFast (false), mDragging (false), mMod1 (false)
|
||||
, mFastFactor (4) /// \todo make this configurable
|
||||
{
|
||||
setAttribute(Qt::WA_PaintOnScreen);
|
||||
setAttribute(Qt::WA_NoSystemBackground);
|
||||
|
||||
setFocusPolicy (Qt::StrongFocus);
|
||||
|
||||
mSceneMgr = Ogre::Root::getSingleton().createSceneManager(Ogre::ST_GENERIC);
|
||||
|
||||
// Throw in a random color just to make sure multiple scenes work
|
||||
|
@ -44,6 +54,16 @@ namespace CSVRender
|
|||
mCamera->lookAt(0,0,0);
|
||||
mCamera->setNearClipDistance(0.1);
|
||||
mCamera->setFarClipDistance(3000);
|
||||
|
||||
QTimer *timer = new QTimer (this);
|
||||
|
||||
connect (timer, SIGNAL (timeout()), this, SLOT (update()));
|
||||
timer->start (20); /// \todo make this configurable
|
||||
}
|
||||
|
||||
void SceneWidget::setAmbient (const Ogre::ColourValue& colour)
|
||||
{
|
||||
mSceneMgr->setAmbientLight (colour);
|
||||
}
|
||||
|
||||
void SceneWidget::updateOgreWindow()
|
||||
|
@ -81,7 +101,21 @@ namespace CSVRender
|
|||
|
||||
SceneWidget::~SceneWidget()
|
||||
{
|
||||
Ogre::Root::getSingleton().destroyRenderTarget(mWindow);
|
||||
if (mWindow)
|
||||
Ogre::Root::getSingleton().destroyRenderTarget (mWindow);
|
||||
|
||||
if (mSceneMgr)
|
||||
Ogre::Root::getSingleton().destroySceneManager (mSceneMgr);
|
||||
}
|
||||
|
||||
void SceneWidget::setNavigation (Navigation *navigation)
|
||||
{
|
||||
if ((mNavigation = navigation))
|
||||
{
|
||||
mNavigation->setFastModeFactor (mFast ? mFastFactor : 1);
|
||||
if (mNavigation->activate (mCamera))
|
||||
mUpdate = true;
|
||||
}
|
||||
}
|
||||
|
||||
void SceneWidget::paintEvent(QPaintEvent* e)
|
||||
|
@ -93,7 +127,6 @@ namespace CSVRender
|
|||
e->accept();
|
||||
}
|
||||
|
||||
|
||||
QPaintEngine* SceneWidget::paintEngine() const
|
||||
{
|
||||
// We don't want another paint engine to get in the way.
|
||||
|
@ -130,4 +163,151 @@ namespace CSVRender
|
|||
return QWidget::event(e);
|
||||
}
|
||||
|
||||
void SceneWidget::keyPressEvent (QKeyEvent *event)
|
||||
{
|
||||
switch (event->key())
|
||||
{
|
||||
case Qt::Key_W: mKeyForward = true; break;
|
||||
case Qt::Key_S: mKeyBackward = true; break;
|
||||
case Qt::Key_A: mKeyLeft = true; break;
|
||||
case Qt::Key_D: mKeyRight = true; break;
|
||||
case Qt::Key_Q: mKeyRollLeft = true; break;
|
||||
case Qt::Key_E: mKeyRollRight = true; break;
|
||||
case Qt::Key_Control: mMod1 = true; break;
|
||||
|
||||
case Qt::Key_Shift:
|
||||
|
||||
mFast = true;
|
||||
|
||||
if (mNavigation)
|
||||
mNavigation->setFastModeFactor (mFastFactor);
|
||||
|
||||
break;
|
||||
|
||||
default: QWidget::keyPressEvent (event);
|
||||
}
|
||||
}
|
||||
|
||||
void SceneWidget::keyReleaseEvent (QKeyEvent *event)
|
||||
{
|
||||
switch (event->key())
|
||||
{
|
||||
case Qt::Key_W: mKeyForward = false; break;
|
||||
case Qt::Key_S: mKeyBackward = false; break;
|
||||
case Qt::Key_A: mKeyLeft = false; break;
|
||||
case Qt::Key_D: mKeyRight = false; break;
|
||||
case Qt::Key_Q: mKeyRollLeft = false; break;
|
||||
case Qt::Key_E: mKeyRollRight = false; break;
|
||||
case Qt::Key_Control: mMod1 = false; break;
|
||||
|
||||
case Qt::Key_Shift:
|
||||
|
||||
mFast = false;
|
||||
|
||||
if (mNavigation)
|
||||
mNavigation->setFastModeFactor (1);
|
||||
|
||||
break;
|
||||
|
||||
default: QWidget::keyReleaseEvent (event);
|
||||
}
|
||||
}
|
||||
|
||||
void SceneWidget::wheelEvent (QWheelEvent *event)
|
||||
{
|
||||
if (mNavigation)
|
||||
if (event->delta())
|
||||
if (mNavigation->wheelMoved (event->delta()))
|
||||
mUpdate = true;
|
||||
}
|
||||
|
||||
void SceneWidget::leaveEvent (QEvent *event)
|
||||
{
|
||||
mDragging = false;
|
||||
}
|
||||
|
||||
void SceneWidget::mouseMoveEvent (QMouseEvent *event)
|
||||
{
|
||||
if (event->buttons() & Qt::LeftButton)
|
||||
{
|
||||
if (mDragging)
|
||||
{
|
||||
QPoint diff = mOldPos-event->pos();
|
||||
mOldPos = event->pos();
|
||||
|
||||
if (mNavigation)
|
||||
if (mNavigation->mouseMoved (diff, mMod1 ? 1 : 0))
|
||||
mUpdate = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
mDragging = true;
|
||||
mOldPos = event->pos();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void SceneWidget::mouseReleaseEvent (QMouseEvent *event)
|
||||
{
|
||||
if (!(event->buttons() & Qt::LeftButton))
|
||||
mDragging = false;
|
||||
}
|
||||
|
||||
void SceneWidget::focusOutEvent (QFocusEvent *event)
|
||||
{
|
||||
mKeyForward = false;
|
||||
mKeyBackward = false;
|
||||
mKeyLeft = false;
|
||||
mKeyRight = false;
|
||||
mFast = false;
|
||||
mMod1 = false;
|
||||
|
||||
QWidget::focusOutEvent (event);
|
||||
}
|
||||
|
||||
void SceneWidget::update()
|
||||
{
|
||||
if (mNavigation)
|
||||
{
|
||||
int horizontal = 0;
|
||||
int vertical = 0;
|
||||
|
||||
if (mKeyForward && !mKeyBackward)
|
||||
vertical = 1;
|
||||
else if (!mKeyForward && mKeyBackward)
|
||||
vertical = -1;
|
||||
|
||||
if (mKeyLeft && !mKeyRight)
|
||||
horizontal = -1;
|
||||
else if (!mKeyLeft && mKeyRight)
|
||||
horizontal = 1;
|
||||
|
||||
if (horizontal || vertical)
|
||||
if (mNavigation->handleMovementKeys (vertical, horizontal))
|
||||
mUpdate = true;
|
||||
|
||||
int roll = 0;
|
||||
|
||||
if (mKeyRollLeft && !mKeyRollRight)
|
||||
roll = 1;
|
||||
else if (!mKeyRollLeft && mKeyRollRight)
|
||||
roll = -1;
|
||||
|
||||
if (roll)
|
||||
if (mNavigation->handleRollKeys (roll))
|
||||
mUpdate = true;
|
||||
|
||||
}
|
||||
|
||||
if (mUpdate)
|
||||
{
|
||||
mUpdate = false;
|
||||
mWindow->update();
|
||||
}
|
||||
}
|
||||
|
||||
int SceneWidget::getFastFactor() const
|
||||
{
|
||||
return mFast ? mFastFactor : 1;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -8,33 +8,77 @@ namespace Ogre
|
|||
class Camera;
|
||||
class SceneManager;
|
||||
class RenderWindow;
|
||||
class ColourValue;
|
||||
}
|
||||
|
||||
namespace CSVRender
|
||||
{
|
||||
class Navigation;
|
||||
|
||||
class SceneWidget : public QWidget
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
SceneWidget(QWidget *parent);
|
||||
virtual ~SceneWidget(void);
|
||||
public:
|
||||
|
||||
QPaintEngine* paintEngine() const;
|
||||
SceneWidget(QWidget *parent);
|
||||
virtual ~SceneWidget();
|
||||
|
||||
private:
|
||||
void paintEvent(QPaintEvent* e);
|
||||
void resizeEvent(QResizeEvent* e);
|
||||
bool event(QEvent* e);
|
||||
QPaintEngine* paintEngine() const;
|
||||
|
||||
void updateOgreWindow();
|
||||
void setAmbient (const Ogre::ColourValue& colour);
|
||||
///< \note The actual ambient colour may differ based on lighting settings.
|
||||
|
||||
Ogre::Camera* mCamera;
|
||||
Ogre::SceneManager* mSceneMgr;
|
||||
Ogre::RenderWindow* mWindow;
|
||||
protected:
|
||||
|
||||
void setNavigation (Navigation *navigation);
|
||||
///< \attention The ownership of \a navigation is not transferred to *this.
|
||||
|
||||
private:
|
||||
void paintEvent(QPaintEvent* e);
|
||||
void resizeEvent(QResizeEvent* e);
|
||||
bool event(QEvent* e);
|
||||
|
||||
void keyPressEvent (QKeyEvent *event);
|
||||
|
||||
void keyReleaseEvent (QKeyEvent *event);
|
||||
|
||||
void focusOutEvent (QFocusEvent *event);
|
||||
|
||||
void wheelEvent (QWheelEvent *event);
|
||||
|
||||
void leaveEvent (QEvent *event);
|
||||
|
||||
void mouseMoveEvent (QMouseEvent *event);
|
||||
|
||||
void mouseReleaseEvent (QMouseEvent *event);
|
||||
|
||||
void updateOgreWindow();
|
||||
|
||||
int getFastFactor() const;
|
||||
|
||||
Ogre::Camera* mCamera;
|
||||
Ogre::SceneManager* mSceneMgr;
|
||||
Ogre::RenderWindow* mWindow;
|
||||
|
||||
Navigation *mNavigation;
|
||||
bool mUpdate;
|
||||
bool mKeyForward;
|
||||
bool mKeyBackward;
|
||||
bool mKeyLeft;
|
||||
bool mKeyRight;
|
||||
bool mKeyRollLeft;
|
||||
bool mKeyRollRight;
|
||||
bool mFast;
|
||||
bool mDragging;
|
||||
bool mMod1;
|
||||
QPoint mOldPos;
|
||||
int mFastFactor;
|
||||
|
||||
private slots:
|
||||
|
||||
void update();
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
|
|
66
apps/opencs/view/render/unpagedworldspacewidget.cpp
Normal file
66
apps/opencs/view/render/unpagedworldspacewidget.cpp
Normal file
|
@ -0,0 +1,66 @@
|
|||
|
||||
#include "unpagedworldspacewidget.hpp"
|
||||
|
||||
#include <OgreColourValue.h>
|
||||
|
||||
#include "../../model/doc/document.hpp"
|
||||
|
||||
#include "../../model/world/data.hpp"
|
||||
#include "../../model/world/idtable.hpp"
|
||||
|
||||
void CSVRender::UnpagedWorldspaceWidget::update()
|
||||
{
|
||||
const CSMWorld::Record<CSMWorld::Cell>& record =
|
||||
dynamic_cast<const CSMWorld::Record<CSMWorld::Cell>&> (mCellsModel->getRecord (mCellId));
|
||||
|
||||
Ogre::ColourValue colour;
|
||||
colour.setAsABGR (record.get().mAmbi.mAmbient);
|
||||
setAmbient (colour);
|
||||
|
||||
/// \todo deal with mSunlight and mFog/mForDensity
|
||||
}
|
||||
|
||||
CSVRender::UnpagedWorldspaceWidget::UnpagedWorldspaceWidget (const std::string& cellId,
|
||||
CSMDoc::Document& document, QWidget *parent)
|
||||
: WorldspaceWidget (parent), mCellId (cellId)
|
||||
{
|
||||
mCellsModel = &dynamic_cast<CSMWorld::IdTable&> (
|
||||
*document.getData().getTableModel (CSMWorld::UniversalId::Type_Cells));
|
||||
|
||||
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();
|
||||
}
|
||||
|
||||
void CSVRender::UnpagedWorldspaceWidget::cellDataChanged (const QModelIndex& topLeft,
|
||||
const QModelIndex& bottomRight)
|
||||
{
|
||||
int index = mCellsModel->findColumnIndex (CSMWorld::Columns::ColumnId_Modification);
|
||||
QModelIndex cellIndex = mCellsModel->getModelIndex (mCellId, index);
|
||||
|
||||
if (cellIndex.row()>=topLeft.row() && cellIndex.row()<=bottomRight.row())
|
||||
{
|
||||
if (mCellsModel->data (cellIndex).toInt()==CSMWorld::RecordBase::State_Deleted)
|
||||
{
|
||||
emit closeRequest();
|
||||
}
|
||||
else
|
||||
{
|
||||
/// \todo possible optimisation: check columns and update only if relevant columns have
|
||||
/// changed
|
||||
update();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void CSVRender::UnpagedWorldspaceWidget::cellRowsAboutToBeRemoved (const QModelIndex& parent,
|
||||
int start, int end)
|
||||
{
|
||||
QModelIndex cellIndex = mCellsModel->getModelIndex (mCellId, 0);
|
||||
|
||||
if (cellIndex.row()>=start && cellIndex.row()<=end)
|
||||
emit closeRequest();
|
||||
}
|
44
apps/opencs/view/render/unpagedworldspacewidget.hpp
Normal file
44
apps/opencs/view/render/unpagedworldspacewidget.hpp
Normal file
|
@ -0,0 +1,44 @@
|
|||
#ifndef OPENCS_VIEW_UNPAGEDWORLDSPACEWIDGET_H
|
||||
#define OPENCS_VIEW_UNPAGEDWORLDSPACEWIDGET_H
|
||||
|
||||
#include <string>
|
||||
|
||||
#include "worldspacewidget.hpp"
|
||||
|
||||
class QModelIndex;
|
||||
|
||||
namespace CSMDoc
|
||||
{
|
||||
class Document;
|
||||
}
|
||||
|
||||
namespace CSMWorld
|
||||
{
|
||||
class IdTable;
|
||||
}
|
||||
|
||||
namespace CSVRender
|
||||
{
|
||||
class UnpagedWorldspaceWidget : public WorldspaceWidget
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
std::string mCellId;
|
||||
CSMWorld::IdTable *mCellsModel;
|
||||
|
||||
void update();
|
||||
|
||||
public:
|
||||
|
||||
UnpagedWorldspaceWidget (const std::string& cellId, CSMDoc::Document& document,
|
||||
QWidget *parent);
|
||||
|
||||
private slots:
|
||||
|
||||
void cellDataChanged (const QModelIndex& topLeft, const QModelIndex& bottomRight);
|
||||
|
||||
void cellRowsAboutToBeRemoved (const QModelIndex& parent, int start, int end);
|
||||
};
|
||||
}
|
||||
|
||||
#endif
|
38
apps/opencs/view/render/worldspacewidget.cpp
Normal file
38
apps/opencs/view/render/worldspacewidget.cpp
Normal file
|
@ -0,0 +1,38 @@
|
|||
|
||||
#include "worldspacewidget.hpp"
|
||||
|
||||
#include "../world/scenetoolmode.hpp"
|
||||
|
||||
CSVRender::WorldspaceWidget::WorldspaceWidget (QWidget *parent)
|
||||
: SceneWidget (parent)
|
||||
{}
|
||||
|
||||
void CSVRender::WorldspaceWidget::selectNavigationMode (const std::string& mode)
|
||||
{
|
||||
if (mode=="1st")
|
||||
setNavigation (&m1st);
|
||||
else if (mode=="free")
|
||||
setNavigation (&mFree);
|
||||
else if (mode=="orbit")
|
||||
setNavigation (&mOrbit);
|
||||
}
|
||||
|
||||
void CSVRender::WorldspaceWidget::selectDefaultNavigationMode()
|
||||
{
|
||||
setNavigation (&m1st);
|
||||
}
|
||||
|
||||
CSVWorld::SceneToolMode *CSVRender::WorldspaceWidget::makeNavigationSelector (
|
||||
CSVWorld::SceneToolbar *parent)
|
||||
{
|
||||
CSVWorld::SceneToolMode *tool = new CSVWorld::SceneToolMode (parent);
|
||||
|
||||
tool->addButton (":door.png", "1st"); /// \todo replace icons
|
||||
tool->addButton (":GMST.png", "free");
|
||||
tool->addButton (":Info.png", "orbit");
|
||||
|
||||
connect (tool, SIGNAL (modeChanged (const std::string&)),
|
||||
this, SLOT (selectNavigationMode (const std::string&)));
|
||||
|
||||
return tool;
|
||||
}
|
46
apps/opencs/view/render/worldspacewidget.hpp
Normal file
46
apps/opencs/view/render/worldspacewidget.hpp
Normal file
|
@ -0,0 +1,46 @@
|
|||
#ifndef OPENCS_VIEW_WORLDSPACEWIDGET_H
|
||||
#define OPENCS_VIEW_WORLDSPACEWIDGET_H
|
||||
|
||||
#include "scenewidget.hpp"
|
||||
|
||||
#include "navigation1st.hpp"
|
||||
#include "navigationfree.hpp"
|
||||
#include "navigationorbit.hpp"
|
||||
|
||||
namespace CSVWorld
|
||||
{
|
||||
class SceneToolMode;
|
||||
class SceneToolbar;
|
||||
}
|
||||
|
||||
namespace CSVRender
|
||||
{
|
||||
class WorldspaceWidget : public SceneWidget
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
CSVRender::Navigation1st m1st;
|
||||
CSVRender::NavigationFree mFree;
|
||||
CSVRender::NavigationOrbit mOrbit;
|
||||
|
||||
public:
|
||||
|
||||
WorldspaceWidget (QWidget *parent = 0);
|
||||
|
||||
CSVWorld::SceneToolMode *makeNavigationSelector (CSVWorld::SceneToolbar *parent);
|
||||
///< \important The created tool is not added to the toolbar (via addTool). Doing that
|
||||
/// is the responsibility of the calling function.
|
||||
|
||||
void selectDefaultNavigationMode();
|
||||
|
||||
private slots:
|
||||
|
||||
void selectNavigationMode (const std::string& mode);
|
||||
|
||||
signals:
|
||||
|
||||
void closeRequest();
|
||||
};
|
||||
}
|
||||
|
||||
#endif
|
|
@ -40,5 +40,5 @@ void CSVTools::ReportSubView::updateEditorSetting (const QString& key, const QSt
|
|||
|
||||
void CSVTools::ReportSubView::show (const QModelIndex& index)
|
||||
{
|
||||
focusId (mModel->getUniversalId (index.row()));
|
||||
focusId (mModel->getUniversalId (index.row()), "");
|
||||
}
|
|
@ -9,7 +9,8 @@
|
|||
|
||||
#include "../filter/filterbox.hpp"
|
||||
|
||||
#include "../render/scenewidget.hpp"
|
||||
#include "../render/pagedworldspacewidget.hpp"
|
||||
#include "../render/unpagedworldspacewidget.hpp"
|
||||
|
||||
#include "tablebottombox.hpp"
|
||||
#include "creator.hpp"
|
||||
|
@ -32,37 +33,20 @@ CSVWorld::SceneSubView::SceneSubView (const CSMWorld::UniversalId& id, CSMDoc::D
|
|||
layout2->setContentsMargins (QMargins (0, 0, 0, 0));
|
||||
|
||||
SceneToolbar *toolbar = new SceneToolbar (48, this);
|
||||
// test
|
||||
SceneToolMode *tool = new SceneToolMode (toolbar);
|
||||
tool->addButton (":door.png", "a");
|
||||
tool->addButton (":GMST.png", "b");
|
||||
tool->addButton (":Info.png", "c");
|
||||
toolbar->addTool (tool);
|
||||
toolbar->addTool (new SceneToolMode (toolbar));
|
||||
toolbar->addTool (new SceneToolMode (toolbar));
|
||||
toolbar->addTool (new SceneToolMode (toolbar));
|
||||
|
||||
if (id.getId()[0]=='#')
|
||||
mScene = new CSVRender::PagedWorldspaceWidget (this);
|
||||
else
|
||||
mScene = new CSVRender::UnpagedWorldspaceWidget (id.getId(), document, this);
|
||||
|
||||
SceneToolMode *tool = mScene->makeNavigationSelector (toolbar);
|
||||
toolbar->addTool (tool);
|
||||
|
||||
layout2->addWidget (toolbar, 0);
|
||||
|
||||
// temporarily disable OGRE-integration (need to fix path problem first)
|
||||
#if 0
|
||||
CSVRender::SceneWidget* sceneWidget = new CSVRender::SceneWidget(this);
|
||||
|
||||
layout2->addWidget (sceneWidget, 1);
|
||||
layout2->addWidget (mScene, 1);
|
||||
|
||||
layout->insertLayout (0, layout2, 1);
|
||||
#endif
|
||||
/// \todo replace with rendering widget
|
||||
QPalette palette2 (palette());
|
||||
palette2.setColor (QPalette::Background, Qt::white);
|
||||
QLabel *placeholder = new QLabel ("Here goes the 3D scene", this);
|
||||
placeholder->setAutoFillBackground (true);
|
||||
placeholder->setPalette (palette2);
|
||||
placeholder->setAlignment (Qt::AlignHCenter);
|
||||
|
||||
layout2->addWidget (placeholder, 1);
|
||||
|
||||
layout->insertLayout (0, layout2, 1);
|
||||
|
||||
|
||||
CSVFilter::FilterBox *filterBox = new CSVFilter::FilterBox (document.getData(), this);
|
||||
|
||||
|
@ -73,6 +57,10 @@ toolbar->addTool (new SceneToolMode (toolbar));
|
|||
widget->setLayout (layout);
|
||||
|
||||
setWidget (widget);
|
||||
|
||||
mScene->selectDefaultNavigationMode();
|
||||
|
||||
connect (mScene, SIGNAL (closeRequest()), this, SLOT (closeRequest()));
|
||||
}
|
||||
|
||||
void CSVWorld::SceneSubView::setEditLock (bool locked)
|
||||
|
@ -91,3 +79,8 @@ void CSVWorld::SceneSubView::setStatusBar (bool show)
|
|||
{
|
||||
mBottom->setStatusBar (show);
|
||||
}
|
||||
|
||||
void CSVWorld::SceneSubView::closeRequest()
|
||||
{
|
||||
deleteLater();
|
||||
}
|
|
@ -10,6 +10,11 @@ namespace CSMDoc
|
|||
class Document;
|
||||
}
|
||||
|
||||
namespace CSVRender
|
||||
{
|
||||
class WorldspaceWidget;
|
||||
}
|
||||
|
||||
namespace CSVWorld
|
||||
{
|
||||
class Table;
|
||||
|
@ -21,6 +26,7 @@ namespace CSVWorld
|
|||
Q_OBJECT
|
||||
|
||||
TableBottomBox *mBottom;
|
||||
CSVRender::WorldspaceWidget *mScene;
|
||||
|
||||
public:
|
||||
|
||||
|
@ -31,6 +37,10 @@ namespace CSVWorld
|
|||
virtual void updateEditorSetting (const QString& key, const QString& value);
|
||||
|
||||
virtual void setStatusBar (bool show);
|
||||
|
||||
private slots:
|
||||
|
||||
void closeRequest();
|
||||
};
|
||||
}
|
||||
|
||||
|
|
|
@ -2,7 +2,6 @@
|
|||
#include "table.hpp"
|
||||
|
||||
#include <QHeaderView>
|
||||
|
||||
#include <QAction>
|
||||
#include <QApplication>
|
||||
#include <QMenu>
|
||||
|
@ -10,6 +9,8 @@
|
|||
#include <QString>
|
||||
#include <QtCore/qnamespace.h>
|
||||
|
||||
#include "../../model/doc/document.hpp"
|
||||
|
||||
#include "../../model/world/data.hpp"
|
||||
#include "../../model/world/commands.hpp"
|
||||
#include "../../model/world/idtableproxymodel.hpp"
|
||||
|
@ -35,8 +36,21 @@ void CSVWorld::Table::contextMenuEvent (QContextMenuEvent *event)
|
|||
if (selectedRows.size()==1)
|
||||
{
|
||||
menu.addAction (mEditAction);
|
||||
|
||||
if (mCreateAction)
|
||||
menu.addAction(mCloneAction);
|
||||
|
||||
if (mModel->getViewing()!=CSMWorld::IdTable::Viewing_None)
|
||||
{
|
||||
int row = selectedRows.begin()->row();
|
||||
|
||||
row = mProxyModel->mapToSource (mProxyModel->index (row, 0)).row();
|
||||
|
||||
CSMWorld::UniversalId id = mModel->view (row).first;
|
||||
|
||||
if (!mDocument.getData().getCells().getRecord (id.getId()).isDeleted())
|
||||
menu.addAction (mViewAction);
|
||||
}
|
||||
}
|
||||
|
||||
if (mCreateAction)
|
||||
|
@ -162,11 +176,12 @@ std::vector<std::string> CSVWorld::Table::listDeletableSelectedIds() const
|
|||
return deletableIds;
|
||||
}
|
||||
|
||||
CSVWorld::Table::Table (const CSMWorld::UniversalId& id, CSMWorld::Data& data, QUndoStack& undoStack,
|
||||
bool createAndDelete, bool sorting, const CSMDoc::Document& document)
|
||||
: mUndoStack (undoStack), mCreateAction (0), mCloneAction(0), mEditLock (false), mRecordStatusDisplay (0), mDocument(document)
|
||||
CSVWorld::Table::Table (const CSMWorld::UniversalId& id,
|
||||
bool createAndDelete, bool sorting, CSMDoc::Document& document)
|
||||
: mCreateAction (0), mCloneAction(0), mEditLock (false), mRecordStatusDisplay (0),
|
||||
mDocument (document)
|
||||
{
|
||||
mModel = &dynamic_cast<CSMWorld::IdTable&> (*data.getTableModel (id));
|
||||
mModel = &dynamic_cast<CSMWorld::IdTable&> (*mDocument.getData().getTableModel (id));
|
||||
|
||||
mProxyModel = new CSMWorld::IdTableProxyModel (this);
|
||||
mProxyModel->setSourceModel (mModel);
|
||||
|
@ -190,7 +205,7 @@ CSVWorld::Table::Table (const CSMWorld::UniversalId& id, CSMWorld::Data& data, Q
|
|||
mModel->headerData (i, Qt::Horizontal, CSMWorld::ColumnBase::Role_Display).toInt());
|
||||
|
||||
CommandDelegate *delegate = CommandDelegateFactoryCollection::get().makeDelegate (display,
|
||||
undoStack, this);
|
||||
mDocument.getUndoStack(), this);
|
||||
|
||||
mDelegates.push_back (delegate);
|
||||
setItemDelegateForColumn (i, delegate);
|
||||
|
@ -230,6 +245,10 @@ CSVWorld::Table::Table (const CSMWorld::UniversalId& id, CSMWorld::Data& data, Q
|
|||
connect (mMoveDownAction, SIGNAL (triggered()), this, SLOT (moveDownRecord()));
|
||||
addAction (mMoveDownAction);
|
||||
|
||||
mViewAction = new QAction (tr ("View"), this);
|
||||
connect (mViewAction, SIGNAL (triggered()), this, SLOT (viewRecord()));
|
||||
addAction (mViewAction);
|
||||
|
||||
connect (mProxyModel, SIGNAL (rowsInserted (const QModelIndex&, int, int)),
|
||||
this, SLOT (tableSizeUpdate()));
|
||||
|
||||
|
@ -268,13 +287,13 @@ void CSVWorld::Table::revertRecord()
|
|||
if (revertableIds.size()>0)
|
||||
{
|
||||
if (revertableIds.size()>1)
|
||||
mUndoStack.beginMacro (tr ("Revert multiple records"));
|
||||
mDocument.getUndoStack().beginMacro (tr ("Revert multiple records"));
|
||||
|
||||
for (std::vector<std::string>::const_iterator iter (revertableIds.begin()); iter!=revertableIds.end(); ++iter)
|
||||
mUndoStack.push (new CSMWorld::RevertCommand (*mModel, *iter));
|
||||
mDocument.getUndoStack().push (new CSMWorld::RevertCommand (*mModel, *iter));
|
||||
|
||||
if (revertableIds.size()>1)
|
||||
mUndoStack.endMacro();
|
||||
mDocument.getUndoStack().endMacro();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -288,13 +307,13 @@ void CSVWorld::Table::deleteRecord()
|
|||
if (deletableIds.size()>0)
|
||||
{
|
||||
if (deletableIds.size()>1)
|
||||
mUndoStack.beginMacro (tr ("Delete multiple records"));
|
||||
mDocument.getUndoStack().beginMacro (tr ("Delete multiple records"));
|
||||
|
||||
for (std::vector<std::string>::const_iterator iter (deletableIds.begin()); iter!=deletableIds.end(); ++iter)
|
||||
mUndoStack.push (new CSMWorld::DeleteCommand (*mModel, *iter));
|
||||
mDocument.getUndoStack().push (new CSMWorld::DeleteCommand (*mModel, *iter));
|
||||
|
||||
if (deletableIds.size()>1)
|
||||
mUndoStack.endMacro();
|
||||
mDocument.getUndoStack().endMacro();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -306,7 +325,7 @@ void CSVWorld::Table::editRecord()
|
|||
QModelIndexList selectedRows = selectionModel()->selectedRows();
|
||||
|
||||
if (selectedRows.size()==1)
|
||||
emit editRequest (selectedRows.begin()->row());
|
||||
emit editRequest (getUniversalId (selectedRows.begin()->row()), "");
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -347,7 +366,7 @@ void CSVWorld::Table::moveUpRecord()
|
|||
for (int i=1; i<row2-row; ++i)
|
||||
newOrder[i] = i;
|
||||
|
||||
mUndoStack.push (new CSMWorld::ReorderRowsCommand (*mModel, row, newOrder));
|
||||
mDocument.getUndoStack().push (new CSMWorld::ReorderRowsCommand (*mModel, row, newOrder));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -376,11 +395,28 @@ void CSVWorld::Table::moveDownRecord()
|
|||
for (int i=1; i<row2-row; ++i)
|
||||
newOrder[i] = i;
|
||||
|
||||
mUndoStack.push (new CSMWorld::ReorderRowsCommand (*mModel, row, newOrder));
|
||||
mDocument.getUndoStack().push (new CSMWorld::ReorderRowsCommand (*mModel, row, newOrder));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void CSVWorld::Table::viewRecord()
|
||||
{
|
||||
QModelIndexList selectedRows = selectionModel()->selectedRows();
|
||||
|
||||
if (selectedRows.size()==1)
|
||||
{
|
||||
int row =selectedRows.begin()->row();
|
||||
|
||||
row = mProxyModel->mapToSource (mProxyModel->index (row, 0)).row();
|
||||
|
||||
std::pair<CSMWorld::UniversalId, std::string> params = mModel->view (row);
|
||||
|
||||
if (params.first.getType()!=CSMWorld::UniversalId::Type_None)
|
||||
emit editRequest (params.first, params.second);
|
||||
}
|
||||
}
|
||||
|
||||
void CSVWorld::Table::updateEditorSetting (const QString &settingName, const QString &settingValue)
|
||||
{
|
||||
int columns = mModel->columnCount();
|
||||
|
@ -517,7 +553,7 @@ void CSVWorld::Table::dropEvent(QDropEvent *event)
|
|||
std::auto_ptr<CSMWorld::ModifyCommand> command (new CSMWorld::ModifyCommand
|
||||
(*mProxyModel, index, QVariant (QString::fromUtf8 (record.getId().c_str()))));
|
||||
|
||||
mUndoStack.push (command.release());
|
||||
mDocument.getUndoStack().push (command.release());
|
||||
}
|
||||
} //TODO handle drops from different document
|
||||
}
|
||||
|
|
|
@ -10,13 +10,14 @@
|
|||
#include "../../model/filter/node.hpp"
|
||||
#include "../../model/world/columnbase.hpp"
|
||||
|
||||
namespace CSMDoc {
|
||||
class Document;
|
||||
}
|
||||
|
||||
class QUndoStack;
|
||||
class QAction;
|
||||
|
||||
namespace CSMDoc
|
||||
{
|
||||
class Document;
|
||||
}
|
||||
|
||||
namespace CSMWorld
|
||||
{
|
||||
class Data;
|
||||
|
@ -35,7 +36,6 @@ namespace CSVWorld
|
|||
Q_OBJECT
|
||||
|
||||
std::vector<CommandDelegate *> mDelegates;
|
||||
QUndoStack& mUndoStack;
|
||||
QAction *mEditAction;
|
||||
QAction *mCreateAction;
|
||||
QAction *mCloneAction;
|
||||
|
@ -43,14 +43,12 @@ namespace CSVWorld
|
|||
QAction *mDeleteAction;
|
||||
QAction *mMoveUpAction;
|
||||
QAction *mMoveDownAction;
|
||||
QAction *mViewAction;
|
||||
CSMWorld::IdTableProxyModel *mProxyModel;
|
||||
CSMWorld::IdTable *mModel;
|
||||
bool mEditLock;
|
||||
int mRecordStatusDisplay;
|
||||
|
||||
/// \brief This variable is used exclusivly for checking if dropEvents came from the same document. Most likely you
|
||||
/// should NOT use it for anything else.
|
||||
const CSMDoc::Document& mDocument;
|
||||
CSMDoc::Document& mDocument;
|
||||
|
||||
private:
|
||||
|
||||
|
@ -70,9 +68,8 @@ namespace CSVWorld
|
|||
|
||||
public:
|
||||
|
||||
Table (const CSMWorld::UniversalId& id, CSMWorld::Data& data, QUndoStack& undoStack, bool createAndDelete,
|
||||
bool sorting, const CSMDoc::Document& document);
|
||||
|
||||
Table (const CSMWorld::UniversalId& id, bool createAndDelete,
|
||||
bool sorting, CSMDoc::Document& document);
|
||||
///< \param createAndDelete Allow creation and deletion of records.
|
||||
/// \param sorting Allow changing order of rows in the view via column headers.
|
||||
|
||||
|
@ -86,7 +83,7 @@ namespace CSVWorld
|
|||
|
||||
signals:
|
||||
|
||||
void editRequest (int row);
|
||||
void editRequest (const CSMWorld::UniversalId& id, const std::string& hint);
|
||||
|
||||
void selectionSizeChanged (int size);
|
||||
|
||||
|
@ -112,6 +109,8 @@ namespace CSVWorld
|
|||
|
||||
void moveDownRecord();
|
||||
|
||||
void viewRecord();
|
||||
|
||||
public slots:
|
||||
|
||||
void tableSizeUpdate();
|
||||
|
|
|
@ -24,7 +24,7 @@ CSVWorld::TableSubView::TableSubView (const CSMWorld::UniversalId& id, CSMDoc::D
|
|||
new TableBottomBox (creatorFactory, document.getData(), document.getUndoStack(), id, this), 0);
|
||||
|
||||
layout->insertWidget (0, mTable =
|
||||
new Table (id, document.getData(), document.getUndoStack(), mBottom->canCreateAndDelete(), sorting, document), 2);
|
||||
new Table (id, mBottom->canCreateAndDelete(), sorting, document), 2);
|
||||
|
||||
CSVFilter::FilterBox *filterBox = new CSVFilter::FilterBox (document.getData(), this);
|
||||
|
||||
|
@ -36,7 +36,8 @@ CSVWorld::TableSubView::TableSubView (const CSMWorld::UniversalId& id, CSMDoc::D
|
|||
|
||||
setWidget (widget);
|
||||
|
||||
connect (mTable, SIGNAL (editRequest (int)), this, SLOT (editRequest (int)));
|
||||
connect (mTable, SIGNAL (editRequest (const CSMWorld::UniversalId&, const std::string&)),
|
||||
this, SLOT (editRequest (const CSMWorld::UniversalId&, const std::string&)));
|
||||
|
||||
connect (mTable, SIGNAL (selectionSizeChanged (int)),
|
||||
mBottom, SLOT (selectionSizeChanged (int)));
|
||||
|
@ -81,9 +82,9 @@ void CSVWorld::TableSubView::setEditLock (bool locked)
|
|||
mBottom->setEditLock (locked);
|
||||
}
|
||||
|
||||
void CSVWorld::TableSubView::editRequest (int row)
|
||||
void CSVWorld::TableSubView::editRequest (const CSMWorld::UniversalId& id, const std::string& hint)
|
||||
{
|
||||
focusId (mTable->getUniversalId (row));
|
||||
focusId (id, hint);
|
||||
}
|
||||
|
||||
void CSVWorld::TableSubView::updateEditorSetting(const QString &settingName, const QString &settingValue)
|
||||
|
|
|
@ -53,7 +53,7 @@ namespace CSVWorld
|
|||
|
||||
private slots:
|
||||
|
||||
void editRequest (int row);
|
||||
void editRequest (const CSMWorld::UniversalId& id, const std::string& hint);
|
||||
void cloneRequest (const CSMWorld::UniversalId& toClone);
|
||||
void createFilterRequest(std::vector< CSMWorld::UniversalId >& types,
|
||||
Qt::DropAction action);
|
||||
|
|
|
@ -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
|
||||
terrainstorage renderconst effectmanager weaponanimation
|
||||
)
|
||||
|
||||
add_openmw_dir (mwinput
|
||||
|
@ -159,3 +159,10 @@ if (BUILD_WITH_CODE_COVERAGE)
|
|||
add_definitions (--coverage)
|
||||
target_link_libraries(openmw gcov)
|
||||
endif()
|
||||
|
||||
if (MSVC)
|
||||
# Debug version needs increased number of sections beyond 2^16
|
||||
if (CMAKE_CL_64)
|
||||
set (CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} /bigobj")
|
||||
endif (CMAKE_CL_64)
|
||||
endif (MSVC)
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
#include "engine.hpp"
|
||||
|
||||
#include <stdexcept>
|
||||
#include <iomanip>
|
||||
|
||||
#include <OgreRoot.h>
|
||||
#include <OgreRenderWindow.h>
|
||||
|
@ -403,7 +404,7 @@ void OMW::Engine::prepareEngine (Settings::Manager & settings)
|
|||
// Create the world
|
||||
mEnvironment.setWorld( new MWWorld::World (*mOgre, mFileCollections, mContentFiles,
|
||||
mResDir, mCfgMgr.getCachePath(), mEncoder, mFallbackMap,
|
||||
mActivationDistanceOverride));
|
||||
mActivationDistanceOverride, mCellName));
|
||||
MWBase::Environment::get().getWorld()->setupPlayer();
|
||||
input->setPlayer(&mEnvironment.getWorld()->getPlayer());
|
||||
|
||||
|
@ -439,31 +440,6 @@ void OMW::Engine::prepareEngine (Settings::Manager & settings)
|
|||
mechanics->buildPlayer();
|
||||
window->updatePlayer();
|
||||
|
||||
// load cell
|
||||
ESM::Position pos;
|
||||
MWBase::World *world = MWBase::Environment::get().getWorld();
|
||||
|
||||
if (!mCellName.empty())
|
||||
{
|
||||
if (world->findExteriorPosition(mCellName, pos)) {
|
||||
world->changeToExteriorCell (pos);
|
||||
}
|
||||
else {
|
||||
world->findInteriorPosition(mCellName, pos);
|
||||
world->changeToInteriorCell (mCellName, pos);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
pos.pos[0] = pos.pos[1] = pos.pos[2] = 0;
|
||||
pos.rot[0] = pos.rot[1] = pos.pos[2] = 0;
|
||||
world->changeToExteriorCell (pos);
|
||||
}
|
||||
|
||||
Ogre::FrameEvent event;
|
||||
event.timeSinceLastEvent = 0;
|
||||
event.timeSinceLastFrame = 0;
|
||||
frameRenderingQueued(event);
|
||||
mOgre->getRoot()->addFrameListener (this);
|
||||
|
||||
// scripts
|
||||
|
@ -501,15 +477,15 @@ void OMW::Engine::go()
|
|||
// Play some good 'ol tunes
|
||||
MWBase::Environment::get().getSoundManager()->playPlaylist(std::string("Explore"));
|
||||
|
||||
if (!mStartupScript.empty())
|
||||
MWBase::Environment::get().getWindowManager()->executeInConsole (mStartupScript);
|
||||
|
||||
// start in main menu
|
||||
if (!mSkipMenu)
|
||||
MWBase::Environment::get().getWindowManager()->pushGuiMode (MWGui::GM_MainMenu);
|
||||
else
|
||||
MWBase::Environment::get().getStateManager()->newGame (true);
|
||||
|
||||
if (!mStartupScript.empty())
|
||||
MWBase::Environment::get().getWindowManager()->executeInConsole (mStartupScript);
|
||||
|
||||
// Start the main rendering loop
|
||||
while (!mEnvironment.get().getStateManager()->hasQuitRequest())
|
||||
Ogre::Root::getSingleton().renderOneFrame();
|
||||
|
@ -621,4 +597,4 @@ void OMW::Engine::setActivationDistanceOverride (int distance)
|
|||
void OMW::Engine::setWarningsMode (int mode)
|
||||
{
|
||||
mWarningsMode = mode;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -3,7 +3,7 @@
|
|||
|
||||
#include <string>
|
||||
|
||||
#include <libs/platform/stdint.h>
|
||||
#include <stdint.h>
|
||||
|
||||
namespace ESM
|
||||
{
|
||||
|
|
|
@ -20,6 +20,9 @@ namespace MWBase
|
|||
|
||||
InputManager() {}
|
||||
|
||||
/// Clear all savegame-specific data
|
||||
virtual void clear() = 0;
|
||||
|
||||
virtual ~InputManager() {}
|
||||
|
||||
virtual void update(float dt, bool loading) = 0;
|
||||
|
|
|
@ -5,7 +5,7 @@
|
|||
#include <deque>
|
||||
#include <map>
|
||||
|
||||
#include <libs/platform/stdint.h>
|
||||
#include <stdint.h>
|
||||
|
||||
#include "../mwdialogue/journalentry.hpp"
|
||||
#include "../mwdialogue/topic.hpp"
|
||||
|
|
|
@ -101,7 +101,8 @@ namespace MWBase
|
|||
|
||||
virtual ~World() {}
|
||||
|
||||
virtual void startNewGame() = 0;
|
||||
virtual void startNewGame (bool bypass) = 0;
|
||||
///< \param bypass Bypass regular game start.
|
||||
|
||||
virtual void clear() = 0;
|
||||
|
||||
|
@ -274,7 +275,7 @@ namespace MWBase
|
|||
virtual void moveObject (const MWWorld::Ptr& ptr, float x, float y, float z) = 0;
|
||||
|
||||
virtual void
|
||||
moveObject(const MWWorld::Ptr &ptr, MWWorld::CellStore &newCell, float x, float y, float z) = 0;
|
||||
moveObject(const MWWorld::Ptr &ptr, MWWorld::CellStore* newCell, float x, float y, float z) = 0;
|
||||
|
||||
virtual void scaleObject (const MWWorld::Ptr& ptr, float scale) = 0;
|
||||
|
||||
|
@ -282,7 +283,7 @@ namespace MWBase
|
|||
|
||||
virtual void localRotateObject (const MWWorld::Ptr& ptr, float x, float y, float z) = 0;
|
||||
|
||||
virtual MWWorld::Ptr safePlaceObject(const MWWorld::Ptr& ptr,MWWorld::CellStore &Cell,ESM::Position pos) = 0;
|
||||
virtual MWWorld::Ptr safePlaceObject(const MWWorld::Ptr& ptr, MWWorld::CellStore* cell, ESM::Position pos) = 0;
|
||||
///< place an object in a "safe" location (ie not in the void, etc).
|
||||
|
||||
virtual void indexToPosition (int cellX, int cellY, float &x, float &y, bool centre = false)
|
||||
|
@ -464,8 +465,10 @@ namespace MWBase
|
|||
|
||||
virtual void castSpell (const MWWorld::Ptr& actor) = 0;
|
||||
|
||||
virtual void launchProjectile (const std::string& id, bool stack, const ESM::EffectList& effects,
|
||||
virtual void launchMagicBolt (const std::string& id, bool stack, const ESM::EffectList& effects,
|
||||
const MWWorld::Ptr& actor, const std::string& sourceName) = 0;
|
||||
virtual void launchProjectile (MWWorld::Ptr actor, MWWorld::Ptr projectile,
|
||||
const Ogre::Vector3& worldPos, const Ogre::Quaternion& orient, MWWorld::Ptr bow, float speed) = 0;
|
||||
|
||||
virtual const std::vector<std::string>& getContentFiles() const = 0;
|
||||
|
||||
|
|
|
@ -7,6 +7,7 @@
|
|||
#include "../mwmechanics/creaturestats.hpp"
|
||||
#include "../mwmechanics/magiceffects.hpp"
|
||||
#include "../mwmechanics/movement.hpp"
|
||||
#include "../mwmechanics/disease.hpp"
|
||||
#include "../mwmechanics/spellcasting.hpp"
|
||||
|
||||
#include "../mwbase/environment.hpp"
|
||||
|
@ -243,15 +244,7 @@ namespace MWClass
|
|||
|
||||
Ogre::Vector3 hitPosition = result.second;
|
||||
|
||||
MWMechanics::CreatureStats &otherstats = victim.getClass().getCreatureStats(victim);
|
||||
const MWMechanics::MagicEffects &mageffects = stats.getMagicEffects();
|
||||
float hitchance = ref->mBase->mData.mCombat +
|
||||
(stats.getAttribute(ESM::Attribute::Agility).getModified() / 5.0f) +
|
||||
(stats.getAttribute(ESM::Attribute::Luck).getModified() / 10.0f);
|
||||
hitchance *= stats.getFatigueTerm();
|
||||
hitchance += mageffects.get(ESM::MagicEffect::FortifyAttack).mMagnitude -
|
||||
mageffects.get(ESM::MagicEffect::Blind).mMagnitude;
|
||||
hitchance -= otherstats.getEvasion();
|
||||
float hitchance = MWMechanics::getHitChance(ptr, victim, ref->mBase->mData.mCombat);
|
||||
|
||||
if((::rand()/(RAND_MAX+1.0)) > hitchance/100.0f)
|
||||
{
|
||||
|
@ -334,6 +327,8 @@ namespace MWClass
|
|||
if (damage > 0)
|
||||
MWBase::Environment::get().getWorld()->spawnBloodEffect(victim, hitPosition);
|
||||
|
||||
MWMechanics::diseaseContact(victim, ptr);
|
||||
|
||||
victim.getClass().onHit(victim, damage, true, weapon, ptr, true);
|
||||
}
|
||||
|
||||
|
@ -530,7 +525,7 @@ namespace MWClass
|
|||
float moveSpeed;
|
||||
if(normalizedEncumbrance >= 1.0f)
|
||||
moveSpeed = 0.0f;
|
||||
else if(isFlying(ptr) || (mageffects.get(ESM::MagicEffect::Levitate).mMagnitude > 0 &&
|
||||
else if(canFly(ptr) || (mageffects.get(ESM::MagicEffect::Levitate).mMagnitude > 0 &&
|
||||
world->isLevitationEnabled()))
|
||||
{
|
||||
float flySpeed = 0.01f*(stats.getAttribute(ESM::Attribute::Speed).getModified() +
|
||||
|
@ -683,7 +678,15 @@ namespace MWClass
|
|||
return MWWorld::Ptr(&cell.get<ESM::Creature>().insert(*ref), &cell);
|
||||
}
|
||||
|
||||
bool Creature::isFlying(const MWWorld::Ptr &ptr) const
|
||||
bool Creature::isBipedal(const MWWorld::Ptr &ptr) const
|
||||
{
|
||||
MWWorld::LiveCellRef<ESM::Creature> *ref =
|
||||
ptr.get<ESM::Creature>();
|
||||
|
||||
return ref->mBase->mFlags & ESM::Creature::Bipedal;
|
||||
}
|
||||
|
||||
bool Creature::canFly(const MWWorld::Ptr &ptr) const
|
||||
{
|
||||
MWWorld::LiveCellRef<ESM::Creature> *ref =
|
||||
ptr.get<ESM::Creature>();
|
||||
|
@ -691,6 +694,22 @@ namespace MWClass
|
|||
return ref->mBase->mFlags & ESM::Creature::Flies;
|
||||
}
|
||||
|
||||
bool Creature::canSwim(const MWWorld::Ptr &ptr) const
|
||||
{
|
||||
MWWorld::LiveCellRef<ESM::Creature> *ref =
|
||||
ptr.get<ESM::Creature>();
|
||||
|
||||
return ref->mBase->mFlags & ESM::Creature::Swims;
|
||||
}
|
||||
|
||||
bool Creature::canWalk(const MWWorld::Ptr &ptr) const
|
||||
{
|
||||
MWWorld::LiveCellRef<ESM::Creature> *ref =
|
||||
ptr.get<ESM::Creature>();
|
||||
|
||||
return ref->mBase->mFlags & ESM::Creature::Walks;
|
||||
}
|
||||
|
||||
int Creature::getSndGenTypeFromName(const MWWorld::Ptr &ptr, const std::string &name)
|
||||
{
|
||||
if(name == "left")
|
||||
|
|
|
@ -124,7 +124,10 @@ namespace MWClass
|
|||
return true;
|
||||
}
|
||||
|
||||
virtual bool isFlying (const MWWorld::Ptr &ptr) const;
|
||||
virtual bool isBipedal (const MWWorld::Ptr &ptr) const;
|
||||
virtual bool canFly (const MWWorld::Ptr &ptr) const;
|
||||
virtual bool canSwim (const MWWorld::Ptr &ptr) const;
|
||||
virtual bool canWalk (const MWWorld::Ptr &ptr) const;
|
||||
|
||||
virtual int getSkill(const MWWorld::Ptr &ptr, int skill) const;
|
||||
|
||||
|
|
|
@ -57,7 +57,7 @@ namespace MWClass
|
|||
MWWorld::ManualRef ref(store, id);
|
||||
ref.getPtr().getCellRef().mPos = ptr.getCellRef().mPos;
|
||||
// TODO: hold on to this for respawn purposes later
|
||||
MWBase::Environment::get().getWorld()->safePlaceObject(ref.getPtr(), *ptr.getCell() , ptr.getCellRef().mPos);
|
||||
MWBase::Environment::get().getWorld()->safePlaceObject(ref.getPtr(), ptr.getCell() , ptr.getCellRef().mPos);
|
||||
}
|
||||
|
||||
ptr.getRefData().setCustomData(data.release());
|
||||
|
|
|
@ -498,15 +498,7 @@ namespace MWClass
|
|||
if(!weapon.isEmpty())
|
||||
weapskill = get(weapon).getEquipmentSkill(weapon);
|
||||
|
||||
MWMechanics::NpcStats &stats = getNpcStats(ptr);
|
||||
const MWMechanics::MagicEffects &mageffects = stats.getMagicEffects();
|
||||
float hitchance = stats.getSkill(weapskill).getModified() +
|
||||
(stats.getAttribute(ESM::Attribute::Agility).getModified() / 5.0f) +
|
||||
(stats.getAttribute(ESM::Attribute::Luck).getModified() / 10.0f);
|
||||
hitchance *= stats.getFatigueTerm();
|
||||
hitchance += mageffects.get(ESM::MagicEffect::FortifyAttack).mMagnitude -
|
||||
mageffects.get(ESM::MagicEffect::Blind).mMagnitude;
|
||||
hitchance -= otherstats.getEvasion();
|
||||
float hitchance = MWMechanics::getHitChance(ptr, victim, ptr.getClass().getSkill(ptr, weapskill));
|
||||
|
||||
if((::rand()/(RAND_MAX+1.0)) > hitchance/100.0f)
|
||||
{
|
||||
|
@ -516,6 +508,7 @@ namespace MWClass
|
|||
|
||||
bool healthdmg;
|
||||
float damage = 0.0f;
|
||||
MWMechanics::NpcStats &stats = getNpcStats(ptr);
|
||||
if(!weapon.isEmpty())
|
||||
{
|
||||
const bool weaphashealth = get(weapon).hasItemHealth(weapon);
|
||||
|
@ -615,6 +608,8 @@ namespace MWClass
|
|||
if (healthdmg && damage > 0)
|
||||
MWBase::Environment::get().getWorld()->spawnBloodEffect(victim, hitPosition);
|
||||
|
||||
MWMechanics::diseaseContact(victim, ptr);
|
||||
|
||||
othercls.onHit(victim, damage, healthdmg, weapon, ptr, true);
|
||||
}
|
||||
|
||||
|
@ -648,9 +643,6 @@ namespace MWClass
|
|||
ptr.getRefData().getLocals().setVarByInt(script, "onpchitme", 1);
|
||||
}
|
||||
|
||||
if (!attacker.isEmpty())
|
||||
MWMechanics::diseaseContact(ptr, attacker);
|
||||
|
||||
if (damage > 0.0f && !object.isEmpty())
|
||||
MWMechanics::resistNormalWeapon(ptr, attacker, object, damage);
|
||||
|
||||
|
@ -681,12 +673,7 @@ namespace MWClass
|
|||
else
|
||||
getCreatureStats(ptr).setHitRecovery(true); // Is this supposed to always occur?
|
||||
|
||||
if(object.isEmpty())
|
||||
{
|
||||
if(ishealth)
|
||||
damage /= std::min(1.0f + getArmorRating(ptr)/std::max(1.0f, damage), 4.0f);
|
||||
}
|
||||
else if(ishealth)
|
||||
if(ishealth)
|
||||
{
|
||||
// Hit percentages:
|
||||
// cuirass = 30%
|
||||
|
|
|
@ -6,7 +6,7 @@
|
|||
#include "MyGUI_TextureUtility.h"
|
||||
#include "MyGUI_FactoryManager.h"
|
||||
|
||||
#include <platform/stdint.h>
|
||||
#include <stdint.h>
|
||||
#include <boost/function.hpp>
|
||||
#include <boost/shared_ptr.hpp>
|
||||
#include <boost/make_shared.hpp>
|
||||
|
|
|
@ -5,7 +5,7 @@
|
|||
#include "MyGUI_Widget.h"
|
||||
|
||||
#include <functional>
|
||||
#include <platform/stdint.h>
|
||||
#include <stdint.h>
|
||||
#include <boost/function.hpp>
|
||||
#include <boost/shared_ptr.hpp>
|
||||
|
||||
|
|
|
@ -1,5 +1,7 @@
|
|||
#include "enchantingdialog.hpp"
|
||||
|
||||
#include <iomanip>
|
||||
|
||||
#include <boost/lexical_cast.hpp>
|
||||
|
||||
#include "../mwbase/environment.hpp"
|
||||
|
|
|
@ -604,15 +604,22 @@ namespace MWGui
|
|||
mEffectBox->setPosition((viewSize.width - mEffectBoxBaseRight) - mEffectBox->getWidth() + effectsDx, mEffectBox->getTop());
|
||||
}
|
||||
|
||||
void HUD::updateEnemyHealthBar()
|
||||
{
|
||||
MWMechanics::CreatureStats& stats = MWWorld::Class::get(mEnemy).getCreatureStats(mEnemy);
|
||||
mEnemyHealth->setProgressRange(100);
|
||||
// Health is usually cast to int before displaying. Actors die whenever they are < 1 health.
|
||||
// Therefore any value < 1 should show as an empty health bar. We do the same in statswindow :)
|
||||
mEnemyHealth->setProgressPosition(int(stats.getHealth().getCurrent()) / stats.getHealth().getModified() * 100);
|
||||
}
|
||||
|
||||
void HUD::update()
|
||||
{
|
||||
mSpellIcons->updateWidgets(mEffectBox, true);
|
||||
|
||||
if (!mEnemy.isEmpty() && mEnemyHealth->getVisible())
|
||||
{
|
||||
MWMechanics::CreatureStats& stats = MWWorld::Class::get(mEnemy).getCreatureStats(mEnemy);
|
||||
mEnemyHealth->setProgressRange(100);
|
||||
mEnemyHealth->setProgressPosition(stats.getHealth().getCurrent() / stats.getHealth().getModified() * 100);
|
||||
updateEnemyHealthBar();
|
||||
}
|
||||
|
||||
if (mIsDrowning)
|
||||
|
@ -629,9 +636,7 @@ namespace MWGui
|
|||
if (!mEnemyHealth->getVisible())
|
||||
mWeaponSpellBox->setPosition(mWeaponSpellBox->getPosition() - MyGUI::IntPoint(0,20));
|
||||
mEnemyHealth->setVisible(true);
|
||||
MWMechanics::CreatureStats& stats = MWWorld::Class::get(mEnemy).getCreatureStats(mEnemy);
|
||||
mEnemyHealth->setProgressRange(100);
|
||||
mEnemyHealth->setProgressPosition(stats.getHealth().getCurrent() / stats.getHealth().getModified() * 100);
|
||||
updateEnemyHealthBar();
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -112,6 +112,8 @@ namespace MWGui
|
|||
void onMagicClicked(MyGUI::Widget* _sender);
|
||||
void onMapClicked(MyGUI::Widget* _sender);
|
||||
|
||||
void updateEnemyHealthBar();
|
||||
|
||||
void updatePositions();
|
||||
};
|
||||
}
|
||||
|
|
|
@ -514,6 +514,9 @@ namespace MWGui
|
|||
|
||||
void InventoryWindow::pickUpObject (MWWorld::Ptr object)
|
||||
{
|
||||
// If the inventory is not yet enabled, don't pick anything up
|
||||
if (!MWBase::Environment::get().getWindowManager()->isAllowed(GW_Inventory))
|
||||
return;
|
||||
// make sure the object is of a type that can be picked up
|
||||
std::string type = object.getTypeName();
|
||||
if ( (type != typeid(ESM::Apparatus).name())
|
||||
|
|
|
@ -206,9 +206,9 @@ struct JournalViewModelImpl : JournalViewModel
|
|||
|
||||
const MWDialogue::Quest& quest = i->second;
|
||||
// Unfortunately Morrowind.esm has no quest names, since the quest book was added with tribunal.
|
||||
if (quest.getName().empty())
|
||||
visitor (reinterpret_cast <QuestId> (&i->second), toUtf8Span (i->first));
|
||||
else
|
||||
// Note that even with Tribunal, some quests still don't have quest names. I'm assuming those are not supposed
|
||||
// to appear in the quest book.
|
||||
if (!quest.getName().empty())
|
||||
visitor (reinterpret_cast <QuestId> (&i->second), toUtf8Span (quest.getName()));
|
||||
}
|
||||
}
|
||||
|
|
|
@ -4,7 +4,7 @@
|
|||
#include <string>
|
||||
#include <memory>
|
||||
#include <functional>
|
||||
#include <platform/stdint.h>
|
||||
#include <stdint.h>
|
||||
#include <boost/function.hpp>
|
||||
#include <boost/shared_ptr.hpp>
|
||||
|
||||
|
|
|
@ -1,6 +1,13 @@
|
|||
#include "loadingscreen.hpp"
|
||||
|
||||
#include <OgreRenderWindow.h>
|
||||
#include <OgreMaterialManager.h>
|
||||
#include <OgreTechnique.h>
|
||||
#include <OgreRectangle2D.h>
|
||||
#include <OgreSceneNode.h>
|
||||
#include <OgreTextureManager.h>
|
||||
#include <OgreViewport.h>
|
||||
#include <OgreHardwarePixelBuffer.h>
|
||||
|
||||
#include <openengine/ogre/fader.hpp>
|
||||
|
||||
|
@ -66,6 +73,10 @@ namespace MWGui
|
|||
|
||||
void LoadingScreen::loadingOn()
|
||||
{
|
||||
// Early-out if already on
|
||||
if (mRectangle->getVisible())
|
||||
return;
|
||||
|
||||
// Temporarily turn off VSync, we want to do actual loading rather than waiting for the screen to sync.
|
||||
// Threaded loading would be even better, of course - especially because some drivers force VSync to on and we can't change it.
|
||||
// In Ogre 1.8, the swapBuffers argument is useless and setVSyncEnabled is bugged with GLX, nothing we can do :/
|
||||
|
@ -74,16 +85,36 @@ namespace MWGui
|
|||
mWindow->setVSyncEnabled(false);
|
||||
#endif
|
||||
|
||||
if (!mFirstLoad)
|
||||
{
|
||||
mBackgroundImage->setImageTexture("");
|
||||
int width = mWindow->getWidth();
|
||||
int height = mWindow->getHeight();
|
||||
const std::string textureName = "@loading_background";
|
||||
Ogre::TexturePtr texture;
|
||||
texture = Ogre::TextureManager::getSingleton().getByName(textureName);
|
||||
if (texture.isNull())
|
||||
{
|
||||
texture = Ogre::TextureManager::getSingleton().createManual(textureName,
|
||||
Ogre::ResourceGroupManager::DEFAULT_RESOURCE_GROUP_NAME,
|
||||
Ogre::TEX_TYPE_2D,
|
||||
width, height, 0, mWindow->suggestPixelFormat(), Ogre::TU_DYNAMIC_WRITE_ONLY);
|
||||
}
|
||||
texture->unload();
|
||||
texture->setWidth(width);
|
||||
texture->setHeight(height);
|
||||
texture->createInternalResources();
|
||||
mWindow->copyContentsToMemory(texture->getBuffer()->lock(Ogre::Image::Box(0,0,width,height), Ogre::HardwareBuffer::HBL_DISCARD));
|
||||
texture->getBuffer()->unlock();
|
||||
mBackgroundImage->setImageTexture(texture->getName());
|
||||
}
|
||||
|
||||
setVisible(true);
|
||||
|
||||
if (mFirstLoad)
|
||||
{
|
||||
changeWallpaper();
|
||||
}
|
||||
else
|
||||
{
|
||||
mBackgroundImage->setImageTexture("");
|
||||
}
|
||||
|
||||
MWBase::Environment::get().getWindowManager()->pushGuiMode(mFirstLoad ? GM_LoadingWallpaper : GM_Loading);
|
||||
}
|
||||
|
@ -197,8 +228,6 @@ namespace MWGui
|
|||
|
||||
MWBase::Environment::get().getInputManager()->update(0, true);
|
||||
|
||||
mWindow->getViewport(0)->setClearEveryFrame(false);
|
||||
|
||||
// First, swap buffers from last draw, then, queue an update of the
|
||||
// window contents, but don't swap buffers (which would have
|
||||
// caused a sync / flush and would be expensive).
|
||||
|
@ -208,9 +237,6 @@ namespace MWGui
|
|||
|
||||
mWindow->update(false);
|
||||
|
||||
mWindow->getViewport(0)->setClearEveryFrame(true);
|
||||
|
||||
|
||||
mRectangle->setVisible(false);
|
||||
|
||||
// resume 3d rendering
|
||||
|
|
|
@ -2,6 +2,7 @@
|
|||
#define MWGUI_LOADINGSCREEN_H
|
||||
|
||||
#include <OgreSceneManager.h>
|
||||
#include <OgreTimer.h>
|
||||
|
||||
#include "windowbase.hpp"
|
||||
|
||||
|
|
|
@ -1,5 +1,7 @@
|
|||
#include "mainmenu.hpp"
|
||||
|
||||
#include <components/version/version.hpp>
|
||||
|
||||
#include "../mwbase/environment.hpp"
|
||||
#include "../mwbase/windowmanager.hpp"
|
||||
#include "../mwbase/soundmanager.hpp"
|
||||
|
@ -20,6 +22,22 @@ namespace MWGui
|
|||
, mButtonBox(0), mWidth (w), mHeight (h)
|
||||
, mSaveGameDialog(NULL)
|
||||
{
|
||||
getWidget(mVersionText, "VersionText");
|
||||
std::stringstream sstream;
|
||||
sstream << "OpenMW version: " << OPENMW_VERSION;
|
||||
|
||||
// adding info about git hash if availible
|
||||
std::string rev = OPENMW_VERSION_COMMITHASH;
|
||||
std::string tag = OPENMW_VERSION_TAGHASH;
|
||||
if (!rev.empty() && !tag.empty())
|
||||
{
|
||||
rev = rev.substr(0,10);
|
||||
sstream << "\nrevision: " << rev;
|
||||
}
|
||||
|
||||
std::string output = sstream.str();
|
||||
mVersionText->setCaption(output);
|
||||
|
||||
updateMenu();
|
||||
}
|
||||
|
||||
|
|
|
@ -24,6 +24,7 @@ namespace MWGui
|
|||
private:
|
||||
|
||||
MyGUI::Widget* mButtonBox;
|
||||
MyGUI::TextBox* mVersionText;
|
||||
|
||||
std::map<std::string, MWGui::ImageButton*> mButtons;
|
||||
|
||||
|
|
|
@ -3,6 +3,7 @@
|
|||
#include <boost/lexical_cast.hpp>
|
||||
|
||||
#include <OgreSceneNode.h>
|
||||
#include <OgreVector2.h>
|
||||
|
||||
#include "../mwbase/windowmanager.hpp"
|
||||
#include "../mwbase/world.hpp"
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
#ifndef MWGUI_MAPWINDOW_H
|
||||
#define MWGUI_MAPWINDOW_H
|
||||
|
||||
#include <libs/platform/stdint.h>
|
||||
#include <stdint.h>
|
||||
|
||||
#include "windowpinnablebase.hpp"
|
||||
|
||||
|
|
|
@ -41,9 +41,13 @@ namespace MWGui
|
|||
getWidget(mPreviewImage, "PreviewImage");
|
||||
|
||||
getWidget(mHeadRotate, "HeadRotate");
|
||||
mHeadRotate->setScrollRange(50);
|
||||
mHeadRotate->setScrollPosition(25);
|
||||
mHeadRotate->setScrollViewPage(10);
|
||||
|
||||
// Mouse wheel step is hardcoded to 50 in MyGUI 3.2 ("FIXME").
|
||||
// Give other steps the same value to accomodate.
|
||||
mHeadRotate->setScrollRange(1000);
|
||||
mHeadRotate->setScrollPosition(500);
|
||||
mHeadRotate->setScrollViewPage(50);
|
||||
mHeadRotate->setScrollPage(50);
|
||||
mHeadRotate->eventScrollChangePosition += MyGUI::newDelegate(this, &RaceDialog::onHeadRotate);
|
||||
|
||||
// Set up next/previous buttons
|
||||
|
@ -171,9 +175,9 @@ namespace MWGui
|
|||
eventBack();
|
||||
}
|
||||
|
||||
void RaceDialog::onHeadRotate(MyGUI::ScrollBar*, size_t _position)
|
||||
void RaceDialog::onHeadRotate(MyGUI::ScrollBar* scroll, size_t _position)
|
||||
{
|
||||
float angle = (float(_position) / 49.f - 0.5) * 3.14 * 2;
|
||||
float angle = (float(_position) / (scroll->getScrollRange()-1) - 0.5) * 3.14 * 2;
|
||||
float diff = angle - mCurrentAngle;
|
||||
mPreview->update (diff);
|
||||
mPreviewDirty = true;
|
||||
|
|
|
@ -1,5 +1,7 @@
|
|||
#include "repair.hpp"
|
||||
|
||||
#include <iomanip>
|
||||
|
||||
#include <boost/lexical_cast.hpp>
|
||||
|
||||
#include "../mwbase/world.hpp"
|
||||
|
|
|
@ -1,5 +1,7 @@
|
|||
#include "tooltips.hpp"
|
||||
|
||||
#include <iomanip>
|
||||
|
||||
#include <boost/lexical_cast.hpp>
|
||||
|
||||
#include "../mwbase/world.hpp"
|
||||
|
|
|
@ -3,6 +3,8 @@
|
|||
#include <cassert>
|
||||
#include <iterator>
|
||||
|
||||
#include <OgreTextureManager.h>
|
||||
|
||||
#include "MyGUI_UString.h"
|
||||
#include "MyGUI_IPointer.h"
|
||||
#include "MyGUI_ResourceImageSetPointer.h"
|
||||
|
|
|
@ -143,6 +143,13 @@ namespace MWInput
|
|||
mControlSwitch["vanitymode"] = true;
|
||||
}
|
||||
|
||||
void InputManager::clear()
|
||||
{
|
||||
// Enable all controls
|
||||
for (std::map<std::string, bool>::iterator it = mControlSwitch.begin(); it != mControlSwitch.end(); ++it)
|
||||
it->second = true;
|
||||
}
|
||||
|
||||
InputManager::~InputManager()
|
||||
{
|
||||
mInputBinder->save (mUserFile);
|
||||
|
@ -455,7 +462,7 @@ namespace MWInput
|
|||
mInputBinder->adjustMouseRegion(width, height);
|
||||
}
|
||||
|
||||
bool InputManager::keyPressed( const SDL_KeyboardEvent &arg )
|
||||
void InputManager::keyPressed( const SDL_KeyboardEvent &arg )
|
||||
{
|
||||
// Cut, copy & paste
|
||||
MyGUI::Widget* focus = MyGUI::InputManager::getInstance().getKeyFocusWidget();
|
||||
|
@ -501,7 +508,6 @@ namespace MWInput
|
|||
|
||||
if (kc != OIS::KC_UNASSIGNED)
|
||||
MyGUI::InputManager::getInstance().injectKeyPress(MyGUI::KeyCode::Enum(kc), 0);
|
||||
return true;
|
||||
}
|
||||
|
||||
void InputManager::textInput(const SDL_TextInputEvent &arg)
|
||||
|
@ -512,23 +518,21 @@ namespace MWInput
|
|||
MyGUI::InputManager::getInstance().injectKeyPress(MyGUI::KeyCode::None, *it);
|
||||
}
|
||||
|
||||
bool InputManager::keyReleased(const SDL_KeyboardEvent &arg )
|
||||
void InputManager::keyReleased(const SDL_KeyboardEvent &arg )
|
||||
{
|
||||
mInputBinder->keyReleased (arg);
|
||||
|
||||
OIS::KeyCode kc = mInputManager->sdl2OISKeyCode(arg.keysym.sym);
|
||||
|
||||
MyGUI::InputManager::getInstance().injectKeyRelease(MyGUI::KeyCode::Enum(kc));
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool InputManager::mousePressed( const SDL_MouseButtonEvent &arg, Uint8 id )
|
||||
void InputManager::mousePressed( const SDL_MouseButtonEvent &arg, Uint8 id )
|
||||
{
|
||||
mInputBinder->mousePressed (arg, id);
|
||||
|
||||
if (id != SDL_BUTTON_LEFT && id != SDL_BUTTON_RIGHT)
|
||||
return true; // MyGUI has no use for these events
|
||||
return; // MyGUI has no use for these events
|
||||
|
||||
MyGUI::InputManager::getInstance().injectMousePress(mMouseX, mMouseY, sdlButtonToMyGUI(id));
|
||||
if (MyGUI::InputManager::getInstance ().getMouseFocusWidget () != 0)
|
||||
|
@ -539,20 +543,16 @@ namespace MWInput
|
|||
MWBase::Environment::get().getSoundManager ()->playSound ("Menu Click", 1.f, 1.f);
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool InputManager::mouseReleased( const SDL_MouseButtonEvent &arg, Uint8 id )
|
||||
void InputManager::mouseReleased( const SDL_MouseButtonEvent &arg, Uint8 id )
|
||||
{
|
||||
mInputBinder->mouseReleased (arg, id);
|
||||
|
||||
MyGUI::InputManager::getInstance().injectMouseRelease(mMouseX, mMouseY, sdlButtonToMyGUI(id));
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool InputManager::mouseMoved(const SFO::MouseMotionEvent &arg )
|
||||
void InputManager::mouseMoved(const SFO::MouseMotionEvent &arg )
|
||||
{
|
||||
mInputBinder->mouseMoved (arg);
|
||||
|
||||
|
@ -585,13 +585,13 @@ namespace MWInput
|
|||
float rot[3];
|
||||
rot[0] = -y;
|
||||
rot[1] = 0.0f;
|
||||
rot[2] = x;
|
||||
rot[2] = -x;
|
||||
|
||||
// Only actually turn player when we're not in vanity mode
|
||||
if(!MWBase::Environment::get().getWorld()->vanityRotateCamera(rot))
|
||||
{
|
||||
mPlayer->yaw(x);
|
||||
mPlayer->pitch(-y);
|
||||
mPlayer->pitch(y);
|
||||
}
|
||||
|
||||
if (arg.zrel && mControlSwitch["playerviewswitch"]) //Check to make sure you are allowed to zoomout and there is a change
|
||||
|
@ -600,8 +600,6 @@ namespace MWInput
|
|||
MWBase::Environment::get().getWorld()->setCameraDistance(arg.zrel, true, true);
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void InputManager::windowFocusChange(bool have_focus)
|
||||
|
|
|
@ -65,6 +65,9 @@ namespace MWInput
|
|||
|
||||
virtual ~InputManager();
|
||||
|
||||
/// Clear all savegame-specific data
|
||||
virtual void clear();
|
||||
|
||||
virtual void update(float dt, bool loading);
|
||||
|
||||
void setPlayer (MWWorld::Player* player) { mPlayer = player; }
|
||||
|
@ -86,13 +89,13 @@ namespace MWInput
|
|||
virtual void resetToDefaultBindings();
|
||||
|
||||
public:
|
||||
virtual bool keyPressed(const SDL_KeyboardEvent &arg );
|
||||
virtual bool keyReleased( const SDL_KeyboardEvent &arg );
|
||||
virtual void keyPressed(const SDL_KeyboardEvent &arg );
|
||||
virtual void keyReleased( const SDL_KeyboardEvent &arg );
|
||||
virtual void textInput (const SDL_TextInputEvent &arg);
|
||||
|
||||
virtual bool mousePressed( const SDL_MouseButtonEvent &arg, Uint8 id );
|
||||
virtual bool mouseReleased( const SDL_MouseButtonEvent &arg, Uint8 id );
|
||||
virtual bool mouseMoved( const SFO::MouseMotionEvent &arg );
|
||||
virtual void mousePressed( const SDL_MouseButtonEvent &arg, Uint8 id );
|
||||
virtual void mouseReleased( const SDL_MouseButtonEvent &arg, Uint8 id );
|
||||
virtual void mouseMoved( const SFO::MouseMotionEvent &arg );
|
||||
|
||||
virtual void windowVisibilityChange( bool visible );
|
||||
virtual void windowFocusChange( bool have_focus );
|
||||
|
|
|
@ -210,7 +210,7 @@ namespace MWMechanics
|
|||
&& LOS
|
||||
)
|
||||
{
|
||||
creatureStats.getAiSequence().stack(AiCombat(MWBase::Environment::get().getWorld()->getPlayer().getPlayer()));
|
||||
creatureStats.getAiSequence().stack(AiCombat(MWBase::Environment::get().getWorld()->getPlayerPtr()));
|
||||
creatureStats.setHostile(true);
|
||||
}
|
||||
}
|
||||
|
@ -541,7 +541,7 @@ namespace MWMechanics
|
|||
// TODO: Add AI to follow player and fight for him
|
||||
// TODO: VFX_SummonStart, VFX_SummonEnd
|
||||
creatureStats.mSummonedCreatures.insert(std::make_pair(it->first,
|
||||
MWBase::Environment::get().getWorld()->safePlaceObject(ref.getPtr(),*store,ipos).getRefData().getHandle()));
|
||||
MWBase::Environment::get().getWorld()->safePlaceObject(ref.getPtr(),store,ipos).getRefData().getHandle()));
|
||||
}
|
||||
}
|
||||
else
|
||||
|
|
|
@ -15,7 +15,7 @@
|
|||
#include "../mwbase/dialoguemanager.hpp"
|
||||
|
||||
|
||||
#include "npcstats.hpp"
|
||||
#include "creaturestats.hpp"
|
||||
#include "steering.hpp"
|
||||
#include "movement.hpp"
|
||||
#include "character.hpp" // fixme: for getActiveWeapon
|
||||
|
@ -140,11 +140,12 @@ namespace MWMechanics
|
|||
{
|
||||
MWMechanics::DrawState_ state = actor.getClass().getCreatureStats(actor).getDrawState();
|
||||
if (state == MWMechanics::DrawState_Spell || state == MWMechanics::DrawState_Nothing)
|
||||
actor.getClass().getNpcStats(actor).setDrawState(MWMechanics::DrawState_Weapon);
|
||||
actor.getClass().getCreatureStats(actor).setDrawState(MWMechanics::DrawState_Weapon);
|
||||
|
||||
//Get weapon speed and range
|
||||
MWWorld::ContainerStoreIterator weaponSlot =
|
||||
MWMechanics::getActiveWeapon(cls.getNpcStats(actor), cls.getInventoryStore(actor), &weaptype);
|
||||
MWMechanics::getActiveWeapon(cls.getCreatureStats(actor), cls.getInventoryStore(actor), &weaptype);
|
||||
|
||||
if (weaptype == WeapType_HandToHand)
|
||||
{
|
||||
const MWWorld::Store<ESM::GameSetting> &gmst =
|
||||
|
@ -242,17 +243,21 @@ namespace MWMechanics
|
|||
//target is at far distance: build path to target OR follow target (if previously actor had reached it once)
|
||||
mFollowTarget = false;
|
||||
|
||||
buildNewPath(actor);
|
||||
buildNewPath(actor); //may fail to build a path, check before use
|
||||
|
||||
//delete visited path node
|
||||
mPathFinder.checkPathCompleted(pos.pos[0],pos.pos[1],pos.pos[2]);
|
||||
|
||||
//try shortcut
|
||||
if(vDir.length() < mPathFinder.getDistToNext(pos.pos[0],pos.pos[1],pos.pos[2]) && MWBase::Environment::get().getWorld()->getLOS(actor, mTarget))
|
||||
mTargetAngle = Ogre::Radian( Ogre::Math::ACos(vDir.y / vDir.length()) * sgn(Ogre::Math::ASin(vDir.x / vDir.length())) ).valueDegrees();
|
||||
else
|
||||
mTargetAngle = mPathFinder.getZAngleToNext(pos.pos[0], pos.pos[1]);
|
||||
mRotate = true;
|
||||
//if no new path leave mTargetAngle unchanged
|
||||
if(!mPathFinder.getPath().empty())
|
||||
{
|
||||
//try shortcut
|
||||
if(vDir.length() < mPathFinder.getDistToNext(pos.pos[0],pos.pos[1],pos.pos[2]) && MWBase::Environment::get().getWorld()->getLOS(actor, mTarget))
|
||||
mTargetAngle = Ogre::Radian( Ogre::Math::ACos(vDir.y / vDir.length()) * sgn(Ogre::Math::ASin(vDir.x / vDir.length())) ).valueDegrees();
|
||||
else
|
||||
mTargetAngle = mPathFinder.getZAngleToNext(pos.pos[0], pos.pos[1]);
|
||||
mRotate = true;
|
||||
}
|
||||
|
||||
mMovement.mPosition[1] = 1;
|
||||
mReadyToAttack = false;
|
||||
|
@ -302,9 +307,13 @@ namespace MWMechanics
|
|||
dest.mZ = mTarget.getRefData().getPosition().pos[2];
|
||||
Ogre::Vector3 newPathTarget = Ogre::Vector3(dest.mX, dest.mY, dest.mZ);
|
||||
|
||||
ESM::Pathgrid::Point lastPt = mPathFinder.getPath().back();
|
||||
Ogre::Vector3 currPathTarget(lastPt.mX, lastPt.mY, lastPt.mZ);
|
||||
float dist = Ogre::Math::Abs((newPathTarget - currPathTarget).length());
|
||||
float dist = -1; //hack to indicate first time, to construct a new path
|
||||
if(!mPathFinder.getPath().empty())
|
||||
{
|
||||
ESM::Pathgrid::Point lastPt = mPathFinder.getPath().back();
|
||||
Ogre::Vector3 currPathTarget(lastPt.mX, lastPt.mY, lastPt.mZ);
|
||||
dist = Ogre::Math::Abs((newPathTarget - currPathTarget).length());
|
||||
}
|
||||
|
||||
float targetPosThreshold;
|
||||
bool isOutside = actor.getCell()->getCell()->isExterior();
|
||||
|
@ -313,7 +322,7 @@ namespace MWMechanics
|
|||
else
|
||||
targetPosThreshold = 100;
|
||||
|
||||
if(dist > targetPosThreshold)
|
||||
if((dist < 0) || (dist > targetPosThreshold))
|
||||
{
|
||||
//construct new path only if target has moved away more than on <targetPosThreshold>
|
||||
ESM::Position pos = actor.getRefData().getPosition();
|
||||
|
@ -334,8 +343,11 @@ namespace MWMechanics
|
|||
//maybe here is a mistake (?): PathFinder::getPathSize() returns number of grid points in the path,
|
||||
//not the actual path length. Here we should know if the new path is actually more effective.
|
||||
//if(pathFinder2.getPathSize() < mPathFinder.getPathSize())
|
||||
newPathFinder.syncStart(mPathFinder.getPath());
|
||||
mPathFinder = newPathFinder;
|
||||
if(!mPathFinder.getPath().empty())
|
||||
{
|
||||
newPathFinder.syncStart(mPathFinder.getPath());
|
||||
mPathFinder = newPathFinder;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -27,6 +27,11 @@ namespace
|
|||
|
||||
namespace MWMechanics
|
||||
{
|
||||
// NOTE: determined empirically but probably need further tweaking
|
||||
static const int COUNT_BEFORE_STUCK = 20;
|
||||
static const int COUNT_BEFORE_RESET = 200;
|
||||
static const int COUNT_EVADE = 7;
|
||||
|
||||
AiWander::AiWander(int distance, int duration, int timeOfDay, const std::vector<int>& idle, bool repeat):
|
||||
mDistance(distance), mDuration(duration), mTimeOfDay(timeOfDay), mIdle(idle), mRepeat(repeat)
|
||||
, mCellX(std::numeric_limits<int>::max())
|
||||
|
@ -36,6 +41,11 @@ namespace MWMechanics
|
|||
, mX(0)
|
||||
, mY(0)
|
||||
, mZ(0)
|
||||
, mPrevX(0)
|
||||
, mPrevY(0)
|
||||
, mWalkState(State_Norm)
|
||||
, mStuckCount(0)
|
||||
, mEvadeCount(0)
|
||||
, mSaidGreeting(false)
|
||||
{
|
||||
for(unsigned short counter = 0; counter < mIdle.size(); counter++)
|
||||
|
@ -298,9 +308,91 @@ namespace MWMechanics
|
|||
}
|
||||
else
|
||||
{
|
||||
zTurn(actor, Ogre::Degree(mPathFinder.getZAngleToNext(pos.pos[0], pos.pos[1])));
|
||||
/* 1 n
|
||||
* State_Norm <---> State_CheckStuck --> State_Evade
|
||||
* ^ ^ | ^ | ^ | |
|
||||
* | | | | | | | |
|
||||
* | +---+ +---+ +---+ | m
|
||||
* | any < n < m |
|
||||
* +--------------------------------------------+
|
||||
*/
|
||||
bool samePosition = (abs(pos.pos[0] - mPrevX) < 1) && (abs(pos.pos[1] - mPrevY) < 1);
|
||||
switch(mWalkState)
|
||||
{
|
||||
case State_Norm:
|
||||
{
|
||||
if(!samePosition)
|
||||
break;
|
||||
else
|
||||
mWalkState = State_CheckStuck;
|
||||
}
|
||||
/* FALL THROUGH */
|
||||
case State_CheckStuck:
|
||||
{
|
||||
if(!samePosition)
|
||||
{
|
||||
mWalkState = State_Norm;
|
||||
// to do this properly need yet another variable, simply don't clear for now
|
||||
//mStuckCount = 0;
|
||||
break;
|
||||
}
|
||||
else
|
||||
{
|
||||
// consider stuck only if position unchanges consecutively
|
||||
if((mStuckCount++ % COUNT_BEFORE_STUCK) == 0)
|
||||
mWalkState = State_Evade;
|
||||
// NOTE: mStuckCount is purposely not cleared here
|
||||
else
|
||||
break; // still in the same state, but counter got incremented
|
||||
}
|
||||
}
|
||||
/* FALL THROUGH */
|
||||
case State_Evade:
|
||||
{
|
||||
if(mEvadeCount++ < COUNT_EVADE)
|
||||
break;
|
||||
else
|
||||
{
|
||||
mWalkState = State_Norm; // tried to evade, assume all is ok and start again
|
||||
// NOTE: mStuckCount is purposely not cleared here
|
||||
mEvadeCount = 0;
|
||||
}
|
||||
}
|
||||
/* NO DEFAULT CASE */
|
||||
}
|
||||
|
||||
actor.getClass().getMovementSettings(actor).mPosition[1] = 1;
|
||||
if(mWalkState == State_Evade)
|
||||
{
|
||||
//std::cout << "Stuck \""<<actor.getClass().getName(actor)<<"\"" << std::endl;
|
||||
|
||||
// diagonal should have same animation as walk forward
|
||||
actor.getClass().getMovementSettings(actor).mPosition[0] = 1;
|
||||
actor.getClass().getMovementSettings(actor).mPosition[1] = 0.01f;
|
||||
// change the angle a bit, too
|
||||
zTurn(actor, Ogre::Degree(mPathFinder.getZAngleToNext(pos.pos[0] + 1, pos.pos[1])));
|
||||
}
|
||||
else
|
||||
{
|
||||
actor.getClass().getMovementSettings(actor).mPosition[1] = 1;
|
||||
zTurn(actor, Ogre::Degree(mPathFinder.getZAngleToNext(pos.pos[0], pos.pos[1])));
|
||||
}
|
||||
|
||||
if(mStuckCount >= COUNT_BEFORE_RESET) // something has gone wrong, reset
|
||||
{
|
||||
//std::cout << "Reset \""<<actor.getClass().getName(actor)<<"\"" << std::endl;
|
||||
mWalkState = State_Norm;
|
||||
mStuckCount = 0;
|
||||
|
||||
stopWalking(actor);
|
||||
mMoveNow = false;
|
||||
mWalking = false;
|
||||
mChooseAction = true;
|
||||
}
|
||||
|
||||
// update position
|
||||
ESM::Position updatedPos = actor.getRefData().getPosition();
|
||||
mPrevX = updatedPos.pos[0];
|
||||
mPrevY = updatedPos.pos[1];
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -43,6 +43,21 @@ namespace MWMechanics
|
|||
float mXCell;
|
||||
float mYCell;
|
||||
|
||||
// for checking if we're stuck (but don't check Z axis)
|
||||
float mPrevX;
|
||||
float mPrevY;
|
||||
|
||||
enum WalkState
|
||||
{
|
||||
State_Norm,
|
||||
State_CheckStuck,
|
||||
State_Evade
|
||||
};
|
||||
WalkState mWalkState;
|
||||
|
||||
int mStuckCount;
|
||||
int mEvadeCount;
|
||||
|
||||
bool mStoredAvailableNodes;
|
||||
bool mChooseAction;
|
||||
bool mIdleNow;
|
||||
|
|
|
@ -313,6 +313,7 @@ void CharacterController::refreshCurrentAnims(CharacterState idle, CharacterStat
|
|||
|
||||
mAnimation->disable(mCurrentMovement);
|
||||
mCurrentMovement = movement;
|
||||
mMovementAnimVelocity = 0.0f;
|
||||
if(!mCurrentMovement.empty())
|
||||
{
|
||||
float vel, speedmult = 1.0f;
|
||||
|
@ -320,7 +321,10 @@ void CharacterController::refreshCurrentAnims(CharacterState idle, CharacterStat
|
|||
bool isrunning = mPtr.getClass().getCreatureStats(mPtr).getStance(MWMechanics::CreatureStats::Stance_Run);
|
||||
|
||||
if(mMovementSpeed > 0.0f && (vel=mAnimation->getVelocity(mCurrentMovement)) > 1.0f)
|
||||
{
|
||||
mMovementAnimVelocity = vel;
|
||||
speedmult = mMovementSpeed / vel;
|
||||
}
|
||||
else if (mMovementState == CharState_TurnLeft || mMovementState == CharState_TurnRight)
|
||||
speedmult = 1.f; // TODO: should get a speed mult depending on the current turning speed
|
||||
else if (mMovementSpeed > 0.0f)
|
||||
|
@ -330,10 +334,7 @@ void CharacterController::refreshCurrentAnims(CharacterState idle, CharacterStat
|
|||
speedmult = mMovementSpeed / (isrunning ? 222.857f : 154.064f);
|
||||
mAnimation->play(mCurrentMovement, Priority_Movement, movegroup, false,
|
||||
speedmult, ((mode!=2)?"start":"loop start"), "stop", 0.0f, ~0ul);
|
||||
|
||||
mMovementAnimVelocity = vel;
|
||||
}
|
||||
else mMovementAnimVelocity = 0.0f;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1194,7 +1195,10 @@ void CharacterController::update(float duration)
|
|||
: (sneak ? CharState_SneakBack
|
||||
: (isrunning ? CharState_RunBack : CharState_WalkBack)));
|
||||
}
|
||||
else if(rot.z != 0.0f && !inwater && !sneak)
|
||||
// Don't play turning animations during attack. It would break positioning of the arrow bone when releasing a shot.
|
||||
// Actually, in vanilla the turning animation is not even played when merely having equipped the weapon,
|
||||
// but I don't think we need to go as far as that.
|
||||
else if(rot.z != 0.0f && !inwater && !sneak && mUpperBodyState < UpperCharState_StartToMinAttack)
|
||||
{
|
||||
if(rot.z > 0.0f)
|
||||
movestate = CharState_TurnRight;
|
||||
|
|
|
@ -4,9 +4,12 @@
|
|||
|
||||
#include "../mwbase/environment.hpp"
|
||||
#include "../mwbase/world.hpp"
|
||||
#include "../mwbase/mechanicsmanager.hpp"
|
||||
#include "../mwbase/soundmanager.hpp"
|
||||
|
||||
#include "../mwmechanics/npcstats.hpp"
|
||||
#include "../mwmechanics/movement.hpp"
|
||||
#include "../mwmechanics/spellcasting.hpp"
|
||||
|
||||
#include "../mwworld/class.hpp"
|
||||
#include "../mwworld/inventorystore.hpp"
|
||||
|
@ -17,14 +20,30 @@
|
|||
namespace
|
||||
{
|
||||
|
||||
Ogre::Radian signedAngle(Ogre::Vector3 v1, Ogre::Vector3 v2, Ogre::Vector3 n)
|
||||
Ogre::Radian signedAngle(Ogre::Vector3 v1, Ogre::Vector3 v2, Ogre::Vector3 normal)
|
||||
{
|
||||
return Ogre::Math::ATan2(
|
||||
n.dotProduct( v1.crossProduct(v2) ),
|
||||
normal.dotProduct( v1.crossProduct(v2) ),
|
||||
v1.dotProduct(v2)
|
||||
);
|
||||
}
|
||||
|
||||
void applyEnchantment (const MWWorld::Ptr& attacker, const MWWorld::Ptr& victim, const MWWorld::Ptr& object, const Ogre::Vector3& hitPosition)
|
||||
{
|
||||
std::string enchantmentName = !object.isEmpty() ? object.getClass().getEnchantment(object) : "";
|
||||
if (!enchantmentName.empty())
|
||||
{
|
||||
const ESM::Enchantment* enchantment = MWBase::Environment::get().getWorld()->getStore().get<ESM::Enchantment>().find(
|
||||
enchantmentName);
|
||||
if (enchantment->mData.mType == ESM::Enchantment::WhenStrikes)
|
||||
{
|
||||
MWMechanics::CastSpell cast(attacker, victim);
|
||||
cast.mHitPosition = hitPosition;
|
||||
cast.cast(object);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
namespace MWMechanics
|
||||
|
@ -135,4 +154,94 @@ namespace MWMechanics
|
|||
MWBase::Environment::get().getWindowManager()->messageBox("#{sMagicTargetResistsWeapons}");
|
||||
}
|
||||
|
||||
void projectileHit(const MWWorld::Ptr &attacker, const MWWorld::Ptr &victim, MWWorld::Ptr weapon, const MWWorld::Ptr &projectile,
|
||||
const Ogre::Vector3& hitPosition)
|
||||
{
|
||||
MWBase::World *world = MWBase::Environment::get().getWorld();
|
||||
const MWWorld::Store<ESM::GameSetting> &gmst = world->getStore().get<ESM::GameSetting>();
|
||||
|
||||
MWMechanics::CreatureStats& attackerStats = attacker.getClass().getCreatureStats(attacker);
|
||||
|
||||
const MWWorld::Class &othercls = victim.getClass();
|
||||
if(!othercls.isActor()) // Can't hit non-actors
|
||||
return;
|
||||
MWMechanics::CreatureStats &otherstats = victim.getClass().getCreatureStats(victim);
|
||||
if(otherstats.isDead()) // Can't hit dead actors
|
||||
return;
|
||||
|
||||
if(attacker.getRefData().getHandle() == "player")
|
||||
MWBase::Environment::get().getWindowManager()->setEnemy(victim);
|
||||
|
||||
int weapskill = ESM::Skill::Marksman;
|
||||
if(!weapon.isEmpty())
|
||||
weapskill = weapon.getClass().getEquipmentSkill(weapon);
|
||||
|
||||
float skillValue = attacker.getClass().getSkill(attacker,
|
||||
weapon.getClass().getEquipmentSkill(weapon));
|
||||
|
||||
if((::rand()/(RAND_MAX+1.0)) > getHitChance(attacker, victim, skillValue)/100.0f)
|
||||
{
|
||||
victim.getClass().onHit(victim, 0.0f, false, projectile, attacker, false);
|
||||
return;
|
||||
}
|
||||
|
||||
float damage = 0.0f;
|
||||
|
||||
float fDamageStrengthBase = gmst.find("fDamageStrengthBase")->getFloat();
|
||||
float fDamageStrengthMult = gmst.find("fDamageStrengthMult")->getFloat();
|
||||
|
||||
const unsigned char* attack = weapon.get<ESM::Weapon>()->mBase->mData.mChop;
|
||||
damage = attack[0] + ((attack[1]-attack[0])*attackerStats.getAttackStrength()); // Bow/crossbow damage
|
||||
if (weapon != projectile)
|
||||
{
|
||||
// Arrow/bolt damage
|
||||
attack = projectile.get<ESM::Weapon>()->mBase->mData.mChop;
|
||||
damage += attack[0] + ((attack[1]-attack[0])*attackerStats.getAttackStrength());
|
||||
}
|
||||
|
||||
damage *= fDamageStrengthBase +
|
||||
(attackerStats.getAttribute(ESM::Attribute::Strength).getModified() * fDamageStrengthMult * 0.1);
|
||||
|
||||
if(attacker.getRefData().getHandle() == "player")
|
||||
attacker.getClass().skillUsageSucceeded(attacker, weapskill, 0);
|
||||
|
||||
bool detected = MWBase::Environment::get().getMechanicsManager()->awarenessCheck(attacker, victim);
|
||||
if(!detected)
|
||||
{
|
||||
damage *= gmst.find("fCombatCriticalStrikeMult")->getFloat();
|
||||
MWBase::Environment::get().getWindowManager()->messageBox("#{sTargetCriticalStrike}");
|
||||
MWBase::Environment::get().getSoundManager()->playSound3D(victim, "critical damage", 1.0f, 1.0f);
|
||||
}
|
||||
if (victim.getClass().getCreatureStats(victim).getKnockedDown())
|
||||
damage *= gmst.find("fCombatKODamageMult")->getFloat();
|
||||
|
||||
// Apply "On hit" effect of the weapon
|
||||
applyEnchantment(attacker, victim, weapon, hitPosition);
|
||||
if (weapon != projectile)
|
||||
applyEnchantment(attacker, victim, projectile, hitPosition);
|
||||
|
||||
if (damage > 0)
|
||||
MWBase::Environment::get().getWorld()->spawnBloodEffect(victim, hitPosition);
|
||||
|
||||
float fProjectileThrownStoreChance = gmst.find("fProjectileThrownStoreChance")->getFloat();
|
||||
if ((::rand()/(RAND_MAX+1.0)) < fProjectileThrownStoreChance/100.f)
|
||||
victim.getClass().getContainerStore(victim).add(projectile, 1, victim);
|
||||
|
||||
victim.getClass().onHit(victim, damage, true, projectile, attacker, true);
|
||||
}
|
||||
|
||||
float getHitChance(const MWWorld::Ptr &attacker, const MWWorld::Ptr &victim, int skillValue)
|
||||
{
|
||||
MWMechanics::CreatureStats &stats = attacker.getClass().getCreatureStats(attacker);
|
||||
const MWMechanics::MagicEffects &mageffects = stats.getMagicEffects();
|
||||
float hitchance = skillValue +
|
||||
(stats.getAttribute(ESM::Attribute::Agility).getModified() / 5.0f) +
|
||||
(stats.getAttribute(ESM::Attribute::Luck).getModified() / 10.0f);
|
||||
hitchance *= stats.getFatigueTerm();
|
||||
hitchance += mageffects.get(ESM::MagicEffect::FortifyAttack).mMagnitude -
|
||||
mageffects.get(ESM::MagicEffect::Blind).mMagnitude;
|
||||
hitchance -= victim.getClass().getCreatureStats(victim).getEvasion();
|
||||
return hitchance;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -2,6 +2,7 @@
|
|||
#define OPENMW_MECHANICS_COMBAT_H
|
||||
|
||||
#include "../mwworld/ptr.hpp"
|
||||
#include <OgreVector3.h>
|
||||
|
||||
namespace MWMechanics
|
||||
{
|
||||
|
@ -11,6 +12,13 @@ bool blockMeleeAttack (const MWWorld::Ptr& attacker, const MWWorld::Ptr& blocker
|
|||
|
||||
void resistNormalWeapon (const MWWorld::Ptr& actor, const MWWorld::Ptr& attacker, const MWWorld::Ptr& weapon, float& damage);
|
||||
|
||||
/// @note for a thrown weapon, \a weapon == \a projectile, for bows/crossbows, \a projectile is the arrow/bolt
|
||||
void projectileHit (const MWWorld::Ptr& attacker, const MWWorld::Ptr& victim, MWWorld::Ptr weapon, const MWWorld::Ptr& projectile,
|
||||
const Ogre::Vector3& hitPosition);
|
||||
|
||||
/// Get the chance (in percent) for \a attacker to successfully hit \a victim with a given weapon skill value
|
||||
float getHitChance (const MWWorld::Ptr& attacker, const MWWorld::Ptr& victim, int skillValue);
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
|
|
|
@ -6,6 +6,8 @@
|
|||
#include <vector>
|
||||
#include <algorithm>
|
||||
|
||||
#include <iomanip>
|
||||
|
||||
#include <boost/format.hpp>
|
||||
|
||||
#include <components/esm/loadskil.hpp>
|
||||
|
@ -509,4 +511,4 @@ void MWMechanics::NpcStats::readState (const ESM::NpcStats& state)
|
|||
mTimeToStartDrowning = state.mTimeToStartDrowning;
|
||||
mLastDrowningHit = state.mLastDrowningHit;
|
||||
mLevelHealthBonus = state.mLevelHealthBonus;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -393,6 +393,8 @@ namespace MWMechanics
|
|||
|
||||
void PathFinder::syncStart(const std::list<ESM::Pathgrid::Point> &path)
|
||||
{
|
||||
if (mPath.size() < 2)
|
||||
return; //nothing to pop
|
||||
std::list<ESM::Pathgrid::Point>::const_iterator oldStart = path.begin();
|
||||
std::list<ESM::Pathgrid::Point>::iterator iter = ++mPath.begin();
|
||||
|
||||
|
|
|
@ -587,7 +587,7 @@ namespace MWMechanics
|
|||
inflict(mTarget, mCaster, enchantment->mEffects, ESM::RT_Touch);
|
||||
}
|
||||
|
||||
MWBase::Environment::get().getWorld()->launchProjectile(mId, false, enchantment->mEffects, mCaster, mSourceName);
|
||||
MWBase::Environment::get().getWorld()->launchMagicBolt(mId, false, enchantment->mEffects, mCaster, mSourceName);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
@ -666,7 +666,7 @@ namespace MWMechanics
|
|||
}
|
||||
}
|
||||
|
||||
MWBase::Environment::get().getWorld()->launchProjectile(mId, false, spell->mEffects, mCaster, mSourceName);
|
||||
MWBase::Environment::get().getWorld()->launchMagicBolt(mId, false, spell->mEffects, mCaster, mSourceName);
|
||||
return true;
|
||||
}
|
||||
|
||||
|
|
|
@ -10,6 +10,8 @@
|
|||
#include <OgreSceneManager.h>
|
||||
#include <OgreControllerManager.h>
|
||||
#include <OgreStaticGeometry.h>
|
||||
#include <OgreSceneNode.h>
|
||||
#include <OgreTechnique.h>
|
||||
|
||||
#include <components/esm/loadligh.hpp>
|
||||
#include <components/esm/loadweap.hpp>
|
||||
|
@ -293,6 +295,17 @@ void Animation::addAnimSource(const std::string &model)
|
|||
}
|
||||
}
|
||||
|
||||
if (grp == 0 && dstval->getNode()->getName() == "Bip01")
|
||||
{
|
||||
mNonAccumRoot = dstval->getNode();
|
||||
mAccumRoot = mNonAccumRoot->getParent();
|
||||
if(!mAccumRoot)
|
||||
{
|
||||
std::cerr<< "Non-Accum root for "<<mPtr.getCellRef().mRefID<<" is skeleton root??" <<std::endl;
|
||||
mNonAccumRoot = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
ctrls[i].setSource(mAnimationTimePtr[grp]);
|
||||
grpctrls[grp].push_back(ctrls[i]);
|
||||
}
|
||||
|
|
|
@ -70,7 +70,7 @@ namespace MWRender
|
|||
if (!mVanity.enabled && !mPreviewMode) {
|
||||
mCamera->getParentNode()->setOrientation(xr);
|
||||
} else {
|
||||
Ogre::Quaternion zr(Ogre::Radian(getYaw()), Ogre::Vector3::NEGATIVE_UNIT_Z);
|
||||
Ogre::Quaternion zr(Ogre::Radian(getYaw()), Ogre::Vector3::UNIT_Z);
|
||||
mCamera->getParentNode()->setOrientation(zr * xr);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,10 +1,13 @@
|
|||
#include "characterpreview.hpp"
|
||||
|
||||
|
||||
#include <OgreSceneManager.h>
|
||||
#include <OgreRoot.h>
|
||||
#include <OgreHardwarePixelBuffer.h>
|
||||
#include <OgreCamera.h>
|
||||
#include <OgreSceneNode.h>
|
||||
#include <OgreTextureManager.h>
|
||||
#include <OgreViewport.h>
|
||||
#include <OgreRenderTexture.h>
|
||||
|
||||
#include <libs/openengine/ogre/selectionbuffer.hpp>
|
||||
|
||||
|
|
|
@ -3,6 +3,7 @@
|
|||
|
||||
#include <OgreRenderTarget.h>
|
||||
#include <OgreMaterialManager.h>
|
||||
#include <OgreVector3.h>
|
||||
|
||||
#include <components/esm/loadnpc.hpp>
|
||||
|
||||
|
|
|
@ -55,6 +55,8 @@ CreatureWeaponAnimation::CreatureWeaponAnimation(const MWWorld::Ptr &ptr)
|
|||
|
||||
updateParts();
|
||||
}
|
||||
|
||||
mWeaponAnimationTime = Ogre::SharedPtr<WeaponAnimationTime>(new WeaponAnimationTime(this));
|
||||
}
|
||||
|
||||
void CreatureWeaponAnimation::showWeapons(bool showWeapon)
|
||||
|
@ -110,6 +112,20 @@ void CreatureWeaponAnimation::updatePart(NifOgre::ObjectScenePtr& scene, int slo
|
|||
setRenderProperties(scene, RV_Actors, RQG_Main, RQG_Alpha, 0,
|
||||
!item.getClass().getEnchantment(item).empty(), &glowColor);
|
||||
|
||||
// Crossbows start out with a bolt attached
|
||||
if (slot == MWWorld::InventoryStore::Slot_CarriedRight &&
|
||||
item.getTypeName() == typeid(ESM::Weapon).name() &&
|
||||
item.get<ESM::Weapon>()->mBase->mData.mType == ESM::Weapon::MarksmanCrossbow)
|
||||
{
|
||||
MWWorld::ContainerStoreIterator ammo = inv.getSlot(MWWorld::InventoryStore::Slot_Ammunition);
|
||||
if (ammo != inv.end() && ammo->get<ESM::Weapon>()->mBase->mData.mType == ESM::Weapon::Bolt)
|
||||
attachArrow();
|
||||
else
|
||||
mAmmunition.setNull();
|
||||
}
|
||||
else
|
||||
mAmmunition.setNull();
|
||||
|
||||
if(scene->mSkelBase)
|
||||
{
|
||||
Ogre::SkeletonInstance *skel = scene->mSkelBase->getSkeleton();
|
||||
|
@ -133,15 +149,42 @@ void CreatureWeaponAnimation::updatePart(NifOgre::ObjectScenePtr& scene, int slo
|
|||
updateSkeletonInstance(mSkelBase->getSkeleton(), skel);
|
||||
}
|
||||
|
||||
// TODO:
|
||||
// type == ESM::PRT_Weapon should get an animation source based on the current offset
|
||||
// of the weapon attack animation (from its beginning, or start marker?)
|
||||
std::vector<Ogre::Controller<Ogre::Real> >::iterator ctrl(scene->mControllers.begin());
|
||||
for(;ctrl != scene->mControllers.end();ctrl++)
|
||||
{
|
||||
if(ctrl->getSource().isNull())
|
||||
ctrl->setSource(Ogre::SharedPtr<NullAnimationTime>(new NullAnimationTime()));
|
||||
{
|
||||
if (slot == MWWorld::InventoryStore::Slot_CarriedRight)
|
||||
ctrl->setSource(mWeaponAnimationTime);
|
||||
else
|
||||
ctrl->setSource(Ogre::SharedPtr<NullAnimationTime>(new NullAnimationTime()));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void CreatureWeaponAnimation::configureAddedObject(NifOgre::ObjectScenePtr object, MWWorld::Ptr ptr, int slot)
|
||||
{
|
||||
Ogre::Vector3 glowColor = getEnchantmentColor(ptr);
|
||||
|
||||
setRenderProperties(object, RV_Actors, RQG_Main, RQG_Alpha, 0,
|
||||
!ptr.getClass().getEnchantment(ptr).empty(), &glowColor);
|
||||
}
|
||||
|
||||
void CreatureWeaponAnimation::attachArrow()
|
||||
{
|
||||
WeaponAnimation::attachArrow(mPtr);
|
||||
}
|
||||
|
||||
void CreatureWeaponAnimation::releaseArrow()
|
||||
{
|
||||
WeaponAnimation::releaseArrow(mPtr);
|
||||
}
|
||||
|
||||
Ogre::Vector3 CreatureWeaponAnimation::runAnimation(float duration)
|
||||
{
|
||||
Ogre::Vector3 ret = Animation::runAnimation(duration);
|
||||
pitchSkeleton(mPtr.getRefData().getPosition().rot[0], mSkelBase->getSkeleton());
|
||||
return ret;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -2,6 +2,7 @@
|
|||
#define GAME_RENDER_CREATUREANIMATION_H
|
||||
|
||||
#include "animation.hpp"
|
||||
#include "weaponanimation.hpp"
|
||||
#include "../mwworld/inventorystore.hpp"
|
||||
|
||||
namespace MWWorld
|
||||
|
@ -21,7 +22,7 @@ namespace MWRender
|
|||
// For creatures with weapons and shields
|
||||
// Animation is already virtual anyway, so might as well make a separate class.
|
||||
// Most creatures don't need weapons/shields, so this will save some memory.
|
||||
class CreatureWeaponAnimation : public Animation, public MWWorld::InventoryStoreListener
|
||||
class CreatureWeaponAnimation : public Animation, public WeaponAnimation, public MWWorld::InventoryStoreListener
|
||||
{
|
||||
public:
|
||||
CreatureWeaponAnimation(const MWWorld::Ptr& ptr);
|
||||
|
@ -36,11 +37,29 @@ namespace MWRender
|
|||
|
||||
void updatePart(NifOgre::ObjectScenePtr& scene, int slot);
|
||||
|
||||
virtual void attachArrow();
|
||||
virtual void releaseArrow();
|
||||
|
||||
virtual Ogre::Vector3 runAnimation(float duration);
|
||||
|
||||
/// A relative factor (0-1) that decides if and how much the skeleton should be pitched
|
||||
/// to indicate the facing orientation of the character.
|
||||
virtual void setPitchFactor(float factor) { mPitchFactor = factor; }
|
||||
|
||||
virtual void setWeaponGroup(const std::string& group) { mWeaponAnimationTime->setGroup(group); }
|
||||
|
||||
// WeaponAnimation
|
||||
virtual NifOgre::ObjectScenePtr getWeapon() { return mWeapon; }
|
||||
virtual void showWeapon(bool show) { showWeapons(show); }
|
||||
virtual void configureAddedObject(NifOgre::ObjectScenePtr object, MWWorld::Ptr ptr, int slot);
|
||||
|
||||
private:
|
||||
NifOgre::ObjectScenePtr mWeapon;
|
||||
NifOgre::ObjectScenePtr mShield;
|
||||
bool mShowWeapons;
|
||||
bool mShowCarriedLeft;
|
||||
|
||||
Ogre::SharedPtr<WeaponAnimationTime> mWeaponAnimationTime;
|
||||
};
|
||||
}
|
||||
|
||||
|
|
|
@ -7,6 +7,8 @@
|
|||
#include <OgreMaterial.h>
|
||||
#include <OgreMaterialManager.h>
|
||||
#include <OgreManualObject.h>
|
||||
#include <OgreTechnique.h>
|
||||
#include <OgreSceneNode.h>
|
||||
|
||||
#include <openengine/bullet/physic.hpp>
|
||||
|
||||
|
|
|
@ -2,6 +2,8 @@
|
|||
|
||||
#include <OgreSceneManager.h>
|
||||
#include <OgreParticleSystem.h>
|
||||
#include <OgreSceneNode.h>
|
||||
#include <OgreTechnique.h>
|
||||
|
||||
#include "animation.hpp"
|
||||
#include "renderconst.hpp"
|
||||
|
|
|
@ -75,10 +75,9 @@ namespace MWRender
|
|||
|
||||
if (land)
|
||||
{
|
||||
if (!land->isDataLoaded(ESM::Land::DATA_VHGT))
|
||||
{
|
||||
land->loadData(ESM::Land::DATA_VHGT);
|
||||
}
|
||||
int mask = ESM::Land::DATA_VHGT | ESM::Land::DATA_VNML | ESM::Land::DATA_VCLR | ESM::Land::DATA_VTEX;
|
||||
if (!land->isDataLoaded(mask))
|
||||
land->loadData(mask);
|
||||
}
|
||||
|
||||
for (int cellY=0; cellY<cellSize; ++cellY)
|
||||
|
|
|
@ -6,6 +6,8 @@
|
|||
#include <OgreSceneNode.h>
|
||||
#include <OgreCamera.h>
|
||||
#include <OgreTextureManager.h>
|
||||
#include <OgreRenderTexture.h>
|
||||
#include <OgreViewport.h>
|
||||
|
||||
#include "../mwbase/environment.hpp"
|
||||
#include "../mwbase/world.hpp"
|
||||
|
|
|
@ -4,6 +4,11 @@
|
|||
#include <OgreEntity.h>
|
||||
#include <OgreParticleSystem.h>
|
||||
#include <OgreSubEntity.h>
|
||||
#include <OgreSkeleton.h>
|
||||
#include <OgreSkeletonInstance.h>
|
||||
#include <OgreSceneNode.h>
|
||||
#include <OgreBone.h>
|
||||
#include <OgreTechnique.h>
|
||||
|
||||
#include <extern/shiny/Main/Factory.hpp>
|
||||
|
||||
|
@ -71,27 +76,6 @@ float HeadAnimationTime::getValue() const
|
|||
return 1;
|
||||
}
|
||||
|
||||
float WeaponAnimationTime::getValue() const
|
||||
{
|
||||
if (mWeaponGroup.empty())
|
||||
return 0;
|
||||
float current = mAnimation->getCurrentTime(mWeaponGroup);
|
||||
if (current == -1)
|
||||
return 0;
|
||||
return current - mStartTime;
|
||||
}
|
||||
|
||||
void WeaponAnimationTime::setGroup(const std::string &group)
|
||||
{
|
||||
mWeaponGroup = group;
|
||||
mStartTime = mAnimation->getStartTime(mWeaponGroup);
|
||||
}
|
||||
|
||||
void WeaponAnimationTime::updateStartTime()
|
||||
{
|
||||
setGroup(mWeaponGroup);
|
||||
}
|
||||
|
||||
static NpcAnimation::PartBoneMap createPartListMap()
|
||||
{
|
||||
NpcAnimation::PartBoneMap result;
|
||||
|
@ -142,8 +126,7 @@ NpcAnimation::NpcAnimation(const MWWorld::Ptr& ptr, Ogre::SceneNode* node, int v
|
|||
mShowCarriedLeft(true),
|
||||
mFirstPersonOffset(0.f, 0.f, 0.f),
|
||||
mAlpha(1.f),
|
||||
mNpcType(Type_Normal),
|
||||
mPitchFactor(0)
|
||||
mNpcType(Type_Normal)
|
||||
{
|
||||
mNpc = mPtr.get<ESM::NPC>()->mBase;
|
||||
|
||||
|
@ -527,20 +510,16 @@ Ogre::Vector3 NpcAnimation::runAnimation(float timepassed)
|
|||
{
|
||||
float pitch = mPtr.getRefData().getPosition().rot[0];
|
||||
Ogre::Node *node = baseinst->getBone("Bip01 Neck");
|
||||
node->pitch(Ogre::Radian(pitch), Ogre::Node::TS_WORLD);
|
||||
node->pitch(Ogre::Radian(-pitch), Ogre::Node::TS_WORLD);
|
||||
|
||||
// This has to be done before this function ends;
|
||||
// updateSkeletonInstance, below, touches the hands.
|
||||
node->translate(mFirstPersonOffset, Ogre::Node::TS_WORLD);
|
||||
}
|
||||
else if (mPitchFactor > 0)
|
||||
else
|
||||
{
|
||||
// In third person mode we may still need pitch for ranged weapon targeting
|
||||
float pitch = mPtr.getRefData().getPosition().rot[0] * mPitchFactor;
|
||||
Ogre::Node *node = baseinst->getBone("Bip01 Spine2");
|
||||
node->pitch(Ogre::Radian(pitch/2), Ogre::Node::TS_WORLD);
|
||||
node = baseinst->getBone("Bip01 Spine1");
|
||||
node->pitch(Ogre::Radian(pitch/2), Ogre::Node::TS_WORLD);
|
||||
pitchSkeleton(mPtr.getRefData().getPosition().rot[0], baseinst);
|
||||
}
|
||||
mFirstPersonOffset = 0.f; // reset the X, Y, Z offset for the next frame.
|
||||
|
||||
|
@ -690,13 +669,14 @@ void NpcAnimation::showWeapons(bool showWeapon)
|
|||
{
|
||||
MWWorld::InventoryStore &inv = MWWorld::Class::get(mPtr).getInventoryStore(mPtr);
|
||||
MWWorld::ContainerStoreIterator weapon = inv.getSlot(MWWorld::InventoryStore::Slot_CarriedRight);
|
||||
if(weapon != inv.end()) // special case for weapons
|
||||
if(weapon != inv.end())
|
||||
{
|
||||
Ogre::Vector3 glowColor = getEnchantmentColor(*weapon);
|
||||
std::string mesh = MWWorld::Class::get(*weapon).getModel(*weapon);
|
||||
addOrReplaceIndividualPart(ESM::PRT_Weapon, MWWorld::InventoryStore::Slot_CarriedRight, 1,
|
||||
mesh, !weapon->getClass().getEnchantment(*weapon).empty(), &glowColor);
|
||||
|
||||
// Crossbows start out with a bolt attached
|
||||
if (weapon->getTypeName() == typeid(ESM::Weapon).name() &&
|
||||
weapon->get<ESM::Weapon>()->mBase->mData.mType == ESM::Weapon::MarksmanCrossbow)
|
||||
{
|
||||
|
@ -738,50 +718,24 @@ void NpcAnimation::showCarriedLeft(bool show)
|
|||
removeIndividualPart(ESM::PRT_Shield);
|
||||
}
|
||||
|
||||
void NpcAnimation::configureAddedObject(NifOgre::ObjectScenePtr object, MWWorld::Ptr ptr, int slot)
|
||||
{
|
||||
Ogre::Vector3 glowColor = getEnchantmentColor(ptr);
|
||||
setRenderProperties(object, (mViewMode == VM_FirstPerson) ? RV_FirstPerson : mVisibilityFlags, RQG_Main, RQG_Alpha, 0,
|
||||
!ptr.getClass().getEnchantment(ptr).empty(), &glowColor);
|
||||
|
||||
std::for_each(object->mEntities.begin(), object->mEntities.end(), SetObjectGroup(slot));
|
||||
std::for_each(object->mParticles.begin(), object->mParticles.end(), SetObjectGroup(slot));
|
||||
}
|
||||
|
||||
void NpcAnimation::attachArrow()
|
||||
{
|
||||
MWWorld::InventoryStore& inv = mPtr.getClass().getInventoryStore(mPtr);
|
||||
MWWorld::ContainerStoreIterator weaponSlot = inv.getSlot(MWWorld::InventoryStore::Slot_CarriedRight);
|
||||
if (weaponSlot != inv.end() && weaponSlot->get<ESM::Weapon>()->mBase->mData.mType == ESM::Weapon::MarksmanThrown)
|
||||
showWeapons(true);
|
||||
else
|
||||
{
|
||||
NifOgre::ObjectScenePtr weapon = mObjectParts[ESM::PRT_Weapon];
|
||||
|
||||
MWWorld::ContainerStoreIterator ammo = inv.getSlot(MWWorld::InventoryStore::Slot_Ammunition);
|
||||
if (ammo == inv.end())
|
||||
return;
|
||||
std::string model = ammo->getClass().getModel(*ammo);
|
||||
|
||||
mAmmunition = NifOgre::Loader::createObjects(weapon->mSkelBase, "ArrowBone", mInsert, model);
|
||||
Ogre::Vector3 glowColor = getEnchantmentColor(*ammo);
|
||||
setRenderProperties(mAmmunition, (mViewMode == VM_FirstPerson) ? RV_FirstPerson : mVisibilityFlags, RQG_Main, RQG_Alpha, 0,
|
||||
!ammo->getClass().getEnchantment(*ammo).empty(), &glowColor);
|
||||
|
||||
std::for_each(mAmmunition->mEntities.begin(), mAmmunition->mEntities.end(), SetObjectGroup(MWWorld::InventoryStore::Slot_Ammunition));
|
||||
std::for_each(mAmmunition->mParticles.begin(), mAmmunition->mParticles.end(), SetObjectGroup(MWWorld::InventoryStore::Slot_Ammunition));
|
||||
}
|
||||
WeaponAnimation::attachArrow(mPtr);
|
||||
}
|
||||
|
||||
void NpcAnimation::releaseArrow()
|
||||
{
|
||||
// Thrown weapons get detached now
|
||||
MWWorld::InventoryStore& inv = mPtr.getClass().getInventoryStore(mPtr);
|
||||
MWWorld::ContainerStoreIterator weapon = inv.getSlot(MWWorld::InventoryStore::Slot_CarriedRight);
|
||||
if (weapon != inv.end() && weapon->get<ESM::Weapon>()->mBase->mData.mType == ESM::Weapon::MarksmanThrown)
|
||||
{
|
||||
showWeapons(false);
|
||||
inv.remove(*weapon, 1, mPtr);
|
||||
}
|
||||
else
|
||||
{
|
||||
// With bows and crossbows only the used arrow/bolt gets detached
|
||||
MWWorld::ContainerStoreIterator ammo = inv.getSlot(MWWorld::InventoryStore::Slot_Ammunition);
|
||||
if (ammo == inv.end())
|
||||
return;
|
||||
inv.remove(*ammo, 1, mPtr);
|
||||
mAmmunition.setNull();
|
||||
}
|
||||
WeaponAnimation::releaseArrow(mPtr);
|
||||
}
|
||||
|
||||
void NpcAnimation::permanentEffectAdded(const ESM::MagicEffect *magicEffect, bool isNew, bool playSound)
|
||||
|
|
|
@ -5,6 +5,8 @@
|
|||
|
||||
#include "../mwworld/inventorystore.hpp"
|
||||
|
||||
#include "weaponanimation.hpp"
|
||||
|
||||
namespace ESM
|
||||
{
|
||||
struct NPC;
|
||||
|
@ -25,24 +27,7 @@ public:
|
|||
{ }
|
||||
};
|
||||
|
||||
class WeaponAnimationTime : public Ogre::ControllerValue<Ogre::Real>
|
||||
{
|
||||
private:
|
||||
Animation* mAnimation;
|
||||
std::string mWeaponGroup;
|
||||
float mStartTime;
|
||||
public:
|
||||
WeaponAnimationTime(Animation* animation) : mAnimation(animation), mStartTime(0) {}
|
||||
void setGroup(const std::string& group);
|
||||
void updateStartTime();
|
||||
|
||||
virtual Ogre::Real getValue() const;
|
||||
virtual void setValue(Ogre::Real value)
|
||||
{ }
|
||||
};
|
||||
|
||||
|
||||
class NpcAnimation : public Animation, public MWWorld::InventoryStoreListener
|
||||
class NpcAnimation : public Animation, public WeaponAnimation, public MWWorld::InventoryStoreListener
|
||||
{
|
||||
public:
|
||||
virtual void equipmentChanged() { updateParts(); }
|
||||
|
@ -91,7 +76,6 @@ private:
|
|||
Ogre::SharedPtr<WeaponAnimationTime> mWeaponAnimationTime;
|
||||
|
||||
float mAlpha;
|
||||
float mPitchFactor;
|
||||
|
||||
void updateNpcBase();
|
||||
|
||||
|
@ -138,7 +122,10 @@ public:
|
|||
virtual void attachArrow();
|
||||
virtual void releaseArrow();
|
||||
|
||||
NifOgre::ObjectScenePtr mAmmunition;
|
||||
// WeaponAnimation
|
||||
virtual NifOgre::ObjectScenePtr getWeapon() { return mObjectParts[ESM::PRT_Weapon]; }
|
||||
virtual void showWeapon(bool show) { showWeapons(show); }
|
||||
virtual void configureAddedObject(NifOgre::ObjectScenePtr object, MWWorld::Ptr ptr, int slot);
|
||||
|
||||
void setViewMode(ViewMode viewMode);
|
||||
|
||||
|
|
|
@ -109,6 +109,7 @@ void Objects::insertModel(const MWWorld::Ptr &ptr, const std::string &mesh)
|
|||
{
|
||||
uniqueID = uniqueID+1;
|
||||
sg = mRenderer.getScene()->createStaticGeometry("sg" + Ogre::StringConverter::toString(uniqueID));
|
||||
sg->setOrigin(ptr.getRefData().getBaseNode()->getPosition());
|
||||
mStaticGeometrySmall[ptr.getCell()] = sg;
|
||||
|
||||
sg->setRenderingDistance(Settings::Manager::getInt("small object distance", "Viewing distance"));
|
||||
|
@ -122,6 +123,7 @@ void Objects::insertModel(const MWWorld::Ptr &ptr, const std::string &mesh)
|
|||
{
|
||||
uniqueID = uniqueID+1;
|
||||
sg = mRenderer.getScene()->createStaticGeometry("sg" + Ogre::StringConverter::toString(uniqueID));
|
||||
sg->setOrigin(ptr.getRefData().getBaseNode()->getPosition());
|
||||
mStaticGeometry[ptr.getCell()] = sg;
|
||||
}
|
||||
else
|
||||
|
|
|
@ -9,6 +9,8 @@
|
|||
#include <OgreMeshManager.h>
|
||||
#include <OgreMaterialManager.h>
|
||||
#include <OgreCamera.h>
|
||||
#include <OgreSceneNode.h>
|
||||
#include <OgreMesh.h>
|
||||
|
||||
#include "renderconst.hpp"
|
||||
|
||||
|
|
|
@ -7,6 +7,8 @@
|
|||
#include <OgreRenderTarget.h>
|
||||
#include <OgreViewport.h>
|
||||
#include <OgreRoot.h>
|
||||
#include <OgreRenderTexture.h>
|
||||
#include <OgreSceneNode.h>
|
||||
|
||||
#include <extern/shiny/Main/Factory.hpp>
|
||||
|
||||
|
|
|
@ -5,12 +5,14 @@
|
|||
#include <OgreRoot.h>
|
||||
#include <OgreRenderWindow.h>
|
||||
#include <OgreSceneManager.h>
|
||||
#include <OgreSceneNode.h>
|
||||
#include <OgreViewport.h>
|
||||
#include <OgreCamera.h>
|
||||
#include <OgreTextureManager.h>
|
||||
#include <OgreHardwarePixelBuffer.h>
|
||||
#include <OgreControllerManager.h>
|
||||
#include <OgreMeshManager.h>
|
||||
#include <OgreRenderTexture.h>
|
||||
|
||||
#include <SDL_video.h>
|
||||
|
||||
|
@ -278,13 +280,12 @@ void RenderingManager::rotateObject(const MWWorld::Ptr &ptr)
|
|||
|
||||
if(ptr.getRefData().getHandle() == mCamera->getHandle() &&
|
||||
!mCamera->isVanityOrPreviewModeEnabled())
|
||||
mCamera->rotateCamera(rot, false);
|
||||
mCamera->rotateCamera(-rot, false);
|
||||
|
||||
Ogre::Quaternion newo = Ogre::Quaternion(Ogre::Radian(-rot.z), Ogre::Vector3::UNIT_Z);
|
||||
Ogre::Quaternion newo = Ogre::Quaternion(Ogre::Radian(rot.z), Ogre::Vector3::NEGATIVE_UNIT_Z);
|
||||
if(!MWWorld::Class::get(ptr).isActor())
|
||||
newo = Ogre::Quaternion(Ogre::Radian(-rot.x), Ogre::Vector3::UNIT_X) *
|
||||
Ogre::Quaternion(Ogre::Radian(-rot.y), Ogre::Vector3::UNIT_Y) * newo;
|
||||
|
||||
newo = Ogre::Quaternion(Ogre::Radian(rot.x), Ogre::Vector3::NEGATIVE_UNIT_X) *
|
||||
Ogre::Quaternion(Ogre::Radian(rot.y), Ogre::Vector3::NEGATIVE_UNIT_Y) * newo;
|
||||
ptr.getRefData().getBaseNode()->setOrientation(newo);
|
||||
}
|
||||
|
||||
|
@ -649,6 +650,18 @@ void RenderingManager::setGlare(bool glare)
|
|||
mSkyManager->setGlare(glare);
|
||||
}
|
||||
|
||||
void RenderingManager::updateTerrain()
|
||||
{
|
||||
if (mTerrain)
|
||||
{
|
||||
// Avoid updating with dims.getCenter for each cell. Player position should be good enough
|
||||
mTerrain->update(mRendering.getCamera()->getRealPosition());
|
||||
mTerrain->syncLoad();
|
||||
// need to update again so the chunks that were just loaded can be made visible
|
||||
mTerrain->update(mRendering.getCamera()->getRealPosition());
|
||||
}
|
||||
}
|
||||
|
||||
void RenderingManager::requestMap(MWWorld::CellStore* cell)
|
||||
{
|
||||
if (cell->getCell()->isExterior())
|
||||
|
@ -659,9 +672,6 @@ void RenderingManager::requestMap(MWWorld::CellStore* cell)
|
|||
Ogre::Vector2 center (cell->getCell()->getGridX() + 0.5, cell->getCell()->getGridY() + 0.5);
|
||||
dims.merge(mTerrain->getWorldBoundingBox(center));
|
||||
|
||||
if (dims.isFinite())
|
||||
mTerrain->update(dims.getCenter());
|
||||
|
||||
mLocalMap->requestMap(cell, dims.getMinimum().z, dims.getMaximum().z);
|
||||
}
|
||||
else
|
||||
|
@ -981,13 +991,11 @@ void RenderingManager::screenshot(Image &image, int w, int h)
|
|||
|
||||
Ogre::PixelFormat pf = rt->suggestPixelFormat();
|
||||
|
||||
std::vector<Ogre::uchar> data;
|
||||
data.resize(w * h * Ogre::PixelUtil::getNumElemBytes(pf));
|
||||
|
||||
Ogre::PixelBox pb(w, h, 1, pf, &data[0]);
|
||||
rt->copyContentsToMemory(pb);
|
||||
|
||||
image.loadDynamicImage(&data[0], w, h, pf);
|
||||
image.loadDynamicImage(
|
||||
OGRE_ALLOC_T(Ogre::uchar, w * h * Ogre::PixelUtil::getNumElemBytes(pf), Ogre::MEMCATEGORY_GENERAL),
|
||||
w, h, 1, pf, true // autoDelete=true, frees memory we allocate
|
||||
);
|
||||
rt->copyContentsToMemory(image.getPixelBox()); // getPixelBox returns a box sharing the same memory as the image
|
||||
|
||||
Ogre::TextureManager::getSingleton().remove(tempName);
|
||||
mRendering.getCamera()->setAspectRatio(oldAspect);
|
||||
|
@ -1045,20 +1053,16 @@ void RenderingManager::enableTerrain(bool enable)
|
|||
{
|
||||
if (!mTerrain)
|
||||
{
|
||||
Loading::Listener* listener = MWBase::Environment::get().getWindowManager()->getLoadingScreen();
|
||||
Loading::ScopedLoad load(listener);
|
||||
mTerrain = new Terrain::World(listener, mRendering.getScene(), new MWRender::TerrainStorage(), RV_Terrain,
|
||||
mTerrain = new Terrain::World(mRendering.getScene(), new MWRender::TerrainStorage(), RV_Terrain,
|
||||
Settings::Manager::getBool("distant land", "Terrain"),
|
||||
Settings::Manager::getBool("shader", "Terrain"));
|
||||
Settings::Manager::getBool("shader", "Terrain"), Terrain::Align_XY, 1, 64);
|
||||
mTerrain->applyMaterials(Settings::Manager::getBool("enabled", "Shadows"),
|
||||
Settings::Manager::getBool("split", "Shadows"));
|
||||
mTerrain->update(mRendering.getCamera()->getRealPosition());
|
||||
mTerrain->setLoadingListener(NULL);
|
||||
}
|
||||
mTerrain->setVisible(true);
|
||||
}
|
||||
else
|
||||
if (mTerrain)
|
||||
else if (mTerrain)
|
||||
mTerrain->setVisible(false);
|
||||
}
|
||||
|
||||
|
@ -1069,7 +1073,7 @@ float RenderingManager::getCameraDistance() const
|
|||
|
||||
void RenderingManager::spawnEffect(const std::string &model, const std::string &texture, const Vector3 &worldPosition, float scale)
|
||||
{
|
||||
mEffectManager->addEffect(model, "", worldPosition, scale);
|
||||
mEffectManager->addEffect(model, texture, worldPosition, scale);
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
|
|
@ -180,6 +180,10 @@ public:
|
|||
void removeWaterRippleEmitter (const MWWorld::Ptr& ptr);
|
||||
void updateWaterRippleEmitterPtr (const MWWorld::Ptr& old, const MWWorld::Ptr& ptr);
|
||||
|
||||
void updateTerrain ();
|
||||
///< update the terrain according to the player position. Usually done automatically, but should be done manually
|
||||
/// before calling requestMap
|
||||
|
||||
void requestMap (MWWorld::CellStore* cell);
|
||||
///< request the local map for a cell
|
||||
|
||||
|
|
|
@ -4,6 +4,10 @@
|
|||
#include <OgreStringConverter.h>
|
||||
#include <OgreHardwarePixelBuffer.h>
|
||||
#include <OgreRoot.h>
|
||||
#include <OgreRectangle2D.h>
|
||||
#include <OgreSceneNode.h>
|
||||
#include <OgreRenderTexture.h>
|
||||
#include <OgreViewport.h>
|
||||
|
||||
#include <extern/shiny/Main/Factory.hpp>
|
||||
|
||||
|
|
|
@ -9,6 +9,8 @@
|
|||
#include <OgreShadowCameraSetupPSSM.h>
|
||||
#include <OgreHardwarePixelBuffer.h>
|
||||
#include <OgreCamera.h>
|
||||
#include <OgreRenderTexture.h>
|
||||
#include <OgreViewport.h>
|
||||
|
||||
#include <extern/shiny/Main/Factory.hpp>
|
||||
|
||||
|
|
|
@ -11,6 +11,7 @@
|
|||
#include <OgreBillboardSet.h>
|
||||
#include <OgreEntity.h>
|
||||
#include <OgreSubEntity.h>
|
||||
#include <OgreTechnique.h>
|
||||
|
||||
#include <OgreMeshManager.h>
|
||||
|
||||
|
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Reference in a new issue