# Conflicts:
#	docs/source/openmw-mods/index.rst
pull/124/head
Ryan Tucker 8 years ago
commit bf805813e5

@ -1,6 +1,6 @@
os:
- linux
- osx
# - osx
osx_image: xcode7.2
language: cpp
sudo: required

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

@ -1,10 +1,11 @@
#!/bin/sh
brew update
brew rm cmake || true
brew rm pkgconfig || 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
unzip ~/openmw-deps.zip -d /private/tmp/openmw-deps > /dev/null

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

@ -46,7 +46,7 @@ if(EXISTS ${PROJECT_SOURCE_DIR}/.git)
else(NOT EXISTS ${PROJECT_SOURCE_DIR}/.git/shallow)
message(STATUS "Shallow Git clone detected, not attempting to retrieve version info")
endif(NOT EXISTS ${PROJECT_SOURCE_DIR}/.git/shallow)
endif(EXISTS ${PROJECT_SOURCE_DIR}/.git)
endif(EXISTS ${PROJECT_SOURCE_DIR}/.git)
# Macros
include(OpenMWMacros)
@ -96,7 +96,7 @@ endif()
# Set up common paths
if (APPLE)
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)
# Paths
SET(BINDIR "${CMAKE_INSTALL_PREFIX}/bin" CACHE PATH "Where to install binaries")
@ -286,6 +286,11 @@ endif (APPLE)
# Set up DEBUG define
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/)
# Specify build paths
@ -307,11 +312,15 @@ endif (APPLE)
configure_file(${OpenMW_SOURCE_DIR}/files/settings-default.cfg
"${OpenMW_BINARY_DIR}/settings-default.cfg")
configure_file(${OpenMW_SOURCE_DIR}/files/openmw.cfg.local
"${OpenMW_BINARY_DIR}/openmw.cfg")
configure_file(${OpenMW_SOURCE_DIR}/files/openmw.cfg
"${OpenMW_BINARY_DIR}/openmw.cfg.install")
if (NOT APPLE)
configure_file(${OpenMW_SOURCE_DIR}/files/openmw.cfg.local
"${OpenMW_BINARY_DIR}/openmw.cfg")
configure_file(${OpenMW_SOURCE_DIR}/files/openmw.cfg
"${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
"${OpenMW_BINARY_DIR}/openmw-cs.cfg")
@ -419,8 +428,10 @@ IF(NOT WIN32 AND NOT APPLE)
ENDIF(NOT WIN32 AND NOT APPLE)
if(WIN32)
FILE(GLOB dll_files "${OpenMW_BINARY_DIR}/Release/*.dll")
INSTALL(FILES ${dll_files} DESTINATION ".")
FILE(GLOB dll_files_debug "${OpenMW_BINARY_DIR}/Debug/*.dll")
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_SOURCE_DIR}/CHANGELOG.md" DESTINATION "." RENAME "CHANGELOG.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_BINARY_DIR}/settings-default.cfg"
"${OpenMW_BINARY_DIR}/gamecontrollerdb.txt"
"${OpenMW_BINARY_DIR}/Release/openmw.exe"
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)
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)
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()
INSTALL(DIRECTORY "${OpenMW_BINARY_DIR}/resources" DESTINATION ".")
FILE(GLOB plugin_dir "${OpenMW_BINARY_DIR}/Release/osgPlugins-*")
INSTALL(DIRECTORY ${plugin_dir} DESTINATION ".")
FILE(GLOB plugin_dir_debug "${OpenMW_BINARY_DIR}/Debug/osgPlugins-*")
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_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)
endif ()
set(INSTALL_SUBDIR OpenMW)
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)
install(DIRECTORY "${APP_BUNDLE_DIR}" USE_SOURCE_PERMISSIONS DESTINATION "." COMPONENT Runtime)
set(CPACK_GENERATOR "DragNDrop")
set(CPACK_PACKAGE_VERSION ${OPENMW_VERSION})
@ -740,8 +731,8 @@ if (APPLE)
set(CPACK_PACKAGE_VERSION_MINOR ${OPENMW_VERSION_MINOR})
set(CPACK_PACKAGE_VERSION_PATCH ${OPENMW_VERSION_RELEASE})
set(INSTALLED_OPENMW_APP "\${CMAKE_INSTALL_PREFIX}/${INSTALL_SUBDIR}/${APP_BUNDLE_NAME}")
set(INSTALLED_OPENCS_APP "\${CMAKE_INSTALL_PREFIX}/${INSTALL_SUBDIR}/${OPENCS_BUNDLE_NAME}")
set(INSTALLED_OPENMW_APP "\${CMAKE_INSTALL_PREFIX}/${APP_BUNDLE_NAME}")
set(INSTALLED_OPENCS_APP "\${CMAKE_INSTALL_PREFIX}/${OPENCS_BUNDLE_NAME}")
install(CODE "
set(BU_CHMOD_BUNDLE_ITEMS ON)
@ -785,8 +776,8 @@ if (APPLE)
set(${plugins_var} ${PLUGINS} PARENT_SCOPE)
endfunction (install_plugins_for_bundle)
install_plugins_for_bundle("${INSTALL_SUBDIR}/${APP_BUNDLE_NAME}" PLUGINS)
install_plugins_for_bundle("${INSTALL_SUBDIR}/${OPENCS_BUNDLE_NAME}" OPENCS_PLUGINS)
install_plugins_for_bundle("${APP_BUNDLE_NAME}" 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(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}
COMMENT "Generating documentation for the github-pages at ${DOXYGEN_PAGES_OUTPUT_DIR}" VERBATIM)
endif ()

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

@ -271,23 +271,34 @@ private:
class ConvertPCDT : public Converter
{
public:
ConvertPCDT() : mFirstPersonCam(true) {}
ConvertPCDT()
: mFirstPersonCam(true),
mTeleportingEnabled(true),
mLevitationEnabled(true)
{}
virtual void read(ESM::ESMReader &esm)
{
PCDT pcdt;
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)
{
esm.startRecord(ESM::REC_ENAB);
esm.writeHNT("TELE", mTeleportingEnabled);
esm.writeHNT("LEVT", mLevitationEnabled);
esm.endRecord(ESM::REC_ENAB);
esm.startRecord(ESM::REC_CAM_);
esm.writeHNT("FIRS", mFirstPersonCam);
esm.endRecord(ESM::REC_CAM_);
}
private:
bool mFirstPersonCam;
bool mTeleportingEnabled;
bool mLevitationEnabled;
};
class ConvertCNTC : public Converter

@ -5,7 +5,7 @@
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.mObject.mNpcStats.mBounty = pcdt.mBounty;
@ -25,18 +25,28 @@ namespace ESSImport
out.mObject.mNpcStats.mSkills[i].mProgress = pcdt.mPNAM.mSkillProgress[i];
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;
if (pcdt.mPNAM.mDrawState & PCDT::DrawState_Spell)
if (pcdt.mPNAM.mPlayerFlags & PCDT::PlayerFlags_SpellDrawn)
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();
it != pcdt.mKnownDialogueTopics.end(); ++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 <components/esm/player.hpp>
#include <components/esm/controlsstate.hpp>
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)
{
assert(image->data(x,y));
*(image->data(x,y)+2) = *it++;
*(image->data(x,y)+1) = *it++;
*image->data(x,y) = *it++;
@ -422,6 +423,10 @@ namespace ESSImport
writer.startRecord (ESM::REC_DIAS);
context.mDialogueState.save(writer);
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/loadcrea.hpp>
#include <components/esm/loadnpc.hpp>
#include <components/esm/controlsstate.hpp>
#include "importnpcc.hpp"
#include "importcrec.hpp"
@ -32,6 +33,8 @@ namespace ESSImport
ESM::DialogueState mDialogueState;
ESM::ControlsState mControlsState;
// cells which should show an explored overlay on the global map
std::set<std::pair<int, int> > mExploredCells;

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

@ -13,7 +13,7 @@ namespace ESM
namespace ESSImport
{
/// Local variable assigments for a running script
/// Local variable assignments for a running script
struct SCRI
{
std::string mScript;

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

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

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

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

@ -162,9 +162,15 @@ endif()
include_directories(${CMAKE_CURRENT_BINARY_DIR})
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()
set (OPENCS_MAC_ICON "")
set (OPENCS_CFG "")
set (OPENCS_DEFAULT_FILTERS_FILE "")
set (OPENCS_OPENMW_CFG "")
endif(APPLE)
add_executable(openmw-cs
@ -174,12 +180,23 @@ add_executable(openmw-cs
${OPENCS_MOC_SRC}
${OPENCS_RES_SRC}
${OPENCS_MAC_ICON}
${OPENCS_CFG}
${OPENCS_DEFAULT_FILTERS_FILE}
${OPENCS_OPENMW_CFG}
)
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
RUNTIME_OUTPUT_DIRECTORY "${OpenMW_BINARY_DIR}"
OUTPUT_NAME "OpenMW-CS"
OUTPUT_NAME ${OPENCS_BUNDLE_NAME}
MACOSX_BUNDLE_ICON_FILE "openmw-cs.icns"
MACOSX_BUNDLE_BUNDLE_NAME "OpenCS"
MACOSX_BUNDLE_GUI_IDENTIFIER "org.openmw.opencs"
@ -190,6 +207,16 @@ if(APPLE)
set_source_files_properties(${OPENCS_MAC_ICON} PROPERTIES
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)
target_link_libraries(openmw-cs
@ -223,9 +250,18 @@ endif()
if (WIN32)
target_link_libraries(openmw-cs ${Boost_LOCALE_LIBRARY})
INSTALL(TARGETS openmw-cs RUNTIME DESTINATION ".")
INSTALL(FILES "${OpenMW_BINARY_DIR}/openmw-cs.cfg" DESTINATION ".")
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)
INSTALL(TARGETS openmw-cs BUNDLE DESTINATION OpenMW COMPONENT BUNDLE)
INSTALL(TARGETS openmw-cs BUNDLE DESTINATION "." COMPONENT BUNDLE)
endif()

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

@ -29,7 +29,7 @@ namespace CSMPrefs
enum SecondaryMode
{
SM_Replace, ///< The secondary signal replaces the regular signal when the modifier is active
SM_Detach, ///< The secondary signal is emitted independant of the regular signal, even if not active
SM_Detach, ///< The secondary signal is emitted independent of the regular signal, even if not active
SM_Ignore ///< The secondary signal will not ever be emitted
};

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

@ -659,7 +659,7 @@ void CSMTools::ReferenceableCheckStage::npcCheck (
{
if ((npc.mFlags & ESM::NPC::Autocalc) == 0) //0x0010 = autocalculated flag
{
messages.push_back (std::make_pair (id, npc.mId + " mNpdtType or flags mismatch!")); //should not happend?
messages.push_back (std::make_pair (id, npc.mId + " mNpdtType or flags mismatch!")); //should not happen?
return;
}
@ -915,7 +915,7 @@ void CSMTools::ReferenceableCheckStage::inventoryListCheck(
id + " contains non-existing item (" + itemName + ")"));
else
{
// Needs to accomodate Containers, Creatures, and NPCs
// Needs to accommodate containers, creatures, and NPCs
switch (localIndex.second)
{
case CSMWorld::UniversalId::Type_Potion:

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

@ -198,12 +198,12 @@ QModelIndex CSMWorld::IdTree::parent (const QModelIndex& index) const
return QModelIndex();
unsigned int id = index.internalId();
const std::pair<int, int>& adress(unfoldIndexAddress(id));
const std::pair<int, int>& address(unfoldIndexAddress(id));
if (adress.first >= this->rowCount() || adress.second >= this->columnCount())
if (address.first >= this->rowCount() || address.second >= this->columnCount())
throw "Parent index is not present in the model";
return createIndex(adress.first, adress.second);
return createIndex(address.first, address.second);
}
unsigned int CSMWorld::IdTree::foldIndexAddress (const QModelIndex& index) const

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

@ -50,7 +50,7 @@ namespace CSVRender
updateCellData(mData.getCells().getRecord(cellIndex));
}
// Keep water existance/height up to date
// Keep water existence/height up to date
QAbstractItemModel* cells = mData.getTableModel(CSMWorld::UniversalId::Type_Cells);
connect(cells, SIGNAL(dataChanged(const QModelIndex&, const QModelIndex&)),
this, SLOT(cellDataChanged(const QModelIndex&, const QModelIndex&)));

@ -516,7 +516,7 @@ void CSVRender::PagedWorldspaceWidget::useViewHint (const std::string& hint)
// Current coordinate
int x, y;
// Loop throught all the coordinates to add them to selection
// Loop through all the coordinates to add them to selection
while (stream >> ignore1 >> ignore2 >> x >> y)
selection.add (CSMWorld::CellCoordinates (x, y));

@ -214,7 +214,7 @@ SceneWidget::SceneWidget(boost::shared_ptr<Resource::ResourceSystem> resourceSys
SceneWidget::~SceneWidget()
{
// Since we're holding on to the scene templates past the existance of this graphics context, we'll need to manually release the created objects
// Since we're holding on to the scene templates past the existence of this graphics context, we'll need to manually release the created objects
mResourceSystem->getSceneManager()->releaseGLObjects(mView->getCamera()->getGraphicsContext()->getState());
}

@ -45,8 +45,8 @@ namespace CSVWorld
///< \note Non-existent cells are not listed.
QModelIndexList getSelectedCells (bool existent = true, bool nonExistent = false) const;
///< \param existant Include existant cells.
/// \param nonExistant Include non-existant cells.
///< \param existent Include existent cells.
/// \param nonExistent Include non-existent cells.
QModelIndexList getMissingRegionCells() const;
///< Unselected cells within all regions that have at least one selected cell.

@ -42,7 +42,7 @@ add_openmw_dir (mwgui
itemmodel containeritemmodel inventoryitemmodel sortfilteritemmodel itemview
tradeitemmodel companionitemmodel pickpocketitemmodel controllers savegamedialog
recharge mode videowidget backgroundimage itemwidget screenfader debugwindow spellmodel spellview
draganddrop timeadvancer jailscreen
draganddrop timeadvancer jailscreen itemchargeview
)
add_openmw_dir (mwdialogue
@ -179,6 +179,21 @@ target_link_libraries(openmw ${CMAKE_THREAD_LIBS_INIT})
endif()
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(IOKIT_FRAMEWORK IOKit)
target_link_libraries(openmw ${COCOA_FRAMEWORK} ${IOKIT_FRAMEWORK})
@ -186,7 +201,7 @@ if(APPLE)
if (FFmpeg_FOUND)
find_library(COREVIDEO_FRAMEWORK CoreVideo)
find_library(VDA_FRAMEWORK VideoDecodeAcceleration)
target_link_libraries(openmw ${COREVIDEO_FRAMEWORK} ${VDA_FRAMEWORK})
target_link_libraries(openmw z ${COREVIDEO_FRAMEWORK} ${VDA_FRAMEWORK})
endif()
endif(APPLE)
@ -202,3 +217,8 @@ if (MSVC)
endif (CMAKE_CL_64)
add_definitions("-D_USE_MATH_DEFINES")
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);
// Create sound system
mEnvironment.setSoundManager (new MWSound::SoundManager(mVFS.get(), mUseSound));
mEnvironment.setSoundManager (new MWSound::SoundManager(mVFS.get(), mFallbackMap, mUseSound));
if (!mSkipMenu)
{

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

@ -5,6 +5,19 @@
#include <set>
#include <vector>
#include <stdint.h>
namespace Loading
{
class Listener;
}
namespace ESM
{
class ESMReader;
class ESMWriter;
}
namespace MWBase
{
/// \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
/// @return true if joystick, false otherwise
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;
};
}

@ -233,7 +233,7 @@ namespace MWBase
virtual void removeDialog(MWGui::Layout* dialog) = 0;
///Gracefully attempts to exit the topmost GUI mode
/** No guarentee of actually closing the window **/
/** No guarantee of actually closing the window **/
virtual void exitCurrentGuiMode() = 0;
virtual void messageBox (const std::string& message, enum MWGui::ShowInDialogueMode showInDialogueMode = MWGui::ShowInDialogueMode_IfPossible) = 0;

@ -548,7 +548,7 @@ namespace MWBase
/// Resets all actors in the current active cells to their original location within that cell.
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.
/// @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 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();
MWWorld::ManualRef ref(store, id);
ref.getPtr().getCellRef().setPosition(ptr.getCellRef().getPosition());
MWWorld::Ptr placed = MWBase::Environment::get().getWorld()->placeObject(ref.getPtr(), ptr.getCell() , ptr.getCellRef().getPosition());
MWWorld::ManualRef manualRef(store, id);
manualRef.getPtr().getCellRef().setPosition(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.mSpawn = false;
}

@ -174,7 +174,7 @@ namespace MWDialogue
executeScript (info->mResultScript);
mLastTopic = Misc::StringUtils::lowerCase(it->mId);
// update topics again to accomodate changes resulting from executeScript
// update topics again to accommodate changes resulting from executeScript
updateTopics();
return;

@ -200,15 +200,15 @@ namespace MWGui
std::set<MWMechanics::EffectKey> effectIds = mAlchemy->listEffects();
Widgets::SpellEffectList list;
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;
params.mEffectID = it->mId;
const ESM::MagicEffect* magicEffect = MWBase::Environment::get().getWorld()->getStore().get<ESM::MagicEffect>().find(it->mId);
params.mEffectID = it2->mId;
const ESM::MagicEffect* magicEffect = MWBase::Environment::get().getWorld()->getStore().get<ESM::MagicEffect>().find(it2->mId);
if (magicEffect->mData.mFlags & ESM::MagicEffect::TargetSkill)
params.mSkill = it->mArg;
params.mSkill = it2->mArg;
else if (magicEffect->mData.mFlags & ESM::MagicEffect::TargetAttribute)
params.mAttribute = it->mArg;
params.mAttribute = it2->mArg;
params.mIsConstant = true;
params.mNoTarget = true;

@ -226,7 +226,7 @@ namespace MWGui
coord.top += lineHeight;
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;
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);
}
void CharacterCreation::onFrame(float duration)
{
if (mReviewDialog)
mReviewDialog->onFrame(duration);
}
void CharacterCreation::spawnDialog(const char id)
{
try

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

@ -85,8 +85,8 @@ void InventoryItemModel::update()
if (mActor.getClass().hasInventoryStore(mActor))
{
MWWorld::InventoryStore& store = mActor.getClass().getInventoryStore(mActor);
if (store.isEquipped(newItem.mBase))
MWWorld::InventoryStore& invStore = mActor.getClass().getInventoryStore(mActor);
if (invStore.isEquipped(newItem.mBase))
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)
mFrame->setImageTexture("");
if (mItemShadow)
mItemShadow->setImageTexture("");
mItem->setImageTexture("");
mText->setCaption("");
return;

@ -5,6 +5,8 @@
#include <MyGUI_ScrollView.h>
#include <MyGUI_Gui.h>
#include <components/widgets/box.hpp>
#include <components/misc/rng.hpp>
#include "../mwbase/world.hpp"
@ -21,6 +23,9 @@
#include "widgets.hpp"
#include "itemwidget.hpp"
#include "itemchargeview.hpp"
#include "sortfilteritemmodel.hpp"
#include "inventoryitemmodel.hpp"
namespace MWGui
{
@ -29,13 +34,15 @@ Recharge::Recharge()
: WindowBase("openmw_recharge_dialog.layout")
{
getWidget(mBox, "Box");
getWidget(mView, "View");
getWidget(mGemBox, "GemBox");
getWidget(mGemIcon, "GemIcon");
getWidget(mChargeLabel, "ChargeLabel");
getWidget(mCancelButton, "CancelButton");
mCancelButton->eventMouseButtonClick += MyGUI::newDelegate(this, &Recharge::onCancel);
mBox->eventItemClicked += MyGUI::newDelegate(this, &Recharge::onItemClicked);
mBox->setDisplayMode(ItemChargeView::DisplayMode_EnchantmentCharge);
setVisible(false);
}
@ -43,8 +50,13 @@ Recharge::Recharge()
void Recharge::open()
{
center();
SortFilterItemModel * model = new SortFilterItemModel(new InventoryItemModel(MWMechanics::getPlayer()));
model->setFilter(SortFilterItemModel::Filter_OnlyRechargable);
mBox->setModel(model);
// Reset scrollbars
mView->setViewOffset(MyGUI::IntPoint(0, 0));
mBox->resetScrollbars();
}
void Recharge::exit()
@ -72,66 +84,16 @@ void Recharge::updateView()
bool toolBoxVisible = (gem.getRefData().getCount() != 0);
mGemBox->setVisible(toolBoxVisible);
mGemBox->setUserString("Hidden", toolBoxVisible ? "false" : "true");
bool toolBoxWasVisible = (mBox->getPosition().top != mGemBox->getPosition().top);
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));
mBox->update();
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();
MWWorld::ContainerStore& store = player.getClass().getContainerStore(player);
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);
box->notifyChildrenSizeChanged();
center();
}
void Recharge::onCancel(MyGUI::Widget *sender)
@ -139,15 +101,13 @@ void Recharge::onCancel(MyGUI::Widget *sender)
exit();
}
void Recharge::onItemClicked(MyGUI::Widget *sender)
void Recharge::onItemClicked(MyGUI::Widget *sender, const MWWorld::Ptr& item)
{
MWWorld::Ptr gem = *mGemIcon->getUserData<MWWorld::Ptr>();
if (!gem.getRefData().getCount())
return;
MWWorld::Ptr item = *sender->getUserData<MWWorld::Ptr>();
MWWorld::Ptr player = MWMechanics::getPlayer();
MWMechanics::CreatureStats& stats = player.getClass().getCreatureStats(player);
MWMechanics::NpcStats& npcStats = player.getClass().getNpcStats(player);
@ -198,12 +158,4 @@ void Recharge::onItemClicked(MyGUI::Widget *sender)
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 ItemChargeView;
class Recharge : public WindowBase
{
@ -25,8 +26,7 @@ public:
void start (const MWWorld::Ptr& gem);
protected:
MyGUI::Widget* mBox;
MyGUI::ScrollView* mView;
ItemChargeView* mBox;
MyGUI::Widget* mGemBox;
@ -38,7 +38,7 @@ protected:
void updateView();
void onItemClicked (MyGUI::Widget* sender);
void onItemClicked (MyGUI::Widget* sender, const MWWorld::Ptr& item);
void onCancel (MyGUI::Widget* sender);
void onMouseWheel(MyGUI::Widget* _sender, int _rel);

@ -4,6 +4,9 @@
#include <MyGUI_ScrollView.h>
#include <MyGUI_Gui.h>
#include <MyGUI_ItemBox.h>
#include <components/widgets/box.hpp>
#include "../mwbase/world.hpp"
#include "../mwbase/environment.hpp"
@ -17,6 +20,9 @@
#include "widgets.hpp"
#include "itemwidget.hpp"
#include "itemchargeview.hpp"
#include "sortfilteritemmodel.hpp"
#include "inventoryitemmodel.hpp"
namespace MWGui
{
@ -25,7 +31,6 @@ Repair::Repair()
: WindowBase("openmw_repair.layout")
{
getWidget(mRepairBox, "RepairBox");
getWidget(mRepairView, "RepairView");
getWidget(mToolBox, "ToolBox");
getWidget(mToolIcon, "ToolIcon");
getWidget(mUsesLabel, "UsesLabel");
@ -33,13 +38,21 @@ Repair::Repair()
getWidget(mCancelButton, "CancelButton");
mCancelButton->eventMouseButtonClick += MyGUI::newDelegate(this, &Repair::onCancel);
mRepairBox->eventItemClicked += MyGUI::newDelegate(this, &Repair::onRepairItem);
mRepairBox->setDisplayMode(ItemChargeView::DisplayMode_Health);
}
void Repair::open()
{
center();
SortFilterItemModel * model = new SortFilterItemModel(new InventoryItemModel(MWMechanics::getPlayer()));
model->setFilter(SortFilterItemModel::Filter_OnlyRepairable);
mRepairBox->setModel(model);
// Reset scrollbars
mRepairView->setViewOffset(MyGUI::IntPoint(0, 0));
mRepairBox->resetScrollbars();
}
void Repair::exit()
@ -75,89 +88,31 @@ void Repair::updateRepairView()
bool toolBoxVisible = (mRepair.getTool().getRefData().getCount() != 0);
mToolBox->setVisible(toolBoxVisible);
mToolBox->setUserString("Hidden", toolBoxVisible ? "false" : "true");
mRepairBox->update();
bool toolBoxWasVisible = (mRepairBox->getPosition().top != mToolBox->getPosition().top);
if (toolBoxVisible && !toolBoxWasVisible)
{
// shrink
mRepairBox->setPosition(mRepairBox->getPosition() + MyGUI::IntPoint(0,mToolBox->getSize().height));
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);
Gui::Box* box = dynamic_cast<Gui::Box*>(mMainWidget);
if (box == NULL)
throw std::runtime_error("main widget must be a box");
box->notifyChildrenSizeChanged();
center();
}
void Repair::onCancel(MyGUI::Widget *sender)
void Repair::onCancel(MyGUI::Widget* /*sender*/)
{
exit();
}
void Repair::onRepairItem(MyGUI::Widget *sender)
void Repair::onRepairItem(MyGUI::Widget* /*sender*/, const MWWorld::Ptr& ptr)
{
if (!mRepair.getTool().getRefData().getCount())
return;
mRepair.repair(*sender->getUserData<MWWorld::Ptr>());
mRepair.repair(ptr);
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 ItemChargeView;
class Repair : public WindowBase
{
@ -22,8 +23,7 @@ public:
void startRepairItem (const MWWorld::Ptr& item);
protected:
MyGUI::Widget* mRepairBox;
MyGUI::ScrollView* mRepairView;
ItemChargeView* mRepairBox;
MyGUI::Widget* mToolBox;
@ -38,9 +38,8 @@ protected:
void updateRepairView();
void onRepairItem (MyGUI::Widget* sender);
void onCancel (MyGUI::Widget* sender);
void onMouseWheel(MyGUI::Widget* _sender, int _rel);
void onRepairItem(MyGUI::Widget* sender, const MWWorld::Ptr& ptr);
void onCancel(MyGUI::Widget* sender);
};

@ -10,6 +10,7 @@
#include "../mwbase/world.hpp"
#include "../mwbase/windowmanager.hpp"
#include "../mwworld/esmstore.hpp"
#include "../mwmechanics/autocalcspell.hpp"
#include "tooltips.hpp"
@ -29,7 +30,8 @@ namespace MWGui
const int ReviewDialog::sLineHeight = 18;
ReviewDialog::ReviewDialog()
: WindowModal("openmw_chargen_review.layout")
: WindowModal("openmw_chargen_review.layout"),
mUpdateSkillArea(false)
{
// Centre dialog
center();
@ -102,7 +104,16 @@ namespace MWGui
void ReviewDialog::open()
{
WindowModal::open();
updateSkillArea();
mUpdateSkillArea = true;
}
void ReviewDialog::onFrame(float /*duration*/)
{
if (mUpdateSkillArea)
{
updateSkillArea();
mUpdateSkillArea = false;
}
}
void ReviewDialog::setPlayerName(const std::string &name)
@ -121,6 +132,8 @@ namespace MWGui
ToolTips::createRaceToolTip(mRaceWidget, race);
mRaceWidget->setCaption(race->mName);
}
mUpdateSkillArea = true;
}
void ReviewDialog::setClass(const ESM::Class& class_)
@ -141,6 +154,8 @@ namespace MWGui
mBirthSignWidget->setCaption(sign->mName);
ToolTips::createBirthsignToolTip(mBirthSignWidget, mBirthSignId);
}
mUpdateSkillArea = true;
}
void ReviewDialog::setHealth(const MWMechanics::DynamicStat<float>& value)
@ -170,7 +185,11 @@ namespace MWGui
if (attr == mAttributeWidgets.end())
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)
@ -191,6 +210,7 @@ namespace MWGui
widget->_setWidgetState(state);
}
mUpdateSkillArea = true;
}
void ReviewDialog::configureSkills(const std::vector<int>& major, const std::vector<int>& minor)
@ -211,7 +231,7 @@ namespace MWGui
mMiscSkills.push_back(skill);
}
updateSkillArea();
mUpdateSkillArea = true;
}
void ReviewDialog::addSeparator(MyGUI::IntCoord &coord1, MyGUI::IntCoord &coord2)
@ -245,7 +265,7 @@ namespace MWGui
skillNameWidget->setCaption(text);
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->_setWidgetState(state);
skillValueWidget->eventMouseWheel += MyGUI::newDelegate(this, &ReviewDialog::onMouseWheel);
@ -273,6 +293,20 @@ namespace MWGui
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)
{
// Add a line separator if there are items above
@ -332,6 +366,80 @@ namespace MWGui
if (!mMiscSkills.empty())
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
mSkillView->setVisibleVScroll(false);
mSkillView->setCanvasSize (mSkillView->getWidth(), std::max(mSkillView->getHeight(), coord1.top));

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

@ -466,9 +466,6 @@ namespace MWGui
else
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)
{
std::string desc = MWBase::Environment::get().getInputManager()->getActionDescription (*it);
@ -481,16 +478,15 @@ namespace MWGui
else
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);
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->setTextAlign (MyGUI::Align::Right);
rightText->setUserData(*it); // save the action id for callbacks
rightText->eventMouseButtonClick += MyGUI::newDelegate(this, &SettingsWindow::onRebindAction);
rightText->eventMouseWheel += MyGUI::newDelegate(this, &SettingsWindow::onInputTabMouseWheel);
curH += h;
Gui::ButtonGroup group;
group.push_back(leftText);
@ -498,9 +494,25 @@ namespace MWGui
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
mControlsBox->setVisibleVScroll(false);
mControlsBox->setCanvasSize (mControlsBox->getWidth(), std::max(curH, mControlsBox->getHeight()));
mControlsBox->setCanvasSize (mControlsBox->getWidth(), std::max(totalH, mControlsBox->getHeight()));
mControlsBox->setVisibleVScroll(true);
}
@ -556,7 +568,7 @@ namespace MWGui
void SettingsWindow::onWindowResize(MyGUI::Window *_sender)
{
updateControlsBox();
layoutControlsBox();
}
void SettingsWindow::resetScrollbars()

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

