1
0
Fork 0
mirror of https://github.com/OpenMW/openmw.git synced 2025-04-30 22:11:23 +00:00

Merge branch 'master' of gitlab.com:openmw/openmw into lua_controller_cursor

This commit is contained in:
Zackhasacat 2024-04-07 08:58:30 -05:00
commit 6491bb4910
543 changed files with 8905 additions and 6750 deletions

View file

@ -521,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
@ -576,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}"))/"
@ -666,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
@ -689,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}"))/"
@ -729,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:

View file

@ -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

View file

@ -33,6 +33,8 @@
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
@ -56,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
@ -71,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
@ -93,22 +99,26 @@
Bug #7415: Unbreakable lock discrepancies Bug #7415: Unbreakable lock discrepancies
Bug #7416: Modpccrimelevel is different from vanilla Bug #7416: Modpccrimelevel is different from vanilla
Bug #7428: AutoCalc flag is not used to calculate enchantment costs Bug #7428: AutoCalc flag is not used to calculate enchantment costs
Bug #7447: OpenMW-CS: Dragging a cell of a different type (from the initial type) into the 3D view crashes OpenMW-CS
Bug #7450: Evading obstacles does not work for actors missing certain animations Bug #7450: Evading obstacles does not work for actors missing certain animations
Bug #7459: Icons get stacked on the cursor when picking up multiple items simultaneously Bug #7459: Icons get stacked on the cursor when picking up multiple items simultaneously
Bug #7472: Crash when enchanting last projectiles Bug #7472: Crash when enchanting last projectiles
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
Bug #7585: Difference in interior lighting between OpenMW with legacy lighting method enabled and vanilla Morrowind Bug #7585: Difference in interior lighting between OpenMW with legacy lighting method enabled and vanilla Morrowind
Bug #7587: Quick load related crash
Bug #7603: Scripts menu size is not updated properly Bug #7603: Scripts menu size is not updated properly
Bug #7604: Goblins Grunt becomes idle once injured Bug #7604: Goblins Grunt becomes idle once injured
Bug #7609: ForceGreeting should not open dialogue for werewolves Bug #7609: ForceGreeting should not open dialogue for werewolves
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 #7633: Groundcover should ignore non-geometry Drawables
@ -129,6 +139,7 @@
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
@ -136,6 +147,7 @@
Bug #7753: Editor: Actors Don't Scale According to Their Race 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
@ -143,22 +155,34 @@
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 #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 #7823: Game crashes when launching it.
Bug #7832: Ingredient tooltips show magnitude for Fortify Maximum Magicka effect 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 #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
Bug #7861: OpenMW-CS: Incorrect DIAL's type in INFO records
Bug #7872: Region sounds use wrong odds
Bug #7886: Equip and unequip animations can't share the animation track section
Bug #7887: Editor: Mismatched reported script data size and actual data size causes a crash during save
Bug #7898: Editor: Invalid reference scales are allowed
Bug #7899: Editor: Doors can't be unlocked
Bug #7901: Editor: Teleport-related fields shouldn't be editable if a ref does not teleport
Bug #7908: Key bindings names in the settings menu are layout-specific
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 #5926: Refraction based on water depth Feature #5926: Refraction based on water depth
Feature #5944: Option to use camera as sound listener Feature #5944: Option to use camera as sound listener
Feature #6149: Dehardcode Lua API_REVISION
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
@ -171,16 +195,19 @@
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
Feature #7546: Start the game on Fredas Feature #7546: Start the game on Fredas
Feature #7554: Controller binding for tab for menu navigation Feature #7554: Controller binding for tab for menu navigation
Feature #7568: Uninterruptable scripted music Feature #7568: Uninterruptable scripted music
Feature #7590: [Lua] Ability to deserialize YAML data from scripts
Feature #7606: Launcher: allow Shift-select in Archives tab Feature #7606: Launcher: allow Shift-select in Archives tab
Feature #7608: Make the missing dependencies warning when loading a savegame more helpful Feature #7608: Make the missing dependencies warning when loading a savegame more helpful
Feature #7618: Show the player character's health in the save details Feature #7618: Show the player character's health in the save details
@ -193,8 +220,14 @@
Feature #7792: Support Timescale Clouds Feature #7792: Support Timescale Clouds
Feature #7795: Support MaxNumberRipples INI setting Feature #7795: Support MaxNumberRipples INI setting
Feature #7805: Lua Menu context Feature #7805: Lua Menu context
Feature #7860: Lua: Expose NPC AI settings (fight, alarm, flee)
Feature #7875: Disable MyGUI windows snapping
Feature #7914: Do not allow to move GUI windows out of screen
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

View file

@ -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

View file

@ -4,8 +4,8 @@ set -o pipefail
LUPDATE="${LUPDATE:-lupdate}" LUPDATE="${LUPDATE:-lupdate}"
${LUPDATE:?} apps/wizard -ts files/lang/wizard_*.ts ${LUPDATE:?} -locations none apps/wizard -ts files/lang/wizard_*.ts
${LUPDATE:?} apps/launcher -ts files/lang/launcher_*.ts ${LUPDATE:?} -locations none apps/launcher -ts files/lang/launcher_*.ts
${LUPDATE:?} components/contentselector components/process -ts files/lang/components_*.ts ${LUPDATE:?} -locations none components/contentselector components/process -ts files/lang/components_*.ts
! (git diff --name-only | grep -q "^") || (echo -e "\033[0;31mBuild a 'translations' CMake target to update Qt localization for these files:\033[0;0m"; git diff --name-only | xargs -i echo -e "\033[0;31m{}\033[0;0m"; exit -1) ! (git diff --name-only | grep -q "^") || (echo -e "\033[0;31mBuild a 'translations' CMake target to update Qt localization for these files:\033[0;0m"; git diff --name-only | xargs -i echo -e "\033[0;31m{}\033[0;0m"; exit -1)

View file

@ -20,6 +20,7 @@ apps/openmw_test_suite/lua/test_storage.cpp
apps/openmw_test_suite/lua/test_ui_content.cpp apps/openmw_test_suite/lua/test_ui_content.cpp
apps/openmw_test_suite/lua/test_utilpackage.cpp apps/openmw_test_suite/lua/test_utilpackage.cpp
apps/openmw_test_suite/lua/test_inputactions.cpp apps/openmw_test_suite/lua/test_inputactions.cpp
apps/openmw_test_suite/lua/test_yaml.cpp
apps/openmw_test_suite/misc/test_endianness.cpp apps/openmw_test_suite/misc/test_endianness.cpp
apps/openmw_test_suite/misc/test_resourcehelpers.cpp apps/openmw_test_suite/misc/test_resourcehelpers.cpp
apps/openmw_test_suite/misc/test_stringops.cpp apps/openmw_test_suite/misc/test_stringops.cpp

View file

@ -44,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.
@ -80,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 54) set(OPENMW_LUA_API_REVISION 59)
set(OPENMW_POSTPROCESSING_API_REVISION 1) set(OPENMW_POSTPROCESSING_API_REVISION 1)
set(OPENMW_VERSION_COMMITHASH "") set(OPENMW_VERSION_COMMITHASH "")
@ -89,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)
@ -190,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
@ -718,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)
@ -1090,17 +1106,17 @@ if (USE_QT)
file(GLOB COMPONENTS_TS_FILES ${CMAKE_SOURCE_DIR}/files/lang/components_*.ts) file(GLOB COMPONENTS_TS_FILES ${CMAKE_SOURCE_DIR}/files/lang/components_*.ts)
get_target_property(QT_LUPDATE_EXECUTABLE Qt::lupdate IMPORTED_LOCATION) get_target_property(QT_LUPDATE_EXECUTABLE Qt::lupdate IMPORTED_LOCATION)
add_custom_target(translations add_custom_target(translations
COMMAND ${QT_LUPDATE_EXECUTABLE} ${CMAKE_SOURCE_DIR}/components/contentselector ${CMAKE_SOURCE_DIR}/components/process -ts ${COMPONENTS_TS_FILES} COMMAND ${QT_LUPDATE_EXECUTABLE} -locations none ${CMAKE_SOURCE_DIR}/components/contentselector ${CMAKE_SOURCE_DIR}/components/process -ts ${COMPONENTS_TS_FILES}
WORKING_DIRECTORY ${CMAKE_SOURCE_DIR}/components WORKING_DIRECTORY ${CMAKE_SOURCE_DIR}/components
VERBATIM VERBATIM
COMMAND_EXPAND_LISTS COMMAND_EXPAND_LISTS
COMMAND ${QT_LUPDATE_EXECUTABLE} ${CMAKE_SOURCE_DIR}/apps/wizard -ts ${WIZARD_TS_FILES} COMMAND ${QT_LUPDATE_EXECUTABLE} -locations none ${CMAKE_SOURCE_DIR}/apps/wizard -ts ${WIZARD_TS_FILES}
WORKING_DIRECTORY ${CMAKE_SOURCE_DIR}/apps/wizard WORKING_DIRECTORY ${CMAKE_SOURCE_DIR}/apps/wizard
VERBATIM VERBATIM
COMMAND_EXPAND_LISTS COMMAND_EXPAND_LISTS
COMMAND ${QT_LUPDATE_EXECUTABLE} ${CMAKE_SOURCE_DIR}/apps/launcher -ts ${LAUNCHER_TS_FILES} COMMAND ${QT_LUPDATE_EXECUTABLE} -locations none ${CMAKE_SOURCE_DIR}/apps/launcher -ts ${LAUNCHER_TS_FILES}
WORKING_DIRECTORY ${CMAKE_SOURCE_DIR}/apps/launcher WORKING_DIRECTORY ${CMAKE_SOURCE_DIR}/apps/launcher
VERBATIM VERBATIM
COMMAND_EXPAND_LISTS) COMMAND_EXPAND_LISTS)

View file

@ -20,7 +20,7 @@ Font Licenses:
Current Status Current Status
-------------- --------------
The main quests in Morrowind, Tribunal and Bloodmoon are all completable. Some issues with side quests are to be expected (but rare). Check the [bug tracker](https://gitlab.com/OpenMW/openmw/issues?label_name%5B%5D=1.0) for a list of issues we need to resolve before the "1.0" release. Even before the "1.0" release however, OpenMW boasts some new [features](https://wiki.openmw.org/index.php?title=Features), such as improved graphics and user interfaces. The main quests in Morrowind, Tribunal and Bloodmoon are all completable. Some issues with side quests are to be expected (but rare). Check the [bug tracker](https://gitlab.com/OpenMW/openmw/-/issues/?milestone_title=openmw-1.0) for a list of issues we need to resolve before the "1.0" release. Even before the "1.0" release however, OpenMW boasts some new [features](https://wiki.openmw.org/index.php?title=Features), such as improved graphics and user interfaces.
Pre-existing modifications created for the original Morrowind engine can be hit-and-miss. The OpenMW script compiler performs more thorough error-checking than Morrowind does, meaning that a mod created for Morrowind may not necessarily run in OpenMW. Some mods also rely on quirky behaviour or engine bugs in order to work. We are considering such compatibility issues on a case-by-case basis - in some cases adding a workaround to OpenMW may be feasible, in other cases fixing the mod will be the only option. If you know of any mods that work or don't work, feel free to add them to the [Mod status](https://wiki.openmw.org/index.php?title=Mod_status) wiki page. Pre-existing modifications created for the original Morrowind engine can be hit-and-miss. The OpenMW script compiler performs more thorough error-checking than Morrowind does, meaning that a mod created for Morrowind may not necessarily run in OpenMW. Some mods also rely on quirky behaviour or engine bugs in order to work. We are considering such compatibility issues on a case-by-case basis - in some cases adding a workaround to OpenMW may be feasible, in other cases fixing the mod will be the only option. If you know of any mods that work or don't work, feel free to add them to the [Mod status](https://wiki.openmw.org/index.php?title=Mod_status) wiki page.

View file

@ -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()

View file

@ -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);
} }

