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
CMakeCache.txt
cmake_install.cmake
CMakeLists.txt.user
Makefile
makefile
build
@ -22,6 +21,8 @@ Doxygen
.project
.settings
.directory
## qt-creator
CMakeLists.txt.user*
## resources
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 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 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
- cd /usr/src/gtest/build
- sudo cmake .. -DBUILD_SHARED_LIBS=1

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

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

@ -137,8 +137,3 @@ if (BUILD_WITH_CODE_COVERAGE)
target_link_libraries(omwlauncher gcov)
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
QString path = QString::fromStdString(mCfgMgr.getUserPath().string()) + QString("openmw.cfg");
QString path = QString::fromStdString(mCfgMgr.getUserConfigPath().string()) + QString("openmw.cfg");
QFile file(path);
if (!file.exists()) {
@ -334,7 +334,7 @@ bool Launcher::MainDialog::setupLauncherSettings()
{
mLauncherSettings.setMultiValueEnabled(true);
QString userPath = QString::fromStdString(mCfgMgr.getUserPath().string());
QString userPath = QString::fromStdString(mCfgMgr.getUserConfigPath().string());
QStringList paths;
paths.append(QString("launcher.cfg"));
@ -440,9 +440,35 @@ bool Launcher::expansions(Launcher::UnshieldThread& cd)
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());
// 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;
paths.append(userPath + QString("openmw.cfg"));
paths.append(QString("openmw.cfg"));
@ -565,7 +591,7 @@ bool Launcher::MainDialog::setupGraphicsSettings()
{
mGraphicsSettings.setMultiValueEnabled(false);
QString userPath = QString::fromStdString(mCfgMgr.getUserPath().string());
QString userPath = QString::fromStdString(mCfgMgr.getUserConfigPath().string());
QString globalPath = QString::fromStdString(mCfgMgr.getGlobalPath().string());
QFile localDefault(QString("settings-default.cfg"));
@ -652,7 +678,7 @@ bool Launcher::MainDialog::writeSettings()
mGraphicsPage->saveSettings();
mDataFilesPage->saveSettings();
QString userPath = QString::fromStdString(mCfgMgr.getUserPath().string());
QString userPath = QString::fromStdString(mCfgMgr.getUserConfigPath().string());
QDir dir(userPath);
if (!dir.exists()) {

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

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

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

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

@ -86,10 +86,6 @@ void CS::Editor::setupDataFiles()
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());
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:
// 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);
OgreInit::OgreInit ogreInit;
ogreInit.init("./opencsOgre.log"); // TODO log path?
#ifdef Q_OS_MAC
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_)
: mSavePath (savePath), mContentFiles (files), mTools (mData), mResDir(resDir),
mProjectPath ((configuration.getUserPath() / "projects") /
mProjectPath ((configuration.getUserDataPath() / "projects") /
(savePath.filename().string() + ".project")),
mSaving (*this, mProjectPath)
{
@ -2254,7 +2254,7 @@ CSMDoc::Document::Document (const Files::ConfigurationManager& configuration, co
}
else
{
boost::filesystem::path locCustomFiltersPath (configuration.getUserPath());
boost::filesystem::path locCustomFiltersPath (configuration.getUserDataPath());
locCustomFiltersPath /= "defaultfilters";
if (boost::filesystem::exists(locCustomFiltersPath))

@ -15,7 +15,7 @@
CSMDoc::DocumentManager::DocumentManager (const Files::ConfigurationManager& configuration)
: mConfiguration (configuration)
{
boost::filesystem::path projectPath = configuration.getUserPath() / "projects";
boost::filesystem::path projectPath = configuration.getUserDataPath() / "projects";
if (!boost::filesystem::is_directory (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)
{
mResDir = boost::filesystem::system_complete(parResDir);
}
}

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

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

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

@ -66,10 +66,6 @@ void OMW::Engine::executeLocalScripts()
localScripts.setIgnore (MWWorld::Ptr());
}
void OMW::Engine::setAnimationVerbose(bool animverbose)
{
}
bool OMW::Engine::frameStarted (const Ogre::FrameEvent& evt)
{
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.");
// 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))
settings.loadUser(settingspath);
else if (boost::filesystem::exists(localdefault))
@ -328,12 +324,16 @@ std::string OMW::Engine::loadSettings (Settings::Manager & settings)
// load nif overrides
NifOverrides::Overrides nifOverrides;
if (boost::filesystem::exists(mCfgMgr.getLocalPath().string() + "/transparency-overrides.cfg"))
nifOverrides.loadTransparencyOverrides(mCfgMgr.getLocalPath().string() + "/transparency-overrides.cfg");
else if (boost::filesystem::exists(mCfgMgr.getGlobalPath().string() + "/transparency-overrides.cfg"))
nifOverrides.loadTransparencyOverrides(mCfgMgr.getGlobalPath().string() + "/transparency-overrides.cfg");
settings.setBool("hardware cursors", "GUI", true);
std::string transparencyOverrides = "/transparency-overrides.cfg";
std::string materialOverrides = "/material-overrides.cfg";
if (boost::filesystem::exists(mCfgMgr.getLocalPath().string() + transparencyOverrides))
nifOverrides.loadTransparencyOverrides(mCfgMgr.getLocalPath().string() + transparencyOverrides);
else if (boost::filesystem::exists(mCfgMgr.getGlobalPath().string() + transparencyOverrides))
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;
}
@ -341,7 +341,7 @@ std::string OMW::Engine::loadSettings (Settings::Manager & settings)
void OMW::Engine::prepareEngine (Settings::Manager & settings)
{
mEnvironment.setStateManager (
new MWState::StateManager (mCfgMgr.getUserPath() / "saves", mContentFiles.at (0)));
new MWState::StateManager (mCfgMgr.getUserDataPath() / "saves", mContentFiles.at (0)));
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
// 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);
MWInput::InputManager* input = new MWInput::InputManager (*mOgre, *this, keybinderUser, keybinderUserExists, mGrab);
mEnvironment.setInputManager (input);
@ -540,6 +540,8 @@ void OMW::Engine::activate()
std::string script = MWWorld::Class::get (ptr).getScript (ptr);
MWBase::Environment::get().getWorld()->breakInvisibility(MWBase::Environment::get().getWorld()->getPlayer().getPlayer());
if (!script.empty())
{
MWBase::Environment::get().getWorld()->getLocalScripts().setIgnore (ptr);
@ -557,7 +559,7 @@ void OMW::Engine::screenshot()
// Count screenshots.
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
std::ostringstream stream;

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

@ -3,8 +3,7 @@
#include <components/files/configurationmanager.hpp>
#include <SDL_messagebox.h>
#include <SDL_main.h>
#include <SDL.h>
#include "engine.hpp"
#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(), "")
->multitoken(), "content file(s): esm/esp, or omwgame/omwaddon")
("anim-verbose", bpo::value<bool>()->implicit_value(true)
->default_value(false), "output animation indices files")
("nosound", bpo::value<bool>()->implicit_value(true)
("no-sound", bpo::value<bool>()->implicit_value(true)
->default_value(false), "disable all sounds")
("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::notify(variables);
cfgMgr.readConfiguration(variables, desc);
bool run = true;
if (variables.count ("help"))
@ -188,6 +182,8 @@ bool parseOptions (int argc, char** argv, OMW::Engine& engine, Files::Configurat
if (!run)
return false;
cfgMgr.readConfiguration(variables, desc);
engine.setGrabMouse(!variables.count("no-grab"));
// 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>());
// other settings
engine.setSoundUsage(!variables["nosound"].as<bool>());
engine.setSoundUsage(!variables["no-sound"].as<bool>());
engine.setScriptsVerbosity(variables["script-verbose"].as<bool>());
engine.setCompileAll(variables["script-all"].as<bool>());
engine.setAnimationVerbose(variables["anim-verbose"].as<bool>());
engine.setFallbackValues(variables["fallback"].as<FallbackMap>().mMap);
engine.setScriptConsoleMode (variables["script-console"].as<bool>());
engine.setStartupScript (variables["script-run"].as<std::string>());
@ -283,7 +278,7 @@ int main(int argc, char**argv)
catch (std::exception &e)
{
#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;
else
#endif

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

@ -137,8 +137,8 @@ namespace MWBase
virtual void wmUpdateFps(float fps, unsigned int triangleCount, unsigned int batchCount) = 0;
/// Set value for the given ID.
virtual void setValue (const std::string& id, const MWMechanics::Stat<int>& value) = 0;
virtual void setValue (int parSkill, const MWMechanics::Stat<float>& value) = 0;
virtual void setValue (const std::string& id, const MWMechanics::AttributeValue& 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 std::string& 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 std::string getSelectedSpell() = 0;
virtual void setSelectedSpell(const std::string& spellId, int successChancePercent) = 0;
virtual void setSelectedEnchantItem(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;
/// \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::Stat<int> > getPlayerAttributeValues() = 0;
virtual std::map<int, MWMechanics::SkillValue > getPlayerSkillValues() = 0;
virtual std::map<int, MWMechanics::AttributeValue > getPlayerAttributeValues() = 0;
virtual SkillList getPlayerMinorSkills() = 0;
virtual SkillList getPlayerMajorSkills() = 0;

@ -81,7 +81,6 @@ namespace MWBase
Render_CollisionDebug,
Render_Wireframe,
Render_Pathgrid,
Render_Compositors,
Render_BoundingBoxes
};
@ -142,7 +141,7 @@ namespace MWBase
virtual Ogre::Vector2 getNorthVector (MWWorld::CellStore* cell) = 0;
///< 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
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;
/**
* @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 launchProjectile (const std::string& id, bool stack, const ESM::EffectList& effects,
const MWWorld::Ptr& actor, const std::string& sourceName) = 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;
text += "\n#{sQuality}: " + MWGui::ToolTips::toString(ref->mBase->mData.mQuality);
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()) {
text += MWGui::ToolTips::getMiscString(ref->mRef.mOwner, "Owner");

@ -172,7 +172,7 @@ namespace MWClass
if (ptr.getCellRef().mCharge == -1)
return ref->mBase->mData.mValue;
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()
@ -248,7 +248,7 @@ namespace MWClass
+ MWGui::ToolTips::toString(ref->mBase->mData.mHealth);
text += "\n#{sWeight}: " + MWGui::ToolTips::toString(ref->mBase->mData.mWeight) + " (" + typeText + ")";
text += MWGui::ToolTips::getValueString(ref->mBase->mData.mValue, "#{sValue}");
text += MWGui::ToolTips::getValueString(getValue(ptr), "#{sValue}");
if (MWBase::Environment::get().getWindowManager()->getFullHelp()) {
text += MWGui::ToolTips::getMiscString(ref->mRef.mOwner, "Owner");
@ -291,44 +291,36 @@ namespace MWClass
{
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
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;
for (std::vector<int>::const_iterator slot=slots_.first.begin();
slot!=slots_.first.end(); ++slot)
// Beast races cannot equip shoes / boots, or full helms (head part vs hair part)
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)
const ESM::Race* race = MWBase::Environment::get().getWorld()->getStore().get<ESM::Race>().find(npcRace);
if(race->mData.mFlags & ESM::Race::Beast)
for(std::vector<ESM::PartReference>::iterator itr = parts.begin(); itr != parts.end(); ++itr)
{
std::vector<ESM::PartReference> parts = ptr.get<ESM::Armor>()->mBase->mParts.mParts;
if(*slot == MWWorld::InventoryStore::Slot_Helmet)
{
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}");
}
}
}
if((*itr).mPart == ESM::PRT_Head)
return std::make_pair(0, "#{sNotifyMessage13}");
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)
{
MWWorld::ContainerStoreIterator weapon = invStore.getSlot(MWWorld::InventoryStore::Slot_CarriedRight);

@ -136,7 +136,7 @@ namespace MWClass
std::string text;
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()) {
text += MWGui::ToolTips::getMiscString(ref->mRef.mOwner, "Owner");

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

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

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

@ -145,7 +145,7 @@ namespace MWClass
std::string text;
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()) {
text += MWGui::ToolTips::getMiscString(ref->mRef.mOwner, "Owner");

@ -183,7 +183,7 @@ namespace MWClass
std::string text;
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()) {
text += MWGui::ToolTips::getMiscString(ref->mRef.mOwner, "Owner");

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

@ -242,7 +242,11 @@ namespace MWClass
item.get<ESM::Miscellaneous>();
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
@ -252,4 +256,11 @@ namespace MWClass
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 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/movement.hpp"
#include "../mwmechanics/spellcasting.hpp"
#include "../mwmechanics/disease.hpp"
#include "../mwworld/ptr.hpp"
#include "../mwworld/actiontalk.hpp"
@ -63,11 +64,10 @@ namespace
bool male = (npc->mFlags & ESM::NPC::Female) == 0;
int level = creatureStats.getLevel();
for (int i=0; i<ESM::Attribute::Length; ++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
@ -79,13 +79,13 @@ namespace
int attribute = class_->mData.mAttribute[i];
if (attribute>=0 && attribute<8)
{
creatureStats.getAttribute(attribute).setBase (
creatureStats.setAttribute(attribute,
creatureStats.getAttribute(attribute).getBase() + 10);
}
}
// skill bonus
for (int attribute=0; attribute<ESM::Attribute::Length; ++attribute)
for (int attribute=0; attribute < ESM::Attribute::Length; ++attribute)
{
float modifierSum = 0;
@ -110,7 +110,7 @@ namespace
}
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) );
}
@ -131,6 +131,89 @@ namespace
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
@ -173,7 +256,7 @@ namespace MWClass
{
std::string faction = ref->mBase->mFaction;
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;
}
@ -185,21 +268,22 @@ namespace MWClass
// creature stats
int gold=0;
if(ref->mBase->mNpdt52.mGold != -10)
if(ref->mBase->mNpdtType != ESM::NPC::NPC_WITH_AUTOCALCULATED_STATS)
{
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.getAttribute(0).set (ref->mBase->mNpdt52.mStrength);
data->mNpcStats.getAttribute(1).set (ref->mBase->mNpdt52.mIntelligence);
data->mNpcStats.getAttribute(2).set (ref->mBase->mNpdt52.mWillpower);
data->mNpcStats.getAttribute(3).set (ref->mBase->mNpdt52.mAgility);
data->mNpcStats.getAttribute(4).set (ref->mBase->mNpdt52.mSpeed);
data->mNpcStats.getAttribute(5).set (ref->mBase->mNpdt52.mEndurance);
data->mNpcStats.getAttribute(6).set (ref->mBase->mNpdt52.mPersonality);
data->mNpcStats.getAttribute(7).set (ref->mBase->mNpdt52.mLuck);
data->mNpcStats.setAttribute(ESM::Attribute::Strength, ref->mBase->mNpdt52.mStrength);
data->mNpcStats.setAttribute(ESM::Attribute::Intelligence, ref->mBase->mNpdt52.mIntelligence);
data->mNpcStats.setAttribute(ESM::Attribute::Willpower, ref->mBase->mNpdt52.mWillpower);
data->mNpcStats.setAttribute(ESM::Attribute::Agility, ref->mBase->mNpdt52.mAgility);
data->mNpcStats.setAttribute(ESM::Attribute::Speed, ref->mBase->mNpdt52.mSpeed);
data->mNpcStats.setAttribute(ESM::Attribute::Endurance, ref->mBase->mNpdt52.mEndurance);
data->mNpcStats.setAttribute(ESM::Attribute::Personality, ref->mBase->mNpdt52.mPersonality);
data->mNpcStats.setAttribute(ESM::Attribute::Luck, ref->mBase->mNpdt52.mLuck);
data->mNpcStats.setHealth (ref->mBase->mNpdt52.mHealth);
data->mNpcStats.setMagicka (ref->mBase->mNpdt52.mMana);
data->mNpcStats.setFatigue (ref->mBase->mNpdt52.mFatigue);
@ -220,14 +304,15 @@ namespace MWClass
data->mNpcStats.setReputation(ref->mBase->mNpdt12.mReputation);
autoCalculateAttributes(ref->mBase, data->mNpcStats);
autoCalculateSkills(ref->mBase, data->mNpcStats);
}
data->mNpcStats.getAiSequence().fill(ref->mBase->mAiPackage);
data->mNpcStats.setAiSetting (0, ref->mBase->mAiData.mHello);
data->mNpcStats.setAiSetting (1, ref->mBase->mAiData.mFight);
data->mNpcStats.setAiSetting (2, ref->mBase->mAiData.mFlee);
data->mNpcStats.setAiSetting (3, ref->mBase->mAiData.mAlarm);
data->mNpcStats.setAiSetting (MWMechanics::CreatureStats::AI_Hello, ref->mBase->mAiData.mHello);
data->mNpcStats.setAiSetting (MWMechanics::CreatureStats::AI_Fight, ref->mBase->mAiData.mFight);
data->mNpcStats.setAiSetting (MWMechanics::CreatureStats::AI_Flee, ref->mBase->mAiData.mFlee);
data->mNpcStats.setAiSetting (MWMechanics::CreatureStats::AI_Alarm, ref->mBase->mAiData.mAlarm);
// spells
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::Luck).getModified() / 10.0f);
hitchance *= stats.getFatigueTerm();
hitchance += mageffects.get(MWMechanics::EffectKey(ESM::MagicEffect::FortifyAttack)).mMagnitude -
mageffects.get(MWMechanics::EffectKey(ESM::MagicEffect::Blind)).mMagnitude;
hitchance += mageffects.get(ESM::MagicEffect::FortifyAttack).mMagnitude -
mageffects.get(ESM::MagicEffect::Blind).mMagnitude;
hitchance -= otherstats.getEvasion();
if((::rand()/(RAND_MAX+1.0)) > hitchance/100.0f)
@ -409,6 +494,11 @@ namespace MWClass
if (!MWBase::Environment::get().getWorld()->getGodModeState())
weapon.getCellRef().mCharge -= std::min(std::max(1,
(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;
}
@ -428,7 +518,8 @@ namespace MWClass
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())
{
healthdmg = true;
@ -514,12 +605,15 @@ namespace MWClass
ptr.getRefData().getLocals().setVarByInt(script, "onpchitme", 1);
}
if (!attacker.isEmpty())
MWMechanics::diseaseContact(ptr, attacker);
if(damage > 0.0f)
{
// 'ptr' is losing health. Play a 'hit' voiced dialog entry if not already saying
// something, alert the character controller, scripts, etc.
MWBase::Environment::get().getDialogueManager()->say(ptr, "hit");
MWBase::Environment::get().getDialogueManager()->say(ptr, "thief");
if(object.isEmpty())
{
@ -560,6 +654,11 @@ namespace MWClass
armorref.mCharge = armor.get<ESM::Armor>()->mBase->mData.mHealth;
armorref.mCharge -= std::min(std::max(1, (int)damagediff),
armorref.mCharge);
// Armor broken? unequip it
if (armorref.mCharge == 0)
inv.unequipItem(armor, ptr);
switch(get(armor).getEquipmentSkill(armor))
{
case ESM::Skill::LightArmor:
@ -586,7 +685,7 @@ namespace MWClass
else
{
MWMechanics::DynamicStat<float> fatigue(getCreatureStats(ptr).getFatigue());
fatigue.setCurrent(fatigue.getCurrent() - damage);
fatigue.setCurrent(fatigue.getCurrent() - damage, true);
getCreatureStats(ptr).setFatigue(fatigue);
}
}
@ -628,6 +727,8 @@ namespace MWClass
return boost::shared_ptr<MWWorld::Action>(new MWWorld::ActionOpen(ptr, true));
if(get(actor).getStance(actor, MWWorld::Class::Sneak))
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));
}
@ -752,10 +853,11 @@ namespace MWClass
float moveSpeed;
if(normalizedEncumbrance >= 1.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() +
mageffects.get(MWMechanics::EffectKey(10/*levitate*/)).mMagnitude);
mageffects.get(ESM::MagicEffect::Levitate).mMagnitude);
flySpeed = fMinFlySpeed->getFloat() + flySpeed*(fMaxFlySpeed->getFloat() - fMinFlySpeed->getFloat());
flySpeed *= 1.0f - fEncumberedMoveEffect->getFloat() * normalizedEncumbrance;
flySpeed = std::max(0.0f, flySpeed);
@ -766,7 +868,7 @@ namespace MWClass
float swimSpeed = walkSpeed;
if(Npc::getStance(ptr, Run, false))
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()*
fSwimRunAthleticsMult->getFloat();
moveSpeed = swimSpeed;
@ -800,7 +902,7 @@ namespace MWClass
float x = fJumpAcrobaticsBase->getFloat() +
std::pow(a / 15.0f, 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;
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 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 fallAcroMult = gmst.find("fFallAcroMult")->getFloat();
const float fallDistanceBase = gmst.find("fFallDistanceBase")->getFloat();
@ -928,8 +1030,8 @@ namespace MWClass
if(!stats.isWerewolf())
{
weight = getContainerStore(ptr).getWeight();
weight -= stats.getMagicEffects().get(MWMechanics::EffectKey(ESM::MagicEffect::Feather)).mMagnitude;
weight += stats.getMagicEffects().get(MWMechanics::EffectKey(ESM::MagicEffect::Burden)).mMagnitude;
weight -= stats.getMagicEffects().get(ESM::MagicEffect::Feather).mMagnitude;
weight += stats.getMagicEffects().get(ESM::MagicEffect::Burden).mMagnitude;
if(weight < 0.0f)
weight = 0.0f;
}

@ -128,7 +128,7 @@ namespace MWClass
std::string text;
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);

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

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

@ -157,7 +157,7 @@ namespace MWClass
if (ptr.getCellRef().mCharge == -1)
return ref->mBase->mData.mValue;
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()
@ -346,7 +346,7 @@ namespace MWClass
}
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;
@ -388,28 +388,26 @@ namespace MWClass
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);
// equip the item in the first free slot
for (std::vector<int>::const_iterator slot=slots_.first.begin();
slot!=slots_.first.end(); ++slot)
if (slots_.first.empty())
return std::make_pair (0, "");
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)
{
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 (2, "");
}
return std::make_pair (0, "");
return std::make_pair(1, "");
}
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);
@ -262,12 +262,9 @@ namespace MWDialogue
MWGui::DialogueWindow* win = MWBase::Environment::get().getWindowManager()->getDialogueWindow();
std::vector<const ESM::DialInfo *> infos = filter.list (dialogue, true, true);
if (!infos.empty())
const ESM::DialInfo* info = filter.search(dialogue, true);
if (info)
{
const ESM::DialInfo* info = infos[randomResponse ? std::rand() % infos.size() : 0];
parseText (info->mResponse);
std::string title;
@ -413,10 +410,6 @@ namespace MWDialogue
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);
// Apply disposition change to NPC's base disposition
@ -474,6 +467,8 @@ namespace MWDialogue
void DialogueManager::goodbye()
{
mIsInChoice = true;
MWGui::DialogueWindow* win = MWBase::Environment::get().getWindowManager()->getDialogueWindow();
win->goodbye();
@ -511,7 +506,7 @@ namespace MWDialogue
text = "Bribe";
}
executeTopic (text + (success ? " Success" : " Fail"), true);
executeTopic (text + (success ? " Success" : " Fail"));
}
int DialogueManager::getTemporaryDispositionChange() const

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