@ -1,5 +1,7 @@
#include "sortfilteritemmodel.hpp"
#include <iostream>
#include <components/misc/stringops.hpp>
#include <components/esm/loadalch.hpp>
@ -14,9 +16,14 @@
#include <components/esm/loadprob.hpp>
#include <components/esm/loadrepa.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/nullaction.hpp"
#include "../mwworld/esmstore.hpp"
namespace
{
@ -139,6 +146,31 @@ namespace MWGui
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;
}

@ -39,6 +39,8 @@ namespace MWGui
static const int Filter_OnlyEnchantable = (1<<2);
static const int Filter_OnlyChargedSoulstones = (1<<3);
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:

@ -11,6 +11,7 @@
#include "../mwworld/inventorystore.hpp"
#include "../mwworld/class.hpp"
#include "../mwworld/esmstore.hpp"
#include "../mwworld/player.hpp"
#include "../mwmechanics/spellcasting.hpp"
#include "../mwmechanics/spells.hpp"
@ -122,8 +123,15 @@ namespace MWGui
const ESM::Spell* spell =
MWBase::Environment::get().getWorld()->getStore().get<ESM::Spell>().find(spellId);
if (spell->mData.mFlags & ESM::Spell::F_Always
|| spell->mData.mType == ESM::Spell::ST_Power)
MWWorld::Ptr player = MWMechanics::getPlayer();
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}");
}

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

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

