Merge branch 'master' into master

pull/124/head
Bret Curtis 8 years ago committed by GitHub
commit 065bf47e38

@ -23,10 +23,12 @@ Programmers
Alexander Olofsson (Ace) Alexander Olofsson (Ace)
Allofich Allofich
AnyOldName3 AnyOldName3
Aussiemon
Austin Salgat (Salgat) Austin Salgat (Salgat)
Artem Kotsynyak (greye) Artem Kotsynyak (greye)
artemutin artemutin
Arthur Moore (EmperorArthur) Arthur Moore (EmperorArthur)
Assumeru
athile athile
Ben Shealy (bentsherman) Ben Shealy (bentsherman)
Bret Curtis (psi29a) Bret Curtis (psi29a)
@ -73,6 +75,7 @@ Programmers
Karl-Felix Glatzer (k1ll) Karl-Felix Glatzer (k1ll)
Kevin Poitra (PuppyKevin) Kevin Poitra (PuppyKevin)
Koncord Koncord
Kurnevsky Evgeny (kurnevsky)
Lars Söderberg (Lazaroth) Lars Söderberg (Lazaroth)
lazydev lazydev
Leon Saunders (emoose) Leon Saunders (emoose)
@ -119,6 +122,7 @@ Programmers
Scott Howard Scott Howard
Sebastian Wick (swick) Sebastian Wick (swick)
Sergey Shambir Sergey Shambir
ShadowRadiance
sir_herrbatka sir_herrbatka
smbas smbas
Stefan Galowicz (bogglez) Stefan Galowicz (bogglez)

@ -1,10 +1,11 @@
#!/bin/sh #!/bin/sh
brew update brew update
brew rm cmake || true brew rm cmake || true
brew rm pkgconfig || true brew rm pkgconfig || true
brew rm qt5 || true brew rm qt5 || true
brew install cmake pkgconfig qt5 brew install cmake pkgconfig qt55
curl http://downloads.openmw.org/osx/dependencies/openmw-deps-263d4a8.zip -o ~/openmw-deps.zip curl http://downloads.openmw.org/osx/dependencies/openmw-deps-263d4a8.zip -o ~/openmw-deps.zip
unzip ~/openmw-deps.zip -d /private/tmp/openmw-deps > /dev/null unzip ~/openmw-deps.zip -d /private/tmp/openmw-deps > /dev/null

@ -4,13 +4,12 @@ export CXX=clang++
export CC=clang export CC=clang
DEPENDENCIES_ROOT="/private/tmp/openmw-deps/openmw-deps" DEPENDENCIES_ROOT="/private/tmp/openmw-deps/openmw-deps"
QT_PATH="/usr/local/opt/qt5" QT_PATH="/usr/local/opt/qt55"
mkdir build mkdir build
cd build cd build
cmake \ cmake \
-D CMAKE_EXE_LINKER_FLAGS="-lz" \
-D CMAKE_PREFIX_PATH="$DEPENDENCIES_ROOT;$QT_PATH" \ -D CMAKE_PREFIX_PATH="$DEPENDENCIES_ROOT;$QT_PATH" \
-D CMAKE_OSX_DEPLOYMENT_TARGET="10.8" \ -D CMAKE_OSX_DEPLOYMENT_TARGET="10.8" \
-D CMAKE_OSX_SYSROOT="macosx10.11" \ -D CMAKE_OSX_SYSROOT="macosx10.11" \

@ -46,7 +46,7 @@ if(EXISTS ${PROJECT_SOURCE_DIR}/.git)
else(NOT EXISTS ${PROJECT_SOURCE_DIR}/.git/shallow) else(NOT EXISTS ${PROJECT_SOURCE_DIR}/.git/shallow)
message(STATUS "Shallow Git clone detected, not attempting to retrieve version info") message(STATUS "Shallow Git clone detected, not attempting to retrieve version info")
endif(NOT EXISTS ${PROJECT_SOURCE_DIR}/.git/shallow) endif(NOT EXISTS ${PROJECT_SOURCE_DIR}/.git/shallow)
endif(EXISTS ${PROJECT_SOURCE_DIR}/.git) endif(EXISTS ${PROJECT_SOURCE_DIR}/.git)
# Macros # Macros
include(OpenMWMacros) include(OpenMWMacros)
@ -96,7 +96,7 @@ endif()
# Set up common paths # Set up common paths
if (APPLE) if (APPLE)
set(MORROWIND_DATA_FILES "./data" CACHE PATH "location of Morrowind data files") set(MORROWIND_DATA_FILES "./data" CACHE PATH "location of Morrowind data files")
set(OPENMW_RESOURCE_FILES "./resources" CACHE PATH "location of OpenMW resources files") set(OPENMW_RESOURCE_FILES "../Resources/resources" CACHE PATH "location of OpenMW resources files")
elseif(UNIX) elseif(UNIX)
# Paths # Paths
SET(BINDIR "${CMAKE_INSTALL_PREFIX}/bin" CACHE PATH "Where to install binaries") SET(BINDIR "${CMAKE_INSTALL_PREFIX}/bin" CACHE PATH "Where to install binaries")
@ -286,6 +286,11 @@ endif (APPLE)
# Set up DEBUG define # Set up DEBUG define
set_directory_properties(PROPERTIES COMPILE_DEFINITIONS_DEBUG DEBUG=1) set_directory_properties(PROPERTIES COMPILE_DEFINITIONS_DEBUG DEBUG=1)
if (NOT APPLE)
set(OPENMW_MYGUI_FILES_ROOT ${OpenMW_BINARY_DIR})
set(OPENMW_SHADERS_ROOT ${OpenMW_BINARY_DIR})
endif ()
add_subdirectory(files/) add_subdirectory(files/)
# Specify build paths # Specify build paths
@ -307,11 +312,15 @@ endif (APPLE)
configure_file(${OpenMW_SOURCE_DIR}/files/settings-default.cfg configure_file(${OpenMW_SOURCE_DIR}/files/settings-default.cfg
"${OpenMW_BINARY_DIR}/settings-default.cfg") "${OpenMW_BINARY_DIR}/settings-default.cfg")
configure_file(${OpenMW_SOURCE_DIR}/files/openmw.cfg.local if (NOT APPLE)
"${OpenMW_BINARY_DIR}/openmw.cfg") configure_file(${OpenMW_SOURCE_DIR}/files/openmw.cfg.local
"${OpenMW_BINARY_DIR}/openmw.cfg")
configure_file(${OpenMW_SOURCE_DIR}/files/openmw.cfg configure_file(${OpenMW_SOURCE_DIR}/files/openmw.cfg
"${OpenMW_BINARY_DIR}/openmw.cfg.install") "${OpenMW_BINARY_DIR}/openmw.cfg.install")
else ()
configure_file(${OpenMW_SOURCE_DIR}/files/openmw.cfg
"${OpenMW_BINARY_DIR}/openmw.cfg")
endif ()
configure_file(${OpenMW_SOURCE_DIR}/files/openmw-cs.cfg configure_file(${OpenMW_SOURCE_DIR}/files/openmw-cs.cfg
"${OpenMW_BINARY_DIR}/openmw-cs.cfg") "${OpenMW_BINARY_DIR}/openmw-cs.cfg")
@ -419,8 +428,10 @@ IF(NOT WIN32 AND NOT APPLE)
ENDIF(NOT WIN32 AND NOT APPLE) ENDIF(NOT WIN32 AND NOT APPLE)
if(WIN32) if(WIN32)
FILE(GLOB dll_files "${OpenMW_BINARY_DIR}/Release/*.dll") FILE(GLOB dll_files_debug "${OpenMW_BINARY_DIR}/Debug/*.dll")
INSTALL(FILES ${dll_files} DESTINATION ".") FILE(GLOB dll_files_release "${OpenMW_BINARY_DIR}/Release/*.dll")
INSTALL(FILES ${dll_files_debug} DESTINATION "." CONFIGURATIONS Debug)
INSTALL(FILES ${dll_files_release} DESTINATION "." CONFIGURATIONS Release;RelWithDebInfo;MinSizeRel)
INSTALL(FILES "${OpenMW_BINARY_DIR}/openmw.cfg.install" DESTINATION "." RENAME "openmw.cfg") INSTALL(FILES "${OpenMW_BINARY_DIR}/openmw.cfg.install" DESTINATION "." RENAME "openmw.cfg")
INSTALL(FILES "${OpenMW_SOURCE_DIR}/CHANGELOG.md" DESTINATION "." RENAME "CHANGELOG.txt") INSTALL(FILES "${OpenMW_SOURCE_DIR}/CHANGELOG.md" DESTINATION "." RENAME "CHANGELOG.txt")
INSTALL(FILES "${OpenMW_SOURCE_DIR}/README.md" DESTINATION "." RENAME "README.txt") INSTALL(FILES "${OpenMW_SOURCE_DIR}/README.md" DESTINATION "." RENAME "README.txt")
@ -429,36 +440,23 @@ if(WIN32)
"${OpenMW_SOURCE_DIR}/Docs/license/DejaVu Font License.txt" "${OpenMW_SOURCE_DIR}/Docs/license/DejaVu Font License.txt"
"${OpenMW_BINARY_DIR}/settings-default.cfg" "${OpenMW_BINARY_DIR}/settings-default.cfg"
"${OpenMW_BINARY_DIR}/gamecontrollerdb.txt" "${OpenMW_BINARY_DIR}/gamecontrollerdb.txt"
"${OpenMW_BINARY_DIR}/Release/openmw.exe"
DESTINATION ".") DESTINATION ".")
IF(BUILD_LAUNCHER)
INSTALL(PROGRAMS "${OpenMW_BINARY_DIR}/Release/openmw-launcher.exe" DESTINATION ".")
ENDIF(BUILD_LAUNCHER)
IF(BUILD_MWINIIMPORTER)
INSTALL(PROGRAMS "${OpenMW_BINARY_DIR}/Release/openmw-iniimporter.exe" DESTINATION ".")
ENDIF(BUILD_MWINIIMPORTER)
IF(BUILD_ESSIMPORTER)
INSTALL(PROGRAMS "${OpenMW_BINARY_DIR}/Release/openmw-essimporter.exe" DESTINATION ".")
ENDIF(BUILD_ESSIMPORTER)
IF(BUILD_OPENCS)
INSTALL(PROGRAMS "${OpenMW_BINARY_DIR}/Release/openmw-cs.exe" DESTINATION ".")
INSTALL(FILES "${OpenMW_BINARY_DIR}/openmw-cs.cfg" DESTINATION ".")
ENDIF(BUILD_OPENCS)
IF(BUILD_WIZARD)
INSTALL(PROGRAMS "${OpenMW_BINARY_DIR}/Release/openmw-wizard.exe" DESTINATION ".")
ENDIF(BUILD_WIZARD)
if(BUILD_MYGUI_PLUGIN) if(BUILD_MYGUI_PLUGIN)
INSTALL(PROGRAMS "${OpenMW_BINARY_DIR}/Release/Plugin_MyGUI_OpenMW_Resources.dll" DESTINATION ".") INSTALL(PROGRAMS "${OpenMW_BINARY_DIR}/Debug/Plugin_MyGUI_OpenMW_Resources.dll" DESTINATION "." CONFIGURATIONS Debug)
INSTALL(PROGRAMS "${OpenMW_BINARY_DIR}/Release/Plugin_MyGUI_OpenMW_Resources.dll" DESTINATION "." CONFIGURATIONS Release;RelWithDebInfo;MinSizeRel)
ENDIF(BUILD_MYGUI_PLUGIN) ENDIF(BUILD_MYGUI_PLUGIN)
IF(DESIRED_QT_VERSION MATCHES 5) IF(DESIRED_QT_VERSION MATCHES 5)
INSTALL(DIRECTORY "${OpenMW_BINARY_DIR}/Release/platforms" DESTINATION ".") INSTALL(DIRECTORY "${OpenMW_BINARY_DIR}/Debug/platforms" DESTINATION "." CONFIGURATIONS Debug)
INSTALL(DIRECTORY "${OpenMW_BINARY_DIR}/Release/platforms" DESTINATION "." CONFIGURATIONS Release;RelWithDebInfo;MinSizeRel)
ENDIF() ENDIF()
INSTALL(DIRECTORY "${OpenMW_BINARY_DIR}/resources" DESTINATION ".") INSTALL(DIRECTORY "${OpenMW_BINARY_DIR}/resources" DESTINATION ".")
FILE(GLOB plugin_dir "${OpenMW_BINARY_DIR}/Release/osgPlugins-*") FILE(GLOB plugin_dir_debug "${OpenMW_BINARY_DIR}/Debug/osgPlugins-*")
INSTALL(DIRECTORY ${plugin_dir} DESTINATION ".") FILE(GLOB plugin_dir_release "${OpenMW_BINARY_DIR}/Release/osgPlugins-*")
INSTALL(DIRECTORY ${plugin_dir_debug} DESTINATION "." CONFIGURATIONS Debug)
INSTALL(DIRECTORY ${plugin_dir_release} DESTINATION "." CONFIGURATIONS Release;RelWithDebInfo;MinSizeRel)
SET(CPACK_GENERATOR "NSIS") SET(CPACK_GENERATOR "NSIS")
SET(CPACK_PACKAGE_NAME "OpenMW") SET(CPACK_PACKAGE_NAME "OpenMW")
@ -725,14 +723,7 @@ if (APPLE)
configure_file("${QT_COCOA_PLUGIN_PATH}" "${OPENCS_BUNDLE_NAME}/Contents/MacOS/${QT_COCOA_PLUGIN_GROUP}/${QT_COCOA_PLUGIN_NAME}" COPYONLY) configure_file("${QT_COCOA_PLUGIN_PATH}" "${OPENCS_BUNDLE_NAME}/Contents/MacOS/${QT_COCOA_PLUGIN_GROUP}/${QT_COCOA_PLUGIN_NAME}" COPYONLY)
endif () endif ()
set(INSTALL_SUBDIR OpenMW) install(DIRECTORY "${APP_BUNDLE_DIR}" USE_SOURCE_PERMISSIONS DESTINATION "." COMPONENT Runtime)
install(DIRECTORY "${APP_BUNDLE_DIR}" USE_SOURCE_PERMISSIONS DESTINATION "${INSTALL_SUBDIR}" COMPONENT Runtime)
install(DIRECTORY "${OpenMW_BINARY_DIR}/resources" DESTINATION "${INSTALL_SUBDIR}" COMPONENT Runtime)
install(FILES "${OpenMW_BINARY_DIR}/openmw.cfg.install" RENAME "openmw.cfg" DESTINATION "${INSTALL_SUBDIR}" COMPONENT Runtime)
install(FILES "${OpenMW_BINARY_DIR}/settings-default.cfg" DESTINATION "${INSTALL_SUBDIR}" COMPONENT Runtime)
install(FILES "${OpenMW_BINARY_DIR}/gamecontrollerdb.txt" DESTINATION "${INSTALL_SUBDIR}" COMPONENT Runtime)
install(FILES "${OpenMW_BINARY_DIR}/openmw-cs.cfg" DESTINATION "${INSTALL_SUBDIR}" COMPONENT Runtime)
set(CPACK_GENERATOR "DragNDrop") set(CPACK_GENERATOR "DragNDrop")
set(CPACK_PACKAGE_VERSION ${OPENMW_VERSION}) set(CPACK_PACKAGE_VERSION ${OPENMW_VERSION})
@ -740,8 +731,8 @@ if (APPLE)
set(CPACK_PACKAGE_VERSION_MINOR ${OPENMW_VERSION_MINOR}) set(CPACK_PACKAGE_VERSION_MINOR ${OPENMW_VERSION_MINOR})
set(CPACK_PACKAGE_VERSION_PATCH ${OPENMW_VERSION_RELEASE}) set(CPACK_PACKAGE_VERSION_PATCH ${OPENMW_VERSION_RELEASE})
set(INSTALLED_OPENMW_APP "\${CMAKE_INSTALL_PREFIX}/${INSTALL_SUBDIR}/${APP_BUNDLE_NAME}") set(INSTALLED_OPENMW_APP "\${CMAKE_INSTALL_PREFIX}/${APP_BUNDLE_NAME}")
set(INSTALLED_OPENCS_APP "\${CMAKE_INSTALL_PREFIX}/${INSTALL_SUBDIR}/${OPENCS_BUNDLE_NAME}") set(INSTALLED_OPENCS_APP "\${CMAKE_INSTALL_PREFIX}/${OPENCS_BUNDLE_NAME}")
install(CODE " install(CODE "
set(BU_CHMOD_BUNDLE_ITEMS ON) set(BU_CHMOD_BUNDLE_ITEMS ON)
@ -785,8 +776,8 @@ if (APPLE)
set(${plugins_var} ${PLUGINS} PARENT_SCOPE) set(${plugins_var} ${PLUGINS} PARENT_SCOPE)
endfunction (install_plugins_for_bundle) endfunction (install_plugins_for_bundle)
install_plugins_for_bundle("${INSTALL_SUBDIR}/${APP_BUNDLE_NAME}" PLUGINS) install_plugins_for_bundle("${APP_BUNDLE_NAME}" PLUGINS)
install_plugins_for_bundle("${INSTALL_SUBDIR}/${OPENCS_BUNDLE_NAME}" OPENCS_PLUGINS) install_plugins_for_bundle("${OPENCS_BUNDLE_NAME}" OPENCS_PLUGINS)
set(PLUGINS ${PLUGINS} "${INSTALLED_OPENMW_APP}/Contents/MacOS/${QT_COCOA_PLUGIN_GROUP}/${QT_COCOA_PLUGIN_NAME}") set(PLUGINS ${PLUGINS} "${INSTALLED_OPENMW_APP}/Contents/MacOS/${QT_COCOA_PLUGIN_GROUP}/${QT_COCOA_PLUGIN_NAME}")
set(OPENCS_PLUGINS ${OPENCS_PLUGINS} "${INSTALLED_OPENCS_APP}/Contents/MacOS/${QT_COCOA_PLUGIN_GROUP}/${QT_COCOA_PLUGIN_NAME}") set(OPENCS_PLUGINS ${OPENCS_PLUGINS} "${INSTALLED_OPENCS_APP}/Contents/MacOS/${QT_COCOA_PLUGIN_GROUP}/${QT_COCOA_PLUGIN_NAME}")
@ -828,3 +819,4 @@ if (DOXYGEN_FOUND)
WORKING_DIRECTORY ${OpenMW_BINARY_DIR} WORKING_DIRECTORY ${OpenMW_BINARY_DIR}
COMMENT "Generating documentation for the github-pages at ${DOXYGEN_PAGES_OUTPUT_DIR}" VERBATIM) COMMENT "Generating documentation for the github-pages at ${DOXYGEN_PAGES_OUTPUT_DIR}" VERBATIM)
endif () endif ()

@ -42,3 +42,7 @@ if (BUILD_WITH_CODE_COVERAGE)
add_definitions (--coverage) add_definitions (--coverage)
target_link_libraries(openmw-essimporter gcov) target_link_libraries(openmw-essimporter gcov)
endif() endif()
if (WIN32)
INSTALL(TARGETS openmw-essimporter RUNTIME DESTINATION ".")
endif(WIN32)

@ -271,23 +271,34 @@ private:
class ConvertPCDT : public Converter class ConvertPCDT : public Converter
{ {
public: public:
ConvertPCDT() : mFirstPersonCam(true) {} ConvertPCDT()
: mFirstPersonCam(true),
mTeleportingEnabled(true),
mLevitationEnabled(true)
{}
virtual void read(ESM::ESMReader &esm) virtual void read(ESM::ESMReader &esm)
{ {
PCDT pcdt; PCDT pcdt;
pcdt.load(esm); pcdt.load(esm);
convertPCDT(pcdt, mContext->mPlayer, mContext->mDialogueState.mKnownTopics, mFirstPersonCam); convertPCDT(pcdt, mContext->mPlayer, mContext->mDialogueState.mKnownTopics, mFirstPersonCam, mTeleportingEnabled, mLevitationEnabled, mContext->mControlsState);
} }
virtual void write(ESM::ESMWriter &esm) virtual void write(ESM::ESMWriter &esm)
{ {
esm.startRecord(ESM::REC_ENAB);
esm.writeHNT("TELE", mTeleportingEnabled);
esm.writeHNT("LEVT", mLevitationEnabled);
esm.endRecord(ESM::REC_ENAB);
esm.startRecord(ESM::REC_CAM_); esm.startRecord(ESM::REC_CAM_);
esm.writeHNT("FIRS", mFirstPersonCam); esm.writeHNT("FIRS", mFirstPersonCam);
esm.endRecord(ESM::REC_CAM_); esm.endRecord(ESM::REC_CAM_);
} }
private: private:
bool mFirstPersonCam; bool mFirstPersonCam;
bool mTeleportingEnabled;
bool mLevitationEnabled;
}; };
class ConvertCNTC : public Converter class ConvertCNTC : public Converter

@ -5,7 +5,7 @@
namespace ESSImport namespace ESSImport
{ {
void convertPCDT(const PCDT& pcdt, ESM::Player& out, std::vector<std::string>& outDialogueTopics, bool& firstPersonCam) void convertPCDT(const PCDT& pcdt, ESM::Player& out, std::vector<std::string>& outDialogueTopics, bool& firstPersonCam, bool& teleportingEnabled, bool& levitationEnabled, ESM::ControlsState& controls)
{ {
out.mBirthsign = pcdt.mBirthsign; out.mBirthsign = pcdt.mBirthsign;
out.mObject.mNpcStats.mBounty = pcdt.mBounty; out.mObject.mNpcStats.mBounty = pcdt.mBounty;
@ -25,18 +25,28 @@ namespace ESSImport
out.mObject.mNpcStats.mSkills[i].mProgress = pcdt.mPNAM.mSkillProgress[i]; out.mObject.mNpcStats.mSkills[i].mProgress = pcdt.mPNAM.mSkillProgress[i];
out.mObject.mNpcStats.mLevelProgress = pcdt.mPNAM.mLevelProgress; out.mObject.mNpcStats.mLevelProgress = pcdt.mPNAM.mLevelProgress;
if (pcdt.mPNAM.mDrawState & PCDT::DrawState_Weapon) if (pcdt.mPNAM.mPlayerFlags & PCDT::PlayerFlags_WeaponDrawn)
out.mObject.mCreatureStats.mDrawState = 1; out.mObject.mCreatureStats.mDrawState = 1;
if (pcdt.mPNAM.mDrawState & PCDT::DrawState_Spell) if (pcdt.mPNAM.mPlayerFlags & PCDT::PlayerFlags_SpellDrawn)
out.mObject.mCreatureStats.mDrawState = 2; out.mObject.mCreatureStats.mDrawState = 2;
firstPersonCam = !(pcdt.mPNAM.mCameraFlags & PCDT::CameraFlag_ThirdPerson); firstPersonCam = !(pcdt.mPNAM.mPlayerFlags & PCDT::PlayerFlags_ThirdPerson);
teleportingEnabled = !(pcdt.mPNAM.mPlayerFlags & PCDT::PlayerFlags_TeleportingDisabled);
levitationEnabled = !(pcdt.mPNAM.mPlayerFlags & PCDT::PlayerFlags_LevitationDisabled);
for (std::vector<std::string>::const_iterator it = pcdt.mKnownDialogueTopics.begin(); for (std::vector<std::string>::const_iterator it = pcdt.mKnownDialogueTopics.begin();
it != pcdt.mKnownDialogueTopics.end(); ++it) it != pcdt.mKnownDialogueTopics.end(); ++it)
{ {
outDialogueTopics.push_back(Misc::StringUtils::lowerCase(*it)); outDialogueTopics.push_back(Misc::StringUtils::lowerCase(*it));
} }
controls.mViewSwitchDisabled = pcdt.mPNAM.mPlayerFlags & PCDT::PlayerFlags_ViewSwitchDisabled;
controls.mControlsDisabled = pcdt.mPNAM.mPlayerFlags & PCDT::PlayerFlags_ControlsDisabled;
controls.mJumpingDisabled = pcdt.mPNAM.mPlayerFlags & PCDT::PlayerFlags_JumpingDisabled;
controls.mLookingDisabled = pcdt.mPNAM.mPlayerFlags & PCDT::PlayerFlags_LookingDisabled;
controls.mVanityModeDisabled = pcdt.mPNAM.mPlayerFlags & PCDT::PlayerFlags_VanityModeDisabled;
controls.mWeaponDrawingDisabled = pcdt.mPNAM.mPlayerFlags & PCDT::PlayerFlags_WeaponDrawingDisabled;
controls.mSpellDrawingDisabled = pcdt.mPNAM.mPlayerFlags & PCDT::PlayerFlags_SpellDrawingDisabled;
} }
} }

@ -4,11 +4,12 @@
#include "importplayer.hpp" #include "importplayer.hpp"
#include <components/esm/player.hpp> #include <components/esm/player.hpp>
#include <components/esm/controlsstate.hpp>
namespace ESSImport namespace ESSImport
{ {
void convertPCDT(const PCDT& pcdt, ESM::Player& out, std::vector<std::string>& outDialogueTopics, bool& firstPersonCam); void convertPCDT(const PCDT& pcdt, ESM::Player& out, std::vector<std::string>& outDialogueTopics, bool& firstPersonCam, bool& teleportingEnabled, bool& levitationEnabled, ESM::ControlsState& controls);
} }

