mirror of
https://github.com/TES3MP/openmw-tes3mp.git
synced 2025-10-08 13:26:33 +00:00
Merge upstream.
This commit is contained in:
commit
44b2cf2b7f
337 changed files with 1537 additions and 1371 deletions
|
@ -15,6 +15,7 @@ Programmers
|
||||||
Adam Hogan (aurix)
|
Adam Hogan (aurix)
|
||||||
Aesylwinn
|
Aesylwinn
|
||||||
aegis
|
aegis
|
||||||
|
AHSauge
|
||||||
Aleksandar Jovanov
|
Aleksandar Jovanov
|
||||||
Alex Haddad (rainChu)
|
Alex Haddad (rainChu)
|
||||||
Alex McKibben
|
Alex McKibben
|
||||||
|
@ -41,6 +42,7 @@ Programmers
|
||||||
Cory F. Cohen (cfcohen)
|
Cory F. Cohen (cfcohen)
|
||||||
Cris Mihalache (Mirceam)
|
Cris Mihalache (Mirceam)
|
||||||
crussell187
|
crussell187
|
||||||
|
DanielVukelich
|
||||||
darkf
|
darkf
|
||||||
devnexen
|
devnexen
|
||||||
Dieho
|
Dieho
|
||||||
|
@ -155,6 +157,8 @@ Programmers
|
||||||
terrorfisch
|
terrorfisch
|
||||||
thegriglat
|
thegriglat
|
||||||
Thomas Luppi (Digmaster)
|
Thomas Luppi (Digmaster)
|
||||||
|
tri4ng1e
|
||||||
|
unelsson
|
||||||
Will Herrmann (Thunderforge)
|
Will Herrmann (Thunderforge)
|
||||||
Tom Mason (wheybags)
|
Tom Mason (wheybags)
|
||||||
Torben Leif Carrington (TorbenC)
|
Torben Leif Carrington (TorbenC)
|
||||||
|
@ -224,7 +228,7 @@ Artwork
|
||||||
|
|
||||||
Necrod - OpenMW Logo
|
Necrod - OpenMW Logo
|
||||||
Mickey Lyle (raevol) - Wordpress Theme
|
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
|
Inactive Contributors
|
||||||
---------------------
|
---------------------
|
||||||
|
|
|
@ -303,25 +303,25 @@ if [ -z $SKIP_DOWNLOAD ]; then
|
||||||
# Boost
|
# Boost
|
||||||
if [ -z $APPVEYOR ]; then
|
if [ -z $APPVEYOR ]; then
|
||||||
download "Boost 1.61.0" \
|
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"
|
"boost-1.61.0-msvc${MSVC_YEAR}-win${BITS}.exe"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
# Bullet
|
# Bullet
|
||||||
download "Bullet 2.86" \
|
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"
|
"Bullet-2.86-msvc${MSVC_YEAR}-win${BITS}.7z"
|
||||||
|
|
||||||
# FFmpeg
|
# FFmpeg
|
||||||
download "FFmpeg 3.2.4" \
|
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" \
|
"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"
|
"ffmpeg-3.2.4-dev-win${BITS}.zip"
|
||||||
|
|
||||||
# MyGUI
|
# MyGUI
|
||||||
download "MyGUI 3.2.2" \
|
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"
|
"MyGUI-3.2.2-msvc${MSVC_YEAR}-win${BITS}.7z"
|
||||||
|
|
||||||
# OpenAL
|
# OpenAL
|
||||||
|
@ -331,7 +331,7 @@ if [ -z $SKIP_DOWNLOAD ]; then
|
||||||
|
|
||||||
# OSG
|
# OSG
|
||||||
download "OpenSceneGraph 3.4.1-scrawl" \
|
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"
|
"OSG-3.4.1-scrawl-msvc${MSVC_YEAR}-win${BITS}.7z"
|
||||||
|
|
||||||
# Qt
|
# Qt
|
||||||
|
@ -343,9 +343,9 @@ if [ -z $SKIP_DOWNLOAD ]; then
|
||||||
fi
|
fi
|
||||||
|
|
||||||
download "Qt 5.7.2" \
|
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" \
|
"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"
|
"qt-5-install.qs"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
@ -613,8 +613,7 @@ fi
|
||||||
SUFFIX=""
|
SUFFIX=""
|
||||||
fi
|
fi
|
||||||
|
|
||||||
add_runtime_dlls "$(pwd)/bin/lib"{EGL,GLESv2}${SUFFIX}.dll \
|
add_runtime_dlls "$(pwd)/bin/Qt5"{Core,Gui,Network,OpenGL,Widgets}${SUFFIX}.dll
|
||||||
"$(pwd)/bin/Qt5"{Core,Gui,Network,OpenGL,Widgets}${SUFFIX}.dll
|
|
||||||
add_qt_platform_dlls "$(pwd)/plugins/platforms/qwindows${SUFFIX}.dll"
|
add_qt_platform_dlls "$(pwd)/plugins/platforms/qwindows${SUFFIX}.dll"
|
||||||
|
|
||||||
echo Done.
|
echo Done.
|
||||||
|
|
|
@ -135,6 +135,8 @@ if (WIN32)
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
# Dependencies
|
# Dependencies
|
||||||
|
find_package(OpenGL REQUIRED)
|
||||||
|
|
||||||
if (USE_QT)
|
if (USE_QT)
|
||||||
message(STATUS "Using Qt${DESIRED_QT_VERSION}")
|
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)
|
set(OPENMW_USE_UNSHIELD TRUE)
|
||||||
endif()
|
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
|
# Fix for not visible pthreads functions for linker with glibc 2.15
|
||||||
if (UNIX AND NOT APPLE)
|
if (UNIX AND NOT APPLE)
|
||||||
find_package (Threads)
|
find_package (Threads)
|
||||||
|
@ -505,8 +501,8 @@ if(WIN32)
|
||||||
SET(CPACK_PACKAGE_DESCRIPTION_FILE "${OpenMW_SOURCE_DIR}/README.md")
|
SET(CPACK_PACKAGE_DESCRIPTION_FILE "${OpenMW_SOURCE_DIR}/README.md")
|
||||||
SET(CPACK_NSIS_EXECUTABLES_DIRECTORY ".")
|
SET(CPACK_NSIS_EXECUTABLES_DIRECTORY ".")
|
||||||
SET(CPACK_NSIS_DISPLAY_NAME "OpenMW ${OPENMW_VERSION}")
|
SET(CPACK_NSIS_DISPLAY_NAME "OpenMW ${OPENMW_VERSION}")
|
||||||
SET(CPACK_NSIS_HELP_LINK "http:\\\\\\\\www.openmw.org")
|
SET(CPACK_NSIS_HELP_LINK "https:\\\\\\\\www.openmw.org")
|
||||||
SET(CPACK_NSIS_URL_INFO_ABOUT "http:\\\\\\\\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_INSTALLED_ICON_NAME "openmw-launcher.exe")
|
||||||
SET(CPACK_NSIS_MUI_FINISHPAGE_RUN "openmw-launcher.exe")
|
SET(CPACK_NSIS_MUI_FINISHPAGE_RUN "openmw-launcher.exe")
|
||||||
SET(CPACK_NSIS_MUI_ICON "${OpenMW_SOURCE_DIR}/files/windows/openmw.ico")
|
SET(CPACK_NSIS_MUI_ICON "${OpenMW_SOURCE_DIR}/files/windows/openmw.ico")
|
||||||
|
@ -549,11 +545,6 @@ endif()
|
||||||
# Components
|
# Components
|
||||||
add_subdirectory (components)
|
add_subdirectory (components)
|
||||||
|
|
||||||
# Plugins
|
|
||||||
#if (BUILD_MYGUI_PLUGIN)
|
|
||||||
# add_subdirectory(plugins/mygui_resource_plugin)
|
|
||||||
#endif()
|
|
||||||
|
|
||||||
# Apps and tools
|
# Apps and tools
|
||||||
if (BUILD_OPENMW)
|
if (BUILD_OPENMW)
|
||||||
add_subdirectory( apps/openmw )
|
add_subdirectory( apps/openmw )
|
||||||
|
|
|
@ -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:
|
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.
|
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:
|
Note:
|
||||||
- Tasks set to 'openmw-future' are usually out of the current scope of the project and can't be started yet.
|
* 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.
|
* Bugs that are not 'Confirmed' should be confirmed first.
|
||||||
- Larger Features should have a discussion before you start implementing.
|
* Often, it's best to start a discussion about possible solutions before you jump into coding, especially for larger features.
|
||||||
- In many cases, it's best to have a discussion about possible solutions before you jump into coding.
|
|
||||||
|
|
||||||
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!
|
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
|
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
|
* Summary of the changes made
|
||||||
* Reasoning / motivation behind the change
|
* Reasoning / motivation behind the change
|
||||||
* What testing you have carried out to verify the change
|
* What testing you have carried out to verify the change
|
||||||
|
|
||||||
Furthermore, we advise to:
|
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.
|
* 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).
|
* 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.
|
* 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.
|
* 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"
|
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 <i>like</i> these "bugs" because that is what they remember the game for.
|
* Many people will actually <i>like</i> 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.
|
* 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:
|
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:
|
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.
|
* 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.
|
* 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.
|
* 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.
|
* 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 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.
|
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/)
|
||||||
|
|
||||||
|
|
8
LICENSE
8
LICENSE
|
@ -1,7 +1,7 @@
|
||||||
GNU GENERAL PUBLIC LICENSE
|
GNU GENERAL PUBLIC LICENSE
|
||||||
Version 3, 29 June 2007
|
Version 3, 29 June 2007
|
||||||
|
|
||||||
Copyright (C) 2007 Free Software Foundation, Inc. <http://fsf.org/>
|
Copyright (C) 2007 Free Software Foundation, Inc. <https://fsf.org/>
|
||||||
Everyone is permitted to copy and distribute verbatim copies
|
Everyone is permitted to copy and distribute verbatim copies
|
||||||
of this license document, but changing it is not allowed.
|
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.
|
GNU General Public License for more details.
|
||||||
|
|
||||||
You should have received a copy of the GNU General Public License
|
You should have received a copy of the GNU General Public License
|
||||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
Also add information on how to contact you by electronic and paper mail.
|
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,
|
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.
|
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
|
For more information on this, and how to apply and follow the GNU GPL, see
|
||||||
<http://www.gnu.org/licenses/>.
|
<https://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
The GNU General Public License does not permit incorporating your program
|
The GNU General Public License does not permit incorporating your program
|
||||||
into proprietary programs. If your program is a subroutine library, you
|
into proprietary programs. If your program is a subroutine library, you
|
||||||
may consider it more useful to permit linking proprietary applications with
|
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
|
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
|
Public License instead of this License. But first, please read
|
||||||
<http://www.gnu.org/philosophy/why-not-lgpl.html>.
|
<https://www.gnu.org/philosophy/why-not-lgpl.html>.
|
||||||
|
|
|
@ -9,7 +9,7 @@ OpenMW also comes with OpenMW-CS, a replacement for Morrowind's TES Construction
|
||||||
|
|
||||||
* Version: 0.43.0
|
* Version: 0.43.0
|
||||||
* License: GPLv3 (see [LICENSE](https://github.com/OpenMW/openmw/blob/master/LICENSE) for more information)
|
* 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
|
* IRC: #openmw on irc.freenode.net
|
||||||
|
|
||||||
Font Licenses:
|
Font Licenses:
|
||||||
|
@ -30,8 +30,8 @@ Getting Started
|
||||||
* [Build from source](https://wiki.openmw.org/index.php?title=Development_Environment_Setup)
|
* [Build from source](https://wiki.openmw.org/index.php?title=Development_Environment_Setup)
|
||||||
* [Testing the game](https://wiki.openmw.org/index.php?title=Testing)
|
* [Testing the game](https://wiki.openmw.org/index.php?title=Testing)
|
||||||
* [How to contribute](https://wiki.openmw.org/index.php?title=Contribution_Wanted)
|
* [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!
|
* [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](http://bugs.openmw.org/projects/openmw/issues?utf8=%E2%9C%93&set_filter=1&f%5B%5D=status_id&op%5Bstatus_id%5D=%3D&v%5Bstatus_id%5D%5B%5D=7&f%5B%5D=tracker_id&op%5Btracker_id%5D=%3D&v%5Btracker_id%5D%5B%5D=1&f%5B%5D=&c%5B%5D=project&c%5B%5D=tracker&c%5B%5D=status&c%5B%5D=priority&c%5B%5D=subject&c%5B%5D=assigned_to&c%5B%5D=updated_on&group_by=tracker)
|
* [Known issues](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
|
The data path
|
||||||
-------------
|
-------------
|
||||||
|
|
|
@ -694,7 +694,7 @@ void Record<ESM::Dialogue>::print()
|
||||||
// loads, rather than loading and then dumping. :-( Anyone mind if
|
// loads, rather than loading and then dumping. :-( Anyone mind if
|
||||||
// I change this?
|
// I change this?
|
||||||
ESM::Dialogue::InfoContainer::iterator iit;
|
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;
|
std::cout << "INFO!" << iit->mId << std::endl;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1040,45 +1040,47 @@ void Record<ESM::NPC>::print()
|
||||||
|
|
||||||
if (mData.mNpdtType == ESM::NPC::NPC_WITH_AUTOCALCULATED_STATS)
|
if (mData.mNpdtType == ESM::NPC::NPC_WITH_AUTOCALCULATED_STATS)
|
||||||
{
|
{
|
||||||
std::cout << " Level: " << mData.mNpdt12.mLevel << std::endl;
|
std::cout << " Level: " << mData.mNpdt.mLevel << std::endl;
|
||||||
std::cout << " Reputation: " << (int)mData.mNpdt12.mReputation << std::endl;
|
std::cout << " Reputation: " << (int)mData.mNpdt.mReputation << std::endl;
|
||||||
std::cout << " Disposition: " << (int)mData.mNpdt12.mDisposition << std::endl;
|
std::cout << " Disposition: " << (int)mData.mNpdt.mDisposition << std::endl;
|
||||||
std::cout << " Rank: " << (int)mData.mNpdt12.mRank << std::endl;
|
std::cout << " Rank: " << (int)mData.mNpdt.mRank << std::endl;
|
||||||
std::cout << " Unknown1: "
|
//Why do we want to print these fields? They are padding in the struct and contain
|
||||||
<< (unsigned int)((unsigned char)mData.mNpdt12.mUnknown1) << std::endl;
|
// nothing of real value. Now we don't deal with NPDTstruct12 in runtime either...
|
||||||
std::cout << " Unknown2: "
|
//std::cout << " Unknown1: "
|
||||||
<< (unsigned int)((unsigned char)mData.mNpdt12.mUnknown2) << std::endl;
|
// << (unsigned int)((unsigned char)mData.mNpdt12.mUnknown1) << std::endl;
|
||||||
std::cout << " Unknown3: "
|
//std::cout << " Unknown2: "
|
||||||
<< (unsigned int)((unsigned char)mData.mNpdt12.mUnknown3) << std::endl;
|
// << (unsigned int)((unsigned char)mData.mNpdt12.mUnknown2) << std::endl;
|
||||||
std::cout << " Gold: " << mData.mNpdt12.mGold << std::endl;
|
//std::cout << " Unknown3: "
|
||||||
|
// << (unsigned int)((unsigned char)mData.mNpdt12.mUnknown3) << std::endl;
|
||||||
|
std::cout << " Gold: " << mData.mNpdt.mGold << std::endl;
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
std::cout << " Level: " << mData.mNpdt52.mLevel << std::endl;
|
std::cout << " Level: " << mData.mNpdt.mLevel << std::endl;
|
||||||
std::cout << " Reputation: " << (int)mData.mNpdt52.mReputation << std::endl;
|
std::cout << " Reputation: " << (int)mData.mNpdt.mReputation << std::endl;
|
||||||
std::cout << " Disposition: " << (int)mData.mNpdt52.mDisposition << std::endl;
|
std::cout << " Disposition: " << (int)mData.mNpdt.mDisposition << std::endl;
|
||||||
std::cout << " Rank: " << (int)mData.mNpdt52.mRank << std::endl;
|
std::cout << " Rank: " << (int)mData.mNpdt.mRank << std::endl;
|
||||||
std::cout << " FactionID: " << (int)mData.mNpdt52.mFactionID << std::endl;
|
std::cout << " FactionID: " << (int)mData.mNpdt.mFactionID << std::endl;
|
||||||
|
|
||||||
std::cout << " Attributes:" << std::endl;
|
std::cout << " Attributes:" << std::endl;
|
||||||
std::cout << " Strength: " << (int)mData.mNpdt52.mStrength << std::endl;
|
std::cout << " Strength: " << (int)mData.mNpdt.mStrength << std::endl;
|
||||||
std::cout << " Intelligence: " << (int)mData.mNpdt52.mIntelligence << std::endl;
|
std::cout << " Intelligence: " << (int)mData.mNpdt.mIntelligence << std::endl;
|
||||||
std::cout << " Willpower: " << (int)mData.mNpdt52.mWillpower << std::endl;
|
std::cout << " Willpower: " << (int)mData.mNpdt.mWillpower << std::endl;
|
||||||
std::cout << " Agility: " << (int)mData.mNpdt52.mAgility << std::endl;
|
std::cout << " Agility: " << (int)mData.mNpdt.mAgility << std::endl;
|
||||||
std::cout << " Speed: " << (int)mData.mNpdt52.mSpeed << std::endl;
|
std::cout << " Speed: " << (int)mData.mNpdt.mSpeed << std::endl;
|
||||||
std::cout << " Endurance: " << (int)mData.mNpdt52.mEndurance << std::endl;
|
std::cout << " Endurance: " << (int)mData.mNpdt.mEndurance << std::endl;
|
||||||
std::cout << " Personality: " << (int)mData.mNpdt52.mPersonality << std::endl;
|
std::cout << " Personality: " << (int)mData.mNpdt.mPersonality << std::endl;
|
||||||
std::cout << " Luck: " << (int)mData.mNpdt52.mLuck << std::endl;
|
std::cout << " Luck: " << (int)mData.mNpdt.mLuck << std::endl;
|
||||||
|
|
||||||
std::cout << " Skills:" << std::endl;
|
std::cout << " Skills:" << std::endl;
|
||||||
for (int i = 0; i != ESM::Skill::Length; i++)
|
for (int i = 0; i != ESM::Skill::Length; i++)
|
||||||
std::cout << " " << skillLabel(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 << " Health: " << mData.mNpdt.mHealth << std::endl;
|
||||||
std::cout << " Magicka: " << mData.mNpdt52.mMana << std::endl;
|
std::cout << " Magicka: " << mData.mNpdt.mMana << std::endl;
|
||||||
std::cout << " Fatigue: " << mData.mNpdt52.mFatigue << std::endl;
|
std::cout << " Fatigue: " << mData.mNpdt.mFatigue << std::endl;
|
||||||
std::cout << " Unknown: " << (int)mData.mNpdt52.mUnknown << std::endl;
|
std::cout << " Unknown: " << (int)mData.mNpdt.mUnknown << std::endl;
|
||||||
std::cout << " Gold: " << mData.mNpdt52.mGold << std::endl;
|
std::cout << " Gold: " << mData.mNpdt.mGold << std::endl;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::vector<ESM::ContItem>::iterator cit;
|
std::vector<ESM::ContItem>::iterator cit;
|
||||||
|
@ -1123,7 +1125,7 @@ void Record<ESM::Pathgrid>::print()
|
||||||
|
|
||||||
int i = 0;
|
int i = 0;
|
||||||
ESM::Pathgrid::PointList::iterator pit;
|
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 << " Point[" << i << "]:" << std::endl;
|
||||||
std::cout << " Coordinates: (" << pit->mX << ","
|
std::cout << " Coordinates: (" << pit->mX << ","
|
||||||
|
@ -1135,7 +1137,7 @@ void Record<ESM::Pathgrid>::print()
|
||||||
}
|
}
|
||||||
i = 0;
|
i = 0;
|
||||||
ESM::Pathgrid::EdgeList::iterator eit;
|
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;
|
std::cout << " Edge[" << i << "]: " << eit->mV0 << " -> " << eit->mV1 << std::endl;
|
||||||
if (eit->mV0 >= mData.mData.mS2 || eit->mV1 >= mData.mData.mS2)
|
if (eit->mV0 >= mData.mData.mS2 || eit->mV1 >= mData.mData.mS2)
|
||||||
|
|
|
@ -122,7 +122,7 @@ public:
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
mContext->mPlayer.mObject.mCreatureStats.mLevel = npc.mNpdt52.mLevel;
|
mContext->mPlayer.mObject.mCreatureStats.mLevel = npc.mNpdt.mLevel;
|
||||||
mContext->mPlayerBase = npc;
|
mContext->mPlayerBase = npc;
|
||||||
ESM::SpellState::SpellParams empty;
|
ESM::SpellState::SpellParams empty;
|
||||||
// FIXME: player start spells and birthsign spells aren't listed here,
|
// FIXME: player start spells and birthsign spells aren't listed here,
|
||||||
|
|
|
@ -377,7 +377,7 @@ namespace ESSImport
|
||||||
profile.mPlayerClassName = context.mCustomPlayerClassName;
|
profile.mPlayerClassName = context.mCustomPlayerClassName;
|
||||||
else
|
else
|
||||||
profile.mPlayerClassId = context.mPlayerBase.mClass;
|
profile.mPlayerClassId = context.mPlayerBase.mClass;
|
||||||
profile.mPlayerLevel = context.mPlayerBase.mNpdt52.mLevel;
|
profile.mPlayerLevel = context.mPlayerBase.mNpdt.mLevel;
|
||||||
profile.mPlayerName = header.mGameData.mPlayerName.toString();
|
profile.mPlayerName = header.mGameData.mPlayerName.toString();
|
||||||
|
|
||||||
writeScreenshot(header, profile);
|
writeScreenshot(header, profile);
|
||||||
|
|
|
@ -106,7 +106,7 @@ if (DESIRED_QT_VERSION MATCHES 4)
|
||||||
target_link_libraries(openmw-launcher ${QT_QTMAIN_LIBRARY})
|
target_link_libraries(openmw-launcher ${QT_QTMAIN_LIBRARY})
|
||||||
endif(WIN32)
|
endif(WIN32)
|
||||||
else()
|
else()
|
||||||
qt5_use_modules(openmw-launcher Widgets Core)
|
target_link_libraries(openmw-launcher Qt5::Widgets Qt5::Core)
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
if (BUILD_WITH_CODE_COVERAGE)
|
if (BUILD_WITH_CODE_COVERAGE)
|
||||||
|
|
|
@ -35,9 +35,11 @@ bool Launcher::AdvancedPage::loadSettings()
|
||||||
loadSettingBool(grabCursorCheckBox, "grab cursor", "Input");
|
loadSettingBool(grabCursorCheckBox, "grab cursor", "Input");
|
||||||
loadSettingBool(toggleSneakCheckBox, "toggle sneak", "Input");
|
loadSettingBool(toggleSneakCheckBox, "toggle sneak", "Input");
|
||||||
|
|
||||||
// Other Settings
|
// Saves Settings
|
||||||
loadSettingBool(timePlayedCheckbox, "timeplayed", "Saves");
|
loadSettingBool(timePlayedCheckbox, "timeplayed", "Saves");
|
||||||
|
maximumQuicksavesComboBox->setValue(mEngineSettings.getInt("max quicksaves", "Saves"));
|
||||||
|
|
||||||
|
// Other Settings
|
||||||
QString screenshotFormatString = QString::fromStdString(mEngineSettings.getString("screenshot format", "General")).toUpper();
|
QString screenshotFormatString = QString::fromStdString(mEngineSettings.getString("screenshot format", "General")).toUpper();
|
||||||
if (screenshotFormatComboBox->findText(screenshotFormatString) == -1)
|
if (screenshotFormatComboBox->findText(screenshotFormatString) == -1)
|
||||||
screenshotFormatComboBox->addItem(screenshotFormatString);
|
screenshotFormatComboBox->addItem(screenshotFormatString);
|
||||||
|
@ -69,9 +71,14 @@ void Launcher::AdvancedPage::saveSettings()
|
||||||
saveSettingBool(grabCursorCheckBox, "grab cursor", "Input");
|
saveSettingBool(grabCursorCheckBox, "grab cursor", "Input");
|
||||||
saveSettingBool(toggleSneakCheckBox, "toggle sneak", "Input");
|
saveSettingBool(toggleSneakCheckBox, "toggle sneak", "Input");
|
||||||
|
|
||||||
// Other Settings
|
// Saves Settings
|
||||||
saveSettingBool(timePlayedCheckbox, "timeplayed", "Saves");
|
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();
|
std::string screenshotFormatString = screenshotFormatComboBox->currentText().toLower().toStdString();
|
||||||
if (screenshotFormatString != mEngineSettings.getString("screenshot format", "General"))
|
if (screenshotFormatString != mEngineSettings.getString("screenshot format", "General"))
|
||||||
mEngineSettings.setString("screenshot format", "General", screenshotFormatString);
|
mEngineSettings.setString("screenshot format", "General", screenshotFormatString);
|
||||||
|
|
|
@ -33,12 +33,12 @@ bool hasExtension(std::string filename, std::string extensionToFind)
|
||||||
}
|
}
|
||||||
|
|
||||||
///See if the file has the "nif" extension.
|
///See if the file has the "nif" extension.
|
||||||
bool isNIF(std::string filename)
|
bool isNIF(const std::string & filename)
|
||||||
{
|
{
|
||||||
return hasExtension(filename,"nif");
|
return hasExtension(filename,"nif");
|
||||||
}
|
}
|
||||||
///See if the file has the "bsa" extension.
|
///See if the file has the "bsa" extension.
|
||||||
bool isBSA(std::string filename)
|
bool isBSA(const std::string & filename)
|
||||||
{
|
{
|
||||||
return hasExtension(filename,"bsa");
|
return hasExtension(filename,"bsa");
|
||||||
}
|
}
|
||||||
|
|
|
@ -246,7 +246,7 @@ if (DESIRED_QT_VERSION MATCHES 4)
|
||||||
target_link_libraries(openmw-cs ${QT_QTMAIN_LIBRARY})
|
target_link_libraries(openmw-cs ${QT_QTMAIN_LIBRARY})
|
||||||
endif()
|
endif()
|
||||||
else()
|
else()
|
||||||
qt5_use_modules(openmw-cs Widgets Core Network OpenGL)
|
target_link_libraries(openmw-cs Qt5::Widgets Qt5::Core Qt5::Network Qt5::OpenGL)
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
if (WIN32)
|
if (WIN32)
|
||||||
|
|
|
@ -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
|
// We do not use isString() here, because there could be a pre-defined filter with an ID that is
|
||||||
// equal a filter keyword.
|
// 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))
|
if (getNextToken()!=Token (Token::Type_EOS))
|
||||||
{
|
{
|
||||||
|
|
|
@ -49,7 +49,7 @@ namespace CSMPrefs
|
||||||
ShortcutMap::iterator shortcutListIt = mWidgetShortcuts.find(widget);
|
ShortcutMap::iterator shortcutListIt = mWidgetShortcuts.find(widget);
|
||||||
if (shortcutListIt != mWidgetShortcuts.end())
|
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());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -32,9 +32,6 @@ void CSMTools::ClassCheckStage::perform (int stage, CSMDoc::Messages& messages)
|
||||||
if (class_.mName.empty())
|
if (class_.mName.empty())
|
||||||
messages.push_back (std::make_pair (id, class_.mId + " has an empty name"));
|
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
|
// test for invalid attributes
|
||||||
for (int i=0; i<2; ++i)
|
for (int i=0; i<2; ++i)
|
||||||
if (class_.mData.mAttribute[i]==-1)
|
if (class_.mData.mAttribute[i]==-1)
|
||||||
|
|
|
@ -29,7 +29,7 @@ void CSMTools::PathgridCheckStage::perform (int stage, CSMDoc::Messages& message
|
||||||
CSMWorld::UniversalId id (CSMWorld::UniversalId::Type_Pathgrid, pathgrid.mId);
|
CSMWorld::UniversalId id (CSMWorld::UniversalId::Type_Pathgrid, pathgrid.mId);
|
||||||
|
|
||||||
// check the number of pathgrid points
|
// check the number of pathgrid points
|
||||||
if (pathgrid.mData.mS2 > static_cast<int>(pathgrid.mPoints.size()))
|
if (pathgrid.mData.mS2 < static_cast<int>(pathgrid.mPoints.size()))
|
||||||
messages.add (id, pathgrid.mId + " has less points than expected", "", CSMDoc::Message::Severity_Error);
|
messages.add (id, pathgrid.mId + " has less points than expected", "", CSMDoc::Message::Severity_Error);
|
||||||
else if (pathgrid.mData.mS2 > static_cast<int>(pathgrid.mPoints.size()))
|
else if (pathgrid.mData.mS2 > static_cast<int>(pathgrid.mPoints.size()))
|
||||||
messages.add (id, pathgrid.mId + " has more points than expected", "", CSMDoc::Message::Severity_Error);
|
messages.add (id, pathgrid.mId + " has more points than expected", "", CSMDoc::Message::Severity_Error);
|
||||||
|
|
|
@ -239,9 +239,7 @@ void CSMTools::ReferenceableCheckStage::bookCheck(
|
||||||
const CSMWorld::RecordBase& baseRecord = records.getRecord(stage);
|
const CSMWorld::RecordBase& baseRecord = records.getRecord(stage);
|
||||||
|
|
||||||
if (baseRecord.isDeleted())
|
if (baseRecord.isDeleted())
|
||||||
{
|
|
||||||
return;
|
return;
|
||||||
}
|
|
||||||
|
|
||||||
const ESM::Book& book = (dynamic_cast<const CSMWorld::Record<ESM::Book>& >(baseRecord)).get();
|
const ESM::Book& book = (dynamic_cast<const CSMWorld::Record<ESM::Book>& >(baseRecord)).get();
|
||||||
CSMWorld::UniversalId id(CSMWorld::UniversalId::Type_Book, book.mId);
|
CSMWorld::UniversalId id(CSMWorld::UniversalId::Type_Book, book.mId);
|
||||||
|
@ -260,9 +258,7 @@ void CSMTools::ReferenceableCheckStage::activatorCheck(
|
||||||
const CSMWorld::RecordBase& baseRecord = records.getRecord(stage);
|
const CSMWorld::RecordBase& baseRecord = records.getRecord(stage);
|
||||||
|
|
||||||
if (baseRecord.isDeleted())
|
if (baseRecord.isDeleted())
|
||||||
{
|
|
||||||
return;
|
return;
|
||||||
}
|
|
||||||
|
|
||||||
const ESM::Activator& activator = (dynamic_cast<const CSMWorld::Record<ESM::Activator>& >(baseRecord)).get();
|
const ESM::Activator& activator = (dynamic_cast<const CSMWorld::Record<ESM::Activator>& >(baseRecord)).get();
|
||||||
CSMWorld::UniversalId id(CSMWorld::UniversalId::Type_Activator, activator.mId);
|
CSMWorld::UniversalId id(CSMWorld::UniversalId::Type_Activator, activator.mId);
|
||||||
|
@ -283,9 +279,7 @@ void CSMTools::ReferenceableCheckStage::potionCheck(
|
||||||
const CSMWorld::RecordBase& baseRecord = records.getRecord(stage);
|
const CSMWorld::RecordBase& baseRecord = records.getRecord(stage);
|
||||||
|
|
||||||
if (baseRecord.isDeleted())
|
if (baseRecord.isDeleted())
|
||||||
{
|
|
||||||
return;
|
return;
|
||||||
}
|
|
||||||
|
|
||||||
const ESM::Potion& potion = (dynamic_cast<const CSMWorld::Record<ESM::Potion>& >(baseRecord)).get();
|
const ESM::Potion& potion = (dynamic_cast<const CSMWorld::Record<ESM::Potion>& >(baseRecord)).get();
|
||||||
CSMWorld::UniversalId id(CSMWorld::UniversalId::Type_Potion, potion.mId);
|
CSMWorld::UniversalId id(CSMWorld::UniversalId::Type_Potion, potion.mId);
|
||||||
|
@ -306,9 +300,7 @@ void CSMTools::ReferenceableCheckStage::apparatusCheck(
|
||||||
const CSMWorld::RecordBase& baseRecord = records.getRecord(stage);
|
const CSMWorld::RecordBase& baseRecord = records.getRecord(stage);
|
||||||
|
|
||||||
if (baseRecord.isDeleted())
|
if (baseRecord.isDeleted())
|
||||||
{
|
|
||||||
return;
|
return;
|
||||||
}
|
|
||||||
|
|
||||||
const ESM::Apparatus& apparatus = (dynamic_cast<const CSMWorld::Record<ESM::Apparatus>& >(baseRecord)).get();
|
const ESM::Apparatus& apparatus = (dynamic_cast<const CSMWorld::Record<ESM::Apparatus>& >(baseRecord)).get();
|
||||||
CSMWorld::UniversalId id(CSMWorld::UniversalId::Type_Apparatus, apparatus.mId);
|
CSMWorld::UniversalId id(CSMWorld::UniversalId::Type_Apparatus, apparatus.mId);
|
||||||
|
@ -329,9 +321,7 @@ void CSMTools::ReferenceableCheckStage::armorCheck(
|
||||||
const CSMWorld::RecordBase& baseRecord = records.getRecord(stage);
|
const CSMWorld::RecordBase& baseRecord = records.getRecord(stage);
|
||||||
|
|
||||||
if (baseRecord.isDeleted())
|
if (baseRecord.isDeleted())
|
||||||
{
|
|
||||||
return;
|
return;
|
||||||
}
|
|
||||||
|
|
||||||
const ESM::Armor& armor = (dynamic_cast<const CSMWorld::Record<ESM::Armor>& >(baseRecord)).get();
|
const ESM::Armor& armor = (dynamic_cast<const CSMWorld::Record<ESM::Armor>& >(baseRecord)).get();
|
||||||
CSMWorld::UniversalId id(CSMWorld::UniversalId::Type_Armor, armor.mId);
|
CSMWorld::UniversalId id(CSMWorld::UniversalId::Type_Armor, armor.mId);
|
||||||
|
@ -358,9 +348,7 @@ void CSMTools::ReferenceableCheckStage::clothingCheck(
|
||||||
const CSMWorld::RecordBase& baseRecord = records.getRecord(stage);
|
const CSMWorld::RecordBase& baseRecord = records.getRecord(stage);
|
||||||
|
|
||||||
if (baseRecord.isDeleted())
|
if (baseRecord.isDeleted())
|
||||||
{
|
|
||||||
return;
|
return;
|
||||||
}
|
|
||||||
|
|
||||||
const ESM::Clothing& clothing = (dynamic_cast<const CSMWorld::Record<ESM::Clothing>& >(baseRecord)).get();
|
const ESM::Clothing& clothing = (dynamic_cast<const CSMWorld::Record<ESM::Clothing>& >(baseRecord)).get();
|
||||||
CSMWorld::UniversalId id(CSMWorld::UniversalId::Type_Clothing, clothing.mId);
|
CSMWorld::UniversalId id(CSMWorld::UniversalId::Type_Clothing, clothing.mId);
|
||||||
|
@ -378,9 +366,7 @@ void CSMTools::ReferenceableCheckStage::containerCheck(
|
||||||
const CSMWorld::RecordBase& baseRecord = records.getRecord(stage);
|
const CSMWorld::RecordBase& baseRecord = records.getRecord(stage);
|
||||||
|
|
||||||
if (baseRecord.isDeleted())
|
if (baseRecord.isDeleted())
|
||||||
{
|
|
||||||
return;
|
return;
|
||||||
}
|
|
||||||
|
|
||||||
const ESM::Container& container = (dynamic_cast<const CSMWorld::Record<ESM::Container>& >(baseRecord)).get();
|
const ESM::Container& container = (dynamic_cast<const CSMWorld::Record<ESM::Container>& >(baseRecord)).get();
|
||||||
CSMWorld::UniversalId id(CSMWorld::UniversalId::Type_Container, container.mId);
|
CSMWorld::UniversalId id(CSMWorld::UniversalId::Type_Container, container.mId);
|
||||||
|
@ -512,9 +498,7 @@ void CSMTools::ReferenceableCheckStage::ingredientCheck(
|
||||||
const CSMWorld::RecordBase& baseRecord = records.getRecord(stage);
|
const CSMWorld::RecordBase& baseRecord = records.getRecord(stage);
|
||||||
|
|
||||||
if (baseRecord.isDeleted())
|
if (baseRecord.isDeleted())
|
||||||
{
|
|
||||||
return;
|
return;
|
||||||
}
|
|
||||||
|
|
||||||
const ESM::Ingredient& ingredient = (dynamic_cast<const CSMWorld::Record<ESM::Ingredient>& >(baseRecord)).get();
|
const ESM::Ingredient& ingredient = (dynamic_cast<const CSMWorld::Record<ESM::Ingredient>& >(baseRecord)).get();
|
||||||
CSMWorld::UniversalId id(CSMWorld::UniversalId::Type_Ingredient, ingredient.mId);
|
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"));
|
messages.push_back (std::make_pair (id, light.mId + " has negative light radius"));
|
||||||
|
|
||||||
if (light.mData.mFlags & ESM::Light::Carry)
|
if (light.mData.mFlags & ESM::Light::Carry)
|
||||||
{
|
|
||||||
inventoryItemCheck<ESM::Light>(light, messages, id.toString());
|
inventoryItemCheck<ESM::Light>(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
|
// Check that mentioned scripts exist
|
||||||
scriptCheck<ESM::Light>(light, messages, id.toString());
|
scriptCheck<ESM::Light>(light, messages, id.toString());
|
||||||
}
|
}
|
||||||
|
@ -596,9 +575,7 @@ void CSMTools::ReferenceableCheckStage::lockpickCheck(
|
||||||
const CSMWorld::RecordBase& baseRecord = records.getRecord(stage);
|
const CSMWorld::RecordBase& baseRecord = records.getRecord(stage);
|
||||||
|
|
||||||
if (baseRecord.isDeleted())
|
if (baseRecord.isDeleted())
|
||||||
{
|
|
||||||
return;
|
return;
|
||||||
}
|
|
||||||
|
|
||||||
const ESM::Lockpick& lockpick = (dynamic_cast<const CSMWorld::Record<ESM::Lockpick>& >(baseRecord)).get();
|
const ESM::Lockpick& lockpick = (dynamic_cast<const CSMWorld::Record<ESM::Lockpick>& >(baseRecord)).get();
|
||||||
CSMWorld::UniversalId id(CSMWorld::UniversalId::Type_Lockpick, lockpick.mId);
|
CSMWorld::UniversalId id(CSMWorld::UniversalId::Type_Lockpick, lockpick.mId);
|
||||||
|
@ -619,9 +596,7 @@ void CSMTools::ReferenceableCheckStage::miscCheck(
|
||||||
const CSMWorld::RecordBase& baseRecord = records.getRecord(stage);
|
const CSMWorld::RecordBase& baseRecord = records.getRecord(stage);
|
||||||
|
|
||||||
if (baseRecord.isDeleted())
|
if (baseRecord.isDeleted())
|
||||||
{
|
|
||||||
return;
|
return;
|
||||||
}
|
|
||||||
|
|
||||||
const ESM::Miscellaneous& miscellaneous = (dynamic_cast<const CSMWorld::Record<ESM::Miscellaneous>& >(baseRecord)).get();
|
const ESM::Miscellaneous& miscellaneous = (dynamic_cast<const CSMWorld::Record<ESM::Miscellaneous>& >(baseRecord)).get();
|
||||||
CSMWorld::UniversalId id(CSMWorld::UniversalId::Type_Miscellaneous, miscellaneous.mId);
|
CSMWorld::UniversalId id(CSMWorld::UniversalId::Type_Miscellaneous, miscellaneous.mId);
|
||||||
|
@ -644,12 +619,12 @@ void CSMTools::ReferenceableCheckStage::npcCheck (
|
||||||
const ESM::NPC& npc = (dynamic_cast<const CSMWorld::Record<ESM::NPC>& >(baseRecord)).get();
|
const ESM::NPC& npc = (dynamic_cast<const CSMWorld::Record<ESM::NPC>& >(baseRecord)).get();
|
||||||
CSMWorld::UniversalId id (CSMWorld::UniversalId::Type_Npc, npc.mId);
|
CSMWorld::UniversalId id (CSMWorld::UniversalId::Type_Npc, npc.mId);
|
||||||
|
|
||||||
short level(npc.mNpdt52.mLevel);
|
short level(npc.mNpdt.mLevel);
|
||||||
char disposition(npc.mNpdt52.mDisposition);
|
char disposition(npc.mNpdt.mDisposition);
|
||||||
char reputation(npc.mNpdt52.mReputation);
|
char reputation(npc.mNpdt.mReputation);
|
||||||
char rank(npc.mNpdt52.mRank);
|
char rank(npc.mNpdt.mRank);
|
||||||
//Don't know what unknown is for
|
//Don't know what unknown is for
|
||||||
int gold(npc.mNpdt52.mGold);
|
int gold(npc.mNpdt.mGold);
|
||||||
|
|
||||||
//Detect if player is present
|
//Detect if player is present
|
||||||
if (Misc::StringUtils::ciEqual(npc.mId, "player")) //Happy now, scrawl?
|
if (Misc::StringUtils::ciEqual(npc.mId, "player")) //Happy now, scrawl?
|
||||||
|
@ -663,36 +638,36 @@ void CSMTools::ReferenceableCheckStage::npcCheck (
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
level = npc.mNpdt12.mLevel;
|
level = npc.mNpdt.mLevel;
|
||||||
disposition = npc.mNpdt12.mDisposition;
|
disposition = npc.mNpdt.mDisposition;
|
||||||
reputation = npc.mNpdt12.mReputation;
|
reputation = npc.mNpdt.mReputation;
|
||||||
rank = npc.mNpdt12.mRank;
|
rank = npc.mNpdt.mRank;
|
||||||
gold = npc.mNpdt12.mGold;
|
gold = npc.mNpdt.mGold;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
if (npc.mNpdt52.mAgility == 0)
|
if (npc.mNpdt.mAgility == 0)
|
||||||
messages.push_back (std::make_pair (id, npc.mId + " agility has zero value"));
|
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"));
|
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"));
|
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"));
|
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"));
|
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"));
|
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"));
|
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"));
|
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"));
|
messages.push_back (std::make_pair (id, npc.mId + " has any empty name"));
|
||||||
|
|
||||||
if (npc.mClass.empty())
|
if (npc.mClass.empty())
|
||||||
{
|
messages.push_back (std::make_pair (id, npc.mId + " has an empty class"));
|
||||||
messages.push_back (std::make_pair (id, npc.mId + " has any empty class"));
|
|
||||||
}
|
|
||||||
else if (mClasses.searchId (npc.mClass) == -1)
|
else if (mClasses.searchId (npc.mClass) == -1)
|
||||||
{
|
|
||||||
messages.push_back (std::make_pair (id, npc.mId + " has invalid class"));
|
messages.push_back (std::make_pair (id, npc.mId + " has invalid class"));
|
||||||
}
|
|
||||||
|
|
||||||
if (npc.mRace.empty())
|
if (npc.mRace.empty())
|
||||||
{
|
messages.push_back (std::make_pair (id, npc.mId + " has an empty race"));
|
||||||
messages.push_back (std::make_pair (id, npc.mId + " has any empty race"));
|
|
||||||
}
|
|
||||||
else if (mRaces.searchId (npc.mRace) == -1)
|
else if (mRaces.searchId (npc.mRace) == -1)
|
||||||
{
|
|
||||||
messages.push_back (std::make_pair (id, npc.mId + " has invalid race"));
|
messages.push_back (std::make_pair (id, npc.mId + " has invalid race"));
|
||||||
}
|
|
||||||
|
|
||||||
if (disposition < 0)
|
if (disposition < 0)
|
||||||
messages.push_back (std::make_pair (id, npc.mId + " has negative disposition"));
|
messages.push_back (std::make_pair (id, npc.mId + " has negative disposition"));
|
||||||
|
@ -823,7 +790,7 @@ void CSMTools::ReferenceableCheckStage::weaponCheck(
|
||||||
{
|
{
|
||||||
//checking of health
|
//checking of health
|
||||||
if (weapon.mData.mHealth <= 0)
|
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)
|
if (weapon.mData.mReach < 0)
|
||||||
messages.push_back (std::make_pair (id, weapon.mId + " has negative reach"));
|
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);
|
const CSMWorld::RecordBase& baseRecord = records.getRecord(stage);
|
||||||
|
|
||||||
if (baseRecord.isDeleted())
|
if (baseRecord.isDeleted())
|
||||||
{
|
|
||||||
return;
|
return;
|
||||||
}
|
|
||||||
|
|
||||||
const ESM::Probe& probe = (dynamic_cast<const CSMWorld::Record<ESM::Probe>& >(baseRecord)).get();
|
const ESM::Probe& probe = (dynamic_cast<const CSMWorld::Record<ESM::Probe>& >(baseRecord)).get();
|
||||||
CSMWorld::UniversalId id(CSMWorld::UniversalId::Type_Probe, probe.mId);
|
CSMWorld::UniversalId id(CSMWorld::UniversalId::Type_Probe, probe.mId);
|
||||||
|
|
|
@ -27,7 +27,7 @@ void CSMTools::SoundCheckStage::perform (int stage, CSMDoc::Messages& messages)
|
||||||
CSMWorld::UniversalId id (CSMWorld::UniversalId::Type_Sound, sound.mId);
|
CSMWorld::UniversalId id (CSMWorld::UniversalId::Type_Sound, sound.mId);
|
||||||
|
|
||||||
if (sound.mData.mMinRange>sound.mData.mMaxRange)
|
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
|
/// \todo check, if the sound file exists
|
||||||
}
|
}
|
||||||
|
|
|
@ -61,12 +61,7 @@ CSMDoc::OperationHolder *CSMTools::Tools::getVerifier()
|
||||||
connect (&mVerifier, SIGNAL (reportMessage (const CSMDoc::Message&, int)),
|
connect (&mVerifier, SIGNAL (reportMessage (const CSMDoc::Message&, int)),
|
||||||
this, SLOT (verifierMessage (const CSMDoc::Message&, int)));
|
this, SLOT (verifierMessage (const CSMDoc::Message&, int)));
|
||||||
|
|
||||||
std::vector<std::string> mandatoryIds; // I want C++11, damn it!
|
std::vector<std::string> mandatoryIds {"Day", "DaysPassed", "GameHour", "Month", "PCRace"};
|
||||||
mandatoryIds.push_back ("Day");
|
|
||||||
mandatoryIds.push_back ("DaysPassed");
|
|
||||||
mandatoryIds.push_back ("GameHour");
|
|
||||||
mandatoryIds.push_back ("Month");
|
|
||||||
mandatoryIds.push_back ("PCRace");
|
|
||||||
|
|
||||||
mVerifierOperation->appendStage (new MandatoryIdStage (mData.getGlobals(),
|
mVerifierOperation->appendStage (new MandatoryIdStage (mData.getGlobals(),
|
||||||
CSMWorld::UniversalId (CSMWorld::UniversalId::Type_Globals), mandatoryIds));
|
CSMWorld::UniversalId (CSMWorld::UniversalId::Type_Globals), mandatoryIds));
|
||||||
|
|
|
@ -66,7 +66,7 @@ namespace CSMWorld
|
||||||
{ ColumnId_SleepForbidden, "Sleep Forbidden" },
|
{ ColumnId_SleepForbidden, "Sleep Forbidden" },
|
||||||
{ ColumnId_InteriorWater, "Interior Water" },
|
{ ColumnId_InteriorWater, "Interior Water" },
|
||||||
{ ColumnId_InteriorSky, "Interior Sky" },
|
{ ColumnId_InteriorSky, "Interior Sky" },
|
||||||
{ ColumnId_Model, "Model" },
|
{ ColumnId_Model, "Model/Animation" },
|
||||||
{ ColumnId_Script, "Script" },
|
{ ColumnId_Script, "Script" },
|
||||||
{ ColumnId_Icon, "Icon" },
|
{ ColumnId_Icon, "Icon" },
|
||||||
{ ColumnId_Weight, "Weight" },
|
{ ColumnId_Weight, "Weight" },
|
||||||
|
|
|
@ -962,6 +962,29 @@ int CSMWorld::Data::startLoading (const boost::filesystem::path& path, bool base
|
||||||
return mReader->getRecordCount();
|
return mReader->getRecordCount();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void CSMWorld::Data::loadFallbackEntries()
|
||||||
|
{
|
||||||
|
// Load default marker definitions, if game files do not have them for some reason
|
||||||
|
std::pair<std::string, std::string> 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<std::string, std::string> marker : markers)
|
||||||
|
{
|
||||||
|
if (mReferenceables.searchId (marker.first)==-1)
|
||||||
|
{
|
||||||
|
CSMWorld::Record<ESM::Static> 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)
|
bool CSMWorld::Data::continueLoading (CSMDoc::Messages& messages)
|
||||||
{
|
{
|
||||||
if (!mReader)
|
if (!mReader)
|
||||||
|
@ -983,6 +1006,9 @@ bool CSMWorld::Data::continueLoading (CSMDoc::Messages& messages)
|
||||||
mReader = 0;
|
mReader = 0;
|
||||||
|
|
||||||
mDialogue = 0;
|
mDialogue = 0;
|
||||||
|
|
||||||
|
loadFallbackEntries();
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -144,6 +144,8 @@ namespace CSMWorld
|
||||||
|
|
||||||
static int count (RecordBase::State state, const CollectionBase& collection);
|
static int count (RecordBase::State state, const CollectionBase& collection);
|
||||||
|
|
||||||
|
void loadFallbackEntries();
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
|
||||||
Data (ToUTF8::FromType encoding, bool fsStrict, const Files::PathContainer& dataPaths,
|
Data (ToUTF8::FromType encoding, bool fsStrict, const Files::PathContainer& dataPaths,
|
||||||
|
|
|
@ -914,7 +914,7 @@ void CSMWorld::NpcAttributesRefIdAdapter::setNestedTable (const RefIdColumn* col
|
||||||
ESM::NPC npc = record.get();
|
ESM::NPC npc = record.get();
|
||||||
|
|
||||||
// store the whole struct
|
// store the whole struct
|
||||||
npc.mNpdt52 =
|
npc.mNpdt =
|
||||||
static_cast<const NestedTableWrapper<std::vector<ESM::NPC::NPDTstruct52> > &>(nestedTable).mNestedTable.at(0);
|
static_cast<const NestedTableWrapper<std::vector<ESM::NPC::NPDTstruct52> > &>(nestedTable).mNestedTable.at(0);
|
||||||
|
|
||||||
record.setModified (npc);
|
record.setModified (npc);
|
||||||
|
@ -928,7 +928,7 @@ CSMWorld::NestedTableWrapperBase* CSMWorld::NpcAttributesRefIdAdapter::nestedTab
|
||||||
|
|
||||||
// return the whole struct
|
// return the whole struct
|
||||||
std::vector<ESM::NPC::NPDTstruct52> wrap;
|
std::vector<ESM::NPC::NPDTstruct52> wrap;
|
||||||
wrap.push_back(record.get().mNpdt52);
|
wrap.push_back(record.get().mNpdt);
|
||||||
// deleted by dtor of NestedTableStoring
|
// deleted by dtor of NestedTableStoring
|
||||||
return new NestedTableWrapper<std::vector<ESM::NPC::NPDTstruct52> >(wrap);
|
return new NestedTableWrapper<std::vector<ESM::NPC::NPDTstruct52> >(wrap);
|
||||||
}
|
}
|
||||||
|
@ -939,7 +939,7 @@ QVariant CSMWorld::NpcAttributesRefIdAdapter::getNestedData (const RefIdColumn *
|
||||||
const Record<ESM::NPC>& record =
|
const Record<ESM::NPC>& record =
|
||||||
static_cast<const Record<ESM::NPC>&> (data.getRecord (RefIdData::LocalIndex (index, UniversalId::Type_Npc)));
|
static_cast<const Record<ESM::NPC>&> (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)
|
if (subColIndex == 0)
|
||||||
return subRowIndex;
|
return subRowIndex;
|
||||||
|
@ -966,7 +966,7 @@ void CSMWorld::NpcAttributesRefIdAdapter::setNestedData (const RefIdColumn *colu
|
||||||
Record<ESM::NPC>& record =
|
Record<ESM::NPC>& record =
|
||||||
static_cast<Record<ESM::NPC>&> (data.getRecord (RefIdData::LocalIndex (row, UniversalId::Type_Npc)));
|
static_cast<Record<ESM::NPC>&> (data.getRecord (RefIdData::LocalIndex (row, UniversalId::Type_Npc)));
|
||||||
ESM::NPC npc = record.get();
|
ESM::NPC npc = record.get();
|
||||||
ESM::NPC::NPDTstruct52& npcStruct = npc.mNpdt52;
|
ESM::NPC::NPDTstruct52& npcStruct = npc.mNpdt;
|
||||||
|
|
||||||
if (subColIndex == 1)
|
if (subColIndex == 1)
|
||||||
switch(subRowIndex)
|
switch(subRowIndex)
|
||||||
|
@ -1021,7 +1021,7 @@ void CSMWorld::NpcSkillsRefIdAdapter::setNestedTable (const RefIdColumn* column,
|
||||||
ESM::NPC npc = record.get();
|
ESM::NPC npc = record.get();
|
||||||
|
|
||||||
// store the whole struct
|
// store the whole struct
|
||||||
npc.mNpdt52 =
|
npc.mNpdt =
|
||||||
static_cast<const NestedTableWrapper<std::vector<ESM::NPC::NPDTstruct52> > &>(nestedTable).mNestedTable.at(0);
|
static_cast<const NestedTableWrapper<std::vector<ESM::NPC::NPDTstruct52> > &>(nestedTable).mNestedTable.at(0);
|
||||||
|
|
||||||
record.setModified (npc);
|
record.setModified (npc);
|
||||||
|
@ -1035,7 +1035,7 @@ CSMWorld::NestedTableWrapperBase* CSMWorld::NpcSkillsRefIdAdapter::nestedTable (
|
||||||
|
|
||||||
// return the whole struct
|
// return the whole struct
|
||||||
std::vector<ESM::NPC::NPDTstruct52> wrap;
|
std::vector<ESM::NPC::NPDTstruct52> wrap;
|
||||||
wrap.push_back(record.get().mNpdt52);
|
wrap.push_back(record.get().mNpdt);
|
||||||
// deleted by dtor of NestedTableStoring
|
// deleted by dtor of NestedTableStoring
|
||||||
return new NestedTableWrapper<std::vector<ESM::NPC::NPDTstruct52> >(wrap);
|
return new NestedTableWrapper<std::vector<ESM::NPC::NPDTstruct52> >(wrap);
|
||||||
}
|
}
|
||||||
|
@ -1046,7 +1046,7 @@ QVariant CSMWorld::NpcSkillsRefIdAdapter::getNestedData (const RefIdColumn *colu
|
||||||
const Record<ESM::NPC>& record =
|
const Record<ESM::NPC>& record =
|
||||||
static_cast<const Record<ESM::NPC>&> (data.getRecord (RefIdData::LocalIndex (index, UniversalId::Type_Npc)));
|
static_cast<const Record<ESM::NPC>&> (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)
|
if (subRowIndex < 0 || subRowIndex >= ESM::Skill::Length)
|
||||||
throw std::runtime_error ("index out of range");
|
throw std::runtime_error ("index out of range");
|
||||||
|
@ -1065,7 +1065,7 @@ void CSMWorld::NpcSkillsRefIdAdapter::setNestedData (const RefIdColumn *column,
|
||||||
Record<ESM::NPC>& record =
|
Record<ESM::NPC>& record =
|
||||||
static_cast<Record<ESM::NPC>&> (data.getRecord (RefIdData::LocalIndex (row, UniversalId::Type_Npc)));
|
static_cast<Record<ESM::NPC>&> (data.getRecord (RefIdData::LocalIndex (row, UniversalId::Type_Npc)));
|
||||||
ESM::NPC npc = record.get();
|
ESM::NPC npc = record.get();
|
||||||
ESM::NPC::NPDTstruct52& npcStruct = npc.mNpdt52;
|
ESM::NPC::NPDTstruct52& npcStruct = npc.mNpdt;
|
||||||
|
|
||||||
if (subRowIndex < 0 || subRowIndex >= ESM::Skill::Length)
|
if (subRowIndex < 0 || subRowIndex >= ESM::Skill::Length)
|
||||||
throw std::runtime_error ("index out of range");
|
throw std::runtime_error ("index out of range");
|
||||||
|
@ -1130,30 +1130,30 @@ QVariant CSMWorld::NpcMiscRefIdAdapter::getNestedData (const RefIdColumn *column
|
||||||
if (autoCalc)
|
if (autoCalc)
|
||||||
switch (subColIndex)
|
switch (subColIndex)
|
||||||
{
|
{
|
||||||
case 0: return static_cast<int>(record.get().mNpdt12.mLevel);
|
case 0: return static_cast<int>(record.get().mNpdt.mLevel);
|
||||||
case 1: return QVariant(QVariant::UserType);
|
case 1: return QVariant(QVariant::UserType);
|
||||||
case 2: return QVariant(QVariant::UserType);
|
case 2: return QVariant(QVariant::UserType);
|
||||||
case 3: return QVariant(QVariant::UserType);
|
case 3: return QVariant(QVariant::UserType);
|
||||||
case 4: return QVariant(QVariant::UserType);
|
case 4: return QVariant(QVariant::UserType);
|
||||||
case 5: return static_cast<int>(record.get().mNpdt12.mDisposition);
|
case 5: return static_cast<int>(record.get().mNpdt.mDisposition);
|
||||||
case 6: return static_cast<int>(record.get().mNpdt12.mReputation);
|
case 6: return static_cast<int>(record.get().mNpdt.mReputation);
|
||||||
case 7: return static_cast<int>(record.get().mNpdt12.mRank);
|
case 7: return static_cast<int>(record.get().mNpdt.mRank);
|
||||||
case 8: return record.get().mNpdt12.mGold;
|
case 8: return record.get().mNpdt.mGold;
|
||||||
case 9: return record.get().mPersistent == true;
|
case 9: return record.get().mPersistent == true;
|
||||||
default: return QVariant(); // throw an exception here?
|
default: return QVariant(); // throw an exception here?
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
switch (subColIndex)
|
switch (subColIndex)
|
||||||
{
|
{
|
||||||
case 0: return static_cast<int>(record.get().mNpdt52.mLevel);
|
case 0: return static_cast<int>(record.get().mNpdt.mLevel);
|
||||||
case 1: return static_cast<int>(record.get().mNpdt52.mFactionID);
|
case 1: return static_cast<int>(record.get().mNpdt.mFactionID);
|
||||||
case 2: return static_cast<int>(record.get().mNpdt52.mHealth);
|
case 2: return static_cast<int>(record.get().mNpdt.mHealth);
|
||||||
case 3: return static_cast<int>(record.get().mNpdt52.mMana);
|
case 3: return static_cast<int>(record.get().mNpdt.mMana);
|
||||||
case 4: return static_cast<int>(record.get().mNpdt52.mFatigue);
|
case 4: return static_cast<int>(record.get().mNpdt.mFatigue);
|
||||||
case 5: return static_cast<int>(record.get().mNpdt52.mDisposition);
|
case 5: return static_cast<int>(record.get().mNpdt.mDisposition);
|
||||||
case 6: return static_cast<int>(record.get().mNpdt52.mReputation);
|
case 6: return static_cast<int>(record.get().mNpdt.mReputation);
|
||||||
case 7: return static_cast<int>(record.get().mNpdt52.mRank);
|
case 7: return static_cast<int>(record.get().mNpdt.mRank);
|
||||||
case 8: return record.get().mNpdt52.mGold;
|
case 8: return record.get().mNpdt.mGold;
|
||||||
case 9: return record.get().mPersistent == true;
|
case 9: return record.get().mPersistent == true;
|
||||||
default: return QVariant(); // throw an exception here?
|
default: return QVariant(); // throw an exception here?
|
||||||
}
|
}
|
||||||
|
@ -1171,30 +1171,30 @@ void CSMWorld::NpcMiscRefIdAdapter::setNestedData (const RefIdColumn *column,
|
||||||
if (autoCalc)
|
if (autoCalc)
|
||||||
switch(subColIndex)
|
switch(subColIndex)
|
||||||
{
|
{
|
||||||
case 0: npc.mNpdt12.mLevel = static_cast<short>(value.toInt()); break;
|
case 0: npc.mNpdt.mLevel = static_cast<short>(value.toInt()); break;
|
||||||
case 1: return;
|
case 1: return;
|
||||||
case 2: return;
|
case 2: return;
|
||||||
case 3: return;
|
case 3: return;
|
||||||
case 4: return;
|
case 4: return;
|
||||||
case 5: npc.mNpdt12.mDisposition = static_cast<signed char>(value.toInt()); break;
|
case 5: npc.mNpdt.mDisposition = static_cast<signed char>(value.toInt()); break;
|
||||||
case 6: npc.mNpdt12.mReputation = static_cast<signed char>(value.toInt()); break;
|
case 6: npc.mNpdt.mReputation = static_cast<signed char>(value.toInt()); break;
|
||||||
case 7: npc.mNpdt12.mRank = static_cast<signed char>(value.toInt()); break;
|
case 7: npc.mNpdt.mRank = static_cast<signed char>(value.toInt()); break;
|
||||||
case 8: npc.mNpdt12.mGold = value.toInt(); break;
|
case 8: npc.mNpdt.mGold = value.toInt(); break;
|
||||||
case 9: npc.mPersistent = value.toBool(); break;
|
case 9: npc.mPersistent = value.toBool(); break;
|
||||||
default: return; // throw an exception here?
|
default: return; // throw an exception here?
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
switch(subColIndex)
|
switch(subColIndex)
|
||||||
{
|
{
|
||||||
case 0: npc.mNpdt52.mLevel = static_cast<short>(value.toInt()); break;
|
case 0: npc.mNpdt.mLevel = static_cast<short>(value.toInt()); break;
|
||||||
case 1: npc.mNpdt52.mFactionID = static_cast<char>(value.toInt()); break;
|
case 1: npc.mNpdt.mFactionID = static_cast<char>(value.toInt()); break;
|
||||||
case 2: npc.mNpdt52.mHealth = static_cast<unsigned short>(value.toInt()); break;
|
case 2: npc.mNpdt.mHealth = static_cast<unsigned short>(value.toInt()); break;
|
||||||
case 3: npc.mNpdt52.mMana = static_cast<unsigned short>(value.toInt()); break;
|
case 3: npc.mNpdt.mMana = static_cast<unsigned short>(value.toInt()); break;
|
||||||
case 4: npc.mNpdt52.mFatigue = static_cast<unsigned short>(value.toInt()); break;
|
case 4: npc.mNpdt.mFatigue = static_cast<unsigned short>(value.toInt()); break;
|
||||||
case 5: npc.mNpdt52.mDisposition = static_cast<signed char>(value.toInt()); break;
|
case 5: npc.mNpdt.mDisposition = static_cast<signed char>(value.toInt()); break;
|
||||||
case 6: npc.mNpdt52.mReputation = static_cast<signed char>(value.toInt()); break;
|
case 6: npc.mNpdt.mReputation = static_cast<signed char>(value.toInt()); break;
|
||||||
case 7: npc.mNpdt52.mRank = static_cast<signed char>(value.toInt()); break;
|
case 7: npc.mNpdt.mRank = static_cast<signed char>(value.toInt()); break;
|
||||||
case 8: npc.mNpdt52.mGold = value.toInt(); break;
|
case 8: npc.mNpdt.mGold = value.toInt(); break;
|
||||||
case 9: npc.mPersistent = value.toBool(); break;
|
case 9: npc.mPersistent = value.toBool(); break;
|
||||||
default: return; // throw an exception here?
|
default: return; // throw an exception here?
|
||||||
}
|
}
|
||||||
|
@ -1375,8 +1375,6 @@ QVariant CSMWorld::CreatureAttackRefIdAdapter::getNestedData (const RefIdColumn
|
||||||
return subRowIndex + 1;
|
return subRowIndex + 1;
|
||||||
else if (subColIndex < 3) // 1 or 2
|
else if (subColIndex < 3) // 1 or 2
|
||||||
return creature.mData.mAttack[(subRowIndex * 2) + (subColIndex - 1)];
|
return creature.mData.mAttack[(subRowIndex * 2) + (subColIndex - 1)];
|
||||||
else
|
|
||||||
return QVariant(); // throw an exception here?
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void CSMWorld::CreatureAttackRefIdAdapter::setNestedData (const RefIdColumn *column,
|
void CSMWorld::CreatureAttackRefIdAdapter::setNestedData (const RefIdColumn *column,
|
||||||
|
|
|
@ -64,21 +64,21 @@ namespace
|
||||||
|
|
||||||
static const TypeData sIdArg[] =
|
static const TypeData sIdArg[] =
|
||||||
{
|
{
|
||||||
{ CSMWorld::UniversalId::Class_Record, CSMWorld::UniversalId::Type_Global, "Global Variable", ":./globvar.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_Gmst, "Game Setting", ":./gmst.png" },
|
||||||
{ CSMWorld::UniversalId::Class_Record, CSMWorld::UniversalId::Type_Skill, "Skill", ":./skill.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_Class, "Class", ":./class.png" },
|
||||||
{ CSMWorld::UniversalId::Class_Record, CSMWorld::UniversalId::Type_Faction, "Faction", ":./faction.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_Race, "Race", ":./race.png" },
|
||||||
{ CSMWorld::UniversalId::Class_Record, CSMWorld::UniversalId::Type_Sound, "Sound", ":./sound.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_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_Birthsign, "Birthsign", ":./birthsign.png" },
|
||||||
{ CSMWorld::UniversalId::Class_Record, CSMWorld::UniversalId::Type_Spell, "Spell", ":./spell.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_Topic, "Topic", ":./dialogue-topics.png" },
|
||||||
{ CSMWorld::UniversalId::Class_Record, CSMWorld::UniversalId::Type_Journal, "Journal", 0 },
|
{ CSMWorld::UniversalId::Class_Record, CSMWorld::UniversalId::Type_Journal, "Journal", ":./journal-topics.png" },
|
||||||
{ CSMWorld::UniversalId::Class_SubRecord, CSMWorld::UniversalId::Type_TopicInfo, "TopicInfo", 0 },
|
{ CSMWorld::UniversalId::Class_SubRecord, CSMWorld::UniversalId::Type_TopicInfo, "TopicInfo", ":./dialogue-topic-infos.png" },
|
||||||
{ CSMWorld::UniversalId::Class_SubRecord, CSMWorld::UniversalId::Type_JournalInfo, "JournalInfo", 0 },
|
{ 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, "Cell", ":./cell.png" },
|
||||||
{ CSMWorld::UniversalId::Class_Record, CSMWorld::UniversalId::Type_Cell_Missing, "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 },
|
{ 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_Door, "Door", ":./door.png" },
|
||||||
{ CSMWorld::UniversalId::Class_RefRecord, CSMWorld::UniversalId::Type_Ingredient, "Ingredient", ":./ingredient.png" },
|
{ CSMWorld::UniversalId::Class_RefRecord, CSMWorld::UniversalId::Type_Ingredient, "Ingredient", ":./ingredient.png" },
|
||||||
{ CSMWorld::UniversalId::Class_RefRecord, CSMWorld::UniversalId::Type_CreatureLevelledList,
|
{ 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,
|
{ CSMWorld::UniversalId::Class_RefRecord, CSMWorld::UniversalId::Type_ItemLevelledList,
|
||||||
"Item Levelled List", ":./leveled-item.png" },
|
"Item Levelled List", ":./leveled-item.png" },
|
||||||
{ CSMWorld::UniversalId::Class_RefRecord, CSMWorld::UniversalId::Type_Light, "Light", ":./light.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_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_Scene, "Scene", 0 },
|
||||||
{ CSMWorld::UniversalId::Class_Collection, CSMWorld::UniversalId::Type_Preview, "Preview", 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_Enchantment, "Enchantment", ":./enchantment.png" },
|
||||||
{ CSMWorld::UniversalId::Class_Record, CSMWorld::UniversalId::Type_BodyPart, "Body Part", 0 },
|
{ CSMWorld::UniversalId::Class_Record, CSMWorld::UniversalId::Type_BodyPart, "Body Part", ":./body-part.png" },
|
||||||
{ CSMWorld::UniversalId::Class_Resource, CSMWorld::UniversalId::Type_Mesh, "Mesh", 0 },
|
{ CSMWorld::UniversalId::Class_Resource, CSMWorld::UniversalId::Type_Mesh, "Mesh", ":resources-mesh"},
|
||||||
{ CSMWorld::UniversalId::Class_Resource, CSMWorld::UniversalId::Type_Icon, "Icon", 0 },
|
{ CSMWorld::UniversalId::Class_Resource, CSMWorld::UniversalId::Type_Icon, "Icon", ":resources-icon"},
|
||||||
{ CSMWorld::UniversalId::Class_Resource, CSMWorld::UniversalId::Type_Music, "Music", 0 },
|
{ CSMWorld::UniversalId::Class_Resource, CSMWorld::UniversalId::Type_Music, "Music", ":resources-music" },
|
||||||
{ CSMWorld::UniversalId::Class_Resource, CSMWorld::UniversalId::Type_SoundRes, "Sound File", 0 },
|
{ CSMWorld::UniversalId::Class_Resource, CSMWorld::UniversalId::Type_SoundRes, "Sound File", ":resources-sound" },
|
||||||
{ CSMWorld::UniversalId::Class_Resource, CSMWorld::UniversalId::Type_Texture, "Texture", 0 },
|
{ CSMWorld::UniversalId::Class_Resource, CSMWorld::UniversalId::Type_Texture, "Texture", ":resources-texture"},
|
||||||
{ CSMWorld::UniversalId::Class_Resource, CSMWorld::UniversalId::Type_Video, "Video", 0 },
|
{ 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_DebugProfile, "Debug Profile", 0 },
|
||||||
{ CSMWorld::UniversalId::Class_Record, CSMWorld::UniversalId::Type_SoundGen, "Sound Generator", 0 },
|
{ CSMWorld::UniversalId::Class_Record, CSMWorld::UniversalId::Type_SoundGen, "Sound Generator", ":./sound-generator.png" },
|
||||||
{ CSMWorld::UniversalId::Class_Record, CSMWorld::UniversalId::Type_MagicEffect, "Magic Effect", 0 },
|
{ CSMWorld::UniversalId::Class_Record, CSMWorld::UniversalId::Type_MagicEffect, "Magic Effect", ":./magic-effect.png" },
|
||||||
{ CSMWorld::UniversalId::Class_Record, CSMWorld::UniversalId::Type_Land, "Land", 0 },
|
{ CSMWorld::UniversalId::Class_Record, CSMWorld::UniversalId::Type_Land, "Land", ":./land-heightmap.png" },
|
||||||
{ CSMWorld::UniversalId::Class_Record, CSMWorld::UniversalId::Type_LandTexture, "LandTexture", 0 },
|
{ CSMWorld::UniversalId::Class_Record, CSMWorld::UniversalId::Type_LandTexture, "LandTexture", ":./land-texture.png" },
|
||||||
{ CSMWorld::UniversalId::Class_Record, CSMWorld::UniversalId::Type_Pathgrid, "Pathgrid", 0 },
|
{ 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_StartScript, "Start Script", 0 },
|
||||||
{ CSMWorld::UniversalId::Class_Record, CSMWorld::UniversalId::Type_MetaData, "Meta Data", 0 },
|
{ CSMWorld::UniversalId::Class_Record, CSMWorld::UniversalId::Type_MetaData, "Meta Data", 0 },
|
||||||
|
|
||||||
|
|
|
@ -167,7 +167,7 @@ void CSVDoc::Loader::loadingStopped (CSMDoc::Document *document, bool completed,
|
||||||
delete iter->second;
|
delete iter->second;
|
||||||
mDocuments.erase (iter);
|
mDocuments.erase (iter);
|
||||||
}
|
}
|
||||||
else if (!completed && !error.empty())
|
else
|
||||||
{
|
{
|
||||||
iter->second->abort (error);
|
iter->second->abort (error);
|
||||||
// Leave the window open for now (wait for the user to close it)
|
// Leave the window open for now (wait for the user to close it)
|
||||||
|
|
|
@ -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
|
/// \todo remove this label once we are feature complete and convinced that this thing is
|
||||||
/// working properly.
|
/// working properly.
|
||||||
QLabel *warning = new QLabel ("<font color=Red>WARNING: OpenMW-CS is in alpha stage.<p>The editor is not feature complete and not sufficiently tested.<br>In theory your data should be safe. But we strongly advice to make backups regularly if you are working with live data.</font color>");
|
QLabel *warning = new QLabel ("<font color=Red>WARNING: OpenMW-CS is in alpha stage.<p>The editor is not feature complete and not sufficiently tested.<br>In theory your data should be safe. But we strongly advise to make backups regularly if you are working with live data.</font color>");
|
||||||
|
|
||||||
QFont font;
|
QFont font;
|
||||||
font.setPointSize (12);
|
font.setPointSize (12);
|
||||||
|
|
|
@ -92,7 +92,7 @@ osg::Vec3f CSVRender::InstanceMode::getScreenCoords(const osg::Vec3f& pos)
|
||||||
}
|
}
|
||||||
|
|
||||||
CSVRender::InstanceMode::InstanceMode (WorldspaceWidget *worldspaceWidget, QWidget *parent)
|
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),
|
parent), mSubMode (0), mSubModeId ("move"), mSelectionMode (0), mDragMode (DragMode_None),
|
||||||
mDragAxis (-1), mLocked (false), mUnitScaleDist(1)
|
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 = new CSVWidget::SceneToolMode (toolbar, "Edit Sub-Mode");
|
||||||
mSubMode->addButton (new InstanceMoveMode (this), "move");
|
mSubMode->addButton (new InstanceMoveMode (this), "move");
|
||||||
mSubMode->addButton (":placeholder", "rotate",
|
mSubMode->addButton (":scenetoolbar/transform-rotate", "rotate",
|
||||||
"Rotate selected instances"
|
"Rotate selected instances"
|
||||||
"<ul><li>Use {scene-edit-primary} to rotate instances freely</li>"
|
"<ul><li>Use {scene-edit-primary} to rotate instances freely</li>"
|
||||||
"<li>Use {scene-edit-secondary} to rotate instances within the grid</li>"
|
"<li>Use {scene-edit-secondary} to rotate instances within the grid</li>"
|
||||||
"<li>The center of the view acts as the axis of rotation</li>"
|
"<li>The center of the view acts as the axis of rotation</li>"
|
||||||
"</ul>"
|
"</ul>"
|
||||||
"<font color=Red>Grid rotate not implemented yet</font color>");
|
"<font color=Red>Grid rotate not implemented yet</font color>");
|
||||||
mSubMode->addButton (":placeholder", "scale",
|
mSubMode->addButton (":scenetoolbar/transform-scale", "scale",
|
||||||
"Scale selected instances"
|
"Scale selected instances"
|
||||||
"<ul><li>Use {scene-edit-primary} to scale instances freely</li>"
|
"<ul><li>Use {scene-edit-primary} to scale instances freely</li>"
|
||||||
"<li>Use {scene-edit-secondary} to scale instances along the grid</li>"
|
"<li>Use {scene-edit-secondary} to scale instances along the grid</li>"
|
||||||
|
|
|
@ -2,7 +2,7 @@
|
||||||
#include "instancemovemode.hpp"
|
#include "instancemovemode.hpp"
|
||||||
|
|
||||||
CSVRender::InstanceMoveMode::InstanceMoveMode (QWidget *parent)
|
CSVRender::InstanceMoveMode::InstanceMoveMode (QWidget *parent)
|
||||||
: ModeButton (QIcon (QPixmap (":placeholder")),
|
: ModeButton (QIcon (QPixmap (":scenetoolbar/transform-move")),
|
||||||
"Move selected instances"
|
"Move selected instances"
|
||||||
"<ul><li>Use {scene-edit-primary} to move instances around freely</li>"
|
"<ul><li>Use {scene-edit-primary} to move instances around freely</li>"
|
||||||
"<li>Use {scene-edit-secondary} to move instances around within the grid</li>"
|
"<li>Use {scene-edit-secondary} to move instances around within the grid</li>"
|
||||||
|
|
|
@ -13,7 +13,7 @@ namespace CSVRender
|
||||||
, mWorldspaceWidget(worldspaceWidget)
|
, mWorldspaceWidget(worldspaceWidget)
|
||||||
, mInteractionMask(interactionMask)
|
, mInteractionMask(interactionMask)
|
||||||
{
|
{
|
||||||
addButton(":placeholder", "cube-centre",
|
addButton(":scenetoolbar/selection-mode-cube", "cube-centre",
|
||||||
"Centred cube"
|
"Centred cube"
|
||||||
"<ul><li>Drag with {scene-select-primary} (make instances the selection) or {scene-select-secondary} "
|
"<ul><li>Drag with {scene-select-primary} (make instances the selection) or {scene-select-secondary} "
|
||||||
"(invert selection state) from the centre of the selection cube outwards</li>"
|
"(invert selection state) from the centre of the selection cube outwards</li>"
|
||||||
|
@ -22,7 +22,7 @@ namespace CSVRender
|
||||||
"starting on an instance will have the same effect</li>"
|
"starting on an instance will have the same effect</li>"
|
||||||
"</ul>"
|
"</ul>"
|
||||||
"<font color=Red>Not implemented yet</font color>");
|
"<font color=Red>Not implemented yet</font color>");
|
||||||
addButton(":placeholder", "cube-corner",
|
addButton(":scenetoolbar/selection-mode-cube-corner", "cube-corner",
|
||||||
"Cube corner to corner"
|
"Cube corner to corner"
|
||||||
"<ul><li>Drag with {scene-select-primary} (make instances the selection) or {scene-select-secondary} "
|
"<ul><li>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</li>"
|
"(invert selection state) from one corner of the selection cube to the opposite corner</li>"
|
||||||
|
@ -31,7 +31,7 @@ namespace CSVRender
|
||||||
"starting on an instance will have the same effect</li>"
|
"starting on an instance will have the same effect</li>"
|
||||||
"</ul>"
|
"</ul>"
|
||||||
"<font color=Red>Not implemented yet</font color>");
|
"<font color=Red>Not implemented yet</font color>");
|
||||||
addButton(":placeholder", "sphere",
|
addButton(":scenetoolbar/selection-mode-cube-sphere", "sphere",
|
||||||
"Centred sphere"
|
"Centred sphere"
|
||||||
"<ul><li>Drag with {scene-select-primary} (make instances the selection) or {scene-select-secondary} "
|
"<ul><li>Drag with {scene-select-primary} (make instances the selection) or {scene-select-secondary} "
|
||||||
"(invert selection state) from the centre of the selection sphere outwards</li>"
|
"(invert selection state) from the centre of the selection sphere outwards</li>"
|
||||||
|
|
|
@ -156,6 +156,7 @@ CSVTools::ReportTable::ReportTable (CSMDoc::Document& document,
|
||||||
setSelectionMode (QAbstractItemView::ExtendedSelection);
|
setSelectionMode (QAbstractItemView::ExtendedSelection);
|
||||||
|
|
||||||
mProxyModel = new QSortFilterProxyModel (this);
|
mProxyModel = new QSortFilterProxyModel (this);
|
||||||
|
mProxyModel->setSortCaseSensitivity(Qt::CaseInsensitive);
|
||||||
mProxyModel->setSourceModel (mModel);
|
mProxyModel->setSourceModel (mModel);
|
||||||
mProxyModel->setSortRole(Qt::UserRole);
|
mProxyModel->setSortRole(Qt::UserRole);
|
||||||
|
|
||||||
|
|
|
@ -57,12 +57,12 @@ CSVWorld::RecordButtonBar::RecordButtonBar (const CSMWorld::UniversalId& id,
|
||||||
|
|
||||||
// left section
|
// left section
|
||||||
mPrevButton = new QToolButton (this);
|
mPrevButton = new QToolButton (this);
|
||||||
mPrevButton->setIcon(QIcon(":/go-previous.png"));
|
mPrevButton->setIcon(QIcon(":record-previous"));
|
||||||
mPrevButton->setToolTip ("Switch to previous record");
|
mPrevButton->setToolTip ("Switch to previous record");
|
||||||
buttonsLayout->addWidget (mPrevButton, 0);
|
buttonsLayout->addWidget (mPrevButton, 0);
|
||||||
|
|
||||||
mNextButton = new QToolButton (this);
|
mNextButton = new QToolButton (this);
|
||||||
mNextButton->setIcon(QIcon(":/go-next.png"));
|
mNextButton->setIcon(QIcon(":/record-next"));
|
||||||
mNextButton->setToolTip ("Switch to next record");
|
mNextButton->setToolTip ("Switch to next record");
|
||||||
buttonsLayout->addWidget (mNextButton, 1);
|
buttonsLayout->addWidget (mNextButton, 1);
|
||||||
|
|
||||||
|
@ -72,7 +72,7 @@ CSVWorld::RecordButtonBar::RecordButtonBar (const CSMWorld::UniversalId& id,
|
||||||
if (mTable.getFeatures() & CSMWorld::IdTable::Feature_Preview)
|
if (mTable.getFeatures() & CSMWorld::IdTable::Feature_Preview)
|
||||||
{
|
{
|
||||||
QToolButton* previewButton = new QToolButton (this);
|
QToolButton* previewButton = new QToolButton (this);
|
||||||
previewButton->setIcon(QIcon(":/edit-preview.png"));
|
previewButton->setIcon(QIcon(":edit-preview"));
|
||||||
previewButton->setToolTip ("Open a preview of this record");
|
previewButton->setToolTip ("Open a preview of this record");
|
||||||
buttonsLayout->addWidget(previewButton);
|
buttonsLayout->addWidget(previewButton);
|
||||||
connect (previewButton, SIGNAL(clicked()), this, SIGNAL (showPreview()));
|
connect (previewButton, SIGNAL(clicked()), this, SIGNAL (showPreview()));
|
||||||
|
@ -89,22 +89,22 @@ CSVWorld::RecordButtonBar::RecordButtonBar (const CSMWorld::UniversalId& id,
|
||||||
|
|
||||||
// right section
|
// right section
|
||||||
mCloneButton = new QToolButton (this);
|
mCloneButton = new QToolButton (this);
|
||||||
mCloneButton->setIcon(QIcon(":/edit-clone.png"));
|
mCloneButton->setIcon(QIcon(":edit-clone"));
|
||||||
mCloneButton->setToolTip ("Clone record");
|
mCloneButton->setToolTip ("Clone record");
|
||||||
buttonsLayout->addWidget(mCloneButton);
|
buttonsLayout->addWidget(mCloneButton);
|
||||||
|
|
||||||
mAddButton = new QToolButton (this);
|
mAddButton = new QToolButton (this);
|
||||||
mAddButton->setIcon(QIcon(":/add.png"));
|
mAddButton->setIcon(QIcon(":edit-add"));
|
||||||
mAddButton->setToolTip ("Add new record");
|
mAddButton->setToolTip ("Add new record");
|
||||||
buttonsLayout->addWidget(mAddButton);
|
buttonsLayout->addWidget(mAddButton);
|
||||||
|
|
||||||
mDeleteButton = new QToolButton (this);
|
mDeleteButton = new QToolButton (this);
|
||||||
mDeleteButton->setIcon(QIcon(":/edit-delete.png"));
|
mDeleteButton->setIcon(QIcon(":edit-delete"));
|
||||||
mDeleteButton->setToolTip ("Delete record");
|
mDeleteButton->setToolTip ("Delete record");
|
||||||
buttonsLayout->addWidget(mDeleteButton);
|
buttonsLayout->addWidget(mDeleteButton);
|
||||||
|
|
||||||
mRevertButton = new QToolButton (this);
|
mRevertButton = new QToolButton (this);
|
||||||
mRevertButton->setIcon(QIcon(":/edit-undo.png"));
|
mRevertButton->setIcon(QIcon(":edit-undo"));
|
||||||
mRevertButton->setToolTip ("Revert record");
|
mRevertButton->setToolTip ("Revert record");
|
||||||
buttonsLayout->addWidget(mRevertButton);
|
buttonsLayout->addWidget(mRevertButton);
|
||||||
|
|
||||||
|
|
|
@ -27,7 +27,7 @@ CSVWorld::RecordStatusDelegateFactory::RecordStatusDelegateFactory()
|
||||||
|
|
||||||
static const char *sIcons[] =
|
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)
|
for (int i=0; sIcons[i]; ++i)
|
||||||
|
|
|
@ -63,19 +63,9 @@ std::string CSVWorld::ReferenceCreator::getErrors() const
|
||||||
std::string cell = mCell->text().toUtf8().constData();
|
std::string cell = mCell->text().toUtf8().constData();
|
||||||
|
|
||||||
if (cell.empty())
|
if (cell.empty())
|
||||||
{
|
|
||||||
if (!errors.empty())
|
|
||||||
errors += "<br>";
|
|
||||||
|
|
||||||
errors += "Missing Cell ID";
|
errors += "Missing Cell ID";
|
||||||
}
|
|
||||||
else if (getData().getCells().searchId (cell)==-1)
|
else if (getData().getCells().searchId (cell)==-1)
|
||||||
{
|
|
||||||
if (!errors.empty())
|
|
||||||
errors += "<br>";
|
|
||||||
|
|
||||||
errors += "Invalid Cell ID";
|
errors += "Invalid Cell ID";
|
||||||
}
|
|
||||||
|
|
||||||
return errors;
|
return errors;
|
||||||
}
|
}
|
||||||
|
|
|
@ -764,10 +764,8 @@ std::vector< CSMWorld::UniversalId > CSVWorld::Table::getDraggedRecords() const
|
||||||
QModelIndexList selectedRows = selectionModel()->selectedRows();
|
QModelIndexList selectedRows = selectionModel()->selectedRows();
|
||||||
std::vector<CSMWorld::UniversalId> idToDrag;
|
std::vector<CSMWorld::UniversalId> 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()));
|
idToDrag.push_back (getUniversalId (it.row()));
|
||||||
}
|
|
||||||
|
|
||||||
return idToDrag;
|
return idToDrag;
|
||||||
}
|
}
|
||||||
|
|
|
@ -89,7 +89,7 @@ add_openmw_dir (mwmechanics
|
||||||
)
|
)
|
||||||
|
|
||||||
add_openmw_dir (mwstate
|
add_openmw_dir (mwstate
|
||||||
statemanagerimp charactermanager character
|
statemanagerimp charactermanager character quicksavemanager
|
||||||
)
|
)
|
||||||
|
|
||||||
add_openmw_dir (mwbase
|
add_openmw_dir (mwbase
|
||||||
|
@ -223,4 +223,3 @@ endif (MSVC)
|
||||||
if (WIN32)
|
if (WIN32)
|
||||||
INSTALL(TARGETS openmw RUNTIME DESTINATION ".")
|
INSTALL(TARGETS openmw RUNTIME DESTINATION ".")
|
||||||
endif (WIN32)
|
endif (WIN32)
|
||||||
|
|
||||||
|
|
|
@ -35,28 +35,11 @@ int Java_org_libsdl_app_SDLActivity_isMouseShown(JNIEnv *env, jclass cls, jobjec
|
||||||
return SDL_ShowCursor(SDL_QUERY);
|
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);
|
setenv("OPENMW_DECOMPRESS_TEXTURES", "1", 1);
|
||||||
|
|
||||||
SDL_Android_Init(env, cls);
|
|
||||||
|
|
||||||
SDL_SetMainReady();
|
|
||||||
|
|
||||||
// On Android, we use a virtual controller with guid="Virtual"
|
// 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");
|
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! */
|
return 0;
|
||||||
|
|
||||||
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;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -39,6 +39,7 @@ namespace MWBase
|
||||||
class ResponseCallback
|
class ResponseCallback
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
|
virtual ~ResponseCallback() = default;
|
||||||
virtual void addResponse(const std::string& title, const std::string& text) = 0;
|
virtual void addResponse(const std::string& title, const std::string& text) = 0;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -337,7 +337,7 @@ namespace MWBase
|
||||||
/// Cycle to next or previous weapon
|
/// Cycle to next or previous weapon
|
||||||
virtual void cycleWeapon(bool next) = 0;
|
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
|
// In WindowManager for now since there isn't a VFS singleton
|
||||||
virtual std::string correctIconPath(const std::string& path) = 0;
|
virtual std::string correctIconPath(const std::string& path) = 0;
|
||||||
|
|
|
@ -491,12 +491,14 @@ namespace MWBase
|
||||||
virtual void launchProjectile (MWWorld::Ptr actor, MWWorld::ConstPtr projectile,
|
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;
|
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<std::string>& getContentFiles() const = 0;
|
virtual const std::vector<std::string>& getContentFiles() const = 0;
|
||||||
|
|
||||||
virtual void breakInvisibility (const MWWorld::Ptr& actor) = 0;
|
virtual void breakInvisibility (const MWWorld::Ptr& actor) = 0;
|
||||||
|
|
||||||
// Are we in an exterior or pseudo-exterior cell and it's night?
|
// Allow NPCs to use torches?
|
||||||
virtual bool isDark() const = 0;
|
virtual bool useTorches() const = 0;
|
||||||
|
|
||||||
virtual bool findInteriorPositionInWorldSpace(const MWWorld::CellStore* cell, osg::Vec3f& result) = 0;
|
virtual bool findInteriorPositionInWorldSpace(const MWWorld::CellStore* cell, osg::Vec3f& result) = 0;
|
||||||
|
|
||||||
|
|
|
@ -233,24 +233,6 @@ namespace MWClass
|
||||||
if (!(ref->mBase->mData.mFlags & ESM::Light::Carry))
|
if (!(ref->mBase->mData.mFlags & ESM::Light::Carry))
|
||||||
return std::make_pair(0,"");
|
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<ESM::Weapon>()->mBase->mData.mType == ESM::Weapon::LongBladeTwoHand ||
|
|
||||||
weapon->get<ESM::Weapon>()->mBase->mData.mType == ESM::Weapon::BluntTwoClose ||
|
|
||||||
weapon->get<ESM::Weapon>()->mBase->mData.mType == ESM::Weapon::BluntTwoWide ||
|
|
||||||
weapon->get<ESM::Weapon>()->mBase->mData.mType == ESM::Weapon::SpearTwoWide ||
|
|
||||||
weapon->get<ESM::Weapon>()->mBase->mData.mType == ESM::Weapon::AxeTwoHand ||
|
|
||||||
weapon->get<ESM::Weapon>()->mBase->mData.mType == ESM::Weapon::MarksmanBow ||
|
|
||||||
weapon->get<ESM::Weapon>()->mBase->mData.mType == ESM::Weapon::MarksmanCrossbow))
|
|
||||||
{
|
|
||||||
return std::make_pair(3,"");
|
|
||||||
}
|
|
||||||
return std::make_pair(1,"");
|
return std::make_pair(1,"");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -83,7 +83,8 @@ namespace MWClass
|
||||||
|
|
||||||
if (ptr.getCellRef().getSoul() != "")
|
if (ptr.getCellRef().getSoul() != "")
|
||||||
{
|
{
|
||||||
const ESM::Creature *creature = MWBase::Environment::get().getWorld()->getStore().get<ESM::Creature>().find(ref->mRef.getSoul());
|
const ESM::Creature *creature = MWBase::Environment::get().getWorld()->getStore().get<ESM::Creature>().search(ref->mRef.getSoul());
|
||||||
|
if (creature)
|
||||||
value *= creature->mData.mSoul;
|
value *= creature->mData.mSoul;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -148,7 +149,8 @@ namespace MWClass
|
||||||
|
|
||||||
if (ref->mRef.getSoul() != "")
|
if (ref->mRef.getSoul() != "")
|
||||||
{
|
{
|
||||||
const ESM::Creature *creature = store.get<ESM::Creature>().find(ref->mRef.getSoul());
|
const ESM::Creature *creature = store.get<ESM::Creature>().search(ref->mRef.getSoul());
|
||||||
|
if (creature)
|
||||||
info.caption += " (" + creature->mName + ")";
|
info.caption += " (" + creature->mName + ")";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -210,7 +212,7 @@ namespace MWClass
|
||||||
|
|
||||||
std::shared_ptr<MWWorld::Action> Miscellaneous::use (const MWWorld::Ptr& ptr) const
|
std::shared_ptr<MWWorld::Action> Miscellaneous::use (const MWWorld::Ptr& ptr) const
|
||||||
{
|
{
|
||||||
if (ptr.getCellRef().getSoul().empty())
|
if (ptr.getCellRef().getSoul().empty() || !MWBase::Environment::get().getWorld()->getStore().get<ESM::Creature>().search(ptr.getCellRef().getSoul()))
|
||||||
return std::shared_ptr<MWWorld::Action>(new MWWorld::NullAction());
|
return std::shared_ptr<MWWorld::Action>(new MWWorld::NullAction());
|
||||||
else
|
else
|
||||||
return std::shared_ptr<MWWorld::Action>(new MWWorld::ActionSoulgem(ptr));
|
return std::shared_ptr<MWWorld::Action>(new MWWorld::ActionSoulgem(ptr));
|
||||||
|
|
|
@ -312,40 +312,40 @@ namespace MWClass
|
||||||
int gold=0;
|
int gold=0;
|
||||||
if(ref->mBase->mNpdtType != ESM::NPC::NPC_WITH_AUTOCALCULATED_STATS)
|
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)
|
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::Strength, ref->mBase->mNpdt.mStrength);
|
||||||
data->mNpcStats.setAttribute(ESM::Attribute::Intelligence, ref->mBase->mNpdt52.mIntelligence);
|
data->mNpcStats.setAttribute(ESM::Attribute::Intelligence, ref->mBase->mNpdt.mIntelligence);
|
||||||
data->mNpcStats.setAttribute(ESM::Attribute::Willpower, ref->mBase->mNpdt52.mWillpower);
|
data->mNpcStats.setAttribute(ESM::Attribute::Willpower, ref->mBase->mNpdt.mWillpower);
|
||||||
data->mNpcStats.setAttribute(ESM::Attribute::Agility, ref->mBase->mNpdt52.mAgility);
|
data->mNpcStats.setAttribute(ESM::Attribute::Agility, ref->mBase->mNpdt.mAgility);
|
||||||
data->mNpcStats.setAttribute(ESM::Attribute::Speed, ref->mBase->mNpdt52.mSpeed);
|
data->mNpcStats.setAttribute(ESM::Attribute::Speed, ref->mBase->mNpdt.mSpeed);
|
||||||
data->mNpcStats.setAttribute(ESM::Attribute::Endurance, ref->mBase->mNpdt52.mEndurance);
|
data->mNpcStats.setAttribute(ESM::Attribute::Endurance, ref->mBase->mNpdt.mEndurance);
|
||||||
data->mNpcStats.setAttribute(ESM::Attribute::Personality, ref->mBase->mNpdt52.mPersonality);
|
data->mNpcStats.setAttribute(ESM::Attribute::Personality, ref->mBase->mNpdt.mPersonality);
|
||||||
data->mNpcStats.setAttribute(ESM::Attribute::Luck, ref->mBase->mNpdt52.mLuck);
|
data->mNpcStats.setAttribute(ESM::Attribute::Luck, ref->mBase->mNpdt.mLuck);
|
||||||
|
|
||||||
data->mNpcStats.setHealth (ref->mBase->mNpdt52.mHealth);
|
data->mNpcStats.setHealth (ref->mBase->mNpdt.mHealth);
|
||||||
data->mNpcStats.setMagicka (ref->mBase->mNpdt52.mMana);
|
data->mNpcStats.setMagicka (ref->mBase->mNpdt.mMana);
|
||||||
data->mNpcStats.setFatigue (ref->mBase->mNpdt52.mFatigue);
|
data->mNpcStats.setFatigue (ref->mBase->mNpdt.mFatigue);
|
||||||
|
|
||||||
data->mNpcStats.setLevel(ref->mBase->mNpdt52.mLevel);
|
data->mNpcStats.setLevel(ref->mBase->mNpdt.mLevel);
|
||||||
data->mNpcStats.setBaseDisposition(ref->mBase->mNpdt52.mDisposition);
|
data->mNpcStats.setBaseDisposition(ref->mBase->mNpdt.mDisposition);
|
||||||
data->mNpcStats.setReputation(ref->mBase->mNpdt52.mReputation);
|
data->mNpcStats.setReputation(ref->mBase->mNpdt.mReputation);
|
||||||
|
|
||||||
data->mNpcStats.setNeedRecalcDynamicStats(false);
|
data->mNpcStats.setNeedRecalcDynamicStats(false);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
gold = ref->mBase->mNpdt12.mGold;
|
gold = ref->mBase->mNpdt.mGold;
|
||||||
|
|
||||||
for (int i=0; i<3; ++i)
|
for (int i=0; i<3; ++i)
|
||||||
data->mNpcStats.setDynamic (i, 10);
|
data->mNpcStats.setDynamic (i, 10);
|
||||||
|
|
||||||
data->mNpcStats.setLevel(ref->mBase->mNpdt12.mLevel);
|
data->mNpcStats.setLevel(ref->mBase->mNpdt.mLevel);
|
||||||
data->mNpcStats.setBaseDisposition(ref->mBase->mNpdt12.mDisposition);
|
data->mNpcStats.setBaseDisposition(ref->mBase->mNpdt.mDisposition);
|
||||||
data->mNpcStats.setReputation(ref->mBase->mNpdt12.mReputation);
|
data->mNpcStats.setReputation(ref->mBase->mNpdt.mReputation);
|
||||||
|
|
||||||
autoCalculateAttributes(ref->mBase, data->mNpcStats);
|
autoCalculateAttributes(ref->mBase, data->mNpcStats);
|
||||||
autoCalculateSkills(ref->mBase, data->mNpcStats, ptr);
|
autoCalculateSkills(ref->mBase, data->mNpcStats, ptr);
|
||||||
|
@ -1327,10 +1327,7 @@ namespace MWClass
|
||||||
int Npc::getBaseGold(const MWWorld::ConstPtr& ptr) const
|
int Npc::getBaseGold(const MWWorld::ConstPtr& ptr) const
|
||||||
{
|
{
|
||||||
const MWWorld::LiveCellRef<ESM::NPC> *ref = ptr.get<ESM::NPC>();
|
const MWWorld::LiveCellRef<ESM::NPC> *ref = ptr.get<ESM::NPC>();
|
||||||
if(ref->mBase->mNpdtType != ESM::NPC::NPC_WITH_AUTOCALCULATED_STATS)
|
return ref->mBase->mNpdt.mGold;
|
||||||
return ref->mBase->mNpdt52.mGold;
|
|
||||||
else
|
|
||||||
return ref->mBase->mNpdt12.mGold;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Npc::isClass(const MWWorld::ConstPtr& ptr, const std::string &className) const
|
bool Npc::isClass(const MWWorld::ConstPtr& ptr, const std::string &className) const
|
||||||
|
|
|
@ -892,7 +892,7 @@ protected:
|
||||||
public:
|
public:
|
||||||
|
|
||||||
typedef TypesetBookImpl::StyleImpl Style;
|
typedef TypesetBookImpl::StyleImpl Style;
|
||||||
typedef std::map <TextFormat::Id, TextFormat*> ActiveTextFormats;
|
typedef std::map <TextFormat::Id, std::unique_ptr<TextFormat>> ActiveTextFormats;
|
||||||
|
|
||||||
int mViewTop;
|
int mViewTop;
|
||||||
int mViewBottom;
|
int mViewBottom;
|
||||||
|
@ -1048,7 +1048,7 @@ public:
|
||||||
{
|
{
|
||||||
if (mNode != NULL)
|
if (mNode != NULL)
|
||||||
i->second->destroyDrawItem (mNode);
|
i->second->destroyDrawItem (mNode);
|
||||||
delete i->second;
|
i->second.reset();
|
||||||
}
|
}
|
||||||
|
|
||||||
mActiveTextFormats.clear ();
|
mActiveTextFormats.clear ();
|
||||||
|
@ -1115,11 +1115,11 @@ public:
|
||||||
|
|
||||||
if (j == this_->mActiveTextFormats.end ())
|
if (j == this_->mActiveTextFormats.end ())
|
||||||
{
|
{
|
||||||
TextFormat * textFormat = new TextFormat (Font, this_);
|
std::unique_ptr<TextFormat> textFormat(new TextFormat (Font, this_));
|
||||||
|
|
||||||
textFormat->mTexture = Font->getTextureFont ();
|
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;
|
j->second->mCountVertex += run.mPrintableChars * 6;
|
||||||
|
|
|
@ -200,7 +200,7 @@ namespace MWGui
|
||||||
{
|
{
|
||||||
if ((mCurrentPage+1)*2 < mPages.size())
|
if ((mCurrentPage+1)*2 < mPages.size())
|
||||||
{
|
{
|
||||||
MWBase::Environment::get().getWindowManager()->playSound("book page2");
|
MWBase::Environment::get().getWindowManager()->playSound("book page2", true);
|
||||||
|
|
||||||
++mCurrentPage;
|
++mCurrentPage;
|
||||||
|
|
||||||
|
@ -211,7 +211,7 @@ namespace MWGui
|
||||||
{
|
{
|
||||||
if (mCurrentPage > 0)
|
if (mCurrentPage > 0)
|
||||||
{
|
{
|
||||||
MWBase::Environment::get().getWindowManager()->playSound("book page");
|
MWBase::Environment::get().getWindowManager()->playSound("book page", true);
|
||||||
|
|
||||||
--mCurrentPage;
|
--mCurrentPage;
|
||||||
|
|
||||||
|
|
|
@ -129,6 +129,12 @@ namespace MWGui
|
||||||
|
|
||||||
mItemView->setModel(mSortModel);
|
mItemView->setModel(mSortModel);
|
||||||
|
|
||||||
|
mFilterAll->setStateSelected(true);
|
||||||
|
mFilterWeapon->setStateSelected(false);
|
||||||
|
mFilterApparel->setStateSelected(false);
|
||||||
|
mFilterMagic->setStateSelected(false);
|
||||||
|
mFilterMisc->setStateSelected(false);
|
||||||
|
|
||||||
mPreview->updatePtr(mPtr);
|
mPreview->updatePtr(mPtr);
|
||||||
mPreview->rebuild();
|
mPreview->rebuild();
|
||||||
mPreview->update();
|
mPreview->update();
|
||||||
|
|
|
@ -16,8 +16,13 @@ namespace
|
||||||
{
|
{
|
||||||
if (count == 1)
|
if (count == 1)
|
||||||
return "";
|
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
|
else
|
||||||
return MyGUI::utility::toString(count);
|
return MyGUI::utility::toString(count);
|
||||||
}
|
}
|
||||||
|
|
|
@ -616,7 +616,7 @@ namespace
|
||||||
|
|
||||||
if (page+2 < book->pageCount())
|
if (page+2 < book->pageCount())
|
||||||
{
|
{
|
||||||
MWBase::Environment::get().getWindowManager()->playSound("book page");
|
MWBase::Environment::get().getWindowManager()->playSound("book page", true);
|
||||||
|
|
||||||
page += 2;
|
page += 2;
|
||||||
updateShowingPages ();
|
updateShowingPages ();
|
||||||
|
@ -634,7 +634,7 @@ namespace
|
||||||
|
|
||||||
if(page >= 2)
|
if(page >= 2)
|
||||||
{
|
{
|
||||||
MWBase::Environment::get().getWindowManager()->playSound("book page");
|
MWBase::Environment::get().getWindowManager()->playSound("book page", true);
|
||||||
|
|
||||||
page -= 2;
|
page -= 2;
|
||||||
updateShowingPages ();
|
updateShowingPages ();
|
||||||
|
|
|
@ -39,6 +39,7 @@ void getKeyFocusWidgets(MyGUI::Widget* parent, std::vector<MyGUI::Widget*>& resu
|
||||||
KeyboardNavigation::KeyboardNavigation()
|
KeyboardNavigation::KeyboardNavigation()
|
||||||
: mCurrentFocus(nullptr)
|
: mCurrentFocus(nullptr)
|
||||||
, mModalWindow(nullptr)
|
, mModalWindow(nullptr)
|
||||||
|
, mEnabled(true)
|
||||||
{
|
{
|
||||||
MyGUI::WidgetManager::getInstance().registerUnlinker(this);
|
MyGUI::WidgetManager::getInstance().registerUnlinker(this);
|
||||||
}
|
}
|
||||||
|
@ -101,6 +102,9 @@ bool isRootParent(MyGUI::Widget* widget, MyGUI::Widget* root)
|
||||||
|
|
||||||
void KeyboardNavigation::onFrame()
|
void KeyboardNavigation::onFrame()
|
||||||
{
|
{
|
||||||
|
if (!mEnabled)
|
||||||
|
return;
|
||||||
|
|
||||||
MyGUI::Widget* focus = MyGUI::InputManager::getInstance().getKeyFocusWidget();
|
MyGUI::Widget* focus = MyGUI::InputManager::getInstance().getKeyFocusWidget();
|
||||||
|
|
||||||
if (focus == mCurrentFocus)
|
if (focus == mCurrentFocus)
|
||||||
|
@ -150,6 +154,11 @@ void KeyboardNavigation::setModalWindow(MyGUI::Widget *window)
|
||||||
mModalWindow = window;
|
mModalWindow = window;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void KeyboardNavigation::setEnabled(bool enabled)
|
||||||
|
{
|
||||||
|
mEnabled = enabled;
|
||||||
|
}
|
||||||
|
|
||||||
enum Direction
|
enum Direction
|
||||||
{
|
{
|
||||||
D_Left,
|
D_Left,
|
||||||
|
@ -162,6 +171,9 @@ enum Direction
|
||||||
|
|
||||||
bool KeyboardNavigation::injectKeyPress(MyGUI::KeyCode key, unsigned int text)
|
bool KeyboardNavigation::injectKeyPress(MyGUI::KeyCode key, unsigned int text)
|
||||||
{
|
{
|
||||||
|
if (!mEnabled)
|
||||||
|
return false;
|
||||||
|
|
||||||
switch (key.getValue())
|
switch (key.getValue())
|
||||||
{
|
{
|
||||||
case MyGUI::KeyCode::ArrowLeft:
|
case MyGUI::KeyCode::ArrowLeft:
|
||||||
|
|
|
@ -28,6 +28,8 @@ namespace MWGui
|
||||||
|
|
||||||
void setModalWindow(MyGUI::Widget* window);
|
void setModalWindow(MyGUI::Widget* window);
|
||||||
|
|
||||||
|
void setEnabled(bool enabled);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
bool switchFocus(int direction, bool wrap);
|
bool switchFocus(int direction, bool wrap);
|
||||||
|
|
||||||
|
@ -40,6 +42,8 @@ namespace MWGui
|
||||||
|
|
||||||
MyGUI::Widget* mCurrentFocus;
|
MyGUI::Widget* mCurrentFocus;
|
||||||
MyGUI::Widget* mModalWindow;
|
MyGUI::Widget* mModalWindow;
|
||||||
|
|
||||||
|
bool mEnabled;
|
||||||
};
|
};
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -330,7 +330,12 @@ namespace MWGui
|
||||||
MWMechanics::CreatureStats& stats = player.getClass().getCreatureStats(player);
|
MWMechanics::CreatureStats& stats = player.getClass().getCreatureStats(player);
|
||||||
MWMechanics::Spells& spells = stats.getSpells();
|
MWMechanics::Spells& spells = stats.getSpells();
|
||||||
if (!spells.hasSpell(spellId))
|
if (!spells.hasSpell(spellId))
|
||||||
|
{
|
||||||
|
const ESM::Spell* spell = MWBase::Environment::get().getWorld()->getStore().get<ESM::Spell>().find(spellId);
|
||||||
|
MWBase::Environment::get().getWindowManager()->messageBox (
|
||||||
|
"#{sQuickMenu5} " + spell->mName);
|
||||||
return;
|
return;
|
||||||
|
}
|
||||||
store.setSelectedEnchantItem(store.end());
|
store.setSelectedEnchantItem(store.end());
|
||||||
MWBase::Environment::get().getWindowManager()->setSelectedSpell(spellId, int(MWMechanics::getSpellSuccessChance(spellId, player)));
|
MWBase::Environment::get().getWindowManager()->setSelectedSpell(spellId, int(MWMechanics::getSpellSuccessChance(spellId, player)));
|
||||||
MWBase::Environment::get().getWorld()->getPlayer().setDrawState(MWMechanics::DrawState_Spell);
|
MWBase::Environment::get().getWorld()->getPlayer().setDrawState(MWMechanics::DrawState_Spell);
|
||||||
|
|
|
@ -14,12 +14,9 @@ namespace MWGui
|
||||||
{
|
{
|
||||||
// check if count of the reference has become 0
|
// check if count of the reference has become 0
|
||||||
if (!mPtr.isEmpty() && mPtr.getRefData().getCount() == 0)
|
if (!mPtr.isEmpty() && mPtr.getRefData().getCount() == 0)
|
||||||
{
|
|
||||||
if (!mPtr.isEmpty())
|
|
||||||
{
|
{
|
||||||
mPtr = MWWorld::Ptr();
|
mPtr = MWWorld::Ptr();
|
||||||
onReferenceUnavailable();
|
onReferenceUnavailable();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
|
@ -208,7 +208,7 @@ namespace MWGui
|
||||||
if ((mFilter & Filter_OnlyEnchanted) && !(item.mFlags & ItemStack::Flag_Enchanted))
|
if ((mFilter & Filter_OnlyEnchanted) && !(item.mFlags & ItemStack::Flag_Enchanted))
|
||||||
return false;
|
return false;
|
||||||
if ((mFilter & Filter_OnlyChargedSoulstones) && (base.getTypeName() != typeid(ESM::Miscellaneous).name()
|
if ((mFilter & Filter_OnlyChargedSoulstones) && (base.getTypeName() != typeid(ESM::Miscellaneous).name()
|
||||||
|| base.getCellRef().getSoul() == ""))
|
|| base.getCellRef().getSoul() == "" || !MWBase::Environment::get().getWorld()->getStore().get<ESM::Creature>().search(base.getCellRef().getSoul())))
|
||||||
return false;
|
return false;
|
||||||
if ((mFilter & Filter_OnlyRepairTools) && (base.getTypeName() != typeid(ESM::Repair).name()))
|
if ((mFilter & Filter_OnlyRepairTools) && (base.getTypeName() != typeid(ESM::Repair).name()))
|
||||||
return false;
|
return false;
|
||||||
|
|
|
@ -4,6 +4,8 @@
|
||||||
#include <MyGUI_ScrollView.h>
|
#include <MyGUI_ScrollView.h>
|
||||||
#include <MyGUI_Gui.h>
|
#include <MyGUI_Gui.h>
|
||||||
|
|
||||||
|
#include <components/settings/settings.hpp>
|
||||||
|
|
||||||
#include "../mwbase/environment.hpp"
|
#include "../mwbase/environment.hpp"
|
||||||
#include "../mwbase/world.hpp"
|
#include "../mwbase/world.hpp"
|
||||||
#include "../mwbase/windowmanager.hpp"
|
#include "../mwbase/windowmanager.hpp"
|
||||||
|
@ -72,6 +74,9 @@ namespace MWGui
|
||||||
MWWorld::ActionTeleport::getFollowersToTeleport(player, followers);
|
MWWorld::ActionTeleport::getFollowersToTeleport(player, followers);
|
||||||
|
|
||||||
// Apply followers cost, in vanilla one follower travels for free
|
// Apply followers cost, in vanilla one follower travels for free
|
||||||
|
if (Settings::Manager::getBool("charge for every follower travelling", "Game"))
|
||||||
|
price *= 1 + static_cast<int>(followers.size());
|
||||||
|
else
|
||||||
price *= std::max(1, static_cast<int>(followers.size()));
|
price *= std::max(1, static_cast<int>(followers.size()));
|
||||||
|
|
||||||
MyGUI::Button* toAdd = mDestinationsView->createWidget<MyGUI::Button>("SandTextButton", 0, mCurrentY, 200, sLineHeight, MyGUI::Align::Default);
|
MyGUI::Button* toAdd = mDestinationsView->createWidget<MyGUI::Button>("SandTextButton", 0, mCurrentY, 200, sLineHeight, MyGUI::Align::Default);
|
||||||
|
|
|
@ -25,7 +25,7 @@ void WindowBase::setVisible(bool visible)
|
||||||
|
|
||||||
if (visible)
|
if (visible)
|
||||||
onOpen();
|
onOpen();
|
||||||
else if (wasVisible && !visible)
|
else if (wasVisible)
|
||||||
onClose();
|
onClose();
|
||||||
|
|
||||||
// This is needed as invisible widgets can retain key focus.
|
// This is needed as invisible widgets can retain key focus.
|
||||||
|
|
|
@ -237,7 +237,10 @@ namespace MWGui
|
||||||
MyGUI::FactoryManager::getInstance().registerFactory<ResourceImageSetPointerFix>("Resource", "ResourceImageSetPointer");
|
MyGUI::FactoryManager::getInstance().registerFactory<ResourceImageSetPointerFix>("Resource", "ResourceImageSetPointer");
|
||||||
MyGUI::ResourceManager::getInstance().load("core.xml");
|
MyGUI::ResourceManager::getInstance().load("core.xml");
|
||||||
|
|
||||||
|
bool keyboardNav = Settings::Manager::getBool("keyboard navigation", "GUI");
|
||||||
mKeyboardNavigation.reset(new KeyboardNavigation());
|
mKeyboardNavigation.reset(new KeyboardNavigation());
|
||||||
|
mKeyboardNavigation->setEnabled(keyboardNav);
|
||||||
|
Gui::ImageButton::setDefaultNeedKeyFocus(keyboardNav);
|
||||||
|
|
||||||
mLoadingScreen = new LoadingScreen(mResourceSystem->getVFS(), mViewer);
|
mLoadingScreen = new LoadingScreen(mResourceSystem->getVFS(), mViewer);
|
||||||
mWindows.push_back(mLoadingScreen);
|
mWindows.push_back(mLoadingScreen);
|
||||||
|
@ -1916,11 +1919,16 @@ namespace MWGui
|
||||||
mInventoryWindow->cycle(next);
|
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())
|
if (soundId.empty())
|
||||||
return;
|
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()
|
void WindowManager::updateSpellWindow()
|
||||||
|
|
|
@ -366,7 +366,7 @@ namespace MWGui
|
||||||
/// Cycle to next or previous weapon
|
/// Cycle to next or previous weapon
|
||||||
virtual void cycleWeapon(bool next);
|
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
|
// In WindowManager for now since there isn't a VFS singleton
|
||||||
virtual std::string correctIconPath(const std::string& path);
|
virtual std::string correctIconPath(const std::string& path);
|
||||||
|
|
|
@ -524,30 +524,29 @@ namespace MWInput
|
||||||
isRunning = xAxis > .75 || xAxis < .25 || yAxis > .75 || yAxis < .25;
|
isRunning = xAxis > .75 || xAxis < .25 || yAxis > .75 || yAxis < .25;
|
||||||
if(triedToMove) resetIdleTime();
|
if(triedToMove) resetIdleTime();
|
||||||
|
|
||||||
if (actionIsActive(A_MoveLeft))
|
if (actionIsActive(A_MoveLeft) && !actionIsActive(A_MoveRight))
|
||||||
{
|
{
|
||||||
triedToMove = true;
|
triedToMove = true;
|
||||||
mPlayer->setLeftRight (-1);
|
mPlayer->setLeftRight (-1);
|
||||||
}
|
}
|
||||||
else if (actionIsActive(A_MoveRight))
|
else if (actionIsActive(A_MoveRight) && !actionIsActive(A_MoveLeft))
|
||||||
{
|
{
|
||||||
triedToMove = true;
|
triedToMove = true;
|
||||||
mPlayer->setLeftRight (1);
|
mPlayer->setLeftRight (1);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (actionIsActive(A_MoveForward))
|
if (actionIsActive(A_MoveForward) && !actionIsActive(A_MoveBackward))
|
||||||
{
|
{
|
||||||
triedToMove = true;
|
triedToMove = true;
|
||||||
mPlayer->setAutoMove (false);
|
mPlayer->setAutoMove (false);
|
||||||
mPlayer->setForwardBackward (1);
|
mPlayer->setForwardBackward (1);
|
||||||
}
|
}
|
||||||
else if (actionIsActive(A_MoveBackward))
|
else if (actionIsActive(A_MoveBackward) && !actionIsActive(A_MoveForward))
|
||||||
{
|
{
|
||||||
triedToMove = true;
|
triedToMove = true;
|
||||||
mPlayer->setAutoMove (false);
|
mPlayer->setAutoMove (false);
|
||||||
mPlayer->setForwardBackward (-1);
|
mPlayer->setForwardBackward (-1);
|
||||||
}
|
}
|
||||||
|
|
||||||
else if(mPlayer->getAutoMove())
|
else if(mPlayer->getAutoMove())
|
||||||
{
|
{
|
||||||
triedToMove = true;
|
triedToMove = true;
|
||||||
|
|
|
@ -391,7 +391,7 @@ namespace MWMechanics
|
||||||
{
|
{
|
||||||
// Player followers and escorters with high fight should not initiate combat with the player or with
|
// Player followers and escorters with high fight should not initiate combat with the player or with
|
||||||
// other player followers or escorters
|
// 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);
|
aggressive = MWBase::Environment::get().getMechanicsManager()->isAggressive(actor1, actor2);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -900,7 +900,7 @@ namespace MWMechanics
|
||||||
stats.setTimeToStartDrowning(fHoldBreathTime);
|
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());
|
bool isPlayer = (ptr == getPlayer());
|
||||||
|
|
||||||
|
@ -922,7 +922,7 @@ namespace MWMechanics
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (MWBase::Environment::get().getWorld()->isDark())
|
if (mayEquip)
|
||||||
{
|
{
|
||||||
if (torch != inventoryStore.end())
|
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.
|
// 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())
|
if (heldIter != inventoryStore.end() && heldIter->getTypeName() != typeid(ESM::Light).name())
|
||||||
inventoryStore.unequipItem(*heldIter, ptr);
|
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);
|
heldIter = inventoryStore.getSlot(MWWorld::InventoryStore::Slot_CarriedLeft);
|
||||||
|
|
||||||
// If we have a torch and can equip it (left slot free, no
|
// If we have a torch and can equip it, then equip it now.
|
||||||
// twohanded weapon in right slot), then equip it now.
|
|
||||||
if (heldIter == inventoryStore.end()
|
if (heldIter == inventoryStore.end()
|
||||||
&& torch->getClass().canBeEquipped(*torch, ptr).first == 1)
|
&& 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();
|
MWWorld::Ptr player = getPlayer();
|
||||||
if (ptr != player && ptr.getClass().isNpc())
|
if (ptr != player && ptr.getClass().isNpc())
|
||||||
|
@ -1204,6 +1199,9 @@ namespace MWMechanics
|
||||||
if (mTimerDisposeSummonsCorpses >= 0.2f) mTimerDisposeSummonsCorpses = 0;
|
if (mTimerDisposeSummonsCorpses >= 0.2f) mTimerDisposeSummonsCorpses = 0;
|
||||||
if (timerUpdateEquippedLight >= updateEquippedLightInterval) timerUpdateEquippedLight = 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();
|
MWWorld::Ptr player = getPlayer();
|
||||||
|
|
||||||
/// \todo move update logic to Actor class where appropriate
|
/// \todo move update logic to Actor class where appropriate
|
||||||
|
@ -1287,7 +1285,7 @@ namespace MWMechanics
|
||||||
}
|
}
|
||||||
|
|
||||||
if (iter->first.getClass().isNpc() && iter->first != player)
|
if (iter->first.getClass().isNpc() && iter->first != player)
|
||||||
updateCrimePersuit(iter->first, duration);
|
updateCrimePursuit(iter->first, duration);
|
||||||
|
|
||||||
if (iter->first != player)
|
if (iter->first != player)
|
||||||
{
|
{
|
||||||
|
@ -1302,7 +1300,7 @@ namespace MWMechanics
|
||||||
updateNpc(iter->first, duration);
|
updateNpc(iter->first, duration);
|
||||||
|
|
||||||
if (timerUpdateEquippedLight == 0)
|
if (timerUpdateEquippedLight == 0)
|
||||||
updateEquippedLight(iter->first, updateEquippedLightInterval);
|
updateEquippedLight(iter->first, updateEquippedLightInterval, showTorches);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1424,7 +1422,7 @@ namespace MWMechanics
|
||||||
MWBase::Environment::get().getWindowManager()->setSneakVisibility(false);
|
MWBase::Environment::get().getWindowManager()->setSneakVisibility(false);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
else if (!detected)
|
else
|
||||||
avoidedNotice = true;
|
avoidedNotice = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -39,9 +39,9 @@ namespace MWMechanics
|
||||||
|
|
||||||
void updateDrowning (const MWWorld::Ptr& ptr, float duration);
|
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 ();
|
void killDeadActors ();
|
||||||
|
|
||||||
|
|
|
@ -189,7 +189,7 @@ void MWMechanics::AiPackage::evadeObstacles(const MWWorld::Ptr& actor, float dur
|
||||||
static float distance = MWBase::Environment::get().getWorld()->getMaxActivationDistance();
|
static float distance = MWBase::Environment::get().getWorld()->getMaxActivationDistance();
|
||||||
|
|
||||||
MWWorld::Ptr door = getNearbyDoor(actor, distance);
|
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
|
// note: AiWander currently does not open doors
|
||||||
if (getTypeId() != TypeIdWander && !door.getCellRef().getTeleport() && door.getClass().getDoorState(door) == 0)
|
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);
|
MWBase::Environment::get().getWorld()->activate(door, actor);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else // any other obstacle (NPC, crate, etc.)
|
else
|
||||||
{
|
{
|
||||||
mObstacleCheck.takeEvasiveAction(movement);
|
mObstacleCheck.takeEvasiveAction(movement);
|
||||||
}
|
}
|
||||||
|
|
|
@ -14,7 +14,7 @@
|
||||||
*
|
*
|
||||||
* You should have received a copy of the GNU General Public License
|
* You should have received a copy of the GNU General Public License
|
||||||
* version 3 along with this program. If not, see
|
* version 3 along with this program. If not, see
|
||||||
* http://www.gnu.org/licenses/ .
|
* https://www.gnu.org/licenses/ .
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include "character.hpp"
|
#include "character.hpp"
|
||||||
|
@ -286,7 +286,7 @@ void CharacterController::refreshHitRecoilAnims()
|
||||||
}
|
}
|
||||||
else if (recovery)
|
else if (recovery)
|
||||||
{
|
{
|
||||||
std::string anim = isSwimming ? chooseRandomGroup("swimhit") : chooseRandomGroup("hit");
|
std::string anim = chooseRandomGroup("swimhit");
|
||||||
if (isSwimming && mAnimation->hasAnimation(anim))
|
if (isSwimming && mAnimation->hasAnimation(anim))
|
||||||
{
|
{
|
||||||
mHitState = CharState_SwimHit;
|
mHitState = CharState_SwimHit;
|
||||||
|
@ -517,8 +517,7 @@ void CharacterController::refreshMovementAnims(const WeaponInfo* weap, Character
|
||||||
|
|
||||||
void CharacterController::refreshIdleAnims(const WeaponInfo* weap, CharacterState idle, bool force)
|
void CharacterController::refreshIdleAnims(const WeaponInfo* weap, CharacterState idle, bool force)
|
||||||
{
|
{
|
||||||
if(force || idle != mIdleState ||
|
if(force || idle != mIdleState || (!mAnimation->isPlaying(mCurrentIdle) && mAnimQueue.empty()))
|
||||||
((idle == mIdleState) && !mAnimation->isPlaying(mCurrentIdle) && mAnimQueue.empty()))
|
|
||||||
{
|
{
|
||||||
mIdleState = idle;
|
mIdleState = idle;
|
||||||
size_t numLoops = ~0ul;
|
size_t numLoops = ~0ul;
|
||||||
|
@ -1189,7 +1188,7 @@ bool CharacterController::updateWeaponState()
|
||||||
std::string weapgroup;
|
std::string weapgroup;
|
||||||
if(weaptype == WeapType_None)
|
if(weaptype == WeapType_None)
|
||||||
{
|
{
|
||||||
if ((!isWerewolf || mWeaponType != WeapType_Spell))
|
if (!isWerewolf || mWeaponType != WeapType_Spell)
|
||||||
{
|
{
|
||||||
getWeaponGroup(mWeaponType, weapgroup);
|
getWeaponGroup(mWeaponType, weapgroup);
|
||||||
mAnimation->play(weapgroup, priorityWeapon,
|
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,
|
MWRender::Animation::BlendMask_All, false, 1.0f,
|
||||||
((mode==2) ? "loop start" : "start"), "stop", 0.0f, count-1, loopfallback);
|
((mode==2) ? "loop start" : "start"), "stop", 0.0f, count-1, loopfallback);
|
||||||
}
|
}
|
||||||
else if(mode == 0)
|
else
|
||||||
{
|
{
|
||||||
mAnimQueue.resize(1);
|
mAnimQueue.resize(1);
|
||||||
mAnimQueue.push_back(entry);
|
mAnimQueue.push_back(entry);
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
#include "combat.hpp"
|
#include "combat.hpp"
|
||||||
|
|
||||||
#include <components/misc/rng.hpp>
|
#include <components/misc/rng.hpp>
|
||||||
|
#include <components/settings/settings.hpp>
|
||||||
|
|
||||||
#include <components/sceneutil/positionattitudetransform.hpp>
|
#include <components/sceneutil/positionattitudetransform.hpp>
|
||||||
|
|
||||||
|
@ -155,7 +156,11 @@ namespace MWMechanics
|
||||||
|
|
||||||
if (!(weapon.get<ESM::Weapon>()->mBase->mData.mFlags & ESM::Weapon::Silver
|
if (!(weapon.get<ESM::Weapon>()->mBase->mData.mFlags & ESM::Weapon::Silver
|
||||||
|| weapon.get<ESM::Weapon>()->mBase->mData.mFlags & ESM::Weapon::Magical))
|
|| weapon.get<ESM::Weapon>()->mBase->mData.mFlags & ESM::Weapon::Magical))
|
||||||
|
{
|
||||||
|
if (weapon.getClass().getEnchantment(weapon).empty()
|
||||||
|
|| !Settings::Manager::getBool("enchanted weapons are magical", "Game"))
|
||||||
damage *= multiplier;
|
damage *= multiplier;
|
||||||
|
}
|
||||||
|
|
||||||
if ((weapon.get<ESM::Weapon>()->mBase->mData.mFlags & ESM::Weapon::Silver)
|
if ((weapon.get<ESM::Weapon>()->mBase->mData.mFlags & ESM::Weapon::Silver)
|
||||||
&& actor.getClass().isNpc() && actor.getClass().getNpcStats(actor).isWerewolf())
|
&& actor.getClass().isNpc() && actor.getClass().getNpcStats(actor).isWerewolf())
|
||||||
|
|
|
@ -242,8 +242,11 @@ namespace MWMechanics
|
||||||
return 0;
|
return 0;
|
||||||
if(mSoulGemPtr.getCellRef().getSoul()=="")
|
if(mSoulGemPtr.getCellRef().getSoul()=="")
|
||||||
return 0;
|
return 0;
|
||||||
const ESM::Creature* soul = store.get<ESM::Creature>().find(mSoulGemPtr.getCellRef().getSoul());
|
const ESM::Creature* soul = store.get<ESM::Creature>().search(mSoulGemPtr.getCellRef().getSoul());
|
||||||
|
if(soul)
|
||||||
return soul->mData.mSoul;
|
return soul->mData.mSoul;
|
||||||
|
else
|
||||||
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
int Enchanting::getMaxEnchantValue() const
|
int Enchanting::getMaxEnchantValue() const
|
||||||
|
|
|
@ -79,21 +79,21 @@ namespace MWMechanics
|
||||||
const ESM::NPC *player = ptr.get<ESM::NPC>()->mBase;
|
const ESM::NPC *player = ptr.get<ESM::NPC>()->mBase;
|
||||||
|
|
||||||
// reset
|
// reset
|
||||||
creatureStats.setLevel(player->mNpdt52.mLevel);
|
creatureStats.setLevel(player->mNpdt.mLevel);
|
||||||
creatureStats.getSpells().clear();
|
creatureStats.getSpells().clear();
|
||||||
creatureStats.modifyMagicEffects(MagicEffects());
|
creatureStats.modifyMagicEffects(MagicEffects());
|
||||||
|
|
||||||
for (int i=0; i<27; ++i)
|
for (int i=0; i<27; ++i)
|
||||||
npcStats.getSkill (i).setBase (player->mNpdt52.mSkills[i]);
|
npcStats.getSkill (i).setBase (player->mNpdt.mSkills[i]);
|
||||||
|
|
||||||
creatureStats.setAttribute(ESM::Attribute::Strength, player->mNpdt52.mStrength);
|
creatureStats.setAttribute(ESM::Attribute::Strength, player->mNpdt.mStrength);
|
||||||
creatureStats.setAttribute(ESM::Attribute::Intelligence, player->mNpdt52.mIntelligence);
|
creatureStats.setAttribute(ESM::Attribute::Intelligence, player->mNpdt.mIntelligence);
|
||||||
creatureStats.setAttribute(ESM::Attribute::Willpower, player->mNpdt52.mWillpower);
|
creatureStats.setAttribute(ESM::Attribute::Willpower, player->mNpdt.mWillpower);
|
||||||
creatureStats.setAttribute(ESM::Attribute::Agility, player->mNpdt52.mAgility);
|
creatureStats.setAttribute(ESM::Attribute::Agility, player->mNpdt.mAgility);
|
||||||
creatureStats.setAttribute(ESM::Attribute::Speed, player->mNpdt52.mSpeed);
|
creatureStats.setAttribute(ESM::Attribute::Speed, player->mNpdt.mSpeed);
|
||||||
creatureStats.setAttribute(ESM::Attribute::Endurance, player->mNpdt52.mEndurance);
|
creatureStats.setAttribute(ESM::Attribute::Endurance, player->mNpdt.mEndurance);
|
||||||
creatureStats.setAttribute(ESM::Attribute::Personality, player->mNpdt52.mPersonality);
|
creatureStats.setAttribute(ESM::Attribute::Personality, player->mNpdt.mPersonality);
|
||||||
creatureStats.setAttribute(ESM::Attribute::Luck, player->mNpdt52.mLuck);
|
creatureStats.setAttribute(ESM::Attribute::Luck, player->mNpdt.mLuck);
|
||||||
const MWWorld::ESMStore &esmStore =
|
const MWWorld::ESMStore &esmStore =
|
||||||
MWBase::Environment::get().getWorld()->getStore();
|
MWBase::Environment::get().getWorld()->getStore();
|
||||||
|
|
||||||
|
@ -1118,8 +1118,11 @@ namespace MWMechanics
|
||||||
Misc::StringUtils::lowerCaseInPlace(owner.first);
|
Misc::StringUtils::lowerCaseInPlace(owner.first);
|
||||||
|
|
||||||
if (!Misc::StringUtils::ciEqual(item.getCellRef().getRefId(), MWWorld::ContainerStore::sGoldId))
|
if (!Misc::StringUtils::ciEqual(item.getCellRef().getRefId(), MWWorld::ContainerStore::sGoldId))
|
||||||
|
{
|
||||||
|
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;
|
mStolenItems[Misc::StringUtils::lowerCase(item.getCellRef().getRefId())][owner] += count;
|
||||||
|
}
|
||||||
if (alarm)
|
if (alarm)
|
||||||
commitCrime(ptr, victim, OT_Theft, item.getClass().getValue(item) * count);
|
commitCrime(ptr, victim, OT_Theft, item.getClass().getValue(item) * count);
|
||||||
}
|
}
|
||||||
|
@ -1442,8 +1445,21 @@ namespace MWMechanics
|
||||||
// Attacker is in combat with us, but we are not in combat with the attacker yet. Time to fight back.
|
// 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.
|
// Note: accidental or collateral damage attacks are ignored.
|
||||||
if (!target.getClass().getCreatureStats(target).getAiSequence().hasPackage(AiPackage::TypeIdPursue))
|
if (!target.getClass().getCreatureStats(target).getAiSequence().hasPackage(AiPackage::TypeIdPursue))
|
||||||
|
{
|
||||||
|
// 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);
|
startCombat(target, attacker);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
@ -1719,11 +1735,11 @@ namespace MWMechanics
|
||||||
{
|
{
|
||||||
if (werewolf)
|
if (werewolf)
|
||||||
{
|
{
|
||||||
player->saveSkillsAttributes();
|
player->saveStats();
|
||||||
player->setWerewolfSkillsAttributes();
|
player->setWerewolfStats();
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
player->restoreSkillsAttributes();
|
player->restoreStats();
|
||||||
}
|
}
|
||||||
|
|
||||||
// Werewolfs can not cast spells, so we need to unset the prepared spell if there is one.
|
// Werewolfs can not cast spells, so we need to unset the prepared spell if there is one.
|
||||||
|
|
|
@ -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();
|
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");
|
MWBase::Environment::get().getWindowManager()->playSound("skillraise");
|
||||||
|
|
||||||
std::stringstream message;
|
std::stringstream message;
|
||||||
|
|
||||||
|
if (readBook)
|
||||||
|
message << std::string("#{sBookSkillMessage}\n");
|
||||||
|
|
||||||
message << boost::format(MWBase::Environment::get().getWindowManager ()->getGameSettingString ("sNotifyMessage39", ""))
|
message << boost::format(MWBase::Environment::get().getWindowManager ()->getGameSettingString ("sNotifyMessage39", ""))
|
||||||
% std::string("#{" + ESM::Skill::sSkillNameIds[skillIndex] + "}")
|
% std::string("#{" + ESM::Skill::sSkillNameIds[skillIndex] + "}")
|
||||||
% static_cast<int> (base);
|
% static_cast<int> (base);
|
||||||
|
|
||||||
MWBase::Environment::get().getWindowManager ()->messageBox(message.str(), MWGui::ShowInDialogueMode_Never);
|
MWBase::Environment::get().getWindowManager ()->messageBox(message.str(), MWGui::ShowInDialogueMode_Never);
|
||||||
|
|
||||||
if (mLevelProgress >= gmst.find("iLevelUpTotal")->getInt())
|
if (mLevelProgress >= gmst.find("iLevelUpTotal")->getInt())
|
||||||
|
|
|
@ -81,7 +81,7 @@ namespace MWMechanics
|
||||||
void useSkill (int skillIndex, const ESM::Class& class_, int usageType = -1, float extraFactor=1.f);
|
void useSkill (int skillIndex, const ESM::Class& class_, int usageType = -1, float extraFactor=1.f);
|
||||||
///< Increase skill by usage.
|
///< 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;
|
int getLevelProgress() const;
|
||||||
|
|
||||||
|
|
|
@ -8,7 +8,7 @@
|
||||||
|
|
||||||
namespace
|
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:
|
// One of the smallest cost in Seyda Neen is between points 77 & 78:
|
||||||
// pt x y
|
// pt x y
|
||||||
|
|
|
@ -7,6 +7,7 @@
|
||||||
#include <boost/format.hpp>
|
#include <boost/format.hpp>
|
||||||
|
|
||||||
#include <components/misc/rng.hpp>
|
#include <components/misc/rng.hpp>
|
||||||
|
#include <components/settings/settings.hpp>
|
||||||
|
|
||||||
#include "../mwbase/windowmanager.hpp"
|
#include "../mwbase/windowmanager.hpp"
|
||||||
#include "../mwbase/soundmanager.hpp"
|
#include "../mwbase/soundmanager.hpp"
|
||||||
|
@ -24,7 +25,6 @@
|
||||||
|
|
||||||
#include "../mwrender/animation.hpp"
|
#include "../mwrender/animation.hpp"
|
||||||
|
|
||||||
#include "magiceffects.hpp"
|
|
||||||
#include "npcstats.hpp"
|
#include "npcstats.hpp"
|
||||||
#include "actorutil.hpp"
|
#include "actorutil.hpp"
|
||||||
#include "aifollow.hpp"
|
#include "aifollow.hpp"
|
||||||
|
@ -489,6 +489,9 @@ namespace MWMechanics
|
||||||
MWBase::Environment::get().getWindowManager()->messageBox("#{sMagicTargetResisted}");
|
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 player is attempting to cast a harmful spell, show the target's HP bar
|
||||||
if (castByPlayer && target != caster)
|
if (castByPlayer && target != caster)
|
||||||
MWBase::Environment::get().getWindowManager()->setEnemy(target);
|
MWBase::Environment::get().getWindowManager()->setEnemy(target);
|
||||||
|
@ -567,7 +570,10 @@ namespace MWMechanics
|
||||||
ActiveSpells::ActiveEffect effect_ = effect;
|
ActiveSpells::ActiveEffect effect_ = effect;
|
||||||
effect_.mMagnitude *= -1;
|
effect_.mMagnitude *= -1;
|
||||||
absorbEffects.push_back(effect_);
|
absorbEffects.push_back(effect_);
|
||||||
// Also make sure to set casterActorId = target, so that the effect on the caster gets purged when the target dies
|
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,
|
caster.getClass().getCreatureStats(caster).getActiveSpells().addSpell("", true,
|
||||||
absorbEffects, mSourceName, target.getClass().getCreatureStats(target).getActorId());
|
absorbEffects, mSourceName, target.getClass().getCreatureStats(target).getActorId());
|
||||||
}
|
}
|
||||||
|
@ -609,7 +615,6 @@ namespace MWMechanics
|
||||||
|
|
||||||
std::string texture = magicEffect->mParticle;
|
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;
|
bool loop = (magicEffect->mData.mFlags & ESM::MagicEffect::ContinuousVfx) != 0;
|
||||||
// Note: in case of non actor, a free effect should be fine as well
|
// Note: in case of non actor, a free effect should be fine as well
|
||||||
MWRender::Animation* anim = MWBase::Environment::get().getWorld()->getAnimation(target);
|
MWRender::Animation* anim = MWBase::Environment::get().getWorld()->getAnimation(target);
|
||||||
|
@ -877,13 +882,12 @@ namespace MWMechanics
|
||||||
const float normalizedEncumbrance = mCaster.getClass().getNormalizedEncumbrance(mCaster);
|
const float normalizedEncumbrance = mCaster.getClass().getNormalizedEncumbrance(mCaster);
|
||||||
|
|
||||||
float fatigueLoss = spell->mData.mCost * (fFatigueSpellBase + normalizedEncumbrance * fFatigueSpellMult);
|
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;
|
bool fail = false;
|
||||||
|
|
||||||
// Check success
|
// Check success
|
||||||
if (!(mCaster == getPlayer() && MWBase::Environment::get().getWorld()->getGodModeState()))
|
|
||||||
{
|
|
||||||
float successChance = getSpellSuccessChance(spell, mCaster);
|
float successChance = getSpellSuccessChance(spell, mCaster);
|
||||||
if (Misc::Rng::roll0to99() >= successChance)
|
if (Misc::Rng::roll0to99() >= successChance)
|
||||||
{
|
{
|
||||||
|
@ -891,7 +895,6 @@ namespace MWMechanics
|
||||||
MWBase::Environment::get().getWindowManager()->messageBox("#{sMagicSkillFail}");
|
MWBase::Environment::get().getWindowManager()->messageBox("#{sMagicSkillFail}");
|
||||||
fail = true;
|
fail = true;
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
if (fail)
|
if (fail)
|
||||||
{
|
{
|
||||||
|
@ -1111,8 +1114,6 @@ namespace MWMechanics
|
||||||
|
|
||||||
bool receivedMagicDamage = false;
|
bool receivedMagicDamage = false;
|
||||||
|
|
||||||
bool godmode = actor == MWMechanics::getPlayer() && MWBase::Environment::get().getWorld()->getGodModeState();
|
|
||||||
|
|
||||||
switch (effectKey.mId)
|
switch (effectKey.mId)
|
||||||
{
|
{
|
||||||
case ESM::MagicEffect::DamageAttribute:
|
case ESM::MagicEffect::DamageAttribute:
|
||||||
|
@ -1135,40 +1136,25 @@ namespace MWMechanics
|
||||||
adjustDynamicStat(creatureStats, effectKey.mId-ESM::MagicEffect::RestoreHealth, magnitude);
|
adjustDynamicStat(creatureStats, effectKey.mId-ESM::MagicEffect::RestoreHealth, magnitude);
|
||||||
break;
|
break;
|
||||||
case ESM::MagicEffect::DamageHealth:
|
case ESM::MagicEffect::DamageHealth:
|
||||||
if (!godmode)
|
|
||||||
{
|
|
||||||
receivedMagicDamage = true;
|
receivedMagicDamage = true;
|
||||||
adjustDynamicStat(creatureStats, effectKey.mId-ESM::MagicEffect::DamageHealth, -magnitude);
|
adjustDynamicStat(creatureStats, effectKey.mId-ESM::MagicEffect::DamageHealth, -magnitude);
|
||||||
}
|
|
||||||
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case ESM::MagicEffect::DamageMagicka:
|
case ESM::MagicEffect::DamageMagicka:
|
||||||
case ESM::MagicEffect::DamageFatigue:
|
case ESM::MagicEffect::DamageFatigue:
|
||||||
if (!godmode)
|
|
||||||
{
|
|
||||||
adjustDynamicStat(creatureStats, effectKey.mId-ESM::MagicEffect::DamageHealth, -magnitude);
|
adjustDynamicStat(creatureStats, effectKey.mId-ESM::MagicEffect::DamageHealth, -magnitude);
|
||||||
}
|
|
||||||
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case ESM::MagicEffect::AbsorbHealth:
|
case ESM::MagicEffect::AbsorbHealth:
|
||||||
if (!godmode)
|
|
||||||
{
|
|
||||||
if (magnitude > 0.f)
|
if (magnitude > 0.f)
|
||||||
receivedMagicDamage = true;
|
receivedMagicDamage = true;
|
||||||
adjustDynamicStat(creatureStats, effectKey.mId-ESM::MagicEffect::AbsorbHealth, -magnitude);
|
adjustDynamicStat(creatureStats, effectKey.mId-ESM::MagicEffect::AbsorbHealth, -magnitude);
|
||||||
}
|
|
||||||
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case ESM::MagicEffect::AbsorbMagicka:
|
case ESM::MagicEffect::AbsorbMagicka:
|
||||||
case ESM::MagicEffect::AbsorbFatigue:
|
case ESM::MagicEffect::AbsorbFatigue:
|
||||||
if (!godmode)
|
|
||||||
{
|
|
||||||
adjustDynamicStat(creatureStats, effectKey.mId-ESM::MagicEffect::AbsorbHealth, -magnitude);
|
adjustDynamicStat(creatureStats, effectKey.mId-ESM::MagicEffect::AbsorbHealth, -magnitude);
|
||||||
}
|
|
||||||
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case ESM::MagicEffect::DisintegrateArmor:
|
case ESM::MagicEffect::DisintegrateArmor:
|
||||||
|
@ -1191,6 +1177,7 @@ namespace MWMechanics
|
||||||
if (disintegrateSlot(actor, priorities[i], magnitude))
|
if (disintegrateSlot(actor, priorities[i], magnitude))
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case ESM::MagicEffect::DisintegrateWeapon:
|
case ESM::MagicEffect::DisintegrateWeapon:
|
||||||
|
@ -1213,12 +1200,9 @@ namespace MWMechanics
|
||||||
if (weather > 1)
|
if (weather > 1)
|
||||||
damageScale *= fMagicSunBlockedMult;
|
damageScale *= fMagicSunBlockedMult;
|
||||||
|
|
||||||
if (!godmode)
|
|
||||||
{
|
|
||||||
adjustDynamicStat(creatureStats, 0, -magnitude * damageScale);
|
adjustDynamicStat(creatureStats, 0, -magnitude * damageScale);
|
||||||
if (magnitude * damageScale > 0.f)
|
if (magnitude * damageScale > 0.f)
|
||||||
receivedMagicDamage = true;
|
receivedMagicDamage = true;
|
||||||
}
|
|
||||||
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
@ -1227,13 +1211,9 @@ namespace MWMechanics
|
||||||
case ESM::MagicEffect::ShockDamage:
|
case ESM::MagicEffect::ShockDamage:
|
||||||
case ESM::MagicEffect::FrostDamage:
|
case ESM::MagicEffect::FrostDamage:
|
||||||
case ESM::MagicEffect::Poison:
|
case ESM::MagicEffect::Poison:
|
||||||
{
|
|
||||||
if (!godmode)
|
|
||||||
{
|
{
|
||||||
adjustDynamicStat(creatureStats, 0, -magnitude);
|
adjustDynamicStat(creatureStats, 0, -magnitude);
|
||||||
receivedMagicDamage = true;
|
receivedMagicDamage = true;
|
||||||
}
|
|
||||||
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1314,4 +1294,24 @@ namespace MWMechanics
|
||||||
return MWBase::Environment::get().getWorld()->getStore().get<ESM::GameSetting>().find(it->second)->getString();
|
return MWBase::Environment::get().getWorld()->getStore().get<ESM::GameSetting>().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<ESM::MagicEffect>().find(key.mId);
|
||||||
|
|
||||||
|
const ESM::Static* castStatic;
|
||||||
|
if (!magicEffect->mHit.empty())
|
||||||
|
castStatic = MWBase::Environment::get().getWorld()->getStore().get<ESM::Static>().find (magicEffect->mHit);
|
||||||
|
else
|
||||||
|
castStatic = MWBase::Environment::get().getWorld()->getStore().get<ESM::Static>().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);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -6,6 +6,8 @@
|
||||||
|
|
||||||
#include "../mwworld/ptr.hpp"
|
#include "../mwworld/ptr.hpp"
|
||||||
|
|
||||||
|
#include "magiceffects.hpp"
|
||||||
|
|
||||||
namespace ESM
|
namespace ESM
|
||||||
{
|
{
|
||||||
struct Spell;
|
struct Spell;
|
||||||
|
@ -119,6 +121,21 @@ namespace MWMechanics
|
||||||
bool applyInstantEffect (const MWWorld::Ptr& target, const MWWorld::Ptr& caster, const MWMechanics::EffectKey& effect, float magnitude);
|
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
|
#endif
|
||||||
|
|
|
@ -13,7 +13,6 @@
|
||||||
#include <BulletCollision/CollisionDispatch/btCollisionObject.h>
|
#include <BulletCollision/CollisionDispatch/btCollisionObject.h>
|
||||||
#include <BulletCollision/CollisionDispatch/btCollisionWorld.h>
|
#include <BulletCollision/CollisionDispatch/btCollisionWorld.h>
|
||||||
#include <BulletCollision/CollisionDispatch/btDefaultCollisionConfiguration.h>
|
#include <BulletCollision/CollisionDispatch/btDefaultCollisionConfiguration.h>
|
||||||
#include <BulletCollision/CollisionDispatch/btCollisionWorld.h>
|
|
||||||
#include <BulletCollision/BroadphaseCollision/btDbvtBroadphase.h>
|
#include <BulletCollision/BroadphaseCollision/btDbvtBroadphase.h>
|
||||||
|
|
||||||
#include <LinearMath/btQuickprof.h>
|
#include <LinearMath/btQuickprof.h>
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
#include "characterpreview.hpp"
|
#include "characterpreview.hpp"
|
||||||
|
|
||||||
|
#include <cmath>
|
||||||
#include <iostream>
|
#include <iostream>
|
||||||
|
|
||||||
#include <osg/Material>
|
#include <osg/Material>
|
||||||
|
@ -13,6 +14,7 @@
|
||||||
#include <osgUtil/IntersectionVisitor>
|
#include <osgUtil/IntersectionVisitor>
|
||||||
#include <osgUtil/LineSegmentIntersector>
|
#include <osgUtil/LineSegmentIntersector>
|
||||||
|
|
||||||
|
#include <components/fallback/fallback.hpp>
|
||||||
#include <components/sceneutil/lightmanager.hpp>
|
#include <components/sceneutil/lightmanager.hpp>
|
||||||
#include <components/sceneutil/shadow.hpp>
|
#include <components/sceneutil/shadow.hpp>
|
||||||
|
|
||||||
|
@ -161,14 +163,25 @@ namespace MWRender
|
||||||
stateset->setAttributeAndModes(fog, osg::StateAttribute::OFF|osg::StateAttribute::OVERRIDE);
|
stateset->setAttributeAndModes(fog, osg::StateAttribute::OFF|osg::StateAttribute::OVERRIDE);
|
||||||
|
|
||||||
osg::ref_ptr<osg::LightModel> lightmodel = new osg::LightModel;
|
osg::ref_ptr<osg::LightModel> 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);
|
stateset->setAttributeAndModes(lightmodel, osg::StateAttribute::ON);
|
||||||
|
|
||||||
/// \todo Read the fallback values from INIImporter (Inventory:Directional*) ?
|
|
||||||
osg::ref_ptr<osg::Light> light = new osg::Light;
|
osg::ref_ptr<osg::Light> light = new osg::Light;
|
||||||
light->setPosition(osg::Vec4(-0.3,0.3,0.7, 0.0));
|
const Fallback::Map* fallback = MWBase::Environment::get().getWorld()->getFallback();
|
||||||
light->setDiffuse(osg::Vec4(1,1,1,1));
|
float diffuseR = fallback->getFallbackFloat("Inventory_DirectionalDiffuseR");
|
||||||
light->setAmbient(osg::Vec4(0,0,0,1));
|
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->setSpecular(osg::Vec4(0,0,0,0));
|
||||||
light->setLightNum(0);
|
light->setLightNum(0);
|
||||||
light->setConstantAttenuation(1.f);
|
light->setConstantAttenuation(1.f);
|
||||||
|
|
|
@ -8,6 +8,7 @@
|
||||||
#include <osg/Texture2D>
|
#include <osg/Texture2D>
|
||||||
#include <osg/ComputeBoundsVisitor>
|
#include <osg/ComputeBoundsVisitor>
|
||||||
#include <osg/LightSource>
|
#include <osg/LightSource>
|
||||||
|
#include <osg/PolygonMode>
|
||||||
|
|
||||||
#include <osgDB/ReadFile>
|
#include <osgDB/ReadFile>
|
||||||
|
|
||||||
|
@ -175,6 +176,7 @@ osg::ref_ptr<osg::Camera> LocalMap::createOrthographicCamera(float x, float y, f
|
||||||
camera->setNodeMask(Mask_RenderToTexture);
|
camera->setNodeMask(Mask_RenderToTexture);
|
||||||
|
|
||||||
osg::ref_ptr<osg::StateSet> stateset = new osg::StateSet;
|
osg::ref_ptr<osg::StateSet> 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
|
// assign large value to effectively turn off fog
|
||||||
// shaders don't respect glDisable(GL_FOG)
|
// shaders don't respect glDisable(GL_FOG)
|
||||||
|
|
|
@ -52,6 +52,16 @@
|
||||||
#include "terrainstorage.hpp"
|
#include "terrainstorage.hpp"
|
||||||
#include "util.hpp"
|
#include "util.hpp"
|
||||||
|
|
||||||
|
namespace
|
||||||
|
{
|
||||||
|
float DLLandFogStart;
|
||||||
|
float DLLandFogEnd;
|
||||||
|
float DLUnderwaterFogStart;
|
||||||
|
float DLUnderwaterFogEnd;
|
||||||
|
float DLInteriorFogStart;
|
||||||
|
float DLInteriorFogEnd;
|
||||||
|
}
|
||||||
|
|
||||||
namespace MWRender
|
namespace MWRender
|
||||||
{
|
{
|
||||||
|
|
||||||
|
@ -174,14 +184,18 @@ namespace MWRender
|
||||||
, mResourceSystem(resourceSystem)
|
, mResourceSystem(resourceSystem)
|
||||||
, mWorkQueue(workQueue)
|
, mWorkQueue(workQueue)
|
||||||
, mUnrefQueue(new SceneUtil::UnrefQueue)
|
, mUnrefQueue(new SceneUtil::UnrefQueue)
|
||||||
, mFogDepth(0.f)
|
, mLandFogStart(0.f)
|
||||||
|
, mLandFogEnd(std::numeric_limits<float>::max())
|
||||||
|
, mUnderwaterFogStart(0.f)
|
||||||
|
, mUnderwaterFogEnd(std::numeric_limits<float>::max())
|
||||||
, mUnderwaterColor(fallback->getFallbackColour("Water_UnderwaterColor"))
|
, mUnderwaterColor(fallback->getFallbackColour("Water_UnderwaterColor"))
|
||||||
, mUnderwaterWeight(fallback->getFallbackFloat("Water_UnderwaterColorWeight"))
|
, mUnderwaterWeight(fallback->getFallbackFloat("Water_UnderwaterColorWeight"))
|
||||||
, mUnderwaterFog(0.f)
|
|
||||||
, mUnderwaterIndoorFog(fallback->getFallbackFloat("Water_UnderwaterIndoorFog"))
|
, mUnderwaterIndoorFog(fallback->getFallbackFloat("Water_UnderwaterIndoorFog"))
|
||||||
, mNightEyeFactor(0.f)
|
, mNightEyeFactor(0.f)
|
||||||
, mFieldOfViewOverride(0.f)
|
, mDistantFog(false)
|
||||||
|
, mDistantTerrain(false)
|
||||||
, mFieldOfViewOverridden(false)
|
, mFieldOfViewOverridden(false)
|
||||||
|
, mFieldOfViewOverride(0.f)
|
||||||
{
|
{
|
||||||
resourceSystem->getSceneManager()->setParticleSystemMask(MWRender::Mask_ParticleSystem);
|
resourceSystem->getSceneManager()->setParticleSystemMask(MWRender::Mask_ParticleSystem);
|
||||||
|
|
||||||
|
@ -239,12 +253,20 @@ namespace MWRender
|
||||||
|
|
||||||
mWater.reset(new Water(mRootNode, sceneRoot, mResourceSystem, mViewer->getIncrementalCompileOperation(), fallback, resourcePath));
|
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"),
|
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"));
|
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));
|
mTerrain.reset(new Terrain::QuadTreeWorld(sceneRoot, mRootNode, mResourceSystem, mTerrainStorage, Mask_Terrain, Mask_PreCompile));
|
||||||
else
|
else
|
||||||
mTerrain.reset(new Terrain::TerrainGrid(sceneRoot, mRootNode, mResourceSystem, mTerrainStorage, Mask_Terrain, Mask_PreCompile));
|
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);
|
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<float>::max();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
mLandFogStart = mViewDistance * (1 - fogDepth);
|
||||||
|
mLandFogEnd = mViewDistance;
|
||||||
|
}
|
||||||
|
mUnderwaterFogStart = mViewDistance * (1 - underwaterFog);
|
||||||
|
mUnderwaterFogEnd = mViewDistance;
|
||||||
|
}
|
||||||
mFogColor = color;
|
mFogColor = color;
|
||||||
mUnderwaterFog = underwaterFog;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
SkyManager* RenderingManager::getSkyManager()
|
SkyManager* RenderingManager::getSkyManager()
|
||||||
|
@ -544,23 +596,15 @@ namespace MWRender
|
||||||
float viewDistance = mViewDistance;
|
float viewDistance = mViewDistance;
|
||||||
viewDistance = std::min(viewDistance, 6666.f);
|
viewDistance = std::min(viewDistance, 6666.f);
|
||||||
setFogColor(mUnderwaterColor * mUnderwaterWeight + mFogColor * (1.f-mUnderwaterWeight));
|
setFogColor(mUnderwaterColor * mUnderwaterWeight + mFogColor * (1.f-mUnderwaterWeight));
|
||||||
mStateUpdater->setFogStart(viewDistance * (1 - mUnderwaterFog));
|
mStateUpdater->setFogStart(mUnderwaterFogStart);
|
||||||
mStateUpdater->setFogEnd(viewDistance);
|
mStateUpdater->setFogEnd(mUnderwaterFogEnd);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
setFogColor(mFogColor);
|
setFogColor(mFogColor);
|
||||||
|
|
||||||
if (mFogDepth == 0.f)
|
mStateUpdater->setFogStart(mLandFogStart);
|
||||||
{
|
mStateUpdater->setFogEnd(mLandFogEnd);
|
||||||
mStateUpdater->setFogStart(0.f);
|
|
||||||
mStateUpdater->setFogEnd(std::numeric_limits<float>::max());
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
mStateUpdater->setFogStart(mViewDistance * (1 - mFogDepth));
|
|
||||||
mStateUpdater->setFogEnd(mViewDistance);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -987,6 +1031,7 @@ namespace MWRender
|
||||||
else if (it->first == "Camera" && it->second == "viewing distance")
|
else if (it->first == "Camera" && it->second == "viewing distance")
|
||||||
{
|
{
|
||||||
mViewDistance = Settings::Manager::getFloat("viewing distance", "Camera");
|
mViewDistance = Settings::Manager::getFloat("viewing distance", "Camera");
|
||||||
|
if(!mDistantFog)
|
||||||
mStateUpdater->setFogEnd(mViewDistance);
|
mStateUpdater->setFogEnd(mViewDistance);
|
||||||
updateProjectionMatrix();
|
updateProjectionMatrix();
|
||||||
}
|
}
|
||||||
|
|
|
@ -107,7 +107,7 @@ namespace MWRender
|
||||||
|
|
||||||
void configureAmbient(const ESM::Cell* cell);
|
void configureAmbient(const ESM::Cell* cell);
|
||||||
void configureFog(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 addCell(const MWWorld::CellStore* store);
|
||||||
void removeCell(const MWWorld::CellStore* store);
|
void removeCell(const MWWorld::CellStore* store);
|
||||||
|
@ -243,10 +243,12 @@ namespace MWRender
|
||||||
|
|
||||||
osg::ref_ptr<StateUpdater> mStateUpdater;
|
osg::ref_ptr<StateUpdater> mStateUpdater;
|
||||||
|
|
||||||
float mFogDepth;
|
float mLandFogStart;
|
||||||
|
float mLandFogEnd;
|
||||||
|
float mUnderwaterFogStart;
|
||||||
|
float mUnderwaterFogEnd;
|
||||||
osg::Vec4f mUnderwaterColor;
|
osg::Vec4f mUnderwaterColor;
|
||||||
float mUnderwaterWeight;
|
float mUnderwaterWeight;
|
||||||
float mUnderwaterFog;
|
|
||||||
float mUnderwaterIndoorFog;
|
float mUnderwaterIndoorFog;
|
||||||
osg::Vec4f mFogColor;
|
osg::Vec4f mFogColor;
|
||||||
|
|
||||||
|
@ -255,8 +257,10 @@ namespace MWRender
|
||||||
|
|
||||||
float mNearClip;
|
float mNearClip;
|
||||||
float mViewDistance;
|
float mViewDistance;
|
||||||
|
bool mDistantFog : 1;
|
||||||
|
bool mDistantTerrain : 1;
|
||||||
|
bool mFieldOfViewOverridden : 1;
|
||||||
float mFieldOfViewOverride;
|
float mFieldOfViewOverride;
|
||||||
bool mFieldOfViewOverridden;
|
|
||||||
float mFieldOfView;
|
float mFieldOfView;
|
||||||
float mFirstPersonFieldOfView;
|
float mFirstPersonFieldOfView;
|
||||||
|
|
||||||
|
|
|
@ -65,6 +65,9 @@ namespace MWRender
|
||||||
|
|
||||||
float mFogDepth;
|
float mFogDepth;
|
||||||
|
|
||||||
|
float mDLFogFactor;
|
||||||
|
float mDLFogOffset;
|
||||||
|
|
||||||
float mWindSpeed;
|
float mWindSpeed;
|
||||||
|
|
||||||
float mCloudSpeed;
|
float mCloudSpeed;
|
||||||
|
|
|
@ -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.
|
// 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.
|
// 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();
|
Resource::SceneManager* sceneManager = mResourceSystem->getSceneManager();
|
||||||
bool oldValue = sceneManager->getForceShaders();
|
bool oldValue = sceneManager->getForceShaders();
|
||||||
sceneManager->setForceShaders(true);
|
sceneManager->setForceShaders(true);
|
||||||
sceneManager->recreateShaders(node);
|
sceneManager->recreateShaders(node);
|
||||||
sceneManager->setForceShaders(oldValue);
|
sceneManager->setForceShaders(oldValue);
|
||||||
#endif
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void Water::createShaderWaterStateSet(osg::Node* node, Reflection* reflection, Refraction* refraction)
|
void Water::createShaderWaterStateSet(osg::Node* node, Reflection* reflection, Refraction* refraction)
|
||||||
|
|
|
@ -406,7 +406,7 @@ namespace MWScript
|
||||||
const MWWorld::ESMStore &store = world->getStore();
|
const MWWorld::ESMStore &store = world->getStore();
|
||||||
const ESM::Faction *faction = store.get<ESM::Faction>().find(factionId);
|
const ESM::Faction *faction = store.get<ESM::Faction>().find(factionId);
|
||||||
|
|
||||||
if(rank < 0 || rank > 9)
|
if(rank < 0)
|
||||||
return "";
|
return "";
|
||||||
|
|
||||||
return faction->mRanks[rank];
|
return faction->mRanks[rank];
|
||||||
|
|
|
@ -454,7 +454,13 @@ namespace MWScript
|
||||||
store.get<ESM::Creature>().find(creature); // This line throws an exception if it can't find the creature
|
store.get<ESM::Creature>().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);
|
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);
|
item.getCellRef().setSoul(creature);
|
||||||
|
|
||||||
|
// Restack the gem with other gems with the same soul
|
||||||
|
item.getContainerStore()->restack(item);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -530,7 +530,8 @@ namespace MWScript
|
||||||
// create item
|
// create item
|
||||||
MWWorld::ManualRef ref(MWBase::Environment::get().getWorld()->getStore(), itemID, 1);
|
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());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
|
@ -15,7 +15,7 @@
|
||||||
* License along with this library; if not, write to the
|
* License along with this library; if not, write to the
|
||||||
* Free Software Foundation, Inc.,
|
* Free Software Foundation, Inc.,
|
||||||
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
* 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
|
#ifndef AL_ALEXT_H
|
||||||
|
|
|
@ -21,7 +21,7 @@ extern "C"
|
||||||
|
|
||||||
// From version 54.56 binkaudio encoding format changed from S16 to FLTP. See:
|
// From version 54.56 binkaudio encoding format changed from S16 to FLTP. See:
|
||||||
// https://gitorious.org/ffmpeg/ffmpeg/commit/7bfd1766d1c18f07b0a2dd042418a874d49ea60d
|
// 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 <libswresample/swresample.h>
|
#include <libswresample/swresample.h>
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -393,32 +393,8 @@ namespace MWSound
|
||||||
|
|
||||||
void SoundManager::startRandomTitle()
|
void SoundManager::startRandomTitle()
|
||||||
{
|
{
|
||||||
std::vector<std::string> filelist;
|
const std::vector<std::string> &filelist = mMusicFiles[mCurrentPlaylist];
|
||||||
auto &tracklist = mMusicToPlay[mCurrentPlaylist];
|
auto &tracklist = mMusicToPlay[mCurrentPlaylist];
|
||||||
if (mMusicFiles.find(mCurrentPlaylist) == mMusicFiles.end())
|
|
||||||
{
|
|
||||||
const std::map<std::string, VFS::File*>& index = mVFS->getIndex();
|
|
||||||
|
|
||||||
std::string pattern = "Music/" + mCurrentPlaylist;
|
|
||||||
mVFS->normalizeFilename(pattern);
|
|
||||||
|
|
||||||
std::map<std::string, VFS::File*>::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
|
// Do a Fisher-Yates shuffle
|
||||||
|
|
||||||
|
@ -454,6 +430,33 @@ namespace MWSound
|
||||||
|
|
||||||
void SoundManager::playPlaylist(const std::string &playlist)
|
void SoundManager::playPlaylist(const std::string &playlist)
|
||||||
{
|
{
|
||||||
|
if (mCurrentPlaylist == playlist)
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (mMusicFiles.find(playlist) == mMusicFiles.end())
|
||||||
|
{
|
||||||
|
std::vector<std::string> filelist;
|
||||||
|
const std::map<std::string, VFS::File*>& index = mVFS->getIndex();
|
||||||
|
|
||||||
|
std::string pattern = "Music/" + playlist;
|
||||||
|
mVFS->normalizeFilename(pattern);
|
||||||
|
|
||||||
|
std::map<std::string, VFS::File*>::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;
|
mCurrentPlaylist = playlist;
|
||||||
startRandomTitle();
|
startRandomTitle();
|
||||||
}
|
}
|
||||||
|
|
38
apps/openmw/mwstate/quicksavemanager.cpp
Normal file
38
apps/openmw/mwstate/quicksavemanager.cpp
Normal file
|
@ -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;
|
||||||
|
}
|
35
apps/openmw/mwstate/quicksavemanager.hpp
Normal file
35
apps/openmw/mwstate/quicksavemanager.hpp
Normal file
|
@ -0,0 +1,35 @@
|
||||||
|
#ifndef GAME_STATE_QUICKSAVEMANAGER_H
|
||||||
|
#define GAME_STATE_QUICKSAVEMANAGER_H
|
||||||
|
|
||||||
|
#include <string>
|
||||||
|
|
||||||
|
#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
|
|
@ -37,6 +37,8 @@
|
||||||
|
|
||||||
#include "../mwscript/globalscripts.hpp"
|
#include "../mwscript/globalscripts.hpp"
|
||||||
|
|
||||||
|
#include "quicksavemanager.hpp"
|
||||||
|
|
||||||
void MWState::StateManager::cleanup (bool force)
|
void MWState::StateManager::cleanup (bool force)
|
||||||
{
|
{
|
||||||
if (mState!=State_NoGame || force)
|
if (mState!=State_NoGame || force)
|
||||||
|
@ -324,20 +326,25 @@ void MWState::StateManager::quickSave (std::string name)
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
const Slot* slot = NULL;
|
int maxSaves = Settings::Manager::getInt("max quicksaves", "Saves");
|
||||||
Character* currentCharacter = getCurrentCharacter(); //Get current character
|
if(maxSaves < 1)
|
||||||
|
maxSaves = 1;
|
||||||
|
|
||||||
|
Character* currentCharacter = getCurrentCharacter(); //Get current character
|
||||||
|
QuickSaveManager saveFinder = QuickSaveManager(name, maxSaves);
|
||||||
|
|
||||||
//Find quicksave slot
|
|
||||||
if (currentCharacter)
|
if (currentCharacter)
|
||||||
{
|
{
|
||||||
for (Character::SlotIterator it = currentCharacter->begin(); it != currentCharacter->end(); ++it)
|
for (Character::SlotIterator it = currentCharacter->begin(); it != currentCharacter->end(); ++it)
|
||||||
{
|
{
|
||||||
if (it->mProfile.mDescription == name)
|
//Visiting slots allows the quicksave finder to find the oldest quicksave
|
||||||
slot = &*it;
|
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)
|
void MWState::StateManager::loadGame(const std::string& filepath)
|
||||||
|
|
|
@ -52,7 +52,7 @@ namespace MWWorld
|
||||||
playerRef->mBase->mClass
|
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);
|
npcStats.flagAsUsed (ref->mBase->mId);
|
||||||
}
|
}
|
||||||
|
|
|
@ -677,7 +677,6 @@ namespace MWWorld
|
||||||
if (mCell->mData.mFlags & ESM::Cell::Interior && mCell->mData.mFlags & ESM::Cell::HasWater)
|
if (mCell->mData.mFlags & ESM::Cell::Interior && mCell->mData.mFlags & ESM::Cell::HasWater)
|
||||||
mWaterLevel = state.mWaterLevel;
|
mWaterLevel = state.mWaterLevel;
|
||||||
|
|
||||||
mWaterLevel = state.mWaterLevel;
|
|
||||||
mLastRespawn = MWWorld::TimeStamp(state.mLastRespawn);
|
mLastRespawn = MWWorld::TimeStamp(state.mLastRespawn);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -688,7 +687,6 @@ namespace MWWorld
|
||||||
if (mCell->mData.mFlags & ESM::Cell::Interior && mCell->mData.mFlags & ESM::Cell::HasWater)
|
if (mCell->mData.mFlags & ESM::Cell::Interior && mCell->mData.mFlags & ESM::Cell::HasWater)
|
||||||
state.mWaterLevel = mWaterLevel;
|
state.mWaterLevel = mWaterLevel;
|
||||||
|
|
||||||
state.mWaterLevel = mWaterLevel;
|
|
||||||
state.mHasFogOfWar = (mFogState.get() ? 1 : 0);
|
state.mHasFogOfWar = (mFogState.get() ? 1 : 0);
|
||||||
state.mLastRespawn = mLastRespawn.toEsm();
|
state.mLastRespawn = mLastRespawn.toEsm();
|
||||||
}
|
}
|
||||||
|
|
|
@ -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::ContainerStoreIterator MWWorld::ContainerStore::add(const std::string &id, int count, const Ptr &actorPtr)
|
||||||
{
|
{
|
||||||
MWWorld::ManualRef ref(MWBase::Environment::get().getWorld()->getStore(), id, count);
|
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);
|
return add(ref.getPtr(), count, actorPtr, true);
|
||||||
else
|
|
||||||
return add(ref.getPtr(), count, actorPtr, false);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
MWWorld::ContainerStoreIterator MWWorld::ContainerStore::add (const Ptr& itemPtr, int count, const Ptr& actorPtr, bool setOwner)
|
MWWorld::ContainerStoreIterator MWWorld::ContainerStore::add (const Ptr& itemPtr, int count, const Ptr& actorPtr, bool setOwner)
|
||||||
|
|
|
@ -141,6 +141,7 @@ void ESMStore::setUp()
|
||||||
mMagicEffects.setUp();
|
mMagicEffects.setUp();
|
||||||
mAttributes.setUp();
|
mAttributes.setUp();
|
||||||
mDialogs.setUp();
|
mDialogs.setUp();
|
||||||
|
mStatics.setUp();
|
||||||
}
|
}
|
||||||
|
|
||||||
int ESMStore::countSavedGameRecords() const
|
int ESMStore::countSavedGameRecords() const
|
||||||
|
|
|
@ -48,6 +48,12 @@ void MWWorld::LiveCellRefBase::loadImp (const ESM::ObjectState& state)
|
||||||
}
|
}
|
||||||
|
|
||||||
mClass->readAdditionalState (ptr, state);
|
mClass->readAdditionalState (ptr, state);
|
||||||
|
|
||||||
|
if (!mRef.getSoul().empty() && !MWBase::Environment::get().getWorld()->getStore().get<ESM::Creature>().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
|
void MWWorld::LiveCellRefBase::saveImp (ESM::ObjectState& state) const
|
||||||
|
|
|
@ -47,37 +47,45 @@ namespace MWWorld
|
||||||
mPlayer.mData.setPosition(playerPos);
|
mPlayer.mData.setPosition(playerPos);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Player::saveSkillsAttributes()
|
void Player::saveStats()
|
||||||
{
|
{
|
||||||
MWMechanics::NpcStats& stats = getPlayer().getClass().getNpcStats(getPlayer());
|
MWMechanics::NpcStats& stats = getPlayer().getClass().getNpcStats(getPlayer());
|
||||||
|
|
||||||
for (int i=0; i<ESM::Skill::Length; ++i)
|
for (int i=0; i<ESM::Skill::Length; ++i)
|
||||||
mSaveSkills[i] = stats.getSkill(i);
|
mSaveSkills[i] = stats.getSkill(i);
|
||||||
for (int i=0; i<ESM::Attribute::Length; ++i)
|
for (int i=0; i<ESM::Attribute::Length; ++i)
|
||||||
mSaveAttributes[i] = stats.getAttribute(i);
|
mSaveAttributes[i] = stats.getAttribute(i);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Player::restoreSkillsAttributes()
|
void Player::restoreStats()
|
||||||
{
|
|
||||||
MWMechanics::NpcStats& stats = getPlayer().getClass().getNpcStats(getPlayer());
|
|
||||||
for (int i=0; i<ESM::Skill::Length; ++i)
|
|
||||||
stats.setSkill(i, mSaveSkills[i]);
|
|
||||||
for (int i=0; i<ESM::Attribute::Length; ++i)
|
|
||||||
stats.setAttribute(i, mSaveAttributes[i]);
|
|
||||||
}
|
|
||||||
|
|
||||||
void Player::setWerewolfSkillsAttributes()
|
|
||||||
{
|
{
|
||||||
const MWWorld::Store<ESM::GameSetting>& gmst = MWBase::Environment::get().getWorld()->getStore().get<ESM::GameSetting>();
|
const MWWorld::Store<ESM::GameSetting>& gmst = MWBase::Environment::get().getWorld()->getStore().get<ESM::GameSetting>();
|
||||||
MWMechanics::NpcStats& stats = getPlayer().getClass().getNpcStats(getPlayer());
|
MWMechanics::CreatureStats& creatureStats = getPlayer().getClass().getCreatureStats(getPlayer());
|
||||||
|
MWMechanics::NpcStats& npcStats = getPlayer().getClass().getNpcStats(getPlayer());
|
||||||
|
MWMechanics::DynamicStat<float> health = creatureStats.getDynamic(0);
|
||||||
|
creatureStats.setHealth(int(health.getBase() / gmst.find("fWereWolfHealth")->getFloat()));
|
||||||
|
for (int i=0; i<ESM::Skill::Length; ++i)
|
||||||
|
npcStats.setSkill(i, mSaveSkills[i]);
|
||||||
|
for (int i=0; i<ESM::Attribute::Length; ++i)
|
||||||
|
npcStats.setAttribute(i, mSaveAttributes[i]);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Player::setWerewolfStats()
|
||||||
|
{
|
||||||
|
const MWWorld::Store<ESM::GameSetting>& gmst = MWBase::Environment::get().getWorld()->getStore().get<ESM::GameSetting>();
|
||||||
|
MWMechanics::CreatureStats& creatureStats = getPlayer().getClass().getCreatureStats(getPlayer());
|
||||||
|
MWMechanics::NpcStats& npcStats = getPlayer().getClass().getNpcStats(getPlayer());
|
||||||
|
MWMechanics::DynamicStat<float> health = creatureStats.getDynamic(0);
|
||||||
|
creatureStats.setHealth(int(health.getBase() * gmst.find("fWereWolfHealth")->getFloat()));
|
||||||
for(size_t i = 0;i < ESM::Attribute::Length;++i)
|
for(size_t i = 0;i < ESM::Attribute::Length;++i)
|
||||||
{
|
{
|
||||||
// Oh, Bethesda. It's "Intelligence".
|
// Oh, Bethesda. It's "Intelligence".
|
||||||
std::string name = "fWerewolf"+((i==ESM::Attribute::Intelligence) ? std::string("Intellegence") :
|
std::string name = "fWerewolf"+((i==ESM::Attribute::Intelligence) ? std::string("Intellegence") :
|
||||||
ESM::Attribute::sAttributeNames[i]);
|
ESM::Attribute::sAttributeNames[i]);
|
||||||
|
|
||||||
MWMechanics::AttributeValue value = stats.getAttribute(i);
|
MWMechanics::AttributeValue value = npcStats.getAttribute(i);
|
||||||
value.setBase(int(gmst.find(name)->getFloat()));
|
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++)
|
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") :
|
std::string name = "fWerewolf"+((i==ESM::Skill::Mercantile) ? std::string("Merchantile") :
|
||||||
ESM::Skill::sSkillNames[i]);
|
ESM::Skill::sSkillNames[i]);
|
||||||
|
|
||||||
MWMechanics::SkillValue value = stats.getSkill(i);
|
MWMechanics::SkillValue value = npcStats.getSkill(i);
|
||||||
value.setBase(int(gmst.find(name)->getFloat()));
|
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)
|
if (player.mObject.mNpcStats.mWerewolfDeprecatedData && player.mObject.mNpcStats.mIsWerewolf)
|
||||||
{
|
{
|
||||||
saveSkillsAttributes();
|
saveStats();
|
||||||
setWerewolfSkillsAttributes();
|
setWerewolfStats();
|
||||||
}
|
}
|
||||||
|
|
||||||
getPlayer().getClass().getCreatureStats(getPlayer()).getAiSequence().clear();
|
getPlayer().getClass().getCreatureStats(getPlayer()).getAiSequence().clear();
|
||||||
|
|
|
@ -46,7 +46,7 @@ namespace MWWorld
|
||||||
int mCurrentCrimeId; // the id assigned witnesses
|
int mCurrentCrimeId; // the id assigned witnesses
|
||||||
int mPaidCrimeId; // the last id paid off (0 bounty)
|
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::SkillValue mSaveSkills[ESM::Skill::Length];
|
||||||
MWMechanics::AttributeValue mSaveAttributes[ESM::Attribute::Length];
|
MWMechanics::AttributeValue mSaveAttributes[ESM::Attribute::Length];
|
||||||
|
|
||||||
|
@ -56,9 +56,9 @@ namespace MWWorld
|
||||||
|
|
||||||
Player(const ESM::NPC *player);
|
Player(const ESM::NPC *player);
|
||||||
|
|
||||||
void saveSkillsAttributes();
|
void saveStats();
|
||||||
void restoreSkillsAttributes();
|
void restoreStats();
|
||||||
void setWerewolfSkillsAttributes();
|
void setWerewolfStats();
|
||||||
|
|
||||||
// For mark/recall magic effects
|
// For mark/recall magic effects
|
||||||
void markPosition (CellStore* markedCell, const ESM::Position& markedPosition);
|
void markPosition (CellStore* markedCell, const ESM::Position& markedPosition);
|
||||||
|
|
|
@ -79,6 +79,9 @@ namespace
|
||||||
|
|
||||||
if (ptr.getClass().isActor())
|
if (ptr.getClass().isActor())
|
||||||
rendering.addWaterRippleEmitter(ptr);
|
rendering.addWaterRippleEmitter(ptr);
|
||||||
|
|
||||||
|
// Restore effect particles
|
||||||
|
MWBase::Environment::get().getWorld()->applyLoopingParticles(ptr);
|
||||||
}
|
}
|
||||||
|
|
||||||
void updateObjectRotation (const MWWorld::Ptr& ptr, MWPhysics::PhysicsSystem& physics,
|
void updateObjectRotation (const MWWorld::Ptr& ptr, MWPhysics::PhysicsSystem& physics,
|
||||||
|
@ -457,7 +460,6 @@ namespace MWWorld
|
||||||
float z = pos.rot[2];
|
float z = pos.rot[2];
|
||||||
world->rotateObject(player, x, y, z);
|
world->rotateObject(player, x, y, z);
|
||||||
|
|
||||||
if (adjustPlayerPos)
|
|
||||||
player.getClass().adjustPosition(player, true);
|
player.getClass().adjustPosition(player, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -592,7 +592,7 @@ namespace MWWorld
|
||||||
const ESM::Cell *ptr = search(id);
|
const ESM::Cell *ptr = search(id);
|
||||||
if (ptr == 0) {
|
if (ptr == 0) {
|
||||||
std::ostringstream msg;
|
std::ostringstream msg;
|
||||||
msg << "Interior cell '" << id << "' not found";
|
msg << "Cell '" << id << "' not found";
|
||||||
throw std::runtime_error(msg.str());
|
throw std::runtime_error(msg.str());
|
||||||
}
|
}
|
||||||
return ptr;
|
return ptr;
|
||||||
|
@ -1053,6 +1053,32 @@ namespace MWWorld
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
template<>
|
||||||
|
void Store<ESM::Static>::setUp()
|
||||||
|
{
|
||||||
|
// Load default marker definitions, if game files do not have them for some reason
|
||||||
|
std::pair<std::string, std::string> 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<std::string, std::string> marker : markers)
|
||||||
|
{
|
||||||
|
if (search(marker.first) == 0)
|
||||||
|
{
|
||||||
|
ESM::Static newMarker = ESM::Static(marker.first, marker.second);
|
||||||
|
std::pair<typename Static::iterator, bool> ret = mStatic.insert(std::make_pair(marker.first, newMarker));
|
||||||
|
if (ret.first != mStatic.end())
|
||||||
|
{
|
||||||
|
mShared.push_back(&ret.first->second);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
template <>
|
template <>
|
||||||
inline RecordId Store<ESM::Dialogue>::load(ESM::ESMReader &esm) {
|
inline RecordId Store<ESM::Dialogue>::load(ESM::ESMReader &esm) {
|
||||||
// The original letter case of a dialogue ID is saved, because it's printed
|
// The original letter case of a dialogue ID is saved, because it's printed
|
||||||
|
|
|
@ -9,7 +9,6 @@
|
||||||
#include <components/fallback/fallback.hpp>
|
#include <components/fallback/fallback.hpp>
|
||||||
|
|
||||||
#include "../mwbase/environment.hpp"
|
#include "../mwbase/environment.hpp"
|
||||||
#include "../mwbase/world.hpp"
|
|
||||||
#include "../mwbase/soundmanager.hpp"
|
#include "../mwbase/soundmanager.hpp"
|
||||||
|
|
||||||
#include "../mwmechanics/actorutil.hpp"
|
#include "../mwmechanics/actorutil.hpp"
|
||||||
|
@ -103,6 +102,8 @@ Weather::Weather(const std::string& name,
|
||||||
const Fallback::Map& fallback,
|
const Fallback::Map& fallback,
|
||||||
float stormWindSpeed,
|
float stormWindSpeed,
|
||||||
float rainSpeed,
|
float rainSpeed,
|
||||||
|
float dlFactor,
|
||||||
|
float dlOffset,
|
||||||
const std::string& particleEffect)
|
const std::string& particleEffect)
|
||||||
: mCloudTexture(fallback.getFallbackString("Weather_" + name + "_Cloud_Texture"))
|
: mCloudTexture(fallback.getFallbackString("Weather_" + name + "_Cloud_Texture"))
|
||||||
, mSkyColor(fallback.getFallbackColour("Weather_" + name +"_Sky_Sunrise_Color"),
|
, 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"))
|
, mFlashDecrement(fallback.getFallbackFloat("Weather_" + name + "_Flash_Decrement"))
|
||||||
, mFlashBrightness(0.0f)
|
, mFlashBrightness(0.0f)
|
||||||
{
|
{
|
||||||
|
mDL.FogFactor = dlFactor;
|
||||||
|
mDL.FogOffset = dlOffset;
|
||||||
mThunderSoundID[0] = fallback.getFallbackString("Weather_" + name + "_Thunder_Sound_ID_0");
|
mThunderSoundID[0] = fallback.getFallbackString("Weather_" + name + "_Thunder_Sound_ID_0");
|
||||||
mThunderSoundID[1] = fallback.getFallbackString("Weather_" + name + "_Thunder_Sound_ID_1");
|
mThunderSoundID[1] = fallback.getFallbackString("Weather_" + name + "_Thunder_Sound_ID_1");
|
||||||
mThunderSoundID[2] = fallback.getFallbackString("Weather_" + name + "_Thunder_Sound_ID_2");
|
mThunderSoundID[2] = fallback.getFallbackString("Weather_" + name + "_Thunder_Sound_ID_2");
|
||||||
|
@ -520,6 +523,7 @@ WeatherManager::WeatherManager(MWRender::RenderingManager& rendering, const Fall
|
||||||
, mSecunda("Secunda", fallback)
|
, mSecunda("Secunda", fallback)
|
||||||
, mWindSpeed(0.f)
|
, mWindSpeed(0.f)
|
||||||
, mIsStorm(false)
|
, mIsStorm(false)
|
||||||
|
, mPrecipitation(false)
|
||||||
, mStormDirection(0,1,0)
|
, mStormDirection(0,1,0)
|
||||||
, mCurrentRegion()
|
, mCurrentRegion()
|
||||||
, mTimePassed(0)
|
, mTimePassed(0)
|
||||||
|
@ -541,16 +545,18 @@ WeatherManager::WeatherManager(MWRender::RenderingManager& rendering, const Fall
|
||||||
mTimeSettings.mSunriseTime = mSunriseTime;
|
mTimeSettings.mSunriseTime = mSunriseTime;
|
||||||
|
|
||||||
mWeatherSettings.reserve(10);
|
mWeatherSettings.reserve(10);
|
||||||
addWeather("Clear", fallback); // 0
|
// These distant land fog factor and offset values are the defaults MGE XE provides. Should be
|
||||||
addWeather("Cloudy", fallback); // 1
|
// provided by settings somewhere?
|
||||||
addWeather("Foggy", fallback); // 2
|
addWeather("Clear", fallback, 1.0f, 0.0f); // 0
|
||||||
addWeather("Overcast", fallback); // 3
|
addWeather("Cloudy", fallback, 0.9f, 0.0f); // 1
|
||||||
addWeather("Rain", fallback); // 4
|
addWeather("Foggy", fallback, 0.2f, 30.0f); // 2
|
||||||
addWeather("Thunderstorm", fallback); // 5
|
addWeather("Overcast", fallback, 0.7f, 0.0f); // 3
|
||||||
addWeather("Ashstorm", fallback, "meshes\\ashcloud.nif"); // 6
|
addWeather("Rain", fallback, 0.5f, 10.0f); // 4
|
||||||
addWeather("Blight", fallback, "meshes\\blightcloud.nif"); // 7
|
addWeather("Thunderstorm", fallback, 0.5f, 20.0f); // 5
|
||||||
addWeather("Snow", fallback, "meshes\\snow.nif"); // 8
|
addWeather("Ashstorm", fallback, 0.2f, 50.0f, "meshes\\ashcloud.nif"); // 6
|
||||||
addWeather("Blizzard", fallback, "meshes\\blizzard.nif"); // 9
|
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<ESM::Region>::iterator it = store.get<ESM::Region>().begin();
|
Store<ESM::Region>::iterator it = store.get<ESM::Region>().begin();
|
||||||
for(; it != store.get<ESM::Region>().end(); ++it)
|
for(; it != store.get<ESM::Region>().end(); ++it)
|
||||||
|
@ -608,14 +614,11 @@ void WeatherManager::modRegion(const std::string& regionID, const std::vector<ch
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void WeatherManager::playerTeleported()
|
void WeatherManager::playerTeleported(const std::string& playerRegion, bool isExterior)
|
||||||
{
|
{
|
||||||
// If the player teleports to an outdoors cell in a new region (for instance, by travelling), the weather needs to
|
// If the player teleports to an outdoors cell in a new region (for instance, by travelling), the weather needs to
|
||||||
// be changed immediately, and any transitions for the previous region discarded.
|
// be changed immediately, and any transitions for the previous region discarded.
|
||||||
MWBase::World* world = MWBase::Environment::get().getWorld();
|
|
||||||
if(world->isCellExterior() || world->isCellQuasiExterior())
|
|
||||||
{
|
{
|
||||||
std::string playerRegion = Misc::StringUtils::lowerCase(world->getPlayerPtr().getCell()->getCell()->mRegion);
|
|
||||||
std::map<std::string, RegionWeather>::iterator it = mRegions.find(playerRegion);
|
std::map<std::string, RegionWeather>::iterator it = mRegions.find(playerRegion);
|
||||||
if(it != mRegions.end() && playerRegion != mCurrentRegion)
|
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();
|
MWWorld::ConstPtr player = MWMechanics::getPlayer();
|
||||||
MWBase::World& world = *MWBase::Environment::get().getWorld();
|
|
||||||
TimeStamp time = world.getTimeStamp();
|
|
||||||
|
|
||||||
if(!paused || mFastForward)
|
if(!paused || mFastForward)
|
||||||
{
|
{
|
||||||
|
@ -647,8 +648,7 @@ void WeatherManager::update(float duration, bool paused)
|
||||||
updateWeatherTransitions(duration);
|
updateWeatherTransitions(duration);
|
||||||
}
|
}
|
||||||
|
|
||||||
const bool exterior = (world.isCellExterior() || world.isCellQuasiExterior());
|
if(!isExterior)
|
||||||
if(!exterior)
|
|
||||||
{
|
{
|
||||||
mRendering.setSkyEnabled(false);
|
mRendering.setSkyEnabled(false);
|
||||||
stopSounds();
|
stopSounds();
|
||||||
|
@ -660,6 +660,10 @@ void WeatherManager::update(float duration, bool paused)
|
||||||
mWindSpeed = mResult.mWindSpeed;
|
mWindSpeed = mResult.mWindSpeed;
|
||||||
mIsStorm = mResult.mIsStorm;
|
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)
|
if (mIsStorm)
|
||||||
{
|
{
|
||||||
osg::Vec3f playerPos (player.getRefData().getPosition().asVec3());
|
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()->setMasserState(mMasser.calculateState(time));
|
||||||
mRendering.getSkyManager()->setSecundaState(mSecunda.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.setAmbientColour(mResult.mAmbientColor);
|
||||||
mRendering.setSunColour(mResult.mSunColor, mResult.mSunColor * mResult.mGlareView);
|
mRendering.setSunColour(mResult.mSunColor, mResult.mSunColor * mResult.mGlareView);
|
||||||
|
|
||||||
|
@ -777,12 +782,11 @@ unsigned int WeatherManager::getWeatherID() const
|
||||||
return mCurrentWeather;
|
return mCurrentWeather;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool WeatherManager::isDark() const
|
bool WeatherManager::useTorches(float hour) const
|
||||||
{
|
{
|
||||||
TimeStamp time = MWBase::Environment::get().getWorld()->getTimeStamp();
|
bool isDark = hour < mSunriseTime || hour > mTimeSettings.mNightStart - 1;
|
||||||
bool exterior = (MWBase::Environment::get().getWorld()->isCellExterior()
|
|
||||||
|| MWBase::Environment::get().getWorld()->isCellQuasiExterior());
|
return isDark && !mPrecipitation;
|
||||||
return exterior && (time.getHour() < mSunriseTime || time.getHour() > mTimeSettings.mNightStart - 1);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void WeatherManager::write(ESM::ESMWriter& writer, Loading::Listener& progress)
|
void WeatherManager::write(ESM::ESMWriter& writer, Loading::Listener& progress)
|
||||||
|
@ -866,11 +870,12 @@ void WeatherManager::clear()
|
||||||
|
|
||||||
inline void WeatherManager::addWeather(const std::string& name,
|
inline void WeatherManager::addWeather(const std::string& name,
|
||||||
const Fallback::Map& fallback,
|
const Fallback::Map& fallback,
|
||||||
|
float dlFactor, float dlOffset,
|
||||||
const std::string& particleEffect)
|
const std::string& particleEffect)
|
||||||
{
|
{
|
||||||
static const float fStromWindSpeed = mStore.get<ESM::GameSetting>().find("fStromWindSpeed")->getFloat();
|
static const float fStromWindSpeed = mStore.get<ESM::GameSetting>().find("fStromWindSpeed")->getFloat();
|
||||||
|
|
||||||
Weather weather(name, fallback, fStromWindSpeed, mRainSpeed, particleEffect);
|
Weather weather(name, fallback, fStromWindSpeed, mRainSpeed, dlFactor, dlOffset, particleEffect);
|
||||||
|
|
||||||
mWeatherSettings.push_back(weather);
|
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.mNight = (gameHour < mSunriseTime || gameHour > mTimeSettings.mNightStart - 1);
|
||||||
|
|
||||||
mResult.mFogDepth = current.mLandFogDepth.getValue(gameHour, mTimeSettings);
|
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.mFogColor = current.mFogColor.getValue(gameHour, mTimeSettings);
|
||||||
mResult.mAmbientColor = current.mAmbientColor.getValue(gameHour, mTimeSettings);
|
mResult.mAmbientColor = current.mAmbientColor.getValue(gameHour, mTimeSettings);
|
||||||
mResult.mSunColor = current.mSunColor.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.mAmbientColor = lerp(current.mAmbientColor, other.mAmbientColor, factor);
|
||||||
mResult.mSunDiscColor = lerp(current.mSunDiscColor, other.mSunDiscColor, factor);
|
mResult.mSunDiscColor = lerp(current.mSunDiscColor, other.mSunDiscColor, factor);
|
||||||
mResult.mFogDepth = lerp(current.mFogDepth, other.mFogDepth, 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.mWindSpeed = lerp(current.mWindSpeed, other.mWindSpeed, factor);
|
||||||
mResult.mCloudSpeed = lerp(current.mCloudSpeed, other.mCloudSpeed, factor);
|
mResult.mCloudSpeed = lerp(current.mCloudSpeed, other.mCloudSpeed, factor);
|
||||||
mResult.mGlareView = lerp(current.mGlareView, other.mGlareView, 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.mIsStorm = current.mIsStorm;
|
||||||
mResult.mParticleEffect = current.mParticleEffect;
|
mResult.mParticleEffect = current.mParticleEffect;
|
||||||
mResult.mRainEffect = current.mRainEffect;
|
mResult.mRainEffect = current.mRainEffect;
|
||||||
mResult.mParticleEffect = current.mParticleEffect;
|
|
||||||
mResult.mRainSpeed = current.mRainSpeed;
|
mResult.mRainSpeed = current.mRainSpeed;
|
||||||
mResult.mRainFrequency = current.mRainFrequency;
|
mResult.mRainFrequency = current.mRainFrequency;
|
||||||
mResult.mAmbientSoundVolume = 1-(factor*2);
|
mResult.mAmbientSoundVolume = 1-(factor*2);
|
||||||
|
@ -1137,7 +1145,6 @@ inline void WeatherManager::calculateTransitionResult(const float factor, const
|
||||||
mResult.mIsStorm = other.mIsStorm;
|
mResult.mIsStorm = other.mIsStorm;
|
||||||
mResult.mParticleEffect = other.mParticleEffect;
|
mResult.mParticleEffect = other.mParticleEffect;
|
||||||
mResult.mRainEffect = other.mRainEffect;
|
mResult.mRainEffect = other.mRainEffect;
|
||||||
mResult.mParticleEffect = other.mParticleEffect;
|
|
||||||
mResult.mRainSpeed = other.mRainSpeed;
|
mResult.mRainSpeed = other.mRainSpeed;
|
||||||
mResult.mRainFrequency = other.mRainFrequency;
|
mResult.mRainFrequency = other.mRainFrequency;
|
||||||
mResult.mAmbientSoundVolume = 2*(factor-0.5f);
|
mResult.mAmbientSoundVolume = 2*(factor-0.5f);
|
||||||
|
|
|
@ -73,6 +73,8 @@ namespace MWWorld
|
||||||
const Fallback::Map& fallback,
|
const Fallback::Map& fallback,
|
||||||
float stormWindSpeed,
|
float stormWindSpeed,
|
||||||
float rainSpeed,
|
float rainSpeed,
|
||||||
|
float dlFactor,
|
||||||
|
float dlOffset,
|
||||||
const std::string& particleEffect);
|
const std::string& particleEffect);
|
||||||
|
|
||||||
std::string mCloudTexture;
|
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.
|
// Also appears to modify how visible the sun, moons, and stars are for various weather effects.
|
||||||
float mGlareView;
|
float mGlareView;
|
||||||
|
|
||||||
|
// Fog factor and offset used with distant land rendering.
|
||||||
|
struct {
|
||||||
|
float FogFactor;
|
||||||
|
float FogOffset;
|
||||||
|
} mDL;
|
||||||
|
|
||||||
// Sound effect
|
// Sound effect
|
||||||
// This is used for Blight, Ashstorm and Blizzard (Bloodmoon)
|
// This is used for Blight, Ashstorm and Blizzard (Bloodmoon)
|
||||||
std::string mAmbientLoopSoundID;
|
std::string mAmbientLoopSoundID;
|
||||||
|
@ -218,14 +226,14 @@ namespace MWWorld
|
||||||
*/
|
*/
|
||||||
void changeWeather(const std::string& regionID, const unsigned int weatherID);
|
void changeWeather(const std::string& regionID, const unsigned int weatherID);
|
||||||
void modRegion(const std::string& regionID, const std::vector<char>& chances);
|
void modRegion(const std::string& regionID, const std::vector<char>& chances);
|
||||||
void playerTeleported();
|
void playerTeleported(const std::string& playerRegion, bool isExterior);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Per-frame update
|
* Per-frame update
|
||||||
* @param duration
|
* @param duration
|
||||||
* @param paused
|
* @param paused
|
||||||
*/
|
*/
|
||||||
void update(float duration, bool paused = false);
|
void update(float duration, bool paused, const TimeStamp& time, bool isExterior);
|
||||||
|
|
||||||
void stopSounds();
|
void stopSounds();
|
||||||
|
|
||||||
|
@ -240,8 +248,7 @@ namespace MWWorld
|
||||||
|
|
||||||
unsigned int getWeatherID() const;
|
unsigned int getWeatherID() const;
|
||||||
|
|
||||||
/// @see World::isDark
|
bool useTorches(float hour) const;
|
||||||
bool isDark() const;
|
|
||||||
|
|
||||||
void write(ESM::ESMWriter& writer, Loading::Listener& progress);
|
void write(ESM::ESMWriter& writer, Loading::Listener& progress);
|
||||||
|
|
||||||
|
@ -275,6 +282,7 @@ namespace MWWorld
|
||||||
|
|
||||||
float mWindSpeed;
|
float mWindSpeed;
|
||||||
bool mIsStorm;
|
bool mIsStorm;
|
||||||
|
bool mPrecipitation;
|
||||||
osg::Vec3f mStormDirection;
|
osg::Vec3f mStormDirection;
|
||||||
|
|
||||||
std::string mCurrentRegion;
|
std::string mCurrentRegion;
|
||||||
|
@ -293,6 +301,7 @@ namespace MWWorld
|
||||||
|
|
||||||
void addWeather(const std::string& name,
|
void addWeather(const std::string& name,
|
||||||
const Fallback::Map& fallback,
|
const Fallback::Map& fallback,
|
||||||
|
float dlFactor, float dlOffset,
|
||||||
const std::string& particleEffect = "");
|
const std::string& particleEffect = "");
|
||||||
|
|
||||||
void importRegions();
|
void importRegions();
|
||||||
|
|
|
@ -406,7 +406,6 @@ namespace MWWorld
|
||||||
gmst["sCompanionWarningMessage"] = ESM::Variant("Warning message");
|
gmst["sCompanionWarningMessage"] = ESM::Variant("Warning message");
|
||||||
gmst["sCompanionWarningButtonOne"] = ESM::Variant("Button 1");
|
gmst["sCompanionWarningButtonOne"] = ESM::Variant("Button 1");
|
||||||
gmst["sCompanionWarningButtonTwo"] = ESM::Variant("Button 2");
|
gmst["sCompanionWarningButtonTwo"] = ESM::Variant("Button 2");
|
||||||
gmst["sCompanionShare"] = ESM::Variant("Companion Share");
|
|
||||||
gmst["sProfitValue"] = ESM::Variant("Profit Value");
|
gmst["sProfitValue"] = ESM::Variant("Profit Value");
|
||||||
gmst["sTeleportDisabled"] = ESM::Variant("Teleport disabled");
|
gmst["sTeleportDisabled"] = ESM::Variant("Teleport disabled");
|
||||||
gmst["sLevitateDisabled"] = ESM::Variant("Levitate disabled");
|
gmst["sLevitateDisabled"] = ESM::Variant("Levitate disabled");
|
||||||
|
@ -2244,6 +2243,8 @@ namespace MWWorld
|
||||||
model = Misc::ResourceHelpers::correctActorModelPath(model, mResourceSystem->getVFS());
|
model = Misc::ResourceHelpers::correctActorModelPath(model, mResourceSystem->getVFS());
|
||||||
mPhysics->remove(getPlayerPtr());
|
mPhysics->remove(getPlayerPtr());
|
||||||
mPhysics->addActor(getPlayerPtr(), model);
|
mPhysics->addActor(getPlayerPtr(), model);
|
||||||
|
|
||||||
|
applyLoopingParticles(player);
|
||||||
}
|
}
|
||||||
|
|
||||||
int World::canRest ()
|
int World::canRest ()
|
||||||
|
@ -2831,6 +2832,19 @@ namespace MWWorld
|
||||||
mProjectileManager->launchMagicBolt(spellId, caster, fallbackDirection);
|
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<std::string>& World::getContentFiles() const
|
const std::vector<std::string>& World::getContentFiles() const
|
||||||
{
|
{
|
||||||
return mContentFiles;
|
return mContentFiles;
|
||||||
|
@ -2847,11 +2861,17 @@ namespace MWWorld
|
||||||
MWBase::Environment::get().getMechanicsManager()->updateMagicEffects(actor);
|
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();
|
MWWorld::CellStore* cell = mPlayer->getPlayer().getCell();
|
||||||
if (cell->isExterior())
|
if (cell->isExterior())
|
||||||
return mWeatherManager->isDark();
|
{
|
||||||
|
float hour = getTimeStamp().getHour();
|
||||||
|
return mWeatherManager->useTorches(hour);
|
||||||
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
uint32_t ambient = cell->getCell()->mAmbi.mAmbient;
|
uint32_t ambient = cell->getCell()->mAmbi.mAmbient;
|
||||||
|
@ -3012,13 +3032,17 @@ namespace MWWorld
|
||||||
|
|
||||||
void World::updateWeather(float duration, bool paused)
|
void World::updateWeather(float duration, bool paused)
|
||||||
{
|
{
|
||||||
|
bool isExterior = isCellExterior() || isCellQuasiExterior();
|
||||||
if (mPlayer->wasTeleported())
|
if (mPlayer->wasTeleported())
|
||||||
{
|
{
|
||||||
mPlayer->setTeleported(false);
|
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
|
struct AddDetectedReferenceVisitor
|
||||||
|
|
|
@ -604,12 +604,13 @@ namespace MWWorld
|
||||||
void launchProjectile (MWWorld::Ptr actor, MWWorld::ConstPtr projectile,
|
void launchProjectile (MWWorld::Ptr actor, MWWorld::ConstPtr projectile,
|
||||||
const osg::Vec3f& worldPos, const osg::Quat& orient, MWWorld::Ptr bow, float speed, float attackStrength) override;
|
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<std::string>& getContentFiles() const override;
|
const std::vector<std::string>& getContentFiles() const override;
|
||||||
|
|
||||||
void breakInvisibility (const MWWorld::Ptr& actor) 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;
|
bool findInteriorPositionInWorldSpace(const MWWorld::CellStore* cell, osg::Vec3f& result) override;
|
||||||
|
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
find_package(GTest REQUIRED)
|
find_package(GTest REQUIRED)
|
||||||
|
|
||||||
if (GTEST_FOUND)
|
if (GTEST_FOUND)
|
||||||
include_directories(${GTEST_INCLUDE_DIRS})
|
include_directories(SYSTEM ${GTEST_INCLUDE_DIRS})
|
||||||
|
|
||||||
file(GLOB UNITTEST_SRC_FILES
|
file(GLOB UNITTEST_SRC_FILES
|
||||||
../openmw/mwworld/store.cpp
|
../openmw/mwworld/store.cpp
|
||||||
|
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Reference in a new issue