diff --git a/.travis.yml b/.travis.yml index 042d4b8f1..1fc85dca3 100644 --- a/.travis.yml +++ b/.travis.yml @@ -21,6 +21,14 @@ addons: build_command_prepend: "cmake ." build_command: "make -j3" branch_pattern: coverity_scan +matrix: + include: + - os: linux + env: + ANALYZE="scan-build-3.6 --use-cc clang-3.6 --use-c++ clang++-3.6 " + compiler: clang + allow_failures: + - env: ANALYZE="scan-build-3.6 --use-cc clang-3.6 --use-c++ clang++-3.6 " before_install: - if [ "${TRAVIS_OS_NAME}" = "linux" ]; then ./CI/before_install.linux.sh; fi @@ -30,8 +38,8 @@ before_script: - if [ "${TRAVIS_OS_NAME}" = "osx" ]; then ./CI/before_script.osx.sh; fi script: - cd ./build - - if [ "$COVERITY_SCAN_BRANCH" != 1 ]; then make -j4; fi - - if [ "$COVERITY_SCAN_BRANCH" != 1 ] && ["${TRAVIS_OS_NAME}" = "osx"]; then make package; fi + - if [ "$COVERITY_SCAN_BRANCH" != 1 ]; then ${ANALYZE}make -j4; fi + - if [ "$COVERITY_SCAN_BRANCH" != 1 ] && [ "${TRAVIS_OS_NAME}" = "osx" ]; then make package; fi after_script: - if [ "${TRAVIS_OS_NAME}" = "linux" ]; then ./openmw_test_suite; fi notifications: diff --git a/AUTHORS.md b/AUTHORS.md index 540c0ede5..0cd961c61 100644 --- a/AUTHORS.md +++ b/AUTHORS.md @@ -39,6 +39,8 @@ Programmers Eli2 Emanuel Guével (potatoesmaster) eroen + escondida + Evgeniy Mineev (sandstranger) Fil Krynicki (filkry) Gašper Sedej gugus/gus @@ -91,7 +93,6 @@ Programmers Rohit Nirmal Roman Melnik (Kromgart) Roman Proskuryakov (humbug) - sandstranger Sandy Carter (bwrsandman) Scott Howard Sebastian Wick (swick) diff --git a/CHANGELOG.md b/CHANGELOG.md index c2aa03dc2..1766aa21d 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,42 @@ +0.35.1 +------ + + Bug #781: incorrect trajectory of the sun + Bug #1079: Wrong starting position in "Character Stuff Wonderland" + Bug #1443: Repetitive taking of a stolen object is repetitively considered as a crime + Bug #1533: Divine Intervention goes to the wrong place. + Bug #1714: No visual indicator for time passed during training + Bug #1916: Telekinesis does not allow safe opening of traps + Bug #2227: Editor: addon file name inconsistency + Bug #2271: Player can melee enemies from water with impunity + Bug #2275: Objects with bigger scale move further using Move script + Bug #2285: Aryon's Dominator enchantment does not work properly + Bug #2290: No punishment for stealing gold from owned containers + Bug #2328: Launcher does not respond to Ctrl+C + Bug #2334: Drag-and-drop on a content file in the launcher creates duplicate items + Bug #2338: Arrows reclaimed from corpses do not stack sometimes + Bug #2344: Launcher - Settings importer running correctly? + Bug #2346: Launcher - Importing plugins into content list screws up the load order + Bug #2348: Mod: H.E.L.L.U.V.A. Handy Holdables does not appear in the content list + Bug #2353: Detect Animal detects dead creatures + Bug #2354: Cmake does not respect LIB_SUFFIX + Bug #2356: Active magic set inactive when switching magic items + Bug #2361: ERROR: ESM Error: Previous record contains unread bytes + Bug #2382: Switching spells with "next spell" or "previous spell" while holding shift promps delete spell dialog + Bug #2388: Regression: Can't toggle map on/off + Bug #2392: MOD Shrines - Restore Health and Cancel Options adds 100 health points + Bug #2394: List of Data Files tab in openmw-laucher needs to show all content files. + Bug #2402: Editor: skills saved incorrectly + Bug #2408: Equipping a constant effect Restore Health/Magicka/Fatigue item will permanently boost the stat it's restoring + Bug #2415: It is now possible to fall off the prison ship into the water when starting a new game + Bug #2419: MOD MCA crash to desktop + Bug #2420: Game crashes when character enters a certain area + Bug #2421: infinite loop when using cycle weapon without having a weapon + Feature #2221: Cannot dress dead NPCs + Feature #2349: Check CMake sets correct MSVC compiler settings for release build. + Feature #2397: Set default values for global mandatory records. + Feature #2412: Basic joystick support + 0.35.0 ------ diff --git a/CI/before_install.linux.sh b/CI/before_install.linux.sh index 998c285db..27cb71463 100755 --- a/CI/before_install.linux.sh +++ b/CI/before_install.linux.sh @@ -1,7 +1,12 @@ #!/bin/sh -export CXX=g++ -export CC=gcc +if [ "${ANALYZE}" ]; then + if [ $(lsb_release -sc) = "precise" ]; then + echo "yes" | sudo apt-add-repository ppa:ubuntu-toolchain-r/test + fi + echo "yes" | sudo add-apt-repository "deb http://llvm.org/apt/`lsb_release -sc`/ llvm-toolchain-`lsb_release -sc`-3.6 main" + wget -O - http://llvm.org/apt/llvm-snapshot.gpg.key|sudo apt-key add - +fi echo "yes" | sudo add-apt-repository "deb http://archive.ubuntu.com/ubuntu `lsb_release -sc` main universe restricted multiverse" echo "yes" | sudo apt-add-repository ppa:openmw/openmw @@ -10,6 +15,7 @@ sudo apt-get install -qq libgtest-dev google-mock sudo apt-get install -qq libboost-filesystem-dev libboost-program-options-dev libboost-system-dev libboost-thread-dev libboost-wave-dev sudo apt-get install -qq libavcodec-dev libavformat-dev libavutil-dev libswscale-dev libavresample-dev sudo apt-get install -qq libbullet-dev libogre-1.9-dev libmygui-dev libsdl2-dev libunshield-dev libtinyxml-dev libopenal-dev libqt4-dev +if [ "${ANALYZE}" ]; then sudo apt-get install -qq clang-3.6; fi sudo mkdir /usr/src/gtest/build cd /usr/src/gtest/build sudo cmake .. -DBUILD_SHARED_LIBS=1 diff --git a/CI/before_script.linux.sh b/CI/before_script.linux.sh index b4889c9e1..71ddd2040 100755 --- a/CI/before_script.linux.sh +++ b/CI/before_script.linux.sh @@ -2,4 +2,6 @@ mkdir build cd build -cmake .. -DBUILD_WITH_CODE_COVERAGE=1 -DBUILD_UNITTESTS=1 -DCMAKE_INSTALL_PREFIX=/usr -DBINDIR=/usr/games -DCMAKE_BUILD_TYPE="RelWithDebInfo" -DUSE_SYSTEM_TINYXML=TRUE +export CODE_COVERAGE=1 +if [ "${CC}" = "clang" ]; then export CODE_COVERAGE=0; fi +${ANALYZE}cmake .. -DBUILD_WITH_CODE_COVERAGE=${CODE_COVERAGE} -DBUILD_UNITTESTS=1 -DCMAKE_INSTALL_PREFIX=/usr -DBINDIR=/usr/games -DCMAKE_BUILD_TYPE="RelWithDebInfo" -DUSE_SYSTEM_TINYXML=TRUE diff --git a/CMakeLists.txt b/CMakeLists.txt index 17abedb4c..0785ef28c 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -20,7 +20,7 @@ message(STATUS "Configuring OpenMW...") set(OPENMW_VERSION_MAJOR 0) set(OPENMW_VERSION_MINOR 35) -set(OPENMW_VERSION_RELEASE 0) +set(OPENMW_VERSION_RELEASE 1) set(OPENMW_VERSION_COMMITHASH "") set(OPENMW_VERSION_TAGHASH "") @@ -98,43 +98,6 @@ endif() # We probably support older versions than this. cmake_minimum_required(VERSION 2.6) -# source directory: libs - -set(LIBS_DIR ${CMAKE_SOURCE_DIR}/libs) - -set(OENGINE_OGRE - ${LIBS_DIR}/openengine/ogre/renderer.cpp - ${LIBS_DIR}/openengine/ogre/lights.cpp - ${LIBS_DIR}/openengine/ogre/selectionbuffer.cpp - ${LIBS_DIR}/openengine/ogre/imagerotate.cpp -) - -set(OENGINE_GUI - ${LIBS_DIR}/openengine/gui/loglistener.cpp - ${LIBS_DIR}/openengine/gui/manager.cpp - ${LIBS_DIR}/openengine/gui/layout.cpp -) - -set(OENGINE_BULLET - ${LIBS_DIR}/openengine/bullet/BtOgre.cpp - ${LIBS_DIR}/openengine/bullet/BtOgreExtras.h - ${LIBS_DIR}/openengine/bullet/BtOgreGP.h - ${LIBS_DIR}/openengine/bullet/BtOgrePG.h - ${LIBS_DIR}/openengine/bullet/physic.cpp - ${LIBS_DIR}/openengine/bullet/physic.hpp - ${LIBS_DIR}/openengine/bullet/BulletShapeLoader.cpp - ${LIBS_DIR}/openengine/bullet/BulletShapeLoader.h - ${LIBS_DIR}/openengine/bullet/trace.cpp - ${LIBS_DIR}/openengine/bullet/trace.h - -) - -set(OENGINE_ALL ${OENGINE_OGRE} ${OENGINE_GUI} ${OENGINE_BULLET}) -source_group(libs\\openengine FILES ${OENGINE_ALL}) - -set(OPENMW_LIBS ${OENGINE_ALL}) -set(OPENMW_LIBS_HEADER) - # Sound setup set(FFmpeg_FIND_COMPONENTS AVCODEC AVFORMAT AVUTIL SWSCALE SWRESAMPLE AVRESAMPLE) unset(FFMPEG_LIBRARIES CACHE) @@ -270,7 +233,8 @@ endif () endif(WIN32) endif(OGRE_STATIC) -include_directories("." +include_directories("." ${LIBS_DIR} + SYSTEM ${OGRE_INCLUDE_DIR} ${OGRE_INCLUDE_DIR}/Ogre ${OGRE_INCLUDE_DIR}/OGRE ${OGRE_INCLUDE_DIRS} ${OGRE_PLUGIN_INCLUDE_DIRS} ${OGRE_INCLUDE_DIR}/Overlay ${OGRE_Overlay_INCLUDE_DIR} ${SDL2_INCLUDE_DIR} @@ -279,7 +243,7 @@ include_directories("." ${MYGUI_INCLUDE_DIRS} ${MYGUI_PLATFORM_INCLUDE_DIRS} ${OPENAL_INCLUDE_DIR} - ${LIBS_DIR} + ${BULLET_INCLUDE_DIRS} ) link_directories(${SDL2_LIBRARY_DIRS} ${Boost_LIBRARY_DIRS} ${OGRE_LIB_DIR} ${MYGUI_LIB_DIR}) @@ -379,6 +343,9 @@ configure_file(${OpenMW_SOURCE_DIR}/files/opencs.ini configure_file(${OpenMW_SOURCE_DIR}/files/opencs/defaultfilters "${OpenMW_BINARY_DIR}/resources/defaultfilters" COPYONLY) +configure_file(${OpenMW_SOURCE_DIR}/files/gamecontrollerdb.txt + "${OpenMW_BINARY_DIR}/gamecontrollerdb.txt") + if (NOT WIN32 AND NOT APPLE) configure_file(${OpenMW_SOURCE_DIR}/files/openmw.desktop "${OpenMW_BINARY_DIR}/openmw.desktop") @@ -386,22 +353,22 @@ if (NOT WIN32 AND NOT APPLE) "${OpenMW_BINARY_DIR}/openmw-cs.desktop") endif() -# Compiler settings -if (CMAKE_COMPILER_IS_GNUCC) - SET(CMAKE_CXX_FLAGS "-Wall -Wextra -Wno-unused-parameter -Wno-reorder -std=c++98 -pedantic -Wno-long-long ${CMAKE_CXX_FLAGS}") +# CXX Compiler settings +if (CMAKE_CXX_COMPILER_ID STREQUAL GNU OR CMAKE_CXX_COMPILER_ID STREQUAL Clang) + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wall -Wextra -Wno-unused-parameter -Wno-reorder -std=c++98 -pedantic -Wno-long-long") execute_process(COMMAND ${CMAKE_C_COMPILER} -dumpversion OUTPUT_VARIABLE GCC_VERSION) - if ("${GCC_VERSION}" VERSION_GREATER 4.6 OR "${GCC_VERSION}" VERSION_EQUAL 4.6) - SET(CMAKE_CXX_FLAGS "-Wno-unused-but-set-parameter ${CMAKE_CXX_FLAGS}") - endif("${GCC_VERSION}" VERSION_GREATER 4.6 OR "${GCC_VERSION}" VERSION_EQUAL 4.6) + if (CMAKE_CXX_COMPILER_ID STREQUAL GNU AND "${GCC_VERSION}" VERSION_GREATER 4.6 OR "${GCC_VERSION}" VERSION_EQUAL 4.6) + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wno-unused-but-set-parameter") + endif(CMAKE_CXX_COMPILER_ID STREQUAL GNU AND "${GCC_VERSION}" VERSION_GREATER 4.6 OR "${GCC_VERSION}" VERSION_EQUAL 4.6) elseif (MSVC) # Enable link-time code generation globally for all linking set(CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS_RELEASE} /GL") set(CMAKE_EXE_LINKER_FLAGS_RELEASE "${CMAKE_EXE_LINKER_FLAGS_RELEASE} /LTCG") set(CMAKE_SHARED_LINKER_FLAGS_RELEASE "${CMAKE_SHARED_LINKER_FLAGS_RELEASE} /LTCG") set(CMAKE_STATIC_LINKER_FLAGS_RELEASE "${CMAKE_STATIC_LINKER_FLAGS_RELEASE} /LTCG") -endif (CMAKE_COMPILER_IS_GNUCC) +endif (CMAKE_CXX_COMPILER_ID STREQUAL GNU OR CMAKE_CXX_COMPILER_ID STREQUAL Clang) IF(NOT WIN32 AND NOT APPLE) # Linux building @@ -468,6 +435,8 @@ IF(NOT WIN32 AND NOT APPLE) INSTALL(FILES "${OpenMW_BINARY_DIR}/settings-default.cfg" DESTINATION "${SYSCONFDIR}" COMPONENT "openmw") INSTALL(FILES "${OpenMW_BINARY_DIR}/transparency-overrides.cfg" DESTINATION "${SYSCONFDIR}" COMPONENT "openmw") INSTALL(FILES "${OpenMW_BINARY_DIR}/openmw.cfg.install" DESTINATION "${SYSCONFDIR}" RENAME "openmw.cfg" COMPONENT "openmw") + INSTALL(FILES "${OpenMW_BINARY_DIR}/gamecontrollerdb.txt" DESTINATION "${SYSCONFDIR}" COMPONENT "openmw") + IF(BUILD_OPENCS) INSTALL(FILES "${OpenMW_BINARY_DIR}/opencs.ini" DESTINATION "${SYSCONFDIR}" COMPONENT "opencs") ENDIF(BUILD_OPENCS) @@ -488,6 +457,7 @@ if(WIN32) "${OpenMW_SOURCE_DIR}/Docs/license/DejaVu Font License.txt" "${OpenMW_BINARY_DIR}/settings-default.cfg" "${OpenMW_BINARY_DIR}/transparency-overrides.cfg" + "${OpenMW_BINARY_DIR}/gamecontrollerdb.txt" "${OpenMW_BINARY_DIR}/Release/openmw.exe" DESTINATION ".") @@ -572,6 +542,10 @@ if(WIN32) include(CPack) endif(WIN32) +# Libs +include_directories(libs) +add_subdirectory(libs/openengine) + # Extern #add_subdirectory (extern/shiny) #add_subdirectory (extern/ogre-ffmpeg-videoplayer) @@ -682,6 +656,7 @@ if (WIN32) 4193 # #pragma warning(pop) : no matching '#pragma warning(push)' 4251 # class 'XXXX' needs to have dll-interface to be used by clients of class 'YYYY' 4275 # non dll-interface struct 'XXXX' used as base for dll-interface class 'YYYY' + 4315 # undocumented, 'this' pointer for member might not be aligned (OgreMemoryStlAllocator.h) # caused by boost 4191 # 'type cast' : unsafe conversion (1.56, thread_primitives.hpp, normally off) @@ -689,6 +664,7 @@ if (WIN32) # OpenMW specific warnings 4099 # Type mismatch, declared class or struct is defined with other type 4100 # Unreferenced formal parameter (-Wunused-parameter) + 4101 # Unreferenced local variable (-Wunused-variable) 4127 # Conditional expression is constant 4242 # Storing value in a variable of a smaller type, possible loss of data 4244 # Storing value of one type in variable of another (size_t in int, for example) @@ -707,56 +683,23 @@ if (WIN32) set(WARNINGS "${WARNINGS} /wd${d}") endforeach(d) + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${WARNINGS} ${MT_BUILD}") + # boost::wave has a few issues with signed / unsigned conversions, so we suppress those here set(SHINY_WARNINGS "${WARNINGS} /wd4245") set_target_properties(shiny PROPERTIES COMPILE_FLAGS "${SHINY_WARNINGS} ${MT_BUILD}") - # there's an unreferenced local variable in the ogre platform, suppress it - set(SHINY_OGRE_WARNINGS "${WARNINGS} /wd4101") - set_target_properties(shiny.OgrePlatform PROPERTIES COMPILE_FLAGS "${SHINY_OGRE_WARNINGS} ${MT_BUILD}") - set_target_properties(sdl4ogre PROPERTIES COMPILE_FLAGS "${WARNINGS} ${MT_BUILD}") + # oics uses tinyxml, which has an initialized but unused variable set(OICS_WARNINGS "${WARNINGS} /wd4189") set_target_properties(oics PROPERTIES COMPILE_FLAGS "${OICS_WARNINGS} ${MT_BUILD}") - set_target_properties(components PROPERTIES COMPILE_FLAGS "${WARNINGS} ${MT_BUILD}") - if (BUILD_LAUNCHER) - set_target_properties(openmw-launcher PROPERTIES COMPILE_FLAGS "${WARNINGS} ${MT_BUILD}") - endif (BUILD_LAUNCHER) - set_target_properties(openmw PROPERTIES COMPILE_FLAGS "${WARNINGS} ${MT_BUILD}") - if (BUILD_BSATOOL) - set_target_properties(bsatool PROPERTIES COMPILE_FLAGS "${WARNINGS} ${MT_BUILD}") - endif (BUILD_BSATOOL) - if (BUILD_ESMTOOL) - set_target_properties(esmtool PROPERTIES COMPILE_FLAGS "${WARNINGS} ${MT_BUILD}") - endif (BUILD_ESMTOOL) - if (BUILD_WIZARD) - set_target_properties(openmw-wizard PROPERTIES COMPILE_FLAGS ${WARNINGS}) - endif (BUILD_WIZARD) + if (BUILD_OPENCS) # QT triggers an informational warning that the object layout may differ when compiled with /vd2 set(OPENCS_WARNINGS "${WARNINGS} ${MT_BUILD} /wd4435") set_target_properties(openmw-cs PROPERTIES COMPILE_FLAGS ${OPENCS_WARNINGS}) endif (BUILD_OPENCS) - if (BUILD_MWINIIMPORTER) - set_target_properties(openmw-iniimporter PROPERTIES COMPILE_FLAGS "${WARNINGS} ${MT_BUILD}") - endif (BUILD_MWINIIMPORTER) endif(MSVC) - # Same for MinGW - if (MINGW) - if (USE_DEBUG_CONSOLE) - set_target_properties(openmw PROPERTIES LINK_FLAGS_DEBUG "-Wl,-subsystem,console") - set_target_properties(openmw PROPERTIES LINK_FLAGS_RELWITHDEBINFO "-Wl,-subsystem,console") - set_target_properties(openmw PROPERTIES COMPILE_DEFINITIONS_DEBUG "_CONSOLE") - else(USE_DEBUG_CONSOLE) - set_target_properties(openmw PROPERTIES LINK_FLAGS_DEBUG "-Wl,-subsystem,windows") - set_target_properties(openmw PROPERTIES LINK_FLAGS_RELWITHDEBINFO "-Wl,-subsystem,windows") - endif(USE_DEBUG_CONSOLE) - - set_target_properties(openmw PROPERTIES LINK_FLAGS_RELEASE "-Wl,-subsystem,console") - set_target_properties(openmw PROPERTIES LINK_FLAGS_MINSIZEREL "-Wl,-subsystem,console") - set_target_properties(openmw PROPERTIES COMPILE_DEFINITIONS_RELEASE "_CONSOLE") - endif(MINGW) - # TODO: At some point release builds should not use the console but rather write to a log file #set_target_properties(openmw PROPERTIES LINK_FLAGS_RELEASE "/SUBSYSTEM:WINDOWS") #set_target_properties(openmw PROPERTIES LINK_FLAGS_MINSIZEREL "/SUBSYSTEM:WINDOWS") @@ -770,6 +713,7 @@ if (APPLE) install(DIRECTORY "${OpenMW_BINARY_DIR}/resources" DESTINATION "${INSTALL_SUBDIR}" COMPONENT Runtime) install(FILES "${OpenMW_BINARY_DIR}/openmw.cfg.install" RENAME "openmw.cfg" DESTINATION "${INSTALL_SUBDIR}" COMPONENT Runtime) install(FILES "${OpenMW_BINARY_DIR}/settings-default.cfg" DESTINATION "${INSTALL_SUBDIR}" COMPONENT Runtime) + install(FILES "${OpenMW_BINARY_DIR}/gamecontrollerdb.txt" DESTINATION "${INSTALL_SUBDIR}" COMPONENT Runtime) install(FILES "${OpenMW_BINARY_DIR}/transparency-overrides.cfg" DESTINATION "${INSTALL_SUBDIR}" COMPONENT Runtime) install(FILES "${OpenMW_BINARY_DIR}/opencs.ini" DESTINATION "${INSTALL_SUBDIR}" COMPONENT Runtime) diff --git a/README.md b/README.md index 63a313896..aa5af0e6d 100644 --- a/README.md +++ b/README.md @@ -6,7 +6,7 @@ OpenMW OpenMW is an attempt at recreating the engine for the popular role-playing game Morrowind by Bethesda Softworks. You need to own and install the original game for OpenMW to work. -* Version: 0.35.0 +* Version: 0.35.1 * License: GPL (see docs/license/GPL3.txt for more information) * Website: http://www.openmw.org * IRC: #openmw on irc.freenode.net @@ -23,7 +23,7 @@ Getting Started * [Testing the game](https://wiki.openmw.org/index.php?title=Testing) * [How to contribute](https://wiki.openmw.org/index.php?title=Contribution_Wanted) * [Report a bug](http://bugs.openmw.org/projects/openmw) - read the [guidelines](https://wiki.openmw.org/index.php?title=Bug_Reporting_Guidelines) before submitting your first bug! -* [Known issues] (http://bugs.openmw.org/projects/openmw/issues?utf8=%E2%9C%93&set_filter=1&f%5B%5D=status_id&op%5Bstatus_id%5D=%3D&v%5Bstatus_id%5D%5B%5D=7&f%5B%5D=tracker_id&op%5Btracker_id%5D=%3D&v%5Btracker_id%5D%5B%5D=1&f%5B%5D=&c%5B%5D=project&c%5B%5D=tracker&c%5B%5D=status&c%5B%5D=priority&c%5B%5D=subject&c%5B%5D=assigned_to&c%5B%5D=updated_on&group_by=tracker) +* [Known issues](http://bugs.openmw.org/projects/openmw/issues?utf8=%E2%9C%93&set_filter=1&f%5B%5D=status_id&op%5Bstatus_id%5D=%3D&v%5Bstatus_id%5D%5B%5D=7&f%5B%5D=tracker_id&op%5Btracker_id%5D=%3D&v%5Btracker_id%5D%5B%5D=1&f%5B%5D=&c%5B%5D=project&c%5B%5D=tracker&c%5B%5D=status&c%5B%5D=priority&c%5B%5D=subject&c%5B%5D=assigned_to&c%5B%5D=updated_on&group_by=tracker) The data path ------------- @@ -68,9 +68,9 @@ Command line options of the blacklist is enabled) --script-blacklist-use [=arg(=1)] (=1) enable script blacklisting - --load-savegame arg load a save game file on game startup - (specify an absolute filename or a - filename relative to the current + --load-savegame arg load a save game file on game startup + (specify an absolute filename or a + filename relative to the current working directory) --skip-menu [=arg(=1)] (=0) skip main menu on game startup --new-game [=arg(=1)] (=0) run new game sequence (ignored if diff --git a/apps/esmtool/esmtool.cpp b/apps/esmtool/esmtool.cpp index 3347aaf34..5b6e50b96 100644 --- a/apps/esmtool/esmtool.cpp +++ b/apps/esmtool/esmtool.cpp @@ -461,7 +461,7 @@ int clone(Arguments& info) for (Stats::iterator it = stats.begin(); it != stats.end(); ++it) { name.val = it->first; - float amount = it->second; + int amount = it->second; std::cout << std::setw(digitCount) << amount << " " << name.toString() << " "; if (++i % 3 == 0) diff --git a/apps/esmtool/record.cpp b/apps/esmtool/record.cpp index 97b0635fe..2ee6c54bb 100644 --- a/apps/esmtool/record.cpp +++ b/apps/esmtool/record.cpp @@ -6,6 +6,9 @@ #include +namespace +{ + void printAIPackage(ESM::AIPackage p) { std::cout << " AI Type: " << aiTypeLabel(p.mType) @@ -16,7 +19,7 @@ void printAIPackage(ESM::AIPackage p) std::cout << " Duration: " << p.mWander.mDuration << std::endl; std::cout << " Time of Day: " << (int)p.mWander.mTimeOfDay << std::endl; if (p.mWander.mShouldRepeat != 1) - std::cout << " Should repeat: " << (bool)p.mWander.mShouldRepeat << std::endl; + std::cout << " Should repeat: " << (bool)(p.mWander.mShouldRepeat != 0) << std::endl; std::cout << " Idle: "; for (int i = 0; i != 8; i++) @@ -149,6 +152,26 @@ void printEffectList(ESM::EffectList effects) } } +void printTransport(const std::vector& transport) +{ + std::vector::const_iterator dit; + for (dit = transport.begin(); dit != transport.end(); ++dit) + { + 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; + 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; + } +} + +} + namespace EsmTool { RecordBase * @@ -631,6 +654,8 @@ void Record::print() for (sit = mData.mSpells.mList.begin(); sit != mData.mSpells.mList.end(); ++sit) std::cout << " Spell: " << *sit << std::endl; + printTransport(mData.getTransport()); + std::cout << " Artifical Intelligence: " << mData.mHasAI << std::endl; std::cout << " AI Hello:" << (int)mData.mAiData.mHello << std::endl; std::cout << " AI Fight:" << (int)mData.mAiData.mFight << std::endl; @@ -1042,20 +1067,7 @@ void Record::print() for (sit = mData.mSpells.mList.begin(); sit != mData.mSpells.mList.end(); ++sit) std::cout << " Spell: " << *sit << std::endl; - std::vector::iterator dit; - for (dit = mData.mTransport.begin(); dit != mData.mTransport.end(); ++dit) - { - 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; - 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; - } + printTransport(mData.getTransport()); std::cout << " Artifical Intelligence: " << mData.mHasAI << std::endl; std::cout << " AI Hello:" << (int)mData.mAiData.mHello << std::endl; @@ -1253,7 +1265,7 @@ void Record::print() template<> void Record::print() { - std::cout << "Start Script: " << mData.mScript << std::endl; + std::cout << "Start Script: " << mData.mId << std::endl; std::cout << "Start Data: " << mData.mData << std::endl; } diff --git a/apps/essimporter/convertacdt.cpp b/apps/essimporter/convertacdt.cpp index 718403a8c..55a20ec3d 100644 --- a/apps/essimporter/convertacdt.cpp +++ b/apps/essimporter/convertacdt.cpp @@ -23,18 +23,18 @@ namespace ESSImport } for (int i=0; i<8; ++i) { - cStats.mAttributes[i].mBase = acdt.mAttributes[i][1]; - cStats.mAttributes[i].mMod = acdt.mAttributes[i][0]; - cStats.mAttributes[i].mCurrent = acdt.mAttributes[i][0]; + cStats.mAttributes[i].mBase = static_cast(acdt.mAttributes[i][1]); + cStats.mAttributes[i].mMod = static_cast(acdt.mAttributes[i][0]); + cStats.mAttributes[i].mCurrent = static_cast(acdt.mAttributes[i][0]); } cStats.mGoldPool = acdt.mGoldPool; - cStats.mTalkedTo = acdt.mFlags & TalkedToPlayer; - cStats.mAttacked = acdt.mFlags & Attacked; + cStats.mTalkedTo = (acdt.mFlags & TalkedToPlayer) != 0; + cStats.mAttacked = (acdt.mFlags & Attacked) != 0; } void convertACSC (const ACSC& acsc, ESM::CreatureStats& cStats) { - cStats.mDead = acsc.mFlags & Dead; + cStats.mDead = (acsc.mFlags & Dead) != 0; } void convertNpcData (const ActorData& actorData, ESM::NpcStats& npcStats) diff --git a/apps/essimporter/converter.hpp b/apps/essimporter/converter.hpp index c23083f8e..5711e6754 100644 --- a/apps/essimporter/converter.hpp +++ b/apps/essimporter/converter.hpp @@ -553,7 +553,7 @@ public: ESM::WeatherState weather; weather.mCurrentWeather = toString(mGame.mGMDT.mCurrentWeather); weather.mNextWeather = toString(mGame.mGMDT.mNextWeather); - weather.mRemainingTransitionTime = mGame.mGMDT.mWeatherTransition/100.f*(0.015*24*3600); + weather.mRemainingTransitionTime = mGame.mGMDT.mWeatherTransition/100.f*(0.015f*24*3600); weather.mHour = mContext->mHour; weather.mWindSpeed = 0.f; weather.mTimePassed = 0.0; diff --git a/apps/essimporter/importacdt.hpp b/apps/essimporter/importacdt.hpp index 47055092d..eacb2edf1 100644 --- a/apps/essimporter/importacdt.hpp +++ b/apps/essimporter/importacdt.hpp @@ -43,13 +43,17 @@ namespace ESSImport float mMagicEffects[27]; // Effect attributes: https://wiki.openmw.org/index.php?title=Research:Magic#Effect_attributes unsigned char mUnknown4[4]; unsigned int mGoldPool; - unsigned char mUnknown5[4]; + unsigned char mCountDown; // seen the same value as in ACSC.mCorpseClearCountdown, maybe + // this one is for respawning? + unsigned char mUnknown5[3]; }; struct ACSC { unsigned char mUnknown1[17]; unsigned char mFlags; // ACSCFlags - unsigned char mUnknown2[94]; + unsigned char mUnknown2[22]; + unsigned char mCorpseClearCountdown; // hours? + unsigned char mUnknown3[71]; }; #pragma pack(pop) diff --git a/apps/essimporter/importcellref.cpp b/apps/essimporter/importcellref.cpp index cca356b2a..442a7781c 100644 --- a/apps/essimporter/importcellref.cpp +++ b/apps/essimporter/importcellref.cpp @@ -43,7 +43,7 @@ namespace ESSImport { unsigned int deleted; esm.getHT(deleted); - mDeleted = (deleted >> 24) & 0x2; // the other 3 bytes seem to be uninitialized garbage + mDeleted = ((deleted >> 24) & 0x2) != 0; // the other 3 bytes seem to be uninitialized garbage } if (esm.isNextSub("MVRF")) diff --git a/apps/essimporter/importcrec.cpp b/apps/essimporter/importcrec.cpp index 7a8a3eb00..64879f2af 100644 --- a/apps/essimporter/importcrec.cpp +++ b/apps/essimporter/importcrec.cpp @@ -14,10 +14,10 @@ namespace ESSImport float scale; esm.getHNOT(scale, "XSCL"); - // FIXME: use AiPackageList, need to fix getSubName() + while (esm.isNextSub("AI_W") || esm.isNextSub("AI_E") || esm.isNextSub("AI_T") || esm.isNextSub("AI_F") || esm.isNextSub("AI_A")) - esm.skipHSub(); + mAiPackages.add(esm); mInventory.load(esm); } diff --git a/apps/essimporter/importcrec.hpp b/apps/essimporter/importcrec.hpp index 16b752807..5110fbc68 100644 --- a/apps/essimporter/importcrec.hpp +++ b/apps/essimporter/importcrec.hpp @@ -2,6 +2,7 @@ #define OPENMW_ESSIMPORT_CREC_H #include "importinventory.hpp" +#include namespace ESM { @@ -17,6 +18,7 @@ namespace ESSImport int mIndex; Inventory mInventory; + ESM::AIPackageList mAiPackages; void load(ESM::ESMReader& esm); }; diff --git a/apps/essimporter/importnpcc.cpp b/apps/essimporter/importnpcc.cpp index 547b01441..3cbd749ce 100644 --- a/apps/essimporter/importnpcc.cpp +++ b/apps/essimporter/importnpcc.cpp @@ -9,10 +9,9 @@ namespace ESSImport { esm.getHNT(mNPDT, "NPDT"); - // FIXME: use AiPackageList, need to fix getSubName() while (esm.isNextSub("AI_W") || esm.isNextSub("AI_E") || esm.isNextSub("AI_T") || esm.isNextSub("AI_F") || esm.isNextSub("AI_A")) - esm.skipHSub(); + mAiPackages.add(esm); mInventory.load(esm); } diff --git a/apps/essimporter/importnpcc.hpp b/apps/essimporter/importnpcc.hpp index c69fa3e03..a23ab1e50 100644 --- a/apps/essimporter/importnpcc.hpp +++ b/apps/essimporter/importnpcc.hpp @@ -27,6 +27,7 @@ namespace ESSImport } mNPDT; Inventory mInventory; + ESM::AIPackageList mAiPackages; void load(ESM::ESMReader &esm); }; diff --git a/apps/launcher/maindialog.cpp b/apps/launcher/maindialog.cpp index b93d55c17..4c142231d 100644 --- a/apps/launcher/maindialog.cpp +++ b/apps/launcher/maindialog.cpp @@ -61,6 +61,7 @@ Launcher::MainDialog::MainDialog(QWidget *parent) QString revision(OPENMW_VERSION_COMMITHASH); QString tag(OPENMW_VERSION_TAGHASH); + versionLabel->setTextInteractionFlags(Qt::TextSelectableByMouse); if (!revision.isEmpty() && !tag.isEmpty()) { if (revision == tag) { @@ -238,24 +239,8 @@ void Launcher::MainDialog::changePage(QListWidgetItem *current, QListWidgetItem current = previous; int currentIndex = iconWidget->row(current); -// int previousIndex = iconWidget->row(previous); - pagesWidget->setCurrentIndex(currentIndex); - - // DataFilesPage *previousPage = dynamic_cast(pagesWidget->widget(previousIndex)); - // DataFilesPage *currentPage = dynamic_cast(pagesWidget->widget(currentIndex)); - - // //special call to update/save data files page list view when it's displayed/hidden. - // if (previousPage) - // { - // if (previousPage->objectName() == "DataFilesPage") - // previousPage->saveSettings(); - // } - // else if (currentPage) - // { - // if (currentPage->objectName() == "DataFilesPage") - // currentPage->loadSettings(); - // } + mSettingsPage->resetProgressBar(); } bool Launcher::MainDialog::setupLauncherSettings() diff --git a/apps/launcher/settingspage.cpp b/apps/launcher/settingspage.cpp index c172a3121..34b4b41a9 100644 --- a/apps/launcher/settingspage.cpp +++ b/apps/launcher/settingspage.cpp @@ -39,6 +39,7 @@ Launcher::SettingsPage::SettingsPage(Files::ConfigurationManager &cfg, mWizardInvoker = new ProcessInvoker(); mImporterInvoker = new ProcessInvoker(); + resetProgressBar(); connect(mWizardInvoker->getProcess(), SIGNAL(started()), this, SLOT(wizardStarted())); @@ -94,7 +95,7 @@ Launcher::SettingsPage::~SettingsPage() void Launcher::SettingsPage::on_wizardButton_clicked() { - saveSettings(); + mMain->writeSettings(); if (!mWizardInvoker->startProcess(QLatin1String("openmw-wizard"), false)) return; @@ -102,7 +103,7 @@ void Launcher::SettingsPage::on_wizardButton_clicked() void Launcher::SettingsPage::on_importerButton_clicked() { - saveSettings(); + mMain->writeSettings(); // Create the file if it doesn't already exist, else the importer will fail QString path(QString::fromUtf8(mCfgMgr.getUserConfigPath().string().c_str())); @@ -141,8 +142,13 @@ void Launcher::SettingsPage::on_importerButton_clicked() qDebug() << "arguments " << arguments; + // start the progress bar as a "bouncing ball" + progressBar->setMaximum(0); + progressBar->setValue(0); if (!mImporterInvoker->startProcess(QLatin1String("openmw-iniimporter"), arguments, false)) - return; + { + resetProgressBar(); + } } void Launcher::SettingsPage::on_browseButton_clicked() @@ -197,38 +203,35 @@ void Launcher::SettingsPage::importerStarted() void Launcher::SettingsPage::importerFinished(int exitCode, QProcess::ExitStatus exitStatus) { if (exitCode != 0 || exitStatus == QProcess::CrashExit) - return; - - // Importer may have changed settings, so refresh - mMain->reloadSettings(); - - // Import selected data files from openmw.cfg - if (addonsCheckBox->isChecked()) { - // Because we've reloaded settings, the current content list matches content in OpenMW.cfg - QString oldContentListName = mLauncherSettings.getCurrentContentListName(); - if (mProfileDialog->exec() == QDialog::Accepted) - { - // remove the current content list to prevent duplication - //... except, not allowed to delete the Default content list - if (oldContentListName.compare(DataFilesPage::mDefaultContentListName) != 0) - { - mLauncherSettings.removeContentList(oldContentListName); - } + resetProgressBar(); - const QString newContentListName(mProfileDialog->lineEdit()->text()); - const QStringList files(mGameSettings.getContentList()); - mLauncherSettings.setCurrentContentListName(newContentListName); - mLauncherSettings.setContentList(newContentListName, files); + QMessageBox msgBox; + msgBox.setWindowTitle(tr("Importer finished")); + msgBox.setStandardButtons(QMessageBox::Ok); + msgBox.setIcon(QMessageBox::Warning); + msgBox.setText(tr("Failed to import settings from INI file.")); + msgBox.exec(); + } + else + { + // indicate progress finished + progressBar->setMaximum(1); + progressBar->setValue(1); - // Make DataFiles Page load the new content list. - mMain->reloadSettings(); - } + // Importer may have changed settings, so refresh + mMain->reloadSettings(); } importerButton->setEnabled(true); } +void Launcher::SettingsPage::resetProgressBar() +{ + // set progress bar to 0 % + progressBar->reset(); +} + void Launcher::SettingsPage::updateOkButton(const QString &text) { // We do this here because we need to access the profiles diff --git a/apps/launcher/settingspage.hpp b/apps/launcher/settingspage.hpp index 124c80600..ccc2061dd 100644 --- a/apps/launcher/settingspage.hpp +++ b/apps/launcher/settingspage.hpp @@ -29,6 +29,9 @@ namespace Launcher void saveSettings(); bool loadSettings(); + + /// set progress bar on page to 0% + void resetProgressBar(); private slots: @@ -57,7 +60,6 @@ namespace Launcher MainDialog *mMain; TextInputDialog *mProfileDialog; - }; } diff --git a/apps/mwiniimporter/importer.cpp b/apps/mwiniimporter/importer.cpp index 80f186b1f..479f8cba2 100644 --- a/apps/mwiniimporter/importer.cpp +++ b/apps/mwiniimporter/importer.cpp @@ -8,7 +8,8 @@ #include #include -#include +#include +#include #include namespace bfs = boost::filesystem; @@ -660,7 +661,7 @@ std::string MwIniImporter::numberToString(int n) { return str.str(); } -MwIniImporter::multistrmap MwIniImporter::loadIniFile(const std::string& filename) const { +MwIniImporter::multistrmap MwIniImporter::loadIniFile(const boost::filesystem::path& filename) const { std::cout << "load ini file: " << filename << std::endl; std::string section(""); @@ -719,7 +720,7 @@ MwIniImporter::multistrmap MwIniImporter::loadIniFile(const std::string& filenam return map; } -MwIniImporter::multistrmap MwIniImporter::loadCfgFile(const std::string& filename) { +MwIniImporter::multistrmap MwIniImporter::loadCfgFile(const boost::filesystem::path& filename) { std::cout << "load cfg file: " << filename << std::endl; MwIniImporter::multistrmap map; @@ -825,10 +826,14 @@ void MwIniImporter::importArchives(multistrmap &cfg, const multistrmap &ini) con } } -void MwIniImporter::importGameFiles(multistrmap &cfg, const multistrmap &ini) const { - std::vector contentFiles; +void MwIniImporter::importGameFiles(multistrmap &cfg, const multistrmap &ini, const boost::filesystem::path& iniFilename) const { + std::vector > contentFiles; std::string baseGameFile("Game Files:GameFile"); std::string gameFile(""); + std::time_t defaultTime = 0; + + // assume the Game Files are all in a "Data Files" directory under the directory holding Morrowind.ini + const boost::filesystem::path gameFilesDir(iniFilename.parent_path() /= "Data Files"); multistrmap::const_iterator it = ini.begin(); for(int i=0; it != ini.end(); i++) { @@ -845,18 +850,20 @@ void MwIniImporter::importGameFiles(multistrmap &cfg, const multistrmap &ini) co Misc::StringUtils::toLower(filetype); if(filetype.compare("esm") == 0 || filetype.compare("esp") == 0) { - contentFiles.push_back(*entry); + boost::filesystem::path filepath(gameFilesDir); + filepath /= *entry; + contentFiles.push_back(std::make_pair(lastWriteTime(filepath, defaultTime), *entry)); } } - - gameFile = ""; } cfg.erase("content"); cfg.insert( std::make_pair("content", std::vector() ) ); - for(std::vector::const_iterator it=contentFiles.begin(); it!=contentFiles.end(); ++it) { - cfg["content"].push_back(*it); + // this will sort files by time order first, then alphabetical (maybe), I suspect non ASCII filenames will be stuffed. + sort(contentFiles.begin(), contentFiles.end()); + for(std::vector >::const_iterator it=contentFiles.begin(); it!=contentFiles.end(); ++it) { + cfg["content"].push_back(it->second); } } @@ -873,3 +880,27 @@ void MwIniImporter::setInputEncoding(const ToUTF8::FromType &encoding) { mEncoding = encoding; } + +std::time_t MwIniImporter::lastWriteTime(const boost::filesystem::path& filename, std::time_t defaultTime) +{ + std::time_t writeTime(defaultTime); + if (boost::filesystem::exists(filename)) + { + // FixMe: remove #if when Boost dependency for Linux builds updated + // This allows Linux to build until then +#if (BOOST_VERSION >= 104800) + // need to resolve any symlinks so that we get time of file, not symlink + boost::filesystem::path resolved = boost::filesystem::canonical(filename); +#else + boost::filesystem::path resolved = filename; +#endif + writeTime = boost::filesystem::last_write_time(resolved); + std::cout << "content file: " << resolved << " timestamp = (" << writeTime << + ") " << asctime(localtime(&writeTime)) << std::endl; + } + else + { + std::cout << "content file: " << filename << " not found" << std::endl; + } + return writeTime; +} diff --git a/apps/mwiniimporter/importer.hpp b/apps/mwiniimporter/importer.hpp index 72b14ba75..c73cc65b5 100644 --- a/apps/mwiniimporter/importer.hpp +++ b/apps/mwiniimporter/importer.hpp @@ -6,6 +6,7 @@ #include #include #include +#include #include @@ -17,17 +18,22 @@ class MwIniImporter { MwIniImporter(); void setInputEncoding(const ToUTF8::FromType& encoding); void setVerbose(bool verbose); - multistrmap loadIniFile(const std::string& filename) const; - static multistrmap loadCfgFile(const std::string& filename); + multistrmap loadIniFile(const boost::filesystem::path& filename) const; + static multistrmap loadCfgFile(const boost::filesystem::path& filename); void merge(multistrmap &cfg, const multistrmap &ini) const; void mergeFallback(multistrmap &cfg, const multistrmap &ini) const; - void importGameFiles(multistrmap &cfg, const multistrmap &ini) const; + void importGameFiles(multistrmap &cfg, const multistrmap &ini, + const boost::filesystem::path& iniFilename) const; void importArchives(multistrmap &cfg, const multistrmap &ini) const; static void writeToFile(std::ostream &out, const multistrmap &cfg); private: static void insertMultistrmap(multistrmap &cfg, const std::string& key, const std::string& value); static std::string numberToString(int n); + + /// \return file's "last modified time", used in original MW to determine plug-in load order + static std::time_t lastWriteTime(const boost::filesystem::path& filename, std::time_t defaultTime); + bool mVerbose; strmap mMergeMap; std::vector mMergeFallback; diff --git a/apps/mwiniimporter/main.cpp b/apps/mwiniimporter/main.cpp index f108678f3..a3f115fcf 100644 --- a/apps/mwiniimporter/main.cpp +++ b/apps/mwiniimporter/main.cpp @@ -93,8 +93,8 @@ int wmain(int argc, wchar_t *wargv[]) { bpo::notify(vm); - std::string iniFile = vm["ini"].as(); - std::string cfgFile = vm["cfg"].as(); + boost::filesystem::path iniFile(vm["ini"].as()); + boost::filesystem::path cfgFile(vm["cfg"].as()); // if no output is given, write back to cfg file std::string outputFile(vm["output"].as()); @@ -110,7 +110,7 @@ int wmain(int argc, wchar_t *wargv[]) { std::cerr << "cfg file does not exist" << std::endl; MwIniImporter importer; - importer.setVerbose(vm.count("verbose")); + importer.setVerbose(vm.count("verbose") != 0); // Font encoding settings std::string encoding(vm["encoding"].as()); @@ -123,7 +123,7 @@ int wmain(int argc, wchar_t *wargv[]) { importer.mergeFallback(cfg, ini); if(vm.count("game-files")) { - importer.importGameFiles(cfg, ini); + importer.importGameFiles(cfg, ini, iniFile); } if(!vm.count("no-archives")) { diff --git a/apps/opencs/CMakeLists.txt b/apps/opencs/CMakeLists.txt index 4e360f6eb..103a56ecc 100644 --- a/apps/opencs/CMakeLists.txt +++ b/apps/opencs/CMakeLists.txt @@ -5,7 +5,7 @@ set (OPENCS_SRC main.cpp opencs_units (. editor) opencs_units (model/doc - document operation saving documentmanager loader runner + document operation saving documentmanager loader runner operationholder ) opencs_units_noqt (model/doc @@ -40,6 +40,7 @@ opencs_units (model/tools opencs_units_noqt (model/tools mandatoryid skillcheck classcheck factioncheck racecheck soundcheck regioncheck birthsigncheck spellcheck referencecheck referenceablecheck scriptcheck bodypartcheck + startscriptcheck ) @@ -164,7 +165,8 @@ qt4_wrap_ui(OPENCS_UI_HDR ${OPENCS_UI}) qt4_wrap_cpp(OPENCS_MOC_SRC ${OPENCS_HDR_QT}) qt4_add_resources(OPENCS_RES_SRC ${OPENCS_RES}) -include_directories(${CMAKE_CURRENT_BINARY_DIR} ${BULLET_INCLUDE_DIRS}) +# for compiled .ui files +include_directories(${CMAKE_CURRENT_BINARY_DIR}) if(APPLE) set (OPENCS_MAC_ICON ${CMAKE_SOURCE_DIR}/files/mac/openmw-cs.icns) @@ -174,7 +176,6 @@ endif(APPLE) add_executable(openmw-cs MACOSX_BUNDLE - ${OENGINE_BULLET} ${OPENCS_SRC} ${OPENCS_UI_HDR} ${OPENCS_MOC_SRC} @@ -198,6 +199,7 @@ if(APPLE) endif(APPLE) target_link_libraries(openmw-cs + ${OENGINE_LIBRARY} ${OGRE_LIBRARIES} ${OGRE_Overlay_LIBRARIES} ${OGRE_STATIC_PLUGINS} diff --git a/apps/opencs/model/doc/blacklist.cpp b/apps/opencs/model/doc/blacklist.cpp index 9b37a4302..083726412 100644 --- a/apps/opencs/model/doc/blacklist.cpp +++ b/apps/opencs/model/doc/blacklist.cpp @@ -28,4 +28,4 @@ void CSMDoc::Blacklist::add (CSMWorld::UniversalId::Type type, std::transform (ids.begin(), ids.end(), list.begin()+size, Misc::StringUtils::lowerCase); std::sort (list.begin(), list.end()); -} \ No newline at end of file +} diff --git a/apps/opencs/model/doc/document.cpp b/apps/opencs/model/doc/document.cpp index 7f3d98d0c..7f50f813e 100644 --- a/apps/opencs/model/doc/document.cpp +++ b/apps/opencs/model/doc/document.cpp @@ -2252,7 +2252,8 @@ CSMDoc::Document::Document (const VFS::Manager* vfs, const Files::ConfigurationM mTools (*this), mResDir(resDir), mProjectPath ((configuration.getUserDataPath() / "projects") / (savePath.filename().string() + ".project")), - mSaving (*this, mProjectPath, encoding), + mSavingOperation (*this, mProjectPath, encoding), + mSaving (&mSavingOperation), mRunner (mProjectPath) { if (mContentFiles.empty()) diff --git a/apps/opencs/model/doc/document.hpp b/apps/opencs/model/doc/document.hpp index 292b292df..d3e65257e 100644 --- a/apps/opencs/model/doc/document.hpp +++ b/apps/opencs/model/doc/document.hpp @@ -20,6 +20,7 @@ #include "saving.hpp" #include "blacklist.hpp" #include "runner.hpp" +#include "operationholder.hpp" class QAbstractItemModel; @@ -38,7 +39,7 @@ namespace ESM namespace Files { - class ConfigurationManager; + struct ConfigurationManager; } namespace CSMWorld @@ -61,7 +62,8 @@ namespace CSMDoc CSMWorld::Data mData; CSMTools::Tools mTools; boost::filesystem::path mProjectPath; - Saving mSaving; + Saving mSavingOperation; + OperationHolder mSaving; boost::filesystem::path mResDir; Blacklist mBlacklist; Runner mRunner; diff --git a/apps/opencs/model/doc/documentmanager.hpp b/apps/opencs/model/doc/documentmanager.hpp index 8dc4f338a..0c6e1541d 100644 --- a/apps/opencs/model/doc/documentmanager.hpp +++ b/apps/opencs/model/doc/documentmanager.hpp @@ -22,7 +22,7 @@ namespace VFS namespace Files { - class ConfigurationManager; + struct ConfigurationManager; } namespace CSMDoc @@ -56,7 +56,7 @@ namespace CSMDoc ///< \param new_ Do not load the last content file in \a files and instead create in an /// appropriate way. - void setResourceDir (const boost::filesystem::path& parResDir); + void setResourceDir (const boost::filesystem::path& parResDir); void setEncoding (ToUTF8::FromType encoding); @@ -66,7 +66,7 @@ namespace CSMDoc private: - boost::filesystem::path mResDir; + boost::filesystem::path mResDir; private slots: diff --git a/apps/opencs/model/doc/messages.cpp b/apps/opencs/model/doc/messages.cpp index 1fb423145..9b295fb28 100644 --- a/apps/opencs/model/doc/messages.cpp +++ b/apps/opencs/model/doc/messages.cpp @@ -25,4 +25,4 @@ CSMDoc::Messages::Iterator CSMDoc::Messages::begin() const CSMDoc::Messages::Iterator CSMDoc::Messages::end() const { return mMessages.end(); -} \ No newline at end of file +} diff --git a/apps/opencs/model/doc/operation.cpp b/apps/opencs/model/doc/operation.cpp index e728050f4..3f1674f50 100644 --- a/apps/opencs/model/doc/operation.cpp +++ b/apps/opencs/model/doc/operation.cpp @@ -29,9 +29,9 @@ void CSMDoc::Operation::prepareStages() CSMDoc::Operation::Operation (int type, bool ordered, bool finalAlways) : mType (type), mStages(std::vector >()), mCurrentStage(mStages.begin()), mCurrentStep(0), mCurrentStepTotal(0), mTotalSteps(0), mOrdered (ordered), - mFinalAlways (finalAlways), mError(false) + mFinalAlways (finalAlways), mError(false), mConnected (false) { - connect (this, SIGNAL (finished()), this, SLOT (operationDone())); + mTimer = new QTimer (this); } CSMDoc::Operation::~Operation() @@ -42,15 +42,17 @@ CSMDoc::Operation::~Operation() void CSMDoc::Operation::run() { + mTimer->stop(); + + if (!mConnected) + { + connect (mTimer, SIGNAL (timeout()), this, SLOT (executeStage())); + mConnected = true; + } + prepareStages(); - QTimer timer; - - timer.connect (&timer, SIGNAL (timeout()), this, SLOT (executeStage())); - - timer.start (0); - - exec(); + mTimer->start (0); } void CSMDoc::Operation::appendStage (Stage *stage) @@ -65,7 +67,7 @@ bool CSMDoc::Operation::hasError() const void CSMDoc::Operation::abort() { - if (!isRunning()) + if (!mTimer->isActive()) return; mError = true; @@ -116,10 +118,11 @@ void CSMDoc::Operation::executeStage() emit reportMessage (iter->mId, iter->mMessage, iter->mHint, mType); if (mCurrentStage==mStages.end()) - exit(); + operationDone(); } void CSMDoc::Operation::operationDone() { + mTimer->stop(); emit done (mType, mError); } diff --git a/apps/opencs/model/doc/operation.hpp b/apps/opencs/model/doc/operation.hpp index 3c9467754..a6217fe2d 100644 --- a/apps/opencs/model/doc/operation.hpp +++ b/apps/opencs/model/doc/operation.hpp @@ -3,7 +3,8 @@ #include -#include +#include +#include namespace CSMWorld { @@ -14,7 +15,7 @@ namespace CSMDoc { class Stage; - class Operation : public QThread + class Operation : public QObject { Q_OBJECT @@ -27,6 +28,8 @@ namespace CSMDoc int mOrdered; bool mFinalAlways; bool mError; + bool mConnected; + QTimer *mTimer; void prepareStages(); @@ -38,8 +41,6 @@ namespace CSMDoc virtual ~Operation(); - virtual void run(); - void appendStage (Stage *stage); ///< The ownership of \a stage is transferred to *this. /// @@ -60,6 +61,8 @@ namespace CSMDoc void abort(); + void run(); + private slots: void executeStage(); @@ -68,4 +71,4 @@ namespace CSMDoc }; } -#endif \ No newline at end of file +#endif diff --git a/apps/opencs/model/doc/operationholder.cpp b/apps/opencs/model/doc/operationholder.cpp new file mode 100644 index 000000000..d79e14023 --- /dev/null +++ b/apps/opencs/model/doc/operationholder.cpp @@ -0,0 +1,65 @@ + +#include "operationholder.hpp" + +#include "operation.hpp" + +CSMDoc::OperationHolder::OperationHolder (Operation *operation) : mRunning (false) +{ + if (operation) + setOperation (operation); +} + +void CSMDoc::OperationHolder::setOperation (Operation *operation) +{ + mOperation = operation; + mOperation->moveToThread (&mThread); + + connect ( + mOperation, SIGNAL (progress (int, int, int)), + this, SIGNAL (progress (int, int, int))); + + connect ( + mOperation, SIGNAL (reportMessage (const CSMWorld::UniversalId&, const std::string&, const std::string&, int)), + this, SIGNAL (reportMessage (const CSMWorld::UniversalId&, const std::string&, const std::string&, int))); + + connect ( + mOperation, SIGNAL (done (int, bool)), + this, SLOT (doneSlot (int, bool))); + + connect (this, SIGNAL (abortSignal()), mOperation, SLOT (abort())); + + connect (&mThread, SIGNAL (started()), mOperation, SLOT (run())); +} + +bool CSMDoc::OperationHolder::isRunning() const +{ + return mRunning; +} + +void CSMDoc::OperationHolder::start() +{ + mRunning = true; + mThread.start(); +} + +void CSMDoc::OperationHolder::abort() +{ + mRunning = false; + emit abortSignal(); +} + +void CSMDoc::OperationHolder::abortAndWait() +{ + if (mRunning) + { + mThread.quit(); + mThread.wait(); + } +} + +void CSMDoc::OperationHolder::doneSlot (int type, bool failed) +{ + mRunning = false; + mThread.quit(); + emit done (type, failed); +} diff --git a/apps/opencs/model/doc/operationholder.hpp b/apps/opencs/model/doc/operationholder.hpp new file mode 100644 index 000000000..6fe6df053 --- /dev/null +++ b/apps/opencs/model/doc/operationholder.hpp @@ -0,0 +1,56 @@ +#ifndef CSM_DOC_OPERATIONHOLDER_H +#define CSM_DOC_OPERATIONHOLDER_H + +#include +#include + +namespace CSMWorld +{ + class UniversalId; +} + +namespace CSMDoc +{ + class Operation; + + class OperationHolder : public QObject + { + Q_OBJECT + + QThread mThread; + Operation *mOperation; + bool mRunning; + + public: + + OperationHolder (Operation *operation = 0); + + void setOperation (Operation *operation); + + bool isRunning() const; + + void start(); + + void abort(); + + // Abort and wait until thread has finished. + void abortAndWait(); + + private slots: + + void doneSlot (int type, bool failed); + + signals: + + void progress (int current, int max, int type); + + void reportMessage (const CSMWorld::UniversalId& id, const std::string& message, + const std::string& hint, int type); + + void done (int type, bool failed); + + void abortSignal(); + }; +} + +#endif diff --git a/apps/opencs/model/doc/runner.cpp b/apps/opencs/model/doc/runner.cpp index d679c1890..14fe0cda8 100644 --- a/apps/opencs/model/doc/runner.cpp +++ b/apps/opencs/model/doc/runner.cpp @@ -6,7 +6,7 @@ #include #include -#include "operation.hpp" +#include "operationholder.hpp" CSMDoc::Runner::Runner (const boost::filesystem::path& projectPath) : mRunning (false), mStartup (0), mProjectPath (projectPath) @@ -145,7 +145,7 @@ void CSMDoc::Runner::readyReadStandardOutput() } -CSMDoc::SaveWatcher::SaveWatcher (Runner *runner, Operation *operation) +CSMDoc::SaveWatcher::SaveWatcher (Runner *runner, OperationHolder *operation) : QObject (runner), mRunner (runner) { connect (operation, SIGNAL (done (int, bool)), this, SLOT (saveDone (int, bool))); diff --git a/apps/opencs/model/doc/runner.hpp b/apps/opencs/model/doc/runner.hpp index 38b52a73b..517122492 100644 --- a/apps/opencs/model/doc/runner.hpp +++ b/apps/opencs/model/doc/runner.hpp @@ -16,6 +16,8 @@ class QTemporaryFile; namespace CSMDoc { + class OperationHolder; + class Runner : public QObject { Q_OBJECT @@ -74,7 +76,7 @@ namespace CSMDoc public: /// *this attaches itself to runner - SaveWatcher (Runner *runner, Operation *operation); + SaveWatcher (Runner *runner, OperationHolder *operation); private slots: diff --git a/apps/opencs/model/doc/saving.cpp b/apps/opencs/model/doc/saving.cpp index 70e9e1d87..9f6e469b8 100644 --- a/apps/opencs/model/doc/saving.cpp +++ b/apps/opencs/model/doc/saving.cpp @@ -78,6 +78,9 @@ CSMDoc::Saving::Saving (Document& document, const boost::filesystem::path& proje appendStage (new WriteCollectionStage > (mDocument.getData().getMagicEffects(), mState)); + appendStage (new WriteCollectionStage > + (mDocument.getData().getStartScripts(), mState)); + appendStage (new WriteDialogueCollectionStage (mDocument, mState, false)); appendStage (new WriteDialogueCollectionStage (mDocument, mState, true)); @@ -90,8 +93,12 @@ CSMDoc::Saving::Saving (Document& document, const boost::filesystem::path& proje appendStage (new WritePathgridCollectionStage (mDocument, mState)); + appendStage (new WriteLandCollectionStage (mDocument, mState)); + + appendStage (new WriteLandTextureCollectionStage (mDocument, mState)); + // close file and clean up appendStage (new CloseSaveStage (mState)); appendStage (new FinalSavingStage (mDocument, mState)); -} \ No newline at end of file +} diff --git a/apps/opencs/model/doc/savingstages.cpp b/apps/opencs/model/doc/savingstages.cpp index 08f8c9eaa..ef7d1d3af 100644 --- a/apps/opencs/model/doc/savingstages.cpp +++ b/apps/opencs/model/doc/savingstages.cpp @@ -90,7 +90,7 @@ void CSMDoc::WriteHeaderStage::perform (int stage, Messages& messages) CSMDoc::WriteDialogueCollectionStage::WriteDialogueCollectionStage (Document& document, SavingState& state, bool journal) -: mDocument (document), mState (state), +: mState (state), mTopics (journal ? document.getData().getJournals() : document.getData().getTopics()), mInfos (journal ? document.getData().getJournalInfos() : document.getData().getTopicInfos()) {} @@ -353,6 +353,74 @@ void CSMDoc::WritePathgridCollectionStage::perform (int stage, Messages& message } +CSMDoc::WriteLandCollectionStage::WriteLandCollectionStage (Document& document, + SavingState& state) +: mDocument (document), mState (state) +{} + +int CSMDoc::WriteLandCollectionStage::setup() +{ + return mDocument.getData().getLand().getSize(); +} + +void CSMDoc::WriteLandCollectionStage::perform (int stage, Messages& messages) +{ + const CSMWorld::Record& land = + mDocument.getData().getLand().getRecord (stage); + + if (land.mState==CSMWorld::RecordBase::State_Modified || + land.mState==CSMWorld::RecordBase::State_ModifiedOnly) + { + CSMWorld::Land record = land.get(); + + mState.getWriter().startRecord (record.mLand->sRecordId); + + record.mLand->save (mState.getWriter()); + if(record.mLand->mLandData) + record.mLand->mLandData->save (mState.getWriter()); + + mState.getWriter().endRecord (record.mLand->sRecordId); + } + else if (land.mState==CSMWorld::RecordBase::State_Deleted) + { + /// \todo write record with delete flag + } +} + + +CSMDoc::WriteLandTextureCollectionStage::WriteLandTextureCollectionStage (Document& document, + SavingState& state) +: mDocument (document), mState (state) +{} + +int CSMDoc::WriteLandTextureCollectionStage::setup() +{ + return mDocument.getData().getLandTextures().getSize(); +} + +void CSMDoc::WriteLandTextureCollectionStage::perform (int stage, Messages& messages) +{ + const CSMWorld::Record& landTexture = + mDocument.getData().getLandTextures().getRecord (stage); + + if (landTexture.mState==CSMWorld::RecordBase::State_Modified || + landTexture.mState==CSMWorld::RecordBase::State_ModifiedOnly) + { + CSMWorld::LandTexture record = landTexture.get(); + + mState.getWriter().startRecord (record.sRecordId); + + record.save (mState.getWriter()); + + mState.getWriter().endRecord (record.sRecordId); + } + else if (landTexture.mState==CSMWorld::RecordBase::State_Deleted) + { + /// \todo write record with delete flag + } +} + + CSMDoc::CloseSaveStage::CloseSaveStage (SavingState& state) : mState (state) {} diff --git a/apps/opencs/model/doc/savingstages.hpp b/apps/opencs/model/doc/savingstages.hpp index 87c9ba7eb..188f22f96 100644 --- a/apps/opencs/model/doc/savingstages.hpp +++ b/apps/opencs/model/doc/savingstages.hpp @@ -7,6 +7,8 @@ #include "../world/idcollection.hpp" #include "../world/scope.hpp" +#include + #include "savingstate.hpp" namespace ESM @@ -103,8 +105,15 @@ namespace CSMDoc if (state==CSMWorld::RecordBase::State_Modified || state==CSMWorld::RecordBase::State_ModifiedOnly) { - mState.getWriter().startRecord (mCollection.getRecord (stage).mModified.sRecordId); - mState.getWriter().writeHNCString ("NAME", mCollection.getId (stage)); + // FIXME: A quick Workaround to support records which should not write + // NAME, including SKIL, MGEF and SCPT. If there are many more + // idcollection records that doesn't use NAME then a more generic + // solution may be required. + uint32_t name = mCollection.getRecord (stage).mModified.sRecordId; + mState.getWriter().startRecord (name); + + if(name != ESM::REC_SKIL && name != ESM::REC_MGEF && name != ESM::REC_SCPT) + mState.getWriter().writeHNCString ("NAME", mCollection.getId (stage)); mCollection.getRecord (stage).mModified.save (mState.getWriter()); mState.getWriter().endRecord (mCollection.getRecord (stage).mModified.sRecordId); } @@ -117,7 +126,6 @@ namespace CSMDoc class WriteDialogueCollectionStage : public Stage { - Document& mDocument; SavingState& mState; const CSMWorld::IdCollection& mTopics; CSMWorld::InfoCollection& mInfos; @@ -200,6 +208,40 @@ namespace CSMDoc ///< Messages resulting from this stage will be appended to \a messages. }; + + class WriteLandCollectionStage : public Stage + { + Document& mDocument; + SavingState& mState; + + public: + + WriteLandCollectionStage (Document& document, SavingState& state); + + virtual int setup(); + ///< \return number of steps + + virtual void perform (int stage, Messages& messages); + ///< Messages resulting from this stage will be appended to \a messages. + }; + + + class WriteLandTextureCollectionStage : public Stage + { + Document& mDocument; + SavingState& mState; + + public: + + WriteLandTextureCollectionStage (Document& document, SavingState& state); + + virtual int setup(); + ///< \return number of steps + + virtual void perform (int stage, Messages& messages); + ///< Messages resulting from this stage will be appended to \a messages. + }; + class CloseSaveStage : public Stage { SavingState& mState; diff --git a/apps/opencs/model/doc/stage.cpp b/apps/opencs/model/doc/stage.cpp index 99b765770..1a2c5c721 100644 --- a/apps/opencs/model/doc/stage.cpp +++ b/apps/opencs/model/doc/stage.cpp @@ -1,4 +1,4 @@ #include "stage.hpp" -CSMDoc::Stage::~Stage() {} \ No newline at end of file +CSMDoc::Stage::~Stage() {} diff --git a/apps/opencs/model/filter/booleannode.cpp b/apps/opencs/model/filter/booleannode.cpp index 2daa1b6d8..35fc98e08 100644 --- a/apps/opencs/model/filter/booleannode.cpp +++ b/apps/opencs/model/filter/booleannode.cpp @@ -12,4 +12,4 @@ bool CSMFilter::BooleanNode::test (const CSMWorld::IdTableBase& table, int row, std::string CSMFilter::BooleanNode::toString (bool numericColumns) const { return mTrue ? "true" : "false"; -} \ No newline at end of file +} diff --git a/apps/opencs/model/filter/booleannode.hpp b/apps/opencs/model/filter/booleannode.hpp index d9635746c..32206b575 100644 --- a/apps/opencs/model/filter/booleannode.hpp +++ b/apps/opencs/model/filter/booleannode.hpp @@ -26,4 +26,4 @@ namespace CSMFilter }; } -#endif \ No newline at end of file +#endif diff --git a/apps/opencs/model/filter/node.cpp b/apps/opencs/model/filter/node.cpp index 276861cdc..091dc4698 100644 --- a/apps/opencs/model/filter/node.cpp +++ b/apps/opencs/model/filter/node.cpp @@ -3,4 +3,4 @@ CSMFilter::Node::Node() {} -CSMFilter::Node::~Node() {} \ No newline at end of file +CSMFilter::Node::~Node() {} diff --git a/apps/opencs/model/filter/notnode.cpp b/apps/opencs/model/filter/notnode.cpp index 231773075..b5d9da7b7 100644 --- a/apps/opencs/model/filter/notnode.cpp +++ b/apps/opencs/model/filter/notnode.cpp @@ -7,4 +7,4 @@ bool CSMFilter::NotNode::test (const CSMWorld::IdTableBase& table, int row, const std::map& columns) const { return !getChild().test (table, row, columns); -} \ No newline at end of file +} diff --git a/apps/opencs/model/filter/textnode.cpp b/apps/opencs/model/filter/textnode.cpp index 24cdce4f5..73c378f11 100644 --- a/apps/opencs/model/filter/textnode.cpp +++ b/apps/opencs/model/filter/textnode.cpp @@ -82,4 +82,4 @@ std::string CSMFilter::TextNode::toString (bool numericColumns) const stream << ", \"" << mText << "\")"; return stream.str(); -} \ No newline at end of file +} diff --git a/apps/opencs/model/filter/unarynode.cpp b/apps/opencs/model/filter/unarynode.cpp index 43a24b76a..c40d191b6 100644 --- a/apps/opencs/model/filter/unarynode.cpp +++ b/apps/opencs/model/filter/unarynode.cpp @@ -23,4 +23,4 @@ std::vector CSMFilter::UnaryNode::getReferencedColumns() const std::string CSMFilter::UnaryNode::toString (bool numericColumns) const { return mName + " " + mChild->toString (numericColumns); -} \ No newline at end of file +} diff --git a/apps/opencs/model/filter/valuenode.cpp b/apps/opencs/model/filter/valuenode.cpp index 26b982441..72cf5896b 100644 --- a/apps/opencs/model/filter/valuenode.cpp +++ b/apps/opencs/model/filter/valuenode.cpp @@ -94,4 +94,4 @@ std::string CSMFilter::ValueNode::toString (bool numericColumns) const stream << ")"; return stream.str(); -} \ No newline at end of file +} diff --git a/apps/opencs/model/tools/birthsigncheck.cpp b/apps/opencs/model/tools/birthsigncheck.cpp index 1d72e24b8..4e6da4631 100644 --- a/apps/opencs/model/tools/birthsigncheck.cpp +++ b/apps/opencs/model/tools/birthsigncheck.cpp @@ -41,4 +41,4 @@ void CSMTools::BirthsignCheckStage::perform (int stage, CSMDoc::Messages& messag /// \todo test if the texture exists /// \todo check data members that can't be edited in the table view -} \ No newline at end of file +} diff --git a/apps/opencs/model/tools/bodypartcheck.hpp b/apps/opencs/model/tools/bodypartcheck.hpp index 0a6ca959a..dbab5f5c6 100644 --- a/apps/opencs/model/tools/bodypartcheck.hpp +++ b/apps/opencs/model/tools/bodypartcheck.hpp @@ -32,4 +32,4 @@ namespace CSMTools }; } -#endif \ No newline at end of file +#endif diff --git a/apps/opencs/model/tools/classcheck.cpp b/apps/opencs/model/tools/classcheck.cpp index 5b872a266..be57a3729 100644 --- a/apps/opencs/model/tools/classcheck.cpp +++ b/apps/opencs/model/tools/classcheck.cpp @@ -65,4 +65,4 @@ void CSMTools::ClassCheckStage::perform (int stage, CSMDoc::Messages& messages) messages.push_back (std::make_pair (id, ESM::Skill::indexToId (iter->first) + " is listed more than once")); } -} \ No newline at end of file +} diff --git a/apps/opencs/model/tools/mandatoryid.cpp b/apps/opencs/model/tools/mandatoryid.cpp index 87d19401b..4c97d2266 100644 --- a/apps/opencs/model/tools/mandatoryid.cpp +++ b/apps/opencs/model/tools/mandatoryid.cpp @@ -20,4 +20,4 @@ void CSMTools::MandatoryIdStage::perform (int stage, CSMDoc::Messages& messages) if (mIdCollection.searchId (mIds.at (stage))==-1 || mIdCollection.getRecord (mIds.at (stage)).isDeleted()) messages.add (mCollectionId, "Missing mandatory record: " + mIds.at (stage)); -} \ No newline at end of file +} diff --git a/apps/opencs/model/tools/racecheck.cpp b/apps/opencs/model/tools/racecheck.cpp index 143d61772..3b2c8d290 100644 --- a/apps/opencs/model/tools/racecheck.cpp +++ b/apps/opencs/model/tools/racecheck.cpp @@ -70,4 +70,4 @@ void CSMTools::RaceCheckStage::perform (int stage, CSMDoc::Messages& messages) performFinal (messages); else performPerRecord (stage, messages); -} \ No newline at end of file +} diff --git a/apps/opencs/model/tools/referencecheck.cpp b/apps/opencs/model/tools/referencecheck.cpp index 0c1d7d38f..198c3627f 100644 --- a/apps/opencs/model/tools/referencecheck.cpp +++ b/apps/opencs/model/tools/referencecheck.cpp @@ -48,10 +48,6 @@ void CSMTools::ReferenceCheckStage::perform(int stage, CSMDoc::Messages &message } } - // Check if referenced object is in valid cell - if (mCells.searchId(cellRef.mCell) == -1) - messages.push_back(std::make_pair(id, " is referencing object from non existing cell " + cellRef.mCell)); - // If object have owner, check if that owner reference is valid if (!cellRef.mOwner.empty() && mReferencables.searchId(cellRef.mOwner) == -1) messages.push_back(std::make_pair(id, " has non existing owner " + cellRef.mOwner)); @@ -70,9 +66,9 @@ void CSMTools::ReferenceCheckStage::perform(int stage, CSMDoc::Messages &message // Check item's faction rank if (hasFaction && cellRef.mFactionRank < -1) - messages.push_back(std::make_pair(id, " has faction set but has invalid faction rank " + cellRef.mFactionRank)); + messages.push_back(std::make_pair(id, " has faction set but has invalid faction rank " + boost::lexical_cast(cellRef.mFactionRank))); else if (!hasFaction && cellRef.mFactionRank != -2) - messages.push_back(std::make_pair(id, " has invalid faction rank " + cellRef.mFactionRank)); + messages.push_back(std::make_pair(id, " has invalid faction rank " + boost::lexical_cast(cellRef.mFactionRank))); // If door have destination cell, check if that reference is valid if (!cellRef.mDestCell.empty()) diff --git a/apps/opencs/model/tools/referencecheck.hpp b/apps/opencs/model/tools/referencecheck.hpp index 9cf685b3a..70ef02916 100644 --- a/apps/opencs/model/tools/referencecheck.hpp +++ b/apps/opencs/model/tools/referencecheck.hpp @@ -26,4 +26,4 @@ namespace CSMTools }; } -#endif // CSM_TOOLS_REFERENCECHECK_H \ No newline at end of file +#endif // CSM_TOOLS_REFERENCECHECK_H diff --git a/apps/opencs/model/tools/regioncheck.cpp b/apps/opencs/model/tools/regioncheck.cpp index 091836d0d..42abc35c9 100644 --- a/apps/opencs/model/tools/regioncheck.cpp +++ b/apps/opencs/model/tools/regioncheck.cpp @@ -35,4 +35,4 @@ void CSMTools::RegionCheckStage::perform (int stage, CSMDoc::Messages& messages) /// \todo test that the ID in mSleeplist exists /// \todo check data members that can't be edited in the table view -} \ No newline at end of file +} diff --git a/apps/opencs/model/tools/reportmodel.cpp b/apps/opencs/model/tools/reportmodel.cpp index 135420612..ac9dabb25 100644 --- a/apps/opencs/model/tools/reportmodel.cpp +++ b/apps/opencs/model/tools/reportmodel.cpp @@ -78,4 +78,4 @@ const CSMWorld::UniversalId& CSMTools::ReportModel::getUniversalId (int row) con std::string CSMTools::ReportModel::getHint (int row) const { return mRows.at (row).second.second; -} \ No newline at end of file +} diff --git a/apps/opencs/model/tools/scriptcheck.cpp b/apps/opencs/model/tools/scriptcheck.cpp index d9dea7f43..a70ee2ae4 100644 --- a/apps/opencs/model/tools/scriptcheck.cpp +++ b/apps/opencs/model/tools/scriptcheck.cpp @@ -98,4 +98,4 @@ void CSMTools::ScriptCheckStage::perform (int stage, CSMDoc::Messages& messages) } mMessages = 0; -} \ No newline at end of file +} diff --git a/apps/opencs/model/tools/skillcheck.cpp b/apps/opencs/model/tools/skillcheck.cpp index e061e042c..2b55526e0 100644 --- a/apps/opencs/model/tools/skillcheck.cpp +++ b/apps/opencs/model/tools/skillcheck.cpp @@ -39,4 +39,4 @@ void CSMTools::SkillCheckStage::perform (int stage, CSMDoc::Messages& messages) if (skill.mDescription.empty()) messages.push_back (std::make_pair (id, skill.mId + " has an empty description")); -} \ No newline at end of file +} diff --git a/apps/opencs/model/tools/soundcheck.cpp b/apps/opencs/model/tools/soundcheck.cpp index e122ced91..f78932a32 100644 --- a/apps/opencs/model/tools/soundcheck.cpp +++ b/apps/opencs/model/tools/soundcheck.cpp @@ -31,4 +31,4 @@ void CSMTools::SoundCheckStage::perform (int stage, CSMDoc::Messages& messages) messages.push_back (std::make_pair (id, "Maximum range larger than minimum range")); /// \todo check, if the sound file exists -} \ No newline at end of file +} diff --git a/apps/opencs/model/tools/spellcheck.cpp b/apps/opencs/model/tools/spellcheck.cpp index 0b59dc862..bd076d2a5 100644 --- a/apps/opencs/model/tools/spellcheck.cpp +++ b/apps/opencs/model/tools/spellcheck.cpp @@ -37,4 +37,4 @@ void CSMTools::SpellCheckStage::perform (int stage, CSMDoc::Messages& messages) messages.push_back (std::make_pair (id, spell.mId + " has a negative spell costs")); /// \todo check data members that can't be edited in the table view -} \ No newline at end of file +} diff --git a/apps/opencs/model/tools/startscriptcheck.cpp b/apps/opencs/model/tools/startscriptcheck.cpp new file mode 100644 index 000000000..e3c01368b --- /dev/null +++ b/apps/opencs/model/tools/startscriptcheck.cpp @@ -0,0 +1,31 @@ + +#include "startscriptcheck.hpp" + +#include + +CSMTools::StartScriptCheckStage::StartScriptCheckStage ( + const CSMWorld::IdCollection& startScripts, + const CSMWorld::IdCollection& scripts) +: mStartScripts (startScripts), mScripts (scripts) +{} + +void CSMTools::StartScriptCheckStage::perform(int stage, CSMDoc::Messages& messages) +{ + const CSMWorld::Record& record = mStartScripts.getRecord (stage); + + if (record.isDeleted()) + return; + + std::string scriptId = record.get().mId; + + CSMWorld::UniversalId id (CSMWorld::UniversalId::Type_StartScript, scriptId); + + if (mScripts.searchId (Misc::StringUtils::lowerCase (scriptId))==-1) + messages.push_back ( + std::make_pair (id, "Start script " + scriptId + " does not exist")); +} + +int CSMTools::StartScriptCheckStage::setup() +{ + return mStartScripts.getSize(); +} diff --git a/apps/opencs/model/tools/startscriptcheck.hpp b/apps/opencs/model/tools/startscriptcheck.hpp new file mode 100644 index 000000000..cb82cbae7 --- /dev/null +++ b/apps/opencs/model/tools/startscriptcheck.hpp @@ -0,0 +1,28 @@ +#ifndef CSM_TOOLS_STARTSCRIPTCHECK_H +#define CSM_TOOLS_STARTSCRIPTCHECK_H + +#include +#include + +#include "../doc/stage.hpp" + +#include "../world/idcollection.hpp" + +namespace CSMTools +{ + class StartScriptCheckStage : public CSMDoc::Stage + { + const CSMWorld::IdCollection& mStartScripts; + const CSMWorld::IdCollection& mScripts; + + public: + + StartScriptCheckStage (const CSMWorld::IdCollection& startScripts, + const CSMWorld::IdCollection& scripts); + + virtual void perform(int stage, CSMDoc::Messages& messages); + virtual int setup(); + }; +} + +#endif diff --git a/apps/opencs/model/tools/tools.cpp b/apps/opencs/model/tools/tools.cpp index 0c20bd17b..170ea8ccd 100644 --- a/apps/opencs/model/tools/tools.cpp +++ b/apps/opencs/model/tools/tools.cpp @@ -24,31 +24,32 @@ #include "scriptcheck.hpp" #include "bodypartcheck.hpp" #include "referencecheck.hpp" +#include "startscriptcheck.hpp" -CSMDoc::Operation *CSMTools::Tools::get (int type) +CSMDoc::OperationHolder *CSMTools::Tools::get (int type) { switch (type) { - case CSMDoc::State_Verifying: return mVerifier; + case CSMDoc::State_Verifying: return &mVerifier; } return 0; } -const CSMDoc::Operation *CSMTools::Tools::get (int type) const +const CSMDoc::OperationHolder *CSMTools::Tools::get (int type) const { return const_cast (this)->get (type); } -CSMDoc::Operation *CSMTools::Tools::getVerifier() +CSMDoc::OperationHolder *CSMTools::Tools::getVerifier() { - if (!mVerifier) + if (!mVerifierOperation) { - mVerifier = new CSMDoc::Operation (CSMDoc::State_Verifying, false); + mVerifierOperation = new CSMDoc::Operation (CSMDoc::State_Verifying, false); - connect (mVerifier, SIGNAL (progress (int, int, int)), this, SIGNAL (progress (int, int, int))); - connect (mVerifier, SIGNAL (done (int, bool)), this, SIGNAL (done (int, bool))); - connect (mVerifier, + connect (&mVerifier, SIGNAL (progress (int, int, int)), this, SIGNAL (progress (int, int, int))); + connect (&mVerifier, SIGNAL (done (int, bool)), this, SIGNAL (done (int, bool))); + connect (&mVerifier, SIGNAL (reportMessage (const CSMWorld::UniversalId&, const std::string&, const std::string&, int)), this, SLOT (verifierMessage (const CSMWorld::UniversalId&, const std::string&, const std::string&, int))); @@ -58,48 +59,49 @@ CSMDoc::Operation *CSMTools::Tools::getVerifier() mandatoryIds.push_back ("GameHour"); mandatoryIds.push_back ("Month"); mandatoryIds.push_back ("PCRace"); - mandatoryIds.push_back ("PCVampire"); - mandatoryIds.push_back ("PCWerewolf"); - mandatoryIds.push_back ("PCYear"); - mVerifier->appendStage (new MandatoryIdStage (mData.getGlobals(), + mVerifierOperation->appendStage (new MandatoryIdStage (mData.getGlobals(), CSMWorld::UniversalId (CSMWorld::UniversalId::Type_Globals), mandatoryIds)); - mVerifier->appendStage (new SkillCheckStage (mData.getSkills())); + mVerifierOperation->appendStage (new SkillCheckStage (mData.getSkills())); - mVerifier->appendStage (new ClassCheckStage (mData.getClasses())); + mVerifierOperation->appendStage (new ClassCheckStage (mData.getClasses())); - mVerifier->appendStage (new FactionCheckStage (mData.getFactions())); + mVerifierOperation->appendStage (new FactionCheckStage (mData.getFactions())); - mVerifier->appendStage (new RaceCheckStage (mData.getRaces())); + mVerifierOperation->appendStage (new RaceCheckStage (mData.getRaces())); - mVerifier->appendStage (new SoundCheckStage (mData.getSounds())); + mVerifierOperation->appendStage (new SoundCheckStage (mData.getSounds())); - mVerifier->appendStage (new RegionCheckStage (mData.getRegions())); + mVerifierOperation->appendStage (new RegionCheckStage (mData.getRegions())); - mVerifier->appendStage (new BirthsignCheckStage (mData.getBirthsigns())); + mVerifierOperation->appendStage (new BirthsignCheckStage (mData.getBirthsigns())); - mVerifier->appendStage (new SpellCheckStage (mData.getSpells())); + mVerifierOperation->appendStage (new SpellCheckStage (mData.getSpells())); - mVerifier->appendStage (new ReferenceableCheckStage (mData.getReferenceables().getDataSet(), mData.getRaces(), mData.getClasses(), mData.getFactions())); + mVerifierOperation->appendStage (new ReferenceableCheckStage (mData.getReferenceables().getDataSet(), mData.getRaces(), mData.getClasses(), mData.getFactions())); - mVerifier->appendStage (new ReferenceCheckStage(mData.getReferences(), mData.getReferenceables(), mData.getCells(), mData.getFactions())); + mVerifierOperation->appendStage (new ReferenceCheckStage(mData.getReferences(), mData.getReferenceables(), mData.getCells(), mData.getFactions())); - mVerifier->appendStage (new ScriptCheckStage (mDocument)); + mVerifierOperation->appendStage (new ScriptCheckStage (mDocument)); - mVerifier->appendStage( + mVerifierOperation->appendStage (new StartScriptCheckStage (mData.getStartScripts(), mData.getScripts())); + + mVerifierOperation->appendStage( new BodyPartCheckStage( mData.getBodyParts(), mData.getResources( CSMWorld::UniversalId( CSMWorld::UniversalId::Type_Meshes )), mData.getRaces() )); + + mVerifier.setOperation (mVerifierOperation); } - return mVerifier; + return &mVerifier; } CSMTools::Tools::Tools (CSMDoc::Document& document) -: mDocument (document), mData (document.getData()), mVerifier (0), mNextReportNumber (0) +: mDocument (document), mData (document.getData()), mVerifierOperation (0), mNextReportNumber (0) { // index 0: load error log mReports.insert (std::make_pair (mNextReportNumber++, new ReportModel)); @@ -108,7 +110,11 @@ CSMTools::Tools::Tools (CSMDoc::Document& document) CSMTools::Tools::~Tools() { - delete mVerifier; + if (mVerifierOperation) + { + mVerifier.abortAndWait(); + delete mVerifierOperation; + } for (std::map::iterator iter (mReports.begin()); iter!=mReports.end(); ++iter) delete iter->second; @@ -126,7 +132,7 @@ CSMWorld::UniversalId CSMTools::Tools::runVerifier() void CSMTools::Tools::abortOperation (int type) { - if (CSMDoc::Operation *operation = get (type)) + if (CSMDoc::OperationHolder *operation = get (type)) operation->abort(); } @@ -141,7 +147,7 @@ int CSMTools::Tools::getRunningOperations() const int result = 0; for (int i=0; sOperations[i]!=-1; ++i) - if (const CSMDoc::Operation *operation = get (sOperations[i])) + if (const CSMDoc::OperationHolder *operation = get (sOperations[i])) if (operation->isRunning()) result |= sOperations[i]; diff --git a/apps/opencs/model/tools/tools.hpp b/apps/opencs/model/tools/tools.hpp index 5125a3638..b8ded8a83 100644 --- a/apps/opencs/model/tools/tools.hpp +++ b/apps/opencs/model/tools/tools.hpp @@ -5,6 +5,8 @@ #include +#include "../doc/operationholder.hpp" + namespace CSMWorld { class Data; @@ -27,7 +29,8 @@ namespace CSMTools CSMDoc::Document& mDocument; CSMWorld::Data& mData; - CSMDoc::Operation *mVerifier; + CSMDoc::Operation *mVerifierOperation; + CSMDoc::OperationHolder mVerifier; std::map mReports; int mNextReportNumber; std::map mActiveReports; // type, report number @@ -36,12 +39,12 @@ namespace CSMTools Tools (const Tools&); Tools& operator= (const Tools&); - CSMDoc::Operation *getVerifier(); + CSMDoc::OperationHolder *getVerifier(); - CSMDoc::Operation *get (int type); + CSMDoc::OperationHolder *get (int type); ///< Returns a 0-pointer, if operation hasn't been used yet. - const CSMDoc::Operation *get (int type) const; + const CSMDoc::OperationHolder *get (int type) const; ///< Returns a 0-pointer, if operation hasn't been used yet. public: diff --git a/apps/opencs/model/world/cell.hpp b/apps/opencs/model/world/cell.hpp index a47dbf45d..f393e2cf9 100644 --- a/apps/opencs/model/world/cell.hpp +++ b/apps/opencs/model/world/cell.hpp @@ -21,4 +21,4 @@ namespace CSMWorld }; } -#endif \ No newline at end of file +#endif diff --git a/apps/opencs/model/world/collectionbase.cpp b/apps/opencs/model/world/collectionbase.cpp index 241f198cb..b8eed4192 100644 --- a/apps/opencs/model/world/collectionbase.cpp +++ b/apps/opencs/model/world/collectionbase.cpp @@ -28,4 +28,4 @@ int CSMWorld::CollectionBase::findColumnIndex (Columns::ColumnId id) const throw std::logic_error ("invalid column index"); return index; -} \ No newline at end of file +} diff --git a/apps/opencs/model/world/collectionbase.hpp b/apps/opencs/model/world/collectionbase.hpp index 442055d5f..ef826e31c 100644 --- a/apps/opencs/model/world/collectionbase.hpp +++ b/apps/opencs/model/world/collectionbase.hpp @@ -106,4 +106,4 @@ namespace CSMWorld }; } -#endif \ No newline at end of file +#endif diff --git a/apps/opencs/model/world/columnbase.cpp b/apps/opencs/model/world/columnbase.cpp index f6363fe2e..665ab9354 100644 --- a/apps/opencs/model/world/columnbase.cpp +++ b/apps/opencs/model/world/columnbase.cpp @@ -22,4 +22,4 @@ std::string CSMWorld::ColumnBase::getTitle() const int CSMWorld::ColumnBase::getId() const { return mColumnId; -} \ No newline at end of file +} diff --git a/apps/opencs/model/world/commanddispatcher.cpp b/apps/opencs/model/world/commanddispatcher.cpp index 4e146d87c..ca6faafbc 100644 --- a/apps/opencs/model/world/commanddispatcher.cpp +++ b/apps/opencs/model/world/commanddispatcher.cpp @@ -264,4 +264,4 @@ void CSMWorld::CommandDispatcher::executeExtendedRevert() if (mExtendedTypes.size()>1) mDocument.getUndoStack().endMacro(); -} \ No newline at end of file +} diff --git a/apps/opencs/model/world/commands.cpp b/apps/opencs/model/world/commands.cpp index de0e9a4e5..1d86ba080 100644 --- a/apps/opencs/model/world/commands.cpp +++ b/apps/opencs/model/world/commands.cpp @@ -170,4 +170,4 @@ void CSMWorld::CloneCommand::redo() void CSMWorld::CloneCommand::undo() { mModel.removeRow (mModel.getModelIndex (mId, 0).row()); -} \ No newline at end of file +} diff --git a/apps/opencs/model/world/commands.hpp b/apps/opencs/model/world/commands.hpp index a15c071a8..3c24b64a5 100644 --- a/apps/opencs/model/world/commands.hpp +++ b/apps/opencs/model/world/commands.hpp @@ -20,7 +20,7 @@ namespace CSMWorld { class IdTable; class IdTable; - class RecordBase; + struct RecordBase; class ModifyCommand : public QUndoCommand { @@ -141,4 +141,4 @@ namespace CSMWorld }; } -#endif \ No newline at end of file +#endif diff --git a/apps/opencs/model/world/data.cpp b/apps/opencs/model/world/data.cpp index 77724c997..dcbea56df 100644 --- a/apps/opencs/model/world/data.cpp +++ b/apps/opencs/model/world/data.cpp @@ -254,6 +254,10 @@ CSMWorld::Data::Data (ToUTF8::FromType encoding, const ResourcesManager& resourc mPathgrids.addColumn (new RecordStateColumn); mPathgrids.addColumn (new FixedRecordTypeColumn (UniversalId::Type_Pathgrid)); + mStartScripts.addColumn (new StringIdColumn); + mStartScripts.addColumn (new RecordStateColumn); + mStartScripts.addColumn (new FixedRecordTypeColumn (UniversalId::Type_StartScript)); + mRefs.addColumn (new StringIdColumn (true)); mRefs.addColumn (new RecordStateColumn); mRefs.addColumn (new FixedRecordTypeColumn (UniversalId::Type_Reference)); @@ -327,6 +331,7 @@ CSMWorld::Data::Data (ToUTF8::FromType encoding, const ResourcesManager& resourc addModel (new IdTable (&mSoundGens), UniversalId::Type_SoundGen); addModel (new IdTable (&mMagicEffects), UniversalId::Type_MagicEffect); addModel (new IdTable (&mPathgrids), UniversalId::Type_Pathgrid); + addModel (new IdTable (&mStartScripts), UniversalId::Type_StartScript); addModel (new IdTable (&mReferenceables, IdTable::Feature_Preview), UniversalId::Type_Referenceable); addModel (new IdTable (&mRefs, IdTable::Feature_ViewCell | IdTable::Feature_Preview), UniversalId::Type_Reference); @@ -620,6 +625,16 @@ CSMWorld::SubCellCollection& CSMWorld::Data::getPathgrids() return mPathgrids; } +const CSMWorld::IdCollection& CSMWorld::Data::getStartScripts() const +{ + return mStartScripts; +} + +CSMWorld::IdCollection& CSMWorld::Data::getStartScripts() +{ + return mStartScripts; +} + const CSMWorld::Resources& CSMWorld::Data::getResources (const UniversalId& id) const { return mResourcesManager.get (id.getType()); @@ -724,6 +739,7 @@ bool CSMWorld::Data::continueLoading (CSMDoc::Messages& messages) case ESM::REC_SNDG: mSoundGens.load (*mReader, mBase); break; case ESM::REC_MGEF: mMagicEffects.load (*mReader, mBase); break; case ESM::REC_PGRD: mPathgrids.load (*mReader, mBase); break; + case ESM::REC_SSCR: mStartScripts.load (*mReader, mBase); break; case ESM::REC_LTEX: mLandTextures.load (*mReader, mBase); break; @@ -734,7 +750,7 @@ bool CSMWorld::Data::continueLoading (CSMDoc::Messages& messages) if (index!=-1 && !mBase) mLand.getRecord (index).mModified.mLand->loadData ( ESM::Land::DATA_VHGT | ESM::Land::DATA_VNML | ESM::Land::DATA_VCLR | - ESM::Land::DATA_VTEX); + ESM::Land::DATA_VTEX | ESM::Land::DATA_WNAM); break; } diff --git a/apps/opencs/model/world/data.hpp b/apps/opencs/model/world/data.hpp index ce8776104..5bb117aa0 100644 --- a/apps/opencs/model/world/data.hpp +++ b/apps/opencs/model/world/data.hpp @@ -25,6 +25,7 @@ #include #include #include +#include #include #include @@ -87,6 +88,7 @@ namespace CSMWorld SubCellCollection mPathgrids; IdCollection mDebugProfiles; IdCollection mSoundGens; + IdCollection mStartScripts; InfoCollection mTopicInfos; InfoCollection mJournalInfos; IdCollection mCells; @@ -238,6 +240,10 @@ namespace CSMWorld SubCellCollection& getPathgrids(); + const IdCollection& getStartScripts() const; + + IdCollection& getStartScripts(); + /// Throws an exception, if \a id does not match a resources list. const Resources& getResources (const UniversalId& id) const; diff --git a/apps/opencs/model/world/idtable.hpp b/apps/opencs/model/world/idtable.hpp index 707d7133b..ea8ab80f9 100644 --- a/apps/opencs/model/world/idtable.hpp +++ b/apps/opencs/model/world/idtable.hpp @@ -10,7 +10,7 @@ namespace CSMWorld { class CollectionBase; - class RecordBase; + struct RecordBase; class IdTable : public IdTableBase { diff --git a/apps/opencs/model/world/idtablebase.cpp b/apps/opencs/model/world/idtablebase.cpp index 31d8d461e..389f5396e 100644 --- a/apps/opencs/model/world/idtablebase.cpp +++ b/apps/opencs/model/world/idtablebase.cpp @@ -6,4 +6,4 @@ CSMWorld::IdTableBase::IdTableBase (unsigned int features) : mFeatures (features unsigned int CSMWorld::IdTableBase::getFeatures() const { return mFeatures; -} \ No newline at end of file +} diff --git a/apps/opencs/model/world/infocollection.cpp b/apps/opencs/model/world/infocollection.cpp index 50d09f313..f2d81823c 100644 --- a/apps/opencs/model/world/infocollection.cpp +++ b/apps/opencs/model/world/infocollection.cpp @@ -26,7 +26,7 @@ void CSMWorld::InfoCollection::load (const Info& record, bool base) if (!record2.get().mPrev.empty()) { - index = getIndex (record2.get().mPrev, topic); + index = getInfoIndex (record2.get().mPrev, topic); if (index!=-1) ++index; @@ -34,7 +34,7 @@ void CSMWorld::InfoCollection::load (const Info& record, bool base) if (index==-1 && !record2.get().mNext.empty()) { - index = getIndex (record2.get().mNext, topic); + index = getInfoIndex (record2.get().mNext, topic); } if (index==-1) @@ -60,7 +60,7 @@ void CSMWorld::InfoCollection::load (const Info& record, bool base) } } -int CSMWorld::InfoCollection::getIndex (const std::string& id, const std::string& topic) const +int CSMWorld::InfoCollection::getInfoIndex (const std::string& id, const std::string& topic) const { std::string fullId = Misc::StringUtils::lowerCase (topic) + "#" + id; diff --git a/apps/opencs/model/world/infocollection.hpp b/apps/opencs/model/world/infocollection.hpp index ae61f5d39..6db47373d 100644 --- a/apps/opencs/model/world/infocollection.hpp +++ b/apps/opencs/model/world/infocollection.hpp @@ -6,7 +6,7 @@ namespace ESM { - class Dialogue; + struct Dialogue; } namespace CSMWorld @@ -22,7 +22,7 @@ namespace CSMWorld void load (const Info& record, bool base); - int getIndex (const std::string& id, const std::string& topic) const; + int getInfoIndex (const std::string& id, const std::string& topic) const; ///< Return index for record \a id or -1 (if not present; deleted records are considered) /// /// \param id info ID without topic prefix @@ -47,4 +47,4 @@ namespace CSMWorld }; } -#endif \ No newline at end of file +#endif diff --git a/apps/opencs/model/world/pathgrid.hpp b/apps/opencs/model/world/pathgrid.hpp index d8cc89f24..7e7b7c3bb 100644 --- a/apps/opencs/model/world/pathgrid.hpp +++ b/apps/opencs/model/world/pathgrid.hpp @@ -26,4 +26,4 @@ namespace CSMWorld }; } -#endif \ No newline at end of file +#endif diff --git a/apps/opencs/model/world/record.cpp b/apps/opencs/model/world/record.cpp index 14f63c155..ef2f4d320 100644 --- a/apps/opencs/model/world/record.cpp +++ b/apps/opencs/model/world/record.cpp @@ -18,4 +18,4 @@ bool CSMWorld::RecordBase::isErased() const bool CSMWorld::RecordBase::isModified() const { return mState==State_Modified || mState==State_ModifiedOnly; -} \ No newline at end of file +} diff --git a/apps/opencs/model/world/record.hpp b/apps/opencs/model/world/record.hpp index 861fc47a3..3362f9f96 100644 --- a/apps/opencs/model/world/record.hpp +++ b/apps/opencs/model/world/record.hpp @@ -22,6 +22,8 @@ namespace CSMWorld virtual RecordBase *clone() const = 0; + virtual RecordBase *modifiedCopy() const = 0; + virtual void assign (const RecordBase& record) = 0; ///< Will throw an exception if the types don't match. @@ -38,8 +40,15 @@ namespace CSMWorld ESXRecordT mBase; ESXRecordT mModified; + Record(); + + Record(State state, + const ESXRecordT *base = 0, const ESXRecordT *modified = 0); + virtual RecordBase *clone() const; + virtual RecordBase *modifiedCopy() const; + virtual void assign (const RecordBase& record); const ESXRecordT& get() const; @@ -58,6 +67,29 @@ namespace CSMWorld ///< Merge modified into base. }; + template + Record::Record() + : mBase(), mModified() + { } + + template + Record::Record(State state, const ESXRecordT *base, const ESXRecordT *modified) + { + if(base) + mBase = *base; + + if(modified) + mModified = *modified; + + this->mState = state; + } + + template + RecordBase *Record::modifiedCopy() const + { + return new Record (State_ModifiedOnly, 0, &(this->get())); + } + template RecordBase *Record::clone() const { diff --git a/apps/opencs/model/world/ref.cpp b/apps/opencs/model/world/ref.cpp index f3c1b0b73..eee454a16 100644 --- a/apps/opencs/model/world/ref.cpp +++ b/apps/opencs/model/world/ref.cpp @@ -5,4 +5,4 @@ CSMWorld::CellRef::CellRef() { mRefNum.mIndex = 0; mRefNum.mContentFile = 0; -} \ No newline at end of file +} diff --git a/apps/opencs/model/world/ref.hpp b/apps/opencs/model/world/ref.hpp index eb62434cf..8ab901a6f 100644 --- a/apps/opencs/model/world/ref.hpp +++ b/apps/opencs/model/world/ref.hpp @@ -5,8 +5,6 @@ namespace CSMWorld { - class Cell; - /// \brief Wrapper for CellRef sub record struct CellRef : public ESM::CellRef { diff --git a/apps/opencs/model/world/refcollection.hpp b/apps/opencs/model/world/refcollection.hpp index 4ecc32b2f..46572752e 100644 --- a/apps/opencs/model/world/refcollection.hpp +++ b/apps/opencs/model/world/refcollection.hpp @@ -12,7 +12,7 @@ namespace CSMWorld { struct Cell; - struct UniversalId; + class UniversalId; /// \brief References in cells class RefCollection : public Collection diff --git a/apps/opencs/model/world/refidadapter.cpp b/apps/opencs/model/world/refidadapter.cpp index 94ae38c3c..8f74e6134 100644 --- a/apps/opencs/model/world/refidadapter.cpp +++ b/apps/opencs/model/world/refidadapter.cpp @@ -3,4 +3,4 @@ CSMWorld::RefIdAdapter::RefIdAdapter() {} -CSMWorld::RefIdAdapter::~RefIdAdapter() {} \ No newline at end of file +CSMWorld::RefIdAdapter::~RefIdAdapter() {} diff --git a/apps/opencs/model/world/refidadapter.hpp b/apps/opencs/model/world/refidadapter.hpp index 0870a2d3e..74c5dfe58 100644 --- a/apps/opencs/model/world/refidadapter.hpp +++ b/apps/opencs/model/world/refidadapter.hpp @@ -9,7 +9,7 @@ namespace CSMWorld { class RefIdColumn; class RefIdData; - class RecordBase; + struct RecordBase; class RefIdAdapter { @@ -35,4 +35,4 @@ namespace CSMWorld }; } -#endif \ No newline at end of file +#endif diff --git a/apps/opencs/model/world/refidadapterimp.hpp b/apps/opencs/model/world/refidadapterimp.hpp index 034905781..202b7781c 100644 --- a/apps/opencs/model/world/refidadapterimp.hpp +++ b/apps/opencs/model/world/refidadapterimp.hpp @@ -156,10 +156,16 @@ namespace CSMWorld Record& record = static_cast&> ( data.getRecord (RefIdData::LocalIndex (index, BaseRefIdAdapter::getType()))); + RecordT record2 = record.get(); if (column==mModel.mModel) - record.get().mModel = value.toString().toUtf8().constData(); + record2.mModel = value.toString().toUtf8().constData(); else + { BaseRefIdAdapter::setData (column, data, index, value); + return; + } + + record.setModified(record2); } struct NameColumns : public ModelColumns @@ -216,12 +222,18 @@ namespace CSMWorld Record& record = static_cast&> ( data.getRecord (RefIdData::LocalIndex (index, BaseRefIdAdapter::getType()))); + RecordT record2 = record.get(); if (column==mName.mName) - record.get().mName = value.toString().toUtf8().constData(); + record2.mName = value.toString().toUtf8().constData(); else if (column==mName.mScript) - record.get().mScript = value.toString().toUtf8().constData(); + record2.mScript = value.toString().toUtf8().constData(); else + { ModelRefIdAdapter::setData (column, data, index, value); + return; + } + + record.setModified(record2); } struct InventoryColumns : public NameColumns @@ -283,14 +295,20 @@ namespace CSMWorld Record& record = static_cast&> ( data.getRecord (RefIdData::LocalIndex (index, BaseRefIdAdapter::getType()))); + RecordT record2 = record.get(); if (column==mInventory.mIcon) - record.get().mIcon = value.toString().toUtf8().constData(); + record2.mIcon = value.toString().toUtf8().constData(); else if (column==mInventory.mWeight) - record.get().mData.mWeight = value.toFloat(); + record2.mData.mWeight = value.toFloat(); else if (column==mInventory.mValue) - record.get().mData.mValue = value.toInt(); + record2.mData.mValue = value.toInt(); else + { NameRefIdAdapter::setData (column, data, index, value); + return; + } + + record.setModified(record2); } class PotionRefIdAdapter : public InventoryRefIdAdapter @@ -364,12 +382,18 @@ namespace CSMWorld Record& record = static_cast&> ( data.getRecord (RefIdData::LocalIndex (index, BaseRefIdAdapter::getType()))); + RecordT record2 = record.get(); if (column==mEnchantable.mEnchantment) - record.get().mEnchant = value.toString().toUtf8().constData(); + record2.mEnchant = value.toString().toUtf8().constData(); else if (column==mEnchantable.mEnchantmentPoints) - record.get().mData.mEnchant = value.toInt(); + record2.mData.mEnchant = value.toInt(); else + { InventoryRefIdAdapter::setData (column, data, index, value); + return; + } + + record.setModified(record2); } struct ToolColumns : public InventoryColumns @@ -426,12 +450,18 @@ namespace CSMWorld Record& record = static_cast&> ( data.getRecord (RefIdData::LocalIndex (index, BaseRefIdAdapter::getType()))); + RecordT record2 = record.get(); if (column==mTools.mQuality) - record.get().mData.mQuality = value.toFloat(); + record2.mData.mQuality = value.toFloat(); else if (column==mTools.mUses) - record.get().mData.mUses = value.toInt(); + record2.mData.mUses = value.toInt(); else + { InventoryRefIdAdapter::setData (column, data, index, value); + return; + } + + record.setModified(record2); } struct ActorColumns : public NameColumns @@ -508,16 +538,17 @@ namespace CSMWorld Record& record = static_cast&> ( data.getRecord (RefIdData::LocalIndex (index, BaseRefIdAdapter::getType()))); + RecordT record2 = record.get(); if (column==mActors.mHasAi) - record.get().mHasAI = value.toInt(); + record2.mHasAI = value.toInt(); else if (column==mActors.mHello) - record.get().mAiData.mHello = value.toInt(); + record2.mAiData.mHello = value.toInt(); else if (column==mActors.mFlee) - record.get().mAiData.mFlee = value.toInt(); + record2.mAiData.mFlee = value.toInt(); else if (column==mActors.mFight) - record.get().mAiData.mFight = value.toInt(); + record2.mAiData.mFight = value.toInt(); else if (column==mActors.mAlarm) - record.get().mAiData.mAlarm = value.toInt(); + record2.mAiData.mAlarm = value.toInt(); else { typename std::map::const_iterator iter = @@ -525,13 +556,18 @@ namespace CSMWorld if (iter!=mActors.mServices.end()) { if (value.toInt()!=0) - record.get().mAiData.mServices |= iter->second; + record2.mAiData.mServices |= iter->second; else - record.get().mAiData.mServices &= ~iter->second; + record2.mAiData.mServices &= ~iter->second; } else + { NameRefIdAdapter::setData (column, data, index, value); + return; + } } + + record.setModified(record2); } class ApparatusRefIdAdapter : public InventoryRefIdAdapter diff --git a/apps/opencs/model/world/refidcollection.cpp b/apps/opencs/model/world/refidcollection.cpp index 779d5a40c..14a8890ad 100644 --- a/apps/opencs/model/world/refidcollection.cpp +++ b/apps/opencs/model/world/refidcollection.cpp @@ -470,8 +470,7 @@ void CSMWorld::RefIdCollection::cloneRecord(const std::string& origin, const std::string& destination, const CSMWorld::UniversalId::Type type) { - std::auto_ptr newRecord(mData.getRecord(mData.searchId(origin)).clone()); - newRecord->mState = RecordBase::State_ModifiedOnly; + std::auto_ptr newRecord(mData.getRecord(mData.searchId(origin)).modifiedCopy()); mAdapters.find(type)->second->setId(*newRecord, destination); mData.insertRecord(*newRecord, type, destination); } diff --git a/apps/opencs/model/world/regionmap.cpp b/apps/opencs/model/world/regionmap.cpp index 5f030bb52..f63426c04 100644 --- a/apps/opencs/model/world/regionmap.cpp +++ b/apps/opencs/model/world/regionmap.cpp @@ -503,4 +503,4 @@ void CSMWorld::RegionMap::cellsChanged (const QModelIndex& topLeft, const QModel // columns we are interested in. If not we can exit the function here and avoid all updating. addCells (topLeft.row(), bottomRight.row()); -} \ No newline at end of file +} diff --git a/apps/opencs/model/world/resourcetable.cpp b/apps/opencs/model/world/resourcetable.cpp index a7180434a..9257b9d2a 100644 --- a/apps/opencs/model/world/resourcetable.cpp +++ b/apps/opencs/model/world/resourcetable.cpp @@ -143,4 +143,4 @@ std::pair CSMWorld::ResourceTable::view (int bool CSMWorld::ResourceTable::isDeleted (const std::string& id) const { return false; -} \ No newline at end of file +} diff --git a/apps/opencs/model/world/scope.cpp b/apps/opencs/model/world/scope.cpp index e3ebf5ebd..6e4ce4c02 100644 --- a/apps/opencs/model/world/scope.cpp +++ b/apps/opencs/model/world/scope.cpp @@ -22,4 +22,4 @@ CSMWorld::Scope CSMWorld::getScopeFromId (const std::string& id) return Scope_Session; return Scope_Content; -} \ No newline at end of file +} diff --git a/apps/opencs/model/world/scriptcontext.cpp b/apps/opencs/model/world/scriptcontext.cpp index 0d2b9984e..a8c2c9452 100644 --- a/apps/opencs/model/world/scriptcontext.cpp +++ b/apps/opencs/model/world/scriptcontext.cpp @@ -120,4 +120,4 @@ void CSMWorld::ScriptContext::clear() mIds.clear(); mIdsUpdated = false; mLocals.clear(); -} \ No newline at end of file +} diff --git a/apps/opencs/model/world/universalid.cpp b/apps/opencs/model/world/universalid.cpp index d19959d44..50ac846db 100644 --- a/apps/opencs/model/world/universalid.cpp +++ b/apps/opencs/model/world/universalid.cpp @@ -55,6 +55,7 @@ namespace { CSMWorld::UniversalId::Class_RecordList, CSMWorld::UniversalId::Type_SoundGens, "Sound Generators", 0 }, { CSMWorld::UniversalId::Class_RecordList, CSMWorld::UniversalId::Type_MagicEffects, "Magic Effects", 0 }, { CSMWorld::UniversalId::Class_RecordList, CSMWorld::UniversalId::Type_Pathgrids, "Pathgrids", 0 }, + { CSMWorld::UniversalId::Class_RecordList, CSMWorld::UniversalId::Type_StartScripts, "Start Scripts", 0 }, { CSMWorld::UniversalId::Class_None, CSMWorld::UniversalId::Type_None, 0, 0 } // end marker }; @@ -118,6 +119,7 @@ namespace { CSMWorld::UniversalId::Class_Record, CSMWorld::UniversalId::Type_SoundGen, "Sound Generator", 0 }, { CSMWorld::UniversalId::Class_Record, CSMWorld::UniversalId::Type_MagicEffect, "Magic Effect", 0 }, { CSMWorld::UniversalId::Class_Record, CSMWorld::UniversalId::Type_Pathgrid, "Pathgrid", 0 }, + { CSMWorld::UniversalId::Class_Record, CSMWorld::UniversalId::Type_StartScript, "Start Script", 0 }, { CSMWorld::UniversalId::Class_None, CSMWorld::UniversalId::Type_None, 0, 0 } // end marker }; diff --git a/apps/opencs/model/world/universalid.hpp b/apps/opencs/model/world/universalid.hpp index ce2d021d0..a716aec03 100644 --- a/apps/opencs/model/world/universalid.hpp +++ b/apps/opencs/model/world/universalid.hpp @@ -128,6 +128,8 @@ namespace CSMWorld Type_MagicEffect, Type_Pathgrids, Type_Pathgrid, + Type_StartScripts, + Type_StartScript, Type_RunLog }; diff --git a/apps/opencs/view/doc/adjusterwidget.cpp b/apps/opencs/view/doc/adjusterwidget.cpp index 09e58690f..6571ad7c8 100644 --- a/apps/opencs/view/doc/adjusterwidget.cpp +++ b/apps/opencs/view/doc/adjusterwidget.cpp @@ -5,6 +5,7 @@ #include #include +#include #include #include @@ -72,8 +73,11 @@ void CSVDoc::AdjusterWidget::setName (const QString& name, bool addon) { boost::filesystem::path path (name.toUtf8().data()); - bool isLegacyPath = (path.extension() == ".esm" || - path.extension() == ".esp"); + std::string extension = path.extension().string(); + boost::algorithm::to_lower(extension); + + bool isLegacyPath = (extension == ".esm" || + extension == ".esp"); bool isFilePathChanged = (path.parent_path().string() != mLocalData.string()); diff --git a/apps/opencs/view/doc/filedialog.cpp b/apps/opencs/view/doc/filedialog.cpp index 6a72f13ed..1b3196112 100644 --- a/apps/opencs/view/doc/filedialog.cpp +++ b/apps/opencs/view/doc/filedialog.cpp @@ -147,17 +147,19 @@ void CSVDoc::FileDialog::slotUpdateAcceptButton(int) void CSVDoc::FileDialog::slotUpdateAcceptButton(const QString &name, bool) { - bool success = (mSelector->selectedFiles().size() > 0); + bool success = !mSelector->selectedFiles().empty(); bool isNew = (mAction == ContentAction_New); if (isNew) success = success && !(name.isEmpty()); - else + else if (success) { ContentSelectorModel::EsmFile *file = mSelector->selectedFiles().back(); mAdjusterWidget->setName (file->filePath(), !file->isGameFile()); } + else + mAdjusterWidget->setName ("", true); ui.projectButtonBox->button (QDialogButtonBox::Ok)->setEnabled (success); } diff --git a/apps/opencs/view/doc/globaldebugprofilemenu.cpp b/apps/opencs/view/doc/globaldebugprofilemenu.cpp index 82bd96326..b88381385 100644 --- a/apps/opencs/view/doc/globaldebugprofilemenu.cpp +++ b/apps/opencs/view/doc/globaldebugprofilemenu.cpp @@ -90,4 +90,4 @@ void CSVDoc::GlobalDebugProfileMenu::profileChanged (const QModelIndex& topLeft, void CSVDoc::GlobalDebugProfileMenu::actionTriggered (QAction *action) { emit triggered (std::string (action->text().toUtf8().constData())); -} \ No newline at end of file +} diff --git a/apps/opencs/view/doc/loader.cpp b/apps/opencs/view/doc/loader.cpp index 046eb5229..30235d0f5 100644 --- a/apps/opencs/view/doc/loader.cpp +++ b/apps/opencs/view/doc/loader.cpp @@ -20,7 +20,7 @@ void CSVDoc::LoadingDocument::closeEvent (QCloseEvent *event) CSVDoc::LoadingDocument::LoadingDocument (CSMDoc::Document *document) : mDocument (document), mAborted (false), mMessages (0), mTotalRecords (0) { - setWindowTitle (("Opening " + document->getSavePath().filename().string()).c_str()); + setWindowTitle (QString::fromUtf8((std::string("Opening ") + document->getSavePath().filename().string()).c_str())); setMinimumWidth (400); diff --git a/apps/opencs/view/doc/runlogsubview.cpp b/apps/opencs/view/doc/runlogsubview.cpp index 68e888e8d..129396999 100644 --- a/apps/opencs/view/doc/runlogsubview.cpp +++ b/apps/opencs/view/doc/runlogsubview.cpp @@ -17,4 +17,4 @@ CSVDoc::RunLogSubView::RunLogSubView (const CSMWorld::UniversalId& id, void CSVDoc::RunLogSubView::setEditLock (bool locked) { // ignored since this SubView does not have editing -} \ No newline at end of file +} diff --git a/apps/opencs/view/doc/startup.cpp b/apps/opencs/view/doc/startup.cpp index 799a07e14..58a46c603 100644 --- a/apps/opencs/view/doc/startup.cpp +++ b/apps/opencs/view/doc/startup.cpp @@ -96,7 +96,7 @@ QWidget *CSVDoc::StartupDialogue::createTools() CSVDoc::StartupDialogue::StartupDialogue() : mWidth (0), mColumn (2) { - setWindowTitle ("Open CS"); + setWindowTitle ("OpenMW-CS"); QVBoxLayout *layout = new QVBoxLayout (this); diff --git a/apps/opencs/view/doc/subview.cpp b/apps/opencs/view/doc/subview.cpp index a399b5b5b..df1e7ee49 100644 --- a/apps/opencs/view/doc/subview.cpp +++ b/apps/opencs/view/doc/subview.cpp @@ -26,7 +26,7 @@ void CSVDoc::SubView::updateUserSetting (const QString &, const QStringList &) void CSVDoc::SubView::setUniversalId (const CSMWorld::UniversalId& id) { mUniversalId = id; - setWindowTitle (mUniversalId.toString().c_str()); + setWindowTitle (QString::fromUtf8(mUniversalId.toString().c_str())); } void CSVDoc::SubView::closeEvent (QCloseEvent *event) diff --git a/apps/opencs/view/doc/subviewfactory.cpp b/apps/opencs/view/doc/subviewfactory.cpp index 8576f6b1d..3137f7e32 100644 --- a/apps/opencs/view/doc/subviewfactory.cpp +++ b/apps/opencs/view/doc/subviewfactory.cpp @@ -35,4 +35,4 @@ CSVDoc::SubView *CSVDoc::SubViewFactoryManager::makeSubView (const CSMWorld::Uni throw std::runtime_error ("Failed to create a sub view for: " + id.toString()); return iter->second->makeSubView (id, document); -} \ No newline at end of file +} diff --git a/apps/opencs/view/doc/subviewfactoryimp.hpp b/apps/opencs/view/doc/subviewfactoryimp.hpp index 059b24fd0..670137985 100644 --- a/apps/opencs/view/doc/subviewfactoryimp.hpp +++ b/apps/opencs/view/doc/subviewfactoryimp.hpp @@ -48,4 +48,4 @@ namespace CSVDoc } } -#endif \ No newline at end of file +#endif diff --git a/apps/opencs/view/doc/view.cpp b/apps/opencs/view/doc/view.cpp index 9117a6d03..cf2940b99 100644 --- a/apps/opencs/view/doc/view.cpp +++ b/apps/opencs/view/doc/view.cpp @@ -173,6 +173,10 @@ void CSVDoc::View::setupMechanicsMenu() QAction *effects = new QAction (tr ("Magic Effects"), this); connect (effects, SIGNAL (triggered()), this, SLOT (addMagicEffectsSubView())); mechanics->addAction (effects); + + QAction *startScripts = new QAction (tr ("Start Scripts"), this); + connect (startScripts, SIGNAL (triggered()), this, SLOT (addStartScriptsSubView())); + mechanics->addAction (startScripts); } void CSVDoc::View::setupCharacterMenu() @@ -320,7 +324,7 @@ void CSVDoc::View::updateTitle() if (hideTitle) stream << " - " << mSubViews.at (0)->getTitle(); - setWindowTitle (stream.str().c_str()); + setWindowTitle (QString::fromUtf8(stream.str().c_str())); } void CSVDoc::View::updateSubViewIndicies(SubView *view) @@ -481,6 +485,8 @@ void CSVDoc::View::addSubView (const CSMWorld::UniversalId& id, const std::strin (!isReferenceable && id == sb->getUniversalId())) { sb->setFocus(); + if (!hint.empty()) + sb->useHint (hint); return; } } @@ -511,8 +517,6 @@ void CSVDoc::View::addSubView (const CSMWorld::UniversalId& id, const std::strin assert(view); view->setParent(this); mSubViews.append(view); // only after assert - if (!hint.empty()) - view->useHint (hint); int minWidth = userSettings.setting ("window/minimum-width", QString("325")).toInt(); view->setMinimumWidth(minWidth); @@ -534,6 +538,9 @@ void CSVDoc::View::addSubView (const CSMWorld::UniversalId& id, const std::strin this, SLOT (updateSubViewIndicies (SubView *))); view->show(); + + if (!hint.empty()) + view->useHint (hint); } void CSVDoc::View::newView() @@ -716,6 +723,11 @@ void CSVDoc::View::addPathgridSubView() addSubView (CSMWorld::UniversalId::Type_Pathgrids); } +void CSVDoc::View::addStartScriptsSubView() +{ + addSubView (CSMWorld::UniversalId::Type_StartScripts); +} + void CSVDoc::View::abortOperation (int type) { mDocument->abortOperation (type); diff --git a/apps/opencs/view/doc/view.hpp b/apps/opencs/view/doc/view.hpp index 55ea5ee51..baadca85c 100644 --- a/apps/opencs/view/doc/view.hpp +++ b/apps/opencs/view/doc/view.hpp @@ -215,6 +215,8 @@ namespace CSVDoc void addPathgridSubView(); + void addStartScriptsSubView(); + void toggleShowStatusBar (bool show); void loadErrorLog(); diff --git a/apps/opencs/view/doc/viewmanager.cpp b/apps/opencs/view/doc/viewmanager.cpp index 5f6b6b46a..9fee26078 100644 --- a/apps/opencs/view/doc/viewmanager.cpp +++ b/apps/opencs/view/doc/viewmanager.cpp @@ -248,7 +248,7 @@ bool CSVDoc::ViewManager::showModifiedDocumentMessageBox (CSVDoc::View *view) QMessageBox messageBox(view); CSMDoc::Document *document = view->getDocument(); - messageBox.setWindowTitle (document->getSavePath().filename().string().c_str()); + messageBox.setWindowTitle (QString::fromUtf8(document->getSavePath().filename().string().c_str())); messageBox.setText ("The document has been modified."); messageBox.setInformativeText ("Do you want to save your changes?"); messageBox.setStandardButtons (QMessageBox::Save | QMessageBox::Discard | QMessageBox::Cancel); diff --git a/apps/opencs/view/filter/editwidget.cpp b/apps/opencs/view/filter/editwidget.cpp index 68e99e0de..bc7f9b5a1 100644 --- a/apps/opencs/view/filter/editwidget.cpp +++ b/apps/opencs/view/filter/editwidget.cpp @@ -193,4 +193,4 @@ std::string CSVFilter::EditWidget::generateFilter (std::pair< std::string, std:: } return ss.str(); -} \ No newline at end of file +} diff --git a/apps/opencs/view/filter/recordfilterbox.hpp b/apps/opencs/view/filter/recordfilterbox.hpp index f4d17510b..29d12529a 100644 --- a/apps/opencs/view/filter/recordfilterbox.hpp +++ b/apps/opencs/view/filter/recordfilterbox.hpp @@ -43,4 +43,4 @@ namespace CSVFilter } -#endif \ No newline at end of file +#endif diff --git a/apps/opencs/view/render/cell.cpp b/apps/opencs/view/render/cell.cpp index 2c540dee6..d40e4f913 100644 --- a/apps/opencs/view/render/cell.cpp +++ b/apps/opencs/view/render/cell.cpp @@ -76,7 +76,7 @@ CSVRender::Cell::Cell (CSMWorld::Data& data, osg::Group* rootNode, const std::st if (landIndex != -1) { const ESM::Land* esmLand = land.getRecord(mId).get().mLand.get(); - if(esmLand) + if(esmLand && esmLand->mDataTypes&ESM::Land::DATA_VHGT) { mTerrain.reset(new Terrain::TerrainGrid(sceneManager, new TerrainStorage(mData), Element_Terrain, true, Terrain::Align_XY)); diff --git a/apps/opencs/view/render/editmode.cpp b/apps/opencs/view/render/editmode.cpp index 51a137d3b..9361030a3 100644 --- a/apps/opencs/view/render/editmode.cpp +++ b/apps/opencs/view/render/editmode.cpp @@ -16,4 +16,4 @@ unsigned int CSVRender::EditMode::getInteractionMask() const void CSVRender::EditMode::activate (CSVWidget::SceneToolbar *toolbar) { mWorldspaceWidget->setInteractionMask (mMask); -} \ No newline at end of file +} diff --git a/apps/opencs/view/render/lighting.cpp b/apps/opencs/view/render/lighting.cpp index d57570d69..3553ef58c 100644 --- a/apps/opencs/view/render/lighting.cpp +++ b/apps/opencs/view/render/lighting.cpp @@ -1,4 +1,4 @@ #include "lighting.hpp" -CSVRender::Lighting::~Lighting() {} \ No newline at end of file +CSVRender::Lighting::~Lighting() {} diff --git a/apps/opencs/view/render/lightingbright.cpp b/apps/opencs/view/render/lightingbright.cpp index ab845b924..a342ab093 100644 --- a/apps/opencs/view/render/lightingbright.cpp +++ b/apps/opencs/view/render/lightingbright.cpp @@ -27,4 +27,4 @@ void CSVRender::LightingBright::deactivate() } } -void CSVRender::LightingBright::setDefaultAmbient (const Ogre::ColourValue& colour) {} \ No newline at end of file +void CSVRender::LightingBright::setDefaultAmbient (const Ogre::ColourValue& colour) {} diff --git a/apps/opencs/view/render/lightingday.cpp b/apps/opencs/view/render/lightingday.cpp index ab0257c0c..c5189ccfd 100644 --- a/apps/opencs/view/render/lightingday.cpp +++ b/apps/opencs/view/render/lightingday.cpp @@ -33,4 +33,4 @@ void CSVRender::LightingDay::deactivate() void CSVRender::LightingDay::setDefaultAmbient (const Ogre::ColourValue& colour) { mSceneManager->setAmbientLight (colour); -} \ No newline at end of file +} diff --git a/apps/opencs/view/render/lightingnight.cpp b/apps/opencs/view/render/lightingnight.cpp index 516bb3f40..7d94dc964 100644 --- a/apps/opencs/view/render/lightingnight.cpp +++ b/apps/opencs/view/render/lightingnight.cpp @@ -33,4 +33,4 @@ void CSVRender::LightingNight::deactivate() void CSVRender::LightingNight::setDefaultAmbient (const Ogre::ColourValue& colour) { mSceneManager->setAmbientLight (colour); -} \ No newline at end of file +} diff --git a/apps/opencs/view/render/navigationorbit.cpp b/apps/opencs/view/render/navigationorbit.cpp index c6e729e96..c5f3eda96 100644 --- a/apps/opencs/view/render/navigationorbit.cpp +++ b/apps/opencs/view/render/navigationorbit.cpp @@ -97,4 +97,4 @@ bool CSVRender::NavigationOrbit::handleRollKeys (int delta) { mCamera->roll (Ogre::Degree (getFactor (false) * delta)); return true; -} \ No newline at end of file +} diff --git a/apps/opencs/view/render/object.hpp b/apps/opencs/view/render/object.hpp index 23a652792..e40253a60 100644 --- a/apps/opencs/view/render/object.hpp +++ b/apps/opencs/view/render/object.hpp @@ -22,7 +22,7 @@ namespace Resource namespace CSMWorld { class Data; - class CellRef; + struct CellRef; } namespace CSVWorld diff --git a/apps/opencs/view/tools/reporttable.cpp b/apps/opencs/view/tools/reporttable.cpp index 4cd11925e..809a39fa4 100644 --- a/apps/opencs/view/tools/reporttable.cpp +++ b/apps/opencs/view/tools/reporttable.cpp @@ -30,7 +30,7 @@ void CSVTools::ReportTable::contextMenuEvent (QContextMenuEvent *event) void CSVTools::ReportTable::mouseMoveEvent (QMouseEvent *event) { if (event->buttons() & Qt::LeftButton) - startDrag (*this); + startDragFromTable (*this); } void CSVTools::ReportTable::mouseDoubleClickEvent (QMouseEvent *event) @@ -133,4 +133,4 @@ void CSVTools::ReportTable::removeSelection() mModel->removeRows (iter->row(), 1); selectionModel()->clear(); -} \ No newline at end of file +} diff --git a/apps/opencs/view/tools/subviews.cpp b/apps/opencs/view/tools/subviews.cpp index 8b04aca50..a50b5724a 100644 --- a/apps/opencs/view/tools/subviews.cpp +++ b/apps/opencs/view/tools/subviews.cpp @@ -11,4 +11,4 @@ void CSVTools::addSubViewFactories (CSVDoc::SubViewFactoryManager& manager) new CSVDoc::SubViewFactory); manager.add (CSMWorld::UniversalId::Type_LoadErrorLog, new CSVDoc::SubViewFactory); -} \ No newline at end of file +} diff --git a/apps/opencs/view/widget/pushbutton.cpp b/apps/opencs/view/widget/pushbutton.cpp index d4e600794..1baeb7ca2 100644 --- a/apps/opencs/view/widget/pushbutton.cpp +++ b/apps/opencs/view/widget/pushbutton.cpp @@ -106,4 +106,4 @@ CSVWidget::PushButton::Type CSVWidget::PushButton::getType() const void CSVWidget::PushButton::checkedStateChanged (bool checked) { setExtendedToolTip(); -} \ No newline at end of file +} diff --git a/apps/opencs/view/widget/scenetoolmode.cpp b/apps/opencs/view/widget/scenetoolmode.cpp index 8d871cc5f..39e051c48 100644 --- a/apps/opencs/view/widget/scenetoolmode.cpp +++ b/apps/opencs/view/widget/scenetoolmode.cpp @@ -100,4 +100,4 @@ void CSVWidget::SceneToolMode::selected() emit modeChanged (iter->second); } -} \ No newline at end of file +} diff --git a/apps/opencs/view/widget/scenetoolrun.cpp b/apps/opencs/view/widget/scenetoolrun.cpp index 0c7a4b9f0..8de334efe 100644 --- a/apps/opencs/view/widget/scenetoolrun.cpp +++ b/apps/opencs/view/widget/scenetoolrun.cpp @@ -148,4 +148,4 @@ void CSVWidget::SceneToolRun::clicked (const QModelIndex& index) removeProfile (*iter); updatePanel(); } -} \ No newline at end of file +} diff --git a/apps/opencs/view/world/creator.cpp b/apps/opencs/view/world/creator.cpp index a24c58e54..2e7c7fe22 100644 --- a/apps/opencs/view/world/creator.cpp +++ b/apps/opencs/view/world/creator.cpp @@ -19,4 +19,4 @@ CSVWorld::Creator *CSVWorld::NullCreatorFactory::makeCreator (CSMWorld::Data& da QUndoStack& undoStack, const CSMWorld::UniversalId& id) const { return 0; -} \ No newline at end of file +} diff --git a/apps/opencs/view/world/creator.hpp b/apps/opencs/view/world/creator.hpp index 8e50e8715..7c0422c88 100644 --- a/apps/opencs/view/world/creator.hpp +++ b/apps/opencs/view/world/creator.hpp @@ -101,4 +101,4 @@ namespace CSVWorld } } -#endif \ No newline at end of file +#endif diff --git a/apps/opencs/view/world/dialoguecreator.cpp b/apps/opencs/view/world/dialoguecreator.cpp index 3523d5e32..956cd26df 100644 --- a/apps/opencs/view/world/dialoguecreator.cpp +++ b/apps/opencs/view/world/dialoguecreator.cpp @@ -32,4 +32,4 @@ CSVWorld::Creator *CSVWorld::JournalCreatorFactory::makeCreator (CSMWorld::Data& QUndoStack& undoStack, const CSMWorld::UniversalId& id) const { return new DialogueCreator (data, undoStack, id, ESM::Dialogue::Journal); -} \ No newline at end of file +} diff --git a/apps/opencs/view/world/dialoguesubview.cpp b/apps/opencs/view/world/dialoguesubview.cpp index 8790601ea..e383f5e9a 100644 --- a/apps/opencs/view/world/dialoguesubview.cpp +++ b/apps/opencs/view/world/dialoguesubview.cpp @@ -2,6 +2,7 @@ #include #include +#include #include #include @@ -39,8 +40,12 @@ QAbstractItemDelegate(parent), mTable(table) {} -void CSVWorld::NotEditableSubDelegate::setEditorData (QLabel* editor, const QModelIndex& index) const +void CSVWorld::NotEditableSubDelegate::setEditorData (QWidget* editor, const QModelIndex& index) const { + QLabel* label = qobject_cast(editor); + if(!label) + return; + QVariant v = index.data(Qt::EditRole); if (!v.isValid()) { @@ -53,16 +58,17 @@ void CSVWorld::NotEditableSubDelegate::setEditorData (QLabel* editor, const QMod if (QVariant::String == v.type()) { - editor->setText(v.toString()); - } else //else we are facing enums + label->setText(v.toString()); + } + else //else we are facing enums { int data = v.toInt(); std::vector enumNames (CSMWorld::Columns::getEnums (static_cast (mTable->getColumnId (index.column())))); - editor->setText(QString::fromUtf8(enumNames.at(data).c_str())); + label->setText(QString::fromUtf8(enumNames.at(data).c_str())); } } -void CSVWorld::NotEditableSubDelegate::setModelData (QWidget* editor, QAbstractItemModel* model, const QModelIndex& index, CSMWorld::ColumnBase::Display display) const +void CSVWorld::NotEditableSubDelegate::setModelData(QWidget* editor, QAbstractItemModel* model, const QModelIndex& index) const { //not editable widgets will not save model data } @@ -79,8 +85,7 @@ QSize CSVWorld::NotEditableSubDelegate::sizeHint (const QStyleOptionViewItem& op QWidget* CSVWorld::NotEditableSubDelegate::createEditor (QWidget *parent, const QStyleOptionViewItem& option, - const QModelIndex& index, - CSMWorld::ColumnBase::Display display) const + const QModelIndex& index) const { return new QLabel(parent); } @@ -223,6 +228,11 @@ void CSVWorld::DialogueDelegateDispatcher::setEditorData (QWidget* editor, const } } +void CSVWorld::DialogueDelegateDispatcher::setModelData(QWidget* editor, QAbstractItemModel* model, const QModelIndex& index) const +{ + setModelData(editor, model, index, CSMWorld::ColumnBase::Display_None); +} + void CSVWorld::DialogueDelegateDispatcher::setModelData(QWidget* editor, QAbstractItemModel* model, const QModelIndex& index, CSMWorld::ColumnBase::Display display) const { std::map::const_iterator delegateIt(mDelegates.find(display)); @@ -257,7 +267,7 @@ QWidget* CSVWorld::DialogueDelegateDispatcher::makeEditor(CSMWorld::ColumnBase:: QWidget* editor = NULL; if (! (mTable->flags (index) & Qt::ItemIsEditable)) { - return mNotEditableDelegate.createEditor(qobject_cast(mParent), QStyleOptionViewItem(), index, display); + return mNotEditableDelegate.createEditor(qobject_cast(mParent), QStyleOptionViewItem(), index); } std::map::iterator delegateIt(mDelegates.find(display)); @@ -266,6 +276,8 @@ QWidget* CSVWorld::DialogueDelegateDispatcher::makeEditor(CSMWorld::ColumnBase:: editor = delegateIt->second->createEditor(qobject_cast(mParent), QStyleOptionViewItem(), index, display); DialogueDelegateDispatcherProxy* proxy = new DialogueDelegateDispatcherProxy(editor, display); + // NOTE: For each entry in CSVWorld::CommandDelegate::createEditor() a corresponding entry + // is required here if (qobject_cast(editor)) { connect(editor, SIGNAL(editingFinished()), proxy, SLOT(editorDataCommited())); @@ -286,10 +298,12 @@ QWidget* CSVWorld::DialogueDelegateDispatcher::makeEditor(CSMWorld::ColumnBase:: { connect(editor, SIGNAL(currentIndexChanged (int)), proxy, SLOT(editorDataCommited())); } - else if (qobject_cast(editor)) + else if (qobject_cast(editor) || qobject_cast(editor)) { connect(editor, SIGNAL(editingFinished()), proxy, SLOT(editorDataCommited())); } + else // throw an exception because this is a coding error + throw std::logic_error ("Dialogue editor type missing"); connect(proxy, SIGNAL(editorDataCommited(QWidget*, const QModelIndex&, CSMWorld::ColumnBase::Display)), this, SLOT(editorDataCommited(QWidget*, const QModelIndex&, CSMWorld::ColumnBase::Display))); mProxys.push_back(proxy); //deleted in the destructor diff --git a/apps/opencs/view/world/dialoguesubview.hpp b/apps/opencs/view/world/dialoguesubview.hpp index 4c260170f..5bd226960 100644 --- a/apps/opencs/view/world/dialoguesubview.hpp +++ b/apps/opencs/view/world/dialoguesubview.hpp @@ -40,9 +40,9 @@ namespace CSVWorld public: NotEditableSubDelegate(const CSMWorld::IdTable* table, QObject * parent = 0); - virtual void setEditorData (QLabel* editor, const QModelIndex& index) const; + virtual void setEditorData (QWidget* editor, const QModelIndex& index) const; - virtual void setModelData (QWidget* editor, QAbstractItemModel* model, const QModelIndex& index, CSMWorld::ColumnBase::Display display) const; + virtual void setModelData (QWidget* editor, QAbstractItemModel* model, const QModelIndex& index) const; virtual void paint (QPainter* painter, const QStyleOptionViewItem& option, const QModelIndex& index) const; ///< does nothing @@ -52,8 +52,7 @@ namespace CSVWorld virtual QWidget *createEditor (QWidget *parent, const QStyleOptionViewItem& option, - const QModelIndex& index, - CSMWorld::ColumnBase::Display display = CSMWorld::ColumnBase::Display_None) const; + const QModelIndex& index) const; }; //this can't be nested into the DialogueDelegateDispatcher, because it needs to emit signals @@ -119,6 +118,8 @@ namespace CSVWorld virtual void setEditorData (QWidget* editor, const QModelIndex& index) const; + virtual void setModelData (QWidget* editor, QAbstractItemModel* model, const QModelIndex& index) const; + virtual void setModelData (QWidget* editor, QAbstractItemModel* model, const QModelIndex& index, CSMWorld::ColumnBase::Display display) const; virtual void paint (QPainter* painter, const QStyleOptionViewItem& option, const QModelIndex& index) const; @@ -209,4 +210,4 @@ namespace CSVWorld }; } -#endif \ No newline at end of file +#endif diff --git a/apps/opencs/view/world/dragrecordtable.cpp b/apps/opencs/view/world/dragrecordtable.cpp index c33fa58ad..f45c45809 100644 --- a/apps/opencs/view/world/dragrecordtable.cpp +++ b/apps/opencs/view/world/dragrecordtable.cpp @@ -3,7 +3,7 @@ #include "../../model/world/tablemimedata.hpp" #include "dragrecordtable.hpp" -void CSVWorld::DragRecordTable::startDrag (const CSVWorld::DragRecordTable& table) +void CSVWorld::DragRecordTable::startDragFromTable (const CSVWorld::DragRecordTable& table) { CSMWorld::TableMimeData* mime = new CSMWorld::TableMimeData (table.getDraggedRecords(), mDocument); diff --git a/apps/opencs/view/world/dragrecordtable.hpp b/apps/opencs/view/world/dragrecordtable.hpp index 8c5f1b841..4996c03ac 100644 --- a/apps/opencs/view/world/dragrecordtable.hpp +++ b/apps/opencs/view/world/dragrecordtable.hpp @@ -33,7 +33,7 @@ namespace CSVWorld void setEditLock(bool locked); protected: - void startDrag(const DragRecordTable& table); + void startDragFromTable(const DragRecordTable& table); void dragEnterEvent(QDragEnterEvent *event); diff --git a/apps/opencs/view/world/enumdelegate.cpp b/apps/opencs/view/world/enumdelegate.cpp index 168e5cb0a..7c305b1b6 100644 --- a/apps/opencs/view/world/enumdelegate.cpp +++ b/apps/opencs/view/world/enumdelegate.cpp @@ -46,7 +46,6 @@ QWidget *CSVWorld::EnumDelegate::createEditor(QWidget *parent, const QModelIndex& index) const { return createEditor(parent, option, index, CSMWorld::ColumnBase::Display_None); - //overloading virtual functions is HARD } QWidget *CSVWorld::EnumDelegate::createEditor(QWidget *parent, const QStyleOptionViewItem& option, diff --git a/apps/opencs/view/world/genericcreator.cpp b/apps/opencs/view/world/genericcreator.cpp index afa59bc45..b4cf46040 100644 --- a/apps/opencs/view/world/genericcreator.cpp +++ b/apps/opencs/view/world/genericcreator.cpp @@ -276,4 +276,4 @@ void CSVWorld::GenericCreator::scopeChanged (int index) { update(); updateNamespace(); -} \ No newline at end of file +} diff --git a/apps/opencs/view/world/genericcreator.hpp b/apps/opencs/view/world/genericcreator.hpp index 8c8c34bd8..678005082 100644 --- a/apps/opencs/view/world/genericcreator.hpp +++ b/apps/opencs/view/world/genericcreator.hpp @@ -111,4 +111,4 @@ namespace CSVWorld }; } -#endif \ No newline at end of file +#endif diff --git a/apps/opencs/view/world/idvalidator.cpp b/apps/opencs/view/world/idvalidator.cpp index 7caa20f9b..13b05d2d1 100644 --- a/apps/opencs/view/world/idvalidator.cpp +++ b/apps/opencs/view/world/idvalidator.cpp @@ -120,4 +120,4 @@ void CSVWorld::IdValidator::setNamespace (const std::string& namespace_) std::string CSVWorld::IdValidator::getError() const { return mError; -} \ No newline at end of file +} diff --git a/apps/opencs/view/world/infocreator.cpp b/apps/opencs/view/world/infocreator.cpp index 1d914716b..14034ea7f 100644 --- a/apps/opencs/view/world/infocreator.cpp +++ b/apps/opencs/view/world/infocreator.cpp @@ -94,4 +94,4 @@ std::string CSVWorld::InfoCreator::getErrors() const void CSVWorld::InfoCreator::topicChanged() { update(); -} \ No newline at end of file +} diff --git a/apps/opencs/view/world/regionmap.cpp b/apps/opencs/view/world/regionmap.cpp index 9497e4054..bc96b0952 100644 --- a/apps/opencs/view/world/regionmap.cpp +++ b/apps/opencs/view/world/regionmap.cpp @@ -345,7 +345,7 @@ void CSVWorld::RegionMap::viewInTable() void CSVWorld::RegionMap::mouseMoveEvent (QMouseEvent* event) { - startDrag(*this); + startDragFromTable(*this); } std::vector< CSMWorld::UniversalId > CSVWorld::RegionMap::getDraggedRecords() const @@ -400,7 +400,7 @@ void CSVWorld::RegionMap::dropEvent (QDropEvent* event) QModelIndex index2(cellsModel->getModelIndex (cellId, cellsModel->findColumnIndex (CSMWorld::Columns::ColumnId_Region))); - mDocument.getUndoStack().push(new CSMWorld::ModifyCommand + mDocument.getUndoStack().push(new CSMWorld::ModifyCommand (*cellsModel, index2, QString::fromUtf8(record.getId().c_str()))); mRegionId = record.getId(); diff --git a/apps/opencs/view/world/regionmapsubview.cpp b/apps/opencs/view/world/regionmapsubview.cpp index a7675a4a6..411e24e75 100644 --- a/apps/opencs/view/world/regionmapsubview.cpp +++ b/apps/opencs/view/world/regionmapsubview.cpp @@ -24,4 +24,4 @@ void CSVWorld::RegionMapSubView::editRequest (const CSMWorld::UniversalId& id, const std::string& hint) { focusId (id, hint); -} \ No newline at end of file +} diff --git a/apps/opencs/view/world/scriptedit.cpp b/apps/opencs/view/world/scriptedit.cpp index c2d94ab5d..271b0316d 100644 --- a/apps/opencs/view/world/scriptedit.cpp +++ b/apps/opencs/view/world/scriptedit.cpp @@ -156,4 +156,4 @@ void CSVWorld::ScriptEdit::updateHighlighting() ChangeLock lock (*this); mHighlighter->rehighlight(); -} \ No newline at end of file +} diff --git a/apps/opencs/view/world/scriptedit.hpp b/apps/opencs/view/world/scriptedit.hpp index c67385816..0192bc550 100644 --- a/apps/opencs/view/world/scriptedit.hpp +++ b/apps/opencs/view/world/scriptedit.hpp @@ -76,4 +76,4 @@ namespace CSVWorld void updateHighlighting(); }; } -#endif // SCRIPTEDIT_H \ No newline at end of file +#endif // SCRIPTEDIT_H diff --git a/apps/opencs/view/world/scripthighlighter.cpp b/apps/opencs/view/world/scripthighlighter.cpp index 36cebcb76..6dda8d4fa 100644 --- a/apps/opencs/view/world/scripthighlighter.cpp +++ b/apps/opencs/view/world/scripthighlighter.cpp @@ -142,4 +142,4 @@ void CSVWorld::ScriptHighlighter::highlightBlock (const QString& text) void CSVWorld::ScriptHighlighter::invalidateIds() { mContext.invalidateIds(); -} \ No newline at end of file +} diff --git a/apps/opencs/view/world/scriptsubview.cpp b/apps/opencs/view/world/scriptsubview.cpp index 9b50a61f8..211462a26 100644 --- a/apps/opencs/view/world/scriptsubview.cpp +++ b/apps/opencs/view/world/scriptsubview.cpp @@ -68,6 +68,7 @@ void CSVWorld::ScriptSubView::useHint (const std::string& hint) if (cursor.movePosition (QTextCursor::Down, QTextCursor::MoveAnchor, line)) cursor.movePosition (QTextCursor::Right, QTextCursor::MoveAnchor, column); + mEditor->setFocus(); mEditor->setTextCursor (cursor); } } diff --git a/apps/opencs/view/world/scriptsubview.hpp b/apps/opencs/view/world/scriptsubview.hpp index 16ffc7b80..561476577 100644 --- a/apps/opencs/view/world/scriptsubview.hpp +++ b/apps/opencs/view/world/scriptsubview.hpp @@ -46,4 +46,4 @@ namespace CSVWorld }; } -#endif \ No newline at end of file +#endif diff --git a/apps/opencs/view/world/subviews.cpp b/apps/opencs/view/world/subviews.cpp index d0b52a9ff..cd9b37a64 100644 --- a/apps/opencs/view/world/subviews.cpp +++ b/apps/opencs/view/world/subviews.cpp @@ -43,6 +43,7 @@ void CSVWorld::addSubViewFactories (CSVDoc::SubViewFactoryManager& manager) CSMWorld::UniversalId::Type_BodyParts, CSMWorld::UniversalId::Type_SoundGens, CSMWorld::UniversalId::Type_Pathgrids, + CSMWorld::UniversalId::Type_StartScripts, CSMWorld::UniversalId::Type_None // end marker }; @@ -123,6 +124,7 @@ void CSVWorld::addSubViewFactories (CSVDoc::SubViewFactoryManager& manager) CSMWorld::UniversalId::Type_BodyPart, CSMWorld::UniversalId::Type_SoundGen, CSMWorld::UniversalId::Type_Pathgrid, + CSMWorld::UniversalId::Type_StartScript, CSMWorld::UniversalId::Type_None // end marker }; diff --git a/apps/opencs/view/world/table.cpp b/apps/opencs/view/world/table.cpp index e864e4ed2..97a3bc2e3 100644 --- a/apps/opencs/view/world/table.cpp +++ b/apps/opencs/view/world/table.cpp @@ -635,7 +635,7 @@ void CSVWorld::Table::mouseMoveEvent (QMouseEvent* event) { if (event->buttons() & Qt::LeftButton) { - startDrag(*this); + startDragFromTable(*this); } } diff --git a/apps/opencs/view/world/util.cpp b/apps/opencs/view/world/util.cpp index c65e12c60..b0f8a035a 100644 --- a/apps/opencs/view/world/util.cpp +++ b/apps/opencs/view/world/util.cpp @@ -139,6 +139,12 @@ void CSVWorld::CommandDelegate::setModelData (QWidget *editor, QAbstractItemMode ///< \todo provide some kind of feedback to the user, indicating that editing is currently not possible. } +QWidget *CSVWorld::CommandDelegate::createEditor (QWidget *parent, const QStyleOptionViewItem& option, + const QModelIndex& index) const +{ + return createEditor (parent, option, index, CSMWorld::ColumnBase::Display_None); +} + QWidget *CSVWorld::CommandDelegate::createEditor (QWidget *parent, const QStyleOptionViewItem& option, const QModelIndex& index, CSMWorld::ColumnBase::Display display) const { @@ -152,6 +158,8 @@ QWidget *CSVWorld::CommandDelegate::createEditor (QWidget *parent, const QStyleO } } + // NOTE: for each editor type (e.g. QLineEdit) there needs to be a corresponding + // entry in CSVWorld::DialogueDelegateDispatcher::makeEditor() switch (display) { case CSMWorld::ColumnBase::Display_Colour: @@ -228,6 +236,11 @@ bool CSVWorld::CommandDelegate::isEditLocked() const return mEditLock; } +void CSVWorld::CommandDelegate::setEditorData (QWidget *editor, const QModelIndex& index) const +{ + setEditorData (editor, index, false); +} + void CSVWorld::CommandDelegate::setEditorData (QWidget *editor, const QModelIndex& index, bool tryDisplay) const { QVariant v = index.data(Qt::EditRole); diff --git a/apps/opencs/view/world/util.hpp b/apps/opencs/view/world/util.hpp index b4d972bf3..10011798d 100644 --- a/apps/opencs/view/world/util.hpp +++ b/apps/opencs/view/world/util.hpp @@ -130,10 +130,14 @@ namespace CSVWorld virtual void setModelData (QWidget *editor, QAbstractItemModel *model, const QModelIndex& index) const; + virtual QWidget *createEditor (QWidget *parent, + const QStyleOptionViewItem& option, + const QModelIndex& index) const; + virtual QWidget *createEditor (QWidget *parent, const QStyleOptionViewItem& option, const QModelIndex& index, - CSMWorld::ColumnBase::Display display = CSMWorld::ColumnBase::Display_None) const; + CSMWorld::ColumnBase::Display display) const; void setEditLock (bool locked); @@ -141,8 +145,9 @@ namespace CSVWorld ///< \return Does column require update? - virtual void setEditorData (QWidget *editor, const QModelIndex& index, bool tryDisplay = false) const; + virtual void setEditorData (QWidget *editor, const QModelIndex& index) const; + virtual void setEditorData (QWidget *editor, const QModelIndex& index, bool tryDisplay) const; public slots: diff --git a/apps/openmw/CMakeLists.txt b/apps/openmw/CMakeLists.txt index eabbb7577..a183d172d 100644 --- a/apps/openmw/CMakeLists.txt +++ b/apps/openmw/CMakeLists.txt @@ -7,6 +7,7 @@ set(GAME ) if (ANDROID) + set(GAME ${GAME} android_commandLine.cpp) set(GAME ${GAME} android_main.c) endif() @@ -104,7 +105,6 @@ find_package(Boost REQUIRED COMPONENTS ${BOOST_COMPONENTS}) if (NOT ANDROID) add_executable(openmw - ${OPENMW_LIBS} ${OPENMW_LIBS_HEADER} ${OPENMW_FILES} ${GAME} ${GAME_HEADER} ${APPLE_BUNDLE_RESOURCES} @@ -112,7 +112,6 @@ if (NOT ANDROID) else () add_library(openmw SHARED - ${OPENMW_LIBS} ${OPENMW_LIBS_HEADER} ${OPENMW_FILES} ${GAME} ${GAME_HEADER} ) @@ -120,9 +119,10 @@ endif () # Sound stuff - here so CMake doesn't stupidly recompile EVERYTHING # when we change the backend. -include_directories(${SOUND_INPUT_INCLUDES} ${BULLET_INCLUDE_DIRS}) +include_directories(${SOUND_INPUT_INCLUDES}) target_link_libraries(openmw + ${OENGINE_LIBRARY} ${OGRE_LIBRARIES} ${OGRE_STATIC_PLUGINS} ${SHINY_LIBRARIES} diff --git a/apps/openmw/android_commandLine.cpp b/apps/openmw/android_commandLine.cpp new file mode 100644 index 000000000..ebfff28ca --- /dev/null +++ b/apps/openmw/android_commandLine.cpp @@ -0,0 +1,27 @@ +#include "android_commandLine.h" +#include "string.h" + +const char **argvData; +int argcData; + +extern "C" void releaseArgv(); + +void releaseArgv() { + delete[] argvData; +} + +JNIEXPORT void JNICALL Java_ui_activity_GameActivity_commandLine(JNIEnv *env, + jobject obj, jint argc, jobjectArray stringArray) { + jboolean iscopy; + argcData = (int) argc; + argvData = new const char *[argcData + 1]; + argvData[0] = "openmw"; + for (int i = 1; i < argcData + 1; i++) { + jstring string = (jstring) (env)->GetObjectArrayElement(stringArray, + i - 1); + argvData[i] = (env)->GetStringUTFChars(string, &iscopy); + (env)->DeleteLocalRef(string); + } + (env)->DeleteLocalRef(stringArray); +} + diff --git a/apps/openmw/android_commandLine.h b/apps/openmw/android_commandLine.h new file mode 100644 index 000000000..21d1064c6 --- /dev/null +++ b/apps/openmw/android_commandLine.h @@ -0,0 +1,16 @@ + + +/* DO NOT EDIT THIS FILE - it is machine generated */ +#include +#ifndef _Included_ui_activity_GameActivity_commandLine +#define _Included_ui_activity_GameActivity_commandLine +#ifdef __cplusplus +extern "C" { +#endif + +JNIEXPORT void JNICALL Java_ui_activity_GameActivity_commandLine(JNIEnv *env, jobject obj,jint argcData, jobjectArray stringArray); + +#ifdef __cplusplus +} +#endif +#endif diff --git a/apps/openmw/android_main.c b/apps/openmw/android_main.c index 76da91c4f..1b2839519 100644 --- a/apps/openmw/android_main.c +++ b/apps/openmw/android_main.c @@ -1,42 +1,37 @@ - #include "../../SDL_internal.h" #ifdef __ANDROID__ #include "SDL_main.h" - /******************************************************************************* - Functions called by JNI -*******************************************************************************/ + Functions called by JNI + *******************************************************************************/ #include /* Called before to initialize JNI bindings */ - - extern void SDL_Android_Init(JNIEnv* env, jclass cls); +extern int argcData; +extern const char **argvData; +void releaseArgv(); +int Java_org_libsdl_app_SDLActivity_nativeInit(JNIEnv* env, jclass cls, + jobject obj) { -int Java_org_libsdl_app_SDLActivity_nativeInit(JNIEnv* env, jclass cls, jobject obj) -{ - - SDL_Android_Init(env, cls); - - SDL_SetMainReady(); + SDL_Android_Init(env, cls); - -/* Run the application code! */ - - int status; - char *argv[2]; - argv[0] = SDL_strdup("openmw"); - argv[1] = NULL; - status = main(1, argv); + SDL_SetMainReady(); - /* Do not issue an exit or the whole application will terminate instead of just the SDL thread */ - /* exit(status); */ + /* Run the application code! */ - return status; + int status; + + status = main(argcData+1, argvData); + releaseArgv(); + /* Do not issue an exit or the whole application will terminate instead of just the SDL thread */ + /* exit(status); */ + + return status; } #endif /* __ANDROID__ */ diff --git a/apps/openmw/engine.cpp b/apps/openmw/engine.cpp index 669bae60a..a4bb8c538 100644 --- a/apps/openmw/engine.cpp +++ b/apps/openmw/engine.cpp @@ -10,6 +10,8 @@ #include +#include + #include #include @@ -191,15 +193,13 @@ OMW::Engine::Engine(Files::ConfigurationManager& configurationManager) , mExportFonts(false) , mNewGame (false) { - std::srand ( std::time(NULL) ); + OEngine::Misc::Rng::init(); + std::srand ( static_cast(std::time(NULL)) ); MWClass::registerClasses(); - Uint32 flags = SDL_INIT_VIDEO|SDL_INIT_NOPARACHUTE; + Uint32 flags = SDL_INIT_VIDEO|SDL_INIT_NOPARACHUTE|SDL_INIT_GAMECONTROLLER|SDL_INIT_JOYSTICK; if(SDL_WasInit(flags) == 0) { - //kindly ask SDL not to trash our OGL context - //might this be related to http://bugzilla.libsdl.org/show_bug.cgi?id=748 ? - SDL_SetHint(SDL_HINT_RENDER_DRIVER, "software"); SDL_SetMainReady(); if(SDL_Init(flags) != 0) { @@ -368,9 +368,29 @@ void OMW::Engine::prepareEngine (Settings::Manager & settings) // Create input and UI first to set up a bootstrapping environment for // showing a loading screen and keeping the window responsive while doing so - std::string keybinderUser = (mCfgMgr.getUserConfigPath() / "input_v2.xml").string(); + std::string keybinderUser = (mCfgMgr.getUserConfigPath() / "input_v3.xml").string(); bool keybinderUserExists = boost::filesystem::exists(keybinderUser); - MWInput::InputManager* input = new MWInput::InputManager (*mOgre, *this, keybinderUser, keybinderUserExists, mGrab); + if(!keybinderUserExists) + { + std::string input2 = (mCfgMgr.getUserConfigPath() / "input_v2.xml").string(); + if(boost::filesystem::exists(input2)) { + boost::filesystem::copy_file(input2, keybinderUser); + keybinderUserExists = boost::filesystem::exists(keybinderUser); + } + } + + // find correct path to the game controller bindings + const std::string localdefault = mCfgMgr.getLocalPath().string() + "/gamecontrollerdb.cfg"; + const std::string globaldefault = mCfgMgr.getGlobalPath().string() + "/gamecontrollerdb.cfg"; + std::string gameControllerdb; + if (boost::filesystem::exists(localdefault)) + gameControllerdb = localdefault; + else if (boost::filesystem::exists(globaldefault)) + gameControllerdb = globaldefault; + else + gameControllerdb = ""; //if it doesn't exist, pass in an empty string + + MWInput::InputManager* input = new MWInput::InputManager (*mOgre, *this, keybinderUser, keybinderUserExists, gameControllerdb, mGrab); mEnvironment.setInputManager (input); MWGui::WindowManager* window = new MWGui::WindowManager( diff --git a/apps/openmw/main.cpp b/apps/openmw/main.cpp index 82fda060e..070136dfd 100644 --- a/apps/openmw/main.cpp +++ b/apps/openmw/main.cpp @@ -290,7 +290,7 @@ public: std::streamsize write(const char *str, std::streamsize size) { // Make a copy for null termination - std::string tmp (str, size); + std::string tmp (str, static_cast(size)); // Write string to Visual Studio Debug output OutputDebugString (tmp.c_str ()); return size; diff --git a/apps/openmw/mwbase/inputmanager.hpp b/apps/openmw/mwbase/inputmanager.hpp index a53d8d9dc..79477d883 100644 --- a/apps/openmw/mwbase/inputmanager.hpp +++ b/apps/openmw/mwbase/inputmanager.hpp @@ -37,11 +37,23 @@ namespace MWBase virtual bool getControlSwitch (const std::string& sw) = 0; virtual std::string getActionDescription (int action) = 0; - virtual std::string getActionBindingName (int action) = 0; - virtual std::vector getActionSorting () = 0; + virtual std::string getActionKeyBindingName (int action) = 0; + virtual std::string getActionControllerBindingName (int action) = 0; + virtual std::string sdlControllerAxisToString(int axis) = 0; + virtual std::string sdlControllerButtonToString(int button) = 0; + ///Actions available for binding to keyboard buttons + virtual std::vector getActionKeySorting() = 0; + ///Actions available for binding to controller buttons + virtual std::vector getActionControllerSorting() = 0; virtual int getNumActions() = 0; - virtual void enableDetectingBindingMode (int action) = 0; - virtual void resetToDefaultBindings() = 0; + ///If keyboard is true, only pay attention to keyboard events. If false, only pay attention to controller events (excluding esc) + virtual void enableDetectingBindingMode (int action, bool keyboard) = 0; + virtual void resetToDefaultKeyBindings() = 0; + virtual void resetToDefaultControllerBindings() = 0; + + /// Returns if the last used input device was a joystick or a keyboard + /// @return true if joystick, false otherwise + virtual bool joystickLastUsed() = 0; }; } diff --git a/apps/openmw/mwbase/soundmanager.hpp b/apps/openmw/mwbase/soundmanager.hpp index f3381a8fd..e71558de0 100644 --- a/apps/openmw/mwbase/soundmanager.hpp +++ b/apps/openmw/mwbase/soundmanager.hpp @@ -20,7 +20,7 @@ namespace MWWorld namespace MWSound { class Sound; - class Sound_Decoder; + struct Sound_Decoder; typedef boost::shared_ptr DecoderPtr; } diff --git a/apps/openmw/mwbase/windowmanager.hpp b/apps/openmw/mwbase/windowmanager.hpp index 2c4cb360d..fdd51ef44 100644 --- a/apps/openmw/mwbase/windowmanager.hpp +++ b/apps/openmw/mwbase/windowmanager.hpp @@ -149,17 +149,14 @@ namespace MWBase /// \todo investigate, if we really need to expose every single lousy UI element to the outside world virtual MWGui::DialogueWindow* getDialogueWindow() = 0; - virtual MWGui::ContainerWindow* getContainerWindow() = 0; virtual MWGui::InventoryWindow* getInventoryWindow() = 0; - virtual MWGui::BookWindow* getBookWindow() = 0; - virtual MWGui::ScrollWindow* getScrollWindow() = 0; virtual MWGui::CountDialog* getCountDialog() = 0; virtual MWGui::ConfirmationDialog* getConfirmationDialog() = 0; virtual MWGui::TradeWindow* getTradeWindow() = 0; - virtual MWGui::SpellBuyingWindow* getSpellBuyingWindow() = 0; - virtual MWGui::TravelWindow* getTravelWindow() = 0; - virtual MWGui::SpellWindow* getSpellWindow() = 0; - virtual MWGui::Console* getConsole() = 0; + + virtual void updateSpellWindow() = 0; + + virtual void setConsoleSelectedObject(const MWWorld::Ptr& object) = 0; virtual void wmUpdateFps(float fps, unsigned int triangleCount, unsigned int batchCount) = 0; @@ -181,12 +178,6 @@ namespace MWBase virtual void configureSkills (const SkillList& major, const SkillList& minor) = 0; ///< configure skill groups, each set contains the skill ID for that group. - virtual void setReputation (int reputation) = 0; - ///< set the current reputation value - - virtual void setBounty (int bounty) = 0; - ///< set the current bounty value - virtual void updateSkillArea() = 0; ///< update display of skills, factions, birth sign, reputation and bounty @@ -303,6 +294,12 @@ namespace MWBase virtual void startTraining(MWWorld::Ptr actor) = 0; virtual void startRepair(MWWorld::Ptr actor) = 0; virtual void startRepairItem(MWWorld::Ptr item) = 0; + virtual void startTravel(const MWWorld::Ptr& actor) = 0; + virtual void startSpellBuying(const MWWorld::Ptr& actor) = 0; + virtual void startTrade(const MWWorld::Ptr& actor) = 0; + virtual void openContainer(const MWWorld::Ptr& container, bool loot) = 0; + virtual void showBook(const MWWorld::Ptr& item, bool showTakeButton) = 0; + virtual void showScroll(const MWWorld::Ptr& item, bool showTakeButton) = 0; virtual void showSoulgemDialog (MWWorld::Ptr item) = 0; @@ -332,9 +329,8 @@ namespace MWBase /// Does the current stack of GUI-windows permit saving? virtual bool isSavingAllowed() const = 0; - /// Returns the current Modal - /** Used to send exit command to active Modal when Esc is pressed **/ - virtual MWGui::WindowModal* getCurrentModal() const = 0; + /// Send exit command to active Modal window + virtual void exitCurrentModal() = 0; /// Sets the current Modal /** Used to send exit command to active Modal when Esc is pressed **/ diff --git a/apps/openmw/mwbase/world.hpp b/apps/openmw/mwbase/world.hpp index 8180d0b1a..9e6c6d9bf 100644 --- a/apps/openmw/mwbase/world.hpp +++ b/apps/openmw/mwbase/world.hpp @@ -49,7 +49,7 @@ namespace MWRender namespace MWMechanics { - class Movement; + struct Movement; } namespace MWWorld @@ -205,10 +205,8 @@ namespace MWBase ///< Return a pointer to a liveCellRef which contains \a ptr. /// \note Search is limited to the active cells. - /// \todo enable reference in the OGRE scene virtual void enable (const MWWorld::Ptr& ptr) = 0; - /// \todo disable reference in the OGRE scene virtual void disable (const MWWorld::Ptr& ptr) = 0; virtual void advanceTime (double hours) = 0; @@ -268,6 +266,8 @@ namespace MWBase virtual MWWorld::Ptr getFacedObject() = 0; ///< Return pointer to the object the player is looking at, if it is within activation range + virtual float getMaxActivationDistance() = 0; + /// Returns a pointer to the object the provided object would hit (if within the /// specified distance), and the point where the hit occurs. This will attempt to /// use the "Head" node, or alternatively the "Bip01 Head" node as a basis. @@ -551,7 +551,7 @@ namespace MWBase virtual void spawnEffect (const std::string& model, const std::string& textureOverride, const Ogre::Vector3& worldPos) = 0; virtual void explodeSpell (const Ogre::Vector3& origin, const ESM::EffectList& effects, - const MWWorld::Ptr& caster, int rangeType, const std::string& id, const std::string& sourceName) = 0; + const MWWorld::Ptr& caster, ESM::RangeType rangeType, const std::string& id, const std::string& sourceName) = 0; virtual void activate (const MWWorld::Ptr& object, const MWWorld::Ptr& actor) = 0; diff --git a/apps/openmw/mwclass/apparatus.cpp b/apps/openmw/mwclass/apparatus.cpp index 316ba3ab6..2abd071bd 100644 --- a/apps/openmw/mwclass/apparatus.cpp +++ b/apps/openmw/mwclass/apparatus.cpp @@ -155,7 +155,7 @@ namespace MWClass bool Apparatus::canSell (const MWWorld::Ptr& item, int npcServices) const { - return npcServices & ESM::NPC::Apparatus; + return (npcServices & ESM::NPC::Apparatus) != 0; } float Apparatus::getWeight(const MWWorld::Ptr &ptr) const diff --git a/apps/openmw/mwclass/armor.cpp b/apps/openmw/mwclass/armor.cpp index 64043157d..686f5af61 100644 --- a/apps/openmw/mwclass/armor.cpp +++ b/apps/openmw/mwclass/armor.cpp @@ -154,9 +154,9 @@ namespace MWClass const MWWorld::Store &gmst = MWBase::Environment::get().getWorld()->getStore().get(); - float iWeight = gmst.find (typeGmst)->getInt(); + float iWeight = floor(gmst.find(typeGmst)->getFloat()); - float epsilon = 5e-4; + float epsilon = 0.0005f; if (ref->mBase->mData.mWeight == 0) return ESM::Skill::Unarmored; @@ -245,7 +245,8 @@ namespace MWClass else typeText = "#{sHeavy}"; - text += "\n#{sArmorRating}: " + MWGui::ToolTips::toString(ref->mBase->mData.mArmor); + text += "\n#{sArmorRating}: " + MWGui::ToolTips::toString(getEffectiveArmorRating(ptr, + MWBase::Environment::get().getWorld()->getPlayerPtr())); int remainingHealth = getItemHealth(ptr); text += "\n#{sCondition}: " + MWGui::ToolTips::toString(remainingHealth) + "/" @@ -261,7 +262,7 @@ namespace MWClass info.enchant = ref->mBase->mEnchant; if (!info.enchant.empty()) - info.remainingEnchantCharge = ptr.getCellRef().getEnchantmentCharge(); + info.remainingEnchantCharge = static_cast(ptr.getCellRef().getEnchantmentCharge()); info.text = text; @@ -290,6 +291,22 @@ namespace MWClass return record->mId; } + int Armor::getEffectiveArmorRating(const MWWorld::Ptr &ptr, const MWWorld::Ptr &actor) const + { + MWWorld::LiveCellRef *ref = ptr.get(); + + int armorSkillType = getEquipmentSkill(ptr); + int armorSkill = actor.getClass().getSkill(actor, armorSkillType); + + const MWBase::World *world = MWBase::Environment::get().getWorld(); + int iBaseArmorSkill = world->getStore().get().find("iBaseArmorSkill")->getInt(); + + if(ref->mBase->mData.mWeight == 0) + return ref->mBase->mData.mArmor; + else + return ref->mBase->mData.mArmor * armorSkill / iBaseArmorSkill; + } + std::pair Armor::canBeEquipped(const MWWorld::Ptr &ptr, const MWWorld::Ptr &npc) const { MWWorld::InventoryStore& invStore = npc.getClass().getInventoryStore(npc); diff --git a/apps/openmw/mwclass/armor.hpp b/apps/openmw/mwclass/armor.hpp index 8c8e74cf4..21d711a0d 100644 --- a/apps/openmw/mwclass/armor.hpp +++ b/apps/openmw/mwclass/armor.hpp @@ -86,6 +86,9 @@ namespace MWClass virtual int getEnchantmentPoints (const MWWorld::Ptr& ptr) const; virtual bool canSell (const MWWorld::Ptr& item, int npcServices) const; + + /// Get the effective armor rating, factoring in the actor's skills, for the given armor. + virtual int getEffectiveArmorRating(const MWWorld::Ptr& ptr, const MWWorld::Ptr& actor) const; }; } diff --git a/apps/openmw/mwclass/clothing.cpp b/apps/openmw/mwclass/clothing.cpp index 0fa686dda..b387a3e9f 100644 --- a/apps/openmw/mwclass/clothing.cpp +++ b/apps/openmw/mwclass/clothing.cpp @@ -203,7 +203,7 @@ namespace MWClass info.enchant = ref->mBase->mEnchant; if (!info.enchant.empty()) - info.remainingEnchantCharge = ptr.getCellRef().getEnchantmentCharge(); + info.remainingEnchantCharge = static_cast(ptr.getCellRef().getEnchantmentCharge()); info.text = text; diff --git a/apps/openmw/mwclass/creature.cpp b/apps/openmw/mwclass/creature.cpp index e44f4ffc1..8404b9523 100644 --- a/apps/openmw/mwclass/creature.cpp +++ b/apps/openmw/mwclass/creature.cpp @@ -1,6 +1,8 @@ #include "creature.hpp" +#include + #include #include @@ -103,9 +105,9 @@ namespace MWClass data->mCreatureStats.setAttribute(ESM::Attribute::Endurance, ref->mBase->mData.mEndurance); data->mCreatureStats.setAttribute(ESM::Attribute::Personality, ref->mBase->mData.mPersonality); data->mCreatureStats.setAttribute(ESM::Attribute::Luck, ref->mBase->mData.mLuck); - data->mCreatureStats.setHealth (ref->mBase->mData.mHealth); - data->mCreatureStats.setMagicka (ref->mBase->mData.mMana); - data->mCreatureStats.setFatigue (ref->mBase->mData.mFatigue); + data->mCreatureStats.setHealth(static_cast(ref->mBase->mData.mHealth)); + data->mCreatureStats.setMagicka(static_cast(ref->mBase->mData.mMana)); + data->mCreatureStats.setFatigue(static_cast(ref->mBase->mData.mFatigue)); data->mCreatureStats.setLevel(ref->mBase->mData.mLevel); @@ -164,7 +166,7 @@ namespace MWClass MWWorld::LiveCellRef *ref = ptr.get(); MWRender::Actors& actors = renderingInterface.getActors(); - actors.insertCreature(ptr, model, ref->mBase->mFlags & ESM::Creature::Weapon); + actors.insertCreature(ptr, model, (ref->mBase->mFlags & ESM::Creature::Weapon) != 0); } void Creature::insertObject(const MWWorld::Ptr& ptr, const std::string& model, MWWorld::PhysicsSystem& physics) const @@ -249,7 +251,7 @@ namespace MWClass float hitchance = MWMechanics::getHitChance(ptr, victim, ref->mBase->mData.mCombat); - if((::rand()/(RAND_MAX+1.0)) > hitchance/100.0f) + if(OEngine::Misc::Rng::rollProbability() >= hitchance/100.0f) { victim.getClass().onHit(victim, 0.0f, false, MWWorld::Ptr(), ptr, false); MWMechanics::reduceWeaponCondition(0.f, false, weapon, ptr); @@ -288,9 +290,7 @@ namespace MWClass if(attack) { damage = attack[0] + ((attack[1]-attack[0])*stats.getAttackStrength()); - damage *= gmst.find("fDamageStrengthBase")->getFloat() + - (stats.getAttribute(ESM::Attribute::Strength).getModified() * gmst.find("fDamageStrengthMult")->getFloat() * 0.1); - MWMechanics::adjustWeaponDamage(damage, weapon); + MWMechanics::adjustWeaponDamage(damage, weapon, ptr); MWMechanics::reduceWeaponCondition(damage, true, weapon, ptr); } @@ -355,7 +355,7 @@ namespace MWClass if(!object.isEmpty()) getCreatureStats(ptr).setLastHitObject(object.getClass().getId(object)); - if(setOnPcHitMe && !attacker.isEmpty() && attacker.getRefData().getHandle() == "player") + if(setOnPcHitMe && !attacker.isEmpty() && attacker == MWBase::Environment::get().getWorld()->getPlayerPtr()) { const std::string &script = ptr.get()->mBase->mScript; /* Set the OnPCHitMe script variable. The script is responsible for clearing it. */ @@ -376,9 +376,8 @@ namespace MWClass // Check for knockdown float agilityTerm = getCreatureStats(ptr).getAttribute(ESM::Attribute::Agility).getModified() * getGmst().fKnockDownMult->getFloat(); float knockdownTerm = getCreatureStats(ptr).getAttribute(ESM::Attribute::Agility).getModified() - * getGmst().iKnockDownOddsMult->getInt() * 0.01 + getGmst().iKnockDownOddsBase->getInt(); - int roll = std::rand()/ (static_cast (RAND_MAX) + 1) * 100; // [0, 99] - if (ishealth && agilityTerm <= damage && knockdownTerm <= roll) + * getGmst().iKnockDownOddsMult->getInt() * 0.01f + getGmst().iKnockDownOddsBase->getInt(); + if (ishealth && agilityTerm <= damage && knockdownTerm <= OEngine::Misc::Rng::roll0to99()) { getCreatureStats(ptr).setKnockedDown(true); @@ -493,7 +492,7 @@ namespace MWClass { MWWorld::LiveCellRef *ref = ptr.get(); - return (ref->mBase->mFlags & ESM::Creature::Weapon); + return (ref->mBase->mFlags & ESM::Creature::Weapon) != 0; } std::string Creature::getScript (const MWWorld::Ptr& ptr) const @@ -508,7 +507,7 @@ namespace MWClass MWWorld::LiveCellRef *ref = ptr.get(); - return ref->mBase->mFlags & ESM::Creature::Essential; + return (ref->mBase->mFlags & ESM::Creature::Essential) != 0; } void Creature::registerSelf() @@ -528,7 +527,7 @@ namespace MWClass MWMechanics::CreatureStats& stats = getCreatureStats(ptr); const GMST& gmst = getGmst(); - float walkSpeed = gmst.fMinWalkSpeedCreature->getFloat() + 0.01 * stats.getAttribute(ESM::Attribute::Speed).getModified() + float walkSpeed = gmst.fMinWalkSpeedCreature->getFloat() + 0.01f * stats.getAttribute(ESM::Attribute::Speed).getModified() * (gmst.fMaxWalkSpeedCreature->getFloat() - gmst.fMinWalkSpeedCreature->getFloat()); const MWBase::World *world = MWBase::Environment::get().getWorld(); @@ -626,7 +625,7 @@ namespace MWClass float Creature::getCapacity (const MWWorld::Ptr& ptr) const { const MWMechanics::CreatureStats& stats = getCreatureStats (ptr); - return stats.getAttribute(0).getModified()*5; + return static_cast(stats.getAttribute(0).getModified() * 5); } float Creature::getEncumbrance (const MWWorld::Ptr& ptr) const @@ -682,7 +681,7 @@ namespace MWClass ++sound; } if(!sounds.empty()) - return sounds[(int)(rand()/(RAND_MAX+1.0)*sounds.size())]->mSound; + return sounds[OEngine::Misc::Rng::rollDice(sounds.size())]->mSound; } if (type == ESM::SoundGenerator::Land) @@ -713,7 +712,7 @@ namespace MWClass MWWorld::LiveCellRef *ref = ptr.get(); - return ref->mBase->mFlags & ESM::Creature::Flies; + return (ref->mBase->mFlags & ESM::Creature::Flies) != 0; } bool Creature::canSwim(const MWWorld::Ptr &ptr) const diff --git a/apps/openmw/mwclass/door.cpp b/apps/openmw/mwclass/door.cpp index 10b9b437d..2d39881b1 100644 --- a/apps/openmw/mwclass/door.cpp +++ b/apps/openmw/mwclass/door.cpp @@ -167,19 +167,19 @@ namespace MWClass if (opening) { MWBase::Environment::get().getSoundManager()->fadeOutSound3D(ptr, - closeSound, 0.5); - float offset = ptr.getRefData().getLocalRotation().rot[2]/ 3.14159265 * 2.0; + closeSound, 0.5f); + float offset = ptr.getRefData().getLocalRotation().rot[2]/ 3.14159265f * 2.0f; action->setSoundOffset(offset); action->setSound(openSound); } else { MWBase::Environment::get().getSoundManager()->fadeOutSound3D(ptr, - openSound, 0.5); - float offset = 1.0 - ptr.getRefData().getLocalRotation().rot[2]/ 3.14159265 * 2.0; + openSound, 0.5f); + float offset = 1.0f - ptr.getRefData().getLocalRotation().rot[2]/ 3.14159265f * 2.0f; //most if not all door have closing bang somewhere in the middle of the sound, //so we divide offset by two - action->setSoundOffset(offset * 0.5); + action->setSoundOffset(offset * 0.5f); action->setSound(closeSound); } diff --git a/apps/openmw/mwclass/ingredient.cpp b/apps/openmw/mwclass/ingredient.cpp index 9f662a60e..de43e818e 100644 --- a/apps/openmw/mwclass/ingredient.cpp +++ b/apps/openmw/mwclass/ingredient.cpp @@ -192,7 +192,7 @@ namespace MWClass bool Ingredient::canSell (const MWWorld::Ptr& item, int npcServices) const { - return npcServices & ESM::NPC::Ingredients; + return (npcServices & ESM::NPC::Ingredients) != 0; } diff --git a/apps/openmw/mwclass/light.cpp b/apps/openmw/mwclass/light.cpp index 35a21b63e..90c708f97 100644 --- a/apps/openmw/mwclass/light.cpp +++ b/apps/openmw/mwclass/light.cpp @@ -50,7 +50,7 @@ namespace MWClass assert (ref->mBase != NULL); if(!model.empty()) - physics.addObject(ptr, model, ref->mBase->mData.mFlags & ESM::Light::Carry); + physics.addObject(ptr, model, (ref->mBase->mData.mFlags & ESM::Light::Carry) != 0); if (!ref->mBase->mSound.empty() && !(ref->mBase->mData.mFlags & ESM::Light::OffDefault)) MWBase::Environment::get().getSoundManager()->playSound3D(ptr, ref->mBase->mSound, 1.0, 1.0, @@ -205,7 +205,7 @@ namespace MWClass { MWWorld::LiveCellRef *ref = ptr.get(); if (ptr.getCellRef().getCharge() == -1) - return ref->mBase->mData.mTime; + return static_cast(ref->mBase->mData.mTime); else return ptr.getCellRef().getChargeFloat(); } @@ -221,7 +221,7 @@ namespace MWClass bool Light::canSell (const MWWorld::Ptr& item, int npcServices) const { - return npcServices & ESM::NPC::Lights; + return (npcServices & ESM::NPC::Lights) != 0; } float Light::getWeight(const MWWorld::Ptr &ptr) const diff --git a/apps/openmw/mwclass/lockpick.cpp b/apps/openmw/mwclass/lockpick.cpp index e78c43eee..478c50301 100644 --- a/apps/openmw/mwclass/lockpick.cpp +++ b/apps/openmw/mwclass/lockpick.cpp @@ -173,7 +173,7 @@ namespace MWClass bool Lockpick::canSell (const MWWorld::Ptr& item, int npcServices) const { - return npcServices & ESM::NPC::Picks; + return (npcServices & ESM::NPC::Picks) != 0; } int Lockpick::getItemMaxHealth (const MWWorld::Ptr& ptr) const diff --git a/apps/openmw/mwclass/misc.cpp b/apps/openmw/mwclass/misc.cpp index f9cfd8e0b..f5daafeec 100644 --- a/apps/openmw/mwclass/misc.cpp +++ b/apps/openmw/mwclass/misc.cpp @@ -259,7 +259,7 @@ namespace MWClass { MWWorld::LiveCellRef *ref = ptr.get(); - return ref->mBase->mData.mIsKey; + return ref->mBase->mData.mIsKey != 0; } } diff --git a/apps/openmw/mwclass/npc.cpp b/apps/openmw/mwclass/npc.cpp index cedff1291..1d58dc87e 100644 --- a/apps/openmw/mwclass/npc.cpp +++ b/apps/openmw/mwclass/npc.cpp @@ -5,6 +5,8 @@ #include +#include + #include #include #include @@ -66,12 +68,12 @@ namespace double i = floor(d); d -= i; if(d < 0.5) - return i; + return static_cast(i); if(d > 0.5) - return i + 1.0; + return static_cast(i) + 1; if(is_even(i)) - return i; - return i + 1.0; + return static_cast(i); + return static_cast(i) + 1; } void autoCalculateAttributes (const ESM::NPC* npc, MWMechanics::CreatureStats& creatureStats) @@ -116,7 +118,7 @@ namespace continue; // is this a minor or major skill? - float add=0.2; + float add=0.2f; for (int k=0; k<5; ++k) { if (class_->mData.mSkills[k][0] == j) @@ -149,7 +151,7 @@ namespace || class_->mData.mAttribute[1] == ESM::Attribute::Endurance) multiplier += 1; - creatureStats.setHealth(static_cast (0.5 * (strength + endurance)) + multiplier * (creatureStats.getLevel() - 1)); + creatureStats.setHealth(floor(0.5f * (strength + endurance)) + multiplier * (creatureStats.getLevel() - 1)); } /** @@ -279,8 +281,6 @@ namespace MWClass gmst.fKnockDownMult = store.find("fKnockDownMult"); gmst.iKnockDownOddsMult = store.find("iKnockDownOddsMult"); gmst.iKnockDownOddsBase = store.find("iKnockDownOddsBase"); - gmst.fDamageStrengthBase = store.find("fDamageStrengthBase"); - gmst.fDamageStrengthMult = store.find("fDamageStrengthMult"); gmst.fCombatArmorMinMult = store.find("fCombatArmorMinMult"); inited = true; @@ -475,7 +475,6 @@ namespace MWClass void Npc::hit(const MWWorld::Ptr& ptr, int type) const { MWBase::World *world = MWBase::Environment::get().getWorld(); - const GMST& gmst = getGmst(); const MWWorld::Store &store = world->getStore().get(); @@ -507,7 +506,7 @@ namespace MWClass if(otherstats.isDead()) // Can't hit dead actors return; - if(ptr.getRefData().getHandle() == "player") + if(ptr == MWBase::Environment::get().getWorld()->getPlayerPtr()) MWBase::Environment::get().getWindowManager()->setEnemy(victim); int weapskill = ESM::Skill::HandToHand; @@ -516,7 +515,7 @@ namespace MWClass float hitchance = MWMechanics::getHitChance(ptr, victim, ptr.getClass().getSkill(ptr, weapskill)); - if((::rand()/(RAND_MAX+1.0)) > hitchance/100.0f) + if (OEngine::Misc::Rng::rollProbability() >= hitchance / 100.0f) { othercls.onHit(victim, 0.0f, false, weapon, ptr, false); MWMechanics::reduceWeaponCondition(0.f, false, weapon, ptr); @@ -538,10 +537,8 @@ namespace MWClass if(attack) { damage = attack[0] + ((attack[1]-attack[0])*stats.getAttackStrength()); - damage *= gmst.fDamageStrengthBase->getFloat() + - (stats.getAttribute(ESM::Attribute::Strength).getModified() * gmst.fDamageStrengthMult->getFloat() * 0.1); } - MWMechanics::adjustWeaponDamage(damage, weapon); + MWMechanics::adjustWeaponDamage(damage, weapon, ptr); MWMechanics::reduceWeaponCondition(damage, true, weapon, ptr); healthdmg = true; } @@ -549,7 +546,7 @@ namespace MWClass { MWMechanics::getHandToHandDamage(ptr, victim, damage, healthdmg); } - if(ptr.getRefData().getHandle() == "player") + if(ptr == MWBase::Environment::get().getWorld()->getPlayerPtr()) { skillUsageSucceeded(ptr, weapskill, 0); @@ -625,7 +622,7 @@ namespace MWClass if(!object.isEmpty()) getCreatureStats(ptr).setLastHitObject(object.getClass().getId(object)); - if(setOnPcHitMe && !attacker.isEmpty() && attacker.getRefData().getHandle() == "player") + if(setOnPcHitMe && !attacker.isEmpty() && attacker == MWBase::Environment::get().getWorld()->getPlayerPtr()) { const std::string &script = ptr.getClass().getScript(ptr); /* Set the OnPCHitMe script variable. The script is responsible for clearing it. */ @@ -648,8 +645,7 @@ namespace MWClass const GMST& gmst = getGmst(); int chance = store.get().find("iVoiceHitOdds")->getInt(); - int roll = std::rand()/ (static_cast (RAND_MAX) + 1) * 100; // [0, 99] - if (roll < chance) + if (OEngine::Misc::Rng::roll0to99() < chance) { MWBase::Environment::get().getDialogueManager()->say(ptr, "hit"); } @@ -657,9 +653,8 @@ namespace MWClass // Check for knockdown float agilityTerm = getCreatureStats(ptr).getAttribute(ESM::Attribute::Agility).getModified() * gmst.fKnockDownMult->getFloat(); float knockdownTerm = getCreatureStats(ptr).getAttribute(ESM::Attribute::Agility).getModified() - * gmst.iKnockDownOddsMult->getInt() * 0.01 + gmst.iKnockDownOddsBase->getInt(); - roll = std::rand()/ (static_cast (RAND_MAX) + 1) * 100; // [0, 99] - if (ishealth && agilityTerm <= damage && knockdownTerm <= roll) + * gmst.iKnockDownOddsMult->getInt() * 0.01f + gmst.iKnockDownOddsBase->getInt(); + if (ishealth && agilityTerm <= damage && knockdownTerm <= OEngine::Misc::Rng::roll0to99()) { getCreatureStats(ptr).setKnockedDown(true); @@ -685,12 +680,12 @@ namespace MWClass MWWorld::InventoryStore::Slot_RightPauldron, MWWorld::InventoryStore::Slot_RightPauldron, MWWorld::InventoryStore::Slot_LeftGauntlet, MWWorld::InventoryStore::Slot_RightGauntlet }; - int hitslot = hitslots[(int)(::rand()/(RAND_MAX+1.0)*20.0)]; + int hitslot = hitslots[OEngine::Misc::Rng::rollDice(20)]; float unmitigatedDamage = damage; float x = damage / (damage + getArmorRating(ptr)); damage *= std::max(gmst.fCombatArmorMinMult->getFloat(), x); - int damageDiff = unmitigatedDamage - damage; + int damageDiff = static_cast(unmitigatedDamage - damage); if (damage < 1) damage = 1; @@ -708,7 +703,7 @@ namespace MWClass if (armorhealth == 0) armor = *inv.unequipItem(armor, ptr); - if (ptr.getRefData().getHandle() == "player") + if (ptr == MWBase::Environment::get().getWorld()->getPlayerPtr()) skillUsageSucceeded(ptr, armor.getClass().getEquipmentSkill(armor), 0); switch(armor.getClass().getEquipmentSkill(armor)) @@ -724,7 +719,7 @@ namespace MWClass break; } } - else if(ptr.getRefData().getHandle() == "player") + else if(ptr == MWBase::Environment::get().getWorld()->getPlayerPtr()) skillUsageSucceeded(ptr, ESM::Skill::Unarmored, 0); } } @@ -737,7 +732,7 @@ namespace MWClass if(damage > 0.0f) { sndMgr->playSound3D(ptr, "Health Damage", 1.0f, 1.0f); - if (ptr.getRefData().getHandle() == "player") + if (ptr == MWBase::Environment::get().getWorld()->getPlayerPtr()) MWBase::Environment::get().getWindowManager()->activateHitOverlay(); } float health = getCreatureStats(ptr).getHealth().getCurrent() - damage; @@ -815,7 +810,7 @@ namespace MWClass const MWWorld::Ptr& actor) const { // player got activated by another NPC - if(ptr.getRefData().getHandle() == "player") + if(ptr == MWBase::Environment::get().getWorld()->getPlayerPtr()) return boost::shared_ptr(new MWWorld::ActionTalk(actor)); // Werewolfs can't activate NPCs @@ -938,7 +933,7 @@ namespace MWClass gmst.fJumpEncumbranceMultiplier->getFloat() * (1.0f - Npc::getEncumbrance(ptr)/Npc::getCapacity(ptr)); - float a = npcdata->mNpcStats.getSkill(ESM::Skill::Acrobatics).getModified(); + float a = static_cast(npcdata->mNpcStats.getSkill(ESM::Skill::Acrobatics).getModified()); float b = 0.0f; if(a > 50.0f) { @@ -993,7 +988,7 @@ namespace MWClass MWWorld::LiveCellRef *ref = ptr.get(); - return ref->mBase->mFlags & ESM::NPC::Essential; + return (ref->mBase->mFlags & ESM::NPC::Essential) != 0; } void Npc::registerSelf() @@ -1086,7 +1081,6 @@ namespace MWClass MWMechanics::NpcStats &stats = getNpcStats(ptr); MWWorld::InventoryStore &invStore = getInventoryStore(ptr); - int iBaseArmorSkill = store.find("iBaseArmorSkill")->getInt(); float fUnarmoredBase1 = store.find("fUnarmoredBase1")->getFloat(); float fUnarmoredBase2 = store.find("fUnarmoredBase2")->getFloat(); int unarmoredSkill = stats.getSkill(ESM::Skill::Unarmored).getModified(); @@ -1098,19 +1092,11 @@ namespace MWClass if (it == invStore.end() || it->getTypeName() != typeid(ESM::Armor).name()) { // unarmored - ratings[i] = (fUnarmoredBase1 * unarmoredSkill) * (fUnarmoredBase2 * unarmoredSkill); + ratings[i] = static_cast((fUnarmoredBase1 * unarmoredSkill) * (fUnarmoredBase2 * unarmoredSkill)); } else { - MWWorld::LiveCellRef *ref = it->get(); - - int armorSkillType = it->getClass().getEquipmentSkill(*it); - int armorSkill = stats.getSkill(armorSkillType).getModified(); - - if(ref->mBase->mData.mWeight == 0) - ratings[i] = ref->mBase->mData.mArmor; - else - ratings[i] = ref->mBase->mData.mArmor * armorSkill / iBaseArmorSkill; + ratings[i] = it->getClass().getEffectiveArmorRating(*it, ptr); } } diff --git a/apps/openmw/mwclass/npc.hpp b/apps/openmw/mwclass/npc.hpp index 9aece7368..27beeb626 100644 --- a/apps/openmw/mwclass/npc.hpp +++ b/apps/openmw/mwclass/npc.hpp @@ -5,7 +5,7 @@ namespace ESM { - class GameSetting; + struct GameSetting; } namespace MWClass @@ -38,8 +38,6 @@ namespace MWClass const ESM::GameSetting *fKnockDownMult; const ESM::GameSetting *iKnockDownOddsMult; const ESM::GameSetting *iKnockDownOddsBase; - const ESM::GameSetting *fDamageStrengthBase; - const ESM::GameSetting *fDamageStrengthMult; const ESM::GameSetting *fCombatArmorMinMult; }; diff --git a/apps/openmw/mwclass/potion.cpp b/apps/openmw/mwclass/potion.cpp index bd06f89fc..ee299ab4f 100644 --- a/apps/openmw/mwclass/potion.cpp +++ b/apps/openmw/mwclass/potion.cpp @@ -185,7 +185,7 @@ namespace MWClass bool Potion::canSell (const MWWorld::Ptr& item, int npcServices) const { - return npcServices & ESM::NPC::Potions; + return (npcServices & ESM::NPC::Potions) != 0; } float Potion::getWeight(const MWWorld::Ptr &ptr) const diff --git a/apps/openmw/mwclass/probe.cpp b/apps/openmw/mwclass/probe.cpp index a11725f26..da22e9be6 100644 --- a/apps/openmw/mwclass/probe.cpp +++ b/apps/openmw/mwclass/probe.cpp @@ -172,7 +172,7 @@ namespace MWClass bool Probe::canSell (const MWWorld::Ptr& item, int npcServices) const { - return npcServices & ESM::NPC::Probes; + return (npcServices & ESM::NPC::Probes) != 0; } int Probe::getItemMaxHealth (const MWWorld::Ptr& ptr) const diff --git a/apps/openmw/mwclass/repair.cpp b/apps/openmw/mwclass/repair.cpp index e9c4ac9b1..c02146f12 100644 --- a/apps/openmw/mwclass/repair.cpp +++ b/apps/openmw/mwclass/repair.cpp @@ -172,7 +172,7 @@ namespace MWClass bool Repair::canSell (const MWWorld::Ptr& item, int npcServices) const { - return npcServices & ESM::NPC::RepairItem; + return (npcServices & ESM::NPC::RepairItem) != 0; } float Repair::getWeight(const MWWorld::Ptr &ptr) const diff --git a/apps/openmw/mwclass/weapon.cpp b/apps/openmw/mwclass/weapon.cpp index d1a44fd0e..a484ad668 100644 --- a/apps/openmw/mwclass/weapon.cpp +++ b/apps/openmw/mwclass/weapon.cpp @@ -345,7 +345,7 @@ namespace MWClass info.enchant = ref->mBase->mEnchant; if (!info.enchant.empty()) - info.remainingEnchantCharge = ptr.getCellRef().getEnchantmentCharge(); + info.remainingEnchantCharge = static_cast(ptr.getCellRef().getEnchantmentCharge()); if (MWBase::Environment::get().getWindowManager()->getFullHelp()) { text += MWGui::ToolTips::getCellRefString(ptr.getCellRef()); diff --git a/apps/openmw/mwdialogue/dialoguemanagerimp.cpp b/apps/openmw/mwdialogue/dialoguemanagerimp.cpp index 1d1f655aa..b928738dd 100644 --- a/apps/openmw/mwdialogue/dialoguemanagerimp.cpp +++ b/apps/openmw/mwdialogue/dialoguemanagerimp.cpp @@ -179,10 +179,7 @@ namespace MWDialogue bool isCompanion = !mActor.getClass().getScript(mActor).empty() && mActor.getRefData().getLocals().getIntVar(mActor.getClass().getScript(mActor), "companion"); if (isCompanion) - { - MWBase::Environment::get().getWindowManager()->pushGuiMode(MWGui::GM_Companion); MWBase::Environment::get().getWindowManager()->showCompanionWindow(mActor); - } } bool DialogueManager::compile (const std::string& cmd,std::vector& code) @@ -383,7 +380,8 @@ namespace MWDialogue || services & ESM::NPC::Misc) windowServices |= MWGui::DialogueWindow::Service_Trade; - if(mActor.getTypeName() == typeid(ESM::NPC).name() && !mActor.get()->mBase->mTransport.empty()) + if((mActor.getTypeName() == typeid(ESM::NPC).name() && !mActor.get()->mBase->getTransport().empty()) + || (mActor.getTypeName() == typeid(ESM::Creature).name() && !mActor.get()->mBase->getTransport().empty())) windowServices |= MWGui::DialogueWindow::Service_Travel; if (services & ESM::NPC::Spells) @@ -444,7 +442,7 @@ namespace MWDialogue if (mActor.getClass().isNpc()) { MWMechanics::NpcStats& npcStats = mActor.getClass().getNpcStats(mActor); - npcStats.setBaseDisposition(npcStats.getBaseDisposition() + mPermanentDispositionChange); + npcStats.setBaseDisposition(static_cast(npcStats.getBaseDisposition() + mPermanentDispositionChange)); } mPermanentDispositionChange = 0; mTemporaryDispositionChange = 0; @@ -521,7 +519,7 @@ namespace MWDialogue mPermanentDispositionChange += perm; // change temp disposition so that final disposition is between 0...100 - int curDisp = MWBase::Environment::get().getMechanicsManager()->getDerivedDisposition(mActor); + float curDisp = static_cast(MWBase::Environment::get().getMechanicsManager()->getDerivedDisposition(mActor)); if (curDisp + mTemporaryDispositionChange < 0) mTemporaryDispositionChange = -curDisp; else if (curDisp + mTemporaryDispositionChange > 100) @@ -564,7 +562,7 @@ namespace MWDialogue int DialogueManager::getTemporaryDispositionChange() const { - return mTemporaryDispositionChange; + return static_cast(mTemporaryDispositionChange); } void DialogueManager::applyDispositionChange(int delta) diff --git a/apps/openmw/mwgui/backgroundimage.cpp b/apps/openmw/mwgui/backgroundimage.cpp index 9c07c5780..ee966c189 100644 --- a/apps/openmw/mwgui/backgroundimage.cpp +++ b/apps/openmw/mwgui/backgroundimage.cpp @@ -41,8 +41,8 @@ void BackgroundImage::adjustSize() MyGUI::IntSize screenSize = getSize(); - int leftPadding = std::max(0.0, (screenSize.width - screenSize.height * mAspect) / 2); - int topPadding = std::max(0.0, (screenSize.height - screenSize.width / mAspect) / 2); + int leftPadding = std::max(0, static_cast(screenSize.width - screenSize.height * mAspect) / 2); + int topPadding = std::max(0, static_cast(screenSize.height - screenSize.width / mAspect) / 2); mChild->setCoord(leftPadding, topPadding, screenSize.width - leftPadding*2, screenSize.height - topPadding*2); } diff --git a/apps/openmw/mwgui/bookpage.cpp b/apps/openmw/mwgui/bookpage.cpp index c9cfc8c2c..962e594ae 100644 --- a/apps/openmw/mwgui/bookpage.cpp +++ b/apps/openmw/mwgui/bookpage.cpp @@ -16,8 +16,8 @@ namespace MWGui { struct TypesetBookImpl; -struct PageDisplay; -struct BookPageImpl; +class PageDisplay; +class BookPageImpl; static bool ucsSpace (int codePoint); static bool ucsLineBreak (int codePoint); @@ -326,7 +326,7 @@ struct TypesetBookImpl::Typesetter : BookTypesetter mLine = NULL; } - void sectionBreak (float margin) + void sectionBreak (int margin) { add_partial_text(); @@ -465,7 +465,7 @@ struct TypesetBookImpl::Typesetter : BookTypesetter { MyGUI::GlyphInfo* gi = style->mFont->getGlyphInfo (stream.peek ()); if (gi) - space_width += gi->advance + gi->bearingX; + space_width += static_cast(gi->advance + gi->bearingX); stream.consume (); } @@ -475,7 +475,7 @@ struct TypesetBookImpl::Typesetter : BookTypesetter { MyGUI::GlyphInfo* gi = style->mFont->getGlyphInfo (stream.peek ()); if (gi) - word_width += gi->advance + gi->bearingX; + word_width += static_cast(gi->advance + gi->bearingX); stream.consume (); } @@ -623,15 +623,15 @@ namespace RenderXform (MyGUI::ICroppedRectangle* croppedParent, MyGUI::RenderTargetInfo const & renderTargetInfo) { - clipTop = croppedParent->_getMarginTop (); - clipLeft = croppedParent->_getMarginLeft (); - clipRight = croppedParent->getWidth () - croppedParent->_getMarginRight (); - clipBottom = croppedParent->getHeight () - croppedParent->_getMarginBottom (); + clipTop = static_cast(croppedParent->_getMarginTop()); + clipLeft = static_cast(croppedParent->_getMarginLeft ()); + clipRight = static_cast(croppedParent->getWidth () - croppedParent->_getMarginRight ()); + clipBottom = static_cast(croppedParent->getHeight() - croppedParent->_getMarginBottom()); - absoluteLeft = croppedParent->getAbsoluteLeft(); - absoluteTop = croppedParent->getAbsoluteTop(); - leftOffset = renderTargetInfo.leftOffset; - topOffset = renderTargetInfo.topOffset; + absoluteLeft = static_cast(croppedParent->getAbsoluteLeft()); + absoluteTop = static_cast(croppedParent->getAbsoluteTop()); + leftOffset = static_cast(renderTargetInfo.leftOffset); + topOffset = static_cast(renderTargetInfo.topOffset); pixScaleX = renderTargetInfo.pixScaleX; pixScaleY = renderTargetInfo.pixScaleY; @@ -1136,7 +1136,7 @@ public: MyGUI::Colour colour = isActive ? (this_->mItemActive ? run.mStyle->mActiveColour: run.mStyle->mHotColour) : run.mStyle->mNormalColour; - glyphStream.reset (section.mRect.left + line.mRect.left + run.mLeft, line.mRect.top, colour); + glyphStream.reset(static_cast(section.mRect.left + line.mRect.left + run.mLeft), static_cast(line.mRect.top), colour); Utf8Stream stream (run.mRange); @@ -1164,7 +1164,7 @@ public: RenderXform renderXform (mCroppedParent, textFormat.mRenderItem->getRenderTarget()->getInfo()); - GlyphStream glyphStream (textFormat.mFont, mCoord.left, mCoord.top-mViewTop, + GlyphStream glyphStream(textFormat.mFont, static_cast(mCoord.left), static_cast(mCoord.top - mViewTop), -1 /*mNode->getNodeDepth()*/, vertices, renderXform); int visit_top = (std::max) (mViewTop, mViewTop + int (renderXform.clipTop )); diff --git a/apps/openmw/mwgui/bookpage.hpp b/apps/openmw/mwgui/bookpage.hpp index 458cf2a19..c7340ec7c 100644 --- a/apps/openmw/mwgui/bookpage.hpp +++ b/apps/openmw/mwgui/bookpage.hpp @@ -71,7 +71,7 @@ namespace MWGui /// to begin when additional text is inserted. Pagination attempts to keep /// sections together on a single page. The margin parameter adds additional space /// before the next line of text. - virtual void sectionBreak (float margin = 0) = 0; + virtual void sectionBreak (int margin = 0) = 0; /// Changes the alignment for the current section of text. virtual void setSectionAlignment (Alignment sectionAlignment) = 0; diff --git a/apps/openmw/mwgui/bookwindow.cpp b/apps/openmw/mwgui/bookwindow.cpp index da0d1950e..55a9b6191 100644 --- a/apps/openmw/mwgui/bookwindow.cpp +++ b/apps/openmw/mwgui/bookwindow.cpp @@ -73,7 +73,7 @@ namespace MWGui mPages.clear(); } - void BookWindow::open (MWWorld::Ptr book) + void BookWindow::open (MWWorld::Ptr book, bool showTakeButton) { mBook = book; @@ -90,7 +90,7 @@ namespace MWGui updatePages(); - setTakeButtonShow(true); + setTakeButtonShow(showTakeButton); } void BookWindow::exit() diff --git a/apps/openmw/mwgui/bookwindow.hpp b/apps/openmw/mwgui/bookwindow.hpp index ea3057a6f..8ad4f6830 100644 --- a/apps/openmw/mwgui/bookwindow.hpp +++ b/apps/openmw/mwgui/bookwindow.hpp @@ -16,10 +16,7 @@ namespace MWGui virtual void exit(); - void open(MWWorld::Ptr book); - void setTakeButtonShow(bool show); - void nextPage(); - void prevPage(); + void open(MWWorld::Ptr book, bool showTakeButton); void setInventoryAllowed(bool allowed); protected: @@ -28,6 +25,10 @@ namespace MWGui void onCloseButtonClicked (MyGUI::Widget* sender); void onTakeButtonClicked (MyGUI::Widget* sender); void onMouseWheel(MyGUI::Widget* _sender, int _rel); + void setTakeButtonShow(bool show); + + void nextPage(); + void prevPage(); void updatePages(); void clearPages(); diff --git a/apps/openmw/mwgui/charactercreation.cpp b/apps/openmw/mwgui/charactercreation.cpp index ab412f63b..fb00d6a98 100644 --- a/apps/openmw/mwgui/charactercreation.cpp +++ b/apps/openmw/mwgui/charactercreation.cpp @@ -330,20 +330,7 @@ namespace MWGui updatePlayerHealth(); - //TODO This bit gets repeated a few times; wrap it in a function - MWBase::Environment::get().getWindowManager()->popGuiMode(); - if (mCreationStage == CSE_ReviewNext) - { - MWBase::Environment::get().getWindowManager()->pushGuiMode(GM_Review); - } - else if (mCreationStage >= CSE_ClassChosen) - { - MWBase::Environment::get().getWindowManager()->pushGuiMode(GM_Birth); - } - else - { - mCreationStage = CSE_ClassChosen; - } + handleDialogDone(CSE_ClassChosen, GM_Birth); } void CharacterCreation::onPickClassDialogBack() @@ -397,19 +384,7 @@ namespace MWGui mNameDialog = 0; } - MWBase::Environment::get().getWindowManager()->popGuiMode(); - if (mCreationStage == CSE_ReviewNext) - { - MWBase::Environment::get().getWindowManager()->pushGuiMode(GM_Review); - } - else if (mCreationStage >= CSE_NameChosen) - { - MWBase::Environment::get().getWindowManager()->pushGuiMode(GM_Race); - } - else - { - mCreationStage = CSE_NameChosen; - } + handleDialogDone(CSE_NameChosen, GM_Race); } void CharacterCreation::onRaceDialogBack() @@ -456,19 +431,7 @@ namespace MWGui updatePlayerHealth(); - MWBase::Environment::get().getWindowManager()->popGuiMode(); - if (mCreationStage == CSE_ReviewNext) - { - MWBase::Environment::get().getWindowManager()->pushGuiMode(GM_Review); - } - else if (mCreationStage >= CSE_RaceChosen) - { - MWBase::Environment::get().getWindowManager()->pushGuiMode(GM_Class); - } - else - { - mCreationStage = CSE_RaceChosen; - } + handleDialogDone(CSE_RaceChosen, GM_Class); } void CharacterCreation::onBirthSignDialogDone(WindowBase* parWindow) @@ -484,15 +447,7 @@ namespace MWGui updatePlayerHealth(); - MWBase::Environment::get().getWindowManager()->popGuiMode(); - if (mCreationStage >= CSE_BirthSignChosen) - { - MWBase::Environment::get().getWindowManager()->pushGuiMode(GM_Review); - } - else - { - mCreationStage = CSE_BirthSignChosen; - } + handleDialogDone(CSE_BirthSignChosen, GM_Review); } void CharacterCreation::onBirthSignDialogBack() @@ -543,19 +498,7 @@ namespace MWGui updatePlayerHealth(); - MWBase::Environment::get().getWindowManager()->popGuiMode(); - if (mCreationStage == CSE_ReviewNext) - { - MWBase::Environment::get().getWindowManager()->pushGuiMode(GM_Review); - } - else if (mCreationStage >= CSE_ClassChosen) - { - MWBase::Environment::get().getWindowManager()->pushGuiMode(GM_Birth); - } - else - { - mCreationStage = CSE_ClassChosen; - } + handleDialogDone(CSE_ClassChosen, GM_Birth); } void CharacterCreation::onCreateClassDialogBack() @@ -711,19 +654,7 @@ namespace MWGui updatePlayerHealth(); - MWBase::Environment::get().getWindowManager()->popGuiMode(); - if (mCreationStage == CSE_ReviewNext) - { - MWBase::Environment::get().getWindowManager()->pushGuiMode(GM_Review); - } - else if (mCreationStage >= CSE_ClassChosen) - { - MWBase::Environment::get().getWindowManager()->pushGuiMode(GM_Birth); - } - else - { - mCreationStage = CSE_ClassChosen; - } + handleDialogDone(CSE_ClassChosen, GM_Birth); } CharacterCreation::~CharacterCreation() @@ -739,4 +670,20 @@ namespace MWGui delete mReviewDialog; } + void CharacterCreation::handleDialogDone(CSE currentStage, int nextMode) + { + MWBase::Environment::get().getWindowManager()->popGuiMode(); + if (mCreationStage == CSE_ReviewNext) + { + MWBase::Environment::get().getWindowManager()->pushGuiMode(GM_Review); + } + else if (mCreationStage >= currentStage) + { + MWBase::Environment::get().getWindowManager()->pushGuiMode((GuiMode)nextMode); + } + else + { + mCreationStage = currentStage; + } + } } diff --git a/apps/openmw/mwgui/charactercreation.hpp b/apps/openmw/mwgui/charactercreation.hpp index c2486c7f0..a4515569d 100644 --- a/apps/openmw/mwgui/charactercreation.hpp +++ b/apps/openmw/mwgui/charactercreation.hpp @@ -104,6 +104,8 @@ namespace MWGui }; CSE mCreationStage; // Which state the character creating is in, controls back/next/ok buttons + + void handleDialogDone(CSE currentStage, int nextMode); }; } diff --git a/apps/openmw/mwgui/companionwindow.cpp b/apps/openmw/mwgui/companionwindow.cpp index 8f709ec8d..fe47437ca 100644 --- a/apps/openmw/mwgui/companionwindow.cpp +++ b/apps/openmw/mwgui/companionwindow.cpp @@ -129,7 +129,7 @@ void CompanionWindow::updateEncumbranceBar() return; float capacity = mPtr.getClass().getCapacity(mPtr); float encumbrance = mPtr.getClass().getEncumbrance(mPtr); - mEncumbranceBar->setValue(encumbrance, capacity); + mEncumbranceBar->setValue(static_cast(encumbrance), static_cast(capacity)); if (mModel && mModel->hasProfit(mPtr)) { diff --git a/apps/openmw/mwgui/controllers.cpp b/apps/openmw/mwgui/controllers.cpp index ad804997a..72f2eb7f3 100644 --- a/apps/openmw/mwgui/controllers.cpp +++ b/apps/openmw/mwgui/controllers.cpp @@ -9,8 +9,8 @@ namespace MWGui { ControllerRepeatEvent::ControllerRepeatEvent() : - mInit(0.5), - mStep(0.1), + mInit(0.5f), + mStep(0.1f), mEnabled(true), mTimeLeft(0) { diff --git a/apps/openmw/mwgui/dialogue.cpp b/apps/openmw/mwgui/dialogue.cpp index eee86c6d2..1b07522f3 100644 --- a/apps/openmw/mwgui/dialogue.cpp +++ b/apps/openmw/mwgui/dialogue.cpp @@ -7,12 +7,14 @@ #include #include +#include #include "../mwbase/environment.hpp" #include "../mwbase/windowmanager.hpp" #include "../mwbase/mechanicsmanager.hpp" #include "../mwbase/world.hpp" #include "../mwbase/soundmanager.hpp" +#include "../mwbase/dialoguemanager.hpp" #include "../mwmechanics/npcstats.hpp" @@ -20,12 +22,7 @@ #include "../mwworld/containerstore.hpp" #include "../mwworld/esmstore.hpp" -#include "../mwdialogue/dialoguemanagerimp.hpp" - #include "widgets.hpp" -#include "tradewindow.hpp" -#include "spellbuyingwindow.hpp" -#include "travelwindow.hpp" #include "bookpage.hpp" #include "journalbooks.hpp" // to_utf8_span @@ -337,51 +334,25 @@ namespace MWGui MWBase::Environment::get().getWorld()->getStore().get(); if (topic == gmst.find("sPersuasion")->getString()) - { mPersuasionDialog.setVisible(true); - } else if (topic == gmst.find("sCompanionShare")->getString()) - { - MWBase::Environment::get().getWindowManager()->pushGuiMode(GM_Companion); MWBase::Environment::get().getWindowManager()->showCompanionWindow(mPtr); - } else if (!MWBase::Environment::get().getDialogueManager()->checkServiceRefused()) { if (topic == gmst.find("sBarter")->getString()) - { - MWBase::Environment::get().getWindowManager()->pushGuiMode(GM_Barter); - MWBase::Environment::get().getWindowManager()->getTradeWindow()->startTrade(mPtr); - } + MWBase::Environment::get().getWindowManager()->startTrade(mPtr); else if (topic == gmst.find("sSpells")->getString()) - { - MWBase::Environment::get().getWindowManager()->pushGuiMode(GM_SpellBuying); - MWBase::Environment::get().getWindowManager()->getSpellBuyingWindow()->startSpellBuying(mPtr); - } + MWBase::Environment::get().getWindowManager()->startSpellBuying(mPtr); else if (topic == gmst.find("sTravel")->getString()) - { - MWBase::Environment::get().getWindowManager()->pushGuiMode(GM_Travel); - MWBase::Environment::get().getWindowManager()->getTravelWindow()->startTravel(mPtr); - } + MWBase::Environment::get().getWindowManager()->startTravel(mPtr); else if (topic == gmst.find("sSpellMakingMenuTitle")->getString()) - { - MWBase::Environment::get().getWindowManager()->pushGuiMode(GM_SpellCreation); MWBase::Environment::get().getWindowManager()->startSpellMaking (mPtr); - } else if (topic == gmst.find("sEnchanting")->getString()) - { - MWBase::Environment::get().getWindowManager()->pushGuiMode(GM_Enchanting); MWBase::Environment::get().getWindowManager()->startEnchanting (mPtr); - } else if (topic == gmst.find("sServiceTrainingTitle")->getString()) - { - MWBase::Environment::get().getWindowManager()->pushGuiMode(GM_Training); MWBase::Environment::get().getWindowManager()->startTraining (mPtr); - } else if (topic == gmst.find("sRepair")->getString()) - { - MWBase::Environment::get().getWindowManager()->pushGuiMode(GM_MerchantRepair); MWBase::Environment::get().getWindowManager()->startRepair (mPtr); - } } } } @@ -440,8 +411,6 @@ namespace MWGui bool isCompanion = !mPtr.getClass().getScript(mPtr).empty() && mPtr.getRefData().getLocals().getIntVar(mPtr.getClass().getScript(mPtr), "companion"); - bool anyService = mServices > 0 || isCompanion || mPtr.getTypeName() == typeid(ESM::NPC).name(); - const MWWorld::Store &gmst = MWBase::Environment::get().getWorld()->getStore().get(); @@ -472,7 +441,7 @@ namespace MWGui if (isCompanion) mTopicsList->addItem(gmst.find("sCompanionShare")->getString()); - if (anyService) + if (mTopicsList->getItemCount() > 0) mTopicsList->addSeparator(); @@ -549,7 +518,7 @@ namespace MWGui size_t range = book->getSize().second - viewHeight; mScrollBar->setScrollRange(range); mScrollBar->setScrollPosition(range-1); - mScrollBar->setTrackSize(viewHeight / static_cast(book->getSize().second) * mScrollBar->getLineSize()); + mScrollBar->setTrackSize(static_cast(viewHeight / static_cast(book->getSize().second) * mScrollBar->getLineSize())); onScrollbarMoved(mScrollBar, range-1); } else @@ -637,14 +606,14 @@ namespace MWGui if (dispositionVisible && !dispositionWasVisible) { mDispositionBar->setVisible(true); - float offset = mDispositionBar->getHeight()+5; + int offset = mDispositionBar->getHeight()+5; mTopicsList->setCoord(mTopicsList->getCoord() + MyGUI::IntCoord(0,offset,0,-offset)); mTopicsList->adjustSize(); } else if (!dispositionVisible && dispositionWasVisible) { mDispositionBar->setVisible(false); - float offset = mDispositionBar->getHeight()+5; + int offset = mDispositionBar->getHeight()+5; mTopicsList->setCoord(mTopicsList->getCoord() - MyGUI::IntCoord(0,offset,0,-offset)); mTopicsList->adjustSize(); } diff --git a/apps/openmw/mwgui/hud.cpp b/apps/openmw/mwgui/hud.cpp index 1f7ead6f5..eb458be50 100644 --- a/apps/openmw/mwgui/hud.cpp +++ b/apps/openmw/mwgui/hud.cpp @@ -24,7 +24,6 @@ #include "../mwmechanics/npcstats.hpp" #include "inventorywindow.hpp" -#include "console.hpp" #include "spellicons.hpp" #include "itemmodel.hpp" #include "draganddrop.hpp" @@ -262,7 +261,7 @@ namespace MWGui void HUD::setDrowningTimeLeft(float time, float maxTime) { - size_t progress = time/maxTime*200.0; + size_t progress = static_cast(time / maxTime * 200); mDrowning->setProgressPosition(progress); bool isDrowning = (progress == 0); @@ -309,7 +308,7 @@ namespace MWGui MWWorld::Ptr object = MWBase::Environment::get().getWorld()->getFacedObject(); if (mode == GM_Console) - MWBase::Environment::get().getWindowManager()->getConsole()->setSelectedObject(object); + MWBase::Environment::get().getWindowManager()->setConsoleSelectedObject(object); else if ((mode == GM_Container) || (mode == GM_Inventory)) { // pick up object @@ -631,7 +630,7 @@ namespace MWGui mEnemyHealth->setProgressRange(100); // Health is usually cast to int before displaying. Actors die whenever they are < 1 health. // Therefore any value < 1 should show as an empty health bar. We do the same in statswindow :) - mEnemyHealth->setProgressPosition(int(stats.getHealth().getCurrent()) / stats.getHealth().getModified() * 100); + mEnemyHealth->setProgressPosition(static_cast(stats.getHealth().getCurrent() / stats.getHealth().getModified() * 100)); static const float fNPCHealthBarFade = MWBase::Environment::get().getWorld()->getStore().get().find("fNPCHealthBarFade")->getFloat(); if (fNPCHealthBarFade > 0.f) @@ -671,4 +670,14 @@ namespace MWGui mEnemyHealthTimer = -1; } + void HUD::customMarkerCreated(MyGUI::Widget *marker) + { + marker->eventMouseButtonClick += MyGUI::newDelegate(this, &HUD::onMapClicked); + } + + void HUD::doorMarkerCreated(MyGUI::Widget *marker) + { + marker->eventMouseButtonClick += MyGUI::newDelegate(this, &HUD::onMapClicked); + } + } diff --git a/apps/openmw/mwgui/hud.hpp b/apps/openmw/mwgui/hud.hpp index 41a535a08..263c08774 100644 --- a/apps/openmw/mwgui/hud.hpp +++ b/apps/openmw/mwgui/hud.hpp @@ -119,6 +119,10 @@ namespace MWGui void onMagicClicked(MyGUI::Widget* _sender); void onMapClicked(MyGUI::Widget* _sender); + // LocalMapBase + virtual void customMarkerCreated(MyGUI::Widget* marker); + virtual void doorMarkerCreated(MyGUI::Widget* marker); + void updateEnemyHealthBar(); void updatePositions(); diff --git a/apps/openmw/mwgui/inventorywindow.cpp b/apps/openmw/mwgui/inventorywindow.cpp index 4270c4be1..80b246e84 100644 --- a/apps/openmw/mwgui/inventorywindow.cpp +++ b/apps/openmw/mwgui/inventorywindow.cpp @@ -23,9 +23,6 @@ #include "../mwbase/scriptmanager.hpp" #include "../mwrender/characterpreview.hpp" -#include "bookwindow.hpp" -#include "scrollwindow.hpp" -#include "spellwindow.hpp" #include "itemview.hpp" #include "inventoryitemmodel.hpp" #include "sortfilteritemmodel.hpp" @@ -101,7 +98,7 @@ namespace MWGui void InventoryWindow::adjustPanes() { const float aspect = 0.5; // fixed aspect ratio for the avatar image - float leftPaneWidth = (mMainWidget->getSize().height-44-mArmorRating->getHeight()) * aspect; + int leftPaneWidth = static_cast((mMainWidget->getSize().height - 44 - mArmorRating->getHeight()) * aspect); mLeftPane->setSize( leftPaneWidth, mMainWidget->getSize().height-44 ); mRightPane->setCoord( mLeftPane->getPosition().left + leftPaneWidth + 4, mRightPane->getPosition().top, @@ -153,10 +150,10 @@ namespace MWGui } MyGUI::IntSize viewSize = MyGUI::RenderManager::getInstance().getViewSize(); - MyGUI::IntPoint pos (Settings::Manager::getFloat(setting + " x", "Windows") * viewSize.width, - Settings::Manager::getFloat(setting + " y", "Windows") * viewSize.height); - MyGUI::IntSize size (Settings::Manager::getFloat(setting + " w", "Windows") * viewSize.width, - Settings::Manager::getFloat(setting + " h", "Windows") * viewSize.height); + MyGUI::IntPoint pos(static_cast(Settings::Manager::getFloat(setting + " x", "Windows") * viewSize.width), + static_cast(Settings::Manager::getFloat(setting + " y", "Windows") * viewSize.height)); + MyGUI::IntSize size(static_cast(Settings::Manager::getFloat(setting + " w", "Windows") * viewSize.width), + static_cast(Settings::Manager::getFloat(setting + " h", "Windows") * viewSize.height)); if (size.width != mMainWidget->getWidth() || size.height != mMainWidget->getHeight()) mPreviewResize = true; @@ -317,8 +314,7 @@ namespace MWGui void InventoryWindow::updateItemView() { - if (MWBase::Environment::get().getWindowManager()->getSpellWindow()) - MWBase::Environment::get().getWindowManager()->getSpellWindow()->updateSpells(); + MWBase::Environment::get().getWindowManager()->updateSpellWindow(); mItemView->update(); mPreviewDirty = true; @@ -432,13 +428,6 @@ namespace MWGui action->execute (MWBase::Environment::get().getWorld()->getPlayerPtr()); - // this is necessary for books/scrolls: if they are already in the player's inventory, - // the "Take" button should not be visible. - // NOTE: the take button is "reset" when the window opens, so we can safely do the following - // without screwing up future book windows - MWBase::Environment::get().getWindowManager()->getBookWindow()->setTakeButtonShow(false); - MWBase::Environment::get().getWindowManager()->getScrollWindow()->setTakeButtonShow(false); - mSkippedToEquip = MWWorld::Ptr(); } else @@ -519,7 +508,7 @@ namespace MWGui float capacity = player.getClass().getCapacity(player); float encumbrance = player.getClass().getEncumbrance(player); mTradeModel->adjustEncumbrance(encumbrance); - mEncumbranceBar->setValue(encumbrance, capacity); + mEncumbranceBar->setValue(static_cast(encumbrance), static_cast(capacity)); } void InventoryWindow::onFrame() @@ -568,8 +557,7 @@ namespace MWGui void InventoryWindow::notifyContentChanged() { // update the spell window just in case new enchanted items were added to inventory - if (MWBase::Environment::get().getWindowManager()->getSpellWindow()) - MWBase::Environment::get().getWindowManager()->getSpellWindow()->updateSpells(); + MWBase::Environment::get().getWindowManager()->updateSpellWindow(); MWBase::Environment::get().getMechanicsManager()->updateMagicEffects( MWBase::Environment::get().getWorld()->getPlayerPtr()); @@ -626,8 +614,7 @@ namespace MWGui MWBase::Environment::get().getMechanicsManager()->itemTaken(player, newObject, MWWorld::Ptr(), count); - if (MWBase::Environment::get().getWindowManager()->getSpellWindow()) - MWBase::Environment::get().getWindowManager()->getSpellWindow()->updateSpells(); + MWBase::Environment::get().getWindowManager()->updateSpellWindow(); } void InventoryWindow::cycle(bool next) @@ -653,16 +640,13 @@ namespace MWGui if (selected != -1) lastId = model.getItem(selected).mBase.getCellRef().getRefId(); ItemModel::ModelIndex cycled = selected; - while (!found) + for (unsigned int i=0; igetViewOffset().left + _rel*0.3 > 0) + if (mScrollView->getViewOffset().left + _rel*0.3f > 0) mScrollView->setViewOffset(MyGUI::IntPoint(0, 0)); else - mScrollView->setViewOffset(MyGUI::IntPoint(mScrollView->getViewOffset().left + _rel*0.3, 0)); + mScrollView->setViewOffset(MyGUI::IntPoint(static_cast(mScrollView->getViewOffset().left + _rel*0.3f), 0)); } void ItemView::setSize(const MyGUI::IntSize &_value) diff --git a/apps/openmw/mwgui/jailscreen.cpp b/apps/openmw/mwgui/jailscreen.cpp index 548b1b604..5c0a6ec5f 100644 --- a/apps/openmw/mwgui/jailscreen.cpp +++ b/apps/openmw/mwgui/jailscreen.cpp @@ -1,5 +1,7 @@ #include +#include + #include "../mwbase/windowmanager.hpp" #include "../mwbase/mechanicsmanager.hpp" #include "../mwbase/world.hpp" @@ -17,7 +19,7 @@ namespace MWGui { JailScreen::JailScreen() : WindowBase("openmw_jail_screen.layout"), - mTimeAdvancer(0.0125), + mTimeAdvancer(0.01f), mDays(1), mFadeTimeRemaining(0) { @@ -39,7 +41,7 @@ namespace MWGui mFadeTimeRemaining = 0.5; setVisible(false); - mProgressBar->setScrollRange(days*24+1); + mProgressBar->setScrollRange(100+1); mProgressBar->setScrollPosition(0); mProgressBar->setTrackSize(0); } @@ -59,14 +61,14 @@ namespace MWGui MWBase::Environment::get().getWorld()->teleportToClosestMarker(player, "prisonmarker"); setVisible(true); - mTimeAdvancer.run(mDays*24); + mTimeAdvancer.run(100); } } void JailScreen::onJailProgressChanged(int cur, int /*total*/) { mProgressBar->setScrollPosition(0); - mProgressBar->setTrackSize(cur / (float)(mProgressBar->getScrollRange()) * mProgressBar->getLineSize()); + mProgressBar->setTrackSize(static_cast(cur / (float)(mProgressBar->getScrollRange()) * mProgressBar->getLineSize())); } void JailScreen::onJailFinished() @@ -83,7 +85,7 @@ namespace MWGui std::set skills; for (int day=0; day (RAND_MAX) + 1) * ESM::Skill::Length; + int skill = OEngine::Misc::Rng::rollDice(ESM::Skill::Length); skills.insert(skill); MWMechanics::SkillValue& value = player.getClass().getNpcStats(player).getSkill(skill); diff --git a/apps/openmw/mwgui/journalviewmodel.cpp b/apps/openmw/mwgui/journalviewmodel.cpp index 3a86613f6..9a47070c2 100644 --- a/apps/openmw/mwgui/journalviewmodel.cpp +++ b/apps/openmw/mwgui/journalviewmodel.cpp @@ -199,7 +199,7 @@ struct JournalViewModelImpl : JournalViewModel }; - void visitQuestNames (bool active_only, boost::function visitor) const + void visitQuestNames (bool active_only, boost::function visitor) const { MWBase::Journal * journal = MWBase::Environment::get ().getJournal (); @@ -231,7 +231,7 @@ struct JournalViewModelImpl : JournalViewModel if (visitedQuests.find(quest.getName()) != visitedQuests.end()) continue; - visitor (quest.getName()); + visitor (quest.getName(), isFinished); visitedQuests.insert(quest.getName()); } diff --git a/apps/openmw/mwgui/journalviewmodel.hpp b/apps/openmw/mwgui/journalviewmodel.hpp index 5f0189b59..b3c6b0183 100644 --- a/apps/openmw/mwgui/journalviewmodel.hpp +++ b/apps/openmw/mwgui/journalviewmodel.hpp @@ -67,8 +67,8 @@ namespace MWGui /// returns true if their are no journal entries to display virtual bool isEmpty () const = 0; - /// walks the active and optionally completed, quests providing the name - virtual void visitQuestNames (bool active_only, boost::function visitor) const = 0; + /// walks the active and optionally completed, quests providing the name and completed status + virtual void visitQuestNames (bool active_only, boost::function visitor) const = 0; /// walks over the journal entries related to all quests with the given name /// If \a questName is empty, simply visits all journal entries diff --git a/apps/openmw/mwgui/journalwindow.cpp b/apps/openmw/mwgui/journalwindow.cpp index d7e27a277..4cfcc8064 100644 --- a/apps/openmw/mwgui/journalwindow.cpp +++ b/apps/openmw/mwgui/journalwindow.cpp @@ -7,6 +7,7 @@ #include #include +#include #include #include @@ -428,11 +429,24 @@ namespace AddNamesToList(Gui::MWList* list) : mList(list) {} Gui::MWList* mList; - void operator () (const std::string& name) + void operator () (const std::string& name, bool finished=false) { mList->addItem(name); } }; + struct SetNamesInactive + { + SetNamesInactive(Gui::MWList* list) : mList(list) {} + + Gui::MWList* mList; + void operator () (const std::string& name, bool finished) + { + if (finished) + { + mList->getItemWidget(name)->setStateSelected(true); + } + } + }; void notifyQuests(MyGUI::Widget* _sender) { @@ -453,6 +467,12 @@ namespace mModel->visitQuestNames(!mAllQuests, add); list->adjustSize(); + + if (mAllQuests) + { + SetNamesInactive setInactive(list); + mModel->visitQuestNames(!mAllQuests, setInactive); + } } void notifyShowAll(MyGUI::Widget* _sender) diff --git a/apps/openmw/mwgui/loadingscreen.cpp b/apps/openmw/mwgui/loadingscreen.cpp index 9e3343c78..3204c6548 100644 --- a/apps/openmw/mwgui/loadingscreen.cpp +++ b/apps/openmw/mwgui/loadingscreen.cpp @@ -15,6 +15,8 @@ #include #include +#include + #include #include "../mwbase/environment.hpp" @@ -33,8 +35,8 @@ namespace MWGui : mSceneMgr(sceneMgr) , mWindow(rw) , WindowBase("openmw_loading_screen.layout") - , mLastRenderTime(0.f) - , mLastWallpaperChangeTime(0.f) + , mLastRenderTime(0) + , mLastWallpaperChangeTime(0) , mProgress(0) , mVSyncWasEnabled(false) { @@ -146,7 +148,7 @@ namespace MWGui if (!mResources.empty()) { - std::string const & randomSplash = mResources.at (rand() % mResources.size()); + std::string const & randomSplash = mResources.at(OEngine::Misc::Rng::rollDice(mResources.size())); Ogre::TextureManager::getSingleton ().load (randomSplash, Ogre::ResourceGroupManager::AUTODETECT_RESOURCE_GROUP_NAME); @@ -173,7 +175,7 @@ namespace MWGui return; mProgress = value; mProgressBar->setScrollPosition(0); - mProgressBar->setTrackSize(value / (float)(mProgressBar->getScrollRange()) * mProgressBar->getLineSize()); + mProgressBar->setTrackSize(static_cast(value / (float)(mProgressBar->getScrollRange()) * mProgressBar->getLineSize())); draw(); } @@ -182,7 +184,7 @@ namespace MWGui mProgressBar->setScrollPosition(0); size_t value = mProgress + increase; mProgress = value; - mProgressBar->setTrackSize(value / (float)(mProgressBar->getScrollRange()) * mProgressBar->getLineSize()); + mProgressBar->setTrackSize(static_cast(value / (float)(mProgressBar->getScrollRange()) * mProgressBar->getLineSize())); draw(); } @@ -193,7 +195,7 @@ namespace MWGui time = (time-2)*-1; mProgressBar->setTrackSize(50); - mProgressBar->setScrollPosition(time * (mProgressBar->getScrollRange()-1)); + mProgressBar->setScrollPosition(static_cast(time * (mProgressBar->getScrollRange() - 1))); draw(); } diff --git a/apps/openmw/mwgui/mapwindow.cpp b/apps/openmw/mwgui/mapwindow.cpp index 13e2e3904..02e8ffdfe 100644 --- a/apps/openmw/mwgui/mapwindow.cpp +++ b/apps/openmw/mwgui/mapwindow.cpp @@ -244,14 +244,14 @@ namespace MWGui // Image space is -Y up, cells are Y up nY = 1 - (worldY - cellSize * cellY) / cellSize; - float cellDx = cellX - mCurX; - float cellDy = cellY - mCurY; + float cellDx = static_cast(cellX - mCurX); + float cellDy = static_cast(cellY - mCurY); markerPos.cellX = cellX; markerPos.cellY = cellY; - widgetPos = MyGUI::IntPoint(nX * mMapWidgetSize + (1+cellDx) * mMapWidgetSize, - nY * mMapWidgetSize - (cellDy-1) * mMapWidgetSize); + widgetPos = MyGUI::IntPoint(static_cast(nX * mMapWidgetSize + (1 + cellDx) * mMapWidgetSize), + static_cast(nY * mMapWidgetSize - (cellDy-1) * mMapWidgetSize)); } else { @@ -263,8 +263,8 @@ namespace MWGui markerPos.cellY = cellY; // Image space is -Y up, cells are Y up - widgetPos = MyGUI::IntPoint(nX * mMapWidgetSize + (1+(cellX-mCurX)) * mMapWidgetSize, - nY * mMapWidgetSize + (1-(cellY-mCurY)) * mMapWidgetSize); + widgetPos = MyGUI::IntPoint(static_cast(nX * mMapWidgetSize + (1 + (cellX - mCurX)) * mMapWidgetSize), + static_cast(nY * mMapWidgetSize + (1-(cellY-mCurY)) * mMapWidgetSize)); } markerPos.nX = nX; @@ -309,8 +309,8 @@ namespace MWGui markerWidget->setUserString("ToolTipType", "Layout"); markerWidget->setUserString("ToolTipLayout", "TextToolTipOneLine"); markerWidget->setUserString("Caption_TextOneLine", MyGUI::TextIterator::toTagsString(marker.mNote)); - markerWidget->setNormalColour(MyGUI::Colour(1.0,0.3,0.3)); - markerWidget->setHoverColour(MyGUI::Colour(1.0,0.5,0.5)); + markerWidget->setNormalColour(MyGUI::Colour(1.0f, 0.3f, 0.3f)); + markerWidget->setHoverColour(MyGUI::Colour(1.0f, 0.5f, 0.5f)); markerWidget->setUserData(marker); markerWidget->setNeedMouseFocus(true); customMarkerCreated(markerWidget); @@ -424,7 +424,7 @@ namespace MWGui void LocalMapBase::setPlayerPos(int cellX, int cellY, const float nx, const float ny) { - MyGUI::IntPoint pos(mMapWidgetSize+nx*mMapWidgetSize-16, mMapWidgetSize+ny*mMapWidgetSize-16); + MyGUI::IntPoint pos(static_cast(mMapWidgetSize + nx*mMapWidgetSize - 16), static_cast(mMapWidgetSize + ny*mMapWidgetSize - 16)); pos.left += (cellX - mCurX) * mMapWidgetSize; pos.top -= (cellY - mCurY) * mMapWidgetSize; @@ -435,7 +435,7 @@ namespace MWGui mCompass->setPosition(pos); MyGUI::IntPoint middle (pos.left+16, pos.top+16); MyGUI::IntCoord viewsize = mLocalMap->getCoord(); - MyGUI::IntPoint viewOffset(0.5*viewsize.width - middle.left, 0.5*viewsize.height - middle.top); + MyGUI::IntPoint viewOffset((viewsize.width / 2) - middle.left, (viewsize.height / 2) - middle.top); mLocalMap->setViewOffset(viewOffset); } } @@ -668,7 +668,7 @@ namespace MWGui else { worldPos.x = (x + nX) * cellSize; - worldPos.y = (y + (1.0-nY)) * cellSize; + worldPos.y = (y + (1.0f-nY)) * cellSize; } mEditingMarker.mWorldX = worldPos.x; @@ -737,8 +737,8 @@ namespace MWGui int markerSize = 12; int offset = mGlobalMapRender->getCellSize()/2 - markerSize/2; MyGUI::IntCoord widgetCoord( - worldX * mGlobalMapRender->getWidth()+offset, - worldY * mGlobalMapRender->getHeight()+offset, + static_cast(worldX * mGlobalMapRender->getWidth()+offset), + static_cast(worldY * mGlobalMapRender->getHeight() + offset), markerSize, markerSize); MyGUI::Widget* markerWidget = mGlobalMap->createWidget("MarkerButton", @@ -827,18 +827,7 @@ namespace MWGui if (MWBase::Environment::get().getWorld ()->isCellExterior ()) { Ogre::Vector3 pos = MWBase::Environment::get().getWorld ()->getPlayerPtr().getRefData ().getBaseNode ()->_getDerivedPosition (); - - float worldX, worldY; - mGlobalMapRender->worldPosToImageSpace (pos.x, pos.y, worldX, worldY); - worldX *= mGlobalMapRender->getWidth(); - worldY *= mGlobalMapRender->getHeight(); - - mPlayerArrowGlobal->setPosition(MyGUI::IntPoint(worldX - 16, worldY - 16)); - - // set the view offset so that player is in the center - MyGUI::IntSize viewsize = mGlobalMap->getSize(); - MyGUI::IntPoint viewoffs(0.5*viewsize.width - worldX, 0.5*viewsize.height - worldY); - mGlobalMap->setViewOffset(viewoffs); + setGlobalMapPlayerPosition(pos.x, pos.y); } } @@ -854,11 +843,11 @@ namespace MWGui x *= mGlobalMapRender->getWidth(); y *= mGlobalMapRender->getHeight(); - mPlayerArrowGlobal->setPosition(MyGUI::IntPoint(x - 16, y - 16)); + mPlayerArrowGlobal->setPosition(MyGUI::IntPoint(static_cast(x - 16), static_cast(y - 16))); // set the view offset so that player is in the center MyGUI::IntSize viewsize = mGlobalMap->getSize(); - MyGUI::IntPoint viewoffs(0.5*viewsize.width - x, 0.5*viewsize.height - y); + MyGUI::IntPoint viewoffs(static_cast(viewsize.width * 0.5f - x), static_cast(viewsize.height *0.5 - y)); mGlobalMap->setViewOffset(viewoffs); } diff --git a/apps/openmw/mwgui/merchantrepair.cpp b/apps/openmw/mwgui/merchantrepair.cpp index 907c664b1..4407bf927 100644 --- a/apps/openmw/mwgui/merchantrepair.cpp +++ b/apps/openmw/mwgui/merchantrepair.cpp @@ -59,11 +59,11 @@ void MerchantRepair::startRepair(const MWWorld::Ptr &actor) float fRepairMult = MWBase::Environment::get().getWorld()->getStore().get() .find("fRepairMult")->getFloat(); - float p = std::max(1, basePrice); - float r = std::max(1, static_cast(maxDurability / p)); + float p = static_cast(std::max(1, basePrice)); + float r = static_cast(std::max(1, static_cast(maxDurability / p))); - int x = ((maxDurability - durability) / r); - x = (fRepairMult * x); + int x = static_cast((maxDurability - durability) / r); + x = static_cast(fRepairMult * x); int price = MWBase::Environment::get().getMechanicsManager()->getBarterOffer(mActor, x, true); @@ -105,10 +105,10 @@ void MerchantRepair::startRepair(const MWWorld::Ptr &actor) void MerchantRepair::onMouseWheel(MyGUI::Widget* _sender, int _rel) { - if (mList->getViewOffset().top + _rel*0.3 > 0) + if (mList->getViewOffset().top + _rel*0.3f > 0) mList->setViewOffset(MyGUI::IntPoint(0, 0)); else - mList->setViewOffset(MyGUI::IntPoint(0, mList->getViewOffset().top + _rel*0.3)); + mList->setViewOffset(MyGUI::IntPoint(0, static_cast(mList->getViewOffset().top + _rel*0.3f))); } void MerchantRepair::open() diff --git a/apps/openmw/mwgui/messagebox.cpp b/apps/openmw/mwgui/messagebox.cpp index cdbcf784d..b7c67e68b 100644 --- a/apps/openmw/mwgui/messagebox.cpp +++ b/apps/openmw/mwgui/messagebox.cpp @@ -70,7 +70,7 @@ namespace MWGui it = mMessageBoxes.begin(); while(it != mMessageBoxes.end()) { - (*it)->update(height); + (*it)->update(static_cast(height)); height += (*it)->getHeight(); ++it; } diff --git a/apps/openmw/mwgui/pickpocketitemmodel.cpp b/apps/openmw/mwgui/pickpocketitemmodel.cpp index f6882ada6..bc7c5528e 100644 --- a/apps/openmw/mwgui/pickpocketitemmodel.cpp +++ b/apps/openmw/mwgui/pickpocketitemmodel.cpp @@ -1,5 +1,7 @@ #include "pickpocketitemmodel.hpp" +#include + #include "../mwmechanics/npcstats.hpp" #include "../mwworld/class.hpp" @@ -12,11 +14,13 @@ namespace MWGui int chance = thief.getClass().getSkill(thief, ESM::Skill::Sneak); mSourceModel->update(); + + // build list of items that player is unable to find when attempts to pickpocket. if (hideItems) { for (size_t i = 0; igetItemCount(); ++i) { - if (std::rand() / static_cast(RAND_MAX) * 100 > chance) + if (chance <= OEngine::Misc::Rng::roll0to99()) mHiddenItems.push_back(mSourceModel->getItem(i)); } } diff --git a/apps/openmw/mwgui/quickkeysmenu.cpp b/apps/openmw/mwgui/quickkeysmenu.cpp index a102de1e5..8f595df80 100644 --- a/apps/openmw/mwgui/quickkeysmenu.cpp +++ b/apps/openmw/mwgui/quickkeysmenu.cpp @@ -94,12 +94,24 @@ namespace MWGui while (key->getChildCount()) // Destroy number label MyGUI::Gui::getInstance().destroyWidget(key->getChildAt(0)); - mAssigned[index] = Type_Unassigned; + if (index == 9) + { + mAssigned[index] = Type_HandToHand; - MyGUI::TextBox* textBox = key->createWidgetReal("SandText", MyGUI::FloatCoord(0,0,1,1), MyGUI::Align::Default); - textBox->setTextAlign (MyGUI::Align::Center); - textBox->setCaption (MyGUI::utility::toString(index+1)); - textBox->setNeedMouseFocus (false); + MyGUI::ImageBox* image = key->createWidget("ImageBox", + MyGUI::IntCoord(14, 13, 32, 32), MyGUI::Align::Default); + image->setImageTexture("icons\\k\\stealth_handtohand.dds"); + image->setNeedMouseFocus(false); + } + else + { + mAssigned[index] = Type_Unassigned; + + MyGUI::TextBox* textBox = key->createWidgetReal("SandText", MyGUI::FloatCoord(0,0,1,1), MyGUI::Align::Default); + textBox->setTextAlign (MyGUI::Align::Center); + textBox->setCaption (MyGUI::utility::toString(index+1)); + textBox->setNeedMouseFocus (false); + } } void QuickKeysMenu::onQuickKeyButtonClicked(MyGUI::Widget* sender) @@ -338,6 +350,11 @@ namespace MWGui store.setSelectedEnchantItem(it); MWBase::Environment::get().getWorld()->getPlayer().setDrawState(MWMechanics::DrawState_Spell); } + else if (type == Type_HandToHand) + { + store.unequipSlot(MWWorld::InventoryStore::Slot_CarriedRight, player); + MWBase::Environment::get().getWorld()->getPlayer().setDrawState(MWMechanics::DrawState_Weapon); + } } // --------------------------------------------------------------------------------------------------------- @@ -409,6 +426,7 @@ namespace MWGui switch (type) { case Type_Unassigned: + case Type_HandToHand: break; case Type_Item: case Type_MagicItem: @@ -489,6 +507,7 @@ namespace MWGui break; } case Type_Unassigned: + case Type_HandToHand: unassign(button, i); break; } diff --git a/apps/openmw/mwgui/quickkeysmenu.hpp b/apps/openmw/mwgui/quickkeysmenu.hpp index 00afa4561..afbcff001 100644 --- a/apps/openmw/mwgui/quickkeysmenu.hpp +++ b/apps/openmw/mwgui/quickkeysmenu.hpp @@ -37,15 +37,16 @@ namespace MWGui void activateQuickKey(int index); + /// @note This enum is serialized, so don't move the items around! enum QuickKeyType { Type_Item, Type_Magic, Type_MagicItem, - Type_Unassigned + Type_Unassigned, + Type_HandToHand }; - void write (ESM::ESMWriter& writer); void readRecord (ESM::ESMReader& reader, uint32_t type); void clear(); diff --git a/apps/openmw/mwgui/race.cpp b/apps/openmw/mwgui/race.cpp index b03bf758a..f908a9dd0 100644 --- a/apps/openmw/mwgui/race.cpp +++ b/apps/openmw/mwgui/race.cpp @@ -142,13 +142,13 @@ namespace MWGui for (unsigned int i=0; igetScrollRange()-1) - 0.5) * 3.14 * 2; + float angle = (float(_position) / (scroll->getScrollRange()-1) - 0.5f) * 3.14f * 2; mPreview->update (angle); mPreviewDirty = true; mCurrentAngle = angle; @@ -404,7 +404,7 @@ namespace MWGui skillWidget = mSkillList->createWidget("MW_StatNameValue", coord1, MyGUI::Align::Default, std::string("Skill") + MyGUI::utility::toString(i)); skillWidget->setSkillNumber(skillId); - skillWidget->setSkillValue(Widgets::MWSkill::SkillValue(race->mData.mBonus[i].mBonus)); + skillWidget->setSkillValue(Widgets::MWSkill::SkillValue(static_cast(race->mData.mBonus[i].mBonus))); ToolTips::createSkillToolTip(skillWidget, skillId); diff --git a/apps/openmw/mwgui/recharge.cpp b/apps/openmw/mwgui/recharge.cpp index 2c854a8f5..a0e5991b4 100644 --- a/apps/openmw/mwgui/recharge.cpp +++ b/apps/openmw/mwgui/recharge.cpp @@ -5,6 +5,8 @@ #include #include +#include + #include #include "../mwbase/world.hpp" @@ -119,7 +121,7 @@ void Recharge::updateView() Widgets::MWDynamicStatPtr chargeWidget = mView->createWidget ("MW_ChargeBar", MyGUI::IntCoord(72, currentY+2, 199, 20), MyGUI::Align::Default); - chargeWidget->setValue(iter->getCellRef().getEnchantmentCharge(), enchantment->mData.mCharge); + chargeWidget->setValue(static_cast(iter->getCellRef().getEnchantmentCharge()), enchantment->mData.mCharge); chargeWidget->setNeedMouseFocus(false); currentY += 32 + 4; @@ -149,11 +151,11 @@ void Recharge::onItemClicked(MyGUI::Widget *sender) MWMechanics::CreatureStats& stats = player.getClass().getCreatureStats(player); MWMechanics::NpcStats& npcStats = player.getClass().getNpcStats(player); - float luckTerm = 0.1 * stats.getAttribute(ESM::Attribute::Luck).getModified(); + float luckTerm = 0.1f * stats.getAttribute(ESM::Attribute::Luck).getModified(); if (luckTerm < 1|| luckTerm > 10) luckTerm = 1; - float intelligenceTerm = 0.2 * stats.getAttribute(ESM::Attribute::Intelligence).getModified(); + float intelligenceTerm = 0.2f * stats.getAttribute(ESM::Attribute::Intelligence).getModified(); if (intelligenceTerm > 20) intelligenceTerm = 20; @@ -161,7 +163,7 @@ void Recharge::onItemClicked(MyGUI::Widget *sender) intelligenceTerm = 1; float x = (npcStats.getSkill(ESM::Skill::Enchant).getModified() + intelligenceTerm + luckTerm) * stats.getFatigueTerm(); - int roll = std::rand()/ (static_cast (RAND_MAX) + 1) * 100; // [0, 99] + int roll = OEngine::Misc::Rng::roll0to99(); if (roll < x) { std::string soul = gem.getCellRef().getSoul(); @@ -197,10 +199,10 @@ void Recharge::onItemClicked(MyGUI::Widget *sender) void Recharge::onMouseWheel(MyGUI::Widget* _sender, int _rel) { - if (mView->getViewOffset().top + _rel*0.3 > 0) + if (mView->getViewOffset().top + _rel*0.3f > 0) mView->setViewOffset(MyGUI::IntPoint(0, 0)); else - mView->setViewOffset(MyGUI::IntPoint(0, mView->getViewOffset().top + _rel*0.3)); + mView->setViewOffset(MyGUI::IntPoint(0, static_cast(mView->getViewOffset().top + _rel*0.3f))); } } diff --git a/apps/openmw/mwgui/repair.cpp b/apps/openmw/mwgui/repair.cpp index c3c971400..9f26923d4 100644 --- a/apps/openmw/mwgui/repair.cpp +++ b/apps/openmw/mwgui/repair.cpp @@ -150,10 +150,10 @@ void Repair::onRepairItem(MyGUI::Widget *sender) void Repair::onMouseWheel(MyGUI::Widget* _sender, int _rel) { - if (mRepairView->getViewOffset().top + _rel*0.3 > 0) + if (mRepairView->getViewOffset().top + _rel*0.3f > 0) mRepairView->setViewOffset(MyGUI::IntPoint(0, 0)); else - mRepairView->setViewOffset(MyGUI::IntPoint(0, mRepairView->getViewOffset().top + _rel*0.3)); + mRepairView->setViewOffset(MyGUI::IntPoint(0, static_cast(mRepairView->getViewOffset().top + _rel*0.3f))); } } diff --git a/apps/openmw/mwgui/review.cpp b/apps/openmw/mwgui/review.cpp index 023f23815..12957c2b0 100644 --- a/apps/openmw/mwgui/review.cpp +++ b/apps/openmw/mwgui/review.cpp @@ -148,21 +148,21 @@ namespace MWGui void ReviewDialog::setHealth(const MWMechanics::DynamicStat& value) { - mHealth->setValue(value.getCurrent(), value.getModified()); + mHealth->setValue(static_cast(value.getCurrent()), static_cast(value.getModified())); std::string valStr = MyGUI::utility::toString(value.getCurrent()) + "/" + MyGUI::utility::toString(value.getModified()); mHealth->setUserString("Caption_HealthDescription", "#{sHealthDesc}\n" + valStr); } void ReviewDialog::setMagicka(const MWMechanics::DynamicStat& value) { - mMagicka->setValue(value.getCurrent(), value.getModified()); + mMagicka->setValue(static_cast(value.getCurrent()), static_cast(value.getModified())); std::string valStr = MyGUI::utility::toString(value.getCurrent()) + "/" + MyGUI::utility::toString(value.getModified()); mMagicka->setUserString("Caption_HealthDescription", "#{sIntDesc}\n" + valStr); } void ReviewDialog::setFatigue(const MWMechanics::DynamicStat& value) { - mFatigue->setValue(value.getCurrent(), value.getModified()); + mFatigue->setValue(static_cast(value.getCurrent()), static_cast(value.getModified())); std::string valStr = MyGUI::utility::toString(value.getCurrent()) + "/" + MyGUI::utility::toString(value.getModified()); mFatigue->setUserString("Caption_HealthDescription", "#{sFatDesc}\n" + valStr); } @@ -182,7 +182,7 @@ namespace MWGui MyGUI::TextBox* widget = mSkillWidgetMap[skillId]; if (widget) { - float modified = value.getModified(), base = value.getBase(); + float modified = static_cast(value.getModified()), base = static_cast(value.getBase()); std::string text = MyGUI::utility::toString(std::floor(modified)); std::string state = "normal"; if (modified > base) @@ -378,7 +378,7 @@ namespace MWGui if (mSkillView->getViewOffset().top + _rel*0.3 > 0) mSkillView->setViewOffset(MyGUI::IntPoint(0, 0)); else - mSkillView->setViewOffset(MyGUI::IntPoint(0, mSkillView->getViewOffset().top + _rel*0.3)); + mSkillView->setViewOffset(MyGUI::IntPoint(0, static_cast(mSkillView->getViewOffset().top + _rel*0.3))); } } diff --git a/apps/openmw/mwgui/savegamedialog.hpp b/apps/openmw/mwgui/savegamedialog.hpp index 11470a20f..2192adbde 100644 --- a/apps/openmw/mwgui/savegamedialog.hpp +++ b/apps/openmw/mwgui/savegamedialog.hpp @@ -6,7 +6,7 @@ namespace MWState { class Character; - class Slot; + struct Slot; } namespace MWGui diff --git a/apps/openmw/mwgui/scrollwindow.cpp b/apps/openmw/mwgui/scrollwindow.cpp index d61693d39..85d1c8c4e 100644 --- a/apps/openmw/mwgui/scrollwindow.cpp +++ b/apps/openmw/mwgui/scrollwindow.cpp @@ -48,7 +48,7 @@ namespace MWGui center(); } - void ScrollWindow::open (MWWorld::Ptr scroll) + void ScrollWindow::open (MWWorld::Ptr scroll, bool showTakeButton) { // no 3d sounds because the object could be in a container. MWBase::Environment::get().getSoundManager()->playSound ("scroll", 1.0, 1.0); @@ -71,7 +71,7 @@ namespace MWGui mTextView->setViewOffset(MyGUI::IntPoint(0,0)); - setTakeButtonShow(true); + setTakeButtonShow(showTakeButton); } void ScrollWindow::exit() diff --git a/apps/openmw/mwgui/scrollwindow.hpp b/apps/openmw/mwgui/scrollwindow.hpp index e1f86529a..3c9e718b6 100644 --- a/apps/openmw/mwgui/scrollwindow.hpp +++ b/apps/openmw/mwgui/scrollwindow.hpp @@ -17,14 +17,14 @@ namespace MWGui public: ScrollWindow (); - void open (MWWorld::Ptr scroll); + void open (MWWorld::Ptr scroll, bool showTakeButton); virtual void exit(); - void setTakeButtonShow(bool show); void setInventoryAllowed(bool allowed); protected: void onCloseButtonClicked (MyGUI::Widget* _sender); void onTakeButtonClicked (MyGUI::Widget* _sender); + void setTakeButtonShow(bool show); private: Gui::ImageButton* mCloseButton; diff --git a/apps/openmw/mwgui/settingswindow.cpp b/apps/openmw/mwgui/settingswindow.cpp index a4f87e598..d895a28ea 100644 --- a/apps/openmw/mwgui/settingswindow.cpp +++ b/apps/openmw/mwgui/settingswindow.cpp @@ -148,11 +148,11 @@ namespace MWGui value = std::max(min, std::min(value, max)); value = (value-min)/(max-min); - scroll->setScrollPosition( value * (scroll->getScrollRange()-1)); + scroll->setScrollPosition(static_cast(value * (scroll->getScrollRange() - 1))); } else { - int value = Settings::Manager::getFloat(getSettingName(current), getSettingCategory(current)); + int value = Settings::Manager::getInt(getSettingName(current), getSettingCategory(current)); scroll->setScrollPosition(value); } scroll->eventScrollChangePosition += MyGUI::newDelegate(this, &SettingsWindow::onSliderChangePosition); @@ -163,7 +163,8 @@ namespace MWGui } SettingsWindow::SettingsWindow() : - WindowBase("openmw_settings_window.layout") + WindowBase("openmw_settings_window.layout"), + mKeyboardMode(true) { configureWidgets(mMainWidget); @@ -188,6 +189,8 @@ namespace MWGui getWidget(mResetControlsButton, "ResetControlsButton"); getWidget(mRefractionButton, "RefractionButton"); getWidget(mDifficultySlider, "DifficultySlider"); + getWidget(mKeyboardSwitch, "KeyboardButton"); + getWidget(mControllerSwitch, "ControllerButton"); #ifndef WIN32 // hide gamma controls since it currently does not work under Linux @@ -213,6 +216,9 @@ namespace MWGui mShadowsTextureSize->eventComboChangePosition += MyGUI::newDelegate(this, &SettingsWindow::onShadowTextureSizeChanged); + mKeyboardSwitch->eventMouseButtonClick += MyGUI::newDelegate(this, &SettingsWindow::onKeyboardSwitchClicked); + mControllerSwitch->eventMouseButtonClick += MyGUI::newDelegate(this, &SettingsWindow::onControllerSwitchClicked); + center(); mResetControlsButton->eventMouseButtonClick += MyGUI::newDelegate(this, &SettingsWindow::onResetDefaultBindings); @@ -260,9 +266,13 @@ namespace MWGui MyGUI::TextBox* diffText; getWidget(diffText, "DifficultyText"); + diffText->setCaptionWithReplacing("#{sDifficulty} (" + MyGUI::utility::toString(int(Settings::Manager::getInt("difficulty", "Game"))) + ")"); mWindowBorderButton->setEnabled(!Settings::Manager::getBool("fullscreen", "Video")); + + mKeyboardSwitch->setStateSelected(true); + mControllerSwitch->setStateSelected(false); } void SettingsWindow::onOkButtonClicked(MyGUI::Widget* _sender) @@ -462,14 +472,37 @@ namespace MWGui MWBase::Environment::get().getInputManager()->processChangedSettings(changed); } + void SettingsWindow::onKeyboardSwitchClicked(MyGUI::Widget* _sender) + { + if(mKeyboardMode) + return; + mKeyboardMode = true; + mKeyboardSwitch->setStateSelected(true); + mControllerSwitch->setStateSelected(false); + updateControlsBox(); + } + + void SettingsWindow::onControllerSwitchClicked(MyGUI::Widget* _sender) + { + if(!mKeyboardMode) + return; + mKeyboardMode = false; + mKeyboardSwitch->setStateSelected(false); + mControllerSwitch->setStateSelected(true); + updateControlsBox(); + } + void SettingsWindow::updateControlsBox() { while (mControlsBox->getChildCount()) MyGUI::Gui::getInstance().destroyWidget(mControlsBox->getChildAt(0)); - MWBase::Environment::get().getWindowManager ()->removeStaticMessageBox(); - - std::vector actions = MWBase::Environment::get().getInputManager()->getActionSorting (); + MWBase::Environment::get().getWindowManager()->removeStaticMessageBox(); + std::vector actions; + if(mKeyboardMode) + actions = MWBase::Environment::get().getInputManager()->getActionKeySorting(); + else + actions = MWBase::Environment::get().getInputManager()->getActionControllerSorting(); const int h = 18; const int w = mControlsBox->getWidth() - 28; @@ -480,7 +513,11 @@ namespace MWGui if (desc == "") continue; - std::string binding = MWBase::Environment::get().getInputManager()->getActionBindingName (*it); + std::string binding; + if(mKeyboardMode) + binding = MWBase::Environment::get().getInputManager()->getActionKeyBindingName(*it); + else + binding = MWBase::Environment::get().getInputManager()->getActionControllerBindingName(*it); Gui::SharedStateButton* leftText = mControlsBox->createWidget("SandTextButton", MyGUI::IntCoord(0,curH,w,h), MyGUI::Align::Default); leftText->setCaptionWithReplacing(desc); @@ -514,16 +551,16 @@ namespace MWGui MWBase::Environment::get().getWindowManager ()->staticMessageBox ("#{sControlsMenu3}"); MWBase::Environment::get().getWindowManager ()->disallowMouse(); - MWBase::Environment::get().getInputManager ()->enableDetectingBindingMode (actionId); + MWBase::Environment::get().getInputManager ()->enableDetectingBindingMode (actionId, mKeyboardMode); } void SettingsWindow::onInputTabMouseWheel(MyGUI::Widget* _sender, int _rel) { - if (mControlsBox->getViewOffset().top + _rel*0.3 > 0) + if (mControlsBox->getViewOffset().top + _rel*0.3f > 0) mControlsBox->setViewOffset(MyGUI::IntPoint(0, 0)); else - mControlsBox->setViewOffset(MyGUI::IntPoint(0, mControlsBox->getViewOffset().top + _rel*0.3)); + mControlsBox->setViewOffset(MyGUI::IntPoint(0, static_cast(mControlsBox->getViewOffset().top + _rel*0.3f))); } void SettingsWindow::onResetDefaultBindings(MyGUI::Widget* _sender) @@ -537,7 +574,10 @@ namespace MWGui void SettingsWindow::onResetDefaultBindingsAccept() { - MWBase::Environment::get().getInputManager ()->resetToDefaultBindings (); + if(mKeyboardMode) + MWBase::Environment::get().getInputManager ()->resetToDefaultKeyBindings (); + else + MWBase::Environment::get().getInputManager()->resetToDefaultControllerBindings(); updateControlsBox (); } diff --git a/apps/openmw/mwgui/settingswindow.hpp b/apps/openmw/mwgui/settingswindow.hpp index 8dcc8dd07..1b970b8de 100644 --- a/apps/openmw/mwgui/settingswindow.hpp +++ b/apps/openmw/mwgui/settingswindow.hpp @@ -46,6 +46,9 @@ namespace MWGui // controls MyGUI::ScrollView* mControlsBox; MyGUI::Button* mResetControlsButton; + MyGUI::Button* mKeyboardSwitch; + MyGUI::Button* mControllerSwitch; + bool mKeyboardMode; //if true, setting up the keyboard. Otherwise, it's controller void onOkButtonClicked(MyGUI::Widget* _sender); void onFpsToggled(MyGUI::Widget* _sender); @@ -63,6 +66,8 @@ namespace MWGui void onInputTabMouseWheel(MyGUI::Widget* _sender, int _rel); void onResetDefaultBindings(MyGUI::Widget* _sender); void onResetDefaultBindingsAccept (); + void onKeyboardSwitchClicked(MyGUI::Widget* _sender); + void onControllerSwitchClicked(MyGUI::Widget* _sender); void onWindowResize(MyGUI::Window* _sender); diff --git a/apps/openmw/mwgui/spellbuyingwindow.cpp b/apps/openmw/mwgui/spellbuyingwindow.cpp index 54094b606..57b02940e 100644 --- a/apps/openmw/mwgui/spellbuyingwindow.cpp +++ b/apps/openmw/mwgui/spellbuyingwindow.cpp @@ -46,7 +46,7 @@ namespace MWGui MWBase::Environment::get().getWorld()->getStore(); const ESM::Spell* spell = MWBase::Environment::get().getWorld()->getStore().get().find(spellId); - int price = spell->mData.mCost*store.get().find("fSpellValueMult")->getFloat(); + int price = static_cast(spell->mData.mCost*store.get().find("fSpellValueMult")->getFloat()); price = MWBase::Environment::get().getMechanicsManager()->getBarterOffer(mPtr,price,true); MWWorld::Ptr player = MWBase::Environment::get().getWorld()->getPlayerPtr(); @@ -187,7 +187,7 @@ namespace MWGui if (mSpellsView->getViewOffset().top + _rel*0.3 > 0) mSpellsView->setViewOffset(MyGUI::IntPoint(0, 0)); else - mSpellsView->setViewOffset(MyGUI::IntPoint(0, mSpellsView->getViewOffset().top + _rel*0.3)); + mSpellsView->setViewOffset(MyGUI::IntPoint(0, static_cast(mSpellsView->getViewOffset().top + _rel*0.3f))); } } diff --git a/apps/openmw/mwgui/spellcreationdialog.cpp b/apps/openmw/mwgui/spellcreationdialog.cpp index f4c9d021a..c744d3ed6 100644 --- a/apps/openmw/mwgui/spellcreationdialog.cpp +++ b/apps/openmw/mwgui/spellcreationdialog.cpp @@ -114,7 +114,7 @@ namespace MWGui void EditEffectDialog::newEffect (const ESM::MagicEffect *effect) { - bool allowSelf = effect->mData.mFlags & ESM::MagicEffect::CastSelf; + bool allowSelf = (effect->mData.mFlags & ESM::MagicEffect::CastSelf) != 0; bool allowTouch = (effect->mData.mFlags & ESM::MagicEffect::CastTouch) && !mConstantEffect; bool allowTarget = (effect->mData.mFlags & ESM::MagicEffect::CastTarget) && !mConstantEffect; @@ -226,7 +226,7 @@ namespace MWGui // cycle through range types until we find something that's allowed // does not handle the case where nothing is allowed (this should be prevented before opening the Add Effect dialog) - bool allowSelf = mMagicEffect->mData.mFlags & ESM::MagicEffect::CastSelf; + bool allowSelf = (mMagicEffect->mData.mFlags & ESM::MagicEffect::CastSelf) != 0; bool allowTouch = (mMagicEffect->mData.mFlags & ESM::MagicEffect::CastTouch) && !mConstantEffect; bool allowTarget = (mMagicEffect->mData.mFlags & ESM::MagicEffect::CastTarget) && !mConstantEffect; if (mEffect.mRange == ESM::RT_Self && !allowSelf) @@ -440,14 +440,14 @@ namespace MWGui for (std::vector::const_iterator it = mEffects.begin(); it != mEffects.end(); ++it) { - float x = 0.5 * (it->mMagnMin + it->mMagnMax); + float x = 0.5f * (it->mMagnMin + it->mMagnMax); const ESM::MagicEffect* effect = store.get().find(it->mEffectID); - x *= 0.1 * effect->mData.mBaseCost; + x *= 0.1f * effect->mData.mBaseCost; x *= 1 + it->mDuration; - x += 0.05 * std::max(1, it->mArea) * effect->mData.mBaseCost; + x += 0.05f * std::max(1, it->mArea) * effect->mData.mBaseCost; float fEffectCostMult = store.get().find("fEffectCostMult")->getFloat(); @@ -471,7 +471,7 @@ namespace MWGui float fSpellMakingValueMult = store.get().find("fSpellMakingValueMult")->getFloat(); - int price = MWBase::Environment::get().getMechanicsManager()->getBarterOffer(mPtr,int(y) * fSpellMakingValueMult,true); + int price = MWBase::Environment::get().getMechanicsManager()->getBarterOffer(mPtr, static_cast(y * fSpellMakingValueMult),true); mPriceLabel->setCaption(MyGUI::utility::toString(int(price))); diff --git a/apps/openmw/mwgui/spellicons.cpp b/apps/openmw/mwgui/spellicons.cpp index 20c6f3ba8..c597cfaeb 100644 --- a/apps/openmw/mwgui/spellicons.cpp +++ b/apps/openmw/mwgui/spellicons.cpp @@ -30,7 +30,7 @@ namespace MWGui { MagicEffectInfo newEffectSource; newEffectSource.mKey = key; - newEffectSource.mMagnitude = magnitude; + newEffectSource.mMagnitude = static_cast(magnitude); newEffectSource.mPermanent = mIsPermanent; newEffectSource.mRemainingTime = remainingTime; newEffectSource.mSource = sourceName; diff --git a/apps/openmw/mwgui/spellmodel.cpp b/apps/openmw/mwgui/spellmodel.cpp index 4713720cd..91512a011 100644 --- a/apps/openmw/mwgui/spellmodel.cpp +++ b/apps/openmw/mwgui/spellmodel.cpp @@ -103,7 +103,7 @@ namespace MWGui && item.getClass().canBeEquipped(item, mActor).first == 0) continue; - int castCost = MWMechanics::getEffectiveEnchantmentCastCost(enchant->mData.mCost, mActor); + int castCost = MWMechanics::getEffectiveEnchantmentCastCost(static_cast(enchant->mData.mCost), mActor); std::string cost = boost::lexical_cast(castCost); int currentCharge = int(item.getCellRef().getEnchantmentCharge()); diff --git a/apps/openmw/mwgui/spellview.cpp b/apps/openmw/mwgui/spellview.cpp index 1c17a11f6..668b239bc 100644 --- a/apps/openmw/mwgui/spellview.cpp +++ b/apps/openmw/mwgui/spellview.cpp @@ -236,10 +236,10 @@ namespace MWGui void SpellView::onMouseWheel(MyGUI::Widget* _sender, int _rel) { - if (mScrollView->getViewOffset().top + _rel*0.3 > 0) + if (mScrollView->getViewOffset().top + _rel*0.3f > 0) mScrollView->setViewOffset(MyGUI::IntPoint(0, 0)); else - mScrollView->setViewOffset(MyGUI::IntPoint(0, mScrollView->getViewOffset().top + _rel*0.3)); + mScrollView->setViewOffset(MyGUI::IntPoint(0, static_cast(mScrollView->getViewOffset().top + _rel*0.3f))); } } diff --git a/apps/openmw/mwgui/spellwindow.cpp b/apps/openmw/mwgui/spellwindow.cpp index 69365c108..cc032691e 100644 --- a/apps/openmw/mwgui/spellwindow.cpp +++ b/apps/openmw/mwgui/spellwindow.cpp @@ -102,6 +102,31 @@ namespace MWGui updateSpells(); } + void SpellWindow::askDeleteSpell(const std::string &spellId) + { + // delete spell, if allowed + const ESM::Spell* spell = + MWBase::Environment::get().getWorld()->getStore().get().find(spellId); + + if (spell->mData.mFlags & ESM::Spell::F_Always + || spell->mData.mType == ESM::Spell::ST_Power) + { + MWBase::Environment::get().getWindowManager()->messageBox("#{sDeleteSpellError}"); + } + else + { + // ask for confirmation + mSpellToDelete = spellId; + ConfirmationDialog* dialog = MWBase::Environment::get().getWindowManager()->getConfirmationDialog(); + std::string question = MWBase::Environment::get().getWindowManager()->getGameSettingString("sQuestionDeleteSpell", "Delete %s?"); + question = boost::str(boost::format(question) % spell->mName); + dialog->open(question); + dialog->eventOkClicked.clear(); + dialog->eventOkClicked += MyGUI::newDelegate(this, &SpellWindow::onDeleteSpellAccept); + dialog->eventCancelClicked.clear(); + } + } + void SpellWindow::onModelIndexSelected(SpellModel::ModelIndex index) { const Spell& spell = mSpellView->getModel()->getItem(index); @@ -111,43 +136,19 @@ namespace MWGui } else { - onSpellSelected(spell.mId); + if (MyGUI::InputManager::getInstance().isShiftPressed()) + askDeleteSpell(spell.mId); + else + onSpellSelected(spell.mId); } } void SpellWindow::onSpellSelected(const std::string& spellId) { - if (MyGUI::InputManager::getInstance().isShiftPressed()) - { - // delete spell, if allowed - const ESM::Spell* spell = - MWBase::Environment::get().getWorld()->getStore().get().find(spellId); - - if (spell->mData.mFlags & ESM::Spell::F_Always - || spell->mData.mType == ESM::Spell::ST_Power) - { - MWBase::Environment::get().getWindowManager()->messageBox("#{sDeleteSpellError}"); - } - else - { - // ask for confirmation - mSpellToDelete = spellId; - ConfirmationDialog* dialog = MWBase::Environment::get().getWindowManager()->getConfirmationDialog(); - std::string question = MWBase::Environment::get().getWindowManager()->getGameSettingString("sQuestionDeleteSpell", "Delete %s?"); - question = boost::str(boost::format(question) % spell->mName); - dialog->open(question); - dialog->eventOkClicked.clear(); - dialog->eventOkClicked += MyGUI::newDelegate(this, &SpellWindow::onDeleteSpellAccept); - dialog->eventCancelClicked.clear(); - } - } - else - { - MWWorld::Ptr player = MWBase::Environment::get().getWorld()->getPlayerPtr(); - MWWorld::InventoryStore& store = player.getClass().getInventoryStore(player); - store.setSelectedEnchantItem(store.end()); - MWBase::Environment::get().getWindowManager()->setSelectedSpell(spellId, int(MWMechanics::getSpellSuccessChance(spellId, player))); - } + MWWorld::Ptr player = MWBase::Environment::get().getWorld()->getPlayerPtr(); + MWWorld::InventoryStore& store = player.getClass().getInventoryStore(player); + store.setSelectedEnchantItem(store.end()); + MWBase::Environment::get().getWindowManager()->setSelectedSpell(spellId, int(MWMechanics::getSpellSuccessChance(spellId, player))); updateSpells(); } @@ -184,6 +185,10 @@ namespace MWGui return; selected = (selected + itemcount) % itemcount; - onModelIndexSelected(selected); + const Spell& spell = mSpellView->getModel()->getItem(selected); + if (spell.mType == Spell::Type_EnchantedItem) + onEnchantedItemSelected(spell.mItem, spell.mActive); + else + onSpellSelected(spell.mId); } } diff --git a/apps/openmw/mwgui/spellwindow.hpp b/apps/openmw/mwgui/spellwindow.hpp index 650218d30..8b5474f58 100644 --- a/apps/openmw/mwgui/spellwindow.hpp +++ b/apps/openmw/mwgui/spellwindow.hpp @@ -33,6 +33,7 @@ namespace MWGui void onSpellSelected(const std::string& spellId); void onModelIndexSelected(SpellModel::ModelIndex index); void onDeleteSpellAccept(); + void askDeleteSpell(const std::string& spellId); virtual void onPinToggled(); virtual void onTitleDoubleClicked(); diff --git a/apps/openmw/mwgui/statswindow.cpp b/apps/openmw/mwgui/statswindow.cpp index 2a22f4239..cb1bf6f37 100644 --- a/apps/openmw/mwgui/statswindow.cpp +++ b/apps/openmw/mwgui/statswindow.cpp @@ -80,13 +80,13 @@ namespace MWGui if (mSkillView->getViewOffset().top + _rel*0.3 > 0) mSkillView->setViewOffset(MyGUI::IntPoint(0, 0)); else - mSkillView->setViewOffset(MyGUI::IntPoint(0, mSkillView->getViewOffset().top + _rel*0.3)); + mSkillView->setViewOffset(MyGUI::IntPoint(0, static_cast(mSkillView->getViewOffset().top + _rel*0.3))); } void StatsWindow::onWindowResize(MyGUI::Window* window) { - mLeftPane->setCoord( MyGUI::IntCoord(0, 0, 0.44*window->getSize().width, window->getSize().height) ); - mRightPane->setCoord( MyGUI::IntCoord(0.44*window->getSize().width, 0, 0.56*window->getSize().width, window->getSize().height) ); + mLeftPane->setCoord( MyGUI::IntCoord(0, 0, static_cast(0.44*window->getSize().width), window->getSize().height) ); + mRightPane->setCoord( MyGUI::IntCoord(static_cast(0.44*window->getSize().width), 0, static_cast(0.56*window->getSize().width), window->getSize().height) ); // Canvas size must be expressed with VScroll disabled, otherwise MyGUI would expand the scroll area when the scrollbar is hidden mSkillView->setVisibleVScroll(false); mSkillView->setCanvasSize (mSkillView->getWidth(), mSkillView->getCanvasSize().height); diff --git a/apps/openmw/mwgui/tooltips.cpp b/apps/openmw/mwgui/tooltips.cpp index 2c10004a6..4e03b788a 100644 --- a/apps/openmw/mwgui/tooltips.cpp +++ b/apps/openmw/mwgui/tooltips.cpp @@ -308,7 +308,7 @@ namespace MWGui void ToolTips::position(MyGUI::IntPoint& position, MyGUI::IntSize size, MyGUI::IntSize viewportSize) { position += MyGUI::IntPoint(0, 32) - - MyGUI::IntPoint((MyGUI::InputManager::getInstance().getMousePosition().left / float(viewportSize.width) * size.width), 0); + - MyGUI::IntPoint(static_cast(MyGUI::InputManager::getInstance().getMousePosition().left / float(viewportSize.width) * size.width), 0); if ((position.left + size.width) > viewportSize.width) { @@ -413,7 +413,7 @@ namespace MWGui { MyGUI::ImageBox* icon = mDynamicToolTipBox->createWidget("MarkerButton", MyGUI::IntCoord(padding.left, totalSize.height+padding.top, 8, 8), MyGUI::Align::Default); - icon->setColour(MyGUI::Colour(1.0,0.3,0.3)); + icon->setColour(MyGUI::Colour(1.0f, 0.3f, 0.3f)); MyGUI::EditBox* edit = mDynamicToolTipBox->createWidget("SandText", MyGUI::IntCoord(padding.left+8+4, totalSize.height+padding.top, 300-padding.left-8-4, 300-totalSize.height), MyGUI::Align::Default); diff --git a/apps/openmw/mwgui/tooltips.hpp b/apps/openmw/mwgui/tooltips.hpp index 4bd4d88aa..71b4a560f 100644 --- a/apps/openmw/mwgui/tooltips.hpp +++ b/apps/openmw/mwgui/tooltips.hpp @@ -9,7 +9,7 @@ namespace ESM { - class Class; + struct Class; struct Race; } diff --git a/apps/openmw/mwgui/tradewindow.cpp b/apps/openmw/mwgui/tradewindow.cpp index 40cf3e9bf..42491a5e8 100644 --- a/apps/openmw/mwgui/tradewindow.cpp +++ b/apps/openmw/mwgui/tradewindow.cpp @@ -4,6 +4,8 @@ #include #include +#include + #include #include "../mwbase/environment.hpp" @@ -34,18 +36,21 @@ namespace int getEffectiveValue (MWWorld::Ptr item, int count) { - int price = item.getClass().getValue(item) * count; + float price = static_cast(item.getClass().getValue(item)); if (item.getClass().hasItemHealth(item)) - price *= (static_cast(item.getClass().getItemHealth(item)) / item.getClass().getItemMaxHealth(item)); - return price; + { + price *= item.getClass().getItemHealth(item); + price /= item.getClass().getItemMaxHealth(item); + } + return static_cast(price * count); } } namespace MWGui { - const float TradeWindow::sBalanceChangeInitialPause = 0.5; - const float TradeWindow::sBalanceChangeInterval = 0.1; + const float TradeWindow::sBalanceChangeInitialPause = 0.5f; + const float TradeWindow::sBalanceChangeInterval = 0.1f; TradeWindow::TradeWindow() : WindowBase("openmw_trade_window.layout") @@ -340,16 +345,16 @@ namespace MWGui else d = int(100 * (b - a) / a); - float clampedDisposition = std::max(0,std::min(int(MWBase::Environment::get().getMechanicsManager()->getDerivedDisposition(mPtr) - + MWBase::Environment::get().getDialogueManager()->getTemporaryDispositionChange()),100)); + int clampedDisposition = std::max(0, std::min(MWBase::Environment::get().getMechanicsManager()->getDerivedDisposition(mPtr) + + MWBase::Environment::get().getDialogueManager()->getTemporaryDispositionChange(),100)); const MWMechanics::CreatureStats &sellerStats = mPtr.getClass().getCreatureStats(mPtr); const MWMechanics::CreatureStats &playerStats = player.getClass().getCreatureStats(player); - float a1 = player.getClass().getSkill(player, ESM::Skill::Mercantile); + float a1 = static_cast(player.getClass().getSkill(player, ESM::Skill::Mercantile)); float b1 = 0.1f * playerStats.getAttribute(ESM::Attribute::Luck).getModified(); float c1 = 0.2f * playerStats.getAttribute(ESM::Attribute::Personality).getModified(); - float d1 = mPtr.getClass().getSkill(mPtr, ESM::Skill::Mercantile); + float d1 = static_cast(mPtr.getClass().getSkill(mPtr, ESM::Skill::Mercantile)); float e1 = 0.1f * sellerStats.getAttribute(ESM::Attribute::Luck).getModified(); float f1 = 0.2f * sellerStats.getAttribute(ESM::Attribute::Personality).getModified(); @@ -362,7 +367,7 @@ namespace MWGui else x += abs(int(npcTerm - pcTerm)); - int roll = std::rand()%100 + 1; + int roll = OEngine::Misc::Rng::rollDice(100) + 1; if(roll > x || (mCurrentMerchantOffer < 0) != (mCurrentBalance < 0)) //trade refused { MWBase::Environment::get().getWindowManager()-> @@ -379,9 +384,9 @@ namespace MWGui int finalPrice = std::abs(mCurrentBalance); int initialMerchantOffer = std::abs(mCurrentMerchantOffer); if (!buying && (finalPrice > initialMerchantOffer) && finalPrice > 0) - skillGain = int(100 * (finalPrice - initialMerchantOffer) / float(finalPrice)); + skillGain = floor(100 * (finalPrice - initialMerchantOffer) / float(finalPrice)); else if (buying && (finalPrice < initialMerchantOffer) && initialMerchantOffer > 0) - skillGain = int(100 * (initialMerchantOffer - finalPrice) / float(initialMerchantOffer)); + skillGain = floor(100 * (initialMerchantOffer - finalPrice) / float(initialMerchantOffer)); player.getClass().skillUsageSucceeded(player, ESM::Skill::Mercantile, 0, skillGain); } diff --git a/apps/openmw/mwgui/trainingwindow.cpp b/apps/openmw/mwgui/trainingwindow.cpp index 5a5f61115..6376ced57 100644 --- a/apps/openmw/mwgui/trainingwindow.cpp +++ b/apps/openmw/mwgui/trainingwindow.cpp @@ -40,7 +40,7 @@ namespace MWGui TrainingWindow::TrainingWindow() : WindowBase("openmw_trainingwindow.layout") , mFadeTimeRemaining(0) - , mTimeAdvancer(0.05) + , mTimeAdvancer(0.05f) { getWidget(mTrainingOptions, "TrainingOptions"); getWidget(mCancelButton, "CancelButton"); diff --git a/apps/openmw/mwgui/travelwindow.cpp b/apps/openmw/mwgui/travelwindow.cpp index 50e08223e..4da1ab33a 100644 --- a/apps/openmw/mwgui/travelwindow.cpp +++ b/apps/openmw/mwgui/travelwindow.cpp @@ -66,13 +66,13 @@ namespace MWGui if(interior) { - price = gmst.find("fMagesGuildTravel")->getFloat(); + price = gmst.find("fMagesGuildTravel")->getInt(); } else { ESM::Position PlayerPos = player.getRefData().getPosition(); float d = sqrt( pow(pos.pos[0] - PlayerPos.pos[0],2) + pow(pos.pos[1] - PlayerPos.pos[1],2) + pow(pos.pos[2] - PlayerPos.pos[2],2) ); - price = d/gmst.find("fTravelMult")->getFloat(); + price = static_cast(d / gmst.find("fTravelMult")->getFloat()); } price = MWBase::Environment::get().getMechanicsManager()->getBarterOffer(mPtr,price,true); @@ -111,20 +111,26 @@ namespace MWGui mPtr = actor; clearDestinations(); - for(unsigned int i = 0;i()->mBase->mTransport.size();i++) + std::vector transport; + if (mPtr.getClass().isNpc()) + transport = mPtr.get()->mBase->getTransport(); + else if (mPtr.getTypeName() == typeid(ESM::Creature).name()) + transport = mPtr.get()->mBase->getTransport(); + + for(unsigned int i = 0;i()->mBase->mTransport[i].mCellName; + std::string cellname = transport[i].mCellName; bool interior = true; int x,y; - MWBase::Environment::get().getWorld()->positionToIndex(mPtr.get()->mBase->mTransport[i].mPos.pos[0], - mPtr.get()->mBase->mTransport[i].mPos.pos[1],x,y); + MWBase::Environment::get().getWorld()->positionToIndex(transport[i].mPos.pos[0], + transport[i].mPos.pos[1],x,y); if (cellname == "") { MWWorld::CellStore* cell = MWBase::Environment::get().getWorld()->getExterior(x,y); cellname = MWBase::Environment::get().getWorld()->getCellName(cell); interior = false; } - addDestination(cellname,mPtr.get()->mBase->mTransport[i].mPos,interior); + addDestination(cellname,transport[i].mPos,interior); } updateLabels(); @@ -209,10 +215,10 @@ namespace MWGui void TravelWindow::onMouseWheel(MyGUI::Widget* _sender, int _rel) { - if (mDestinationsView->getViewOffset().top + _rel*0.3 > 0) + if (mDestinationsView->getViewOffset().top + _rel*0.3f > 0) mDestinationsView->setViewOffset(MyGUI::IntPoint(0, 0)); else - mDestinationsView->setViewOffset(MyGUI::IntPoint(0, mDestinationsView->getViewOffset().top + _rel*0.3)); + mDestinationsView->setViewOffset(MyGUI::IntPoint(0, static_cast(mDestinationsView->getViewOffset().top + _rel*0.3f))); } } diff --git a/apps/openmw/mwgui/videowidget.cpp b/apps/openmw/mwgui/videowidget.cpp index 046070841..f865de377 100644 --- a/apps/openmw/mwgui/videowidget.cpp +++ b/apps/openmw/mwgui/videowidget.cpp @@ -58,8 +58,8 @@ void VideoWidget::autoResize(bool stretch) { double imageaspect = static_cast(getVideoWidth())/getVideoHeight(); - int leftPadding = std::max(0.0, (screenSize.width - screenSize.height * imageaspect) / 2); - int topPadding = std::max(0.0, (screenSize.height - screenSize.width / imageaspect) / 2); + int leftPadding = std::max(0, static_cast(screenSize.width - screenSize.height * imageaspect) / 2); + int topPadding = std::max(0, static_cast(screenSize.height - screenSize.width / imageaspect) / 2); setCoord(leftPadding, topPadding, screenSize.width - leftPadding*2, screenSize.height - topPadding*2); diff --git a/apps/openmw/mwgui/waitdialog.cpp b/apps/openmw/mwgui/waitdialog.cpp index ad873a7c3..f74b06891 100644 --- a/apps/openmw/mwgui/waitdialog.cpp +++ b/apps/openmw/mwgui/waitdialog.cpp @@ -2,6 +2,8 @@ #include +#include + #include #include @@ -49,7 +51,7 @@ namespace MWGui WaitDialog::WaitDialog() : WindowBase("openmw_wait_dialog.layout") , mProgressBar() - , mTimeAdvancer(0.05) + , mTimeAdvancer(0.05f) , mSleeping(false) , mHours(1) , mManualHours(1) @@ -104,7 +106,7 @@ namespace MWGui mHourSlider->setScrollPosition (0); std::string month = MWBase::Environment::get().getWorld ()->getMonthName(); - int hour = MWBase::Environment::get().getWorld ()->getTimeStamp ().getHour (); + int hour = static_cast(MWBase::Environment::get().getWorld()->getTimeStamp().getHour()); bool pm = hour >= 12; if (hour >= 13) hour -= 12; if (hour == 0) hour = 12; @@ -135,8 +137,8 @@ namespace MWGui MWBase::Environment::get().getStateManager()->quickSave("Autosave"); MWBase::World* world = MWBase::Environment::get().getWorld(); - MWBase::Environment::get().getWindowManager()->fadeScreenOut(0.2); - mFadeTimeRemaining = 0.4; + MWBase::Environment::get().getWindowManager()->fadeScreenOut(0.2f); + mFadeTimeRemaining = 0.4f; setVisible(false); mHours = hoursToWait; @@ -152,10 +154,9 @@ namespace MWGui const ESM::Region *region = world->getStore().get().find (regionstr); if (!region->mSleepList.empty()) { + // figure out if player will be woken while sleeping float fSleepRandMod = world->getStore().get().find("fSleepRandMod")->getFloat(); - int x = std::rand()/ (static_cast (RAND_MAX) + 1) * hoursToWait; // [0, hoursRested] - float y = fSleepRandMod * hoursToWait; - if (x > y) + if (OEngine::Misc::Rng::rollProbability() > fSleepRandMod) { float fSleepRestMod = world->getStore().get().find("fSleepRestMod")->getFloat(); mInterruptAt = hoursToWait - int(fSleepRestMod * hoursToWait); @@ -251,7 +252,7 @@ namespace MWGui void WaitDialog::stopWaiting () { - MWBase::Environment::get().getWindowManager()->fadeScreenIn(0.2); + MWBase::Environment::get().getWindowManager()->fadeScreenIn(0.2f); mProgressBar.setVisible (false); MWBase::Environment::get().getWindowManager()->removeGuiMode (GM_Rest); MWBase::Environment::get().getWindowManager()->removeGuiMode (GM_RestBed); diff --git a/apps/openmw/mwgui/widgets.cpp b/apps/openmw/mwgui/widgets.cpp index 26fe31567..718624a16 100644 --- a/apps/openmw/mwgui/widgets.cpp +++ b/apps/openmw/mwgui/widgets.cpp @@ -239,7 +239,7 @@ namespace MWGui params.mMagnMin = it->mMagnMin; params.mMagnMax = it->mMagnMax; params.mRange = it->mRange; - params.mIsConstant = (flags & MWEffectList::EF_Constant); + params.mIsConstant = (flags & MWEffectList::EF_Constant) != 0; params.mNoTarget = (flags & MWEffectList::EF_NoTarget); effect->setSpellEffect(params); effects.push_back(effect); @@ -540,8 +540,8 @@ namespace MWGui MWScrollBar::MWScrollBar() : mEnableRepeat(true) - , mRepeatTriggerTime(0.5) - , mRepeatStepTime(0.1) + , mRepeatTriggerTime(0.5f) + , mRepeatStepTime(0.1f) , mIsIncreasing(true) { } diff --git a/apps/openmw/mwgui/windowmanagerimp.cpp b/apps/openmw/mwgui/windowmanagerimp.cpp index c74cff31c..279c2f22e 100644 --- a/apps/openmw/mwgui/windowmanagerimp.cpp +++ b/apps/openmw/mwgui/windowmanagerimp.cpp @@ -565,11 +565,11 @@ namespace MWGui int eff = mShown & mAllowed & ~mForceHidden; // Show the windows we want - mMap ->setVisible(eff & GW_Map); - mStatsWindow ->setVisible(eff & GW_Stats); - mInventoryWindow->setVisible(eff & GW_Inventory); + mMap ->setVisible((eff & GW_Map) != 0); + mStatsWindow ->setVisible((eff & GW_Stats) != 0); + mInventoryWindow->setVisible((eff & GW_Inventory) != 0); mInventoryWindow->setGuiMode(mode); - mSpellWindow ->setVisible(eff & GW_Magic); + mSpellWindow ->setVisible((eff & GW_Magic) != 0); break; } case GM_Container: @@ -715,16 +715,6 @@ namespace MWGui mPlayerMinorSkills = minor; } - void WindowManager::setReputation (int reputation) - { - mStatsWindow->setReputation (reputation); - } - - void WindowManager::setBounty (int bounty) - { - mStatsWindow->setBounty (bounty); - } - void WindowManager::updateSkillArea() { mStatsWindow->updateSkillArea(); @@ -1103,10 +1093,10 @@ namespace MWGui for (std::map::iterator it = mTrackedWindows.begin(); it != mTrackedWindows.end(); ++it) { - MyGUI::IntPoint pos (Settings::Manager::getFloat(it->second + " x", "Windows") * x, - Settings::Manager::getFloat(it->second+ " y", "Windows") * y); - MyGUI::IntSize size (Settings::Manager::getFloat(it->second + " w", "Windows") * x, - Settings::Manager::getFloat(it->second + " h", "Windows") * y); + MyGUI::IntPoint pos(static_cast(Settings::Manager::getFloat(it->second + " x", "Windows") * x), + static_cast( Settings::Manager::getFloat(it->second+ " y", "Windows") * y)); + MyGUI::IntSize size(static_cast(Settings::Manager::getFloat(it->second + " w", "Windows") * x), + static_cast(Settings::Manager::getFloat(it->second + " h", "Windows") * y)); it->first->setPosition(pos); it->first->setSize(size); } @@ -1221,7 +1211,7 @@ namespace MWGui .find(item.getClass().getEnchantment(item)); int chargePercent = (item.getCellRef().getEnchantmentCharge() == -1) ? 100 - : (item.getCellRef().getEnchantmentCharge() / static_cast(ench->mData.mCharge) * 100); + : static_cast(item.getCellRef().getEnchantmentCharge() / static_cast(ench->mData.mCharge) * 100); mHud->setSelectedEnchantItem(item, chargePercent); mSpellWindow->setTitle(item.getClass().getName(item)); } @@ -1229,7 +1219,7 @@ namespace MWGui void WindowManager::setSelectedWeapon(const MWWorld::Ptr& item) { int durabilityPercent = - (item.getClass().getItemHealth(item) / static_cast(item.getClass().getItemMaxHealth(item)) * 100); + static_cast(item.getClass().getItemHealth(item) / static_cast(item.getClass().getItemMaxHealth(item)) * 100); mHud->setSelectedWeapon(item, durabilityPercent); mInventoryWindow->setTitle(item.getClass().getName(item)); } @@ -1262,8 +1252,8 @@ namespace MWGui void WindowManager::getMousePosition(float &x, float &y) { const MyGUI::IntPoint& pos = MyGUI::InputManager::getInstance().getMousePosition(); - x = pos.left; - y = pos.top; + x = static_cast(pos.left); + y = static_cast(pos.top); const MyGUI::IntSize& viewSize = MyGUI::RenderManager::getInstance().getViewSize(); x /= viewSize.width; y /= viewSize.height; @@ -1287,21 +1277,14 @@ namespace MWGui } MWGui::DialogueWindow* WindowManager::getDialogueWindow() { return mDialogueWindow; } - MWGui::ContainerWindow* WindowManager::getContainerWindow() { return mContainerWindow; } MWGui::InventoryWindow* WindowManager::getInventoryWindow() { return mInventoryWindow; } - MWGui::BookWindow* WindowManager::getBookWindow() { return mBookWindow; } - MWGui::ScrollWindow* WindowManager::getScrollWindow() { return mScrollWindow; } MWGui::CountDialog* WindowManager::getCountDialog() { return mCountDialog; } MWGui::ConfirmationDialog* WindowManager::getConfirmationDialog() { return mConfirmationDialog; } MWGui::TradeWindow* WindowManager::getTradeWindow() { return mTradeWindow; } - MWGui::SpellBuyingWindow* WindowManager::getSpellBuyingWindow() { return mSpellBuyingWindow; } - MWGui::TravelWindow* WindowManager::getTravelWindow() { return mTravelWindow; } - MWGui::SpellWindow* WindowManager::getSpellWindow() { return mSpellWindow; } - MWGui::Console* WindowManager::getConsole() { return mConsole; } bool WindowManager::isAllowed (GuiWindow wnd) const { - return mAllowed & wnd; + return (mAllowed & wnd) != 0; } void WindowManager::allow (GuiWindow wnd) @@ -1459,11 +1442,13 @@ namespace MWGui void WindowManager::startSpellMaking(MWWorld::Ptr actor) { + pushGuiMode(GM_SpellCreation); mSpellCreationDialog->startSpellMaking (actor); } void WindowManager::startEnchanting (MWWorld::Ptr actor) { + pushGuiMode(GM_Enchanting); mEnchantingDialog->startEnchanting (actor); } @@ -1474,16 +1459,19 @@ namespace MWGui void WindowManager::startTraining(MWWorld::Ptr actor) { + pushGuiMode(GM_Training); mTrainingWindow->startTraining(actor); } void WindowManager::startRepair(MWWorld::Ptr actor) { + pushGuiMode(GM_MerchantRepair); mMerchantRepair->startRepair(actor); } void WindowManager::startRepairItem(MWWorld::Ptr item) { + pushGuiMode(MWGui::GM_Repair); mRepair->startRepairItem(item); } @@ -1494,6 +1482,7 @@ namespace MWGui void WindowManager::showCompanionWindow(MWWorld::Ptr actor) { + pushGuiMode(MWGui::GM_Companion); mCompanionWindow->open(actor); } @@ -1569,10 +1558,10 @@ namespace MWGui void WindowManager::trackWindow(OEngine::GUI::Layout *layout, const std::string &name) { MyGUI::IntSize viewSize = MyGUI::RenderManager::getInstance().getViewSize(); - MyGUI::IntPoint pos (Settings::Manager::getFloat(name + " x", "Windows") * viewSize.width, - Settings::Manager::getFloat(name + " y", "Windows") * viewSize.height); - MyGUI::IntSize size (Settings::Manager::getFloat(name + " w", "Windows") * viewSize.width, - Settings::Manager::getFloat(name + " h", "Windows") * viewSize.height); + MyGUI::IntPoint pos(static_cast(Settings::Manager::getFloat(name + " x", "Windows") * viewSize.width), + static_cast(Settings::Manager::getFloat(name + " y", "Windows") * viewSize.height)); + MyGUI::IntSize size (static_cast(Settings::Manager::getFloat(name + " w", "Windows") * viewSize.width), + static_cast(Settings::Manager::getFloat(name + " h", "Windows") * viewSize.height)); layout->mMainWidget->setPosition(pos); layout->mMainWidget->setSize(size); @@ -1744,12 +1733,10 @@ namespace MWGui mVideoWidget->autoResize(stretch); } - WindowModal* WindowManager::getCurrentModal() const + void WindowManager::exitCurrentModal() { - if(!mCurrentModals.empty()) - return mCurrentModals.top(); - else - return NULL; + if (!mCurrentModals.empty()) + mCurrentModals.top()->exit(); } void WindowManager::removeCurrentModal(WindowModal* input) @@ -1874,4 +1861,51 @@ namespace MWGui mInventoryWindow->cycle(next); } + void WindowManager::setConsoleSelectedObject(const MWWorld::Ptr &object) + { + mConsole->setSelectedObject(object); + } + + void WindowManager::updateSpellWindow() + { + if (mSpellWindow) + mSpellWindow->updateSpells(); + } + + void WindowManager::startTravel(const MWWorld::Ptr &actor) + { + pushGuiMode(GM_Travel); + mTravelWindow->startTravel(actor); + } + + void WindowManager::startSpellBuying(const MWWorld::Ptr &actor) + { + pushGuiMode(GM_SpellBuying); + mSpellBuyingWindow->startSpellBuying(actor); + } + + void WindowManager::startTrade(const MWWorld::Ptr &actor) + { + pushGuiMode(GM_Barter); + mTradeWindow->startTrade(actor); + } + + void WindowManager::openContainer(const MWWorld::Ptr &container, bool loot) + { + pushGuiMode(GM_Container); + mContainerWindow->open(container, loot); + } + + void WindowManager::showBook(const MWWorld::Ptr &item, bool showTakeButton) + { + pushGuiMode(GM_Book); + mBookWindow->open(item, showTakeButton); + } + + void WindowManager::showScroll(const MWWorld::Ptr &item, bool showTakeButton) + { + pushGuiMode(GM_Scroll); + mScrollWindow->open(item, showTakeButton); + } + } diff --git a/apps/openmw/mwgui/windowmanagerimp.hpp b/apps/openmw/mwgui/windowmanagerimp.hpp index 735b02d2d..297480d20 100644 --- a/apps/openmw/mwgui/windowmanagerimp.hpp +++ b/apps/openmw/mwgui/windowmanagerimp.hpp @@ -65,7 +65,7 @@ namespace MWGui class MainMenu; class StatsWindow; class InventoryWindow; - class JournalWindow; + struct JournalWindow; class CharacterCreation; class DragAndDrop; class ToolTips; @@ -154,17 +154,14 @@ namespace MWGui /// \todo investigate, if we really need to expose every single lousy UI element to the outside world virtual MWGui::DialogueWindow* getDialogueWindow(); - virtual MWGui::ContainerWindow* getContainerWindow(); virtual MWGui::InventoryWindow* getInventoryWindow(); - virtual MWGui::BookWindow* getBookWindow(); - virtual MWGui::ScrollWindow* getScrollWindow(); virtual MWGui::CountDialog* getCountDialog(); virtual MWGui::ConfirmationDialog* getConfirmationDialog(); virtual MWGui::TradeWindow* getTradeWindow(); - virtual MWGui::SpellBuyingWindow* getSpellBuyingWindow(); - virtual MWGui::TravelWindow* getTravelWindow(); - virtual MWGui::SpellWindow* getSpellWindow(); - virtual MWGui::Console* getConsole(); + + virtual void updateSpellWindow(); + + virtual void setConsoleSelectedObject(const MWWorld::Ptr& object); virtual void wmUpdateFps(float fps, unsigned int triangleCount, unsigned int batchCount); @@ -182,8 +179,6 @@ namespace MWGui virtual void setPlayerClass (const ESM::Class &class_); ///< set current class of player virtual void configureSkills (const SkillList& major, const SkillList& minor); ///< configure skill groups, each set contains the skill ID for that group. - virtual void setReputation (int reputation); ///< set the current reputation value - virtual void setBounty (int bounty); ///< set the current bounty value virtual void updateSkillArea(); ///< update display of skills, factions, birth sign, reputation and bounty virtual void changeCell(MWWorld::CellStore* cell); ///< change the active cell @@ -277,7 +272,7 @@ namespace MWGui virtual void enableRest() { mRestAllowed = true; } virtual bool getRestEnabled(); - virtual bool getJournalAllowed() { return (mAllowed & GW_Magic); } + virtual bool getJournalAllowed() { return (mAllowed & GW_Magic) != 0; } virtual bool getPlayerSleeping(); virtual void wakeUpPlayer(); @@ -292,6 +287,12 @@ namespace MWGui virtual void startRepair(MWWorld::Ptr actor); virtual void startRepairItem(MWWorld::Ptr item); virtual void startRecharge(MWWorld::Ptr soulgem); + virtual void startTravel(const MWWorld::Ptr& actor); + virtual void startSpellBuying(const MWWorld::Ptr &actor); + virtual void startTrade(const MWWorld::Ptr &actor); + virtual void openContainer(const MWWorld::Ptr &container, bool loot); + virtual void showBook(const MWWorld::Ptr& item, bool showTakeButton); + virtual void showScroll(const MWWorld::Ptr& item, bool showTakeButton); virtual void frameStarted(float dt); @@ -317,9 +318,8 @@ namespace MWGui /// Does the current stack of GUI-windows permit saving? virtual bool isSavingAllowed() const; - /// Returns the current Modal - /** Used to send exit command to active Modal when Esc is pressed **/ - virtual WindowModal* getCurrentModal() const; + /// Send exit command to active Modal window **/ + virtual void exitCurrentModal(); /// Sets the current Modal /** Used to send exit command to active Modal when Esc is pressed **/ diff --git a/apps/openmw/mwinput/inputmanagerimp.cpp b/apps/openmw/mwinput/inputmanagerimp.cpp index fed864dfc..88d891a02 100644 --- a/apps/openmw/mwinput/inputmanagerimp.cpp +++ b/apps/openmw/mwinput/inputmanagerimp.cpp @@ -2,6 +2,7 @@ #include #include +#include #include @@ -11,6 +12,8 @@ #include #include +#include + #include #include "../engine.hpp" @@ -30,7 +33,7 @@ #include "../mwdialogue/dialoguemanagerimp.hpp" -#include "../mwgui/windowbase.hpp" +#include using namespace ICS; @@ -97,7 +100,8 @@ namespace MWInput { InputManager::InputManager(OEngine::Render::OgreRenderer &ogre, OMW::Engine& engine, - const std::string& userFile, bool userFileExists, bool grab) + const std::string& userFile, bool userFileExists, + const std::string& controllerBindingsFile, bool grab) : mOgre(ogre) , mPlayer(NULL) , mEngine(engine) @@ -118,8 +122,13 @@ namespace MWInput , mTimeIdle(0.f) , mOverencumberedMessageDelay(0.f) , mAlwaysRunActive(Settings::Manager::getBool("always run", "Input")) + , mSneakToggles(Settings::Manager::getBool("toggle sneak", "Input")) + , mSneaking(false) , mAttemptJump(false) , mControlsDisabled(false) + , mJoystickLastUsed(false) + , mDetectingKeyboard(false) + , mFakeDeviceID(1) { Ogre::RenderWindow* window = ogre.getWindow (); @@ -128,13 +137,14 @@ namespace MWInput mInputManager->setMouseEventCallback (this); mInputManager->setKeyboardEventCallback (this); mInputManager->setWindowEventCallback(this); + mInputManager->setControllerEventCallback(this); std::string file = userFileExists ? userFile : ""; mInputBinder = new ICS::InputControlSystem(file, true, this, NULL, A_Last); - adjustMouseRegion (window->getWidth(), window->getHeight()); loadKeyDefaults(); + loadControllerDefaults(); for (int i = 0; i < A_Last; ++i) { @@ -148,6 +158,32 @@ namespace MWInput mControlSwitch["playermagic"] = true; mControlSwitch["playerviewswitch"] = true; mControlSwitch["vanitymode"] = true; + + /* Joystick Init */ + + //Load controller mappings +#if SDL_VERSION_ATLEAST(2,0,2) + if(controllerBindingsFile!="") + { + SDL_GameControllerAddMappingsFromFile(controllerBindingsFile.c_str()); + } +#endif + + //Open all presently connected sticks + int numSticks = SDL_NumJoysticks(); + for(int i = 0; i < numSticks; i++) + { + if(SDL_IsGameController(i)) + { + SDL_ControllerDeviceEvent evt; + evt.which = i; + controllerAdded(mFakeDeviceID, evt); + } + else + { + //ICS_LOG(std::string("Unusable controller plugged in: ")+SDL_JoystickNameForIndex(i)); + } + } } void InputManager::clear() @@ -190,10 +226,31 @@ namespace MWInput int action = channel->getNumber(); + if((previousValue == 1 || previousValue == 0) && (currentValue==1 || currentValue==0)) + { + //Is a normal button press, so don't change it at all + } + //Otherwise only trigger button presses as they go through specific points + else if(previousValue >= .8 && currentValue < .8) + { + currentValue = 0.0; + previousValue = 1.0; + } + else if(previousValue <= .6 && currentValue > .6) + { + currentValue = 1.0; + previousValue = 0.0; + } + else + { + //If it's not switching between those values, ignore the channel change. + return; + } + if (mControlSwitch["playercontrols"]) { if (action == A_Use) - mPlayer->getPlayer().getClass().getCreatureStats(mPlayer->getPlayer()).setAttackingOrSpell(currentValue); + mPlayer->getPlayer().getClass().getCreatureStats(mPlayer->getPlayer()).setAttackingOrSpell(currentValue != 0); else if (action == A_Jump) mAttemptJump = (currentValue == 1.0 && previousValue == 0.0); } @@ -219,7 +276,6 @@ namespace MWInput break; case A_Activate: resetIdleTime(); - if (!MWBase::Environment::get().getWindowManager()->isGuiMode()) activate(); break; @@ -298,6 +354,12 @@ namespace MWInput case A_CycleWeaponRight: MWBase::Environment::get().getWindowManager()->cycleWeapon(true); break; + case A_Sneak: + if (mSneakToggles) + { + toggleSneaking(); + } + break; } } } @@ -321,7 +383,7 @@ namespace MWInput //cursor is if( !is_relative && was_relative != is_relative ) { - mInputManager->warpMouse(mMouseX, mMouseY); + mInputManager->warpMouse(static_cast(mMouseX), static_cast(mMouseY)); } } @@ -346,6 +408,47 @@ namespace MWInput updateCursorMode(); + if(mJoystickLastUsed) + { + if (mGuiCursorEnabled) + { + float xAxis = mInputBinder->getChannel(A_MoveLeftRight)->getValue()*2.0f-1.0f; + float yAxis = mInputBinder->getChannel(A_MoveForwardBackward)->getValue()*2.0f-1.0f; + float zAxis = mInputBinder->getChannel(A_LookUpDown)->getValue()*2.0f-1.0f; + const MyGUI::IntSize& viewSize = MyGUI::RenderManager::getInstance().getViewSize(); + + // We keep track of our own mouse position, so that moving the mouse while in + // game mode does not move the position of the GUI cursor + mMouseX += xAxis * dt * 1500.0f; + mMouseY += yAxis * dt * 1500.0f; + mMouseWheel -= static_cast(zAxis * dt * 1500.0f); + + mMouseX = std::max(0.f, std::min(mMouseX, float(viewSize.width))); + mMouseY = std::max(0.f, std::min(mMouseY, float(viewSize.height))); + + MyGUI::InputManager::getInstance().injectMouseMove(static_cast(mMouseX), static_cast(mMouseY), mMouseWheel); + mInputManager->warpMouse(static_cast(mMouseX), static_cast(mMouseY)); + } + if (mMouseLookEnabled) + { + float xAxis = mInputBinder->getChannel(A_LookLeftRight)->getValue()*2.0f-1.0f; + float yAxis = mInputBinder->getChannel(A_LookUpDown)->getValue()*2.0f-1.0f; + resetIdleTime(); + + 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); + + // Only actually turn player when we're not in vanity mode + if(!MWBase::Environment::get().getWorld()->vanityRotateCamera(rot)) + { + mPlayer->yaw(rot[2]); + mPlayer->pitch(rot[0]); + } + } + } + // Disable movement in Gui mode if (!(MWBase::Environment::get().getWindowManager()->isGuiMode() || MWBase::Environment::get().getStateManager()->getState() != MWBase::StateManager::State_Running)) @@ -355,37 +458,80 @@ namespace MWInput if (mControlSwitch["playercontrols"]) { bool triedToMove = false; - if (actionIsActive(A_MoveLeft)) + bool isRunning = false; + if(mJoystickLastUsed) { - triedToMove = true; - mPlayer->setLeftRight (-1); + float xAxis = mInputBinder->getChannel(A_MoveLeftRight)->getValue(); + float yAxis = mInputBinder->getChannel(A_MoveForwardBackward)->getValue(); + if (xAxis < .5) + { + triedToMove = true; + mPlayer->setLeftRight (-1); + } + else if (xAxis > .5) + { + triedToMove = true; + mPlayer->setLeftRight (1); + } + + if (yAxis < .5) + { + triedToMove = true; + mPlayer->setAutoMove (false); + mPlayer->setForwardBackward (1); + } + else if (yAxis > .5) + { + triedToMove = true; + mPlayer->setAutoMove (false); + mPlayer->setForwardBackward (-1); + } + + else if(mPlayer->getAutoMove()) + { + triedToMove = true; + mPlayer->setForwardBackward (1); + } + isRunning = xAxis > .75 || xAxis < .25 || yAxis > .75 || yAxis < .25; + if(triedToMove) resetIdleTime(); } - else if (actionIsActive(A_MoveRight)) + else { - triedToMove = true; - mPlayer->setLeftRight (1); + if (actionIsActive(A_MoveLeft)) + { + triedToMove = true; + mPlayer->setLeftRight (-1); + } + else if (actionIsActive(A_MoveRight)) + { + triedToMove = true; + mPlayer->setLeftRight (1); + } + + if (actionIsActive(A_MoveForward)) + { + triedToMove = true; + mPlayer->setAutoMove (false); + mPlayer->setForwardBackward (1); + } + else if (actionIsActive(A_MoveBackward)) + { + triedToMove = true; + mPlayer->setAutoMove (false); + mPlayer->setForwardBackward (-1); + } + + else if(mPlayer->getAutoMove()) + { + triedToMove = true; + mPlayer->setForwardBackward (1); + } } - if (actionIsActive(A_MoveForward)) + if (!mSneakToggles) { - triedToMove = true; - mPlayer->setAutoMove (false); - mPlayer->setForwardBackward (1); + mPlayer->setSneak(actionIsActive(A_Sneak)); } - else if (actionIsActive(A_MoveBackward)) - { - triedToMove = true; - mPlayer->setAutoMove (false); - mPlayer->setForwardBackward (-1); - } - - else if(mPlayer->getAutoMove()) - { - triedToMove = true; - mPlayer->setForwardBackward (1); - } - - mPlayer->setSneak(actionIsActive(A_Sneak)); if (mAttemptJump && mControlSwitch["playerjumping"]) { @@ -394,7 +540,7 @@ namespace MWInput mOverencumberedMessageDelay = 0.f; } - if (mAlwaysRunActive) + if (mAlwaysRunActive || isRunning) mPlayer->setRunState(!actionIsActive(A_Run)); else mPlayer->setRunState(actionIsActive(A_Run)); @@ -538,6 +684,7 @@ namespace MWInput } if (!mControlsDisabled && !consumed) mInputBinder->keyPressed (arg); + mJoystickLastUsed = false; } void InputManager::textInput(const SDL_TextInputEvent &arg) @@ -550,6 +697,7 @@ namespace MWInput void InputManager::keyReleased(const SDL_KeyboardEvent &arg ) { + mJoystickLastUsed = false; OIS::KeyCode kc = mInputManager->sdl2OISKeyCode(arg.keysym.sym); setPlayerControlsEnabled(!MyGUI::InputManager::getInstance().injectKeyRelease(MyGUI::KeyCode::Enum(kc))); @@ -558,12 +706,13 @@ namespace MWInput void InputManager::mousePressed( const SDL_MouseButtonEvent &arg, Uint8 id ) { + mJoystickLastUsed = false; bool guiMode = false; if (id == SDL_BUTTON_LEFT || id == SDL_BUTTON_RIGHT) // MyGUI only uses these mouse events { guiMode = MWBase::Environment::get().getWindowManager()->isGuiMode(); - guiMode = MyGUI::InputManager::getInstance().injectMousePress(mMouseX, mMouseY, sdlButtonToMyGUI(id)) && guiMode; + guiMode = MyGUI::InputManager::getInstance().injectMousePress(static_cast(mMouseX), static_cast(mMouseY), sdlButtonToMyGUI(id)) && guiMode; if (MyGUI::InputManager::getInstance ().getMouseFocusWidget () != 0) { MyGUI::Button* b = MyGUI::InputManager::getInstance ().getMouseFocusWidget ()->castType(false); @@ -582,14 +731,15 @@ namespace MWInput } void InputManager::mouseReleased( const SDL_MouseButtonEvent &arg, Uint8 id ) - { + { + mJoystickLastUsed = false; if(mInputBinder->detectingBindingState()) { mInputBinder->mouseReleased (arg, id); } else { bool guiMode = MWBase::Environment::get().getWindowManager()->isGuiMode(); - guiMode = MyGUI::InputManager::getInstance().injectMouseRelease(mMouseX, mMouseY, sdlButtonToMyGUI(id)) && guiMode; + guiMode = MyGUI::InputManager::getInstance().injectMouseRelease(static_cast(mMouseX), static_cast(mMouseY), sdlButtonToMyGUI(id)) && guiMode; if(mInputBinder->detectingBindingState()) return; // don't allow same mouseup to bind as initiated bind @@ -602,6 +752,7 @@ namespace MWInput { mInputBinder->mouseMoved (arg); + mJoystickLastUsed = false; resetIdleTime (); if (mGuiCursorEnabled) @@ -610,8 +761,8 @@ namespace MWInput // We keep track of our own mouse position, so that moving the mouse while in // game mode does not move the position of the GUI cursor - mMouseX = arg.x; - mMouseY = arg.y; + mMouseX = static_cast(arg.x); + mMouseY = static_cast(arg.y); mMouseX = std::max(0.f, std::min(mMouseX, float(viewSize.width))); mMouseY = std::max(0.f, std::min(mMouseY, float(viewSize.height))); @@ -625,8 +776,8 @@ namespace MWInput { resetIdleTime(); - double x = arg.xrel * mCameraSensitivity * (1.0f/256.f); - double y = arg.yrel * mCameraSensitivity * (1.0f/256.f) * (mInvertY ? -1 : 1) * mCameraYMultiplier; + float x = arg.xrel * mCameraSensitivity * (1.0f/256.f); + float y = arg.yrel * mCameraSensitivity * (1.0f/256.f) * (mInvertY ? -1 : 1) * mCameraYMultiplier; float rot[3]; rot[0] = -y; @@ -642,14 +793,87 @@ namespace MWInput if (arg.zrel && mControlSwitch["playerviewswitch"] && mControlSwitch["playercontrols"]) //Check to make sure you are allowed to zoomout and there is a change { - MWBase::Environment::get().getWorld()->changeVanityModeScale(arg.zrel); + MWBase::Environment::get().getWorld()->changeVanityModeScale(static_cast(arg.zrel)); if (Settings::Manager::getBool("allow third person zoom", "Input")) - MWBase::Environment::get().getWorld()->setCameraDistance(arg.zrel, true, true); + MWBase::Environment::get().getWorld()->setCameraDistance(static_cast(arg.zrel), true, true); } } } + void InputManager::buttonPressed(int deviceID, const SDL_ControllerButtonEvent &arg ) + { + mJoystickLastUsed = true; + bool guiMode = false; + + if (arg.button == SDL_CONTROLLER_BUTTON_A || arg.button == SDL_CONTROLLER_BUTTON_B) // We'll pretend that A is left click and B is right click + { + guiMode = MWBase::Environment::get().getWindowManager()->isGuiMode(); + if(!mInputBinder->detectingBindingState()) + { + guiMode = MyGUI::InputManager::getInstance().injectMousePress(static_cast(mMouseX), static_cast(mMouseY), + sdlButtonToMyGUI((arg.button == SDL_CONTROLLER_BUTTON_B) ? SDL_BUTTON_RIGHT : SDL_BUTTON_LEFT)) && guiMode; + if (MyGUI::InputManager::getInstance ().getMouseFocusWidget () != 0) + { + MyGUI::Button* b = MyGUI::InputManager::getInstance ().getMouseFocusWidget ()->castType(false); + if (b && b->getEnabled()) + { + MWBase::Environment::get().getSoundManager ()->playSound ("Menu Click", 1.f, 1.f); + } + } + } + } + + setPlayerControlsEnabled(!guiMode); + + //esc, to leave initial movie screen + OIS::KeyCode kc = mInputManager->sdl2OISKeyCode(SDLK_ESCAPE); + bool guiFocus = MyGUI::InputManager::getInstance().injectKeyPress(MyGUI::KeyCode::Enum(kc), 0); + setPlayerControlsEnabled(!guiFocus); + + if (!mControlsDisabled) + mInputBinder->buttonPressed(deviceID, arg); + } + + void InputManager::buttonReleased(int deviceID, const SDL_ControllerButtonEvent &arg ) + { + mJoystickLastUsed = true; + if(mInputBinder->detectingBindingState()) + mInputBinder->buttonReleased(deviceID, arg); + else if(arg.button == SDL_CONTROLLER_BUTTON_A || arg.button == SDL_CONTROLLER_BUTTON_B) + { + bool guiMode = MWBase::Environment::get().getWindowManager()->isGuiMode(); + guiMode = MyGUI::InputManager::getInstance().injectMouseRelease(static_cast(mMouseX), static_cast(mMouseY), sdlButtonToMyGUI((arg.button == SDL_CONTROLLER_BUTTON_B) ? SDL_BUTTON_RIGHT : SDL_BUTTON_LEFT)) && guiMode; + + if(mInputBinder->detectingBindingState()) return; // don't allow same mouseup to bind as initiated bind + + setPlayerControlsEnabled(!guiMode); + mInputBinder->buttonReleased(deviceID, arg); + } + else + mInputBinder->buttonReleased(deviceID, arg); + + //to escape initial movie + OIS::KeyCode kc = mInputManager->sdl2OISKeyCode(SDLK_ESCAPE); + setPlayerControlsEnabled(!MyGUI::InputManager::getInstance().injectKeyRelease(MyGUI::KeyCode::Enum(kc))); + } + + void InputManager::axisMoved(int deviceID, const SDL_ControllerAxisEvent &arg ) + { + mJoystickLastUsed = true; + if (!mControlsDisabled) + mInputBinder->axisMoved(deviceID, arg); + } + + void InputManager::controllerAdded(int deviceID, const SDL_ControllerDeviceEvent &arg) + { + mInputBinder->controllerAdded(deviceID, arg); + } + void InputManager::controllerRemoved(const SDL_ControllerDeviceEvent &arg) + { + mInputBinder->controllerRemoved(arg); + } + void InputManager::windowFocusChange(bool have_focus) { } @@ -672,7 +896,7 @@ namespace MWInput void InputManager::toggleMainMenu() { if (MyGUI::InputManager::getInstance().isModalAny()) { - MWBase::Environment::get().getWindowManager()->getCurrentModal()->exit(); + MWBase::Environment::get().getWindowManager()->exitCurrentModal(); return; } @@ -846,7 +1070,7 @@ namespace MWInput } else if (MWBase::Environment::get().getWindowManager()->getMode () == MWGui::GM_QuickKeysMenu) { while(MyGUI::InputManager::getInstance().isModalAny()) { //Handle any open Modal windows - MWBase::Environment::get().getWindowManager()->getCurrentModal()->exit(); + MWBase::Environment::get().getWindowManager()->exitCurrentModal(); } MWBase::Environment::get().getWindowManager()->exitCurrentGuiMode(); //And handle the actual main window } @@ -874,6 +1098,13 @@ namespace MWInput Settings::Manager::setBool("always run", "Input", mAlwaysRunActive); } + void InputManager::toggleSneaking() + { + if (MWBase::Environment::get().getWindowManager()->isGuiMode()) return; + mSneaking = !mSneaking; + mPlayer->setSneak(mSneaking); + } + void InputManager::resetIdleTime() { if (mTimeIdle < 0) @@ -895,7 +1126,7 @@ namespace MWInput bool InputManager::actionIsActive (int id) { - return mInputBinder->getChannel (id)->getValue () == 1; + return (mInputBinder->getChannel (id)->getValue ()==1.0); } void InputManager::loadKeyDefaults (bool force) @@ -968,14 +1199,88 @@ namespace MWInput && mInputBinder->getMouseButtonBinding (control, ICS::Control::INCREASE) == ICS_MAX_DEVICE_BUTTONS )) { - clearAllBindings (control); + clearAllKeyBindings(control); if (defaultKeyBindings.find(i) != defaultKeyBindings.end() && !mInputBinder->isKeyBound(defaultKeyBindings[i])) + { + control->setInitialValue(0.0f); mInputBinder->addKeyBinding(control, defaultKeyBindings[i], ICS::Control::INCREASE); + } else if (defaultMouseButtonBindings.find(i) != defaultMouseButtonBindings.end() && !mInputBinder->isMouseButtonBound(defaultMouseButtonBindings[i])) + { + control->setInitialValue(0.0f); mInputBinder->addMouseButtonBinding (control, defaultMouseButtonBindings[i], ICS::Control::INCREASE); + } + } + } + } + + void InputManager::loadControllerDefaults(bool force) + { + // using hardcoded key defaults is inevitable, if we want the configuration files to stay valid + // across different versions of OpenMW (in the case where another input action is added) + std::map defaultButtonBindings; + + defaultButtonBindings[A_Activate] = SDL_CONTROLLER_BUTTON_A; + defaultButtonBindings[A_ToggleWeapon] = SDL_CONTROLLER_BUTTON_X; + defaultButtonBindings[A_ToggleSpell] = SDL_CONTROLLER_BUTTON_LEFTSHOULDER; + //defaultButtonBindings[A_QuickButtonsMenu] = SDL_GetButtonFromScancode(SDL_SCANCODE_F1); // Need to implement, should be ToggleSpell(5) AND Wait(9) + defaultButtonBindings[A_Sneak] = SDL_CONTROLLER_BUTTON_RIGHTSTICK; + defaultButtonBindings[A_Jump] = SDL_CONTROLLER_BUTTON_Y; + defaultButtonBindings[A_Journal] = SDL_CONTROLLER_BUTTON_RIGHTSHOULDER; + defaultButtonBindings[A_Rest] = SDL_CONTROLLER_BUTTON_BACK; + defaultButtonBindings[A_TogglePOV] = SDL_CONTROLLER_BUTTON_LEFTSTICK; + defaultButtonBindings[A_Inventory] = SDL_CONTROLLER_BUTTON_B; + defaultButtonBindings[A_GameMenu] = SDL_CONTROLLER_BUTTON_START; + defaultButtonBindings[A_QuickSave] = SDL_CONTROLLER_BUTTON_GUIDE; + defaultButtonBindings[A_QuickKey1] = SDL_CONTROLLER_BUTTON_DPAD_UP; + defaultButtonBindings[A_QuickKey2] = SDL_CONTROLLER_BUTTON_DPAD_LEFT; + defaultButtonBindings[A_QuickKey3] = SDL_CONTROLLER_BUTTON_DPAD_DOWN; + defaultButtonBindings[A_QuickKey4] = SDL_CONTROLLER_BUTTON_DPAD_RIGHT; + + std::map defaultAxisBindings; + defaultAxisBindings[A_MoveForwardBackward] = SDL_CONTROLLER_AXIS_LEFTY; + defaultAxisBindings[A_MoveLeftRight] = SDL_CONTROLLER_AXIS_LEFTX; + defaultAxisBindings[A_LookUpDown] = SDL_CONTROLLER_AXIS_RIGHTY; + defaultAxisBindings[A_LookLeftRight] = SDL_CONTROLLER_AXIS_RIGHTX; + defaultAxisBindings[A_Use] = SDL_CONTROLLER_AXIS_TRIGGERRIGHT; + + for (int i = 0; i < A_Last; i++) + { + ICS::Control* control; + bool controlExists = mInputBinder->getChannel(i)->getControlsCount () != 0; + if (!controlExists) + { + float initial; + if (defaultButtonBindings.find(i) != defaultButtonBindings.end()) + initial = 0.0f; + else initial = 0.5f; + control = new ICS::Control(boost::lexical_cast(i), false, true, initial, ICS::ICS_MAX, ICS::ICS_MAX); + mInputBinder->addControl(control); + control->attachChannel(mInputBinder->getChannel(i), ICS::Channel::DIRECT); + } + else + { + control = mInputBinder->getChannel(i)->getAttachedControls ().front().control; + } + + if (!controlExists || force || ( mInputBinder->getJoystickAxisBinding (control, mFakeDeviceID, ICS::Control::INCREASE) == ICS::InputControlSystem::UNASSIGNED && mInputBinder->getJoystickButtonBinding (control, mFakeDeviceID, ICS::Control::INCREASE) == ICS_MAX_DEVICE_BUTTONS )) + { + clearAllControllerBindings(control); + + if (defaultButtonBindings.find(i) != defaultButtonBindings.end()) + { + control->setInitialValue(0.0f); + mInputBinder->addJoystickButtonBinding(control, mFakeDeviceID, defaultButtonBindings[i], ICS::Control::INCREASE); + } + else if (defaultAxisBindings.find(i) != defaultAxisBindings.end()) + { + control->setValue(0.5f); + control->setInitialValue(0.5f); + mInputBinder->addJoystickAxisBinding(control, mFakeDeviceID, defaultAxisBindings[i], ICS::Control::INCREASE); + } } } } @@ -1029,7 +1334,7 @@ namespace MWInput return "#{" + descriptions[action] + "}"; } - std::string InputManager::getActionBindingName (int action) + std::string InputManager::getActionKeyBindingName (int action) { if (mInputBinder->getChannel (action)->getControlsCount () == 0) return "#{sNone}"; @@ -1044,7 +1349,81 @@ namespace MWInput return "#{sNone}"; } - std::vector InputManager::getActionSorting() + std::string InputManager::getActionControllerBindingName (int action) + { + if (mInputBinder->getChannel (action)->getControlsCount () == 0) + return "#{sNone}"; + + ICS::Control* c = mInputBinder->getChannel (action)->getAttachedControls ().front().control; + + if (mInputBinder->getJoystickAxisBinding (c, mFakeDeviceID, ICS::Control::INCREASE) != ICS::InputControlSystem::UNASSIGNED) + return sdlControllerAxisToString(mInputBinder->getJoystickAxisBinding (c, mFakeDeviceID, ICS::Control::INCREASE)); + else if (mInputBinder->getJoystickButtonBinding (c, mFakeDeviceID, ICS::Control::INCREASE) != ICS_MAX_DEVICE_BUTTONS ) + return sdlControllerButtonToString(mInputBinder->getJoystickButtonBinding (c, mFakeDeviceID, ICS::Control::INCREASE)); + else + return "#{sNone}"; + } + + std::string InputManager::sdlControllerButtonToString(int button) + { + switch(button) + { + case SDL_CONTROLLER_BUTTON_A: + return "A Button"; + case SDL_CONTROLLER_BUTTON_B: + return "B Button"; + case SDL_CONTROLLER_BUTTON_BACK: + return "Back Button"; + case SDL_CONTROLLER_BUTTON_DPAD_DOWN: + return "DPad Down"; + case SDL_CONTROLLER_BUTTON_DPAD_LEFT: + return "DPad Left"; + case SDL_CONTROLLER_BUTTON_DPAD_RIGHT: + return "DPad Right"; + case SDL_CONTROLLER_BUTTON_DPAD_UP: + return "DPad Up"; + case SDL_CONTROLLER_BUTTON_GUIDE: + return "Guide Button"; + case SDL_CONTROLLER_BUTTON_LEFTSHOULDER: + return "Left Shoulder"; + case SDL_CONTROLLER_BUTTON_LEFTSTICK: + return "Left Stick Button"; + case SDL_CONTROLLER_BUTTON_RIGHTSHOULDER: + return "Right Shoulder"; + case SDL_CONTROLLER_BUTTON_RIGHTSTICK: + return "Right Stick Button"; + case SDL_CONTROLLER_BUTTON_START: + return "Start Button"; + case SDL_CONTROLLER_BUTTON_X: + return "X Button"; + case SDL_CONTROLLER_BUTTON_Y: + return "Y Button"; + default: + return "Button " + boost::lexical_cast(button); + } + } + std::string InputManager::sdlControllerAxisToString(int axis) + { + switch(axis) + { + case SDL_CONTROLLER_AXIS_LEFTX: + return "Left Stick X"; + case SDL_CONTROLLER_AXIS_LEFTY: + return "Left Stick Y"; + case SDL_CONTROLLER_AXIS_RIGHTX: + return "Right Stick X"; + case SDL_CONTROLLER_AXIS_RIGHTY: + return "Right Stick Y"; + case SDL_CONTROLLER_AXIS_TRIGGERLEFT: + return "Left Trigger"; + case SDL_CONTROLLER_AXIS_TRIGGERRIGHT: + return "Right Trigger"; + default: + return "Axis " + boost::lexical_cast(axis); + } + } + + std::vector InputManager::getActionKeySorting() { std::vector ret; ret.push_back(A_MoveForward); @@ -1086,11 +1465,42 @@ namespace MWInput return ret; } - - void InputManager::enableDetectingBindingMode (int action) + std::vector InputManager::getActionControllerSorting() { - ICS::Control* c = mInputBinder->getChannel (action)->getAttachedControls ().front().control; + std::vector ret; + ret.push_back(A_TogglePOV); + ret.push_back(A_Sneak); + ret.push_back(A_Activate); + ret.push_back(A_Use); + ret.push_back(A_ToggleWeapon); + ret.push_back(A_ToggleSpell); + ret.push_back(A_AutoMove); + ret.push_back(A_Jump); + ret.push_back(A_Inventory); + ret.push_back(A_Journal); + ret.push_back(A_Rest); + ret.push_back(A_QuickSave); + ret.push_back(A_QuickLoad); + ret.push_back(A_Screenshot); + ret.push_back(A_QuickKeysMenu); + ret.push_back(A_QuickKey1); + ret.push_back(A_QuickKey2); + ret.push_back(A_QuickKey3); + ret.push_back(A_QuickKey4); + ret.push_back(A_QuickKey5); + ret.push_back(A_QuickKey6); + ret.push_back(A_QuickKey7); + ret.push_back(A_QuickKey8); + ret.push_back(A_QuickKey9); + ret.push_back(A_QuickKey10); + return ret; + } + + void InputManager::enableDetectingBindingMode (int action, bool keyboard) + { + mDetectingKeyboard = keyboard; + ICS::Control* c = mInputBinder->getChannel (action)->getAttachedControls ().front().control; mInputBinder->enableDetectingBindingState (c, ICS::Control::INCREASE); } @@ -1106,9 +1516,17 @@ namespace MWInput { //Disallow binding escape key if(key==SDL_SCANCODE_ESCAPE) + { + //Stop binding if esc pressed + mInputBinder->cancelDetectingBindingState(); + MWBase::Environment::get().getWindowManager ()->notifyInputActionBound (); + return; + } + if(!mDetectingKeyboard) return; - clearAllBindings(control); + clearAllKeyBindings(control); + control->setInitialValue(0.0f); ICS::DetectingBindingListener::keyBindingDetected (ICS, control, key, direction); MWBase::Environment::get().getWindowManager ()->notifyInputActionBound (); } @@ -1116,59 +1534,69 @@ namespace MWInput void InputManager::mouseButtonBindingDetected(ICS::InputControlSystem* ICS, ICS::Control* control , unsigned int button, ICS::Control::ControlChangingDirection direction) { - clearAllBindings(control); + if(!mDetectingKeyboard) + return; + clearAllKeyBindings(control); + control->setInitialValue(0.0f); ICS::DetectingBindingListener::mouseButtonBindingDetected (ICS, control, button, direction); MWBase::Environment::get().getWindowManager ()->notifyInputActionBound (); } - void InputManager::joystickAxisBindingDetected(ICS::InputControlSystem* ICS, ICS::Control* control - , int deviceId, int axis, ICS::Control::ControlChangingDirection direction) + void InputManager::joystickAxisBindingDetected(ICS::InputControlSystem* ICS, int deviceID, ICS::Control* control + , int axis, ICS::Control::ControlChangingDirection direction) { - clearAllBindings(control); - ICS::DetectingBindingListener::joystickAxisBindingDetected (ICS, control, deviceId, axis, direction); + //only allow binding to the trigers + if(axis != SDL_CONTROLLER_AXIS_TRIGGERLEFT && axis != SDL_CONTROLLER_AXIS_TRIGGERRIGHT) + return; + if(mDetectingKeyboard) + return; + + clearAllControllerBindings(control); + control->setValue(0.5f); //axis bindings must start at 0.5 + control->setInitialValue(0.5f); + ICS::DetectingBindingListener::joystickAxisBindingDetected (ICS, deviceID, control, axis, direction); MWBase::Environment::get().getWindowManager ()->notifyInputActionBound (); } - void InputManager::joystickButtonBindingDetected(ICS::InputControlSystem* ICS, ICS::Control* control - , int deviceId, unsigned int button, ICS::Control::ControlChangingDirection direction) + void InputManager::joystickButtonBindingDetected(ICS::InputControlSystem* ICS, int deviceID, ICS::Control* control + , unsigned int button, ICS::Control::ControlChangingDirection direction) { - clearAllBindings(control); - ICS::DetectingBindingListener::joystickButtonBindingDetected (ICS, control, deviceId, button, direction); + if(mDetectingKeyboard) + return; + clearAllControllerBindings(control); + control->setInitialValue(0.0f); + ICS::DetectingBindingListener::joystickButtonBindingDetected (ICS, deviceID, control, button, direction); MWBase::Environment::get().getWindowManager ()->notifyInputActionBound (); } - void InputManager::joystickPOVBindingDetected(ICS::InputControlSystem* ICS, ICS::Control* control - , int deviceId, int pov,ICS:: InputControlSystem::POVAxis axis, ICS::Control::ControlChangingDirection direction) - { - clearAllBindings(control); - ICS::DetectingBindingListener::joystickPOVBindingDetected (ICS, control, deviceId, pov, axis, direction); - MWBase::Environment::get().getWindowManager ()->notifyInputActionBound (); - } - - void InputManager::joystickSliderBindingDetected(ICS::InputControlSystem* ICS, ICS::Control* control - , int deviceId, int slider, ICS::Control::ControlChangingDirection direction) - { - clearAllBindings(control); - ICS::DetectingBindingListener::joystickSliderBindingDetected (ICS, control, deviceId, slider, direction); - MWBase::Environment::get().getWindowManager ()->notifyInputActionBound (); - } - - void InputManager::clearAllBindings (ICS::Control* control) + void InputManager::clearAllKeyBindings (ICS::Control* control) { // right now we don't really need multiple bindings for the same action, so remove all others first if (mInputBinder->getKeyBinding (control, ICS::Control::INCREASE) != SDL_SCANCODE_UNKNOWN) mInputBinder->removeKeyBinding (mInputBinder->getKeyBinding (control, ICS::Control::INCREASE)); if (mInputBinder->getMouseButtonBinding (control, ICS::Control::INCREASE) != ICS_MAX_DEVICE_BUTTONS) mInputBinder->removeMouseButtonBinding (mInputBinder->getMouseButtonBinding (control, ICS::Control::INCREASE)); - - /// \todo add joysticks here once they are added } - void InputManager::resetToDefaultBindings() + void InputManager::clearAllControllerBindings (ICS::Control* control) + { + // right now we don't really need multiple bindings for the same action, so remove all others first + if (mInputBinder->getJoystickAxisBinding (control, mFakeDeviceID, ICS::Control::INCREASE) != SDL_SCANCODE_UNKNOWN) + mInputBinder->removeJoystickAxisBinding (mFakeDeviceID, mInputBinder->getJoystickAxisBinding (control, mFakeDeviceID, ICS::Control::INCREASE)); + if (mInputBinder->getJoystickButtonBinding (control, mFakeDeviceID, ICS::Control::INCREASE) != ICS_MAX_DEVICE_BUTTONS) + mInputBinder->removeJoystickButtonBinding (mFakeDeviceID, mInputBinder->getJoystickButtonBinding (control, mFakeDeviceID, ICS::Control::INCREASE)); + } + + void InputManager::resetToDefaultKeyBindings() { loadKeyDefaults(true); } + void InputManager::resetToDefaultControllerBindings() + { + loadControllerDefaults(true); + } + MyGUI::MouseButton InputManager::sdlButtonToMyGUI(Uint8 button) { //The right button is the second button, according to MyGUI diff --git a/apps/openmw/mwinput/inputmanagerimp.hpp b/apps/openmw/mwinput/inputmanagerimp.hpp index 851f24971..558801023 100644 --- a/apps/openmw/mwinput/inputmanagerimp.hpp +++ b/apps/openmw/mwinput/inputmanagerimp.hpp @@ -4,6 +4,7 @@ #include "../mwgui/mode.hpp" #include +#include #include "../mwbase/inputmanager.hpp" #include @@ -38,7 +39,12 @@ namespace ICS namespace MyGUI { - class MouseButton; + struct MouseButton; +} + +namespace Files +{ + struct ConfigurationManager; } #include @@ -55,13 +61,15 @@ namespace MWInput public SFO::KeyListener, public SFO::MouseListener, public SFO::WindowListener, + public SFO::ControllerListener, public ICS::ChannelListener, public ICS::DetectingBindingListener { public: InputManager(OEngine::Render::OgreRenderer &_ogre, OMW::Engine& engine, - const std::string& userFile, bool userFileExists, bool grab); + const std::string& userFile, bool userFileExists, + const std::string& controllerBindingsFile, bool grab); virtual ~InputManager(); @@ -82,11 +90,16 @@ namespace MWInput virtual bool getControlSwitch (const std::string& sw); virtual std::string getActionDescription (int action); - virtual std::string getActionBindingName (int action); + virtual std::string getActionKeyBindingName (int action); + virtual std::string getActionControllerBindingName (int action); virtual int getNumActions() { return A_Last; } - virtual std::vector getActionSorting (); - virtual void enableDetectingBindingMode (int action); - virtual void resetToDefaultBindings(); + virtual std::vector getActionKeySorting(); + virtual std::vector getActionControllerSorting(); + virtual void enableDetectingBindingMode (int action, bool keyboard); + virtual void resetToDefaultKeyBindings(); + virtual void resetToDefaultControllerBindings(); + + virtual bool joystickLastUsed() {return mJoystickLastUsed;} public: virtual void keyPressed(const SDL_KeyboardEvent &arg ); @@ -97,6 +110,12 @@ namespace MWInput virtual void mouseReleased( const SDL_MouseButtonEvent &arg, Uint8 id ); virtual void mouseMoved( const SFO::MouseMotionEvent &arg ); + virtual void buttonPressed(int deviceID, const SDL_ControllerButtonEvent &arg); + virtual void buttonReleased(int deviceID, const SDL_ControllerButtonEvent &arg); + virtual void axisMoved(int deviceID, const SDL_ControllerAxisEvent &arg); + virtual void controllerAdded(int deviceID, const SDL_ControllerDeviceEvent &arg); + virtual void controllerRemoved(const SDL_ControllerDeviceEvent &arg); + virtual void windowVisibilityChange( bool visible ); virtual void windowFocusChange( bool have_focus ); virtual void windowResized (int x, int y); @@ -113,21 +132,17 @@ namespace MWInput virtual void mouseButtonBindingDetected(ICS::InputControlSystem* ICS, ICS::Control* control , unsigned int button, ICS::Control::ControlChangingDirection direction); - virtual void joystickAxisBindingDetected(ICS::InputControlSystem* ICS, ICS::Control* control - , int deviceId, int axis, ICS::Control::ControlChangingDirection direction); + virtual void joystickAxisBindingDetected(ICS::InputControlSystem* ICS, int deviceID, ICS::Control* control + , int axis, ICS::Control::ControlChangingDirection direction); - virtual void joystickButtonBindingDetected(ICS::InputControlSystem* ICS, ICS::Control* control - , int deviceId, unsigned int button, ICS::Control::ControlChangingDirection direction); + virtual void joystickButtonBindingDetected(ICS::InputControlSystem* ICS, int deviceID, ICS::Control* control + , unsigned int button, ICS::Control::ControlChangingDirection direction); - virtual void joystickPOVBindingDetected(ICS::InputControlSystem* ICS, ICS::Control* control - , int deviceId, int pov,ICS:: InputControlSystem::POVAxis axis, ICS::Control::ControlChangingDirection direction); - - virtual void joystickSliderBindingDetected(ICS::InputControlSystem* ICS, ICS::Control* control - , int deviceId, int slider, ICS::Control::ControlChangingDirection direction); - - void clearAllBindings (ICS::Control* control); + void clearAllKeyBindings (ICS::Control* control); + void clearAllControllerBindings (ICS::Control* control); private: + bool mJoystickLastUsed; OEngine::Render::OgreRenderer &mOgre; MWWorld::Player* mPlayer; OMW::Engine& mEngine; @@ -156,6 +171,8 @@ namespace MWInput bool mMouseLookEnabled; bool mGuiCursorEnabled; + bool mDetectingKeyboard; + float mOverencumberedMessageDelay; float mMouseX; @@ -163,6 +180,8 @@ namespace MWInput int mMouseWheel; bool mUserFileExists; bool mAlwaysRunActive; + bool mSneakToggles; + bool mSneaking; bool mAttemptJump; std::map mControlSwitch; @@ -171,6 +190,9 @@ namespace MWInput void adjustMouseRegion(int width, int height); MyGUI::MouseButton sdlButtonToMyGUI(Uint8 button); + virtual std::string sdlControllerAxisToString(int axis); + virtual std::string sdlControllerButtonToString(int button); + void resetIdleTime(); void updateIdleTime(float dt); @@ -188,6 +210,7 @@ namespace MWInput void toggleJournal(); void activate(); void toggleWalking(); + void toggleSneaking(); void toggleAutoMove(); void rest(); void quickLoad(); @@ -199,6 +222,9 @@ namespace MWInput bool actionIsActive (int id); void loadKeyDefaults(bool force = false); + void loadControllerDefaults(bool force = false); + + int mFakeDeviceID; //As we only support one controller at a time, use a fake deviceID so we don't lose bindings when switching controllers private: enum Actions @@ -263,6 +289,11 @@ namespace MWInput A_ToggleDebug, + A_LookUpDown, //Joystick look + A_LookLeftRight, + A_MoveForwardBackward, + A_MoveLeftRight, + A_Last // Marker for the last item }; }; diff --git a/apps/openmw/mwmechanics/activespells.cpp b/apps/openmw/mwmechanics/activespells.cpp index 6e15449e1..a6cc9af8e 100644 --- a/apps/openmw/mwmechanics/activespells.cpp +++ b/apps/openmw/mwmechanics/activespells.cpp @@ -1,5 +1,7 @@ #include "activespells.hpp" +#include + #include #include @@ -74,9 +76,9 @@ namespace MWMechanics for (std::vector::const_iterator effectIt = effects.begin(); effectIt != effects.end(); ++effectIt) { - int duration = effectIt->mDuration; + double duration = effectIt->mDuration; MWWorld::TimeStamp end = start; - end += static_cast (duration)* + end += duration * MWBase::Environment::get().getWorld()->getTimeScaleFactor()/(60*60); if (end>now) @@ -110,7 +112,7 @@ namespace MWMechanics { const std::vector& effects = iterator->second.mEffects; - int duration = 0; + float duration = 0; for (std::vector::const_iterator iter (effects.begin()); iter!=effects.end(); ++iter) @@ -152,12 +154,7 @@ namespace MWMechanics void ActiveSpells::addSpell(const std::string &id, bool stack, std::vector effects, const std::string &displayName, int casterActorId) { - bool exists = false; - for (TContainer::const_iterator it = begin(); it != end(); ++it) - { - if (id == it->first) - exists = true; - } + TContainer::iterator it(mSpells.find(id)); ActiveSpellParams params; params.mTimeStamp = MWBase::Environment::get().getWorld()->getTimeStamp(); @@ -165,14 +162,44 @@ namespace MWMechanics params.mDisplayName = displayName; params.mCasterActorId = casterActorId; - if (!exists || stack) - mSpells.insert (std::make_pair(id, params)); + if (it == end() || stack) + { + mSpells.insert(std::make_pair(id, params)); + } else - mSpells.find(id)->second = params; + { + // addSpell() is called with effects for a range. + // but a spell may have effects with different ranges (e.g. Touch & Target) + // so, if we see new effects for same spell assume additional + // spell effects and add to existing effects of spell + mergeEffects(params.mEffects, it->second.mEffects); + it->second = params; + } mSpellsChanged = true; } + void ActiveSpells::mergeEffects(std::vector& addTo, const std::vector& from) + { + for (std::vector::const_iterator effect(from.begin()); effect != from.end(); ++effect) + { + // if effect is not in addTo, add it + bool missing = true; + for (std::vector::const_iterator iter(addTo.begin()); iter != addTo.end(); ++iter) + { + if ((effect->mEffectId == iter->mEffectId) && (effect->mArg == iter->mArg)) + { + missing = false; + break; + } + } + if (missing) + { + addTo.push_back(*effect); + } + } + } + void ActiveSpells::removeEffects(const std::string &id) { mSpells.erase(Misc::StringUtils::lowerCase(id)); @@ -191,7 +218,7 @@ namespace MWMechanics std::string name = it->second.mDisplayName; float remainingTime = effectIt->mDuration + - (it->second.mTimeStamp - MWBase::Environment::get().getWorld()->getTimeStamp())*3600/timeScale; + static_cast(it->second.mTimeStamp - MWBase::Environment::get().getWorld()->getTimeStamp())*3600/timeScale; float magnitude = effectIt->mMagnitude; if (magnitude) @@ -204,8 +231,7 @@ namespace MWMechanics { for (TContainer::iterator it = mSpells.begin(); it != mSpells.end(); ) { - int roll = std::rand()/ (static_cast (RAND_MAX) + 1) * 100; // [0, 99] - if (roll < chance) + if (OEngine::Misc::Rng::roll0to99() < chance) mSpells.erase(it++); else ++it; diff --git a/apps/openmw/mwmechanics/activespells.hpp b/apps/openmw/mwmechanics/activespells.hpp index 4f9d15d8c..2a4d75d40 100644 --- a/apps/openmw/mwmechanics/activespells.hpp +++ b/apps/openmw/mwmechanics/activespells.hpp @@ -55,6 +55,9 @@ namespace MWMechanics void rebuildEffects() const; + /// Add any effects that are in "from" and not in "addTo" to "addTo" + void mergeEffects(std::vector& addTo, const std::vector& from); + double timeToExpire (const TIterator& iterator) const; ///< Returns time (in in-game hours) until the spell pointed to by \a iterator /// expires. diff --git a/apps/openmw/mwmechanics/actors.cpp b/apps/openmw/mwmechanics/actors.cpp index f8068e800..c6df24154 100644 --- a/apps/openmw/mwmechanics/actors.cpp +++ b/apps/openmw/mwmechanics/actors.cpp @@ -54,9 +54,17 @@ void adjustBoundItem (const std::string& item, bool bound, const MWWorld::Ptr& a { if (actor.getClass().getContainerStore(actor).count(item) == 0) { - MWWorld::Ptr newPtr = *actor.getClass().getContainerStore(actor).add(item, 1, actor); + MWWorld::InventoryStore& store = actor.getClass().getInventoryStore(actor); + MWWorld::Ptr newPtr = *store.MWWorld::ContainerStore::add(item, 1, actor); MWWorld::ActionEquip action(newPtr); action.execute(actor); + MWWorld::ContainerStoreIterator rightHand = store.getSlot(MWWorld::InventoryStore::Slot_CarriedRight); + // change draw state only if the item is in player's right hand + if (actor == MWBase::Environment::get().getWorld()->getPlayerPtr() + && rightHand != store.end() && newPtr == *rightHand) + { + MWBase::Environment::get().getWorld()->getPlayer().setDrawState(MWMechanics::DrawState_Weapon); + } } } else @@ -84,14 +92,14 @@ bool disintegrateSlot (MWWorld::Ptr ptr, int slot, float disintegrate) // FIXME: charge should be a float, not int so that damage < 1 per frame can be applied. // This was also a bug in the original engine. charge -= - std::min(disintegrate, - static_cast(charge)); + std::min(static_cast(disintegrate), + charge); item->getCellRef().setCharge(charge); if (charge == 0) { // Will unequip the broken item and try to find a replacement - if (ptr.getRefData().getHandle() != "player") + if (ptr != MWBase::Environment::get().getWorld()->getPlayerPtr()) inv.autoEquip(ptr); else inv.unequipItem(*item, ptr); @@ -146,6 +154,7 @@ void adjustCommandedActor (const MWWorld::Ptr& actor) if (check.mCommanded && !hasCommandPackage) { + // FIXME: don't use refid string MWMechanics::AiFollow package("player", true); stats.getAiSequence().stack(package, actor); } @@ -163,7 +172,7 @@ void getRestorationPerHourOfSleep (const MWWorld::Ptr& ptr, float& health, float bool stunted = stats.getMagicEffects ().get(ESM::MagicEffect::StuntedMagicka).getMagnitude() > 0; int endurance = stats.getAttribute (ESM::Attribute::Endurance).getModified (); - health = 0.1 * endurance; + health = 0.1f * endurance; magicka = 0; if (!stunted) @@ -203,7 +212,7 @@ namespace MWMechanics static const float fSoulgemMult = world->getStore().get().find("fSoulgemMult")->getFloat(); - float creatureSoulValue = mCreature.get()->mBase->mData.mSoul; + int creatureSoulValue = mCreature.get()->mBase->mData.mSoul; if (creatureSoulValue == 0) return; @@ -236,7 +245,7 @@ namespace MWMechanics gem->getContainerStore()->unstack(*gem, caster); gem->getCellRef().setSoul(mCreature.getCellRef().getRefId()); - if (caster.getRefData().getHandle() == "player") + if (caster == MWBase::Environment::get().getWorld()->getPlayerPtr()) MWBase::Environment::get().getWindowManager()->messageBox("#{sSoultrapSuccess}"); const ESM::Static* fx = MWBase::Environment::get().getWorld()->getStore().get() @@ -425,7 +434,7 @@ namespace MWMechanics int intelligence = creatureStats.getAttribute(ESM::Attribute::Intelligence).getModified(); float base = 1.f; - if (ptr.getCellRef().getRefId() == "player") + if (ptr == MWBase::Environment::get().getWorld()->getPlayerPtr()) base = MWBase::Environment::get().getWorld()->getStore().get().find("fPCbaseMagickaMult")->getFloat(); else base = MWBase::Environment::get().getWorld()->getStore().get().find("fNPCbaseMagickaMult")->getFloat(); @@ -515,12 +524,12 @@ namespace MWMechanics for(int i = 0;i < ESM::Attribute::Length;++i) { AttributeValue stat = creatureStats.getAttribute(i); - stat.setModifier(effects.get(EffectKey(ESM::MagicEffect::FortifyAttribute, i)).getMagnitude() - + stat.setModifier(static_cast(effects.get(EffectKey(ESM::MagicEffect::FortifyAttribute, i)).getMagnitude() - effects.get(EffectKey(ESM::MagicEffect::DrainAttribute, i)).getMagnitude() - - effects.get(EffectKey(ESM::MagicEffect::AbsorbAttribute, i)).getMagnitude()); + effects.get(EffectKey(ESM::MagicEffect::AbsorbAttribute, i)).getMagnitude())); - stat.damage(effects.get(EffectKey(ESM::MagicEffect::DamageAttribute, i)).getMagnitude() * duration * 1.5); - stat.restore(effects.get(EffectKey(ESM::MagicEffect::RestoreAttribute, i)).getMagnitude() * duration * 1.5); + stat.damage(effects.get(EffectKey(ESM::MagicEffect::DamageAttribute, i)).getMagnitude() * duration); + stat.restore(effects.get(EffectKey(ESM::MagicEffect::RestoreAttribute, i)).getMagnitude() * duration); creatureStats.setAttribute(i, stat); } @@ -535,7 +544,7 @@ namespace MWMechanics { spells.worsenCorprus(it->first); - if (ptr.getRefData().getHandle() == "player") + if (ptr == MWBase::Environment::get().getWorld()->getPlayerPtr()) MWBase::Environment::get().getWindowManager()->messageBox("#{sMagicCorprusWorsens}"); } } @@ -547,7 +556,9 @@ namespace MWMechanics { DynamicStat stat = creatureStats.getDynamic(i); stat.setModifier(effects.get(ESM::MagicEffect::FortifyHealth+i).getMagnitude() - - effects.get(ESM::MagicEffect::DrainHealth+i).getMagnitude()); + effects.get(ESM::MagicEffect::DrainHealth+i).getMagnitude(), + // Fatigue can be decreased below zero meaning the actor will be knocked out + i == 2); float currentDiff = creatureStats.getMagicEffects().get(ESM::MagicEffect::RestoreHealth+i).getMagnitude() @@ -566,19 +577,19 @@ namespace MWMechanics if (!creature || ptr.get()->mBase->mData.mType == ESM::Creature::Creatures) { Stat stat = creatureStats.getAiSetting(CreatureStats::AI_Fight); - stat.setModifier(creatureStats.getMagicEffects().get(ESM::MagicEffect::FrenzyHumanoid+creature).getMagnitude() - - creatureStats.getMagicEffects().get(ESM::MagicEffect::CalmHumanoid+creature).getMagnitude()); + stat.setModifier(static_cast(creatureStats.getMagicEffects().get(ESM::MagicEffect::FrenzyHumanoid + creature).getMagnitude() + - creatureStats.getMagicEffects().get(ESM::MagicEffect::CalmHumanoid+creature).getMagnitude())); creatureStats.setAiSetting(CreatureStats::AI_Fight, stat); stat = creatureStats.getAiSetting(CreatureStats::AI_Flee); - stat.setModifier(creatureStats.getMagicEffects().get(ESM::MagicEffect::DemoralizeHumanoid+creature).getMagnitude() - - creatureStats.getMagicEffects().get(ESM::MagicEffect::RallyHumanoid+creature).getMagnitude()); + stat.setModifier(static_cast(creatureStats.getMagicEffects().get(ESM::MagicEffect::DemoralizeHumanoid + creature).getMagnitude() + - creatureStats.getMagicEffects().get(ESM::MagicEffect::RallyHumanoid+creature).getMagnitude())); creatureStats.setAiSetting(CreatureStats::AI_Flee, stat); } if (creature && ptr.get()->mBase->mData.mType == ESM::Creature::Undead) { Stat stat = creatureStats.getAiSetting(CreatureStats::AI_Flee); - stat.setModifier(creatureStats.getMagicEffects().get(ESM::MagicEffect::TurnUndead).getMagnitude()); + stat.setModifier(static_cast(creatureStats.getMagicEffects().get(ESM::MagicEffect::TurnUndead).getMagnitude())); creatureStats.setAiSetting(CreatureStats::AI_Flee, stat); } @@ -655,7 +666,7 @@ namespace MWMechanics } } - if (receivedMagicDamage && ptr.getRefData().getHandle() == "player") + if (receivedMagicDamage && ptr == MWBase::Environment::get().getWorld()->getPlayerPtr()) MWBase::Environment::get().getWindowManager()->activateHitOverlay(false); creatureStats.setHealth(health); @@ -741,7 +752,7 @@ namespace MWMechanics for (std::map::iterator it = boundItemsMap.begin(); it != boundItemsMap.end(); ++it) { bool found = creatureStats.mBoundItems.find(it->first) != creatureStats.mBoundItems.end(); - int magnitude = creatureStats.getMagicEffects().get(it->first).getMagnitude(); + float magnitude = creatureStats.getMagicEffects().get(it->first).getMagnitude(); if (found != (magnitude > 0)) { std::string itemGmst = it->second; @@ -782,12 +793,12 @@ namespace MWMechanics for(int i = 0;i < ESM::Skill::Length;++i) { SkillValue& skill = npcStats.getSkill(i); - skill.setModifier(effects.get(EffectKey(ESM::MagicEffect::FortifySkill, i)).getMagnitude() - + skill.setModifier(static_cast(effects.get(EffectKey(ESM::MagicEffect::FortifySkill, i)).getMagnitude() - effects.get(EffectKey(ESM::MagicEffect::DrainSkill, i)).getMagnitude() - - effects.get(EffectKey(ESM::MagicEffect::AbsorbSkill, i)).getMagnitude()); + effects.get(EffectKey(ESM::MagicEffect::AbsorbSkill, i)).getMagnitude())); - skill.damage(effects.get(EffectKey(ESM::MagicEffect::DamageSkill, i)).getMagnitude() * duration * 1.5); - skill.restore(effects.get(EffectKey(ESM::MagicEffect::RestoreSkill, i)).getMagnitude() * duration * 1.5); + skill.damage(effects.get(EffectKey(ESM::MagicEffect::DamageSkill, i)).getMagnitude() * duration); + skill.restore(effects.get(EffectKey(ESM::MagicEffect::RestoreSkill, i)).getMagnitude() * duration); } } @@ -838,7 +849,7 @@ namespace MWMechanics void Actors::updateEquippedLight (const MWWorld::Ptr& ptr, float duration) { - bool isPlayer = ptr.getRefData().getHandle()=="player"; + bool isPlayer = (ptr == MWBase::Environment::get().getWorld()->getPlayerPtr()); MWWorld::InventoryStore &inventoryStore = ptr.getClass().getInventoryStore(ptr); MWWorld::ContainerStoreIterator heldIter = @@ -1147,7 +1158,7 @@ namespace MWMechanics // Handle player last, in case a cell transition occurs by casting a teleportation spell // (would invalidate the iterator) - if (iter->first.getCellRef().getRefId() == "player") + if (iter->first == MWBase::Environment::get().getWorld()->getPlayerPtr()) { playerCharacter = iter->second->getCharacterController(); continue; @@ -1331,7 +1342,7 @@ namespace MWMechanics ? (stats.getMagicka().getModified() - stats.getMagicka().getCurrent()) / magickaPerHour : 1.0f; - int autoHours = std::ceil(std::max(1.f, std::max(healthHours, magickaHours))); + int autoHours = static_cast(std::ceil(std::max(1.f, std::max(healthHours, magickaHours)))); return autoHours; } diff --git a/apps/openmw/mwmechanics/aiavoiddoor.cpp b/apps/openmw/mwmechanics/aiavoiddoor.cpp index b9954337d..a73d955c5 100644 --- a/apps/openmw/mwmechanics/aiavoiddoor.cpp +++ b/apps/openmw/mwmechanics/aiavoiddoor.cpp @@ -31,12 +31,12 @@ bool MWMechanics::AiAvoidDoor::execute (const MWWorld::Ptr& actor, AiState& stat float x = pos.pos[0] - mLastPos.pos[0]; float y = pos.pos[1] - mLastPos.pos[1]; float z = pos.pos[2] - mLastPos.pos[2]; - int distance = x * x + y * y + z * z; + float distance = x * x + y * y + z * z; if(distance < 10 * 10) { //Got stuck, didn't move if(mAdjAngle == 0) //Try going in various directions mAdjAngle = 1.57079632679f; //pi/2 else if (mAdjAngle == 1.57079632679f) - mAdjAngle = -1.57079632679; + mAdjAngle = -1.57079632679f; else mAdjAngle = 0; mDuration = 1; //reset timer diff --git a/apps/openmw/mwmechanics/aicombat.cpp b/apps/openmw/mwmechanics/aicombat.cpp index f2b125add..2f68087e5 100644 --- a/apps/openmw/mwmechanics/aicombat.cpp +++ b/apps/openmw/mwmechanics/aicombat.cpp @@ -2,6 +2,8 @@ #include +#include + #include #include "../mwworld/class.hpp" @@ -207,16 +209,6 @@ namespace MWMechanics const MWWorld::Class& actorClass = actor.getClass(); MWBase::World* world = MWBase::Environment::get().getWorld(); - // can't fight if attacker can't go where target is. E.g. A fish can't attack person on land. - if (!actorClass.isNpc() && !MWMechanics::isEnvironmentCompatible(actor, target)) - { - actorClass.getCreatureStats(actor).setAttackingOrSpell(false); - return true; - } - - - - //Update every frame bool& combatMove = storage.mCombatMove; @@ -403,7 +395,7 @@ namespace MWMechanics if (!distantCombat) attackType = chooseBestAttack(weapon, movement); else attackType = ESM::Weapon::AT_Chop; // cause it's =0 - strength = static_cast(rand()) / RAND_MAX; + strength = OEngine::Misc::Rng::rollClosedProbability(); // Note: may be 0 for some animations timerAttack = minMaxAttackDuration[attackType][0] + @@ -414,8 +406,7 @@ namespace MWMechanics { const MWWorld::ESMStore &store = world->getStore(); int chance = store.get().find("iVoiceAttackOdds")->getInt(); - int roll = std::rand()/ (static_cast (RAND_MAX) + 1) * 100; // [0, 99] - if (roll < chance) + if (OEngine::Misc::Rng::roll0to99() < chance) { MWBase::Environment::get().getDialogueManager()->say(actor, "attack"); } @@ -476,6 +467,19 @@ namespace MWMechanics // for distant combat we should know if target is in LOS even if distToTarget < rangeAttack bool inLOS = distantCombat ? world->getLOS(actor, target) : true; + // can't fight if attacker can't go where target is. E.g. A fish can't attack person on land. + if (distToTarget >= rangeAttack + && !actorClass.isNpc() && !MWMechanics::isEnvironmentCompatible(actor, target)) + { + // TODO: start fleeing? + movement.mPosition[0] = 0; + movement.mPosition[1] = 0; + movement.mPosition[2] = 0; + readyToAttack = false; + actorClass.getCreatureStats(actor).setAttackingOrSpell(false); + return false; + } + // (within attack dist) || (not quite attack dist while following) if(inLOS && (distToTarget < rangeAttack || (distToTarget <= rangeFollow && followTarget && !isStuck))) { @@ -509,17 +513,17 @@ namespace MWMechanics { if(movement.mPosition[0] || movement.mPosition[1]) { - timerCombatMove = 0.1f + 0.1f * static_cast(rand())/RAND_MAX; + timerCombatMove = 0.1f + 0.1f * OEngine::Misc::Rng::rollClosedProbability(); combatMove = true; } // only NPCs are smart enough to use dodge movements else if(actorClass.isNpc() && (!distantCombat || (distantCombat && distToTarget < rangeAttack/2))) { //apply sideway movement (kind of dodging) with some probability - if(static_cast(rand())/RAND_MAX < 0.25) + if (OEngine::Misc::Rng::rollClosedProbability() < 0.25) { - movement.mPosition[0] = static_cast(rand())/RAND_MAX < 0.5? 1: -1; - timerCombatMove = 0.05f + 0.15f * static_cast(rand())/RAND_MAX; + movement.mPosition[0] = OEngine::Misc::Rng::rollProbability() < 0.5 ? 1.0f : -1.0f; + timerCombatMove = 0.05f + 0.15f * OEngine::Misc::Rng::rollClosedProbability(); combatMove = true; } } @@ -577,7 +581,7 @@ namespace MWMechanics buildNewPath(actor, target); //may fail to build a path, check before use //delete visited path node - mPathFinder.checkPathCompleted(pos.pos[0],pos.pos[1],pos.pos[2]); + mPathFinder.checkPathCompleted(pos.pos[0],pos.pos[1]); // This works on the borders between the path grid and areas with no waypoints. if(inLOS && mPathFinder.getPath().size() > 1) @@ -585,7 +589,7 @@ namespace MWMechanics // get point just before target std::list::const_iterator pntIter = --mPathFinder.getPath().end(); --pntIter; - Ogre::Vector3 vBeforeTarget = Ogre::Vector3(pntIter->mX, pntIter->mY, pntIter->mZ); + Ogre::Vector3 vBeforeTarget(PathFinder::MakeOgreVector3(*pntIter)); // if current actor pos is closer to target then last point of path (excluding target itself) then go straight on target if(distToTarget <= (vTargetPos - vBeforeTarget).length()) @@ -634,7 +638,7 @@ namespace MWMechanics float s2 = speed2 * t; float t_swing = minMaxAttackDuration[ESM::Weapon::AT_Thrust][0] + - (minMaxAttackDuration[ESM::Weapon::AT_Thrust][1] - minMaxAttackDuration[ESM::Weapon::AT_Thrust][0]) * static_cast(rand()) / RAND_MAX; + (minMaxAttackDuration[ESM::Weapon::AT_Thrust][1] - minMaxAttackDuration[ESM::Weapon::AT_Thrust][0]) * OEngine::Misc::Rng::rollClosedProbability(); if (t + s2/speed1 <= t_swing) { @@ -682,27 +686,21 @@ namespace MWMechanics if(!mPathFinder.getPath().empty()) { ESM::Pathgrid::Point lastPt = mPathFinder.getPath().back(); - Ogre::Vector3 currPathTarget(lastPt.mX, lastPt.mY, lastPt.mZ); + Ogre::Vector3 currPathTarget(PathFinder::MakeOgreVector3(lastPt)); dist = (newPathTarget - currPathTarget).length(); } else dist = 1e+38F; // necessarily construct a new path - float targetPosThreshold = (actor.getCell()->getCell()->isExterior())? 300 : 100; + float targetPosThreshold = (actor.getCell()->getCell()->isExterior())? 300.0f : 100.0f; //construct new path only if target has moved away more than on [targetPosThreshold] if(dist > targetPosThreshold) { ESM::Position pos = actor.getRefData().getPosition(); - ESM::Pathgrid::Point start; - start.mX = pos.pos[0]; - start.mY = pos.pos[1]; - start.mZ = pos.pos[2]; + ESM::Pathgrid::Point start(PathFinder::MakePathgridPoint(pos)); - ESM::Pathgrid::Point dest; - dest.mX = newPathTarget.x; - dest.mY = newPathTarget.y; - dest.mZ = newPathTarget.z; + ESM::Pathgrid::Point dest(PathFinder::MakePathgridPoint(newPathTarget)); if(!mPathFinder.isPathConstructed()) mPathFinder.buildPath(start, dest, actor.getCell(), false); @@ -764,10 +762,10 @@ ESM::Weapon::AttackType chooseBestAttack(const ESM::Weapon* weapon, MWMechanics: if (weapon == NULL) { //hand-to-hand deal equal damage for each type - float roll = static_cast(rand())/RAND_MAX; + float roll = OEngine::Misc::Rng::rollClosedProbability(); if(roll <= 0.333f) //side punch { - movement.mPosition[0] = (static_cast(rand())/RAND_MAX < 0.5f)? 1: -1; + movement.mPosition[0] = OEngine::Misc::Rng::rollClosedProbability() ? 1.0f : -1.0f; movement.mPosition[1] = 0; attackType = ESM::Weapon::AT_Slash; } @@ -789,16 +787,16 @@ ESM::Weapon::AttackType chooseBestAttack(const ESM::Weapon* weapon, MWMechanics: int chop = (weapon->mData.mChop[0] + weapon->mData.mChop[1])/2; int thrust = (weapon->mData.mThrust[0] + weapon->mData.mThrust[1])/2; - float total = slash + chop + thrust; + float total = static_cast(slash + chop + thrust); - float roll = static_cast(rand())/RAND_MAX; - if(roll <= static_cast(slash)/total) + float roll = OEngine::Misc::Rng::rollClosedProbability(); + if(roll <= (slash/total)) { - movement.mPosition[0] = (static_cast(rand())/RAND_MAX < 0.5f)? 1: -1; + movement.mPosition[0] = (OEngine::Misc::Rng::rollClosedProbability() < 0.5f) ? 1.0f : -1.0f; movement.mPosition[1] = 0; attackType = ESM::Weapon::AT_Slash; } - else if(roll <= (static_cast(slash) + static_cast(thrust))/total) + else if(roll <= (slash + (thrust/total))) { movement.mPosition[1] = 1; attackType = ESM::Weapon::AT_Thrust; diff --git a/apps/openmw/mwmechanics/aicombataction.cpp b/apps/openmw/mwmechanics/aicombataction.cpp index 175b98001..33e3c3d67 100644 --- a/apps/openmw/mwmechanics/aicombataction.cpp +++ b/apps/openmw/mwmechanics/aicombataction.cpp @@ -323,14 +323,14 @@ namespace MWMechanics if (effect.mAttribute >= 0 && effect.mAttribute < ESM::Attribute::Length) { const float attributePriorities[ESM::Attribute::Length] = { - 1.f, // Strength - 0.5, // Intelligence - 0.6, // Willpower - 0.7, // Agility - 0.5, // Speed - 0.8, // Endurance - 0.7, // Personality - 0.3 // Luck + 1.0f, // Strength + 0.5f, // Intelligence + 0.6f, // Willpower + 0.7f, // Agility + 0.5f, // Speed + 0.8f, // Endurance + 0.7f, // Personality + 0.3f // Luck }; rating *= attributePriorities[effect.mAttribute]; } diff --git a/apps/openmw/mwmechanics/aiescort.cpp b/apps/openmw/mwmechanics/aiescort.cpp index c89cfe492..91bf7c9b0 100644 --- a/apps/openmw/mwmechanics/aiescort.cpp +++ b/apps/openmw/mwmechanics/aiescort.cpp @@ -23,7 +23,7 @@ namespace MWMechanics { AiEscort::AiEscort(const std::string &actorId, int duration, float x, float y, float z) - : mActorId(actorId), mX(x), mY(y), mZ(z), mRemainingDuration(duration) + : mActorId(actorId), mX(x), mY(y), mZ(z), mRemainingDuration(static_cast(duration)) , mCellX(std::numeric_limits::max()) , mCellY(std::numeric_limits::max()) { @@ -36,7 +36,7 @@ namespace MWMechanics } AiEscort::AiEscort(const std::string &actorId, const std::string &cellId,int duration, float x, float y, float z) - : mActorId(actorId), mCellId(cellId), mX(x), mY(y), mZ(z), mRemainingDuration(duration) + : mActorId(actorId), mCellId(cellId), mX(x), mY(y), mZ(z), mRemainingDuration(static_cast(duration)) , mCellX(std::numeric_limits::max()) , mCellY(std::numeric_limits::max()) { @@ -86,13 +86,13 @@ namespace MWMechanics for (short counter = 0; counter < 3; counter++) differenceBetween[counter] = (leaderPos[counter] - followerPos[counter]); - float distanceBetweenResult = + double distanceBetweenResult = (differenceBetween[0] * differenceBetween[0]) + (differenceBetween[1] * differenceBetween[1]) + (differenceBetween[2] * differenceBetween[2]); if(distanceBetweenResult <= mMaxDist * mMaxDist) { - ESM::Pathgrid::Point point(mX,mY,mZ); + ESM::Pathgrid::Point point(static_cast(mX), static_cast(mY), static_cast(mZ)); point.mAutogenerated = 0; point.mConnectionNum = 0; point.mUnknown = 0; diff --git a/apps/openmw/mwmechanics/aipackage.cpp b/apps/openmw/mwmechanics/aipackage.cpp index f015bb8a4..52a975320 100644 --- a/apps/openmw/mwmechanics/aipackage.cpp +++ b/apps/openmw/mwmechanics/aipackage.cpp @@ -16,7 +16,7 @@ MWMechanics::AiPackage::~AiPackage() {} -MWMechanics::AiPackage::AiPackage() : mTimer(.26), mStuckTimer(0) { //mTimer starts at .26 to force initial pathbuild +MWMechanics::AiPackage::AiPackage() : mTimer(0.26f), mStuckTimer(0) { //mTimer starts at .26 to force initial pathbuild } @@ -86,7 +86,7 @@ bool MWMechanics::AiPackage::pathTo(const MWWorld::Ptr& actor, ESM::Pathgrid::Po //************************ /// Checks if you aren't moving; attempts to unstick you //************************ - if(mPathFinder.checkPathCompleted(pos.pos[0],pos.pos[1],pos.pos[2])) //Path finished? + if(mPathFinder.checkPathCompleted(pos.pos[0],pos.pos[1])) //Path finished? return true; else if(mStuckTimer>0.5) //Every half second see if we need to take action to avoid something { diff --git a/apps/openmw/mwmechanics/aipackage.hpp b/apps/openmw/mwmechanics/aipackage.hpp index 80b48fc37..179ae440b 100644 --- a/apps/openmw/mwmechanics/aipackage.hpp +++ b/apps/openmw/mwmechanics/aipackage.hpp @@ -16,7 +16,7 @@ namespace ESM { namespace AiSequence { - class AiSequence; + struct AiSequence; } } diff --git a/apps/openmw/mwmechanics/aisequence.cpp b/apps/openmw/mwmechanics/aisequence.cpp index 533bcd17c..bb078f883 100644 --- a/apps/openmw/mwmechanics/aisequence.cpp +++ b/apps/openmw/mwmechanics/aisequence.cpp @@ -294,7 +294,7 @@ void AiSequence::fill(const ESM::AIPackageList &list) idles.reserve(8); for (int i=0; i<8; ++i) idles.push_back(data.mIdle[i]); - package = new MWMechanics::AiWander(data.mDistance, data.mDuration, data.mTimeOfDay, idles, data.mShouldRepeat); + package = new MWMechanics::AiWander(data.mDistance, data.mDuration, data.mTimeOfDay, idles, data.mShouldRepeat != 0); } else if (it->mType == ESM::AI_Escort) { diff --git a/apps/openmw/mwmechanics/aisequence.hpp b/apps/openmw/mwmechanics/aisequence.hpp index e43ce72f1..19f1e1454 100644 --- a/apps/openmw/mwmechanics/aisequence.hpp +++ b/apps/openmw/mwmechanics/aisequence.hpp @@ -15,7 +15,7 @@ namespace ESM { namespace AiSequence { - class AiSequence; + struct AiSequence; } } diff --git a/apps/openmw/mwmechanics/aitravel.cpp b/apps/openmw/mwmechanics/aitravel.cpp index 7124a1102..2824e2c6c 100644 --- a/apps/openmw/mwmechanics/aitravel.cpp +++ b/apps/openmw/mwmechanics/aitravel.cpp @@ -93,20 +93,14 @@ namespace MWMechanics mCellX = cell->mData.mX; mCellY = cell->mData.mY; - ESM::Pathgrid::Point dest; - dest.mX = mX; - dest.mY = mY; - dest.mZ = mZ; + ESM::Pathgrid::Point dest(static_cast(mX), static_cast(mY), static_cast(mZ)); - ESM::Pathgrid::Point start; - start.mX = pos.pos[0]; - start.mY = pos.pos[1]; - start.mZ = pos.pos[2]; + ESM::Pathgrid::Point start(PathFinder::MakePathgridPoint(pos)); mPathFinder.buildPath(start, dest, actor.getCell(), true); } - if(mPathFinder.checkPathCompleted(pos.pos[0], pos.pos[1], pos.pos[2])) + if(mPathFinder.checkPathCompleted(pos.pos[0], pos.pos[1])) { movement.mPosition[1] = 0; return true; diff --git a/apps/openmw/mwmechanics/aiwander.cpp b/apps/openmw/mwmechanics/aiwander.cpp index fbb147b34..d277b1249 100644 --- a/apps/openmw/mwmechanics/aiwander.cpp +++ b/apps/openmw/mwmechanics/aiwander.cpp @@ -3,6 +3,8 @@ #include #include +#include + #include #include "../mwbase/world.hpp" @@ -29,6 +31,18 @@ namespace MWMechanics static const int GREETING_SHOULD_START = 4; //how many reaction intervals should pass before NPC can greet player static const int GREETING_SHOULD_END = 10; + const std::string AiWander::sIdleSelectToGroupName[GroupIndex_MaxIdle - GroupIndex_MinIdle + 1] = + { + std::string("idle2"), + std::string("idle3"), + std::string("idle4"), + std::string("idle5"), + std::string("idle6"), + std::string("idle7"), + std::string("idle8"), + std::string("idle9"), + }; + /// \brief This class holds the variables AiWander needs which are deleted if the package becomes inactive. struct AiWanderStorage : AiTemporaryBase { @@ -192,7 +206,7 @@ namespace MWMechanics if(mDistance && // actor is not intended to be stationary idleNow && // but is in idle !walking && // FIXME: some actors are idle while walking - proximityToDoor(actor, MIN_DIST_TO_DOOR_SQUARED*1.6*1.6)) // NOTE: checks interior cells only + proximityToDoor(actor, MIN_DIST_TO_DOOR_SQUARED*1.6f*1.6f)) // NOTE: checks interior cells only { idleNow = false; moveNow = true; @@ -203,7 +217,7 @@ namespace MWMechanics // Are we there yet? bool& chooseAction = storage.mChooseAction; if(walking && - storage.mPathFinder.checkPathCompleted(pos.pos[0], pos.pos[1], pos.pos[2], 64.f)) + storage.mPathFinder.checkPathCompleted(pos.pos[0], pos.pos[1], 64.f)) { stopWalking(actor, storage); moveNow = false; @@ -315,13 +329,13 @@ namespace MWMechanics static float fVoiceIdleOdds = MWBase::Environment::get().getWorld()->getStore() .get().find("fVoiceIdleOdds")->getFloat(); - float roll = std::rand()/ (static_cast (RAND_MAX) + 1) * 10000; + float roll = OEngine::Misc::Rng::rollProbability() * 10000.0f; // In vanilla MW the chance was FPS dependent, and did not allow proper changing of fVoiceIdleOdds // due to the roll being an integer. // Our implementation does not have these issues, so needs to be recalibrated. We chose to // use the chance MW would have when run at 60 FPS with the default value of the GMST for calibration. - float x = fVoiceIdleOdds * 0.6 * (MWBase::Environment::get().getFrameDuration() / 0.1); + float x = fVoiceIdleOdds * 0.6f * (MWBase::Environment::get().getFrameDuration() / 0.1f); // Only say Idle voices when player is in LOS // A bit counterintuitive, likely vanilla did this to reduce the appearance of @@ -393,18 +407,10 @@ namespace MWMechanics if (!storage.mPathFinder.isPathConstructed()) { - Ogre::Vector3 destNodePos = mReturnPosition; - - ESM::Pathgrid::Point dest; - dest.mX = destNodePos[0]; - dest.mY = destNodePos[1]; - dest.mZ = destNodePos[2]; + ESM::Pathgrid::Point dest(PathFinder::MakePathgridPoint(mReturnPosition)); // actor position is already in world co-ordinates - ESM::Pathgrid::Point start; - start.mX = pos.pos[0]; - start.mY = pos.pos[1]; - start.mZ = pos.pos[2]; + ESM::Pathgrid::Point start(PathFinder::MakePathgridPoint(pos)); // don't take shortcuts for wandering storage.mPathFinder.buildPath(start, dest, actor.getCell(), false); @@ -422,7 +428,7 @@ namespace MWMechanics { // Play a random voice greeting if the player gets too close int hello = cStats.getAiSetting(CreatureStats::AI_Hello).getModified(); - float helloDistance = hello; + float helloDistance = static_cast(hello); static int iGreetDistanceMultiplier =MWBase::Environment::get().getWorld()->getStore() .get().find("iGreetDistanceMultiplier")->getInt(); @@ -498,17 +504,12 @@ namespace MWMechanics if(!storage.mPathFinder.isPathConstructed()) { assert(mAllowedNodes.size()); - unsigned int randNode = (int)(rand() / ((double)RAND_MAX + 1) * mAllowedNodes.size()); + unsigned int randNode = OEngine::Misc::Rng::rollDice(mAllowedNodes.size()); // NOTE: initially constructed with local (i.e. cell) co-ordinates - Ogre::Vector3 destNodePos(mAllowedNodes[randNode].mX, - mAllowedNodes[randNode].mY, - mAllowedNodes[randNode].mZ); + Ogre::Vector3 destNodePos(PathFinder::MakeOgreVector3(mAllowedNodes[randNode])); // convert dest to use world co-ordinates - ESM::Pathgrid::Point dest; - dest.mX = destNodePos[0]; - dest.mY = destNodePos[1]; - dest.mZ = destNodePos[2]; + ESM::Pathgrid::Point dest(PathFinder::MakePathgridPoint(destNodePos)); if (currentCell->getCell()->isExterior()) { dest.mX += currentCell->getCell()->mData.mX * ESM::Land::REAL_SIZE; @@ -516,10 +517,7 @@ namespace MWMechanics } // actor position is already in world co-ordinates - ESM::Pathgrid::Point start; - start.mX = pos.pos[0]; - start.mY = pos.pos[1]; - start.mZ = pos.pos[2]; + ESM::Pathgrid::Point start(PathFinder::MakePathgridPoint(pos)); // don't take shortcuts for wandering storage.mPathFinder.buildPath(start, dest, actor.getCell(), false); @@ -594,44 +592,24 @@ namespace MWMechanics void AiWander::playIdle(const MWWorld::Ptr& actor, unsigned short idleSelect) { - if(idleSelect == 2) - MWBase::Environment::get().getMechanicsManager()->playAnimationGroup(actor, "idle2", 0, 1); - else if(idleSelect == 3) - MWBase::Environment::get().getMechanicsManager()->playAnimationGroup(actor, "idle3", 0, 1); - else if(idleSelect == 4) - MWBase::Environment::get().getMechanicsManager()->playAnimationGroup(actor, "idle4", 0, 1); - else if(idleSelect == 5) - MWBase::Environment::get().getMechanicsManager()->playAnimationGroup(actor, "idle5", 0, 1); - else if(idleSelect == 6) - MWBase::Environment::get().getMechanicsManager()->playAnimationGroup(actor, "idle6", 0, 1); - else if(idleSelect == 7) - MWBase::Environment::get().getMechanicsManager()->playAnimationGroup(actor, "idle7", 0, 1); - else if(idleSelect == 8) - MWBase::Environment::get().getMechanicsManager()->playAnimationGroup(actor, "idle8", 0, 1); - else if(idleSelect == 9) - MWBase::Environment::get().getMechanicsManager()->playAnimationGroup(actor, "idle9", 0, 1); + if ((GroupIndex_MinIdle <= idleSelect) && (idleSelect <= GroupIndex_MaxIdle)) + { + const std::string& groupName = sIdleSelectToGroupName[idleSelect - GroupIndex_MinIdle]; + MWBase::Environment::get().getMechanicsManager()->playAnimationGroup(actor, groupName, 0, 1); + } } bool AiWander::checkIdle(const MWWorld::Ptr& actor, unsigned short idleSelect) { - if(idleSelect == 2) - return MWBase::Environment::get().getMechanicsManager()->checkAnimationPlaying(actor, "idle2"); - else if(idleSelect == 3) - return MWBase::Environment::get().getMechanicsManager()->checkAnimationPlaying(actor, "idle3"); - else if(idleSelect == 4) - return MWBase::Environment::get().getMechanicsManager()->checkAnimationPlaying(actor, "idle4"); - else if(idleSelect == 5) - return MWBase::Environment::get().getMechanicsManager()->checkAnimationPlaying(actor, "idle5"); - else if(idleSelect == 6) - return MWBase::Environment::get().getMechanicsManager()->checkAnimationPlaying(actor, "idle6"); - else if(idleSelect == 7) - return MWBase::Environment::get().getMechanicsManager()->checkAnimationPlaying(actor, "idle7"); - else if(idleSelect == 8) - return MWBase::Environment::get().getMechanicsManager()->checkAnimationPlaying(actor, "idle8"); - else if(idleSelect == 9) - return MWBase::Environment::get().getMechanicsManager()->checkAnimationPlaying(actor, "idle9"); + if ((GroupIndex_MinIdle <= idleSelect) && (idleSelect <= GroupIndex_MaxIdle)) + { + const std::string& groupName = sIdleSelectToGroupName[idleSelect - GroupIndex_MinIdle]; + return MWBase::Environment::get().getMechanicsManager()->checkAnimationPlaying(actor, groupName); + } else + { return false; + } } void AiWander::setReturnPosition(const Ogre::Vector3& position) @@ -652,8 +630,8 @@ namespace MWMechanics static float fIdleChanceMultiplier = MWBase::Environment::get().getWorld()->getStore() .get().find("fIdleChanceMultiplier")->getFloat(); - unsigned short idleChance = fIdleChanceMultiplier * mIdle[counter]; - unsigned short randSelect = (int)(rand() / ((double)RAND_MAX + 1) * int(100 / fIdleChanceMultiplier)); + unsigned short idleChance = static_cast(fIdleChanceMultiplier * mIdle[counter]); + unsigned short randSelect = (int)(OEngine::Misc::Rng::rollProbability() * int(100 / fIdleChanceMultiplier)); if(randSelect < idleChance && randSelect > idleRoll) { playedIdle = counter+2; @@ -675,12 +653,12 @@ namespace MWMechanics state.moveIn(new AiWanderStorage()); - int index = std::rand() / (static_cast (RAND_MAX) + 1) * mAllowedNodes.size(); + int index = OEngine::Misc::Rng::rollDice(mAllowedNodes.size()); ESM::Pathgrid::Point dest = mAllowedNodes[index]; // apply a slight offset to prevent overcrowding - dest.mX += Ogre::Math::RangeRandom(-64, 64); - dest.mY += Ogre::Math::RangeRandom(-64, 64); + dest.mX += static_cast(Ogre::Math::RangeRandom(-64, 64)); + dest.mY += static_cast(Ogre::Math::RangeRandom(-64, 64)); if (actor.getCell()->isExterior()) { @@ -688,7 +666,8 @@ namespace MWMechanics dest.mY += actor.getCell()->getCell()->mData.mY * ESM::Land::REAL_SIZE; } - MWBase::Environment::get().getWorld()->moveObject(actor, dest.mX, dest.mY, dest.mZ); + MWBase::Environment::get().getWorld()->moveObject(actor, static_cast(dest.mX), + static_cast(dest.mY), static_cast(dest.mZ)); actor.getClass().adjustPosition(actor, false); } @@ -720,8 +699,8 @@ namespace MWMechanics float cellYOffset = 0; if(cell->isExterior()) { - cellXOffset = cell->mData.mX * ESM::Land::REAL_SIZE; - cellYOffset = cell->mData.mY * ESM::Land::REAL_SIZE; + cellXOffset = static_cast(cell->mData.mX * ESM::Land::REAL_SIZE); + cellYOffset = static_cast(cell->mData.mY * ESM::Land::REAL_SIZE); } // convert npcPos to local (i.e. cell) co-ordinates @@ -733,20 +712,18 @@ namespace MWMechanics // NOTE: mPoints and mAllowedNodes are in local co-ordinates for(unsigned int counter = 0; counter < pathgrid->mPoints.size(); counter++) { - Ogre::Vector3 nodePos(pathgrid->mPoints[counter].mX, pathgrid->mPoints[counter].mY, - pathgrid->mPoints[counter].mZ); + Ogre::Vector3 nodePos(PathFinder::MakeOgreVector3(pathgrid->mPoints[counter])); if(npcPos.squaredDistance(nodePos) <= mDistance * mDistance) mAllowedNodes.push_back(pathgrid->mPoints[counter]); } if(!mAllowedNodes.empty()) { - Ogre::Vector3 firstNodePos(mAllowedNodes[0].mX, mAllowedNodes[0].mY, mAllowedNodes[0].mZ); + Ogre::Vector3 firstNodePos(PathFinder::MakeOgreVector3(mAllowedNodes[0])); float closestNode = npcPos.squaredDistance(firstNodePos); unsigned int index = 0; for(unsigned int counterThree = 1; counterThree < mAllowedNodes.size(); counterThree++) { - Ogre::Vector3 nodePos(mAllowedNodes[counterThree].mX, mAllowedNodes[counterThree].mY, - mAllowedNodes[counterThree].mZ); + Ogre::Vector3 nodePos(PathFinder::MakeOgreVector3(mAllowedNodes[counterThree])); float tempDist = npcPos.squaredDistance(nodePos); if(tempDist < closestNode) index = counterThree; @@ -785,7 +762,7 @@ namespace MWMechanics , mDuration(wander->mData.mDuration) , mStartTime(MWWorld::TimeStamp(wander->mStartTime)) , mTimeOfDay(wander->mData.mTimeOfDay) - , mRepeat(wander->mData.mShouldRepeat) + , mRepeat(wander->mData.mShouldRepeat != 0) , mStoredInitialActorPosition(wander->mStoredInitialActorPosition) { if (mStoredInitialActorPosition) diff --git a/apps/openmw/mwmechanics/aiwander.hpp b/apps/openmw/mwmechanics/aiwander.hpp index 5e1b41813..7e138c001 100644 --- a/apps/openmw/mwmechanics/aiwander.hpp +++ b/apps/openmw/mwmechanics/aiwander.hpp @@ -17,7 +17,7 @@ namespace ESM { - class Cell; + struct Cell; namespace AiSequence { struct AiWander; @@ -113,7 +113,15 @@ namespace MWMechanics float mDoorCheckDuration; int mStuckCount; + // constants for converting idleSelect values into groupNames + enum GroupIndex + { + GroupIndex_MinIdle = 2, + GroupIndex_MaxIdle = 9 + }; + /// lookup table for converting idleSelect value to groupName + static const std::string sIdleSelectToGroupName[GroupIndex_MaxIdle - GroupIndex_MinIdle + 1]; }; diff --git a/apps/openmw/mwmechanics/alchemy.cpp b/apps/openmw/mwmechanics/alchemy.cpp index f3d376a70..58c42ddb8 100644 --- a/apps/openmw/mwmechanics/alchemy.cpp +++ b/apps/openmw/mwmechanics/alchemy.cpp @@ -8,6 +8,8 @@ #include #include +#include + #include #include #include @@ -67,7 +69,7 @@ void MWMechanics::Alchemy::applyTools (int flags, float& value) const { bool magnitude = !(flags & ESM::MagicEffect::NoMagnitude); bool duration = !(flags & ESM::MagicEffect::NoDuration); - bool negative = flags & (ESM::MagicEffect::Harmful); + bool negative = (flags & ESM::MagicEffect::Harmful) != 0; int tool = negative ? ESM::Apparatus::Retort : ESM::Apparatus::Albemic; @@ -94,17 +96,17 @@ void MWMechanics::Alchemy::applyTools (int flags, float& value) const quality = negative ? 2 * toolQuality + 3 * calcinatorQuality : (magnitude && duration ? - 2 * toolQuality + calcinatorQuality : 2/3.0 * (toolQuality + calcinatorQuality) + 0.5); + 2 * toolQuality + calcinatorQuality : 2/3.0f * (toolQuality + calcinatorQuality) + 0.5f); break; case 2: - quality = negative ? 1+toolQuality : (magnitude && duration ? toolQuality : toolQuality + 0.5); + quality = negative ? 1+toolQuality : (magnitude && duration ? toolQuality : toolQuality + 0.5f); break; case 3: - quality = magnitude && duration ? calcinatorQuality : calcinatorQuality + 0.5; + quality = magnitude && duration ? calcinatorQuality : calcinatorQuality + 0.5f; break; } @@ -178,8 +180,8 @@ void MWMechanics::Alchemy::updateEffects() if (!(magicEffect->mData.mFlags & ESM::MagicEffect::NoDuration)) applyTools (magicEffect->mData.mFlags, duration); - duration = static_cast (duration+0.5); - magnitude = static_cast (magnitude+0.5); + duration = roundf(duration); + magnitude = roundf(magnitude); if (magnitude>0 && duration>0) { @@ -197,8 +199,8 @@ void MWMechanics::Alchemy::updateEffects() effect.mRange = 0; effect.mArea = 0; - effect.mDuration = duration; - effect.mMagnMin = effect.mMagnMax = magnitude; + effect.mDuration = static_cast(duration); + effect.mMagnMin = effect.mMagnMax = static_cast(magnitude); mEffects.push_back (effect); } @@ -294,7 +296,7 @@ void MWMechanics::Alchemy::addPotion (const std::string& name) newRecord.mName = name; - int index = static_cast (std::rand()/(static_cast (RAND_MAX)+1)*6); + int index = OEngine::Misc::Rng::rollDice(6); assert (index>=0 && index<6); static const char *meshes[] = { "standard", "bargain", "cheap", "fresh", "exclusive", "quality" }; @@ -323,8 +325,8 @@ float MWMechanics::Alchemy::getAlchemyFactor() const return (npcStats.getSkill (ESM::Skill::Alchemy).getModified() + - 0.1 * creatureStats.getAttribute (ESM::Attribute::Intelligence).getModified() - + 0.1 * creatureStats.getAttribute (ESM::Attribute::Luck).getModified()); + 0.1f * creatureStats.getAttribute (ESM::Attribute::Intelligence).getModified() + + 0.1f * creatureStats.getAttribute (ESM::Attribute::Luck).getModified()); } int MWMechanics::Alchemy::countIngredients() const @@ -467,7 +469,7 @@ MWMechanics::Alchemy::Result MWMechanics::Alchemy::create (const std::string& na return Result_RandomFailure; } - if (getAlchemyFactor() (RAND_MAX)*100) + if (getAlchemyFactor() < OEngine::Misc::Rng::roll0to99()) { removeIngredients(); return Result_RandomFailure; diff --git a/apps/openmw/mwmechanics/autocalcspell.cpp b/apps/openmw/mwmechanics/autocalcspell.cpp index 7b8c43a06..e4b143826 100644 --- a/apps/openmw/mwmechanics/autocalcspell.cpp +++ b/apps/openmw/mwmechanics/autocalcspell.cpp @@ -187,7 +187,7 @@ namespace MWMechanics for (std::vector::const_iterator it = effects.mList.begin(); it != effects.mList.end(); ++it) { const ESM::ENAMstruct& effect = *it; - float x = effect.mDuration; + float x = static_cast(effect.mDuration); const ESM::MagicEffect* magicEffect = MWBase::Environment::get().getWorld()->getStore().get().find(effect.mEffectID); if (!(magicEffect->mData.mFlags & ESM::MagicEffect::UncappedDamage)) diff --git a/apps/openmw/mwmechanics/character.cpp b/apps/openmw/mwmechanics/character.cpp index 449c030f4..ffde59aee 100644 --- a/apps/openmw/mwmechanics/character.cpp +++ b/apps/openmw/mwmechanics/character.cpp @@ -27,6 +27,8 @@ #include "creaturestats.hpp" #include "security.hpp" +#include + #include #include "../mwrender/animation.hpp" @@ -112,7 +114,7 @@ float getFallDamage(const MWWorld::Ptr& ptr, float fallHeight) if (fallHeight >= fallDistanceMin) { - const float acrobaticsSkill = ptr.getClass().getSkill(ptr, ESM::Skill::Acrobatics); + const float acrobaticsSkill = static_cast(ptr.getClass().getSkill(ptr, ESM::Skill::Acrobatics)); const float jumpSpellBonus = ptr.getClass().getCreatureStats(ptr).getMagicEffects().get(ESM::MagicEffect::Jump).getMagnitude(); const float fallAcroBase = store.find("fFallAcroBase")->getFloat(); const float fallAcroMult = store.find("fFallAcroMult")->getFloat(); @@ -120,7 +122,7 @@ float getFallDamage(const MWWorld::Ptr& ptr, float fallHeight) const float fallDistanceMult = store.find("fFallDistanceMult")->getFloat(); float x = fallHeight - fallDistanceMin; - x -= (1.5 * acrobaticsSkill) + jumpSpellBonus; + x -= (1.5f * acrobaticsSkill) + jumpSpellBonus; x = std::max(0.0f, x); float a = fallAcroBase + fallAcroMult * (100 - acrobaticsSkill); @@ -220,7 +222,7 @@ std::string CharacterController::chooseRandomGroup (const std::string& prefix, i while (mAnimation->hasAnimation(prefix + Ogre::StringConverter::toString(numAnims+1))) ++numAnims; - int roll = std::rand()/ (static_cast (RAND_MAX) + 1) * numAnims + 1; // [1, numAnims] + int roll = OEngine::Misc::Rng::rollDice(numAnims) + 1; // [1, numAnims] if (num) *num = roll; return prefix + Ogre::StringConverter::toString(roll); @@ -829,7 +831,7 @@ bool CharacterController::updateCreatureState() } if (weapType != WeapType_Spell || !mAnimation->hasAnimation("spellcast")) // Not all creatures have a dedicated spellcast animation { - int roll = std::rand()/ (static_cast (RAND_MAX) + 1) * 3; // [0, 2] + int roll = OEngine::Misc::Rng::rollDice(3); // [0, 2] if (roll == 0) mCurrentWeapon = "attack1"; else if (roll == 1) @@ -1010,7 +1012,7 @@ bool CharacterController::updateWeaponState() // For the player, set the spell we want to cast // This has to be done at the start of the casting animation, // *not* when selecting a spell in the GUI (otherwise you could change the spell mid-animation) - if (mPtr.getRefData().getHandle() == "player") + if (mPtr == MWBase::Environment::get().getWorld()->getPlayerPtr()) { std::string selectedSpell = MWBase::Environment::get().getWindowManager()->getSelectedSpell(); stats.getSpells().setSelectedSpell(selectedSpell); @@ -1094,7 +1096,7 @@ bool CharacterController::updateWeaponState() mAttackType = "shoot"; else { - if(isWeapon && mPtr.getRefData().getHandle() == "player" && + if(isWeapon && mPtr == MWBase::Environment::get().getWorld()->getPlayerPtr() && Settings::Manager::getBool("best attack", "Game")) { MWWorld::ContainerStoreIterator weapon = mPtr.getClass().getInventoryStore(mPtr).getSlot(MWWorld::InventoryStore::Slot_CarriedRight); @@ -1125,7 +1127,7 @@ bool CharacterController::updateWeaponState() // most creatures don't actually have an attack wind-up animation, so use a uniform random value // (even some creatures that can use weapons don't have a wind-up animation either, e.g. Rieklings) // Note: vanilla MW uses a random value for *all* non-player actors, but we probably don't need to go that far. - attackStrength = std::min(1.f, 0.1f + std::rand() / float(RAND_MAX)); + attackStrength = std::min(1.f, 0.1f + OEngine::Misc::Rng::rollClosedProbability()); } if(mWeaponType != WeapType_Crossbow && mWeaponType != WeapType_BowAndArrow) @@ -1421,7 +1423,7 @@ void CharacterController::update(float duration) // advance athletics - if(mHasMovedInXY && mPtr.getRefData().getHandle() == "player") + if(mHasMovedInXY && mPtr == MWBase::Environment::get().getWorld()->getPlayerPtr()) { if(inwater) { @@ -1521,7 +1523,7 @@ void CharacterController::update(float duration) } // advance acrobatics - if (mPtr.getRefData().getHandle() == "player") + if (mPtr == MWBase::Environment::get().getWorld()->getPlayerPtr()) cls.skillUsageSucceeded(mPtr, ESM::Skill::Acrobatics, 0); // decrease fatigue @@ -1531,7 +1533,7 @@ void CharacterController::update(float duration) float normalizedEncumbrance = mPtr.getClass().getNormalizedEncumbrance(mPtr); if (normalizedEncumbrance > 1) normalizedEncumbrance = 1; - const int fatigueDecrease = fatigueJumpBase + (1 - normalizedEncumbrance) * fatigueJumpMult; + const float fatigueDecrease = fatigueJumpBase + (1 - normalizedEncumbrance) * fatigueJumpMult; DynamicStat fatigue = cls.getCreatureStats(mPtr).getFatigue(); fatigue.setCurrent(fatigue.getCurrent() - fatigueDecrease); cls.getCreatureStats(mPtr).setFatigue(fatigue); @@ -1551,12 +1553,12 @@ void CharacterController::update(float duration) // inflict fall damages DynamicStat health = cls.getCreatureStats(mPtr).getHealth(); - int realHealthLost = healthLost * (1.0f - 0.25 * fatigueTerm); + float realHealthLost = static_cast(healthLost * (1.0f - 0.25f * fatigueTerm)); health.setCurrent(health.getCurrent() - realHealthLost); cls.getCreatureStats(mPtr).setHealth(health); cls.onHit(mPtr, realHealthLost, true, MWWorld::Ptr(), MWWorld::Ptr(), true); - const float acrobaticsSkill = cls.getSkill(mPtr, ESM::Skill::Acrobatics); + const int acrobaticsSkill = cls.getSkill(mPtr, ESM::Skill::Acrobatics); if (healthLost > (acrobaticsSkill * fatigueTerm)) { cls.getCreatureStats(mPtr).setKnockedDown(true); @@ -1564,7 +1566,7 @@ void CharacterController::update(float duration) else { // report acrobatics progression - if (mPtr.getRefData().getHandle() == "player") + if (mPtr == MWBase::Environment::get().getWorld()->getPlayerPtr()) cls.skillUsageSucceeded(mPtr, ESM::Skill::Acrobatics, 1); } } @@ -1612,7 +1614,7 @@ void CharacterController::update(float duration) mTurnAnimationThreshold -= duration; if (movestate == CharState_TurnRight || movestate == CharState_TurnLeft) - mTurnAnimationThreshold = 0.05; + mTurnAnimationThreshold = 0.05f; else if (movestate == CharState_None && (mMovementState == CharState_TurnRight || mMovementState == CharState_TurnLeft) && mTurnAnimationThreshold > 0) { @@ -1797,7 +1799,7 @@ bool CharacterController::kill() { if( isDead() ) { - if( mPtr.getRefData().getHandle()=="player" && !isAnimPlaying(mCurrentDeath) ) + if( mPtr == MWBase::Environment::get().getWorld()->getPlayerPtr() && !isAnimPlaying(mCurrentDeath) ) { //player's death animation is over MWBase::Environment::get().getStateManager()->askLoadRecent(); @@ -1813,7 +1815,7 @@ bool CharacterController::kill() mCurrentIdle.clear(); // Play Death Music if it was the player dying - if(mPtr.getRefData().getHandle()=="player") + if(mPtr == MWBase::Environment::get().getWorld()->getPlayerPtr()) MWBase::Environment::get().getSoundManager()->streamMusic("Special/MW_Death.mp3"); return true; @@ -1854,7 +1856,7 @@ void CharacterController::updateMagicEffects() float alpha = 1.f; if (mPtr.getClass().getCreatureStats(mPtr).getMagicEffects().get(ESM::MagicEffect::Invisibility).getMagnitude()) { - if (mPtr.getRefData().getHandle() == "player") + if (mPtr == MWBase::Environment::get().getWorld()->getPlayerPtr()) alpha = 0.4f; else alpha = 0.f; diff --git a/apps/openmw/mwmechanics/character.hpp b/apps/openmw/mwmechanics/character.hpp index 8a77494b9..da74b2a33 100644 --- a/apps/openmw/mwmechanics/character.hpp +++ b/apps/openmw/mwmechanics/character.hpp @@ -21,7 +21,7 @@ namespace MWRender namespace MWMechanics { -class Movement; +struct Movement; class CreatureStats; enum Priority { diff --git a/apps/openmw/mwmechanics/combat.cpp b/apps/openmw/mwmechanics/combat.cpp index e22e9ec24..c5fc34507 100644 --- a/apps/openmw/mwmechanics/combat.cpp +++ b/apps/openmw/mwmechanics/combat.cpp @@ -2,6 +2,8 @@ #include +#include + #include "../mwbase/environment.hpp" #include "../mwbase/world.hpp" #include "../mwbase/mechanicsmanager.hpp" @@ -83,8 +85,8 @@ namespace MWMechanics MWMechanics::CreatureStats& attackerStats = attacker.getClass().getCreatureStats(attacker); - float blockTerm = blocker.getClass().getSkill(blocker, ESM::Skill::Block) + 0.2 * blockerStats.getAttribute(ESM::Attribute::Agility).getModified() - + 0.1 * blockerStats.getAttribute(ESM::Attribute::Luck).getModified(); + float blockTerm = blocker.getClass().getSkill(blocker, ESM::Skill::Block) + 0.2f * blockerStats.getAttribute(ESM::Attribute::Agility).getModified() + + 0.1f * blockerStats.getAttribute(ESM::Attribute::Luck).getModified(); float enemySwing = attackerStats.getAttackStrength(); float swingTerm = enemySwing * gmst.find("fSwingBlockMult")->getFloat() + gmst.find("fSwingBlockBase")->getFloat(); @@ -93,13 +95,13 @@ namespace MWMechanics blockerTerm *= gmst.find("fBlockStillBonus")->getFloat(); blockerTerm *= blockerStats.getFatigueTerm(); - float attackerSkill = 0.f; + int attackerSkill = 0; if (weapon.isEmpty()) attackerSkill = attacker.getClass().getSkill(attacker, ESM::Skill::HandToHand); else attackerSkill = attacker.getClass().getSkill(attacker, weapon.getClass().getEquipmentSkill(weapon)); - float attackerTerm = attackerSkill + 0.2 * attackerStats.getAttribute(ESM::Attribute::Agility).getModified() - + 0.1 * attackerStats.getAttribute(ESM::Attribute::Luck).getModified(); + float attackerTerm = attackerSkill + 0.2f * attackerStats.getAttribute(ESM::Attribute::Agility).getModified() + + 0.1f * attackerStats.getAttribute(ESM::Attribute::Luck).getModified(); attackerTerm *= attackerStats.getFatigueTerm(); int x = int(blockerTerm - attackerTerm); @@ -107,8 +109,7 @@ namespace MWMechanics int iBlockMinChance = gmst.find("iBlockMinChance")->getInt(); x = std::min(iBlockMaxChance, std::max(iBlockMinChance, x)); - int roll = std::rand()/ (static_cast (RAND_MAX) + 1) * 100; // [0, 99] - if (roll < x) + if (OEngine::Misc::Rng::roll0to99() < x) { // Reduce shield durability by incoming damage int shieldhealth = shield->getClass().getItemHealth(*shield); @@ -133,7 +134,7 @@ namespace MWMechanics blockerStats.setBlock(true); - if (blocker.getCellRef().getRefId() == "player") + if (blocker == MWBase::Environment::get().getWorld()->getPlayerPtr()) blocker.getClass().skillUsageSucceeded(blocker, ESM::Skill::Block, 0); return true; @@ -157,7 +158,7 @@ namespace MWMechanics && actor.getClass().isNpc() && actor.getClass().getNpcStats(actor).isWerewolf()) damage *= MWBase::Environment::get().getWorld()->getStore().get().find("fWereWolfSilverWeaponDamageMult")->getFloat(); - if (damage == 0 && attacker.getRefData().getHandle() == "player") + if (damage == 0 && attacker == MWBase::Environment::get().getWorld()->getPlayerPtr()) MWBase::Environment::get().getWindowManager()->messageBox("#{sMagicTargetResistsWeapons}"); } @@ -176,42 +177,36 @@ namespace MWMechanics return; } - if(attacker.getRefData().getHandle() == "player") + if(attacker == MWBase::Environment::get().getWorld()->getPlayerPtr()) MWBase::Environment::get().getWindowManager()->setEnemy(victim); int weapskill = ESM::Skill::Marksman; if(!weapon.isEmpty()) weapskill = weapon.getClass().getEquipmentSkill(weapon); - float skillValue = attacker.getClass().getSkill(attacker, + int skillValue = attacker.getClass().getSkill(attacker, weapon.getClass().getEquipmentSkill(weapon)); - if((::rand()/(RAND_MAX+1.0)) > getHitChance(attacker, victim, skillValue)/100.0f) + if (OEngine::Misc::Rng::rollProbability() >= getHitChance(attacker, victim, skillValue) / 100.0f) { victim.getClass().onHit(victim, 0.0f, false, projectile, attacker, false); MWMechanics::reduceWeaponCondition(0.f, false, weapon, attacker); return; } - float fDamageStrengthBase = gmst.find("fDamageStrengthBase")->getFloat(); - float fDamageStrengthMult = gmst.find("fDamageStrengthMult")->getFloat(); const unsigned char* attack = weapon.get()->mBase->mData.mChop; float damage = attack[0] + ((attack[1]-attack[0])*attackerStats.getAttackStrength()); // Bow/crossbow damage - if (weapon != projectile) - { - // Arrow/bolt damage - attack = projectile.get()->mBase->mData.mChop; - damage += attack[0] + ((attack[1]-attack[0])*attackerStats.getAttackStrength()); - } - damage *= fDamageStrengthBase + - (attackerStats.getAttribute(ESM::Attribute::Strength).getModified() * fDamageStrengthMult * 0.1); + // Arrow/bolt damage + // NB in case of thrown weapons, we are applying the damage twice since projectile == weapon + attack = projectile.get()->mBase->mData.mChop; + damage += attack[0] + ((attack[1]-attack[0])*attackerStats.getAttackStrength()); - adjustWeaponDamage(damage, weapon); + adjustWeaponDamage(damage, weapon, attacker); reduceWeaponCondition(damage, true, weapon, attacker); - if(attacker.getRefData().getHandle() == "player") + if(attacker == MWBase::Environment::get().getWorld()->getPlayerPtr()) attacker.getClass().skillUsageSucceeded(attacker, weapskill, 0); if (victim.getClass().getCreatureStats(victim).getKnockedDown()) @@ -230,7 +225,7 @@ namespace MWMechanics && !appliedEnchantment) { float fProjectileThrownStoreChance = gmst.find("fProjectileThrownStoreChance")->getFloat(); - if ((::rand()/(RAND_MAX+1.0)) < fProjectileThrownStoreChance/100.f) + if (OEngine::Misc::Rng::rollProbability() < fProjectileThrownStoreChance / 100.f) victim.getClass().getContainerStore(victim).add(projectile, 1, victim); } @@ -241,14 +236,39 @@ namespace MWMechanics { MWMechanics::CreatureStats &stats = attacker.getClass().getCreatureStats(attacker); const MWMechanics::MagicEffects &mageffects = stats.getMagicEffects(); - float hitchance = skillValue + + + MWBase::World *world = MWBase::Environment::get().getWorld(); + const MWWorld::Store &gmst = world->getStore().get(); + + float defenseTerm = 0; + if (victim.getClass().getCreatureStats(victim).getFatigue().getCurrent() >= 0) + { + MWMechanics::CreatureStats& victimStats = victim.getClass().getCreatureStats(victim); + // Maybe we should keep an aware state for actors updated every so often instead of testing every time + bool unaware = (!victimStats.getAiSequence().isInCombat()) + && (attacker == MWBase::Environment::get().getWorld()->getPlayerPtr()) + && (!MWBase::Environment::get().getMechanicsManager()->awarenessCheck(attacker, victim)); + if (!(victimStats.getKnockedDown() || + victimStats.getMagicEffects().get(ESM::MagicEffect::Paralyze).getMagnitude() > 0 + || unaware )) + { + defenseTerm = victimStats.getEvasion(); + } + defenseTerm += std::min(100.f, + gmst.find("fCombatInvisoMult")->getFloat() * + victimStats.getMagicEffects().get(ESM::MagicEffect::Chameleon).getMagnitude()); + defenseTerm += std::min(100.f, + gmst.find("fCombatInvisoMult")->getFloat() * + victimStats.getMagicEffects().get(ESM::MagicEffect::Invisibility).getMagnitude()); + } + float attackTerm = skillValue + (stats.getAttribute(ESM::Attribute::Agility).getModified() / 5.0f) + (stats.getAttribute(ESM::Attribute::Luck).getModified() / 10.0f); - hitchance *= stats.getFatigueTerm(); - hitchance += mageffects.get(ESM::MagicEffect::FortifyAttack).getMagnitude() - + attackTerm *= stats.getFatigueTerm(); + attackTerm += mageffects.get(ESM::MagicEffect::FortifyAttack).getMagnitude() - mageffects.get(ESM::MagicEffect::Blind).getMagnitude(); - hitchance -= victim.getClass().getCreatureStats(victim).getEvasion(); - return hitchance; + + return round(attackTerm - defenseTerm); } void applyElementalShields(const MWWorld::Ptr &attacker, const MWWorld::Ptr &victim) @@ -265,15 +285,14 @@ namespace MWMechanics + 0.2f * attackerStats.getAttribute(ESM::Attribute::Willpower).getModified() + 0.1f * attackerStats.getAttribute(ESM::Attribute::Luck).getModified(); - int fatigueMax = attackerStats.getFatigue().getModified(); - int fatigueCurrent = attackerStats.getFatigue().getCurrent(); + float fatigueMax = attackerStats.getFatigue().getModified(); + float fatigueCurrent = attackerStats.getFatigue().getCurrent(); - float normalisedFatigue = fatigueMax==0 ? 1 : std::max (0.0f, static_cast (fatigueCurrent)/fatigueMax); + float normalisedFatigue = floor(fatigueMax)==0 ? 1 : std::max (0.0f, (fatigueCurrent/fatigueMax)); saveTerm *= 1.25f * normalisedFatigue; - float roll = std::rand()/ (static_cast (RAND_MAX) + 1) * 100; // [0, 99] - float x = std::max(0.f, saveTerm - roll); + float x = std::max(0.f, saveTerm - OEngine::Misc::Rng::roll0to99()); int element = ESM::MagicEffect::FireDamage; if (i == 1) @@ -322,7 +341,7 @@ namespace MWMechanics } } - void adjustWeaponDamage(float &damage, const MWWorld::Ptr &weapon) + void adjustWeaponDamage(float &damage, const MWWorld::Ptr &weapon, const MWWorld::Ptr& attacker) { if (weapon.isEmpty()) return; @@ -334,6 +353,13 @@ namespace MWMechanics int weapmaxhealth = weapon.getClass().getItemMaxHealth(weapon); damage *= (float(weaphealth) / weapmaxhealth); } + + static const float fDamageStrengthBase = MWBase::Environment::get().getWorld()->getStore().get() + .find("fDamageStrengthBase")->getFloat(); + static const float fDamageStrengthMult = MWBase::Environment::get().getWorld()->getStore().get() + .find("fDamageStrengthMult")->getFloat(); + damage *= fDamageStrengthBase + + (attacker.getClass().getCreatureStats(attacker).getAttribute(ESM::Attribute::Strength).getModified() * fDamageStrengthMult * 0.1f); } void getHandToHandDamage(const MWWorld::Ptr &attacker, const MWWorld::Ptr &victim, float &damage, bool &healthdmg) @@ -344,7 +370,7 @@ namespace MWMechanics const MWWorld::ESMStore& store = MWBase::Environment::get().getWorld()->getStore(); float minstrike = store.get().find("fMinHandToHandMult")->getFloat(); float maxstrike = store.get().find("fMaxHandToHandMult")->getFloat(); - damage = attacker.getClass().getSkill(attacker, ESM::Skill::HandToHand); + damage = static_cast(attacker.getClass().getSkill(attacker, ESM::Skill::HandToHand)); damage *= minstrike + ((maxstrike-minstrike)*attacker.getClass().getCreatureStats(attacker).getAttackStrength()); MWMechanics::CreatureStats& otherstats = victim.getClass().getCreatureStats(victim); diff --git a/apps/openmw/mwmechanics/combat.hpp b/apps/openmw/mwmechanics/combat.hpp index a48dcf72a..a2fd8b006 100644 --- a/apps/openmw/mwmechanics/combat.hpp +++ b/apps/openmw/mwmechanics/combat.hpp @@ -30,7 +30,7 @@ void applyElementalShields(const MWWorld::Ptr& attacker, const MWWorld::Ptr& vic void reduceWeaponCondition (float damage, bool hit, MWWorld::Ptr& weapon, const MWWorld::Ptr& attacker); /// Adjust weapon damage based on its condition. A used weapon will be less effective. -void adjustWeaponDamage (float& damage, const MWWorld::Ptr& weapon); +void adjustWeaponDamage (float& damage, const MWWorld::Ptr& weapon, const MWWorld::Ptr& attacker); void getHandToHandDamage (const MWWorld::Ptr& attacker, const MWWorld::Ptr& victim, float& damage, bool& healthdmg); diff --git a/apps/openmw/mwmechanics/creaturestats.cpp b/apps/openmw/mwmechanics/creaturestats.cpp index 05ea9fb5e..4c338e23f 100644 --- a/apps/openmw/mwmechanics/creaturestats.cpp +++ b/apps/openmw/mwmechanics/creaturestats.cpp @@ -42,10 +42,10 @@ namespace MWMechanics float CreatureStats::getFatigueTerm() const { - int max = getFatigue().getModified(); - int current = getFatigue().getCurrent(); + float max = getFatigue().getModified(); + float current = getFatigue().getCurrent(); - float normalised = max==0 ? 1 : std::max (0.0f, static_cast (current)/max); + float normalised = floor(max) == 0 ? 1 : std::max (0.0f, current / max); const MWWorld::Store &gmst = MWBase::Environment::get().getWorld()->getStore().get(); @@ -336,7 +336,7 @@ namespace MWMechanics float evasion = (getAttribute(ESM::Attribute::Agility).getModified() / 5.0f) + (getAttribute(ESM::Attribute::Luck).getModified() / 10.0f); evasion *= getFatigueTerm(); - evasion += mMagicEffects.get(ESM::MagicEffect::Sanctuary).getMagnitude(); + evasion += std::min(100.f, mMagicEffects.get(ESM::MagicEffect::Sanctuary).getMagnitude()); return evasion; } @@ -439,7 +439,7 @@ namespace MWMechanics bool CreatureStats::getMovementFlag (Flag flag) const { - return mMovementFlags & flag; + return (mMovementFlags & flag) != 0; } void CreatureStats::setMovementFlag (Flag flag, bool state) diff --git a/apps/openmw/mwmechanics/disease.hpp b/apps/openmw/mwmechanics/disease.hpp index a973c0e35..0153be3dc 100644 --- a/apps/openmw/mwmechanics/disease.hpp +++ b/apps/openmw/mwmechanics/disease.hpp @@ -1,6 +1,8 @@ #ifndef OPENMW_MECHANICS_DISEASE_H #define OPENMW_MECHANICS_DISEASE_H +#include + #include "../mwbase/windowmanager.hpp" #include "../mwbase/environment.hpp" #include "../mwbase/world.hpp" @@ -37,21 +39,19 @@ namespace MWMechanics float resist = 0.f; if (spells.hasCorprusEffect(spell)) - resist = 1.f - 0.01 * (actorEffects.get(ESM::MagicEffect::ResistCorprusDisease).getMagnitude() + resist = 1.f - 0.01f * (actorEffects.get(ESM::MagicEffect::ResistCorprusDisease).getMagnitude() - actorEffects.get(ESM::MagicEffect::WeaknessToCorprusDisease).getMagnitude()); else if (spell->mData.mType == ESM::Spell::ST_Disease) - resist = 1.f - 0.01 * (actorEffects.get(ESM::MagicEffect::ResistCommonDisease).getMagnitude() + resist = 1.f - 0.01f * (actorEffects.get(ESM::MagicEffect::ResistCommonDisease).getMagnitude() - actorEffects.get(ESM::MagicEffect::WeaknessToCommonDisease).getMagnitude()); else if (spell->mData.mType == ESM::Spell::ST_Blight) - resist = 1.f - 0.01 * (actorEffects.get(ESM::MagicEffect::ResistBlightDisease).getMagnitude() + resist = 1.f - 0.01f * (actorEffects.get(ESM::MagicEffect::ResistBlightDisease).getMagnitude() - actorEffects.get(ESM::MagicEffect::WeaknessToBlightDisease).getMagnitude()); else continue; - int x = fDiseaseXferChance * 100 * resist; - float roll = std::rand()/ (static_cast (RAND_MAX) + 1) * 10000; // [0, 9999] - - if (roll < x) + int x = static_cast(fDiseaseXferChance * 100 * resist); + if (OEngine::Misc::Rng::rollDice(10000) < x) { // Contracted disease! actor.getClass().getCreatureStats(actor).getSpells().add(it->first); diff --git a/apps/openmw/mwmechanics/enchanting.cpp b/apps/openmw/mwmechanics/enchanting.cpp index de5921a70..bb02fb41d 100644 --- a/apps/openmw/mwmechanics/enchanting.cpp +++ b/apps/openmw/mwmechanics/enchanting.cpp @@ -1,4 +1,7 @@ #include "enchanting.hpp" + +#include + #include "../mwworld/manualref.hpp" #include "../mwworld/class.hpp" #include "../mwworld/containerstore.hpp" @@ -67,7 +70,7 @@ namespace MWMechanics if(mSelfEnchanting) { - if(getEnchantChance() (RAND_MAX)*100) + if(getEnchantChance() <= (OEngine::Misc::Rng::roll0to99())) return false; mEnchanter.getClass().skillUsageSucceeded (mEnchanter, ESM::Skill::Enchant, 2); @@ -176,7 +179,7 @@ namespace MWMechanics int magMax = (it->mMagnMax == 0) ? 1 : it->mMagnMax; int area = (it->mArea == 0) ? 1 : it->mArea; - float magnitudeCost = (magMin + magMax) * baseCost * 0.05; + float magnitudeCost = (magMin + magMax) * baseCost * 0.05f; if (mCastStyle == ESM::Enchantment::ConstantEffect) { magnitudeCost *= store.get().find("fEnchantmentConstantDurationMult")->getFloat(); @@ -186,7 +189,7 @@ namespace MWMechanics magnitudeCost *= it->mDuration; } - float areaCost = area * 0.05 * baseCost; + float areaCost = area * 0.05f * baseCost; const float fEffectCostMult = store.get().find("fEffectCostMult")->getFloat(); @@ -215,7 +218,7 @@ namespace MWMechanics { int baseCost = getBaseCastCost(); MWWorld::Ptr player = MWBase::Environment::get().getWorld()->getPlayerPtr(); - return getEffectiveEnchantmentCastCost(baseCost, player); + return getEffectiveEnchantmentCastCost(static_cast(baseCost), player); } @@ -225,7 +228,7 @@ namespace MWMechanics return 0; float priceMultipler = MWBase::Environment::get().getWorld()->getStore().get().find ("fEnchantmentValueMult")->getFloat(); - int price = MWBase::Environment::get().getMechanicsManager()->getBarterOffer(mEnchanter, (getEnchantPoints() * priceMultipler), true); + int price = MWBase::Environment::get().getMechanicsManager()->getBarterOffer(mEnchanter, static_cast(getEnchantPoints() * priceMultipler), true); return price; } @@ -247,7 +250,7 @@ namespace MWMechanics const MWWorld::ESMStore &store = MWBase::Environment::get().getWorld()->getStore(); - return mOldItemPtr.getClass().getEnchantmentPoints(mOldItemPtr) * store.get().find("fEnchantmentMult")->getFloat(); + return static_cast(mOldItemPtr.getClass().getEnchantmentPoints(mOldItemPtr) * store.get().find("fEnchantmentMult")->getFloat()); } bool Enchanting::soulEmpty() const { @@ -274,13 +277,13 @@ namespace MWMechanics const NpcStats& npcStats = mEnchanter.getClass().getNpcStats (mEnchanter); float chance1 = (npcStats.getSkill (ESM::Skill::Enchant).getModified() + - (0.25 * npcStats.getAttribute (ESM::Attribute::Intelligence).getModified()) - + (0.125 * npcStats.getAttribute (ESM::Attribute::Luck).getModified())); + (0.25f * npcStats.getAttribute (ESM::Attribute::Intelligence).getModified()) + + (0.125f * npcStats.getAttribute (ESM::Attribute::Luck).getModified())); const MWWorld::Store& gmst = MWBase::Environment::get().getWorld()->getStore().get(); - float chance2 = 7.5 / (gmst.find("fEnchantmentChanceMult")->getFloat() * ((mCastStyle == ESM::Enchantment::ConstantEffect) ? - gmst.find("fEnchantmentConstantChanceMult")->getFloat() : 1 )) + float chance2 = 7.5f / (gmst.find("fEnchantmentChanceMult")->getFloat() * ((mCastStyle == ESM::Enchantment::ConstantEffect) ? + gmst.find("fEnchantmentConstantChanceMult")->getFloat() : 1.0f )) * getEnchantPoints(); return (chance1-chance2); diff --git a/apps/openmw/mwmechanics/levelledlist.hpp b/apps/openmw/mwmechanics/levelledlist.hpp index 691996410..20b87a3a9 100644 --- a/apps/openmw/mwmechanics/levelledlist.hpp +++ b/apps/openmw/mwmechanics/levelledlist.hpp @@ -1,6 +1,8 @@ #ifndef OPENMW_MECHANICS_LEVELLEDLIST_H #define OPENMW_MECHANICS_LEVELLEDLIST_H +#include + #include "../mwworld/ptr.hpp" #include "../mwworld/esmstore.hpp" #include "../mwworld/manualref.hpp" @@ -22,8 +24,7 @@ namespace MWMechanics failChance += levItem->mChanceNone; - int random = std::rand()/ (static_cast (RAND_MAX) + 1) * 100; // [0, 99] - if (random < failChance) + if (OEngine::Misc::Rng::roll0to99() < failChance) return std::string(); std::vector candidates; @@ -35,7 +36,7 @@ namespace MWMechanics } // For levelled creatures, the flags are swapped. This file format just makes so much sense. - bool allLevels = levItem->mFlags & ESM::ItemLevList::AllLevels; + bool allLevels = (levItem->mFlags & ESM::ItemLevList::AllLevels) != 0; if (creature) allLevels = levItem->mFlags & ESM::CreatureLevList::AllLevels; @@ -52,7 +53,7 @@ namespace MWMechanics } if (candidates.empty()) return std::string(); - std::string item = candidates[std::rand()%candidates.size()]; + std::string item = candidates[OEngine::Misc::Rng::rollDice(candidates.size())]; // Vanilla doesn't fail on nonexistent items in levelled lists if (!MWBase::Environment::get().getWorld()->getStore().find(Misc::StringUtils::lowerCase(item))) diff --git a/apps/openmw/mwmechanics/magiceffects.hpp b/apps/openmw/mwmechanics/magiceffects.hpp index c384d0857..86f5a1804 100644 --- a/apps/openmw/mwmechanics/magiceffects.hpp +++ b/apps/openmw/mwmechanics/magiceffects.hpp @@ -72,6 +72,8 @@ namespace MWMechanics // Used by effect management classes (ActiveSpells, InventoryStore, Spells) to list active effect sources for GUI display struct EffectSourceVisitor { + virtual ~EffectSourceVisitor() { } + virtual void visit (MWMechanics::EffectKey key, const std::string& sourceName, const std::string& sourceId, int casterActorId, float magnitude, float remainingTime = -1, float totalTime = -1) = 0; diff --git a/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp b/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp index 4e4a1a8a6..0d4518f87 100644 --- a/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp +++ b/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp @@ -2,6 +2,8 @@ #include "mechanicsmanagerimp.hpp" #include "npcstats.hpp" +#include + #include #include "../mwworld/esmstore.hpp" @@ -556,7 +558,7 @@ namespace MWMechanics int MechanicsManager::getDerivedDisposition(const MWWorld::Ptr& ptr) { const MWMechanics::NpcStats& npcSkill = ptr.getClass().getNpcStats(ptr); - float x = npcSkill.getBaseDisposition(); + float x = static_cast(npcSkill.getBaseDisposition()); MWWorld::LiveCellRef* npc = ptr.get(); MWWorld::Ptr playerPtr = MWBase::Environment::get().getWorld()->getPlayerPtr(); @@ -583,7 +585,7 @@ namespace MWMechanics if (!playerStats.getExpelled(npcFaction)) { // faction reaction towards itself. yes, that exists - reaction = MWBase::Environment::get().getDialogueManager()->getFactionReaction(npcFaction, npcFaction); + reaction = static_cast(MWBase::Environment::get().getDialogueManager()->getFactionReaction(npcFaction, npcFaction)); rank = playerStats.getFactionRanks().find(npcFaction)->second; } @@ -597,7 +599,7 @@ namespace MWMechanics int itReaction = MWBase::Environment::get().getDialogueManager()->getFactionReaction(npcFaction, itFaction); if (playerFactionIt == playerStats.getFactionRanks().begin() || itReaction < reaction) - reaction = itReaction; + reaction = static_cast(itReaction); } } else @@ -643,17 +645,17 @@ namespace MWMechanics // otherwise one would get different prices when exiting and re-entering the dialogue window... int clampedDisposition = std::max(0, std::min(getDerivedDisposition(ptr) + MWBase::Environment::get().getDialogueManager()->getTemporaryDispositionChange(),100)); - float a = std::min(playerStats.getSkill(ESM::Skill::Mercantile).getModified(), 100); + float a = static_cast(std::min(playerStats.getSkill(ESM::Skill::Mercantile).getModified(), 100)); float b = std::min(0.1f * playerStats.getAttribute(ESM::Attribute::Luck).getModified(), 10.f); float c = std::min(0.2f * playerStats.getAttribute(ESM::Attribute::Personality).getModified(), 10.f); - float d = std::min(sellerStats.getSkill(ESM::Skill::Mercantile).getModified(), 100); + float d = static_cast(std::min(sellerStats.getSkill(ESM::Skill::Mercantile).getModified(), 100)); float e = std::min(0.1f * sellerStats.getAttribute(ESM::Attribute::Luck).getModified(), 10.f); float f = std::min(0.2f * sellerStats.getAttribute(ESM::Attribute::Personality).getModified(), 10.f); float pcTerm = (clampedDisposition - 50 + a + b + c) * playerStats.getFatigueTerm(); float npcTerm = (d + e + f) * sellerStats.getFatigueTerm(); - float buyTerm = 0.01 * (100 - 0.5 * (pcTerm - npcTerm)); - float sellTerm = 0.01 * (50 - 0.5 * (npcTerm - pcTerm)); + float buyTerm = 0.01f * (100 - 0.5f * (pcTerm - npcTerm)); + float sellTerm = 0.01f * (50 - 0.5f * (npcTerm - pcTerm)); float x; if(buying) x = buyTerm; @@ -704,7 +706,7 @@ namespace MWMechanics int currentDisposition = std::min(100, std::max(0, int(getDerivedDisposition(npc) + currentTemporaryDispositionDelta))); - float d = 1 - 0.02 * abs(currentDisposition - 50); + float d = 1 - 0.02f * abs(currentDisposition - 50); float target1 = d * (playerRating1 - npcRating1 + 50); float target2 = d * (playerRating2 - npcRating2 + 50); @@ -715,21 +717,21 @@ namespace MWMechanics float target3 = d * (playerRating3 - npcRating3 + 50) + bribeMod; - float iPerMinChance = gmst.find("iPerMinChance")->getInt(); - float iPerMinChange = gmst.find("iPerMinChange")->getInt(); + float iPerMinChance = floor(gmst.find("iPerMinChance")->getFloat()); + float iPerMinChange = floor(gmst.find("iPerMinChange")->getFloat()); float fPerDieRollMult = gmst.find("fPerDieRollMult")->getFloat(); float fPerTempMult = gmst.find("fPerTempMult")->getFloat(); float x = 0; float y = 0; - float roll = static_cast (std::rand()) / RAND_MAX * 100; + float roll = OEngine::Misc::Rng::rollClosedProbability() * 100; if (type == PT_Admire) { target1 = std::max(iPerMinChance, target1); success = (roll <= target1); - float c = int(fPerDieRollMult * (target1 - roll)); + float c = floor(fPerDieRollMult * (target1 - roll)); x = success ? std::max(iPerMinChange, c) : c; } else if (type == PT_Intimidate) @@ -740,13 +742,13 @@ namespace MWMechanics float r; if (roll != target2) - r = int(target2 - roll); + r = floor(target2 - roll); else r = 1; if (roll <= target2) { - float s = int(r * fPerDieRollMult * fPerTempMult); + float s = floor(r * fPerDieRollMult * fPerTempMult); int flee = npcStats.getAiSetting(MWMechanics::CreatureStats::AI_Flee).getBase(); int fight = npcStats.getAiSetting(MWMechanics::CreatureStats::AI_Fight).getBase(); @@ -756,7 +758,7 @@ namespace MWMechanics std::max(0, std::min(100, fight + int(std::min(-iPerMinChange, -s))))); } - float c = -std::abs(int(r * fPerDieRollMult)); + float c = -std::abs(floor(r * fPerDieRollMult)); if (success) { if (std::abs(c) < iPerMinChange) @@ -766,13 +768,13 @@ namespace MWMechanics } else { - x = -int(c * fPerTempMult); + x = -floor(c * fPerTempMult); y = c; } } else { - x = int(c * fPerTempMult); + x = floor(c * fPerTempMult); y = c; } } @@ -781,7 +783,7 @@ namespace MWMechanics target1 = std::max(iPerMinChance, target1); success = (roll <= target1); - float c = std::abs(int(target1 - roll)); + float c = std::abs(floor(target1 - roll)); if (success) { @@ -793,7 +795,7 @@ namespace MWMechanics npcStats.setAiSetting (CreatureStats::AI_Fight, std::max(0, std::min(100, fight + std::max(int(iPerMinChange), int(s))))); } - x = int(-c * fPerDieRollMult); + x = floor(-c * fPerDieRollMult); if (success && std::abs(x) < iPerMinChange) x = -iPerMinChange; @@ -802,7 +804,7 @@ namespace MWMechanics { target3 = std::max(iPerMinChance, target3); success = (roll <= target3); - float c = int((target3 - roll) * fPerDieRollMult); + float c = floor((target3 - roll) * fPerDieRollMult); x = success ? std::max(iPerMinChange, c) : c; } @@ -812,11 +814,11 @@ namespace MWMechanics float cappedDispositionChange = tempChange; if (currentDisposition + tempChange > 100.f) - cappedDispositionChange = 100 - currentDisposition; + cappedDispositionChange = static_cast(100 - currentDisposition); if (currentDisposition + tempChange < 0.f) - cappedDispositionChange = -currentDisposition; + cappedDispositionChange = static_cast(-currentDisposition); - permChange = int(cappedDispositionChange / fPerTempMult); + permChange = floor(cappedDispositionChange / fPerTempMult); if (type == PT_Intimidate) { permChange = success ? -int(cappedDispositionChange/ fPerTempMult) : y; @@ -1104,7 +1106,7 @@ namespace MWMechanics if (type == OT_Trespassing || type == OT_SleepingInOwnedBed) { arg = store.find("iCrimeTresspass")->getInt(); - disp = dispVictim = store.find("iDispTresspass")->getInt(); + disp = dispVictim = store.find("iDispTresspass")->getFloat(); } else if (type == OT_Pickpocket) { @@ -1114,18 +1116,18 @@ namespace MWMechanics else if (type == OT_Assault) { arg = store.find("iCrimeAttack")->getInt(); - disp = store.find("iDispAttackMod")->getInt(); + disp = store.find("iDispAttackMod")->getFloat(); dispVictim = store.find("fDispAttacking")->getFloat(); } else if (type == OT_Murder) { arg = store.find("iCrimeKilling")->getInt(); - disp = dispVictim = store.find("iDispKilling")->getInt(); + disp = dispVictim = store.find("iDispKilling")->getFloat(); } else if (type == OT_Theft) { disp = dispVictim = store.find("fDispStealing")->getFloat() * arg; - arg *= store.find("fCrimeStealing")->getFloat(); + arg = static_cast(arg * store.find("fCrimeStealing")->getFloat()); arg = std::max(1, arg); // Minimum bounty of 1, in case items with zero value are stolen } @@ -1163,7 +1165,7 @@ namespace MWMechanics else if (type == OT_Murder) fight = fightVictim = esmStore.get().find("iFightKilling")->getInt(); else if (type == OT_Theft) - fight = fightVictim = esmStore.get().find("fFightStealing")->getFloat(); + fight = fightVictim = esmStore.get().find("fFightStealing")->getInt(); bool reported = false; @@ -1197,21 +1199,21 @@ namespace MWMechanics { float dispTerm = (*it == victim) ? dispVictim : disp; - float alarmTerm = 0.01 * it->getClass().getCreatureStats(*it).getAiSetting(CreatureStats::AI_Alarm).getBase(); + float alarmTerm = 0.01f * it->getClass().getCreatureStats(*it).getAiSetting(CreatureStats::AI_Alarm).getBase(); if (type == OT_Pickpocket && alarmTerm <= 0) alarmTerm = 1.0; if (*it != victim) dispTerm *= alarmTerm; - float fightTerm = (*it == victim) ? fightVictim : fight; + float fightTerm = static_cast((*it == victim) ? fightVictim : fight); fightTerm += getFightDispositionBias(dispTerm); fightTerm += getFightDistanceBias(*it, player); fightTerm *= alarmTerm; int observerFightRating = it->getClass().getCreatureStats(*it).getAiSetting(CreatureStats::AI_Fight).getBase(); if (observerFightRating + fightTerm > 100) - fightTerm = 100 - observerFightRating; + fightTerm = static_cast(100 - observerFightRating); fightTerm = std::max(0.f, fightTerm); if (observerFightRating + fightTerm >= 100) @@ -1221,9 +1223,9 @@ namespace MWMechanics NpcStats& observerStats = it->getClass().getNpcStats(*it); // Apply aggression value to the base Fight rating, so that the actor can continue fighting // after a Calm spell wears off - observerStats.setAiSetting(CreatureStats::AI_Fight, observerFightRating + fightTerm); + observerStats.setAiSetting(CreatureStats::AI_Fight, observerFightRating + static_cast(fightTerm)); - observerStats.setBaseDisposition(observerStats.getBaseDisposition()+dispTerm); + observerStats.setBaseDisposition(observerStats.getBaseDisposition() + static_cast(dispTerm)); // Set the crime ID, which we will use to calm down participants // once the bounty has been paid. @@ -1334,7 +1336,7 @@ namespace MWMechanics { static float fSneakSkillMult = store.find("fSneakSkillMult")->getFloat(); static float fSneakBootMult = store.find("fSneakBootMult")->getFloat(); - float sneak = ptr.getClass().getSkill(ptr, ESM::Skill::Sneak); + float sneak = static_cast(ptr.getClass().getSkill(ptr, ESM::Skill::Sneak)); int agility = stats.getAttribute(ESM::Attribute::Agility).getModified(); int luck = stats.getAttribute(ESM::Attribute::Luck).getModified(); float bootWeight = 0; @@ -1345,7 +1347,7 @@ namespace MWMechanics if (it != inv.end()) bootWeight = it->getClass().getWeight(*it); } - sneakTerm = fSneakSkillMult * sneak + 0.2 * agility + 0.1 * luck + bootWeight * fSneakBootMult; + sneakTerm = fSneakSkillMult * sneak + 0.2f * agility + 0.1f * luck + bootWeight * fSneakBootMult; } static float fSneakDistBase = store.find("fSneakDistanceBase")->getFloat(); @@ -1364,7 +1366,7 @@ namespace MWMechanics float obsBlind = observerStats.getMagicEffects().get(ESM::MagicEffect::Blind).getMagnitude(); int obsSneak = observer.getClass().getSkill(observer, ESM::Skill::Sneak); - float obsTerm = obsSneak + 0.2 * obsAgility + 0.1 * obsLuck - obsBlind; + float obsTerm = obsSneak + 0.2f * obsAgility + 0.1f * obsLuck - obsBlind; // is ptr behind the observer? static float fSneakNoViewMult = store.find("fSneakNoViewMult")->getFloat(); @@ -1378,9 +1380,8 @@ namespace MWMechanics y = obsTerm * observerStats.getFatigueTerm() * fSneakViewMult; float target = x - y; - int roll = std::rand()/ (static_cast (RAND_MAX) + 1) * 100; // [0, 99] - return (roll >= target); + return (OEngine::Misc::Rng::roll0to99() >= target); } void MechanicsManager::startCombat(const MWWorld::Ptr &ptr, const MWWorld::Ptr &target) @@ -1479,9 +1480,8 @@ namespace MWMechanics if (ptr.getClass().isNpc()) disposition = getDerivedDisposition(ptr); - int fight = std::max(0.f, ptr.getClass().getCreatureStats(ptr).getAiSetting(CreatureStats::AI_Fight).getModified() - + getFightDistanceBias(ptr, target) - + getFightDispositionBias(disposition)); + int fight = std::max(0, ptr.getClass().getCreatureStats(ptr).getAiSetting(CreatureStats::AI_Fight).getModified() + + static_cast(getFightDistanceBias(ptr, target) + getFightDispositionBias(static_cast(disposition)))); if (ptr.getClass().isNpc() && target.getClass().isNpc()) { diff --git a/apps/openmw/mwmechanics/npcstats.cpp b/apps/openmw/mwmechanics/npcstats.cpp index 58bf11cff..7f468f6d4 100644 --- a/apps/openmw/mwmechanics/npcstats.cpp +++ b/apps/openmw/mwmechanics/npcstats.cpp @@ -142,7 +142,7 @@ void MWMechanics::NpcStats::setFactionReputation (const std::string& faction, in float MWMechanics::NpcStats::getSkillProgressRequirement (int skillIndex, const ESM::Class& class_) const { - float progressRequirement = 1 + getSkill (skillIndex).getBase(); + float progressRequirement = static_cast(1 + getSkill(skillIndex).getBase()); const MWWorld::Store &gmst = MWBase::Environment::get().getWorld()->getStore().get(); @@ -303,7 +303,7 @@ void MWMechanics::NpcStats::updateHealth() const int endurance = getAttribute(ESM::Attribute::Endurance).getBase(); const int strength = getAttribute(ESM::Attribute::Strength).getBase(); - setHealth(static_cast (0.5 * (strength + endurance))); + setHealth(floor(0.5f * (strength + endurance))); } int MWMechanics::NpcStats::getLevelupAttributeMultiplier(int attribute) const diff --git a/apps/openmw/mwmechanics/pathfinding.cpp b/apps/openmw/mwmechanics/pathfinding.cpp index 0634725a8..5795f818a 100644 --- a/apps/openmw/mwmechanics/pathfinding.cpp +++ b/apps/openmw/mwmechanics/pathfinding.cpp @@ -17,7 +17,7 @@ namespace // float distanceSquared(ESM::Pathgrid::Point point, Ogre::Vector3 pos) { - return Ogre::Vector3(point.mX, point.mY, point.mZ).squaredDistance(pos); + return MWMechanics::PathFinder::MakeOgreVector3(point).squaredDistance(pos); } // Return the closest pathgrid point index from the specified position co @@ -90,12 +90,11 @@ namespace namespace MWMechanics { - float sqrDistanceZCorrected(ESM::Pathgrid::Point point, float x, float y, float z) + float sqrDistanceIgnoreZ(ESM::Pathgrid::Point point, float x, float y) { x -= point.mX; y -= point.mY; - z -= point.mZ; - return (x * x + y * y + 0.1 * z * z); + return (x * x + y * y); } float distance(ESM::Pathgrid::Point point, float x, float y, float z) @@ -108,9 +107,9 @@ namespace MWMechanics float distance(ESM::Pathgrid::Point a, ESM::Pathgrid::Point b) { - float x = a.mX - b.mX; - float y = a.mY - b.mY; - float z = a.mZ - b.mZ; + float x = static_cast(a.mX - b.mX); + float y = static_cast(a.mY - b.mY); + float z = static_cast(a.mZ - b.mZ); return sqrt(x * x + y * y + z * z); } @@ -176,8 +175,9 @@ namespace MWMechanics if(allowShortcuts) { // if there's a ray cast hit, can't take a direct path - if(!MWBase::Environment::get().getWorld()->castRay(startPoint.mX, startPoint.mY, startPoint.mZ, - endPoint.mX, endPoint.mY, endPoint.mZ)) + if (!MWBase::Environment::get().getWorld()->castRay( + static_cast(startPoint.mX), static_cast(startPoint.mY), static_cast(startPoint.mZ), + static_cast(endPoint.mX), static_cast(endPoint.mY), static_cast(endPoint.mZ))) { mPath.push_back(endPoint); mIsPathConstructed = true; @@ -206,8 +206,8 @@ namespace MWMechanics float yCell = 0; if (mCell->isExterior()) { - xCell = mCell->getCell()->mData.mX * ESM::Land::REAL_SIZE; - yCell = mCell->getCell()->mData.mY * ESM::Land::REAL_SIZE; + xCell = static_cast(mCell->getCell()->mData.mX * ESM::Land::REAL_SIZE); + yCell = static_cast(mCell->getCell()->mData.mY * ESM::Land::REAL_SIZE); } // NOTE: It is possible that getClosestPoint returns a pathgrind point index @@ -216,12 +216,12 @@ namespace MWMechanics // point right behind the wall that is closer than any pathgrid // point outside the wall int startNode = getClosestPoint(mPathgrid, - Ogre::Vector3(startPoint.mX - xCell, startPoint.mY - yCell, startPoint.mZ)); + Ogre::Vector3(startPoint.mX - xCell, startPoint.mY - yCell, static_cast(startPoint.mZ))); // Some cells don't have any pathgrids at all if(startNode != -1) { std::pair endNode = getClosestReachablePoint(mPathgrid, cell, - Ogre::Vector3(endPoint.mX - xCell, endPoint.mY - yCell, endPoint.mZ), + Ogre::Vector3(endPoint.mX - xCell, endPoint.mY - yCell, static_cast(endPoint.mZ)), startNode); // this shouldn't really happen, but just in case @@ -282,13 +282,13 @@ namespace MWMechanics return Ogre::Math::ATan2(directionX,directionY).valueDegrees(); } - bool PathFinder::checkPathCompleted(float x, float y, float z, float tolerance) + bool PathFinder::checkPathCompleted(float x, float y, float tolerance) { if(mPath.empty()) return true; ESM::Pathgrid::Point nextPoint = *mPath.begin(); - if(sqrDistanceZCorrected(nextPoint, x, y, z) < tolerance*tolerance) + if (sqrDistanceIgnoreZ(nextPoint, x, y) < tolerance*tolerance) { mPath.pop_front(); if(mPath.empty()) diff --git a/apps/openmw/mwmechanics/pathfinding.hpp b/apps/openmw/mwmechanics/pathfinding.hpp index 7ba2d22ba..f48de6624 100644 --- a/apps/openmw/mwmechanics/pathfinding.hpp +++ b/apps/openmw/mwmechanics/pathfinding.hpp @@ -1,10 +1,12 @@ #ifndef GAME_MWMECHANICS_PATHFINDING_H #define GAME_MWMECHANICS_PATHFINDING_H +#include #include #include #include +#include namespace MWWorld { @@ -27,11 +29,11 @@ namespace MWMechanics return -1.0; } - static float sgn(float a) + static int sgn(int a) { if(a > 0) - return 1.0; - return -1.0; + return 1; + return -1; } void clearPath(); @@ -39,7 +41,7 @@ namespace MWMechanics void buildPath(const ESM::Pathgrid::Point &startPoint, const ESM::Pathgrid::Point &endPoint, const MWWorld::CellStore* cell, bool allowShortcuts = true); - bool checkPathCompleted(float x, float y, float z, float tolerance=32.f); + bool checkPathCompleted(float x, float y, float tolerance=32.f); ///< \Returns true if we are within \a tolerance units of the last path point. float getZAngleToNext(float x, float y) const; @@ -74,6 +76,24 @@ namespace MWMechanics mPath.push_back(point); } + /// utility function to convert a Ogre::Vector3 to a Pathgrid::Point + static ESM::Pathgrid::Point MakePathgridPoint(const Ogre::Vector3& v) + { + return ESM::Pathgrid::Point(static_cast(v[0]), static_cast(v[1]), static_cast(v[2])); + } + + /// utility function to convert an ESM::Position to a Pathgrid::Point + static ESM::Pathgrid::Point MakePathgridPoint(const ESM::Position& p) + { + return ESM::Pathgrid::Point(static_cast(p.pos[0]), static_cast(p.pos[1]), static_cast(p.pos[2])); + } + + /// utility function to convert a Pathgrid::Point to a Ogre::Vector3 + static Ogre::Vector3 MakeOgreVector3(const ESM::Pathgrid::Point& p) + { + return Ogre::Vector3(static_cast(p.mX), static_cast(p.mY), static_cast(p.mZ)); + } + private: bool mIsPathConstructed; diff --git a/apps/openmw/mwmechanics/pathgrid.cpp b/apps/openmw/mwmechanics/pathgrid.cpp index 9e50af2b8..c1e094bb1 100644 --- a/apps/openmw/mwmechanics/pathgrid.cpp +++ b/apps/openmw/mwmechanics/pathgrid.cpp @@ -27,7 +27,7 @@ namespace // float manhattan(const ESM::Pathgrid::Point& a, const ESM::Pathgrid::Point& b) { - return 300 * (abs(a.mX - b.mX) + abs(a.mY - b.mY) + abs(a.mZ - b.mZ)); + return 300.0f * (abs(a.mX - b.mX) + abs(a.mY - b.mY) + abs(a.mZ - b.mZ)); } // Choose a heuristics - Note that these may not be the best for directed @@ -317,23 +317,23 @@ namespace MWMechanics float yCell = 0; if (mIsExterior) { - xCell = mPathgrid->mData.mX * ESM::Land::REAL_SIZE; - yCell = mPathgrid->mData.mY * ESM::Land::REAL_SIZE; + xCell = static_cast(mPathgrid->mData.mX * ESM::Land::REAL_SIZE); + yCell = static_cast(mPathgrid->mData.mY * ESM::Land::REAL_SIZE); } while(graphParent[current] != -1) { ESM::Pathgrid::Point pt = mPathgrid->mPoints[current]; - pt.mX += xCell; - pt.mY += yCell; + pt.mX += static_cast(xCell); + pt.mY += static_cast(yCell); path.push_front(pt); current = graphParent[current]; } // add first node to path explicitly ESM::Pathgrid::Point pt = mPathgrid->mPoints[start]; - pt.mX += xCell; - pt.mY += yCell; + pt.mX += static_cast(xCell); + pt.mY += static_cast(yCell); path.push_front(pt); return path; } diff --git a/apps/openmw/mwmechanics/pathgrid.hpp b/apps/openmw/mwmechanics/pathgrid.hpp index 2742957a6..67fbacded 100644 --- a/apps/openmw/mwmechanics/pathgrid.hpp +++ b/apps/openmw/mwmechanics/pathgrid.hpp @@ -6,7 +6,7 @@ namespace ESM { - class Cell; + struct Cell; } namespace MWWorld diff --git a/apps/openmw/mwmechanics/pickpocket.cpp b/apps/openmw/mwmechanics/pickpocket.cpp index 14abcd643..561011df3 100644 --- a/apps/openmw/mwmechanics/pickpocket.cpp +++ b/apps/openmw/mwmechanics/pickpocket.cpp @@ -1,5 +1,7 @@ #include "pickpocket.hpp" +#include + #include "../mwworld/class.hpp" #include "../mwworld/esmstore.hpp" @@ -20,10 +22,10 @@ namespace MWMechanics float Pickpocket::getChanceModifier(const MWWorld::Ptr &ptr, float add) { NpcStats& stats = ptr.getClass().getNpcStats(ptr); - float agility = stats.getAttribute(ESM::Attribute::Agility).getModified(); - float luck = stats.getAttribute(ESM::Attribute::Luck).getModified(); - float sneak = ptr.getClass().getSkill(ptr, ESM::Skill::Sneak); - return (add + 0.2 * agility + 0.1 * luck + sneak) * stats.getFatigueTerm(); + float agility = static_cast(stats.getAttribute(ESM::Attribute::Agility).getModified()); + float luck = static_cast(stats.getAttribute(ESM::Attribute::Luck).getModified()); + float sneak = static_cast(ptr.getClass().getSkill(ptr, ESM::Skill::Sneak)); + return (add + 0.2f * agility + 0.1f * luck + sneak) * stats.getFatigueTerm(); } bool Pickpocket::getDetected(float valueTerm) @@ -33,13 +35,13 @@ namespace MWMechanics float t = 2*x - y; - float pcSneak = mThief.getClass().getSkill(mThief, ESM::Skill::Sneak); + float pcSneak = static_cast(mThief.getClass().getSkill(mThief, ESM::Skill::Sneak)); int iPickMinChance = MWBase::Environment::get().getWorld()->getStore().get() .find("iPickMinChance")->getInt(); int iPickMaxChance = MWBase::Environment::get().getWorld()->getStore().get() .find("iPickMaxChance")->getInt(); - int roll = std::rand()/ (static_cast (RAND_MAX) + 1) * 100; // [0, 99] + int roll = OEngine::Misc::Rng::roll0to99(); if (t < pcSneak / iPickMinChance) { return (roll > int(pcSneak / iPickMinChance)); @@ -53,7 +55,7 @@ namespace MWMechanics bool Pickpocket::pick(MWWorld::Ptr item, int count) { - float stackValue = item.getClass().getValue(item) * count; + float stackValue = static_cast(item.getClass().getValue(item) * count); float fPickPocketMod = MWBase::Environment::get().getWorld()->getStore().get() .find("fPickPocketMod")->getFloat(); float valueTerm = 10 * fPickPocketMod * stackValue; diff --git a/apps/openmw/mwmechanics/repair.cpp b/apps/openmw/mwmechanics/repair.cpp index 6d6f889ed..b5058fb88 100644 --- a/apps/openmw/mwmechanics/repair.cpp +++ b/apps/openmw/mwmechanics/repair.cpp @@ -2,6 +2,8 @@ #include +#include + #include "../mwbase/world.hpp" #include "../mwbase/environment.hpp" #include "../mwbase/mechanicsmanager.hpp" @@ -44,12 +46,12 @@ void Repair::repair(const MWWorld::Ptr &itemToRepair) float toolQuality = ref->mBase->mData.mQuality; - float x = (0.1 * pcStrength + 0.1 * pcLuck + armorerSkill) * fatigueTerm; + float x = (0.1f * pcStrength + 0.1f * pcLuck + armorerSkill) * fatigueTerm; - int roll = static_cast (std::rand()) / RAND_MAX * 100; + int roll = OEngine::Misc::Rng::roll0to99(); if (roll <= x) { - int y = fRepairAmountMult * toolQuality * roll; + int y = static_cast(fRepairAmountMult * toolQuality * roll); y = std::max(1, y); // repair by 'y' points diff --git a/apps/openmw/mwmechanics/security.cpp b/apps/openmw/mwmechanics/security.cpp index 4a049d60f..3f72f1b66 100644 --- a/apps/openmw/mwmechanics/security.cpp +++ b/apps/openmw/mwmechanics/security.cpp @@ -1,5 +1,7 @@ #include "security.hpp" +#include + #include "../mwworld/class.hpp" #include "../mwworld/containerstore.hpp" #include "../mwworld/esmstore.hpp" @@ -20,9 +22,9 @@ namespace MWMechanics { CreatureStats& creatureStats = actor.getClass().getCreatureStats(actor); NpcStats& npcStats = actor.getClass().getNpcStats(actor); - mAgility = creatureStats.getAttribute(ESM::Attribute::Agility).getModified(); - mLuck = creatureStats.getAttribute(ESM::Attribute::Luck).getModified(); - mSecuritySkill = npcStats.getSkill(ESM::Skill::Security).getModified(); + mAgility = static_cast(creatureStats.getAttribute(ESM::Attribute::Agility).getModified()); + mLuck = static_cast(creatureStats.getAttribute(ESM::Attribute::Luck).getModified()); + mSecuritySkill = static_cast(npcStats.getSkill(ESM::Skill::Security).getModified()); mFatigueTerm = creatureStats.getFatigueTerm(); } @@ -38,7 +40,7 @@ namespace MWMechanics float fPickLockMult = MWBase::Environment::get().getWorld()->getStore().get().find("fPickLockMult")->getFloat(); - float x = 0.2 * mAgility + 0.1 * mLuck + mSecuritySkill; + float x = 0.2f * mAgility + 0.1f * mLuck + mSecuritySkill; x *= pickQuality * mFatigueTerm; x += fPickLockMult * lockStrength; @@ -48,8 +50,7 @@ namespace MWMechanics else { MWBase::Environment::get().getMechanicsManager()->objectOpened(mActor, lock); - int roll = static_cast (std::rand()) / RAND_MAX * 100; - if (roll <= x) + if (OEngine::Misc::Rng::roll0to99() <= x) { lock.getClass().unlock(lock); resultMessage = "#{sLockSuccess}"; @@ -76,11 +77,11 @@ namespace MWMechanics float probeQuality = probe.get()->mBase->mData.mQuality; const ESM::Spell* trapSpell = MWBase::Environment::get().getWorld()->getStore().get().find(trap.getCellRef().getTrap()); - float trapSpellPoints = trapSpell->mData.mCost; + int trapSpellPoints = trapSpell->mData.mCost; float fTrapCostMult = MWBase::Environment::get().getWorld()->getStore().get().find("fTrapCostMult")->getFloat(); - float x = 0.2 * mAgility + 0.1 * mLuck + mSecuritySkill; + float x = 0.2f * mAgility + 0.1f * mLuck + mSecuritySkill; x += fTrapCostMult * trapSpellPoints; x *= probeQuality * mFatigueTerm; @@ -90,8 +91,7 @@ namespace MWMechanics else { MWBase::Environment::get().getMechanicsManager()->objectOpened(mActor, trap); - int roll = static_cast (std::rand()) / RAND_MAX * 100; - if (roll <= x) + if (OEngine::Misc::Rng::roll0to99() <= x) { trap.getCellRef().setTrap(""); diff --git a/apps/openmw/mwmechanics/spellcasting.cpp b/apps/openmw/mwmechanics/spellcasting.cpp index 49887e560..8a43cc932 100644 --- a/apps/openmw/mwmechanics/spellcasting.cpp +++ b/apps/openmw/mwmechanics/spellcasting.cpp @@ -4,6 +4,8 @@ #include +#include + #include "../mwbase/windowmanager.hpp" #include "../mwbase/soundmanager.hpp" #include "../mwbase/mechanicsmanager.hpp" @@ -56,6 +58,64 @@ namespace } } + void applyDynamicStatsEffect(int attribute, const MWWorld::Ptr& target, float magnitude) + { + MWMechanics::DynamicStat value = target.getClass().getCreatureStats(target).getDynamic(attribute); + value.setCurrent(value.getCurrent()+magnitude, attribute == 2); + target.getClass().getCreatureStats(target).setDynamic(attribute, value); + } + + // TODO: refactor the effect tick functions in Actors so they can be reused here + void applyInstantEffectTick(MWMechanics::EffectKey effect, const MWWorld::Ptr& target, float magnitude) + { + int effectId = effect.mId; + if (effectId == ESM::MagicEffect::DamageHealth) + { + applyDynamicStatsEffect(0, target, magnitude * -1); + } + else if (effectId == ESM::MagicEffect::RestoreHealth) + { + applyDynamicStatsEffect(0, target, magnitude); + } + else if (effectId == ESM::MagicEffect::DamageFatigue) + { + applyDynamicStatsEffect(2, target, magnitude * -1); + } + else if (effectId == ESM::MagicEffect::RestoreFatigue) + { + applyDynamicStatsEffect(2, target, magnitude); + } + else if (effectId == ESM::MagicEffect::DamageMagicka) + { + applyDynamicStatsEffect(1, target, magnitude * -1); + } + else if (effectId == ESM::MagicEffect::RestoreMagicka) + { + applyDynamicStatsEffect(1, target, magnitude); + } + else if (effectId == ESM::MagicEffect::DamageAttribute || effectId == ESM::MagicEffect::RestoreAttribute) + { + int attribute = effect.mArg; + MWMechanics::AttributeValue value = target.getClass().getCreatureStats(target).getAttribute(attribute); + if (effectId == ESM::MagicEffect::DamageAttribute) + value.damage(magnitude); + else + value.restore(magnitude); + target.getClass().getCreatureStats(target).setAttribute(attribute, value); + } + else if (effectId == ESM::MagicEffect::DamageSkill || effectId == ESM::MagicEffect::RestoreSkill) + { + if (target.getTypeName() != typeid(ESM::NPC).name()) + return; + int skill = effect.mArg; + MWMechanics::SkillValue& value = target.getClass().getNpcStats(target).getSkill(skill); + if (effectId == ESM::MagicEffect::DamageSkill) + value.damage(magnitude); + else + value.restore(magnitude); + } + } + } namespace MWMechanics @@ -86,21 +146,21 @@ namespace MWMechanics for (std::vector::const_iterator it = spell->mEffects.mList.begin(); it != spell->mEffects.mList.end(); ++it) { - float x = it->mDuration; + float x = static_cast(it->mDuration); const ESM::MagicEffect* magicEffect = MWBase::Environment::get().getWorld()->getStore().get().find( it->mEffectID); if (!(magicEffect->mData.mFlags & ESM::MagicEffect::UncappedDamage)) x = std::max(1.f, x); - x *= 0.1 * magicEffect->mData.mBaseCost; - x *= 0.5 * (it->mMagnMin + it->mMagnMax); - x *= it->mArea * 0.05 * magicEffect->mData.mBaseCost; + x *= 0.1f * magicEffect->mData.mBaseCost; + x *= 0.5f * (it->mMagnMin + it->mMagnMax); + x *= it->mArea * 0.05f * magicEffect->mData.mBaseCost; if (it->mRange == ESM::RT_Target) - x *= 1.5; + x *= 1.5f; static const float fEffectCostMult = MWBase::Environment::get().getWorld()->getStore().get().find( "fEffectCostMult")->getFloat(); x *= fEffectCostMult; - float s = 2 * actor.getClass().getSkill(actor, spellSchoolToSkill(magicEffect->mData.mSchool)); + float s = 2.0f * actor.getClass().getSkill(actor, spellSchoolToSkill(magicEffect->mData.mSchool)); if (s - x < y) { y = s - x; @@ -116,13 +176,13 @@ namespace MWMechanics if (spell->mData.mFlags & ESM::Spell::F_Always) return 100; - int castBonus = -stats.getMagicEffects().get(ESM::MagicEffect::Sound).getMagnitude(); + float castBonus = -stats.getMagicEffects().get(ESM::MagicEffect::Sound).getMagnitude(); int actorWillpower = stats.getAttribute(ESM::Attribute::Willpower).getModified(); int actorLuck = stats.getAttribute(ESM::Attribute::Luck).getModified(); - float castChance = (lowestSkill - spell->mData.mCost + castBonus + 0.2 * actorWillpower + 0.1 * actorLuck) * stats.getFatigueTerm(); - if (MWBase::Environment::get().getWorld()->getGodModeState() && actor.getRefData().getHandle() == "player") + float castChance = (lowestSkill - spell->mData.mCost + castBonus + 0.2f * actorWillpower + 0.1f * actorLuck) * stats.getFatigueTerm(); + if (MWBase::Environment::get().getWorld()->getGodModeState() && actor == MWBase::Environment::get().getWorld()->getPlayerPtr()) castChance = 100; if (!cap) @@ -209,9 +269,9 @@ namespace MWMechanics float resistance = getEffectResistanceAttribute(effectId, magicEffects); - float willpower = stats.getAttribute(ESM::Attribute::Willpower).getModified(); - float luck = stats.getAttribute(ESM::Attribute::Luck).getModified(); - float x = (willpower + 0.1 * luck) * stats.getFatigueTerm(); + int willpower = stats.getAttribute(ESM::Attribute::Willpower).getModified(); + float luck = static_cast(stats.getAttribute(ESM::Attribute::Luck).getModified()); + float x = (willpower + 0.1f * luck) * stats.getFatigueTerm(); // This makes spells that are easy to cast harder to resist and vice versa float castChance = 100.f; @@ -222,7 +282,7 @@ namespace MWMechanics if (castChance > 0) x *= 50 / castChance; - float roll = static_cast(std::rand()) / RAND_MAX * 100; + float roll = OEngine::Misc::Rng::rollClosedProbability() * 100; if (magicEffect->mData.mFlags & ESM::MagicEffect::NoMagnitude) roll -= resistance; @@ -309,9 +369,11 @@ namespace MWMechanics for (std::vector::const_iterator iter (effects.mList.begin()); iter!=effects.mList.end(); ++iter) { - if (iter->mRange != range) - continue; - found = true; + if (iter->mRange == range) + { + found = true; + break; + } } if (!found) return; @@ -323,11 +385,10 @@ namespace MWMechanics target.getClass().getCreatureStats(target).getMagicEffects().get(ESM::MagicEffect::ResistCommonDisease).getMagnitude() : target.getClass().getCreatureStats(target).getMagicEffects().get(ESM::MagicEffect::ResistBlightDisease).getMagnitude(); - int roll = std::rand()/ (static_cast (RAND_MAX) + 1) * 100; // [0, 99] - if (roll <= x) + if (OEngine::Misc::Rng::roll0to99() <= x) { // Fully resisted, show message - if (target.getRefData().getHandle() == "player") + if (target == MWBase::Environment::get().getWorld()->getPlayerPtr()) MWBase::Environment::get().getWindowManager()->messageBox("#{sMagicPCResisted}"); return; } @@ -345,7 +406,7 @@ namespace MWMechanics if (target.getClass().isActor()) targetEffects += target.getClass().getCreatureStats(target).getMagicEffects(); - bool castByPlayer = (!caster.isEmpty() && caster.getRefData().getHandle() == "player"); + bool castByPlayer = (!caster.isEmpty() && caster == MWBase::Environment::get().getWorld()->getPlayerPtr()); // Try absorbing if it's a spell // NOTE: Vanilla does this once per effect source instead of adding the % from all sources together, not sure @@ -353,9 +414,8 @@ namespace MWMechanics bool absorbed = false; if (spell && caster != target && target.getClass().isActor()) { - int absorb = target.getClass().getCreatureStats(target).getMagicEffects().get(ESM::MagicEffect::SpellAbsorption).getMagnitude(); - int roll = std::rand()/ (static_cast (RAND_MAX) + 1) * 100; // [0, 99] - absorbed = (roll < absorb); + float absorb = target.getClass().getCreatureStats(target).getMagicEffects().get(ESM::MagicEffect::SpellAbsorption).getMagnitude(); + absorbed = (OEngine::Misc::Rng::roll0to99() < absorb); if (absorbed) { const ESM::Static* absorbStatic = MWBase::Environment::get().getWorld()->getStore().get().find ("VFX_Absorb"); @@ -402,9 +462,8 @@ namespace MWMechanics // Try reflecting if (!reflected && magnitudeMult > 0 && !caster.isEmpty() && caster != target && !(magicEffect->mData.mFlags & ESM::MagicEffect::Unreflectable)) { - int reflect = target.getClass().getCreatureStats(target).getMagicEffects().get(ESM::MagicEffect::Reflect).getMagnitude(); - int roll = std::rand()/ (static_cast (RAND_MAX) + 1) * 100; // [0, 99] - bool isReflected = (roll < reflect); + float reflect = target.getClass().getCreatureStats(target).getMagicEffects().get(ESM::MagicEffect::Reflect).getMagnitude(); + bool isReflected = (OEngine::Misc::Rng::roll0to99() < reflect); if (isReflected) { const ESM::Static* reflectStatic = MWBase::Environment::get().getWorld()->getStore().get().find ("VFX_Reflect"); @@ -422,7 +481,7 @@ namespace MWMechanics if (magnitudeMult == 0) { // Fully resisted, show message - if (target.getRefData().getHandle() == "player") + if (target == MWBase::Environment::get().getWorld()->getPlayerPtr()) MWBase::Environment::get().getWindowManager()->messageBox("#{sMagicPCResisted}"); else if (castByPlayer) MWBase::Environment::get().getWindowManager()->messageBox("#{sMagicTargetResisted}"); @@ -432,17 +491,17 @@ namespace MWMechanics if (magnitudeMult > 0 && !absorbed) { - float random = std::rand() / static_cast(RAND_MAX); + float random = OEngine::Misc::Rng::rollClosedProbability(); float magnitude = effectIt->mMagnMin + (effectIt->mMagnMax - effectIt->mMagnMin) * random; magnitude *= magnitudeMult; - bool hasDuration = !(magicEffect->mData.mFlags & ESM::MagicEffect::NoDuration) && effectIt->mDuration > 0; - if (target.getClass().isActor() && hasDuration) + bool hasDuration = !(magicEffect->mData.mFlags & ESM::MagicEffect::NoDuration); + if (target.getClass().isActor() && hasDuration && effectIt->mDuration > 0) { ActiveSpells::ActiveEffect effect; effect.mEffectId = effectIt->mEffectID; effect.mArg = MWMechanics::EffectKey(*effectIt).mArg; - effect.mDuration = effectIt->mDuration; + effect.mDuration = static_cast(effectIt->mDuration); effect.mMagnitude = magnitude; targetEffects.add(MWMechanics::EffectKey(*effectIt), MWMechanics::EffectParam(effect.mMagnitude)); @@ -469,7 +528,12 @@ namespace MWMechanics } } else - applyInstantEffect(target, caster, EffectKey(*effectIt), magnitude); + { + if (hasDuration && target.getClass().isActor()) + applyInstantEffectTick(EffectKey(*effectIt), target, magnitude); + else + applyInstantEffect(target, caster, EffectKey(*effectIt), magnitude); + } // Re-casting a summon effect will remove the creature from previous castings of that effect. if (isSummoningEffect(effectIt->mEffectID) && !target.isEmpty() && target.getClass().isActor()) @@ -483,16 +547,6 @@ namespace MWMechanics } } - // HACK: Damage attribute/skill actually has a duration, even though the actual effect is instant and permanent. - // This was probably just done to have the effect visible in the magic menu for a while - // to notify the player they've been damaged? - if (effectIt->mEffectID == ESM::MagicEffect::DamageAttribute - || effectIt->mEffectID == ESM::MagicEffect::DamageSkill - || effectIt->mEffectID == ESM::MagicEffect::RestoreAttribute - || effectIt->mEffectID == ESM::MagicEffect::RestoreSkill - ) - applyInstantEffect(target, caster, EffectKey(*effectIt), magnitude); - if (target.getClass().isActor() || magicEffect->mData.mFlags & ESM::MagicEffect::NoDuration) { // Play sound, only for the first effect @@ -518,7 +572,7 @@ namespace MWMechanics castStatic = MWBase::Environment::get().getWorld()->getStore().get().find ("VFX_DefaultHit"); // TODO: VFX are no longer active after saving/reloading the game - bool loop = magicEffect->mData.mFlags & ESM::MagicEffect::ContinuousVfx; + bool loop = (magicEffect->mData.mFlags & ESM::MagicEffect::ContinuousVfx) != 0; // Note: in case of non actor, a free effect should be fine as well MWRender::Animation* anim = MWBase::Environment::get().getWorld()->getAnimation(target); if (anim) @@ -556,9 +610,9 @@ namespace MWMechanics { if (target.getCellRef().getLockLevel() < magnitude) //If the door is not already locked to a higher value, lock it to spell magnitude { - if (caster.getRefData().getHandle() == "player") + if (caster == MWBase::Environment::get().getWorld()->getPlayerPtr()) MWBase::Environment::get().getWindowManager()->messageBox("#{sMagicLockSuccess}"); - target.getCellRef().setLockLevel(magnitude); + target.getCellRef().setLockLevel(static_cast(magnitude)); } } else if (effectId == ESM::MagicEffect::Open) @@ -571,7 +625,7 @@ namespace MWMechanics if (!caster.isEmpty() && caster.getClass().isActor()) MWBase::Environment::get().getMechanicsManager()->objectOpened(caster, target); - if (caster.getRefData().getHandle() == "player") + if (caster == MWBase::Environment::get().getWorld()->getPlayerPtr()) MWBase::Environment::get().getWindowManager()->messageBox("#{sMagicOpenSuccess}"); } target.getCellRef().setLockLevel(-abs(target.getCellRef().getLockLevel())); @@ -582,52 +636,6 @@ namespace MWMechanics } else { - if (effectId == ESM::MagicEffect::DamageAttribute || effectId == ESM::MagicEffect::RestoreAttribute) - { - int attribute = effect.mArg; - AttributeValue value = target.getClass().getCreatureStats(target).getAttribute(attribute); - if (effectId == ESM::MagicEffect::DamageAttribute) - value.damage(magnitude); - else - value.restore(magnitude); - target.getClass().getCreatureStats(target).setAttribute(attribute, value); - } - else if (effectId == ESM::MagicEffect::DamageHealth) - { - applyDynamicStatsEffect(0, target, magnitude * -1); - } - else if (effectId == ESM::MagicEffect::RestoreHealth) - { - applyDynamicStatsEffect(0, target, magnitude); - } - else if (effectId == ESM::MagicEffect::DamageFatigue) - { - applyDynamicStatsEffect(2, target, magnitude * -1); - } - else if (effectId == ESM::MagicEffect::RestoreFatigue) - { - applyDynamicStatsEffect(2, target, magnitude); - } - else if (effectId == ESM::MagicEffect::DamageMagicka) - { - applyDynamicStatsEffect(1, target, magnitude * -1); - } - else if (effectId == ESM::MagicEffect::RestoreMagicka) - { - applyDynamicStatsEffect(1, target, magnitude); - } - else if (effectId == ESM::MagicEffect::DamageSkill || effectId == ESM::MagicEffect::RestoreSkill) - { - if (target.getTypeName() != typeid(ESM::NPC).name()) - return; - int skill = effect.mArg; - SkillValue& value = target.getClass().getNpcStats(target).getSkill(skill); - if (effectId == ESM::MagicEffect::DamageSkill) - value.damage(magnitude); - else - value.restore(magnitude); - } - if (effectId == ESM::MagicEffect::CurePoison) target.getClass().getCreatureStats(target).getActiveSpells().purgeEffect(ESM::MagicEffect::Poison); else if (effectId == ESM::MagicEffect::CureParalyzation) @@ -643,7 +651,7 @@ namespace MWMechanics else if (effectId == ESM::MagicEffect::RemoveCurse) target.getClass().getCreatureStats(target).getSpells().purgeCurses(); - if (target.getRefData().getHandle() != "player") + if (target != MWBase::Environment::get().getWorld()->getPlayerPtr()) return; if (!MWBase::Environment::get().getWorld()->isTeleportingEnabled()) return; @@ -677,13 +685,7 @@ namespace MWMechanics } } } - - void CastSpell::applyDynamicStatsEffect(int attribute, const MWWorld::Ptr& target, float magnitude) - { - DynamicStat value = target.getClass().getCreatureStats(target).getDynamic(attribute); - value.modify(magnitude); - target.getClass().getCreatureStats(target).setDynamic(attribute, value); - } + bool CastSpell::cast(const std::string &id) { @@ -718,14 +720,14 @@ namespace MWMechanics // Check if there's enough charge left if (enchantment->mData.mType == ESM::Enchantment::WhenUsed || enchantment->mData.mType == ESM::Enchantment::WhenStrikes) { - const int castCost = getEffectiveEnchantmentCastCost(enchantment->mData.mCost, mCaster); + const int castCost = getEffectiveEnchantmentCastCost(static_cast(enchantment->mData.mCost), mCaster); if (item.getCellRef().getEnchantmentCharge() == -1) - item.getCellRef().setEnchantmentCharge(enchantment->mData.mCharge); + item.getCellRef().setEnchantmentCharge(static_cast(enchantment->mData.mCharge)); if (item.getCellRef().getEnchantmentCharge() < castCost) { - if (mCaster.getRefData().getHandle() == "player") + if (mCaster == MWBase::Environment::get().getWorld()->getPlayerPtr()) MWBase::Environment::get().getWindowManager()->messageBox("#{sMagicInsufficientCharge}"); // Failure sound @@ -749,14 +751,14 @@ namespace MWMechanics if (enchantment->mData.mType == ESM::Enchantment::WhenUsed) { - if (mCaster.getRefData().getHandle() == "player") + if (mCaster == MWBase::Environment::get().getWorld()->getPlayerPtr()) mCaster.getClass().skillUsageSucceeded (mCaster, ESM::Skill::Enchant, 1); } if (enchantment->mData.mType == ESM::Enchantment::CastOnce) item.getContainerStore()->remove(item, 1, mCaster); else if (enchantment->mData.mType != ESM::Enchantment::WhenStrikes) { - if (mCaster.getRefData().getHandle() == "player") + if (mCaster == MWBase::Environment::get().getWorld()->getPlayerPtr()) { mCaster.getClass().skillUsageSucceeded (mCaster, ESM::Skill::Enchant, 3); } @@ -766,8 +768,7 @@ namespace MWMechanics if (!mTarget.isEmpty()) { - if (!mTarget.getClass().isActor() || !mTarget.getClass().getCreatureStats(mTarget).isDead()) - inflict(mTarget, mCaster, enchantment->mEffects, ESM::RT_Touch); + inflict(mTarget, mCaster, enchantment->mEffects, ESM::RT_Touch); } std::string projectileModel; @@ -821,11 +822,10 @@ namespace MWMechanics bool fail = false; // Check success - int successChance = getSpellSuccessChance(spell, mCaster); - int roll = std::rand()/ (static_cast (RAND_MAX) + 1) * 100; // [0, 99] - if (!fail && roll >= successChance) + float successChance = getSpellSuccessChance(spell, mCaster); + if (OEngine::Misc::Rng::roll0to99() >= successChance) { - if (mCaster.getRefData().getHandle() == "player") + if (mCaster == MWBase::Environment::get().getWorld()->getPlayerPtr()) MWBase::Environment::get().getWindowManager()->messageBox("#{sMagicSkillFail}"); fail = true; } @@ -843,7 +843,7 @@ namespace MWMechanics } } - if (mCaster.getRefData().getHandle() == "player" && spellIncreasesSkill(spell)) + if (mCaster == MWBase::Environment::get().getWorld()->getPlayerPtr() && spellIncreasesSkill(spell)) mCaster.getClass().skillUsageSucceeded(mCaster, spellSchoolToSkill(school), 0); @@ -851,10 +851,7 @@ namespace MWMechanics if (!mTarget.isEmpty()) { - if (!mTarget.getClass().isActor() || !mTarget.getClass().getCreatureStats(mTarget).isDead()) - { - inflict(mTarget, mCaster, spell->mEffects, ESM::RT_Touch); - } + inflict(mTarget, mCaster, spell->mEffects, ESM::RT_Touch); } @@ -900,11 +897,11 @@ namespace MWMechanics const MWMechanics::CreatureStats& creatureStats = mCaster.getClass().getCreatureStats(mCaster); float x = (npcStats.getSkill (ESM::Skill::Alchemy).getModified() + - 0.2 * creatureStats.getAttribute (ESM::Attribute::Intelligence).getModified() - + 0.1 * creatureStats.getAttribute (ESM::Attribute::Luck).getModified()) + 0.2f * creatureStats.getAttribute (ESM::Attribute::Intelligence).getModified() + + 0.1f * creatureStats.getAttribute (ESM::Attribute::Luck).getModified()) * creatureStats.getFatigueTerm(); - int roll = std::rand()/ (static_cast (RAND_MAX) + 1) * 100; // [0, 99] + int roll = OEngine::Misc::Rng::roll0to99(); if (roll > x) { // "X has no effect on you" @@ -916,24 +913,24 @@ namespace MWMechanics float magnitude = 0; float y = roll / std::min(x, 100.f); - y *= 0.25 * x; + y *= 0.25f * x; if (magicEffect->mData.mFlags & ESM::MagicEffect::NoDuration) - effect.mDuration = int(y); + effect.mDuration = static_cast(y); else effect.mDuration = 1; if (!(magicEffect->mData.mFlags & ESM::MagicEffect::NoMagnitude)) { if (!(magicEffect->mData.mFlags & ESM::MagicEffect::NoDuration)) - magnitude = int((0.05 * y) / (0.1 * magicEffect->mData.mBaseCost)); + magnitude = floor((0.05f * y) / (0.1f * magicEffect->mData.mBaseCost)); else - magnitude = int(y / (0.1 * magicEffect->mData.mBaseCost)); + magnitude = floor(y / (0.1f * magicEffect->mData.mBaseCost)); magnitude = std::max(1.f, magnitude); } else magnitude = 1; - effect.mMagnMax = magnitude; - effect.mMagnMin = magnitude; + effect.mMagnMax = static_cast(magnitude); + effect.mMagnMin = static_cast(magnitude); ESM::EffectList effects; effects.mList.push_back(effect); diff --git a/apps/openmw/mwmechanics/spellcasting.hpp b/apps/openmw/mwmechanics/spellcasting.hpp index 2d550e085..f50584edf 100644 --- a/apps/openmw/mwmechanics/spellcasting.hpp +++ b/apps/openmw/mwmechanics/spellcasting.hpp @@ -17,7 +17,7 @@ namespace ESM namespace MWMechanics { - class EffectKey; + struct EffectKey; class MagicEffects; ESM::Skill::SkillEnum spellSchoolToSkill(int school); @@ -97,8 +97,6 @@ namespace MWMechanics /// @note \a caster can be any type of object, or even an empty object. void applyInstantEffect (const MWWorld::Ptr& target, const MWWorld::Ptr& caster, const MWMechanics::EffectKey& effect, float magnitude); - - void applyDynamicStatsEffect (int attribute, const MWWorld::Ptr& target, float magnitude); }; } diff --git a/apps/openmw/mwmechanics/spells.cpp b/apps/openmw/mwmechanics/spells.cpp index dcbd3f09f..04225b43e 100644 --- a/apps/openmw/mwmechanics/spells.cpp +++ b/apps/openmw/mwmechanics/spells.cpp @@ -38,7 +38,7 @@ namespace MWMechanics for (unsigned int i=0; imEffects.mList.size();++i) { if (spell->mEffects.mList[i].mMagnMin != spell->mEffects.mList[i].mMagnMax) - random[i] = static_cast (std::rand()) / RAND_MAX; + random[i] = OEngine::Misc::Rng::rollClosedProbability(); } } diff --git a/apps/openmw/mwmechanics/stat.cpp b/apps/openmw/mwmechanics/stat.cpp index 61b6d60ad..1b909d579 100644 --- a/apps/openmw/mwmechanics/stat.cpp +++ b/apps/openmw/mwmechanics/stat.cpp @@ -15,7 +15,6 @@ void MWMechanics::AttributeValue::readState (const ESM::StatState& state) mDamage = state.mDamage; } - void MWMechanics::SkillValue::writeState (ESM::StatState& state) const { AttributeValue::writeState (state); @@ -26,4 +25,4 @@ void MWMechanics::SkillValue::readState (const ESM::StatState& state) { AttributeValue::readState (state); mProgress = state.mProgress; -} \ No newline at end of file +} diff --git a/apps/openmw/mwmechanics/stat.hpp b/apps/openmw/mwmechanics/stat.hpp index 1c33db0fd..ffbc19e15 100644 --- a/apps/openmw/mwmechanics/stat.hpp +++ b/apps/openmw/mwmechanics/stat.hpp @@ -170,10 +170,10 @@ namespace MWMechanics } /// Change modified relatively. - void modify (const T& diff) + void modify (const T& diff, bool allowCurrentDecreaseBelowZero=false) { mStatic.modify (diff); - setCurrent (getCurrent()+diff); + setCurrent (getCurrent()+diff, allowCurrentDecreaseBelowZero); } void setCurrent (const T& value, bool allowDecreaseBelowZero = false) @@ -198,11 +198,11 @@ namespace MWMechanics } } - void setModifier (const T& modifier) + void setModifier (const T& modifier, bool allowCurrentDecreaseBelowZero=false) { T diff = modifier - mStatic.getModifier(); mStatic.setModifier (modifier); - setCurrent (getCurrent()+diff); + setCurrent (getCurrent()+diff, allowCurrentDecreaseBelowZero); } void writeState (ESM::StatState& state) const @@ -246,11 +246,16 @@ namespace MWMechanics int getModifier() const { return mModifier; } void setBase(int base) { mBase = std::max(0, base); } + void setModifier(int mod) { mModifier = mod; } - void damage(float damage) { mDamage += damage; } + // Maximum attribute damage is limited to the modified value. + // Note: I think MW applies damage directly to mModified, since you can also + // "restore" drained attributes. We need to rewrite the magic effect system to support this. + void damage(float damage) { mDamage += std::min(damage, (float)getModified()); } void restore(float amount) { mDamage -= std::min(mDamage, amount); } - int getDamage() const { return mDamage; } + + float getDamage() const { return mDamage; } void writeState (ESM::StatState& state) const; diff --git a/apps/openmw/mwmechanics/summoning.cpp b/apps/openmw/mwmechanics/summoning.cpp index ec9bd0ea0..668031141 100644 --- a/apps/openmw/mwmechanics/summoning.cpp +++ b/apps/openmw/mwmechanics/summoning.cpp @@ -51,6 +51,10 @@ namespace MWMechanics } + UpdateSummonedCreatures::~UpdateSummonedCreatures() + { + } + void UpdateSummonedCreatures::visit(EffectKey key, const std::string &sourceName, const std::string &sourceId, int casterActorId, float magnitude, float remainingTime, float totalTime) { if (isSummoningEffect(key.mId) && magnitude > 0) diff --git a/apps/openmw/mwmechanics/summoning.hpp b/apps/openmw/mwmechanics/summoning.hpp index b8fe37783..8e418cdeb 100644 --- a/apps/openmw/mwmechanics/summoning.hpp +++ b/apps/openmw/mwmechanics/summoning.hpp @@ -14,6 +14,7 @@ namespace MWMechanics struct UpdateSummonedCreatures : public EffectSourceVisitor { UpdateSummonedCreatures(const MWWorld::Ptr& actor); + virtual ~UpdateSummonedCreatures(); virtual void visit (MWMechanics::EffectKey key, const std::string& sourceName, const std::string& sourceId, int casterActorId, diff --git a/apps/openmw/mwrender/animation.cpp b/apps/openmw/mwrender/animation.cpp index 50afc5afd..871561bdc 100644 --- a/apps/openmw/mwrender/animation.cpp +++ b/apps/openmw/mwrender/animation.cpp @@ -365,7 +365,7 @@ void Animation::addExtraLight(Ogre::SceneManager *sceneMgr, NifOgre::ObjectScene // with the standard 1 / (c + d*l + d*d*q) equation the attenuation factor never becomes zero, // so we ignore lights if their attenuation falls below this factor. - const float threshold = 0.03; + const float threshold = 0.03f; float quadraticAttenuation = 0; float linearAttenuation = 0; @@ -1271,7 +1271,11 @@ void Animation::addEffect(const std::string &model, int effectId, bool loop, con if (bonename.empty()) params.mObjects = NifOgre::Loader::createObjects(mInsert, model); else + { + if (!mSkelBase) + return; params.mObjects = NifOgre::Loader::createObjects(mSkelBase, bonename, "", mInsert, model); + } setRenderProperties(params.mObjects, RV_Effects, RQG_Main, RQG_Alpha, 0.f, false, NULL); @@ -1473,7 +1477,7 @@ void Animation::setLightEffect(float effect) } mGlowLight->setType(Ogre::Light::LT_POINT); effect += 3; - mGlowLight->setAttenuation(1.0f / (0.03 * (0.5/effect)), 0, 0.5/effect, 0); + mGlowLight->setAttenuation(1.0f / (0.03f * (0.5f/effect)), 0, 0.5f/effect, 0); } } diff --git a/apps/openmw/mwrender/characterpreview.cpp b/apps/openmw/mwrender/characterpreview.cpp index 756c79ad8..8071dd5fd 100644 --- a/apps/openmw/mwrender/characterpreview.cpp +++ b/apps/openmw/mwrender/characterpreview.cpp @@ -69,13 +69,13 @@ namespace MWRender /// \todo Read the fallback values from INIImporter (Inventory:Directional*) l = mSceneMgr->createLight(); l->setType (Ogre::Light::LT_DIRECTIONAL); - l->setDirection (Ogre::Vector3(0.3, -0.7, 0.3)); + l->setDirection (Ogre::Vector3(0.3f, -0.7f, 0.3f)); l->setDiffuseColour (Ogre::ColourValue(1,1,1)); mSceneMgr->setAmbientLight (Ogre::ColourValue(0.25, 0.25, 0.25)); mCamera = mSceneMgr->createCamera (mName); - mCamera->setFOVy(Ogre::Degree(12.3)); + mCamera->setFOVy(Ogre::Degree(12.3f)); mCamera->setAspectRatio (float(mSizeX) / float(mSizeY)); Ogre::SceneNode* renderRoot = mSceneMgr->getRootSceneNode()->createChildSceneNode("renderRoot"); diff --git a/apps/openmw/mwrender/creatureanimation.cpp b/apps/openmw/mwrender/creatureanimation.cpp index 2bdf8a499..7260fc6d1 100644 --- a/apps/openmw/mwrender/creatureanimation.cpp +++ b/apps/openmw/mwrender/creatureanimation.cpp @@ -88,6 +88,9 @@ void CreatureWeaponAnimation::updateParts() void CreatureWeaponAnimation::updatePart(NifOgre::ObjectScenePtr& scene, int slot) { + if (!mSkelBase) + return; + MWWorld::InventoryStore& inv = mPtr.getClass().getInventoryStore(mPtr); MWWorld::ContainerStoreIterator it = inv.getSlot(slot); @@ -181,7 +184,9 @@ void CreatureWeaponAnimation::releaseArrow() Ogre::Vector3 CreatureWeaponAnimation::runAnimation(float duration) { Ogre::Vector3 ret = Animation::runAnimation(duration); - pitchSkeleton(mPtr.getRefData().getPosition().rot[0], mSkelBase->getSkeleton()); + + if (mSkelBase) + pitchSkeleton(mPtr.getRefData().getPosition().rot[0], mSkelBase->getSkeleton()); if (!mWeapon.isNull()) { diff --git a/apps/openmw/mwrender/debugging.cpp b/apps/openmw/mwrender/debugging.cpp index 972c1b6dd..79eeff2d0 100644 --- a/apps/openmw/mwrender/debugging.cpp +++ b/apps/openmw/mwrender/debugging.cpp @@ -21,6 +21,7 @@ #include "../mwworld/ptr.hpp" #include "../mwworld/cellstore.hpp" #include "../mwworld/esmstore.hpp" +#include "../mwmechanics/pathfinding.hpp" #include "renderconst.hpp" @@ -81,12 +82,12 @@ ManualObject *Debugging::createPathgridLines(const ESM::Pathgrid *pathgrid) { const ESM::Pathgrid::Edge &edge = *it; const ESM::Pathgrid::Point &p1 = pathgrid->mPoints[edge.mV0], &p2 = pathgrid->mPoints[edge.mV1]; - Vector3 direction = (Vector3(p2.mX, p2.mY, p2.mZ) - Vector3(p1.mX, p1.mY, p1.mZ)); + Vector3 direction = (MWMechanics::PathFinder::MakeOgreVector3(p2) - MWMechanics::PathFinder::MakeOgreVector3(p1)); Vector3 lineDisplacement = direction.crossProduct(Vector3::UNIT_Z).normalisedCopy(); lineDisplacement = lineDisplacement * POINT_MESH_BASE + Vector3(0, 0, 10); // move lines up a little, so they will be less covered by meshes/landscape - result->position(Vector3(p1.mX, p1.mY, p1.mZ) + lineDisplacement); - result->position(Vector3(p2.mX, p2.mY, p2.mZ) + lineDisplacement); + result->position(MWMechanics::PathFinder::MakeOgreVector3(p1) + lineDisplacement); + result->position(MWMechanics::PathFinder::MakeOgreVector3(p2) + lineDisplacement); } result->end(); @@ -108,7 +109,7 @@ ManualObject *Debugging::createPathgridPoints(const ESM::Pathgrid *pathgrid) it != pathgrid->mPoints.end(); ++it, startIndex += 6) { - Vector3 pointPos(it->mX, it->mY, it->mZ); + Vector3 pointPos(MWMechanics::PathFinder::MakeOgreVector3(*it)); if (!first) { @@ -117,11 +118,13 @@ ManualObject *Debugging::createPathgridPoints(const ESM::Pathgrid *pathgrid) result->index(startIndex); // start point of current octahedron } + Ogre::Real pointMeshBase = static_cast(POINT_MESH_BASE); + result->position(pointPos + Vector3(0, 0, height)); // 0 - result->position(pointPos + Vector3(-POINT_MESH_BASE, -POINT_MESH_BASE, 0)); // 1 - result->position(pointPos + Vector3(POINT_MESH_BASE, -POINT_MESH_BASE, 0)); // 2 - result->position(pointPos + Vector3(POINT_MESH_BASE, POINT_MESH_BASE, 0)); // 3 - result->position(pointPos + Vector3(-POINT_MESH_BASE, POINT_MESH_BASE, 0)); // 4 + result->position(pointPos + Vector3(-pointMeshBase, -pointMeshBase, 0)); // 1 + result->position(pointPos + Vector3(pointMeshBase, -pointMeshBase, 0)); // 2 + result->position(pointPos + Vector3(pointMeshBase, pointMeshBase, 0)); // 3 + result->position(pointPos + Vector3(-pointMeshBase, pointMeshBase, 0)); // 4 result->position(pointPos + Vector3(0, 0, -height)); // 5 result->index(startIndex + 0); @@ -239,8 +242,8 @@ void Debugging::enableCellPathgrid(MWWorld::CellStore *store) Vector3 cellPathGridPos(0, 0, 0); if (store->getCell()->isExterior()) { - cellPathGridPos.x = store->getCell()->mData.mX * ESM::Land::REAL_SIZE; - cellPathGridPos.y = store->getCell()->mData.mY * ESM::Land::REAL_SIZE; + cellPathGridPos.x = static_cast(store->getCell()->mData.mX * ESM::Land::REAL_SIZE); + cellPathGridPos.y = static_cast(store->getCell()->mData.mY * ESM::Land::REAL_SIZE); } SceneNode *cellPathGrid = mPathGridRoot->createChildSceneNode(cellPathGridPos); cellPathGrid->attachObject(createPathgridLines(pathgrid)); diff --git a/apps/openmw/mwrender/globalmap.cpp b/apps/openmw/mwrender/globalmap.cpp index de78748b5..95d4429d6 100644 --- a/apps/openmw/mwrender/globalmap.cpp +++ b/apps/openmw/mwrender/globalmap.cpp @@ -86,8 +86,8 @@ namespace MWRender { for (int cellX=0; cellX(float(cellX)/float(mCellSize) * 9); + int vertexY = static_cast(float(cellY) / float(mCellSize) * 9); int texelX = (x-mMinX) * mCellSize + cellX; @@ -102,9 +102,9 @@ namespace MWRender y = (SCHAR_MIN << 4) / 2048.f; if (y < 0) { - r = (14 * y + 38); - g = 20 * y + 56; - b = 18 * y + 51; + r = static_cast(14 * y + 38); + g = static_cast(20 * y + 56); + b = static_cast(18 * y + 51); } else if (y < 0.3f) { @@ -112,20 +112,20 @@ namespace MWRender y *= 8.f; else { - y -= 0.1; - y += 0.8; + y -= 0.1f; + y += 0.8f; } - r = 66 - 32 * y; - g = 48 - 23 * y; - b = 33 - 16 * y; + r = static_cast(66 - 32 * y); + g = static_cast(48 - 23 * y); + b = static_cast(33 - 16 * y); } else { y -= 0.3f; y *= 1.428f; - r = 34 - 29 * y; - g = 25 - 20 * y; - b = 17 - 12 * y; + r = static_cast(34 - 29 * y); + g = static_cast(25 - 20 * y); + b = static_cast(17 - 12 * y); } data[texelY * mWidth * 3 + texelX * 3] = r; @@ -172,9 +172,9 @@ namespace MWRender void GlobalMap::exploreCell(int cellX, int cellY) { - float originX = (cellX - mMinX) * mCellSize; + float originX = static_cast((cellX - mMinX) * mCellSize); // NB y + 1, because we want the top left corner, not bottom left where the origin of the cell is - float originY = mHeight - (cellY+1 - mMinY) * mCellSize; + float originY = static_cast(mHeight - (cellY + 1 - mMinY) * mCellSize); if (cellX > mMaxX || cellX < mMinX || cellY > mMaxY || cellY < mMinY) return; @@ -188,7 +188,8 @@ namespace MWRender int mapHeight = localMapTexture->getHeight(); mOverlayTexture->load(); mOverlayTexture->getBuffer()->blit(localMapTexture->getBuffer(), Ogre::Image::Box(0,0,mapWidth,mapHeight), - Ogre::Image::Box(originX,originY,originX+mCellSize,originY+mCellSize)); + Ogre::Image::Box(static_cast(originX), static_cast(originY), + static_cast(originX + mCellSize), static_cast(originY + mCellSize))); Ogre::Image backup; std::vector data; @@ -204,7 +205,7 @@ namespace MWRender assert (originY+y < mOverlayImage.getHeight()); assert (x < int(backup.getWidth())); assert (y < int(backup.getHeight())); - mOverlayImage.setColourAt(backup.getColourAt(x, y, 0), originX+x, originY+y, 0); + mOverlayImage.setColourAt(backup.getColourAt(x, y, 0), static_cast(originX + x), static_cast(originY + y), 0); } } } diff --git a/apps/openmw/mwrender/globalmap.hpp b/apps/openmw/mwrender/globalmap.hpp index b3ae85b11..a162ab68f 100644 --- a/apps/openmw/mwrender/globalmap.hpp +++ b/apps/openmw/mwrender/globalmap.hpp @@ -12,7 +12,7 @@ namespace Loading namespace ESM { - class GlobalMap; + struct GlobalMap; } namespace MWRender diff --git a/apps/openmw/mwrender/localmap.cpp b/apps/openmw/mwrender/localmap.cpp index 638a08623..0299dc493 100644 --- a/apps/openmw/mwrender/localmap.cpp +++ b/apps/openmw/mwrender/localmap.cpp @@ -43,9 +43,9 @@ LocalMap::LocalMap(OEngine::Render::OgreRenderer* rend, MWRender::RenderingManag mLight = mRendering->getScene()->createLight(); mLight->setType (Ogre::Light::LT_DIRECTIONAL); - mLight->setDirection (Ogre::Vector3(0.3, 0.3, -0.7)); + mLight->setDirection (Ogre::Vector3(0.3f, 0.3f, -0.7f)); mLight->setVisible (false); - mLight->setDiffuseColour (ColourValue(0.7,0.7,0.7)); + mLight->setDiffuseColour (ColourValue(0.7f,0.7f,0.7f)); mRenderTexture = TextureManager::getSingleton().createManual( "localmap/rtt", @@ -114,8 +114,8 @@ void LocalMap::saveFogOfWar(MWWorld::CellStore* cell) Vector2 min(mBounds.getMinimum().x, mBounds.getMinimum().y); Vector2 max(mBounds.getMaximum().x, mBounds.getMaximum().y); Vector2 length = max-min; - const int segsX = std::ceil( length.x / sSize ); - const int segsY = std::ceil( length.y / sSize ); + const int segsX = static_cast(std::ceil(length.x / sSize)); + const int segsY = static_cast(std::ceil(length.y / sSize)); mInteriorName = cell->getCell()->mName; @@ -175,7 +175,7 @@ void LocalMap::requestMap(MWWorld::CellStore* cell, float zMin, float zMax) // Note: using force=true for exterior cell maps. // They must be updated even if they were visited before, because the set of surrounding active cells might be different // (and objects in a different cell can "bleed" into another cell's map if they cross the border) - render((x+0.5)*sSize, (y+0.5)*sSize, zMin, zMax, sSize, sSize, name, true); + render((x+0.5f)*sSize, (y+0.5f)*sSize, zMin, zMax, static_cast(sSize), static_cast(sSize), name, true); if (mBuffers.find(name) == mBuffers.end()) { @@ -226,7 +226,7 @@ void LocalMap::requestMap(MWWorld::CellStore* cell, // Do NOT change padding! This will break older savegames. // If the padding really needs to be changed, then it must be saved in the ESM::FogState and // assume the old (500) value as default for older savegames. - const int padding = 500; + const Ogre::Real padding = 500.0f; // Apply a little padding mBounds.setMinimum (mBounds.getMinimum() - Vector3(padding,padding,0)); @@ -279,8 +279,8 @@ void LocalMap::requestMap(MWWorld::CellStore* cell, mCameraPosNode->setPosition(Vector3(center.x, center.y, 0)); // divide into segments - const int segsX = std::ceil( length.x / sSize ); - const int segsY = std::ceil( length.y / sSize ); + const int segsX = static_cast(std::ceil(length.x / sSize)); + const int segsY = static_cast(std::ceil(length.y / sSize)); mInteriorName = cell->getCell()->mName; @@ -289,12 +289,12 @@ void LocalMap::requestMap(MWWorld::CellStore* cell, { for (int y=0; y(sSize*x), static_cast(sSize*y)); Vector2 newcenter = start + sSize/2; std::string texturePrefix = cell->getCell()->mName + "_" + coordStr(x,y); - render(newcenter.x - center.x, newcenter.y - center.y, zMin, zMax, sSize, sSize, texturePrefix); + render(newcenter.x - center.x, newcenter.y - center.y, zMin, zMax, static_cast(sSize), static_cast(sSize), texturePrefix); if (!cell->getFog()) createFogOfWar(texturePrefix); @@ -397,7 +397,7 @@ void LocalMap::render(const float x, const float y, // set up lighting Ogre::ColourValue oldAmbient = mRendering->getScene()->getAmbientLight(); - mRendering->getScene()->setAmbientLight(Ogre::ColourValue(0.3, 0.3, 0.3)); + mRendering->getScene()->setAmbientLight(Ogre::ColourValue(0.3f, 0.3f, 0.3f)); mRenderingManager->disableLights(true); mLight->setVisible(true); @@ -439,11 +439,11 @@ void LocalMap::worldToInteriorMapPosition (Ogre::Vector2 pos, float& nX, float& Vector2 min(mBounds.getMinimum().x, mBounds.getMinimum().y); - x = std::ceil((pos.x - min.x)/sSize)-1; - y = std::ceil((pos.y - min.y)/sSize)-1; + x = static_cast(std::ceil((pos.x - min.x) / sSize) - 1); + y = static_cast(std::ceil((pos.y - min.y) / sSize) - 1); nX = (pos.x - min.x - sSize*x)/sSize; - nY = 1.0-(pos.y - min.y - sSize*y)/sSize; + nY = 1.0f-(pos.y - min.y - sSize*y)/sSize; } Ogre::Vector2 LocalMap::interiorMapToWorldPosition (float nX, float nY, int x, int y) @@ -452,7 +452,7 @@ Ogre::Vector2 LocalMap::interiorMapToWorldPosition (float nX, float nY, int x, i Ogre::Vector2 pos; pos.x = sSize * (nX + x) + min.x; - pos.y = sSize * (1.0-nY + y) + min.y; + pos.y = sSize * (1.0f-nY + y) + min.y; pos = rotatePoint(pos, Vector2(mBounds.getCenter().x, mBounds.getCenter().y), -mAngle); return pos; @@ -468,8 +468,8 @@ bool LocalMap::isPositionExplored (float nX, float nY, int x, int y, bool interi nX = std::max(0.f, std::min(1.f, nX)); nY = std::max(0.f, std::min(1.f, nY)); - int texU = (sFogOfWarResolution-1) * nX; - int texV = (sFogOfWarResolution-1) * nY; + int texU = static_cast((sFogOfWarResolution - 1) * nX); + int texV = static_cast((sFogOfWarResolution - 1) * nY); Ogre::uint32 clr = mBuffers[texName][texV * sFogOfWarResolution + texU]; uint8 alpha = (clr >> 24); @@ -522,8 +522,8 @@ void LocalMap::updatePlayer (const Ogre::Vector3& position, const Ogre::Quaterni if (!mInterior) { - x = std::ceil(pos.x / sSize)-1; - y = std::ceil(pos.y / sSize)-1; + x = static_cast(std::ceil(pos.x / sSize) - 1); + y = static_cast(std::ceil(pos.y / sSize) - 1); } else MWBase::Environment::get().getWindowManager()->setActiveMap(x,y,mInterior); @@ -533,7 +533,7 @@ void LocalMap::updatePlayer (const Ogre::Vector3& position, const Ogre::Quaterni if (!mInterior) { u = std::abs((pos.x - (sSize*x))/sSize); - v = 1.0-std::abs((pos.y - (sSize*y))/sSize); + v = 1.0f-std::abs((pos.y - (sSize*y))/sSize); texBaseName = "Cell_"; } else @@ -545,7 +545,7 @@ void LocalMap::updatePlayer (const Ogre::Vector3& position, const Ogre::Quaterni MWBase::Environment::get().getWindowManager()->setPlayerDir(playerdirection.x, playerdirection.y); // explore radius (squared) - const float exploreRadius = (mInterior ? 0.1 : 0.3) * (sFogOfWarResolution-1); // explore radius from 0 to sFogOfWarResolution-1 + const float exploreRadius = (mInterior ? 0.1f : 0.3f) * (sFogOfWarResolution-1); // explore radius from 0 to sFogOfWarResolution-1 const float sqrExploreRadius = Math::Sqr(exploreRadius); const float exploreRadiusUV = exploreRadius / sFogOfWarResolution; // explore radius from 0 to 1 (UV space) diff --git a/apps/openmw/mwrender/localmap.hpp b/apps/openmw/mwrender/localmap.hpp index 7cfa38814..014c67f16 100644 --- a/apps/openmw/mwrender/localmap.hpp +++ b/apps/openmw/mwrender/localmap.hpp @@ -14,7 +14,7 @@ namespace MWWorld namespace ESM { - class FogTexture; + struct FogTexture; } namespace MWRender diff --git a/apps/openmw/mwrender/npcanimation.cpp b/apps/openmw/mwrender/npcanimation.cpp index 0926498c0..a724644a7 100644 --- a/apps/openmw/mwrender/npcanimation.cpp +++ b/apps/openmw/mwrender/npcanimation.cpp @@ -12,6 +12,8 @@ #include +#include + #include #include "../mwworld/esmstore.hpp" @@ -101,7 +103,7 @@ void HeadAnimationTime::setEnabled(bool enabled) void HeadAnimationTime::resetBlinkTimer() { - mBlinkTimer = -(2 + (std::rand() / double(RAND_MAX*1.0)) * 6); + mBlinkTimer = -(2.0f + OEngine::Misc::Rng::rollDice(6)); } void HeadAnimationTime::update(float dt) @@ -335,7 +337,10 @@ void NpcAnimation::updateNpcBase() } void NpcAnimation::updateParts() -{ +{ + if (!mSkelBase) + return; + mAlpha = 1.f; const MWWorld::Class &cls = mPtr.getClass(); @@ -374,7 +379,7 @@ void NpcAnimation::updateParts() }; static const size_t slotlistsize = sizeof(slotlist)/sizeof(slotlist[0]); - bool wasArrowAttached = (mAmmunition.get()); + bool wasArrowAttached = (mAmmunition.get() != NULL); MWWorld::InventoryStore& inv = mPtr.getClass().getInventoryStore(mPtr); for(size_t i = 0;i < slotlistsize && mViewMode != VM_HeadOnly;i++) @@ -621,30 +626,33 @@ NifOgre::ObjectScenePtr NpcAnimation::insertBoundedPart(const std::string &model } Ogre::Vector3 NpcAnimation::runAnimation(float timepassed) -{ +{ Ogre::Vector3 ret = Animation::runAnimation(timepassed); mHeadAnimationTime->update(timepassed); - Ogre::SkeletonInstance *baseinst = mSkelBase->getSkeleton(); - if(mViewMode == VM_FirstPerson) + if (mSkelBase) { - float pitch = mPtr.getRefData().getPosition().rot[0]; - Ogre::Node *node = baseinst->getBone("Bip01 Neck"); - node->pitch(Ogre::Radian(-pitch), Ogre::Node::TS_WORLD); + Ogre::SkeletonInstance *baseinst = mSkelBase->getSkeleton(); + if(mViewMode == VM_FirstPerson) + { + float pitch = mPtr.getRefData().getPosition().rot[0]; + Ogre::Node *node = baseinst->getBone("Bip01 Neck"); + node->pitch(Ogre::Radian(-pitch), Ogre::Node::TS_WORLD); - // This has to be done before this function ends; - // updateSkeletonInstance, below, touches the hands. - node->translate(mFirstPersonOffset, Ogre::Node::TS_WORLD); - } - else - { - // In third person mode we may still need pitch for ranged weapon targeting - pitchSkeleton(mPtr.getRefData().getPosition().rot[0], baseinst); + // This has to be done before this function ends; + // updateSkeletonInstance, below, touches the hands. + node->translate(mFirstPersonOffset, Ogre::Node::TS_WORLD); + } + else + { + // In third person mode we may still need pitch for ranged weapon targeting + pitchSkeleton(mPtr.getRefData().getPosition().rot[0], baseinst); - Ogre::Node* node = baseinst->getBone("Bip01 Head"); - if (node) - node->rotate(Ogre::Quaternion(mHeadYaw, Ogre::Vector3::UNIT_Z) * Ogre::Quaternion(mHeadPitch, Ogre::Vector3::UNIT_X), Ogre::Node::TS_WORLD); + Ogre::Node* node = baseinst->getBone("Bip01 Head"); + if (node) + node->rotate(Ogre::Quaternion(mHeadYaw, Ogre::Vector3::UNIT_Z) * Ogre::Quaternion(mHeadPitch, Ogre::Vector3::UNIT_X), Ogre::Node::TS_WORLD); + } } mFirstPersonOffset = 0.f; // reset the X, Y, Z offset for the next frame. @@ -659,7 +667,9 @@ Ogre::Vector3 NpcAnimation::runAnimation(float timepassed) if (!isSkinned(mObjectParts[i])) continue; - updateSkeletonInstance(baseinst, mObjectParts[i]->mSkelBase->getSkeleton()); + if (mSkelBase) + updateSkeletonInstance(mSkelBase->getSkeleton(), mObjectParts[i]->mSkelBase->getSkeleton()); + mObjectParts[i]->mSkelBase->getAllAnimationStates()->_notifyDirty(); } @@ -933,7 +943,7 @@ void NpcAnimation::permanentEffectAdded(const ESM::MagicEffect *magicEffect, boo if (!magicEffect->mHit.empty()) { const ESM::Static* castStatic = MWBase::Environment::get().getWorld()->getStore().get().find (magicEffect->mHit); - bool loop = magicEffect->mData.mFlags & ESM::MagicEffect::ContinuousVfx; + bool loop = (magicEffect->mData.mFlags & ESM::MagicEffect::ContinuousVfx) != 0; // Don't play particle VFX unless the effect is new or it should be looping. if (isNew || loop) addEffect("meshes\\" + castStatic->mModel, magicEffect->mIndex, loop, ""); diff --git a/apps/openmw/mwrender/objects.cpp b/apps/openmw/mwrender/objects.cpp index 965083019..bdaa2d515 100644 --- a/apps/openmw/mwrender/objects.cpp +++ b/apps/openmw/mwrender/objects.cpp @@ -111,7 +111,7 @@ void Objects::insertModel(const MWWorld::Ptr &ptr, const std::string &mesh, bool sg->setOrigin(ptr.getRefData().getBaseNode()->getPosition()); mStaticGeometrySmall[ptr.getCell()] = sg; - sg->setRenderingDistance(Settings::Manager::getInt("small object distance", "Viewing distance")); + sg->setRenderingDistance(static_cast(Settings::Manager::getInt("small object distance", "Viewing distance"))); } else sg = mStaticGeometrySmall[ptr.getCell()]; diff --git a/apps/openmw/mwrender/refraction.cpp b/apps/openmw/mwrender/refraction.cpp index 6cc49089a..739ed24d9 100644 --- a/apps/openmw/mwrender/refraction.cpp +++ b/apps/openmw/mwrender/refraction.cpp @@ -35,7 +35,7 @@ namespace MWRender vp->setShadowsEnabled(false); vp->setVisibilityMask(RV_Refraction); vp->setMaterialScheme("water_refraction"); - vp->setBackgroundColour (Ogre::ColourValue(0.090195, 0.115685, 0.12745)); + vp->setBackgroundColour (Ogre::ColourValue(0.090195f, 0.115685f, 0.12745f)); mRenderTarget->setAutoUpdated(true); mRenderTarget->addListener(this); } diff --git a/apps/openmw/mwrender/renderingmanager.cpp b/apps/openmw/mwrender/renderingmanager.cpp index b83a078ba..8fb1ee53c 100644 --- a/apps/openmw/mwrender/renderingmanager.cpp +++ b/apps/openmw/mwrender/renderingmanager.cpp @@ -120,14 +120,12 @@ RenderingManager::RenderingManager(OEngine::Render::OgreRenderer& _rend, const b // Set default texture filtering options TextureFilterOptions tfo; std::string filter = Settings::Manager::getString("texture filtering", "General"); -#ifndef ANDROID + if (filter == "anisotropic") tfo = TFO_ANISOTROPIC; else if (filter == "trilinear") tfo = TFO_TRILINEAR; else if (filter == "bilinear") tfo = TFO_BILINEAR; else /*if (filter == "none")*/ tfo = TFO_NONE; -#else - tfo = TFO_NONE; -#endif + MaterialManager::getSingleton().setDefaultTextureFiltering(tfo); MaterialManager::getSingleton().setDefaultAnisotropy( (filter == "anisotropic") ? Settings::Manager::getInt("anisotropy", "General") : 1 ); @@ -150,8 +148,8 @@ RenderingManager::RenderingManager(OEngine::Render::OgreRenderer& _rend, const b sh::Factory::getInstance ().setSharedParameter ("waterEnabled", sh::makeProperty (new sh::FloatValue(0.0))); sh::Factory::getInstance ().setSharedParameter ("waterLevel", sh::makeProperty(new sh::FloatValue(0))); sh::Factory::getInstance ().setSharedParameter ("waterTimer", sh::makeProperty(new sh::FloatValue(0))); - sh::Factory::getInstance ().setSharedParameter ("windDir_windSpeed", sh::makeProperty(new sh::Vector3(0.5, -0.8, 0.2))); - sh::Factory::getInstance ().setSharedParameter ("waterSunFade_sunHeight", sh::makeProperty(new sh::Vector2(1, 0.6))); + sh::Factory::getInstance ().setSharedParameter ("windDir_windSpeed", sh::makeProperty(new sh::Vector3(0.5f, -0.8f, 0.2f))); + sh::Factory::getInstance ().setSharedParameter ("waterSunFade_sunHeight", sh::makeProperty(new sh::Vector2(1, 0.6f))); sh::Factory::getInstance ().setGlobalSetting ("refraction", Settings::Manager::getBool("refraction", "Water") ? "true" : "false"); sh::Factory::getInstance ().setGlobalSetting ("viewproj_fix", "false"); sh::Factory::getInstance ().setSharedParameter ("vpRow2Fix", sh::makeProperty (new sh::Vector4(0,0,0,0))); @@ -323,7 +321,7 @@ void RenderingManager::updatePlayerPtr(const MWWorld::Ptr &ptr) void RenderingManager::rebuildPtr(const MWWorld::Ptr &ptr) { NpcAnimation *anim = NULL; - if(ptr.getRefData().getHandle() == "player") + if(ptr == MWBase::Environment::get().getWorld()->getPlayerPtr()) anim = mPlayerAnimation; else if(ptr.getClass().isActor()) anim = dynamic_cast(mActors->getAnimation(ptr)); @@ -348,7 +346,7 @@ void RenderingManager::update (float duration, bool paused) MWWorld::Ptr player = world->getPlayerPtr(); - int blind = player.getClass().getCreatureStats(player).getMagicEffects().get(ESM::MagicEffect::Blind).getMagnitude(); + int blind = static_cast(player.getClass().getCreatureStats(player).getMagicEffects().get(ESM::MagicEffect::Blind).getMagnitude()); MWBase::Environment::get().getWindowManager()->setBlindness(std::max(0, std::min(100, blind))); setAmbientMode(); @@ -367,7 +365,7 @@ void RenderingManager::update (float duration, bool paused) btVector3 btOrig(orig.x, orig.y, orig.z); btVector3 btDest(dest.x, dest.y, dest.z); - std::pair test = mPhysicsEngine->sphereCast(mRendering.getCamera()->getNearClipDistance()*2.5, btOrig, btDest); + std::pair test = mPhysicsEngine->sphereCast(mRendering.getCamera()->getNearClipDistance()*2.5f, btOrig, btDest); if(test.first) mCamera->setCameraDistance(test.second * orig.distance(dest), false, false); } @@ -377,8 +375,8 @@ void RenderingManager::update (float duration, bool paused) bool isInAir = !world->isOnGround(player); bool isSwimming = world->isSwimming(player); - static const int i1stPersonSneakDelta = MWBase::Environment::get().getWorld()->getStore().get() - .find("i1stPersonSneakDelta")->getInt(); + static const float i1stPersonSneakDelta = MWBase::Environment::get().getWorld()->getStore().get() + .find("i1stPersonSneakDelta")->getFloat(); if(!paused && isSneaking && !(isSwimming || isInAir)) mCamera->setSneakOffset(i1stPersonSneakDelta); @@ -540,7 +538,7 @@ void RenderingManager::applyFog (bool underwater) } else { - Ogre::ColourValue clv(0.090195, 0.115685, 0.12745); + Ogre::ColourValue clv(0.090195f, 0.115685f, 0.12745f); mRendering.getScene()->setFog (FOG_LINEAR, Ogre::ColourValue(clv), 0, 0, 1000); mRendering.getViewport()->setBackgroundColour (Ogre::ColourValue(clv)); mWater->setViewportBackground (Ogre::ColourValue(clv)); @@ -600,9 +598,9 @@ void RenderingManager::setAmbientColour(const Ogre::ColourValue& colour) mAmbientColor = colour; MWWorld::Ptr player = MWBase::Environment::get().getWorld()->getPlayerPtr(); - int nightEye = player.getClass().getCreatureStats(player).getMagicEffects().get(ESM::MagicEffect::NightEye).getMagnitude(); + int nightEye = static_cast(player.getClass().getCreatureStats(player).getMagicEffects().get(ESM::MagicEffect::NightEye).getMagnitude()); Ogre::ColourValue final = colour; - final += Ogre::ColourValue(0.7,0.7,0.7,0) * std::min(1.f, (nightEye/100.f)); + final += Ogre::ColourValue(0.7f,0.7f,0.7f,0) * std::min(1.f, (nightEye/100.f)); mRendering.getScene()->setAmbientLight(final); } @@ -664,7 +662,7 @@ void RenderingManager::requestMap(MWWorld::CellStore* cell) assert(mTerrain); Ogre::AxisAlignedBox dims = mObjects->getDimensions(cell); - Ogre::Vector2 center (cell->getCell()->getGridX() + 0.5, cell->getCell()->getGridY() + 0.5); + Ogre::Vector2 center (cell->getCell()->getGridX() + 0.5f, cell->getCell()->getGridY() + 0.5f); dims.merge(mTerrain->getWorldBoundingBox(center)); mLocalMap->requestMap(cell, dims.getMinimum().z, dims.getMaximum().z); @@ -716,8 +714,8 @@ Ogre::Vector4 RenderingManager::boundingBoxToScreen(Ogre::AxisAlignedBox bounds) // make 2D relative/normalized coords from the view-space vertex // by dividing out the Z (depth) factor -- this is an approximation - float x = corner.x / corner.z + 0.5; - float y = corner.y / corner.z + 0.5; + float x = corner.x / corner.z + 0.5f; + float y = corner.y / corner.z + 0.5f; if (x < min_x) min_x = x; @@ -957,7 +955,7 @@ Animation* RenderingManager::getAnimation(const MWWorld::Ptr &ptr) { Animation *anim = mActors->getAnimation(ptr); - if(!anim && ptr.getRefData().getHandle() == "player") + if(!anim && ptr == MWBase::Environment::get().getWorld()->getPlayerPtr()) anim = mPlayerAnimation; if (!anim) diff --git a/apps/openmw/mwrender/ripplesimulation.cpp b/apps/openmw/mwrender/ripplesimulation.cpp index 84794162f..f75061af4 100644 --- a/apps/openmw/mwrender/ripplesimulation.cpp +++ b/apps/openmw/mwrender/ripplesimulation.cpp @@ -107,13 +107,13 @@ void RippleSimulation::update(float dt, Ogre::Vector2 position) Ogre::Radian& rotation = created->rotation; #endif timeToLive = totalTimeToLive = mRippleLifeTime; - colour = Ogre::ColourValue(0.f, 0.f, 0.f, 0.7); // Water_RippleAlphas.x? + colour = Ogre::ColourValue(0.f, 0.f, 0.f, 0.7f); // Water_RippleAlphas.x? direction = Ogre::Vector3(0,0,0); position = currentPos; position.z = 0; // Z is set by the Scene Node rotSpeed = mRippleRotSpeed; rotation = Ogre::Radian(Ogre::Math::RangeRandom(-Ogre::Math::PI, Ogre::Math::PI)); - created->setDimensions(50,50); + created->setDimensions(mParticleSystem->getDefaultWidth(), mParticleSystem->getDefaultHeight()); } } diff --git a/apps/openmw/mwrender/shadows.cpp b/apps/openmw/mwrender/shadows.cpp index 5a6ccaca6..f2e60b11b 100644 --- a/apps/openmw/mwrender/shadows.cpp +++ b/apps/openmw/mwrender/shadows.cpp @@ -21,7 +21,7 @@ using namespace MWRender; Shadows::Shadows(OEngine::Render::OgreRenderer* rend) : mRendering(rend), mSceneMgr(rend->getScene()), mPSSMSetup(NULL), - mShadowFar(1000), mFadeStart(0.9) + mShadowFar(1000), mFadeStart(0.9f) { recreate(); } @@ -58,7 +58,7 @@ void Shadows::recreate() mSceneMgr->setShadowTexturePixelFormat(PF_FLOAT32_R); mSceneMgr->setShadowDirectionalLightExtrusionDistance(1000000); - mShadowFar = split ? Settings::Manager::getInt("split shadow distance", "Shadows") : Settings::Manager::getInt("shadow distance", "Shadows"); + mShadowFar = Settings::Manager::getFloat(split ? "split shadow distance" : "shadow distance", "Shadows"); mSceneMgr->setShadowFarDistance(mShadowFar); mFadeStart = Settings::Manager::getFloat("fade start", "Shadows"); diff --git a/apps/openmw/mwrender/sky.cpp b/apps/openmw/mwrender/sky.cpp index f6287de5e..d591cca2e 100644 --- a/apps/openmw/mwrender/sky.cpp +++ b/apps/openmw/mwrender/sky.cpp @@ -19,6 +19,8 @@ #include +#include + #include #include @@ -310,22 +312,22 @@ void SkyManager::create() // Create light used for thunderstorm mLightning = mSceneMgr->createLight(); mLightning->setType (Ogre::Light::LT_DIRECTIONAL); - mLightning->setDirection (Ogre::Vector3(0.3, -0.7, 0.3)); + mLightning->setDirection (Ogre::Vector3(0.3f, -0.7f, 0.3f)); mLightning->setVisible (false); mLightning->setDiffuseColour (ColourValue(3,3,3)); const MWWorld::Fallback* fallback=MWBase::Environment::get().getWorld()->getFallback(); - mSecunda = new Moon("secunda_texture", fallback->getFallbackFloat("Moons_Secunda_Size")/100, Vector3(-0.4, 0.4, 0.5), mRootNode, "openmw_moon"); + mSecunda = new Moon("secunda_texture", fallback->getFallbackFloat("Moons_Secunda_Size")/100, Vector3(-0.4f, 0.4f, 0.5f), mRootNode, "openmw_moon"); mSecunda->setType(Moon::Type_Secunda); mSecunda->setRenderQueue(RQG_SkiesEarly+4); - mMasser = new Moon("masser_texture", fallback->getFallbackFloat("Moons_Masser_Size")/100, Vector3(-0.4, 0.4, 0.5), mRootNode, "openmw_moon"); + mMasser = new Moon("masser_texture", fallback->getFallbackFloat("Moons_Masser_Size")/100, Vector3(-0.4f, 0.4f, 0.5f), mRootNode, "openmw_moon"); mMasser->setRenderQueue(RQG_SkiesEarly+3); mMasser->setType(Moon::Type_Masser); - mSun = new BillboardObject("textures\\tx_sun_05.dds", 1, Vector3(0.4, 0.4, 0.4), mRootNode, "openmw_sun"); + mSun = new BillboardObject("textures\\tx_sun_05.dds", 1, Vector3(0.4f, 0.4f, 0.4f), mRootNode, "openmw_sun"); mSun->setRenderQueue(RQG_SkiesEarly+4); - mSunGlare = new BillboardObject("textures\\tx_sun_flash_grey_05.dds", 3, Vector3(0.4, 0.4, 0.4), mRootNode, "openmw_sun"); + mSunGlare = new BillboardObject("textures\\tx_sun_flash_grey_05.dds", 3, Vector3(0.4f, 0.4f, 0.4f), mRootNode, "openmw_sun"); mSunGlare->setRenderQueue(RQG_SkiesLate); mSunGlare->setVisibilityFlags(RV_NoReflection); @@ -464,8 +466,8 @@ void SkyManager::updateRain(float dt) // TODO: handle rain settings from Morrowind.ini const float rangeRandom = 100; - float xOffs = (std::rand()/(RAND_MAX+1.0)) * rangeRandom - (rangeRandom/2); - float yOffs = (std::rand()/(RAND_MAX+1.0)) * rangeRandom - (rangeRandom/2); + float xOffs = OEngine::Misc::Rng::rollProbability() * rangeRandom - (rangeRandom / 2); + float yOffs = OEngine::Misc::Rng::rollProbability() * rangeRandom - (rangeRandom / 2); // Create a separate node to control the offset, since a node with setInheritOrientation(false) will still // consider the orientation of the parent node for its position, just not for its orientation @@ -680,9 +682,9 @@ void SkyManager::setWeather(const MWWorld::WeatherResult& weather) if (mCloudColour != weather.mSunColor) { - ColourValue clr( weather.mSunColor.r*0.7 + weather.mAmbientColor.r*0.7, - weather.mSunColor.g*0.7 + weather.mAmbientColor.g*0.7, - weather.mSunColor.b*0.7 + weather.mAmbientColor.b*0.7); + ColourValue clr( weather.mSunColor.r*0.7f + weather.mAmbientColor.r*0.7f, + weather.mSunColor.g*0.7f + weather.mAmbientColor.g*0.7f, + weather.mSunColor.b*0.7f + weather.mAmbientColor.b*0.7f); sh::Factory::getInstance().setSharedParameter ("cloudColour", sh::makeProperty(new sh::Vector3(clr.r, clr.g, clr.b))); @@ -774,7 +776,7 @@ void SkyManager::setSunDirection(const Vector3& direction, bool is_night) mSunGlare->setPosition(direction); float height = direction.z; - float fade = is_night ? 0.0 : (( height > 0.5) ? 1.0 : height * 2); + float fade = is_night ? 0.0f : (( height > 0.5) ? 1.0f : height * 2); sh::Factory::getInstance ().setSharedParameter ("waterSunFade_sunHeight", sh::makeProperty(new sh::Vector2(fade, height))); } @@ -836,7 +838,7 @@ void SkyManager::setSecundaFade(const float fade) void SkyManager::setHour(double hour) { - mHour = hour; + mHour = static_cast(hour); } void SkyManager::setDate(int day, int month) diff --git a/apps/openmw/mwrender/terrainstorage.cpp b/apps/openmw/mwrender/terrainstorage.cpp index e74b6af12..8ad2ea321 100644 --- a/apps/openmw/mwrender/terrainstorage.cpp +++ b/apps/openmw/mwrender/terrainstorage.cpp @@ -36,13 +36,13 @@ namespace MWRender for (; it != esmStore.get().extEnd(); ++it) { if (it->getGridX() < minX) - minX = it->getGridX(); + minX = static_cast(it->getGridX()); if (it->getGridX() > maxX) - maxX = it->getGridX(); + maxX = static_cast(it->getGridX()); if (it->getGridY() < minY) - minY = it->getGridY(); + minY = static_cast(it->getGridY()); if (it->getGridY() > maxY) - maxY = it->getGridY(); + maxY = static_cast(it->getGridY()); } // since grid coords are at cell origin, we need to add 1 cell diff --git a/apps/openmw/mwrender/water.cpp b/apps/openmw/mwrender/water.cpp index 456fc47e9..a16b156ae 100644 --- a/apps/openmw/mwrender/water.cpp +++ b/apps/openmw/mwrender/water.cpp @@ -210,7 +210,8 @@ Water::Water (Ogre::Camera *camera, RenderingManager* rend, const MWWorld::Fallb int waterScale = 30; MeshManager::getSingleton().createPlane("water", ResourceGroupManager::DEFAULT_RESOURCE_GROUP_NAME, mWaterPlane, - CELL_SIZE*5*waterScale, CELL_SIZE*5*waterScale, 40, 40, true, 1, 3*waterScale,3*waterScale, Vector3::UNIT_Y); + static_cast(CELL_SIZE*5*waterScale), static_cast(CELL_SIZE*5*waterScale), + 40, 40, true, 1, static_cast(3 * waterScale), static_cast(3 * waterScale), Vector3::UNIT_Y); mWater = mSceneMgr->createEntity("water"); mWater->setVisibilityFlags(RV_Water); @@ -284,7 +285,7 @@ void Water::setActive(bool active) mActive = active; updateVisible(); - sh::Factory::getInstance ().setSharedParameter ("waterEnabled", sh::makeProperty (new sh::FloatValue(active ? 1.0 : 0.0))); + sh::Factory::getInstance ().setSharedParameter ("waterEnabled", sh::makeProperty (new sh::FloatValue(active ? 1.0f : 0.0f))); } Water::~Water() @@ -351,7 +352,7 @@ Water::updateUnderwater(bool underwater) Vector3 Water::getSceneNodeCoordinates(int gridX, int gridY) { - return Vector3(gridX * CELL_SIZE + (CELL_SIZE / 2), gridY * CELL_SIZE + (CELL_SIZE / 2), mTop); + return Vector3(static_cast(gridX * CELL_SIZE + (CELL_SIZE / 2)), static_cast(gridY * CELL_SIZE + (CELL_SIZE / 2)), mTop); } void Water::setViewportBackground(const ColourValue& bg) diff --git a/apps/openmw/mwrender/water.hpp b/apps/openmw/mwrender/water.hpp index 10d0a06ff..775950431 100644 --- a/apps/openmw/mwrender/water.hpp +++ b/apps/openmw/mwrender/water.hpp @@ -122,7 +122,7 @@ namespace MWRender { bool mIsUnderwater; bool mActive; bool mToggled; - int mTop; + float mTop; float mWaterTimer; diff --git a/apps/openmw/mwscript/aiextensions.cpp b/apps/openmw/mwscript/aiextensions.cpp index a3f935487..f0cb8a967 100644 --- a/apps/openmw/mwscript/aiextensions.cpp +++ b/apps/openmw/mwscript/aiextensions.cpp @@ -107,7 +107,7 @@ namespace MWScript // discard additional arguments (reset), because we have no idea what they mean. for (unsigned int i=0; i(duration), x, y, z); ptr.getClass().getCreatureStats (ptr).getAiSequence().stack(escortPackage, ptr); std::cout << "AiEscort: " << x << ", " << y << ", " << z << ", " << duration @@ -145,7 +145,7 @@ namespace MWScript // discard additional arguments (reset), because we have no idea what they mean. for (unsigned int i=0; i(duration), x, y, z); ptr.getClass().getCreatureStats (ptr).getAiSequence().stack(escortPackage, ptr); std::cout << "AiEscort: " << x << ", " << y << ", " << z << ", " << duration @@ -177,13 +177,13 @@ namespace MWScript { MWWorld::Ptr ptr = R()(runtime); - Interpreter::Type_Integer range = runtime[0].mFloat; + Interpreter::Type_Integer range = static_cast(runtime[0].mFloat); runtime.pop(); - Interpreter::Type_Integer duration = runtime[0].mFloat; + Interpreter::Type_Integer duration = static_cast(runtime[0].mFloat); runtime.pop(); - Interpreter::Type_Integer time = runtime[0].mFloat; + Interpreter::Type_Integer time = static_cast(runtime[0].mFloat); runtime.pop(); std::vector idleList; @@ -466,12 +466,9 @@ namespace MWScript virtual void execute (Interpreter::Runtime& runtime) { - InterpreterContext& context - = static_cast (runtime.getContext()); - bool enabled = MWBase::Environment::get().getMechanicsManager()->toggleAI(); - context.report (enabled ? "AI -> On" : "AI -> Off"); + runtime.getContext().report (enabled ? "AI -> On" : "AI -> Off"); } }; diff --git a/apps/openmw/mwscript/containerextensions.cpp b/apps/openmw/mwscript/containerextensions.cpp index 86329191e..70475d8e2 100644 --- a/apps/openmw/mwscript/containerextensions.cpp +++ b/apps/openmw/mwscript/containerextensions.cpp @@ -175,7 +175,7 @@ namespace MWScript MWWorld::ActionEquip action (*it); action.execute(ptr); - if (ptr.getRefData().getHandle() == "player" && !ptr.getClass().getScript(ptr).empty()) + if (ptr == MWBase::Environment::get().getWorld()->getPlayerPtr() && !ptr.getClass().getScript(ptr).empty()) ptr.getRefData().getLocals().setVarByInt(ptr.getClass().getScript(ptr), "onpcequip", 1); } }; diff --git a/apps/openmw/mwscript/controlextensions.cpp b/apps/openmw/mwscript/controlextensions.cpp index fd7fe4737..904e0ee85 100644 --- a/apps/openmw/mwscript/controlextensions.cpp +++ b/apps/openmw/mwscript/controlextensions.cpp @@ -65,12 +65,9 @@ namespace MWScript virtual void execute (Interpreter::Runtime& runtime) { - InterpreterContext& context - = static_cast (runtime.getContext()); - bool enabled = MWBase::Environment::get().getWorld()->toggleCollisionMode(); - context.report (enabled ? "Collision -> On" : "Collision -> Off"); + runtime.getContext().report (enabled ? "Collision -> On" : "Collision -> Off"); } }; diff --git a/apps/openmw/mwscript/globalscripts.cpp b/apps/openmw/mwscript/globalscripts.cpp index 92fd51d87..a6ad2cc11 100644 --- a/apps/openmw/mwscript/globalscripts.cpp +++ b/apps/openmw/mwscript/globalscripts.cpp @@ -100,7 +100,7 @@ namespace MWScript mStore.get().begin(); iter != mStore.get().end(); ++iter) { - scripts.push_back (iter->mScript); + scripts.push_back (iter->mId); } // add scripts diff --git a/apps/openmw/mwscript/globalscripts.hpp b/apps/openmw/mwscript/globalscripts.hpp index 9f009db98..9b7aa0514 100644 --- a/apps/openmw/mwscript/globalscripts.hpp +++ b/apps/openmw/mwscript/globalscripts.hpp @@ -21,7 +21,7 @@ namespace Loading namespace MWWorld { - struct ESMStore; + class ESMStore; } namespace MWScript diff --git a/apps/openmw/mwscript/interpretercontext.cpp b/apps/openmw/mwscript/interpretercontext.cpp index 435f82de7..a8c04aa4b 100644 --- a/apps/openmw/mwscript/interpretercontext.cpp +++ b/apps/openmw/mwscript/interpretercontext.cpp @@ -270,15 +270,21 @@ namespace MWScript std::string InterpreterContext::getActionBinding(const std::string& action) const { - std::vector actions = MWBase::Environment::get().getInputManager()->getActionSorting (); + MWBase::InputManager* input = MWBase::Environment::get().getInputManager(); + std::vector actions = input->getActionKeySorting (); for (std::vector::const_iterator it = actions.begin(); it != actions.end(); ++it) { - std::string desc = MWBase::Environment::get().getInputManager()->getActionDescription (*it); + std::string desc = input->getActionDescription (*it); if(desc == "") continue; if(desc == action) - return MWBase::Environment::get().getInputManager()->getActionBindingName (*it); + { + if(input->joystickLastUsed()) + return input->getActionControllerBindingName(*it); + else + return input->getActionKeyBindingName (*it); + } } return "None"; @@ -469,7 +475,7 @@ namespace MWScript for (int i=0; i<3; ++i) diff[i] = pos1[i] - pos2[i]; - return std::sqrt (diff[0]*diff[0] + diff[1]*diff[1] + diff[2]*diff[2]); + return static_cast(std::sqrt(diff[0] * diff[0] + diff[1] * diff[1] + diff[2] * diff[2])); } bool InterpreterContext::hasBeenActivated (const MWWorld::Ptr& ptr) diff --git a/apps/openmw/mwscript/interpretercontext.hpp b/apps/openmw/mwscript/interpretercontext.hpp index 698df62c2..d3841befd 100644 --- a/apps/openmw/mwscript/interpretercontext.hpp +++ b/apps/openmw/mwscript/interpretercontext.hpp @@ -20,7 +20,7 @@ namespace MWInput namespace MWScript { - struct Locals; + class Locals; class InterpreterContext : public Interpreter::Context { diff --git a/apps/openmw/mwscript/locals.cpp b/apps/openmw/mwscript/locals.cpp index 9dbf07fba..a18d0d5ae 100644 --- a/apps/openmw/mwscript/locals.cpp +++ b/apps/openmw/mwscript/locals.cpp @@ -63,7 +63,7 @@ namespace MWScript return mLongs.at (index); case 'f': - return mFloats.at (index); + return static_cast(mFloats.at(index)); default: return 0; } @@ -87,7 +87,7 @@ namespace MWScript mLongs.at (index) = val; break; case 'f': - mFloats.at (index) = val; break; + mFloats.at(index) = static_cast(val); break; } return true; } diff --git a/apps/openmw/mwscript/locals.hpp b/apps/openmw/mwscript/locals.hpp index bd95835ac..a9fcf317c 100644 --- a/apps/openmw/mwscript/locals.hpp +++ b/apps/openmw/mwscript/locals.hpp @@ -7,7 +7,7 @@ namespace ESM { - struct Script; + class Script; struct Locals; } diff --git a/apps/openmw/mwscript/miscextensions.cpp b/apps/openmw/mwscript/miscextensions.cpp index 52094947c..29f586a65 100644 --- a/apps/openmw/mwscript/miscextensions.cpp +++ b/apps/openmw/mwscript/miscextensions.cpp @@ -81,7 +81,7 @@ namespace MWScript std::string name = runtime.getStringLiteral (runtime[0].mInteger); runtime.pop(); - bool allowSkipping = runtime[0].mInteger; + bool allowSkipping = runtime[0].mInteger != 0; runtime.pop(); MWBase::Environment::get().getWindowManager()->playVideo (name, allowSkipping); @@ -212,13 +212,10 @@ namespace MWScript virtual void execute (Interpreter::Runtime& runtime) { - InterpreterContext& context = - static_cast (runtime.getContext()); - bool enabled = MWBase::Environment::get().getWorld()->toggleRenderMode (MWBase::World::Render_CollisionDebug); - context.report (enabled ? + runtime.getContext().report (enabled ? "Collision Mesh Rendering -> On" : "Collision Mesh Rendering -> Off"); } }; @@ -230,13 +227,10 @@ namespace MWScript virtual void execute (Interpreter::Runtime& runtime) { - InterpreterContext& context = - static_cast (runtime.getContext()); - bool enabled = MWBase::Environment::get().getWorld()->toggleRenderMode (MWBase::World::Render_BoundingBoxes); - context.report (enabled ? + runtime.getContext().report (enabled ? "Bounding Box Rendering -> On" : "Bounding Box Rendering -> Off"); } }; @@ -247,13 +241,10 @@ namespace MWScript virtual void execute (Interpreter::Runtime& runtime) { - InterpreterContext& context = - static_cast (runtime.getContext()); - bool enabled = MWBase::Environment::get().getWorld()->toggleRenderMode (MWBase::World::Render_Wireframe); - context.report (enabled ? + runtime.getContext().report (enabled ? "Wireframe Rendering -> On" : "Wireframe Rendering -> Off"); } }; @@ -263,13 +254,10 @@ namespace MWScript public: virtual void execute (Interpreter::Runtime& runtime) { - InterpreterContext& context = - static_cast (runtime.getContext()); - bool enabled = MWBase::Environment::get().getWorld()->toggleRenderMode (MWBase::World::Render_Pathgrid); - context.report (enabled ? + runtime.getContext().report (enabled ? "Path Grid rendering -> On" : "Path Grid Rendering -> Off"); } }; @@ -312,7 +300,7 @@ namespace MWScript Interpreter::Type_Float time = runtime[0].mFloat; runtime.pop(); - MWBase::Environment::get().getWindowManager()->fadeScreenTo(alpha, time, false); + MWBase::Environment::get().getWindowManager()->fadeScreenTo(static_cast(alpha), time, false); } }; @@ -386,17 +374,14 @@ namespace MWScript virtual void execute(Interpreter::Runtime &runtime) { - InterpreterContext& context = - static_cast (runtime.getContext()); - MWBase::World *world = MWBase::Environment::get().getWorld(); if (world->toggleVanityMode(sActivate)) { - context.report(sActivate ? "Vanity Mode -> On" : "Vanity Mode -> Off"); + runtime.getContext().report(sActivate ? "Vanity Mode -> On" : "Vanity Mode -> Off"); sActivate = !sActivate; } else { - context.report("Vanity Mode -> No"); + runtime.getContext().report("Vanity Mode -> No"); } } }; @@ -862,14 +847,11 @@ namespace MWScript void printGlobalVars(Interpreter::Runtime &runtime) { - InterpreterContext& context = - static_cast (runtime.getContext()); - std::stringstream str; str<< "Global variables:"; MWBase::World *world = MWBase::Environment::get().getWorld(); - std::vector names = context.getGlobals(); + std::vector names = runtime.getContext().getGlobals(); for(size_t i = 0;i < names.size();++i) { char type = world->getGlobalVariableType (names[i]); @@ -879,17 +861,17 @@ namespace MWScript { case 's': - str << context.getGlobalShort (names[i]) << " (short)"; + str << runtime.getContext().getGlobalShort (names[i]) << " (short)"; break; case 'l': - str << context.getGlobalLong (names[i]) << " (long)"; + str << runtime.getContext().getGlobalLong (names[i]) << " (long)"; break; case 'f': - str << context.getGlobalFloat (names[i]) << " (float)"; + str << runtime.getContext().getGlobalFloat (names[i]) << " (float)"; break; default: @@ -898,7 +880,7 @@ namespace MWScript } } - context.report (str.str()); + runtime.getContext().report (str.str()); } public: @@ -920,11 +902,9 @@ namespace MWScript public: virtual void execute (Interpreter::Runtime& runtime) { - InterpreterContext& context = static_cast (runtime.getContext()); - bool enabled = MWBase::Environment::get().getWorld()->toggleScripts(); - context.report(enabled ? "Scripts -> On" : "Scripts -> Off"); + runtime.getContext().report(enabled ? "Scripts -> On" : "Scripts -> Off"); } }; @@ -933,11 +913,9 @@ namespace MWScript public: virtual void execute (Interpreter::Runtime& runtime) { - InterpreterContext& context = static_cast (runtime.getContext()); - bool enabled = MWBase::Environment::get().getWorld()->toggleGodMode(); - context.report (enabled ? "God Mode -> On" : "God Mode -> Off"); + runtime.getContext().report (enabled ? "God Mode -> On" : "God Mode -> Off"); } }; diff --git a/apps/openmw/mwscript/scriptmanagerimp.hpp b/apps/openmw/mwscript/scriptmanagerimp.hpp index 6026f6aba..e4a123b86 100644 --- a/apps/openmw/mwscript/scriptmanagerimp.hpp +++ b/apps/openmw/mwscript/scriptmanagerimp.hpp @@ -16,7 +16,7 @@ namespace MWWorld { - struct ESMStore; + class ESMStore; } namespace Compiler diff --git a/apps/openmw/mwscript/skyextensions.cpp b/apps/openmw/mwscript/skyextensions.cpp index 0ccd0ce31..d28d01b63 100644 --- a/apps/openmw/mwscript/skyextensions.cpp +++ b/apps/openmw/mwscript/skyextensions.cpp @@ -25,10 +25,7 @@ namespace MWScript { bool enabled = MWBase::Environment::get().getWorld()->toggleSky(); - InterpreterContext& context = - static_cast (runtime.getContext()); - - context.report (enabled ? "Sky -> On" : "Sky -> Off"); + runtime.getContext().report (enabled ? "Sky -> On" : "Sky -> Off"); } }; diff --git a/apps/openmw/mwscript/statsextensions.cpp b/apps/openmw/mwscript/statsextensions.cpp index b8bb76388..d825b085e 100644 --- a/apps/openmw/mwscript/statsextensions.cpp +++ b/apps/openmw/mwscript/statsextensions.cpp @@ -169,7 +169,7 @@ namespace MWScript if (mIndex==0 && ptr.getClass().hasItemHealth (ptr)) { // health is a special case - value = ptr.getClass().getItemMaxHealth (ptr); + value = static_cast(ptr.getClass().getItemMaxHealth(ptr)); } else { value = ptr.getClass() @@ -402,7 +402,7 @@ namespace MWScript MWBase::World *world = MWBase::Environment::get().getWorld(); MWWorld::Ptr player = world->getPlayerPtr(); - int bounty = runtime[0].mFloat; + int bounty = static_cast(runtime[0].mFloat); runtime.pop(); player.getClass().getNpcStats (player).setBounty(bounty); @@ -420,7 +420,7 @@ namespace MWScript MWBase::World *world = MWBase::Environment::get().getWorld(); MWWorld::Ptr player = world->getPlayerPtr(); - player.getClass().getNpcStats (player).setBounty(runtime[0].mFloat + player.getClass().getNpcStats (player).getBounty()); + player.getClass().getNpcStats(player).setBounty(static_cast(runtime[0].mFloat) + player.getClass().getNpcStats(player).getBounty()); runtime.pop(); } }; @@ -1195,11 +1195,10 @@ namespace MWScript float currentValue = stats.getMagicEffects().get(mPositiveEffect).getMagnitude(); if (mNegativeEffect != -1) currentValue -= stats.getMagicEffects().get(mNegativeEffect).getMagnitude(); - currentValue = int(currentValue); int arg = runtime[0].mInteger; runtime.pop(); - stats.getMagicEffects().modifyBase(mPositiveEffect, (arg - currentValue)); + stats.getMagicEffects().modifyBase(mPositiveEffect, (arg - static_cast(currentValue))); } }; diff --git a/apps/openmw/mwscript/transformationextensions.cpp b/apps/openmw/mwscript/transformationextensions.cpp index 7af35a9ff..f87983ce8 100644 --- a/apps/openmw/mwscript/transformationextensions.cpp +++ b/apps/openmw/mwscript/transformationextensions.cpp @@ -212,7 +212,7 @@ namespace MWScript if (!ptr.isInCell()) return; - if (ptr.getRefData().getHandle() == "player") + if (ptr == MWBase::Environment::get().getWorld()->getPlayerPtr()) { MWBase::Environment::get().getWorld()->getPlayer().setTeleported(true); } @@ -287,7 +287,7 @@ namespace MWScript if (ptr.getContainerStore()) return; - if (ptr.getRefData().getHandle() == "player") + if (ptr == MWBase::Environment::get().getWorld()->getPlayerPtr()) { MWBase::Environment::get().getWorld()->getPlayer().setTeleported(true); } @@ -310,12 +310,14 @@ namespace MWScript } catch(std::exception&) { - const ESM::Cell* cell = MWBase::Environment::get().getWorld()->getExterior(cellID); - if(cell) + const ESM::Cell* cell = MWBase::Environment::get().getWorld()->getExterior(cellID); + int cx,cy; + MWBase::Environment::get().getWorld()->positionToIndex(x,y,cx,cy); + store = MWBase::Environment::get().getWorld()->getExterior(cx,cy); + if(!cell) { - int cx,cy; - MWBase::Environment::get().getWorld()->positionToIndex(x,y,cx,cy); - store = MWBase::Environment::get().getWorld()->getExterior(cx,cy); + runtime.getContext().report ("unknown cell (" + cellID + ")"); + std::cerr << "unknown cell (" << cellID << ")\n"; } } if(store) @@ -330,15 +332,11 @@ namespace MWScript // except for when you position the player, then degrees must be used. // See "Morrowind Scripting for Dummies (9th Edition)" pages 50 and 54 for reference. if(ptr != MWBase::Environment::get().getWorld()->getPlayerPtr()) - zRot = zRot/60.; + zRot = zRot/60.0f; MWBase::Environment::get().getWorld()->rotateObject(ptr,ax,ay,zRot); ptr.getClass().adjustPosition(ptr, false); } - else - { - throw std::runtime_error (std::string("unknown cell (") + cellID + ")"); - } } }; @@ -354,7 +352,7 @@ namespace MWScript if (!ptr.isInCell()) return; - if (ptr.getRefData().getHandle() == "player") + if (ptr == MWBase::Environment::get().getWorld()->getPlayerPtr()) { MWBase::Environment::get().getWorld()->getPlayer().setTeleported(true); } @@ -373,7 +371,7 @@ namespace MWScript // another morrowind oddity: player will be moved to the exterior cell at this location, // non-player actors will move within the cell they are in. MWWorld::Ptr updated; - if (ptr.getRefData().getHandle() == "player") + if (ptr == MWBase::Environment::get().getWorld()->getPlayerPtr()) { MWWorld::CellStore* cell = MWBase::Environment::get().getWorld()->getExterior(cx,cy); MWBase::Environment::get().getWorld()->moveObject(ptr,cell,x,y,z); @@ -391,7 +389,7 @@ namespace MWScript // except for when you position the player, then degrees must be used. // See "Morrowind Scripting for Dummies (9th Edition)" pages 50 and 54 for reference. if(ptr != MWBase::Environment::get().getWorld()->getPlayerPtr()) - zRot = zRot/60.; + zRot = zRot/60.0f; MWBase::Environment::get().getWorld()->rotateObject(ptr,ax,ay,zRot); ptr.getClass().adjustPosition(ptr, false); } @@ -426,11 +424,13 @@ namespace MWScript catch(std::exception&) { const ESM::Cell* cell = MWBase::Environment::get().getWorld()->getExterior(cellID); - if(cell) + int cx,cy; + MWBase::Environment::get().getWorld()->positionToIndex(x,y,cx,cy); + store = MWBase::Environment::get().getWorld()->getExterior(cx,cy); + if(!cell) { - int cx,cy; - MWBase::Environment::get().getWorld()->positionToIndex(x,y,cx,cy); - store = MWBase::Environment::get().getWorld()->getExterior(cx,cy); + runtime.getContext().report ("unknown cell (" + cellID + ")"); + std::cerr << "unknown cell (" << cellID << ")\n"; } } if(store) @@ -446,10 +446,6 @@ namespace MWScript MWWorld::Ptr placed = MWBase::Environment::get().getWorld()->safePlaceObject(ref.getPtr(),store,pos); placed.getClass().adjustPosition(placed, true); } - else - { - throw std::runtime_error ( std::string("unknown cell (") + cellID + ")"); - } } }; diff --git a/apps/openmw/mwscript/transformationextensions.hpp b/apps/openmw/mwscript/transformationextensions.hpp index a25cc0c3d..7a4d29e06 100644 --- a/apps/openmw/mwscript/transformationextensions.hpp +++ b/apps/openmw/mwscript/transformationextensions.hpp @@ -20,4 +20,4 @@ namespace MWScript } } -#endif \ No newline at end of file +#endif diff --git a/apps/openmw/mwsound/ffmpeg_decoder.cpp b/apps/openmw/mwsound/ffmpeg_decoder.cpp index bc467acff..0185d3ecc 100644 --- a/apps/openmw/mwsound/ffmpeg_decoder.cpp +++ b/apps/openmw/mwsound/ffmpeg_decoder.cpp @@ -30,7 +30,7 @@ int FFmpeg_Decoder::readPacket(void *user_data, uint8_t *buf, int buf_size) Ogre::DataStreamPtr stream = static_cast(user_data)->mDataStream; return stream->read(buf, buf_size); } - catch (std::exception& e) + catch (std::exception& ) { return 0; } @@ -43,7 +43,7 @@ int FFmpeg_Decoder::writePacket(void *user_data, uint8_t *buf, int buf_size) Ogre::DataStreamPtr stream = static_cast(user_data)->mDataStream; return stream->write(buf, buf_size); } - catch (std::exception& e) + catch (std::exception& ) { return 0; } @@ -57,11 +57,11 @@ int64_t FFmpeg_Decoder::seek(void *user_data, int64_t offset, int whence) if(whence == AVSEEK_SIZE) return stream->size(); if(whence == SEEK_SET) - stream->seek(offset); + stream->seek(static_cast(offset)); else if(whence == SEEK_CUR) - stream->seek(stream->tell()+offset); + stream->seek(static_cast(stream->tell()+offset)); else if(whence == SEEK_END) - stream->seek(stream->size()+offset); + stream->seek(static_cast(stream->size()+offset)); else return -1; diff --git a/apps/openmw/mwsound/loudness.cpp b/apps/openmw/mwsound/loudness.cpp index c64913b1f..007791984 100644 --- a/apps/openmw/mwsound/loudness.cpp +++ b/apps/openmw/mwsound/loudness.cpp @@ -8,7 +8,7 @@ namespace MWSound void analyzeLoudness(const std::vector &data, int sampleRate, ChannelConfig chans, SampleType type, std::vector &out, float valuesPerSecond) { - int samplesPerSegment = sampleRate / valuesPerSecond; + int samplesPerSegment = static_cast(sampleRate / valuesPerSecond); int numSamples = bytesToFrames(data.size(), chans, type); int advance = framesToBytes(1, chans, type); diff --git a/apps/openmw/mwsound/openal_output.cpp b/apps/openmw/mwsound/openal_output.cpp index bc9478945..1b3dced80 100644 --- a/apps/openmw/mwsound/openal_output.cpp +++ b/apps/openmw/mwsound/openal_output.cpp @@ -801,7 +801,7 @@ const CachedSound& OpenAL_Output::getBuffer(const std::string &fname) decoder->close(); CachedSound cached; - analyzeLoudness(data, srate, chans, type, cached.mLoudnessVector, loudnessFPS); + analyzeLoudness(data, srate, chans, type, cached.mLoudnessVector, static_cast(loudnessFPS)); alGenBuffers(1, &buf); throwALerror(); @@ -885,7 +885,7 @@ MWBase::SoundPtr OpenAL_Output::playSound(const std::string &fname, float vol, f offset=1; alSourcei(src, AL_BUFFER, buf); - alSourcef(src, AL_SEC_OFFSET, sound->getLength()*offset/pitch); + alSourcef(src, AL_SEC_OFFSET, static_cast(sound->getLength()*offset / pitch)); alSourcePlay(src); throwALerror(); @@ -910,7 +910,7 @@ MWBase::SoundPtr OpenAL_Output::playSound3D(const std::string &fname, const Ogre sound.reset(new OpenAL_Sound3D(*this, src, buf, pos, vol, basevol, pitch, min, max, flags)); if (extractLoudness) - sound->setLoudnessVector(cached.mLoudnessVector, loudnessFPS); + sound->setLoudnessVector(cached.mLoudnessVector, static_cast(loudnessFPS)); } catch(std::exception&) { @@ -929,7 +929,7 @@ MWBase::SoundPtr OpenAL_Output::playSound3D(const std::string &fname, const Ogre offset=1; alSourcei(src, AL_BUFFER, buf); - alSourcef(src, AL_SEC_OFFSET, sound->getLength()*offset/pitch); + alSourcef(src, AL_SEC_OFFSET, static_cast(sound->getLength()*offset / pitch)); alSourcePlay(src); throwALerror(); diff --git a/apps/openmw/mwsound/openal_output.hpp b/apps/openmw/mwsound/openal_output.hpp index be12bfbec..1a95d6150 100644 --- a/apps/openmw/mwsound/openal_output.hpp +++ b/apps/openmw/mwsound/openal_output.hpp @@ -69,7 +69,7 @@ namespace MWSound OpenAL_Output(SoundManager &mgr); virtual ~OpenAL_Output(); - class StreamThread; + struct StreamThread; std::auto_ptr mStreamThread; friend class OpenAL_Sound; diff --git a/apps/openmw/mwsound/sound.cpp b/apps/openmw/mwsound/sound.cpp index b3105a82c..8b6bfda82 100644 --- a/apps/openmw/mwsound/sound.cpp +++ b/apps/openmw/mwsound/sound.cpp @@ -7,7 +7,7 @@ namespace MWSound { if (mLoudnessVector.empty()) return 0.f; - int index = getTimeOffset() * mLoudnessFPS; + int index = static_cast(getTimeOffset() * mLoudnessFPS); index = std::max(0, std::min(index, int(mLoudnessVector.size()-1))); diff --git a/apps/openmw/mwsound/sound_output.hpp b/apps/openmw/mwsound/sound_output.hpp index a9a999a5c..4f5c210bb 100644 --- a/apps/openmw/mwsound/sound_output.hpp +++ b/apps/openmw/mwsound/sound_output.hpp @@ -13,7 +13,7 @@ namespace MWSound { class SoundManager; - class Sound_Decoder; + struct Sound_Decoder; class Sound; class Sound_Output diff --git a/apps/openmw/mwsound/soundmanagerimp.cpp b/apps/openmw/mwsound/soundmanagerimp.cpp index 0bc155118..06c40dd8e 100644 --- a/apps/openmw/mwsound/soundmanagerimp.cpp +++ b/apps/openmw/mwsound/soundmanagerimp.cpp @@ -4,6 +4,8 @@ #include #include +#include + #include "../mwbase/environment.hpp" #include "../mwbase/world.hpp" #include "../mwbase/statemanager.hpp" @@ -106,7 +108,7 @@ namespace MWSound MWBase::World* world = MWBase::Environment::get().getWorld(); const ESM::Sound *snd = world->getStore().get().find(soundId); - volume *= pow(10.0, (snd->mData.mVolume/255.0*3348.0 - 3348.0) / 2000.0); + volume *= static_cast(pow(10.0, (snd->mData.mVolume / 255.0*3348.0 - 3348.0) / 2000.0)); if(snd->mData.mMinRange == 0 && snd->mData.mMaxRange == 0) { @@ -224,7 +226,7 @@ namespace MWSound if(!filelist.size()) return; - int i = rand()%filelist.size(); + int i = OEngine::Misc::Rng::rollDice(filelist.size()); // Don't play the same music track twice in a row if (filelist[i] == mLastPlayedMusic) @@ -477,7 +479,7 @@ namespace MWSound while(snditer != mActiveSounds.end()) { if(snditer->second.first != MWWorld::Ptr() && - snditer->second.first.getCellRef().getRefId() != "player" && + snditer->second.first != MWBase::Environment::get().getWorld()->getPlayerPtr() && snditer->second.first.getCell() == cell) { snditer->first->stop(); @@ -559,7 +561,7 @@ namespace MWSound if(!cell->isExterior() || sTimePassed < sTimeToNextEnvSound) return; - float a = std::rand() / (double)RAND_MAX; + float a = OEngine::Misc::Rng::rollClosedProbability(); // NOTE: We should use the "Minimum Time Between Environmental Sounds" and // "Maximum Time Between Environmental Sounds" fallback settings here. sTimeToNextEnvSound = 5.0f*a + 15.0f*(1.0f-a); @@ -588,7 +590,7 @@ namespace MWSound return; } - int r = (int)(rand()/((double)RAND_MAX+1) * total); + int r = OEngine::Misc::Rng::rollDice(total); int pos = 0; soundIter = regn->mSoundList.begin(); diff --git a/apps/openmw/mwworld/action.cpp b/apps/openmw/mwworld/action.cpp index 0fe061e5c..1c360fd4d 100644 --- a/apps/openmw/mwworld/action.cpp +++ b/apps/openmw/mwworld/action.cpp @@ -20,7 +20,7 @@ void MWWorld::Action::execute (const Ptr& actor) { if (!mSoundId.empty()) { - if (mKeepSound && actor.getRefData().getHandle()=="player") + if (mKeepSound && actor == MWBase::Environment::get().getWorld()->getPlayerPtr()) MWBase::Environment::get().getSoundManager()->playSound(mSoundId, 1.0, 1.0, MWBase::SoundManager::Play_TypeSfx, MWBase::SoundManager::Play_Normal,mSoundOffset); else diff --git a/apps/openmw/mwworld/actionopen.cpp b/apps/openmw/mwworld/actionopen.cpp index e9d8b4716..0df451b18 100644 --- a/apps/openmw/mwworld/actionopen.cpp +++ b/apps/openmw/mwworld/actionopen.cpp @@ -3,8 +3,6 @@ #include "../mwbase/environment.hpp" #include "../mwbase/windowmanager.hpp" -#include "../mwgui/container.hpp" - #include "../mwmechanics/disease.hpp" #include "class.hpp" @@ -25,7 +23,6 @@ namespace MWWorld MWMechanics::diseaseContact(actor, getTarget()); - MWBase::Environment::get().getWindowManager()->pushGuiMode(MWGui::GM_Container); - MWBase::Environment::get().getWindowManager()->getContainerWindow()->open(getTarget(), mLoot); + MWBase::Environment::get().getWindowManager()->openContainer(getTarget(), mLoot); } } diff --git a/apps/openmw/mwworld/actionread.cpp b/apps/openmw/mwworld/actionread.cpp index 0a4e2d6c9..cd0471a0e 100644 --- a/apps/openmw/mwworld/actionread.cpp +++ b/apps/openmw/mwworld/actionread.cpp @@ -4,13 +4,8 @@ #include "../mwbase/windowmanager.hpp" #include "../mwbase/world.hpp" -#include "../mwworld/player.hpp" - #include "../mwmechanics/npcstats.hpp" -#include "../mwgui/bookwindow.hpp" -#include "../mwgui/scrollwindow.hpp" - #include "player.hpp" #include "class.hpp" #include "esmstore.hpp" @@ -33,27 +28,22 @@ namespace MWWorld return; } + bool showTakeButton = (getTarget().getContainerStore() != &actor.getClass().getContainerStore(actor)); + LiveCellRef *ref = getTarget().get(); if (ref->mBase->mData.mIsScroll) - { - MWBase::Environment::get().getWindowManager()->pushGuiMode(MWGui::GM_Scroll); - MWBase::Environment::get().getWindowManager()->getScrollWindow()->open(getTarget()); - } + MWBase::Environment::get().getWindowManager()->showScroll(getTarget(), showTakeButton); else - { - MWBase::Environment::get().getWindowManager()->pushGuiMode(MWGui::GM_Book); - MWBase::Environment::get().getWindowManager()->getBookWindow()->open(getTarget()); - } + MWBase::Environment::get().getWindowManager()->showBook(getTarget(), showTakeButton); - MWWorld::Ptr player = MWBase::Environment::get().getWorld ()->getPlayerPtr(); - MWMechanics::NpcStats& npcStats = player.getClass().getNpcStats (player); + MWMechanics::NpcStats& npcStats = actor.getClass().getNpcStats (actor); // Skill gain from books if (ref->mBase->mData.mSkillID >= 0 && ref->mBase->mData.mSkillID < ESM::Skill::Length && !npcStats.hasBeenUsed (ref->mBase->mId)) { - MWWorld::LiveCellRef *playerRef = player.get(); + MWWorld::LiveCellRef *playerRef = actor.get(); const ESM::Class *class_ = MWBase::Environment::get().getWorld()->getStore().get().find ( diff --git a/apps/openmw/mwworld/actionrepair.cpp b/apps/openmw/mwworld/actionrepair.cpp index a86dc38b1..699440a01 100644 --- a/apps/openmw/mwworld/actionrepair.cpp +++ b/apps/openmw/mwworld/actionrepair.cpp @@ -19,7 +19,6 @@ namespace MWWorld return; } - MWBase::Environment::get().getWindowManager()->pushGuiMode(MWGui::GM_Repair); MWBase::Environment::get().getWindowManager()->startRepairItem(getTarget()); } } diff --git a/apps/openmw/mwworld/actiontrap.cpp b/apps/openmw/mwworld/actiontrap.cpp index 1472afc08..d153b7e61 100644 --- a/apps/openmw/mwworld/actiontrap.cpp +++ b/apps/openmw/mwworld/actiontrap.cpp @@ -1,16 +1,39 @@ #include "actiontrap.hpp" #include "../mwmechanics/spellcasting.hpp" +#include "../mwbase/environment.hpp" +#include "../mwbase/world.hpp" namespace MWWorld { void ActionTrap::executeImp(const Ptr &actor) { - MWMechanics::CastSpell cast(mTrapSource, actor); - cast.mHitPosition = Ogre::Vector3(actor.getRefData().getPosition().pos); - cast.cast(mSpellId); + Ogre::Vector3 actorPosition(actor.getRefData().getPosition().pos); + Ogre::Vector3 trapPosition(mTrapSource.getRefData().getPosition().pos); + float activationDistance = MWBase::Environment::get().getWorld()->getMaxActivationDistance(); + // GUI calcs if object in activation distance include object and player geometry + const float fudgeFactor = 1.25f; + + // Hack: if actor is beyond activation range, then assume actor is using telekinesis + // to open door/container. + // Note, can't just detonate the trap at the trapped object's location and use the blast + // radius, because for most trap spells this is 1 foot, much less than the activation distance. + if (trapPosition.distance(actorPosition) < (activationDistance * fudgeFactor)) + { + // assume actor touched trap + MWMechanics::CastSpell cast(mTrapSource, actor); + cast.mHitPosition = actorPosition; + cast.cast(mSpellId); + } + else + { + // assume telekinesis used + MWMechanics::CastSpell cast(mTrapSource, mTrapSource); + cast.mHitPosition = trapPosition; + cast.cast(mSpellId); + } mTrapSource.getCellRef().setTrap(""); } diff --git a/apps/openmw/mwworld/cellstore.cpp b/apps/openmw/mwworld/cellstore.cpp index 545bbd4b3..7da7c187d 100644 --- a/apps/openmw/mwworld/cellstore.cpp +++ b/apps/openmw/mwworld/cellstore.cpp @@ -407,8 +407,6 @@ namespace MWWorld if (mState==State_Preloaded) mIds.clear(); - std::cout << "loading cell " << mCell->getDescription() << std::endl; - loadRefs (store, esm); mState = State_Loaded; diff --git a/apps/openmw/mwworld/cellstore.hpp b/apps/openmw/mwworld/cellstore.hpp index f6f2a3b48..d7036d6b1 100644 --- a/apps/openmw/mwworld/cellstore.hpp +++ b/apps/openmw/mwworld/cellstore.hpp @@ -3,6 +3,8 @@ #include #include +#include +#include #include #include "livecellref.hpp" @@ -181,7 +183,12 @@ namespace MWWorld template CellRefList& get() { - throw std::runtime_error ("Storage for this type not exist in cells"); + throw std::runtime_error ("Storage for type " + std::string(typeid(T).name())+ " does not exist in cells"); + } + + template + const CellRefList& getReadOnly() { + throw std::runtime_error ("Read Only CellRefList access not available for type " + std::string(typeid(T).name()) ); } bool isPointConnected(const int start, const int end) const; @@ -357,6 +364,12 @@ namespace MWWorld return mWeapons; } + template<> + inline const CellRefList& CellStore::getReadOnly() + { + return mDoors; + } + bool operator== (const CellStore& left, const CellStore& right); bool operator!= (const CellStore& left, const CellStore& right); } diff --git a/apps/openmw/mwworld/class.cpp b/apps/openmw/mwworld/class.cpp index afc5ed635..6fa9ba9b6 100644 --- a/apps/openmw/mwworld/class.cpp +++ b/apps/openmw/mwworld/class.cpp @@ -454,4 +454,9 @@ namespace MWWorld { return -1; } + + int Class::getEffectiveArmorRating(const Ptr &ptr, const Ptr &actor) const + { + throw std::runtime_error("class does not support armor ratings"); + } } diff --git a/apps/openmw/mwworld/class.hpp b/apps/openmw/mwworld/class.hpp index 380d2a34b..782aa7815 100644 --- a/apps/openmw/mwworld/class.hpp +++ b/apps/openmw/mwworld/class.hpp @@ -347,6 +347,9 @@ namespace MWWorld virtual std::string getPrimaryFaction (const MWWorld::Ptr& ptr) const; virtual int getPrimaryFactionRank (const MWWorld::Ptr& ptr) const; + + /// Get the effective armor rating, factoring in the actor's skills, for the given armor. + virtual int getEffectiveArmorRating(const MWWorld::Ptr& ptr, const MWWorld::Ptr& actor) const; }; } diff --git a/apps/openmw/mwworld/containerstore.cpp b/apps/openmw/mwworld/containerstore.cpp index c2906e447..d4aadc6c7 100644 --- a/apps/openmw/mwworld/containerstore.cpp +++ b/apps/openmw/mwworld/containerstore.cpp @@ -185,7 +185,7 @@ bool MWWorld::ContainerStore::stacks(const Ptr& ptr1, const Ptr& ptr2) { const ESM::Enchantment* enchantment = MWBase::Environment::get().getWorld()->getStore().get().find( ptr1.getClass().getEnchantment(ptr1)); - float maxCharge = enchantment->mData.mCharge; + float maxCharge = static_cast(enchantment->mData.mCharge); float enchantCharge1 = ptr1.getCellRef().getEnchantmentCharge() == -1 ? maxCharge : ptr1.getCellRef().getEnchantmentCharge(); float enchantCharge2 = ptr2.getCellRef().getEnchantmentCharge() == -1 ? maxCharge : ptr2.getCellRef().getEnchantmentCharge(); if (enchantCharge1 != maxCharge || enchantCharge2 != maxCharge) @@ -210,7 +210,7 @@ MWWorld::ContainerStoreIterator MWWorld::ContainerStore::add(const std::string & { MWWorld::ManualRef ref(MWBase::Environment::get().getWorld()->getStore(), id, count); // a bit pointless to set owner for the player - if (actorPtr.getRefData().getHandle() != "player") + if (actorPtr != MWBase::Environment::get().getWorld()->getPlayerPtr()) return add(ref.getPtr(), count, actorPtr, true); else return add(ref.getPtr(), count, actorPtr, false); diff --git a/apps/openmw/mwworld/esmstore.cpp b/apps/openmw/mwworld/esmstore.cpp index 36c198f01..5d9beecb6 100644 --- a/apps/openmw/mwworld/esmstore.cpp +++ b/apps/openmw/mwworld/esmstore.cpp @@ -124,7 +124,7 @@ void ESMStore::load(ESM::ESMReader &esm, Loading::Listener* listener) mIds[Misc::StringUtils::lowerCase (id)] = n.val; } } - listener->setProgress(esm.getFileOffset() / (float)esm.getFileSize() * 1000); + listener->setProgress(static_cast(esm.getFileOffset() / (float)esm.getFileSize() * 1000)); } } diff --git a/apps/openmw/mwworld/failedaction.cpp b/apps/openmw/mwworld/failedaction.cpp index 7c8ef8c7b..cf5a2a5c2 100644 --- a/apps/openmw/mwworld/failedaction.cpp +++ b/apps/openmw/mwworld/failedaction.cpp @@ -13,7 +13,7 @@ namespace MWWorld void FailedAction::executeImp(const Ptr &actor) { - if(actor.getRefData().getHandle() == "player" && !mMessage.empty()) + if(actor == MWBase::Environment::get().getWorld()->getPlayerPtr() && !mMessage.empty()) MWBase::Environment::get().getWindowManager()->messageBox(mMessage); } } diff --git a/apps/openmw/mwworld/failedaction.hpp b/apps/openmw/mwworld/failedaction.hpp index c69d62023..f248ee3bd 100644 --- a/apps/openmw/mwworld/failedaction.hpp +++ b/apps/openmw/mwworld/failedaction.hpp @@ -17,4 +17,4 @@ namespace MWWorld }; } -#endif \ No newline at end of file +#endif diff --git a/apps/openmw/mwworld/inventorystore.cpp b/apps/openmw/mwworld/inventorystore.cpp index 020f9561a..4503e66f5 100644 --- a/apps/openmw/mwworld/inventorystore.cpp +++ b/apps/openmw/mwworld/inventorystore.cpp @@ -133,7 +133,7 @@ MWWorld::ContainerStoreIterator MWWorld::InventoryStore::add(const Ptr& itemPtr, const MWWorld::ContainerStoreIterator& retVal = MWWorld::ContainerStore::add(itemPtr, count, actorPtr, setOwner); // Auto-equip items if an armor/clothing or weapon item is added, but not for the player nor werewolves - if (actorPtr.getRefData().getHandle() != "player" + if (actorPtr != MWBase::Environment::get().getWorld()->getPlayerPtr() && !(actorPtr.getClass().isNpc() && actorPtr.getClass().getNpcStats(actorPtr).isWerewolf())) { std::string type = itemPtr.getTypeName(); @@ -364,7 +364,7 @@ void MWWorld::InventoryStore::updateMagicEffects(const Ptr& actor) // Roll some dice, one for each effect params.resize(enchantment.mEffects.mList.size()); for (unsigned int i=0; i (std::rand()) / RAND_MAX; + params[i].mRandom = OEngine::Misc::Rng::rollClosedProbability(); // Try resisting each effect int i=0; @@ -503,7 +503,7 @@ int MWWorld::InventoryStore::remove(const Ptr& item, int count, const Ptr& actor // If an armor/clothing item is removed, try to find a replacement, // but not for the player nor werewolves. - if ((actor.getRefData().getHandle() != "player") + if ((actor != MWBase::Environment::get().getWorld()->getPlayerPtr()) && !(actor.getClass().isNpc() && actor.getClass().getNpcStats(actor).isWerewolf())) { std::string type = item.getTypeName(); @@ -535,7 +535,7 @@ MWWorld::ContainerStoreIterator MWWorld::InventoryStore::unequipSlot(int slot, c { retval = restack(*it); - if (actor.getRefData().getHandle() == "player") + if (actor == MWBase::Environment::get().getWorld()->getPlayerPtr()) { // Unset OnPCEquip Variable on item's script, if it has a script with that variable declared const std::string& script = it->getClass().getScript(*it); @@ -630,7 +630,7 @@ void MWWorld::InventoryStore::updateRechargingItems() it->getClass().getEnchantment(*it)); if (enchantment->mData.mType == ESM::Enchantment::WhenUsed || enchantment->mData.mType == ESM::Enchantment::WhenStrikes) - mRechargingItems.push_back(std::make_pair(it, enchantment->mData.mCharge)); + mRechargingItems.push_back(std::make_pair(it, static_cast(enchantment->mData.mCharge))); } } } diff --git a/apps/openmw/mwworld/localscripts.hpp b/apps/openmw/mwworld/localscripts.hpp index 840243fff..9d612cb33 100644 --- a/apps/openmw/mwworld/localscripts.hpp +++ b/apps/openmw/mwworld/localscripts.hpp @@ -8,7 +8,7 @@ namespace MWWorld { - struct ESMStore; + class ESMStore; class CellStore; class RefData; diff --git a/apps/openmw/mwworld/manualref.cpp b/apps/openmw/mwworld/manualref.cpp index 30b4fe353..b926c5799 100644 --- a/apps/openmw/mwworld/manualref.cpp +++ b/apps/openmw/mwworld/manualref.cpp @@ -64,4 +64,4 @@ MWWorld::ManualRef::ManualRef(const MWWorld::ESMStore& store, const std::string& } mPtr.getRefData().setCount(count); -} \ No newline at end of file +} diff --git a/apps/openmw/mwworld/player.cpp b/apps/openmw/mwworld/player.cpp index 8f3560a69..58718074e 100644 --- a/apps/openmw/mwworld/player.cpp +++ b/apps/openmw/mwworld/player.cpp @@ -97,13 +97,13 @@ namespace MWWorld if (mAutoMove) value = 1; - ptr.getClass().getMovementSettings (ptr).mPosition[1] = value; + ptr.getClass().getMovementSettings(ptr).mPosition[1] = static_cast(value); } void Player::setLeftRight (int value) { MWWorld::Ptr ptr = getPlayer(); - ptr.getClass().getMovementSettings (ptr).mPosition[0] = value; + ptr.getClass().getMovementSettings(ptr).mPosition[0] = static_cast(value); } void Player::setForwardBackward (int value) @@ -115,13 +115,13 @@ namespace MWWorld if (mAutoMove) value = 1; - ptr.getClass().getMovementSettings (ptr).mPosition[1] = value; + ptr.getClass().getMovementSettings(ptr).mPosition[1] = static_cast(value); } void Player::setUpDown(int value) { MWWorld::Ptr ptr = getPlayer(); - ptr.getClass().getMovementSettings (ptr).mPosition[2] = value; + ptr.getClass().getMovementSettings(ptr).mPosition[2] = static_cast(value); } void Player::setRunState(bool run) diff --git a/apps/openmw/mwworld/projectilemanager.cpp b/apps/openmw/mwworld/projectilemanager.cpp index c97e4e3a5..acbe819f1 100644 --- a/apps/openmw/mwworld/projectilemanager.cpp +++ b/apps/openmw/mwworld/projectilemanager.cpp @@ -68,7 +68,7 @@ namespace MWWorld { float height = 0; if (OEngine::Physic::PhysicActor* actor = mPhysEngine.getCharacter(caster.getRefData().getHandle())) - height = actor->getHalfExtents().z * 2 * 0.75; // Spawn at 0.75 * ActorHeight + height = actor->getHalfExtents().z * 2 * 0.75f; // Spawn at 0.75 * ActorHeight Ogre::Vector3 pos(caster.getRefData().getPosition().pos); pos.z += height; diff --git a/apps/openmw/mwworld/ptr.hpp b/apps/openmw/mwworld/ptr.hpp index 4d928dacf..c97d2e6d1 100644 --- a/apps/openmw/mwworld/ptr.hpp +++ b/apps/openmw/mwworld/ptr.hpp @@ -12,7 +12,7 @@ namespace MWWorld { class ContainerStore; class CellStore; - class LiveCellRefBase; + struct LiveCellRefBase; /// \brief Pointer to a LiveCellRef diff --git a/apps/openmw/mwworld/refdata.cpp b/apps/openmw/mwworld/refdata.cpp index c2a5e5f83..14a315a81 100644 --- a/apps/openmw/mwworld/refdata.cpp +++ b/apps/openmw/mwworld/refdata.cpp @@ -59,7 +59,7 @@ namespace MWWorld } RefData::RefData (const ESM::ObjectState& objectState) - : mBaseNode (0), mHasLocals (false), mEnabled (objectState.mEnabled), + : mBaseNode (0), mHasLocals (false), mEnabled (objectState.mEnabled != 0), mCount (objectState.mCount), mPosition (objectState.mPosition), mCustomData (0), mChanged(true), // Loading from a savegame -> assume changed mDeleted(false) diff --git a/apps/openmw/mwworld/refdata.hpp b/apps/openmw/mwworld/refdata.hpp index da7986ba0..e90b44f9c 100644 --- a/apps/openmw/mwworld/refdata.hpp +++ b/apps/openmw/mwworld/refdata.hpp @@ -33,11 +33,11 @@ namespace MWWorld MWScript::Locals mLocals; // if we find the overhead of heaving a locals // object in the refdata of refs without a script, // we can make this a pointer later. + bool mDeleted; // separate delete flag used for deletion by a content file bool mHasLocals; bool mEnabled; int mCount; // 0: deleted - bool mDeleted; // separate delete flag used for deletion by a content file ESM::Position mPosition; diff --git a/apps/openmw/mwworld/scene.cpp b/apps/openmw/mwworld/scene.cpp index 72d475f16..8d689240b 100644 --- a/apps/openmw/mwworld/scene.cpp +++ b/apps/openmw/mwworld/scene.cpp @@ -199,7 +199,7 @@ namespace MWWorld (*iter)->getCell()->getGridX(), (*iter)->getCell()->getGridY() ); - if (land) + if (land && land->mDataTypes&ESM::Land::DATA_VHGT) mPhysics->removeHeightField ((*iter)->getCell()->getGridX(), (*iter)->getCell()->getGridY()); } @@ -219,6 +219,8 @@ namespace MWWorld if(result.second) { + std::cout << "loading cell " << cell->getCell()->getDescription() << std::endl; + float verts = ESM::Land::LAND_SIZE; float worldsize = ESM::Land::REAL_SIZE; @@ -230,7 +232,7 @@ namespace MWWorld cell->getCell()->getGridX(), cell->getCell()->getGridY() ); - if (land) { + if (land && land->mDataTypes&ESM::Land::DATA_VHGT) { // Actually only VHGT is needed here, but we'll need the rest for rendering anyway. // Load everything now to reduce IO overhead. const int flags = ESM::Land::DATA_VCLR|ESM::Land::DATA_VHGT|ESM::Land::DATA_VNML|ESM::Land::DATA_VTEX; @@ -490,8 +492,6 @@ namespace MWWorld loadingListener->setProgressRange(refsToLoad); // Load cell. - std::cout << "cellName: " << cell->getCell()->mName << std::endl; - loadCell (cell, loadingListener); changePlayerCell(cell, position, true); diff --git a/apps/openmw/mwworld/store.hpp b/apps/openmw/mwworld/store.hpp index a155a3760..d6aeeb51e 100644 --- a/apps/openmw/mwworld/store.hpp +++ b/apps/openmw/mwworld/store.hpp @@ -7,6 +7,8 @@ #include #include +#include + #include #include @@ -29,7 +31,7 @@ namespace MWWorld virtual bool eraseStatic(const std::string &id) {return false;} virtual void clearDynamic() {} - virtual void write (ESM::ESMWriter& writer) const {} + virtual void write (ESM::ESMWriter& writer, Loading::Listener& progress) const {} virtual void read (ESM::ESMReader& reader, const std::string& id) {} ///< Read into dynamic storage @@ -178,7 +180,7 @@ namespace MWWorld std::vector results; std::for_each(mShared.begin(), mShared.end(), GetRecords(id, &results)); if(!results.empty()) - return results[int(std::rand()/((double)RAND_MAX+1)*results.size())]; + return results[OEngine::Misc::Rng::rollDice(results.size())]; return NULL; } @@ -234,7 +236,7 @@ namespace MWWorld int getDynamicSize() const { - return mDynamic.size(); + return static_cast (mDynamic.size()); // truncated from unsigned __int64 if _MSC_VER && _WIN64 } void listIdentifier(std::vector &list) const { @@ -364,19 +366,6 @@ namespace MWWorld inserted.first->second = scpt; } - template <> - inline void Store::load(ESM::ESMReader &esm, const std::string &id) { - ESM::StartScript s; - s.load(esm); - s.mId = Misc::StringUtils::toLower(s.mScript); - - std::pair inserted = mStatic.insert(std::make_pair(s.mId, s)); - if (inserted.second) - mShared.push_back(&inserted.first->second); - else - inserted.first->second = s; - } - template <> class Store : public StoreBase { @@ -555,6 +544,9 @@ namespace MWWorld if (left.first == right.first) return left.second > right.second; + // Exterior cells are listed in descending, row-major order, + // this is a workaround for an ambiguous chargen_plank reference in the vanilla game. + // there is one at -22,16 and one at -2,-9, the latter should be used. return left.first > right.first; } }; diff --git a/apps/openmw/mwworld/timestamp.cpp b/apps/openmw/mwworld/timestamp.cpp index a73ed7ca5..bd07b91f3 100644 --- a/apps/openmw/mwworld/timestamp.cpp +++ b/apps/openmw/mwworld/timestamp.cpp @@ -33,7 +33,7 @@ namespace MWWorld mHour = static_cast (std::fmod (hours, 24)); - mDay += hours / 24; + mDay += static_cast(hours / 24); return *this; } diff --git a/apps/openmw/mwworld/timestamp.hpp b/apps/openmw/mwworld/timestamp.hpp index 54cd40baf..36d11cee0 100644 --- a/apps/openmw/mwworld/timestamp.hpp +++ b/apps/openmw/mwworld/timestamp.hpp @@ -3,7 +3,7 @@ namespace ESM { - class TimeStamp; + struct TimeStamp; } namespace MWWorld diff --git a/apps/openmw/mwworld/weather.cpp b/apps/openmw/mwworld/weather.cpp index 4440ed030..a9ca8e72b 100644 --- a/apps/openmw/mwworld/weather.cpp +++ b/apps/openmw/mwworld/weather.cpp @@ -3,6 +3,8 @@ #include "weather.hpp" +#include + #include #include "../mwbase/environment.hpp" @@ -142,7 +144,7 @@ WeatherManager::WeatherManager(MWRender::RenderingManager* rendering,MWWorld::Fa * These values are fallbacks attached to weather. */ mNightStart = mSunsetTime + mSunsetDuration; - mNightEnd = mSunriseTime - 0.5; + mNightEnd = mSunriseTime - 0.5f; mDayStart = mSunriseTime + mSunriseDuration; mDayEnd = mSunsetTime; @@ -368,7 +370,7 @@ void WeatherManager::transition(float factor) mResult.mParticleEffect = other.mParticleEffect; mResult.mRainSpeed = other.mRainSpeed; mResult.mRainFrequency = other.mRainFrequency; - mResult.mAmbientSoundVolume = 2*(factor-0.5); + mResult.mAmbientSoundVolume = 2*(factor-0.5f); mResult.mEffectFade = mResult.mAmbientSoundVolume; mResult.mAmbientLoopSoundID = other.mAmbientLoopSoundID; } @@ -376,7 +378,7 @@ void WeatherManager::transition(float factor) void WeatherManager::update(float duration, bool paused) { - float timePassed = mTimePassed; + float timePassed = static_cast(mTimePassed); mTimePassed = 0; mWeatherUpdateTime -= timePassed; @@ -454,9 +456,9 @@ void WeatherManager::update(float duration, bool paused) } Vector3 final( - cos( theta ), + static_cast(cos(theta)), -0.268f, // approx tan( -15 degrees ) - sin( theta ) ); + static_cast(sin(theta))); mRendering->setSunDirection( final, is_night ); } @@ -488,8 +490,8 @@ void WeatherManager::update(float duration, bool paused) moonHeight); Vector3 secunda( - (moonHeight - 1) * facing * 1.25, - (1 - moonHeight) * facing * 0.8, + (moonHeight - 1) * facing * 1.25f, + (1 - moonHeight) * facing * 0.8f, moonHeight); mRendering->getSkyManager()->setMasserDirection(masser); @@ -526,7 +528,7 @@ void WeatherManager::update(float duration, bool paused) if (mThunderSoundDelay <= 0) { // pick a random sound - int sound = rand() % 4; + int sound = OEngine::Misc::Rng::rollDice(4); std::string* soundName = NULL; if (sound == 0) soundName = &mThunderSoundID0; else if (sound == 1) soundName = &mThunderSoundID1; @@ -542,7 +544,7 @@ void WeatherManager::update(float duration, bool paused) mRendering->getSkyManager()->setLightningStrength( mThunderFlash / mThunderThreshold ); else { - mThunderChanceNeeded = rand() % 100; + mThunderChanceNeeded = static_cast(OEngine::Misc::Rng::rollDice(100)); mThunderChance = 0; mRendering->getSkyManager()->setLightningStrength( 0.f ); } @@ -624,7 +626,7 @@ std::string WeatherManager::nextWeather(const ESM::Region* region) const * 70% will be greater than 30 (in theory). */ - int chance = (rand() % 100) + 1; // 1..100 + int chance = OEngine::Misc::Rng::rollDice(100) + 1; // 1..100 int sum = 0; unsigned int i = 0; for (; i < probability.size(); ++i) diff --git a/apps/openmw/mwworld/worldimp.cpp b/apps/openmw/mwworld/worldimp.cpp index 188f3cdad..013386f8f 100644 --- a/apps/openmw/mwworld/worldimp.cpp +++ b/apps/openmw/mwworld/worldimp.cpp @@ -14,6 +14,8 @@ #include #include +#include + #include #include #include @@ -423,6 +425,19 @@ namespace MWWorld globals["werewolfclawmult"] = ESM::Variant(25.f); globals["pcknownwerewolf"] = ESM::Variant(0); + // following should exist in all versions of MW, but not necessarily in TCs + globals["gamehour"] = ESM::Variant(0.f); + globals["timescale"] = ESM::Variant(30.f); + globals["day"] = ESM::Variant(1); + globals["month"] = ESM::Variant(1); + globals["year"] = ESM::Variant(1); + globals["pcrace"] = ESM::Variant(0); + globals["pchascrimegold"] = ESM::Variant(0); + globals["pchasgolddiscount"] = ESM::Variant(0); + globals["crimegolddiscount"] = ESM::Variant(0); + globals["crimegoldturnin"] = ESM::Variant(0); + globals["pchasturnin"] = ESM::Variant(0); + for (std::map::iterator it = gmst.begin(); it != gmst.end(); ++it) { if (!mStore.get().search(it->first)) @@ -557,9 +572,9 @@ namespace MWWorld if (name=="gamehour") setHour (value); else if (name=="day") - setDay (value); + setDay(static_cast(value)); else if (name=="month") - setMonth (value); + setMonth(static_cast(value)); else mGlobalVariables[name].setFloat (value); } @@ -787,7 +802,7 @@ namespace MWWorld void World::advanceTime (double hours) { - MWBase::Environment::get().getMechanicsManager()->advanceTime(hours*3600); + MWBase::Environment::get().getMechanicsManager()->advanceTime(static_cast(hours * 3600)); mWeatherManager->advanceTime (hours); @@ -795,7 +810,7 @@ namespace MWWorld setHour (hours); - int days = hours / 24; + int days = static_cast(hours / 24); if (days>0) mGlobalVariables["dayspassed"].setInteger ( @@ -807,15 +822,15 @@ namespace MWWorld if (hour<0) hour = 0; - int days = hour / 24; + int days = static_cast(hour / 24); hour = std::fmod (hour, 24); - mGlobalVariables["gamehour"].setFloat (hour); + mGlobalVariables["gamehour"].setFloat(static_cast(hour)); mRendering->skySetHour (hour); - mWeatherManager->setHour (hour); + mWeatherManager->setHour(static_cast(hour)); if (days>0) setDay (days + mGlobalVariables["day"].getInteger()); @@ -1002,25 +1017,9 @@ namespace MWWorld float World::getMaxActivationDistance () { if (mActivationDistanceOverride >= 0) - return mActivationDistanceOverride; + return static_cast(mActivationDistanceOverride); - return (std::max) (getNpcActivationDistance (), getObjectActivationDistance ()); - } - - float World::getNpcActivationDistance () - { - if (mActivationDistanceOverride >= 0) - return mActivationDistanceOverride; - - return getStore().get().find ("iMaxActivateDist")->getInt()*5/4; - } - - float World::getObjectActivationDistance () - { - if (mActivationDistanceOverride >= 0) - return mActivationDistanceOverride; - - return getStore().get().find ("iMaxActivateDist")->getInt(); + return getStore().get().find("iMaxActivateDist")->getFloat() * 5 / 4; } MWWorld::Ptr World::getFacedObject() @@ -1349,7 +1348,7 @@ namespace MWWorld pos.pos[2] += dist; actor.getRefData().setPosition(pos); - Ogre::Vector3 traced = mPhysics->traceDown(actor, dist*1.1); + Ogre::Vector3 traced = mPhysics->traceDown(actor, dist*1.1f); moveObject(actor, actor.getCell(), traced.x, traced.y, traced.z); } @@ -1370,8 +1369,8 @@ namespace MWWorld { const int cellSize = 8192; - x = cellSize * cellX; - y = cellSize * cellY; + x = static_cast(cellSize * cellX); + y = static_cast(cellSize * cellY); if (centre) { @@ -1384,8 +1383,8 @@ namespace MWWorld { const int cellSize = 8192; - cellX = std::floor(x/cellSize); - cellY = std::floor(y/cellSize); + cellX = static_cast(std::floor(x / cellSize)); + cellY = static_cast(std::floor(y / cellSize)); } void World::queueMovement(const Ptr &ptr, const Vector3 &velocity) @@ -1405,7 +1404,7 @@ namespace MWWorld PtrVelocityList::const_iterator player(results.end()); for(PtrVelocityList::const_iterator iter(results.begin());iter != results.end();++iter) { - if(iter->first.getRefData().getHandle() == "player") + if(iter->first == getPlayerPtr()) { /* Handle player last, in case a cell transition occurs */ player = iter; @@ -1604,7 +1603,7 @@ namespace MWWorld { Ogre::Vector3 playerPos = mPlayer->getPlayer().getRefData().getBaseNode()->getPosition(); const OEngine::Physic::PhysicActor *actor = mPhysEngine->getCharacter(getPlayerPtr().getRefData().getHandle()); - if(actor) playerPos.z += 1.85*actor->getHalfExtents().z; + if(actor) playerPos.z += 1.85f * actor->getHalfExtents().z; Ogre::Quaternion playerOrient = Ogre::Quaternion(Ogre::Radian(getPlayerPtr().getRefData().getPosition().rot[2]), Ogre::Vector3::NEGATIVE_UNIT_Z) * Ogre::Quaternion(Ogre::Radian(getPlayerPtr().getRefData().getPosition().rot[0]), Ogre::Vector3::NEGATIVE_UNIT_X) * Ogre::Quaternion(Ogre::Radian(getPlayerPtr().getRefData().getPosition().rot[1]), Ogre::Vector3::NEGATIVE_UNIT_Y); @@ -1996,7 +1995,7 @@ namespace MWWorld bool World::isSubmerged(const MWWorld::Ptr &object) const { - return isUnderwater(object, 1.0/mSwimHeightScale); + return isUnderwater(object, 1.0f/mSwimHeightScale); } bool World::isSwimming(const MWWorld::Ptr &object) const @@ -2227,7 +2226,7 @@ namespace MWWorld if (healthPerSecond > 0.0f) { - if (actor.getRefData().getHandle() == "player") + if (actor == getPlayerPtr()) MWBase::Environment::get().getWindowManager()->activateHitOverlay(false); if (!MWBase::Environment::get().getSoundManager()->getSoundPlaying(actor, "Health Damage")) @@ -2258,7 +2257,7 @@ namespace MWWorld if (healthPerSecond > 0.0f) { - if (actor.getRefData().getHandle() == "player") + if (actor == getPlayerPtr()) MWBase::Environment::get().getWindowManager()->activateHitOverlay(false); if (!MWBase::Environment::get().getSoundManager()->getSoundPlaying(actor, "Health Damage")) @@ -2354,8 +2353,8 @@ namespace MWWorld Ogre::Vector3 halfExt2 = actor2->getHalfExtents(); const float* pos2 = targetActor.getRefData().getPosition().pos; - btVector3 from(pos1[0],pos1[1],pos1[2]+halfExt1.z*2*0.9); // eye level - btVector3 to(pos2[0],pos2[1],pos2[2]+halfExt2.z*2*0.9); + btVector3 from(pos1[0],pos1[1],pos1[2]+halfExt1.z*2*0.9f); // eye level + btVector3 to(pos2[0],pos2[1],pos2[2]+halfExt2.z*2*0.9f); std::pair result = mPhysEngine->rayTest(from, to,false); if(result.first == "") return true; @@ -2515,7 +2514,7 @@ namespace MWWorld // the following is just for reattaching the camera properly. mRendering->rebuildPtr(actor); - if(actor.getRefData().getHandle() == "player") + if(actor == getPlayerPtr()) { // Update the GUI only when called on the player MWBase::WindowManager* windowManager = MWBase::Environment::get().getWindowManager(); @@ -2574,7 +2573,7 @@ namespace MWWorld const Store &gmst = getStore().get(); MWMechanics::NpcStats &stats = actor.getClass().getNpcStats(actor); - stats.getSkill(ESM::Skill::Acrobatics).setBase(gmst.find("fWerewolfAcrobatics")->getFloat()); + stats.getSkill(ESM::Skill::Acrobatics).setBase(gmst.find("fWerewolfAcrobatics")->getInt()); } bool World::getGodModeState() @@ -2784,18 +2783,45 @@ namespace MWWorld { if (cell->isExterior()) return false; - MWWorld::CellRefList& doors = cell->get(); - CellRefList::List& refList = doors.mList; - // Check if any door in the cell leads to an exterior directly - for (CellRefList::List::iterator it = refList.begin(); it != refList.end(); ++it) - { - MWWorld::LiveCellRef& ref = *it; - if (ref.mRef.getTeleport() && ref.mRef.getDestCell().empty()) - { - ESM::Position pos = ref.mRef.getDoorDest(); - result = Ogre::Vector3(pos.pos); - return true; + // Search for a 'nearest' exterior, counting each cell between the starting + // cell and the exterior as a distance of 1. Will fail for isolated interiors. + std::set< std::string >checkedCells; + std::set< std::string >currentCells; + std::set< std::string >nextCells; + nextCells.insert( cell->getCell()->mName ); + + while ( !nextCells.empty() ) { + currentCells = nextCells; + nextCells.clear(); + for( std::set< std::string >::const_iterator i = currentCells.begin(); i != currentCells.end(); ++i ) { + MWWorld::CellStore *next = getInterior( *i ); + if ( !next ) continue; + + const MWWorld::CellRefList& doors = next->getReadOnly(); + const CellRefList::List& refList = doors.mList; + + // Check if any door in the cell leads to an exterior directly + for (CellRefList::List::const_iterator it = refList.begin(); it != refList.end(); ++it) + { + const MWWorld::LiveCellRef& ref = *it; + if (!ref.mRef.getTeleport()) continue; + + if (ref.mRef.getDestCell().empty()) + { + ESM::Position pos = ref.mRef.getDoorDest(); + result = Ogre::Vector3(pos.pos); + return true; + } + else + { + std::string dest = ref.mRef.getDestCell(); + if ( !checkedCells.count(dest) && !currentCells.count(dest) ) + nextCells.insert(dest); + } + } + + checkedCells.insert( *i ); } } @@ -2803,33 +2829,102 @@ namespace MWWorld return false; } - void World::teleportToClosestMarker (const MWWorld::Ptr& ptr, - const std::string& id) + MWWorld::Ptr World::getClosestMarker( const MWWorld::Ptr &ptr, const std::string &id ) { - Ogre::Vector3 worldPos; - if (!findInteriorPositionInWorldSpace(ptr.getCell(), worldPos)) - worldPos = mPlayer->getLastKnownExteriorPosition(); + if ( ptr.getCell()->isExterior() ) { + return getClosestMarkerFromExteriorPosition(mPlayer->getLastKnownExteriorPosition(), id); + } + // Search for a 'nearest' marker, counting each cell between the starting + // cell and the exterior as a distance of 1. If an exterior is found, jump + // to the nearest exterior marker, without further interior searching. + std::set< std::string >checkedCells; + std::set< std::string >currentCells; + std::set< std::string >nextCells; + MWWorld::Ptr closestMarker; + + nextCells.insert( ptr.getCell()->getCell()->mName ); + while ( !nextCells.empty() ) { + currentCells = nextCells; + nextCells.clear(); + for( std::set< std::string >::const_iterator i = currentCells.begin(); i != currentCells.end(); ++i ) { + MWWorld::CellStore *next = getInterior( *i ); + checkedCells.insert( *i ); + if ( !next ) continue; + + closestMarker = next->search( id ); + if ( !closestMarker.isEmpty() ) + { + return closestMarker; + } + + const MWWorld::CellRefList& doors = next->getReadOnly(); + const CellRefList::List& doorList = doors.mList; + + // Check if any door in the cell leads to an exterior directly + for (CellRefList::List::const_iterator it = doorList.begin(); it != doorList.end(); ++it) + { + const MWWorld::LiveCellRef& ref = *it; + + if (!ref.mRef.getTeleport()) continue; + + if (ref.mRef.getDestCell().empty()) + { + Ogre::Vector3 worldPos = Ogre::Vector3(ref.mRef.getDoorDest().pos); + return getClosestMarkerFromExteriorPosition(worldPos, id); + } + else + { + std::string dest = ref.mRef.getDestCell(); + if ( !checkedCells.count(dest) && !currentCells.count(dest) ) + nextCells.insert(dest); + } + } + } + } + + return MWWorld::Ptr(); + } + + MWWorld::Ptr World::getClosestMarkerFromExteriorPosition( const Ogre::Vector3 worldPos, const std::string &id ) { MWWorld::Ptr closestMarker; float closestDistance = FLT_MAX; std::vector markers; mCells.getExteriorPtrs(id, markers); - - for (std::vector::iterator it = markers.begin(); it != markers.end(); ++it) + for (std::vector::iterator it2 = markers.begin(); it2 != markers.end(); ++it2) { - ESM::Position pos = it->getRefData().getPosition(); + ESM::Position pos = it2->getRefData().getPosition(); Ogre::Vector3 markerPos = Ogre::Vector3(pos.pos); float distance = worldPos.squaredDistance(markerPos); if (distance < closestDistance) { closestDistance = distance; - closestMarker = *it; + closestMarker = *it2; } } - MWWorld::ActionTeleport action("", closestMarker.getRefData().getPosition()); + return closestMarker; + } + + + void World::teleportToClosestMarker (const MWWorld::Ptr& ptr, + const std::string& id) + { + MWWorld::Ptr closestMarker = getClosestMarker( ptr, id ); + + if ( closestMarker.isEmpty() ) + { + std::cerr << "Failed to teleport: no closest marker found" << std::endl; + return; + } + + std::string cellName; + if ( !closestMarker.mCell->isExterior() ) + cellName = closestMarker.mCell->getCell()->mName; + + MWWorld::ActionTeleport action(cellName, closestMarker.getRefData().getPosition()); action.execute(ptr); } @@ -2958,8 +3053,8 @@ namespace MWWorld float fCrimeGoldDiscountMult = getStore().get().find("fCrimeGoldDiscountMult")->getFloat(); float fCrimeGoldTurnInMult = getStore().get().find("fCrimeGoldTurnInMult")->getFloat(); - int discount = bounty * fCrimeGoldDiscountMult; - int turnIn = bounty * fCrimeGoldTurnInMult; + int discount = static_cast(bounty * fCrimeGoldDiscountMult); + int turnIn = static_cast(bounty * fCrimeGoldTurnInMult); if (bounty > 0) { @@ -2978,31 +3073,26 @@ namespace MWWorld void World::confiscateStolenItems(const Ptr &ptr) { - Ogre::Vector3 playerPos; - if (!findInteriorPositionInWorldSpace(ptr.getCell(), playerPos)) - playerPos = mPlayer->getLastKnownExteriorPosition(); - - MWWorld::Ptr closestChest; - float closestDistance = FLT_MAX; - - //Find closest stolen_goods chest - std::vector chests; - mCells.getInteriorPtrs("stolen_goods", chests); - - Ogre::Vector3 chestPos; - for (std::vector::iterator it = chests.begin(); it != chests.end(); ++it) + MWWorld::Ptr prisonMarker = getClosestMarker( ptr, "prisonmarker" ); + if ( prisonMarker.isEmpty() ) { - if (!findInteriorPositionInWorldSpace(it->getCell(), chestPos)) - continue; - - float distance = playerPos.squaredDistance(chestPos); - if (distance < closestDistance) - { - closestDistance = distance; - closestChest = *it; - } + std::cerr << "Failed to confiscate items: no closest prison marker found." << std::endl; + return; + } + std::string prisonName = prisonMarker.mRef->mRef.getDestCell(); + if ( prisonName.empty() ) + { + std::cerr << "Failed to confiscate items: prison marker not linked to prison interior" << std::endl; + return; + } + MWWorld::CellStore *prison = getInterior( prisonName ); + if ( !prison ) + { + std::cerr << "Failed to confiscate items: failed to load cell " << prisonName << std::endl; + return; } + MWWorld::Ptr closestChest = prison->search( "stolen_goods" ); if (!closestChest.isEmpty()) //Found a close chest { MWBase::Environment::get().getMechanicsManager()->confiscateStolenItems(ptr, closestChest); @@ -3045,7 +3135,7 @@ namespace MWWorld const ESM::CreatureLevList* list = getStore().get().find(creatureList); int iNumberCreatures = getStore().get().find("iNumberCreatures")->getInt(); - int numCreatures = 1 + std::rand()/ (static_cast (RAND_MAX) + 1) * iNumberCreatures; // [1, iNumberCreatures] + int numCreatures = 1 + OEngine::Misc::Rng::rollDice(iNumberCreatures); // [1, iNumberCreatures] for (int i=0; i (RAND_MAX) + 1) * 3; // [0, 2] + int roll = OEngine::Misc::Rng::rollDice(3); // [0, 2] modelName << roll; std::string model = "meshes\\" + getFallback()->getFallbackString(modelName.str()); @@ -3108,7 +3198,7 @@ namespace MWWorld mRendering->spawnEffect(model, textureOverride, worldPos); } - void World::explodeSpell(const Vector3 &origin, const ESM::EffectList &effects, const Ptr &caster, int rangeType, + void World::explodeSpell(const Vector3 &origin, const ESM::EffectList &effects, const Ptr &caster, ESM::RangeType rangeType, const std::string& id, const std::string& sourceName) { std::map > toApply; @@ -3127,7 +3217,7 @@ namespace MWWorld else areaStatic = getStore().get().find ("VFX_DefaultArea"); - mRendering->spawnEffect("meshes\\" + areaStatic->mModel, "", origin, effectIt->mArea); + mRendering->spawnEffect("meshes\\" + areaStatic->mModel, "", origin, static_cast(effectIt->mArea)); // Play explosion sound (make sure to use NoTrack, since we will delete the projectile now) static const std::string schools[] = { @@ -3143,7 +3233,7 @@ namespace MWWorld // Get the actors in range of the effect std::vector objects; MWBase::Environment::get().getMechanicsManager()->getObjectsInRange( - origin, feetToGameUnits(effectIt->mArea), objects); + origin, feetToGameUnits(static_cast(effectIt->mArea)), objects); for (std::vector::iterator affected = objects.begin(); affected != objects.end(); ++affected) toApply[*affected].push_back(*effectIt); } @@ -3167,7 +3257,7 @@ namespace MWWorld cast.mStack = false; ESM::EffectList effects; effects.mList = apply->second; - cast.inflict(apply->first, caster, effects, (ESM::RangeType)rangeType, false, true); + cast.inflict(apply->first, caster, effects, rangeType, false, true); } } diff --git a/apps/openmw/mwworld/worldimp.hpp b/apps/openmw/mwworld/worldimp.hpp index 9980f6f90..63d6506de 100644 --- a/apps/openmw/mwworld/worldimp.hpp +++ b/apps/openmw/mwworld/worldimp.hpp @@ -115,10 +115,6 @@ namespace MWWorld void performUpdateSceneQueries (); void getFacedHandle(std::string& facedHandle, float maxDistance, bool ignorePlayer=true); - float getMaxActivationDistance (); - float getNpcActivationDistance (); - float getObjectActivationDistance (); - void removeContainerScripts(const Ptr& reference); void addContainerScripts(const Ptr& reference, CellStore* cell); void PCDropped (const Ptr& item); @@ -151,6 +147,9 @@ namespace MWWorld float feetToGameUnits(float feet); + MWWorld::Ptr getClosestMarker( const MWWorld::Ptr &ptr, const std::string &id ); + MWWorld::Ptr getClosestMarkerFromExteriorPosition( const Ogre::Vector3 worldPos, const std::string &id ); + public: World (OEngine::Render::OgreRenderer& renderer, @@ -363,6 +362,8 @@ namespace MWWorld virtual MWWorld::Ptr safePlaceObject(const MWWorld::Ptr& ptr, MWWorld::CellStore* cell, ESM::Position pos); ///< place an object in a "safe" location (ie not in the void, etc). Makes a copy of the Ptr. + virtual float getMaxActivationDistance(); + virtual void indexToPosition (int cellX, int cellY, float &x, float &y, bool centre = false) const; ///< Convert cell numbers to position. @@ -633,7 +634,7 @@ namespace MWWorld virtual void spawnEffect (const std::string& model, const std::string& textureOverride, const Ogre::Vector3& worldPos); virtual void explodeSpell (const Ogre::Vector3& origin, const ESM::EffectList& effects, - const MWWorld::Ptr& caster, int rangeType, const std::string& id, const std::string& sourceName); + const MWWorld::Ptr& caster, ESM::RangeType rangeType, const std::string& id, const std::string& sourceName); virtual void activate (const MWWorld::Ptr& object, const MWWorld::Ptr& actor); diff --git a/apps/wizard/componentselectionpage.cpp b/apps/wizard/componentselectionpage.cpp index 1fcde7857..21a5c58d9 100644 --- a/apps/wizard/componentselectionpage.cpp +++ b/apps/wizard/componentselectionpage.cpp @@ -156,9 +156,13 @@ bool Wizard::ComponentSelectionPage::validatePage() int Wizard::ComponentSelectionPage::nextId() const { +#ifdef OPENMW_USE_UNSHIELD if (isCommitPage()) { return MainWizard::Page_Installation; } else { return MainWizard::Page_Import; } +#else + return MainWizard::Page_Import; +#endif } diff --git a/apps/wizard/existinginstallationpage.cpp b/apps/wizard/existinginstallationpage.cpp index 83ea20f5a..f821b38ba 100644 --- a/apps/wizard/existinginstallationpage.cpp +++ b/apps/wizard/existinginstallationpage.cpp @@ -29,11 +29,7 @@ void Wizard::ExistingInstallationPage::initializePage() QStringList paths(mWizard->mInstallations.keys()); // Hide the default item if there are installations to choose from - if (paths.isEmpty()) { - installationsList->item(0)->setHidden(false); - } else { - installationsList->item(0)->setHidden(true); - } + installationsList->item(0)->setHidden(!paths.isEmpty()); foreach (const QString &path, paths) { QListWidgetItem *item = new QListWidgetItem(path); diff --git a/apps/wizard/mainwizard.cpp b/apps/wizard/mainwizard.cpp index a1370b125..a61daa5a4 100644 --- a/apps/wizard/mainwizard.cpp +++ b/apps/wizard/mainwizard.cpp @@ -62,6 +62,12 @@ Wizard::MainWizard::MainWizard(QWidget *parent) : setupLauncherSettings(); setupInstallations(); setupPages(); + + const boost::filesystem::path& installedPath = mCfgMgr.getInstallPath(); + if (!installedPath.empty()) + { + addInstallation(toQString(installedPath)); + } } Wizard::MainWizard::~MainWizard() @@ -71,7 +77,7 @@ Wizard::MainWizard::~MainWizard() void Wizard::MainWizard::setupLog() { - QString logPath(QString::fromUtf8(mCfgMgr.getLogPath().string().c_str())); + QString logPath(toQString(mCfgMgr.getLogPath())); logPath.append(QLatin1String("wizard.log")); QFile file(logPath); @@ -93,7 +99,7 @@ void Wizard::MainWizard::setupLog() void Wizard::MainWizard::addLogText(const QString &text) { - QString logPath(QString::fromUtf8(mCfgMgr.getLogPath().string().c_str())); + QString logPath(toQString(mCfgMgr.getLogPath())); logPath.append(QLatin1String("wizard.log")); QFile file(logPath); @@ -121,8 +127,8 @@ void Wizard::MainWizard::addLogText(const QString &text) void Wizard::MainWizard::setupGameSettings() { - QString userPath(QString::fromUtf8(mCfgMgr.getUserConfigPath().string().c_str())); - QString globalPath(QString::fromUtf8(mCfgMgr.getGlobalPath().string().c_str())); + QString userPath(toQString(mCfgMgr.getUserConfigPath())); + QString globalPath(toQString(mCfgMgr.getGlobalPath())); QString message(tr("

Could not open %1 for reading

\

Please make sure you have the right permissions \ and try again.

")); @@ -181,7 +187,7 @@ void Wizard::MainWizard::setupGameSettings() void Wizard::MainWizard::setupLauncherSettings() { - QString path(QString::fromUtf8(mCfgMgr.getUserConfigPath().string().c_str())); + QString path(toQString(mCfgMgr.getUserConfigPath())); path.append(QLatin1String(Config::LauncherSettings::sLauncherConfigFileName)); QString message(tr("

Could not open %1 for reading

\ @@ -228,7 +234,7 @@ void Wizard::MainWizard::runSettingsImporter() QString path(field(QLatin1String("installation.path")).toString()); // Create the file if it doesn't already exist, else the importer will fail - QString userPath(QString::fromUtf8(mCfgMgr.getUserConfigPath().string().c_str())); + QString userPath(toQString(mCfgMgr.getUserConfigPath())); QFile file(userPath + QLatin1String("openmw.cfg")); if (!file.exists()) { @@ -387,7 +393,7 @@ void Wizard::MainWizard::writeSettings() mGameSettings.removeDataDir(path); mGameSettings.addDataDir(path); - QString userPath(QString::fromUtf8(mCfgMgr.getUserConfigPath().string().c_str())); + QString userPath(toQString(mCfgMgr.getUserConfigPath())); QDir dir(userPath); if (!dir.exists()) { @@ -460,3 +466,8 @@ bool Wizard::MainWizard::findFiles(const QString &name, const QString &path) return (dir.entryList().contains(name + QLatin1String(".esm"), Qt::CaseInsensitive) && dir.entryList().contains(name + QLatin1String(".bsa"), Qt::CaseInsensitive)); } + +QString Wizard::MainWizard::toQString(const boost::filesystem::path& path) +{ + return QString::fromUtf8(path.string().c_str()); +} diff --git a/apps/wizard/mainwizard.hpp b/apps/wizard/mainwizard.hpp index c22f20c25..7f6e48a87 100644 --- a/apps/wizard/mainwizard.hpp +++ b/apps/wizard/mainwizard.hpp @@ -59,6 +59,8 @@ namespace Wizard void addLogText(const QString &text); private: + /// convert boost::filesystem::path to QString + QString toQString(const boost::filesystem::path& path); void setupLog(); void setupGameSettings(); diff --git a/components/CMakeLists.txt b/components/CMakeLists.txt index 70c9daa8b..161c9ce4a 100644 --- a/components/CMakeLists.txt +++ b/components/CMakeLists.txt @@ -74,7 +74,7 @@ add_component_dir (esm loadweap records aipackage effectlist spelllist variant variantimp loadtes3 cellref filter savedgame journalentry queststate locals globalscript player objectstate cellid cellstate globalmap inventorystate containerstate npcstate creaturestate dialoguestate statstate npcstats creaturestats weatherstate quickkeys fogstate spellstate activespells creaturelevliststate doorstate projectilestate debugprofile - aisequence magiceffects util custommarkerstate stolenitems + aisequence magiceffects util custommarkerstate stolenitems transport ) add_component_dir (esmterrain @@ -173,7 +173,12 @@ include_directories(${BULLET_INCLUDE_DIRS} ${CMAKE_CURRENT_BINARY_DIR}) add_library(components STATIC ${COMPONENT_FILES} ${MOC_SRCS} ${ESM_UI_HDR}) -target_link_libraries(components ${Boost_LIBRARIES} ${OGRE_LIBRARIES} ${OPENSCENEGRAPH_LIBRARIES}) +target_link_libraries(components + ${Boost_LIBRARIES} + ${OGRE_LIBRARIES} + ${OENGINE_LIBRARY} + ${OPENSCENEGRAPH_LIBRARIES} +) if (GIT_CHECKOUT) add_dependencies (components git-version) diff --git a/components/bsa/bsa_file.cpp b/components/bsa/bsa_file.cpp index d598c0d6f..401d043d9 100644 --- a/components/bsa/bsa_file.cpp +++ b/components/bsa/bsa_file.cpp @@ -79,7 +79,7 @@ void BSAFile::readHeader() bfs::ifstream input(bfs::path(filename), std::ios_base::binary); // Total archive size - size_t fsize = 0; + std::streamoff fsize = 0; if(input.seekg(0, std::ios_base::end)) { fsize = input.tellg(); @@ -111,7 +111,7 @@ void BSAFile::readHeader() // Each file must take up at least 21 bytes of data in the bsa. So // if files*21 overflows the file size then we are guaranteed that // the archive is corrupt. - if((filenum*21 > fsize -12) || (dirsize+8*filenum > fsize -12) ) + if((filenum*21 > unsigned(fsize -12)) || (dirsize+8*filenum > unsigned(fsize -12)) ) fail("Directory information larger than entire archive"); // Read the offset info into a temporary buffer diff --git a/components/compiler/exprparser.cpp b/components/compiler/exprparser.cpp index 7eaca5c02..dc36b58d8 100644 --- a/components/compiler/exprparser.cpp +++ b/components/compiler/exprparser.cpp @@ -324,7 +324,7 @@ namespace Compiler mNextOperand = false; mOperands.push_back ('l'); - return 2; + return true; } } diff --git a/components/compiler/extensions0.hpp b/components/compiler/extensions0.hpp index d51507711..83f3a44fa 100644 --- a/components/compiler/extensions0.hpp +++ b/components/compiler/extensions0.hpp @@ -78,4 +78,4 @@ namespace Compiler } } -#endif \ No newline at end of file +#endif diff --git a/components/compiler/nullerrorhandler.cpp b/components/compiler/nullerrorhandler.cpp index 3071701e8..ee2884705 100644 --- a/components/compiler/nullerrorhandler.cpp +++ b/components/compiler/nullerrorhandler.cpp @@ -3,4 +3,4 @@ void Compiler::NullErrorHandler::report (const std::string& message, const TokenLoc& loc, Type type) {} -void Compiler::NullErrorHandler::report (const std::string& message, Type type) {} \ No newline at end of file +void Compiler::NullErrorHandler::report (const std::string& message, Type type) {} diff --git a/components/compiler/opcodes.cpp b/components/compiler/opcodes.cpp index 8617062d6..03081dff9 100644 --- a/components/compiler/opcodes.cpp +++ b/components/compiler/opcodes.cpp @@ -10,4 +10,4 @@ namespace Compiler "playerviewswitch", "vanitymode" }; } -} \ No newline at end of file +} diff --git a/components/compiler/quickfileparser.cpp b/components/compiler/quickfileparser.cpp index f3d8063b2..4e9f76e13 100644 --- a/components/compiler/quickfileparser.cpp +++ b/components/compiler/quickfileparser.cpp @@ -49,4 +49,4 @@ bool Compiler::QuickFileParser::parseSpecial (int code, const TokenLoc& loc, Sca void Compiler::QuickFileParser::parseEOF (Scanner& scanner) { -} \ No newline at end of file +} diff --git a/components/config/launchersettings.cpp b/components/config/launchersettings.cpp index 66f05f691..1d4b428c9 100644 --- a/components/config/launchersettings.cpp +++ b/components/config/launchersettings.cpp @@ -105,6 +105,12 @@ void Config::LauncherSettings::setContentList(const GameSettings& gameSettings) // obtain content list from game settings (if present) const QStringList files(gameSettings.getContentList()); + // if openmw.cfg has no content, exit so we don't create an empty content list. + if (files.isEmpty()) + { + return; + } + // if any existing profile in launcher matches the content list, make that profile the default foreach(const QString &listName, getContentLists()) { diff --git a/components/config/launchersettings.hpp b/components/config/launchersettings.hpp index cbe21c54a..c5eefb22a 100644 --- a/components/config/launchersettings.hpp +++ b/components/config/launchersettings.hpp @@ -17,7 +17,7 @@ namespace Config /// \return names of all Content Lists in the launcher's .cfg file. QStringList getContentLists(); - /// Set initally selected content list to match values from openmw.cfg, creating if necessary + /// Set initially selected content list to match values from openmw.cfg, creating if necessary void setContentList(const GameSettings& gameSettings); /// Create a Content List (or replace if it already exists) diff --git a/components/contentselector/model/contentmodel.cpp b/components/contentselector/model/contentmodel.cpp index ec1fcc21e..62f6d9014 100644 --- a/components/contentselector/model/contentmodel.cpp +++ b/components/contentselector/model/contentmodel.cpp @@ -115,10 +115,10 @@ Qt::ItemFlags ContentSelectorModel::ContentModel::flags(const QModelIndex &index return Qt::ItemIsEnabled | Qt::ItemIsSelectable | Qt::ItemIsUserCheckable; Qt::ItemFlags returnFlags; - bool allDependenciesFound = true; - bool gamefileChecked = false; - //addon can be checked if its gamefile is and all other dependencies exist + // addon can be checked if its gamefile is + // ... special case, addon with no dependency can be used with any gamefile. + bool gamefileChecked = (file->gameFiles().count() == 0); foreach (const QString &fileName, file->gameFiles()) { bool depFound = false; @@ -144,16 +144,11 @@ Qt::ItemFlags ContentSelectorModel::ContentModel::flags(const QModelIndex &index if (gamefileChecked || !(dependency->isGameFile())) break; } - - allDependenciesFound = allDependenciesFound && depFound; } if (gamefileChecked) { - if (allDependenciesFound) - returnFlags = returnFlags | Qt::ItemIsEnabled | Qt::ItemIsSelectable | Qt::ItemIsUserCheckable | Qt::ItemIsDragEnabled; - else - returnFlags = Qt::ItemIsSelectable; + returnFlags = Qt::ItemIsEnabled | Qt::ItemIsSelectable | Qt::ItemIsUserCheckable | Qt::ItemIsDragEnabled; } return returnFlags; @@ -454,7 +449,7 @@ void ContentSelectorModel::ContentModel::addFiles(const QString &path) ToUTF8::Utf8Encoder encoder = ToUTF8::calculateEncoding(mEncoding.toStdString()); fileReader.setEncoder(&encoder); - fileReader.open(dir.absoluteFilePath(path).toStdString()); + fileReader.open(std::string(dir.absoluteFilePath(path).toUtf8().constData())); EsmFile *file = new EsmFile(path); @@ -467,6 +462,14 @@ void ContentSelectorModel::ContentModel::addFiles(const QString &path) file->setFilePath (info.absoluteFilePath()); file->setDescription(QString::fromUtf8(fileReader.getDesc().c_str())); + // HACK + // Load order constraint of Bloodmoon.esm needing Tribunal.esm is missing + // from the file supplied by Bethesda, so we have to add it ourselves + if (file->fileName().compare("Bloodmoon.esm", Qt::CaseInsensitive) == 0) + { + file->addGameFile(QString::fromUtf8("Tribunal.esm")); + } + // Put the file in the table addFile(file); @@ -481,6 +484,19 @@ void ContentSelectorModel::ContentModel::addFiles(const QString &path) sortFiles(); } +QStringList ContentSelectorModel::ContentModel::gameFiles() const +{ + QStringList gameFiles; + foreach(const ContentSelectorModel::EsmFile *file, mFiles) + { + if (file->isGameFile()) + { + gameFiles.append(file->fileName()); + } + } + return gameFiles; +} + void ContentSelectorModel::ContentModel::sortFiles() { //first, sort the model such that all dependencies are ordered upstream (gamefile) first. @@ -536,13 +552,13 @@ bool ContentSelectorModel::ContentModel::isLoadOrderError(const EsmFile *file) c return mPluginsWithLoadOrderError.contains(file->filePath()); } -void ContentSelectorModel::ContentModel::setContentList(const QStringList &fileList, bool isChecked) +void ContentSelectorModel::ContentModel::setContentList(const QStringList &fileList) { mPluginsWithLoadOrderError.clear(); int previousPosition = -1; foreach (const QString &filepath, fileList) { - if (setCheckState(filepath, isChecked)) + if (setCheckState(filepath, true)) { // as necessary, move plug-ins in visible list to match sequence of supplied filelist const EsmFile* file = item(filepath); @@ -581,7 +597,7 @@ void ContentSelectorModel::ContentModel::checkForLoadOrderErrors() QList ContentSelectorModel::ContentModel::checkForLoadOrderErrors(const EsmFile *file, int row) const { QList errors = QList(); - foreach(QString dependentfileName, file->gameFiles()) + foreach(const QString &dependentfileName, file->gameFiles()) { const EsmFile* dependentFile = item(dependentfileName); diff --git a/components/contentselector/model/contentmodel.hpp b/components/contentselector/model/contentmodel.hpp index 6af5425c7..658555852 100644 --- a/components/contentselector/model/contentmodel.hpp +++ b/components/contentselector/model/contentmodel.hpp @@ -47,11 +47,12 @@ namespace ContentSelectorModel QModelIndex indexFromItem(const EsmFile *item) const; const EsmFile *item(const QString &name) const; + QStringList gameFiles() const; bool isEnabled (QModelIndex index) const; bool isChecked(const QString &filepath) const; bool setCheckState(const QString &filepath, bool isChecked); - void setContentList(const QStringList &fileList, bool isChecked); + void setContentList(const QStringList &fileList); ContentFileList checkedItems() const; void uncheckAll(); diff --git a/components/contentselector/model/esmfile.cpp b/components/contentselector/model/esmfile.cpp index a0a09105a..1ac1c7500 100644 --- a/components/contentselector/model/esmfile.cpp +++ b/components/contentselector/model/esmfile.cpp @@ -62,6 +62,13 @@ QByteArray ContentSelectorModel::EsmFile::encodedData() const return encodedData; } +bool ContentSelectorModel::EsmFile::isGameFile() const +{ + return (mGameFiles.size() == 0) && + (mFileName.endsWith(QLatin1String(".esm"), Qt::CaseInsensitive) || + mFileName.endsWith(QLatin1String(".omwgame"), Qt::CaseInsensitive)); +} + QVariant ContentSelectorModel::EsmFile::fileProperty(const FileProperty prop) const { switch (prop) diff --git a/components/contentselector/model/esmfile.hpp b/components/contentselector/model/esmfile.hpp index 7e1edcaba..d0cebab3c 100644 --- a/components/contentselector/model/esmfile.hpp +++ b/components/contentselector/model/esmfile.hpp @@ -64,7 +64,7 @@ namespace ContentSelectorModel .arg(mGameFiles.join(", ")); } - inline bool isGameFile() const { return (mGameFiles.size() == 0); } + bool isGameFile() const; QByteArray encodedData() const; public: diff --git a/components/contentselector/view/contentselector.cpp b/components/contentselector/view/contentselector.cpp index ad023e5b2..e3093d568 100644 --- a/components/contentselector/view/contentselector.cpp +++ b/components/contentselector/view/contentselector.cpp @@ -10,6 +10,7 @@ #include #include #include +#include #include ContentSelectorView::ContentSelector::ContentSelector(QWidget *parent) : @@ -33,13 +34,7 @@ void ContentSelectorView::ContentSelector::buildGameFileView() { ui.gameFileView->setVisible (true); - mGameFileProxyModel = new QSortFilterProxyModel(this); - mGameFileProxyModel->setFilterRegExp(QString::number((int)ContentSelectorModel::ContentType_GameFile)); - mGameFileProxyModel->setFilterRole (Qt::UserRole); - mGameFileProxyModel->setSourceModel (mContentModel); - ui.gameFileView->setPlaceholderText(QString("Select a game file...")); - ui.gameFileView->setModel(mGameFileProxyModel); connect (ui.gameFileView, SIGNAL (currentIndexChanged(int)), this, SLOT (slotCurrentGameFileIndexChanged(int))); @@ -113,7 +108,7 @@ void ContentSelectorView::ContentSelector::setContentList(const QStringList &lis slotCurrentGameFileIndexChanged (ui.gameFileView->currentIndex()); } else - mContentModel->setContentList(list, true); + mContentModel->setContentList(list); } ContentSelectorModel::ContentFileList @@ -129,6 +124,15 @@ void ContentSelectorView::ContentSelector::addFiles(const QString &path) { mContentModel->addFiles(path); + // add any game files to the combo box + foreach(const QString gameFileName, mContentModel->gameFiles()) + { + if (ui.gameFileView->findText(gameFileName) == -1) + { + ui.gameFileView->addItem(gameFileName); + } + } + if (ui.gameFileView->currentIndex() != -1) ui.gameFileView->setCurrentIndex(-1); @@ -150,31 +154,36 @@ void ContentSelectorView::ContentSelector::slotCurrentGameFileIndexChanged(int i { static int oldIndex = -1; - QAbstractItemModel *const model = ui.gameFileView->model(); - QSortFilterProxyModel *proxy = dynamic_cast(model); - - if (proxy) - proxy->setDynamicSortFilter(false); - if (index != oldIndex) { if (oldIndex > -1) - model->setData(model->index(oldIndex, 0), false, Qt::UserRole + 1); + { + setGameFileSelected(oldIndex, false); + } oldIndex = index; - model->setData(model->index(index, 0), true, Qt::UserRole + 1); + setGameFileSelected(index, true); mContentModel->checkForLoadOrderErrors(); } - if (proxy) - proxy->setDynamicSortFilter(true); - emit signalCurrentGamefileIndexChanged (index); } +void ContentSelectorView::ContentSelector::setGameFileSelected(int index, bool selected) +{ + QString fileName = ui.gameFileView->itemText(index); + const ContentSelectorModel::EsmFile* file = mContentModel->item(fileName); + if (file != NULL) + { + QModelIndex index(mContentModel->indexFromItem(file)); + mContentModel->setData(index, selected, Qt::UserRole + 1); + } +} + void ContentSelectorView::ContentSelector::slotAddonTableItemActivated(const QModelIndex &index) { + // toggles check state when an AddOn file is double clicked or activated by keyboard QModelIndex sourceIndex = mAddonProxyModel->mapToSource (index); if (!mContentModel->isEnabled (sourceIndex)) diff --git a/components/contentselector/view/contentselector.hpp b/components/contentselector/view/contentselector.hpp index 8651dac2e..2507cf6ad 100644 --- a/components/contentselector/view/contentselector.hpp +++ b/components/contentselector/view/contentselector.hpp @@ -19,7 +19,6 @@ namespace ContentSelectorView protected: ContentSelectorModel::ContentModel *mContentModel; - QSortFilterProxyModel *mGameFileProxyModel; QSortFilterProxyModel *mAddonProxyModel; public: @@ -52,6 +51,7 @@ namespace ContentSelectorView void buildContentModel(); void buildGameFileView(); void buildAddonView(); + void setGameFileSelected(int index, bool selected); signals: void signalCurrentGamefileIndexChanged (int); diff --git a/components/esm/aipackage.cpp b/components/esm/aipackage.cpp index 8ad64b797..efcd6651e 100644 --- a/components/esm/aipackage.cpp +++ b/components/esm/aipackage.cpp @@ -41,29 +41,6 @@ namespace ESM } - void AIPackageList::load(ESMReader &esm) - { - mList.clear(); - while (esm.hasMoreSubs()) { - // initialize every iteration - esm.getSubName(); - switch (esm.retSubName().val) - { - case AI_Wander: - case AI_Activate: - case AI_Escort: - case AI_Follow: - case AI_Travel: - case AI_CNDT: - - add(esm); - break; - default: - return; - } - } - } - void AIPackageList::save(ESMWriter &esm) const { typedef std::vector::const_iterator PackageIter; diff --git a/components/esm/aipackage.hpp b/components/esm/aipackage.hpp index 30bd2ce04..5e08806c8 100644 --- a/components/esm/aipackage.hpp +++ b/components/esm/aipackage.hpp @@ -94,9 +94,6 @@ namespace ESM /// Add a single AIPackage, assumes subrecord name was already read void add(ESMReader &esm); - /// TODO: remove this method. The ESM format does not guarantee that all AI packages follow one another - void load(ESMReader &esm); - void save(ESMWriter &esm) const; }; } diff --git a/components/esm/cellid.hpp b/components/esm/cellid.hpp index 40bc552e0..44a1b387a 100644 --- a/components/esm/cellid.hpp +++ b/components/esm/cellid.hpp @@ -28,4 +28,4 @@ namespace ESM bool operator!= (const CellId& left, const CellId& right); } -#endif \ No newline at end of file +#endif diff --git a/components/esm/containerstate.cpp b/components/esm/containerstate.cpp index 5dcf17733..80ad5cbdc 100644 --- a/components/esm/containerstate.cpp +++ b/components/esm/containerstate.cpp @@ -13,4 +13,4 @@ void ESM::ContainerState::save (ESMWriter &esm, bool inInventory) const ObjectState::save (esm, inInventory); mInventory.save (esm); -} \ No newline at end of file +} diff --git a/components/esm/effectlist.cpp b/components/esm/effectlist.cpp index fc9acccf2..f6d5a6e07 100644 --- a/components/esm/effectlist.cpp +++ b/components/esm/effectlist.cpp @@ -8,13 +8,18 @@ namespace ESM { void EffectList::load(ESMReader &esm) { mList.clear(); - ENAMstruct s; while (esm.isNextSub("ENAM")) { - esm.getHT(s, 24); - mList.push_back(s); + add(esm); } } +void EffectList::add(ESMReader &esm) +{ + ENAMstruct s; + esm.getHT(s, 24); + mList.push_back(s); +} + void EffectList::save(ESMWriter &esm) const { for (std::vector::const_iterator it = mList.begin(); it != mList.end(); ++it) { diff --git a/components/esm/effectlist.hpp b/components/esm/effectlist.hpp index 04adcc5cd..d581f8337 100644 --- a/components/esm/effectlist.hpp +++ b/components/esm/effectlist.hpp @@ -29,11 +29,15 @@ namespace ESM }; #pragma pack(pop) + /// EffectList, ENAM subrecord struct EffectList { - std::vector mList; + /// Load one effect, assumes subrecord name was already read + void add(ESMReader &esm); + + /// Load all effects void load(ESMReader &esm); void save(ESMWriter &esm) const; }; diff --git a/components/esm/esmcommon.hpp b/components/esm/esmcommon.hpp index 54b18aeaf..d90a3444d 100644 --- a/components/esm/esmcommon.hpp +++ b/components/esm/esmcommon.hpp @@ -5,7 +5,7 @@ #include #include -#include +#include namespace ESM { diff --git a/components/esm/esmreader.hpp b/components/esm/esmreader.hpp index 31fc3e32d..89062bd27 100644 --- a/components/esm/esmreader.hpp +++ b/components/esm/esmreader.hpp @@ -2,7 +2,7 @@ #define OPENMW_ESM_READER_H #include -#include +#include #include #include #include diff --git a/components/esm/globalscript.cpp b/components/esm/globalscript.cpp index 467fe54a1..0129f8eb7 100644 --- a/components/esm/globalscript.cpp +++ b/components/esm/globalscript.cpp @@ -26,4 +26,4 @@ void ESM::GlobalScript::save (ESMWriter &esm) const esm.writeHNT ("RUN_", mRunning); esm.writeHNOString ("TARG", mTargetId); -} \ No newline at end of file +} diff --git a/components/esm/loadacti.cpp b/components/esm/loadacti.cpp index 8efea3302..b5adce550 100644 --- a/components/esm/loadacti.cpp +++ b/components/esm/loadacti.cpp @@ -8,18 +8,34 @@ namespace ESM { unsigned int Activator::sRecordId = REC_ACTI; -void Activator::load(ESMReader &esm) -{ - mModel = esm.getHNString("MODL"); - mName = esm.getHNOString("FNAM"); - mScript = esm.getHNOString("SCRI"); -} -void Activator::save(ESMWriter &esm) const -{ - esm.writeHNCString("MODL", mModel); - esm.writeHNOCString("FNAM", mName); - esm.writeHNOCString("SCRI", mScript); -} + void Activator::load(ESMReader &esm) + { + while (esm.hasMoreSubs()) + { + esm.getSubName(); + uint32_t name = esm.retSubName().val; + switch (name) + { + case ESM::FourCC<'M','O','D','L'>::value: + mModel = esm.getHString(); + break; + case ESM::FourCC<'F','N','A','M'>::value: + mName = esm.getHString(); + break; + case ESM::FourCC<'S','C','R','I'>::value: + mScript = esm.getHString(); + break; + default: + esm.fail("Unknown subrecord"); + } + } + } + void Activator::save(ESMWriter &esm) const + { + esm.writeHNCString("MODL", mModel); + esm.writeHNOCString("FNAM", mName); + esm.writeHNOCString("SCRI", mScript); + } void Activator::blank() { diff --git a/components/esm/loadalch.cpp b/components/esm/loadalch.cpp index aac88482f..18db512c0 100644 --- a/components/esm/loadalch.cpp +++ b/components/esm/loadalch.cpp @@ -8,24 +8,51 @@ namespace ESM { unsigned int Potion::sRecordId = REC_ALCH; -void Potion::load(ESMReader &esm) -{ - mModel = esm.getHNOString("MODL"); - mIcon = esm.getHNOString("TEXT"); // not ITEX here for some reason - mScript = esm.getHNOString("SCRI"); - mName = esm.getHNOString("FNAM"); - esm.getHNT(mData, "ALDT", 12); - mEffects.load(esm); -} -void Potion::save(ESMWriter &esm) const -{ - esm.writeHNCString("MODL", mModel); - esm.writeHNOCString("TEXT", mIcon); - esm.writeHNOCString("SCRI", mScript); - esm.writeHNOCString("FNAM", mName); - esm.writeHNT("ALDT", mData, 12); - mEffects.save(esm); -} + void Potion::load(ESMReader &esm) + { + mEffects.mList.clear(); + bool hasData = false; + while (esm.hasMoreSubs()) + { + esm.getSubName(); + uint32_t name = esm.retSubName().val; + switch (name) + { + case ESM::FourCC<'M','O','D','L'>::value: + mModel = esm.getHString(); + break; + case ESM::FourCC<'T','E','X','T'>::value: // not ITEX here for some reason + mIcon = esm.getHString(); + break; + case ESM::FourCC<'S','C','R','I'>::value: + mScript = esm.getHString(); + break; + case ESM::FourCC<'F','N','A','M'>::value: + mName = esm.getHString(); + break; + case ESM::FourCC<'A','L','D','T'>::value: + esm.getHT(mData, 12); + hasData = true; + break; + case ESM::FourCC<'E','N','A','M'>::value: + mEffects.add(esm); + break; + default: + esm.fail("Unknown subrecord"); + } + } + if (!hasData) + esm.fail("Missing ALDT"); + } + void Potion::save(ESMWriter &esm) const + { + esm.writeHNCString("MODL", mModel); + esm.writeHNOCString("TEXT", mIcon); + esm.writeHNOCString("SCRI", mScript); + esm.writeHNOCString("FNAM", mName); + esm.writeHNT("ALDT", mData, 12); + mEffects.save(esm); + } void Potion::blank() { diff --git a/components/esm/loadappa.cpp b/components/esm/loadappa.cpp index 29ea78acc..f2c82aacf 100644 --- a/components/esm/loadappa.cpp +++ b/components/esm/loadappa.cpp @@ -10,25 +10,35 @@ namespace ESM void Apparatus::load(ESMReader &esm) { - // we will not treat duplicated subrecords as errors here + bool hasData = false; while (esm.hasMoreSubs()) { esm.getSubName(); - NAME subName = esm.retSubName(); - - if (subName == "MODL") - mModel = esm.getHString(); - else if (subName == "FNAM") - mName = esm.getHString(); - else if (subName == "AADT") - esm.getHT(mData); - else if (subName == "SCRI") - mScript = esm.getHString(); - else if (subName == "ITEX") - mIcon = esm.getHString(); - else - esm.fail("wrong subrecord type " + subName.toString() + " for APPA record"); + uint32_t name = esm.retSubName().val; + switch (name) + { + case ESM::FourCC<'M','O','D','L'>::value: + mModel = esm.getHString(); + break; + case ESM::FourCC<'F','N','A','M'>::value: + mName = esm.getHString(); + break; + case ESM::FourCC<'A','A','D','T'>::value: + esm.getHT(mData); + hasData = true; + break; + case ESM::FourCC<'S','C','R','I'>::value: + mScript = esm.getHString(); + break; + case ESM::FourCC<'I','T','E','X'>::value: + mIcon = esm.getHString(); + break; + default: + esm.fail("Unknown subrecord"); + } } + if (!hasData) + esm.fail("Missing AADT"); } void Apparatus::save(ESMWriter &esm) const diff --git a/components/esm/loadbody.cpp b/components/esm/loadbody.cpp index 9a1164d04..ed24ded57 100644 --- a/components/esm/loadbody.cpp +++ b/components/esm/loadbody.cpp @@ -11,9 +11,30 @@ namespace ESM void BodyPart::load(ESMReader &esm) { - mModel = esm.getHNString("MODL"); - mRace = esm.getHNOString("FNAM"); - esm.getHNT(mData, "BYDT", 4); + bool hasData = false; + while (esm.hasMoreSubs()) + { + esm.getSubName(); + uint32_t name = esm.retSubName().val; + switch (name) + { + case ESM::FourCC<'M','O','D','L'>::value: + mModel = esm.getHString(); + break; + case ESM::FourCC<'F','N','A','M'>::value: + mRace = esm.getHString(); + break; + case ESM::FourCC<'B','Y','D','T'>::value: + esm.getHT(mData, 4); + hasData = true; + break; + default: + esm.fail("Unknown subrecord"); + } + } + + if (!hasData) + esm.fail("Missing BYDT subrecord"); } void BodyPart::save(ESMWriter &esm) const { diff --git a/components/esm/loadbsgn.cpp b/components/esm/loadbsgn.cpp index db1a72a36..e0cd83ea0 100644 --- a/components/esm/loadbsgn.cpp +++ b/components/esm/loadbsgn.cpp @@ -10,11 +10,29 @@ namespace ESM void BirthSign::load(ESMReader &esm) { - mName = esm.getHNOString("FNAM"); - mTexture = esm.getHNOString("TNAM"); - mDescription = esm.getHNOString("DESC"); - - mPowers.load(esm); + mPowers.mList.clear(); + while (esm.hasMoreSubs()) + { + esm.getSubName(); + uint32_t name = esm.retSubName().val; + switch (name) + { + case ESM::FourCC<'F','N','A','M'>::value: + mName = esm.getHString(); + break; + case ESM::FourCC<'T','N','A','M'>::value: + mTexture = esm.getHString(); + break; + case ESM::FourCC<'D','E','S','C'>::value: + mDescription = esm.getHString(); + break; + case ESM::FourCC<'N','P','C','S'>::value: + mPowers.add(esm); + break; + default: + esm.fail("Unknown subrecord"); + } + } } void BirthSign::save(ESMWriter &esm) const diff --git a/components/esm/loadclas.cpp b/components/esm/loadclas.cpp index ec339bd15..66acaea72 100644 --- a/components/esm/loadclas.cpp +++ b/components/esm/loadclas.cpp @@ -10,17 +10,17 @@ namespace ESM { unsigned int Class::sRecordId = REC_CLAS; -const Class::Specialization Class::sSpecializationIds[3] = { - Class::Combat, - Class::Magic, - Class::Stealth -}; + const Class::Specialization Class::sSpecializationIds[3] = { + Class::Combat, + Class::Magic, + Class::Stealth + }; -const char *Class::sGmstSpecializationIds[3] = { - "sSpecializationCombat", - "sSpecializationMagic", - "sSpecializationStealth" -}; + const char *Class::sGmstSpecializationIds[3] = { + "sSpecializationCombat", + "sSpecializationMagic", + "sSpecializationStealth" + }; int& Class::CLDTstruct::getSkill (int index, bool major) @@ -39,22 +39,40 @@ const char *Class::sGmstSpecializationIds[3] = { return mSkills[index][major ? 1 : 0]; } -void Class::load(ESMReader &esm) -{ - mName = esm.getHNOString("FNAM"); - esm.getHNT(mData, "CLDT", 60); - - if (mData.mIsPlayable > 1) - esm.fail("Unknown bool value"); - - mDescription = esm.getHNOString("DESC"); -} -void Class::save(ESMWriter &esm) const -{ - esm.writeHNOCString("FNAM", mName); - esm.writeHNT("CLDT", mData, 60); - esm.writeHNOString("DESC", mDescription); -} + void Class::load(ESMReader &esm) + { + bool hasData = false; + while (esm.hasMoreSubs()) + { + esm.getSubName(); + uint32_t name = esm.retSubName().val; + switch (name) + { + case ESM::FourCC<'F','N','A','M'>::value: + mName = esm.getHString(); + break; + case ESM::FourCC<'C','L','D','T'>::value: + esm.getHT(mData, 60); + if (mData.mIsPlayable > 1) + esm.fail("Unknown bool value"); + hasData = true; + break; + case ESM::FourCC<'D','E','S','C'>::value: + mDescription = esm.getHString(); + break; + default: + esm.fail("Unknown subrecord"); + } + } + if (!hasData) + esm.fail("Missing CLDT subrecord"); + } + void Class::save(ESMWriter &esm) const + { + esm.writeHNOCString("FNAM", mName); + esm.writeHNT("CLDT", mData, 60); + esm.writeHNOString("DESC", mDescription); + } void Class::blank() { diff --git a/components/esm/loadcont.cpp b/components/esm/loadcont.cpp index f48f06930..3481189c3 100644 --- a/components/esm/loadcont.cpp +++ b/components/esm/loadcont.cpp @@ -7,60 +7,79 @@ namespace ESM { -void InventoryList::add(ESMReader &esm) -{ - ContItem ci; - esm.getHT(ci, 36); - mList.push_back(ci); -} - -void InventoryList::load(ESMReader &esm) -{ - mList.clear(); - while (esm.isNextSub("NPCO")) + void InventoryList::add(ESMReader &esm) { - add(esm); + ContItem ci; + esm.getHT(ci, 36); + mList.push_back(ci); } -} -void InventoryList::save(ESMWriter &esm) const -{ - for (std::vector::const_iterator it = mList.begin(); it != mList.end(); ++it) + void InventoryList::save(ESMWriter &esm) const { - esm.writeHNT("NPCO", *it, 36); + for (std::vector::const_iterator it = mList.begin(); it != mList.end(); ++it) + { + esm.writeHNT("NPCO", *it, 36); + } } -} unsigned int Container::sRecordId = REC_CONT; -void Container::load(ESMReader &esm) -{ - mModel = esm.getHNString("MODL"); - mName = esm.getHNOString("FNAM"); - esm.getHNT(mWeight, "CNDT", 4); - esm.getHNT(mFlags, "FLAG", 4); + void Container::load(ESMReader &esm) + { + mInventory.mList.clear(); + bool hasWeight = false; + bool hasFlags = false; + while (esm.hasMoreSubs()) + { + esm.getSubName(); + uint32_t name = esm.retSubName().val; + switch (name) + { + case ESM::FourCC<'M','O','D','L'>::value: + mModel = esm.getHString(); + break; + case ESM::FourCC<'F','N','A','M'>::value: + mName = esm.getHString(); + break; + case ESM::FourCC<'C','N','D','T'>::value: + esm.getHT(mWeight, 4); + hasWeight = true; + break; + case ESM::FourCC<'F','L','A','G'>::value: + esm.getHT(mFlags, 4); + if (mFlags & 0xf4) + esm.fail("Unknown flags"); + if (!(mFlags & 0x8)) + esm.fail("Flag 8 not set"); + hasFlags = true; + break; + case ESM::FourCC<'S','C','R','I'>::value: + mScript = esm.getHString(); + break; + case ESM::FourCC<'N','P','C','O'>::value: + mInventory.add(esm); + break; + default: + esm.fail("Unknown subrecord"); + } + } + if (!hasWeight) + esm.fail("Missing CNDT subrecord"); + if (!hasFlags) + esm.fail("Missing FLAG subrecord"); + } - if (mFlags & 0xf4) - esm.fail("Unknown flags"); - if (!(mFlags & 0x8)) - esm.fail("Flag 8 not set"); + void Container::save(ESMWriter &esm) const + { + esm.writeHNCString("MODL", mModel); + esm.writeHNOCString("FNAM", mName); + esm.writeHNT("CNDT", mWeight, 4); + esm.writeHNT("FLAG", mFlags, 4); - mScript = esm.getHNOString("SCRI"); + esm.writeHNOCString("SCRI", mScript); - mInventory.load(esm); -} - -void Container::save(ESMWriter &esm) const -{ - esm.writeHNCString("MODL", mModel); - esm.writeHNOCString("FNAM", mName); - esm.writeHNT("CNDT", mWeight, 4); - esm.writeHNT("FLAG", mFlags, 4); - - esm.writeHNOCString("SCRI", mScript); - - mInventory.save(esm); -} + mInventory.save(esm); + } void Container::blank() { @@ -68,7 +87,7 @@ void Container::save(ESMWriter &esm) const mModel.clear(); mScript.clear(); mWeight = 0; - mFlags = 0; + mFlags = 0x8; // set default flag value mInventory.mList.clear(); } } diff --git a/components/esm/loadcont.hpp b/components/esm/loadcont.hpp index 93db94759..76c522d74 100644 --- a/components/esm/loadcont.hpp +++ b/components/esm/loadcont.hpp @@ -22,6 +22,7 @@ struct ContItem NAME32 mItem; }; +/// InventoryList, NPCO subrecord struct InventoryList { std::vector mList; @@ -29,8 +30,6 @@ struct InventoryList /// Load one item, assumes subrecord name is already read void add(ESMReader &esm); - /// TODO: remove this method, the ESM format doesn't guarantee that all ContItems follow one another - void load(ESMReader &esm); void save(ESMWriter &esm) const; }; diff --git a/components/esm/loadcrea.cpp b/components/esm/loadcrea.cpp index 650de0801..50c47349c 100644 --- a/components/esm/loadcrea.cpp +++ b/components/esm/loadcrea.cpp @@ -8,55 +8,100 @@ namespace ESM { unsigned int Creature::sRecordId = REC_CREA; -void Creature::load(ESMReader &esm) -{ - mPersistent = esm.getRecordFlags() & 0x0400; - - mModel = esm.getHNString("MODL"); - mOriginal = esm.getHNOString("CNAM"); - mName = esm.getHNOString("FNAM"); - mScript = esm.getHNOString("SCRI"); - - esm.getHNT(mData, "NPDT", 96); - - esm.getHNT(mFlags, "FLAG"); - mScale = 1.0; - esm.getHNOT(mScale, "XSCL"); - - mInventory.load(esm); - mSpells.load(esm); - - if (esm.isNextSub("AIDT")) + void Creature::load(ESMReader &esm) { - esm.getHExact(&mAiData, sizeof(mAiData)); - mHasAI = true; - } - else + mPersistent = (esm.getRecordFlags() & 0x0400) != 0; + + mAiPackage.mList.clear(); + mInventory.mList.clear(); + mSpells.mList.clear(); + mTransport.mList.clear(); + + mScale = 1.f; mHasAI = false; - - mAiPackage.load(esm); - esm.skipRecord(); -} - -void Creature::save(ESMWriter &esm) const -{ - esm.writeHNCString("MODL", mModel); - esm.writeHNOCString("CNAM", mOriginal); - esm.writeHNOCString("FNAM", mName); - esm.writeHNOCString("SCRI", mScript); - esm.writeHNT("NPDT", mData, 96); - esm.writeHNT("FLAG", mFlags); - if (mScale != 1.0) { - esm.writeHNT("XSCL", mScale); + bool hasNpdt = false; + bool hasFlags = false; + while (esm.hasMoreSubs()) + { + esm.getSubName(); + uint32_t name = esm.retSubName().val; + switch (name) + { + case ESM::FourCC<'M','O','D','L'>::value: + mModel = esm.getHString(); + break; + case ESM::FourCC<'C','N','A','M'>::value: + mOriginal = esm.getHString(); + break; + case ESM::FourCC<'F','N','A','M'>::value: + mName = esm.getHString(); + break; + case ESM::FourCC<'S','C','R','I'>::value: + mScript = esm.getHString(); + break; + case ESM::FourCC<'N','P','D','T'>::value: + esm.getHT(mData, 96); + hasNpdt = true; + break; + case ESM::FourCC<'F','L','A','G'>::value: + esm.getHT(mFlags); + hasFlags = true; + break; + case ESM::FourCC<'X','S','C','L'>::value: + esm.getHT(mScale); + break; + case ESM::FourCC<'N','P','C','O'>::value: + mInventory.add(esm); + break; + case ESM::FourCC<'N','P','C','S'>::value: + mSpells.add(esm); + break; + case ESM::FourCC<'A','I','D','T'>::value: + esm.getHExact(&mAiData, sizeof(mAiData)); + mHasAI = true; + break; + case ESM::FourCC<'D','O','D','T'>::value: + case ESM::FourCC<'D','N','A','M'>::value: + mTransport.add(esm); + break; + case AI_Wander: + case AI_Activate: + case AI_Escort: + case AI_Follow: + case AI_Travel: + case AI_CNDT: + mAiPackage.add(esm); + break; + default: + esm.fail("Unknown subrecord"); + } + } + if (!hasNpdt) + esm.fail("Missing NPDT subrecord"); + if (!hasFlags) + esm.fail("Missing FLAG subrecord"); } - mInventory.save(esm); - mSpells.save(esm); - if (mHasAI) { - esm.writeHNT("AIDT", mAiData, sizeof(mAiData)); + void Creature::save(ESMWriter &esm) const + { + esm.writeHNCString("MODL", mModel); + esm.writeHNOCString("CNAM", mOriginal); + esm.writeHNOCString("FNAM", mName); + esm.writeHNOCString("SCRI", mScript); + esm.writeHNT("NPDT", mData, 96); + esm.writeHNT("FLAG", mFlags); + if (mScale != 1.0) { + esm.writeHNT("XSCL", mScale); + } + + mInventory.save(esm); + mSpells.save(esm); + if (mHasAI) { + esm.writeHNT("AIDT", mAiData, sizeof(mAiData)); + } + mTransport.save(esm); + mAiPackage.save(esm); } - mAiPackage.save(esm); -} void Creature::blank() { @@ -81,5 +126,11 @@ void Creature::save(ESMWriter &esm) const mAiData.blank(); mAiData.mServices = 0; mAiPackage.mList.clear(); + mTransport.mList.clear(); + } + + const std::vector& Creature::getTransport() const + { + return mTransport.mList; } } diff --git a/components/esm/loadcrea.hpp b/components/esm/loadcrea.hpp index e459dded7..1b02aa0ab 100644 --- a/components/esm/loadcrea.hpp +++ b/components/esm/loadcrea.hpp @@ -6,6 +6,7 @@ #include "loadcont.hpp" #include "spelllist.hpp" #include "aipackage.hpp" +#include "transport.hpp" namespace ESM { @@ -92,6 +93,9 @@ struct Creature bool mHasAI; AIData mAiData; AIPackageList mAiPackage; + Transport mTransport; + + const std::vector& getTransport() const; void load(ESMReader &esm); void save(ESMWriter &esm) const; diff --git a/components/esm/loadench.cpp b/components/esm/loadench.cpp index 243803833..54690d9a0 100644 --- a/components/esm/loadench.cpp +++ b/components/esm/loadench.cpp @@ -10,8 +10,28 @@ namespace ESM void Enchantment::load(ESMReader &esm) { - esm.getHNT(mData, "ENDT", 16); - mEffects.load(esm); + mEffects.mList.clear(); + bool hasData = false; + while (esm.hasMoreSubs()) + { + esm.getSubName(); + uint32_t name = esm.retSubName().val; + switch (name) + { + case ESM::FourCC<'E','N','D','T'>::value: + esm.getHT(mData, 16); + hasData = true; + break; + case ESM::FourCC<'E','N','A','M'>::value: + mEffects.add(esm); + break; + default: + esm.fail("Unknown subrecord"); + break; + } + } + if (!hasData) + esm.fail("Missing ENDT subrecord"); } void Enchantment::save(ESMWriter &esm) const diff --git a/components/esm/loadfact.cpp b/components/esm/loadfact.cpp index db7e5b7b4..006ca0ce0 100644 --- a/components/esm/loadfact.cpp +++ b/components/esm/loadfact.cpp @@ -28,27 +28,46 @@ namespace ESM void Faction::load(ESMReader &esm) { - mName = esm.getHNOString("FNAM"); + mReactions.clear(); + for (int i=0;i<10;++i) + mRanks[i].clear(); - // Read rank names. These are optional. - int i = 0; - while (esm.isNextSub("RNAM") && i < 10) - mRanks[i++] = esm.getHString(); - - // Main data struct - esm.getHNT(mData, "FADT", 240); - - if (mData.mIsHidden > 1) - esm.fail("Unknown flag!"); - - // Read faction response values + int rankCounter=0; + bool hasData = false; while (esm.hasMoreSubs()) { - std::string faction = esm.getHNString("ANAM"); - int reaction; - esm.getHNT(reaction, "INTV"); - mReactions[faction] = reaction; + esm.getSubName(); + uint32_t name = esm.retSubName().val; + switch (name) + { + case ESM::FourCC<'F','N','A','M'>::value: + mName = esm.getHString(); + break; + case ESM::FourCC<'R','N','A','M'>::value: + if (rankCounter >= 10) + esm.fail("Rank out of range"); + mRanks[rankCounter++] = esm.getHString(); + break; + case ESM::FourCC<'F','A','D','T'>::value: + esm.getHT(mData, 240); + if (mData.mIsHidden > 1) + esm.fail("Unknown flag!"); + hasData = true; + break; + case ESM::FourCC<'A','N','A','M'>::value: + { + std::string faction = esm.getHString(); + int reaction; + esm.getHNT(reaction, "INTV"); + mReactions[faction] = reaction; + break; + } + default: + esm.fail("Unknown subrecord"); + } } + if (!hasData) + esm.fail("Missing FADT subrecord"); } void Faction::save(ESMWriter &esm) const { diff --git a/components/esm/loadgmst.hpp b/components/esm/loadgmst.hpp index 6b66ac832..398b8047f 100644 --- a/components/esm/loadgmst.hpp +++ b/components/esm/loadgmst.hpp @@ -12,7 +12,7 @@ class ESMReader; class ESMWriter; /* - * Game setting, with automatic cleaning of "dirty" entries. + * Game setting * */ diff --git a/components/esm/loadingr.cpp b/components/esm/loadingr.cpp index 5c98cb8b9..7e0cc3168 100644 --- a/components/esm/loadingr.cpp +++ b/components/esm/loadingr.cpp @@ -8,45 +8,71 @@ namespace ESM { unsigned int Ingredient::sRecordId = REC_INGR; -void Ingredient::load(ESMReader &esm) -{ - mModel = esm.getHNString("MODL"); - mName = esm.getHNOString("FNAM"); - esm.getHNT(mData, "IRDT", 56); - mScript = esm.getHNOString("SCRI"); - mIcon = esm.getHNOString("ITEX"); - // horrible hack to fix broken data in records - for (int i=0; i<4; ++i) + void Ingredient::load(ESMReader &esm) { - if (mData.mEffectID[i] != 85 && - mData.mEffectID[i] != 22 && - mData.mEffectID[i] != 17 && - mData.mEffectID[i] != 79 && - mData.mEffectID[i] != 74) + bool hasData = false; + while (esm.hasMoreSubs()) { - mData.mAttributes[i] = -1; + esm.getSubName(); + uint32_t name = esm.retSubName().val; + switch (name) + { + case ESM::FourCC<'M','O','D','L'>::value: + mModel = esm.getHString(); + break; + case ESM::FourCC<'F','N','A','M'>::value: + mName = esm.getHString(); + break; + case ESM::FourCC<'I','R','D','T'>::value: + esm.getHT(mData, 56); + hasData = true; + break; + case ESM::FourCC<'S','C','R','I'>::value: + mScript = esm.getHString(); + break; + case ESM::FourCC<'I','T','E','X'>::value: + mIcon = esm.getHString(); + break; + default: + esm.fail("Unknown subrecord"); + } } - // is this relevant in cycle from 0 to 4? - if (mData.mEffectID[i] != 89 && - mData.mEffectID[i] != 26 && - mData.mEffectID[i] != 21 && - mData.mEffectID[i] != 83 && - mData.mEffectID[i] != 78) + if (!hasData) + esm.fail("Missing IRDT subrecord"); + + // horrible hack to fix broken data in records + for (int i=0; i<4; ++i) { - mData.mSkills[i] = -1; + if (mData.mEffectID[i] != 85 && + mData.mEffectID[i] != 22 && + mData.mEffectID[i] != 17 && + mData.mEffectID[i] != 79 && + mData.mEffectID[i] != 74) + { + mData.mAttributes[i] = -1; + } + + // is this relevant in cycle from 0 to 4? + if (mData.mEffectID[i] != 89 && + mData.mEffectID[i] != 26 && + mData.mEffectID[i] != 21 && + mData.mEffectID[i] != 83 && + mData.mEffectID[i] != 78) + { + mData.mSkills[i] = -1; + } } } -} -void Ingredient::save(ESMWriter &esm) const -{ - esm.writeHNCString("MODL", mModel); - esm.writeHNOCString("FNAM", mName); - esm.writeHNT("IRDT", mData, 56); - esm.writeHNOCString("SCRI", mScript); - esm.writeHNOCString("ITEX", mIcon); -} + void Ingredient::save(ESMWriter &esm) const + { + esm.writeHNCString("MODL", mModel); + esm.writeHNOCString("FNAM", mName); + esm.writeHNT("IRDT", mData, 56); + esm.writeHNOCString("SCRI", mScript); + esm.writeHNOCString("ITEX", mIcon); + } void Ingredient::blank() { diff --git a/components/esm/loadland.cpp b/components/esm/loadland.cpp index ae73eee52..b1c01fcba 100644 --- a/components/esm/loadland.cpp +++ b/components/esm/loadland.cpp @@ -11,7 +11,7 @@ namespace ESM void Land::LandData::save(ESMWriter &esm) { if (mDataTypes & Land::DATA_VNML) { - esm.writeHNT("VNML", mNormals, sizeof(VNML)); + esm.writeHNT("VNML", mNormals, sizeof(mNormals)); } if (mDataTypes & Land::DATA_VHGT) { VHGT offsets; diff --git a/components/esm/loadlevlist.cpp b/components/esm/loadlevlist.cpp index 2cbfac0b4..ca5c5d74d 100644 --- a/components/esm/loadlevlist.cpp +++ b/components/esm/loadlevlist.cpp @@ -7,49 +7,51 @@ namespace ESM { -void LevelledListBase::load(ESMReader &esm) -{ - esm.getHNT(mFlags, "DATA"); - esm.getHNT(mChanceNone, "NNAM"); - - if (esm.isNextSub("INDX")) + void LevelledListBase::load(ESMReader &esm) { - int len; - esm.getHT(len); - mList.resize(len); - } - else - { - esm.skipRecord(); - return; - } + esm.getHNT(mFlags, "DATA"); + esm.getHNT(mChanceNone, "NNAM"); - // If this levelled list was already loaded by a previous content file, - // we overwrite the list. Merging lists should probably be left to external tools, - // with the limited amount of information there is in the records, all merging methods - // will be flawed in some way. For a proper fix the ESM format would have to be changed - // to actually track list changes instead of including the whole list for every file - // that does something with that list. + if (esm.isNextSub("INDX")) + { + int len; + esm.getHT(len); + mList.resize(len); + } + else + { + // Original engine ignores rest of the record, even if there are items following + mList.clear(); + esm.skipRecord(); + return; + } - for (size_t i = 0; i < mList.size(); i++) - { - LevelItem &li = mList[i]; - li.mId = esm.getHNString(mRecName); - esm.getHNT(li.mLevel, "INTV"); - } -} -void LevelledListBase::save(ESMWriter &esm) const -{ - esm.writeHNT("DATA", mFlags); - esm.writeHNT("NNAM", mChanceNone); - esm.writeHNT("INDX", mList.size()); + // If this levelled list was already loaded by a previous content file, + // we overwrite the list. Merging lists should probably be left to external tools, + // with the limited amount of information there is in the records, all merging methods + // will be flawed in some way. For a proper fix the ESM format would have to be changed + // to actually track list changes instead of including the whole list for every file + // that does something with that list. - for (std::vector::const_iterator it = mList.begin(); it != mList.end(); ++it) - { - esm.writeHNCString(mRecName, it->mId); - esm.writeHNT("INTV", it->mLevel); + for (size_t i = 0; i < mList.size(); i++) + { + LevelItem &li = mList[i]; + li.mId = esm.getHNString(mRecName); + esm.getHNT(li.mLevel, "INTV"); + } + } + void LevelledListBase::save(ESMWriter &esm) const + { + esm.writeHNT("DATA", mFlags); + esm.writeHNT("NNAM", mChanceNone); + esm.writeHNT("INDX", mList.size()); + + for (std::vector::const_iterator it = mList.begin(); it != mList.end(); ++it) + { + esm.writeHNCString(mRecName, it->mId); + esm.writeHNT("INTV", it->mLevel); + } } -} void LevelledListBase::blank() { diff --git a/components/esm/loadligh.cpp b/components/esm/loadligh.cpp index f88ff09d6..26d70d964 100644 --- a/components/esm/loadligh.cpp +++ b/components/esm/loadligh.cpp @@ -8,25 +8,50 @@ namespace ESM { unsigned int Light::sRecordId = REC_LIGH; -void Light::load(ESMReader &esm) -{ - mModel = esm.getHNOString("MODL"); - mName = esm.getHNOString("FNAM"); - mIcon = esm.getHNOString("ITEX"); - assert(sizeof(mData) == 24); - esm.getHNT(mData, "LHDT", 24); - mScript = esm.getHNOString("SCRI"); - mSound = esm.getHNOString("SNAM"); -} -void Light::save(ESMWriter &esm) const -{ - esm.writeHNCString("MODL", mModel); - esm.writeHNOCString("FNAM", mName); - esm.writeHNOCString("ITEX", mIcon); - esm.writeHNT("LHDT", mData, 24); - esm.writeHNOCString("SCRI", mScript); - esm.writeHNOCString("SNAM", mSound); -} + void Light::load(ESMReader &esm) + { + bool hasData = false; + while (esm.hasMoreSubs()) + { + esm.getSubName(); + uint32_t name = esm.retSubName().val; + switch (name) + { + case ESM::FourCC<'M','O','D','L'>::value: + mModel = esm.getHString(); + break; + case ESM::FourCC<'F','N','A','M'>::value: + mName = esm.getHString(); + break; + case ESM::FourCC<'I','T','E','X'>::value: + mIcon = esm.getHString(); + break; + case ESM::FourCC<'L','H','D','T'>::value: + esm.getHT(mData, 24); + hasData = true; + break; + case ESM::FourCC<'S','C','R','I'>::value: + mScript = esm.getHString(); + break; + case ESM::FourCC<'S','N','A','M'>::value: + mSound = esm.getHString(); + break; + default: + esm.fail("Unknown subrecord"); + } + } + if (!hasData) + esm.fail("Missing LHDT subrecord"); + } + void Light::save(ESMWriter &esm) const + { + esm.writeHNCString("MODL", mModel); + esm.writeHNOCString("FNAM", mName); + esm.writeHNOCString("ITEX", mIcon); + esm.writeHNT("LHDT", mData, 24); + esm.writeHNOCString("SCRI", mScript); + esm.writeHNOCString("SNAM", mSound); + } void Light::blank() { diff --git a/components/esm/loadlock.cpp b/components/esm/loadlock.cpp index 42677a22b..2747a6f78 100644 --- a/components/esm/loadlock.cpp +++ b/components/esm/loadlock.cpp @@ -8,26 +8,48 @@ namespace ESM { unsigned int Lockpick::sRecordId = REC_LOCK; -void Lockpick::load(ESMReader &esm) -{ - mModel = esm.getHNString("MODL"); - mName = esm.getHNOString("FNAM"); + void Lockpick::load(ESMReader &esm) + { + bool hasData = true; + while (esm.hasMoreSubs()) + { + esm.getSubName(); + uint32_t name = esm.retSubName().val; + switch (name) + { + case ESM::FourCC<'M','O','D','L'>::value: + mModel = esm.getHString(); + break; + case ESM::FourCC<'F','N','A','M'>::value: + mName = esm.getHString(); + break; + case ESM::FourCC<'L','K','D','T'>::value: + esm.getHT(mData, 16); + hasData = true; + break; + case ESM::FourCC<'S','C','R','I'>::value: + mScript = esm.getHString(); + break; + case ESM::FourCC<'I','T','E','X'>::value: + mIcon = esm.getHString(); + break; + default: + esm.fail("Unknown subrecord"); + } + } + if (!hasData) + esm.fail("Missing LKDT subrecord"); + } - esm.getHNT(mData, "LKDT", 16); + void Lockpick::save(ESMWriter &esm) const + { + esm.writeHNCString("MODL", mModel); + esm.writeHNOCString("FNAM", mName); - mScript = esm.getHNOString("SCRI"); - mIcon = esm.getHNOString("ITEX"); -} - -void Lockpick::save(ESMWriter &esm) const -{ - esm.writeHNCString("MODL", mModel); - esm.writeHNOCString("FNAM", mName); - - esm.writeHNT("LKDT", mData, 16); - esm.writeHNOString("SCRI", mScript); - esm.writeHNOCString("ITEX", mIcon); -} + esm.writeHNT("LKDT", mData, 16); + esm.writeHNOString("SCRI", mScript); + esm.writeHNOCString("ITEX", mIcon); + } void Lockpick::blank() { diff --git a/components/esm/loadmgef.cpp b/components/esm/loadmgef.cpp index 3ec07a2a9..6f859ab3c 100644 --- a/components/esm/loadmgef.cpp +++ b/components/esm/loadmgef.cpp @@ -246,7 +246,7 @@ void MagicEffect::load(ESMReader &esm) mDescription = esm.getHString(); break; default: - esm.fail("Unknown subrecord " + esm.retSubName().toString()); + esm.fail("Unknown subrecord"); } } } diff --git a/components/esm/loadmgef.hpp b/components/esm/loadmgef.hpp index 4c7ac938a..e66322832 100644 --- a/components/esm/loadmgef.hpp +++ b/components/esm/loadmgef.hpp @@ -57,9 +57,9 @@ struct MagicEffect // Glow color for enchanted items with this effect int mRed, mGreen, mBlue; - float mUnknown1; + float mUnknown1; // Called "Size X" in CS float mSpeed; // Speed of fired projectile - float mUnknown2; + float mUnknown2; // Called "Size Cap" in CS }; // 36 bytes static const std::map sNames; diff --git a/components/esm/loadnpc.cpp b/components/esm/loadnpc.cpp index 3d617241b..751c7f252 100644 --- a/components/esm/loadnpc.cpp +++ b/components/esm/loadnpc.cpp @@ -10,11 +10,11 @@ namespace ESM void NPC::load(ESMReader &esm) { - mPersistent = esm.getRecordFlags() & 0x0400; + mPersistent = (esm.getRecordFlags() & 0x0400) != 0; mSpells.mList.clear(); mInventory.mList.clear(); - mTransport.clear(); + mTransport.mList.clear(); mAiPackage.mList.clear(); bool hasNpdt = false; @@ -81,14 +81,8 @@ namespace ESM mHasAI= true; break; case ESM::FourCC<'D','O','D','T'>::value: - { - Dest dodt; - esm.getHExact(&dodt.mPos, 24); - mTransport.push_back(dodt); - break; - } case ESM::FourCC<'D','N','A','M'>::value: - mTransport.back().mCellName = esm.getHString(); + mTransport.add(esm); break; case AI_Wander: case AI_Activate: @@ -99,7 +93,7 @@ namespace ESM mAiPackage.add(esm); break; default: - esm.fail("Unknown subrecord " + esm.retSubName().toString()); + esm.fail("Unknown subrecord"); } } if (!hasNpdt) @@ -131,11 +125,8 @@ namespace ESM esm.writeHNT("AIDT", mAiData, sizeof(mAiData)); } - typedef std::vector::const_iterator DestIter; - for (DestIter it = mTransport.begin(); it != mTransport.end(); ++it) { - esm.writeHNT("DODT", it->mPos, sizeof(it->mPos)); - esm.writeHNOCString("DNAM", it->mCellName); - } + mTransport.save(esm); + mAiPackage.save(esm); } @@ -177,7 +168,7 @@ namespace ESM mSpells.mList.clear(); mAiData.blank(); mHasAI = false; - mTransport.clear(); + mTransport.mList.clear(); mAiPackage.mList.clear(); mName.clear(); mModel.clear(); @@ -198,4 +189,9 @@ namespace ESM else // NPC_DEFAULT return mNpdt52.mRank; } + + const std::vector& NPC::getTransport() const + { + return mTransport.mList; + } } diff --git a/components/esm/loadnpc.hpp b/components/esm/loadnpc.hpp index 9dc3be513..b535b91b0 100644 --- a/components/esm/loadnpc.hpp +++ b/components/esm/loadnpc.hpp @@ -9,6 +9,7 @@ #include "aipackage.hpp" #include "spelllist.hpp" #include "loadskil.hpp" +#include "transport.hpp" namespace ESM { @@ -98,12 +99,6 @@ struct NPC char mUnknown1, mUnknown2, mUnknown3; int mGold; }; // 12 bytes - - struct Dest - { - Position mPos; - std::string mCellName; - }; #pragma pack(pop) unsigned char mNpdtType; @@ -122,7 +117,10 @@ struct NPC AIData mAiData; bool mHasAI; - std::vector mTransport; + Transport mTransport; + + const std::vector& getTransport() const; + AIPackageList mAiPackage; std::string mId, mName, mModel, mRace, mClass, mFaction, mScript; diff --git a/components/esm/loadpgrd.cpp b/components/esm/loadpgrd.cpp index 61f56b511..fc0974c9d 100644 --- a/components/esm/loadpgrd.cpp +++ b/components/esm/loadpgrd.cpp @@ -10,22 +10,22 @@ namespace ESM Pathgrid::Point& Pathgrid::Point::operator=(const float rhs[3]) { - mX = rhs[0]; - mY = rhs[1]; - mZ = rhs[2]; + mX = static_cast(rhs[0]); + mY = static_cast(rhs[1]); + mZ = static_cast(rhs[2]); mAutogenerated = 0; mConnectionNum = 0; mUnknown = 0; return *this; } Pathgrid::Point::Point(const float rhs[3]) - : mAutogenerated(0), + : mX(static_cast(rhs[0])), + mY(static_cast(rhs[1])), + mZ(static_cast(rhs[2])), + mAutogenerated(0), mConnectionNum(0), mUnknown(0) { - mX = rhs[0]; - mY = rhs[1]; - mZ = rhs[2]; } Pathgrid::Point::Point():mX(0),mY(0),mZ(0),mAutogenerated(0), mConnectionNum(0),mUnknown(0) diff --git a/components/esm/loadprob.cpp b/components/esm/loadprob.cpp index b736bb64b..c5f80c584 100644 --- a/components/esm/loadprob.cpp +++ b/components/esm/loadprob.cpp @@ -8,26 +8,48 @@ namespace ESM { unsigned int Probe::sRecordId = REC_PROB; -void Probe::load(ESMReader &esm) -{ - mModel = esm.getHNString("MODL"); - mName = esm.getHNOString("FNAM"); + void Probe::load(ESMReader &esm) + { + bool hasData = true; + while (esm.hasMoreSubs()) + { + esm.getSubName(); + uint32_t name = esm.retSubName().val; + switch (name) + { + case ESM::FourCC<'M','O','D','L'>::value: + mModel = esm.getHString(); + break; + case ESM::FourCC<'F','N','A','M'>::value: + mName = esm.getHString(); + break; + case ESM::FourCC<'P','B','D','T'>::value: + esm.getHT(mData, 16); + hasData = true; + break; + case ESM::FourCC<'S','C','R','I'>::value: + mScript = esm.getHString(); + break; + case ESM::FourCC<'I','T','E','X'>::value: + mIcon = esm.getHString(); + break; + default: + esm.fail("Unknown subrecord"); + } + } + if (!hasData) + esm.fail("Missing PBDT subrecord"); + } - esm.getHNT(mData, "PBDT", 16); + void Probe::save(ESMWriter &esm) const + { + esm.writeHNCString("MODL", mModel); + esm.writeHNOCString("FNAM", mName); - mScript = esm.getHNOString("SCRI"); - mIcon = esm.getHNOString("ITEX"); -} - -void Probe::save(ESMWriter &esm) const -{ - esm.writeHNCString("MODL", mModel); - esm.writeHNOCString("FNAM", mName); - - esm.writeHNT("PBDT", mData, 16); - esm.writeHNOString("SCRI", mScript); - esm.writeHNOCString("ITEX", mIcon); -} + esm.writeHNT("PBDT", mData, 16); + esm.writeHNOString("SCRI", mScript); + esm.writeHNOCString("ITEX", mIcon); + } void Probe::blank() { diff --git a/components/esm/loadrace.cpp b/components/esm/loadrace.cpp index 211fd5ffb..e88454d4c 100644 --- a/components/esm/loadrace.cpp +++ b/components/esm/loadrace.cpp @@ -15,7 +15,7 @@ namespace ESM int Race::MaleFemaleF::getValue (bool male) const { - return male ? mMale : mFemale; + return static_cast(male ? mMale : mFemale); } void Race::load(ESMReader &esm) @@ -43,7 +43,7 @@ void Race::load(ESMReader &esm) mPowers.add(esm); break; default: - esm.fail("Unknown subrecord " + esm.retSubName().toString()); + esm.fail("Unknown subrecord"); } } if (!hasData) diff --git a/components/esm/loadrepa.cpp b/components/esm/loadrepa.cpp index 4e6cd7794..f90f9e39d 100644 --- a/components/esm/loadrepa.cpp +++ b/components/esm/loadrepa.cpp @@ -10,13 +10,35 @@ namespace ESM void Repair::load(ESMReader &esm) { - mModel = esm.getHNString("MODL"); - mName = esm.getHNOString("FNAM"); - - esm.getHNT(mData, "RIDT", 16); - - mScript = esm.getHNOString("SCRI"); - mIcon = esm.getHNOString("ITEX"); + bool hasData = true; + while (esm.hasMoreSubs()) + { + esm.getSubName(); + uint32_t name = esm.retSubName().val; + switch (name) + { + case ESM::FourCC<'M','O','D','L'>::value: + mModel = esm.getHString(); + break; + case ESM::FourCC<'F','N','A','M'>::value: + mName = esm.getHString(); + break; + case ESM::FourCC<'R','I','D','T'>::value: + esm.getHT(mData, 16); + hasData = true; + break; + case ESM::FourCC<'S','C','R','I'>::value: + mScript = esm.getHString(); + break; + case ESM::FourCC<'I','T','E','X'>::value: + mIcon = esm.getHString(); + break; + default: + esm.fail("Unknown subrecord"); + } + } + if (!hasData) + esm.fail("Missing RIDT subrecord"); } void Repair::save(ESMWriter &esm) const diff --git a/components/esm/loadscpt.cpp b/components/esm/loadscpt.cpp index d9eb7290c..fd807ddd3 100644 --- a/components/esm/loadscpt.cpp +++ b/components/esm/loadscpt.cpp @@ -11,17 +11,7 @@ namespace ESM unsigned int Script::sRecordId = REC_SCPT; -void Script::load(ESMReader &esm) -{ - SCHD data; - esm.getHNT(data, "SCHD", 52); - mData = data.mData; - mId = data.mName.toString(); - - mVarNames.clear(); - - // List of local variables - if (esm.isNextSub("SCVR")) + void Script::loadSCVR(ESMReader &esm) { int s = mData.mStringTableSize; @@ -68,58 +58,70 @@ void Script::load(ESMReader &esm) } } - // Script mData - if (esm.isNextSub("SCDT")) + void Script::load(ESMReader &esm) { - mScriptData.resize(mData.mScriptDataSize); - esm.getHExact(&mScriptData[0], mScriptData.size()); - } + SCHD data; + esm.getHNT(data, "SCHD", 52); + mData = data.mData; + mId = data.mName.toString(); - // Script text - mScriptText = esm.getHNOString("SCTX"); + mVarNames.clear(); - // NOTE: A minor hack/workaround... - // - // MAO_Containers.esp from Morrowind Acoustic Overhaul has SCVR records - // at the end (see Bug #1849). Since OpenMW does not use SCVR subrecords - // for variable names just skip these as a quick fix. An alternative - // solution would be to decode and validate SCVR subrecords even if they - // appear here. - if (esm.isNextSub("SCVR")) { - esm.skipHSub(); - } -} -void Script::save(ESMWriter &esm) const -{ - std::string varNameString; - if (!mVarNames.empty()) - for (std::vector::const_iterator it = mVarNames.begin(); it != mVarNames.end(); ++it) - varNameString.append(*it); - - SCHD data; - memset(&data, 0, sizeof(data)); - - data.mData = mData; - memcpy(data.mName.name, mId.c_str(), mId.size()); - - esm.writeHNT("SCHD", data, 52); - - if (!mVarNames.empty()) - { - esm.startSubRecord("SCVR"); - for (std::vector::const_iterator it = mVarNames.begin(); it != mVarNames.end(); ++it) + while (esm.hasMoreSubs()) { - esm.writeHCString(*it); + esm.getSubName(); + uint32_t name = esm.retSubName().val; + switch (name) + { + case ESM::FourCC<'S','C','V','R'>::value: + // list of local variables + loadSCVR(esm); + break; + case ESM::FourCC<'S','C','D','T'>::value: + // compiled script + mScriptData.resize(mData.mScriptDataSize); + esm.getHExact(&mScriptData[0], mScriptData.size()); + break; + case ESM::FourCC<'S','C','T','X'>::value: + mScriptText = esm.getHString(); + break; + default: + esm.fail("Unknown subrecord"); + } } - esm.endRecord("SCVR"); } - esm.startSubRecord("SCDT"); - esm.write(reinterpret_cast(&mScriptData[0]), mData.mScriptDataSize); - esm.endRecord("SCDT"); + void Script::save(ESMWriter &esm) const + { + std::string varNameString; + if (!mVarNames.empty()) + for (std::vector::const_iterator it = mVarNames.begin(); it != mVarNames.end(); ++it) + varNameString.append(*it); - esm.writeHNOString("SCTX", mScriptText); -} + SCHD data; + memset(&data, 0, sizeof(data)); + + data.mData = mData; + memcpy(data.mName.name, mId.c_str(), mId.size()); + + esm.writeHNT("SCHD", data, 52); + + if (!mVarNames.empty()) + { + esm.startSubRecord("SCVR"); + for (std::vector::const_iterator it = mVarNames.begin(); it != mVarNames.end(); ++it) + { + esm.writeHCString(*it); + } + esm.endRecord("SCVR"); + } + + esm.startSubRecord("SCDT"); + esm.write(reinterpret_cast(&mScriptData[0]), mData.mScriptDataSize); + esm.endRecord("SCDT"); + + esm.writeHNOString("SCTX", mScriptText); + } void Script::blank() { diff --git a/components/esm/loadscpt.hpp b/components/esm/loadscpt.hpp index d5b87b5dc..deb71de6a 100644 --- a/components/esm/loadscpt.hpp +++ b/components/esm/loadscpt.hpp @@ -53,6 +53,9 @@ public: void blank(); ///< Set record to default state (does not touch the ID/index). + +private: + void loadSCVR(ESMReader &esm); }; } #endif diff --git a/components/esm/loadskil.cpp b/components/esm/loadskil.cpp index b6724e938..7883b8a1a 100644 --- a/components/esm/loadskil.cpp +++ b/components/esm/loadskil.cpp @@ -129,23 +129,47 @@ namespace ESM unsigned int Skill::sRecordId = REC_SKIL; -void Skill::load(ESMReader &esm) -{ - esm.getHNT(mIndex, "INDX"); - esm.getHNT(mData, "SKDT", 24); - mDescription = esm.getHNOString("DESC"); + void Skill::load(ESMReader &esm) + { + bool hasIndex = false; + bool hasData = false; + while (esm.hasMoreSubs()) + { + esm.getSubName(); + uint32_t name = esm.retSubName().val; + switch (name) + { + case ESM::FourCC<'I','N','D','X'>::value: + esm.getHT(mIndex); + hasIndex = true; + break; + case ESM::FourCC<'S','K','D','T'>::value: + esm.getHT(mData, 24); + hasData = true; + break; + case ESM::FourCC<'D','E','S','C'>::value: + mDescription = esm.getHString(); + break; + default: + esm.fail("Unknown subrecord"); + } + } + if (!hasIndex) + esm.fail("Missing INDX"); + if (!hasData) + esm.fail("Missing SKDT"); - // create an ID from the index and the name (only used in the editor and likely to change in the - // future) - mId = indexToId (mIndex); -} + // create an ID from the index and the name (only used in the editor and likely to change in the + // future) + mId = indexToId (mIndex); + } -void Skill::save(ESMWriter &esm) const -{ - esm.writeHNT("INDX", mIndex); - esm.writeHNT("SKDT", mData, 24); - esm.writeHNOString("DESC", mDescription); -} + void Skill::save(ESMWriter &esm) const + { + esm.writeHNT("INDX", mIndex); + esm.writeHNT("SKDT", mData, 24); + esm.writeHNOString("DESC", mDescription); + } void Skill::blank() { diff --git a/components/esm/loadsndg.cpp b/components/esm/loadsndg.cpp index 9ab061ec2..5ee6f5245 100644 --- a/components/esm/loadsndg.cpp +++ b/components/esm/loadsndg.cpp @@ -8,19 +8,38 @@ namespace ESM { unsigned int SoundGenerator::sRecordId = REC_SNDG; -void SoundGenerator::load(ESMReader &esm) -{ - esm.getHNT(mType, "DATA", 4); - - mCreature = esm.getHNOString("CNAM"); - mSound = esm.getHNOString("SNAM"); -} -void SoundGenerator::save(ESMWriter &esm) const -{ - esm.writeHNT("DATA", mType, 4); - esm.writeHNOCString("CNAM", mCreature); - esm.writeHNOCString("SNAM", mSound); -} + void SoundGenerator::load(ESMReader &esm) + { + bool hasData = false; + while (esm.hasMoreSubs()) + { + esm.getSubName(); + uint32_t name = esm.retSubName().val; + switch (name) + { + case ESM::FourCC<'D','A','T','A'>::value: + esm.getHT(mType, 4); + hasData = true; + break; + case ESM::FourCC<'C','N','A','M'>::value: + mCreature = esm.getHString(); + break; + case ESM::FourCC<'S','N','A','M'>::value: + mSound = esm.getHString(); + break; + default: + esm.fail("Unknown subrecord"); + } + } + if (!hasData) + esm.fail("Missing DATA"); + } + void SoundGenerator::save(ESMWriter &esm) const + { + esm.writeHNT("DATA", mType, 4); + esm.writeHNOCString("CNAM", mCreature); + esm.writeHNOCString("SNAM", mSound); + } void SoundGenerator::blank() { diff --git a/components/esm/loadsoun.cpp b/components/esm/loadsoun.cpp index 28e4d7d9c..690c1b448 100644 --- a/components/esm/loadsoun.cpp +++ b/components/esm/loadsoun.cpp @@ -8,22 +8,35 @@ namespace ESM { unsigned int Sound::sRecordId = REC_SOUN; -void Sound::load(ESMReader &esm) -{ - mSound = esm.getHNOString("FNAM"); - esm.getHNT(mData, "DATA", 3); - /* - cout << "vol=" << (int)data.volume - << " min=" << (int)data.minRange - << " max=" << (int)data.maxRange - << endl; - */ -} -void Sound::save(ESMWriter &esm) const -{ - esm.writeHNOCString("FNAM", mSound); - esm.writeHNT("DATA", mData, 3); -} + void Sound::load(ESMReader &esm) + { + bool hasData = false; + while (esm.hasMoreSubs()) + { + esm.getSubName(); + uint32_t name = esm.retSubName().val; + switch (name) + { + case ESM::FourCC<'F','N','A','M'>::value: + mSound = esm.getHString(); + break; + case ESM::FourCC<'D','A','T','A'>::value: + esm.getHT(mData, 3); + hasData = true; + break; + default: + esm.fail("Unknown subrecord"); + } + } + if (!hasData) + esm.fail("Missing DATA"); + } + + void Sound::save(ESMWriter &esm) const + { + esm.writeHNOCString("FNAM", mSound); + esm.writeHNT("DATA", mData, 3); + } void Sound::blank() { diff --git a/components/esm/loadspel.cpp b/components/esm/loadspel.cpp index 716f47e71..96c048e0a 100644 --- a/components/esm/loadspel.cpp +++ b/components/esm/loadspel.cpp @@ -8,40 +8,41 @@ namespace ESM { unsigned int Spell::sRecordId = REC_SPEL; -void Spell::load(ESMReader &esm) -{ - bool hasData = false; - while (esm.hasMoreSubs()) + void Spell::load(ESMReader &esm) { - esm.getSubName(); - uint32_t val = esm.retSubName().val; - - switch (val) + mEffects.mList.clear(); + bool hasData = false; + while (esm.hasMoreSubs()) { - case ESM::FourCC<'F','N','A','M'>::value: - mName = esm.getHString(); - break; - case ESM::FourCC<'S','P','D','T'>::value: - esm.getHT(mData, 12); - hasData = true; - break; - case ESM::FourCC<'E','N','A','M'>::value: - ENAMstruct s; - esm.getHT(s, 24); - mEffects.mList.push_back(s); - break; - } - } - if (!hasData) - esm.fail("Missing SPDT subrecord"); -} + esm.getSubName(); + uint32_t val = esm.retSubName().val; -void Spell::save(ESMWriter &esm) const -{ - esm.writeHNOCString("FNAM", mName); - esm.writeHNT("SPDT", mData, 12); - mEffects.save(esm); -} + switch (val) + { + case ESM::FourCC<'F','N','A','M'>::value: + mName = esm.getHString(); + break; + case ESM::FourCC<'S','P','D','T'>::value: + esm.getHT(mData, 12); + hasData = true; + break; + case ESM::FourCC<'E','N','A','M'>::value: + ENAMstruct s; + esm.getHT(s, 24); + mEffects.mList.push_back(s); + break; + } + } + if (!hasData) + esm.fail("Missing SPDT subrecord"); + } + + void Spell::save(ESMWriter &esm) const + { + esm.writeHNOCString("FNAM", mName); + esm.writeHNT("SPDT", mData, 12); + mEffects.save(esm); + } void Spell::blank() { diff --git a/components/esm/loadsscr.cpp b/components/esm/loadsscr.cpp index 69b04bb23..7380dd0a7 100644 --- a/components/esm/loadsscr.cpp +++ b/components/esm/loadsscr.cpp @@ -8,15 +8,41 @@ namespace ESM { unsigned int StartScript::sRecordId = REC_SSCR; -void StartScript::load(ESMReader &esm) -{ - mData = esm.getHNString("DATA"); - mScript = esm.getHNString("NAME"); -} -void StartScript::save(ESMWriter &esm) const -{ - esm.writeHNString("DATA", mData); - esm.writeHNString("NAME", mScript); -} + void StartScript::load(ESMReader &esm) + { + bool hasData = false; + bool hasName = false; + while (esm.hasMoreSubs()) + { + esm.getSubName(); + uint32_t name = esm.retSubName().val; + switch (name) + { + case ESM::FourCC<'D','A','T','A'>::value: + mData = esm.getHString(); + hasData = true; + break; + case ESM::FourCC<'N','A','M','E'>::value: + mId = esm.getHString(); + hasName = true; + break; + default: + esm.fail("Unknown subrecord"); + } + } + if (!hasData) + esm.fail("Missing DATA"); + if (!hasName) + esm.fail("Missing NAME"); + } + void StartScript::save(ESMWriter &esm) const + { + esm.writeHNString("DATA", mData); + esm.writeHNString("NAME", mId); + } + void StartScript::blank() + { + mData.clear(); + } } diff --git a/components/esm/loadsscr.hpp b/components/esm/loadsscr.hpp index d09ad883e..1420d16c4 100644 --- a/components/esm/loadsscr.hpp +++ b/components/esm/loadsscr.hpp @@ -22,11 +22,13 @@ struct StartScript static unsigned int sRecordId; std::string mData; - std::string mId, mScript; + std::string mId; // Load a record and add it to the list void load(ESMReader &esm); void save(ESMWriter &esm) const; + + void blank(); }; } diff --git a/components/esm/loadstat.cpp b/components/esm/loadstat.cpp index 53d1b4bb5..ed90b0475 100644 --- a/components/esm/loadstat.cpp +++ b/components/esm/loadstat.cpp @@ -8,15 +8,16 @@ namespace ESM { unsigned int Static::sRecordId = REC_STAT; -void Static::load(ESMReader &esm) -{ - mPersistent = esm.getRecordFlags() & 0x0400; - mModel = esm.getHNString("MODL"); -} -void Static::save(ESMWriter &esm) const -{ - esm.writeHNCString("MODL", mModel); -} + void Static::load(ESMReader &esm) + { + mPersistent = (esm.getRecordFlags() & 0x0400) != 0; + + mModel = esm.getHNString("MODL"); + } + void Static::save(ESMWriter &esm) const + { + esm.writeHNCString("MODL", mModel); + } void Static::blank() { diff --git a/components/esm/loadtes3.hpp b/components/esm/loadtes3.hpp index 2c63e3691..f2dde4d1f 100644 --- a/components/esm/loadtes3.hpp +++ b/components/esm/loadtes3.hpp @@ -50,8 +50,8 @@ namespace ESM NAME32 mPlayerName; }; GMDT mGameData; // Used in .ess savegames only - std::vector mSCRD; // Used in .ess savegames only, screenshot? - std::vector mSCRS; // Used in .ess savegames only, screenshot? + std::vector mSCRD; // Used in .ess savegames only, unknown + std::vector mSCRS; // Used in .ess savegames only, screenshot Data mData; int mFormat; diff --git a/components/esm/queststate.cpp b/components/esm/queststate.cpp index e93826725..c8cff7adc 100644 --- a/components/esm/queststate.cpp +++ b/components/esm/queststate.cpp @@ -16,4 +16,4 @@ void ESM::QuestState::save (ESMWriter &esm) const esm.writeHNString ("YETO", mTopic); esm.writeHNT ("QSTA", mState); esm.writeHNT ("QFIN", mFinished); -} \ No newline at end of file +} diff --git a/components/esm/spelllist.cpp b/components/esm/spelllist.cpp index 98bd53ae6..71c7b340d 100644 --- a/components/esm/spelllist.cpp +++ b/components/esm/spelllist.cpp @@ -5,14 +5,6 @@ namespace ESM { -void SpellList::load(ESMReader &esm) -{ - mList.clear(); - while (esm.isNextSub("NPCS")) { - add(esm); - } -} - void SpellList::add(ESMReader &esm) { mList.push_back(esm.getHString()); diff --git a/components/esm/spelllist.hpp b/components/esm/spelllist.hpp index 9493199a8..6fb098065 100644 --- a/components/esm/spelllist.hpp +++ b/components/esm/spelllist.hpp @@ -11,6 +11,7 @@ namespace ESM /** A list of references to spells and spell effects. This is shared between the records BSGN, NPC and RACE. + NPCS subrecord. */ struct SpellList { @@ -22,9 +23,6 @@ namespace ESM /// Load one spell, assumes the subrecord name was already read void add(ESMReader &esm); - /// Load all spells - /// TODO: remove this method, the ESM format doesn't guarantee that all spell subrecords follow one another - void load(ESMReader &esm); void save(ESMWriter &esm) const; }; } diff --git a/components/esm/statstate.hpp b/components/esm/statstate.hpp index 801d0ce82..f57ba9f30 100644 --- a/components/esm/statstate.hpp +++ b/components/esm/statstate.hpp @@ -40,7 +40,7 @@ namespace ESM // mDamage was changed to a float; ensure backwards compatibility T oldDamage = 0; esm.getHNOT(oldDamage, "STDA"); - mDamage = oldDamage; + mDamage = static_cast(oldDamage); esm.getHNOT (mDamage, "STDF"); diff --git a/components/esm/transport.cpp b/components/esm/transport.cpp new file mode 100644 index 000000000..da0a5f767 --- /dev/null +++ b/components/esm/transport.cpp @@ -0,0 +1,33 @@ +#include "transport.hpp" + +#include +#include + +namespace ESM +{ + + void Transport::add(ESMReader &esm) + { + if (esm.retSubName().val == ESM::FourCC<'D','O','D','T'>::value) + { + Dest dodt; + esm.getHExact(&dodt.mPos, 24); + mList.push_back(dodt); + } + else if (esm.retSubName().val == ESM::FourCC<'D','N','A','M'>::value) + { + mList.back().mCellName = esm.getHString(); + } + } + + void Transport::save(ESMWriter &esm) const + { + typedef std::vector::const_iterator DestIter; + for (DestIter it = mList.begin(); it != mList.end(); ++it) + { + esm.writeHNT("DODT", it->mPos, sizeof(it->mPos)); + esm.writeHNOCString("DNAM", it->mCellName); + } + } + +} diff --git a/components/esm/transport.hpp b/components/esm/transport.hpp new file mode 100644 index 000000000..10d4013f7 --- /dev/null +++ b/components/esm/transport.hpp @@ -0,0 +1,36 @@ +#ifndef OPENMW_COMPONENTS_ESM_TRANSPORT_H +#define OPENMW_COMPONENTS_ESM_TRANSPORT_H + +#include +#include + +#include "defs.hpp" + +namespace ESM +{ + + class ESMReader; + class ESMWriter; + + /// List of travel service destination. Shared by CREA and NPC_ records. + struct Transport + { + + struct Dest + { + Position mPos; + std::string mCellName; + }; + + std::vector mList; + + /// Load one destination, assumes the subrecord name was already read + void add(ESMReader &esm); + + void save(ESMWriter &esm) const; + + }; + +} + +#endif diff --git a/components/esm/variantimp.cpp b/components/esm/variantimp.cpp index fd068fc19..eeb0bf04f 100644 --- a/components/esm/variantimp.cpp +++ b/components/esm/variantimp.cpp @@ -128,7 +128,7 @@ int ESM::VariantIntegerData::getInteger (bool default_) const float ESM::VariantIntegerData::getFloat (bool default_) const { - return mValue; + return static_cast(mValue); } void ESM::VariantIntegerData::setInteger (int value) @@ -202,7 +202,7 @@ void ESM::VariantIntegerData::write (ESMWriter& esm, Variant::Format format, Var { if (type==VT_Short || type==VT_Long) { - float value = mValue; + float value = static_cast(mValue); esm.writeHNString ("FNAM", type==VT_Short ? "s" : "l"); esm.writeHNT ("FLTV", value); } @@ -262,7 +262,7 @@ float ESM::VariantFloatData::getFloat (bool default_) const void ESM::VariantFloatData::setInteger (int value) { - mValue = value; + mValue = static_cast(value); } void ESM::VariantFloatData::setFloat (float value) diff --git a/components/esmterrain/storage.cpp b/components/esmterrain/storage.cpp index 84a7ef568..5a69fd27a 100644 --- a/components/esmterrain/storage.cpp +++ b/components/esmterrain/storage.cpp @@ -27,8 +27,8 @@ namespace ESMTerrain assert(origin.x == (int) origin.x); assert(origin.y == (int) origin.y); - int cellX = origin.x; - int cellY = origin.y; + int cellX = static_cast(origin.x); + int cellY = static_cast(origin.y); const ESM::Land* land = getLand(cellX, cellY); if (!land || !(land->mDataTypes&ESM::Land::DATA_VHGT)) @@ -135,10 +135,10 @@ namespace ESMTerrain assert(origin.x == (int) origin.x); assert(origin.y == (int) origin.y); - int startX = origin.x; - int startY = origin.y; + int startX = static_cast(origin.x); + int startY = static_cast(origin.y); - size_t numVerts = size*(ESM::Land::LAND_SIZE-1)/increment + 1; + size_t numVerts = static_cast(size*(ESM::Land::LAND_SIZE - 1) / increment + 1); colours.resize(numVerts*numVerts*4); positions.resize(numVerts*numVerts*3); @@ -175,12 +175,12 @@ namespace ESMTerrain vertX = vertX_; for (int row=rowStart; row(vertX*numVerts * 3 + vertY * 3)] = ((vertX / float(numVerts - 1) - 0.5f) * size * 8192); + positions[static_cast(vertX*numVerts * 3 + vertY * 3 + 1)] = ((vertY / float(numVerts - 1) - 0.5f) * size * 8192); if (land) - positions[vertX*numVerts*3 + vertY*3 + 2] = land->mLandData->mHeights[col*ESM::Land::LAND_SIZE+row]; + positions[static_cast(vertX*numVerts * 3 + vertY * 3 + 2)] = land->mLandData->mHeights[col*ESM::Land::LAND_SIZE + row]; else - positions[vertX*numVerts*3 + vertY*3 + 2] = -2048; + positions[static_cast(vertX*numVerts * 3 + vertY * 3 + 2)] = -2048; if (land && land->mDataTypes&ESM::Land::DATA_VNML) { @@ -202,9 +202,9 @@ namespace ESMTerrain assert(normal.z > 0); - normals[vertX*numVerts*3 + vertY*3] = normal.x; - normals[vertX*numVerts*3 + vertY*3 + 1] = normal.y; - normals[vertX*numVerts*3 + vertY*3 + 2] = normal.z; + normals[static_cast(vertX*numVerts * 3 + vertY * 3)] = normal.x; + normals[static_cast(vertX*numVerts * 3 + vertY * 3 + 1)] = normal.y; + normals[static_cast(vertX*numVerts * 3 + vertY * 3 + 2)] = normal.z; if (land && land->mDataTypes&ESM::Land::DATA_VCLR) { @@ -226,7 +226,7 @@ namespace ESMTerrain color.a = 1; Ogre::uint32 rsColor; Ogre::Root::getSingleton().getRenderSystem()->convertColourValue(color, &rsColor); - memcpy(&colours[vertX*numVerts*4 + vertY*4], &rsColor, sizeof(Ogre::uint32)); + memcpy(&colours[static_cast(vertX*numVerts * 4 + vertY * 4)], &rsColor, sizeof(Ogre::uint32)); ++vertX; } @@ -294,7 +294,7 @@ namespace ESMTerrain { out.push_back(Terrain::LayerCollection()); out.back().mTarget = *it; - getBlendmapsImpl((*it)->getSize(), (*it)->getCenter(), pack, out.back().mBlendmaps, out.back().mLayers); + getBlendmapsImpl(static_cast((*it)->getSize()), (*it)->getCenter(), pack, out.back().mBlendmaps, out.back().mLayers); } } @@ -312,8 +312,8 @@ namespace ESMTerrain // and interpolate the rest of the cell by hand? :/ Ogre::Vector2 origin = chunkCenter - Ogre::Vector2(chunkSize/2.f, chunkSize/2.f); - int cellX = origin.x; - int cellY = origin.y; + int cellX = static_cast(origin.x); + int cellY = static_cast(origin.y); // Save the used texture indices so we know the total number of textures // and number of required blend maps @@ -344,7 +344,7 @@ namespace ESMTerrain int numTextures = textureIndices.size(); // numTextures-1 since the base layer doesn't need blending - int numBlendmaps = pack ? std::ceil((numTextures-1) / 4.f) : (numTextures-1); + int numBlendmaps = pack ? static_cast(std::ceil((numTextures - 1) / 4.f)) : (numTextures - 1); int channels = pack ? 4 : 1; @@ -365,7 +365,7 @@ namespace ESMTerrain { UniqueTextureId id = getVtexIndexAt(cellX, cellY, x, y); int layerIndex = textureIndicesMap.find(id)->second; - int blendIndex = (pack ? std::floor((layerIndex-1)/4.f) : layerIndex-1); + int blendIndex = (pack ? static_cast(std::floor((layerIndex - 1) / 4.f)) : layerIndex - 1); int channel = pack ? std::max(0, (layerIndex-1) % 4) : 0; if (blendIndex == i) @@ -380,11 +380,11 @@ namespace ESMTerrain float Storage::getHeightAt(const Ogre::Vector3 &worldPos) { - int cellX = std::floor(worldPos.x / 8192.f); - int cellY = std::floor(worldPos.y / 8192.f); + int cellX = static_cast(std::floor(worldPos.x / 8192.f)); + int cellY = static_cast(std::floor(worldPos.y / 8192.f)); ESM::Land* land = getLand(cellX, cellY); - if (!land) + if (!land || !(land->mDataTypes&ESM::Land::DATA_VHGT)) return -2048; // Mostly lifted from Ogre::Terrain::getHeightAtTerrainPosition @@ -466,8 +466,9 @@ namespace ESMTerrain Terrain::LayerInfo Storage::getLayerInfo(const std::string& texture) { // Already have this cached? - if (mLayerInfoMap.find(texture) != mLayerInfoMap.end()) - return mLayerInfoMap[texture]; + std::map::iterator found = mLayerInfoMap.find(texture); + if (found != mLayerInfoMap.end()) + return found->second; Terrain::LayerInfo info; info.mParallax = false; @@ -519,7 +520,7 @@ namespace ESMTerrain float Storage::getCellWorldSize() { - return ESM::Land::REAL_SIZE; + return static_cast(ESM::Land::REAL_SIZE); } int Storage::getCellVertices() diff --git a/components/files/androidpath.cpp b/components/files/androidpath.cpp index 117626095..84886f473 100644 --- a/components/files/androidpath.cpp +++ b/components/files/androidpath.cpp @@ -27,10 +27,11 @@ char const * Buffer::getData() } -JNIEXPORT void JNICALL Java_org_libsdl_app_SDLActivity_getPathToJni(JNIEnv *env, jobject obj, jstring prompt) +JNIEXPORT void JNICALL Java_ui_activity_GameActivity_getPathToJni(JNIEnv *env, jobject obj, jstring prompt) { jboolean iscopy; Buffer::setData((env)->GetStringUTFChars(prompt, &iscopy)); + (env)->DeleteLocalRef(prompt); } namespace diff --git a/components/files/androidpath.h b/components/files/androidpath.h index 3157c067f..a93a160e0 100644 --- a/components/files/androidpath.h +++ b/components/files/androidpath.h @@ -1,8 +1,8 @@ /* DO NOT EDIT THIS FILE - it is machine generated */ #include -#ifndef _Included_org_libsdl_app_SDLActivity_getPathToJni -#define _Included_org_libsdl_app_SDLActivity_getPathToJni +#ifndef _Included_ui_activity_GameActivity_getPathToJni +#define _Included_ui_activity_GameActivity_getPathToJni #ifdef __cplusplus extern "C" { #endif @@ -11,7 +11,7 @@ extern "C" { * Method: getPathToJni * Signature: (I)I */ -JNIEXPORT void JNICALL Java_org_libsdl_app_SDLActivity_getPathToJni(JNIEnv *env, jobject obj, jstring prompt); +JNIEXPORT void JNICALL Java_ui_activity_GameActivity_getPathToJni(JNIEnv *env, jobject obj, jstring prompt); #ifdef __cplusplus } diff --git a/components/files/macospath.cpp b/components/files/macospath.cpp index 3e53f5306..6e794796f 100644 --- a/components/files/macospath.cpp +++ b/components/files/macospath.cpp @@ -7,10 +7,6 @@ #include #include -/** - * FIXME: Someone with MacOS system should check this and correct if necessary - */ - namespace { boost::filesystem::path getUserHome() @@ -49,9 +45,8 @@ boost::filesystem::path MacOsPath::getUserConfigPath() const boost::filesystem::path MacOsPath::getUserDataPath() const { - // TODO: probably wrong? boost::filesystem::path userPath (getUserHome()); - userPath /= "Library/Preferences/"; + userPath /= "Library/Application Support/"; return userPath / mName; } diff --git a/components/files/windowspath.cpp b/components/files/windowspath.cpp index 6b58304a0..0df782702 100644 --- a/components/files/windowspath.cpp +++ b/components/files/windowspath.cpp @@ -94,18 +94,8 @@ boost::filesystem::path WindowsPath::getInstallPath() const HKEY hKey; - BOOL f64 = FALSE; - LPCTSTR regkey; - if ((IsWow64Process(GetCurrentProcess(), &f64) && f64) || sizeof(void*) == 8) - { - regkey = "SOFTWARE\\Wow6432Node\\Bethesda Softworks\\Morrowind"; - } - else - { - regkey = "SOFTWARE\\Bethesda Softworks\\Morrowind"; - } - - if (RegOpenKeyEx(HKEY_LOCAL_MACHINE, TEXT(regkey), 0, KEY_ALL_ACCESS, &hKey) == ERROR_SUCCESS) + LPCTSTR regkey = TEXT("SOFTWARE\\Bethesda Softworks\\Morrowind"); + if (RegOpenKeyEx(HKEY_LOCAL_MACHINE, regkey, 0, KEY_READ | KEY_WOW64_32KEY, &hKey) == ERROR_SUCCESS) { //Key existed, let's try to read the install dir std::vector buf(512); @@ -115,6 +105,7 @@ boost::filesystem::path WindowsPath::getInstallPath() const { installPath = &buf[0]; } + RegCloseKey(hKey); } return installPath; diff --git a/components/fontloader/fontloader.cpp b/components/fontloader/fontloader.cpp index 17c630fd9..eb7dd901d 100644 --- a/components/fontloader/fontloader.cpp +++ b/components/fontloader/fontloader.cpp @@ -20,12 +20,12 @@ namespace { size_t i = 0; unsigned long unicode; - size_t todo; + size_t numbytes; unsigned char ch = utf8[i++]; if (ch <= 0x7F) { unicode = ch; - todo = 0; + numbytes = 0; } else if (ch <= 0xBF) { @@ -34,23 +34,23 @@ namespace else if (ch <= 0xDF) { unicode = ch&0x1F; - todo = 1; + numbytes = 1; } else if (ch <= 0xEF) { unicode = ch&0x0F; - todo = 2; + numbytes = 2; } else if (ch <= 0xF7) { unicode = ch&0x07; - todo = 3; + numbytes = 3; } else { throw std::logic_error("not a UTF-8 string"); } - for (size_t j = 0; j < todo; ++j) + for (size_t j = 0; j < numbytes; ++j) { unsigned char ch = utf8[i++]; if (ch < 0x80 || ch > 0xBF) @@ -288,7 +288,7 @@ namespace Gui code->addAttribute("advance", data[i].width); code->addAttribute("bearing", MyGUI::utility::toString(data[i].kerning) + " " + MyGUI::utility::toString((fontSize-data[i].ascent))); - code->addAttribute("size", MyGUI::IntSize(data[i].width, data[i].height)); + code->addAttribute("size", MyGUI::IntSize(static_cast(data[i].width), static_cast(data[i].height))); // More hacks! The french game uses several win1252 characters that are not included // in the cp437 encoding of the font. Fall back to similar available characters. @@ -334,7 +334,7 @@ namespace Gui code->addAttribute("advance", data[i].width); code->addAttribute("bearing", MyGUI::utility::toString(data[i].kerning) + " " + MyGUI::utility::toString((fontSize-data[i].ascent))); - code->addAttribute("size", MyGUI::IntSize(data[i].width, data[i].height)); + code->addAttribute("size", MyGUI::IntSize(static_cast(data[i].width), static_cast(data[i].height))); } } @@ -350,7 +350,7 @@ namespace Gui cursorCode->addAttribute("advance", data[i].width); cursorCode->addAttribute("bearing", MyGUI::utility::toString(data[i].kerning) + " " + MyGUI::utility::toString((fontSize-data[i].ascent))); - cursorCode->addAttribute("size", MyGUI::IntSize(data[i].width, data[i].height)); + cursorCode->addAttribute("size", MyGUI::IntSize(static_cast(data[i].width), static_cast(data[i].height))); } // Question mark, use for NotDefined marker (used for glyphs not existing in the font) @@ -365,7 +365,7 @@ namespace Gui cursorCode->addAttribute("advance", data[i].width); cursorCode->addAttribute("bearing", MyGUI::utility::toString(data[i].kerning) + " " + MyGUI::utility::toString((fontSize-data[i].ascent))); - cursorCode->addAttribute("size", MyGUI::IntSize(data[i].width, data[i].height)); + cursorCode->addAttribute("size", MyGUI::IntSize(static_cast(data[i].width), static_cast(data[i].height))); } } diff --git a/components/interpreter/miscopcodes.hpp b/components/interpreter/miscopcodes.hpp index 1da8cf695..f566a5499 100644 --- a/components/interpreter/miscopcodes.hpp +++ b/components/interpreter/miscopcodes.hpp @@ -12,6 +12,8 @@ #include "runtime.hpp" #include "defines.hpp" +#include + namespace Interpreter { inline std::string formatMessage (const std::string& message, Runtime& runtime) @@ -140,15 +142,13 @@ namespace Interpreter virtual void execute (Runtime& runtime) { - double r = static_cast (std::rand()) / RAND_MAX; // [0, 1) - Type_Integer limit = runtime[0].mInteger; if (limit<0) throw std::runtime_error ( "random: argument out of range (Don't be so negative!)"); - Type_Integer value = static_cast (r*limit); // [o, limit) + Type_Integer value = OEngine::Misc::Rng::rollDice(limit); // [o, limit) runtime[0].mInteger = value; } diff --git a/components/nif/.gitignore b/components/nif/.gitignore deleted file mode 100644 index 731498d9a..000000000 --- a/components/nif/.gitignore +++ /dev/null @@ -1 +0,0 @@ -old_d diff --git a/components/nif/data.cpp b/components/nif/data.cpp index 4c9373029..3a06e4006 100644 --- a/components/nif/data.cpp +++ b/components/nif/data.cpp @@ -179,7 +179,7 @@ void NiVisData::read(NIFStream *nif) for(size_t i = 0;i < mVis.size();i++) { mVis[i].time = nif->getFloat(); - mVis[i].isSet = nif->getChar(); + mVis[i].isSet = (nif->getChar() != 0); } } diff --git a/components/nif/data.hpp b/components/nif/data.hpp index e3f1e2770..1b4d02f26 100644 --- a/components/nif/data.hpp +++ b/components/nif/data.hpp @@ -121,7 +121,7 @@ class NiVisData : public Record public: struct VisData { float time; - char isSet; + bool isSet; }; std::vector mVis; diff --git a/components/nif/node.cpp b/components/nif/node.cpp index b0c5d990e..e69de29bb 100644 --- a/components/nif/node.cpp +++ b/components/nif/node.cpp @@ -1,2 +0,0 @@ -#include "node.hpp" - diff --git a/components/nif/node.hpp b/components/nif/node.hpp index b47c05281..943ddcc66 100644 --- a/components/nif/node.hpp +++ b/components/nif/node.hpp @@ -12,7 +12,7 @@ namespace Nif { -class NiNode; +struct NiNode; /** A Node is an object that's part of the main NIF tree. It has parent node (unless it's the root), and transformation (location diff --git a/components/nif/recordptr.hpp b/components/nif/recordptr.hpp index 5eac277d0..25beaf098 100644 --- a/components/nif/recordptr.hpp +++ b/components/nif/recordptr.hpp @@ -122,10 +122,10 @@ class Controller; class Controlled; class NiSkinData; class NiFloatData; -class NiMorphData; +struct NiMorphData; class NiPixelData; class NiColorData; -class NiKeyframeData; +struct NiKeyframeData; class NiTriShapeData; class NiSkinInstance; class NiSourceTexture; diff --git a/components/nifbullet/bulletnifloader.cpp b/components/nifbullet/bulletnifloader.cpp index 35d552726..cdc06f985 100644 --- a/components/nifbullet/bulletnifloader.cpp +++ b/components/nifbullet/bulletnifloader.cpp @@ -274,10 +274,12 @@ void ManualBulletShapeLoader::handleNode(const Nif::Node *node, int flags, // No collision. Use an internal flag setting to mark this. flags |= 0x800; } - else if (sd->string == "MRK" && !mShowMarkers) - // Marker objects. These are only visible in the - // editor. + else if (sd->string == "MRK" && !mShowMarkers && raycasting) + { + // Marker objects should be invisible, but still have collision. + // Except in the editor, the marker objects are visible. return; + } } } diff --git a/components/nifbullet/bulletnifloader.hpp b/components/nifbullet/bulletnifloader.hpp index 56d98834d..0d81d84b6 100644 --- a/components/nifbullet/bulletnifloader.hpp +++ b/components/nifbullet/bulletnifloader.hpp @@ -38,8 +38,8 @@ namespace Nif { class Node; - class Transformation; - class NiTriShape; + struct Transformation; + struct NiTriShape; } namespace NifBullet diff --git a/components/terrain/defaultworld.cpp b/components/terrain/defaultworld.cpp index e14c64f3a..c6f0f7136 100644 --- a/components/terrain/defaultworld.cpp +++ b/components/terrain/defaultworld.cpp @@ -108,8 +108,8 @@ namespace Terrain storage->getBounds(mMinX, mMaxX, mMinY, mMaxY); - int origSizeX = mMaxX-mMinX; - int origSizeY = mMaxY-mMinY; + int origSizeX = static_cast(mMaxX - mMinX); + int origSizeY = static_cast(mMaxY - mMinY); // Dividing a quad tree only works well for powers of two, so round up to the nearest one int size = nextPowerOfTwo(std::max(origSizeX, origSizeY)); @@ -124,7 +124,7 @@ namespace Terrain LayersRequestData data; data.mPack = getShadersEnabled(); - mRootNode = new QuadTreeNode(this, Root, size, Ogre::Vector2(centerX, centerY), NULL); + mRootNode = new QuadTreeNode(this, Root, static_cast(size), Ogre::Vector2(centerX, centerY), NULL); buildQuadTree(mRootNode, data.mNodes); //loadingListener->indicateProgress(); mRootNode->initAabb(); @@ -160,7 +160,7 @@ namespace Terrain float minZ,maxZ; Ogre::Vector2 center = node->getCenter(); float cellWorldSize = getStorage()->getCellWorldSize(); - if (mStorage->getMinMaxHeights(node->getSize(), center, minZ, maxZ)) + if (mStorage->getMinMaxHeights(static_cast(node->getSize()), center, minZ, maxZ)) { Ogre::AxisAlignedBox bounds(Ogre::Vector3(-halfSize*cellWorldSize, -halfSize*cellWorldSize, minZ), Ogre::Vector3(halfSize*cellWorldSize, halfSize*cellWorldSize, maxZ)); @@ -275,7 +275,7 @@ namespace Terrain LoadResponseData* responseData = new LoadResponseData(); - getStorage()->fillVertexBuffers(node->getNativeLodLevel(), node->getSize(), node->getCenter(), getAlign(), + getStorage()->fillVertexBuffers(node->getNativeLodLevel(), static_cast(node->getSize()), node->getCenter(), getAlign(), responseData->mPositions, responseData->mNormals, responseData->mColours); return OGRE_NEW Ogre::WorkQueue::Response(req, true, Ogre::Any(responseData)); diff --git a/components/terrain/defaultworld.hpp b/components/terrain/defaultworld.hpp index 90e8cc2b6..4caef8462 100644 --- a/components/terrain/defaultworld.hpp +++ b/components/terrain/defaultworld.hpp @@ -84,7 +84,7 @@ namespace Terrain /// adding or removing passes. This can only be achieved by a full rebuild.) virtual void applyMaterials(bool shadows, bool splitShadows); - int getMaxBatchSize() { return mMaxBatchSize; } + int getMaxBatchSize() { return static_cast(mMaxBatchSize); } /// Wait until all background loading is complete. void syncLoad(); diff --git a/components/terrain/material.cpp b/components/terrain/material.cpp index 4ff04ab93..4d2318aa6 100644 --- a/components/terrain/material.cpp +++ b/components/terrain/material.cpp @@ -36,7 +36,7 @@ namespace int getBlendmapIndexForLayer (int layerIndex) { - return std::floor((layerIndex-1)/4.f); + return static_cast(std::floor((layerIndex - 1) / 4.f)); } std::string getBlendmapComponentForLayer (int layerIndex) diff --git a/components/terrain/material.hpp b/components/terrain/material.hpp index f35080e7c..b79df9f48 100644 --- a/components/terrain/material.hpp +++ b/components/terrain/material.hpp @@ -35,7 +35,7 @@ namespace Terrain MaterialGenerator (); void setLayerList (const std::vector& layerList) { mLayerList = layerList; } - bool hasLayers() { return mLayerList.size(); } + bool hasLayers() { return mLayerList.size() > 0; } void setBlendmapList (const std::vector& blendmapList) { mBlendmapList = blendmapList; } const std::vector& getBlendmapList() { return mBlendmapList; } void setCompositeMap (const std::string& name) { mCompositeMap = name; } diff --git a/components/terrain/quadtreenode.cpp b/components/terrain/quadtreenode.cpp index 5fce5eae9..6a9964213 100644 --- a/components/terrain/quadtreenode.cpp +++ b/components/terrain/quadtreenode.cpp @@ -135,7 +135,7 @@ QuadTreeNode::QuadTreeNode(DefaultWorld* terrain, ChildDirection dir, float size : mMaterialGenerator(NULL) , mIsDummy(false) , mSize(size) - , mLodLevel(Log2(mSize)) + , mLodLevel(Log2(static_cast(mSize))) , mBounds(Ogre::AxisAlignedBox::BOX_NULL) , mWorldBounds(Ogre::AxisAlignedBox::BOX_NULL) , mDirection(dir) diff --git a/components/terrain/quadtreenode.hpp b/components/terrain/quadtreenode.hpp index 1ecd6fcd5..e44b64600 100644 --- a/components/terrain/quadtreenode.hpp +++ b/components/terrain/quadtreenode.hpp @@ -95,7 +95,7 @@ namespace Terrain Ogre::SceneNode* getSceneNode() { return mSceneNode; } - int getSize() { return mSize; } + int getSize() { return static_cast(mSize); } Ogre::Vector2 getCenter() { return mCenter; } bool hasChildren() { return mChildren[0] != 0; } diff --git a/components/terrain/terraingrid.cpp b/components/terrain/terraingrid.cpp index 269152e61..bb99ca23e 100644 --- a/components/terrain/terraingrid.cpp +++ b/components/terrain/terraingrid.cpp @@ -56,16 +56,16 @@ void TerrainGrid::loadCell(int x, int y) if (mGrid.find(std::make_pair(x, y)) != mGrid.end()) return; // already loaded - Ogre::Vector2 center(x+0.5, y+0.5); + Ogre::Vector2 center(x+0.5f, y+0.5f); float minH, maxH; if (!mStorage->getMinMaxHeights(1, center, minH, maxH)) return; // no terrain defined - Ogre::Vector3 min (-0.5*mStorage->getCellWorldSize(), - -0.5*mStorage->getCellWorldSize(), + Ogre::Vector3 min (-0.5f*mStorage->getCellWorldSize(), + -0.5f*mStorage->getCellWorldSize(), minH); - Ogre::Vector3 max (0.5*mStorage->getCellWorldSize(), - 0.5*mStorage->getCellWorldSize(), + Ogre::Vector3 max (0.5f*mStorage->getCellWorldSize(), + 0.5f*mStorage->getCellWorldSize(), maxH); Ogre::AxisAlignedBox bounds(min, max); @@ -163,8 +163,8 @@ void TerrainGrid::setVisible(bool visible) Ogre::AxisAlignedBox TerrainGrid::getWorldBoundingBox (const Ogre::Vector2& center) { - int cellX = std::floor(center.x); - int cellY = std::floor(center.y); + int cellX = static_cast(std::floor(center.x)); + int cellY = static_cast(std::floor(center.y)); Grid::iterator it = mGrid.find(std::make_pair(cellX, cellY)); if (it == mGrid.end()) diff --git a/components/to_utf8/to_utf8.cpp b/components/to_utf8/to_utf8.cpp index cb9680441..d7f9c3a38 100644 --- a/components/to_utf8/to_utf8.cpp +++ b/components/to_utf8/to_utf8.cpp @@ -84,11 +84,11 @@ std::string Utf8Encoder::getUtf8(const char* input, size_t size) // is also ok.) assert(input[size] == 0); - // TODO: The rest of this function is designed for single-character + // Note: The rest of this function is designed for single-character // input encodings only. It also assumes that the input the input - // encoding shares its first 128 values (0-127) with ASCII. These - // conditions must be checked again if you add more input encodings - // later. + // encoding shares its first 128 values (0-127) with ASCII. There are + // no plans to add more encodings to this module (we are using utf8 + // for new content files), so that shouldn't be an issue. // Compute output length, and check for pure ascii input at the same // time. diff --git a/components/widgets/list.cpp b/components/widgets/list.cpp index 28271e87d..8517a0303 100644 --- a/components/widgets/list.cpp +++ b/components/widgets/list.cpp @@ -138,10 +138,10 @@ namespace Gui void MWList::onMouseWheel(MyGUI::Widget* _sender, int _rel) { //NB view offset is negative - if (mScrollView->getViewOffset().top + _rel*0.3 > 0) + if (mScrollView->getViewOffset().top + _rel*0.3f > 0) mScrollView->setViewOffset(MyGUI::IntPoint(0, 0)); else - mScrollView->setViewOffset(MyGUI::IntPoint(0, mScrollView->getViewOffset().top + _rel*0.3)); + mScrollView->setViewOffset(MyGUI::IntPoint(0, static_cast(mScrollView->getViewOffset().top + _rel*0.3))); } void MWList::onItemSelected(MyGUI::Widget* _sender) @@ -152,9 +152,9 @@ namespace Gui eventWidgetSelected(_sender); } - MyGUI::Widget* MWList::getItemWidget(const std::string& name) + MyGUI::Button *MWList::getItemWidget(const std::string& name) { - return mScrollView->findWidget (getName() + "_item_" + name); + return mScrollView->findWidget (getName() + "_item_" + name)->castType(); } } diff --git a/components/widgets/list.hpp b/components/widgets/list.hpp index 093cd8c18..72c8a733c 100644 --- a/components/widgets/list.hpp +++ b/components/widgets/list.hpp @@ -43,7 +43,7 @@ namespace Gui std::string getItemNameAt(unsigned int at); ///< \attention if there are separators, this method will return "" at the place where the separator is void clear(); - MyGUI::Widget* getItemWidget(const std::string& name); + MyGUI::Button* getItemWidget(const std::string& name); ///< get widget for an item name, useful to set up tooltip virtual void setPropertyOverride(const std::string& _key, const std::string& _value); diff --git a/extern/ogre-ffmpeg-videoplayer/audiodecoder.cpp b/extern/ogre-ffmpeg-videoplayer/audiodecoder.cpp index cfc6c17b9..1a56802da 100644 --- a/extern/ogre-ffmpeg-videoplayer/audiodecoder.cpp +++ b/extern/ogre-ffmpeg-videoplayer/audiodecoder.cpp @@ -222,7 +222,7 @@ int MovieAudioDecoder::audio_decode_frame(AVFrame *frame, int &sample_skip) } /* if update, update the audio clock w/pts */ - if((uint64_t)pkt->pts != AV_NOPTS_VALUE) + if(pkt->pts != AV_NOPTS_VALUE) mAudioClock = av_q2d(mAVStream->time_base)*pkt->pts; } } diff --git a/extern/ogre-ffmpeg-videoplayer/videostate.cpp b/extern/ogre-ffmpeg-videoplayer/videostate.cpp index 0894499b2..66c7c2ad5 100644 --- a/extern/ogre-ffmpeg-videoplayer/videostate.cpp +++ b/extern/ogre-ffmpeg-videoplayer/videostate.cpp @@ -179,7 +179,7 @@ int VideoState::OgreResource_Read(void *user_data, uint8_t *buf, int buf_size) { return stream->read(buf, buf_size); } - catch (std::exception& e) + catch (std::exception& ) { return 0; } @@ -192,7 +192,7 @@ int VideoState::OgreResource_Write(void *user_data, uint8_t *buf, int buf_size) { return stream->write(buf, buf_size); } - catch (std::exception& e) + catch (std::exception& ) { return 0; } @@ -206,11 +206,11 @@ int64_t VideoState::OgreResource_Seek(void *user_data, int64_t offset, int whenc if(whence == AVSEEK_SIZE) return stream->size(); if(whence == SEEK_SET) - stream->seek(offset); + stream->seek(static_cast(offset)); else if(whence == SEEK_CUR) - stream->seek(stream->tell()+offset); + stream->seek(static_cast(stream->tell()+offset)); else if(whence == SEEK_END) - stream->seek(stream->size()+offset); + stream->seek(static_cast(stream->size() + offset)); else return -1; @@ -400,7 +400,7 @@ void VideoState::video_thread_loop(VideoState *self) self->pictq_mutex.unlock(); self->frame_last_pts = packet->pts * av_q2d((*self->video_st)->time_base); - global_video_pkt_pts = self->frame_last_pts; + global_video_pkt_pts = static_cast(self->frame_last_pts); continue; } @@ -412,9 +412,9 @@ void VideoState::video_thread_loop(VideoState *self) double pts = 0; if(packet->dts != AV_NOPTS_VALUE) - pts = packet->dts; + pts = static_cast(packet->dts); else if(pFrame->opaque && *(int64_t*)pFrame->opaque != AV_NOPTS_VALUE) - pts = *(int64_t*)pFrame->opaque; + pts = static_cast(*(int64_t*)pFrame->opaque); pts *= av_q2d((*self->video_st)->time_base); av_free_packet(packet); diff --git a/extern/oics/ICSChannelListener.h b/extern/oics/ICSChannelListener.h index d520b3bce..a202e7e22 100644 --- a/extern/oics/ICSChannelListener.h +++ b/extern/oics/ICSChannelListener.h @@ -43,4 +43,4 @@ namespace ICS } -#endif \ No newline at end of file +#endif diff --git a/extern/oics/ICSControl.cpp b/extern/oics/ICSControl.cpp index 7c804d6ee..974d69f08 100644 --- a/extern/oics/ICSControl.cpp +++ b/extern/oics/ICSControl.cpp @@ -43,10 +43,10 @@ namespace ICS , mAxisBindable(axisBindable) , currentChangingDirection(STOP) { - + } - Control::~Control() + Control::~Control() { mAttachedChannels.clear(); } @@ -92,7 +92,7 @@ namespace ICS } void Control::setChangingDirection(ControlChangingDirection direction) - { + { currentChangingDirection = direction; mPendingActions.push_back(direction); } @@ -102,9 +102,9 @@ namespace ICS if(!mPendingActions.empty()) { size_t timedActionsCount = 0; - + std::list::iterator cached_end = mPendingActions.end(); - for(std::list::iterator it = mPendingActions.begin() ; + for(std::list::iterator it = mPendingActions.begin() ; it != cached_end ; ++it) { if( (*it) != Control::STOP ) @@ -112,14 +112,14 @@ namespace ICS timedActionsCount++; } } - + float timeSinceLastFramePart = timeSinceLastFrame / std::max(1, timedActionsCount); - for(std::list::iterator it = mPendingActions.begin() ; + for(std::list::iterator it = mPendingActions.begin() ; it != cached_end ; ++it) { if( (*it) != Control::STOP ) { - this->setValue(mValue + + this->setValue(mValue + (((int)(*it)) * mStepSize * mStepsPerSeconds * (timeSinceLastFramePart))); } else if(mAutoReverseToInitialValue && !mIgnoreAutoReverse && mValue != mInitialValue ) @@ -141,7 +141,7 @@ namespace ICS } else if( currentChangingDirection != Control::STOP ) { - this->setValue(mValue + + this->setValue(mValue + (((int)currentChangingDirection) * mStepSize * mStepsPerSeconds * (timeSinceLastFrame))); } else if(mAutoReverseToInitialValue && !mIgnoreAutoReverse && mValue != mInitialValue ) diff --git a/extern/oics/ICSControl.h b/extern/oics/ICSControl.h index ebf75a3fe..1ed437652 100644 --- a/extern/oics/ICSControl.h +++ b/extern/oics/ICSControl.h @@ -34,7 +34,7 @@ SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. namespace ICS { - + class DllExport Control { public: @@ -52,9 +52,10 @@ namespace ICS void setValue(float value); inline float getValue(){ return mValue; }; - inline float getInitialValue(){ return mInitialValue; }; + inline float getInitialValue(){ return mInitialValue; }; + inline void setInitialValue(float i) {mInitialValue = i;}; - void attachChannel(Channel* channel, Channel::ChannelDirection direction, float percentage = 1.0); + void attachChannel(Channel* channel, Channel::ChannelDirection direction, float percentage = 1.0); std::list getAttachedChannels(){ return mAttachedChannels; }; inline float getStepSize(){ return mStepSize; }; diff --git a/extern/oics/ICSControlListener.h b/extern/oics/ICSControlListener.h index 067b2d6f2..97b3940be 100644 --- a/extern/oics/ICSControlListener.h +++ b/extern/oics/ICSControlListener.h @@ -43,4 +43,4 @@ namespace ICS } -#endif \ No newline at end of file +#endif diff --git a/extern/oics/ICSInputControlSystem.cpp b/extern/oics/ICSInputControlSystem.cpp index e1bd58728..2599c5761 100644 --- a/extern/oics/ICSInputControlSystem.cpp +++ b/extern/oics/ICSInputControlSystem.cpp @@ -60,10 +60,10 @@ namespace ICS xmlDoc = new TiXmlDocument(file.c_str()); xmlDoc->LoadFile(); - if(xmlDoc->Error()) + if(xmlDoc->Error()) { - std::ostringstream message; - message << "TinyXml reported an error reading \""+ file + "\". Row " << + std::ostringstream message; + message << "TinyXml reported an error reading \""+ file + "\". Row " << (int)xmlDoc->ErrorRow() << ", Col " << (int)xmlDoc->ErrorCol() << ": " << xmlDoc->ErrorDesc() ; ICS_LOG(message.str()); @@ -81,10 +81,10 @@ namespace ICS TiXmlElement* xmlControl = xmlRoot->FirstChildElement("Control"); - size_t controlChannelCount = 0; - while(xmlControl) + size_t controlChannelCount = 0; + while(xmlControl) { - TiXmlElement* xmlChannel = xmlControl->FirstChildElement("Channel"); + TiXmlElement* xmlChannel = xmlControl->FirstChildElement("Channel"); while(xmlChannel) { controlChannelCount = std::max(channelCount, FromString(xmlChannel->Attribute("number"))+1); @@ -111,7 +111,7 @@ namespace ICS // // - TiXmlElement* xmlChannelFilter = xmlRoot->FirstChildElement("ChannelFilter"); + TiXmlElement* xmlChannelFilter = xmlRoot->FirstChildElement("ChannelFilter"); while(xmlChannelFilter) { int ch = FromString(xmlChannelFilter->Attribute("number")); @@ -133,12 +133,12 @@ namespace ICS float step = FromString(xmlInterval->Attribute("step")); ICS_LOG("Applying Bezier filter to channel [number=" - + ToString(ch) + ", startX=" - + ToString(startX) + ", startY=" - + ToString(startY) + ", midX=" - + ToString(midX) + ", midY=" - + ToString(midY) + ", endX=" - + ToString(endX) + ", endY=" + + ToString(ch) + ", startX=" + + ToString(startX) + ", startY=" + + ToString(startY) + ", midX=" + + ToString(midX) + ", midY=" + + ToString(midY) + ", endX=" + + ToString(endX) + ", endY=" + ToString(endY) + ", step=" + ToString(step) + "]"); @@ -152,8 +152,8 @@ namespace ICS xmlChannelFilter = xmlChannelFilter->NextSiblingElement("ChannelFilter"); } - xmlControl = xmlRoot->FirstChildElement("Control"); - while(xmlControl) + xmlControl = xmlRoot->FirstChildElement("Control"); + while(xmlControl) { bool axisBindable = true; if(xmlControl->Attribute("axisBindable")) @@ -176,11 +176,11 @@ namespace ICS std::string value(xmlControl->Attribute("stepSize")); if(value == "MAX") { - _stepSize = ICS_MAX; + _stepSize = ICS_MAX; } else { - _stepSize = FromString(value.c_str()); + _stepSize = FromString(value.c_str()); } } else @@ -194,7 +194,7 @@ namespace ICS std::string value(xmlControl->Attribute("stepsPerSeconds")); if(value == "MAX") { - _stepsPerSeconds = ICS_MAX; + _stepsPerSeconds = ICS_MAX; } else { @@ -224,12 +224,8 @@ namespace ICS loadJoystickButtonBinders(xmlControl); - loadJoystickPOVBinders(xmlControl); - - loadJoystickSliderBinders(xmlControl); - // Attach controls to channels - TiXmlElement* xmlChannel = xmlControl->FirstChildElement("Channel"); + TiXmlElement* xmlChannel = xmlControl->FirstChildElement("Channel"); while(xmlChannel) { ICS_LOG("\tAttaching control to channel [number=" @@ -250,7 +246,7 @@ namespace ICS { percentage = val; } - } + } else { ICS_LOG("ERROR: attaching percentage value range is [0,1]"); @@ -338,7 +334,7 @@ namespace ICS for(std::vector::const_iterator o = mChannels.begin() ; o != mChannels.end(); ++o) { ICS::IntervalList intervals = (*o)->getIntervals(); - + if(intervals.size() > 1) // all channels have a default linear filter { TiXmlElement ChannelFilter( "ChannelFilter" ); @@ -371,7 +367,7 @@ namespace ICS ChannelFilter.InsertEndChild(XMLInterval); } - + ++interval; } @@ -401,7 +397,7 @@ namespace ICS control.SetAttribute( "autoReverseToInitialValue", "false" ); } control.SetAttribute( "initialValue", ToString((*o)->getInitialValue()).c_str() ); - + if((*o)->getStepSize() == ICS_MAX) { control.SetAttribute( "stepSize", "MAX" ); @@ -445,12 +441,12 @@ namespace ICS control.InsertEndChild(keyBinder); } - if(getMouseAxisBinding(*o, Control/*::ControlChangingDirection*/::INCREASE) + if(getMouseAxisBinding(*o, Control/*::ControlChangingDirection*/::INCREASE) != InputControlSystem/*::NamedAxis*/::UNASSIGNED) { TiXmlElement binder( "MouseBinder" ); - InputControlSystem::NamedAxis axis = + InputControlSystem::NamedAxis axis = getMouseAxisBinding(*o, Control/*::ControlChangingDirection*/::INCREASE); if(axis == InputControlSystem/*::NamedAxis*/::X) { @@ -469,12 +465,12 @@ namespace ICS control.InsertEndChild(binder); } - if(getMouseAxisBinding(*o, Control/*::ControlChangingDirection*/::DECREASE) + if(getMouseAxisBinding(*o, Control/*::ControlChangingDirection*/::DECREASE) != InputControlSystem/*::NamedAxis*/::UNASSIGNED) { TiXmlElement binder( "MouseBinder" ); - InputControlSystem::NamedAxis axis = + InputControlSystem::NamedAxis axis = getMouseAxisBinding(*o, Control/*::ControlChangingDirection*/::DECREASE); if(axis == InputControlSystem/*::NamedAxis*/::X) { @@ -493,7 +489,7 @@ namespace ICS control.InsertEndChild(binder); } - if(getMouseButtonBinding(*o, Control/*::ControlChangingDirection*/::INCREASE) + if(getMouseButtonBinding(*o, Control/*::ControlChangingDirection*/::INCREASE) != ICS_MAX_DEVICE_BUTTONS) { TiXmlElement binder( "MouseButtonBinder" ); @@ -519,7 +515,7 @@ namespace ICS control.InsertEndChild(binder); } - if(getMouseButtonBinding(*o, Control/*::ControlChangingDirection*/::DECREASE) + if(getMouseButtonBinding(*o, Control/*::ControlChangingDirection*/::DECREASE) != ICS_MAX_DEVICE_BUTTONS) { TiXmlElement binder( "MouseButtonBinder" ); @@ -543,153 +539,72 @@ namespace ICS } binder.SetAttribute( "direction", "DECREASE" ); control.InsertEndChild(binder); - } + } + JoystickIDList::const_iterator it = mJoystickIDList.begin(); + while(it!=mJoystickIDList.end()) + { + int deviceID = *it; + if(getJoystickAxisBinding(*o, deviceID, Control/*::ControlChangingDirection*/::INCREASE) + != /*NamedAxis::*/UNASSIGNED) + { + TiXmlElement binder( "JoystickAxisBinder" ); - JoystickIDList::const_iterator it = mJoystickIDList.begin(); - while(it != mJoystickIDList.end()) - { - int deviceId = *it; + binder.SetAttribute( "axis", ToString( + getJoystickAxisBinding(*o, deviceID, Control/*::ControlChangingDirection*/::INCREASE)).c_str() ); - if(getJoystickAxisBinding(*o, deviceId, Control/*::ControlChangingDirection*/::INCREASE) - != /*NamedAxis::*/UNASSIGNED) - { - TiXmlElement binder( "JoystickAxisBinder" ); + binder.SetAttribute( "direction", "INCREASE" ); + + binder.SetAttribute( "deviceId", deviceID ); //completely useless, but required for backwards compatability - binder.SetAttribute( "axis", ToString( - getJoystickAxisBinding(*o, deviceId, Control/*::ControlChangingDirection*/::INCREASE)).c_str() ); + control.InsertEndChild(binder); + } - binder.SetAttribute( "direction", "INCREASE" ); + if(getJoystickAxisBinding(*o, deviceID, Control/*::ControlChangingDirection*/::DECREASE) + != /*NamedAxis::*/UNASSIGNED) + { + TiXmlElement binder( "JoystickAxisBinder" ); - binder.SetAttribute( "deviceId", ToString(deviceId).c_str() ); - - control.InsertEndChild(binder); - } + binder.SetAttribute( "axis", ToString( + getJoystickAxisBinding(*o, deviceID, Control/*::ControlChangingDirection*/::DECREASE)).c_str() ); - if(getJoystickAxisBinding(*o, deviceId, Control/*::ControlChangingDirection*/::DECREASE) - != /*NamedAxis::*/UNASSIGNED) - { - TiXmlElement binder( "JoystickAxisBinder" ); + binder.SetAttribute( "direction", "DECREASE" ); + + binder.SetAttribute( "deviceId", deviceID ); //completely useless, but required for backwards compatability - binder.SetAttribute( "axis", ToString( - getJoystickAxisBinding(*o, deviceId, Control/*::ControlChangingDirection*/::DECREASE)).c_str() ); + control.InsertEndChild(binder); + } - binder.SetAttribute( "direction", "DECREASE" ); + if(getJoystickButtonBinding(*o, deviceID, Control/*::ControlChangingDirection*/::INCREASE) + != ICS_MAX_DEVICE_BUTTONS) + { + TiXmlElement binder( "JoystickButtonBinder" ); - binder.SetAttribute( "deviceId", ToString(deviceId).c_str() ); - - control.InsertEndChild(binder); - } + binder.SetAttribute( "button", ToString( + getJoystickButtonBinding(*o, deviceID, Control/*::ControlChangingDirection*/::INCREASE)).c_str() ); - if(getJoystickButtonBinding(*o, deviceId, Control/*::ControlChangingDirection*/::INCREASE) - != ICS_MAX_DEVICE_BUTTONS) - { - TiXmlElement binder( "JoystickButtonBinder" ); + binder.SetAttribute( "direction", "INCREASE" ); + + binder.SetAttribute( "deviceId", deviceID ); //completely useless, but required for backwards compatability - binder.SetAttribute( "button", ToString( - getJoystickButtonBinding(*o, deviceId, Control/*::ControlChangingDirection*/::INCREASE)).c_str() ); + control.InsertEndChild(binder); + } - binder.SetAttribute( "direction", "INCREASE" ); + if(getJoystickButtonBinding(*o, deviceID, Control/*::ControlChangingDirection*/::DECREASE) + != ICS_MAX_DEVICE_BUTTONS) + { + TiXmlElement binder( "JoystickButtonBinder" ); - binder.SetAttribute( "deviceId", ToString(deviceId).c_str() ); - - control.InsertEndChild(binder); - } + binder.SetAttribute( "button", ToString( + getJoystickButtonBinding(*o, deviceID, Control/*::ControlChangingDirection*/::DECREASE)).c_str() ); - if(getJoystickButtonBinding(*o, deviceId, Control/*::ControlChangingDirection*/::DECREASE) - != ICS_MAX_DEVICE_BUTTONS) - { - TiXmlElement binder( "JoystickButtonBinder" ); + binder.SetAttribute( "direction", "DECREASE" ); + + binder.SetAttribute( "deviceId", deviceID ); //completely useless, but required for backwards compatability - binder.SetAttribute( "button", ToString( - getJoystickButtonBinding(*o, *it, Control/*::ControlChangingDirection*/::DECREASE)).c_str() ); - - binder.SetAttribute( "direction", "DECREASE" ); - - binder.SetAttribute( "deviceId", ToString(deviceId).c_str() ); - - control.InsertEndChild(binder); - } - - if(getJoystickPOVBinding(*o, deviceId, Control/*::ControlChangingDirection*/::INCREASE).index >= 0) - { - TiXmlElement binder( "JoystickPOVBinder" ); - - POVBindingPair POVPair = getJoystickPOVBinding(*o, deviceId, Control/*::ControlChangingDirection*/::INCREASE); - - binder.SetAttribute( "pov", ToString(POVPair.index).c_str() ); - - binder.SetAttribute( "direction", "INCREASE" ); - - binder.SetAttribute( "deviceId", ToString(deviceId).c_str() ); - - if(POVPair.axis == ICS::InputControlSystem::EastWest) - { - binder.SetAttribute( "axis", "EastWest" ); - } - else - { - binder.SetAttribute( "axis", "NorthSouth" ); - } - - control.InsertEndChild(binder); - } - - if(getJoystickPOVBinding(*o, deviceId, Control/*::ControlChangingDirection*/::DECREASE).index >= 0) - { - TiXmlElement binder( "JoystickPOVBinder" ); - - POVBindingPair POVPair = getJoystickPOVBinding(*o, deviceId, Control/*::ControlChangingDirection*/::DECREASE); - - binder.SetAttribute( "pov", ToString(POVPair.index).c_str() ); - - binder.SetAttribute( "direction", "DECREASE" ); - - binder.SetAttribute( "deviceId", ToString(deviceId).c_str() ); - - if(POVPair.axis == ICS::InputControlSystem::EastWest) - { - binder.SetAttribute( "axis", "EastWest" ); - } - else - { - binder.SetAttribute( "axis", "NorthSouth" ); - } - - control.InsertEndChild(binder); - } - - if(getJoystickSliderBinding(*o, deviceId, Control/*::ControlChangingDirection*/::INCREASE) - != /*NamedAxis::*/UNASSIGNED) - { - TiXmlElement binder( "JoystickSliderBinder" ); - - binder.SetAttribute( "slider", ToString( - getJoystickSliderBinding(*o, deviceId, Control/*::ControlChangingDirection*/::INCREASE)).c_str() ); - - binder.SetAttribute( "direction", "INCREASE" ); - - binder.SetAttribute( "deviceId", ToString(deviceId).c_str() ); - - control.InsertEndChild(binder); - } - - if(getJoystickSliderBinding(*o, deviceId, Control/*::ControlChangingDirection*/::DECREASE) - != /*NamedAxis::*/UNASSIGNED) - { - TiXmlElement binder( "JoystickSliderBinder" ); - - binder.SetAttribute( "slider", ToString( - getJoystickSliderBinding(*o, deviceId, Control/*::ControlChangingDirection*/::DECREASE)).c_str() ); - - binder.SetAttribute( "direction", "DECREASE" ); - - binder.SetAttribute( "deviceId", ToString(deviceId).c_str() ); - - control.InsertEndChild(binder); - } - - ++it; - } + control.InsertEndChild(binder); + } + it++; + } std::list channels = (*o)->getAttachedChannels(); @@ -700,19 +615,19 @@ namespace ICS binder.SetAttribute( "number", ToString((*it)->getNumber()).c_str() ); - Channel::ChannelDirection direction = (*it)->getAttachedControlBinding(*o).direction; + Channel::ChannelDirection direction = (*it)->getAttachedControlBinding(*o).direction; if(direction == Channel/*::ChannelDirection*/::DIRECT) { binder.SetAttribute( "direction", "DIRECT" ); - } + } else { binder.SetAttribute( "direction", "INVERSE" ); } - + float percentage = (*it)->getAttachedControlBinding(*o).percentage; binder.SetAttribute( "percentage", ToString(percentage).c_str() ); - + control.InsertEndChild(binder); } @@ -734,7 +649,7 @@ namespace ICS } } - //! @todo Future versions should consider channel exponentials and mixtures, so + //! @todo Future versions should consider channel exponentials and mixtures, so // after updating Controls, Channels should be updated according to their values } @@ -748,24 +663,6 @@ namespace ICS return mControls[i]->getValue(); } - void InputControlSystem::addJoystick(int deviceId) - { - ICS_LOG("Adding joystick (device id: " + ToString(deviceId) + ")"); - - for(int j = 0 ; j < ICS_MAX_JOYSTICK_AXIS ; j++) - { - if(mControlsJoystickAxisBinderMap[deviceId].find(j) == mControlsJoystickAxisBinderMap[deviceId].end()) - { - ControlAxisBinderItem controlJoystickBinderItem; - controlJoystickBinderItem.direction = Control::STOP; - controlJoystickBinderItem.control = NULL; - mControlsJoystickAxisBinderMap[deviceId][j] = controlJoystickBinderItem; - } - } - - mJoystickIDList.push_back(deviceId); - } - Control* InputControlSystem::findControl(std::string name) { if(mActive) diff --git a/extern/oics/ICSInputControlSystem.h b/extern/oics/ICSInputControlSystem.h index 6a6a6bf09..51b701b48 100644 --- a/extern/oics/ICSInputControlSystem.h +++ b/extern/oics/ICSInputControlSystem.h @@ -32,7 +32,9 @@ SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. #include "ICSControl.h" #include "ICSChannel.h" -#include "../sdl4ogre/events.h" +#include "../sdl4ogre/events.h" + +#include "boost/lexical_cast.hpp" #define ICS_LOG(text) if(mLog) mLog->logMessage( ("ICS: " + std::string(text)).c_str() ); #define ICS_MAX_JOYSTICK_AXIS 16 @@ -43,16 +45,16 @@ SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. namespace ICS { - class DllExport InputControlSystemLog + class DllExport InputControlSystemLog { public: virtual void logMessage(const char* text) = 0; }; - class DllExport InputControlSystem : + class DllExport InputControlSystem : public SFO::MouseListener, public SFO::KeyListener, - public SFO::JoyListener + public SFO::ControllerListener { public: @@ -62,6 +64,7 @@ namespace ICS typedef NamedAxis MouseAxis; // MouseAxis is deprecated. It will be removed in future versions + typedef std::map JoystickInstanceMap; typedef std::list JoystickIDList; typedef struct @@ -72,7 +75,7 @@ namespace ICS InputControlSystem(std::string file = "", bool active = true , DetectingBindingListener* detectingBindingListener = NULL - , InputControlSystemLog* log = NULL, size_t channelCount = 16); + , InputControlSystemLog* log = NULL, size_t channelCount = 16); ~InputControlSystem(); std::string getFileName(){ return mFileName; }; @@ -98,50 +101,43 @@ namespace ICS inline void activate(){ this->mActive = true; }; inline void deactivate(){ this->mActive = false; }; - void addJoystick(int deviceId); - JoystickIDList& getJoystickIdList(){ return mJoystickIDList; }; - + void controllerAdded (int deviceID, const SDL_ControllerDeviceEvent &args); + void controllerRemoved(const SDL_ControllerDeviceEvent &args); + JoystickIDList& getJoystickIdList(){ return mJoystickIDList; }; + JoystickInstanceMap& getJoystickInstanceMap(){ return mJoystickInstanceMap; }; + // MouseListener void mouseMoved(const SFO::MouseMotionEvent &evt); void mousePressed(const SDL_MouseButtonEvent &evt, Uint8); void mouseReleased(const SDL_MouseButtonEvent &evt, Uint8); - + // KeyListener void keyPressed(const SDL_KeyboardEvent &evt); void keyReleased(const SDL_KeyboardEvent &evt); - - // JoyStickListener - void buttonPressed(const SDL_JoyButtonEvent &evt, int button); - void buttonReleased(const SDL_JoyButtonEvent &evt, int button); - void axisMoved(const SDL_JoyAxisEvent &evt, int axis); - void povMoved(const SDL_JoyHatEvent &evt, int index); - //TODO: does this have an SDL equivalent? - //bool sliderMoved(const OIS::JoyStickEvent &evt, int index); + + // ControllerListener + void buttonPressed(int deviceID, const SDL_ControllerButtonEvent &evt); + void buttonReleased(int deviceID, const SDL_ControllerButtonEvent &evt); + void axisMoved(int deviceID, const SDL_ControllerAxisEvent &evt); void addKeyBinding(Control* control, SDL_Scancode key, Control::ControlChangingDirection direction); bool isKeyBound(SDL_Scancode key) const; void addMouseAxisBinding(Control* control, NamedAxis axis, Control::ControlChangingDirection direction); void addMouseButtonBinding(Control* control, unsigned int button, Control::ControlChangingDirection direction); bool isMouseButtonBound(unsigned int button) const; - void addJoystickAxisBinding(Control* control, int deviceId, int axis, Control::ControlChangingDirection direction); - void addJoystickButtonBinding(Control* control, int deviceId, unsigned int button, Control::ControlChangingDirection direction); - void addJoystickPOVBinding(Control* control, int deviceId, int index, POVAxis axis, Control::ControlChangingDirection direction); - void addJoystickSliderBinding(Control* control, int deviceId, int index, Control::ControlChangingDirection direction); + void addJoystickAxisBinding(Control* control, int deviceID, int axis, Control::ControlChangingDirection direction); + void addJoystickButtonBinding(Control* control, int deviceID, unsigned int button, Control::ControlChangingDirection direction); void removeKeyBinding(SDL_Scancode key); void removeMouseAxisBinding(NamedAxis axis); void removeMouseButtonBinding(unsigned int button); - void removeJoystickAxisBinding(int deviceId, int axis); - void removeJoystickButtonBinding(int deviceId, unsigned int button); - void removeJoystickPOVBinding(int deviceId, int index, POVAxis axis); - void removeJoystickSliderBinding(int deviceId, int index); + void removeJoystickAxisBinding(int deviceID, int axis); + void removeJoystickButtonBinding(int deviceID, unsigned int button); SDL_Scancode getKeyBinding(Control* control, ICS::Control::ControlChangingDirection direction); NamedAxis getMouseAxisBinding(Control* control, ICS::Control::ControlChangingDirection direction); unsigned int getMouseButtonBinding(Control* control, ICS::Control::ControlChangingDirection direction); - int getJoystickAxisBinding(Control* control, int deviceId, ICS::Control::ControlChangingDirection direction); - unsigned int getJoystickButtonBinding(Control* control, int deviceId, ICS::Control::ControlChangingDirection direction); - POVBindingPair getJoystickPOVBinding(Control* control, int deviceId, ICS::Control::ControlChangingDirection direction); - int getJoystickSliderBinding(Control* control, int deviceId, ICS::Control::ControlChangingDirection direction); + int getJoystickAxisBinding(Control* control, int deviceID, ICS::Control::ControlChangingDirection direction); + unsigned int getJoystickButtonBinding(Control* control, int deviceID, ICS::Control::ControlChangingDirection direction); std::string scancodeToString(SDL_Scancode key); @@ -189,21 +185,15 @@ namespace ICS typedef std::map ControlsKeyBinderMapType; // typedef std::map ControlsAxisBinderMapType; // - typedef std::map ControlsButtonBinderMapType; // - typedef std::map ControlsPOVBinderMapType; // - typedef std::map ControlsSliderBinderMapType; // - - typedef std::map JoystickAxisBinderMapType; // > - typedef std::map JoystickButtonBinderMapType; // > - typedef std::map > JoystickPOVBinderMapType; // > > - typedef std::map JoystickSliderBinderMapType; // > + typedef std::map ControlsButtonBinderMapType; // + + typedef std::map JoystickAxisBinderMapType; // > + typedef std::map JoystickButtonBinderMapType; // > ControlsAxisBinderMapType mControlsMouseAxisBinderMap; // ControlsButtonBinderMapType mControlsMouseButtonBinderMap; // - JoystickAxisBinderMapType mControlsJoystickAxisBinderMap; // > - JoystickButtonBinderMapType mControlsJoystickButtonBinderMap; // > - JoystickPOVBinderMapType mControlsJoystickPOVBinderMap; // > > - JoystickSliderBinderMapType mControlsJoystickSliderBinderMap; // > + JoystickAxisBinderMapType mControlsJoystickAxisBinderMap; // + JoystickButtonBinderMapType mControlsJoystickButtonBinderMap; // std::vector mControls; std::vector mChannels; @@ -212,7 +202,7 @@ namespace ICS bool mActive; InputControlSystemLog* mLog; - + DetectingBindingListener* mDetectingBindingListener; Control* mDetectingBindingControl; Control::ControlChangingDirection mDetectingBindingDirection; @@ -220,7 +210,8 @@ namespace ICS bool mXmouseAxisBinded; bool mYmouseAxisBinded; - JoystickIDList mJoystickIDList; + JoystickIDList mJoystickIDList; + JoystickInstanceMap mJoystickInstanceMap; int mMouseAxisBindingInitialValues[3]; @@ -242,17 +233,12 @@ namespace ICS virtual void mouseButtonBindingDetected(InputControlSystem* ICS, Control* control , unsigned int button, Control::ControlChangingDirection direction); - virtual void joystickAxisBindingDetected(InputControlSystem* ICS, Control* control - , int deviceId, int axis, Control::ControlChangingDirection direction); + virtual void joystickAxisBindingDetected(InputControlSystem* ICS, int deviceID, Control* control + , int axis, Control::ControlChangingDirection direction); - virtual void joystickButtonBindingDetected(InputControlSystem* ICS, Control* control - , int deviceId, unsigned int button, Control::ControlChangingDirection direction); + virtual void joystickButtonBindingDetected(InputControlSystem* ICS, int deviceID, Control* control + , unsigned int button, Control::ControlChangingDirection direction); - virtual void joystickPOVBindingDetected(InputControlSystem* ICS, Control* control - , int deviceId, int pov, InputControlSystem::POVAxis axis, Control::ControlChangingDirection direction); - - virtual void joystickSliderBindingDetected(InputControlSystem* ICS, Control* control - , int deviceId, int slider, Control::ControlChangingDirection direction); }; static const float ICS_MAX = std::numeric_limits::max(); diff --git a/extern/oics/ICSInputControlSystem_joystick.cpp b/extern/oics/ICSInputControlSystem_joystick.cpp index 0fcd36bbd..ab219d074 100644 --- a/extern/oics/ICSInputControlSystem_joystick.cpp +++ b/extern/oics/ICSInputControlSystem_joystick.cpp @@ -27,14 +27,15 @@ SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. #include "ICSInputControlSystem.h" #define SDL_JOY_AXIS_MIN -32768 -#define SDL_JOY_AXIS_MAX 32767 +#define SDL_JOY_AXIS_MAX 32767 +#define DEADZONE 0.1f namespace ICS { // load xml void InputControlSystem::loadJoystickAxisBinders(TiXmlElement* xmlControlNode) { - TiXmlElement* xmlJoystickBinder = xmlControlNode->FirstChildElement("JoystickAxisBinder"); + TiXmlElement* xmlJoystickBinder = xmlControlNode->FirstChildElement("JoystickAxisBinder"); while(xmlJoystickBinder) { Control::ControlChangingDirection dir = Control::STOP; @@ -47,8 +48,7 @@ namespace ICS dir = Control::DECREASE; } - addJoystickAxisBinding(mControls.back(), FromString(xmlJoystickBinder->Attribute("deviceId")) - , FromString(xmlJoystickBinder->Attribute("axis")), dir); + addJoystickAxisBinding(mControls.back(), FromString(xmlJoystickBinder->Attribute("deviceId")), FromString(xmlJoystickBinder->Attribute("axis")), dir); xmlJoystickBinder = xmlJoystickBinder->NextSiblingElement("JoystickAxisBinder"); } @@ -56,7 +56,7 @@ namespace ICS void InputControlSystem::loadJoystickButtonBinders(TiXmlElement* xmlControlNode) { - TiXmlElement* xmlJoystickButtonBinder = xmlControlNode->FirstChildElement("JoystickButtonBinder"); + TiXmlElement* xmlJoystickButtonBinder = xmlControlNode->FirstChildElement("JoystickButtonBinder"); while(xmlJoystickButtonBinder) { Control::ControlChangingDirection dir = Control::STOP; @@ -69,335 +69,194 @@ namespace ICS dir = Control::DECREASE; } - addJoystickButtonBinding(mControls.back(), FromString(xmlJoystickButtonBinder->Attribute("deviceId")) - , FromString(xmlJoystickButtonBinder->Attribute("button")), dir); + addJoystickButtonBinding(mControls.back(), FromString(xmlJoystickButtonBinder->Attribute("deviceId")), FromString(xmlJoystickButtonBinder->Attribute("button")), dir); xmlJoystickButtonBinder = xmlJoystickButtonBinder->NextSiblingElement("JoystickButtonBinder"); } } - void InputControlSystem::loadJoystickPOVBinders(TiXmlElement* xmlControlNode) - { - TiXmlElement* xmlJoystickPOVBinder = xmlControlNode->FirstChildElement("JoystickPOVBinder"); - while(xmlJoystickPOVBinder) - { - Control::ControlChangingDirection dir = Control::STOP; - if(std::string(xmlJoystickPOVBinder->Attribute("direction")) == "INCREASE") - { - dir = Control::INCREASE; - } - else if(std::string(xmlJoystickPOVBinder->Attribute("direction")) == "DECREASE") - { - dir = Control::DECREASE; - } - - InputControlSystem::POVAxis axis = /*POVAxis::*/NorthSouth; - if(std::string(xmlJoystickPOVBinder->Attribute("axis")) == "EastWest") - { - axis = /*POVAxis::*/EastWest; - } - - addJoystickPOVBinding(mControls.back(), FromString(xmlJoystickPOVBinder->Attribute("deviceId")) - , FromString(xmlJoystickPOVBinder->Attribute("pov")), axis, dir); - - xmlJoystickPOVBinder = xmlJoystickPOVBinder->NextSiblingElement("JoystickPOVBinder"); - } - } - - void InputControlSystem::loadJoystickSliderBinders(TiXmlElement* xmlControlNode) - { - TiXmlElement* xmlJoystickSliderBinder = xmlControlNode->FirstChildElement("JoystickSliderBinder"); - while(xmlJoystickSliderBinder) - { - Control::ControlChangingDirection dir = Control::STOP; - if(std::string(xmlJoystickSliderBinder->Attribute("direction")) == "INCREASE") - { - dir = Control::INCREASE; - } - else if(std::string(xmlJoystickSliderBinder->Attribute("direction")) == "DECREASE") - { - dir = Control::DECREASE; - } - - addJoystickSliderBinding(mControls.back(), FromString(xmlJoystickSliderBinder->Attribute("deviceId")) - , FromString(xmlJoystickSliderBinder->Attribute("slider")), dir); - - xmlJoystickSliderBinder = xmlJoystickSliderBinder->NextSiblingElement("JoystickSliderBinder"); - } - } - // add bindings - void InputControlSystem::addJoystickAxisBinding(Control* control, int deviceId, int axis, Control::ControlChangingDirection direction) + void InputControlSystem::addJoystickAxisBinding(Control* control, int deviceID, int axis, Control::ControlChangingDirection direction) { - ICS_LOG("\tAdding AxisBinder [deviceid=" - + ToString(deviceId) + ", axis=" - + ToString(axis) + ", direction=" - + ToString(direction) + "]"); + ICS_LOG("\tAdding AxisBinder [axis=" + + ToString(axis) + ", deviceID=" + + ToString(deviceID) + ", direction=" + + ToString(direction) + "]"); + + control->setValue(0.5f); //all joystick axis start at .5, so do that ControlAxisBinderItem controlAxisBinderItem; controlAxisBinderItem.control = control; controlAxisBinderItem.direction = direction; - mControlsJoystickAxisBinderMap[ deviceId ][ axis ] = controlAxisBinderItem; + mControlsJoystickAxisBinderMap[deviceID][axis] = controlAxisBinderItem; } - void InputControlSystem::addJoystickButtonBinding(Control* control, int deviceId, unsigned int button, Control::ControlChangingDirection direction) + void InputControlSystem::addJoystickButtonBinding(Control* control, int deviceID, unsigned int button, Control::ControlChangingDirection direction) { - ICS_LOG("\tAdding JoystickButtonBinder [deviceId=" - + ToString(deviceId) + ", button=" - + ToString(button) + ", direction=" - + ToString(direction) + "]"); + ICS_LOG("\tAdding JoystickButtonBinder [button=" + + ToString(button) + ", deviceID=" + + ToString(deviceID) + ", direction=" + + ToString(direction) + "]"); ControlButtonBinderItem controlJoystickButtonBinderItem; controlJoystickButtonBinderItem.direction = direction; controlJoystickButtonBinderItem.control = control; - mControlsJoystickButtonBinderMap[ deviceId ][ button ] = controlJoystickButtonBinderItem; - } - - void InputControlSystem::addJoystickPOVBinding(Control* control, int deviceId, int index, InputControlSystem::POVAxis axis, Control::ControlChangingDirection direction) - { - ICS_LOG("\tAdding JoystickPOVBinder [deviceId=" - + ToString(deviceId) + ", pov=" - + ToString(index) + ", axis=" - + ToString(axis) + ", direction=" - + ToString(direction) + "]"); - - ControlPOVBinderItem ControlPOVBinderItem; - ControlPOVBinderItem.direction = direction; - ControlPOVBinderItem.control = control; - mControlsJoystickPOVBinderMap[ deviceId ][ index ][ axis ] = ControlPOVBinderItem; - } - - void InputControlSystem::addJoystickSliderBinding(Control* control, int deviceId, int index, Control::ControlChangingDirection direction) - { - ICS_LOG("\tAdding JoystickSliderBinder [deviceId=" - + ToString(deviceId) + ", direction=" - + ToString(index) + ", direction=" - + ToString(direction) + "]"); - - ControlSliderBinderItem ControlSliderBinderItem; - ControlSliderBinderItem.direction = direction; - ControlSliderBinderItem.control = control; - mControlsJoystickSliderBinderMap[ deviceId ][ index ] = ControlSliderBinderItem; + mControlsJoystickButtonBinderMap[deviceID][button] = controlJoystickButtonBinderItem; } // get bindings - int InputControlSystem::getJoystickAxisBinding(Control* control, int deviceId, ICS::Control::ControlChangingDirection direction) - { - if(mControlsJoystickAxisBinderMap.find(deviceId) != mControlsJoystickAxisBinderMap.end()) + int InputControlSystem::getJoystickAxisBinding(Control* control, int deviceID, ICS::Control::ControlChangingDirection direction) + { + if(mControlsJoystickAxisBinderMap.find(deviceID) != mControlsJoystickAxisBinderMap.end()) { - ControlsAxisBinderMapType::iterator it = mControlsJoystickAxisBinderMap[deviceId].begin(); - while(it != mControlsJoystickAxisBinderMap[deviceId].end()) - { - if(it->first >= 0 && it->second.control == control && it->second.direction == direction) - { - return it->first; - } + ControlsAxisBinderMapType::iterator it = mControlsJoystickAxisBinderMap[deviceID].begin(); + while(it != mControlsJoystickAxisBinderMap[deviceID].end()) + { + if(it->first >= 0 && it->second.control == control && it->second.direction == direction) + { + return it->first; + } ++it; - } - } + } + } return /*NamedAxis::*/UNASSIGNED; } - unsigned int InputControlSystem::getJoystickButtonBinding(Control* control, int deviceId, ICS::Control::ControlChangingDirection direction) - { - if(mControlsJoystickButtonBinderMap.find(deviceId) != mControlsJoystickButtonBinderMap.end()) + unsigned int InputControlSystem::getJoystickButtonBinding(Control* control, int deviceID, ICS::Control::ControlChangingDirection direction) + { + if(mControlsJoystickButtonBinderMap.find(deviceID) != mControlsJoystickButtonBinderMap.end()) { - ControlsButtonBinderMapType::iterator it = mControlsJoystickButtonBinderMap[deviceId].begin(); - while(it != mControlsJoystickButtonBinderMap[deviceId].end()) - { - if(it->second.control == control && it->second.direction == direction) - { - return it->first; - } + ControlsButtonBinderMapType::iterator it = mControlsJoystickButtonBinderMap[deviceID].begin(); + while(it != mControlsJoystickButtonBinderMap[deviceID].end()) + { + if(it->second.control == control && it->second.direction == direction) + { + return it->first; + } ++it; - } - } + } + } return ICS_MAX_DEVICE_BUTTONS; } - InputControlSystem::POVBindingPair InputControlSystem::getJoystickPOVBinding(Control* control, int deviceId, ICS::Control::ControlChangingDirection direction) - { - POVBindingPair result; - result.index = -1; - - if(mControlsJoystickPOVBinderMap.find(deviceId) != mControlsJoystickPOVBinderMap.end()) - { - //ControlsAxisBinderMapType::iterator it = mControlsJoystickPOVBinderMap[deviceId].begin(); - std::map::iterator it = mControlsJoystickPOVBinderMap[deviceId].begin(); - while(it != mControlsJoystickPOVBinderMap[deviceId].end()) - { - ControlsPOVBinderMapType::const_iterator it2 = it->second.begin(); - while(it2 != it->second.end()) - { - if(it2->second.control == control && it2->second.direction == direction) - { - result.index = it->first; - result.axis = (POVAxis)it2->first; - return result; - } - it2++; - } - - it++; - } - } - - return result; - } - - int InputControlSystem::getJoystickSliderBinding(Control* control, int deviceId, ICS::Control::ControlChangingDirection direction) - { - if(mControlsJoystickSliderBinderMap.find(deviceId) != mControlsJoystickSliderBinderMap.end()) - { - ControlsButtonBinderMapType::iterator it = mControlsJoystickSliderBinderMap[deviceId].begin(); - while(it != mControlsJoystickSliderBinderMap[deviceId].end()) - { - if(it->second.control == control && it->second.direction == direction) - { - return it->first; - } - it++; - } - } - - return /*NamedAxis::*/UNASSIGNED; - } - // remove bindings - void InputControlSystem::removeJoystickAxisBinding(int deviceId, int axis) - { - if(mControlsJoystickAxisBinderMap.find(deviceId) != mControlsJoystickAxisBinderMap.end()) + void InputControlSystem::removeJoystickAxisBinding(int deviceID, int axis) + { + if(mControlsJoystickAxisBinderMap.find(deviceID) != mControlsJoystickAxisBinderMap.end()) { - ControlsButtonBinderMapType::iterator it = mControlsJoystickAxisBinderMap[deviceId].find(axis); - if(it != mControlsJoystickAxisBinderMap[deviceId].end()) - { - mControlsJoystickAxisBinderMap[deviceId].erase(it); - } - } + ControlsAxisBinderMapType::iterator it = mControlsJoystickAxisBinderMap[deviceID].find(axis); + if(it != mControlsJoystickAxisBinderMap[deviceID].end()) + { + mControlsJoystickAxisBinderMap[deviceID].erase(it); + } + } } - void InputControlSystem::removeJoystickButtonBinding(int deviceId, unsigned int button) - { - if(mControlsJoystickButtonBinderMap.find(deviceId) != mControlsJoystickButtonBinderMap.end()) + void InputControlSystem::removeJoystickButtonBinding(int deviceID, unsigned int button) + { + if(mControlsJoystickButtonBinderMap.find(deviceID) != mControlsJoystickButtonBinderMap.end()) { - ControlsButtonBinderMapType::iterator it = mControlsJoystickButtonBinderMap[deviceId].find(button); - if(it != mControlsJoystickButtonBinderMap[deviceId].end()) - { - mControlsJoystickButtonBinderMap[deviceId].erase(it); - } - } - } - - void InputControlSystem::removeJoystickPOVBinding(int deviceId, int index, POVAxis axis) - { - if(mControlsJoystickPOVBinderMap.find(deviceId) != mControlsJoystickPOVBinderMap.end()) - { - std::map::iterator it = mControlsJoystickPOVBinderMap[deviceId].find(index); - if(it != mControlsJoystickPOVBinderMap[deviceId].end()) - { - if(it->second.find(axis) != it->second.end()) - { - it->second.erase( it->second.find(axis) ); - } - } - } - } - - void InputControlSystem::removeJoystickSliderBinding(int deviceId, int index) - { - if(mControlsJoystickSliderBinderMap.find(deviceId) != mControlsJoystickSliderBinderMap.end()) - { - ControlsButtonBinderMapType::iterator it = mControlsJoystickSliderBinderMap[deviceId].find(index); - if(it != mControlsJoystickSliderBinderMap[deviceId].end()) - { - mControlsJoystickSliderBinderMap[deviceId].erase(it); - } - } + ControlsButtonBinderMapType::iterator it = mControlsJoystickButtonBinderMap[deviceID].find(button); + if(it != mControlsJoystickButtonBinderMap[deviceID].end()) + { + mControlsJoystickButtonBinderMap[deviceID].erase(it); + } + } } // joyStick listeners - void InputControlSystem::buttonPressed(const SDL_JoyButtonEvent &evt, int button) - { - if(mActive) - { - if(!mDetectingBindingControl) - { - if(mControlsJoystickButtonBinderMap.find(evt.which) != mControlsJoystickButtonBinderMap.end()) - { - ControlsButtonBinderMapType::const_iterator it = mControlsJoystickButtonBinderMap[evt.which].find(button); - if(it != mControlsJoystickButtonBinderMap[evt.which].end()) - { - it->second.control->setIgnoreAutoReverse(false); - if(!it->second.control->getAutoChangeDirectionOnLimitsAfterStop()) - { - it->second.control->setChangingDirection(it->second.direction); - } - else - { - if(it->second.control->getValue() == 1) - { - it->second.control->setChangingDirection(Control::DECREASE); - } - else if(it->second.control->getValue() == 0) - { - it->second.control->setChangingDirection(Control::INCREASE); - } - } - } - } - } - else if(mDetectingBindingListener) - { - mDetectingBindingListener->joystickButtonBindingDetected(this, - mDetectingBindingControl, evt.which, button, mDetectingBindingDirection); - } - } - } - - void InputControlSystem::buttonReleased(const SDL_JoyButtonEvent &evt, int button) - { - if(mActive) - { - if(mControlsJoystickButtonBinderMap.find(evt.which) != mControlsJoystickButtonBinderMap.end()) - { - ControlsButtonBinderMapType::const_iterator it = mControlsJoystickButtonBinderMap[evt.which].find(button); - if(it != mControlsJoystickButtonBinderMap[evt.which].end()) - { - it->second.control->setChangingDirection(Control::STOP); - } - } - } - } - - void InputControlSystem::axisMoved(const SDL_JoyAxisEvent &evt, int axis) + void InputControlSystem::buttonPressed(int deviceID, const SDL_ControllerButtonEvent &evt) { if(mActive) { if(!mDetectingBindingControl) + { + if(mControlsJoystickButtonBinderMap.find(deviceID) != mControlsJoystickButtonBinderMap.end()) + { + ControlsButtonBinderMapType::const_iterator it = mControlsJoystickButtonBinderMap[deviceID].find(evt.button); + if(it != mControlsJoystickButtonBinderMap[deviceID].end()) + { + it->second.control->setIgnoreAutoReverse(false); + if(!it->second.control->getAutoChangeDirectionOnLimitsAfterStop()) + { + it->second.control->setChangingDirection(it->second.direction); + } + else + { + if(it->second.control->getValue() == 1) + { + it->second.control->setChangingDirection(Control::DECREASE); + } + else if(it->second.control->getValue() == 0) + { + it->second.control->setChangingDirection(Control::INCREASE); + } + } + } + } + } + } + } + + void InputControlSystem::buttonReleased(int deviceID, const SDL_ControllerButtonEvent &evt) + { + if(mActive) + { + if(!mDetectingBindingControl) + { + if(mControlsJoystickButtonBinderMap.find(deviceID) != mControlsJoystickButtonBinderMap.end()) + { + ControlsButtonBinderMapType::const_iterator it = mControlsJoystickButtonBinderMap[deviceID].find(evt.button); + if(it != mControlsJoystickButtonBinderMap[deviceID].end()) + { + it->second.control->setChangingDirection(Control::STOP); + } + } + } + else if(mDetectingBindingListener) { - if(mControlsJoystickAxisBinderMap.find(evt.which) != mControlsJoystickAxisBinderMap.end()) - { - ControlAxisBinderItem joystickBinderItem = mControlsJoystickAxisBinderMap[ evt.which ][ axis ]; // joystic axis start at 0 index - Control* ctrl = joystickBinderItem.control; - if(ctrl) - { - ctrl->setIgnoreAutoReverse(true); + mDetectingBindingListener->joystickButtonBindingDetected(this, deviceID, + mDetectingBindingControl, evt.button, mDetectingBindingDirection); + } + } + } - float axisRange = SDL_JOY_AXIS_MAX - SDL_JOY_AXIS_MIN; - float valDisplaced = (float)(evt.value - SDL_JOY_AXIS_MIN); + void InputControlSystem::axisMoved(int deviceID, const SDL_ControllerAxisEvent &evt) + { + if(mActive) + { + if(!mDetectingBindingControl) + { + if(mControlsJoystickAxisBinderMap.find(deviceID) != mControlsJoystickAxisBinderMap.end()) + { + ControlAxisBinderItem joystickBinderItem = mControlsJoystickAxisBinderMap[deviceID][evt.axis]; // joystic axis start at 0 index + Control* ctrl = joystickBinderItem.control; + if(ctrl) + { + ctrl->setIgnoreAutoReverse(true); - if(joystickBinderItem.direction == Control::INCREASE) - { - ctrl->setValue( valDisplaced / axisRange ); - } - else if(joystickBinderItem.direction == Control::DECREASE) - { - ctrl->setValue( 1 - ( valDisplaced / axisRange ) ); - } - } - } + float axisRange = SDL_JOY_AXIS_MAX - SDL_JOY_AXIS_MIN; + float valDisplaced = (float)(evt.value - SDL_JOY_AXIS_MIN); + float percent = valDisplaced / axisRange * (1+DEADZONE*2) - DEADZONE; //Assures all values, 0 through 1, are seen + if(percent > .5-DEADZONE && percent < .5+DEADZONE) //close enough to center + percent = .5; + else if(percent > .5) + percent -= DEADZONE; + else + percent += DEADZONE; + + if(joystickBinderItem.direction == Control::INCREASE) + { + ctrl->setValue( percent ); + } + else if(joystickBinderItem.direction == Control::DECREASE) + { + ctrl->setValue( 1 - ( percent ) ); + } + } + } } else if(mDetectingBindingListener) { @@ -408,250 +267,76 @@ namespace ICS { if( abs( evt.value ) > ICS_JOYSTICK_AXIS_BINDING_MARGIN) { - mDetectingBindingListener->joystickAxisBindingDetected(this, - mDetectingBindingControl, evt.which, axis, mDetectingBindingDirection); + mDetectingBindingListener->joystickAxisBindingDetected(this, deviceID, + mDetectingBindingControl, evt.axis, mDetectingBindingDirection); } } } } - } - - //Here be dragons, apparently - void InputControlSystem::povMoved(const SDL_JoyHatEvent &evt, int index) + } + + void InputControlSystem::controllerAdded(int deviceID, const SDL_ControllerDeviceEvent &args) { - if(mActive) - { - if(!mDetectingBindingControl) - { - if(mControlsJoystickPOVBinderMap.find(evt.which) != mControlsJoystickPOVBinderMap.end()) - { - std::map::const_iterator i = mControlsJoystickPOVBinderMap[ evt.which ].find(index); - if(i != mControlsJoystickPOVBinderMap[ evt.which ].end()) - { - if(evt.value != SDL_HAT_LEFT - && evt.value != SDL_HAT_RIGHT - && evt.value != SDL_HAT_CENTERED) - { - ControlsPOVBinderMapType::const_iterator it = i->second.find( /*POVAxis::*/NorthSouth ); - if(it != i->second.end()) - { - it->second.control->setIgnoreAutoReverse(false); - if(!it->second.control->getAutoChangeDirectionOnLimitsAfterStop()) - { - if(evt.value == SDL_HAT_UP - || evt.value == SDL_HAT_LEFTUP - || evt.value == SDL_HAT_RIGHTUP) - { - it->second.control->setChangingDirection(it->second.direction); - } - else - { - it->second.control->setChangingDirection((Control::ControlChangingDirection)(-1 * it->second.direction)); - } - } - else - { - if(it->second.control->getValue() == 1) - { - it->second.control->setChangingDirection(Control::DECREASE); - } - else if(it->second.control->getValue() == 0) - { - it->second.control->setChangingDirection(Control::INCREASE); - } - } - } - } + ICS_LOG("Adding joystick (index: " + ToString(args.which) + ")"); + SDL_GameController* cntrl = SDL_GameControllerOpen(args.which); + int instanceID = SDL_JoystickInstanceID(SDL_GameControllerGetJoystick(cntrl)); + if(std::find(mJoystickIDList.begin(), mJoystickIDList.end(), deviceID)==mJoystickIDList.end()) + { + for(int j = 0 ; j < ICS_MAX_JOYSTICK_AXIS ; j++) + { + if(mControlsJoystickAxisBinderMap[deviceID].find(j) == mControlsJoystickAxisBinderMap[deviceID].end()) + { + ControlAxisBinderItem controlJoystickBinderItem; + controlJoystickBinderItem.direction = Control::STOP; + controlJoystickBinderItem.control = NULL; + mControlsJoystickAxisBinderMap[deviceID][j] = controlJoystickBinderItem; + } + } + mJoystickIDList.push_front(deviceID); + } - if(evt.value != SDL_HAT_UP - && evt.value != SDL_HAT_DOWN - && evt.value != SDL_HAT_CENTERED) - { - ControlsPOVBinderMapType::const_iterator it = i->second.find( /*POVAxis::*/EastWest ); - if(it != i->second.end()) - { - it->second.control->setIgnoreAutoReverse(false); - if(!it->second.control->getAutoChangeDirectionOnLimitsAfterStop()) - { - if(evt.value == SDL_HAT_RIGHT - || evt.value == SDL_HAT_RIGHTUP - || evt.value == SDL_HAT_RIGHTDOWN) - { - it->second.control->setChangingDirection(it->second.direction); - } - else - { - it->second.control->setChangingDirection((Control::ControlChangingDirection)(-1 * it->second.direction)); - } - } - else - { - if(it->second.control->getValue() == 1) - { - it->second.control->setChangingDirection(Control::DECREASE); - } - else if(it->second.control->getValue() == 0) - { - it->second.control->setChangingDirection(Control::INCREASE); - } - } - } - } - - if(evt.value == SDL_HAT_CENTERED) - { - ControlsPOVBinderMapType::const_iterator it = i->second.find( /*POVAxis::*/NorthSouth ); - if(it != i->second.end()) - { - it->second.control->setChangingDirection(Control::STOP); - } - - it = i->second.find( /*POVAxis::*/EastWest ); - if(it != i->second.end()) - { - it->second.control->setChangingDirection(Control::STOP); - } - } - } - } - } - else if(mDetectingBindingListener) - { - if(mDetectingBindingControl && mDetectingBindingControl->isAxisBindable()) - { - if(evt.value == SDL_HAT_LEFT - || evt.value == SDL_HAT_RIGHT - || evt.value == SDL_HAT_UP - || evt.value == SDL_HAT_DOWN) - { - POVAxis povAxis = NorthSouth; - if(evt.value == SDL_HAT_LEFT - || evt.value == SDL_HAT_RIGHT) - { - povAxis = EastWest; - } - - mDetectingBindingListener->joystickPOVBindingDetected(this, - mDetectingBindingControl, evt.which, index, povAxis, mDetectingBindingDirection); - } - } - } - } + mJoystickInstanceMap[instanceID] = cntrl; + } + void InputControlSystem::controllerRemoved(const SDL_ControllerDeviceEvent &args) + { + ICS_LOG("Removing joystick (instance id: " + ToString(args.which) + ")"); + if(mJoystickInstanceMap.count(args.which)!=0) + { + SDL_GameControllerClose(mJoystickInstanceMap.at(args.which)); + mJoystickInstanceMap.erase(args.which); + } } - //TODO: does this have an SDL equivalent? - /* - void InputControlSystem::sliderMoved(const OIS::JoyStickEvent &evt, int index) - { - if(mActive) - { - if(!mDetectingBindingControl) - { - if(mControlsJoystickSliderBinderMap.find(evt.device->getID()) != mControlsJoystickSliderBinderMap.end()) - { - ControlSliderBinderItem joystickBinderItem = mControlsJoystickSliderBinderMap[ evt.device->getID() ][ index ]; - Control* ctrl = joystickBinderItem.control; - if(ctrl) - { - ctrl->setIgnoreAutoReverse(true); - if(joystickBinderItem.direction == Control::INCREASE) - { - float axisRange = OIS::JoyStick::MAX_AXIS - OIS::JoyStick::MIN_AXIS; - float valDisplaced = (float)( evt.state.mSliders[index].abX - OIS::JoyStick::MIN_AXIS); - - ctrl->setValue( valDisplaced / axisRange ); - } - else if(joystickBinderItem.direction == Control::DECREASE) - { - float axisRange = OIS::JoyStick::MAX_AXIS - OIS::JoyStick::MIN_AXIS; - float valDisplaced = (float)(evt.state.mSliders[index].abX - OIS::JoyStick::MIN_AXIS); - - ctrl->setValue( 1 - ( valDisplaced / axisRange ) ); - } - } - } - } - else if(mDetectingBindingListener) - { - if(mDetectingBindingControl && mDetectingBindingControl->isAxisBindable()) - { - if( abs( evt.state.mSliders[index].abX ) > ICS_JOYSTICK_SLIDER_BINDING_MARGIN) - { - mDetectingBindingListener->joystickSliderBindingDetected(this, - mDetectingBindingControl, evt.device->getID(), index, mDetectingBindingDirection); - } - } - } - } - } - */ - // joystick auto bindings - void DetectingBindingListener::joystickAxisBindingDetected(InputControlSystem* ICS, Control* control - , int deviceId, int axis, Control::ControlChangingDirection direction) + void DetectingBindingListener::joystickAxisBindingDetected(InputControlSystem* ICS, int deviceID, Control* control, int axis, Control::ControlChangingDirection direction) { // if the joystick axis is used by another control, remove it - ICS->removeJoystickAxisBinding(deviceId, axis); + ICS->removeJoystickAxisBinding(deviceID, axis); // if the control has an axis assigned, remove it - int oldAxis = ICS->getJoystickAxisBinding(control, deviceId, direction); - if(oldAxis != InputControlSystem::UNASSIGNED) + int oldAxis = ICS->getJoystickAxisBinding(control, deviceID, direction); + if(oldAxis != InputControlSystem::UNASSIGNED) { - ICS->removeJoystickAxisBinding(deviceId, oldAxis); + ICS->removeJoystickAxisBinding(deviceID, oldAxis); } - ICS->addJoystickAxisBinding(control, deviceId, axis, direction); + ICS->addJoystickAxisBinding(control, deviceID, axis, direction); ICS->cancelDetectingBindingState(); } - void DetectingBindingListener::joystickButtonBindingDetected(InputControlSystem* ICS, Control* control - , int deviceId, unsigned int button, Control::ControlChangingDirection direction) + void DetectingBindingListener::joystickButtonBindingDetected(InputControlSystem* ICS, int deviceID, Control* control + , unsigned int button, Control::ControlChangingDirection direction) { // if the joystick button is used by another control, remove it - ICS->removeJoystickButtonBinding(deviceId, button); + ICS->removeJoystickButtonBinding(deviceID, button); // if the control has a joystick button assigned, remove it - unsigned int oldButton = ICS->getJoystickButtonBinding(control, deviceId, direction); + unsigned int oldButton = ICS->getJoystickButtonBinding(control, deviceID, direction); if(oldButton != ICS_MAX_DEVICE_BUTTONS) { - ICS->removeJoystickButtonBinding(deviceId, oldButton); + ICS->removeJoystickButtonBinding(deviceID, oldButton); } - ICS->addJoystickButtonBinding(control, deviceId, button, direction); - ICS->cancelDetectingBindingState(); - } - - - void DetectingBindingListener::joystickPOVBindingDetected(InputControlSystem* ICS, Control* control - , int deviceId, int pov, InputControlSystem::POVAxis axis, Control::ControlChangingDirection direction) - { - // if the joystick slider is used by another control, remove it - ICS->removeJoystickPOVBinding(deviceId, pov, axis); - - // if the control has a joystick button assigned, remove it - ICS::InputControlSystem::POVBindingPair oldPOV = ICS->getJoystickPOVBinding(control, deviceId, direction); - if(oldPOV.index >= 0 && oldPOV.axis == axis) - { - ICS->removeJoystickPOVBinding(deviceId, oldPOV.index, oldPOV.axis); - } - - ICS->addJoystickPOVBinding(control, deviceId, pov, axis, direction); - ICS->cancelDetectingBindingState(); - } - - void DetectingBindingListener::joystickSliderBindingDetected(InputControlSystem* ICS, Control* control - , int deviceId, int slider, Control::ControlChangingDirection direction) - { - // if the joystick slider is used by another control, remove it - ICS->removeJoystickSliderBinding(deviceId, slider); - - // if the control has a joystick slider assigned, remove it - int oldSlider = ICS->getJoystickSliderBinding(control, deviceId, direction); - if(oldSlider != InputControlSystem::/*NamedAxis::*/UNASSIGNED) - { - ICS->removeJoystickSliderBinding(deviceId, oldSlider); - } - - ICS->addJoystickSliderBinding(control, deviceId, slider, direction); + ICS->addJoystickButtonBinding(control, deviceID, button, direction); ICS->cancelDetectingBindingState(); } } diff --git a/extern/sdl4ogre/CMakeLists.txt b/extern/sdl4ogre/CMakeLists.txt index 86ce7b70e..b8c56bd00 100644 --- a/extern/sdl4ogre/CMakeLists.txt +++ b/extern/sdl4ogre/CMakeLists.txt @@ -6,6 +6,7 @@ set(SDL4OGRE_SOURCE_FILES sdlinputwrapper.cpp sdlcursormanager.cpp sdlwindowhelper.cpp + imagerotate.cpp ) if (APPLE) diff --git a/extern/sdl4ogre/events.h b/extern/sdl4ogre/events.h index 6961e81fc..986dd7d8b 100644 --- a/extern/sdl4ogre/events.h +++ b/extern/sdl4ogre/events.h @@ -40,23 +40,25 @@ public: virtual void keyReleased(const SDL_KeyboardEvent &arg) = 0; }; -class JoyListener +class ControllerListener { public: - virtual ~JoyListener() {} + virtual ~ControllerListener() {} /** @remarks Joystick button down event */ - virtual void buttonPressed( const SDL_JoyButtonEvent &evt, int button ) = 0; + virtual void buttonPressed(int deviceID, const SDL_ControllerButtonEvent &evt) = 0; /** @remarks Joystick button up event */ - virtual void buttonReleased( const SDL_JoyButtonEvent &evt, int button ) = 0; + virtual void buttonReleased(int deviceID, const SDL_ControllerButtonEvent &evt) = 0; /** @remarks Joystick axis moved event */ - virtual void axisMoved( const SDL_JoyAxisEvent &arg, int axis ) = 0; + virtual void axisMoved(int deviceID, const SDL_ControllerAxisEvent &arg) = 0; - //-- Not so common control events, so are not required --// + /** @remarks Joystick Added **/ + virtual void controllerAdded(int deviceID, const SDL_ControllerDeviceEvent &arg) = 0; + + /** @remarks Joystick Removed **/ + virtual void controllerRemoved(const SDL_ControllerDeviceEvent &arg) = 0; - //! Joystick Event, and povID - virtual void povMoved( const SDL_JoyHatEvent &arg, int index) {} }; class WindowListener diff --git a/libs/openengine/ogre/imagerotate.cpp b/extern/sdl4ogre/imagerotate.cpp similarity index 99% rename from libs/openengine/ogre/imagerotate.cpp rename to extern/sdl4ogre/imagerotate.cpp index cc5f572cf..b825943fc 100644 --- a/libs/openengine/ogre/imagerotate.cpp +++ b/extern/sdl4ogre/imagerotate.cpp @@ -17,7 +17,9 @@ #include using namespace Ogre; -using namespace OEngine::Render; + +namespace SFO +{ void ImageRotate::rotate(const std::string& sourceImage, const std::string& destImage, const float angle) { @@ -93,3 +95,5 @@ void ImageRotate::rotate(const std::string& sourceImage, const std::string& dest root->destroySceneManager(sceneMgr); delete rect; } + +} diff --git a/libs/openengine/ogre/imagerotate.hpp b/extern/sdl4ogre/imagerotate.hpp similarity index 94% rename from libs/openengine/ogre/imagerotate.hpp rename to extern/sdl4ogre/imagerotate.hpp index a3f6d662f..7135a571a 100644 --- a/libs/openengine/ogre/imagerotate.hpp +++ b/extern/sdl4ogre/imagerotate.hpp @@ -3,9 +3,8 @@ #include -namespace OEngine -{ -namespace Render + +namespace SFO { /// Rotate an image by certain degrees and save as file, uses the GPU @@ -22,6 +21,5 @@ namespace Render }; } -} #endif diff --git a/extern/sdl4ogre/sdlcursormanager.cpp b/extern/sdl4ogre/sdlcursormanager.cpp index 7623d57db..61d9c32dd 100644 --- a/extern/sdl4ogre/sdlcursormanager.cpp +++ b/extern/sdl4ogre/sdlcursormanager.cpp @@ -7,7 +7,7 @@ #include #include -#include +#include "imagerotate.hpp" namespace SFO { @@ -91,7 +91,7 @@ namespace SFO // we use a render target to uncompress the DDS texture // just blitting doesn't seem to work on D3D9 - OEngine::Render::ImageRotate::rotate(tex->getName(), tempName, -rotDegrees); + ImageRotate::rotate(tex->getName(), tempName, static_cast(-rotDegrees)); Ogre::TexturePtr resultTexture = Ogre::TextureManager::getSingleton().getByName(tempName); @@ -110,7 +110,8 @@ namespace SFO Ogre::ColourValue clr = destImage.getColourAt(x, y, 0); //set the pixel on the SDL surface to the same value as the Ogre texture's - _putPixel(surf, x, y, SDL_MapRGBA(surf->format, clr.r*255, clr.g*255, clr.b*255, clr.a*255)); + _putPixel(surf, x, y, SDL_MapRGBA(surf->format, static_cast(clr.r * 255), + static_cast(clr.g * 255), static_cast(clr.b * 255), static_cast(clr.a * 255))); } } diff --git a/extern/sdl4ogre/sdlinputwrapper.cpp b/extern/sdl4ogre/sdlinputwrapper.cpp index a6c7d3e5c..aaf669ff4 100644 --- a/extern/sdl4ogre/sdlinputwrapper.cpp +++ b/extern/sdl4ogre/sdlinputwrapper.cpp @@ -20,7 +20,7 @@ namespace SFO mMouseY(0), mMouseX(0), mMouseInWindow(true), - mJoyListener(NULL), + mConListener(NULL), mKeyboardListener(NULL), mMouseListener(NULL), mWindowListener(NULL), @@ -91,24 +91,32 @@ namespace SFO case SDL_TEXTINPUT: mKeyboardListener->textInput(evt.text); break; + case SDL_JOYHATMOTION: //As we manage everything with GameController, don't even bother with these. case SDL_JOYAXISMOTION: - if (mJoyListener) - mJoyListener->axisMoved(evt.jaxis, evt.jaxis.axis); - break; case SDL_JOYBUTTONDOWN: - if (mJoyListener) - mJoyListener->buttonPressed(evt.jbutton, evt.jbutton.button); - break; case SDL_JOYBUTTONUP: - if (mJoyListener) - mJoyListener->buttonReleased(evt.jbutton, evt.jbutton.button); - break; case SDL_JOYDEVICEADDED: - //SDL_JoystickOpen(evt.jdevice.which); - //std::cout << "Detected a new joystick: " << SDL_JoystickNameForIndex(evt.jdevice.which) << std::endl; - break; case SDL_JOYDEVICEREMOVED: - //std::cout << "A joystick has been removed" << std::endl; + break; + case SDL_CONTROLLERDEVICEADDED: + if(mConListener) + mConListener->controllerAdded(1, evt.cdevice); //We only support one joystick, so give everything a generic deviceID + break; + case SDL_CONTROLLERDEVICEREMOVED: + if(mConListener) + mConListener->controllerRemoved(evt.cdevice); + break; + case SDL_CONTROLLERBUTTONDOWN: + if(mConListener) + mConListener->buttonPressed(1, evt.cbutton); + break; + case SDL_CONTROLLERBUTTONUP: + if(mConListener) + mConListener->buttonReleased(1, evt.cbutton); + break; + case SDL_CONTROLLERAXISMOTION: + if(mConListener) + mConListener->axisMoved(1, evt.caxis); break; case SDL_WINDOWEVENT: handleWindowEvent(evt); @@ -193,12 +201,12 @@ namespace SFO bool InputWrapper::isModifierHeld(SDL_Keymod mod) { - return SDL_GetModState() & mod; + return (SDL_GetModState() & mod) != 0; } bool InputWrapper::isKeyDown(SDL_Scancode key) { - return SDL_GetKeyboardState(NULL)[key]; + return (SDL_GetKeyboardState(NULL)[key]) != 0; } /// \brief Moves the mouse to the specified point within the viewport diff --git a/extern/sdl4ogre/sdlinputwrapper.hpp b/extern/sdl4ogre/sdlinputwrapper.hpp index af16ab68d..a7023207c 100644 --- a/extern/sdl4ogre/sdlinputwrapper.hpp +++ b/extern/sdl4ogre/sdlinputwrapper.hpp @@ -24,7 +24,7 @@ namespace SFO void setMouseEventCallback(MouseListener* listen) { mMouseListener = listen; } void setKeyboardEventCallback(KeyListener* listen) { mKeyboardListener = listen; } void setWindowEventCallback(WindowListener* listen) { mWindowListener = listen; } - void setJoyEventCallback(JoyListener* listen) { mJoyListener = listen; } + void setControllerEventCallback(ControllerListener* listen) { mConListener = listen; } void capture(bool windowEventsOnly); bool isModifierHeld(SDL_Keymod mod); @@ -54,7 +54,7 @@ namespace SFO SFO::MouseListener* mMouseListener; SFO::KeyListener* mKeyboardListener; SFO::WindowListener* mWindowListener; - SFO::JoyListener* mJoyListener; + SFO::ControllerListener* mConListener; typedef boost::unordered_map KeyMap; KeyMap mKeyMap; diff --git a/extern/sdl4ogre/sdlwindowhelper.cpp b/extern/sdl4ogre/sdlwindowhelper.cpp index 44993947f..637fae0ef 100644 --- a/extern/sdl4ogre/sdlwindowhelper.cpp +++ b/extern/sdl4ogre/sdlwindowhelper.cpp @@ -93,7 +93,8 @@ void SDLWindowHelper::setWindowIcon(const std::string &name) int bpp = surface->format->BytesPerPixel; /* Here p is the address to the pixel we want to set */ Uint8 *p = (Uint8 *)surface->pixels + y * surface->pitch + x * bpp; - Uint32 pixel = SDL_MapRGBA(surface->format, clr.r*255, clr.g*255, clr.b*255, clr.a*255); + Uint32 pixel = SDL_MapRGBA(surface->format, static_cast(clr.r * 255), + static_cast(clr.g * 255), static_cast(clr.b * 255), static_cast(clr.a * 255)); switch(bpp) { case 1: *p = pixel; diff --git a/extern/shiny/Platforms/Ogre/OgrePass.cpp b/extern/shiny/Platforms/Ogre/OgrePass.cpp index 3a25c5c74..5cd501094 100644 --- a/extern/shiny/Platforms/Ogre/OgrePass.cpp +++ b/extern/shiny/Platforms/Ogre/OgrePass.cpp @@ -109,7 +109,7 @@ namespace sh { params->addSharedParameters (name); } - catch (Ogre::Exception& e) + catch (Ogre::Exception& ) { std::stringstream msg; msg << "Could not create a shared parameter instance for '" diff --git a/files/gamecontrollerdb.txt b/files/gamecontrollerdb.txt new file mode 100644 index 000000000..bd8d9c5fc --- /dev/null +++ b/files/gamecontrollerdb.txt @@ -0,0 +1,101 @@ +# from https://github.com/gabomdq/SDL_GameControllerDB +# License: +# Simple DirectMedia Layer +# Copyright (C) 1997-2013 Sam Lantinga +# +# This software is provided 'as-is', without any express or implied +# warranty. In no event will the authors be held liable for any damages +# arising from the use of this software. +# +# Permission is granted to anyone to use this software for any purpose, +# including commercial applications, and to alter it and redistribute it +# freely, subject to the following restrictions: +# +# 1. The origin of this software must not be misrepresented; you must not +# claim that you wrote the original software. If you use this software +# in a product, an acknowledgment in the product documentation would be +# appreciated but is not required. +# 2. Altered source versions must be plainly marked as such, and must not be +# misrepresented as being the original software. +# 3. This notice may not be removed or altered from any source distribution. + +# Windows - DINPUT +8f0e1200000000000000504944564944,Acme,platform:Windows,x:b2,a:b0,b:b1,y:b3,back:b8,start:b9,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,dpup:h0.1,leftshoulder:b4,lefttrigger:b5,rightshoulder:b6,righttrigger:b7,leftstick:b10,rightstick:b11,leftx:a0,lefty:a1,rightx:a3,righty:a2, +341a3608000000000000504944564944,Afterglow PS3 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Windows, +ffff0000000000000000504944564944,GameStop Gamepad,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b2,y:b3,platform:Windows, +6d0416c2000000000000504944564944,Generic DirectInput Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Windows, +6d0419c2000000000000504944564944,Logitech F710 Gamepad,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Windows, +88880803000000000000504944564944,PS3 Controller,a:b2,b:b1,back:b8,dpdown:h0.8,dpleft:h0.4,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b9,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:b7,rightx:a3,righty:a4,start:b11,x:b0,y:b3,platform:Windows, +4c056802000000000000504944564944,PS3 Controller,a:b14,b:b13,back:b0,dpdown:b6,dpleft:b7,dpright:b5,dpup:b4,guide:b16,leftshoulder:b10,leftstick:b1,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b11,rightstick:b2,righttrigger:b9,rightx:a2,righty:a3,start:b3,x:b15,y:b12,platform:Windows, +25090500000000000000504944564944,PS3 DualShock,a:b2,b:b1,back:b9,dpdown:h0.8,dpleft:h0.4,dpright:h0.2,dpup:h0.1,guide:,leftshoulder:b6,leftstick:b10,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b11,righttrigger:b5,rightx:a2,righty:a3,start:b8,x:b0,y:b3,platform:Windows, +4c05c405000000000000504944564944,PS4 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Windows, +6d0418c2000000000000504944564944,Logitech RumblePad 2 USB,platform:Windows,x:b0,a:b1,b:b2,y:b3,back:b8,start:b9,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,dpup:h0.1,leftshoulder:b4,lefttrigger:b6,rightshoulder:b5,righttrigger:b7,leftstick:b10,rightstick:b11,leftx:a0,lefty:a1,rightx:a2,righty:a3, +36280100000000000000504944564944,OUYA Controller,platform:Windows,a:b0,b:b3,y:b2,x:b1,start:b14,guide:b15,leftstick:b6,rightstick:b7,leftshoulder:b4,rightshoulder:b5,dpup:b8,dpleft:b10,dpdown:b9,dpright:b11,leftx:a0,lefty:a1,rightx:a3,righty:a4,lefttrigger:b12,righttrigger:b13, +4f0400b3000000000000504944564944,Thrustmaster Firestorm Dual Power,a:b0,b:b2,y:b3,x:b1,start:b10,guide:b8,back:b9,leftstick:b11,rightstick:b12,leftshoulder:b4,rightshoulder:b6,dpup:h0.1,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,leftx:a0,lefty:a1,rightx:a2,righty:a3,lefttrigger:b5,righttrigger:b7,platform:Windows, +00f00300000000000000504944564944,RetroUSB.com RetroPad,a:b1,b:b5,x:b0,y:b4,back:b2,start:b3,leftshoulder:b6,rightshoulder:b7,leftx:a0,lefty:a1,platform:Windows, +00f0f100000000000000504944564944,RetroUSB.com Super RetroPort,a:b1,b:b5,x:b0,y:b4,back:b2,start:b3,leftshoulder:b6,rightshoulder:b7,leftx:a0,lefty:a1,platform:Windows, +28040140000000000000504944564944,GamePad Pro USB,platform:Windows,a:b1,b:b2,x:b0,y:b3,back:b8,start:b9,leftshoulder:b4,rightshoulder:b5,leftx:a0,lefty:a1,lefttrigger:b6,righttrigger:b7, +ff113133000000000000504944564944,SVEN X-PAD,platform:Windows,a:b2,b:b3,y:b1,x:b0,start:b5,back:b4,leftshoulder:b6,rightshoulder:b7,dpup:h0.1,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,leftx:a0,lefty:a1,rightx:a2,righty:a4,lefttrigger:b8,righttrigger:b9, +8f0e0300000000000000504944564944,Piranha xtreme,platform:Windows,x:b3,a:b2,b:b1,y:b0,back:b8,start:b9,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,dpup:h0.1,leftshoulder:b6,lefttrigger:b4,rightshoulder:b7,righttrigger:b5,leftstick:b10,rightstick:b11,leftx:a0,lefty:a1,rightx:a3,righty:a2, +8f0e0d31000000000000504944564944,Multilaser JS071 USB,platform:Windows,a:b1,b:b2,y:b3,x:b0,start:b9,back:b8,leftstick:b10,rightstick:b11,leftshoulder:b4,rightshoulder:b5,dpup:h0.1,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,leftx:a0,lefty:a1,rightx:a2,righty:a3,lefttrigger:b6,righttrigger:b7, +10080300000000000000504944564944,PS2 USB,platform:Windows,a:b2,b:b1,y:b0,x:b3,start:b9,back:b8,leftstick:b10,rightstick:b11,leftshoulder:b6,rightshoulder:b7,dpup:h0.1,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,leftx:a0,lefty:a1,rightx:a4,righty:a2,lefttrigger:b4,righttrigger:b5, + +# OS X +0500000047532047616d657061640000,GameStop Gamepad,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b2,y:b3,platform:Mac OS X, +6d0400000000000016c2000000000000,Logitech F310 Gamepad (DInput),a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Mac OS X, +6d0400000000000018c2000000000000,Logitech F510 Gamepad (DInput),a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Mac OS X, +6d040000000000001fc2000000000000,Logitech F710 Gamepad (XInput),a:b0,b:b1,back:b9,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,guide:b10,leftshoulder:b4,leftstick:b6,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b7,righttrigger:a5,rightx:a3,righty:a4,start:b8,x:b2,y:b3,platform:Mac OS X, +6d0400000000000019c2000000000000,Logitech Wireless Gamepad (DInput),a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Mac OS X, +4c050000000000006802000000000000,PS3 Controller,a:b14,b:b13,back:b0,dpdown:b6,dpleft:b7,dpright:b5,dpup:b4,guide:b16,leftshoulder:b10,leftstick:b1,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b11,rightstick:b2,righttrigger:b9,rightx:a2,righty:a3,start:b3,x:b15,y:b12,platform:Mac OS X, +4c05000000000000c405000000000000,PS4 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,Platform:Mac OS X, +5e040000000000008e02000000000000,X360 Controller,a:b0,b:b1,back:b9,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,guide:b10,leftshoulder:b4,leftstick:b6,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b7,righttrigger:a5,rightx:a3,righty:a4,start:b8,x:b2,y:b3,platform:Mac OS X, +891600000000000000fd000000000000,Razer Onza Tournament,a:b0,b:b1,y:b3,x:b2,start:b8,guide:b10,back:b9,leftstick:b6,rightstick:b7,leftshoulder:b4,rightshoulder:b5,dpup:b11,dpleft:b13,dpdown:b12,dpright:b14,leftx:a0,lefty:a1,rightx:a3,righty:a4,lefttrigger:a2,righttrigger:a5,platform:Mac OS X, +4f0400000000000000b3000000000000,Thrustmaster Firestorm Dual Power,a:b0,b:b2,y:b3,x:b1,start:b10,guide:b8,back:b9,leftstick:b11,rightstick:,leftshoulder:b4,rightshoulder:b6,dpup:h0.1,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,leftx:a0,lefty:a1,rightx:a2,righty:a3,lefttrigger:b5,righttrigger:b7,platform:Mac OS X, +8f0e0000000000000300000000000000,Piranha xtreme,platform:Mac OS X,x:b3,a:b2,b:b1,y:b0,back:b8,start:b9,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,dpup:h0.1,leftshoulder:b6,lefttrigger:b4,rightshoulder:b7,righttrigger:b5,leftstick:b10,rightstick:b11,leftx:a0,lefty:a1,rightx:a3,righty:a2, +0d0f0000000000004d00000000000000,HORI Gem Pad 3,platform:Mac OS X,a:b1,b:b2,y:b3,x:b0,start:b9,guide:b12,back:b8,leftstick:b10,rightstick:b11,leftshoulder:b4,rightshoulder:b5,dpup:h0.1,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,leftx:a0,lefty:a1,rightx:a2,righty:a3,lefttrigger:b6,righttrigger:b7, + +# Linux +0500000047532047616d657061640000,GameStop Gamepad,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b2,y:b3,platform:Linux, +03000000ba2200002010000001010000,Jess Technology USB Game Controller,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:,leftshoulder:b4,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:b7,rightx:a3,righty:a2,start:b9,x:b3,y:b0,platform:Linux, +030000006d04000019c2000010010000,Logitech Cordless RumblePad 2,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Linux, +030000006d0400001dc2000014400000,Logitech F310 Gamepad (XInput),a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux, +030000006d0400001ec2000020200000,Logitech F510 Gamepad (XInput),a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux, +030000006d04000019c2000011010000,Logitech F710 Gamepad (DInput),a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Linux, +030000006d0400001fc2000005030000,Logitech F710 Gamepad (XInput),a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux, +030000004c0500006802000011010000,PS3 Controller,a:b14,b:b13,back:b0,dpdown:b6,dpleft:b7,dpright:b5,dpup:b4,guide:b16,leftshoulder:b10,leftstick:b1,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b11,rightstick:b2,righttrigger:b9,rightx:a2,righty:a3,start:b3,x:b15,y:b12,platform:Linux, +030000004c050000c405000011010000,Sony DualShock 4,a:b1,b:b2,y:b3,x:b0,start:b9,guide:b12,back:b8,leftstick:b10,rightstick:b11,leftshoulder:b4,rightshoulder:b5,dpup:h0.1,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,leftx:a0,lefty:a1,rightx:a2,righty:a5,lefttrigger:b6,righttrigger:b7,platform:Linux, +03000000de280000ff11000001000000,Valve Streaming Gamepad,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux, +030000005e0400008e02000014010000,X360 Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux, +030000005e0400008e02000010010000,X360 Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux, +030000005e0400001907000000010000,X360 Wireless Controller,a:b0,b:b1,back:b6,dpdown:b14,dpleft:b11,dpright:b12,dpup:b13,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux, +03000000100800000100000010010000,Twin USB PS2 Adapter,a:b2,b:b1,y:b0,x:b3,start:b9,guide:,back:b8,leftstick:b10,rightstick:b11,leftshoulder:b6,rightshoulder:b7,dpup:h0.1,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,leftx:a0,lefty:a1,rightx:a3,righty:a2,lefttrigger:b4,righttrigger:b5,platform:Linux, +03000000a306000023f6000011010000,Saitek Cyborg V.1 Game Pad,a:b1,b:b2,y:b3,x:b0,start:b9,guide:b12,back:b8,leftstick:b10,rightstick:b11,leftshoulder:b4,rightshoulder:b5,dpup:h0.1,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,leftx:a0,lefty:a1,rightx:a2,righty:a4,lefttrigger:b6,righttrigger:b7,platform:Linux, +030000004f04000020b3000010010000,Thrustmaster 2 in 1 DT,a:b0,b:b2,y:b3,x:b1,start:b9,guide:,back:b8,leftstick:b10,rightstick:b11,leftshoulder:b4,rightshoulder:b6,dpup:h0.1,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,leftx:a0,lefty:a1,rightx:a2,righty:a3,lefttrigger:b5,righttrigger:b7,platform:Linux, +030000004f04000023b3000000010000,Thrustmaster Dual Trigger 3-in-1,platform:Linux,x:b0,a:b1,b:b2,y:b3,back:b8,start:b9,dpleft:h0.8,dpdown:h0.0,dpdown:h0.4,dpright:h0.0,dpright:h0.2,dpup:h0.0,dpup:h0.1,leftshoulder:h0.0,leftshoulder:b4,lefttrigger:b6,rightshoulder:b5,righttrigger:b7,leftstick:b10,rightstick:b11,leftx:a0,lefty:a1,rightx:a2,righty:a5, +030000008f0e00000300000010010000,GreenAsia Inc. USB Joystick ,platform:Linux,x:b3,a:b2,b:b1,y:b0,back:b8,start:b9,dpleft:h0.8,dpdown:h0.0,dpdown:h0.4,dpright:h0.0,dpright:h0.2,dpup:h0.0,dpup:h0.1,leftshoulder:h0.0,leftshoulder:b6,lefttrigger:b4,rightshoulder:b7,righttrigger:b5,leftstick:b10,rightstick:b11,leftx:a0,lefty:a1,rightx:a3,righty:a2, +030000008f0e00001200000010010000,GreenAsia Inc. USB Joystick ,platform:Linux,x:b2,a:b0,b:b1,y:b3,back:b8,start:b9,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,dpup:h0.1,leftshoulder:b4,lefttrigger:b5,rightshoulder:b6,righttrigger:b7,leftstick:b10,rightstick:b11,leftx:a0,lefty:a1,rightx:a3,righty:a2, +030000005e0400009102000007010000,X360 Wireless Controller,a:b0,b:b1,y:b3,x:b2,start:b7,guide:b8,back:b6,leftstick:b9,rightstick:b10,leftshoulder:b4,rightshoulder:b5,dpup:b13,dpleft:b11,dpdown:b14,dpright:b12,leftx:a0,lefty:a1,rightx:a3,righty:a4,lefttrigger:a2,righttrigger:a5,platform:Linux, +030000006d04000016c2000010010000,Logitech Logitech Dual Action,platform:Linux,x:b0,a:b1,b:b2,y:b3,back:b8,start:b9,dpleft:h0.8,dpdown:h0.0,dpdown:h0.4,dpright:h0.0,dpright:h0.2,dpup:h0.0,dpup:h0.1,leftshoulder:h0.0,dpup:h0.1,leftshoulder:h0.0,leftshoulder:b4,lefttrigger:b6,rightshoulder:b5,righttrigger:b7,leftstick:b10,rightstick:b11,leftx:a0,lefty:a1,rightx:a2,righty:a3, +03000000260900008888000000010000,GameCube {WiseGroup USB box},a:b0,b:b2,y:b3,x:b1,start:b7,leftshoulder:,rightshoulder:b6,dpup:h0.1,dpleft:h0.8,rightstick:,dpdown:h0.4,dpright:h0.2,leftx:a0,lefty:a1,rightx:a2,righty:a3,lefttrigger:a4,righttrigger:a5,platform:Linux, +030000006d04000011c2000010010000,Logitech WingMan Cordless RumblePad,a:b0,b:b1,y:b4,x:b3,start:b8,guide:b5,back:b2,leftshoulder:b6,rightshoulder:b7,dpup:h0.1,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,leftx:a0,lefty:a1,rightx:a3,righty:a4,lefttrigger:b9,righttrigger:b10,platform:Linux, +030000006d04000018c2000010010000,Logitech Logitech RumblePad 2 USB,platform:Linux,x:b0,a:b1,b:b2,y:b3,back:b8,start:b9,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,dpup:h0.1,leftshoulder:b4,lefttrigger:b6,rightshoulder:b5,righttrigger:b7,leftstick:b10,rightstick:b11,leftx:a0,lefty:a1,rightx:a2,righty:a3, +05000000d6200000ad0d000001000000,Moga Pro,platform:Linux,a:b0,b:b1,y:b3,x:b2,start:b6,leftstick:b7,rightstick:b8,leftshoulder:b4,rightshoulder:b5,dpup:h0.1,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,leftx:a0,lefty:a1,rightx:a2,righty:a3,lefttrigger:a5,righttrigger:a4, +030000004f04000009d0000000010000,Thrustmaster Run N Drive Wireless PS3,platform:Linux,a:b1,b:b2,x:b0,y:b3,start:b9,guide:b12,back:b8,leftstick:b10,rightstick:b11,leftshoulder:b4,rightshoulder:b5,dpup:h0.1,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,leftx:a0,lefty:a1,rightx:a2,righty:a3,lefttrigger:b6,righttrigger:b7, +030000004f04000008d0000000010000,Thrustmaster Run N Drive Wireless,platform:Linux,a:b1,b:b2,x:b0,y:b3,start:b9,back:b8,leftstick:b10,rightstick:b11,leftshoulder:b4,rightshoulder:b5,dpup:h0.1,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,leftx:a0,lefty:a1,rightx:a2,righty:a5,lefttrigger:b6,righttrigger:b7, +0300000000f000000300000000010000,RetroUSB.com RetroPad,a:b1,b:b5,x:b0,y:b4,back:b2,start:b3,leftshoulder:b6,rightshoulder:b7,leftx:a0,lefty:a1,platform:Linux, +0300000000f00000f100000000010000,RetroUSB.com Super RetroPort,a:b1,b:b5,x:b0,y:b4,back:b2,start:b3,leftshoulder:b6,rightshoulder:b7,leftx:a0,lefty:a1,platform:Linux, +030000006f0e00001f01000000010000,Generic X-Box pad,platform:Linux,x:b2,a:b0,b:b1,y:b3,back:b6,guide:b8,start:b7,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,dpup:h0.1,leftshoulder:b4,lefttrigger:a2,rightshoulder:b5,righttrigger:a5,leftstick:b9,rightstick:b10,leftx:a0,lefty:a1,rightx:a3,righty:a4, +03000000280400000140000000010000,Gravis GamePad Pro USB ,platform:Linux,x:b0,a:b1,b:b2,y:b3,back:b8,start:b9,leftshoulder:b4,lefttrigger:b6,rightshoulder:b5,righttrigger:b7,leftx:a0,lefty:a1, +030000005e0400008902000021010000,Microsoft X-Box pad v2 (US),platform:Linux,x:b3,a:b0,b:b1,y:b4,back:b6,start:b7,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,dpup:h0.1,leftshoulder:b5,lefttrigger:a2,rightshoulder:b2,righttrigger:a5,leftstick:b8,rightstick:b9,leftx:a0,lefty:a1,rightx:a3,righty:a4, +030000006f0e00001e01000011010000,Rock Candy Gamepad for PS3,platform:Linux,a:b1,b:b2,x:b0,y:b3,back:b8,start:b9,guide:b12,leftshoulder:b4,rightshoulder:b5,leftstick:b10,rightstick:b11,leftx:a0,lefty:a1,rightx:a2,righty:a3,lefttrigger:b6,righttrigger:b7,dpup:h0.1,dpleft:h0.8,dpdown:h0.4,dpright:h0.2, +03000000250900000500000000010000,Sony PS2 pad with SmartJoy adapter,platform:Linux,a:b2,b:b1,y:b0,x:b3,start:b8,back:b9,leftstick:b10,rightstick:b11,leftshoulder:b6,rightshoulder:b7,dpup:h0.1,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,leftx:a0,lefty:a1,rightx:a2,righty:a3,lefttrigger:b4,righttrigger:b5, +030000008916000000fd000024010000,Razer Onza Tournament,a:b0,b:b1,y:b3,x:b2,start:b7,guide:b8,back:b6,leftstick:b9,rightstick:b10,leftshoulder:b4,rightshoulder:b5,dpup:b13,dpleft:b11,dpdown:b14,dpright:b12,leftx:a0,lefty:a1,rightx:a3,righty:a4,lefttrigger:a2,righttrigger:a5,platform:Linux, +030000004f04000000b3000010010000,Thrustmaster Firestorm Dual Power,a:b0,b:b2,y:b3,x:b1,start:b10,guide:b8,back:b9,leftstick:b11,rightstick:b12,leftshoulder:b4,rightshoulder:b6,dpup:h0.1,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,leftx:a0,lefty:a1,rightx:a2,righty:a3,lefttrigger:b5,righttrigger:b7,platform:Linux, +03000000ad1b000001f5000033050000,Hori Pad EX Turbo 2,a:b0,b:b1,y:b3,x:b2,start:b7,guide:b8,back:b6,leftstick:b9,rightstick:b10,leftshoulder:b4,rightshoulder:b5,dpup:h0.1,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,leftx:a0,lefty:a1,rightx:a3,righty:a4,lefttrigger:a2,righttrigger:a5,platform:Linux, +050000004c050000c405000000010000,PS4 Controller (Bluetooth),a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Linux, +060000004c0500006802000000010000,PS3 Controller (Bluetooth),a:b14,b:b13,y:b12,x:b15,start:b3,guide:b16,back:b0,leftstick:b1,rightstick:b2,leftshoulder:b10,rightshoulder:b11,dpup:b4,dpleft:b7,dpdown:b6,dpright:b5,leftx:a0,lefty:a1,rightx:a2,righty:a3,lefttrigger:b8,righttrigger:b9,platform:Linux, +03000000790000000600000010010000,DragonRise Inc. Generic USB Joystick ,platform:Linux,x:b3,a:b2,b:b1,y:b0,back:b8,start:b9,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,dpup:h0.1,leftshoulder:b4,lefttrigger:b6,rightshoulder:b5,righttrigger:b7,leftstick:b10,rightstick:b11,leftx:a0,lefty:a1,rightx:a3,righty:a4, +03000000666600000488000000010000,Super Joy Box 5 Pro,platform:Linux,a:b2,b:b1,x:b3,y:b0,back:b9,start:b8,leftshoulder:b6,rightshoulder:b7,leftstick:b10,rightstick:b11,leftx:a0,lefty:a1,rightx:a2,righty:a3,lefttrigger:b4,righttrigger:b5,dpup:b12,dpleft:b15,dpdown:b14,dpright:b13, +05000000362800000100000002010000,OUYA Game Controller,a:b0,b:b3,dpdown:b9,dpleft:b10,dpright:b11,dpup:b8,guide:b14,leftshoulder:b4,leftstick:b6,lefttrigger:a2,leftx:a0,lefty:a1,platform:Linux,rightshoulder:b5,rightstick:b7,righttrigger:a5,rightx:a3,righty:a4,x:b1,y:b2, +05000000362800000100000003010000,OUYA Game Controller,a:b0,b:b3,dpdown:b9,dpleft:b10,dpright:b11,dpup:b8,guide:b14,leftshoulder:b4,leftstick:b6,lefttrigger:a2,leftx:a0,lefty:a1,platform:Linux,rightshoulder:b5,rightstick:b7,righttrigger:a5,rightx:a3,righty:a4,x:b1,y:b2, +030000008916000001fd000024010000,Razer Onza Classic Edition,platform:Linux,x:b2,a:b0,b:b1,y:b3,back:b6,guide:b8tart:b7,dpleft:b11,dpdown:b14,dpright:b12,dpup:b13,leftshoulder:b4,lefttrigger:a2,rightshoulder:b5,righttrigger:a5,leftstick:b9,rightstick:b10,leftx:a0,lefty:a1,rightx:a3,righty:a4, diff --git a/files/materials/atmosphere.shader b/files/materials/atmosphere.shader index 5040052fc..3eaa73b1c 100644 --- a/files/materials/atmosphere.shader +++ b/files/materials/atmosphere.shader @@ -11,7 +11,7 @@ SH_START_PROGRAM { float4x4 viewFixed = view; -#if !SH_GLSL +#if !SH_GLSL && !SH_GLSLES viewFixed[0][3] = 0.0; viewFixed[1][3] = 0.0; viewFixed[2][3] = 0.0; diff --git a/files/materials/clouds.shader b/files/materials/clouds.shader index 93d0780e0..5902d2fdc 100644 --- a/files/materials/clouds.shader +++ b/files/materials/clouds.shader @@ -13,7 +13,7 @@ { float4x4 worldviewFixed = worldview; -#if !SH_GLSL +#if !SH_GLSL && !SH_GLSLES worldviewFixed[0][3] = 0.0; worldviewFixed[1][3] = 0.0; worldviewFixed[2][3] = 0.0; diff --git a/files/materials/moon.shader b/files/materials/moon.shader index 0e1a4ffc8..151b94180 100644 --- a/files/materials/moon.shader +++ b/files/materials/moon.shader @@ -12,7 +12,7 @@ shUniform(float4x4, projection) @shAutoConstant(projection, projection_matrix) SH_START_PROGRAM { float4x4 viewFixed = view; -#if !SH_GLSL +#if !SH_GLSL && !SH_GLSLES viewFixed[0][3] = 0.0; viewFixed[1][3] = 0.0; viewFixed[2][3] = 0.0; diff --git a/files/materials/objects.shader b/files/materials/objects.shader index 2368d9961..5c74b1139 100644 --- a/files/materials/objects.shader +++ b/files/materials/objects.shader @@ -166,7 +166,7 @@ #if VIEWPROJ_FIX float4x4 vpFixed = vpMatrix; -#if !SH_GLSL +#if !SH_GLSL && !SH_GLSLES vpFixed[2] = vpRow2Fix; #else vpFixed[0][2] = vpRow2Fix.x; @@ -243,7 +243,9 @@ } #else - +#if NORMAL_MAP && SH_GLSLES + mat3 transpose( mat3 m); +#endif // ----------------------------------- FRAGMENT ------------------------------------------ #if UNDERWATER @@ -376,13 +378,13 @@ float3 binormal = cross(tangentPassthrough.xyz, normal.xyz); float3x3 tbn = float3x3(tangentPassthrough.xyz, binormal, normal.xyz); - #if SH_GLSL + #if SH_GLSL || SH_GLSLES tbn = transpose(tbn); #endif float4 normalTex = shSample(normalMap, UV.xy); - normal = normalize (shMatrixMult( transpose(tbn), normalTex.xyz * 2 - 1 )); + normal = normalize (shMatrixMult( transpose(tbn), normalTex.xyz * 2.0 - 1.0 )); #endif #if ENV_MAP || SPECULAR || PARALLAX @@ -576,5 +578,14 @@ // prevent negative colour output (for example with negative lights) shOutputColour(0).xyz = max(shOutputColour(0).xyz, float3(0.0,0.0,0.0)); } +#if NORMAL_MAP && SH_GLSLES + mat3 transpose(mat3 m){ + return mat3( + m[0][0],m[1][0],m[2][0], + m[0][1],m[1][1],m[2][1], + m[0][2],m[1][2],m[2][2] + ); + } +#endif #endif diff --git a/files/materials/ripples.particle b/files/materials/ripples.particle index e8402b691..58045f6d7 100644 --- a/files/materials/ripples.particle +++ b/files/materials/ripples.particle @@ -1,8 +1,8 @@ particle_system openmw/Ripples { material openmw/Ripple - particle_width 50 - particle_height 50 + particle_width 30 + particle_height 30 // To make the particles move with the scene node when the waterlevel changes local_space true quota 300 @@ -17,7 +17,7 @@ particle_system openmw/Ripples affector Scaler { - rate 100 + rate 120 } affector Rotator diff --git a/files/materials/stars.shader b/files/materials/stars.shader index f2eb616a2..830be862a 100644 --- a/files/materials/stars.shader +++ b/files/materials/stars.shader @@ -13,7 +13,7 @@ SH_START_PROGRAM { float4x4 worldviewFixed = worldview; -#if !SH_GLSL +#if !SH_GLSL && !SH_GLSLES worldviewFixed[0][3] = 0.0; worldviewFixed[1][3] = 0.0; worldviewFixed[2][3] = 0.0; diff --git a/files/materials/sun.shader b/files/materials/sun.shader index fc747b522..72e49d1a7 100644 --- a/files/materials/sun.shader +++ b/files/materials/sun.shader @@ -12,7 +12,7 @@ shUniform(float4x4, projection) @shAutoConstant(projection, projection_matrix) SH_START_PROGRAM { float4x4 viewFixed = view; -#if !SH_GLSL +#if !SH_GLSL && !SH_GLSLES viewFixed[0][3] = 0.0; viewFixed[1][3] = 0.0; viewFixed[2][3] = 0.0; diff --git a/files/materials/terrain.shader b/files/materials/terrain.shader index a4ca10fcc..f20fce506 100644 --- a/files/materials/terrain.shader +++ b/files/materials/terrain.shader @@ -136,7 +136,7 @@ #if NEED_DEPTH #if VIEWPROJ_FIX float4x4 vpFixed = viewProjMatrix; -#if !SH_GLSL +#if !SH_GLSL && !SH_GLSLES vpFixed[2] = vpRow2Fix; #else vpFixed[0][2] = vpRow2Fix.x; @@ -221,6 +221,9 @@ #if UNDERWATER #include "underwater.h" #endif +#if NORMAL_MAP && SH_GLSLES + mat3 transpose(mat3 m); +#endif SH_BEGIN_PROGRAM @@ -319,7 +322,7 @@ shUniform(float4, cameraPos) @shAutoConstant(cameraPos, camera_position) // derive final matrix float3x3 tbn = float3x3(tangent, binormal, normal); - #if SH_GLSL + #if SH_GLSL || SH_GLSLES tbn = transpose(tbn); #endif #endif @@ -492,5 +495,13 @@ albedo = shLerp(albedo, diffuseTex, blendValues@shPropertyString(blendmap_compon shOutputColour(0).a = 1.0-previousAlpha; #endif } - +#if NORMAL_MAP && SH_GLSLES + mat3 transpose(mat3 m){ + return mat3( + m[0][0],m[1][0],m[2][0], + m[0][1],m[1][1],m[2][1], + m[0][2],m[1][2],m[2][2] + ); + } +#endif #endif diff --git a/files/materials/underwater.h b/files/materials/underwater.h index 332a0fd7d..2f38f6546 100644 --- a/files/materials/underwater.h +++ b/files/materials/underwater.h @@ -93,7 +93,7 @@ float3 getCaustics (shTexture2D causticMap, float3 worldPos, float3 waterEyePos, // NOTE: the original shader calculated a tangent space basis here, // but using only the world normal is cheaper and i couldn't see a visual difference // also, if this effect gets moved to screen-space some day, it's unlikely to have tangent information - float3 causticNorm = worldNormal.xyz * perturb(causticMap, causticPos.xy, causticdepth, windDir_windSpeed.xy, windDir_windSpeed.z, waterTimer).xyz * 2 - 1; + float3 causticNorm = worldNormal.xyz * perturb(causticMap, causticPos.xy, causticdepth, windDir_windSpeed.xy, windDir_windSpeed.z, waterTimer).xyz * 2.0 - 1.0; causticNorm = float3(causticNorm.x, causticNorm.y, -causticNorm.z); //float fresnel = pow(clamp(dot(LV,causticnorm),0.0,1.0),2.0); @@ -111,7 +111,7 @@ float3 getCaustics (shTexture2D causticMap, float3 worldPos, float3 waterEyePos, //caustics = shSaturate(pow(float3(causticR,causticG,causticB)*5.5,float3(5.5*causticdepth)))*NdotL*sunFade*causticdepth; caustics = shSaturate(pow(float3(causticR,causticG,causticB)*5.5,float3(5.5*causticdepth,5.5*causticdepth,5.5*causticdepth)))*NdotL*causticdepth; - caustics *= 3; + caustics *= 3.0; // shore transition caustics = shLerp (float3(1,1,1), caustics, waterDepth); diff --git a/files/materials/water.shader b/files/materials/water.shader index 10d63cdf4..eff245b5e 100644 --- a/files/materials/water.shader +++ b/files/materials/water.shader @@ -97,7 +97,7 @@ shOutputPosition = shMatrixMult(wvp, shInputPosition); - #if !SH_GLSL + #if !SH_GLSL && !SH_GLSLES float4x4 scalemat = float4x4( 0.5, 0.0, 0.0, 0.5, 0.0, -0.5, 0.0, 0.5, 0.0, 0.0, 0.5, 0.5, diff --git a/files/mygui/openmw_hud.layout b/files/mygui/openmw_hud.layout index 84fd9d247..0cbe0dd97 100644 --- a/files/mygui/openmw_hud.layout +++ b/files/mygui/openmw_hud.layout @@ -112,7 +112,8 @@ - + + @@ -126,35 +127,35 @@ - + - + - + - + - - + + - - + + - + diff --git a/files/mygui/openmw_journal.skin.xml b/files/mygui/openmw_journal.skin.xml index 942c9a4d4..42be2bb62 100644 --- a/files/mygui/openmw_journal.skin.xml +++ b/files/mygui/openmw_journal.skin.xml @@ -28,9 +28,9 @@ - - - + + + diff --git a/files/mygui/openmw_loading_screen.layout b/files/mygui/openmw_loading_screen.layout index 8a1514f84..92bc5aa4c 100644 --- a/files/mygui/openmw_loading_screen.layout +++ b/files/mygui/openmw_loading_screen.layout @@ -10,7 +10,7 @@ - + diff --git a/files/mygui/openmw_settings_window.layout b/files/mygui/openmw_settings_window.layout index 4a993e140..2efd5841e 100644 --- a/files/mygui/openmw_settings_window.layout +++ b/files/mygui/openmw_settings_window.layout @@ -4,7 +4,7 @@ - + @@ -172,15 +172,21 @@ - + + + + + + + - + - + @@ -190,10 +196,10 @@ - + - + @@ -203,11 +209,11 @@ - + - + diff --git a/files/mygui/openmw_stats_window.layout b/files/mygui/openmw_stats_window.layout index 11119c404..1d9b75b9b 100644 --- a/files/mygui/openmw_stats_window.layout +++ b/files/mygui/openmw_stats_window.layout @@ -235,7 +235,9 @@ - + + + diff --git a/files/mygui/openmw_text.skin.xml b/files/mygui/openmw_text.skin.xml index fe01d3417..e459f22fa 100644 --- a/files/mygui/openmw_text.skin.xml +++ b/files/mygui/openmw_text.skin.xml @@ -19,9 +19,11 @@ color_misc=0,205,205 # ???? - + + + diff --git a/files/settings-default.cfg b/files/settings-default.cfg index 19b570e2a..de22e1b56 100644 --- a/files/settings-default.cfg +++ b/files/settings-default.cfg @@ -194,6 +194,8 @@ always run = false allow third person zoom = false +toggle sneak = false + [Game] # Always use the most powerful attack when striking with a weapon (chop, slash or thrust) best attack = false diff --git a/files/ui/settingspage.ui b/files/ui/settingspage.ui index 6c873ea92..7f5e4a7de 100644 --- a/files/ui/settingspage.ui +++ b/files/ui/settingspage.ui @@ -131,6 +131,13 @@ + + + + 4 + + + diff --git a/libs/openengine/CMakeLists.txt b/libs/openengine/CMakeLists.txt new file mode 100644 index 000000000..3542becf6 --- /dev/null +++ b/libs/openengine/CMakeLists.txt @@ -0,0 +1,38 @@ +set(OENGINE_OGRE + ogre/renderer.cpp + ogre/lights.cpp + ogre/selectionbuffer.cpp +) + +set(OENGINE_GUI + gui/loglistener.cpp + gui/manager.cpp + gui/layout.cpp +) + +set(OENGINE_BULLET + bullet/BtOgre.cpp + bullet/BtOgreExtras.h + bullet/BtOgreGP.h + bullet/BtOgrePG.h + bullet/physic.cpp + bullet/physic.hpp + bullet/BulletShapeLoader.cpp + bullet/BulletShapeLoader.h + bullet/trace.cpp + bullet/trace.h +) + +set(OENGINE_MISC + misc/rng.cpp + misc/rng.hpp +) + +set(OENGINE_ALL ${OENGINE_OGRE} ${OENGINE_GUI} ${OENGINE_BULLET} ${OENGINE_MISC}) + +set(OENGINE_LIBRARY "oengine") +set(OENGINE_LIBRARY ${OENGINE_LIBRARY} PARENT_SCOPE) + +source_group(oengine FILES ${OENGINE_ALL}) + +add_library(${OENGINE_LIBRARY} STATIC ${OENGINE_ALL}) diff --git a/libs/openengine/bullet/BtOgre.cpp b/libs/openengine/bullet/BtOgre.cpp index de9ea6f57..0af173adc 100644 --- a/libs/openengine/bullet/BtOgre.cpp +++ b/libs/openengine/bullet/BtOgre.cpp @@ -150,7 +150,7 @@ namespace BtOgre { if (i == mBoneIndex->end()) { l = new Vector3Array; - mBoneIndex->insert(BoneKeyIndex(currBone, l)); + mBoneIndex->insert(std::make_pair(currBone, l)); } else { @@ -215,7 +215,7 @@ namespace BtOgre { if (mBoundRadius == (-1)) { getSize(); - mBoundRadius = (std::max(mBounds.x,std::max(mBounds.y,mBounds.z)) * 0.5); + mBoundRadius = (std::max(mBounds.x,std::max(mBounds.y,mBounds.z)) * 0.5f); } return mBoundRadius; } @@ -737,7 +737,7 @@ namespace BtOgre { { box_kCenter += vertices[c]; } - const Ogre::Real invVertexCount = 1.0 / vertex_count; + const Ogre::Real invVertexCount = 1.0f / vertex_count; box_kCenter *= invVertexCount; } Quaternion orient = boneOrientation; @@ -782,9 +782,9 @@ namespace BtOgre { box_afExtent.y = ((Real)0.5)*(fY1Max - fY1Min); box_afExtent.z = ((Real)0.5)*(fY2Max - fY2Min); - box_kCenter += (0.5*(fY0Max+fY0Min))*box_akAxis[0] + - (0.5*(fY1Max+fY1Min))*box_akAxis[1] + - (0.5*(fY2Max+fY2Min))*box_akAxis[2]; + box_kCenter += (0.5f*(fY0Max+fY0Min))*box_akAxis[0] + + (0.5f*(fY1Max+fY1Min))*box_akAxis[1] + + (0.5f*(fY2Max+fY2Min))*box_akAxis[2]; box_afExtent *= 2.0; diff --git a/libs/openengine/bullet/BtOgreGP.h b/libs/openengine/bullet/BtOgreGP.h index dde606a4f..7e497b535 100644 --- a/libs/openengine/bullet/BtOgreGP.h +++ b/libs/openengine/bullet/BtOgreGP.h @@ -27,7 +27,6 @@ namespace BtOgre { typedef std::map BoneIndex; -typedef std::pair BoneKeyIndex; class VertexIndexToShape { diff --git a/libs/openengine/bullet/BulletShapeLoader.cpp b/libs/openengine/bullet/BulletShapeLoader.cpp index fd9204b44..92d56b42c 100644 --- a/libs/openengine/bullet/BulletShapeLoader.cpp +++ b/libs/openengine/bullet/BulletShapeLoader.cpp @@ -117,6 +117,13 @@ BulletShapePtr BulletShapeManager::create (const Ogre::String& name, const Ogre: return createResource(name,group,isManual,loader,createParams).staticCast(); } +Ogre::ResourcePtr BulletShapeManager::load(const Ogre::String &name, const Ogre::String &group, + bool isManual, Ogre::ManualResourceLoader *loader, const Ogre::NameValuePairList *loadParams, + bool backgroundThread) +{ + return this->load(name, group); +} + BulletShapePtr BulletShapeManager::load(const Ogre::String &name, const Ogre::String &group) { BulletShapePtr textf = getByName(name); diff --git a/libs/openengine/bullet/BulletShapeLoader.h b/libs/openengine/bullet/BulletShapeLoader.h index 31ee3cc7d..907ff8bfe 100644 --- a/libs/openengine/bullet/BulletShapeLoader.h +++ b/libs/openengine/bullet/BulletShapeLoader.h @@ -92,6 +92,11 @@ private: /** \brief Private operator= . This is a forbidden operation. */ BulletShapeManager& operator=(const BulletShapeManager &); + // Not intended to be used, declared here to keep the compiler from complaining + // about hidden virtual methods. + virtual Ogre::ResourcePtr load(const Ogre::String &name, const Ogre::String &group, + bool isManual, Ogre::ManualResourceLoader *loader, const Ogre::NameValuePairList *loadParams, + bool backgroundThread); public: @@ -101,7 +106,8 @@ public: /// Get a resource by name /// @see ResourceManager::getByName - BulletShapePtr getByName(const Ogre::String& name, const Ogre::String& groupName = Ogre::ResourceGroupManager::AUTODETECT_RESOURCE_GROUP_NAME); + BulletShapePtr getByName(const Ogre::String& name, + const Ogre::String& groupName = Ogre::ResourceGroupManager::AUTODETECT_RESOURCE_GROUP_NAME); /// Create a new shape /// @see ResourceManager::createResource diff --git a/libs/openengine/bullet/physic.cpp b/libs/openengine/bullet/physic.cpp index a0259a11f..d5103d32b 100644 --- a/libs/openengine/bullet/physic.cpp +++ b/libs/openengine/bullet/physic.cpp @@ -285,14 +285,14 @@ namespace Physic } } - void PhysicEngine::setDebugRenderingMode(int mode) + void PhysicEngine::setDebugRenderingMode(bool isDebug) { if(!isDebugCreated) { createDebugRendering(); } - mDebugDrawer->setDebugMode(mode); - mDebugActive = mode; + mDebugDrawer->setDebugMode(isDebug); + mDebugActive = isDebug; } bool PhysicEngine::toggleDebugRendering() @@ -387,7 +387,7 @@ namespace Physic } btHeightfieldTerrainShape* hfShape = new btHeightfieldTerrainShape( - sqrtVerts, sqrtVerts, heights, 1, + static_cast(sqrtVerts), static_cast(sqrtVerts), heights, 1, minh, maxh, 2, PHY_FLOAT,true); @@ -398,7 +398,7 @@ namespace Physic btRigidBody::btRigidBodyConstructionInfo CI = btRigidBody::btRigidBodyConstructionInfo(0,0,hfShape); RigidBody* body = new RigidBody(CI,name); - body->getWorldTransform().setOrigin(btVector3( (x+0.5)*triSize*(sqrtVerts-1), (y+0.5)*triSize*(sqrtVerts-1), (maxh+minh)/2.f)); + body->getWorldTransform().setOrigin(btVector3( (x+0.5f)*triSize*(sqrtVerts-1), (y+0.5f)*triSize*(sqrtVerts-1), (maxh+minh)/2.f)); HeightField hf; hf.mBody = body; @@ -416,13 +416,17 @@ namespace Physic + boost::lexical_cast(x) + "_" + boost::lexical_cast(y); - HeightField hf = mHeightFieldMap [name]; + HeightFieldContainer::iterator it = mHeightFieldMap.find(name); + if (it == mHeightFieldMap.end()) + return; + + const HeightField& hf = it->second; mDynamicsWorld->removeRigidBody(hf.mBody); delete hf.mShape; delete hf.mBody; - mHeightFieldMap.erase(name); + mHeightFieldMap.erase(it); } void PhysicEngine::adjustRigidBody(RigidBody* body, const Ogre::Vector3 &position, const Ogre::Quaternion &rotation, @@ -718,7 +722,7 @@ namespace Physic void PhysicEngine::stepSimulation(double deltaT) { // This seems to be needed for character controller objects - mDynamicsWorld->stepSimulation(deltaT,10, 1/60.0); + mDynamicsWorld->stepSimulation(static_cast(deltaT), 10, 1 / 60.0f); if(isDebugCreated) { mDebugDrawer->step(); @@ -826,7 +830,7 @@ namespace Physic if (callback.hasHit()) return std::make_pair(true, callback.m_closestHitFraction); else - return std::make_pair(false, 1); + return std::make_pair(false, 1.0f); } std::vector< std::pair > PhysicEngine::rayTest2(const btVector3& from, const btVector3& to, int filterGroup) diff --git a/libs/openengine/bullet/physic.hpp b/libs/openengine/bullet/physic.hpp index f497150f9..7784e8941 100644 --- a/libs/openengine/bullet/physic.hpp +++ b/libs/openengine/bullet/physic.hpp @@ -258,13 +258,12 @@ namespace Physic const Ogre::Vector3 &position, float scale, const Ogre::Quaternion &rotation); /** - * Remove a character from the scene. TODO:delete it! for now, a small memory leak^^ done? + * Remove a character from the scene. */ void removeCharacter(const std::string &name); /** * Return a pointer to a character - * TODO:check if the actor exist... */ PhysicActor* getCharacter(const std::string &name); @@ -283,7 +282,7 @@ namespace Physic * Set the debug rendering mode. 0 to turn it off. * Important Note: this will crash if the Render is not yet initialise! */ - void setDebugRenderingMode(int mode); + void setDebugRenderingMode(bool isDebug); bool toggleDebugRendering(); diff --git a/libs/openengine/gui/manager.cpp b/libs/openengine/gui/manager.cpp index 512c7f069..349647892 100644 --- a/libs/openengine/gui/manager.cpp +++ b/libs/openengine/gui/manager.cpp @@ -451,7 +451,6 @@ public: mRenderSystem->_setSceneBlending(Ogre::SBF_SOURCE_ALPHA, Ogre::SBF_ONE_MINUS_SOURCE_ALPHA); // always use wireframe - // TODO: add option to enable wireframe mode in platform mRenderSystem->_setPolygonMode(Ogre::PM_SOLID); } diff --git a/libs/openengine/misc/rng.cpp b/libs/openengine/misc/rng.cpp new file mode 100644 index 000000000..140aa337e --- /dev/null +++ b/libs/openengine/misc/rng.cpp @@ -0,0 +1,29 @@ +#include "rng.hpp" +#include +#include + +namespace OEngine { +namespace Misc { + + void Rng::init() + { + std::srand(static_cast(std::time(NULL))); + } + + float Rng::rollProbability() + { + return static_cast(std::rand() / (static_cast(RAND_MAX)+1.0)); + } + + float Rng::rollClosedProbability() + { + return static_cast(std::rand() / static_cast(RAND_MAX)); + } + + int Rng::rollDice(int max) + { + return static_cast((std::rand() / (static_cast(RAND_MAX)+1.0)) * (max)); + } + +} +} \ No newline at end of file diff --git a/libs/openengine/misc/rng.hpp b/libs/openengine/misc/rng.hpp new file mode 100644 index 000000000..4e1da17e1 --- /dev/null +++ b/libs/openengine/misc/rng.hpp @@ -0,0 +1,36 @@ +#ifndef MISC_RNG_H +#define MISC_RNG_H + +#include + +namespace OEngine { +namespace Misc +{ + +/* + Provides central implementation of the RNG logic +*/ +class Rng +{ +public: + + /// seed the RNG + static void init(); + + /// return value in range [0.0f, 1.0f) <- note open upper range. + static float rollProbability(); + + /// return value in range [0.0f, 1.0f] <- note closed upper range. + static float rollClosedProbability(); + + /// return value in range [0, max) <- note open upper range. + static int rollDice(int max); + + /// return value in range [0, 99] + static int roll0to99() { return rollDice(100); } +}; + +} +} + +#endif diff --git a/libs/openengine/ogre/lights.cpp b/libs/openengine/ogre/lights.cpp index 348057b84..97fa938da 100644 --- a/libs/openengine/ogre/lights.cpp +++ b/libs/openengine/ogre/lights.cpp @@ -74,16 +74,16 @@ Ogre::Real LightFunction::calculate(Ogre::Real value) if(mType == LT_Normal) { // Less than 1/255 light modifier for a constant light: - brightness = 1.0 + flickerAmplitude(mDeltaCount*slow)/255.0f; + brightness = 1.0f + flickerAmplitude(mDeltaCount*slow)/255.0f; } else if(mType == LT_Flicker) - brightness = 0.75 + flickerAmplitude(mDeltaCount*fast)*0.25; + brightness = 0.75f + flickerAmplitude(mDeltaCount*fast)*0.25f; else if(mType == LT_FlickerSlow) - brightness = 0.75 + flickerAmplitude(mDeltaCount*slow)*0.25; + brightness = 0.75f + flickerAmplitude(mDeltaCount*slow)*0.25f; else if(mType == LT_Pulse) - brightness = 1.0 + pulseAmplitude(mDeltaCount*fast)*0.25; + brightness = 1.0f + pulseAmplitude(mDeltaCount*fast)*0.25f; else if(mType == LT_PulseSlow) - brightness = 1.0 + pulseAmplitude(mDeltaCount*slow)*0.25; + brightness = 1.0f + pulseAmplitude(mDeltaCount*slow)*0.25f; return brightness; } diff --git a/libs/openengine/ogre/renderer.cpp b/libs/openengine/ogre/renderer.cpp index 0e37d2802..bdeeeb8c4 100644 --- a/libs/openengine/ogre/renderer.cpp +++ b/libs/openengine/ogre/renderer.cpp @@ -184,7 +184,7 @@ void OgreRenderer::setWindowGammaContrast(float gamma, float contrast) if (value > 65535) value = 65535; else if (value < 0) value = 0; - red[i] = green[i] = blue[i] = value; + red[i] = green[i] = blue[i] = static_cast(value); } if (SDL_SetWindowGammaRamp(mSDLWindow, red, green, blue) < 0) std::cout << "Couldn't set gamma: " << SDL_GetError() << std::endl; diff --git a/libs/openengine/ogre/selectionbuffer.cpp b/libs/openengine/ogre/selectionbuffer.cpp index 0ca24676e..741b672ff 100644 --- a/libs/openengine/ogre/selectionbuffer.cpp +++ b/libs/openengine/ogre/selectionbuffer.cpp @@ -10,6 +10,8 @@ #include +#include + #include namespace OEngine @@ -26,7 +28,7 @@ namespace Render setupRenderTarget(); - mCurrentColour = Ogre::ColourValue(0.3, 0.3, 0.3); + mCurrentColour = Ogre::ColourValue(0.3f, 0.3f, 0.3f); } void SelectionBuffer::setupRenderTarget() @@ -145,7 +147,7 @@ namespace Render void SelectionBuffer::getNextColour () { - Ogre::ARGB color = (float(rand()) / float(RAND_MAX)) * std::numeric_limits::max(); + Ogre::ARGB color = static_cast(OEngine::Misc::Rng::rollClosedProbability() * std::numeric_limits::max()); if (mCurrentColour.getAsARGB () == color) { diff --git a/libs/openengine/testall.sh b/libs/openengine/testall.sh deleted file mode 100755 index 097fdabd5..000000000 --- a/libs/openengine/testall.sh +++ /dev/null @@ -1,11 +0,0 @@ -#!/bin/bash - -function run() -{ - echo "TESTING $1" - cd "$1/tests/" - ./test.sh - cd ../../ -} - -run input diff --git a/libs/platform/string.h b/libs/platform/string.h deleted file mode 100644 index 5368d757c..000000000 --- a/libs/platform/string.h +++ /dev/null @@ -1,34 +0,0 @@ -// Wrapper for string.h on Mac and MinGW -#ifndef _STRING_WRAPPER_H -#define _STRING_WRAPPER_H - -#ifdef __APPLE__ -#include -#endif - -#include -#if (defined(__APPLE__) && __MAC_OS_X_VERSION_MIN_REQUIRED < 1070) || defined(__MINGW32__) -// need our own implementation of strnlen -#ifdef __MINGW32__ -static size_t strnlen(const char *s, size_t n) -{ - const char *p = (const char *)memchr(s, 0, n); - return(p ? p-s : n); -} -#elif (defined(__APPLE__) && __MAC_OS_X_VERSION_MIN_REQUIRED < 1070) -static size_t mw_strnlen(const char *s, size_t n) -{ - if (strnlen != NULL) { - return strnlen(s, n); - } - else { - const char *p = (const char *)memchr(s, 0, n); - return(p ? p-s : n); - } -} -#define strnlen mw_strnlen -#endif - -#endif - -#endif