View file

@ -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()

View file

@ -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()

View file

@ -38,7 +38,7 @@ namespace
{ {
for (auto _ : state) for (auto _ : state)
{ {
static const float v = Settings::Manager::getFloat("sky blending start", "Fog"); static float v = Settings::Manager::getFloat("sky blending start", "Fog");
benchmark::DoNotOptimize(v); benchmark::DoNotOptimize(v);
} }
} }
@ -47,8 +47,8 @@ namespace
{ {
for (auto _ : state) for (auto _ : state)
{ {
static const float v1 = Settings::Manager::getFloat("near clip", "Camera"); static float v1 = Settings::Manager::getFloat("near clip", "Camera");
static const bool v2 = Settings::Manager::getBool("transparent postpass", "Post Processing"); static bool v2 = Settings::Manager::getBool("transparent postpass", "Post Processing");
benchmark::DoNotOptimize(v1); benchmark::DoNotOptimize(v1);
benchmark::DoNotOptimize(v2); benchmark::DoNotOptimize(v2);
} }
@ -58,9 +58,9 @@ namespace
{ {
for (auto _ : state) for (auto _ : state)
{ {
static const float v1 = Settings::Manager::getFloat("near clip", "Camera"); static float v1 = Settings::Manager::getFloat("near clip", "Camera");
static const bool v2 = Settings::Manager::getBool("transparent postpass", "Post Processing"); static bool v2 = Settings::Manager::getBool("transparent postpass", "Post Processing");
static const int v3 = Settings::Manager::getInt("reflection detail", "Water"); static int v3 = Settings::Manager::getInt("reflection detail", "Water");
benchmark::DoNotOptimize(v1); benchmark::DoNotOptimize(v1);
benchmark::DoNotOptimize(v2); benchmark::DoNotOptimize(v2);
benchmark::DoNotOptimize(v3); benchmark::DoNotOptimize(v3);
@ -71,7 +71,8 @@ namespace
{ {
for (auto _ : state) for (auto _ : state)
{ {
benchmark::DoNotOptimize(Settings::fog().mSkyBlendingStart.get()); float v = Settings::fog().mSkyBlendingStart.get();
benchmark::DoNotOptimize(v);
} }
} }
@ -79,8 +80,10 @@ namespace
{ {
for (auto _ : state) for (auto _ : state)
{ {
benchmark::DoNotOptimize(Settings::postProcessing().mTransparentPostpass.get()); bool v1 = Settings::postProcessing().mTransparentPostpass.get();
benchmark::DoNotOptimize(Settings::camera().mNearClip.get()); float v2 = Settings::camera().mNearClip.get();
benchmark::DoNotOptimize(v1);
benchmark::DoNotOptimize(v2);
} }
} }
@ -88,9 +91,12 @@ namespace
{ {
for (auto _ : state) for (auto _ : state)
{ {
benchmark::DoNotOptimize(Settings::postProcessing().mTransparentPostpass.get()); bool v1 = Settings::postProcessing().mTransparentPostpass.get();
benchmark::DoNotOptimize(Settings::camera().mNearClip.get()); float v2 = Settings::camera().mNearClip.get();
benchmark::DoNotOptimize(Settings::water().mReflectionDetail.get()); int v3 = Settings::water().mReflectionDetail.get();
benchmark::DoNotOptimize(v1);
benchmark::DoNotOptimize(v2);
benchmark::DoNotOptimize(v3);
} }
} }

View file

@ -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>

View file

@ -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)
{ {

View file

@ -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>

View file

@ -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>

View file

@ -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;
}

View file

@ -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);

View file

@ -180,22 +180,23 @@ namespace
void printEffectList(const ESM::EffectList& effects) void printEffectList(const ESM::EffectList& effects)
{ {
int i = 0; int i = 0;
for (const ESM::ENAMstruct& effect : effects.mList) for (const ESM::IndexedENAMstruct& effect : effects.mList)
{ {
std::cout << " Effect[" << i << "]: " << magicEffectLabel(effect.mEffectID) << " (" << effect.mEffectID std::cout << " Effect[" << i << "]: " << magicEffectLabel(effect.mData.mEffectID) << " ("
<< ")" << std::endl; << effect.mData.mEffectID << ")" << std::endl;
if (effect.mSkill != -1) if (effect.mData.mSkill != -1)
std::cout << " Skill: " << skillLabel(effect.mSkill) << " (" << (int)effect.mSkill << ")" std::cout << " Skill: " << skillLabel(effect.mData.mSkill) << " (" << (int)effect.mData.mSkill << ")"
<< std::endl; << std::endl;
if (effect.mAttribute != -1) if (effect.mData.mAttribute != -1)
std::cout << " Attribute: " << attributeLabel(effect.mAttribute) << " (" << (int)effect.mAttribute std::cout << " Attribute: " << attributeLabel(effect.mData.mAttribute) << " ("
<< ")" << std::endl; << (int)effect.mData.mAttribute << ")" << std::endl;
std::cout << " Range: " << rangeTypeLabel(effect.mRange) << " (" << effect.mRange << ")" << std::endl; std::cout << " Range: " << rangeTypeLabel(effect.mData.mRange) << " (" << effect.mData.mRange << ")"
<< std::endl;
// Area is always zero if range type is "Self" // Area is always zero if range type is "Self"
if (effect.mRange != ESM::RT_Self) if (effect.mData.mRange != ESM::RT_Self)
std::cout << " Area: " << effect.mArea << std::endl; std::cout << " Area: " << effect.mData.mArea << std::endl;
std::cout << " Duration: " << effect.mDuration << std::endl; std::cout << " Duration: " << effect.mData.mDuration << std::endl;
std::cout << " Magnitude: " << effect.mMagnMin << "-" << effect.mMagnMax << std::endl; std::cout << " Magnitude: " << effect.mData.mMagnMin << "-" << effect.mData.mMagnMax << std::endl;
i++; i++;
} }
} }
@ -479,7 +480,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 +613,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;
} }
@ -840,8 +840,7 @@ namespace EsmTool
std::cout << " Quest Status: " << questStatusLabel(mData.mQuestStatus) << " (" << mData.mQuestStatus << ")" std::cout << " Quest Status: " << questStatusLabel(mData.mQuestStatus) << " (" << mData.mQuestStatus << ")"
<< std::endl; << std::endl;
std::cout << " Unknown1: " << mData.mData.mUnknown1 << std::endl; std::cout << " Type: " << dialogTypeLabel(mData.mData.mType) << std::endl;
std::cout << " Unknown2: " << (int)mData.mData.mUnknown2 << std::endl;
for (const ESM::DialInfo::SelectStruct& rule : mData.mSelects) for (const ESM::DialInfo::SelectStruct& rule : mData.mSelects)
std::cout << " Select Rule: " << ruleString(rule) << std::endl; std::cout << " Select Rule: " << ruleString(rule) << std::endl;
@ -898,9 +897,6 @@ namespace EsmTool
if (const ESM::Land::LandData* data = mData.getLandData(mData.mDataTypes)) if (const ESM::Land::LandData* data = mData.getLandData(mData.mDataTypes))
{ {
std::cout << " Height Offset: " << data->mHeightOffset << std::endl; std::cout << " Height Offset: " << data->mHeightOffset << std::endl;
// Lots of missing members.
std::cout << " Unknown1: " << data->mUnk1 << std::endl;
std::cout << " Unknown2: " << static_cast<unsigned>(data->mUnk2) << std::endl;
} }
mData.unloadData(); mData.unloadData();
std::cout << " Deleted: " << mIsDeleted << std::endl; std::cout << " Deleted: " << mIsDeleted << std::endl;
@ -1138,7 +1134,6 @@ namespace EsmTool
std::cout << " Coordinates: (" << point.mX << "," << point.mY << "," << point.mZ << ")" << std::endl; std::cout << " Coordinates: (" << point.mX << "," << point.mY << "," << point.mZ << ")" << std::endl;
std::cout << " Auto-Generated: " << (int)point.mAutogenerated << std::endl; std::cout << " Auto-Generated: " << (int)point.mAutogenerated << std::endl;
std::cout << " Connections: " << (int)point.mConnectionNum << std::endl; std::cout << " Connections: " << (int)point.mConnectionNum << std::endl;
std::cout << " Unknown: " << point.mUnknown << std::endl;
i++; i++;
} }

View file

@ -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>

View file

@ -232,7 +232,7 @@ namespace ESSImport
esm.skip(4); esm.skip(4);
} }
esm.getExact(nam8, 32); esm.getT(nam8);
newcell.mFogOfWar.reserve(16 * 16); newcell.mFogOfWar.reserve(16 * 16);
for (int x = 0; x < 16; ++x) for (int x = 0; x < 16; ++x)

View file