@ -5,6 +5,7 @@
#include "../mwbase/world.hpp"
#include "../mwbase/journal.hpp"
#include "../mwbase/mechanicsmanager.hpp"
#include "../mwbase/dialoguemanager.hpp"
#include "../mwworld/class.hpp"
#include "../mwworld/player.hpp"
@ -133,7 +134,8 @@ bool MWDialogue::Filter::testDisposition (const ESM::DialInfo& info, bool invert
if (isCreature)
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".
return invert ? (info.mData.mDisposition == 0 || actorDisposition < info.mData.mDisposition)
: (actorDisposition >= info.mData.mDisposition);
@ -277,7 +279,8 @@ int MWDialogue::Filter::getSelectStructInteger (const SelectWrapper& select) con
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:
@ -512,7 +515,8 @@ bool MWDialogue::Filter::getSelectStructBoolean (const SelectWrapper& select) co
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:

@ -44,6 +44,11 @@ namespace MWGui
adjustButton(mNextPageButton);
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)
{
// english button has a 7 pixel wide strip of garbage on its right edge
@ -54,6 +59,14 @@ namespace MWGui
center();
}
void BookWindow::onMouseWheel(MyGUI::Widget *_sender, int _rel)
{
if (_rel < 0)
nextPage();
else
prevPage();
}
void BookWindow::clearPages()
{
for (std::vector<MyGUI::Widget*>::iterator it=mPages.begin();
@ -89,6 +102,7 @@ namespace MWGui
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));
pageWidget->setNeedMouseFocus(false);
parser.parsePage(*it, pageWidget, mLeftPage->getSize().width);
mPages.push_back(pageWidget);
++i;

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

