Merge branch 'master' into HEAD

Conflicts:
	apps/openmw/mwbase/world.hpp
	apps/openmw/mwinput/inputmanagerimp.cpp
	apps/openmw/mwmechanics/actors.cpp
	apps/openmw/mwworld/worldimp.cpp
	apps/openmw/mwworld/worldimp.hpp
	components/esm/loadtes3.cpp
actorid
scrawl 11 years ago
commit 62774fcc4a

3
.gitignore vendored

@ -3,7 +3,6 @@ CMakeFiles
*/CMakeFiles */CMakeFiles
CMakeCache.txt CMakeCache.txt
cmake_install.cmake cmake_install.cmake
CMakeLists.txt.user
Makefile Makefile
makefile makefile
build build
@ -22,6 +21,8 @@ Doxygen
.project .project
.settings .settings
.directory .directory
## qt-creator
CMakeLists.txt.user*
## resources ## resources
data data

@ -15,7 +15,7 @@ before_install:
- sudo apt-get install -qq libqt4-dev libxaw7-dev libxrandr-dev libfreeimage-dev libpng-dev - sudo apt-get install -qq libqt4-dev libxaw7-dev libxrandr-dev libfreeimage-dev libpng-dev
- sudo apt-get install -qq libopenal-dev libmpg123-dev libsndfile1-dev - sudo apt-get install -qq libopenal-dev libmpg123-dev libsndfile1-dev
- sudo apt-get install -qq libavcodec-dev libavformat-dev libavdevice-dev libavutil-dev libswscale-dev libpostproc-dev - sudo apt-get install -qq libavcodec-dev libavformat-dev libavdevice-dev libavutil-dev libswscale-dev libpostproc-dev
- sudo apt-get install -qq libbullet-dev libogre-1.8-dev libmygui-dev libsdl2-dev libunshield-dev - sudo apt-get install -qq libbullet-dev libogre-1.9-dev libmygui-dev libsdl2-dev libunshield-dev
- sudo mkdir /usr/src/gtest/build - sudo mkdir /usr/src/gtest/build
- cd /usr/src/gtest/build - cd /usr/src/gtest/build
- sudo cmake .. -DBUILD_SHARED_LIBS=1 - sudo cmake .. -DBUILD_SHARED_LIBS=1

