diff --git a/AUTHORS.md b/AUTHORS.md index 155d017f3..9c6a5edbe 100644 --- a/AUTHORS.md +++ b/AUTHORS.md @@ -15,6 +15,7 @@ Programmers Adam Hogan (aurix) Aesylwinn aegis + AHSauge Aleksandar Jovanov Alex Haddad (rainChu) Alex McKibben @@ -41,6 +42,7 @@ Programmers Cory F. Cohen (cfcohen) Cris Mihalache (Mirceam) crussell187 + DanielVukelich darkf devnexen Dieho @@ -155,6 +157,8 @@ Programmers terrorfisch thegriglat Thomas Luppi (Digmaster) + tri4ng1e + unelsson Will Herrmann (Thunderforge) Tom Mason (wheybags) Torben Leif Carrington (TorbenC) @@ -224,7 +228,7 @@ Artwork Necrod - OpenMW Logo Mickey Lyle (raevol) - Wordpress Theme - Tom Koenderink (Okulo), SirHerrbatka, crysthala, Shnatsel - OpenMW Editor Icons + Tom Koenderink (Okulo), SirHerrbatka, crysthala, Shnatsel, Lamoot - OpenMW Editor Icons Inactive Contributors --------------------- diff --git a/CI/before_script.msvc.sh b/CI/before_script.msvc.sh index 522554581..65a6ff0d7 100644 --- a/CI/before_script.msvc.sh +++ b/CI/before_script.msvc.sh @@ -303,25 +303,25 @@ if [ -z $SKIP_DOWNLOAD ]; then # Boost if [ -z $APPVEYOR ]; then download "Boost 1.61.0" \ - "http://sourceforge.net/projects/boost/files/boost-binaries/1.61.0/boost_1_61_0-msvc-${MSVC_VER}.0-${BITS}.exe" \ + "https://sourceforge.net/projects/boost/files/boost-binaries/1.61.0/boost_1_61_0-msvc-${MSVC_VER}.0-${BITS}.exe" \ "boost-1.61.0-msvc${MSVC_YEAR}-win${BITS}.exe" fi # Bullet download "Bullet 2.86" \ - "http://www.lysator.liu.se/~ace/OpenMW/deps/Bullet-2.86-msvc${MSVC_YEAR}-win${BITS}.7z" \ + "https://www.lysator.liu.se/~ace/OpenMW/deps/Bullet-2.86-msvc${MSVC_YEAR}-win${BITS}.7z" \ "Bullet-2.86-msvc${MSVC_YEAR}-win${BITS}.7z" # FFmpeg download "FFmpeg 3.2.4" \ - "http://ffmpeg.zeranoe.com/builds/win${BITS}/shared/ffmpeg-3.2.4-win${BITS}-shared.zip" \ + "https://ffmpeg.zeranoe.com/builds/win${BITS}/shared/ffmpeg-3.2.4-win${BITS}-shared.zip" \ "ffmpeg-3.2.4-win${BITS}.zip" \ - "http://ffmpeg.zeranoe.com/builds/win${BITS}/dev/ffmpeg-3.2.4-win${BITS}-dev.zip" \ + "https://ffmpeg.zeranoe.com/builds/win${BITS}/dev/ffmpeg-3.2.4-win${BITS}-dev.zip" \ "ffmpeg-3.2.4-dev-win${BITS}.zip" # MyGUI download "MyGUI 3.2.2" \ - "http://www.lysator.liu.se/~ace/OpenMW/deps/MyGUI-3.2.2-msvc${MSVC_YEAR}-win${BITS}.7z" \ + "https://www.lysator.liu.se/~ace/OpenMW/deps/MyGUI-3.2.2-msvc${MSVC_YEAR}-win${BITS}.7z" \ "MyGUI-3.2.2-msvc${MSVC_YEAR}-win${BITS}.7z" # OpenAL @@ -331,7 +331,7 @@ if [ -z $SKIP_DOWNLOAD ]; then # OSG download "OpenSceneGraph 3.4.1-scrawl" \ - "http://www.lysator.liu.se/~ace/OpenMW/deps/OSG-3.4.1-scrawl-msvc${MSVC_YEAR}-win${BITS}.7z" \ + "https://www.lysator.liu.se/~ace/OpenMW/deps/OSG-3.4.1-scrawl-msvc${MSVC_YEAR}-win${BITS}.7z" \ "OSG-3.4.1-scrawl-msvc${MSVC_YEAR}-win${BITS}.7z" # Qt @@ -343,9 +343,9 @@ if [ -z $SKIP_DOWNLOAD ]; then fi download "Qt 5.7.2" \ - "http://download.qt.io/official_releases/qt/5.7/5.7.0/qt-opensource-windows-x86-msvc${MSVC_YEAR}${QT_SUFFIX}-5.7.0.exe" \ + "https://download.qt.io/official_releases/qt/5.7/5.7.0/qt-opensource-windows-x86-msvc${MSVC_YEAR}${QT_SUFFIX}-5.7.0.exe" \ "qt-5.7.0-msvc${MSVC_YEAR}-win${BITS}.exe" \ - "http://www.lysator.liu.se/~ace/OpenMW/deps/qt-5-install.qs" \ + "https://www.lysator.liu.se/~ace/OpenMW/deps/qt-5-install.qs" \ "qt-5-install.qs" fi @@ -613,8 +613,7 @@ fi SUFFIX="" fi - add_runtime_dlls "$(pwd)/bin/lib"{EGL,GLESv2}${SUFFIX}.dll \ - "$(pwd)/bin/Qt5"{Core,Gui,Network,OpenGL,Widgets}${SUFFIX}.dll + add_runtime_dlls "$(pwd)/bin/Qt5"{Core,Gui,Network,OpenGL,Widgets}${SUFFIX}.dll add_qt_platform_dlls "$(pwd)/plugins/platforms/qwindows${SUFFIX}.dll" echo Done. diff --git a/CMakeLists.txt b/CMakeLists.txt index c2d4304e4..a9f2d5354 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -135,6 +135,8 @@ if (WIN32) endif() # Dependencies +find_package(OpenGL REQUIRED) + if (USE_QT) message(STATUS "Using Qt${DESIRED_QT_VERSION}") @@ -182,12 +184,6 @@ if (NOT WIN32 AND BUILD_WIZARD) # windows users can just run the morrowind insta set(OPENMW_USE_UNSHIELD TRUE) endif() -option(OPENGL_ES "enable opengl es support" FALSE ) - -if (OPENGL_ES) - add_definitions(-DOPENGL_ES) -endif(OPENGL_ES) - # Fix for not visible pthreads functions for linker with glibc 2.15 if (UNIX AND NOT APPLE) find_package (Threads) @@ -505,8 +501,8 @@ if(WIN32) SET(CPACK_PACKAGE_DESCRIPTION_FILE "${OpenMW_SOURCE_DIR}/README.md") SET(CPACK_NSIS_EXECUTABLES_DIRECTORY ".") SET(CPACK_NSIS_DISPLAY_NAME "OpenMW ${OPENMW_VERSION}") - SET(CPACK_NSIS_HELP_LINK "http:\\\\\\\\www.openmw.org") - SET(CPACK_NSIS_URL_INFO_ABOUT "http:\\\\\\\\www.openmw.org") + SET(CPACK_NSIS_HELP_LINK "https:\\\\\\\\www.openmw.org") + SET(CPACK_NSIS_URL_INFO_ABOUT "https:\\\\\\\\www.openmw.org") SET(CPACK_NSIS_INSTALLED_ICON_NAME "openmw-launcher.exe") SET(CPACK_NSIS_MUI_FINISHPAGE_RUN "openmw-launcher.exe") SET(CPACK_NSIS_MUI_ICON "${OpenMW_SOURCE_DIR}/files/windows/openmw.ico") @@ -549,11 +545,6 @@ endif() # Components add_subdirectory (components) -# Plugins -#if (BUILD_MYGUI_PLUGIN) -# add_subdirectory(plugins/mygui_resource_plugin) -#endif() - # Apps and tools if (BUILD_OPENMW) add_subdirectory( apps/openmw ) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 6c82d1dfd..4805bff3b 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -3,15 +3,14 @@ How to contribute to OpenMW Not sure what to do with all your free time? Pick out a task from here: -http://bugs.openmw.org/ +https://bugs.openmw.org/ Currently, we are focused on completing the MW game experience and general polishing. Features out of this scope may be approved in some cases, but you should probably start a discussion first. Note: -- Tasks set to 'openmw-future' are usually out of the current scope of the project and can't be started yet. -- Bugs that are not 'Confirmed' should be confirmed first. -- Larger Features should have a discussion before you start implementing. -- In many cases, it's best to have a discussion about possible solutions before you jump into coding. +* Tasks set to 'openmw-future' are usually out of the current scope of the project and can't be started yet. +* Bugs that are not 'Confirmed' should be confirmed first. +* Often, it's best to start a discussion about possible solutions before you jump into coding, especially for larger features. Aside from coding, you can also help by triaging the issues list. Check for bugs that are 'Unconfirmed' and try to confirm them on your end, working out any details that may be necessary. Check for bugs that do not conform to [Bug reporting guidelines](https://wiki.openmw.org/index.php?title=Bug_Reporting_Guidelines) and improve them to do so! @@ -20,20 +19,21 @@ There are various [Tools](https://wiki.openmw.org/index.php?title=Tools) to faci Pull Request Guidelines ======================= -Thought of a change? Great! To facilitate the review process, your pull request description should include the following (if applicable): +To facilitate the review process, your pull request description should include the following, if applicable: -* A link back to the bug report or forum discussion that prompted the change +* A link back to the bug report or forum discussion that prompted the change. Note: when linking bugs, use the syntax ```[Bug #xyz](https://bugs.openmw.org/issues/#xyz)``` to create a clickable link. Writing only 'Bug #xyz' will unfortunately create a link to the Github pull request with that number instead. * Summary of the changes made * Reasoning / motivation behind the change * What testing you have carried out to verify the change Furthermore, we advise to: -* Separate your work into multiple pull requests whenever possible. As a rule of thumb, each feature and each bugfix should go into a separate PR, unless they are closely related or dependent upon each other. Small pull requests are easier to review, and are less likely to require further changes before we can merge them. A "mega" pull request with lots of unrelated commits in it is likely to get held up in review for a long time. +* Avoid stuffing unrelated commits into one pull request. As a rule of thumb, each feature and each bugfix should go into a separate PR, unless they are closely related or dependent upon each other. Small pull requests are easier to review, and are less likely to require further changes before we can merge them. A "mega" pull request with lots of unrelated commits in it is likely to get held up in review for a long time. * Feel free to submit incomplete pull requests. Even if the work can not be merged yet, pull requests are a great place to collect early feedback. Just make sure to mark it as *[Incomplete]* or *[Do not merge yet]* in the title. * If you plan on contributing often, please read the [Developer Reference](https://wiki.openmw.org/index.php?title=Developer_Reference) on our wiki, especially the [Policies and Standards](https://wiki.openmw.org/index.php?title=Policies_and_Standards). * Make sure each of your changes has a clear objective. Unnecessary changes may lead to merge conflicts, clutter the commit history and slow down review. Code formatting 'fixes' should be avoided, unless you were already changing that particular line anyway. * Reference the bug / feature ticket(s) in your commit message (e.g. 'Bug #123') to make it easier to keep track of what we changed for what reason. Our bugtracker will show those commits next to the ticket. If your commit message includes 'Fixes #123', that bug/feature will automatically be set to 'Closed' when your commit is merged. +* When pulling changes from master, prefer rebase over merge. Consider using a merge if there are conflicts or for long-running PRs. Guidelines for original engine "fixes" ================================= @@ -47,7 +47,7 @@ Unfortunately, the definition of what is a "bug" is not so clear. Consider that * Many people will actually like these "bugs" because that is what they remember the game for. * Exploits may be part of the fun of an open-world game - they reward knowledge with power. There are too many of them to plug them all, anyway. -OpenMW, in its default configuration, is meant to be a faithful reimplementation of Morrowind, minus things like crash bugs, stability issues and design errors. However, we try to avoid touching anything that affects the core gameplay, the balancing of the game or introduces incompatibilities with existing mod content. +OpenMW, in its default configuration, is meant to be a faithful reimplementation of Morrowind, minus things like crash bugs, stability issues and severe design errors. However, we try to avoid touching anything that affects the core gameplay, the balancing of the game or introduces incompatibilities with existing mod content. That said, we may sometimes evaluate such issues on an individual basis. Common exceptions to the above would be: @@ -62,10 +62,54 @@ We get it, you have waited so long for feature XYZ to be available in Morrowind Unfortunately, since maintaining features comes at a cost and our resources are limited, we have to be a little selective in what features we allow into the main repository. Generally: -- Features should be as generic and non-redundant as possible. -- Any feature that is also possible with modding should be done as a mod instead. -- In the future, OpenMW plans to expand the scope of what is possible with modding, e.g. by moving certain game logic into editable scripts. -- Currently, modders can edit OpenMW's GUI skins and layout XML files, although there are still a few missing hooks (e.g. scripting support) in order to make this into a powerful way of modding. -- If a feature introduces new game UI strings, that reduces its chance of being accepted because we do not currently have any way of localizing these to the user's Morrowind installation language. +* Features should be as generic and non-redundant as possible. +* Any feature that is also possible with modding should be done as a mod instead. +* In the future, OpenMW plans to expand the scope of what is possible with modding, e.g. by moving certain game logic into editable scripts. +* Currently, modders can edit OpenMW's GUI skins and layout XML files, although there are still a few missing hooks (e.g. scripting support) in order to make this into a powerful way of modding. +* If a feature introduces new game UI strings, that reduces its chance of being accepted because we do not currently have any way of localizing these to the user's Morrowind installation language. If you are in doubt of your feature being within our scope, it is probably best to start a forum discussion first. See the [settings documentation](https://openmw.readthedocs.io/en/stable/reference/modding/settings/index.html) and [Features list](https://wiki.openmw.org/index.php?title=Features) for some examples of features that were deemed acceptable. + +Reviewing pull requests +======================= + +We welcome any help in reviewing open PRs. You don't need to be a developer to comment on new features. We also encourage ["junior" developers to review senior's work](https://pagefault.blog/2018/04/08/why-junior-devs-should-review-seniors-commits/). + +This review process is divided into two sections because complaining about code or style issues hardly makes sense until the functionality of the PR is deemed OK. Anyone can help with the Functionality Review while most parts of the Code Review require you to have programming experience. + +In addition to the checklist below, make sure to check that the Pull Request Guidelines (first half of this document) were followed. + +First review +============ + +1. Ask for missing information or clarifications. Compare against the project's design goals and roadmap. +2. Check if the automated tests are passing. If they are not, make the PR author aware of the issue and potentially link to the error line on Travis CI or Appveyor. If the error appears unrelated to the PR and/or the master branch is failing with the same error, our CI has broken and needs to be fixed independently of any open PRs. Raise this issue on the forums, bug tracker or with the relevant maintainer. The PR can be merged in this case as long as you've built it yourself to make sure it does build. +3. Make sure that the new code has been tested thoroughly, either by asking the author or, preferably, testing yourself. In a complex project like OpenMW, it is easy to make mistakes, typos, etc. Therefore, prefer testing all code changes, no matter how trivial they look. When you have tested a PR that no one has tested so far, post a comment letting us know. +4. On long running PRs, request the author to update its description with the current state or a checklist of things left to do. + +Code Review +=========== + +1. Carefully review each line for issues the author may not have thought of, paying special attention to 'special' cases. Often, people build their code with a particular mindset and forget about other configurations or unexpected interactions. +2. If any changes are workarounds for an issue in an upstream library, make sure the issue was reported upstream so we can eventually drop the workaround when the issue is fixed and the new version of that library is a build dependency. +3. Make sure PRs do not turn into arguments about hardly related issues. If the PR author disagrees with an established part of the project (e.g. supported build environments), they should open a forum discussion or bug report and in the meantime adjust the PR to adhere to the established way, rather than leaving the PR hanging on a dispute. +4. Check if the code matches our style guidelines. +5. Check to make sure the commit history is clean. Squashing should be considered if the review process has made the commit history particularly long. Commits that don't build should be avoided because they are a nuisance for ```git bisect```. + +Merging +======= + +To be able to merge PRs, commit priviledges are required. If you do not have the priviledges, just ping someone that does have them with a short comment like "Looks good to me @user". + +The person to merge the PR may either use github's Merge button or if using the command line, use the ```--no-ff``` flag (so a merge commit is created, just like with Github's merge button) and include the pull request number in the commit description. + +Dealing with regressions +======================== + +The master branch should always be in a working state that is not worse than the previous release in any way. If a regression is found, the first and foremost priority should be to get the regression fixed quickly, either by reverting the change that caused it or finding a better solution. Please avoid leaving the project in the 'broken' state for an extensive period of time while proper solutions are found. If the solution takes more than a day or so then it is usually better to revert the offending change first and reapply it later when fixed. + +Other resources +=============== + +[GitHub blog - how to write the perfect pull request](https://blog.github.com/2015-01-21-how-to-write-the-perfect-pull-request/) + diff --git a/LICENSE b/LICENSE index 9cecc1d46..9d742475f 100644 --- a/LICENSE +++ b/LICENSE @@ -1,7 +1,7 @@ GNU GENERAL PUBLIC LICENSE Version 3, 29 June 2007 - Copyright (C) 2007 Free Software Foundation, Inc. + Copyright (C) 2007 Free Software Foundation, Inc. Everyone is permitted to copy and distribute verbatim copies of this license document, but changing it is not allowed. @@ -645,7 +645,7 @@ the "copyright" line and a pointer to where the full notice is found. GNU General Public License for more details. You should have received a copy of the GNU General Public License - along with this program. If not, see . + along with this program. If not, see . Also add information on how to contact you by electronic and paper mail. @@ -664,11 +664,11 @@ might be different; for a GUI interface, you would use an "about box". You should also get your employer (if you work as a programmer) or school, if any, to sign a "copyright disclaimer" for the program, if necessary. For more information on this, and how to apply and follow the GNU GPL, see -. +. The GNU General Public License does not permit incorporating your program into proprietary programs. If your program is a subroutine library, you may consider it more useful to permit linking proprietary applications with the library. If this is what you want to do, use the GNU Lesser General Public License instead of this License. But first, please read -. +. diff --git a/README.md b/README.md index 0b5f63f93..368609332 100644 --- a/README.md +++ b/README.md @@ -9,7 +9,7 @@ OpenMW also comes with OpenMW-CS, a replacement for Morrowind's TES Construction * Version: 0.43.0 * License: GPLv3 (see [LICENSE](https://github.com/OpenMW/openmw/blob/master/LICENSE) for more information) -* Website: http://www.openmw.org +* Website: https://www.openmw.org * IRC: #openmw on irc.freenode.net Font Licenses: @@ -30,8 +30,8 @@ Getting Started * [Build from source](https://wiki.openmw.org/index.php?title=Development_Environment_Setup) * [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) +* [Report a bug](https://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](https://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 ------------- diff --git a/apps/esmtool/record.cpp b/apps/esmtool/record.cpp index 3123308ef..089a25c93 100644 --- a/apps/esmtool/record.cpp +++ b/apps/esmtool/record.cpp @@ -694,7 +694,7 @@ void Record::print() // loads, rather than loading and then dumping. :-( Anyone mind if // I change this? ESM::Dialogue::InfoContainer::iterator iit; - for (iit = mData.mInfo.begin(); iit != mData.mInfo.end(); iit++) + for (iit = mData.mInfo.begin(); iit != mData.mInfo.end(); ++iit) std::cout << "INFO!" << iit->mId << std::endl; } @@ -1040,45 +1040,47 @@ void Record::print() if (mData.mNpdtType == ESM::NPC::NPC_WITH_AUTOCALCULATED_STATS) { - std::cout << " Level: " << mData.mNpdt12.mLevel << std::endl; - std::cout << " Reputation: " << (int)mData.mNpdt12.mReputation << std::endl; - std::cout << " Disposition: " << (int)mData.mNpdt12.mDisposition << std::endl; - std::cout << " Rank: " << (int)mData.mNpdt12.mRank << std::endl; - std::cout << " Unknown1: " - << (unsigned int)((unsigned char)mData.mNpdt12.mUnknown1) << std::endl; - std::cout << " Unknown2: " - << (unsigned int)((unsigned char)mData.mNpdt12.mUnknown2) << std::endl; - std::cout << " Unknown3: " - << (unsigned int)((unsigned char)mData.mNpdt12.mUnknown3) << std::endl; - std::cout << " Gold: " << mData.mNpdt12.mGold << std::endl; + std::cout << " Level: " << mData.mNpdt.mLevel << std::endl; + std::cout << " Reputation: " << (int)mData.mNpdt.mReputation << std::endl; + std::cout << " Disposition: " << (int)mData.mNpdt.mDisposition << std::endl; + std::cout << " Rank: " << (int)mData.mNpdt.mRank << std::endl; + //Why do we want to print these fields? They are padding in the struct and contain + // nothing of real value. Now we don't deal with NPDTstruct12 in runtime either... + //std::cout << " Unknown1: " + // << (unsigned int)((unsigned char)mData.mNpdt12.mUnknown1) << std::endl; + //std::cout << " Unknown2: " + // << (unsigned int)((unsigned char)mData.mNpdt12.mUnknown2) << std::endl; + //std::cout << " Unknown3: " + // << (unsigned int)((unsigned char)mData.mNpdt12.mUnknown3) << std::endl; + std::cout << " Gold: " << mData.mNpdt.mGold << std::endl; } else { - std::cout << " Level: " << mData.mNpdt52.mLevel << std::endl; - std::cout << " Reputation: " << (int)mData.mNpdt52.mReputation << std::endl; - std::cout << " Disposition: " << (int)mData.mNpdt52.mDisposition << std::endl; - std::cout << " Rank: " << (int)mData.mNpdt52.mRank << std::endl; - std::cout << " FactionID: " << (int)mData.mNpdt52.mFactionID << std::endl; + std::cout << " Level: " << mData.mNpdt.mLevel << std::endl; + std::cout << " Reputation: " << (int)mData.mNpdt.mReputation << std::endl; + std::cout << " Disposition: " << (int)mData.mNpdt.mDisposition << std::endl; + std::cout << " Rank: " << (int)mData.mNpdt.mRank << std::endl; + std::cout << " FactionID: " << (int)mData.mNpdt.mFactionID << std::endl; std::cout << " Attributes:" << std::endl; - std::cout << " Strength: " << (int)mData.mNpdt52.mStrength << std::endl; - std::cout << " Intelligence: " << (int)mData.mNpdt52.mIntelligence << std::endl; - std::cout << " Willpower: " << (int)mData.mNpdt52.mWillpower << std::endl; - std::cout << " Agility: " << (int)mData.mNpdt52.mAgility << std::endl; - std::cout << " Speed: " << (int)mData.mNpdt52.mSpeed << std::endl; - std::cout << " Endurance: " << (int)mData.mNpdt52.mEndurance << std::endl; - std::cout << " Personality: " << (int)mData.mNpdt52.mPersonality << std::endl; - std::cout << " Luck: " << (int)mData.mNpdt52.mLuck << std::endl; + std::cout << " Strength: " << (int)mData.mNpdt.mStrength << std::endl; + std::cout << " Intelligence: " << (int)mData.mNpdt.mIntelligence << std::endl; + std::cout << " Willpower: " << (int)mData.mNpdt.mWillpower << std::endl; + std::cout << " Agility: " << (int)mData.mNpdt.mAgility << std::endl; + std::cout << " Speed: " << (int)mData.mNpdt.mSpeed << std::endl; + std::cout << " Endurance: " << (int)mData.mNpdt.mEndurance << std::endl; + std::cout << " Personality: " << (int)mData.mNpdt.mPersonality << std::endl; + std::cout << " Luck: " << (int)mData.mNpdt.mLuck << std::endl; std::cout << " Skills:" << std::endl; for (int i = 0; i != ESM::Skill::Length; i++) std::cout << " " << skillLabel(i) << ": " - << (int)(mData.mNpdt52.mSkills[i]) << std::endl; + << (int)(mData.mNpdt.mSkills[i]) << std::endl; - std::cout << " Health: " << mData.mNpdt52.mHealth << std::endl; - std::cout << " Magicka: " << mData.mNpdt52.mMana << std::endl; - std::cout << " Fatigue: " << mData.mNpdt52.mFatigue << std::endl; - std::cout << " Unknown: " << (int)mData.mNpdt52.mUnknown << std::endl; - std::cout << " Gold: " << mData.mNpdt52.mGold << std::endl; + std::cout << " Health: " << mData.mNpdt.mHealth << std::endl; + std::cout << " Magicka: " << mData.mNpdt.mMana << std::endl; + std::cout << " Fatigue: " << mData.mNpdt.mFatigue << std::endl; + std::cout << " Unknown: " << (int)mData.mNpdt.mUnknown << std::endl; + std::cout << " Gold: " << mData.mNpdt.mGold << std::endl; } std::vector::iterator cit; @@ -1123,7 +1125,7 @@ void Record::print() int i = 0; ESM::Pathgrid::PointList::iterator pit; - for (pit = mData.mPoints.begin(); pit != mData.mPoints.end(); pit++) + for (pit = mData.mPoints.begin(); pit != mData.mPoints.end(); ++pit) { std::cout << " Point[" << i << "]:" << std::endl; std::cout << " Coordinates: (" << pit->mX << "," @@ -1135,7 +1137,7 @@ void Record::print() } i = 0; ESM::Pathgrid::EdgeList::iterator eit; - for (eit = mData.mEdges.begin(); eit != mData.mEdges.end(); eit++) + for (eit = mData.mEdges.begin(); eit != mData.mEdges.end(); ++eit) { std::cout << " Edge[" << i << "]: " << eit->mV0 << " -> " << eit->mV1 << std::endl; if (eit->mV0 >= mData.mData.mS2 || eit->mV1 >= mData.mData.mS2) diff --git a/apps/essimporter/converter.hpp b/apps/essimporter/converter.hpp index 621b85709..1772e0e2d 100644 --- a/apps/essimporter/converter.hpp +++ b/apps/essimporter/converter.hpp @@ -122,7 +122,7 @@ public: } else { - mContext->mPlayer.mObject.mCreatureStats.mLevel = npc.mNpdt52.mLevel; + mContext->mPlayer.mObject.mCreatureStats.mLevel = npc.mNpdt.mLevel; mContext->mPlayerBase = npc; ESM::SpellState::SpellParams empty; // FIXME: player start spells and birthsign spells aren't listed here, diff --git a/apps/essimporter/importer.cpp b/apps/essimporter/importer.cpp index 73b15baae..4538d4e63 100644 --- a/apps/essimporter/importer.cpp +++ b/apps/essimporter/importer.cpp @@ -377,7 +377,7 @@ namespace ESSImport profile.mPlayerClassName = context.mCustomPlayerClassName; else profile.mPlayerClassId = context.mPlayerBase.mClass; - profile.mPlayerLevel = context.mPlayerBase.mNpdt52.mLevel; + profile.mPlayerLevel = context.mPlayerBase.mNpdt.mLevel; profile.mPlayerName = header.mGameData.mPlayerName.toString(); writeScreenshot(header, profile); diff --git a/apps/launcher/CMakeLists.txt b/apps/launcher/CMakeLists.txt index aec8c2533..99e7b4daa 100644 --- a/apps/launcher/CMakeLists.txt +++ b/apps/launcher/CMakeLists.txt @@ -106,7 +106,7 @@ if (DESIRED_QT_VERSION MATCHES 4) target_link_libraries(openmw-launcher ${QT_QTMAIN_LIBRARY}) endif(WIN32) else() - qt5_use_modules(openmw-launcher Widgets Core) + target_link_libraries(openmw-launcher Qt5::Widgets Qt5::Core) endif() if (BUILD_WITH_CODE_COVERAGE) diff --git a/apps/launcher/advancedpage.cpp b/apps/launcher/advancedpage.cpp index 3ba378599..9b6e5fa8c 100644 --- a/apps/launcher/advancedpage.cpp +++ b/apps/launcher/advancedpage.cpp @@ -35,9 +35,11 @@ bool Launcher::AdvancedPage::loadSettings() loadSettingBool(grabCursorCheckBox, "grab cursor", "Input"); loadSettingBool(toggleSneakCheckBox, "toggle sneak", "Input"); - // Other Settings + // Saves Settings loadSettingBool(timePlayedCheckbox, "timeplayed", "Saves"); + maximumQuicksavesComboBox->setValue(mEngineSettings.getInt("max quicksaves", "Saves")); + // Other Settings QString screenshotFormatString = QString::fromStdString(mEngineSettings.getString("screenshot format", "General")).toUpper(); if (screenshotFormatComboBox->findText(screenshotFormatString) == -1) screenshotFormatComboBox->addItem(screenshotFormatString); @@ -69,9 +71,14 @@ void Launcher::AdvancedPage::saveSettings() saveSettingBool(grabCursorCheckBox, "grab cursor", "Input"); saveSettingBool(toggleSneakCheckBox, "toggle sneak", "Input"); - // Other Settings + // Saves Settings saveSettingBool(timePlayedCheckbox, "timeplayed", "Saves"); + int maximumQuicksaves = maximumQuicksavesComboBox->value(); + if (maximumQuicksaves != mEngineSettings.getInt("max quicksaves", "Saves")) { + mEngineSettings.setInt("max quicksaves", "Saves", maximumQuicksaves); + } + // Other Settings std::string screenshotFormatString = screenshotFormatComboBox->currentText().toLower().toStdString(); if (screenshotFormatString != mEngineSettings.getString("screenshot format", "General")) mEngineSettings.setString("screenshot format", "General", screenshotFormatString); diff --git a/apps/niftest/niftest.cpp b/apps/niftest/niftest.cpp index 72393db40..572a58f26 100644 --- a/apps/niftest/niftest.cpp +++ b/apps/niftest/niftest.cpp @@ -33,12 +33,12 @@ bool hasExtension(std::string filename, std::string extensionToFind) } ///See if the file has the "nif" extension. -bool isNIF(std::string filename) +bool isNIF(const std::string & filename) { return hasExtension(filename,"nif"); } ///See if the file has the "bsa" extension. -bool isBSA(std::string filename) +bool isBSA(const std::string & filename) { return hasExtension(filename,"bsa"); } diff --git a/apps/opencs/CMakeLists.txt b/apps/opencs/CMakeLists.txt index b9279bf91..f07b518a9 100644 --- a/apps/opencs/CMakeLists.txt +++ b/apps/opencs/CMakeLists.txt @@ -246,7 +246,7 @@ if (DESIRED_QT_VERSION MATCHES 4) target_link_libraries(openmw-cs ${QT_QTMAIN_LIBRARY}) endif() else() - qt5_use_modules(openmw-cs Widgets Core Network OpenGL) + target_link_libraries(openmw-cs Qt5::Widgets Qt5::Core Qt5::Network Qt5::OpenGL) endif() if (WIN32) diff --git a/apps/opencs/model/filter/parser.cpp b/apps/opencs/model/filter/parser.cpp index d2bedc666..d2a4f2a35 100644 --- a/apps/opencs/model/filter/parser.cpp +++ b/apps/opencs/model/filter/parser.cpp @@ -579,7 +579,7 @@ bool CSMFilter::Parser::parse (const std::string& filter, bool allowPredefined) } // We do not use isString() here, because there could be a pre-defined filter with an ID that is // equal a filter keyword. - else if (token.mType==Token::Type_String && allowPredefined) + else if (token.mType==Token::Type_String) { if (getNextToken()!=Token (Token::Type_EOS)) { diff --git a/apps/opencs/model/prefs/shortcuteventhandler.cpp b/apps/opencs/model/prefs/shortcuteventhandler.cpp index 93e2d85d3..e42cb5da1 100644 --- a/apps/opencs/model/prefs/shortcuteventhandler.cpp +++ b/apps/opencs/model/prefs/shortcuteventhandler.cpp @@ -49,7 +49,7 @@ namespace CSMPrefs ShortcutMap::iterator shortcutListIt = mWidgetShortcuts.find(widget); if (shortcutListIt != mWidgetShortcuts.end()) { - std::remove(shortcutListIt->second.begin(), shortcutListIt->second.end(), shortcut); + shortcutListIt->second.erase(std::remove(shortcutListIt->second.begin(), shortcutListIt->second.end(), shortcut), shortcutListIt->second.end()); } } diff --git a/apps/opencs/model/tools/classcheck.cpp b/apps/opencs/model/tools/classcheck.cpp index e4964d4e3..316fc0ce5 100644 --- a/apps/opencs/model/tools/classcheck.cpp +++ b/apps/opencs/model/tools/classcheck.cpp @@ -32,9 +32,6 @@ void CSMTools::ClassCheckStage::perform (int stage, CSMDoc::Messages& messages) if (class_.mName.empty()) messages.push_back (std::make_pair (id, class_.mId + " has an empty name")); - if (class_.mDescription.empty()) - messages.push_back (std::make_pair (id, class_.mId + " has an empty description")); - // test for invalid attributes for (int i=0; i<2; ++i) if (class_.mData.mAttribute[i]==-1) diff --git a/apps/opencs/model/tools/pathgridcheck.cpp b/apps/opencs/model/tools/pathgridcheck.cpp index 3cd4a1b09..be4d37792 100644 --- a/apps/opencs/model/tools/pathgridcheck.cpp +++ b/apps/opencs/model/tools/pathgridcheck.cpp @@ -29,7 +29,7 @@ void CSMTools::PathgridCheckStage::perform (int stage, CSMDoc::Messages& message CSMWorld::UniversalId id (CSMWorld::UniversalId::Type_Pathgrid, pathgrid.mId); // check the number of pathgrid points - if (pathgrid.mData.mS2 > static_cast(pathgrid.mPoints.size())) + if (pathgrid.mData.mS2 < static_cast(pathgrid.mPoints.size())) messages.add (id, pathgrid.mId + " has less points than expected", "", CSMDoc::Message::Severity_Error); else if (pathgrid.mData.mS2 > static_cast(pathgrid.mPoints.size())) messages.add (id, pathgrid.mId + " has more points than expected", "", CSMDoc::Message::Severity_Error); diff --git a/apps/opencs/model/tools/referenceablecheck.cpp b/apps/opencs/model/tools/referenceablecheck.cpp index 4dd3e1edf..1e86dfe37 100644 --- a/apps/opencs/model/tools/referenceablecheck.cpp +++ b/apps/opencs/model/tools/referenceablecheck.cpp @@ -239,9 +239,7 @@ void CSMTools::ReferenceableCheckStage::bookCheck( const CSMWorld::RecordBase& baseRecord = records.getRecord(stage); if (baseRecord.isDeleted()) - { return; - } const ESM::Book& book = (dynamic_cast& >(baseRecord)).get(); CSMWorld::UniversalId id(CSMWorld::UniversalId::Type_Book, book.mId); @@ -260,9 +258,7 @@ void CSMTools::ReferenceableCheckStage::activatorCheck( const CSMWorld::RecordBase& baseRecord = records.getRecord(stage); if (baseRecord.isDeleted()) - { return; - } const ESM::Activator& activator = (dynamic_cast& >(baseRecord)).get(); CSMWorld::UniversalId id(CSMWorld::UniversalId::Type_Activator, activator.mId); @@ -283,9 +279,7 @@ void CSMTools::ReferenceableCheckStage::potionCheck( const CSMWorld::RecordBase& baseRecord = records.getRecord(stage); if (baseRecord.isDeleted()) - { return; - } const ESM::Potion& potion = (dynamic_cast& >(baseRecord)).get(); CSMWorld::UniversalId id(CSMWorld::UniversalId::Type_Potion, potion.mId); @@ -306,9 +300,7 @@ void CSMTools::ReferenceableCheckStage::apparatusCheck( const CSMWorld::RecordBase& baseRecord = records.getRecord(stage); if (baseRecord.isDeleted()) - { return; - } const ESM::Apparatus& apparatus = (dynamic_cast& >(baseRecord)).get(); CSMWorld::UniversalId id(CSMWorld::UniversalId::Type_Apparatus, apparatus.mId); @@ -329,9 +321,7 @@ void CSMTools::ReferenceableCheckStage::armorCheck( const CSMWorld::RecordBase& baseRecord = records.getRecord(stage); if (baseRecord.isDeleted()) - { return; - } const ESM::Armor& armor = (dynamic_cast& >(baseRecord)).get(); CSMWorld::UniversalId id(CSMWorld::UniversalId::Type_Armor, armor.mId); @@ -358,9 +348,7 @@ void CSMTools::ReferenceableCheckStage::clothingCheck( const CSMWorld::RecordBase& baseRecord = records.getRecord(stage); if (baseRecord.isDeleted()) - { return; - } const ESM::Clothing& clothing = (dynamic_cast& >(baseRecord)).get(); CSMWorld::UniversalId id(CSMWorld::UniversalId::Type_Clothing, clothing.mId); @@ -378,9 +366,7 @@ void CSMTools::ReferenceableCheckStage::containerCheck( const CSMWorld::RecordBase& baseRecord = records.getRecord(stage); if (baseRecord.isDeleted()) - { return; - } const ESM::Container& container = (dynamic_cast& >(baseRecord)).get(); CSMWorld::UniversalId id(CSMWorld::UniversalId::Type_Container, container.mId); @@ -512,9 +498,7 @@ void CSMTools::ReferenceableCheckStage::ingredientCheck( const CSMWorld::RecordBase& baseRecord = records.getRecord(stage); if (baseRecord.isDeleted()) - { return; - } const ESM::Ingredient& ingredient = (dynamic_cast& >(baseRecord)).get(); CSMWorld::UniversalId id(CSMWorld::UniversalId::Type_Ingredient, ingredient.mId); @@ -577,13 +561,8 @@ void CSMTools::ReferenceableCheckStage::lightCheck( messages.push_back (std::make_pair (id, light.mId + " has negative light radius")); if (light.mData.mFlags & ESM::Light::Carry) - { inventoryItemCheck(light, messages, id.toString()); - if (light.mData.mTime == 0) - messages.push_back (std::make_pair (id, light.mId + " has zero duration")); - } - // Check that mentioned scripts exist scriptCheck(light, messages, id.toString()); } @@ -596,9 +575,7 @@ void CSMTools::ReferenceableCheckStage::lockpickCheck( const CSMWorld::RecordBase& baseRecord = records.getRecord(stage); if (baseRecord.isDeleted()) - { return; - } const ESM::Lockpick& lockpick = (dynamic_cast& >(baseRecord)).get(); CSMWorld::UniversalId id(CSMWorld::UniversalId::Type_Lockpick, lockpick.mId); @@ -619,9 +596,7 @@ void CSMTools::ReferenceableCheckStage::miscCheck( const CSMWorld::RecordBase& baseRecord = records.getRecord(stage); if (baseRecord.isDeleted()) - { return; - } const ESM::Miscellaneous& miscellaneous = (dynamic_cast& >(baseRecord)).get(); CSMWorld::UniversalId id(CSMWorld::UniversalId::Type_Miscellaneous, miscellaneous.mId); @@ -644,12 +619,12 @@ void CSMTools::ReferenceableCheckStage::npcCheck ( const ESM::NPC& npc = (dynamic_cast& >(baseRecord)).get(); CSMWorld::UniversalId id (CSMWorld::UniversalId::Type_Npc, npc.mId); - short level(npc.mNpdt52.mLevel); - char disposition(npc.mNpdt52.mDisposition); - char reputation(npc.mNpdt52.mReputation); - char rank(npc.mNpdt52.mRank); + short level(npc.mNpdt.mLevel); + char disposition(npc.mNpdt.mDisposition); + char reputation(npc.mNpdt.mReputation); + char rank(npc.mNpdt.mRank); //Don't know what unknown is for - int gold(npc.mNpdt52.mGold); + int gold(npc.mNpdt.mGold); //Detect if player is present if (Misc::StringUtils::ciEqual(npc.mId, "player")) //Happy now, scrawl? @@ -663,36 +638,36 @@ void CSMTools::ReferenceableCheckStage::npcCheck ( return; } - level = npc.mNpdt12.mLevel; - disposition = npc.mNpdt12.mDisposition; - reputation = npc.mNpdt12.mReputation; - rank = npc.mNpdt12.mRank; - gold = npc.mNpdt12.mGold; + level = npc.mNpdt.mLevel; + disposition = npc.mNpdt.mDisposition; + reputation = npc.mNpdt.mReputation; + rank = npc.mNpdt.mRank; + gold = npc.mNpdt.mGold; } else { - if (npc.mNpdt52.mAgility == 0) + if (npc.mNpdt.mAgility == 0) messages.push_back (std::make_pair (id, npc.mId + " agility has zero value")); - if (npc.mNpdt52.mEndurance == 0) + if (npc.mNpdt.mEndurance == 0) messages.push_back (std::make_pair (id, npc.mId + " endurance has zero value")); - if (npc.mNpdt52.mIntelligence == 0) + if (npc.mNpdt.mIntelligence == 0) messages.push_back (std::make_pair (id, npc.mId + " intelligence has zero value")); - if (npc.mNpdt52.mLuck == 0) + if (npc.mNpdt.mLuck == 0) messages.push_back (std::make_pair (id, npc.mId + " luck has zero value")); - if (npc.mNpdt52.mPersonality == 0) + if (npc.mNpdt.mPersonality == 0) messages.push_back (std::make_pair (id, npc.mId + " personality has zero value")); - if (npc.mNpdt52.mStrength == 0) + if (npc.mNpdt.mStrength == 0) messages.push_back (std::make_pair (id, npc.mId + " strength has zero value")); - if (npc.mNpdt52.mSpeed == 0) + if (npc.mNpdt.mSpeed == 0) messages.push_back (std::make_pair (id, npc.mId + " speed has zero value")); - if (npc.mNpdt52.mWillpower == 0) + if (npc.mNpdt.mWillpower == 0) messages.push_back (std::make_pair (id, npc.mId + " willpower has zero value")); } @@ -706,22 +681,14 @@ void CSMTools::ReferenceableCheckStage::npcCheck ( messages.push_back (std::make_pair (id, npc.mId + " has any empty name")); if (npc.mClass.empty()) - { - messages.push_back (std::make_pair (id, npc.mId + " has any empty class")); - } + messages.push_back (std::make_pair (id, npc.mId + " has an empty class")); else if (mClasses.searchId (npc.mClass) == -1) - { messages.push_back (std::make_pair (id, npc.mId + " has invalid class")); - } if (npc.mRace.empty()) - { - messages.push_back (std::make_pair (id, npc.mId + " has any empty race")); - } + messages.push_back (std::make_pair (id, npc.mId + " has an empty race")); else if (mRaces.searchId (npc.mRace) == -1) - { messages.push_back (std::make_pair (id, npc.mId + " has invalid race")); - } if (disposition < 0) messages.push_back (std::make_pair (id, npc.mId + " has negative disposition")); @@ -823,7 +790,7 @@ void CSMTools::ReferenceableCheckStage::weaponCheck( { //checking of health if (weapon.mData.mHealth <= 0) - messages.push_back (std::make_pair (id, weapon.mId + " has non-positivie health")); + messages.push_back (std::make_pair (id, weapon.mId + " has non-positive health")); if (weapon.mData.mReach < 0) messages.push_back (std::make_pair (id, weapon.mId + " has negative reach")); @@ -842,9 +809,7 @@ void CSMTools::ReferenceableCheckStage::probeCheck( const CSMWorld::RecordBase& baseRecord = records.getRecord(stage); if (baseRecord.isDeleted()) - { return; - } const ESM::Probe& probe = (dynamic_cast& >(baseRecord)).get(); CSMWorld::UniversalId id(CSMWorld::UniversalId::Type_Probe, probe.mId); diff --git a/apps/opencs/model/tools/soundcheck.cpp b/apps/opencs/model/tools/soundcheck.cpp index 6a059bee2..3dbd3ef11 100644 --- a/apps/opencs/model/tools/soundcheck.cpp +++ b/apps/opencs/model/tools/soundcheck.cpp @@ -27,7 +27,7 @@ void CSMTools::SoundCheckStage::perform (int stage, CSMDoc::Messages& messages) CSMWorld::UniversalId id (CSMWorld::UniversalId::Type_Sound, sound.mId); if (sound.mData.mMinRange>sound.mData.mMaxRange) - messages.push_back (std::make_pair (id, "Maximum range larger than minimum range")); + messages.push_back (std::make_pair (id, "Minimum range larger than maximum range")); /// \todo check, if the sound file exists } diff --git a/apps/opencs/model/tools/tools.cpp b/apps/opencs/model/tools/tools.cpp index 3b2c80263..445db53af 100644 --- a/apps/opencs/model/tools/tools.cpp +++ b/apps/opencs/model/tools/tools.cpp @@ -61,12 +61,7 @@ CSMDoc::OperationHolder *CSMTools::Tools::getVerifier() connect (&mVerifier, SIGNAL (reportMessage (const CSMDoc::Message&, int)), this, SLOT (verifierMessage (const CSMDoc::Message&, int))); - std::vector mandatoryIds; // I want C++11, damn it! - mandatoryIds.push_back ("Day"); - mandatoryIds.push_back ("DaysPassed"); - mandatoryIds.push_back ("GameHour"); - mandatoryIds.push_back ("Month"); - mandatoryIds.push_back ("PCRace"); + std::vector mandatoryIds {"Day", "DaysPassed", "GameHour", "Month", "PCRace"}; mVerifierOperation->appendStage (new MandatoryIdStage (mData.getGlobals(), CSMWorld::UniversalId (CSMWorld::UniversalId::Type_Globals), mandatoryIds)); diff --git a/apps/opencs/model/world/columns.cpp b/apps/opencs/model/world/columns.cpp index ec010ba36..7c0fbff4b 100644 --- a/apps/opencs/model/world/columns.cpp +++ b/apps/opencs/model/world/columns.cpp @@ -66,7 +66,7 @@ namespace CSMWorld { ColumnId_SleepForbidden, "Sleep Forbidden" }, { ColumnId_InteriorWater, "Interior Water" }, { ColumnId_InteriorSky, "Interior Sky" }, - { ColumnId_Model, "Model" }, + { ColumnId_Model, "Model/Animation" }, { ColumnId_Script, "Script" }, { ColumnId_Icon, "Icon" }, { ColumnId_Weight, "Weight" }, diff --git a/apps/opencs/model/world/data.cpp b/apps/opencs/model/world/data.cpp index 2216d5ca6..053754943 100644 --- a/apps/opencs/model/world/data.cpp +++ b/apps/opencs/model/world/data.cpp @@ -962,6 +962,29 @@ int CSMWorld::Data::startLoading (const boost::filesystem::path& path, bool base return mReader->getRecordCount(); } +void CSMWorld::Data::loadFallbackEntries() +{ + // Load default marker definitions, if game files do not have them for some reason + std::pair markers[] = { + std::make_pair("divinemarker", "marker_divine.nif"), + std::make_pair("doormarker", "marker_arrow.nif"), + std::make_pair("northmarker", "marker_north.nif"), + std::make_pair("templemarker", "marker_temple.nif"), + std::make_pair("travelmarker", "marker_travel.nif") + }; + + for (const std::pair marker : markers) + { + if (mReferenceables.searchId (marker.first)==-1) + { + CSMWorld::Record record; + record.mBase = ESM::Static(marker.first, marker.second); + record.mState = CSMWorld::RecordBase::State_BaseOnly; + mReferenceables.appendRecord (record, CSMWorld::UniversalId::Type_Static); + } + } +} + bool CSMWorld::Data::continueLoading (CSMDoc::Messages& messages) { if (!mReader) @@ -983,6 +1006,9 @@ bool CSMWorld::Data::continueLoading (CSMDoc::Messages& messages) mReader = 0; mDialogue = 0; + + loadFallbackEntries(); + return true; } diff --git a/apps/opencs/model/world/data.hpp b/apps/opencs/model/world/data.hpp index 8a3667ea1..1b975f430 100644 --- a/apps/opencs/model/world/data.hpp +++ b/apps/opencs/model/world/data.hpp @@ -144,6 +144,8 @@ namespace CSMWorld static int count (RecordBase::State state, const CollectionBase& collection); + void loadFallbackEntries(); + public: Data (ToUTF8::FromType encoding, bool fsStrict, const Files::PathContainer& dataPaths, diff --git a/apps/opencs/model/world/refidadapterimp.cpp b/apps/opencs/model/world/refidadapterimp.cpp index e8f921580..352384c73 100644 --- a/apps/opencs/model/world/refidadapterimp.cpp +++ b/apps/opencs/model/world/refidadapterimp.cpp @@ -914,7 +914,7 @@ void CSMWorld::NpcAttributesRefIdAdapter::setNestedTable (const RefIdColumn* col ESM::NPC npc = record.get(); // store the whole struct - npc.mNpdt52 = + npc.mNpdt = static_cast > &>(nestedTable).mNestedTable.at(0); record.setModified (npc); @@ -928,7 +928,7 @@ CSMWorld::NestedTableWrapperBase* CSMWorld::NpcAttributesRefIdAdapter::nestedTab // return the whole struct std::vector wrap; - wrap.push_back(record.get().mNpdt52); + wrap.push_back(record.get().mNpdt); // deleted by dtor of NestedTableStoring return new NestedTableWrapper >(wrap); } @@ -939,7 +939,7 @@ QVariant CSMWorld::NpcAttributesRefIdAdapter::getNestedData (const RefIdColumn * const Record& record = static_cast&> (data.getRecord (RefIdData::LocalIndex (index, UniversalId::Type_Npc))); - const ESM::NPC::NPDTstruct52& npcStruct = record.get().mNpdt52; + const ESM::NPC::NPDTstruct52& npcStruct = record.get().mNpdt; if (subColIndex == 0) return subRowIndex; @@ -966,7 +966,7 @@ void CSMWorld::NpcAttributesRefIdAdapter::setNestedData (const RefIdColumn *colu Record& record = static_cast&> (data.getRecord (RefIdData::LocalIndex (row, UniversalId::Type_Npc))); ESM::NPC npc = record.get(); - ESM::NPC::NPDTstruct52& npcStruct = npc.mNpdt52; + ESM::NPC::NPDTstruct52& npcStruct = npc.mNpdt; if (subColIndex == 1) switch(subRowIndex) @@ -1021,7 +1021,7 @@ void CSMWorld::NpcSkillsRefIdAdapter::setNestedTable (const RefIdColumn* column, ESM::NPC npc = record.get(); // store the whole struct - npc.mNpdt52 = + npc.mNpdt = static_cast > &>(nestedTable).mNestedTable.at(0); record.setModified (npc); @@ -1035,7 +1035,7 @@ CSMWorld::NestedTableWrapperBase* CSMWorld::NpcSkillsRefIdAdapter::nestedTable ( // return the whole struct std::vector wrap; - wrap.push_back(record.get().mNpdt52); + wrap.push_back(record.get().mNpdt); // deleted by dtor of NestedTableStoring return new NestedTableWrapper >(wrap); } @@ -1046,7 +1046,7 @@ QVariant CSMWorld::NpcSkillsRefIdAdapter::getNestedData (const RefIdColumn *colu const Record& record = static_cast&> (data.getRecord (RefIdData::LocalIndex (index, UniversalId::Type_Npc))); - const ESM::NPC::NPDTstruct52& npcStruct = record.get().mNpdt52; + const ESM::NPC::NPDTstruct52& npcStruct = record.get().mNpdt; if (subRowIndex < 0 || subRowIndex >= ESM::Skill::Length) throw std::runtime_error ("index out of range"); @@ -1065,7 +1065,7 @@ void CSMWorld::NpcSkillsRefIdAdapter::setNestedData (const RefIdColumn *column, Record& record = static_cast&> (data.getRecord (RefIdData::LocalIndex (row, UniversalId::Type_Npc))); ESM::NPC npc = record.get(); - ESM::NPC::NPDTstruct52& npcStruct = npc.mNpdt52; + ESM::NPC::NPDTstruct52& npcStruct = npc.mNpdt; if (subRowIndex < 0 || subRowIndex >= ESM::Skill::Length) throw std::runtime_error ("index out of range"); @@ -1130,30 +1130,30 @@ QVariant CSMWorld::NpcMiscRefIdAdapter::getNestedData (const RefIdColumn *column if (autoCalc) switch (subColIndex) { - case 0: return static_cast(record.get().mNpdt12.mLevel); + case 0: return static_cast(record.get().mNpdt.mLevel); case 1: return QVariant(QVariant::UserType); case 2: return QVariant(QVariant::UserType); case 3: return QVariant(QVariant::UserType); case 4: return QVariant(QVariant::UserType); - case 5: return static_cast(record.get().mNpdt12.mDisposition); - case 6: return static_cast(record.get().mNpdt12.mReputation); - case 7: return static_cast(record.get().mNpdt12.mRank); - case 8: return record.get().mNpdt12.mGold; + case 5: return static_cast(record.get().mNpdt.mDisposition); + case 6: return static_cast(record.get().mNpdt.mReputation); + case 7: return static_cast(record.get().mNpdt.mRank); + case 8: return record.get().mNpdt.mGold; case 9: return record.get().mPersistent == true; default: return QVariant(); // throw an exception here? } else switch (subColIndex) { - case 0: return static_cast(record.get().mNpdt52.mLevel); - case 1: return static_cast(record.get().mNpdt52.mFactionID); - case 2: return static_cast(record.get().mNpdt52.mHealth); - case 3: return static_cast(record.get().mNpdt52.mMana); - case 4: return static_cast(record.get().mNpdt52.mFatigue); - case 5: return static_cast(record.get().mNpdt52.mDisposition); - case 6: return static_cast(record.get().mNpdt52.mReputation); - case 7: return static_cast(record.get().mNpdt52.mRank); - case 8: return record.get().mNpdt52.mGold; + case 0: return static_cast(record.get().mNpdt.mLevel); + case 1: return static_cast(record.get().mNpdt.mFactionID); + case 2: return static_cast(record.get().mNpdt.mHealth); + case 3: return static_cast(record.get().mNpdt.mMana); + case 4: return static_cast(record.get().mNpdt.mFatigue); + case 5: return static_cast(record.get().mNpdt.mDisposition); + case 6: return static_cast(record.get().mNpdt.mReputation); + case 7: return static_cast(record.get().mNpdt.mRank); + case 8: return record.get().mNpdt.mGold; case 9: return record.get().mPersistent == true; default: return QVariant(); // throw an exception here? } @@ -1171,30 +1171,30 @@ void CSMWorld::NpcMiscRefIdAdapter::setNestedData (const RefIdColumn *column, if (autoCalc) switch(subColIndex) { - case 0: npc.mNpdt12.mLevel = static_cast(value.toInt()); break; + case 0: npc.mNpdt.mLevel = static_cast(value.toInt()); break; case 1: return; case 2: return; case 3: return; case 4: return; - case 5: npc.mNpdt12.mDisposition = static_cast(value.toInt()); break; - case 6: npc.mNpdt12.mReputation = static_cast(value.toInt()); break; - case 7: npc.mNpdt12.mRank = static_cast(value.toInt()); break; - case 8: npc.mNpdt12.mGold = value.toInt(); break; + case 5: npc.mNpdt.mDisposition = static_cast(value.toInt()); break; + case 6: npc.mNpdt.mReputation = static_cast(value.toInt()); break; + case 7: npc.mNpdt.mRank = static_cast(value.toInt()); break; + case 8: npc.mNpdt.mGold = value.toInt(); break; case 9: npc.mPersistent = value.toBool(); break; default: return; // throw an exception here? } else switch(subColIndex) { - case 0: npc.mNpdt52.mLevel = static_cast(value.toInt()); break; - case 1: npc.mNpdt52.mFactionID = static_cast(value.toInt()); break; - case 2: npc.mNpdt52.mHealth = static_cast(value.toInt()); break; - case 3: npc.mNpdt52.mMana = static_cast(value.toInt()); break; - case 4: npc.mNpdt52.mFatigue = static_cast(value.toInt()); break; - case 5: npc.mNpdt52.mDisposition = static_cast(value.toInt()); break; - case 6: npc.mNpdt52.mReputation = static_cast(value.toInt()); break; - case 7: npc.mNpdt52.mRank = static_cast(value.toInt()); break; - case 8: npc.mNpdt52.mGold = value.toInt(); break; + case 0: npc.mNpdt.mLevel = static_cast(value.toInt()); break; + case 1: npc.mNpdt.mFactionID = static_cast(value.toInt()); break; + case 2: npc.mNpdt.mHealth = static_cast(value.toInt()); break; + case 3: npc.mNpdt.mMana = static_cast(value.toInt()); break; + case 4: npc.mNpdt.mFatigue = static_cast(value.toInt()); break; + case 5: npc.mNpdt.mDisposition = static_cast(value.toInt()); break; + case 6: npc.mNpdt.mReputation = static_cast(value.toInt()); break; + case 7: npc.mNpdt.mRank = static_cast(value.toInt()); break; + case 8: npc.mNpdt.mGold = value.toInt(); break; case 9: npc.mPersistent = value.toBool(); break; default: return; // throw an exception here? } @@ -1375,8 +1375,6 @@ QVariant CSMWorld::CreatureAttackRefIdAdapter::getNestedData (const RefIdColumn return subRowIndex + 1; else if (subColIndex < 3) // 1 or 2 return creature.mData.mAttack[(subRowIndex * 2) + (subColIndex - 1)]; - else - return QVariant(); // throw an exception here? } void CSMWorld::CreatureAttackRefIdAdapter::setNestedData (const RefIdColumn *column, diff --git a/apps/opencs/model/world/universalid.cpp b/apps/opencs/model/world/universalid.cpp index 38386f6da..8d7a7761e 100644 --- a/apps/opencs/model/world/universalid.cpp +++ b/apps/opencs/model/world/universalid.cpp @@ -64,21 +64,21 @@ namespace static const TypeData sIdArg[] = { - { CSMWorld::UniversalId::Class_Record, CSMWorld::UniversalId::Type_Global, "Global Variable", ":./globvar.png" }, - { CSMWorld::UniversalId::Class_Record, CSMWorld::UniversalId::Type_Gmst, "Game Setting", ":./GMST.png" }, + { CSMWorld::UniversalId::Class_Record, CSMWorld::UniversalId::Type_Global, "Global Variable", ":./global-variable.png" }, + { CSMWorld::UniversalId::Class_Record, CSMWorld::UniversalId::Type_Gmst, "Game Setting", ":./gmst.png" }, { CSMWorld::UniversalId::Class_Record, CSMWorld::UniversalId::Type_Skill, "Skill", ":./skill.png" }, { CSMWorld::UniversalId::Class_Record, CSMWorld::UniversalId::Type_Class, "Class", ":./class.png" }, { CSMWorld::UniversalId::Class_Record, CSMWorld::UniversalId::Type_Faction, "Faction", ":./faction.png" }, { CSMWorld::UniversalId::Class_Record, CSMWorld::UniversalId::Type_Race, "Race", ":./race.png" }, { CSMWorld::UniversalId::Class_Record, CSMWorld::UniversalId::Type_Sound, "Sound", ":./sound.png" }, { CSMWorld::UniversalId::Class_Record, CSMWorld::UniversalId::Type_Script, "Script", ":./script.png" }, - { CSMWorld::UniversalId::Class_Record, CSMWorld::UniversalId::Type_Region, "Region", ":./land.png" }, + { CSMWorld::UniversalId::Class_Record, CSMWorld::UniversalId::Type_Region, "Region", ":./region.png" }, { CSMWorld::UniversalId::Class_Record, CSMWorld::UniversalId::Type_Birthsign, "Birthsign", ":./birthsign.png" }, { CSMWorld::UniversalId::Class_Record, CSMWorld::UniversalId::Type_Spell, "Spell", ":./spell.png" }, - { CSMWorld::UniversalId::Class_Record, CSMWorld::UniversalId::Type_Topic, "Topic", 0 }, - { CSMWorld::UniversalId::Class_Record, CSMWorld::UniversalId::Type_Journal, "Journal", 0 }, - { CSMWorld::UniversalId::Class_SubRecord, CSMWorld::UniversalId::Type_TopicInfo, "TopicInfo", 0 }, - { CSMWorld::UniversalId::Class_SubRecord, CSMWorld::UniversalId::Type_JournalInfo, "JournalInfo", 0 }, + { CSMWorld::UniversalId::Class_Record, CSMWorld::UniversalId::Type_Topic, "Topic", ":./dialogue-topics.png" }, + { CSMWorld::UniversalId::Class_Record, CSMWorld::UniversalId::Type_Journal, "Journal", ":./journal-topics.png" }, + { CSMWorld::UniversalId::Class_SubRecord, CSMWorld::UniversalId::Type_TopicInfo, "TopicInfo", ":./dialogue-topic-infos.png" }, + { CSMWorld::UniversalId::Class_SubRecord, CSMWorld::UniversalId::Type_JournalInfo, "JournalInfo", ":./journal-topic-infos.png" }, { CSMWorld::UniversalId::Class_Record, CSMWorld::UniversalId::Type_Cell, "Cell", ":./cell.png" }, { CSMWorld::UniversalId::Class_Record, CSMWorld::UniversalId::Type_Cell_Missing, "Cell", ":./cell.png" }, { CSMWorld::UniversalId::Class_Record, CSMWorld::UniversalId::Type_Referenceable, "Object", 0 }, @@ -93,7 +93,7 @@ namespace { CSMWorld::UniversalId::Class_RefRecord, CSMWorld::UniversalId::Type_Door, "Door", ":./door.png" }, { CSMWorld::UniversalId::Class_RefRecord, CSMWorld::UniversalId::Type_Ingredient, "Ingredient", ":./ingredient.png" }, { CSMWorld::UniversalId::Class_RefRecord, CSMWorld::UniversalId::Type_CreatureLevelledList, - "Creature Levelled List", ":./creature.png" }, + "Creature Levelled List", ":./leveled-creature.png" }, { CSMWorld::UniversalId::Class_RefRecord, CSMWorld::UniversalId::Type_ItemLevelledList, "Item Levelled List", ":./leveled-item.png" }, { CSMWorld::UniversalId::Class_RefRecord, CSMWorld::UniversalId::Type_Light, "Light", ":./light.png" }, @@ -109,20 +109,20 @@ namespace { CSMWorld::UniversalId::Class_Record, CSMWorld::UniversalId::Type_Filter, "Filter", ":./filter.png" }, { CSMWorld::UniversalId::Class_Collection, CSMWorld::UniversalId::Type_Scene, "Scene", 0 }, { CSMWorld::UniversalId::Class_Collection, CSMWorld::UniversalId::Type_Preview, "Preview", 0 }, - { CSMWorld::UniversalId::Class_Record, CSMWorld::UniversalId::Type_Enchantment, "Enchantment", 0 }, - { CSMWorld::UniversalId::Class_Record, CSMWorld::UniversalId::Type_BodyPart, "Body Part", 0 }, - { CSMWorld::UniversalId::Class_Resource, CSMWorld::UniversalId::Type_Mesh, "Mesh", 0 }, - { CSMWorld::UniversalId::Class_Resource, CSMWorld::UniversalId::Type_Icon, "Icon", 0 }, - { CSMWorld::UniversalId::Class_Resource, CSMWorld::UniversalId::Type_Music, "Music", 0 }, - { CSMWorld::UniversalId::Class_Resource, CSMWorld::UniversalId::Type_SoundRes, "Sound File", 0 }, - { CSMWorld::UniversalId::Class_Resource, CSMWorld::UniversalId::Type_Texture, "Texture", 0 }, - { CSMWorld::UniversalId::Class_Resource, CSMWorld::UniversalId::Type_Video, "Video", 0 }, + { CSMWorld::UniversalId::Class_Record, CSMWorld::UniversalId::Type_Enchantment, "Enchantment", ":./enchantment.png" }, + { CSMWorld::UniversalId::Class_Record, CSMWorld::UniversalId::Type_BodyPart, "Body Part", ":./body-part.png" }, + { CSMWorld::UniversalId::Class_Resource, CSMWorld::UniversalId::Type_Mesh, "Mesh", ":resources-mesh"}, + { CSMWorld::UniversalId::Class_Resource, CSMWorld::UniversalId::Type_Icon, "Icon", ":resources-icon"}, + { CSMWorld::UniversalId::Class_Resource, CSMWorld::UniversalId::Type_Music, "Music", ":resources-music" }, + { CSMWorld::UniversalId::Class_Resource, CSMWorld::UniversalId::Type_SoundRes, "Sound File", ":resources-sound" }, + { CSMWorld::UniversalId::Class_Resource, CSMWorld::UniversalId::Type_Texture, "Texture", ":resources-texture"}, + { CSMWorld::UniversalId::Class_Resource, CSMWorld::UniversalId::Type_Video, "Video", ":resources-video"}, { CSMWorld::UniversalId::Class_Record, CSMWorld::UniversalId::Type_DebugProfile, "Debug Profile", 0 }, - { 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_Land, "Land", 0 }, - { CSMWorld::UniversalId::Class_Record, CSMWorld::UniversalId::Type_LandTexture, "LandTexture", 0 }, - { CSMWorld::UniversalId::Class_Record, CSMWorld::UniversalId::Type_Pathgrid, "Pathgrid", 0 }, + { CSMWorld::UniversalId::Class_Record, CSMWorld::UniversalId::Type_SoundGen, "Sound Generator", ":./sound-generator.png" }, + { CSMWorld::UniversalId::Class_Record, CSMWorld::UniversalId::Type_MagicEffect, "Magic Effect", ":./magic-effect.png" }, + { CSMWorld::UniversalId::Class_Record, CSMWorld::UniversalId::Type_Land, "Land", ":./land-heightmap.png" }, + { CSMWorld::UniversalId::Class_Record, CSMWorld::UniversalId::Type_LandTexture, "LandTexture", ":./land-texture.png" }, + { CSMWorld::UniversalId::Class_Record, CSMWorld::UniversalId::Type_Pathgrid, "Pathgrid", ":./pathgrid.png" }, { CSMWorld::UniversalId::Class_Record, CSMWorld::UniversalId::Type_StartScript, "Start Script", 0 }, { CSMWorld::UniversalId::Class_Record, CSMWorld::UniversalId::Type_MetaData, "Meta Data", 0 }, diff --git a/apps/opencs/view/doc/loader.cpp b/apps/opencs/view/doc/loader.cpp index 713295d70..49a53e179 100644 --- a/apps/opencs/view/doc/loader.cpp +++ b/apps/opencs/view/doc/loader.cpp @@ -167,7 +167,7 @@ void CSVDoc::Loader::loadingStopped (CSMDoc::Document *document, bool completed, delete iter->second; mDocuments.erase (iter); } - else if (!completed && !error.empty()) + else { iter->second->abort (error); // Leave the window open for now (wait for the user to close it) diff --git a/apps/opencs/view/doc/startup.cpp b/apps/opencs/view/doc/startup.cpp index 67ff50dab..78f18b3a1 100644 --- a/apps/opencs/view/doc/startup.cpp +++ b/apps/opencs/view/doc/startup.cpp @@ -106,7 +106,7 @@ CSVDoc::StartupDialogue::StartupDialogue() : mWidth (0), mColumn (2) /// \todo remove this label once we are feature complete and convinced that this thing is /// working properly. - QLabel *warning = new QLabel ("WARNING: OpenMW-CS is in alpha stage.