@ -51,6 +51,7 @@ namespace
{ {
for (int x=0; x<128; ++x) for (int x=0; x<128; ++x)
{ {
assert(image->data(x,y));
*(image->data(x,y)+2) = *it++; *(image->data(x,y)+2) = *it++;
*(image->data(x,y)+1) = *it++; *(image->data(x,y)+1) = *it++;
*image->data(x,y) = *it++; *image->data(x,y) = *it++;
@ -422,6 +423,10 @@ namespace ESSImport
writer.startRecord (ESM::REC_DIAS); writer.startRecord (ESM::REC_DIAS);
context.mDialogueState.save(writer); context.mDialogueState.save(writer);
writer.endRecord(ESM::REC_DIAS); writer.endRecord(ESM::REC_DIAS);
writer.startRecord(ESM::REC_INPU);
context.mControlsState.save(writer);
writer.endRecord(ESM::REC_INPU);
} }

@ -9,6 +9,7 @@
#include <components/esm/globalmap.hpp> #include <components/esm/globalmap.hpp>
#include <components/esm/loadcrea.hpp> #include <components/esm/loadcrea.hpp>
#include <components/esm/loadnpc.hpp> #include <components/esm/loadnpc.hpp>
#include <components/esm/controlsstate.hpp>
#include "importnpcc.hpp" #include "importnpcc.hpp"
#include "importcrec.hpp" #include "importcrec.hpp"
@ -32,6 +33,8 @@ namespace ESSImport
ESM::DialogueState mDialogueState; ESM::DialogueState mDialogueState;
ESM::ControlsState mControlsState;
// cells which should show an explored overlay on the global map // cells which should show an explored overlay on the global map
std::set<std::pair<int, int> > mExploredCells; std::set<std::pair<int, int> > mExploredCells;

@ -38,14 +38,20 @@ struct PCDT
std::vector<std::string> mKnownDialogueTopics; std::vector<std::string> mKnownDialogueTopics;
enum DrawState_ enum PlayerFlags
{ {
DrawState_Weapon = 0x80, PlayerFlags_ViewSwitchDisabled = 0x1,
DrawState_Spell = 0x100 PlayerFlags_ControlsDisabled = 0x4,
}; PlayerFlags_WeaponDrawn = 0x80,
enum CameraFlags PlayerFlags_SpellDrawn = 0x100,
{ PlayerFlags_JumpingDisabled = 0x1000,
CameraFlag_ThirdPerson = 0x2 PlayerFlags_LookingDisabled = 0x2000,
PlayerFlags_VanityModeDisabled = 0x4000,
PlayerFlags_WeaponDrawingDisabled = 0x8000,
PlayerFlags_SpellDrawingDisabled = 0x10000,
PlayerFlags_ThirdPerson = 0x20000,
PlayerFlags_TeleportingDisabled = 0x40000,
PlayerFlags_LevitationDisabled = 0x80000
}; };
#pragma pack(push) #pragma pack(push)
@ -62,8 +68,7 @@ struct PCDT
struct PNAM struct PNAM
{ {
short mDrawState; // DrawState int mPlayerFlags; // controls, camera and draw state
short mCameraFlags; // CameraFlags
unsigned int mLevelProgress; unsigned int mLevelProgress;
float mSkillProgress[27]; // skill progress, non-uniform scaled float mSkillProgress[27]; // skill progress, non-uniform scaled
unsigned char mSkillIncreases[8]; // number of skill increases for each attribute unsigned char mSkillIncreases[8]; // number of skill increases for each attribute

@ -87,6 +87,10 @@ add_executable(openmw-launcher
${UI_HDRS} ${UI_HDRS}
) )
if (WIN32)
INSTALL(TARGETS openmw-launcher RUNTIME DESTINATION ".")
endif (WIN32)
target_link_libraries(openmw-launcher target_link_libraries(openmw-launcher
${SDL2_LIBRARY_ONLY} ${SDL2_LIBRARY_ONLY}
components components

@ -35,14 +35,6 @@ int main(int argc, char *argv[])
// Now we make sure the current dir is set to application path // Now we make sure the current dir is set to application path
QDir dir(QCoreApplication::applicationDirPath()); QDir dir(QCoreApplication::applicationDirPath());
#ifdef Q_OS_MAC
if (dir.dirName() == "MacOS") {
dir.cdUp();
dir.cdUp();
dir.cdUp();
}
#endif
QDir::setCurrent(dir.absolutePath()); QDir::setCurrent(dir.absolutePath());
Launcher::MainDialog mainWin; Launcher::MainDialog mainWin;

@ -293,6 +293,7 @@ bool Launcher::MainDialog::setupGameSettings()
{ {
mGameSettings.clear(); mGameSettings.clear();
QString localPath = QString::fromUtf8(mCfgMgr.getLocalPath().string().c_str());
QString userPath = QString::fromUtf8(mCfgMgr.getUserConfigPath().string().c_str()); QString userPath = QString::fromUtf8(mCfgMgr.getUserConfigPath().string().c_str());
QString globalPath = QString::fromUtf8(mCfgMgr.getGlobalPath().string().c_str()); QString globalPath = QString::fromUtf8(mCfgMgr.getGlobalPath().string().c_str());
@ -320,13 +321,13 @@ bool Launcher::MainDialog::setupGameSettings()
// Now the rest - priority: user > local > global // Now the rest - priority: user > local > global
QStringList paths; QStringList paths;
paths.append(globalPath + QString("openmw.cfg")); paths.append(globalPath + QString("openmw.cfg"));
paths.append(QString("openmw.cfg")); paths.append(localPath + QString("openmw.cfg"));
paths.append(userPath + QString("openmw.cfg")); paths.append(userPath + QString("openmw.cfg"));
foreach (const QString &path, paths) { foreach (const QString &path2, paths) {
qDebug() << "Loading config file:" << path.toUtf8().constData(); qDebug() << "Loading config file:" << path2.toUtf8().constData();
QFile file(path); file.setFileName(path2);
if (file.exists()) { if (file.exists()) {
if (!file.open(QIODevice::ReadOnly | QIODevice::Text)) { if (!file.open(QIODevice::ReadOnly | QIODevice::Text)) {
cfgError(tr("Error opening OpenMW configuration file"), cfgError(tr("Error opening OpenMW configuration file"),
@ -346,13 +347,13 @@ bool Launcher::MainDialog::setupGameSettings()
QStringList dataDirs; QStringList dataDirs;
// Check if the paths actually contain data files // Check if the paths actually contain data files
foreach (const QString path, mGameSettings.getDataDirs()) { foreach (const QString path3, mGameSettings.getDataDirs()) {
QDir dir(path); QDir dir(path3);
QStringList filters; QStringList filters;
filters << "*.esp" << "*.esm" << "*.omwgame" << "*.omwaddon"; filters << "*.esp" << "*.esm" << "*.omwgame" << "*.omwaddon";
if (!dir.entryList(filters).isEmpty()) if (!dir.entryList(filters).isEmpty())
dataDirs.append(path); dataDirs.append(path3);
} }
if (dataDirs.isEmpty()) if (dataDirs.isEmpty())

@ -22,7 +22,8 @@ target_link_libraries(openmw-iniimporter
if (WIN32) if (WIN32)
target_link_libraries(openmw-iniimporter target_link_libraries(openmw-iniimporter
${Boost_LOCALE_LIBRARY}) ${Boost_LOCALE_LIBRARY})
endif() INSTALL(TARGETS openmw-iniimporter RUNTIME DESTINATION ".")
endif(WIN32)
if (MINGW) if (MINGW)
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -municode") set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -municode")

@ -162,9 +162,15 @@ endif()
include_directories(${CMAKE_CURRENT_BINARY_DIR}) include_directories(${CMAKE_CURRENT_BINARY_DIR})
if(APPLE) if(APPLE)
set (OPENCS_MAC_ICON ${CMAKE_SOURCE_DIR}/files/mac/openmw-cs.icns) set (OPENCS_MAC_ICON "${CMAKE_SOURCE_DIR}/files/mac/openmw-cs.icns")
set (OPENCS_CFG "${OpenMW_BINARY_DIR}/openmw-cs.cfg")
set (OPENCS_DEFAULT_FILTERS_FILE "${OpenMW_BINARY_DIR}/resources/defaultfilters")
set (OPENCS_OPENMW_CFG "${OpenMW_BINARY_DIR}/openmw.cfg")
else() else()
set (OPENCS_MAC_ICON "") set (OPENCS_MAC_ICON "")
set (OPENCS_CFG "")
set (OPENCS_DEFAULT_FILTERS_FILE "")
set (OPENCS_OPENMW_CFG "")
endif(APPLE) endif(APPLE)
add_executable(openmw-cs add_executable(openmw-cs
@ -174,12 +180,23 @@ add_executable(openmw-cs
${OPENCS_MOC_SRC} ${OPENCS_MOC_SRC}
${OPENCS_RES_SRC} ${OPENCS_RES_SRC}
${OPENCS_MAC_ICON} ${OPENCS_MAC_ICON}
${OPENCS_CFG}
${OPENCS_DEFAULT_FILTERS_FILE}
${OPENCS_OPENMW_CFG}
) )
if(APPLE) if(APPLE)
set(OPENCS_BUNDLE_NAME "OpenMW-CS")
set(OPENCS_BUNDLE_RESOURCES_DIR "${OpenMW_BINARY_DIR}/${OPENCS_BUNDLE_NAME}.app/Contents/Resources")
set(OPENMW_MYGUI_FILES_ROOT ${OPENCS_BUNDLE_RESOURCES_DIR})
set(OPENMW_SHADERS_ROOT ${OPENCS_BUNDLE_RESOURCES_DIR})
add_subdirectory(../../files/ ${CMAKE_CURRENT_BINARY_DIR}/files)
set_target_properties(openmw-cs PROPERTIES set_target_properties(openmw-cs PROPERTIES
RUNTIME_OUTPUT_DIRECTORY "${OpenMW_BINARY_DIR}" RUNTIME_OUTPUT_DIRECTORY "${OpenMW_BINARY_DIR}"
OUTPUT_NAME "OpenMW-CS" OUTPUT_NAME ${OPENCS_BUNDLE_NAME}
MACOSX_BUNDLE_ICON_FILE "openmw-cs.icns" MACOSX_BUNDLE_ICON_FILE "openmw-cs.icns"
MACOSX_BUNDLE_BUNDLE_NAME "OpenCS" MACOSX_BUNDLE_BUNDLE_NAME "OpenCS"
MACOSX_BUNDLE_GUI_IDENTIFIER "org.openmw.opencs" MACOSX_BUNDLE_GUI_IDENTIFIER "org.openmw.opencs"
@ -190,6 +207,16 @@ if(APPLE)
set_source_files_properties(${OPENCS_MAC_ICON} PROPERTIES set_source_files_properties(${OPENCS_MAC_ICON} PROPERTIES
MACOSX_PACKAGE_LOCATION Resources) MACOSX_PACKAGE_LOCATION Resources)
set_source_files_properties(${OPENCS_CFG} PROPERTIES
MACOSX_PACKAGE_LOCATION Resources)
set_source_files_properties(${OPENCS_DEFAULT_FILTERS_FILE} PROPERTIES
MACOSX_PACKAGE_LOCATION Resources/resources)
set_source_files_properties(${OPENCS_OPENMW_CFG} PROPERTIES
MACOSX_PACKAGE_LOCATION Resources)
add_custom_command(TARGET openmw-cs
POST_BUILD
COMMAND cp "${OpenMW_BINARY_DIR}/resources/version" "${OPENCS_BUNDLE_RESOURCES_DIR}/resources")
endif(APPLE) endif(APPLE)
target_link_libraries(openmw-cs target_link_libraries(openmw-cs
@ -223,9 +250,18 @@ endif()
if (WIN32) if (WIN32)
target_link_libraries(openmw-cs ${Boost_LOCALE_LIBRARY}) target_link_libraries(openmw-cs ${Boost_LOCALE_LIBRARY})
INSTALL(TARGETS openmw-cs RUNTIME DESTINATION ".")
INSTALL(FILES "${OpenMW_BINARY_DIR}/openmw-cs.cfg" DESTINATION ".")
endif() endif()
if (MSVC)
# Debug version needs increased number of sections beyond 2^16
if (CMAKE_CL_64)
set (CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} /bigobj")
endif (CMAKE_CL_64)
endif (MSVC)
if(APPLE) if(APPLE)
INSTALL(TARGETS openmw-cs BUNDLE DESTINATION OpenMW COMPONENT BUNDLE) INSTALL(TARGETS openmw-cs BUNDLE DESTINATION "." COMPONENT BUNDLE)
endif() endif()

@ -62,11 +62,6 @@ int main(int argc, char *argv[])
#ifdef Q_OS_MAC #ifdef Q_OS_MAC
QDir dir(QCoreApplication::applicationDirPath()); QDir dir(QCoreApplication::applicationDirPath());
if (dir.dirName() == "MacOS") {
dir.cdUp();
dir.cdUp();
dir.cdUp();
}
QDir::setCurrent(dir.absolutePath()); QDir::setCurrent(dir.absolutePath());
#endif #endif

@ -184,7 +184,7 @@ void CSMTools::MergeLandTexturesStage::perform (int stage, CSMDoc::Messages& mes
CSMWorld::LandTexture texture = CSMWorld::LandTexture texture =
mState.mSource.getData().getLandTextures().getRecord (index).get(); mState.mSource.getData().getLandTextures().getRecord (index).get();
std::ostringstream stream; stream.clear();
stream << mNext->second-1 << "_0"; stream << mNext->second-1 << "_0";
texture.mIndex = mNext->second-1; texture.mIndex = mNext->second-1;

@ -1627,264 +1627,264 @@ const char * CSMWorld::DefaultGmsts::OptionalStrings[CSMWorld::DefaultGmsts::Opt
const float CSMWorld::DefaultGmsts::FloatsDefaultValues[CSMWorld::DefaultGmsts::FloatCount] = const float CSMWorld::DefaultGmsts::FloatsDefaultValues[CSMWorld::DefaultGmsts::FloatCount] =
{ {
0.3, // fAIFleeFleeMult 0.3f, // fAIFleeFleeMult
7.0, // fAIFleeHealthMult 7.0f, // fAIFleeHealthMult
3.0, // fAIMagicSpellMult 3.0f, // fAIMagicSpellMult
1.0, // fAIMeleeArmorMult 1.0f, // fAIMeleeArmorMult
1.0, // fAIMeleeSummWeaponMult 1.0f, // fAIMeleeSummWeaponMult
2.0, // fAIMeleeWeaponMult 2.0f, // fAIMeleeWeaponMult
5.0, // fAIRangeMagicSpellMult 5.0f, // fAIRangeMagicSpellMult
5.0, // fAIRangeMeleeWeaponMult 5.0f, // fAIRangeMeleeWeaponMult
2000.0, // fAlarmRadius 2000.0f, // fAlarmRadius
1.0, // fAthleticsRunBonus 1.0f, // fAthleticsRunBonus
40.0, // fAudioDefaultMaxDistance 40.0f, // fAudioDefaultMaxDistance
5.0, // fAudioDefaultMinDistance 5.0f, // fAudioDefaultMinDistance
50.0, // fAudioMaxDistanceMult 50.0f, // fAudioMaxDistanceMult
20.0, // fAudioMinDistanceMult 20.0f, // fAudioMinDistanceMult
60.0, // fAudioVoiceDefaultMaxDistance 60.0f, // fAudioVoiceDefaultMaxDistance
10.0, // fAudioVoiceDefaultMinDistance 10.0f, // fAudioVoiceDefaultMinDistance
50.0, // fAutoPCSpellChance 50.0f, // fAutoPCSpellChance
80.0, // fAutoSpellChance 80.0f, // fAutoSpellChance
50.0, // fBargainOfferBase 50.0f, // fBargainOfferBase
-4.0, // fBargainOfferMulti -4.0f, // fBargainOfferMulti
24.0, // fBarterGoldResetDelay 24.0f, // fBarterGoldResetDelay
1.75, // fBaseRunMultiplier 1.75f, // fBaseRunMultiplier
1.25, // fBlockStillBonus 1.25f, // fBlockStillBonus
150.0, // fBribe1000Mod 150.0f, // fBribe1000Mod
75.0, // fBribe100Mod 75.0f, // fBribe100Mod
35.0, // fBribe10Mod 35.0f, // fBribe10Mod
60.0, // fCombatAngleXY 60.0f, // fCombatAngleXY
60.0, // fCombatAngleZ 60.0f, // fCombatAngleZ
0.25, // fCombatArmorMinMult 0.25f, // fCombatArmorMinMult
-90.0, // fCombatBlockLeftAngle -90.0f, // fCombatBlockLeftAngle
30.0, // fCombatBlockRightAngle 30.0f, // fCombatBlockRightAngle
4.0, // fCombatCriticalStrikeMult 4.0f, // fCombatCriticalStrikeMult
0.1, // fCombatDelayCreature 0.1f, // fCombatDelayCreature
0.1, // fCombatDelayNPC 0.1f, // fCombatDelayNPC
128.0, // fCombatDistance 128.0f, // fCombatDistance
0.3, // fCombatDistanceWerewolfMod 0.3f, // fCombatDistanceWerewolfMod
30.0, // fCombatForceSideAngle 30.0f, // fCombatForceSideAngle
0.2, // fCombatInvisoMult 0.2f, // fCombatInvisoMult
1.5, // fCombatKODamageMult 1.5f, // fCombatKODamageMult
45.0, // fCombatTorsoSideAngle 45.0f, // fCombatTorsoSideAngle
0.3, // fCombatTorsoStartPercent 0.3f, // fCombatTorsoStartPercent
0.8, // fCombatTorsoStopPercent 0.8f, // fCombatTorsoStopPercent
15.0, // fConstantEffectMult 15.0f, // fConstantEffectMult
72.0, // fCorpseClearDelay 72.0f, // fCorpseClearDelay
72.0, // fCorpseRespawnDelay 72.0f, // fCorpseRespawnDelay
0.5, // fCrimeGoldDiscountMult 0.5f, // fCrimeGoldDiscountMult
0.9, // fCrimeGoldTurnInMult 0.9f, // fCrimeGoldTurnInMult
1.0, // fCrimeStealing 1.0f, // fCrimeStealing
0.5, // fDamageStrengthBase 0.5f, // fDamageStrengthBase
0.1, // fDamageStrengthMult 0.1f, // fDamageStrengthMult
5.0, // fDifficultyMult 5.0f, // fDifficultyMult
2.5, // fDiseaseXferChance 2.5f, // fDiseaseXferChance
-10.0, // fDispAttacking -10.0f, // fDispAttacking
-1.0, // fDispBargainFailMod -1.0f, // fDispBargainFailMod
1.0, // fDispBargainSuccessMod 1.0f, // fDispBargainSuccessMod
0.0, // fDispCrimeMod 0.0f, // fDispCrimeMod
-10.0, // fDispDiseaseMod -10.0f, // fDispDiseaseMod
3.0, // fDispFactionMod 3.0f, // fDispFactionMod
1.0, // fDispFactionRankBase 1.0f, // fDispFactionRankBase
0.5, // fDispFactionRankMult 0.5f, // fDispFactionRankMult
1.0, // fDispositionMod 1.0f, // fDispositionMod
50.0, // fDispPersonalityBase 50.0f, // fDispPersonalityBase
0.5, // fDispPersonalityMult 0.5f, // fDispPersonalityMult
-25.0, // fDispPickPocketMod -25.0f, // fDispPickPocketMod
5.0, // fDispRaceMod 5.0f, // fDispRaceMod
-0.5, // fDispStealing -0.5f, // fDispStealing
-5.0, // fDispWeaponDrawn -5.0f, // fDispWeaponDrawn
0.5, // fEffectCostMult 0.5f, // fEffectCostMult
0.1, // fElementalShieldMult 0.1f, // fElementalShieldMult
3.0, // fEnchantmentChanceMult 3.0f, // fEnchantmentChanceMult
0.5, // fEnchantmentConstantChanceMult 0.5f, // fEnchantmentConstantChanceMult
100.0, // fEnchantmentConstantDurationMult 100.0f, // fEnchantmentConstantDurationMult
0.1, // fEnchantmentMult 0.1f, // fEnchantmentMult
1000.0, // fEnchantmentValueMult 1000.0f, // fEnchantmentValueMult
0.3, // fEncumberedMoveEffect 0.3f, // fEncumberedMoveEffect
5.0, // fEncumbranceStrMult 5.0f, // fEncumbranceStrMult
0.04, // fEndFatigueMult 0.04f, // fEndFatigueMult
0.25, // fFallAcroBase 0.25f, // fFallAcroBase
0.01, // fFallAcroMult 0.01f, // fFallAcroMult
400.0, // fFallDamageDistanceMin 400.0f, // fFallDamageDistanceMin
0.0, // fFallDistanceBase 0.0f, // fFallDistanceBase
0.07, // fFallDistanceMult 0.07f, // fFallDistanceMult
2.0, // fFatigueAttackBase 2.0f, // fFatigueAttackBase
0.0, // fFatigueAttackMult 0.0f, // fFatigueAttackMult
1.25, // fFatigueBase 1.25f, // fFatigueBase
4.0, // fFatigueBlockBase 4.0f, // fFatigueBlockBase
0.0, // fFatigueBlockMult 0.0f, // fFatigueBlockMult
5.0, // fFatigueJumpBase 5.0f, // fFatigueJumpBase
0.0, // fFatigueJumpMult 0.0f, // fFatigueJumpMult
0.5, // fFatigueMult 0.5f, // fFatigueMult
2.5, // fFatigueReturnBase 2.5f, // fFatigueReturnBase
0.02, // fFatigueReturnMult 0.02f, // fFatigueReturnMult
5.0, // fFatigueRunBase 5.0f, // fFatigueRunBase
2.0, // fFatigueRunMult 2.0f, // fFatigueRunMult
1.5, // fFatigueSneakBase 1.5f, // fFatigueSneakBase
1.5, // fFatigueSneakMult 1.5f, // fFatigueSneakMult
0.0, // fFatigueSpellBase 0.0f, // fFatigueSpellBase
0.0, // fFatigueSpellCostMult 0.0f, // fFatigueSpellCostMult
0.0, // fFatigueSpellMult 0.0f, // fFatigueSpellMult
7.0, // fFatigueSwimRunBase 7.0f, // fFatigueSwimRunBase
0.0, // fFatigueSwimRunMult 0.0f, // fFatigueSwimRunMult
2.5, // fFatigueSwimWalkBase 2.5f, // fFatigueSwimWalkBase
0.0, // fFatigueSwimWalkMult 0.0f, // fFatigueSwimWalkMult
0.2, // fFightDispMult 0.2f, // fFightDispMult
0.005, // fFightDistanceMultiplier 0.005f, // fFightDistanceMultiplier
50.0, // fFightStealing 50.0f, // fFightStealing
3000.0, // fFleeDistance 3000.0f, // fFleeDistance
512.0, // fGreetDistanceReset 512.0f, // fGreetDistanceReset
0.1, // fHandtoHandHealthPer 0.1f, // fHandtoHandHealthPer
1.0, // fHandToHandReach 1.0f, // fHandToHandReach
0.5, // fHoldBreathEndMult 0.5f, // fHoldBreathEndMult
20.0, // fHoldBreathTime 20.0f, // fHoldBreathTime
0.75, // fIdleChanceMultiplier 0.75f, // fIdleChanceMultiplier
1.0, // fIngredientMult 1.0f, // fIngredientMult
0.5, // fInteriorHeadTrackMult 0.5f, // fInteriorHeadTrackMult
128.0, // fJumpAcrobaticsBase 128.0f, // fJumpAcrobaticsBase
4.0, // fJumpAcroMultiplier 4.0f, // fJumpAcroMultiplier
0.5, // fJumpEncumbranceBase 0.5f, // fJumpEncumbranceBase
1.0, // fJumpEncumbranceMultiplier 1.0f, // fJumpEncumbranceMultiplier
0.5, // fJumpMoveBase 0.5f, // fJumpMoveBase
0.5, // fJumpMoveMult 0.5f, // fJumpMoveMult
1.0, // fJumpRunMultiplier 1.0f, // fJumpRunMultiplier
0.5, // fKnockDownMult 0.5f, // fKnockDownMult
5.0, // fLevelMod 5.0f, // fLevelMod
0.1, // fLevelUpHealthEndMult 0.1f, // fLevelUpHealthEndMult
0.6, // fLightMaxMod 0.6f, // fLightMaxMod
10.0, // fLuckMod 10.0f, // fLuckMod
10.0, // fMagesGuildTravel 10.0f, // fMagesGuildTravel
1.5, // fMagicCreatureCastDelay 1.5f, // fMagicCreatureCastDelay
0.0167, // fMagicDetectRefreshRate 0.0167f, // fMagicDetectRefreshRate
1.0, // fMagicItemConstantMult 1.0f, // fMagicItemConstantMult
1.0, // fMagicItemCostMult 1.0f, // fMagicItemCostMult
1.0, // fMagicItemOnceMult 1.0f, // fMagicItemOnceMult
1.0, // fMagicItemPriceMult 1.0f, // fMagicItemPriceMult
0.05, // fMagicItemRechargePerSecond 0.05f, // fMagicItemRechargePerSecond
1.0, // fMagicItemStrikeMult 1.0f, // fMagicItemStrikeMult
1.0, // fMagicItemUsedMult 1.0f, // fMagicItemUsedMult
3.0, // fMagicStartIconBlink 3.0f, // fMagicStartIconBlink
0.5, // fMagicSunBlockedMult 0.5f, // fMagicSunBlockedMult
0.75, // fMajorSkillBonus 0.75f, // fMajorSkillBonus
300.0, // fMaxFlySpeed 300.0f, // fMaxFlySpeed
0.5, // fMaxHandToHandMult 0.5f, // fMaxHandToHandMult
400.0, // fMaxHeadTrackDistance 400.0f, // fMaxHeadTrackDistance
200.0, // fMaxWalkSpeed 200.0f, // fMaxWalkSpeed
300.0, // fMaxWalkSpeedCreature 300.0f, // fMaxWalkSpeedCreature
0.9, // fMedMaxMod 0.9f, // fMedMaxMod
0.1, // fMessageTimePerChar 0.1f, // fMessageTimePerChar
5.0, // fMinFlySpeed 5.0f, // fMinFlySpeed
0.1, // fMinHandToHandMult 0.1f, // fMinHandToHandMult
1.0, // fMinorSkillBonus 1.0f, // fMinorSkillBonus
100.0, // fMinWalkSpeed 100.0f, // fMinWalkSpeed
5.0, // fMinWalkSpeedCreature 5.0f, // fMinWalkSpeedCreature
1.25, // fMiscSkillBonus 1.25f, // fMiscSkillBonus
2.0, // fNPCbaseMagickaMult 2.0f, // fNPCbaseMagickaMult
0.5, // fNPCHealthBarFade 0.5f, // fNPCHealthBarFade
3.0, // fNPCHealthBarTime 3.0f, // fNPCHealthBarTime
1.0, // fPCbaseMagickaMult 1.0f, // fPCbaseMagickaMult
0.3, // fPerDieRollMult 0.3f, // fPerDieRollMult
5.0, // fPersonalityMod 5.0f, // fPersonalityMod
1.0, // fPerTempMult 1.0f, // fPerTempMult
-1.0, // fPickLockMult -1.0f, // fPickLockMult
0.3, // fPickPocketMod 0.3f, // fPickPocketMod
20.0, // fPotionMinUsefulDuration 20.0f, // fPotionMinUsefulDuration
0.5, // fPotionStrengthMult 0.5f, // fPotionStrengthMult
0.5, // fPotionT1DurMult 0.5f, // fPotionT1DurMult
1.5, // fPotionT1MagMult 1.5f, // fPotionT1MagMult
20.0, // fPotionT4BaseStrengthMult 20.0f, // fPotionT4BaseStrengthMult
12.0, // fPotionT4EquipStrengthMult 12.0f, // fPotionT4EquipStrengthMult
3000.0, // fProjectileMaxSpeed 3000.0f, // fProjectileMaxSpeed
400.0, // fProjectileMinSpeed 400.0f, // fProjectileMinSpeed
25.0, // fProjectileThrownStoreChance 25.0f, // fProjectileThrownStoreChance
3.0, // fRepairAmountMult 3.0f, // fRepairAmountMult
1.0, // fRepairMult 1.0f, // fRepairMult
1.0, // fReputationMod 1.0f, // fReputationMod
0.15, // fRestMagicMult 0.15f, // fRestMagicMult
0.0, // fSeriousWoundMult 0.0f, // fSeriousWoundMult
0.25, // fSleepRandMod 0.25f, // fSleepRandMod
0.3, // fSleepRestMod 0.3f, // fSleepRestMod
-1.0, // fSneakBootMult -1.0f, // fSneakBootMult
0.5, // fSneakDistanceBase 0.5f, // fSneakDistanceBase
0.002, // fSneakDistanceMultiplier 0.002f, // fSneakDistanceMultiplier
0.5, // fSneakNoViewMult 0.5f, // fSneakNoViewMult
1.0, // fSneakSkillMult 1.0f, // fSneakSkillMult
0.75, // fSneakSpeedMultiplier 0.75f, // fSneakSpeedMultiplier
1.0, // fSneakUseDelay 1.0f, // fSneakUseDelay
500.0, // fSneakUseDist 500.0f, // fSneakUseDist
1.5, // fSneakViewMult 1.5f, // fSneakViewMult
3.0, // fSoulGemMult 3.0f, // fSoulGemMult
0.8, // fSpecialSkillBonus 0.8f, // fSpecialSkillBonus
7.0, // fSpellMakingValueMult 7.0f, // fSpellMakingValueMult
2.0, // fSpellPriceMult 2.0f, // fSpellPriceMult
10.0, // fSpellValueMult 10.0f, // fSpellValueMult
0.25, // fStromWalkMult 0.25f, // fStromWalkMult
0.7, // fStromWindSpeed 0.7f, // fStromWindSpeed
3.0, // fSuffocationDamage 3.0f, // fSuffocationDamage
0.9, // fSwimHeightScale 0.9f, // fSwimHeightScale
0.1, // fSwimRunAthleticsMult 0.1f, // fSwimRunAthleticsMult
0.5, // fSwimRunBase 0.5f, // fSwimRunBase
0.02, // fSwimWalkAthleticsMult 0.02f, // fSwimWalkAthleticsMult
0.5, // fSwimWalkBase 0.5f, // fSwimWalkBase
1.0, // fSwingBlockBase 1.0f, // fSwingBlockBase
1.0, // fSwingBlockMult 1.0f, // fSwingBlockMult
1000.0, // fTargetSpellMaxSpeed 1000.0f, // fTargetSpellMaxSpeed
1000.0, // fThrownWeaponMaxSpeed 1000.0f, // fThrownWeaponMaxSpeed
300.0, // fThrownWeaponMinSpeed 300.0f, // fThrownWeaponMinSpeed
0.0, // fTrapCostMult 0.0f, // fTrapCostMult
4000.0, // fTravelMult 4000.0f, // fTravelMult
16000.0,// fTravelTimeMult 16000.0f,// fTravelTimeMult
0.1, // fUnarmoredBase1 0.1f, // fUnarmoredBase1
0.065, // fUnarmoredBase2 0.065f, // fUnarmoredBase2
30.0, // fVanityDelay 30.0f, // fVanityDelay
10.0, // fVoiceIdleOdds 10.0f, // fVoiceIdleOdds
0.0, // fWaterReflectUpdateAlways 0.0f, // fWaterReflectUpdateAlways
10.0, // fWaterReflectUpdateSeldom 10.0f, // fWaterReflectUpdateSeldom
0.1, // fWeaponDamageMult 0.1f, // fWeaponDamageMult
1.0, // fWeaponFatigueBlockMult 1.0f, // fWeaponFatigueBlockMult
0.25, // fWeaponFatigueMult 0.25f, // fWeaponFatigueMult
150.0, // fWereWolfAcrobatics 150.0f, // fWereWolfAcrobatics
150.0, // fWereWolfAgility 150.0f, // fWereWolfAgility
1.0, // fWereWolfAlchemy 1.0f, // fWereWolfAlchemy
1.0, // fWereWolfAlteration 1.0f, // fWereWolfAlteration
1.0, // fWereWolfArmorer 1.0f, // fWereWolfArmorer
150.0, // fWereWolfAthletics 150.0f, // fWereWolfAthletics
1.0, // fWereWolfAxe 1.0f, // fWereWolfAxe
1.0, // fWereWolfBlock 1.0f, // fWereWolfBlock
1.0, // fWereWolfBluntWeapon 1.0f, // fWereWolfBluntWeapon
1.0, // fWereWolfConjuration 1.0f, // fWereWolfConjuration
1.0, // fWereWolfDestruction 1.0f, // fWereWolfDestruction
1.0, // fWereWolfEnchant 1.0f, // fWereWolfEnchant
150.0, // fWereWolfEndurance 150.0f, // fWereWolfEndurance
400.0, // fWereWolfFatigue 400.0f, // fWereWolfFatigue
100.0, // fWereWolfHandtoHand 100.0f, // fWereWolfHandtoHand
2.0, // fWereWolfHealth 2.0f, // fWereWolfHealth
1.0, // fWereWolfHeavyArmor 1.0f, // fWereWolfHeavyArmor
1.0, // fWereWolfIllusion 1.0f, // fWereWolfIllusion
1.0, // fWereWolfIntellegence 1.0f, // fWereWolfIntellegence
1.0, // fWereWolfLightArmor 1.0f, // fWereWolfLightArmor
1.0, // fWereWolfLongBlade 1.0f, // fWereWolfLongBlade
1.0, // fWereWolfLuck 1.0f, // fWereWolfLuck
100.0, // fWereWolfMagicka 100.0f, // fWereWolfMagicka
1.0, // fWereWolfMarksman 1.0f, // fWereWolfMarksman
1.0, // fWereWolfMediumArmor 1.0f, // fWereWolfMediumArmor
1.0, // fWereWolfMerchantile 1.0f, // fWereWolfMerchantile
1.0, // fWereWolfMysticism 1.0f, // fWereWolfMysticism
1.0, // fWereWolfPersonality 1.0f, // fWereWolfPersonality
1.0, // fWereWolfRestoration 1.0f, // fWereWolfRestoration
1.5, // fWereWolfRunMult 1.5f, // fWereWolfRunMult
1.0, // fWereWolfSecurity 1.0f, // fWereWolfSecurity
1.0, // fWereWolfShortBlade 1.0f, // fWereWolfShortBlade
1.5, // fWereWolfSilverWeaponDamageMult 1.5f, // fWereWolfSilverWeaponDamageMult
1.0, // fWereWolfSneak 1.0f, // fWereWolfSneak
1.0, // fWereWolfSpear 1.0f, // fWereWolfSpear
1.0, // fWereWolfSpeechcraft 1.0f, // fWereWolfSpeechcraft
150.0, // fWereWolfSpeed 150.0f, // fWereWolfSpeed
150.0, // fWereWolfStrength 150.0f, // fWereWolfStrength
100.0, // fWereWolfUnarmored 100.0f, // fWereWolfUnarmored
1.0, // fWereWolfWillPower 1.0f, // fWereWolfWillPower
15.0 // fWortChanceValue 15.0f // fWortChanceValue
}; };
const int CSMWorld::DefaultGmsts::IntsDefaultValues[CSMWorld::DefaultGmsts::IntCount] = const int CSMWorld::DefaultGmsts::IntsDefaultValues[CSMWorld::DefaultGmsts::IntCount] =

@ -191,7 +191,7 @@ void CSMWorld::IdTable::setRecord (const std::string& id, const RecordBase& reco
if (index==-1) if (index==-1)
{ {
int index = mIdCollection->getAppendIndex (id, type); index = mIdCollection->getAppendIndex (id, type);
beginInsertRows (QModelIndex(), index, index); beginInsertRows (QModelIndex(), index, index);

@ -63,7 +63,7 @@ void CSMWorld::RefCollection::load (ESM::ESMReader& reader, int cellIndex, bool
std::cerr << "Position: #" << index.first << " " << index.second std::cerr << "Position: #" << index.first << " " << index.second
<<", Target #"<< mref.mTarget[0] << " " << mref.mTarget[1] << std::endl; <<", Target #"<< mref.mTarget[0] << " " << mref.mTarget[1] << std::endl;
std::ostringstream stream; stream.clear();
stream << "#" << mref.mTarget[0] << " " << mref.mTarget[1]; stream << "#" << mref.mTarget[0] << " " << mref.mTarget[1];
ref.mCell = stream.str(); // overwrite ref.mCell = stream.str(); // overwrite
} }

@ -42,7 +42,7 @@ add_openmw_dir (mwgui
itemmodel containeritemmodel inventoryitemmodel sortfilteritemmodel itemview itemmodel containeritemmodel inventoryitemmodel sortfilteritemmodel itemview
tradeitemmodel companionitemmodel pickpocketitemmodel controllers savegamedialog tradeitemmodel companionitemmodel pickpocketitemmodel controllers savegamedialog
recharge mode videowidget backgroundimage itemwidget screenfader debugwindow spellmodel spellview recharge mode videowidget backgroundimage itemwidget screenfader debugwindow spellmodel spellview
draganddrop timeadvancer jailscreen draganddrop timeadvancer jailscreen itemchargeview
) )
add_openmw_dir (mwdialogue add_openmw_dir (mwdialogue
@ -179,6 +179,21 @@ target_link_libraries(openmw ${CMAKE_THREAD_LIBS_INIT})
endif() endif()
if(APPLE) if(APPLE)
set(BUNDLE_RESOURCES_DIR "${APP_BUNDLE_DIR}/Contents/Resources")
set(OPENMW_MYGUI_FILES_ROOT ${BUNDLE_RESOURCES_DIR})
set(OPENMW_SHADERS_ROOT ${BUNDLE_RESOURCES_DIR})
add_subdirectory(../../files/ ${CMAKE_CURRENT_BINARY_DIR}/files)
configure_file("${OpenMW_BINARY_DIR}/settings-default.cfg" ${BUNDLE_RESOURCES_DIR} COPYONLY)
configure_file("${OpenMW_BINARY_DIR}/openmw.cfg" ${BUNDLE_RESOURCES_DIR} COPYONLY)
configure_file("${OpenMW_BINARY_DIR}/gamecontrollerdb.txt" ${BUNDLE_RESOURCES_DIR} COPYONLY)
add_custom_command(TARGET openmw
POST_BUILD
COMMAND cp "${OpenMW_BINARY_DIR}/resources/version" "${BUNDLE_RESOURCES_DIR}/resources")
find_library(COCOA_FRAMEWORK Cocoa) find_library(COCOA_FRAMEWORK Cocoa)
find_library(IOKIT_FRAMEWORK IOKit) find_library(IOKIT_FRAMEWORK IOKit)
target_link_libraries(openmw ${COCOA_FRAMEWORK} ${IOKIT_FRAMEWORK}) target_link_libraries(openmw ${COCOA_FRAMEWORK} ${IOKIT_FRAMEWORK})
@ -186,7 +201,7 @@ if(APPLE)
if (FFmpeg_FOUND) if (FFmpeg_FOUND)
find_library(COREVIDEO_FRAMEWORK CoreVideo) find_library(COREVIDEO_FRAMEWORK CoreVideo)
find_library(VDA_FRAMEWORK VideoDecodeAcceleration) find_library(VDA_FRAMEWORK VideoDecodeAcceleration)
target_link_libraries(openmw ${COREVIDEO_FRAMEWORK} ${VDA_FRAMEWORK}) target_link_libraries(openmw z ${COREVIDEO_FRAMEWORK} ${VDA_FRAMEWORK})
endif() endif()
endif(APPLE) endif(APPLE)
@ -202,3 +217,8 @@ if (MSVC)
endif (CMAKE_CL_64) endif (CMAKE_CL_64)
add_definitions("-D_USE_MATH_DEFINES") add_definitions("-D_USE_MATH_DEFINES")
endif (MSVC) endif (MSVC)
if (WIN32)
INSTALL(TARGETS openmw RUNTIME DESTINATION ".")
endif (WIN32)

@ -493,7 +493,7 @@ void OMW::Engine::prepareEngine (Settings::Manager & settings)
mEnvironment.setWindowManager (window); mEnvironment.setWindowManager (window);
// Create sound system // Create sound system
mEnvironment.setSoundManager (new MWSound::SoundManager(mVFS.get(), mUseSound)); mEnvironment.setSoundManager (new MWSound::SoundManager(mVFS.get(), mFallbackMap, mUseSound));
if (!mSkipMenu) if (!mSkipMenu)
{ {

@ -352,9 +352,8 @@ int main(int argc, char**argv)
#endif #endif
#ifdef __APPLE__ #ifdef __APPLE__
// FIXME: set current dir to bundle path boost::filesystem::path binary_path = boost::filesystem::system_complete(boost::filesystem::path(argv[0]));
//boost::filesystem::path bundlePath = boost::filesystem::path(Ogre::macBundlePath()).parent_path(); boost::filesystem::current_path(binary_path.parent_path());
//boost::filesystem::current_path(bundlePath);
#endif #endif
engine.reset(new OMW::Engine(cfgMgr)); engine.reset(new OMW::Engine(cfgMgr));

@ -5,6 +5,19 @@
#include <set> #include <set>
#include <vector> #include <vector>
#include <stdint.h>
namespace Loading
{
class Listener;
}
namespace ESM
{
class ESMReader;
class ESMWriter;
}
namespace MWBase namespace MWBase
{ {
/// \brief Interface for input manager (implemented in MWInput) /// \brief Interface for input manager (implemented in MWInput)
@ -56,6 +69,10 @@ namespace MWBase
/// Returns if the last used input device was a joystick or a keyboard /// Returns if the last used input device was a joystick or a keyboard
/// @return true if joystick, false otherwise /// @return true if joystick, false otherwise
virtual bool joystickLastUsed() = 0; virtual bool joystickLastUsed() = 0;
virtual int countSavedGameRecords() const = 0;
virtual void write(ESM::ESMWriter& writer, Loading::Listener& progress) = 0;
virtual void readRecord(ESM::ESMReader& reader, uint32_t type) = 0;
}; };
} }

@ -548,7 +548,7 @@ namespace MWBase
/// Resets all actors in the current active cells to their original location within that cell. /// Resets all actors in the current active cells to their original location within that cell.
virtual void resetActors() = 0; virtual void resetActors() = 0;
virtual bool isWalkingOnWater (const MWWorld::ConstPtr& actor) = 0; virtual bool isWalkingOnWater (const MWWorld::ConstPtr& actor) const = 0;
/// Return a vector aiming the actor's weapon towards a target. /// Return a vector aiming the actor's weapon towards a target.
/// @note The length of the vector is the distance between actor and target. /// @note The length of the vector is the distance between actor and target.
@ -560,6 +560,12 @@ namespace MWBase
virtual void removeContainerScripts(const MWWorld::Ptr& reference) = 0; virtual void removeContainerScripts(const MWWorld::Ptr& reference) = 0;
virtual bool isPlayerInJail() const = 0; virtual bool isPlayerInJail() const = 0;
/// Return terrain height at \a worldPos position.
virtual float getTerrainHeightAt(const osg::Vec3f& worldPos) const = 0;
/// Return physical or rendering half extents of the given actor.
virtual osg::Vec3f getHalfExtents(const MWWorld::ConstPtr& actor, bool rendering=false) const = 0;
}; };
} }

@ -118,9 +118,9 @@ namespace MWClass
} }
const MWWorld::ESMStore& store = MWBase::Environment::get().getWorld()->getStore(); const MWWorld::ESMStore& store = MWBase::Environment::get().getWorld()->getStore();
MWWorld::ManualRef ref(store, id); MWWorld::ManualRef manualRef(store, id);
ref.getPtr().getCellRef().setPosition(ptr.getCellRef().getPosition()); manualRef.getPtr().getCellRef().setPosition(ptr.getCellRef().getPosition());
MWWorld::Ptr placed = MWBase::Environment::get().getWorld()->placeObject(ref.getPtr(), ptr.getCell() , ptr.getCellRef().getPosition()); MWWorld::Ptr placed = MWBase::Environment::get().getWorld()->placeObject(manualRef.getPtr(), ptr.getCell() , ptr.getCellRef().getPosition());
customData.mSpawnActorId = placed.getClass().getCreatureStats(placed).getActorId(); customData.mSpawnActorId = placed.getClass().getCreatureStats(placed).getActorId();
customData.mSpawn = false; customData.mSpawn = false;
} }

@ -200,15 +200,15 @@ namespace MWGui
std::set<MWMechanics::EffectKey> effectIds = mAlchemy->listEffects(); std::set<MWMechanics::EffectKey> effectIds = mAlchemy->listEffects();
Widgets::SpellEffectList list; Widgets::SpellEffectList list;
unsigned int effectIndex=0; unsigned int effectIndex=0;
for (std::set<MWMechanics::EffectKey>::iterator it = effectIds.begin(); it != effectIds.end(); ++it) for (std::set<MWMechanics::EffectKey>::iterator it2 = effectIds.begin(); it2 != effectIds.end(); ++it2)
{ {
Widgets::SpellEffectParams params; Widgets::SpellEffectParams params;
params.mEffectID = it->mId; params.mEffectID = it2->mId;
const ESM::MagicEffect* magicEffect = MWBase::Environment::get().getWorld()->getStore().get<ESM::MagicEffect>().find(it->mId); const ESM::MagicEffect* magicEffect = MWBase::Environment::get().getWorld()->getStore().get<ESM::MagicEffect>().find(it2->mId);
if (magicEffect->mData.mFlags & ESM::MagicEffect::TargetSkill) if (magicEffect->mData.mFlags & ESM::MagicEffect::TargetSkill)
params.mSkill = it->mArg; params.mSkill = it2->mArg;
else if (magicEffect->mData.mFlags & ESM::MagicEffect::TargetAttribute) else if (magicEffect->mData.mFlags & ESM::MagicEffect::TargetAttribute)
params.mAttribute = it->mArg; params.mAttribute = it2->mArg;
params.mIsConstant = true; params.mIsConstant = true;
params.mNoTarget = true; params.mNoTarget = true;

@ -226,7 +226,7 @@ namespace MWGui
coord.top += lineHeight; coord.top += lineHeight;
end = categories[category].spells.end(); end = categories[category].spells.end();
for (std::vector<std::string>::const_iterator it = categories[category].spells.begin(); it != end; ++it) for (it = categories[category].spells.begin(); it != end; ++it)
{ {
const std::string &spellId = *it; const std::string &spellId = *it;
spellWidget = mSpellArea->createWidget<Widgets::MWSpell>("MW_StatName", coord, MyGUI::Align::Default, std::string("Spell") + MyGUI::utility::toString(i)); spellWidget = mSpellArea->createWidget<Widgets::MWSpell>("MW_StatName", coord, MyGUI::Align::Default, std::string("Spell") + MyGUI::utility::toString(i));

@ -132,6 +132,12 @@ namespace MWGui
mReviewDialog->configureSkills(major, minor); mReviewDialog->configureSkills(major, minor);
} }
void CharacterCreation::onFrame(float duration)
{
if (mReviewDialog)
mReviewDialog->onFrame(duration);
}
void CharacterCreation::spawnDialog(const char id) void CharacterCreation::spawnDialog(const char id)
{ {
try try

@ -50,6 +50,8 @@ namespace MWGui
void setValue(const ESM::Skill::SkillEnum parSkill, const MWMechanics::SkillValue& value); void setValue(const ESM::Skill::SkillEnum parSkill, const MWMechanics::SkillValue& value);
void configureSkills (const SkillList& major, const SkillList& minor); void configureSkills (const SkillList& major, const SkillList& minor);
void onFrame(float duration);
private: private:
osg::Group* mParent; osg::Group* mParent;
Resource::ResourceSystem* mResourceSystem; Resource::ResourceSystem* mResourceSystem;

@ -85,8 +85,8 @@ void InventoryItemModel::update()
if (mActor.getClass().hasInventoryStore(mActor)) if (mActor.getClass().hasInventoryStore(mActor))
{ {
MWWorld::InventoryStore& store = mActor.getClass().getInventoryStore(mActor); MWWorld::InventoryStore& invStore = mActor.getClass().getInventoryStore(mActor);
if (store.isEquipped(newItem.mBase)) if (invStore.isEquipped(newItem.mBase))
newItem.mType = ItemStack::Type_Equipped; newItem.mType = ItemStack::Type_Equipped;
} }

@ -0,0 +1,212 @@
#include "itemchargeview.hpp"
#include <set>
#include <MyGUI_Gui.h>
#include <MyGUI_TextBox.h>
#include <MyGUI_ScrollView.h>
#include <MyGUI_FactoryManager.h>
#include <components/esm/loadench.hpp>
#include "../mwbase/environment.hpp"
#include "../mwbase/world.hpp"
#include "../mwworld/class.hpp"
#include "../mwworld/esmstore.hpp"
#include "itemmodel.hpp"
#include "itemwidget.hpp"
namespace MWGui
{
ItemChargeView::ItemChargeView()
: mScrollView(NULL),
mDisplayMode(DisplayMode_Health)
{
}
void ItemChargeView::registerComponents()
{
MyGUI::FactoryManager::getInstance().registerFactory<ItemChargeView>("Widget");
}
void ItemChargeView::initialiseOverride()
{
Base::initialiseOverride();
assignWidget(mScrollView, "ScrollView");
if (mScrollView == NULL)
throw std::runtime_error("Item charge view needs a scroll view");
mScrollView->setCanvasAlign(MyGUI::Align::Left | MyGUI::Align::Top);
}
void ItemChargeView::setModel(ItemModel* model)
{
mModel.reset(model);
}
void ItemChargeView::setDisplayMode(ItemChargeView::DisplayMode type)
{
mDisplayMode = type;
update();
}
void ItemChargeView::update()
{
if (!mModel.get())
{
layoutWidgets();
return;
}
mModel->update();
Lines lines;
std::set<Lines::const_iterator> visitedLines;
for (size_t i = 0; i < mModel->getItemCount(); ++i)
{
ItemStack stack = mModel->getItem(static_cast<ItemModel::ModelIndex>(i));
bool found = false;
for (Lines::const_iterator iter = mLines.begin(); iter != mLines.end(); ++iter)
{
if (iter->mItemPtr == stack.mBase)
{
found = true;
visitedLines.insert(iter);
// update line widgets
updateLine(*iter);
lines.push_back(*iter);
break;
}
}
if (!found)
{
// add line widgets
Line line;
line.mItemPtr = stack.mBase;
line.mText = mScrollView->createWidget<MyGUI::TextBox>("SandText", MyGUI::IntCoord(), MyGUI::Align::Default);
line.mText->setNeedMouseFocus(false);
line.mIcon = mScrollView->createWidget<ItemWidget>("MW_ItemIconSmall", MyGUI::IntCoord(), MyGUI::Align::Default);
line.mIcon->setItem(line.mItemPtr);
line.mIcon->setUserString("ToolTipType", "ItemPtr");
line.mIcon->setUserData(line.mItemPtr);
line.mIcon->eventMouseButtonClick += MyGUI::newDelegate(this, &ItemChargeView::onIconClicked);
line.mIcon->eventMouseWheel += MyGUI::newDelegate(this, &ItemChargeView::onMouseWheelMoved);
line.mCharge = mScrollView->createWidget<Widgets::MWDynamicStat>("MW_ChargeBar", MyGUI::IntCoord(), MyGUI::Align::Default);
line.mCharge->setNeedMouseFocus(false);
updateLine(line);
lines.push_back(line);
}
}
for (Lines::iterator iter = mLines.begin(); iter != mLines.end(); ++iter)
{
if (visitedLines.count(iter))
continue;
// remove line widgets
MyGUI::Gui::getInstance().destroyWidget(iter->mText);
MyGUI::Gui::getInstance().destroyWidget(iter->mIcon);
MyGUI::Gui::getInstance().destroyWidget(iter->mCharge);
}
mLines.swap(lines);
layoutWidgets();
}
void ItemChargeView::layoutWidgets()
{
int currentY = 0;
for (Lines::const_iterator iter = mLines.begin(); iter != mLines.end(); ++iter)
{
iter->mText->setCoord(8, currentY, mScrollView->getWidth()-8, 18);
currentY += 19;
iter->mIcon->setCoord(16, currentY, 32, 32);
iter->mCharge->setCoord(72, currentY+2, std::max(199, mScrollView->getWidth()-72-38), 20);
currentY += 32 + 4;
}
// Canvas size must be expressed with VScroll disabled, otherwise MyGUI would expand the scroll area when the scrollbar is hidden
mScrollView->setVisibleVScroll(false);
mScrollView->setCanvasSize(MyGUI::IntSize(mScrollView->getWidth(), std::max(mScrollView->getHeight(), currentY)));
mScrollView->setVisibleVScroll(true);
}
void ItemChargeView::resetScrollbars()
{
mScrollView->setViewOffset(MyGUI::IntPoint(0, 0));
}
void ItemChargeView::setSize(const MyGUI::IntSize& value)
{
bool changed = (value.width != getWidth() || value.height != getHeight());
Base::setSize(value);
if (changed)
layoutWidgets();
}
void ItemChargeView::setCoord(const MyGUI::IntCoord& value)
{
bool changed = (value.width != getWidth() || value.height != getHeight());
Base::setCoord(value);
if (changed)
layoutWidgets();
}
void ItemChargeView::updateLine(const ItemChargeView::Line& line)
{
line.mText->setCaption(line.mItemPtr.getClass().getName(line.mItemPtr));
line.mCharge->setVisible(false);
switch (mDisplayMode)
{
case DisplayMode_Health:
if (!line.mItemPtr.getClass().hasItemHealth(line.mItemPtr))
break;
line.mCharge->setVisible(true);
line.mCharge->setValue(line.mItemPtr.getClass().getItemHealth(line.mItemPtr),
line.mItemPtr.getClass().getItemMaxHealth(line.mItemPtr));
break;
case DisplayMode_EnchantmentCharge:
std::string enchId = line.mItemPtr.getClass().getEnchantment(line.mItemPtr);
if (enchId.empty())
break;
const ESM::Enchantment* ench = MWBase::Environment::get().getWorld()->getStore().get<ESM::Enchantment>().search(enchId);
if (!ench)
break;
line.mCharge->setVisible(true);
line.mCharge->setValue(static_cast<int>(line.mItemPtr.getCellRef().getEnchantmentCharge()),
ench->mData.mCharge);
break;
}
}
void ItemChargeView::onIconClicked(MyGUI::Widget* sender)
{
eventItemClicked(this, *sender->getUserData<MWWorld::Ptr>());
}
void ItemChargeView::onMouseWheelMoved(MyGUI::Widget* /*sender*/, int rel)
{
if (mScrollView->getViewOffset().top + rel*0.3f > 0)
mScrollView->setViewOffset(MyGUI::IntPoint(0, 0));
else
mScrollView->setViewOffset(MyGUI::IntPoint(0, static_cast<int>(mScrollView->getViewOffset().top + rel*0.3f)));
}
}

@ -0,0 +1,78 @@
#ifndef MWGUI_ITEMCHARGEVIEW_H
#define MWGUI_ITEMCHARGEVIEW_H
#include <vector>
#include <memory>
#include <MyGUI_Widget.h>
#include "../mwworld/ptr.hpp"
#include "widgets.hpp"
namespace MyGUI
{
class TextBox;
class ScrollView;
}
namespace MWGui
{
class ItemModel;
class ItemWidget;
class ItemChargeView : public MyGUI::Widget
{
MYGUI_RTTI_DERIVED(ItemChargeView)
public:
enum DisplayMode
{
DisplayMode_Health,
DisplayMode_EnchantmentCharge
};
ItemChargeView();
/// Register needed components with MyGUI's factory manager
static void registerComponents();
virtual void initialiseOverride();
/// Takes ownership of \a model
void setModel(ItemModel* model);
void setDisplayMode(DisplayMode type);
void update();
void layoutWidgets();
void resetScrollbars();
virtual void setSize(const MyGUI::IntSize& value);
virtual void setCoord(const MyGUI::IntCoord& value);
MyGUI::delegates::CMultiDelegate2<MyGUI::Widget*, const MWWorld::Ptr&> eventItemClicked;
private:
struct Line
{
MWWorld::Ptr mItemPtr;
MyGUI::TextBox* mText;
ItemWidget* mIcon;
Widgets::MWDynamicStatPtr mCharge;
};
void updateLine(const Line& line);
void onIconClicked(MyGUI::Widget* sender);
void onMouseWheelMoved(MyGUI::Widget* sender, int rel);
typedef std::vector<Line> Lines;
Lines mLines;
std::auto_ptr<ItemModel> mModel;
MyGUI::ScrollView* mScrollView;
DisplayMode mDisplayMode;
};
}
#endif

@ -101,6 +101,8 @@ namespace MWGui
{ {
if (mFrame) if (mFrame)
mFrame->setImageTexture(""); mFrame->setImageTexture("");
if (mItemShadow)
mItemShadow->setImageTexture("");
mItem->setImageTexture(""); mItem->setImageTexture("");
mText->setCaption(""); mText->setCaption("");
return; return;

@ -5,6 +5,8 @@
#include <MyGUI_ScrollView.h> #include <MyGUI_ScrollView.h>
#include <MyGUI_Gui.h> #include <MyGUI_Gui.h>
#include <components/widgets/box.hpp>
#include <components/misc/rng.hpp> #include <components/misc/rng.hpp>
#include "../mwbase/world.hpp" #include "../mwbase/world.hpp"
@ -21,6 +23,9 @@
#include "widgets.hpp" #include "widgets.hpp"
#include "itemwidget.hpp" #include "itemwidget.hpp"
#include "itemchargeview.hpp"
#include "sortfilteritemmodel.hpp"
#include "inventoryitemmodel.hpp"
namespace MWGui namespace MWGui
{ {
@ -29,13 +34,15 @@ Recharge::Recharge()
: WindowBase("openmw_recharge_dialog.layout") : WindowBase("openmw_recharge_dialog.layout")
{ {
getWidget(mBox, "Box"); getWidget(mBox, "Box");
getWidget(mView, "View");
getWidget(mGemBox, "GemBox"); getWidget(mGemBox, "GemBox");
getWidget(mGemIcon, "GemIcon"); getWidget(mGemIcon, "GemIcon");
getWidget(mChargeLabel, "ChargeLabel"); getWidget(mChargeLabel, "ChargeLabel");
getWidget(mCancelButton, "CancelButton"); getWidget(mCancelButton, "CancelButton");
mCancelButton->eventMouseButtonClick += MyGUI::newDelegate(this, &Recharge::onCancel); mCancelButton->eventMouseButtonClick += MyGUI::newDelegate(this, &Recharge::onCancel);
mBox->eventItemClicked += MyGUI::newDelegate(this, &Recharge::onItemClicked);
mBox->setDisplayMode(ItemChargeView::DisplayMode_EnchantmentCharge);
setVisible(false); setVisible(false);
} }
@ -43,8 +50,13 @@ Recharge::Recharge()
void Recharge::open() void Recharge::open()
{ {
center(); center();
SortFilterItemModel * model = new SortFilterItemModel(new InventoryItemModel(MWMechanics::getPlayer()));
model->setFilter(SortFilterItemModel::Filter_OnlyRechargable);
mBox->setModel(model);
// Reset scrollbars // Reset scrollbars
mView->setViewOffset(MyGUI::IntPoint(0, 0)); mBox->resetScrollbars();
} }
void Recharge::exit() void Recharge::exit()
@ -72,66 +84,16 @@ void Recharge::updateView()
bool toolBoxVisible = (gem.getRefData().getCount() != 0); bool toolBoxVisible = (gem.getRefData().getCount() != 0);
mGemBox->setVisible(toolBoxVisible); mGemBox->setVisible(toolBoxVisible);
mGemBox->setUserString("Hidden", toolBoxVisible ? "false" : "true");
bool toolBoxWasVisible = (mBox->getPosition().top != mGemBox->getPosition().top); mBox->update();
if (toolBoxVisible && !toolBoxWasVisible)
{
// shrink
mBox->setPosition(mBox->getPosition() + MyGUI::IntPoint(0, mGemBox->getSize().height));
mBox->setSize(mBox->getSize() - MyGUI::IntSize(0,mGemBox->getSize().height));
}
else if (!toolBoxVisible && toolBoxWasVisible)
{
// expand
mBox->setPosition(MyGUI::IntPoint (mBox->getPosition().left, mGemBox->getPosition().top));
mBox->setSize(mBox->getSize() + MyGUI::IntSize(0,mGemBox->getSize().height));
}
while (mView->getChildCount())
MyGUI::Gui::getInstance().destroyWidget(mView->getChildAt(0));
int currentY = 0; Gui::Box* box = dynamic_cast<Gui::Box*>(mMainWidget);
if (box == NULL)
throw std::runtime_error("main widget must be a box");
MWWorld::Ptr player = MWMechanics::getPlayer(); box->notifyChildrenSizeChanged();
MWWorld::ContainerStore& store = player.getClass().getContainerStore(player); center();
for (MWWorld::ContainerStoreIterator iter (store.begin());
iter!=store.end(); ++iter)
{
std::string enchantmentName = iter->getClass().getEnchantment(*iter);
if (enchantmentName.empty())
continue;
const ESM::Enchantment* enchantment = MWBase::Environment::get().getWorld()->getStore().get<ESM::Enchantment>().find(enchantmentName);
if (iter->getCellRef().getEnchantmentCharge() >= enchantment->mData.mCharge
|| iter->getCellRef().getEnchantmentCharge() == -1)
continue;
MyGUI::TextBox* text = mView->createWidget<MyGUI::TextBox> (
"SandText", MyGUI::IntCoord(8, currentY, mView->getWidth()-8, 18), MyGUI::Align::Default);
text->setCaption(iter->getClass().getName(*iter));
text->setNeedMouseFocus(false);
currentY += 19;
ItemWidget* icon = mView->createWidget<ItemWidget> (
"MW_ItemIconSmall", MyGUI::IntCoord(16, currentY, 32, 32), MyGUI::Align::Default);
icon->setItem(*iter);
icon->setUserString("ToolTipType", "ItemPtr");
icon->setUserData(*iter);
icon->eventMouseButtonClick += MyGUI::newDelegate(this, &Recharge::onItemClicked);
icon->eventMouseWheel += MyGUI::newDelegate(this, &Recharge::onMouseWheel);
Widgets::MWDynamicStatPtr chargeWidget = mView->createWidget<Widgets::MWDynamicStat>
("MW_ChargeBar", MyGUI::IntCoord(72, currentY+2, 199, 20), MyGUI::Align::Default);
chargeWidget->setValue(static_cast<int>(iter->getCellRef().getEnchantmentCharge()), enchantment->mData.mCharge);
chargeWidget->setNeedMouseFocus(false);
currentY += 32 + 4;
}
// Canvas size must be expressed with VScroll disabled, otherwise MyGUI would expand the scroll area when the scrollbar is hidden
mView->setVisibleVScroll(false);
mView->setCanvasSize (MyGUI::IntSize(mView->getWidth(), std::max(mView->getHeight(), currentY)));
mView->setVisibleVScroll(true);
} }
void Recharge::onCancel(MyGUI::Widget *sender) void Recharge::onCancel(MyGUI::Widget *sender)
@ -139,15 +101,13 @@ void Recharge::onCancel(MyGUI::Widget *sender)
exit(); exit();
} }
void Recharge::onItemClicked(MyGUI::Widget *sender) void Recharge::onItemClicked(MyGUI::Widget *sender, const MWWorld::Ptr& item)
{ {
MWWorld::Ptr gem = *mGemIcon->getUserData<MWWorld::Ptr>(); MWWorld::Ptr gem = *mGemIcon->getUserData<MWWorld::Ptr>();
if (!gem.getRefData().getCount()) if (!gem.getRefData().getCount())
return; return;
MWWorld::Ptr item = *sender->getUserData<MWWorld::Ptr>();
MWWorld::Ptr player = MWMechanics::getPlayer(); MWWorld::Ptr player = MWMechanics::getPlayer();
MWMechanics::CreatureStats& stats = player.getClass().getCreatureStats(player); MWMechanics::CreatureStats& stats = player.getClass().getCreatureStats(player);
MWMechanics::NpcStats& npcStats = player.getClass().getNpcStats(player); MWMechanics::NpcStats& npcStats = player.getClass().getNpcStats(player);
@ -198,12 +158,4 @@ void Recharge::onItemClicked(MyGUI::Widget *sender)
updateView(); updateView();
} }
void Recharge::onMouseWheel(MyGUI::Widget* _sender, int _rel)
{
if (mView->getViewOffset().top + _rel*0.3f > 0)
mView->setViewOffset(MyGUI::IntPoint(0, 0));
else
mView->setViewOffset(MyGUI::IntPoint(0, static_cast<int>(mView->getViewOffset().top + _rel*0.3f)));
}
} }

@ -12,6 +12,7 @@ namespace MWGui
{ {
class ItemWidget; class ItemWidget;
class ItemChargeView;
class Recharge : public WindowBase class Recharge : public WindowBase
{ {
@ -25,8 +26,7 @@ public:
void start (const MWWorld::Ptr& gem); void start (const MWWorld::Ptr& gem);
protected: protected:
MyGUI::Widget* mBox; ItemChargeView* mBox;
MyGUI::ScrollView* mView;
MyGUI::Widget* mGemBox; MyGUI::Widget* mGemBox;
@ -38,7 +38,7 @@ protected:
void updateView(); void updateView();
void onItemClicked (MyGUI::Widget* sender); void onItemClicked (MyGUI::Widget* sender, const MWWorld::Ptr& item);
void onCancel (MyGUI::Widget* sender); void onCancel (MyGUI::Widget* sender);
void onMouseWheel(MyGUI::Widget* _sender, int _rel); void onMouseWheel(MyGUI::Widget* _sender, int _rel);

@ -4,6 +4,9 @@
#include <MyGUI_ScrollView.h> #include <MyGUI_ScrollView.h>
#include <MyGUI_Gui.h> #include <MyGUI_Gui.h>
#include <MyGUI_ItemBox.h>
#include <components/widgets/box.hpp>
#include "../mwbase/world.hpp" #include "../mwbase/world.hpp"
#include "../mwbase/environment.hpp" #include "../mwbase/environment.hpp"
@ -17,6 +20,9 @@
#include "widgets.hpp" #include "widgets.hpp"
#include "itemwidget.hpp" #include "itemwidget.hpp"
#include "itemchargeview.hpp"
#include "sortfilteritemmodel.hpp"
#include "inventoryitemmodel.hpp"
namespace MWGui namespace MWGui
{ {
@ -25,7 +31,6 @@ Repair::Repair()
: WindowBase("openmw_repair.layout") : WindowBase("openmw_repair.layout")
{ {
getWidget(mRepairBox, "RepairBox"); getWidget(mRepairBox, "RepairBox");
getWidget(mRepairView, "RepairView");
getWidget(mToolBox, "ToolBox"); getWidget(mToolBox, "ToolBox");
getWidget(mToolIcon, "ToolIcon"); getWidget(mToolIcon, "ToolIcon");
getWidget(mUsesLabel, "UsesLabel"); getWidget(mUsesLabel, "UsesLabel");
@ -33,13 +38,21 @@ Repair::Repair()
getWidget(mCancelButton, "CancelButton"); getWidget(mCancelButton, "CancelButton");
mCancelButton->eventMouseButtonClick += MyGUI::newDelegate(this, &Repair::onCancel); mCancelButton->eventMouseButtonClick += MyGUI::newDelegate(this, &Repair::onCancel);
mRepairBox->eventItemClicked += MyGUI::newDelegate(this, &Repair::onRepairItem);
mRepairBox->setDisplayMode(ItemChargeView::DisplayMode_Health);
} }
void Repair::open() void Repair::open()
{ {
center(); center();
SortFilterItemModel * model = new SortFilterItemModel(new InventoryItemModel(MWMechanics::getPlayer()));
model->setFilter(SortFilterItemModel::Filter_OnlyRepairable);
mRepairBox->setModel(model);
// Reset scrollbars // Reset scrollbars
mRepairView->setViewOffset(MyGUI::IntPoint(0, 0)); mRepairBox->resetScrollbars();
} }
void Repair::exit() void Repair::exit()
@ -75,89 +88,31 @@ void Repair::updateRepairView()
bool toolBoxVisible = (mRepair.getTool().getRefData().getCount() != 0); bool toolBoxVisible = (mRepair.getTool().getRefData().getCount() != 0);
mToolBox->setVisible(toolBoxVisible); mToolBox->setVisible(toolBoxVisible);
mToolBox->setUserString("Hidden", toolBoxVisible ? "false" : "true");
mRepairBox->update();
bool toolBoxWasVisible = (mRepairBox->getPosition().top != mToolBox->getPosition().top); Gui::Box* box = dynamic_cast<Gui::Box*>(mMainWidget);
if (box == NULL)
if (toolBoxVisible && !toolBoxWasVisible) throw std::runtime_error("main widget must be a box");
{
// shrink box->notifyChildrenSizeChanged();
mRepairBox->setPosition(mRepairBox->getPosition() + MyGUI::IntPoint(0,mToolBox->getSize().height)); center();
mRepairBox->setSize(mRepairBox->getSize() - MyGUI::IntSize(0,mToolBox->getSize().height));
}
else if (!toolBoxVisible && toolBoxWasVisible)
{
// expand
mRepairBox->setPosition(MyGUI::IntPoint (mRepairBox->getPosition().left, mToolBox->getPosition().top));
mRepairBox->setSize(mRepairBox->getSize() + MyGUI::IntSize(0,mToolBox->getSize().height));
}
while (mRepairView->getChildCount())
MyGUI::Gui::getInstance().destroyWidget(mRepairView->getChildAt(0));
int currentY = 0;
MWWorld::Ptr player = MWMechanics::getPlayer();
MWWorld::ContainerStore& store = player.getClass().getContainerStore(player);
int categories = MWWorld::ContainerStore::Type_Weapon | MWWorld::ContainerStore::Type_Armor;
for (MWWorld::ContainerStoreIterator iter (store.begin(categories));
iter!=store.end(); ++iter)
{
if (iter->getClass().hasItemHealth(*iter))
{
int maxDurability = iter->getClass().getItemMaxHealth(*iter);
int durability = iter->getClass().getItemHealth(*iter);
if (maxDurability == durability)
continue;
MyGUI::TextBox* text = mRepairView->createWidget<MyGUI::TextBox> (
"SandText", MyGUI::IntCoord(8, currentY, mRepairView->getWidth()-8, 18), MyGUI::Align::Default);
text->setCaption(iter->getClass().getName(*iter));
text->setNeedMouseFocus(false);
currentY += 19;
ItemWidget* icon = mRepairView->createWidget<ItemWidget> (
"MW_ItemIconSmall", MyGUI::IntCoord(16, currentY, 32, 32), MyGUI::Align::Default);
icon->setItem(*iter);
icon->setUserString("ToolTipType", "ItemPtr");
icon->setUserData(*iter);
icon->eventMouseButtonClick += MyGUI::newDelegate(this, &Repair::onRepairItem);
icon->eventMouseWheel += MyGUI::newDelegate(this, &Repair::onMouseWheel);
Widgets::MWDynamicStatPtr chargeWidget = mRepairView->createWidget<Widgets::MWDynamicStat>
("MW_ChargeBar", MyGUI::IntCoord(72, currentY+2, 199, 20), MyGUI::Align::Default);
chargeWidget->setValue(durability, maxDurability);
chargeWidget->setNeedMouseFocus(false);
currentY += 32 + 4;
}
}
// Canvas size must be expressed with VScroll disabled, otherwise MyGUI would expand the scroll area when the scrollbar is hidden
mRepairView->setVisibleVScroll(false);
mRepairView->setCanvasSize (MyGUI::IntSize(mRepairView->getWidth(), std::max(mRepairView->getHeight(), currentY)));
mRepairView->setVisibleVScroll(true);
} }
void Repair::onCancel(MyGUI::Widget *sender) void Repair::onCancel(MyGUI::Widget* /*sender*/)
{ {
exit(); exit();
} }
void Repair::onRepairItem(MyGUI::Widget *sender) void Repair::onRepairItem(MyGUI::Widget* /*sender*/, const MWWorld::Ptr& ptr)
{ {
if (!mRepair.getTool().getRefData().getCount()) if (!mRepair.getTool().getRefData().getCount())
return; return;
mRepair.repair(*sender->getUserData<MWWorld::Ptr>()); mRepair.repair(ptr);
updateRepairView(); updateRepairView();
} }
void Repair::onMouseWheel(MyGUI::Widget* _sender, int _rel)
{
if (mRepairView->getViewOffset().top + _rel*0.3f > 0)
mRepairView->setViewOffset(MyGUI::IntPoint(0, 0));
else
mRepairView->setViewOffset(MyGUI::IntPoint(0, static_cast<int>(mRepairView->getViewOffset().top + _rel*0.3f)));
}
} }

@ -9,6 +9,7 @@ namespace MWGui
{ {
class ItemWidget; class ItemWidget;
class ItemChargeView;
class Repair : public WindowBase class Repair : public WindowBase
{ {
@ -22,8 +23,7 @@ public:
void startRepairItem (const MWWorld::Ptr& item); void startRepairItem (const MWWorld::Ptr& item);
protected: protected:
MyGUI::Widget* mRepairBox; ItemChargeView* mRepairBox;
MyGUI::ScrollView* mRepairView;
MyGUI::Widget* mToolBox; MyGUI::Widget* mToolBox;
@ -38,9 +38,8 @@ protected:
void updateRepairView(); void updateRepairView();
void onRepairItem (MyGUI::Widget* sender); void onRepairItem(MyGUI::Widget* sender, const MWWorld::Ptr& ptr);
void onCancel (MyGUI::Widget* sender); void onCancel(MyGUI::Widget* sender);
void onMouseWheel(MyGUI::Widget* _sender, int _rel);
}; };

@ -10,6 +10,7 @@
#include "../mwbase/world.hpp" #include "../mwbase/world.hpp"
#include "../mwbase/windowmanager.hpp" #include "../mwbase/windowmanager.hpp"
#include "../mwworld/esmstore.hpp" #include "../mwworld/esmstore.hpp"
#include "../mwmechanics/autocalcspell.hpp"
#include "tooltips.hpp" #include "tooltips.hpp"
@ -29,7 +30,8 @@ namespace MWGui
const int ReviewDialog::sLineHeight = 18; const int ReviewDialog::sLineHeight = 18;
ReviewDialog::ReviewDialog() ReviewDialog::ReviewDialog()
: WindowModal("openmw_chargen_review.layout") : WindowModal("openmw_chargen_review.layout"),
mUpdateSkillArea(false)
{ {
// Centre dialog // Centre dialog
center(); center();
@ -102,7 +104,16 @@ namespace MWGui
void ReviewDialog::open() void ReviewDialog::open()
{ {
WindowModal::open(); WindowModal::open();
updateSkillArea(); mUpdateSkillArea = true;
}
void ReviewDialog::onFrame(float /*duration*/)
{
if (mUpdateSkillArea)
{
updateSkillArea();
mUpdateSkillArea = false;
}
} }
void ReviewDialog::setPlayerName(const std::string &name) void ReviewDialog::setPlayerName(const std::string &name)
@ -121,6 +132,8 @@ namespace MWGui
ToolTips::createRaceToolTip(mRaceWidget, race); ToolTips::createRaceToolTip(mRaceWidget, race);
mRaceWidget->setCaption(race->mName); mRaceWidget->setCaption(race->mName);
} }
mUpdateSkillArea = true;
} }
void ReviewDialog::setClass(const ESM::Class& class_) void ReviewDialog::setClass(const ESM::Class& class_)
@ -141,6 +154,8 @@ namespace MWGui
mBirthSignWidget->setCaption(sign->mName); mBirthSignWidget->setCaption(sign->mName);
ToolTips::createBirthsignToolTip(mBirthSignWidget, mBirthSignId); ToolTips::createBirthsignToolTip(mBirthSignWidget, mBirthSignId);
} }
mUpdateSkillArea = true;
} }
void ReviewDialog::setHealth(const MWMechanics::DynamicStat<float>& value) void ReviewDialog::setHealth(const MWMechanics::DynamicStat<float>& value)
@ -170,7 +185,11 @@ namespace MWGui
if (attr == mAttributeWidgets.end()) if (attr == mAttributeWidgets.end())
return; return;
attr->second->setAttributeValue(value); if (attr->second->getAttributeValue() != value)
{
attr->second->setAttributeValue(value);
mUpdateSkillArea = true;
}
} }
void ReviewDialog::setSkillValue(ESM::Skill::SkillEnum skillId, const MWMechanics::SkillValue& value) void ReviewDialog::setSkillValue(ESM::Skill::SkillEnum skillId, const MWMechanics::SkillValue& value)
@ -191,6 +210,7 @@ namespace MWGui
widget->_setWidgetState(state); widget->_setWidgetState(state);
} }
mUpdateSkillArea = true;
} }
void ReviewDialog::configureSkills(const std::vector<int>& major, const std::vector<int>& minor) void ReviewDialog::configureSkills(const std::vector<int>& major, const std::vector<int>& minor)
@ -211,7 +231,7 @@ namespace MWGui
mMiscSkills.push_back(skill); mMiscSkills.push_back(skill);
} }
updateSkillArea(); mUpdateSkillArea = true;
} }
void ReviewDialog::addSeparator(MyGUI::IntCoord &coord1, MyGUI::IntCoord &coord2) void ReviewDialog::addSeparator(MyGUI::IntCoord &coord1, MyGUI::IntCoord &coord2)
@ -245,7 +265,7 @@ namespace MWGui
skillNameWidget->setCaption(text); skillNameWidget->setCaption(text);
skillNameWidget->eventMouseWheel += MyGUI::newDelegate(this, &ReviewDialog::onMouseWheel); skillNameWidget->eventMouseWheel += MyGUI::newDelegate(this, &ReviewDialog::onMouseWheel);
skillValueWidget = mSkillView->createWidget<MyGUI::TextBox>("SandTextRight", coord2, MyGUI::Align::Top | MyGUI::Align::Right); skillValueWidget = mSkillView->createWidget<MyGUI::TextBox>("SandTextRight", coord2, MyGUI::Align::Default);
skillValueWidget->setCaption(value); skillValueWidget->setCaption(value);
skillValueWidget->_setWidgetState(state); skillValueWidget->_setWidgetState(state);
skillValueWidget->eventMouseWheel += MyGUI::newDelegate(this, &ReviewDialog::onMouseWheel); skillValueWidget->eventMouseWheel += MyGUI::newDelegate(this, &ReviewDialog::onMouseWheel);
@ -273,6 +293,20 @@ namespace MWGui
coord2.top += sLineHeight; coord2.top += sLineHeight;
} }
void ReviewDialog::addItem(const ESM::Spell* spell, MyGUI::IntCoord& coord1, MyGUI::IntCoord& coord2)
{
Widgets::MWSpellPtr widget = mSkillView->createWidget<Widgets::MWSpell>("MW_StatName", coord1 + MyGUI::IntSize(coord2.width, 0), MyGUI::Align::Default);
widget->setSpellId(spell->mId);
widget->setUserString("ToolTipType", "Spell");
widget->setUserString("Spell", spell->mId);
widget->eventMouseWheel += MyGUI::newDelegate(this, &ReviewDialog::onMouseWheel);
mSkillWidgets.push_back(widget);
coord1.top += sLineHeight;
coord2.top += sLineHeight;
}
void ReviewDialog::addSkills(const SkillList &skills, const std::string &titleId, const std::string &titleDefault, MyGUI::IntCoord &coord1, MyGUI::IntCoord &coord2) void ReviewDialog::addSkills(const SkillList &skills, const std::string &titleId, const std::string &titleDefault, MyGUI::IntCoord &coord1, MyGUI::IntCoord &coord2)
{ {
// Add a line separator if there are items above // Add a line separator if there are items above
@ -332,6 +366,80 @@ namespace MWGui
if (!mMiscSkills.empty()) if (!mMiscSkills.empty())
addSkills(mMiscSkills, "sSkillClassMisc", "Misc Skills", coord1, coord2); addSkills(mMiscSkills, "sSkillClassMisc", "Misc Skills", coord1, coord2);
// starting spells
std::vector<std::string> spells;
const ESM::Race* race = NULL;
if (!mRaceId.empty())
race = MWBase::Environment::get().getWorld()->getStore().get<ESM::Race>().find(mRaceId);
int skills[ESM::Skill::Length];
for (int i=0; i<ESM::Skill::Length; ++i)
skills[i] = mSkillValues.find(i)->second.getBase();
int attributes[ESM::Attribute::Length];
for (int i=0; i<ESM::Attribute::Length; ++i)
attributes[i] = mAttributeWidgets[i]->getAttributeValue().getBase();
std::vector<std::string> selectedSpells = MWMechanics::autoCalcPlayerSpells(skills, attributes, race);
for (std::vector<std::string>::iterator iter = selectedSpells.begin(); iter != selectedSpells.end(); ++iter)
{
std::string lower = Misc::StringUtils::lowerCase(*iter);
if (std::find(spells.begin(), spells.end(), lower) == spells.end())
spells.push_back(lower);
}
if (race)
{
for (std::vector<std::string>::const_iterator iter = race->mPowers.mList.begin();
iter != race->mPowers.mList.end(); ++iter)
{
std::string lower = Misc::StringUtils::lowerCase(*iter);
if (std::find(spells.begin(), spells.end(), lower) == spells.end())
spells.push_back(lower);
}
}
if (!mBirthSignId.empty())
{
const ESM::BirthSign* sign = MWBase::Environment::get().getWorld()->getStore().get<ESM::BirthSign>().find(mBirthSignId);
for (std::vector<std::string>::const_iterator iter = sign->mPowers.mList.begin();
iter != sign->mPowers.mList.end(); ++iter)
{
std::string lower = Misc::StringUtils::lowerCase(*iter);
if (std::find(spells.begin(), spells.end(), lower) == spells.end())
spells.push_back(lower);
}
}
if (!mSkillWidgets.empty())
addSeparator(coord1, coord2);
addGroup(MWBase::Environment::get().getWindowManager()->getGameSettingString("sTypeAbility", "Abilities"), coord1, coord2);
for (std::vector<std::string>::const_iterator iter = spells.begin(); iter != spells.end(); ++iter)
{
const ESM::Spell* spell = MWBase::Environment::get().getWorld()->getStore().get<ESM::Spell>().find(*iter);
if (spell->mData.mType == ESM::Spell::ST_Ability)
addItem(spell, coord1, coord2);
}
addSeparator(coord1, coord2);
addGroup(MWBase::Environment::get().getWindowManager()->getGameSettingString("sTypePower", "Powers"), coord1, coord2);
for (std::vector<std::string>::const_iterator iter = spells.begin(); iter != spells.end(); ++iter)
{
const ESM::Spell* spell = MWBase::Environment::get().getWorld()->getStore().get<ESM::Spell>().find(*iter);
if (spell->mData.mType == ESM::Spell::ST_Power)
addItem(spell, coord1, coord2);
}
addSeparator(coord1, coord2);
addGroup(MWBase::Environment::get().getWindowManager()->getGameSettingString("sTypeSpell", "Spells"), coord1, coord2);
for (std::vector<std::string>::const_iterator iter = spells.begin(); iter != spells.end(); ++iter)
{
const ESM::Spell* spell = MWBase::Environment::get().getWorld()->getStore().get<ESM::Spell>().find(*iter);
if (spell->mData.mType == ESM::Spell::ST_Spell)
addItem(spell, coord1, coord2);
}
// Canvas size must be expressed with VScroll disabled, otherwise MyGUI would expand the scroll area when the scrollbar is hidden // Canvas size must be expressed with VScroll disabled, otherwise MyGUI would expand the scroll area when the scrollbar is hidden
mSkillView->setVisibleVScroll(false); mSkillView->setVisibleVScroll(false);
mSkillView->setCanvasSize (mSkillView->getWidth(), std::max(mSkillView->getHeight(), coord1.top)); mSkillView->setCanvasSize (mSkillView->getWidth(), std::max(mSkillView->getHeight(), coord1.top));

@ -6,6 +6,11 @@
#include "windowbase.hpp" #include "windowbase.hpp"
#include "widgets.hpp" #include "widgets.hpp"
namespace ESM
{
struct Spell;
}
namespace MWGui namespace MWGui
{ {
class WindowManager; class WindowManager;
@ -42,6 +47,8 @@ namespace MWGui
virtual void open(); virtual void open();
void onFrame(float duration);
// Events // Events
typedef MyGUI::delegates::CMultiDelegate0 EventHandle_Void; typedef MyGUI::delegates::CMultiDelegate0 EventHandle_Void;
typedef MyGUI::delegates::CMultiDelegate1<int> EventHandle_Int; typedef MyGUI::delegates::CMultiDelegate1<int> EventHandle_Int;
@ -75,6 +82,7 @@ namespace MWGui
void addGroup(const std::string &label, MyGUI::IntCoord &coord1, MyGUI::IntCoord &coord2); void addGroup(const std::string &label, MyGUI::IntCoord &coord1, MyGUI::IntCoord &coord2);
MyGUI::TextBox* addValueItem(const std::string& text, const std::string &value, const std::string& state, MyGUI::IntCoord &coord1, MyGUI::IntCoord &coord2); MyGUI::TextBox* addValueItem(const std::string& text, const std::string &value, const std::string& state, MyGUI::IntCoord &coord1, MyGUI::IntCoord &coord2);
void addItem(const std::string& text, MyGUI::IntCoord &coord1, MyGUI::IntCoord &coord2); void addItem(const std::string& text, MyGUI::IntCoord &coord1, MyGUI::IntCoord &coord2);
void addItem(const ESM::Spell* spell, MyGUI::IntCoord &coord1, MyGUI::IntCoord &coord2);
void updateSkillArea(); void updateSkillArea();
static const int sLineHeight; static const int sLineHeight;
@ -92,6 +100,8 @@ namespace MWGui
std::string mName, mRaceId, mBirthSignId; std::string mName, mRaceId, mBirthSignId;
ESM::Class mKlass; ESM::Class mKlass;
std::vector<MyGUI::Widget*> mSkillWidgets; //< Skills and other information std::vector<MyGUI::Widget*> mSkillWidgets; //< Skills and other information
bool mUpdateSkillArea;
}; };
} }
#endif #endif

@ -466,9 +466,6 @@ namespace MWGui
else else
actions = MWBase::Environment::get().getInputManager()->getActionControllerSorting(); actions = MWBase::Environment::get().getInputManager()->getActionControllerSorting();
const int h = 18;
const int w = mControlsBox->getWidth() - 28;
int curH = 0;
for (std::vector<int>::const_iterator it = actions.begin(); it != actions.end(); ++it) for (std::vector<int>::const_iterator it = actions.begin(); it != actions.end(); ++it)
{ {
std::string desc = MWBase::Environment::get().getInputManager()->getActionDescription (*it); std::string desc = MWBase::Environment::get().getInputManager()->getActionDescription (*it);
@ -481,16 +478,15 @@ namespace MWGui
else else
binding = MWBase::Environment::get().getInputManager()->getActionControllerBindingName(*it); binding = MWBase::Environment::get().getInputManager()->getActionControllerBindingName(*it);
Gui::SharedStateButton* leftText = mControlsBox->createWidget<Gui::SharedStateButton>("SandTextButton", MyGUI::IntCoord(0,curH,w,h), MyGUI::Align::Default); Gui::SharedStateButton* leftText = mControlsBox->createWidget<Gui::SharedStateButton>("SandTextButton", MyGUI::IntCoord(), MyGUI::Align::Default);
leftText->setCaptionWithReplacing(desc); leftText->setCaptionWithReplacing(desc);
Gui::SharedStateButton* rightText = mControlsBox->createWidget<Gui::SharedStateButton>("SandTextButton", MyGUI::IntCoord(0,curH,w,h), MyGUI::Align::Default); Gui::SharedStateButton* rightText = mControlsBox->createWidget<Gui::SharedStateButton>("SandTextButton", MyGUI::IntCoord(), MyGUI::Align::Default);
rightText->setCaptionWithReplacing(binding); rightText->setCaptionWithReplacing(binding);
rightText->setTextAlign (MyGUI::Align::Right); rightText->setTextAlign (MyGUI::Align::Right);
rightText->setUserData(*it); // save the action id for callbacks rightText->setUserData(*it); // save the action id for callbacks
rightText->eventMouseButtonClick += MyGUI::newDelegate(this, &SettingsWindow::onRebindAction); rightText->eventMouseButtonClick += MyGUI::newDelegate(this, &SettingsWindow::onRebindAction);
rightText->eventMouseWheel += MyGUI::newDelegate(this, &SettingsWindow::onInputTabMouseWheel); rightText->eventMouseWheel += MyGUI::newDelegate(this, &SettingsWindow::onInputTabMouseWheel);
curH += h;
Gui::ButtonGroup group; Gui::ButtonGroup group;
group.push_back(leftText); group.push_back(leftText);
@ -498,9 +494,25 @@ namespace MWGui
Gui::SharedStateButton::createButtonGroup(group); Gui::SharedStateButton::createButtonGroup(group);
} }
layoutControlsBox();
}
void SettingsWindow::layoutControlsBox()
{
const int h = 18;
const int w = mControlsBox->getWidth() - 28;
const int noWidgetsInRow = 2;
const int totalH = mControlsBox->getChildCount() / noWidgetsInRow * h;
for (size_t i = 0; i < mControlsBox->getChildCount(); i++)
{
MyGUI::Widget * widget = mControlsBox->getChildAt(i);
widget->setCoord(0, i / noWidgetsInRow * h, w, h);
}
// Canvas size must be expressed with VScroll disabled, otherwise MyGUI would expand the scroll area when the scrollbar is hidden // Canvas size must be expressed with VScroll disabled, otherwise MyGUI would expand the scroll area when the scrollbar is hidden
mControlsBox->setVisibleVScroll(false); mControlsBox->setVisibleVScroll(false);
mControlsBox->setCanvasSize (mControlsBox->getWidth(), std::max(curH, mControlsBox->getHeight())); mControlsBox->setCanvasSize (mControlsBox->getWidth(), std::max(totalH, mControlsBox->getHeight()));
mControlsBox->setVisibleVScroll(true); mControlsBox->setVisibleVScroll(true);
} }
@ -556,7 +568,7 @@ namespace MWGui
void SettingsWindow::onWindowResize(MyGUI::Window *_sender) void SettingsWindow::onWindowResize(MyGUI::Window *_sender)
{ {
updateControlsBox(); layoutControlsBox();
} }
void SettingsWindow::resetScrollbars() void SettingsWindow::resetScrollbars()

@ -66,6 +66,8 @@ namespace MWGui
void configureWidgets(MyGUI::Widget* widget); void configureWidgets(MyGUI::Widget* widget);
void updateSliderLabel(MyGUI::ScrollBar* scroller, const std::string& value); void updateSliderLabel(MyGUI::ScrollBar* scroller, const std::string& value);
void layoutControlsBox();
private: private:
void resetScrollbars(); void resetScrollbars();

@ -1,5 +1,7 @@
#include "sortfilteritemmodel.hpp" #include "sortfilteritemmodel.hpp"
#include <iostream>
#include <components/misc/stringops.hpp> #include <components/misc/stringops.hpp>
#include <components/esm/loadalch.hpp> #include <components/esm/loadalch.hpp>
@ -14,9 +16,14 @@
#include <components/esm/loadprob.hpp> #include <components/esm/loadprob.hpp>
#include <components/esm/loadrepa.hpp> #include <components/esm/loadrepa.hpp>
#include <components/esm/loadweap.hpp> #include <components/esm/loadweap.hpp>
#include <components/esm/loadench.hpp>
#include "../mwbase/environment.hpp"
#include "../mwbase/world.hpp"
#include "../mwworld/class.hpp" #include "../mwworld/class.hpp"
#include "../mwworld/nullaction.hpp" #include "../mwworld/nullaction.hpp"
#include "../mwworld/esmstore.hpp"
namespace namespace
{ {
@ -139,6 +146,31 @@ namespace MWGui
return false; return false;
} }
if ((mFilter & Filter_OnlyRepairable) && (
!base.getClass().hasItemHealth(base)
|| (base.getClass().getItemHealth(base) == base.getClass().getItemMaxHealth(base))
|| (base.getTypeName() != typeid(ESM::Weapon).name()
&& base.getTypeName() != typeid(ESM::Armor).name())))
return false;
if (mFilter & Filter_OnlyRechargable)
{
if (!(item.mFlags & ItemStack::Flag_Enchanted))
return false;
std::string enchId = base.getClass().getEnchantment(base);
const ESM::Enchantment* ench = MWBase::Environment::get().getWorld()->getStore().get<ESM::Enchantment>().search(enchId);
if (!ench)
{
std::cerr << "Can't find enchantment '" << enchId << "' on item " << base.getCellRef().getRefId() << std::endl;
return false;
}
if (base.getCellRef().getEnchantmentCharge() >= ench->mData.mCharge
|| base.getCellRef().getEnchantmentCharge() == -1)
return false;
}
return true; return true;
} }

@ -39,6 +39,8 @@ namespace MWGui
static const int Filter_OnlyEnchantable = (1<<2); static const int Filter_OnlyEnchantable = (1<<2);
static const int Filter_OnlyChargedSoulstones = (1<<3); static const int Filter_OnlyChargedSoulstones = (1<<3);
static const int Filter_OnlyUsableItems = (1<<4); // Only items with a Use action static const int Filter_OnlyUsableItems = (1<<4); // Only items with a Use action
static const int Filter_OnlyRepairable = (1<<5);
static const int Filter_OnlyRechargable = (1<<6);
private: private:

@ -11,6 +11,7 @@
#include "../mwworld/inventorystore.hpp" #include "../mwworld/inventorystore.hpp"
#include "../mwworld/class.hpp" #include "../mwworld/class.hpp"
#include "../mwworld/esmstore.hpp" #include "../mwworld/esmstore.hpp"
#include "../mwworld/player.hpp"
#include "../mwmechanics/spellcasting.hpp" #include "../mwmechanics/spellcasting.hpp"
#include "../mwmechanics/spells.hpp" #include "../mwmechanics/spells.hpp"
@ -122,8 +123,15 @@ namespace MWGui
const ESM::Spell* spell = const ESM::Spell* spell =
MWBase::Environment::get().getWorld()->getStore().get<ESM::Spell>().find(spellId); MWBase::Environment::get().getWorld()->getStore().get<ESM::Spell>().find(spellId);
if (spell->mData.mFlags & ESM::Spell::F_Always MWWorld::Ptr player = MWMechanics::getPlayer();
|| spell->mData.mType == ESM::Spell::ST_Power) std::string raceId = player.get<ESM::NPC>()->mBase->mRace;
const std::string& signId =
MWBase::Environment::get().getWorld()->getPlayer().getBirthSign();
const ESM::Race* race = MWBase::Environment::get().getWorld()->getStore().get<ESM::Race>().find(raceId);
const ESM::BirthSign* birthsign = MWBase::Environment::get().getWorld()->getStore().get<ESM::BirthSign>().find(signId);
// can't delete racial spells, birthsign spells or powers
if (race->mPowers.exists(spell->mId) || birthsign->mPowers.exists(spell->mId) || spell->mData.mType == ESM::Spell::ST_Power)
{ {
MWBase::Environment::get().getWindowManager()->messageBox("#{sDeleteSpellError}"); MWBase::Environment::get().getWindowManager()->messageBox("#{sDeleteSpellError}");
} }

@ -256,7 +256,7 @@ namespace MWGui
std::string key = it->first.substr(0, underscorePos); std::string key = it->first.substr(0, underscorePos);
std::string widgetName = it->first.substr(underscorePos+1, it->first.size()-(underscorePos+1)); std::string widgetName = it->first.substr(underscorePos+1, it->first.size()-(underscorePos+1));
std::string type = "Property"; type = "Property";
size_t caretPos = key.find("^"); size_t caretPos = key.find("^");
if (caretPos != std::string::npos) if (caretPos != std::string::npos)
{ {

@ -109,6 +109,7 @@
#include "container.hpp" #include "container.hpp"
#include "controllers.hpp" #include "controllers.hpp"
#include "jailscreen.hpp" #include "jailscreen.hpp"
#include "itemchargeview.hpp"
namespace MWGui namespace MWGui
{ {
@ -223,6 +224,7 @@ namespace MWGui
MyGUI::FactoryManager::getInstance().registerFactory<osgMyGUI::ScalingLayer>("Layer"); MyGUI::FactoryManager::getInstance().registerFactory<osgMyGUI::ScalingLayer>("Layer");
BookPage::registerMyGUIComponents (); BookPage::registerMyGUIComponents ();
ItemView::registerComponents(); ItemView::registerComponents();
ItemChargeView::registerComponents();
ItemWidget::registerComponents(); ItemWidget::registerComponents();
SpellView::registerComponents(); SpellView::registerComponents();
Gui::registerAllWidgets(); Gui::registerAllWidgets();
@ -1004,6 +1006,9 @@ namespace MWGui
mScreenFader->update(frameDuration); mScreenFader->update(frameDuration);
mDebugWindow->onFrame(frameDuration); mDebugWindow->onFrame(frameDuration);
if (mCharGen)
mCharGen->onFrame(frameDuration);
} }
void WindowManager::changeCell(const MWWorld::CellStore* cell) void WindowManager::changeCell(const MWWorld::CellStore* cell)

@ -16,6 +16,9 @@
#include <components/sdlutil/sdlinputwrapper.hpp> #include <components/sdlutil/sdlinputwrapper.hpp>
#include <components/sdlutil/sdlvideowrapper.hpp> #include <components/sdlutil/sdlvideowrapper.hpp>
#include <components/esm/esmwriter.hpp>
#include <components/esm/esmreader.hpp>
#include <components/esm/controlsstate.hpp>
#include "../mwbase/world.hpp" #include "../mwbase/world.hpp"
#include "../mwbase/windowmanager.hpp" #include "../mwbase/windowmanager.hpp"
@ -1574,6 +1577,44 @@ namespace MWInput
mInputBinder->removeJoystickButtonBinding (mFakeDeviceID, mInputBinder->getJoystickButtonBinding (control, mFakeDeviceID, ICS::Control::INCREASE)); mInputBinder->removeJoystickButtonBinding (mFakeDeviceID, mInputBinder->getJoystickButtonBinding (control, mFakeDeviceID, ICS::Control::INCREASE));
} }
int InputManager::countSavedGameRecords() const
{
return 1;
}
void InputManager::write(ESM::ESMWriter& writer, Loading::Listener& /*progress*/)
{
ESM::ControlsState controls;
controls.mViewSwitchDisabled = !getControlSwitch("playerviewswitch");
controls.mControlsDisabled = !getControlSwitch("playercontrols");
controls.mJumpingDisabled = !getControlSwitch("playerjumping");
controls.mLookingDisabled = !getControlSwitch("playerlooking");
controls.mVanityModeDisabled = !getControlSwitch("vanitymode");
controls.mWeaponDrawingDisabled = !getControlSwitch("playerfighting");
controls.mSpellDrawingDisabled = !getControlSwitch("playermagic");
writer.startRecord (ESM::REC_INPU);
controls.save(writer);
writer.endRecord (ESM::REC_INPU);
}
void InputManager::readRecord(ESM::ESMReader& reader, uint32_t type)
{
if (type == ESM::REC_INPU)
{
ESM::ControlsState controls;
controls.load(reader);
toggleControlSwitch("playerviewswitch", !controls.mViewSwitchDisabled);
toggleControlSwitch("playercontrols", !controls.mControlsDisabled);
toggleControlSwitch("playerjumping", !controls.mJumpingDisabled);
toggleControlSwitch("playerlooking", !controls.mLookingDisabled);
toggleControlSwitch("vanitymode", !controls.mVanityModeDisabled);
toggleControlSwitch("playerfighting", !controls.mWeaponDrawingDisabled);
toggleControlSwitch("playermagic", !controls.mSpellDrawingDisabled);
}
}
void InputManager::resetToDefaultKeyBindings() void InputManager::resetToDefaultKeyBindings()
{ {
loadKeyDefaults(true); loadKeyDefaults(true);

@ -149,6 +149,10 @@ namespace MWInput
void clearAllKeyBindings (ICS::Control* control); void clearAllKeyBindings (ICS::Control* control);
void clearAllControllerBindings (ICS::Control* control); void clearAllControllerBindings (ICS::Control* control);
virtual int countSavedGameRecords() const;
virtual void write(ESM::ESMWriter& writer, Loading::Listener& progress);
virtual void readRecord(ESM::ESMReader& reader, uint32_t type);
private: private:
SDL_Window* mWindow; SDL_Window* mWindow;
bool mWindowVisible; bool mWindowVisible;

@ -512,8 +512,8 @@ namespace MWMechanics
if (magnitude > 0 && remainingTime > 0 && remainingTime < mDuration) if (magnitude > 0 && remainingTime > 0 && remainingTime < mDuration)
{ {
CreatureStats& creatureStats = mActor.getClass().getCreatureStats(mActor); CreatureStats& creatureStats = mActor.getClass().getCreatureStats(mActor);
effectTick(creatureStats, mActor, key, magnitude * remainingTime); if (effectTick(creatureStats, mActor, key, magnitude * remainingTime))
creatureStats.getMagicEffects().add(key, -magnitude); creatureStats.getMagicEffects().add(key, -magnitude);
} }
} }
}; };
@ -527,8 +527,10 @@ namespace MWMechanics
if (duration > 0) if (duration > 0)
{ {
// apply correct magnitude for tickable effects that have just expired, // Apply correct magnitude for tickable effects that have just expired,
// in case duration > remaining time of effect // in case duration > remaining time of effect.
// One case where this will happen is when the player uses the rest/wait command
// while there is a tickable effect active that should expire before the end of the rest/wait.
ExpiryVisitor visitor(ptr, duration); ExpiryVisitor visitor(ptr, duration);
creatureStats.getActiveSpells().visitEffectSources(visitor); creatureStats.getActiveSpells().visitEffectSources(visitor);

@ -41,9 +41,7 @@ namespace MWMechanics
if (pathTo(actor, dest, duration, MWBase::Environment::get().getWorld()->getMaxActivationDistance())) //Stop when you get in activation range if (pathTo(actor, dest, duration, MWBase::Environment::get().getWorld()->getMaxActivationDistance())) //Stop when you get in activation range
{ {
// activate when reached // activate when reached
MWWorld::Ptr target = MWBase::Environment::get().getWorld()->getPtr(mObjectId,false);
MWBase::Environment::get().getWorld()->activate(target, actor); MWBase::Environment::get().getWorld()->activate(target, actor);
return true; return true;
} }

@ -18,6 +18,7 @@
#include "character.hpp" #include "character.hpp"
#include "aicombataction.hpp" #include "aicombataction.hpp"
#include "combat.hpp" #include "combat.hpp"
#include "coordinateconverter.hpp"
namespace namespace
{ {
@ -50,23 +51,40 @@ namespace MWMechanics
bool mForceNoShortcut; bool mForceNoShortcut;
ESM::Position mShortcutFailPos; ESM::Position mShortcutFailPos;
MWMechanics::Movement mMovement; MWMechanics::Movement mMovement;
enum FleeState
{
FleeState_None,
FleeState_Idle,
FleeState_RunBlindly,
FleeState_RunToDestination
};
FleeState mFleeState;
bool mLOS;
float mUpdateLOSTimer;
float mFleeBlindRunTimer;
ESM::Pathgrid::Point mFleeDest;
AiCombatStorage(): AiCombatStorage():
mAttackCooldown(0), mAttackCooldown(0.0f),
mTimerReact(AI_REACTION_TIME), mTimerReact(AI_REACTION_TIME),
mTimerCombatMove(0), mTimerCombatMove(0.0f),
mReadyToAttack(false), mReadyToAttack(false),
mAttack(false), mAttack(false),
mAttackRange(0), mAttackRange(0.0f),
mCombatMove(false), mCombatMove(false),
mLastTargetPos(0,0,0), mLastTargetPos(0,0,0),
mCell(NULL), mCell(NULL),
mCurrentAction(), mCurrentAction(),
mActionCooldown(0), mActionCooldown(0.0f),
mStrength(), mStrength(),
mForceNoShortcut(false), mForceNoShortcut(false),
mShortcutFailPos(), mShortcutFailPos(),
mMovement() mMovement(),
mFleeState(FleeState_None),
mLOS(false),
mUpdateLOSTimer(0.0f),
mFleeBlindRunTimer(0.0f)
{} {}
void startCombatMove(bool isDistantCombat, float distToTarget, float rangeAttack, const MWWorld::Ptr& actor, const MWWorld::Ptr& target); void startCombatMove(bool isDistantCombat, float distToTarget, float rangeAttack, const MWWorld::Ptr& actor, const MWWorld::Ptr& target);
@ -76,6 +94,10 @@ namespace MWMechanics
const ESM::Weapon* weapon, bool distantCombat); const ESM::Weapon* weapon, bool distantCombat);
void updateAttack(CharacterController& characterController); void updateAttack(CharacterController& characterController);
void stopAttack(); void stopAttack();
void startFleeing();
void stopFleeing();
bool isFleeing();
}; };
AiCombat::AiCombat(const MWWorld::Ptr& actor) : AiCombat::AiCombat(const MWWorld::Ptr& actor) :
@ -157,16 +179,27 @@ namespace MWMechanics
|| target.getClass().getCreatureStats(target).isDead()) || target.getClass().getCreatureStats(target).isDead())
return true; return true;
if (storage.mCurrentAction.get()) // need to wait to init action with it's attack range if (!storage.isFleeing())
{ {
//Update every frame if (storage.mCurrentAction.get()) // need to wait to init action with its attack range
bool is_target_reached = pathTo(actor, target.getRefData().getPosition().pos, duration, storage.mAttackRange); {
if (is_target_reached) storage.mReadyToAttack = true; //Update every frame. UpdateLOS uses a timer, so the LOS check does not happen every frame.
} updateLOS(actor, target, duration, storage);
float targetReachedTolerance = 0.0f;
if (storage.mLOS)
targetReachedTolerance = storage.mAttackRange;
bool is_target_reached = pathTo(actor, target.getRefData().getPosition().pos, duration, targetReachedTolerance);
if (is_target_reached) storage.mReadyToAttack = true;
}
storage.updateCombatMove(duration); storage.updateCombatMove(duration);
if (storage.mReadyToAttack) updateActorsMovement(actor, duration, storage); if (storage.mReadyToAttack) updateActorsMovement(actor, duration, storage);
storage.updateAttack(characterController); storage.updateAttack(characterController);
}
else
{
updateFleeing(actor, target, duration, storage);
}
storage.mActionCooldown -= duration; storage.mActionCooldown -= duration;
float& timerReact = storage.mTimerReact; float& timerReact = storage.mTimerReact;
@ -185,12 +218,6 @@ namespace MWMechanics
void AiCombat::attack(const MWWorld::Ptr& actor, const MWWorld::Ptr& target, AiCombatStorage& storage, CharacterController& characterController) void AiCombat::attack(const MWWorld::Ptr& actor, const MWWorld::Ptr& target, AiCombatStorage& storage, CharacterController& characterController)
{ {
if (isTargetMagicallyHidden(target))
{
storage.stopAttack();
return; // TODO: run away instead of doing nothing
}
const MWWorld::CellStore*& currentCell = storage.mCell; const MWWorld::CellStore*& currentCell = storage.mCell;
bool cellChange = currentCell && (actor.getCell() != currentCell); bool cellChange = currentCell && (actor.getCell() != currentCell);
if(!currentCell || cellChange) if(!currentCell || cellChange)
@ -198,30 +225,61 @@ namespace MWMechanics
currentCell = actor.getCell(); currentCell = actor.getCell();
} }
bool forceFlee = false;
if (!canFight(actor, target))
{
storage.stopAttack();
characterController.setAttackingOrSpell(false);
storage.mActionCooldown = 0.f;
forceFlee = true;
}
const MWWorld::Class& actorClass = actor.getClass(); const MWWorld::Class& actorClass = actor.getClass();
actorClass.getCreatureStats(actor).setMovementFlag(CreatureStats::Flag_Run, true); actorClass.getCreatureStats(actor).setMovementFlag(CreatureStats::Flag_Run, true);
float& actionCooldown = storage.mActionCooldown; float& actionCooldown = storage.mActionCooldown;
if (actionCooldown > 0)
return;
float &rangeAttack = storage.mAttackRange;
boost::shared_ptr<Action>& currentAction = storage.mCurrentAction; boost::shared_ptr<Action>& currentAction = storage.mCurrentAction;
if (characterController.readyToPrepareAttack())
if (!forceFlee)
{ {
currentAction = prepareNextAction(actor, target); if (actionCooldown > 0)
return;
if (characterController.readyToPrepareAttack())
{
currentAction = prepareNextAction(actor, target);
actionCooldown = currentAction->getActionCooldown();
}
}
else
{
currentAction.reset(new ActionFlee());
actionCooldown = currentAction->getActionCooldown(); actionCooldown = currentAction->getActionCooldown();
} }
const ESM::Weapon *weapon = NULL; if (!currentAction)
bool isRangedCombat = false; return;
if (currentAction.get())
if (storage.isFleeing() != currentAction->isFleeing())
{ {
rangeAttack = currentAction->getCombatRange(isRangedCombat); if (currentAction->isFleeing())
// Get weapon characteristics {
weapon = currentAction->getWeapon(); storage.startFleeing();
MWBase::Environment::get().getDialogueManager()->say(actor, "flee");
return;
}
else
storage.stopFleeing();
} }
bool isRangedCombat = false;
float &rangeAttack = storage.mAttackRange;
rangeAttack = currentAction->getCombatRange(isRangedCombat);
// Get weapon characteristics
const ESM::Weapon* weapon = currentAction->getWeapon();
ESM::Position pos = actor.getRefData().getPosition(); ESM::Position pos = actor.getRefData().getPosition();
osg::Vec3f vActorPos(pos.asVec3()); osg::Vec3f vActorPos(pos.asVec3());
osg::Vec3f vTargetPos(target.getRefData().getPosition().asVec3()); osg::Vec3f vTargetPos(target.getRefData().getPosition().asVec3());
@ -229,19 +287,7 @@ namespace MWMechanics
osg::Vec3f vAimDir = MWBase::Environment::get().getWorld()->aimToTarget(actor, target); osg::Vec3f vAimDir = MWBase::Environment::get().getWorld()->aimToTarget(actor, target);
float distToTarget = MWBase::Environment::get().getWorld()->getHitDistance(actor, target); float distToTarget = MWBase::Environment::get().getWorld()->getHitDistance(actor, target);
if (!currentAction) storage.mReadyToAttack = (currentAction->isAttackingOrSpell() && distToTarget <= rangeAttack && storage.mLOS);
return;
storage.mReadyToAttack = (currentAction->isAttackingOrSpell() && distToTarget <= rangeAttack);
// can't fight if attacker can't go where target is. E.g. A fish can't attack person on land.
if (distToTarget > rangeAttack
&& !actorClass.isNpc() && !MWMechanics::isEnvironmentCompatible(actor, target))
{
// TODO: start fleeing?
storage.stopAttack();
return;
}
if (storage.mReadyToAttack) if (storage.mReadyToAttack)
{ {
@ -267,6 +313,111 @@ namespace MWMechanics
} }
} }
void MWMechanics::AiCombat::updateLOS(const MWWorld::Ptr& actor, const MWWorld::Ptr& target, float duration, MWMechanics::AiCombatStorage& storage)
{
static const float LOS_UPDATE_DURATION = 0.5f;
if (storage.mUpdateLOSTimer <= 0.f)
{
storage.mLOS = MWBase::Environment::get().getWorld()->getLOS(actor, target);
storage.mUpdateLOSTimer = LOS_UPDATE_DURATION;
}
else
storage.mUpdateLOSTimer -= duration;
}
void MWMechanics::AiCombat::updateFleeing(const MWWorld::Ptr& actor, const MWWorld::Ptr& target, float duration, MWMechanics::AiCombatStorage& storage)
{
static const float BLIND_RUN_DURATION = 1.0f;
updateLOS(actor, target, duration, storage);
AiCombatStorage::FleeState& state = storage.mFleeState;
switch (state)
{
case AiCombatStorage::FleeState_None:
return;
case AiCombatStorage::FleeState_Idle:
{
float triggerDist = getMaxAttackDistance(target);
if (storage.mLOS &&
(triggerDist >= 1000 || getDistanceMinusHalfExtents(actor, target) <= triggerDist))
{
const ESM::Pathgrid* pathgrid =
MWBase::Environment::get().getWorld()->getStore().get<ESM::Pathgrid>().search(*storage.mCell->getCell());
bool runFallback = true;
if (pathgrid && !actor.getClass().isPureWaterCreature(actor))
{
ESM::Pathgrid::PointList points;
CoordinateConverter coords(storage.mCell->getCell());
osg::Vec3f localPos = actor.getRefData().getPosition().asVec3();
coords.toLocal(localPos);
int closestPointIndex = PathFinder::GetClosestPoint(pathgrid, localPos);
for (int i = 0; i < static_cast<int>(pathgrid->mPoints.size()); i++)
{
if (i != closestPointIndex && storage.mCell->isPointConnected(closestPointIndex, i))
{
points.push_back(pathgrid->mPoints[static_cast<size_t>(i)]);
}
}
if (!points.empty())
{
ESM::Pathgrid::Point dest = points[Misc::Rng::rollDice(points.size())];
coords.toWorld(dest);
state = AiCombatStorage::FleeState_RunToDestination;
storage.mFleeDest = ESM::Pathgrid::Point(dest.mX, dest.mY, dest.mZ);
runFallback = false;
}
}
if (runFallback)
{
state = AiCombatStorage::FleeState_RunBlindly;
storage.mFleeBlindRunTimer = 0.0f;
}
}
}
break;
case AiCombatStorage::FleeState_RunBlindly:
{
// timer to prevent twitchy movement that can be observed in vanilla MW
if (storage.mFleeBlindRunTimer < BLIND_RUN_DURATION)
{
storage.mFleeBlindRunTimer += duration;
storage.mMovement.mRotation[2] = osg::PI + getZAngleToDir(target.getRefData().getPosition().asVec3()-actor.getRefData().getPosition().asVec3());
storage.mMovement.mPosition[1] = 1;
updateActorsMovement(actor, duration, storage);
}
else
state = AiCombatStorage::FleeState_Idle;
}
break;
case AiCombatStorage::FleeState_RunToDestination:
{
static const float fFleeDistance = MWBase::Environment::get().getWorld()->getStore().get<ESM::GameSetting>().find("fFleeDistance")->getFloat();
float dist = (actor.getRefData().getPosition().asVec3() - target.getRefData().getPosition().asVec3()).length();
if ((dist > fFleeDistance && !storage.mLOS)
|| pathTo(actor, storage.mFleeDest, duration))
{
state = AiCombatStorage::FleeState_Idle;
}
}
break;
};
}
void AiCombat::updateActorsMovement(const MWWorld::Ptr& actor, float duration, AiCombatStorage& storage) void AiCombat::updateActorsMovement(const MWWorld::Ptr& actor, float duration, AiCombatStorage& storage)
{ {
// apply combat movement // apply combat movement
@ -446,6 +597,26 @@ namespace MWMechanics
mReadyToAttack = false; mReadyToAttack = false;
mAttack = false; mAttack = false;
} }
void AiCombatStorage::startFleeing()
{
stopFleeing();
mFleeState = FleeState_Idle;
}
void AiCombatStorage::stopFleeing()
{
mMovement.mPosition[0] = 0;
mMovement.mPosition[1] = 0;
mMovement.mPosition[2] = 0;
mFleeState = FleeState_None;
mFleeDest = ESM::Pathgrid::Point(0, 0, 0);
}
bool AiCombatStorage::isFleeing()
{
return mFleeState != FleeState_None;
}
} }

