diff --git a/.gitignore b/.gitignore index 3a35b5e44..5be010fc8 100644 --- a/.gitignore +++ b/.gitignore @@ -82,5 +82,4 @@ moc_*.cxx *ui_playpage.h *.[ao] *.so -openmw.appdata.xml venv/ diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index 06fab6cce..6be563e9e 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -15,8 +15,8 @@ Debian: - apt-get update -yq - apt-get -o dir::cache::archives="$APT_CACHE_DIR" install -y cmake libboost-filesystem-dev libboost-program-options-dev libboost-system-dev libavcodec-dev libavformat-dev libavutil-dev libswscale-dev libswresample-dev libsdl2-dev libqt4-dev libopenal-dev libopenscenegraph-3.4-dev libunshield-dev libtinyxml-dev # - apt-get install -y libmygui-dev libbullet-dev # to be updated to latest below because stretch is too old - - curl -L http://ftp.us.debian.org/debian/pool/main/b/bullet/libbullet-dev_2.87+dfsg-2_amd64.deb -o libbullet-dev_2.87+dfsg-2_amd64.deb - - curl -L http://ftp.us.debian.org/debian/pool/main/b/bullet/libbullet2.87_2.87+dfsg-2_amd64.deb -o libbullet2.87_2.87+dfsg-2_amd64.deb + - curl -L http://ftp.us.debian.org/debian/pool/main/b/bullet/libbullet-dev_2.87+dfsg-3_amd64.deb -o libbullet-dev_2.87+dfsg-3_amd64.deb + - curl -L http://ftp.us.debian.org/debian/pool/main/b/bullet/libbullet2.87_2.87+dfsg-3_amd64.deb -o libbullet2.87_2.87+dfsg-3_amd64.deb - curl -L https://http.kali.org/pool/main/m/mygui/libmygui.openglplatform0debian1v5_3.2.2+dfsg-1_amd64.deb -o libmygui.openglplatform0debian1v5_3.2.2+dfsg-1_amd64.deb - curl -L https://http.kali.org/pool/main/m/mygui/libmyguiengine3debian1v5_3.2.2+dfsg-1_amd64.deb -o libmyguiengine3debian1v5_3.2.2+dfsg-1_amd64.deb - curl -L https://http.kali.org/pool/main/m/mygui/libmygui-dev_3.2.2+dfsg-1_amd64.deb -o libmygui-dev_3.2.2+dfsg-1_amd64.deb diff --git a/.travis.yml b/.travis.yml index 5dfdca6a6..ebc1cae76 100644 --- a/.travis.yml +++ b/.travis.yml @@ -72,6 +72,7 @@ script: - cd ./build - if [ "$COVERITY_SCAN_BRANCH" != 1 ]; then ${ANALYZE}make -j3; fi - if [ "$COVERITY_SCAN_BRANCH" != 1 ] && [ "${TRAVIS_OS_NAME}" = "osx" ]; then make package; fi + - if [ "${COVERITY_SCAN_BRANCH}" != 1 ] && [ "${TRAVIS_OS_NAME}" = "osx" ]; then ../CI/check_package.osx.sh; fi - if [ "$COVERITY_SCAN_BRANCH" != 1 ] && [ "${TRAVIS_OS_NAME}" = "linux" ]; then ./openmw_test_suite; fi - if [ "$COVERITY_SCAN_BRANCH" != 1 ] && [ "${TRAVIS_OS_NAME}" = "linux" ]; then cd .. && ./CI/check_tabs.sh; fi #deploy: diff --git a/CHANGELOG.md b/CHANGELOG.md index 1f44e83b3..0da3ba67d 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,16 +1,24 @@ 0.46.0 ------ + Bug #2987: Editor: some chance and AI data fields can overflow Bug #3623: Fix HiDPI on Windows + Bug #4411: Reloading a saved game while falling prevents damage in some cases Bug #4540: Rain delay when exiting water Bug #4701: PrisonMarker record is not hardcoded like other markers Bug #4714: Crash upon game load in the repair menu while the "Your repair failed!" message is active Bug #4715: "Cannot get class of an empty object" exception after pressing ESC in the dialogue mode Bug #4720: Inventory avatar has shield with two-handed weapon during [un]equipping animation Bug #4723: ResetActors command works incorrectly + Bug #4745: Editor: Interior cell lighting field values are not displayed as colors + Bug #4746: Non-solid player can't run or sneak + Bug #4750: Sneaking doesn't work in first person view if the player is in attack ready state + Bug #4768: Fallback numerical value recovery chokes on invalid arguments Feature #2229: Improve pathfinding AI Feature #3442: Default values for fallbacks from ini file + Feature #3610: Option to invert X axis Feature #4673: Weapon sheathing + Feature #4730: Native animated containers support Task #4686: Upgrade media decoder to a more current FFmpeg API 0.45.0 diff --git a/CI/before_install.osx.sh b/CI/before_install.osx.sh index d75ee3be5..43102356e 100755 --- a/CI/before_install.osx.sh +++ b/CI/before_install.osx.sh @@ -1,10 +1,11 @@ #!/bin/sh -e brew update - -brew outdated cmake || brew upgrade cmake +brew unlink cmake || true +brew install https://raw.githubusercontent.com/Homebrew/homebrew-core/a3b64391ebace30b84de8e7997665a1621c0b2c0/Formula/cmake.rb +brew switch cmake 3.12.4 brew outdated pkgconfig || brew upgrade pkgconfig brew install qt -curl -fSL -R -J https://downloads.openmw.org/osx/dependencies/openmw-deps-7cf2789.zip -o ~/openmw-deps.zip +curl -fSL -R -J https://downloads.openmw.org/osx/dependencies/openmw-deps-55c27b1.zip -o ~/openmw-deps.zip unzip -o ~/openmw-deps.zip -d /private/tmp/openmw-deps > /dev/null diff --git a/CI/before_script.msvc.sh b/CI/before_script.msvc.sh index b0d4a1ae1..4fd352f7d 100644 --- a/CI/before_script.msvc.sh +++ b/CI/before_script.msvc.sh @@ -31,6 +31,7 @@ SKIP_EXTRACT="" KEEP="" UNITY_BUILD="" VS_VERSION="" +NMAKE="" PLATFORM="" CONFIGURATION="" @@ -66,6 +67,9 @@ while [ $# -gt 0 ]; do VS_VERSION=$1 shift ;; + n ) + NMAKE=true ;; + p ) PLATFORM=$1 shift ;; @@ -94,6 +98,8 @@ Options: Configure for unity builds. -v <2013/2015/2017> Choose the Visual Studio version to use. + -n + Produce NMake makefiles instead of a Visual Studio solution. -V Run verbosely EOF @@ -108,6 +114,10 @@ EOF done done +if [ -n "$NMAKE" ]; then + command -v nmake -? >/dev/null 2>&1 || { echo "Error: nmake (NMake) is not on the path. Make sure you have the necessary environment variables set for command-line C++ development (for example, by starting from a Developer Command Prompt)."; exit 1; } +fi + if [ -z $VERBOSE ]; then STRIP="> /dev/null 2>&1" fi @@ -267,18 +277,12 @@ case $PLATFORM in ARCHNAME="x86-64" ARCHSUFFIX="64" BITS="64" - - BASE_OPTS="-G\"$GENERATOR Win64\"" - add_cmake_opts "-G\"$GENERATOR Win64\"" ;; x32|x86|i686|i386|win32|Win32 ) ARCHNAME="x86" ARCHSUFFIX="86" BITS="32" - - BASE_OPTS="-G\"$GENERATOR\"" - add_cmake_opts "-G\"$GENERATOR\"" ;; * ) @@ -304,14 +308,24 @@ case $CONFIGURATION in ;; esac -if ! [ -z $UNITY_BUILD ]; then - add_cmake_opts "-DOPENMW_UNITY_BUILD=True" -fi - if [ ${BITS} -eq 64 ]; then GENERATOR="${GENERATOR} Win64" fi +if [ -n "$NMAKE" ]; then + GENERATOR="NMake Makefiles" +fi + +add_cmake_opts "-G\"$GENERATOR\"" + +if [ -n "$NMAKE" ]; then + add_cmake_opts "-DCMAKE_BUILD_TYPE=${BUILD_CONFIG}" +fi + +if ! [ -z $UNITY_BUILD ]; then + add_cmake_opts "-DOPENMW_UNITY_BUILD=True" +fi + echo echo "===================================" echo "Starting prebuild on MSVC${MSVC_DISPLAY_YEAR} WIN${BITS}" @@ -387,6 +401,11 @@ cd .. #/.. # Set up dependencies BUILD_DIR="MSVC${MSVC_DISPLAY_YEAR}_${BITS}" + +if [ -n "$NMAKE" ]; then + BUILD_DIR="${BUILD_DIR}_NMake_${BUILD_CONFIG}" +fi + if [ -z $KEEP ]; then echo echo "(Re)Creating build directory." @@ -696,7 +715,11 @@ fi # NOTE: Disable this when/if we want to run test cases #if [ -z $CI ]; then echo "- Copying Runtime DLLs..." - mkdir -p $BUILD_CONFIG + DLL_PREFIX="" + if [ -z $NMAKE ]; then + mkdir -p $BUILD_CONFIG + DLL_PREFIX="$BUILD_CONFIG/" + fi for DLL in $RUNTIME_DLLS; do TARGET="$(basename "$DLL")" if [[ "$DLL" == *":"* ]]; then @@ -705,21 +728,21 @@ fi TARGET=${SPLIT[1]} fi echo " ${TARGET}." - cp "$DLL" "$BUILD_CONFIG/$TARGET" + cp "$DLL" "${DLL_PREFIX}$TARGET" done echo echo "- OSG Plugin DLLs..." - mkdir -p $BUILD_CONFIG/osgPlugins-3.4.1 + mkdir -p ${DLL_PREFIX}osgPlugins-3.4.1 for DLL in $OSG_PLUGINS; do echo " $(basename $DLL)." - cp "$DLL" $BUILD_CONFIG/osgPlugins-3.4.1 + cp "$DLL" ${DLL_PREFIX}osgPlugins-3.4.1 done echo echo "- Qt Platform DLLs..." - mkdir -p ${BUILD_CONFIG}/platforms + mkdir -p ${DLL_PREFIX}platforms for DLL in $QT_PLATFORMS; do echo " $(basename $DLL)" - cp "$DLL" "${BUILD_CONFIG}/platforms" + cp "$DLL" "${DLL_PREFIX}platforms" done echo #fi diff --git a/CI/before_script.osx.sh b/CI/before_script.osx.sh index 16f461639..d3994a7ae 100755 --- a/CI/before_script.osx.sh +++ b/CI/before_script.osx.sh @@ -11,7 +11,7 @@ cd build cmake \ -D CMAKE_PREFIX_PATH="$DEPENDENCIES_ROOT;$QT_PATH" \ -D CMAKE_OSX_DEPLOYMENT_TARGET="10.9" \ --D CMAKE_OSX_SYSROOT="macosx10.13" \ +-D CMAKE_OSX_SYSROOT="macosx10.14" \ -D CMAKE_BUILD_TYPE=Release \ -D OPENMW_OSX_DEPLOYMENT=TRUE \ -D DESIRED_QT_VERSION=5 \ diff --git a/CI/check_package.osx.sh b/CI/check_package.osx.sh new file mode 100755 index 000000000..f5da5c273 --- /dev/null +++ b/CI/check_package.osx.sh @@ -0,0 +1,15 @@ +#!/usr/bin/env bash + +hdiutil attach ./*.dmg -mountpoint "${TRAVIS_BUILD_DIR}/openmw-package" > /dev/null || echo "hdutil has failed" + +EXPECTED_PACKAGE_FILES=('Applications' 'OpenMW-CS.app' 'OpenMW.app') +PACKAGE_FILES=$(ls "${TRAVIS_BUILD_DIR}/openmw-package" | LC_ALL=C sort) + +DIFF=$(diff <(printf "%s\n" "${EXPECTED_PACKAGE_FILES[@]}") <(printf "%s\n" "${PACKAGE_FILES[@]}")) +DIFF_STATUS=$? + +if [[ $DIFF_STATUS -ne 0 ]]; then + echo "The package should only contain an Applications symlink and two applications, see the following diff for details." >&2 + echo "$DIFF" >&2 + exit 1 +fi diff --git a/CMakeLists.txt b/CMakeLists.txt index e2b547aa4..6281785a8 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -62,6 +62,7 @@ set(OPENMW_VERSION_RELEASE 0) set(OPENMW_VERSION_COMMITHASH "") set(OPENMW_VERSION_TAGHASH "") +set(OPENMW_VERSION_COMMITDATE "") set(OPENMW_VERSION "${OPENMW_VERSION_MAJOR}.${OPENMW_VERSION_MINOR}.${OPENMW_VERSION_RELEASE}") @@ -74,6 +75,18 @@ if(EXISTS ${PROJECT_SOURCE_DIR}/.git) else(GIT_FOUND) message(WARNING "Git executable not found") endif(GIT_FOUND) + + if(GIT_FOUND) + execute_process ( + COMMAND ${GIT_EXECUTABLE} log -1 --format='%aI' + WORKING_DIRECTORY ${PROJECT_SOURCE_DIR} + RESULT_VARIABLE EXITCODE3 + OUTPUT_VARIABLE OPENMW_VERSION_COMMITDATE + OUTPUT_STRIP_TRAILING_WHITESPACE) + if(NOT EXITCODE3) + string(SUBSTRING ${OPENMW_VERSION_COMMITDATE} 1 10 OPENMW_VERSION_COMMITDATE) + endif(NOT EXITCODE3) + endif(GIT_FOUND) endif(EXISTS ${PROJECT_SOURCE_DIR}/.git) # Macros @@ -266,8 +279,14 @@ IF(BUILD_OPENMW OR BUILD_OPENCS) osgdb_tga ) - get_filename_component(OSG_LIB_DIR ${OSGDB_LIBRARY} DIRECTORY) - set(OSGPlugins_LIB_DIR "${OSG_LIB_DIR}/osgPlugins-${OPENSCENEGRAPH_VERSION}") + set(OSGPlugins_LIB_DIR "") + foreach(OSGDB_LIB ${OSGDB_LIBRARY}) + # Skip library type names + if(EXISTS ${OSGDB_LIB} AND NOT IS_DIRECTORY ${OSGDB_LIB}) + get_filename_component(OSG_LIB_DIR ${OSGDB_LIB} DIRECTORY) + list(APPEND OSGPlugins_LIB_DIR "${OSG_LIB_DIR}/osgPlugins-${OPENSCENEGRAPH_VERSION}") + endif() + endforeach(OSGDB_LIB) if(OSG_STATIC) add_definitions(-DOSG_LIBRARY_STATIC) @@ -366,6 +385,9 @@ configure_resource_file(${OpenMW_SOURCE_DIR}/files/tes3mp/tes3mp-server-default. configure_resource_file(${OpenMW_SOURCE_DIR}/files/settings-default.cfg "${OpenMW_BINARY_DIR}" "settings-default.cfg") +configure_resource_file(${OpenMW_SOURCE_DIR}/files/openmw.appdata.xml + "${OpenMW_BINARY_DIR}" "openmw.appdata.xml") + if (NOT APPLE) configure_resource_file(${OpenMW_SOURCE_DIR}/files/openmw.cfg.local "${OpenMW_BINARY_DIR}" "openmw.cfg") @@ -625,7 +647,7 @@ set(RECASTNAVIGATION_DEMO OFF CACHE BOOL "Do not build RecastDemo") set(RECASTNAVIGATION_STATIC ON CACHE BOOL "Build recastnavigation static libraries") set(RECASTNAVIGATION_TESTS OFF CACHE BOOL "Do not build recastnavigation tests") -add_subdirectory (extern/recastnavigation) +add_subdirectory (extern/recastnavigation EXCLUDE_FROM_ALL) add_subdirectory (extern/osg-ffmpeg-videoplayer) add_subdirectory (extern/oics) if (BUILD_OPENCS) @@ -836,6 +858,10 @@ endif() # Apple bundling if (OPENMW_OSX_DEPLOYMENT AND APPLE AND DESIRED_QT_VERSION MATCHES 5) + if (${CMAKE_MAJOR_VERSION} STREQUAL "3" AND ${CMAKE_MINOR_VERSION} STREQUAL "13") + message(FATAL_ERROR "macOS packaging is broken in CMake 3.13.*, see https://gitlab.com/OpenMW/openmw/issues/4767. Please use an older version like 3.12.4") + endif () + get_property(QT_COCOA_PLUGIN_PATH TARGET Qt5::QCocoaIntegrationPlugin PROPERTY LOCATION_RELEASE) get_filename_component(QT_COCOA_PLUGIN_DIR "${QT_COCOA_PLUGIN_PATH}" DIRECTORY) get_filename_component(QT_COCOA_PLUGIN_GROUP "${QT_COCOA_PLUGIN_DIR}" NAME) @@ -870,15 +896,24 @@ if (OPENMW_OSX_DEPLOYMENT AND APPLE AND DESIRED_QT_VERSION MATCHES 5) set(ABSOLUTE_PLUGINS "") + set(OSGPlugins_DONT_FIND_DEPENDENCIES 1) + find_package(OSGPlugins REQUIRED COMPONENTS ${USED_OSG_PLUGINS}) + foreach (PLUGIN_NAME ${USED_OSG_PLUGINS}) - set(PLUGIN_ABS "${OSGPlugins_LIB_DIR}/${PLUGIN_NAME}.so") - set(ABSOLUTE_PLUGINS ${PLUGIN_ABS} ${ABSOLUTE_PLUGINS}) + string(TOUPPER ${PLUGIN_NAME} PLUGIN_NAME_UC) + if(${PLUGIN_NAME_UC}_LIBRARY_RELEASE) + set(PLUGIN_ABS ${${PLUGIN_NAME_UC}_LIBRARY_RELEASE}) + elseif(${PLUGIN_NAME_UC}_LIBRARY) + set(PLUGIN_ABS ${${PLUGIN_NAME_UC}_LIBRARY}) + else() + message(FATAL_ERROR "Can't find library file for ${PLUGIN_NAME}") + # We used to construct the path manually from OSGPlugins_LIB_DIR and the plugin name. + # Maybe that could be restored as a fallback? + endif() + set(ABSOLUTE_PLUGINS ${PLUGIN_ABS} ${ABSOLUTE_PLUGINS}) endforeach () - get_filename_component(OSG_PLUGIN_PREFIX_DIR "${OSGPlugins_LIB_DIR}" NAME) - if (NOT OSG_PLUGIN_PREFIX_DIR) - message(FATAL_ERROR "Can't get directory name for OSG plugins from '${OSGPlugins_LIB_DIR}'") - endif() + set(OSG_PLUGIN_PREFIX_DIR "osgPlugins-${OPENSCENEGRAPH_VERSION}") # installs used plugins in bundle at given path (bundle_path must be relative to ${CMAKE_INSTALL_PREFIX}) # and returns list of install paths for all installed plugins diff --git a/apps/esmtool/esmtool.cpp b/apps/esmtool/esmtool.cpp index 699ff855c..4734e1c56 100644 --- a/apps/esmtool/esmtool.cpp +++ b/apps/esmtool/esmtool.cpp @@ -406,13 +406,10 @@ int load(Arguments& info) } catch(std::exception &e) { std::cout << "\nERROR:\n\n " << e.what() << std::endl; - typedef std::deque RecStore; - RecStore &store = info.data.mRecords; - for (RecStore::iterator it = store.begin(); it != store.end(); ++it) - { - delete *it; - } - store.clear(); + for (const EsmTool::RecordBase* record : info.data.mRecords) + delete record; + + info.data.mRecords.clear(); return 1; } @@ -444,15 +441,12 @@ int clone(Arguments& info) std::cout << "Loaded " << recordCount << " records:" << std::endl << std::endl; int i = 0; - typedef std::map Stats; - Stats &stats = info.data.mRecordStats; - for (Stats::iterator it = stats.begin(); it != stats.end(); ++it) + for (std::pair stat : info.data.mRecordStats) { ESM::NAME name; - name.intval = it->first; - int amount = it->second; + name.intval = stat.first; + int amount = stat.second; std::cout << std::setw(digitCount) << amount << " " << name.toString() << " "; - if (++i % 3 == 0) std::cout << std::endl; } @@ -470,18 +464,18 @@ int clone(Arguments& info) esm.setVersion(info.data.version); esm.setRecordCount (recordCount); - for (std::vector::iterator it = info.data.masters.begin(); it != info.data.masters.end(); ++it) - esm.addMaster(it->name, it->size); + for (const ESM::Header::MasterData &master : info.data.masters) + esm.addMaster(master.name, master.size); std::fstream save(info.outname.c_str(), std::fstream::out | std::fstream::binary); esm.save(save); int saved = 0; - typedef std::deque Records; - Records &records = info.data.mRecords; - for (Records::iterator it = records.begin(); it != records.end() && i > 0; ++it) + for (EsmTool::RecordBase* record : info.data.mRecords) { - EsmTool::RecordBase *record = *it; + if (i <= 0) + break; + const ESM::NAME& typeName = record->getType(); esm.startRecord(typeName.toString(), record->getFlags()); @@ -489,13 +483,10 @@ int clone(Arguments& info) record->save(esm); if (typeName.intval == ESM::REC_CELL) { ESM::Cell *ptr = &record->cast()->get(); - if (!info.data.mCellRefs[ptr].empty()) { - typedef std::deque > RefList; - RefList &refs = info.data.mCellRefs[ptr]; - for (RefList::iterator refIt = refs.begin(); refIt != refs.end(); ++refIt) - { - refIt->first.save(esm, refIt->second); - } + if (!info.data.mCellRefs[ptr].empty()) + { + for (std::pair &ref : info.data.mCellRefs[ptr]) + ref.first.save(esm, ref.second); } } @@ -558,8 +549,5 @@ int comp(Arguments& info) return 1; } - - - return 0; } diff --git a/apps/esmtool/labels.cpp b/apps/esmtool/labels.cpp index ea7b50129..bee2a3565 100644 --- a/apps/esmtool/labels.cpp +++ b/apps/esmtool/labels.cpp @@ -651,7 +651,7 @@ std::string ruleFunction(int idx) std::string bodyPartFlags(int flags) { - std::string properties = ""; + std::string properties; if (flags == 0) properties += "[None] "; if (flags & ESM::BodyPart::BPF_Female) properties += "Female "; if (flags & ESM::BodyPart::BPF_NotPlayable) properties += "NotPlayable "; @@ -665,7 +665,7 @@ std::string bodyPartFlags(int flags) std::string cellFlags(int flags) { - std::string properties = ""; + std::string properties; if (flags == 0) properties += "[None] "; if (flags & ESM::Cell::HasWater) properties += "HasWater "; if (flags & ESM::Cell::Interior) properties += "Interior "; @@ -686,7 +686,7 @@ std::string cellFlags(int flags) std::string containerFlags(int flags) { - std::string properties = ""; + std::string properties; if (flags == 0) properties += "[None] "; if (flags & ESM::Container::Unknown) properties += "Unknown "; if (flags & ESM::Container::Organic) properties += "Organic "; @@ -702,7 +702,7 @@ std::string containerFlags(int flags) std::string creatureFlags(int flags) { - std::string properties = ""; + std::string properties; if (flags == 0) properties += "[None] "; if (flags & ESM::Creature::None) properties += "All "; if (flags & ESM::Creature::Walks) properties += "Walks "; @@ -732,7 +732,7 @@ std::string creatureFlags(int flags) std::string landFlags(int flags) { - std::string properties = ""; + std::string properties; // The ESM component says that this first four bits are used, but // only the first three bits are used as far as I can tell. // There's also no enumeration of the bit in the ESM component. @@ -747,7 +747,7 @@ std::string landFlags(int flags) std::string itemListFlags(int flags) { - std::string properties = ""; + std::string properties; if (flags == 0) properties += "[None] "; if (flags & ESM::ItemLevList::AllLevels) properties += "AllLevels "; if (flags & ESM::ItemLevList::Each) properties += "Each "; @@ -761,7 +761,7 @@ std::string itemListFlags(int flags) std::string creatureListFlags(int flags) { - std::string properties = ""; + std::string properties; if (flags == 0) properties += "[None] "; if (flags & ESM::CreatureLevList::AllLevels) properties += "AllLevels "; int unused = (0xFFFFFFFF ^ ESM::CreatureLevList::AllLevels); @@ -800,7 +800,7 @@ std::string lightFlags(int flags) std::string magicEffectFlags(int flags) { - std::string properties = ""; + std::string properties; if (flags == 0) properties += "[None] "; if (flags & ESM::MagicEffect::TargetAttribute) properties += "TargetAttribute "; if (flags & ESM::MagicEffect::TargetSkill) properties += "TargetSkill "; @@ -826,7 +826,7 @@ std::string magicEffectFlags(int flags) std::string npcFlags(int flags) { - std::string properties = ""; + std::string properties; if (flags == 0) properties += "[None] "; // Mythicmods and the ESM component differ. Mythicmods says // 0x8=None and 0x10=AutoCalc, while our code previously defined @@ -860,7 +860,7 @@ std::string npcFlags(int flags) std::string raceFlags(int flags) { - std::string properties = ""; + std::string properties; if (flags == 0) properties += "[None] "; // All races have the playable flag set in Bethesda files. if (flags & ESM::Race::Playable) properties += "Playable "; @@ -875,7 +875,7 @@ std::string raceFlags(int flags) std::string spellFlags(int flags) { - std::string properties = ""; + std::string properties; if (flags == 0) properties += "[None] "; if (flags & ESM::Spell::F_Autocalc) properties += "Autocalc "; if (flags & ESM::Spell::F_PCStart) properties += "PCStart "; @@ -891,7 +891,7 @@ std::string spellFlags(int flags) std::string weaponFlags(int flags) { - std::string properties = ""; + std::string properties; if (flags == 0) properties += "[None] "; // The interpretation of the flags are still unclear to me. // Apparently you can't be Silver without being Magical? Many of diff --git a/apps/esmtool/record.cpp b/apps/esmtool/record.cpp index 089a25c93..6cd32077c 100644 --- a/apps/esmtool/record.cpp +++ b/apps/esmtool/record.cpp @@ -49,7 +49,7 @@ void printAIPackage(ESM::AIPackage p) std::cout << " BadPackage: " << boost::format("0x%08x") % p.mType << std::endl; } - if (p.mCellName != "") + if (!p.mCellName.empty()) std::cout << " Cell Name: " << p.mCellName << std::endl; } @@ -130,43 +130,41 @@ std::string ruleString(ESM::DialInfo::SelectStruct ss) void printEffectList(ESM::EffectList effects) { int i = 0; - std::vector::iterator eit; - for (eit = effects.mList.begin(); eit != effects.mList.end(); ++eit) - { - std::cout << " Effect[" << i << "]: " << magicEffectLabel(eit->mEffectID) - << " (" << eit->mEffectID << ")" << std::endl; - if (eit->mSkill != -1) - std::cout << " Skill: " << skillLabel(eit->mSkill) - << " (" << (int)eit->mSkill << ")" << std::endl; - if (eit->mAttribute != -1) - std::cout << " Attribute: " << attributeLabel(eit->mAttribute) - << " (" << (int)eit->mAttribute << ")" << std::endl; - std::cout << " Range: " << rangeTypeLabel(eit->mRange) - << " (" << eit->mRange << ")" << std::endl; + for (const ESM::ENAMstruct& effect : effects.mList) + { + std::cout << " Effect[" << i << "]: " << magicEffectLabel(effect.mEffectID) + << " (" << effect.mEffectID << ")" << std::endl; + if (effect.mSkill != -1) + std::cout << " Skill: " << skillLabel(effect.mSkill) + << " (" << (int)effect.mSkill << ")" << std::endl; + if (effect.mAttribute != -1) + std::cout << " Attribute: " << attributeLabel(effect.mAttribute) + << " (" << (int)effect.mAttribute << ")" << std::endl; + std::cout << " Range: " << rangeTypeLabel(effect.mRange) + << " (" << effect.mRange << ")" << std::endl; // Area is always zero if range type is "Self" - if (eit->mRange != ESM::RT_Self) - std::cout << " Area: " << eit->mArea << std::endl; - std::cout << " Duration: " << eit->mDuration << std::endl; - std::cout << " Magnitude: " << eit->mMagnMin << "-" << eit->mMagnMax << std::endl; + if (effect.mRange != ESM::RT_Self) + std::cout << " Area: " << effect.mArea << std::endl; + std::cout << " Duration: " << effect.mDuration << std::endl; + std::cout << " Magnitude: " << effect.mMagnMin << "-" << effect.mMagnMax << std::endl; i++; } } void printTransport(const std::vector& transport) { - std::vector::const_iterator dit; - for (dit = transport.begin(); dit != transport.end(); ++dit) + for (const ESM::Transport::Dest& dest : transport) { std::cout << " Destination Position: " - << boost::format("%12.3f") % dit->mPos.pos[0] << "," - << boost::format("%12.3f") % dit->mPos.pos[1] << "," - << boost::format("%12.3f") % dit->mPos.pos[2] << ")" << std::endl; + << boost::format("%12.3f") % dest.mPos.pos[0] << "," + << boost::format("%12.3f") % dest.mPos.pos[1] << "," + << boost::format("%12.3f") % dest.mPos.pos[2] << ")" << std::endl; std::cout << " Destination Rotation: " - << boost::format("%9.6f") % dit->mPos.rot[0] << "," - << boost::format("%9.6f") % dit->mPos.rot[1] << "," - << boost::format("%9.6f") % dit->mPos.rot[2] << ")" << std::endl; - if (dit->mCellName != "") - std::cout << " Destination Cell: " << dit->mCellName << std::endl; + << boost::format("%9.6f") % dest.mPos.rot[0] << "," + << boost::format("%9.6f") % dest.mPos.rot[1] << "," + << boost::format("%9.6f") % dest.mPos.rot[2] << ")" << std::endl; + if (!dest.mCellName.empty()) + std::cout << " Destination Cell: " << dest.mCellName << std::endl; } } @@ -414,7 +412,7 @@ void Record::print() std::cout << " Name: " << mData.mName << std::endl; std::cout << " Model: " << mData.mModel << std::endl; std::cout << " Icon: " << mData.mIcon << std::endl; - if (mData.mScript != "") + if (!mData.mScript.empty()) std::cout << " Script: " << mData.mScript << std::endl; std::cout << " Weight: " << mData.mData.mWeight << std::endl; std::cout << " Value: " << mData.mData.mValue << std::endl; @@ -429,9 +427,9 @@ void Record::print() std::cout << " Name: " << mData.mName << std::endl; std::cout << " Model: " << mData.mModel << std::endl; std::cout << " Icon: " << mData.mIcon << std::endl; - if (mData.mScript != "") + if (!mData.mScript.empty()) std::cout << " Script: " << mData.mScript << std::endl; - if (mData.mEnchant != "") + if (!mData.mEnchant.empty()) std::cout << " Enchantment: " << mData.mEnchant << std::endl; std::cout << " Type: " << armorTypeLabel(mData.mData.mType) << " (" << mData.mData.mType << ")" << std::endl; @@ -440,15 +438,15 @@ void Record::print() std::cout << " Health: " << mData.mData.mHealth << std::endl; std::cout << " Armor: " << mData.mData.mArmor << std::endl; std::cout << " Enchantment Points: " << mData.mData.mEnchant << std::endl; - std::vector::iterator pit; - for (pit = mData.mParts.mParts.begin(); pit != mData.mParts.mParts.end(); ++pit) + for (const ESM::PartReference &part : mData.mParts.mParts) { - std::cout << " Body Part: " << bodyPartLabel(pit->mPart) - << " (" << (int)(pit->mPart) << ")" << std::endl; - std::cout << " Male Name: " << pit->mMale << std::endl; - if (pit->mFemale != "") - std::cout << " Female Name: " << pit->mFemale << std::endl; + std::cout << " Body Part: " << bodyPartLabel(part.mPart) + << " (" << (int)(part.mPart) << ")" << std::endl; + std::cout << " Male Name: " << part.mMale << std::endl; + if (!part.mFemale.empty()) + std::cout << " Female Name: " << part.mFemale << std::endl; } + std::cout << " Deleted: " << mIsDeleted << std::endl; } @@ -487,9 +485,9 @@ void Record::print() std::cout << " Name: " << mData.mName << std::endl; std::cout << " Model: " << mData.mModel << std::endl; std::cout << " Icon: " << mData.mIcon << std::endl; - if (mData.mScript != "") + if (!mData.mScript.empty()) std::cout << " Script: " << mData.mScript << std::endl; - if (mData.mEnchant != "") + if (!mData.mEnchant.empty()) std::cout << " Enchantment: " << mData.mEnchant << std::endl; std::cout << " Weight: " << mData.mData.mWeight << std::endl; std::cout << " Value: " << mData.mData.mValue << std::endl; @@ -516,9 +514,8 @@ void Record::print() std::cout << " Name: " << mData.mName << std::endl; std::cout << " Texture: " << mData.mTexture << std::endl; std::cout << " Description: " << mData.mDescription << std::endl; - std::vector::iterator pit; - for (pit = mData.mPowers.mList.begin(); pit != mData.mPowers.mList.end(); ++pit) - std::cout << " Power: " << *pit << std::endl; + for (const std::string &power : mData.mPowers.mList) + std::cout << " Power: " << power << std::endl; std::cout << " Deleted: " << mIsDeleted << std::endl; } @@ -526,9 +523,9 @@ template<> void Record::print() { // None of the cells have names... - if (mData.mName != "") + if (!mData.mName.empty()) std::cout << " Name: " << mData.mName << std::endl; - if (mData.mRegion != "") + if (!mData.mRegion.empty()) std::cout << " Region: " << mData.mRegion << std::endl; std::cout << " Flags: " << cellFlags(mData.mData.mFlags) << std::endl; @@ -580,23 +577,22 @@ void Record::print() std::cout << " Name: " << mData.mName << std::endl; std::cout << " Model: " << mData.mModel << std::endl; std::cout << " Icon: " << mData.mIcon << std::endl; - if (mData.mScript != "") + if (!mData.mScript.empty()) std::cout << " Script: " << mData.mScript << std::endl; - if (mData.mEnchant != "") + if (!mData.mEnchant.empty()) std::cout << " Enchantment: " << mData.mEnchant << std::endl; std::cout << " Type: " << clothingTypeLabel(mData.mData.mType) << " (" << mData.mData.mType << ")" << std::endl; std::cout << " Weight: " << mData.mData.mWeight << std::endl; std::cout << " Value: " << mData.mData.mValue << std::endl; std::cout << " Enchantment Points: " << mData.mData.mEnchant << std::endl; - std::vector::iterator pit; - for (pit = mData.mParts.mParts.begin(); pit != mData.mParts.mParts.end(); ++pit) + for (const ESM::PartReference &part : mData.mParts.mParts) { - std::cout << " Body Part: " << bodyPartLabel(pit->mPart) - << " (" << (int)(pit->mPart) << ")" << std::endl; - std::cout << " Male Name: " << pit->mMale << std::endl; - if (pit->mFemale != "") - std::cout << " Female Name: " << pit->mFemale << std::endl; + std::cout << " Body Part: " << bodyPartLabel(part.mPart) + << " (" << (int)(part.mPart) << ")" << std::endl; + std::cout << " Male Name: " << part.mMale << std::endl; + if (!part.mFemale.empty()) + std::cout << " Female Name: " << part.mFemale << std::endl; } std::cout << " Deleted: " << mIsDeleted << std::endl; } @@ -606,14 +602,13 @@ void Record::print() { std::cout << " Name: " << mData.mName << std::endl; std::cout << " Model: " << mData.mModel << std::endl; - if (mData.mScript != "") + if (!mData.mScript.empty()) std::cout << " Script: " << mData.mScript << std::endl; std::cout << " Flags: " << containerFlags(mData.mFlags) << std::endl; std::cout << " Weight: " << mData.mWeight << std::endl; - std::vector::iterator cit; - for (cit = mData.mInventory.mList.begin(); cit != mData.mInventory.mList.end(); ++cit) - std::cout << " Inventory: Count: " << boost::format("%4d") % cit->mCount - << " Item: " << cit->mItem.toString() << std::endl; + for (const ESM::ContItem &item : mData.mInventory.mList) + std::cout << " Inventory: Count: " << boost::format("%4d") % item.mCount + << " Item: " << item.mItem.toString() << std::endl; std::cout << " Deleted: " << mIsDeleted << std::endl; } @@ -656,14 +651,12 @@ void Record::print() << "-" << mData.mData.mAttack[5] << std::endl; std::cout << " Gold: " << mData.mData.mGold << std::endl; - std::vector::iterator cit; - for (cit = mData.mInventory.mList.begin(); cit != mData.mInventory.mList.end(); ++cit) - std::cout << " Inventory: Count: " << boost::format("%4d") % cit->mCount - << " Item: " << cit->mItem.toString() << std::endl; + for (const ESM::ContItem &item : mData.mInventory.mList) + std::cout << " Inventory: Count: " << boost::format("%4d") % item.mCount + << " Item: " << item.mItem.toString() << std::endl; - std::vector::iterator sit; - for (sit = mData.mSpells.mList.begin(); sit != mData.mSpells.mList.end(); ++sit) - std::cout << " Spell: " << *sit << std::endl; + for (const std::string &spell : mData.mSpells.mList) + std::cout << " Spell: " << spell << std::endl; printTransport(mData.getTransport()); @@ -678,9 +671,8 @@ void Record::print() std::cout << " AI U4:" << (int)mData.mAiData.mU4 << std::endl; std::cout << " AI Services:" << boost::format("0x%08X") % mData.mAiData.mServices << std::endl; - std::vector::iterator pit; - for (pit = mData.mAiPackage.mList.begin(); pit != mData.mAiPackage.mList.end(); ++pit) - printAIPackage(*pit); + for (const ESM::AIPackage &package : mData.mAiPackage.mList) + printAIPackage(package); std::cout << " Deleted: " << mIsDeleted << std::endl; } @@ -693,9 +685,8 @@ void Record::print() // Sadly, there are no DialInfos, because the loader dumps as it // loads, rather than loading and then dumping. :-( Anyone mind if // I change this? - ESM::Dialogue::InfoContainer::iterator iit; - for (iit = mData.mInfo.begin(); iit != mData.mInfo.end(); ++iit) - std::cout << "INFO!" << iit->mId << std::endl; + for (const ESM::DialInfo &info : mData.mInfo) + std::cout << "INFO!" << info.mId << std::endl; } template<> @@ -735,7 +726,7 @@ void Record::print() std::cout << " Skill: " << skillLabel(mData.mData.mSkills[i]) << " (" << mData.mData.mSkills[i] << ")" << std::endl; for (int i = 0; i != 10; i++) - if (mData.mRanks[i] != "") + if (!mData.mRanks[i].empty()) { std::cout << " Rank: " << mData.mRanks[i] << std::endl; std::cout << " Attribute1 Requirement: " @@ -749,9 +740,8 @@ void Record::print() std::cout << " Faction Reaction: " << mData.mData.mRankData[i].mFactReaction << std::endl; } - std::map::iterator rit; - for (rit = mData.mReactions.begin(); rit != mData.mReactions.end(); ++rit) - std::cout << " Reaction: " << rit->second << " = " << rit->first << std::endl; + for (const std::pair &reaction : mData.mReactions) + std::cout << " Reaction: " << reaction.second << " = " << reaction.first << std::endl; std::cout << " Deleted: " << mIsDeleted << std::endl; } @@ -772,34 +762,34 @@ template<> void Record::print() { std::cout << " Id: " << mData.mId << std::endl; - if (mData.mPrev != "") + if (!mData.mPrev.empty()) std::cout << " Previous ID: " << mData.mPrev << std::endl; - if (mData.mNext != "") + if (!mData.mNext.empty()) std::cout << " Next ID: " << mData.mNext << std::endl; std::cout << " Text: " << mData.mResponse << std::endl; - if (mData.mActor != "") + if (!mData.mActor.empty()) std::cout << " Actor: " << mData.mActor << std::endl; - if (mData.mRace != "") + if (!mData.mRace.empty()) std::cout << " Race: " << mData.mRace << std::endl; - if (mData.mClass != "") + if (!mData.mClass.empty()) std::cout << " Class: " << mData.mClass << std::endl; std::cout << " Factionless: " << mData.mFactionLess << std::endl; - if (mData.mFaction != "") + if (!mData.mFaction.empty()) std::cout << " NPC Faction: " << mData.mFaction << std::endl; if (mData.mData.mRank != -1) std::cout << " NPC Rank: " << (int)mData.mData.mRank << std::endl; - if (mData.mPcFaction != "") + if (!mData.mPcFaction.empty()) std::cout << " PC Faction: " << mData.mPcFaction << std::endl; // CHANGE? non-standard capitalization mPCrank -> mPCRank (mPcRank?) if (mData.mData.mPCrank != -1) std::cout << " PC Rank: " << (int)mData.mData.mPCrank << std::endl; - if (mData.mCell != "") + if (!mData.mCell.empty()) std::cout << " Cell: " << mData.mCell << std::endl; if (mData.mData.mDisposition > 0) std::cout << " Disposition/Journal index: " << mData.mData.mDisposition << std::endl; if (mData.mData.mGender != ESM::DialInfo::NA) std::cout << " Gender: " << mData.mData.mGender << std::endl; - if (mData.mSound != "") + if (!mData.mSound.empty()) std::cout << " Sound File: " << mData.mSound << std::endl; @@ -808,11 +798,10 @@ void Record::print() std::cout << " Unknown1: " << mData.mData.mUnknown1 << std::endl; std::cout << " Unknown2: " << (int)mData.mData.mUnknown2 << std::endl; - std::vector::iterator sit; - for (sit = mData.mSelects.begin(); sit != mData.mSelects.end(); ++sit) - std::cout << " Select Rule: " << ruleString(*sit) << std::endl; + for (const ESM::DialInfo::SelectStruct &rule : mData.mSelects) + std::cout << " Select Rule: " << ruleString(rule) << std::endl; - if (mData.mResultScript != "") + if (!mData.mResultScript.empty()) { if (mPrintPlain) { @@ -835,7 +824,7 @@ void Record::print() std::cout << " Name: " << mData.mName << std::endl; std::cout << " Model: " << mData.mModel << std::endl; std::cout << " Icon: " << mData.mIcon << std::endl; - if (mData.mScript != "") + if (!mData.mScript.empty()) std::cout << " Script: " << mData.mScript << std::endl; std::cout << " Weight: " << mData.mData.mWeight << std::endl; std::cout << " Value: " << mData.mData.mValue << std::endl; @@ -877,10 +866,9 @@ void Record::print() std::cout << " Chance for None: " << (int)mData.mChanceNone << std::endl; std::cout << " Flags: " << creatureListFlags(mData.mFlags) << std::endl; std::cout << " Number of items: " << mData.mList.size() << std::endl; - std::vector::iterator iit; - for (iit = mData.mList.begin(); iit != mData.mList.end(); ++iit) - std::cout << " Creature: Level: " << iit->mLevel - << " Creature: " << iit->mId << std::endl; + for (const ESM::LevelledListBase::LevelItem &item : mData.mList) + std::cout << " Creature: Level: " << item.mLevel + << " Creature: " << item.mId << std::endl; std::cout << " Deleted: " << mIsDeleted << std::endl; } @@ -890,23 +878,22 @@ void Record::print() std::cout << " Chance for None: " << (int)mData.mChanceNone << std::endl; std::cout << " Flags: " << itemListFlags(mData.mFlags) << std::endl; std::cout << " Number of items: " << mData.mList.size() << std::endl; - std::vector::iterator iit; - for (iit = mData.mList.begin(); iit != mData.mList.end(); ++iit) - std::cout << " Inventory: Level: " << iit->mLevel - << " Item: " << iit->mId << std::endl; + for (const ESM::LevelledListBase::LevelItem &item : mData.mList) + std::cout << " Inventory: Level: " << item.mLevel + << " Item: " << item.mId << std::endl; std::cout << " Deleted: " << mIsDeleted << std::endl; } template<> void Record::print() { - if (mData.mName != "") + if (!mData.mName.empty()) std::cout << " Name: " << mData.mName << std::endl; - if (mData.mModel != "") + if (!mData.mModel.empty()) std::cout << " Model: " << mData.mModel << std::endl; - if (mData.mIcon != "") + if (!mData.mIcon.empty()) std::cout << " Icon: " << mData.mIcon << std::endl; - if (mData.mScript != "") + if (!mData.mScript.empty()) std::cout << " Script: " << mData.mScript << std::endl; std::cout << " Flags: " << lightFlags(mData.mData.mFlags) << std::endl; std::cout << " Weight: " << mData.mData.mWeight << std::endl; @@ -924,7 +911,7 @@ void Record::print() std::cout << " Name: " << mData.mName << std::endl; std::cout << " Model: " << mData.mModel << std::endl; std::cout << " Icon: " << mData.mIcon << std::endl; - if (mData.mScript != "") + if (!mData.mScript.empty()) std::cout << " Script: " << mData.mScript << std::endl; std::cout << " Weight: " << mData.mData.mWeight << std::endl; std::cout << " Value: " << mData.mData.mValue << std::endl; @@ -939,7 +926,7 @@ void Record::print() std::cout << " Name: " << mData.mName << std::endl; std::cout << " Model: " << mData.mModel << std::endl; std::cout << " Icon: " << mData.mIcon << std::endl; - if (mData.mScript != "") + if (!mData.mScript.empty()) std::cout << " Script: " << mData.mScript << std::endl; std::cout << " Weight: " << mData.mData.mWeight << std::endl; std::cout << " Value: " << mData.mData.mValue << std::endl; @@ -954,7 +941,7 @@ void Record::print() std::cout << " Name: " << mData.mName << std::endl; std::cout << " Model: " << mData.mModel << std::endl; std::cout << " Icon: " << mData.mIcon << std::endl; - if (mData.mScript != "") + if (!mData.mScript.empty()) std::cout << " Script: " << mData.mScript << std::endl; std::cout << " Weight: " << mData.mData.mWeight << std::endl; std::cout << " Value: " << mData.mData.mValue << std::endl; @@ -981,21 +968,21 @@ void Record::print() std::cout << " Icon: " << mData.mIcon << std::endl; std::cout << " Flags: " << magicEffectFlags(mData.mData.mFlags) << std::endl; std::cout << " Particle Texture: " << mData.mParticle << std::endl; - if (mData.mCasting != "") + if (!mData.mCasting.empty()) std::cout << " Casting Static: " << mData.mCasting << std::endl; - if (mData.mCastSound != "") + if (!mData.mCastSound.empty()) std::cout << " Casting Sound: " << mData.mCastSound << std::endl; - if (mData.mBolt != "") + if (!mData.mBolt.empty()) std::cout << " Bolt Static: " << mData.mBolt << std::endl; - if (mData.mBoltSound != "") + if (!mData.mBoltSound.empty()) std::cout << " Bolt Sound: " << mData.mBoltSound << std::endl; - if (mData.mHit != "") + if (!mData.mHit.empty()) std::cout << " Hit Static: " << mData.mHit << std::endl; - if (mData.mHitSound != "") + if (!mData.mHitSound.empty()) std::cout << " Hit Sound: " << mData.mHitSound << std::endl; - if (mData.mArea != "") + if (!mData.mArea.empty()) std::cout << " Area Static: " << mData.mArea << std::endl; - if (mData.mAreaSound != "") + if (!mData.mAreaSound.empty()) std::cout << " Area Sound: " << mData.mAreaSound << std::endl; std::cout << " School: " << schoolLabel(mData.mData.mSchool) << " (" << mData.mData.mSchool << ")" << std::endl; @@ -1015,7 +1002,7 @@ void Record::print() std::cout << " Name: " << mData.mName << std::endl; std::cout << " Model: " << mData.mModel << std::endl; std::cout << " Icon: " << mData.mIcon << std::endl; - if (mData.mScript != "") + if (!mData.mScript.empty()) std::cout << " Script: " << mData.mScript << std::endl; std::cout << " Weight: " << mData.mData.mWeight << std::endl; std::cout << " Value: " << mData.mData.mValue << std::endl; @@ -1032,9 +1019,9 @@ void Record::print() std::cout << " Head Model: " << mData.mHead << std::endl; std::cout << " Race: " << mData.mRace << std::endl; std::cout << " Class: " << mData.mClass << std::endl; - if (mData.mScript != "") + if (!mData.mScript.empty()) std::cout << " Script: " << mData.mScript << std::endl; - if (mData.mFaction != "") + if (!mData.mFaction.empty()) std::cout << " Faction: " << mData.mFaction << std::endl; std::cout << " Flags: " << npcFlags(mData.mFlags) << std::endl; @@ -1083,14 +1070,12 @@ void Record::print() std::cout << " Gold: " << mData.mNpdt.mGold << std::endl; } - std::vector::iterator cit; - for (cit = mData.mInventory.mList.begin(); cit != mData.mInventory.mList.end(); ++cit) - std::cout << " Inventory: Count: " << boost::format("%4d") % cit->mCount - << " Item: " << cit->mItem.toString() << std::endl; + for (const ESM::ContItem &item : mData.mInventory.mList) + std::cout << " Inventory: Count: " << boost::format("%4d") % item.mCount + << " Item: " << item.mItem.toString() << std::endl; - std::vector::iterator sit; - for (sit = mData.mSpells.mList.begin(); sit != mData.mSpells.mList.end(); ++sit) - std::cout << " Spell: " << *sit << std::endl; + for (const std::string &spell : mData.mSpells.mList) + std::cout << " Spell: " << spell << std::endl; printTransport(mData.getTransport()); @@ -1105,9 +1090,8 @@ void Record::print() std::cout << " AI U4:" << (int)mData.mAiData.mU4 << std::endl; std::cout << " AI Services:" << boost::format("0x%08X") % mData.mAiData.mServices << std::endl; - std::vector::iterator pit; - for (pit = mData.mAiPackage.mList.begin(); pit != mData.mAiPackage.mList.end(); ++pit) - printAIPackage(*pit); + for (const ESM::AIPackage &package : mData.mAiPackage.mList) + printAIPackage(package); std::cout << " Deleted: " << mIsDeleted << std::endl; } @@ -1124,23 +1108,22 @@ void Record::print() std::cout << " Edge Count: " << mData.mEdges.size() << std::endl; int i = 0; - ESM::Pathgrid::PointList::iterator pit; - for (pit = mData.mPoints.begin(); pit != mData.mPoints.end(); ++pit) + for (const ESM::Pathgrid::Point &point : mData.mPoints) { std::cout << " Point[" << i << "]:" << std::endl; - std::cout << " Coordinates: (" << pit->mX << "," - << pit->mY << "," << pit->mZ << ")" << std::endl; - std::cout << " Auto-Generated: " << (int)pit->mAutogenerated << std::endl; - std::cout << " Connections: " << (int)pit->mConnectionNum << std::endl; - std::cout << " Unknown: " << pit->mUnknown << std::endl; + std::cout << " Coordinates: (" << point.mX << "," + << point.mY << "," << point.mZ << ")" << std::endl; + std::cout << " Auto-Generated: " << (int)point.mAutogenerated << std::endl; + std::cout << " Connections: " << (int)point.mConnectionNum << std::endl; + std::cout << " Unknown: " << point.mUnknown << std::endl; i++; } + i = 0; - ESM::Pathgrid::EdgeList::iterator eit; - for (eit = mData.mEdges.begin(); eit != mData.mEdges.end(); ++eit) + for (const ESM::Pathgrid::Edge &edge : mData.mEdges) { - std::cout << " Edge[" << i << "]: " << eit->mV0 << " -> " << eit->mV1 << std::endl; - if (eit->mV0 >= mData.mData.mS2 || eit->mV1 >= mData.mData.mS2) + std::cout << " Edge[" << i << "]: " << edge.mV0 << " -> " << edge.mV1 << std::endl; + if (edge.mV0 >= mData.mData.mS2 || edge.mV1 >= mData.mData.mS2) std::cout << " BAD POINT IN EDGE!" << std::endl; i++; } @@ -1183,9 +1166,8 @@ void Record::print() << " (" << mData.mData.mBonus[i].mSkill << ") = " << mData.mData.mBonus[i].mBonus << std::endl; - std::vector::iterator sit; - for (sit = mData.mPowers.mList.begin(); sit != mData.mPowers.mList.end(); ++sit) - std::cout << " Power: " << *sit << std::endl; + for (const std::string &power : mData.mPowers.mList) + std::cout << " Power: " << power << std::endl; std::cout << " Deleted: " << mIsDeleted << std::endl; } @@ -1207,11 +1189,10 @@ void Record::print() std::cout << " UnknownA: " << (int)mData.mData.mA << std::endl; std::cout << " UnknownB: " << (int)mData.mData.mB << std::endl; std::cout << " Map Color: " << mData.mMapColor << std::endl; - if (mData.mSleepList != "") + if (!mData.mSleepList.empty()) std::cout << " Sleep List: " << mData.mSleepList << std::endl; - std::vector::iterator sit; - for (sit = mData.mSoundList.begin(); sit != mData.mSoundList.end(); ++sit) - std::cout << " Sound: " << (int)sit->mChance << " = " << sit->mSound.toString() << std::endl; + for (const ESM::Region::SoundRef &soundref : mData.mSoundList) + std::cout << " Sound: " << (int)soundref.mChance << " = " << soundref.mSound.toString() << std::endl; } template<> @@ -1225,15 +1206,12 @@ void Record::print() std::cout << " Script Data Size: " << mData.mData.mScriptDataSize << std::endl; std::cout << " Table Size: " << mData.mData.mStringTableSize << std::endl; - - std::vector::iterator vit; - for (vit = mData.mVarNames.begin(); vit != mData.mVarNames.end(); ++vit) - std::cout << " Variable: " << *vit << std::endl; + for (const std::string &variable : mData.mVarNames) + std::cout << " Variable: " << variable << std::endl; std::cout << " ByteCode: "; - std::vector::iterator cit; - for (cit = mData.mScriptData.begin(); cit != mData.mScriptData.end(); ++cit) - std::cout << boost::format("%02X") % (int)(*cit); + for (const unsigned char &byte : mData.mScriptData) + std::cout << boost::format("%02X") % (int)(byte); std::cout << std::endl; if (mPrintPlain) @@ -1268,7 +1246,8 @@ void Record::print() template<> void Record::print() { - std::cout << " Creature: " << mData.mCreature << std::endl; + if (!mData.mCreature.empty()) + std::cout << " Creature: " << mData.mCreature << std::endl; std::cout << " Sound: " << mData.mSound << std::endl; std::cout << " Type: " << soundTypeLabel(mData.mType) << " (" << mData.mType << ")" << std::endl; @@ -1316,15 +1295,15 @@ template<> void Record::print() { // No names on VFX bolts - if (mData.mName != "") + if (!mData.mName.empty()) std::cout << " Name: " << mData.mName << std::endl; std::cout << " Model: " << mData.mModel << std::endl; // No icons on VFX bolts or magic bolts - if (mData.mIcon != "") + if (!mData.mIcon.empty()) std::cout << " Icon: " << mData.mIcon << std::endl; - if (mData.mScript != "") + if (!mData.mScript.empty()) std::cout << " Script: " << mData.mScript << std::endl; - if (mData.mEnchant != "") + if (!mData.mEnchant.empty()) std::cout << " Enchantment: " << mData.mEnchant << std::endl; std::cout << " Type: " << weaponTypeLabel(mData.mData.mType) << " (" << mData.mData.mType << ")" << std::endl; @@ -1356,25 +1335,25 @@ std::string Record::getId() const template<> std::string Record::getId() const { - return ""; // No ID for Land record + return std::string(); // No ID for Land record } template<> std::string Record::getId() const { - return ""; // No ID for MagicEffect record + return std::string(); // No ID for MagicEffect record } template<> std::string Record::getId() const { - return ""; // No ID for Pathgrid record + return std::string(); // No ID for Pathgrid record } template<> std::string Record::getId() const { - return ""; // No ID for Skill record + return std::string(); // No ID for Skill record } } // end namespace diff --git a/apps/launcher/maindialog.hpp b/apps/launcher/maindialog.hpp index 6d3871b7c..75fe5ab89 100644 --- a/apps/launcher/maindialog.hpp +++ b/apps/launcher/maindialog.hpp @@ -6,7 +6,7 @@ #ifndef Q_MOC_RUN #include -#endif + #include @@ -14,7 +14,7 @@ #include #include - +#endif #include "ui_mainwindow.h" class QListWidgetItem; diff --git a/apps/opencs/model/tools/referenceablecheck.cpp b/apps/opencs/model/tools/referenceablecheck.cpp index fdbab7fd0..73c28f564 100644 --- a/apps/opencs/model/tools/referenceablecheck.cpp +++ b/apps/opencs/model/tools/referenceablecheck.cpp @@ -470,6 +470,13 @@ void CSMTools::ReferenceableCheckStage::creatureCheck ( if (creature.mData.mSoul < 0) messages.add(id, "Soul value is negative", "", CSMDoc::Message::Severity_Error); + if (creature.mAiData.mAlarm > 100) + messages.add(id, "Alarm rating is over 100", "", CSMDoc::Message::Severity_Warning); + if (creature.mAiData.mFight > 100) + messages.add(id, "Fight rating is over 100", "", CSMDoc::Message::Severity_Warning); + if (creature.mAiData.mFlee > 100) + messages.add(id, "Flee rating is over 100", "", CSMDoc::Message::Severity_Warning); + for (int i = 0; i < 6; ++i) { if (creature.mData.mAttack[i] < 0) @@ -700,6 +707,13 @@ void CSMTools::ReferenceableCheckStage::npcCheck ( if (level <= 0) messages.add(id, "Level is non-positive", "", CSMDoc::Message::Severity_Warning); + if (npc.mAiData.mAlarm > 100) + messages.add(id, "Alarm rating is over 100", "", CSMDoc::Message::Severity_Warning); + if (npc.mAiData.mFight > 100) + messages.add(id, "Fight rating is over 100", "", CSMDoc::Message::Severity_Warning); + if (npc.mAiData.mFlee > 100) + messages.add(id, "Flee rating is over 100", "", CSMDoc::Message::Severity_Warning); + if (gold < 0) messages.add(id, "Gold count is negative", "", CSMDoc::Message::Severity_Error); @@ -1014,6 +1028,11 @@ template void CSMTools::ReferenceableCheckStage::toolCheck ( template void CSMTools::ReferenceableCheckStage::listCheck ( const List& someList, CSMDoc::Messages& messages, const std::string& someID) { + if (someList.mChanceNone > 100) + { + messages.add(someID, "Chance that no object is used is over 100 percent", "", CSMDoc::Message::Severity_Warning); + } + for (unsigned i = 0; i < someList.mList.size(); ++i) { if (mReferencables.searchId(someList.mList[i].mId).first == -1) diff --git a/apps/opencs/model/tools/regioncheck.cpp b/apps/opencs/model/tools/regioncheck.cpp index 0b6537d7f..1e6f64786 100644 --- a/apps/opencs/model/tools/regioncheck.cpp +++ b/apps/opencs/model/tools/regioncheck.cpp @@ -42,5 +42,11 @@ void CSMTools::RegionCheckStage::perform (int stage, CSMDoc::Messages& messages) if (chances != 100) messages.add(id, "Weather chances do not add up to 100", "", CSMDoc::Message::Severity_Error); + for (const ESM::Region::SoundRef& sound : region.mSoundList) + { + if (sound.mChance > 100) + messages.add(id, "Chance of '" + sound.mSound.toString() + "' sound to play is over 100 percent", "", CSMDoc::Message::Severity_Warning); + } + /// \todo check data members that can't be edited in the table view } diff --git a/apps/opencs/model/world/data.cpp b/apps/opencs/model/world/data.cpp index 63c7a52a8..9e9447c5a 100644 --- a/apps/opencs/model/world/data.cpp +++ b/apps/opencs/model/world/data.cpp @@ -205,7 +205,7 @@ CSMWorld::Data::Data (ToUTF8::FromType encoding, bool fsStrict, const Files::Pat mRegions.getNestableColumn(index)->addColumn( new NestedChildColumn (Columns::ColumnId_SoundName, ColumnBase::Display_Sound)); mRegions.getNestableColumn(index)->addColumn( - new NestedChildColumn (Columns::ColumnId_SoundChance, ColumnBase::Display_Integer)); + new NestedChildColumn (Columns::ColumnId_SoundChance, ColumnBase::Display_UnsignedInteger8)); mBirthsigns.addColumn (new StringIdColumn); mBirthsigns.addColumn (new RecordStateColumn); @@ -326,11 +326,11 @@ CSMWorld::Data::Data (ToUTF8::FromType encoding, bool fsStrict, const Files::Pat new NestedChildColumn (Columns::ColumnId_Interior, ColumnBase::Display_Boolean, ColumnBase::Flag_Table | ColumnBase::Flag_Dialogue | ColumnBase::Flag_Dialogue_Refresh)); mCells.getNestableColumn(index)->addColumn( - new NestedChildColumn (Columns::ColumnId_Ambient, ColumnBase::Display_Integer)); + new NestedChildColumn (Columns::ColumnId_Ambient, ColumnBase::Display_Colour)); mCells.getNestableColumn(index)->addColumn( - new NestedChildColumn (Columns::ColumnId_Sunlight, ColumnBase::Display_Integer)); + new NestedChildColumn (Columns::ColumnId_Sunlight, ColumnBase::Display_Colour)); mCells.getNestableColumn(index)->addColumn( - new NestedChildColumn (Columns::ColumnId_Fog, ColumnBase::Display_Integer)); + new NestedChildColumn (Columns::ColumnId_Fog, ColumnBase::Display_Colour)); mCells.getNestableColumn(index)->addColumn( new NestedChildColumn (Columns::ColumnId_FogDensity, ColumnBase::Display_Float)); mCells.getNestableColumn(index)->addColumn( @@ -989,23 +989,29 @@ void CSMWorld::Data::loadFallbackEntries() std::make_pair("PrisonMarker", "marker_prison.nif") }; - for (const std::pair marker : staticMarkers) + for (const std::pair &marker : staticMarkers) { if (mReferenceables.searchId (marker.first)==-1) { + ESM::Static newMarker; + newMarker.mId = marker.first; + newMarker.mModel = marker.second; CSMWorld::Record record; - record.mBase = ESM::Static(marker.first, marker.second); + record.mBase = newMarker; record.mState = CSMWorld::RecordBase::State_BaseOnly; mReferenceables.appendRecord (record, CSMWorld::UniversalId::Type_Static); } } - for (const std::pair marker : doorMarkers) + for (const std::pair &marker : doorMarkers) { if (mReferenceables.searchId (marker.first)==-1) { + ESM::Door newMarker; + newMarker.mId = marker.first; + newMarker.mModel = marker.second; CSMWorld::Record record; - record.mBase = ESM::Door(marker.first, std::string(), marker.second, std::string(), std::string(), std::string()); + record.mBase = newMarker; record.mState = CSMWorld::RecordBase::State_BaseOnly; mReferenceables.appendRecord (record, CSMWorld::UniversalId::Type_Door); } diff --git a/apps/opencs/model/world/refidcollection.cpp b/apps/opencs/model/world/refidcollection.cpp index 272722f64..89d346204 100644 --- a/apps/opencs/model/world/refidcollection.cpp +++ b/apps/opencs/model/world/refidcollection.cpp @@ -128,13 +128,13 @@ CSMWorld::RefIdCollection::RefIdCollection() ActorColumns actorsColumns (nameColumns); - mColumns.push_back (RefIdColumn (Columns::ColumnId_AiHello, ColumnBase::Display_Integer)); + mColumns.push_back (RefIdColumn (Columns::ColumnId_AiHello, ColumnBase::Display_UnsignedInteger8)); actorsColumns.mHello = &mColumns.back(); - mColumns.push_back (RefIdColumn (Columns::ColumnId_AiFlee, ColumnBase::Display_Integer)); + mColumns.push_back (RefIdColumn (Columns::ColumnId_AiFlee, ColumnBase::Display_UnsignedInteger8)); actorsColumns.mFlee = &mColumns.back(); - mColumns.push_back (RefIdColumn (Columns::ColumnId_AiFight, ColumnBase::Display_Integer)); + mColumns.push_back (RefIdColumn (Columns::ColumnId_AiFight, ColumnBase::Display_UnsignedInteger8)); actorsColumns.mFight = &mColumns.back(); - mColumns.push_back (RefIdColumn (Columns::ColumnId_AiAlarm, ColumnBase::Display_Integer)); + mColumns.push_back (RefIdColumn (Columns::ColumnId_AiAlarm, ColumnBase::Display_UnsignedInteger8)); actorsColumns.mAlarm = &mColumns.back(); // Nested table @@ -645,7 +645,7 @@ CSMWorld::RefIdCollection::RefIdCollection() mColumns.back().addColumn( new RefIdColumn (Columns::ColumnId_LevelledItemType, CSMWorld::ColumnBase::Display_Boolean)); mColumns.back().addColumn( - new RefIdColumn (Columns::ColumnId_LevelledItemChanceNone, CSMWorld::ColumnBase::Display_Integer)); + new RefIdColumn (Columns::ColumnId_LevelledItemChanceNone, CSMWorld::ColumnBase::Display_UnsignedInteger8)); mAdapters.insert (std::make_pair (UniversalId::Type_Activator, new NameRefIdAdapter (UniversalId::Type_Activator, nameColumns))); diff --git a/apps/opencs/view/doc/filedialog.hpp b/apps/opencs/view/doc/filedialog.hpp index 69acfac3d..bec2c6869 100644 --- a/apps/opencs/view/doc/filedialog.hpp +++ b/apps/opencs/view/doc/filedialog.hpp @@ -4,6 +4,8 @@ #include #include +#ifndef Q_MOC_RUN + #include #include "adjusterwidget.hpp" @@ -12,6 +14,8 @@ Q_DECLARE_METATYPE (boost::filesystem::path) #endif +#endif + #include "ui_filedialog.h" namespace ContentSelectorView diff --git a/apps/opencs/view/render/terraintexturemode.hpp b/apps/opencs/view/render/terraintexturemode.hpp index e1538e243..5184f0f73 100644 --- a/apps/opencs/view/render/terraintexturemode.hpp +++ b/apps/opencs/view/render/terraintexturemode.hpp @@ -8,6 +8,7 @@ #include #include +#ifndef Q_MOC_RUN #include "../../model/world/data.hpp" #include "../../model/world/land.hpp" @@ -15,6 +16,7 @@ #include "../../model/world/commands.hpp" #include "../../model/world/idtable.hpp" #include "../../model/world/landtexture.hpp" +#endif namespace CSVWidget { diff --git a/apps/opencs/view/tools/merge.hpp b/apps/opencs/view/tools/merge.hpp index d4ed7e34b..e332b799f 100644 --- a/apps/opencs/view/tools/merge.hpp +++ b/apps/opencs/view/tools/merge.hpp @@ -3,7 +3,9 @@ #include +#ifndef Q_MOC_RUN #include +#endif class QPushButton; class QListWidget; diff --git a/apps/opencs/view/widget/scenetooltexturebrush.hpp b/apps/opencs/view/widget/scenetooltexturebrush.hpp index 4669f432e..80e9a9382 100644 --- a/apps/opencs/view/widget/scenetooltexturebrush.hpp +++ b/apps/opencs/view/widget/scenetooltexturebrush.hpp @@ -14,9 +14,11 @@ #include #include +#ifndef Q_MOC_RUN #include "scenetool.hpp" #include "../../model/doc/document.hpp" +#endif class QTableWidget; diff --git a/apps/opencs/view/world/creator.hpp b/apps/opencs/view/world/creator.hpp index 0020fd3c8..f50333e4e 100644 --- a/apps/opencs/view/world/creator.hpp +++ b/apps/opencs/view/world/creator.hpp @@ -5,10 +5,12 @@ #include +#ifndef Q_MOC_RUN #include "../../model/doc/document.hpp" #include "../../model/world/scope.hpp" #include "../../model/world/universalid.hpp" +#endif namespace CSMDoc { diff --git a/apps/opencs/view/world/dialoguesubview.hpp b/apps/opencs/view/world/dialoguesubview.hpp index cbcb9b210..52d3d8da5 100644 --- a/apps/opencs/view/world/dialoguesubview.hpp +++ b/apps/opencs/view/world/dialoguesubview.hpp @@ -8,11 +8,13 @@ #include #include +#ifndef Q_MOC_RUN #include "../doc/subview.hpp" #include "../../model/world/columnbase.hpp" #include "../../model/world/commanddispatcher.hpp" #include "../../model/world/universalid.hpp" +#endif class QDataWidgetMapper; class QSize; diff --git a/apps/opencs/view/world/util.hpp b/apps/opencs/view/world/util.hpp index 766d72958..ebd5c0ad7 100644 --- a/apps/opencs/view/world/util.hpp +++ b/apps/opencs/view/world/util.hpp @@ -6,8 +6,11 @@ #include #include + +#ifndef Q_MOC_RUN #include "../../model/world/columnbase.hpp" #include "../../model/doc/document.hpp" +#endif class QUndoStack; diff --git a/apps/openmw/android_main.c b/apps/openmw/android_main.c index 9a7b6bc50..393d48d77 100644 --- a/apps/openmw/android_main.c +++ b/apps/openmw/android_main.c @@ -20,14 +20,14 @@ void releaseArgv(); int Java_org_libsdl_app_SDLActivity_getMouseX(JNIEnv *env, jclass cls, jobject obj) { int ret = 0; - SDL_GetMouseState(&ret, nullptr); + SDL_GetMouseState(&ret, NULL); return ret; } int Java_org_libsdl_app_SDLActivity_getMouseY(JNIEnv *env, jclass cls, jobject obj) { int ret = 0; - SDL_GetMouseState(nullptr, &ret); + SDL_GetMouseState(NULL, &ret); return ret; } @@ -35,6 +35,17 @@ int Java_org_libsdl_app_SDLActivity_isMouseShown(JNIEnv *env, jclass cls, jobjec return SDL_ShowCursor(SDL_QUERY); } +extern SDL_Window *Android_Window; +int SDL_SendMouseMotion(SDL_Window * window, int mouseID, int relative, int x, int y); +void Java_org_libsdl_app_SDLActivity_sendRelativeMouseMotion(JNIEnv *env, jclass cls, int x, int y) { + SDL_SendMouseMotion(Android_Window, 0, 1, x, y); +} + +int SDL_SendMouseButton(SDL_Window * window, int mouseID, Uint8 state, Uint8 button); +void Java_org_libsdl_app_SDLActivity_sendMouseButton(JNIEnv *env, jclass cls, int state, int button) { + SDL_SendMouseButton(Android_Window, 0, state, button); +} + int Java_org_libsdl_app_SDLActivity_nativeInit(JNIEnv* env, jclass cls, jobject obj) { setenv("OPENMW_DECOMPRESS_TEXTURES", "1", 1); diff --git a/apps/openmw/mwbase/mechanicsmanager.hpp b/apps/openmw/mwbase/mechanicsmanager.hpp index 374bcd2a3..68459b471 100644 --- a/apps/openmw/mwbase/mechanicsmanager.hpp +++ b/apps/openmw/mwbase/mechanicsmanager.hpp @@ -247,6 +247,9 @@ namespace MWBase virtual float getActorsProcessingRange() const = 0; + virtual bool onOpen(const MWWorld::Ptr& ptr) = 0; + virtual void onClose(const MWWorld::Ptr& ptr) = 0; + /// Check if the target actor was detected by an observer /// If the observer is a non-NPC, check all actors in AI processing distance as observers virtual bool isActorDetected(const MWWorld::Ptr& actor, const MWWorld::Ptr& observer) = 0; diff --git a/apps/openmw/mwbase/world.hpp b/apps/openmw/mwbase/world.hpp index 6bd942166..eea8033db 100644 --- a/apps/openmw/mwbase/world.hpp +++ b/apps/openmw/mwbase/world.hpp @@ -451,6 +451,8 @@ namespace MWBase End of tes3mp addition */ + virtual void updateAnimatedCollisionShape(const MWWorld::Ptr &ptr) = 0; + virtual bool castRay (float x1, float y1, float z1, float x2, float y2, float z2, int mask) = 0; ///< cast a Ray and return true if there is an object in the ray path. diff --git a/apps/openmw/mwgui/container.cpp b/apps/openmw/mwgui/container.cpp index 6caecce35..4c778034b 100644 --- a/apps/openmw/mwgui/container.cpp +++ b/apps/openmw/mwgui/container.cpp @@ -285,6 +285,8 @@ namespace MWGui if (mModel) mModel->onClose(); + + MWBase::Environment::get().getMechanicsManager()->onClose(mPtr); } void ContainerWindow::onCloseButtonClicked(MyGUI::Widget* _sender) diff --git a/apps/openmw/mwgui/loadingscreen.cpp b/apps/openmw/mwgui/loadingscreen.cpp index 7f641d408..a9480f261 100644 --- a/apps/openmw/mwgui/loadingscreen.cpp +++ b/apps/openmw/mwgui/loadingscreen.cpp @@ -133,22 +133,23 @@ namespace MWGui public: CopyFramebufferToTextureCallback(osg::Texture2D* texture) : mTexture(texture) + , oneshot(true) { } virtual void operator () (osg::RenderInfo& renderInfo) const { + if (!oneshot) + return; + oneshot = false; int w = renderInfo.getCurrentCamera()->getViewport()->width(); int h = renderInfo.getCurrentCamera()->getViewport()->height(); mTexture->copyTexImage2D(*renderInfo.getState(), 0, 0, w, h); - - // Callback removes itself when done - if (renderInfo.getCurrentCamera()) - renderInfo.getCurrentCamera()->setInitialDrawCallback(nullptr); } private: osg::ref_ptr mTexture; + mutable bool oneshot; }; class DontComputeBoundCallback : public osg::Node::ComputeBoundingSphereCallback @@ -308,6 +309,8 @@ namespace MWGui mGuiTexture.reset(new osgMyGUI::OSGTexture(mTexture)); } + // Notice that the next time this is called, the current CopyFramebufferToTextureCallback will be deleted + // so there's no memory leak as at most one object of type CopyFramebufferToTextureCallback is allocated at a time. mViewer->getCamera()->setInitialDrawCallback(new CopyFramebufferToTextureCallback(mTexture)); mBackgroundImage->setBackgroundImage(""); diff --git a/apps/openmw/mwinput/inputmanagerimp.cpp b/apps/openmw/mwinput/inputmanagerimp.cpp index 975921ec3..ce70a2691 100644 --- a/apps/openmw/mwinput/inputmanagerimp.cpp +++ b/apps/openmw/mwinput/inputmanagerimp.cpp @@ -64,6 +64,7 @@ namespace MWInput , mUserFile(userFile) , mDragDrop(false) , mGrabCursor (Settings::Manager::getBool("grab cursor", "Input")) + , mInvertX (Settings::Manager::getBool("invert x axis", "Input")) , mInvertY (Settings::Manager::getBool("invert y axis", "Input")) , mControlsDisabled(false) , mCameraSensitivity (Settings::Manager::getFloat("camera sensitivity", "Input")) @@ -479,7 +480,7 @@ namespace MWInput float rot[3]; rot[0] = yAxis * (dt * 100.0f) * 10.0f * mCameraSensitivity * (1.0f/256.f) * (mInvertY ? -1 : 1) * mCameraYMultiplier; rot[1] = 0.0f; - rot[2] = xAxis * (dt * 100.0f) * 10.0f * mCameraSensitivity * (1.0f/256.f); + rot[2] = xAxis * (dt * 100.0f) * 10.0f * mCameraSensitivity * (1.0f/256.f) * (mInvertX ? -1 : 1); // Only actually turn player when we're not in vanity mode if(!MWBase::Environment::get().getWorld()->vanityRotateCamera(rot)) @@ -658,6 +659,9 @@ namespace MWInput for (Settings::CategorySettingVector::const_iterator it = changed.begin(); it != changed.end(); ++it) { + if (it->first == "Input" && it->second == "invert x axis") + mInvertX = Settings::Manager::getBool("invert x axis", "Input"); + if (it->first == "Input" && it->second == "invert y axis") mInvertY = Settings::Manager::getBool("invert y axis", "Input"); @@ -840,7 +844,7 @@ namespace MWInput { resetIdleTime(); - float x = arg.xrel * mCameraSensitivity * (1.0f/256.f); + float x = arg.xrel * mCameraSensitivity * (1.0f/256.f) * (mInvertX ? -1 : 1); float y = arg.yrel * mCameraSensitivity * (1.0f/256.f) * (mInvertY ? -1 : 1) * mCameraYMultiplier; float rot[3]; @@ -1239,7 +1243,7 @@ namespace MWInput void InputManager::toggleWalking() { - if (MWBase::Environment::get().getWindowManager()->isGuiMode()) return; + if (MWBase::Environment::get().getWindowManager()->isGuiMode() || SDL_IsTextInputActive()) return; mAlwaysRunActive = !mAlwaysRunActive; Settings::Manager::setBool("always run", "Input", mAlwaysRunActive); diff --git a/apps/openmw/mwinput/inputmanagerimp.hpp b/apps/openmw/mwinput/inputmanagerimp.hpp index bc62ef7dc..361babec4 100644 --- a/apps/openmw/mwinput/inputmanagerimp.hpp +++ b/apps/openmw/mwinput/inputmanagerimp.hpp @@ -175,6 +175,7 @@ namespace MWInput bool mGrabCursor; + bool mInvertX; bool mInvertY; bool mControlsDisabled; diff --git a/apps/openmw/mwmechanics/aipackage.cpp b/apps/openmw/mwmechanics/aipackage.cpp index c2e5c9afb..4646875fd 100644 --- a/apps/openmw/mwmechanics/aipackage.cpp +++ b/apps/openmw/mwmechanics/aipackage.cpp @@ -413,5 +413,5 @@ DetourNavigator::Flags MWMechanics::AiPackage::getNavigatorFlags(const MWWorld:: bool MWMechanics::AiPackage::canActorMoveByZAxis(const MWWorld::Ptr& actor) const { MWBase::World* world = MWBase::Environment::get().getWorld(); - return (actor.getClass().canSwim(actor) && world->isSwimming(actor)) || world->isFlying(actor); + return (actor.getClass().canSwim(actor) && world->isSwimming(actor)) || world->isFlying(actor) || !world->isActorCollisionEnabled(actor); } diff --git a/apps/openmw/mwmechanics/aiwander.cpp b/apps/openmw/mwmechanics/aiwander.cpp index 129d1347b..837d49f38 100644 --- a/apps/openmw/mwmechanics/aiwander.cpp +++ b/apps/openmw/mwmechanics/aiwander.cpp @@ -209,7 +209,8 @@ namespace MWMechanics } bool actorCanMoveByZ = (actor.getClass().canSwim(actor) && MWBase::Environment::get().getWorld()->isSwimming(actor)) - || MWBase::Environment::get().getWorld()->isFlying(actor); + || MWBase::Environment::get().getWorld()->isFlying(actor) + || !MWBase::Environment::get().getWorld()->isActorCollisionEnabled(actor); if(actorCanMoveByZ && mDistance > 0) { // Typically want to idle for a short time before the next wander diff --git a/apps/openmw/mwmechanics/character.cpp b/apps/openmw/mwmechanics/character.cpp index d4015cbfe..92e06bc7a 100644 --- a/apps/openmw/mwmechanics/character.cpp +++ b/apps/openmw/mwmechanics/character.cpp @@ -435,6 +435,43 @@ void CharacterController::refreshJumpAnims(const WeaponInfo* weap, JumpingState } } +bool CharacterController::onOpen() +{ + if (mPtr.getTypeName() == typeid(ESM::Container).name()) + { + if (!mAnimation->hasAnimation("containeropen")) + return true; + + if (mAnimation->isPlaying("containeropen")) + return false; + + if (mAnimation->isPlaying("containerclose")) + return false; + + mAnimation->play("containeropen", Priority_Persistent, MWRender::Animation::BlendMask_All, false, 1.0f, "start", "stop", 0.f, 0); + if (mAnimation->isPlaying("containeropen")) + return false; + } + + return true; +} + +void CharacterController::onClose() +{ + if (mPtr.getTypeName() == typeid(ESM::Container).name()) + { + if (!mAnimation->hasAnimation("containerclose")) + return; + + float complete, startPoint = 0.f; + bool animPlaying = mAnimation->getInfo("containeropen", &complete); + if (animPlaying) + startPoint = 1.f - complete; + + mAnimation->play("containerclose", Priority_Persistent, MWRender::Animation::BlendMask_All, false, 1.0f, "start", "stop", startPoint, 0); + } +} + void CharacterController::refreshMovementAnims(const WeaponInfo* weap, CharacterState movement, CharacterState& idle, bool force) { if (movement == mMovementState && idle == mIdleState && !force) @@ -1109,6 +1146,8 @@ void CharacterController::handleTextKey(const std::string &groupname, const std: else if (groupname == "shield" && evt.compare(off, len, "block hit") == 0) mPtr.getClass().block(mPtr); + else if (groupname == "containeropen" && evt.compare(off, len, "loot") == 0) + MWBase::Environment::get().getWindowManager()->pushGuiMode(MWGui::GM_Container, mPtr); } void CharacterController::updatePtr(const MWWorld::Ptr &ptr) @@ -1711,11 +1750,7 @@ bool CharacterController::updateWeaponState(CharacterState& idle) } } - // We should reset player's idle animation in the first-person mode. - if (resetIdle && mPtr == player && MWBase::Environment::get().getWorld()->isFirstPerson()) - idle = CharState_None; - - // In other cases we should not break swim and sneak animations + // We should not break swim and sneak animations if (resetIdle && idle != CharState_IdleSneak && idle != CharState_IdleSwim && mIdleState != CharState_IdleSneak && mIdleState != CharState_IdleSwim) @@ -1975,6 +2010,7 @@ void CharacterController::update(float duration, bool animationOnly) bool incapacitated = (cls.getCreatureStats(mPtr).isParalyzed() || cls.getCreatureStats(mPtr).getKnockedDown()); bool inwater = world->isSwimming(mPtr); bool flying = world->isFlying(mPtr); + bool solid = world->isActorCollisionEnabled(mPtr); // Can't run and sneak while flying (see speed formula in Npc/Creature::getSpeed) bool sneak = cls.getCreatureStats(mPtr).getStance(MWMechanics::CreatureStats::Stance_Sneak) && !flying; bool isrunning = cls.getCreatureStats(mPtr).getStance(MWMechanics::CreatureStats::Stance_Run) && !flying; @@ -1983,7 +2019,7 @@ void CharacterController::update(float duration, bool animationOnly) //Force Jump Logic bool isMoving = (std::abs(cls.getMovementSettings(mPtr).mPosition[0]) > .5 || std::abs(cls.getMovementSettings(mPtr).mPosition[1]) > .5); - if(!inwater && !flying) + if(!inwater && !flying && solid) { //Force Jump if(stats.getMovementFlag(MWMechanics::CreatureStats::Flag_ForceJump)) @@ -2124,12 +2160,12 @@ void CharacterController::update(float duration, bool animationOnly) cls.getCreatureStats(mPtr).setFatigue(fatigue); } - if(sneak || inwater || flying || incapacitated) + if(sneak || inwater || flying || incapacitated || !solid) vec.z() = 0.0f; bool inJump = true; bool playLandingSound = false; - if(!onground && !flying && !inwater) + if(!onground && !flying && !inwater && solid) { // In the air (either getting up —ascending part of jump— or falling). @@ -2182,7 +2218,7 @@ void CharacterController::update(float duration, bool animationOnly) } } } - else if(mJumpState == JumpState_InAir && !inwater && !flying) + else if(mJumpState == JumpState_InAir && !inwater && !flying && solid) { forcestateupdate = true; jumpstate = JumpState_Landing; @@ -2221,7 +2257,7 @@ void CharacterController::update(float duration, bool animationOnly) } else { - if(mPtr.getClass().isNpc() && mJumpState == JumpState_InAir && !flying) + if(mPtr.getClass().isNpc() && mJumpState == JumpState_InAir && !flying && solid) playLandingSound = true; jumpstate = mAnimation->isPlaying(mCurrentJump) ? JumpState_Landing : JumpState_None; diff --git a/apps/openmw/mwmechanics/character.hpp b/apps/openmw/mwmechanics/character.hpp index 0f4b3aa90..7e6e82c07 100644 --- a/apps/openmw/mwmechanics/character.hpp +++ b/apps/openmw/mwmechanics/character.hpp @@ -259,6 +259,9 @@ public: void update(float duration, bool animationOnly=false); + bool onOpen(); + void onClose(); + void persistAnimationState(); void unpersistAnimationState(); diff --git a/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp b/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp index b6cc4136c..c47d3e248 100644 --- a/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp +++ b/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp @@ -871,6 +871,20 @@ namespace MWMechanics return false; } + bool MechanicsManager::onOpen(const MWWorld::Ptr& ptr) + { + if(ptr.getClass().isActor()) + return true; + else + return mObjects.onOpen(ptr); + } + + void MechanicsManager::onClose(const MWWorld::Ptr& ptr) + { + if(!ptr.getClass().isActor()) + mObjects.onClose(ptr); + } + void MechanicsManager::persistAnimationStates() { mActors.persistAnimationStates(); diff --git a/apps/openmw/mwmechanics/mechanicsmanagerimp.hpp b/apps/openmw/mwmechanics/mechanicsmanagerimp.hpp index 64565c031..84f4e568c 100644 --- a/apps/openmw/mwmechanics/mechanicsmanagerimp.hpp +++ b/apps/openmw/mwmechanics/mechanicsmanagerimp.hpp @@ -192,6 +192,9 @@ namespace MWMechanics virtual void playerLoaded() override; + virtual bool onOpen(const MWWorld::Ptr& ptr) override; + virtual void onClose(const MWWorld::Ptr& ptr) override; + virtual int countSavedGameRecords() const override; virtual void write (ESM::ESMWriter& writer, Loading::Listener& listener) const override; diff --git a/apps/openmw/mwmechanics/objects.cpp b/apps/openmw/mwmechanics/objects.cpp index e95c0a704..726508161 100644 --- a/apps/openmw/mwmechanics/objects.cpp +++ b/apps/openmw/mwmechanics/objects.cpp @@ -1,8 +1,10 @@ #include "objects.hpp" #include +#include #include "../mwbase/environment.hpp" +#include "../mwbase/windowmanager.hpp" #include "../mwbase/world.hpp" #include "movement.hpp" @@ -77,6 +79,40 @@ void Objects::update(float duration, bool paused) for(PtrControllerMap::iterator iter(mObjects.begin());iter != mObjects.end();++iter) iter->second->update(duration); } + else + { + // We still should play container opening animation in the Container GUI mode. + MWGui::GuiMode mode = MWBase::Environment::get().getWindowManager()->getMode(); + if(mode != MWGui::GM_Container) + return; + + for(PtrControllerMap::iterator iter(mObjects.begin());iter != mObjects.end();++iter) + { + if (iter->first.getTypeName() != typeid(ESM::Container).name()) + continue; + + if (iter->second->isAnimPlaying("containeropen")) + { + iter->second->update(duration); + MWBase::Environment::get().getWorld()->updateAnimatedCollisionShape(iter->first); + } + } + } +} + +bool Objects::onOpen(const MWWorld::Ptr& ptr) +{ + PtrControllerMap::iterator iter = mObjects.find(ptr); + if(iter != mObjects.end()) + return iter->second->onOpen(); + return false; +} + +void Objects::onClose(const MWWorld::Ptr& ptr) +{ + PtrControllerMap::iterator iter = mObjects.find(ptr); + if(iter != mObjects.end()) + iter->second->onClose(); } bool Objects::playAnimationGroup(const MWWorld::Ptr& ptr, const std::string& groupName, int mode, int number, bool persist) diff --git a/apps/openmw/mwmechanics/objects.hpp b/apps/openmw/mwmechanics/objects.hpp index 1efebafbe..81b95baf8 100644 --- a/apps/openmw/mwmechanics/objects.hpp +++ b/apps/openmw/mwmechanics/objects.hpp @@ -38,6 +38,9 @@ namespace MWMechanics void update(float duration, bool paused); ///< Update object animations + bool onOpen(const MWWorld::Ptr& ptr); + void onClose(const MWWorld::Ptr& ptr); + bool playAnimationGroup(const MWWorld::Ptr& ptr, const std::string& groupName, int mode, int number, bool persist=false); void skipAnimation(const MWWorld::Ptr& ptr); void persistAnimationStates(); diff --git a/apps/openmw/mwphysics/physicssystem.cpp b/apps/openmw/mwphysics/physicssystem.cpp index ab384cf23..555e9239e 100644 --- a/apps/openmw/mwphysics/physicssystem.cpp +++ b/apps/openmw/mwphysics/physicssystem.cpp @@ -1361,7 +1361,7 @@ namespace MWPhysics float heightDiff = position.z() - oldHeight; MWMechanics::CreatureStats& stats = iter->first.getClass().getCreatureStats(iter->first); - if ((wasOnGround && physicActor->getOnGround()) || flying || world->isSwimming(iter->first) || slowFall < 1) + if ((numSteps > 0 && wasOnGround && physicActor->getOnGround()) || flying || world->isSwimming(iter->first) || slowFall < 1) stats.land(iter->first == player); else if (heightDiff < 0) stats.addToFallHeight(-heightDiff); @@ -1385,6 +1385,13 @@ namespace MWPhysics #endif } + void PhysicsSystem::updateAnimatedCollisionShape(const MWWorld::Ptr& object) + { + ObjectMap::iterator found = mObjects.find(object); + if (found != mObjects.end()) + found->second->animateCollisionShapes(mCollisionWorld); + } + void PhysicsSystem::debugDraw() { if (mDebugDrawer.get()) diff --git a/apps/openmw/mwphysics/physicssystem.hpp b/apps/openmw/mwphysics/physicssystem.hpp index 25091d482..de6c68d39 100644 --- a/apps/openmw/mwphysics/physicssystem.hpp +++ b/apps/openmw/mwphysics/physicssystem.hpp @@ -188,6 +188,8 @@ namespace MWPhysics End of tes3mp addition */ + void updateAnimatedCollisionShape(const MWWorld::Ptr& object); + template void forEachAnimatedObject(Function&& function) const { diff --git a/apps/openmw/mwsound/openal_output.cpp b/apps/openmw/mwsound/openal_output.cpp index 39e872b0c..ccb3f22b5 100644 --- a/apps/openmw/mwsound/openal_output.cpp +++ b/apps/openmw/mwsound/openal_output.cpp @@ -4,6 +4,7 @@ #include #include #include +#include #include @@ -279,7 +280,7 @@ private: std::unique_ptr mLoudnessAnalyzer; - volatile bool mIsFinished; + std::atomic mIsFinished; void updateAll(bool local); @@ -313,7 +314,7 @@ struct OpenAL_Output::StreamThread : public OpenThreads::Thread { typedef std::vector StreamVec; StreamVec mStreams; - volatile bool mQuitNow; + std::atomic mQuitNow; OpenThreads::Mutex mMutex; OpenThreads::Condition mCondVar; diff --git a/apps/openmw/mwworld/actionopen.cpp b/apps/openmw/mwworld/actionopen.cpp index 7ff6dd068..f678037ce 100644 --- a/apps/openmw/mwworld/actionopen.cpp +++ b/apps/openmw/mwworld/actionopen.cpp @@ -1,6 +1,7 @@ #include "actionopen.hpp" #include "../mwbase/environment.hpp" +#include "../mwbase/mechanicsmanager.hpp" #include "../mwbase/windowmanager.hpp" #include "../mwmechanics/disease.hpp" @@ -20,6 +21,9 @@ namespace MWWorld if (!MWBase::Environment::get().getWindowManager()->isAllowed(MWGui::GW_Inventory)) return; + if (!MWBase::Environment::get().getMechanicsManager()->onOpen(getTarget())) + return; + MWMechanics::diseaseContact(actor, getTarget()); MWBase::Environment::get().getWindowManager()->pushGuiMode(MWGui::GM_Container, getTarget()); diff --git a/apps/openmw/mwworld/cellpreloader.cpp b/apps/openmw/mwworld/cellpreloader.cpp index a06c208b5..3bf66a5a1 100644 --- a/apps/openmw/mwworld/cellpreloader.cpp +++ b/apps/openmw/mwworld/cellpreloader.cpp @@ -1,5 +1,7 @@ #include "cellpreloader.hpp" +#include + #include #include #include @@ -159,7 +161,7 @@ namespace MWWorld MWRender::LandManager* mLandManager; bool mPreloadInstances; - volatile bool mAbort; + std::atomic mAbort; osg::ref_ptr mTerrainView; @@ -392,7 +394,7 @@ namespace MWWorld } private: - volatile bool mAbort; + std::atomic mAbort; std::vector > mTerrainViews; Terrain::World* mWorld; std::vector mPreloadPositions; diff --git a/apps/openmw/mwworld/inventorystore.cpp b/apps/openmw/mwworld/inventorystore.cpp index 0c08ee544..fb06f0a4d 100644 --- a/apps/openmw/mwworld/inventorystore.cpp +++ b/apps/openmw/mwworld/inventorystore.cpp @@ -163,7 +163,7 @@ MWWorld::ContainerStoreIterator MWWorld::InventoryStore::add(const Ptr& itemPtr, } if (mListener) - mListener->itemAdded(itemPtr, count); + mListener->itemAdded(*retVal, count); return retVal; } diff --git a/apps/openmw/mwworld/store.cpp b/apps/openmw/mwworld/store.cpp index ec9965a6c..7df61bec3 100644 --- a/apps/openmw/mwworld/store.cpp +++ b/apps/openmw/mwworld/store.cpp @@ -1007,14 +1007,13 @@ namespace MWWorld } void Store::setUp() { - for (int i = 0; i < ESM::Attribute::Length; ++i) { - mStatic.push_back( - ESM::Attribute( - ESM::Attribute::sAttributeIds[i], - ESM::Attribute::sGmstAttributeIds[i], - ESM::Attribute::sGmstAttributeDescIds[i] - ) - ); + for (int i = 0; i < ESM::Attribute::Length; ++i) + { + ESM::Attribute newAttribute; + newAttribute.mId = ESM::Attribute::sAttributeIds[i]; + newAttribute.mName = ESM::Attribute::sGmstAttributeIds[i]; + newAttribute.mDescription = ESM::Attribute::sGmstAttributeDescIds[i]; + mStatic.push_back(newAttribute); } } size_t Store::getSize() const @@ -1059,18 +1058,20 @@ namespace MWWorld { // Load default marker definitions, if game files do not have them for some reason std::pair markers[] = { - std::make_pair("DivineMarker", "marker_divine.nif"), - std::make_pair("DoorMarker", "marker_arrow.nif"), - std::make_pair("NorthMarker", "marker_north.nif"), - std::make_pair("TempleMarker", "marker_temple.nif"), - std::make_pair("TravelMarker", "marker_travel.nif") + std::make_pair("divinemarker", "marker_divine.nif"), + std::make_pair("doormarker", "marker_arrow.nif"), + std::make_pair("northmarker", "marker_north.nif"), + std::make_pair("templemarker", "marker_temple.nif"), + std::make_pair("travelmarker", "marker_travel.nif") }; - for (const std::pair marker : markers) + for (const std::pair &marker : markers) { if (search(marker.first) == 0) { - ESM::Static newMarker = ESM::Static(marker.first, marker.second); + ESM::Static newMarker; + newMarker.mId = marker.first; + newMarker.mModel = marker.second; std::pair ret = mStatic.insert(std::make_pair(marker.first, newMarker)); if (ret.first != mStatic.end()) { @@ -1085,14 +1086,16 @@ namespace MWWorld { // Load default Door type marker definitions std::pair markers[] = { - std::make_pair("PrisonMarker", "marker_prison.nif") + std::make_pair("prisonmarker", "marker_prison.nif") }; - for (const std::pair marker : markers) + for (const std::pair &marker : markers) { if (search(marker.first) == 0) { - ESM::Door newMarker = ESM::Door(marker.first, std::string(), marker.second, std::string(), std::string(), std::string()); + ESM::Door newMarker; + newMarker.mId = marker.first; + newMarker.mModel = marker.second; std::pair ret = mStatic.insert(std::make_pair(marker.first, newMarker)); if (ret.first != mStatic.end()) { diff --git a/apps/openmw/mwworld/worldimp.cpp b/apps/openmw/mwworld/worldimp.cpp index c8b27990d..7dd826fd9 100644 --- a/apps/openmw/mwworld/worldimp.cpp +++ b/apps/openmw/mwworld/worldimp.cpp @@ -1587,7 +1587,7 @@ namespace MWWorld pos.z() += 20; // place slightly above. will snap down to ground with code below - if (force || !isFlying(ptr)) + if (force || !ptr.getClass().isActor() || (!isFlying(ptr) && isActorCollisionEnabled(ptr))) { osg::Vec3f traced = mPhysics->traceDown(ptr, pos, Constants::CellSizeInUnits); if (traced.z() < pos.z()) @@ -1757,6 +1757,11 @@ namespace MWWorld End of tes3mp addition */ + void World::updateAnimatedCollisionShape(const Ptr &ptr) + { + mPhysics->updateAnimatedCollisionShape(ptr); + } + void World::doPhysics(float duration) { mPhysics->stepSimulation(duration); @@ -2521,11 +2526,11 @@ namespace MWWorld bool World::isFlying(const MWWorld::Ptr &ptr) const { - const MWMechanics::CreatureStats &stats = ptr.getClass().getCreatureStats(ptr); - if(!ptr.getClass().isActor()) return false; + const MWMechanics::CreatureStats &stats = ptr.getClass().getCreatureStats(ptr); + if (stats.isDead()) return false; @@ -2537,7 +2542,7 @@ namespace MWWorld return true; const MWPhysics::Actor* actor = mPhysics->getActor(ptr); - if(!actor || !actor->getCollisionMode()) + if(!actor) return true; return false; diff --git a/apps/openmw/mwworld/worldimp.hpp b/apps/openmw/mwworld/worldimp.hpp index 799a03600..63be4575b 100644 --- a/apps/openmw/mwworld/worldimp.hpp +++ b/apps/openmw/mwworld/worldimp.hpp @@ -547,6 +547,8 @@ namespace MWWorld End of tes3mp addition */ + void updateAnimatedCollisionShape(const Ptr &ptr) override; + bool castRay (float x1, float y1, float z1, float x2, float y2, float z2, int mask) override; ///< cast a Ray and return true if there is an object in the ray path. diff --git a/apps/wizard/mainwizard.hpp b/apps/wizard/mainwizard.hpp index 7f6e48a87..a05013d98 100644 --- a/apps/wizard/mainwizard.hpp +++ b/apps/wizard/mainwizard.hpp @@ -9,9 +9,10 @@ #ifndef Q_MOC_RUN #include -#endif + #include #include +#endif namespace Wizard { diff --git a/cmake/FindOSGPlugins.cmake b/cmake/FindOSGPlugins.cmake index 8220f33d4..c210466c0 100644 --- a/cmake/FindOSGPlugins.cmake +++ b/cmake/FindOSGPlugins.cmake @@ -1,5 +1,6 @@ # This module accepts the following env variable # OSGPlugins_LIB_DIR - /lib/osgPlugins- , path to search plugins +# OSGPlugins_DONT_FIND_DEPENDENCIES - Set to skip also finding png, zlib and jpeg # # Once done this will define # OSGPlugins_FOUND - System has the all required components. @@ -41,10 +42,12 @@ foreach(_library ${OSGPlugins_FIND_COMPONENTS}) list(APPEND OSGPlugins_PROCESS_LIBS ${_component}_LIBRARY) endforeach() -foreach(_dependency PNG ZLIB JPEG) # needed by osgdb_png or osgdb_jpeg - libfind_package(OSGPlugins ${_dependency}) - set(${_dependency}_LIBRARY_OPTS ${_dependency}_LIBRARY) - #list(APPEND OSGPlugins_PROCESS_LIBS ${_dependency}_LIBRARY) -endforeach() +if(NOT DEFINED OSGPlugins_DONT_FIND_DEPENDENCIES) + foreach(_dependency PNG ZLIB JPEG) # needed by osgdb_png or osgdb_jpeg + libfind_package(OSGPlugins ${_dependency}) + set(${_dependency}_LIBRARY_OPTS ${_dependency}_LIBRARY) + #list(APPEND OSGPlugins_PROCESS_LIBS ${_dependency}_LIBRARY) + endforeach() +endif() libfind_process(OSGPlugins) diff --git a/components/debug/debugging.cpp b/components/debug/debugging.cpp index e89a65956..2d05fbc55 100644 --- a/components/debug/debugging.cpp +++ b/components/debug/debugging.cpp @@ -2,8 +2,42 @@ #include +#ifdef _WIN32 +# undef WIN32_LEAN_AND_MEAN +# define WIN32_LEAN_AND_MEAN +# include +#endif + namespace Debug { +#ifdef _WIN32 + bool attachParentConsole() + { + if (GetConsoleWindow() != nullptr) + return true; + + if (AttachConsole(ATTACH_PARENT_PROCESS)) + { + fflush(stdout); + fflush(stderr); + std::cout.flush(); + std::cerr.flush(); + + // this looks dubious but is really the right way + _wfreopen(L"CON", L"w", stdout); + _wfreopen(L"CON", L"w", stderr); + _wfreopen(L"CON", L"r", stdin); + freopen("CON", "w", stdout); + freopen("CON", "w", stderr); + freopen("CON", "r", stdin); + + return true; + } + + return false; + } +#endif + std::streamsize DebugOutputBase::write(const char *str, std::streamsize size) { // Skip debug level marker @@ -52,6 +86,10 @@ namespace Debug int wrapApplication(int (*innerApplication)(int argc, char *argv[]), int argc, char *argv[], const std::string& appName) { +#if defined _WIN32 + (void)Debug::attachParentConsole(); +#endif + // Some objects used to redirect cout and cerr // Scope must be here, so this still works inside the catch block for logging exceptions std::streambuf* cout_rdbuf = std::cout.rdbuf (); diff --git a/components/debug/debugging.hpp b/components/debug/debugging.hpp index 361f321cb..81b01d055 100644 --- a/components/debug/debugging.hpp +++ b/components/debug/debugging.hpp @@ -10,6 +10,12 @@ #include "debuglog.hpp" +#if defined _WIN32 && defined _DEBUG +# undef WIN32_LEAN_AND_MEAN +# define WIN32_LEAN_AND_MEAN +# include +#endif + namespace Debug { // ANSI colors for terminal @@ -43,11 +49,11 @@ namespace Debug } }; -#if defined(_WIN32) && defined(_DEBUG) -#ifndef WIN32_LEAN_AND_MEAN -#define WIN32_LEAN_AND_MEAN 1 -#endif // !WIN32_LEAN_AND_MEAN -#include +#ifdef _WIN32 + bool attachParentConsole(); +#endif + +#if defined _WIN32 && defined _DEBUG class DebugOutput : public DebugOutputBase { public: diff --git a/components/detournavigator/navmeshtilescache.hpp b/components/detournavigator/navmeshtilescache.hpp index 45c0a6bb3..7418c4d3a 100644 --- a/components/detournavigator/navmeshtilescache.hpp +++ b/components/detournavigator/navmeshtilescache.hpp @@ -56,12 +56,12 @@ namespace DetourNavigator Value(Value&& other) : mOwner(other.mOwner), mIterator(other.mIterator) { - other.mIterator = ItemIterator(); + other.mOwner = nullptr; } ~Value() { - if (mIterator != ItemIterator()) + if (mOwner) mOwner->releaseItem(mIterator); } @@ -69,16 +69,13 @@ namespace DetourNavigator Value& operator =(Value&& other) { - if (mIterator == other.mIterator) - return *this; - - if (mIterator != ItemIterator()) + if (mOwner) mOwner->releaseItem(mIterator); mOwner = other.mOwner; mIterator = other.mIterator; - other.mIterator = ItemIterator(); + other.mOwner = nullptr; return *this; } @@ -90,7 +87,7 @@ namespace DetourNavigator operator bool() const { - return mIterator != ItemIterator(); + return mOwner; } private: diff --git a/components/esm/attr.hpp b/components/esm/attr.hpp index 993de6ccb..c0a54c659 100644 --- a/components/esm/attr.hpp +++ b/components/esm/attr.hpp @@ -32,13 +32,6 @@ struct Attribute static const std::string sGmstAttributeIds[Length]; static const std::string sGmstAttributeDescIds[Length]; static const std::string sAttributeIcons[Length]; - - Attribute(AttributeID id, const std::string &name, const std::string &description) - : mId(id) - , mName(name) - , mDescription(description) - { - } }; } #endif diff --git a/components/esm/loaddoor.hpp b/components/esm/loaddoor.hpp index 955abec89..3afe5d5e4 100644 --- a/components/esm/loaddoor.hpp +++ b/components/esm/loaddoor.hpp @@ -22,21 +22,6 @@ struct Door void blank(); ///< Set record to default state (does not touch the ID). - - Door(const std::string id, const std::string name, const std::string &model, - const std::string script, const std::string opensound, const std::string closesound) - : mId(id) - , mName(name) - , mModel(model) - , mScript(script) - , mOpenSound(opensound) - , mCloseSound(closesound) - { - } - - Door() - { - } }; } #endif diff --git a/components/esm/loadstat.hpp b/components/esm/loadstat.hpp index f80875b65..3d9144040 100644 --- a/components/esm/loadstat.hpp +++ b/components/esm/loadstat.hpp @@ -33,16 +33,6 @@ struct Static void blank(); ///< Set record to default state (does not touch the ID). - - Static(const std::string id, const std::string &model) - : mId(id) - , mModel(model) - { - } - - Static() - { - } }; } #endif diff --git a/components/fallback/fallback.cpp b/components/fallback/fallback.cpp index edc3f2678..9e64d5fea 100644 --- a/components/fallback/fallback.cpp +++ b/components/fallback/fallback.cpp @@ -1,70 +1,95 @@ #include "fallback.hpp" -#include +#include +#include namespace Fallback { - bool stob(std::string const& s) { - return s != "0"; - } - Map::Map(const std::map& fallback):mFallbackMap(fallback) {} std::string Map::getFallbackString(const std::string& fall) const { std::map::const_iterator it; - if((it = mFallbackMap.find(fall)) == mFallbackMap.end()) + if ((it = mFallbackMap.find(fall)) == mFallbackMap.end()) { - return ""; + return std::string(); } return it->second; } float Map::getFallbackFloat(const std::string& fall) const { - std::string fallback=getFallbackString(fall); - if (fallback.empty()) - return 0; - else - return boost::lexical_cast(fallback); + std::string fallback = getFallbackString(fall); + if (!fallback.empty()) + { + try + { + // We have to rely on Boost because std::stof from C++11 + // uses the current locale for separators which we don't want and often silently ignores parsing errors. + return boost::lexical_cast(fallback); + } + catch (boost::bad_lexical_cast&) + { + Log(Debug::Error) << "Error: '" << fall << "' setting value (" << fallback << ") is not a valid number, using 0 as a fallback"; + } + } + + return 0; } int Map::getFallbackInt(const std::string& fall) const { - std::string fallback=getFallbackString(fall); - if (fallback.empty()) - return 0; - else - return std::stoi(fallback); + std::string fallback = getFallbackString(fall); + if (!fallback.empty()) + { + try + { + return std::stoi(fallback); + } + catch (const std::invalid_argument&) + { + Log(Debug::Error) << "Error: '" << fall << "' setting value (" << fallback << ") is not a valid number, using 0 as a fallback"; + } + catch (const std::out_of_range&) + { + Log(Debug::Error) << "Error: '" << fall << "' setting value (" << fallback << ") is out of range, using 0 as a fallback"; + } + } + + return 0; } bool Map::getFallbackBool(const std::string& fall) const { - std::string fallback=getFallbackString(fall); - if (fallback.empty()) - return false; - else - return stob(fallback); + std::string fallback = getFallbackString(fall); + return !fallback.empty() && fallback != "0"; } osg::Vec4f Map::getFallbackColour(const std::string& fall) const { - std::string sum=getFallbackString(fall); - if (sum.empty()) - return osg::Vec4f(0.5f,0.5f,0.5f,1.f); - else + std::string sum = getFallbackString(fall); + if (!sum.empty()) { - std::string ret[3]; - unsigned int j=0; - for(unsigned int i=0;i +#include + namespace SceneUtil { @@ -176,6 +178,10 @@ void MorphGeometry::cull(osg::NodeVisitor *nv) positionDst->dirty(); +#if OSG_MIN_VERSION_REQUIRED(3, 5, 6) + geom.dirtyGLObjects(); +#endif + nv->pushOntoNodePath(&geom); nv->apply(geom); nv->popFromNodePath(); diff --git a/components/sceneutil/riggeometry.cpp b/components/sceneutil/riggeometry.cpp index 30a3f076c..b086cf628 100644 --- a/components/sceneutil/riggeometry.cpp +++ b/components/sceneutil/riggeometry.cpp @@ -3,6 +3,8 @@ #include #include +#include + #include #include "skeleton.hpp" @@ -235,6 +237,10 @@ void RigGeometry::cull(osg::NodeVisitor* nv) if (tangentDst) tangentDst->dirty(); +#if OSG_MIN_VERSION_REQUIRED(3, 5, 6) + geom.dirtyGLObjects(); +#endif + nv->pushOntoNodePath(&geom); nv->apply(geom); nv->popFromNodePath(); diff --git a/components/sceneutil/workqueue.hpp b/components/sceneutil/workqueue.hpp index 2084df328..0b16db0e7 100644 --- a/components/sceneutil/workqueue.hpp +++ b/components/sceneutil/workqueue.hpp @@ -9,6 +9,7 @@ #include #include +#include #include namespace SceneUtil @@ -87,7 +88,7 @@ namespace SceneUtil private: WorkQueue* mWorkQueue; - volatile bool mActive; + std::atomic mActive; }; diff --git a/docs/source/reference/modding/font.rst b/docs/source/reference/modding/font.rst index 213cdf760..cae320633 100644 --- a/docs/source/reference/modding/font.rst +++ b/docs/source/reference/modding/font.rst @@ -4,9 +4,8 @@ Fonts Morrowind .fnt fonts -------------------- -Morrowind uses a custom ``.fnt`` file format. It is not compatible with the Windows Font File ``.fnt`` format, -nor compatible with ``.fnt`` formats from any other Bethesda games. To our knowledge, -the format is undocumented and no tools for viewing or editing these fonts exist. +Morrowind uses a custom ``.fnt`` file format. It is not compatible with the Windows Font File ``.fnt`` format. +To our knowledge, the format is undocumented. OpenMW can load this format and convert it on the fly into something usable (see font loader `source code `_). @@ -16,20 +15,62 @@ In OpenMW 0.32, an --export-fonts command line option was added to write the con TrueType fonts -------------- -Unlike vanilla Morrowind, OpenMW directly supports TrueType (``.ttf``) fonts. -This is the recommended way to create new fonts. +Unlike vanilla Morrowind, OpenMW directly supports TrueType (``.ttf``) fonts. + +0.45.0+ way +----------- +This is the recommended way to install replacement fonts. + +- To replace the primary "Magic Cards" font: + + #. Download `Pelagiad `_ by Isak Larborn (aka Isaskar). + #. Create ``Fonts`` folder at the location of your ``openmw.cfg``. + #. Copy ``openmw_font.xml`` and ``Pelagiad.ttf`` files into the folder. + #. If desired, you can now delete the original ``Magic_Cards.*`` files from your ``Data Files/Fonts`` directory. + #. Pelagiad glyphs may appear to be pretty small, so open ``openmw.cfg`` and adjust the following settings as you deem necessary:: + + [GUI] + font size = 17 + ttf resolution = 96 + +- You can also replace the Daedric font: + + #. Download `Ayembedt `_ by Georg Duffner. + #. Install ``OMWAyembedt.otf`` into the ``Fonts`` folder. + #. Add the following lines into ``openmw_font.xml``:: + + + + + + + + + + + + + + #. This font is missing a few glyphs (mostly punctuation), but it has all the primary glyphs. If desired, you can now delete the original ``daedric.*`` files from your ``Data Files/Fonts`` directory. + +Any Resolution or Size properties in the file have no effect because the engine settings override them. + +The engine automatically takes UI scaling factor into account, so don't account for it when tweaking the settings. + +Pre-0.45.0 way +-------------- - To replace the primary "Magic Cards" font: #. Download `Pelagiad `_ by Isak Larborn (aka Isaskar). #. Install the ``openmw_font.xml`` file into ``resources/mygui/openmw_font.xml`` in your OpenMW installation. #. Copy ``Pelagiad.ttf`` into ``resources/mygui/`` as well. - #. If desired, you can now delete the original ``Magic_Cards.*`` files from your Data Files/Fonts directory. + #. If desired, you can now delete the original ``Magic_Cards.*`` files from your ``Data Files/Fonts`` directory. - You can also replace the Daedric font: #. Download `Ayembedt `_ by Georg Duffner. #. Install ``OMWAyembedt.otf`` into ``/resources/mygui/`` folder in your OpenMW installation. - #. Add the following lines to openmw_font.xml:: + #. Add the following lines to ``openmw_font.xml``:: @@ -45,12 +86,12 @@ This is the recommended way to create new fonts. - #. This font is missing a few glyphs (mostly punctuation), but is complete in the primary glyphs. If desired, you can now delete the original ``daedric.*`` files from your Data Files/Fonts directory. + #. This font is missing a few glyphs (mostly punctuation), but it has all the primary glyphs. If desired, you can now delete the original ``daedric.*`` files from your ``Data Files/Fonts`` directory. - Another replacement for the Daedric font is `Oblivion `_ by Dongle. - #. Install the ``Oblivion.ttf`` file resources/mygui/. - #. The openmw_fonts.xml entry is:: + #. Install the ``Oblivion.ttf`` file into ``resources/mygui/``. + #. The ``openmw_font.xml`` entry is:: @@ -80,7 +121,7 @@ This is the recommended way to create new fonts. Bitmap fonts ------------ -Morrowind ``.fnt`` files are essentially a bitmap font, but using them is discouraged because of no Unicode support. +Morrowind ``.fnt`` files are essentially a bitmap font, but using them is discouraged because they don't have Unicode support. MyGUI has its own format for bitmap fonts. An example can be seen by using the --export-fonts command line option (see above), which converts Morrowind ``.fnt`` to a MyGUI bitmap font. This is the recommended format to use if you wish to edit Morrowind's bitmap font or create a new bitmap font. diff --git a/docs/source/reference/modding/settings/input.rst b/docs/source/reference/modding/settings/input.rst index 36c8fa41a..321c28afd 100644 --- a/docs/source/reference/modding/settings/input.rst +++ b/docs/source/reference/modding/settings/input.rst @@ -94,6 +94,20 @@ meaning that it should remain set at 1.0 unless the player desires to have diffe This setting can only be configured by editing the settings configuration file. +invert x axis +------------- + +:Type: boolean +:Range: True/False +:Default: False + + +Invert the horizontal axis while not in GUI mode. +If this setting is true, moving the mouse to the left will cause the view to rotate counter-clockwise, +while moving it to the right will cause the view to rotate clockwise. This setting does not affect cursor movement in GUI mode. + +This setting can be toggled in game with the Invert X Axis button in the Controls panel of the Options menu. + invert y axis ------------- diff --git a/extern/osg-ffmpeg-videoplayer/videostate.hpp b/extern/osg-ffmpeg-videoplayer/videostate.hpp index 2fdb98da5..6abaa64cd 100644 --- a/extern/osg-ffmpeg-videoplayer/videostate.hpp +++ b/extern/osg-ffmpeg-videoplayer/videostate.hpp @@ -2,8 +2,10 @@ #define VIDEOPLAYER_VIDEOSTATE_H #include +#include #include #include +#include #include #include @@ -77,7 +79,7 @@ struct PacketQueue { { clear(); } AVPacketList *first_pkt, *last_pkt; - volatile bool flushing; + std::atomic flushing; int nb_packets; int size; @@ -168,12 +170,12 @@ struct VideoState { std::unique_ptr parse_thread; std::unique_ptr video_thread; - volatile bool mSeekRequested; + std::atomic mSeekRequested; uint64_t mSeekPos; - volatile bool mVideoEnded; - volatile bool mPaused; - volatile bool mQuit; + std::atomic mVideoEnded; + std::atomic mPaused; + std::atomic mQuit; }; } diff --git a/files/mygui/openmw_settings_window.layout b/files/mygui/openmw_settings_window.layout index 3c2664857..8062980ff 100644 --- a/files/mygui/openmw_settings_window.layout +++ b/files/mygui/openmw_settings_window.layout @@ -214,6 +214,16 @@ + + + + + + + + + + @@ -223,10 +233,10 @@ - + - + @@ -236,11 +246,11 @@ - + - + diff --git a/files/openmw.appdata.xml b/files/openmw.appdata.xml index 5c093e3c4..39504070c 100644 --- a/files/openmw.appdata.xml +++ b/files/openmw.appdata.xml @@ -1,7 +1,7 @@ org.openmw.desktop @@ -43,9 +43,9 @@ Copyright 2017 Bret Curtis RolePlaying - + https://openmw.org - https://bugs.openmw.org/ + https://gitlab.com/OpenMW/openmw/issues https://openmw.org/faq/ diff --git a/files/settings-default.cfg b/files/settings-default.cfg index dad915cbb..71a93d1a2 100644 --- a/files/settings-default.cfg +++ b/files/settings-default.cfg @@ -333,6 +333,9 @@ camera sensitivity = 1.0 # (>0.0, Because it's a multiplier values should be near 1.0) camera y multiplier = 1.0 +# Invert the horizontal axis while not in GUI mode. +invert x axis = false + # Invert the vertical axis while not in GUI mode. invert y axis = false