The editor is not feature complete and not sufficiently tested.
In theory your data should be safe. But we strongly advice to make backups regularly if you are working with live data.
"); + QLabel *warning = new QLabel ("WARNING: OpenMW-CS is in alpha stage.

The editor is not feature complete and not sufficiently tested.
In theory your data should be safe. But we strongly advise to make backups regularly if you are working with live data.
"); QFont font; font.setPointSize (12); diff --git a/apps/opencs/view/render/instancemode.cpp b/apps/opencs/view/render/instancemode.cpp index fae609af5..ee3e18d71 100644 --- a/apps/opencs/view/render/instancemode.cpp +++ b/apps/opencs/view/render/instancemode.cpp @@ -92,7 +92,7 @@ osg::Vec3f CSVRender::InstanceMode::getScreenCoords(const osg::Vec3f& pos) } CSVRender::InstanceMode::InstanceMode (WorldspaceWidget *worldspaceWidget, QWidget *parent) -: EditMode (worldspaceWidget, QIcon (":placeholder"), Mask_Reference | Mask_Terrain, "Instance editing", +: EditMode (worldspaceWidget, QIcon (":scenetoolbar/editing-instance"), Mask_Reference | Mask_Terrain, "Instance editing", parent), mSubMode (0), mSubModeId ("move"), mSelectionMode (0), mDragMode (DragMode_None), mDragAxis (-1), mLocked (false), mUnitScaleDist(1) { @@ -104,14 +104,14 @@ void CSVRender::InstanceMode::activate (CSVWidget::SceneToolbar *toolbar) { mSubMode = new CSVWidget::SceneToolMode (toolbar, "Edit Sub-Mode"); mSubMode->addButton (new InstanceMoveMode (this), "move"); - mSubMode->addButton (":placeholder", "rotate", + mSubMode->addButton (":scenetoolbar/transform-rotate", "rotate", "Rotate selected instances" "

  • Use {scene-edit-primary} to rotate instances freely
  • " "
  • Use {scene-edit-secondary} to rotate instances within the grid
  • " "
  • The center of the view acts as the axis of rotation
  • " "