@ -61,6 +61,10 @@ namespace MWMechanics
void attack(const MWWorld::Ptr& actor, const MWWorld::Ptr& target, AiCombatStorage& storage, CharacterController& characterController); void attack(const MWWorld::Ptr& actor, const MWWorld::Ptr& target, AiCombatStorage& storage, CharacterController& characterController);
void updateLOS(const MWWorld::Ptr& actor, const MWWorld::Ptr& target, float duration, AiCombatStorage& storage);
void updateFleeing(const MWWorld::Ptr& actor, const MWWorld::Ptr& target, float duration, AiCombatStorage& storage);
/// Transfer desired movement (from AiCombatStorage) to Actor /// Transfer desired movement (from AiCombatStorage) to Actor
void updateActorsMovement(const MWWorld::Ptr& actor, float duration, AiCombatStorage& storage); void updateActorsMovement(const MWWorld::Ptr& actor, float duration, AiCombatStorage& storage);
void rotateActorOnAxis(const MWWorld::Ptr& actor, int axis, void rotateActorOnAxis(const MWWorld::Ptr& actor, int axis,

@ -5,14 +5,17 @@
#include "../mwbase/environment.hpp" #include "../mwbase/environment.hpp"
#include "../mwbase/world.hpp" #include "../mwbase/world.hpp"
#include "../mwbase/mechanicsmanager.hpp"
#include "../mwworld/class.hpp" #include "../mwworld/class.hpp"
#include "../mwworld/esmstore.hpp" #include "../mwworld/esmstore.hpp"
#include "../mwworld/inventorystore.hpp" #include "../mwworld/inventorystore.hpp"
#include "../mwworld/actionequip.hpp" #include "../mwworld/actionequip.hpp"
#include "../mwworld/cellstore.hpp"
#include "npcstats.hpp" #include "npcstats.hpp"
#include "spellcasting.hpp" #include "spellcasting.hpp"
#include "combat.hpp"
namespace namespace
{ {
@ -517,6 +520,7 @@ namespace MWMechanics
Spells& spells = actor.getClass().getCreatureStats(actor).getSpells(); Spells& spells = actor.getClass().getCreatureStats(actor).getSpells();
float bestActionRating = 0.f; float bestActionRating = 0.f;
float antiFleeRating = 0.f;
// Default to hand-to-hand combat // Default to hand-to-hand combat
boost::shared_ptr<Action> bestAction (new ActionWeapon(MWWorld::Ptr())); boost::shared_ptr<Action> bestAction (new ActionWeapon(MWWorld::Ptr()));
if (actor.getClass().isNpc() && actor.getClass().getNpcStats(actor).isWerewolf()) if (actor.getClass().isNpc() && actor.getClass().getNpcStats(actor).isWerewolf())
@ -536,6 +540,7 @@ namespace MWMechanics
{ {
bestActionRating = rating; bestActionRating = rating;
bestAction.reset(new ActionPotion(*it)); bestAction.reset(new ActionPotion(*it));
antiFleeRating = std::numeric_limits<float>::max();
} }
} }
@ -546,6 +551,7 @@ namespace MWMechanics
{ {
bestActionRating = rating; bestActionRating = rating;
bestAction.reset(new ActionEnchantedItem(it)); bestAction.reset(new ActionEnchantedItem(it));
antiFleeRating = std::numeric_limits<float>::max();
} }
} }
@ -593,6 +599,7 @@ namespace MWMechanics
bestActionRating = rating; bestActionRating = rating;
bestAction.reset(new ActionWeapon(*it, ammo)); bestAction.reset(new ActionWeapon(*it, ammo));
antiFleeRating = vanillaRateWeaponAndAmmo(*it, ammo, actor, enemy);
} }
} }
} }
@ -606,13 +613,308 @@ namespace MWMechanics
{ {
bestActionRating = rating; bestActionRating = rating;
bestAction.reset(new ActionSpell(spell->mId)); bestAction.reset(new ActionSpell(spell->mId));
antiFleeRating = vanillaRateSpell(spell, actor, enemy);
} }
} }
if (makeFleeDecision(actor, enemy, antiFleeRating))
bestAction.reset(new ActionFlee());
if (bestAction.get()) if (bestAction.get())
bestAction->prepare(actor); bestAction->prepare(actor);
return bestAction; return bestAction;
} }
float getDistanceMinusHalfExtents(const MWWorld::Ptr& actor1, const MWWorld::Ptr& actor2, bool minusZDist)
{
osg::Vec3f actor1Pos = actor1.getRefData().getPosition().asVec3();
osg::Vec3f actor2Pos = actor2.getRefData().getPosition().asVec3();
float dist = (actor1Pos - actor2Pos).length();
if (minusZDist)
dist -= std::abs(actor1Pos.z() - actor2Pos.z());
return (dist
- MWBase::Environment::get().getWorld()->getHalfExtents(actor1).y()
- MWBase::Environment::get().getWorld()->getHalfExtents(actor2).y());
}
float getMaxAttackDistance(const MWWorld::Ptr& actor)
{
const CreatureStats& stats = actor.getClass().getCreatureStats(actor);
const MWWorld::Store<ESM::GameSetting>& gmst = MWBase::Environment::get().getWorld()->getStore().get<ESM::GameSetting>();
std::string selectedSpellId = stats.getSpells().getSelectedSpell();
MWWorld::Ptr selectedEnchItem;
MWWorld::Ptr activeWeapon, activeAmmo;
if (actor.getClass().hasInventoryStore(actor))
{
MWWorld::InventoryStore& invStore = actor.getClass().getInventoryStore(actor);
MWWorld::ContainerStoreIterator item = invStore.getSlot(MWWorld::InventoryStore::Slot_CarriedRight);
if (item != invStore.end() && item.getType() == MWWorld::ContainerStore::Type_Weapon)
activeWeapon = *item;
item = invStore.getSlot(MWWorld::InventoryStore::Slot_Ammunition);
if (item != invStore.end() && item.getType() == MWWorld::ContainerStore::Type_Weapon)
activeAmmo = *item;
if (invStore.getSelectedEnchantItem() != invStore.end())
selectedEnchItem = *invStore.getSelectedEnchantItem();
}
float dist = 1.0f;
if (activeWeapon.isEmpty() && !selectedSpellId.empty() && !selectedEnchItem.isEmpty())
{
static const float fHandToHandReach = gmst.find("fHandToHandReach")->getFloat();
dist = fHandToHandReach;
}
else if (stats.getDrawState() == MWMechanics::DrawState_Spell)
{
dist = 1.0f;
if (!selectedSpellId.empty())
{
const ESM::Spell* spell = MWBase::Environment::get().getWorld()->getStore().get<ESM::Spell>().find(selectedSpellId);
for (std::vector<ESM::ENAMstruct>::const_iterator effectIt =
spell->mEffects.mList.begin(); effectIt != spell->mEffects.mList.end(); ++effectIt)
{
if (effectIt->mArea == ESM::RT_Target)
{
const ESM::MagicEffect* effect = MWBase::Environment::get().getWorld()->getStore().get<ESM::MagicEffect>().find(effectIt->mEffectID);
dist = effect->mData.mSpeed;
break;
}
}
}
else if (!selectedEnchItem.isEmpty())
{
std::string enchId = selectedEnchItem.getClass().getEnchantment(selectedEnchItem);
if (!enchId.empty())
{
const ESM::Enchantment* ench = MWBase::Environment::get().getWorld()->getStore().get<ESM::Enchantment>().find(enchId);
for (std::vector<ESM::ENAMstruct>::const_iterator effectIt =
ench->mEffects.mList.begin(); effectIt != ench->mEffects.mList.end(); ++effectIt)
{
if (effectIt->mArea == ESM::RT_Target)
{
const ESM::MagicEffect* effect = MWBase::Environment::get().getWorld()->getStore().get<ESM::MagicEffect>().find(effectIt->mEffectID);
dist = effect->mData.mSpeed;
break;
}
}
}
}
static const float fTargetSpellMaxSpeed = gmst.find("fTargetSpellMaxSpeed")->getFloat();
dist *= std::max(1000.0f, fTargetSpellMaxSpeed);
}
else if (!activeWeapon.isEmpty())
{
const ESM::Weapon* esmWeap = activeWeapon.get<ESM::Weapon>()->mBase;
if (esmWeap->mData.mType >= ESM::Weapon::MarksmanBow)
{
static const float fTargetSpellMaxSpeed = gmst.find("fProjectileMaxSpeed")->getFloat();
dist = fTargetSpellMaxSpeed;
if (!activeAmmo.isEmpty())
{
const ESM::Weapon* esmAmmo = activeAmmo.get<ESM::Weapon>()->mBase;
dist *= esmAmmo->mData.mSpeed;
}
}
else if (esmWeap->mData.mReach > 1)
{
dist = esmWeap->mData.mReach;
}
}
dist = (dist > 0.f) ? dist : 1.0f;
static const float fCombatDistance = gmst.find("fCombatDistance")->getFloat();
static const float fCombatDistanceWerewolfMod = gmst.find("fCombatDistanceWerewolfMod")->getFloat();
float combatDistance = fCombatDistance;
if (actor.getClass().isNpc() && actor.getClass().getNpcStats(actor).isWerewolf())
combatDistance *= (fCombatDistanceWerewolfMod + 1.0f);
if (dist < combatDistance)
dist *= combatDistance;
return dist;
}
bool canFight(const MWWorld::Ptr& actor, const MWWorld::Ptr& enemy)
{
ESM::Position actorPos = actor.getRefData().getPosition();
ESM::Position enemyPos = enemy.getRefData().getPosition();
const CreatureStats& enemyStats = enemy.getClass().getCreatureStats(enemy);
if (enemyStats.getMagicEffects().get(ESM::MagicEffect::Invisibility).getMagnitude() > 0
|| enemyStats.getMagicEffects().get(ESM::MagicEffect::Chameleon).getMagnitude() > 0)
{
if (!MWBase::Environment::get().getMechanicsManager()->awarenessCheck(enemy, actor))
return false;
}
if (actor.getClass().isPureWaterCreature(actor))
{
if (!MWBase::Environment::get().getWorld()->isWading(enemy))
return false;
}
float atDist = getMaxAttackDistance(actor);
if (atDist > getDistanceMinusHalfExtents(actor, enemy)
&& atDist > std::abs(actorPos.pos[2] - enemyPos.pos[2]))
{
if (MWBase::Environment::get().getWorld()->getLOS(actor, enemy))
return true;
}
if (actor.getClass().isPureFlyingCreature(actor) || actor.getClass().isPureLandCreature(actor))
{
if (MWBase::Environment::get().getWorld()->isSwimming(enemy))
return false;
}
if (actor.getClass().isBipedal(actor) || !actor.getClass().canFly(actor))
{
if (enemy.getClass().getCreatureStats(enemy).getMagicEffects().get(ESM::MagicEffect::Levitate).getMagnitude() > 0)
{
float attackDistance = getMaxAttackDistance(actor);
if ((attackDistance + actorPos.pos[2]) < enemyPos.pos[2])
{
if (enemy.getCell()->isExterior())
{
if (attackDistance < (enemyPos.pos[2] - MWBase::Environment::get().getWorld()->getTerrainHeightAt(enemyPos.asVec3())))
return false;
}
}
}
}
if (!actor.getClass().canWalk(actor) && !actor.getClass().isBipedal(actor))
return true;
if (actor.getClass().getCreatureStats(actor).getMagicEffects().get(ESM::MagicEffect::Levitate).getMagnitude() > 0)
return true;
if (MWBase::Environment::get().getWorld()->isSwimming(actor))
return true;
if (getDistanceMinusHalfExtents(actor, enemy, true) <= 0.0f)
return false;
return true;
}
float vanillaRateSpell(const ESM::Spell* spell, const MWWorld::Ptr& actor, const MWWorld::Ptr& enemy)
{
const MWWorld::Store<ESM::GameSetting>& gmst = MWBase::Environment::get().getWorld()->getStore().get<ESM::GameSetting>();
static const float fAIMagicSpellMult = gmst.find("fAIMagicSpellMult")->getFloat();
static const float fAIRangeMagicSpellMult = gmst.find("fAIRangeMagicSpellMult")->getFloat();
float mult = fAIMagicSpellMult;
for (std::vector<ESM::ENAMstruct>::const_iterator effectIt =
spell->mEffects.mList.begin(); effectIt != spell->mEffects.mList.end(); ++effectIt)
{
if (effectIt->mArea == ESM::RT_Target)
{
if (!MWBase::Environment::get().getWorld()->isSwimming(enemy))
mult = fAIRangeMagicSpellMult;
else
mult = 0.0f;
break;
}
}
return MWMechanics::getSpellSuccessChance(spell, actor) * mult;
}
float vanillaRateWeaponAndAmmo(const MWWorld::Ptr& weapon, const MWWorld::Ptr& ammo, const MWWorld::Ptr& actor, const MWWorld::Ptr& enemy)
{
const MWWorld::Store<ESM::GameSetting>& gmst = MWBase::Environment::get().getWorld()->getStore().get<ESM::GameSetting>();
static const float fAIMeleeWeaponMult = gmst.find("fAIMeleeWeaponMult")->getFloat();
static const float fAIMeleeArmorMult = gmst.find("fAIMeleeArmorMult")->getFloat();
static const float fAIRangeMeleeWeaponMult = gmst.find("fAIRangeMeleeWeaponMult")->getFloat();
if (weapon.isEmpty())
return 0.f;
float skillMult = actor.getClass().getSkill(actor, weapon.getClass().getEquipmentSkill(weapon)) * 0.01f;
float chopMult = fAIMeleeWeaponMult;
float bonusDamage = 0.f;
const ESM::Weapon* esmWeap = weapon.get<ESM::Weapon>()->mBase;
if (esmWeap->mData.mType >= ESM::Weapon::MarksmanBow)
{
if (!ammo.isEmpty() && !MWBase::Environment::get().getWorld()->isSwimming(enemy))
{
bonusDamage = ammo.get<ESM::Weapon>()->mBase->mData.mChop[1];
chopMult = fAIRangeMeleeWeaponMult;
}
else
chopMult = 0.f;
}
float chopRating = (esmWeap->mData.mChop[1] + bonusDamage) * skillMult * chopMult;
float slashRating = esmWeap->mData.mSlash[1] * skillMult * fAIMeleeWeaponMult;
float thrustRating = esmWeap->mData.mThrust[1] * skillMult * fAIMeleeWeaponMult;
return actor.getClass().getArmorRating(actor) * fAIMeleeArmorMult
+ std::max(std::max(chopRating, slashRating), thrustRating);
}
float vanillaRateFlee(const MWWorld::Ptr& actor, const MWWorld::Ptr& enemy)
{
const CreatureStats& stats = actor.getClass().getCreatureStats(actor);
const MWWorld::Store<ESM::GameSetting>& gmst = MWBase::Environment::get().getWorld()->getStore().get<ESM::GameSetting>();
int flee = stats.getAiSetting(CreatureStats::AI_Flee).getModified();
if (flee >= 100)
return flee;
static const float fAIFleeHealthMult = gmst.find("fAIFleeHealthMult")->getFloat();
static const float fAIFleeFleeMult = gmst.find("fAIFleeFleeMult")->getFloat();
float healthPercentage = (stats.getHealth().getModified() == 0.0f)
? 1.0f : stats.getHealth().getCurrent() / stats.getHealth().getModified();
float rating = (1.0f - healthPercentage) * fAIFleeHealthMult + flee * fAIFleeFleeMult;
static const int iWereWolfLevelToAttack = gmst.find("iWereWolfLevelToAttack")->getInt();
if (enemy.getClass().isNpc() && enemy.getClass().getNpcStats(enemy).isWerewolf() && stats.getLevel() < iWereWolfLevelToAttack)
{
static const int iWereWolfFleeMod = gmst.find("iWereWolfFleeMod")->getInt();
rating = iWereWolfFleeMod;
}
if (rating != 0.0f)
rating += getFightDistanceBias(actor, enemy);
return rating;
}
bool makeFleeDecision(const MWWorld::Ptr& actor, const MWWorld::Ptr& enemy, float antiFleeRating)
{
float fleeRating = vanillaRateFlee(actor, enemy);
if (fleeRating < 100.0f)
fleeRating = 0.0f;
if (fleeRating > antiFleeRating)
return true;
// Run away after summoning a creature if we have nothing to use but fists.
if (antiFleeRating == 0.0f && !actor.getClass().getCreatureStats(actor).getSummonedCreatureMap().empty())
return true;
return false;
}
} }