@ -99,8 +99,6 @@ set(OENGINE_BULLET
${LIBDIR}/openengine/bullet/BtOgreExtras.h ${LIBDIR}/openengine/bullet/BtOgreExtras.h
${LIBDIR}/openengine/bullet/BtOgreGP.h ${LIBDIR}/openengine/bullet/BtOgreGP.h
${LIBDIR}/openengine/bullet/BtOgrePG.h ${LIBDIR}/openengine/bullet/BtOgrePG.h
${LIBDIR}/openengine/bullet/CMotionState.cpp
${LIBDIR}/openengine/bullet/CMotionState.h
${LIBDIR}/openengine/bullet/physic.cpp ${LIBDIR}/openengine/bullet/physic.cpp
${LIBDIR}/openengine/bullet/physic.hpp ${LIBDIR}/openengine/bullet/physic.hpp
${LIBDIR}/openengine/bullet/BulletShapeLoader.cpp ${LIBDIR}/openengine/bullet/BulletShapeLoader.cpp
@ -212,7 +210,7 @@ if (HAVE_UNORDERED_MAP)
endif () endif ()
set(BOOST_COMPONENTS system filesystem program_options thread date_time wave) set(BOOST_COMPONENTS system filesystem program_options)
IF(BOOST_STATIC) IF(BOOST_STATIC)
set(Boost_USE_STATIC_LIBS ON) set(Boost_USE_STATIC_LIBS ON)

@ -989,8 +989,7 @@ void Record<ESM::NPC>::print()
std::cout << " Faction: " << mData.mFaction << std::endl; std::cout << " Faction: " << mData.mFaction << std::endl;
std::cout << " Flags: " << npcFlags(mData.mFlags) << std::endl; std::cout << " Flags: " << npcFlags(mData.mFlags) << std::endl;
// Seriously? if (mData.mNpdtType == ESM::NPC::NPC_WITH_AUTOCALCULATED_STATS)
if (mData.mNpdt52.mGold == -10)
{ {
std::cout << " Level: " << mData.mNpdt12.mLevel << std::endl; std::cout << " Level: " << mData.mNpdt12.mLevel << std::endl;
std::cout << " Reputation: " << (int)mData.mNpdt12.mReputation << std::endl; std::cout << " Reputation: " << (int)mData.mNpdt12.mReputation << std::endl;
@ -1022,7 +1021,7 @@ void Record<ESM::NPC>::print()
std::cout << " Luck: " << (int)mData.mNpdt52.mLuck << std::endl; std::cout << " Luck: " << (int)mData.mNpdt52.mLuck << std::endl;
std::cout << " Skills:" << std::endl; std::cout << " Skills:" << std::endl;
for (int i = 0; i != 27; i++) for (int i = 0; i != ESM::Skill::Length; i++)
std::cout << " " << skillLabel(i) << ": " std::cout << " " << skillLabel(i) << ": "
<< (int)((unsigned char)mData.mNpdt52.mSkills[i]) << std::endl; << (int)((unsigned char)mData.mNpdt52.mSkills[i]) << std::endl;

@ -137,8 +137,3 @@ if (BUILD_WITH_CODE_COVERAGE)
target_link_libraries(omwlauncher gcov) target_link_libraries(omwlauncher gcov)
endif() endif()
# Workaround for binutil => 2.23 problem when linking, should be fixed eventually upstream
if (UNIX AND NOT APPLE)
target_link_libraries(omwlauncher dl Xt)
endif()

@ -219,7 +219,7 @@ bool Launcher::MainDialog::showFirstRunDialog()
} }
// Create the file if it doesn't already exist, else the importer will fail // Create the file if it doesn't already exist, else the importer will fail
QString path = QString::fromStdString(mCfgMgr.getUserPath().string()) + QString("openmw.cfg"); QString path = QString::fromStdString(mCfgMgr.getUserConfigPath().string()) + QString("openmw.cfg");
QFile file(path); QFile file(path);
if (!file.exists()) { if (!file.exists()) {
@ -334,7 +334,7 @@ bool Launcher::MainDialog::setupLauncherSettings()
{ {
mLauncherSettings.setMultiValueEnabled(true); mLauncherSettings.setMultiValueEnabled(true);
QString userPath = QString::fromStdString(mCfgMgr.getUserPath().string()); QString userPath = QString::fromStdString(mCfgMgr.getUserConfigPath().string());
QStringList paths; QStringList paths;
paths.append(QString("launcher.cfg")); paths.append(QString("launcher.cfg"));
@ -440,9 +440,35 @@ bool Launcher::expansions(Launcher::UnshieldThread& cd)
bool Launcher::MainDialog::setupGameSettings() bool Launcher::MainDialog::setupGameSettings()
{ {
QString userPath = QString::fromStdString(mCfgMgr.getUserPath().string()); QString userPath = QString::fromStdString(mCfgMgr.getUserConfigPath().string());
QString globalPath = QString::fromStdString(mCfgMgr.getGlobalPath().string()); QString globalPath = QString::fromStdString(mCfgMgr.getGlobalPath().string());
// Load the user config file first, separately
// So we can write it properly, uncontaminated
QString path = userPath + QLatin1String("openmw.cfg");
QFile file(path);
qDebug() << "Loading config file:" << qPrintable(path);
if (file.exists()) {
if (!file.open(QIODevice::ReadOnly | QIODevice::Text)) {
QMessageBox msgBox;
msgBox.setWindowTitle(tr("Error opening OpenMW configuration file"));
msgBox.setIcon(QMessageBox::Critical);
msgBox.setStandardButtons(QMessageBox::Ok);
msgBox.setText(QObject::tr("<br><b>Could not open %0 for reading</b><br><br> \
Please make sure you have the right permissions \
and try again.<br>").arg(file.fileName()));
msgBox.exec();
return false;
}
QTextStream stream(&file);
stream.setCodec(QTextCodec::codecForName("UTF-8"));
mGameSettings.readUserFile(stream);
}
// Now the rest
QStringList paths; QStringList paths;
paths.append(userPath + QString("openmw.cfg")); paths.append(userPath + QString("openmw.cfg"));
paths.append(QString("openmw.cfg")); paths.append(QString("openmw.cfg"));
@ -565,7 +591,7 @@ bool Launcher::MainDialog::setupGraphicsSettings()
{ {
mGraphicsSettings.setMultiValueEnabled(false); mGraphicsSettings.setMultiValueEnabled(false);
QString userPath = QString::fromStdString(mCfgMgr.getUserPath().string()); QString userPath = QString::fromStdString(mCfgMgr.getUserConfigPath().string());
QString globalPath = QString::fromStdString(mCfgMgr.getGlobalPath().string()); QString globalPath = QString::fromStdString(mCfgMgr.getGlobalPath().string());
QFile localDefault(QString("settings-default.cfg")); QFile localDefault(QString("settings-default.cfg"));
@ -652,7 +678,7 @@ bool Launcher::MainDialog::writeSettings()
mGraphicsPage->saveSettings(); mGraphicsPage->saveSettings();
mDataFilesPage->saveSettings(); mDataFilesPage->saveSettings();
QString userPath = QString::fromStdString(mCfgMgr.getUserPath().string()); QString userPath = QString::fromStdString(mCfgMgr.getUserConfigPath().string());
QDir dir(userPath); QDir dir(userPath);
if (!dir.exists()) { if (!dir.exists()) {

@ -90,6 +90,16 @@ QStringList Launcher::GameSettings::values(const QString &key, const QStringList
} }
bool Launcher::GameSettings::readFile(QTextStream &stream) bool Launcher::GameSettings::readFile(QTextStream &stream)
{
return readFile(stream, mSettings);
}
bool Launcher::GameSettings::readUserFile(QTextStream &stream)
{
return readFile(stream, mUserSettings);
}
bool Launcher::GameSettings::readFile(QTextStream &stream, QMap<QString, QString> &settings)
{ {
QMap<QString, QString> cache; QMap<QString, QString> cache;
QRegExp keyRe("^([^=]+)\\s*=\\s*(.+)$"); QRegExp keyRe("^([^=]+)\\s*=\\s*(.+)$");
@ -107,10 +117,10 @@ bool Launcher::GameSettings::readFile(QTextStream &stream)
// Don't remove existing data entries // Don't remove existing data entries
if (key != QLatin1String("data")) if (key != QLatin1String("data"))
mSettings.remove(key); settings.remove(key);
QStringList values = cache.values(key); QStringList values = cache.values(key);
values.append(mSettings.values(key)); values.append(settings.values(key));
if (!values.contains(value)) { if (!values.contains(value)) {
cache.insertMulti(key, value); cache.insertMulti(key, value);
@ -118,23 +128,24 @@ bool Launcher::GameSettings::readFile(QTextStream &stream)
} }
} }
if (mSettings.isEmpty()) { if (settings.isEmpty()) {
mSettings = cache; // This is the first time we read a file settings = cache; // This is the first time we read a file
validatePaths(); validatePaths();
return true; return true;
} }
// Merge the changed keys with those which didn't // Merge the changed keys with those which didn't
mSettings.unite(cache); settings.unite(cache);
validatePaths(); validatePaths();
return true; return true;
} }
bool Launcher::GameSettings::writeFile(QTextStream &stream) bool Launcher::GameSettings::writeFile(QTextStream &stream)
{ {
// Iterate in reverse order to preserve insertion order // Iterate in reverse order to preserve insertion order
QMapIterator<QString, QString> i(mSettings); QMapIterator<QString, QString> i(mUserSettings);
i.toBack(); i.toBack();
while (i.hasPrevious()) { while (i.hasPrevious()) {
@ -162,7 +173,7 @@ bool Launcher::GameSettings::writeFile(QTextStream &stream)
} }
QStringList content = mSettings.values(QString("content")); QStringList content = mUserSettings.values(QString("content"));
for (int i = content.count(); i--;) { for (int i = content.count(); i--;) {
stream << "content=" << content.at(i) << "\n"; stream << "content=" << content.at(i) << "\n";
} }
@ -172,14 +183,14 @@ bool Launcher::GameSettings::writeFile(QTextStream &stream)
bool Launcher::GameSettings::hasMaster() bool Launcher::GameSettings::hasMaster()
{ {
bool result = false; bool result = false;
QStringList content = mSettings.values(QString("content")); QStringList content = mSettings.values(QString("content"));
for (int i = 0; i < content.count(); ++i) { for (int i = 0; i < content.count(); ++i) {
if (content.at(i).contains(".omwgame") || content.at(i).contains(".esm")) { if (content.at(i).contains(".omwgame") || content.at(i).contains(".esm")) {
result = true; result = true;
break; break;
}
} }
}
return result; return result;
} }

@ -31,6 +31,7 @@ namespace Launcher
inline void setValue(const QString &key, const QString &value) inline void setValue(const QString &key, const QString &value)
{ {
mSettings.insert(key, value); mSettings.insert(key, value);
mUserSettings.insert(key, value);
} }
inline void setMultiValue(const QString &key, const QString &value) inline void setMultiValue(const QString &key, const QString &value)
@ -38,11 +39,16 @@ namespace Launcher
QStringList values = mSettings.values(key); QStringList values = mSettings.values(key);
if (!values.contains(value)) if (!values.contains(value))
mSettings.insertMulti(key, value); mSettings.insertMulti(key, value);
values = mUserSettings.values(key);
if (!values.contains(value))
mUserSettings.insertMulti(key, value);
} }
inline void remove(const QString &key) inline void remove(const QString &key)
{ {
mSettings.remove(key); mSettings.remove(key);
mUserSettings.remove(key);
} }
inline QStringList getDataDirs() { return mDataDirs; } inline QStringList getDataDirs() { return mDataDirs; }
@ -52,7 +58,11 @@ namespace Launcher
bool hasMaster(); bool hasMaster();
QStringList values(const QString &key, const QStringList &defaultValues = QStringList()); QStringList values(const QString &key, const QStringList &defaultValues = QStringList());
bool readFile(QTextStream &stream); bool readFile(QTextStream &stream);
bool readFile(QTextStream &stream, QMap<QString, QString> &settings);
bool readUserFile(QTextStream &stream);
bool writeFile(QTextStream &stream); bool writeFile(QTextStream &stream);
private: private:
@ -60,6 +70,7 @@ namespace Launcher
void validatePaths(); void validatePaths();
QMap<QString, QString> mSettings; QMap<QString, QString> mSettings;
QMap<QString, QString> mUserSettings;
QStringList mDataDirs; QStringList mDataDirs;
QString mDataLocal; QString mDataLocal;

@ -16,7 +16,7 @@ MwIniImporter::MwIniImporter()
const char *map[][2] = const char *map[][2] =
{ {
{ "fps", "General:Show FPS" }, { "fps", "General:Show FPS" },
{ "nosound", "General:Disable Audio" }, { "no-sound", "General:Disable Audio" },
{ 0, 0 } { 0, 0 }
}; };
const char *fallback[] = { const char *fallback[] = {

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

@ -86,10 +86,6 @@ void CS::Editor::setupDataFiles()
return; return;
} }
// Set the charset for reading the esm/esp files
// QString encoding = QString::fromStdString(variables["encoding"].as<std::string>());
//mFileDialog.setEncoding(encoding);
dataDirs.insert (dataDirs.end(), dataLocal.begin(), dataLocal.end()); dataDirs.insert (dataDirs.end(), dataLocal.begin(), dataLocal.end());
mDocumentManager.setResourceDir (variables["resources"].as<std::string>()); mDocumentManager.setResourceDir (variables["resources"].as<std::string>());

@ -42,10 +42,10 @@ int main(int argc, char *argv[])
// TODO: Ogre startup shouldn't be here, but it currently has to: // 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 :( // SceneWidget destructor will delete the created render window, which would be called _after_ Root has shut down :(
OgreInit::OgreInit ogreInit;
ogreInit.init("./opencsOgre.log"); // TODO log path?
Application mApplication (argc, argv); Application mApplication (argc, argv);
OgreInit::OgreInit ogreInit;
ogreInit.init("./opencsOgre.log"); // TODO log path?
#ifdef Q_OS_MAC #ifdef Q_OS_MAC
QDir dir(QCoreApplication::applicationDirPath()); QDir dir(QCoreApplication::applicationDirPath());

@ -2221,7 +2221,7 @@ void CSMDoc::Document::createBase()
CSMDoc::Document::Document (const Files::ConfigurationManager& configuration, const std::vector< boost::filesystem::path >& files, const boost::filesystem::path& savePath, const boost::filesystem::path& resDir, bool new_) CSMDoc::Document::Document (const Files::ConfigurationManager& configuration, const std::vector< boost::filesystem::path >& files, const boost::filesystem::path& savePath, const boost::filesystem::path& resDir, bool new_)
: mSavePath (savePath), mContentFiles (files), mTools (mData), mResDir(resDir), : mSavePath (savePath), mContentFiles (files), mTools (mData), mResDir(resDir),
mProjectPath ((configuration.getUserPath() / "projects") / mProjectPath ((configuration.getUserDataPath() / "projects") /
(savePath.filename().string() + ".project")), (savePath.filename().string() + ".project")),
mSaving (*this, mProjectPath) mSaving (*this, mProjectPath)
{ {
@ -2254,7 +2254,7 @@ CSMDoc::Document::Document (const Files::ConfigurationManager& configuration, co
} }
else else
{ {
boost::filesystem::path locCustomFiltersPath (configuration.getUserPath()); boost::filesystem::path locCustomFiltersPath (configuration.getUserDataPath());
locCustomFiltersPath /= "defaultfilters"; locCustomFiltersPath /= "defaultfilters";
if (boost::filesystem::exists(locCustomFiltersPath)) if (boost::filesystem::exists(locCustomFiltersPath))

@ -15,7 +15,7 @@
CSMDoc::DocumentManager::DocumentManager (const Files::ConfigurationManager& configuration) CSMDoc::DocumentManager::DocumentManager (const Files::ConfigurationManager& configuration)
: mConfiguration (configuration) : mConfiguration (configuration)
{ {
boost::filesystem::path projectPath = configuration.getUserPath() / "projects"; boost::filesystem::path projectPath = configuration.getUserDataPath() / "projects";
if (!boost::filesystem::is_directory (projectPath)) if (!boost::filesystem::is_directory (projectPath))
boost::filesystem::create_directories (projectPath); boost::filesystem::create_directories (projectPath);
@ -53,4 +53,4 @@ bool CSMDoc::DocumentManager::removeDocument (Document *document)
void CSMDoc::DocumentManager::setResourceDir (const boost::filesystem::path& parResDir) void CSMDoc::DocumentManager::setResourceDir (const boost::filesystem::path& parResDir)
{ {
mResDir = boost::filesystem::system_complete(parResDir); mResDir = boost::filesystem::system_complete(parResDir);
} }

@ -251,7 +251,7 @@ void CSMSettings::UserSettings::loadSettings (const QString &fileName)
bool localOk = loadFromFile(localFilePath); bool localOk = loadFromFile(localFilePath);
//user //user
mUserFilePath = QString::fromStdString(mCfgMgr.getUserPath().string()) + fileName; mUserFilePath = QString::fromStdString(mCfgMgr.getUserConfigPath().string()) + fileName;
loadFromFile(mUserFilePath); loadFromFile(mUserFilePath);
if (!(localOk || globalOk)) if (!(localOk || globalOk))

@ -263,7 +263,7 @@ namespace
static const char *sCreatureTypes[] = static const char *sCreatureTypes[] =
{ {
"Creature", "Deadra", "Undead", "Humanoid", 0 "Creature", "Daedra", "Undead", "Humanoid", 0
}; };
static const char *sWeaponTypes[] = static const char *sWeaponTypes[] =
@ -342,4 +342,4 @@ std::vector<std::string> CSMWorld::Columns::getEnums (ColumnId column)
} }
return enums; return enums;
} }

@ -19,8 +19,8 @@ source_group(game FILES ${GAME} ${GAME_HEADER})
add_openmw_dir (mwrender add_openmw_dir (mwrender
renderingmanager debugging sky camera animation npcanimation creatureanimation activatoranimation renderingmanager debugging sky camera animation npcanimation creatureanimation activatoranimation
actors objects renderinginterface localmap occlusionquery water shadows actors objects renderinginterface localmap occlusionquery water shadows
compositors characterpreview externalrendering globalmap videoplayer ripplesimulation refraction characterpreview externalrendering globalmap videoplayer ripplesimulation refraction
terrainstorage terrainstorage renderconst
) )
add_openmw_dir (mwinput add_openmw_dir (mwinput
@ -74,6 +74,7 @@ add_openmw_dir (mwmechanics
mechanicsmanagerimp stat character creaturestats magiceffects movement actors objects mechanicsmanagerimp stat character creaturestats magiceffects movement actors objects
drawstate spells activespells npcstats aipackage aisequence alchemy aiwander aitravel aifollow drawstate spells activespells npcstats aipackage aisequence alchemy aiwander aitravel aifollow
aiescort aiactivate aicombat repair enchanting pathfinding security spellsuccess spellcasting aiescort aiactivate aicombat repair enchanting pathfinding security spellsuccess spellcasting
disease
) )
add_openmw_dir (mwstate add_openmw_dir (mwstate
@ -86,6 +87,8 @@ add_openmw_dir (mwbase
) )
# Main executable # Main executable
set(BOOST_COMPONENTS system filesystem program_options thread wave)
find_package(Boost REQUIRED COMPONENTS ${BOOST_COMPONENTS})
IF(OGRE_STATIC) IF(OGRE_STATIC)
ADD_DEFINITIONS(-DENABLE_PLUGIN_OctreeSceneManager -DENABLE_PLUGIN_ParticleFX -DENABLE_PLUGIN_GL) ADD_DEFINITIONS(-DENABLE_PLUGIN_OctreeSceneManager -DENABLE_PLUGIN_ParticleFX -DENABLE_PLUGIN_GL)
@ -115,6 +118,7 @@ add_definitions(${SOUND_DEFINE})
target_link_libraries(openmw target_link_libraries(openmw
${OGRE_LIBRARIES} ${OGRE_LIBRARIES}
${OGRE_STATIC_PLUGINS} ${OGRE_STATIC_PLUGINS}
${SHINY_LIBRARIES}
${Boost_LIBRARIES} ${Boost_LIBRARIES}
${OPENAL_LIBRARY} ${OPENAL_LIBRARY}
${SOUND_INPUT_LIBRARY} ${SOUND_INPUT_LIBRARY}
@ -122,7 +126,6 @@ target_link_libraries(openmw
${MYGUI_LIBRARIES} ${MYGUI_LIBRARIES}
${SDL2_LIBRARY} ${SDL2_LIBRARY}
${MYGUI_PLATFORM_LIBRARIES} ${MYGUI_PLATFORM_LIBRARIES}
${SHINY_LIBRARIES}
"oics" "oics"
"sdl4ogre" "sdl4ogre"
components components
@ -141,12 +144,6 @@ if (UNIX AND NOT APPLE)
target_link_libraries(openmw ${CMAKE_THREAD_LIBS_INIT}) target_link_libraries(openmw ${CMAKE_THREAD_LIBS_INIT})
endif() endif()
# Workaround for binutil => 2.23 problem when linking, should be fixed eventually upstream
if (UNIX AND NOT APPLE)
target_link_libraries(openmw dl Xt)
endif()
if(APPLE) if(APPLE)
find_library(COCOA_FRAMEWORK Cocoa) find_library(COCOA_FRAMEWORK Cocoa)
find_library(IOKIT_FRAMEWORK IOKit) find_library(IOKIT_FRAMEWORK IOKit)

@ -66,10 +66,6 @@ void OMW::Engine::executeLocalScripts()
localScripts.setIgnore (MWWorld::Ptr()); localScripts.setIgnore (MWWorld::Ptr());
} }
void OMW::Engine::setAnimationVerbose(bool animverbose)
{
}
bool OMW::Engine::frameStarted (const Ogre::FrameEvent& evt) bool OMW::Engine::frameStarted (const Ogre::FrameEvent& evt)
{ {
bool paused = MWBase::Environment::get().getWindowManager()->isGuiMode(); bool paused = MWBase::Environment::get().getWindowManager()->isGuiMode();
@ -316,7 +312,7 @@ std::string OMW::Engine::loadSettings (Settings::Manager & settings)
throw std::runtime_error ("No default settings file found! Make sure the file \"settings-default.cfg\" was properly installed."); throw std::runtime_error ("No default settings file found! Make sure the file \"settings-default.cfg\" was properly installed.");
// load user settings if they exist, otherwise just load the default settings as user settings // load user settings if they exist, otherwise just load the default settings as user settings
const std::string settingspath = mCfgMgr.getUserPath().string() + "/settings.cfg"; const std::string settingspath = mCfgMgr.getUserConfigPath().string() + "/settings.cfg";
if (boost::filesystem::exists(settingspath)) if (boost::filesystem::exists(settingspath))
settings.loadUser(settingspath); settings.loadUser(settingspath);
else if (boost::filesystem::exists(localdefault)) else if (boost::filesystem::exists(localdefault))
@ -328,12 +324,16 @@ std::string OMW::Engine::loadSettings (Settings::Manager & settings)
// load nif overrides // load nif overrides
NifOverrides::Overrides nifOverrides; NifOverrides::Overrides nifOverrides;
if (boost::filesystem::exists(mCfgMgr.getLocalPath().string() + "/transparency-overrides.cfg")) std::string transparencyOverrides = "/transparency-overrides.cfg";
nifOverrides.loadTransparencyOverrides(mCfgMgr.getLocalPath().string() + "/transparency-overrides.cfg"); std::string materialOverrides = "/material-overrides.cfg";
else if (boost::filesystem::exists(mCfgMgr.getGlobalPath().string() + "/transparency-overrides.cfg")) if (boost::filesystem::exists(mCfgMgr.getLocalPath().string() + transparencyOverrides))
nifOverrides.loadTransparencyOverrides(mCfgMgr.getGlobalPath().string() + "/transparency-overrides.cfg"); nifOverrides.loadTransparencyOverrides(mCfgMgr.getLocalPath().string() + transparencyOverrides);
else if (boost::filesystem::exists(mCfgMgr.getGlobalPath().string() + transparencyOverrides))
settings.setBool("hardware cursors", "GUI", true); nifOverrides.loadTransparencyOverrides(mCfgMgr.getGlobalPath().string() + transparencyOverrides);
if (boost::filesystem::exists(mCfgMgr.getLocalPath().string() + materialOverrides))
nifOverrides.loadMaterialOverrides(mCfgMgr.getLocalPath().string() + materialOverrides);
else if (boost::filesystem::exists(mCfgMgr.getGlobalPath().string() + materialOverrides))
nifOverrides.loadMaterialOverrides(mCfgMgr.getGlobalPath().string() + materialOverrides);
return settingspath; return settingspath;
} }
@ -341,7 +341,7 @@ std::string OMW::Engine::loadSettings (Settings::Manager & settings)
void OMW::Engine::prepareEngine (Settings::Manager & settings) void OMW::Engine::prepareEngine (Settings::Manager & settings)
{ {
mEnvironment.setStateManager ( mEnvironment.setStateManager (
new MWState::StateManager (mCfgMgr.getUserPath() / "saves", mContentFiles.at (0))); new MWState::StateManager (mCfgMgr.getUserDataPath() / "saves", mContentFiles.at (0)));
Nif::NIFFile::CacheLock cachelock; Nif::NIFFile::CacheLock cachelock;
@ -391,7 +391,7 @@ void OMW::Engine::prepareEngine (Settings::Manager & settings)
// Create input and UI first to set up a bootstrapping environment for // Create input and UI first to set up a bootstrapping environment for
// showing a loading screen and keeping the window responsive while doing so // showing a loading screen and keeping the window responsive while doing so
std::string keybinderUser = (mCfgMgr.getUserPath() / "input.xml").string(); std::string keybinderUser = (mCfgMgr.getUserConfigPath() / "input.xml").string();
bool keybinderUserExists = boost::filesystem::exists(keybinderUser); bool keybinderUserExists = boost::filesystem::exists(keybinderUser);
MWInput::InputManager* input = new MWInput::InputManager (*mOgre, *this, keybinderUser, keybinderUserExists, mGrab); MWInput::InputManager* input = new MWInput::InputManager (*mOgre, *this, keybinderUser, keybinderUserExists, mGrab);
mEnvironment.setInputManager (input); mEnvironment.setInputManager (input);
@ -540,6 +540,8 @@ void OMW::Engine::activate()
std::string script = MWWorld::Class::get (ptr).getScript (ptr); std::string script = MWWorld::Class::get (ptr).getScript (ptr);
MWBase::Environment::get().getWorld()->breakInvisibility(MWBase::Environment::get().getWorld()->getPlayer().getPlayer());
if (!script.empty()) if (!script.empty())
{ {
MWBase::Environment::get().getWorld()->getLocalScripts().setIgnore (ptr); MWBase::Environment::get().getWorld()->getLocalScripts().setIgnore (ptr);
@ -557,7 +559,7 @@ void OMW::Engine::screenshot()
// Count screenshots. // Count screenshots.
int shotCount = 0; int shotCount = 0;
const std::string screenshotPath = mCfgMgr.getUserPath().string(); const std::string& screenshotPath = mCfgMgr.getUserDataPath().string();
// Find the first unused filename with a do-while // Find the first unused filename with a do-while
std::ostringstream stream; std::ostringstream stream;

@ -170,8 +170,6 @@ namespace OMW
/// Font encoding /// Font encoding
void setEncoding(const ToUTF8::FromType& encoding); void setEncoding(const ToUTF8::FromType& encoding);
void setAnimationVerbose(bool animverbose);
void setFallbackValues(std::map<std::string,std::string> map); void setFallbackValues(std::map<std::string,std::string> map);
/// Enable console-only script functionality /// Enable console-only script functionality

@ -3,8 +3,7 @@
#include <components/files/configurationmanager.hpp> #include <components/files/configurationmanager.hpp>
#include <SDL_messagebox.h> #include <SDL.h>
#include <SDL_main.h>
#include "engine.hpp" #include "engine.hpp"
#if defined(_WIN32) && !defined(_CONSOLE) #if defined(_WIN32) && !defined(_CONSOLE)
@ -122,10 +121,7 @@ bool parseOptions (int argc, char** argv, OMW::Engine& engine, Files::Configurat
("content", bpo::value<StringsVector>()->default_value(StringsVector(), "") ("content", bpo::value<StringsVector>()->default_value(StringsVector(), "")
->multitoken(), "content file(s): esm/esp, or omwgame/omwaddon") ->multitoken(), "content file(s): esm/esp, or omwgame/omwaddon")
("anim-verbose", bpo::value<bool>()->implicit_value(true) ("no-sound", bpo::value<bool>()->implicit_value(true)
->default_value(false), "output animation indices files")
("nosound", bpo::value<bool>()->implicit_value(true)
->default_value(false), "disable all sounds") ->default_value(false), "disable all sounds")
("script-verbose", bpo::value<bool>()->implicit_value(true) ("script-verbose", bpo::value<bool>()->implicit_value(true)
@ -169,8 +165,6 @@ bool parseOptions (int argc, char** argv, OMW::Engine& engine, Files::Configurat
bpo::store(valid_opts, variables); bpo::store(valid_opts, variables);
bpo::notify(variables); bpo::notify(variables);
cfgMgr.readConfiguration(variables, desc);
bool run = true; bool run = true;
if (variables.count ("help")) if (variables.count ("help"))
@ -188,6 +182,8 @@ bool parseOptions (int argc, char** argv, OMW::Engine& engine, Files::Configurat
if (!run) if (!run)
return false; return false;
cfgMgr.readConfiguration(variables, desc);
engine.setGrabMouse(!variables.count("no-grab")); engine.setGrabMouse(!variables.count("no-grab"));
// Font encoding settings // Font encoding settings
@ -238,10 +234,9 @@ bool parseOptions (int argc, char** argv, OMW::Engine& engine, Files::Configurat
engine.setSkipMenu (variables["skip-menu"].as<bool>()); engine.setSkipMenu (variables["skip-menu"].as<bool>());
// other settings // other settings
engine.setSoundUsage(!variables["nosound"].as<bool>()); engine.setSoundUsage(!variables["no-sound"].as<bool>());
engine.setScriptsVerbosity(variables["script-verbose"].as<bool>()); engine.setScriptsVerbosity(variables["script-verbose"].as<bool>());
engine.setCompileAll(variables["script-all"].as<bool>()); engine.setCompileAll(variables["script-all"].as<bool>());
engine.setAnimationVerbose(variables["anim-verbose"].as<bool>());
engine.setFallbackValues(variables["fallback"].as<FallbackMap>().mMap); engine.setFallbackValues(variables["fallback"].as<FallbackMap>().mMap);
engine.setScriptConsoleMode (variables["script-console"].as<bool>()); engine.setScriptConsoleMode (variables["script-console"].as<bool>());
engine.setStartupScript (variables["script-run"].as<std::string>()); engine.setStartupScript (variables["script-run"].as<std::string>());
@ -283,7 +278,7 @@ int main(int argc, char**argv)
catch (std::exception &e) catch (std::exception &e)
{ {
#if OGRE_PLATFORM == OGRE_PLATFORM_LINUX || OGRE_PLATFORM == OGRE_PLATFORM_APPLE #if OGRE_PLATFORM == OGRE_PLATFORM_LINUX || OGRE_PLATFORM == OGRE_PLATFORM_APPLE
if (isatty(fileno(stdin))) if (isatty(fileno(stdin)) || !SDL_WasInit(SDL_INIT_VIDEO))
std::cerr << "\nERROR: " << e.what() << std::endl; std::cerr << "\nERROR: " << e.what() << std::endl;
else else
#endif #endif

@ -153,15 +153,15 @@ void MWBase::Environment::cleanup()
delete mScriptManager; delete mScriptManager;
mScriptManager = 0; mScriptManager = 0;
delete mWindowManager;
mWindowManager = 0;
delete mWorld; delete mWorld;
mWorld = 0; mWorld = 0;
delete mSoundManager; delete mSoundManager;
mSoundManager = 0; mSoundManager = 0;
delete mWindowManager;
mWindowManager = 0;
delete mInputManager; delete mInputManager;
mInputManager = 0; mInputManager = 0;

@ -137,8 +137,8 @@ namespace MWBase
virtual void wmUpdateFps(float fps, unsigned int triangleCount, unsigned int batchCount) = 0; virtual void wmUpdateFps(float fps, unsigned int triangleCount, unsigned int batchCount) = 0;
/// Set value for the given ID. /// Set value for the given ID.
virtual void setValue (const std::string& id, const MWMechanics::Stat<int>& value) = 0; virtual void setValue (const std::string& id, const MWMechanics::AttributeValue& value) = 0;
virtual void setValue (int parSkill, const MWMechanics::Stat<float>& value) = 0; virtual void setValue (int parSkill, const MWMechanics::SkillValue& value) = 0;
virtual void setValue (const std::string& id, const MWMechanics::DynamicStat<float>& value) = 0; virtual void setValue (const std::string& id, const MWMechanics::DynamicStat<float>& value) = 0;
virtual void setValue (const std::string& id, const std::string& value) = 0; virtual void setValue (const std::string& id, const std::string& value) = 0;
virtual void setValue (const std::string& id, int value) = 0; virtual void setValue (const std::string& id, int value) = 0;
@ -204,6 +204,7 @@ namespace MWBase
virtual void activateQuickKey (int index) = 0; virtual void activateQuickKey (int index) = 0;
virtual std::string getSelectedSpell() = 0;
virtual void setSelectedSpell(const std::string& spellId, int successChancePercent) = 0; virtual void setSelectedSpell(const std::string& spellId, int successChancePercent) = 0;
virtual void setSelectedEnchantItem(const MWWorld::Ptr& item) = 0; virtual void setSelectedEnchantItem(const MWWorld::Ptr& item) = 0;
virtual void setSelectedWeapon(const MWWorld::Ptr& item) = 0; virtual void setSelectedWeapon(const MWWorld::Ptr& item) = 0;
@ -235,8 +236,8 @@ namespace MWBase
virtual void onFrame (float frameDuration) = 0; virtual void onFrame (float frameDuration) = 0;
/// \todo get rid of this stuff. Move it to the respective UI element classes, if needed. /// \todo get rid of this stuff. Move it to the respective UI element classes, if needed.
virtual std::map<int, MWMechanics::Stat<float> > getPlayerSkillValues() = 0; virtual std::map<int, MWMechanics::SkillValue > getPlayerSkillValues() = 0;
virtual std::map<int, MWMechanics::Stat<int> > getPlayerAttributeValues() = 0; virtual std::map<int, MWMechanics::AttributeValue > getPlayerAttributeValues() = 0;
virtual SkillList getPlayerMinorSkills() = 0; virtual SkillList getPlayerMinorSkills() = 0;
virtual SkillList getPlayerMajorSkills() = 0; virtual SkillList getPlayerMajorSkills() = 0;

@ -81,7 +81,6 @@ namespace MWBase
Render_CollisionDebug, Render_CollisionDebug,
Render_Wireframe, Render_Wireframe,
Render_Pathgrid, Render_Pathgrid,
Render_Compositors,
Render_BoundingBoxes Render_BoundingBoxes
}; };
@ -142,7 +141,7 @@ namespace MWBase
virtual Ogre::Vector2 getNorthVector (MWWorld::CellStore* cell) = 0; virtual Ogre::Vector2 getNorthVector (MWWorld::CellStore* cell) = 0;
///< get north vector (OGRE coordinates) for given interior cell ///< get north vector (OGRE coordinates) for given interior cell
virtual std::vector<DoorMarker> getDoorMarkers (MWWorld::CellStore* cell) = 0; virtual void getDoorMarkers (MWWorld::CellStore* cell, std::vector<DoorMarker>& out) = 0;
///< get a list of teleport door markers for a given cell, to be displayed on the local map ///< get a list of teleport door markers for a given cell, to be displayed on the local map
virtual void getInteriorMapPosition (Ogre::Vector2 position, float& nX, float& nY, int &x, int& y) = 0; virtual void getInteriorMapPosition (Ogre::Vector2 position, float& nX, float& nY, int &x, int& y) = 0;
@ -440,12 +439,44 @@ namespace MWBase
virtual bool toggleGodMode() = 0; virtual bool toggleGodMode() = 0;
/**
* @brief startSpellCast attempt to start casting a spell. Might fail immediately if conditions are not met.
* @param actor
* @return true if the spell can be casted (i.e. the animation should start)
*/
virtual bool startSpellCast (const MWWorld::Ptr& actor) = 0;
virtual void castSpell (const MWWorld::Ptr& actor) = 0; virtual void castSpell (const MWWorld::Ptr& actor) = 0;
virtual void launchProjectile (const std::string& id, bool stack, const ESM::EffectList& effects, virtual void launchProjectile (const std::string& id, bool stack, const ESM::EffectList& effects,
const MWWorld::Ptr& actor, const std::string& sourceName) = 0; const MWWorld::Ptr& actor, const std::string& sourceName) = 0;
virtual const std::vector<std::string>& getContentFiles() const = 0; virtual const std::vector<std::string>& getContentFiles() const = 0;
virtual void breakInvisibility (const MWWorld::Ptr& actor) = 0;
// Are we in an exterior or pseudo-exterior cell and it's night?
virtual bool isDark() const = 0;
virtual bool findInteriorPositionInWorldSpace(MWWorld::CellStore* cell, Ogre::Vector3& result) = 0;
/// Teleports \a ptr to the reference of \a id (e.g. DivineMarker, PrisonMarker, TempleMarker)
/// closest to \a worldPos.
/// @note id must be lower case
virtual void teleportToClosestMarker (const MWWorld::Ptr& ptr,
const std::string& id, Ogre::Vector3 worldPos) = 0;
enum DetectionType
{
Detect_Enchantment,
Detect_Key,
Detect_Creature
};
/// List all references (filtered by \a type) detected by \a ptr. The range
/// is determined by the current magnitude of the "Detect X" magic effect belonging to \a type.
/// @note This also works for references in containers.
virtual void listDetectedReferences (const MWWorld::Ptr& ptr, std::vector<MWWorld::Ptr>& out,
DetectionType type) = 0;
}; };
} }

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

@ -172,7 +172,7 @@ namespace MWClass
if (ptr.getCellRef().mCharge == -1) if (ptr.getCellRef().mCharge == -1)
return ref->mBase->mData.mValue; return ref->mBase->mData.mValue;
else else
return ref->mBase->mData.mValue * (ptr.getCellRef().mCharge / getItemMaxHealth(ptr)); return ref->mBase->mData.mValue * (static_cast<float>(ptr.getCellRef().mCharge) / getItemMaxHealth(ptr));
} }
void Armor::registerSelf() void Armor::registerSelf()
@ -248,7 +248,7 @@ namespace MWClass
+ MWGui::ToolTips::toString(ref->mBase->mData.mHealth); + MWGui::ToolTips::toString(ref->mBase->mData.mHealth);
text += "\n#{sWeight}: " + MWGui::ToolTips::toString(ref->mBase->mData.mWeight) + " (" + typeText + ")"; text += "\n#{sWeight}: " + MWGui::ToolTips::toString(ref->mBase->mData.mWeight) + " (" + typeText + ")";
text += MWGui::ToolTips::getValueString(ref->mBase->mData.mValue, "#{sValue}"); text += MWGui::ToolTips::getValueString(getValue(ptr), "#{sValue}");
if (MWBase::Environment::get().getWindowManager()->getFullHelp()) { if (MWBase::Environment::get().getWindowManager()->getFullHelp()) {
text += MWGui::ToolTips::getMiscString(ref->mRef.mOwner, "Owner"); text += MWGui::ToolTips::getMiscString(ref->mRef.mOwner, "Owner");
@ -291,44 +291,36 @@ namespace MWClass
{ {
MWWorld::InventoryStore& invStore = MWWorld::Class::get(npc).getInventoryStore(npc); MWWorld::InventoryStore& invStore = MWWorld::Class::get(npc).getInventoryStore(npc);
if (ptr.getCellRef().mCharge == 0)
return std::make_pair(0, "#{sInventoryMessage1}");
// slots that this item can be equipped in // slots that this item can be equipped in
std::pair<std::vector<int>, bool> slots_ = MWWorld::Class::get(ptr).getEquipmentSlots(ptr); std::pair<std::vector<int>, bool> slots_ = MWWorld::Class::get(ptr).getEquipmentSlots(ptr);
if (slots_.first.empty())
return std::make_pair(0, "");
std::string npcRace = npc.get<ESM::NPC>()->mBase->mRace; std::string npcRace = npc.get<ESM::NPC>()->mBase->mRace;
for (std::vector<int>::const_iterator slot=slots_.first.begin(); // Beast races cannot equip shoes / boots, or full helms (head part vs hair part)
slot!=slots_.first.end(); ++slot) const ESM::Race* race = MWBase::Environment::get().getWorld()->getStore().get<ESM::Race>().find(npcRace);
if(race->mData.mFlags & ESM::Race::Beast)
{ {
std::vector<ESM::PartReference> parts = ptr.get<ESM::Armor>()->mBase->mParts.mParts;
// Beast races cannot equip shoes / boots, or full helms (head part vs hair part) for(std::vector<ESM::PartReference>::iterator itr = parts.begin(); itr != parts.end(); ++itr)
const ESM::Race* race = MWBase::Environment::get().getWorld()->getStore().get<ESM::Race>().find(npcRace);
if(race->mData.mFlags & ESM::Race::Beast)
{ {
std::vector<ESM::PartReference> parts = ptr.get<ESM::Armor>()->mBase->mParts.mParts; if((*itr).mPart == ESM::PRT_Head)
return std::make_pair(0, "#{sNotifyMessage13}");
if(*slot == MWWorld::InventoryStore::Slot_Helmet) if((*itr).mPart == ESM::PRT_LFoot || (*itr).mPart == ESM::PRT_RFoot)
{ return std::make_pair(0, "#{sNotifyMessage14}");
for(std::vector<ESM::PartReference>::iterator itr = parts.begin(); itr != parts.end(); ++itr)
{
if((*itr).mPart == ESM::PRT_Head)
{
return std::make_pair(0, "#{sNotifyMessage13}");
}
}
}
if (*slot == MWWorld::InventoryStore::Slot_Boots)
{
for(std::vector<ESM::PartReference>::iterator itr = parts.begin(); itr != parts.end(); ++itr)
{
if((*itr).mPart == ESM::PRT_LFoot || (*itr).mPart == ESM::PRT_RFoot)
{
return std::make_pair(0, "#{sNotifyMessage14}");
}
}
}
} }
}
for (std::vector<int>::const_iterator slot=slots_.first.begin();
slot!=slots_.first.end(); ++slot)
{
// If equipping a shield, check if there's a twohanded weapon conflicting with it
if(*slot == MWWorld::InventoryStore::Slot_CarriedLeft) if(*slot == MWWorld::InventoryStore::Slot_CarriedLeft)
{ {
MWWorld::ContainerStoreIterator weapon = invStore.getSlot(MWWorld::InventoryStore::Slot_CarriedRight); MWWorld::ContainerStoreIterator weapon = invStore.getSlot(MWWorld::InventoryStore::Slot_CarriedRight);

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

@ -191,7 +191,7 @@ namespace MWClass
std::string text; std::string text;
text += "\n#{sWeight}: " + MWGui::ToolTips::toString(ref->mBase->mData.mWeight); text += "\n#{sWeight}: " + MWGui::ToolTips::toString(ref->mBase->mData.mWeight);
text += MWGui::ToolTips::getValueString(ref->mBase->mData.mValue, "#{sValue}"); text += MWGui::ToolTips::getValueString(getValue(ptr), "#{sValue}");
if (MWBase::Environment::get().getWindowManager()->getFullHelp()) { if (MWBase::Environment::get().getWindowManager()->getFullHelp()) {
text += MWGui::ToolTips::getMiscString(ref->mRef.mOwner, "Owner"); text += MWGui::ToolTips::getMiscString(ref->mRef.mOwner, "Owner");
@ -235,37 +235,26 @@ namespace MWClass
// slots that this item can be equipped in // slots that this item can be equipped in
std::pair<std::vector<int>, bool> slots_ = MWWorld::Class::get(ptr).getEquipmentSlots(ptr); std::pair<std::vector<int>, bool> slots_ = MWWorld::Class::get(ptr).getEquipmentSlots(ptr);
if (slots_.first.empty())
return std::make_pair(0, "");
std::string npcRace = npc.get<ESM::NPC>()->mBase->mRace; std::string npcRace = npc.get<ESM::NPC>()->mBase->mRace;
for (std::vector<int>::const_iterator slot=slots_.first.begin(); // Beast races cannot equip shoes / boots, or full helms (head part vs hair part)
slot!=slots_.first.end(); ++slot) const ESM::Race* race = MWBase::Environment::get().getWorld()->getStore().get<ESM::Race>().find(npcRace);
if(race->mData.mFlags & ESM::Race::Beast)
{ {
std::vector<ESM::PartReference> parts = ptr.get<ESM::Clothing>()->mBase->mParts.mParts;
// Beast races cannot equip shoes / boots, or full helms (head part vs hair part) for(std::vector<ESM::PartReference>::iterator itr = parts.begin(); itr != parts.end(); ++itr)
const ESM::Race* race = MWBase::Environment::get().getWorld()->getStore().get<ESM::Race>().find(npcRace);
if(race->mData.mFlags & ESM::Race::Beast)
{ {
std::vector<ESM::PartReference> parts = ptr.get<ESM::Clothing>()->mBase->mParts.mParts; if((*itr).mPart == ESM::PRT_Head)
return std::make_pair(0, "#{sNotifyMessage13}");
if(*slot == MWWorld::InventoryStore::Slot_Helmet) if((*itr).mPart == ESM::PRT_LFoot || (*itr).mPart == ESM::PRT_RFoot)
{ return std::make_pair(0, "#{sNotifyMessage15}");
for(std::vector<ESM::PartReference>::iterator itr = parts.begin(); itr != parts.end(); ++itr)
{
if((*itr).mPart == ESM::PRT_Head)
return std::make_pair(0, "#{sNotifyMessage13}");
}
}
if (*slot == MWWorld::InventoryStore::Slot_Boots)
{
for(std::vector<ESM::PartReference>::iterator itr = parts.begin(); itr != parts.end(); ++itr)
{
if((*itr).mPart == ESM::PRT_LFoot || (*itr).mPart == ESM::PRT_RFoot)
return std::make_pair(0, "#{sNotifyMessage15}");
}
}
} }
} }
return std::make_pair (1, ""); return std::make_pair (1, "");
} }

@ -68,14 +68,14 @@ namespace MWClass
MWWorld::LiveCellRef<ESM::Creature> *ref = ptr.get<ESM::Creature>(); MWWorld::LiveCellRef<ESM::Creature> *ref = ptr.get<ESM::Creature>();
// creature stats // creature stats
data->mCreatureStats.getAttribute(0).set (ref->mBase->mData.mStrength); data->mCreatureStats.setAttribute(ESM::Attribute::Strength, ref->mBase->mData.mStrength);
data->mCreatureStats.getAttribute(1).set (ref->mBase->mData.mIntelligence); data->mCreatureStats.setAttribute(ESM::Attribute::Intelligence, ref->mBase->mData.mIntelligence);
data->mCreatureStats.getAttribute(2).set (ref->mBase->mData.mWillpower); data->mCreatureStats.setAttribute(ESM::Attribute::Willpower, ref->mBase->mData.mWillpower);
data->mCreatureStats.getAttribute(3).set (ref->mBase->mData.mAgility); data->mCreatureStats.setAttribute(ESM::Attribute::Agility, ref->mBase->mData.mAgility);
data->mCreatureStats.getAttribute(4).set (ref->mBase->mData.mSpeed); data->mCreatureStats.setAttribute(ESM::Attribute::Speed, ref->mBase->mData.mSpeed);
data->mCreatureStats.getAttribute(5).set (ref->mBase->mData.mEndurance); data->mCreatureStats.setAttribute(ESM::Attribute::Endurance, ref->mBase->mData.mEndurance);
data->mCreatureStats.getAttribute(6).set (ref->mBase->mData.mPersonality); data->mCreatureStats.setAttribute(ESM::Attribute::Personality, ref->mBase->mData.mPersonality);
data->mCreatureStats.getAttribute(7).set (ref->mBase->mData.mLuck); data->mCreatureStats.setAttribute(ESM::Attribute::Luck, ref->mBase->mData.mLuck);
data->mCreatureStats.setHealth (ref->mBase->mData.mHealth); data->mCreatureStats.setHealth (ref->mBase->mData.mHealth);
data->mCreatureStats.setMagicka (ref->mBase->mData.mMana); data->mCreatureStats.setMagicka (ref->mBase->mData.mMana);
data->mCreatureStats.setFatigue (ref->mBase->mData.mFatigue); data->mCreatureStats.setFatigue (ref->mBase->mData.mFatigue);
@ -84,10 +84,10 @@ namespace MWClass
data->mCreatureStats.getAiSequence().fill(ref->mBase->mAiPackage); data->mCreatureStats.getAiSequence().fill(ref->mBase->mAiPackage);
data->mCreatureStats.setAiSetting (0, ref->mBase->mAiData.mHello); data->mCreatureStats.setAiSetting (MWMechanics::CreatureStats::AI_Hello, ref->mBase->mAiData.mHello);
data->mCreatureStats.setAiSetting (1, ref->mBase->mAiData.mFight); data->mCreatureStats.setAiSetting (MWMechanics::CreatureStats::AI_Fight, ref->mBase->mAiData.mFight);
data->mCreatureStats.setAiSetting (2, ref->mBase->mAiData.mFlee); data->mCreatureStats.setAiSetting (MWMechanics::CreatureStats::AI_Flee, ref->mBase->mAiData.mFlee);
data->mCreatureStats.setAiSetting (3, ref->mBase->mAiData.mAlarm); data->mCreatureStats.setAiSetting (MWMechanics::CreatureStats::AI_Alarm, ref->mBase->mAiData.mAlarm);
// spells // spells
for (std::vector<std::string>::const_iterator iter (ref->mBase->mSpells.mList.begin()); for (std::vector<std::string>::const_iterator iter (ref->mBase->mSpells.mList.begin());
@ -199,7 +199,7 @@ namespace MWClass
else else
{ {
MWMechanics::DynamicStat<float> fatigue(getCreatureStats(ptr).getFatigue()); MWMechanics::DynamicStat<float> fatigue(getCreatureStats(ptr).getFatigue());
fatigue.setCurrent(fatigue.getCurrent() - damage); fatigue.setCurrent(fatigue.getCurrent() - damage, true);
getCreatureStats(ptr).setFatigue(fatigue); getCreatureStats(ptr).setFatigue(fatigue);
} }
} }
@ -413,6 +413,14 @@ namespace MWClass
return MWWorld::Ptr(&cell.mCreatures.insert(*ref), &cell); return MWWorld::Ptr(&cell.mCreatures.insert(*ref), &cell);
} }
bool Creature::isFlying(const MWWorld::Ptr &ptr) const
{
MWWorld::LiveCellRef<ESM::Creature> *ref =
ptr.get<ESM::Creature>();
return ref->mBase->mFlags & ESM::Creature::Flies;
}
int Creature::getSndGenTypeFromName(const MWWorld::Ptr &ptr, const std::string &name) int Creature::getSndGenTypeFromName(const MWWorld::Ptr &ptr, const std::string &name)
{ {
if(name == "left") if(name == "left")

@ -99,6 +99,8 @@ namespace MWClass
isActor() const { isActor() const {
return true; return true;
} }
virtual bool isFlying (const MWWorld::Ptr &ptr) const;
}; };
} }

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

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

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

@ -242,7 +242,11 @@ namespace MWClass
item.get<ESM::Miscellaneous>(); item.get<ESM::Miscellaneous>();
return !ref->mBase->mData.mIsKey && (npcServices & ESM::NPC::Misc) return !ref->mBase->mData.mIsKey && (npcServices & ESM::NPC::Misc)
&& !Misc::StringUtils::ciEqual(item.getCellRef().mRefID, "gold_001"); && !Misc::StringUtils::ciEqual(item.getCellRef().mRefID, "gold_001")
&& !Misc::StringUtils::ciEqual(item.getCellRef().mRefID, "gold_005")
&& !Misc::StringUtils::ciEqual(item.getCellRef().mRefID, "gold_010")
&& !Misc::StringUtils::ciEqual(item.getCellRef().mRefID, "gold_025")
&& !Misc::StringUtils::ciEqual(item.getCellRef().mRefID, "gold_100");
} }
float Miscellaneous::getWeight(const MWWorld::Ptr &ptr) const float Miscellaneous::getWeight(const MWWorld::Ptr &ptr) const
@ -252,4 +256,11 @@ namespace MWClass
return ref->mBase->mData.mWeight; return ref->mBase->mData.mWeight;
} }
bool Miscellaneous::isKey(const MWWorld::Ptr &ptr) const
{
MWWorld::LiveCellRef<ESM::Miscellaneous> *ref =
ptr.get<ESM::Miscellaneous>();
return ref->mBase->mData.mIsKey;
}
} }

@ -57,6 +57,8 @@ namespace MWClass
virtual float getWeight (const MWWorld::Ptr& ptr) const; virtual float getWeight (const MWWorld::Ptr& ptr) const;
virtual bool canSell (const MWWorld::Ptr& item, int npcServices) const; virtual bool canSell (const MWWorld::Ptr& item, int npcServices) const;
virtual bool isKey (const MWWorld::Ptr &ptr) const;
}; };
} }

@ -21,6 +21,7 @@
#include "../mwmechanics/npcstats.hpp" #include "../mwmechanics/npcstats.hpp"
#include "../mwmechanics/movement.hpp" #include "../mwmechanics/movement.hpp"
#include "../mwmechanics/spellcasting.hpp" #include "../mwmechanics/spellcasting.hpp"
#include "../mwmechanics/disease.hpp"
#include "../mwworld/ptr.hpp" #include "../mwworld/ptr.hpp"
#include "../mwworld/actiontalk.hpp" #include "../mwworld/actiontalk.hpp"
@ -63,11 +64,10 @@ namespace
bool male = (npc->mFlags & ESM::NPC::Female) == 0; bool male = (npc->mFlags & ESM::NPC::Female) == 0;
int level = creatureStats.getLevel(); int level = creatureStats.getLevel();
for (int i=0; i<ESM::Attribute::Length; ++i) for (int i=0; i<ESM::Attribute::Length; ++i)
{ {
const ESM::Race::MaleFemale& attribute = race->mData.mAttributeValues[i]; const ESM::Race::MaleFemale& attribute = race->mData.mAttributeValues[i];
creatureStats.getAttribute(i).setBase (male ? attribute.mMale : attribute.mFemale); creatureStats.setAttribute(i, male ? attribute.mMale : attribute.mFemale);
} }
// class bonus // class bonus
@ -79,13 +79,13 @@ namespace
int attribute = class_->mData.mAttribute[i]; int attribute = class_->mData.mAttribute[i];
if (attribute>=0 && attribute<8) if (attribute>=0 && attribute<8)
{ {
creatureStats.getAttribute(attribute).setBase ( creatureStats.setAttribute(attribute,
creatureStats.getAttribute(attribute).getBase() + 10); creatureStats.getAttribute(attribute).getBase() + 10);
} }
} }
// skill bonus // skill bonus
for (int attribute=0; attribute<ESM::Attribute::Length; ++attribute) for (int attribute=0; attribute < ESM::Attribute::Length; ++attribute)
{ {
float modifierSum = 0; float modifierSum = 0;
@ -110,7 +110,7 @@ namespace
} }
modifierSum += add; modifierSum += add;
} }
creatureStats.getAttribute(attribute).setBase ( std::min(creatureStats.getAttribute(attribute).getBase() creatureStats.setAttribute(attribute, std::min(creatureStats.getAttribute(attribute).getBase()
+ static_cast<int>((level-1) * modifierSum+0.5), 100) ); + static_cast<int>((level-1) * modifierSum+0.5), 100) );
} }
@ -131,6 +131,89 @@ namespace
creatureStats.setHealth(static_cast<int> (0.5 * (strength + endurance)) + multiplier * (creatureStats.getLevel() - 1)); creatureStats.setHealth(static_cast<int> (0.5 * (strength + endurance)) + multiplier * (creatureStats.getLevel() - 1));
} }
/**
* @brief autoCalculateSkills
*
* Skills are calculated with following formulae ( http://www.uesp.net/wiki/Morrowind:NPCs#Skills ):
*
* Skills: (Level - 1) × (Majority Multiplier + Specialization Multiplier)
*
* The Majority Multiplier is 1.0 for a Major or Minor Skill, or 0.1 for a Miscellaneous Skill.
*
* The Specialization Multiplier is 0.5 for a Skill in the same Specialization as the class,
* zero for other Skills.
*
* and by adding class, race, specialization bonus.
*/
void autoCalculateSkills(const ESM::NPC* npc, MWMechanics::NpcStats& npcStats)
{
const ESM::Class *class_ =
MWBase::Environment::get().getWorld()->getStore().get<ESM::Class>().find(npc->mClass);
unsigned int level = npcStats.getLevel();
const ESM::Race *race = MWBase::Environment::get().getWorld()->getStore().get<ESM::Race>().find(npc->mRace);
for (int i = 0; i < 2; ++i)
{
int bonus = (i==0) ? 10 : 25;
for (int i2 = 0; i2 < 5; ++i2)
{
int index = class_->mData.mSkills[i2][i];
if (index >= 0 && index < ESM::Skill::Length)
{
npcStats.getSkill(index).setBase (npcStats.getSkill(index).getBase() + bonus);
}
}
}
for (int skillIndex = 0; skillIndex < ESM::Skill::Length; ++skillIndex)
{
float majorMultiplier = 0.1f;
float specMultiplier = 0.0f;
int raceBonus = 0;
int specBonus = 0;
for (int raceSkillIndex = 0; raceSkillIndex < 7; ++raceSkillIndex)
{
if (race->mData.mBonus[raceSkillIndex].mSkill == skillIndex)
{
raceBonus = race->mData.mBonus[raceSkillIndex].mBonus;
break;
}
}
for (int k = 0; k < 5; ++k)
{
// is this a minor or major skill?
if ((class_->mData.mSkills[k][0] == skillIndex) || (class_->mData.mSkills[k][1] == skillIndex))
{
majorMultiplier = 1.0f;
break;
}
}
// is this skill in the same Specialization as the class?
const ESM::Skill* skill = MWBase::Environment::get().getWorld()->getStore().get<ESM::Skill>().find(skillIndex);
if (skill->mData.mSpecialization == class_->mData.mSpecialization)
{
specMultiplier = 0.5f;
specBonus = 5;
}
npcStats.getSkill(skillIndex).setBase(
std::min(
npcStats.getSkill(skillIndex).getBase()
+ 5
+ raceBonus
+ specBonus
+ static_cast<int>((level-1) * (majorMultiplier + specMultiplier)), 100));
}
}
} }
namespace MWClass namespace MWClass
@ -173,7 +256,7 @@ namespace MWClass
{ {
std::string faction = ref->mBase->mFaction; std::string faction = ref->mBase->mFaction;
Misc::StringUtils::toLower(faction); Misc::StringUtils::toLower(faction);
if(ref->mBase->mNpdt52.mGold != -10) if(ref->mBase->mNpdtType != ESM::NPC::NPC_WITH_AUTOCALCULATED_STATS)
{ {
data->mNpcStats.getFactionRanks()[faction] = (int)ref->mBase->mNpdt52.mRank; data->mNpcStats.getFactionRanks()[faction] = (int)ref->mBase->mNpdt52.mRank;
} }
@ -185,21 +268,22 @@ namespace MWClass
// creature stats // creature stats
int gold=0; int gold=0;
if(ref->mBase->mNpdt52.mGold != -10) if(ref->mBase->mNpdtType != ESM::NPC::NPC_WITH_AUTOCALCULATED_STATS)
{ {
gold = ref->mBase->mNpdt52.mGold; gold = ref->mBase->mNpdt52.mGold;
for (int i=0; i<27; ++i) for (unsigned int i=0; i< ESM::Skill::Length; ++i)
data->mNpcStats.getSkill (i).setBase (ref->mBase->mNpdt52.mSkills[i]); data->mNpcStats.getSkill (i).setBase (ref->mBase->mNpdt52.mSkills[i]);
data->mNpcStats.getAttribute(0).set (ref->mBase->mNpdt52.mStrength); data->mNpcStats.setAttribute(ESM::Attribute::Strength, ref->mBase->mNpdt52.mStrength);
data->mNpcStats.getAttribute(1).set (ref->mBase->mNpdt52.mIntelligence); data->mNpcStats.setAttribute(ESM::Attribute::Intelligence, ref->mBase->mNpdt52.mIntelligence);
data->mNpcStats.getAttribute(2).set (ref->mBase->mNpdt52.mWillpower); data->mNpcStats.setAttribute(ESM::Attribute::Willpower, ref->mBase->mNpdt52.mWillpower);
data->mNpcStats.getAttribute(3).set (ref->mBase->mNpdt52.mAgility); data->mNpcStats.setAttribute(ESM::Attribute::Agility, ref->mBase->mNpdt52.mAgility);
data->mNpcStats.getAttribute(4).set (ref->mBase->mNpdt52.mSpeed); data->mNpcStats.setAttribute(ESM::Attribute::Speed, ref->mBase->mNpdt52.mSpeed);
data->mNpcStats.getAttribute(5).set (ref->mBase->mNpdt52.mEndurance); data->mNpcStats.setAttribute(ESM::Attribute::Endurance, ref->mBase->mNpdt52.mEndurance);
data->mNpcStats.getAttribute(6).set (ref->mBase->mNpdt52.mPersonality); data->mNpcStats.setAttribute(ESM::Attribute::Personality, ref->mBase->mNpdt52.mPersonality);
data->mNpcStats.getAttribute(7).set (ref->mBase->mNpdt52.mLuck); data->mNpcStats.setAttribute(ESM::Attribute::Luck, ref->mBase->mNpdt52.mLuck);
data->mNpcStats.setHealth (ref->mBase->mNpdt52.mHealth); data->mNpcStats.setHealth (ref->mBase->mNpdt52.mHealth);
data->mNpcStats.setMagicka (ref->mBase->mNpdt52.mMana); data->mNpcStats.setMagicka (ref->mBase->mNpdt52.mMana);
data->mNpcStats.setFatigue (ref->mBase->mNpdt52.mFatigue); data->mNpcStats.setFatigue (ref->mBase->mNpdt52.mFatigue);
@ -220,14 +304,15 @@ namespace MWClass
data->mNpcStats.setReputation(ref->mBase->mNpdt12.mReputation); data->mNpcStats.setReputation(ref->mBase->mNpdt12.mReputation);
autoCalculateAttributes(ref->mBase, data->mNpcStats); autoCalculateAttributes(ref->mBase, data->mNpcStats);
autoCalculateSkills(ref->mBase, data->mNpcStats);
} }
data->mNpcStats.getAiSequence().fill(ref->mBase->mAiPackage); data->mNpcStats.getAiSequence().fill(ref->mBase->mAiPackage);
data->mNpcStats.setAiSetting (0, ref->mBase->mAiData.mHello); data->mNpcStats.setAiSetting (MWMechanics::CreatureStats::AI_Hello, ref->mBase->mAiData.mHello);
data->mNpcStats.setAiSetting (1, ref->mBase->mAiData.mFight); data->mNpcStats.setAiSetting (MWMechanics::CreatureStats::AI_Fight, ref->mBase->mAiData.mFight);
data->mNpcStats.setAiSetting (2, ref->mBase->mAiData.mFlee); data->mNpcStats.setAiSetting (MWMechanics::CreatureStats::AI_Flee, ref->mBase->mAiData.mFlee);
data->mNpcStats.setAiSetting (3, ref->mBase->mAiData.mAlarm); data->mNpcStats.setAiSetting (MWMechanics::CreatureStats::AI_Alarm, ref->mBase->mAiData.mAlarm);
// spells // spells
for (std::vector<std::string>::const_iterator iter (ref->mBase->mSpells.mList.begin()); for (std::vector<std::string>::const_iterator iter (ref->mBase->mSpells.mList.begin());
@ -366,8 +451,8 @@ namespace MWClass
(stats.getAttribute(ESM::Attribute::Agility).getModified() / 5.0f) + (stats.getAttribute(ESM::Attribute::Agility).getModified() / 5.0f) +
(stats.getAttribute(ESM::Attribute::Luck).getModified() / 10.0f); (stats.getAttribute(ESM::Attribute::Luck).getModified() / 10.0f);
hitchance *= stats.getFatigueTerm(); hitchance *= stats.getFatigueTerm();
hitchance += mageffects.get(MWMechanics::EffectKey(ESM::MagicEffect::FortifyAttack)).mMagnitude - hitchance += mageffects.get(ESM::MagicEffect::FortifyAttack).mMagnitude -
mageffects.get(MWMechanics::EffectKey(ESM::MagicEffect::Blind)).mMagnitude; mageffects.get(ESM::MagicEffect::Blind).mMagnitude;
hitchance -= otherstats.getEvasion(); hitchance -= otherstats.getEvasion();
if((::rand()/(RAND_MAX+1.0)) > hitchance/100.0f) if((::rand()/(RAND_MAX+1.0)) > hitchance/100.0f)
@ -409,6 +494,11 @@ namespace MWClass
if (!MWBase::Environment::get().getWorld()->getGodModeState()) if (!MWBase::Environment::get().getWorld()->getGodModeState())
weapon.getCellRef().mCharge -= std::min(std::max(1, weapon.getCellRef().mCharge -= std::min(std::max(1,
(int)(damage * gmst.find("fWeaponDamageMult")->getFloat())), weapon.getCellRef().mCharge); (int)(damage * gmst.find("fWeaponDamageMult")->getFloat())), weapon.getCellRef().mCharge);
// Weapon broken? unequip it
if (weapon.getCellRef().mCharge == 0)
weapon = *inv.unequipItem(weapon, ptr);
} }
healthdmg = true; healthdmg = true;
} }
@ -428,7 +518,8 @@ namespace MWClass
MWBase::Environment::get().getSoundManager()->playSound3D(victim, "critical damage", 1.0f, 1.0f); MWBase::Environment::get().getSoundManager()->playSound3D(victim, "critical damage", 1.0f, 1.0f);
} }
healthdmg = (otherstats.getFatigue().getCurrent() < 1.0f); healthdmg = (otherstats.getFatigue().getCurrent() < 1.0f)
|| (otherstats.getMagicEffects().get(ESM::MagicEffect::Paralyze).mMagnitude > 0);
if(stats.isWerewolf()) if(stats.isWerewolf())
{ {
healthdmg = true; healthdmg = true;
@ -514,12 +605,15 @@ namespace MWClass
ptr.getRefData().getLocals().setVarByInt(script, "onpchitme", 1); ptr.getRefData().getLocals().setVarByInt(script, "onpchitme", 1);
} }
if (!attacker.isEmpty())
MWMechanics::diseaseContact(ptr, attacker);
if(damage > 0.0f) if(damage > 0.0f)
{ {
// 'ptr' is losing health. Play a 'hit' voiced dialog entry if not already saying // 'ptr' is losing health. Play a 'hit' voiced dialog entry if not already saying
// something, alert the character controller, scripts, etc. // something, alert the character controller, scripts, etc.
MWBase::Environment::get().getDialogueManager()->say(ptr, "hit"); MWBase::Environment::get().getDialogueManager()->say(ptr, "thief");
if(object.isEmpty()) if(object.isEmpty())
{ {
@ -560,6 +654,11 @@ namespace MWClass
armorref.mCharge = armor.get<ESM::Armor>()->mBase->mData.mHealth; armorref.mCharge = armor.get<ESM::Armor>()->mBase->mData.mHealth;
armorref.mCharge -= std::min(std::max(1, (int)damagediff), armorref.mCharge -= std::min(std::max(1, (int)damagediff),
armorref.mCharge); armorref.mCharge);
// Armor broken? unequip it
if (armorref.mCharge == 0)
inv.unequipItem(armor, ptr);
switch(get(armor).getEquipmentSkill(armor)) switch(get(armor).getEquipmentSkill(armor))
{ {
case ESM::Skill::LightArmor: case ESM::Skill::LightArmor:
@ -586,7 +685,7 @@ namespace MWClass
else else
{ {
MWMechanics::DynamicStat<float> fatigue(getCreatureStats(ptr).getFatigue()); MWMechanics::DynamicStat<float> fatigue(getCreatureStats(ptr).getFatigue());
fatigue.setCurrent(fatigue.getCurrent() - damage); fatigue.setCurrent(fatigue.getCurrent() - damage, true);
getCreatureStats(ptr).setFatigue(fatigue); getCreatureStats(ptr).setFatigue(fatigue);
} }
} }
@ -628,6 +727,8 @@ namespace MWClass
return boost::shared_ptr<MWWorld::Action>(new MWWorld::ActionOpen(ptr, true)); return boost::shared_ptr<MWWorld::Action>(new MWWorld::ActionOpen(ptr, true));
if(get(actor).getStance(actor, MWWorld::Class::Sneak)) if(get(actor).getStance(actor, MWWorld::Class::Sneak))
return boost::shared_ptr<MWWorld::Action>(new MWWorld::ActionOpen(ptr)); // stealing return boost::shared_ptr<MWWorld::Action>(new MWWorld::ActionOpen(ptr)); // stealing
if(get(ptr).getCreatureStats(ptr).isHostile())
return boost::shared_ptr<MWWorld::Action>(new MWWorld::FailedAction("#{sActorInCombat}"));
return boost::shared_ptr<MWWorld::Action>(new MWWorld::ActionTalk(ptr)); return boost::shared_ptr<MWWorld::Action>(new MWWorld::ActionTalk(ptr));
} }
@ -752,10 +853,11 @@ namespace MWClass
float moveSpeed; float moveSpeed;
if(normalizedEncumbrance >= 1.0f) if(normalizedEncumbrance >= 1.0f)
moveSpeed = 0.0f; moveSpeed = 0.0f;
else if(mageffects.get(MWMechanics::EffectKey(10/*levitate*/)).mMagnitude > 0) else if(mageffects.get(ESM::MagicEffect::Levitate).mMagnitude > 0 &&
world->isLevitationEnabled())
{ {
float flySpeed = 0.01f*(npcdata->mNpcStats.getAttribute(ESM::Attribute::Speed).getModified() + float flySpeed = 0.01f*(npcdata->mNpcStats.getAttribute(ESM::Attribute::Speed).getModified() +
mageffects.get(MWMechanics::EffectKey(10/*levitate*/)).mMagnitude); mageffects.get(ESM::MagicEffect::Levitate).mMagnitude);
flySpeed = fMinFlySpeed->getFloat() + flySpeed*(fMaxFlySpeed->getFloat() - fMinFlySpeed->getFloat()); flySpeed = fMinFlySpeed->getFloat() + flySpeed*(fMaxFlySpeed->getFloat() - fMinFlySpeed->getFloat());
flySpeed *= 1.0f - fEncumberedMoveEffect->getFloat() * normalizedEncumbrance; flySpeed *= 1.0f - fEncumberedMoveEffect->getFloat() * normalizedEncumbrance;
flySpeed = std::max(0.0f, flySpeed); flySpeed = std::max(0.0f, flySpeed);
@ -766,7 +868,7 @@ namespace MWClass
float swimSpeed = walkSpeed; float swimSpeed = walkSpeed;
if(Npc::getStance(ptr, Run, false)) if(Npc::getStance(ptr, Run, false))
swimSpeed = runSpeed; swimSpeed = runSpeed;
swimSpeed *= 1.0f + 0.01f * mageffects.get(MWMechanics::EffectKey(1/*swift swim*/)).mMagnitude; swimSpeed *= 1.0f + 0.01f * mageffects.get(ESM::MagicEffect::SwiftSwim).mMagnitude;
swimSpeed *= fSwimRunBase->getFloat() + 0.01f*npcdata->mNpcStats.getSkill(ESM::Skill::Athletics).getModified()* swimSpeed *= fSwimRunBase->getFloat() + 0.01f*npcdata->mNpcStats.getSkill(ESM::Skill::Athletics).getModified()*
fSwimRunAthleticsMult->getFloat(); fSwimRunAthleticsMult->getFloat();
moveSpeed = swimSpeed; moveSpeed = swimSpeed;
@ -800,7 +902,7 @@ namespace MWClass
float x = fJumpAcrobaticsBase->getFloat() + float x = fJumpAcrobaticsBase->getFloat() +
std::pow(a / 15.0f, fJumpAcroMultiplier->getFloat()); std::pow(a / 15.0f, fJumpAcroMultiplier->getFloat());
x += 3.0f * b * fJumpAcroMultiplier->getFloat(); x += 3.0f * b * fJumpAcroMultiplier->getFloat();
x += mageffects.get(MWMechanics::EffectKey(ESM::MagicEffect::Jump)).mMagnitude * 64; x += mageffects.get(ESM::MagicEffect::Jump).mMagnitude * 64;
x *= encumbranceTerm; x *= encumbranceTerm;
if(Npc::getStance(ptr, Run, false)) if(Npc::getStance(ptr, Run, false))
@ -823,7 +925,7 @@ namespace MWClass
{ {
const float acrobaticsSkill = MWWorld::Class::get(ptr).getNpcStats (ptr).getSkill(ESM::Skill::Acrobatics).getModified(); const float acrobaticsSkill = MWWorld::Class::get(ptr).getNpcStats (ptr).getSkill(ESM::Skill::Acrobatics).getModified();
const CustomData *npcdata = static_cast<const CustomData*>(ptr.getRefData().getCustomData()); const CustomData *npcdata = static_cast<const CustomData*>(ptr.getRefData().getCustomData());
const float jumpSpellBonus = npcdata->mNpcStats.getMagicEffects().get(MWMechanics::EffectKey(ESM::MagicEffect::Jump)).mMagnitude; const float jumpSpellBonus = npcdata->mNpcStats.getMagicEffects().get(ESM::MagicEffect::Jump).mMagnitude;
const float fallAcroBase = gmst.find("fFallAcroBase")->getFloat(); const float fallAcroBase = gmst.find("fFallAcroBase")->getFloat();
const float fallAcroMult = gmst.find("fFallAcroMult")->getFloat(); const float fallAcroMult = gmst.find("fFallAcroMult")->getFloat();
const float fallDistanceBase = gmst.find("fFallDistanceBase")->getFloat(); const float fallDistanceBase = gmst.find("fFallDistanceBase")->getFloat();
@ -928,8 +1030,8 @@ namespace MWClass
if(!stats.isWerewolf()) if(!stats.isWerewolf())
{ {
weight = getContainerStore(ptr).getWeight(); weight = getContainerStore(ptr).getWeight();
weight -= stats.getMagicEffects().get(MWMechanics::EffectKey(ESM::MagicEffect::Feather)).mMagnitude; weight -= stats.getMagicEffects().get(ESM::MagicEffect::Feather).mMagnitude;
weight += stats.getMagicEffects().get(MWMechanics::EffectKey(ESM::MagicEffect::Burden)).mMagnitude; weight += stats.getMagicEffects().get(ESM::MagicEffect::Burden).mMagnitude;
if(weight < 0.0f) if(weight < 0.0f)
weight = 0.0f; weight = 0.0f;
} }

@ -128,7 +128,7 @@ namespace MWClass
std::string text; std::string text;
text += "\n#{sWeight}: " + MWGui::ToolTips::toString(ref->mBase->mData.mWeight); text += "\n#{sWeight}: " + MWGui::ToolTips::toString(ref->mBase->mData.mWeight);
text += MWGui::ToolTips::getValueString(ref->mBase->mData.mValue, "#{sValue}"); text += MWGui::ToolTips::getValueString(getValue(ptr), "#{sValue}");
info.effects = MWGui::Widgets::MWEffectList::effectListFromESM(&ref->mBase->mEffects); info.effects = MWGui::Widgets::MWEffectList::effectListFromESM(&ref->mBase->mEffects);

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

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

@ -157,7 +157,7 @@ namespace MWClass
if (ptr.getCellRef().mCharge == -1) if (ptr.getCellRef().mCharge == -1)
return ref->mBase->mData.mValue; return ref->mBase->mData.mValue;
else else
return ref->mBase->mData.mValue * (ptr.getCellRef().mCharge / getItemMaxHealth(ptr)); return ref->mBase->mData.mValue * (static_cast<float>(ptr.getCellRef().mCharge) / getItemMaxHealth(ptr));
} }
void Weapon::registerSelf() void Weapon::registerSelf()
@ -346,7 +346,7 @@ namespace MWClass
} }
text += "\n#{sWeight}: " + MWGui::ToolTips::toString(ref->mBase->mData.mWeight); text += "\n#{sWeight}: " + MWGui::ToolTips::toString(ref->mBase->mData.mWeight);
text += MWGui::ToolTips::getValueString(ref->mBase->mData.mValue, "#{sValue}"); text += MWGui::ToolTips::getValueString(getValue(ptr), "#{sValue}");
info.enchant = ref->mBase->mEnchant; info.enchant = ref->mBase->mEnchant;
@ -388,28 +388,26 @@ namespace MWClass
std::pair<int, std::string> Weapon::canBeEquipped(const MWWorld::Ptr &ptr, const MWWorld::Ptr &npc) const std::pair<int, std::string> Weapon::canBeEquipped(const MWWorld::Ptr &ptr, const MWWorld::Ptr &npc) const
{ {
if (ptr.getCellRef().mCharge == 0)
return std::make_pair(0, "#{sInventoryMessage1}");
std::pair<std::vector<int>, bool> slots_ = MWWorld::Class::get(ptr).getEquipmentSlots(ptr); std::pair<std::vector<int>, bool> slots_ = MWWorld::Class::get(ptr).getEquipmentSlots(ptr);
// equip the item in the first free slot if (slots_.first.empty())
for (std::vector<int>::const_iterator slot=slots_.first.begin(); return std::make_pair (0, "");
slot!=slots_.first.end(); ++slot)
if(ptr.get<ESM::Weapon>()->mBase->mData.mType == ESM::Weapon::LongBladeTwoHand ||
ptr.get<ESM::Weapon>()->mBase->mData.mType == ESM::Weapon::BluntTwoClose ||
ptr.get<ESM::Weapon>()->mBase->mData.mType == ESM::Weapon::BluntTwoWide ||
ptr.get<ESM::Weapon>()->mBase->mData.mType == ESM::Weapon::SpearTwoWide ||
ptr.get<ESM::Weapon>()->mBase->mData.mType == ESM::Weapon::AxeTwoHand ||
ptr.get<ESM::Weapon>()->mBase->mData.mType == ESM::Weapon::MarksmanBow ||
ptr.get<ESM::Weapon>()->mBase->mData.mType == ESM::Weapon::MarksmanCrossbow)
{ {
if(*slot == MWWorld::InventoryStore::Slot_CarriedRight) return std::make_pair (2, "");
{
if(ptr.get<ESM::Weapon>()->mBase->mData.mType == ESM::Weapon::LongBladeTwoHand ||
ptr.get<ESM::Weapon>()->mBase->mData.mType == ESM::Weapon::BluntTwoClose ||
ptr.get<ESM::Weapon>()->mBase->mData.mType == ESM::Weapon::BluntTwoWide ||
ptr.get<ESM::Weapon>()->mBase->mData.mType == ESM::Weapon::SpearTwoWide ||
ptr.get<ESM::Weapon>()->mBase->mData.mType == ESM::Weapon::AxeTwoHand ||
ptr.get<ESM::Weapon>()->mBase->mData.mType == ESM::Weapon::MarksmanBow ||
ptr.get<ESM::Weapon>()->mBase->mData.mType == ESM::Weapon::MarksmanCrossbow)
{
return std::make_pair (2, "");
}
}
return std::make_pair(1, "");
} }
return std::make_pair (0, "");
return std::make_pair(1, "");
} }
boost::shared_ptr<MWWorld::Action> Weapon::use (const MWWorld::Ptr& ptr) const boost::shared_ptr<MWWorld::Action> Weapon::use (const MWWorld::Ptr& ptr) const

@ -251,7 +251,7 @@ namespace MWDialogue
} }
} }
void DialogueManager::executeTopic (const std::string& topic, bool randomResponse) void DialogueManager::executeTopic (const std::string& topic)
{ {
Filter filter (mActor, mChoice, mTalkedTo); Filter filter (mActor, mChoice, mTalkedTo);
@ -262,12 +262,9 @@ namespace MWDialogue
MWGui::DialogueWindow* win = MWBase::Environment::get().getWindowManager()->getDialogueWindow(); MWGui::DialogueWindow* win = MWBase::Environment::get().getWindowManager()->getDialogueWindow();
std::vector<const ESM::DialInfo *> infos = filter.list (dialogue, true, true); const ESM::DialInfo* info = filter.search(dialogue, true);
if (info)
if (!infos.empty())
{ {
const ESM::DialInfo* info = infos[randomResponse ? std::rand() % infos.size() : 0];
parseText (info->mResponse); parseText (info->mResponse);
std::string title; std::string title;
@ -413,10 +410,6 @@ namespace MWDialogue
void DialogueManager::goodbyeSelected() void DialogueManager::goodbyeSelected()
{ {
// Do not close the dialogue window if the player has to answer a question
if (mIsInChoice)
return;
MWBase::Environment::get().getWindowManager()->removeGuiMode(MWGui::GM_Dialogue); MWBase::Environment::get().getWindowManager()->removeGuiMode(MWGui::GM_Dialogue);
// Apply disposition change to NPC's base disposition // Apply disposition change to NPC's base disposition
@ -474,6 +467,8 @@ namespace MWDialogue
void DialogueManager::goodbye() void DialogueManager::goodbye()
{ {
mIsInChoice = true;
MWGui::DialogueWindow* win = MWBase::Environment::get().getWindowManager()->getDialogueWindow(); MWGui::DialogueWindow* win = MWBase::Environment::get().getWindowManager()->getDialogueWindow();
win->goodbye(); win->goodbye();
@ -511,7 +506,7 @@ namespace MWDialogue
text = "Bribe"; text = "Bribe";
} }
executeTopic (text + (success ? " Success" : " Fail"), true); executeTopic (text + (success ? " Success" : " Fail"));
} }
int DialogueManager::getTemporaryDispositionChange() const int DialogueManager::getTemporaryDispositionChange() const

@ -44,7 +44,7 @@ namespace MWDialogue
bool compile (const std::string& cmd,std::vector<Interpreter::Type_Code>& code); bool compile (const std::string& cmd,std::vector<Interpreter::Type_Code>& code);
void executeScript (const std::string& script); void executeScript (const std::string& script);
void executeTopic (const std::string& topic, bool randomResponse=false); void executeTopic (const std::string& topic);
public: public:

@ -5,6 +5,7 @@
#include "../mwbase/world.hpp" #include "../mwbase/world.hpp"
#include "../mwbase/journal.hpp" #include "../mwbase/journal.hpp"
#include "../mwbase/mechanicsmanager.hpp" #include "../mwbase/mechanicsmanager.hpp"
#include "../mwbase/dialoguemanager.hpp"
#include "../mwworld/class.hpp" #include "../mwworld/class.hpp"
#include "../mwworld/player.hpp" #include "../mwworld/player.hpp"
@ -133,7 +134,8 @@ bool MWDialogue::Filter::testDisposition (const ESM::DialInfo& info, bool invert
if (isCreature) if (isCreature)
return true; return true;
int actorDisposition = MWBase::Environment::get().getMechanicsManager()->getDerivedDisposition(mActor); int actorDisposition = MWBase::Environment::get().getMechanicsManager()->getDerivedDisposition(mActor)
+ MWBase::Environment::get().getDialogueManager()->getTemporaryDispositionChange();
// For service refusal, the disposition check is inverted. However, a value of 0 still means "always succeed". // For service refusal, the disposition check is inverted. However, a value of 0 still means "always succeed".
return invert ? (info.mData.mDisposition == 0 || actorDisposition < info.mData.mDisposition) return invert ? (info.mData.mDisposition == 0 || actorDisposition < info.mData.mDisposition)
: (actorDisposition >= info.mData.mDisposition); : (actorDisposition >= info.mData.mDisposition);
@ -277,7 +279,8 @@ int MWDialogue::Filter::getSelectStructInteger (const SelectWrapper& select) con
case SelectWrapper::Function_AiSetting: case SelectWrapper::Function_AiSetting:
return MWWorld::Class::get (mActor).getCreatureStats (mActor).getAiSetting (select.getArgument()); return MWWorld::Class::get (mActor).getCreatureStats (mActor).getAiSetting (
(MWMechanics::CreatureStats::AiSetting)select.getArgument()).getModified();
case SelectWrapper::Function_PcAttribute: case SelectWrapper::Function_PcAttribute:
@ -512,7 +515,8 @@ bool MWDialogue::Filter::getSelectStructBoolean (const SelectWrapper& select) co
case SelectWrapper::Function_PcVampire: case SelectWrapper::Function_PcVampire:
return MWWorld::Class::get (player).getNpcStats (player).isVampire(); return MWWorld::Class::get (player).getCreatureStats(player).getMagicEffects().
get(ESM::MagicEffect::Vampirism).mMagnitude > 0;
case SelectWrapper::Function_TalkedToPc: case SelectWrapper::Function_TalkedToPc:

@ -44,6 +44,11 @@ namespace MWGui
adjustButton(mNextPageButton); adjustButton(mNextPageButton);
adjustButton(mPrevPageButton); adjustButton(mPrevPageButton);
mLeftPage->setNeedMouseFocus(true);
mLeftPage->eventMouseWheel += MyGUI::newDelegate(this, &BookWindow::onMouseWheel);
mRightPage->setNeedMouseFocus(true);
mRightPage->eventMouseWheel += MyGUI::newDelegate(this, &BookWindow::onMouseWheel);
if (mNextPageButton->getSize().width == 64) if (mNextPageButton->getSize().width == 64)
{ {
// english button has a 7 pixel wide strip of garbage on its right edge // english button has a 7 pixel wide strip of garbage on its right edge
@ -54,6 +59,14 @@ namespace MWGui
center(); center();
} }
void BookWindow::onMouseWheel(MyGUI::Widget *_sender, int _rel)
{
if (_rel < 0)
nextPage();
else
prevPage();
}
void BookWindow::clearPages() void BookWindow::clearPages()
{ {
for (std::vector<MyGUI::Widget*>::iterator it=mPages.begin(); for (std::vector<MyGUI::Widget*>::iterator it=mPages.begin();
@ -89,6 +102,7 @@ namespace MWGui
parent = mRightPage; parent = mRightPage;
MyGUI::Widget* pageWidget = parent->createWidgetReal<MyGUI::Widget>("", MyGUI::FloatCoord(0.0,0.0,1.0,1.0), MyGUI::Align::Default, "BookPage" + boost::lexical_cast<std::string>(i)); MyGUI::Widget* pageWidget = parent->createWidgetReal<MyGUI::Widget>("", MyGUI::FloatCoord(0.0,0.0,1.0,1.0), MyGUI::Align::Default, "BookPage" + boost::lexical_cast<std::string>(i));
pageWidget->setNeedMouseFocus(false);
parser.parsePage(*it, pageWidget, mLeftPage->getSize().width); parser.parsePage(*it, pageWidget, mLeftPage->getSize().width);
mPages.push_back(pageWidget); mPages.push_back(pageWidget);
++i; ++i;

@ -25,6 +25,7 @@ namespace MWGui
void onPrevPageButtonClicked (MyGUI::Widget* sender); void onPrevPageButtonClicked (MyGUI::Widget* sender);
void onCloseButtonClicked (MyGUI::Widget* sender); void onCloseButtonClicked (MyGUI::Widget* sender);
void onTakeButtonClicked (MyGUI::Widget* sender); void onTakeButtonClicked (MyGUI::Widget* sender);
void onMouseWheel(MyGUI::Widget* _sender, int _rel);
void updatePages(); void updatePages();
void clearPages(); void clearPages();

@ -75,7 +75,7 @@ namespace MWGui
mGenerateClassSpecializations[2] = 0; mGenerateClassSpecializations[2] = 0;
} }
void CharacterCreation::setValue (const std::string& id, const MWMechanics::Stat<int>& value) void CharacterCreation::setValue (const std::string& id, const MWMechanics::AttributeValue& value)
{ {
if (mReviewDialog) if (mReviewDialog)
{ {
@ -113,7 +113,7 @@ namespace MWGui
} }
} }
void CharacterCreation::setValue(const ESM::Skill::SkillEnum parSkill, const MWMechanics::Stat<float>& value) void CharacterCreation::setValue(const ESM::Skill::SkillEnum parSkill, const MWMechanics::SkillValue& value)
{ {
if (mReviewDialog) if (mReviewDialog)
mReviewDialog->setSkillValue(parSkill, value); mReviewDialog->setSkillValue(parSkill, value);
@ -229,8 +229,8 @@ namespace MWGui
} }
{ {
std::map<int, MWMechanics::Stat<int> > attributes = MWBase::Environment::get().getWindowManager()->getPlayerAttributeValues(); std::map<int, MWMechanics::AttributeValue > attributes = MWBase::Environment::get().getWindowManager()->getPlayerAttributeValues();
for (std::map<int, MWMechanics::Stat<int> >::iterator it = attributes.begin(); for (std::map<int, MWMechanics::AttributeValue >::iterator it = attributes.begin();
it != attributes.end(); ++it) it != attributes.end(); ++it)
{ {
mReviewDialog->setAttribute(static_cast<ESM::Attribute::AttributeID> (it->first), it->second); mReviewDialog->setAttribute(static_cast<ESM::Attribute::AttributeID> (it->first), it->second);
@ -238,8 +238,8 @@ namespace MWGui
} }
{ {
std::map<int, MWMechanics::Stat<float> > skills = MWBase::Environment::get().getWindowManager()->getPlayerSkillValues(); std::map<int, MWMechanics::SkillValue > skills = MWBase::Environment::get().getWindowManager()->getPlayerSkillValues();
for (std::map<int, MWMechanics::Stat<float> >::iterator it = skills.begin(); for (std::map<int, MWMechanics::SkillValue >::iterator it = skills.begin();
it != skills.end(); ++it) it != skills.end(); ++it)
{ {
mReviewDialog->setSkillValue(static_cast<ESM::Skill::SkillEnum> (it->first), it->second); mReviewDialog->setSkillValue(static_cast<ESM::Skill::SkillEnum> (it->first), it->second);

@ -31,9 +31,9 @@ namespace MWGui
//Show a dialog //Show a dialog
void spawnDialog(const char id); void spawnDialog(const char id);
void setValue (const std::string& id, const MWMechanics::Stat<int>& value); void setValue (const std::string& id, const MWMechanics::AttributeValue& value);
void setValue (const std::string& id, const MWMechanics::DynamicStat<float>& value); void setValue (const std::string& id, const MWMechanics::DynamicStat<float>& value);
void setValue(const ESM::Skill::SkillEnum parSkill, const MWMechanics::Stat<float>& value); void setValue(const ESM::Skill::SkillEnum parSkill, const MWMechanics::SkillValue& value);
void configureSkills (const SkillList& major, const SkillList& minor); void configureSkills (const SkillList& major, const SkillList& minor);
void doRenderUpdate(); void doRenderUpdate();

@ -466,7 +466,7 @@ namespace MWGui
std::string CreateClassDialog::getName() const std::string CreateClassDialog::getName() const
{ {
return mEditName->getOnlyText(); return mEditName->getCaption();
} }
std::string CreateClassDialog::getDescription() const std::string CreateClassDialog::getDescription() const

@ -228,8 +228,8 @@ namespace MWGui
DescriptionDialog(); DescriptionDialog();
~DescriptionDialog(); ~DescriptionDialog();
std::string getTextInput() const { return mTextEdit ? mTextEdit->getOnlyText() : ""; } std::string getTextInput() const { return mTextEdit->getCaption(); }
void setTextInput(const std::string &text) { if (mTextEdit) mTextEdit->setOnlyText(text); } void setTextInput(const std::string &text) { mTextEdit->setCaption(text); }
protected: protected:
void onOkClicked(MyGUI::Widget* _sender); void onOkClicked(MyGUI::Widget* _sender);

@ -119,8 +119,6 @@ namespace MWGui
// Set up the log window // Set up the log window
mHistory->setOverflowToTheLeft(true); mHistory->setOverflowToTheLeft(true);
mHistory->setEditStatic(true);
mHistory->setVisibleVScroll(true);
// compiler // compiler
Compiler::registerExtensions (mExtensions, mConsoleOnlyScripts); Compiler::registerExtensions (mExtensions, mConsoleOnlyScripts);
@ -215,7 +213,7 @@ namespace MWGui
{ {
std::vector<std::string> matches; std::vector<std::string> matches;
listNames(); listNames();
mCommandLine->setCaption(complete( mCommandLine->getCaption(), matches )); mCommandLine->setCaption(complete( mCommandLine->getOnlyText(), matches ));
#if 0 #if 0
int i = 0; int i = 0;
for(std::vector<std::string>::iterator it=matches.begin(); it < matches.end(); ++it,++i ) for(std::vector<std::string>::iterator it=matches.begin(); it < matches.end(); ++it,++i )
@ -234,7 +232,7 @@ namespace MWGui
{ {
// If the user was editing a string, store it for later // If the user was editing a string, store it for later
if(mCurrent == mCommandHistory.end()) if(mCurrent == mCommandHistory.end())
mEditString = mCommandLine->getCaption(); mEditString = mCommandLine->getOnlyText();
if(mCurrent != mCommandHistory.begin()) if(mCurrent != mCommandHistory.begin())
{ {
@ -259,7 +257,7 @@ namespace MWGui
void Console::acceptCommand(MyGUI::EditBox* _sender) void Console::acceptCommand(MyGUI::EditBox* _sender)
{ {
const std::string &cm = mCommandLine->getCaption(); const std::string &cm = mCommandLine->getOnlyText();
if(cm.empty()) return; if(cm.empty()) return;
// Add the command to the history, and set the current pointer to // Add the command to the history, and set the current pointer to
@ -406,13 +404,14 @@ namespace MWGui
setTitle("#{sConsoleTitle} (" + object.getCellRef().mRefID + ")"); setTitle("#{sConsoleTitle} (" + object.getCellRef().mRefID + ")");
mPtr = object; mPtr = object;
} }
// User clicked on an object. Restore focus to the console command line.
MWBase::Environment::get().getWindowManager()->setKeyFocusWidget(mCommandLine);
} }
else else
{ {
setTitle("#{sConsoleTitle}"); setTitle("#{sConsoleTitle}");
mPtr = MWWorld::Ptr(); mPtr = MWWorld::Ptr();
} }
MWBase::Environment::get().getWindowManager()->setKeyFocusWidget(mCommandLine);
} }
void Console::onReferenceUnavailable() void Console::onReferenceUnavailable()

@ -61,8 +61,9 @@ namespace MWGui
mDraggedWidget = baseWidget; mDraggedWidget = baseWidget;
MyGUI::ImageBox* image = baseWidget->createWidget<MyGUI::ImageBox>("ImageBox", MyGUI::ImageBox* image = baseWidget->createWidget<MyGUI::ImageBox>("ImageBox",
MyGUI::IntCoord(5, 5, 32, 32), MyGUI::Align::Default); MyGUI::IntCoord(5, 5, 32, 32), MyGUI::Align::Default);
int pos = path.rfind("."); size_t pos = path.rfind(".");
path.erase(pos); if (pos != std::string::npos)
path.erase(pos);
path.append(".dds"); path.append(".dds");
image->setImageTexture(path); image->setImageTexture(path);
image->setNeedMouseFocus(false); image->setNeedMouseFocus(false);

@ -76,10 +76,7 @@ void ContainerItemModel::copyItem (const ItemStack& item, size_t count)
const MWWorld::Ptr& source = mItemSources[mItemSources.size()-1]; const MWWorld::Ptr& source = mItemSources[mItemSources.size()-1];
if (item.mBase.getContainerStore() == &source.getClass().getContainerStore(source)) if (item.mBase.getContainerStore() == &source.getClass().getContainerStore(source))
throw std::runtime_error("Item to copy needs to be from a different container!"); throw std::runtime_error("Item to copy needs to be from a different container!");
int origCount = item.mBase.getRefData().getCount(); source.getClass().getContainerStore(source).add(item.mBase, count, source);
item.mBase.getRefData().setCount(count);
source.getClass().getContainerStore(source).add(item.mBase, source);
item.mBase.getRefData().setCount(origCount);
} }
void ContainerItemModel::removeItem (const ItemStack& item, size_t count) void ContainerItemModel::removeItem (const ItemStack& item, size_t count)

@ -302,6 +302,8 @@ namespace MWGui
void DialogueWindow::onByeClicked(MyGUI::Widget* _sender) void DialogueWindow::onByeClicked(MyGUI::Widget* _sender)
{ {
if (!mEnabled || MWBase::Environment::get().getDialogueManager()->isInChoice())
return;
MWBase::Environment::get().getDialogueManager()->goodbyeSelected(); MWBase::Environment::get().getDialogueManager()->goodbyeSelected();
} }

@ -55,6 +55,8 @@ namespace MWGui
, mWorldMouseOver(false) , mWorldMouseOver(false)
, mEnemyHealthTimer(0) , mEnemyHealthTimer(0)
, mIsDrowning(false) , mIsDrowning(false)
, mWeaponSpellTimer(0.f)
, mDrowningFlashTheta(0.f)
{ {
setCoord(0,0, width, height); setCoord(0,0, width, height);
@ -174,38 +176,32 @@ namespace MWGui
void HUD::setValue(const std::string& id, const MWMechanics::DynamicStat<float>& value) void HUD::setValue(const std::string& id, const MWMechanics::DynamicStat<float>& value)
{ {
static const char *ids[] = int current = std::max(0, static_cast<int>(value.getCurrent()));
{ int modified = static_cast<int>(value.getModified());
"HBar", "MBar", "FBar", 0
};
for (int i=0; ids[i]; ++i) MyGUI::Widget* w;
if (ids[i]==id) std::string valStr = boost::lexical_cast<std::string>(current) + "/" + boost::lexical_cast<std::string>(modified);
{ if (id == "HBar")
MyGUI::Widget* w; {
std::string valStr = boost::lexical_cast<std::string>(value.getCurrent()) + "/" + boost::lexical_cast<std::string>(value.getModified()); mHealth->setProgressRange(modified);
switch (i) mHealth->setProgressPosition(current);
{ getWidget(w, "HealthFrame");
case 0: w->setUserString("Caption_HealthDescription", "#{sHealthDesc}\n" + valStr);
mHealth->setProgressRange (value.getModified()); }
mHealth->setProgressPosition (value.getCurrent()); else if (id == "MBar")
getWidget(w, "HealthFrame"); {
w->setUserString("Caption_HealthDescription", "#{sHealthDesc}\n" + valStr); mMagicka->setProgressRange (modified);
break; mMagicka->setProgressPosition (current);
case 1: getWidget(w, "MagickaFrame");
mMagicka->setProgressRange (value.getModified()); w->setUserString("Caption_HealthDescription", "#{sIntDesc}\n" + valStr);
mMagicka->setProgressPosition (value.getCurrent()); }
getWidget(w, "MagickaFrame"); else if (id == "FBar")
w->setUserString("Caption_HealthDescription", "#{sIntDesc}\n" + valStr); {
break; mStamina->setProgressRange (modified);
case 2: mStamina->setProgressPosition (current);
mStamina->setProgressRange (value.getModified()); getWidget(w, "FatigueFrame");
mStamina->setProgressPosition (value.getCurrent()); w->setUserString("Caption_HealthDescription", "#{sFatDesc}\n" + valStr);
getWidget(w, "FatigueFrame"); }
w->setUserString("Caption_HealthDescription", "#{sFatDesc}\n" + valStr);
break;
}
}
} }
void HUD::setDrowningTimeLeft(float time) void HUD::setDrowningTimeLeft(float time)

@ -42,10 +42,7 @@ void InventoryItemModel::copyItem (const ItemStack& item, size_t count)
{ {
if (item.mBase.getContainerStore() == &mActor.getClass().getContainerStore(mActor)) if (item.mBase.getContainerStore() == &mActor.getClass().getContainerStore(mActor))
throw std::runtime_error("Item to copy needs to be from a different container!"); throw std::runtime_error("Item to copy needs to be from a different container!");
int origCount = item.mBase.getRefData().getCount(); mActor.getClass().getContainerStore(mActor).add(item.mBase, count, mActor);
item.mBase.getRefData().setCount(count);
mActor.getClass().getContainerStore(mActor).add(item.mBase, mActor);
item.mBase.getRefData().setCount(origCount);
} }
@ -72,7 +69,7 @@ void InventoryItemModel::update()
// NOTE: Don't show WerewolfRobe objects in the inventory, or allow them to be taken. // NOTE: Don't show WerewolfRobe objects in the inventory, or allow them to be taken.
// Vanilla likely uses a hack like this since there's no other way to prevent it from // Vanilla likely uses a hack like this since there's no other way to prevent it from
// being shown or taken. // being shown or taken.
if(item.getCellRef().mRefID == "WerewolfRobe") if(item.getCellRef().mRefID == "werewolfrobe")
continue; continue;
ItemStack newItem (item, this, item.getRefData().getCount()); ItemStack newItem (item, this, item.getRefData().getCount());

@ -120,10 +120,13 @@ namespace MWGui
Settings::Manager::getFloat(setting + " y", "Windows") * viewSize.height); Settings::Manager::getFloat(setting + " y", "Windows") * viewSize.height);
MyGUI::IntSize size (Settings::Manager::getFloat(setting + " w", "Windows") * viewSize.width, MyGUI::IntSize size (Settings::Manager::getFloat(setting + " w", "Windows") * viewSize.width,
Settings::Manager::getFloat(setting + " h", "Windows") * viewSize.height); Settings::Manager::getFloat(setting + " h", "Windows") * viewSize.height);
if (size.width != mMainWidget->getWidth() || size.height != mMainWidget->getHeight())
mPreviewDirty = true;
mMainWidget->setPosition(pos); mMainWidget->setPosition(pos);
mMainWidget->setSize(size); mMainWidget->setSize(size);
adjustPanes(); adjustPanes();
mPreviewDirty = true;
} }
TradeItemModel* InventoryWindow::getTradeModel() TradeItemModel* InventoryWindow::getTradeModel()
@ -160,6 +163,14 @@ namespace MWGui
MWWorld::Ptr object = item.mBase; MWWorld::Ptr object = item.mBase;
int count = item.mCount; int count = item.mCount;
// Bound items may not be moved
if (item.mBase.getCellRef().mRefID.size() > 6
&& item.mBase.getCellRef().mRefID.substr(0,6) == "bound_")
{
MWBase::Environment::get().getWindowManager()->messageBox("#{sBarterDialog12}");
return;
}
if (item.mType == ItemStack::Type_Equipped) if (item.mType == ItemStack::Type_Equipped)
{ {
MWWorld::InventoryStore& invStore = MWWorld::Class::get(mPtr).getInventoryStore(mPtr); MWWorld::InventoryStore& invStore = MWWorld::Class::get(mPtr).getInventoryStore(mPtr);
@ -353,10 +364,7 @@ namespace MWGui
MWWorld::ContainerStore& invStore = MWWorld::Class::get(mPtr).getContainerStore(mPtr); MWWorld::ContainerStore& invStore = MWWorld::Class::get(mPtr).getContainerStore(mPtr);
MWWorld::ContainerStoreIterator it = invStore.begin(); MWWorld::ContainerStoreIterator it = invStore.begin();
int origCount = ptr.getRefData().getCount(); it = invStore.add(ptr, mDragAndDrop->mDraggedCount, mPtr);
ptr.getRefData().setCount(mDragAndDrop->mDraggedCount);
it = invStore.add(ptr, mPtr);
ptr.getRefData().setCount(origCount);
mDragAndDrop->mSourceModel->removeItem(mDragAndDrop->mItem, mDragAndDrop->mDraggedCount); mDragAndDrop->mSourceModel->removeItem(mDragAndDrop->mItem, mDragAndDrop->mDraggedCount);
ptr = *it; ptr = *it;
@ -414,7 +422,7 @@ namespace MWGui
// NOTE: Don't allow users to select WerewolfRobe objects in the inventory. Vanilla // NOTE: Don't allow users to select WerewolfRobe objects in the inventory. Vanilla
// likely uses a hack like this since there's no other way to prevent it from being // likely uses a hack like this since there's no other way to prevent it from being
// taken. // taken.
if(item.getCellRef().mRefID == "WerewolfRobe") if(item.getCellRef().mRefID == "werewolfrobe")
return MWWorld::Ptr(); return MWWorld::Ptr();
return item; return item;
} }
@ -510,7 +518,7 @@ namespace MWGui
// add to player inventory // add to player inventory
// can't use ActionTake here because we need an MWWorld::Ptr to the newly inserted object // can't use ActionTake here because we need an MWWorld::Ptr to the newly inserted object
MWWorld::Ptr player = MWBase::Environment::get().getWorld()->getPlayer().getPlayer(); MWWorld::Ptr player = MWBase::Environment::get().getWorld()->getPlayer().getPlayer();
MWWorld::Ptr newObject = *MWWorld::Class::get (player).getContainerStore (player).add (object, player); MWWorld::Ptr newObject = *player.getClass().getContainerStore (player).add (object, object.getRefData().getCount(), player);
// remove from world // remove from world
MWBase::Environment::get().getWorld()->deleteObject (object); MWBase::Environment::get().getWorld()->deleteObject (object);

@ -166,11 +166,12 @@ namespace MWGui
// increase attributes // increase attributes
for (int i=0; i<3; ++i) for (int i=0; i<3; ++i)
{ {
MWMechanics::Stat<int>& attribute = creatureStats.getAttribute(mSpentAttributes[i]); MWMechanics::AttributeValue attribute = creatureStats.getAttribute(mSpentAttributes[i]);
attribute.setBase (attribute.getBase () + pcStats.getLevelupAttributeMultiplier (mSpentAttributes[i])); attribute.setBase (attribute.getBase () + pcStats.getLevelupAttributeMultiplier (mSpentAttributes[i]));
if (attribute.getBase() >= 100) if (attribute.getBase() >= 100)
attribute.setBase(100); attribute.setBase(100);
creatureStats.setAttribute(mSpentAttributes[i], attribute);
} }
creatureStats.levelUp(); creatureStats.levelUp();

@ -1,8 +1,6 @@
#include "loadingscreen.hpp" #include "loadingscreen.hpp"
#include <OgreRenderWindow.h> #include <OgreRenderWindow.h>
#include <OgreCompositorManager.h>
#include <OgreCompositorChain.h>
#include <openengine/ogre/fader.hpp> #include <openengine/ogre/fader.hpp>
@ -199,28 +197,7 @@ namespace MWGui
MWBase::Environment::get().getInputManager()->update(0, true); MWBase::Environment::get().getInputManager()->update(0, true);
Ogre::CompositorChain* chain = Ogre::CompositorManager::getSingleton().getCompositorChain(mWindow->getViewport(0)); mWindow->getViewport(0)->setClearEveryFrame(false);
bool hasCompositor = chain->getCompositor ("gbufferFinalizer");
if (!hasCompositor)
{
mWindow->getViewport(0)->setClearEveryFrame(false);
}
else
{
if (!mFirstLoad)
{
mBackgroundMaterial->getTechnique(0)->getPass(0)->getTextureUnitState(0)->setTextureName(chain->getCompositor ("gbufferFinalizer")->getTextureInstance ("no_mrt_output", 0)->getName());
mRectangle->setVisible(true);
}
for (unsigned int i = 0; i<chain->getNumCompositors(); ++i)
{
Ogre::CompositorManager::getSingleton().setCompositorEnabled(mWindow->getViewport(0), chain->getCompositor(i)->getCompositor()->getName(), false);
}
}
// First, swap buffers from last draw, then, queue an update of the // First, swap buffers from last draw, then, queue an update of the
// window contents, but don't swap buffers (which would have // window contents, but don't swap buffers (which would have
@ -231,15 +208,8 @@ namespace MWGui
mWindow->update(false); mWindow->update(false);
if (!hasCompositor) mWindow->getViewport(0)->setClearEveryFrame(true);
mWindow->getViewport(0)->setClearEveryFrame(true);
else
{
for (unsigned int i = 0; i<chain->getNumCompositors(); ++i)
{
Ogre::CompositorManager::getSingleton().setCompositorEnabled(mWindow->getViewport(0), chain->getCompositor(i)->getCompositor()->getName(), true);
}
}
mRectangle->setVisible(false); mRectangle->setVisible(false);

@ -103,27 +103,80 @@ namespace MWGui
void LocalMapBase::onMarkerFocused (MyGUI::Widget* w1, MyGUI::Widget* w2) void LocalMapBase::onMarkerFocused (MyGUI::Widget* w1, MyGUI::Widget* w2)
{ {
// Workaround to not make the marker visible if it's under fog of war
applyFogOfWar (); applyFogOfWar ();
} }
void LocalMapBase::onMarkerUnfocused (MyGUI::Widget* w1, MyGUI::Widget* w2) void LocalMapBase::onMarkerUnfocused (MyGUI::Widget* w1, MyGUI::Widget* w2)
{ {
// Workaround to not make the marker visible if it's under fog of war
applyFogOfWar (); applyFogOfWar ();
} }
MyGUI::IntPoint LocalMapBase::getMarkerPosition(float worldX, float worldY, MarkerPosition& markerPos)
{
MyGUI::IntPoint widgetPos;
// normalized cell coordinates
float nX,nY;
markerPos.interior = mInterior;
if (!mInterior)
{
int cellX, cellY;
MWBase::Environment::get().getWorld()->positionToIndex(worldX, worldY, cellX, cellY);
const int cellSize = 8192;
nX = (worldX - cellSize * cellX) / cellSize;
// Image space is -Y up, cells are Y up
nY = 1 - (worldY - cellSize * cellY) / cellSize;
float cellDx = cellX - mCurX;
float cellDy = cellY - mCurY;
markerPos.cellX = cellX;
markerPos.cellY = cellY;
widgetPos = MyGUI::IntPoint(nX * 512 + (1+cellDx) * 512,
nY * 512 - (cellDy-1) * 512);
}
else
{
int cellX, cellY;
Ogre::Vector2 worldPos (worldX, worldY);
MWBase::Environment::get().getWorld ()->getInteriorMapPosition (worldPos, nX, nY, cellX, cellY);
markerPos.cellX = cellX;
markerPos.cellY = cellY;
widgetPos = MyGUI::IntPoint(nX * 512 + (1+cellX-mCurX) * 512,
nY * 512 + (1+cellY-mCurY) * 512);
}
markerPos.nX = nX;
markerPos.nY = nY;
return widgetPos;
}
void LocalMapBase::setActiveCell(const int x, const int y, bool interior) void LocalMapBase::setActiveCell(const int x, const int y, bool interior)
{ {
if (x==mCurX && y==mCurY && mInterior==interior && !mChanged) return; // don't do anything if we're still in the same cell if (x==mCurX && y==mCurY && mInterior==interior && !mChanged)
return; // don't do anything if we're still in the same cell
mCurX = x;
mCurY = y;
mInterior = interior;
mChanged = false;
// clear all previous markers // clear all previous markers
for (unsigned int i=0; i< mLocalMap->getChildCount(); ++i) for (unsigned int i=0; i< mLocalMap->getChildCount(); ++i)
{ {
if (mLocalMap->getChildAt(i)->getName ().substr (0, 6) == "Marker") if (mLocalMap->getChildAt(i)->getName ().substr (0, 4) == "Door")
{ {
MyGUI::Gui::getInstance ().destroyWidget (mLocalMap->getChildAt(i)); MyGUI::Gui::getInstance ().destroyWidget (mLocalMap->getChildAt(i));
} }
} }
// Update the map textures
for (int mx=0; mx<3; ++mx) for (int mx=0; mx<3; ++mx)
{ {
for (int my=0; my<3; ++my) for (int my=0; my<3; ++my)
@ -138,78 +191,57 @@ namespace MWGui
box->setImageTexture(image); box->setImageTexture(image);
else else
box->setImageTexture("black.png"); box->setImageTexture("black.png");
}
}
MWBase::World* world = MWBase::Environment::get().getWorld();
// door markers // Retrieve the door markers we want to show
std::vector<MWBase::World::DoorMarker> doors;
// interior map only consists of one cell, so handle the markers only once if (interior)
if (interior && (mx != 2 || my != 2)) {
continue; MWWorld::CellStore* cell = world->getInterior (mPrefix);
world->getDoorMarkers(cell, doors);
MWWorld::CellStore* cell; }
if (interior) else
cell = MWBase::Environment::get().getWorld ()->getInterior (mPrefix); {
else for (int dX=-1; dX<2; ++dX)
cell = MWBase::Environment::get().getWorld ()->getExterior (x+mx-1, y-(my-1)); {
for (int dY=-1; dY<2; ++dY)
std::vector<MWBase::World::DoorMarker> doors = MWBase::Environment::get().getWorld ()->getDoorMarkers (cell);
for (std::vector<MWBase::World::DoorMarker>::iterator it = doors.begin(); it != doors.end(); ++it)
{ {
MWBase::World::DoorMarker marker = *it; MWWorld::CellStore* cell = world->getExterior (mCurX+dX, mCurY+dY);
world->getDoorMarkers(cell, doors);
// convert world coordinates to normalized cell coordinates
MyGUI::IntCoord widgetCoord;
float nX,nY;
int cellDx, cellDy;
if (!interior)
{
const int cellSize = 8192;
nX = (marker.x - cellSize * (x+mx-1)) / cellSize;
nY = 1 - (marker.y - cellSize * (y-(my-1))) / cellSize;
widgetCoord = MyGUI::IntCoord(nX * 512 - 4 + mx * 512, nY * 512 - 4 + my * 512, 8, 8);
}
else
{
Ogre::Vector2 position (marker.x, marker.y);
MWBase::Environment::get().getWorld ()->getInteriorMapPosition (position, nX, nY, cellDx, cellDy);
widgetCoord = MyGUI::IntCoord(nX * 512 - 4 + (1+cellDx-x) * 512, nY * 512 - 4 + (1+cellDy-y) * 512, 8, 8);
}
static int counter = 0;
++counter;
MyGUI::Button* markerWidget = mLocalMap->createWidget<MyGUI::Button>("ButtonImage",
widgetCoord, MyGUI::Align::Default, "Marker" + boost::lexical_cast<std::string>(counter));
markerWidget->setImageResource("DoorMarker");
markerWidget->setUserString("ToolTipType", "Layout");
markerWidget->setUserString("ToolTipLayout", "TextToolTipOneLine");
markerWidget->setUserString("Caption_TextOneLine", marker.name);
markerWidget->setUserString("IsMarker", "true");
markerWidget->eventMouseSetFocus += MyGUI::newDelegate(this, &LocalMapBase::onMarkerFocused);
markerWidget->eventMouseLostFocus += MyGUI::newDelegate(this, &LocalMapBase::onMarkerUnfocused);
MarkerPosition markerPos;
markerPos.interior = interior;
markerPos.cellX = interior ? cellDx : x + mx - 1;
markerPos.cellY = interior ? cellDy : y + ((my - 1)*-1);
markerPos.nX = nX;
markerPos.nY = nY;
markerWidget->setUserData(markerPos);
} }
} }
} }
mInterior = interior;
mCurX = x;
mCurY = y;
mChanged = false;
// fog of war // Create a widget for each marker
int counter = 0;
for (std::vector<MWBase::World::DoorMarker>::iterator it = doors.begin(); it != doors.end(); ++it)
{
MWBase::World::DoorMarker marker = *it;
MarkerPosition markerPos;
MyGUI::IntPoint widgetPos = getMarkerPosition(marker.x, marker.y, markerPos);
MyGUI::IntCoord widgetCoord(widgetPos.left - 4,
widgetPos.top - 4,
8, 8);
++counter;
MyGUI::Button* markerWidget = mLocalMap->createWidget<MyGUI::Button>("ButtonImage",
widgetCoord, MyGUI::Align::Default, "Door" + boost::lexical_cast<std::string>(counter));
markerWidget->setImageResource("DoorMarker");
markerWidget->setUserString("ToolTipType", "Layout");
markerWidget->setUserString("ToolTipLayout", "TextToolTipOneLine");
markerWidget->setUserString("Caption_TextOneLine", marker.name);
markerWidget->eventMouseSetFocus += MyGUI::newDelegate(this, &LocalMapBase::onMarkerFocused);
markerWidget->eventMouseLostFocus += MyGUI::newDelegate(this, &LocalMapBase::onMarkerUnfocused);
// Used by tooltips to not show the tooltip if marker is hidden by fog of war
markerWidget->setUserString("IsMarker", "true");
markerWidget->setUserData(markerPos);
}
updateMarkers();
applyFogOfWar(); applyFogOfWar();
// set the compass texture again, because MyGUI determines sorting of ImageBox widgets // set the compass texture again, because MyGUI determines sorting of ImageBox widgets
@ -222,6 +254,8 @@ namespace MWGui
void LocalMapBase::setPlayerPos(const float x, const float y) void LocalMapBase::setPlayerPos(const float x, const float y)
{ {
updateMarkers();
if (x == mLastPositionX && y == mLastPositionY) if (x == mLastPositionX && y == mLastPositionY)
return; return;
@ -255,6 +289,88 @@ namespace MWGui
mLastDirectionY = y; mLastDirectionY = y;
} }
void LocalMapBase::addDetectionMarkers(int type)
{
std::vector<MWWorld::Ptr> markers;
MWBase::World* world = MWBase::Environment::get().getWorld();
world->listDetectedReferences(
world->getPlayer().getPlayer(),
markers, MWBase::World::DetectionType(type));
if (markers.empty())
return;
std::string markerTexture;
MyGUI::Colour markerColour;
if (type == MWBase::World::Detect_Creature)
{
markerTexture = "textures\\menu_map_dcreature.dds";
markerColour = MyGUI::Colour(1,0,0,1);
}
if (type == MWBase::World::Detect_Key)
{
markerTexture = "textures\\menu_map_dkey.dds";
markerColour = MyGUI::Colour(0,1,0,1);
}
if (type == MWBase::World::Detect_Enchantment)
{
markerTexture = "textures\\menu_map_dmagic.dds";
markerColour = MyGUI::Colour(0,0,1,1);
}
int counter = 0;
for (std::vector<MWWorld::Ptr>::iterator it = markers.begin(); it != markers.end(); ++it)
{
const ESM::Position& worldPos = it->getRefData().getPosition();
MarkerPosition markerPos;
MyGUI::IntPoint widgetPos = getMarkerPosition(worldPos.pos[0], worldPos.pos[1], markerPos);
MyGUI::IntCoord widgetCoord(widgetPos.left - 4,
widgetPos.top - 4,
8, 8);
++counter;
MyGUI::ImageBox* markerWidget = mLocalMap->createWidget<MyGUI::ImageBox>("ImageBox",
widgetCoord, MyGUI::Align::Default, "Marker" + boost::lexical_cast<std::string>(counter));
markerWidget->setImageTexture(markerTexture);
markerWidget->setUserString("IsMarker", "true");
markerWidget->setUserData(markerPos);
markerWidget->setColour(markerColour);
}
}
void LocalMapBase::updateMarkers()
{
// clear all previous markers
for (unsigned int i=0; i< mLocalMap->getChildCount(); ++i)
{
if (mLocalMap->getChildAt(i)->getName ().substr (0, 6) == "Marker")
{
MyGUI::Gui::getInstance ().destroyWidget (mLocalMap->getChildAt(i));
}
}
addDetectionMarkers(MWBase::World::Detect_Creature);
addDetectionMarkers(MWBase::World::Detect_Key);
addDetectionMarkers(MWBase::World::Detect_Enchantment);
// Add marker for the spot marked with Mark magic effect
MWWorld::CellStore* markedCell = NULL;
ESM::Position markedPosition;
MWBase::Environment::get().getWorld()->getPlayer().getMarkedPosition(markedCell, markedPosition);
if (markedCell && markedCell->isExterior() == !mInterior
&& (!mInterior || Misc::StringUtils::ciEqual(markedCell->mCell->mName, mPrefix)))
{
MarkerPosition markerPos;
MyGUI::IntPoint widgetPos = getMarkerPosition(markedPosition.pos[0], markedPosition.pos[1], markerPos);
MyGUI::IntCoord widgetCoord(widgetPos.left - 4,
widgetPos.top - 4,
8, 8);
MyGUI::ImageBox* markerWidget = mLocalMap->createWidget<MyGUI::ImageBox>("ImageBox",
widgetCoord, MyGUI::Align::Default, "MarkerMarked");
markerWidget->setImageTexture("textures\\menu_map_smark.dds");
markerWidget->setUserString("IsMarker", "true");
markerWidget->setUserData(markerPos);
}
}
// ------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------
MapWindow::MapWindow(const std::string& cacheDir) MapWindow::MapWindow(const std::string& cacheDir)
@ -319,7 +435,7 @@ namespace MWGui
static int _counter=0; static int _counter=0;
MyGUI::Button* markerWidget = mGlobalMapImage->createWidget<MyGUI::Button>("ButtonImage", MyGUI::Button* markerWidget = mGlobalMapImage->createWidget<MyGUI::Button>("ButtonImage",
widgetCoord, MyGUI::Align::Default, "Marker" + boost::lexical_cast<std::string>(_counter)); widgetCoord, MyGUI::Align::Default, "Door" + boost::lexical_cast<std::string>(_counter));
markerWidget->setImageResource("DoorMarker"); markerWidget->setImageResource("DoorMarker");
markerWidget->setUserString("ToolTipType", "Layout"); markerWidget->setUserString("ToolTipType", "Layout");
markerWidget->setUserString("ToolTipLayout", "TextToolTipOneLine"); markerWidget->setUserString("ToolTipLayout", "TextToolTipOneLine");
@ -385,7 +501,7 @@ namespace MWGui
for (unsigned int i=0; i<mGlobalMapImage->getChildCount (); ++i) for (unsigned int i=0; i<mGlobalMapImage->getChildCount (); ++i)
{ {
if (mGlobalMapImage->getChildAt (i)->getName().substr(0,6) == "Marker") if (mGlobalMapImage->getChildAt (i)->getName().substr(0,4) == "Door")
mGlobalMapImage->getChildAt (i)->castType<MyGUI::Button>()->setImageResource("DoorMarker"); mGlobalMapImage->getChildAt (i)->castType<MyGUI::Button>()->setImageResource("DoorMarker");
} }
@ -396,20 +512,18 @@ namespace MWGui
void MapWindow::globalMapUpdatePlayer () void MapWindow::globalMapUpdatePlayer ()
{ {
Ogre::Vector3 pos = MWBase::Environment::get().getWorld ()->getPlayer ().getPlayer().getRefData ().getBaseNode ()->_getDerivedPosition (); // For interiors, position is set by WindowManager via setGlobalMapPlayerPosition
Ogre::Quaternion orient = MWBase::Environment::get().getWorld ()->getPlayer ().getPlayer().getRefData ().getBaseNode ()->_getDerivedOrientation ();
Ogre::Vector2 dir (orient.yAxis ().x, orient.yAxis().y);
float worldX, worldY;
mGlobalMapRender->worldPosToImageSpace (pos.x, pos.y, worldX, worldY);
worldX *= mGlobalMapRender->getWidth();
worldY *= mGlobalMapRender->getHeight();
// for interiors, we have no choice other than using the last position & direction.
/// \todo save this last position in the savegame?
if (MWBase::Environment::get().getWorld ()->isCellExterior ()) if (MWBase::Environment::get().getWorld ()->isCellExterior ())
{ {
Ogre::Vector3 pos = MWBase::Environment::get().getWorld ()->getPlayer ().getPlayer().getRefData ().getBaseNode ()->_getDerivedPosition ();
Ogre::Quaternion orient = MWBase::Environment::get().getWorld ()->getPlayer ().getPlayer().getRefData ().getBaseNode ()->_getDerivedOrientation ();
Ogre::Vector2 dir (orient.yAxis ().x, orient.yAxis().y);
float worldX, worldY;
mGlobalMapRender->worldPosToImageSpace (pos.x, pos.y, worldX, worldY);
worldX *= mGlobalMapRender->getWidth();
worldY *= mGlobalMapRender->getHeight();
mPlayerArrowGlobal->setPosition(MyGUI::IntPoint(worldX - 16, worldY - 16)); mPlayerArrowGlobal->setPosition(MyGUI::IntPoint(worldX - 16, worldY - 16));
MyGUI::ISubWidget* main = mPlayerArrowGlobal->getSubWidgetMain(); MyGUI::ISubWidget* main = mPlayerArrowGlobal->getSubWidgetMain();
@ -444,4 +558,19 @@ namespace MWGui
"#{sWorld}"); "#{sWorld}");
} }
void MapWindow::setGlobalMapPlayerPosition(float worldX, float worldY)
{
float x, y;
mGlobalMapRender->worldPosToImageSpace (worldX, worldY, x, y);
x *= mGlobalMapRender->getWidth();
y *= mGlobalMapRender->getHeight();
mPlayerArrowGlobal->setPosition(MyGUI::IntPoint(x - 16, y - 16));
// set the view offset so that player is in the center
MyGUI::IntSize viewsize = mGlobalMap->getSize();
MyGUI::IntPoint viewoffs(0.5*viewsize.width - x, 0.5*viewsize.height - y);
mGlobalMap->setViewOffset(viewoffs);
}
} }

@ -55,9 +55,16 @@ namespace MWGui
void onMarkerFocused(MyGUI::Widget* w1, MyGUI::Widget* w2); void onMarkerFocused(MyGUI::Widget* w1, MyGUI::Widget* w2);
void onMarkerUnfocused(MyGUI::Widget* w1, MyGUI::Widget* w2); void onMarkerUnfocused(MyGUI::Widget* w1, MyGUI::Widget* w2);
MyGUI::IntPoint getMarkerPosition (float worldX, float worldY, MarkerPosition& markerPos);
virtual void notifyPlayerUpdate() {} virtual void notifyPlayerUpdate() {}
virtual void notifyMapChanged() {} virtual void notifyMapChanged() {}
// Update markers (Detect X effects, Mark/Recall effects)
// Note, door markers handled in setActiveCell
void updateMarkers();
void addDetectionMarkers(int type);
OEngine::GUI::Layout* mLayout; OEngine::GUI::Layout* mLayout;
bool mMapDragAndDrop; bool mMapDragAndDrop;
@ -81,6 +88,8 @@ namespace MWGui
void addVisitedLocation(const std::string& name, int x, int y); // adds the marker to the global map void addVisitedLocation(const std::string& name, int x, int y); // adds the marker to the global map
void cellExplored(int x, int y); void cellExplored(int x, int y);
void setGlobalMapPlayerPosition (float worldX, float worldY);
virtual void open(); virtual void open();
private: private:

@ -16,6 +16,15 @@ namespace MWGui
mLastButtonPressed = -1; mLastButtonPressed = -1;
} }
MessageBoxManager::~MessageBoxManager ()
{
std::vector<MessageBox*>::iterator it(mMessageBoxes.begin());
for (; it != mMessageBoxes.end(); ++it)
{
delete *it;
}
}
void MessageBoxManager::onFrame (float frameDuration) void MessageBoxManager::onFrame (float frameDuration)
{ {
std::vector<MessageBox*>::iterator it; std::vector<MessageBox*>::iterator it;
@ -141,7 +150,6 @@ namespace MWGui
, mMaxTime(0) , mMaxTime(0)
{ {
// defines // defines
mFixedWidth = 300;
mBottomPadding = 20; mBottomPadding = 20;
mNextBoxPadding = 20; mNextBoxPadding = 20;
@ -149,41 +157,21 @@ namespace MWGui
mMessageWidget->setOverflowToTheLeft(true); mMessageWidget->setOverflowToTheLeft(true);
mMessageWidget->setCaptionWithReplacing(mMessage); mMessageWidget->setCaptionWithReplacing(mMessage);
MyGUI::IntSize size;
size.width = mFixedWidth;
size.height = 100; // dummy
mMessageWidget->setSize(size);
MyGUI::IntSize textSize = mMessageWidget->getTextSize();
size.height = mHeight = textSize.height + 20; // this is the padding between the text and the box
mMainWidget->setSize(size);
size.width -= 15; // this is to center the text (see messagebox.layout, Widget type="Edit" position="-2 -3 0 0")
mMessageWidget->setSize(size);
} }
void MessageBox::update (int height) void MessageBox::update (int height)
{ {
MyGUI::IntSize gameWindowSize = MyGUI::RenderManager::getInstance().getViewSize(); MyGUI::IntSize gameWindowSize = MyGUI::RenderManager::getInstance().getViewSize();
MyGUI::IntCoord coord; MyGUI::IntPoint pos;
coord.left = (gameWindowSize.width - mFixedWidth)/2; pos.left = (gameWindowSize.width - mMainWidget->getWidth())/2;
coord.top = (gameWindowSize.height - mHeight - height - mBottomPadding); pos.top = (gameWindowSize.height - mMainWidget->getHeight() - height - mBottomPadding);
MyGUI::IntSize size;
size.width = mFixedWidth;
size.height = mHeight;
mMainWidget->setCoord(coord); mMainWidget->setPosition(pos);
mMainWidget->setSize(size);
mMainWidget->setVisible(true);
} }
int MessageBox::getHeight () int MessageBox::getHeight ()
{ {
return mHeight+mNextBoxPadding; // 20 is the padding between this and the next MessageBox return mMainWidget->getHeight()+mNextBoxPadding; // 20 is the padding between this and the next MessageBox
} }

@ -23,6 +23,7 @@ namespace MWGui
{ {
public: public:
MessageBoxManager (); MessageBoxManager ();
~MessageBoxManager ();
void onFrame (float frameDuration); void onFrame (float frameDuration);
void createMessageBox (const std::string& message, bool stat = false); void createMessageBox (const std::string& message, bool stat = false);
void removeStaticMessageBox (); void removeStaticMessageBox ();
@ -63,10 +64,8 @@ namespace MWGui
protected: protected:
MessageBoxManager& mMessageBoxManager; MessageBoxManager& mMessageBoxManager;
int mHeight;
const std::string& mMessage; const std::string& mMessage;
MyGUI::EditBox* mMessageWidget; MyGUI::EditBox* mMessageWidget;
int mFixedWidth;
int mBottomPadding; int mBottomPadding;
int mNextBoxPadding; int mNextBoxPadding;
}; };

@ -40,6 +40,14 @@ namespace MWGui
for (size_t i = 0; i<mSourceModel->getItemCount(); ++i) for (size_t i = 0; i<mSourceModel->getItemCount(); ++i)
{ {
const ItemStack& item = mSourceModel->getItem(i); const ItemStack& item = mSourceModel->getItem(i);
// Bound items may not be stolen
if (item.mBase.getCellRef().mRefID.size() > 6
&& item.mBase.getCellRef().mRefID.substr(0,6) == "bound_")
{
continue;
}
if (std::find(mHiddenItems.begin(), mHiddenItems.end(), item) == mHiddenItems.end() if (std::find(mHiddenItems.begin(), mHiddenItems.end(), item) == mHiddenItems.end()
&& item.mType != ItemStack::Type_Equipped) && item.mType != ItemStack::Type_Equipped)
mItems.push_back(item); mItems.push_back(item);

@ -269,13 +269,39 @@ namespace MWGui
MWWorld::Ptr player = MWBase::Environment::get().getWorld()->getPlayer().getPlayer(); MWWorld::Ptr player = MWBase::Environment::get().getWorld()->getPlayer().getPlayer();
MWWorld::InventoryStore& store = MWWorld::Class::get(player).getInventoryStore(player); MWWorld::InventoryStore& store = MWWorld::Class::get(player).getInventoryStore(player);
MWMechanics::CreatureStats& stats = MWWorld::Class::get(player).getCreatureStats(player);
MWMechanics::Spells& spells = stats.getSpells(); if (type == Type_Item || type == Type_MagicItem)
{
MWWorld::Ptr item = *button->getChildAt (0)->getUserData<MWWorld::Ptr>();
// make sure the item is available
if (item.getRefData ().getCount() < 1)
{
// Try searching for a compatible replacement
std::string id = item.getCellRef().mRefID;
for (MWWorld::ContainerStoreIterator it = store.begin(); it != store.end(); ++it)
{
if (Misc::StringUtils::ciEqual(it->getCellRef().mRefID, id))
{
item = *it;
button->getChildAt(0)->setUserData(item);
break;
}
}
if (item.getRefData().getCount() < 1)
{
// No replacement was found
MWBase::Environment::get().getWindowManager ()->messageBox (
"#{sQuickMenu5} " + MWWorld::Class::get(item).getName(item));
return;
}
}
}
if (type == Type_Magic) if (type == Type_Magic)
{ {
std::string spellId = button->getChildAt(0)->getUserString("Spell"); std::string spellId = button->getChildAt(0)->getUserString("Spell");
spells.setSelectedSpell(spellId);
store.setSelectedEnchantItem(store.end()); store.setSelectedEnchantItem(store.end());
MWBase::Environment::get().getWindowManager()->setSelectedSpell(spellId, int(MWMechanics::getSpellSuccessChance(spellId, player))); MWBase::Environment::get().getWindowManager()->setSelectedSpell(spellId, int(MWMechanics::getSpellSuccessChance(spellId, player)));
} }
@ -283,15 +309,6 @@ namespace MWGui
{ {
MWWorld::Ptr item = *button->getChildAt (0)->getUserData<MWWorld::Ptr>(); MWWorld::Ptr item = *button->getChildAt (0)->getUserData<MWWorld::Ptr>();
// make sure the item is available
if (item.getRefData ().getCount() < 1)
{
// TODO: Try to find a replacement with the same ID?
MWBase::Environment::get().getWindowManager ()->messageBox (
"#{sQuickMenu5} " + MWWorld::Class::get(item).getName(item));
return;
}
boost::shared_ptr<MWWorld::Action> action = MWWorld::Class::get(item).use(item); boost::shared_ptr<MWWorld::Action> action = MWWorld::Class::get(item).use(item);
action->execute (MWBase::Environment::get().getWorld()->getPlayer().getPlayer()); action->execute (MWBase::Environment::get().getWorld()->getPlayer().getPlayer());
@ -310,14 +327,6 @@ namespace MWGui
{ {
MWWorld::Ptr item = *button->getChildAt (0)->getUserData<MWWorld::Ptr>(); MWWorld::Ptr item = *button->getChildAt (0)->getUserData<MWWorld::Ptr>();
// make sure the item is available
if (item.getRefData ().getCount() == 0)
{
MWBase::Environment::get().getWindowManager ()->messageBox (
"#{sQuickMenu5} " + MWWorld::Class::get(item).getName(item));
return;
}
// retrieve ContainerStoreIterator to the item // retrieve ContainerStoreIterator to the item
MWWorld::ContainerStoreIterator it = store.begin(); MWWorld::ContainerStoreIterator it = store.begin();
for (; it != store.end(); ++it) for (; it != store.end(); ++it)
@ -336,13 +345,9 @@ namespace MWGui
MWWorld::ActionEquip action(item); MWWorld::ActionEquip action(item);
action.execute (MWBase::Environment::get().getWorld ()->getPlayer ().getPlayer ()); action.execute (MWBase::Environment::get().getWorld ()->getPlayer ().getPlayer ());
// since we changed equipping status, update the inventory window
MWBase::Environment::get().getWindowManager()->getInventoryWindow()->updateItemView();
} }
store.setSelectedEnchantItem(it); store.setSelectedEnchantItem(it);
spells.setSelectedSpell("");
MWBase::Environment::get().getWindowManager()->setSelectedEnchantItem(item); MWBase::Environment::get().getWindowManager()->setSelectedEnchantItem(item);
} }
} }

@ -65,7 +65,7 @@ namespace MWGui
getWidget(attribute, std::string("Attribute") + boost::lexical_cast<std::string>(idx)); getWidget(attribute, std::string("Attribute") + boost::lexical_cast<std::string>(idx));
mAttributeWidgets.insert(std::make_pair(static_cast<int>(ESM::Attribute::sAttributeIds[idx]), attribute)); mAttributeWidgets.insert(std::make_pair(static_cast<int>(ESM::Attribute::sAttributeIds[idx]), attribute));
attribute->setAttributeId(ESM::Attribute::sAttributeIds[idx]); attribute->setAttributeId(ESM::Attribute::sAttributeIds[idx]);
attribute->setAttributeValue(Widgets::MWAttribute::AttributeValue(0, 0)); attribute->setAttributeValue(Widgets::MWAttribute::AttributeValue());
} }
// Setup skills // Setup skills
@ -74,7 +74,7 @@ namespace MWGui
for (int i = 0; i < ESM::Skill::Length; ++i) for (int i = 0; i < ESM::Skill::Length; ++i)
{ {
mSkillValues.insert(std::make_pair(i, MWMechanics::Stat<float>())); mSkillValues.insert(std::make_pair(i, MWMechanics::SkillValue()));
mSkillWidgetMap.insert(std::make_pair(i, static_cast<MyGUI::TextBox*> (0))); mSkillWidgetMap.insert(std::make_pair(i, static_cast<MyGUI::TextBox*> (0)));
} }
@ -152,7 +152,7 @@ namespace MWGui
mFatigue->setUserString("Caption_HealthDescription", "#{sFatDesc}\n" + valStr); mFatigue->setUserString("Caption_HealthDescription", "#{sFatDesc}\n" + valStr);
} }
void ReviewDialog::setAttribute(ESM::Attribute::AttributeID attributeId, const MWMechanics::Stat<int>& value) void ReviewDialog::setAttribute(ESM::Attribute::AttributeID attributeId, const MWMechanics::AttributeValue& value)
{ {
std::map<int, Widgets::MWAttributePtr>::iterator attr = mAttributeWidgets.find(static_cast<int>(attributeId)); std::map<int, Widgets::MWAttributePtr>::iterator attr = mAttributeWidgets.find(static_cast<int>(attributeId));
if (attr == mAttributeWidgets.end()) if (attr == mAttributeWidgets.end())
@ -161,7 +161,7 @@ namespace MWGui
attr->second->setAttributeValue(value); attr->second->setAttributeValue(value);
} }
void ReviewDialog::setSkillValue(ESM::Skill::SkillEnum skillId, const MWMechanics::Stat<float>& value) void ReviewDialog::setSkillValue(ESM::Skill::SkillEnum skillId, const MWMechanics::SkillValue& value)
{ {
mSkillValues[skillId] = value; mSkillValues[skillId] = value;
MyGUI::TextBox* widget = mSkillWidgetMap[skillId]; MyGUI::TextBox* widget = mSkillWidgetMap[skillId];
@ -279,9 +279,9 @@ namespace MWGui
continue; continue;
assert(skillId >= 0 && skillId < ESM::Skill::Length); assert(skillId >= 0 && skillId < ESM::Skill::Length);
const std::string &skillNameId = ESM::Skill::sSkillNameIds[skillId]; const std::string &skillNameId = ESM::Skill::sSkillNameIds[skillId];
const MWMechanics::Stat<float> &stat = mSkillValues.find(skillId)->second; const MWMechanics::SkillValue &stat = mSkillValues.find(skillId)->second;
float base = stat.getBase(); int base = stat.getBase();
float modified = stat.getModified(); int modified = stat.getModified();
std::string state = "normal"; std::string state = "normal";
if (modified > base) if (modified > base)

@ -38,10 +38,10 @@ namespace MWGui
void setMagicka(const MWMechanics::DynamicStat<float>& value); void setMagicka(const MWMechanics::DynamicStat<float>& value);
void setFatigue(const MWMechanics::DynamicStat<float>& value); void setFatigue(const MWMechanics::DynamicStat<float>& value);
void setAttribute(ESM::Attribute::AttributeID attributeId, const MWMechanics::Stat<int>& value); void setAttribute(ESM::Attribute::AttributeID attributeId, const MWMechanics::AttributeValue& value);
void configureSkills(const SkillList& major, const SkillList& minor); void configureSkills(const SkillList& major, const SkillList& minor);
void setSkillValue(ESM::Skill::SkillEnum skillId, const MWMechanics::Stat<float>& value); void setSkillValue(ESM::Skill::SkillEnum skillId, const MWMechanics::SkillValue& value);
virtual void open(); virtual void open();
@ -85,7 +85,7 @@ namespace MWGui
std::map<int, Widgets::MWAttributePtr> mAttributeWidgets; std::map<int, Widgets::MWAttributePtr> mAttributeWidgets;
SkillList mMajorSkills, mMinorSkills, mMiscSkills; SkillList mMajorSkills, mMinorSkills, mMiscSkills;
std::map<int, MWMechanics::Stat<float> > mSkillValues; std::map<int, MWMechanics::SkillValue > mSkillValues;
std::map<int, MyGUI::TextBox*> mSkillWidgetMap; std::map<int, MyGUI::TextBox*> mSkillWidgetMap;
std::string mName, mRaceId, mBirthSignId; std::string mName, mRaceId, mBirthSignId;
ESM::Class mKlass; ESM::Class mKlass;

@ -92,6 +92,7 @@ namespace MWGui
{ {
getWidget(mOkButton, "OkButton"); getWidget(mOkButton, "OkButton");
getWidget(mBestAttackButton, "BestAttackButton"); getWidget(mBestAttackButton, "BestAttackButton");
getWidget(mGrabCursorButton, "GrabCursorButton");
getWidget(mSubtitlesButton, "SubtitlesButton"); getWidget(mSubtitlesButton, "SubtitlesButton");
getWidget(mCrosshairButton, "CrosshairButton"); getWidget(mCrosshairButton, "CrosshairButton");
getWidget(mResolutionList, "ResolutionList"); getWidget(mResolutionList, "ResolutionList");
@ -133,6 +134,7 @@ namespace MWGui
mSubtitlesButton->eventMouseButtonClick += MyGUI::newDelegate(this, &SettingsWindow::onButtonToggled); mSubtitlesButton->eventMouseButtonClick += MyGUI::newDelegate(this, &SettingsWindow::onButtonToggled);
mCrosshairButton->eventMouseButtonClick += MyGUI::newDelegate(this, &SettingsWindow::onButtonToggled); mCrosshairButton->eventMouseButtonClick += MyGUI::newDelegate(this, &SettingsWindow::onButtonToggled);
mBestAttackButton->eventMouseButtonClick += MyGUI::newDelegate(this, &SettingsWindow::onButtonToggled); mBestAttackButton->eventMouseButtonClick += MyGUI::newDelegate(this, &SettingsWindow::onButtonToggled);
mGrabCursorButton->eventMouseButtonClick += MyGUI::newDelegate(this, &SettingsWindow::onButtonToggled);
mInvertYButton->eventMouseButtonClick += MyGUI::newDelegate(this, &SettingsWindow::onButtonToggled); mInvertYButton->eventMouseButtonClick += MyGUI::newDelegate(this, &SettingsWindow::onButtonToggled);
mOkButton->eventMouseButtonClick += MyGUI::newDelegate(this, &SettingsWindow::onOkButtonClicked); mOkButton->eventMouseButtonClick += MyGUI::newDelegate(this, &SettingsWindow::onOkButtonClicked);
mShadersButton->eventMouseButtonClick += MyGUI::newDelegate(this, &SettingsWindow::onShadersToggled); mShadersButton->eventMouseButtonClick += MyGUI::newDelegate(this, &SettingsWindow::onShadersToggled);
@ -201,6 +203,7 @@ namespace MWGui
mSubtitlesButton->setCaptionWithReplacing(Settings::Manager::getBool("subtitles", "GUI") ? "#{sOn}" : "#{sOff}"); mSubtitlesButton->setCaptionWithReplacing(Settings::Manager::getBool("subtitles", "GUI") ? "#{sOn}" : "#{sOff}");
mCrosshairButton->setCaptionWithReplacing(Settings::Manager::getBool("crosshair", "HUD") ? "#{sOn}" : "#{sOff}"); mCrosshairButton->setCaptionWithReplacing(Settings::Manager::getBool("crosshair", "HUD") ? "#{sOn}" : "#{sOff}");
mBestAttackButton->setCaptionWithReplacing(Settings::Manager::getBool("best attack", "Game") ? "#{sOn}" : "#{sOff}"); mBestAttackButton->setCaptionWithReplacing(Settings::Manager::getBool("best attack", "Game") ? "#{sOn}" : "#{sOff}");
mGrabCursorButton->setCaptionWithReplacing(Settings::Manager::getBool("grab cursor", "Input") ? "#{sOn}" : "#{sOff}");
float fovVal = (Settings::Manager::getFloat("field of view", "General")-sFovMin)/(sFovMax-sFovMin); float fovVal = (Settings::Manager::getFloat("field of view", "General")-sFovMin)/(sFovMax-sFovMin);
mFOVSlider->setScrollPosition(fovVal * (mFOVSlider->getScrollRange()-1)); mFOVSlider->setScrollPosition(fovVal * (mFOVSlider->getScrollRange()-1));
@ -393,7 +396,8 @@ namespace MWGui
Settings::Manager::setBool("subtitles", "GUI", newState); Settings::Manager::setBool("subtitles", "GUI", newState);
else if (_sender == mBestAttackButton) else if (_sender == mBestAttackButton)
Settings::Manager::setBool("best attack", "Game", newState); Settings::Manager::setBool("best attack", "Game", newState);
else if (_sender == mGrabCursorButton)
Settings::Manager::setBool("grab cursor", "Input", newState);
apply(); apply();
} }
} }

@ -33,6 +33,7 @@ namespace MWGui
MyGUI::Button* mSubtitlesButton; MyGUI::Button* mSubtitlesButton;
MyGUI::Button* mCrosshairButton; MyGUI::Button* mCrosshairButton;
MyGUI::Button* mBestAttackButton; MyGUI::Button* mBestAttackButton;
MyGUI::Button* mGrabCursorButton;
// graphics // graphics
MyGUI::ListBox* mResolutionList; MyGUI::ListBox* mResolutionList;

@ -22,7 +22,8 @@ namespace MWGui
{ {
void EffectSourceVisitor::visit (MWMechanics::EffectKey key, void EffectSourceVisitor::visit (MWMechanics::EffectKey key,
const std::string& sourceName, float magnitude, float remainingTime) const std::string& sourceName, const std::string& casterHandle,
float magnitude, float remainingTime)
{ {
MagicEffectInfo newEffectSource; MagicEffectInfo newEffectSource;
newEffectSource.mKey = key; newEffectSource.mKey = key;

@ -43,7 +43,8 @@ namespace MWGui
std::map <int, std::vector<MagicEffectInfo> > mEffectSources; std::map <int, std::vector<MagicEffectInfo> > mEffectSources;
virtual void visit (MWMechanics::EffectKey key, virtual void visit (MWMechanics::EffectKey key,
const std::string& sourceName, float magnitude, float remainingTime = -1); const std::string& sourceName, const std::string& casterHandle,
float magnitude, float remainingTime = -1);
}; };
class SpellIcons class SpellIcons

@ -86,61 +86,8 @@ namespace MWGui
MWMechanics::CreatureStats& stats = MWWorld::Class::get(player).getCreatureStats(player); MWMechanics::CreatureStats& stats = MWWorld::Class::get(player).getCreatureStats(player);
MWMechanics::Spells& spells = stats.getSpells(); MWMechanics::Spells& spells = stats.getSpells();
// the following code switches between selected enchanted item and selected spell (only one of these
// can be active at a time)
std::string selectedSpell = spells.getSelectedSpell();
MWWorld::Ptr selectedItem;
if (store.getSelectedEnchantItem() != store.end())
{
selectedSpell = "";
selectedItem = *store.getSelectedEnchantItem();
bool allowSelectedItem = true;
// make sure that the item is still in the player inventory, otherwise it can't be selected
bool found = false;
for (MWWorld::ContainerStoreIterator it(store.begin()); it != store.end(); ++it)
{
if (*it == selectedItem)
found = true;
}
if (!found)
allowSelectedItem = false;
// if the selected item can be equipped, make sure that it actually is equipped
std::pair<std::vector<int>, bool> slots_;
slots_ = MWWorld::Class::get(selectedItem).getEquipmentSlots(selectedItem);
if (!slots_.first.empty())
{
bool equipped = false;
for (int i=0; i < MWWorld::InventoryStore::Slots; ++i)
{
if (store.getSlot(i) != store.end() && *store.getSlot(i) == selectedItem)
{
equipped = true;
break;
}
}
if (!equipped)
allowSelectedItem = false;
}
if (!allowSelectedItem)
{
store.setSelectedEnchantItem(store.end());
spells.setSelectedSpell("");
MWBase::Environment::get().getWindowManager()->unsetSelectedSpell();
selectedItem = MWWorld::Ptr();
}
}
for (MWMechanics::Spells::TIterator it = spells.begin(); it != spells.end(); ++it) for (MWMechanics::Spells::TIterator it = spells.begin(); it != spells.end(); ++it)
{
spellList.push_back (it->first); spellList.push_back (it->first);
}
const MWWorld::ESMStore &esmStore = const MWWorld::ESMStore &esmStore =
MWBase::Environment::get().getWorld()->getStore(); MWBase::Environment::get().getWorld()->getStore();
@ -210,7 +157,7 @@ namespace MWGui
t->eventMouseWheel += MyGUI::newDelegate(this, &SpellWindow::onMouseWheel); t->eventMouseWheel += MyGUI::newDelegate(this, &SpellWindow::onMouseWheel);
t->eventMouseButtonClick += MyGUI::newDelegate(this, &SpellWindow::onSpellSelected); t->eventMouseButtonClick += MyGUI::newDelegate(this, &SpellWindow::onSpellSelected);
if (*it == selectedSpell) if (*it == MWBase::Environment::get().getWindowManager()->getSelectedSpell())
t->setStateSelected(true); t->setStateSelected(true);
mHeight += spellHeight; mHeight += spellHeight;
@ -229,7 +176,7 @@ namespace MWGui
t->setUserString("Spell", *it); t->setUserString("Spell", *it);
t->eventMouseWheel += MyGUI::newDelegate(this, &SpellWindow::onMouseWheel); t->eventMouseWheel += MyGUI::newDelegate(this, &SpellWindow::onMouseWheel);
t->eventMouseButtonClick += MyGUI::newDelegate(this, &SpellWindow::onSpellSelected); t->eventMouseButtonClick += MyGUI::newDelegate(this, &SpellWindow::onSpellSelected);
t->setStateSelected(*it == selectedSpell); t->setStateSelected(*it == MWBase::Environment::get().getWindowManager()->getSelectedSpell());
// cost / success chance // cost / success chance
MyGUI::Button* costChance = mSpellView->createWidget<MyGUI::Button>("SpellText", MyGUI::Button* costChance = mSpellView->createWidget<MyGUI::Button>("SpellText",
@ -239,7 +186,7 @@ namespace MWGui
costChance->setCaption(cost + "/" + chance); costChance->setCaption(cost + "/" + chance);
costChance->setTextAlign(MyGUI::Align::Right); costChance->setTextAlign(MyGUI::Align::Right);
costChance->setNeedMouseFocus(false); costChance->setNeedMouseFocus(false);
costChance->setStateSelected(*it == selectedSpell); costChance->setStateSelected(*it == MWBase::Environment::get().getWindowManager()->getSelectedSpell());
mHeight += spellHeight; mHeight += spellHeight;
@ -276,7 +223,9 @@ namespace MWGui
t->setUserString("Equipped", equipped ? "true" : "false"); t->setUserString("Equipped", equipped ? "true" : "false");
t->eventMouseButtonClick += MyGUI::newDelegate(this, &SpellWindow::onEnchantedItemSelected); t->eventMouseButtonClick += MyGUI::newDelegate(this, &SpellWindow::onEnchantedItemSelected);
t->eventMouseWheel += MyGUI::newDelegate(this, &SpellWindow::onMouseWheel); t->eventMouseWheel += MyGUI::newDelegate(this, &SpellWindow::onMouseWheel);
t->setStateSelected(item == selectedItem); if (store.getSelectedEnchantItem() != store.end())
t->setStateSelected(item == *store.getSelectedEnchantItem());
// cost / charge // cost / charge
MyGUI::Button* costCharge = mSpellView->createWidget<MyGUI::Button>(equipped ? "SpellText" : "SpellTextUnequipped", MyGUI::Button* costCharge = mSpellView->createWidget<MyGUI::Button>(equipped ? "SpellText" : "SpellTextUnequipped",
@ -302,7 +251,8 @@ namespace MWGui
costCharge->setCaption(cost + "/" + charge); costCharge->setCaption(cost + "/" + charge);
costCharge->setTextAlign(MyGUI::Align::Right); costCharge->setTextAlign(MyGUI::Align::Right);
costCharge->setNeedMouseFocus(false); costCharge->setNeedMouseFocus(false);
costCharge->setStateSelected(item == selectedItem); if (store.getSelectedEnchantItem() != store.end())
costCharge->setStateSelected(item == *store.getSelectedEnchantItem());
mHeight += spellHeight; mHeight += spellHeight;
} }
@ -349,9 +299,7 @@ namespace MWGui
void SpellWindow::onEnchantedItemSelected(MyGUI::Widget* _sender) void SpellWindow::onEnchantedItemSelected(MyGUI::Widget* _sender)
{ {
MWWorld::Ptr player = MWBase::Environment::get().getWorld()->getPlayer().getPlayer(); MWWorld::Ptr player = MWBase::Environment::get().getWorld()->getPlayer().getPlayer();
MWMechanics::CreatureStats& stats = MWWorld::Class::get(player).getCreatureStats(player);
MWWorld::InventoryStore& store = MWWorld::Class::get(player).getInventoryStore(player); MWWorld::InventoryStore& store = MWWorld::Class::get(player).getInventoryStore(player);
MWMechanics::Spells& spells = stats.getSpells();
MWWorld::Ptr item = *_sender->getUserData<MWWorld::Ptr>(); MWWorld::Ptr item = *_sender->getUserData<MWWorld::Ptr>();
// retrieve ContainerStoreIterator to the item // retrieve ContainerStoreIterator to the item
@ -379,7 +327,6 @@ namespace MWGui
} }
store.setSelectedEnchantItem(it); store.setSelectedEnchantItem(it);
spells.setSelectedSpell("");
MWBase::Environment::get().getWindowManager()->setSelectedEnchantItem(item); MWBase::Environment::get().getWindowManager()->setSelectedEnchantItem(item);
updateSpells(); updateSpells();
@ -389,9 +336,7 @@ namespace MWGui
{ {
std::string spellId = _sender->getUserString("Spell"); std::string spellId = _sender->getUserString("Spell");
MWWorld::Ptr player = MWBase::Environment::get().getWorld()->getPlayer().getPlayer(); MWWorld::Ptr player = MWBase::Environment::get().getWorld()->getPlayer().getPlayer();
MWMechanics::CreatureStats& stats = MWWorld::Class::get(player).getCreatureStats(player);
MWWorld::InventoryStore& store = MWWorld::Class::get(player).getInventoryStore(player); MWWorld::InventoryStore& store = MWWorld::Class::get(player).getInventoryStore(player);
MWMechanics::Spells& spells = stats.getSpells();
if (MyGUI::InputManager::getInstance().isShiftPressed()) if (MyGUI::InputManager::getInstance().isShiftPressed())
{ {
@ -419,7 +364,6 @@ namespace MWGui
} }
else else
{ {
spells.setSelectedSpell(spellId);
store.setSelectedEnchantItem(store.end()); store.setSelectedEnchantItem(store.end());
MWBase::Environment::get().getWindowManager()->setSelectedSpell(spellId, int(MWMechanics::getSpellSuccessChance(spellId, player))); MWBase::Environment::get().getWindowManager()->setSelectedSpell(spellId, int(MWMechanics::getSpellSuccessChance(spellId, player)));
} }
@ -449,11 +393,8 @@ namespace MWGui
MWMechanics::CreatureStats& stats = MWWorld::Class::get(player).getCreatureStats(player); MWMechanics::CreatureStats& stats = MWWorld::Class::get(player).getCreatureStats(player);
MWMechanics::Spells& spells = stats.getSpells(); MWMechanics::Spells& spells = stats.getSpells();
if (spells.getSelectedSpell() == mSpellToDelete) if (MWBase::Environment::get().getWindowManager()->getSelectedSpell() == mSpellToDelete)
{
spells.setSelectedSpell("");
MWBase::Environment::get().getWindowManager()->unsetSelectedSpell(); MWBase::Environment::get().getWindowManager()->unsetSelectedSpell();
}
spells.remove(mSpellToDelete); spells.remove(mSpellToDelete);

@ -61,7 +61,7 @@ namespace MWGui
for (int i = 0; i < ESM::Skill::Length; ++i) for (int i = 0; i < ESM::Skill::Length; ++i)
{ {
mSkillValues.insert(std::pair<int, MWMechanics::Stat<float> >(i, MWMechanics::Stat<float>())); mSkillValues.insert(std::pair<int, MWMechanics::SkillValue >(i, MWMechanics::SkillValue()));
mSkillWidgetMap.insert(std::pair<int, MyGUI::TextBox*>(i, (MyGUI::TextBox*)NULL)); mSkillWidgetMap.insert(std::pair<int, MyGUI::TextBox*>(i, (MyGUI::TextBox*)NULL));
} }
@ -102,7 +102,7 @@ namespace MWGui
adjustWindowCaption(); adjustWindowCaption();
} }
void StatsWindow::setValue (const std::string& id, const MWMechanics::Stat<int>& value) void StatsWindow::setValue (const std::string& id, const MWMechanics::AttributeValue& value)
{ {
static const char *ids[] = static const char *ids[] =
{ {
@ -134,38 +134,28 @@ namespace MWGui
void StatsWindow::setValue (const std::string& id, const MWMechanics::DynamicStat<float>& value) void StatsWindow::setValue (const std::string& id, const MWMechanics::DynamicStat<float>& value)
{ {
static const char *ids[] = int current = std::max(0, static_cast<int>(value.getCurrent()));
{ int modified = static_cast<int>(value.getModified());
"HBar", "MBar", "FBar",
0
};
for (int i=0; ids[i]; ++i) setBar (id, id + "T", current, modified);
{
if (ids[i]==id)
{
std::string id (ids[i]);
setBar (id, id + "T", static_cast<int>(value.getCurrent()), static_cast<int>(value.getModified()));
// health, magicka, fatigue tooltip // health, magicka, fatigue tooltip
MyGUI::Widget* w; MyGUI::Widget* w;
std::string valStr = boost::lexical_cast<std::string>(value.getCurrent()) + "/" + boost::lexical_cast<std::string>(value.getModified()); std::string valStr = boost::lexical_cast<std::string>(current) + "/" + boost::lexical_cast<std::string>(modified);
if (i==0) if (id == "HBar")
{ {
getWidget(w, "Health"); getWidget(w, "Health");
w->setUserString("Caption_HealthDescription", "#{sHealthDesc}\n" + valStr); w->setUserString("Caption_HealthDescription", "#{sHealthDesc}\n" + valStr);
} }
else if (i==1) else if (id == "MBar")
{ {
getWidget(w, "Magicka"); getWidget(w, "Magicka");
w->setUserString("Caption_HealthDescription", "#{sIntDesc}\n" + valStr); w->setUserString("Caption_HealthDescription", "#{sIntDesc}\n" + valStr);
} }
else if (i==2) else if (id == "FBar")
{ {
getWidget(w, "Fatigue"); getWidget(w, "Fatigue");
w->setUserString("Caption_HealthDescription", "#{sFatDesc}\n" + valStr); w->setUserString("Caption_HealthDescription", "#{sFatDesc}\n" + valStr);
}
}
} }
} }
@ -189,7 +179,7 @@ namespace MWGui
} }
} }
void StatsWindow::setValue(const ESM::Skill::SkillEnum parSkill, const MWMechanics::Stat<float>& value) void StatsWindow::setValue(const ESM::Skill::SkillEnum parSkill, const MWMechanics::SkillValue& value)
{ {
mSkillValues[parSkill] = value; mSkillValues[parSkill] = value;
MyGUI::TextBox* widget = mSkillWidgetMap[(int)parSkill]; MyGUI::TextBox* widget = mSkillWidgetMap[(int)parSkill];
@ -368,22 +358,20 @@ namespace MWGui
continue; continue;
assert(skillId >= 0 && skillId < ESM::Skill::Length); assert(skillId >= 0 && skillId < ESM::Skill::Length);
const std::string &skillNameId = ESM::Skill::sSkillNameIds[skillId]; const std::string &skillNameId = ESM::Skill::sSkillNameIds[skillId];
const MWMechanics::Stat<float> &stat = mSkillValues.find(skillId)->second; const MWMechanics::SkillValue &stat = mSkillValues.find(skillId)->second;
float base = stat.getBase(); int base = stat.getBase();
float modified = stat.getModified(); int modified = stat.getModified();
int progressPercent = (modified - float(static_cast<int>(modified))) * 100; int progressPercent = stat.getProgress() * 100;
const MWWorld::ESMStore &esmStore = const MWWorld::ESMStore &esmStore =
MWBase::Environment::get().getWorld()->getStore(); MWBase::Environment::get().getWorld()->getStore();
const ESM::Skill* skill = esmStore.get<ESM::Skill>().find(skillId); const ESM::Skill* skill = esmStore.get<ESM::Skill>().find(skillId);
assert(skill);
std::string icon = "icons\\k\\" + ESM::Skill::sIconNames[skillId]; std::string icon = "icons\\k\\" + ESM::Skill::sIconNames[skillId];
const ESM::Attribute* attr = const ESM::Attribute* attr =
esmStore.get<ESM::Attribute>().find(skill->mData.mAttribute); esmStore.get<ESM::Attribute>().find(skill->mData.mAttribute);
assert(attr);
std::string state = "normal"; std::string state = "normal";
if (modified > base) if (modified > base)
@ -494,7 +482,6 @@ namespace MWGui
ESM::RankData rankData = faction->mData.mRankData[it->second+1]; ESM::RankData rankData = faction->mData.mRankData[it->second+1];
const ESM::Attribute* attr1 = store.get<ESM::Attribute>().find(faction->mData.mAttribute[0]); const ESM::Attribute* attr1 = store.get<ESM::Attribute>().find(faction->mData.mAttribute[0]);
const ESM::Attribute* attr2 = store.get<ESM::Attribute>().find(faction->mData.mAttribute[1]); const ESM::Attribute* attr2 = store.get<ESM::Attribute>().find(faction->mData.mAttribute[1]);
assert(attr1 && attr2);
text += "\n#BF9959#{" + attr1->mName + "}: " + boost::lexical_cast<std::string>(rankData.mAttribute1) text += "\n#BF9959#{" + attr1->mName + "}: " + boost::lexical_cast<std::string>(rankData.mAttribute1)
+ ", #{" + attr2->mName + "}: " + boost::lexical_cast<std::string>(rankData.mAttribute2); + ", #{" + attr2->mName + "}: " + boost::lexical_cast<std::string>(rankData.mAttribute2);

@ -26,11 +26,11 @@ namespace MWGui
void setPlayerName(const std::string& playerName); void setPlayerName(const std::string& playerName);
/// Set value for the given ID. /// Set value for the given ID.
void setValue (const std::string& id, const MWMechanics::Stat<int>& value); void setValue (const std::string& id, const MWMechanics::AttributeValue& value);
void setValue (const std::string& id, const MWMechanics::DynamicStat<float>& value); void setValue (const std::string& id, const MWMechanics::DynamicStat<float>& value);
void setValue (const std::string& id, const std::string& value); void setValue (const std::string& id, const std::string& value);
void setValue (const std::string& id, int value); void setValue (const std::string& id, int value);
void setValue(const ESM::Skill::SkillEnum parSkill, const MWMechanics::Stat<float>& value); void setValue(const ESM::Skill::SkillEnum parSkill, const MWMechanics::SkillValue& value);
void configureSkills (const SkillList& major, const SkillList& minor); void configureSkills (const SkillList& major, const SkillList& minor);
void setReputation (int reputation) { if (reputation != mReputation) mChanged = true; this->mReputation = reputation; } void setReputation (int reputation) { if (reputation != mReputation) mChanged = true; this->mReputation = reputation; }
@ -61,7 +61,7 @@ namespace MWGui
MyGUI::ScrollView* mSkillView; MyGUI::ScrollView* mSkillView;
SkillList mMajorSkills, mMinorSkills, mMiscSkills; SkillList mMajorSkills, mMinorSkills, mMiscSkills;
std::map<int, MWMechanics::Stat<float> > mSkillValues; std::map<int, MWMechanics::SkillValue > mSkillValues;
std::map<int, MyGUI::TextBox*> mSkillWidgetMap; std::map<int, MyGUI::TextBox*> mSkillWidgetMap;
std::map<std::string, MyGUI::Widget*> mFactionWidgetMap; std::map<std::string, MyGUI::Widget*> mFactionWidgetMap;
FactionList mFactions; ///< Stores a list of factions and the current rank FactionList mFactions; ///< Stores a list of factions and the current rank

@ -15,8 +15,8 @@ namespace MWGui
public: public:
TextInputDialog(); TextInputDialog();
std::string getTextInput() const { return mTextEdit ? mTextEdit->getOnlyText() : ""; } std::string getTextInput() const { return mTextEdit->getCaption(); }
void setTextInput(const std::string &text) { if (mTextEdit) mTextEdit->setOnlyText(text); } void setTextInput(const std::string &text) { mTextEdit->setCaption(text); }
void setNextButtonShow(bool shown); void setNextButtonShow(bool shown);
void setTextLabel(const std::string &label); void setTextLabel(const std::string &label);

@ -154,6 +154,13 @@ namespace MWGui
if(!MWWorld::Class::get(base).canSell(base, services)) if(!MWWorld::Class::get(base).canSell(base, services))
continue; continue;
// Bound items may not be bought
if (item.mBase.getCellRef().mRefID.size() > 6
&& item.mBase.getCellRef().mRefID.substr(0,6) == "bound_")
{
continue;
}
// don't show equipped items // don't show equipped items
if(mMerchant.getTypeName() == typeid(ESM::NPC).name()) if(mMerchant.getTypeName() == typeid(ESM::NPC).name())
{ {

@ -24,6 +24,7 @@
#include "containeritemmodel.hpp" #include "containeritemmodel.hpp"
#include "tradeitemmodel.hpp" #include "tradeitemmodel.hpp"
#include "countdialog.hpp" #include "countdialog.hpp"
#include "dialogue.hpp"
namespace MWGui namespace MWGui
{ {
@ -296,10 +297,10 @@ namespace MWGui
const MWMechanics::NpcStats &sellerStats = MWWorld::Class::get(mPtr).getNpcStats(mPtr); const MWMechanics::NpcStats &sellerStats = MWWorld::Class::get(mPtr).getNpcStats(mPtr);
const MWMechanics::NpcStats &playerStats = MWWorld::Class::get(playerPtr).getNpcStats(playerPtr); const MWMechanics::NpcStats &playerStats = MWWorld::Class::get(playerPtr).getNpcStats(playerPtr);
float a1 = std::min(playerStats.getSkill(ESM::Skill::Mercantile).getModified(), 100.f); float a1 = std::min(playerStats.getSkill(ESM::Skill::Mercantile).getModified(), 100);
float b1 = std::min(0.1f * playerStats.getAttribute(ESM::Attribute::Luck).getModified(), 10.f); float b1 = std::min(0.1f * playerStats.getAttribute(ESM::Attribute::Luck).getModified(), 10.f);
float c1 = std::min(0.2f * playerStats.getAttribute(ESM::Attribute::Personality).getModified(), 10.f); float c1 = std::min(0.2f * playerStats.getAttribute(ESM::Attribute::Personality).getModified(), 10.f);
float d1 = std::min(sellerStats.getSkill(ESM::Skill::Mercantile).getModified(), 100.f); float d1 = std::min(sellerStats.getSkill(ESM::Skill::Mercantile).getModified(), 100);
float e1 = std::min(0.1f * sellerStats.getAttribute(ESM::Attribute::Luck).getModified(), 10.f); float e1 = std::min(0.1f * sellerStats.getAttribute(ESM::Attribute::Luck).getModified(), 10.f);
float f1 = std::min(0.2f * sellerStats.getAttribute(ESM::Attribute::Personality).getModified(), 10.f); float f1 = std::min(0.2f * sellerStats.getAttribute(ESM::Attribute::Personality).getModified(), 10.f);
@ -340,6 +341,9 @@ namespace MWGui
addOrRemoveGold(-mCurrentBalance, mPtr); addOrRemoveGold(-mCurrentBalance, mPtr);
} }
MWBase::Environment::get().getWindowManager()->getDialogueWindow()->addResponse(
MWBase::Environment::get().getWorld()->getStore().get<ESM::GameSetting>().find("sBarterDialog5")->getString());
std::string sound = "Item Gold Up"; std::string sound = "Item Gold Up";
MWBase::Environment::get().getSoundManager()->playSound (sound, 1.0, 1.0); MWBase::Environment::get().getSoundManager()->playSound (sound, 1.0, 1.0);

@ -112,7 +112,7 @@ namespace MWGui
float hourlyHealthDelta = stats.getAttribute(ESM::Attribute::Endurance).getModified() * 0.1; float hourlyHealthDelta = stats.getAttribute(ESM::Attribute::Endurance).getModified() * 0.1;
bool stunted = (stats.getMagicEffects().get(MWMechanics::EffectKey(ESM::MagicEffect::StuntedMagicka)).mMagnitude > 0); bool stunted = (stats.getMagicEffects().get(ESM::MagicEffect::StuntedMagicka).mMagnitude > 0);
float fRestMagicMult = store.get<ESM::GameSetting>().find("fRestMagicMult")->getFloat(); float fRestMagicMult = store.get<ESM::GameSetting>().find("fRestMagicMult")->getFloat();
float hourlyMagickaDelta = fRestMagicMult * stats.getAttribute(ESM::Attribute::Intelligence).getModified(); float hourlyMagickaDelta = fRestMagicMult * stats.getAttribute(ESM::Attribute::Intelligence).getModified();

@ -178,7 +178,7 @@ namespace MWGui
} }
if (mAttributeValueWidget) if (mAttributeValueWidget)
{ {
AttributeValue::Type modified = mValue.getModified(), base = mValue.getBase(); int modified = mValue.getModified(), base = mValue.getBase();
static_cast<MyGUI::TextBox*>(mAttributeValueWidget)->setCaption(boost::lexical_cast<std::string>(modified)); static_cast<MyGUI::TextBox*>(mAttributeValueWidget)->setCaption(boost::lexical_cast<std::string>(modified));
if (modified > base) if (modified > base)
mAttributeValueWidget->_setWidgetState("increased"); mAttributeValueWidget->_setWidgetState("increased");
@ -528,14 +528,9 @@ namespace MWGui
if (mBarTextWidget) if (mBarTextWidget)
{ {
if (mValue >= 0 && mMax > 0) std::stringstream out;
{ out << mValue << "/" << mMax;
std::stringstream out; static_cast<MyGUI::TextBox*>(mBarTextWidget)->setCaption(out.str().c_str());
out << mValue << "/" << mMax;
static_cast<MyGUI::TextBox*>(mBarTextWidget)->setCaption(out.str().c_str());
}
else
static_cast<MyGUI::TextBox*>(mBarTextWidget)->setCaption("");
} }
} }
void MWDynamicStat::setTitle(const std::string& text) void MWDynamicStat::setTitle(const std::string& text)

@ -133,7 +133,7 @@ namespace MWGui
public: public:
MWAttribute(); MWAttribute();
typedef MWMechanics::Stat<int> AttributeValue; typedef MWMechanics::AttributeValue AttributeValue;
void setAttributeId(int attributeId); void setAttributeId(int attributeId);
void setAttributeValue(const AttributeValue& value); void setAttributeValue(const AttributeValue& value);

@ -16,6 +16,7 @@
#include "../mwbase/inputmanager.hpp" #include "../mwbase/inputmanager.hpp"
#include "../mwworld/class.hpp" #include "../mwworld/class.hpp"
#include "../mwworld/player.hpp"
#include "console.hpp" #include "console.hpp"
#include "journalwindow.hpp" #include "journalwindow.hpp"
@ -112,9 +113,6 @@ namespace MWGui
, mPlayerMinorSkills() , mPlayerMinorSkills()
, mPlayerMajorSkills() , mPlayerMajorSkills()
, mPlayerSkillValues() , mPlayerSkillValues()
, mPlayerHealth()
, mPlayerMagicka()
, mPlayerFatigue()
, mGui(NULL) , mGui(NULL)
, mGuiModes() , mGuiModes()
, mCursorManager(NULL) , mCursorManager(NULL)
@ -177,11 +175,11 @@ namespace MWGui
MyGUI::InputManager::getInstance().eventChangeKeyFocus += MyGUI::newDelegate(this, &WindowManager::onKeyFocusChanged); MyGUI::InputManager::getInstance().eventChangeKeyFocus += MyGUI::newDelegate(this, &WindowManager::onKeyFocusChanged);
mCursorManager->setEnabled(true);
onCursorChange(MyGUI::PointerManager::getInstance().getDefaultPointer()); onCursorChange(MyGUI::PointerManager::getInstance().getDefaultPointer());
SDL_ShowCursor(false); SDL_ShowCursor(false);
mCursorManager->setEnabled(true);
// hide mygui's pointer // hide mygui's pointer
MyGUI::PointerManager::getInstance().setVisible(false); MyGUI::PointerManager::getInstance().setVisible(false);
} }
@ -251,12 +249,12 @@ namespace MWGui
// Setup player stats // Setup player stats
for (int i = 0; i < ESM::Attribute::Length; ++i) for (int i = 0; i < ESM::Attribute::Length; ++i)
{ {
mPlayerAttributes.insert(std::make_pair(ESM::Attribute::sAttributeIds[i], MWMechanics::Stat<int>())); mPlayerAttributes.insert(std::make_pair(ESM::Attribute::sAttributeIds[i], MWMechanics::AttributeValue()));
} }
for (int i = 0; i < ESM::Skill::Length; ++i) for (int i = 0; i < ESM::Skill::Length; ++i)
{ {
mPlayerSkillValues.insert(std::make_pair(ESM::Skill::sSkillIds[i], MWMechanics::Stat<float>())); mPlayerSkillValues.insert(std::make_pair(ESM::Skill::sSkillIds[i], MWMechanics::SkillValue()));
} }
// Set up visibility // Set up visibility
@ -325,6 +323,7 @@ namespace MWGui
delete mSoulgemDialog; delete mSoulgemDialog;
delete mCursorManager; delete mCursorManager;
delete mRecharge; delete mRecharge;
delete mCompanionWindow;
cleanupGarbage(); cleanupGarbage();
@ -545,7 +544,7 @@ namespace MWGui
} }
} }
void WindowManager::setValue (const std::string& id, const MWMechanics::Stat<int>& value) void WindowManager::setValue (const std::string& id, const MWMechanics::AttributeValue& value)
{ {
mStatsWindow->setValue (id, value); mStatsWindow->setValue (id, value);
mCharGen->setValue(id, value); mCharGen->setValue(id, value);
@ -576,7 +575,7 @@ namespace MWGui
} }
void WindowManager::setValue (int parSkill, const MWMechanics::Stat<float>& value) void WindowManager::setValue (int parSkill, const MWMechanics::SkillValue& value)
{ {
/// \todo Don't use the skill enum as a parameter type (we will have to drop it anyway, once we /// \todo Don't use the skill enum as a parameter type (we will have to drop it anyway, once we
/// allow custom skills. /// allow custom skills.
@ -590,32 +589,8 @@ namespace MWGui
mStatsWindow->setValue (id, value); mStatsWindow->setValue (id, value);
mHud->setValue (id, value); mHud->setValue (id, value);
mCharGen->setValue(id, value); mCharGen->setValue(id, value);
if (id == "HBar")
{
mPlayerHealth = value;
}
else if (id == "MBar")
{
mPlayerMagicka = value;
}
else if (id == "FBar")
{
mPlayerFatigue = value;
}
} }
#if 0
MWMechanics::DynamicStat<int> WindowManager::getValue(const std::string& id)
{
if(id == "HBar")
return mPlayerHealth;
else if (id == "MBar")
return mPlayerMagicka;
else if (id == "FBar")
return mPlayerFatigue;
}
#endif
void WindowManager::setValue (const std::string& id, const std::string& value) void WindowManager::setValue (const std::string& id, const std::string& value)
{ {
mStatsWindow->setValue (id, value); mStatsWindow->setValue (id, value);
@ -788,6 +763,13 @@ namespace MWGui
{ {
mMap->setCellPrefix( cell->mCell->mName ); mMap->setCellPrefix( cell->mCell->mName );
mHud->setCellPrefix( cell->mCell->mName ); mHud->setCellPrefix( cell->mCell->mName );
Ogre::Vector3 worldPos;
if (!MWBase::Environment::get().getWorld()->findInteriorPositionInWorldSpace(cell, worldPos))
worldPos = MWBase::Environment::get().getWorld()->getPlayer().getLastKnownExteriorPosition();
else
MWBase::Environment::get().getWorld()->getPlayer().setLastKnownExteriorPosition(worldPos);
mMap->setGlobalMapPlayerPosition(worldPos.x, worldPos.y);
} }
} }
@ -1023,6 +1005,7 @@ namespace MWGui
void WindowManager::setSelectedSpell(const std::string& spellId, int successChancePercent) void WindowManager::setSelectedSpell(const std::string& spellId, int successChancePercent)
{ {
mSelectedSpell = spellId;
mHud->setSelectedSpell(spellId, successChancePercent); mHud->setSelectedSpell(spellId, successChancePercent);
const ESM::Spell* spell = const ESM::Spell* spell =
@ -1033,6 +1016,7 @@ namespace MWGui
void WindowManager::setSelectedEnchantItem(const MWWorld::Ptr& item) void WindowManager::setSelectedEnchantItem(const MWWorld::Ptr& item)
{ {
mSelectedSpell = "";
const ESM::Enchantment* ench = MWBase::Environment::get().getWorld()->getStore().get<ESM::Enchantment>() const ESM::Enchantment* ench = MWBase::Environment::get().getWorld()->getStore().get<ESM::Enchantment>()
.find(MWWorld::Class::get(item).getEnchantment(item)); .find(MWWorld::Class::get(item).getEnchantment(item));
@ -1052,6 +1036,7 @@ namespace MWGui
void WindowManager::unsetSelectedSpell() void WindowManager::unsetSelectedSpell()
{ {
mSelectedSpell = "";
mHud->unsetSelectedSpell(); mHud->unsetSelectedSpell();
mSpellWindow->setTitle("#{sNone}"); mSpellWindow->setTitle("#{sNone}");
} }
@ -1179,12 +1164,12 @@ namespace MWGui
return mGuiModes.back(); return mGuiModes.back();
} }
std::map<int, MWMechanics::Stat<float> > WindowManager::getPlayerSkillValues() std::map<int, MWMechanics::SkillValue > WindowManager::getPlayerSkillValues()
{ {
return mPlayerSkillValues; return mPlayerSkillValues;
} }
std::map<int, MWMechanics::Stat<int> > WindowManager::getPlayerAttributeValues() std::map<int, MWMechanics::AttributeValue > WindowManager::getPlayerAttributeValues()
{ {
return mPlayerAttributes; return mPlayerAttributes;
} }

@ -152,8 +152,8 @@ namespace MWGui
virtual void wmUpdateFps(float fps, unsigned int triangleCount, unsigned int batchCount); virtual void wmUpdateFps(float fps, unsigned int triangleCount, unsigned int batchCount);
///< Set value for the given ID. ///< Set value for the given ID.
virtual void setValue (const std::string& id, const MWMechanics::Stat<int>& value); virtual void setValue (const std::string& id, const MWMechanics::AttributeValue& value);
virtual void setValue (int parSkill, const MWMechanics::Stat<float>& value); virtual void setValue (int parSkill, const MWMechanics::SkillValue& value);
virtual void setValue (const std::string& id, const MWMechanics::DynamicStat<float>& value); virtual void setValue (const std::string& id, const MWMechanics::DynamicStat<float>& value);
virtual void setValue (const std::string& id, const std::string& value); virtual void setValue (const std::string& id, const std::string& value);
virtual void setValue (const std::string& id, int value); virtual void setValue (const std::string& id, int value);
@ -200,6 +200,7 @@ namespace MWGui
virtual void activateQuickKey (int index); virtual void activateQuickKey (int index);
virtual std::string getSelectedSpell() { return mSelectedSpell; }
virtual void setSelectedSpell(const std::string& spellId, int successChancePercent); virtual void setSelectedSpell(const std::string& spellId, int successChancePercent);
virtual void setSelectedEnchantItem(const MWWorld::Ptr& item); virtual void setSelectedEnchantItem(const MWWorld::Ptr& item);
virtual void setSelectedWeapon(const MWWorld::Ptr& item); virtual void setSelectedWeapon(const MWWorld::Ptr& item);
@ -228,8 +229,8 @@ namespace MWGui
virtual void onFrame (float frameDuration); virtual void onFrame (float frameDuration);
/// \todo get rid of this stuff. Move it to the respective UI element classes, if needed. /// \todo get rid of this stuff. Move it to the respective UI element classes, if needed.
virtual std::map<int, MWMechanics::Stat<float> > getPlayerSkillValues(); virtual std::map<int, MWMechanics::SkillValue > getPlayerSkillValues();
virtual std::map<int, MWMechanics::Stat<int> > getPlayerAttributeValues(); virtual std::map<int, MWMechanics::AttributeValue > getPlayerAttributeValues();
virtual SkillList getPlayerMinorSkills(); virtual SkillList getPlayerMinorSkills();
virtual SkillList getPlayerMajorSkills(); virtual SkillList getPlayerMajorSkills();
@ -288,6 +289,8 @@ namespace MWGui
void trackWindow(OEngine::GUI::Layout* layout, const std::string& name); void trackWindow(OEngine::GUI::Layout* layout, const std::string& name);
void onWindowChangeCoord(MyGUI::Window* _sender); void onWindowChangeCoord(MyGUI::Window* _sender);
std::string mSelectedSpell;
OEngine::GUI::MyGUIManager *mGuiManager; OEngine::GUI::MyGUIManager *mGuiManager;
OEngine::Render::OgreRenderer *mRendering; OEngine::Render::OgreRenderer *mRendering;
HUD *mHud; HUD *mHud;
@ -343,11 +346,9 @@ namespace MWGui
// Various stats about player as needed by window manager // Various stats about player as needed by window manager
std::string mPlayerName; std::string mPlayerName;
std::string mPlayerRaceId; std::string mPlayerRaceId;
std::map<int, MWMechanics::Stat<int> > mPlayerAttributes; std::map<int, MWMechanics::AttributeValue > mPlayerAttributes;
SkillList mPlayerMajorSkills, mPlayerMinorSkills; SkillList mPlayerMajorSkills, mPlayerMinorSkills;
std::map<int, MWMechanics::Stat<float> > mPlayerSkillValues; std::map<int, MWMechanics::SkillValue > mPlayerSkillValues;
MWMechanics::DynamicStat<float> mPlayerHealth, mPlayerMagicka, mPlayerFatigue;
MyGUI::Gui *mGui; // Gui MyGUI::Gui *mGui; // Gui
std::vector<GuiMode> mGuiModes; std::vector<GuiMode> mGuiModes;

@ -9,6 +9,7 @@
#include <MyGUI_RenderManager.h> #include <MyGUI_RenderManager.h>
#include <MyGUI_Widget.h> #include <MyGUI_Widget.h>
#include <MyGUI_Button.h> #include <MyGUI_Button.h>
#include <MyGUI_EditBox.h>
#include <openengine/ogre/renderer.hpp> #include <openengine/ogre/renderer.hpp>
@ -20,7 +21,6 @@
#include "../mwbase/windowmanager.hpp" #include "../mwbase/windowmanager.hpp"
#include "../mwbase/soundmanager.hpp" #include "../mwbase/soundmanager.hpp"
#include "../mwbase/statemanager.hpp" #include "../mwbase/statemanager.hpp"
#include "../mwgui/bookwindow.hpp"
#include "../mwmechanics/creaturestats.hpp" #include "../mwmechanics/creaturestats.hpp"
using namespace ICS; using namespace ICS;
@ -104,6 +104,7 @@ namespace MWInput
, mCameraSensitivity (Settings::Manager::getFloat("camera sensitivity", "Input")) , mCameraSensitivity (Settings::Manager::getFloat("camera sensitivity", "Input"))
, mUISensitivity (Settings::Manager::getFloat("ui sensitivity", "Input")) , mUISensitivity (Settings::Manager::getFloat("ui sensitivity", "Input"))
, mCameraYMultiplier (Settings::Manager::getFloat("camera y multiplier", "Input")) , mCameraYMultiplier (Settings::Manager::getFloat("camera y multiplier", "Input"))
, mGrabCursor (Settings::Manager::getBool("grab cursor", "Input"))
, mPreviewPOVDelay(0.f) , mPreviewPOVDelay(0.f)
, mTimeIdle(0.f) , mTimeIdle(0.f)
, mOverencumberedMessageDelay(0.f) , mOverencumberedMessageDelay(0.f)
@ -290,7 +291,7 @@ namespace MWInput
mInputManager->setMouseRelative(is_relative); mInputManager->setMouseRelative(is_relative);
//we let the mouse escape in the main menu //we let the mouse escape in the main menu
mInputManager->setGrabPointer(grab); mInputManager->setGrabPointer(grab && (mGrabCursor || is_relative));
//we switched to non-relative mode, move our cursor to where the in-game //we switched to non-relative mode, move our cursor to where the in-game
//cursor is //cursor is
@ -383,10 +384,9 @@ namespace MWInput
MWBase::Environment::get().getWorld()->togglePreviewMode(true); MWBase::Environment::get().getWorld()->togglePreviewMode(true);
} }
} else { } else {
if (mPreviewPOVDelay > 0.5) { //disable preview mode
//disable preview mode MWBase::Environment::get().getWorld()->togglePreviewMode(false);
MWBase::Environment::get().getWorld()->togglePreviewMode(false); if (mPreviewPOVDelay > 0.f && mPreviewPOVDelay <= 0.5) {
} else if (mPreviewPOVDelay > 0.f) {
MWBase::Environment::get().getWorld()->togglePOV(); MWBase::Environment::get().getWorld()->togglePOV();
} }
mPreviewPOVDelay = 0.f; mPreviewPOVDelay = 0.f;
@ -436,6 +436,9 @@ namespace MWInput
if (it->first == "Input" && it->second == "ui sensitivity") if (it->first == "Input" && it->second == "ui sensitivity")
mUISensitivity = Settings::Manager::getFloat("ui sensitivity", "Input"); mUISensitivity = Settings::Manager::getFloat("ui sensitivity", "Input");
if (it->first == "Input" && it->second == "grab cursor")
mGrabCursor = Settings::Manager::getBool("grab cursor", "Input");
} }
} }
@ -499,6 +502,9 @@ namespace MWInput
edit->deleteTextSelection(); edit->deleteTextSelection();
} }
} }
}
if (edit && !edit->getEditStatic())
{
if (arg.keysym.sym == SDLK_c && (arg.keysym.mod & SDL_Keymod(KMOD_CTRL))) if (arg.keysym.sym == SDLK_c && (arg.keysym.mod & SDL_Keymod(KMOD_CTRL)))
{ {
std::string text = edit->getTextSelection(); std::string text = edit->getTextSelection();
@ -593,15 +599,6 @@ namespace MWInput
mMouseWheel = int(arg.z); mMouseWheel = int(arg.z);
MyGUI::InputManager::getInstance().injectMouseMove( int(mMouseX), int(mMouseY), mMouseWheel); MyGUI::InputManager::getInstance().injectMouseMove( int(mMouseX), int(mMouseY), mMouseWheel);
//if the player is reading a book and flicking the mouse wheel
if (MWBase::Environment::get().getWindowManager()->getMode() == MWGui::GM_Book && arg.zrel)
{
if (arg.zrel < 0)
MWBase::Environment::get().getWindowManager()->getBookWindow()->nextPage();
else
MWBase::Environment::get().getWindowManager()->getBookWindow()->prevPage();
}
} }
if (mMouseLookEnabled) if (mMouseLookEnabled)
@ -678,7 +675,7 @@ namespace MWInput
if (MWBase::Environment::get().getWindowManager()->isGuiMode()) return; if (MWBase::Environment::get().getWindowManager()->isGuiMode()) return;
// Not allowed before the magic window is accessible // Not allowed before the magic window is accessible
if (!MWBase::Environment::get().getWindowManager()->isAllowed(MWGui::GW_Magic)) if (!mControlSwitch["playermagic"])
return; return;
MWMechanics::DrawState_ state = mPlayer->getDrawState(); MWMechanics::DrawState_ state = mPlayer->getDrawState();
@ -693,7 +690,7 @@ namespace MWInput
if (MWBase::Environment::get().getWindowManager()->isGuiMode()) return; if (MWBase::Environment::get().getWindowManager()->isGuiMode()) return;
// Not allowed before the inventory window is accessible // Not allowed before the inventory window is accessible
if (!MWBase::Environment::get().getWindowManager()->isAllowed(MWGui::GW_Inventory)) if (!mControlSwitch["playerfighting"])
return; return;
MWMechanics::DrawState_ state = mPlayer->getDrawState(); MWMechanics::DrawState_ state = mPlayer->getDrawState();
@ -833,9 +830,11 @@ namespace MWInput
void InputManager::updateIdleTime(float dt) void InputManager::updateIdleTime(float dt)
{ {
static const float vanityDelay = MWBase::Environment::get().getWorld()->getStore().get<ESM::GameSetting>()
.find("fVanityDelay")->getFloat();
if (mTimeIdle >= 0.f) if (mTimeIdle >= 0.f)
mTimeIdle += dt; mTimeIdle += dt;
if (mTimeIdle > 30.f) { if (mTimeIdle > vanityDelay) {
MWBase::Environment::get().getWorld()->toggleVanityMode(true); MWBase::Environment::get().getWorld()->toggleVanityMode(true);
mTimeIdle = -1.f; mTimeIdle = -1.f;
} }

@ -1,5 +1,5 @@
#ifndef _MWINPUT_MWINPUTMANAGERIMP_H #ifndef MWINPUT_MWINPUTMANAGERIMP_H
#define _MWINPUT_MWINPUTMANAGERIMP_H #define MWINPUT_MWINPUTMANAGERIMP_H
#include "../mwgui/mode.hpp" #include "../mwgui/mode.hpp"
@ -138,6 +138,8 @@ namespace MWInput
bool mDragDrop; bool mDragDrop;
bool mGrabCursor;
bool mInvertY; bool mInvertY;
float mCameraSensitivity; float mCameraSensitivity;

@ -126,7 +126,8 @@ namespace MWMechanics
return mSpells; return mSpells;
} }
void ActiveSpells::addSpell(const std::string &id, bool stack, std::vector<Effect> effects, const std::string &displayName) void ActiveSpells::addSpell(const std::string &id, bool stack, std::vector<Effect> effects,
const std::string &displayName, const std::string& casterHandle)
{ {
bool exists = false; bool exists = false;
for (TContainer::const_iterator it = begin(); it != end(); ++it) for (TContainer::const_iterator it = begin(); it != end(); ++it)
@ -139,6 +140,7 @@ namespace MWMechanics
params.mTimeStamp = MWBase::Environment::get().getWorld()->getTimeStamp(); params.mTimeStamp = MWBase::Environment::get().getWorld()->getTimeStamp();
params.mEffects = effects; params.mEffects = effects;
params.mDisplayName = displayName; params.mDisplayName = displayName;
params.mCasterHandle = casterHandle;
if (!exists || stack) if (!exists || stack)
mSpells.insert (std::make_pair(id, params)); mSpells.insert (std::make_pair(id, params));
@ -148,6 +150,12 @@ namespace MWMechanics
mSpellsChanged = true; mSpellsChanged = true;
} }
void ActiveSpells::removeEffects(const std::string &id)
{
mSpells.erase(Misc::StringUtils::lowerCase(id));
mSpellsChanged = true;
}
void ActiveSpells::visitEffectSources(EffectSourceVisitor &visitor) const void ActiveSpells::visitEffectSources(EffectSourceVisitor &visitor) const
{ {
for (TContainer::const_iterator it = begin(); it != end(); ++it) for (TContainer::const_iterator it = begin(); it != end(); ++it)
@ -164,14 +172,22 @@ namespace MWMechanics
float magnitude = effectIt->mMagnitude; float magnitude = effectIt->mMagnitude;
if (magnitude) if (magnitude)
visitor.visit(effectIt->mKey, name, magnitude, remainingTime); visitor.visit(effectIt->mKey, name, it->second.mCasterHandle, magnitude, remainingTime);
} }
} }
} }
void ActiveSpells::purgeAll() void ActiveSpells::purgeAll(float chance)
{ {
mSpells.clear(); for (TContainer::iterator it = mSpells.begin(); it != mSpells.end(); )
{
int roll = std::rand()/ (static_cast<double> (RAND_MAX) + 1) * 100; // [0, 99]
if (roll < chance)
mSpells.erase(it++);
else
++it;
}
mSpellsChanged = true;
} }
void ActiveSpells::purgeEffect(short effectId) void ActiveSpells::purgeEffect(short effectId)
@ -187,6 +203,6 @@ namespace MWMechanics
effectIt++; effectIt++;
} }
} }
mSpellsChanged = true;
} }
} }

