mirror of
https://github.com/OpenMW/openmw.git
synced 2025-03-29 04:06:40 +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
|
BUILD_TYPE: RelWithDebInfo
|
||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
build:
|
Ubuntu:
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
|
|
||||||
steps:
|
steps:
|
||||||
|
@ -26,25 +26,62 @@ jobs:
|
||||||
key: ${{ matrix.os }}-${{ env.BUILD_TYPE }}
|
key: ${{ matrix.os }}-${{ env.BUILD_TYPE }}
|
||||||
max-size: 1000M
|
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
|
- 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
|
- name: Build
|
||||||
run: cmake --build . --config ${{env.BUILD_TYPE}} --parallel 3
|
run: cmake --build . --config ${{env.BUILD_TYPE}} --parallel 3
|
||||||
|
|
||||||
- name: Install
|
- name: Test
|
||||||
shell: bash
|
run: ./openmw_test_suite
|
||||||
run: cmake --install .
|
|
||||||
|
|
||||||
- name: Create Artifact
|
# - name: Install
|
||||||
shell: bash
|
# shell: bash
|
||||||
working-directory: install
|
# run: cmake --install .
|
||||||
run: |
|
|
||||||
ls -laR
|
|
||||||
7z a ../build_artifact.7z .
|
|
||||||
|
|
||||||
- name: Upload Artifact
|
# - name: Create Artifact
|
||||||
uses: actions/upload-artifact@v1
|
# shell: bash
|
||||||
|
# working-directory: install
|
||||||
|
# run: |
|
||||||
|
# ls -laR
|
||||||
|
# 7z a ../build_artifact.7z .
|
||||||
|
|
||||||
|
# - 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:
|
with:
|
||||||
path: ./build_artifact.7z
|
key: ${{ matrix.os }}-${{ env.BUILD_TYPE }}
|
||||||
name: build_artifact.7z
|
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:
|
stages:
|
||||||
- build
|
- build
|
||||||
|
|
||||||
.Debian_Image:
|
.Ubuntu_Image:
|
||||||
tags:
|
tags:
|
||||||
- docker
|
- docker
|
||||||
- linux
|
- linux
|
||||||
image: debian:bullseye
|
image: ubuntu:focal
|
||||||
|
rules:
|
||||||
|
- if: $CI_PIPELINE_SOURCE == "push"
|
||||||
|
|
||||||
.Debian:
|
|
||||||
extends: .Debian_Image
|
.Ubuntu:
|
||||||
|
extends: .Ubuntu_Image
|
||||||
cache:
|
cache:
|
||||||
paths:
|
paths:
|
||||||
- apt-cache/
|
- apt-cache/
|
||||||
|
@ -32,11 +35,12 @@ stages:
|
||||||
- build/install/
|
- build/install/
|
||||||
|
|
||||||
Clang_Tidy:
|
Clang_Tidy:
|
||||||
extends: .Debian_Image
|
extends: .Ubuntu_Image
|
||||||
stage: build
|
stage: build
|
||||||
rules:
|
rules:
|
||||||
- if: '$CI_PIPELINE_SOURCE == "schedule"'
|
- if: '$CI_PIPELINE_SOURCE == "schedule"'
|
||||||
before_script:
|
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
|
- CI/install_debian_deps.sh gcc openmw-deps openmw-deps-dynamic clang-tidy clang
|
||||||
script:
|
script:
|
||||||
- CI/before_script.linux.sh
|
- CI/before_script.linux.sh
|
||||||
|
@ -47,13 +51,17 @@ Clang_Tidy:
|
||||||
CXX: clang++
|
CXX: clang++
|
||||||
CI_CLANG_TIDY: 1
|
CI_CLANG_TIDY: 1
|
||||||
timeout: 8h
|
timeout: 8h
|
||||||
|
artifacts:
|
||||||
|
paths: []
|
||||||
|
expire_in: 1 minute
|
||||||
|
|
||||||
Coverity:
|
Coverity:
|
||||||
extends: .Debian_Image
|
extends: .Ubuntu_Image
|
||||||
stage: build
|
stage: build
|
||||||
rules:
|
rules:
|
||||||
- if: '$CI_PIPELINE_SOURCE == "schedule"'
|
- if: $CI_PIPELINE_SOURCE == "schedule"
|
||||||
before_script:
|
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
|
- 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
|
- 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
|
- tar xfz /tmp/cov-analysis-linux64.tgz
|
||||||
|
@ -67,16 +75,20 @@ Coverity:
|
||||||
--form token=$COVERITY_SCAN_TOKEN --form email=$GITLAB_USER_EMAIL
|
--form token=$COVERITY_SCAN_TOKEN --form email=$GITLAB_USER_EMAIL
|
||||||
--form file=@cov-int.tar.gz --form version="`git describe --tags`"
|
--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"
|
--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:
|
variables:
|
||||||
CC: gcc
|
CC: gcc
|
||||||
CXX: g++
|
CXX: g++
|
||||||
artifacts:
|
artifacts:
|
||||||
|
paths: []
|
||||||
|
expire_in: 1 minute
|
||||||
|
|
||||||
Debian_GCC:
|
Ubuntu_GCC:
|
||||||
extends: .Debian
|
extends: .Ubuntu
|
||||||
cache:
|
cache:
|
||||||
key: Debian_GCC.v2
|
key: Ubuntu_GCC.v2
|
||||||
before_script:
|
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
|
- CI/install_debian_deps.sh gcc openmw-deps openmw-deps-dynamic
|
||||||
variables:
|
variables:
|
||||||
CC: gcc
|
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.
|
# 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
|
timeout: 2h
|
||||||
|
|
||||||
Debian_GCC_tests:
|
Ubuntu_GCC_tests:
|
||||||
extends: Debian_GCC
|
extends: Ubuntu_GCC
|
||||||
cache:
|
cache:
|
||||||
key: Debian_GCC_tests.v2
|
key: Ubuntu_GCC_tests.v2
|
||||||
variables:
|
variables:
|
||||||
CCACHE_SIZE: 1G
|
CCACHE_SIZE: 1G
|
||||||
BUILD_TESTS_ONLY: 1
|
BUILD_TESTS_ONLY: 1
|
||||||
|
artifacts:
|
||||||
|
paths: []
|
||||||
|
expire_in: 1 minute
|
||||||
|
|
||||||
Debian_GCC_tests_Debug:
|
Ubuntu_GCC_tests_Debug:
|
||||||
extends: Debian_GCC
|
extends: Ubuntu_GCC
|
||||||
cache:
|
cache:
|
||||||
key: Debian_GCC_tests_Debug.v1
|
key: Ubuntu_GCC_tests_Debug.v1
|
||||||
variables:
|
variables:
|
||||||
CCACHE_SIZE: 1G
|
CCACHE_SIZE: 1G
|
||||||
BUILD_TESTS_ONLY: 1
|
BUILD_TESTS_ONLY: 1
|
||||||
CMAKE_BUILD_TYPE: Debug
|
CMAKE_BUILD_TYPE: Debug
|
||||||
|
artifacts:
|
||||||
|
paths: []
|
||||||
|
expire_in: 1 minute
|
||||||
|
|
||||||
Debian_GCC_Static_Deps:
|
Ubuntu_GCC_Static_Deps:
|
||||||
extends: Debian_GCC
|
extends: Ubuntu_GCC
|
||||||
cache:
|
cache:
|
||||||
key: Debian_GCC_Static_Deps
|
key: Ubuntu_GCC_Static_Deps
|
||||||
paths:
|
paths:
|
||||||
- apt-cache/
|
- apt-cache/
|
||||||
- ccache/
|
- ccache/
|
||||||
- build/extern/fetched/
|
- build/extern/fetched/
|
||||||
before_script:
|
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
|
- CI/install_debian_deps.sh gcc openmw-deps openmw-deps-static
|
||||||
variables:
|
variables:
|
||||||
CI_OPENMW_USE_STATIC_DEPS: 1
|
CI_OPENMW_USE_STATIC_DEPS: 1
|
||||||
timeout: 3h
|
timeout: 3h
|
||||||
|
|
||||||
Debian_GCC_Static_Deps_tests:
|
Ubuntu_GCC_Static_Deps_tests:
|
||||||
extends: Debian_GCC_Static_Deps
|
extends: Ubuntu_GCC_Static_Deps
|
||||||
cache:
|
cache:
|
||||||
key: Debian_GCC_Static_Deps_tests
|
key: Ubuntu_GCC_Static_Deps_tests
|
||||||
variables:
|
variables:
|
||||||
CCACHE_SIZE: 1G
|
CCACHE_SIZE: 1G
|
||||||
BUILD_TESTS_ONLY: 1
|
BUILD_TESTS_ONLY: 1
|
||||||
|
artifacts:
|
||||||
|
paths: []
|
||||||
|
expire_in: 1 minute
|
||||||
|
|
||||||
Debian_Clang:
|
Ubuntu_Clang:
|
||||||
extends: .Debian
|
extends: .Ubuntu
|
||||||
before_script:
|
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
|
- CI/install_debian_deps.sh clang openmw-deps openmw-deps-dynamic
|
||||||
cache:
|
cache:
|
||||||
key: Debian_Clang.v2
|
key: Ubuntu_Clang.v2
|
||||||
variables:
|
variables:
|
||||||
CC: clang
|
CC: clang
|
||||||
CXX: 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.
|
# 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
|
timeout: 2h
|
||||||
|
|
||||||
Debian_Clang_tests:
|
Ubuntu_Clang_tests:
|
||||||
extends: Debian_Clang
|
extends: Ubuntu_Clang
|
||||||
cache:
|
cache:
|
||||||
key: Debian_Clang_tests.v2
|
key: Ubuntu_Clang_tests.v2
|
||||||
variables:
|
variables:
|
||||||
CCACHE_SIZE: 1G
|
CCACHE_SIZE: 1G
|
||||||
BUILD_TESTS_ONLY: 1
|
BUILD_TESTS_ONLY: 1
|
||||||
|
artifacts:
|
||||||
|
paths: []
|
||||||
|
expire_in: 1 minute
|
||||||
|
|
||||||
Debian_Clang_tests_Debug:
|
Ubuntu_Clang_tests_Debug:
|
||||||
extends: Debian_Clang
|
extends: Ubuntu_Clang
|
||||||
cache:
|
cache:
|
||||||
key: Debian_Clang_tests_Debug.v1
|
key: Ubuntu_Clang_tests_Debug.v1
|
||||||
variables:
|
variables:
|
||||||
CCACHE_SIZE: 1G
|
CCACHE_SIZE: 1G
|
||||||
BUILD_TESTS_ONLY: 1
|
BUILD_TESTS_ONLY: 1
|
||||||
CMAKE_BUILD_TYPE: Debug
|
CMAKE_BUILD_TYPE: Debug
|
||||||
|
artifacts:
|
||||||
|
paths: []
|
||||||
|
expire_in: 1 minute
|
||||||
|
|
||||||
.MacOS:
|
.MacOS:
|
||||||
image: macos-11-xcode-12
|
image: macos-11-xcode-12
|
||||||
|
@ -161,7 +190,7 @@ Debian_Clang_tests_Debug:
|
||||||
stage: build
|
stage: build
|
||||||
only:
|
only:
|
||||||
variables:
|
variables:
|
||||||
- $CI_PROJECT_ID == "7107382"
|
- $CI_PROJECT_ID == "7107382" && $CI_PIPELINE_SOURCE == "push"
|
||||||
cache:
|
cache:
|
||||||
paths:
|
paths:
|
||||||
- ccache/
|
- ccache/
|
||||||
|
@ -174,7 +203,7 @@ Debian_Clang_tests_Debug:
|
||||||
- ccache -z -M "${CCACHE_SIZE}"
|
- ccache -z -M "${CCACHE_SIZE}"
|
||||||
- CI/before_script.osx.sh
|
- CI/before_script.osx.sh
|
||||||
- cd build; make -j $(sysctl -n hw.logicalcpu) package
|
- 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
|
- ccache -s
|
||||||
artifacts:
|
artifacts:
|
||||||
paths:
|
paths:
|
||||||
|
@ -184,26 +213,17 @@ Debian_Clang_tests_Debug:
|
||||||
macOS11_Xcode12:
|
macOS11_Xcode12:
|
||||||
extends: .MacOS
|
extends: .MacOS
|
||||||
image: macos-11-xcode-12
|
image: macos-11-xcode-12
|
||||||
allow_failure: true
|
|
||||||
cache:
|
cache:
|
||||||
key: macOS11_Xcode12.v1
|
key: macOS11_Xcode12.v1
|
||||||
variables:
|
variables:
|
||||||
CCACHE_SIZE: 3G
|
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
|
variables: &engine-targets
|
||||||
targets: "openmw,openmw-essimporter,openmw-iniimporter,openmw-launcher,openmw-wizard"
|
targets: "openmw,openmw-iniimporter,openmw-launcher,openmw-wizard"
|
||||||
package: "Engine"
|
package: "Engine"
|
||||||
|
|
||||||
variables: &cs-targets
|
variables: &cs-targets
|
||||||
targets: "openmw-cs,bsatool,esmtool,niftest"
|
targets: "openmw-cs,bsatool,esmtool,niftest,openmw-essimporter"
|
||||||
package: "CS"
|
package: "CS"
|
||||||
|
|
||||||
variables: &tests-targets
|
variables: &tests-targets
|
||||||
|
@ -213,6 +233,8 @@ variables: &tests-targets
|
||||||
.Windows_Ninja_Base:
|
.Windows_Ninja_Base:
|
||||||
tags:
|
tags:
|
||||||
- windows
|
- windows
|
||||||
|
rules:
|
||||||
|
- if: $CI_PIPELINE_SOURCE == "push"
|
||||||
before_script:
|
before_script:
|
||||||
- Import-Module "$env:ChocolateyInstall\helpers\chocolateyProfile.psm1"
|
- Import-Module "$env:ChocolateyInstall\helpers\chocolateyProfile.psm1"
|
||||||
- choco source add -n=openmw-proxy -s="https://repo.openmw.org/repository/Chocolatey/" --priority=1
|
- 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"
|
config: "RelWithDebInfo"
|
||||||
# Gitlab can't successfully execute following binaries due to unknown reason
|
# Gitlab can't successfully execute following binaries due to unknown reason
|
||||||
# executables: "openmw_test_suite.exe,openmw_detournavigator_navmeshtilescache_benchmark.exe"
|
# executables: "openmw_test_suite.exe,openmw_detournavigator_navmeshtilescache_benchmark.exe"
|
||||||
|
artifacts:
|
||||||
|
paths: []
|
||||||
|
expire_in: 1 minute
|
||||||
|
|
||||||
.Windows_MSBuild_Base:
|
.Windows_MSBuild_Base:
|
||||||
tags:
|
tags:
|
||||||
- windows
|
- windows
|
||||||
|
rules:
|
||||||
|
- if: $CI_PIPELINE_SOURCE == "push"
|
||||||
before_script:
|
before_script:
|
||||||
- Import-Module "$env:ChocolateyInstall\helpers\chocolateyProfile.psm1"
|
- Import-Module "$env:ChocolateyInstall\helpers\chocolateyProfile.psm1"
|
||||||
- choco source add -n=openmw-proxy -s="https://repo.openmw.org/repository/Chocolatey/" --priority=1
|
- choco source add -n=openmw-proxy -s="https://repo.openmw.org/repository/Chocolatey/" --priority=1
|
||||||
|
@ -395,6 +422,10 @@ Windows_MSBuild_Engine_Release:
|
||||||
variables:
|
variables:
|
||||||
<<: *engine-targets
|
<<: *engine-targets
|
||||||
config: "Release"
|
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:
|
Windows_MSBuild_Engine_Debug:
|
||||||
extends:
|
extends:
|
||||||
|
@ -416,6 +447,10 @@ Windows_MSBuild_CS_Release:
|
||||||
variables:
|
variables:
|
||||||
<<: *cs-targets
|
<<: *cs-targets
|
||||||
config: "Release"
|
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:
|
Windows_MSBuild_CS_Debug:
|
||||||
extends:
|
extends:
|
||||||
|
@ -439,25 +474,28 @@ Windows_MSBuild_Tests_RelWithDebInfo:
|
||||||
config: "RelWithDebInfo"
|
config: "RelWithDebInfo"
|
||||||
# Gitlab can't successfully execute following binaries due to unknown reason
|
# Gitlab can't successfully execute following binaries due to unknown reason
|
||||||
# executables: "openmw_test_suite.exe,openmw_detournavigator_navmeshtilescache_benchmark.exe"
|
# 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:
|
tags:
|
||||||
- linux
|
- linux
|
||||||
image: debian:bullseye
|
image: psi29a/android-ndk:focal-ndk22
|
||||||
|
rules:
|
||||||
|
- if: $CI_PIPELINE_SOURCE == "push"
|
||||||
variables:
|
variables:
|
||||||
CCACHE_SIZE: 3G
|
CCACHE_SIZE: 3G
|
||||||
cache:
|
cache:
|
||||||
key: Debian_AndroidNDK_arm64-v8a.v3
|
key: Ubuntu__Focal_AndroidNDK_r22b_arm64-v8a.v1
|
||||||
paths:
|
paths:
|
||||||
- apt-cache/
|
- apt-cache/
|
||||||
- ccache/
|
- ccache/
|
||||||
- build/extern/fetched/
|
- build/extern/fetched/
|
||||||
before_script:
|
before_script:
|
||||||
- export APT_CACHE_DIR=`pwd`/apt-cache && mkdir -pv $APT_CACHE_DIR
|
- 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 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
|
stage: build
|
||||||
script:
|
script:
|
||||||
- export CCACHE_BASEDIR="`pwd`"
|
- 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.
|
# 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
|
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
|
Allofich
|
||||||
Andreas Stöckel
|
Andreas Stöckel
|
||||||
Andrei Kortunov (akortunov)
|
Andrei Kortunov (akortunov)
|
||||||
|
Andrew Appuhamy (andrew-app)
|
||||||
AnyOldName3
|
AnyOldName3
|
||||||
Ardekantur
|
Ardekantur
|
||||||
Armin Preiml
|
Armin Preiml
|
||||||
|
@ -92,6 +93,7 @@ Programmers
|
||||||
Haoda Wang (h313)
|
Haoda Wang (h313)
|
||||||
hristoast
|
hristoast
|
||||||
Internecine
|
Internecine
|
||||||
|
Ivan Beloborodov (myrix)
|
||||||
Jackerty
|
Jackerty
|
||||||
Jacob Essex (Yacoby)
|
Jacob Essex (Yacoby)
|
||||||
Jacob Turnbull (Tankinfrank)
|
Jacob Turnbull (Tankinfrank)
|
||||||
|
@ -177,6 +179,7 @@ Programmers
|
||||||
PlutonicOverkill
|
PlutonicOverkill
|
||||||
Radu-Marius Popovici (rpopovici)
|
Radu-Marius Popovici (rpopovici)
|
||||||
Rafael Moura (dhustkoder)
|
Rafael Moura (dhustkoder)
|
||||||
|
Randy Davin (Kindi)
|
||||||
rdimesio
|
rdimesio
|
||||||
rexelion
|
rexelion
|
||||||
riothamus
|
riothamus
|
||||||
|
@ -214,6 +217,7 @@ Programmers
|
||||||
tlmullis
|
tlmullis
|
||||||
tri4ng1e
|
tri4ng1e
|
||||||
Thoronador
|
Thoronador
|
||||||
|
Tom Lowe (Vulpen)
|
||||||
Tom Mason (wheybags)
|
Tom Mason (wheybags)
|
||||||
Torben Leif Carrington (TorbenC)
|
Torben Leif Carrington (TorbenC)
|
||||||
unelsson
|
unelsson
|
||||||
|
@ -229,7 +233,7 @@ Programmers
|
||||||
Yuri Krupenin
|
Yuri Krupenin
|
||||||
zelurker
|
zelurker
|
||||||
Noah Gooder
|
Noah Gooder
|
||||||
Andrew Appuhamy (andrew-app)
|
|
||||||
|
|
||||||
Documentation
|
Documentation
|
||||||
-------------
|
-------------
|
||||||
|
|
47
CHANGELOG.md
47
CHANGELOG.md
|
@ -2,19 +2,29 @@
|
||||||
------
|
------
|
||||||
|
|
||||||
Bug #1751: Birthsign abilities increase modified attribute values instead of base ones
|
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 #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 #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 #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 #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 #3905: Great House Dagoth issues
|
||||||
Bug #4203: Resurrecting an actor should close the loot GUI
|
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 #4602: Robert's Bodies: crash inside createInstance()
|
||||||
Bug #4700: Editor: Incorrect command implementation
|
Bug #4700: Editor: Incorrect command implementation
|
||||||
Bug #4744: Invisible particles must still be processed
|
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 #5100: Persuasion doesn't always clamp the resulting disposition
|
||||||
Bug #5120: Scripted object spawning updates physics system
|
Bug #5120: Scripted object spawning updates physics system
|
||||||
Bug #5207: Loose summons can be present in scene
|
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 #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 #5453: Magic effect VFX are offset for creatures
|
||||||
Bug #5483: AutoCalc flag is not used to calculate spells cost
|
Bug #5483: AutoCalc flag is not used to calculate spells cost
|
||||||
Bug #5508: Engine binary links to Qt without using it
|
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 #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 #5842: GetDisposition adds temporary disposition change from different actors
|
||||||
Bug #5863: GetEffect should return true after the player has teleported
|
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 #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 #6051: NaN water height in ESM file is not handled gracefully
|
||||||
Bug #6066: addtopic "return" does not work from within script. No errors thrown
|
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 #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 #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 #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 #6172: Some creatures can't open doors
|
||||||
Bug #6174: Spellmaking and Enchanting sliders differences from vanilla
|
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 #6184: Command and Calm and Demoralize and Frenzy and Rally magic effects inconsistencies with vanilla
|
||||||
Bug #6197: Infinite Casting Loop
|
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 #6273: Respawning NPCs rotation is inconsistent
|
||||||
Bug #6282: Laura craft doesn't follow the player character
|
Bug #6282: Laura craft doesn't follow the player character
|
||||||
Bug #6283: Avis Dorsey follows you after her death
|
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 #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 #6291: Can't pickup the dead mage's journal from the mysterious hunter mod
|
||||||
Bug #6302: Teleporting disabled actor breaks its disabled state
|
Bug #6302: Teleporting disabled actor breaks its disabled state
|
||||||
Bug #6307: Pathfinding in Infidelities quest from Tribunal addon is broken
|
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 #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 #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 #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 #2780: A way to see current OpenMW version in the console
|
||||||
Feature #3616: Allow Zoom levels on the World Map
|
Feature #3616: Allow Zoom levels on the World Map
|
||||||
|
@ -66,15 +104,20 @@
|
||||||
Feature #5996: Support Lua scripts in OpenMW
|
Feature #5996: Support Lua scripts in OpenMW
|
||||||
Feature #6017: Separate persistent and temporary cell references when saving
|
Feature #6017: Separate persistent and temporary cell references when saving
|
||||||
Feature #6032: Reverse-z depth buffer
|
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 #6162: Refactor GUI to use shaders and to be GLES and GL3+ friendly
|
||||||
Feature #6199: Support FBO Rendering
|
Feature #6199: Support FBO Rendering
|
||||||
|
Feature #6248: Embedded error marker mesh
|
||||||
Feature #6249: Alpha testing support for Collada
|
Feature #6249: Alpha testing support for Collada
|
||||||
Feature #6251: OpenMW-CS: Set instance movement based on camera zoom
|
Feature #6251: OpenMW-CS: Set instance movement based on camera zoom
|
||||||
Feature #6288: Preserve the "blocked" record flag for referenceable objects.
|
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 #6201: Remove the "Note: No relevant classes found. No output generated" warnings
|
||||||
Task #6264: Remove the old classes in animation.cpp
|
Task #6264: Remove the old classes in animation.cpp
|
||||||
|
|
||||||
|
|
||||||
0.47.0
|
0.47.0
|
||||||
------
|
------
|
||||||
|
|
||||||
|
@ -208,6 +251,8 @@
|
||||||
Bug #6043: Actor can have torch missing when torch animation is played
|
Bug #6043: Actor can have torch missing when torch animation is played
|
||||||
Bug #6047: Mouse bindings can be triggered during save loading
|
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 #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
|
Bug #6294: Game crashes with empty pathgrid
|
||||||
Feature #390: 3rd person look "over the shoulder"
|
Feature #390: 3rd person look "over the shoulder"
|
||||||
Feature #832: OpenMW-CS: Handle deleted references
|
Feature #832: OpenMW-CS: Handle deleted references
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
#!/bin/sh -ex
|
#!/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
|
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 /usr/lib/android-sdk/ndk-bundle/toolchains/llvm/prebuilt/linux-x86_64/sysroot/usr > /dev/null
|
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
|
cd build
|
||||||
|
|
||||||
cmake \
|
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_ABI=arm64-v8a \
|
||||||
-DANDROID_PLATFORM=android-21 \
|
-DANDROID_PLATFORM=android-21 \
|
||||||
|
-DANDROID_LD=deprecated \
|
||||||
-DCMAKE_C_COMPILER_LAUNCHER=ccache \
|
-DCMAKE_C_COMPILER_LAUNCHER=ccache \
|
||||||
-DCMAKE_CXX_COMPILER_LAUNCHER=ccache \
|
-DCMAKE_CXX_COMPILER_LAUNCHER=ccache \
|
||||||
-DCMAKE_INSTALL_PREFIX=install \
|
-DCMAKE_INSTALL_PREFIX=install \
|
||||||
|
@ -22,6 +23,5 @@ cmake \
|
||||||
-DBUILD_OPENCS=0 \
|
-DBUILD_OPENCS=0 \
|
||||||
-DBUILD_WIZARD=0 \
|
-DBUILD_WIZARD=0 \
|
||||||
-DOPENMW_USE_SYSTEM_MYGUI=OFF \
|
-DOPENMW_USE_SYSTEM_MYGUI=OFF \
|
||||||
-DOPENMW_USE_SYSTEM_OSG=OFF \
|
-DOPENMW_USE_SYSTEM_SQLITE3=OFF \
|
||||||
-DOPENMW_USE_SYSTEM_BULLET=OFF \
|
|
||||||
..
|
..
|
||||||
|
|
|
@ -40,6 +40,7 @@ if [[ $CI_OPENMW_USE_STATIC_DEPS ]]; then
|
||||||
-DOPENMW_USE_SYSTEM_MYGUI=OFF
|
-DOPENMW_USE_SYSTEM_MYGUI=OFF
|
||||||
-DOPENMW_USE_SYSTEM_OSG=OFF
|
-DOPENMW_USE_SYSTEM_OSG=OFF
|
||||||
-DOPENMW_USE_SYSTEM_BULLET=OFF
|
-DOPENMW_USE_SYSTEM_BULLET=OFF
|
||||||
|
-DOPENMW_USE_SYSTEM_SQLITE3=OFF
|
||||||
)
|
)
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
|
|
@ -1018,6 +1018,7 @@ echo
|
||||||
echo "Setting up OpenMW build..."
|
echo "Setting up OpenMW build..."
|
||||||
add_cmake_opts -DOPENMW_MP_BUILD=on
|
add_cmake_opts -DOPENMW_MP_BUILD=on
|
||||||
add_cmake_opts -DCMAKE_INSTALL_PREFIX="${INSTALL_PREFIX}"
|
add_cmake_opts -DCMAKE_INSTALL_PREFIX="${INSTALL_PREFIX}"
|
||||||
|
add_cmake_opts -DOPENMW_USE_SYSTEM_SQLITE3=OFF
|
||||||
if [ ! -z $CI ]; then
|
if [ ! -z $CI ]; then
|
||||||
case $STEP in
|
case $STEP in
|
||||||
components )
|
components )
|
||||||
|
|
|
@ -19,6 +19,7 @@ cmake \
|
||||||
-D CMAKE_OSX_DEPLOYMENT_TARGET="10.14" \
|
-D CMAKE_OSX_DEPLOYMENT_TARGET="10.14" \
|
||||||
-D CMAKE_BUILD_TYPE=RELEASE \
|
-D CMAKE_BUILD_TYPE=RELEASE \
|
||||||
-D OPENMW_OSX_DEPLOYMENT=TRUE \
|
-D OPENMW_OSX_DEPLOYMENT=TRUE \
|
||||||
|
-D OPENMW_USE_SYSTEM_SQLITE3=OFF \
|
||||||
-D BUILD_OPENMW=TRUE \
|
-D BUILD_OPENMW=TRUE \
|
||||||
-D BUILD_OPENCS=TRUE \
|
-D BUILD_OPENCS=TRUE \
|
||||||
-D BUILD_ESMTOOL=TRUE \
|
-D BUILD_ESMTOOL=TRUE \
|
||||||
|
|
|
@ -27,7 +27,7 @@ declare -rA GROUPED_DEPS=(
|
||||||
# TODO: add librecastnavigation-dev when debian is ready
|
# TODO: add librecastnavigation-dev when debian is ready
|
||||||
|
|
||||||
# These dependencies can alternatively be built and linked statically.
|
# 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"
|
[coverity]="curl"
|
||||||
[clang-tidy]="clang-tidy"
|
[clang-tidy]="clang-tidy"
|
||||||
|
|
||||||
|
|
|
@ -149,6 +149,8 @@ else()
|
||||||
endif()
|
endif()
|
||||||
option(RECASTNAVIGATION_STATIC "Build recastnavigation static libraries" ${_recastnavigation_static_default})
|
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_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)
|
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)
|
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()
|
endif()
|
||||||
|
|
||||||
|
if(MSVC)
|
||||||
|
add_compile_options("/utf-8")
|
||||||
|
endif()
|
||||||
|
|
||||||
# Dependencies
|
# Dependencies
|
||||||
find_package(OpenGL REQUIRED)
|
find_package(OpenGL REQUIRED)
|
||||||
|
|
||||||
|
@ -408,7 +414,8 @@ else(USE_LUAJIT)
|
||||||
endif(USE_LUAJIT)
|
endif(USE_LUAJIT)
|
||||||
|
|
||||||
# C++ library binding to Lua
|
# 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(
|
include_directories(
|
||||||
BEFORE SYSTEM
|
BEFORE SYSTEM
|
||||||
|
@ -420,7 +427,8 @@ include_directories(
|
||||||
${OPENGL_INCLUDE_DIR}
|
${OPENGL_INCLUDE_DIR}
|
||||||
${BULLET_INCLUDE_DIRS}
|
${BULLET_INCLUDE_DIRS}
|
||||||
${LUA_INCLUDE_DIR}
|
${LUA_INCLUDE_DIR}
|
||||||
${SOL_INCLUDE_DIRS}
|
${SOL_INCLUDE_DIR}
|
||||||
|
${SOL_CONFIG_DIR}
|
||||||
)
|
)
|
||||||
|
|
||||||
link_directories(${SDL2_LIBRARY_DIRS} ${Boost_LIBRARY_DIRS})
|
link_directories(${SDL2_LIBRARY_DIRS} ${Boost_LIBRARY_DIRS})
|
||||||
|
@ -437,9 +445,8 @@ if (APPLE)
|
||||||
"${APP_BUNDLE_DIR}/Contents/Resources/OpenMW.icns" COPYONLY)
|
"${APP_BUNDLE_DIR}/Contents/Resources/OpenMW.icns" COPYONLY)
|
||||||
endif (APPLE)
|
endif (APPLE)
|
||||||
|
|
||||||
if (NOT APPLE)
|
if (NOT APPLE) # this is modified for macOS use later in "apps/open[mw|cs]/CMakeLists.txt"
|
||||||
set(OPENMW_MYGUI_FILES_ROOT ${OpenMW_BINARY_DIR})
|
set(OPENMW_RESOURCES_ROOT ${OpenMW_BINARY_DIR})
|
||||||
set(OPENMW_SHADERS_ROOT ${OpenMW_BINARY_DIR})
|
|
||||||
endif ()
|
endif ()
|
||||||
|
|
||||||
add_subdirectory(files/)
|
add_subdirectory(files/)
|
||||||
|
@ -703,8 +710,12 @@ if (WIN32)
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
if (BUILD_OPENMW AND APPLE)
|
if (BUILD_OPENMW AND APPLE)
|
||||||
|
if (USE_LUAJIT)
|
||||||
# Without these flags LuaJit crashes on startup on OSX
|
# Without these flags LuaJit crashes on startup on OSX
|
||||||
set_target_properties(openmw PROPERTIES LINK_FLAGS "-pagezero_size 10000 -image_base 100000000")
|
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()
|
endif()
|
||||||
|
|
||||||
# Apple bundling
|
# Apple bundling
|
||||||
|
|
|
@ -1,8 +1,6 @@
|
||||||
OpenMW
|
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 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.
|
OpenMW also comes with OpenMW-CS, a replacement for Bethesda's Construction Set.
|
||||||
|
|
|
@ -25,18 +25,10 @@ namespace
|
||||||
};
|
};
|
||||||
|
|
||||||
template <typename Random>
|
template <typename Random>
|
||||||
TilePosition generateTilePosition(int max, Random& random)
|
osg::Vec2i generateVec2i(int max, Random& random)
|
||||||
{
|
{
|
||||||
std::uniform_int_distribution<int> distribution(0, max);
|
std::uniform_int_distribution<int> distribution(0, max);
|
||||||
return TilePosition(distribution(random), distribution(random));
|
return osg::Vec2i(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)};
|
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename Random>
|
template <typename Random>
|
||||||
|
@ -91,8 +83,7 @@ namespace
|
||||||
{
|
{
|
||||||
std::uniform_real_distribution<float> distribution(0.0, 1.0);
|
std::uniform_real_distribution<float> distribution(0.0, 1.0);
|
||||||
std::generate_n(out, count, [&] {
|
std::generate_n(out, count, [&] {
|
||||||
const osg::Vec3f shift(distribution(random), distribution(random), distribution(random));
|
return CellWater {generateVec2i(1000, random), Water {ESM::Land::REAL_SIZE, distribution(random)}};
|
||||||
return Cell {1, shift};
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -117,16 +108,18 @@ namespace
|
||||||
{
|
{
|
||||||
std::uniform_real_distribution<float> distribution(0.0, 1.0);
|
std::uniform_real_distribution<float> distribution(0.0, 1.0);
|
||||||
Heightfield result;
|
Heightfield result;
|
||||||
result.mBounds = generateTileBounds(random);
|
result.mCellPosition = generateVec2i(1000, random);
|
||||||
|
result.mCellSize = ESM::Land::REAL_SIZE;
|
||||||
result.mMinHeight = distribution(random);
|
result.mMinHeight = distribution(random);
|
||||||
result.mMaxHeight = result.mMinHeight + 1.0;
|
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);
|
result.mLength = static_cast<std::uint8_t>(ESM::Land::LAND_SIZE);
|
||||||
std::generate_n(std::back_inserter(result.mHeights), ESM::Land::LAND_NUM_VERTS, [&]
|
std::generate_n(std::back_inserter(result.mHeights), ESM::Land::LAND_NUM_VERTS, [&]
|
||||||
{
|
{
|
||||||
return distribution(random);
|
return distribution(random);
|
||||||
});
|
});
|
||||||
|
result.mOriginalSize = ESM::Land::LAND_SIZE;
|
||||||
|
result.mMinX = 0;
|
||||||
|
result.mMinY = 0;
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -135,7 +128,8 @@ namespace
|
||||||
{
|
{
|
||||||
std::uniform_real_distribution<float> distribution(0.0, 1.0);
|
std::uniform_real_distribution<float> distribution(0.0, 1.0);
|
||||||
FlatHeightfield result;
|
FlatHeightfield result;
|
||||||
result.mBounds = generateTileBounds(random);
|
result.mCellPosition = generateVec2i(1000, random);
|
||||||
|
result.mCellSize = ESM::Land::REAL_SIZE;
|
||||||
result.mHeight = distribution(random);
|
result.mHeight = distribution(random);
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
@ -144,11 +138,11 @@ namespace
|
||||||
Key generateKey(std::size_t triangles, Random& random)
|
Key generateKey(std::size_t triangles, Random& random)
|
||||||
{
|
{
|
||||||
const osg::Vec3f agentHalfExtents = generateAgentHalfExtents(0.5, 1.5, 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 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);
|
const std::size_t revision = std::uniform_int_distribution<std::size_t>(0, 10000)(random);
|
||||||
Mesh mesh = generateMesh(triangles, random);
|
Mesh mesh = generateMesh(triangles, random);
|
||||||
std::vector<Cell> water;
|
std::vector<CellWater> water;
|
||||||
generateWater(std::back_inserter(water), 1, random);
|
generateWater(std::back_inserter(water), 1, random);
|
||||||
RecastMesh recastMesh(generation, revision, std::move(mesh), std::move(water),
|
RecastMesh recastMesh(generation, revision, std::move(mesh), std::move(water),
|
||||||
{generateHeightfield(random)}, {generateFlatHeightfield(random)});
|
{generateHeightfield(random)}, {generateFlatHeightfield(random)});
|
||||||
|
|
|
@ -233,7 +233,17 @@ int extract(std::unique_ptr<Bsa::BSAFile>& bsa, Arguments& info)
|
||||||
std::string extractPath = info.extractfile;
|
std::string extractPath = info.extractfile;
|
||||||
Misc::StringUtils::replaceAll(extractPath, "\\", "/");
|
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 << "ERROR: file '" << archivePath << "' not found\n";
|
||||||
std::cout << "In archive: " << info.filename << std::endl;
|
std::cout << "In archive: " << info.filename << std::endl;
|
||||||
|
@ -260,9 +270,6 @@ int extract(std::unique_ptr<Bsa::BSAFile>& bsa, Arguments& info)
|
||||||
return 3;
|
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);
|
bfs::ofstream out(target, std::ios::binary);
|
||||||
|
|
||||||
// Write the file to disk
|
// 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
|
// Get a stream for the file to extract
|
||||||
// (inefficient because getFile iter on the list again)
|
Files::IStreamPtr data = bsa->getFile(&file);
|
||||||
Files::IStreamPtr data = bsa->getFile(file.name());
|
|
||||||
bfs::ofstream out(target, std::ios::binary);
|
bfs::ofstream out(target, std::ios::binary);
|
||||||
|
|
||||||
// Write the file to disk
|
// Write the file to disk
|
||||||
|
|
|
@ -367,10 +367,10 @@ int load(Arguments& info)
|
||||||
EsmTool::RecordBase *record = EsmTool::RecordBase::create(n);
|
EsmTool::RecordBase *record = EsmTool::RecordBase::create(n);
|
||||||
if (record == nullptr)
|
if (record == nullptr)
|
||||||
{
|
{
|
||||||
if (skipped.count(n.intval) == 0)
|
if (skipped.count(n.toInt()) == 0)
|
||||||
{
|
{
|
||||||
std::cout << "Skipping " << n.toString() << " records.\n";
|
std::cout << "Skipping " << n.toString() << " records.\n";
|
||||||
skipped.emplace(n.intval);
|
skipped.emplace(n.toInt());
|
||||||
}
|
}
|
||||||
|
|
||||||
esm.skipRecord();
|
esm.skipRecord();
|
||||||
|
@ -402,7 +402,7 @@ int load(Arguments& info)
|
||||||
record->print();
|
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);
|
loadCell(record->cast<ESM::Cell>()->get(), esm, info);
|
||||||
}
|
}
|
||||||
|
@ -415,7 +415,7 @@ int load(Arguments& info)
|
||||||
{
|
{
|
||||||
delete record;
|
delete record;
|
||||||
}
|
}
|
||||||
++info.data.mRecordStats[n.intval];
|
++info.data.mRecordStats[n.toInt()];
|
||||||
}
|
}
|
||||||
|
|
||||||
} catch(std::exception &e) {
|
} catch(std::exception &e) {
|
||||||
|
@ -459,7 +459,7 @@ int clone(Arguments& info)
|
||||||
for (std::pair<int, int> stat : info.data.mRecordStats)
|
for (std::pair<int, int> stat : info.data.mRecordStats)
|
||||||
{
|
{
|
||||||
ESM::NAME name;
|
ESM::NAME name;
|
||||||
name.intval = stat.first;
|
name = stat.first;
|
||||||
int amount = stat.second;
|
int amount = stat.second;
|
||||||
std::cout << std::setw(digitCount) << amount << " " << name.toString() << " ";
|
std::cout << std::setw(digitCount) << amount << " " << name.toString() << " ";
|
||||||
if (++i % 3 == 0)
|
if (++i % 3 == 0)
|
||||||
|
@ -496,7 +496,7 @@ int clone(Arguments& info)
|
||||||
esm.startRecord(typeName.toString(), record->getFlags());
|
esm.startRecord(typeName.toString(), record->getFlags());
|
||||||
|
|
||||||
record->save(esm);
|
record->save(esm);
|
||||||
if (typeName.intval == ESM::REC_CELL) {
|
if (typeName.toInt() == ESM::REC_CELL) {
|
||||||
ESM::Cell *ptr = &record->cast<ESM::Cell>()->get();
|
ESM::Cell *ptr = &record->cast<ESM::Cell>()->get();
|
||||||
if (!info.data.mCellRefs[ptr].empty())
|
if (!info.data.mCellRefs[ptr].empty())
|
||||||
{
|
{
|
||||||
|
|
|
@ -30,7 +30,7 @@ void printAIPackage(const ESM::AIPackage& p)
|
||||||
{
|
{
|
||||||
std::cout << " Travel Coordinates: (" << p.mTravel.mX << ","
|
std::cout << " Travel Coordinates: (" << p.mTravel.mX << ","
|
||||||
<< p.mTravel.mY << "," << p.mTravel.mZ << ")" << std::endl;
|
<< 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)
|
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;
|
<< p.mTarget.mY << "," << p.mTarget.mZ << ")" << std::endl;
|
||||||
std::cout << " Duration: " << p.mTarget.mDuration << std::endl;
|
std::cout << " Duration: " << p.mTarget.mDuration << std::endl;
|
||||||
std::cout << " Target ID: " << p.mTarget.mId.toString() << 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)
|
else if (p.mType == ESM::AI_Activate)
|
||||||
{
|
{
|
||||||
std::cout << " Name: " << p.mActivate.mName.toString() << std::endl;
|
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 {
|
else {
|
||||||
std::cout << " BadPackage: " << Misc::StringUtils::format("0x%08X", p.mType) << std::endl;
|
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;
|
RecordBase *record = nullptr;
|
||||||
|
|
||||||
switch (type.intval) {
|
switch (type.toInt()) {
|
||||||
case ESM::REC_ACTI:
|
case ESM::REC_ACTI:
|
||||||
{
|
{
|
||||||
record = new EsmTool::Record<ESM::Activator>;
|
record = new EsmTool::Record<ESM::Activator>;
|
||||||
|
|
|
@ -324,14 +324,14 @@ namespace ESSImport
|
||||||
ESM::NAME n = esm.getRecName();
|
ESM::NAME n = esm.getRecName();
|
||||||
esm.getRecHeader();
|
esm.getRecHeader();
|
||||||
|
|
||||||
auto it = converters.find(n.intval);
|
auto it = converters.find(n.toInt());
|
||||||
if (it != converters.end())
|
if (it != converters.end())
|
||||||
{
|
{
|
||||||
it->second->read(esm);
|
it->second->read(esm);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
if (unknownRecords.insert(n.intval).second)
|
if (unknownRecords.insert(n.toInt()).second)
|
||||||
{
|
{
|
||||||
std::ios::fmtflags f(std::cerr.flags());
|
std::ios::fmtflags f(std::cerr.flags());
|
||||||
std::cerr << "Error: unknown record " << n.toString() << " (0x" << std::hex << esm.getFileOffset() << ")" << std::endl;
|
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(autoUseTerrainSpecularMapsCheckBox, "auto use terrain specular maps", "Shaders");
|
||||||
loadSettingBool(bumpMapLocalLightingCheckBox, "apply lighting to environment maps", "Shaders");
|
loadSettingBool(bumpMapLocalLightingCheckBox, "apply lighting to environment maps", "Shaders");
|
||||||
loadSettingBool(radialFogCheckBox, "radial fog", "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");
|
loadSettingBool(magicItemAnimationsCheckBox, "use magic item animations", "Game");
|
||||||
connect(animSourcesCheckBox, SIGNAL(toggled(bool)), this, SLOT(slotAnimSourcesToggled(bool)));
|
connect(animSourcesCheckBox, SIGNAL(toggled(bool)), this, SLOT(slotAnimSourcesToggled(bool)));
|
||||||
loadSettingBool(animSourcesCheckBox, "use additional anim sources", "Game");
|
loadSettingBool(animSourcesCheckBox, "use additional anim sources", "Game");
|
||||||
|
@ -207,7 +212,7 @@ bool Launcher::AdvancedPage::loadSettings()
|
||||||
{
|
{
|
||||||
// Saves
|
// Saves
|
||||||
loadSettingBool(timePlayedCheckbox, "timeplayed", "Saves");
|
loadSettingBool(timePlayedCheckbox, "timeplayed", "Saves");
|
||||||
maximumQuicksavesComboBox->setValue(Settings::Manager::getInt("max quicksaves", "Saves"));
|
loadSettingInt(maximumQuicksavesComboBox,"max quicksaves", "Saves");
|
||||||
|
|
||||||
// Other Settings
|
// Other Settings
|
||||||
QString screenshotFormatString = QString::fromStdString(Settings::Manager::getString("screenshot format", "General")).toUpper();
|
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(normaliseRaceSpeedCheckBox, "normalise race speed", "Game");
|
||||||
saveSettingBool(swimUpwardCorrectionCheckBox, "swim upward correction", "Game");
|
saveSettingBool(swimUpwardCorrectionCheckBox, "swim upward correction", "Game");
|
||||||
saveSettingBool(avoidCollisionsCheckBox, "NPCs avoid collisions", "Game");
|
saveSettingBool(avoidCollisionsCheckBox, "NPCs avoid collisions", "Game");
|
||||||
int unarmedFactorsStrengthIndex = unarmedFactorsStrengthComboBox->currentIndex();
|
saveSettingInt(unarmedFactorsStrengthComboBox, "strength influences hand to hand", "Game");
|
||||||
if (unarmedFactorsStrengthIndex != Settings::Manager::getInt("strength influences hand to hand", "Game"))
|
|
||||||
Settings::Manager::setInt("strength influences hand to hand", "Game", unarmedFactorsStrengthIndex);
|
|
||||||
saveSettingBool(stealingFromKnockedOutCheckBox, "always allow stealing from knocked out actors", "Game");
|
saveSettingBool(stealingFromKnockedOutCheckBox, "always allow stealing from knocked out actors", "Game");
|
||||||
saveSettingBool(enableNavigatorCheckBox, "enable", "Navigator");
|
saveSettingBool(enableNavigatorCheckBox, "enable", "Navigator");
|
||||||
int numPhysicsThreads = physicsThreadsSpinBox->value();
|
saveSettingInt(physicsThreadsSpinBox, "async num threads", "Physics");
|
||||||
if (numPhysicsThreads != Settings::Manager::getInt("async num threads", "Physics"))
|
|
||||||
Settings::Manager::setInt("async num threads", "Physics", numPhysicsThreads);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Visuals
|
// Visuals
|
||||||
|
@ -270,6 +271,8 @@ void Launcher::AdvancedPage::saveSettings()
|
||||||
saveSettingBool(autoUseTerrainSpecularMapsCheckBox, "auto use terrain specular maps", "Shaders");
|
saveSettingBool(autoUseTerrainSpecularMapsCheckBox, "auto use terrain specular maps", "Shaders");
|
||||||
saveSettingBool(bumpMapLocalLightingCheckBox, "apply lighting to environment maps", "Shaders");
|
saveSettingBool(bumpMapLocalLightingCheckBox, "apply lighting to environment maps", "Shaders");
|
||||||
saveSettingBool(radialFogCheckBox, "radial fog", "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(magicItemAnimationsCheckBox, "use magic item animations", "Game");
|
||||||
saveSettingBool(animSourcesCheckBox, "use additional anim sources", "Game");
|
saveSettingBool(animSourcesCheckBox, "use additional anim sources", "Game");
|
||||||
saveSettingBool(weaponSheathingCheckBox, "weapon sheathing", "Game");
|
saveSettingBool(weaponSheathingCheckBox, "weapon sheathing", "Game");
|
||||||
|
@ -349,9 +352,7 @@ void Launcher::AdvancedPage::saveSettings()
|
||||||
saveSettingBool(showMeleeInfoCheckBox, "show melee info", "Game");
|
saveSettingBool(showMeleeInfoCheckBox, "show melee info", "Game");
|
||||||
saveSettingBool(showProjectileDamageCheckBox, "show projectile damage", "Game");
|
saveSettingBool(showProjectileDamageCheckBox, "show projectile damage", "Game");
|
||||||
saveSettingBool(changeDialogTopicsCheckBox, "color topic enable", "GUI");
|
saveSettingBool(changeDialogTopicsCheckBox, "color topic enable", "GUI");
|
||||||
int showOwnedCurrentIndex = showOwnedComboBox->currentIndex();
|
saveSettingInt(showOwnedComboBox,"show owned", "Game");
|
||||||
if (showOwnedCurrentIndex != Settings::Manager::getInt("show owned", "Game"))
|
|
||||||
Settings::Manager::setInt("show owned", "Game", showOwnedCurrentIndex);
|
|
||||||
saveSettingBool(stretchBackgroundCheckBox, "stretch menu background", "GUI");
|
saveSettingBool(stretchBackgroundCheckBox, "stretch menu background", "GUI");
|
||||||
saveSettingBool(useZoomOnMapCheckBox, "allow zooming", "Map");
|
saveSettingBool(useZoomOnMapCheckBox, "allow zooming", "Map");
|
||||||
saveSettingBool(graphicHerbalismCheckBox, "graphic herbalism", "Game");
|
saveSettingBool(graphicHerbalismCheckBox, "graphic herbalism", "Game");
|
||||||
|
@ -370,11 +371,7 @@ void Launcher::AdvancedPage::saveSettings()
|
||||||
{
|
{
|
||||||
// Saves Settings
|
// Saves Settings
|
||||||
saveSettingBool(timePlayedCheckbox, "timeplayed", "Saves");
|
saveSettingBool(timePlayedCheckbox, "timeplayed", "Saves");
|
||||||
int maximumQuicksaves = maximumQuicksavesComboBox->value();
|
saveSettingInt(maximumQuicksavesComboBox, "max quicksaves", "Saves");
|
||||||
if (maximumQuicksaves != Settings::Manager::getInt("max quicksaves", "Saves"))
|
|
||||||
{
|
|
||||||
Settings::Manager::setInt("max quicksaves", "Saves", maximumQuicksaves);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Other Settings
|
// Other Settings
|
||||||
std::string screenshotFormatString = screenshotFormatComboBox->currentText().toLower().toStdString();
|
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);
|
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)
|
void Launcher::AdvancedPage::slotLoadedCellsChanged(QStringList cellNames)
|
||||||
{
|
{
|
||||||
loadCellsForAutocomplete(cellNames);
|
loadCellsForAutocomplete(cellNames);
|
||||||
|
|
|
@ -41,8 +41,12 @@ namespace Launcher
|
||||||
* @param filePaths the file paths of the content files to be examined
|
* @param filePaths the file paths of the content files to be examined
|
||||||
*/
|
*/
|
||||||
void loadCellsForAutocomplete(QStringList filePaths);
|
void loadCellsForAutocomplete(QStringList filePaths);
|
||||||
void loadSettingBool(QCheckBox *checkbox, const std::string& setting, const std::string& group);
|
static 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 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
|
#endif
|
||||||
|
|
|
@ -32,7 +32,7 @@ Launcher::DataFilesPage::DataFilesPage(Files::ConfigurationManager &cfg, Config:
|
||||||
{
|
{
|
||||||
ui.setupUi (this);
|
ui.setupUi (this);
|
||||||
setObjectName ("DataFilesPage");
|
setObjectName ("DataFilesPage");
|
||||||
mSelector = new ContentSelectorView::ContentSelector (ui.contentSelectorWidget);
|
mSelector = new ContentSelectorView::ContentSelector (ui.contentSelectorWidget, /*showOMWScripts=*/true);
|
||||||
const QString encoding = mGameSettings.value("encoding", "win1252");
|
const QString encoding = mGameSettings.value("encoding", "win1252");
|
||||||
mSelector->setEncoding(encoding);
|
mSelector->setEncoding(encoding);
|
||||||
|
|
||||||
|
@ -121,6 +121,7 @@ void Launcher::DataFilesPage::populateFileViews(const QString& contentModelName)
|
||||||
|
|
||||||
for (const QString &path : paths)
|
for (const QString &path : paths)
|
||||||
mSelector->addFiles(path);
|
mSelector->addFiles(path);
|
||||||
|
mSelector->sortFiles();
|
||||||
|
|
||||||
PathIterator pathIterator(paths);
|
PathIterator pathIterator(paths);
|
||||||
|
|
||||||
|
|
|
@ -47,7 +47,6 @@ Launcher::GraphicsPage::GraphicsPage(QWidget *parent)
|
||||||
connect(screenComboBox, SIGNAL(currentIndexChanged(int)), this, SLOT(screenChanged(int)));
|
connect(screenComboBox, SIGNAL(currentIndexChanged(int)), this, SLOT(screenChanged(int)));
|
||||||
connect(framerateLimitCheckBox, SIGNAL(toggled(bool)), this, SLOT(slotFramerateLimitToggled(bool)));
|
connect(framerateLimitCheckBox, SIGNAL(toggled(bool)), this, SLOT(slotFramerateLimitToggled(bool)));
|
||||||
connect(shadowDistanceCheckBox, SIGNAL(toggled(bool)), this, SLOT(slotShadowDistLimitToggled(bool)));
|
connect(shadowDistanceCheckBox, SIGNAL(toggled(bool)), this, SLOT(slotShadowDistLimitToggled(bool)));
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Launcher::GraphicsPage::setupSDL()
|
bool Launcher::GraphicsPage::setupSDL()
|
||||||
|
|
|
@ -146,7 +146,6 @@ void Launcher::MainDialog::createPages()
|
||||||
connect(mDataFilesPage, SIGNAL(signalProfileChanged(int)), mPlayPage, SLOT(setProfilesIndex(int)));
|
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
|
// 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);
|
connect(mDataFilesPage, SIGNAL(signalLoadedCellsChanged(QStringList)), mAdvancedPage, SLOT(slotLoadedCellsChanged(QStringList)), Qt::QueuedConnection);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Launcher::FirstRunDialogResult Launcher::MainDialog::showFirstRunDialog()
|
Launcher::FirstRunDialogResult Launcher::MainDialog::showFirstRunDialog()
|
||||||
|
|
|
@ -10,6 +10,8 @@ QSet<QString> CellNameLoader::getCellNames(QStringList &contentPaths)
|
||||||
|
|
||||||
// Loop through all content files
|
// Loop through all content files
|
||||||
for (auto &contentPath : contentPaths) {
|
for (auto &contentPath : contentPaths) {
|
||||||
|
if (contentPath.endsWith(".omwscripts", Qt::CaseInsensitive))
|
||||||
|
continue;
|
||||||
esmReader.open(contentPath.toStdString());
|
esmReader.open(contentPath.toStdString());
|
||||||
|
|
||||||
// Loop through all records
|
// Loop through all records
|
||||||
|
@ -35,7 +37,7 @@ QSet<QString> CellNameLoader::getCellNames(QStringList &contentPaths)
|
||||||
|
|
||||||
bool CellNameLoader::isCellRecord(ESM::NAME &recordName)
|
bool CellNameLoader::isCellRecord(ESM::NAME &recordName)
|
||||||
{
|
{
|
||||||
return recordName.intval == ESM::REC_CELL;
|
return recordName.toInt() == ESM::REC_CELL;
|
||||||
}
|
}
|
||||||
|
|
||||||
QString CellNameLoader::getCellName(ESM::ESMReader &esmReader)
|
QString CellNameLoader::getCellName(ESM::ESMReader &esmReader)
|
||||||
|
|
|
@ -2,8 +2,8 @@
|
||||||
|
|
||||||
#include <iostream>
|
#include <iostream>
|
||||||
#include <fstream>
|
#include <fstream>
|
||||||
#include <cstdlib>
|
|
||||||
|
|
||||||
|
#include <components/misc/stringops.hpp>
|
||||||
#include <components/nif/niffile.hpp>
|
#include <components/nif/niffile.hpp>
|
||||||
#include <components/files/constrainedfilestream.hpp>
|
#include <components/files/constrainedfilestream.hpp>
|
||||||
#include <components/vfs/manager.hpp>
|
#include <components/vfs/manager.hpp>
|
||||||
|
@ -21,15 +21,7 @@ namespace bfs = boost::filesystem;
|
||||||
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);
|
std::string extension = filename.substr(filename.find_last_of('.')+1);
|
||||||
|
return Misc::StringUtils::ciEqual(extension, extensionToFind);
|
||||||
//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;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
///See if the file has the "nif" extension.
|
///See if the file has the "nif" extension.
|
||||||
|
|
|
@ -183,8 +183,7 @@ if(APPLE)
|
||||||
set(OPENCS_BUNDLE_NAME "OpenMW-CS")
|
set(OPENCS_BUNDLE_NAME "OpenMW-CS")
|
||||||
set(OPENCS_BUNDLE_RESOURCES_DIR "${OpenMW_BINARY_DIR}/${OPENCS_BUNDLE_NAME}.app/Contents/Resources")
|
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_RESOURCES_ROOT ${OPENCS_BUNDLE_RESOURCES_DIR})
|
||||||
set(OPENMW_SHADERS_ROOT ${OPENCS_BUNDLE_RESOURCES_DIR})
|
|
||||||
|
|
||||||
add_subdirectory(../../files/ ${CMAKE_CURRENT_BINARY_DIR}/files)
|
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());
|
dataDirs.insert (dataDirs.end(), dataLocal.begin(), dataLocal.end());
|
||||||
|
|
||||||
//iterate the data directories and add them to the file dialog for loading
|
//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)
|
mFileDialog.addFiles(dataDirs);
|
||||||
{
|
|
||||||
QString path = QString::fromUtf8 (iter->string().c_str());
|
|
||||||
mFileDialog.addFiles(path);
|
|
||||||
}
|
|
||||||
|
|
||||||
return std::make_pair (dataDirs, variables["fallback-archive"].as<std::vector<std::string>>());
|
return std::make_pair (dataDirs, variables["fallback-archive"].as<std::vector<std::string>>());
|
||||||
}
|
}
|
||||||
|
|
|
@ -17,6 +17,19 @@
|
||||||
#include "textnode.hpp"
|
#include "textnode.hpp"
|
||||||
#include "valuenode.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
|
namespace CSMFilter
|
||||||
{
|
{
|
||||||
struct Token
|
struct Token
|
||||||
|
@ -103,7 +116,7 @@ CSMFilter::Token CSMFilter::Parser::getStringToken()
|
||||||
{
|
{
|
||||||
char c = mInput[mIndex];
|
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.empty() && string[0]=='"'))
|
||||||
string += c;
|
string += c;
|
||||||
else
|
else
|
||||||
|
@ -150,7 +163,7 @@ CSMFilter::Token CSMFilter::Parser::getNumberToken()
|
||||||
{
|
{
|
||||||
char c = mInput[mIndex];
|
char c = mInput[mIndex];
|
||||||
|
|
||||||
if (std::isdigit (c))
|
if (isDigit(c))
|
||||||
{
|
{
|
||||||
string += c;
|
string += c;
|
||||||
hasDigit = true;
|
hasDigit = true;
|
||||||
|
@ -225,10 +238,10 @@ CSMFilter::Token CSMFilter::Parser::getNextToken()
|
||||||
case '!': ++mIndex; return Token (Token::Type_OneShot);
|
case '!': ++mIndex; return Token (Token::Type_OneShot);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (c=='"' || c=='_' || std::isalpha (c) || c==':')
|
if (c=='"' || c=='_' || isAlpha(c) || c==':')
|
||||||
return getStringToken();
|
return getStringToken();
|
||||||
|
|
||||||
if (c=='-' || c=='.' || std::isdigit (c))
|
if (c=='-' || c=='.' || isDigit(c))
|
||||||
return getNumberToken();
|
return getNumberToken();
|
||||||
|
|
||||||
error();
|
error();
|
||||||
|
|
|
@ -395,12 +395,12 @@ bool CSMTools::TopicInfoCheckStage::verifyId(const std::string& name, const CSMW
|
||||||
|
|
||||||
if (index == -1)
|
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;
|
return false;
|
||||||
}
|
}
|
||||||
else if (collection.getRecord(index).isDeleted())
|
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;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -296,7 +296,7 @@ namespace CSMWorld
|
||||||
const std::string& destination, const UniversalId::Type type)
|
const std::string& destination, const UniversalId::Type type)
|
||||||
{
|
{
|
||||||
int index = cloneRecordImp(origin, destination, type);
|
int index = cloneRecordImp(origin, destination, type);
|
||||||
mRecords.at(index)->get().mPlugin = 0;
|
mRecords.at(index)->get().setPlugin(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename ESXRecordT, typename IdAccessorT>
|
template<typename ESXRecordT, typename IdAccessorT>
|
||||||
|
@ -311,7 +311,7 @@ namespace CSMWorld
|
||||||
int index = touchRecordImp(id);
|
int index = touchRecordImp(id);
|
||||||
if (index >= 0)
|
if (index >= 0)
|
||||||
{
|
{
|
||||||
mRecords.at(index)->get().mPlugin = 0;
|
mRecords.at(index)->get().setPlugin(0);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -52,7 +52,7 @@ namespace CSMWorld
|
||||||
|
|
||||||
QVariant LandPluginIndexColumn::get(const Record<Land>& record) const
|
QVariant LandPluginIndexColumn::get(const Record<Land>& record) const
|
||||||
{
|
{
|
||||||
return record.get().mPlugin;
|
return record.get().getPlugin();
|
||||||
}
|
}
|
||||||
|
|
||||||
bool LandPluginIndexColumn::isEditable() const
|
bool LandPluginIndexColumn::isEditable() const
|
||||||
|
|
|
@ -255,7 +255,7 @@ namespace CSMWorld
|
||||||
{ ColumnId_AiWanderDist, "Wander Dist" },
|
{ ColumnId_AiWanderDist, "Wander Dist" },
|
||||||
{ ColumnId_AiDuration, "Ai Duration" },
|
{ ColumnId_AiDuration, "Ai Duration" },
|
||||||
{ ColumnId_AiWanderToD, "Wander ToD" },
|
{ ColumnId_AiWanderToD, "Wander ToD" },
|
||||||
{ ColumnId_AiWanderRepeat, "Wander Repeat" },
|
{ ColumnId_AiWanderRepeat, "Ai Repeat" },
|
||||||
{ ColumnId_AiActivateName, "Activate" },
|
{ ColumnId_AiActivateName, "Activate" },
|
||||||
{ ColumnId_AiTargetId, "Target ID" },
|
{ ColumnId_AiTargetId, "Target ID" },
|
||||||
{ ColumnId_AiTargetCell, "Target Cell" },
|
{ ColumnId_AiTargetCell, "Target Cell" },
|
||||||
|
|
|
@ -1086,7 +1086,7 @@ bool CSMWorld::Data::continueLoading (CSMDoc::Messages& messages)
|
||||||
|
|
||||||
bool unhandledRecord = false;
|
bool unhandledRecord = false;
|
||||||
|
|
||||||
switch (n.intval)
|
switch (n.toInt())
|
||||||
{
|
{
|
||||||
case ESM::REC_GLOB: mGlobals.load (*mReader, mBase); break;
|
case ESM::REC_GLOB: mGlobals.load (*mReader, mBase); break;
|
||||||
case ESM::REC_GMST: mGmsts.load (*mReader, mBase); break;
|
case ESM::REC_GMST: mGmsts.load (*mReader, mBase); break;
|
||||||
|
|
|
@ -8,6 +8,7 @@
|
||||||
#include <stdexcept>
|
#include <stdexcept>
|
||||||
|
|
||||||
#include <components/esm/cellid.hpp>
|
#include <components/esm/cellid.hpp>
|
||||||
|
#include <components/misc/stringops.hpp>
|
||||||
|
|
||||||
#include "collectionbase.hpp"
|
#include "collectionbase.hpp"
|
||||||
#include "columnbase.hpp"
|
#include "columnbase.hpp"
|
||||||
|
@ -354,8 +355,7 @@ CSMWorld::LandTextureIdTable::ImportResults CSMWorld::LandTextureIdTable::import
|
||||||
for (int i = 0; i < idCollection()->getSize(); ++i)
|
for (int i = 0; i < idCollection()->getSize(); ++i)
|
||||||
{
|
{
|
||||||
auto& record = static_cast<const Record<LandTexture>&>(idCollection()->getRecord(i));
|
auto& record = static_cast<const Record<LandTexture>&>(idCollection()->getRecord(i));
|
||||||
std::string texture = record.get().mTexture;
|
std::string texture = Misc::StringUtils::lowerCase(record.get().mTexture);
|
||||||
std::transform(texture.begin(), texture.end(), texture.begin(), tolower);
|
|
||||||
if (record.isModified())
|
if (record.isModified())
|
||||||
reverseLookupMap.emplace(texture, idCollection()->getId(i));
|
reverseLookupMap.emplace(texture, idCollection()->getId(i));
|
||||||
}
|
}
|
||||||
|
@ -376,8 +376,7 @@ CSMWorld::LandTextureIdTable::ImportResults CSMWorld::LandTextureIdTable::import
|
||||||
|
|
||||||
// Look for a pre-existing record
|
// Look for a pre-existing record
|
||||||
auto& record = static_cast<const Record<LandTexture>&>(idCollection()->getRecord(oldRow));
|
auto& record = static_cast<const Record<LandTexture>&>(idCollection()->getRecord(oldRow));
|
||||||
std::string texture = record.get().mTexture;
|
std::string texture = Misc::StringUtils::lowerCase(record.get().mTexture);
|
||||||
std::transform(texture.begin(), texture.end(), texture.begin(), tolower);
|
|
||||||
auto searchIt = reverseLookupMap.find(texture);
|
auto searchIt = reverseLookupMap.find(texture);
|
||||||
if (searchIt != reverseLookupMap.end())
|
if (searchIt != reverseLookupMap.end())
|
||||||
{
|
{
|
||||||
|
|
|
@ -1678,7 +1678,7 @@ namespace CSMWorld
|
||||||
newRow.mWander.mTimeOfDay = 0;
|
newRow.mWander.mTimeOfDay = 0;
|
||||||
for (int i = 0; i < 8; ++i)
|
for (int i = 0; i < 8; ++i)
|
||||||
newRow.mWander.mIdle[i] = 0;
|
newRow.mWander.mIdle[i] = 0;
|
||||||
newRow.mWander.mShouldRepeat = 0;
|
newRow.mWander.mShouldRepeat = 1;
|
||||||
newRow.mCellName = "";
|
newRow.mCellName = "";
|
||||||
|
|
||||||
if (position >= (int)list.size())
|
if (position >= (int)list.size())
|
||||||
|
@ -1784,9 +1784,15 @@ namespace CSMWorld
|
||||||
return static_cast<int>(content.mWander.mIdle[subColIndex-4]);
|
return static_cast<int>(content.mWander.mIdle[subColIndex-4]);
|
||||||
else
|
else
|
||||||
return QVariant();
|
return QVariant();
|
||||||
case 12: // wander repeat
|
case 12: // repeat
|
||||||
if (content.mType == ESM::AI_Wander)
|
if (content.mType == ESM::AI_Wander)
|
||||||
return content.mWander.mShouldRepeat != 0;
|
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
|
else
|
||||||
return QVariant();
|
return QVariant();
|
||||||
case 13: // activate name
|
case 13: // activate name
|
||||||
|
@ -1895,6 +1901,12 @@ namespace CSMWorld
|
||||||
case 12:
|
case 12:
|
||||||
if (content.mType == ESM::AI_Wander)
|
if (content.mType == ESM::AI_Wander)
|
||||||
content.mWander.mShouldRepeat = static_cast<unsigned char>(value.toInt());
|
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
|
else
|
||||||
return; // return without saving
|
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));
|
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()
|
void CSMWorld::ScriptContext::invalidateIds()
|
||||||
{
|
{
|
||||||
mIdsUpdated = false;
|
mIdsUpdated = false;
|
||||||
|
|
|
@ -39,9 +39,6 @@ namespace CSMWorld
|
||||||
bool isId (const std::string& name) const override;
|
bool isId (const std::string& name) const override;
|
||||||
///< Does \a name match an ID, that can be referenced?
|
///< 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 invalidateIds();
|
||||||
|
|
||||||
void clear();
|
void clear();
|
||||||
|
|
|
@ -24,13 +24,18 @@ CSVDoc::FileDialog::FileDialog(QWidget *parent) :
|
||||||
resize(400, 400);
|
resize(400, 400);
|
||||||
|
|
||||||
setObjectName ("FileDialog");
|
setObjectName ("FileDialog");
|
||||||
mSelector = new ContentSelectorView::ContentSelector (ui.contentSelectorWidget);
|
mSelector = new ContentSelectorView::ContentSelector (ui.contentSelectorWidget, /*showOMWScripts=*/false);
|
||||||
mAdjusterWidget = new AdjusterWidget (this);
|
mAdjusterWidget = new AdjusterWidget (this);
|
||||||
}
|
}
|
||||||
|
|
||||||
void CSVDoc::FileDialog::addFiles(const QString &path)
|
void CSVDoc::FileDialog::addFiles(const std::vector<boost::filesystem::path>& dataDirs)
|
||||||
{
|
{
|
||||||
|
for (auto iter = dataDirs.rbegin(); iter != dataDirs.rend(); ++iter)
|
||||||
|
{
|
||||||
|
QString path = QString::fromUtf8(iter->string().c_str());
|
||||||
mSelector->addFiles(path);
|
mSelector->addFiles(path);
|
||||||
|
}
|
||||||
|
mSelector->sortFiles();
|
||||||
}
|
}
|
||||||
|
|
||||||
void CSVDoc::FileDialog::setEncoding(const QString &encoding)
|
void CSVDoc::FileDialog::setEncoding(const QString &encoding)
|
||||||
|
|
|
@ -45,7 +45,7 @@ namespace CSVDoc
|
||||||
explicit FileDialog(QWidget *parent = nullptr);
|
explicit FileDialog(QWidget *parent = nullptr);
|
||||||
void showDialog (ContentAction action);
|
void showDialog (ContentAction action);
|
||||||
|
|
||||||
void addFiles (const QString &path);
|
void addFiles(const std::vector<boost::filesystem::path>& dataDirs);
|
||||||
void setEncoding (const QString &encoding);
|
void setEncoding (const QString &encoding);
|
||||||
void clearFiles ();
|
void clearFiles ();
|
||||||
|
|
||||||
|
|
|
@ -111,7 +111,7 @@ namespace CSVRender
|
||||||
if (!mesh.empty() && node != mNodeMap.end())
|
if (!mesh.empty() && node != mNodeMap.end())
|
||||||
{
|
{
|
||||||
auto instance = sceneMgr->getInstance(mesh);
|
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 OuterRadius = InnerRadius + MarkerShaftWidth;
|
||||||
|
|
||||||
const float SegmentDistance = 100.f;
|
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 VerticesPerSegment = 4;
|
||||||
const size_t IndicesPerSegment = 24;
|
const size_t IndicesPerSegment = 24;
|
||||||
|
|
||||||
|
|
|
@ -16,11 +16,13 @@
|
||||||
#include "worldspacewidget.hpp"
|
#include "worldspacewidget.hpp"
|
||||||
|
|
||||||
CSVRender::TerrainSelection::TerrainSelection(osg::Group* parentNode, WorldspaceWidget *worldspaceWidget, TerrainSelectionType type):
|
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();
|
mGeometry = new osg::Geometry();
|
||||||
|
|
||||||
mSelectionNode = new osg::Group();
|
mSelectionNode = new osg::Group();
|
||||||
|
mSelectionNode->getOrCreateStateSet()->setMode(GL_DEPTH_TEST, osg::StateAttribute::OFF);
|
||||||
|
mSelectionNode->getOrCreateStateSet()->setRenderBinDetails(11, "RenderBin");
|
||||||
mSelectionNode->addChild(mGeometry);
|
mSelectionNode->addChild(mGeometry);
|
||||||
|
|
||||||
activate();
|
activate();
|
||||||
|
@ -43,19 +45,24 @@ void CSVRender::TerrainSelection::onlySelect(const std::vector<std::pair<int, in
|
||||||
update();
|
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()
|
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 xWorldCoord(CSMWorld::CellCoordinates::vertexGlobalToWorldCoords(x));
|
||||||
float yWorldCoord(CSMWorld::CellCoordinates::vertexGlobalToWorldCoords(y));
|
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(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(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)));
|
||||||
|
|
||||||
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(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)));
|
||||||
}
|
|
||||||
|
|
||||||
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(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)));
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -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 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));
|
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(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)+2));
|
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 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));
|
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(drawPreviousX, CSMWorld::CellCoordinates::textureGlobalYToWorldCoords(y), calculateLandHeight(x1+(i-1), y1)));
|
||||||
vertices->push_back(osg::Vec3f(drawCurrentX, CSMWorld::CellCoordinates::textureGlobalYToWorldCoords(y), calculateLandHeight(x1+i, y1)+2));
|
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 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));
|
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), drawPreviousY, calculateLandHeight(x2, y1+(i-1))));
|
||||||
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), drawCurrentY, calculateLandHeight(x2, y1+i)));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -190,84 +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 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));
|
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), drawPreviousY, calculateLandHeight(x1, y1+(i-1))));
|
||||||
vertices->push_back(osg::Vec3f(CSMWorld::CellCoordinates::textureGlobalXToWorldCoords(x), drawCurrentY, calculateLandHeight(x1, y1+i)+2));
|
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)
|
|
||||||
{
|
|
||||||
auto iterTemp = std::find(mTemporarySelection.begin(), mTemporarySelection.end(), localPos);
|
|
||||||
mDraggedOperationFlag = true;
|
|
||||||
|
|
||||||
if (iterTemp == mTemporarySelection.end())
|
|
||||||
{
|
|
||||||
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;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
mTemporarySelection.push_back(localPos);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else if (mDraggedOperationFlag == false)
|
|
||||||
{
|
|
||||||
for (auto const& localPos : localPositions)
|
for (auto const& localPos : localPositions)
|
||||||
{
|
{
|
||||||
const auto iter = std::find(mSelection.begin(), mSelection.end(), localPos);
|
const auto iter = std::find(mSelection.begin(), mSelection.end(), localPos);
|
||||||
|
|
||||||
switch (selectionMethod)
|
switch (selectionMethod)
|
||||||
{
|
{
|
||||||
|
case SelectionMethod::OnlySelect:
|
||||||
|
break;
|
||||||
|
|
||||||
case SelectionMethod::AddSelect:
|
case SelectionMethod::AddSelect:
|
||||||
if (iter == mSelection.end())
|
if (iter == mSelection.end())
|
||||||
{
|
{
|
||||||
mSelection.emplace_back(localPos);
|
mSelection.emplace_back(localPos);
|
||||||
}
|
}
|
||||||
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case SelectionMethod::RemoveSelect:
|
case SelectionMethod::RemoveSelect:
|
||||||
if (iter != mSelection.end())
|
if (iter != mSelection.end())
|
||||||
{
|
{
|
||||||
mSelection.erase(iter);
|
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())
|
if (iter == mSelection.end())
|
||||||
{
|
{
|
||||||
mSelection.emplace_back(localPos);
|
mSelection.emplace_back(localPos);
|
||||||
|
@ -276,17 +233,14 @@ void CSVRender::TerrainSelection::handleSelection(const std::vector<std::pair<in
|
||||||
{
|
{
|
||||||
mSelection.erase(iter);
|
mSelection.erase(iter);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
mTemporarySelection.emplace_back(localPos);
|
||||||
break;
|
break;
|
||||||
default: break;
|
|
||||||
}
|
}
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
mDraggedOperationFlag = false;
|
|
||||||
|
|
||||||
mTemporarySelection.clear();
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
update();
|
update();
|
||||||
|
@ -336,11 +290,9 @@ int CSVRender::TerrainSelection::calculateLandHeight(int x, int y) // global ver
|
||||||
else if (isLandLoaded(CSMWorld::CellCoordinates::generateId(cellX, cellY)))
|
else if (isLandLoaded(CSMWorld::CellCoordinates::generateId(cellX, cellY)))
|
||||||
{
|
{
|
||||||
CSMDoc::Document& document = mWorldspaceWidget->getDocument();
|
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);
|
std::string cellId = CSMWorld::CellCoordinates::generateId(cellX, cellY);
|
||||||
int landshapeColumn = landTable.findColumnIndex(CSMWorld::Columns::ColumnId_LandHeightsIndex);
|
const ESM::Land::LandData* landData = document.getData().getLand().getRecord(cellId).get().getLandData(ESM::Land::DATA_VHGT);
|
||||||
const CSMWorld::LandHeightsColumn::DataType mPointer = landTable.data(landTable.getModelIndex(cellId, landshapeColumn)).value<CSMWorld::LandHeightsColumn::DataType>();
|
return landData->mHeights[localY*ESM::Land::LAND_SIZE + localX];
|
||||||
return mPointer[localY*ESM::Land::LAND_SIZE + localX];
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return landHeight;
|
return landHeight;
|
||||||
|
|
|
@ -44,9 +44,10 @@ namespace CSVRender
|
||||||
~TerrainSelection();
|
~TerrainSelection();
|
||||||
|
|
||||||
void onlySelect(const std::vector<std::pair<int, int>> &localPositions);
|
void onlySelect(const std::vector<std::pair<int, int>> &localPositions);
|
||||||
void addSelect(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, bool toggleInProgress);
|
void removeSelect(const std::vector<std::pair<int, int>>& localPositions);
|
||||||
void toggleSelect(const std::vector<std::pair<int, int>> &localPositions, bool toggleInProgress);
|
void toggleSelect(const std::vector<std::pair<int, int>> &localPositions);
|
||||||
|
void clearTemporarySelection();
|
||||||
|
|
||||||
void activate();
|
void activate();
|
||||||
void deactivate();
|
void deactivate();
|
||||||
|
@ -64,7 +65,7 @@ namespace CSVRender
|
||||||
|
|
||||||
private:
|
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);
|
bool noCell(const std::string& cellId);
|
||||||
|
|
||||||
|
@ -81,7 +82,6 @@ namespace CSVRender
|
||||||
osg::ref_ptr<osg::Group> mSelectionNode;
|
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>> 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
|
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;
|
TerrainSelectionType mSelectionType;
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
|
@ -106,16 +106,6 @@ void CSVRender::TerrainShapeMode::primaryEditPressed(const WorldspaceHitResult&
|
||||||
editTerrainShapeGrid(CSMWorld::CellCoordinates::toVertexCoords(hit.worldPos), true);
|
editTerrainShapeGrid(CSMWorld::CellCoordinates::toVertexCoords(hit.worldPos), true);
|
||||||
applyTerrainEditChanges();
|
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();
|
clearTransientEdits();
|
||||||
}
|
}
|
||||||
|
@ -124,7 +114,8 @@ void CSVRender::TerrainShapeMode::primarySelectPressed(const WorldspaceHitResult
|
||||||
{
|
{
|
||||||
if(hit.hit && hit.tag == nullptr)
|
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)
|
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;
|
mDragMode = InteractionType_None;
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
selectTerrainShapes(CSMWorld::CellCoordinates::toVertexCoords(hit.worldPos), 0, true);
|
selectTerrainShapes(CSMWorld::CellCoordinates::toVertexCoords(hit.worldPos), 0);
|
||||||
return false;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool CSVRender::TerrainShapeMode::secondarySelectStartDrag (const QPoint& pos)
|
bool CSVRender::TerrainShapeMode::secondarySelectStartDrag (const QPoint& pos)
|
||||||
|
@ -180,8 +172,8 @@ bool CSVRender::TerrainShapeMode::secondarySelectStartDrag (const QPoint& pos)
|
||||||
mDragMode = InteractionType_None;
|
mDragMode = InteractionType_None;
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
selectTerrainShapes(CSMWorld::CellCoordinates::toVertexCoords(hit.worldPos), 1, true);
|
selectTerrainShapes(CSMWorld::CellCoordinates::toVertexCoords(hit.worldPos), 1);
|
||||||
return false;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
void CSVRender::TerrainShapeMode::drag (const QPoint& pos, int diffX, int diffY, double speedFactor)
|
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)
|
if (mDragMode == InteractionType_PrimarySelect)
|
||||||
{
|
{
|
||||||
WorldspaceHitResult hit = getWorldspaceWidget().mousePick (pos, getWorldspaceWidget().getInteractionMask());
|
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)
|
if (mDragMode == InteractionType_SecondarySelect)
|
||||||
{
|
{
|
||||||
WorldspaceHitResult hit = getWorldspaceWidget().mousePick (pos, getWorldspaceWidget().getInteractionMask());
|
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();
|
applyTerrainEditChanges();
|
||||||
clearTransientEdits();
|
clearTransientEdits();
|
||||||
}
|
}
|
||||||
|
if (mDragMode == InteractionType_PrimarySelect || mDragMode == InteractionType_SecondarySelect)
|
||||||
|
{
|
||||||
|
mTerrainShapeSelection->clearTemporarySelection();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void CSVRender::TerrainShapeMode::dragAborted()
|
void CSVRender::TerrainShapeMode::dragAborted()
|
||||||
{
|
{
|
||||||
clearTransientEdits();
|
clearTransientEdits();
|
||||||
|
mDragMode = InteractionType_None;
|
||||||
}
|
}
|
||||||
|
|
||||||
void CSVRender::TerrainShapeMode::dragWheel (int diff, double speedFactor)
|
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;
|
int r = mBrushSize / 2;
|
||||||
std::vector<std::pair<int, int>> selections;
|
std::vector<std::pair<int, int>> selections;
|
||||||
|
@ -1136,11 +1133,11 @@ void CSVRender::TerrainShapeMode::selectTerrainShapes(const std::pair<int, int>&
|
||||||
if (selectAction == "Select only")
|
if (selectAction == "Select only")
|
||||||
mTerrainShapeSelection->onlySelect(selections);
|
mTerrainShapeSelection->onlySelect(selections);
|
||||||
else if (selectAction == "Add to selection")
|
else if (selectAction == "Add to selection")
|
||||||
mTerrainShapeSelection->addSelect(selections, dragOperation);
|
mTerrainShapeSelection->addSelect(selections);
|
||||||
else if (selectAction == "Remove from selection")
|
else if (selectAction == "Remove from selection")
|
||||||
mTerrainShapeSelection->removeSelect(selections, dragOperation);
|
mTerrainShapeSelection->removeSelect(selections);
|
||||||
else if (selectAction == "Invert selection")
|
else if (selectAction == "Invert selection")
|
||||||
mTerrainShapeSelection->toggleSelect(selections, dragOperation);
|
mTerrainShapeSelection->toggleSelect(selections);
|
||||||
}
|
}
|
||||||
|
|
||||||
void CSVRender::TerrainShapeMode::pushEditToCommand(const CSMWorld::LandHeightsColumn::DataType& newLandGrid, CSMDoc::Document& document,
|
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);
|
void handleSelection(int globalSelectionX, int globalSelectionY, std::vector<std::pair<int, int>>* selections);
|
||||||
|
|
||||||
/// Handle brush mechanics for terrain shape selection
|
/// 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
|
/// Push terrain shape edits to command macro
|
||||||
void pushEditToCommand (const CSMWorld::LandHeightsColumn::DataType& newLandGrid, CSMDoc::Document& document,
|
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 TerrainStorage::getSumOfAlteredAndTrueHeight(int cellX, int cellY, int inCellX, int inCellY)
|
||||||
{
|
{
|
||||||
float height = 0.f;
|
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)
|
float* TerrainStorage::getAlteredHeight(int inCellX, int inCellY)
|
||||||
|
|
|
@ -129,7 +129,8 @@ void CSVRender::TerrainTextureMode::primarySelectPressed(const WorldspaceHitResu
|
||||||
{
|
{
|
||||||
if(hit.hit && hit.tag == nullptr)
|
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)
|
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;
|
mDragMode = InteractionType_None;
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
selectTerrainTextures(CSMWorld::CellCoordinates::toTextureCoords(hit.worldPos), 0, true);
|
selectTerrainTextures(CSMWorld::CellCoordinates::toTextureCoords(hit.worldPos), 0);
|
||||||
return false;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool CSVRender::TerrainTextureMode::secondarySelectStartDrag (const QPoint& pos)
|
bool CSVRender::TerrainTextureMode::secondarySelectStartDrag (const QPoint& pos)
|
||||||
|
@ -201,8 +203,8 @@ bool CSVRender::TerrainTextureMode::secondarySelectStartDrag (const QPoint& pos)
|
||||||
mDragMode = InteractionType_None;
|
mDragMode = InteractionType_None;
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
selectTerrainTextures(CSMWorld::CellCoordinates::toTextureCoords(hit.worldPos), 1, true);
|
selectTerrainTextures(CSMWorld::CellCoordinates::toTextureCoords(hit.worldPos), 1);
|
||||||
return false;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
void CSVRender::TerrainTextureMode::drag (const QPoint& pos, int diffX, int diffY, double speedFactor)
|
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)
|
if (mDragMode == InteractionType_PrimarySelect)
|
||||||
{
|
{
|
||||||
WorldspaceHitResult hit = getWorldspaceWidget().mousePick (pos, getWorldspaceWidget().getInteractionMask());
|
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)
|
if (mDragMode == InteractionType_SecondarySelect)
|
||||||
{
|
{
|
||||||
WorldspaceHitResult hit = getWorldspaceWidget().mousePick (pos, getWorldspaceWidget().getInteractionMask());
|
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;
|
mIsEditing = false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
mTerrainTextureSelection->clearTemporarySelection();
|
||||||
}
|
}
|
||||||
|
|
||||||
void CSVRender::TerrainTextureMode::dragAborted()
|
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;
|
int r = mBrushSize / 2;
|
||||||
std::vector<std::pair<int, int>> selections;
|
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);
|
std::string selectAction;
|
||||||
if(selectMode == 1) mTerrainTextureSelection->toggleSelect(selections, dragOperation);
|
|
||||||
|
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,
|
void CSVRender::TerrainTextureMode::pushEditToCommand(CSMWorld::LandTexturesColumn::DataType& newLandGrid, CSMDoc::Document& document,
|
||||||
|
|
|
@ -95,7 +95,7 @@ namespace CSVRender
|
||||||
bool isInCellSelection(int globalSelectionX, int globalSelectionY);
|
bool isInCellSelection(int globalSelectionX, int globalSelectionY);
|
||||||
|
|
||||||
/// \brief Handle brush mechanics for texture selection
|
/// \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
|
/// \brief Push texture edits to command macro
|
||||||
void pushEditToCommand (CSMWorld::LandTexturesColumn::DataType& newLandGrid, CSMDoc::Document& document,
|
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& editMode = dynamic_cast<CSVRender::EditMode&> (*mEditMode->getCurrent());
|
||||||
|
|
||||||
editMode.dragAborted();
|
editMode.dragAborted();
|
||||||
mDragging = false;
|
|
||||||
mDragMode = InteractionType_None;
|
mDragMode = InteractionType_None;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -19,7 +19,7 @@ set(GAME_HEADER
|
||||||
source_group(game FILES ${GAME} ${GAME_HEADER})
|
source_group(game FILES ${GAME} ${GAME_HEADER})
|
||||||
|
|
||||||
add_openmw_dir (mwrender
|
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
|
creatureanimation effectmanager util renderinginterface pathgrid rendermode weaponanimation screenshotmanager
|
||||||
bulletdebugdraw globalmap characterpreview camera viewovershoulder localmap water terrainstorage ripplesimulation
|
bulletdebugdraw globalmap characterpreview camera viewovershoulder localmap water terrainstorage ripplesimulation
|
||||||
renderbin actoranimation landmanager navmesh actorspaths recastmesh fogmanager objectpaging groundcover postprocessor
|
renderbin actoranimation landmanager navmesh actorspaths recastmesh fogmanager objectpaging groundcover postprocessor
|
||||||
|
@ -27,7 +27,7 @@ add_openmw_dir (mwrender
|
||||||
|
|
||||||
add_openmw_dir (mwinput
|
add_openmw_dir (mwinput
|
||||||
actions actionmanager bindingsmanager controllermanager controlswitch
|
actions actionmanager bindingsmanager controllermanager controlswitch
|
||||||
inputmanagerimp mousemanager keyboardmanager sdlmappings sensormanager
|
inputmanagerimp mousemanager keyboardmanager sensormanager
|
||||||
)
|
)
|
||||||
|
|
||||||
add_openmw_dir (mwgui
|
add_openmw_dir (mwgui
|
||||||
|
@ -72,9 +72,9 @@ add_openmw_dir (mwworld
|
||||||
containerstore actiontalk actiontake manualref player cellvisitors failedaction
|
containerstore actiontalk actiontake manualref player cellvisitors failedaction
|
||||||
cells localscripts customdata inventorystore ptr actionopen actionread actionharvest
|
cells localscripts customdata inventorystore ptr actionopen actionread actionharvest
|
||||||
actionequip timestamp actionalchemy cellstore actionapply actioneat
|
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
|
contentloader esmloader actiontrap cellreflist cellref weather projectilemanager
|
||||||
cellpreloader datetimemanager
|
cellpreloader datetimemanager groundcoverstore magiceffects
|
||||||
)
|
)
|
||||||
|
|
||||||
add_openmw_dir (mwphysics
|
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
|
aicast aiescort aiface aiactivate aicombat recharge repair enchanting pathfinding pathgrid security spellcasting spellresistance
|
||||||
disease pickpocket levelledlist combat steering obstacle autocalcspell difficultyscaling aicombataction actor summoning
|
disease pickpocket levelledlist combat steering obstacle autocalcspell difficultyscaling aicombataction actor summoning
|
||||||
character actors objects aistate trading weaponpriority spellpriority weapontype spellutil
|
character actors objects aistate trading weaponpriority spellpriority weapontype spellutil
|
||||||
spellabsorption spelleffects
|
spelleffects
|
||||||
)
|
)
|
||||||
|
|
||||||
add_openmw_dir (mwstate
|
add_openmw_dir (mwstate
|
||||||
|
@ -153,9 +153,12 @@ target_link_libraries(openmw
|
||||||
"osg-ffmpeg-videoplayer"
|
"osg-ffmpeg-videoplayer"
|
||||||
"oics"
|
"oics"
|
||||||
components
|
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)
|
if (ANDROID)
|
||||||
target_link_libraries(openmw EGL android log z)
|
target_link_libraries(openmw EGL android log z)
|
||||||
endif (ANDROID)
|
endif (ANDROID)
|
||||||
|
@ -176,8 +179,7 @@ endif()
|
||||||
if(APPLE)
|
if(APPLE)
|
||||||
set(BUNDLE_RESOURCES_DIR "${APP_BUNDLE_DIR}/Contents/Resources")
|
set(BUNDLE_RESOURCES_DIR "${APP_BUNDLE_DIR}/Contents/Resources")
|
||||||
|
|
||||||
set(OPENMW_MYGUI_FILES_ROOT ${BUNDLE_RESOURCES_DIR})
|
set(OPENMW_RESOURCES_ROOT ${BUNDLE_RESOURCES_DIR})
|
||||||
set(OPENMW_SHADERS_ROOT ${BUNDLE_RESOURCES_DIR})
|
|
||||||
|
|
||||||
add_subdirectory(../../files/ ${CMAKE_CURRENT_BINARY_DIR}/files)
|
add_subdirectory(../../files/ ${CMAKE_CURRENT_BINARY_DIR}/files)
|
||||||
|
|
||||||
|
|
|
@ -1,4 +1,6 @@
|
||||||
|
#ifndef stderr
|
||||||
int stderr = 0; // Hack: fix linker error
|
int stderr = 0; // Hack: fix linker error
|
||||||
|
#endif
|
||||||
|
|
||||||
#include "SDL_main.h"
|
#include "SDL_main.h"
|
||||||
#include <SDL_gamecontroller.h>
|
#include <SDL_gamecontroller.h>
|
||||||
|
|
|
@ -8,6 +8,8 @@
|
||||||
|
|
||||||
#include <boost/filesystem/fstream.hpp>
|
#include <boost/filesystem/fstream.hpp>
|
||||||
|
|
||||||
|
#include <osg/Version>
|
||||||
|
|
||||||
#include <osgViewer/ViewerEventHandlers>
|
#include <osgViewer/ViewerEventHandlers>
|
||||||
#include <osgDB/ReadFile>
|
#include <osgDB/ReadFile>
|
||||||
#include <osgDB/WriteFile>
|
#include <osgDB/WriteFile>
|
||||||
|
@ -37,11 +39,10 @@
|
||||||
|
|
||||||
#include <components/version/version.hpp>
|
#include <components/version/version.hpp>
|
||||||
|
|
||||||
#include <components/detournavigator/navigator.hpp>
|
|
||||||
|
|
||||||
#include <components/misc/frameratelimiter.hpp>
|
#include <components/misc/frameratelimiter.hpp>
|
||||||
|
|
||||||
#include <components/sceneutil/screencapture.hpp>
|
#include <components/sceneutil/screencapture.hpp>
|
||||||
|
#include <components/sceneutil/depth.hpp>
|
||||||
|
|
||||||
#include "mwinput/inputmanagerimp.hpp"
|
#include "mwinput/inputmanagerimp.hpp"
|
||||||
|
|
||||||
|
@ -293,6 +294,10 @@ bool OMW::Engine::frame(float frametime)
|
||||||
// Main menu opened? Then scripts are also paused.
|
// Main menu opened? Then scripts are also paused.
|
||||||
bool paused = mEnvironment.getWindowManager()->containsMode(MWGui::GM_MainMenu);
|
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
|
// update game state
|
||||||
{
|
{
|
||||||
ScopedProfile<UserStatsType::State> profile(frameStart, frameNumber, *timer, *stats);
|
ScopedProfile<UserStatsType::State> profile(frameStart, frameNumber, *timer, *stats);
|
||||||
|
@ -495,11 +500,6 @@ void OMW::Engine::addGroundcoverFile(const std::string& file)
|
||||||
mGroundcoverFiles.emplace_back(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)
|
void OMW::Engine::setSkipMenu (bool skipMenu, bool newGame)
|
||||||
{
|
{
|
||||||
mSkipMenu = skipMenu;
|
mSkipMenu = skipMenu;
|
||||||
|
@ -551,6 +551,10 @@ void OMW::Engine::createWindow(Settings::Manager& settings)
|
||||||
if(fullscreen)
|
if(fullscreen)
|
||||||
flags |= SDL_WINDOW_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)
|
if (!windowBorder)
|
||||||
flags |= SDL_WINDOW_BORDERLESS;
|
flags |= SDL_WINDOW_BORDERLESS;
|
||||||
|
|
||||||
|
@ -674,7 +678,7 @@ void OMW::Engine::setWindowIcon()
|
||||||
void OMW::Engine::prepareEngine (Settings::Manager & settings)
|
void OMW::Engine::prepareEngine (Settings::Manager & settings)
|
||||||
{
|
{
|
||||||
mEnvironment.setStateManager (
|
mEnvironment.setStateManager (
|
||||||
new MWState::StateManager (mCfgMgr.getUserDataPath() / "saves", mContentFiles.at (0)));
|
new MWState::StateManager (mCfgMgr.getUserDataPath() / "saves", mContentFiles));
|
||||||
|
|
||||||
createWindow(settings);
|
createWindow(settings);
|
||||||
|
|
||||||
|
@ -714,7 +718,7 @@ void OMW::Engine::prepareEngine (Settings::Manager & settings)
|
||||||
|
|
||||||
mViewer->addEventHandler(mScreenCaptureHandler);
|
mViewer->addEventHandler(mScreenCaptureHandler);
|
||||||
|
|
||||||
mLuaManager = new MWLua::LuaManager(mVFS.get(), mLuaScriptListFiles);
|
mLuaManager = new MWLua::LuaManager(mVFS.get());
|
||||||
mEnvironment.setLuaManager(mLuaManager);
|
mEnvironment.setLuaManager(mLuaManager);
|
||||||
|
|
||||||
// Create input and UI first to set up a bootstrapping environment for
|
// 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);
|
osg::ref_ptr<osg::GLExtensions> exts = osg::GLExtensions::Get(0, false);
|
||||||
bool shadersSupported = exts && (exts->glslLanguageVersion >= 1.2f);
|
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();
|
std::string myguiResources = (mResDir / "mygui").string();
|
||||||
osg::ref_ptr<osg::Group> guiRoot = new osg::Group;
|
osg::ref_ptr<osg::Group> guiRoot = new osg::Group;
|
||||||
|
@ -869,7 +895,6 @@ public:
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
update();
|
update();
|
||||||
mEngine->mLuaManager->applyQueuedChanges();
|
|
||||||
};
|
};
|
||||||
|
|
||||||
void join()
|
void join()
|
||||||
|
@ -1064,8 +1089,6 @@ void OMW::Engine::go()
|
||||||
// Save user settings
|
// Save user settings
|
||||||
settings.saveUser(settingspath);
|
settings.saveUser(settingspath);
|
||||||
|
|
||||||
mViewer->stopThreading();
|
|
||||||
|
|
||||||
Log(Debug::Info) << "Quitting peacefully.";
|
Log(Debug::Info) << "Quitting peacefully.";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -72,7 +72,6 @@ namespace OMW
|
||||||
std::string mCellName;
|
std::string mCellName;
|
||||||
std::vector<std::string> mContentFiles;
|
std::vector<std::string> mContentFiles;
|
||||||
std::vector<std::string> mGroundcoverFiles;
|
std::vector<std::string> mGroundcoverFiles;
|
||||||
std::vector<std::string> mLuaScriptListFiles;
|
|
||||||
bool mSkipMenu;
|
bool mSkipMenu;
|
||||||
bool mUseSound;
|
bool mUseSound;
|
||||||
bool mCompileAll;
|
bool mCompileAll;
|
||||||
|
@ -146,7 +145,6 @@ namespace OMW
|
||||||
*/
|
*/
|
||||||
void addContentFile(const std::string& file);
|
void addContentFile(const std::string& file);
|
||||||
void addGroundcoverFile(const std::string& file);
|
void addGroundcoverFile(const std::string& file);
|
||||||
void addLuaScriptListFile(const std::string& file);
|
|
||||||
|
|
||||||
/// Disable or enable all sounds
|
/// Disable or enable all sounds
|
||||||
void setSoundUsage(bool soundUsage);
|
void setSoundUsage(bool soundUsage);
|
||||||
|
|
|
@ -123,9 +123,11 @@ bool parseOptions (int argc, char** argv, OMW::Engine& engine, Files::Configurat
|
||||||
engine.addGroundcoverFile(file);
|
engine.addGroundcoverFile(file);
|
||||||
}
|
}
|
||||||
|
|
||||||
StringsVector luaScriptLists = variables["lua-scripts"].as<StringsVector>();
|
if (variables.count("lua-scripts"))
|
||||||
for (const auto& file : luaScriptLists)
|
{
|
||||||
engine.addLuaScriptListFile(file);
|
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
|
// startup-settings
|
||||||
engine.setCell(variables["start"].as<std::string>());
|
engine.setCell(variables["start"].as<std::string>());
|
||||||
|
|
|
@ -49,8 +49,8 @@ namespace MWBase
|
||||||
virtual void setGamepadGuiCursorEnabled(bool enabled) = 0;
|
virtual void setGamepadGuiCursorEnabled(bool enabled) = 0;
|
||||||
virtual void setAttemptJump(bool jumping) = 0;
|
virtual void setAttemptJump(bool jumping) = 0;
|
||||||
|
|
||||||
virtual void toggleControlSwitch (const std::string& sw, bool value) = 0;
|
virtual void toggleControlSwitch(std::string_view sw, bool value) = 0;
|
||||||
virtual bool getControlSwitch (const std::string& sw) = 0;
|
virtual bool getControlSwitch(std::string_view sw) = 0;
|
||||||
|
|
||||||
virtual std::string getActionDescription (int action) const = 0;
|
virtual std::string getActionDescription (int action) const = 0;
|
||||||
virtual std::string getActionKeyBindingName (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 bool actionIsActive(int action) const = 0;
|
||||||
|
|
||||||
virtual float getActionValue(int action) const = 0; // returns value in range [0, 1]
|
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 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 getMouseMoveX() const = 0;
|
||||||
virtual int getMouseMoveY() const = 0;
|
virtual int getMouseMoveY() const = 0;
|
||||||
|
|
||||||
|
|
|
@ -30,6 +30,7 @@ namespace MWBase
|
||||||
virtual ~LuaManager() = default;
|
virtual ~LuaManager() = default;
|
||||||
|
|
||||||
virtual void newGameStarted() = 0;
|
virtual void newGameStarted() = 0;
|
||||||
|
virtual void gameLoaded() = 0;
|
||||||
virtual void registerObject(const MWWorld::Ptr& ptr) = 0;
|
virtual void registerObject(const MWWorld::Ptr& ptr) = 0;
|
||||||
virtual void deregisterObject(const MWWorld::Ptr& ptr) = 0;
|
virtual void deregisterObject(const MWWorld::Ptr& ptr) = 0;
|
||||||
virtual void objectAddedToScene(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.
|
/// Makes \a ptr fight \a target. Also shouts a combat taunt.
|
||||||
virtual void startCombat (const MWWorld::Ptr& ptr, const MWWorld::Ptr& target) = 0;
|
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
|
enum OffenseType
|
||||||
{
|
{
|
||||||
OT_Theft, // Taking items owned by an NPC or a faction you are not a member of
|
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 const std::string& getVersionDescription() const = 0;
|
||||||
|
|
||||||
virtual void onDeleteCustomData(const MWWorld::Ptr& ptr) = 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
|
namespace MWRender
|
||||||
{
|
{
|
||||||
class Animation;
|
class Animation;
|
||||||
|
class Camera;
|
||||||
}
|
}
|
||||||
|
|
||||||
namespace MWMechanics
|
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;
|
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
|
///< @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
|
///< @return an updated Ptr
|
||||||
|
|
||||||
virtual void scaleObject (const MWWorld::Ptr& ptr, float scale) = 0;
|
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 osg::Matrixf getActorHeadTransform(const MWWorld::ConstPtr& actor) const = 0;
|
||||||
|
|
||||||
|
virtual MWRender::Camera* getCamera() = 0;
|
||||||
virtual void togglePOV(bool force = false) = 0;
|
virtual void togglePOV(bool force = false) = 0;
|
||||||
virtual bool isFirstPerson() const = 0;
|
virtual bool isFirstPerson() const = 0;
|
||||||
virtual bool isPreviewModeEnabled() const = 0;
|
virtual bool isPreviewModeEnabled() const = 0;
|
||||||
virtual void togglePreviewMode(bool enable) = 0;
|
|
||||||
virtual bool toggleVanityMode(bool enable) = 0;
|
virtual bool toggleVanityMode(bool enable) = 0;
|
||||||
virtual void allowVanityMode(bool allow) = 0;
|
|
||||||
virtual bool vanityRotateCamera(float * rot) = 0;
|
virtual bool vanityRotateCamera(float * rot) = 0;
|
||||||
virtual void adjustCameraDistance(float dist) = 0;
|
|
||||||
virtual void applyDeferredPreviewRotationToPlayer(float dt) = 0;
|
virtual void applyDeferredPreviewRotationToPlayer(float dt) = 0;
|
||||||
virtual void disableDeferredPreviewRotation() = 0;
|
virtual void disableDeferredPreviewRotation() = 0;
|
||||||
|
|
||||||
|
|
|
@ -89,7 +89,7 @@ namespace MWClass
|
||||||
{
|
{
|
||||||
std::shared_ptr<Class> instance (new Activator);
|
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
|
bool Activator::hasToolTip (const MWWorld::ConstPtr& ptr) const
|
||||||
|
|
|
@ -3,6 +3,8 @@
|
||||||
|
|
||||||
#include "../mwworld/class.hpp"
|
#include "../mwworld/class.hpp"
|
||||||
|
|
||||||
|
#include <components/esm/loadmgef.hpp>
|
||||||
|
|
||||||
namespace ESM
|
namespace ESM
|
||||||
{
|
{
|
||||||
struct GameSetting;
|
struct GameSetting;
|
||||||
|
@ -17,6 +19,15 @@ namespace MWClass
|
||||||
|
|
||||||
Actor() = default;
|
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:
|
public:
|
||||||
~Actor() override = default;
|
~Actor() override = default;
|
||||||
|
|
||||||
|
|
|
@ -69,7 +69,7 @@ namespace MWClass
|
||||||
{
|
{
|
||||||
std::shared_ptr<Class> instance (new Apparatus);
|
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
|
std::string Apparatus::getUpSoundId (const MWWorld::ConstPtr& ptr) const
|
||||||
|
|
|
@ -163,7 +163,7 @@ namespace MWClass
|
||||||
{
|
{
|
||||||
std::shared_ptr<Class> instance (new Armor);
|
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
|
std::string Armor::getUpSoundId (const MWWorld::ConstPtr& ptr) const
|
||||||
|
@ -322,7 +322,7 @@ namespace MWClass
|
||||||
if(*slot == MWWorld::InventoryStore::Slot_CarriedLeft)
|
if(*slot == MWWorld::InventoryStore::Slot_CarriedLeft)
|
||||||
{
|
{
|
||||||
MWWorld::ConstContainerStoreIterator weapon = invStore.getSlot(MWWorld::InventoryStore::Slot_CarriedRight);
|
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>();
|
const MWWorld::LiveCellRef<ESM::Weapon> *ref = weapon->get<ESM::Weapon>();
|
||||||
if (MWMechanics::getWeaponType(ref->mBase->mData.mType)->mFlags & ESM::WeaponType::TwoHanded)
|
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);
|
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
|
std::string BodyPart::getModel(const MWWorld::ConstPtr &ptr) const
|
||||||
|
|
|
@ -85,7 +85,7 @@ namespace MWClass
|
||||||
{
|
{
|
||||||
std::shared_ptr<Class> instance (new Book);
|
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
|
std::string Book::getUpSoundId (const MWWorld::ConstPtr& ptr) const
|
||||||
|
|
|
@ -121,7 +121,7 @@ namespace MWClass
|
||||||
{
|
{
|
||||||
std::shared_ptr<Class> instance (new Clothing);
|
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
|
std::string Clothing::getUpSoundId (const MWWorld::ConstPtr& ptr) const
|
||||||
|
|
|
@ -242,7 +242,7 @@ namespace MWClass
|
||||||
{
|
{
|
||||||
std::shared_ptr<Class> instance (new Container);
|
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
|
bool Container::hasToolTip (const MWWorld::ConstPtr& ptr) const
|
||||||
|
|
|
@ -82,12 +82,13 @@ namespace MWClass
|
||||||
|
|
||||||
const Creature::GMST& Creature::getGmst()
|
const Creature::GMST& Creature::getGmst()
|
||||||
{
|
{
|
||||||
static GMST gmst;
|
static const GMST staticGmst = []
|
||||||
static bool inited = false;
|
|
||||||
if (!inited)
|
|
||||||
{
|
{
|
||||||
|
GMST gmst;
|
||||||
|
|
||||||
const MWBase::World *world = MWBase::Environment::get().getWorld();
|
const MWBase::World *world = MWBase::Environment::get().getWorld();
|
||||||
const MWWorld::Store<ESM::GameSetting> &store = world->getStore().get<ESM::GameSetting>();
|
const MWWorld::Store<ESM::GameSetting> &store = world->getStore().get<ESM::GameSetting>();
|
||||||
|
|
||||||
gmst.fMinWalkSpeedCreature = store.find("fMinWalkSpeedCreature");
|
gmst.fMinWalkSpeedCreature = store.find("fMinWalkSpeedCreature");
|
||||||
gmst.fMaxWalkSpeedCreature = store.find("fMaxWalkSpeedCreature");
|
gmst.fMaxWalkSpeedCreature = store.find("fMaxWalkSpeedCreature");
|
||||||
gmst.fEncumberedMoveEffect = store.find("fEncumberedMoveEffect");
|
gmst.fEncumberedMoveEffect = store.find("fEncumberedMoveEffect");
|
||||||
|
@ -101,16 +102,20 @@ namespace MWClass
|
||||||
gmst.fKnockDownMult = store.find("fKnockDownMult");
|
gmst.fKnockDownMult = store.find("fKnockDownMult");
|
||||||
gmst.iKnockDownOddsMult = store.find("iKnockDownOddsMult");
|
gmst.iKnockDownOddsMult = store.find("iKnockDownOddsMult");
|
||||||
gmst.iKnockDownOddsBase = store.find("iKnockDownOddsBase");
|
gmst.iKnockDownOddsBase = store.find("iKnockDownOddsBase");
|
||||||
inited = true;
|
|
||||||
}
|
|
||||||
return gmst;
|
return gmst;
|
||||||
|
} ();
|
||||||
|
return staticGmst;
|
||||||
}
|
}
|
||||||
|
|
||||||
void Creature::ensureCustomData (const MWWorld::Ptr& ptr) const
|
void Creature::ensureCustomData (const MWWorld::Ptr& ptr) const
|
||||||
{
|
{
|
||||||
if (!ptr.getRefData().getCustomData())
|
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>();
|
MWWorld::LiveCellRef<ESM::Creature> *ref = ptr.get<ESM::Creature>();
|
||||||
|
|
||||||
|
@ -154,10 +159,7 @@ namespace MWClass
|
||||||
|
|
||||||
data->mCreatureStats.setGoldPool(ref->mBase->mData.mGold);
|
data->mCreatureStats.setGoldPool(ref->mBase->mData.mGold);
|
||||||
|
|
||||||
data->mCreatureStats.setNeedRecalcDynamicStats(false);
|
resetter.mPtr = {};
|
||||||
|
|
||||||
// store
|
|
||||||
ptr.getRefData().setCustomData(std::move(data));
|
|
||||||
|
|
||||||
getContainerStore(ptr).fill(ref->mBase->mInventory, ptr.getCellRef().getRefId());
|
getContainerStore(ptr).fill(ref->mBase->mInventory, ptr.getCellRef().getRefId());
|
||||||
|
|
||||||
|
@ -238,7 +240,7 @@ namespace MWClass
|
||||||
{
|
{
|
||||||
MWWorld::InventoryStore &inv = getInventoryStore(ptr);
|
MWWorld::InventoryStore &inv = getInventoryStore(ptr);
|
||||||
MWWorld::ContainerStoreIterator weaponslot = inv.getSlot(MWWorld::InventoryStore::Slot_CarriedRight);
|
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;
|
weapon = *weaponslot;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -497,7 +499,7 @@ namespace MWClass
|
||||||
{
|
{
|
||||||
std::shared_ptr<Class> instance (new Creature);
|
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
|
float Creature::getMaxSpeed(const MWWorld::Ptr &ptr) const
|
||||||
|
@ -891,12 +893,8 @@ namespace MWClass
|
||||||
float Creature::getSwimSpeed(const MWWorld::Ptr& ptr) const
|
float Creature::getSwimSpeed(const MWWorld::Ptr& ptr) const
|
||||||
{
|
{
|
||||||
const MWMechanics::CreatureStats& stats = getCreatureStats(ptr);
|
const MWMechanics::CreatureStats& stats = getCreatureStats(ptr);
|
||||||
const GMST& gmst = getGmst();
|
|
||||||
const MWMechanics::MagicEffects& mageffects = stats.getMagicEffects();
|
const MWMechanics::MagicEffects& mageffects = stats.getMagicEffects();
|
||||||
|
|
||||||
return getWalkSpeed(ptr)
|
return getSwimSpeedImpl(ptr, getGmst(), mageffects, 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());
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -5,6 +5,7 @@
|
||||||
|
|
||||||
#include "../mwmechanics/levelledlist.hpp"
|
#include "../mwmechanics/levelledlist.hpp"
|
||||||
|
|
||||||
|
#include "../mwworld/cellstore.hpp"
|
||||||
#include "../mwworld/customdata.hpp"
|
#include "../mwworld/customdata.hpp"
|
||||||
#include "../mwmechanics/creaturestats.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
|
std::string CreatureLevList::getName (const MWWorld::ConstPtr& ptr) const
|
||||||
{
|
{
|
||||||
return "";
|
return "";
|
||||||
|
@ -45,7 +64,13 @@ namespace MWClass
|
||||||
if (customData.mSpawn)
|
if (customData.mSpawn)
|
||||||
return;
|
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())
|
if (!creature.isEmpty())
|
||||||
{
|
{
|
||||||
const MWMechanics::CreatureStats& creatureStats = creature.getClass().getCreatureStats(creature);
|
const MWMechanics::CreatureStats& creatureStats = creature.getClass().getCreatureStats(creature);
|
||||||
|
@ -70,7 +95,7 @@ namespace MWClass
|
||||||
{
|
{
|
||||||
std::shared_ptr<Class> instance (new CreatureLevList);
|
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
|
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.
|
///< Write additional state from \a ptr into \a state.
|
||||||
|
|
||||||
void respawn (const MWWorld::Ptr& ptr) const override;
|
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);
|
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
|
MWGui::ToolTipInfo Door::getToolTipInfo (const MWWorld::ConstPtr& ptr, int count) const
|
||||||
|
|
|
@ -81,7 +81,7 @@ namespace MWClass
|
||||||
{
|
{
|
||||||
std::shared_ptr<Class> instance (new Ingredient);
|
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
|
std::string Ingredient::getUpSoundId (const MWWorld::ConstPtr& ptr) const
|
||||||
|
|
|
@ -19,6 +19,6 @@ namespace MWClass
|
||||||
{
|
{
|
||||||
std::shared_ptr<Class> instance (new ItemLevList);
|
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);
|
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
|
std::string Light::getUpSoundId (const MWWorld::ConstPtr& ptr) const
|
||||||
|
|
|
@ -80,7 +80,7 @@ namespace MWClass
|
||||||
{
|
{
|
||||||
std::shared_ptr<Class> instance (new Lockpick);
|
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
|
std::string Lockpick::getUpSoundId (const MWWorld::ConstPtr& ptr) const
|
||||||
|
|
|
@ -106,7 +106,7 @@ namespace MWClass
|
||||||
{
|
{
|
||||||
std::shared_ptr<Class> instance (new Miscellaneous);
|
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
|
std::string Miscellaneous::getUpSoundId (const MWWorld::ConstPtr& ptr) const
|
||||||
|
|
|
@ -266,10 +266,10 @@ namespace MWClass
|
||||||
|
|
||||||
const Npc::GMST& Npc::getGmst()
|
const Npc::GMST& Npc::getGmst()
|
||||||
{
|
{
|
||||||
static GMST gmst;
|
static const GMST staticGmst = []
|
||||||
static bool inited = false;
|
|
||||||
if(!inited)
|
|
||||||
{
|
{
|
||||||
|
GMST gmst;
|
||||||
|
|
||||||
const MWBase::World *world = MWBase::Environment::get().getWorld();
|
const MWBase::World *world = MWBase::Environment::get().getWorld();
|
||||||
const MWWorld::Store<ESM::GameSetting> &store = world->getStore().get<ESM::GameSetting>();
|
const MWWorld::Store<ESM::GameSetting> &store = world->getStore().get<ESM::GameSetting>();
|
||||||
|
|
||||||
|
@ -294,16 +294,20 @@ namespace MWClass
|
||||||
gmst.iKnockDownOddsBase = store.find("iKnockDownOddsBase");
|
gmst.iKnockDownOddsBase = store.find("iKnockDownOddsBase");
|
||||||
gmst.fCombatArmorMinMult = store.find("fCombatArmorMinMult");
|
gmst.fCombatArmorMinMult = store.find("fCombatArmorMinMult");
|
||||||
|
|
||||||
inited = true;
|
|
||||||
}
|
|
||||||
return gmst;
|
return gmst;
|
||||||
|
} ();
|
||||||
|
return staticGmst;
|
||||||
}
|
}
|
||||||
|
|
||||||
void Npc::ensureCustomData (const MWWorld::Ptr& ptr) const
|
void Npc::ensureCustomData (const MWWorld::Ptr& ptr) const
|
||||||
{
|
{
|
||||||
if (!ptr.getRefData().getCustomData())
|
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>();
|
MWWorld::LiveCellRef<ESM::NPC> *ref = ptr.get<ESM::NPC>();
|
||||||
|
|
||||||
|
@ -334,8 +338,6 @@ namespace MWClass
|
||||||
data->mNpcStats.setLevel(ref->mBase->mNpdt.mLevel);
|
data->mNpcStats.setLevel(ref->mBase->mNpdt.mLevel);
|
||||||
data->mNpcStats.setBaseDisposition(ref->mBase->mNpdt.mDisposition);
|
data->mNpcStats.setBaseDisposition(ref->mBase->mNpdt.mDisposition);
|
||||||
data->mNpcStats.setReputation(ref->mBase->mNpdt.mReputation);
|
data->mNpcStats.setReputation(ref->mBase->mNpdt.mReputation);
|
||||||
|
|
||||||
data->mNpcStats.setNeedRecalcDynamicStats(false);
|
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
@ -351,7 +353,7 @@ namespace MWClass
|
||||||
autoCalculateAttributes(ref->mBase, data->mNpcStats);
|
autoCalculateAttributes(ref->mBase, data->mNpcStats);
|
||||||
autoCalculateSkills(ref->mBase, data->mNpcStats, ptr, spellsInitialised);
|
autoCalculateSkills(ref->mBase, data->mNpcStats, ptr, spellsInitialised);
|
||||||
|
|
||||||
data->mNpcStats.setNeedRecalcDynamicStats(true);
|
recalculate = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Persistent actors with 0 health do not play death animation
|
// Persistent actors with 0 health do not play death animation
|
||||||
|
@ -387,7 +389,9 @@ namespace MWClass
|
||||||
data->mNpcStats.setGoldPool(gold);
|
data->mNpcStats.setGoldPool(gold);
|
||||||
|
|
||||||
// store
|
// store
|
||||||
ptr.getRefData().setCustomData(std::move(data));
|
resetter.mPtr = {};
|
||||||
|
if(recalculate)
|
||||||
|
data->mNpcStats.recalculateMagicka();
|
||||||
|
|
||||||
// inventory
|
// inventory
|
||||||
// setting ownership is used to make the NPC auto-equip his initial equipment only, and not bartered items
|
// 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())
|
if (equipped != invStore.end())
|
||||||
{
|
{
|
||||||
std::vector<ESM::PartReference> parts;
|
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;
|
const ESM::Clothing *clothes = equipped->get<ESM::Clothing>()->mBase;
|
||||||
parts = clothes->mParts.mParts;
|
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;
|
const ESM::Armor *armor = equipped->get<ESM::Armor>()->mBase;
|
||||||
parts = armor->mParts.mParts;
|
parts = armor->mParts.mParts;
|
||||||
|
@ -543,7 +547,7 @@ namespace MWClass
|
||||||
MWWorld::InventoryStore &inv = getInventoryStore(ptr);
|
MWWorld::InventoryStore &inv = getInventoryStore(ptr);
|
||||||
MWWorld::ContainerStoreIterator weaponslot = inv.getSlot(MWWorld::InventoryStore::Slot_CarriedRight);
|
MWWorld::ContainerStoreIterator weaponslot = inv.getSlot(MWWorld::InventoryStore::Slot_CarriedRight);
|
||||||
MWWorld::Ptr weapon = ((weaponslot != inv.end()) ? *weaponslot : MWWorld::Ptr());
|
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();
|
weapon = MWWorld::Ptr();
|
||||||
|
|
||||||
MWMechanics::applyFatigueLoss(ptr, weapon, attackStrength);
|
MWMechanics::applyFatigueLoss(ptr, weapon, attackStrength);
|
||||||
|
@ -766,7 +770,7 @@ namespace MWClass
|
||||||
MWWorld::InventoryStore &inv = getInventoryStore(ptr);
|
MWWorld::InventoryStore &inv = getInventoryStore(ptr);
|
||||||
MWWorld::ContainerStoreIterator armorslot = inv.getSlot(hitslot);
|
MWWorld::ContainerStoreIterator armorslot = inv.getSlot(hitslot);
|
||||||
MWWorld::Ptr armor = ((armorslot != inv.end()) ? *armorslot : MWWorld::Ptr());
|
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 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)
|
if (!hasArmor && hitslot == MWWorld::InventoryStore::Slot_CarriedLeft)
|
||||||
{
|
{
|
||||||
|
@ -778,7 +782,7 @@ namespace MWClass
|
||||||
if (armorslot != inv.end())
|
if (armorslot != inv.end())
|
||||||
{
|
{
|
||||||
armor = *armorslot;
|
armor = *armorslot;
|
||||||
hasArmor = !armor.isEmpty() && armor.getTypeName() == typeid(ESM::Armor).name();
|
hasArmor = !armor.isEmpty() && armor.getType() == ESM::Armor::sRecordId;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (hasArmor)
|
if (hasArmor)
|
||||||
|
@ -1036,7 +1040,7 @@ namespace MWClass
|
||||||
void Npc::registerSelf()
|
void Npc::registerSelf()
|
||||||
{
|
{
|
||||||
std::shared_ptr<Class> instance (new Npc);
|
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
|
bool Npc::hasToolTip(const MWWorld::ConstPtr& ptr) const
|
||||||
|
@ -1135,7 +1139,7 @@ namespace MWClass
|
||||||
for(int i = 0;i < MWWorld::InventoryStore::Slots;i++)
|
for(int i = 0;i < MWWorld::InventoryStore::Slots;i++)
|
||||||
{
|
{
|
||||||
MWWorld::ConstContainerStoreIterator it = invStore.getSlot(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
|
// unarmored
|
||||||
ratings[i] = (fUnarmoredBase1 * unarmoredSkill) * (fUnarmoredBase2 * unarmoredSkill);
|
ratings[i] = (fUnarmoredBase1 * unarmoredSkill) * (fUnarmoredBase2 * unarmoredSkill);
|
||||||
|
@ -1232,7 +1236,7 @@ namespace MWClass
|
||||||
|
|
||||||
const MWWorld::InventoryStore &inv = Npc::getInventoryStore(ptr);
|
const MWWorld::InventoryStore &inv = Npc::getInventoryStore(ptr);
|
||||||
MWWorld::ConstContainerStoreIterator boots = inv.getSlot(MWWorld::InventoryStore::Slot_Boots);
|
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";
|
return (name == "left") ? "FootBareLeft" : "FootBareRight";
|
||||||
|
|
||||||
switch(boots->getClass().getEquipmentSkill(*boots))
|
switch(boots->getClass().getEquipmentSkill(*boots))
|
||||||
|
@ -1476,7 +1480,6 @@ namespace MWClass
|
||||||
|
|
||||||
float Npc::getSwimSpeed(const MWWorld::Ptr& ptr) const
|
float Npc::getSwimSpeed(const MWWorld::Ptr& ptr) const
|
||||||
{
|
{
|
||||||
const GMST& gmst = getGmst();
|
|
||||||
const MWBase::World* world = MWBase::Environment::get().getWorld();
|
const MWBase::World* world = MWBase::Environment::get().getWorld();
|
||||||
const MWMechanics::CreatureStats& stats = getCreatureStats(ptr);
|
const MWMechanics::CreatureStats& stats = getCreatureStats(ptr);
|
||||||
const NpcCustomData* npcdata = static_cast<const NpcCustomData*>(ptr.getRefData().getCustomData());
|
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)
|
const bool running = stats.getStance(MWMechanics::CreatureStats::Stance_Run)
|
||||||
&& (inair || MWBase::Environment::get().getMechanicsManager()->isRunning(ptr));
|
&& (inair || MWBase::Environment::get().getMechanicsManager()->isRunning(ptr));
|
||||||
|
|
||||||
float swimSpeed;
|
return getSwimSpeedImpl(ptr, getGmst(), mageffects, running ? getRunSpeed(ptr) : getWalkSpeed(ptr));
|
||||||
|
|
||||||
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;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -74,7 +74,7 @@ namespace MWClass
|
||||||
{
|
{
|
||||||
std::shared_ptr<Class> instance (new Potion);
|
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
|
std::string Potion::getUpSoundId (const MWWorld::ConstPtr& ptr) const
|
||||||
|
|
|
@ -80,7 +80,7 @@ namespace MWClass
|
||||||
{
|
{
|
||||||
std::shared_ptr<Class> instance (new Probe);
|
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
|
std::string Probe::getUpSoundId (const MWWorld::ConstPtr& ptr) const
|
||||||
|
|
|
@ -69,7 +69,7 @@ namespace MWClass
|
||||||
{
|
{
|
||||||
std::shared_ptr<Class> instance (new Repair);
|
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
|
std::string Repair::getUpSoundId (const MWWorld::ConstPtr& ptr) const
|
||||||
|
|
|
@ -59,7 +59,7 @@ namespace MWClass
|
||||||
{
|
{
|
||||||
std::shared_ptr<Class> instance (new Static);
|
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
|
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);
|
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
|
std::string Weapon::getUpSoundId (const MWWorld::ConstPtr& ptr) const
|
||||||
|
|
|
@ -76,9 +76,10 @@ namespace MWDialogue
|
||||||
mKnownTopics.insert( Misc::StringUtils::lowerCase(topic) );
|
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);
|
std::vector<HyperTextParser::Token> hypertext = HyperTextParser::parseHyperText(text);
|
||||||
|
|
||||||
for (std::vector<HyperTextParser::Token>::iterator tok = hypertext.begin(); tok != hypertext.end(); ++tok)
|
for (std::vector<HyperTextParser::Token>::iterator tok = hypertext.begin(); tok != hypertext.end(); ++tok)
|
||||||
|
@ -95,6 +96,18 @@ namespace MWDialogue
|
||||||
topicId = mTranslationDataStorage.topicStandardForm(topicId);
|
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 ))
|
if (mActorKnownTopics.count( topicId ))
|
||||||
mKnownTopics.insert( topicId );
|
mKnownTopics.insert( topicId );
|
||||||
}
|
}
|
||||||
|
@ -136,7 +149,6 @@ namespace MWDialogue
|
||||||
mTalkedTo = creatureStats.hasTalkedToPlayer();
|
mTalkedTo = creatureStats.hasTalkedToPlayer();
|
||||||
|
|
||||||
mActorKnownTopics.clear();
|
mActorKnownTopics.clear();
|
||||||
mActorKnownTopicsFlag.clear();
|
|
||||||
|
|
||||||
//greeting
|
//greeting
|
||||||
const MWWorld::Store<ESM::Dialogue> &dialogs =
|
const MWWorld::Store<ESM::Dialogue> &dialogs =
|
||||||
|
@ -163,7 +175,7 @@ namespace MWDialogue
|
||||||
executeScript (info->mResultScript, mActor);
|
executeScript (info->mResultScript, mActor);
|
||||||
mLastTopic = it->mId;
|
mLastTopic = it->mId;
|
||||||
|
|
||||||
parseText (info->mResponse);
|
addTopicsFromText (info->mResponse);
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
@ -277,7 +289,10 @@ namespace MWDialogue
|
||||||
|
|
||||||
const ESM::Dialogue& dialogue = *dialogues.find (topic);
|
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)
|
if (info)
|
||||||
{
|
{
|
||||||
std::string title;
|
std::string title;
|
||||||
|
@ -320,7 +335,7 @@ namespace MWDialogue
|
||||||
|
|
||||||
executeScript (info->mResultScript, mActor);
|
executeScript (info->mResultScript, mActor);
|
||||||
|
|
||||||
parseText (info->mResponse);
|
addTopicsFromText (info->mResponse);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -339,7 +354,6 @@ namespace MWDialogue
|
||||||
updateGlobals();
|
updateGlobals();
|
||||||
|
|
||||||
mActorKnownTopics.clear();
|
mActorKnownTopics.clear();
|
||||||
mActorKnownTopicsFlag.clear();
|
|
||||||
|
|
||||||
const auto& dialogs = MWBase::Environment::get().getWorld()->getStore().get<ESM::Dialogue>();
|
const auto& dialogs = MWBase::Environment::get().getWorld()->getStore().get<ESM::Dialogue>();
|
||||||
|
|
||||||
|
@ -354,21 +368,41 @@ namespace MWDialogue
|
||||||
|
|
||||||
if (answer != nullptr)
|
if (answer != nullptr)
|
||||||
{
|
{
|
||||||
int flag = 0;
|
int topicFlags = 0;
|
||||||
if(!inJournal(topicId, answer->mId))
|
if(!inJournal(topicId, answer->mId))
|
||||||
{
|
{
|
||||||
// Does this dialogue contains some actor-specific answer?
|
// Does this dialogue contains some actor-specific answer?
|
||||||
if (Misc::StringUtils::ciEqual(answer->mActor, mActor.getCellRef().getRefId()))
|
if (Misc::StringUtils::ciEqual(answer->mActor, mActor.getCellRef().getRefId()))
|
||||||
flag |= MWBase::DialogueManager::TopicType::Specific;
|
topicFlags |= MWBase::DialogueManager::TopicType::Specific;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
flag |= MWBase::DialogueManager::TopicType::Exhausted;
|
topicFlags |= MWBase::DialogueManager::TopicType::Exhausted;
|
||||||
mActorKnownTopics.insert (dialog.mId);
|
mActorKnownTopics.insert (std::make_pair(dialog.mId, ActorKnownTopicInfo {topicFlags, answer}));
|
||||||
mActorKnownTopicsFlag[dialog.mId] = flag;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 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()
|
std::list<std::string> DialogueManager::getAvailableTopics()
|
||||||
|
@ -377,7 +411,7 @@ namespace MWDialogue
|
||||||
|
|
||||||
std::list<std::string> keywordList;
|
std::list<std::string> keywordList;
|
||||||
|
|
||||||
for (const std::string& topic : mActorKnownTopics)
|
for (const auto& [topic, topicInfo] : mActorKnownTopics)
|
||||||
{
|
{
|
||||||
//does the player know the topic?
|
//does the player know the topic?
|
||||||
if (mKnownTopics.count(topic))
|
if (mKnownTopics.count(topic))
|
||||||
|
@ -391,7 +425,7 @@ namespace MWDialogue
|
||||||
|
|
||||||
int DialogueManager::getTopicFlag(const std::string& topicId)
|
int DialogueManager::getTopicFlag(const std::string& topicId)
|
||||||
{
|
{
|
||||||
return mActorKnownTopicsFlag[topicId];
|
return mActorKnownTopics[topicId].mFlags;
|
||||||
}
|
}
|
||||||
|
|
||||||
void DialogueManager::keywordSelected (const std::string& keyword, ResponseCallback* callback)
|
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)
|
// Clamp permanent disposition change so that final disposition doesn't go below 0 (could happen with intimidate)
|
||||||
npcStats.setBaseDisposition(0);
|
npcStats.setBaseDisposition(0);
|
||||||
int zero = MWBase::Environment::get().getMechanicsManager()->getDerivedDisposition(mActor, false);
|
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);
|
npcStats.setBaseDisposition(disposition);
|
||||||
}
|
}
|
||||||
|
@ -444,7 +478,7 @@ namespace MWDialogue
|
||||||
if (const ESM::DialInfo *info = filter.search (*dialogue, true))
|
if (const ESM::DialInfo *info = filter.search (*dialogue, true))
|
||||||
{
|
{
|
||||||
std::string text = info->mResponse;
|
std::string text = info->mResponse;
|
||||||
parseText (text);
|
addTopicsFromText (text);
|
||||||
|
|
||||||
mChoice = -1;
|
mChoice = -1;
|
||||||
mIsInChoice = false;
|
mIsInChoice = false;
|
||||||
|
@ -579,7 +613,7 @@ namespace MWDialogue
|
||||||
{
|
{
|
||||||
const ESM::DialInfo* info = infos[0];
|
const ESM::DialInfo* info = infos[0];
|
||||||
|
|
||||||
parseText (info->mResponse);
|
addTopicsFromText (info->mResponse);
|
||||||
|
|
||||||
const MWWorld::Store<ESM::GameSetting>& gmsts =
|
const MWWorld::Store<ESM::GameSetting>& gmsts =
|
||||||
MWBase::Environment::get().getWorld()->getStore().get<ESM::GameSetting>();
|
MWBase::Environment::get().getWorld()->getStore().get<ESM::GameSetting>();
|
||||||
|
|
|
@ -10,6 +10,7 @@
|
||||||
#include <components/compiler/streamerrorhandler.hpp>
|
#include <components/compiler/streamerrorhandler.hpp>
|
||||||
#include <components/translation/translation.hpp>
|
#include <components/translation/translation.hpp>
|
||||||
#include <components/misc/stringops.hpp>
|
#include <components/misc/stringops.hpp>
|
||||||
|
#include <components/esm/loadinfo.hpp>
|
||||||
|
|
||||||
#include "../mwworld/ptr.hpp"
|
#include "../mwworld/ptr.hpp"
|
||||||
|
|
||||||
|
@ -24,14 +25,19 @@ namespace MWDialogue
|
||||||
{
|
{
|
||||||
class DialogueManager : public MWBase::DialogueManager
|
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.
|
std::set<std::string, Misc::StringUtils::CiComp> mKnownTopics;// Those are the topics the player knows.
|
||||||
|
|
||||||
// Modified faction reactions. <Faction1, <Faction2, Difference> >
|
// Modified faction reactions. <Faction1, <Faction2, Difference> >
|
||||||
typedef std::map<std::string, std::map<std::string, int> > ModFactionReactionMap;
|
typedef std::map<std::string, std::map<std::string, int> > ModFactionReactionMap;
|
||||||
ModFactionReactionMap mChangedFactionReaction;
|
ModFactionReactionMap mChangedFactionReaction;
|
||||||
|
|
||||||
std::set<std::string, Misc::StringUtils::CiComp> mActorKnownTopics;
|
std::map<std::string, ActorKnownTopicInfo, Misc::StringUtils::CiComp> mActorKnownTopics;
|
||||||
std::unordered_map<std::string, int> mActorKnownTopicsFlag;
|
|
||||||
|
|
||||||
Translation::Storage& mTranslationDataStorage;
|
Translation::Storage& mTranslationDataStorage;
|
||||||
MWScript::CompilerContext mCompilerContext;
|
MWScript::CompilerContext mCompilerContext;
|
||||||
|
@ -51,7 +57,8 @@ namespace MWDialogue
|
||||||
int mCurrentDisposition;
|
int mCurrentDisposition;
|
||||||
int mPermanentDispositionChange;
|
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 updateActorKnownTopics();
|
||||||
void updateGlobals();
|
void updateGlobals();
|
||||||
|
|
|
@ -23,7 +23,7 @@
|
||||||
|
|
||||||
bool MWDialogue::Filter::testActor (const ESM::DialInfo& info) const
|
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
|
// actor id
|
||||||
if (!info.mActor.empty())
|
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 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)
|
if (isCreature)
|
||||||
return true;
|
return true;
|
||||||
|
@ -207,7 +207,7 @@ bool MWDialogue::Filter::testFunctionLocal(const MWDialogue::SelectWrapper& sele
|
||||||
|
|
||||||
bool MWDialogue::Filter::testSelectStruct (const SelectWrapper& select) const
|
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.
|
// If the actor is a creature, we pass all conditions only applicable to NPCs.
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
|
@ -452,7 +452,7 @@ int MWDialogue::Filter::getSelectStructInteger (const SelectWrapper& select) con
|
||||||
{
|
{
|
||||||
if (target.getClass().isNpc() && target.getClass().getNpcStats(target).isWerewolf())
|
if (target.getClass().isNpc() && target.getClass().getNpcStats(target).isWerewolf())
|
||||||
return 2;
|
return 2;
|
||||||
if (target.getTypeName() == typeid(ESM::Creature).name())
|
if (target.getType() == ESM::Creature::sRecordId)
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -30,7 +30,7 @@ public:
|
||||||
{
|
{
|
||||||
if (keyword.empty())
|
if (keyword.empty())
|
||||||
return;
|
return;
|
||||||
seed_impl (/*std::move*/ (keyword), /*std::move*/ (value), 0, mRoot);
|
seed_impl (std::move(keyword), std::move (value), 0, mRoot);
|
||||||
}
|
}
|
||||||
|
|
||||||
void clear ()
|
void clear ()
|
||||||
|
@ -39,7 +39,7 @@ public:
|
||||||
mRoot.mKeyword.clear ();
|
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 current;
|
||||||
typename Entry::childen_t::iterator next;
|
typename Entry::childen_t::iterator next;
|
||||||
|
@ -209,8 +209,8 @@ private:
|
||||||
|
|
||||||
if (j == entry.mChildren.end ())
|
if (j == entry.mChildren.end ())
|
||||||
{
|
{
|
||||||
entry.mChildren [ch].mValue = /*std::move*/ (value);
|
entry.mChildren [ch].mValue = std::move (value);
|
||||||
entry.mChildren [ch].mKeyword = /*std::move*/ (keyword);
|
entry.mChildren [ch].mKeyword = std::move (keyword);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
@ -219,22 +219,22 @@ private:
|
||||||
if (keyword == j->second.mKeyword)
|
if (keyword == j->second.mKeyword)
|
||||||
throw std::runtime_error ("duplicate keyword inserted");
|
throw std::runtime_error ("duplicate keyword inserted");
|
||||||
|
|
||||||
value_t pushValue = /*std::move*/ (j->second.mValue);
|
value_t pushValue = j->second.mValue;
|
||||||
string_t pushKeyword = /*std::move*/ (j->second.mKeyword);
|
string_t pushKeyword = j->second.mKeyword;
|
||||||
|
|
||||||
if (depth >= pushKeyword.size ())
|
if (depth >= pushKeyword.size ())
|
||||||
throw std::runtime_error ("unexpected");
|
throw std::runtime_error ("unexpected");
|
||||||
|
|
||||||
if (depth+1 < pushKeyword.size())
|
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 ();
|
j->second.mKeyword.clear ();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (depth+1 == keyword.size())
|
if (depth+1 == keyword.size())
|
||||||
j->second.mKeyword = value;
|
j->second.mKeyword = value;
|
||||||
else // depth+1 < keyword.size()
|
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)
|
for (size_t i = 0; i < mModel->getItemCount(); ++i)
|
||||||
{
|
{
|
||||||
MWWorld::Ptr item = mModel->getItem(i).mBase;
|
MWWorld::Ptr item = mModel->getItem(i).mBase;
|
||||||
if (item.getTypeName() != typeid(ESM::Ingredient).name())
|
if (item.getType() != ESM::Ingredient::sRecordId)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
itemNames.insert(item.getClass().getName(item));
|
itemNames.insert(item.getClass().getName(item));
|
||||||
|
|
|
@ -8,7 +8,7 @@
|
||||||
#include "MyGUI_FactoryManager.h"
|
#include "MyGUI_FactoryManager.h"
|
||||||
|
|
||||||
#include <components/misc/utf8stream.hpp>
|
#include <components/misc/utf8stream.hpp>
|
||||||
#include <components/sceneutil/util.hpp>
|
#include <components/sceneutil/depth.hpp>
|
||||||
|
|
||||||
#include "../mwbase/environment.hpp"
|
#include "../mwbase/environment.hpp"
|
||||||
#include "../mwbase/windowmanager.hpp"
|
#include "../mwbase/windowmanager.hpp"
|
||||||
|
@ -1221,7 +1221,7 @@ public:
|
||||||
|
|
||||||
RenderXform renderXform (mCroppedParent, textFormat.mRenderItem->getRenderTarget()->getInfo());
|
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),
|
GlyphStream glyphStream(textFormat.mFont, static_cast<float>(mCoord.left), static_cast<float>(mCoord.top - mViewTop),
|
||||||
z /*mNode->getNodeDepth()*/, vertices, renderXform);
|
z /*mNode->getNodeDepth()*/, vertices, renderXform);
|
||||||
|
|
|
@ -38,6 +38,7 @@ namespace MWGui
|
||||||
, mSortModel(nullptr)
|
, mSortModel(nullptr)
|
||||||
, mModel(nullptr)
|
, mModel(nullptr)
|
||||||
, mSelectedItem(-1)
|
, mSelectedItem(-1)
|
||||||
|
, mTreatNextOpenAsLoot(false)
|
||||||
{
|
{
|
||||||
getWidget(mDisposeCorpseButton, "DisposeCorpseButton");
|
getWidget(mDisposeCorpseButton, "DisposeCorpseButton");
|
||||||
getWidget(mTakeButton, "TakeButton");
|
getWidget(mTakeButton, "TakeButton");
|
||||||
|
@ -121,13 +122,15 @@ namespace MWGui
|
||||||
|
|
||||||
void ContainerWindow::setPtr(const MWWorld::Ptr& container)
|
void ContainerWindow::setPtr(const MWWorld::Ptr& container)
|
||||||
{
|
{
|
||||||
|
bool lootAnyway = mTreatNextOpenAsLoot;
|
||||||
|
mTreatNextOpenAsLoot = false;
|
||||||
mPtr = container;
|
mPtr = container;
|
||||||
|
|
||||||
bool loot = mPtr.getClass().isActor() && mPtr.getClass().getCreatureStats(mPtr).isDead();
|
bool loot = mPtr.getClass().isActor() && mPtr.getClass().getCreatureStats(mPtr).isDead();
|
||||||
|
|
||||||
if (mPtr.getClass().hasInventoryStore(mPtr))
|
if (mPtr.getClass().hasInventoryStore(mPtr))
|
||||||
{
|
{
|
||||||
if (mPtr.getClass().isNpc() && !loot)
|
if (mPtr.getClass().isNpc() && !loot && !lootAnyway)
|
||||||
{
|
{
|
||||||
// we are stealing stuff
|
// we are stealing stuff
|
||||||
mModel = new PickpocketItemModel(mPtr, new InventoryItemModel(container),
|
mModel = new PickpocketItemModel(mPtr, new InventoryItemModel(container),
|
||||||
|
|
|
@ -37,6 +37,7 @@ namespace MWGui
|
||||||
|
|
||||||
void onDeleteCustomData(const MWWorld::Ptr& ptr) override;
|
void onDeleteCustomData(const MWWorld::Ptr& ptr) override;
|
||||||
|
|
||||||
|
void treatNextOpenAsLoot() { mTreatNextOpenAsLoot = true; };
|
||||||
private:
|
private:
|
||||||
DragAndDrop* mDragAndDrop;
|
DragAndDrop* mDragAndDrop;
|
||||||
|
|
||||||
|
@ -44,7 +45,7 @@ namespace MWGui
|
||||||
SortFilterItemModel* mSortModel;
|
SortFilterItemModel* mSortModel;
|
||||||
ItemModel* mModel;
|
ItemModel* mModel;
|
||||||
int mSelectedItem;
|
int mSelectedItem;
|
||||||
|
bool mTreatNextOpenAsLoot;
|
||||||
MyGUI::Button* mDisposeCorpseButton;
|
MyGUI::Button* mDisposeCorpseButton;
|
||||||
MyGUI::Button* mTakeButton;
|
MyGUI::Button* mTakeButton;
|
||||||
MyGUI::Button* mCloseButton;
|
MyGUI::Button* mCloseButton;
|
||||||
|
|
|
@ -209,7 +209,7 @@ bool ContainerItemModel::onDropItem(const MWWorld::Ptr &item, int count)
|
||||||
|
|
||||||
MWWorld::Ptr target = mItemSources[0].first;
|
MWWorld::Ptr target = mItemSources[0].first;
|
||||||
|
|
||||||
if (target.getTypeName() != typeid(ESM::Container).name())
|
if (target.getType() != ESM::Container::sRecordId)
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
// check container organic flag
|
// check container organic flag
|
||||||
|
|
|
@ -347,8 +347,7 @@ namespace MWGui
|
||||||
{
|
{
|
||||||
if (!mScrollBar->getVisible())
|
if (!mScrollBar->getVisible())
|
||||||
return;
|
return;
|
||||||
mScrollBar->setScrollPosition(std::min(static_cast<int>(mScrollBar->getScrollRange()-1),
|
mScrollBar->setScrollPosition(std::clamp<int>(mScrollBar->getScrollPosition() - _rel*0.3, 0, mScrollBar->getScrollRange() - 1));
|
||||||
std::max(0, static_cast<int>(mScrollBar->getScrollPosition() - _rel*0.3))));
|
|
||||||
onScrollbarMoved(mScrollBar, mScrollBar->getScrollPosition());
|
onScrollbarMoved(mScrollBar, mScrollBar->getScrollPosition());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -508,13 +507,13 @@ namespace MWGui
|
||||||
|
|
||||||
int services = mPtr.getClass().getServices(mPtr);
|
int services = mPtr.getClass().getServices(mPtr);
|
||||||
|
|
||||||
bool travel = (mPtr.getTypeName() == typeid(ESM::NPC).name() && !mPtr.get<ESM::NPC>()->mBase->getTransport().empty())
|
bool travel = (mPtr.getType() == ESM::NPC::sRecordId && !mPtr.get<ESM::NPC>()->mBase->getTransport().empty())
|
||||||
|| (mPtr.getTypeName() == typeid(ESM::Creature).name() && !mPtr.get<ESM::Creature>()->mBase->getTransport().empty());
|
|| (mPtr.getType() == ESM::Creature::sRecordId && !mPtr.get<ESM::Creature>()->mBase->getTransport().empty());
|
||||||
|
|
||||||
const MWWorld::Store<ESM::GameSetting> &gmst =
|
const MWWorld::Store<ESM::GameSetting> &gmst =
|
||||||
MWBase::Environment::get().getWorld()->getStore().get<ESM::GameSetting>();
|
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());
|
mTopicsList->addItem(gmst.find("sPersuasion")->mValue.getString());
|
||||||
|
|
||||||
if (services & ESM::NPC::AllItems)
|
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()));
|
mEnchantmentPoints->setCaption(std::to_string(static_cast<int>(mEnchanting.getEnchantPoints(false))) + " / " + std::to_string(mEnchanting.getMaxEnchantValue()));
|
||||||
mCharge->setCaption(std::to_string(mEnchanting.getGemCharge()));
|
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()));
|
mCastCost->setCaption(std::to_string(mEnchanting.getEffectiveCastCost()));
|
||||||
mPrice->setCaption(std::to_string(mEnchanting.getEnchantPrice()));
|
mPrice->setCaption(std::to_string(mEnchanting.getEnchantPrice()));
|
||||||
|
|
||||||
|
|
|
@ -81,7 +81,7 @@ namespace MWGui
|
||||||
, mMinimap(nullptr)
|
, mMinimap(nullptr)
|
||||||
, mCrosshair(nullptr)
|
, mCrosshair(nullptr)
|
||||||
, mCellNameBox(nullptr)
|
, mCellNameBox(nullptr)
|
||||||
, mDrowningFrame(nullptr)
|
, mDrowningBar(nullptr)
|
||||||
, mDrowningFlash(nullptr)
|
, mDrowningFlash(nullptr)
|
||||||
, mHealthManaStaminaBaseLeft(0)
|
, mHealthManaStaminaBaseLeft(0)
|
||||||
, mWeapBoxBaseLeft(0)
|
, mWeapBoxBaseLeft(0)
|
||||||
|
@ -119,6 +119,7 @@ namespace MWGui
|
||||||
fatigueFrame->eventMouseButtonClick += MyGUI::newDelegate(this, &HUD::onHMSClicked);
|
fatigueFrame->eventMouseButtonClick += MyGUI::newDelegate(this, &HUD::onHMSClicked);
|
||||||
|
|
||||||
//Drowning bar
|
//Drowning bar
|
||||||
|
getWidget(mDrowningBar, "DrowningBar");
|
||||||
getWidget(mDrowningFrame, "DrowningFrame");
|
getWidget(mDrowningFrame, "DrowningFrame");
|
||||||
getWidget(mDrowning, "Drowning");
|
getWidget(mDrowning, "Drowning");
|
||||||
getWidget(mDrowningFlash, "Flash");
|
getWidget(mDrowningFlash, "Flash");
|
||||||
|
@ -224,7 +225,7 @@ namespace MWGui
|
||||||
|
|
||||||
void HUD::setDrowningBarVisible(bool visible)
|
void HUD::setDrowningBarVisible(bool visible)
|
||||||
{
|
{
|
||||||
mDrowningFrame->setVisible(visible);
|
mDrowningBar->setVisible(visible);
|
||||||
}
|
}
|
||||||
|
|
||||||
void HUD::onWorldClicked(MyGUI::Widget* _sender)
|
void HUD::onWorldClicked(MyGUI::Widget* _sender)
|
||||||
|
@ -368,9 +369,6 @@ namespace MWGui
|
||||||
mWeaponSpellBox->setPosition(mWeaponSpellBox->getPosition() + MyGUI::IntPoint(0,20));
|
mWeaponSpellBox->setPosition(mWeaponSpellBox->getPosition() + MyGUI::IntPoint(0,20));
|
||||||
}
|
}
|
||||||
|
|
||||||
if (mIsDrowning)
|
|
||||||
mDrowningFlashTheta += dt * osg::PI*2;
|
|
||||||
|
|
||||||
mSpellIcons->updateWidgets(mEffectBox, true);
|
mSpellIcons->updateWidgets(mEffectBox, true);
|
||||||
|
|
||||||
if (mEnemyActorId != -1 && mEnemyHealth->getVisible())
|
if (mEnemyActorId != -1 && mEnemyHealth->getVisible())
|
||||||
|
@ -378,8 +376,13 @@ namespace MWGui
|
||||||
updateEnemyHealthBar();
|
updateEnemyHealthBar();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (mDrowningBar->getVisible())
|
||||||
|
mDrowningBar->setPosition(mMainWidget->getWidth()/2 - mDrowningFrame->getWidth()/2, mMainWidget->getTop());
|
||||||
|
|
||||||
if (mIsDrowning)
|
if (mIsDrowning)
|
||||||
{
|
{
|
||||||
|
mDrowningFlashTheta += dt * osg::PI*2;
|
||||||
|
|
||||||
float intensity = (cos(mDrowningFlashTheta) + 2.0f) / 3.0f;
|
float intensity = (cos(mDrowningFlashTheta) + 2.0f) / 3.0f;
|
||||||
|
|
||||||
mDrowningFlash->setAlpha(intensity);
|
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();
|
static const float fNPCHealthBarFade = MWBase::Environment::get().getWorld()->getStore().get<ESM::GameSetting>().find("fNPCHealthBarFade")->mValue.getFloat();
|
||||||
if (fNPCHealthBarFade > 0.f)
|
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::ImageBox* mCrosshair;
|
||||||
MyGUI::TextBox* mCellNameBox;
|
MyGUI::TextBox* mCellNameBox;
|
||||||
MyGUI::TextBox* mWeaponSpellBox;
|
MyGUI::TextBox* mWeaponSpellBox;
|
||||||
MyGUI::Widget *mDrowningFrame, *mDrowningFlash;
|
MyGUI::Widget *mDrowningBar, *mDrowningFrame, *mDrowningFlash;
|
||||||
|
|
||||||
// bottom left elements
|
// bottom left elements
|
||||||
int mHealthManaStaminaBaseLeft, mWeapBoxBaseLeft, mSpellBoxBaseLeft, mSneakBoxBaseLeft;
|
int mHealthManaStaminaBaseLeft, mWeapBoxBaseLeft, mSpellBoxBaseLeft, mSneakBoxBaseLeft;
|
||||||
|
|
|
@ -46,7 +46,7 @@ namespace
|
||||||
|
|
||||||
bool isRightHandWeapon(const MWWorld::Ptr& item)
|
bool isRightHandWeapon(const MWWorld::Ptr& item)
|
||||||
{
|
{
|
||||||
if (item.getClass().getTypeName() != typeid(ESM::Weapon).name())
|
if (item.getClass().getType() != ESM::Weapon::sRecordId)
|
||||||
return false;
|
return false;
|
||||||
std::vector<int> equipmentSlots = item.getClass().getEquipmentSlots(item).first;
|
std::vector<int> equipmentSlots = item.getClass().getEquipmentSlots(item).first;
|
||||||
return (!equipmentSlots.empty() && equipmentSlots.front() == MWWorld::InventoryStore::Slot_CarriedRight);
|
return (!equipmentSlots.empty() && equipmentSlots.front() == MWWorld::InventoryStore::Slot_CarriedRight);
|
||||||
|
@ -70,7 +70,7 @@ namespace MWGui
|
||||||
, mTrading(false)
|
, mTrading(false)
|
||||||
, mUpdateTimer(0.f)
|
, mUpdateTimer(0.f)
|
||||||
{
|
{
|
||||||
mPreviewTexture.reset(new osgMyGUI::OSGTexture(mPreview->getTexture()));
|
mPreviewTexture.reset(new osgMyGUI::OSGTexture(mPreview->getTexture(), mPreview->getTextureStateSet()));
|
||||||
mPreview->rebuild();
|
mPreview->rebuild();
|
||||||
|
|
||||||
mMainWidget->castType<MyGUI::Window>()->eventWindowChangeCoord += MyGUI::newDelegate(this, &InventoryWindow::onWindowResize);
|
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 we unequip weapon during attack, it can lead to unexpected behaviour
|
||||||
if (MWBase::Environment::get().getMechanicsManager()->isAttackingOrSpell(mPtr))
|
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);
|
MWWorld::InventoryStore& invStore = mPtr.getClass().getInventoryStore(mPtr);
|
||||||
|
|
||||||
if (isWeapon && invStore.isEquipped(item.mBase))
|
if (isWeapon && invStore.isEquipped(item.mBase))
|
||||||
|
@ -555,9 +555,9 @@ namespace MWGui
|
||||||
if (!script.empty())
|
if (!script.empty())
|
||||||
{
|
{
|
||||||
// Ingredients, books and repair hammers must not have OnPCEquip set to 1 here
|
// Ingredients, books and repair hammers must not have OnPCEquip set to 1 here
|
||||||
const std::string& type = ptr.getTypeName();
|
auto type = ptr.getType();
|
||||||
bool isBook = type == typeid(ESM::Book).name();
|
bool isBook = type == ESM::Book::sRecordId;
|
||||||
if (!isBook && type != typeid(ESM::Ingredient).name() && type != typeid(ESM::Repair).name())
|
if (!isBook && type != ESM::Ingredient::sRecordId && type != ESM::Repair::sRecordId)
|
||||||
ptr.getRefData().getLocals().setVarByInt(script, "onpcequip", 1);
|
ptr.getRefData().getLocals().setVarByInt(script, "onpcequip", 1);
|
||||||
// Books must have PCSkipEquip set to 1 instead
|
// Books must have PCSkipEquip set to 1 instead
|
||||||
else if (isBook)
|
else if (isBook)
|
||||||
|
@ -593,8 +593,8 @@ namespace MWGui
|
||||||
useItem(ptr);
|
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 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() ||
|
if ((ptr.getType() == ESM::Potion::sRecordId ||
|
||||||
ptr.getTypeName() == typeid(ESM::Ingredient).name())
|
ptr.getType() == ESM::Ingredient::sRecordId)
|
||||||
&& mDragAndDrop->mDraggedCount > 1)
|
&& mDragAndDrop->mDraggedCount > 1)
|
||||||
{
|
{
|
||||||
// Item can be provided from other window for example container.
|
// Item can be provided from other window for example container.
|
||||||
|
@ -704,19 +704,19 @@ namespace MWGui
|
||||||
if (!MWBase::Environment::get().getWindowManager()->isAllowed(GW_Inventory))
|
if (!MWBase::Environment::get().getWindowManager()->isAllowed(GW_Inventory))
|
||||||
return;
|
return;
|
||||||
// make sure the object is of a type that can be picked up
|
// make sure the object is of a type that can be picked up
|
||||||
const std::string& type = object.getTypeName();
|
auto type = object.getType();
|
||||||
if ( (type != typeid(ESM::Apparatus).name())
|
if ( (type != ESM::Apparatus::sRecordId)
|
||||||
&& (type != typeid(ESM::Armor).name())
|
&& (type != ESM::Armor::sRecordId)
|
||||||
&& (type != typeid(ESM::Book).name())
|
&& (type != ESM::Book::sRecordId)
|
||||||
&& (type != typeid(ESM::Clothing).name())
|
&& (type != ESM::Clothing::sRecordId)
|
||||||
&& (type != typeid(ESM::Ingredient).name())
|
&& (type != ESM::Ingredient::sRecordId)
|
||||||
&& (type != typeid(ESM::Light).name())
|
&& (type != ESM::Light::sRecordId)
|
||||||
&& (type != typeid(ESM::Miscellaneous).name())
|
&& (type != ESM::Miscellaneous::sRecordId)
|
||||||
&& (type != typeid(ESM::Lockpick).name())
|
&& (type != ESM::Lockpick::sRecordId)
|
||||||
&& (type != typeid(ESM::Probe).name())
|
&& (type != ESM::Probe::sRecordId)
|
||||||
&& (type != typeid(ESM::Repair).name())
|
&& (type != ESM::Repair::sRecordId)
|
||||||
&& (type != typeid(ESM::Weapon).name())
|
&& (type != ESM::Weapon::sRecordId)
|
||||||
&& (type != typeid(ESM::Potion).name()))
|
&& (type != ESM::Potion::sRecordId))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
// An object that can be picked up must have a tooltip.
|
// An object that can be picked up must have a tooltip.
|
||||||
|
@ -809,7 +809,7 @@ namespace MWGui
|
||||||
|
|
||||||
lastId = item.getCellRef().getRefId();
|
lastId = item.getCellRef().getRefId();
|
||||||
|
|
||||||
if (item.getClass().getTypeName() == typeid(ESM::Weapon).name() &&
|
if (item.getClass().getType() == ESM::Weapon::sRecordId &&
|
||||||
isRightHandWeapon(item) &&
|
isRightHandWeapon(item) &&
|
||||||
item.getClass().canBeEquipped(item, player).first)
|
item.getClass().canBeEquipped(item, player).first)
|
||||||
{
|
{
|
||||||
|
|
|
@ -313,9 +313,9 @@ struct JournalViewModelImpl : JournalViewModel
|
||||||
for (MWBase::Journal::TTopicIter i = journal->topicBegin (); i != journal->topicEnd (); ++i)
|
for (MWBase::Journal::TTopicIter i = journal->topicBegin (); i != journal->topicEnd (); ++i)
|
||||||
{
|
{
|
||||||
Utf8Stream stream (i->first.c_str());
|
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;
|
continue;
|
||||||
|
|
||||||
visitor (i->second.getName());
|
visitor (i->second.getName());
|
||||||
|
|
|
@ -79,7 +79,7 @@ void KeyboardNavigation::restoreFocus(int mode)
|
||||||
if (found != mKeyFocus.end())
|
if (found != mKeyFocus.end())
|
||||||
{
|
{
|
||||||
MyGUI::Widget* w = found->second;
|
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);
|
MWBase::Environment::get().getWindowManager()->setKeyFocusWidget(found->second);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -273,7 +273,7 @@ bool KeyboardNavigation::switchFocus(int direction, bool wrap)
|
||||||
if (wrap)
|
if (wrap)
|
||||||
index = (index + keyFocusList.size())%keyFocusList.size();
|
index = (index + keyFocusList.size())%keyFocusList.size();
|
||||||
else
|
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];
|
MyGUI::Widget* next = keyFocusList[index];
|
||||||
int vertdiff = next->getTop() - focus->getTop();
|
int vertdiff = next->getTop() - focus->getTop();
|
||||||
|
|
|
@ -4,6 +4,8 @@
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
#include <memory>
|
#include <memory>
|
||||||
|
|
||||||
|
#include <osg/Vec2f>
|
||||||
|
|
||||||
#include "windowpinnablebase.hpp"
|
#include "windowpinnablebase.hpp"
|
||||||
|
|
||||||
#include <components/esm/cellid.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