@ -20,6 +20,18 @@ namespace MWMechanics
virtual float getActionCooldown() { return 0.f; } virtual float getActionCooldown() { return 0.f; }
virtual const ESM::Weapon* getWeapon() const { return NULL; }; virtual const ESM::Weapon* getWeapon() const { return NULL; };
virtual bool isAttackingOrSpell() const { return true; } virtual bool isAttackingOrSpell() const { return true; }
virtual bool isFleeing() const { return false; }
};
class ActionFlee : public Action
{
public:
ActionFlee() {}
virtual void prepare(const MWWorld::Ptr& actor) {}
virtual float getCombatRange (bool& isRanged) const { return 0.0f; }
virtual float getActionCooldown() { return 3.0f; }
virtual bool isAttackingOrSpell() const { return false; }
virtual bool isFleeing() const { return true; }
}; };
class ActionSpell : public Action class ActionSpell : public Action
@ -89,6 +101,15 @@ namespace MWMechanics
float rateEffects (const ESM::EffectList& list, const MWWorld::Ptr& actor, const MWWorld::Ptr& enemy); float rateEffects (const ESM::EffectList& list, const MWWorld::Ptr& actor, const MWWorld::Ptr& enemy);
boost::shared_ptr<Action> prepareNextAction (const MWWorld::Ptr& actor, const MWWorld::Ptr& enemy); boost::shared_ptr<Action> prepareNextAction (const MWWorld::Ptr& actor, const MWWorld::Ptr& enemy);
float getDistanceMinusHalfExtents(const MWWorld::Ptr& actor, const MWWorld::Ptr& enemy, bool minusZDist=false);
float getMaxAttackDistance(const MWWorld::Ptr& actor);
bool canFight(const MWWorld::Ptr& actor, const MWWorld::Ptr& enemy);
float vanillaRateSpell(const ESM::Spell* spell, const MWWorld::Ptr& actor, const MWWorld::Ptr& enemy);
float vanillaRateWeaponAndAmmo(const MWWorld::Ptr& weapon, const MWWorld::Ptr& ammo, const MWWorld::Ptr& actor, const MWWorld::Ptr& enemy);
float vanillaRateFlee(const MWWorld::Ptr& actor, const MWWorld::Ptr& enemy);
bool makeFleeDecision(const MWWorld::Ptr& actor, const MWWorld::Ptr& enemy, float antiFleeRating);
} }
#endif #endif

