mirror of
https://github.com/OpenMW/openmw.git
synced 2025-03-03 02:09:41 +00:00
Merge remote-tracking branch 'upstream/master' into detain-hash-selectively-reluctant
Merge conflicts included: * One setting being removed (branch had changed its type). * One setting's description being changed (branch had changed its type). * List of files in components/files was changed both upstream and on the branch. * Upstream had changed something in a file the branch deletes.
This commit is contained in:
commit
8fc09f8c51
727 changed files with 22674 additions and 11072 deletions
67
.github/workflows/cmake.yml
vendored
67
.github/workflows/cmake.yml
vendored
|
@ -8,7 +8,7 @@ env:
|
|||
BUILD_TYPE: RelWithDebInfo
|
||||
|
||||
jobs:
|
||||
build:
|
||||
Ubuntu:
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
steps:
|
||||
|
@ -26,25 +26,62 @@ jobs:
|
|||
key: ${{ matrix.os }}-${{ env.BUILD_TYPE }}
|
||||
max-size: 1000M
|
||||
|
||||
- name: Install gtest
|
||||
run: |
|
||||
export CONFIGURATION="Release"
|
||||
export GOOGLETEST_DIR="."
|
||||
export GENERATOR="Unix Makefiles"
|
||||
export CC="gcc"
|
||||
export CXX="g++"
|
||||
sudo -E CI/build_googletest.sh
|
||||
|
||||
- name: Configure
|
||||
run: cmake -S . -B . -DCMAKE_BUILD_TYPE=${{env.BUILD_TYPE}} -DCMAKE_INSTALL_PREFIX=./install -DCMAKE_C_COMPILER_LAUNCHER=ccache -DCMAKE_CXX_COMPILER_LAUNCHER=ccache -DCMAKE_C_FLAGS='-Werror' -DCMAKE_CXX_FLAGS="-Werror -Wno-error=deprecated-declarations -Wno-error=nonnull -Wno-error=deprecated-copy"
|
||||
run: cmake -S . -B . -DGTEST_ROOT="$(pwd)/googletest/build" -DGMOCK_ROOT="$(pwd)/googletest/build" -DBUILD_UNITTESTS=ON -DCMAKE_BUILD_TYPE=${{env.BUILD_TYPE}} -DCMAKE_INSTALL_PREFIX=./install -DCMAKE_C_COMPILER_LAUNCHER=ccache -DCMAKE_CXX_COMPILER_LAUNCHER=ccache -DCMAKE_C_FLAGS='-Werror' -DCMAKE_CXX_FLAGS="-Werror -Wno-error=deprecated-declarations -Wno-error=nonnull -Wno-error=deprecated-copy"
|
||||
|
||||
- name: Build
|
||||
run: cmake --build . --config ${{env.BUILD_TYPE}} --parallel 3
|
||||
|
||||
- name: Install
|
||||
shell: bash
|
||||
run: cmake --install .
|
||||
- name: Test
|
||||
run: ./openmw_test_suite
|
||||
|
||||
# - name: Install
|
||||
# shell: bash
|
||||
# run: cmake --install .
|
||||
|
||||
- name: Create Artifact
|
||||
shell: bash
|
||||
working-directory: install
|
||||
run: |
|
||||
ls -laR
|
||||
7z a ../build_artifact.7z .
|
||||
# - name: Create Artifact
|
||||
# shell: bash
|
||||
# working-directory: install
|
||||
# run: |
|
||||
# ls -laR
|
||||
# 7z a ../build_artifact.7z .
|
||||
|
||||
- name: Upload Artifact
|
||||
uses: actions/upload-artifact@v1
|
||||
# - name: Upload Artifact
|
||||
# uses: actions/upload-artifact@v1
|
||||
# with:
|
||||
# path: ./build_artifact.7z
|
||||
# name: build_artifact.7z
|
||||
|
||||
MacOS:
|
||||
runs-on: macos-latest
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
|
||||
- name: Install Building Dependancies
|
||||
run: CI/before_install.osx.sh
|
||||
|
||||
- name: Prime ccache
|
||||
uses: hendrikmuhs/ccache-action@v1
|
||||
with:
|
||||
path: ./build_artifact.7z
|
||||
name: build_artifact.7z
|
||||
key: ${{ matrix.os }}-${{ env.BUILD_TYPE }}
|
||||
max-size: 1000M
|
||||
|
||||
- name: Configure
|
||||
run: |
|
||||
rm -fr build # remove the build directory
|
||||
CI/before_script.osx.sh
|
||||
|
||||
- name: Build
|
||||
run: |
|
||||
cd build
|
||||
make -j $(sysctl -n hw.logicalcpu) package
|
||||
|
|
153
.gitlab-ci.yml
153
.gitlab-ci.yml
|
@ -3,14 +3,17 @@
|
|||
stages:
|
||||
- build
|
||||
|
||||
.Debian_Image:
|
||||
.Ubuntu_Image:
|
||||
tags:
|
||||
- docker
|
||||
- linux
|
||||
image: debian:bullseye
|
||||
image: ubuntu:focal
|
||||
rules:
|
||||
- if: $CI_PIPELINE_SOURCE == "push"
|
||||
|
||||
|
||||
.Debian:
|
||||
extends: .Debian_Image
|
||||
.Ubuntu:
|
||||
extends: .Ubuntu_Image
|
||||
cache:
|
||||
paths:
|
||||
- apt-cache/
|
||||
|
@ -32,11 +35,12 @@ stages:
|
|||
- build/install/
|
||||
|
||||
Clang_Tidy:
|
||||
extends: .Debian_Image
|
||||
extends: .Ubuntu_Image
|
||||
stage: build
|
||||
rules:
|
||||
- if: '$CI_PIPELINE_SOURCE == "schedule"'
|
||||
before_script:
|
||||
- apt-get update; apt-get -y install software-properties-common; add-apt-repository -y ppa:openmw/openmw
|
||||
- CI/install_debian_deps.sh gcc openmw-deps openmw-deps-dynamic clang-tidy clang
|
||||
script:
|
||||
- CI/before_script.linux.sh
|
||||
|
@ -47,13 +51,17 @@ Clang_Tidy:
|
|||
CXX: clang++
|
||||
CI_CLANG_TIDY: 1
|
||||
timeout: 8h
|
||||
artifacts:
|
||||
paths: []
|
||||
expire_in: 1 minute
|
||||
|
||||
Coverity:
|
||||
extends: .Debian_Image
|
||||
extends: .Ubuntu_Image
|
||||
stage: build
|
||||
rules:
|
||||
- if: '$CI_PIPELINE_SOURCE == "schedule"'
|
||||
- if: $CI_PIPELINE_SOURCE == "schedule"
|
||||
before_script:
|
||||
- apt-get update; apt-get -y install software-properties-common; add-apt-repository -y ppa:openmw/openmw
|
||||
- CI/install_debian_deps.sh gcc openmw-deps openmw-deps-dynamic coverity
|
||||
- curl -o /tmp/cov-analysis-linux64.tgz https://scan.coverity.com/download/linux64 --form project=$COVERITY_SCAN_PROJECT_NAME --form token=$COVERITY_SCAN_TOKEN
|
||||
- tar xfz /tmp/cov-analysis-linux64.tgz
|
||||
|
@ -67,16 +75,20 @@ Coverity:
|
|||
--form token=$COVERITY_SCAN_TOKEN --form email=$GITLAB_USER_EMAIL
|
||||
--form file=@cov-int.tar.gz --form version="`git describe --tags`"
|
||||
--form description="`git describe --tags` / $CI_COMMIT_TITLE / $CI_COMMIT_REF_NAME:$CI_PIPELINE_ID"
|
||||
- cat /builds/OpenMW/openmw/cov-int/build-log.txt
|
||||
variables:
|
||||
CC: gcc
|
||||
CXX: g++
|
||||
artifacts:
|
||||
paths: []
|
||||
expire_in: 1 minute
|
||||
|
||||
Debian_GCC:
|
||||
extends: .Debian
|
||||
Ubuntu_GCC:
|
||||
extends: .Ubuntu
|
||||
cache:
|
||||
key: Debian_GCC.v2
|
||||
key: Ubuntu_GCC.v2
|
||||
before_script:
|
||||
- apt-get update; apt-get -y install software-properties-common; add-apt-repository -y ppa:openmw/openmw
|
||||
- CI/install_debian_deps.sh gcc openmw-deps openmw-deps-dynamic
|
||||
variables:
|
||||
CC: gcc
|
||||
|
@ -85,51 +97,62 @@ Debian_GCC:
|
|||
# When CCache doesn't exist (e.g. first build on a fork), build takes more than 1h, which is the default for forks.
|
||||
timeout: 2h
|
||||
|
||||
Debian_GCC_tests:
|
||||
extends: Debian_GCC
|
||||
Ubuntu_GCC_tests:
|
||||
extends: Ubuntu_GCC
|
||||
cache:
|
||||
key: Debian_GCC_tests.v2
|
||||
key: Ubuntu_GCC_tests.v2
|
||||
variables:
|
||||
CCACHE_SIZE: 1G
|
||||
BUILD_TESTS_ONLY: 1
|
||||
artifacts:
|
||||
paths: []
|
||||
expire_in: 1 minute
|
||||
|
||||
Debian_GCC_tests_Debug:
|
||||
extends: Debian_GCC
|
||||
Ubuntu_GCC_tests_Debug:
|
||||
extends: Ubuntu_GCC
|
||||
cache:
|
||||
key: Debian_GCC_tests_Debug.v1
|
||||
key: Ubuntu_GCC_tests_Debug.v1
|
||||
variables:
|
||||
CCACHE_SIZE: 1G
|
||||
BUILD_TESTS_ONLY: 1
|
||||
CMAKE_BUILD_TYPE: Debug
|
||||
artifacts:
|
||||
paths: []
|
||||
expire_in: 1 minute
|
||||
|
||||
Debian_GCC_Static_Deps:
|
||||
extends: Debian_GCC
|
||||
Ubuntu_GCC_Static_Deps:
|
||||
extends: Ubuntu_GCC
|
||||
cache:
|
||||
key: Debian_GCC_Static_Deps
|
||||
key: Ubuntu_GCC_Static_Deps
|
||||
paths:
|
||||
- apt-cache/
|
||||
- ccache/
|
||||
- build/extern/fetched/
|
||||
before_script:
|
||||
- apt-get update; apt-get -y install software-properties-common; add-apt-repository -y ppa:openmw/openmw
|
||||
- CI/install_debian_deps.sh gcc openmw-deps openmw-deps-static
|
||||
variables:
|
||||
CI_OPENMW_USE_STATIC_DEPS: 1
|
||||
timeout: 3h
|
||||
|
||||
Debian_GCC_Static_Deps_tests:
|
||||
extends: Debian_GCC_Static_Deps
|
||||
Ubuntu_GCC_Static_Deps_tests:
|
||||
extends: Ubuntu_GCC_Static_Deps
|
||||
cache:
|
||||
key: Debian_GCC_Static_Deps_tests
|
||||
key: Ubuntu_GCC_Static_Deps_tests
|
||||
variables:
|
||||
CCACHE_SIZE: 1G
|
||||
BUILD_TESTS_ONLY: 1
|
||||
artifacts:
|
||||
paths: []
|
||||
expire_in: 1 minute
|
||||
|
||||
Debian_Clang:
|
||||
extends: .Debian
|
||||
Ubuntu_Clang:
|
||||
extends: .Ubuntu
|
||||
before_script:
|
||||
- apt-get update; apt-get -y install software-properties-common; add-apt-repository -y ppa:openmw/openmw
|
||||
- CI/install_debian_deps.sh clang openmw-deps openmw-deps-dynamic
|
||||
cache:
|
||||
key: Debian_Clang.v2
|
||||
key: Ubuntu_Clang.v2
|
||||
variables:
|
||||
CC: clang
|
||||
CXX: clang++
|
||||
|
@ -137,22 +160,28 @@ Debian_Clang:
|
|||
# When CCache doesn't exist (e.g. first build on a fork), build takes more than 1h, which is the default for forks.
|
||||
timeout: 2h
|
||||
|
||||
Debian_Clang_tests:
|
||||
extends: Debian_Clang
|
||||
Ubuntu_Clang_tests:
|
||||
extends: Ubuntu_Clang
|
||||
cache:
|
||||
key: Debian_Clang_tests.v2
|
||||
key: Ubuntu_Clang_tests.v2
|
||||
variables:
|
||||
CCACHE_SIZE: 1G
|
||||
BUILD_TESTS_ONLY: 1
|
||||
artifacts:
|
||||
paths: []
|
||||
expire_in: 1 minute
|
||||
|
||||
Debian_Clang_tests_Debug:
|
||||
extends: Debian_Clang
|
||||
Ubuntu_Clang_tests_Debug:
|
||||
extends: Ubuntu_Clang
|
||||
cache:
|
||||
key: Debian_Clang_tests_Debug.v1
|
||||
key: Ubuntu_Clang_tests_Debug.v1
|
||||
variables:
|
||||
CCACHE_SIZE: 1G
|
||||
BUILD_TESTS_ONLY: 1
|
||||
CMAKE_BUILD_TYPE: Debug
|
||||
artifacts:
|
||||
paths: []
|
||||
expire_in: 1 minute
|
||||
|
||||
.MacOS:
|
||||
image: macos-11-xcode-12
|
||||
|
@ -161,7 +190,7 @@ Debian_Clang_tests_Debug:
|
|||
stage: build
|
||||
only:
|
||||
variables:
|
||||
- $CI_PROJECT_ID == "7107382"
|
||||
- $CI_PROJECT_ID == "7107382" && $CI_PIPELINE_SOURCE == "push"
|
||||
cache:
|
||||
paths:
|
||||
- ccache/
|
||||
|
@ -174,7 +203,7 @@ Debian_Clang_tests_Debug:
|
|||
- ccache -z -M "${CCACHE_SIZE}"
|
||||
- CI/before_script.osx.sh
|
||||
- cd build; make -j $(sysctl -n hw.logicalcpu) package
|
||||
- for dmg in *.dmg; do mv "$dmg" "${dmg%.dmg}_${CI_COMMIT_REF_NAME}_${CI_JOB_ID}.dmg"; done
|
||||
- for dmg in *.dmg; do mv "$dmg" "${dmg%.dmg}_${CI_COMMIT_REF_NAME##*/}_${CI_JOB_ID}.dmg"; done
|
||||
- ccache -s
|
||||
artifacts:
|
||||
paths:
|
||||
|
@ -184,26 +213,17 @@ Debian_Clang_tests_Debug:
|
|||
macOS11_Xcode12:
|
||||
extends: .MacOS
|
||||
image: macos-11-xcode-12
|
||||
allow_failure: true
|
||||
cache:
|
||||
key: macOS11_Xcode12.v1
|
||||
variables:
|
||||
CCACHE_SIZE: 3G
|
||||
|
||||
macOS10.15_Xcode11:
|
||||
extends: .MacOS
|
||||
image: macos-10.15-xcode-11
|
||||
cache:
|
||||
key: macOS10.15_Xcode11.v1
|
||||
variables:
|
||||
CCACHE_SIZE: 3G
|
||||
|
||||
variables: &engine-targets
|
||||
targets: "openmw,openmw-essimporter,openmw-iniimporter,openmw-launcher,openmw-wizard"
|
||||
targets: "openmw,openmw-iniimporter,openmw-launcher,openmw-wizard"
|
||||
package: "Engine"
|
||||
|
||||
variables: &cs-targets
|
||||
targets: "openmw-cs,bsatool,esmtool,niftest"
|
||||
targets: "openmw-cs,bsatool,esmtool,niftest,openmw-essimporter"
|
||||
package: "CS"
|
||||
|
||||
variables: &tests-targets
|
||||
|
@ -213,6 +233,8 @@ variables: &tests-targets
|
|||
.Windows_Ninja_Base:
|
||||
tags:
|
||||
- windows
|
||||
rules:
|
||||
- if: $CI_PIPELINE_SOURCE == "push"
|
||||
before_script:
|
||||
- Import-Module "$env:ChocolateyInstall\helpers\chocolateyProfile.psm1"
|
||||
- choco source add -n=openmw-proxy -s="https://repo.openmw.org/repository/Chocolatey/" --priority=1
|
||||
|
@ -325,10 +347,15 @@ Windows_Ninja_Tests_RelWithDebInfo:
|
|||
config: "RelWithDebInfo"
|
||||
# Gitlab can't successfully execute following binaries due to unknown reason
|
||||
# executables: "openmw_test_suite.exe,openmw_detournavigator_navmeshtilescache_benchmark.exe"
|
||||
artifacts:
|
||||
paths: []
|
||||
expire_in: 1 minute
|
||||
|
||||
.Windows_MSBuild_Base:
|
||||
tags:
|
||||
- windows
|
||||
rules:
|
||||
- if: $CI_PIPELINE_SOURCE == "push"
|
||||
before_script:
|
||||
- Import-Module "$env:ChocolateyInstall\helpers\chocolateyProfile.psm1"
|
||||
- choco source add -n=openmw-proxy -s="https://repo.openmw.org/repository/Chocolatey/" --priority=1
|
||||
|
@ -395,6 +422,10 @@ Windows_MSBuild_Engine_Release:
|
|||
variables:
|
||||
<<: *engine-targets
|
||||
config: "Release"
|
||||
rules:
|
||||
# run this for both pushes and schedules so 'latest successful pipeline for branch' always includes it
|
||||
- if: $CI_PIPELINE_SOURCE == "push"
|
||||
- if: $CI_PIPELINE_SOURCE == "schedule"
|
||||
|
||||
Windows_MSBuild_Engine_Debug:
|
||||
extends:
|
||||
|
@ -416,6 +447,10 @@ Windows_MSBuild_CS_Release:
|
|||
variables:
|
||||
<<: *cs-targets
|
||||
config: "Release"
|
||||
rules:
|
||||
# run this for both pushes and schedules so 'latest successful pipeline for branch' always includes it
|
||||
- if: $CI_PIPELINE_SOURCE == "push"
|
||||
- if: $CI_PIPELINE_SOURCE == "schedule"
|
||||
|
||||
Windows_MSBuild_CS_Debug:
|
||||
extends:
|
||||
|
@ -439,25 +474,28 @@ Windows_MSBuild_Tests_RelWithDebInfo:
|
|||
config: "RelWithDebInfo"
|
||||
# Gitlab can't successfully execute following binaries due to unknown reason
|
||||
# executables: "openmw_test_suite.exe,openmw_detournavigator_navmeshtilescache_benchmark.exe"
|
||||
artifacts:
|
||||
paths: []
|
||||
expire_in: 1 minute
|
||||
|
||||
Debian_AndroidNDK_arm64-v8a:
|
||||
Ubuntu_AndroidNDK_arm64-v8a:
|
||||
tags:
|
||||
- linux
|
||||
image: debian:bullseye
|
||||
image: psi29a/android-ndk:focal-ndk22
|
||||
rules:
|
||||
- if: $CI_PIPELINE_SOURCE == "push"
|
||||
variables:
|
||||
CCACHE_SIZE: 3G
|
||||
cache:
|
||||
key: Debian_AndroidNDK_arm64-v8a.v3
|
||||
key: Ubuntu__Focal_AndroidNDK_r22b_arm64-v8a.v1
|
||||
paths:
|
||||
- apt-cache/
|
||||
- ccache/
|
||||
- build/extern/fetched/
|
||||
before_script:
|
||||
- export APT_CACHE_DIR=`pwd`/apt-cache && mkdir -pv $APT_CACHE_DIR
|
||||
- echo "deb http://deb.debian.org/debian unstable main contrib" > /etc/apt/sources.list
|
||||
- echo "google-android-ndk-installer google-android-installers/mirror select https://dl.google.com" | debconf-set-selections
|
||||
- apt-get update -yq
|
||||
- apt-get -q -o dir::cache::archives="$APT_CACHE_DIR" install -y cmake ccache curl unzip git build-essential google-android-ndk-installer
|
||||
- apt-get -q -o dir::cache::archives="$APT_CACHE_DIR" install -y cmake ccache curl unzip git build-essential
|
||||
stage: build
|
||||
script:
|
||||
- export CCACHE_BASEDIR="`pwd`"
|
||||
|
@ -475,3 +513,18 @@ Debian_AndroidNDK_arm64-v8a:
|
|||
# When CCache doesn't exist (e.g. first build on a fork), build takes more than 1h, which is the default for forks.
|
||||
timeout: 1h30m
|
||||
|
||||
FindMissingMergeRequests:
|
||||
image: python:latest
|
||||
stage: build
|
||||
rules:
|
||||
- if: '$CI_PIPELINE_SOURCE == "schedule"'
|
||||
variables:
|
||||
PIP_CACHE_DIR: "$CI_PROJECT_DIR/.cache/pip"
|
||||
cache:
|
||||
key: FindMissingMergeRequests.v1
|
||||
paths:
|
||||
- .cache/pip
|
||||
before_script:
|
||||
- pip3 install --user requests click discord_webhook
|
||||
script:
|
||||
- scripts/find_missing_merge_requests.py --project_id=$CI_PROJECT_ID --ignored_mrs_path=$CI_PROJECT_DIR/.resubmitted_merge_requests.txt
|
||||
|
|
10
.readthedocs.yaml
Normal file
10
.readthedocs.yaml
Normal file
|
@ -0,0 +1,10 @@
|
|||
version: 2
|
||||
|
||||
sphinx:
|
||||
configuration: docs/source/conf.py
|
||||
|
||||
python:
|
||||
version: 3.8
|
||||
install:
|
||||
- requirements: docs/requirements.txt
|
||||
|
7
.resubmitted_merge_requests.txt
Normal file
7
.resubmitted_merge_requests.txt
Normal file
|
@ -0,0 +1,7 @@
|
|||
1450
|
||||
1420
|
||||
1314
|
||||
1216
|
||||
1172
|
||||
1160
|
||||
1051
|
|
@ -31,6 +31,7 @@ Programmers
|
|||
Allofich
|
||||
Andreas Stöckel
|
||||
Andrei Kortunov (akortunov)
|
||||
Andrew Appuhamy (andrew-app)
|
||||
AnyOldName3
|
||||
Ardekantur
|
||||
Armin Preiml
|
||||
|
@ -92,6 +93,7 @@ Programmers
|
|||
Haoda Wang (h313)
|
||||
hristoast
|
||||
Internecine
|
||||
Ivan Beloborodov (myrix)
|
||||
Jackerty
|
||||
Jacob Essex (Yacoby)
|
||||
Jacob Turnbull (Tankinfrank)
|
||||
|
@ -177,6 +179,7 @@ Programmers
|
|||
PlutonicOverkill
|
||||
Radu-Marius Popovici (rpopovici)
|
||||
Rafael Moura (dhustkoder)
|
||||
Randy Davin (Kindi)
|
||||
rdimesio
|
||||
rexelion
|
||||
riothamus
|
||||
|
@ -214,6 +217,7 @@ Programmers
|
|||
tlmullis
|
||||
tri4ng1e
|
||||
Thoronador
|
||||
Tom Lowe (Vulpen)
|
||||
Tom Mason (wheybags)
|
||||
Torben Leif Carrington (TorbenC)
|
||||
unelsson
|
||||
|
@ -229,7 +233,7 @@ Programmers
|
|||
Yuri Krupenin
|
||||
zelurker
|
||||
Noah Gooder
|
||||
Andrew Appuhamy (andrew-app)
|
||||
|
||||
|
||||
Documentation
|
||||
-------------
|
||||
|
|
47
CHANGELOG.md
47
CHANGELOG.md
|
@ -2,19 +2,29 @@
|
|||
------
|
||||
|
||||
Bug #1751: Birthsign abilities increase modified attribute values instead of base ones
|
||||
Bug #1930: Followers are still fighting if a target stops combat with a leader
|
||||
Bug #3246: ESSImporter: Most NPCs are dead on save load
|
||||
Bug #3488: AI combat aiming is too slow
|
||||
Bug #3514: Editing a reference's position after loading an esp file makes the reference disappear
|
||||
Bug #3737: Scripts from The Underground 2 .esp do not play (all patched versions)
|
||||
Bug #3792: 1 frame late magicka recalc breaks early scripted magicka reactions to Intelligence change
|
||||
Bug #3846: Strings starting with "-" fail to compile if not enclosed in quotes
|
||||
Bug #3855: AI sometimes spams defensive spells
|
||||
Bug #3905: Great House Dagoth issues
|
||||
Bug #4203: Resurrecting an actor should close the loot GUI
|
||||
Bug #4376: Moved actors don't respawn in their original cells
|
||||
Bug #4389: NPC's lips do not move if his head model has the NiBSAnimationNode root node
|
||||
Bug #4602: Robert's Bodies: crash inside createInstance()
|
||||
Bug #4700: Editor: Incorrect command implementation
|
||||
Bug #4744: Invisible particles must still be processed
|
||||
Bug #5088: Sky abruptly changes direction during certain weather transitions
|
||||
Bug #5100: Persuasion doesn't always clamp the resulting disposition
|
||||
Bug #5120: Scripted object spawning updates physics system
|
||||
Bug #5207: Loose summons can be present in scene
|
||||
Bug #5377: console does not appear after using menutest in inventory
|
||||
Bug #5379: Wandering NPCs falling through cantons
|
||||
Bug #5394: Windows snapping no longer works
|
||||
Bug #5434: Pinned windows shouldn't cover breath progress bar
|
||||
Bug #5453: Magic effect VFX are offset for creatures
|
||||
Bug #5483: AutoCalc flag is not used to calculate spells cost
|
||||
Bug #5508: Engine binary links to Qt without using it
|
||||
|
@ -25,6 +35,8 @@
|
|||
Bug #5801: A multi-effect spell with the intervention effects and recall always favors Almsivi intervention
|
||||
Bug #5842: GetDisposition adds temporary disposition change from different actors
|
||||
Bug #5863: GetEffect should return true after the player has teleported
|
||||
Bug #5913: Failed assertion during Ritual of Trees quest
|
||||
Bug #5937: Lights always need to be rotated by 90 degrees
|
||||
Bug #6037: Morrowind Content Language Cannot be Set to English in OpenMW Launcher
|
||||
Bug #6051: NaN water height in ESM file is not handled gracefully
|
||||
Bug #6066: addtopic "return" does not work from within script. No errors thrown
|
||||
|
@ -40,19 +52,45 @@
|
|||
Bug #6133: Cannot reliably sneak or steal in the sight of the NPCs siding with player
|
||||
Bug #6143: Capturing a screenshot makes engine to be a temporary unresponsive
|
||||
Bug #6165: Paralyzed player character can pickup items when the inventory is open
|
||||
Bug #6168: Weather particles flicker for a frame at start of storms
|
||||
Bug #6172: Some creatures can't open doors
|
||||
Bug #6174: Spellmaking and Enchanting sliders differences from vanilla
|
||||
Bug #6177: Followers of player follower stop following after waiting for a day
|
||||
Bug #6184: Command and Calm and Demoralize and Frenzy and Rally magic effects inconsistencies with vanilla
|
||||
Bug #6197: Infinite Casting Loop
|
||||
Bug #6253: Multiple instances of Reflect stack additively
|
||||
Bug #6255: Reflect is different from vanilla
|
||||
Bug #6258: Barter menu glitches out when modifying prices
|
||||
Bug #6273: Respawning NPCs rotation is inconsistent
|
||||
Bug #6282: Laura craft doesn't follow the player character
|
||||
Bug #6283: Avis Dorsey follows you after her death
|
||||
Bug #6285: Brush template drawing and terrain selection drawing performance is very bad
|
||||
Bug #6289: Keyword search in dialogues expected the text to be all ASCII characters
|
||||
Bug #6291: Can't pickup the dead mage's journal from the mysterious hunter mod
|
||||
Bug #6302: Teleporting disabled actor breaks its disabled state
|
||||
Bug #6307: Pathfinding in Infidelities quest from Tribunal addon is broken
|
||||
Bug #6321: Arrow enchantments should always be applied to the target
|
||||
Bug #6322: Total sold/cost should reset to 0 when there are no items offered
|
||||
Bug #6323: Wyrmhaven: Alboin doesn't follower the player character out of his house
|
||||
Bug #6324: Special Slave Companions: Can't buy the slave companions
|
||||
Bug #6326: Detect Enchantment/Key should detect items in unresolved containers
|
||||
Bug #6327: Blocking roots the character in place
|
||||
Bug #6343: Magic projectile speed doesn't take race weight into account
|
||||
Bug #6347: PlaceItem/PlaceItemCell/PlaceAt should work with levelled creatures
|
||||
Bug #6354: SFX abruptly cut off after crossing max distance; implement soft fading of sound effects
|
||||
Bug #6358: Changeweather command does not report an error when entering non-existent region
|
||||
Bug #6363: Some scripts in Morrowland fail to work
|
||||
Bug #6376: Creatures should be able to use torches
|
||||
Bug #6386: Artifacts in water reflection due to imprecise screen-space coordinate computation
|
||||
Bug #6396: Inputting certain Unicode characters triggers an assertion
|
||||
Bug #6416: Morphs are applied to the wrong target
|
||||
Bug #6417: OpenMW doesn't always use the right node to accumulate movement
|
||||
Bug #6429: Wyrmhaven: Can't add AI packages to player
|
||||
Bug #6433: Items bound to Quick Keys sometimes do not appear until the Quick Key menu is opened
|
||||
Bug #6451: Weapon summoned from Cast When Used item will have the name "None"
|
||||
Bug #6473: Strings from NIF should be parsed only to first null terminator
|
||||
Feature #890: OpenMW-CS: Column filtering
|
||||
Feature #1465: "Reset" argument for AI functions
|
||||
Feature #2554: Modifying an object triggers the instances table to scroll to the corresponding record
|
||||
Feature #2780: A way to see current OpenMW version in the console
|
||||
Feature #3616: Allow Zoom levels on the World Map
|
||||
|
@ -66,15 +104,20 @@
|
|||
Feature #5996: Support Lua scripts in OpenMW
|
||||
Feature #6017: Separate persistent and temporary cell references when saving
|
||||
Feature #6032: Reverse-z depth buffer
|
||||
Feature #6078: First person should not clear depth buffer
|
||||
Feature #6128: Soft Particles
|
||||
Feature #6161: Refactor Sky to use shaders and GLES/GL3 friendly
|
||||
Feature #6162: Refactor GUI to use shaders and to be GLES and GL3+ friendly
|
||||
Feature #6199: Support FBO Rendering
|
||||
Feature #6248: Embedded error marker mesh
|
||||
Feature #6249: Alpha testing support for Collada
|
||||
Feature #6251: OpenMW-CS: Set instance movement based on camera zoom
|
||||
Feature #6288: Preserve the "blocked" record flag for referenceable objects.
|
||||
Feature #6380: Commas are treated as whitespace in vanilla
|
||||
Feature #6419: Topics shouldn't be greyed out if they can produce another topic reference
|
||||
Task #6201: Remove the "Note: No relevant classes found. No output generated" warnings
|
||||
Task #6264: Remove the old classes in animation.cpp
|
||||
|
||||
|
||||
0.47.0
|
||||
------
|
||||
|
||||
|
@ -208,6 +251,8 @@
|
|||
Bug #6043: Actor can have torch missing when torch animation is played
|
||||
Bug #6047: Mouse bindings can be triggered during save loading
|
||||
Bug #6136: Game freezes when NPCs try to open doors that are about to be closed
|
||||
Bug #6142: Groundcover plugins change cells flags
|
||||
Bug #6276: Deleted groundcover instances are not deleted in game
|
||||
Bug #6294: Game crashes with empty pathgrid
|
||||
Feature #390: 3rd person look "over the shoulder"
|
||||
Feature #832: OpenMW-CS: Handle deleted references
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
#!/bin/sh -ex
|
||||
|
||||
curl -fSL -R -J https://gitlab.com/OpenMW/openmw-deps/-/raw/main/android/openmw-android-deps-20201230.zip -o ~/openmw-android-deps.zip
|
||||
unzip -o ~/openmw-android-deps -d /usr/lib/android-sdk/ndk-bundle/toolchains/llvm/prebuilt/linux-x86_64/sysroot/usr > /dev/null
|
||||
curl -fSL -R -J https://gitlab.com/OpenMW/openmw-deps/-/raw/main/android/openmw-android-deps-20211114.zip -o ~/openmw-android-deps.zip
|
||||
unzip -o ~/openmw-android-deps -d /android-ndk-r22/toolchains/llvm/prebuilt/linux-x86_64/sysroot/usr > /dev/null
|
||||
|
|
|
@ -7,9 +7,10 @@ mkdir -p build
|
|||
cd build
|
||||
|
||||
cmake \
|
||||
-DCMAKE_TOOLCHAIN_FILE=/usr/lib/android-sdk/ndk-bundle/build/cmake/android.toolchain.cmake \
|
||||
-DCMAKE_TOOLCHAIN_FILE=/android-ndk-r22/build/cmake/android.toolchain.cmake \
|
||||
-DANDROID_ABI=arm64-v8a \
|
||||
-DANDROID_PLATFORM=android-21 \
|
||||
-DANDROID_LD=deprecated \
|
||||
-DCMAKE_C_COMPILER_LAUNCHER=ccache \
|
||||
-DCMAKE_CXX_COMPILER_LAUNCHER=ccache \
|
||||
-DCMAKE_INSTALL_PREFIX=install \
|
||||
|
@ -22,6 +23,5 @@ cmake \
|
|||
-DBUILD_OPENCS=0 \
|
||||
-DBUILD_WIZARD=0 \
|
||||
-DOPENMW_USE_SYSTEM_MYGUI=OFF \
|
||||
-DOPENMW_USE_SYSTEM_OSG=OFF \
|
||||
-DOPENMW_USE_SYSTEM_BULLET=OFF \
|
||||
-DOPENMW_USE_SYSTEM_SQLITE3=OFF \
|
||||
..
|
||||
|
|
|
@ -40,6 +40,7 @@ if [[ $CI_OPENMW_USE_STATIC_DEPS ]]; then
|
|||
-DOPENMW_USE_SYSTEM_MYGUI=OFF
|
||||
-DOPENMW_USE_SYSTEM_OSG=OFF
|
||||
-DOPENMW_USE_SYSTEM_BULLET=OFF
|
||||
-DOPENMW_USE_SYSTEM_SQLITE3=OFF
|
||||
)
|
||||
fi
|
||||
|
||||
|
|
|
@ -1018,6 +1018,7 @@ echo
|
|||
echo "Setting up OpenMW build..."
|
||||
add_cmake_opts -DOPENMW_MP_BUILD=on
|
||||
add_cmake_opts -DCMAKE_INSTALL_PREFIX="${INSTALL_PREFIX}"
|
||||
add_cmake_opts -DOPENMW_USE_SYSTEM_SQLITE3=OFF
|
||||
if [ ! -z $CI ]; then
|
||||
case $STEP in
|
||||
components )
|
||||
|
|
|
@ -19,6 +19,7 @@ cmake \
|
|||
-D CMAKE_OSX_DEPLOYMENT_TARGET="10.14" \
|
||||
-D CMAKE_BUILD_TYPE=RELEASE \
|
||||
-D OPENMW_OSX_DEPLOYMENT=TRUE \
|
||||
-D OPENMW_USE_SYSTEM_SQLITE3=OFF \
|
||||
-D BUILD_OPENMW=TRUE \
|
||||
-D BUILD_OPENCS=TRUE \
|
||||
-D BUILD_ESMTOOL=TRUE \
|
||||
|
|
|
@ -27,7 +27,7 @@ declare -rA GROUPED_DEPS=(
|
|||
# TODO: add librecastnavigation-dev when debian is ready
|
||||
|
||||
# These dependencies can alternatively be built and linked statically.
|
||||
[openmw-deps-dynamic]="libmygui-dev libopenscenegraph-dev"
|
||||
[openmw-deps-dynamic]="libmygui-dev libopenscenegraph-dev libsqlite3-dev"
|
||||
[coverity]="curl"
|
||||
[clang-tidy]="clang-tidy"
|
||||
|
||||
|
|
|
@ -149,6 +149,8 @@ else()
|
|||
endif()
|
||||
option(RECASTNAVIGATION_STATIC "Build recastnavigation static libraries" ${_recastnavigation_static_default})
|
||||
|
||||
option(OPENMW_USE_SYSTEM_SQLITE3 "Use system provided SQLite3 library" ON)
|
||||
|
||||
option(OPENMW_UNITY_BUILD "Use fewer compilation units to speed up compile time" FALSE)
|
||||
option(OPENMW_LTO_BUILD "Build OpenMW with Link-Time Optimization (Needs ~2GB of RAM)" OFF)
|
||||
|
||||
|
@ -197,6 +199,10 @@ if (WIN32)
|
|||
option(USE_DEBUG_CONSOLE "whether a debug console should be enabled for debug builds, if false debug output is redirected to Visual Studio output" ON)
|
||||
endif()
|
||||
|
||||
if(MSVC)
|
||||
add_compile_options("/utf-8")
|
||||
endif()
|
||||
|
||||
# Dependencies
|
||||
find_package(OpenGL REQUIRED)
|
||||
|
||||
|
@ -408,7 +414,8 @@ else(USE_LUAJIT)
|
|||
endif(USE_LUAJIT)
|
||||
|
||||
# C++ library binding to Lua
|
||||
set(SOL_INCLUDE_DIRS ${OpenMW_SOURCE_DIR}/extern/sol3.2.2 ${OpenMW_SOURCE_DIR}/extern/sol_config)
|
||||
set(SOL_INCLUDE_DIR ${OpenMW_SOURCE_DIR}/extern/sol3.2.2)
|
||||
set(SOL_CONFIG_DIR ${OpenMW_SOURCE_DIR}/extern/sol_config)
|
||||
|
||||
include_directories(
|
||||
BEFORE SYSTEM
|
||||
|
@ -420,7 +427,8 @@ include_directories(
|
|||
${OPENGL_INCLUDE_DIR}
|
||||
${BULLET_INCLUDE_DIRS}
|
||||
${LUA_INCLUDE_DIR}
|
||||
${SOL_INCLUDE_DIRS}
|
||||
${SOL_INCLUDE_DIR}
|
||||
${SOL_CONFIG_DIR}
|
||||
)
|
||||
|
||||
link_directories(${SDL2_LIBRARY_DIRS} ${Boost_LIBRARY_DIRS})
|
||||
|
@ -437,9 +445,8 @@ if (APPLE)
|
|||
"${APP_BUNDLE_DIR}/Contents/Resources/OpenMW.icns" COPYONLY)
|
||||
endif (APPLE)
|
||||
|
||||
if (NOT APPLE)
|
||||
set(OPENMW_MYGUI_FILES_ROOT ${OpenMW_BINARY_DIR})
|
||||
set(OPENMW_SHADERS_ROOT ${OpenMW_BINARY_DIR})
|
||||
if (NOT APPLE) # this is modified for macOS use later in "apps/open[mw|cs]/CMakeLists.txt"
|
||||
set(OPENMW_RESOURCES_ROOT ${OpenMW_BINARY_DIR})
|
||||
endif ()
|
||||
|
||||
add_subdirectory(files/)
|
||||
|
@ -703,8 +710,12 @@ if (WIN32)
|
|||
endif()
|
||||
|
||||
if (BUILD_OPENMW AND APPLE)
|
||||
# Without these flags LuaJit crashes on startup on OSX
|
||||
set_target_properties(openmw PROPERTIES LINK_FLAGS "-pagezero_size 10000 -image_base 100000000")
|
||||
if (USE_LUAJIT)
|
||||
# Without these flags LuaJit crashes on startup on OSX
|
||||
set_target_properties(openmw PROPERTIES LINK_FLAGS "-pagezero_size 10000 -image_base 100000000")
|
||||
endif(USE_LUAJIT)
|
||||
target_compile_definitions(components PRIVATE GL_SILENCE_DEPRECATION=1)
|
||||
target_compile_definitions(openmw PRIVATE GL_SILENCE_DEPRECATION=1)
|
||||
endif()
|
||||
|
||||
# Apple bundling
|
||||
|
|
|
@ -1,8 +1,6 @@
|
|||
OpenMW
|
||||
======
|
||||
|
||||
[](https://scan.coverity.com/projects/3740) [](https://gitlab.com/OpenMW/openmw/commits/master)
|
||||
|
||||
OpenMW is an open-source game engine that supports playing Morrowind by Bethesda Softworks. You need to own the game for OpenMW to play Morrowind.
|
||||
|
||||
OpenMW also comes with OpenMW-CS, a replacement for Bethesda's Construction Set.
|
||||
|
|
|
@ -25,18 +25,10 @@ namespace
|
|||
};
|
||||
|
||||
template <typename Random>
|
||||
TilePosition generateTilePosition(int max, Random& random)
|
||||
osg::Vec2i generateVec2i(int max, Random& random)
|
||||
{
|
||||
std::uniform_int_distribution<int> distribution(0, max);
|
||||
return TilePosition(distribution(random), distribution(random));
|
||||
}
|
||||
|
||||
template <typename Random>
|
||||
TileBounds generateTileBounds(Random& random)
|
||||
{
|
||||
std::uniform_real_distribution<float> distribution(0.0, 1.0);
|
||||
const osg::Vec2f min(distribution(random), distribution(random));
|
||||
return TileBounds {min, min + osg::Vec2f(1.0, 1.0)};
|
||||
return osg::Vec2i(distribution(random), distribution(random));
|
||||
}
|
||||
|
||||
template <typename Random>
|
||||
|
@ -91,8 +83,7 @@ namespace
|
|||
{
|
||||
std::uniform_real_distribution<float> distribution(0.0, 1.0);
|
||||
std::generate_n(out, count, [&] {
|
||||
const osg::Vec3f shift(distribution(random), distribution(random), distribution(random));
|
||||
return Cell {1, shift};
|
||||
return CellWater {generateVec2i(1000, random), Water {ESM::Land::REAL_SIZE, distribution(random)}};
|
||||
});
|
||||
}
|
||||
|
||||
|
@ -117,16 +108,18 @@ namespace
|
|||
{
|
||||
std::uniform_real_distribution<float> distribution(0.0, 1.0);
|
||||
Heightfield result;
|
||||
result.mBounds = generateTileBounds(random);
|
||||
result.mCellPosition = generateVec2i(1000, random);
|
||||
result.mCellSize = ESM::Land::REAL_SIZE;
|
||||
result.mMinHeight = distribution(random);
|
||||
result.mMaxHeight = result.mMinHeight + 1.0;
|
||||
result.mShift = osg::Vec3f(distribution(random), distribution(random), distribution(random));
|
||||
result.mScale = distribution(random);
|
||||
result.mLength = static_cast<std::uint8_t>(ESM::Land::LAND_SIZE);
|
||||
std::generate_n(std::back_inserter(result.mHeights), ESM::Land::LAND_NUM_VERTS, [&]
|
||||
{
|
||||
return distribution(random);
|
||||
});
|
||||
result.mOriginalSize = ESM::Land::LAND_SIZE;
|
||||
result.mMinX = 0;
|
||||
result.mMinY = 0;
|
||||
return result;
|
||||
}
|
||||
|
||||
|
@ -135,7 +128,8 @@ namespace
|
|||
{
|
||||
std::uniform_real_distribution<float> distribution(0.0, 1.0);
|
||||
FlatHeightfield result;
|
||||
result.mBounds = generateTileBounds(random);
|
||||
result.mCellPosition = generateVec2i(1000, random);
|
||||
result.mCellSize = ESM::Land::REAL_SIZE;
|
||||
result.mHeight = distribution(random);
|
||||
return result;
|
||||
}
|
||||
|
@ -144,11 +138,11 @@ namespace
|
|||
Key generateKey(std::size_t triangles, Random& random)
|
||||
{
|
||||
const osg::Vec3f agentHalfExtents = generateAgentHalfExtents(0.5, 1.5, random);
|
||||
const TilePosition tilePosition = generateTilePosition(10000, random);
|
||||
const TilePosition tilePosition = generateVec2i(10000, random);
|
||||
const std::size_t generation = std::uniform_int_distribution<std::size_t>(0, 100)(random);
|
||||
const std::size_t revision = std::uniform_int_distribution<std::size_t>(0, 10000)(random);
|
||||
Mesh mesh = generateMesh(triangles, random);
|
||||
std::vector<Cell> water;
|
||||
std::vector<CellWater> water;
|
||||
generateWater(std::back_inserter(water), 1, random);
|
||||
RecastMesh recastMesh(generation, revision, std::move(mesh), std::move(water),
|
||||
{generateHeightfield(random)}, {generateFlatHeightfield(random)});
|
||||
|
|
|
@ -233,7 +233,17 @@ int extract(std::unique_ptr<Bsa::BSAFile>& bsa, Arguments& info)
|
|||
std::string extractPath = info.extractfile;
|
||||
Misc::StringUtils::replaceAll(extractPath, "\\", "/");
|
||||
|
||||
if (!bsa->exists(archivePath.c_str()))
|
||||
Files::IStreamPtr stream;
|
||||
// Get a stream for the file to extract
|
||||
for (auto it = bsa->getList().rbegin(); it != bsa->getList().rend(); ++it)
|
||||
{
|
||||
if (Misc::StringUtils::ciEqual(std::string(it->name()), archivePath))
|
||||
{
|
||||
stream = bsa->getFile(&*it);
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!stream)
|
||||
{
|
||||
std::cout << "ERROR: file '" << archivePath << "' not found\n";
|
||||
std::cout << "In archive: " << info.filename << std::endl;
|
||||
|
@ -260,9 +270,6 @@ int extract(std::unique_ptr<Bsa::BSAFile>& bsa, Arguments& info)
|
|||
return 3;
|
||||
}
|
||||
|
||||
// Get a stream for the file to extract
|
||||
Files::IStreamPtr stream = bsa->getFile(archivePath.c_str());
|
||||
|
||||
bfs::ofstream out(target, std::ios::binary);
|
||||
|
||||
// Write the file to disk
|
||||
|
@ -296,8 +303,7 @@ int extractAll(std::unique_ptr<Bsa::BSAFile>& bsa, Arguments& info)
|
|||
}
|
||||
|
||||
// Get a stream for the file to extract
|
||||
// (inefficient because getFile iter on the list again)
|
||||
Files::IStreamPtr data = bsa->getFile(file.name());
|
||||
Files::IStreamPtr data = bsa->getFile(&file);
|
||||
bfs::ofstream out(target, std::ios::binary);
|
||||
|
||||
// Write the file to disk
|
||||
|
|
|
@ -367,10 +367,10 @@ int load(Arguments& info)
|
|||
EsmTool::RecordBase *record = EsmTool::RecordBase::create(n);
|
||||
if (record == nullptr)
|
||||
{
|
||||
if (skipped.count(n.intval) == 0)
|
||||
if (skipped.count(n.toInt()) == 0)
|
||||
{
|
||||
std::cout << "Skipping " << n.toString() << " records.\n";
|
||||
skipped.emplace(n.intval);
|
||||
skipped.emplace(n.toInt());
|
||||
}
|
||||
|
||||
esm.skipRecord();
|
||||
|
@ -402,7 +402,7 @@ int load(Arguments& info)
|
|||
record->print();
|
||||
}
|
||||
|
||||
if (record->getType().intval == ESM::REC_CELL && loadCells && interested)
|
||||
if (record->getType().toInt() == ESM::REC_CELL && loadCells && interested)
|
||||
{
|
||||
loadCell(record->cast<ESM::Cell>()->get(), esm, info);
|
||||
}
|
||||
|
@ -415,7 +415,7 @@ int load(Arguments& info)
|
|||
{
|
||||
delete record;
|
||||
}
|
||||
++info.data.mRecordStats[n.intval];
|
||||
++info.data.mRecordStats[n.toInt()];
|
||||
}
|
||||
|
||||
} catch(std::exception &e) {
|
||||
|
@ -459,7 +459,7 @@ int clone(Arguments& info)
|
|||
for (std::pair<int, int> stat : info.data.mRecordStats)
|
||||
{
|
||||
ESM::NAME name;
|
||||
name.intval = stat.first;
|
||||
name = stat.first;
|
||||
int amount = stat.second;
|
||||
std::cout << std::setw(digitCount) << amount << " " << name.toString() << " ";
|
||||
if (++i % 3 == 0)
|
||||
|
@ -496,7 +496,7 @@ int clone(Arguments& info)
|
|||
esm.startRecord(typeName.toString(), record->getFlags());
|
||||
|
||||
record->save(esm);
|
||||
if (typeName.intval == ESM::REC_CELL) {
|
||||
if (typeName.toInt() == ESM::REC_CELL) {
|
||||
ESM::Cell *ptr = &record->cast<ESM::Cell>()->get();
|
||||
if (!info.data.mCellRefs[ptr].empty())
|
||||
{
|
||||
|
|
|
@ -30,7 +30,7 @@ void printAIPackage(const ESM::AIPackage& p)
|
|||
{
|
||||
std::cout << " Travel Coordinates: (" << p.mTravel.mX << ","
|
||||
<< p.mTravel.mY << "," << p.mTravel.mZ << ")" << std::endl;
|
||||
std::cout << " Travel Unknown: " << p.mTravel.mUnk << std::endl;
|
||||
std::cout << " Should repeat: " << p.mTravel.mShouldRepeat << std::endl;
|
||||
}
|
||||
else if (p.mType == ESM::AI_Follow || p.mType == ESM::AI_Escort)
|
||||
{
|
||||
|
@ -38,12 +38,12 @@ void printAIPackage(const ESM::AIPackage& p)
|
|||
<< p.mTarget.mY << "," << p.mTarget.mZ << ")" << std::endl;
|
||||
std::cout << " Duration: " << p.mTarget.mDuration << std::endl;
|
||||
std::cout << " Target ID: " << p.mTarget.mId.toString() << std::endl;
|
||||
std::cout << " Unknown: " << p.mTarget.mUnk << std::endl;
|
||||
std::cout << " Should repeat: " << p.mTarget.mShouldRepeat << std::endl;
|
||||
}
|
||||
else if (p.mType == ESM::AI_Activate)
|
||||
{
|
||||
std::cout << " Name: " << p.mActivate.mName.toString() << std::endl;
|
||||
std::cout << " Activate Unknown: " << p.mActivate.mUnk << std::endl;
|
||||
std::cout << " Should repeat: " << p.mActivate.mShouldRepeat << std::endl;
|
||||
}
|
||||
else {
|
||||
std::cout << " BadPackage: " << Misc::StringUtils::format("0x%08X", p.mType) << std::endl;
|
||||
|
@ -176,7 +176,7 @@ RecordBase::create(const ESM::NAME type)
|
|||
{
|
||||
RecordBase *record = nullptr;
|
||||
|
||||
switch (type.intval) {
|
||||
switch (type.toInt()) {
|
||||
case ESM::REC_ACTI:
|
||||
{
|
||||
record = new EsmTool::Record<ESM::Activator>;
|
||||
|
|
|
@ -324,14 +324,14 @@ namespace ESSImport
|
|||
ESM::NAME n = esm.getRecName();
|
||||
esm.getRecHeader();
|
||||
|
||||
auto it = converters.find(n.intval);
|
||||
auto it = converters.find(n.toInt());
|
||||
if (it != converters.end())
|
||||
{
|
||||
it->second->read(esm);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (unknownRecords.insert(n.intval).second)
|
||||
if (unknownRecords.insert(n.toInt()).second)
|
||||
{
|
||||
std::ios::fmtflags f(std::cerr.flags());
|
||||
std::cerr << "Error: unknown record " << n.toString() << " (0x" << std::hex << esm.getFileOffset() << ")" << std::endl;
|
||||
|
|
|
@ -117,6 +117,11 @@ bool Launcher::AdvancedPage::loadSettings()
|
|||
loadSettingBool(autoUseTerrainSpecularMapsCheckBox, "auto use terrain specular maps", "Shaders");
|
||||
loadSettingBool(bumpMapLocalLightingCheckBox, "apply lighting to environment maps", "Shaders");
|
||||
loadSettingBool(radialFogCheckBox, "radial fog", "Shaders");
|
||||
loadSettingBool(softParticlesCheckBox, "soft particles", "Shaders");
|
||||
loadSettingBool(antialiasAlphaTestCheckBox, "antialias alpha test", "Shaders");
|
||||
if (Settings::Manager::getInt("antialiasing", "Video") == 0) {
|
||||
antialiasAlphaTestCheckBox->setCheckState(Qt::Unchecked);
|
||||
}
|
||||
loadSettingBool(magicItemAnimationsCheckBox, "use magic item animations", "Game");
|
||||
connect(animSourcesCheckBox, SIGNAL(toggled(bool)), this, SLOT(slotAnimSourcesToggled(bool)));
|
||||
loadSettingBool(animSourcesCheckBox, "use additional anim sources", "Game");
|
||||
|
@ -207,7 +212,7 @@ bool Launcher::AdvancedPage::loadSettings()
|
|||
{
|
||||
// Saves
|
||||
loadSettingBool(timePlayedCheckbox, "timeplayed", "Saves");
|
||||
maximumQuicksavesComboBox->setValue(Settings::Manager::getInt("max quicksaves", "Saves"));
|
||||
loadSettingInt(maximumQuicksavesComboBox,"max quicksaves", "Saves");
|
||||
|
||||
// Other Settings
|
||||
QString screenshotFormatString = QString::fromStdString(Settings::Manager::getString("screenshot format", "General")).toUpper();
|
||||
|
@ -252,14 +257,10 @@ void Launcher::AdvancedPage::saveSettings()
|
|||
saveSettingBool(normaliseRaceSpeedCheckBox, "normalise race speed", "Game");
|
||||
saveSettingBool(swimUpwardCorrectionCheckBox, "swim upward correction", "Game");
|
||||
saveSettingBool(avoidCollisionsCheckBox, "NPCs avoid collisions", "Game");
|
||||
int unarmedFactorsStrengthIndex = unarmedFactorsStrengthComboBox->currentIndex();
|
||||
if (unarmedFactorsStrengthIndex != Settings::Manager::getInt("strength influences hand to hand", "Game"))
|
||||
Settings::Manager::setInt("strength influences hand to hand", "Game", unarmedFactorsStrengthIndex);
|
||||
saveSettingInt(unarmedFactorsStrengthComboBox, "strength influences hand to hand", "Game");
|
||||
saveSettingBool(stealingFromKnockedOutCheckBox, "always allow stealing from knocked out actors", "Game");
|
||||
saveSettingBool(enableNavigatorCheckBox, "enable", "Navigator");
|
||||
int numPhysicsThreads = physicsThreadsSpinBox->value();
|
||||
if (numPhysicsThreads != Settings::Manager::getInt("async num threads", "Physics"))
|
||||
Settings::Manager::setInt("async num threads", "Physics", numPhysicsThreads);
|
||||
saveSettingInt(physicsThreadsSpinBox, "async num threads", "Physics");
|
||||
}
|
||||
|
||||
// Visuals
|
||||
|
@ -270,6 +271,8 @@ void Launcher::AdvancedPage::saveSettings()
|
|||
saveSettingBool(autoUseTerrainSpecularMapsCheckBox, "auto use terrain specular maps", "Shaders");
|
||||
saveSettingBool(bumpMapLocalLightingCheckBox, "apply lighting to environment maps", "Shaders");
|
||||
saveSettingBool(radialFogCheckBox, "radial fog", "Shaders");
|
||||
saveSettingBool(softParticlesCheckBox, "soft particles", "Shaders");
|
||||
saveSettingBool(antialiasAlphaTestCheckBox, "antialias alpha test", "Shaders");
|
||||
saveSettingBool(magicItemAnimationsCheckBox, "use magic item animations", "Game");
|
||||
saveSettingBool(animSourcesCheckBox, "use additional anim sources", "Game");
|
||||
saveSettingBool(weaponSheathingCheckBox, "weapon sheathing", "Game");
|
||||
|
@ -349,9 +352,7 @@ void Launcher::AdvancedPage::saveSettings()
|
|||
saveSettingBool(showMeleeInfoCheckBox, "show melee info", "Game");
|
||||
saveSettingBool(showProjectileDamageCheckBox, "show projectile damage", "Game");
|
||||
saveSettingBool(changeDialogTopicsCheckBox, "color topic enable", "GUI");
|
||||
int showOwnedCurrentIndex = showOwnedComboBox->currentIndex();
|
||||
if (showOwnedCurrentIndex != Settings::Manager::getInt("show owned", "Game"))
|
||||
Settings::Manager::setInt("show owned", "Game", showOwnedCurrentIndex);
|
||||
saveSettingInt(showOwnedComboBox,"show owned", "Game");
|
||||
saveSettingBool(stretchBackgroundCheckBox, "stretch menu background", "GUI");
|
||||
saveSettingBool(useZoomOnMapCheckBox, "allow zooming", "Map");
|
||||
saveSettingBool(graphicHerbalismCheckBox, "graphic herbalism", "Game");
|
||||
|
@ -370,11 +371,7 @@ void Launcher::AdvancedPage::saveSettings()
|
|||
{
|
||||
// Saves Settings
|
||||
saveSettingBool(timePlayedCheckbox, "timeplayed", "Saves");
|
||||
int maximumQuicksaves = maximumQuicksavesComboBox->value();
|
||||
if (maximumQuicksaves != Settings::Manager::getInt("max quicksaves", "Saves"))
|
||||
{
|
||||
Settings::Manager::setInt("max quicksaves", "Saves", maximumQuicksaves);
|
||||
}
|
||||
saveSettingInt(maximumQuicksavesComboBox, "max quicksaves", "Saves");
|
||||
|
||||
// Other Settings
|
||||
std::string screenshotFormatString = screenshotFormatComboBox->currentText().toLower().toStdString();
|
||||
|
@ -416,6 +413,32 @@ void Launcher::AdvancedPage::saveSettingBool(QCheckBox *checkbox, const std::str
|
|||
Settings::Manager::setBool(setting, group, cValue);
|
||||
}
|
||||
|
||||
void Launcher::AdvancedPage::loadSettingInt(QComboBox *comboBox, const std::string &setting, const std::string &group)
|
||||
{
|
||||
int currentIndex = Settings::Manager::getInt(setting, group);
|
||||
comboBox->setCurrentIndex(currentIndex);
|
||||
}
|
||||
|
||||
void Launcher::AdvancedPage::saveSettingInt(QComboBox *comboBox, const std::string &setting, const std::string &group)
|
||||
{
|
||||
int currentIndex = comboBox->currentIndex();
|
||||
if (currentIndex != Settings::Manager::getInt(setting, group))
|
||||
Settings::Manager::setInt(setting, group, currentIndex);
|
||||
}
|
||||
|
||||
void Launcher::AdvancedPage::loadSettingInt(QSpinBox *spinBox, const std::string &setting, const std::string &group)
|
||||
{
|
||||
int value = Settings::Manager::getInt(setting, group);
|
||||
spinBox->setValue(value);
|
||||
}
|
||||
|
||||
void Launcher::AdvancedPage::saveSettingInt(QSpinBox *spinBox, const std::string &setting, const std::string &group)
|
||||
{
|
||||
int value = spinBox->value();
|
||||
if (value != Settings::Manager::getInt(setting, group))
|
||||
Settings::Manager::setInt(setting, group, value);
|
||||
}
|
||||
|
||||
void Launcher::AdvancedPage::slotLoadedCellsChanged(QStringList cellNames)
|
||||
{
|
||||
loadCellsForAutocomplete(cellNames);
|
||||
|
|
|
@ -41,8 +41,12 @@ namespace Launcher
|
|||
* @param filePaths the file paths of the content files to be examined
|
||||
*/
|
||||
void loadCellsForAutocomplete(QStringList filePaths);
|
||||
void loadSettingBool(QCheckBox *checkbox, const std::string& setting, const std::string& group);
|
||||
void saveSettingBool(QCheckBox *checkbox, const std::string& setting, const std::string& group);
|
||||
static void loadSettingBool(QCheckBox *checkbox, const std::string& setting, const std::string& group);
|
||||
static void saveSettingBool(QCheckBox *checkbox, const std::string& setting, const std::string& group);
|
||||
static void loadSettingInt(QComboBox *comboBox, const std::string& setting, const std::string& group);
|
||||
static void saveSettingInt(QComboBox *comboBox, const std::string& setting, const std::string& group);
|
||||
static void loadSettingInt(QSpinBox *spinBox, const std::string& setting, const std::string& group);
|
||||
static void saveSettingInt(QSpinBox *spinBox, const std::string& setting, const std::string& group);
|
||||
};
|
||||
}
|
||||
#endif
|
||||
|
|
|
@ -32,7 +32,7 @@ Launcher::DataFilesPage::DataFilesPage(Files::ConfigurationManager &cfg, Config:
|
|||
{
|
||||
ui.setupUi (this);
|
||||
setObjectName ("DataFilesPage");
|
||||
mSelector = new ContentSelectorView::ContentSelector (ui.contentSelectorWidget);
|
||||
mSelector = new ContentSelectorView::ContentSelector (ui.contentSelectorWidget, /*showOMWScripts=*/true);
|
||||
const QString encoding = mGameSettings.value("encoding", "win1252");
|
||||
mSelector->setEncoding(encoding);
|
||||
|
||||
|
@ -121,6 +121,7 @@ void Launcher::DataFilesPage::populateFileViews(const QString& contentModelName)
|
|||
|
||||
for (const QString &path : paths)
|
||||
mSelector->addFiles(path);
|
||||
mSelector->sortFiles();
|
||||
|
||||
PathIterator pathIterator(paths);
|
||||
|
||||
|
|
|
@ -47,7 +47,6 @@ Launcher::GraphicsPage::GraphicsPage(QWidget *parent)
|
|||
connect(screenComboBox, SIGNAL(currentIndexChanged(int)), this, SLOT(screenChanged(int)));
|
||||
connect(framerateLimitCheckBox, SIGNAL(toggled(bool)), this, SLOT(slotFramerateLimitToggled(bool)));
|
||||
connect(shadowDistanceCheckBox, SIGNAL(toggled(bool)), this, SLOT(slotShadowDistLimitToggled(bool)));
|
||||
|
||||
}
|
||||
|
||||
bool Launcher::GraphicsPage::setupSDL()
|
||||
|
|
|
@ -146,7 +146,6 @@ void Launcher::MainDialog::createPages()
|
|||
connect(mDataFilesPage, SIGNAL(signalProfileChanged(int)), mPlayPage, SLOT(setProfilesIndex(int)));
|
||||
// Using Qt::QueuedConnection because signal is emitted in a subthread and slot is in the main thread
|
||||
connect(mDataFilesPage, SIGNAL(signalLoadedCellsChanged(QStringList)), mAdvancedPage, SLOT(slotLoadedCellsChanged(QStringList)), Qt::QueuedConnection);
|
||||
|
||||
}
|
||||
|
||||
Launcher::FirstRunDialogResult Launcher::MainDialog::showFirstRunDialog()
|
||||
|
|
|
@ -10,6 +10,8 @@ QSet<QString> CellNameLoader::getCellNames(QStringList &contentPaths)
|
|||
|
||||
// Loop through all content files
|
||||
for (auto &contentPath : contentPaths) {
|
||||
if (contentPath.endsWith(".omwscripts", Qt::CaseInsensitive))
|
||||
continue;
|
||||
esmReader.open(contentPath.toStdString());
|
||||
|
||||
// Loop through all records
|
||||
|
@ -35,7 +37,7 @@ QSet<QString> CellNameLoader::getCellNames(QStringList &contentPaths)
|
|||
|
||||
bool CellNameLoader::isCellRecord(ESM::NAME &recordName)
|
||||
{
|
||||
return recordName.intval == ESM::REC_CELL;
|
||||
return recordName.toInt() == ESM::REC_CELL;
|
||||
}
|
||||
|
||||
QString CellNameLoader::getCellName(ESM::ESMReader &esmReader)
|
||||
|
|
|
@ -2,8 +2,8 @@
|
|||
|
||||
#include <iostream>
|
||||
#include <fstream>
|
||||
#include <cstdlib>
|
||||
|
||||
#include <components/misc/stringops.hpp>
|
||||
#include <components/nif/niffile.hpp>
|
||||
#include <components/files/constrainedfilestream.hpp>
|
||||
#include <components/vfs/manager.hpp>
|
||||
|
@ -18,18 +18,10 @@ namespace bpo = boost::program_options;
|
|||
namespace bfs = boost::filesystem;
|
||||
|
||||
///See if the file has the named extension
|
||||
bool hasExtension(std::string filename, std::string extensionToFind)
|
||||
bool hasExtension(std::string filename, std::string extensionToFind)
|
||||
{
|
||||
std::string extension = filename.substr(filename.find_last_of('.')+1);
|
||||
|
||||
//Convert strings to lower case for comparison
|
||||
std::transform(extension.begin(), extension.end(), extension.begin(), ::tolower);
|
||||
std::transform(extensionToFind.begin(), extensionToFind.end(), extensionToFind.begin(), ::tolower);
|
||||
|
||||
if(extension == extensionToFind)
|
||||
return true;
|
||||
else
|
||||
return false;
|
||||
return Misc::StringUtils::ciEqual(extension, extensionToFind);
|
||||
}
|
||||
|
||||
///See if the file has the "nif" extension.
|
||||
|
|
|
@ -183,8 +183,7 @@ if(APPLE)
|
|||
set(OPENCS_BUNDLE_NAME "OpenMW-CS")
|
||||
set(OPENCS_BUNDLE_RESOURCES_DIR "${OpenMW_BINARY_DIR}/${OPENCS_BUNDLE_NAME}.app/Contents/Resources")
|
||||
|
||||
set(OPENMW_MYGUI_FILES_ROOT ${OPENCS_BUNDLE_RESOURCES_DIR})
|
||||
set(OPENMW_SHADERS_ROOT ${OPENCS_BUNDLE_RESOURCES_DIR})
|
||||
set(OPENMW_RESOURCES_ROOT ${OPENCS_BUNDLE_RESOURCES_DIR})
|
||||
|
||||
add_subdirectory(../../files/ ${CMAKE_CURRENT_BINARY_DIR}/files)
|
||||
|
||||
|
|
|
@ -149,11 +149,7 @@ std::pair<Files::PathContainer, std::vector<std::string> > CS::Editor::readConfi
|
|||
dataDirs.insert (dataDirs.end(), dataLocal.begin(), dataLocal.end());
|
||||
|
||||
//iterate the data directories and add them to the file dialog for loading
|
||||
for (Files::PathContainer::const_reverse_iterator iter = dataDirs.rbegin(); iter != dataDirs.rend(); ++iter)
|
||||
{
|
||||
QString path = QString::fromUtf8 (iter->string().c_str());
|
||||
mFileDialog.addFiles(path);
|
||||
}
|
||||
mFileDialog.addFiles(dataDirs);
|
||||
|
||||
return std::make_pair (dataDirs, variables["fallback-archive"].as<std::vector<std::string>>());
|
||||
}
|
||||
|
|
|
@ -17,6 +17,19 @@
|
|||
#include "textnode.hpp"
|
||||
#include "valuenode.hpp"
|
||||
|
||||
namespace
|
||||
{
|
||||
bool isAlpha(char c)
|
||||
{
|
||||
return std::isalpha(static_cast<unsigned char>(c));
|
||||
}
|
||||
|
||||
bool isDigit(char c)
|
||||
{
|
||||
return std::isdigit(static_cast<unsigned char>(c));
|
||||
}
|
||||
}
|
||||
|
||||
namespace CSMFilter
|
||||
{
|
||||
struct Token
|
||||
|
@ -103,7 +116,7 @@ CSMFilter::Token CSMFilter::Parser::getStringToken()
|
|||
{
|
||||
char c = mInput[mIndex];
|
||||
|
||||
if (std::isalpha (c) || c==':' || c=='_' || (!string.empty() && std::isdigit (c)) || c=='"' ||
|
||||
if (isAlpha(c) || c==':' || c=='_' || (!string.empty() && isDigit(c)) || c=='"' ||
|
||||
(!string.empty() && string[0]=='"'))
|
||||
string += c;
|
||||
else
|
||||
|
@ -150,7 +163,7 @@ CSMFilter::Token CSMFilter::Parser::getNumberToken()
|
|||
{
|
||||
char c = mInput[mIndex];
|
||||
|
||||
if (std::isdigit (c))
|
||||
if (isDigit(c))
|
||||
{
|
||||
string += c;
|
||||
hasDigit = true;
|
||||
|
@ -225,10 +238,10 @@ CSMFilter::Token CSMFilter::Parser::getNextToken()
|
|||
case '!': ++mIndex; return Token (Token::Type_OneShot);
|
||||
}
|
||||
|
||||
if (c=='"' || c=='_' || std::isalpha (c) || c==':')
|
||||
if (c=='"' || c=='_' || isAlpha(c) || c==':')
|
||||
return getStringToken();
|
||||
|
||||
if (c=='-' || c=='.' || std::isdigit (c))
|
||||
if (c=='-' || c=='.' || isDigit(c))
|
||||
return getNumberToken();
|
||||
|
||||
error();
|
||||
|
|
|
@ -395,12 +395,12 @@ bool CSMTools::TopicInfoCheckStage::verifyId(const std::string& name, const CSMW
|
|||
|
||||
if (index == -1)
|
||||
{
|
||||
messages.add(id, T::getRecordType() + " '" + name + "' does not exist", "", CSMDoc::Message::Severity_Error);
|
||||
messages.add(id, std::string(T::getRecordType()) + " '" + name + "' does not exist", "", CSMDoc::Message::Severity_Error);
|
||||
return false;
|
||||
}
|
||||
else if (collection.getRecord(index).isDeleted())
|
||||
{
|
||||
messages.add(id, "Deleted " + T::getRecordType() + " record '" + name + "' is being referenced", "", CSMDoc::Message::Severity_Error);
|
||||
messages.add(id, "Deleted " + std::string(T::getRecordType()) + " record '" + name + "' is being referenced", "", CSMDoc::Message::Severity_Error);
|
||||
return false;
|
||||
}
|
||||
|
||||
|
|
|
@ -296,7 +296,7 @@ namespace CSMWorld
|
|||
const std::string& destination, const UniversalId::Type type)
|
||||
{
|
||||
int index = cloneRecordImp(origin, destination, type);
|
||||
mRecords.at(index)->get().mPlugin = 0;
|
||||
mRecords.at(index)->get().setPlugin(0);
|
||||
}
|
||||
|
||||
template<typename ESXRecordT, typename IdAccessorT>
|
||||
|
@ -311,7 +311,7 @@ namespace CSMWorld
|
|||
int index = touchRecordImp(id);
|
||||
if (index >= 0)
|
||||
{
|
||||
mRecords.at(index)->get().mPlugin = 0;
|
||||
mRecords.at(index)->get().setPlugin(0);
|
||||
return true;
|
||||
}
|
||||
|
||||
|
|
|
@ -52,7 +52,7 @@ namespace CSMWorld
|
|||
|
||||
QVariant LandPluginIndexColumn::get(const Record<Land>& record) const
|
||||
{
|
||||
return record.get().mPlugin;
|
||||
return record.get().getPlugin();
|
||||
}
|
||||
|
||||
bool LandPluginIndexColumn::isEditable() const
|
||||
|
|
|
@ -255,7 +255,7 @@ namespace CSMWorld
|
|||
{ ColumnId_AiWanderDist, "Wander Dist" },
|
||||
{ ColumnId_AiDuration, "Ai Duration" },
|
||||
{ ColumnId_AiWanderToD, "Wander ToD" },
|
||||
{ ColumnId_AiWanderRepeat, "Wander Repeat" },
|
||||
{ ColumnId_AiWanderRepeat, "Ai Repeat" },
|
||||
{ ColumnId_AiActivateName, "Activate" },
|
||||
{ ColumnId_AiTargetId, "Target ID" },
|
||||
{ ColumnId_AiTargetCell, "Target Cell" },
|
||||
|
|
|
@ -1086,7 +1086,7 @@ bool CSMWorld::Data::continueLoading (CSMDoc::Messages& messages)
|
|||
|
||||
bool unhandledRecord = false;
|
||||
|
||||
switch (n.intval)
|
||||
switch (n.toInt())
|
||||
{
|
||||
case ESM::REC_GLOB: mGlobals.load (*mReader, mBase); break;
|
||||
case ESM::REC_GMST: mGmsts.load (*mReader, mBase); break;
|
||||
|
|
|
@ -8,6 +8,7 @@
|
|||
#include <stdexcept>
|
||||
|
||||
#include <components/esm/cellid.hpp>
|
||||
#include <components/misc/stringops.hpp>
|
||||
|
||||
#include "collectionbase.hpp"
|
||||
#include "columnbase.hpp"
|
||||
|
@ -354,8 +355,7 @@ CSMWorld::LandTextureIdTable::ImportResults CSMWorld::LandTextureIdTable::import
|
|||
for (int i = 0; i < idCollection()->getSize(); ++i)
|
||||
{
|
||||
auto& record = static_cast<const Record<LandTexture>&>(idCollection()->getRecord(i));
|
||||
std::string texture = record.get().mTexture;
|
||||
std::transform(texture.begin(), texture.end(), texture.begin(), tolower);
|
||||
std::string texture = Misc::StringUtils::lowerCase(record.get().mTexture);
|
||||
if (record.isModified())
|
||||
reverseLookupMap.emplace(texture, idCollection()->getId(i));
|
||||
}
|
||||
|
@ -376,8 +376,7 @@ CSMWorld::LandTextureIdTable::ImportResults CSMWorld::LandTextureIdTable::import
|
|||
|
||||
// Look for a pre-existing record
|
||||
auto& record = static_cast<const Record<LandTexture>&>(idCollection()->getRecord(oldRow));
|
||||
std::string texture = record.get().mTexture;
|
||||
std::transform(texture.begin(), texture.end(), texture.begin(), tolower);
|
||||
std::string texture = Misc::StringUtils::lowerCase(record.get().mTexture);
|
||||
auto searchIt = reverseLookupMap.find(texture);
|
||||
if (searchIt != reverseLookupMap.end())
|
||||
{
|
||||
|
|
|
@ -1678,7 +1678,7 @@ namespace CSMWorld
|
|||
newRow.mWander.mTimeOfDay = 0;
|
||||
for (int i = 0; i < 8; ++i)
|
||||
newRow.mWander.mIdle[i] = 0;
|
||||
newRow.mWander.mShouldRepeat = 0;
|
||||
newRow.mWander.mShouldRepeat = 1;
|
||||
newRow.mCellName = "";
|
||||
|
||||
if (position >= (int)list.size())
|
||||
|
@ -1784,9 +1784,15 @@ namespace CSMWorld
|
|||
return static_cast<int>(content.mWander.mIdle[subColIndex-4]);
|
||||
else
|
||||
return QVariant();
|
||||
case 12: // wander repeat
|
||||
case 12: // repeat
|
||||
if (content.mType == ESM::AI_Wander)
|
||||
return content.mWander.mShouldRepeat != 0;
|
||||
else if (content.mType == ESM::AI_Travel)
|
||||
return content.mTravel.mShouldRepeat != 0;
|
||||
else if (content.mType == ESM::AI_Follow || content.mType == ESM::AI_Escort)
|
||||
return content.mTarget.mShouldRepeat != 0;
|
||||
else if (content.mType == ESM::AI_Activate)
|
||||
return content.mActivate.mShouldRepeat != 0;
|
||||
else
|
||||
return QVariant();
|
||||
case 13: // activate name
|
||||
|
@ -1895,6 +1901,12 @@ namespace CSMWorld
|
|||
case 12:
|
||||
if (content.mType == ESM::AI_Wander)
|
||||
content.mWander.mShouldRepeat = static_cast<unsigned char>(value.toInt());
|
||||
else if (content.mType == ESM::AI_Travel)
|
||||
content.mTravel.mShouldRepeat = static_cast<unsigned char>(value.toInt());
|
||||
else if (content.mType == ESM::AI_Follow || content.mType == ESM::AI_Escort)
|
||||
content.mTarget.mShouldRepeat = static_cast<unsigned char>(value.toInt());
|
||||
else if (content.mType == ESM::AI_Activate)
|
||||
content.mActivate.mShouldRepeat = static_cast<unsigned char>(value.toInt());
|
||||
else
|
||||
return; // return without saving
|
||||
|
||||
|
|
|
@ -102,11 +102,6 @@ bool CSMWorld::ScriptContext::isId (const std::string& name) const
|
|||
return std::binary_search (mIds.begin(), mIds.end(), Misc::StringUtils::lowerCase (name));
|
||||
}
|
||||
|
||||
bool CSMWorld::ScriptContext::isJournalId (const std::string& name) const
|
||||
{
|
||||
return mData.getJournals().searchId (name)!=-1;
|
||||
}
|
||||
|
||||
void CSMWorld::ScriptContext::invalidateIds()
|
||||
{
|
||||
mIdsUpdated = false;
|
||||
|
|
|
@ -39,9 +39,6 @@ namespace CSMWorld
|
|||
bool isId (const std::string& name) const override;
|
||||
///< Does \a name match an ID, that can be referenced?
|
||||
|
||||
bool isJournalId (const std::string& name) const override;
|
||||
///< Does \a name match a journal ID?
|
||||
|
||||
void invalidateIds();
|
||||
|
||||
void clear();
|
||||
|
|
|
@ -24,13 +24,18 @@ CSVDoc::FileDialog::FileDialog(QWidget *parent) :
|
|||
resize(400, 400);
|
||||
|
||||
setObjectName ("FileDialog");
|
||||
mSelector = new ContentSelectorView::ContentSelector (ui.contentSelectorWidget);
|
||||
mSelector = new ContentSelectorView::ContentSelector (ui.contentSelectorWidget, /*showOMWScripts=*/false);
|
||||
mAdjusterWidget = new AdjusterWidget (this);
|
||||
}
|
||||
|
||||
void CSVDoc::FileDialog::addFiles(const QString &path)
|
||||
void CSVDoc::FileDialog::addFiles(const std::vector<boost::filesystem::path>& dataDirs)
|
||||
{
|
||||
mSelector->addFiles(path);
|
||||
for (auto iter = dataDirs.rbegin(); iter != dataDirs.rend(); ++iter)
|
||||
{
|
||||
QString path = QString::fromUtf8(iter->string().c_str());
|
||||
mSelector->addFiles(path);
|
||||
}
|
||||
mSelector->sortFiles();
|
||||
}
|
||||
|
||||
void CSVDoc::FileDialog::setEncoding(const QString &encoding)
|
||||
|
|
|
@ -45,7 +45,7 @@ namespace CSVDoc
|
|||
explicit FileDialog(QWidget *parent = nullptr);
|
||||
void showDialog (ContentAction action);
|
||||
|
||||
void addFiles (const QString &path);
|
||||
void addFiles(const std::vector<boost::filesystem::path>& dataDirs);
|
||||
void setEncoding (const QString &encoding);
|
||||
void clearFiles ();
|
||||
|
||||
|
|
|
@ -111,7 +111,7 @@ namespace CSVRender
|
|||
if (!mesh.empty() && node != mNodeMap.end())
|
||||
{
|
||||
auto instance = sceneMgr->getInstance(mesh);
|
||||
SceneUtil::attach(instance, mSkeleton, boneName, node->second);
|
||||
SceneUtil::attach(instance, mSkeleton, boneName, node->second, sceneMgr);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -308,7 +308,7 @@ osg::ref_ptr<osg::Node> CSVRender::Object::makeRotateMarker (int axis)
|
|||
const float OuterRadius = InnerRadius + MarkerShaftWidth;
|
||||
|
||||
const float SegmentDistance = 100.f;
|
||||
const size_t SegmentCount = std::min(64, std::max(24, (int)(OuterRadius * 2 * osg::PI / SegmentDistance)));
|
||||
const size_t SegmentCount = std::clamp<int>(OuterRadius * 2 * osg::PI / SegmentDistance, 24, 64);
|
||||
const size_t VerticesPerSegment = 4;
|
||||
const size_t IndicesPerSegment = 24;
|
||||
|
||||
|
|
|
@ -16,11 +16,13 @@
|
|||
#include "worldspacewidget.hpp"
|
||||
|
||||
CSVRender::TerrainSelection::TerrainSelection(osg::Group* parentNode, WorldspaceWidget *worldspaceWidget, TerrainSelectionType type):
|
||||
mParentNode(parentNode), mWorldspaceWidget (worldspaceWidget), mDraggedOperationFlag(false), mSelectionType(type)
|
||||
mParentNode(parentNode), mWorldspaceWidget (worldspaceWidget), mSelectionType(type)
|
||||
{
|
||||
mGeometry = new osg::Geometry();
|
||||
|
||||
mSelectionNode = new osg::Group();
|
||||
mSelectionNode->getOrCreateStateSet()->setMode(GL_DEPTH_TEST, osg::StateAttribute::OFF);
|
||||
mSelectionNode->getOrCreateStateSet()->setRenderBinDetails(11, "RenderBin");
|
||||
mSelectionNode->addChild(mGeometry);
|
||||
|
||||
activate();
|
||||
|
@ -43,19 +45,24 @@ void CSVRender::TerrainSelection::onlySelect(const std::vector<std::pair<int, in
|
|||
update();
|
||||
}
|
||||
|
||||
void CSVRender::TerrainSelection::addSelect(const std::vector<std::pair<int, int>>& localPositions, bool toggleInProgress)
|
||||
void CSVRender::TerrainSelection::addSelect(const std::vector<std::pair<int, int>>& localPositions)
|
||||
{
|
||||
handleSelection(localPositions, toggleInProgress, SelectionMethod::AddSelect);
|
||||
handleSelection(localPositions, SelectionMethod::AddSelect);
|
||||
}
|
||||
|
||||
void CSVRender::TerrainSelection::removeSelect(const std::vector<std::pair<int, int>>& localPositions, bool toggleInProgress)
|
||||
void CSVRender::TerrainSelection::removeSelect(const std::vector<std::pair<int, int>>& localPositions)
|
||||
{
|
||||
handleSelection(localPositions, toggleInProgress, SelectionMethod::RemoveSelect);
|
||||
handleSelection(localPositions, SelectionMethod::RemoveSelect);
|
||||
}
|
||||
|
||||
void CSVRender::TerrainSelection::toggleSelect(const std::vector<std::pair<int, int>>& localPositions, bool toggleInProgress)
|
||||
void CSVRender::TerrainSelection::toggleSelect(const std::vector<std::pair<int, int>>& localPositions)
|
||||
{
|
||||
handleSelection(localPositions, toggleInProgress, SelectionMethod::ToggleSelect);
|
||||
handleSelection(localPositions, SelectionMethod::ToggleSelect);
|
||||
}
|
||||
|
||||
void CSVRender::TerrainSelection::clearTemporarySelection()
|
||||
{
|
||||
mTemporarySelection.clear();
|
||||
}
|
||||
|
||||
void CSVRender::TerrainSelection::activate()
|
||||
|
@ -102,26 +109,16 @@ void CSVRender::TerrainSelection::drawShapeSelection(const osg::ref_ptr<osg::Vec
|
|||
float xWorldCoord(CSMWorld::CellCoordinates::vertexGlobalToWorldCoords(x));
|
||||
float yWorldCoord(CSMWorld::CellCoordinates::vertexGlobalToWorldCoords(y));
|
||||
|
||||
osg::Vec3f pointXY(xWorldCoord, yWorldCoord, calculateLandHeight(x, y) + 2);
|
||||
osg::Vec3f pointXY(xWorldCoord, yWorldCoord, calculateLandHeight(x, y));
|
||||
|
||||
vertices->push_back(pointXY);
|
||||
vertices->push_back(osg::Vec3f(xWorldCoord, CSMWorld::CellCoordinates::vertexGlobalToWorldCoords(y - 1), calculateLandHeight(x, y - 1) + 2));
|
||||
vertices->push_back(osg::Vec3f(xWorldCoord, CSMWorld::CellCoordinates::vertexGlobalToWorldCoords(y - 1), calculateLandHeight(x, y - 1)));
|
||||
vertices->push_back(pointXY);
|
||||
vertices->push_back(osg::Vec3f(CSMWorld::CellCoordinates::vertexGlobalToWorldCoords(x - 1), yWorldCoord, calculateLandHeight(x - 1, y) + 2));
|
||||
|
||||
const auto north = std::find(mSelection.begin(), mSelection.end(), std::make_pair(x, y + 1));
|
||||
if (north == mSelection.end())
|
||||
{
|
||||
vertices->push_back(pointXY);
|
||||
vertices->push_back(osg::Vec3f(xWorldCoord, CSMWorld::CellCoordinates::vertexGlobalToWorldCoords(y + 1), calculateLandHeight(x, y + 1) + 2));
|
||||
}
|
||||
|
||||
const auto east = std::find(mSelection.begin(), mSelection.end(), std::make_pair(x + 1, y));
|
||||
if (east == mSelection.end())
|
||||
{
|
||||
vertices->push_back(pointXY);
|
||||
vertices->push_back(osg::Vec3f(CSMWorld::CellCoordinates::vertexGlobalToWorldCoords(x + 1), yWorldCoord, calculateLandHeight(x + 1, y) + 2));
|
||||
}
|
||||
vertices->push_back(osg::Vec3f(CSMWorld::CellCoordinates::vertexGlobalToWorldCoords(x - 1), yWorldCoord, calculateLandHeight(x - 1, y)));
|
||||
vertices->push_back(pointXY);
|
||||
vertices->push_back(osg::Vec3f(xWorldCoord, CSMWorld::CellCoordinates::vertexGlobalToWorldCoords(y + 1), calculateLandHeight(x, y + 1)));
|
||||
vertices->push_back(pointXY);
|
||||
vertices->push_back(osg::Vec3f(CSMWorld::CellCoordinates::vertexGlobalToWorldCoords(x + 1), yWorldCoord, calculateLandHeight(x + 1, y)));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -154,8 +151,8 @@ void CSVRender::TerrainSelection::drawTextureSelection(const osg::ref_ptr<osg::V
|
|||
{
|
||||
float drawPreviousX = CSMWorld::CellCoordinates::textureGlobalXToWorldCoords(x) + (i - 1) * (ESM::Land::REAL_SIZE / (ESM::Land::LAND_SIZE - 1));
|
||||
float drawCurrentX = CSMWorld::CellCoordinates::textureGlobalXToWorldCoords(x) + i * (ESM::Land::REAL_SIZE / (ESM::Land::LAND_SIZE - 1));
|
||||
vertices->push_back(osg::Vec3f(drawPreviousX, CSMWorld::CellCoordinates::textureGlobalYToWorldCoords(y + 1), calculateLandHeight(x1+(i-1), y2)+2));
|
||||
vertices->push_back(osg::Vec3f(drawCurrentX, CSMWorld::CellCoordinates::textureGlobalYToWorldCoords(y + 1), calculateLandHeight(x1+i, y2)+2));
|
||||
vertices->push_back(osg::Vec3f(drawPreviousX, CSMWorld::CellCoordinates::textureGlobalYToWorldCoords(y + 1), calculateLandHeight(x1+(i-1), y2)));
|
||||
vertices->push_back(osg::Vec3f(drawCurrentX, CSMWorld::CellCoordinates::textureGlobalYToWorldCoords(y + 1), calculateLandHeight(x1+i, y2)));
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -166,8 +163,8 @@ void CSVRender::TerrainSelection::drawTextureSelection(const osg::ref_ptr<osg::V
|
|||
{
|
||||
float drawPreviousX = CSMWorld::CellCoordinates::textureGlobalXToWorldCoords(x) + (i - 1) *(ESM::Land::REAL_SIZE / (ESM::Land::LAND_SIZE - 1));
|
||||
float drawCurrentX = CSMWorld::CellCoordinates::textureGlobalXToWorldCoords(x) + i * (ESM::Land::REAL_SIZE / (ESM::Land::LAND_SIZE - 1));
|
||||
vertices->push_back(osg::Vec3f(drawPreviousX, CSMWorld::CellCoordinates::textureGlobalYToWorldCoords(y), calculateLandHeight(x1+(i-1), y1)+2));
|
||||
vertices->push_back(osg::Vec3f(drawCurrentX, CSMWorld::CellCoordinates::textureGlobalYToWorldCoords(y), calculateLandHeight(x1+i, y1)+2));
|
||||
vertices->push_back(osg::Vec3f(drawPreviousX, CSMWorld::CellCoordinates::textureGlobalYToWorldCoords(y), calculateLandHeight(x1+(i-1), y1)));
|
||||
vertices->push_back(osg::Vec3f(drawCurrentX, CSMWorld::CellCoordinates::textureGlobalYToWorldCoords(y), calculateLandHeight(x1+i, y1)));
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -178,8 +175,8 @@ void CSVRender::TerrainSelection::drawTextureSelection(const osg::ref_ptr<osg::V
|
|||
{
|
||||
float drawPreviousY = CSMWorld::CellCoordinates::textureGlobalYToWorldCoords(y) + (i - 1) * (ESM::Land::REAL_SIZE / (ESM::Land::LAND_SIZE - 1));
|
||||
float drawCurrentY = CSMWorld::CellCoordinates::textureGlobalYToWorldCoords(y) + i * (ESM::Land::REAL_SIZE / (ESM::Land::LAND_SIZE - 1));
|
||||
vertices->push_back(osg::Vec3f(CSMWorld::CellCoordinates::textureGlobalXToWorldCoords(x + 1), drawPreviousY, calculateLandHeight(x2, y1+(i-1))+2));
|
||||
vertices->push_back(osg::Vec3f(CSMWorld::CellCoordinates::textureGlobalXToWorldCoords(x + 1), drawCurrentY, calculateLandHeight(x2, y1+i)+2));
|
||||
vertices->push_back(osg::Vec3f(CSMWorld::CellCoordinates::textureGlobalXToWorldCoords(x + 1), drawPreviousY, calculateLandHeight(x2, y1+(i-1))));
|
||||
vertices->push_back(osg::Vec3f(CSMWorld::CellCoordinates::textureGlobalXToWorldCoords(x + 1), drawCurrentY, calculateLandHeight(x2, y1+i)));
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -190,44 +187,44 @@ void CSVRender::TerrainSelection::drawTextureSelection(const osg::ref_ptr<osg::V
|
|||
{
|
||||
float drawPreviousY = CSMWorld::CellCoordinates::textureGlobalYToWorldCoords(y) + (i - 1) * (ESM::Land::REAL_SIZE / (ESM::Land::LAND_SIZE - 1));
|
||||
float drawCurrentY = CSMWorld::CellCoordinates::textureGlobalYToWorldCoords(y) + i * (ESM::Land::REAL_SIZE / (ESM::Land::LAND_SIZE - 1));
|
||||
vertices->push_back(osg::Vec3f(CSMWorld::CellCoordinates::textureGlobalXToWorldCoords(x), drawPreviousY, calculateLandHeight(x1, y1+(i-1))+2));
|
||||
vertices->push_back(osg::Vec3f(CSMWorld::CellCoordinates::textureGlobalXToWorldCoords(x), drawCurrentY, calculateLandHeight(x1, y1+i)+2));
|
||||
vertices->push_back(osg::Vec3f(CSMWorld::CellCoordinates::textureGlobalXToWorldCoords(x), drawPreviousY, calculateLandHeight(x1, y1+(i-1))));
|
||||
vertices->push_back(osg::Vec3f(CSMWorld::CellCoordinates::textureGlobalXToWorldCoords(x), drawCurrentY, calculateLandHeight(x1, y1+i)));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void CSVRender::TerrainSelection::handleSelection(const std::vector<std::pair<int, int>>& localPositions, bool toggleInProgress, SelectionMethod selectionMethod)
|
||||
void CSVRender::TerrainSelection::handleSelection(const std::vector<std::pair<int, int>>& localPositions, SelectionMethod selectionMethod)
|
||||
{
|
||||
if (toggleInProgress)
|
||||
for (auto const& localPos : localPositions)
|
||||
{
|
||||
for (auto const& localPos : localPositions)
|
||||
const auto iter = std::find(mSelection.begin(), mSelection.end(), localPos);
|
||||
|
||||
switch (selectionMethod)
|
||||
{
|
||||
auto iterTemp = std::find(mTemporarySelection.begin(), mTemporarySelection.end(), localPos);
|
||||
mDraggedOperationFlag = true;
|
||||
case SelectionMethod::OnlySelect:
|
||||
break;
|
||||
|
||||
if (iterTemp == mTemporarySelection.end())
|
||||
{
|
||||
auto iter = std::find(mSelection.begin(), mSelection.end(), localPos);
|
||||
|
||||
switch (selectionMethod)
|
||||
case SelectionMethod::AddSelect:
|
||||
if (iter == mSelection.end())
|
||||
{
|
||||
case SelectionMethod::AddSelect:
|
||||
if (iter == mSelection.end())
|
||||
{
|
||||
mSelection.emplace_back(localPos);
|
||||
}
|
||||
mSelection.emplace_back(localPos);
|
||||
}
|
||||
break;
|
||||
|
||||
break;
|
||||
case SelectionMethod::RemoveSelect:
|
||||
if (iter != mSelection.end())
|
||||
{
|
||||
mSelection.erase(iter);
|
||||
}
|
||||
case SelectionMethod::RemoveSelect:
|
||||
if (iter != mSelection.end())
|
||||
{
|
||||
mSelection.erase(iter);
|
||||
}
|
||||
break;
|
||||
|
||||
break;
|
||||
case SelectionMethod::ToggleSelect:
|
||||
case SelectionMethod::ToggleSelect:
|
||||
{
|
||||
const auto iterTemp = std::find(mTemporarySelection.begin(), mTemporarySelection.end(), localPos);
|
||||
if (iterTemp == mTemporarySelection.end())
|
||||
{
|
||||
if (iter == mSelection.end())
|
||||
{
|
||||
mSelection.emplace_back(localPos);
|
||||
|
@ -236,58 +233,15 @@ void CSVRender::TerrainSelection::handleSelection(const std::vector<std::pair<in
|
|||
{
|
||||
mSelection.erase(iter);
|
||||
}
|
||||
|
||||
break;
|
||||
default: break;
|
||||
}
|
||||
mTemporarySelection.emplace_back(localPos);
|
||||
break;
|
||||
}
|
||||
|
||||
mTemporarySelection.push_back(localPos);
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
else if (mDraggedOperationFlag == false)
|
||||
{
|
||||
for (auto const& localPos : localPositions)
|
||||
{
|
||||
const auto iter = std::find(mSelection.begin(), mSelection.end(), localPos);
|
||||
|
||||
switch (selectionMethod)
|
||||
{
|
||||
case SelectionMethod::AddSelect:
|
||||
if (iter == mSelection.end())
|
||||
{
|
||||
mSelection.emplace_back(localPos);
|
||||
}
|
||||
|
||||
break;
|
||||
case SelectionMethod::RemoveSelect:
|
||||
if (iter != mSelection.end())
|
||||
{
|
||||
mSelection.erase(iter);
|
||||
}
|
||||
|
||||
break;
|
||||
case SelectionMethod::ToggleSelect:
|
||||
if (iter == mSelection.end())
|
||||
{
|
||||
mSelection.emplace_back(localPos);
|
||||
}
|
||||
else
|
||||
{
|
||||
mSelection.erase(iter);
|
||||
}
|
||||
|
||||
break;
|
||||
default: break;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
mDraggedOperationFlag = false;
|
||||
|
||||
mTemporarySelection.clear();
|
||||
}
|
||||
|
||||
update();
|
||||
}
|
||||
|
@ -336,11 +290,9 @@ int CSVRender::TerrainSelection::calculateLandHeight(int x, int y) // global ver
|
|||
else if (isLandLoaded(CSMWorld::CellCoordinates::generateId(cellX, cellY)))
|
||||
{
|
||||
CSMDoc::Document& document = mWorldspaceWidget->getDocument();
|
||||
CSMWorld::IdTable& landTable = dynamic_cast<CSMWorld::IdTable&> ( *document.getData().getTableModel (CSMWorld::UniversalId::Type_Land));
|
||||
std::string cellId = CSMWorld::CellCoordinates::generateId(cellX, cellY);
|
||||
int landshapeColumn = landTable.findColumnIndex(CSMWorld::Columns::ColumnId_LandHeightsIndex);
|
||||
const CSMWorld::LandHeightsColumn::DataType mPointer = landTable.data(landTable.getModelIndex(cellId, landshapeColumn)).value<CSMWorld::LandHeightsColumn::DataType>();
|
||||
return mPointer[localY*ESM::Land::LAND_SIZE + localX];
|
||||
const ESM::Land::LandData* landData = document.getData().getLand().getRecord(cellId).get().getLandData(ESM::Land::DATA_VHGT);
|
||||
return landData->mHeights[localY*ESM::Land::LAND_SIZE + localX];
|
||||
}
|
||||
|
||||
return landHeight;
|
||||
|
|
|
@ -44,9 +44,10 @@ namespace CSVRender
|
|||
~TerrainSelection();
|
||||
|
||||
void onlySelect(const std::vector<std::pair<int, int>> &localPositions);
|
||||
void addSelect(const std::vector<std::pair<int, int>>& localPositions, bool toggleInProgress);
|
||||
void removeSelect(const std::vector<std::pair<int, int>>& localPositions, bool toggleInProgress);
|
||||
void toggleSelect(const std::vector<std::pair<int, int>> &localPositions, bool toggleInProgress);
|
||||
void addSelect(const std::vector<std::pair<int, int>>& localPositions);
|
||||
void removeSelect(const std::vector<std::pair<int, int>>& localPositions);
|
||||
void toggleSelect(const std::vector<std::pair<int, int>> &localPositions);
|
||||
void clearTemporarySelection();
|
||||
|
||||
void activate();
|
||||
void deactivate();
|
||||
|
@ -64,7 +65,7 @@ namespace CSVRender
|
|||
|
||||
private:
|
||||
|
||||
void handleSelection(const std::vector<std::pair<int, int>>& localPositions, bool toggleInProgress, SelectionMethod selectionMethod);
|
||||
void handleSelection(const std::vector<std::pair<int, int>>& localPositions, SelectionMethod selectionMethod);
|
||||
|
||||
bool noCell(const std::string& cellId);
|
||||
|
||||
|
@ -73,7 +74,7 @@ namespace CSVRender
|
|||
bool noLandLoaded(const std::string& cellId);
|
||||
|
||||
bool isLandLoaded(const std::string& cellId);
|
||||
|
||||
|
||||
osg::Group* mParentNode;
|
||||
WorldspaceWidget *mWorldspaceWidget;
|
||||
osg::ref_ptr<osg::PositionAttitudeTransform> mBaseNode;
|
||||
|
@ -81,7 +82,6 @@ namespace CSVRender
|
|||
osg::ref_ptr<osg::Group> mSelectionNode;
|
||||
std::vector<std::pair<int, int>> mSelection; // Global terrain selection coordinate in either vertex or texture units
|
||||
std::vector<std::pair<int, int>> mTemporarySelection; // Used during toggle to compare the most recent drag operation
|
||||
bool mDraggedOperationFlag; //true during drag operation, false when click-operation
|
||||
TerrainSelectionType mSelectionType;
|
||||
};
|
||||
}
|
||||
|
|
|
@ -106,16 +106,6 @@ void CSVRender::TerrainShapeMode::primaryEditPressed(const WorldspaceHitResult&
|
|||
editTerrainShapeGrid(CSMWorld::CellCoordinates::toVertexCoords(hit.worldPos), true);
|
||||
applyTerrainEditChanges();
|
||||
}
|
||||
|
||||
if (mDragMode == InteractionType_PrimarySelect)
|
||||
{
|
||||
selectTerrainShapes(CSMWorld::CellCoordinates::toVertexCoords(hit.worldPos), 0, true);
|
||||
}
|
||||
|
||||
if (mDragMode == InteractionType_SecondarySelect)
|
||||
{
|
||||
selectTerrainShapes(CSMWorld::CellCoordinates::toVertexCoords(hit.worldPos), 1, true);
|
||||
}
|
||||
}
|
||||
clearTransientEdits();
|
||||
}
|
||||
|
@ -124,7 +114,8 @@ void CSVRender::TerrainShapeMode::primarySelectPressed(const WorldspaceHitResult
|
|||
{
|
||||
if(hit.hit && hit.tag == nullptr)
|
||||
{
|
||||
selectTerrainShapes(CSMWorld::CellCoordinates::toVertexCoords(hit.worldPos), 0, false);
|
||||
selectTerrainShapes(CSMWorld::CellCoordinates::toVertexCoords(hit.worldPos), 0);
|
||||
mTerrainShapeSelection->clearTemporarySelection();
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -132,7 +123,8 @@ void CSVRender::TerrainShapeMode::secondarySelectPressed(const WorldspaceHitResu
|
|||
{
|
||||
if(hit.hit && hit.tag == nullptr)
|
||||
{
|
||||
selectTerrainShapes(CSMWorld::CellCoordinates::toVertexCoords(hit.worldPos), 1, false);
|
||||
selectTerrainShapes(CSMWorld::CellCoordinates::toVertexCoords(hit.worldPos), 1);
|
||||
mTerrainShapeSelection->clearTemporarySelection();
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -167,8 +159,8 @@ bool CSVRender::TerrainShapeMode::primarySelectStartDrag (const QPoint& pos)
|
|||
mDragMode = InteractionType_None;
|
||||
return false;
|
||||
}
|
||||
selectTerrainShapes(CSMWorld::CellCoordinates::toVertexCoords(hit.worldPos), 0, true);
|
||||
return false;
|
||||
selectTerrainShapes(CSMWorld::CellCoordinates::toVertexCoords(hit.worldPos), 0);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool CSVRender::TerrainShapeMode::secondarySelectStartDrag (const QPoint& pos)
|
||||
|
@ -180,8 +172,8 @@ bool CSVRender::TerrainShapeMode::secondarySelectStartDrag (const QPoint& pos)
|
|||
mDragMode = InteractionType_None;
|
||||
return false;
|
||||
}
|
||||
selectTerrainShapes(CSMWorld::CellCoordinates::toVertexCoords(hit.worldPos), 1, true);
|
||||
return false;
|
||||
selectTerrainShapes(CSMWorld::CellCoordinates::toVertexCoords(hit.worldPos), 1);
|
||||
return true;
|
||||
}
|
||||
|
||||
void CSVRender::TerrainShapeMode::drag (const QPoint& pos, int diffX, int diffY, double speedFactor)
|
||||
|
@ -200,13 +192,13 @@ void CSVRender::TerrainShapeMode::drag (const QPoint& pos, int diffX, int diffY,
|
|||
if (mDragMode == InteractionType_PrimarySelect)
|
||||
{
|
||||
WorldspaceHitResult hit = getWorldspaceWidget().mousePick (pos, getWorldspaceWidget().getInteractionMask());
|
||||
if (hit.hit && hit.tag == nullptr) selectTerrainShapes(CSMWorld::CellCoordinates::toVertexCoords(hit.worldPos), 0, true);
|
||||
if (hit.hit && hit.tag == nullptr) selectTerrainShapes(CSMWorld::CellCoordinates::toVertexCoords(hit.worldPos), 0);
|
||||
}
|
||||
|
||||
if (mDragMode == InteractionType_SecondarySelect)
|
||||
{
|
||||
WorldspaceHitResult hit = getWorldspaceWidget().mousePick (pos, getWorldspaceWidget().getInteractionMask());
|
||||
if (hit.hit && hit.tag == nullptr) selectTerrainShapes(CSMWorld::CellCoordinates::toVertexCoords(hit.worldPos), 1, true);
|
||||
if (hit.hit && hit.tag == nullptr) selectTerrainShapes(CSMWorld::CellCoordinates::toVertexCoords(hit.worldPos), 1);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -217,12 +209,17 @@ void CSVRender::TerrainShapeMode::dragCompleted(const QPoint& pos)
|
|||
applyTerrainEditChanges();
|
||||
clearTransientEdits();
|
||||
}
|
||||
if (mDragMode == InteractionType_PrimarySelect || mDragMode == InteractionType_SecondarySelect)
|
||||
{
|
||||
mTerrainShapeSelection->clearTemporarySelection();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void CSVRender::TerrainShapeMode::dragAborted()
|
||||
{
|
||||
clearTransientEdits();
|
||||
mDragMode = InteractionType_None;
|
||||
}
|
||||
|
||||
void CSVRender::TerrainShapeMode::dragWheel (int diff, double speedFactor)
|
||||
|
@ -1076,7 +1073,7 @@ void CSVRender::TerrainShapeMode::handleSelection(int globalSelectionX, int glob
|
|||
}
|
||||
}
|
||||
|
||||
void CSVRender::TerrainShapeMode::selectTerrainShapes(const std::pair<int, int>& vertexCoords, unsigned char selectMode, bool dragOperation)
|
||||
void CSVRender::TerrainShapeMode::selectTerrainShapes(const std::pair<int, int>& vertexCoords, unsigned char selectMode)
|
||||
{
|
||||
int r = mBrushSize / 2;
|
||||
std::vector<std::pair<int, int>> selections;
|
||||
|
@ -1136,11 +1133,11 @@ void CSVRender::TerrainShapeMode::selectTerrainShapes(const std::pair<int, int>&
|
|||
if (selectAction == "Select only")
|
||||
mTerrainShapeSelection->onlySelect(selections);
|
||||
else if (selectAction == "Add to selection")
|
||||
mTerrainShapeSelection->addSelect(selections, dragOperation);
|
||||
mTerrainShapeSelection->addSelect(selections);
|
||||
else if (selectAction == "Remove from selection")
|
||||
mTerrainShapeSelection->removeSelect(selections, dragOperation);
|
||||
mTerrainShapeSelection->removeSelect(selections);
|
||||
else if (selectAction == "Invert selection")
|
||||
mTerrainShapeSelection->toggleSelect(selections, dragOperation);
|
||||
mTerrainShapeSelection->toggleSelect(selections);
|
||||
}
|
||||
|
||||
void CSVRender::TerrainShapeMode::pushEditToCommand(const CSMWorld::LandHeightsColumn::DataType& newLandGrid, CSMDoc::Document& document,
|
||||
|
|
|
@ -142,7 +142,7 @@ namespace CSVRender
|
|||
void handleSelection(int globalSelectionX, int globalSelectionY, std::vector<std::pair<int, int>>* selections);
|
||||
|
||||
/// Handle brush mechanics for terrain shape selection
|
||||
void selectTerrainShapes (const std::pair<int, int>& vertexCoords, unsigned char selectMode, bool dragOperation);
|
||||
void selectTerrainShapes (const std::pair<int, int>& vertexCoords, unsigned char selectMode);
|
||||
|
||||
/// Push terrain shape edits to command macro
|
||||
void pushEditToCommand (const CSMWorld::LandHeightsColumn::DataType& newLandGrid, CSMDoc::Document& document,
|
||||
|
|
|
@ -48,15 +48,14 @@ namespace CSVRender
|
|||
float TerrainStorage::getSumOfAlteredAndTrueHeight(int cellX, int cellY, int inCellX, int inCellY)
|
||||
{
|
||||
float height = 0.f;
|
||||
osg::ref_ptr<const ESMTerrain::LandObject> land = getLand (cellX, cellY);
|
||||
if (land)
|
||||
{
|
||||
const ESM::Land::LandData* data = land ? land->getData(ESM::Land::DATA_VHGT) : nullptr;
|
||||
if (data) height = getVertexHeight(data, inCellX, inCellY);
|
||||
}
|
||||
else return height;
|
||||
return mAlteredHeight[inCellY*ESM::Land::LAND_SIZE + inCellX] + height;
|
||||
|
||||
int index = mData.getLand().searchId(CSMWorld::Land::createUniqueRecordId(cellX, cellY));
|
||||
if (index == -1) // no land!
|
||||
return height;
|
||||
|
||||
const ESM::Land::LandData* landData = mData.getLand().getRecord(index).get().getLandData(ESM::Land::DATA_VHGT);
|
||||
height = landData->mHeights[inCellY*ESM::Land::LAND_SIZE + inCellX];
|
||||
return mAlteredHeight[inCellY*ESM::Land::LAND_SIZE + inCellX] + height;
|
||||
}
|
||||
|
||||
float* TerrainStorage::getAlteredHeight(int inCellX, int inCellY)
|
||||
|
|
|
@ -129,7 +129,8 @@ void CSVRender::TerrainTextureMode::primarySelectPressed(const WorldspaceHitResu
|
|||
{
|
||||
if(hit.hit && hit.tag == nullptr)
|
||||
{
|
||||
selectTerrainTextures(CSMWorld::CellCoordinates::toTextureCoords(hit.worldPos), 0, false);
|
||||
selectTerrainTextures(CSMWorld::CellCoordinates::toTextureCoords(hit.worldPos), 0);
|
||||
mTerrainTextureSelection->clearTemporarySelection();
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -137,7 +138,8 @@ void CSVRender::TerrainTextureMode::secondarySelectPressed(const WorldspaceHitRe
|
|||
{
|
||||
if(hit.hit && hit.tag == nullptr)
|
||||
{
|
||||
selectTerrainTextures(CSMWorld::CellCoordinates::toTextureCoords(hit.worldPos), 1, false);
|
||||
selectTerrainTextures(CSMWorld::CellCoordinates::toTextureCoords(hit.worldPos), 1);
|
||||
mTerrainTextureSelection->clearTemporarySelection();
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -188,8 +190,8 @@ bool CSVRender::TerrainTextureMode::primarySelectStartDrag (const QPoint& pos)
|
|||
mDragMode = InteractionType_None;
|
||||
return false;
|
||||
}
|
||||
selectTerrainTextures(CSMWorld::CellCoordinates::toTextureCoords(hit.worldPos), 0, true);
|
||||
return false;
|
||||
selectTerrainTextures(CSMWorld::CellCoordinates::toTextureCoords(hit.worldPos), 0);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool CSVRender::TerrainTextureMode::secondarySelectStartDrag (const QPoint& pos)
|
||||
|
@ -201,8 +203,8 @@ bool CSVRender::TerrainTextureMode::secondarySelectStartDrag (const QPoint& pos)
|
|||
mDragMode = InteractionType_None;
|
||||
return false;
|
||||
}
|
||||
selectTerrainTextures(CSMWorld::CellCoordinates::toTextureCoords(hit.worldPos), 1, true);
|
||||
return false;
|
||||
selectTerrainTextures(CSMWorld::CellCoordinates::toTextureCoords(hit.worldPos), 1);
|
||||
return true;
|
||||
}
|
||||
|
||||
void CSVRender::TerrainTextureMode::drag (const QPoint& pos, int diffX, int diffY, double speedFactor)
|
||||
|
@ -225,13 +227,13 @@ void CSVRender::TerrainTextureMode::drag (const QPoint& pos, int diffX, int diff
|
|||
if (mDragMode == InteractionType_PrimarySelect)
|
||||
{
|
||||
WorldspaceHitResult hit = getWorldspaceWidget().mousePick (pos, getWorldspaceWidget().getInteractionMask());
|
||||
if (hit.hit && hit.tag == nullptr) selectTerrainTextures(CSMWorld::CellCoordinates::toTextureCoords(hit.worldPos), 0, true);
|
||||
if (hit.hit && hit.tag == nullptr) selectTerrainTextures(CSMWorld::CellCoordinates::toTextureCoords(hit.worldPos), 0);
|
||||
}
|
||||
|
||||
if (mDragMode == InteractionType_SecondarySelect)
|
||||
{
|
||||
WorldspaceHitResult hit = getWorldspaceWidget().mousePick (pos, getWorldspaceWidget().getInteractionMask());
|
||||
if (hit.hit && hit.tag == nullptr) selectTerrainTextures(CSMWorld::CellCoordinates::toTextureCoords(hit.worldPos), 1, true);
|
||||
if (hit.hit && hit.tag == nullptr) selectTerrainTextures(CSMWorld::CellCoordinates::toTextureCoords(hit.worldPos), 1);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -251,6 +253,8 @@ void CSVRender::TerrainTextureMode::dragCompleted(const QPoint& pos)
|
|||
mIsEditing = false;
|
||||
}
|
||||
}
|
||||
|
||||
mTerrainTextureSelection->clearTemporarySelection();
|
||||
}
|
||||
|
||||
void CSVRender::TerrainTextureMode::dragAborted()
|
||||
|
@ -496,7 +500,7 @@ bool CSVRender::TerrainTextureMode::isInCellSelection(int globalSelectionX, int
|
|||
}
|
||||
|
||||
|
||||
void CSVRender::TerrainTextureMode::selectTerrainTextures(const std::pair<int, int>& texCoords, unsigned char selectMode, bool dragOperation)
|
||||
void CSVRender::TerrainTextureMode::selectTerrainTextures(const std::pair<int, int>& texCoords, unsigned char selectMode)
|
||||
{
|
||||
int r = mBrushSize / 2;
|
||||
std::vector<std::pair<int, int>> selections;
|
||||
|
@ -559,8 +563,21 @@ void CSVRender::TerrainTextureMode::selectTerrainTextures(const std::pair<int, i
|
|||
}
|
||||
}
|
||||
|
||||
if(selectMode == 0) mTerrainTextureSelection->onlySelect(selections);
|
||||
if(selectMode == 1) mTerrainTextureSelection->toggleSelect(selections, dragOperation);
|
||||
std::string selectAction;
|
||||
|
||||
if (selectMode == 0)
|
||||
selectAction = CSMPrefs::get()["3D Scene Editing"]["primary-select-action"].toString();
|
||||
else
|
||||
selectAction = CSMPrefs::get()["3D Scene Editing"]["secondary-select-action"].toString();
|
||||
|
||||
if (selectAction == "Select only")
|
||||
mTerrainTextureSelection->onlySelect(selections);
|
||||
else if (selectAction == "Add to selection")
|
||||
mTerrainTextureSelection->addSelect(selections);
|
||||
else if (selectAction == "Remove from selection")
|
||||
mTerrainTextureSelection->removeSelect(selections);
|
||||
else if (selectAction == "Invert selection")
|
||||
mTerrainTextureSelection->toggleSelect(selections);
|
||||
}
|
||||
|
||||
void CSVRender::TerrainTextureMode::pushEditToCommand(CSMWorld::LandTexturesColumn::DataType& newLandGrid, CSMDoc::Document& document,
|
||||
|
|
|
@ -95,7 +95,7 @@ namespace CSVRender
|
|||
bool isInCellSelection(int globalSelectionX, int globalSelectionY);
|
||||
|
||||
/// \brief Handle brush mechanics for texture selection
|
||||
void selectTerrainTextures (const std::pair<int, int>& texCoords, unsigned char selectMode, bool dragOperation);
|
||||
void selectTerrainTextures (const std::pair<int, int>& texCoords, unsigned char selectMode);
|
||||
|
||||
/// \brief Push texture edits to command macro
|
||||
void pushEditToCommand (CSMWorld::LandTexturesColumn::DataType& newLandGrid, CSMDoc::Document& document,
|
||||
|
|
|
@ -464,7 +464,6 @@ void CSVRender::WorldspaceWidget::abortDrag()
|
|||
EditMode& editMode = dynamic_cast<CSVRender::EditMode&> (*mEditMode->getCurrent());
|
||||
|
||||
editMode.dragAborted();
|
||||
mDragging = false;
|
||||
mDragMode = InteractionType_None;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -19,7 +19,7 @@ set(GAME_HEADER
|
|||
source_group(game FILES ${GAME} ${GAME_HEADER})
|
||||
|
||||
add_openmw_dir (mwrender
|
||||
actors objects renderingmanager animation rotatecontroller sky npcanimation vismask
|
||||
actors objects renderingmanager animation rotatecontroller sky skyutil npcanimation vismask
|
||||
creatureanimation effectmanager util renderinginterface pathgrid rendermode weaponanimation screenshotmanager
|
||||
bulletdebugdraw globalmap characterpreview camera viewovershoulder localmap water terrainstorage ripplesimulation
|
||||
renderbin actoranimation landmanager navmesh actorspaths recastmesh fogmanager objectpaging groundcover postprocessor
|
||||
|
@ -27,7 +27,7 @@ add_openmw_dir (mwrender
|
|||
|
||||
add_openmw_dir (mwinput
|
||||
actions actionmanager bindingsmanager controllermanager controlswitch
|
||||
inputmanagerimp mousemanager keyboardmanager sdlmappings sensormanager
|
||||
inputmanagerimp mousemanager keyboardmanager sensormanager
|
||||
)
|
||||
|
||||
add_openmw_dir (mwgui
|
||||
|
@ -72,9 +72,9 @@ add_openmw_dir (mwworld
|
|||
containerstore actiontalk actiontake manualref player cellvisitors failedaction
|
||||
cells localscripts customdata inventorystore ptr actionopen actionread actionharvest
|
||||
actionequip timestamp actionalchemy cellstore actionapply actioneat
|
||||
store esmstore recordcmp fallback actionrepair actionsoulgem livecellref actiondoor
|
||||
store esmstore fallback actionrepair actionsoulgem livecellref actiondoor
|
||||
contentloader esmloader actiontrap cellreflist cellref weather projectilemanager
|
||||
cellpreloader datetimemanager
|
||||
cellpreloader datetimemanager groundcoverstore magiceffects
|
||||
)
|
||||
|
||||
add_openmw_dir (mwphysics
|
||||
|
@ -94,7 +94,7 @@ add_openmw_dir (mwmechanics
|
|||
aicast aiescort aiface aiactivate aicombat recharge repair enchanting pathfinding pathgrid security spellcasting spellresistance
|
||||
disease pickpocket levelledlist combat steering obstacle autocalcspell difficultyscaling aicombataction actor summoning
|
||||
character actors objects aistate trading weaponpriority spellpriority weapontype spellutil
|
||||
spellabsorption spelleffects
|
||||
spelleffects
|
||||
)
|
||||
|
||||
add_openmw_dir (mwstate
|
||||
|
@ -153,9 +153,12 @@ target_link_libraries(openmw
|
|||
"osg-ffmpeg-videoplayer"
|
||||
"oics"
|
||||
components
|
||||
${LUA_LIBRARIES}
|
||||
)
|
||||
|
||||
if (CMAKE_VERSION VERSION_GREATER_EQUAL 3.16)
|
||||
target_precompile_headers(openmw PRIVATE ${SOL_INCLUDE_DIR}/sol/sol.hpp)
|
||||
endif ()
|
||||
|
||||
if (ANDROID)
|
||||
target_link_libraries(openmw EGL android log z)
|
||||
endif (ANDROID)
|
||||
|
@ -176,8 +179,7 @@ endif()
|
|||
if(APPLE)
|
||||
set(BUNDLE_RESOURCES_DIR "${APP_BUNDLE_DIR}/Contents/Resources")
|
||||
|
||||
set(OPENMW_MYGUI_FILES_ROOT ${BUNDLE_RESOURCES_DIR})
|
||||
set(OPENMW_SHADERS_ROOT ${BUNDLE_RESOURCES_DIR})
|
||||
set(OPENMW_RESOURCES_ROOT ${BUNDLE_RESOURCES_DIR})
|
||||
|
||||
add_subdirectory(../../files/ ${CMAKE_CURRENT_BINARY_DIR}/files)
|
||||
|
||||
|
|
|
@ -1,4 +1,6 @@
|
|||
#ifndef stderr
|
||||
int stderr = 0; // Hack: fix linker error
|
||||
#endif
|
||||
|
||||
#include "SDL_main.h"
|
||||
#include <SDL_gamecontroller.h>
|
||||
|
|
|
@ -8,6 +8,8 @@
|
|||
|
||||
#include <boost/filesystem/fstream.hpp>
|
||||
|
||||
#include <osg/Version>
|
||||
|
||||
#include <osgViewer/ViewerEventHandlers>
|
||||
#include <osgDB/ReadFile>
|
||||
#include <osgDB/WriteFile>
|
||||
|
@ -37,11 +39,10 @@
|
|||
|
||||
#include <components/version/version.hpp>
|
||||
|
||||
#include <components/detournavigator/navigator.hpp>
|
||||
|
||||
#include <components/misc/frameratelimiter.hpp>
|
||||
|
||||
#include <components/sceneutil/screencapture.hpp>
|
||||
#include <components/sceneutil/depth.hpp>
|
||||
|
||||
#include "mwinput/inputmanagerimp.hpp"
|
||||
|
||||
|
@ -293,6 +294,10 @@ bool OMW::Engine::frame(float frametime)
|
|||
// Main menu opened? Then scripts are also paused.
|
||||
bool paused = mEnvironment.getWindowManager()->containsMode(MWGui::GM_MainMenu);
|
||||
|
||||
// Should be called after input manager update and before any change to the game world.
|
||||
// It applies to the game world queued changes from the previous frame.
|
||||
mLuaManager->synchronizedUpdate(mEnvironment.getWindowManager()->isGuiMode(), frametime);
|
||||
|
||||
// update game state
|
||||
{
|
||||
ScopedProfile<UserStatsType::State> profile(frameStart, frameNumber, *timer, *stats);
|
||||
|
@ -495,11 +500,6 @@ void OMW::Engine::addGroundcoverFile(const std::string& file)
|
|||
mGroundcoverFiles.emplace_back(file);
|
||||
}
|
||||
|
||||
void OMW::Engine::addLuaScriptListFile(const std::string& file)
|
||||
{
|
||||
mLuaScriptListFiles.push_back(file);
|
||||
}
|
||||
|
||||
void OMW::Engine::setSkipMenu (bool skipMenu, bool newGame)
|
||||
{
|
||||
mSkipMenu = skipMenu;
|
||||
|
@ -551,6 +551,10 @@ void OMW::Engine::createWindow(Settings::Manager& settings)
|
|||
if(fullscreen)
|
||||
flags |= SDL_WINDOW_FULLSCREEN;
|
||||
|
||||
// Allows for Windows snapping features to properly work in borderless window
|
||||
SDL_SetHint("SDL_BORDERLESS_WINDOWED_STYLE", "1");
|
||||
SDL_SetHint("SDL_BORDERLESS_RESIZABLE_STYLE", "1");
|
||||
|
||||
if (!windowBorder)
|
||||
flags |= SDL_WINDOW_BORDERLESS;
|
||||
|
||||
|
@ -674,7 +678,7 @@ void OMW::Engine::setWindowIcon()
|
|||
void OMW::Engine::prepareEngine (Settings::Manager & settings)
|
||||
{
|
||||
mEnvironment.setStateManager (
|
||||
new MWState::StateManager (mCfgMgr.getUserDataPath() / "saves", mContentFiles.at (0)));
|
||||
new MWState::StateManager (mCfgMgr.getUserDataPath() / "saves", mContentFiles));
|
||||
|
||||
createWindow(settings);
|
||||
|
||||
|
@ -714,7 +718,7 @@ void OMW::Engine::prepareEngine (Settings::Manager & settings)
|
|||
|
||||
mViewer->addEventHandler(mScreenCaptureHandler);
|
||||
|
||||
mLuaManager = new MWLua::LuaManager(mVFS.get(), mLuaScriptListFiles);
|
||||
mLuaManager = new MWLua::LuaManager(mVFS.get());
|
||||
mEnvironment.setLuaManager(mLuaManager);
|
||||
|
||||
// Create input and UI first to set up a bootstrapping environment for
|
||||
|
@ -758,6 +762,28 @@ void OMW::Engine::prepareEngine (Settings::Manager & settings)
|
|||
|
||||
osg::ref_ptr<osg::GLExtensions> exts = osg::GLExtensions::Get(0, false);
|
||||
bool shadersSupported = exts && (exts->glslLanguageVersion >= 1.2f);
|
||||
bool enableReverseZ = false;
|
||||
|
||||
if (Settings::Manager::getBool("reverse z", "Camera"))
|
||||
{
|
||||
if (exts && exts->isClipControlSupported)
|
||||
{
|
||||
enableReverseZ = true;
|
||||
Log(Debug::Info) << "Using reverse-z depth buffer";
|
||||
}
|
||||
else
|
||||
Log(Debug::Warning) << "GL_ARB_clip_control not supported: disabling reverse-z depth buffer";
|
||||
}
|
||||
else
|
||||
Log(Debug::Info) << "Using standard depth buffer";
|
||||
|
||||
SceneUtil::AutoDepth::setReversed(enableReverseZ);
|
||||
|
||||
#if OSG_VERSION_LESS_THAN(3, 6, 6)
|
||||
// hack fix for https://github.com/openscenegraph/OpenSceneGraph/issues/1028
|
||||
if (exts)
|
||||
exts->glRenderbufferStorageMultisampleCoverageNV = nullptr;
|
||||
#endif
|
||||
|
||||
std::string myguiResources = (mResDir / "mygui").string();
|
||||
osg::ref_ptr<osg::Group> guiRoot = new osg::Group;
|
||||
|
@ -869,7 +895,6 @@ public:
|
|||
}
|
||||
else
|
||||
update();
|
||||
mEngine->mLuaManager->applyQueuedChanges();
|
||||
};
|
||||
|
||||
void join()
|
||||
|
@ -1064,8 +1089,6 @@ void OMW::Engine::go()
|
|||
// Save user settings
|
||||
settings.saveUser(settingspath);
|
||||
|
||||
mViewer->stopThreading();
|
||||
|
||||
Log(Debug::Info) << "Quitting peacefully.";
|
||||
}
|
||||
|
||||
|
|
|
@ -72,7 +72,6 @@ namespace OMW
|
|||
std::string mCellName;
|
||||
std::vector<std::string> mContentFiles;
|
||||
std::vector<std::string> mGroundcoverFiles;
|
||||
std::vector<std::string> mLuaScriptListFiles;
|
||||
bool mSkipMenu;
|
||||
bool mUseSound;
|
||||
bool mCompileAll;
|
||||
|
@ -146,7 +145,6 @@ namespace OMW
|
|||
*/
|
||||
void addContentFile(const std::string& file);
|
||||
void addGroundcoverFile(const std::string& file);
|
||||
void addLuaScriptListFile(const std::string& file);
|
||||
|
||||
/// Disable or enable all sounds
|
||||
void setSoundUsage(bool soundUsage);
|
||||
|
|
|
@ -123,9 +123,11 @@ bool parseOptions (int argc, char** argv, OMW::Engine& engine, Files::Configurat
|
|||
engine.addGroundcoverFile(file);
|
||||
}
|
||||
|
||||
StringsVector luaScriptLists = variables["lua-scripts"].as<StringsVector>();
|
||||
for (const auto& file : luaScriptLists)
|
||||
engine.addLuaScriptListFile(file);
|
||||
if (variables.count("lua-scripts"))
|
||||
{
|
||||
Log(Debug::Warning) << "Lua scripts have been specified via the old lua-scripts option and will not be loaded. "
|
||||
"Please update them to a version which uses the new omwscripts format.";
|
||||
}
|
||||
|
||||
// startup-settings
|
||||
engine.setCell(variables["start"].as<std::string>());
|
||||
|
|
|
@ -49,8 +49,8 @@ namespace MWBase
|
|||
virtual void setGamepadGuiCursorEnabled(bool enabled) = 0;
|
||||
virtual void setAttemptJump(bool jumping) = 0;
|
||||
|
||||
virtual void toggleControlSwitch (const std::string& sw, bool value) = 0;
|
||||
virtual bool getControlSwitch (const std::string& sw) = 0;
|
||||
virtual void toggleControlSwitch(std::string_view sw, bool value) = 0;
|
||||
virtual bool getControlSwitch(std::string_view sw) = 0;
|
||||
|
||||
virtual std::string getActionDescription (int action) const = 0;
|
||||
virtual std::string getActionKeyBindingName (int action) const = 0;
|
||||
|
@ -58,8 +58,8 @@ namespace MWBase
|
|||
virtual bool actionIsActive(int action) const = 0;
|
||||
|
||||
virtual float getActionValue(int action) const = 0; // returns value in range [0, 1]
|
||||
virtual bool isControllerButtonPressed(SDL_GameControllerButton button) const = 0;
|
||||
virtual float getControllerAxisValue(SDL_GameControllerAxis axis) const = 0; // returns value in range [-1, 1]
|
||||
virtual uint32_t getMouseButtonsState() const = 0;
|
||||
virtual int getMouseMoveX() const = 0;
|
||||
virtual int getMouseMoveY() const = 0;
|
||||
|
||||
|
|
|
@ -30,6 +30,7 @@ namespace MWBase
|
|||
virtual ~LuaManager() = default;
|
||||
|
||||
virtual void newGameStarted() = 0;
|
||||
virtual void gameLoaded() = 0;
|
||||
virtual void registerObject(const MWWorld::Ptr& ptr) = 0;
|
||||
virtual void deregisterObject(const MWWorld::Ptr& ptr) = 0;
|
||||
virtual void objectAddedToScene(const MWWorld::Ptr& ptr) = 0;
|
||||
|
|
|
@ -112,6 +112,9 @@ namespace MWBase
|
|||
/// Makes \a ptr fight \a target. Also shouts a combat taunt.
|
||||
virtual void startCombat (const MWWorld::Ptr& ptr, const MWWorld::Ptr& target) = 0;
|
||||
|
||||
/// Removes an actor and its allies from combat with the actor's targets.
|
||||
virtual void stopCombat(const MWWorld::Ptr& ptr) = 0;
|
||||
|
||||
enum OffenseType
|
||||
{
|
||||
OT_Theft, // Taking items owned by an NPC or a faction you are not a member of
|
||||
|
|
|
@ -355,6 +355,7 @@ namespace MWBase
|
|||
virtual const std::string& getVersionDescription() const = 0;
|
||||
|
||||
virtual void onDeleteCustomData(const MWWorld::Ptr& ptr) = 0;
|
||||
virtual void forceLootMode(const MWWorld::Ptr& ptr) = 0;
|
||||
};
|
||||
}
|
||||
|
||||
|
|
|
@ -62,6 +62,7 @@ namespace MWPhysics
|
|||
namespace MWRender
|
||||
{
|
||||
class Animation;
|
||||
class Camera;
|
||||
}
|
||||
|
||||
namespace MWMechanics
|
||||
|
@ -289,7 +290,7 @@ namespace MWBase
|
|||
virtual MWWorld::Ptr moveObject(const MWWorld::Ptr &ptr, MWWorld::CellStore* newCell, const osg::Vec3f& position, bool movePhysics=true, bool keepActive=false) = 0;
|
||||
///< @return an updated Ptr
|
||||
|
||||
virtual MWWorld::Ptr moveObjectBy(const MWWorld::Ptr &ptr, const osg::Vec3f& vec, bool moveToActive, bool ignoreCollisions) = 0;
|
||||
virtual MWWorld::Ptr moveObjectBy(const MWWorld::Ptr &ptr, const osg::Vec3f& vec) = 0;
|
||||
///< @return an updated Ptr
|
||||
|
||||
virtual void scaleObject (const MWWorld::Ptr& ptr, float scale) = 0;
|
||||
|
@ -433,14 +434,12 @@ namespace MWBase
|
|||
|
||||
virtual osg::Matrixf getActorHeadTransform(const MWWorld::ConstPtr& actor) const = 0;
|
||||
|
||||
virtual MWRender::Camera* getCamera() = 0;
|
||||
virtual void togglePOV(bool force = false) = 0;
|
||||
virtual bool isFirstPerson() const = 0;
|
||||
virtual bool isPreviewModeEnabled() const = 0;
|
||||
virtual void togglePreviewMode(bool enable) = 0;
|
||||
virtual bool toggleVanityMode(bool enable) = 0;
|
||||
virtual void allowVanityMode(bool allow) = 0;
|
||||
virtual bool vanityRotateCamera(float * rot) = 0;
|
||||
virtual void adjustCameraDistance(float dist) = 0;
|
||||
virtual void applyDeferredPreviewRotationToPlayer(float dt) = 0;
|
||||
virtual void disableDeferredPreviewRotation() = 0;
|
||||
|
||||
|
|
|
@ -89,7 +89,7 @@ namespace MWClass
|
|||
{
|
||||
std::shared_ptr<Class> instance (new Activator);
|
||||
|
||||
registerClass (typeid (ESM::Activator).name(), instance);
|
||||
registerClass (ESM::Activator::sRecordId, instance);
|
||||
}
|
||||
|
||||
bool Activator::hasToolTip (const MWWorld::ConstPtr& ptr) const
|
||||
|
|
|
@ -3,6 +3,8 @@
|
|||
|
||||
#include "../mwworld/class.hpp"
|
||||
|
||||
#include <components/esm/loadmgef.hpp>
|
||||
|
||||
namespace ESM
|
||||
{
|
||||
struct GameSetting;
|
||||
|
@ -17,6 +19,15 @@ namespace MWClass
|
|||
|
||||
Actor() = default;
|
||||
|
||||
template <class GMST>
|
||||
float getSwimSpeedImpl(const MWWorld::Ptr& ptr, const GMST& gmst, const MWMechanics::MagicEffects& mageffects, float baseSpeed) const
|
||||
{
|
||||
return baseSpeed
|
||||
* (1.0f + 0.01f * mageffects.get(ESM::MagicEffect::SwiftSwim).getMagnitude())
|
||||
* (gmst.fSwimRunBase->mValue.getFloat()
|
||||
+ 0.01f * getSkill(ptr, ESM::Skill::Athletics) * gmst.fSwimRunAthleticsMult->mValue.getFloat());
|
||||
}
|
||||
|
||||
public:
|
||||
~Actor() override = default;
|
||||
|
||||
|
|
|
@ -69,7 +69,7 @@ namespace MWClass
|
|||
{
|
||||
std::shared_ptr<Class> instance (new Apparatus);
|
||||
|
||||
registerClass (typeid (ESM::Apparatus).name(), instance);
|
||||
registerClass (ESM::Apparatus::sRecordId, instance);
|
||||
}
|
||||
|
||||
std::string Apparatus::getUpSoundId (const MWWorld::ConstPtr& ptr) const
|
||||
|
|
|
@ -163,7 +163,7 @@ namespace MWClass
|
|||
{
|
||||
std::shared_ptr<Class> instance (new Armor);
|
||||
|
||||
registerClass (typeid (ESM::Armor).name(), instance);
|
||||
registerClass (ESM::Armor::sRecordId, instance);
|
||||
}
|
||||
|
||||
std::string Armor::getUpSoundId (const MWWorld::ConstPtr& ptr) const
|
||||
|
@ -322,7 +322,7 @@ namespace MWClass
|
|||
if(*slot == MWWorld::InventoryStore::Slot_CarriedLeft)
|
||||
{
|
||||
MWWorld::ConstContainerStoreIterator weapon = invStore.getSlot(MWWorld::InventoryStore::Slot_CarriedRight);
|
||||
if(weapon != invStore.end() && weapon->getTypeName() == typeid(ESM::Weapon).name())
|
||||
if(weapon != invStore.end() && weapon->getType() == ESM::Weapon::sRecordId)
|
||||
{
|
||||
const MWWorld::LiveCellRef<ESM::Weapon> *ref = weapon->get<ESM::Weapon>();
|
||||
if (MWMechanics::getWeaponType(ref->mBase->mData.mType)->mFlags & ESM::WeaponType::TwoHanded)
|
||||
|
|
|
@ -36,7 +36,7 @@ namespace MWClass
|
|||
{
|
||||
std::shared_ptr<MWWorld::Class> instance (new BodyPart);
|
||||
|
||||
registerClass (typeid (ESM::BodyPart).name(), instance);
|
||||
registerClass (ESM::BodyPart::sRecordId, instance);
|
||||
}
|
||||
|
||||
std::string BodyPart::getModel(const MWWorld::ConstPtr &ptr) const
|
||||
|
|
|
@ -85,7 +85,7 @@ namespace MWClass
|
|||
{
|
||||
std::shared_ptr<Class> instance (new Book);
|
||||
|
||||
registerClass (typeid (ESM::Book).name(), instance);
|
||||
registerClass (ESM::Book::sRecordId, instance);
|
||||
}
|
||||
|
||||
std::string Book::getUpSoundId (const MWWorld::ConstPtr& ptr) const
|
||||
|
|
|
@ -121,7 +121,7 @@ namespace MWClass
|
|||
{
|
||||
std::shared_ptr<Class> instance (new Clothing);
|
||||
|
||||
registerClass (typeid (ESM::Clothing).name(), instance);
|
||||
registerClass (ESM::Clothing::sRecordId, instance);
|
||||
}
|
||||
|
||||
std::string Clothing::getUpSoundId (const MWWorld::ConstPtr& ptr) const
|
||||
|
|
|
@ -242,7 +242,7 @@ namespace MWClass
|
|||
{
|
||||
std::shared_ptr<Class> instance (new Container);
|
||||
|
||||
registerClass (typeid (ESM::Container).name(), instance);
|
||||
registerClass (ESM::Container::sRecordId, instance);
|
||||
}
|
||||
|
||||
bool Container::hasToolTip (const MWWorld::ConstPtr& ptr) const
|
||||
|
|
|
@ -82,12 +82,13 @@ namespace MWClass
|
|||
|
||||
const Creature::GMST& Creature::getGmst()
|
||||
{
|
||||
static GMST gmst;
|
||||
static bool inited = false;
|
||||
if (!inited)
|
||||
static const GMST staticGmst = []
|
||||
{
|
||||
GMST gmst;
|
||||
|
||||
const MWBase::World *world = MWBase::Environment::get().getWorld();
|
||||
const MWWorld::Store<ESM::GameSetting> &store = world->getStore().get<ESM::GameSetting>();
|
||||
|
||||
gmst.fMinWalkSpeedCreature = store.find("fMinWalkSpeedCreature");
|
||||
gmst.fMaxWalkSpeedCreature = store.find("fMaxWalkSpeedCreature");
|
||||
gmst.fEncumberedMoveEffect = store.find("fEncumberedMoveEffect");
|
||||
|
@ -101,16 +102,20 @@ namespace MWClass
|
|||
gmst.fKnockDownMult = store.find("fKnockDownMult");
|
||||
gmst.iKnockDownOddsMult = store.find("iKnockDownOddsMult");
|
||||
gmst.iKnockDownOddsBase = store.find("iKnockDownOddsBase");
|
||||
inited = true;
|
||||
}
|
||||
return gmst;
|
||||
|
||||
return gmst;
|
||||
} ();
|
||||
return staticGmst;
|
||||
}
|
||||
|
||||
void Creature::ensureCustomData (const MWWorld::Ptr& ptr) const
|
||||
{
|
||||
if (!ptr.getRefData().getCustomData())
|
||||
{
|
||||
std::unique_ptr<CreatureCustomData> data (new CreatureCustomData);
|
||||
auto tempData = std::make_unique<CreatureCustomData>();
|
||||
CreatureCustomData* data = tempData.get();
|
||||
MWMechanics::CreatureCustomDataResetter resetter(ptr);
|
||||
ptr.getRefData().setCustomData(std::move(tempData));
|
||||
|
||||
MWWorld::LiveCellRef<ESM::Creature> *ref = ptr.get<ESM::Creature>();
|
||||
|
||||
|
@ -154,10 +159,7 @@ namespace MWClass
|
|||
|
||||
data->mCreatureStats.setGoldPool(ref->mBase->mData.mGold);
|
||||
|
||||
data->mCreatureStats.setNeedRecalcDynamicStats(false);
|
||||
|
||||
// store
|
||||
ptr.getRefData().setCustomData(std::move(data));
|
||||
resetter.mPtr = {};
|
||||
|
||||
getContainerStore(ptr).fill(ref->mBase->mInventory, ptr.getCellRef().getRefId());
|
||||
|
||||
|
@ -238,7 +240,7 @@ namespace MWClass
|
|||
{
|
||||
MWWorld::InventoryStore &inv = getInventoryStore(ptr);
|
||||
MWWorld::ContainerStoreIterator weaponslot = inv.getSlot(MWWorld::InventoryStore::Slot_CarriedRight);
|
||||
if (weaponslot != inv.end() && weaponslot->getTypeName() == typeid(ESM::Weapon).name())
|
||||
if (weaponslot != inv.end() && weaponslot->getType() == ESM::Weapon::sRecordId)
|
||||
weapon = *weaponslot;
|
||||
}
|
||||
|
||||
|
@ -497,7 +499,7 @@ namespace MWClass
|
|||
{
|
||||
std::shared_ptr<Class> instance (new Creature);
|
||||
|
||||
registerClass (typeid (ESM::Creature).name(), instance);
|
||||
registerClass (ESM::Creature::sRecordId, instance);
|
||||
}
|
||||
|
||||
float Creature::getMaxSpeed(const MWWorld::Ptr &ptr) const
|
||||
|
@ -891,12 +893,8 @@ namespace MWClass
|
|||
float Creature::getSwimSpeed(const MWWorld::Ptr& ptr) const
|
||||
{
|
||||
const MWMechanics::CreatureStats& stats = getCreatureStats(ptr);
|
||||
const GMST& gmst = getGmst();
|
||||
const MWMechanics::MagicEffects& mageffects = stats.getMagicEffects();
|
||||
|
||||
return getWalkSpeed(ptr)
|
||||
* (1.0f + 0.01f * mageffects.get(ESM::MagicEffect::SwiftSwim).getMagnitude())
|
||||
* (gmst.fSwimRunBase->mValue.getFloat()
|
||||
+ 0.01f * getSkill(ptr, ESM::Skill::Athletics) * gmst.fSwimRunAthleticsMult->mValue.getFloat());
|
||||
return getSwimSpeedImpl(ptr, getGmst(), mageffects, getWalkSpeed(ptr));
|
||||
}
|
||||
}
|
||||
|
|
|
@ -5,6 +5,7 @@
|
|||
|
||||
#include "../mwmechanics/levelledlist.hpp"
|
||||
|
||||
#include "../mwworld/cellstore.hpp"
|
||||
#include "../mwworld/customdata.hpp"
|
||||
#include "../mwmechanics/creaturestats.hpp"
|
||||
|
||||
|
@ -27,6 +28,24 @@ namespace MWClass
|
|||
}
|
||||
};
|
||||
|
||||
MWWorld::Ptr CreatureLevList::copyToCellImpl(const MWWorld::ConstPtr &ptr, MWWorld::CellStore &cell) const
|
||||
{
|
||||
const MWWorld::LiveCellRef<ESM::CreatureLevList> *ref = ptr.get<ESM::CreatureLevList>();
|
||||
|
||||
return MWWorld::Ptr(cell.insert(ref), &cell);
|
||||
}
|
||||
|
||||
void CreatureLevList::adjustPosition(const MWWorld::Ptr& ptr, bool force) const
|
||||
{
|
||||
if (ptr.getRefData().getCustomData() == nullptr)
|
||||
return;
|
||||
|
||||
CreatureLevListCustomData& customData = ptr.getRefData().getCustomData()->asCreatureLevListCustomData();
|
||||
MWWorld::Ptr creature = (customData.mSpawnActorId == -1) ? MWWorld::Ptr() : MWBase::Environment::get().getWorld()->searchPtrViaActorId(customData.mSpawnActorId);
|
||||
if (!creature.isEmpty())
|
||||
MWBase::Environment::get().getWorld()->adjustPosition(creature, force);
|
||||
}
|
||||
|
||||
std::string CreatureLevList::getName (const MWWorld::ConstPtr& ptr) const
|
||||
{
|
||||
return "";
|
||||
|
@ -45,7 +64,13 @@ namespace MWClass
|
|||
if (customData.mSpawn)
|
||||
return;
|
||||
|
||||
MWWorld::Ptr creature = (customData.mSpawnActorId == -1) ? MWWorld::Ptr() : MWBase::Environment::get().getWorld()->searchPtrViaActorId(customData.mSpawnActorId);
|
||||
MWWorld::Ptr creature;
|
||||
if(customData.mSpawnActorId != -1)
|
||||
{
|
||||
creature = MWBase::Environment::get().getWorld()->searchPtrViaActorId(customData.mSpawnActorId);
|
||||
if(creature.isEmpty())
|
||||
creature = ptr.getCell()->getMovedActor(customData.mSpawnActorId);
|
||||
}
|
||||
if (!creature.isEmpty())
|
||||
{
|
||||
const MWMechanics::CreatureStats& creatureStats = creature.getClass().getCreatureStats(creature);
|
||||
|
@ -70,7 +95,7 @@ namespace MWClass
|
|||
{
|
||||
std::shared_ptr<Class> instance (new CreatureLevList);
|
||||
|
||||
registerClass (typeid (ESM::CreatureLevList).name(), instance);
|
||||
registerClass (ESM::CreatureLevList::sRecordId, instance);
|
||||
}
|
||||
|
||||
void CreatureLevList::getModelsToPreload(const MWWorld::Ptr &ptr, std::vector<std::string> &models) const
|
||||
|
|
|
@ -32,6 +32,10 @@ namespace MWClass
|
|||
///< Write additional state from \a ptr into \a state.
|
||||
|
||||
void respawn (const MWWorld::Ptr& ptr) const override;
|
||||
|
||||
MWWorld::Ptr copyToCellImpl(const MWWorld::ConstPtr &ptr, MWWorld::CellStore &cell) const override;
|
||||
|
||||
void adjustPosition(const MWWorld::Ptr& ptr, bool force) const override;
|
||||
};
|
||||
}
|
||||
|
||||
|
|
|
@ -264,7 +264,7 @@ namespace MWClass
|
|||
{
|
||||
std::shared_ptr<Class> instance (new Door);
|
||||
|
||||
registerClass (typeid (ESM::Door).name(), instance);
|
||||
registerClass (ESM::Door::sRecordId, instance);
|
||||
}
|
||||
|
||||
MWGui::ToolTipInfo Door::getToolTipInfo (const MWWorld::ConstPtr& ptr, int count) const
|
||||
|
|
|
@ -81,7 +81,7 @@ namespace MWClass
|
|||
{
|
||||
std::shared_ptr<Class> instance (new Ingredient);
|
||||
|
||||
registerClass (typeid (ESM::Ingredient).name(), instance);
|
||||
registerClass (ESM::Ingredient::sRecordId, instance);
|
||||
}
|
||||
|
||||
std::string Ingredient::getUpSoundId (const MWWorld::ConstPtr& ptr) const
|
||||
|
|
|
@ -19,6 +19,6 @@ namespace MWClass
|
|||
{
|
||||
std::shared_ptr<Class> instance (new ItemLevList);
|
||||
|
||||
registerClass (typeid (ESM::ItemLevList).name(), instance);
|
||||
registerClass (ESM::ItemLevList::sRecordId, instance);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -124,7 +124,7 @@ namespace MWClass
|
|||
{
|
||||
std::shared_ptr<Class> instance (new Light);
|
||||
|
||||
registerClass (typeid (ESM::Light).name(), instance);
|
||||
registerClass (ESM::Light::sRecordId, instance);
|
||||
}
|
||||
|
||||
std::string Light::getUpSoundId (const MWWorld::ConstPtr& ptr) const
|
||||
|
|
|
@ -80,7 +80,7 @@ namespace MWClass
|
|||
{
|
||||
std::shared_ptr<Class> instance (new Lockpick);
|
||||
|
||||
registerClass (typeid (ESM::Lockpick).name(), instance);
|
||||
registerClass (ESM::Lockpick::sRecordId, instance);
|
||||
}
|
||||
|
||||
std::string Lockpick::getUpSoundId (const MWWorld::ConstPtr& ptr) const
|
||||
|
|
|
@ -106,7 +106,7 @@ namespace MWClass
|
|||
{
|
||||
std::shared_ptr<Class> instance (new Miscellaneous);
|
||||
|
||||
registerClass (typeid (ESM::Miscellaneous).name(), instance);
|
||||
registerClass (ESM::Miscellaneous::sRecordId, instance);
|
||||
}
|
||||
|
||||
std::string Miscellaneous::getUpSoundId (const MWWorld::ConstPtr& ptr) const
|
||||
|
|
|
@ -266,10 +266,10 @@ namespace MWClass
|
|||
|
||||
const Npc::GMST& Npc::getGmst()
|
||||
{
|
||||
static GMST gmst;
|
||||
static bool inited = false;
|
||||
if(!inited)
|
||||
static const GMST staticGmst = []
|
||||
{
|
||||
GMST gmst;
|
||||
|
||||
const MWBase::World *world = MWBase::Environment::get().getWorld();
|
||||
const MWWorld::Store<ESM::GameSetting> &store = world->getStore().get<ESM::GameSetting>();
|
||||
|
||||
|
@ -294,16 +294,20 @@ namespace MWClass
|
|||
gmst.iKnockDownOddsBase = store.find("iKnockDownOddsBase");
|
||||
gmst.fCombatArmorMinMult = store.find("fCombatArmorMinMult");
|
||||
|
||||
inited = true;
|
||||
}
|
||||
return gmst;
|
||||
return gmst;
|
||||
} ();
|
||||
return staticGmst;
|
||||
}
|
||||
|
||||
void Npc::ensureCustomData (const MWWorld::Ptr& ptr) const
|
||||
{
|
||||
if (!ptr.getRefData().getCustomData())
|
||||
{
|
||||
std::unique_ptr<NpcCustomData> data(new NpcCustomData);
|
||||
bool recalculate = false;
|
||||
auto tempData = std::make_unique<NpcCustomData>();
|
||||
NpcCustomData* data = tempData.get();
|
||||
MWMechanics::CreatureCustomDataResetter resetter(ptr);
|
||||
ptr.getRefData().setCustomData(std::move(tempData));
|
||||
|
||||
MWWorld::LiveCellRef<ESM::NPC> *ref = ptr.get<ESM::NPC>();
|
||||
|
||||
|
@ -334,8 +338,6 @@ namespace MWClass
|
|||
data->mNpcStats.setLevel(ref->mBase->mNpdt.mLevel);
|
||||
data->mNpcStats.setBaseDisposition(ref->mBase->mNpdt.mDisposition);
|
||||
data->mNpcStats.setReputation(ref->mBase->mNpdt.mReputation);
|
||||
|
||||
data->mNpcStats.setNeedRecalcDynamicStats(false);
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -351,7 +353,7 @@ namespace MWClass
|
|||
autoCalculateAttributes(ref->mBase, data->mNpcStats);
|
||||
autoCalculateSkills(ref->mBase, data->mNpcStats, ptr, spellsInitialised);
|
||||
|
||||
data->mNpcStats.setNeedRecalcDynamicStats(true);
|
||||
recalculate = true;
|
||||
}
|
||||
|
||||
// Persistent actors with 0 health do not play death animation
|
||||
|
@ -387,7 +389,9 @@ namespace MWClass
|
|||
data->mNpcStats.setGoldPool(gold);
|
||||
|
||||
// store
|
||||
ptr.getRefData().setCustomData(std::move(data));
|
||||
resetter.mPtr = {};
|
||||
if(recalculate)
|
||||
data->mNpcStats.recalculateMagicka();
|
||||
|
||||
// inventory
|
||||
// setting ownership is used to make the NPC auto-equip his initial equipment only, and not bartered items
|
||||
|
@ -459,12 +463,12 @@ namespace MWClass
|
|||
if (equipped != invStore.end())
|
||||
{
|
||||
std::vector<ESM::PartReference> parts;
|
||||
if(equipped->getTypeName() == typeid(ESM::Clothing).name())
|
||||
if(equipped->getType() == ESM::Clothing::sRecordId)
|
||||
{
|
||||
const ESM::Clothing *clothes = equipped->get<ESM::Clothing>()->mBase;
|
||||
parts = clothes->mParts.mParts;
|
||||
}
|
||||
else if(equipped->getTypeName() == typeid(ESM::Armor).name())
|
||||
else if(equipped->getType() == ESM::Armor::sRecordId)
|
||||
{
|
||||
const ESM::Armor *armor = equipped->get<ESM::Armor>()->mBase;
|
||||
parts = armor->mParts.mParts;
|
||||
|
@ -543,7 +547,7 @@ namespace MWClass
|
|||
MWWorld::InventoryStore &inv = getInventoryStore(ptr);
|
||||
MWWorld::ContainerStoreIterator weaponslot = inv.getSlot(MWWorld::InventoryStore::Slot_CarriedRight);
|
||||
MWWorld::Ptr weapon = ((weaponslot != inv.end()) ? *weaponslot : MWWorld::Ptr());
|
||||
if(!weapon.isEmpty() && weapon.getTypeName() != typeid(ESM::Weapon).name())
|
||||
if(!weapon.isEmpty() && weapon.getType() != ESM::Weapon::sRecordId)
|
||||
weapon = MWWorld::Ptr();
|
||||
|
||||
MWMechanics::applyFatigueLoss(ptr, weapon, attackStrength);
|
||||
|
@ -766,7 +770,7 @@ namespace MWClass
|
|||
MWWorld::InventoryStore &inv = getInventoryStore(ptr);
|
||||
MWWorld::ContainerStoreIterator armorslot = inv.getSlot(hitslot);
|
||||
MWWorld::Ptr armor = ((armorslot != inv.end()) ? *armorslot : MWWorld::Ptr());
|
||||
bool hasArmor = !armor.isEmpty() && armor.getTypeName() == typeid(ESM::Armor).name();
|
||||
bool hasArmor = !armor.isEmpty() && armor.getType() == ESM::Armor::sRecordId;
|
||||
// If there's no item in the carried left slot or if it is not a shield redistribute the hit.
|
||||
if (!hasArmor && hitslot == MWWorld::InventoryStore::Slot_CarriedLeft)
|
||||
{
|
||||
|
@ -778,7 +782,7 @@ namespace MWClass
|
|||
if (armorslot != inv.end())
|
||||
{
|
||||
armor = *armorslot;
|
||||
hasArmor = !armor.isEmpty() && armor.getTypeName() == typeid(ESM::Armor).name();
|
||||
hasArmor = !armor.isEmpty() && armor.getType() == ESM::Armor::sRecordId;
|
||||
}
|
||||
}
|
||||
if (hasArmor)
|
||||
|
@ -1036,7 +1040,7 @@ namespace MWClass
|
|||
void Npc::registerSelf()
|
||||
{
|
||||
std::shared_ptr<Class> instance (new Npc);
|
||||
registerClass (typeid (ESM::NPC).name(), instance);
|
||||
registerClass (ESM::NPC::sRecordId, instance);
|
||||
}
|
||||
|
||||
bool Npc::hasToolTip(const MWWorld::ConstPtr& ptr) const
|
||||
|
@ -1135,7 +1139,7 @@ namespace MWClass
|
|||
for(int i = 0;i < MWWorld::InventoryStore::Slots;i++)
|
||||
{
|
||||
MWWorld::ConstContainerStoreIterator it = invStore.getSlot(i);
|
||||
if (it == invStore.end() || it->getTypeName() != typeid(ESM::Armor).name())
|
||||
if (it == invStore.end() || it->getType() != ESM::Armor::sRecordId)
|
||||
{
|
||||
// unarmored
|
||||
ratings[i] = (fUnarmoredBase1 * unarmoredSkill) * (fUnarmoredBase2 * unarmoredSkill);
|
||||
|
@ -1232,7 +1236,7 @@ namespace MWClass
|
|||
|
||||
const MWWorld::InventoryStore &inv = Npc::getInventoryStore(ptr);
|
||||
MWWorld::ConstContainerStoreIterator boots = inv.getSlot(MWWorld::InventoryStore::Slot_Boots);
|
||||
if(boots == inv.end() || boots->getTypeName() != typeid(ESM::Armor).name())
|
||||
if(boots == inv.end() || boots->getType() != ESM::Armor::sRecordId)
|
||||
return (name == "left") ? "FootBareLeft" : "FootBareRight";
|
||||
|
||||
switch(boots->getClass().getEquipmentSkill(*boots))
|
||||
|
@ -1476,7 +1480,6 @@ namespace MWClass
|
|||
|
||||
float Npc::getSwimSpeed(const MWWorld::Ptr& ptr) const
|
||||
{
|
||||
const GMST& gmst = getGmst();
|
||||
const MWBase::World* world = MWBase::Environment::get().getWorld();
|
||||
const MWMechanics::CreatureStats& stats = getCreatureStats(ptr);
|
||||
const NpcCustomData* npcdata = static_cast<const NpcCustomData*>(ptr.getRefData().getCustomData());
|
||||
|
@ -1486,17 +1489,6 @@ namespace MWClass
|
|||
const bool running = stats.getStance(MWMechanics::CreatureStats::Stance_Run)
|
||||
&& (inair || MWBase::Environment::get().getMechanicsManager()->isRunning(ptr));
|
||||
|
||||
float swimSpeed;
|
||||
|
||||
if (running)
|
||||
swimSpeed = getRunSpeed(ptr);
|
||||
else
|
||||
swimSpeed = getWalkSpeed(ptr);
|
||||
|
||||
swimSpeed *= 1.0f + 0.01f * mageffects.get(ESM::MagicEffect::SwiftSwim).getMagnitude();
|
||||
swimSpeed *= gmst.fSwimRunBase->mValue.getFloat()
|
||||
+ 0.01f * getSkill(ptr, ESM::Skill::Athletics) * gmst.fSwimRunAthleticsMult->mValue.getFloat();
|
||||
|
||||
return swimSpeed;
|
||||
return getSwimSpeedImpl(ptr, getGmst(), mageffects, running ? getRunSpeed(ptr) : getWalkSpeed(ptr));
|
||||
}
|
||||
}
|
||||
|
|
|
@ -74,7 +74,7 @@ namespace MWClass
|
|||
{
|
||||
std::shared_ptr<Class> instance (new Potion);
|
||||
|
||||
registerClass (typeid (ESM::Potion).name(), instance);
|
||||
registerClass (ESM::Potion::sRecordId, instance);
|
||||
}
|
||||
|
||||
std::string Potion::getUpSoundId (const MWWorld::ConstPtr& ptr) const
|
||||
|
|
|
@ -80,7 +80,7 @@ namespace MWClass
|
|||
{
|
||||
std::shared_ptr<Class> instance (new Probe);
|
||||
|
||||
registerClass (typeid (ESM::Probe).name(), instance);
|
||||
registerClass (ESM::Probe::sRecordId, instance);
|
||||
}
|
||||
|
||||
std::string Probe::getUpSoundId (const MWWorld::ConstPtr& ptr) const
|
||||
|
|
|
@ -69,7 +69,7 @@ namespace MWClass
|
|||
{
|
||||
std::shared_ptr<Class> instance (new Repair);
|
||||
|
||||
registerClass (typeid (ESM::Repair).name(), instance);
|
||||
registerClass (ESM::Repair::sRecordId, instance);
|
||||
}
|
||||
|
||||
std::string Repair::getUpSoundId (const MWWorld::ConstPtr& ptr) const
|
||||
|
|
|
@ -59,7 +59,7 @@ namespace MWClass
|
|||
{
|
||||
std::shared_ptr<Class> instance (new Static);
|
||||
|
||||
registerClass (typeid (ESM::Static).name(), instance);
|
||||
registerClass (ESM::Static::sRecordId, instance);
|
||||
}
|
||||
|
||||
MWWorld::Ptr Static::copyToCellImpl(const MWWorld::ConstPtr &ptr, MWWorld::CellStore &cell) const
|
||||
|
|
|
@ -125,7 +125,7 @@ namespace MWClass
|
|||
{
|
||||
std::shared_ptr<Class> instance (new Weapon);
|
||||
|
||||
registerClass (typeid (ESM::Weapon).name(), instance);
|
||||
registerClass (ESM::Weapon::sRecordId, instance);
|
||||
}
|
||||
|
||||
std::string Weapon::getUpSoundId (const MWWorld::ConstPtr& ptr) const
|
||||
|
|
|
@ -76,9 +76,10 @@ namespace MWDialogue
|
|||
mKnownTopics.insert( Misc::StringUtils::lowerCase(topic) );
|
||||
}
|
||||
|
||||
void DialogueManager::parseText (const std::string& text)
|
||||
std::vector<std::string> DialogueManager::parseTopicIdsFromText (const std::string& text)
|
||||
{
|
||||
updateActorKnownTopics();
|
||||
std::vector<std::string> topicIdList;
|
||||
|
||||
std::vector<HyperTextParser::Token> hypertext = HyperTextParser::parseHyperText(text);
|
||||
|
||||
for (std::vector<HyperTextParser::Token>::iterator tok = hypertext.begin(); tok != hypertext.end(); ++tok)
|
||||
|
@ -95,6 +96,18 @@ namespace MWDialogue
|
|||
topicId = mTranslationDataStorage.topicStandardForm(topicId);
|
||||
}
|
||||
|
||||
topicIdList.push_back(topicId);
|
||||
}
|
||||
|
||||
return topicIdList;
|
||||
}
|
||||
|
||||
void DialogueManager::addTopicsFromText (const std::string& text)
|
||||
{
|
||||
updateActorKnownTopics();
|
||||
|
||||
for (const auto& topicId : parseTopicIdsFromText(text))
|
||||
{
|
||||
if (mActorKnownTopics.count( topicId ))
|
||||
mKnownTopics.insert( topicId );
|
||||
}
|
||||
|
@ -136,7 +149,6 @@ namespace MWDialogue
|
|||
mTalkedTo = creatureStats.hasTalkedToPlayer();
|
||||
|
||||
mActorKnownTopics.clear();
|
||||
mActorKnownTopicsFlag.clear();
|
||||
|
||||
//greeting
|
||||
const MWWorld::Store<ESM::Dialogue> &dialogs =
|
||||
|
@ -163,7 +175,7 @@ namespace MWDialogue
|
|||
executeScript (info->mResultScript, mActor);
|
||||
mLastTopic = it->mId;
|
||||
|
||||
parseText (info->mResponse);
|
||||
addTopicsFromText (info->mResponse);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
@ -277,7 +289,10 @@ namespace MWDialogue
|
|||
|
||||
const ESM::Dialogue& dialogue = *dialogues.find (topic);
|
||||
|
||||
const ESM::DialInfo* info = filter.search(dialogue, true);
|
||||
const ESM::DialInfo* info =
|
||||
mChoice == -1 && mActorKnownTopics.count(topic) ?
|
||||
mActorKnownTopics[topic].mInfo : filter.search(dialogue, true);
|
||||
|
||||
if (info)
|
||||
{
|
||||
std::string title;
|
||||
|
@ -320,7 +335,7 @@ namespace MWDialogue
|
|||
|
||||
executeScript (info->mResultScript, mActor);
|
||||
|
||||
parseText (info->mResponse);
|
||||
addTopicsFromText (info->mResponse);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -339,7 +354,6 @@ namespace MWDialogue
|
|||
updateGlobals();
|
||||
|
||||
mActorKnownTopics.clear();
|
||||
mActorKnownTopicsFlag.clear();
|
||||
|
||||
const auto& dialogs = MWBase::Environment::get().getWorld()->getStore().get<ESM::Dialogue>();
|
||||
|
||||
|
@ -354,21 +368,41 @@ namespace MWDialogue
|
|||
|
||||
if (answer != nullptr)
|
||||
{
|
||||
int flag = 0;
|
||||
int topicFlags = 0;
|
||||
if(!inJournal(topicId, answer->mId))
|
||||
{
|
||||
// Does this dialogue contains some actor-specific answer?
|
||||
if (Misc::StringUtils::ciEqual(answer->mActor, mActor.getCellRef().getRefId()))
|
||||
flag |= MWBase::DialogueManager::TopicType::Specific;
|
||||
topicFlags |= MWBase::DialogueManager::TopicType::Specific;
|
||||
}
|
||||
else
|
||||
flag |= MWBase::DialogueManager::TopicType::Exhausted;
|
||||
mActorKnownTopics.insert (dialog.mId);
|
||||
mActorKnownTopicsFlag[dialog.mId] = flag;
|
||||
topicFlags |= MWBase::DialogueManager::TopicType::Exhausted;
|
||||
mActorKnownTopics.insert (std::make_pair(dialog.mId, ActorKnownTopicInfo {topicFlags, answer}));
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
// If response to a topic leads to a new topic, the original topic is not exhausted.
|
||||
|
||||
for (auto& [dialogId, topicInfo] : mActorKnownTopics)
|
||||
{
|
||||
// If the topic is not marked as exhausted, we don't need to do anything about it.
|
||||
// If the topic will not be shown to the player, the flag actually does not matter.
|
||||
|
||||
if (!(topicInfo.mFlags & MWBase::DialogueManager::TopicType::Exhausted) ||
|
||||
!mKnownTopics.count(dialogId))
|
||||
continue;
|
||||
|
||||
for (const auto& topicId : parseTopicIdsFromText(topicInfo.mInfo->mResponse))
|
||||
{
|
||||
if (mActorKnownTopics.count( topicId ) && !mKnownTopics.count( topicId ))
|
||||
{
|
||||
topicInfo.mFlags &= ~MWBase::DialogueManager::TopicType::Exhausted;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
std::list<std::string> DialogueManager::getAvailableTopics()
|
||||
|
@ -377,7 +411,7 @@ namespace MWDialogue
|
|||
|
||||
std::list<std::string> keywordList;
|
||||
|
||||
for (const std::string& topic : mActorKnownTopics)
|
||||
for (const auto& [topic, topicInfo] : mActorKnownTopics)
|
||||
{
|
||||
//does the player know the topic?
|
||||
if (mKnownTopics.count(topic))
|
||||
|
@ -391,7 +425,7 @@ namespace MWDialogue
|
|||
|
||||
int DialogueManager::getTopicFlag(const std::string& topicId)
|
||||
{
|
||||
return mActorKnownTopicsFlag[topicId];
|
||||
return mActorKnownTopics[topicId].mFlags;
|
||||
}
|
||||
|
||||
void DialogueManager::keywordSelected (const std::string& keyword, ResponseCallback* callback)
|
||||
|
@ -421,7 +455,7 @@ namespace MWDialogue
|
|||
// Clamp permanent disposition change so that final disposition doesn't go below 0 (could happen with intimidate)
|
||||
npcStats.setBaseDisposition(0);
|
||||
int zero = MWBase::Environment::get().getMechanicsManager()->getDerivedDisposition(mActor, false);
|
||||
int disposition = std::min(100 - zero, std::max(mOriginalDisposition + mPermanentDispositionChange, -zero));
|
||||
int disposition = std::clamp(mOriginalDisposition + mPermanentDispositionChange, -zero, 100 - zero);
|
||||
|
||||
npcStats.setBaseDisposition(disposition);
|
||||
}
|
||||
|
@ -444,7 +478,7 @@ namespace MWDialogue
|
|||
if (const ESM::DialInfo *info = filter.search (*dialogue, true))
|
||||
{
|
||||
std::string text = info->mResponse;
|
||||
parseText (text);
|
||||
addTopicsFromText (text);
|
||||
|
||||
mChoice = -1;
|
||||
mIsInChoice = false;
|
||||
|
@ -579,7 +613,7 @@ namespace MWDialogue
|
|||
{
|
||||
const ESM::DialInfo* info = infos[0];
|
||||
|
||||
parseText (info->mResponse);
|
||||
addTopicsFromText (info->mResponse);
|
||||
|
||||
const MWWorld::Store<ESM::GameSetting>& gmsts =
|
||||
MWBase::Environment::get().getWorld()->getStore().get<ESM::GameSetting>();
|
||||
|
|
|
@ -10,6 +10,7 @@
|
|||
#include <components/compiler/streamerrorhandler.hpp>
|
||||
#include <components/translation/translation.hpp>
|
||||
#include <components/misc/stringops.hpp>
|
||||
#include <components/esm/loadinfo.hpp>
|
||||
|
||||
#include "../mwworld/ptr.hpp"
|
||||
|
||||
|
@ -24,14 +25,19 @@ namespace MWDialogue
|
|||
{
|
||||
class DialogueManager : public MWBase::DialogueManager
|
||||
{
|
||||
struct ActorKnownTopicInfo
|
||||
{
|
||||
int mFlags;
|
||||
const ESM::DialInfo* mInfo;
|
||||
};
|
||||
|
||||
std::set<std::string, Misc::StringUtils::CiComp> mKnownTopics;// Those are the topics the player knows.
|
||||
|
||||
// Modified faction reactions. <Faction1, <Faction2, Difference> >
|
||||
typedef std::map<std::string, std::map<std::string, int> > ModFactionReactionMap;
|
||||
ModFactionReactionMap mChangedFactionReaction;
|
||||
|
||||
std::set<std::string, Misc::StringUtils::CiComp> mActorKnownTopics;
|
||||
std::unordered_map<std::string, int> mActorKnownTopicsFlag;
|
||||
std::map<std::string, ActorKnownTopicInfo, Misc::StringUtils::CiComp> mActorKnownTopics;
|
||||
|
||||
Translation::Storage& mTranslationDataStorage;
|
||||
MWScript::CompilerContext mCompilerContext;
|
||||
|
@ -51,7 +57,8 @@ namespace MWDialogue
|
|||
int mCurrentDisposition;
|
||||
int mPermanentDispositionChange;
|
||||
|
||||
void parseText (const std::string& text);
|
||||
std::vector<std::string> parseTopicIdsFromText (const std::string& text);
|
||||
void addTopicsFromText (const std::string& text);
|
||||
|
||||
void updateActorKnownTopics();
|
||||
void updateGlobals();
|
||||
|
|
|
@ -23,7 +23,7 @@
|
|||
|
||||
bool MWDialogue::Filter::testActor (const ESM::DialInfo& info) const
|
||||
{
|
||||
bool isCreature = (mActor.getTypeName() != typeid (ESM::NPC).name());
|
||||
bool isCreature = (mActor.getType() != ESM::NPC::sRecordId);
|
||||
|
||||
// actor id
|
||||
if (!info.mActor.empty())
|
||||
|
@ -160,7 +160,7 @@ bool MWDialogue::Filter::testSelectStructs (const ESM::DialInfo& info) const
|
|||
|
||||
bool MWDialogue::Filter::testDisposition (const ESM::DialInfo& info, bool invert) const
|
||||
{
|
||||
bool isCreature = (mActor.getTypeName() != typeid (ESM::NPC).name());
|
||||
bool isCreature = (mActor.getType() != ESM::NPC::sRecordId);
|
||||
|
||||
if (isCreature)
|
||||
return true;
|
||||
|
@ -207,7 +207,7 @@ bool MWDialogue::Filter::testFunctionLocal(const MWDialogue::SelectWrapper& sele
|
|||
|
||||
bool MWDialogue::Filter::testSelectStruct (const SelectWrapper& select) const
|
||||
{
|
||||
if (select.isNpcOnly() && (mActor.getTypeName() != typeid (ESM::NPC).name()))
|
||||
if (select.isNpcOnly() && (mActor.getType() != ESM::NPC::sRecordId))
|
||||
// If the actor is a creature, we pass all conditions only applicable to NPCs.
|
||||
return true;
|
||||
|
||||
|
@ -452,7 +452,7 @@ int MWDialogue::Filter::getSelectStructInteger (const SelectWrapper& select) con
|
|||
{
|
||||
if (target.getClass().isNpc() && target.getClass().getNpcStats(target).isWerewolf())
|
||||
return 2;
|
||||
if (target.getTypeName() == typeid(ESM::Creature).name())
|
||||
if (target.getType() == ESM::Creature::sRecordId)
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -30,7 +30,7 @@ public:
|
|||
{
|
||||
if (keyword.empty())
|
||||
return;
|
||||
seed_impl (/*std::move*/ (keyword), /*std::move*/ (value), 0, mRoot);
|
||||
seed_impl (std::move(keyword), std::move (value), 0, mRoot);
|
||||
}
|
||||
|
||||
void clear ()
|
||||
|
@ -39,7 +39,7 @@ public:
|
|||
mRoot.mKeyword.clear ();
|
||||
}
|
||||
|
||||
bool containsKeyword (string_t keyword, value_t& value)
|
||||
bool containsKeyword (const string_t& keyword, value_t& value)
|
||||
{
|
||||
typename Entry::childen_t::iterator current;
|
||||
typename Entry::childen_t::iterator next;
|
||||
|
@ -209,8 +209,8 @@ private:
|
|||
|
||||
if (j == entry.mChildren.end ())
|
||||
{
|
||||
entry.mChildren [ch].mValue = /*std::move*/ (value);
|
||||
entry.mChildren [ch].mKeyword = /*std::move*/ (keyword);
|
||||
entry.mChildren [ch].mValue = std::move (value);
|
||||
entry.mChildren [ch].mKeyword = std::move (keyword);
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -219,22 +219,22 @@ private:
|
|||
if (keyword == j->second.mKeyword)
|
||||
throw std::runtime_error ("duplicate keyword inserted");
|
||||
|
||||
value_t pushValue = /*std::move*/ (j->second.mValue);
|
||||
string_t pushKeyword = /*std::move*/ (j->second.mKeyword);
|
||||
value_t pushValue = j->second.mValue;
|
||||
string_t pushKeyword = j->second.mKeyword;
|
||||
|
||||
if (depth >= pushKeyword.size ())
|
||||
throw std::runtime_error ("unexpected");
|
||||
|
||||
if (depth+1 < pushKeyword.size())
|
||||
{
|
||||
seed_impl (/*std::move*/ (pushKeyword), /*std::move*/ (pushValue), depth+1, j->second);
|
||||
seed_impl (std::move (pushKeyword), std::move (pushValue), depth+1, j->second);
|
||||
j->second.mKeyword.clear ();
|
||||
}
|
||||
}
|
||||
if (depth+1 == keyword.size())
|
||||
j->second.mKeyword = value;
|
||||
else // depth+1 < keyword.size()
|
||||
seed_impl (/*std::move*/ (keyword), /*std::move*/ (value), depth+1, j->second);
|
||||
seed_impl (std::move (keyword), std::move (value), depth+1, j->second);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -194,7 +194,7 @@ namespace MWGui
|
|||
for (size_t i = 0; i < mModel->getItemCount(); ++i)
|
||||
{
|
||||
MWWorld::Ptr item = mModel->getItem(i).mBase;
|
||||
if (item.getTypeName() != typeid(ESM::Ingredient).name())
|
||||
if (item.getType() != ESM::Ingredient::sRecordId)
|
||||
continue;
|
||||
|
||||
itemNames.insert(item.getClass().getName(item));
|
||||
|
|
|
@ -8,7 +8,7 @@
|
|||
#include "MyGUI_FactoryManager.h"
|
||||
|
||||
#include <components/misc/utf8stream.hpp>
|
||||
#include <components/sceneutil/util.hpp>
|
||||
#include <components/sceneutil/depth.hpp>
|
||||
|
||||
#include "../mwbase/environment.hpp"
|
||||
#include "../mwbase/windowmanager.hpp"
|
||||
|
@ -1221,7 +1221,7 @@ public:
|
|||
|
||||
RenderXform renderXform (mCroppedParent, textFormat.mRenderItem->getRenderTarget()->getInfo());
|
||||
|
||||
float z = SceneUtil::getReverseZ() ? 1.f : -1.f;
|
||||
float z = SceneUtil::AutoDepth::isReversed() ? 1.f : -1.f;
|
||||
|
||||
GlyphStream glyphStream(textFormat.mFont, static_cast<float>(mCoord.left), static_cast<float>(mCoord.top - mViewTop),
|
||||
z /*mNode->getNodeDepth()*/, vertices, renderXform);
|
||||
|
|
|
@ -38,6 +38,7 @@ namespace MWGui
|
|||
, mSortModel(nullptr)
|
||||
, mModel(nullptr)
|
||||
, mSelectedItem(-1)
|
||||
, mTreatNextOpenAsLoot(false)
|
||||
{
|
||||
getWidget(mDisposeCorpseButton, "DisposeCorpseButton");
|
||||
getWidget(mTakeButton, "TakeButton");
|
||||
|
@ -121,13 +122,15 @@ namespace MWGui
|
|||
|
||||
void ContainerWindow::setPtr(const MWWorld::Ptr& container)
|
||||
{
|
||||
bool lootAnyway = mTreatNextOpenAsLoot;
|
||||
mTreatNextOpenAsLoot = false;
|
||||
mPtr = container;
|
||||
|
||||
bool loot = mPtr.getClass().isActor() && mPtr.getClass().getCreatureStats(mPtr).isDead();
|
||||
|
||||
if (mPtr.getClass().hasInventoryStore(mPtr))
|
||||
{
|
||||
if (mPtr.getClass().isNpc() && !loot)
|
||||
if (mPtr.getClass().isNpc() && !loot && !lootAnyway)
|
||||
{
|
||||
// we are stealing stuff
|
||||
mModel = new PickpocketItemModel(mPtr, new InventoryItemModel(container),
|
||||
|
|
|
@ -37,6 +37,7 @@ namespace MWGui
|
|||
|
||||
void onDeleteCustomData(const MWWorld::Ptr& ptr) override;
|
||||
|
||||
void treatNextOpenAsLoot() { mTreatNextOpenAsLoot = true; };
|
||||
private:
|
||||
DragAndDrop* mDragAndDrop;
|
||||
|
||||
|
@ -44,7 +45,7 @@ namespace MWGui
|
|||
SortFilterItemModel* mSortModel;
|
||||
ItemModel* mModel;
|
||||
int mSelectedItem;
|
||||
|
||||
bool mTreatNextOpenAsLoot;
|
||||
MyGUI::Button* mDisposeCorpseButton;
|
||||
MyGUI::Button* mTakeButton;
|
||||
MyGUI::Button* mCloseButton;
|
||||
|
|
|
@ -209,7 +209,7 @@ bool ContainerItemModel::onDropItem(const MWWorld::Ptr &item, int count)
|
|||
|
||||
MWWorld::Ptr target = mItemSources[0].first;
|
||||
|
||||
if (target.getTypeName() != typeid(ESM::Container).name())
|
||||
if (target.getType() != ESM::Container::sRecordId)
|
||||
return true;
|
||||
|
||||
// check container organic flag
|
||||
|
|
|
@ -347,8 +347,7 @@ namespace MWGui
|
|||
{
|
||||
if (!mScrollBar->getVisible())
|
||||
return;
|
||||
mScrollBar->setScrollPosition(std::min(static_cast<int>(mScrollBar->getScrollRange()-1),
|
||||
std::max(0, static_cast<int>(mScrollBar->getScrollPosition() - _rel*0.3))));
|
||||
mScrollBar->setScrollPosition(std::clamp<int>(mScrollBar->getScrollPosition() - _rel*0.3, 0, mScrollBar->getScrollRange() - 1));
|
||||
onScrollbarMoved(mScrollBar, mScrollBar->getScrollPosition());
|
||||
}
|
||||
|
||||
|
@ -508,13 +507,13 @@ namespace MWGui
|
|||
|
||||
int services = mPtr.getClass().getServices(mPtr);
|
||||
|
||||
bool travel = (mPtr.getTypeName() == typeid(ESM::NPC).name() && !mPtr.get<ESM::NPC>()->mBase->getTransport().empty())
|
||||
|| (mPtr.getTypeName() == typeid(ESM::Creature).name() && !mPtr.get<ESM::Creature>()->mBase->getTransport().empty());
|
||||
bool travel = (mPtr.getType() == ESM::NPC::sRecordId && !mPtr.get<ESM::NPC>()->mBase->getTransport().empty())
|
||||
|| (mPtr.getType() == ESM::Creature::sRecordId && !mPtr.get<ESM::Creature>()->mBase->getTransport().empty());
|
||||
|
||||
const MWWorld::Store<ESM::GameSetting> &gmst =
|
||||
MWBase::Environment::get().getWorld()->getStore().get<ESM::GameSetting>();
|
||||
|
||||
if (mPtr.getTypeName() == typeid(ESM::NPC).name())
|
||||
if (mPtr.getType() == ESM::NPC::sRecordId)
|
||||
mTopicsList->addItem(gmst.find("sPersuasion")->mValue.getString());
|
||||
|
||||
if (services & ESM::NPC::AllItems)
|
||||
|
|
|
@ -109,7 +109,7 @@ namespace MWGui
|
|||
{
|
||||
mEnchantmentPoints->setCaption(std::to_string(static_cast<int>(mEnchanting.getEnchantPoints(false))) + " / " + std::to_string(mEnchanting.getMaxEnchantValue()));
|
||||
mCharge->setCaption(std::to_string(mEnchanting.getGemCharge()));
|
||||
mSuccessChance->setCaption(std::to_string(std::max(0, std::min(100, mEnchanting.getEnchantChance()))));
|
||||
mSuccessChance->setCaption(std::to_string(std::clamp(mEnchanting.getEnchantChance(), 0, 100)));
|
||||
mCastCost->setCaption(std::to_string(mEnchanting.getEffectiveCastCost()));
|
||||
mPrice->setCaption(std::to_string(mEnchanting.getEnchantPrice()));
|
||||
|
||||
|
|
|
@ -81,7 +81,7 @@ namespace MWGui
|
|||
, mMinimap(nullptr)
|
||||
, mCrosshair(nullptr)
|
||||
, mCellNameBox(nullptr)
|
||||
, mDrowningFrame(nullptr)
|
||||
, mDrowningBar(nullptr)
|
||||
, mDrowningFlash(nullptr)
|
||||
, mHealthManaStaminaBaseLeft(0)
|
||||
, mWeapBoxBaseLeft(0)
|
||||
|
@ -119,6 +119,7 @@ namespace MWGui
|
|||
fatigueFrame->eventMouseButtonClick += MyGUI::newDelegate(this, &HUD::onHMSClicked);
|
||||
|
||||
//Drowning bar
|
||||
getWidget(mDrowningBar, "DrowningBar");
|
||||
getWidget(mDrowningFrame, "DrowningFrame");
|
||||
getWidget(mDrowning, "Drowning");
|
||||
getWidget(mDrowningFlash, "Flash");
|
||||
|
@ -224,7 +225,7 @@ namespace MWGui
|
|||
|
||||
void HUD::setDrowningBarVisible(bool visible)
|
||||
{
|
||||
mDrowningFrame->setVisible(visible);
|
||||
mDrowningBar->setVisible(visible);
|
||||
}
|
||||
|
||||
void HUD::onWorldClicked(MyGUI::Widget* _sender)
|
||||
|
@ -368,9 +369,6 @@ namespace MWGui
|
|||
mWeaponSpellBox->setPosition(mWeaponSpellBox->getPosition() + MyGUI::IntPoint(0,20));
|
||||
}
|
||||
|
||||
if (mIsDrowning)
|
||||
mDrowningFlashTheta += dt * osg::PI*2;
|
||||
|
||||
mSpellIcons->updateWidgets(mEffectBox, true);
|
||||
|
||||
if (mEnemyActorId != -1 && mEnemyHealth->getVisible())
|
||||
|
@ -378,8 +376,13 @@ namespace MWGui
|
|||
updateEnemyHealthBar();
|
||||
}
|
||||
|
||||
if (mDrowningBar->getVisible())
|
||||
mDrowningBar->setPosition(mMainWidget->getWidth()/2 - mDrowningFrame->getWidth()/2, mMainWidget->getTop());
|
||||
|
||||
if (mIsDrowning)
|
||||
{
|
||||
mDrowningFlashTheta += dt * osg::PI*2;
|
||||
|
||||
float intensity = (cos(mDrowningFlashTheta) + 2.0f) / 3.0f;
|
||||
|
||||
mDrowningFlash->setAlpha(intensity);
|
||||
|
@ -610,7 +613,7 @@ namespace MWGui
|
|||
|
||||
static const float fNPCHealthBarFade = MWBase::Environment::get().getWorld()->getStore().get<ESM::GameSetting>().find("fNPCHealthBarFade")->mValue.getFloat();
|
||||
if (fNPCHealthBarFade > 0.f)
|
||||
mEnemyHealth->setAlpha(std::max(0.f, std::min(1.f, mEnemyHealthTimer/fNPCHealthBarFade)));
|
||||
mEnemyHealth->setAlpha(std::clamp(mEnemyHealthTimer / fNPCHealthBarFade, 0.f, 1.f));
|
||||
|
||||
}
|
||||
|
||||
|
|
|
@ -73,7 +73,7 @@ namespace MWGui
|
|||
MyGUI::ImageBox* mCrosshair;
|
||||
MyGUI::TextBox* mCellNameBox;
|
||||
MyGUI::TextBox* mWeaponSpellBox;
|
||||
MyGUI::Widget *mDrowningFrame, *mDrowningFlash;
|
||||
MyGUI::Widget *mDrowningBar, *mDrowningFrame, *mDrowningFlash;
|
||||
|
||||
// bottom left elements
|
||||
int mHealthManaStaminaBaseLeft, mWeapBoxBaseLeft, mSpellBoxBaseLeft, mSneakBoxBaseLeft;
|
||||
|
|
|
@ -46,7 +46,7 @@ namespace
|
|||
|
||||
bool isRightHandWeapon(const MWWorld::Ptr& item)
|
||||
{
|
||||
if (item.getClass().getTypeName() != typeid(ESM::Weapon).name())
|
||||
if (item.getClass().getType() != ESM::Weapon::sRecordId)
|
||||
return false;
|
||||
std::vector<int> equipmentSlots = item.getClass().getEquipmentSlots(item).first;
|
||||
return (!equipmentSlots.empty() && equipmentSlots.front() == MWWorld::InventoryStore::Slot_CarriedRight);
|
||||
|
@ -70,7 +70,7 @@ namespace MWGui
|
|||
, mTrading(false)
|
||||
, mUpdateTimer(0.f)
|
||||
{
|
||||
mPreviewTexture.reset(new osgMyGUI::OSGTexture(mPreview->getTexture()));
|
||||
mPreviewTexture.reset(new osgMyGUI::OSGTexture(mPreview->getTexture(), mPreview->getTextureStateSet()));
|
||||
mPreview->rebuild();
|
||||
|
||||
mMainWidget->castType<MyGUI::Window>()->eventWindowChangeCoord += MyGUI::newDelegate(this, &InventoryWindow::onWindowResize);
|
||||
|
@ -281,7 +281,7 @@ namespace MWGui
|
|||
// If we unequip weapon during attack, it can lead to unexpected behaviour
|
||||
if (MWBase::Environment::get().getMechanicsManager()->isAttackingOrSpell(mPtr))
|
||||
{
|
||||
bool isWeapon = item.mBase.getTypeName() == typeid(ESM::Weapon).name();
|
||||
bool isWeapon = item.mBase.getType() == ESM::Weapon::sRecordId;
|
||||
MWWorld::InventoryStore& invStore = mPtr.getClass().getInventoryStore(mPtr);
|
||||
|
||||
if (isWeapon && invStore.isEquipped(item.mBase))
|
||||
|
@ -555,9 +555,9 @@ namespace MWGui
|
|||
if (!script.empty())
|
||||
{
|
||||
// Ingredients, books and repair hammers must not have OnPCEquip set to 1 here
|
||||
const std::string& type = ptr.getTypeName();
|
||||
bool isBook = type == typeid(ESM::Book).name();
|
||||
if (!isBook && type != typeid(ESM::Ingredient).name() && type != typeid(ESM::Repair).name())
|
||||
auto type = ptr.getType();
|
||||
bool isBook = type == ESM::Book::sRecordId;
|
||||
if (!isBook && type != ESM::Ingredient::sRecordId && type != ESM::Repair::sRecordId)
|
||||
ptr.getRefData().getLocals().setVarByInt(script, "onpcequip", 1);
|
||||
// Books must have PCSkipEquip set to 1 instead
|
||||
else if (isBook)
|
||||
|
@ -593,8 +593,8 @@ namespace MWGui
|
|||
useItem(ptr);
|
||||
|
||||
// If item is ingredient or potion don't stop drag and drop to simplify action of taking more than one 1 item
|
||||
if ((ptr.getTypeName() == typeid(ESM::Potion).name() ||
|
||||
ptr.getTypeName() == typeid(ESM::Ingredient).name())
|
||||
if ((ptr.getType() == ESM::Potion::sRecordId ||
|
||||
ptr.getType() == ESM::Ingredient::sRecordId)
|
||||
&& mDragAndDrop->mDraggedCount > 1)
|
||||
{
|
||||
// Item can be provided from other window for example container.
|
||||
|
@ -704,19 +704,19 @@ namespace MWGui
|
|||
if (!MWBase::Environment::get().getWindowManager()->isAllowed(GW_Inventory))
|
||||
return;
|
||||
// make sure the object is of a type that can be picked up
|
||||
const std::string& type = object.getTypeName();
|
||||
if ( (type != typeid(ESM::Apparatus).name())
|
||||
&& (type != typeid(ESM::Armor).name())
|
||||
&& (type != typeid(ESM::Book).name())
|
||||
&& (type != typeid(ESM::Clothing).name())
|
||||
&& (type != typeid(ESM::Ingredient).name())
|
||||
&& (type != typeid(ESM::Light).name())
|
||||
&& (type != typeid(ESM::Miscellaneous).name())
|
||||
&& (type != typeid(ESM::Lockpick).name())
|
||||
&& (type != typeid(ESM::Probe).name())
|
||||
&& (type != typeid(ESM::Repair).name())
|
||||
&& (type != typeid(ESM::Weapon).name())
|
||||
&& (type != typeid(ESM::Potion).name()))
|
||||
auto type = object.getType();
|
||||
if ( (type != ESM::Apparatus::sRecordId)
|
||||
&& (type != ESM::Armor::sRecordId)
|
||||
&& (type != ESM::Book::sRecordId)
|
||||
&& (type != ESM::Clothing::sRecordId)
|
||||
&& (type != ESM::Ingredient::sRecordId)
|
||||
&& (type != ESM::Light::sRecordId)
|
||||
&& (type != ESM::Miscellaneous::sRecordId)
|
||||
&& (type != ESM::Lockpick::sRecordId)
|
||||
&& (type != ESM::Probe::sRecordId)
|
||||
&& (type != ESM::Repair::sRecordId)
|
||||
&& (type != ESM::Weapon::sRecordId)
|
||||
&& (type != ESM::Potion::sRecordId))
|
||||
return;
|
||||
|
||||
// An object that can be picked up must have a tooltip.
|
||||
|
@ -809,7 +809,7 @@ namespace MWGui
|
|||
|
||||
lastId = item.getCellRef().getRefId();
|
||||
|
||||
if (item.getClass().getTypeName() == typeid(ESM::Weapon).name() &&
|
||||
if (item.getClass().getType() == ESM::Weapon::sRecordId &&
|
||||
isRightHandWeapon(item) &&
|
||||
item.getClass().canBeEquipped(item, player).first)
|
||||
{
|
||||
|
|
|
@ -313,9 +313,9 @@ struct JournalViewModelImpl : JournalViewModel
|
|||
for (MWBase::Journal::TTopicIter i = journal->topicBegin (); i != journal->topicEnd (); ++i)
|
||||
{
|
||||
Utf8Stream stream (i->first.c_str());
|
||||
Utf8Stream::UnicodeChar first = Misc::StringUtils::toLowerUtf8(stream.peek());
|
||||
Utf8Stream::UnicodeChar first = Utf8Stream::toLowerUtf8(stream.peek());
|
||||
|
||||
if (first != Misc::StringUtils::toLowerUtf8(character))
|
||||
if (first != Utf8Stream::toLowerUtf8(character))
|
||||
continue;
|
||||
|
||||
visitor (i->second.getName());
|
||||
|
|
|
@ -79,7 +79,7 @@ void KeyboardNavigation::restoreFocus(int mode)
|
|||
if (found != mKeyFocus.end())
|
||||
{
|
||||
MyGUI::Widget* w = found->second;
|
||||
if (w && w->getVisible() && w->getEnabled())
|
||||
if (w && w->getVisible() && w->getEnabled() && w->getInheritedVisible() && w->getInheritedEnabled())
|
||||
MWBase::Environment::get().getWindowManager()->setKeyFocusWidget(found->second);
|
||||
}
|
||||
}
|
||||
|
@ -273,7 +273,7 @@ bool KeyboardNavigation::switchFocus(int direction, bool wrap)
|
|||
if (wrap)
|
||||
index = (index + keyFocusList.size())%keyFocusList.size();
|
||||
else
|
||||
index = std::min(std::max(0, index), static_cast<int>(keyFocusList.size())-1);
|
||||
index = std::clamp<int>(index, 0, keyFocusList.size() - 1);
|
||||
|
||||
MyGUI::Widget* next = keyFocusList[index];
|
||||
int vertdiff = next->getTop() - focus->getTop();
|
||||
|
|
|
@ -4,6 +4,8 @@
|
|||
#include <stdint.h>
|
||||
#include <memory>
|
||||
|
||||
#include <osg/Vec2f>
|
||||
|
||||
#include "windowpinnablebase.hpp"
|
||||
|
||||
#include <components/esm/cellid.hpp>
|
||||
|
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Reference in a new issue