@ -37,8 +37,8 @@ namespace MWMechanics
MWWorld::TimeStamp mTimeStamp; MWWorld::TimeStamp mTimeStamp;
std::string mDisplayName; std::string mDisplayName;
// TODO: To handle CASTER_LINKED flag (spell is purged when caster dies), // Handle to the caster that that inflicted this spell on us
// we should probably store a handle to the caster here. std::string mCasterHandle;
}; };
typedef std::multimap<std::string, ActiveSpellParams > TContainer; typedef std::multimap<std::string, ActiveSpellParams > TContainer;
@ -76,14 +76,19 @@ namespace MWMechanics
/// \param stack If false, the spell is not added if one with the same ID exists already. /// \param stack If false, the spell is not added if one with the same ID exists already.
/// \param effects /// \param effects
/// \param displayName Name for display in magic menu. /// \param displayName Name for display in magic menu.
/// \param casterHandle
/// ///
void addSpell (const std::string& id, bool stack, std::vector<Effect> effects, const std::string& displayName); void addSpell (const std::string& id, bool stack, std::vector<Effect> effects,
const std::string& displayName, const std::string& casterHandle);
/// Remove all active effects with this id /// Removes the active effects from this spell/potion/.. with \a id
void removeEffects (const std::string& id);
/// Remove all active effects with this effect id
void purgeEffect (short effectId); void purgeEffect (short effectId);
/// Remove all active effects /// Remove all active effects, if roll succeeds (for each effect)
void purgeAll (); void purgeAll (float chance);
bool isSpellActive (std::string id) const; bool isSpellActive (std::string id) const;
///< case insensitive ///< case insensitive