" "Grid rotate not implemented yet"); - mSubMode->addButton (":placeholder", "scale", + mSubMode->addButton (":scenetoolbar/transform-scale", "scale", "Scale selected instances" "
  • Use {scene-edit-primary} to scale instances freely
  • " "
  • Use {scene-edit-secondary} to scale instances along the grid
  • " diff --git a/apps/opencs/view/render/instancemovemode.cpp b/apps/opencs/view/render/instancemovemode.cpp index fe58b581b..723af811d 100644 --- a/apps/opencs/view/render/instancemovemode.cpp +++ b/apps/opencs/view/render/instancemovemode.cpp @@ -2,7 +2,7 @@ #include "instancemovemode.hpp" CSVRender::InstanceMoveMode::InstanceMoveMode (QWidget *parent) -: ModeButton (QIcon (QPixmap (":placeholder")), +: ModeButton (QIcon (QPixmap (":scenetoolbar/transform-move")), "Move selected instances" "
    • Use {scene-edit-primary} to move instances around freely
    • " "
    • Use {scene-edit-secondary} to move instances around within the grid
    • " diff --git a/apps/opencs/view/render/selectionmode.cpp b/apps/opencs/view/render/selectionmode.cpp index cf0967e47..b5ccda5ad 100644 --- a/apps/opencs/view/render/selectionmode.cpp +++ b/apps/opencs/view/render/selectionmode.cpp @@ -13,7 +13,7 @@ namespace CSVRender , mWorldspaceWidget(worldspaceWidget) , mInteractionMask(interactionMask) { - addButton(":placeholder", "cube-centre", + addButton(":scenetoolbar/selection-mode-cube", "cube-centre", "Centred cube" "
      • Drag with {scene-select-primary} (make instances the selection) or {scene-select-secondary} " "(invert selection state) from the centre of the selection cube outwards
      • " @@ -22,7 +22,7 @@ namespace CSVRender "starting on an instance will have the same effect" "
      " "Not implemented yet"); - addButton(":placeholder", "cube-corner", + addButton(":scenetoolbar/selection-mode-cube-corner", "cube-corner", "Cube corner to corner" "
      • Drag with {scene-select-primary} (make instances the selection) or {scene-select-secondary} " "(invert selection state) from one corner of the selection cube to the opposite corner
      • " @@ -31,7 +31,7 @@ namespace CSVRender "starting on an instance will have the same effect" "
      " "Not implemented yet"); - addButton(":placeholder", "sphere", + addButton(":scenetoolbar/selection-mode-cube-sphere", "sphere", "Centred sphere" "
      • Drag with {scene-select-primary} (make instances the selection) or {scene-select-secondary} " "(invert selection state) from the centre of the selection sphere outwards
      • " diff --git a/apps/opencs/view/tools/reporttable.cpp b/apps/opencs/view/tools/reporttable.cpp index 4d1456cd9..a970af168 100644 --- a/apps/opencs/view/tools/reporttable.cpp +++ b/apps/opencs/view/tools/reporttable.cpp @@ -156,6 +156,7 @@ CSVTools::ReportTable::ReportTable (CSMDoc::Document& document, setSelectionMode (QAbstractItemView::ExtendedSelection); mProxyModel = new QSortFilterProxyModel (this); + mProxyModel->setSortCaseSensitivity(Qt::CaseInsensitive); mProxyModel->setSourceModel (mModel); mProxyModel->setSortRole(Qt::UserRole); diff --git a/apps/opencs/view/world/recordbuttonbar.cpp b/apps/opencs/view/world/recordbuttonbar.cpp index 40a24bf65..9fea7b303 100644 --- a/apps/opencs/view/world/recordbuttonbar.cpp +++ b/apps/opencs/view/world/recordbuttonbar.cpp @@ -57,12 +57,12 @@ CSVWorld::RecordButtonBar::RecordButtonBar (const CSMWorld::UniversalId& id, // left section mPrevButton = new QToolButton (this); - mPrevButton->setIcon(QIcon(":/go-previous.png")); + mPrevButton->setIcon(QIcon(":record-previous")); mPrevButton->setToolTip ("Switch to previous record"); buttonsLayout->addWidget (mPrevButton, 0); mNextButton = new QToolButton (this); - mNextButton->setIcon(QIcon(":/go-next.png")); + mNextButton->setIcon(QIcon(":/record-next")); mNextButton->setToolTip ("Switch to next record"); buttonsLayout->addWidget (mNextButton, 1); @@ -72,7 +72,7 @@ CSVWorld::RecordButtonBar::RecordButtonBar (const CSMWorld::UniversalId& id, if (mTable.getFeatures() & CSMWorld::IdTable::Feature_Preview) { QToolButton* previewButton = new QToolButton (this); - previewButton->setIcon(QIcon(":/edit-preview.png")); + previewButton->setIcon(QIcon(":edit-preview")); previewButton->setToolTip ("Open a preview of this record"); buttonsLayout->addWidget(previewButton); connect (previewButton, SIGNAL(clicked()), this, SIGNAL (showPreview())); @@ -89,22 +89,22 @@ CSVWorld::RecordButtonBar::RecordButtonBar (const CSMWorld::UniversalId& id, // right section mCloneButton = new QToolButton (this); - mCloneButton->setIcon(QIcon(":/edit-clone.png")); + mCloneButton->setIcon(QIcon(":edit-clone")); mCloneButton->setToolTip ("Clone record"); buttonsLayout->addWidget(mCloneButton); mAddButton = new QToolButton (this); - mAddButton->setIcon(QIcon(":/add.png")); + mAddButton->setIcon(QIcon(":edit-add")); mAddButton->setToolTip ("Add new record"); buttonsLayout->addWidget(mAddButton); mDeleteButton = new QToolButton (this); - mDeleteButton->setIcon(QIcon(":/edit-delete.png")); + mDeleteButton->setIcon(QIcon(":edit-delete")); mDeleteButton->setToolTip ("Delete record"); buttonsLayout->addWidget(mDeleteButton); mRevertButton = new QToolButton (this); - mRevertButton->setIcon(QIcon(":/edit-undo.png")); + mRevertButton->setIcon(QIcon(":edit-undo")); mRevertButton->setToolTip ("Revert record"); buttonsLayout->addWidget(mRevertButton); diff --git a/apps/opencs/view/world/recordstatusdelegate.cpp b/apps/opencs/view/world/recordstatusdelegate.cpp index 12d545339..4a229657d 100644 --- a/apps/opencs/view/world/recordstatusdelegate.cpp +++ b/apps/opencs/view/world/recordstatusdelegate.cpp @@ -27,7 +27,7 @@ CSVWorld::RecordStatusDelegateFactory::RecordStatusDelegateFactory() static const char *sIcons[] = { - ":./base.png", ":./modified.png", ":./added.png", ":./removed.png", ":./removed.png", 0 + ":list-base", ":list-modified", ":list-added", ":list-removed", ":list-removed", 0 }; for (int i=0; sIcons[i]; ++i) diff --git a/apps/opencs/view/world/referencecreator.cpp b/apps/opencs/view/world/referencecreator.cpp index 1363f489a..e939b9baf 100644 --- a/apps/opencs/view/world/referencecreator.cpp +++ b/apps/opencs/view/world/referencecreator.cpp @@ -63,19 +63,9 @@ std::string CSVWorld::ReferenceCreator::getErrors() const std::string cell = mCell->text().toUtf8().constData(); if (cell.empty()) - { - if (!errors.empty()) - errors += "
        "; - errors += "Missing Cell ID"; - } else if (getData().getCells().searchId (cell)==-1) - { - if (!errors.empty()) - errors += "
        "; - errors += "Invalid Cell ID"; - } return errors; } diff --git a/apps/opencs/view/world/table.cpp b/apps/opencs/view/world/table.cpp index 34ecd57d0..986717cb2 100644 --- a/apps/opencs/view/world/table.cpp +++ b/apps/opencs/view/world/table.cpp @@ -764,10 +764,8 @@ std::vector< CSMWorld::UniversalId > CSVWorld::Table::getDraggedRecords() const QModelIndexList selectedRows = selectionModel()->selectedRows(); std::vector idToDrag; - foreach (QModelIndex it, selectedRows) //I had a dream. Dream where you could use C++11 in OpenMW. - { + for (QModelIndex& it : selectedRows) idToDrag.push_back (getUniversalId (it.row())); - } return idToDrag; } diff --git a/apps/openmw/CMakeLists.txt b/apps/openmw/CMakeLists.txt index 4995f9b41..9c1dd60a9 100644 --- a/apps/openmw/CMakeLists.txt +++ b/apps/openmw/CMakeLists.txt @@ -89,7 +89,7 @@ add_openmw_dir (mwmechanics ) add_openmw_dir (mwstate - statemanagerimp charactermanager character + statemanagerimp charactermanager character quicksavemanager ) add_openmw_dir (mwbase @@ -223,4 +223,3 @@ endif (MSVC) if (WIN32) INSTALL(TARGETS openmw RUNTIME DESTINATION ".") endif (WIN32) - diff --git a/apps/openmw/android_main.c b/apps/openmw/android_main.c index 3f28afa1b..d234a369d 100644 --- a/apps/openmw/android_main.c +++ b/apps/openmw/android_main.c @@ -35,28 +35,11 @@ int Java_org_libsdl_app_SDLActivity_isMouseShown(JNIEnv *env, jclass cls, jobjec return SDL_ShowCursor(SDL_QUERY); } - -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) { setenv("OPENMW_DECOMPRESS_TEXTURES", "1", 1); - SDL_Android_Init(env, cls); - - SDL_SetMainReady(); - // On Android, we use a virtual controller with guid="Virtual" SDL_GameControllerAddMapping("5669727475616c000000000000000000,Virtual,a:b0,b:b1,back:b15,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b16,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4"); - /* Run the application code! */ - - 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; + return 0; } - diff --git a/apps/openmw/mwbase/dialoguemanager.hpp b/apps/openmw/mwbase/dialoguemanager.hpp index a9afae786..7bace3790 100644 --- a/apps/openmw/mwbase/dialoguemanager.hpp +++ b/apps/openmw/mwbase/dialoguemanager.hpp @@ -39,6 +39,7 @@ namespace MWBase class ResponseCallback { public: + virtual ~ResponseCallback() = default; virtual void addResponse(const std::string& title, const std::string& text) = 0; }; diff --git a/apps/openmw/mwbase/windowmanager.hpp b/apps/openmw/mwbase/windowmanager.hpp index d454067c8..8a9eb2ea6 100644 --- a/apps/openmw/mwbase/windowmanager.hpp +++ b/apps/openmw/mwbase/windowmanager.hpp @@ -337,7 +337,7 @@ namespace MWBase /// Cycle to next or previous weapon virtual void cycleWeapon(bool next) = 0; - virtual void playSound(const std::string& soundId, float volume = 1.f, float pitch = 1.f) = 0; + virtual void playSound(const std::string& soundId, bool preventOverlapping = false, float volume = 1.f, float pitch = 1.f) = 0; // In WindowManager for now since there isn't a VFS singleton virtual std::string correctIconPath(const std::string& path) = 0; diff --git a/apps/openmw/mwbase/world.hpp b/apps/openmw/mwbase/world.hpp index 038535939..47502fd71 100644 --- a/apps/openmw/mwbase/world.hpp +++ b/apps/openmw/mwbase/world.hpp @@ -491,12 +491,14 @@ namespace MWBase virtual void launchProjectile (MWWorld::Ptr actor, MWWorld::ConstPtr projectile, const osg::Vec3f& worldPos, const osg::Quat& orient, MWWorld::Ptr bow, float speed, float attackStrength) = 0; + virtual void applyLoopingParticles(const MWWorld::Ptr& ptr) = 0; + virtual const std::vector& getContentFiles() const = 0; virtual void breakInvisibility (const MWWorld::Ptr& actor) = 0; - // Are we in an exterior or pseudo-exterior cell and it's night? - virtual bool isDark() const = 0; + // Allow NPCs to use torches? + virtual bool useTorches() const = 0; virtual bool findInteriorPositionInWorldSpace(const MWWorld::CellStore* cell, osg::Vec3f& result) = 0; diff --git a/apps/openmw/mwclass/light.cpp b/apps/openmw/mwclass/light.cpp index f9056b75d..aeeb89a72 100644 --- a/apps/openmw/mwclass/light.cpp +++ b/apps/openmw/mwclass/light.cpp @@ -233,24 +233,6 @@ namespace MWClass if (!(ref->mBase->mData.mFlags & ESM::Light::Carry)) return std::make_pair(0,""); - const MWWorld::InventoryStore& invStore = npc.getClass().getInventoryStore(npc); - MWWorld::ConstContainerStoreIterator weapon = invStore.getSlot(MWWorld::InventoryStore::Slot_CarriedRight); - - if(weapon == invStore.end()) - return std::make_pair(1,""); - - /// \todo the 2h check is repeated many times; put it in a function - if(weapon->getTypeName() == typeid(ESM::Weapon).name() && - (weapon->get()->mBase->mData.mType == ESM::Weapon::LongBladeTwoHand || - weapon->get()->mBase->mData.mType == ESM::Weapon::BluntTwoClose || - weapon->get()->mBase->mData.mType == ESM::Weapon::BluntTwoWide || - weapon->get()->mBase->mData.mType == ESM::Weapon::SpearTwoWide || - weapon->get()->mBase->mData.mType == ESM::Weapon::AxeTwoHand || - weapon->get()->mBase->mData.mType == ESM::Weapon::MarksmanBow || - weapon->get()->mBase->mData.mType == ESM::Weapon::MarksmanCrossbow)) - { - return std::make_pair(3,""); - } return std::make_pair(1,""); } diff --git a/apps/openmw/mwclass/misc.cpp b/apps/openmw/mwclass/misc.cpp index a68176226..5a933d535 100644 --- a/apps/openmw/mwclass/misc.cpp +++ b/apps/openmw/mwclass/misc.cpp @@ -83,8 +83,9 @@ namespace MWClass if (ptr.getCellRef().getSoul() != "") { - const ESM::Creature *creature = MWBase::Environment::get().getWorld()->getStore().get().find(ref->mRef.getSoul()); - value *= creature->mData.mSoul; + const ESM::Creature *creature = MWBase::Environment::get().getWorld()->getStore().get().search(ref->mRef.getSoul()); + if (creature) + value *= creature->mData.mSoul; } return value; @@ -148,8 +149,9 @@ namespace MWClass if (ref->mRef.getSoul() != "") { - const ESM::Creature *creature = store.get().find(ref->mRef.getSoul()); - info.caption += " (" + creature->mName + ")"; + const ESM::Creature *creature = store.get().search(ref->mRef.getSoul()); + if (creature) + info.caption += " (" + creature->mName + ")"; } std::string text; @@ -210,7 +212,7 @@ namespace MWClass std::shared_ptr Miscellaneous::use (const MWWorld::Ptr& ptr) const { - if (ptr.getCellRef().getSoul().empty()) + if (ptr.getCellRef().getSoul().empty() || !MWBase::Environment::get().getWorld()->getStore().get().search(ptr.getCellRef().getSoul())) return std::shared_ptr(new MWWorld::NullAction()); else return std::shared_ptr(new MWWorld::ActionSoulgem(ptr)); diff --git a/apps/openmw/mwclass/npc.cpp b/apps/openmw/mwclass/npc.cpp index 134bbf943..f3f763897 100644 --- a/apps/openmw/mwclass/npc.cpp +++ b/apps/openmw/mwclass/npc.cpp @@ -312,40 +312,40 @@ namespace MWClass int gold=0; if(ref->mBase->mNpdtType != ESM::NPC::NPC_WITH_AUTOCALCULATED_STATS) { - gold = ref->mBase->mNpdt52.mGold; + gold = ref->mBase->mNpdt.mGold; for (unsigned int i=0; i< ESM::Skill::Length; ++i) - data->mNpcStats.getSkill (i).setBase (ref->mBase->mNpdt52.mSkills[i]); + data->mNpcStats.getSkill (i).setBase (ref->mBase->mNpdt.mSkills[i]); - data->mNpcStats.setAttribute(ESM::Attribute::Strength, ref->mBase->mNpdt52.mStrength); - data->mNpcStats.setAttribute(ESM::Attribute::Intelligence, ref->mBase->mNpdt52.mIntelligence); - data->mNpcStats.setAttribute(ESM::Attribute::Willpower, ref->mBase->mNpdt52.mWillpower); - data->mNpcStats.setAttribute(ESM::Attribute::Agility, ref->mBase->mNpdt52.mAgility); - data->mNpcStats.setAttribute(ESM::Attribute::Speed, ref->mBase->mNpdt52.mSpeed); - data->mNpcStats.setAttribute(ESM::Attribute::Endurance, ref->mBase->mNpdt52.mEndurance); - data->mNpcStats.setAttribute(ESM::Attribute::Personality, ref->mBase->mNpdt52.mPersonality); - data->mNpcStats.setAttribute(ESM::Attribute::Luck, ref->mBase->mNpdt52.mLuck); + data->mNpcStats.setAttribute(ESM::Attribute::Strength, ref->mBase->mNpdt.mStrength); + data->mNpcStats.setAttribute(ESM::Attribute::Intelligence, ref->mBase->mNpdt.mIntelligence); + data->mNpcStats.setAttribute(ESM::Attribute::Willpower, ref->mBase->mNpdt.mWillpower); + data->mNpcStats.setAttribute(ESM::Attribute::Agility, ref->mBase->mNpdt.mAgility); + data->mNpcStats.setAttribute(ESM::Attribute::Speed, ref->mBase->mNpdt.mSpeed); + data->mNpcStats.setAttribute(ESM::Attribute::Endurance, ref->mBase->mNpdt.mEndurance); + data->mNpcStats.setAttribute(ESM::Attribute::Personality, ref->mBase->mNpdt.mPersonality); + data->mNpcStats.setAttribute(ESM::Attribute::Luck, ref->mBase->mNpdt.mLuck); - data->mNpcStats.setHealth (ref->mBase->mNpdt52.mHealth); - data->mNpcStats.setMagicka (ref->mBase->mNpdt52.mMana); - data->mNpcStats.setFatigue (ref->mBase->mNpdt52.mFatigue); + data->mNpcStats.setHealth (ref->mBase->mNpdt.mHealth); + data->mNpcStats.setMagicka (ref->mBase->mNpdt.mMana); + data->mNpcStats.setFatigue (ref->mBase->mNpdt.mFatigue); - data->mNpcStats.setLevel(ref->mBase->mNpdt52.mLevel); - data->mNpcStats.setBaseDisposition(ref->mBase->mNpdt52.mDisposition); - data->mNpcStats.setReputation(ref->mBase->mNpdt52.mReputation); + data->mNpcStats.setLevel(ref->mBase->mNpdt.mLevel); + data->mNpcStats.setBaseDisposition(ref->mBase->mNpdt.mDisposition); + data->mNpcStats.setReputation(ref->mBase->mNpdt.mReputation); data->mNpcStats.setNeedRecalcDynamicStats(false); } else { - gold = ref->mBase->mNpdt12.mGold; + gold = ref->mBase->mNpdt.mGold; for (int i=0; i<3; ++i) data->mNpcStats.setDynamic (i, 10); - data->mNpcStats.setLevel(ref->mBase->mNpdt12.mLevel); - data->mNpcStats.setBaseDisposition(ref->mBase->mNpdt12.mDisposition); - data->mNpcStats.setReputation(ref->mBase->mNpdt12.mReputation); + data->mNpcStats.setLevel(ref->mBase->mNpdt.mLevel); + data->mNpcStats.setBaseDisposition(ref->mBase->mNpdt.mDisposition); + data->mNpcStats.setReputation(ref->mBase->mNpdt.mReputation); autoCalculateAttributes(ref->mBase, data->mNpcStats); autoCalculateSkills(ref->mBase, data->mNpcStats, ptr); @@ -406,7 +406,7 @@ namespace MWClass // store ptr.getRefData().setCustomData (data.release()); - getInventoryStore(ptr).autoEquip(ptr); + getInventoryStore(ptr).autoEquip(ptr); } } @@ -1327,10 +1327,7 @@ namespace MWClass int Npc::getBaseGold(const MWWorld::ConstPtr& ptr) const { const MWWorld::LiveCellRef *ref = ptr.get(); - if(ref->mBase->mNpdtType != ESM::NPC::NPC_WITH_AUTOCALCULATED_STATS) - return ref->mBase->mNpdt52.mGold; - else - return ref->mBase->mNpdt12.mGold; + return ref->mBase->mNpdt.mGold; } bool Npc::isClass(const MWWorld::ConstPtr& ptr, const std::string &className) const diff --git a/apps/openmw/mwgui/bookpage.cpp b/apps/openmw/mwgui/bookpage.cpp index 5a9237cea..6f16cf076 100644 --- a/apps/openmw/mwgui/bookpage.cpp +++ b/apps/openmw/mwgui/bookpage.cpp @@ -892,7 +892,7 @@ protected: public: typedef TypesetBookImpl::StyleImpl Style; - typedef std::map ActiveTextFormats; + typedef std::map > ActiveTextFormats; int mViewTop; int mViewBottom; @@ -1048,7 +1048,7 @@ public: { if (mNode != NULL) i->second->destroyDrawItem (mNode); - delete i->second; + i->second.reset(); } mActiveTextFormats.clear (); @@ -1115,11 +1115,11 @@ public: if (j == this_->mActiveTextFormats.end ()) { - TextFormat * textFormat = new TextFormat (Font, this_); + std::unique_ptr textFormat(new TextFormat (Font, this_)); textFormat->mTexture = Font->getTextureFont (); - j = this_->mActiveTextFormats.insert (std::make_pair (Font, textFormat)).first; + j = this_->mActiveTextFormats.insert (std::make_pair (Font, std::move(textFormat))).first; } j->second->mCountVertex += run.mPrintableChars * 6; diff --git a/apps/openmw/mwgui/bookwindow.cpp b/apps/openmw/mwgui/bookwindow.cpp index c18548dad..cb902cadf 100644 --- a/apps/openmw/mwgui/bookwindow.cpp +++ b/apps/openmw/mwgui/bookwindow.cpp @@ -200,7 +200,7 @@ namespace MWGui { if ((mCurrentPage+1)*2 < mPages.size()) { - MWBase::Environment::get().getWindowManager()->playSound("book page2"); + MWBase::Environment::get().getWindowManager()->playSound("book page2", true); ++mCurrentPage; @@ -211,7 +211,7 @@ namespace MWGui { if (mCurrentPage > 0) { - MWBase::Environment::get().getWindowManager()->playSound("book page"); + MWBase::Environment::get().getWindowManager()->playSound("book page", true); --mCurrentPage; diff --git a/apps/openmw/mwgui/inventorywindow.cpp b/apps/openmw/mwgui/inventorywindow.cpp index 7bf8ad025..4acf61d93 100644 --- a/apps/openmw/mwgui/inventorywindow.cpp +++ b/apps/openmw/mwgui/inventorywindow.cpp @@ -129,6 +129,12 @@ namespace MWGui mItemView->setModel(mSortModel); + mFilterAll->setStateSelected(true); + mFilterWeapon->setStateSelected(false); + mFilterApparel->setStateSelected(false); + mFilterMagic->setStateSelected(false); + mFilterMisc->setStateSelected(false); + mPreview->updatePtr(mPtr); mPreview->rebuild(); mPreview->update(); diff --git a/apps/openmw/mwgui/itemwidget.cpp b/apps/openmw/mwgui/itemwidget.cpp index a31eb9c76..6b5be0314 100644 --- a/apps/openmw/mwgui/itemwidget.cpp +++ b/apps/openmw/mwgui/itemwidget.cpp @@ -16,8 +16,13 @@ namespace { if (count == 1) return ""; - if (count > 9999) - return MyGUI::utility::toString(int(count/1000.f)) + "k"; + + if (count > 999999999) + return MyGUI::utility::toString(count/1000000000) + "b"; + else if (count > 999999) + return MyGUI::utility::toString(count/1000000) + "m"; + else if (count > 9999) + return MyGUI::utility::toString(count/1000) + "k"; else return MyGUI::utility::toString(count); } diff --git a/apps/openmw/mwgui/journalwindow.cpp b/apps/openmw/mwgui/journalwindow.cpp index 4b7a789e8..0776706d8 100644 --- a/apps/openmw/mwgui/journalwindow.cpp +++ b/apps/openmw/mwgui/journalwindow.cpp @@ -616,7 +616,7 @@ namespace if (page+2 < book->pageCount()) { - MWBase::Environment::get().getWindowManager()->playSound("book page"); + MWBase::Environment::get().getWindowManager()->playSound("book page", true); page += 2; updateShowingPages (); @@ -634,7 +634,7 @@ namespace if(page >= 2) { - MWBase::Environment::get().getWindowManager()->playSound("book page"); + MWBase::Environment::get().getWindowManager()->playSound("book page", true); page -= 2; updateShowingPages (); diff --git a/apps/openmw/mwgui/keyboardnavigation.cpp b/apps/openmw/mwgui/keyboardnavigation.cpp index d27185204..1374ef93d 100644 --- a/apps/openmw/mwgui/keyboardnavigation.cpp +++ b/apps/openmw/mwgui/keyboardnavigation.cpp @@ -39,6 +39,7 @@ void getKeyFocusWidgets(MyGUI::Widget* parent, std::vector& resu KeyboardNavigation::KeyboardNavigation() : mCurrentFocus(nullptr) , mModalWindow(nullptr) + , mEnabled(true) { MyGUI::WidgetManager::getInstance().registerUnlinker(this); } @@ -101,6 +102,9 @@ bool isRootParent(MyGUI::Widget* widget, MyGUI::Widget* root) void KeyboardNavigation::onFrame() { + if (!mEnabled) + return; + MyGUI::Widget* focus = MyGUI::InputManager::getInstance().getKeyFocusWidget(); if (focus == mCurrentFocus) @@ -150,6 +154,11 @@ void KeyboardNavigation::setModalWindow(MyGUI::Widget *window) mModalWindow = window; } +void KeyboardNavigation::setEnabled(bool enabled) +{ + mEnabled = enabled; +} + enum Direction { D_Left, @@ -162,6 +171,9 @@ enum Direction bool KeyboardNavigation::injectKeyPress(MyGUI::KeyCode key, unsigned int text) { + if (!mEnabled) + return false; + switch (key.getValue()) { case MyGUI::KeyCode::ArrowLeft: diff --git a/apps/openmw/mwgui/keyboardnavigation.hpp b/apps/openmw/mwgui/keyboardnavigation.hpp index 728f16a3d..7caf25690 100644 --- a/apps/openmw/mwgui/keyboardnavigation.hpp +++ b/apps/openmw/mwgui/keyboardnavigation.hpp @@ -28,6 +28,8 @@ namespace MWGui void setModalWindow(MyGUI::Widget* window); + void setEnabled(bool enabled); + private: bool switchFocus(int direction, bool wrap); @@ -40,6 +42,8 @@ namespace MWGui MyGUI::Widget* mCurrentFocus; MyGUI::Widget* mModalWindow; + + bool mEnabled; }; } diff --git a/apps/openmw/mwgui/quickkeysmenu.cpp b/apps/openmw/mwgui/quickkeysmenu.cpp index 6da7b0905..2ce9d04e5 100644 --- a/apps/openmw/mwgui/quickkeysmenu.cpp +++ b/apps/openmw/mwgui/quickkeysmenu.cpp @@ -330,7 +330,12 @@ namespace MWGui MWMechanics::CreatureStats& stats = player.getClass().getCreatureStats(player); MWMechanics::Spells& spells = stats.getSpells(); if (!spells.hasSpell(spellId)) + { + const ESM::Spell* spell = MWBase::Environment::get().getWorld()->getStore().get().find(spellId); + MWBase::Environment::get().getWindowManager()->messageBox ( + "#{sQuickMenu5} " + spell->mName); return; + } store.setSelectedEnchantItem(store.end()); MWBase::Environment::get().getWindowManager()->setSelectedSpell(spellId, int(MWMechanics::getSpellSuccessChance(spellId, player))); MWBase::Environment::get().getWorld()->getPlayer().setDrawState(MWMechanics::DrawState_Spell); diff --git a/apps/openmw/mwgui/referenceinterface.cpp b/apps/openmw/mwgui/referenceinterface.cpp index 6213d9e25..83221c4f4 100644 --- a/apps/openmw/mwgui/referenceinterface.cpp +++ b/apps/openmw/mwgui/referenceinterface.cpp @@ -15,11 +15,8 @@ namespace MWGui // check if count of the reference has become 0 if (!mPtr.isEmpty() && mPtr.getRefData().getCount() == 0) { - if (!mPtr.isEmpty()) - { - mPtr = MWWorld::Ptr(); - onReferenceUnavailable(); - } + mPtr = MWWorld::Ptr(); + onReferenceUnavailable(); } } } diff --git a/apps/openmw/mwgui/sortfilteritemmodel.cpp b/apps/openmw/mwgui/sortfilteritemmodel.cpp index 1ee3cf631..097412b5d 100644 --- a/apps/openmw/mwgui/sortfilteritemmodel.cpp +++ b/apps/openmw/mwgui/sortfilteritemmodel.cpp @@ -208,7 +208,7 @@ namespace MWGui if ((mFilter & Filter_OnlyEnchanted) && !(item.mFlags & ItemStack::Flag_Enchanted)) return false; if ((mFilter & Filter_OnlyChargedSoulstones) && (base.getTypeName() != typeid(ESM::Miscellaneous).name() - || base.getCellRef().getSoul() == "")) + || base.getCellRef().getSoul() == "" || !MWBase::Environment::get().getWorld()->getStore().get().search(base.getCellRef().getSoul()))) return false; if ((mFilter & Filter_OnlyRepairTools) && (base.getTypeName() != typeid(ESM::Repair).name())) return false; diff --git a/apps/openmw/mwgui/travelwindow.cpp b/apps/openmw/mwgui/travelwindow.cpp index 7586bb66a..7b65eb771 100644 --- a/apps/openmw/mwgui/travelwindow.cpp +++ b/apps/openmw/mwgui/travelwindow.cpp @@ -4,6 +4,8 @@ #include #include +#include + #include "../mwbase/environment.hpp" #include "../mwbase/world.hpp" #include "../mwbase/windowmanager.hpp" @@ -72,7 +74,10 @@ namespace MWGui MWWorld::ActionTeleport::getFollowersToTeleport(player, followers); // Apply followers cost, in vanilla one follower travels for free - price *= std::max(1, static_cast(followers.size())); + if (Settings::Manager::getBool("charge for every follower travelling", "Game")) + price *= 1 + static_cast(followers.size()); + else + price *= std::max(1, static_cast(followers.size())); MyGUI::Button* toAdd = mDestinationsView->createWidget("SandTextButton", 0, mCurrentY, 200, sLineHeight, MyGUI::Align::Default); toAdd->setEnabled(price <= playerGold); diff --git a/apps/openmw/mwgui/widgets.cpp b/apps/openmw/mwgui/widgets.cpp index 45767bf01..024a91fc6 100644 --- a/apps/openmw/mwgui/widgets.cpp +++ b/apps/openmw/mwgui/widgets.cpp @@ -533,10 +533,10 @@ namespace MWGui } MWScrollBar::MWScrollBar() - : mEnableRepeat(true) - , mRepeatTriggerTime(0.5f) - , mRepeatStepTime(0.1f) - , mIsIncreasing(true) + : mEnableRepeat(true) + , mRepeatTriggerTime(0.5f) + , mRepeatStepTime(0.1f) + , mIsIncreasing(true) { #if MYGUI_VERSION >= MYGUI_DEFINE_VERSION(3,2,2) ScrollBar::setRepeatEnabled(false); diff --git a/apps/openmw/mwgui/windowbase.cpp b/apps/openmw/mwgui/windowbase.cpp index a0e7eedde..93440a50a 100644 --- a/apps/openmw/mwgui/windowbase.cpp +++ b/apps/openmw/mwgui/windowbase.cpp @@ -25,7 +25,7 @@ void WindowBase::setVisible(bool visible) if (visible) onOpen(); - else if (wasVisible && !visible) + else if (wasVisible) onClose(); // This is needed as invisible widgets can retain key focus. diff --git a/apps/openmw/mwgui/windowmanagerimp.cpp b/apps/openmw/mwgui/windowmanagerimp.cpp index 300f8e39f..c103f60ad 100644 --- a/apps/openmw/mwgui/windowmanagerimp.cpp +++ b/apps/openmw/mwgui/windowmanagerimp.cpp @@ -237,7 +237,10 @@ namespace MWGui MyGUI::FactoryManager::getInstance().registerFactory("Resource", "ResourceImageSetPointer"); MyGUI::ResourceManager::getInstance().load("core.xml"); + bool keyboardNav = Settings::Manager::getBool("keyboard navigation", "GUI"); mKeyboardNavigation.reset(new KeyboardNavigation()); + mKeyboardNavigation->setEnabled(keyboardNav); + Gui::ImageButton::setDefaultNeedKeyFocus(keyboardNav); mLoadingScreen = new LoadingScreen(mResourceSystem->getVFS(), mViewer); mWindows.push_back(mLoadingScreen); @@ -1916,11 +1919,16 @@ namespace MWGui mInventoryWindow->cycle(next); } - void WindowManager::playSound(const std::string& soundId, float volume, float pitch) + void WindowManager::playSound(const std::string& soundId, bool preventOverlapping, float volume, float pitch) { if (soundId.empty()) return; - MWBase::Environment::get().getSoundManager()->playSound(soundId, volume, pitch, MWSound::Type::Sfx, MWSound::PlayMode::NoEnv); + + MWBase::SoundManager *sndmgr = MWBase::Environment::get().getSoundManager(); + if (preventOverlapping && sndmgr->getSoundPlaying(MWWorld::Ptr(), soundId)) + return; + + sndmgr->playSound(soundId, volume, pitch, MWSound::Type::Sfx, MWSound::PlayMode::NoEnv); } void WindowManager::updateSpellWindow() diff --git a/apps/openmw/mwgui/windowmanagerimp.hpp b/apps/openmw/mwgui/windowmanagerimp.hpp index 1d250f6d4..56ccea33b 100644 --- a/apps/openmw/mwgui/windowmanagerimp.hpp +++ b/apps/openmw/mwgui/windowmanagerimp.hpp @@ -366,7 +366,7 @@ namespace MWGui /// Cycle to next or previous weapon virtual void cycleWeapon(bool next); - virtual void playSound(const std::string& soundId, float volume = 1.f, float pitch = 1.f); + virtual void playSound(const std::string& soundId, bool preventOverlapping = false, float volume = 1.f, float pitch = 1.f); // In WindowManager for now since there isn't a VFS singleton virtual std::string correctIconPath(const std::string& path); diff --git a/apps/openmw/mwinput/inputmanagerimp.cpp b/apps/openmw/mwinput/inputmanagerimp.cpp index 3b4ff25a0..507e97a6a 100644 --- a/apps/openmw/mwinput/inputmanagerimp.cpp +++ b/apps/openmw/mwinput/inputmanagerimp.cpp @@ -524,30 +524,29 @@ namespace MWInput isRunning = xAxis > .75 || xAxis < .25 || yAxis > .75 || yAxis < .25; if(triedToMove) resetIdleTime(); - if (actionIsActive(A_MoveLeft)) + if (actionIsActive(A_MoveLeft) && !actionIsActive(A_MoveRight)) { triedToMove = true; mPlayer->setLeftRight (-1); } - else if (actionIsActive(A_MoveRight)) + else if (actionIsActive(A_MoveRight) && !actionIsActive(A_MoveLeft)) { triedToMove = true; mPlayer->setLeftRight (1); } - if (actionIsActive(A_MoveForward)) + if (actionIsActive(A_MoveForward) && !actionIsActive(A_MoveBackward)) { triedToMove = true; mPlayer->setAutoMove (false); mPlayer->setForwardBackward (1); } - else if (actionIsActive(A_MoveBackward)) + else if (actionIsActive(A_MoveBackward) && !actionIsActive(A_MoveForward)) { triedToMove = true; mPlayer->setAutoMove (false); mPlayer->setForwardBackward (-1); } - else if(mPlayer->getAutoMove()) { triedToMove = true; diff --git a/apps/openmw/mwmechanics/actors.cpp b/apps/openmw/mwmechanics/actors.cpp index 7a1e7270d..7990373a7 100644 --- a/apps/openmw/mwmechanics/actors.cpp +++ b/apps/openmw/mwmechanics/actors.cpp @@ -391,7 +391,7 @@ namespace MWMechanics { // Player followers and escorters with high fight should not initiate combat with the player or with // other player followers or escorters - if (std::find(playerAllies.begin(), playerAllies.end(), actor1) == playerAllies.end()) + if (!isPlayerFollowerOrEscorter) aggressive = MWBase::Environment::get().getMechanicsManager()->isAggressive(actor1, actor2); } } @@ -900,7 +900,7 @@ namespace MWMechanics stats.setTimeToStartDrowning(fHoldBreathTime); } - void Actors::updateEquippedLight (const MWWorld::Ptr& ptr, float duration) + void Actors::updateEquippedLight (const MWWorld::Ptr& ptr, float duration, bool mayEquip) { bool isPlayer = (ptr == getPlayer()); @@ -922,7 +922,7 @@ namespace MWMechanics } } - if (MWBase::Environment::get().getWorld()->isDark()) + if (mayEquip) { if (torch != inventoryStore.end()) { @@ -931,16 +931,11 @@ namespace MWMechanics // For non-hostile NPCs, unequip whatever is in the left slot in favor of a light. if (heldIter != inventoryStore.end() && heldIter->getTypeName() != typeid(ESM::Light).name()) inventoryStore.unequipItem(*heldIter, ptr); - - // Also unequip twohanded weapons which conflict with anything in CarriedLeft - if (torch->getClass().canBeEquipped(*torch, ptr).first == 3) - inventoryStore.unequipSlot(MWWorld::InventoryStore::Slot_CarriedRight, ptr); } heldIter = inventoryStore.getSlot(MWWorld::InventoryStore::Slot_CarriedLeft); - // If we have a torch and can equip it (left slot free, no - // twohanded weapon in right slot), then equip it now. + // If we have a torch and can equip it, then equip it now. if (heldIter == inventoryStore.end() && torch->getClass().canBeEquipped(*torch, ptr).first == 1) { @@ -997,7 +992,7 @@ namespace MWMechanics } } - void Actors::updateCrimePersuit(const MWWorld::Ptr& ptr, float duration) + void Actors::updateCrimePursuit(const MWWorld::Ptr& ptr, float duration) { MWWorld::Ptr player = getPlayer(); if (ptr != player && ptr.getClass().isNpc()) @@ -1204,6 +1199,9 @@ namespace MWMechanics if (mTimerDisposeSummonsCorpses >= 0.2f) mTimerDisposeSummonsCorpses = 0; if (timerUpdateEquippedLight >= updateEquippedLightInterval) timerUpdateEquippedLight = 0; + // show torches only when there are darkness and no precipitations + bool showTorches = MWBase::Environment::get().getWorld()->useTorches(); + MWWorld::Ptr player = getPlayer(); /// \todo move update logic to Actor class where appropriate @@ -1287,7 +1285,7 @@ namespace MWMechanics } if (iter->first.getClass().isNpc() && iter->first != player) - updateCrimePersuit(iter->first, duration); + updateCrimePursuit(iter->first, duration); if (iter->first != player) { @@ -1302,7 +1300,7 @@ namespace MWMechanics updateNpc(iter->first, duration); if (timerUpdateEquippedLight == 0) - updateEquippedLight(iter->first, updateEquippedLightInterval); + updateEquippedLight(iter->first, updateEquippedLightInterval, showTorches); } } } @@ -1424,7 +1422,7 @@ namespace MWMechanics MWBase::Environment::get().getWindowManager()->setSneakVisibility(false); break; } - else if (!detected) + else avoidedNotice = true; } } diff --git a/apps/openmw/mwmechanics/actors.hpp b/apps/openmw/mwmechanics/actors.hpp index 13641abf4..15f2d3dc8 100644 --- a/apps/openmw/mwmechanics/actors.hpp +++ b/apps/openmw/mwmechanics/actors.hpp @@ -39,9 +39,9 @@ namespace MWMechanics void updateDrowning (const MWWorld::Ptr& ptr, float duration); - void updateEquippedLight (const MWWorld::Ptr& ptr, float duration); + void updateEquippedLight (const MWWorld::Ptr& ptr, float duration, bool mayEquip); - void updateCrimePersuit (const MWWorld::Ptr& ptr, float duration); + void updateCrimePursuit (const MWWorld::Ptr& ptr, float duration); void killDeadActors (); diff --git a/apps/openmw/mwmechanics/aipackage.cpp b/apps/openmw/mwmechanics/aipackage.cpp index 398e84448..38f641b94 100644 --- a/apps/openmw/mwmechanics/aipackage.cpp +++ b/apps/openmw/mwmechanics/aipackage.cpp @@ -189,7 +189,7 @@ void MWMechanics::AiPackage::evadeObstacles(const MWWorld::Ptr& actor, float dur static float distance = MWBase::Environment::get().getWorld()->getMaxActivationDistance(); MWWorld::Ptr door = getNearbyDoor(actor, distance); - if (door != MWWorld::Ptr()) + if (door != MWWorld::Ptr() && actor.getClass().isBipedal(actor)) { // note: AiWander currently does not open doors if (getTypeId() != TypeIdWander && !door.getCellRef().getTeleport() && door.getClass().getDoorState(door) == 0) @@ -224,7 +224,7 @@ void MWMechanics::AiPackage::evadeObstacles(const MWWorld::Ptr& actor, float dur MWBase::Environment::get().getWorld()->activate(door, actor); } } - else // any other obstacle (NPC, crate, etc.) + else { mObstacleCheck.takeEvasiveAction(movement); } diff --git a/apps/openmw/mwmechanics/character.cpp b/apps/openmw/mwmechanics/character.cpp index 676f01922..2ef5e07d7 100644 --- a/apps/openmw/mwmechanics/character.cpp +++ b/apps/openmw/mwmechanics/character.cpp @@ -14,7 +14,7 @@ * * You should have received a copy of the GNU General Public License * version 3 along with this program. If not, see - * http://www.gnu.org/licenses/ . + * https://www.gnu.org/licenses/ . */ #include "character.hpp" @@ -286,7 +286,7 @@ void CharacterController::refreshHitRecoilAnims() } else if (recovery) { - std::string anim = isSwimming ? chooseRandomGroup("swimhit") : chooseRandomGroup("hit"); + std::string anim = chooseRandomGroup("swimhit"); if (isSwimming && mAnimation->hasAnimation(anim)) { mHitState = CharState_SwimHit; @@ -517,8 +517,7 @@ void CharacterController::refreshMovementAnims(const WeaponInfo* weap, Character void CharacterController::refreshIdleAnims(const WeaponInfo* weap, CharacterState idle, bool force) { - if(force || idle != mIdleState || - ((idle == mIdleState) && !mAnimation->isPlaying(mCurrentIdle) && mAnimQueue.empty())) + if(force || idle != mIdleState || (!mAnimation->isPlaying(mCurrentIdle) && mAnimQueue.empty())) { mIdleState = idle; size_t numLoops = ~0ul; @@ -1189,7 +1188,7 @@ bool CharacterController::updateWeaponState() std::string weapgroup; if(weaptype == WeapType_None) { - if ((!isWerewolf || mWeaponType != WeapType_Spell)) + if (!isWerewolf || mWeaponType != WeapType_Spell) { getWeaponGroup(mWeaponType, weapgroup); mAnimation->play(weapgroup, priorityWeapon, @@ -2152,7 +2151,7 @@ bool CharacterController::playGroup(const std::string &groupname, int mode, int MWRender::Animation::BlendMask_All, false, 1.0f, ((mode==2) ? "loop start" : "start"), "stop", 0.0f, count-1, loopfallback); } - else if(mode == 0) + else { mAnimQueue.resize(1); mAnimQueue.push_back(entry); diff --git a/apps/openmw/mwmechanics/combat.cpp b/apps/openmw/mwmechanics/combat.cpp index 13cd4232d..ac34c658b 100644 --- a/apps/openmw/mwmechanics/combat.cpp +++ b/apps/openmw/mwmechanics/combat.cpp @@ -1,6 +1,7 @@ #include "combat.hpp" #include +#include #include @@ -155,7 +156,11 @@ namespace MWMechanics if (!(weapon.get()->mBase->mData.mFlags & ESM::Weapon::Silver || weapon.get()->mBase->mData.mFlags & ESM::Weapon::Magical)) - damage *= multiplier; + { + if (weapon.getClass().getEnchantment(weapon).empty() + || !Settings::Manager::getBool("enchanted weapons are magical", "Game")) + damage *= multiplier; + } if ((weapon.get()->mBase->mData.mFlags & ESM::Weapon::Silver) && actor.getClass().isNpc() && actor.getClass().getNpcStats(actor).isWerewolf()) diff --git a/apps/openmw/mwmechanics/enchanting.cpp b/apps/openmw/mwmechanics/enchanting.cpp index a658c379a..08f30aba1 100644 --- a/apps/openmw/mwmechanics/enchanting.cpp +++ b/apps/openmw/mwmechanics/enchanting.cpp @@ -242,8 +242,11 @@ namespace MWMechanics return 0; if(mSoulGemPtr.getCellRef().getSoul()=="") return 0; - const ESM::Creature* soul = store.get().find(mSoulGemPtr.getCellRef().getSoul()); - return soul->mData.mSoul; + const ESM::Creature* soul = store.get().search(mSoulGemPtr.getCellRef().getSoul()); + if(soul) + return soul->mData.mSoul; + else + return 0; } int Enchanting::getMaxEnchantValue() const diff --git a/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp b/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp index bd5fa1b11..df93d875d 100644 --- a/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp +++ b/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp @@ -79,21 +79,21 @@ namespace MWMechanics const ESM::NPC *player = ptr.get()->mBase; // reset - creatureStats.setLevel(player->mNpdt52.mLevel); + creatureStats.setLevel(player->mNpdt.mLevel); creatureStats.getSpells().clear(); creatureStats.modifyMagicEffects(MagicEffects()); for (int i=0; i<27; ++i) - npcStats.getSkill (i).setBase (player->mNpdt52.mSkills[i]); - - creatureStats.setAttribute(ESM::Attribute::Strength, player->mNpdt52.mStrength); - creatureStats.setAttribute(ESM::Attribute::Intelligence, player->mNpdt52.mIntelligence); - creatureStats.setAttribute(ESM::Attribute::Willpower, player->mNpdt52.mWillpower); - creatureStats.setAttribute(ESM::Attribute::Agility, player->mNpdt52.mAgility); - creatureStats.setAttribute(ESM::Attribute::Speed, player->mNpdt52.mSpeed); - creatureStats.setAttribute(ESM::Attribute::Endurance, player->mNpdt52.mEndurance); - creatureStats.setAttribute(ESM::Attribute::Personality, player->mNpdt52.mPersonality); - creatureStats.setAttribute(ESM::Attribute::Luck, player->mNpdt52.mLuck); + npcStats.getSkill (i).setBase (player->mNpdt.mSkills[i]); + + creatureStats.setAttribute(ESM::Attribute::Strength, player->mNpdt.mStrength); + creatureStats.setAttribute(ESM::Attribute::Intelligence, player->mNpdt.mIntelligence); + creatureStats.setAttribute(ESM::Attribute::Willpower, player->mNpdt.mWillpower); + creatureStats.setAttribute(ESM::Attribute::Agility, player->mNpdt.mAgility); + creatureStats.setAttribute(ESM::Attribute::Speed, player->mNpdt.mSpeed); + creatureStats.setAttribute(ESM::Attribute::Endurance, player->mNpdt.mEndurance); + creatureStats.setAttribute(ESM::Attribute::Personality, player->mNpdt.mPersonality); + creatureStats.setAttribute(ESM::Attribute::Luck, player->mNpdt.mLuck); const MWWorld::ESMStore &esmStore = MWBase::Environment::get().getWorld()->getStore(); @@ -1118,8 +1118,11 @@ namespace MWMechanics Misc::StringUtils::lowerCaseInPlace(owner.first); if (!Misc::StringUtils::ciEqual(item.getCellRef().getRefId(), MWWorld::ContainerStore::sGoldId)) - mStolenItems[Misc::StringUtils::lowerCase(item.getCellRef().getRefId())][owner] += count; - + { + const MWWorld::Ptr victimRef = MWBase::Environment::get().getWorld()->searchPtr(ownerCellRef->getOwner(), true); + if (victimRef.isEmpty() || !victimRef.getClass().getCreatureStats(victimRef).isDead()) + mStolenItems[Misc::StringUtils::lowerCase(item.getCellRef().getRefId())][owner] += count; + } if (alarm) commitCrime(ptr, victim, OT_Theft, item.getClass().getValue(item) * count); } @@ -1442,7 +1445,20 @@ namespace MWMechanics // Attacker is in combat with us, but we are not in combat with the attacker yet. Time to fight back. // Note: accidental or collateral damage attacks are ignored. if (!target.getClass().getCreatureStats(target).getAiSequence().hasPackage(AiPackage::TypeIdPursue)) - startCombat(target, attacker); + { + // If an actor has OnPCHitMe declared in his script, his Fight = 0 and the attacker is player, + // he will attack the player only if we will force him (e.g. via StartCombat console command) + bool peaceful = false; + std::string script = target.getClass().getScript(target); + if (!script.empty() && target.getRefData().getLocals().hasVar(script, "onpchitme") && attacker == getPlayer()) + { + int fight = std::max(0, target.getClass().getCreatureStats(target).getAiSetting(CreatureStats::AI_Fight).getModified()); + peaceful = (fight == 0); + } + + if (!peaceful) + startCombat(target, attacker); + } } return true; @@ -1719,11 +1735,11 @@ namespace MWMechanics { if (werewolf) { - player->saveSkillsAttributes(); - player->setWerewolfSkillsAttributes(); + player->saveStats(); + player->setWerewolfStats(); } else - player->restoreSkillsAttributes(); + player->restoreStats(); } // Werewolfs can not cast spells, so we need to unset the prepared spell if there is one. diff --git a/apps/openmw/mwmechanics/npcstats.cpp b/apps/openmw/mwmechanics/npcstats.cpp index f0fc7fb6e..f15152759 100644 --- a/apps/openmw/mwmechanics/npcstats.cpp +++ b/apps/openmw/mwmechanics/npcstats.cpp @@ -214,7 +214,7 @@ void MWMechanics::NpcStats::useSkill (int skillIndex, const ESM::Class& class_, } } -void MWMechanics::NpcStats::increaseSkill(int skillIndex, const ESM::Class &class_, bool preserveProgress) +void MWMechanics::NpcStats::increaseSkill(int skillIndex, const ESM::Class &class_, bool preserveProgress, bool readBook) { int base = getSkill (skillIndex).getBase(); @@ -256,9 +256,14 @@ void MWMechanics::NpcStats::increaseSkill(int skillIndex, const ESM::Class &clas MWBase::Environment::get().getWindowManager()->playSound("skillraise"); std::stringstream message; + + if (readBook) + message << std::string("#{sBookSkillMessage}\n"); + message << boost::format(MWBase::Environment::get().getWindowManager ()->getGameSettingString ("sNotifyMessage39", "")) % std::string("#{" + ESM::Skill::sSkillNameIds[skillIndex] + "}") % static_cast (base); + MWBase::Environment::get().getWindowManager ()->messageBox(message.str(), MWGui::ShowInDialogueMode_Never); if (mLevelProgress >= gmst.find("iLevelUpTotal")->getInt()) diff --git a/apps/openmw/mwmechanics/npcstats.hpp b/apps/openmw/mwmechanics/npcstats.hpp index 9ded47c07..d2e42e994 100644 --- a/apps/openmw/mwmechanics/npcstats.hpp +++ b/apps/openmw/mwmechanics/npcstats.hpp @@ -81,7 +81,7 @@ namespace MWMechanics void useSkill (int skillIndex, const ESM::Class& class_, int usageType = -1, float extraFactor=1.f); ///< Increase skill by usage. - void increaseSkill (int skillIndex, const ESM::Class& class_, bool preserveProgress); + void increaseSkill (int skillIndex, const ESM::Class& class_, bool preserveProgress, bool readBook = false); int getLevelProgress() const; diff --git a/apps/openmw/mwmechanics/pathfinding.cpp b/apps/openmw/mwmechanics/pathfinding.cpp index 1dccb6c9a..0591667b7 100644 --- a/apps/openmw/mwmechanics/pathfinding.cpp +++ b/apps/openmw/mwmechanics/pathfinding.cpp @@ -316,7 +316,7 @@ namespace MWMechanics buildPath(startPoint, endPoint, cell, pathgridGraph); if (mPath.size() >= 2) { - // if 2nd waypoint of new path == 1st waypoint of old, + // if 2nd waypoint of new path == 1st waypoint of old, // delete 1st waypoint of new path. std::list::iterator iter = ++mPath.begin(); if (iter->mX == oldStart.mX diff --git a/apps/openmw/mwmechanics/pathgrid.cpp b/apps/openmw/mwmechanics/pathgrid.cpp index c0122a861..ea4c973b7 100644 --- a/apps/openmw/mwmechanics/pathgrid.cpp +++ b/apps/openmw/mwmechanics/pathgrid.cpp @@ -8,7 +8,7 @@ namespace { - // See http://theory.stanford.edu/~amitp/GameProgramming/Heuristics.html + // See https://theory.stanford.edu/~amitp/GameProgramming/Heuristics.html // // One of the smallest cost in Seyda Neen is between points 77 & 78: // pt x y diff --git a/apps/openmw/mwmechanics/spellcasting.cpp b/apps/openmw/mwmechanics/spellcasting.cpp index d864dc619..7570cb9ba 100644 --- a/apps/openmw/mwmechanics/spellcasting.cpp +++ b/apps/openmw/mwmechanics/spellcasting.cpp @@ -7,6 +7,7 @@ #include #include +#include #include "../mwbase/windowmanager.hpp" #include "../mwbase/soundmanager.hpp" @@ -24,7 +25,6 @@ #include "../mwrender/animation.hpp" -#include "magiceffects.hpp" #include "npcstats.hpp" #include "actorutil.hpp" #include "aifollow.hpp" @@ -489,6 +489,9 @@ namespace MWMechanics MWBase::Environment::get().getWindowManager()->messageBox("#{sMagicTargetResisted}"); } + if (target == getPlayer() && MWBase::Environment::get().getWorld()->getGodModeState()) + magnitudeMult = 0; + // If player is attempting to cast a harmful spell, show the target's HP bar if (castByPlayer && target != caster) MWBase::Environment::get().getWindowManager()->setEnemy(target); @@ -567,9 +570,12 @@ namespace MWMechanics ActiveSpells::ActiveEffect effect_ = effect; effect_.mMagnitude *= -1; absorbEffects.push_back(effect_); - // Also make sure to set casterActorId = target, so that the effect on the caster gets purged when the target dies - caster.getClass().getCreatureStats(caster).getActiveSpells().addSpell("", true, - absorbEffects, mSourceName, target.getClass().getCreatureStats(target).getActorId()); + if (reflected && Settings::Manager::getBool("classic reflect absorb attribute behavior", "Game")) + target.getClass().getCreatureStats(target).getActiveSpells().addSpell("", true, + absorbEffects, mSourceName, caster.getClass().getCreatureStats(caster).getActorId()); + else + caster.getClass().getCreatureStats(caster).getActiveSpells().addSpell("", true, + absorbEffects, mSourceName, target.getClass().getCreatureStats(target).getActorId()); } } } @@ -609,7 +615,6 @@ namespace MWMechanics std::string texture = magicEffect->mParticle; - // TODO: VFX are no longer active after saving/reloading the game 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); @@ -877,20 +882,18 @@ namespace MWMechanics const float normalizedEncumbrance = mCaster.getClass().getNormalizedEncumbrance(mCaster); float fatigueLoss = spell->mData.mCost * (fFatigueSpellBase + normalizedEncumbrance * fFatigueSpellMult); - fatigue.setCurrent(fatigue.getCurrent() - fatigueLoss); stats.setFatigue(fatigue); + fatigue.setCurrent(fatigue.getCurrent() - fatigueLoss); + stats.setFatigue(fatigue); bool fail = false; // Check success - if (!(mCaster == getPlayer() && MWBase::Environment::get().getWorld()->getGodModeState())) + float successChance = getSpellSuccessChance(spell, mCaster); + if (Misc::Rng::roll0to99() >= successChance) { - float successChance = getSpellSuccessChance(spell, mCaster); - if (Misc::Rng::roll0to99() >= successChance) - { - if (mCaster == getPlayer()) - MWBase::Environment::get().getWindowManager()->messageBox("#{sMagicSkillFail}"); - fail = true; - } + if (mCaster == getPlayer()) + MWBase::Environment::get().getWindowManager()->messageBox("#{sMagicSkillFail}"); + fail = true; } if (fail) @@ -1111,8 +1114,6 @@ namespace MWMechanics bool receivedMagicDamage = false; - bool godmode = actor == MWMechanics::getPlayer() && MWBase::Environment::get().getWorld()->getGodModeState(); - switch (effectKey.mId) { case ESM::MagicEffect::DamageAttribute: @@ -1135,40 +1136,25 @@ namespace MWMechanics adjustDynamicStat(creatureStats, effectKey.mId-ESM::MagicEffect::RestoreHealth, magnitude); break; case ESM::MagicEffect::DamageHealth: - if (!godmode) - { - receivedMagicDamage = true; - adjustDynamicStat(creatureStats, effectKey.mId-ESM::MagicEffect::DamageHealth, -magnitude); - } - + receivedMagicDamage = true; + adjustDynamicStat(creatureStats, effectKey.mId-ESM::MagicEffect::DamageHealth, -magnitude); break; case ESM::MagicEffect::DamageMagicka: case ESM::MagicEffect::DamageFatigue: - if (!godmode) - { - adjustDynamicStat(creatureStats, effectKey.mId-ESM::MagicEffect::DamageHealth, -magnitude); - } - + adjustDynamicStat(creatureStats, effectKey.mId-ESM::MagicEffect::DamageHealth, -magnitude); break; case ESM::MagicEffect::AbsorbHealth: - if (!godmode) - { - if (magnitude > 0.f) - receivedMagicDamage = true; - adjustDynamicStat(creatureStats, effectKey.mId-ESM::MagicEffect::AbsorbHealth, -magnitude); - } + if (magnitude > 0.f) + receivedMagicDamage = true; + adjustDynamicStat(creatureStats, effectKey.mId-ESM::MagicEffect::AbsorbHealth, -magnitude); break; case ESM::MagicEffect::AbsorbMagicka: case ESM::MagicEffect::AbsorbFatigue: - if (!godmode) - { - adjustDynamicStat(creatureStats, effectKey.mId-ESM::MagicEffect::AbsorbHealth, -magnitude); - } - + adjustDynamicStat(creatureStats, effectKey.mId-ESM::MagicEffect::AbsorbHealth, -magnitude); break; case ESM::MagicEffect::DisintegrateArmor: @@ -1191,6 +1177,7 @@ namespace MWMechanics if (disintegrateSlot(actor, priorities[i], magnitude)) break; } + break; } case ESM::MagicEffect::DisintegrateWeapon: @@ -1213,12 +1200,9 @@ namespace MWMechanics if (weather > 1) damageScale *= fMagicSunBlockedMult; - if (!godmode) - { - adjustDynamicStat(creatureStats, 0, -magnitude * damageScale); - if (magnitude * damageScale > 0.f) - receivedMagicDamage = true; - } + adjustDynamicStat(creatureStats, 0, -magnitude * damageScale); + if (magnitude * damageScale > 0.f) + receivedMagicDamage = true; break; } @@ -1228,12 +1212,8 @@ namespace MWMechanics case ESM::MagicEffect::FrostDamage: case ESM::MagicEffect::Poison: { - if (!godmode) - { - adjustDynamicStat(creatureStats, 0, -magnitude); - receivedMagicDamage = true; - } - + adjustDynamicStat(creatureStats, 0, -magnitude); + receivedMagicDamage = true; break; } @@ -1314,4 +1294,24 @@ namespace MWMechanics return MWBase::Environment::get().getWorld()->getStore().get().find(it->second)->getString(); } + void ApplyLoopingParticlesVisitor::visit (MWMechanics::EffectKey key, + const std::string& /*sourceName*/, const std::string& /*sourceId*/, int /*casterActorId*/, + float /*magnitude*/, float /*remainingTime*/, float /*totalTime*/) + { + const ESM::MagicEffect *magicEffect = + MWBase::Environment::get().getWorld()->getStore().get().find(key.mId); + + const ESM::Static* castStatic; + if (!magicEffect->mHit.empty()) + castStatic = MWBase::Environment::get().getWorld()->getStore().get().find (magicEffect->mHit); + else + castStatic = MWBase::Environment::get().getWorld()->getStore().get().find ("VFX_DefaultHit"); + + std::string texture = magicEffect->mParticle; + + bool loop = (magicEffect->mData.mFlags & ESM::MagicEffect::ContinuousVfx) != 0; + MWRender::Animation* anim = MWBase::Environment::get().getWorld()->getAnimation(mActor); + if (anim && loop) + anim->addEffect("meshes\\" + castStatic->mModel, magicEffect->mIndex, loop, "", texture); + } } diff --git a/apps/openmw/mwmechanics/spellcasting.hpp b/apps/openmw/mwmechanics/spellcasting.hpp index 1f5ef45bd..07c5b8477 100644 --- a/apps/openmw/mwmechanics/spellcasting.hpp +++ b/apps/openmw/mwmechanics/spellcasting.hpp @@ -6,6 +6,8 @@ #include "../mwworld/ptr.hpp" +#include "magiceffects.hpp" + namespace ESM { struct Spell; @@ -119,6 +121,21 @@ namespace MWMechanics bool applyInstantEffect (const MWWorld::Ptr& target, const MWWorld::Ptr& caster, const MWMechanics::EffectKey& effect, float magnitude); }; + class ApplyLoopingParticlesVisitor : public EffectSourceVisitor + { + private: + MWWorld::Ptr mActor; + + public: + ApplyLoopingParticlesVisitor(const MWWorld::Ptr& actor) + : mActor(actor) + { + } + + virtual void visit (MWMechanics::EffectKey key, + const std::string& /*sourceName*/, const std::string& /*sourceId*/, int /*casterActorId*/, + float /*magnitude*/, float /*remainingTime*/ = -1, float /*totalTime*/ = -1); + }; } #endif diff --git a/apps/openmw/mwphysics/physicssystem.cpp b/apps/openmw/mwphysics/physicssystem.cpp index 174560e6b..f3c34bc4e 100644 --- a/apps/openmw/mwphysics/physicssystem.cpp +++ b/apps/openmw/mwphysics/physicssystem.cpp @@ -13,7 +13,6 @@ #include #include #include -#include #include #include diff --git a/apps/openmw/mwrender/characterpreview.cpp b/apps/openmw/mwrender/characterpreview.cpp index 63fe32dfe..8d8c4e0d1 100644 --- a/apps/openmw/mwrender/characterpreview.cpp +++ b/apps/openmw/mwrender/characterpreview.cpp @@ -1,5 +1,6 @@ #include "characterpreview.hpp" +#include #include #include @@ -13,6 +14,7 @@ #include #include +#include #include #include @@ -161,14 +163,25 @@ namespace MWRender stateset->setAttributeAndModes(fog, osg::StateAttribute::OFF|osg::StateAttribute::OVERRIDE); osg::ref_ptr lightmodel = new osg::LightModel; - lightmodel->setAmbientIntensity(osg::Vec4(0.25, 0.25, 0.25, 1.0)); + lightmodel->setAmbientIntensity(osg::Vec4(0.0, 0.0, 0.0, 1.0)); stateset->setAttributeAndModes(lightmodel, osg::StateAttribute::ON); - /// \todo Read the fallback values from INIImporter (Inventory:Directional*) ? osg::ref_ptr light = new osg::Light; - light->setPosition(osg::Vec4(-0.3,0.3,0.7, 0.0)); - light->setDiffuse(osg::Vec4(1,1,1,1)); - light->setAmbient(osg::Vec4(0,0,0,1)); + const Fallback::Map* fallback = MWBase::Environment::get().getWorld()->getFallback(); + float diffuseR = fallback->getFallbackFloat("Inventory_DirectionalDiffuseR"); + float diffuseG = fallback->getFallbackFloat("Inventory_DirectionalDiffuseG"); + float diffuseB = fallback->getFallbackFloat("Inventory_DirectionalDiffuseB"); + float ambientR = fallback->getFallbackFloat("Inventory_DirectionalAmbientR"); + float ambientG = fallback->getFallbackFloat("Inventory_DirectionalAmbientG"); + float ambientB = fallback->getFallbackFloat("Inventory_DirectionalAmbientB"); + float azimuth = osg::DegreesToRadians(180.f - fallback->getFallbackFloat("Inventory_DirectionalRotationX")); + float altitude = osg::DegreesToRadians(fallback->getFallbackFloat("Inventory_DirectionalRotationY")); + float positionX = std::cos(azimuth) * std::sin(altitude); + float positionY = std::sin(azimuth) * std::sin(altitude); + float positionZ = std::cos(altitude); + light->setPosition(osg::Vec4(positionX,positionY,positionZ, 0.0)); + light->setDiffuse(osg::Vec4(diffuseR,diffuseG,diffuseB,1)); + light->setAmbient(osg::Vec4(ambientR,ambientG,ambientB,1)); light->setSpecular(osg::Vec4(0,0,0,0)); light->setLightNum(0); light->setConstantAttenuation(1.f); diff --git a/apps/openmw/mwrender/localmap.cpp b/apps/openmw/mwrender/localmap.cpp index 70d7a1dbe..fb8d716c8 100644 --- a/apps/openmw/mwrender/localmap.cpp +++ b/apps/openmw/mwrender/localmap.cpp @@ -8,6 +8,7 @@ #include #include #include +#include #include @@ -175,6 +176,7 @@ osg::ref_ptr LocalMap::createOrthographicCamera(float x, float y, f camera->setNodeMask(Mask_RenderToTexture); osg::ref_ptr stateset = new osg::StateSet; + stateset->setAttribute(new osg::PolygonMode(osg::PolygonMode::FRONT_AND_BACK, osg::PolygonMode::FILL), osg::StateAttribute::OVERRIDE); // assign large value to effectively turn off fog // shaders don't respect glDisable(GL_FOG) diff --git a/apps/openmw/mwrender/renderingmanager.cpp b/apps/openmw/mwrender/renderingmanager.cpp index bc414401f..9570f074e 100644 --- a/apps/openmw/mwrender/renderingmanager.cpp +++ b/apps/openmw/mwrender/renderingmanager.cpp @@ -52,6 +52,16 @@ #include "terrainstorage.hpp" #include "util.hpp" +namespace +{ + float DLLandFogStart; + float DLLandFogEnd; + float DLUnderwaterFogStart; + float DLUnderwaterFogEnd; + float DLInteriorFogStart; + float DLInteriorFogEnd; +} + namespace MWRender { @@ -174,14 +184,18 @@ namespace MWRender , mResourceSystem(resourceSystem) , mWorkQueue(workQueue) , mUnrefQueue(new SceneUtil::UnrefQueue) - , mFogDepth(0.f) + , mLandFogStart(0.f) + , mLandFogEnd(std::numeric_limits::max()) + , mUnderwaterFogStart(0.f) + , mUnderwaterFogEnd(std::numeric_limits::max()) , mUnderwaterColor(fallback->getFallbackColour("Water_UnderwaterColor")) , mUnderwaterWeight(fallback->getFallbackFloat("Water_UnderwaterColorWeight")) - , mUnderwaterFog(0.f) , mUnderwaterIndoorFog(fallback->getFallbackFloat("Water_UnderwaterIndoorFog")) , mNightEyeFactor(0.f) - , mFieldOfViewOverride(0.f) + , mDistantFog(false) + , mDistantTerrain(false) , mFieldOfViewOverridden(false) + , mFieldOfViewOverride(0.f) { resourceSystem->getSceneManager()->setParticleSystemMask(MWRender::Mask_ParticleSystem); @@ -239,12 +253,20 @@ namespace MWRender mWater.reset(new Water(mRootNode, sceneRoot, mResourceSystem, mViewer->getIncrementalCompileOperation(), fallback, resourcePath)); - const bool distantTerrain = Settings::Manager::getBool("distant terrain", "Terrain"); + DLLandFogStart = Settings::Manager::getFloat("distant land fog start", "Fog"); + DLLandFogEnd = Settings::Manager::getFloat("distant land fog end", "Fog"); + DLUnderwaterFogStart = Settings::Manager::getFloat("distant underwater fog start", "Fog"); + DLUnderwaterFogEnd = Settings::Manager::getFloat("distant underwater fog end", "Fog"); + DLInteriorFogStart = Settings::Manager::getFloat("distant interior fog start", "Fog"); + DLInteriorFogEnd = Settings::Manager::getFloat("distant interior fog end", "Fog"); + + mDistantFog = Settings::Manager::getBool("use distant fog", "Fog"); + mDistantTerrain = Settings::Manager::getBool("distant terrain", "Terrain"); mTerrainStorage = new TerrainStorage(mResourceSystem, Settings::Manager::getString("normal map pattern", "Shaders"), Settings::Manager::getString("normal height map pattern", "Shaders"), - Settings::Manager::getBool("auto use terrain normal maps", "Shaders"), Settings::Manager::getString("terrain specular map pattern", "Shaders"), + Settings::Manager::getBool("auto use terrain normal maps", "Shaders"), Settings::Manager::getString("terrain specular map pattern", "Shaders"), Settings::Manager::getBool("auto use terrain specular maps", "Shaders")); - if (distantTerrain) + if (mDistantTerrain) mTerrain.reset(new Terrain::QuadTreeWorld(sceneRoot, mRootNode, mResourceSystem, mTerrainStorage, Mask_Terrain, Mask_PreCompile)); else mTerrain.reset(new Terrain::TerrainGrid(sceneRoot, mRootNode, mResourceSystem, mTerrainStorage, Mask_Terrain, Mask_PreCompile)); @@ -506,14 +528,44 @@ namespace MWRender { osg::Vec4f color = SceneUtil::colourFromRGB(cell->mAmbi.mFog); - configureFog (cell->mAmbi.mFogDensity, mUnderwaterIndoorFog, color); + if(mDistantFog) + { + float density = std::max(0.2f, cell->mAmbi.mFogDensity); + mLandFogStart = (DLInteriorFogEnd*(1.0f-density) + DLInteriorFogStart*density); + mLandFogEnd = DLInteriorFogEnd; + mUnderwaterFogStart = DLUnderwaterFogStart; + mUnderwaterFogEnd = DLUnderwaterFogEnd; + mFogColor = color; + } + else + configureFog(cell->mAmbi.mFogDensity, mUnderwaterIndoorFog, 1.0f, 0.0f, color); } - void RenderingManager::configureFog(float fogDepth, float underwaterFog, const osg::Vec4f &color) + void RenderingManager::configureFog(float fogDepth, float underwaterFog, float dlFactor, float dlOffset, const osg::Vec4f &color) { - mFogDepth = fogDepth; + if(mDistantFog) + { + mLandFogStart = dlFactor * (DLLandFogStart - dlOffset*DLLandFogEnd); + mLandFogEnd = dlFactor * (1.0f-dlOffset) * DLLandFogEnd; + mUnderwaterFogStart = DLUnderwaterFogStart; + mUnderwaterFogEnd = DLUnderwaterFogEnd; + } + else + { + if(fogDepth == 0.0) + { + mLandFogStart = 0.0f; + mLandFogEnd = std::numeric_limits::max(); + } + else + { + mLandFogStart = mViewDistance * (1 - fogDepth); + mLandFogEnd = mViewDistance; + } + mUnderwaterFogStart = mViewDistance * (1 - underwaterFog); + mUnderwaterFogEnd = mViewDistance; + } mFogColor = color; - mUnderwaterFog = underwaterFog; } SkyManager* RenderingManager::getSkyManager() @@ -544,23 +596,15 @@ namespace MWRender float viewDistance = mViewDistance; viewDistance = std::min(viewDistance, 6666.f); setFogColor(mUnderwaterColor * mUnderwaterWeight + mFogColor * (1.f-mUnderwaterWeight)); - mStateUpdater->setFogStart(viewDistance * (1 - mUnderwaterFog)); - mStateUpdater->setFogEnd(viewDistance); + mStateUpdater->setFogStart(mUnderwaterFogStart); + mStateUpdater->setFogEnd(mUnderwaterFogEnd); } else { setFogColor(mFogColor); - if (mFogDepth == 0.f) - { - mStateUpdater->setFogStart(0.f); - mStateUpdater->setFogEnd(std::numeric_limits::max()); - } - else - { - mStateUpdater->setFogStart(mViewDistance * (1 - mFogDepth)); - mStateUpdater->setFogEnd(mViewDistance); - } + mStateUpdater->setFogStart(mLandFogStart); + mStateUpdater->setFogEnd(mLandFogEnd); } } @@ -987,7 +1031,8 @@ namespace MWRender else if (it->first == "Camera" && it->second == "viewing distance") { mViewDistance = Settings::Manager::getFloat("viewing distance", "Camera"); - mStateUpdater->setFogEnd(mViewDistance); + if(!mDistantFog) + mStateUpdater->setFogEnd(mViewDistance); updateProjectionMatrix(); } else if (it->first == "General" && (it->second == "texture filter" || diff --git a/apps/openmw/mwrender/renderingmanager.hpp b/apps/openmw/mwrender/renderingmanager.hpp index d322bfaf4..edd7e6def 100644 --- a/apps/openmw/mwrender/renderingmanager.hpp +++ b/apps/openmw/mwrender/renderingmanager.hpp @@ -107,7 +107,7 @@ namespace MWRender void configureAmbient(const ESM::Cell* cell); void configureFog(const ESM::Cell* cell); - void configureFog(float fogDepth, float underwaterFog, const osg::Vec4f& colour); + void configureFog(float fogDepth, float underwaterFog, float dlFactor, float dlOffset, const osg::Vec4f& colour); void addCell(const MWWorld::CellStore* store); void removeCell(const MWWorld::CellStore* store); @@ -243,10 +243,12 @@ namespace MWRender osg::ref_ptr mStateUpdater; - float mFogDepth; + float mLandFogStart; + float mLandFogEnd; + float mUnderwaterFogStart; + float mUnderwaterFogEnd; osg::Vec4f mUnderwaterColor; float mUnderwaterWeight; - float mUnderwaterFog; float mUnderwaterIndoorFog; osg::Vec4f mFogColor; @@ -255,8 +257,10 @@ namespace MWRender float mNearClip; float mViewDistance; + bool mDistantFog : 1; + bool mDistantTerrain : 1; + bool mFieldOfViewOverridden : 1; float mFieldOfViewOverride; - bool mFieldOfViewOverridden; float mFieldOfView; float mFirstPersonFieldOfView; diff --git a/apps/openmw/mwrender/sky.hpp b/apps/openmw/mwrender/sky.hpp index 4357d468c..a9345cdb4 100644 --- a/apps/openmw/mwrender/sky.hpp +++ b/apps/openmw/mwrender/sky.hpp @@ -65,6 +65,9 @@ namespace MWRender float mFogDepth; + float mDLFogFactor; + float mDLFogOffset; + float mWindSpeed; float mCloudSpeed; diff --git a/apps/openmw/mwrender/water.cpp b/apps/openmw/mwrender/water.cpp index dbfee05df..6e1fef716 100644 --- a/apps/openmw/mwrender/water.cpp +++ b/apps/openmw/mwrender/water.cpp @@ -503,13 +503,11 @@ void Water::createSimpleWaterStateSet(osg::Node* node, float alpha) // use a shader to render the simple water, ensuring that fog is applied per pixel as required. // this could be removed if a more detailed water mesh, using some sort of paging solution, is implemented. -#if !defined(OPENGL_ES) && !defined(ANDROID) Resource::SceneManager* sceneManager = mResourceSystem->getSceneManager(); bool oldValue = sceneManager->getForceShaders(); sceneManager->setForceShaders(true); sceneManager->recreateShaders(node); sceneManager->setForceShaders(oldValue); -#endif } void Water::createShaderWaterStateSet(osg::Node* node, Reflection* reflection, Refraction* refraction) diff --git a/apps/openmw/mwscript/interpretercontext.cpp b/apps/openmw/mwscript/interpretercontext.cpp index d70ff5319..f4e729da1 100644 --- a/apps/openmw/mwscript/interpretercontext.cpp +++ b/apps/openmw/mwscript/interpretercontext.cpp @@ -406,7 +406,7 @@ namespace MWScript const MWWorld::ESMStore &store = world->getStore(); const ESM::Faction *faction = store.get().find(factionId); - if(rank < 0 || rank > 9) + if(rank < 0) return ""; return faction->mRanks[rank]; diff --git a/apps/openmw/mwscript/miscextensions.cpp b/apps/openmw/mwscript/miscextensions.cpp index 1067b5536..59f2cc9c6 100644 --- a/apps/openmw/mwscript/miscextensions.cpp +++ b/apps/openmw/mwscript/miscextensions.cpp @@ -454,7 +454,13 @@ namespace MWScript store.get().find(creature); // This line throws an exception if it can't find the creature MWWorld::Ptr item = *ptr.getClass().getContainerStore(ptr).add(gem, 1, ptr); + + // Set the soul on just one of the gems, not the whole stack + item.getContainerStore()->unstack(item, ptr); item.getCellRef().setSoul(creature); + + // Restack the gem with other gems with the same soul + item.getContainerStore()->restack(item); } }; diff --git a/apps/openmw/mwscript/transformationextensions.cpp b/apps/openmw/mwscript/transformationextensions.cpp index 68b1063e4..5e617fb1a 100644 --- a/apps/openmw/mwscript/transformationextensions.cpp +++ b/apps/openmw/mwscript/transformationextensions.cpp @@ -530,7 +530,8 @@ namespace MWScript // create item MWWorld::ManualRef ref(MWBase::Environment::get().getWorld()->getStore(), itemID, 1); - MWBase::Environment::get().getWorld()->safePlaceObject(ref.getPtr(), actor, actor.getCell(), direction, distance); + MWWorld::Ptr ptr = MWBase::Environment::get().getWorld()->safePlaceObject(ref.getPtr(), actor, actor.getCell(), direction, distance); + MWBase::Environment::get().getWorld()->scaleObject(ptr, actor.getCellRef().getScale()); } } }; diff --git a/apps/openmw/mwsound/alext.h b/apps/openmw/mwsound/alext.h index 4b9a15537..7162fa955 100644 --- a/apps/openmw/mwsound/alext.h +++ b/apps/openmw/mwsound/alext.h @@ -15,7 +15,7 @@ * License along with this library; if not, write to the * Free Software Foundation, Inc., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. - * Or go to http://www.gnu.org/copyleft/lgpl.html + * Or go to https://www.gnu.org/copyleft/lgpl.html */ #ifndef AL_ALEXT_H diff --git a/apps/openmw/mwsound/ffmpeg_decoder.hpp b/apps/openmw/mwsound/ffmpeg_decoder.hpp index e06a68d64..2b76e0d7d 100644 --- a/apps/openmw/mwsound/ffmpeg_decoder.hpp +++ b/apps/openmw/mwsound/ffmpeg_decoder.hpp @@ -21,7 +21,7 @@ extern "C" // From version 54.56 binkaudio encoding format changed from S16 to FLTP. See: // https://gitorious.org/ffmpeg/ffmpeg/commit/7bfd1766d1c18f07b0a2dd042418a874d49ea60d -// http://ffmpeg.zeranoe.com/forum/viewtopic.php?f=15&t=872 +// https://ffmpeg.zeranoe.com/forum/viewtopic.php?f=15&t=872 #include } diff --git a/apps/openmw/mwsound/soundmanagerimp.cpp b/apps/openmw/mwsound/soundmanagerimp.cpp index a798d350c..db02bb482 100644 --- a/apps/openmw/mwsound/soundmanagerimp.cpp +++ b/apps/openmw/mwsound/soundmanagerimp.cpp @@ -393,32 +393,8 @@ namespace MWSound void SoundManager::startRandomTitle() { - std::vector filelist; + const std::vector &filelist = mMusicFiles[mCurrentPlaylist]; auto &tracklist = mMusicToPlay[mCurrentPlaylist]; - if (mMusicFiles.find(mCurrentPlaylist) == mMusicFiles.end()) - { - const std::map& index = mVFS->getIndex(); - - std::string pattern = "Music/" + mCurrentPlaylist; - mVFS->normalizeFilename(pattern); - - std::map::const_iterator found = index.lower_bound(pattern); - while (found != index.end()) - { - if (found->first.size() >= pattern.size() && found->first.substr(0, pattern.size()) == pattern) - filelist.push_back(found->first); - else - break; - ++found; - } - - mMusicFiles[mCurrentPlaylist] = filelist; - } - else - filelist = mMusicFiles[mCurrentPlaylist]; - - if(filelist.empty()) - return; // Do a Fisher-Yates shuffle @@ -454,6 +430,33 @@ namespace MWSound void SoundManager::playPlaylist(const std::string &playlist) { + if (mCurrentPlaylist == playlist) + return; + + if (mMusicFiles.find(playlist) == mMusicFiles.end()) + { + std::vector filelist; + const std::map& index = mVFS->getIndex(); + + std::string pattern = "Music/" + playlist; + mVFS->normalizeFilename(pattern); + + std::map::const_iterator found = index.lower_bound(pattern); + while (found != index.end()) + { + if (found->first.size() >= pattern.size() && found->first.substr(0, pattern.size()) == pattern) + filelist.push_back(found->first); + else + break; + ++found; + } + + mMusicFiles[playlist] = filelist; + } + + if (mMusicFiles[playlist].empty()) + return; + mCurrentPlaylist = playlist; startRandomTitle(); } diff --git a/apps/openmw/mwstate/quicksavemanager.cpp b/apps/openmw/mwstate/quicksavemanager.cpp new file mode 100644 index 000000000..59658ce6e --- /dev/null +++ b/apps/openmw/mwstate/quicksavemanager.cpp @@ -0,0 +1,38 @@ +#include "quicksavemanager.hpp" + +MWState::QuickSaveManager::QuickSaveManager(std::string &saveName, unsigned int maxSaves) + : mSaveName(saveName) + , mMaxSaves(maxSaves) + , mSlotsVisited(0) + , mOldestSlotVisited(nullptr) +{ +} + +void MWState::QuickSaveManager::visitSave(const Slot *saveSlot) +{ + if(mSaveName == saveSlot->mProfile.mDescription) + { + ++mSlotsVisited; + if(isOldestSave(saveSlot)) + mOldestSlotVisited = saveSlot; + } +} + +bool MWState::QuickSaveManager::isOldestSave(const Slot *compare) +{ + if(mOldestSlotVisited == NULL) + return true; + return (compare->mTimeStamp <= mOldestSlotVisited->mTimeStamp); +} + +bool MWState::QuickSaveManager::shouldCreateNewSlot() +{ + return (mSlotsVisited < mMaxSaves); +} + +const MWState::Slot *MWState::QuickSaveManager::getNextQuickSaveSlot() +{ + if(shouldCreateNewSlot()) + return NULL; + return mOldestSlotVisited; +} diff --git a/apps/openmw/mwstate/quicksavemanager.hpp b/apps/openmw/mwstate/quicksavemanager.hpp new file mode 100644 index 000000000..e52cd609f --- /dev/null +++ b/apps/openmw/mwstate/quicksavemanager.hpp @@ -0,0 +1,35 @@ +#ifndef GAME_STATE_QUICKSAVEMANAGER_H +#define GAME_STATE_QUICKSAVEMANAGER_H + +#include + +#include "character.hpp" +#include "../mwbase/statemanager.hpp" + +namespace MWState{ + class QuickSaveManager{ + std::string mSaveName; + unsigned int mMaxSaves; + unsigned int mSlotsVisited; + const Slot *mOldestSlotVisited; + private: + bool shouldCreateNewSlot(); + bool isOldestSave(const Slot *compare); + public: + QuickSaveManager(std::string &saveName, unsigned int maxSaves); + ///< A utility class to manage multiple quicksave slots + /// + /// \param saveName The name of the save ("QuickSave", "AutoSave", etc) + /// \param maxSaves The maximum number of save slots to create before recycling old ones + + void visitSave(const Slot *saveSlot); + ///< Visits the given \a slot \a + + const Slot *getNextQuickSaveSlot(); + ///< Get the slot that the next quicksave should use. + /// + ///\return Either the oldest quicksave slot visited, or NULL if a new slot can be made + }; +} + +#endif diff --git a/apps/openmw/mwstate/statemanagerimp.cpp b/apps/openmw/mwstate/statemanagerimp.cpp index 14ee5adee..c1bb589e8 100644 --- a/apps/openmw/mwstate/statemanagerimp.cpp +++ b/apps/openmw/mwstate/statemanagerimp.cpp @@ -37,6 +37,8 @@ #include "../mwscript/globalscripts.hpp" +#include "quicksavemanager.hpp" + void MWState::StateManager::cleanup (bool force) { if (mState!=State_NoGame || force) @@ -324,20 +326,25 @@ void MWState::StateManager::quickSave (std::string name) return; } - const Slot* slot = NULL; + int maxSaves = Settings::Manager::getInt("max quicksaves", "Saves"); + if(maxSaves < 1) + maxSaves = 1; + Character* currentCharacter = getCurrentCharacter(); //Get current character + QuickSaveManager saveFinder = QuickSaveManager(name, maxSaves); - //Find quicksave slot if (currentCharacter) { for (Character::SlotIterator it = currentCharacter->begin(); it != currentCharacter->end(); ++it) { - if (it->mProfile.mDescription == name) - slot = &*it; + //Visiting slots allows the quicksave finder to find the oldest quicksave + saveFinder.visitSave(&*it); } } - saveGame(name, slot); + //Once all the saves have been visited, the save finder can tell us which + //one to replace (or create) + saveGame(name, saveFinder.getNextQuickSaveSlot()); } void MWState::StateManager::loadGame(const std::string& filepath) diff --git a/apps/openmw/mwworld/actionread.cpp b/apps/openmw/mwworld/actionread.cpp index d2dc972fc..58611f0af 100644 --- a/apps/openmw/mwworld/actionread.cpp +++ b/apps/openmw/mwworld/actionread.cpp @@ -52,7 +52,7 @@ namespace MWWorld playerRef->mBase->mClass ); - npcStats.increaseSkill (ref->mBase->mData.mSkillId, *class_, true); + npcStats.increaseSkill (ref->mBase->mData.mSkillId, *class_, true, true); npcStats.flagAsUsed (ref->mBase->mId); } diff --git a/apps/openmw/mwworld/cellstore.cpp b/apps/openmw/mwworld/cellstore.cpp index f33c7bb67..1b6495c11 100644 --- a/apps/openmw/mwworld/cellstore.cpp +++ b/apps/openmw/mwworld/cellstore.cpp @@ -677,7 +677,6 @@ namespace MWWorld if (mCell->mData.mFlags & ESM::Cell::Interior && mCell->mData.mFlags & ESM::Cell::HasWater) mWaterLevel = state.mWaterLevel; - mWaterLevel = state.mWaterLevel; mLastRespawn = MWWorld::TimeStamp(state.mLastRespawn); } @@ -688,7 +687,6 @@ namespace MWWorld if (mCell->mData.mFlags & ESM::Cell::Interior && mCell->mData.mFlags & ESM::Cell::HasWater) state.mWaterLevel = mWaterLevel; - state.mWaterLevel = mWaterLevel; state.mHasFogOfWar = (mFogState.get() ? 1 : 0); state.mLastRespawn = mLastRespawn.toEsm(); } diff --git a/apps/openmw/mwworld/containerstore.cpp b/apps/openmw/mwworld/containerstore.cpp index 981f63e34..dd5d7a853 100644 --- a/apps/openmw/mwworld/containerstore.cpp +++ b/apps/openmw/mwworld/containerstore.cpp @@ -256,11 +256,7 @@ bool MWWorld::ContainerStore::stacks(const ConstPtr& ptr1, const ConstPtr& ptr2) MWWorld::ContainerStoreIterator MWWorld::ContainerStore::add(const std::string &id, int count, const Ptr &actorPtr) { MWWorld::ManualRef ref(MWBase::Environment::get().getWorld()->getStore(), id, count); - // a bit pointless to set owner for the player - if (actorPtr != MWMechanics::getPlayer()) - return add(ref.getPtr(), count, actorPtr, true); - else - return add(ref.getPtr(), count, actorPtr, false); + return add(ref.getPtr(), count, actorPtr, true); } MWWorld::ContainerStoreIterator MWWorld::ContainerStore::add (const Ptr& itemPtr, int count, const Ptr& actorPtr, bool setOwner) diff --git a/apps/openmw/mwworld/esmstore.cpp b/apps/openmw/mwworld/esmstore.cpp index 4a1763d0a..2fe9ebcad 100644 --- a/apps/openmw/mwworld/esmstore.cpp +++ b/apps/openmw/mwworld/esmstore.cpp @@ -141,6 +141,7 @@ void ESMStore::setUp() mMagicEffects.setUp(); mAttributes.setUp(); mDialogs.setUp(); + mStatics.setUp(); } int ESMStore::countSavedGameRecords() const diff --git a/apps/openmw/mwworld/livecellref.cpp b/apps/openmw/mwworld/livecellref.cpp index 294734f46..b8178f774 100644 --- a/apps/openmw/mwworld/livecellref.cpp +++ b/apps/openmw/mwworld/livecellref.cpp @@ -48,6 +48,12 @@ void MWWorld::LiveCellRefBase::loadImp (const ESM::ObjectState& state) } mClass->readAdditionalState (ptr, state); + + if (!mRef.getSoul().empty() && !MWBase::Environment::get().getWorld()->getStore().get().search(mRef.getSoul())) + { + std::cerr << "Soul '" << mRef.getSoul() << "' not found, removing the soul from soul gem" << std::endl; + mRef.setSoul(std::string()); + } } void MWWorld::LiveCellRefBase::saveImp (ESM::ObjectState& state) const diff --git a/apps/openmw/mwworld/player.cpp b/apps/openmw/mwworld/player.cpp index 19bf7f55e..34c5f713d 100644 --- a/apps/openmw/mwworld/player.cpp +++ b/apps/openmw/mwworld/player.cpp @@ -47,37 +47,45 @@ namespace MWWorld mPlayer.mData.setPosition(playerPos); } - void Player::saveSkillsAttributes() + void Player::saveStats() { MWMechanics::NpcStats& stats = getPlayer().getClass().getNpcStats(getPlayer()); + for (int i=0; i& gmst = MWBase::Environment::get().getWorld()->getStore().get(); + MWMechanics::CreatureStats& creatureStats = getPlayer().getClass().getCreatureStats(getPlayer()); + MWMechanics::NpcStats& npcStats = getPlayer().getClass().getNpcStats(getPlayer()); + MWMechanics::DynamicStat health = creatureStats.getDynamic(0); + creatureStats.setHealth(int(health.getBase() / gmst.find("fWereWolfHealth")->getFloat())); for (int i=0; i& gmst = MWBase::Environment::get().getWorld()->getStore().get(); - MWMechanics::NpcStats& stats = getPlayer().getClass().getNpcStats(getPlayer()); + MWMechanics::CreatureStats& creatureStats = getPlayer().getClass().getCreatureStats(getPlayer()); + MWMechanics::NpcStats& npcStats = getPlayer().getClass().getNpcStats(getPlayer()); + MWMechanics::DynamicStat health = creatureStats.getDynamic(0); + creatureStats.setHealth(int(health.getBase() * gmst.find("fWereWolfHealth")->getFloat())); for(size_t i = 0;i < ESM::Attribute::Length;++i) { // Oh, Bethesda. It's "Intelligence". std::string name = "fWerewolf"+((i==ESM::Attribute::Intelligence) ? std::string("Intellegence") : ESM::Attribute::sAttributeNames[i]); - MWMechanics::AttributeValue value = stats.getAttribute(i); + MWMechanics::AttributeValue value = npcStats.getAttribute(i); value.setBase(int(gmst.find(name)->getFloat())); - stats.setAttribute(i, value); + npcStats.setAttribute(i, value); } for(size_t i = 0;i < ESM::Skill::Length;i++) @@ -90,9 +98,9 @@ namespace MWWorld std::string name = "fWerewolf"+((i==ESM::Skill::Mercantile) ? std::string("Merchantile") : ESM::Skill::sSkillNames[i]); - MWMechanics::SkillValue value = stats.getSkill(i); + MWMechanics::SkillValue value = npcStats.getSkill(i); value.setBase(int(gmst.find(name)->getFloat())); - stats.setSkill(i, value); + npcStats.setSkill(i, value); } } @@ -366,8 +374,8 @@ namespace MWWorld if (player.mObject.mNpcStats.mWerewolfDeprecatedData && player.mObject.mNpcStats.mIsWerewolf) { - saveSkillsAttributes(); - setWerewolfSkillsAttributes(); + saveStats(); + setWerewolfStats(); } getPlayer().getClass().getCreatureStats(getPlayer()).getAiSequence().clear(); diff --git a/apps/openmw/mwworld/player.hpp b/apps/openmw/mwworld/player.hpp index 4ba66e37e..aabbe7015 100644 --- a/apps/openmw/mwworld/player.hpp +++ b/apps/openmw/mwworld/player.hpp @@ -46,7 +46,7 @@ namespace MWWorld int mCurrentCrimeId; // the id assigned witnesses int mPaidCrimeId; // the last id paid off (0 bounty) - // Saved skills and attributes prior to becoming a werewolf + // Saved stats prior to becoming a werewolf MWMechanics::SkillValue mSaveSkills[ESM::Skill::Length]; MWMechanics::AttributeValue mSaveAttributes[ESM::Attribute::Length]; @@ -56,9 +56,9 @@ namespace MWWorld Player(const ESM::NPC *player); - void saveSkillsAttributes(); - void restoreSkillsAttributes(); - void setWerewolfSkillsAttributes(); + void saveStats(); + void restoreStats(); + void setWerewolfStats(); // For mark/recall magic effects void markPosition (CellStore* markedCell, const ESM::Position& markedPosition); diff --git a/apps/openmw/mwworld/scene.cpp b/apps/openmw/mwworld/scene.cpp index 0a27cf257..2c2d401d1 100644 --- a/apps/openmw/mwworld/scene.cpp +++ b/apps/openmw/mwworld/scene.cpp @@ -79,6 +79,9 @@ namespace if (ptr.getClass().isActor()) rendering.addWaterRippleEmitter(ptr); + + // Restore effect particles + MWBase::Environment::get().getWorld()->applyLoopingParticles(ptr); } void updateObjectRotation (const MWWorld::Ptr& ptr, MWPhysics::PhysicsSystem& physics, @@ -457,8 +460,7 @@ namespace MWWorld float z = pos.rot[2]; world->rotateObject(player, x, y, z); - if (adjustPlayerPos) - player.getClass().adjustPosition(player, true); + player.getClass().adjustPosition(player, true); } MWBase::MechanicsManager *mechMgr = diff --git a/apps/openmw/mwworld/store.cpp b/apps/openmw/mwworld/store.cpp index 9279e3fe7..6f0a1b49f 100644 --- a/apps/openmw/mwworld/store.cpp +++ b/apps/openmw/mwworld/store.cpp @@ -592,7 +592,7 @@ namespace MWWorld const ESM::Cell *ptr = search(id); if (ptr == 0) { std::ostringstream msg; - msg << "Interior cell '" << id << "' not found"; + msg << "Cell '" << id << "' not found"; throw std::runtime_error(msg.str()); } return ptr; @@ -1053,6 +1053,32 @@ namespace MWWorld } } + template<> + void Store::setUp() + { + // Load default marker definitions, if game files do not have them for some reason + std::pair markers[] = { + std::make_pair("divinemarker", "marker_divine.nif"), + std::make_pair("doormarker", "marker_arrow.nif"), + std::make_pair("northmarker", "marker_north.nif"), + std::make_pair("templemarker", "marker_temple.nif"), + std::make_pair("travelmarker", "marker_travel.nif") + }; + + for (const std::pair marker : markers) + { + if (search(marker.first) == 0) + { + ESM::Static newMarker = ESM::Static(marker.first, marker.second); + std::pair ret = mStatic.insert(std::make_pair(marker.first, newMarker)); + if (ret.first != mStatic.end()) + { + mShared.push_back(&ret.first->second); + } + } + } + } + template <> inline RecordId Store::load(ESM::ESMReader &esm) { // The original letter case of a dialogue ID is saved, because it's printed diff --git a/apps/openmw/mwworld/weather.cpp b/apps/openmw/mwworld/weather.cpp index 2f0a2f8cf..155e4340a 100644 --- a/apps/openmw/mwworld/weather.cpp +++ b/apps/openmw/mwworld/weather.cpp @@ -9,7 +9,6 @@ #include #include "../mwbase/environment.hpp" -#include "../mwbase/world.hpp" #include "../mwbase/soundmanager.hpp" #include "../mwmechanics/actorutil.hpp" @@ -103,6 +102,8 @@ Weather::Weather(const std::string& name, const Fallback::Map& fallback, float stormWindSpeed, float rainSpeed, + float dlFactor, + float dlOffset, const std::string& particleEffect) : mCloudTexture(fallback.getFallbackString("Weather_" + name + "_Cloud_Texture")) , mSkyColor(fallback.getFallbackColour("Weather_" + name +"_Sky_Sunrise_Color"), @@ -142,6 +143,8 @@ Weather::Weather(const std::string& name, , mFlashDecrement(fallback.getFallbackFloat("Weather_" + name + "_Flash_Decrement")) , mFlashBrightness(0.0f) { + mDL.FogFactor = dlFactor; + mDL.FogOffset = dlOffset; mThunderSoundID[0] = fallback.getFallbackString("Weather_" + name + "_Thunder_Sound_ID_0"); mThunderSoundID[1] = fallback.getFallbackString("Weather_" + name + "_Thunder_Sound_ID_1"); mThunderSoundID[2] = fallback.getFallbackString("Weather_" + name + "_Thunder_Sound_ID_2"); @@ -520,6 +523,7 @@ WeatherManager::WeatherManager(MWRender::RenderingManager& rendering, const Fall , mSecunda("Secunda", fallback) , mWindSpeed(0.f) , mIsStorm(false) + , mPrecipitation(false) , mStormDirection(0,1,0) , mCurrentRegion() , mTimePassed(0) @@ -541,16 +545,18 @@ WeatherManager::WeatherManager(MWRender::RenderingManager& rendering, const Fall mTimeSettings.mSunriseTime = mSunriseTime; mWeatherSettings.reserve(10); - addWeather("Clear", fallback); // 0 - addWeather("Cloudy", fallback); // 1 - addWeather("Foggy", fallback); // 2 - addWeather("Overcast", fallback); // 3 - addWeather("Rain", fallback); // 4 - addWeather("Thunderstorm", fallback); // 5 - addWeather("Ashstorm", fallback, "meshes\\ashcloud.nif"); // 6 - addWeather("Blight", fallback, "meshes\\blightcloud.nif"); // 7 - addWeather("Snow", fallback, "meshes\\snow.nif"); // 8 - addWeather("Blizzard", fallback, "meshes\\blizzard.nif"); // 9 + // These distant land fog factor and offset values are the defaults MGE XE provides. Should be + // provided by settings somewhere? + addWeather("Clear", fallback, 1.0f, 0.0f); // 0 + addWeather("Cloudy", fallback, 0.9f, 0.0f); // 1 + addWeather("Foggy", fallback, 0.2f, 30.0f); // 2 + addWeather("Overcast", fallback, 0.7f, 0.0f); // 3 + addWeather("Rain", fallback, 0.5f, 10.0f); // 4 + addWeather("Thunderstorm", fallback, 0.5f, 20.0f); // 5 + addWeather("Ashstorm", fallback, 0.2f, 50.0f, "meshes\\ashcloud.nif"); // 6 + addWeather("Blight", fallback, 0.2f, 60.0f, "meshes\\blightcloud.nif"); // 7 + addWeather("Snow", fallback, 0.5f, 40.0f, "meshes\\snow.nif"); // 8 + addWeather("Blizzard", fallback, 0.16f, 70.0f, "meshes\\blizzard.nif"); // 9 Store::iterator it = store.get().begin(); for(; it != store.get().end(); ++it) @@ -608,14 +614,11 @@ void WeatherManager::modRegion(const std::string& regionID, const std::vectorisCellExterior() || world->isCellQuasiExterior()) { - std::string playerRegion = Misc::StringUtils::lowerCase(world->getPlayerPtr().getCell()->getCell()->mRegion); std::map::iterator it = mRegions.find(playerRegion); if(it != mRegions.end() && playerRegion != mCurrentRegion) { @@ -625,11 +628,9 @@ void WeatherManager::playerTeleported() } } -void WeatherManager::update(float duration, bool paused) +void WeatherManager::update(float duration, bool paused, const TimeStamp& time, bool isExterior) { MWWorld::ConstPtr player = MWMechanics::getPlayer(); - MWBase::World& world = *MWBase::Environment::get().getWorld(); - TimeStamp time = world.getTimeStamp(); if(!paused || mFastForward) { @@ -647,8 +648,7 @@ void WeatherManager::update(float duration, bool paused) updateWeatherTransitions(duration); } - const bool exterior = (world.isCellExterior() || world.isCellQuasiExterior()); - if(!exterior) + if(!isExterior) { mRendering.setSkyEnabled(false); stopSounds(); @@ -660,6 +660,10 @@ void WeatherManager::update(float duration, bool paused) mWindSpeed = mResult.mWindSpeed; mIsStorm = mResult.mIsStorm; + // For some reason Ash Storm is not considered as a precipitation weather in game + mPrecipitation = !(mResult.mParticleEffect.empty() && mResult.mRainEffect.empty()) + && mResult.mParticleEffect != "meshes\\ashcloud.nif"; + if (mIsStorm) { osg::Vec3f playerPos (player.getRefData().getPosition().asVec3()); @@ -720,7 +724,8 @@ void WeatherManager::update(float duration, bool paused) mRendering.getSkyManager()->setMasserState(mMasser.calculateState(time)); mRendering.getSkyManager()->setSecundaState(mSecunda.calculateState(time)); - mRendering.configureFog(mResult.mFogDepth, underwaterFog, mResult.mFogColor); + mRendering.configureFog(mResult.mFogDepth, underwaterFog, mResult.mDLFogFactor, + mResult.mDLFogOffset/100.0f, mResult.mFogColor); mRendering.setAmbientColour(mResult.mAmbientColor); mRendering.setSunColour(mResult.mSunColor, mResult.mSunColor * mResult.mGlareView); @@ -777,12 +782,11 @@ unsigned int WeatherManager::getWeatherID() const return mCurrentWeather; } -bool WeatherManager::isDark() const +bool WeatherManager::useTorches(float hour) const { - TimeStamp time = MWBase::Environment::get().getWorld()->getTimeStamp(); - bool exterior = (MWBase::Environment::get().getWorld()->isCellExterior() - || MWBase::Environment::get().getWorld()->isCellQuasiExterior()); - return exterior && (time.getHour() < mSunriseTime || time.getHour() > mTimeSettings.mNightStart - 1); + bool isDark = hour < mSunriseTime || hour > mTimeSettings.mNightStart - 1; + + return isDark && !mPrecipitation; } void WeatherManager::write(ESM::ESMWriter& writer, Loading::Listener& progress) @@ -866,11 +870,12 @@ void WeatherManager::clear() inline void WeatherManager::addWeather(const std::string& name, const Fallback::Map& fallback, + float dlFactor, float dlOffset, const std::string& particleEffect) { static const float fStromWindSpeed = mStore.get().find("fStromWindSpeed")->getFloat(); - Weather weather(name, fallback, fStromWindSpeed, mRainSpeed, particleEffect); + Weather weather(name, fallback, fStromWindSpeed, mRainSpeed, dlFactor, dlOffset, particleEffect); mWeatherSettings.push_back(weather); } @@ -1058,6 +1063,8 @@ inline void WeatherManager::calculateResult(const int weatherID, const float gam mResult.mNight = (gameHour < mSunriseTime || gameHour > mTimeSettings.mNightStart - 1); mResult.mFogDepth = current.mLandFogDepth.getValue(gameHour, mTimeSettings); + mResult.mDLFogFactor = current.mDL.FogFactor; + mResult.mDLFogOffset = current.mDL.FogOffset; mResult.mFogColor = current.mFogColor.getValue(gameHour, mTimeSettings); mResult.mAmbientColor = current.mAmbientColor.getValue(gameHour, mTimeSettings); mResult.mSunColor = current.mSunColor.getValue(gameHour, mTimeSettings); @@ -1113,6 +1120,8 @@ inline void WeatherManager::calculateTransitionResult(const float factor, const mResult.mAmbientColor = lerp(current.mAmbientColor, other.mAmbientColor, factor); mResult.mSunDiscColor = lerp(current.mSunDiscColor, other.mSunDiscColor, factor); mResult.mFogDepth = lerp(current.mFogDepth, other.mFogDepth, factor); + mResult.mDLFogFactor = lerp(current.mDLFogFactor, other.mDLFogFactor, factor); + mResult.mDLFogOffset = lerp(current.mDLFogOffset, other.mDLFogOffset, factor); mResult.mWindSpeed = lerp(current.mWindSpeed, other.mWindSpeed, factor); mResult.mCloudSpeed = lerp(current.mCloudSpeed, other.mCloudSpeed, factor); mResult.mGlareView = lerp(current.mGlareView, other.mGlareView, factor); @@ -1125,7 +1134,6 @@ inline void WeatherManager::calculateTransitionResult(const float factor, const mResult.mIsStorm = current.mIsStorm; mResult.mParticleEffect = current.mParticleEffect; mResult.mRainEffect = current.mRainEffect; - mResult.mParticleEffect = current.mParticleEffect; mResult.mRainSpeed = current.mRainSpeed; mResult.mRainFrequency = current.mRainFrequency; mResult.mAmbientSoundVolume = 1-(factor*2); @@ -1137,7 +1145,6 @@ inline void WeatherManager::calculateTransitionResult(const float factor, const mResult.mIsStorm = other.mIsStorm; mResult.mParticleEffect = other.mParticleEffect; mResult.mRainEffect = other.mRainEffect; - mResult.mParticleEffect = other.mParticleEffect; mResult.mRainSpeed = other.mRainSpeed; mResult.mRainFrequency = other.mRainFrequency; mResult.mAmbientSoundVolume = 2*(factor-0.5f); diff --git a/apps/openmw/mwworld/weather.hpp b/apps/openmw/mwworld/weather.hpp index 84a6c5105..4be0d3e20 100644 --- a/apps/openmw/mwworld/weather.hpp +++ b/apps/openmw/mwworld/weather.hpp @@ -73,6 +73,8 @@ namespace MWWorld const Fallback::Map& fallback, float stormWindSpeed, float rainSpeed, + float dlFactor, + float dlOffset, const std::string& particleEffect); std::string mCloudTexture; @@ -102,6 +104,12 @@ namespace MWWorld // Also appears to modify how visible the sun, moons, and stars are for various weather effects. float mGlareView; + // Fog factor and offset used with distant land rendering. + struct { + float FogFactor; + float FogOffset; + } mDL; + // Sound effect // This is used for Blight, Ashstorm and Blizzard (Bloodmoon) std::string mAmbientLoopSoundID; @@ -218,14 +226,14 @@ namespace MWWorld */ void changeWeather(const std::string& regionID, const unsigned int weatherID); void modRegion(const std::string& regionID, const std::vector& chances); - void playerTeleported(); + void playerTeleported(const std::string& playerRegion, bool isExterior); /** * Per-frame update * @param duration * @param paused */ - void update(float duration, bool paused = false); + void update(float duration, bool paused, const TimeStamp& time, bool isExterior); void stopSounds(); @@ -240,8 +248,7 @@ namespace MWWorld unsigned int getWeatherID() const; - /// @see World::isDark - bool isDark() const; + bool useTorches(float hour) const; void write(ESM::ESMWriter& writer, Loading::Listener& progress); @@ -275,6 +282,7 @@ namespace MWWorld float mWindSpeed; bool mIsStorm; + bool mPrecipitation; osg::Vec3f mStormDirection; std::string mCurrentRegion; @@ -293,6 +301,7 @@ namespace MWWorld void addWeather(const std::string& name, const Fallback::Map& fallback, + float dlFactor, float dlOffset, const std::string& particleEffect = ""); void importRegions(); diff --git a/apps/openmw/mwworld/worldimp.cpp b/apps/openmw/mwworld/worldimp.cpp index 7786b6823..13bfc32b3 100644 --- a/apps/openmw/mwworld/worldimp.cpp +++ b/apps/openmw/mwworld/worldimp.cpp @@ -406,7 +406,6 @@ namespace MWWorld gmst["sCompanionWarningMessage"] = ESM::Variant("Warning message"); gmst["sCompanionWarningButtonOne"] = ESM::Variant("Button 1"); gmst["sCompanionWarningButtonTwo"] = ESM::Variant("Button 2"); - gmst["sCompanionShare"] = ESM::Variant("Companion Share"); gmst["sProfitValue"] = ESM::Variant("Profit Value"); gmst["sTeleportDisabled"] = ESM::Variant("Teleport disabled"); gmst["sLevitateDisabled"] = ESM::Variant("Levitate disabled"); @@ -2244,6 +2243,8 @@ namespace MWWorld model = Misc::ResourceHelpers::correctActorModelPath(model, mResourceSystem->getVFS()); mPhysics->remove(getPlayerPtr()); mPhysics->addActor(getPlayerPtr(), model); + + applyLoopingParticles(player); } int World::canRest () @@ -2831,6 +2832,19 @@ namespace MWWorld mProjectileManager->launchMagicBolt(spellId, caster, fallbackDirection); } + void World::applyLoopingParticles(const MWWorld::Ptr& ptr) + { + const MWWorld::Class &cls = ptr.getClass(); + if (cls.isActor()) + { + MWMechanics::ApplyLoopingParticlesVisitor visitor(ptr); + cls.getCreatureStats(ptr).getActiveSpells().visitEffectSources(visitor); + cls.getCreatureStats(ptr).getSpells().visitEffectSources(visitor); + if (cls.hasInventoryStore(ptr)) + cls.getInventoryStore(ptr).visitEffectSources(visitor); + } + } + const std::vector& World::getContentFiles() const { return mContentFiles; @@ -2847,11 +2861,17 @@ namespace MWWorld MWBase::Environment::get().getMechanicsManager()->updateMagicEffects(actor); } - bool World::isDark() const + bool World::useTorches() const { + // If we are in exterior, check the weather manager. + // In interiors there are no precipitations and sun, so check the ambient + // Looks like pseudo-exteriors considered as interiors in this case MWWorld::CellStore* cell = mPlayer->getPlayer().getCell(); if (cell->isExterior()) - return mWeatherManager->isDark(); + { + float hour = getTimeStamp().getHour(); + return mWeatherManager->useTorches(hour); + } else { uint32_t ambient = cell->getCell()->mAmbi.mAmbient; @@ -3012,13 +3032,17 @@ namespace MWWorld void World::updateWeather(float duration, bool paused) { + bool isExterior = isCellExterior() || isCellQuasiExterior(); if (mPlayer->wasTeleported()) { mPlayer->setTeleported(false); - mWeatherManager->playerTeleported(); + + const std::string playerRegion = Misc::StringUtils::lowerCase(getPlayerPtr().getCell()->getCell()->mRegion); + mWeatherManager->playerTeleported(playerRegion, isExterior); } - mWeatherManager->update(duration, paused); + const TimeStamp time = getTimeStamp(); + mWeatherManager->update(duration, paused, time, isExterior); } struct AddDetectedReferenceVisitor diff --git a/apps/openmw/mwworld/worldimp.hpp b/apps/openmw/mwworld/worldimp.hpp index 02b3756d5..40a22af5d 100644 --- a/apps/openmw/mwworld/worldimp.hpp +++ b/apps/openmw/mwworld/worldimp.hpp @@ -604,12 +604,13 @@ namespace MWWorld void launchProjectile (MWWorld::Ptr actor, MWWorld::ConstPtr projectile, const osg::Vec3f& worldPos, const osg::Quat& orient, MWWorld::Ptr bow, float speed, float attackStrength) override; + void applyLoopingParticles(const MWWorld::Ptr& ptr); const std::vector& getContentFiles() const override; - void breakInvisibility (const MWWorld::Ptr& actor) override; - // Are we in an exterior or pseudo-exterior cell and it's night? - bool isDark() const override; + + // Allow NPCs to use torches? + bool useTorches() const override; bool findInteriorPositionInWorldSpace(const MWWorld::CellStore* cell, osg::Vec3f& result) override; diff --git a/apps/openmw_test_suite/CMakeLists.txt b/apps/openmw_test_suite/CMakeLists.txt index 9b09bc41f..48c8be4d8 100644 --- a/apps/openmw_test_suite/CMakeLists.txt +++ b/apps/openmw_test_suite/CMakeLists.txt @@ -1,7 +1,7 @@ find_package(GTest REQUIRED) if (GTEST_FOUND) - include_directories(${GTEST_INCLUDE_DIRS}) + include_directories(SYSTEM ${GTEST_INCLUDE_DIRS}) file(GLOB UNITTEST_SRC_FILES ../openmw/mwworld/store.cpp diff --git a/apps/openmw_test_suite/esm/test_fixed_string.cpp b/apps/openmw_test_suite/esm/test_fixed_string.cpp index 59dd7fe66..598e8daad 100644 --- a/apps/openmw_test_suite/esm/test_fixed_string.cpp +++ b/apps/openmw_test_suite/esm/test_fixed_string.cpp @@ -66,10 +66,8 @@ TEST(EsmFixedString, struct_size) TEST(EsmFixedString, DISABLED_is_pod) { - /* TODO: enable in C++11 - * ASSERT_TRUE(std::is_pod::value); - * ASSERT_TRUE(std::is_pod::value); - * ASSERT_TRUE(std::is_pod::value); - * ASSERT_TRUE(std::is_pod::value); - */ + ASSERT_TRUE(std::is_pod::value); + ASSERT_TRUE(std::is_pod::value); + ASSERT_TRUE(std::is_pod::value); + ASSERT_TRUE(std::is_pod::value); } diff --git a/apps/wizard/CMakeLists.txt b/apps/wizard/CMakeLists.txt index 5f7338e52..8d97bbcbf 100644 --- a/apps/wizard/CMakeLists.txt +++ b/apps/wizard/CMakeLists.txt @@ -118,7 +118,7 @@ if (DESIRED_QT_VERSION MATCHES 4) target_link_libraries(openmw-wizard ${QT_QTMAIN_LIBRARY}) endif() else() - qt5_use_modules(openmw-wizard Widgets Core) + target_link_libraries(openmw-wizard Qt5::Widgets Qt5::Core) endif() if (OPENMW_USE_UNSHIELD) diff --git a/apps/wizard/installationpage.cpp b/apps/wizard/installationpage.cpp index 7a4dcbf10..3deb30f25 100644 --- a/apps/wizard/installationpage.cpp +++ b/apps/wizard/installationpage.cpp @@ -161,7 +161,7 @@ void Wizard::InstallationPage::showFileDialog(Wizard::Component component) if (path.isEmpty()) { logTextEdit->appendHtml(tr("


        \ - Error: The installation was aborted by the user

        ")); + Error: The installation was aborted by the user

        ")); mWizard->addLogText(QLatin1String("Error: The installation was aborted by the user")); mWizard->mError = true; diff --git a/apps/wizard/mainwizard.cpp b/apps/wizard/mainwizard.cpp index b99f151aa..0f8fb0c49 100644 --- a/apps/wizard/mainwizard.cpp +++ b/apps/wizard/mainwizard.cpp @@ -62,10 +62,11 @@ Wizard::MainWizard::MainWizard(QWidget *parent) : setupInstallations(); setupPages(); - const boost::filesystem::path& installedPath = mCfgMgr.getInstallPath(); - if (!installedPath.empty()) + const boost::filesystem::path& installationPath = mCfgMgr.getInstallPath(); + if (!installationPath.empty()) { - addInstallation(toQString(installedPath)); + const boost::filesystem::path& dataPath = installationPath / "Data Files"; + addInstallation(toQString(dataPath)); } } diff --git a/apps/wizard/unshield/unshieldworker.cpp b/apps/wizard/unshield/unshieldworker.cpp index 020de9f80..9cdb4cd78 100644 --- a/apps/wizard/unshield/unshieldworker.cpp +++ b/apps/wizard/unshield/unshieldworker.cpp @@ -472,8 +472,8 @@ bool Wizard::UnshieldWorker::setupComponent(Component component) if (morrowindFound) { // Check if we have correct archive, other archives have Morrowind.bsa too - if ((tribunalFound && bloodmoonFound) - || (!tribunalFound && !bloodmoonFound)) { + if (tribunalFound == bloodmoonFound) + { cabFile = file; found = true; // We have a GoTY disk or a Morrowind-only disk } diff --git a/cmake/FindFreetype.cmake b/cmake/FindFreetype.cmake index 3d28613ae..3b7586835 100644 --- a/cmake/FindFreetype.cmake +++ b/cmake/FindFreetype.cmake @@ -1,7 +1,7 @@ #------------------------------------------------------------------- # This file is part of the CMake build system for OGRE # (Object-oriented Graphics Rendering Engine) -# For the latest info, see http://www.ogre3d.org/ +# For the latest info, see https://www.ogre3d.org/ # # The contents of this file are placed in the public domain. Feel # free to make use of it in any way you like. diff --git a/cmake/FindLIBUNSHIELD.cmake b/cmake/FindLIBUNSHIELD.cmake index 285740b63..ee6414646 100644 --- a/cmake/FindLIBUNSHIELD.cmake +++ b/cmake/FindLIBUNSHIELD.cmake @@ -4,7 +4,7 @@ # LIBUNSHIELD_FOUND, if false, do not try to link to LibUnshield # LIBUNSHIELD_INCLUDE_DIRS, where to find the headers # -# Created by Tom Mason (wheybags) for OpenMW (http://openmw.org), based on FindMPG123.cmake +# Created by Tom Mason (wheybags) for OpenMW (https://openmw.org), based on FindMPG123.cmake # # Ripped off from other sources. In fact, this file is so generic (I # just did a search and replace on another file) that I wonder why the diff --git a/cmake/FindOpenGLES.cmake b/cmake/FindOpenGLES.cmake deleted file mode 100644 index 7ee2c07f1..000000000 --- a/cmake/FindOpenGLES.cmake +++ /dev/null @@ -1,94 +0,0 @@ -#------------------------------------------------------------------- -# This file is part of the CMake build system for OGRE -# (Object-oriented Graphics Rendering Engine) -# For the latest info, see http://www.ogre3d.org/ -# -# The contents of this file are placed in the public domain. Feel -# free to make use of it in any way you like. -#------------------------------------------------------------------- - -# - Try to find OpenGLES -# Once done this will define -# -# OPENGLES_FOUND - system has OpenGLES -# OPENGLES_INCLUDE_DIR - the GL include directory -# OPENGLES_LIBRARIES - Link these to use OpenGLES - -IF (WIN32) - IF (CYGWIN) - - FIND_PATH(OPENGLES_INCLUDE_DIR GLES/gl.h ) - - FIND_LIBRARY(OPENGLES_gl_LIBRARY libgles_cm ) - - ELSE (CYGWIN) - - IF(BORLAND) - SET (OPENGLES_gl_LIBRARY import32 CACHE STRING "OpenGL ES 1.x library for win32") - ELSE(BORLAND) - #MS compiler - todo - fix the following line: - SET (OPENGLES_gl_LIBRARY ${OGRE_SOURCE_DIR}/Dependencies/lib/release/libgles_cm.lib CACHE STRING "OpenGL ES 1.x library for win32") - ENDIF(BORLAND) - - ENDIF (CYGWIN) - -ELSE (WIN32) - - IF (APPLE) - - #create_search_paths(/Developer/Platforms) - #findpkg_framework(OpenGLES) - #set(OPENGLES_gl_LIBRARY "-framework OpenGLES") - - ELSE(APPLE) - - FIND_PATH(OPENGLES_INCLUDE_DIR GLES/gl.h - /opt/vc/include - /opt/graphics/OpenGL/include - /usr/openwin/share/include - /usr/X11R6/include - /usr/include - ) - - FIND_LIBRARY(OPENGLES_gl_LIBRARY - NAMES GLES_CM GLESv1_CM - PATHS /opt/vc/lib - /opt/graphics/OpenGL/lib - /usr/openwin/lib - /usr/shlib /usr/X11R6/lib - /usr/lib - ) - - # On Unix OpenGL most certainly always requires X11. - # Feel free to tighten up these conditions if you don't - # think this is always true. - - #IF (OPENGLES_gl_LIBRARY) - # IF(NOT X11_FOUND) - # INCLUDE(FindX11) - # ENDIF(NOT X11_FOUND) - # IF (X11_FOUND) - # SET (OPENGLES_LIBRARIES ${X11_LIBRARIES}) - # ENDIF (X11_FOUND) - #ENDIF (OPENGLES_gl_LIBRARY) - - ENDIF(APPLE) -ENDIF (WIN32) - -SET( OPENGLES_FOUND "NO" ) -IF(OPENGLES_gl_LIBRARY) - - SET( OPENGLES_LIBRARIES ${OPENGLES_gl_LIBRARY} ${OPENGLES_LIBRARIES}) - - SET( OPENGLES_FOUND "YES" ) - -ENDIF(OPENGLES_gl_LIBRARY) - -MARK_AS_ADVANCED( - OPENGLES_INCLUDE_DIR - OPENGLES_gl_LIBRARY -) - -INCLUDE(FindPackageHandleStandardArgs) - -FIND_PACKAGE_HANDLE_STANDARD_ARGS(OPENGLES REQUIRED_VARS OPENGLES_LIBRARIES OPENGLES_INCLUDE_DIR) diff --git a/components/CMakeLists.txt b/components/CMakeLists.txt index e68e7ed07..c19341a97 100644 --- a/components/CMakeLists.txt +++ b/components/CMakeLists.txt @@ -26,12 +26,6 @@ else (GIT_CHECKOUT) configure_resource_file(${VERSION_IN_FILE} ${VERSION_FILE_PATH_BASE} ${VERSION_FILE_PATH_RELATIVE}) endif (GIT_CHECKOUT) -if (OPENGL_ES) - find_package(OpenGLES REQUIRED) -else() - find_package(OpenGL REQUIRED) -endif() - # source files add_component_dir (settings @@ -191,12 +185,6 @@ include_directories(${Bullet_INCLUDE_DIRS} ${CMAKE_CURRENT_BINARY_DIR}) add_library(components STATIC ${COMPONENT_FILES} ${MOC_SRCS} ${ESM_UI_HDR}) -if (OPENGL_ES) - set(GL_LIB ${OPENGLES_gl_LIBRARY}) -else() - set(GL_LIB ${OPENGL_gl_LIBRARY}) -endif() - target_link_libraries(components ${Boost_SYSTEM_LIBRARY} ${Boost_FILESYSTEM_LIBRARY} @@ -214,8 +202,7 @@ target_link_libraries(components ${OSGANIMATION_LIBRARIES} ${Bullet_LIBRARIES} ${SDL2_LIBRARIES} - # For MyGUI platform - ${GL_LIB} + ${OPENGL_gl_LIBRARY} ${MyGUI_LIBRARIES} ) @@ -230,7 +217,7 @@ if (USE_QT) ${QT_QTCORE_LIBRARY} ${QT_QTGUI_LIBRARY}) else() - qt5_use_modules(components Widgets Core) + target_link_libraries(components Qt5::Widgets Qt5::Core) endif() endif() diff --git a/components/bsa/bsa_file.cpp b/components/bsa/bsa_file.cpp index c4be428b3..8905a86a1 100644 --- a/components/bsa/bsa_file.cpp +++ b/components/bsa/bsa_file.cpp @@ -2,7 +2,7 @@ OpenMW - The completely unofficial reimplementation of Morrowind Copyright (C) 2008-2010 Nicolay Korslund Email: < korslund@gmail.com > - WWW: http://openmw.sourceforge.net/ + WWW: https://openmw.org/ This file (bsa_file.cpp) is part of the OpenMW package. @@ -17,7 +17,7 @@ You should have received a copy of the GNU General Public License version 3 along with this program. If not, see - http://www.gnu.org/licenses/ . + https://www.gnu.org/licenses/ . */ diff --git a/components/bsa/bsa_file.hpp b/components/bsa/bsa_file.hpp index 5ff86ef65..196dc30fb 100644 --- a/components/bsa/bsa_file.hpp +++ b/components/bsa/bsa_file.hpp @@ -2,7 +2,7 @@ OpenMW - The completely unofficial reimplementation of Morrowind Copyright (C) 2008-2010 Nicolay Korslund Email: < korslund@gmail.com > - WWW: http://openmw.sourceforge.net/ + WWW: https://openmw.org/ This file (bsa_file.h) is part of the OpenMW package. @@ -17,7 +17,7 @@ You should have received a copy of the GNU General Public License version 3 along with this program. If not, see - http://www.gnu.org/licenses/ . + https://www.gnu.org/licenses/ . */ diff --git a/components/config/gamesettings.cpp b/components/config/gamesettings.cpp index b35612ee4..29dbe0391 100644 --- a/components/config/gamesettings.cpp +++ b/components/config/gamesettings.cpp @@ -493,8 +493,10 @@ bool Config::GameSettings::hasMaster() { bool result = false; QStringList content = mSettings.values(QString(Config::GameSettings::sContentKey)); - for (int i = 0; i < content.count(); ++i) { - if (content.at(i).contains(".omwgame") || content.at(i).contains(".esm")) { + for (int i = 0; i < content.count(); ++i) + { + if (content.at(i).endsWith(QLatin1String(".omwgame"), Qt::CaseInsensitive) || content.at(i).endsWith(QLatin1String(".esm"), Qt::CaseInsensitive)) + { result = true; break; } diff --git a/components/contentselector/model/contentmodel.cpp b/components/contentselector/model/contentmodel.cpp index a7ac29b46..41407ec88 100644 --- a/components/contentselector/model/contentmodel.cpp +++ b/components/contentselector/model/contentmodel.cpp @@ -512,7 +512,9 @@ void ContentSelectorModel::ContentModel::sortFiles() //dependencies appear. for (int j = i + 1; j < fileCount; j++) { - if (gamefiles.contains(mFiles.at(j)->fileName(), Qt::CaseInsensitive)) + if (gamefiles.contains(mFiles.at(j)->fileName(), Qt::CaseInsensitive) + || (!mFiles.at(i)->isGameFile() && gamefiles.isEmpty() + && mFiles.at(j)->fileName().compare("Morrowind.esm", Qt::CaseInsensitive) == 0)) // Hack: implicit dependency on Morrowind.esm for dependency-less files { mFiles.move(j, i); diff --git a/components/esm/cellref.cpp b/components/esm/cellref.cpp index e41201d6e..f35149586 100644 --- a/components/esm/cellref.cpp +++ b/components/esm/cellref.cpp @@ -173,10 +173,10 @@ void ESM::CellRef::save (ESMWriter &esm, bool wideRefNum, bool inInventory, bool } if (!inInventory) + { esm.writeHNOCString ("KNAM", mKey); - - if (!inInventory) esm.writeHNOCString ("TNAM", mTrap); + } if (mReferenceBlocked != -1) esm.writeHNT("UNAM", mReferenceBlocked); @@ -188,7 +188,7 @@ void ESM::CellRef::save (ESMWriter &esm, bool wideRefNum, bool inInventory, bool void ESM::CellRef::blank() { mRefNum.unset(); - mRefID.clear(); + mRefID.clear(); mScale = 1; mOwner.clear(); mGlobalVariable.clear(); @@ -205,7 +205,7 @@ void ESM::CellRef::blank() mTrap.clear(); mReferenceBlocked = -1; mTeleport = false; - + for (int i=0; i<3; ++i) { mDoorDest.pos[i] = 0; diff --git a/components/esm/loadnpc.cpp b/components/esm/loadnpc.cpp index a68c97a6a..dd34934ad 100644 --- a/components/esm/loadnpc.cpp +++ b/components/esm/loadnpc.cpp @@ -62,12 +62,23 @@ namespace ESM if (esm.getSubSize() == 52) { mNpdtType = NPC_DEFAULT; - esm.getExact(&mNpdt52, 52); + esm.getExact(&mNpdt, 52); } else if (esm.getSubSize() == 12) { + //Reading into temporary NPDTstruct12 object + NPDTstruct12 npdt12; mNpdtType = NPC_WITH_AUTOCALCULATED_STATS; - esm.getExact(&mNpdt12, 12); + esm.getExact(&npdt12, 12); + + //Clearing the mNdpt struct to initialize all values + blankNpdt(); + //Swiching to an internal representation + mNpdt.mLevel = npdt12.mLevel; + mNpdt.mDisposition = npdt12.mDisposition; + mNpdt.mReputation = npdt12.mReputation; + mNpdt.mRank = npdt12.mRank; + mNpdt.mGold = npdt12.mGold; } else esm.fail("NPC_NPDT must be 12 or 52 bytes long"); @@ -135,9 +146,19 @@ namespace ESM esm.writeHNOCString("SCRI", mScript); if (mNpdtType == NPC_DEFAULT) - esm.writeHNT("NPDT", mNpdt52, 52); + { + esm.writeHNT("NPDT", mNpdt, 52); + } else if (mNpdtType == NPC_WITH_AUTOCALCULATED_STATS) - esm.writeHNT("NPDT", mNpdt12, 12); + { + NPDTstruct12 npdt12; + npdt12.mLevel = mNpdt.mLevel; + npdt12.mDisposition = mNpdt.mDisposition; + npdt12.mReputation = mNpdt.mReputation; + npdt12.mRank = mNpdt.mRank; + npdt12.mGold = mNpdt.mGold; + esm.writeHNT("NPDT", npdt12, 12); + } esm.writeHNT("FLAG", mFlags); @@ -171,25 +192,7 @@ namespace ESM void NPC::blank() { mNpdtType = NPC_DEFAULT; - mNpdt52.mLevel = 0; - mNpdt52.mStrength = mNpdt52.mIntelligence = mNpdt52.mWillpower = mNpdt52.mAgility = - mNpdt52.mSpeed = mNpdt52.mEndurance = mNpdt52.mPersonality = mNpdt52.mLuck = 0; - for (int i=0; i< Skill::Length; ++i) mNpdt52.mSkills[i] = 0; - mNpdt52.mReputation = 0; - mNpdt52.mHealth = mNpdt52.mMana = mNpdt52.mFatigue = 0; - mNpdt52.mDisposition = 0; - mNpdt52.mFactionID = 0; - mNpdt52.mRank = 0; - mNpdt52.mUnknown = 0; - mNpdt52.mGold = 0; - mNpdt12.mLevel = 0; - mNpdt12.mDisposition = 0; - mNpdt12.mReputation = 0; - mNpdt12.mRank = 0; - mNpdt12.mUnknown1 = 0; - mNpdt12.mUnknown2 = 0; - mNpdt12.mUnknown3 = 0; - mNpdt12.mGold = 0; + blankNpdt(); mFlags = 0; mInventory.mList.clear(); mSpells.mList.clear(); @@ -207,14 +210,27 @@ namespace ESM mHead.clear(); } + void NPC::blankNpdt() + { + mNpdt.mLevel = 0; + mNpdt.mStrength = mNpdt.mIntelligence = mNpdt.mWillpower = mNpdt.mAgility = + mNpdt.mSpeed = mNpdt.mEndurance = mNpdt.mPersonality = mNpdt.mLuck = 0; + for (int i=0; i< Skill::Length; ++i) mNpdt.mSkills[i] = 0; + mNpdt.mReputation = 0; + mNpdt.mHealth = mNpdt.mMana = mNpdt.mFatigue = 0; + mNpdt.mDisposition = 0; + mNpdt.mFactionID = 0; + mNpdt.mRank = 0; + mNpdt.mUnknown = 0; + mNpdt.mGold = 0; + } + int NPC::getFactionRank() const { if (mFaction.empty()) return -1; - else if (mNpdtType == ESM::NPC::NPC_WITH_AUTOCALCULATED_STATS) - return mNpdt12.mRank; - else // NPC_DEFAULT - return mNpdt52.mRank; + else + return mNpdt.mRank; } const std::vector& NPC::getTransport() const diff --git a/components/esm/loadnpc.hpp b/components/esm/loadnpc.hpp index d7f30e079..5f567d999 100644 --- a/components/esm/loadnpc.hpp +++ b/components/esm/loadnpc.hpp @@ -95,6 +95,8 @@ struct NPC int mGold; }; // 52 bytes + //Structure for autocalculated characters. + // This is only used for load and save operations. struct NPDTstruct12 { short mLevel; @@ -106,8 +108,9 @@ struct NPC #pragma pack(pop) unsigned char mNpdtType; - NPDTstruct52 mNpdt52; - NPDTstruct12 mNpdt12; //for autocalculated characters + //Worth noting when saving the struct: + // Although we might read a NPDTstruct12 in, we use NPDTstruct52 internally + NPDTstruct52 mNpdt; int getFactionRank() const; /// wrapper for mNpdt*, -1 = no rank @@ -141,6 +144,9 @@ struct NPC void blank(); ///< Set record to default state (does not touch the ID). + + /// Resets the mNpdt object + void blankNpdt(); }; } #endif diff --git a/components/esm/loadregn.cpp b/components/esm/loadregn.cpp index 6e0e6db9d..e708bbb4e 100644 --- a/components/esm/loadregn.cpp +++ b/components/esm/loadregn.cpp @@ -109,8 +109,6 @@ namespace ESM void Region::blank() { - mName.clear(); - mData.mClear = mData.mCloudy = mData.mFoggy = mData.mOvercast = mData.mRain = mData.mThunder = mData.mAsh, mData.mBlight = mData.mA = mData.mB = 0; diff --git a/components/esm/loadstat.hpp b/components/esm/loadstat.hpp index 930cdb849..f80875b65 100644 --- a/components/esm/loadstat.hpp +++ b/components/esm/loadstat.hpp @@ -26,13 +26,23 @@ struct Static /// Return a string descriptor for this record type. Currently used for debugging / error logs only. static std::string getRecordType() { return "Static"; } - std::string mId, mModel; + std::string mId, mModel; - void load(ESMReader &esm, bool &isDeleted); - void save(ESMWriter &esm, bool isDeleted = false) const; + void load(ESMReader &esm, bool &isDeleted); + void save(ESMWriter &esm, bool isDeleted = false) const; void blank(); ///< Set record to default state (does not touch the ID). + + Static(const std::string id, const std::string &model) + : mId(id) + , mModel(model) + { + } + + Static() + { + } }; } #endif diff --git a/components/esmterrain/storage.cpp b/components/esmterrain/storage.cpp index 63efb36be..dc144d119 100644 --- a/components/esmterrain/storage.cpp +++ b/components/esmterrain/storage.cpp @@ -232,9 +232,9 @@ namespace ESMTerrain // Skip the first row / column unless we're at a chunk edge, // since this row / column is already contained in a previous cell // This is only relevant if we're creating a chunk spanning multiple cells - if (colStart == 0 && vertY_ != 0) + if (vertY_ != 0) colStart += increment; - if (rowStart == 0 && vertX_ != 0) + if (vertX_ != 0) rowStart += increment; // Only relevant for chunks smaller than (contained in) one cell diff --git a/components/fallback/fallback.cpp b/components/fallback/fallback.cpp index 11a577a45..edc3f2678 100644 --- a/components/fallback/fallback.cpp +++ b/components/fallback/fallback.cpp @@ -25,7 +25,7 @@ namespace Fallback float Map::getFallbackFloat(const std::string& fall) const { std::string fallback=getFallbackString(fall); - if(fallback.empty()) + if (fallback.empty()) return 0; else return boost::lexical_cast(fallback); @@ -34,7 +34,7 @@ namespace Fallback int Map::getFallbackInt(const std::string& fall) const { std::string fallback=getFallbackString(fall); - if(fallback.empty()) + if (fallback.empty()) return 0; else return std::stoi(fallback); @@ -43,7 +43,7 @@ namespace Fallback bool Map::getFallbackBool(const std::string& fall) const { std::string fallback=getFallbackString(fall); - if(fallback.empty()) + if (fallback.empty()) return false; else return stob(fallback); @@ -52,8 +52,8 @@ namespace Fallback osg::Vec4f Map::getFallbackColour(const std::string& fall) const { std::string sum=getFallbackString(fall); - if(sum.empty()) - return osg::Vec4f(0.f,0.f,0.f,1.f); + if (sum.empty()) + return osg::Vec4f(0.5f,0.5f,0.5f,1.f); else { std::string ret[3]; diff --git a/components/fontloader/fontloader.cpp b/components/fontloader/fontloader.cpp index aa92a01c6..080739bc1 100644 --- a/components/fontloader/fontloader.cpp +++ b/components/fontloader/fontloader.cpp @@ -339,52 +339,76 @@ namespace Gui + MyGUI::utility::toString((fontSize-data[i].ascent))); 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. - if (mEncoding == ToUTF8::CP437) + // Fall back from unavailable Windows-1252 encoding symbols to similar characters available in the game fonts + std::multimap additional; // fallback glyph index, unicode + additional.insert(std::make_pair(156, 0x00A2)); // cent sign + additional.insert(std::make_pair(89, 0x00A5)); // yen sign + additional.insert(std::make_pair(221, 0x00A6)); // broken bar + additional.insert(std::make_pair(99, 0x00A9)); // copyright sign + additional.insert(std::make_pair(97, 0x00AA)); // prima ordinal indicator + additional.insert(std::make_pair(60, 0x00AB)); // double left-pointing angle quotation mark + additional.insert(std::make_pair(45, 0x00AD)); // soft hyphen + additional.insert(std::make_pair(114, 0x00AE)); // registered trademark symbol + additional.insert(std::make_pair(45, 0x00AF)); // macron + additional.insert(std::make_pair(241, 0x00B1)); // plus-minus sign + additional.insert(std::make_pair(50, 0x00B2)); // superscript two + additional.insert(std::make_pair(51, 0x00B3)); // superscript three + additional.insert(std::make_pair(44, 0x00B8)); // cedilla + additional.insert(std::make_pair(49, 0x00B9)); // superscript one + additional.insert(std::make_pair(111, 0x00BA)); // primo ordinal indicator + additional.insert(std::make_pair(62, 0x00BB)); // double right-pointing angle quotation mark + additional.insert(std::make_pair(63, 0x00BF)); // inverted question mark + additional.insert(std::make_pair(65, 0x00C6)); // latin capital ae ligature + additional.insert(std::make_pair(79, 0x00D8)); // latin capital o with stroke + additional.insert(std::make_pair(97, 0x00E6)); // latin small ae ligature + additional.insert(std::make_pair(111, 0x00F8)); // latin small o with stroke + additional.insert(std::make_pair(79, 0x0152)); // latin capital oe ligature + additional.insert(std::make_pair(111, 0x0153)); // latin small oe ligature + additional.insert(std::make_pair(83, 0x015A)); // latin capital s with caron + additional.insert(std::make_pair(115, 0x015B)); // latin small s with caron + additional.insert(std::make_pair(89, 0x0178)); // latin capital y with diaresis + additional.insert(std::make_pair(90, 0x017D)); // latin capital z with caron + additional.insert(std::make_pair(122, 0x017E)); // latin small z with caron + additional.insert(std::make_pair(102, 0x0192)); // latin small f with hook + additional.insert(std::make_pair(94, 0x02C6)); // circumflex modifier + additional.insert(std::make_pair(126, 0x02DC)); // small tilde + additional.insert(std::make_pair(69, 0x0401)); // cyrillic capital io (no diaeresis latin e is available) + additional.insert(std::make_pair(137, 0x0451)); // cyrillic small io + additional.insert(std::make_pair(45, 0x2012)); // figure dash + additional.insert(std::make_pair(45, 0x2013)); // en dash + additional.insert(std::make_pair(45, 0x2014)); // em dash + additional.insert(std::make_pair(39, 0x2018)); // left single quotation mark + additional.insert(std::make_pair(39, 0x2019)); // right single quotation mark + additional.insert(std::make_pair(44, 0x201A)); // single low quotation mark + additional.insert(std::make_pair(39, 0x201B)); // single high quotation mark (reversed) + additional.insert(std::make_pair(34, 0x201C)); // left double quotation mark + additional.insert(std::make_pair(34, 0x201D)); // right double quotation mark + additional.insert(std::make_pair(44, 0x201E)); // double low quotation mark + additional.insert(std::make_pair(34, 0x201F)); // double high quotation mark (reversed) + additional.insert(std::make_pair(43, 0x2020)); // dagger + additional.insert(std::make_pair(216, 0x2021)); // double dagger (note: this glyph is not available) + additional.insert(std::make_pair(46, 0x2026)); // ellipsis + additional.insert(std::make_pair(37, 0x2030)); // per mille sign + additional.insert(std::make_pair(60, 0x2039)); // single left-pointing angle quotation mark + additional.insert(std::make_pair(62, 0x203A)); // single right-pointing angle quotation mark + additional.insert(std::make_pair(101, 0x20AC)); // euro sign + additional.insert(std::make_pair(84, 0x2122)); // trademark sign + additional.insert(std::make_pair(45, 0x2212)); // minus sign + + for (std::multimap::iterator it = additional.begin(); it != additional.end(); ++it) { - std::multimap additional; // - additional.insert(std::make_pair(39, 0x2019)); // apostrophe - additional.insert(std::make_pair(45, 0x2013)); // dash - additional.insert(std::make_pair(45, 0x2014)); // dash - additional.insert(std::make_pair(34, 0x201D)); // right double quotation mark - additional.insert(std::make_pair(34, 0x201C)); // left double quotation mark - additional.insert(std::make_pair(44, 0x201A)); - additional.insert(std::make_pair(44, 0x201E)); - additional.insert(std::make_pair(43, 0x2020)); - additional.insert(std::make_pair(94, 0x02C6)); - additional.insert(std::make_pair(37, 0x2030)); - additional.insert(std::make_pair(83, 0x0160)); - additional.insert(std::make_pair(60, 0x2039)); - additional.insert(std::make_pair(79, 0x0152)); - additional.insert(std::make_pair(90, 0x017D)); - additional.insert(std::make_pair(39, 0x2019)); - additional.insert(std::make_pair(126, 0x02DC)); - additional.insert(std::make_pair(84, 0x2122)); - additional.insert(std::make_pair(83, 0x0161)); - additional.insert(std::make_pair(62, 0x203A)); - additional.insert(std::make_pair(111, 0x0153)); - additional.insert(std::make_pair(122, 0x017E)); - additional.insert(std::make_pair(89, 0x0178)); - additional.insert(std::make_pair(156, 0x00A2)); - additional.insert(std::make_pair(46, 0x2026)); - - for (std::multimap::iterator it = additional.begin(); it != additional.end(); ++it) - { - if (it->first != i) - continue; - - code = codes->createChild("Code"); - code->addAttribute("index", it->second); - code->addAttribute("coord", MyGUI::utility::toString(x1) + " " - + MyGUI::utility::toString(y1) + " " - + MyGUI::utility::toString(w) + " " - + MyGUI::utility::toString(h)); - 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(static_cast(data[i].width), static_cast(data[i].height))); - } + if (it->first != i) + continue; + code = codes->createChild("Code"); + code->addAttribute("index", it->second); + code->addAttribute("coord", MyGUI::utility::toString(x1) + " " + + MyGUI::utility::toString(y1) + " " + + MyGUI::utility::toString(w) + " " + + MyGUI::utility::toString(h)); + 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(static_cast(data[i].width), static_cast(data[i].height))); } // ASCII vertical bar, use this as text input cursor @@ -424,7 +448,7 @@ namespace Gui MyGUI::FontCodeType::Enum type; if(i == 0) type = MyGUI::FontCodeType::Selected; - else if (i == 1) + else // if (i == 1) type = MyGUI::FontCodeType::SelectedBack; MyGUI::xml::ElementPtr cursorCode = codes->createChild("Code"); diff --git a/components/misc/resourcehelpers.cpp b/components/misc/resourcehelpers.cpp index 5cf4378b8..f38387ff8 100644 --- a/components/misc/resourcehelpers.cpp +++ b/components/misc/resourcehelpers.cpp @@ -63,28 +63,16 @@ std::string Misc::ResourceHelpers::correctResourcePath(const std::string &topLev std::string origExt = correctedPath; - // since we know all (GOTY edition or less) textures end - // in .dds, we change the extension - bool changedToDds = changeExtensionToDds(correctedPath); - if (vfs->exists(correctedPath)) + if (vfs->exists(origExt) + || (changeExtensionToDds(correctedPath) && vfs->exists(correctedPath))) return correctedPath; - // if it turns out that the above wasn't true in all cases (not for vanilla, but maybe mods) - // verify, and revert if false (this call succeeds quickly, but fails slowly) - if (changedToDds && vfs->exists(origExt)) - return origExt; // fall back to a resource in the top level directory if it exists - std::string fallback = topLevelDirectory + "\\" + getBasename(correctedPath); - if (vfs->exists(fallback)) + std::string fallback = topLevelDirectory + "\\" + getBasename(origExt); + if (vfs->exists(fallback) + || (changeExtensionToDds(fallback) && vfs->exists(fallback))) return fallback; - if (changedToDds) - { - fallback = topLevelDirectory + "\\" + getBasename(origExt); - if (vfs->exists(fallback)) - return fallback; - } - return correctedPath; } diff --git a/components/misc/rng.cpp b/components/misc/rng.cpp index df0fc687e..e402f0b79 100644 --- a/components/misc/rng.cpp +++ b/components/misc/rng.cpp @@ -1,28 +1,31 @@ #include "rng.hpp" -#include -#include + +#include +#include namespace Misc { + std::mt19937 Rng::generator = std::mt19937(); + void Rng::init() { - std::srand(static_cast(std::time(NULL))); + generator.seed(static_cast(std::chrono::high_resolution_clock::now().time_since_epoch().count())); } float Rng::rollProbability() { - return static_cast(std::rand() / (static_cast(RAND_MAX)+1.0)); + return std::uniform_real_distribution(0, 1 - std::numeric_limits::epsilon())(generator); } float Rng::rollClosedProbability() { - return static_cast(std::rand() / static_cast(RAND_MAX)); + return std::uniform_real_distribution(0, 1)(generator); } int Rng::rollDice(int max) { - return static_cast((std::rand() / (static_cast(RAND_MAX)+1.0)) * (max)); + return max > 0 ? std::uniform_int_distribution(0, max - 1)(generator) : 0; } } diff --git a/components/misc/rng.hpp b/components/misc/rng.hpp index 01fcdd763..ff56906d9 100644 --- a/components/misc/rng.hpp +++ b/components/misc/rng.hpp @@ -2,6 +2,7 @@ #define OPENMW_COMPONENTS_MISC_RNG_H #include +#include namespace Misc { @@ -13,6 +14,9 @@ class Rng { public: + /// create a RNG + static std::mt19937 generator; + /// seed the RNG static void init(); diff --git a/components/nif/controlled.hpp b/components/nif/controlled.hpp index 5601474ac..be48e912e 100644 --- a/components/nif/controlled.hpp +++ b/components/nif/controlled.hpp @@ -2,7 +2,7 @@ OpenMW - The completely unofficial reimplementation of Morrowind Copyright (C) 2008-2010 Nicolay Korslund Email: < korslund@gmail.com > - WWW: http://openmw.sourceforge.net/ + WWW: https://openmw.org/ This file (controlled.h) is part of the OpenMW package. @@ -17,7 +17,7 @@ You should have received a copy of the GNU General Public License version 3 along with this program. If not, see - http://www.gnu.org/licenses/ . + https://www.gnu.org/licenses/ . */ diff --git a/components/nif/controller.cpp b/components/nif/controller.cpp index f39132543..ddfa02a09 100644 --- a/components/nif/controller.cpp +++ b/components/nif/controller.cpp @@ -101,6 +101,18 @@ namespace Nif data.post(nif); } + void NiLookAtController::read(NIFStream *nif) + { + Controller::read(nif); + data.read(nif); + } + + void NiLookAtController::post(NIFFile *nif) + { + Controller::post(nif); + data.post(nif); + } + void NiPathController::read(NIFStream *nif) { Controller::read(nif); diff --git a/components/nif/controller.hpp b/components/nif/controller.hpp index 0861dfa6b..ce8bff041 100644 --- a/components/nif/controller.hpp +++ b/components/nif/controller.hpp @@ -2,7 +2,7 @@ OpenMW - The completely unofficial reimplementation of Morrowind Copyright (C) 2008-2010 Nicolay Korslund Email: < korslund@gmail.com > - WWW: http://openmw.sourceforge.net/ + WWW: https://openmw.org/ This file (controller.h) is part of the OpenMW package. @@ -17,7 +17,7 @@ You should have received a copy of the GNU General Public License version 3 along with this program. If not, see - http://www.gnu.org/licenses/ . + https://www.gnu.org/licenses/ . */ @@ -99,6 +99,15 @@ public: void post(NIFFile *nif); }; +class NiLookAtController : public Controller +{ +public: + NiKeyframeDataPtr data; + + void read(NIFStream *nif); + void post(NIFFile *nif); +}; + class NiUVController : public Controller { public: diff --git a/components/nif/data.hpp b/components/nif/data.hpp index 9b4a3a67c..6b7aa579b 100644 --- a/components/nif/data.hpp +++ b/components/nif/data.hpp @@ -2,7 +2,7 @@ OpenMW - The completely unofficial reimplementation of Morrowind Copyright (C) 2008-2010 Nicolay Korslund Email: < korslund@gmail.com > - WWW: http://openmw.sourceforge.net/ + WWW: https://openmw.org/ This file (data.h) is part of the OpenMW package. @@ -17,7 +17,7 @@ You should have received a copy of the GNU General Public License version 3 along with this program. If not, see - http://www.gnu.org/licenses/ . + https://www.gnu.org/licenses/ . */ diff --git a/components/nif/effect.hpp b/components/nif/effect.hpp index 015809a68..453e4b04c 100644 --- a/components/nif/effect.hpp +++ b/components/nif/effect.hpp @@ -2,7 +2,7 @@ OpenMW - The completely unofficial reimplementation of Morrowind Copyright (C) 2008-2010 Nicolay Korslund Email: < korslund@gmail.com > - WWW: http://openmw.sourceforge.net/ + WWW: https://openmw.org/ This file (effect.h) is part of the OpenMW package. @@ -17,7 +17,7 @@ You should have received a copy of the GNU General Public License version 3 along with this program. If not, see - http://www.gnu.org/licenses/ . + https://www.gnu.org/licenses/ . */ diff --git a/components/nif/extra.hpp b/components/nif/extra.hpp index 1e5a8616d..d935add55 100644 --- a/components/nif/extra.hpp +++ b/components/nif/extra.hpp @@ -2,7 +2,7 @@ OpenMW - The completely unofficial reimplementation of Morrowind Copyright (C) 2008-2010 Nicolay Korslund Email: < korslund@gmail.com > - WWW: http://openmw.sourceforge.net/ + WWW: https://openmw.org/ This file (extra.h) is part of the OpenMW package. @@ -17,7 +17,7 @@ You should have received a copy of the GNU General Public License version 3 along with this program. If not, see - http://www.gnu.org/licenses/ . + https://www.gnu.org/licenses/ . */ diff --git a/components/nif/niffile.cpp b/components/nif/niffile.cpp index b4b1caefc..4061247b5 100644 --- a/components/nif/niffile.cpp +++ b/components/nif/niffile.cpp @@ -108,6 +108,7 @@ static std::map makeFactory() newFactory.insert(makeEntry("NiSequenceStreamHelper", &construct , RC_NiSequenceStreamHelper )); newFactory.insert(makeEntry("NiSourceTexture", &construct , RC_NiSourceTexture )); newFactory.insert(makeEntry("NiSkinInstance", &construct , RC_NiSkinInstance )); + newFactory.insert(makeEntry("NiLookAtController", &construct , RC_NiLookAtController )); return newFactory; } diff --git a/components/nif/niftypes.hpp b/components/nif/niftypes.hpp index 5827448fd..778625717 100644 --- a/components/nif/niftypes.hpp +++ b/components/nif/niftypes.hpp @@ -2,7 +2,7 @@ OpenMW - The completely unofficial reimplementation of Morrowind Copyright (C) 2008-2010 Nicolay Korslund Email: < korslund@gmail.com > - WWW: http://openmw.sourceforge.net/ + WWW: https://openmw.org/ This file (nif_types.h) is part of the OpenMW package. @@ -17,7 +17,7 @@ You should have received a copy of the GNU General Public License version 3 along with this program. If not, see - http://www.gnu.org/licenses/ . + https://www.gnu.org/licenses/ . */ diff --git a/components/nif/property.hpp b/components/nif/property.hpp index 96156c6d8..f46f8ef27 100644 --- a/components/nif/property.hpp +++ b/components/nif/property.hpp @@ -2,7 +2,7 @@ OpenMW - The completely unofficial reimplementation of Morrowind Copyright (C) 2008-2010 Nicolay Korslund Email: < korslund@gmail.com > - WWW: http://openmw.sourceforge.net/ + WWW: https://openmw.org/ This file (property.h) is part of the OpenMW package. @@ -17,7 +17,7 @@ You should have received a copy of the GNU General Public License version 3 along with this program. If not, see - http://www.gnu.org/licenses/ . + https://www.gnu.org/licenses/ . */ diff --git a/components/nif/record.hpp b/components/nif/record.hpp index 605c4d76e..ee4d508ab 100644 --- a/components/nif/record.hpp +++ b/components/nif/record.hpp @@ -2,7 +2,7 @@ OpenMW - The completely unofficial reimplementation of Morrowind Copyright (C) 2008-2010 Nicolay Korslund Email: < korslund@gmail.com > - WWW: http://openmw.sourceforge.net/ + WWW: https://openmw.org/ This file (record.h) is part of the OpenMW package. @@ -17,7 +17,7 @@ You should have received a copy of the GNU General Public License version 3 along with this program. If not, see - http://www.gnu.org/licenses/ . + https://www.gnu.org/licenses/ . */ @@ -93,7 +93,8 @@ enum RecordType RC_NiSourceTexture, RC_NiSkinInstance, RC_RootCollisionNode, - RC_NiSphericalCollider + RC_NiSphericalCollider, + RC_NiLookAtController }; /// Base class for all records diff --git a/components/nifosg/nifloader.cpp b/components/nifosg/nifloader.cpp index 6e04c6405..0add92f29 100644 --- a/components/nifosg/nifloader.cpp +++ b/components/nifosg/nifloader.cpp @@ -275,7 +275,6 @@ namespace NifOsg for (unsigned int i=0; igetNumChildren(); ++i) skel->addChild(root->getChild(i)); root->removeChildren(0, root->getNumChildren()); - created = skel; } else skel->addChild(created); diff --git a/components/sceneutil/controller.hpp b/components/sceneutil/controller.hpp index 775cb23b0..d02b65cf1 100644 --- a/components/sceneutil/controller.hpp +++ b/components/sceneutil/controller.hpp @@ -25,6 +25,8 @@ namespace SceneUtil class ControllerFunction { public: + virtual ~ControllerFunction() = default; + virtual float calculate(float input) const = 0; /// Get the "stop time" of the controller function, typically the maximum of the calculate() function. diff --git a/components/sceneutil/morphgeometry.hpp b/components/sceneutil/morphgeometry.hpp index 122c1456c..ba3b40961 100644 --- a/components/sceneutil/morphgeometry.hpp +++ b/components/sceneutil/morphgeometry.hpp @@ -21,6 +21,9 @@ namespace SceneUtil /// @note The source geometry will not be modified. void setSourceGeometry(osg::ref_ptr sourceGeom); + // Currently empty as this is difficult to implement. Technically we would need to compile both internal geometries in separate frames but this method is only called once. Alternatively we could compile just the static parts of the model. + virtual void compileGLObjects(osg::RenderInfo& renderInfo) const {} + class MorphTarget { protected: diff --git a/components/sceneutil/riggeometry.hpp b/components/sceneutil/riggeometry.hpp index 64f4bf312..60b3edc9d 100644 --- a/components/sceneutil/riggeometry.hpp +++ b/components/sceneutil/riggeometry.hpp @@ -23,8 +23,8 @@ namespace SceneUtil META_Object(SceneUtil, RigGeometry) - // At this point compileGLObjects() remains unimplemented, hard to avoid race conditions - // and there is limited value in compiling anyway since the data will change again for the next frame + // Currently empty as this is difficult to implement. Technically we would need to compile both internal geometries in separate frames but this method is only called once. Alternatively we could compile just the static parts of the model. + virtual void compileGLObjects(osg::RenderInfo& renderInfo) const {} struct BoneInfluence { diff --git a/components/sdlutil/sdlgraphicswindow.cpp b/components/sdlutil/sdlgraphicswindow.cpp index de82ca850..f9767238f 100644 --- a/components/sdlutil/sdlgraphicswindow.cpp +++ b/components/sdlutil/sdlgraphicswindow.cpp @@ -91,7 +91,7 @@ void GraphicsWindowSDL2::init() SDL_Window *oldWin = SDL_GL_GetCurrentWindow(); SDL_GLContext oldCtx = SDL_GL_GetCurrentContext(); -#if defined(OPENGL_ES) || defined(ANDROID) +#if defined(ANDROID) int major = 1; int minor = 1; char *ver = getenv("OPENMW_GLES_VERSION"); diff --git a/components/settings/settings.cpp b/components/settings/settings.cpp index 2e7b5a8ae..15a222d31 100644 --- a/components/settings/settings.cpp +++ b/components/settings/settings.cpp @@ -292,7 +292,7 @@ public: ostream << "# to its default, simply remove it from this file. For available" << std::endl; ostream << "# settings, see the file 'settings-default.cfg' or the documentation at:" << std::endl; ostream << "#" << std::endl; - ostream << "# http://openmw.readthedocs.io/en/master/reference/modding/settings/index.html" << std::endl; + ostream << "# https://openmw.readthedocs.io/en/master/reference/modding/settings/index.html" << std::endl; } // We still have one more thing to do before we're completely done writing the file. diff --git a/components/widgets/imagebutton.cpp b/components/widgets/imagebutton.cpp index ab0739c2c..a3b0ae28a 100644 --- a/components/widgets/imagebutton.cpp +++ b/components/widgets/imagebutton.cpp @@ -5,13 +5,20 @@ namespace Gui { + bool ImageButton::sDefaultNeedKeyFocus = true; + ImageButton::ImageButton() : Base() , mMouseFocus(false) , mMousePress(false) , mKeyFocus(false) { - setNeedKeyFocus(true); + setNeedKeyFocus(sDefaultNeedKeyFocus); + } + + void ImageButton::setDefaultNeedKeyFocus(bool enabled) + { + sDefaultNeedKeyFocus = enabled; } void ImageButton::setPropertyOverride(const std::string &_key, const std::string &_value) diff --git a/components/widgets/imagebutton.hpp b/components/widgets/imagebutton.hpp index 509b1c8c2..bfcff7997 100644 --- a/components/widgets/imagebutton.hpp +++ b/components/widgets/imagebutton.hpp @@ -18,12 +18,16 @@ namespace Gui ImageButton(); + static void setDefaultNeedKeyFocus(bool enabled); + /// Set mImageNormal, mImageHighlighted and mImagePushed based on file convention (image_idle.ext, image_over.ext and image_pressed.ext) void setImage(const std::string& image); private: void updateImage(); + static bool sDefaultNeedKeyFocus; + protected: virtual void setPropertyOverride(const std::string& _key, const std::string& _value); virtual void onMouseLostFocus(MyGUI::Widget* _new); diff --git a/docs/Doxyfile.cmake b/docs/Doxyfile.cmake index 38ad84165..71ce32069 100644 --- a/docs/Doxyfile.cmake +++ b/docs/Doxyfile.cmake @@ -20,7 +20,7 @@ # This tag specifies the encoding used for all characters in the config file # that follow. The default is UTF-8 which is also the encoding used for all text # before the first occurrence of this tag. Doxygen uses libiconv (or the iconv -# built into libc) for the transcoding. See http://www.gnu.org/software/libiconv +# built into libc) for the transcoding. See https://www.gnu.org/software/libiconv # for the list of possible encodings. # The default value is: UTF-8. @@ -295,7 +295,7 @@ EXTENSION_MAPPING = # If the MARKDOWN_SUPPORT tag is enabled then doxygen pre-processes all comments # according to the Markdown format, which allows for more readable -# documentation. See http://daringfireball.net/projects/markdown/ for details. +# documentation. See https://daringfireball.net/projects/markdown/ for details. # The output of markdown processing is further processed by doxygen, so you can # mix doxygen, HTML, and XML commands with Markdown formatting. Disable only in # case of backward compatibilities issues. @@ -328,7 +328,7 @@ BUILTIN_STL_SUPPORT = YES CPP_CLI_SUPPORT = NO # Set the SIP_SUPPORT tag to YES if your project consists of sip (see: -# http://www.riverbankcomputing.co.uk/software/sip/intro) sources only. Doxygen +# https://riverbankcomputing.com/software/sip/intro) sources only. Doxygen # will parse them like normal C++ but will assume all classes use public instead # of private inheritance when no explicit protection keyword is present. # The default value is: NO. @@ -687,7 +687,7 @@ LAYOUT_FILE = # The CITE_BIB_FILES tag can be used to specify one or more bib files containing # the reference definitions. This must be a list of .bib files. The .bib # extension is automatically appended if omitted. This requires the bibtex tool -# to be installed. See also http://en.wikipedia.org/wiki/BibTeX for more info. +# to be installed. See also https://en.wikipedia.org/wiki/BibTeX for more info. # For LaTeX the style of the bibliography can be controlled using # LATEX_BIB_STYLE. To use this feature you need bibtex and perl available in the # search path. Do not use file names with spaces, bibtex cannot handle them. See @@ -772,7 +772,7 @@ INPUT = @OpenMW_SOURCE_DIR@/apps \ # This tag can be used to specify the character encoding of the source files # that doxygen parses. Internally doxygen uses the UTF-8 encoding. Doxygen uses # libiconv (or the iconv built into libc) for the transcoding. See the libiconv -# documentation (see: http://www.gnu.org/software/libiconv) for the list of +# documentation (see: https://www.gnu.org/software/libiconv) for the list of # possible encodings. # The default value is: UTF-8. @@ -993,7 +993,7 @@ SOURCE_TOOLTIPS = YES # If the USE_HTAGS tag is set to YES then the references to source code will # point to the HTML generated by the htags(1) tool instead of doxygen built-in # source browser. The htags tool is part of GNU's global source tagging system -# (see http://www.gnu.org/software/global/global.html). You will need version +# (see https://www.gnu.org/software/global/global.html). You will need version # 4.8.6 or higher. # # To use it do the following: @@ -1136,7 +1136,7 @@ HTML_EXTRA_FILES = # The HTML_COLORSTYLE_HUE tag controls the color of the HTML output. Doxygen # will adjust the colors in the stylesheet and background images according to # this color. Hue is specified as an angle on a colorwheel, see -# http://en.wikipedia.org/wiki/Hue for more information. For instance the value +# https://en.wikipedia.org/wiki/Hue for more information. For instance the value # 0 represents red, 60 is yellow, 120 is green, 180 is cyan, 240 is blue, 300 # purple, and 360 is red again. # Minimum value: 0, maximum value: 359, default value: 220. @@ -1194,7 +1194,7 @@ HTML_INDEX_NUM_ENTRIES = 100 # If the GENERATE_DOCSET tag is set to YES, additional index files will be # generated that can be used as input for Apple's Xcode 3 integrated development -# environment (see: http://developer.apple.com/tools/xcode/), introduced with +# environment (see: https://developer.apple.com/xcode/), introduced with # OSX 10.5 (Leopard). To create a documentation set, doxygen will generate a # Makefile in the HTML output directory. Running make will produce the docset in # that directory and running make install will install the docset in @@ -1239,7 +1239,7 @@ DOCSET_PUBLISHER_NAME = OpenMW # If the GENERATE_HTMLHELP tag is set to YES then doxygen generates three # additional HTML index files: index.hhp, index.hhc, and index.hhk. The # index.hhp is a project file that can be read by Microsoft's HTML Help Workshop -# (see: http://www.microsoft.com/en-us/download/details.aspx?id=21138) on +# (see: https://www.microsoft.com/en-us/download/details.aspx?id=21138) on # Windows. # # The HTML Help Workshop contains a compiler that can convert all HTML output @@ -1315,7 +1315,7 @@ QCH_FILE = # The QHP_NAMESPACE tag specifies the namespace to use when generating Qt Help # Project output. For more information please see Qt Help Project / Namespace -# (see: http://qt-project.org/doc/qt-4.8/qthelpproject.html#namespace). +# (see: https://doc.qt.io/archives/qt-4.8/qthelpproject.html#namespace). # The default value is: org.doxygen.Project. # This tag requires that the tag GENERATE_QHP is set to YES. @@ -1323,8 +1323,7 @@ QHP_NAMESPACE = org.openmw # The QHP_VIRTUAL_FOLDER tag specifies the namespace to use when generating Qt # Help Project output. For more information please see Qt Help Project / Virtual -# Folders (see: http://qt-project.org/doc/qt-4.8/qthelpproject.html#virtual- -# folders). +# Folders (see: https://doc.qt.io/archives/qt-4.8/qthelpproject.html#virtual-folders). # The default value is: doc. # This tag requires that the tag GENERATE_QHP is set to YES. @@ -1332,23 +1331,21 @@ QHP_VIRTUAL_FOLDER = doc # If the QHP_CUST_FILTER_NAME tag is set, it specifies the name of a custom # filter to add. For more information please see Qt Help Project / Custom -# Filters (see: http://qt-project.org/doc/qt-4.8/qthelpproject.html#custom- -# filters). +# Filters (see: https://doc.qt.io/archives/qt-4.8/qthelpproject.html#custom-filters). # This tag requires that the tag GENERATE_QHP is set to YES. QHP_CUST_FILTER_NAME = # The QHP_CUST_FILTER_ATTRS tag specifies the list of the attributes of the # custom filter to add. For more information please see Qt Help Project / Custom -# Filters (see: http://qt-project.org/doc/qt-4.8/qthelpproject.html#custom- -# filters). +# Filters (see: https://doc.qt.io/archives/qt-4.8/qthelpproject.html#custom-filters). # This tag requires that the tag GENERATE_QHP is set to YES. QHP_CUST_FILTER_ATTRS = # The QHP_SECT_FILTER_ATTRS tag specifies the list of the attributes this # project's filter section matches. Qt Help Project / Filter Attributes (see: -# http://qt-project.org/doc/qt-4.8/qthelpproject.html#filter-attributes). +# https://doc.qt.io/archives/qt-4.8/qthelpproject.html#filter-attributes). # This tag requires that the tag GENERATE_QHP is set to YES. QHP_SECT_FILTER_ATTRS = @@ -1453,7 +1450,7 @@ FORMULA_FONTSIZE = 10 FORMULA_TRANSPARENT = YES # Enable the USE_MATHJAX option to render LaTeX formulas using MathJax (see -# http://www.mathjax.org) which uses client side Javascript for the rendering +# https://www.mathjax.org) which uses client side Javascript for the rendering # instead of using prerendered bitmaps. Use this if you do not have LaTeX # installed or if you want to formulas look prettier in the HTML output. When # enabled you may also need to install MathJax separately and configure the path @@ -1465,7 +1462,7 @@ USE_MATHJAX = YES # When MathJax is enabled you can set the default output format to be used for # the MathJax output. See the MathJax site (see: -# http://docs.mathjax.org/en/latest/output.html) for more details. +# https://docs.mathjax.org/en/latest/output.html) for more details. # Possible values are: HTML-CSS (which is slower, but has the best # compatibility), NativeMML (i.e. MathML) and SVG. # The default value is: HTML-CSS. @@ -1480,11 +1477,11 @@ MATHJAX_FORMAT = HTML-CSS # MATHJAX_RELPATH should be ../mathjax. The default value points to the MathJax # Content Delivery Network so you can quickly see the result without installing # MathJax. However, it is strongly recommended to install a local copy of -# MathJax from http://www.mathjax.org before deployment. -# The default value is: http://cdn.mathjax.org/mathjax/latest. +# MathJax from https://www.mathjax.org before deployment. +# The default value is: https://cdn.mathjax.org/mathjax/latest. # This tag requires that the tag USE_MATHJAX is set to YES. -MATHJAX_RELPATH = http://cdn.mathjax.org/mathjax/latest +MATHJAX_RELPATH = https://cdn.mathjax.org/mathjax/latest # The MATHJAX_EXTENSIONS tag can be used to specify one or more MathJax # extension names that should be enabled during MathJax rendering. For example @@ -1495,7 +1492,7 @@ MATHJAX_EXTENSIONS = # The MATHJAX_CODEFILE tag can be used to specify a file with javascript pieces # of code that will be used on startup of the MathJax code. See the MathJax site -# (see: http://docs.mathjax.org/en/latest/output.html) for more details. For an +# (see: https://docs.mathjax.org/en/latest/output.html) for more details. For an # example see the documentation. # This tag requires that the tag USE_MATHJAX is set to YES. @@ -1542,7 +1539,7 @@ SERVER_BASED_SEARCH = NO # # Doxygen ships with an example indexer ( doxyindexer) and search engine # (doxysearch.cgi) which are based on the open source search engine library -# Xapian (see: http://xapian.org/). +# Xapian (see: https://xapian.org/). # # See the section "External Indexing and Searching" for details. # The default value is: NO. @@ -1555,7 +1552,7 @@ EXTERNAL_SEARCH = NO # # Doxygen ships with an example indexer ( doxyindexer) and search engine # (doxysearch.cgi) which are based on the open source search engine library -# Xapian (see: http://xapian.org/). See the section "External Indexing and +# Xapian (see: https://xapian.org/). See the section "External Indexing and # Searching" for details. # This tag requires that the tag SEARCHENGINE is set to YES. @@ -1726,7 +1723,7 @@ LATEX_SOURCE_CODE = NO # The LATEX_BIB_STYLE tag can be used to specify the style to use for the # bibliography, e.g. plainnat, or ieeetr. See -# http://en.wikipedia.org/wiki/BibTeX and \cite for more info. +# https://en.wikipedia.org/wiki/BibTeX and \cite for more info. # The default value is: plain. # This tag requires that the tag GENERATE_LATEX is set to YES. @@ -1882,7 +1879,7 @@ DOCBOOK_OUTPUT = docbook #--------------------------------------------------------------------------- # If the GENERATE_AUTOGEN_DEF tag is set to YES doxygen will generate an AutoGen -# Definitions (see http://autogen.sf.net) file that captures the structure of +# Definitions (see http://autogen.sourceforge.net) file that captures the structure of # the code including all documentation. Note that this feature is still # experimental and incomplete at the moment. # The default value is: NO. @@ -2093,7 +2090,7 @@ HIDE_UNDOC_RELATIONS = NO # If you set the HAVE_DOT tag to YES then doxygen will assume the dot tool is # available from the path. This tool is part of Graphviz (see: -# http://www.graphviz.org/), a graph visualization toolkit from AT&T and Lucent +# https://www.graphviz.org/), a graph visualization toolkit from AT&T and Lucent # Bell Labs. The other options in this section have no effect if this option is # set to NO # The default value is: YES. diff --git a/docs/DoxyfilePages.cmake b/docs/DoxyfilePages.cmake index d50a043d6..f3454c9d0 100644 --- a/docs/DoxyfilePages.cmake +++ b/docs/DoxyfilePages.cmake @@ -18,7 +18,7 @@ # that follow. The default is UTF-8 which is also the encoding used for all # text before the first occurrence of this tag. Doxygen uses libiconv (or the # iconv built into libc) for the transcoding. See -# http://www.gnu.org/software/libiconv for the list of possible encodings. +# https://www.gnu.org/software/libiconv for the list of possible encodings. DOXYFILE_ENCODING = UTF-8 @@ -581,7 +581,7 @@ INPUT = @OpenMW_SOURCE_DIR@/apps \ # This tag can be used to specify the character encoding of the source files # that doxygen parses. Internally doxygen uses the UTF-8 encoding, which is # also the default input encoding. Doxygen uses libiconv (or the iconv built -# into libc) for the transcoding. See http://www.gnu.org/software/libiconv for +# into libc) for the transcoding. See https://www.gnu.org/software/libiconv for # the list of possible encodings. INPUT_ENCODING = UTF-8 @@ -753,7 +753,7 @@ REFERENCES_LINK_SOURCE = YES # If the USE_HTAGS tag is set to YES then the references to source code # will point to the HTML generated by the htags(1) tool instead of doxygen # built-in source browser. The htags tool is part of GNU's global source -# tagging system (see http://www.gnu.org/software/global/global.html). You +# tagging system (see https://www.gnu.org/software/global/global.html). You # will need version 4.8.6 or higher. USE_HTAGS = NO @@ -928,30 +928,30 @@ QCH_FILE = # The QHP_NAMESPACE tag specifies the namespace to use when generating # Qt Help Project output. For more information please see -# http://doc.trolltech.com/qthelpproject.html#namespace +# https://doc.qt.io/archives/qt-4.8/qthelpproject.html#namespace QHP_NAMESPACE = # The QHP_VIRTUAL_FOLDER tag specifies the namespace to use when generating # Qt Help Project output. For more information please see -# http://doc.trolltech.com/qthelpproject.html#virtual-folders +# https://doc.qt.io/archives/qt-4.8/qthelpproject.html#virtual-folders QHP_VIRTUAL_FOLDER = doc # If QHP_CUST_FILTER_NAME is set, it specifies the name of a custom filter to add. # For more information please see -# http://doc.trolltech.com/qthelpproject.html#custom-filters +# https://doc.qt.io/archives/qt-4.8/qthelpproject.html#custom-filters QHP_CUST_FILTER_NAME = # The QHP_CUST_FILT_ATTRS tag specifies the list of the attributes of the custom filter to add.For more information please see -# Qt Help Project / Custom Filters. +# Qt Help Project / Custom Filters. QHP_CUST_FILTER_ATTRS = # The QHP_SECT_FILTER_ATTRS tag specifies the list of the attributes this project's # filter section matches. -# Qt Help Project / Filter Attributes. +# Qt Help Project / Filter Attributes. QHP_SECT_FILTER_ATTRS = diff --git a/docs/source/conf.py b/docs/source/conf.py index b18b40c50..0ba8567c0 100644 --- a/docs/source/conf.py +++ b/docs/source/conf.py @@ -60,16 +60,32 @@ copyright = u'2017, OpenMW Team' # The short X.Y version. # The full version, including alpha/beta/rc tags. +release = version = "UNRELEASED" + + +def get_openmw_version(haystack): + needle = 'OPENMW_VERSION_MAJOR' + line_counter = 0 + for hay in haystack: + if needle in str(hay): + break + line_counter += 1 + + version = '.'.join([haystack[line_counter][1][1].contents, + haystack[line_counter+1][1][1].contents, + haystack[line_counter+2][1][1].contents]) + return version + + try: from parse_cmake import parsing cmake_raw = open(project_root+'/CMakeLists.txt', 'r').read() cmake_data = parsing.parse(cmake_raw) - release = version = '.'.join([cmake_data[24][1][1].contents, - cmake_data[25][1][1].contents, - cmake_data[26][1][1].contents]) -except ImportError: - release = "UNRELEASED" - print("WARNING: Unable to import parse_cmake, version will be set to: {0}.".format(release)) + release = version = get_openmw_version(cmake_data) + +except Exception as ex: + print("WARNING: Version will be set to '{0}' because: '{1}'.".format(release, str(ex))) + import traceback; traceback.print_exc() # The language for content autogenerated by Sphinx. Refer to documentation # for a list of supported languages. diff --git a/docs/source/manuals/openmw-cs/files-and-directories.rst b/docs/source/manuals/openmw-cs/files-and-directories.rst index 77593dece..ae39082d7 100644 --- a/docs/source/manuals/openmw-cs/files-and-directories.rst +++ b/docs/source/manuals/openmw-cs/files-and-directories.rst @@ -145,7 +145,7 @@ and a place where OpenMW CS looks for already existing files. Resource files ============== -.. TODO This paragraph sounds weird +.. TODO This paragraph sounds weird Unless we are talking about a fully text based game, like Zork or Rogue, one would expect that a video game is using some media files: 3D models with @@ -219,6 +219,6 @@ files for textures. .. Hyperlink targets for the entire document -.. _FFmpeg: http://ffmpeg.org +.. _FFmpeg: https://ffmpeg.org .. _Vorbis: http://www.vorbis.com -.. _Theora: http://www.theora.org +.. _Theora: https://www.theora.org diff --git a/docs/source/manuals/openmw-cs/tour.rst b/docs/source/manuals/openmw-cs/tour.rst index 645c18453..83b7aae27 100644 --- a/docs/source/manuals/openmw-cs/tour.rst +++ b/docs/source/manuals/openmw-cs/tour.rst @@ -3,7 +3,7 @@ A Tour through OpenMW CS: making a magic ring In this first chapter we will create a mod that adds a new ring with a simple enchantment to the game. The ring will give its wearer a permanent Night Vision -effect while being worn. You do not need previous Morrowind modding experience, +effect while being worn. You do not need previous Morrowind modding experience, but you should be familiar with the game itself. There will be no scripting necessary, we can achieve everything using just what the base game offers out of the box. Before continuing make sure that OpenMW is properly @@ -133,7 +133,7 @@ the filter directly into the filter field rather than the name of an existing filter. To signify that we are using an instant filter the have to use `!` as the first character. Type the following into the field: -.. code:: +.. code:: !string("id", ".*ring.*") @@ -217,20 +217,20 @@ actually modify the contents of the game. Adding to an NPC ================ -The simplest way is probably to add it to the inventory of a shopkeeper. +The simplest way is probably to add it to the inventory of a shopkeeper. An obvious candidate is Arrille in Seyda Neen - he's quick to find in a new game and he's easy to find in the CS as his name comes early alphabetically. .. figure:: _static/images/chapter-1/Ring_to_Arrille.png :alt: Putting the ring into Arrille's inventory - -Open the CS and open the *Objects* table (*World* → *Objects*). + +Open the CS and open the *Objects* table (*World* → *Objects*). Scroll down to Arrille, or use a filter like !string("ID","arrille"). -Open another pane to edit him - either right click and select edit or use the +Open another pane to edit him - either right click and select edit or use the shortcut (default is shift double-click). Scroll down to the inventory section -and right click to add a new row. Type in the id of the ring (or find it in the -object pane, and drag and drop). Set the number of rings for him to stock - with +and right click to add a new row. Type in the id of the ring (or find it in the +object pane, and drag and drop). Set the number of rings for him to stock - with a negative number indicating that he will restock again to maintain that level. However, it's an attractive item, so he will probably wear it rather than sell it. @@ -241,7 +241,7 @@ Fargoth to give it to the player in exchange for his healing ring. .. figure:: _static/images/chapter-1/Ring_to_Fargoth_1.png :alt: Editing Fargoth to give ring to player - + Open the *Topicinfo* Table (*Characters* → *Topic Infos*). Use a filter !string(Topic,ring) and select the row with a response starting with "You found it!". Edit the record, firstly by adding a bit more to the response, then by adding a line to the script @@ -297,7 +297,7 @@ Placing in plain sight ===================== Let's hide the Ring of Night vision in the cabin of the [Ancient Shipwreck] -(http://en.uesp.net/wiki/Morrowind:Ancient_Shipwreck), a derelict vessel +(https://en.uesp.net/wiki/Morrowind:Ancient_Shipwreck), a derelict vessel southeast of Dagon Fel. Open the list of Cells (*World* → *Cells*) and find "Ancient Shipwreck, Cabin". @@ -333,8 +333,8 @@ This is probably a suitable place to start talking about how navigation differs in vanilla Morrowind. There is advice in Scripting for Dummies, the definitive manual for Morrowind Scripting: -"If you give your scripts a common tag, that will make it easier to jump between the -different scripts of your project, e.g. start every script name with AA_Scriptname +"If you give your scripts a common tag, that will make it easier to jump between the +different scripts of your project, e.g. start every script name with AA_Scriptname this will put them right at the beginning of the list and keep them neatly together." This is valid for the rather poorer navigation facilities there, but it's not sensible for @@ -359,12 +359,12 @@ the base game. "Modified" status will cover items from the base game which have been modified in this addon. -Click on the top of the column to toggle between ascending and descending order - thus between "Added" -and "Modified" at the top. Or put your desired modified status into a filter then sort alpabetically +Click on the top of the column to toggle between ascending and descending order - thus between "Added" +and "Modified" at the top. Or put your desired modified status into a filter then sort alpabetically on a different column. - + Checking your new addon ======================= @@ -372,4 +372,4 @@ Launch OpenMW and in the launcher under *Data Files* check your addon, if it's n already checked. Load a game and make your way to Seyda Neen - or start a new game. Check whether Arrille has one (or more) for sale, and whether Fargoth give you one -when you return his healing ring. \ No newline at end of file +when you return his healing ring. diff --git a/docs/source/reference/modding/convert_bump_mapped_mods.rst b/docs/source/reference/modding/convert_bump_mapped_mods.rst index 71ac29468..1891b5c4d 100644 --- a/docs/source/reference/modding/convert_bump_mapped_mods.rst +++ b/docs/source/reference/modding/convert_bump_mapped_mods.rst @@ -20,7 +20,7 @@ General introduction to normal map conversion :Authors: Joakim (Lysol) Berg :Updated: 2016-11-11 -This page has general information and tutorials on how normal mapping works in OpenMW and how you can make mods using the old fake normal mapping technique (such as `Netch Bump mapped`_ and `Hlaalu Bump mapped`_, and maybe the most (in)famous one to give shiny rocks in OpenMW, the mod `On the Rocks`_!, featured in MGSO and Morrowind Rebirth) work in OpenMW. +This page has general information and tutorials on how normal mapping works in OpenMW and how you can make mods using the old fake normal mapping technique (such as `Netch Bump mapped`_ and `Hlaalu Bump mapped`_, and maybe the most (in)famous one to give shiny rocks in OpenMW, the mod `On the Rocks`_!, featured in MGSO and Morrowind Rebirth) work in OpenMW. *Note:* The conversion made in the `Converting Apel's Various Things - Sacks`_-part of this tutorial require the use of the application NifSkope. There are binaries available for Windows, but not for Mac or Linux. Reports say that NifSkope versions 1.X will compile on Linux as long as you have Qt packages installed, while the later 2.X versions will not compile. @@ -179,24 +179,24 @@ The sacks included in Apel's `Various Things - Sacks`_ come in two versions – #. Remove all these tags by selecting them one at a time and press right click>Block>Remove Branch. (Ctrl-Del) #. Repeat this on all the affected models. #. If you launch OpenMW now, you'll `no longer have shiny models`_. But one thing is missing. Can you see it? It's actually hard to spot on still pictures, but we have no normal maps here. -#. Now, go back to the root of where you installed the mod. Now go to ``./Textures/`` and you'll find the texture files in question. +#. Now, go back to the root of where you installed the mod. Now go to ``./Textures/`` and you'll find the texture files in question. #. OpenMW detects normal maps if they have the same name as the base diffuse texture, but with a *_n.dds* suffix. In this mod, the normal maps has a suffix of *_nm.dds*. Change all the files that ends with *_nm.dds* to instead end with *_n.dds*. #. Finally, `we are done`_! Since these models have one or two textures applied to them, the fix was not that time-consuming. It gets worse when you have to fix a model that uses loads of textures. The principle is the same, it just requires more manual work which is annoying and takes time. -.. _`Netch Bump mapped`: http://www.nexusmods.com/morrowind/mods/42851/? -.. _`Hlaalu Bump mapped`: http://www.nexusmods.com/morrowind/mods/42396/? +.. _`Netch Bump mapped`: https://www.nexusmods.com/morrowind/mods/42851/? +.. _`Hlaalu Bump mapped`: https://www.nexusmods.com/morrowind/mods/42396/? .. _`On the Rocks`: http://mw.modhistory.com/download-44-14107 .. _`texture modding`: https://wiki.openmw.org/index.php?title=TextureModding -.. _`MGE XE`: http://www.nexusmods.com/morrowind/mods/26348/? -.. _PeterBitt: http://www.nexusmods.com/morrowind/users/4381248/? -.. _`PBR Scamp Replacer`: http://www.nexusmods.com/morrowind/mods/44314/? +.. _`MGE XE`: https://www.nexusmods.com/morrowind/mods/26348/? +.. _PeterBitt: https://www.nexusmods.com/morrowind/users/4381248/? +.. _`PBR Scamp Replacer`: https://www.nexusmods.com/morrowind/mods/44314/? .. _settings.cfg: https://wiki.openmw.org/index.php?title=Settings .. _`Multiple data folders`: https://wiki.openmw.org/index.php?title=Mod_installation -.. _`Various Things - Sacks`: http://www.nexusmods.com/morrowind/mods/42558/? -.. _Lead: http://imgur.com/bwpcYlc +.. _`Various Things - Sacks`: https://www.nexusmods.com/morrowind/mods/42558/? +.. _Lead: https://imgur.com/bwpcYlc .. _NifSkope: http://niftools.sourceforge.net/wiki/NifSkope -.. _Blocks: http://imgur.com/VmQC0WG -.. _`no longer have shiny models`: http://imgur.com/vu1k7n1 -.. _`we are done`: http://imgur.com/yyZxlTw +.. _Blocks: https://imgur.com/VmQC0WG +.. _`no longer have shiny models`: https://imgur.com/vu1k7n1 +.. _`we are done`: https://imgur.com/yyZxlTw diff --git a/docs/source/reference/modding/font.rst b/docs/source/reference/modding/font.rst index 5f01b12d9..80d01c27f 100644 --- a/docs/source/reference/modding/font.rst +++ b/docs/source/reference/modding/font.rst @@ -15,7 +15,7 @@ Unlike vanilla Morrowind, OpenMW directly supports TrueType (``.ttf``) fonts. Th - To replace the primary "Magic Cards" font: - #. Download `Pelagiad `_ by Isak Larborn (aka Isaskar). + #. Download `Pelagiad `_ by Isak Larborn (aka Isaskar). #. Install the ``openmw_font.xml`` file into ``resources/mygui/openmw_font.xml`` in your OpenMW installation. #. Copy ``Pelagiad.ttf`` into ``resources/mygui/`` as well. #. If desired, you can now delete the original ``Magic_Cards.*`` files from your Data Files/Fonts directory. @@ -74,4 +74,4 @@ Unlike vanilla Morrowind, OpenMW directly supports TrueType (``.ttf``) fonts. Th Bitmap fonts ------------ -Morrowind ``.fnt`` files are essentially a bitmap font, but using them is discouraged because of no Unicode support. MyGUI has its own format for bitmap fonts. An example can be seen by using the --export-fonts command line option (see above), which converts Morrowind ``.fnt`` to a MyGUI bitmap font. This is the recommended format to use if you wish to edit Morrowind's bitmap font or create a new bitmap font. \ No newline at end of file +Morrowind ``.fnt`` files are essentially a bitmap font, but using them is discouraged because of no Unicode support. MyGUI has its own format for bitmap fonts. An example can be seen by using the --export-fonts command line option (see above), which converts Morrowind ``.fnt`` to a MyGUI bitmap font. This is the recommended format to use if you wish to edit Morrowind's bitmap font or create a new bitmap font. diff --git a/docs/source/reference/modding/settings/game.rst b/docs/source/reference/modding/settings/game.rst index 45ac81d64..7a9b89295 100644 --- a/docs/source/reference/modding/settings/game.rst +++ b/docs/source/reference/modding/settings/game.rst @@ -90,12 +90,26 @@ difficulty This setting adjusts the difficulty of the game and is intended to be in the range -100 to 100 inclusive. Given the default game setting for fDifficultyMult of 5.0, a value of -100 results in the player taking 80% of the usual damage, doing 6 times the normal damage. -A value of 100 results in the player taking 6 times as much damage, but inflicting only 80% of the usual damage. -Values less than -500 will result in the player receiving no damage, -and values greater than 500 will result in the player inflicting no damage. +A value of 100 results in the player taking 6 times as much damage, while inflicting only 80% of the usual damage. +Values below -500 will result in the player receiving no damage, +and values above 500 will result in the player inflicting no damage. This setting can be controlled in game with the Difficulty slider in the Prefs panel of the Options menu. +classic reflect absorb attribute behavior +----------------------------------------- + +:Type: boolean +:Range: True/False +:Default: True + +If this setting is true, "Absorb Attribute" spells which were reflected by the target are not "mirrored", +and the caster will absorb their own attribute resulting in no effect on both the caster and the target. +This makes the gameplay as a mage easier, but these spells become imbalanced. +This is how the original Morrowind behaves. + +This setting can only be configured by editing the settings configuration file. + show effect duration -------------------- @@ -108,6 +122,18 @@ The remaining duration is displayed in the tooltip by hovering over the magical This setting can only be configured by editing the settings configuration file. +enchanted weapons are magical +----------------------------- + +:Type: boolean +:Range: True/False +:Default: True + +Makes enchanted weapons without Magical flag bypass normal weapons resistance (and weakness) certain creatures have. +This is how original Morrowind behaves. + +This setting can only be configured by editing the settings configuration file. + prevent merchant equipping -------------------------- diff --git a/docs/source/reference/modding/settings/saves.rst b/docs/source/reference/modding/settings/saves.rst index 777404ebf..fdb25fb79 100644 --- a/docs/source/reference/modding/settings/saves.rst +++ b/docs/source/reference/modding/settings/saves.rst @@ -5,7 +5,7 @@ character --------- :Type: string -:Range: +:Range: :Default: "" This contains the default character for the Load Game menu and is automatically updated when a different character is selected. @@ -32,3 +32,14 @@ This setting determines whether the amount of the time the player has spent play for each saved game in the Load menu. Currently, the counter includes time spent in menus, including the pause menu, but does not include time spent with the game window minimized. This setting can only be configured by editing the settings configuration file. + +max quicksaves +---------- + +:Type: integer +:Range: >0 +:Default: 1 + +This setting determines how many quicksave and autosave slots you can have at a time. If greater than 1, quicksaves will be sequentially created each time you quicksave. Once the maximum number of quicksaves has been reached, the oldest quicksave will be recycled the next time you perform a quicksave. + +This setting can only be configured by editing the settings configuration file. diff --git a/extern/oics/tinyxmlparser.cpp b/extern/oics/tinyxmlparser.cpp index 253cd93ff..d5bda8fee 100644 --- a/extern/oics/tinyxmlparser.cpp +++ b/extern/oics/tinyxmlparser.cpp @@ -2,23 +2,23 @@ www.sourceforge.net/projects/tinyxml Original code (2.0 and earlier )copyright (c) 2000-2002 Lee Thomason (www.grinninglizard.com) -This software is provided 'as-is', without any express or implied -warranty. In no event will the authors be held liable for any +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 +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 +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 +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 +3. This notice may not be removed or altered from any source distribution. */ @@ -39,8 +39,8 @@ distribution. // Note tha "PutString" hardcodes the same list. This // is less flexible than it appears. Changing the entries -// or order will break putstring. -TiXmlBase::Entity TiXmlBase::entity[ NUM_ENTITY ] = +// or order will break putstring. +TiXmlBase::Entity TiXmlBase::entity[ NUM_ENTITY ] = { { "&", 5, '&' }, { "<", 4, '<' }, @@ -50,20 +50,20 @@ TiXmlBase::Entity TiXmlBase::entity[ NUM_ENTITY ] = }; // Bunch of unicode info at: -// http://www.unicode.org/faq/utf_bom.html +// https://www.unicode.org/faq/utf_bom.html // Including the basic of this table, which determines the #bytes in the // sequence from the lead byte. 1 placed for invalid sequences -- // although the result will be junk, pass it through as much as possible. -// Beware of the non-characters in UTF-8: +// Beware of the non-characters in UTF-8: // ef bb bf (Microsoft "lead bytes") // ef bf be -// ef bf bf +// ef bf bf const unsigned char TIXML_UTF_LEAD_0 = 0xefU; const unsigned char TIXML_UTF_LEAD_1 = 0xbbU; const unsigned char TIXML_UTF_LEAD_2 = 0xbfU; -const int TiXmlBase::utf8ByteTable[256] = +const int TiXmlBase::utf8ByteTable[256] = { // 0 1 2 3 4 5 6 7 8 9 a b c d e f 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 0x00 @@ -75,9 +75,9 @@ const int TiXmlBase::utf8ByteTable[256] = 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 0x60 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 0x70 End of ASCII range 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 0x80 0x80 to 0xc1 invalid - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 0x90 - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 0xa0 - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 0xb0 + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 0x90 + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 0xa0 + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 0xb0 1, 1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, // 0xc0 0xc2 to 0xdf 2 byte 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, // 0xd0 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, // 0xe0 0xe0 to 0xef 3 byte @@ -91,7 +91,7 @@ void TiXmlBase::ConvertUTF32ToUTF8( unsigned long input, char* output, int* leng const unsigned long BYTE_MARK = 0x80; const unsigned long FIRST_BYTE_MARK[7] = { 0x00, 0x00, 0xC0, 0xE0, 0xF0, 0xF8, 0xFC }; - if (input < 0x80) + if (input < 0x80) *length = 1; else if ( input < 0x800 ) *length = 2; @@ -105,22 +105,22 @@ void TiXmlBase::ConvertUTF32ToUTF8( unsigned long input, char* output, int* leng output += *length; // Scary scary fall throughs. - switch (*length) + switch (*length) { case 4: - --output; - *output = (char)((input | BYTE_MARK) & BYTE_MASK); + --output; + *output = (char)((input | BYTE_MARK) & BYTE_MASK); input >>= 6; case 3: - --output; - *output = (char)((input | BYTE_MARK) & BYTE_MASK); + --output; + *output = (char)((input | BYTE_MARK) & BYTE_MASK); input >>= 6; case 2: - --output; - *output = (char)((input | BYTE_MARK) & BYTE_MASK); + --output; + *output = (char)((input | BYTE_MARK) & BYTE_MASK); input >>= 6; case 1: - --output; + --output; *output = (char)(input | FIRST_BYTE_MARK[*length]); } } @@ -130,7 +130,7 @@ void TiXmlBase::ConvertUTF32ToUTF8( unsigned long input, char* output, int* leng { // This will only work for low-ascii, everything else is assumed to be a valid // letter. I'm not sure this is the best approach, but it is quite tricky trying - // to figure out alhabetical vs. not across encoding. So take a very + // to figure out alhabetical vs. not across encoding. So take a very // conservative approach. // if ( encoding == TIXML_ENCODING_UTF8 ) @@ -151,7 +151,7 @@ void TiXmlBase::ConvertUTF32ToUTF8( unsigned long input, char* output, int* leng { // This will only work for low-ascii, everything else is assumed to be a valid // letter. I'm not sure this is the best approach, but it is quite tricky trying - // to figure out alhabetical vs. not across encoding. So take a very + // to figure out alhabetical vs. not across encoding. So take a very // conservative approach. // if ( encoding == TIXML_ENCODING_UTF8 ) @@ -224,7 +224,7 @@ void TiXmlParsingData::Stamp( const char* now, TiXmlEncoding encoding ) case '\r': // bump down to the next line ++row; - col = 0; + col = 0; // Eat the character ++p; @@ -266,11 +266,11 @@ void TiXmlParsingData::Stamp( const char* now, TiXmlEncoding encoding ) // In these cases, don't advance the column. These are // 0-width spaces. if ( *(pU+1)==TIXML_UTF_LEAD_1 && *(pU+2)==TIXML_UTF_LEAD_2 ) - p += 3; + p += 3; else if ( *(pU+1)==0xbfU && *(pU+2)==0xbeU ) - p += 3; + p += 3; else if ( *(pU+1)==0xbfU && *(pU+2)==0xbfU ) - p += 3; + p += 3; else { p +=3; ++col; } // A normal character. } @@ -322,10 +322,10 @@ const char* TiXmlBase::SkipWhiteSpace( const char* p, TiXmlEncoding encoding ) while ( *p ) { const unsigned char* pU = (const unsigned char*)p; - + // Skip the stupid Microsoft UTF-8 Byte order marks if ( *(pU+0)==TIXML_UTF_LEAD_0 - && *(pU+1)==TIXML_UTF_LEAD_1 + && *(pU+1)==TIXML_UTF_LEAD_1 && *(pU+2)==TIXML_UTF_LEAD_2 ) { p += 3; @@ -413,12 +413,12 @@ const char* TiXmlBase::ReadName( const char* p, TIXML_STRING * name, TiXmlEncodi // After that, they can be letters, underscores, numbers, // hyphens, or colons. (Colons are valid ony for namespaces, // but tinyxml can't tell namespaces from names.) - if ( p && *p + if ( p && *p && ( IsAlpha( (unsigned char) *p, encoding ) || *p == '_' ) ) { const char* start = p; while( p && *p - && ( IsAlphaNum( (unsigned char ) *p, encoding ) + && ( IsAlphaNum( (unsigned char ) *p, encoding ) || *p == '_' || *p == '-' || *p == '.' @@ -469,7 +469,7 @@ const char* TiXmlBase::GetEntity( const char* p, char* value, int* length, TiXml ucs += mult * (*q - 'a' + 10); else if ( *q >= 'A' && *q <= 'F' ) ucs += mult * (*q - 'A' + 10 ); - else + else return 0; mult *= 16; --q; @@ -492,7 +492,7 @@ const char* TiXmlBase::GetEntity( const char* p, char* value, int* length, TiXml { if ( *q >= '0' && *q <= '9' ) ucs += mult * (*q - '0'); - else + else return 0; mult *= 10; --q; @@ -571,10 +571,10 @@ bool TiXmlBase::StringEqual( const char* p, return false; } -const char* TiXmlBase::ReadText( const char* p, - TIXML_STRING * text, - bool trimWhiteSpace, - const char* endTag, +const char* TiXmlBase::ReadText( const char* p, + TIXML_STRING * text, + bool trimWhiteSpace, + const char* endTag, bool caseInsensitive, TiXmlEncoding encoding ) { @@ -631,7 +631,7 @@ const char* TiXmlBase::ReadText( const char* p, } } } - if ( p ) + if ( p ) p += strlen( endTag ); return p; } @@ -647,7 +647,7 @@ void TiXmlDocument::StreamIn( std::istream * in, TIXML_STRING * tag ) // This "pre-streaming" will never read the closing ">" so the // sub-tag can orient itself. - if ( !StreamTo( in, '<', tag ) ) + if ( !StreamTo( in, '<', tag ) ) { SetError( TIXML_ERROR_PARSING_EMPTY, 0, 0, TIXML_ENCODING_UNKNOWN ); return; @@ -669,7 +669,7 @@ void TiXmlDocument::StreamIn( std::istream * in, TIXML_STRING * tag ) if ( in->good() ) { - // We now have something we presume to be a node of + // We now have something we presume to be a node of // some sort. Identify it, and call the node to // continue streaming. TiXmlNode* node = Identify( tag->c_str() + tagIndex, TIXML_DEFAULT_ENCODING ); @@ -778,7 +778,7 @@ const char* TiXmlDocument::Parse( const char* p, TiXmlParsingData* prevData, TiX encoding = TIXML_ENCODING_UTF8; else if ( StringEqual( enc, "UTF8", true, TIXML_ENCODING_UNKNOWN ) ) encoding = TIXML_ENCODING_UTF8; // incorrect, but be nice - else + else encoding = TIXML_ENCODING_LEGACY; } @@ -796,7 +796,7 @@ const char* TiXmlDocument::Parse( const char* p, TiXmlParsingData* prevData, TiX } void TiXmlDocument::SetError( int err, const char* pError, TiXmlParsingData* data, TiXmlEncoding encoding ) -{ +{ // The first error in a chain is more accurate - don't set again! if ( error ) return; @@ -833,7 +833,7 @@ TiXmlNode* TiXmlNode::Identify( const char* p, TiXmlEncoding encoding ) return 0; } - // What is this thing? + // What is this thing? // - Elements start with a letter or underscore, but xml is reserved. // - Comments: - + org.openmw.desktop CC0-1.0 - GPL-3.0 and MIT + GPL-3.0 and MIT OpenMW Unofficial open source engine re-implementation of the game Morrowind @@ -20,21 +20,31 @@ Copyright 2017 Bret Curtis You will still need the original game data to play OpenMW.

        - - http://wiki.openmw.org/images/b/b2/Openmw_0.11.1_launcher_1.png + https://wiki.openmw.org/images/b/b2/Openmw_0.11.1_launcher_1.png The OpenMW launcher - http://wiki.openmw.org/images/f/f1/Screenshot_mournhold_plaza_0.35.png + https://wiki.openmw.org/images/f/f1/Screenshot_mournhold_plaza_0.35.png The Mournhold's plaza on OpenMW - http://wiki.openmw.org/images/5/5b/Screenshot_Vivec_seen_from_Ebonheart_0.35.png + https://wiki.openmw.org/images/5/5b/Screenshot_Vivec_seen_from_Ebonheart_0.35.png Vivec seen from Ebonheart on OpenMW + + http://wiki.openmw.org/images/a/a3/0.40_Screenshot-Balmora_3.png + Balmora at morning on OpenMW + + + Game + RolePlaying + + + + https://openmw.org https://bugs.openmw.org/ https://openmw.org/faq/ diff --git a/files/settings-default.cfg b/files/settings-default.cfg index c0283b378..3cc2b138e 100644 --- a/files/settings-default.cfg +++ b/files/settings-default.cfg @@ -7,8 +7,8 @@ # significance of each setting, interaction with other settings, hard # limits on value ranges and more information in general, please read # the detailed documentation at: -# -# http://openmw.readthedocs.io/en/master/reference/modding/settings/index.html +# +# https://openmw.readthedocs.io/en/master/reference/modding/settings/index.html # [Camera] @@ -90,6 +90,24 @@ pointers cache size = 40 # If true, use paging and LOD algorithms to display the entire terrain. If false, only display terrain of the loaded cells distant terrain = false +[Fog] + +# If true, use extended fog parameters for distant terrain not controlled by +# viewing distance. If false, use the standard fog calculations. +use distant fog = false + +distant land fog start = 16384 + +distant land fog end = 40960 + +distant underwater fog start = -4096 + +distant underwater fog end = 2457.6 + +distant interior fog start = 0 + +distant interior fog end = 16384 + [Map] # Size of each exterior cell in pixels in the world map. (e.g. 12 to 24). @@ -147,6 +165,9 @@ werewolf overlay = true color background owned = 0.15 0.0 0.0 1.0 color crosshair owned = 1.0 0.15 0.15 1.0 +# Controls whether Arrow keys, Movement keys, Tab/Shift-Tab and Spacebar/Enter/Activate may be used to navigate GUI buttons. +keyboard navigation = true + [HUD] # Displays the crosshair or reticle when not in GUI mode. @@ -173,12 +194,21 @@ best attack = false # Difficulty. Expressed as damage dealt and received. (e.g. -100 to 100). difficulty = 0 +# Replicate how reflected "absorb attribute" spells do not have any effect in Morrowind engine. The caster absorbs the attribute from themselves. +classic reflect absorb attribute behavior = true + # Show duration of magic effect and lights in the spells window. show effect duration = false +# Account for the first follower in fast travel cost calculations. +charge for every follower travelling = false + # Prevents merchants from equipping items that are sold to them. prevent merchant equipping = false +# Make enchanted weaponry without Magical flag bypass normal weapons resistance +enchanted weapons are magical = true + # Makes player followers and escorters start combat with enemies who have started combat with them # or the player. Otherwise they wait for the enemies or the player to do an attack first. followers attack on sight = false @@ -291,6 +321,10 @@ autosave = true # Display the time played on each save file in the load menu. timeplayed = false +# The maximum number of quick (or auto) save slots to have. +# If all slots are used, the oldest save is reused +max quicksaves = 1 + [Sound] # Name of audio device file. Blank means use the default device. @@ -379,7 +413,7 @@ reflect actors = false # Overrides the value in '[Camera] small feature culling pixel size' specifically for water reflection/refraction textures. small feature culling pixel size = 20.0 -# By what factor water downscales objects. Only works with water shader and refractions on. +# By what factor water downscales objects. Only works with water shader and refractions on. refraction scale = 1.0 [Windows] diff --git a/files/shaders/lighting.glsl b/files/shaders/lighting.glsl index 09b78b596..e67ed295a 100644 --- a/files/shaders/lighting.glsl +++ b/files/shaders/lighting.glsl @@ -67,8 +67,8 @@ vec3 getSpecular(vec3 viewNormal, vec3 viewDirection, float shininess, vec3 matS { vec3 lightDir = normalize(gl_LightSource[0].position.xyz); float NdotL = max(dot(viewNormal, lightDir), 0.0); - if (NdotL < 0) - return vec3(0,0,0); + if (NdotL < 0.0) + return vec3(0.,0.,0.); vec3 halfVec = normalize(lightDir - viewDirection); - return pow(max(dot(viewNormal, halfVec), 0.0), 128) * gl_LightSource[0].specular.xyz * matSpec; + return pow(max(dot(viewNormal, halfVec), 0.0), 128.) * gl_LightSource[0].specular.xyz * matSpec; } diff --git a/files/shaders/objects_fragment.glsl b/files/shaders/objects_fragment.glsl index 9196c1490..98b11f420 100644 --- a/files/shaders/objects_fragment.glsl +++ b/files/shaders/objects_fragment.glsl @@ -49,10 +49,10 @@ varying float depth; #define PER_PIXEL_LIGHTING (@normalMap || @forcePPL) #if !PER_PIXEL_LIGHTING -varying vec4 lighting; -varying vec3 shadowDiffuseLighting; +centroid varying vec4 lighting; +centroid varying vec3 shadowDiffuseLighting; #else -varying vec4 passColor; +centroid varying vec4 passColor; #endif varying vec3 passViewPos; varying vec3 passNormal; diff --git a/files/shaders/objects_vertex.glsl b/files/shaders/objects_vertex.glsl index f84971c97..aa3636c50 100644 --- a/files/shaders/objects_vertex.glsl +++ b/files/shaders/objects_vertex.glsl @@ -40,10 +40,10 @@ varying float depth; #define PER_PIXEL_LIGHTING (@normalMap || @forcePPL) #if !PER_PIXEL_LIGHTING -varying vec4 lighting; -varying vec3 shadowDiffuseLighting; +centroid varying vec4 lighting; +centroid varying vec3 shadowDiffuseLighting; #else -varying vec4 passColor; +centroid varying vec4 passColor; #endif varying vec3 passViewPos; varying vec3 passNormal; diff --git a/files/shaders/terrain_fragment.glsl b/files/shaders/terrain_fragment.glsl index 1b985e14b..77b41eab9 100644 --- a/files/shaders/terrain_fragment.glsl +++ b/files/shaders/terrain_fragment.glsl @@ -19,10 +19,10 @@ varying float depth; #define PER_PIXEL_LIGHTING (@normalMap || @forcePPL) #if !PER_PIXEL_LIGHTING -varying vec4 lighting; -varying vec3 shadowDiffuseLighting; +centroid varying vec4 lighting; +centroid varying vec3 shadowDiffuseLighting; #else -varying vec4 passColor; +centroid varying vec4 passColor; #endif varying vec3 passViewPos; varying vec3 passNormal; diff --git a/files/shaders/terrain_vertex.glsl b/files/shaders/terrain_vertex.glsl index 7cb959d3e..0ed011cf7 100644 --- a/files/shaders/terrain_vertex.glsl +++ b/files/shaders/terrain_vertex.glsl @@ -8,10 +8,10 @@ varying float depth; #define PER_PIXEL_LIGHTING (@normalMap || @forcePPL) #if !PER_PIXEL_LIGHTING -varying vec4 lighting; -varying vec3 shadowDiffuseLighting; +centroid varying vec4 lighting; +centroid varying vec3 shadowDiffuseLighting; #else -varying vec4 passColor; +centroid varying vec4 passColor; #endif varying vec3 passViewPos; varying vec3 passNormal; diff --git a/files/shaders/water_fragment.glsl b/files/shaders/water_fragment.glsl index fddd81eff..c277e86bc 100644 --- a/files/shaders/water_fragment.glsl +++ b/files/shaders/water_fragment.glsl @@ -3,7 +3,7 @@ #define REFRACTION @refraction_enabled #define SHADOWS @shadows_enabled -// Inspired by Blender GLSL Water by martinsh ( http://devlog-martinsh.blogspot.de/2012/07/waterundewater-shader-wip.html ) +// Inspired by Blender GLSL Water by martinsh ( https://devlog-martinsh.blogspot.de/2012/07/waterundewater-shader-wip.html ) // tweakables -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- @@ -68,16 +68,16 @@ vec4 circle(vec2 coords, vec2 i_part, float phase) float d = length(toCenter); float r = RAIN_RIPPLE_RADIUS * phase; - + if (d > r) return vec4(0.0,0.0,1.0,0.0); - + float sinValue = (sin(d / r * 1.2) + 0.7) / 2.0; float height = (1.0 - abs(phase)) * pow(sinValue,3.0); vec3 normal = normalize(mix(vec3(0.0,0.0,1.0),vec3(normalize(toCenter),0.0),height)); - + return vec4(normal,height); } @@ -94,7 +94,7 @@ vec4 rainCombined(vec2 uv, float time) // returns ripple normal in xyz and r rain(uv,time) + rain(uv + vec2(10.5,5.7),time) + rain(uv * 0.75 + vec2(3.7,18.9),time) + - rain(uv * 0.9 + vec2(5.7,30.1),time) + + rain(uv * 0.9 + vec2(5.7,30.1),time) + rain(uv * 0.8 + vec2(1.2,3.0),time); } @@ -121,7 +121,7 @@ float fresnel_dielectric(vec3 Incoming, vec3 Normal, float eta) vec2 normalCoords(vec2 uv, float scale, float speed, float time, float timer1, float timer2, vec3 previousNormal) { return uv * (WAVE_SCALE * scale) + WIND_DIR * time * (WIND_SPEED * speed) -(previousNormal.xy/previousNormal.zz) * WAVE_CHOPPYNESS + vec2(time * timer1,time * timer2); - } + } varying vec3 screenCoordsPassthrough; varying vec4 position; @@ -134,7 +134,7 @@ uniform sampler2D reflectionMap; uniform sampler2D refractionMap; uniform sampler2D refractionDepthMap; #endif - + uniform float osg_SimulationTime; uniform float near; @@ -185,7 +185,7 @@ void main(void) #define waterTimer osg_SimulationTime - vec3 normal0 = 2.0 * texture2D(normalMap,normalCoords(UV, 0.05, 0.04, waterTimer, -0.015, -0.005, vec3(0.0,0.0,0.0))).rgb - 1.0; + vec3 normal0 = 2.0 * texture2D(normalMap,normalCoords(UV, 0.05, 0.04, waterTimer, -0.015, -0.005, vec3(0.0,0.0,0.0))).rgb - 1.0; vec3 normal1 = 2.0 * texture2D(normalMap,normalCoords(UV, 0.1, 0.08, waterTimer, 0.02, 0.015, normal0)).rgb - 1.0; vec3 normal2 = 2.0 * texture2D(normalMap,normalCoords(UV, 0.25, 0.07, waterTimer, -0.04, -0.03, normal1)).rgb - 1.0; vec3 normal3 = 2.0 * texture2D(normalMap,normalCoords(UV, 0.5, 0.09, waterTimer, 0.03, 0.04, normal2)).rgb - 1.0; @@ -198,7 +198,7 @@ void main(void) rainRipple = rainCombined(position.xy / 1000.0,waterTimer) * clamp(rainIntensity,0.0,1.0); else rainRipple = vec4(0.0,0.0,0.0,0.0); - + vec3 rippleAdd = rainRipple.xyz * rainRipple.w * 10.0; vec3 normal = (normal0 * BIG_WAVES_X + normal1 * BIG_WAVES_Y + @@ -249,7 +249,7 @@ void main(void) float depthSample = linearizeDepth(texture2D(refractionDepthMap,screenCoords).x) * normalization; float depthSampleDistorted = linearizeDepth(texture2D(refractionDepthMap,screenCoords-(normal.xy*REFR_BUMP)).x) * normalization; float surfaceDepth = linearizeDepth(gl_FragCoord.z) * normalization; - float realWaterDepth = depthSample - surfaceDepth; // undistorted water depth in view direction, independent of frustum + float realWaterDepth = depthSample - surfaceDepth; // undistorted water depth in view direction, independent of frustum float shore = clamp(realWaterDepth / BUMP_SUPPRESS_DEPTH,0,1); #else float shore = 1.0; diff --git a/files/ui/advancedpage.ui b/files/ui/advancedpage.ui index 8a0795d34..6832b86df 100644 --- a/files/ui/advancedpage.ui +++ b/files/ui/advancedpage.ui @@ -6,7 +6,7 @@ 0 0 - 434 + 671 373 @@ -27,9 +27,9 @@ 0 - 0 - 393 - 437 + -187 + 630 + 510 @@ -139,6 +139,9 @@ + + 1 + Off @@ -207,11 +210,11 @@ - + - Other + Saves - + @@ -222,12 +225,59 @@ + + + + <html><head/><body><p>This setting determines how many quicksave and autosave slots you can have at a time. If greater than 1, quicksaves will be sequentially created each time you quicksave. Once the maximum number of quicksaves has been reached, the oldest quicksave will be recycled the next time you perform a quicksave.</p></body></html> + + + + -1 + + + 0 + + + 0 + + + 0 + + + 0 + + + + + Maximum Quicksaves + + + + + + + 1 + + + + + + + + + + + + + Other + + <html><head/><body><p>Specify the format for screen shots taken by pressing the screen shot key (bound to F12 by default). This setting should be the file extension commonly associated with the desired format. The formats supported will be determined at compilation, but “jpg”, “png”, and “tga” should be allowed.</p></body></html> - + -1 diff --git a/plugins/mygui_resource_plugin/CMakeLists.txt b/plugins/mygui_resource_plugin/CMakeLists.txt deleted file mode 100644 index be834b17d..000000000 --- a/plugins/mygui_resource_plugin/CMakeLists.txt +++ /dev/null @@ -1,31 +0,0 @@ -set (MYGUI_RESOURCE_PLUGIN_SOURCES - plugin.hpp - plugin.cpp - plugin_export.cpp -) - -set (MYGUI_RESOURCE_PLUGIN_LIBRARY - Plugin_MyGUI_OpenMW_Resources -) - -add_definitions("-D_USRDLL -DMYGUI_BUILD_DLL") - -add_library(${MYGUI_RESOURCE_PLUGIN_LIBRARY} - SHARED - ${MYGUI_RESOURCE_PLUGIN_SOURCES} - ) - -if(WIN32) - if(MSVC) - # from top-level CMakelists.txt: - # 4305 - Truncating value (double to float, for example) - set_target_properties(${MYGUI_RESOURCE_PLUGIN_LIBRARY} PROPERTIES COMPILE_FLAGS "/wd4305") - endif(MSVC) -endif(WIN32) - -set_target_properties(${MYGUI_RESOURCE_PLUGIN_LIBRARY} PROPERTIES PREFIX "") - -target_link_libraries(${MYGUI_RESOURCE_PLUGIN_LIBRARY} - ${OGRE_LIBRARIES} - components -) diff --git a/plugins/mygui_resource_plugin/plugin.cpp b/plugins/mygui_resource_plugin/plugin.cpp deleted file mode 100644 index 1b718b547..000000000 --- a/plugins/mygui_resource_plugin/plugin.cpp +++ /dev/null @@ -1,183 +0,0 @@ -#include "plugin.hpp" - -#include -#include -#include -#include -#include -#include - -#include -#include -#include - -#include -#include - -#include -#include - -//FIXME: code duplication -namespace boost -{ -struct FallbackMap { - std::map mMap; -}; - -void validate(boost::any &v, std::vector const &tokens, FallbackMap*, int) -{ - if(v.empty()) - { - v = boost::any(FallbackMap()); - } - - FallbackMap *map = boost::any_cast(&v); - - for(std::vector::const_iterator it=tokens.begin(); it != tokens.end(); ++it) - { - int sep = it->find(","); - if(sep < 1 || sep == (int)it->length()-1) -#if (BOOST_VERSION < 104200) - throw boost::program_options::validation_error("invalid value"); -#else - throw boost::program_options::validation_error(boost::program_options::validation_error::invalid_option_value); -#endif - - std::string key(it->substr(0,sep)); - std::string value(it->substr(sep+1)); - - if(map->mMap.find(key) == map->mMap.end()) - { - map->mMap.insert(std::make_pair (key,value)); - } - } -} -} - -namespace MyGUIPlugin -{ - - // Dummy - obsolete when using MyGUI git, because the ScrollBar there has autorepeat support added. - class MWScrollBar : public MyGUI::ScrollBar - { - MYGUI_RTTI_DERIVED(MWScrollBar) - }; - - const std::string& ResourcePlugin::getName() const - { - static const std::string name = "OpenMW resource plugin"; - return name; - } - - void ResourcePlugin::install() - { - - } - void ResourcePlugin::uninstall() - { - - } - - void ResourcePlugin::registerResources() - { - boost::program_options::variables_map variables; - - boost::program_options::options_description desc("Allowed options"); - desc.add_options() - ("data", boost::program_options::value()->default_value(Files::PathContainer(), "data")->multitoken()->composing()) - ("data-local", boost::program_options::value()->default_value("")) - ("fs-strict", boost::program_options::value()->implicit_value(true)->default_value(false)) - ("fallback-archive", boost::program_options::value >()-> - default_value(std::vector(), "fallback-archive")->multitoken()) - ("encoding", boost::program_options::value()->default_value("win1252")) - ("fallback", boost::program_options::value()->default_value(boost::FallbackMap(), "") - ->multitoken()->composing(), "fallback values"); - - boost::program_options::notify(variables); - - Files::ConfigurationManager cfgManager; - cfgManager.readConfiguration(variables, desc); - - std::vector archives = variables["fallback-archive"].as >(); - bool fsStrict = variables["fs-strict"].as(); - - Files::PathContainer dataDirs, dataLocal; - if (!variables["data"].empty()) { - dataDirs = Files::PathContainer(variables["data"].as()); - } - - std::string local = variables["data-local"].as(); - if (!local.empty()) { - dataLocal.push_back(Files::PathContainer::value_type(local)); - } - - cfgManager.processPaths (dataDirs); - cfgManager.processPaths (dataLocal, true); - - if (!dataLocal.empty()) - dataDirs.insert (dataDirs.end(), dataLocal.begin(), dataLocal.end()); - - Files::Collections collections (dataDirs, !fsStrict); - - Bsa::registerResources(collections, archives, true, fsStrict); - - std::string encoding(variables["encoding"].as()); - std::cout << ToUTF8::encodingUsingMessage(encoding) << std::endl; - - Gui::FontLoader loader(ToUTF8::calculateEncoding(encoding)); - loader.loadAllFonts(false); - - mFallbackMap = variables["fallback"].as().mMap; - } - - void ResourcePlugin::registerWidgets() - { - MyGUI::FactoryManager::getInstance().registerFactory("Widget"); - - Gui::registerAllWidgets(); - } - - void ResourcePlugin::createTransparentBGTexture() - { - // This texture is manually created in OpenMW to be able to change its opacity at runtime in the options menu - Ogre::TexturePtr tex = Ogre::TextureManager::getSingleton().createManual( - "transparent.png", - Ogre::ResourceGroupManager::DEFAULT_RESOURCE_GROUP_NAME, - Ogre::TEX_TYPE_2D, - 1, 1, - 0, - Ogre::PF_A8R8G8B8, - Ogre::TU_WRITE_ONLY); - std::vector buffer; - buffer.resize(1); - const float val = 0.7; - buffer[0] = (int(255*val) << 24) | (255 << 16) | (255 << 8) | 255; - memcpy(tex->getBuffer()->lock(Ogre::HardwareBuffer::HBL_DISCARD), &buffer[0], 1*4); - tex->getBuffer()->unlock(); - } - - void ResourcePlugin::initialize() - { - MYGUI_LOGGING("OpenMW_Resource_Plugin", Info, "initialize"); - - registerResources(); - registerWidgets(); - createTransparentBGTexture(); - - MyGUI::LanguageManager::getInstance().eventRequestTag = MyGUI::newDelegate(this, &ResourcePlugin::onRetrieveTag); - } - - void ResourcePlugin::shutdown() - { - /// \todo cleanup - - MYGUI_LOGGING("OpenMW_Resource_Plugin", Info, "shutdown"); - } - - void ResourcePlugin::onRetrieveTag(const MyGUI::UString& tag, MyGUI::UString& out) - { - if (!Gui::replaceTag(tag, out, mFallbackMap)) - out = tag; - } - -} diff --git a/plugins/mygui_resource_plugin/plugin.hpp b/plugins/mygui_resource_plugin/plugin.hpp deleted file mode 100644 index 6a06060d9..000000000 --- a/plugins/mygui_resource_plugin/plugin.hpp +++ /dev/null @@ -1,52 +0,0 @@ -#ifndef OPENMW_MYGUI_RESOURCE_PLUGIN_H -#define OPENMW_MYGUI_RESOURCE_PLUGIN_H - -#include -#include - -namespace MyGUIPlugin -{ - - /** - * @brief MyGUI plugin used to register Morrowind resources, custom widgets used in OpenMW, and load Morrowind fonts. - * @paragraph The plugin isn't used in OpenMW itself, but it is useful with the standalone MyGUI tools. To use it, - * change EditorPlugin.xml in Media/Tools/LayoutEditor/EditorPlugin.xml and add an entry for this plugin. - */ - class ResourcePlugin : public MyGUI::IPlugin - { - /*! Get the name of the plugin. - @remarks An implementation must be supplied for this method to uniquely - identify the plugin - */ - virtual const std::string& getName() const; - - /*! Perform the plugin initial installation sequence - */ - virtual void install(); - - /*! Perform any tasks the plugin needs to perform on full system - initialisation. - */ - virtual void initialize(); - - /*! Perform any tasks the plugin needs to perform when the system is shut down - */ - virtual void shutdown(); - - /*! Perform the final plugin uninstallation sequence - */ - virtual void uninstall(); - - private: - void registerResources(); - void registerWidgets(); - void createTransparentBGTexture(); - - void onRetrieveTag(const MyGUI::UString& tag, MyGUI::UString& out); - - std::map mFallbackMap; - }; - -} - -#endif diff --git a/plugins/mygui_resource_plugin/plugin_export.cpp b/plugins/mygui_resource_plugin/plugin_export.cpp deleted file mode 100644 index 0d6b4b804..000000000 --- a/plugins/mygui_resource_plugin/plugin_export.cpp +++ /dev/null @@ -1,17 +0,0 @@ -#include "plugin.hpp" -#include "MyGUI_PluginManager.h" - -MyGUIPlugin::ResourcePlugin* plugin_item = nullptr; - -extern "C" MYGUI_EXPORT_DLL void dllStartPlugin(void) -{ - plugin_item = new MyGUIPlugin::ResourcePlugin(); - MyGUI::PluginManager::getInstance().installPlugin(plugin_item); -} - -extern "C" MYGUI_EXPORT_DLL void dllStopPlugin(void) -{ - MyGUI::PluginManager::getInstance().uninstallPlugin(plugin_item); - delete plugin_item; - plugin_item = nullptr; -}