@ -141,6 +141,79 @@ namespace MWMechanics
return selectedSpells; return selectedSpells;
} }
std::vector<std::string> autoCalcPlayerSpells(const int* actorSkills, const int* actorAttributes, const ESM::Race* race)
{
const MWWorld::ESMStore& esmStore = MWBase::Environment::get().getWorld()->getStore();
static const float fPCbaseMagickaMult = esmStore.get<ESM::GameSetting>().find("fPCbaseMagickaMult")->getFloat();
float baseMagicka = fPCbaseMagickaMult * actorAttributes[ESM::Attribute::Intelligence];
bool reachedLimit = false;
const ESM::Spell* weakestSpell = NULL;
int minCost = INT_MAX;
std::vector<std::string> selectedSpells;
const MWWorld::Store<ESM::Spell> &spells =
esmStore.get<ESM::Spell>();
for (MWWorld::Store<ESM::Spell>::iterator iter = spells.begin(); iter != spells.end(); ++iter)
{
const ESM::Spell* spell = &*iter;
if (spell->mData.mType != ESM::Spell::ST_Spell)
continue;
if (!(spell->mData.mFlags & ESM::Spell::F_PCStart))
continue;
if (reachedLimit && spell->mData.mCost <= minCost)
continue;
if (race && std::find(race->mPowers.mList.begin(), race->mPowers.mList.end(), spell->mId) != race->mPowers.mList.end())
continue;
if (baseMagicka < spell->mData.mCost)
continue;
static const float fAutoPCSpellChance = esmStore.get<ESM::GameSetting>().find("fAutoPCSpellChance")->getFloat();
if (calcAutoCastChance(spell, actorSkills, actorAttributes, -1) < fAutoPCSpellChance)
continue;
if (!attrSkillCheck(spell, actorSkills, actorAttributes))
continue;
selectedSpells.push_back(spell->mId);
if (reachedLimit)
{
std::vector<std::string>::iterator it = std::find(selectedSpells.begin(), selectedSpells.end(), weakestSpell->mId);
if (it != selectedSpells.end())
selectedSpells.erase(it);
minCost = INT_MAX;
for (std::vector<std::string>::iterator weakIt = selectedSpells.begin(); weakIt != selectedSpells.end(); ++weakIt)
{
const ESM::Spell* testSpell = esmStore.get<ESM::Spell>().find(*weakIt);
if (testSpell->mData.mCost < minCost)
{
minCost = testSpell->mData.mCost;
weakestSpell = testSpell;
}
}
}
else
{
if (spell->mData.mCost < minCost)
{
weakestSpell = spell;
minCost = weakestSpell->mData.mCost;
}
static const unsigned int iAutoPCSpellMax = esmStore.get<ESM::GameSetting>().find("iAutoPCSpellMax")->getInt();
if (selectedSpells.size() == iAutoPCSpellMax)
reachedLimit = true;
}
}
return selectedSpells;
}
bool attrSkillCheck (const ESM::Spell* spell, const int* actorSkills, const int* actorAttributes) bool attrSkillCheck (const ESM::Spell* spell, const int* actorSkills, const int* actorAttributes)
{ {
const std::vector<ESM::ENAMstruct>& effects = spell->mEffects.mList; const std::vector<ESM::ENAMstruct>& effects = spell->mEffects.mList;

@ -16,6 +16,8 @@ namespace MWMechanics
std::vector<std::string> autoCalcNpcSpells(const int* actorSkills, const int* actorAttributes, const ESM::Race* race); std::vector<std::string> autoCalcNpcSpells(const int* actorSkills, const int* actorAttributes, const ESM::Race* race);
std::vector<std::string> autoCalcPlayerSpells(const int* actorSkills, const int* actorAttributes, const ESM::Race* race);
// Helpers // Helpers
bool attrSkillCheck (const ESM::Spell* spell, const int* actorSkills, const int* actorAttributes); bool attrSkillCheck (const ESM::Spell* spell, const int* actorSkills, const int* actorAttributes);

@ -1049,6 +1049,9 @@ bool CharacterController::updateCreatureState()
mUpperBodyState = UpperCharState_StartToMinAttack; mUpperBodyState = UpperCharState_StartToMinAttack;
mAttackStrength = std::min(1.f, 0.1f + Misc::Rng::rollClosedProbability()); mAttackStrength = std::min(1.f, 0.1f + Misc::Rng::rollClosedProbability());
if (weapType == WeapType_HandToHand)
playSwishSound(0.0f);
} }
} }
@ -1370,13 +1373,7 @@ bool CharacterController::updateWeaponState()
} }
else else
{ {
std::string sound = "SwishM"; playSwishSound(attackStrength);
if(attackStrength < 0.5f)
sndMgr->playSound3D(mPtr, sound, 1.0f, 0.8f); //Weak attack
else if(attackStrength < 1.0f)
sndMgr->playSound3D(mPtr, sound, 1.0f, 1.0f); //Medium attack
else
sndMgr->playSound3D(mPtr, sound, 1.0f, 1.2f); //Strong attack
} }
} }
mAttackStrength = attackStrength; mAttackStrength = attackStrength;
@ -2271,6 +2268,19 @@ void CharacterController::setHeadTrackTarget(const MWWorld::ConstPtr &target)
mHeadTrackTarget = target; mHeadTrackTarget = target;
} }
void CharacterController::playSwishSound(float attackStrength)
{
MWBase::SoundManager *sndMgr = MWBase::Environment::get().getSoundManager();
std::string sound = "Weapon Swish";
if(attackStrength < 0.5f)
sndMgr->playSound3D(mPtr, sound, 1.0f, 0.8f); //Weak attack
else if(attackStrength < 1.0f)
sndMgr->playSound3D(mPtr, sound, 1.0f, 1.0f); //Medium attack
else
sndMgr->playSound3D(mPtr, sound, 1.0f, 1.2f); //Strong attack
}
void CharacterController::updateHeadTracking(float duration) void CharacterController::updateHeadTracking(float duration)
{ {
const osg::Node* head = mAnimation->getNode("Bip01 Head"); const osg::Node* head = mAnimation->getNode("Bip01 Head");

@ -281,6 +281,8 @@ public:
/// Make this character turn its head towards \a target. To turn off head tracking, pass an empty Ptr. /// Make this character turn its head towards \a target. To turn off head tracking, pass an empty Ptr.
void setHeadTrackTarget(const MWWorld::ConstPtr& target); void setHeadTrackTarget(const MWWorld::ConstPtr& target);
void playSwishSound(float attackStrength);
}; };
MWWorld::ContainerStoreIterator getActiveWeapon(CreatureStats &stats, MWWorld::InventoryStore &inv, WeaponType *weaptype); MWWorld::ContainerStoreIterator getActiveWeapon(CreatureStats &stats, MWWorld::InventoryStore &inv, WeaponType *weaptype);