@ -75,7 +75,7 @@ namespace MWGui
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)
{
@ -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)
mReviewDialog->setSkillValue(parSkill, value);
@ -229,8 +229,8 @@ namespace MWGui
}
{
std::map<int, MWMechanics::Stat<int> > attributes = MWBase::Environment::get().getWindowManager()->getPlayerAttributeValues();
for (std::map<int, MWMechanics::Stat<int> >::iterator it = attributes.begin();
std::map<int, MWMechanics::AttributeValue > attributes = MWBase::Environment::get().getWindowManager()->getPlayerAttributeValues();
for (std::map<int, MWMechanics::AttributeValue >::iterator it = attributes.begin();
it != attributes.end(); ++it)
{
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();
for (std::map<int, MWMechanics::Stat<float> >::iterator it = skills.begin();
std::map<int, MWMechanics::SkillValue > skills = MWBase::Environment::get().getWindowManager()->getPlayerSkillValues();
for (std::map<int, MWMechanics::SkillValue >::iterator it = skills.begin();
it != skills.end(); ++it)
{
mReviewDialog->setSkillValue(static_cast<ESM::Skill::SkillEnum> (it->first), it->second);

@ -31,9 +31,9 @@ namespace MWGui
//Show a dialog
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 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 doRenderUpdate();

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

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

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

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

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

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

@ -55,6 +55,8 @@ namespace MWGui
, mWorldMouseOver(false)
, mEnemyHealthTimer(0)
, mIsDrowning(false)
, mWeaponSpellTimer(0.f)
, mDrowningFlashTheta(0.f)
{
setCoord(0,0, width, height);
@ -174,38 +176,32 @@ namespace MWGui
void HUD::setValue(const std::string& id, const MWMechanics::DynamicStat<float>& value)
{
static const char *ids[] =
{
"HBar", "MBar", "FBar", 0
};
int current = std::max(0, static_cast<int>(value.getCurrent()));
int modified = static_cast<int>(value.getModified());
for (int i=0; ids[i]; ++i)
if (ids[i]==id)
{
MyGUI::Widget* w;
std::string valStr = boost::lexical_cast<std::string>(value.getCurrent()) + "/" + boost::lexical_cast<std::string>(value.getModified());
switch (i)
{
case 0:
mHealth->setProgressRange (value.getModified());
mHealth->setProgressPosition (value.getCurrent());
getWidget(w, "HealthFrame");
w->setUserString("Caption_HealthDescription", "#{sHealthDesc}\n" + valStr);
break;
case 1:
mMagicka->setProgressRange (value.getModified());
mMagicka->setProgressPosition (value.getCurrent());
getWidget(w, "MagickaFrame");
w->setUserString("Caption_HealthDescription", "#{sIntDesc}\n" + valStr);
break;
case 2:
mStamina->setProgressRange (value.getModified());
mStamina->setProgressPosition (value.getCurrent());
getWidget(w, "FatigueFrame");
w->setUserString("Caption_HealthDescription", "#{sFatDesc}\n" + valStr);
break;
}
}
MyGUI::Widget* w;
std::string valStr = boost::lexical_cast<std::string>(current) + "/" + boost::lexical_cast<std::string>(modified);
if (id == "HBar")
{
mHealth->setProgressRange(modified);
mHealth->setProgressPosition(current);
getWidget(w, "HealthFrame");
w->setUserString("Caption_HealthDescription", "#{sHealthDesc}\n" + valStr);
}
else if (id == "MBar")
{
mMagicka->setProgressRange (modified);
mMagicka->setProgressPosition (current);
getWidget(w, "MagickaFrame");
w->setUserString("Caption_HealthDescription", "#{sIntDesc}\n" + valStr);
}
else if (id == "FBar")
{
mStamina->setProgressRange (modified);
mStamina->setProgressPosition (current);
getWidget(w, "FatigueFrame");
w->setUserString("Caption_HealthDescription", "#{sFatDesc}\n" + valStr);
}
}
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))
throw std::runtime_error("Item to copy needs to be from a different container!");
int origCount = item.mBase.getRefData().getCount();
item.mBase.getRefData().setCount(count);
mActor.getClass().getContainerStore(mActor).add(item.mBase, mActor);
item.mBase.getRefData().setCount(origCount);
mActor.getClass().getContainerStore(mActor).add(item.mBase, count, mActor);
}
@ -72,7 +69,7 @@ void InventoryItemModel::update()
// 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
// being shown or taken.
if(item.getCellRef().mRefID == "WerewolfRobe")
if(item.getCellRef().mRefID == "werewolfrobe")
continue;
ItemStack newItem (item, this, item.getRefData().getCount());

@ -120,10 +120,13 @@ namespace MWGui
Settings::Manager::getFloat(setting + " y", "Windows") * viewSize.height);
MyGUI::IntSize size (Settings::Manager::getFloat(setting + " w", "Windows") * viewSize.width,
Settings::Manager::getFloat(setting + " h", "Windows") * viewSize.height);
if (size.width != mMainWidget->getWidth() || size.height != mMainWidget->getHeight())
mPreviewDirty = true;
mMainWidget->setPosition(pos);
mMainWidget->setSize(size);
adjustPanes();
mPreviewDirty = true;
}
TradeItemModel* InventoryWindow::getTradeModel()
@ -160,6 +163,14 @@ namespace MWGui
MWWorld::Ptr object = item.mBase;
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)
{
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::ContainerStoreIterator it = invStore.begin();
int origCount = ptr.getRefData().getCount();
ptr.getRefData().setCount(mDragAndDrop->mDraggedCount);
it = invStore.add(ptr, mPtr);
ptr.getRefData().setCount(origCount);
it = invStore.add(ptr, mDragAndDrop->mDraggedCount, mPtr);
mDragAndDrop->mSourceModel->removeItem(mDragAndDrop->mItem, mDragAndDrop->mDraggedCount);
ptr = *it;
@ -414,7 +422,7 @@ namespace MWGui
// 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
// taken.
if(item.getCellRef().mRefID == "WerewolfRobe")
if(item.getCellRef().mRefID == "werewolfrobe")
return MWWorld::Ptr();
return item;
}
@ -510,7 +518,7 @@ namespace MWGui
// add to player inventory
// 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 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
MWBase::Environment::get().getWorld()->deleteObject (object);

