mirror of
https://github.com/OpenMW/openmw.git
synced 2025-06-07 01:11:32 +00:00
Merge branch 'master' of gitlab.com:openmw/openmw into fix_global_iteration
This commit is contained in:
commit
8b75932f50
300 changed files with 4597 additions and 2004 deletions
|
@ -210,6 +210,7 @@ Ubuntu_GCC_Debug:
|
||||||
CCACHE_SIZE: 3G
|
CCACHE_SIZE: 3G
|
||||||
CMAKE_BUILD_TYPE: Debug
|
CMAKE_BUILD_TYPE: Debug
|
||||||
CMAKE_CXX_FLAGS_DEBUG: -O0
|
CMAKE_CXX_FLAGS_DEBUG: -O0
|
||||||
|
BUILD_SHARED_LIBS: 1
|
||||||
# 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
|
||||||
|
|
||||||
|
@ -520,13 +521,13 @@ Ubuntu_GCC_integration_tests_asan:
|
||||||
- build/OpenMW-*.dmg
|
- build/OpenMW-*.dmg
|
||||||
- "build/**/*.log"
|
- "build/**/*.log"
|
||||||
|
|
||||||
macOS13_Xcode14_arm64:
|
macOS14_Xcode15_arm64:
|
||||||
extends: .MacOS
|
extends: .MacOS
|
||||||
image: macos-12-xcode-14
|
image: macos-14-xcode-15
|
||||||
tags:
|
tags:
|
||||||
- saas-macos-medium-m1
|
- saas-macos-medium-m1
|
||||||
cache:
|
cache:
|
||||||
key: macOS12_Xcode14_arm64.v4
|
key: macOS14_Xcode15_arm64.v1
|
||||||
variables:
|
variables:
|
||||||
CCACHE_SIZE: 3G
|
CCACHE_SIZE: 3G
|
||||||
|
|
||||||
|
@ -575,7 +576,7 @@ macOS13_Xcode14_arm64:
|
||||||
- cd MSVC2019_64_Ninja
|
- cd MSVC2019_64_Ninja
|
||||||
- .\ActivateMSVC.ps1
|
- .\ActivateMSVC.ps1
|
||||||
- cmake --build . --config $config
|
- cmake --build . --config $config
|
||||||
- ccache --show-stats
|
- ccache --show-stats -v
|
||||||
- cd $config
|
- cd $config
|
||||||
- echo "CI_COMMIT_REF_NAME ${CI_COMMIT_REF_NAME}`nCI_JOB_ID ${CI_JOB_ID}`nCI_COMMIT_SHA ${CI_COMMIT_SHA}" | Out-File -Encoding UTF8 CI-ID.txt
|
- echo "CI_COMMIT_REF_NAME ${CI_COMMIT_REF_NAME}`nCI_JOB_ID ${CI_JOB_ID}`nCI_COMMIT_SHA ${CI_COMMIT_SHA}" | Out-File -Encoding UTF8 CI-ID.txt
|
||||||
- $artifactDirectory = "$(Make-SafeFileName("${CI_PROJECT_NAMESPACE}"))/$(Make-SafeFileName("${CI_COMMIT_REF_NAME}"))/$(Make-SafeFileName("${CI_COMMIT_SHORT_SHA}-${CI_JOB_ID}"))/"
|
- $artifactDirectory = "$(Make-SafeFileName("${CI_PROJECT_NAMESPACE}"))/$(Make-SafeFileName("${CI_COMMIT_REF_NAME}"))/$(Make-SafeFileName("${CI_COMMIT_SHORT_SHA}-${CI_JOB_ID}"))/"
|
||||||
|
@ -665,7 +666,6 @@ macOS13_Xcode14_arm64:
|
||||||
- choco source disable -n=chocolatey
|
- choco source disable -n=chocolatey
|
||||||
- choco install git --force --params "/GitAndUnixToolsOnPath" -y
|
- choco install git --force --params "/GitAndUnixToolsOnPath" -y
|
||||||
- choco install 7zip -y
|
- choco install 7zip -y
|
||||||
- choco install ccache -y
|
|
||||||
- choco install vswhere -y
|
- choco install vswhere -y
|
||||||
- choco install python -y
|
- choco install python -y
|
||||||
- choco install awscli -y
|
- choco install awscli -y
|
||||||
|
@ -688,15 +688,11 @@ macOS13_Xcode14_arm64:
|
||||||
- $time = (Get-Date -Format "HH:mm:ss")
|
- $time = (Get-Date -Format "HH:mm:ss")
|
||||||
- echo ${time}
|
- echo ${time}
|
||||||
- echo "started by ${GITLAB_USER_NAME}"
|
- echo "started by ${GITLAB_USER_NAME}"
|
||||||
- $env:CCACHE_BASEDIR = Get-Location
|
|
||||||
- $env:CCACHE_DIR = "$(Get-Location)\ccache"
|
|
||||||
- New-Item -Type Directory -Force -Path $env:CCACHE_DIR
|
|
||||||
- New-Item -Type File -Force -Path MSVC2019_64\.cmake\api\v1\query\codemodel-v2
|
- New-Item -Type File -Force -Path MSVC2019_64\.cmake\api\v1\query\codemodel-v2
|
||||||
- sh CI/before_script.msvc.sh -c $config -p Win64 -v 2019 -k -V -b -t -C $multiview -E
|
- sh CI/before_script.msvc.sh -c $config -p Win64 -v 2019 -k -V -b -t -C $multiview -E
|
||||||
- cd MSVC2019_64
|
- cd MSVC2019_64
|
||||||
- Get-Volume
|
- Get-Volume
|
||||||
- cmake --build . --config $config
|
- cmake --build . --config $config
|
||||||
- ccache --show-stats
|
|
||||||
- cd $config
|
- cd $config
|
||||||
- echo "CI_COMMIT_REF_NAME ${CI_COMMIT_REF_NAME}`nCI_JOB_ID ${CI_JOB_ID}`nCI_COMMIT_SHA ${CI_COMMIT_SHA}" | Out-File -Encoding UTF8 CI-ID.txt
|
- echo "CI_COMMIT_REF_NAME ${CI_COMMIT_REF_NAME}`nCI_JOB_ID ${CI_JOB_ID}`nCI_COMMIT_SHA ${CI_COMMIT_SHA}" | Out-File -Encoding UTF8 CI-ID.txt
|
||||||
- $artifactDirectory = "$(Make-SafeFileName("${CI_PROJECT_NAMESPACE}"))/$(Make-SafeFileName("${CI_COMMIT_REF_NAME}"))/$(Make-SafeFileName("${CI_COMMIT_SHORT_SHA}-${CI_JOB_ID}"))/"
|
- $artifactDirectory = "$(Make-SafeFileName("${CI_PROJECT_NAMESPACE}"))/$(Make-SafeFileName("${CI_COMMIT_REF_NAME}"))/$(Make-SafeFileName("${CI_COMMIT_SHORT_SHA}-${CI_JOB_ID}"))/"
|
||||||
|
@ -728,7 +724,6 @@ macOS13_Xcode14_arm64:
|
||||||
cache:
|
cache:
|
||||||
key: msbuild-v8
|
key: msbuild-v8
|
||||||
paths:
|
paths:
|
||||||
- ccache
|
|
||||||
- deps
|
- deps
|
||||||
- MSVC2019_64/deps/Qt
|
- MSVC2019_64/deps/Qt
|
||||||
artifacts:
|
artifacts:
|
||||||
|
|
|
@ -15,6 +15,7 @@ Programmers
|
||||||
Nicolay Korslund - Project leader 2008-2010
|
Nicolay Korslund - Project leader 2008-2010
|
||||||
scrawl - Top contributor
|
scrawl - Top contributor
|
||||||
|
|
||||||
|
AbduSharif
|
||||||
Adam Hogan (aurix)
|
Adam Hogan (aurix)
|
||||||
Aesylwinn
|
Aesylwinn
|
||||||
aegis
|
aegis
|
||||||
|
@ -79,6 +80,7 @@ Programmers
|
||||||
Eduard Cot (trombonecot)
|
Eduard Cot (trombonecot)
|
||||||
Eli2
|
Eli2
|
||||||
Emanuel Guével (potatoesmaster)
|
Emanuel Guével (potatoesmaster)
|
||||||
|
Epoch
|
||||||
Eris Caffee (eris)
|
Eris Caffee (eris)
|
||||||
eroen
|
eroen
|
||||||
escondida
|
escondida
|
||||||
|
@ -187,6 +189,7 @@ Programmers
|
||||||
pkubik
|
pkubik
|
||||||
PLkolek
|
PLkolek
|
||||||
PlutonicOverkill
|
PlutonicOverkill
|
||||||
|
Qlonever
|
||||||
Radu-Marius Popovici (rpopovici)
|
Radu-Marius Popovici (rpopovici)
|
||||||
Rafael Moura (dhustkoder)
|
Rafael Moura (dhustkoder)
|
||||||
Randy Davin (Kindi)
|
Randy Davin (Kindi)
|
||||||
|
|
30
CHANGELOG.md
30
CHANGELOG.md
|
@ -26,12 +26,15 @@
|
||||||
Bug #5371: Keyframe animation tracks are used for any file that begins with an X
|
Bug #5371: Keyframe animation tracks are used for any file that begins with an X
|
||||||
Bug #5413: Enemies do a battlecry everytime the player summons a creature
|
Bug #5413: Enemies do a battlecry everytime the player summons a creature
|
||||||
Bug #5714: Touch spells cast using ExplodeSpell don't always explode
|
Bug #5714: Touch spells cast using ExplodeSpell don't always explode
|
||||||
|
Bug #5755: Reset friendly hit counter
|
||||||
Bug #5849: Paralysis breaks landing
|
Bug #5849: Paralysis breaks landing
|
||||||
Bug #5870: Disposing of actors who were selected in the console doesn't deselect them like vanilla
|
Bug #5870: Disposing of actors who were selected in the console doesn't deselect them like vanilla
|
||||||
Bug #5883: Immobile creatures don't cause water ripples
|
Bug #5883: Immobile creatures don't cause water ripples
|
||||||
Bug #5977: Fatigueless NPCs' corpse underwater changes animation on game load
|
Bug #5977: Fatigueless NPCs' corpse underwater changes animation on game load
|
||||||
Bug #6025: Subrecords cannot overlap records
|
Bug #6025: Subrecords cannot overlap records
|
||||||
Bug #6027: Collisionshape becomes spiderweb-like when the mesh is too complex
|
Bug #6027: Collisionshape becomes spiderweb-like when the mesh is too complex
|
||||||
|
Bug #6146: Lua command `actor:setEquipment` doesn't trigger mwscripts when equipping or unequipping a scripted item
|
||||||
|
Bug #6156: 1ft Charm or Sound magic effect vfx doesn't work properly
|
||||||
Bug #6190: Unintuitive sun specularity time of day dependence
|
Bug #6190: Unintuitive sun specularity time of day dependence
|
||||||
Bug #6222: global map cell size can crash openmw if set to too high a value
|
Bug #6222: global map cell size can crash openmw if set to too high a value
|
||||||
Bug #6313: Followers with high Fight can turn hostile
|
Bug #6313: Followers with high Fight can turn hostile
|
||||||
|
@ -55,6 +58,7 @@
|
||||||
Bug #6973: Fade in happens after the scene load and is shown
|
Bug #6973: Fade in happens after the scene load and is shown
|
||||||
Bug #6974: Only harmful effects are reflected
|
Bug #6974: Only harmful effects are reflected
|
||||||
Bug #6977: Sun damage implementation does not match research
|
Bug #6977: Sun damage implementation does not match research
|
||||||
|
Bug #6985: Issues with Magic Cards numbers readability
|
||||||
Bug #6986: Sound magic effect does not make noise
|
Bug #6986: Sound magic effect does not make noise
|
||||||
Bug #6987: Set/Mod Blindness should not darken the screen
|
Bug #6987: Set/Mod Blindness should not darken the screen
|
||||||
Bug #6992: Crossbow reloading doesn't look the same as in Morrowind
|
Bug #6992: Crossbow reloading doesn't look the same as in Morrowind
|
||||||
|
@ -70,12 +74,15 @@
|
||||||
Bug #7084: Resurrecting an actor doesn't take into account base record changes
|
Bug #7084: Resurrecting an actor doesn't take into account base record changes
|
||||||
Bug #7088: Deleting last save game of last character doesn't clear character name/details
|
Bug #7088: Deleting last save game of last character doesn't clear character name/details
|
||||||
Bug #7092: BSA archives from higher priority directories don't take priority
|
Bug #7092: BSA archives from higher priority directories don't take priority
|
||||||
|
Bug #7102: Some HQ Creatures mod models can hit the 8 texture slots limit with 0.48
|
||||||
Bug #7103: Multiple paths pointing to the same plugin but with different cases lead to automatically removed config entries
|
Bug #7103: Multiple paths pointing to the same plugin but with different cases lead to automatically removed config entries
|
||||||
Bug #7122: Teleportation to underwater should cancel active water walking effect
|
Bug #7122: Teleportation to underwater should cancel active water walking effect
|
||||||
Bug #7131: MyGUI log spam when post processing HUD is open
|
Bug #7131: MyGUI log spam when post processing HUD is open
|
||||||
Bug #7134: Saves with an invalid last generated RefNum can be loaded
|
Bug #7134: Saves with an invalid last generated RefNum can be loaded
|
||||||
Bug #7163: Myar Aranath: Wheat breaks the GUI
|
Bug #7163: Myar Aranath: Wheat breaks the GUI
|
||||||
|
Bug #7168: Fix average scene luminance
|
||||||
Bug #7172: Current music playlist continues playing indefinitely if next playlist is empty
|
Bug #7172: Current music playlist continues playing indefinitely if next playlist is empty
|
||||||
|
Bug #7202: Post-processing normals for terrain, water randomly stop rendering
|
||||||
Bug #7204: Missing actor scripts freeze the game
|
Bug #7204: Missing actor scripts freeze the game
|
||||||
Bug #7229: Error marker loading failure is not handled
|
Bug #7229: Error marker loading failure is not handled
|
||||||
Bug #7243: Supporting loading external files from VFS from esm files
|
Bug #7243: Supporting loading external files from VFS from esm files
|
||||||
|
@ -98,6 +105,7 @@
|
||||||
Bug #7475: Equipping a constant effect item doesn't update the magic menu
|
Bug #7475: Equipping a constant effect item doesn't update the magic menu
|
||||||
Bug #7502: Data directories dialog (0.48.0) forces adding subdirectory instead of intended directory
|
Bug #7502: Data directories dialog (0.48.0) forces adding subdirectory instead of intended directory
|
||||||
Bug #7505: Distant terrain does not support sample size greater than cell size
|
Bug #7505: Distant terrain does not support sample size greater than cell size
|
||||||
|
Bug #7535: Bookart paths for textures in OpenMW vs vanilla Morrowind
|
||||||
Bug #7553: Faction reaction loading is incorrect
|
Bug #7553: Faction reaction loading is incorrect
|
||||||
Bug #7557: Terrain::ChunkManager::createChunk is called twice for the same position, lod on initial loading
|
Bug #7557: Terrain::ChunkManager::createChunk is called twice for the same position, lod on initial loading
|
||||||
Bug #7573: Drain Fatigue can't bring fatigue below zero by default
|
Bug #7573: Drain Fatigue can't bring fatigue below zero by default
|
||||||
|
@ -108,8 +116,10 @@
|
||||||
Bug #7611: Beast races' idle animations slide after turning or jumping in place
|
Bug #7611: Beast races' idle animations slide after turning or jumping in place
|
||||||
Bug #7617: The death prompt asks the player if they wanted to load the character's last created save
|
Bug #7617: The death prompt asks the player if they wanted to load the character's last created save
|
||||||
Bug #7619: Long map notes may get cut off
|
Bug #7619: Long map notes may get cut off
|
||||||
|
Bug #7623: Incorrect placement of the script info in the engraved ring of healing tooltip
|
||||||
Bug #7630: Charm can be cast on creatures
|
Bug #7630: Charm can be cast on creatures
|
||||||
Bug #7631: Cannot trade with/talk to Creeper or Mudcrab Merchant when they're fleeing
|
Bug #7631: Cannot trade with/talk to Creeper or Mudcrab Merchant when they're fleeing
|
||||||
|
Bug #7633: Groundcover should ignore non-geometry Drawables
|
||||||
Bug #7636: Animations bug out when switching between 1st and 3rd person, while playing a scripted animation
|
Bug #7636: Animations bug out when switching between 1st and 3rd person, while playing a scripted animation
|
||||||
Bug #7637: Actors can sometimes move while playing scripted animations
|
Bug #7637: Actors can sometimes move while playing scripted animations
|
||||||
Bug #7639: NPCs don't use hand-to-hand if their other melee skills were damaged during combat
|
Bug #7639: NPCs don't use hand-to-hand if their other melee skills were damaged during combat
|
||||||
|
@ -127,30 +137,41 @@
|
||||||
Bug #7679: Scene luminance value flashes when toggling shaders
|
Bug #7679: Scene luminance value flashes when toggling shaders
|
||||||
Bug #7685: Corky sometimes doesn't follow Llovyn Andus
|
Bug #7685: Corky sometimes doesn't follow Llovyn Andus
|
||||||
Bug #7712: Casting doesn't support spells and enchantments with no effects
|
Bug #7712: Casting doesn't support spells and enchantments with no effects
|
||||||
|
Bug #7721: CS: Special Chars Not Allowed in IDs
|
||||||
Bug #7723: Assaulting vampires and werewolves shouldn't be a crime
|
Bug #7723: Assaulting vampires and werewolves shouldn't be a crime
|
||||||
Bug #7724: Guards don't help vs werewolves
|
Bug #7724: Guards don't help vs werewolves
|
||||||
Bug #7733: Launcher shows incorrect data paths when there's two plugins with the same name
|
Bug #7733: Launcher shows incorrect data paths when there's two plugins with the same name
|
||||||
Bug #7742: Governing attribute training limit should use the modified attribute
|
Bug #7742: Governing attribute training limit should use the modified attribute
|
||||||
|
Bug #7753: Editor: Actors Don't Scale According to Their Race
|
||||||
Bug #7758: Water walking is not taken into account to compute path cost on the water
|
Bug #7758: Water walking is not taken into account to compute path cost on the water
|
||||||
Bug #7761: Rain and ambient loop sounds are mutually exclusive
|
Bug #7761: Rain and ambient loop sounds are mutually exclusive
|
||||||
|
Bug #7763: Bullet shape loading problems, assorted
|
||||||
Bug #7765: OpenMW-CS: Touch Record option is broken
|
Bug #7765: OpenMW-CS: Touch Record option is broken
|
||||||
Bug #7769: Sword of the Perithia: Broken NPCs
|
Bug #7769: Sword of the Perithia: Broken NPCs
|
||||||
Bug #7770: Sword of the Perithia: Script execution failure
|
Bug #7770: Sword of the Perithia: Script execution failure
|
||||||
Bug #7780: Non-ASCII texture paths in NIF files don't work
|
Bug #7780: Non-ASCII texture paths in NIF files don't work
|
||||||
Bug #7785: OpenMW-CS initialising Skill and Attribute fields to 0 instead of -1 on non-FortifyStat spells
|
Bug #7785: OpenMW-CS initialising Skill and Attribute fields to 0 instead of -1 on non-FortifyStat spells
|
||||||
|
Bug #7794: Fleeing NPCs name tooltip doesn't appear
|
||||||
Bug #7796: Absorbed enchantments don't restore magicka
|
Bug #7796: Absorbed enchantments don't restore magicka
|
||||||
|
Bug #7832: Ingredient tooltips show magnitude for Fortify Maximum Magicka effect
|
||||||
|
Bug #7840: First run of the launcher doesn't save viewing distance as the default value
|
||||||
|
Bug #7841: Editor: "Dirty" water heights are saved in modified CELLs
|
||||||
|
Bug #7859: AutoCalc flag is not used to calculate potion value
|
||||||
Feature #2566: Handle NAM9 records for manual cell references
|
Feature #2566: Handle NAM9 records for manual cell references
|
||||||
Feature #3537: Shader-based water ripples
|
Feature #3537: Shader-based water ripples
|
||||||
Feature #5173: Support for NiFogProperty
|
Feature #5173: Support for NiFogProperty
|
||||||
Feature #5492: Let rain and snow collide with statics
|
Feature #5492: Let rain and snow collide with statics
|
||||||
Feature #6149: Dehardcode Lua API_REVISION
|
Feature #5926: Refraction based on water depth
|
||||||
|
Feature #5944: Option to use camera as sound listener
|
||||||
Feature #6152: Playing music via lua scripts
|
Feature #6152: Playing music via lua scripts
|
||||||
Feature #6188: Specular lighting from point light sources
|
Feature #6188: Specular lighting from point light sources
|
||||||
Feature #6411: Support translations in openmw-launcher
|
Feature #6411: Support translations in openmw-launcher
|
||||||
Feature #6447: Add LOD support to Object Paging
|
Feature #6447: Add LOD support to Object Paging
|
||||||
Feature #6491: Add support for Qt6
|
Feature #6491: Add support for Qt6
|
||||||
Feature #6556: Lua API for sounds
|
Feature #6556: Lua API for sounds
|
||||||
|
Feature #6679: Design a custom Input Action API
|
||||||
Feature #6726: Lua API for creating new objects
|
Feature #6726: Lua API for creating new objects
|
||||||
|
Feature #6727: Lua API for records of all object types
|
||||||
Feature #6864: Lua file access API
|
Feature #6864: Lua file access API
|
||||||
Feature #6922: Improve launcher appearance
|
Feature #6922: Improve launcher appearance
|
||||||
Feature #6933: Support high-resolution cursor textures
|
Feature #6933: Support high-resolution cursor textures
|
||||||
|
@ -163,10 +184,12 @@
|
||||||
Feature #7125: Remembering console commands between sessions
|
Feature #7125: Remembering console commands between sessions
|
||||||
Feature #7129: Add support for non-adaptive VSync
|
Feature #7129: Add support for non-adaptive VSync
|
||||||
Feature #7130: Ability to set MyGUI logging verbosity
|
Feature #7130: Ability to set MyGUI logging verbosity
|
||||||
|
Feature #7142: MWScript Lua API
|
||||||
Feature #7148: Optimize string literal lookup in mwscript
|
Feature #7148: Optimize string literal lookup in mwscript
|
||||||
|
Feature #7161: OpenMW-CS: Make adding and filtering TopicInfos easier
|
||||||
Feature #7194: Ori to show texture paths
|
Feature #7194: Ori to show texture paths
|
||||||
Feature #7214: Searching in the in-game console
|
Feature #7214: Searching in the in-game console
|
||||||
Feature #7284: Searching in the console with regex and toggleable case-sensitivity
|
Feature #7248: Searching in the console with regex and toggleable case-sensitivity
|
||||||
Feature #7468: Factions API for Lua
|
Feature #7468: Factions API for Lua
|
||||||
Feature #7477: NegativeLight Magic Effect flag
|
Feature #7477: NegativeLight Magic Effect flag
|
||||||
Feature #7499: OpenMW-CS: Generate record filters by drag & dropping cell content to the filters field
|
Feature #7499: OpenMW-CS: Generate record filters by drag & dropping cell content to the filters field
|
||||||
|
@ -186,7 +209,10 @@
|
||||||
Feature #7795: Support MaxNumberRipples INI setting
|
Feature #7795: Support MaxNumberRipples INI setting
|
||||||
Feature #7805: Lua Menu context
|
Feature #7805: Lua Menu context
|
||||||
Task #5896: Do not use deprecated MyGUI properties
|
Task #5896: Do not use deprecated MyGUI properties
|
||||||
|
Task #6085: Replace boost::filesystem with std::filesystem
|
||||||
|
Task #6149: Dehardcode Lua API_REVISION
|
||||||
Task #6624: Drop support for saves made prior to 0.45
|
Task #6624: Drop support for saves made prior to 0.45
|
||||||
|
Task #7048: Get rid of std::bind
|
||||||
Task #7113: Move from std::atoi to std::from_char
|
Task #7113: Move from std::atoi to std::from_char
|
||||||
Task #7117: Replace boost::scoped_array with std::vector
|
Task #7117: Replace boost::scoped_array with std::vector
|
||||||
Task #7151: Do not use std::strerror to get errno error message
|
Task #7151: Do not use std::strerror to get errno error message
|
||||||
|
|
|
@ -22,7 +22,7 @@ declare -a CMAKE_CONF_OPTS=(
|
||||||
-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
|
||||||
-DBUILD_SHARED_LIBS=OFF
|
-DBUILD_SHARED_LIBS="${BUILD_SHARED_LIBS:-OFF}"
|
||||||
-DUSE_SYSTEM_TINYXML=ON
|
-DUSE_SYSTEM_TINYXML=ON
|
||||||
-DOPENMW_USE_SYSTEM_RECASTNAVIGATION=ON
|
-DOPENMW_USE_SYSTEM_RECASTNAVIGATION=ON
|
||||||
-DOPENMW_CXX_FLAGS="-Werror -Werror=implicit-fallthrough" # flags specific to OpenMW project
|
-DOPENMW_CXX_FLAGS="-Werror -Werror=implicit-fallthrough" # flags specific to OpenMW project
|
||||||
|
|
|
@ -528,8 +528,12 @@ if ! [ -z $UNITY_BUILD ]; then
|
||||||
add_cmake_opts "-DOPENMW_UNITY_BUILD=True"
|
add_cmake_opts "-DOPENMW_UNITY_BUILD=True"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
if ! [ -z $USE_CCACHE ]; then
|
if [ -n "$USE_CCACHE" ]; then
|
||||||
add_cmake_opts "-DCMAKE_C_COMPILER_LAUNCHER=ccache -DCMAKE_CXX_COMPILER_LAUNCHER=ccache"
|
if [ -n "$NMAKE" ] || [ -n "$NINJA" ]; then
|
||||||
|
add_cmake_opts "-DCMAKE_C_COMPILER_LAUNCHER=ccache -DCMAKE_CXX_COMPILER_LAUNCHER=ccache -DPRECOMPILE_HEADERS_WITH_MSVC=OFF"
|
||||||
|
else
|
||||||
|
echo "Ignoring -C (CCache) as it is incompatible with Visual Studio CMake generators"
|
||||||
|
fi
|
||||||
fi
|
fi
|
||||||
|
|
||||||
# turn on LTO by default
|
# turn on LTO by default
|
||||||
|
|
|
@ -19,6 +19,14 @@ if(OPENMW_GL4ES_MANUAL_INIT)
|
||||||
add_definitions(-DOPENMW_GL4ES_MANUAL_INIT)
|
add_definitions(-DOPENMW_GL4ES_MANUAL_INIT)
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
|
if (APPLE OR WIN32)
|
||||||
|
set(DEPLOY_QT_TRANSLATIONS_DEFAULT ON)
|
||||||
|
else ()
|
||||||
|
set(DEPLOY_QT_TRANSLATIONS_DEFAULT OFF)
|
||||||
|
endif ()
|
||||||
|
|
||||||
|
option(DEPLOY_QT_TRANSLATIONS "Deploy standard Qt translations to resources folder. Needed when OpenMW applications are deployed with Qt libraries" ${DEPLOY_QT_TRANSLATIONS_DEFAULT})
|
||||||
|
|
||||||
# Apps and tools
|
# Apps and tools
|
||||||
option(BUILD_OPENMW "Build OpenMW" ON)
|
option(BUILD_OPENMW "Build OpenMW" ON)
|
||||||
option(BUILD_LAUNCHER "Build Launcher" ON)
|
option(BUILD_LAUNCHER "Build Launcher" ON)
|
||||||
|
@ -36,6 +44,7 @@ option(BUILD_BENCHMARKS "Build benchmarks with Google Benchmark" OFF)
|
||||||
option(BUILD_NAVMESHTOOL "Build navmesh tool" ON)
|
option(BUILD_NAVMESHTOOL "Build navmesh tool" ON)
|
||||||
option(BUILD_BULLETOBJECTTOOL "Build Bullet object tool" ON)
|
option(BUILD_BULLETOBJECTTOOL "Build Bullet object tool" ON)
|
||||||
option(BUILD_OPENCS_TESTS "Build OpenMW Construction Set tests" OFF)
|
option(BUILD_OPENCS_TESTS "Build OpenMW Construction Set tests" OFF)
|
||||||
|
option(PRECOMPILE_HEADERS_WITH_MSVC "Precompile most common used headers with MSVC (alternative to ccache)" ON)
|
||||||
|
|
||||||
set(OpenGL_GL_PREFERENCE LEGACY) # Use LEGACY as we use GL2; GLNVD is for GL3 and up.
|
set(OpenGL_GL_PREFERENCE LEGACY) # Use LEGACY as we use GL2; GLNVD is for GL3 and up.
|
||||||
|
|
||||||
|
@ -72,7 +81,7 @@ message(STATUS "Configuring OpenMW...")
|
||||||
set(OPENMW_VERSION_MAJOR 0)
|
set(OPENMW_VERSION_MAJOR 0)
|
||||||
set(OPENMW_VERSION_MINOR 49)
|
set(OPENMW_VERSION_MINOR 49)
|
||||||
set(OPENMW_VERSION_RELEASE 0)
|
set(OPENMW_VERSION_RELEASE 0)
|
||||||
set(OPENMW_LUA_API_REVISION 53)
|
set(OPENMW_LUA_API_REVISION 56)
|
||||||
set(OPENMW_POSTPROCESSING_API_REVISION 1)
|
set(OPENMW_POSTPROCESSING_API_REVISION 1)
|
||||||
|
|
||||||
set(OPENMW_VERSION_COMMITHASH "")
|
set(OPENMW_VERSION_COMMITHASH "")
|
||||||
|
@ -81,7 +90,7 @@ set(OPENMW_VERSION_COMMITDATE "")
|
||||||
|
|
||||||
set(OPENMW_VERSION "${OPENMW_VERSION_MAJOR}.${OPENMW_VERSION_MINOR}.${OPENMW_VERSION_RELEASE}")
|
set(OPENMW_VERSION "${OPENMW_VERSION_MAJOR}.${OPENMW_VERSION_MINOR}.${OPENMW_VERSION_RELEASE}")
|
||||||
|
|
||||||
set(OPENMW_DOC_BASEURL "https://openmw.readthedocs.io/en/stable/")
|
set(OPENMW_DOC_BASEURL "https://openmw.readthedocs.io/en/")
|
||||||
|
|
||||||
set(GIT_CHECKOUT FALSE)
|
set(GIT_CHECKOUT FALSE)
|
||||||
if(EXISTS ${PROJECT_SOURCE_DIR}/.git)
|
if(EXISTS ${PROJECT_SOURCE_DIR}/.git)
|
||||||
|
@ -182,6 +191,22 @@ if (MSVC)
|
||||||
add_compile_options(/bigobj)
|
add_compile_options(/bigobj)
|
||||||
|
|
||||||
add_compile_options(/Zc:__cplusplus)
|
add_compile_options(/Zc:__cplusplus)
|
||||||
|
|
||||||
|
if (CMAKE_CXX_COMPILER_LAUNCHER OR CMAKE_C_COMPILER_LAUNCHER)
|
||||||
|
if (CMAKE_GENERATOR MATCHES "Visual Studio")
|
||||||
|
message(STATUS "A compiler launcher was specified, but will be unused by the current generator (${CMAKE_GENERATOR})")
|
||||||
|
else()
|
||||||
|
foreach (config_lower ${CMAKE_CONFIGURATION_TYPES})
|
||||||
|
string(TOUPPER "${config_lower}" config)
|
||||||
|
if (CMAKE_C_COMPILER_LAUNCHER STREQUAL "ccache")
|
||||||
|
string(REPLACE "/Zi" "/Z7" CMAKE_C_FLAGS_${config} "${CMAKE_C_FLAGS_${config}}")
|
||||||
|
endif()
|
||||||
|
if (CMAKE_CXX_COMPILER_LAUNCHER STREQUAL "ccache")
|
||||||
|
string(REPLACE "/Zi" "/Z7" CMAKE_CXX_FLAGS_${config} "${CMAKE_CXX_FLAGS_${config}}")
|
||||||
|
endif()
|
||||||
|
endforeach()
|
||||||
|
endif()
|
||||||
|
endif()
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
# Set up common paths
|
# Set up common paths
|
||||||
|
@ -710,67 +735,66 @@ if (WIN32)
|
||||||
)
|
)
|
||||||
|
|
||||||
foreach(d ${WARNINGS_DISABLE})
|
foreach(d ${WARNINGS_DISABLE})
|
||||||
set(WARNINGS "${WARNINGS} /wd${d}")
|
list(APPEND WARNINGS "/wd${d}")
|
||||||
endforeach(d)
|
endforeach(d)
|
||||||
|
|
||||||
if(OPENMW_MSVC_WERROR)
|
if(OPENMW_MSVC_WERROR)
|
||||||
set(WARNINGS "${WARNINGS} /WX")
|
list(APPEND WARNINGS "/WX")
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
set_target_properties(components PROPERTIES COMPILE_FLAGS "${WARNINGS}")
|
target_compile_options(components PRIVATE ${WARNINGS})
|
||||||
set_target_properties(osg-ffmpeg-videoplayer PROPERTIES COMPILE_FLAGS "${WARNINGS}")
|
target_compile_options(osg-ffmpeg-videoplayer PRIVATE ${WARNINGS})
|
||||||
|
|
||||||
if (MSVC_VERSION GREATER_EQUAL 1915 AND MSVC_VERSION LESS 1920)
|
if (MSVC_VERSION GREATER_EQUAL 1915 AND MSVC_VERSION LESS 1920)
|
||||||
target_compile_definitions(components INTERFACE _ENABLE_EXTENDED_ALIGNED_STORAGE)
|
target_compile_definitions(components INTERFACE _ENABLE_EXTENDED_ALIGNED_STORAGE)
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
if (BUILD_BSATOOL)
|
if (BUILD_BSATOOL)
|
||||||
set_target_properties(bsatool PROPERTIES COMPILE_FLAGS "${WARNINGS}")
|
target_compile_options(bsatool PRIVATE ${WARNINGS})
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
if (BUILD_ESMTOOL)
|
if (BUILD_ESMTOOL)
|
||||||
set_target_properties(esmtool PROPERTIES COMPILE_FLAGS "${WARNINGS}")
|
target_compile_options(esmtool PRIVATE ${WARNINGS})
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
if (BUILD_ESSIMPORTER)
|
if (BUILD_ESSIMPORTER)
|
||||||
set_target_properties(openmw-essimporter PROPERTIES COMPILE_FLAGS "${WARNINGS}")
|
target_compile_options(openmw-essimporter PRIVATE ${WARNINGS})
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
if (BUILD_LAUNCHER)
|
if (BUILD_LAUNCHER)
|
||||||
set_target_properties(openmw-launcher PROPERTIES COMPILE_FLAGS "${WARNINGS}")
|
target_compile_options(openmw-launcher PRIVATE ${WARNINGS})
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
if (BUILD_MWINIIMPORTER)
|
if (BUILD_MWINIIMPORTER)
|
||||||
set_target_properties(openmw-iniimporter PROPERTIES COMPILE_FLAGS "${WARNINGS}")
|
target_compile_options(openmw-iniimporter PRIVATE ${WARNINGS})
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
if (BUILD_OPENCS)
|
if (BUILD_OPENCS)
|
||||||
set_target_properties(openmw-cs PROPERTIES COMPILE_FLAGS "${WARNINGS}")
|
target_compile_options(openmw-cs PRIVATE ${WARNINGS})
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
if (BUILD_OPENMW)
|
if (BUILD_OPENMW)
|
||||||
set_target_properties(openmw PROPERTIES COMPILE_FLAGS "${WARNINGS}")
|
target_compile_options(openmw PRIVATE ${WARNINGS})
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
if (BUILD_WIZARD)
|
if (BUILD_WIZARD)
|
||||||
set_target_properties(openmw-wizard PROPERTIES COMPILE_FLAGS "${WARNINGS}")
|
target_compile_options(openmw-wizard PRIVATE ${WARNINGS})
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
if (BUILD_UNITTESTS)
|
if (BUILD_UNITTESTS)
|
||||||
set_target_properties(openmw_test_suite PROPERTIES COMPILE_FLAGS "${WARNINGS}")
|
target_compile_options(openmw_test_suite PRIVATE ${WARNINGS})
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
if (BUILD_BENCHMARKS)
|
if (BUILD_BENCHMARKS)
|
||||||
set_target_properties(openmw_detournavigator_navmeshtilescache_benchmark PROPERTIES COMPILE_FLAGS "${WARNINGS}")
|
target_compile_options(openmw_detournavigator_navmeshtilescache_benchmark PRIVATE ${WARNINGS})
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
if (BUILD_NAVMESHTOOL)
|
if (BUILD_NAVMESHTOOL)
|
||||||
set_target_properties(openmw-navmeshtool PROPERTIES COMPILE_FLAGS "${WARNINGS}")
|
target_compile_options(openmw-navmeshtool PRIVATE ${WARNINGS})
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
if (BUILD_BULLETOBJECTTOOL)
|
if (BUILD_BULLETOBJECTTOOL)
|
||||||
set(WARNINGS "${WARNINGS} ${MT_BUILD}")
|
target_compile_options(openmw-bulletobjecttool PRIVATE ${WARNINGS} ${MT_BUILD})
|
||||||
set_target_properties(openmw-bulletobjecttool PROPERTIES COMPILE_FLAGS "${WARNINGS}")
|
|
||||||
endif()
|
endif()
|
||||||
endif(MSVC)
|
endif(MSVC)
|
||||||
|
|
||||||
|
@ -1099,13 +1123,13 @@ if (USE_QT)
|
||||||
|
|
||||||
if (BUILD_LAUNCHER OR BUILD_WIZARD)
|
if (BUILD_LAUNCHER OR BUILD_WIZARD)
|
||||||
if (APPLE)
|
if (APPLE)
|
||||||
set(QT_TRANSLATIONS_PATH "${APP_BUNDLE_DIR}/Contents/Resources/resources/translations")
|
set(QT_OPENMW_TRANSLATIONS_PATH "${APP_BUNDLE_DIR}/Contents/Resources/resources/translations")
|
||||||
else ()
|
else ()
|
||||||
get_generator_is_multi_config(multi_config)
|
get_generator_is_multi_config(multi_config)
|
||||||
if (multi_config)
|
if (multi_config)
|
||||||
set(QT_TRANSLATIONS_PATH "${OpenMW_BINARY_DIR}/$<CONFIG>/resources/translations")
|
set(QT_OPENMW_TRANSLATIONS_PATH "${OpenMW_BINARY_DIR}/$<CONFIG>/resources/translations")
|
||||||
else ()
|
else ()
|
||||||
set(QT_TRANSLATIONS_PATH "${OpenMW_BINARY_DIR}/resources/translations")
|
set(QT_OPENMW_TRANSLATIONS_PATH "${OpenMW_BINARY_DIR}/resources/translations")
|
||||||
endif ()
|
endif ()
|
||||||
endif ()
|
endif ()
|
||||||
|
|
||||||
|
@ -1121,9 +1145,30 @@ if (USE_QT)
|
||||||
|
|
||||||
qt_add_translation(QM_FILES ${TS_FILES} OPTIONS -silent)
|
qt_add_translation(QM_FILES ${TS_FILES} OPTIONS -silent)
|
||||||
|
|
||||||
|
if (DEPLOY_QT_TRANSLATIONS)
|
||||||
|
# Once we set a Qt 6.2.0 as a minimum required version, we may use "qtpaths --qt-query" instead.
|
||||||
|
get_target_property(QT_QMAKE_EXECUTABLE Qt::qmake IMPORTED_LOCATION)
|
||||||
|
execute_process(COMMAND "${QT_QMAKE_EXECUTABLE}" -query QT_INSTALL_TRANSLATIONS
|
||||||
|
OUTPUT_VARIABLE QT_TRANSLATIONS_DIR OUTPUT_STRIP_TRAILING_WHITESPACE)
|
||||||
|
|
||||||
|
foreach(QM_FILE ${QM_FILES})
|
||||||
|
get_filename_component(QM_BASENAME ${QM_FILE} NAME)
|
||||||
|
string(REGEX REPLACE "[^_]+_(.*)\\.qm" "\\1" LANG_NAME ${QM_BASENAME})
|
||||||
|
if (EXISTS "${QT_TRANSLATIONS_DIR}/qtbase_${LANG_NAME}.qm")
|
||||||
|
set(QM_FILES ${QM_FILES} "${QT_TRANSLATIONS_DIR}/qtbase_${LANG_NAME}.qm")
|
||||||
|
elseif (EXISTS "${QT_TRANSLATIONS_DIR}/qt_${LANG_NAME}.qm")
|
||||||
|
set(QM_FILES ${QM_FILES} "${QT_TRANSLATIONS_DIR}/qt_${LANG_NAME}.qm")
|
||||||
|
else ()
|
||||||
|
message(FATAL_ERROR "Qt translations for '${LANG_NAME}' locale are not found in the '${QT_TRANSLATIONS_DIR}' folder.")
|
||||||
|
endif ()
|
||||||
|
endforeach(QM_FILE)
|
||||||
|
|
||||||
|
list(REMOVE_DUPLICATES QM_FILES)
|
||||||
|
endif ()
|
||||||
|
|
||||||
add_custom_target(qm-files
|
add_custom_target(qm-files
|
||||||
COMMAND ${CMAKE_COMMAND} -E make_directory ${QT_TRANSLATIONS_PATH}
|
COMMAND ${CMAKE_COMMAND} -E make_directory ${QT_OPENMW_TRANSLATIONS_PATH}
|
||||||
COMMAND ${CMAKE_COMMAND} -E copy_if_different ${QM_FILES} ${QT_TRANSLATIONS_PATH}
|
COMMAND ${CMAKE_COMMAND} -E copy_if_different ${QM_FILES} ${QT_OPENMW_TRANSLATIONS_PATH}
|
||||||
DEPENDS ${QM_FILES}
|
DEPENDS ${QM_FILES}
|
||||||
COMMENT "Copy *.qm files to resources folder")
|
COMMENT "Copy *.qm files to resources folder")
|
||||||
endif ()
|
endif ()
|
||||||
|
|
|
@ -5,7 +5,7 @@ if (UNIX AND NOT APPLE)
|
||||||
target_link_libraries(openmw_detournavigator_navmeshtilescache_benchmark ${CMAKE_THREAD_LIBS_INIT})
|
target_link_libraries(openmw_detournavigator_navmeshtilescache_benchmark ${CMAKE_THREAD_LIBS_INIT})
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
if (MSVC)
|
if (MSVC AND PRECOMPILE_HEADERS_WITH_MSVC)
|
||||||
target_precompile_headers(openmw_detournavigator_navmeshtilescache_benchmark PRIVATE <algorithm>)
|
target_precompile_headers(openmw_detournavigator_navmeshtilescache_benchmark PRIVATE <algorithm>)
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
|
|
|
@ -182,7 +182,7 @@ namespace
|
||||||
for (auto _ : state)
|
for (auto _ : state)
|
||||||
{
|
{
|
||||||
const auto& key = keys[n++ % keys.size()];
|
const auto& key = keys[n++ % keys.size()];
|
||||||
const auto result = cache.get(key.mAgentBounds, key.mTilePosition, key.mRecastMesh);
|
auto result = cache.get(key.mAgentBounds, key.mTilePosition, key.mRecastMesh);
|
||||||
benchmark::DoNotOptimize(result);
|
benchmark::DoNotOptimize(result);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -241,7 +241,7 @@ namespace
|
||||||
while (state.KeepRunning())
|
while (state.KeepRunning())
|
||||||
{
|
{
|
||||||
const auto& key = keys[n++ % keys.size()];
|
const auto& key = keys[n++ % keys.size()];
|
||||||
const auto result = cache.set(
|
auto result = cache.set(
|
||||||
key.mAgentBounds, key.mTilePosition, key.mRecastMesh, std::make_unique<PreparedNavMeshData>());
|
key.mAgentBounds, key.mTilePosition, key.mRecastMesh, std::make_unique<PreparedNavMeshData>());
|
||||||
benchmark::DoNotOptimize(result);
|
benchmark::DoNotOptimize(result);
|
||||||
}
|
}
|
||||||
|
|
|
@ -5,7 +5,7 @@ if (UNIX AND NOT APPLE)
|
||||||
target_link_libraries(openmw_esm_refid_benchmark ${CMAKE_THREAD_LIBS_INIT})
|
target_link_libraries(openmw_esm_refid_benchmark ${CMAKE_THREAD_LIBS_INIT})
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
if (MSVC)
|
if (MSVC AND PRECOMPILE_HEADERS_WITH_MSVC)
|
||||||
target_precompile_headers(openmw_esm_refid_benchmark PRIVATE <algorithm>)
|
target_precompile_headers(openmw_esm_refid_benchmark PRIVATE <algorithm>)
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
|
|
|
@ -8,7 +8,7 @@ if (UNIX AND NOT APPLE)
|
||||||
target_link_libraries(openmw_settings_access_benchmark ${CMAKE_THREAD_LIBS_INIT})
|
target_link_libraries(openmw_settings_access_benchmark ${CMAKE_THREAD_LIBS_INIT})
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
if (MSVC)
|
if (MSVC AND PRECOMPILE_HEADERS_WITH_MSVC)
|
||||||
target_precompile_headers(openmw_settings_access_benchmark PRIVATE <algorithm>)
|
target_precompile_headers(openmw_settings_access_benchmark PRIVATE <algorithm>)
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
|
|
|
@ -18,7 +18,7 @@ if (BUILD_WITH_CODE_COVERAGE)
|
||||||
target_link_libraries(bsatool gcov)
|
target_link_libraries(bsatool gcov)
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
if (MSVC)
|
if (MSVC AND PRECOMPILE_HEADERS_WITH_MSVC)
|
||||||
target_precompile_headers(bsatool PRIVATE
|
target_precompile_headers(bsatool PRIVATE
|
||||||
<filesystem>
|
<filesystem>
|
||||||
<fstream>
|
<fstream>
|
||||||
|
|
|
@ -329,17 +329,19 @@ int main(int argc, char** argv)
|
||||||
|
|
||||||
switch (bsaVersion)
|
switch (bsaVersion)
|
||||||
{
|
{
|
||||||
case Bsa::BSAVER_COMPRESSED:
|
case Bsa::BsaVersion::Unknown:
|
||||||
return call<Bsa::CompressedBSAFile>(info);
|
break;
|
||||||
case Bsa::BSAVER_BA2_GNRL:
|
case Bsa::BsaVersion::Uncompressed:
|
||||||
return call<Bsa::BA2GNRLFile>(info);
|
|
||||||
case Bsa::BSAVER_BA2_DX10:
|
|
||||||
return call<Bsa::BA2DX10File>(info);
|
|
||||||
case Bsa::BSAVER_UNCOMPRESSED:
|
|
||||||
return call<Bsa::BSAFile>(info);
|
return call<Bsa::BSAFile>(info);
|
||||||
default:
|
case Bsa::BsaVersion::Compressed:
|
||||||
throw std::runtime_error("Unrecognised BSA archive");
|
return call<Bsa::CompressedBSAFile>(info);
|
||||||
|
case Bsa::BsaVersion::BA2GNRL:
|
||||||
|
return call<Bsa::BA2GNRLFile>(info);
|
||||||
|
case Bsa::BsaVersion::BA2DX10:
|
||||||
|
return call<Bsa::BA2DX10File>(info);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
throw std::runtime_error("Unrecognised BSA archive");
|
||||||
}
|
}
|
||||||
catch (std::exception& e)
|
catch (std::exception& e)
|
||||||
{
|
{
|
||||||
|
|
|
@ -19,7 +19,7 @@ if (WIN32)
|
||||||
install(TARGETS openmw-bulletobjecttool RUNTIME DESTINATION ".")
|
install(TARGETS openmw-bulletobjecttool RUNTIME DESTINATION ".")
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
if (MSVC)
|
if (MSVC AND PRECOMPILE_HEADERS_WITH_MSVC)
|
||||||
target_precompile_headers(openmw-bulletobjecttool PRIVATE
|
target_precompile_headers(openmw-bulletobjecttool PRIVATE
|
||||||
<string>
|
<string>
|
||||||
<vector>
|
<vector>
|
||||||
|
|
|
@ -25,7 +25,7 @@ if (BUILD_WITH_CODE_COVERAGE)
|
||||||
target_link_libraries(esmtool gcov)
|
target_link_libraries(esmtool gcov)
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
if (MSVC)
|
if (MSVC AND PRECOMPILE_HEADERS_WITH_MSVC)
|
||||||
target_precompile_headers(esmtool PRIVATE
|
target_precompile_headers(esmtool PRIVATE
|
||||||
<fstream>
|
<fstream>
|
||||||
<string>
|
<string>
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
#include "labels.hpp"
|
#include "labels.hpp"
|
||||||
|
|
||||||
|
#include <components/esm3/loadalch.hpp>
|
||||||
#include <components/esm3/loadbody.hpp>
|
#include <components/esm3/loadbody.hpp>
|
||||||
#include <components/esm3/loadcell.hpp>
|
#include <components/esm3/loadcell.hpp>
|
||||||
#include <components/esm3/loadcont.hpp>
|
#include <components/esm3/loadcont.hpp>
|
||||||
|
@ -987,3 +988,16 @@ std::string recordFlags(uint32_t flags)
|
||||||
properties += Misc::StringUtils::format("(0x%08X)", flags);
|
properties += Misc::StringUtils::format("(0x%08X)", flags);
|
||||||
return properties;
|
return properties;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
std::string potionFlags(int flags)
|
||||||
|
{
|
||||||
|
std::string properties;
|
||||||
|
if (flags == 0)
|
||||||
|
properties += "[None] ";
|
||||||
|
if (flags & ESM::Potion::Autocalc)
|
||||||
|
properties += "Autocalc ";
|
||||||
|
if (flags & (0xFFFFFFFF ^ ESM::Enchantment::Autocalc))
|
||||||
|
properties += "Invalid ";
|
||||||
|
properties += Misc::StringUtils::format("(0x%08X)", flags);
|
||||||
|
return properties;
|
||||||
|
}
|
||||||
|
|
|
@ -60,6 +60,7 @@ std::string itemListFlags(int flags);
|
||||||
std::string lightFlags(int flags);
|
std::string lightFlags(int flags);
|
||||||
std::string magicEffectFlags(int flags);
|
std::string magicEffectFlags(int flags);
|
||||||
std::string npcFlags(int flags);
|
std::string npcFlags(int flags);
|
||||||
|
std::string potionFlags(int flags);
|
||||||
std::string raceFlags(int flags);
|
std::string raceFlags(int flags);
|
||||||
std::string spellFlags(int flags);
|
std::string spellFlags(int flags);
|
||||||
std::string weaponFlags(int flags);
|
std::string weaponFlags(int flags);
|
||||||
|
|
|
@ -479,7 +479,7 @@ namespace EsmTool
|
||||||
std::cout << " Script: " << mData.mScript << std::endl;
|
std::cout << " Script: " << mData.mScript << std::endl;
|
||||||
std::cout << " Weight: " << mData.mData.mWeight << std::endl;
|
std::cout << " Weight: " << mData.mData.mWeight << std::endl;
|
||||||
std::cout << " Value: " << mData.mData.mValue << std::endl;
|
std::cout << " Value: " << mData.mData.mValue << std::endl;
|
||||||
std::cout << " AutoCalc: " << mData.mData.mAutoCalc << std::endl;
|
std::cout << " Flags: " << potionFlags(mData.mData.mFlags) << std::endl;
|
||||||
printEffectList(mData.mEffects);
|
printEffectList(mData.mEffects);
|
||||||
std::cout << " Deleted: " << mIsDeleted << std::endl;
|
std::cout << " Deleted: " << mIsDeleted << std::endl;
|
||||||
}
|
}
|
||||||
|
@ -612,7 +612,6 @@ namespace EsmTool
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
std::cout << " Map Color: " << Misc::StringUtils::format("0x%08X", mData.mMapColor) << std::endl;
|
std::cout << " Map Color: " << Misc::StringUtils::format("0x%08X", mData.mMapColor) << std::endl;
|
||||||
std::cout << " Water Level Int: " << mData.mWaterInt << std::endl;
|
|
||||||
std::cout << " RefId counter: " << mData.mRefNumCounter << std::endl;
|
std::cout << " RefId counter: " << mData.mRefNumCounter << std::endl;
|
||||||
std::cout << " Deleted: " << mIsDeleted << std::endl;
|
std::cout << " Deleted: " << mIsDeleted << std::endl;
|
||||||
}
|
}
|
||||||
|
@ -722,9 +721,6 @@ namespace EsmTool
|
||||||
std::cout << " AI Fight:" << (int)mData.mAiData.mFight << std::endl;
|
std::cout << " AI Fight:" << (int)mData.mAiData.mFight << std::endl;
|
||||||
std::cout << " AI Flee:" << (int)mData.mAiData.mFlee << std::endl;
|
std::cout << " AI Flee:" << (int)mData.mAiData.mFlee << std::endl;
|
||||||
std::cout << " AI Alarm:" << (int)mData.mAiData.mAlarm << std::endl;
|
std::cout << " AI Alarm:" << (int)mData.mAiData.mAlarm << std::endl;
|
||||||
std::cout << " AI U1:" << (int)mData.mAiData.mU1 << std::endl;
|
|
||||||
std::cout << " AI U2:" << (int)mData.mAiData.mU2 << std::endl;
|
|
||||||
std::cout << " AI U3:" << (int)mData.mAiData.mU3 << std::endl;
|
|
||||||
std::cout << " AI Services:" << Misc::StringUtils::format("0x%08X", mData.mAiData.mServices) << std::endl;
|
std::cout << " AI Services:" << Misc::StringUtils::format("0x%08X", mData.mAiData.mServices) << std::endl;
|
||||||
|
|
||||||
for (const ESM::AIPackage& package : mData.mAiPackage.mList)
|
for (const ESM::AIPackage& package : mData.mAiPackage.mList)
|
||||||
|
@ -1115,9 +1111,6 @@ namespace EsmTool
|
||||||
std::cout << " AI Fight:" << (int)mData.mAiData.mFight << std::endl;
|
std::cout << " AI Fight:" << (int)mData.mAiData.mFight << std::endl;
|
||||||
std::cout << " AI Flee:" << (int)mData.mAiData.mFlee << std::endl;
|
std::cout << " AI Flee:" << (int)mData.mAiData.mFlee << std::endl;
|
||||||
std::cout << " AI Alarm:" << (int)mData.mAiData.mAlarm << std::endl;
|
std::cout << " AI Alarm:" << (int)mData.mAiData.mAlarm << std::endl;
|
||||||
std::cout << " AI U1:" << (int)mData.mAiData.mU1 << std::endl;
|
|
||||||
std::cout << " AI U2:" << (int)mData.mAiData.mU2 << std::endl;
|
|
||||||
std::cout << " AI U3:" << (int)mData.mAiData.mU3 << std::endl;
|
|
||||||
std::cout << " AI Services:" << Misc::StringUtils::format("0x%08X", mData.mAiData.mServices) << std::endl;
|
std::cout << " AI Services:" << Misc::StringUtils::format("0x%08X", mData.mAiData.mServices) << std::endl;
|
||||||
|
|
||||||
for (const ESM::AIPackage& package : mData.mAiPackage.mList)
|
for (const ESM::AIPackage& package : mData.mAiPackage.mList)
|
||||||
|
|
|
@ -47,7 +47,7 @@ if (WIN32)
|
||||||
INSTALL(TARGETS openmw-essimporter RUNTIME DESTINATION ".")
|
INSTALL(TARGETS openmw-essimporter RUNTIME DESTINATION ".")
|
||||||
endif(WIN32)
|
endif(WIN32)
|
||||||
|
|
||||||
if (MSVC)
|
if (MSVC AND PRECOMPILE_HEADERS_WITH_MSVC)
|
||||||
target_precompile_headers(openmw-essimporter PRIVATE
|
target_precompile_headers(openmw-essimporter PRIVATE
|
||||||
<algorithm>
|
<algorithm>
|
||||||
<filesystem>
|
<filesystem>
|
||||||
|
|
|
@ -94,7 +94,7 @@ if(USE_QT)
|
||||||
set_property(TARGET openmw-launcher PROPERTY AUTOMOC ON)
|
set_property(TARGET openmw-launcher PROPERTY AUTOMOC ON)
|
||||||
endif(USE_QT)
|
endif(USE_QT)
|
||||||
|
|
||||||
if (MSVC)
|
if (MSVC AND PRECOMPILE_HEADERS_WITH_MSVC)
|
||||||
target_precompile_headers(openmw-launcher PRIVATE
|
target_precompile_headers(openmw-launcher PRIVATE
|
||||||
<boost/program_options/options_description.hpp>
|
<boost/program_options/options_description.hpp>
|
||||||
|
|
||||||
|
|
|
@ -819,7 +819,7 @@ void Launcher::DataFilesPage::addArchivesFromDir(const QString& path)
|
||||||
for (const auto& fileinfo : dir.entryInfoList(archiveFilter))
|
for (const auto& fileinfo : dir.entryInfoList(archiveFilter))
|
||||||
{
|
{
|
||||||
const auto absPath = fileinfo.absoluteFilePath();
|
const auto absPath = fileinfo.absoluteFilePath();
|
||||||
if (Bsa::BSAFile::detectVersion(Files::pathFromQString(absPath)) == Bsa::BSAVER_UNKNOWN)
|
if (Bsa::BSAFile::detectVersion(Files::pathFromQString(absPath)) == Bsa::BsaVersion::Unknown)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
const auto fileName = fileinfo.fileName();
|
const auto fileName = fileinfo.fileName();
|
||||||
|
|
|
@ -1,7 +1,6 @@
|
||||||
#include <iostream>
|
#include <iostream>
|
||||||
|
|
||||||
#include <QDir>
|
#include <QDir>
|
||||||
#include <QTranslator>
|
|
||||||
|
|
||||||
#include <boost/program_options/options_description.hpp>
|
#include <boost/program_options/options_description.hpp>
|
||||||
#include <boost/program_options/variables_map.hpp>
|
#include <boost/program_options/variables_map.hpp>
|
||||||
|
@ -9,6 +8,7 @@
|
||||||
#include <components/debug/debugging.hpp>
|
#include <components/debug/debugging.hpp>
|
||||||
#include <components/files/configurationmanager.hpp>
|
#include <components/files/configurationmanager.hpp>
|
||||||
#include <components/files/qtconversion.hpp>
|
#include <components/files/qtconversion.hpp>
|
||||||
|
#include <components/l10n/qttranslations.hpp>
|
||||||
#include <components/platform/platform.hpp>
|
#include <components/platform/platform.hpp>
|
||||||
|
|
||||||
#ifdef MAC_OS_X_VERSION_MIN_REQUIRED
|
#ifdef MAC_OS_X_VERSION_MIN_REQUIRED
|
||||||
|
@ -41,16 +41,7 @@ int runLauncher(int argc, char* argv[])
|
||||||
resourcesPath = Files::pathToQString(variables["resources"].as<Files::MaybeQuotedPath>().u8string());
|
resourcesPath = Files::pathToQString(variables["resources"].as<Files::MaybeQuotedPath>().u8string());
|
||||||
}
|
}
|
||||||
|
|
||||||
// Internationalization
|
l10n::installQtTranslations(app, "launcher", resourcesPath);
|
||||||
QString locale = QLocale::system().name().section('_', 0, 0);
|
|
||||||
|
|
||||||
QTranslator appTranslator;
|
|
||||||
appTranslator.load(resourcesPath + "/translations/launcher_" + locale + ".qm");
|
|
||||||
app.installTranslator(&appTranslator);
|
|
||||||
|
|
||||||
QTranslator componentsAppTranslator;
|
|
||||||
componentsAppTranslator.load(resourcesPath + "/translations/components_" + locale + ".qm");
|
|
||||||
app.installTranslator(&componentsAppTranslator);
|
|
||||||
|
|
||||||
Launcher::MainDialog mainWin(configurationManager);
|
Launcher::MainDialog mainWin(configurationManager);
|
||||||
|
|
||||||
|
|
|
@ -193,8 +193,10 @@ bool Launcher::SettingsPage::loadSettings()
|
||||||
loadSettingBool(Settings::game().mSmoothMovement, *smoothMovementCheckBox);
|
loadSettingBool(Settings::game().mSmoothMovement, *smoothMovementCheckBox);
|
||||||
loadSettingBool(Settings::game().mPlayerMovementIgnoresAnimation, *playerMovementIgnoresAnimationCheckBox);
|
loadSettingBool(Settings::game().mPlayerMovementIgnoresAnimation, *playerMovementIgnoresAnimationCheckBox);
|
||||||
|
|
||||||
distantLandCheckBox->setCheckState(
|
connect(distantLandCheckBox, &QCheckBox::toggled, this, &SettingsPage::slotDistantLandToggled);
|
||||||
Settings::terrain().mDistantTerrain && Settings::terrain().mObjectPaging ? Qt::Checked : Qt::Unchecked);
|
bool distantLandEnabled = Settings::terrain().mDistantTerrain && Settings::terrain().mObjectPaging;
|
||||||
|
distantLandCheckBox->setCheckState(distantLandEnabled ? Qt::Checked : Qt::Unchecked);
|
||||||
|
slotDistantLandToggled(distantLandEnabled);
|
||||||
|
|
||||||
loadSettingBool(Settings::terrain().mObjectPagingActiveGrid, *activeGridObjectPagingCheckBox);
|
loadSettingBool(Settings::terrain().mObjectPagingActiveGrid, *activeGridObjectPagingCheckBox);
|
||||||
viewingDistanceComboBox->setValue(convertToCells(Settings::camera().mViewingDistance));
|
viewingDistanceComboBox->setValue(convertToCells(Settings::camera().mViewingDistance));
|
||||||
|
@ -294,6 +296,7 @@ bool Launcher::SettingsPage::loadSettings()
|
||||||
hrtfProfileSelectorComboBox->setCurrentIndex(hrtfProfileIndex);
|
hrtfProfileSelectorComboBox->setCurrentIndex(hrtfProfileIndex);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
loadSettingBool(Settings::sound().mCameraListener, *cameraListenerCheckBox);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Interface Changes
|
// Interface Changes
|
||||||
|
@ -490,6 +493,9 @@ void Launcher::SettingsPage::saveSettings()
|
||||||
Settings::sound().mHrtf.set(hrtfProfileSelectorComboBox->currentText().toStdString());
|
Settings::sound().mHrtf.set(hrtfProfileSelectorComboBox->currentText().toStdString());
|
||||||
else
|
else
|
||||||
Settings::sound().mHrtf.set({});
|
Settings::sound().mHrtf.set({});
|
||||||
|
|
||||||
|
const bool cCameraListener = cameraListenerCheckBox->checkState() != Qt::Unchecked;
|
||||||
|
Settings::sound().mCameraListener.set(cCameraListener);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Interface Changes
|
// Interface Changes
|
||||||
|
@ -579,9 +585,16 @@ void Launcher::SettingsPage::slotShadowDistLimitToggled(bool checked)
|
||||||
fadeStartSpinBox->setEnabled(checked);
|
fadeStartSpinBox->setEnabled(checked);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void Launcher::SettingsPage::slotDistantLandToggled(bool checked)
|
||||||
|
{
|
||||||
|
activeGridObjectPagingCheckBox->setEnabled(checked);
|
||||||
|
objectPagingMinSizeComboBox->setEnabled(checked);
|
||||||
|
}
|
||||||
|
|
||||||
void Launcher::SettingsPage::slotLightTypeCurrentIndexChanged(int index)
|
void Launcher::SettingsPage::slotLightTypeCurrentIndexChanged(int index)
|
||||||
{
|
{
|
||||||
lightsMaximumDistanceSpinBox->setEnabled(index != 0);
|
lightsMaximumDistanceSpinBox->setEnabled(index != 0);
|
||||||
|
lightFadeMultiplierSpinBox->setEnabled(index != 0);
|
||||||
lightsMaxLightsSpinBox->setEnabled(index != 0);
|
lightsMaxLightsSpinBox->setEnabled(index != 0);
|
||||||
lightsBoundingSphereMultiplierSpinBox->setEnabled(index != 0);
|
lightsBoundingSphereMultiplierSpinBox->setEnabled(index != 0);
|
||||||
lightsMinimumInteriorBrightnessSpinBox->setEnabled(index != 0);
|
lightsMinimumInteriorBrightnessSpinBox->setEnabled(index != 0);
|
||||||
|
|
|
@ -33,6 +33,7 @@ namespace Launcher
|
||||||
void slotPostProcessToggled(bool checked);
|
void slotPostProcessToggled(bool checked);
|
||||||
void slotSkyBlendingToggled(bool checked);
|
void slotSkyBlendingToggled(bool checked);
|
||||||
void slotShadowDistLimitToggled(bool checked);
|
void slotShadowDistLimitToggled(bool checked);
|
||||||
|
void slotDistantLandToggled(bool checked);
|
||||||
void slotLightTypeCurrentIndexChanged(int index);
|
void slotLightTypeCurrentIndexChanged(int index);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
|
@ -524,7 +524,7 @@
|
||||||
<string><html><head/><body><p>Allows MSAA to work with alpha-tested meshes, producing better-looking edges without pixelation. Can negatively impact performance.</p></body></html></string>
|
<string><html><head/><body><p>Allows MSAA to work with alpha-tested meshes, producing better-looking edges without pixelation. Can negatively impact performance.</p></body></html></string>
|
||||||
</property>
|
</property>
|
||||||
<property name="text">
|
<property name="text">
|
||||||
<string>Use anti-alias alpha testing</string>
|
<string>Use anti-aliased alpha testing</string>
|
||||||
</property>
|
</property>
|
||||||
</widget>
|
</widget>
|
||||||
</item>
|
</item>
|
||||||
|
@ -652,42 +652,6 @@
|
||||||
<item>
|
<item>
|
||||||
<layout class="QGridLayout" name="terrainLayout" columnstretch="0,0">
|
<layout class="QGridLayout" name="terrainLayout" columnstretch="0,0">
|
||||||
<item row="4" column="0">
|
<item row="4" column="0">
|
||||||
<widget class="QCheckBox" name="distantLandCheckBox">
|
|
||||||
<property name="toolTip">
|
|
||||||
<string><html><head/><body><p>If true, use paging and LOD algorithms to display the entire terrain. If false, only display terrain of the loaded cells.</p></body></html></string>
|
|
||||||
</property>
|
|
||||||
<property name="text">
|
|
||||||
<string>Distant land</string>
|
|
||||||
</property>
|
|
||||||
</widget>
|
|
||||||
</item>
|
|
||||||
<item row="2" column="1">
|
|
||||||
<widget class="QDoubleSpinBox" name="viewingDistanceComboBox">
|
|
||||||
<property name="suffix">
|
|
||||||
<string> cells</string>
|
|
||||||
</property>
|
|
||||||
<property name="minimum">
|
|
||||||
<double>0.000000000000000</double>
|
|
||||||
</property>
|
|
||||||
<property name="singleStep">
|
|
||||||
<double>0.500000000000000</double>
|
|
||||||
</property>
|
|
||||||
</widget>
|
|
||||||
</item>
|
|
||||||
<item row="6" column="1">
|
|
||||||
<spacer name="verticalSpacer_15">
|
|
||||||
<property name="orientation">
|
|
||||||
<enum>Qt::Vertical</enum>
|
|
||||||
</property>
|
|
||||||
<property name="sizeHint" stdset="0">
|
|
||||||
<size>
|
|
||||||
<width>20</width>
|
|
||||||
<height>40</height>
|
|
||||||
</size>
|
|
||||||
</property>
|
|
||||||
</spacer>
|
|
||||||
</item>
|
|
||||||
<item row="3" column="0">
|
|
||||||
<widget class="QLabel" name="objectPagingMinSizeLabel">
|
<widget class="QLabel" name="objectPagingMinSizeLabel">
|
||||||
<property name="toolTip">
|
<property name="toolTip">
|
||||||
<string><html><head/><body><p>Controls how large an object must be to be visible in the scene. The object’s size is divided by its distance to the camera and the result of the division is compared with this value. The smaller this value is, the more objects you will see in the scene.</p></body></html></string>
|
<string><html><head/><body><p>Controls how large an object must be to be visible in the scene. The object’s size is divided by its distance to the camera and the result of the division is compared with this value. The smaller this value is, the more objects you will see in the scene.</p></body></html></string>
|
||||||
|
@ -697,14 +661,7 @@
|
||||||
</property>
|
</property>
|
||||||
</widget>
|
</widget>
|
||||||
</item>
|
</item>
|
||||||
<item row="2" column="0">
|
<item row="4" column="1">
|
||||||
<widget class="QLabel" name="viewingDistanceLabel">
|
|
||||||
<property name="text">
|
|
||||||
<string>Viewing distance</string>
|
|
||||||
</property>
|
|
||||||
</widget>
|
|
||||||
</item>
|
|
||||||
<item row="3" column="1">
|
|
||||||
<widget class="QDoubleSpinBox" name="objectPagingMinSizeComboBox">
|
<widget class="QDoubleSpinBox" name="objectPagingMinSizeComboBox">
|
||||||
<property name="decimals">
|
<property name="decimals">
|
||||||
<number>3</number>
|
<number>3</number>
|
||||||
|
@ -720,7 +677,53 @@
|
||||||
</property>
|
</property>
|
||||||
</widget>
|
</widget>
|
||||||
</item>
|
</item>
|
||||||
<item row="4" column="1">
|
<item row="2" column="0">
|
||||||
|
<widget class="QLabel" name="viewingDistanceLabel">
|
||||||
|
<property name="text">
|
||||||
|
<string>Viewing distance</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item row="2" column="1">
|
||||||
|
<widget class="QDoubleSpinBox" name="viewingDistanceComboBox">
|
||||||
|
<property name="suffix">
|
||||||
|
<string> cells</string>
|
||||||
|
</property>
|
||||||
|
<property name="decimals">
|
||||||
|
<number>3</number>
|
||||||
|
</property>
|
||||||
|
<property name="minimum">
|
||||||
|
<double>0.000000000000000</double>
|
||||||
|
</property>
|
||||||
|
<property name="singleStep">
|
||||||
|
<double>0.125000000000000</double>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item row="7" column="1">
|
||||||
|
<spacer name="verticalSpacer_15">
|
||||||
|
<property name="orientation">
|
||||||
|
<enum>Qt::Vertical</enum>
|
||||||
|
</property>
|
||||||
|
<property name="sizeHint" stdset="0">
|
||||||
|
<size>
|
||||||
|
<width>20</width>
|
||||||
|
<height>40</height>
|
||||||
|
</size>
|
||||||
|
</property>
|
||||||
|
</spacer>
|
||||||
|
</item>
|
||||||
|
<item row="3" column="0">
|
||||||
|
<widget class="QCheckBox" name="distantLandCheckBox">
|
||||||
|
<property name="toolTip">
|
||||||
|
<string><html><head/><body><p>If true, use paging and LOD algorithms to display the entire terrain. If false, only display terrain of the loaded cells.</p></body></html></string>
|
||||||
|
</property>
|
||||||
|
<property name="text">
|
||||||
|
<string>Distant land</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item row="3" column="1">
|
||||||
<widget class="QCheckBox" name="activeGridObjectPagingCheckBox">
|
<widget class="QCheckBox" name="activeGridObjectPagingCheckBox">
|
||||||
<property name="toolTip">
|
<property name="toolTip">
|
||||||
<string><html><head/><body><p>Use object paging for active cells grid.</p></body></html></string>
|
<string><html><head/><body><p>Use object paging for active cells grid.</p></body></html></string>
|
||||||
|
@ -866,6 +869,9 @@
|
||||||
<property name="maximum">
|
<property name="maximum">
|
||||||
<number>81920</number>
|
<number>81920</number>
|
||||||
</property>
|
</property>
|
||||||
|
<property name="singleStep">
|
||||||
|
<number>128</number>
|
||||||
|
</property>
|
||||||
<property name="value">
|
<property name="value">
|
||||||
<number>8192</number>
|
<number>8192</number>
|
||||||
</property>
|
</property>
|
||||||
|
@ -969,6 +975,9 @@
|
||||||
<property name="maximum">
|
<property name="maximum">
|
||||||
<double>1.000000000000000</double>
|
<double>1.000000000000000</double>
|
||||||
</property>
|
</property>
|
||||||
|
<property name="singleStep">
|
||||||
|
<double>0.010000000000000</double>
|
||||||
|
</property>
|
||||||
<property name="value">
|
<property name="value">
|
||||||
<double>0.900000000000000</double>
|
<double>0.900000000000000</double>
|
||||||
</property>
|
</property>
|
||||||
|
@ -1024,7 +1033,7 @@
|
||||||
<string><html><head/><body><p>Maximum distance at which lights will appear (measured in units).</p><p>Set this to 0 to use an unlimited distance.</p></body></html></string>
|
<string><html><head/><body><p>Maximum distance at which lights will appear (measured in units).</p><p>Set this to 0 to use an unlimited distance.</p></body></html></string>
|
||||||
</property>
|
</property>
|
||||||
<property name="text">
|
<property name="text">
|
||||||
<string>Lights maximum distance</string>
|
<string>Maximum light distance</string>
|
||||||
</property>
|
</property>
|
||||||
</widget>
|
</widget>
|
||||||
</item>
|
</item>
|
||||||
|
@ -1047,7 +1056,7 @@
|
||||||
<string><html><head/><body><p>Maximum number of lights per object.</p><p>A low number near default will cause light popping similar to what you would see with legacy lighting.</p></body></html></string>
|
<string><html><head/><body><p>Maximum number of lights per object.</p><p>A low number near default will cause light popping similar to what you would see with legacy lighting.</p></body></html></string>
|
||||||
</property>
|
</property>
|
||||||
<property name="text">
|
<property name="text">
|
||||||
<string>Max light sources</string>
|
<string>Max lights</string>
|
||||||
</property>
|
</property>
|
||||||
</widget>
|
</widget>
|
||||||
</item>
|
</item>
|
||||||
|
@ -1057,7 +1066,7 @@
|
||||||
<string><html><head/><body><p>Fraction of maximum distance at which lights will start to fade.</p><p>Set this to a low value for slower transitions or a high value for quicker transitions.</p></body></html></string>
|
<string><html><head/><body><p>Fraction of maximum distance at which lights will start to fade.</p><p>Set this to a low value for slower transitions or a high value for quicker transitions.</p></body></html></string>
|
||||||
</property>
|
</property>
|
||||||
<property name="text">
|
<property name="text">
|
||||||
<string>Lights fade multiplier</string>
|
<string>Fade start multiplier</string>
|
||||||
</property>
|
</property>
|
||||||
</widget>
|
</widget>
|
||||||
</item>
|
</item>
|
||||||
|
@ -1099,7 +1108,7 @@
|
||||||
<string><html><head/><body><p>Multipler for bounding sphere of lights.</p><p>Higher numbers allows for smooth falloff but require an increase in number of max lights.</p><p>Does not effect the illumination or strength of lights.</p></body></html></string>
|
<string><html><head/><body><p>Multipler for bounding sphere of lights.</p><p>Higher numbers allows for smooth falloff but require an increase in number of max lights.</p><p>Does not effect the illumination or strength of lights.</p></body></html></string>
|
||||||
</property>
|
</property>
|
||||||
<property name="text">
|
<property name="text">
|
||||||
<string>Lights bounding sphere multiplier</string>
|
<string>Bounding sphere multiplier</string>
|
||||||
</property>
|
</property>
|
||||||
</widget>
|
</widget>
|
||||||
</item>
|
</item>
|
||||||
|
@ -1109,7 +1118,7 @@
|
||||||
<string><html><head/><body><p>Minimum ambient interior brightness.</p><p>Increase this if you feel interiors are too dark.</p></body></html></string>
|
<string><html><head/><body><p>Minimum ambient interior brightness.</p><p>Increase this if you feel interiors are too dark.</p></body></html></string>
|
||||||
</property>
|
</property>
|
||||||
<property name="text">
|
<property name="text">
|
||||||
<string>Lights minimum interior brightness</string>
|
<string>Minimum interior brightness</string>
|
||||||
</property>
|
</property>
|
||||||
</widget>
|
</widget>
|
||||||
</item>
|
</item>
|
||||||
|
@ -1320,6 +1329,16 @@
|
||||||
</item>
|
</item>
|
||||||
</layout>
|
</layout>
|
||||||
</item>
|
</item>
|
||||||
|
<item>
|
||||||
|
<widget class="QCheckBox" name="cameraListenerCheckBox">
|
||||||
|
<property name="toolTip">
|
||||||
|
<string>In third-person view, use the camera as the sound listener instead of the player character.</string>
|
||||||
|
</property>
|
||||||
|
<property name="text">
|
||||||
|
<string>Use the camera as the sound listener</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
<item>
|
<item>
|
||||||
<spacer>
|
<spacer>
|
||||||
<property name="orientation">
|
<property name="orientation">
|
||||||
|
|
|
@ -33,7 +33,7 @@ if (BUILD_WITH_CODE_COVERAGE)
|
||||||
target_link_libraries(openmw-iniimporter gcov)
|
target_link_libraries(openmw-iniimporter gcov)
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
if (MSVC)
|
if (MSVC AND PRECOMPILE_HEADERS_WITH_MSVC)
|
||||||
target_precompile_headers(openmw-iniimporter PRIVATE
|
target_precompile_headers(openmw-iniimporter PRIVATE
|
||||||
<string>
|
<string>
|
||||||
<vector>
|
<vector>
|
||||||
|
|
|
@ -21,7 +21,7 @@ if (WIN32)
|
||||||
install(TARGETS openmw-navmeshtool RUNTIME DESTINATION ".")
|
install(TARGETS openmw-navmeshtool RUNTIME DESTINATION ".")
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
if (MSVC)
|
if (MSVC AND PRECOMPILE_HEADERS_WITH_MSVC)
|
||||||
target_precompile_headers(openmw-navmeshtool PRIVATE
|
target_precompile_headers(openmw-navmeshtool PRIVATE
|
||||||
<algorithm>
|
<algorithm>
|
||||||
<memory>
|
<memory>
|
||||||
|
|
|
@ -17,6 +17,6 @@ if (BUILD_WITH_CODE_COVERAGE)
|
||||||
target_link_libraries(niftest gcov)
|
target_link_libraries(niftest gcov)
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
if (MSVC)
|
if (MSVC AND PRECOMPILE_HEADERS_WITH_MSVC)
|
||||||
target_precompile_headers(niftest PRIVATE <filesystem>)
|
target_precompile_headers(niftest PRIVATE <filesystem>)
|
||||||
endif()
|
endif()
|
||||||
|
|
|
@ -42,29 +42,10 @@ bool isBSA(const std::filesystem::path& filename)
|
||||||
return hasExtension(filename, ".bsa") || hasExtension(filename, ".ba2");
|
return hasExtension(filename, ".bsa") || hasExtension(filename, ".ba2");
|
||||||
}
|
}
|
||||||
|
|
||||||
std::unique_ptr<VFS::Archive> makeBsaArchive(const std::filesystem::path& path)
|
|
||||||
{
|
|
||||||
switch (Bsa::BSAFile::detectVersion(path))
|
|
||||||
{
|
|
||||||
case Bsa::BSAVER_COMPRESSED:
|
|
||||||
return std::make_unique<VFS::ArchiveSelector<Bsa::BSAVER_COMPRESSED>::type>(path);
|
|
||||||
case Bsa::BSAVER_BA2_GNRL:
|
|
||||||
return std::make_unique<VFS::ArchiveSelector<Bsa::BSAVER_BA2_GNRL>::type>(path);
|
|
||||||
case Bsa::BSAVER_BA2_DX10:
|
|
||||||
return std::make_unique<VFS::ArchiveSelector<Bsa::BSAVER_BA2_DX10>::type>(path);
|
|
||||||
case Bsa::BSAVER_UNCOMPRESSED:
|
|
||||||
return std::make_unique<VFS::ArchiveSelector<Bsa::BSAVER_UNCOMPRESSED>::type>(path);
|
|
||||||
case Bsa::BSAVER_UNKNOWN:
|
|
||||||
default:
|
|
||||||
std::cerr << "'" << Files::pathToUnicodeString(path) << "' is not a recognized BSA archive" << std::endl;
|
|
||||||
return nullptr;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
std::unique_ptr<VFS::Archive> makeArchive(const std::filesystem::path& path)
|
std::unique_ptr<VFS::Archive> makeArchive(const std::filesystem::path& path)
|
||||||
{
|
{
|
||||||
if (isBSA(path))
|
if (isBSA(path))
|
||||||
return makeBsaArchive(path);
|
return VFS::makeBsaArchive(path);
|
||||||
if (std::filesystem::is_directory(path))
|
if (std::filesystem::is_directory(path))
|
||||||
return std::make_unique<VFS::FileSystemArchive>(path);
|
return std::make_unique<VFS::FileSystemArchive>(path);
|
||||||
return nullptr;
|
return nullptr;
|
||||||
|
@ -124,17 +105,23 @@ void readVFS(std::unique_ptr<VFS::Archive>&& archive, const std::filesystem::pat
|
||||||
|
|
||||||
if (!archivePath.empty() && !isBSA(archivePath))
|
if (!archivePath.empty() && !isBSA(archivePath))
|
||||||
{
|
{
|
||||||
Files::PathContainer dataDirs = { archivePath };
|
const Files::Collections fileCollections({ archivePath });
|
||||||
const Files::Collections fileCollections = Files::Collections(dataDirs);
|
|
||||||
const Files::MultiDirCollection& bsaCol = fileCollections.getCollection(".bsa");
|
const Files::MultiDirCollection& bsaCol = fileCollections.getCollection(".bsa");
|
||||||
const Files::MultiDirCollection& ba2Col = fileCollections.getCollection(".ba2");
|
const Files::MultiDirCollection& ba2Col = fileCollections.getCollection(".ba2");
|
||||||
for (auto& file : bsaCol)
|
for (const Files::MultiDirCollection& collection : { bsaCol, ba2Col })
|
||||||
{
|
{
|
||||||
readVFS(makeBsaArchive(file.second), file.second, quiet);
|
for (auto& file : collection)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
readVFS(VFS::makeBsaArchive(file.second), file.second, quiet);
|
||||||
}
|
}
|
||||||
for (auto& file : ba2Col)
|
catch (const std::exception& e)
|
||||||
{
|
{
|
||||||
readVFS(makeBsaArchive(file.second), file.second, quiet);
|
std::cerr << "Failed to read archive file '" << Files::pathToUnicodeString(file.second)
|
||||||
|
<< "': " << e.what() << std::endl;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -172,7 +172,7 @@ else()
|
||||||
set (OPENCS_OPENMW_CFG "")
|
set (OPENCS_OPENMW_CFG "")
|
||||||
endif(APPLE)
|
endif(APPLE)
|
||||||
|
|
||||||
add_library(openmw-cs-lib
|
add_library(openmw-cs-lib STATIC
|
||||||
${OPENCS_SRC}
|
${OPENCS_SRC}
|
||||||
${OPENCS_UI_HDR}
|
${OPENCS_UI_HDR}
|
||||||
${OPENCS_MOC_SRC}
|
${OPENCS_MOC_SRC}
|
||||||
|
@ -292,7 +292,7 @@ if (BUILD_WITH_CODE_COVERAGE)
|
||||||
target_link_libraries(openmw-cs-lib gcov)
|
target_link_libraries(openmw-cs-lib gcov)
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
if (MSVC)
|
if (MSVC AND PRECOMPILE_HEADERS_WITH_MSVC)
|
||||||
target_precompile_headers(openmw-cs-lib PRIVATE
|
target_precompile_headers(openmw-cs-lib PRIVATE
|
||||||
<boost/program_options/options_description.hpp>
|
<boost/program_options/options_description.hpp>
|
||||||
|
|
||||||
|
|
|
@ -67,6 +67,11 @@ namespace CSMWorld
|
||||||
return mMaleParts[ESM::getMeshPart(index)];
|
return mMaleParts[ESM::getMeshPart(index)];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const osg::Vec2f& ActorAdapter::RaceData::getGenderWeightHeight(bool isFemale)
|
||||||
|
{
|
||||||
|
return isFemale ? mWeightsHeights.mFemaleWeightHeight : mWeightsHeights.mMaleWeightHeight;
|
||||||
|
}
|
||||||
|
|
||||||
bool ActorAdapter::RaceData::hasDependency(const ESM::RefId& id) const
|
bool ActorAdapter::RaceData::hasDependency(const ESM::RefId& id) const
|
||||||
{
|
{
|
||||||
return mDependencies.find(id) != mDependencies.end();
|
return mDependencies.find(id) != mDependencies.end();
|
||||||
|
@ -90,10 +95,11 @@ namespace CSMWorld
|
||||||
mDependencies.emplace(id);
|
mDependencies.emplace(id);
|
||||||
}
|
}
|
||||||
|
|
||||||
void ActorAdapter::RaceData::reset_data(const ESM::RefId& id, bool isBeast)
|
void ActorAdapter::RaceData::reset_data(const ESM::RefId& id, const WeightsHeights& raceStats, bool isBeast)
|
||||||
{
|
{
|
||||||
mId = id;
|
mId = id;
|
||||||
mIsBeast = isBeast;
|
mIsBeast = isBeast;
|
||||||
|
mWeightsHeights = raceStats;
|
||||||
for (auto& str : mFemaleParts)
|
for (auto& str : mFemaleParts)
|
||||||
str = ESM::RefId();
|
str = ESM::RefId();
|
||||||
for (auto& str : mMaleParts)
|
for (auto& str : mMaleParts)
|
||||||
|
@ -163,6 +169,11 @@ namespace CSMWorld
|
||||||
return it->second.first;
|
return it->second.first;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const osg::Vec2f& ActorAdapter::ActorData::getRaceWeightHeight() const
|
||||||
|
{
|
||||||
|
return mRaceData->getGenderWeightHeight(isFemale());
|
||||||
|
}
|
||||||
|
|
||||||
bool ActorAdapter::ActorData::hasDependency(const ESM::RefId& id) const
|
bool ActorAdapter::ActorData::hasDependency(const ESM::RefId& id) const
|
||||||
{
|
{
|
||||||
return mDependencies.find(id) != mDependencies.end();
|
return mDependencies.find(id) != mDependencies.end();
|
||||||
|
@ -504,7 +515,11 @@ namespace CSMWorld
|
||||||
}
|
}
|
||||||
|
|
||||||
auto& race = raceRecord.get();
|
auto& race = raceRecord.get();
|
||||||
data->reset_data(id, race.mData.mFlags & ESM::Race::Beast);
|
|
||||||
|
WeightsHeights scaleStats = { osg::Vec2f(race.mData.mMaleWeight, race.mData.mMaleHeight),
|
||||||
|
osg::Vec2f(race.mData.mFemaleWeight, race.mData.mFemaleHeight) };
|
||||||
|
|
||||||
|
data->reset_data(id, scaleStats, race.mData.mFlags & ESM::Race::Beast);
|
||||||
|
|
||||||
// Setup body parts
|
// Setup body parts
|
||||||
for (int i = 0; i < mBodyParts.getSize(); ++i)
|
for (int i = 0; i < mBodyParts.getSize(); ++i)
|
||||||
|
|
|
@ -41,6 +41,12 @@ namespace CSMWorld
|
||||||
/// Tracks unique strings
|
/// Tracks unique strings
|
||||||
using RefIdSet = std::unordered_set<ESM::RefId>;
|
using RefIdSet = std::unordered_set<ESM::RefId>;
|
||||||
|
|
||||||
|
struct WeightsHeights
|
||||||
|
{
|
||||||
|
osg::Vec2f mMaleWeightHeight;
|
||||||
|
osg::Vec2f mFemaleWeightHeight;
|
||||||
|
};
|
||||||
|
|
||||||
/// Contains base race data shared between actors
|
/// Contains base race data shared between actors
|
||||||
class RaceData
|
class RaceData
|
||||||
{
|
{
|
||||||
|
@ -57,6 +63,8 @@ namespace CSMWorld
|
||||||
const ESM::RefId& getFemalePart(ESM::PartReferenceType index) const;
|
const ESM::RefId& getFemalePart(ESM::PartReferenceType index) const;
|
||||||
/// Retrieves the associated body part
|
/// Retrieves the associated body part
|
||||||
const ESM::RefId& getMalePart(ESM::PartReferenceType index) const;
|
const ESM::RefId& getMalePart(ESM::PartReferenceType index) const;
|
||||||
|
|
||||||
|
const osg::Vec2f& getGenderWeightHeight(bool isFemale);
|
||||||
/// Checks if the race has a data dependency
|
/// Checks if the race has a data dependency
|
||||||
bool hasDependency(const ESM::RefId& id) const;
|
bool hasDependency(const ESM::RefId& id) const;
|
||||||
|
|
||||||
|
@ -67,7 +75,8 @@ namespace CSMWorld
|
||||||
/// Marks an additional dependency
|
/// Marks an additional dependency
|
||||||
void addOtherDependency(const ESM::RefId& id);
|
void addOtherDependency(const ESM::RefId& id);
|
||||||
/// Clears parts and dependencies
|
/// Clears parts and dependencies
|
||||||
void reset_data(const ESM::RefId& raceId, bool isBeast = false);
|
void reset_data(const ESM::RefId& raceId,
|
||||||
|
const WeightsHeights& raceStats = { osg::Vec2f(1.f, 1.f), osg::Vec2f(1.f, 1.f) }, bool isBeast = false);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
bool handles(ESM::PartReferenceType type) const;
|
bool handles(ESM::PartReferenceType type) const;
|
||||||
|
@ -75,6 +84,7 @@ namespace CSMWorld
|
||||||
bool mIsBeast;
|
bool mIsBeast;
|
||||||
RacePartList mFemaleParts;
|
RacePartList mFemaleParts;
|
||||||
RacePartList mMaleParts;
|
RacePartList mMaleParts;
|
||||||
|
WeightsHeights mWeightsHeights;
|
||||||
RefIdSet mDependencies;
|
RefIdSet mDependencies;
|
||||||
};
|
};
|
||||||
using RaceDataPtr = std::shared_ptr<RaceData>;
|
using RaceDataPtr = std::shared_ptr<RaceData>;
|
||||||
|
@ -96,6 +106,8 @@ namespace CSMWorld
|
||||||
std::string getSkeleton() const;
|
std::string getSkeleton() const;
|
||||||
/// Retrieves the associated actor part
|
/// Retrieves the associated actor part
|
||||||
ESM::RefId getPart(ESM::PartReferenceType index) const;
|
ESM::RefId getPart(ESM::PartReferenceType index) const;
|
||||||
|
|
||||||
|
const osg::Vec2f& getRaceWeightHeight() const;
|
||||||
/// Checks if the actor has a data dependency
|
/// Checks if the actor has a data dependency
|
||||||
bool hasDependency(const ESM::RefId& id) const;
|
bool hasDependency(const ESM::RefId& id) const;
|
||||||
|
|
||||||
|
|
|
@ -585,19 +585,22 @@ namespace CSMWorld
|
||||||
void set(Record<ESXRecordT>& record, const QVariant& data) override
|
void set(Record<ESXRecordT>& record, const QVariant& data) override
|
||||||
{
|
{
|
||||||
ESXRecordT record2 = record.get();
|
ESXRecordT record2 = record.get();
|
||||||
|
|
||||||
|
float bodyAttr = std::clamp(data.toFloat(), 0.5f, 2.0f);
|
||||||
|
|
||||||
if (mWeight)
|
if (mWeight)
|
||||||
{
|
{
|
||||||
if (mMale)
|
if (mMale)
|
||||||
record2.mData.mMaleWeight = data.toFloat();
|
record2.mData.mMaleWeight = bodyAttr;
|
||||||
else
|
else
|
||||||
record2.mData.mFemaleWeight = data.toFloat();
|
record2.mData.mFemaleWeight = bodyAttr;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
if (mMale)
|
if (mMale)
|
||||||
record2.mData.mMaleHeight = data.toFloat();
|
record2.mData.mMaleHeight = bodyAttr;
|
||||||
else
|
else
|
||||||
record2.mData.mFemaleHeight = data.toFloat();
|
record2.mData.mFemaleHeight = bodyAttr;
|
||||||
}
|
}
|
||||||
record.setModified(record2);
|
record.setModified(record2);
|
||||||
}
|
}
|
||||||
|
|
|
@ -996,7 +996,10 @@ namespace CSMWorld
|
||||||
case 5:
|
case 5:
|
||||||
{
|
{
|
||||||
if (isInterior && interiorWater)
|
if (isInterior && interiorWater)
|
||||||
|
{
|
||||||
cell.mWater = value.toFloat();
|
cell.mWater = value.toFloat();
|
||||||
|
cell.setHasWaterHeightSub(true);
|
||||||
|
}
|
||||||
else
|
else
|
||||||
return; // return without saving
|
return; // return without saving
|
||||||
break;
|
break;
|
||||||
|
|
|
@ -33,7 +33,7 @@ QVariant CSMWorld::PotionRefIdAdapter::getData(const RefIdColumn* column, const
|
||||||
data.getRecord(RefIdData::LocalIndex(index, UniversalId::Type_Potion)));
|
data.getRecord(RefIdData::LocalIndex(index, UniversalId::Type_Potion)));
|
||||||
|
|
||||||
if (column == mAutoCalc)
|
if (column == mAutoCalc)
|
||||||
return record.get().mData.mAutoCalc != 0;
|
return record.get().mData.mFlags & ESM::Potion::Autocalc;
|
||||||
|
|
||||||
// to show nested tables in dialogue subview, see IdTree::hasChildren()
|
// to show nested tables in dialogue subview, see IdTree::hasChildren()
|
||||||
if (column == mColumns.mEffects)
|
if (column == mColumns.mEffects)
|
||||||
|
@ -51,7 +51,7 @@ void CSMWorld::PotionRefIdAdapter::setData(
|
||||||
ESM::Potion potion = record.get();
|
ESM::Potion potion = record.get();
|
||||||
|
|
||||||
if (column == mAutoCalc)
|
if (column == mAutoCalc)
|
||||||
potion.mData.mAutoCalc = value.toInt();
|
potion.mData.mFlags = value.toBool();
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
InventoryRefIdAdapter<ESM::Potion>::setData(column, data, index, value);
|
InventoryRefIdAdapter<ESM::Potion>::setData(column, data, index, value);
|
||||||
|
|
|
@ -7,6 +7,7 @@
|
||||||
#include <osg/Group>
|
#include <osg/Group>
|
||||||
#include <osg/MatrixTransform>
|
#include <osg/MatrixTransform>
|
||||||
#include <osg/Node>
|
#include <osg/Node>
|
||||||
|
#include <osg/Vec3d>
|
||||||
|
|
||||||
#include <apps/opencs/model/world/actoradapter.hpp>
|
#include <apps/opencs/model/world/actoradapter.hpp>
|
||||||
#include <apps/opencs/model/world/idcollection.hpp>
|
#include <apps/opencs/model/world/idcollection.hpp>
|
||||||
|
@ -29,7 +30,7 @@ namespace CSVRender
|
||||||
Actor::Actor(const ESM::RefId& id, CSMWorld::Data& data)
|
Actor::Actor(const ESM::RefId& id, CSMWorld::Data& data)
|
||||||
: mId(id)
|
: mId(id)
|
||||||
, mData(data)
|
, mData(data)
|
||||||
, mBaseNode(new osg::Group())
|
, mBaseNode(new osg::PositionAttitudeTransform())
|
||||||
, mSkeleton(nullptr)
|
, mSkeleton(nullptr)
|
||||||
{
|
{
|
||||||
mActorData = mData.getActorAdapter()->getActorData(mId);
|
mActorData = mData.getActorAdapter()->getActorData(mId);
|
||||||
|
@ -60,6 +61,10 @@ namespace CSVRender
|
||||||
|
|
||||||
// Attach parts to skeleton
|
// Attach parts to skeleton
|
||||||
loadBodyParts();
|
loadBodyParts();
|
||||||
|
|
||||||
|
const osg::Vec2f& attributes = mActorData->getRaceWeightHeight();
|
||||||
|
|
||||||
|
mBaseNode->setScale(osg::Vec3d(attributes.x(), attributes.x(), attributes.y()));
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
|
|
@ -5,6 +5,7 @@
|
||||||
#include <string_view>
|
#include <string_view>
|
||||||
|
|
||||||
#include <osg/Group>
|
#include <osg/Group>
|
||||||
|
#include <osg/PositionAttitudeTransform>
|
||||||
#include <osg/ref_ptr>
|
#include <osg/ref_ptr>
|
||||||
|
|
||||||
#include <QObject>
|
#include <QObject>
|
||||||
|
@ -59,7 +60,7 @@ namespace CSVRender
|
||||||
CSMWorld::Data& mData;
|
CSMWorld::Data& mData;
|
||||||
CSMWorld::ActorAdapter::ActorDataPtr mActorData;
|
CSMWorld::ActorAdapter::ActorDataPtr mActorData;
|
||||||
|
|
||||||
osg::ref_ptr<osg::Group> mBaseNode;
|
osg::ref_ptr<osg::PositionAttitudeTransform> mBaseNode;
|
||||||
SceneUtil::Skeleton* mSkeleton;
|
SceneUtil::Skeleton* mSkeleton;
|
||||||
SceneUtil::NodeMapVisitor::NodeMap mNodeMap;
|
SceneUtil::NodeMapVisitor::NodeMap mNodeMap;
|
||||||
};
|
};
|
||||||
|
|
|
@ -48,6 +48,7 @@
|
||||||
#include <components/debug/debuglog.hpp>
|
#include <components/debug/debuglog.hpp>
|
||||||
#include <components/resource/resourcesystem.hpp>
|
#include <components/resource/resourcesystem.hpp>
|
||||||
#include <components/resource/scenemanager.hpp>
|
#include <components/resource/scenemanager.hpp>
|
||||||
|
#include <components/sceneutil/glextensions.hpp>
|
||||||
#include <components/sceneutil/lightmanager.hpp>
|
#include <components/sceneutil/lightmanager.hpp>
|
||||||
|
|
||||||
#include "../widget/scenetoolmode.hpp"
|
#include "../widget/scenetoolmode.hpp"
|
||||||
|
@ -76,6 +77,8 @@ namespace CSVRender
|
||||||
= new osgViewer::GraphicsWindowEmbedded(0, 0, width(), height());
|
= new osgViewer::GraphicsWindowEmbedded(0, 0, width(), height());
|
||||||
mWidget->setGraphicsWindowEmbedded(window);
|
mWidget->setGraphicsWindowEmbedded(window);
|
||||||
|
|
||||||
|
mRenderer->setRealizeOperation(new SceneUtil::GetGLExtensionsOperation());
|
||||||
|
|
||||||
int frameRateLimit = CSMPrefs::get()["Rendering"]["framerate-limit"].toInt();
|
int frameRateLimit = CSMPrefs::get()["Rendering"]["framerate-limit"].toInt();
|
||||||
mRenderer->setRunMaxFrameRate(frameRateLimit);
|
mRenderer->setRunMaxFrameRate(frameRateLimit);
|
||||||
mRenderer->setUseConfigureAffinity(false);
|
mRenderer->setUseConfigureAffinity(false);
|
||||||
|
|
|
@ -2,17 +2,6 @@
|
||||||
|
|
||||||
#include <components/misc/strings/lower.hpp>
|
#include <components/misc/strings/lower.hpp>
|
||||||
|
|
||||||
bool CSVWorld::IdValidator::isValid(const QChar& c, bool first) const
|
|
||||||
{
|
|
||||||
if (c.isLetter() || c == '_')
|
|
||||||
return true;
|
|
||||||
|
|
||||||
if (!first && (c.isDigit() || c.isSpace()))
|
|
||||||
return true;
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
CSVWorld::IdValidator::IdValidator(bool relaxed, QObject* parent)
|
CSVWorld::IdValidator::IdValidator(bool relaxed, QObject* parent)
|
||||||
: QValidator(parent)
|
: QValidator(parent)
|
||||||
, mRelaxed(relaxed)
|
, mRelaxed(relaxed)
|
||||||
|
@ -92,7 +81,7 @@ QValidator::State CSVWorld::IdValidator::validate(QString& input, int& pos) cons
|
||||||
{
|
{
|
||||||
prevScope = false;
|
prevScope = false;
|
||||||
|
|
||||||
if (!isValid(*iter, first))
|
if (!iter->isPrint())
|
||||||
return QValidator::Invalid;
|
return QValidator::Invalid;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -13,9 +13,6 @@ namespace CSVWorld
|
||||||
std::string mNamespace;
|
std::string mNamespace;
|
||||||
mutable std::string mError;
|
mutable std::string mError;
|
||||||
|
|
||||||
private:
|
|
||||||
bool isValid(const QChar& c, bool first) const;
|
|
||||||
|
|
||||||
public:
|
public:
|
||||||
IdValidator(bool relaxed = false, QObject* parent = nullptr);
|
IdValidator(bool relaxed = false, QObject* parent = nullptr);
|
||||||
///< \param relaxed Relaxed rules for IDs that also functino as user visible text
|
///< \param relaxed Relaxed rules for IDs that also functino as user visible text
|
||||||
|
|
|
@ -26,7 +26,7 @@ if (BUILD_WITH_CODE_COVERAGE)
|
||||||
target_link_libraries(openmw-cs-tests PRIVATE gcov)
|
target_link_libraries(openmw-cs-tests PRIVATE gcov)
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
if (MSVC)
|
if (MSVC AND PRECOMPILE_HEADERS_WITH_MSVC)
|
||||||
target_precompile_headers(openmw-cs-tests PRIVATE
|
target_precompile_headers(openmw-cs-tests PRIVATE
|
||||||
<gtest/gtest.h>
|
<gtest/gtest.h>
|
||||||
)
|
)
|
||||||
|
|
|
@ -64,7 +64,7 @@ add_openmw_dir (mwlua
|
||||||
context menuscripts globalscripts localscripts playerscripts luabindings objectbindings cellbindings
|
context menuscripts globalscripts localscripts playerscripts luabindings objectbindings cellbindings
|
||||||
mwscriptbindings camerabindings vfsbindings uibindings soundbindings inputbindings nearbybindings
|
mwscriptbindings camerabindings vfsbindings uibindings soundbindings inputbindings nearbybindings
|
||||||
postprocessingbindings stats debugbindings corebindings worldbindings worker magicbindings factionbindings
|
postprocessingbindings stats debugbindings corebindings worldbindings worker magicbindings factionbindings
|
||||||
classbindings itemdata inputprocessor animationbindings
|
classbindings itemdata inputprocessor animationbindings birthsignbindings racebindings
|
||||||
types/types types/door types/item types/actor types/container types/lockable types/weapon types/npc
|
types/types types/door types/item types/actor types/container types/lockable types/weapon types/npc
|
||||||
types/creature types/player types/activator types/book types/lockpick types/probe types/apparatus
|
types/creature types/player types/activator types/book types/lockpick types/probe types/apparatus
|
||||||
types/potion types/ingredient types/misc types/repair types/armor types/light types/static
|
types/potion types/ingredient types/misc types/repair types/armor types/light types/static
|
||||||
|
@ -88,7 +88,7 @@ add_openmw_dir (mwworld
|
||||||
|
|
||||||
add_openmw_dir (mwphysics
|
add_openmw_dir (mwphysics
|
||||||
physicssystem trace collisiontype actor convert object heightfield closestnotmerayresultcallback
|
physicssystem trace collisiontype actor convert object heightfield closestnotmerayresultcallback
|
||||||
contacttestresultcallback deepestnotmecontacttestresultcallback stepper movementsolver projectile
|
contacttestresultcallback stepper movementsolver projectile
|
||||||
actorconvexcallback raycasting mtphysics contacttestwrapper projectileconvexcallback
|
actorconvexcallback raycasting mtphysics contacttestwrapper projectileconvexcallback
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -161,7 +161,7 @@ target_link_libraries(openmw
|
||||||
components
|
components
|
||||||
)
|
)
|
||||||
|
|
||||||
if (MSVC)
|
if (MSVC AND PRECOMPILE_HEADERS_WITH_MSVC)
|
||||||
target_precompile_headers(openmw PRIVATE
|
target_precompile_headers(openmw PRIVATE
|
||||||
<boost/program_options/options_description.hpp>
|
<boost/program_options/options_description.hpp>
|
||||||
|
|
||||||
|
|
|
@ -14,6 +14,7 @@
|
||||||
#include <components/debug/gldebug.hpp>
|
#include <components/debug/gldebug.hpp>
|
||||||
|
|
||||||
#include <components/misc/rng.hpp>
|
#include <components/misc/rng.hpp>
|
||||||
|
#include <components/misc/strings/format.hpp>
|
||||||
|
|
||||||
#include <components/vfs/manager.hpp>
|
#include <components/vfs/manager.hpp>
|
||||||
#include <components/vfs/registerarchives.hpp>
|
#include <components/vfs/registerarchives.hpp>
|
||||||
|
@ -30,6 +31,7 @@
|
||||||
#include <components/stereo/multiview.hpp>
|
#include <components/stereo/multiview.hpp>
|
||||||
#include <components/stereo/stereomanager.hpp>
|
#include <components/stereo/stereomanager.hpp>
|
||||||
|
|
||||||
|
#include <components/sceneutil/glextensions.hpp>
|
||||||
#include <components/sceneutil/workqueue.hpp>
|
#include <components/sceneutil/workqueue.hpp>
|
||||||
|
|
||||||
#include <components/files/configurationmanager.hpp>
|
#include <components/files/configurationmanager.hpp>
|
||||||
|
@ -109,10 +111,23 @@ namespace
|
||||||
profiler.removeUserStatsLine(" -Async");
|
profiler.removeUserStatsLine(" -Async");
|
||||||
}
|
}
|
||||||
|
|
||||||
struct ScheduleNonDialogMessageBox
|
struct ScreenCaptureMessageBox
|
||||||
{
|
{
|
||||||
void operator()(std::string message) const
|
void operator()(std::string filePath) const
|
||||||
{
|
{
|
||||||
|
if (filePath.empty())
|
||||||
|
{
|
||||||
|
MWBase::Environment::get().getWindowManager()->scheduleMessageBox(
|
||||||
|
"#{OMWEngine:ScreenshotFailed}", MWGui::ShowInDialogueMode_Never);
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string messageFormat
|
||||||
|
= MWBase::Environment::get().getL10nManager()->getMessage("OMWEngine", "ScreenshotMade");
|
||||||
|
|
||||||
|
std::string message = Misc::StringUtils::format(messageFormat, filePath);
|
||||||
|
|
||||||
MWBase::Environment::get().getWindowManager()->scheduleMessageBox(
|
MWBase::Environment::get().getWindowManager()->scheduleMessageBox(
|
||||||
std::move(message), MWGui::ShowInDialogueMode_Never);
|
std::move(message), MWGui::ShowInDialogueMode_Never);
|
||||||
}
|
}
|
||||||
|
@ -586,6 +601,7 @@ void OMW::Engine::createWindow()
|
||||||
mViewer->setRealizeOperation(realizeOperations);
|
mViewer->setRealizeOperation(realizeOperations);
|
||||||
osg::ref_ptr<IdentifyOpenGLOperation> identifyOp = new IdentifyOpenGLOperation();
|
osg::ref_ptr<IdentifyOpenGLOperation> identifyOp = new IdentifyOpenGLOperation();
|
||||||
realizeOperations->add(identifyOp);
|
realizeOperations->add(identifyOp);
|
||||||
|
realizeOperations->add(new SceneUtil::GetGLExtensionsOperation());
|
||||||
|
|
||||||
if (Debug::shouldDebugOpenGL())
|
if (Debug::shouldDebugOpenGL())
|
||||||
realizeOperations->add(new Debug::EnableGLDebugOperation());
|
realizeOperations->add(new Debug::EnableGLDebugOperation());
|
||||||
|
@ -717,8 +733,7 @@ void OMW::Engine::prepareEngine()
|
||||||
mScreenCaptureOperation = new SceneUtil::AsyncScreenCaptureOperation(mWorkQueue,
|
mScreenCaptureOperation = new SceneUtil::AsyncScreenCaptureOperation(mWorkQueue,
|
||||||
new SceneUtil::WriteScreenshotToFileOperation(mCfgMgr.getScreenshotPath(),
|
new SceneUtil::WriteScreenshotToFileOperation(mCfgMgr.getScreenshotPath(),
|
||||||
Settings::general().mScreenshotFormat,
|
Settings::general().mScreenshotFormat,
|
||||||
Settings::general().mNotifyOnSavedScreenshot
|
Settings::general().mNotifyOnSavedScreenshot ? std::function<void(std::string)>(ScreenCaptureMessageBox{})
|
||||||
? std::function<void(std::string)>(ScheduleNonDialogMessageBox{})
|
|
||||||
: std::function<void(std::string)>(IgnoreString{})));
|
: std::function<void(std::string)>(IgnoreString{})));
|
||||||
|
|
||||||
mScreenCaptureHandler = new osgViewer::ScreenCaptureHandler(mScreenCaptureOperation);
|
mScreenCaptureHandler = new osgViewer::ScreenCaptureHandler(mScreenCaptureOperation);
|
||||||
|
@ -767,13 +782,13 @@ void OMW::Engine::prepareEngine()
|
||||||
// gui needs our shaders path before everything else
|
// gui needs our shaders path before everything else
|
||||||
mResourceSystem->getSceneManager()->setShaderPath(mResDir / "shaders");
|
mResourceSystem->getSceneManager()->setShaderPath(mResDir / "shaders");
|
||||||
|
|
||||||
osg::ref_ptr<osg::GLExtensions> exts = osg::GLExtensions::Get(0, false);
|
osg::GLExtensions& exts = SceneUtil::getGLExtensions();
|
||||||
bool shadersSupported = exts && (exts->glslLanguageVersion >= 1.2f);
|
bool shadersSupported = exts.glslLanguageVersion >= 1.2f;
|
||||||
|
|
||||||
#if OSG_VERSION_LESS_THAN(3, 6, 6)
|
#if OSG_VERSION_LESS_THAN(3, 6, 6)
|
||||||
// hack fix for https://github.com/openscenegraph/OpenSceneGraph/issues/1028
|
// hack fix for https://github.com/openscenegraph/OpenSceneGraph/issues/1028
|
||||||
if (exts)
|
if (!osg::isGLExtensionSupported(exts.contextID, "NV_framebuffer_multisample_coverage"))
|
||||||
exts->glRenderbufferStorageMultisampleCoverageNV = nullptr;
|
exts.glRenderbufferStorageMultisampleCoverageNV = nullptr;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
osg::ref_ptr<osg::Group> guiRoot = new osg::Group;
|
osg::ref_ptr<osg::Group> guiRoot = new osg::Group;
|
||||||
|
|
|
@ -2,6 +2,7 @@
|
||||||
#include <components/fallback/fallback.hpp>
|
#include <components/fallback/fallback.hpp>
|
||||||
#include <components/fallback/validate.hpp>
|
#include <components/fallback/validate.hpp>
|
||||||
#include <components/files/configurationmanager.hpp>
|
#include <components/files/configurationmanager.hpp>
|
||||||
|
#include <components/misc/osgpluginchecker.hpp>
|
||||||
#include <components/misc/rng.hpp>
|
#include <components/misc/rng.hpp>
|
||||||
#include <components/platform/platform.hpp>
|
#include <components/platform/platform.hpp>
|
||||||
#include <components/version/version.hpp>
|
#include <components/version/version.hpp>
|
||||||
|
@ -228,6 +229,9 @@ int runApplication(int argc, char* argv[])
|
||||||
|
|
||||||
if (parseOptions(argc, argv, *engine, cfgMgr))
|
if (parseOptions(argc, argv, *engine, cfgMgr))
|
||||||
{
|
{
|
||||||
|
if (!Misc::checkRequiredOSGPluginsArePresent())
|
||||||
|
return 1;
|
||||||
|
|
||||||
engine->go();
|
engine->go();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -68,6 +68,8 @@ namespace MWBase
|
||||||
const MWRender::AnimPriority& priority, int blendMask, bool autodisable, float speedmult,
|
const MWRender::AnimPriority& priority, int blendMask, bool autodisable, float speedmult,
|
||||||
std::string_view start, std::string_view stop, float startpoint, uint32_t loops, bool loopfallback)
|
std::string_view start, std::string_view stop, float startpoint, uint32_t loops, bool loopfallback)
|
||||||
= 0;
|
= 0;
|
||||||
|
virtual void skillLevelUp(const MWWorld::Ptr& actor, ESM::RefId skillId, std::string_view source) = 0;
|
||||||
|
virtual void skillUse(const MWWorld::Ptr& actor, ESM::RefId skillId, int useType, float scale) = 0;
|
||||||
virtual void exteriorCreated(MWWorld::CellStore& cell) = 0;
|
virtual void exteriorCreated(MWWorld::CellStore& cell) = 0;
|
||||||
virtual void actorDied(const MWWorld::Ptr& actor) = 0;
|
virtual void actorDied(const MWWorld::Ptr& actor) = 0;
|
||||||
virtual void questUpdated(const ESM::RefId& questId, int stage) = 0;
|
virtual void questUpdated(const ESM::RefId& questId, int stage) = 0;
|
||||||
|
@ -81,6 +83,12 @@ namespace MWBase
|
||||||
|
|
||||||
struct InputEvent
|
struct InputEvent
|
||||||
{
|
{
|
||||||
|
struct WheelChange
|
||||||
|
{
|
||||||
|
int x;
|
||||||
|
int y;
|
||||||
|
};
|
||||||
|
|
||||||
enum
|
enum
|
||||||
{
|
{
|
||||||
KeyPressed,
|
KeyPressed,
|
||||||
|
@ -91,8 +99,11 @@ namespace MWBase
|
||||||
TouchPressed,
|
TouchPressed,
|
||||||
TouchReleased,
|
TouchReleased,
|
||||||
TouchMoved,
|
TouchMoved,
|
||||||
|
MouseButtonPressed,
|
||||||
|
MouseButtonReleased,
|
||||||
|
MouseWheel,
|
||||||
} mType;
|
} mType;
|
||||||
std::variant<SDL_Keysym, int, SDLUtil::TouchEvent> mValue;
|
std::variant<SDL_Keysym, int, SDLUtil::TouchEvent, WheelChange> mValue;
|
||||||
};
|
};
|
||||||
virtual void inputEvent(const InputEvent& event) = 0;
|
virtual void inputEvent(const InputEvent& event) = 0;
|
||||||
|
|
||||||
|
|
|
@ -6,6 +6,8 @@
|
||||||
#include <string>
|
#include <string>
|
||||||
#include <string_view>
|
#include <string_view>
|
||||||
|
|
||||||
|
#include <components/vfs/pathutil.hpp>
|
||||||
|
|
||||||
#include "../mwsound/type.hpp"
|
#include "../mwsound/type.hpp"
|
||||||
#include "../mwworld/ptr.hpp"
|
#include "../mwworld/ptr.hpp"
|
||||||
|
|
||||||
|
@ -129,11 +131,11 @@ namespace MWBase
|
||||||
/// \param name of the folder that contains the playlist
|
/// \param name of the folder that contains the playlist
|
||||||
/// Title music playlist is predefined
|
/// Title music playlist is predefined
|
||||||
|
|
||||||
virtual void say(const MWWorld::ConstPtr& reference, const std::string& filename) = 0;
|
virtual void say(const MWWorld::ConstPtr& reference, VFS::Path::NormalizedView filename) = 0;
|
||||||
///< Make an actor say some text.
|
///< Make an actor say some text.
|
||||||
/// \param filename name of a sound file in the VFS
|
/// \param filename name of a sound file in the VFS
|
||||||
|
|
||||||
virtual void say(const std::string& filename) = 0;
|
virtual void say(VFS::Path::NormalizedView filename) = 0;
|
||||||
///< Say some text, without an actor ref
|
///< Say some text, without an actor ref
|
||||||
/// \param filename name of a sound file in the VFS
|
/// \param filename name of a sound file in the VFS
|
||||||
|
|
||||||
|
|
|
@ -202,9 +202,6 @@ namespace MWBase
|
||||||
|
|
||||||
virtual bool getFullHelp() const = 0;
|
virtual bool getFullHelp() const = 0;
|
||||||
|
|
||||||
virtual void setActiveMap(int x, int y, bool interior) = 0;
|
|
||||||
///< set the indices of the map texture that should be used
|
|
||||||
|
|
||||||
/// sets the visibility of the drowning bar
|
/// sets the visibility of the drowning bar
|
||||||
virtual void setDrowningBarVisibility(bool visible) = 0;
|
virtual void setDrowningBarVisibility(bool visible) = 0;
|
||||||
|
|
||||||
|
|
|
@ -304,7 +304,7 @@ namespace MWBase
|
||||||
virtual const MWPhysics::RayCastingInterface* getRayCasting() const = 0;
|
virtual const MWPhysics::RayCastingInterface* getRayCasting() const = 0;
|
||||||
|
|
||||||
virtual bool castRenderingRay(MWPhysics::RayCastingResult& res, const osg::Vec3f& from, const osg::Vec3f& to,
|
virtual bool castRenderingRay(MWPhysics::RayCastingResult& res, const osg::Vec3f& from, const osg::Vec3f& to,
|
||||||
bool ignorePlayer, bool ignoreActors)
|
bool ignorePlayer, bool ignoreActors, std::span<const MWWorld::Ptr> ignoreList = {})
|
||||||
= 0;
|
= 0;
|
||||||
|
|
||||||
virtual void setActorCollisionMode(const MWWorld::Ptr& ptr, bool internal, bool external) = 0;
|
virtual void setActorCollisionMode(const MWWorld::Ptr& ptr, bool internal, bool external) = 0;
|
||||||
|
|
|
@ -104,13 +104,11 @@ namespace MWClass
|
||||||
std::string_view name = getName(ptr);
|
std::string_view name = getName(ptr);
|
||||||
info.caption = MyGUI::TextIterator::toTagsString(MyGUI::UString(name)) + MWGui::ToolTips::getCountString(count);
|
info.caption = MyGUI::TextIterator::toTagsString(MyGUI::UString(name)) + MWGui::ToolTips::getCountString(count);
|
||||||
|
|
||||||
std::string text;
|
|
||||||
if (MWBase::Environment::get().getWindowManager()->getFullHelp())
|
if (MWBase::Environment::get().getWindowManager()->getFullHelp())
|
||||||
{
|
{
|
||||||
text += MWGui::ToolTips::getCellRefString(ptr.getCellRef());
|
info.extra += MWGui::ToolTips::getCellRefString(ptr.getCellRef());
|
||||||
text += MWGui::ToolTips::getMiscString(ref->mBase->mScript.getRefIdString(), "Script");
|
info.extra += MWGui::ToolTips::getMiscString(ref->mBase->mScript.getRefIdString(), "Script");
|
||||||
}
|
}
|
||||||
info.text = std::move(text);
|
|
||||||
|
|
||||||
return info;
|
return info;
|
||||||
}
|
}
|
||||||
|
|
|
@ -102,8 +102,8 @@ namespace MWClass
|
||||||
|
|
||||||
if (MWBase::Environment::get().getWindowManager()->getFullHelp())
|
if (MWBase::Environment::get().getWindowManager()->getFullHelp())
|
||||||
{
|
{
|
||||||
text += MWGui::ToolTips::getCellRefString(ptr.getCellRef());
|
info.extra += MWGui::ToolTips::getCellRefString(ptr.getCellRef());
|
||||||
text += MWGui::ToolTips::getMiscString(ref->mBase->mScript.getRefIdString(), "Script");
|
info.extra += MWGui::ToolTips::getMiscString(ref->mBase->mScript.getRefIdString(), "Script");
|
||||||
}
|
}
|
||||||
info.text = std::move(text);
|
info.text = std::move(text);
|
||||||
|
|
||||||
|
|
|
@ -257,8 +257,8 @@ namespace MWClass
|
||||||
|
|
||||||
if (MWBase::Environment::get().getWindowManager()->getFullHelp())
|
if (MWBase::Environment::get().getWindowManager()->getFullHelp())
|
||||||
{
|
{
|
||||||
text += MWGui::ToolTips::getCellRefString(ptr.getCellRef());
|
info.extra += MWGui::ToolTips::getCellRefString(ptr.getCellRef());
|
||||||
text += MWGui::ToolTips::getMiscString(ref->mBase->mScript.getRefIdString(), "Script");
|
info.extra += MWGui::ToolTips::getMiscString(ref->mBase->mScript.getRefIdString(), "Script");
|
||||||
}
|
}
|
||||||
|
|
||||||
info.enchant = ref->mBase->mEnchant;
|
info.enchant = ref->mBase->mEnchant;
|
||||||
|
|
|
@ -121,8 +121,8 @@ namespace MWClass
|
||||||
|
|
||||||
if (MWBase::Environment::get().getWindowManager()->getFullHelp())
|
if (MWBase::Environment::get().getWindowManager()->getFullHelp())
|
||||||
{
|
{
|
||||||
text += MWGui::ToolTips::getCellRefString(ptr.getCellRef());
|
info.extra += MWGui::ToolTips::getCellRefString(ptr.getCellRef());
|
||||||
text += MWGui::ToolTips::getMiscString(ref->mBase->mScript.getRefIdString(), "Script");
|
info.extra += MWGui::ToolTips::getMiscString(ref->mBase->mScript.getRefIdString(), "Script");
|
||||||
}
|
}
|
||||||
|
|
||||||
info.enchant = ref->mBase->mEnchant;
|
info.enchant = ref->mBase->mEnchant;
|
||||||
|
|
|
@ -164,8 +164,8 @@ namespace MWClass
|
||||||
|
|
||||||
if (MWBase::Environment::get().getWindowManager()->getFullHelp())
|
if (MWBase::Environment::get().getWindowManager()->getFullHelp())
|
||||||
{
|
{
|
||||||
text += MWGui::ToolTips::getCellRefString(ptr.getCellRef());
|
info.extra += MWGui::ToolTips::getCellRefString(ptr.getCellRef());
|
||||||
text += MWGui::ToolTips::getMiscString(ref->mBase->mScript.getRefIdString(), "Script");
|
info.extra += MWGui::ToolTips::getMiscString(ref->mBase->mScript.getRefIdString(), "Script");
|
||||||
}
|
}
|
||||||
|
|
||||||
info.enchant = ref->mBase->mEnchant;
|
info.enchant = ref->mBase->mEnchant;
|
||||||
|
|
|
@ -265,10 +265,10 @@ namespace MWClass
|
||||||
|
|
||||||
if (MWBase::Environment::get().getWindowManager()->getFullHelp())
|
if (MWBase::Environment::get().getWindowManager()->getFullHelp())
|
||||||
{
|
{
|
||||||
text += MWGui::ToolTips::getCellRefString(ptr.getCellRef());
|
info.extra += MWGui::ToolTips::getCellRefString(ptr.getCellRef());
|
||||||
text += MWGui::ToolTips::getMiscString(ref->mBase->mScript.getRefIdString(), "Script");
|
info.extra += MWGui::ToolTips::getMiscString(ref->mBase->mScript.getRefIdString(), "Script");
|
||||||
if (ptr.getCellRef().getRefId() == "stolen_goods")
|
if (ptr.getCellRef().getRefId() == "stolen_goods")
|
||||||
text += "\nYou can not use evidence chests";
|
info.extra += "\nYou cannot use evidence chests";
|
||||||
}
|
}
|
||||||
|
|
||||||
info.text = std::move(text);
|
info.text = std::move(text);
|
||||||
|
|
|
@ -316,11 +316,11 @@ namespace MWClass
|
||||||
{
|
{
|
||||||
const unsigned char* attack = nullptr;
|
const unsigned char* attack = nullptr;
|
||||||
if (type == ESM::Weapon::AT_Chop)
|
if (type == ESM::Weapon::AT_Chop)
|
||||||
attack = weapon.get<ESM::Weapon>()->mBase->mData.mChop;
|
attack = weapon.get<ESM::Weapon>()->mBase->mData.mChop.data();
|
||||||
else if (type == ESM::Weapon::AT_Slash)
|
else if (type == ESM::Weapon::AT_Slash)
|
||||||
attack = weapon.get<ESM::Weapon>()->mBase->mData.mSlash;
|
attack = weapon.get<ESM::Weapon>()->mBase->mData.mSlash.data();
|
||||||
else if (type == ESM::Weapon::AT_Thrust)
|
else if (type == ESM::Weapon::AT_Thrust)
|
||||||
attack = weapon.get<ESM::Weapon>()->mBase->mData.mThrust;
|
attack = weapon.get<ESM::Weapon>()->mBase->mData.mThrust.data();
|
||||||
if (attack)
|
if (attack)
|
||||||
{
|
{
|
||||||
damage = attack[0] + ((attack[1] - attack[0]) * attackStrength);
|
damage = attack[0] + ((attack[1] - attack[0]) * attackStrength);
|
||||||
|
@ -474,20 +474,17 @@ namespace MWClass
|
||||||
}
|
}
|
||||||
|
|
||||||
const MWMechanics::CreatureStats& stats = getCreatureStats(ptr);
|
const MWMechanics::CreatureStats& stats = getCreatureStats(ptr);
|
||||||
const MWMechanics::AiSequence& aiSequence = stats.getAiSequence();
|
|
||||||
|
|
||||||
const bool isInCombat = aiSequence.isInCombat();
|
|
||||||
if (stats.isDead())
|
if (stats.isDead())
|
||||||
{
|
{
|
||||||
// by default user can loot friendly actors during death animation
|
// by default user can loot non-fighting actors during death animation
|
||||||
if (Settings::game().mCanLootDuringDeathAnimation && !isInCombat)
|
if (Settings::game().mCanLootDuringDeathAnimation)
|
||||||
return std::make_unique<MWWorld::ActionOpen>(ptr);
|
return std::make_unique<MWWorld::ActionOpen>(ptr);
|
||||||
|
|
||||||
// otherwise wait until death animation
|
// otherwise wait until death animation
|
||||||
if (stats.isDeathAnimationFinished())
|
if (stats.isDeathAnimationFinished())
|
||||||
return std::make_unique<MWWorld::ActionOpen>(ptr);
|
return std::make_unique<MWWorld::ActionOpen>(ptr);
|
||||||
}
|
}
|
||||||
else if ((!isInCombat || aiSequence.isFleeing()) && !stats.getKnockedDown())
|
else if (!stats.getKnockedDown())
|
||||||
return std::make_unique<MWWorld::ActionTalk>(ptr);
|
return std::make_unique<MWWorld::ActionTalk>(ptr);
|
||||||
|
|
||||||
// Tribunal and some mod companions oddly enough must use open action as fallback
|
// Tribunal and some mod companions oddly enough must use open action as fallback
|
||||||
|
@ -594,10 +591,8 @@ namespace MWClass
|
||||||
std::string_view name = getName(ptr);
|
std::string_view name = getName(ptr);
|
||||||
info.caption = MyGUI::TextIterator::toTagsString(MyGUI::UString(name));
|
info.caption = MyGUI::TextIterator::toTagsString(MyGUI::UString(name));
|
||||||
|
|
||||||
std::string text;
|
|
||||||
if (MWBase::Environment::get().getWindowManager()->getFullHelp())
|
if (MWBase::Environment::get().getWindowManager()->getFullHelp())
|
||||||
text += MWGui::ToolTips::getMiscString(ref->mBase->mScript.getRefIdString(), "Script");
|
info.extra += MWGui::ToolTips::getMiscString(ref->mBase->mScript.getRefIdString(), "Script");
|
||||||
info.text = std::move(text);
|
|
||||||
|
|
||||||
return info;
|
return info;
|
||||||
}
|
}
|
||||||
|
|
|
@ -290,8 +290,8 @@ namespace MWClass
|
||||||
|
|
||||||
if (MWBase::Environment::get().getWindowManager()->getFullHelp())
|
if (MWBase::Environment::get().getWindowManager()->getFullHelp())
|
||||||
{
|
{
|
||||||
text += MWGui::ToolTips::getCellRefString(ptr.getCellRef());
|
info.extra += MWGui::ToolTips::getCellRefString(ptr.getCellRef());
|
||||||
text += MWGui::ToolTips::getMiscString(ref->mBase->mScript.getRefIdString(), "Script");
|
info.extra += MWGui::ToolTips::getMiscString(ref->mBase->mScript.getRefIdString(), "Script");
|
||||||
}
|
}
|
||||||
info.text = std::move(text);
|
info.text = std::move(text);
|
||||||
|
|
||||||
|
|
|
@ -103,7 +103,7 @@ namespace MWClass
|
||||||
// Hide meshes meshes/marker/* and *LOD.nif in ESM4 cells. It is a temporarty hack.
|
// Hide meshes meshes/marker/* and *LOD.nif in ESM4 cells. It is a temporarty hack.
|
||||||
// Needed because otherwise LOD meshes are rendered on top of normal meshes.
|
// Needed because otherwise LOD meshes are rendered on top of normal meshes.
|
||||||
// TODO: Figure out a better way find markers and LOD meshes; show LOD only outside of active grid.
|
// TODO: Figure out a better way find markers and LOD meshes; show LOD only outside of active grid.
|
||||||
if (model.empty() || Misc::StringUtils::ciStartsWith(model, "meshes\\marker")
|
if (model.empty() || Misc::StringUtils::ciStartsWith(model, "marker")
|
||||||
|| Misc::StringUtils::ciEndsWith(model, "lod.nif"))
|
|| Misc::StringUtils::ciEndsWith(model, "lod.nif"))
|
||||||
return {};
|
return {};
|
||||||
|
|
||||||
|
|
|
@ -117,8 +117,8 @@ namespace MWClass
|
||||||
|
|
||||||
if (MWBase::Environment::get().getWindowManager()->getFullHelp())
|
if (MWBase::Environment::get().getWindowManager()->getFullHelp())
|
||||||
{
|
{
|
||||||
text += MWGui::ToolTips::getCellRefString(ptr.getCellRef());
|
info.extra += MWGui::ToolTips::getCellRefString(ptr.getCellRef());
|
||||||
text += MWGui::ToolTips::getMiscString(ref->mBase->mScript.getRefIdString(), "Script");
|
info.extra += MWGui::ToolTips::getMiscString(ref->mBase->mScript.getRefIdString(), "Script");
|
||||||
}
|
}
|
||||||
|
|
||||||
MWWorld::Ptr player = MWBase::Environment::get().getWorld()->getPlayerPtr();
|
MWWorld::Ptr player = MWBase::Environment::get().getWorld()->getPlayerPtr();
|
||||||
|
|
|
@ -173,8 +173,8 @@ namespace MWClass
|
||||||
|
|
||||||
if (MWBase::Environment::get().getWindowManager()->getFullHelp())
|
if (MWBase::Environment::get().getWindowManager()->getFullHelp())
|
||||||
{
|
{
|
||||||
text += MWGui::ToolTips::getCellRefString(ptr.getCellRef());
|
info.extra += MWGui::ToolTips::getCellRefString(ptr.getCellRef());
|
||||||
text += MWGui::ToolTips::getMiscString(ref->mBase->mScript.getRefIdString(), "Script");
|
info.extra += MWGui::ToolTips::getMiscString(ref->mBase->mScript.getRefIdString(), "Script");
|
||||||
}
|
}
|
||||||
|
|
||||||
info.text = std::move(text);
|
info.text = std::move(text);
|
||||||
|
|
|
@ -118,8 +118,8 @@ namespace MWClass
|
||||||
|
|
||||||
if (MWBase::Environment::get().getWindowManager()->getFullHelp())
|
if (MWBase::Environment::get().getWindowManager()->getFullHelp())
|
||||||
{
|
{
|
||||||
text += MWGui::ToolTips::getCellRefString(ptr.getCellRef());
|
info.extra += MWGui::ToolTips::getCellRefString(ptr.getCellRef());
|
||||||
text += MWGui::ToolTips::getMiscString(ref->mBase->mScript.getRefIdString(), "Script");
|
info.extra += MWGui::ToolTips::getMiscString(ref->mBase->mScript.getRefIdString(), "Script");
|
||||||
}
|
}
|
||||||
|
|
||||||
info.text = std::move(text);
|
info.text = std::move(text);
|
||||||
|
|
|
@ -163,8 +163,8 @@ namespace MWClass
|
||||||
|
|
||||||
if (MWBase::Environment::get().getWindowManager()->getFullHelp())
|
if (MWBase::Environment::get().getWindowManager()->getFullHelp())
|
||||||
{
|
{
|
||||||
text += MWGui::ToolTips::getCellRefString(ptr.getCellRef());
|
info.extra += MWGui::ToolTips::getCellRefString(ptr.getCellRef());
|
||||||
text += MWGui::ToolTips::getMiscString(ref->mBase->mScript.getRefIdString(), "Script");
|
info.extra += MWGui::ToolTips::getMiscString(ref->mBase->mScript.getRefIdString(), "Script");
|
||||||
}
|
}
|
||||||
|
|
||||||
info.text = std::move(text);
|
info.text = std::move(text);
|
||||||
|
|
|
@ -23,6 +23,7 @@
|
||||||
|
|
||||||
#include "../mwbase/dialoguemanager.hpp"
|
#include "../mwbase/dialoguemanager.hpp"
|
||||||
#include "../mwbase/environment.hpp"
|
#include "../mwbase/environment.hpp"
|
||||||
|
#include "../mwbase/luamanager.hpp"
|
||||||
#include "../mwbase/mechanicsmanager.hpp"
|
#include "../mwbase/mechanicsmanager.hpp"
|
||||||
#include "../mwbase/soundmanager.hpp"
|
#include "../mwbase/soundmanager.hpp"
|
||||||
#include "../mwbase/windowmanager.hpp"
|
#include "../mwbase/windowmanager.hpp"
|
||||||
|
@ -634,11 +635,11 @@ namespace MWClass
|
||||||
{
|
{
|
||||||
const unsigned char* attack = nullptr;
|
const unsigned char* attack = nullptr;
|
||||||
if (type == ESM::Weapon::AT_Chop)
|
if (type == ESM::Weapon::AT_Chop)
|
||||||
attack = weapon.get<ESM::Weapon>()->mBase->mData.mChop;
|
attack = weapon.get<ESM::Weapon>()->mBase->mData.mChop.data();
|
||||||
else if (type == ESM::Weapon::AT_Slash)
|
else if (type == ESM::Weapon::AT_Slash)
|
||||||
attack = weapon.get<ESM::Weapon>()->mBase->mData.mSlash;
|
attack = weapon.get<ESM::Weapon>()->mBase->mData.mSlash.data();
|
||||||
else if (type == ESM::Weapon::AT_Thrust)
|
else if (type == ESM::Weapon::AT_Thrust)
|
||||||
attack = weapon.get<ESM::Weapon>()->mBase->mData.mThrust;
|
attack = weapon.get<ESM::Weapon>()->mBase->mData.mThrust.data();
|
||||||
if (attack)
|
if (attack)
|
||||||
{
|
{
|
||||||
damage = attack[0] + ((attack[1] - attack[0]) * attackStrength);
|
damage = attack[0] + ((attack[1] - attack[0]) * attackStrength);
|
||||||
|
@ -662,7 +663,7 @@ namespace MWClass
|
||||||
ESM::RefId weapskill = ESM::Skill::HandToHand;
|
ESM::RefId weapskill = ESM::Skill::HandToHand;
|
||||||
if (!weapon.isEmpty())
|
if (!weapon.isEmpty())
|
||||||
weapskill = weapon.getClass().getEquipmentSkill(weapon);
|
weapskill = weapon.getClass().getEquipmentSkill(weapon);
|
||||||
skillUsageSucceeded(ptr, weapskill, 0);
|
skillUsageSucceeded(ptr, weapskill, ESM::Skill::Weapon_SuccessfulHit);
|
||||||
|
|
||||||
const MWMechanics::AiSequence& seq = victim.getClass().getCreatureStats(victim).getAiSequence();
|
const MWMechanics::AiSequence& seq = victim.getClass().getCreatureStats(victim).getAiSequence();
|
||||||
|
|
||||||
|
@ -852,7 +853,7 @@ namespace MWClass
|
||||||
|
|
||||||
ESM::RefId skill = armor.getClass().getEquipmentSkill(armor);
|
ESM::RefId skill = armor.getClass().getEquipmentSkill(armor);
|
||||||
if (ptr == MWMechanics::getPlayer())
|
if (ptr == MWMechanics::getPlayer())
|
||||||
skillUsageSucceeded(ptr, skill, 0);
|
skillUsageSucceeded(ptr, skill, ESM::Skill::Armor_HitByOpponent);
|
||||||
|
|
||||||
if (skill == ESM::Skill::LightArmor)
|
if (skill == ESM::Skill::LightArmor)
|
||||||
sndMgr->playSound3D(ptr, ESM::RefId::stringRefId("Light Armor Hit"), 1.0f, 1.0f);
|
sndMgr->playSound3D(ptr, ESM::RefId::stringRefId("Light Armor Hit"), 1.0f, 1.0f);
|
||||||
|
@ -862,7 +863,7 @@ namespace MWClass
|
||||||
sndMgr->playSound3D(ptr, ESM::RefId::stringRefId("Heavy Armor Hit"), 1.0f, 1.0f);
|
sndMgr->playSound3D(ptr, ESM::RefId::stringRefId("Heavy Armor Hit"), 1.0f, 1.0f);
|
||||||
}
|
}
|
||||||
else if (ptr == MWMechanics::getPlayer())
|
else if (ptr == MWMechanics::getPlayer())
|
||||||
skillUsageSucceeded(ptr, ESM::Skill::Unarmored, 0);
|
skillUsageSucceeded(ptr, ESM::Skill::Unarmored, ESM::Skill::Armor_HitByOpponent);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -924,35 +925,38 @@ namespace MWClass
|
||||||
}
|
}
|
||||||
|
|
||||||
const MWMechanics::CreatureStats& stats = getCreatureStats(ptr);
|
const MWMechanics::CreatureStats& stats = getCreatureStats(ptr);
|
||||||
|
const MWMechanics::AiSequence& aiSequence = stats.getAiSequence();
|
||||||
|
const bool isPursuing = aiSequence.isInPursuit() && actor == MWMechanics::getPlayer();
|
||||||
|
const bool inCombatWithActor = aiSequence.isInCombat(actor) || isPursuing;
|
||||||
|
|
||||||
if (stats.isDead())
|
if (stats.isDead())
|
||||||
{
|
{
|
||||||
// by default user can loot friendly actors during death animation
|
// by default user can loot non-fighting actors during death animation
|
||||||
if (Settings::game().mCanLootDuringDeathAnimation && !stats.getAiSequence().isInCombat())
|
if (Settings::game().mCanLootDuringDeathAnimation)
|
||||||
return std::make_unique<MWWorld::ActionOpen>(ptr);
|
return std::make_unique<MWWorld::ActionOpen>(ptr);
|
||||||
|
|
||||||
// otherwise wait until death animation
|
// otherwise wait until death animation
|
||||||
if (stats.isDeathAnimationFinished())
|
if (stats.isDeathAnimationFinished())
|
||||||
return std::make_unique<MWWorld::ActionOpen>(ptr);
|
return std::make_unique<MWWorld::ActionOpen>(ptr);
|
||||||
}
|
}
|
||||||
else if (!stats.getAiSequence().isInCombat())
|
else
|
||||||
{
|
{
|
||||||
if (stats.getKnockedDown() || MWBase::Environment::get().getMechanicsManager()->isSneaking(actor))
|
const bool allowStealingFromKO
|
||||||
return std::make_unique<MWWorld::ActionOpen>(ptr); // stealing
|
= Settings::game().mAlwaysAllowStealingFromKnockedOutActors || !inCombatWithActor;
|
||||||
|
if (stats.getKnockedDown() && allowStealingFromKO)
|
||||||
|
return std::make_unique<MWWorld::ActionOpen>(ptr);
|
||||||
|
|
||||||
// Can't talk to werewolves
|
const bool allowStealingWhileSneaking = !inCombatWithActor;
|
||||||
if (!getNpcStats(ptr).isWerewolf())
|
if (MWBase::Environment::get().getMechanicsManager()->isSneaking(actor) && allowStealingWhileSneaking)
|
||||||
|
return std::make_unique<MWWorld::ActionOpen>(ptr);
|
||||||
|
|
||||||
|
const bool allowTalking = !inCombatWithActor && !getNpcStats(ptr).isWerewolf();
|
||||||
|
if (allowTalking)
|
||||||
return std::make_unique<MWWorld::ActionTalk>(ptr);
|
return std::make_unique<MWWorld::ActionTalk>(ptr);
|
||||||
}
|
}
|
||||||
else // In combat
|
|
||||||
{
|
|
||||||
if (Settings::game().mAlwaysAllowStealingFromKnockedOutActors && stats.getKnockedDown())
|
|
||||||
return std::make_unique<MWWorld::ActionOpen>(ptr); // stealing
|
|
||||||
}
|
|
||||||
|
|
||||||
// Tribunal and some mod companions oddly enough must use open action as fallback
|
if (inCombatWithActor)
|
||||||
if (!getScript(ptr).empty() && ptr.getRefData().getLocals().getIntVar(getScript(ptr), "companion"))
|
return std::make_unique<MWWorld::FailedAction>("#{sActorInCombat}");
|
||||||
return std::make_unique<MWWorld::ActionOpen>(ptr);
|
|
||||||
|
|
||||||
return std::make_unique<MWWorld::FailedAction>();
|
return std::make_unique<MWWorld::FailedAction>();
|
||||||
}
|
}
|
||||||
|
@ -1086,7 +1090,8 @@ namespace MWClass
|
||||||
if (customData.mNpcStats.isDead() && customData.mNpcStats.isDeathAnimationFinished())
|
if (customData.mNpcStats.isDead() && customData.mNpcStats.isDeathAnimationFinished())
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
if (!customData.mNpcStats.getAiSequence().isInCombat())
|
const MWMechanics::AiSequence& aiSeq = customData.mNpcStats.getAiSequence();
|
||||||
|
if (!aiSeq.isInCombat() || aiSeq.isFleeing())
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
if (Settings::game().mAlwaysAllowStealingFromKnockedOutActors && customData.mNpcStats.getKnockedDown())
|
if (Settings::game().mAlwaysAllowStealingFromKnockedOutActors && customData.mNpcStats.getKnockedDown())
|
||||||
|
@ -1113,7 +1118,7 @@ namespace MWClass
|
||||||
}
|
}
|
||||||
|
|
||||||
if (fullHelp)
|
if (fullHelp)
|
||||||
info.text = MWGui::ToolTips::getMiscString(ref->mBase->mScript.getRefIdString(), "Script");
|
info.extra = MWGui::ToolTips::getMiscString(ref->mBase->mScript.getRefIdString(), "Script");
|
||||||
|
|
||||||
return info;
|
return info;
|
||||||
}
|
}
|
||||||
|
@ -1138,16 +1143,7 @@ namespace MWClass
|
||||||
|
|
||||||
void Npc::skillUsageSucceeded(const MWWorld::Ptr& ptr, ESM::RefId skill, int usageType, float extraFactor) const
|
void Npc::skillUsageSucceeded(const MWWorld::Ptr& ptr, ESM::RefId skill, int usageType, float extraFactor) const
|
||||||
{
|
{
|
||||||
MWMechanics::NpcStats& stats = getNpcStats(ptr);
|
MWBase::Environment::get().getLuaManager()->skillUse(ptr, skill, usageType, extraFactor);
|
||||||
|
|
||||||
if (stats.isWerewolf())
|
|
||||||
return;
|
|
||||||
|
|
||||||
MWWorld::LiveCellRef<ESM::NPC>* ref = ptr.get<ESM::NPC>();
|
|
||||||
|
|
||||||
const ESM::Class* class_ = MWBase::Environment::get().getESMStore()->get<ESM::Class>().find(ref->mBase->mClass);
|
|
||||||
|
|
||||||
stats.useSkill(skill, *class_, usageType, extraFactor);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
float Npc::getArmorRating(const MWWorld::Ptr& ptr) const
|
float Npc::getArmorRating(const MWWorld::Ptr& ptr) const
|
||||||
|
|
|
@ -19,6 +19,7 @@
|
||||||
#include "../mwrender/renderinginterface.hpp"
|
#include "../mwrender/renderinginterface.hpp"
|
||||||
|
|
||||||
#include "../mwmechanics/alchemy.hpp"
|
#include "../mwmechanics/alchemy.hpp"
|
||||||
|
#include "../mwmechanics/spellutil.hpp"
|
||||||
|
|
||||||
#include "classmodel.hpp"
|
#include "classmodel.hpp"
|
||||||
|
|
||||||
|
@ -65,9 +66,7 @@ namespace MWClass
|
||||||
|
|
||||||
int Potion::getValue(const MWWorld::ConstPtr& ptr) const
|
int Potion::getValue(const MWWorld::ConstPtr& ptr) const
|
||||||
{
|
{
|
||||||
const MWWorld::LiveCellRef<ESM::Potion>* ref = ptr.get<ESM::Potion>();
|
return MWMechanics::getPotionValue(*ptr.get<ESM::Potion>()->mBase);
|
||||||
|
|
||||||
return ref->mBase->mData.mValue;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const ESM::RefId& Potion::getUpSoundId(const MWWorld::ConstPtr& ptr) const
|
const ESM::RefId& Potion::getUpSoundId(const MWWorld::ConstPtr& ptr) const
|
||||||
|
@ -101,7 +100,7 @@ namespace MWClass
|
||||||
std::string text;
|
std::string text;
|
||||||
|
|
||||||
text += "\n#{sWeight}: " + MWGui::ToolTips::toString(ref->mBase->mData.mWeight);
|
text += "\n#{sWeight}: " + MWGui::ToolTips::toString(ref->mBase->mData.mWeight);
|
||||||
text += MWGui::ToolTips::getValueString(ref->mBase->mData.mValue, "#{sValue}");
|
text += MWGui::ToolTips::getValueString(getValue(ptr), "#{sValue}");
|
||||||
|
|
||||||
info.effects = MWGui::Widgets::MWEffectList::effectListFromESM(&ref->mBase->mEffects);
|
info.effects = MWGui::Widgets::MWEffectList::effectListFromESM(&ref->mBase->mEffects);
|
||||||
|
|
||||||
|
@ -114,8 +113,8 @@ namespace MWClass
|
||||||
|
|
||||||
if (MWBase::Environment::get().getWindowManager()->getFullHelp())
|
if (MWBase::Environment::get().getWindowManager()->getFullHelp())
|
||||||
{
|
{
|
||||||
text += MWGui::ToolTips::getCellRefString(ptr.getCellRef());
|
info.extra += MWGui::ToolTips::getCellRefString(ptr.getCellRef());
|
||||||
text += MWGui::ToolTips::getMiscString(ref->mBase->mScript.getRefIdString(), "Script");
|
info.extra += MWGui::ToolTips::getMiscString(ref->mBase->mScript.getRefIdString(), "Script");
|
||||||
}
|
}
|
||||||
|
|
||||||
info.text = std::move(text);
|
info.text = std::move(text);
|
||||||
|
|
|
@ -117,8 +117,8 @@ namespace MWClass
|
||||||
|
|
||||||
if (MWBase::Environment::get().getWindowManager()->getFullHelp())
|
if (MWBase::Environment::get().getWindowManager()->getFullHelp())
|
||||||
{
|
{
|
||||||
text += MWGui::ToolTips::getCellRefString(ptr.getCellRef());
|
info.extra += MWGui::ToolTips::getCellRefString(ptr.getCellRef());
|
||||||
text += MWGui::ToolTips::getMiscString(ref->mBase->mScript.getRefIdString(), "Script");
|
info.extra += MWGui::ToolTips::getMiscString(ref->mBase->mScript.getRefIdString(), "Script");
|
||||||
}
|
}
|
||||||
|
|
||||||
info.text = std::move(text);
|
info.text = std::move(text);
|
||||||
|
|
|
@ -119,8 +119,8 @@ namespace MWClass
|
||||||
|
|
||||||
if (MWBase::Environment::get().getWindowManager()->getFullHelp())
|
if (MWBase::Environment::get().getWindowManager()->getFullHelp())
|
||||||
{
|
{
|
||||||
text += MWGui::ToolTips::getCellRefString(ptr.getCellRef());
|
info.extra += MWGui::ToolTips::getCellRefString(ptr.getCellRef());
|
||||||
text += MWGui::ToolTips::getMiscString(ref->mBase->mScript.getRefIdString(), "Script");
|
info.extra += MWGui::ToolTips::getMiscString(ref->mBase->mScript.getRefIdString(), "Script");
|
||||||
}
|
}
|
||||||
|
|
||||||
info.text = std::move(text);
|
info.text = std::move(text);
|
||||||
|
|
|
@ -239,8 +239,8 @@ namespace MWClass
|
||||||
|
|
||||||
if (MWBase::Environment::get().getWindowManager()->getFullHelp())
|
if (MWBase::Environment::get().getWindowManager()->getFullHelp())
|
||||||
{
|
{
|
||||||
text += MWGui::ToolTips::getCellRefString(ptr.getCellRef());
|
info.extra += MWGui::ToolTips::getCellRefString(ptr.getCellRef());
|
||||||
text += MWGui::ToolTips::getMiscString(ref->mBase->mScript.getRefIdString(), "Script");
|
info.extra += MWGui::ToolTips::getMiscString(ref->mBase->mScript.getRefIdString(), "Script");
|
||||||
}
|
}
|
||||||
|
|
||||||
info.text = std::move(text);
|
info.text = std::move(text);
|
||||||
|
|
|
@ -543,7 +543,8 @@ namespace MWDialogue
|
||||||
mPermanentDispositionChange += perm;
|
mPermanentDispositionChange += perm;
|
||||||
|
|
||||||
MWWorld::Ptr player = MWMechanics::getPlayer();
|
MWWorld::Ptr player = MWMechanics::getPlayer();
|
||||||
player.getClass().skillUsageSucceeded(player, ESM::Skill::Speechcraft, success ? 0 : 1);
|
player.getClass().skillUsageSucceeded(
|
||||||
|
player, ESM::Skill::Speechcraft, success ? ESM::Skill::Speechcraft_Success : ESM::Skill::Speechcraft_Fail);
|
||||||
|
|
||||||
if (success)
|
if (success)
|
||||||
{
|
{
|
||||||
|
@ -652,7 +653,7 @@ namespace MWDialogue
|
||||||
if (Settings::gui().mSubtitles)
|
if (Settings::gui().mSubtitles)
|
||||||
winMgr->messageBox(info->mResponse);
|
winMgr->messageBox(info->mResponse);
|
||||||
if (!info->mSound.empty())
|
if (!info->mSound.empty())
|
||||||
sndMgr->say(actor, Misc::ResourceHelpers::correctSoundPath(info->mSound));
|
sndMgr->say(actor, Misc::ResourceHelpers::correctSoundPath(VFS::Path::Normalized(info->mSound)));
|
||||||
if (!info->mResultScript.empty())
|
if (!info->mResultScript.empty())
|
||||||
executeScript(info->mResultScript, actor);
|
executeScript(info->mResultScript, actor);
|
||||||
}
|
}
|
||||||
|
|
|
@ -39,7 +39,7 @@ namespace
|
||||||
{
|
{
|
||||||
const std::string mText;
|
const std::string mText;
|
||||||
const Response mResponses[3];
|
const Response mResponses[3];
|
||||||
const std::string mSound;
|
const VFS::Path::Normalized mSound;
|
||||||
};
|
};
|
||||||
|
|
||||||
Step sGenerateClassSteps(int number)
|
Step sGenerateClassSteps(int number)
|
||||||
|
|
|
@ -164,8 +164,10 @@ namespace MWGui
|
||||||
const MWMechanics::NpcStats& pcStats = player.getClass().getNpcStats(player);
|
const MWMechanics::NpcStats& pcStats = player.getClass().getNpcStats(player);
|
||||||
|
|
||||||
setClassImage(mClassImage,
|
setClassImage(mClassImage,
|
||||||
ESM::RefId::stringRefId(getLevelupClassImage(pcStats.getSkillIncreasesForSpecialization(0),
|
ESM::RefId::stringRefId(
|
||||||
pcStats.getSkillIncreasesForSpecialization(1), pcStats.getSkillIncreasesForSpecialization(2))));
|
getLevelupClassImage(pcStats.getSkillIncreasesForSpecialization(ESM::Class::Specialization::Combat),
|
||||||
|
pcStats.getSkillIncreasesForSpecialization(ESM::Class::Specialization::Magic),
|
||||||
|
pcStats.getSkillIncreasesForSpecialization(ESM::Class::Specialization::Stealth))));
|
||||||
|
|
||||||
int level = creatureStats.getLevel() + 1;
|
int level = creatureStats.getLevel() + 1;
|
||||||
mLevelText->setCaptionWithReplacing("#{sLevelUpMenu1} " + MyGUI::utility::toString(level));
|
mLevelText->setCaptionWithReplacing("#{sLevelUpMenu1} " + MyGUI::utility::toString(level));
|
||||||
|
|
|
@ -95,6 +95,13 @@ namespace
|
||||||
return std::clamp(
|
return std::clamp(
|
||||||
viewingDistanceInCells, Constants::CellGridRadius, Settings::map().mMaxLocalViewingDistance.get());
|
viewingDistanceInCells, Constants::CellGridRadius, Settings::map().mMaxLocalViewingDistance.get());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ESM::RefId getCellIdInWorldSpace(const MWWorld::Cell& cell, int x, int y)
|
||||||
|
{
|
||||||
|
if (cell.isExterior())
|
||||||
|
return ESM::Cell::generateIdForCell(true, {}, x, y);
|
||||||
|
return cell.getId();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
namespace MWGui
|
namespace MWGui
|
||||||
|
@ -170,12 +177,9 @@ namespace MWGui
|
||||||
LocalMapBase::LocalMapBase(
|
LocalMapBase::LocalMapBase(
|
||||||
CustomMarkerCollection& markers, MWRender::LocalMap* localMapRender, bool fogOfWarEnabled)
|
CustomMarkerCollection& markers, MWRender::LocalMap* localMapRender, bool fogOfWarEnabled)
|
||||||
: mLocalMapRender(localMapRender)
|
: mLocalMapRender(localMapRender)
|
||||||
, mCurX(0)
|
, mActiveCell(nullptr)
|
||||||
, mCurY(0)
|
|
||||||
, mInterior(false)
|
|
||||||
, mLocalMap(nullptr)
|
, mLocalMap(nullptr)
|
||||||
, mCompass(nullptr)
|
, mCompass(nullptr)
|
||||||
, mChanged(true)
|
|
||||||
, mFogOfWarToggled(true)
|
, mFogOfWarToggled(true)
|
||||||
, mFogOfWarEnabled(fogOfWarEnabled)
|
, mFogOfWarEnabled(fogOfWarEnabled)
|
||||||
, mNumCells(1)
|
, mNumCells(1)
|
||||||
|
@ -231,12 +235,6 @@ namespace MWGui
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void LocalMapBase::setCellPrefix(const std::string& prefix)
|
|
||||||
{
|
|
||||||
mPrefix = prefix;
|
|
||||||
mChanged = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool LocalMapBase::toggleFogOfWar()
|
bool LocalMapBase::toggleFogOfWar()
|
||||||
{
|
{
|
||||||
mFogOfWarToggled = !mFogOfWarToggled;
|
mFogOfWarToggled = !mFogOfWarToggled;
|
||||||
|
@ -262,8 +260,8 @@ namespace MWGui
|
||||||
{
|
{
|
||||||
// normalized cell coordinates
|
// normalized cell coordinates
|
||||||
auto mapWidgetSize = getWidgetSize();
|
auto mapWidgetSize = getWidgetSize();
|
||||||
return MyGUI::IntPoint(std::round(nX * mapWidgetSize + (mCellDistance + (cellX - mCurX)) * mapWidgetSize),
|
return MyGUI::IntPoint(std::round((nX + mCellDistance + cellX - mActiveCell->getGridX()) * mapWidgetSize),
|
||||||
std::round(nY * mapWidgetSize + (mCellDistance - (cellY - mCurY)) * mapWidgetSize));
|
std::round((nY + mCellDistance - cellY + mActiveCell->getGridY()) * mapWidgetSize));
|
||||||
}
|
}
|
||||||
|
|
||||||
MyGUI::IntPoint LocalMapBase::getMarkerPosition(float worldX, float worldY, MarkerUserData& markerPos) const
|
MyGUI::IntPoint LocalMapBase::getMarkerPosition(float worldX, float worldY, MarkerUserData& markerPos) const
|
||||||
|
@ -272,7 +270,7 @@ namespace MWGui
|
||||||
// normalized cell coordinates
|
// normalized cell coordinates
|
||||||
float nX, nY;
|
float nX, nY;
|
||||||
|
|
||||||
if (!mInterior)
|
if (mActiveCell->isExterior())
|
||||||
{
|
{
|
||||||
ESM::ExteriorCellLocation cellPos = ESM::positionToExteriorCellLocation(worldX, worldY);
|
ESM::ExteriorCellLocation cellPos = ESM::positionToExteriorCellLocation(worldX, worldY);
|
||||||
cellIndex.x() = cellPos.mX;
|
cellIndex.x() = cellPos.mX;
|
||||||
|
@ -336,7 +334,7 @@ namespace MWGui
|
||||||
|
|
||||||
std::vector<MyGUI::Widget*>& LocalMapBase::currentDoorMarkersWidgets()
|
std::vector<MyGUI::Widget*>& LocalMapBase::currentDoorMarkersWidgets()
|
||||||
{
|
{
|
||||||
return mInterior ? mInteriorDoorMarkerWidgets : mExteriorDoorMarkerWidgets;
|
return mActiveCell->isExterior() ? mExteriorDoorMarkerWidgets : mInteriorDoorMarkerWidgets;
|
||||||
}
|
}
|
||||||
|
|
||||||
void LocalMapBase::updateCustomMarkers()
|
void LocalMapBase::updateCustomMarkers()
|
||||||
|
@ -344,12 +342,14 @@ namespace MWGui
|
||||||
for (MyGUI::Widget* widget : mCustomMarkerWidgets)
|
for (MyGUI::Widget* widget : mCustomMarkerWidgets)
|
||||||
MyGUI::Gui::getInstance().destroyWidget(widget);
|
MyGUI::Gui::getInstance().destroyWidget(widget);
|
||||||
mCustomMarkerWidgets.clear();
|
mCustomMarkerWidgets.clear();
|
||||||
|
if (!mActiveCell)
|
||||||
|
return;
|
||||||
for (int dX = -mCellDistance; dX <= mCellDistance; ++dX)
|
for (int dX = -mCellDistance; dX <= mCellDistance; ++dX)
|
||||||
{
|
{
|
||||||
for (int dY = -mCellDistance; dY <= mCellDistance; ++dY)
|
for (int dY = -mCellDistance; dY <= mCellDistance; ++dY)
|
||||||
{
|
{
|
||||||
ESM::RefId cellRefId = ESM::Cell::generateIdForCell(!mInterior, mPrefix, mCurX + dX, mCurY + dY);
|
ESM::RefId cellRefId
|
||||||
|
= getCellIdInWorldSpace(*mActiveCell, mActiveCell->getGridX() + dX, mActiveCell->getGridY() + dY);
|
||||||
|
|
||||||
CustomMarkerCollection::RangeType markers = mCustomMarkers.getMarkers(cellRefId);
|
CustomMarkerCollection::RangeType markers = mCustomMarkers.getMarkers(cellRefId);
|
||||||
for (CustomMarkerCollection::ContainerType::const_iterator it = markers.first; it != markers.second;
|
for (CustomMarkerCollection::ContainerType::const_iterator it = markers.first; it != markers.second;
|
||||||
|
@ -377,16 +377,25 @@ namespace MWGui
|
||||||
redraw();
|
redraw();
|
||||||
}
|
}
|
||||||
|
|
||||||
void LocalMapBase::setActiveCell(const int x, const int y, bool interior)
|
void LocalMapBase::setActiveCell(const MWWorld::Cell& cell)
|
||||||
{
|
{
|
||||||
if (x == mCurX && y == mCurY && mInterior == interior && !mChanged)
|
if (&cell == mActiveCell)
|
||||||
return; // don't do anything if we're still in the same cell
|
return; // don't do anything if we're still in the same cell
|
||||||
|
|
||||||
if (!interior && !(x == mCurX && y == mCurY))
|
const int x = cell.getGridX();
|
||||||
|
const int y = cell.getGridY();
|
||||||
|
|
||||||
|
if (cell.isExterior())
|
||||||
{
|
{
|
||||||
const MyGUI::IntRect intersection
|
int curX = 0;
|
||||||
= { std::max(x, mCurX) - mCellDistance, std::max(y, mCurY) - mCellDistance,
|
int curY = 0;
|
||||||
std::min(x, mCurX) + mCellDistance, std::min(y, mCurY) + mCellDistance };
|
if (mActiveCell)
|
||||||
|
{
|
||||||
|
curX = mActiveCell->getGridX();
|
||||||
|
curY = mActiveCell->getGridY();
|
||||||
|
}
|
||||||
|
const MyGUI::IntRect intersection = { std::max(x, curX) - mCellDistance, std::max(y, curY) - mCellDistance,
|
||||||
|
std::min(x, curX) + mCellDistance, std::min(y, curY) + mCellDistance };
|
||||||
|
|
||||||
const MyGUI::IntRect activeGrid = createRect({ x, y }, Constants::CellGridRadius);
|
const MyGUI::IntRect activeGrid = createRect({ x, y }, Constants::CellGridRadius);
|
||||||
const MyGUI::IntRect currentView = createRect({ x, y }, mCellDistance);
|
const MyGUI::IntRect currentView = createRect({ x, y }, mCellDistance);
|
||||||
|
@ -407,17 +416,14 @@ namespace MWGui
|
||||||
for (auto& widget : mDoorMarkersToRecycle)
|
for (auto& widget : mDoorMarkersToRecycle)
|
||||||
widget->setVisible(false);
|
widget->setVisible(false);
|
||||||
|
|
||||||
for (auto const& cell : mMaps)
|
for (auto const& entry : mMaps)
|
||||||
{
|
{
|
||||||
if (mHasALastActiveCell && !intersection.inside({ cell.mCellX, cell.mCellY }))
|
if (mHasALastActiveCell && !intersection.inside({ entry.mCellX, entry.mCellY }))
|
||||||
mLocalMapRender->removeExteriorCell(cell.mCellX, cell.mCellY);
|
mLocalMapRender->removeExteriorCell(entry.mCellX, entry.mCellY);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
mCurX = x;
|
mActiveCell = &cell;
|
||||||
mCurY = y;
|
|
||||||
mInterior = interior;
|
|
||||||
mChanged = false;
|
|
||||||
|
|
||||||
for (int mx = 0; mx < mNumCells; ++mx)
|
for (int mx = 0; mx < mNumCells; ++mx)
|
||||||
{
|
{
|
||||||
|
@ -441,7 +447,7 @@ namespace MWGui
|
||||||
for (MyGUI::Widget* widget : currentDoorMarkersWidgets())
|
for (MyGUI::Widget* widget : currentDoorMarkersWidgets())
|
||||||
widget->setCoord(getMarkerCoordinates(widget, 8));
|
widget->setCoord(getMarkerCoordinates(widget, 8));
|
||||||
|
|
||||||
if (!mInterior)
|
if (mActiveCell->isExterior())
|
||||||
mHasALastActiveCell = true;
|
mHasALastActiveCell = true;
|
||||||
|
|
||||||
updateMagicMarkers();
|
updateMagicMarkers();
|
||||||
|
@ -580,7 +586,7 @@ namespace MWGui
|
||||||
|
|
||||||
if (!entry.mMapTexture)
|
if (!entry.mMapTexture)
|
||||||
{
|
{
|
||||||
if (!mInterior)
|
if (mActiveCell->isExterior())
|
||||||
requestMapRender(&MWBase::Environment::get().getWorldModel()->getExterior(
|
requestMapRender(&MWBase::Environment::get().getWorldModel()->getExterior(
|
||||||
ESM::ExteriorCellLocation(entry.mCellX, entry.mCellY, ESM::Cell::sDefaultWorldspaceId)));
|
ESM::ExteriorCellLocation(entry.mCellX, entry.mCellY, ESM::Cell::sDefaultWorldspaceId)));
|
||||||
|
|
||||||
|
@ -626,12 +632,12 @@ namespace MWGui
|
||||||
mDoorMarkersToRecycle.end(), mInteriorDoorMarkerWidgets.begin(), mInteriorDoorMarkerWidgets.end());
|
mDoorMarkersToRecycle.end(), mInteriorDoorMarkerWidgets.begin(), mInteriorDoorMarkerWidgets.end());
|
||||||
mInteriorDoorMarkerWidgets.clear();
|
mInteriorDoorMarkerWidgets.clear();
|
||||||
|
|
||||||
if (mInterior)
|
if (!mActiveCell->isExterior())
|
||||||
{
|
{
|
||||||
for (MyGUI::Widget* widget : mExteriorDoorMarkerWidgets)
|
for (MyGUI::Widget* widget : mExteriorDoorMarkerWidgets)
|
||||||
widget->setVisible(false);
|
widget->setVisible(false);
|
||||||
|
|
||||||
MWWorld::CellStore& cell = worldModel->getInterior(mPrefix);
|
MWWorld::CellStore& cell = worldModel->getInterior(mActiveCell->getNameId());
|
||||||
world->getDoorMarkers(cell, doors);
|
world->getDoorMarkers(cell, doors);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
|
@ -678,7 +684,7 @@ namespace MWGui
|
||||||
}
|
}
|
||||||
|
|
||||||
currentDoorMarkersWidgets().push_back(markerWidget);
|
currentDoorMarkersWidgets().push_back(markerWidget);
|
||||||
if (!mInterior)
|
if (mActiveCell->isExterior())
|
||||||
mExteriorDoorsByCell[{ data->cellX, data->cellY }].push_back(markerWidget);
|
mExteriorDoorsByCell[{ data->cellX, data->cellY }].push_back(markerWidget);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -701,8 +707,7 @@ namespace MWGui
|
||||||
MWWorld::CellStore* markedCell = nullptr;
|
MWWorld::CellStore* markedCell = nullptr;
|
||||||
ESM::Position markedPosition;
|
ESM::Position markedPosition;
|
||||||
MWBase::Environment::get().getWorld()->getPlayer().getMarkedPosition(markedCell, markedPosition);
|
MWBase::Environment::get().getWorld()->getPlayer().getMarkedPosition(markedCell, markedPosition);
|
||||||
if (markedCell && markedCell->isExterior() == !mInterior
|
if (markedCell && markedCell->getCell()->getWorldSpace() == mActiveCell->getWorldSpace())
|
||||||
&& (!mInterior || Misc::StringUtils::ciEqual(markedCell->getCell()->getNameId(), mPrefix)))
|
|
||||||
{
|
{
|
||||||
MarkerUserData markerPos(mLocalMapRender);
|
MarkerUserData markerPos(mLocalMapRender);
|
||||||
MyGUI::ImageBox* markerWidget = mLocalMap->createWidget<MyGUI::ImageBox>("ImageBox",
|
MyGUI::ImageBox* markerWidget = mLocalMap->createWidget<MyGUI::ImageBox>("ImageBox",
|
||||||
|
@ -870,11 +875,11 @@ namespace MWGui
|
||||||
int y = (int(widgetPos.top / float(mapWidgetSize)) - mCellDistance) * -1;
|
int y = (int(widgetPos.top / float(mapWidgetSize)) - mCellDistance) * -1;
|
||||||
float nX = widgetPos.left / float(mapWidgetSize) - int(widgetPos.left / float(mapWidgetSize));
|
float nX = widgetPos.left / float(mapWidgetSize) - int(widgetPos.left / float(mapWidgetSize));
|
||||||
float nY = widgetPos.top / float(mapWidgetSize) - int(widgetPos.top / float(mapWidgetSize));
|
float nY = widgetPos.top / float(mapWidgetSize) - int(widgetPos.top / float(mapWidgetSize));
|
||||||
x += mCurX;
|
x += mActiveCell->getGridX();
|
||||||
y += mCurY;
|
y += mActiveCell->getGridY();
|
||||||
|
|
||||||
osg::Vec2f worldPos;
|
osg::Vec2f worldPos;
|
||||||
if (mInterior)
|
if (!mActiveCell->isExterior())
|
||||||
{
|
{
|
||||||
worldPos = mLocalMapRender->interiorMapToWorldPosition(nX, nY, x, y);
|
worldPos = mLocalMapRender->interiorMapToWorldPosition(nX, nY, x, y);
|
||||||
}
|
}
|
||||||
|
@ -886,7 +891,7 @@ namespace MWGui
|
||||||
|
|
||||||
mEditingMarker.mWorldX = worldPos.x();
|
mEditingMarker.mWorldX = worldPos.x();
|
||||||
mEditingMarker.mWorldY = worldPos.y();
|
mEditingMarker.mWorldY = worldPos.y();
|
||||||
ESM::RefId clickedId = ESM::Cell::generateIdForCell(!mInterior, LocalMapBase::mPrefix, x, y);
|
ESM::RefId clickedId = getCellIdInWorldSpace(*mActiveCell, x, y);
|
||||||
|
|
||||||
mEditingMarker.mCell = clickedId;
|
mEditingMarker.mCell = clickedId;
|
||||||
|
|
||||||
|
@ -977,7 +982,7 @@ namespace MWGui
|
||||||
resizeGlobalMap();
|
resizeGlobalMap();
|
||||||
|
|
||||||
float x = mCurPos.x(), y = mCurPos.y();
|
float x = mCurPos.x(), y = mCurPos.y();
|
||||||
if (mInterior)
|
if (!mActiveCell->isExterior())
|
||||||
{
|
{
|
||||||
auto pos = MWBase::Environment::get().getWorld()->getPlayer().getLastKnownExteriorPosition();
|
auto pos = MWBase::Environment::get().getWorld()->getPlayer().getLastKnownExteriorPosition();
|
||||||
x = pos.x();
|
x = pos.x();
|
||||||
|
@ -1020,7 +1025,7 @@ namespace MWGui
|
||||||
resizeGlobalMap();
|
resizeGlobalMap();
|
||||||
}
|
}
|
||||||
|
|
||||||
MapWindow::~MapWindow() {}
|
MapWindow::~MapWindow() = default;
|
||||||
|
|
||||||
void MapWindow::setCellName(const std::string& cellName)
|
void MapWindow::setCellName(const std::string& cellName)
|
||||||
{
|
{
|
||||||
|
@ -1289,7 +1294,7 @@ namespace MWGui
|
||||||
mMarkers.clear();
|
mMarkers.clear();
|
||||||
|
|
||||||
mGlobalMapRender->clear();
|
mGlobalMapRender->clear();
|
||||||
mChanged = true;
|
mActiveCell = nullptr;
|
||||||
|
|
||||||
for (auto& widgetPair : mGlobalMapMarkers)
|
for (auto& widgetPair : mGlobalMapMarkers)
|
||||||
MyGUI::Gui::getInstance().destroyWidget(widgetPair.first.widget);
|
MyGUI::Gui::getInstance().destroyWidget(widgetPair.first.widget);
|
||||||
|
|
|
@ -27,6 +27,7 @@ namespace ESM
|
||||||
|
|
||||||
namespace MWWorld
|
namespace MWWorld
|
||||||
{
|
{
|
||||||
|
class Cell;
|
||||||
class CellStore;
|
class CellStore;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -77,8 +78,7 @@ namespace MWGui
|
||||||
virtual ~LocalMapBase();
|
virtual ~LocalMapBase();
|
||||||
void init(MyGUI::ScrollView* widget, MyGUI::ImageBox* compass, int cellDistance = Constants::CellGridRadius);
|
void init(MyGUI::ScrollView* widget, MyGUI::ImageBox* compass, int cellDistance = Constants::CellGridRadius);
|
||||||
|
|
||||||
void setCellPrefix(const std::string& prefix);
|
void setActiveCell(const MWWorld::Cell& cell);
|
||||||
void setActiveCell(const int x, const int y, bool interior = false);
|
|
||||||
void requestMapRender(const MWWorld::CellStore* cell);
|
void requestMapRender(const MWWorld::CellStore* cell);
|
||||||
void setPlayerDir(const float x, const float y);
|
void setPlayerDir(const float x, const float y);
|
||||||
void setPlayerPos(int cellX, int cellY, const float nx, const float ny);
|
void setPlayerPos(int cellX, int cellY, const float nx, const float ny);
|
||||||
|
@ -115,15 +115,12 @@ namespace MWGui
|
||||||
float mLocalMapZoom = 1.f;
|
float mLocalMapZoom = 1.f;
|
||||||
MWRender::LocalMap* mLocalMapRender;
|
MWRender::LocalMap* mLocalMapRender;
|
||||||
|
|
||||||
int mCurX, mCurY; // the position of the active cell on the global map (in cell coords)
|
const MWWorld::Cell* mActiveCell;
|
||||||
bool mHasALastActiveCell = false;
|
bool mHasALastActiveCell = false;
|
||||||
osg::Vec2f mCurPos; // the position of the player in the world (in cell coords)
|
osg::Vec2f mCurPos; // the position of the player in the world (in cell coords)
|
||||||
|
|
||||||
bool mInterior;
|
|
||||||
MyGUI::ScrollView* mLocalMap;
|
MyGUI::ScrollView* mLocalMap;
|
||||||
MyGUI::ImageBox* mCompass;
|
MyGUI::ImageBox* mCompass;
|
||||||
std::string mPrefix;
|
|
||||||
bool mChanged;
|
|
||||||
bool mFogOfWarToggled;
|
bool mFogOfWarToggled;
|
||||||
bool mFogOfWarEnabled;
|
bool mFogOfWarEnabled;
|
||||||
|
|
||||||
|
|
|
@ -134,7 +134,7 @@ namespace MWGui
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
player.getClass().skillUsageSucceeded(player, ESM::Skill::Sneak, 1);
|
player.getClass().skillUsageSucceeded(player, ESM::Skill::Sneak, ESM::Skill::Sneak_PickPocket);
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
|
@ -410,10 +410,13 @@ namespace MWGui
|
||||||
const std::string& image = info.icon;
|
const std::string& image = info.icon;
|
||||||
int imageSize = (!image.empty()) ? info.imageSize : 0;
|
int imageSize = (!image.empty()) ? info.imageSize : 0;
|
||||||
std::string text = info.text;
|
std::string text = info.text;
|
||||||
|
std::string_view extra = info.extra;
|
||||||
|
|
||||||
// remove the first newline (easier this way)
|
// remove the first newline (easier this way)
|
||||||
if (text.size() > 0 && text[0] == '\n')
|
if (!text.empty() && text[0] == '\n')
|
||||||
text.erase(0, 1);
|
text.erase(0, 1);
|
||||||
|
if (!extra.empty() && extra[0] == '\n')
|
||||||
|
extra = extra.substr(1);
|
||||||
|
|
||||||
const ESM::Enchantment* enchant = nullptr;
|
const ESM::Enchantment* enchant = nullptr;
|
||||||
const MWWorld::ESMStore& store = *MWBase::Environment::get().getESMStore();
|
const MWWorld::ESMStore& store = *MWBase::Environment::get().getESMStore();
|
||||||
|
@ -572,6 +575,24 @@ namespace MWGui
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!extra.empty())
|
||||||
|
{
|
||||||
|
Gui::EditBox* extraWidget = mDynamicToolTipBox->createWidget<Gui::EditBox>("SandText",
|
||||||
|
MyGUI::IntCoord(padding.left, totalSize.height + 12, 300 - padding.left, 300 - totalSize.height),
|
||||||
|
MyGUI::Align::Stretch, "ToolTipExtraText");
|
||||||
|
|
||||||
|
extraWidget->setEditStatic(true);
|
||||||
|
extraWidget->setEditMultiLine(true);
|
||||||
|
extraWidget->setEditWordWrap(info.wordWrap);
|
||||||
|
extraWidget->setCaptionWithReplacing(extra);
|
||||||
|
extraWidget->setTextAlign(MyGUI::Align::HCenter | MyGUI::Align::Top);
|
||||||
|
extraWidget->setNeedKeyFocus(false);
|
||||||
|
|
||||||
|
MyGUI::IntSize extraTextSize = extraWidget->getTextSize();
|
||||||
|
totalSize.height += extraTextSize.height + 4;
|
||||||
|
totalSize.width = std::max(totalSize.width, extraTextSize.width);
|
||||||
|
}
|
||||||
|
|
||||||
captionWidget->setCoord((totalSize.width - captionSize.width) / 2 + imageSize,
|
captionWidget->setCoord((totalSize.width - captionSize.width) / 2 + imageSize,
|
||||||
(captionHeight - captionSize.height) / 2, captionSize.width - imageSize, captionSize.height);
|
(captionHeight - captionSize.height) / 2, captionSize.width - imageSize, captionSize.height);
|
||||||
|
|
||||||
|
|
|
@ -29,6 +29,7 @@ namespace MWGui
|
||||||
|
|
||||||
std::string caption;
|
std::string caption;
|
||||||
std::string text;
|
std::string text;
|
||||||
|
std::string extra;
|
||||||
std::string icon;
|
std::string icon;
|
||||||
int imageSize;
|
int imageSize;
|
||||||
|
|
||||||
|
|
|
@ -5,6 +5,7 @@
|
||||||
#include <MyGUI_TextIterator.h>
|
#include <MyGUI_TextIterator.h>
|
||||||
|
|
||||||
#include "../mwbase/environment.hpp"
|
#include "../mwbase/environment.hpp"
|
||||||
|
#include "../mwbase/luamanager.hpp"
|
||||||
#include "../mwbase/mechanicsmanager.hpp"
|
#include "../mwbase/mechanicsmanager.hpp"
|
||||||
#include "../mwbase/windowmanager.hpp"
|
#include "../mwbase/windowmanager.hpp"
|
||||||
#include "../mwbase/world.hpp"
|
#include "../mwbase/world.hpp"
|
||||||
|
@ -174,10 +175,7 @@ namespace MWGui
|
||||||
}
|
}
|
||||||
|
|
||||||
// increase skill
|
// increase skill
|
||||||
MWWorld::LiveCellRef<ESM::NPC>* playerRef = player.get<ESM::NPC>();
|
MWBase::Environment::get().getLuaManager()->skillLevelUp(player, skill->mId, "trainer");
|
||||||
|
|
||||||
const ESM::Class* class_ = store.get<ESM::Class>().find(playerRef->mBase->mClass);
|
|
||||||
pcStats.increaseSkill(skill->mId, *class_, true);
|
|
||||||
|
|
||||||
// remove gold
|
// remove gold
|
||||||
player.getClass().getContainerStore(player).remove(MWWorld::ContainerStore::sGoldId, price);
|
player.getClass().getContainerStore(player).remove(MWWorld::ContainerStore::sGoldId, price);
|
||||||
|
|
|
@ -371,7 +371,7 @@ namespace MWGui::Widgets
|
||||||
|
|
||||||
std::string spellLine = MWMechanics::getMagicEffectString(*magicEffect, attribute, skill);
|
std::string spellLine = MWMechanics::getMagicEffectString(*magicEffect, attribute, skill);
|
||||||
|
|
||||||
if (mEffectParams.mMagnMin || mEffectParams.mMagnMax)
|
if ((mEffectParams.mMagnMin || mEffectParams.mMagnMax) && !mEffectParams.mNoMagnitude)
|
||||||
{
|
{
|
||||||
ESM::MagicEffect::MagnitudeDisplayType displayType = magicEffect->getMagnitudeDisplayType();
|
ESM::MagicEffect::MagnitudeDisplayType displayType = magicEffect->getMagnitudeDisplayType();
|
||||||
if (displayType == ESM::MagicEffect::MDT_TimesInt)
|
if (displayType == ESM::MagicEffect::MDT_TimesInt)
|
||||||
|
@ -386,7 +386,7 @@ namespace MWGui::Widgets
|
||||||
|
|
||||||
spellLine += formatter.str();
|
spellLine += formatter.str();
|
||||||
}
|
}
|
||||||
else if (displayType != ESM::MagicEffect::MDT_None && !mEffectParams.mNoMagnitude)
|
else if (displayType != ESM::MagicEffect::MDT_None)
|
||||||
{
|
{
|
||||||
spellLine += " " + MyGUI::utility::toString(mEffectParams.mMagnMin);
|
spellLine += " " + MyGUI::utility::toString(mEffectParams.mMagnMin);
|
||||||
if (mEffectParams.mMagnMin != mEffectParams.mMagnMax)
|
if (mEffectParams.mMagnMin != mEffectParams.mMagnMax)
|
||||||
|
|
|
@ -844,7 +844,7 @@ namespace MWGui
|
||||||
|
|
||||||
if (!player.getCell()->isExterior())
|
if (!player.getCell()->isExterior())
|
||||||
{
|
{
|
||||||
setActiveMap(x, y, true);
|
setActiveMap(*player.getCell()->getCell());
|
||||||
}
|
}
|
||||||
// else: need to know the current grid center, call setActiveMap from changeCell
|
// else: need to know the current grid center, call setActiveMap from changeCell
|
||||||
|
|
||||||
|
@ -982,29 +982,23 @@ namespace MWGui
|
||||||
mMap->addVisitedLocation(name, cellCommon->getGridX(), cellCommon->getGridY());
|
mMap->addVisitedLocation(name, cellCommon->getGridX(), cellCommon->getGridY());
|
||||||
|
|
||||||
mMap->cellExplored(cellCommon->getGridX(), cellCommon->getGridY());
|
mMap->cellExplored(cellCommon->getGridX(), cellCommon->getGridY());
|
||||||
|
|
||||||
setActiveMap(cellCommon->getGridX(), cellCommon->getGridY(), false);
|
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
mMap->setCellPrefix(std::string(cellCommon->getNameId()));
|
|
||||||
mHud->setCellPrefix(std::string(cellCommon->getNameId()));
|
|
||||||
|
|
||||||
osg::Vec3f worldPos;
|
osg::Vec3f worldPos;
|
||||||
if (!MWBase::Environment::get().getWorld()->findInteriorPositionInWorldSpace(cell, worldPos))
|
if (!MWBase::Environment::get().getWorld()->findInteriorPositionInWorldSpace(cell, worldPos))
|
||||||
worldPos = MWBase::Environment::get().getWorld()->getPlayer().getLastKnownExteriorPosition();
|
worldPos = MWBase::Environment::get().getWorld()->getPlayer().getLastKnownExteriorPosition();
|
||||||
else
|
else
|
||||||
MWBase::Environment::get().getWorld()->getPlayer().setLastKnownExteriorPosition(worldPos);
|
MWBase::Environment::get().getWorld()->getPlayer().setLastKnownExteriorPosition(worldPos);
|
||||||
mMap->setGlobalMapPlayerPosition(worldPos.x(), worldPos.y());
|
mMap->setGlobalMapPlayerPosition(worldPos.x(), worldPos.y());
|
||||||
|
|
||||||
setActiveMap(0, 0, true);
|
|
||||||
}
|
}
|
||||||
|
setActiveMap(*cellCommon);
|
||||||
}
|
}
|
||||||
|
|
||||||
void WindowManager::setActiveMap(int x, int y, bool interior)
|
void WindowManager::setActiveMap(const MWWorld::Cell& cell)
|
||||||
{
|
{
|
||||||
mMap->setActiveCell(x, y, interior);
|
mMap->setActiveCell(cell);
|
||||||
mHud->setActiveCell(x, y, interior);
|
mHud->setActiveCell(cell);
|
||||||
}
|
}
|
||||||
|
|
||||||
void WindowManager::setDrowningBarVisibility(bool visible)
|
void WindowManager::setDrowningBarVisibility(bool visible)
|
||||||
|
|
|
@ -50,6 +50,7 @@ namespace MyGUI
|
||||||
|
|
||||||
namespace MWWorld
|
namespace MWWorld
|
||||||
{
|
{
|
||||||
|
class Cell;
|
||||||
class ESMStore;
|
class ESMStore;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -216,9 +217,6 @@ namespace MWGui
|
||||||
bool toggleFullHelp() override; ///< show extra info in item tooltips (owner, script)
|
bool toggleFullHelp() override; ///< show extra info in item tooltips (owner, script)
|
||||||
bool getFullHelp() const override;
|
bool getFullHelp() const override;
|
||||||
|
|
||||||
void setActiveMap(int x, int y, bool interior) override;
|
|
||||||
///< set the indices of the map texture that should be used
|
|
||||||
|
|
||||||
/// sets the visibility of the drowning bar
|
/// sets the visibility of the drowning bar
|
||||||
void setDrowningBarVisibility(bool visible) override;
|
void setDrowningBarVisibility(bool visible) override;
|
||||||
|
|
||||||
|
@ -589,6 +587,9 @@ namespace MWGui
|
||||||
void setCullMask(uint32_t mask) override;
|
void setCullMask(uint32_t mask) override;
|
||||||
uint32_t getCullMask() override;
|
uint32_t getCullMask() override;
|
||||||
|
|
||||||
|
void setActiveMap(const MWWorld::Cell& cell);
|
||||||
|
///< set the indices of the map texture that should be used
|
||||||
|
|
||||||
Files::ConfigurationManager& mCfgMgr;
|
Files::ConfigurationManager& mCfgMgr;
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
|
@ -10,6 +10,7 @@
|
||||||
|
|
||||||
#include "../mwbase/environment.hpp"
|
#include "../mwbase/environment.hpp"
|
||||||
#include "../mwbase/inputmanager.hpp"
|
#include "../mwbase/inputmanager.hpp"
|
||||||
|
#include "../mwbase/luamanager.hpp"
|
||||||
#include "../mwbase/windowmanager.hpp"
|
#include "../mwbase/windowmanager.hpp"
|
||||||
#include "../mwbase/world.hpp"
|
#include "../mwbase/world.hpp"
|
||||||
|
|
||||||
|
@ -119,15 +120,22 @@ namespace MWInput
|
||||||
mBindingsManager->setPlayerControlsEnabled(!guiMode);
|
mBindingsManager->setPlayerControlsEnabled(!guiMode);
|
||||||
mBindingsManager->mouseReleased(arg, id);
|
mBindingsManager->mouseReleased(arg, id);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
MWBase::Environment::get().getLuaManager()->inputEvent(
|
||||||
|
{ MWBase::LuaManager::InputEvent::MouseButtonReleased, arg.button });
|
||||||
}
|
}
|
||||||
|
|
||||||
void MouseManager::mouseWheelMoved(const SDL_MouseWheelEvent& arg)
|
void MouseManager::mouseWheelMoved(const SDL_MouseWheelEvent& arg)
|
||||||
{
|
{
|
||||||
MWBase::InputManager* input = MWBase::Environment::get().getInputManager();
|
MWBase::InputManager* input = MWBase::Environment::get().getInputManager();
|
||||||
if (mBindingsManager->isDetectingBindingState() || !input->controlsDisabled())
|
if (mBindingsManager->isDetectingBindingState() || !input->controlsDisabled())
|
||||||
|
{
|
||||||
mBindingsManager->mouseWheelMoved(arg);
|
mBindingsManager->mouseWheelMoved(arg);
|
||||||
|
}
|
||||||
|
|
||||||
input->setJoystickLastUsed(false);
|
input->setJoystickLastUsed(false);
|
||||||
|
MWBase::Environment::get().getLuaManager()->inputEvent({ MWBase::LuaManager::InputEvent::MouseWheel,
|
||||||
|
MWBase::LuaManager::InputEvent::WheelChange{ arg.x, arg.y } });
|
||||||
}
|
}
|
||||||
|
|
||||||
void MouseManager::mousePressed(const SDL_MouseButtonEvent& arg, Uint8 id)
|
void MouseManager::mousePressed(const SDL_MouseButtonEvent& arg, Uint8 id)
|
||||||
|
@ -161,8 +169,12 @@ namespace MWInput
|
||||||
const MWGui::SettingsWindow* settingsWindow
|
const MWGui::SettingsWindow* settingsWindow
|
||||||
= MWBase::Environment::get().getWindowManager()->getSettingsWindow();
|
= MWBase::Environment::get().getWindowManager()->getSettingsWindow();
|
||||||
if ((!settingsWindow || !settingsWindow->isVisible()) && !input->controlsDisabled())
|
if ((!settingsWindow || !settingsWindow->isVisible()) && !input->controlsDisabled())
|
||||||
|
{
|
||||||
mBindingsManager->mousePressed(arg, id);
|
mBindingsManager->mousePressed(arg, id);
|
||||||
}
|
}
|
||||||
|
MWBase::Environment::get().getLuaManager()->inputEvent(
|
||||||
|
{ MWBase::LuaManager::InputEvent::MouseButtonPressed, arg.button });
|
||||||
|
}
|
||||||
|
|
||||||
void MouseManager::updateCursorMode()
|
void MouseManager::updateCursorMode()
|
||||||
{
|
{
|
||||||
|
@ -208,14 +220,14 @@ namespace MWInput
|
||||||
};
|
};
|
||||||
|
|
||||||
// Only actually turn player when we're not in vanity mode
|
// Only actually turn player when we're not in vanity mode
|
||||||
bool controls = MWBase::Environment::get().getInputManager()->getControlSwitch("playercontrols");
|
bool playerLooking = MWBase::Environment::get().getInputManager()->getControlSwitch("playerlooking");
|
||||||
if (!MWBase::Environment::get().getWorld()->vanityRotateCamera(rot) && controls)
|
if (!MWBase::Environment::get().getWorld()->vanityRotateCamera(rot) && playerLooking)
|
||||||
{
|
{
|
||||||
MWWorld::Player& player = MWBase::Environment::get().getWorld()->getPlayer();
|
MWWorld::Player& player = MWBase::Environment::get().getWorld()->getPlayer();
|
||||||
player.yaw(-rot[2]);
|
player.yaw(-rot[2]);
|
||||||
player.pitch(-rot[0]);
|
player.pitch(-rot[0]);
|
||||||
}
|
}
|
||||||
else if (!controls)
|
else if (!playerLooking)
|
||||||
MWBase::Environment::get().getWorld()->disableDeferredPreviewRotation();
|
MWBase::Environment::get().getWorld()->disableDeferredPreviewRotation();
|
||||||
|
|
||||||
MWBase::Environment::get().getInputManager()->resetIdleTime();
|
MWBase::Environment::get().getInputManager()->resetIdleTime();
|
||||||
|
|
|
@ -21,24 +21,6 @@
|
||||||
#include "animationbindings.hpp"
|
#include "animationbindings.hpp"
|
||||||
#include <array>
|
#include <array>
|
||||||
|
|
||||||
namespace MWLua
|
|
||||||
{
|
|
||||||
struct AnimationGroup;
|
|
||||||
struct TextKeyCallback;
|
|
||||||
}
|
|
||||||
|
|
||||||
namespace sol
|
|
||||||
{
|
|
||||||
template <>
|
|
||||||
struct is_automagical<MWLua::AnimationGroup> : std::false_type
|
|
||||||
{
|
|
||||||
};
|
|
||||||
template <>
|
|
||||||
struct is_automagical<std::shared_ptr<MWLua::TextKeyCallback>> : std::false_type
|
|
||||||
{
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
namespace MWLua
|
namespace MWLua
|
||||||
{
|
{
|
||||||
using BlendMask = MWRender::Animation::BlendMask;
|
using BlendMask = MWRender::Animation::BlendMask;
|
||||||
|
|
49
apps/openmw/mwlua/birthsignbindings.cpp
Normal file
49
apps/openmw/mwlua/birthsignbindings.cpp
Normal file
|
@ -0,0 +1,49 @@
|
||||||
|
#include <components/esm3/loadbsgn.hpp>
|
||||||
|
#include <components/lua/luastate.hpp>
|
||||||
|
#include <components/misc/resourcehelpers.hpp>
|
||||||
|
#include <components/resource/resourcesystem.hpp>
|
||||||
|
|
||||||
|
#include "../mwbase/environment.hpp"
|
||||||
|
#include "../mwworld/class.hpp"
|
||||||
|
#include "../mwworld/esmstore.hpp"
|
||||||
|
|
||||||
|
#include "birthsignbindings.hpp"
|
||||||
|
#include "idcollectionbindings.hpp"
|
||||||
|
#include "luamanagerimp.hpp"
|
||||||
|
#include "types/types.hpp"
|
||||||
|
|
||||||
|
namespace sol
|
||||||
|
{
|
||||||
|
template <>
|
||||||
|
struct is_automagical<ESM::BirthSign> : std::false_type
|
||||||
|
{
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
namespace MWLua
|
||||||
|
{
|
||||||
|
sol::table initBirthSignRecordBindings(const Context& context)
|
||||||
|
{
|
||||||
|
sol::state_view& lua = context.mLua->sol();
|
||||||
|
sol::table birthSigns(context.mLua->sol(), sol::create);
|
||||||
|
addRecordFunctionBinding<ESM::BirthSign>(birthSigns, context);
|
||||||
|
|
||||||
|
auto signT = lua.new_usertype<ESM::BirthSign>("ESM3_BirthSign");
|
||||||
|
signT[sol::meta_function::to_string] = [](const ESM::BirthSign& rec) -> std::string {
|
||||||
|
return "ESM3_BirthSign[" + rec.mId.toDebugString() + "]";
|
||||||
|
};
|
||||||
|
signT["id"] = sol::readonly_property([](const ESM::BirthSign& rec) { return rec.mId.serializeText(); });
|
||||||
|
signT["name"] = sol::readonly_property([](const ESM::BirthSign& rec) -> std::string_view { return rec.mName; });
|
||||||
|
signT["description"]
|
||||||
|
= sol::readonly_property([](const ESM::BirthSign& rec) -> std::string_view { return rec.mDescription; });
|
||||||
|
auto vfs = MWBase::Environment::get().getResourceSystem()->getVFS();
|
||||||
|
signT["texture"] = sol::readonly_property([vfs](const ESM::BirthSign& rec) -> std::string {
|
||||||
|
return Misc::ResourceHelpers::correctTexturePath(rec.mTexture, vfs);
|
||||||
|
});
|
||||||
|
signT["spells"] = sol::readonly_property([lua](const ESM::BirthSign& rec) -> sol::table {
|
||||||
|
return createReadOnlyRefIdTable(lua, rec.mPowers.mList);
|
||||||
|
});
|
||||||
|
|
||||||
|
return LuaUtil::makeReadOnly(birthSigns);
|
||||||
|
}
|
||||||
|
}
|
13
apps/openmw/mwlua/birthsignbindings.hpp
Normal file
13
apps/openmw/mwlua/birthsignbindings.hpp
Normal file
|
@ -0,0 +1,13 @@
|
||||||
|
#ifndef MWLUA_BIRTHSIGNBINDINGS_H
|
||||||
|
#define MWLUA_BIRTHSIGNBINDINGS_H
|
||||||
|
|
||||||
|
#include <sol/forward.hpp>
|
||||||
|
|
||||||
|
#include "context.hpp"
|
||||||
|
|
||||||
|
namespace MWLua
|
||||||
|
{
|
||||||
|
sol::table initBirthSignRecordBindings(const Context& context);
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif // MWLUA_BIRTHSIGNBINDINGS_H
|
|
@ -6,6 +6,7 @@
|
||||||
#include "../mwworld/esmstore.hpp"
|
#include "../mwworld/esmstore.hpp"
|
||||||
|
|
||||||
#include "classbindings.hpp"
|
#include "classbindings.hpp"
|
||||||
|
#include "idcollectionbindings.hpp"
|
||||||
#include "luamanagerimp.hpp"
|
#include "luamanagerimp.hpp"
|
||||||
#include "stats.hpp"
|
#include "stats.hpp"
|
||||||
#include "types/types.hpp"
|
#include "types/types.hpp"
|
||||||
|
@ -16,16 +17,12 @@ namespace sol
|
||||||
struct is_automagical<ESM::Class> : std::false_type
|
struct is_automagical<ESM::Class> : std::false_type
|
||||||
{
|
{
|
||||||
};
|
};
|
||||||
template <>
|
|
||||||
struct is_automagical<MWWorld::Store<ESM::Class>> : std::false_type
|
|
||||||
{
|
|
||||||
};
|
|
||||||
}
|
}
|
||||||
|
|
||||||
namespace MWLua
|
namespace MWLua
|
||||||
{
|
{
|
||||||
|
|
||||||
sol::table initCoreClassBindings(const Context& context)
|
sol::table initClassRecordBindings(const Context& context)
|
||||||
{
|
{
|
||||||
sol::state_view& lua = context.mLua->sol();
|
sol::state_view& lua = context.mLua->sol();
|
||||||
sol::table classes(context.mLua->sol(), sol::create);
|
sol::table classes(context.mLua->sol(), sol::create);
|
||||||
|
@ -40,34 +37,15 @@ namespace MWLua
|
||||||
= sol::readonly_property([](const ESM::Class& rec) -> std::string_view { return rec.mDescription; });
|
= sol::readonly_property([](const ESM::Class& rec) -> std::string_view { return rec.mDescription; });
|
||||||
|
|
||||||
classT["attributes"] = sol::readonly_property([lua](const ESM::Class& rec) -> sol::table {
|
classT["attributes"] = sol::readonly_property([lua](const ESM::Class& rec) -> sol::table {
|
||||||
sol::table res(lua, sol::create);
|
return createReadOnlyRefIdTable(lua, rec.mData.mAttribute, ESM::Attribute::indexToRefId);
|
||||||
auto attribute = rec.mData.mAttribute;
|
|
||||||
for (size_t i = 0; i < attribute.size(); ++i)
|
|
||||||
{
|
|
||||||
ESM::RefId attributeId = ESM::Attribute::indexToRefId(attribute[i]);
|
|
||||||
res[i + 1] = attributeId.serializeText();
|
|
||||||
}
|
|
||||||
return res;
|
|
||||||
});
|
});
|
||||||
classT["majorSkills"] = sol::readonly_property([lua](const ESM::Class& rec) -> sol::table {
|
classT["majorSkills"] = sol::readonly_property([lua](const ESM::Class& rec) -> sol::table {
|
||||||
sol::table res(lua, sol::create);
|
return createReadOnlyRefIdTable(
|
||||||
auto skills = rec.mData.mSkills;
|
lua, rec.mData.mSkills, [](const auto& pair) { return ESM::Skill::indexToRefId(pair[1]); });
|
||||||
for (size_t i = 0; i < skills.size(); ++i)
|
|
||||||
{
|
|
||||||
ESM::RefId skillId = ESM::Skill::indexToRefId(skills[i][1]);
|
|
||||||
res[i + 1] = skillId.serializeText();
|
|
||||||
}
|
|
||||||
return res;
|
|
||||||
});
|
});
|
||||||
classT["minorSkills"] = sol::readonly_property([lua](const ESM::Class& rec) -> sol::table {
|
classT["minorSkills"] = sol::readonly_property([lua](const ESM::Class& rec) -> sol::table {
|
||||||
sol::table res(lua, sol::create);
|
return createReadOnlyRefIdTable(
|
||||||
auto skills = rec.mData.mSkills;
|
lua, rec.mData.mSkills, [](const auto& pair) { return ESM::Skill::indexToRefId(pair[0]); });
|
||||||
for (size_t i = 0; i < skills.size(); ++i)
|
|
||||||
{
|
|
||||||
ESM::RefId skillId = ESM::Skill::indexToRefId(skills[i][0]);
|
|
||||||
res[i + 1] = skillId.serializeText();
|
|
||||||
}
|
|
||||||
return res;
|
|
||||||
});
|
});
|
||||||
|
|
||||||
classT["specialization"] = sol::readonly_property([](const ESM::Class& rec) -> std::string_view {
|
classT["specialization"] = sol::readonly_property([](const ESM::Class& rec) -> std::string_view {
|
||||||
|
|
|
@ -7,7 +7,7 @@
|
||||||
|
|
||||||
namespace MWLua
|
namespace MWLua
|
||||||
{
|
{
|
||||||
sol::table initCoreClassBindings(const Context& context);
|
sol::table initClassRecordBindings(const Context& context);
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif // MWLUA_CLASSBINDINGS_H
|
#endif // MWLUA_CLASSBINDINGS_H
|
||||||
|
|
|
@ -95,6 +95,24 @@ namespace MWLua
|
||||||
scripts->onAnimationTextKey(event.mGroupname, event.mKey);
|
scripts->onAnimationTextKey(event.mGroupname, event.mKey);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void operator()(const OnSkillUse& event) const
|
||||||
|
{
|
||||||
|
MWWorld::Ptr actor = getPtr(event.mActor);
|
||||||
|
if (actor.isEmpty())
|
||||||
|
return;
|
||||||
|
if (auto* scripts = getLocalScripts(actor))
|
||||||
|
scripts->onSkillUse(event.mSkill, event.useType, event.scale);
|
||||||
|
}
|
||||||
|
|
||||||
|
void operator()(const OnSkillLevelUp& event) const
|
||||||
|
{
|
||||||
|
MWWorld::Ptr actor = getPtr(event.mActor);
|
||||||
|
if (actor.isEmpty())
|
||||||
|
return;
|
||||||
|
if (auto* scripts = getLocalScripts(actor))
|
||||||
|
scripts->onSkillLevelUp(event.mSkill, event.mSource);
|
||||||
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
MWWorld::Ptr getPtr(ESM::RefNum id) const
|
MWWorld::Ptr getPtr(ESM::RefNum id) const
|
||||||
{
|
{
|
||||||
|
|
|
@ -57,8 +57,21 @@ namespace MWLua
|
||||||
std::string mGroupname;
|
std::string mGroupname;
|
||||||
std::string mKey;
|
std::string mKey;
|
||||||
};
|
};
|
||||||
|
struct OnSkillUse
|
||||||
|
{
|
||||||
|
ESM::RefNum mActor;
|
||||||
|
std::string mSkill;
|
||||||
|
int useType;
|
||||||
|
float scale;
|
||||||
|
};
|
||||||
|
struct OnSkillLevelUp
|
||||||
|
{
|
||||||
|
ESM::RefNum mActor;
|
||||||
|
std::string mSkill;
|
||||||
|
std::string mSource;
|
||||||
|
};
|
||||||
using Event = std::variant<OnActive, OnInactive, OnConsume, OnActivate, OnUseItem, OnNewExterior, OnTeleported,
|
using Event = std::variant<OnActive, OnInactive, OnConsume, OnActivate, OnUseItem, OnNewExterior, OnTeleported,
|
||||||
OnAnimationTextKey>;
|
OnAnimationTextKey, OnSkillUse, OnSkillLevelUp>;
|
||||||
|
|
||||||
void clear() { mQueue.clear(); }
|
void clear() { mQueue.clear(); }
|
||||||
void addToQueue(Event e) { mQueue.push_back(std::move(e)); }
|
void addToQueue(Event e) { mQueue.push_back(std::move(e)); }
|
||||||
|
|
|
@ -9,6 +9,7 @@
|
||||||
|
|
||||||
#include "../mwmechanics/npcstats.hpp"
|
#include "../mwmechanics/npcstats.hpp"
|
||||||
|
|
||||||
|
#include "idcollectionbindings.hpp"
|
||||||
#include "luamanagerimp.hpp"
|
#include "luamanagerimp.hpp"
|
||||||
|
|
||||||
namespace
|
namespace
|
||||||
|
@ -96,26 +97,10 @@ namespace MWLua
|
||||||
return res;
|
return res;
|
||||||
});
|
});
|
||||||
factionT["attributes"] = sol::readonly_property([&lua](const ESM::Faction& rec) {
|
factionT["attributes"] = sol::readonly_property([&lua](const ESM::Faction& rec) {
|
||||||
sol::table res(lua, sol::create);
|
return createReadOnlyRefIdTable(lua, rec.mData.mAttribute, ESM::Attribute::indexToRefId);
|
||||||
for (auto attributeIndex : rec.mData.mAttribute)
|
|
||||||
{
|
|
||||||
ESM::RefId id = ESM::Attribute::indexToRefId(attributeIndex);
|
|
||||||
if (!id.empty())
|
|
||||||
res.add(id.serializeText());
|
|
||||||
}
|
|
||||||
|
|
||||||
return res;
|
|
||||||
});
|
});
|
||||||
factionT["skills"] = sol::readonly_property([&lua](const ESM::Faction& rec) {
|
factionT["skills"] = sol::readonly_property([&lua](const ESM::Faction& rec) {
|
||||||
sol::table res(lua, sol::create);
|
return createReadOnlyRefIdTable(lua, rec.mData.mSkills, ESM::Skill::indexToRefId);
|
||||||
for (auto skillIndex : rec.mData.mSkills)
|
|
||||||
{
|
|
||||||
ESM::RefId id = ESM::Skill::indexToRefId(skillIndex);
|
|
||||||
if (!id.empty())
|
|
||||||
res.add(id.serializeText());
|
|
||||||
}
|
|
||||||
|
|
||||||
return res;
|
|
||||||
});
|
});
|
||||||
auto rankT = lua.new_usertype<FactionRank>("ESM3_FactionRank");
|
auto rankT = lua.new_usertype<FactionRank>("ESM3_FactionRank");
|
||||||
rankT[sol::meta_function::to_string] = [](const FactionRank& rec) -> std::string {
|
rankT[sol::meta_function::to_string] = [](const FactionRank& rec) -> std::string {
|
||||||
|
|
25
apps/openmw/mwlua/idcollectionbindings.hpp
Normal file
25
apps/openmw/mwlua/idcollectionbindings.hpp
Normal file
|
@ -0,0 +1,25 @@
|
||||||
|
#ifndef MWLUA_IDCOLLECTIONBINDINGS_H
|
||||||
|
#define MWLUA_IDCOLLECTIONBINDINGS_H
|
||||||
|
|
||||||
|
#include <functional>
|
||||||
|
|
||||||
|
#include <components/esm/refid.hpp>
|
||||||
|
#include <components/lua/luastate.hpp>
|
||||||
|
|
||||||
|
namespace MWLua
|
||||||
|
{
|
||||||
|
template <class C, class P = std::identity>
|
||||||
|
sol::table createReadOnlyRefIdTable(const sol::state_view& lua, const C& container, P projection = {})
|
||||||
|
{
|
||||||
|
sol::table res(lua, sol::create);
|
||||||
|
for (const auto& element : container)
|
||||||
|
{
|
||||||
|
ESM::RefId id = projection(element);
|
||||||
|
if (!id.empty())
|
||||||
|
res.add(id.serializeText());
|
||||||
|
}
|
||||||
|
return LuaUtil::makeReadOnly(res);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
|
@ -18,7 +18,7 @@ namespace MWLua
|
||||||
{
|
{
|
||||||
mScriptsContainer->registerEngineHandlers({ &mKeyPressHandlers, &mKeyReleaseHandlers,
|
mScriptsContainer->registerEngineHandlers({ &mKeyPressHandlers, &mKeyReleaseHandlers,
|
||||||
&mControllerButtonPressHandlers, &mControllerButtonReleaseHandlers, &mActionHandlers, &mTouchpadPressed,
|
&mControllerButtonPressHandlers, &mControllerButtonReleaseHandlers, &mActionHandlers, &mTouchpadPressed,
|
||||||
&mTouchpadReleased, &mTouchpadMoved });
|
&mTouchpadReleased, &mTouchpadMoved, &mMouseButtonPress, &mMouseButtonRelease, &mMouseWheel });
|
||||||
}
|
}
|
||||||
|
|
||||||
void processInputEvent(const MWBase::LuaManager::InputEvent& event)
|
void processInputEvent(const MWBase::LuaManager::InputEvent& event)
|
||||||
|
@ -53,6 +53,16 @@ namespace MWLua
|
||||||
case InputEvent::TouchMoved:
|
case InputEvent::TouchMoved:
|
||||||
mScriptsContainer->callEngineHandlers(mTouchpadMoved, std::get<SDLUtil::TouchEvent>(event.mValue));
|
mScriptsContainer->callEngineHandlers(mTouchpadMoved, std::get<SDLUtil::TouchEvent>(event.mValue));
|
||||||
break;
|
break;
|
||||||
|
case InputEvent::MouseButtonPressed:
|
||||||
|
mScriptsContainer->callEngineHandlers(mMouseButtonPress, std::get<int>(event.mValue));
|
||||||
|
break;
|
||||||
|
case InputEvent::MouseButtonReleased:
|
||||||
|
mScriptsContainer->callEngineHandlers(mMouseButtonRelease, std::get<int>(event.mValue));
|
||||||
|
break;
|
||||||
|
case InputEvent::MouseWheel:
|
||||||
|
auto wheelEvent = std::get<MWBase::LuaManager::InputEvent::WheelChange>(event.mValue);
|
||||||
|
mScriptsContainer->callEngineHandlers(mMouseWheel, wheelEvent.y, wheelEvent.x);
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -66,6 +76,9 @@ namespace MWLua
|
||||||
typename Container::EngineHandlerList mTouchpadPressed{ "onTouchPress" };
|
typename Container::EngineHandlerList mTouchpadPressed{ "onTouchPress" };
|
||||||
typename Container::EngineHandlerList mTouchpadReleased{ "onTouchRelease" };
|
typename Container::EngineHandlerList mTouchpadReleased{ "onTouchRelease" };
|
||||||
typename Container::EngineHandlerList mTouchpadMoved{ "onTouchMove" };
|
typename Container::EngineHandlerList mTouchpadMoved{ "onTouchMove" };
|
||||||
|
typename Container::EngineHandlerList mMouseButtonPress{ "onMouseButtonPress" };
|
||||||
|
typename Container::EngineHandlerList mMouseButtonRelease{ "onMouseButtonRelease" };
|
||||||
|
typename Container::EngineHandlerList mMouseWheel{ "onMouseWheel" };
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -176,7 +176,8 @@ namespace MWLua
|
||||||
{
|
{
|
||||||
this->addPackage("openmw.self", sol::make_object(lua->sol(), &mData));
|
this->addPackage("openmw.self", sol::make_object(lua->sol(), &mData));
|
||||||
registerEngineHandlers({ &mOnActiveHandlers, &mOnInactiveHandlers, &mOnConsumeHandlers, &mOnActivatedHandlers,
|
registerEngineHandlers({ &mOnActiveHandlers, &mOnInactiveHandlers, &mOnConsumeHandlers, &mOnActivatedHandlers,
|
||||||
&mOnTeleportedHandlers, &mOnAnimationTextKeyHandlers, &mOnPlayAnimationHandlers });
|
&mOnTeleportedHandlers, &mOnAnimationTextKeyHandlers, &mOnPlayAnimationHandlers, &mOnSkillUse,
|
||||||
|
&mOnSkillLevelUp });
|
||||||
}
|
}
|
||||||
|
|
||||||
void LocalScripts::setActive(bool active)
|
void LocalScripts::setActive(bool active)
|
||||||
|
|
|
@ -79,6 +79,14 @@ namespace MWLua
|
||||||
{
|
{
|
||||||
callEngineHandlers(mOnPlayAnimationHandlers, groupname, options);
|
callEngineHandlers(mOnPlayAnimationHandlers, groupname, options);
|
||||||
}
|
}
|
||||||
|
void onSkillUse(std::string_view skillId, int useType, float scale)
|
||||||
|
{
|
||||||
|
callEngineHandlers(mOnSkillUse, skillId, useType, scale);
|
||||||
|
}
|
||||||
|
void onSkillLevelUp(std::string_view skillId, std::string_view source)
|
||||||
|
{
|
||||||
|
callEngineHandlers(mOnSkillLevelUp, skillId, source);
|
||||||
|
}
|
||||||
|
|
||||||
void applyStatsCache();
|
void applyStatsCache();
|
||||||
|
|
||||||
|
@ -93,6 +101,8 @@ namespace MWLua
|
||||||
EngineHandlerList mOnTeleportedHandlers{ "onTeleported" };
|
EngineHandlerList mOnTeleportedHandlers{ "onTeleported" };
|
||||||
EngineHandlerList mOnAnimationTextKeyHandlers{ "_onAnimationTextKey" };
|
EngineHandlerList mOnAnimationTextKeyHandlers{ "_onAnimationTextKey" };
|
||||||
EngineHandlerList mOnPlayAnimationHandlers{ "_onPlayAnimation" };
|
EngineHandlerList mOnPlayAnimationHandlers{ "_onPlayAnimation" };
|
||||||
|
EngineHandlerList mOnSkillUse{ "_onSkillUse" };
|
||||||
|
EngineHandlerList mOnSkillLevelUp{ "_onSkillLevelUp" };
|
||||||
};
|
};
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -112,13 +112,12 @@ namespace MWLua
|
||||||
mPlayerPackages.insert(mLocalPackages.begin(), mLocalPackages.end());
|
mPlayerPackages.insert(mLocalPackages.begin(), mLocalPackages.end());
|
||||||
|
|
||||||
LuaUtil::LuaStorage::initLuaBindings(mLua.sol());
|
LuaUtil::LuaStorage::initLuaBindings(mLua.sol());
|
||||||
mGlobalScripts.addPackage(
|
mGlobalScripts.addPackage("openmw.storage", LuaUtil::LuaStorage::initGlobalPackage(mLua, &mGlobalStorage));
|
||||||
"openmw.storage", LuaUtil::LuaStorage::initGlobalPackage(mLua.sol(), &mGlobalStorage));
|
|
||||||
mMenuScripts.addPackage(
|
mMenuScripts.addPackage(
|
||||||
"openmw.storage", LuaUtil::LuaStorage::initMenuPackage(mLua.sol(), &mGlobalStorage, &mPlayerStorage));
|
"openmw.storage", LuaUtil::LuaStorage::initMenuPackage(mLua, &mGlobalStorage, &mPlayerStorage));
|
||||||
mLocalPackages["openmw.storage"] = LuaUtil::LuaStorage::initLocalPackage(mLua.sol(), &mGlobalStorage);
|
mLocalPackages["openmw.storage"] = LuaUtil::LuaStorage::initLocalPackage(mLua, &mGlobalStorage);
|
||||||
mPlayerPackages["openmw.storage"]
|
mPlayerPackages["openmw.storage"]
|
||||||
= LuaUtil::LuaStorage::initPlayerPackage(mLua.sol(), &mGlobalStorage, &mPlayerStorage);
|
= LuaUtil::LuaStorage::initPlayerPackage(mLua, &mGlobalStorage, &mPlayerStorage);
|
||||||
|
|
||||||
mPlayerStorage.setActive(true);
|
mPlayerStorage.setActive(true);
|
||||||
mGlobalStorage.setActive(false);
|
mGlobalStorage.setActive(false);
|
||||||
|
@ -456,6 +455,17 @@ namespace MWLua
|
||||||
scripts->onPlayAnimation(groupname, options);
|
scripts->onPlayAnimation(groupname, options);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void LuaManager::skillUse(const MWWorld::Ptr& actor, ESM::RefId skillId, int useType, float scale)
|
||||||
|
{
|
||||||
|
mEngineEvents.addToQueue(EngineEvents::OnSkillUse{ getId(actor), skillId.serializeText(), useType, scale });
|
||||||
|
}
|
||||||
|
|
||||||
|
void LuaManager::skillLevelUp(const MWWorld::Ptr& actor, ESM::RefId skillId, std::string_view source)
|
||||||
|
{
|
||||||
|
mEngineEvents.addToQueue(
|
||||||
|
EngineEvents::OnSkillLevelUp{ getId(actor), skillId.serializeText(), std::string(source) });
|
||||||
|
}
|
||||||
|
|
||||||
void LuaManager::objectAddedToScene(const MWWorld::Ptr& ptr)
|
void LuaManager::objectAddedToScene(const MWWorld::Ptr& ptr)
|
||||||
{
|
{
|
||||||
mObjectLists.objectAddedToScene(ptr); // assigns generated RefNum if it is not set yet.
|
mObjectLists.objectAddedToScene(ptr); // assigns generated RefNum if it is not set yet.
|
||||||
|
|
|
@ -88,6 +88,8 @@ namespace MWLua
|
||||||
const MWRender::AnimPriority& priority, int blendMask, bool autodisable, float speedmult,
|
const MWRender::AnimPriority& priority, int blendMask, bool autodisable, float speedmult,
|
||||||
std::string_view start, std::string_view stop, float startpoint, uint32_t loops,
|
std::string_view start, std::string_view stop, float startpoint, uint32_t loops,
|
||||||
bool loopfallback) override;
|
bool loopfallback) override;
|
||||||
|
void skillUse(const MWWorld::Ptr& actor, ESM::RefId skillId, int useType, float scale) override;
|
||||||
|
void skillLevelUp(const MWWorld::Ptr& actor, ESM::RefId skillId, std::string_view source) override;
|
||||||
void exteriorCreated(MWWorld::CellStore& cell) override
|
void exteriorCreated(MWWorld::CellStore& cell) override
|
||||||
{
|
{
|
||||||
mEngineEvents.addToQueue(EngineEvents::OnNewExterior{ cell });
|
mEngineEvents.addToQueue(EngineEvents::OnNewExterior{ cell });
|
||||||
|
|
|
@ -16,6 +16,31 @@
|
||||||
#include "luamanagerimp.hpp"
|
#include "luamanagerimp.hpp"
|
||||||
#include "objectlists.hpp"
|
#include "objectlists.hpp"
|
||||||
|
|
||||||
|
namespace
|
||||||
|
{
|
||||||
|
template <class T = MWWorld::Ptr>
|
||||||
|
std::vector<T> parseIgnoreList(const sol::table& options)
|
||||||
|
{
|
||||||
|
std::vector<T> ignore;
|
||||||
|
|
||||||
|
if (const auto& ignoreObj = options.get<sol::optional<MWLua::LObject>>("ignore"))
|
||||||
|
{
|
||||||
|
ignore.push_back(ignoreObj->ptr());
|
||||||
|
}
|
||||||
|
else if (const auto& ignoreTable = options.get<sol::optional<sol::table>>("ignore"))
|
||||||
|
{
|
||||||
|
ignoreTable->for_each([&](const auto& _, const sol::object& value) {
|
||||||
|
if (value.is<MWLua::LObject>())
|
||||||
|
{
|
||||||
|
ignore.push_back(value.as<MWLua::LObject>().ptr());
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
return ignore;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
namespace sol
|
namespace sol
|
||||||
{
|
{
|
||||||
template <>
|
template <>
|
||||||
|
@ -71,24 +96,27 @@ namespace MWLua
|
||||||
}));
|
}));
|
||||||
|
|
||||||
api["castRay"] = [](const osg::Vec3f& from, const osg::Vec3f& to, sol::optional<sol::table> options) {
|
api["castRay"] = [](const osg::Vec3f& from, const osg::Vec3f& to, sol::optional<sol::table> options) {
|
||||||
MWWorld::Ptr ignore;
|
std::vector<MWWorld::ConstPtr> ignore;
|
||||||
int collisionType = MWPhysics::CollisionType_Default;
|
int collisionType = MWPhysics::CollisionType_Default;
|
||||||
float radius = 0;
|
float radius = 0;
|
||||||
if (options)
|
if (options)
|
||||||
{
|
{
|
||||||
sol::optional<LObject> ignoreObj = options->get<sol::optional<LObject>>("ignore");
|
ignore = parseIgnoreList<MWWorld::ConstPtr>(*options);
|
||||||
if (ignoreObj)
|
|
||||||
ignore = ignoreObj->ptr();
|
|
||||||
collisionType = options->get<sol::optional<int>>("collisionType").value_or(collisionType);
|
collisionType = options->get<sol::optional<int>>("collisionType").value_or(collisionType);
|
||||||
radius = options->get<sol::optional<float>>("radius").value_or(0);
|
radius = options->get<sol::optional<float>>("radius").value_or(0);
|
||||||
}
|
}
|
||||||
const MWPhysics::RayCastingInterface* rayCasting = MWBase::Environment::get().getWorld()->getRayCasting();
|
const MWPhysics::RayCastingInterface* rayCasting = MWBase::Environment::get().getWorld()->getRayCasting();
|
||||||
if (radius <= 0)
|
if (radius <= 0)
|
||||||
return rayCasting->castRay(from, to, ignore, std::vector<MWWorld::Ptr>(), collisionType);
|
{
|
||||||
|
return rayCasting->castRay(from, to, ignore, {}, collisionType);
|
||||||
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
if (!ignore.isEmpty())
|
for (const auto& ptr : ignore)
|
||||||
|
{
|
||||||
|
if (!ptr.isEmpty())
|
||||||
throw std::logic_error("Currently castRay doesn't support `ignore` when radius > 0");
|
throw std::logic_error("Currently castRay doesn't support `ignore` when radius > 0");
|
||||||
|
}
|
||||||
return rayCasting->castSphere(from, to, radius, collisionType);
|
return rayCasting->castSphere(from, to, radius, collisionType);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
@ -108,22 +136,37 @@ namespace MWLua
|
||||||
// and use this callback from the main thread at the beginning of the next frame processing.
|
// and use this callback from the main thread at the beginning of the next frame processing.
|
||||||
rayCasting->asyncCastRay(callback, from, to, ignore, std::vector<MWWorld::Ptr>(), collisionType);
|
rayCasting->asyncCastRay(callback, from, to, ignore, std::vector<MWWorld::Ptr>(), collisionType);
|
||||||
};*/
|
};*/
|
||||||
api["castRenderingRay"] = [manager = context.mLuaManager](const osg::Vec3f& from, const osg::Vec3f& to) {
|
api["castRenderingRay"] = [manager = context.mLuaManager](const osg::Vec3f& from, const osg::Vec3f& to,
|
||||||
|
const sol::optional<sol::table>& options) {
|
||||||
if (!manager->isProcessingInputEvents())
|
if (!manager->isProcessingInputEvents())
|
||||||
{
|
{
|
||||||
throw std::logic_error(
|
throw std::logic_error(
|
||||||
"castRenderingRay can be used only in player scripts during processing of input events; "
|
"castRenderingRay can be used only in player scripts during processing of input events; "
|
||||||
"use asyncCastRenderingRay instead.");
|
"use asyncCastRenderingRay instead.");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
std::vector<MWWorld::Ptr> ignore;
|
||||||
|
if (options.has_value())
|
||||||
|
{
|
||||||
|
ignore = parseIgnoreList(*options);
|
||||||
|
}
|
||||||
|
|
||||||
MWPhysics::RayCastingResult res;
|
MWPhysics::RayCastingResult res;
|
||||||
MWBase::Environment::get().getWorld()->castRenderingRay(res, from, to, false, false);
|
MWBase::Environment::get().getWorld()->castRenderingRay(res, from, to, false, false, ignore);
|
||||||
return res;
|
return res;
|
||||||
};
|
};
|
||||||
api["asyncCastRenderingRay"] = [context](
|
api["asyncCastRenderingRay"] = [context](const sol::table& callback, const osg::Vec3f& from,
|
||||||
const sol::table& callback, const osg::Vec3f& from, const osg::Vec3f& to) {
|
const osg::Vec3f& to, const sol::optional<sol::table>& options) {
|
||||||
context.mLuaManager->addAction([context, callback = LuaUtil::Callback::fromLua(callback), from, to] {
|
std::vector<MWWorld::Ptr> ignore;
|
||||||
|
if (options.has_value())
|
||||||
|
{
|
||||||
|
ignore = parseIgnoreList(*options);
|
||||||
|
}
|
||||||
|
|
||||||
|
context.mLuaManager->addAction([context, ignore = std::move(ignore),
|
||||||
|
callback = LuaUtil::Callback::fromLua(callback), from, to] {
|
||||||
MWPhysics::RayCastingResult res;
|
MWPhysics::RayCastingResult res;
|
||||||
MWBase::Environment::get().getWorld()->castRenderingRay(res, from, to, false, false);
|
MWBase::Environment::get().getWorld()->castRenderingRay(res, from, to, false, false, ignore);
|
||||||
context.mLuaManager->queueCallback(callback, sol::main_object(context.mLua->sol(), sol::in_place, res));
|
context.mLuaManager->queueCallback(callback, sol::main_object(context.mLua->sol(), sol::in_place, res));
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
117
apps/openmw/mwlua/racebindings.cpp
Normal file
117
apps/openmw/mwlua/racebindings.cpp
Normal file
|
@ -0,0 +1,117 @@
|
||||||
|
#include <components/esm/attr.hpp>
|
||||||
|
#include <components/esm3/loadrace.hpp>
|
||||||
|
#include <components/lua/luastate.hpp>
|
||||||
|
|
||||||
|
#include "../mwbase/environment.hpp"
|
||||||
|
#include "../mwworld/class.hpp"
|
||||||
|
#include "../mwworld/esmstore.hpp"
|
||||||
|
|
||||||
|
#include "idcollectionbindings.hpp"
|
||||||
|
#include "luamanagerimp.hpp"
|
||||||
|
#include "racebindings.hpp"
|
||||||
|
#include "types/types.hpp"
|
||||||
|
|
||||||
|
namespace
|
||||||
|
{
|
||||||
|
struct RaceAttributes
|
||||||
|
{
|
||||||
|
const ESM::Race& mRace;
|
||||||
|
const sol::state_view mLua;
|
||||||
|
|
||||||
|
sol::table getAttribute(ESM::RefId id) const
|
||||||
|
{
|
||||||
|
sol::table res(mLua, sol::create);
|
||||||
|
res["male"] = mRace.mData.getAttribute(id, true);
|
||||||
|
res["female"] = mRace.mData.getAttribute(id, false);
|
||||||
|
return LuaUtil::makeReadOnly(res);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
namespace sol
|
||||||
|
{
|
||||||
|
template <>
|
||||||
|
struct is_automagical<ESM::Race> : std::false_type
|
||||||
|
{
|
||||||
|
};
|
||||||
|
template <>
|
||||||
|
struct is_automagical<RaceAttributes> : std::false_type
|
||||||
|
{
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
namespace MWLua
|
||||||
|
{
|
||||||
|
sol::table initRaceRecordBindings(const Context& context)
|
||||||
|
{
|
||||||
|
sol::state_view& lua = context.mLua->sol();
|
||||||
|
sol::table races(context.mLua->sol(), sol::create);
|
||||||
|
addRecordFunctionBinding<ESM::Race>(races, context);
|
||||||
|
|
||||||
|
auto raceT = lua.new_usertype<ESM::Race>("ESM3_Race");
|
||||||
|
raceT[sol::meta_function::to_string]
|
||||||
|
= [](const ESM::Race& rec) -> std::string { return "ESM3_Race[" + rec.mId.toDebugString() + "]"; };
|
||||||
|
raceT["id"] = sol::readonly_property([](const ESM::Race& rec) { return rec.mId.serializeText(); });
|
||||||
|
raceT["name"] = sol::readonly_property([](const ESM::Race& rec) -> std::string_view { return rec.mName; });
|
||||||
|
raceT["description"]
|
||||||
|
= sol::readonly_property([](const ESM::Race& rec) -> std::string_view { return rec.mDescription; });
|
||||||
|
raceT["spells"] = sol::readonly_property(
|
||||||
|
[lua](const ESM::Race& rec) -> sol::table { return createReadOnlyRefIdTable(lua, rec.mPowers.mList); });
|
||||||
|
raceT["skills"] = sol::readonly_property([lua](const ESM::Race& rec) -> sol::table {
|
||||||
|
sol::table res(lua, sol::create);
|
||||||
|
for (const auto& skillBonus : rec.mData.mBonus)
|
||||||
|
{
|
||||||
|
ESM::RefId skill = ESM::Skill::indexToRefId(skillBonus.mSkill);
|
||||||
|
if (!skill.empty())
|
||||||
|
res[skill.serializeText()] = skillBonus.mBonus;
|
||||||
|
}
|
||||||
|
return res;
|
||||||
|
});
|
||||||
|
raceT["isPlayable"] = sol::readonly_property(
|
||||||
|
[](const ESM::Race& rec) -> bool { return rec.mData.mFlags & ESM::Race::Playable; });
|
||||||
|
raceT["isBeast"]
|
||||||
|
= sol::readonly_property([](const ESM::Race& rec) -> bool { return rec.mData.mFlags & ESM::Race::Beast; });
|
||||||
|
raceT["height"] = sol::readonly_property([lua](const ESM::Race& rec) -> sol::table {
|
||||||
|
sol::table res(lua, sol::create);
|
||||||
|
res["male"] = rec.mData.mMaleHeight;
|
||||||
|
res["female"] = rec.mData.mFemaleHeight;
|
||||||
|
return LuaUtil::makeReadOnly(res);
|
||||||
|
});
|
||||||
|
raceT["weight"] = sol::readonly_property([lua](const ESM::Race& rec) -> sol::table {
|
||||||
|
sol::table res(lua, sol::create);
|
||||||
|
res["male"] = rec.mData.mMaleWeight;
|
||||||
|
res["female"] = rec.mData.mFemaleWeight;
|
||||||
|
return LuaUtil::makeReadOnly(res);
|
||||||
|
});
|
||||||
|
|
||||||
|
raceT["attributes"] = sol::readonly_property([lua](const ESM::Race& rec) -> RaceAttributes {
|
||||||
|
return { rec, lua };
|
||||||
|
});
|
||||||
|
|
||||||
|
auto attributesT = lua.new_usertype<RaceAttributes>("ESM3_RaceAttributes");
|
||||||
|
const auto& store = MWBase::Environment::get().getESMStore()->get<ESM::Attribute>();
|
||||||
|
attributesT[sol::meta_function::index]
|
||||||
|
= [&](const RaceAttributes& attributes, std::string_view stringId) -> sol::optional<sol::table> {
|
||||||
|
ESM::RefId id = ESM::RefId::deserializeText(stringId);
|
||||||
|
if (!store.search(id))
|
||||||
|
return sol::nullopt;
|
||||||
|
return attributes.getAttribute(id);
|
||||||
|
};
|
||||||
|
attributesT[sol::meta_function::pairs] = [&](sol::this_state ts, RaceAttributes& attributes) {
|
||||||
|
auto iterator = store.begin();
|
||||||
|
return sol::as_function(
|
||||||
|
[iterator, attributes,
|
||||||
|
&store]() mutable -> std::pair<sol::optional<std::string>, sol::optional<sol::table>> {
|
||||||
|
if (iterator != store.end())
|
||||||
|
{
|
||||||
|
ESM::RefId id = iterator->mId;
|
||||||
|
++iterator;
|
||||||
|
return { id.serializeText(), attributes.getAttribute(id) };
|
||||||
|
}
|
||||||
|
return { sol::nullopt, sol::nullopt };
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
return LuaUtil::makeReadOnly(races);
|
||||||
|
}
|
||||||
|
}
|
13
apps/openmw/mwlua/racebindings.hpp
Normal file
13
apps/openmw/mwlua/racebindings.hpp
Normal file
|
@ -0,0 +1,13 @@
|
||||||
|
#ifndef MWLUA_RACEBINDINGS_H
|
||||||
|
#define MWLUA_RACEBINDINGS_H
|
||||||
|
|
||||||
|
#include <sol/forward.hpp>
|
||||||
|
|
||||||
|
#include "context.hpp"
|
||||||
|
|
||||||
|
namespace MWLua
|
||||||
|
{
|
||||||
|
sol::table initRaceRecordBindings(const Context& context);
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif // MWLUA_RACEBINDINGS_H
|
|
@ -174,12 +174,12 @@ namespace MWLua
|
||||||
api["say"] = sol::overload(
|
api["say"] = sol::overload(
|
||||||
[luaManager = context.mLuaManager](
|
[luaManager = context.mLuaManager](
|
||||||
std::string_view fileName, const Object& object, sol::optional<std::string_view> text) {
|
std::string_view fileName, const Object& object, sol::optional<std::string_view> text) {
|
||||||
MWBase::Environment::get().getSoundManager()->say(object.ptr(), std::string(fileName));
|
MWBase::Environment::get().getSoundManager()->say(object.ptr(), VFS::Path::Normalized(fileName));
|
||||||
if (text)
|
if (text)
|
||||||
luaManager->addUIMessage(*text);
|
luaManager->addUIMessage(*text);
|
||||||
},
|
},
|
||||||
[luaManager = context.mLuaManager](std::string_view fileName, sol::optional<std::string_view> text) {
|
[luaManager = context.mLuaManager](std::string_view fileName, sol::optional<std::string_view> text) {
|
||||||
MWBase::Environment::get().getSoundManager()->say(std::string(fileName));
|
MWBase::Environment::get().getSoundManager()->say(VFS::Path::Normalized(fileName));
|
||||||
if (text)
|
if (text)
|
||||||
luaManager->addUIMessage(*text);
|
luaManager->addUIMessage(*text);
|
||||||
});
|
});
|
||||||
|
@ -227,7 +227,7 @@ namespace MWLua
|
||||||
soundT["maxRange"]
|
soundT["maxRange"]
|
||||||
= sol::readonly_property([](const ESM::Sound& rec) -> unsigned char { return rec.mData.mMaxRange; });
|
= sol::readonly_property([](const ESM::Sound& rec) -> unsigned char { return rec.mData.mMaxRange; });
|
||||||
soundT["fileName"] = sol::readonly_property([](const ESM::Sound& rec) -> std::string {
|
soundT["fileName"] = sol::readonly_property([](const ESM::Sound& rec) -> std::string {
|
||||||
return VFS::Path::normalizeFilename(Misc::ResourceHelpers::correctSoundPath(rec.mSound));
|
return Misc::ResourceHelpers::correctSoundPath(VFS::Path::Normalized(rec.mSound)).value();
|
||||||
});
|
});
|
||||||
|
|
||||||
return LuaUtil::makeReadOnly(api);
|
return LuaUtil::makeReadOnly(api);
|
||||||
|
|
|
@ -73,6 +73,96 @@ namespace MWLua
|
||||||
"StatUpdateAction");
|
"StatUpdateAction");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void setCreatureValue(Index, std::string_view prop, const MWWorld::Ptr& ptr, const sol::object& value)
|
||||||
|
{
|
||||||
|
auto& stats = ptr.getClass().getCreatureStats(ptr);
|
||||||
|
if (prop == "current")
|
||||||
|
stats.setLevel(LuaUtil::cast<int>(value));
|
||||||
|
}
|
||||||
|
|
||||||
|
static void setNpcValue(Index index, std::string_view prop, const MWWorld::Ptr& ptr, const sol::object& value)
|
||||||
|
{
|
||||||
|
auto& stats = ptr.getClass().getNpcStats(ptr);
|
||||||
|
if (prop == "progress")
|
||||||
|
stats.setLevelProgress(LuaUtil::cast<int>(value));
|
||||||
|
else if (prop == "skillIncreasesForAttribute")
|
||||||
|
stats.setSkillIncreasesForAttribute(
|
||||||
|
*std::get<ESM::RefId>(index).getIf<ESM::StringRefId>(), LuaUtil::cast<int>(value));
|
||||||
|
else if (prop == "skillIncreasesForSpecialization")
|
||||||
|
stats.setSkillIncreasesForSpecialization(
|
||||||
|
static_cast<ESM::Class::Specialization>(std::get<int>(index)), LuaUtil::cast<int>(value));
|
||||||
|
}
|
||||||
|
|
||||||
|
class SkillIncreasesForAttributeStats
|
||||||
|
{
|
||||||
|
ObjectVariant mObject;
|
||||||
|
|
||||||
|
public:
|
||||||
|
SkillIncreasesForAttributeStats(ObjectVariant object)
|
||||||
|
: mObject(std::move(object))
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
sol::object get(const Context& context, ESM::StringRefId attributeId) const
|
||||||
|
{
|
||||||
|
const auto& ptr = mObject.ptr();
|
||||||
|
if (!ptr.getClass().isNpc())
|
||||||
|
return sol::nil;
|
||||||
|
|
||||||
|
return getValue(context, mObject, &setNpcValue, attributeId, "skillIncreasesForAttribute",
|
||||||
|
[attributeId](const MWWorld::Ptr& ptr) {
|
||||||
|
return ptr.getClass().getNpcStats(ptr).getSkillIncreasesForAttribute(attributeId);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
void set(const Context& context, ESM::StringRefId attributeId, const sol::object& value) const
|
||||||
|
{
|
||||||
|
const auto& ptr = mObject.ptr();
|
||||||
|
if (!ptr.getClass().isNpc())
|
||||||
|
return;
|
||||||
|
|
||||||
|
SelfObject* obj = mObject.asSelfObject();
|
||||||
|
addStatUpdateAction(context.mLuaManager, *obj);
|
||||||
|
obj->mStatsCache[SelfObject::CachedStat{ &setNpcValue, attributeId, "skillIncreasesForAttribute" }] = value;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
class SkillIncreasesForSpecializationStats
|
||||||
|
{
|
||||||
|
ObjectVariant mObject;
|
||||||
|
|
||||||
|
public:
|
||||||
|
SkillIncreasesForSpecializationStats(ObjectVariant object)
|
||||||
|
: mObject(std::move(object))
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
sol::object get(const Context& context, int specialization) const
|
||||||
|
{
|
||||||
|
const auto& ptr = mObject.ptr();
|
||||||
|
if (!ptr.getClass().isNpc())
|
||||||
|
return sol::nil;
|
||||||
|
|
||||||
|
return getValue(context, mObject, &setNpcValue, specialization, "skillIncreasesForSpecialization",
|
||||||
|
[specialization](const MWWorld::Ptr& ptr) {
|
||||||
|
return ptr.getClass().getNpcStats(ptr).getSkillIncreasesForSpecialization(
|
||||||
|
static_cast<ESM::Class::Specialization>(specialization));
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
void set(const Context& context, int specialization, const sol::object& value) const
|
||||||
|
{
|
||||||
|
const auto& ptr = mObject.ptr();
|
||||||
|
if (!ptr.getClass().isNpc())
|
||||||
|
return;
|
||||||
|
|
||||||
|
SelfObject* obj = mObject.asSelfObject();
|
||||||
|
addStatUpdateAction(context.mLuaManager, *obj);
|
||||||
|
obj->mStatsCache[SelfObject::CachedStat{ &setNpcValue, specialization, "skillIncreasesForSpecialization" }]
|
||||||
|
= value;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
class LevelStat
|
class LevelStat
|
||||||
{
|
{
|
||||||
ObjectVariant mObject;
|
ObjectVariant mObject;
|
||||||
|
@ -85,7 +175,7 @@ namespace MWLua
|
||||||
public:
|
public:
|
||||||
sol::object getCurrent(const Context& context) const
|
sol::object getCurrent(const Context& context) const
|
||||||
{
|
{
|
||||||
return getValue(context, mObject, &LevelStat::setValue, std::monostate{}, "current",
|
return getValue(context, mObject, &setCreatureValue, std::monostate{}, "current",
|
||||||
[](const MWWorld::Ptr& ptr) { return ptr.getClass().getCreatureStats(ptr).getLevel(); });
|
[](const MWWorld::Ptr& ptr) { return ptr.getClass().getCreatureStats(ptr).getLevel(); });
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -93,7 +183,7 @@ namespace MWLua
|
||||||
{
|
{
|
||||||
SelfObject* obj = mObject.asSelfObject();
|
SelfObject* obj = mObject.asSelfObject();
|
||||||
addStatUpdateAction(context.mLuaManager, *obj);
|
addStatUpdateAction(context.mLuaManager, *obj);
|
||||||
obj->mStatsCache[SelfObject::CachedStat{ &LevelStat::setValue, std::monostate{}, "current" }] = value;
|
obj->mStatsCache[SelfObject::CachedStat{ &setCreatureValue, std::monostate{}, "current" }] = value;
|
||||||
}
|
}
|
||||||
|
|
||||||
sol::object getProgress(const Context& context) const
|
sol::object getProgress(const Context& context) const
|
||||||
|
@ -101,7 +191,30 @@ namespace MWLua
|
||||||
const auto& ptr = mObject.ptr();
|
const auto& ptr = mObject.ptr();
|
||||||
if (!ptr.getClass().isNpc())
|
if (!ptr.getClass().isNpc())
|
||||||
return sol::nil;
|
return sol::nil;
|
||||||
return sol::make_object(context.mLua->sol(), ptr.getClass().getNpcStats(ptr).getLevelProgress());
|
|
||||||
|
return getValue(context, mObject, &setNpcValue, std::monostate{}, "progress",
|
||||||
|
[](const MWWorld::Ptr& ptr) { return ptr.getClass().getNpcStats(ptr).getLevelProgress(); });
|
||||||
|
}
|
||||||
|
|
||||||
|
void setProgress(const Context& context, const sol::object& value) const
|
||||||
|
{
|
||||||
|
const auto& ptr = mObject.ptr();
|
||||||
|
if (!ptr.getClass().isNpc())
|
||||||
|
return;
|
||||||
|
|
||||||
|
SelfObject* obj = mObject.asSelfObject();
|
||||||
|
addStatUpdateAction(context.mLuaManager, *obj);
|
||||||
|
obj->mStatsCache[SelfObject::CachedStat{ &setNpcValue, std::monostate{}, "progress" }] = value;
|
||||||
|
}
|
||||||
|
|
||||||
|
SkillIncreasesForAttributeStats getSkillIncreasesForAttributeStats() const
|
||||||
|
{
|
||||||
|
return SkillIncreasesForAttributeStats{ mObject };
|
||||||
|
}
|
||||||
|
|
||||||
|
SkillIncreasesForSpecializationStats getSkillIncreasesForSpecializationStats() const
|
||||||
|
{
|
||||||
|
return SkillIncreasesForSpecializationStats{ mObject };
|
||||||
}
|
}
|
||||||
|
|
||||||
static std::optional<LevelStat> create(ObjectVariant object, Index)
|
static std::optional<LevelStat> create(ObjectVariant object, Index)
|
||||||
|
@ -110,13 +223,6 @@ namespace MWLua
|
||||||
return {};
|
return {};
|
||||||
return LevelStat{ std::move(object) };
|
return LevelStat{ std::move(object) };
|
||||||
}
|
}
|
||||||
|
|
||||||
static void setValue(Index, std::string_view prop, const MWWorld::Ptr& ptr, const sol::object& value)
|
|
||||||
{
|
|
||||||
auto& stats = ptr.getClass().getCreatureStats(ptr);
|
|
||||||
if (prop == "current")
|
|
||||||
stats.setLevel(LuaUtil::cast<int>(value));
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
|
|
||||||
class DynamicStat
|
class DynamicStat
|
||||||
|
@ -323,6 +429,14 @@ namespace MWLua
|
||||||
|
|
||||||
namespace sol
|
namespace sol
|
||||||
{
|
{
|
||||||
|
template <>
|
||||||
|
struct is_automagical<MWLua::SkillIncreasesForAttributeStats> : std::false_type
|
||||||
|
{
|
||||||
|
};
|
||||||
|
template <>
|
||||||
|
struct is_automagical<MWLua::SkillIncreasesForSpecializationStats> : std::false_type
|
||||||
|
{
|
||||||
|
};
|
||||||
template <>
|
template <>
|
||||||
struct is_automagical<MWLua::LevelStat> : std::false_type
|
struct is_automagical<MWLua::LevelStat> : std::false_type
|
||||||
{
|
{
|
||||||
|
@ -360,10 +474,39 @@ namespace MWLua
|
||||||
sol::table stats(context.mLua->sol(), sol::create);
|
sol::table stats(context.mLua->sol(), sol::create);
|
||||||
actor["stats"] = LuaUtil::makeReadOnly(stats);
|
actor["stats"] = LuaUtil::makeReadOnly(stats);
|
||||||
|
|
||||||
|
auto skillIncreasesForAttributeStatsT
|
||||||
|
= context.mLua->sol().new_usertype<SkillIncreasesForAttributeStats>("SkillIncreasesForAttributeStats");
|
||||||
|
for (const auto& attribute : MWBase::Environment::get().getESMStore()->get<ESM::Attribute>())
|
||||||
|
{
|
||||||
|
skillIncreasesForAttributeStatsT[ESM::RefId(attribute.mId).serializeText()] = sol::property(
|
||||||
|
[=](const SkillIncreasesForAttributeStats& stat) { return stat.get(context, attribute.mId); },
|
||||||
|
[=](const SkillIncreasesForAttributeStats& stat, const sol::object& value) {
|
||||||
|
stat.set(context, attribute.mId, value);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
// ESM::Class::specializationIndexToLuaId.at(rec.mData.mSpecialization)
|
||||||
|
auto skillIncreasesForSpecializationStatsT
|
||||||
|
= context.mLua->sol().new_usertype<SkillIncreasesForSpecializationStats>(
|
||||||
|
"skillIncreasesForSpecializationStats");
|
||||||
|
for (int i = 0; i < 3; i++)
|
||||||
|
{
|
||||||
|
std::string_view index = ESM::Class::specializationIndexToLuaId.at(i);
|
||||||
|
skillIncreasesForSpecializationStatsT[index]
|
||||||
|
= sol::property([=](const SkillIncreasesForSpecializationStats& stat) { return stat.get(context, i); },
|
||||||
|
[=](const SkillIncreasesForSpecializationStats& stat, const sol::object& value) {
|
||||||
|
stat.set(context, i, value);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
auto levelStatT = context.mLua->sol().new_usertype<LevelStat>("LevelStat");
|
auto levelStatT = context.mLua->sol().new_usertype<LevelStat>("LevelStat");
|
||||||
levelStatT["current"] = sol::property([context](const LevelStat& stat) { return stat.getCurrent(context); },
|
levelStatT["current"] = sol::property([context](const LevelStat& stat) { return stat.getCurrent(context); },
|
||||||
[context](const LevelStat& stat, const sol::object& value) { stat.setCurrent(context, value); });
|
[context](const LevelStat& stat, const sol::object& value) { stat.setCurrent(context, value); });
|
||||||
levelStatT["progress"] = sol::property([context](const LevelStat& stat) { return stat.getProgress(context); });
|
levelStatT["progress"] = sol::property([context](const LevelStat& stat) { return stat.getProgress(context); },
|
||||||
|
[context](const LevelStat& stat, const sol::object& value) { stat.setProgress(context, value); });
|
||||||
|
levelStatT["skillIncreasesForAttribute"]
|
||||||
|
= sol::readonly_property([](const LevelStat& stat) { return stat.getSkillIncreasesForAttributeStats(); });
|
||||||
|
levelStatT["skillIncreasesForSpecialization"] = sol::readonly_property(
|
||||||
|
[](const LevelStat& stat) { return stat.getSkillIncreasesForSpecializationStats(); });
|
||||||
stats["level"] = addIndexedAccessor<LevelStat>(0);
|
stats["level"] = addIndexedAccessor<LevelStat>(0);
|
||||||
|
|
||||||
auto dynamicStatT = context.mLua->sol().new_usertype<DynamicStat>("DynamicStat");
|
auto dynamicStatT = context.mLua->sol().new_usertype<DynamicStat>("DynamicStat");
|
||||||
|
@ -461,6 +604,13 @@ namespace MWLua
|
||||||
skillT["attribute"] = sol::readonly_property([](const ESM::Skill& rec) -> std::string {
|
skillT["attribute"] = sol::readonly_property([](const ESM::Skill& rec) -> std::string {
|
||||||
return ESM::Attribute::indexToRefId(rec.mData.mAttribute).serializeText();
|
return ESM::Attribute::indexToRefId(rec.mData.mAttribute).serializeText();
|
||||||
});
|
});
|
||||||
|
skillT["skillGain"] = sol::readonly_property([lua](const ESM::Skill& rec) -> sol::table {
|
||||||
|
sol::table res(lua, sol::create);
|
||||||
|
int index = 1;
|
||||||
|
for (auto skillGain : rec.mData.mUseValue)
|
||||||
|
res[index++] = skillGain;
|
||||||
|
return res;
|
||||||
|
});
|
||||||
|
|
||||||
auto schoolT = context.mLua->sol().new_usertype<ESM::MagicSchool>("MagicSchool");
|
auto schoolT = context.mLua->sol().new_usertype<ESM::MagicSchool>("MagicSchool");
|
||||||
schoolT[sol::meta_function::to_string]
|
schoolT[sol::meta_function::to_string]
|
||||||
|
|
|
@ -403,6 +403,11 @@ namespace MWLua
|
||||||
return target.getClass().getCreatureStats(target).isDead();
|
return target.getClass().getCreatureStats(target).isDead();
|
||||||
};
|
};
|
||||||
|
|
||||||
|
actor["isDeathFinished"] = [](const Object& o) {
|
||||||
|
const auto& target = o.ptr();
|
||||||
|
return target.getClass().getCreatureStats(target).isDeathAnimationFinished();
|
||||||
|
};
|
||||||
|
|
||||||
actor["getEncumbrance"] = [](const Object& actor) -> float {
|
actor["getEncumbrance"] = [](const Object& actor) -> float {
|
||||||
const MWWorld::Ptr ptr = actor.ptr();
|
const MWWorld::Ptr ptr = actor.ptr();
|
||||||
return ptr.getClass().getEncumbrance(ptr);
|
return ptr.getClass().getEncumbrance(ptr);
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
#include <sol/sol.hpp>
|
#include <sol/sol.hpp>
|
||||||
|
|
||||||
|
#include "../../mwmechanics/spellutil.hpp"
|
||||||
#include "../../mwworld/class.hpp"
|
#include "../../mwworld/class.hpp"
|
||||||
|
|
||||||
#include "../itemdata.hpp"
|
#include "../itemdata.hpp"
|
||||||
|
@ -10,13 +11,21 @@ namespace MWLua
|
||||||
{
|
{
|
||||||
void addItemBindings(sol::table item, const Context& context)
|
void addItemBindings(sol::table item, const Context& context)
|
||||||
{
|
{
|
||||||
item["getEnchantmentCharge"]
|
item["getEnchantmentCharge"] = [](const Object& object) -> sol::optional<float> {
|
||||||
= [](const Object& object) { return object.ptr().getCellRef().getEnchantmentCharge(); };
|
float charge = object.ptr().getCellRef().getEnchantmentCharge();
|
||||||
item["setEnchantmentCharge"]
|
if (charge == -1)
|
||||||
= [](const GObject& object, float charge) { object.ptr().getCellRef().setEnchantmentCharge(charge); };
|
return sol::nullopt;
|
||||||
|
else
|
||||||
|
return charge;
|
||||||
|
};
|
||||||
|
item["setEnchantmentCharge"] = [](const GObject& object, sol::optional<float> charge) {
|
||||||
|
object.ptr().getCellRef().setEnchantmentCharge(charge.value_or(-1));
|
||||||
|
};
|
||||||
item["isRestocking"]
|
item["isRestocking"]
|
||||||
= [](const Object& object) -> bool { return object.ptr().getCellRef().getCount(false) < 0; };
|
= [](const Object& object) -> bool { return object.ptr().getCellRef().getCount(false) < 0; };
|
||||||
|
|
||||||
|
item["isCarriable"] = [](const Object& object) -> bool { return object.ptr().getClass().isItem(object.ptr()); };
|
||||||
|
|
||||||
addItemDataBindings(item, context);
|
addItemDataBindings(item, context);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -15,6 +15,7 @@
|
||||||
|
|
||||||
#include "../classbindings.hpp"
|
#include "../classbindings.hpp"
|
||||||
#include "../localscripts.hpp"
|
#include "../localscripts.hpp"
|
||||||
|
#include "../racebindings.hpp"
|
||||||
#include "../stats.hpp"
|
#include "../stats.hpp"
|
||||||
|
|
||||||
namespace sol
|
namespace sol
|
||||||
|
@ -85,7 +86,8 @@ namespace MWLua
|
||||||
record["baseGold"] = sol::readonly_property([](const ESM::NPC& rec) -> int { return rec.mNpdt.mGold; });
|
record["baseGold"] = sol::readonly_property([](const ESM::NPC& rec) -> int { return rec.mNpdt.mGold; });
|
||||||
addActorServicesBindings<ESM::NPC>(record, context);
|
addActorServicesBindings<ESM::NPC>(record, context);
|
||||||
|
|
||||||
npc["classes"] = initCoreClassBindings(context);
|
npc["classes"] = initClassRecordBindings(context);
|
||||||
|
npc["races"] = initRaceRecordBindings(context);
|
||||||
|
|
||||||
// This function is game-specific, in future we should replace it with something more universal.
|
// This function is game-specific, in future we should replace it with something more universal.
|
||||||
npc["isWerewolf"] = [](const Object& o) {
|
npc["isWerewolf"] = [](const Object& o) {
|
||||||
|
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Reference in a new issue