@ -1,10 +1,30 @@
#include "importcellref.hpp" #include "importcellref.hpp"
#include <components/esm3/esmreader.hpp> #include <components/esm3/esmreader.hpp>
#include <components/misc/concepts.hpp>
#include <cstdint> #include <cstdint>
namespace ESSImport namespace ESSImport
{ {
template <Misc::SameAsWithoutCvref<ACDT> T>
void decompose(T&& v, const auto& f)
{
f(v.mUnknown, v.mFlags, v.mBreathMeter, v.mUnknown2, v.mDynamic, v.mUnknown3, v.mAttributes, v.mMagicEffects,
v.mUnknown4, v.mGoldPool, v.mCountDown, v.mUnknown5);
}
template <Misc::SameAsWithoutCvref<ACSC> T>
void decompose(T&& v, const auto& f)
{
f(v.mUnknown1, v.mFlags, v.mUnknown2, v.mCorpseClearCountdown, v.mUnknown3);
}
template <Misc::SameAsWithoutCvref<ANIS> T>
void decompose(T&& v, const auto& f)
{
f(v.mGroupIndex, v.mUnknown, v.mTime);
}
void CellRef::load(ESM::ESMReader& esm) void CellRef::load(ESM::ESMReader& esm)
{ {
@ -45,14 +65,9 @@ namespace ESSImport
bool isDeleted = false; bool isDeleted = false;
ESM::CellRef::loadData(esm, isDeleted); ESM::CellRef::loadData(esm, isDeleted);
mActorData.mHasACDT mActorData.mHasACDT = esm.getOptionalComposite("ACDT", mActorData.mACDT);
= esm.getHNOT("ACDT", mActorData.mACDT.mUnknown, mActorData.mACDT.mFlags, mActorData.mACDT.mBreathMeter,
mActorData.mACDT.mUnknown2, mActorData.mACDT.mDynamic, mActorData.mACDT.mUnknown3,
mActorData.mACDT.mAttributes, mActorData.mACDT.mMagicEffects, mActorData.mACDT.mUnknown4,
mActorData.mACDT.mGoldPool, mActorData.mACDT.mCountDown, mActorData.mACDT.mUnknown5);
mActorData.mHasACSC = esm.getHNOT("ACSC", mActorData.mACSC.mUnknown1, mActorData.mACSC.mFlags, mActorData.mHasACSC = esm.getOptionalComposite("ACSC", mActorData.mACSC);
mActorData.mACSC.mUnknown2, mActorData.mACSC.mCorpseClearCountdown, mActorData.mACSC.mUnknown3);
if (esm.isNextSub("ACSL")) if (esm.isNextSub("ACSL"))
esm.skipHSubSize(112); esm.skipHSubSize(112);
@ -127,8 +142,7 @@ namespace ESSImport
if (esm.isNextSub("ND3D")) if (esm.isNextSub("ND3D"))
esm.skipHSub(); esm.skipHSub();
mActorData.mHasANIS mActorData.mHasANIS = esm.getOptionalComposite("ANIS", mActorData.mANIS);
= esm.getHNOT("ANIS", mActorData.mANIS.mGroupIndex, mActorData.mANIS.mUnknown, mActorData.mANIS.mTime);
if (esm.isNextSub("LVCR")) if (esm.isNextSub("LVCR"))
{ {
@ -146,7 +160,7 @@ namespace ESSImport
// I've seen DATA *twice* on a creature record, and with the exact same content too! weird // I've seen DATA *twice* on a creature record, and with the exact same content too! weird
// alarmvoi0000.ess // alarmvoi0000.ess
for (int i = 0; i < 2; ++i) for (int i = 0; i < 2; ++i)
esm.getHNOT("DATA", mPos.pos, mPos.rot); esm.getOptionalComposite("DATA", mPos);
mDeleted = 0; mDeleted = 0;
if (esm.isNextSub("DELE")) if (esm.isNextSub("DELE"))

View file

@ -135,7 +135,7 @@ namespace ESSImport
sub.mFileOffset = esm.getFileOffset(); sub.mFileOffset = esm.getFileOffset();
sub.mName = esm.retSubName().toString(); sub.mName = esm.retSubName().toString();
sub.mData.resize(esm.getSubSize()); sub.mData.resize(esm.getSubSize());
esm.getExact(&sub.mData[0], sub.mData.size()); esm.getExact(sub.mData.data(), sub.mData.size());
rec.mSubrecords.push_back(sub); rec.mSubrecords.push_back(sub);
} }
file.mRecords.push_back(rec); file.mRecords.push_back(rec);

View file

@ -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>

View file

@ -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();

View file

@ -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));
@ -244,6 +246,11 @@ bool Launcher::SettingsPage::loadSettings()
int shadowResIndex = shadowResolutionComboBox->findText(QString::number(shadowRes)); int shadowResIndex = shadowResolutionComboBox->findText(QString::number(shadowRes));
if (shadowResIndex != -1) if (shadowResIndex != -1)
shadowResolutionComboBox->setCurrentIndex(shadowResIndex); shadowResolutionComboBox->setCurrentIndex(shadowResIndex);
else
{
shadowResolutionComboBox->addItem(QString::number(shadowRes));
shadowResolutionComboBox->setCurrentIndex(shadowResolutionComboBox->count() - 1);
}
connect(shadowDistanceCheckBox, &QCheckBox::toggled, this, &SettingsPage::slotShadowDistLimitToggled); connect(shadowDistanceCheckBox, &QCheckBox::toggled, this, &SettingsPage::slotShadowDistLimitToggled);
@ -583,9 +590,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);

View file

@ -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:

View file

@ -652,45 +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>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;If true, use paging and LOD algorithms to display the entire terrain. If false, only display terrain of the loaded cells.&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
</property>
<property name="text">
<string>Distant land</string>
</property>
</widget>
</item>
<item row="2" column="1">
<widget class="QDoubleSpinBox" name="viewingDistanceComboBox">
<property name="decimals">
<number>3</number>
</property>
<property name="suffix">
<string> cells</string>
</property>
<property name="minimum">
<double>0.000000000000000</double>
</property>
<property name="singleStep">
<double>0.125000000000000</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>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;Controls how large an object must be to be visible in the scene. The objects 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.&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string> <string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;Controls how large an object must be to be visible in the scene. The objects 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.&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
@ -700,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>
@ -723,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>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;If true, use paging and LOD algorithms to display the entire terrain. If false, only display terrain of the loaded cells.&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</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>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;Use object paging for active cells grid.&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string> <string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;Use object paging for active cells grid.&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
@ -869,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>
@ -972,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>
@ -1027,7 +1033,7 @@
<string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;Maximum distance at which lights will appear (measured in units).&lt;/p&gt;&lt;p&gt;Set this to 0 to use an unlimited distance.&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string> <string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;Maximum distance at which lights will appear (measured in units).&lt;/p&gt;&lt;p&gt;Set this to 0 to use an unlimited distance.&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</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>
@ -1050,7 +1056,7 @@
<string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;Maximum number of lights per object.&lt;/p&gt;&lt;p&gt;A low number near default will cause light popping similar to what you would see with legacy lighting.&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string> <string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;Maximum number of lights per object.&lt;/p&gt;&lt;p&gt;A low number near default will cause light popping similar to what you would see with legacy lighting.&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
</property> </property>
<property name="text"> <property name="text">
<string>Max light sources</string> <string>Max lights</string>
</property> </property>
</widget> </widget>
</item> </item>
@ -1060,7 +1066,7 @@
<string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;Fraction of maximum distance at which lights will start to fade.&lt;/p&gt;&lt;p&gt;Set this to a low value for slower transitions or a high value for quicker transitions.&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string> <string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;Fraction of maximum distance at which lights will start to fade.&lt;/p&gt;&lt;p&gt;Set this to a low value for slower transitions or a high value for quicker transitions.&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</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>
@ -1102,7 +1108,7 @@
<string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;Multipler for bounding sphere of lights.&lt;/p&gt;&lt;p&gt;Higher numbers allows for smooth falloff but require an increase in number of max lights.&lt;/p&gt;&lt;p&gt;Does not effect the illumination or strength of lights.&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string> <string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;Multipler for bounding sphere of lights.&lt;/p&gt;&lt;p&gt;Higher numbers allows for smooth falloff but require an increase in number of max lights.&lt;/p&gt;&lt;p&gt;Does not effect the illumination or strength of lights.&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</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>
@ -1112,7 +1118,7 @@
<string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;Minimum ambient interior brightness.&lt;/p&gt;&lt;p&gt;Increase this if you feel interiors are too dark.&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string> <string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;Minimum ambient interior brightness.&lt;/p&gt;&lt;p&gt;Increase this if you feel interiors are too dark.&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</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>
@ -1323,7 +1329,7 @@
</item> </item>
</layout> </layout>
</item> </item>
<item row="0" column="0"> <item>
<widget class="QCheckBox" name="cameraListenerCheckBox"> <widget class="QCheckBox" name="cameraListenerCheckBox">
<property name="toolTip"> <property name="toolTip">
<string>In third-person view, use the camera as the sound listener instead of the player character.</string> <string>In third-person view, use the camera as the sound listener instead of the player character.</string>

View file

@ -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>

View file

@ -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>

View file

@ -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()

View file

@ -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;
@ -84,10 +65,10 @@ void readNIF(
std::cout << " from '" << Files::pathToUnicodeString(isBSA(source) ? source.filename() : source) << "'"; std::cout << " from '" << Files::pathToUnicodeString(isBSA(source) ? source.filename() : source) << "'";
std::cout << std::endl; std::cout << std::endl;
} }
std::filesystem::path fullPath = !source.empty() ? source / path : path; const std::filesystem::path fullPath = !source.empty() ? source / path : path;
try try
{ {
Nif::NIFFile file(fullPath); Nif::NIFFile file(Files::pathToUnicodeString(fullPath));
Nif::Reader reader(file, nullptr); Nif::Reader reader(file, nullptr);
if (vfs != nullptr) if (vfs != nullptr)
reader.parse(vfs->get(pathStr)); reader.parse(vfs->get(pathStr));
@ -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)
} {
for (auto& file : ba2Col) try
{ {
readVFS(makeBsaArchive(file.second), file.second, quiet); readVFS(VFS::makeBsaArchive(file.second), file.second, quiet);
}
catch (const std::exception& e)
{
std::cerr << "Failed to read archive file '" << Files::pathToUnicodeString(file.second)
<< "': " << e.what() << std::endl;
}
}
} }
} }
} }

View file

@ -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>

View file

@ -135,7 +135,7 @@ void CSMDoc::WriteDialogueCollectionStage::perform(int stage, Messages& messages
if (topic.mState == CSMWorld::RecordBase::State_Deleted) if (topic.mState == CSMWorld::RecordBase::State_Deleted)
{ {
// if the topic is deleted, we do not need to bother with INFO records. // if the topic is deleted, we do not need to bother with INFO records.
ESM::Dialogue dialogue = topic.get(); const ESM::Dialogue& dialogue = topic.get();
writer.startRecord(dialogue.sRecordId); writer.startRecord(dialogue.sRecordId);
dialogue.save(writer, true); dialogue.save(writer, true);
writer.endRecord(dialogue.sRecordId); writer.endRecord(dialogue.sRecordId);
@ -187,6 +187,7 @@ void CSMDoc::WriteDialogueCollectionStage::perform(int stage, Messages& messages
{ {
ESM::DialInfo info = record.get(); ESM::DialInfo info = record.get();
info.mId = record.get().mOriginalId; info.mId = record.get().mOriginalId;
info.mData.mType = topic.get().mType;
if (iter == infos.begin()) if (iter == infos.begin())
info.mPrev = ESM::RefId(); info.mPrev = ESM::RefId();

View file

@ -452,7 +452,10 @@ std::shared_ptr<CSMFilter::Node> CSMFilter::Parser::parseText()
return std::shared_ptr<Node>(); return std::shared_ptr<Node>();
} }
return std::make_shared<TextNode>(columnId, text); auto node = std::make_shared<TextNode>(columnId, text);
if (!node->isValid())
error();
return node;
} }
std::shared_ptr<CSMFilter::Node> CSMFilter::Parser::parseValue() std::shared_ptr<CSMFilter::Node> CSMFilter::Parser::parseValue()

View file

@ -34,6 +34,8 @@ namespace CSMFilter
///< Return a string that represents this node. ///< Return a string that represents this node.
/// ///
/// \param numericColumns Use numeric IDs instead of string to represent columns. /// \param numericColumns Use numeric IDs instead of string to represent columns.
bool isValid() { return mRegExp.isValid(); }
}; };
} }

View file

@ -90,6 +90,7 @@ void CSMPrefs::State::declare()
.setTooltip( .setTooltip(
"When editing a record, open the view in a new window," "When editing a record, open the view in a new window,"
" rather than docked in the main view."); " rather than docked in the main view.");
declareInt(mValues->mIdTables.mFilterDelay, "Delay before applying a filter (in miliseconds)");
declareCategory("ID Dialogues"); declareCategory("ID Dialogues");
declareBool(mValues->mIdDialogues.mToolbar, "Show toolbar"); declareBool(mValues->mIdDialogues.mToolbar, "Show toolbar");

View file

@ -138,6 +138,7 @@ namespace CSMPrefs
EnumSettingValue mJumpToAdded{ mIndex, sName, "jump-to-added", sJumpAndSelectValues, 0 }; EnumSettingValue mJumpToAdded{ mIndex, sName, "jump-to-added", sJumpAndSelectValues, 0 };
Settings::SettingValue<bool> mExtendedConfig{ mIndex, sName, "extended-config", false }; Settings::SettingValue<bool> mExtendedConfig{ mIndex, sName, "extended-config", false };
Settings::SettingValue<bool> mSubviewNewWindow{ mIndex, sName, "subview-new-window", false }; Settings::SettingValue<bool> mSubviewNewWindow{ mIndex, sName, "subview-new-window", false };
Settings::SettingValue<int> mFilterDelay{ mIndex, sName, "filter-delay", 500 };
}; };
struct IdDialoguesCategory : Settings::WithIndex struct IdDialoguesCategory : Settings::WithIndex

View file