@ -166,11 +166,12 @@ namespace MWGui
// increase attributes
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]));
if (attribute.getBase() >= 100)
attribute.setBase(100);
creatureStats.setAttribute(mSpentAttributes[i], attribute);
}
creatureStats.levelUp();

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

@ -103,27 +103,80 @@ namespace MWGui
void LocalMapBase::onMarkerFocused (MyGUI::Widget* w1, MyGUI::Widget* w2)
{
// Workaround to not make the marker visible if it's under fog of war
applyFogOfWar ();
}
void LocalMapBase::onMarkerUnfocused (MyGUI::Widget* w1, MyGUI::Widget* w2)
{
// Workaround to not make the marker visible if it's under fog of war
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)
{
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
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));
}
}
// Update the map textures
for (int mx=0; mx<3; ++mx)
{
for (int my=0; my<3; ++my)
@ -138,78 +191,57 @@ namespace MWGui
box->setImageTexture(image);
else
box->setImageTexture("black.png");
}
}
MWBase::World* world = MWBase::Environment::get().getWorld();
// door markers
// interior map only consists of one cell, so handle the markers only once
if (interior && (mx != 2 || my != 2))
continue;
MWWorld::CellStore* cell;
if (interior)
cell = MWBase::Environment::get().getWorld ()->getInterior (mPrefix);
else
cell = MWBase::Environment::get().getWorld ()->getExterior (x+mx-1, y-(my-1));
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)
// Retrieve the door markers we want to show
std::vector<MWBase::World::DoorMarker> doors;
if (interior)
{
MWWorld::CellStore* cell = world->getInterior (mPrefix);
world->getDoorMarkers(cell, doors);
}
else
{
for (int dX=-1; dX<2; ++dX)
{
for (int dY=-1; dY<2; ++dY)
{
MWBase::World::DoorMarker marker = *it;
// 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);
MWWorld::CellStore* cell = world->getExterior (mCurX+dX, mCurY+dY);
world->getDoorMarkers(cell, doors);
}
}
}
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();
// 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)
{
updateMarkers();
if (x == mLastPositionX && y == mLastPositionY)
return;
@ -255,6 +289,88 @@ namespace MWGui
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)
@ -319,7 +435,7 @@ namespace MWGui
static int _counter=0;
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->setUserString("ToolTipType", "Layout");
markerWidget->setUserString("ToolTipLayout", "TextToolTipOneLine");
@ -385,7 +501,7 @@ namespace MWGui
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");
}
@ -396,20 +512,18 @@ namespace MWGui
void MapWindow::globalMapUpdatePlayer ()
{
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();
// for interiors, we have no choice other than using the last position & direction.
/// \todo save this last position in the savegame?
// For interiors, position is set by WindowManager via setGlobalMapPlayerPosition
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));
MyGUI::ISubWidget* main = mPlayerArrowGlobal->getSubWidgetMain();
@ -444,4 +558,19 @@ namespace MWGui
"#{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 onMarkerUnfocused(MyGUI::Widget* w1, MyGUI::Widget* w2);
MyGUI::IntPoint getMarkerPosition (float worldX, float worldY, MarkerPosition& markerPos);
virtual void notifyPlayerUpdate() {}
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;
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 cellExplored(int x, int y);
void setGlobalMapPlayerPosition (float worldX, float worldY);
virtual void open();
private:

@ -16,6 +16,15 @@ namespace MWGui
mLastButtonPressed = -1;
}
MessageBoxManager::~MessageBoxManager ()
{
std::vector<MessageBox*>::iterator it(mMessageBoxes.begin());
for (; it != mMessageBoxes.end(); ++it)
{
delete *it;
}
}
void MessageBoxManager::onFrame (float frameDuration)
{
std::vector<MessageBox*>::iterator it;
@ -141,7 +150,6 @@ namespace MWGui
, mMaxTime(0)
{
// defines
mFixedWidth = 300;
mBottomPadding = 20;
mNextBoxPadding = 20;
@ -149,41 +157,21 @@ namespace MWGui
mMessageWidget->setOverflowToTheLeft(true);
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)
{
MyGUI::IntSize gameWindowSize = MyGUI::RenderManager::getInstance().getViewSize();
MyGUI::IntCoord coord;
coord.left = (gameWindowSize.width - mFixedWidth)/2;
coord.top = (gameWindowSize.height - mHeight - height - mBottomPadding);
MyGUI::IntSize size;
size.width = mFixedWidth;
size.height = mHeight;
MyGUI::IntPoint pos;
pos.left = (gameWindowSize.width - mMainWidget->getWidth())/2;
pos.top = (gameWindowSize.height - mMainWidget->getHeight() - height - mBottomPadding);
mMainWidget->setCoord(coord);
mMainWidget->setSize(size);
mMainWidget->setVisible(true);
mMainWidget->setPosition(pos);
}
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:
MessageBoxManager ();
~MessageBoxManager ();
void onFrame (float frameDuration);
void createMessageBox (const std::string& message, bool stat = false);
void removeStaticMessageBox ();
@ -63,10 +64,8 @@ namespace MWGui
protected:
MessageBoxManager& mMessageBoxManager;
int mHeight;
const std::string& mMessage;
MyGUI::EditBox* mMessageWidget;
int mFixedWidth;
int mBottomPadding;
int mNextBoxPadding;
};

@ -40,6 +40,14 @@ namespace MWGui
for (size_t i = 0; i<mSourceModel->getItemCount(); ++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()
&& item.mType != ItemStack::Type_Equipped)
mItems.push_back(item);

@ -269,13 +269,39 @@ namespace MWGui
MWWorld::Ptr player = MWBase::Environment::get().getWorld()->getPlayer().getPlayer();
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)
{
std::string spellId = button->getChildAt(0)->getUserString("Spell");
spells.setSelectedSpell(spellId);
store.setSelectedEnchantItem(store.end());
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>();
// 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);
action->execute (MWBase::Environment::get().getWorld()->getPlayer().getPlayer());
@ -310,14 +327,6 @@ namespace MWGui
{
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
MWWorld::ContainerStoreIterator it = store.begin();
for (; it != store.end(); ++it)
@ -336,13 +345,9 @@ namespace MWGui
MWWorld::ActionEquip action(item);
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);
spells.setSelectedSpell("");
MWBase::Environment::get().getWindowManager()->setSelectedEnchantItem(item);
}
}