@ -16,6 +16,9 @@
#include <components/sdlutil/sdlinputwrapper.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/windowmanager.hpp"
@ -1574,6 +1577,44 @@ namespace MWInput
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()
{
loadKeyDefaults(true);

@ -149,6 +149,10 @@ namespace MWInput
void clearAllKeyBindings (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:
SDL_Window* mWindow;
bool mWindowVisible;

@ -512,8 +512,8 @@ namespace MWMechanics
if (magnitude > 0 && remainingTime > 0 && remainingTime < mDuration)
{
CreatureStats& creatureStats = mActor.getClass().getCreatureStats(mActor);
effectTick(creatureStats, mActor, key, magnitude * remainingTime);
creatureStats.getMagicEffects().add(key, -magnitude);
if (effectTick(creatureStats, mActor, key, magnitude * remainingTime))
creatureStats.getMagicEffects().add(key, -magnitude);
}
}
};
@ -527,8 +527,10 @@ namespace MWMechanics
if (duration > 0)
{
// apply correct magnitude for tickable effects that have just expired,
// in case duration > remaining time of effect
// Apply correct magnitude for tickable effects that have just expired,
// 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);
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
{
// activate when reached
MWWorld::Ptr target = MWBase::Environment::get().getWorld()->getPtr(mObjectId,false);
MWBase::Environment::get().getWorld()->activate(target, actor);
return true;
}

@ -18,6 +18,7 @@
#include "character.hpp"
#include "aicombataction.hpp"
#include "combat.hpp"
#include "coordinateconverter.hpp"
namespace
{
@ -50,23 +51,40 @@ namespace MWMechanics
bool mForceNoShortcut;
ESM::Position mShortcutFailPos;
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():
mAttackCooldown(0),
mAttackCooldown(0.0f),
mTimerReact(AI_REACTION_TIME),
mTimerCombatMove(0),
mTimerCombatMove(0.0f),
mReadyToAttack(false),
mAttack(false),
mAttackRange(0),
mAttackRange(0.0f),
mCombatMove(false),
mLastTargetPos(0,0,0),
mCell(NULL),
mCurrentAction(),
mActionCooldown(0),
mActionCooldown(0.0f),
mStrength(),
mForceNoShortcut(false),
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);
@ -76,6 +94,10 @@ namespace MWMechanics
const ESM::Weapon* weapon, bool distantCombat);
void updateAttack(CharacterController& characterController);
void stopAttack();
void startFleeing();
void stopFleeing();
bool isFleeing();
};
AiCombat::AiCombat(const MWWorld::Ptr& actor) :
@ -157,16 +179,27 @@ namespace MWMechanics
|| target.getClass().getCreatureStats(target).isDead())
return true;
if (storage.mCurrentAction.get()) // need to wait to init action with it's attack range
if (!storage.isFleeing())
{
//Update every frame
bool is_target_reached = pathTo(actor, target.getRefData().getPosition().pos, duration, storage.mAttackRange);
if (is_target_reached) storage.mReadyToAttack = true;
}
if (storage.mCurrentAction.get()) // need to wait to init action with its attack range
{
//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);
if (storage.mReadyToAttack) updateActorsMovement(actor, duration, storage);
storage.updateAttack(characterController);
storage.updateCombatMove(duration);
if (storage.mReadyToAttack) updateActorsMovement(actor, duration, storage);
storage.updateAttack(characterController);
}
else
{
updateFleeing(actor, target, duration, storage);
}
storage.mActionCooldown -= duration;
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)
{
if (isTargetMagicallyHidden(target))
{
storage.stopAttack();
return; // TODO: run away instead of doing nothing
}
const MWWorld::CellStore*& currentCell = storage.mCell;
bool cellChange = currentCell && (actor.getCell() != currentCell);
if(!currentCell || cellChange)
@ -198,30 +225,61 @@ namespace MWMechanics
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();
actorClass.getCreatureStats(actor).setMovementFlag(CreatureStats::Flag_Run, true);
float& actionCooldown = storage.mActionCooldown;
if (actionCooldown > 0)
return;
float &rangeAttack = storage.mAttackRange;
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();
}
const ESM::Weapon *weapon = NULL;
bool isRangedCombat = false;
if (currentAction.get())
if (!currentAction)
return;
if (storage.isFleeing() != currentAction->isFleeing())
{
rangeAttack = currentAction->getCombatRange(isRangedCombat);
// Get weapon characteristics
weapon = currentAction->getWeapon();
if (currentAction->isFleeing())
{
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();
osg::Vec3f vActorPos(pos.asVec3());
osg::Vec3f vTargetPos(target.getRefData().getPosition().asVec3());
@ -229,19 +287,7 @@ namespace MWMechanics
osg::Vec3f vAimDir = MWBase::Environment::get().getWorld()->aimToTarget(actor, target);
float distToTarget = MWBase::Environment::get().getWorld()->getHitDistance(actor, target);
if (!currentAction)
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;
}
storage.mReadyToAttack = (currentAction->isAttackingOrSpell() && distToTarget <= rangeAttack && storage.mLOS);
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)
{
// apply combat movement
@ -446,6 +597,26 @@ namespace MWMechanics
mReadyToAttack = 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 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
void updateActorsMovement(const MWWorld::Ptr& actor, float duration, AiCombatStorage& storage);
void rotateActorOnAxis(const MWWorld::Ptr& actor, int axis,

@ -5,14 +5,17 @@
#include "../mwbase/environment.hpp"
#include "../mwbase/world.hpp"
#include "../mwbase/mechanicsmanager.hpp"
#include "../mwworld/class.hpp"
#include "../mwworld/esmstore.hpp"
#include "../mwworld/inventorystore.hpp"
#include "../mwworld/actionequip.hpp"
#include "../mwworld/cellstore.hpp"
#include "npcstats.hpp"
#include "spellcasting.hpp"
#include "combat.hpp"
namespace
{
@ -517,6 +520,7 @@ namespace MWMechanics
Spells& spells = actor.getClass().getCreatureStats(actor).getSpells();
float bestActionRating = 0.f;
float antiFleeRating = 0.f;
// Default to hand-to-hand combat
boost::shared_ptr<Action> bestAction (new ActionWeapon(MWWorld::Ptr()));
if (actor.getClass().isNpc() && actor.getClass().getNpcStats(actor).isWerewolf())
@ -536,6 +540,7 @@ namespace MWMechanics
{
bestActionRating = rating;
bestAction.reset(new ActionPotion(*it));
antiFleeRating = std::numeric_limits<float>::max();
}
}
@ -546,6 +551,7 @@ namespace MWMechanics
{
bestActionRating = rating;
bestAction.reset(new ActionEnchantedItem(it));
antiFleeRating = std::numeric_limits<float>::max();
}
}
@ -593,6 +599,7 @@ namespace MWMechanics
bestActionRating = rating;
bestAction.reset(new ActionWeapon(*it, ammo));
antiFleeRating = vanillaRateWeaponAndAmmo(*it, ammo, actor, enemy);
}
}
}
@ -606,13 +613,308 @@ namespace MWMechanics
{
bestActionRating = rating;
bestAction.reset(new ActionSpell(spell->mId));
antiFleeRating = vanillaRateSpell(spell, actor, enemy);
}
}
if (makeFleeDecision(actor, enemy, antiFleeRating))
bestAction.reset(new ActionFlee());
if (bestAction.get())
bestAction->prepare(actor);
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 const ESM::Weapon* getWeapon() const { return NULL; };
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
@ -89,6 +101,15 @@ namespace MWMechanics
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);
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