@ -60,38 +60,38 @@ void CSMTools::EnchantmentCheckStage::perform(int stage, CSMDoc::Messages& messa
} }
else else
{ {
std::vector<ESM::ENAMstruct>::const_iterator effect = enchantment.mEffects.mList.begin(); std::vector<ESM::IndexedENAMstruct>::const_iterator effect = enchantment.mEffects.mList.begin();
for (size_t i = 1; i <= enchantment.mEffects.mList.size(); i++) for (size_t i = 1; i <= enchantment.mEffects.mList.size(); i++)
{ {
const std::string number = std::to_string(i); const std::string number = std::to_string(i);
// At the time of writing this effects, attributes and skills are hardcoded // At the time of writing this effects, attributes and skills are hardcoded
if (effect->mEffectID < 0 || effect->mEffectID > 142) if (effect->mData.mEffectID < 0 || effect->mData.mEffectID > 142)
{ {
messages.add(id, "Effect #" + number + " is invalid", "", CSMDoc::Message::Severity_Error); messages.add(id, "Effect #" + number + " is invalid", "", CSMDoc::Message::Severity_Error);
++effect; ++effect;
continue; continue;
} }
if (effect->mSkill < -1 || effect->mSkill > 26) if (effect->mData.mSkill < -1 || effect->mData.mSkill > 26)
messages.add( messages.add(
id, "Effect #" + number + " affected skill is invalid", "", CSMDoc::Message::Severity_Error); id, "Effect #" + number + " affected skill is invalid", "", CSMDoc::Message::Severity_Error);
if (effect->mAttribute < -1 || effect->mAttribute > 7) if (effect->mData.mAttribute < -1 || effect->mData.mAttribute > 7)
messages.add( messages.add(
id, "Effect #" + number + " affected attribute is invalid", "", CSMDoc::Message::Severity_Error); id, "Effect #" + number + " affected attribute is invalid", "", CSMDoc::Message::Severity_Error);
if (effect->mRange < 0 || effect->mRange > 2) if (effect->mData.mRange < 0 || effect->mData.mRange > 2)
messages.add(id, "Effect #" + number + " range is invalid", "", CSMDoc::Message::Severity_Error); messages.add(id, "Effect #" + number + " range is invalid", "", CSMDoc::Message::Severity_Error);
if (effect->mArea < 0) if (effect->mData.mArea < 0)
messages.add(id, "Effect #" + number + " area is negative", "", CSMDoc::Message::Severity_Error); messages.add(id, "Effect #" + number + " area is negative", "", CSMDoc::Message::Severity_Error);
if (effect->mDuration < 0) if (effect->mData.mDuration < 0)
messages.add(id, "Effect #" + number + " duration is negative", "", CSMDoc::Message::Severity_Error); messages.add(id, "Effect #" + number + " duration is negative", "", CSMDoc::Message::Severity_Error);
if (effect->mMagnMin < 0) if (effect->mData.mMagnMin < 0)
messages.add( messages.add(
id, "Effect #" + number + " minimum magnitude is negative", "", CSMDoc::Message::Severity_Error); id, "Effect #" + number + " minimum magnitude is negative", "", CSMDoc::Message::Severity_Error);
if (effect->mMagnMax < 0) if (effect->mData.mMagnMax < 0)
messages.add( messages.add(
id, "Effect #" + number + " maximum magnitude is negative", "", CSMDoc::Message::Severity_Error); id, "Effect #" + number + " maximum magnitude is negative", "", CSMDoc::Message::Severity_Error);
if (effect->mMagnMin > effect->mMagnMax) if (effect->mData.mMagnMin > effect->mData.mMagnMax)
messages.add(id, "Effect #" + number + " minimum magnitude is higher than maximum magnitude", "", messages.add(id, "Effect #" + number + " minimum magnitude is higher than maximum magnitude", "",
CSMDoc::Message::Severity_Error); CSMDoc::Message::Severity_Error);
++effect; ++effect;

View file

@ -58,7 +58,12 @@ void CSMTools::MagicEffectCheckStage::perform(int stage, CSMDoc::Messages& messa
return; return;
ESM::MagicEffect effect = record.get(); ESM::MagicEffect effect = record.get();
CSMWorld::UniversalId id(CSMWorld::UniversalId::Type_MagicEffect, effect.mId); CSMWorld::UniversalId id(CSMWorld::UniversalId::Type_MagicEffect, CSMWorld::getRecordId(effect));
if (effect.mData.mSpeed <= 0.0f)
{
messages.add(id, "Speed is less than or equal to zero", "", CSMDoc::Message::Severity_Error);
}
if (effect.mDescription.empty()) if (effect.mDescription.empty())
{ {

View file

@ -971,7 +971,7 @@ 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();
record2.mScale = data.toFloat(); record2.mScale = std::clamp(data.toFloat(), 0.5f, 2.0f);
record.setModified(record2); record.setModified(record2);
} }
@ -1136,8 +1136,8 @@ namespace CSMWorld
template <typename ESXRecordT> template <typename ESXRecordT>
struct TeleportColumn : public Column<ESXRecordT> struct TeleportColumn : public Column<ESXRecordT>
{ {
TeleportColumn() TeleportColumn(int flags)
: Column<ESXRecordT>(Columns::ColumnId_Teleport, ColumnBase::Display_Boolean) : Column<ESXRecordT>(Columns::ColumnId_Teleport, ColumnBase::Display_Boolean, flags)
{ {
} }
@ -1165,6 +1165,8 @@ namespace CSMWorld
QVariant get(const Record<ESXRecordT>& record) const override QVariant get(const Record<ESXRecordT>& record) const override
{ {
if (!record.get().mTeleport)
return QVariant();
return QString::fromUtf8(record.get().mDestCell.c_str()); return QString::fromUtf8(record.get().mDestCell.c_str());
} }
@ -1182,6 +1184,26 @@ namespace CSMWorld
bool isUserEditable() const override { return true; } bool isUserEditable() const override { return true; }
}; };
template <typename ESXRecordT>
struct IsLockedColumn : public Column<ESXRecordT>
{
IsLockedColumn(int flags)
: Column<ESXRecordT>(Columns::ColumnId_IsLocked, ColumnBase::Display_Boolean, flags)
{
}
QVariant get(const Record<ESXRecordT>& record) const override { return record.get().mIsLocked; }
void set(Record<ESXRecordT>& record, const QVariant& data) override
{
ESXRecordT record2 = record.get();
record2.mIsLocked = data.toBool();
record.setModified(record2);
}
bool isEditable() const override { return true; }
};
template <typename ESXRecordT> template <typename ESXRecordT>
struct LockLevelColumn : public Column<ESXRecordT> struct LockLevelColumn : public Column<ESXRecordT>
{ {
@ -1190,7 +1212,12 @@ namespace CSMWorld
{ {
} }
QVariant get(const Record<ESXRecordT>& record) const override { return record.get().mLockLevel; } QVariant get(const Record<ESXRecordT>& record) const override
{
if (record.get().mIsLocked)
return record.get().mLockLevel;
return QVariant();
}
void set(Record<ESXRecordT>& record, const QVariant& data) override void set(Record<ESXRecordT>& record, const QVariant& data) override
{ {
@ -1212,7 +1239,9 @@ namespace CSMWorld
QVariant get(const Record<ESXRecordT>& record) const override QVariant get(const Record<ESXRecordT>& record) const override
{ {
return QString::fromUtf8(record.get().mKey.getRefIdString().c_str()); if (record.get().mIsLocked)
return QString::fromUtf8(record.get().mKey.getRefIdString().c_str());
return QVariant();
} }
void set(Record<ESXRecordT>& record, const QVariant& data) override void set(Record<ESXRecordT>& record, const QVariant& data) override
@ -1282,17 +1311,21 @@ namespace CSMWorld
{ {
ESM::Position ESXRecordT::*mPosition; ESM::Position ESXRecordT::*mPosition;
int mIndex; int mIndex;
bool mIsDoor;
PosColumn(ESM::Position ESXRecordT::*position, int index, bool door) PosColumn(ESM::Position ESXRecordT::*position, int index, bool door)
: Column<ESXRecordT>((door ? Columns::ColumnId_DoorPositionXPos : Columns::ColumnId_PositionXPos) + index, : Column<ESXRecordT>((door ? Columns::ColumnId_DoorPositionXPos : Columns::ColumnId_PositionXPos) + index,
ColumnBase::Display_Float) ColumnBase::Display_Float)
, mPosition(position) , mPosition(position)
, mIndex(index) , mIndex(index)
, mIsDoor(door)
{ {
} }
QVariant get(const Record<ESXRecordT>& record) const override QVariant get(const Record<ESXRecordT>& record) const override
{ {
if (!record.get().mTeleport && mIsDoor)
return QVariant();
const ESM::Position& position = record.get().*mPosition; const ESM::Position& position = record.get().*mPosition;
return position.pos[mIndex]; return position.pos[mIndex];
} }
@ -1316,17 +1349,21 @@ namespace CSMWorld
{ {
ESM::Position ESXRecordT::*mPosition; ESM::Position ESXRecordT::*mPosition;
int mIndex; int mIndex;
bool mIsDoor;
RotColumn(ESM::Position ESXRecordT::*position, int index, bool door) RotColumn(ESM::Position ESXRecordT::*position, int index, bool door)
: Column<ESXRecordT>((door ? Columns::ColumnId_DoorPositionXRot : Columns::ColumnId_PositionXRot) + index, : Column<ESXRecordT>((door ? Columns::ColumnId_DoorPositionXRot : Columns::ColumnId_PositionXRot) + index,
ColumnBase::Display_Double) ColumnBase::Display_Double)
, mPosition(position) , mPosition(position)
, mIndex(index) , mIndex(index)
, mIsDoor(door)
{ {
} }
QVariant get(const Record<ESXRecordT>& record) const override QVariant get(const Record<ESXRecordT>& record) const override
{ {
if (!record.get().mTeleport && mIsDoor)
return QVariant();
const ESM::Position& position = record.get().*mPosition; const ESM::Position& position = record.get().*mPosition;
return osg::RadiansToDegrees(position.rot[mIndex]); return osg::RadiansToDegrees(position.rot[mIndex]);
} }
@ -2052,6 +2089,26 @@ namespace CSMWorld
bool isEditable() const override { return true; } bool isEditable() const override { return true; }
}; };
template <typename ESXRecordT>
struct ProjectileSpeedColumn : public Column<ESXRecordT>
{
ProjectileSpeedColumn()
: Column<ESXRecordT>(Columns::ColumnId_ProjectileSpeed, ColumnBase::Display_Float)
{
}
QVariant get(const Record<ESXRecordT>& record) const override { return record.get().mData.mSpeed; }
void set(Record<ESXRecordT>& record, const QVariant& data) override
{
ESXRecordT record2 = record.get();
record2.mData.mSpeed = data.toFloat();
record.setModified(record2);
}
bool isEditable() const override { return true; }
};
template <typename ESXRecordT> template <typename ESXRecordT>
struct SchoolColumn : public Column<ESXRecordT> struct SchoolColumn : public Column<ESXRecordT>
{ {

View file

@ -57,8 +57,10 @@ namespace CSMWorld
{ ColumnId_Charges, "Charges" }, { ColumnId_Charges, "Charges" },
{ ColumnId_Enchantment, "Enchantment" }, { ColumnId_Enchantment, "Enchantment" },
{ ColumnId_StackCount, "Count" }, { ColumnId_StackCount, "Count" },
{ ColumnId_GoldValue, "Value" },
{ ColumnId_Teleport, "Teleport" }, { ColumnId_Teleport, "Teleport" },
{ ColumnId_TeleportCell, "Teleport Cell" }, { ColumnId_TeleportCell, "Teleport Cell" },
{ ColumnId_IsLocked, "Locked" },
{ ColumnId_LockLevel, "Lock Level" }, { ColumnId_LockLevel, "Lock Level" },
{ ColumnId_Key, "Key" }, { ColumnId_Key, "Key" },
{ ColumnId_Trap, "Trap" }, { ColumnId_Trap, "Trap" },
@ -235,6 +237,7 @@ namespace CSMWorld
{ ColumnId_RegionSounds, "Sounds" }, { ColumnId_RegionSounds, "Sounds" },
{ ColumnId_SoundName, "Sound Name" }, { ColumnId_SoundName, "Sound Name" },
{ ColumnId_SoundChance, "Chance" }, { ColumnId_SoundChance, "Chance" },
{ ColumnId_SoundProbability, "Probability" },
{ ColumnId_FactionReactions, "Reactions" }, { ColumnId_FactionReactions, "Reactions" },
{ ColumnId_FactionRanks, "Ranks" }, { ColumnId_FactionRanks, "Ranks" },
@ -376,6 +379,7 @@ namespace CSMWorld
{ ColumnId_Blocked, "Blocked" }, { ColumnId_Blocked, "Blocked" },
{ ColumnId_LevelledCreatureId, "Levelled Creature" }, { ColumnId_LevelledCreatureId, "Levelled Creature" },
{ ColumnId_ProjectileSpeed, "Projectile Speed" },
// end marker // end marker
{ -1, 0 }, { -1, 0 },

View file

@ -349,6 +349,14 @@ namespace CSMWorld
ColumnId_SelectionGroupObjects = 316, ColumnId_SelectionGroupObjects = 316,
ColumnId_SoundProbability = 317,
ColumnId_IsLocked = 318,
ColumnId_ProjectileSpeed = 319,
ColumnId_GoldValue = 320,
// Allocated to a separate value range, so we don't get a collision should we ever need // Allocated to a separate value range, so we don't get a collision should we ever need
// to extend the number of use values. // to extend the number of use values.
ColumnId_UseValue1 = 0x10000, ColumnId_UseValue1 = 0x10000,

View file

@ -161,7 +161,7 @@ CSMWorld::Data::Data(ToUTF8::FromType encoding, const Files::PathContainer& data
defines["radialFog"] = "0"; defines["radialFog"] = "0";
defines["lightingModel"] = "0"; defines["lightingModel"] = "0";
defines["reverseZ"] = "0"; defines["reverseZ"] = "0";
defines["refraction_enabled"] = "0"; defines["waterRefraction"] = "0";
for (const auto& define : shadowDefines) for (const auto& define : shadowDefines)
defines[define.first] = define.second; defines[define.first] = define.second;
mResourceSystem->getSceneManager()->getShaderManager().setGlobalDefines(defines); mResourceSystem->getSceneManager()->getShaderManager().setGlobalDefines(defines);
@ -301,8 +301,8 @@ CSMWorld::Data::Data(ToUTF8::FromType encoding, const Files::PathContainer& data
mRegions.addColumn(new NestedParentColumn<ESM::Region>(Columns::ColumnId_RegionWeather)); mRegions.addColumn(new NestedParentColumn<ESM::Region>(Columns::ColumnId_RegionWeather));
index = mRegions.getColumns() - 1; index = mRegions.getColumns() - 1;
mRegions.addAdapter(std::make_pair(&mRegions.getColumn(index), new RegionWeatherAdapter())); mRegions.addAdapter(std::make_pair(&mRegions.getColumn(index), new RegionWeatherAdapter()));
mRegions.getNestableColumn(index)->addColumn( mRegions.getNestableColumn(index)->addColumn(new NestedChildColumn(
new NestedChildColumn(Columns::ColumnId_WeatherName, ColumnBase::Display_String, false)); Columns::ColumnId_WeatherName, ColumnBase::Display_String, ColumnBase::Flag_Dialogue, false));
mRegions.getNestableColumn(index)->addColumn( mRegions.getNestableColumn(index)->addColumn(
new NestedChildColumn(Columns::ColumnId_WeatherChance, ColumnBase::Display_UnsignedInteger8)); new NestedChildColumn(Columns::ColumnId_WeatherChance, ColumnBase::Display_UnsignedInteger8));
// Region Sounds // Region Sounds
@ -313,6 +313,8 @@ CSMWorld::Data::Data(ToUTF8::FromType encoding, const Files::PathContainer& data
new NestedChildColumn(Columns::ColumnId_SoundName, ColumnBase::Display_Sound)); new NestedChildColumn(Columns::ColumnId_SoundName, ColumnBase::Display_Sound));
mRegions.getNestableColumn(index)->addColumn( mRegions.getNestableColumn(index)->addColumn(
new NestedChildColumn(Columns::ColumnId_SoundChance, ColumnBase::Display_UnsignedInteger8)); new NestedChildColumn(Columns::ColumnId_SoundChance, ColumnBase::Display_UnsignedInteger8));
mRegions.getNestableColumn(index)->addColumn(new NestedChildColumn(
Columns::ColumnId_SoundProbability, ColumnBase::Display_String, ColumnBase::Flag_Dialogue, false));
mBirthsigns.addColumn(new StringIdColumn<ESM::BirthSign>); mBirthsigns.addColumn(new StringIdColumn<ESM::BirthSign>);
mBirthsigns.addColumn(new RecordStateColumn<ESM::BirthSign>); mBirthsigns.addColumn(new RecordStateColumn<ESM::BirthSign>);
@ -500,6 +502,7 @@ CSMWorld::Data::Data(ToUTF8::FromType encoding, const Files::PathContainer& data
mMagicEffects.addColumn(new FixedRecordTypeColumn<ESM::MagicEffect>(UniversalId::Type_MagicEffect)); mMagicEffects.addColumn(new FixedRecordTypeColumn<ESM::MagicEffect>(UniversalId::Type_MagicEffect));
mMagicEffects.addColumn(new SchoolColumn<ESM::MagicEffect>); mMagicEffects.addColumn(new SchoolColumn<ESM::MagicEffect>);
mMagicEffects.addColumn(new BaseCostColumn<ESM::MagicEffect>); mMagicEffects.addColumn(new BaseCostColumn<ESM::MagicEffect>);
mMagicEffects.addColumn(new ProjectileSpeedColumn<ESM::MagicEffect>);
mMagicEffects.addColumn(new EffectTextureColumn<ESM::MagicEffect>(Columns::ColumnId_Icon)); mMagicEffects.addColumn(new EffectTextureColumn<ESM::MagicEffect>(Columns::ColumnId_Icon));
mMagicEffects.addColumn(new EffectTextureColumn<ESM::MagicEffect>(Columns::ColumnId_Particle)); mMagicEffects.addColumn(new EffectTextureColumn<ESM::MagicEffect>(Columns::ColumnId_Particle));
mMagicEffects.addColumn(new EffectObjectColumn<ESM::MagicEffect>(Columns::ColumnId_CastingObject)); mMagicEffects.addColumn(new EffectObjectColumn<ESM::MagicEffect>(Columns::ColumnId_CastingObject));
@ -510,6 +513,7 @@ CSMWorld::Data::Data(ToUTF8::FromType encoding, const Files::PathContainer& data
mMagicEffects.addColumn(new EffectSoundColumn<ESM::MagicEffect>(Columns::ColumnId_HitSound)); mMagicEffects.addColumn(new EffectSoundColumn<ESM::MagicEffect>(Columns::ColumnId_HitSound));
mMagicEffects.addColumn(new EffectSoundColumn<ESM::MagicEffect>(Columns::ColumnId_AreaSound)); mMagicEffects.addColumn(new EffectSoundColumn<ESM::MagicEffect>(Columns::ColumnId_AreaSound));
mMagicEffects.addColumn(new EffectSoundColumn<ESM::MagicEffect>(Columns::ColumnId_BoltSound)); mMagicEffects.addColumn(new EffectSoundColumn<ESM::MagicEffect>(Columns::ColumnId_BoltSound));
mMagicEffects.addColumn( mMagicEffects.addColumn(
new FlagColumn<ESM::MagicEffect>(Columns::ColumnId_AllowSpellmaking, ESM::MagicEffect::AllowSpellmaking)); new FlagColumn<ESM::MagicEffect>(Columns::ColumnId_AllowSpellmaking, ESM::MagicEffect::AllowSpellmaking));
mMagicEffects.addColumn( mMagicEffects.addColumn(
@ -589,7 +593,8 @@ CSMWorld::Data::Data(ToUTF8::FromType encoding, const Files::PathContainer& data
mRefs.addColumn(new ChargesColumn<CellRef>); mRefs.addColumn(new ChargesColumn<CellRef>);
mRefs.addColumn(new EnchantmentChargesColumn<CellRef>); mRefs.addColumn(new EnchantmentChargesColumn<CellRef>);
mRefs.addColumn(new StackSizeColumn<CellRef>); mRefs.addColumn(new StackSizeColumn<CellRef>);
mRefs.addColumn(new TeleportColumn<CellRef>); mRefs.addColumn(new TeleportColumn<CellRef>(
ColumnBase::Flag_Table | ColumnBase::Flag_Dialogue | ColumnBase::Flag_Dialogue_Refresh));
mRefs.addColumn(new TeleportCellColumn<CellRef>); mRefs.addColumn(new TeleportCellColumn<CellRef>);
mRefs.addColumn(new PosColumn<CellRef>(&CellRef::mDoorDest, 0, true)); mRefs.addColumn(new PosColumn<CellRef>(&CellRef::mDoorDest, 0, true));
mRefs.addColumn(new PosColumn<CellRef>(&CellRef::mDoorDest, 1, true)); mRefs.addColumn(new PosColumn<CellRef>(&CellRef::mDoorDest, 1, true));
@ -597,6 +602,8 @@ CSMWorld::Data::Data(ToUTF8::FromType encoding, const Files::PathContainer& data
mRefs.addColumn(new RotColumn<CellRef>(&CellRef::mDoorDest, 0, true)); mRefs.addColumn(new RotColumn<CellRef>(&CellRef::mDoorDest, 0, true));
mRefs.addColumn(new RotColumn<CellRef>(&CellRef::mDoorDest, 1, true)); mRefs.addColumn(new RotColumn<CellRef>(&CellRef::mDoorDest, 1, true));
mRefs.addColumn(new RotColumn<CellRef>(&CellRef::mDoorDest, 2, true)); mRefs.addColumn(new RotColumn<CellRef>(&CellRef::mDoorDest, 2, true));
mRefs.addColumn(new IsLockedColumn<CellRef>(
ColumnBase::Flag_Table | ColumnBase::Flag_Dialogue | ColumnBase::Flag_Dialogue_Refresh));
mRefs.addColumn(new LockLevelColumn<CellRef>); mRefs.addColumn(new LockLevelColumn<CellRef>);
mRefs.addColumn(new KeyColumn<CellRef>); mRefs.addColumn(new KeyColumn<CellRef>);
mRefs.addColumn(new TrapColumn<CellRef>); mRefs.addColumn(new TrapColumn<CellRef>);

View file

@ -63,9 +63,18 @@ bool CSMWorld::IdTableProxyModel::filterAcceptsRow(int sourceRow, const QModelIn
CSMWorld::IdTableProxyModel::IdTableProxyModel(QObject* parent) CSMWorld::IdTableProxyModel::IdTableProxyModel(QObject* parent)
: QSortFilterProxyModel(parent) : QSortFilterProxyModel(parent)
, mFilterTimer{ new QTimer(this) }
, mSourceModel(nullptr) , mSourceModel(nullptr)
{ {
setSortCaseSensitivity(Qt::CaseInsensitive); setSortCaseSensitivity(Qt::CaseInsensitive);
mFilterTimer->setSingleShot(true);
int intervalSetting = CSMPrefs::State::get()["ID Tables"]["filter-delay"].toInt();
mFilterTimer->setInterval(intervalSetting);
connect(&CSMPrefs::State::get(), &CSMPrefs::State::settingChanged, this,
[this](const CSMPrefs::Setting* setting) { this->settingChanged(setting); });
connect(mFilterTimer.get(), &QTimer::timeout, this, [this]() { this->timerTimeout(); });
} }
QModelIndex CSMWorld::IdTableProxyModel::getModelIndex(const std::string& id, int column) const QModelIndex CSMWorld::IdTableProxyModel::getModelIndex(const std::string& id, int column) const
@ -87,10 +96,8 @@ void CSMWorld::IdTableProxyModel::setSourceModel(QAbstractItemModel* model)
void CSMWorld::IdTableProxyModel::setFilter(const std::shared_ptr<CSMFilter::Node>& filter) void CSMWorld::IdTableProxyModel::setFilter(const std::shared_ptr<CSMFilter::Node>& filter)
{ {
beginResetModel(); mAwaitingFilter = filter;
mFilter = filter; mFilterTimer->start();
updateColumnMap();
endResetModel();
} }
bool CSMWorld::IdTableProxyModel::lessThan(const QModelIndex& left, const QModelIndex& right) const bool CSMWorld::IdTableProxyModel::lessThan(const QModelIndex& left, const QModelIndex& right) const
@ -131,6 +138,26 @@ void CSMWorld::IdTableProxyModel::refreshFilter()
} }
} }
void CSMWorld::IdTableProxyModel::timerTimeout()
{
if (mAwaitingFilter)
{
beginResetModel();
mFilter = mAwaitingFilter;
updateColumnMap();
endResetModel();
mAwaitingFilter.reset();
}
}
void CSMWorld::IdTableProxyModel::settingChanged(const CSMPrefs::Setting* setting)
{
if (*setting == "ID Tables/filter-delay")
{
mFilterTimer->setInterval(setting->toInt());
}
}
void CSMWorld::IdTableProxyModel::sourceRowsInserted(const QModelIndex& parent, int /*start*/, int end) void CSMWorld::IdTableProxyModel::sourceRowsInserted(const QModelIndex& parent, int /*start*/, int end)
{ {
refreshFilter(); refreshFilter();

View file

@ -10,6 +10,9 @@
#include <QModelIndex> #include <QModelIndex>
#include <QSortFilterProxyModel> #include <QSortFilterProxyModel>
#include <QString> #include <QString>
#include <QTimer>
#include "../prefs/state.hpp"
#include "columns.hpp" #include "columns.hpp"
@ -29,6 +32,8 @@ namespace CSMWorld
Q_OBJECT Q_OBJECT
std::shared_ptr<CSMFilter::Node> mFilter; std::shared_ptr<CSMFilter::Node> mFilter;
std::unique_ptr<QTimer> mFilterTimer;
std::shared_ptr<CSMFilter::Node> mAwaitingFilter;
std::map<int, int> mColumnMap; // column ID, column index in this model (or -1) std::map<int, int> mColumnMap; // column ID, column index in this model (or -1)
// Cache of enum values for enum columns (e.g. Modified, Record Type). // Cache of enum values for enum columns (e.g. Modified, Record Type).
@ -68,6 +73,10 @@ namespace CSMWorld
virtual void sourceDataChanged(const QModelIndex& topLeft, const QModelIndex& bottomRight); virtual void sourceDataChanged(const QModelIndex& topLeft, const QModelIndex& bottomRight);
void timerTimeout();
void settingChanged(const CSMPrefs::Setting* setting);
signals: signals:
void rowAdded(const std::string& id); void rowAdded(const std::string& id);

View file

@ -38,7 +38,6 @@ namespace CSMWorld
point.mZ = 0; point.mZ = 0;
point.mAutogenerated = 0; point.mAutogenerated = 0;
point.mConnectionNum = 0; point.mConnectionNum = 0;
point.mUnknown = 0;
points.insert(points.begin() + position, point); points.insert(points.begin() + position, point);
pathgrid.mData.mPoints = pathgrid.mPoints.size(); pathgrid.mData.mPoints = pathgrid.mPoints.size();
@ -414,20 +413,32 @@ namespace CSMWorld
QVariant RegionSoundListAdapter::getData(const Record<ESM::Region>& record, int subRowIndex, int subColIndex) const QVariant RegionSoundListAdapter::getData(const Record<ESM::Region>& record, int subRowIndex, int subColIndex) const
{ {
ESM::Region region = record.get(); const ESM::Region& region = record.get();
std::vector<ESM::Region::SoundRef>& soundList = region.mSoundList; const std::vector<ESM::Region::SoundRef>& soundList = region.mSoundList;
if (subRowIndex < 0 || subRowIndex >= static_cast<int>(soundList.size())) const size_t index = static_cast<size_t>(subRowIndex);
if (subRowIndex < 0 || index >= soundList.size())
throw std::runtime_error("index out of range"); throw std::runtime_error("index out of range");
ESM::Region::SoundRef soundRef = soundList[subRowIndex]; const ESM::Region::SoundRef& soundRef = soundList[subRowIndex];
switch (subColIndex) switch (subColIndex)
{ {
case 0: case 0:
return QString(soundRef.mSound.getRefIdString().c_str()); return QString(soundRef.mSound.getRefIdString().c_str());
case 1: case 1:
return soundRef.mChance; return soundRef.mChance;
case 2:
{
float probability = 1.f;
for (size_t i = 0; i < index; ++i)
{
const float p = std::min(soundList[i].mChance / 100.f, 1.f);
probability *= 1.f - p;
}
probability *= std::min(soundRef.mChance / 100.f, 1.f) * 100.f;
return QString("%1%").arg(probability, 0, 'f', 2);
}
default: default:
throw std::runtime_error("Region sounds subcolumn index out of range"); throw std::runtime_error("Region sounds subcolumn index out of range");
} }
@ -463,7 +474,7 @@ namespace CSMWorld
int RegionSoundListAdapter::getColumnsCount(const Record<ESM::Region>& record) const int RegionSoundListAdapter::getColumnsCount(const Record<ESM::Region>& record) const
{ {
return 2; return 3;
} }
int RegionSoundListAdapter::getRowsCount(const Record<ESM::Region>& record) const int RegionSoundListAdapter::getRowsCount(const Record<ESM::Region>& record) const
@ -996,7 +1007,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;

View file

@ -255,20 +255,22 @@ namespace CSMWorld
{ {
ESXRecordT magic = record.get(); ESXRecordT magic = record.get();
std::vector<ESM::ENAMstruct>& effectsList = magic.mEffects.mList; std::vector<ESM::IndexedENAMstruct>& effectsList = magic.mEffects.mList;
// blank row // blank row
ESM::ENAMstruct effect; ESM::IndexedENAMstruct effect;
effect.mEffectID = 0; effect.mIndex = position;
effect.mSkill = -1; effect.mData.mEffectID = 0;
effect.mAttribute = -1; effect.mData.mSkill = -1;
effect.mRange = 0; effect.mData.mAttribute = -1;
effect.mArea = 0; effect.mData.mRange = 0;
effect.mDuration = 0; effect.mData.mArea = 0;
effect.mMagnMin = 0; effect.mData.mDuration = 0;
effect.mMagnMax = 0; effect.mData.mMagnMin = 0;
effect.mData.mMagnMax = 0;
effectsList.insert(effectsList.begin() + position, effect); effectsList.insert(effectsList.begin() + position, effect);
magic.mEffects.updateIndexes();
record.setModified(magic); record.setModified(magic);
} }
@ -277,12 +279,13 @@ namespace CSMWorld
{ {
ESXRecordT magic = record.get(); ESXRecordT magic = record.get();
std::vector<ESM::ENAMstruct>& effectsList = magic.mEffects.mList; std::vector<ESM::IndexedENAMstruct>& effectsList = magic.mEffects.mList;
if (rowToRemove < 0 || rowToRemove >= static_cast<int>(effectsList.size())) if (rowToRemove < 0 || rowToRemove >= static_cast<int>(effectsList.size()))
throw std::runtime_error("index out of range"); throw std::runtime_error("index out of range");
effectsList.erase(effectsList.begin() + rowToRemove); effectsList.erase(effectsList.begin() + rowToRemove);
magic.mEffects.updateIndexes();
record.setModified(magic); record.setModified(magic);
} }
@ -292,7 +295,7 @@ namespace CSMWorld
ESXRecordT magic = record.get(); ESXRecordT magic = record.get();
magic.mEffects.mList magic.mEffects.mList
= static_cast<const NestedTableWrapper<std::vector<ESM::ENAMstruct>>&>(nestedTable).mNestedTable; = static_cast<const NestedTableWrapper<std::vector<ESM::IndexedENAMstruct>>&>(nestedTable).mNestedTable;
record.setModified(magic); record.setModified(magic);
} }
@ -300,19 +303,19 @@ namespace CSMWorld
NestedTableWrapperBase* table(const Record<ESXRecordT>& record) const override NestedTableWrapperBase* table(const Record<ESXRecordT>& record) const override
{ {
// deleted by dtor of NestedTableStoring // deleted by dtor of NestedTableStoring
return new NestedTableWrapper<std::vector<ESM::ENAMstruct>>(record.get().mEffects.mList); return new NestedTableWrapper<std::vector<ESM::IndexedENAMstruct>>(record.get().mEffects.mList);
} }
QVariant getData(const Record<ESXRecordT>& record, int subRowIndex, int subColIndex) const override QVariant getData(const Record<ESXRecordT>& record, int subRowIndex, int subColIndex) const override
{ {
ESXRecordT magic = record.get(); ESXRecordT magic = record.get();
std::vector<ESM::ENAMstruct>& effectsList = magic.mEffects.mList; std::vector<ESM::IndexedENAMstruct>& effectsList = magic.mEffects.mList;
if (subRowIndex < 0 || subRowIndex >= static_cast<int>(effectsList.size())) if (subRowIndex < 0 || subRowIndex >= static_cast<int>(effectsList.size()))
throw std::runtime_error("index out of range"); throw std::runtime_error("index out of range");
ESM::ENAMstruct effect = effectsList[subRowIndex]; ESM::ENAMstruct effect = effectsList[subRowIndex].mData;
switch (subColIndex) switch (subColIndex)
{ {
case 0: case 0:
@ -374,12 +377,12 @@ namespace CSMWorld
{ {
ESXRecordT magic = record.get(); ESXRecordT magic = record.get();
std::vector<ESM::ENAMstruct>& effectsList = magic.mEffects.mList; std::vector<ESM::IndexedENAMstruct>& effectsList = magic.mEffects.mList;
if (subRowIndex < 0 || subRowIndex >= static_cast<int>(effectsList.size())) if (subRowIndex < 0 || subRowIndex >= static_cast<int>(effectsList.size()))
throw std::runtime_error("index out of range"); throw std::runtime_error("index out of range");
ESM::ENAMstruct effect = effectsList[subRowIndex]; ESM::ENAMstruct effect = effectsList[subRowIndex].mData;
switch (subColIndex) switch (subColIndex)
{ {
case 0: case 0:
@ -438,7 +441,7 @@ namespace CSMWorld
throw std::runtime_error("Magic Effects subcolumn index out of range"); throw std::runtime_error("Magic Effects subcolumn index out of range");
} }
magic.mEffects.mList[subRowIndex] = effect; magic.mEffects.mList[subRowIndex].mData = effect;
record.setModified(magic); record.setModified(magic);
} }

View file

@ -19,6 +19,11 @@ namespace CSMWorld
State mState; State mState;
explicit RecordBase(State state)
: mState(state)
{
}
virtual ~RecordBase() = default; virtual ~RecordBase() = default;
virtual std::unique_ptr<RecordBase> clone() const = 0; virtual std::unique_ptr<RecordBase> clone() const = 0;
@ -69,21 +74,18 @@ namespace CSMWorld
template <typename ESXRecordT> template <typename ESXRecordT>
Record<ESXRecordT>::Record() Record<ESXRecordT>::Record()
: mBase() : RecordBase(State_BaseOnly)
, mBase()
, mModified() , mModified()
{ {
} }
template <typename ESXRecordT> template <typename ESXRecordT>
Record<ESXRecordT>::Record(State state, const ESXRecordT* base, const ESXRecordT* modified) Record<ESXRecordT>::Record(State state, const ESXRecordT* base, const ESXRecordT* modified)
: RecordBase(state)
, mBase(base == nullptr ? ESXRecordT{} : *base)
, mModified(modified == nullptr ? ESXRecordT{} : *modified)
{ {
if (base)
mBase = *base;
if (modified)
mModified = *modified;
this->mState = state;
} }
template <typename ESXRecordT> template <typename ESXRecordT>

View file

@ -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);

View file

@ -97,7 +97,7 @@ CSMWorld::RefIdCollection::RefIdCollection()
inventoryColumns.mIcon = &mColumns.back(); inventoryColumns.mIcon = &mColumns.back();
mColumns.emplace_back(Columns::ColumnId_Weight, ColumnBase::Display_Float); mColumns.emplace_back(Columns::ColumnId_Weight, ColumnBase::Display_Float);
inventoryColumns.mWeight = &mColumns.back(); inventoryColumns.mWeight = &mColumns.back();
mColumns.emplace_back(Columns::ColumnId_StackCount, ColumnBase::Display_Integer); mColumns.emplace_back(Columns::ColumnId_GoldValue, ColumnBase::Display_Integer);
inventoryColumns.mValue = &mColumns.back(); inventoryColumns.mValue = &mColumns.back();
IngredientColumns ingredientColumns(inventoryColumns); IngredientColumns ingredientColumns(inventoryColumns);

View file

@ -1,7 +1,9 @@
#include "regionmap.hpp" #include "regionmap.hpp"
#include <QApplication>
#include <QBrush> #include <QBrush>
#include <QModelIndex> #include <QModelIndex>
#include <QPalette>
#include <QSize> #include <QSize>
#include <QVariant> #include <QVariant>
@ -21,20 +23,33 @@
#include "data.hpp" #include "data.hpp"
#include "universalid.hpp" #include "universalid.hpp"
CSMWorld::RegionMap::CellDescription::CellDescription() namespace CSMWorld
: mDeleted(false)
{ {
float getLandHeight(const CSMWorld::Cell& cell, CSMWorld::Data& data)
{
const IdCollection<Land>& lands = data.getLand();
int landIndex = lands.searchId(cell.mId);
if (landIndex == -1)
return 0.0f;
// If any part of land is above water, returns > 0 - otherwise returns < 0
const Land& land = lands.getRecord(landIndex).get();
if (land.getLandData())
return land.getLandData()->mMaxHeight - cell.mWater;
return 0.0f;
}
} }
CSMWorld::RegionMap::CellDescription::CellDescription(const Record<Cell>& cell) CSMWorld::RegionMap::CellDescription::CellDescription(const Record<Cell>& cell, float landHeight)
{ {
const Cell& cell2 = cell.get(); const Cell& cell2 = cell.get();
if (!cell2.isExterior()) if (!cell2.isExterior())
throw std::logic_error("Interior cell in region map"); throw std::logic_error("Interior cell in region map");
mMaxLandHeight = landHeight;
mDeleted = cell.isDeleted(); mDeleted = cell.isDeleted();
mRegion = cell2.mRegion; mRegion = cell2.mRegion;
mName = cell2.mName; mName = cell2.mName;
} }
@ -92,7 +107,7 @@ void CSMWorld::RegionMap::buildMap()
if (cell2.isExterior()) if (cell2.isExterior())
{ {
CellDescription description(cell); CellDescription description(cell, getLandHeight(cell2, mData));
CellCoordinates index = getIndex(cell2); CellCoordinates index = getIndex(cell2);
@ -140,7 +155,7 @@ void CSMWorld::RegionMap::addCells(int start, int end)
{ {
CellCoordinates index = getIndex(cell2); CellCoordinates index = getIndex(cell2);
CellDescription description(cell); CellDescription description(cell, getLandHeight(cell.get(), mData));
addCell(index, description); addCell(index, description);
} }
@ -335,10 +350,11 @@ QVariant CSMWorld::RegionMap::data(const QModelIndex& index, int role) const
auto iter = mColours.find(cell->second.mRegion); auto iter = mColours.find(cell->second.mRegion);
if (iter != mColours.end()) if (iter != mColours.end())
return QBrush(QColor(iter->second & 0xff, (iter->second >> 8) & 0xff, (iter->second >> 16) & 0xff)); return QBrush(QColor(iter->second & 0xff, (iter->second >> 8) & 0xff, (iter->second >> 16) & 0xff),
cell->second.mMaxLandHeight > 0 ? Qt::SolidPattern : Qt::CrossPattern);
if (cell->second.mRegion.empty()) if (cell->second.mRegion.empty()) // no region
return QBrush(Qt::Dense6Pattern); // no region return QBrush(cell->second.mMaxLandHeight > 0 ? Qt::Dense3Pattern : Qt::Dense6Pattern);
return QBrush(Qt::red, Qt::Dense6Pattern); // invalid region return QBrush(Qt::red, Qt::Dense6Pattern); // invalid region
} }

View file

@ -40,13 +40,12 @@ namespace CSMWorld
private: private:
struct CellDescription struct CellDescription
{ {
float mMaxLandHeight;
bool mDeleted; bool mDeleted;
ESM::RefId mRegion; ESM::RefId mRegion;
std::string mName; std::string mName;
CellDescription(); CellDescription(const Record<Cell>& cell, float landHeight);
CellDescription(const Record<Cell>& cell);
}; };
Data& mData; Data& mData;

View file

@ -58,7 +58,8 @@ namespace CSVRender
InstanceSelectionMode::~InstanceSelectionMode() InstanceSelectionMode::~InstanceSelectionMode()
{ {
mParentNode->removeChild(mBaseNode); if (mBaseNode)
mParentNode->removeChild(mBaseNode);
} }
void InstanceSelectionMode::setDragStart(const osg::Vec3d& dragStart) void InstanceSelectionMode::setDragStart(const osg::Vec3d& dragStart)

View file

@ -8,7 +8,7 @@
#include <osg/Vec4f> #include <osg/Vec4f>
#include <osg/ref_ptr> #include <osg/ref_ptr>
#include <components/esm/defs.hpp> #include <components/esm/position.hpp>
#include <components/esm/refid.hpp> #include <components/esm/refid.hpp>
#include "tagbase.hpp" #include "tagbase.hpp"

View file

@ -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);

View file

@ -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;
} }
} }

View file

@ -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

View file

@ -224,6 +224,10 @@ CSVWorld::RegionMap::RegionMap(const CSMWorld::UniversalId& universalId, CSMDoc:
addAction(mViewInTableAction); addAction(mViewInTableAction);
setAcceptDrops(true); setAcceptDrops(true);
// Make columns square incase QSizeHint doesnt apply
for (int column = 0; column < this->model()->columnCount(); ++column)
this->setColumnWidth(column, this->rowHeight(0));
} }
void CSVWorld::RegionMap::selectAll() void CSVWorld::RegionMap::selectAll()
@ -358,12 +362,23 @@ std::vector<CSMWorld::UniversalId> CSVWorld::RegionMap::getDraggedRecords() cons
return ids; return ids;
} }
void CSVWorld::RegionMap::dragMoveEvent(QDragMoveEvent* event)
{
const CSMWorld::TableMimeData* mime = dynamic_cast<const CSMWorld::TableMimeData*>(event->mimeData());
if (mime != nullptr && (mime->holdsType(CSMWorld::UniversalId::Type_Region)))
{
event->accept();
return;
}
event->ignore();
}
void CSVWorld::RegionMap::dropEvent(QDropEvent* event) void CSVWorld::RegionMap::dropEvent(QDropEvent* event)
{ {
QModelIndex index = indexAt(event->pos()); QModelIndex index = indexAt(event->pos());
bool exists = QTableView::model()->data(index, Qt::BackgroundRole) != QBrush(Qt::DiagCrossPattern); bool exists = QTableView::model()->data(index, Qt::BackgroundRole) != QBrush(Qt::DiagCrossPattern);
if (!index.isValid() || !exists) if (!index.isValid() || !exists)
{ {
return; return;

View file

@ -59,6 +59,8 @@ namespace CSVWorld
void mouseMoveEvent(QMouseEvent* event) override; void mouseMoveEvent(QMouseEvent* event) override;
void dragMoveEvent(QDragMoveEvent* event) override;
void dropEvent(QDropEvent* event) override; void dropEvent(QDropEvent* event) override;
public: public:

View file

@ -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>
) )

View file

@ -63,8 +63,8 @@ add_openmw_dir (mwlua
luamanagerimp object objectlists userdataserializer luaevents engineevents objectvariant luamanagerimp object objectlists userdataserializer luaevents engineevents objectvariant
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 recordstore debugbindings corebindings worldbindings worker magicbindings factionbindings
classbindings itemdata inputprocessor animationbindings birthsignbindings classbindings itemdata inputprocessor animationbindings birthsignbindings racebindings markupbindings
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
@ -103,7 +103,7 @@ add_openmw_dir (mwmechanics
drawstate spells activespells npcstats aipackage aisequence aipursue alchemy aiwander aitravel aifollow aiavoiddoor aibreathe drawstate spells activespells npcstats aipackage aisequence aipursue alchemy aiwander aitravel aifollow aiavoiddoor aibreathe
aicast aiescort aiface aiactivate aicombat recharge repair enchanting pathfinding pathgrid security spellcasting spellresistance aicast aiescort aiface aiactivate aicombat recharge repair enchanting pathfinding pathgrid security spellcasting spellresistance
disease pickpocket levelledlist combat steering obstacle autocalcspell difficultyscaling aicombataction summoning disease pickpocket levelledlist combat steering obstacle autocalcspell difficultyscaling aicombataction summoning
character actors objects aistate trading weaponpriority spellpriority weapontype spellutil character actors objects aistate weaponpriority spellpriority weapontype spellutil
spelleffects spelleffects
) )
@ -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>

View file

@ -31,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>
@ -600,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());
@ -780,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;
@ -963,17 +965,17 @@ void OMW::Engine::go()
} }
// Setup profiler // Setup profiler
osg::ref_ptr<Resource::Profiler> statshandler = new Resource::Profiler(stats.is_open(), mVFS.get()); osg::ref_ptr<Resource::Profiler> statsHandler = new Resource::Profiler(stats.is_open(), *mVFS);
initStatsHandler(*statshandler); initStatsHandler(*statsHandler);
mViewer->addEventHandler(statshandler); mViewer->addEventHandler(statsHandler);
osg::ref_ptr<Resource::StatsHandler> resourceshandler = new Resource::StatsHandler(stats.is_open(), mVFS.get()); osg::ref_ptr<Resource::StatsHandler> resourcesHandler = new Resource::StatsHandler(stats.is_open(), *mVFS);
mViewer->addEventHandler(resourceshandler); mViewer->addEventHandler(resourcesHandler);
if (stats.is_open()) if (stats.is_open())
Resource::CollectStatistics(mViewer); Resource::collectStatistics(*mViewer);
// Start the game // Start the game
if (!mSaveGameFile.empty()) if (!mSaveGameFile.empty())

View file

@ -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();
} }

View file

@ -265,7 +265,7 @@ namespace MWBase
virtual bool isReadyToBlock(const MWWorld::Ptr& ptr) const = 0; virtual bool isReadyToBlock(const MWWorld::Ptr& ptr) const = 0;
virtual bool isAttackingOrSpell(const MWWorld::Ptr& ptr) const = 0; virtual bool isAttackingOrSpell(const MWWorld::Ptr& ptr) const = 0;
virtual void castSpell(const MWWorld::Ptr& ptr, const ESM::RefId& spellId, bool manualSpell) = 0; virtual void castSpell(const MWWorld::Ptr& ptr, const ESM::RefId& spellId, bool scriptedSpell) = 0;
virtual void processChangedSettings(const std::set<std::pair<std::string, std::string>>& settings) = 0; virtual void processChangedSettings(const std::set<std::pair<std::string, std::string>>& settings) = 0;

View file

@ -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

View file

@ -136,6 +136,7 @@ namespace MWBase
virtual bool isConsoleMode() const = 0; virtual bool isConsoleMode() const = 0;
virtual bool isPostProcessorHudVisible() const = 0; virtual bool isPostProcessorHudVisible() const = 0;
virtual bool isSettingsWindowVisible() const = 0;
virtual bool isInteractiveMessageBoxActive() const = 0; virtual bool isInteractiveMessageBoxActive() const = 0;
virtual void toggleVisible(MWGui::GuiWindow wnd) = 0; virtual void toggleVisible(MWGui::GuiWindow wnd) = 0;
@ -157,7 +158,6 @@ namespace MWBase
virtual MWGui::ConfirmationDialog* getConfirmationDialog() = 0; virtual MWGui::ConfirmationDialog* getConfirmationDialog() = 0;
virtual MWGui::TradeWindow* getTradeWindow() = 0; virtual MWGui::TradeWindow* getTradeWindow() = 0;
virtual MWGui::PostProcessorHud* getPostProcessorHud() = 0; virtual MWGui::PostProcessorHud* getPostProcessorHud() = 0;
virtual MWGui::SettingsWindow* getSettingsWindow() = 0;
/// Make the player use an item, while updating GUI state accordingly /// Make the player use an item, while updating GUI state accordingly
virtual void useItem(const MWWorld::Ptr& item, bool force = false) = 0; virtual void useItem(const MWWorld::Ptr& item, bool force = false) = 0;
@ -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;
@ -293,7 +290,7 @@ namespace MWBase
virtual void setEnemy(const MWWorld::Ptr& enemy) = 0; virtual void setEnemy(const MWWorld::Ptr& enemy) = 0;
virtual int getMessagesCount() const = 0; virtual std::size_t getMessagesCount() const = 0;
virtual const Translation::Storage& getTranslationDataStorage() const = 0; virtual const Translation::Storage& getTranslationDataStorage() const = 0;
@ -345,6 +342,7 @@ namespace MWBase
virtual void toggleConsole() = 0; virtual void toggleConsole() = 0;
virtual void toggleDebugWindow() = 0; virtual void toggleDebugWindow() = 0;
virtual void togglePostProcessorHud() = 0; virtual void togglePostProcessorHud() = 0;
virtual void toggleSettingsWindow() = 0;
/// Cycle to next or previous spell /// Cycle to next or previous spell
virtual void cycleSpell(bool next) = 0; virtual void cycleSpell(bool next) = 0;

View file

@ -183,8 +183,6 @@ namespace MWBase
/// generate a name. /// generate a name.
virtual std::string_view getCellName(const MWWorld::Cell& cell) const = 0; virtual std::string_view getCellName(const MWWorld::Cell& cell) const = 0;
virtual std::string_view getCellName(const ESM::Cell* cell) const = 0;
virtual void removeRefScript(const MWWorld::CellRef* ref) = 0; virtual void removeRefScript(const MWWorld::CellRef* ref) = 0;
//< Remove the script attached to ref from mLocalScripts //< Remove the script attached to ref from mLocalScripts
@ -463,7 +461,7 @@ namespace MWBase
*/ */
virtual MWWorld::SpellCastState startSpellCast(const MWWorld::Ptr& actor) = 0; virtual MWWorld::SpellCastState startSpellCast(const MWWorld::Ptr& actor) = 0;
virtual void castSpell(const MWWorld::Ptr& actor, bool manualSpell = false) = 0; virtual void castSpell(const MWWorld::Ptr& actor, bool scriptedSpell = false) = 0;
virtual void launchMagicBolt(const ESM::RefId& spellId, const MWWorld::Ptr& caster, virtual void launchMagicBolt(const ESM::RefId& spellId, const MWWorld::Ptr& caster,
const osg::Vec3f& fallbackDirection, ESM::RefNum item) const osg::Vec3f& fallbackDirection, ESM::RefNum item)

View file

@ -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;
} }

View file

@ -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);

View file

@ -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;

View file

@ -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;

View file

@ -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;

View file

@ -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);

View file

@ -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);
@ -591,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;
} }

View file

@ -136,7 +136,7 @@ namespace MWClass
const ESM::MagicEffect* effect = store.get<ESM::MagicEffect>().find(ESM::MagicEffect::Telekinesis); const ESM::MagicEffect* effect = store.get<ESM::MagicEffect>().find(ESM::MagicEffect::Telekinesis);
animation->addSpellCastGlow( animation->addSpellCastGlow(
effect, 1); // 1 second glow to match the time taken for a door opening or closing effect->getColor(), 1); // 1 second glow to match the time taken for a door opening or closing
} }
} }
@ -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);