@ -65,7 +65,7 @@ namespace MWGui
getWidget(attribute, std::string("Attribute") + boost::lexical_cast<std::string>(idx));
mAttributeWidgets.insert(std::make_pair(static_cast<int>(ESM::Attribute::sAttributeIds[idx]), attribute));
attribute->setAttributeId(ESM::Attribute::sAttributeIds[idx]);
attribute->setAttributeValue(Widgets::MWAttribute::AttributeValue(0, 0));
attribute->setAttributeValue(Widgets::MWAttribute::AttributeValue());
}
// Setup skills
@ -74,7 +74,7 @@ namespace MWGui
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)));
}
@ -152,7 +152,7 @@ namespace MWGui
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));
if (attr == mAttributeWidgets.end())
@ -161,7 +161,7 @@ namespace MWGui
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;
MyGUI::TextBox* widget = mSkillWidgetMap[skillId];
@ -279,9 +279,9 @@ namespace MWGui
continue;
assert(skillId >= 0 && skillId < ESM::Skill::Length);
const std::string &skillNameId = ESM::Skill::sSkillNameIds[skillId];
const MWMechanics::Stat<float> &stat = mSkillValues.find(skillId)->second;
float base = stat.getBase();
float modified = stat.getModified();
const MWMechanics::SkillValue &stat = mSkillValues.find(skillId)->second;
int base = stat.getBase();
int modified = stat.getModified();
std::string state = "normal";
if (modified > base)

@ -38,10 +38,10 @@ namespace MWGui
void setMagicka(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 setSkillValue(ESM::Skill::SkillEnum skillId, const MWMechanics::Stat<float>& value);
void setSkillValue(ESM::Skill::SkillEnum skillId, const MWMechanics::SkillValue& value);
virtual void open();
@ -85,7 +85,7 @@ namespace MWGui
std::map<int, Widgets::MWAttributePtr> mAttributeWidgets;
SkillList mMajorSkills, mMinorSkills, mMiscSkills;
std::map<int, MWMechanics::Stat<float> > mSkillValues;
std::map<int, MWMechanics::SkillValue > mSkillValues;
std::map<int, MyGUI::TextBox*> mSkillWidgetMap;
std::string mName, mRaceId, mBirthSignId;
ESM::Class mKlass;

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

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

@ -22,7 +22,8 @@ namespace MWGui
{
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;
newEffectSource.mKey = key;

@ -43,7 +43,8 @@ namespace MWGui
std::map <int, std::vector<MagicEffectInfo> > mEffectSources;
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

@ -86,61 +86,8 @@ namespace MWGui
MWMechanics::CreatureStats& stats = MWWorld::Class::get(player).getCreatureStats(player);
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)
{
spellList.push_back (it->first);
}
const MWWorld::ESMStore &esmStore =
MWBase::Environment::get().getWorld()->getStore();
@ -210,7 +157,7 @@ namespace MWGui
t->eventMouseWheel += MyGUI::newDelegate(this, &SpellWindow::onMouseWheel);
t->eventMouseButtonClick += MyGUI::newDelegate(this, &SpellWindow::onSpellSelected);
if (*it == selectedSpell)
if (*it == MWBase::Environment::get().getWindowManager()->getSelectedSpell())
t->setStateSelected(true);
mHeight += spellHeight;
@ -229,7 +176,7 @@ namespace MWGui
t->setUserString("Spell", *it);
t->eventMouseWheel += MyGUI::newDelegate(this, &SpellWindow::onMouseWheel);
t->eventMouseButtonClick += MyGUI::newDelegate(this, &SpellWindow::onSpellSelected);
t->setStateSelected(*it == selectedSpell);
t->setStateSelected(*it == MWBase::Environment::get().getWindowManager()->getSelectedSpell());
// cost / success chance
MyGUI::Button* costChance = mSpellView->createWidget<MyGUI::Button>("SpellText",
@ -239,7 +186,7 @@ namespace MWGui
costChance->setCaption(cost + "/" + chance);
costChance->setTextAlign(MyGUI::Align::Right);
costChance->setNeedMouseFocus(false);
costChance->setStateSelected(*it == selectedSpell);
costChance->setStateSelected(*it == MWBase::Environment::get().getWindowManager()->getSelectedSpell());
mHeight += spellHeight;
@ -276,7 +223,9 @@ namespace MWGui
t->setUserString("Equipped", equipped ? "true" : "false");
t->eventMouseButtonClick += MyGUI::newDelegate(this, &SpellWindow::onEnchantedItemSelected);
t->eventMouseWheel += MyGUI::newDelegate(this, &SpellWindow::onMouseWheel);
t->setStateSelected(item == selectedItem);
if (store.getSelectedEnchantItem() != store.end())
t->setStateSelected(item == *store.getSelectedEnchantItem());
// cost / charge
MyGUI::Button* costCharge = mSpellView->createWidget<MyGUI::Button>(equipped ? "SpellText" : "SpellTextUnequipped",
@ -302,7 +251,8 @@ namespace MWGui
costCharge->setCaption(cost + "/" + charge);
costCharge->setTextAlign(MyGUI::Align::Right);
costCharge->setNeedMouseFocus(false);
costCharge->setStateSelected(item == selectedItem);
if (store.getSelectedEnchantItem() != store.end())
costCharge->setStateSelected(item == *store.getSelectedEnchantItem());
mHeight += spellHeight;
}
@ -349,9 +299,7 @@ namespace MWGui
void SpellWindow::onEnchantedItemSelected(MyGUI::Widget* _sender)
{
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);
MWMechanics::Spells& spells = stats.getSpells();
MWWorld::Ptr item = *_sender->getUserData<MWWorld::Ptr>();
// retrieve ContainerStoreIterator to the item
@ -379,7 +327,6 @@ namespace MWGui
}
store.setSelectedEnchantItem(it);
spells.setSelectedSpell("");
MWBase::Environment::get().getWindowManager()->setSelectedEnchantItem(item);
updateSpells();
@ -389,9 +336,7 @@ namespace MWGui
{
std::string spellId = _sender->getUserString("Spell");
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);
MWMechanics::Spells& spells = stats.getSpells();
if (MyGUI::InputManager::getInstance().isShiftPressed())
{
@ -419,7 +364,6 @@ namespace MWGui
}
else
{
spells.setSelectedSpell(spellId);
store.setSelectedEnchantItem(store.end());
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::Spells& spells = stats.getSpells();
if (spells.getSelectedSpell() == mSpellToDelete)
{
spells.setSelectedSpell("");
if (MWBase::Environment::get().getWindowManager()->getSelectedSpell() == mSpellToDelete)
MWBase::Environment::get().getWindowManager()->unsetSelectedSpell();
}
spells.remove(mSpellToDelete);

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

@ -26,11 +26,11 @@ namespace MWGui
void setPlayerName(const std::string& playerName);
/// 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 std::string& 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 setReputation (int reputation) { if (reputation != mReputation) mChanged = true; this->mReputation = reputation; }
@ -61,7 +61,7 @@ namespace MWGui
MyGUI::ScrollView* mSkillView;
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<std::string, MyGUI::Widget*> mFactionWidgetMap;
FactionList mFactions; ///< Stores a list of factions and the current rank

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

@ -154,6 +154,13 @@ namespace MWGui
if(!MWWorld::Class::get(base).canSell(base, services))
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
if(mMerchant.getTypeName() == typeid(ESM::NPC).name())
{

@ -24,6 +24,7 @@
#include "containeritemmodel.hpp"
#include "tradeitemmodel.hpp"
#include "countdialog.hpp"
#include "dialogue.hpp"
namespace MWGui
{
@ -296,10 +297,10 @@ namespace MWGui
const MWMechanics::NpcStats &sellerStats = MWWorld::Class::get(mPtr).getNpcStats(mPtr);
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 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 f1 = std::min(0.2f * sellerStats.getAttribute(ESM::Attribute::Personality).getModified(), 10.f);
@ -340,6 +341,9 @@ namespace MWGui
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";
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;
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 hourlyMagickaDelta = fRestMagicMult * stats.getAttribute(ESM::Attribute::Intelligence).getModified();

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

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

@ -16,6 +16,7 @@
#include "../mwbase/inputmanager.hpp"
#include "../mwworld/class.hpp"
#include "../mwworld/player.hpp"
#include "console.hpp"
#include "journalwindow.hpp"
@ -112,9 +113,6 @@ namespace MWGui
, mPlayerMinorSkills()
, mPlayerMajorSkills()
, mPlayerSkillValues()
, mPlayerHealth()
, mPlayerMagicka()
, mPlayerFatigue()
, mGui(NULL)
, mGuiModes()
, mCursorManager(NULL)
@ -177,11 +175,11 @@ namespace MWGui
MyGUI::InputManager::getInstance().eventChangeKeyFocus += MyGUI::newDelegate(this, &WindowManager::onKeyFocusChanged);
mCursorManager->setEnabled(true);
onCursorChange(MyGUI::PointerManager::getInstance().getDefaultPointer());
SDL_ShowCursor(false);
mCursorManager->setEnabled(true);
// hide mygui's pointer
MyGUI::PointerManager::getInstance().setVisible(false);
}
@ -251,12 +249,12 @@ namespace MWGui
// Setup player stats
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)
{
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
@ -325,6 +323,7 @@ namespace MWGui
delete mSoulgemDialog;
delete mCursorManager;
delete mRecharge;
delete mCompanionWindow;
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);
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
/// allow custom skills.
@ -590,32 +589,8 @@ namespace MWGui
mStatsWindow->setValue (id, value);
mHud->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)
{
mStatsWindow->setValue (id, value);
@ -788,6 +763,13 @@ namespace MWGui
{
mMap->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)
{
mSelectedSpell = spellId;
mHud->setSelectedSpell(spellId, successChancePercent);
const ESM::Spell* spell =
@ -1033,6 +1016,7 @@ namespace MWGui
void WindowManager::setSelectedEnchantItem(const MWWorld::Ptr& item)
{
mSelectedSpell = "";
const ESM::Enchantment* ench = MWBase::Environment::get().getWorld()->getStore().get<ESM::Enchantment>()
.find(MWWorld::Class::get(item).getEnchantment(item));
@ -1052,6 +1036,7 @@ namespace MWGui
void WindowManager::unsetSelectedSpell()
{
mSelectedSpell = "";
mHud->unsetSelectedSpell();
mSpellWindow->setTitle("#{sNone}");
}
@ -1179,12 +1164,12 @@ namespace MWGui
return mGuiModes.back();
}
std::map<int, MWMechanics::Stat<float> > WindowManager::getPlayerSkillValues()
std::map<int, MWMechanics::SkillValue > WindowManager::getPlayerSkillValues()
{
return mPlayerSkillValues;
}
std::map<int, MWMechanics::Stat<int> > WindowManager::getPlayerAttributeValues()
std::map<int, MWMechanics::AttributeValue > WindowManager::getPlayerAttributeValues()
{
return mPlayerAttributes;
}

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

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

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

@ -126,7 +126,8 @@ namespace MWMechanics
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;
for (TContainer::const_iterator it = begin(); it != end(); ++it)
@ -139,6 +140,7 @@ namespace MWMechanics
params.mTimeStamp = MWBase::Environment::get().getWorld()->getTimeStamp();
params.mEffects = effects;
params.mDisplayName = displayName;
params.mCasterHandle = casterHandle;
if (!exists || stack)
mSpells.insert (std::make_pair(id, params));
@ -148,6 +150,12 @@ namespace MWMechanics
mSpellsChanged = true;
}
void ActiveSpells::removeEffects(const std::string &id)
{
mSpells.erase(Misc::StringUtils::lowerCase(id));
mSpellsChanged = true;
}
void ActiveSpells::visitEffectSources(EffectSourceVisitor &visitor) const
{
for (TContainer::const_iterator it = begin(); it != end(); ++it)
@ -164,14 +172,22 @@ namespace MWMechanics
float magnitude = effectIt->mMagnitude;
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)
@ -187,6 +203,6 @@ namespace MWMechanics
effectIt++;
}
}
mSpellsChanged = true;
}
}