@ -431,4 +431,19 @@ namespace MWMechanics
return true; return true;
} }
float getFightDistanceBias(const MWWorld::Ptr& actor1, const MWWorld::Ptr& actor2)
{
osg::Vec3f pos1 (actor1.getRefData().getPosition().asVec3());
osg::Vec3f pos2 (actor2.getRefData().getPosition().asVec3());
float d = (pos1 - pos2).length();
static const int iFightDistanceBase = MWBase::Environment::get().getWorld()->getStore().get<ESM::GameSetting>().find(
"iFightDistanceBase")->getInt();
static const float fFightDistanceMultiplier = MWBase::Environment::get().getWorld()->getStore().get<ESM::GameSetting>().find(
"fFightDistanceMultiplier")->getFloat();
return (iFightDistanceBase - fFightDistanceMultiplier * d);
}
} }

@ -42,6 +42,7 @@ void applyFatigueLoss(const MWWorld::Ptr& attacker, const MWWorld::Ptr& weapon,
/// e.g. If attacker is a fish, is victim in water? Or, if attacker can't swim, is victim on land? /// e.g. If attacker is a fish, is victim in water? Or, if attacker can't swim, is victim on land?
bool isEnvironmentCompatible(const MWWorld::Ptr& attacker, const MWWorld::Ptr& victim); bool isEnvironmentCompatible(const MWWorld::Ptr& attacker, const MWWorld::Ptr& victim);
float getFightDistanceBias(const MWWorld::Ptr& actor1, const MWWorld::Ptr& actor2);
} }
#endif #endif

@ -25,25 +25,11 @@
#include "autocalcspell.hpp" #include "autocalcspell.hpp"
#include "npcstats.hpp" #include "npcstats.hpp"
#include "actorutil.hpp" #include "actorutil.hpp"
#include "combat.hpp"
namespace namespace
{ {
float getFightDistanceBias(const MWWorld::Ptr& actor1, const MWWorld::Ptr& actor2)
{
osg::Vec3f pos1 (actor1.getRefData().getPosition().asVec3());
osg::Vec3f pos2 (actor2.getRefData().getPosition().asVec3());
float d = (pos1 - pos2).length();
static const int iFightDistanceBase = MWBase::Environment::get().getWorld()->getStore().get<ESM::GameSetting>().find(
"iFightDistanceBase")->getInt();
static const float fFightDistanceMultiplier = MWBase::Environment::get().getWorld()->getStore().get<ESM::GameSetting>().find(
"fFightDistanceMultiplier")->getFloat();
return (iFightDistanceBase - fFightDistanceMultiplier * d);
}
float getFightDispositionBias(float disposition) float getFightDispositionBias(float disposition)
{ {
static const float fFightDispMult = MWBase::Environment::get().getWorld()->getStore().get<ESM::GameSetting>().find( static const float fFightDispMult = MWBase::Environment::get().getWorld()->getStore().get<ESM::GameSetting>().find(
@ -212,15 +198,6 @@ namespace MWMechanics
} }
// F_PCStart spells // F_PCStart spells
static const float fPCbaseMagickaMult = esmStore.get<ESM::GameSetting>().find("fPCbaseMagickaMult")->getFloat();
float baseMagicka = fPCbaseMagickaMult * creatureStats.getAttribute(ESM::Attribute::Intelligence).getBase();
bool reachedLimit = false;
const ESM::Spell* weakestSpell = NULL;
int minCost = INT_MAX;
std::vector<std::string> selectedSpells;
const ESM::Race* race = NULL; const ESM::Race* race = NULL;
if (mRaceSelected) if (mRaceSelected)
race = esmStore.get<ESM::Race>().find(player->mRace); race = esmStore.get<ESM::Race>().find(player->mRace);
@ -233,61 +210,7 @@ namespace MWMechanics
for (int i=0; i<ESM::Attribute::Length; ++i) for (int i=0; i<ESM::Attribute::Length; ++i)
attributes[i] = npcStats.getAttribute(i).getBase(); attributes[i] = npcStats.getAttribute(i).getBase();
const MWWorld::Store<ESM::Spell> &spells = std::vector<std::string> selectedSpells = autoCalcPlayerSpells(skills, attributes, race);
esmStore.get<ESM::Spell>();
for (MWWorld::Store<ESM::Spell>::iterator iter = spells.begin(); iter != spells.end(); ++iter)
{
const ESM::Spell* spell = &*iter;
if (spell->mData.mType != ESM::Spell::ST_Spell)
continue;
if (!(spell->mData.mFlags & ESM::Spell::F_PCStart))
continue;
if (reachedLimit && spell->mData.mCost <= minCost)
continue;
if (race && std::find(race->mPowers.mList.begin(), race->mPowers.mList.end(), spell->mId) != race->mPowers.mList.end())
continue;
if (baseMagicka < spell->mData.mCost)
continue;
static const float fAutoPCSpellChance = esmStore.get<ESM::GameSetting>().find("fAutoPCSpellChance")->getFloat();
if (calcAutoCastChance(spell, skills, attributes, -1) < fAutoPCSpellChance)
continue;
if (!attrSkillCheck(spell, skills, attributes))
continue;
selectedSpells.push_back(spell->mId);
if (reachedLimit)
{
std::vector<std::string>::iterator it = std::find(selectedSpells.begin(), selectedSpells.end(), weakestSpell->mId);
if (it != selectedSpells.end())
selectedSpells.erase(it);
minCost = INT_MAX;
for (std::vector<std::string>::iterator weakIt = selectedSpells.begin(); weakIt != selectedSpells.end(); ++weakIt)
{
const ESM::Spell* testSpell = esmStore.get<ESM::Spell>().find(*weakIt);
if (testSpell->mData.mCost < minCost)
{
minCost = testSpell->mData.mCost;
weakestSpell = testSpell;
}
}
}
else
{
if (spell->mData.mCost < minCost)
{
weakestSpell = spell;
minCost = weakestSpell->mData.mCost;
}
static const unsigned int iAutoPCSpellMax = esmStore.get<ESM::GameSetting>().find("iAutoPCSpellMax")->getInt();
if (selectedSpells.size() == iAutoPCSpellMax)
reachedLimit = true;
}
}
for (std::vector<std::string>::iterator it = selectedSpells.begin(); it != selectedSpells.end(); ++it) for (std::vector<std::string>::iterator it = selectedSpells.begin(); it != selectedSpells.end(); ++it)
creatureStats.getSpells().add(*it); creatureStats.getSpells().add(*it);
@ -1608,27 +1531,23 @@ namespace MWMechanics
player->restoreSkillsAttributes(); player->restoreSkillsAttributes();
} }
// Equipped items other than WerewolfRobe may reference bones that do not even
// exist with the werewolf object root, so make sure to unequip all items
// *before* we become a werewolf.
MWWorld::InventoryStore& invStore = actor.getClass().getInventoryStore(actor);
invStore.unequipAll(actor);
// Werewolfs can not cast spells, so we need to unset the prepared spell if there is one. // Werewolfs can not cast spells, so we need to unset the prepared spell if there is one.
if (npcStats.getDrawState() == MWMechanics::DrawState_Spell) if (npcStats.getDrawState() == MWMechanics::DrawState_Spell)
npcStats.setDrawState(MWMechanics::DrawState_Nothing); npcStats.setDrawState(MWMechanics::DrawState_Nothing);
npcStats.setWerewolf(werewolf); npcStats.setWerewolf(werewolf);
MWWorld::InventoryStore &inv = actor.getClass().getInventoryStore(actor);
if(werewolf) if(werewolf)
{ {
MWWorld::InventoryStore &inv = actor.getClass().getInventoryStore(actor); inv.unequipAll(actor);
inv.equip(MWWorld::InventoryStore::Slot_Robe, inv.ContainerStore::add("werewolfrobe", 1, actor), actor); inv.equip(MWWorld::InventoryStore::Slot_Robe, inv.ContainerStore::add("werewolfrobe", 1, actor), actor);
} }
else else
{ {
actor.getClass().getContainerStore(actor).remove("werewolfrobe", 1, actor); inv.unequipSlot(MWWorld::InventoryStore::Slot_Robe, actor);
inv.ContainerStore::remove("werewolfrobe", 1, actor);
} }
if(actor == player->getPlayer()) if(actor == player->getPlayer())

@ -223,7 +223,7 @@ namespace MWMechanics
return 1 - resistance / 100.f; return 1 - resistance / 100.f;
} }
/// Check if the given affect can be applied to the target. If \a castByPlayer, emits a message box on failure. /// Check if the given effect can be applied to the target. If \a castByPlayer, emits a message box on failure.
bool checkEffectTarget (int effectId, const MWWorld::Ptr& target, const MWWorld::Ptr& caster, bool castByPlayer) bool checkEffectTarget (int effectId, const MWWorld::Ptr& target, const MWWorld::Ptr& caster, bool castByPlayer)
{ {
switch (effectId) switch (effectId)
@ -913,7 +913,7 @@ namespace MWMechanics
MWRender::Animation* animation = MWBase::Environment::get().getWorld()->getAnimation(mCaster); MWRender::Animation* animation = MWBase::Environment::get().getWorld()->getAnimation(mCaster);
if (mCaster.getClass().isActor()) // TODO: Non-actors should also create a spell cast vfx if (animation && mCaster.getClass().isActor()) // TODO: Non-actors should also create a spell cast vfx even if they are disabled (animation == NULL)
{ {
const ESM::Static* castStatic; const ESM::Static* castStatic;
@ -927,7 +927,7 @@ namespace MWMechanics
animation->addEffect("meshes\\" + castStatic->mModel, effect->mIndex, false, "", texture); animation->addEffect("meshes\\" + castStatic->mModel, effect->mIndex, false, "", texture);
} }
if (!mCaster.getClass().isActor()) if (animation && !mCaster.getClass().isActor())
animation->addSpellCastGlow(effect); animation->addSpellCastGlow(effect);
static const std::string schools[] = { static const std::string schools[] = {
@ -980,8 +980,10 @@ namespace MWMechanics
if (charge == 0) if (charge == 0)
return false; return false;
// FIXME: charge should be a float, not int so that damage < 1 per frame can be applied. // Store remainder of disintegrate amount (automatically subtracted if > 1)
// This was also a bug in the original engine. item->getCellRef().applyChargeRemainderToBeSubtracted(disintegrate - std::floor(disintegrate));
charge = item->getClass().getItemHealth(*item);
charge -= charge -=
std::min(static_cast<int>(disintegrate), std::min(static_cast<int>(disintegrate),
charge); charge);
@ -1009,10 +1011,10 @@ namespace MWMechanics
creatureStats.setDynamic(index, stat); creatureStats.setDynamic(index, stat);
} }
void effectTick(CreatureStats& creatureStats, const MWWorld::Ptr& actor, const EffectKey &effectKey, float magnitude) bool effectTick(CreatureStats& creatureStats, const MWWorld::Ptr& actor, const EffectKey &effectKey, float magnitude)
{ {
if (magnitude == 0.f) if (magnitude == 0.f)
return; return false;
bool receivedMagicDamage = false; bool receivedMagicDamage = false;
@ -1144,10 +1146,13 @@ namespace MWMechanics
case ESM::MagicEffect::RemoveCurse: case ESM::MagicEffect::RemoveCurse:
actor.getClass().getCreatureStats(actor).getSpells().purgeCurses(); actor.getClass().getCreatureStats(actor).getSpells().purgeCurses();
break; break;
default:
return false;
} }
if (receivedMagicDamage && actor == getPlayer()) if (receivedMagicDamage && actor == getPlayer())
MWBase::Environment::get().getWindowManager()->activateHitOverlay(false); MWBase::Environment::get().getWindowManager()->activateHitOverlay(false);
return true;
} }
} }