@ -46,15 +46,116 @@ void adjustBoundItem (const std::string& item, bool bound, const MWWorld::Ptr& a
} }
} }
bool disintegrateSlot (MWWorld::Ptr ptr, int slot, float disintegrate)
{
// TODO: remove this check once creatures support inventory store
if (ptr.getTypeName() == typeid(ESM::NPC).name())
{
MWWorld::InventoryStore& inv = ptr.getClass().getInventoryStore(ptr);
MWWorld::ContainerStoreIterator item =
inv.getSlot(slot);
if (item != inv.end())
{
if (!item->getClass().hasItemHealth(*item))
return false;
if (item->getCellRef().mCharge == -1)
item->getCellRef().mCharge = item->getClass().getItemMaxHealth(*item);
if (item->getCellRef().mCharge == 0)
return false;
item->getCellRef().mCharge -=
std::min(disintegrate,
static_cast<float>(item->getCellRef().mCharge));
if (item->getCellRef().mCharge == 0)
{
// Will unequip the broken item and try to find a replacement
if (ptr.getRefData().getHandle() != "player")
inv.autoEquip(ptr);
else
inv.unequipItem(*item, ptr);
}
return true;
}
}
return true;
}
} }
namespace MWMechanics namespace MWMechanics
{ {
class SoulTrap : public MWMechanics::EffectSourceVisitor
{
MWWorld::Ptr mCreature;
MWWorld::Ptr mActor;
public:
SoulTrap(MWWorld::Ptr trappedCreature)
: mCreature(trappedCreature) {}
virtual void visit (MWMechanics::EffectKey key,
const std::string& sourceName, const std::string& casterHandle,
float magnitude, float remainingTime = -1)
{
if (key.mId != ESM::MagicEffect::Soultrap)
return;
if (magnitude <= 0)
return;
MWBase::World* world = MWBase::Environment::get().getWorld();
MWWorld::Ptr caster = world->searchPtrViaHandle(casterHandle);
if (caster.isEmpty() || !caster.getClass().isActor())
return;
static const float fSoulgemMult = world->getStore().get<ESM::GameSetting>().find("fSoulgemMult")->getFloat();
float creatureSoulValue = mCreature.get<ESM::Creature>()->mBase->mData.mSoul;
// Use the smallest soulgem that is large enough to hold the soul
MWWorld::ContainerStore& container = caster.getClass().getContainerStore(caster);
MWWorld::ContainerStoreIterator gem = container.end();
float gemCapacity = std::numeric_limits<float>().max();
std::string soulgemFilter = "misc_soulgem"; // no other way to check for soulgems? :/
for (MWWorld::ContainerStoreIterator it = container.begin(MWWorld::ContainerStore::Type_Miscellaneous);
it != container.end(); ++it)
{
const std::string& id = it->getCellRef().mRefID;
if (id.size() >= soulgemFilter.size()
&& id.substr(0,soulgemFilter.size()) == soulgemFilter)
{
float thisGemCapacity = it->get<ESM::Miscellaneous>()->mBase->mData.mValue * fSoulgemMult;
if (thisGemCapacity >= creatureSoulValue && thisGemCapacity < gemCapacity
&& it->getCellRef().mSoul.empty())
{
gem = it;
gemCapacity = thisGemCapacity;
}
}
}
if (gem == container.end())
return;
// Set the soul on just one of the gems, not the whole stack
gem->getContainerStore()->unstack(*gem, caster);
gem->getCellRef().mSoul = mCreature.getCellRef().mRefID;
if (caster.getRefData().getHandle() == "player")
MWBase::Environment::get().getWindowManager()->messageBox("#{sSoultrapSuccess}");
}
};
void Actors::updateActor (const MWWorld::Ptr& ptr, float duration) void Actors::updateActor (const MWWorld::Ptr& ptr, float duration)
{ {
// magic effects // magic effects
adjustMagicEffects (ptr); adjustMagicEffects (ptr);
calculateDynamicStats (ptr); if (ptr.getClass().getCreatureStats(ptr).needToRecalcDynamicStats())
calculateDynamicStats (ptr);
calculateCreatureStatModifiers (ptr, duration); calculateCreatureStatModifiers (ptr, duration);
if(!MWBase::Environment::get().getWindowManager()->isGuiMode()) if(!MWBase::Environment::get().getWindowManager()->isGuiMode())
@ -71,7 +172,7 @@ namespace MWMechanics
float d = sqrt((actorpos.pos[0] - playerpos.pos[0])*(actorpos.pos[0] - playerpos.pos[0]) float d = sqrt((actorpos.pos[0] - playerpos.pos[0])*(actorpos.pos[0] - playerpos.pos[0])
+(actorpos.pos[1] - playerpos.pos[1])*(actorpos.pos[1] - playerpos.pos[1]) +(actorpos.pos[1] - playerpos.pos[1])*(actorpos.pos[1] - playerpos.pos[1])
+(actorpos.pos[2] - playerpos.pos[2])*(actorpos.pos[2] - playerpos.pos[2])); +(actorpos.pos[2] - playerpos.pos[2])*(actorpos.pos[2] - playerpos.pos[2]));
float fight = ptr.getClass().getCreatureStats(ptr).getAiSetting(1); float fight = ptr.getClass().getCreatureStats(ptr).getAiSetting(CreatureStats::AI_Fight).getModified();
float disp = 100; //creatures don't have disposition, so set it to 100 by default float disp = 100; //creatures don't have disposition, so set it to 100 by default
if(ptr.getTypeName() == typeid(ESM::NPC).name()) if(ptr.getTypeName() == typeid(ESM::NPC).name())
{ {
@ -127,7 +228,7 @@ namespace MWMechanics
now += creatureStats.getActiveSpells().getMagicEffects(); now += creatureStats.getActiveSpells().getMagicEffects();
MagicEffects diff = MagicEffects::diff (creatureStats.getMagicEffects(), now); //MagicEffects diff = MagicEffects::diff (creatureStats.getMagicEffects(), now);
creatureStats.setMagicEffects(now); creatureStats.setMagicEffects(now);
@ -177,7 +278,7 @@ namespace MWMechanics
{ {
// the actor is sleeping, restore health and magicka // the actor is sleeping, restore health and magicka
bool stunted = stats.getMagicEffects ().get(MWMechanics::EffectKey(ESM::MagicEffect::StuntedMagicka)).mMagnitude > 0; bool stunted = stats.getMagicEffects ().get(ESM::MagicEffect::StuntedMagicka).mMagnitude > 0;
DynamicStat<float> health = stats.getHealth(); DynamicStat<float> health = stats.getHealth();
health.setCurrent (health.getCurrent() + 0.1 * endurance); health.setCurrent (health.getCurrent() + 0.1 * endurance);
@ -216,7 +317,7 @@ namespace MWMechanics
// attributes // attributes
for(int i = 0;i < ESM::Attribute::Length;++i) for(int i = 0;i < ESM::Attribute::Length;++i)
{ {
Stat<int> stat = creatureStats.getAttribute(i); AttributeValue stat = creatureStats.getAttribute(i);
stat.setModifier(effects.get(EffectKey(ESM::MagicEffect::FortifyAttribute, i)).mMagnitude - stat.setModifier(effects.get(EffectKey(ESM::MagicEffect::FortifyAttribute, i)).mMagnitude -
effects.get(EffectKey(ESM::MagicEffect::DrainAttribute, i)).mMagnitude - effects.get(EffectKey(ESM::MagicEffect::DrainAttribute, i)).mMagnitude -
effects.get(EffectKey(ESM::MagicEffect::AbsorbAttribute, i)).mMagnitude); effects.get(EffectKey(ESM::MagicEffect::AbsorbAttribute, i)).mMagnitude);
@ -228,18 +329,69 @@ namespace MWMechanics
for(int i = 0;i < 3;++i) for(int i = 0;i < 3;++i)
{ {
DynamicStat<float> stat = creatureStats.getDynamic(i); DynamicStat<float> stat = creatureStats.getDynamic(i);
stat.setModifier(effects.get(EffectKey(ESM::MagicEffect::FortifyHealth+i)).mMagnitude - stat.setModifier(effects.get(ESM::MagicEffect::FortifyHealth+i).mMagnitude -
effects.get(EffectKey(ESM::MagicEffect::DrainHealth+i)).mMagnitude); effects.get(ESM::MagicEffect::DrainHealth+i).mMagnitude);
float currentDiff = creatureStats.getMagicEffects().get(EffectKey(ESM::MagicEffect::RestoreHealth+i)).mMagnitude float currentDiff = creatureStats.getMagicEffects().get(ESM::MagicEffect::RestoreHealth+i).mMagnitude
- creatureStats.getMagicEffects().get(EffectKey(ESM::MagicEffect::DamageHealth+i)).mMagnitude - creatureStats.getMagicEffects().get(ESM::MagicEffect::DamageHealth+i).mMagnitude
- creatureStats.getMagicEffects().get(EffectKey(ESM::MagicEffect::AbsorbHealth+i)).mMagnitude; - creatureStats.getMagicEffects().get(ESM::MagicEffect::AbsorbHealth+i).mMagnitude;
stat.setCurrent(stat.getCurrent() + currentDiff * duration); stat.setCurrent(stat.getCurrent() + currentDiff * duration);
creatureStats.setDynamic(i, stat); creatureStats.setDynamic(i, stat);
} }
// AI setting modifiers
int creature = !ptr.getClass().isNpc();
if (creature && ptr.get<ESM::Creature>()->mBase->mData.mType == ESM::Creature::Humanoid)
creature = false;
// Note: the Creature variants only work on normal creatures, not on daedra or undead creatures.
if (!creature || ptr.get<ESM::Creature>()->mBase->mData.mType == ESM::Creature::Creatures)
{
Stat<int> stat = creatureStats.getAiSetting(CreatureStats::AI_Fight);
stat.setModifier(creatureStats.getMagicEffects().get(ESM::MagicEffect::FrenzyHumanoid+creature).mMagnitude
- creatureStats.getMagicEffects().get(ESM::MagicEffect::CalmHumanoid+creature).mMagnitude);
creatureStats.setAiSetting(CreatureStats::AI_Fight, stat);
stat = creatureStats.getAiSetting(CreatureStats::AI_Flee);
stat.setModifier(creatureStats.getMagicEffects().get(ESM::MagicEffect::DemoralizeHumanoid+creature).mMagnitude
- creatureStats.getMagicEffects().get(ESM::MagicEffect::RallyHumanoid+creature).mMagnitude);
creatureStats.setAiSetting(CreatureStats::AI_Flee, stat);
}
if (creature && ptr.get<ESM::Creature>()->mBase->mData.mType == ESM::Creature::Undead)
{
Stat<int> stat = creatureStats.getAiSetting(CreatureStats::AI_Flee);
stat.setModifier(creatureStats.getMagicEffects().get(ESM::MagicEffect::TurnUndead).mMagnitude);
creatureStats.setAiSetting(CreatureStats::AI_Flee, stat);
}
// Apply disintegration (reduces item health)
float disintegrateWeapon = effects.get(ESM::MagicEffect::DisintegrateWeapon).mMagnitude;
if (disintegrateWeapon > 0)
disintegrateSlot(ptr, MWWorld::InventoryStore::Slot_CarriedRight, disintegrateWeapon*duration);
float disintegrateArmor = effects.get(ESM::MagicEffect::DisintegrateArmor).mMagnitude;
if (disintegrateArmor > 0)
{
// According to UESP
int priorities[] = {
MWWorld::InventoryStore::Slot_CarriedLeft,
MWWorld::InventoryStore::Slot_Cuirass,
MWWorld::InventoryStore::Slot_LeftPauldron,
MWWorld::InventoryStore::Slot_RightPauldron,
MWWorld::InventoryStore::Slot_LeftGauntlet,
MWWorld::InventoryStore::Slot_RightGauntlet,
MWWorld::InventoryStore::Slot_Helmet,
MWWorld::InventoryStore::Slot_Greaves,
MWWorld::InventoryStore::Slot_Boots
};
for (unsigned int i=0; i<sizeof(priorities)/sizeof(int); ++i)
{
if (disintegrateSlot(ptr, priorities[i], disintegrateArmor*duration))
break;
}
}
// Apply damage ticks // Apply damage ticks
int damageEffects[] = { int damageEffects[] = {
ESM::MagicEffect::FireDamage, ESM::MagicEffect::ShockDamage, ESM::MagicEffect::FrostDamage, ESM::MagicEffect::Poison, ESM::MagicEffect::FireDamage, ESM::MagicEffect::ShockDamage, ESM::MagicEffect::FrostDamage, ESM::MagicEffect::Poison,
@ -249,7 +401,7 @@ namespace MWMechanics
DynamicStat<float> health = creatureStats.getHealth(); DynamicStat<float> health = creatureStats.getHealth();
for (unsigned int i=0; i<sizeof(damageEffects)/sizeof(int); ++i) for (unsigned int i=0; i<sizeof(damageEffects)/sizeof(int); ++i)
{ {
float magnitude = creatureStats.getMagicEffects().get(EffectKey(damageEffects[i])).mMagnitude; float magnitude = creatureStats.getMagicEffects().get(damageEffects[i]).mMagnitude;
if (damageEffects[i] == ESM::MagicEffect::SunDamage) if (damageEffects[i] == ESM::MagicEffect::SunDamage)
{ {
@ -280,30 +432,32 @@ namespace MWMechanics
static std::map<int, std::string> boundItemsMap; static std::map<int, std::string> boundItemsMap;
if (boundItemsMap.empty()) if (boundItemsMap.empty())
{ {
boundItemsMap[ESM::MagicEffect::BoundBattleAxe] = "battle_axe"; boundItemsMap[ESM::MagicEffect::BoundBattleAxe] = "sMagicBoundBattleAxeID";
boundItemsMap[ESM::MagicEffect::BoundBoots] = "boots"; boundItemsMap[ESM::MagicEffect::BoundBoots] = "sMagicBoundBootsID";
boundItemsMap[ESM::MagicEffect::BoundCuirass] = "cuirass"; boundItemsMap[ESM::MagicEffect::BoundCuirass] = "sMagicBoundCuirassID";
boundItemsMap[ESM::MagicEffect::BoundDagger] = "dagger"; boundItemsMap[ESM::MagicEffect::BoundDagger] = "sMagicBoundDaggerID";
boundItemsMap[ESM::MagicEffect::BoundGloves] = "gauntlet"; // Note: needs both _left and _right variants, see below boundItemsMap[ESM::MagicEffect::BoundGloves] = "sMagicBoundLeftGauntletID"; // Note: needs RightGauntlet variant too (see below)
boundItemsMap[ESM::MagicEffect::BoundHelm] = "helm"; boundItemsMap[ESM::MagicEffect::BoundHelm] = "sMagicBoundHelmID";
boundItemsMap[ESM::MagicEffect::BoundLongbow] = "longbow"; boundItemsMap[ESM::MagicEffect::BoundLongbow] = "sMagicBoundLongbowID";
boundItemsMap[ESM::MagicEffect::BoundLongsword] = "longsword"; boundItemsMap[ESM::MagicEffect::BoundLongsword] = "sMagicBoundLongswordID";
boundItemsMap[ESM::MagicEffect::BoundMace] = "mace"; boundItemsMap[ESM::MagicEffect::BoundMace] = "sMagicBoundMaceID";
boundItemsMap[ESM::MagicEffect::BoundShield] = "shield"; boundItemsMap[ESM::MagicEffect::BoundShield] = "sMagicBoundShieldID";
boundItemsMap[ESM::MagicEffect::BoundSpear] = "spear"; boundItemsMap[ESM::MagicEffect::BoundSpear] = "sMagicBoundSpearID";
} }
for (std::map<int, std::string>::iterator it = boundItemsMap.begin(); it != boundItemsMap.end(); ++it) for (std::map<int, std::string>::iterator it = boundItemsMap.begin(); it != boundItemsMap.end(); ++it)
{ {
bool found = creatureStats.mBoundItems.find(it->first) != creatureStats.mBoundItems.end(); bool found = creatureStats.mBoundItems.find(it->first) != creatureStats.mBoundItems.end();
int magnitude = creatureStats.getMagicEffects().get(EffectKey(it->first)).mMagnitude; int magnitude = creatureStats.getMagicEffects().get(it->first).mMagnitude;
if (found != (magnitude > 0)) if (found != (magnitude > 0))
{ {
std::string item = "bound_" + it->second; std::string itemGmst = it->second;
std::string item = MWBase::Environment::get().getWorld()->getStore().get<ESM::GameSetting>().find(
itemGmst)->getString();
if (it->first == ESM::MagicEffect::BoundGloves) if (it->first == ESM::MagicEffect::BoundGloves)
{ {
adjustBoundItem(item + "_left", magnitude > 0, ptr); adjustBoundItem("sMagicBoundLeftGauntletID", magnitude > 0, ptr);
adjustBoundItem(item + "_right", magnitude > 0, ptr); adjustBoundItem("sMagicBoundRightGauntletID", magnitude > 0, ptr);
} }
else else
adjustBoundItem(item, magnitude > 0, ptr); adjustBoundItem(item, magnitude > 0, ptr);
@ -319,32 +473,34 @@ namespace MWMechanics
static std::map<int, std::string> summonMap; static std::map<int, std::string> summonMap;
if (summonMap.empty()) if (summonMap.empty())
{ {
summonMap[ESM::MagicEffect::SummonAncestralGhost] = "ancestor_ghost_summon"; summonMap[ESM::MagicEffect::SummonAncestralGhost] = "sMagicAncestralGhostID";
summonMap[ESM::MagicEffect::SummonBear] = "BM_bear_black_summon"; summonMap[ESM::MagicEffect::SummonBonelord] = "sMagicBonelordID";
summonMap[ESM::MagicEffect::SummonBonelord] = "bonelord_summon"; summonMap[ESM::MagicEffect::SummonBonewalker] = "sMagicLeastBonewalkerID";
summonMap[ESM::MagicEffect::SummonBonewalker] = "bonewalker_summon"; summonMap[ESM::MagicEffect::SummonCenturionSphere] = "sMagicCenturionSphereID";
summonMap[ESM::MagicEffect::SummonBonewolf] = "BM_wolf_bone_summon"; summonMap[ESM::MagicEffect::SummonClannfear] = "sMagicClannfearID";
summonMap[ESM::MagicEffect::SummonCenturionSphere] = "centurion_sphere_summon"; summonMap[ESM::MagicEffect::SummonDaedroth] = "sMagicDaedrothID";
summonMap[ESM::MagicEffect::SummonClannfear] = "clannfear_summon"; summonMap[ESM::MagicEffect::SummonDremora] = "sMagicDremoraID";
summonMap[ESM::MagicEffect::SummonDaedroth] = "daedroth_summon"; summonMap[ESM::MagicEffect::SummonFabricant] = "sMagicFabricantID";
summonMap[ESM::MagicEffect::SummonDremora] = "dremora_summon"; summonMap[ESM::MagicEffect::SummonFlameAtronach] = "sMagicFlameAtronachID";
summonMap[ESM::MagicEffect::SummonFabricant] = "fabricant_summon"; summonMap[ESM::MagicEffect::SummonFrostAtronach] = "sMagicFrostAtronachID";
summonMap[ESM::MagicEffect::SummonFlameAtronach] = "atronach_flame_summon"; summonMap[ESM::MagicEffect::SummonGoldenSaint] = "sMagicGoldenSaintID";
summonMap[ESM::MagicEffect::SummonFrostAtronach] = "atronach_frost_summon"; summonMap[ESM::MagicEffect::SummonGreaterBonewalker] = "sMagicGreaterBonewalkerID";
summonMap[ESM::MagicEffect::SummonGoldenSaint] = "golden saint_summon"; summonMap[ESM::MagicEffect::SummonHunger] = "sMagicHungerID";
summonMap[ESM::MagicEffect::SummonGreaterBonewalker] = "bonewalker_greater_summ"; summonMap[ESM::MagicEffect::SummonScamp] = "sMagicScampID";
summonMap[ESM::MagicEffect::SummonHunger] = "hunger_summon"; summonMap[ESM::MagicEffect::SummonSkeletalMinion] = "sMagicSkeletalMinionID";
summonMap[ESM::MagicEffect::SummonScamp] = "scamp_summon"; summonMap[ESM::MagicEffect::SummonStormAtronach] = "sMagicStormAtronachID";
summonMap[ESM::MagicEffect::SummonSkeletalMinion] = "skeleton_summon"; summonMap[ESM::MagicEffect::SummonWingedTwilight] = "sMagicWingedTwilightID";
summonMap[ESM::MagicEffect::SummonStormAtronach] = "atronach_storm_summon"; summonMap[ESM::MagicEffect::SummonWolf] = "sMagicCreature01ID";
summonMap[ESM::MagicEffect::SummonWingedTwilight] = "winged twilight_summon"; summonMap[ESM::MagicEffect::SummonBear] = "sMagicCreature02ID";
summonMap[ESM::MagicEffect::SummonWolf] = "BM_wolf_grey_summon"; summonMap[ESM::MagicEffect::SummonBonewolf] = "sMagicCreature03ID";
summonMap[ESM::MagicEffect::SummonCreature04] = "sMagicCreature04ID";
summonMap[ESM::MagicEffect::SummonCreature05] = "sMagicCreature05ID";
} }
for (std::map<int, std::string>::iterator it = summonMap.begin(); it != summonMap.end(); ++it) for (std::map<int, std::string>::iterator it = summonMap.begin(); it != summonMap.end(); ++it)
{ {
bool found = creatureStats.mSummonedCreatures.find(it->first) != creatureStats.mSummonedCreatures.end(); bool found = creatureStats.mSummonedCreatures.find(it->first) != creatureStats.mSummonedCreatures.end();
int magnitude = creatureStats.getMagicEffects().get(EffectKey(it->first)).mMagnitude; int magnitude = creatureStats.getMagicEffects().get(it->first).mMagnitude;
if (found != (magnitude > 0)) if (found != (magnitude > 0))
{ {
if (magnitude > 0) if (magnitude > 0)
@ -361,15 +517,20 @@ namespace MWMechanics
ipos.rot[1] = 0; ipos.rot[1] = 0;
ipos.rot[2] = 0; ipos.rot[2] = 0;
MWWorld::CellStore* store = ptr.getCell(); std::string creatureID =
MWWorld::ManualRef ref(MWBase::Environment::get().getWorld()->getStore(), it->second, 1); MWBase::Environment::get().getWorld()->getStore().get<ESM::GameSetting>().find(it->second)->getString();
ref.getPtr().getCellRef().mPos = ipos;
// TODO: Add AI to follow player and fight for him if (!creatureID.empty())
{
MWWorld::CellStore* store = ptr.getCell();
MWWorld::ManualRef ref(MWBase::Environment::get().getWorld()->getStore(), creatureID, 1);
ref.getPtr().getCellRef().mPos = ipos;
creatureStats.mSummonedCreatures.insert(std::make_pair(it->first, // TODO: Add AI to follow player and fight for him
MWBase::Environment::get().getWorld()->safePlaceObject(ref.getPtr(),*store,ipos).getRefData().getHandle()));
creatureStats.mSummonedCreatures.insert(std::make_pair(it->first,
MWBase::Environment::get().getWorld()->safePlaceObject(ref.getPtr(),*store,ipos).getRefData().getHandle()));
}
} }
else else
{ {
@ -395,7 +556,7 @@ namespace MWMechanics
// skills // skills
for(int i = 0;i < ESM::Skill::Length;++i) for(int i = 0;i < ESM::Skill::Length;++i)
{ {
Stat<float>& skill = npcStats.getSkill(i); SkillValue& skill = npcStats.getSkill(i);
skill.setModifier(effects.get(EffectKey(ESM::MagicEffect::FortifySkill, i)).mMagnitude - skill.setModifier(effects.get(EffectKey(ESM::MagicEffect::FortifySkill, i)).mMagnitude -
effects.get(EffectKey(ESM::MagicEffect::DrainSkill, i)).mMagnitude - effects.get(EffectKey(ESM::MagicEffect::DrainSkill, i)).mMagnitude -
effects.get(EffectKey(ESM::MagicEffect::AbsorbSkill, i)).mMagnitude); effects.get(EffectKey(ESM::MagicEffect::AbsorbSkill, i)).mMagnitude);
@ -439,15 +600,69 @@ namespace MWMechanics
void Actors::updateEquippedLight (const MWWorld::Ptr& ptr, float duration) void Actors::updateEquippedLight (const MWWorld::Ptr& ptr, float duration)
{ {
//If holding a light... bool isPlayer = ptr.getRefData().getHandle()=="player";
MWWorld::InventoryStore &inventoryStore = MWWorld::Class::get(ptr).getInventoryStore(ptr); MWWorld::InventoryStore &inventoryStore = MWWorld::Class::get(ptr).getInventoryStore(ptr);
MWWorld::ContainerStoreIterator heldIter = MWWorld::ContainerStoreIterator heldIter =
inventoryStore.getSlot(MWWorld::InventoryStore::Slot_CarriedLeft); inventoryStore.getSlot(MWWorld::InventoryStore::Slot_CarriedLeft);
/**
* Automatically equip NPCs torches at night and unequip them at day
*/
if (!isPlayer)
{
MWWorld::ContainerStoreIterator torch = inventoryStore.end();
for (MWWorld::ContainerStoreIterator it = inventoryStore.begin(); it != inventoryStore.end(); ++it)
{
if (it->getTypeName() == typeid(ESM::Light).name())
{
torch = it;
break;
}
}
if (MWBase::Environment::get().getWorld()->isDark())
{
if (torch != inventoryStore.end())
{
if (!MWWorld::Class::get (ptr).getCreatureStats (ptr).isHostile())
{
// For non-hostile NPCs, unequip whatever is in the left slot in favor of a light.
if (heldIter != inventoryStore.end() && heldIter->getTypeName() != typeid(ESM::Light).name())
inventoryStore.unequipItem(*heldIter, ptr);
// Also unequip twohanded weapons which conflict with anything in CarriedLeft
if (torch->getClass().canBeEquipped(*torch, ptr).first == 3)
inventoryStore.unequipSlot(MWWorld::InventoryStore::Slot_CarriedRight, ptr);
}
heldIter = inventoryStore.getSlot(MWWorld::InventoryStore::Slot_CarriedLeft);
// If we have a torch and can equip it (left slot free, no
// twohanded weapon in right slot), then equip it now.
if (heldIter == inventoryStore.end()
&& torch->getClass().canBeEquipped(*torch, ptr).first == 1)
{
inventoryStore.equip(MWWorld::InventoryStore::Slot_CarriedLeft, torch, ptr);
}
}
}
else
{
if (heldIter != inventoryStore.end() && heldIter->getTypeName() == typeid(ESM::Light).name())
{
// At day, unequip lights and auto equip shields or other suitable items
// (Note: autoEquip will ignore lights)
inventoryStore.autoEquip(ptr);
}
}
}
heldIter = inventoryStore.getSlot(MWWorld::InventoryStore::Slot_CarriedLeft);
//If holding a light...
if(heldIter.getType() == MWWorld::ContainerStore::Type_Light) if(heldIter.getType() == MWWorld::ContainerStore::Type_Light)
{ {
// Use time from the player's light // Use time from the player's light
bool isPlayer = ptr.getRefData().getHandle()=="player";
if(isPlayer) if(isPlayer)
{ {
float timeRemaining = heldIter->getClass().getRemainingUsageTime(*heldIter); float timeRemaining = heldIter->getClass().getRemainingUsageTime(*heldIter);
@ -482,6 +697,16 @@ namespace MWMechanics
Actors::Actors() {} Actors::Actors() {}
Actors::~Actors()
{
PtrControllerMap::iterator it(mActors.begin());
for (; it != mActors.end(); ++it)
{
delete it->second;
it->second = NULL;
}
}
void Actors::addActor (const MWWorld::Ptr& ptr) void Actors::addActor (const MWWorld::Ptr& ptr)
{ {
// erase previous death events since we are currently only tracking them while in an active cell // erase previous death events since we are currently only tracking them while in an active cell
@ -572,6 +797,18 @@ namespace MWMechanics
} }
} }
// Apply soultrap
if (iter->first.getTypeName() == typeid(ESM::Creature).name())
{
SoulTrap soulTrap (iter->first);
stats.getActiveSpells().visitEffectSources(soulTrap);
}
// Reset magic effects and recalculate derived effects
// One case where we need this is to make sure bound items are removed upon death
stats.setMagicEffects(MWMechanics::MagicEffects());
calculateCreatureStatModifiers(iter->first, 0);
if (iter->second->kill()) if (iter->second->kill())
{ {
++mDeathCount[cls.getId(iter->first)]; ++mDeathCount[cls.getId(iter->first)];
@ -592,7 +829,12 @@ namespace MWMechanics
iter->second->updateContinuousVfx(); iter->second->updateContinuousVfx();
for(PtrControllerMap::iterator iter(mActors.begin());iter != mActors.end();++iter) for(PtrControllerMap::iterator iter(mActors.begin());iter != mActors.end();++iter)
{
if (iter->first.getClass().getCreatureStats(iter->first).getMagicEffects().get(
ESM::MagicEffect::Paralyze).mMagnitude > 0)
iter->second->skipAnim();
iter->second->update(duration); iter->second->update(duration);
}
} }
} }
void Actors::restoreDynamicStats() void Actors::restoreDynamicStats()

@ -25,14 +25,12 @@ namespace MWMechanics
{ {
class Actors class Actors
{ {
typedef std::map<MWWorld::Ptr,CharacterController*> PtrControllerMap; typedef std::map<MWWorld::Ptr,CharacterController*> PtrControllerMap;
PtrControllerMap mActors; PtrControllerMap mActors;
std::map<std::string, int> mDeathCount;
void updateNpc(const MWWorld::Ptr &ptr, float duration, bool paused);
std::map<std::string, int> mDeathCount;
void updateNpc(const MWWorld::Ptr &ptr, float duration, bool paused);
void adjustMagicEffects (const MWWorld::Ptr& creature); void adjustMagicEffects (const MWWorld::Ptr& creature);
@ -50,6 +48,7 @@ namespace MWMechanics
public: public:
Actors(); Actors();
~Actors();
/// Update magic effects for an actor. Usually done automatically once per frame, but if we're currently /// Update magic effects for an actor. Usually done automatically once per frame, but if we're currently
/// paused we may want to do it manually (after equipping permanent enchantment) /// paused we may want to do it manually (after equipping permanent enchantment)

@ -91,6 +91,8 @@ namespace MWMechanics
mPathFinder.checkPathCompleted(pos.pos[0],pos.pos[1],pos.pos[2]); mPathFinder.checkPathCompleted(pos.pos[0],pos.pos[1],pos.pos[2]);
float zAngle = mPathFinder.getZAngleToNext(pos.pos[0], pos.pos[1]); float zAngle = mPathFinder.getZAngleToNext(pos.pos[0], pos.pos[1]);
// TODO: use movement settings instead of rotating directly
MWBase::Environment::get().getWorld()->rotateObject(actor, 0, 0, zAngle, false); MWBase::Environment::get().getWorld()->rotateObject(actor, 0, 0, zAngle, false);
MWWorld::Class::get(actor).getMovementSettings(actor).mPosition[1] = 1; MWWorld::Class::get(actor).getMovementSettings(actor).mPosition[1] = 1;
@ -105,6 +107,7 @@ namespace MWMechanics
float directionResult = sqrt(directionX * directionX + directionY * directionY); float directionResult = sqrt(directionX * directionX + directionY * directionY);
zAngle = Ogre::Radian( acos(directionY / directionResult) * sgn(asin(directionX / directionResult)) ).valueDegrees(); zAngle = Ogre::Radian( acos(directionY / directionResult) * sgn(asin(directionX / directionResult)) ).valueDegrees();
// TODO: use movement settings instead of rotating directly
MWBase::Environment::get().getWorld()->rotateObject(actor, 0, 0, zAngle, false); MWBase::Environment::get().getWorld()->rotateObject(actor, 0, 0, zAngle, false);
mPathFinder.clearPath(); mPathFinder.clearPath();

@ -161,6 +161,7 @@ namespace MWMechanics
if(distanceBetweenResult <= mMaxDist * mMaxDist) if(distanceBetweenResult <= mMaxDist * mMaxDist)
{ {
float zAngle = mPathFinder.getZAngleToNext(pos.pos[0], pos.pos[1]); float zAngle = mPathFinder.getZAngleToNext(pos.pos[0], pos.pos[1]);
// TODO: use movement settings instead of rotating directly
MWBase::Environment::get().getWorld()->rotateObject(actor, 0, 0, zAngle, false); MWBase::Environment::get().getWorld()->rotateObject(actor, 0, 0, zAngle, false);
MWWorld::Class::get(actor).getMovementSettings(actor).mPosition[1] = 1; MWWorld::Class::get(actor).getMovementSettings(actor).mPosition[1] = 1;
mMaxDist = 470; mMaxDist = 470;

@ -97,6 +97,7 @@ namespace MWMechanics
} }
float zAngle = mPathFinder.getZAngleToNext(pos.pos[0], pos.pos[1]); float zAngle = mPathFinder.getZAngleToNext(pos.pos[0], pos.pos[1]);
// TODO: use movement settings instead of rotating directly
world->rotateObject(actor, 0, 0, zAngle, false); world->rotateObject(actor, 0, 0, zAngle, false);
movement.mPosition[1] = 1; movement.mPosition[1] = 1;

@ -236,6 +236,7 @@ namespace MWMechanics
if(mWalking) if(mWalking)
{ {
float zAngle = mPathFinder.getZAngleToNext(pos.pos[0], pos.pos[1]); float zAngle = mPathFinder.getZAngleToNext(pos.pos[0], pos.pos[1]);
// TODO: use movement settings instead of rotating directly
world->rotateObject(actor, 0, 0, zAngle, false); world->rotateObject(actor, 0, 0, zAngle, false);
MWWorld::Class::get(actor).getMovementSettings(actor).mPosition[1] = 1; MWWorld::Class::get(actor).getMovementSettings(actor).mPosition[1] = 1;

@ -351,7 +351,6 @@ CharacterController::CharacterController(const MWWorld::Ptr &ptr, MWRender::Anim
, mSkipAnim(false) , mSkipAnim(false)
, mSecondsOfRunning(0) , mSecondsOfRunning(0)
, mSecondsOfSwimming(0) , mSecondsOfSwimming(0)
, mFallHeight(0)
{ {
if(!mAnimation) if(!mAnimation)
return; return;
@ -427,10 +426,10 @@ bool CharacterController::updateNpcState(bool onground, bool inwater, bool isrun
{ {
forcestateupdate = true; forcestateupdate = true;
// Shields shouldn't be visible during spellcasting // Shields/torches shouldn't be visible during spellcasting or hand-to-hand
// There seems to be no text keys for this purpose, except maybe for "[un]equip start/stop", // There seems to be no text keys for this purpose, except maybe for "[un]equip start/stop",
// but they are also present in weapon drawing animation. // but they are also present in weapon drawing animation.
mAnimation->showShield(weaptype != WeapType_Spell); mAnimation->showCarriedLeft(weaptype != WeapType_Spell && weaptype != WeapType_HandToHand);
std::string weapgroup; std::string weapgroup;
if(weaptype == WeapType_None) if(weaptype == WeapType_None)
@ -502,13 +501,25 @@ bool CharacterController::updateNpcState(bool onground, bool inwater, bool isrun
{ {
if(mUpperBodyState == UpperCharState_WeapEquiped) if(mUpperBodyState == UpperCharState_WeapEquiped)
{ {
MWBase::Environment::get().getWorld()->breakInvisibility(mPtr);
mAttackType.clear(); mAttackType.clear();
if(mWeaponType == WeapType_Spell) if(mWeaponType == WeapType_Spell)
{ {
// Unset casting flag, otherwise pressing the mouse button down would
// continue casting every frame if there is no animation
mPtr.getClass().getCreatureStats(mPtr).setAttackingOrSpell(false);
const MWWorld::ESMStore &store = MWBase::Environment::get().getWorld()->getStore(); const MWWorld::ESMStore &store = MWBase::Environment::get().getWorld()->getStore();
const std::string spellid = stats.getSpells().getSelectedSpell(); // For the player, set the spell we want to cast
if(!spellid.empty()) // This has to be done at the start of the casting animation,
// *not* when selecting a spell in the GUI (otherwise you could change the spell mid-animation)
if (mPtr.getRefData().getHandle() == "player")
stats.getSpells().setSelectedSpell(MWBase::Environment::get().getWindowManager()->getSelectedSpell());
std::string spellid = stats.getSpells().getSelectedSpell();
if(!spellid.empty() && MWBase::Environment::get().getWorld()->startSpellCast(mPtr))
{ {
static const std::string schools[] = { static const std::string schools[] = {
"alteration", "conjuration", "destruction", "illusion", "mysticism", "restoration" "alteration", "conjuration", "destruction", "illusion", "mysticism", "restoration"
@ -707,17 +718,18 @@ bool CharacterController::updateNpcState(bool onground, bool inwater, bool isrun
} }
} }
MWWorld::ContainerStoreIterator torch = inv.getSlot(MWWorld::InventoryStore::Slot_CarriedLeft); MWWorld::ContainerStoreIterator torch = inv.getSlot(MWWorld::InventoryStore::Slot_CarriedLeft);
if(torch != inv.end() && torch->getTypeName() == typeid(ESM::Light).name()) if(torch != inv.end() && torch->getTypeName() == typeid(ESM::Light).name()
&& mWeaponType != WeapType_Spell && mWeaponType != WeapType_HandToHand)
{ {
if(!mAnimation->isPlaying("torch")) mAnimation->play("torch", Priority_Torch, MWRender::Animation::Group_LeftArm,
mAnimation->play("torch", Priority_Torch, false, 1.0f, "start", "stop", 0.0f, (~(size_t)0));
MWRender::Animation::Group_LeftArm, false,
1.0f, "start", "stop", 0.0f, (~(size_t)0));
} }
else if(mAnimation->isPlaying("torch")) else if (mAnimation->isPlaying("torch"))
{
mAnimation->disable("torch"); mAnimation->disable("torch");
}
return forcestateupdate; return forcestateupdate;
} }
@ -728,6 +740,8 @@ void CharacterController::update(float duration)
const MWWorld::Class &cls = MWWorld::Class::get(mPtr); const MWWorld::Class &cls = MWWorld::Class::get(mPtr);
Ogre::Vector3 movement(0.0f); Ogre::Vector3 movement(0.0f);
updateVisibility();
if(!cls.isActor()) if(!cls.isActor())
{ {
if(mAnimQueue.size() > 1) if(mAnimQueue.size() > 1)
@ -787,10 +801,10 @@ void CharacterController::update(float duration)
} }
if(sneak || inwater || flying) if(sneak || inwater || flying)
{
vec.z = 0.0f; vec.z = 0.0f;
mFallHeight = mPtr.getRefData().getPosition().pos[2];
} if (inwater || flying)
cls.getCreatureStats(mPtr).land();
if(!onground && !flying && !inwater) if(!onground && !flying && !inwater)
{ {
@ -799,11 +813,7 @@ void CharacterController::update(float duration)
if (world->isSlowFalling(mPtr)) if (world->isSlowFalling(mPtr))
{ {
// SlowFalling spell effect is active, do not keep previous fall height // SlowFalling spell effect is active, do not keep previous fall height
mFallHeight = mPtr.getRefData().getPosition().pos[2]; cls.getCreatureStats(mPtr).land();
}
else
{
mFallHeight = std::max(mFallHeight, mPtr.getRefData().getPosition().pos[2]);
} }
const MWWorld::Store<ESM::GameSetting> &gmst = world->getStore().get<ESM::GameSetting>(); const MWWorld::Store<ESM::GameSetting> &gmst = world->getStore().get<ESM::GameSetting>();
@ -859,7 +869,8 @@ void CharacterController::update(float duration)
mJumpState = JumpState_Landing; mJumpState = JumpState_Landing;
vec.z = 0.0f; vec.z = 0.0f;
float healthLost = cls.getFallDamage(mPtr, mFallHeight - mPtr.getRefData().getPosition().pos[2]); float height = cls.getCreatureStats(mPtr).land();
float healthLost = cls.getFallDamage(mPtr, height);
if (healthLost > 0.0f) if (healthLost > 0.0f)
{ {
const float fatigueTerm = cls.getCreatureStats(mPtr).getFatigueTerm(); const float fatigueTerm = cls.getCreatureStats(mPtr).getFatigueTerm();
@ -880,8 +891,6 @@ void CharacterController::update(float duration)
//TODO: actor falls over //TODO: actor falls over
} }
} }
mFallHeight = mPtr.getRefData().getPosition().pos[2];
} }
else else
{ {
@ -920,6 +929,9 @@ void CharacterController::update(float duration)
} }
} }
if (onground)
cls.getCreatureStats(mPtr).land();
if(movestate != CharState_None) if(movestate != CharState_None)
clearAnimQueue(); clearAnimQueue();
@ -944,9 +956,12 @@ void CharacterController::update(float duration)
refreshCurrentAnims(idlestate, movestate, forcestateupdate); refreshCurrentAnims(idlestate, movestate, forcestateupdate);
rot *= duration * Ogre::Math::RadiansToDegrees(1.0f); rot *= duration * Ogre::Math::RadiansToDegrees(1.0f);
world->rotateObject(mPtr, rot.x, rot.y, rot.z, true);
world->queueMovement(mPtr, vec); if (!mSkipAnim)
{
world->rotateObject(mPtr, rot.x, rot.y, rot.z, true);
world->queueMovement(mPtr, vec);
}
movement = vec; movement = vec;
} }
else if(cls.getCreatureStats(mPtr).isDead()) else if(cls.getCreatureStats(mPtr).isDead())
@ -1141,4 +1156,25 @@ void CharacterController::updateContinuousVfx()
} }
} }
void CharacterController::updateVisibility()
{
if (!mPtr.getClass().isActor())
return;
float alpha = 1.f;
if (mPtr.getClass().getCreatureStats(mPtr).getMagicEffects().get(ESM::MagicEffect::Invisibility).mMagnitude)
{
if (mPtr.getRefData().getHandle() == "player")
alpha = 0.4f;
else
alpha = 0.f;
}
float chameleon = mPtr.getClass().getCreatureStats(mPtr).getMagicEffects().get(ESM::MagicEffect::Chameleon).mMagnitude;
if (chameleon)
{
alpha *= std::max(0.2f, (100.f - chameleon)/100.f);
}
mAnimation->setAlpha(alpha);
}
} }

@ -156,9 +156,6 @@ class CharacterController
float mSecondsOfSwimming; float mSecondsOfSwimming;
float mSecondsOfRunning; float mSecondsOfRunning;
// used for acrobatics progress and fall damages
float mFallHeight;
std::string mAttackType; // slash, chop or thrust std::string mAttackType; // slash, chop or thrust
void refreshCurrentAnims(CharacterState idle, CharacterState movement, bool force=false); void refreshCurrentAnims(CharacterState idle, CharacterState movement, bool force=false);
@ -173,6 +170,8 @@ class CharacterController
bool updateNpcState(bool onground, bool inwater, bool isrunning, bool sneak); bool updateNpcState(bool onground, bool inwater, bool isrunning, bool sneak);
void updateVisibility();
public: public:
CharacterController(const MWWorld::Ptr &ptr, MWRender::Animation *anim); CharacterController(const MWWorld::Ptr &ptr, MWRender::Animation *anim);
virtual ~CharacterController(); virtual ~CharacterController();

@ -14,7 +14,8 @@ namespace MWMechanics
mTalkedTo (false), mAlarmed (false), mTalkedTo (false), mAlarmed (false),
mAttacked (false), mHostile (false), mAttacked (false), mHostile (false),
mAttackingOrSpell(false), mAttackType(AT_Chop), mAttackingOrSpell(false), mAttackType(AT_Chop),
mIsWerewolf(false) mIsWerewolf(false),
mFallHeight(0), mRecalcDynamicStats(false)
{ {
for (int i=0; i<4; ++i) for (int i=0; i<4; ++i)
mAiSettings[i] = 0; mAiSettings[i] = 0;
@ -73,7 +74,7 @@ namespace MWMechanics
- gmst.find ("fFatigueMult")->getFloat() * (1-normalised); - gmst.find ("fFatigueMult")->getFloat() * (1-normalised);
} }
const Stat<int> &CreatureStats::getAttribute(int index) const const AttributeValue &CreatureStats::getAttribute(int index) const
{ {
if (index < 0 || index > 7) { if (index < 0 || index > 7) {
throw std::runtime_error("attribute index is out of range"); throw std::runtime_error("attribute index is out of range");
@ -121,20 +122,12 @@ namespace MWMechanics
return mLevel; return mLevel;
} }
int CreatureStats::getAiSetting (int index) const Stat<int> CreatureStats::getAiSetting (AiSetting index) const
{ {
assert (index>=0 && index<4); assert (index>=0 && index<4);
return mAiSettings[index]; return mAiSettings[index];
} }
Stat<int> &CreatureStats::getAttribute(int index)
{
if (index < 0 || index > 7) {
throw std::runtime_error("attribute index is out of range");
}
return (!mIsWerewolf ? mAttributes[index] : mWerewolfAttributes[index]);
}
const DynamicStat<float> &CreatureStats::getDynamic(int index) const const DynamicStat<float> &CreatureStats::getDynamic(int index) const
{ {
if (index < 0 || index > 2) { if (index < 0 || index > 2) {
@ -163,11 +156,29 @@ namespace MWMechanics
return mMagicEffects; return mMagicEffects;
} }
void CreatureStats::setAttribute(int index, const Stat<int> &value) void CreatureStats::setAttribute(int index, int base)
{
AttributeValue current = getAttribute(index);
current.setBase(base);
setAttribute(index, current);
}
void CreatureStats::setAttribute(int index, const AttributeValue &value)
{ {
if (index < 0 || index > 7) { if (index < 0 || index > 7) {
throw std::runtime_error("attribute index is out of range"); throw std::runtime_error("attribute index is out of range");
} }
const AttributeValue& currentValue = !mIsWerewolf ? mAttributes[index] : mWerewolfAttributes[index];
if (value != currentValue)
{
if (index != ESM::Attribute::Luck
&& index != ESM::Attribute::Personality
&& index != ESM::Attribute::Speed)
mRecalcDynamicStats = true;
}
if(!mIsWerewolf) if(!mIsWerewolf)
mAttributes[index] = value; mAttributes[index] = value;
else else
@ -217,6 +228,10 @@ namespace MWMechanics
void CreatureStats::setMagicEffects(const MagicEffects &effects) void CreatureStats::setMagicEffects(const MagicEffects &effects)
{ {
if (effects.get(ESM::MagicEffect::FortifyMaximumMagicka).mMagnitude
!= mMagicEffects.get(ESM::MagicEffect::FortifyMaximumMagicka).mMagnitude)
mRecalcDynamicStats = true;
mMagicEffects = effects; mMagicEffects = effects;
} }
@ -225,12 +240,18 @@ namespace MWMechanics
mAttackingOrSpell = attackingOrSpell; mAttackingOrSpell = attackingOrSpell;
} }
void CreatureStats::setAiSetting (int index, int value) void CreatureStats::setAiSetting (AiSetting index, Stat<int> value)
{ {
assert (index>=0 && index<4); assert (index>=0 && index<4);
mAiSettings[index] = value; mAiSettings[index] = value;
} }
void CreatureStats::setAiSetting (AiSetting index, int base)
{
Stat<int> stat(base);
setAiSetting(index, stat);
}
bool CreatureStats::isDead() const bool CreatureStats::isDead() const
{ {
return mDead; return mDead;
@ -251,8 +272,10 @@ namespace MWMechanics
if (mDead) if (mDead)
{ {
if (mDynamic[0].getCurrent()<1) if (mDynamic[0].getCurrent()<1)
mDynamic[0].setCurrent (1); {
mDynamic[0].setModified(mDynamic[0].getModified(), 1);
mDynamic[0].setCurrent(1);
}
if (mDynamic[0].getCurrent()>=1) if (mDynamic[0].getCurrent()>=1)
mDead = false; mDead = false;
} }
@ -328,7 +351,7 @@ namespace MWMechanics
float evasion = (getAttribute(ESM::Attribute::Agility).getModified() / 5.0f) + float evasion = (getAttribute(ESM::Attribute::Agility).getModified() / 5.0f) +
(getAttribute(ESM::Attribute::Luck).getModified() / 10.0f); (getAttribute(ESM::Attribute::Luck).getModified() / 10.0f);
evasion *= getFatigueTerm(); evasion *= getFatigueTerm();
evasion += mMagicEffects.get(EffectKey(ESM::MagicEffect::Sanctuary)).mMagnitude; evasion += mMagicEffects.get(ESM::MagicEffect::Sanctuary).mMagnitude;
return evasion; return evasion;
} }
@ -356,4 +379,26 @@ namespace MWMechanics
{ {
mUsedPowers[power] = MWBase::Environment::get().getWorld()->getTimeStamp(); mUsedPowers[power] = MWBase::Environment::get().getWorld()->getTimeStamp();
} }
void CreatureStats::addToFallHeight(float height)
{
mFallHeight += height;
}
float CreatureStats::land()
{
float height = mFallHeight;
mFallHeight = 0;
return height;
}
bool CreatureStats::needToRecalcDynamicStats()
{
if (mRecalcDynamicStats)
{
mRecalcDynamicStats = false;
return true;
}
return false;
}
} }

@ -18,13 +18,13 @@ namespace MWMechanics
/// ///
class CreatureStats class CreatureStats
{ {
Stat<int> mAttributes[8]; AttributeValue mAttributes[8];
DynamicStat<float> mDynamic[3]; // health, magicka, fatigue DynamicStat<float> mDynamic[3]; // health, magicka, fatigue
int mLevel; int mLevel;
Spells mSpells; Spells mSpells;
ActiveSpells mActiveSpells; ActiveSpells mActiveSpells;
MagicEffects mMagicEffects; MagicEffects mMagicEffects;
int mAiSettings[4]; Stat<int> mAiSettings[4];
AiSequence mAiSequence; AiSequence mAiSequence;
float mLevelHealthBonus; float mLevelHealthBonus;
bool mDead; bool mDead;
@ -36,23 +36,36 @@ namespace MWMechanics
bool mHostile; bool mHostile;
bool mAttackingOrSpell;//for the player, this is true if the left mouse button is pressed, false if not. bool mAttackingOrSpell;//for the player, this is true if the left mouse button is pressed, false if not.
float mFallHeight;
int mAttackType; int mAttackType;
std::string mLastHitObject; // The last object to hit this actor std::string mLastHitObject; // The last object to hit this actor
// Do we need to recalculate stats derived from attributes or other factors?
bool mRecalcDynamicStats;
std::map<std::string, MWWorld::TimeStamp> mUsedPowers; std::map<std::string, MWWorld::TimeStamp> mUsedPowers;
protected: protected:
bool mIsWerewolf; bool mIsWerewolf;
Stat<int> mWerewolfAttributes[8]; AttributeValue mWerewolfAttributes[8];
public: public:
CreatureStats(); CreatureStats();
bool needToRecalcDynamicStats();
void addToFallHeight(float height);
/// Reset the fall height
/// @return total fall height
float land();
bool canUsePower (const std::string& power) const; bool canUsePower (const std::string& power) const;
void usePower (const std::string& power); void usePower (const std::string& power);
const Stat<int> & getAttribute(int index) const; const AttributeValue & getAttribute(int index) const;
const DynamicStat<float> & getHealth() const; const DynamicStat<float> & getHealth() const;
@ -72,18 +85,15 @@ namespace MWMechanics
int getLevel() const; int getLevel() const;
int getAiSetting (int index) const;
///< 0: hello, 1 fight, 2 flee, 3 alarm
Stat<int> & getAttribute(int index);
Spells & getSpells(); Spells & getSpells();
ActiveSpells & getActiveSpells(); ActiveSpells & getActiveSpells();
MagicEffects & getMagicEffects(); MagicEffects & getMagicEffects();
void setAttribute(int index, const Stat<int> &value); void setAttribute(int index, const AttributeValue &value);
// Shortcut to set only the base
void setAttribute(int index, int base);
void setHealth(const DynamicStat<float> &value); void setHealth(const DynamicStat<float> &value);
@ -112,8 +122,16 @@ namespace MWMechanics
void setLevel(int level); void setLevel(int level);
void setAiSetting (int index, int value); enum AiSetting
///< 0: hello, 1 fight, 2 flee, 3 alarm {
AI_Hello,
AI_Fight,
AI_Flee,
AI_Alarm
};
void setAiSetting (AiSetting index, Stat<int> value);
void setAiSetting (AiSetting index, int base);
Stat<int> getAiSetting (AiSetting index) const;
const AiSequence& getAiSequence() const; const AiSequence& getAiSequence() const;

@ -0,0 +1,53 @@
#ifndef OPENMW_MECHANICS_DISEASE_H
#define OPENMW_MECHANICS_DISEASE_H
#include "../mwbase/windowmanager.hpp"
#include "../mwbase/environment.hpp"
#include "../mwbase/world.hpp"
#include "../mwworld/ptr.hpp"
#include "../mwworld/class.hpp"
#include "../mwmechanics/spells.hpp"
#include "../mwmechanics/creaturestats.hpp"
namespace MWMechanics
{
/// Call when \a actor has got in contact with \a carrier (e.g. hit by him, or loots him)
inline void diseaseContact (MWWorld::Ptr actor, MWWorld::Ptr carrier)
{
if (!carrier.getClass().isActor())
return;
float fDiseaseXferChance =
MWBase::Environment::get().getWorld()->getStore().get<ESM::GameSetting>().find(
"fDiseaseXferChance")->getFloat();
Spells& spells = carrier.getClass().getCreatureStats(carrier).getSpells();
for (Spells::TIterator it = spells.begin(); it != spells.end(); ++it)
{
const ESM::Spell* spell = MWBase::Environment::get().getWorld()->getStore().get<ESM::Spell>().find(it->first);
if (spell->mData.mType == ESM::Spell::ST_Disease
|| spell->mData.mType == ESM::Spell::ST_Blight)
{
float roll = std::rand()/ (static_cast<double> (RAND_MAX) + 1) * 100; // [0, 99]
if (roll < fDiseaseXferChance)
{
// Contracted disease!
actor.getClass().getCreatureStats(actor).getSpells().add(it->first);
if (actor.getRefData().getHandle() == "player")
{
std::string msg = "sMagicContractDisease";
msg = MWBase::Environment::get().getWorld()->getStore().get<ESM::GameSetting>().find(msg)->getString();
if (msg.find("%s") != std::string::npos)
msg.replace(msg.find("%s"), 2, spell->mName);
MWBase::Environment::get().getWindowManager()->messageBox(msg);
}
}
}
}
}
}
#endif

@ -90,7 +90,7 @@ namespace MWMechanics
// Add the new item to player inventory and remove the old one // Add the new item to player inventory and remove the old one
store.remove(mOldItemPtr, 1, player); store.remove(mOldItemPtr, 1, player);
store.add(newItemPtr, player); store.add(newItemPtr, 1, player);
if(!mSelfEnchanting) if(!mSelfEnchanting)
payForEnchantment(); payForEnchantment();

@ -56,7 +56,8 @@ namespace MWMechanics
struct EffectSourceVisitor struct EffectSourceVisitor
{ {
virtual void visit (MWMechanics::EffectKey key, virtual void visit (MWMechanics::EffectKey key,
const std::string& sourceName, float magnitude, float remainingTime = -1) = 0; const std::string& sourceName, const std::string& casterHandle,
float magnitude, float remainingTime = -1) = 0;
}; };
/// \brief Effects currently affecting a NPC or creature /// \brief Effects currently affecting a NPC or creature

@ -12,6 +12,8 @@
#include "../mwworld/class.hpp" #include "../mwworld/class.hpp"
#include "../mwworld/player.hpp" #include "../mwworld/player.hpp"
#include "spellcasting.hpp"
namespace MWMechanics namespace MWMechanics
{ {
void MechanicsManager::buildPlayer() void MechanicsManager::buildPlayer()
@ -31,15 +33,14 @@ namespace MWMechanics
for (int i=0; i<27; ++i) for (int i=0; i<27; ++i)
npcStats.getSkill (i).setBase (player->mNpdt52.mSkills[i]); npcStats.getSkill (i).setBase (player->mNpdt52.mSkills[i]);
creatureStats.getAttribute(0).setBase (player->mNpdt52.mStrength); creatureStats.setAttribute(ESM::Attribute::Strength, player->mNpdt52.mStrength);
creatureStats.getAttribute(1).setBase (player->mNpdt52.mIntelligence); creatureStats.setAttribute(ESM::Attribute::Intelligence, player->mNpdt52.mIntelligence);
creatureStats.getAttribute(2).setBase (player->mNpdt52.mWillpower); creatureStats.setAttribute(ESM::Attribute::Willpower, player->mNpdt52.mWillpower);
creatureStats.getAttribute(3).setBase (player->mNpdt52.mAgility); creatureStats.setAttribute(ESM::Attribute::Agility, player->mNpdt52.mAgility);
creatureStats.getAttribute(4).setBase (player->mNpdt52.mSpeed); creatureStats.setAttribute(ESM::Attribute::Speed, player->mNpdt52.mSpeed);
creatureStats.getAttribute(5).setBase (player->mNpdt52.mEndurance); creatureStats.setAttribute(ESM::Attribute::Endurance, player->mNpdt52.mEndurance);
creatureStats.getAttribute(6).setBase (player->mNpdt52.mPersonality); creatureStats.setAttribute(ESM::Attribute::Personality, player->mNpdt52.mPersonality);
creatureStats.getAttribute(7).setBase (player->mNpdt52.mLuck); creatureStats.setAttribute(ESM::Attribute::Luck, player->mNpdt52.mLuck);
const MWWorld::ESMStore &esmStore = const MWWorld::ESMStore &esmStore =
MWBase::Environment::get().getWorld()->getStore(); MWBase::Environment::get().getWorld()->getStore();
@ -55,7 +56,7 @@ namespace MWMechanics
{ {
const ESM::Race::MaleFemale& attribute = race->mData.mAttributeValues[i]; const ESM::Race::MaleFemale& attribute = race->mData.mAttributeValues[i];
creatureStats.getAttribute(i).setBase (male ? attribute.mMale : attribute.mFemale); creatureStats.setAttribute(i, male ? attribute.mMale : attribute.mFemale);
} }
for (int i=0; i<27; ++i) for (int i=0; i<27; ++i)
@ -106,7 +107,7 @@ namespace MWMechanics
int attribute = class_->mData.mAttribute[i]; int attribute = class_->mData.mAttribute[i];
if (attribute>=0 && attribute<8) if (attribute>=0 && attribute<8)
{ {
creatureStats.getAttribute(attribute).setBase ( creatureStats.setAttribute(attribute,
creatureStats.getAttribute(attribute).getBase() + 10); creatureStats.getAttribute(attribute).getBase() + 10);
} }
} }
@ -124,6 +125,19 @@ namespace MWMechanics
npcStats.getSkill (index).setBase ( npcStats.getSkill (index).setBase (
npcStats.getSkill (index).getBase() + bonus); npcStats.getSkill (index).getBase() + bonus);
} }
if (i==1)
{
// Major skill - add starting spells for this skill if existing
const MWWorld::ESMStore& store = MWBase::Environment::get().getWorld()->getStore();
MWWorld::Store<ESM::Spell>::iterator it = store.get<ESM::Spell>().begin();
for (; it != store.get<ESM::Spell>().end(); ++it)
{
if (it->mData.mFlags & ESM::Spell::F_PCStart
&& spellSchoolToSkill(getSpellSchool(&*it, ptr)) == index)
creatureStats.getSpells().add(it->mId);
}
}
} }
} }
@ -467,6 +481,8 @@ namespace MWMechanics
if (playerStats.getDrawState() == MWMechanics::DrawState_Weapon) if (playerStats.getDrawState() == MWMechanics::DrawState_Weapon)
x += MWBase::Environment::get().getWorld()->getStore().get<ESM::GameSetting>().find("fDispWeaponDrawn")->getFloat(); x += MWBase::Environment::get().getWorld()->getStore().get<ESM::GameSetting>().find("fDispWeaponDrawn")->getFloat();
x += ptr.getClass().getCreatureStats(ptr).getMagicEffects().get(ESM::MagicEffect::Charm).mMagnitude;
int effective_disposition = std::max(0,std::min(int(x),100));//, normally clamped to [0..100] when used int effective_disposition = std::max(0,std::min(int(x),100));//, normally clamped to [0..100] when used
return effective_disposition; return effective_disposition;
} }
@ -485,10 +501,10 @@ namespace MWMechanics
// otherwise one would get different prices when exiting and re-entering the dialogue window... // otherwise one would get different prices when exiting and re-entering the dialogue window...
int clampedDisposition = std::max(0, std::min(getDerivedDisposition(ptr) int clampedDisposition = std::max(0, std::min(getDerivedDisposition(ptr)
+ MWBase::Environment::get().getDialogueManager()->getTemporaryDispositionChange(),100)); + MWBase::Environment::get().getDialogueManager()->getTemporaryDispositionChange(),100));
float a = std::min(playerStats.getSkill(ESM::Skill::Mercantile).getModified(), 100.f); float a = std::min(playerStats.getSkill(ESM::Skill::Mercantile).getModified(), 100);
float b = std::min(0.1f * playerStats.getAttribute(ESM::Attribute::Luck).getModified(), 10.f); float b = std::min(0.1f * playerStats.getAttribute(ESM::Attribute::Luck).getModified(), 10.f);
float c = std::min(0.2f * playerStats.getAttribute(ESM::Attribute::Personality).getModified(), 10.f); float c = std::min(0.2f * playerStats.getAttribute(ESM::Attribute::Personality).getModified(), 10.f);
float d = std::min(sellerStats.getSkill(ESM::Skill::Mercantile).getModified(), 100.f); float d = std::min(sellerStats.getSkill(ESM::Skill::Mercantile).getModified(), 100);
float e = std::min(0.1f * sellerStats.getAttribute(ESM::Attribute::Luck).getModified(), 10.f); float e = std::min(0.1f * sellerStats.getAttribute(ESM::Attribute::Luck).getModified(), 10.f);
float f = std::min(0.2f * sellerStats.getAttribute(ESM::Attribute::Personality).getModified(), 10.f); float f = std::min(0.2f * sellerStats.getAttribute(ESM::Attribute::Personality).getModified(), 10.f);
@ -591,8 +607,12 @@ namespace MWMechanics
{ {
float s = int(r * fPerDieRollMult * fPerTempMult); float s = int(r * fPerDieRollMult * fPerTempMult);
npcStats.setAiSetting (2, std::max(0, std::min(100, npcStats.getAiSetting (2) + int(std::max(iPerMinChange, s))))); int flee = npcStats.getAiSetting(MWMechanics::CreatureStats::AI_Flee).getBase();
npcStats.setAiSetting (1, std::max(0, std::min(100, npcStats.getAiSetting (1) + int(std::min(-iPerMinChange, -s))))); int fight = npcStats.getAiSetting(MWMechanics::CreatureStats::AI_Fight).getBase();
npcStats.setAiSetting (MWMechanics::CreatureStats::AI_Flee,
std::max(0, std::min(100, flee + int(std::max(iPerMinChange, s)))));
npcStats.setAiSetting (MWMechanics::CreatureStats::AI_Fight,
std::max(0, std::min(100, fight + int(std::min(-iPerMinChange, -s)))));
} }
float c = -std::abs(int(r * fPerDieRollMult)); float c = -std::abs(int(r * fPerDieRollMult));
@ -626,8 +646,12 @@ namespace MWMechanics
{ {
float s = c * fPerDieRollMult * fPerTempMult; float s = c * fPerDieRollMult * fPerTempMult;
npcStats.setAiSetting (2, std::max(0, std::min(100, npcStats.getAiSetting (2) + std::min(-int(iPerMinChange), int(-s))))); int flee = npcStats.getAiSetting (CreatureStats::AI_Flee).getBase();
npcStats.setAiSetting (1, std::max(0, std::min(100, npcStats.getAiSetting (1) + std::max(int(iPerMinChange), int(s))))); int fight = npcStats.getAiSetting (CreatureStats::AI_Fight).getBase();
npcStats.setAiSetting (CreatureStats::AI_Flee,
std::max(0, std::min(100, flee + std::min(-int(iPerMinChange), int(-s)))));
npcStats.setAiSetting (CreatureStats::AI_Fight,
std::max(0, std::min(100, fight + std::max(int(iPerMinChange), int(s)))));
} }
x = int(-c * fPerDieRollMult); x = int(-c * fPerDieRollMult);

@ -28,7 +28,6 @@ MWMechanics::NpcStats::NpcStats()
, mBounty (0) , mBounty (0)
, mLevelProgress(0) , mLevelProgress(0)
, mDisposition(0) , mDisposition(0)
, mVampire (0)
, mReputation(0) , mReputation(0)
, mWerewolfKills (0) , mWerewolfKills (0)
, mProfit(0) , mProfit(0)
@ -84,17 +83,17 @@ void MWMechanics::NpcStats::setMovementFlag (Flag flag, bool state)
mMovementFlags &= ~flag; mMovementFlags &= ~flag;
} }
const MWMechanics::Stat<float>& MWMechanics::NpcStats::getSkill (int index) const const MWMechanics::SkillValue& MWMechanics::NpcStats::getSkill (int index) const
{ {
if (index<0 || index>=27) if (index<0 || index>=ESM::Skill::Length)
throw std::runtime_error ("skill index out of range"); throw std::runtime_error ("skill index out of range");
return (!mIsWerewolf ? mSkill[index] : mWerewolfSkill[index]); return (!mIsWerewolf ? mSkill[index] : mWerewolfSkill[index]);
} }
MWMechanics::Stat<float>& MWMechanics::NpcStats::getSkill (int index) MWMechanics::SkillValue& MWMechanics::NpcStats::getSkill (int index)
{ {
if (index<0 || index>=27) if (index<0 || index>=ESM::Skill::Length)
throw std::runtime_error ("skill index out of range"); throw std::runtime_error ("skill index out of range");
return (!mIsWerewolf ? mSkill[index] : mWerewolfSkill[index]); return (!mIsWerewolf ? mSkill[index] : mWerewolfSkill[index]);
@ -197,34 +196,25 @@ void MWMechanics::NpcStats::useSkill (int skillIndex, const ESM::Class& class_,
if(mIsWerewolf) if(mIsWerewolf)
return; return;
float base = getSkill (skillIndex).getBase(); MWMechanics::SkillValue value = getSkill (skillIndex);
int level = static_cast<int> (base); value.setProgress(value.getProgress() + getSkillGain (skillIndex, class_, usageType));
base += getSkillGain (skillIndex, class_, usageType); if (value.getProgress()>=1)
if (static_cast<int> (base)!=level)
{ {
// skill leveled up // skill leveled up
increaseSkill(skillIndex, class_, false); increaseSkill(skillIndex, class_, false);
} }
else
getSkill (skillIndex).setBase (base);
} }
void MWMechanics::NpcStats::increaseSkill(int skillIndex, const ESM::Class &class_, bool preserveProgress) void MWMechanics::NpcStats::increaseSkill(int skillIndex, const ESM::Class &class_, bool preserveProgress)
{ {
float base = getSkill (skillIndex).getBase(); int base = getSkill (skillIndex).getBase();
int level = static_cast<int> (base);
if (level >= 100) if (base >= 100)
return; return;
if (preserveProgress) base += 1;
base += 1;
else
base = level+1;
// if this is a major or minor skill of the class, increase level progress // if this is a major or minor skill of the class, increase level progress
bool levelProgress = false; bool levelProgress = false;
@ -260,6 +250,8 @@ void MWMechanics::NpcStats::increaseSkill(int skillIndex, const ESM::Class &clas
} }
getSkill (skillIndex).setBase (base); getSkill (skillIndex).setBase (base);
if (!preserveProgress)
getSkill(skillIndex).setProgress(0);
} }
int MWMechanics::NpcStats::getLevelProgress () const int MWMechanics::NpcStats::getLevelProgress () const
@ -325,16 +317,6 @@ void MWMechanics::NpcStats::setFactionReputation (const std::string& faction, in
mFactionReputation[faction] = value; mFactionReputation[faction] = value;
} }
bool MWMechanics::NpcStats::isVampire() const
{
return mVampire;
}
void MWMechanics::NpcStats::setVampire (bool set)
{
mVampire = set;
}
int MWMechanics::NpcStats::getReputation() const int MWMechanics::NpcStats::getReputation() const
{ {
return mReputation; return mReputation;
@ -387,7 +369,7 @@ void MWMechanics::NpcStats::setWerewolf (bool set)
// Oh, Bethesda. It's "Intelligence". // Oh, Bethesda. It's "Intelligence".
std::string name = "fWerewolf"+((i==ESM::Attribute::Intelligence) ? std::string("Intellegence") : std::string name = "fWerewolf"+((i==ESM::Attribute::Intelligence) ? std::string("Intellegence") :
ESM::Attribute::sAttributeNames[i]); ESM::Attribute::sAttributeNames[i]);
mWerewolfAttributes[i].setModified(int(gmst.find(name)->getFloat()), 0); mWerewolfAttributes[i].setBase(int(gmst.find(name)->getFloat()));
} }
for(size_t i = 0;i < ESM::Skill::Length;i++) for(size_t i = 0;i < ESM::Skill::Length;i++)
@ -401,7 +383,7 @@ void MWMechanics::NpcStats::setWerewolf (bool set)
// "Mercantile"! >_< // "Mercantile"! >_<
std::string name = "fWerewolf"+((i==ESM::Skill::Mercantile) ? std::string("Merchantile") : std::string name = "fWerewolf"+((i==ESM::Skill::Mercantile) ? std::string("Merchantile") :
ESM::Skill::sSkillNames[i]); ESM::Skill::sSkillNames[i]);
mWerewolfSkill[i].setModified(int(gmst.find(name)->getFloat()), 0); mWerewolfSkill[i].setBase(int(gmst.find(name)->getFloat()));
} }
} }
mIsWerewolf = set; mIsWerewolf = set;

@ -45,12 +45,11 @@ namespace MWMechanics
DrawState_ mDrawState; DrawState_ mDrawState;
int mDisposition; int mDisposition;
unsigned int mMovementFlags; unsigned int mMovementFlags;
Stat<float> mSkill[27]; SkillValue mSkill[27];
Stat<float> mWerewolfSkill[27]; SkillValue mWerewolfSkill[27];
int mBounty; int mBounty;
std::set<std::string> mExpelled; std::set<std::string> mExpelled;
std::map<std::string, int> mFactionReputation; std::map<std::string, int> mFactionReputation;
bool mVampire;
int mReputation; int mReputation;
int mWerewolfKills; int mWerewolfKills;
int mProfit; int mProfit;
@ -94,8 +93,8 @@ namespace MWMechanics
void setMovementFlag (Flag flag, bool state); void setMovementFlag (Flag flag, bool state);
const Stat<float>& getSkill (int index) const; const SkillValue& getSkill (int index) const;
Stat<float>& getSkill (int index); SkillValue& getSkill (int index);
const std::map<std::string, int>& getFactionRanks() const; const std::map<std::string, int>& getFactionRanks() const;
std::map<std::string, int>& getFactionRanks(); std::map<std::string, int>& getFactionRanks();
@ -135,10 +134,6 @@ namespace MWMechanics
void setFactionReputation (const std::string& faction, int value); void setFactionReputation (const std::string& faction, int value);
bool isVampire() const;
void setVampire (bool set);
bool hasSkillsForRank (const std::string& factionId, int rank) const; bool hasSkillsForRank (const std::string& factionId, int rank) const;
bool isWerewolf() const; bool isWerewolf() const;

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

Loading…
Cancel
Save