@ -37,8 +37,8 @@ namespace MWMechanics
MWWorld::TimeStamp mTimeStamp;
std::string mDisplayName;
// TODO: To handle CASTER_LINKED flag (spell is purged when caster dies),
// we should probably store a handle to the caster here.
// Handle to the caster that that inflicted this spell on us
std::string mCasterHandle;
};
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 effects
/// \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);
/// Remove all active effects
void purgeAll ();
/// Remove all active effects, if roll succeeds (for each effect)
void purgeAll (float chance);
bool isSpellActive (std::string id) const;
///< 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
{
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)
{
// magic effects
adjustMagicEffects (ptr);
calculateDynamicStats (ptr);
if (ptr.getClass().getCreatureStats(ptr).needToRecalcDynamicStats())
calculateDynamicStats (ptr);
calculateCreatureStatModifiers (ptr, duration);
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])
+(actorpos.pos[1] - playerpos.pos[1])*(actorpos.pos[1] - playerpos.pos[1])
+(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
if(ptr.getTypeName() == typeid(ESM::NPC).name())
{
@ -127,7 +228,7 @@ namespace MWMechanics
now += creatureStats.getActiveSpells().getMagicEffects();
MagicEffects diff = MagicEffects::diff (creatureStats.getMagicEffects(), now);
//MagicEffects diff = MagicEffects::diff (creatureStats.getMagicEffects(), now);
creatureStats.setMagicEffects(now);
@ -177,7 +278,7 @@ namespace MWMechanics
{
// 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();
health.setCurrent (health.getCurrent() + 0.1 * endurance);
@ -216,7 +317,7 @@ namespace MWMechanics
// attributes
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 -
effects.get(EffectKey(ESM::MagicEffect::DrainAttribute, i)).mMagnitude -
effects.get(EffectKey(ESM::MagicEffect::AbsorbAttribute, i)).mMagnitude);
@ -228,18 +329,69 @@ namespace MWMechanics
for(int i = 0;i < 3;++i)
{
DynamicStat<float> stat = creatureStats.getDynamic(i);
stat.setModifier(effects.get(EffectKey(ESM::MagicEffect::FortifyHealth+i)).mMagnitude -
effects.get(EffectKey(ESM::MagicEffect::DrainHealth+i)).mMagnitude);
stat.setModifier(effects.get(ESM::MagicEffect::FortifyHealth+i).mMagnitude -
effects.get(ESM::MagicEffect::DrainHealth+i).mMagnitude);
float currentDiff = creatureStats.getMagicEffects().get(EffectKey(ESM::MagicEffect::RestoreHealth+i)).mMagnitude
- creatureStats.getMagicEffects().get(EffectKey(ESM::MagicEffect::DamageHealth+i)).mMagnitude
- creatureStats.getMagicEffects().get(EffectKey(ESM::MagicEffect::AbsorbHealth+i)).mMagnitude;
float currentDiff = creatureStats.getMagicEffects().get(ESM::MagicEffect::RestoreHealth+i).mMagnitude
- creatureStats.getMagicEffects().get(ESM::MagicEffect::DamageHealth+i).mMagnitude
- creatureStats.getMagicEffects().get(ESM::MagicEffect::AbsorbHealth+i).mMagnitude;
stat.setCurrent(stat.getCurrent() + currentDiff * duration);
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
int damageEffects[] = {
ESM::MagicEffect::FireDamage, ESM::MagicEffect::ShockDamage, ESM::MagicEffect::FrostDamage, ESM::MagicEffect::Poison,
@ -249,7 +401,7 @@ namespace MWMechanics
DynamicStat<float> health = creatureStats.getHealth();
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)
{
@ -280,30 +432,32 @@ namespace MWMechanics
static std::map<int, std::string> boundItemsMap;
if (boundItemsMap.empty())
{
boundItemsMap[ESM::MagicEffect::BoundBattleAxe] = "battle_axe";
boundItemsMap[ESM::MagicEffect::BoundBoots] = "boots";
boundItemsMap[ESM::MagicEffect::BoundCuirass] = "cuirass";
boundItemsMap[ESM::MagicEffect::BoundDagger] = "dagger";
boundItemsMap[ESM::MagicEffect::BoundGloves] = "gauntlet"; // Note: needs both _left and _right variants, see below
boundItemsMap[ESM::MagicEffect::BoundHelm] = "helm";
boundItemsMap[ESM::MagicEffect::BoundLongbow] = "longbow";
boundItemsMap[ESM::MagicEffect::BoundLongsword] = "longsword";
boundItemsMap[ESM::MagicEffect::BoundMace] = "mace";
boundItemsMap[ESM::MagicEffect::BoundShield] = "shield";
boundItemsMap[ESM::MagicEffect::BoundSpear] = "spear";
boundItemsMap[ESM::MagicEffect::BoundBattleAxe] = "sMagicBoundBattleAxeID";
boundItemsMap[ESM::MagicEffect::BoundBoots] = "sMagicBoundBootsID";
boundItemsMap[ESM::MagicEffect::BoundCuirass] = "sMagicBoundCuirassID";
boundItemsMap[ESM::MagicEffect::BoundDagger] = "sMagicBoundDaggerID";
boundItemsMap[ESM::MagicEffect::BoundGloves] = "sMagicBoundLeftGauntletID"; // Note: needs RightGauntlet variant too (see below)
boundItemsMap[ESM::MagicEffect::BoundHelm] = "sMagicBoundHelmID";
boundItemsMap[ESM::MagicEffect::BoundLongbow] = "sMagicBoundLongbowID";
boundItemsMap[ESM::MagicEffect::BoundLongsword] = "sMagicBoundLongswordID";
boundItemsMap[ESM::MagicEffect::BoundMace] = "sMagicBoundMaceID";
boundItemsMap[ESM::MagicEffect::BoundShield] = "sMagicBoundShieldID";
boundItemsMap[ESM::MagicEffect::BoundSpear] = "sMagicBoundSpearID";
}
for (std::map<int, std::string>::iterator it = boundItemsMap.begin(); it != boundItemsMap.end(); ++it)
{
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))
{
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)
{
adjustBoundItem(item + "_left", magnitude > 0, ptr);
adjustBoundItem(item + "_right", magnitude > 0, ptr);
adjustBoundItem("sMagicBoundLeftGauntletID", magnitude > 0, ptr);
adjustBoundItem("sMagicBoundRightGauntletID", magnitude > 0, ptr);
}
else
adjustBoundItem(item, magnitude > 0, ptr);
@ -319,32 +473,34 @@ namespace MWMechanics
static std::map<int, std::string> summonMap;
if (summonMap.empty())
{
summonMap[ESM::MagicEffect::SummonAncestralGhost] = "ancestor_ghost_summon";
summonMap[ESM::MagicEffect::SummonBear] = "BM_bear_black_summon";
summonMap[ESM::MagicEffect::SummonBonelord] = "bonelord_summon";
summonMap[ESM::MagicEffect::SummonBonewalker] = "bonewalker_summon";
summonMap[ESM::MagicEffect::SummonBonewolf] = "BM_wolf_bone_summon";
summonMap[ESM::MagicEffect::SummonCenturionSphere] = "centurion_sphere_summon";
summonMap[ESM::MagicEffect::SummonClannfear] = "clannfear_summon";
summonMap[ESM::MagicEffect::SummonDaedroth] = "daedroth_summon";
summonMap[ESM::MagicEffect::SummonDremora] = "dremora_summon";
summonMap[ESM::MagicEffect::SummonFabricant] = "fabricant_summon";
summonMap[ESM::MagicEffect::SummonFlameAtronach] = "atronach_flame_summon";
summonMap[ESM::MagicEffect::SummonFrostAtronach] = "atronach_frost_summon";
summonMap[ESM::MagicEffect::SummonGoldenSaint] = "golden saint_summon";
summonMap[ESM::MagicEffect::SummonGreaterBonewalker] = "bonewalker_greater_summ";
summonMap[ESM::MagicEffect::SummonHunger] = "hunger_summon";
summonMap[ESM::MagicEffect::SummonScamp] = "scamp_summon";
summonMap[ESM::MagicEffect::SummonSkeletalMinion] = "skeleton_summon";
summonMap[ESM::MagicEffect::SummonStormAtronach] = "atronach_storm_summon";
summonMap[ESM::MagicEffect::SummonWingedTwilight] = "winged twilight_summon";
summonMap[ESM::MagicEffect::SummonWolf] = "BM_wolf_grey_summon";
summonMap[ESM::MagicEffect::SummonAncestralGhost] = "sMagicAncestralGhostID";
summonMap[ESM::MagicEffect::SummonBonelord] = "sMagicBonelordID";
summonMap[ESM::MagicEffect::SummonBonewalker] = "sMagicLeastBonewalkerID";
summonMap[ESM::MagicEffect::SummonCenturionSphere] = "sMagicCenturionSphereID";
summonMap[ESM::MagicEffect::SummonClannfear] = "sMagicClannfearID";
summonMap[ESM::MagicEffect::SummonDaedroth] = "sMagicDaedrothID";
summonMap[ESM::MagicEffect::SummonDremora] = "sMagicDremoraID";
summonMap[ESM::MagicEffect::SummonFabricant] = "sMagicFabricantID";
summonMap[ESM::MagicEffect::SummonFlameAtronach] = "sMagicFlameAtronachID";
summonMap[ESM::MagicEffect::SummonFrostAtronach] = "sMagicFrostAtronachID";
summonMap[ESM::MagicEffect::SummonGoldenSaint] = "sMagicGoldenSaintID";
summonMap[ESM::MagicEffect::SummonGreaterBonewalker] = "sMagicGreaterBonewalkerID";
summonMap[ESM::MagicEffect::SummonHunger] = "sMagicHungerID";
summonMap[ESM::MagicEffect::SummonScamp] = "sMagicScampID";
summonMap[ESM::MagicEffect::SummonSkeletalMinion] = "sMagicSkeletalMinionID";
summonMap[ESM::MagicEffect::SummonStormAtronach] = "sMagicStormAtronachID";
summonMap[ESM::MagicEffect::SummonWingedTwilight] = "sMagicWingedTwilightID";
summonMap[ESM::MagicEffect::SummonWolf] = "sMagicCreature01ID";
summonMap[ESM::MagicEffect::SummonBear] = "sMagicCreature02ID";
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)
{
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 (magnitude > 0)
@ -361,15 +517,20 @@ namespace MWMechanics
ipos.rot[1] = 0;
ipos.rot[2] = 0;
MWWorld::CellStore* store = ptr.getCell();
MWWorld::ManualRef ref(MWBase::Environment::get().getWorld()->getStore(), it->second, 1);
ref.getPtr().getCellRef().mPos = ipos;
std::string creatureID =
MWBase::Environment::get().getWorld()->getStore().get<ESM::GameSetting>().find(it->second)->getString();
// 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,
MWBase::Environment::get().getWorld()->safePlaceObject(ref.getPtr(),*store,ipos).getRefData().getHandle()));
// TODO: Add AI to follow player and fight for him
creatureStats.mSummonedCreatures.insert(std::make_pair(it->first,
MWBase::Environment::get().getWorld()->safePlaceObject(ref.getPtr(),*store,ipos).getRefData().getHandle()));
}
}
else
{
@ -395,7 +556,7 @@ namespace MWMechanics
// skills
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 -
effects.get(EffectKey(ESM::MagicEffect::DrainSkill, 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)
{
//If holding a light...
bool isPlayer = ptr.getRefData().getHandle()=="player";
MWWorld::InventoryStore &inventoryStore = MWWorld::Class::get(ptr).getInventoryStore(ptr);
MWWorld::ContainerStoreIterator heldIter =
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)
{
// Use time from the player's light
bool isPlayer = ptr.getRefData().getHandle()=="player";
if(isPlayer)
{
float timeRemaining = heldIter->getClass().getRemainingUsageTime(*heldIter);
@ -482,6 +697,16 @@ namespace MWMechanics
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)
{
// 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())
{
++mDeathCount[cls.getId(iter->first)];
@ -592,7 +829,12 @@ namespace MWMechanics
iter->second->updateContinuousVfx();
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);
}
}
}
void Actors::restoreDynamicStats()

@ -25,14 +25,12 @@ namespace MWMechanics
{
class Actors
{
typedef std::map<MWWorld::Ptr,CharacterController*> PtrControllerMap;
PtrControllerMap mActors;
std::map<std::string, int> mDeathCount;
void updateNpc(const MWWorld::Ptr &ptr, float duration, bool paused);
typedef std::map<MWWorld::Ptr,CharacterController*> PtrControllerMap;
PtrControllerMap mActors;
std::map<std::string, int> mDeathCount;
void updateNpc(const MWWorld::Ptr &ptr, float duration, bool paused);
void adjustMagicEffects (const MWWorld::Ptr& creature);
@ -50,6 +48,7 @@ namespace MWMechanics
public:
Actors();
~Actors();
/// 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)

@ -91,6 +91,8 @@ namespace MWMechanics
mPathFinder.checkPathCompleted(pos.pos[0],pos.pos[1],pos.pos[2]);
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);
MWWorld::Class::get(actor).getMovementSettings(actor).mPosition[1] = 1;
@ -105,6 +107,7 @@ namespace MWMechanics
float directionResult = sqrt(directionX * directionX + directionY * directionY);
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);
mPathFinder.clearPath();

@ -161,6 +161,7 @@ namespace MWMechanics
if(distanceBetweenResult <= mMaxDist * mMaxDist)
{
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);
MWWorld::Class::get(actor).getMovementSettings(actor).mPosition[1] = 1;
mMaxDist = 470;

@ -97,6 +97,7 @@ namespace MWMechanics
}
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);
movement.mPosition[1] = 1;