@ -152,7 +152,7 @@ bool AiFollow::execute (const MWWorld::Ptr& actor, CharacterController& characte
if (dist > 450)
actor.getClass().getCreatureStats(actor).setMovementFlag(MWMechanics::CreatureStats::Flag_Run, true); //Make NPC run
else if (dist < 325) //Have a bit of a dead zone, otherwise npc will constantly flip between running and not when right on the edge of the running threshhold
else if (dist < 325) //Have a bit of a dead zone, otherwise npc will constantly flip between running and not when right on the edge of the running threshold
actor.getClass().getCreatureStats(actor).setMovementFlag(MWMechanics::CreatureStats::Flag_Run, false); //make NPC walk
}

@ -141,6 +141,79 @@ namespace MWMechanics
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)
{
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> autoCalcPlayerSpells(const int* actorSkills, const int* actorAttributes, const ESM::Race* race);
// Helpers
bool attrSkillCheck (const ESM::Spell* spell, const int* actorSkills, const int* actorAttributes);

@ -1049,6 +1049,9 @@ bool CharacterController::updateCreatureState()
mUpperBodyState = UpperCharState_StartToMinAttack;
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
{
std::string sound = "SwishM";
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
playSwishSound(attackStrength);
}
}
mAttackStrength = attackStrength;
@ -2271,6 +2268,19 @@ void CharacterController::setHeadTrackTarget(const MWWorld::ConstPtr &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)
{
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.
void setHeadTrackTarget(const MWWorld::ConstPtr& target);
void playSwishSound(float attackStrength);
};
MWWorld::ContainerStoreIterator getActiveWeapon(CreatureStats &stats, MWWorld::InventoryStore &inv, WeaponType *weaptype);