View file

@ -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();

View file

@ -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);

View file

@ -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);

View file

@ -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);

View file

@ -635,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);
@ -1118,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;
} }

View file

@ -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);

View file

@ -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);

View file

@ -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);

View file

@ -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);

View file

@ -653,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);
} }

View file

@ -87,7 +87,7 @@ namespace MWDialogue
// some keywords might be longer variations of other keywords, so we definitely need a list of // some keywords might be longer variations of other keywords, so we definitely need a list of
// candidates the first element in the pair is length of the match, i.e. depth from the first character // candidates the first element in the pair is length of the match, i.e. depth from the first character
// on // on
std::vector<typename std::pair<int, typename Entry::childen_t::const_iterator>> candidates; std::vector<typename std::pair<std::ptrdiff_t, typename Entry::childen_t::const_iterator>> candidates;
while ((j + 1) != end) while ((j + 1) != end)
{ {
@ -148,11 +148,11 @@ namespace MWDialogue
// resolve overlapping keywords // resolve overlapping keywords
while (!matches.empty()) while (!matches.empty())
{ {
int longestKeywordSize = 0; std::size_t longestKeywordSize = 0;
typename std::vector<Match>::iterator longestKeyword = matches.begin(); typename std::vector<Match>::iterator longestKeyword = matches.begin();
for (typename std::vector<Match>::iterator it = matches.begin(); it != matches.end(); ++it) for (typename std::vector<Match>::iterator it = matches.begin(); it != matches.end(); ++it)
{ {
int size = it->mEnd - it->mBeg; std::size_t size = it->mEnd - it->mBeg;
if (size > longestKeywordSize) if (size > longestKeywordSize)
{ {
longestKeywordSize = size; longestKeywordSize = size;
@ -199,7 +199,7 @@ namespace MWDialogue
void seed_impl(std::string_view keyword, value_t value, size_t depth, Entry& entry) void seed_impl(std::string_view keyword, value_t value, size_t depth, Entry& entry)
{ {
int ch = Misc::StringUtils::toLower(keyword.at(depth)); auto ch = Misc::StringUtils::toLower(keyword.at(depth));
typename Entry::childen_t::iterator j = entry.mChildren.find(ch); typename Entry::childen_t::iterator j = entry.mChildren.find(ch);

View file

@ -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)

View file

@ -771,11 +771,6 @@ namespace MWGui
return output.append(matches.front()); return output.append(matches.front());
} }
void Console::onResChange(int width, int height)
{
setCoord(10, 10, width - 10, height / 2);
}
void Console::updateSelectedObjectPtr(const MWWorld::Ptr& currentPtr, const MWWorld::Ptr& newPtr) void Console::updateSelectedObjectPtr(const MWWorld::Ptr& currentPtr, const MWWorld::Ptr& newPtr)
{ {
if (mPtr == currentPtr) if (mPtr == currentPtr)

View file

@ -47,8 +47,6 @@ namespace MWGui
void onOpen() override; void onOpen() override;
void onResChange(int width, int height) override;
// Print a message to the console, in specified color. // Print a message to the console, in specified color.
void print(const std::string& msg, std::string_view color = MWBase::WindowManager::sConsoleColor_Default); void print(const std::string& msg, std::string_view color = MWBase::WindowManager::sConsoleColor_Default);

View file

@ -273,7 +273,7 @@ namespace MWGui
void EnchantingDialog::notifyEffectsChanged() void EnchantingDialog::notifyEffectsChanged()
{ {
mEffectList.mList = mEffects; mEffectList.populate(mEffects);
mEnchanting.setEffect(mEffectList); mEnchanting.setEffect(mEffectList);
updateLabels(); updateLabels();
} }

View file

@ -427,7 +427,7 @@ namespace MWGui
{ {
// use the icon of the first effect // use the icon of the first effect
const ESM::MagicEffect* effect = MWBase::Environment::get().getESMStore()->get<ESM::MagicEffect>().find( const ESM::MagicEffect* effect = MWBase::Environment::get().getESMStore()->get<ESM::MagicEffect>().find(
spell->mEffects.mList.front().mEffectID); spell->mEffects.mList.front().mData.mEffectID);
std::string icon = effect->mIcon; std::string icon = effect->mIcon;
std::replace(icon.begin(), icon.end(), '/', '\\'); std::replace(icon.begin(), icon.end(), '/', '\\');
size_t slashPos = icon.rfind('\\'); size_t slashPos = icon.rfind('\\');

View file

@ -417,6 +417,8 @@ namespace MWGui
void InventoryWindow::onWindowResize(MyGUI::Window* _sender) void InventoryWindow::onWindowResize(MyGUI::Window* _sender)
{ {
WindowBase::clampWindowCoordinates(_sender);
adjustPanes(); adjustPanes();
const WindowSettingValues settings = getModeSettings(mGuiMode); const WindowSettingValues settings = getModeSettings(mGuiMode);

View file

@ -246,12 +246,12 @@ namespace MWGui
bool forward = (direction == D_Next || direction == D_Right || direction == D_Down); bool forward = (direction == D_Next || direction == D_Right || direction == D_Down);
int index = found - keyFocusList.begin(); std::ptrdiff_t index{ found - keyFocusList.begin() };
index = forward ? (index + 1) : (index - 1); index = forward ? (index + 1) : (index - 1);
if (wrap) if (wrap)
index = (index + keyFocusList.size()) % keyFocusList.size(); index = (index + keyFocusList.size()) % keyFocusList.size();
else else
index = std::clamp<int>(index, 0, keyFocusList.size() - 1); index = std::clamp<std::ptrdiff_t>(index, 0, keyFocusList.size() - 1);
MyGUI::Widget* next = keyFocusList[index]; MyGUI::Widget* next = keyFocusList[index];
int vertdiff = next->getTop() - focus->getTop(); int vertdiff = next->getTop() - focus->getTop();

View file

@ -99,7 +99,7 @@ namespace MWGui
} }
else if (name == "options") else if (name == "options")
{ {
winMgr->getSettingsWindow()->setVisible(true); winMgr->toggleSettingsWindow();
} }
else if (name == "credits") else if (name == "credits")
winMgr->playVideo("mw_credits.bik", true); winMgr->playVideo("mw_credits.bik", true);
@ -212,6 +212,12 @@ namespace MWGui
bool MainMenu::exit() bool MainMenu::exit()
{ {
if (MWBase::Environment::get().getWindowManager()->isSettingsWindowVisible())
{
MWBase::Environment::get().getWindowManager()->toggleSettingsWindow();
return false;
}
return MWBase::Environment::get().getStateManager()->getState() == MWBase::StateManager::State_Running; return MWBase::Environment::get().getStateManager()->getState() == MWBase::StateManager::State_Running;
} }

View file

@ -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);

View file

@ -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;

View file

@ -28,7 +28,7 @@ namespace MWGui
MessageBoxManager::clear(); MessageBoxManager::clear();
} }
int MessageBoxManager::getMessagesCount() std::size_t MessageBoxManager::getMessagesCount()
{ {
return mMessageBoxes.size(); return mMessageBoxes.size();
} }

View file

@ -29,7 +29,7 @@ namespace MWGui
bool immediate = false, int defaultFocus = -1); bool immediate = false, int defaultFocus = -1);
bool isInteractiveMessageBox(); bool isInteractiveMessageBox();
int getMessagesCount(); std::size_t getMessagesCount();
const InteractiveMessageBox* getInteractiveMessageBox() const { return mInterMessageBoxe.get(); } const InteractiveMessageBox* getInteractiveMessageBox() const { return mInterMessageBoxe.get(); }

Some files were not shown because too many files have changed in this diff Show more