@ -236,6 +236,7 @@ namespace MWMechanics
if(mWalking)
{
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);
MWWorld::Class::get(actor).getMovementSettings(actor).mPosition[1] = 1;

@ -351,7 +351,6 @@ CharacterController::CharacterController(const MWWorld::Ptr &ptr, MWRender::Anim
, mSkipAnim(false)
, mSecondsOfRunning(0)
, mSecondsOfSwimming(0)
, mFallHeight(0)
{
if(!mAnimation)
return;
@ -427,10 +426,10 @@ bool CharacterController::updateNpcState(bool onground, bool inwater, bool isrun
{
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",
// 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;
if(weaptype == WeapType_None)
@ -502,13 +501,25 @@ bool CharacterController::updateNpcState(bool onground, bool inwater, bool isrun
{
if(mUpperBodyState == UpperCharState_WeapEquiped)
{
MWBase::Environment::get().getWorld()->breakInvisibility(mPtr);
mAttackType.clear();
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 std::string spellid = stats.getSpells().getSelectedSpell();
if(!spellid.empty())
// For the player, set the spell we want to cast
// 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[] = {
"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);
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, false,
1.0f, "start", "stop", 0.0f, (~(size_t)0));
mAnimation->play("torch", Priority_Torch, 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");
}
return forcestateupdate;
}
@ -728,6 +740,8 @@ void CharacterController::update(float duration)
const MWWorld::Class &cls = MWWorld::Class::get(mPtr);
Ogre::Vector3 movement(0.0f);
updateVisibility();
if(!cls.isActor())
{
if(mAnimQueue.size() > 1)
@ -787,10 +801,10 @@ void CharacterController::update(float duration)
}
if(sneak || inwater || flying)
{
vec.z = 0.0f;
mFallHeight = mPtr.getRefData().getPosition().pos[2];
}
if (inwater || flying)
cls.getCreatureStats(mPtr).land();
if(!onground && !flying && !inwater)
{
@ -799,11 +813,7 @@ void CharacterController::update(float duration)
if (world->isSlowFalling(mPtr))
{
// SlowFalling spell effect is active, do not keep previous fall height
mFallHeight = mPtr.getRefData().getPosition().pos[2];
}
else
{
mFallHeight = std::max(mFallHeight, mPtr.getRefData().getPosition().pos[2]);
cls.getCreatureStats(mPtr).land();
}
const MWWorld::Store<ESM::GameSetting> &gmst = world->getStore().get<ESM::GameSetting>();
@ -859,7 +869,8 @@ void CharacterController::update(float duration)
mJumpState = JumpState_Landing;
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)
{
const float fatigueTerm = cls.getCreatureStats(mPtr).getFatigueTerm();
@ -880,8 +891,6 @@ void CharacterController::update(float duration)
//TODO: actor falls over
}
}
mFallHeight = mPtr.getRefData().getPosition().pos[2];
}
else
{
@ -920,6 +929,9 @@ void CharacterController::update(float duration)
}
}
if (onground)
cls.getCreatureStats(mPtr).land();
if(movestate != CharState_None)
clearAnimQueue();
@ -944,9 +956,12 @@ void CharacterController::update(float duration)
refreshCurrentAnims(idlestate, movestate, forcestateupdate);
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;
}
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 mSecondsOfRunning;
// used for acrobatics progress and fall damages
float mFallHeight;
std::string mAttackType; // slash, chop or thrust
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);
void updateVisibility();
public:
CharacterController(const MWWorld::Ptr &ptr, MWRender::Animation *anim);
virtual ~CharacterController();