@ -431,4 +431,19 @@ namespace MWMechanics
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?
bool isEnvironmentCompatible(const MWWorld::Ptr& attacker, const MWWorld::Ptr& victim);
float getFightDistanceBias(const MWWorld::Ptr& actor1, const MWWorld::Ptr& actor2);
}
#endif

@ -25,25 +25,11 @@
#include "autocalcspell.hpp"
#include "npcstats.hpp"
#include "actorutil.hpp"
#include "combat.hpp"
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)
{
static const float fFightDispMult = MWBase::Environment::get().getWorld()->getStore().get<ESM::GameSetting>().find(
@ -212,15 +198,6 @@ namespace MWMechanics
}
// 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;
if (mRaceSelected)
race = esmStore.get<ESM::Race>().find(player->mRace);
@ -233,61 +210,7 @@ namespace MWMechanics
for (int i=0; i<ESM::Attribute::Length; ++i)
attributes[i] = npcStats.getAttribute(i).getBase();
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, 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;
}
}
std::vector<std::string> selectedSpells = autoCalcPlayerSpells(skills, attributes, race);
for (std::vector<std::string>::iterator it = selectedSpells.begin(); it != selectedSpells.end(); ++it)
creatureStats.getSpells().add(*it);
@ -313,7 +236,7 @@ namespace MWMechanics
: mWatchedTimeToStartDrowning(0), mWatchedStatsEmpty (true), mUpdatePlayer (true), mClassSelected (false),
mRaceSelected (false), mAI(true)
{
//buildPlayer no longer here, needs to be done explicitely after all subsystems are up and running
//buildPlayer no longer here, needs to be done explicitly after all subsystems are up and running
}
void MechanicsManager::add(const MWWorld::Ptr& ptr)
@ -1608,27 +1531,23 @@ namespace MWMechanics
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.
if (npcStats.getDrawState() == MWMechanics::DrawState_Spell)
npcStats.setDrawState(MWMechanics::DrawState_Nothing);
npcStats.setWerewolf(werewolf);
MWWorld::InventoryStore &inv = actor.getClass().getInventoryStore(actor);
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);
}
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())

