diff --git a/.gitignore b/.gitignore index 827c0a072..0ee4a6399 100644 --- a/.gitignore +++ b/.gitignore @@ -81,5 +81,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/CHANGELOG.md b/CHANGELOG.md index 1f44e83b3..d28da21ce 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -8,9 +8,14 @@ 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 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_script.msvc.sh b/CI/before_script.msvc.sh index 615055712..dfc3b3147 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/CMakeLists.txt b/CMakeLists.txt index ade1f1457..722467f32 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -59,6 +59,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}") @@ -71,6 +72,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 @@ -256,8 +269,14 @@ set(USED_OSG_PLUGINS 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) @@ -346,6 +365,9 @@ endif (APPLE) 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") @@ -807,15 +829,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/world/data.cpp b/apps/opencs/model/world/data.cpp index 63c7a52a8..53bd04147 100644 --- a/apps/opencs/model/world/data.cpp +++ b/apps/opencs/model/world/data.cpp @@ -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( 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/mwbase/mechanicsmanager.hpp b/apps/openmw/mwbase/mechanicsmanager.hpp index 056628211..1bdd8f8b5 100644 --- a/apps/openmw/mwbase/mechanicsmanager.hpp +++ b/apps/openmw/mwbase/mechanicsmanager.hpp @@ -237,6 +237,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 ffacb267c..dfae5700b 100644 --- a/apps/openmw/mwbase/world.hpp +++ b/apps/openmw/mwbase/world.hpp @@ -303,6 +303,8 @@ namespace MWBase ///< Queues movement for \a ptr (in local space), to be applied in the next call to /// doPhysics. + 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 2f9643f74..51c0603ca 100644 --- a/apps/openmw/mwgui/container.cpp +++ b/apps/openmw/mwgui/container.cpp @@ -162,6 +162,8 @@ namespace MWGui if (mModel) mModel->onClose(); + + MWBase::Environment::get().getMechanicsManager()->onClose(mPtr); } void ContainerWindow::onCloseButtonClicked(MyGUI::Widget* _sender) diff --git a/apps/openmw/mwinput/inputmanagerimp.cpp b/apps/openmw/mwinput/inputmanagerimp.cpp index 0d017ba90..be1301aac 100644 --- a/apps/openmw/mwinput/inputmanagerimp.cpp +++ b/apps/openmw/mwinput/inputmanagerimp.cpp @@ -52,6 +52,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")) @@ -467,7 +468,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)) @@ -646,6 +647,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"); @@ -827,7 +831,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]; @@ -1169,7 +1173,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 cdb2fdc7c..418962901 100644 --- a/apps/openmw/mwmechanics/character.cpp +++ b/apps/openmw/mwmechanics/character.cpp @@ -419,6 +419,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) @@ -446,11 +483,10 @@ void CharacterController::refreshMovementAnims(const WeaponInfo* weap, Character if(!mAnimation->hasAnimation(movementAnimName)) { - movemask = MWRender::Animation::BlendMask_LowerBody; movementAnimName = movestate->groupname; - if (swimpos == std::string::npos) { + movemask = MWRender::Animation::BlendMask_LowerBody; // Since we apply movement only for lower body, do not reset idle animations. // For upper body there will be idle animation. if (idle == CharState_None) @@ -462,7 +498,11 @@ void CharacterController::refreshMovementAnims(const WeaponInfo* weap, Character } else if (idle == CharState_None) { - idle = CharState_IdleSwim; + // In the 1st-person mode use ground idle animations as fallback + if (mPtr == getPlayer() && MWBase::Environment::get().getWorld()->isFirstPerson()) + idle = CharState_Idle; + else + idle = CharState_IdleSwim; } } } @@ -1076,6 +1116,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) @@ -1247,6 +1289,7 @@ bool CharacterController::updateWeaponState(CharacterState& idle) std::string upSoundId; std::string downSoundId; + bool weaponChanged = false; if (mPtr.getClass().hasInventoryStore(mPtr)) { MWWorld::InventoryStore &inv = cls.getInventoryStore(mPtr); @@ -1264,7 +1307,13 @@ bool CharacterController::updateWeaponState(CharacterState& idle) if(weapon == inv.end() && !mWeapon.isEmpty() && weaptype == WeapType_HandToHand && mWeaponType != WeapType_Spell) downSoundId = mWeapon.getClass().getDownSoundId(mWeapon); - mWeapon = weapon != inv.end() ? *weapon : MWWorld::Ptr(); + MWWorld::Ptr newWeapon = weapon != inv.end() ? *weapon : MWWorld::Ptr(); + + if (mWeapon != newWeapon) + { + mWeapon = newWeapon; + weaponChanged = true; + } } // Use blending only with 3d-person movement animations for bipedal actors @@ -1299,9 +1348,8 @@ bool CharacterController::updateWeaponState(CharacterState& idle) && mUpperBodyState != UpperCharState_UnEquipingWeap && !isStillWeapon) { - // We can not play un-equip animation when we switch to HtH - // because we already un-equipped weapon - if (weaptype != WeapType_HandToHand || mWeaponType == WeapType_Spell) + // We can not play un-equip animation if weapon changed since last update + if (!weaponChanged) { // Note: we do not disable unequipping animation automatically to avoid body desync getWeaponGroup(mWeaponType, weapgroup); @@ -1613,13 +1661,13 @@ 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 - if (resetIdle && mIdleState != CharState_IdleSneak && mIdleState != CharState_IdleSwim) + // We should not break swim and sneak animations + if (resetIdle && + idle != CharState_IdleSneak && idle != CharState_IdleSwim && + mIdleState != CharState_IdleSneak && mIdleState != CharState_IdleSwim) + { idle = CharState_None; + } animPlaying = mAnimation->getInfo(mCurrentWeapon, &complete); if(mUpperBodyState == UpperCharState_MinAttackToMaxAttack && !isKnockedDown()) @@ -1873,6 +1921,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; @@ -1881,7 +1930,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)) @@ -1989,11 +2038,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; - if(!onground && !flying && !inwater) + bool playLandingSound = false; + if(!onground && !flying && !inwater && solid) { // In the air (either getting up —ascending part of jump— or falling). @@ -2046,7 +2096,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; @@ -2080,20 +2130,14 @@ void CharacterController::update(float duration, bool animationOnly) } } - // Play landing sound for NPCs if (mPtr.getClass().isNpc()) - { - MWBase::SoundManager *sndMgr = MWBase::Environment::get().getSoundManager(); - std::string sound = "DefaultLand"; - osg::Vec3f pos(mPtr.getRefData().getPosition().asVec3()); - if (world->isUnderwater(mPtr.getCell(), pos) || world->isWalkingOnWater(mPtr)) - sound = "DefaultLandWater"; - - sndMgr->playSound3D(mPtr, sound, 1.f, 1.f, MWSound::Type::Foot, MWSound::PlayMode::NoPlayerLocal); - } + playLandingSound = true; } else { + if(mPtr.getClass().isNpc() && mJumpState == JumpState_InAir && !flying && solid) + playLandingSound = true; + jumpstate = mAnimation->isPlaying(mCurrentJump) ? JumpState_Landing : JumpState_None; vec.z() = 0.0f; @@ -2143,6 +2187,17 @@ void CharacterController::update(float duration, bool animationOnly) } } + if (playLandingSound) + { + MWBase::SoundManager *sndMgr = MWBase::Environment::get().getSoundManager(); + std::string sound = "DefaultLand"; + osg::Vec3f pos(mPtr.getRefData().getPosition().asVec3()); + if (world->isUnderwater(mPtr.getCell(), pos) || world->isWalkingOnWater(mPtr)) + sound = "DefaultLandWater"; + + sndMgr->playSound3D(mPtr, sound, 1.f, 1.f, MWSound::Type::Foot, MWSound::PlayMode::NoPlayerLocal); + } + // Player can not use smooth turning as NPCs, so we play turning animation a bit to avoid jittering if (isPlayer) { 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 a907fb89f..43a082348 100644 --- a/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp +++ b/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp @@ -845,6 +845,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 7b6bbc636..a1fce4fa9 100644 --- a/apps/openmw/mwmechanics/mechanicsmanagerimp.hpp +++ b/apps/openmw/mwmechanics/mechanicsmanagerimp.hpp @@ -182,6 +182,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 57b6d348b..836370255 100644 --- a/apps/openmw/mwphysics/physicssystem.cpp +++ b/apps/openmw/mwphysics/physicssystem.cpp @@ -1363,6 +1363,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 d4829f623..7d7f5a33c 100644 --- a/apps/openmw/mwphysics/physicssystem.hpp +++ b/apps/openmw/mwphysics/physicssystem.hpp @@ -178,6 +178,8 @@ namespace MWPhysics bool isOnSolidGround (const MWWorld::Ptr& actor) const; + void updateAnimatedCollisionShape(const MWWorld::Ptr& object); + template void forEachAnimatedObject(Function&& function) const { 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/inventorystore.cpp b/apps/openmw/mwworld/inventorystore.cpp index 6fe1d0c73..8b35d8dcc 100644 --- a/apps/openmw/mwworld/inventorystore.cpp +++ b/apps/openmw/mwworld/inventorystore.cpp @@ -150,7 +150,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..70f8cf44f 100644 --- a/apps/openmw/mwworld/store.cpp +++ b/apps/openmw/mwworld/store.cpp @@ -1059,11 +1059,11 @@ 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) @@ -1085,7 +1085,7 @@ 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) diff --git a/apps/openmw/mwworld/worldimp.cpp b/apps/openmw/mwworld/worldimp.cpp index 6fd11c2af..cb5ded593 100644 --- a/apps/openmw/mwworld/worldimp.cpp +++ b/apps/openmw/mwworld/worldimp.cpp @@ -1385,7 +1385,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()) @@ -1527,6 +1527,11 @@ namespace MWWorld mPhysics->queueObjectMovement(ptr, velocity); } + void World::updateAnimatedCollisionShape(const Ptr &ptr) + { + mPhysics->updateAnimatedCollisionShape(ptr); + } + void World::doPhysics(float duration) { mPhysics->stepSimulation(duration); @@ -2229,11 +2234,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; @@ -2245,7 +2250,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 8b3be2013..51953cd40 100644 --- a/apps/openmw/mwworld/worldimp.hpp +++ b/apps/openmw/mwworld/worldimp.hpp @@ -412,6 +412,8 @@ namespace MWWorld ///< Queues movement for \a ptr (in local space), to be applied in the next call to /// doPhysics. + 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/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..a60d6032f 100644 --- a/extern/osg-ffmpeg-videoplayer/videostate.hpp +++ b/extern/osg-ffmpeg-videoplayer/videostate.hpp @@ -4,6 +4,7 @@ #include #include #include +#include #include #include 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 df9ea3008..240530be0 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