@ -14,7 +14,8 @@ namespace MWMechanics
mTalkedTo (false), mAlarmed (false),
mAttacked (false), mHostile (false),
mAttackingOrSpell(false), mAttackType(AT_Chop),
mIsWerewolf(false)
mIsWerewolf(false),
mFallHeight(0), mRecalcDynamicStats(false)
{
for (int i=0; i<4; ++i)
mAiSettings[i] = 0;
@ -73,7 +74,7 @@ namespace MWMechanics
- 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) {
throw std::runtime_error("attribute index is out of range");
@ -121,20 +122,12 @@ namespace MWMechanics
return mLevel;
}
int CreatureStats::getAiSetting (int index) const
Stat<int> CreatureStats::getAiSetting (AiSetting index) const
{
assert (index>=0 && index<4);
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
{
if (index < 0 || index > 2) {
@ -163,11 +156,29 @@ namespace MWMechanics
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) {
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)
mAttributes[index] = value;
else
@ -217,6 +228,10 @@ namespace MWMechanics
void CreatureStats::setMagicEffects(const MagicEffects &effects)
{
if (effects.get(ESM::MagicEffect::FortifyMaximumMagicka).mMagnitude
!= mMagicEffects.get(ESM::MagicEffect::FortifyMaximumMagicka).mMagnitude)
mRecalcDynamicStats = true;
mMagicEffects = effects;
}
@ -225,12 +240,18 @@ namespace MWMechanics
mAttackingOrSpell = attackingOrSpell;
}
void CreatureStats::setAiSetting (int index, int value)
void CreatureStats::setAiSetting (AiSetting index, Stat<int> value)
{
assert (index>=0 && index<4);
mAiSettings[index] = value;
}
void CreatureStats::setAiSetting (AiSetting index, int base)
{
Stat<int> stat(base);
setAiSetting(index, stat);
}
bool CreatureStats::isDead() const
{
return mDead;
@ -251,8 +272,10 @@ namespace MWMechanics
if (mDead)
{
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)
mDead = false;
}
@ -328,7 +351,7 @@ namespace MWMechanics
float evasion = (getAttribute(ESM::Attribute::Agility).getModified() / 5.0f) +
(getAttribute(ESM::Attribute::Luck).getModified() / 10.0f);
evasion *= getFatigueTerm();
evasion += mMagicEffects.get(EffectKey(ESM::MagicEffect::Sanctuary)).mMagnitude;
evasion += mMagicEffects.get(ESM::MagicEffect::Sanctuary).mMagnitude;
return evasion;
}
@ -356,4 +379,26 @@ namespace MWMechanics
{
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
{
Stat<int> mAttributes[8];
AttributeValue mAttributes[8];
DynamicStat<float> mDynamic[3]; // health, magicka, fatigue
int mLevel;
Spells mSpells;
ActiveSpells mActiveSpells;
MagicEffects mMagicEffects;
int mAiSettings[4];
Stat<int> mAiSettings[4];
AiSequence mAiSequence;
float mLevelHealthBonus;
bool mDead;
@ -36,23 +36,36 @@ namespace MWMechanics
bool mHostile;
bool mAttackingOrSpell;//for the player, this is true if the left mouse button is pressed, false if not.
float mFallHeight;
int mAttackType;
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;
protected:
bool mIsWerewolf;
Stat<int> mWerewolfAttributes[8];
AttributeValue mWerewolfAttributes[8];
public:
CreatureStats();
bool needToRecalcDynamicStats();
void addToFallHeight(float height);
/// Reset the fall height
/// @return total fall height
float land();
bool canUsePower (const std::string& power) const;
void usePower (const std::string& power);
const Stat<int> & getAttribute(int index) const;
const AttributeValue & getAttribute(int index) const;
const DynamicStat<float> & getHealth() const;
@ -72,18 +85,15 @@ namespace MWMechanics
int getLevel() const;
int getAiSetting (int index) const;
///< 0: hello, 1 fight, 2 flee, 3 alarm
Stat<int> & getAttribute(int index);
Spells & getSpells();
ActiveSpells & getActiveSpells();
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);
@ -112,8 +122,16 @@ namespace MWMechanics
void setLevel(int level);
void setAiSetting (int index, int value);
///< 0: hello, 1 fight, 2 flee, 3 alarm
enum AiSetting
{
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;

@ -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
store.remove(mOldItemPtr, 1, player);
store.add(newItemPtr, player);
store.add(newItemPtr, 1, player);
if(!mSelfEnchanting)
payForEnchantment();

@ -56,7 +56,8 @@ namespace MWMechanics
struct EffectSourceVisitor
{
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

@ -12,6 +12,8 @@
#include "../mwworld/class.hpp"
#include "../mwworld/player.hpp"
#include "spellcasting.hpp"
namespace MWMechanics
{
void MechanicsManager::buildPlayer()
@ -31,15 +33,14 @@ namespace MWMechanics
for (int i=0; i<27; ++i)
npcStats.getSkill (i).setBase (player->mNpdt52.mSkills[i]);
creatureStats.getAttribute(0).setBase (player->mNpdt52.mStrength);
creatureStats.getAttribute(1).setBase (player->mNpdt52.mIntelligence);
creatureStats.getAttribute(2).setBase (player->mNpdt52.mWillpower);
creatureStats.getAttribute(3).setBase (player->mNpdt52.mAgility);
creatureStats.getAttribute(4).setBase (player->mNpdt52.mSpeed);
creatureStats.getAttribute(5).setBase (player->mNpdt52.mEndurance);
creatureStats.getAttribute(6).setBase (player->mNpdt52.mPersonality);
creatureStats.getAttribute(7).setBase (player->mNpdt52.mLuck);
creatureStats.setAttribute(ESM::Attribute::Strength, player->mNpdt52.mStrength);
creatureStats.setAttribute(ESM::Attribute::Intelligence, player->mNpdt52.mIntelligence);
creatureStats.setAttribute(ESM::Attribute::Willpower, player->mNpdt52.mWillpower);
creatureStats.setAttribute(ESM::Attribute::Agility, player->mNpdt52.mAgility);
creatureStats.setAttribute(ESM::Attribute::Speed, player->mNpdt52.mSpeed);
creatureStats.setAttribute(ESM::Attribute::Endurance, player->mNpdt52.mEndurance);
creatureStats.setAttribute(ESM::Attribute::Personality, player->mNpdt52.mPersonality);
creatureStats.setAttribute(ESM::Attribute::Luck, player->mNpdt52.mLuck);
const MWWorld::ESMStore &esmStore =
MWBase::Environment::get().getWorld()->getStore();
@ -55,7 +56,7 @@ namespace MWMechanics
{
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)
@ -106,7 +107,7 @@ namespace MWMechanics
int attribute = class_->mData.mAttribute[i];
if (attribute>=0 && attribute<8)
{
creatureStats.getAttribute(attribute).setBase (
creatureStats.setAttribute(attribute,
creatureStats.getAttribute(attribute).getBase() + 10);
}
}
@ -124,6 +125,19 @@ namespace MWMechanics
npcStats.getSkill (index).setBase (
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)
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
return effective_disposition;
}
@ -485,10 +501,10 @@ namespace MWMechanics
// otherwise one would get different prices when exiting and re-entering the dialogue window...
int clampedDisposition = std::max(0, std::min(getDerivedDisposition(ptr)
+ 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 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 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);
npcStats.setAiSetting (2, std::max(0, std::min(100, npcStats.getAiSetting (2) + int(std::max(iPerMinChange, s)))));
npcStats.setAiSetting (1, std::max(0, std::min(100, npcStats.getAiSetting (1) + int(std::min(-iPerMinChange, -s)))));
int flee = npcStats.getAiSetting(MWMechanics::CreatureStats::AI_Flee).getBase();
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));
@ -626,8 +646,12 @@ namespace MWMechanics
{
float s = c * fPerDieRollMult * fPerTempMult;
npcStats.setAiSetting (2, std::max(0, std::min(100, npcStats.getAiSetting (2) + std::min(-int(iPerMinChange), int(-s)))));
npcStats.setAiSetting (1, std::max(0, std::min(100, npcStats.getAiSetting (1) + std::max(int(iPerMinChange), int(s)))));
int flee = npcStats.getAiSetting (CreatureStats::AI_Flee).getBase();
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);

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

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

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

Loading…
Cancel
Save