@ -19,7 +19,7 @@ namespace MWMechanics
bool proximityToDoor(const MWWorld::Ptr& actor,
float minSqr = MIN_DIST_TO_DOOR_SQUARED);
/// Returns door pointer within range. No guarentee is given as too which one
/// Returns door pointer within range. No guarantee is given as to which one
/** \return Pointer to the door, or NULL if none exists **/
MWWorld::Ptr getNearbyDoor(const MWWorld::Ptr& actor,
float minSqr = MIN_DIST_TO_DOOR_SQUARED);

@ -223,7 +223,7 @@ namespace MWMechanics
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)
{
switch (effectId)
@ -491,7 +491,7 @@ namespace MWMechanics
appliedLastingEffects.push_back(effect);
// For absorb effects, also apply the effect to the caster - but with a negative
// magnitude, since we're transfering stats from the target to the caster
// magnitude, since we're transferring stats from the target to the caster
if (!caster.isEmpty() && caster.getClass().isActor())
{
for (int i=0; i<5; ++i)
@ -913,7 +913,7 @@ namespace MWMechanics
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;
@ -927,7 +927,7 @@ namespace MWMechanics
animation->addEffect("meshes\\" + castStatic->mModel, effect->mIndex, false, "", texture);
}
if (!mCaster.getClass().isActor())
if (animation && !mCaster.getClass().isActor())
animation->addSpellCastGlow(effect);
static const std::string schools[] = {
@ -980,8 +980,10 @@ namespace MWMechanics
if (charge == 0)
return false;
// FIXME: charge should be a float, not int so that damage < 1 per frame can be applied.
// This was also a bug in the original engine.
// Store remainder of disintegrate amount (automatically subtracted if > 1)
item->getCellRef().applyChargeRemainderToBeSubtracted(disintegrate - std::floor(disintegrate));
charge = item->getClass().getItemHealth(*item);
charge -=
std::min(static_cast<int>(disintegrate),
charge);
@ -1009,10 +1011,10 @@ namespace MWMechanics
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)
return;
return false;
bool receivedMagicDamage = false;
@ -1144,10 +1146,13 @@ namespace MWMechanics
case ESM::MagicEffect::RemoveCurse:
actor.getClass().getCreatureStats(actor).getSpells().purgeCurses();
break;
default:
return false;
}
if (receivedMagicDamage && actor == getPlayer())
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,
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);
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
{

@ -69,7 +69,14 @@ namespace MWPhysics
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)
{
/*
@ -120,7 +127,7 @@ namespace MWPhysics
stepper.doTrace(colobj, position, position+osg::Vec3f(0.0f,0.0f,sStepSizeUp), collisionWorld);
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?)
/*
@ -138,7 +145,7 @@ namespace MWPhysics
*/
tracer.doTrace(colobj, stepper.mEndPos, stepper.mEndPos + toMove, collisionWorld);
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.
@ -156,22 +163,22 @@ namespace MWPhysics
* ==============================================
*/
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
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.
// TODO: stepper.mPlaneNormal does not appear to be reliable - needs more testing
// NOTE: caller's variables 'position' & 'remainingTime' are modified here
position = stepper.mEndPos;
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,
// or moved full sStepSize distance (FIXME: is this a bug?)
return false;
return Result_Blocked;
}
@ -361,14 +368,15 @@ namespace MWPhysics
osg::Vec3f oldPosition = newPosition;
// We hit something. Try to step up onto it. (NOTE: stepMove does not allow stepping over)
// NOTE: stepMove modifies newPosition if successful
bool result = stepMove(colobj, newPosition, velocity*remainingTime, remainingTime, collisionWorld);
if (!result) // to make sure the maximum stepping distance isn't framerate-dependent or movement-speed dependent
const float minStep = 10.f;
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;
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
if (ptr.getClass().isPureWaterCreature(ptr)
@ -450,8 +458,8 @@ namespace MWPhysics
if (inertia.z() < 0)
inertia.z() *= slowFall;
if (slowFall < 1.f) {
inertia.x() = 0;
inertia.y() = 0;
inertia.x() *= slowFall;
inertia.y() *= slowFall;
}
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
{
const Actor* physactor = getActor(actor);
@ -1309,25 +1329,29 @@ namespace MWPhysics
PtrVelocityList::iterator iter = mMovementQueue.begin();
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();
const MWWorld::CellStore *cell = iter->first.getCell();
if(cell->getCell()->hasWater())
waterlevel = cell->getWaterLevel();
const MWMechanics::MagicEffects& effects = iter->first.getClass().getCreatureStats(iter->first).getMagicEffects();
bool waterCollision = false;
if (effects.get(ESM::MagicEffect::WaterWalking).getMagnitude()
&& cell->getCell()->hasWater()
&& !world->isUnderwater(iter->first.getCell(),
osg::Vec3f(iter->first.getRefData().getPosition().asVec3())))
waterCollision = true;
ActorMap::iterator foundActor = mActors.find(iter->first);
if (foundActor == mActors.end()) // actor was already removed from the scene
continue;
Actor* physicActor = foundActor->second;
if (cell->getCell()->hasWater() && effects.get(ESM::MagicEffect::WaterWalking).getMagnitude())
{
if (!world->isUnderwater(iter->first.getCell(), osg::Vec3f(iter->first.getRefData().getPosition().asVec3())))
waterCollision = true;
else if (physicActor->getCollisionMode() && canMoveToWaterSurface(iter->first, waterlevel))
{
const osg::Vec3f actorPosition = physicActor->getPosition();
physicActor->setPosition(osg::Vec3f(actorPosition.x(), actorPosition.y(), waterlevel));
}
}
physicActor->setCanWaterWalk(waterCollision);
// 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 canMoveToWaterSurface (const MWWorld::ConstPtr &actor, const float waterlevel);
/// Get physical half extents (scaled) of the given actor.
osg::Vec3f getHalfExtents(const MWWorld::ConstPtr& actor) const;

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

@ -302,7 +302,7 @@ protected:
/** Sets the root model of the object.
*
* Note that you must make sure all animation sources are cleared before reseting the object
* Note that you must make sure all animation sources are cleared before resetting the object
* root. All nodes previously retrieved with getNode will also become invalidated.
* @param forceskeleton Wrap the object root in a Skeleton, even if it contains no skinned parts. Use this if you intend to add skinned parts manually.
* @param baseonly If true, then any meshes or particle systems in the model are ignored

@ -221,10 +221,10 @@ namespace MWRender
groupname = "inventoryhandtohand";
else
{
const std::string &type = iter->getTypeName();
if(type == typeid(ESM::Lockpick).name() || type == typeid(ESM::Probe).name())
const std::string &typeName = iter->getTypeName();
if(typeName == typeid(ESM::Lockpick).name() || typeName == typeid(ESM::Probe).name())
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>();

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

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

@ -39,11 +39,11 @@ namespace
{
std::ostringstream texname;
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())));
tex->setWrap(osg::Texture::WRAP_S, osg::Texture::REPEAT);
tex->setWrap(osg::Texture::WRAP_T, osg::Texture::REPEAT);
resourceSystem->getSceneManager()->applyFilterSettings(tex);
textures.push_back(tex);
osg::ref_ptr<osg::Texture2D> tex2 (new osg::Texture2D(resourceSystem->getImageManager()->getImage(texname.str())));
tex2->setWrap(osg::Texture::WRAP_S, osg::Texture::REPEAT);
tex2->setWrap(osg::Texture::WRAP_T, osg::Texture::REPEAT);
resourceSystem->getSceneManager()->applyFilterSettings(tex2);
textures.push_back(tex2);
}
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)
{
const MWBase::World* world = MWBase::Environment::get().getWorld();
for (std::vector<Emitter>::iterator it=mEmitters.begin(); it !=mEmitters.end(); ++it)
{
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());
if ( (currentPos - it->mLastEmitPosition).length() > 10
// Only emit when close to the water surface, not above it and not too deep in the water
&& MWBase::Environment::get().getWorld ()->isUnderwater (it->mPtr.getCell(), it->mPtr.getRefData().getPosition().asVec3())
&& !MWBase::Environment::get().getWorld()->isSubmerged(it->mPtr))
bool shouldEmit = ( world->isUnderwater (it->mPtr.getCell(), it->mPtr.getRefData().getPosition().asVec3()) && !world->isSubmerged(it->mPtr) ) || world->isWalkingOnWater(it->mPtr);
if ( shouldEmit && (currentPos - it->mLastEmitPosition).length() > 10 )
{
it->mLastEmitPosition = currentPos;

@ -1329,7 +1329,7 @@ void SkyManager::createRain()
mRainParticleSystem = new osgParticle::ParticleSystem;
mRainParticleSystem->setParticleAlignment(osgParticle::ParticleSystem::FIXED);
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());

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

@ -34,8 +34,9 @@
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)
, mFallback(fallbackMap)
, mOutput(new DEFAULT_OUTPUT(*this))
, mMasterVolume(1.0f)
, mSFXVolume(1.0f)
@ -61,6 +62,13 @@ namespace MWSound
mFootstepsVolume = Settings::Manager::getFloat("footsteps volume", "Sound");
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);
mBufferCacheMax = std::max(Settings::Manager::getInt("buffer cache max", "Sound"), 1);
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)
{
static float timePassed = 0.0;
@ -941,6 +1039,7 @@ namespace MWSound
{
updateSounds(duration);
updateRegionSound(duration);
updateWaterSound(duration);
}
}
@ -1105,6 +1204,7 @@ namespace MWSound
mOutput->finishStream(*trkiter);
mActiveTracks.clear();
mUnderwaterSound.reset();
mNearWaterSound.reset();
stopMusic();
}
}

@ -11,6 +11,8 @@
#include <components/settings/settings.hpp>
#include <components/fallback/fallback.hpp>
#include "../mwbase/soundmanager.hpp"
namespace VFS
@ -44,6 +46,8 @@ namespace MWSound
{
const VFS::Manager* mVFS;
Fallback::Map mFallback;
std::auto_ptr<Sound_Output> mOutput;
// Caches available music tracks by <playlist name, (sound files) >
@ -56,6 +60,13 @@ namespace MWSound
float mVoiceVolume;
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;
// List of sound buffers, grown as needed. New enties are added to the
// back, allowing existing Sound_Buffer references/pointers to remain
@ -94,6 +105,7 @@ namespace MWSound
int mPausedSoundTypes;
MWBase::SoundPtr mUnderwaterSound;
MWBase::SoundPtr mNearWaterSound;
Sound_Buffer *insertSound(const std::string &soundId, const ESM::Sound *sound);
@ -108,6 +120,7 @@ namespace MWSound
void streamMusicFull(const std::string& filename);
void updateSounds(float duration);
void updateRegionSound(float duration);
void updateWaterSound(float duration);
float volumeFromType(PlayType type) const;
@ -119,7 +132,7 @@ namespace MWSound
friend class OpenAL_Output;
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 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().getDialogueManager()->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.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().getWindowManager()->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
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);
break;
case ESM::REC_INPU:
MWBase::Environment::get().getInputManager()->readRecord(reader, n.intval);
break;
default:
// 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
{
return mCellRef.mChargeFloat;

@ -65,6 +65,7 @@ namespace MWWorld
float getChargeFloat() const; // Implemented as union with int charge
void setCharge(int 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)
std::string getOwner() const;

@ -204,6 +204,14 @@ namespace MWWorld
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)
{
if (mState != State_Loaded)
@ -964,26 +972,26 @@ namespace MWWorld
mLastRespawn = MWBase::Environment::get().getWorld()->getTimeStamp();
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);
}
}
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);
ptr.getClass().respawn(ptr);
}
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);
ptr.getClass().respawn(ptr);
}
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
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
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.
void moveFrom(const MWWorld::Ptr& object, MWWorld::CellStore* from);

@ -393,7 +393,26 @@ namespace MWWorld
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

@ -312,6 +312,8 @@ namespace MWWorld
virtual bool canSwim(const MWWorld::ConstPtr& ptr) const;
virtual bool canWalk(const MWWorld::ConstPtr& 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;
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())
restockNum -= std::min(restockNum, listInMap->second);
//restock
addInitialItem(itemOrList, owner, restockNum, true);
addInitialItem(itemOrList, owner, -restockNum, true);
}
else
{
//Restocking static item - just restock to the max count
int currentCount = count(itemOrList);
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();

@ -6,6 +6,7 @@
#include <components/esm/loadench.hpp>
#include <components/esm/inventorystate.hpp>
#include <components/misc/rng.hpp>
#include <components/settings/settings.hpp>
#include "../mwbase/environment.hpp"
#include "../mwbase/world.hpp"
@ -214,36 +215,71 @@ MWWorld::ContainerStoreIterator MWWorld::InventoryStore::getSlot (int 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)
{
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_;
initSlots (slots_);
// Disable model update during auto-equip
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;
// Don't autoEquip lights. Handled in Actors::updateEquippedLight based on environment light.
if (test.getTypeName() == typeid(ESM::Light).name())
{
if (!canActorAutoEquip(actor, test))
continue;
switch(test.getClass().canBeEquipped (test, actor).first)
{
case 0:
continue;
default:
break;
}
// 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(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
)
if (iter.getType() == ContainerStore::Type_Armor &&
test.getClass().getEffectiveArmorRating(test, actor) <= std::max(unarmoredRating, 0.f))
{
continue;
}
int testSkill = test.getClass().getEquipmentSkill (test);
std::pair<std::vector<int>, bool> itemsSlots =
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());
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())
{
Ptr old = *slots_.at (*iter2);
// check skill
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 (iter.getType() == ContainerStore::Type_Armor)
{
if (actor.getClass().getSkill(actor, oldSkill) > actor.getClass().getSkill (actor, testSkill))
continue; // rejected, because old item better matched the NPC's skills.
if (actor.getClass().getSkill(actor, oldSkill) < actor.getClass().getSkill (actor, testSkill))
use = true;
if (old.getTypeName() == typeid(ESM::Armor).name())
{
if (old.getClass().getEffectiveArmorRating(old, actor) >= test.getClass().getEffectiveArmorRating(test, actor))
// old armor had better armor rating
continue;
}
// suitable armor should replace already equipped clothing
}
if (!use)
else if (iter.getType() == ContainerStore::Type_Clothing)
{
// check value
if (old.getClass().getValue (old)>=
test.getClass().getValue (test))
if (old.getTypeName() == typeid(ESM::Clothing).name())
{
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
{
// 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;
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 (
effectIt->mEffectID);
// Fully resisted?
if (params[i].mMultiplier == 0)
// Fully resisted or can't be applied to target?
if (params[i].mMultiplier == 0 || !MWMechanics::checkEffectTarget(effectIt->mEffectID, actor, actor, actor == MWMechanics::getPlayer()))
continue;
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());
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];
float magnitude = effectIt->mMagnMin + (effectIt->mMagnMax - effectIt->mMagnMin) * params.mRandom;
magnitude *= params.mMultiplier;

@ -115,6 +115,8 @@ namespace MWWorld
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);
bool canActorAutoEquip(const MWWorld::Ptr& actor, const MWWorld::Ptr& item);
public:
InventoryStore();

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

Loading…
Cancel
Save