@ -59,9 +59,13 @@ namespace MWMechanics
float getEffectMultiplier(short effectId, const MWWorld::Ptr& actor, const MWWorld::Ptr& caster, float getEffectMultiplier(short effectId, const MWWorld::Ptr& actor, const MWWorld::Ptr& caster,
const ESM::Spell* spell = NULL, const MagicEffects* effects = NULL); const ESM::Spell* spell = NULL, const MagicEffects* effects = NULL);
bool checkEffectTarget (int effectId, const MWWorld::Ptr& target, const MWWorld::Ptr& caster, bool castByPlayer);
int getEffectiveEnchantmentCastCost (float castCost, const MWWorld::Ptr& actor); int getEffectiveEnchantmentCastCost (float castCost, const MWWorld::Ptr& actor);
void effectTick(CreatureStats& creatureStats, const MWWorld::Ptr& actor, const MWMechanics::EffectKey& effectKey, float magnitude); /// Apply a magic effect that is applied in tick intervals until its remaining time ends or it is removed
/// @return Was the effect a tickable effect with a magnitude?
bool effectTick(CreatureStats& creatureStats, const MWWorld::Ptr& actor, const MWMechanics::EffectKey& effectKey, float magnitude);
class CastSpell class CastSpell
{ {

@ -69,7 +69,14 @@ namespace MWPhysics
return osg::RadiansToDegrees(std::acos(normal * osg::Vec3f(0.f, 0.f, 1.f))); return osg::RadiansToDegrees(std::acos(normal * osg::Vec3f(0.f, 0.f, 1.f)));
} }
static bool stepMove(const btCollisionObject *colobj, osg::Vec3f &position, enum StepMoveResult
{
Result_Blocked, // unable to move over obstacle
Result_MaxSlope, // unable to end movement on this slope
Result_Success
};
static StepMoveResult stepMove(const btCollisionObject *colobj, osg::Vec3f &position,
const osg::Vec3f &toMove, float &remainingTime, const btCollisionWorld* collisionWorld) const osg::Vec3f &toMove, float &remainingTime, const btCollisionWorld* collisionWorld)
{ {
/* /*
@ -120,7 +127,7 @@ namespace MWPhysics
stepper.doTrace(colobj, position, position+osg::Vec3f(0.0f,0.0f,sStepSizeUp), collisionWorld); stepper.doTrace(colobj, position, position+osg::Vec3f(0.0f,0.0f,sStepSizeUp), collisionWorld);
if(stepper.mFraction < std::numeric_limits<float>::epsilon()) if(stepper.mFraction < std::numeric_limits<float>::epsilon())
return false; // didn't even move the smallest representable amount return Result_Blocked; // didn't even move the smallest representable amount
// (TODO: shouldn't this be larger? Why bother with such a small amount?) // (TODO: shouldn't this be larger? Why bother with such a small amount?)
/* /*
@ -138,7 +145,7 @@ namespace MWPhysics
*/ */
tracer.doTrace(colobj, stepper.mEndPos, stepper.mEndPos + toMove, collisionWorld); tracer.doTrace(colobj, stepper.mEndPos, stepper.mEndPos + toMove, collisionWorld);
if(tracer.mFraction < std::numeric_limits<float>::epsilon()) if(tracer.mFraction < std::numeric_limits<float>::epsilon())
return false; // didn't even move the smallest representable amount return Result_Blocked; // didn't even move the smallest representable amount
/* /*
* Try moving back down sStepSizeDown using stepper. * Try moving back down sStepSizeDown using stepper.
@ -156,22 +163,22 @@ namespace MWPhysics
* ============================================== * ==============================================
*/ */
stepper.doTrace(colobj, tracer.mEndPos, tracer.mEndPos-osg::Vec3f(0.0f,0.0f,sStepSizeDown), collisionWorld); stepper.doTrace(colobj, tracer.mEndPos, tracer.mEndPos-osg::Vec3f(0.0f,0.0f,sStepSizeDown), collisionWorld);
if(stepper.mFraction < 1.0f && getSlope(stepper.mPlaneNormal) <= sMaxSlope) if (getSlope(stepper.mPlaneNormal) > sMaxSlope)
return Result_MaxSlope;
if(stepper.mFraction < 1.0f)
{ {
// don't allow stepping up other actors // don't allow stepping up other actors
if (stepper.mHitObject->getBroadphaseHandle()->m_collisionFilterGroup == CollisionType_Actor) if (stepper.mHitObject->getBroadphaseHandle()->m_collisionFilterGroup == CollisionType_Actor)
return false; return Result_Blocked;
// only step down onto semi-horizontal surfaces. don't step down onto the side of a house or a wall. // only step down onto semi-horizontal surfaces. don't step down onto the side of a house or a wall.
// TODO: stepper.mPlaneNormal does not appear to be reliable - needs more testing // TODO: stepper.mPlaneNormal does not appear to be reliable - needs more testing
// NOTE: caller's variables 'position' & 'remainingTime' are modified here // NOTE: caller's variables 'position' & 'remainingTime' are modified here
position = stepper.mEndPos; position = stepper.mEndPos;
remainingTime *= (1.0f-tracer.mFraction); // remaining time is proportional to remaining distance remainingTime *= (1.0f-tracer.mFraction); // remaining time is proportional to remaining distance
return true; return Result_Success;
} }
// moved between 0 and just under sStepSize distance but slope was too great, return Result_Blocked;
// or moved full sStepSize distance (FIXME: is this a bug?)
return false;
} }
@ -361,14 +368,15 @@ namespace MWPhysics
osg::Vec3f oldPosition = newPosition; osg::Vec3f oldPosition = newPosition;
// We hit something. Try to step up onto it. (NOTE: stepMove does not allow stepping over) // We hit something. Try to step up onto it. (NOTE: stepMove does not allow stepping over)
// NOTE: stepMove modifies newPosition if successful // NOTE: stepMove modifies newPosition if successful
bool result = stepMove(colobj, newPosition, velocity*remainingTime, remainingTime, collisionWorld); const float minStep = 10.f;
if (!result) // to make sure the maximum stepping distance isn't framerate-dependent or movement-speed dependent StepMoveResult result = stepMove(colobj, newPosition, velocity*remainingTime, remainingTime, collisionWorld);
if (result == Result_MaxSlope && (velocity*remainingTime).length() < minStep) // to make sure the maximum stepping distance isn't framerate-dependent or movement-speed dependent
{ {
osg::Vec3f normalizedVelocity = velocity; osg::Vec3f normalizedVelocity = velocity;
normalizedVelocity.normalize(); normalizedVelocity.normalize();
result = stepMove(colobj, newPosition, normalizedVelocity*10.f, remainingTime, collisionWorld); result = stepMove(colobj, newPosition, normalizedVelocity*minStep, remainingTime, collisionWorld);
} }
if(result) if(result == Result_Success)
{ {
// don't let pure water creatures move out of water after stepMove // don't let pure water creatures move out of water after stepMove
if (ptr.getClass().isPureWaterCreature(ptr) if (ptr.getClass().isPureWaterCreature(ptr)
@ -450,8 +458,8 @@ namespace MWPhysics
if (inertia.z() < 0) if (inertia.z() < 0)
inertia.z() *= slowFall; inertia.z() *= slowFall;
if (slowFall < 1.f) { if (slowFall < 1.f) {
inertia.x() = 0; inertia.x() *= slowFall;
inertia.y() = 0; inertia.y() *= slowFall;
} }
physicActor->setInertialForce(inertia); physicActor->setInertialForce(inertia);
} }
@ -985,6 +993,18 @@ namespace MWPhysics
} }
} }
bool PhysicsSystem::canMoveToWaterSurface(const MWWorld::ConstPtr &actor, const float waterlevel)
{
const Actor* physicActor = getActor(actor);
const float halfZ = physicActor->getHalfExtents().z();
const osg::Vec3f actorPosition = physicActor->getPosition();
const osg::Vec3f startingPosition(actorPosition.x(), actorPosition.y(), actorPosition.z() + halfZ);
const osg::Vec3f destinationPosition(actorPosition.x(), actorPosition.y(), waterlevel + halfZ);
ActorTracer tracer;
tracer.doTrace(physicActor->getCollisionObject(), startingPosition, destinationPosition, mCollisionWorld);
return (tracer.mFraction >= 1.0f);
}
osg::Vec3f PhysicsSystem::getHalfExtents(const MWWorld::ConstPtr &actor) const osg::Vec3f PhysicsSystem::getHalfExtents(const MWWorld::ConstPtr &actor) const
{ {
const Actor* physactor = getActor(actor); const Actor* physactor = getActor(actor);
@ -1309,25 +1329,29 @@ namespace MWPhysics
PtrVelocityList::iterator iter = mMovementQueue.begin(); PtrVelocityList::iterator iter = mMovementQueue.begin();
for(;iter != mMovementQueue.end();++iter) for(;iter != mMovementQueue.end();++iter)
{ {
ActorMap::iterator foundActor = mActors.find(iter->first);
if (foundActor == mActors.end()) // actor was already removed from the scene
continue;
Actor* physicActor = foundActor->second;
float waterlevel = -std::numeric_limits<float>::max(); float waterlevel = -std::numeric_limits<float>::max();
const MWWorld::CellStore *cell = iter->first.getCell(); const MWWorld::CellStore *cell = iter->first.getCell();
if(cell->getCell()->hasWater()) if(cell->getCell()->hasWater())
waterlevel = cell->getWaterLevel(); waterlevel = cell->getWaterLevel();
const MWMechanics::MagicEffects& effects = iter->first.getClass().getCreatureStats(iter->first).getMagicEffects(); const MWMechanics::MagicEffects& effects = iter->first.getClass().getCreatureStats(iter->first).getMagicEffects();
bool waterCollision = false; bool waterCollision = false;
if (effects.get(ESM::MagicEffect::WaterWalking).getMagnitude() if (cell->getCell()->hasWater() && effects.get(ESM::MagicEffect::WaterWalking).getMagnitude())
&& cell->getCell()->hasWater() {
&& !world->isUnderwater(iter->first.getCell(), if (!world->isUnderwater(iter->first.getCell(), osg::Vec3f(iter->first.getRefData().getPosition().asVec3())))
osg::Vec3f(iter->first.getRefData().getPosition().asVec3()))) waterCollision = true;
waterCollision = true; else if (physicActor->getCollisionMode() && canMoveToWaterSurface(iter->first, waterlevel))
{
ActorMap::iterator foundActor = mActors.find(iter->first); const osg::Vec3f actorPosition = physicActor->getPosition();
if (foundActor == mActors.end()) // actor was already removed from the scene physicActor->setPosition(osg::Vec3f(actorPosition.x(), actorPosition.y(), waterlevel));
continue; }
Actor* physicActor = foundActor->second; }
physicActor->setCanWaterWalk(waterCollision); physicActor->setCanWaterWalk(waterCollision);
// Slow fall reduces fall speed by a factor of (effect magnitude / 200) // Slow fall reduces fall speed by a factor of (effect magnitude / 200)

@ -123,6 +123,8 @@ namespace MWPhysics
bool isOnGround (const MWWorld::Ptr& actor); bool isOnGround (const MWWorld::Ptr& actor);
bool canMoveToWaterSurface (const MWWorld::ConstPtr &actor, const float waterlevel);
/// Get physical half extents (scaled) of the given actor. /// Get physical half extents (scaled) of the given actor.
osg::Vec3f getHalfExtents(const MWWorld::ConstPtr& actor) const; osg::Vec3f getHalfExtents(const MWWorld::ConstPtr& actor) const;

@ -686,9 +686,9 @@ namespace MWRender
state.mAutoDisable = autodisable; state.mAutoDisable = autodisable;
mStates[groupname] = state; mStates[groupname] = state;
NifOsg::TextKeyMap::const_iterator textkey(textkeys.lower_bound(state.getTime()));
if (state.mPlaying) if (state.mPlaying)
{ {
NifOsg::TextKeyMap::const_iterator textkey(textkeys.lower_bound(state.getTime()));
while(textkey != textkeys.end() && textkey->first <= state.getTime()) while(textkey != textkeys.end() && textkey->first <= state.getTime())
{ {
handleTextKey(state, groupname, textkey, textkeys); handleTextKey(state, groupname, textkey, textkeys);
@ -976,14 +976,14 @@ namespace MWRender
while(!(velocity > 1.0f) && ++animiter != mAnimSources.rend()) while(!(velocity > 1.0f) && ++animiter != mAnimSources.rend())
{ {
const NifOsg::TextKeyMap &keys = (*animiter)->getTextKeys(); const NifOsg::TextKeyMap &keys2 = (*animiter)->getTextKeys();
const AnimSource::ControllerMap& ctrls2 = (*animiter)->mControllerMap[0]; const AnimSource::ControllerMap& ctrls2 = (*animiter)->mControllerMap[0];
for (AnimSource::ControllerMap::const_iterator it = ctrls2.begin(); it != ctrls2.end(); ++it) for (AnimSource::ControllerMap::const_iterator it = ctrls2.begin(); it != ctrls2.end(); ++it)
{ {
if (Misc::StringUtils::ciEqual(it->first, mAccumRoot->getName())) if (Misc::StringUtils::ciEqual(it->first, mAccumRoot->getName()))
{ {
velocity = calcAnimVelocity(keys, it->second, mAccumulate, groupname); velocity = calcAnimVelocity(keys2, it->second, mAccumulate, groupname);
break; break;
} }
} }

@ -221,10 +221,10 @@ namespace MWRender
groupname = "inventoryhandtohand"; groupname = "inventoryhandtohand";
else else
{ {
const std::string &type = iter->getTypeName(); const std::string &typeName = iter->getTypeName();
if(type == typeid(ESM::Lockpick).name() || type == typeid(ESM::Probe).name()) if(typeName == typeid(ESM::Lockpick).name() || typeName == typeid(ESM::Probe).name())
groupname = "inventoryweapononehand"; groupname = "inventoryweapononehand";
else if(type == typeid(ESM::Weapon).name()) else if(typeName == typeid(ESM::Weapon).name())
{ {
MWWorld::LiveCellRef<ESM::Weapon> *ref = iter->get<ESM::Weapon>(); MWWorld::LiveCellRef<ESM::Weapon> *ref = iter->get<ESM::Weapon>();

@ -403,6 +403,9 @@ void NpcAnimation::rebuild()
{ {
updateNpcBase(); updateNpcBase();
if (mAlpha != 1.f)
mResourceSystem->getSceneManager()->recreateShaders(mObjectRoot);
MWBase::Environment::get().getMechanicsManager()->forceStateUpdate(mPtr); MWBase::Environment::get().getMechanicsManager()->forceStateUpdate(mPtr);
} }
@ -503,10 +506,10 @@ void NpcAnimation::updateNpcBase()
if(!isWerewolf) if(!isWerewolf)
{ {
if(Misc::StringUtils::lowerCase(mNpc->mRace).find("argonian") != std::string::npos)
addAnimSource("meshes\\xargonian_swimkna.nif");
if(mNpc->mModel.length() > 0) if(mNpc->mModel.length() > 0)
addAnimSource(Misc::ResourceHelpers::correctActorModelPath("meshes\\" + mNpc->mModel, mResourceSystem->getVFS())); addAnimSource(Misc::ResourceHelpers::correctActorModelPath("meshes\\" + mNpc->mModel, mResourceSystem->getVFS()));
if(Misc::StringUtils::lowerCase(mNpc->mRace).find("argonian") != std::string::npos)
addAnimSource("meshes\\xargonian_swimkna.nif");
} }
} }
else else

@ -458,9 +458,9 @@ namespace MWRender
{ {
mEffectManager->update(dt); mEffectManager->update(dt);
mSky->update(dt); mSky->update(dt);
mWater->update(dt);
} }
mWater->update(dt);
mCamera->update(dt, paused); mCamera->update(dt, paused);
osg::Vec3f focal, cameraPos; osg::Vec3f focal, cameraPos;

@ -39,11 +39,11 @@ namespace
{ {
std::ostringstream texname; std::ostringstream texname;
texname << "textures/water/" << tex << std::setw(2) << std::setfill('0') << i << ".dds"; texname << "textures/water/" << tex << std::setw(2) << std::setfill('0') << i << ".dds";
osg::ref_ptr<osg::Texture2D> tex (new osg::Texture2D(resourceSystem->getImageManager()->getImage(texname.str()))); osg::ref_ptr<osg::Texture2D> tex2 (new osg::Texture2D(resourceSystem->getImageManager()->getImage(texname.str())));
tex->setWrap(osg::Texture::WRAP_S, osg::Texture::REPEAT); tex2->setWrap(osg::Texture::WRAP_S, osg::Texture::REPEAT);
tex->setWrap(osg::Texture::WRAP_T, osg::Texture::REPEAT); tex2->setWrap(osg::Texture::WRAP_T, osg::Texture::REPEAT);
resourceSystem->getSceneManager()->applyFilterSettings(tex); resourceSystem->getSceneManager()->applyFilterSettings(tex2);
textures.push_back(tex); textures.push_back(tex2);
} }
osg::ref_ptr<NifOsg::FlipController> controller (new NifOsg::FlipController(0, 0.3f/rippleFrameCount, textures)); osg::ref_ptr<NifOsg::FlipController> controller (new NifOsg::FlipController(0, 0.3f/rippleFrameCount, textures));
@ -117,6 +117,7 @@ RippleSimulation::~RippleSimulation()
void RippleSimulation::update(float dt) void RippleSimulation::update(float dt)
{ {
const MWBase::World* world = MWBase::Environment::get().getWorld();
for (std::vector<Emitter>::iterator it=mEmitters.begin(); it !=mEmitters.end(); ++it) for (std::vector<Emitter>::iterator it=mEmitters.begin(); it !=mEmitters.end(); ++it)
{ {
if (it->mPtr == MWBase::Environment::get().getWorld ()->getPlayerPtr()) if (it->mPtr == MWBase::Environment::get().getWorld ()->getPlayerPtr())
@ -128,10 +129,8 @@ void RippleSimulation::update(float dt)
osg::Vec3f currentPos (it->mPtr.getRefData().getPosition().asVec3()); osg::Vec3f currentPos (it->mPtr.getRefData().getPosition().asVec3());
if ( (currentPos - it->mLastEmitPosition).length() > 10 bool shouldEmit = ( world->isUnderwater (it->mPtr.getCell(), it->mPtr.getRefData().getPosition().asVec3()) && !world->isSubmerged(it->mPtr) ) || world->isWalkingOnWater(it->mPtr);
// Only emit when close to the water surface, not above it and not too deep in the water if ( shouldEmit && (currentPos - it->mLastEmitPosition).length() > 10 )
&& MWBase::Environment::get().getWorld ()->isUnderwater (it->mPtr.getCell(), it->mPtr.getRefData().getPosition().asVec3())
&& !MWBase::Environment::get().getWorld()->isSubmerged(it->mPtr))
{ {
it->mLastEmitPosition = currentPos; it->mLastEmitPosition = currentPos;

@ -1329,7 +1329,7 @@ void SkyManager::createRain()
mRainParticleSystem = new osgParticle::ParticleSystem; mRainParticleSystem = new osgParticle::ParticleSystem;
mRainParticleSystem->setParticleAlignment(osgParticle::ParticleSystem::FIXED); mRainParticleSystem->setParticleAlignment(osgParticle::ParticleSystem::FIXED);
mRainParticleSystem->setAlignVectorX(osg::Vec3f(0.1,0,0)); mRainParticleSystem->setAlignVectorX(osg::Vec3f(0.1,0,0));
mRainParticleSystem->setAlignVectorY(osg::Vec3f(0,0,-1)); mRainParticleSystem->setAlignVectorY(osg::Vec3f(0,0,1));
osg::ref_ptr<osg::StateSet> stateset (mRainParticleSystem->getOrCreateStateSet()); osg::ref_ptr<osg::StateSet> stateset (mRainParticleSystem->getOrCreateStateSet());

@ -238,15 +238,15 @@ namespace MWScript
else else
{ {
char type = declarations.getType (iter->first); char type = declarations.getType (iter->first);
char index = declarations.getIndex (iter->first); int index2 = declarations.getIndex (iter->first);
try try
{ {
switch (type) switch (type)
{ {
case 's': mShorts.at (index) = iter->second.getInteger(); break; case 's': mShorts.at (index2) = iter->second.getInteger(); break;
case 'l': mLongs.at (index) = iter->second.getInteger(); break; case 'l': mLongs.at (index2) = iter->second.getInteger(); break;
case 'f': mFloats.at (index) = iter->second.getFloat(); break; case 'f': mFloats.at (index2) = iter->second.getFloat(); break;
// silently ignore locals that don't exist anymore // silently ignore locals that don't exist anymore
} }

@ -34,8 +34,9 @@
namespace MWSound namespace MWSound
{ {
SoundManager::SoundManager(const VFS::Manager* vfs, bool useSound) SoundManager::SoundManager(const VFS::Manager* vfs, const std::map<std::string,std::string>& fallbackMap, bool useSound)
: mVFS(vfs) : mVFS(vfs)
, mFallback(fallbackMap)
, mOutput(new DEFAULT_OUTPUT(*this)) , mOutput(new DEFAULT_OUTPUT(*this))
, mMasterVolume(1.0f) , mMasterVolume(1.0f)
, mSFXVolume(1.0f) , mSFXVolume(1.0f)
@ -61,6 +62,13 @@ namespace MWSound
mFootstepsVolume = Settings::Manager::getFloat("footsteps volume", "Sound"); mFootstepsVolume = Settings::Manager::getFloat("footsteps volume", "Sound");
mFootstepsVolume = std::min(std::max(mFootstepsVolume, 0.0f), 1.0f); mFootstepsVolume = std::min(std::max(mFootstepsVolume, 0.0f), 1.0f);
mNearWaterRadius = mFallback.getFallbackInt("Water_NearWaterRadius");
mNearWaterPoints = mFallback.getFallbackInt("Water_NearWaterPoints");
mNearWaterIndoorTolerance = mFallback.getFallbackFloat("Water_NearWaterIndoorTolerance");
mNearWaterOutdoorTolerance = mFallback.getFallbackFloat("Water_NearWaterOutdoorTolerance");
mNearWaterIndoorID = mFallback.getFallbackString("Water_NearWaterIndoorID");
mNearWaterOutdoorID = mFallback.getFallbackString("Water_NearWaterOutdoorID");
mBufferCacheMin = std::max(Settings::Manager::getInt("buffer cache min", "Sound"), 1); mBufferCacheMin = std::max(Settings::Manager::getInt("buffer cache min", "Sound"), 1);
mBufferCacheMax = std::max(Settings::Manager::getInt("buffer cache max", "Sound"), 1); mBufferCacheMax = std::max(Settings::Manager::getInt("buffer cache max", "Sound"), 1);
mBufferCacheMax *= 1024*1024; mBufferCacheMax *= 1024*1024;
@ -796,6 +804,96 @@ namespace MWSound
} }
} }
void SoundManager::updateWaterSound(float /*duration*/)
{
MWBase::World* world = MWBase::Environment::get().getWorld();
const MWWorld::ConstPtr player = world->getPlayerPtr();
osg::Vec3f pos = player.getRefData().getPosition().asVec3();
float volume = 0.0f;
const std::string& soundId = player.getCell()->isExterior() ? mNearWaterOutdoorID : mNearWaterIndoorID;
if (!mListenerUnderwater)
{
if (player.getCell()->getCell()->hasWater())
{
float dist = std::abs(player.getCell()->getWaterLevel() - pos.z());
if (player.getCell()->isExterior() && dist < mNearWaterOutdoorTolerance)
{
volume = (mNearWaterOutdoorTolerance - dist) / mNearWaterOutdoorTolerance;
if (mNearWaterPoints > 1)
{
int underwaterPoints = 0;
float step = mNearWaterRadius * 2.0f / (mNearWaterPoints - 1);
for (int x = 0; x < mNearWaterPoints; x++)
{
for (int y = 0; y < mNearWaterPoints; y++)
{
float height = world->getTerrainHeightAt(
osg::Vec3f(pos.x() - mNearWaterRadius + x*step, pos.y() - mNearWaterRadius + y*step, 0.0f));
if (height < 0)
underwaterPoints++;
}
}
volume *= underwaterPoints * 2.0f / (mNearWaterPoints*mNearWaterPoints);
}
}
else if (!player.getCell()->isExterior() && dist < mNearWaterIndoorTolerance)
{
volume = (mNearWaterIndoorTolerance - dist) / mNearWaterIndoorTolerance;
}
}
}
else
volume = 1.0f;
volume = std::min(volume, 1.0f);
if (mNearWaterSound)
{
if (volume == 0.0f)
{
mOutput->finishSound(mNearWaterSound);
mNearWaterSound.reset();
}
else
{
bool soundIdChanged = false;
Sound_Buffer* sfx = lookupSound(Misc::StringUtils::lowerCase(soundId));
for (SoundMap::const_iterator snditer = mActiveSounds.begin(); snditer != mActiveSounds.end(); ++snditer)
{
for (SoundBufferRefPairList::const_iterator pairiter = snditer->second.begin(); pairiter != snditer->second.end(); ++pairiter)
{
if (pairiter->first == mNearWaterSound)
{
if (pairiter->second != sfx)
soundIdChanged = true;
break;
}
}
}
if (soundIdChanged)
{
mOutput->finishSound(mNearWaterSound);
mNearWaterSound = playSound(soundId, volume, 1.0f, Play_TypeSfx, Play_Loop);
}
else if (sfx)
mNearWaterSound->setVolume(volume * sfx->mVolume);
}
}
else if (volume > 0.0f)
mNearWaterSound = playSound(soundId, volume, 1.0f, Play_TypeSfx, Play_Loop);
}
void SoundManager::updateSounds(float duration) void SoundManager::updateSounds(float duration)
{ {
static float timePassed = 0.0; static float timePassed = 0.0;
@ -941,6 +1039,7 @@ namespace MWSound
{ {
updateSounds(duration); updateSounds(duration);
updateRegionSound(duration); updateRegionSound(duration);
updateWaterSound(duration);
} }
} }
@ -1105,6 +1204,7 @@ namespace MWSound
mOutput->finishStream(*trkiter); mOutput->finishStream(*trkiter);
mActiveTracks.clear(); mActiveTracks.clear();
mUnderwaterSound.reset(); mUnderwaterSound.reset();
mNearWaterSound.reset();
stopMusic(); stopMusic();
} }
} }

@ -11,6 +11,8 @@
#include <components/settings/settings.hpp> #include <components/settings/settings.hpp>
#include <components/fallback/fallback.hpp>
#include "../mwbase/soundmanager.hpp" #include "../mwbase/soundmanager.hpp"
namespace VFS namespace VFS
@ -44,6 +46,8 @@ namespace MWSound
{ {
const VFS::Manager* mVFS; const VFS::Manager* mVFS;
Fallback::Map mFallback;
std::auto_ptr<Sound_Output> mOutput; std::auto_ptr<Sound_Output> mOutput;
// Caches available music tracks by <playlist name, (sound files) > // Caches available music tracks by <playlist name, (sound files) >
@ -56,6 +60,13 @@ namespace MWSound
float mVoiceVolume; float mVoiceVolume;
float mFootstepsVolume; float mFootstepsVolume;
int mNearWaterRadius;
int mNearWaterPoints;
float mNearWaterIndoorTolerance;
float mNearWaterOutdoorTolerance;
std::string mNearWaterIndoorID;
std::string mNearWaterOutdoorID;
typedef std::auto_ptr<std::deque<Sound_Buffer> > SoundBufferList; typedef std::auto_ptr<std::deque<Sound_Buffer> > SoundBufferList;
// List of sound buffers, grown as needed. New enties are added to the // List of sound buffers, grown as needed. New enties are added to the
// back, allowing existing Sound_Buffer references/pointers to remain // back, allowing existing Sound_Buffer references/pointers to remain
@ -94,6 +105,7 @@ namespace MWSound
int mPausedSoundTypes; int mPausedSoundTypes;
MWBase::SoundPtr mUnderwaterSound; MWBase::SoundPtr mUnderwaterSound;
MWBase::SoundPtr mNearWaterSound;
Sound_Buffer *insertSound(const std::string &soundId, const ESM::Sound *sound); Sound_Buffer *insertSound(const std::string &soundId, const ESM::Sound *sound);
@ -108,6 +120,7 @@ namespace MWSound
void streamMusicFull(const std::string& filename); void streamMusicFull(const std::string& filename);
void updateSounds(float duration); void updateSounds(float duration);
void updateRegionSound(float duration); void updateRegionSound(float duration);
void updateWaterSound(float duration);
float volumeFromType(PlayType type) const; float volumeFromType(PlayType type) const;
@ -119,7 +132,7 @@ namespace MWSound
friend class OpenAL_Output; friend class OpenAL_Output;
public: public:
SoundManager(const VFS::Manager* vfs, bool useSound); SoundManager(const VFS::Manager* vfs, const std::map<std::string, std::string>& fallbackMap, bool useSound);
virtual ~SoundManager(); virtual ~SoundManager();
virtual void processChangedSettings(const Settings::CategorySettingVector& settings); virtual void processChangedSettings(const Settings::CategorySettingVector& settings);

@ -249,7 +249,8 @@ void MWState::StateManager::saveGame (const std::string& description, const Slot
+MWBase::Environment::get().getScriptManager()->getGlobalScripts().countSavedGameRecords() +MWBase::Environment::get().getScriptManager()->getGlobalScripts().countSavedGameRecords()
+MWBase::Environment::get().getDialogueManager()->countSavedGameRecords() +MWBase::Environment::get().getDialogueManager()->countSavedGameRecords()
+MWBase::Environment::get().getWindowManager()->countSavedGameRecords() +MWBase::Environment::get().getWindowManager()->countSavedGameRecords()
+MWBase::Environment::get().getMechanicsManager()->countSavedGameRecords(); +MWBase::Environment::get().getMechanicsManager()->countSavedGameRecords()
+MWBase::Environment::get().getInputManager()->countSavedGameRecords();
writer.setRecordCount (recordCount); writer.setRecordCount (recordCount);
writer.save (stream); writer.save (stream);
@ -271,6 +272,7 @@ void MWState::StateManager::saveGame (const std::string& description, const Slot
MWBase::Environment::get().getScriptManager()->getGlobalScripts().write (writer, listener); MWBase::Environment::get().getScriptManager()->getGlobalScripts().write (writer, listener);
MWBase::Environment::get().getWindowManager()->write(writer, listener); MWBase::Environment::get().getWindowManager()->write(writer, listener);
MWBase::Environment::get().getMechanicsManager()->write(writer, listener); MWBase::Environment::get().getMechanicsManager()->write(writer, listener);
MWBase::Environment::get().getInputManager()->write(writer, listener);
// Ensure we have written the number of records that was estimated // Ensure we have written the number of records that was estimated
if (writer.getRecordCount() != recordCount+1) // 1 extra for TES3 record if (writer.getRecordCount() != recordCount+1) // 1 extra for TES3 record
@ -462,6 +464,10 @@ void MWState::StateManager::loadGame (const Character *character, const std::str
MWBase::Environment::get().getMechanicsManager()->readRecord(reader, n.intval); MWBase::Environment::get().getMechanicsManager()->readRecord(reader, n.intval);
break; break;
case ESM::REC_INPU:
MWBase::Environment::get().getInputManager()->readRecord(reader, n.intval);
break;
default: default:
// ignore invalid records // ignore invalid records

@ -93,6 +93,24 @@ namespace MWWorld
} }
} }
void CellRef::applyChargeRemainderToBeSubtracted(float chargeRemainder)
{
mCellRef.mChargeIntRemainder += std::abs(chargeRemainder);
if (mCellRef.mChargeIntRemainder > 1.0f)
{
float newChargeRemainder = (mCellRef.mChargeIntRemainder - std::floor(mCellRef.mChargeIntRemainder));
if (mCellRef.mChargeInt <= static_cast<int>(mCellRef.mChargeIntRemainder))
{
mCellRef.mChargeInt = 0;
}
else
{
mCellRef.mChargeInt -= static_cast<int>(mCellRef.mChargeIntRemainder);
}
mCellRef.mChargeIntRemainder = newChargeRemainder;
}
}
float CellRef::getChargeFloat() const float CellRef::getChargeFloat() const
{ {
return mCellRef.mChargeFloat; return mCellRef.mChargeFloat;

@ -65,6 +65,7 @@ namespace MWWorld
float getChargeFloat() const; // Implemented as union with int charge float getChargeFloat() const; // Implemented as union with int charge
void setCharge(int charge); void setCharge(int charge);
void setChargeFloat(float charge); void setChargeFloat(float charge);
void applyChargeRemainderToBeSubtracted(float chargeRemainder); // Stores remainders and applies if > 1
// The NPC that owns this object (and will get angry if you steal it) // The NPC that owns this object (and will get angry if you steal it)
std::string getOwner() const; std::string getOwner() const;

@ -204,6 +204,14 @@ namespace MWWorld
return (ref.mRef.mRefnum == pRefnum); return (ref.mRef.mRefnum == pRefnum);
} }
Ptr CellStore::getCurrentPtr(LiveCellRefBase *ref)
{
MovedRefTracker::iterator found = mMovedToAnotherCell.find(ref);
if (found != mMovedToAnotherCell.end())
return Ptr(ref, found->second);
return Ptr(ref, this);
}
void CellStore::moveFrom(const Ptr &object, CellStore *from) void CellStore::moveFrom(const Ptr &object, CellStore *from)
{ {
if (mState != State_Loaded) if (mState != State_Loaded)
@ -964,26 +972,26 @@ namespace MWWorld
mLastRespawn = MWBase::Environment::get().getWorld()->getTimeStamp(); mLastRespawn = MWBase::Environment::get().getWorld()->getTimeStamp();
for (CellRefList<ESM::Container>::List::iterator it (mContainers.mList.begin()); it!=mContainers.mList.end(); ++it) for (CellRefList<ESM::Container>::List::iterator it (mContainers.mList.begin()); it!=mContainers.mList.end(); ++it)
{ {
Ptr ptr (&*it, this); Ptr ptr = getCurrentPtr(&*it);
ptr.getClass().respawn(ptr); ptr.getClass().respawn(ptr);
} }
} }
for (CellRefList<ESM::Creature>::List::iterator it (mCreatures.mList.begin()); it!=mCreatures.mList.end(); ++it) for (CellRefList<ESM::Creature>::List::iterator it (mCreatures.mList.begin()); it!=mCreatures.mList.end(); ++it)
{ {
Ptr ptr (&*it, this); Ptr ptr = getCurrentPtr(&*it);
clearCorpse(ptr); clearCorpse(ptr);
ptr.getClass().respawn(ptr); ptr.getClass().respawn(ptr);
} }
for (CellRefList<ESM::NPC>::List::iterator it (mNpcs.mList.begin()); it!=mNpcs.mList.end(); ++it) for (CellRefList<ESM::NPC>::List::iterator it (mNpcs.mList.begin()); it!=mNpcs.mList.end(); ++it)
{ {
Ptr ptr (&*it, this); Ptr ptr = getCurrentPtr(&*it);
clearCorpse(ptr); clearCorpse(ptr);
ptr.getClass().respawn(ptr); ptr.getClass().respawn(ptr);
} }
for (CellRefList<ESM::CreatureLevList>::List::iterator it (mCreatureLists.mList.begin()); it!=mCreatureLists.mList.end(); ++it) for (CellRefList<ESM::CreatureLevList>::List::iterator it (mCreatureLists.mList.begin()); it!=mCreatureLists.mList.end(); ++it)
{ {
Ptr ptr (&*it, this); Ptr ptr = getCurrentPtr(&*it);
// no need to clearCorpse, handled as part of mCreatures // no need to clearCorpse, handled as part of mCreatures
ptr.getClass().respawn(ptr); ptr.getClass().respawn(ptr);
} }

@ -111,6 +111,9 @@ namespace MWWorld
// Merged list of ref's currently in this cell - i.e. with added refs from mMovedHere, removed refs from mMovedToAnotherCell // Merged list of ref's currently in this cell - i.e. with added refs from mMovedHere, removed refs from mMovedToAnotherCell
std::vector<LiveCellRefBase*> mMergedRefs; std::vector<LiveCellRefBase*> mMergedRefs;
// Get the Ptr for the given ref which originated from this cell (possibly moved to another cell at this point).
Ptr getCurrentPtr(MWWorld::LiveCellRefBase* ref);
/// Moves object from the given cell to this cell. /// Moves object from the given cell to this cell.
void moveFrom(const MWWorld::Ptr& object, MWWorld::CellStore* from); void moveFrom(const MWWorld::Ptr& object, MWWorld::CellStore* from);

@ -393,7 +393,26 @@ namespace MWWorld
bool Class::isPureWaterCreature(const MWWorld::Ptr& ptr) const bool Class::isPureWaterCreature(const MWWorld::Ptr& ptr) const
{ {
return canSwim(ptr) && !canWalk(ptr); return canSwim(ptr)
&& !isBipedal(ptr)
&& !canFly(ptr)
&& !canWalk(ptr);
}
bool Class::isPureFlyingCreature(const Ptr& ptr) const
{
return canFly(ptr)
&& !isBipedal(ptr)
&& !canSwim(ptr)
&& !canWalk(ptr);
}
bool Class::isPureLandCreature(const Ptr& ptr) const
{
return canWalk(ptr)
&& !isBipedal(ptr)
&& !canFly(ptr)
&& !canSwim(ptr);
} }
bool Class::isMobile(const MWWorld::Ptr& ptr) const bool Class::isMobile(const MWWorld::Ptr& ptr) const

@ -312,6 +312,8 @@ namespace MWWorld
virtual bool canSwim(const MWWorld::ConstPtr& ptr) const; virtual bool canSwim(const MWWorld::ConstPtr& ptr) const;
virtual bool canWalk(const MWWorld::ConstPtr& ptr) const; virtual bool canWalk(const MWWorld::ConstPtr& ptr) const;
bool isPureWaterCreature(const MWWorld::Ptr& ptr) const; bool isPureWaterCreature(const MWWorld::Ptr& ptr) const;
bool isPureFlyingCreature(const MWWorld::Ptr& ptr) const;
bool isPureLandCreature(const MWWorld::Ptr& ptr) const;
bool isMobile(const MWWorld::Ptr& ptr) const; bool isMobile(const MWWorld::Ptr& ptr) const;
virtual int getSkill(const MWWorld::Ptr& ptr, int skill) const; virtual int getSkill(const MWWorld::Ptr& ptr, int skill) const;

@ -553,14 +553,14 @@ void MWWorld::ContainerStore::restock (const ESM::InventoryList& items, const MW
if(listInMap != allowedForReplace.end()) if(listInMap != allowedForReplace.end())
restockNum -= std::min(restockNum, listInMap->second); restockNum -= std::min(restockNum, listInMap->second);
//restock //restock
addInitialItem(itemOrList, owner, restockNum, true); addInitialItem(itemOrList, owner, -restockNum, true);
} }
else else
{ {
//Restocking static item - just restock to the max count //Restocking static item - just restock to the max count
int currentCount = count(itemOrList); int currentCount = count(itemOrList);
if (currentCount < std::abs(it->mCount)) if (currentCount < std::abs(it->mCount))
addInitialItem(itemOrList, owner, std::abs(it->mCount) - currentCount, true); addInitialItem(itemOrList, owner, -(std::abs(it->mCount) - currentCount), true);
} }
} }
flagAsModified(); flagAsModified();

@ -6,6 +6,7 @@
#include <components/esm/loadench.hpp> #include <components/esm/loadench.hpp>
#include <components/esm/inventorystate.hpp> #include <components/esm/inventorystate.hpp>
#include <components/misc/rng.hpp> #include <components/misc/rng.hpp>
#include <components/settings/settings.hpp>
#include "../mwbase/environment.hpp" #include "../mwbase/environment.hpp"
#include "../mwbase/world.hpp" #include "../mwbase/world.hpp"
@ -214,36 +215,71 @@ MWWorld::ContainerStoreIterator MWWorld::InventoryStore::getSlot (int slot)
return mSlots[slot]; return mSlots[slot];
} }
bool MWWorld::InventoryStore::canActorAutoEquip(const MWWorld::Ptr& actor, const MWWorld::Ptr& item)
{
if (!Settings::Manager::getBool("prevent merchant equipping", "Game"))
return true;
// Only autoEquip if we are the original owner of the item.
// This stops merchants from auto equipping anything you sell to them.
// ...unless this is a companion, he should always equip items given to him.
if (!Misc::StringUtils::ciEqual(item.getCellRef().getOwner(), actor.getCellRef().getRefId()) &&
(actor.getClass().getScript(actor).empty() ||
!actor.getRefData().getLocals().getIntVar(actor.getClass().getScript(actor), "companion"))
&& !actor.getClass().getCreatureStats(actor).isDead() // Corpses can be dressed up by the player as desired
)
{
return false;
}
return true;
}
void MWWorld::InventoryStore::autoEquip (const MWWorld::Ptr& actor) void MWWorld::InventoryStore::autoEquip (const MWWorld::Ptr& actor)
{ {
if (!actor.getClass().isNpc())
// autoEquip is no-op for creatures
return;
const MWBase::World *world = MWBase::Environment::get().getWorld();
const MWWorld::Store<ESM::GameSetting> &store = world->getStore().get<ESM::GameSetting>();
MWMechanics::NpcStats& stats = actor.getClass().getNpcStats(actor);
static float fUnarmoredBase1 = store.find("fUnarmoredBase1")->getFloat();
static float fUnarmoredBase2 = store.find("fUnarmoredBase2")->getFloat();
int unarmoredSkill = stats.getSkill(ESM::Skill::Unarmored).getModified();
float unarmoredRating = static_cast<int>((fUnarmoredBase1 * unarmoredSkill) * (fUnarmoredBase2 * unarmoredSkill));
TSlots slots_; TSlots slots_;
initSlots (slots_); initSlots (slots_);
// Disable model update during auto-equip // Disable model update during auto-equip
mUpdatesEnabled = false; mUpdatesEnabled = false;
for (ContainerStoreIterator iter (begin()); iter!=end(); ++iter) // Autoequip clothing, armor and weapons.
// Equipping lights is handled in Actors::updateEquippedLight based on environment light.
for (ContainerStoreIterator iter (begin(ContainerStore::Type_Clothing | ContainerStore::Type_Armor)); iter!=end(); ++iter)
{ {
Ptr test = *iter; Ptr test = *iter;
// Don't autoEquip lights. Handled in Actors::updateEquippedLight based on environment light. if (!canActorAutoEquip(actor, test))
if (test.getTypeName() == typeid(ESM::Light).name())
{
continue; continue;
switch(test.getClass().canBeEquipped (test, actor).first)
{
case 0:
continue;
default:
break;
} }
// Only autoEquip if we are the original owner of the item. if (iter.getType() == ContainerStore::Type_Armor &&
// This stops merchants from auto equipping anything you sell to them. test.getClass().getEffectiveArmorRating(test, actor) <= std::max(unarmoredRating, 0.f))
// ...unless this is a companion, he should always equip items given to him.
if (!Misc::StringUtils::ciEqual(test.getCellRef().getOwner(), actor.getCellRef().getRefId()) &&
(actor.getClass().getScript(actor).empty() ||
!actor.getRefData().getLocals().getIntVar(actor.getClass().getScript(actor), "companion"))
&& !actor.getClass().getCreatureStats(actor).isDead() // Corpses can be dressed up by the player as desired
)
{ {
continue; continue;
} }
int testSkill = test.getClass().getEquipmentSkill (test);
std::pair<std::vector<int>, bool> itemsSlots = std::pair<std::vector<int>, bool> itemsSlots =
iter->getClass().getEquipmentSlots (*iter); iter->getClass().getEquipmentSlots (*iter);
@ -251,51 +287,35 @@ void MWWorld::InventoryStore::autoEquip (const MWWorld::Ptr& actor)
for (std::vector<int>::const_iterator iter2 (itemsSlots.first.begin()); for (std::vector<int>::const_iterator iter2 (itemsSlots.first.begin());
iter2!=itemsSlots.first.end(); ++iter2) iter2!=itemsSlots.first.end(); ++iter2)
{ {
if (*iter2 == Slot_CarriedRight) // Items in right hand are situational use, so don't equip them.
// Equipping weapons is handled by AiCombat. Anything else (lockpicks, probes) can't be used by NPCs anyway (yet)
continue;
if (iter.getType() == MWWorld::ContainerStore::Type_Weapon)
continue;
if (slots_.at (*iter2)!=end()) if (slots_.at (*iter2)!=end())
{ {
Ptr old = *slots_.at (*iter2); Ptr old = *slots_.at (*iter2);
// check skill if (iter.getType() == ContainerStore::Type_Armor)
int oldSkill = old.getClass().getEquipmentSkill (old);
bool use = false;
if (testSkill!=-1 && oldSkill==-1)
use = true;
else if (testSkill!=-1 && oldSkill!=-1 && testSkill!=oldSkill)
{ {
if (actor.getClass().getSkill(actor, oldSkill) > actor.getClass().getSkill (actor, testSkill)) if (old.getTypeName() == typeid(ESM::Armor).name())
continue; // rejected, because old item better matched the NPC's skills. {
if (old.getClass().getEffectiveArmorRating(old, actor) >= test.getClass().getEffectiveArmorRating(test, actor))
if (actor.getClass().getSkill(actor, oldSkill) < actor.getClass().getSkill (actor, testSkill)) // old armor had better armor rating
use = true; continue;
}
// suitable armor should replace already equipped clothing
} }
else if (iter.getType() == ContainerStore::Type_Clothing)
if (!use)
{ {
// check value if (old.getTypeName() == typeid(ESM::Clothing).name())
if (old.getClass().getValue (old)>=
test.getClass().getValue (test))
{ {
continue; // check value
if (old.getClass().getValue (old) > test.getClass().getValue (test))
// old clothing was more valuable
continue;
} }
else
// suitable clothing should NOT replace already equipped armor
continue;
} }
} }
switch(test.getClass().canBeEquipped (test, actor).first)
{
case 0:
continue;
default:
break;
}
if (!itemsSlots.second) // if itemsSlots.second is true, item can stay stacked when equipped if (!itemsSlots.second) // if itemsSlots.second is true, item can stay stacked when equipped
{ {
// unstack item pointed to by iterator if required // unstack item pointed to by iterator if required
@ -310,6 +330,99 @@ void MWWorld::InventoryStore::autoEquip (const MWWorld::Ptr& actor)
} }
} }
static const ESM::Skill::SkillEnum weaponSkills[] =
{
ESM::Skill::LongBlade,
ESM::Skill::Axe,
ESM::Skill::Spear,
ESM::Skill::ShortBlade,
ESM::Skill::Marksman,
ESM::Skill::BluntWeapon
};
const size_t weaponSkillsLength = sizeof(weaponSkills) / sizeof(weaponSkills[0]);
bool weaponSkillVisited[weaponSkillsLength] = { false };
for (int i = 0; i < static_cast<int>(weaponSkillsLength); ++i)
{
int max = 0;
int maxWeaponSkill = -1;
for (int j = 0; j < static_cast<int>(weaponSkillsLength); ++j)
{
int skillValue = stats.getSkill(static_cast<int>(weaponSkills[j])).getModified();
if (skillValue > max && !weaponSkillVisited[j])
{
max = skillValue;
maxWeaponSkill = j;
}
}
if (maxWeaponSkill == -1)
break;
max = 0;
ContainerStoreIterator weapon(end());
for (ContainerStoreIterator iter(begin(ContainerStore::Type_Weapon)); iter!=end(); ++iter)
{
if (!canActorAutoEquip(actor, *iter))
continue;
const ESM::Weapon* esmWeapon = iter->get<ESM::Weapon>()->mBase;
if (esmWeapon->mData.mType == ESM::Weapon::Arrow || esmWeapon->mData.mType == ESM::Weapon::Bolt)
continue;
if (iter->getClass().getEquipmentSkill(*iter) == weaponSkills[maxWeaponSkill])
{
if (esmWeapon->mData.mChop[1] >= max)
{
max = esmWeapon->mData.mChop[1];
weapon = iter;
}
if (esmWeapon->mData.mSlash[1] >= max)
{
max = esmWeapon->mData.mSlash[1];
weapon = iter;
}
if (esmWeapon->mData.mThrust[1] >= max)
{
max = esmWeapon->mData.mThrust[1];
weapon = iter;
}
}
}
if (weapon != end() && weapon->getClass().canBeEquipped(*weapon, actor).first)
{
std::pair<std::vector<int>, bool> itemsSlots =
weapon->getClass().getEquipmentSlots (*weapon);
for (std::vector<int>::const_iterator slot (itemsSlots.first.begin());
slot!=itemsSlots.first.end(); ++slot)
{
if (!itemsSlots.second)
{
if (weapon->getRefData().getCount() > 1)
{
unstack(*weapon, actor);
}
}
slots_[*slot] = weapon;
break;
}
break;
}
weaponSkillVisited[maxWeaponSkill] = true;
}
bool changed = false; bool changed = false;
for (std::size_t i=0; i<slots_.size(); ++i) for (std::size_t i=0; i<slots_.size(); ++i)
@ -402,8 +515,8 @@ void MWWorld::InventoryStore::updateMagicEffects(const Ptr& actor)
MWBase::Environment::get().getWorld()->getStore().get<ESM::MagicEffect>().find ( MWBase::Environment::get().getWorld()->getStore().get<ESM::MagicEffect>().find (
effectIt->mEffectID); effectIt->mEffectID);
// Fully resisted? // Fully resisted or can't be applied to target?
if (params[i].mMultiplier == 0) if (params[i].mMultiplier == 0 || !MWMechanics::checkEffectTarget(effectIt->mEffectID, actor, actor, actor == MWMechanics::getPlayer()))
continue; continue;
float magnitude = effectIt->mMagnMin + (effectIt->mMagnMax - effectIt->mMagnMin) * params[i].mRandom; float magnitude = effectIt->mMagnMin + (effectIt->mMagnMax - effectIt->mMagnMin) * params[i].mRandom;
@ -657,6 +770,9 @@ void MWWorld::InventoryStore::visitEffectSources(MWMechanics::EffectSourceVisito
for (std::vector<ESM::ENAMstruct>::const_iterator effectIt (enchantment.mEffects.mList.begin()); for (std::vector<ESM::ENAMstruct>::const_iterator effectIt (enchantment.mEffects.mList.begin());
effectIt!=enchantment.mEffects.mList.end(); ++effectIt) effectIt!=enchantment.mEffects.mList.end(); ++effectIt)
{ {
// Don't get spell icon display information for enchantments that weren't actually applied
if (mMagicEffects.get(MWMechanics::EffectKey(*effectIt)).getMagnitude() == 0)
continue;
const EffectParams& params = mPermanentMagicEffectMagnitudes[(**iter).getCellRef().getRefId()][i]; const EffectParams& params = mPermanentMagicEffectMagnitudes[(**iter).getCellRef().getRefId()][i];
float magnitude = effectIt->mMagnMin + (effectIt->mMagnMax - effectIt->mMagnMin) * params.mRandom; float magnitude = effectIt->mMagnMin + (effectIt->mMagnMax - effectIt->mMagnMin) * params.mRandom;
magnitude *= params.mMultiplier; magnitude *= params.mMultiplier;

@ -115,6 +115,8 @@ namespace MWWorld
virtual void storeEquipmentState (const MWWorld::LiveCellRefBase& ref, int index, ESM::InventoryState& inventory) const; virtual void storeEquipmentState (const MWWorld::LiveCellRefBase& ref, int index, ESM::InventoryState& inventory) const;
virtual void readEquipmentState (const MWWorld::ContainerStoreIterator& iter, int index, const ESM::InventoryState& inventory); virtual void readEquipmentState (const MWWorld::ContainerStoreIterator& iter, int index, const ESM::InventoryState& inventory);
bool canActorAutoEquip(const MWWorld::Ptr& actor, const MWWorld::Ptr& item);
public: public:
InventoryStore(); InventoryStore();

@ -16,6 +16,7 @@ namespace
cellRef.mScale = 1; cellRef.mScale = 1;
cellRef.mFactionRank = 0; cellRef.mFactionRank = 0;
cellRef.mChargeInt = -1; cellRef.mChargeInt = -1;
cellRef.mChargeIntRemainder = 0.0f;
cellRef.mGoldValue = 1; cellRef.mGoldValue = 1;
cellRef.mEnchantmentCharge = -1; cellRef.mEnchantmentCharge = -1;
cellRef.mTeleport = false; cellRef.mTeleport = false;

@ -136,7 +136,7 @@ namespace MWWorld
}; };
void ProjectileManager::createModel(State &state, const std::string &model, const osg::Vec3f& pos, const osg::Quat& orient, bool rotate, std::string texture) void ProjectileManager::createModel(State &state, const std::string &model, const osg::Vec3f& pos, const osg::Quat& orient, bool rotate, bool createLight, std::string texture)
{ {
state.mNode = new osg::PositionAttitudeTransform; state.mNode = new osg::PositionAttitudeTransform;
state.mNode->setNodeMask(MWRender::Mask_Effect); state.mNode->setNodeMask(MWRender::Mask_Effect);
@ -167,6 +167,55 @@ namespace MWWorld
mResourceSystem->getSceneManager()->getInstance("meshes\\" + weapon->mModel, findVisitor.mFoundNode); mResourceSystem->getSceneManager()->getInstance("meshes\\" + weapon->mModel, findVisitor.mFoundNode);
} }
if (createLight)
{
// Case: magical effects (combine colors of individual effects)
osg::Vec4 lightDiffuseColor;
if (state.mIdMagic.size() > 0)
{
float lightDiffuseRed = 0.0f;
float lightDiffuseGreen = 0.0f;
float lightDiffuseBlue = 0.0f;
for (std::vector<ESM::ENAMstruct>::const_iterator it = ((MagicBoltState&)state).mEffects.mList.begin(); it != ((MagicBoltState&)state).mEffects.mList.end(); ++it)
{
const ESM::MagicEffect* magicEffect = MWBase::Environment::get().getWorld()->getStore().get<ESM::MagicEffect>().find(
it->mEffectID);
lightDiffuseRed += ((float) magicEffect->mData.mRed / 255.f);
lightDiffuseGreen += ((float) magicEffect->mData.mGreen / 255.f);
lightDiffuseBlue += ((float) magicEffect->mData.mBlue / 255.f);
}
int numberOfEffects = ((MagicBoltState&)state).mEffects.mList.size();
lightDiffuseColor = osg::Vec4(lightDiffuseRed / numberOfEffects
, lightDiffuseGreen / numberOfEffects
, lightDiffuseBlue / numberOfEffects
, 1.0f);
}
else
{
// Case: no magical effects, but still creating light
lightDiffuseColor = osg::Vec4(0.814f, 0.682f, 0.652f, 1.0f);
}
// Add light
osg::ref_ptr<osg::Light> projectileLight(new osg::Light);
projectileLight->setAmbient(osg::Vec4(1.0f, 1.0f, 1.0f, 1.0f));
projectileLight->setDiffuse(lightDiffuseColor);
projectileLight->setSpecular(osg::Vec4(0.0f, 0.0f, 0.0f, 0.0f));
projectileLight->setConstantAttenuation(0.f);
projectileLight->setLinearAttenuation(0.1f);
projectileLight->setQuadraticAttenuation(0.f);
projectileLight->setPosition(osg::Vec4(pos, 1.0));
// Add light source
SceneUtil::LightSource* projectileLightSource = new SceneUtil::LightSource;
projectileLightSource->setNodeMask(MWRender::Mask_Lighting);
projectileLightSource->setRadius(66.f);
// Attach to scene node
state.mNode->addChild(projectileLightSource);
projectileLightSource->setLight(projectileLight);
}
SceneUtil::DisableFreezeOnCullVisitor disableFreezeOnCullVisitor; SceneUtil::DisableFreezeOnCullVisitor disableFreezeOnCullVisitor;
state.mNode->accept(disableFreezeOnCullVisitor); state.mNode->accept(disableFreezeOnCullVisitor);
@ -229,7 +278,7 @@ namespace MWWorld
MWWorld::ManualRef ref(MWBase::Environment::get().getWorld()->getStore(), state.mIdMagic.at(0)); MWWorld::ManualRef ref(MWBase::Environment::get().getWorld()->getStore(), state.mIdMagic.at(0));
MWWorld::Ptr ptr = ref.getPtr(); MWWorld::Ptr ptr = ref.getPtr();
createModel(state, ptr.getClass().getModel(ptr), pos, orient, true, texture); createModel(state, ptr.getClass().getModel(ptr), pos, orient, true, true, texture);
MWBase::SoundManager *sndMgr = MWBase::Environment::get().getSoundManager(); MWBase::SoundManager *sndMgr = MWBase::Environment::get().getSoundManager();
for (size_t it = 0; it != state.mSoundIds.size(); it++) for (size_t it = 0; it != state.mSoundIds.size(); it++)
@ -253,7 +302,7 @@ namespace MWWorld
MWWorld::ManualRef ref(MWBase::Environment::get().getWorld()->getStore(), projectile.getCellRef().getRefId()); MWWorld::ManualRef ref(MWBase::Environment::get().getWorld()->getStore(), projectile.getCellRef().getRefId());
MWWorld::Ptr ptr = ref.getPtr(); MWWorld::Ptr ptr = ref.getPtr();
createModel(state, ptr.getClass().getModel(ptr), pos, orient, false); createModel(state, ptr.getClass().getModel(ptr), pos, orient, false, false);
mProjectiles.push_back(state); mProjectiles.push_back(state);
} }
@ -369,7 +418,7 @@ namespace MWWorld
// Try to get a Ptr to the bow that was used. It might no longer exist. // Try to get a Ptr to the bow that was used. It might no longer exist.
MWWorld::Ptr bow = projectileRef.getPtr(); MWWorld::Ptr bow = projectileRef.getPtr();
if (!caster.isEmpty()) if (!caster.isEmpty() && it->mIdArrow != it->mBowId)
{ {
MWWorld::InventoryStore& inv = caster.getClass().getInventoryStore(caster); MWWorld::InventoryStore& inv = caster.getClass().getInventoryStore(caster);
MWWorld::ContainerStoreIterator invIt = inv.getSlot(MWWorld::InventoryStore::Slot_CarriedRight); MWWorld::ContainerStoreIterator invIt = inv.getSlot(MWWorld::InventoryStore::Slot_CarriedRight);
@ -483,7 +532,7 @@ namespace MWWorld
return true; return true;
} }
createModel(state, model, osg::Vec3f(esm.mPosition), osg::Quat(esm.mOrientation), false); createModel(state, model, osg::Vec3f(esm.mPosition), osg::Quat(esm.mOrientation), false, false);
mProjectiles.push_back(state); mProjectiles.push_back(state);
return true; return true;
@ -518,7 +567,7 @@ namespace MWWorld
return true; return true;
} }
createModel(state, model, osg::Vec3f(esm.mPosition), osg::Quat(esm.mOrientation), true, texture); createModel(state, model, osg::Vec3f(esm.mPosition), osg::Quat(esm.mOrientation), true, true, texture);
MWBase::SoundManager *sndMgr = MWBase::Environment::get().getSoundManager(); MWBase::SoundManager *sndMgr = MWBase::Environment::get().getSoundManager();

@ -122,7 +122,7 @@ namespace MWWorld
void moveProjectiles(float dt); void moveProjectiles(float dt);
void moveMagicBolts(float dt); void moveMagicBolts(float dt);
void createModel (State& state, const std::string& model, const osg::Vec3f& pos, const osg::Quat& orient, bool rotate, std::string texture = ""); void createModel (State& state, const std::string& model, const osg::Vec3f& pos, const osg::Quat& orient, bool rotate, bool createLight, std::string texture = "");
void update (State& state, float duration); void update (State& state, float duration);
void operator=(const ProjectileManager&); void operator=(const ProjectileManager&);

@ -421,11 +421,17 @@ namespace MWWorld
gmst["sBribeFail"] = ESM::Variant("Bribe Fail"); gmst["sBribeFail"] = ESM::Variant("Bribe Fail");
gmst["fNPCHealthBarTime"] = ESM::Variant(5.f); gmst["fNPCHealthBarTime"] = ESM::Variant(5.f);
gmst["fNPCHealthBarFade"] = ESM::Variant(1.f); gmst["fNPCHealthBarFade"] = ESM::Variant(1.f);
gmst["fFleeDistance"] = ESM::Variant(3000.f);
gmst["sMaxSale"] = ESM::Variant("Max Sale");
// Werewolf (BM) // Werewolf (BM)
gmst["fWereWolfRunMult"] = ESM::Variant(1.f); gmst["fWereWolfRunMult"] = ESM::Variant(1.3f);
gmst["fWereWolfSilverWeaponDamageMult"] = ESM::Variant(1.f); gmst["fWereWolfSilverWeaponDamageMult"] = ESM::Variant(2.f);
gmst["iWerewolfFightMod"] = ESM::Variant(1); gmst["iWerewolfFightMod"] = ESM::Variant(100);
gmst["iWereWolfFleeMod"] = ESM::Variant(100);
gmst["iWereWolfLevelToAttack"] = ESM::Variant(20);
gmst["iWereWolfBounty"] = ESM::Variant(1000);
gmst["fCombatDistanceWerewolfMod"] = ESM::Variant(0.3f);
std::map<std::string, ESM::Variant> globals; std::map<std::string, ESM::Variant> globals;
// vanilla Morrowind does not define dayspassed. // vanilla Morrowind does not define dayspassed.
@ -1295,7 +1301,7 @@ namespace MWWorld
float terrainHeight = -std::numeric_limits<float>::max(); float terrainHeight = -std::numeric_limits<float>::max();
if (ptr.getCell()->isExterior()) if (ptr.getCell()->isExterior())
terrainHeight = mRendering->getTerrainHeightAt(pos.asVec3()); terrainHeight = getTerrainHeightAt(pos.asVec3());
if (pos.pos[2] < terrainHeight) if (pos.pos[2] < terrainHeight)
pos.pos[2] = terrainHeight; pos.pos[2] = terrainHeight;
@ -2078,11 +2084,16 @@ namespace MWWorld
if (!cell->getCell()->hasWater()) if (!cell->getCell()->hasWater())
return true; return true;
// Based on observations from the original engine, the depth float waterlevel = cell->getWaterLevel();
// limit at which water walking can still be cast on a target
// in water appears to be the same as what the highest swimmable // SwimHeightScale affects the upper z position an actor can swim to
// z position would be with SwimHeightScale + 1. // while in water. Based on observation from the original engine,
return !isUnderwater(target, mSwimHeightScale + 1); // the upper z position you get with a +1 SwimHeightScale is the depth
// limit for being able to cast water walking on an underwater target.
if (isUnderwater(target, mSwimHeightScale + 1) || (isUnderwater(cell, target.getRefData().getPosition().asVec3()) && !mPhysics->canMoveToWaterSurface(target, waterlevel)))
return false; // not castable if too deep or if not enough room to move actor to surface
else
return true;
} }
bool World::isOnGround(const MWWorld::Ptr &ptr) const bool World::isOnGround(const MWWorld::Ptr &ptr) const
@ -2183,7 +2194,7 @@ namespace MWWorld
if (!actor) if (!actor)
throw std::runtime_error("can't find player"); throw std::runtime_error("can't find player");
if ((actor->getCollisionMode() && !mPhysics->isOnSolidGround(player)) || isUnderwater(currentCell, playerPos)) if ((actor->getCollisionMode() && !mPhysics->isOnSolidGround(player)) || isUnderwater(currentCell, playerPos) || isWalkingOnWater(player))
return 2; return 2;
if((currentCell->getCell()->mData.mFlags&ESM::Cell::NoSleep) || player.getClass().getNpcStats(player).isWerewolf()) if((currentCell->getCell()->mData.mFlags&ESM::Cell::NoSleep) || player.getClass().getNpcStats(player).isWerewolf())
@ -3121,6 +3132,19 @@ namespace MWWorld
return MWBase::Environment::get().getWindowManager()->containsMode(MWGui::GM_Jail); return MWBase::Environment::get().getWindowManager()->containsMode(MWGui::GM_Jail);
} }
float World::getTerrainHeightAt(const osg::Vec3f& worldPos) const
{
return mRendering->getTerrainHeightAt(worldPos);
}
osg::Vec3f World::getHalfExtents(const ConstPtr& actor, bool rendering) const
{
if (rendering)
return mPhysics->getRenderingHalfExtents(actor);
else
return mPhysics->getHalfExtents(actor);
}
void World::spawnRandomCreature(const std::string &creatureList) void World::spawnRandomCreature(const std::string &creatureList)
{ {
const ESM::CreatureLevList* list = getStore().get<ESM::CreatureLevList>().find(creatureList); const ESM::CreatureLevList* list = getStore().get<ESM::CreatureLevList>().find(creatureList);
@ -3289,7 +3313,7 @@ namespace MWWorld
} }
} }
bool World::isWalkingOnWater(const ConstPtr &actor) bool World::isWalkingOnWater(const ConstPtr &actor) const
{ {
const MWPhysics::Actor* physicActor = mPhysics->getActor(actor); const MWPhysics::Actor* physicActor = mPhysics->getActor(actor);
if (physicActor && physicActor->isWalkingOnWater()) if (physicActor && physicActor->isWalkingOnWater())

@ -651,7 +651,7 @@ namespace MWWorld
/// Resets all actors in the current active cells to their original location within that cell. /// Resets all actors in the current active cells to their original location within that cell.
virtual void resetActors(); virtual void resetActors();
virtual bool isWalkingOnWater (const MWWorld::ConstPtr& actor); virtual bool isWalkingOnWater (const MWWorld::ConstPtr& actor) const;
/// Return a vector aiming the actor's weapon towards a target. /// Return a vector aiming the actor's weapon towards a target.
/// @note The length of the vector is the distance between actor and target. /// @note The length of the vector is the distance between actor and target.
@ -661,6 +661,12 @@ namespace MWWorld
virtual float getHitDistance(const MWWorld::ConstPtr& actor, const MWWorld::ConstPtr& target); virtual float getHitDistance(const MWWorld::ConstPtr& actor, const MWWorld::ConstPtr& target);
virtual bool isPlayerInJail() const; virtual bool isPlayerInJail() const;
/// Return terrain height at \a worldPos position.
virtual float getTerrainHeightAt(const osg::Vec3f& worldPos) const;
/// Return physical or rendering half extents of the given actor.
virtual osg::Vec3f getHalfExtents(const MWWorld::ConstPtr& actor, bool rendering=false) const;
}; };
} }

@ -140,3 +140,6 @@ if (CMAKE_SYSTEM_NAME MATCHES "Linux")
target_link_libraries(openmw-wizard dl Xt) target_link_libraries(openmw-wizard dl Xt)
endif() endif()
if (WIN32)
INSTALL(TARGETS openmw-wizard RUNTIME DESTINATION ".")
endif(WIN32)

@ -24,7 +24,7 @@ Wizard::ComponentSelectionPage::ComponentSelectionPage(QWidget *parent) :
} }
void Wizard::ComponentSelectionPage::updateButton(QListWidgetItem *item) void Wizard::ComponentSelectionPage::updateButton(QListWidgetItem*)
{ {
if (field(QLatin1String("installation.new")).toBool() == true) if (field(QLatin1String("installation.new")).toBool() == true)
return; // Morrowind is always checked here return; // Morrowind is always checked here

@ -63,13 +63,13 @@ bool Wizard::ExistingInstallationPage::validatePage()
The Wizard needs to update settings in this file.<br><br> \ The Wizard needs to update settings in this file.<br><br> \
Press \"Browse...\" to specify the location manually.<br>")); Press \"Browse...\" to specify the location manually.<br>"));
QAbstractButton *browseButton = QAbstractButton *browseButton2 =
msgBox.addButton(QObject::tr("B&rowse..."), QMessageBox::ActionRole); msgBox.addButton(QObject::tr("B&rowse..."), QMessageBox::ActionRole);
msgBox.exec(); msgBox.exec();
QString iniFile; QString iniFile;
if (msgBox.clickedButton() == browseButton) { if (msgBox.clickedButton() == browseButton2) {
iniFile = QFileDialog::getOpenFileName( iniFile = QFileDialog::getOpenFileName(
this, this,
QObject::tr("Select configuration file"), QObject::tr("Select configuration file"),

@ -20,12 +20,6 @@ int main(int argc, char *argv[])
QDir dir(QCoreApplication::applicationDirPath()); QDir dir(QCoreApplication::applicationDirPath());
#ifdef Q_OS_MAC #ifdef Q_OS_MAC
if (dir.dirName() == "MacOS") {
dir.cdUp();
dir.cdUp();
dir.cdUp();
}
// force Qt to load only LOCAL plugins, don't touch system Qt installation // force Qt to load only LOCAL plugins, don't touch system Qt installation
QDir pluginsPath(QCoreApplication::applicationDirPath()); QDir pluginsPath(QCoreApplication::applicationDirPath());
pluginsPath.cdUp(); pluginsPath.cdUp();

@ -162,10 +162,10 @@ void Wizard::MainWizard::setupGameSettings()
paths.append(QLatin1String("openmw.cfg")); paths.append(QLatin1String("openmw.cfg"));
paths.append(globalPath + QLatin1String("openmw.cfg")); paths.append(globalPath + QLatin1String("openmw.cfg"));
foreach (const QString &path, paths) { foreach (const QString &path2, paths) {
qDebug() << "Loading config file:" << path.toUtf8().constData(); qDebug() << "Loading config file:" << path2.toUtf8().constData();
QFile file(path); file.setFileName(path2);
if (file.exists()) { if (file.exists()) {
if (!file.open(QIODevice::ReadOnly | QIODevice::Text)) { if (!file.open(QIODevice::ReadOnly | QIODevice::Text)) {
QMessageBox msgBox; QMessageBox msgBox;

@ -77,7 +77,7 @@ add_component_dir (esm
loadweap records aipackage effectlist spelllist variant variantimp loadtes3 cellref filter loadweap records aipackage effectlist spelllist variant variantimp loadtes3 cellref filter
savedgame journalentry queststate locals globalscript player objectstate cellid cellstate globalmap inventorystate containerstate npcstate creaturestate dialoguestate statstate savedgame journalentry queststate locals globalscript player objectstate cellid cellstate globalmap inventorystate containerstate npcstate creaturestate dialoguestate statstate
npcstats creaturestats weatherstate quickkeys fogstate spellstate activespells creaturelevliststate doorstate projectilestate debugprofile npcstats creaturestats weatherstate quickkeys fogstate spellstate activespells creaturelevliststate doorstate projectilestate debugprofile
aisequence magiceffects util custommarkerstate stolenitems transport animationstate aisequence magiceffects util custommarkerstate stolenitems transport animationstate controlsstate
) )
add_component_dir (esmterrain add_component_dir (esmterrain
@ -206,7 +206,7 @@ target_link_libraries(components
${OSGFX_LIBRARIES} ${OSGFX_LIBRARIES}
${OSGANIMATION_LIBRARIES} ${OSGANIMATION_LIBRARIES}
${Bullet_LIBRARIES} ${Bullet_LIBRARIES}
${SDL2_LIBRARY} ${SDL2_LIBRARIES}
# For MyGUI platform # For MyGUI platform
${GL_LIB} ${GL_LIB}
${MyGUI_LIBRARIES} ${MyGUI_LIBRARIES}

@ -110,26 +110,26 @@ Qt::ItemFlags ContentSelectorModel::ContentModel::flags(const QModelIndex &index
bool gamefileChecked = (file->gameFiles().count() == 0); bool gamefileChecked = (file->gameFiles().count() == 0);
foreach (const QString &fileName, file->gameFiles()) foreach (const QString &fileName, file->gameFiles())
{ {
foreach (EsmFile *dependency, mFiles) for (QListIterator<EsmFile *> dependencyIter(mFiles); dependencyIter.hasNext(); dependencyIter.next())
{ {
//compare filenames only. Multiple instances //compare filenames only. Multiple instances
//of the filename (with different paths) is not relevant here. //of the filename (with different paths) is not relevant here.
bool depFound = (dependency->fileName().compare(fileName, Qt::CaseInsensitive) == 0); bool depFound = (dependencyIter.peekNext()->fileName().compare(fileName, Qt::CaseInsensitive) == 0);
if (!depFound) if (!depFound)
continue; continue;
if (!gamefileChecked) if (!gamefileChecked)
{ {
if (isChecked (dependency->filePath())) if (isChecked (dependencyIter.peekNext()->filePath()))
gamefileChecked = (dependency->isGameFile()); gamefileChecked = (dependencyIter.peekNext()->isGameFile());
} }
// force it to iterate all files in cases where the current // force it to iterate all files in cases where the current
// dependency is a game file to ensure that a later duplicate // dependency is a game file to ensure that a later duplicate
// game file is / is not checked. // game file is / is not checked.
// (i.e., break only if it's not a gamefile or the game file has been checked previously) // (i.e., break only if it's not a gamefile or the game file has been checked previously)
if (gamefileChecked || !(dependency->isGameFile())) if (gamefileChecked || !(dependencyIter.peekNext()->isGameFile()))
break; break;
} }
} }
@ -283,12 +283,11 @@ bool ContentSelectorModel::ContentModel::setData(const QModelIndex &index, const
else else
return success; return success;
foreach (EsmFile *file2, mFiles)
foreach (EsmFile *file, mFiles)
{ {
if (file->gameFiles().contains(fileName, Qt::CaseInsensitive)) if (file2->gameFiles().contains(fileName, Qt::CaseInsensitive))
{ {
QModelIndex idx = indexFromItem(file); QModelIndex idx = indexFromItem(file2);
emit dataChanged(idx, idx); emit dataChanged(idx, idx);
} }
} }
@ -425,9 +424,9 @@ void ContentSelectorModel::ContentModel::addFiles(const QString &path)
filters << "*.esp" << "*.esm" << "*.omwgame" << "*.omwaddon"; filters << "*.esp" << "*.esm" << "*.omwgame" << "*.omwaddon";
dir.setNameFilters(filters); dir.setNameFilters(filters);
foreach (const QString &path, dir.entryList()) foreach (const QString &path2, dir.entryList())
{ {
QFileInfo info(dir.absoluteFilePath(path)); QFileInfo info(dir.absoluteFilePath(path2));
if (item(info.absoluteFilePath()) != 0) if (item(info.absoluteFilePath()) != 0)
continue; continue;
@ -437,12 +436,13 @@ void ContentSelectorModel::ContentModel::addFiles(const QString &path)
ToUTF8::Utf8Encoder encoder = ToUTF8::Utf8Encoder encoder =
ToUTF8::calculateEncoding(mEncoding.toStdString()); ToUTF8::calculateEncoding(mEncoding.toStdString());
fileReader.setEncoder(&encoder); fileReader.setEncoder(&encoder);
fileReader.open(std::string(dir.absoluteFilePath(path).toUtf8().constData())); fileReader.open(std::string(dir.absoluteFilePath(path2).toUtf8().constData()));
EsmFile *file = new EsmFile(path);
foreach (const ESM::Header::MasterData &item, fileReader.getGameFiles()) EsmFile *file = new EsmFile(path2);
file->addGameFile(QString::fromUtf8(item.name.c_str()));
for (std::vector<ESM::Header::MasterData>::const_iterator itemIter = fileReader.getGameFiles().begin();
itemIter != fileReader.getGameFiles().end(); ++itemIter)
file->addGameFile(QString::fromUtf8(itemIter->name.c_str()));
file->setAuthor (QString::fromUtf8(fileReader.getAuthor().c_str())); file->setAuthor (QString::fromUtf8(fileReader.getAuthor().c_str()));
file->setDate (info.lastModified()); file->setDate (info.lastModified());

@ -192,8 +192,8 @@ void ContentSelectorView::ContentSelector::setGameFileSelected(int index, bool s
const ContentSelectorModel::EsmFile* file = mContentModel->item(fileName); const ContentSelectorModel::EsmFile* file = mContentModel->item(fileName);
if (file != NULL) if (file != NULL)
{ {
QModelIndex index(mContentModel->indexFromItem(file)); QModelIndex index2(mContentModel->indexFromItem(file));
mContentModel->setData(index, selected, Qt::UserRole + 1); mContentModel->setData(index2, selected, Qt::UserRole + 1);
} }
} }

@ -21,7 +21,18 @@ namespace ESM
anim.mGroup = esm.getHString(); anim.mGroup = esm.getHString();
esm.getHNOT(anim.mTime, "TIME"); esm.getHNOT(anim.mTime, "TIME");
esm.getHNOT(anim.mAbsolute, "ABST"); esm.getHNOT(anim.mAbsolute, "ABST");
esm.getHNT(anim.mLoopCount, "COUN");
esm.getSubNameIs("COUN");
// workaround bug in earlier version where size_t was used
esm.getSubHeader();
if (esm.getSubSize() == 8)
esm.getT(anim.mLoopCount);
else
{
uint32_t loopcount;
esm.getT(loopcount);
anim.mLoopCount = (uint64_t) loopcount;
}
mScriptedAnims.push_back(anim); mScriptedAnims.push_back(anim);
} }

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

Loading…
Cancel
Save