mirror of
https://gitlab.com/OpenMW/openmw.git
synced 2025-02-28 12:40:06 +00:00
Merge branch 'master' of gitlab.com:openmw/openmw into lua_controller_cursor
This commit is contained in:
commit
6491bb4910
@ -521,13 +521,13 @@ Ubuntu_GCC_integration_tests_asan:
|
||||
- build/OpenMW-*.dmg
|
||||
- "build/**/*.log"
|
||||
|
||||
macOS13_Xcode14_arm64:
|
||||
macOS14_Xcode15_arm64:
|
||||
extends: .MacOS
|
||||
image: macos-12-xcode-14
|
||||
image: macos-14-xcode-15
|
||||
tags:
|
||||
- saas-macos-medium-m1
|
||||
cache:
|
||||
key: macOS12_Xcode14_arm64.v4
|
||||
key: macOS14_Xcode15_arm64.v1
|
||||
variables:
|
||||
CCACHE_SIZE: 3G
|
||||
|
||||
@ -576,7 +576,7 @@ macOS13_Xcode14_arm64:
|
||||
- cd MSVC2019_64_Ninja
|
||||
- .\ActivateMSVC.ps1
|
||||
- cmake --build . --config $config
|
||||
- ccache --show-stats
|
||||
- ccache --show-stats -v
|
||||
- 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
|
||||
- $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 install git --force --params "/GitAndUnixToolsOnPath" -y
|
||||
- choco install 7zip -y
|
||||
- choco install ccache -y
|
||||
- choco install vswhere -y
|
||||
- choco install python -y
|
||||
- choco install awscli -y
|
||||
@ -689,15 +688,11 @@ macOS13_Xcode14_arm64:
|
||||
- $time = (Get-Date -Format "HH:mm:ss")
|
||||
- echo ${time}
|
||||
- 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
|
||||
- sh CI/before_script.msvc.sh -c $config -p Win64 -v 2019 -k -V -b -t -C $multiview -E
|
||||
- cd MSVC2019_64
|
||||
- Get-Volume
|
||||
- cmake --build . --config $config
|
||||
- ccache --show-stats
|
||||
- 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
|
||||
- $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:
|
||||
key: msbuild-v8
|
||||
paths:
|
||||
- ccache
|
||||
- deps
|
||||
- MSVC2019_64/deps/Qt
|
||||
artifacts:
|
||||
|
@ -15,6 +15,7 @@ Programmers
|
||||
Nicolay Korslund - Project leader 2008-2010
|
||||
scrawl - Top contributor
|
||||
|
||||
AbduSharif
|
||||
Adam Hogan (aurix)
|
||||
Aesylwinn
|
||||
aegis
|
||||
|
37
CHANGELOG.md
37
CHANGELOG.md
@ -33,6 +33,8 @@
|
||||
Bug #5977: Fatigueless NPCs' corpse underwater changes animation on game load
|
||||
Bug #6025: Subrecords cannot overlap records
|
||||
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 #6222: global map cell size can crash openmw if set to too high a value
|
||||
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 #6974: Only harmful effects are reflected
|
||||
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 #6987: Set/Mod Blindness should not darken the screen
|
||||
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 #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 #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 #7122: Teleportation to underwater should cancel active water walking effect
|
||||
Bug #7131: MyGUI log spam when post processing HUD is open
|
||||
Bug #7134: Saves with an invalid last generated RefNum can be loaded
|
||||
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 #7202: Post-processing normals for terrain, water randomly stop rendering
|
||||
Bug #7204: Missing actor scripts freeze the game
|
||||
Bug #7229: Error marker loading failure is not handled
|
||||
Bug #7243: Supporting loading external files from VFS from esm files
|
||||
@ -93,22 +99,26 @@
|
||||
Bug #7415: Unbreakable lock discrepancies
|
||||
Bug #7416: Modpccrimelevel is different from vanilla
|
||||
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 #7459: Icons get stacked on the cursor when picking up multiple items simultaneously
|
||||
Bug #7472: Crash when enchanting last projectiles
|
||||
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 #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 #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 #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 #7604: Goblins Grunt becomes idle once injured
|
||||
Bug #7609: ForceGreeting should not open dialogue for werewolves
|
||||
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 #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 #7631: Cannot trade with/talk to Creeper or Mudcrab Merchant when they're fleeing
|
||||
Bug #7633: Groundcover should ignore non-geometry Drawables
|
||||
@ -129,6 +139,7 @@
|
||||
Bug #7679: Scene luminance value flashes when toggling shaders
|
||||
Bug #7685: Corky sometimes doesn't follow Llovyn Andus
|
||||
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 #7724: Guards don't help vs werewolves
|
||||
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 #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 #7763: Bullet shape loading problems, assorted
|
||||
Bug #7765: OpenMW-CS: Touch Record option is broken
|
||||
Bug #7769: Sword of the Perithia: Broken NPCs
|
||||
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 #7794: Fleeing NPCs name tooltip doesn't appear
|
||||
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 #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 #3537: Shader-based water ripples
|
||||
Feature #5173: Support for NiFogProperty
|
||||
Feature #5492: Let rain and snow collide with statics
|
||||
Feature #5926: Refraction based on water depth
|
||||
Feature #5944: Option to use camera as sound listener
|
||||
Feature #6149: Dehardcode Lua API_REVISION
|
||||
Feature #6152: Playing music via lua scripts
|
||||
Feature #6188: Specular lighting from point light sources
|
||||
Feature #6411: Support translations in openmw-launcher
|
||||
Feature #6447: Add LOD support to Object Paging
|
||||
Feature #6491: Add support for Qt6
|
||||
Feature #6556: Lua API for sounds
|
||||
Feature #6679: Design a custom Input Action API
|
||||
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 #6922: Improve launcher appearance
|
||||
Feature #6933: Support high-resolution cursor textures
|
||||
@ -171,16 +195,19 @@
|
||||
Feature #7125: Remembering console commands between sessions
|
||||
Feature #7129: Add support for non-adaptive VSync
|
||||
Feature #7130: Ability to set MyGUI logging verbosity
|
||||
Feature #7142: MWScript Lua API
|
||||
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 #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 #7477: NegativeLight Magic Effect flag
|
||||
Feature #7499: OpenMW-CS: Generate record filters by drag & dropping cell content to the filters field
|
||||
Feature #7546: Start the game on Fredas
|
||||
Feature #7554: Controller binding for tab for menu navigation
|
||||
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 #7608: Make the missing dependencies warning when loading a savegame more helpful
|
||||
Feature #7618: Show the player character's health in the save details
|
||||
@ -193,8 +220,14 @@
|
||||
Feature #7792: Support Timescale Clouds
|
||||
Feature #7795: Support MaxNumberRipples INI setting
|
||||
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 #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 #7048: Get rid of std::bind
|
||||
Task #7113: Move from std::atoi to std::from_char
|
||||
Task #7117: Replace boost::scoped_array with std::vector
|
||||
Task #7151: Do not use std::strerror to get errno error message
|
||||
|
@ -528,8 +528,12 @@ if ! [ -z $UNITY_BUILD ]; then
|
||||
add_cmake_opts "-DOPENMW_UNITY_BUILD=True"
|
||||
fi
|
||||
|
||||
if ! [ -z $USE_CCACHE ]; then
|
||||
add_cmake_opts "-DCMAKE_C_COMPILER_LAUNCHER=ccache -DCMAKE_CXX_COMPILER_LAUNCHER=ccache"
|
||||
if [ -n "$USE_CCACHE" ]; then
|
||||
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
|
||||
|
||||
# turn on LTO by default
|
||||
|
@ -4,8 +4,8 @@ set -o pipefail
|
||||
|
||||
LUPDATE="${LUPDATE:-lupdate}"
|
||||
|
||||
${LUPDATE:?} apps/wizard -ts files/lang/wizard_*.ts
|
||||
${LUPDATE:?} apps/launcher -ts files/lang/launcher_*.ts
|
||||
${LUPDATE:?} components/contentselector components/process -ts files/lang/components_*.ts
|
||||
${LUPDATE:?} -locations none apps/wizard -ts files/lang/wizard_*.ts
|
||||
${LUPDATE:?} -locations none apps/launcher -ts files/lang/launcher_*.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)
|
||||
|
@ -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_utilpackage.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_resourcehelpers.cpp
|
||||
apps/openmw_test_suite/misc/test_stringops.cpp
|
||||
|
@ -44,6 +44,7 @@ option(BUILD_BENCHMARKS "Build benchmarks with Google Benchmark" OFF)
|
||||
option(BUILD_NAVMESHTOOL "Build navmesh tool" ON)
|
||||
option(BUILD_BULLETOBJECTTOOL "Build Bullet object tool" ON)
|
||||
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.
|
||||
|
||||
@ -80,7 +81,7 @@ message(STATUS "Configuring OpenMW...")
|
||||
set(OPENMW_VERSION_MAJOR 0)
|
||||
set(OPENMW_VERSION_MINOR 49)
|
||||
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_VERSION_COMMITHASH "")
|
||||
@ -89,7 +90,7 @@ set(OPENMW_VERSION_COMMITDATE "")
|
||||
|
||||
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)
|
||||
if(EXISTS ${PROJECT_SOURCE_DIR}/.git)
|
||||
@ -190,6 +191,22 @@ if (MSVC)
|
||||
add_compile_options(/bigobj)
|
||||
|
||||
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()
|
||||
|
||||
# Set up common paths
|
||||
@ -718,67 +735,66 @@ if (WIN32)
|
||||
)
|
||||
|
||||
foreach(d ${WARNINGS_DISABLE})
|
||||
set(WARNINGS "${WARNINGS} /wd${d}")
|
||||
list(APPEND WARNINGS "/wd${d}")
|
||||
endforeach(d)
|
||||
|
||||
if(OPENMW_MSVC_WERROR)
|
||||
set(WARNINGS "${WARNINGS} /WX")
|
||||
list(APPEND WARNINGS "/WX")
|
||||
endif()
|
||||
|
||||
set_target_properties(components PROPERTIES COMPILE_FLAGS "${WARNINGS}")
|
||||
set_target_properties(osg-ffmpeg-videoplayer PROPERTIES COMPILE_FLAGS "${WARNINGS}")
|
||||
target_compile_options(components PRIVATE ${WARNINGS})
|
||||
target_compile_options(osg-ffmpeg-videoplayer PRIVATE ${WARNINGS})
|
||||
|
||||
if (MSVC_VERSION GREATER_EQUAL 1915 AND MSVC_VERSION LESS 1920)
|
||||
target_compile_definitions(components INTERFACE _ENABLE_EXTENDED_ALIGNED_STORAGE)
|
||||
endif()
|
||||
|
||||
if (BUILD_BSATOOL)
|
||||
set_target_properties(bsatool PROPERTIES COMPILE_FLAGS "${WARNINGS}")
|
||||
target_compile_options(bsatool PRIVATE ${WARNINGS})
|
||||
endif()
|
||||
|
||||
if (BUILD_ESMTOOL)
|
||||
set_target_properties(esmtool PROPERTIES COMPILE_FLAGS "${WARNINGS}")
|
||||
target_compile_options(esmtool PRIVATE ${WARNINGS})
|
||||
endif()
|
||||
|
||||
if (BUILD_ESSIMPORTER)
|
||||
set_target_properties(openmw-essimporter PROPERTIES COMPILE_FLAGS "${WARNINGS}")
|
||||
target_compile_options(openmw-essimporter PRIVATE ${WARNINGS})
|
||||
endif()
|
||||
|
||||
if (BUILD_LAUNCHER)
|
||||
set_target_properties(openmw-launcher PROPERTIES COMPILE_FLAGS "${WARNINGS}")
|
||||
target_compile_options(openmw-launcher PRIVATE ${WARNINGS})
|
||||
endif()
|
||||
|
||||
if (BUILD_MWINIIMPORTER)
|
||||
set_target_properties(openmw-iniimporter PROPERTIES COMPILE_FLAGS "${WARNINGS}")
|
||||
target_compile_options(openmw-iniimporter PRIVATE ${WARNINGS})
|
||||
endif()
|
||||
|
||||
if (BUILD_OPENCS)
|
||||
set_target_properties(openmw-cs PROPERTIES COMPILE_FLAGS "${WARNINGS}")
|
||||
target_compile_options(openmw-cs PRIVATE ${WARNINGS})
|
||||
endif()
|
||||
|
||||
if (BUILD_OPENMW)
|
||||
set_target_properties(openmw PROPERTIES COMPILE_FLAGS "${WARNINGS}")
|
||||
target_compile_options(openmw PRIVATE ${WARNINGS})
|
||||
endif()
|
||||
|
||||
if (BUILD_WIZARD)
|
||||
set_target_properties(openmw-wizard PROPERTIES COMPILE_FLAGS "${WARNINGS}")
|
||||
target_compile_options(openmw-wizard PRIVATE ${WARNINGS})
|
||||
endif()
|
||||
|
||||
if (BUILD_UNITTESTS)
|
||||
set_target_properties(openmw_test_suite PROPERTIES COMPILE_FLAGS "${WARNINGS}")
|
||||
target_compile_options(openmw_test_suite PRIVATE ${WARNINGS})
|
||||
endif()
|
||||
|
||||
if (BUILD_BENCHMARKS)
|
||||
set_target_properties(openmw_detournavigator_navmeshtilescache_benchmark PROPERTIES COMPILE_FLAGS "${WARNINGS}")
|
||||
target_compile_options(openmw_detournavigator_navmeshtilescache_benchmark PRIVATE ${WARNINGS})
|
||||
endif()
|
||||
|
||||
if (BUILD_NAVMESHTOOL)
|
||||
set_target_properties(openmw-navmeshtool PROPERTIES COMPILE_FLAGS "${WARNINGS}")
|
||||
target_compile_options(openmw-navmeshtool PRIVATE ${WARNINGS})
|
||||
endif()
|
||||
|
||||
if (BUILD_BULLETOBJECTTOOL)
|
||||
set(WARNINGS "${WARNINGS} ${MT_BUILD}")
|
||||
set_target_properties(openmw-bulletobjecttool PROPERTIES COMPILE_FLAGS "${WARNINGS}")
|
||||
target_compile_options(openmw-bulletobjecttool PRIVATE ${WARNINGS} ${MT_BUILD})
|
||||
endif()
|
||||
endif(MSVC)
|
||||
|
||||
@ -1090,17 +1106,17 @@ if (USE_QT)
|
||||
file(GLOB COMPONENTS_TS_FILES ${CMAKE_SOURCE_DIR}/files/lang/components_*.ts)
|
||||
get_target_property(QT_LUPDATE_EXECUTABLE Qt::lupdate IMPORTED_LOCATION)
|
||||
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
|
||||
VERBATIM
|
||||
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
|
||||
VERBATIM
|
||||
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
|
||||
VERBATIM
|
||||
COMMAND_EXPAND_LISTS)
|
||||
|
@ -20,7 +20,7 @@ Font Licenses:
|
||||
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.
|
||||
|
||||
|
@ -5,7 +5,7 @@ if (UNIX AND NOT APPLE)
|
||||
target_link_libraries(openmw_detournavigator_navmeshtilescache_benchmark ${CMAKE_THREAD_LIBS_INIT})
|
||||
endif()
|
||||
|
||||
if (MSVC)
|
||||
if (MSVC AND PRECOMPILE_HEADERS_WITH_MSVC)
|
||||
target_precompile_headers(openmw_detournavigator_navmeshtilescache_benchmark PRIVATE <algorithm>)
|
||||
endif()
|
||||
|
||||
|
@ -182,7 +182,7 @@ namespace
|
||||
for (auto _ : state)
|
||||
{
|
||||
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);
|
||||
}
|
||||
}
|
||||
@ -241,7 +241,7 @@ namespace
|
||||
while (state.KeepRunning())
|
||||
{
|
||||
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>());
|
||||
benchmark::DoNotOptimize(result);
|
||||
}
|
||||
|
@ -5,7 +5,7 @@ if (UNIX AND NOT APPLE)
|
||||
target_link_libraries(openmw_esm_refid_benchmark ${CMAKE_THREAD_LIBS_INIT})
|
||||
endif()
|
||||
|
||||
if (MSVC)
|
||||
if (MSVC AND PRECOMPILE_HEADERS_WITH_MSVC)
|
||||
target_precompile_headers(openmw_esm_refid_benchmark PRIVATE <algorithm>)
|
||||
endif()
|
||||
|
||||
|
@ -8,7 +8,7 @@ if (UNIX AND NOT APPLE)
|
||||
target_link_libraries(openmw_settings_access_benchmark ${CMAKE_THREAD_LIBS_INIT})
|
||||
endif()
|
||||
|
||||
if (MSVC)
|
||||
if (MSVC AND PRECOMPILE_HEADERS_WITH_MSVC)
|
||||
target_precompile_headers(openmw_settings_access_benchmark PRIVATE <algorithm>)
|
||||
endif()
|
||||
|
||||
|
@ -38,7 +38,7 @@ namespace
|
||||
{
|
||||
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);
|
||||
}
|
||||
}
|
||||
@ -47,8 +47,8 @@ namespace
|
||||
{
|
||||
for (auto _ : state)
|
||||
{
|
||||
static const float v1 = Settings::Manager::getFloat("near clip", "Camera");
|
||||
static const bool v2 = Settings::Manager::getBool("transparent postpass", "Post Processing");
|
||||
static float v1 = Settings::Manager::getFloat("near clip", "Camera");
|
||||
static bool v2 = Settings::Manager::getBool("transparent postpass", "Post Processing");
|
||||
benchmark::DoNotOptimize(v1);
|
||||
benchmark::DoNotOptimize(v2);
|
||||
}
|
||||
@ -58,9 +58,9 @@ namespace
|
||||
{
|
||||
for (auto _ : state)
|
||||
{
|
||||
static const float v1 = Settings::Manager::getFloat("near clip", "Camera");
|
||||
static const bool v2 = Settings::Manager::getBool("transparent postpass", "Post Processing");
|
||||
static const int v3 = Settings::Manager::getInt("reflection detail", "Water");
|
||||
static float v1 = Settings::Manager::getFloat("near clip", "Camera");
|
||||
static bool v2 = Settings::Manager::getBool("transparent postpass", "Post Processing");
|
||||
static int v3 = Settings::Manager::getInt("reflection detail", "Water");
|
||||
benchmark::DoNotOptimize(v1);
|
||||
benchmark::DoNotOptimize(v2);
|
||||
benchmark::DoNotOptimize(v3);
|
||||
@ -71,7 +71,8 @@ namespace
|
||||
{
|
||||
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)
|
||||
{
|
||||
benchmark::DoNotOptimize(Settings::postProcessing().mTransparentPostpass.get());
|
||||
benchmark::DoNotOptimize(Settings::camera().mNearClip.get());
|
||||
bool v1 = Settings::postProcessing().mTransparentPostpass.get();
|
||||
float v2 = Settings::camera().mNearClip.get();
|
||||
benchmark::DoNotOptimize(v1);
|
||||
benchmark::DoNotOptimize(v2);
|
||||
}
|
||||
}
|
||||
|
||||
@ -88,9 +91,12 @@ namespace
|
||||
{
|
||||
for (auto _ : state)
|
||||
{
|
||||
benchmark::DoNotOptimize(Settings::postProcessing().mTransparentPostpass.get());
|
||||
benchmark::DoNotOptimize(Settings::camera().mNearClip.get());
|
||||
benchmark::DoNotOptimize(Settings::water().mReflectionDetail.get());
|
||||
bool v1 = Settings::postProcessing().mTransparentPostpass.get();
|
||||
float v2 = Settings::camera().mNearClip.get();
|
||||
int v3 = Settings::water().mReflectionDetail.get();
|
||||
benchmark::DoNotOptimize(v1);
|
||||
benchmark::DoNotOptimize(v2);
|
||||
benchmark::DoNotOptimize(v3);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -18,7 +18,7 @@ if (BUILD_WITH_CODE_COVERAGE)
|
||||
target_link_libraries(bsatool gcov)
|
||||
endif()
|
||||
|
||||
if (MSVC)
|
||||
if (MSVC AND PRECOMPILE_HEADERS_WITH_MSVC)
|
||||
target_precompile_headers(bsatool PRIVATE
|
||||
<filesystem>
|
||||
<fstream>
|
||||
|
@ -329,17 +329,19 @@ int main(int argc, char** argv)
|
||||
|
||||
switch (bsaVersion)
|
||||
{
|
||||
case Bsa::BSAVER_COMPRESSED:
|
||||
return call<Bsa::CompressedBSAFile>(info);
|
||||
case Bsa::BSAVER_BA2_GNRL:
|
||||
return call<Bsa::BA2GNRLFile>(info);
|
||||
case Bsa::BSAVER_BA2_DX10:
|
||||
return call<Bsa::BA2DX10File>(info);
|
||||
case Bsa::BSAVER_UNCOMPRESSED:
|
||||
case Bsa::BsaVersion::Unknown:
|
||||
break;
|
||||
case Bsa::BsaVersion::Uncompressed:
|
||||
return call<Bsa::BSAFile>(info);
|
||||
default:
|
||||
throw std::runtime_error("Unrecognised BSA archive");
|
||||
case Bsa::BsaVersion::Compressed:
|
||||
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)
|
||||
{
|
||||
|
@ -19,7 +19,7 @@ if (WIN32)
|
||||
install(TARGETS openmw-bulletobjecttool RUNTIME DESTINATION ".")
|
||||
endif()
|
||||
|
||||
if (MSVC)
|
||||
if (MSVC AND PRECOMPILE_HEADERS_WITH_MSVC)
|
||||
target_precompile_headers(openmw-bulletobjecttool PRIVATE
|
||||
<string>
|
||||
<vector>
|
||||
|
@ -25,7 +25,7 @@ if (BUILD_WITH_CODE_COVERAGE)
|
||||
target_link_libraries(esmtool gcov)
|
||||
endif()
|
||||
|
||||
if (MSVC)
|
||||
if (MSVC AND PRECOMPILE_HEADERS_WITH_MSVC)
|
||||
target_precompile_headers(esmtool PRIVATE
|
||||
<fstream>
|
||||
<string>
|
||||
|
@ -1,5 +1,6 @@
|
||||
#include "labels.hpp"
|
||||
|
||||
#include <components/esm3/loadalch.hpp>
|
||||
#include <components/esm3/loadbody.hpp>
|
||||
#include <components/esm3/loadcell.hpp>
|
||||
#include <components/esm3/loadcont.hpp>
|
||||
@ -987,3 +988,16 @@ std::string recordFlags(uint32_t flags)
|
||||
properties += Misc::StringUtils::format("(0x%08X)", flags);
|
||||
return properties;
|
||||
}
|
||||
|
||||
std::string potionFlags(int flags)
|
||||
{
|
||||
std::string properties;
|
||||
if (flags == 0)
|
||||
properties += "[None] ";
|
||||
if (flags & ESM::Potion::Autocalc)
|
||||
properties += "Autocalc ";
|
||||
if (flags & (0xFFFFFFFF ^ ESM::Enchantment::Autocalc))
|
||||
properties += "Invalid ";
|
||||
properties += Misc::StringUtils::format("(0x%08X)", flags);
|
||||
return properties;
|
||||
}
|
||||
|
@ -60,6 +60,7 @@ std::string itemListFlags(int flags);
|
||||
std::string lightFlags(int flags);
|
||||
std::string magicEffectFlags(int flags);
|
||||
std::string npcFlags(int flags);
|
||||
std::string potionFlags(int flags);
|
||||
std::string raceFlags(int flags);
|
||||
std::string spellFlags(int flags);
|
||||
std::string weaponFlags(int flags);
|
||||
|
@ -180,22 +180,23 @@ namespace
|
||||
void printEffectList(const ESM::EffectList& effects)
|
||||
{
|
||||
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::endl;
|
||||
if (effect.mSkill != -1)
|
||||
std::cout << " Skill: " << skillLabel(effect.mSkill) << " (" << (int)effect.mSkill << ")"
|
||||
std::cout << " Effect[" << i << "]: " << magicEffectLabel(effect.mData.mEffectID) << " ("
|
||||
<< effect.mData.mEffectID << ")" << std::endl;
|
||||
if (effect.mData.mSkill != -1)
|
||||
std::cout << " Skill: " << skillLabel(effect.mData.mSkill) << " (" << (int)effect.mData.mSkill << ")"
|
||||
<< std::endl;
|
||||
if (effect.mAttribute != -1)
|
||||
std::cout << " Attribute: " << attributeLabel(effect.mAttribute) << " (" << (int)effect.mAttribute
|
||||
<< ")" << std::endl;
|
||||
std::cout << " Range: " << rangeTypeLabel(effect.mRange) << " (" << effect.mRange << ")" << std::endl;
|
||||
if (effect.mData.mAttribute != -1)
|
||||
std::cout << " Attribute: " << attributeLabel(effect.mData.mAttribute) << " ("
|
||||
<< (int)effect.mData.mAttribute << ")" << std::endl;
|
||||
std::cout << " Range: " << rangeTypeLabel(effect.mData.mRange) << " (" << effect.mData.mRange << ")"
|
||||
<< std::endl;
|
||||
// Area is always zero if range type is "Self"
|
||||
if (effect.mRange != ESM::RT_Self)
|
||||
std::cout << " Area: " << effect.mArea << std::endl;
|
||||
std::cout << " Duration: " << effect.mDuration << std::endl;
|
||||
std::cout << " Magnitude: " << effect.mMagnMin << "-" << effect.mMagnMax << std::endl;
|
||||
if (effect.mData.mRange != ESM::RT_Self)
|
||||
std::cout << " Area: " << effect.mData.mArea << std::endl;
|
||||
std::cout << " Duration: " << effect.mData.mDuration << std::endl;
|
||||
std::cout << " Magnitude: " << effect.mData.mMagnMin << "-" << effect.mData.mMagnMax << std::endl;
|
||||
i++;
|
||||
}
|
||||
}
|
||||
@ -479,7 +480,7 @@ namespace EsmTool
|
||||
std::cout << " Script: " << mData.mScript << std::endl;
|
||||
std::cout << " Weight: " << mData.mData.mWeight << 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);
|
||||
std::cout << " Deleted: " << mIsDeleted << std::endl;
|
||||
}
|
||||
@ -612,7 +613,6 @@ namespace EsmTool
|
||||
}
|
||||
else
|
||||
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 << " Deleted: " << mIsDeleted << std::endl;
|
||||
}
|
||||
@ -840,8 +840,7 @@ namespace EsmTool
|
||||
|
||||
std::cout << " Quest Status: " << questStatusLabel(mData.mQuestStatus) << " (" << mData.mQuestStatus << ")"
|
||||
<< std::endl;
|
||||
std::cout << " Unknown1: " << mData.mData.mUnknown1 << std::endl;
|
||||
std::cout << " Unknown2: " << (int)mData.mData.mUnknown2 << std::endl;
|
||||
std::cout << " Type: " << dialogTypeLabel(mData.mData.mType) << std::endl;
|
||||
|
||||
for (const ESM::DialInfo::SelectStruct& rule : mData.mSelects)
|
||||
std::cout << " Select Rule: " << ruleString(rule) << std::endl;
|
||||
@ -898,9 +897,6 @@ namespace EsmTool
|
||||
if (const ESM::Land::LandData* data = mData.getLandData(mData.mDataTypes))
|
||||
{
|
||||
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();
|
||||
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 << " Auto-Generated: " << (int)point.mAutogenerated << std::endl;
|
||||
std::cout << " Connections: " << (int)point.mConnectionNum << std::endl;
|
||||
std::cout << " Unknown: " << point.mUnknown << std::endl;
|
||||
i++;
|
||||
}
|
||||
|
||||
|
@ -47,7 +47,7 @@ if (WIN32)
|
||||
INSTALL(TARGETS openmw-essimporter RUNTIME DESTINATION ".")
|
||||
endif(WIN32)
|
||||
|
||||
if (MSVC)
|
||||
if (MSVC AND PRECOMPILE_HEADERS_WITH_MSVC)
|
||||
target_precompile_headers(openmw-essimporter PRIVATE
|
||||
<algorithm>
|
||||
<filesystem>
|
||||
|
@ -232,7 +232,7 @@ namespace ESSImport
|
||||
esm.skip(4);
|
||||
}
|
||||
|
||||
esm.getExact(nam8, 32);
|
||||
esm.getT(nam8);
|
||||
|
||||
newcell.mFogOfWar.reserve(16 * 16);
|
||||
for (int x = 0; x < 16; ++x)
|
||||
|
@ -1,10 +1,30 @@
|
||||
#include "importcellref.hpp"
|
||||
|
||||
#include <components/esm3/esmreader.hpp>
|
||||
#include <components/misc/concepts.hpp>
|
||||
|
||||
#include <cstdint>
|
||||
|
||||
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)
|
||||
{
|
||||
@ -45,14 +65,9 @@ namespace ESSImport
|
||||
bool isDeleted = false;
|
||||
ESM::CellRef::loadData(esm, isDeleted);
|
||||
|
||||
mActorData.mHasACDT
|
||||
= 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.mHasACDT = esm.getOptionalComposite("ACDT", mActorData.mACDT);
|
||||
|
||||
mActorData.mHasACSC = esm.getHNOT("ACSC", mActorData.mACSC.mUnknown1, mActorData.mACSC.mFlags,
|
||||
mActorData.mACSC.mUnknown2, mActorData.mACSC.mCorpseClearCountdown, mActorData.mACSC.mUnknown3);
|
||||
mActorData.mHasACSC = esm.getOptionalComposite("ACSC", mActorData.mACSC);
|
||||
|
||||
if (esm.isNextSub("ACSL"))
|
||||
esm.skipHSubSize(112);
|
||||
@ -127,8 +142,7 @@ namespace ESSImport
|
||||
if (esm.isNextSub("ND3D"))
|
||||
esm.skipHSub();
|
||||
|
||||
mActorData.mHasANIS
|
||||
= esm.getHNOT("ANIS", mActorData.mANIS.mGroupIndex, mActorData.mANIS.mUnknown, mActorData.mANIS.mTime);
|
||||
mActorData.mHasANIS = esm.getOptionalComposite("ANIS", mActorData.mANIS);
|
||||
|
||||
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
|
||||
// alarmvoi0000.ess
|
||||
for (int i = 0; i < 2; ++i)
|
||||
esm.getHNOT("DATA", mPos.pos, mPos.rot);
|
||||
esm.getOptionalComposite("DATA", mPos);
|
||||
|
||||
mDeleted = 0;
|
||||
if (esm.isNextSub("DELE"))
|
||||
|
@ -135,7 +135,7 @@ namespace ESSImport
|
||||
sub.mFileOffset = esm.getFileOffset();
|
||||
sub.mName = esm.retSubName().toString();
|
||||
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);
|
||||
}
|
||||
file.mRecords.push_back(rec);
|
||||
|
@ -94,7 +94,7 @@ if(USE_QT)
|
||||
set_property(TARGET openmw-launcher PROPERTY AUTOMOC ON)
|
||||
endif(USE_QT)
|
||||
|
||||
if (MSVC)
|
||||
if (MSVC AND PRECOMPILE_HEADERS_WITH_MSVC)
|
||||
target_precompile_headers(openmw-launcher PRIVATE
|
||||
<boost/program_options/options_description.hpp>
|
||||
|
||||
|
@ -819,7 +819,7 @@ void Launcher::DataFilesPage::addArchivesFromDir(const QString& path)
|
||||
for (const auto& fileinfo : dir.entryInfoList(archiveFilter))
|
||||
{
|
||||
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;
|
||||
|
||||
const auto fileName = fileinfo.fileName();
|
||||
|
@ -193,8 +193,10 @@ bool Launcher::SettingsPage::loadSettings()
|
||||
loadSettingBool(Settings::game().mSmoothMovement, *smoothMovementCheckBox);
|
||||
loadSettingBool(Settings::game().mPlayerMovementIgnoresAnimation, *playerMovementIgnoresAnimationCheckBox);
|
||||
|
||||
distantLandCheckBox->setCheckState(
|
||||
Settings::terrain().mDistantTerrain && Settings::terrain().mObjectPaging ? Qt::Checked : Qt::Unchecked);
|
||||
connect(distantLandCheckBox, &QCheckBox::toggled, this, &SettingsPage::slotDistantLandToggled);
|
||||
bool distantLandEnabled = Settings::terrain().mDistantTerrain && Settings::terrain().mObjectPaging;
|
||||
distantLandCheckBox->setCheckState(distantLandEnabled ? Qt::Checked : Qt::Unchecked);
|
||||
slotDistantLandToggled(distantLandEnabled);
|
||||
|
||||
loadSettingBool(Settings::terrain().mObjectPagingActiveGrid, *activeGridObjectPagingCheckBox);
|
||||
viewingDistanceComboBox->setValue(convertToCells(Settings::camera().mViewingDistance));
|
||||
@ -244,6 +246,11 @@ bool Launcher::SettingsPage::loadSettings()
|
||||
int shadowResIndex = shadowResolutionComboBox->findText(QString::number(shadowRes));
|
||||
if (shadowResIndex != -1)
|
||||
shadowResolutionComboBox->setCurrentIndex(shadowResIndex);
|
||||
else
|
||||
{
|
||||
shadowResolutionComboBox->addItem(QString::number(shadowRes));
|
||||
shadowResolutionComboBox->setCurrentIndex(shadowResolutionComboBox->count() - 1);
|
||||
}
|
||||
|
||||
connect(shadowDistanceCheckBox, &QCheckBox::toggled, this, &SettingsPage::slotShadowDistLimitToggled);
|
||||
|
||||
@ -583,9 +590,16 @@ void Launcher::SettingsPage::slotShadowDistLimitToggled(bool checked)
|
||||
fadeStartSpinBox->setEnabled(checked);
|
||||
}
|
||||
|
||||
void Launcher::SettingsPage::slotDistantLandToggled(bool checked)
|
||||
{
|
||||
activeGridObjectPagingCheckBox->setEnabled(checked);
|
||||
objectPagingMinSizeComboBox->setEnabled(checked);
|
||||
}
|
||||
|
||||
void Launcher::SettingsPage::slotLightTypeCurrentIndexChanged(int index)
|
||||
{
|
||||
lightsMaximumDistanceSpinBox->setEnabled(index != 0);
|
||||
lightFadeMultiplierSpinBox->setEnabled(index != 0);
|
||||
lightsMaxLightsSpinBox->setEnabled(index != 0);
|
||||
lightsBoundingSphereMultiplierSpinBox->setEnabled(index != 0);
|
||||
lightsMinimumInteriorBrightnessSpinBox->setEnabled(index != 0);
|
||||
|
@ -33,6 +33,7 @@ namespace Launcher
|
||||
void slotPostProcessToggled(bool checked);
|
||||
void slotSkyBlendingToggled(bool checked);
|
||||
void slotShadowDistLimitToggled(bool checked);
|
||||
void slotDistantLandToggled(bool checked);
|
||||
void slotLightTypeCurrentIndexChanged(int index);
|
||||
|
||||
private:
|
||||
|
@ -652,45 +652,6 @@
|
||||
<item>
|
||||
<layout class="QGridLayout" name="terrainLayout" columnstretch="0,0">
|
||||
<item row="4" column="0">
|
||||
<widget class="QCheckBox" name="distantLandCheckBox">
|
||||
<property name="toolTip">
|
||||
<string><html><head/><body><p>If true, use paging and LOD algorithms to display the entire terrain. If false, only display terrain of the loaded cells.</p></body></html></string>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Distant land</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="2" column="1">
|
||||
<widget class="QDoubleSpinBox" name="viewingDistanceComboBox">
|
||||
<property name="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">
|
||||
<property name="toolTip">
|
||||
<string><html><head/><body><p>Controls how large an object must be to be visible in the scene. The object’s size is divided by its distance to the camera and the result of the division is compared with this value. The smaller this value is, the more objects you will see in the scene.</p></body></html></string>
|
||||
@ -700,14 +661,7 @@
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="2" column="0">
|
||||
<widget class="QLabel" name="viewingDistanceLabel">
|
||||
<property name="text">
|
||||
<string>Viewing distance</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="3" column="1">
|
||||
<item row="4" column="1">
|
||||
<widget class="QDoubleSpinBox" name="objectPagingMinSizeComboBox">
|
||||
<property name="decimals">
|
||||
<number>3</number>
|
||||
@ -723,7 +677,53 @@
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="4" column="1">
|
||||
<item row="2" column="0">
|
||||
<widget class="QLabel" name="viewingDistanceLabel">
|
||||
<property name="text">
|
||||
<string>Viewing distance</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="2" column="1">
|
||||
<widget class="QDoubleSpinBox" name="viewingDistanceComboBox">
|
||||
<property name="suffix">
|
||||
<string> cells</string>
|
||||
</property>
|
||||
<property name="decimals">
|
||||
<number>3</number>
|
||||
</property>
|
||||
<property name="minimum">
|
||||
<double>0.000000000000000</double>
|
||||
</property>
|
||||
<property name="singleStep">
|
||||
<double>0.125000000000000</double>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="7" column="1">
|
||||
<spacer name="verticalSpacer_15">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Vertical</enum>
|
||||
</property>
|
||||
<property name="sizeHint" stdset="0">
|
||||
<size>
|
||||
<width>20</width>
|
||||
<height>40</height>
|
||||
</size>
|
||||
</property>
|
||||
</spacer>
|
||||
</item>
|
||||
<item row="3" column="0">
|
||||
<widget class="QCheckBox" name="distantLandCheckBox">
|
||||
<property name="toolTip">
|
||||
<string><html><head/><body><p>If true, use paging and LOD algorithms to display the entire terrain. If false, only display terrain of the loaded cells.</p></body></html></string>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Distant land</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="3" column="1">
|
||||
<widget class="QCheckBox" name="activeGridObjectPagingCheckBox">
|
||||
<property name="toolTip">
|
||||
<string><html><head/><body><p>Use object paging for active cells grid.</p></body></html></string>
|
||||
@ -869,6 +869,9 @@
|
||||
<property name="maximum">
|
||||
<number>81920</number>
|
||||
</property>
|
||||
<property name="singleStep">
|
||||
<number>128</number>
|
||||
</property>
|
||||
<property name="value">
|
||||
<number>8192</number>
|
||||
</property>
|
||||
@ -972,6 +975,9 @@
|
||||
<property name="maximum">
|
||||
<double>1.000000000000000</double>
|
||||
</property>
|
||||
<property name="singleStep">
|
||||
<double>0.010000000000000</double>
|
||||
</property>
|
||||
<property name="value">
|
||||
<double>0.900000000000000</double>
|
||||
</property>
|
||||
@ -1027,7 +1033,7 @@
|
||||
<string><html><head/><body><p>Maximum distance at which lights will appear (measured in units).</p><p>Set this to 0 to use an unlimited distance.</p></body></html></string>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Lights maximum distance</string>
|
||||
<string>Maximum light distance</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
@ -1050,7 +1056,7 @@
|
||||
<string><html><head/><body><p>Maximum number of lights per object.</p><p>A low number near default will cause light popping similar to what you would see with legacy lighting.</p></body></html></string>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Max light sources</string>
|
||||
<string>Max lights</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
@ -1060,7 +1066,7 @@
|
||||
<string><html><head/><body><p>Fraction of maximum distance at which lights will start to fade.</p><p>Set this to a low value for slower transitions or a high value for quicker transitions.</p></body></html></string>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Lights fade multiplier</string>
|
||||
<string>Fade start multiplier</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
@ -1102,7 +1108,7 @@
|
||||
<string><html><head/><body><p>Multipler for bounding sphere of lights.</p><p>Higher numbers allows for smooth falloff but require an increase in number of max lights.</p><p>Does not effect the illumination or strength of lights.</p></body></html></string>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Lights bounding sphere multiplier</string>
|
||||
<string>Bounding sphere multiplier</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
@ -1112,7 +1118,7 @@
|
||||
<string><html><head/><body><p>Minimum ambient interior brightness.</p><p>Increase this if you feel interiors are too dark.</p></body></html></string>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Lights minimum interior brightness</string>
|
||||
<string>Minimum interior brightness</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
@ -1323,7 +1329,7 @@
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
<item row="0" column="0">
|
||||
<item>
|
||||
<widget class="QCheckBox" name="cameraListenerCheckBox">
|
||||
<property name="toolTip">
|
||||
<string>In third-person view, use the camera as the sound listener instead of the player character.</string>
|
||||
|
@ -33,7 +33,7 @@ if (BUILD_WITH_CODE_COVERAGE)
|
||||
target_link_libraries(openmw-iniimporter gcov)
|
||||
endif()
|
||||
|
||||
if (MSVC)
|
||||
if (MSVC AND PRECOMPILE_HEADERS_WITH_MSVC)
|
||||
target_precompile_headers(openmw-iniimporter PRIVATE
|
||||
<string>
|
||||
<vector>
|
||||
|
@ -21,7 +21,7 @@ if (WIN32)
|
||||
install(TARGETS openmw-navmeshtool RUNTIME DESTINATION ".")
|
||||
endif()
|
||||
|
||||
if (MSVC)
|
||||
if (MSVC AND PRECOMPILE_HEADERS_WITH_MSVC)
|
||||
target_precompile_headers(openmw-navmeshtool PRIVATE
|
||||
<algorithm>
|
||||
<memory>
|
||||
|
@ -17,6 +17,6 @@ if (BUILD_WITH_CODE_COVERAGE)
|
||||
target_link_libraries(niftest gcov)
|
||||
endif()
|
||||
|
||||
if (MSVC)
|
||||
if (MSVC AND PRECOMPILE_HEADERS_WITH_MSVC)
|
||||
target_precompile_headers(niftest PRIVATE <filesystem>)
|
||||
endif()
|
||||
|
@ -42,29 +42,10 @@ bool isBSA(const std::filesystem::path& filename)
|
||||
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)
|
||||
{
|
||||
if (isBSA(path))
|
||||
return makeBsaArchive(path);
|
||||
return VFS::makeBsaArchive(path);
|
||||
if (std::filesystem::is_directory(path))
|
||||
return std::make_unique<VFS::FileSystemArchive>(path);
|
||||
return nullptr;
|
||||
@ -84,10 +65,10 @@ void readNIF(
|
||||
std::cout << " from '" << Files::pathToUnicodeString(isBSA(source) ? source.filename() : source) << "'";
|
||||
std::cout << std::endl;
|
||||
}
|
||||
std::filesystem::path fullPath = !source.empty() ? source / path : path;
|
||||
const std::filesystem::path fullPath = !source.empty() ? source / path : path;
|
||||
try
|
||||
{
|
||||
Nif::NIFFile file(fullPath);
|
||||
Nif::NIFFile file(Files::pathToUnicodeString(fullPath));
|
||||
Nif::Reader reader(file, nullptr);
|
||||
if (vfs != nullptr)
|
||||
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))
|
||||
{
|
||||
Files::PathContainer dataDirs = { archivePath };
|
||||
const Files::Collections fileCollections = Files::Collections(dataDirs);
|
||||
const Files::Collections fileCollections({ archivePath });
|
||||
const Files::MultiDirCollection& bsaCol = fileCollections.getCollection(".bsa");
|
||||
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 : ba2Col)
|
||||
{
|
||||
readVFS(makeBsaArchive(file.second), file.second, quiet);
|
||||
for (auto& file : collection)
|
||||
{
|
||||
try
|
||||
{
|
||||
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;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -292,7 +292,7 @@ if (BUILD_WITH_CODE_COVERAGE)
|
||||
target_link_libraries(openmw-cs-lib gcov)
|
||||
endif()
|
||||
|
||||
if (MSVC)
|
||||
if (MSVC AND PRECOMPILE_HEADERS_WITH_MSVC)
|
||||
target_precompile_headers(openmw-cs-lib PRIVATE
|
||||
<boost/program_options/options_description.hpp>
|
||||
|
||||
|
@ -135,7 +135,7 @@ void CSMDoc::WriteDialogueCollectionStage::perform(int stage, Messages& messages
|
||||
if (topic.mState == CSMWorld::RecordBase::State_Deleted)
|
||||
{
|
||||
// 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);
|
||||
dialogue.save(writer, true);
|
||||
writer.endRecord(dialogue.sRecordId);
|
||||
@ -187,6 +187,7 @@ void CSMDoc::WriteDialogueCollectionStage::perform(int stage, Messages& messages
|
||||
{
|
||||
ESM::DialInfo info = record.get();
|
||||
info.mId = record.get().mOriginalId;
|
||||
info.mData.mType = topic.get().mType;
|
||||
|
||||
if (iter == infos.begin())
|
||||
info.mPrev = ESM::RefId();
|
||||
|
@ -452,7 +452,10 @@ std::shared_ptr<CSMFilter::Node> CSMFilter::Parser::parseText()
|
||||
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()
|
||||
|
@ -34,6 +34,8 @@ namespace CSMFilter
|
||||
///< Return a string that represents this node.
|
||||
///
|
||||
/// \param numericColumns Use numeric IDs instead of string to represent columns.
|
||||
|
||||
bool isValid() { return mRegExp.isValid(); }
|
||||
};
|
||||
}
|
||||
|
||||
|
@ -90,6 +90,7 @@ void CSMPrefs::State::declare()
|
||||
.setTooltip(
|
||||
"When editing a record, open the view in a new window,"
|
||||
" rather than docked in the main view.");
|
||||
declareInt(mValues->mIdTables.mFilterDelay, "Delay before applying a filter (in miliseconds)");
|
||||
|
||||
declareCategory("ID Dialogues");
|
||||
declareBool(mValues->mIdDialogues.mToolbar, "Show toolbar");
|
||||
|
@ -138,6 +138,7 @@ namespace CSMPrefs
|
||||
EnumSettingValue mJumpToAdded{ mIndex, sName, "jump-to-added", sJumpAndSelectValues, 0 };
|
||||
Settings::SettingValue<bool> mExtendedConfig{ mIndex, sName, "extended-config", false };
|
||||
Settings::SettingValue<bool> mSubviewNewWindow{ mIndex, sName, "subview-new-window", false };
|
||||
Settings::SettingValue<int> mFilterDelay{ mIndex, sName, "filter-delay", 500 };
|
||||
};
|
||||
|
||||
struct IdDialoguesCategory : Settings::WithIndex
|
||||
|
@ -60,38 +60,38 @@ void CSMTools::EnchantmentCheckStage::perform(int stage, CSMDoc::Messages& messa
|
||||
}
|
||||
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++)
|
||||
{
|
||||
const std::string number = std::to_string(i);
|
||||
// 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);
|
||||
++effect;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (effect->mSkill < -1 || effect->mSkill > 26)
|
||||
if (effect->mData.mSkill < -1 || effect->mData.mSkill > 26)
|
||||
messages.add(
|
||||
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(
|
||||
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);
|
||||
if (effect->mArea < 0)
|
||||
if (effect->mData.mArea < 0)
|
||||
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);
|
||||
if (effect->mMagnMin < 0)
|
||||
if (effect->mData.mMagnMin < 0)
|
||||
messages.add(
|
||||
id, "Effect #" + number + " minimum magnitude is negative", "", CSMDoc::Message::Severity_Error);
|
||||
if (effect->mMagnMax < 0)
|
||||
if (effect->mData.mMagnMax < 0)
|
||||
messages.add(
|
||||
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", "",
|
||||
CSMDoc::Message::Severity_Error);
|
||||
++effect;
|
||||
|
@ -58,7 +58,12 @@ void CSMTools::MagicEffectCheckStage::perform(int stage, CSMDoc::Messages& messa
|
||||
return;
|
||||
|
||||
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())
|
||||
{
|
||||
|
@ -971,7 +971,7 @@ namespace CSMWorld
|
||||
void set(Record<ESXRecordT>& record, const QVariant& data) override
|
||||
{
|
||||
ESXRecordT record2 = record.get();
|
||||
record2.mScale = data.toFloat();
|
||||
record2.mScale = std::clamp(data.toFloat(), 0.5f, 2.0f);
|
||||
record.setModified(record2);
|
||||
}
|
||||
|
||||
@ -1136,8 +1136,8 @@ namespace CSMWorld
|
||||
template <typename ESXRecordT>
|
||||
struct TeleportColumn : public Column<ESXRecordT>
|
||||
{
|
||||
TeleportColumn()
|
||||
: Column<ESXRecordT>(Columns::ColumnId_Teleport, ColumnBase::Display_Boolean)
|
||||
TeleportColumn(int flags)
|
||||
: Column<ESXRecordT>(Columns::ColumnId_Teleport, ColumnBase::Display_Boolean, flags)
|
||||
{
|
||||
}
|
||||
|
||||
@ -1165,6 +1165,8 @@ namespace CSMWorld
|
||||
|
||||
QVariant get(const Record<ESXRecordT>& record) const override
|
||||
{
|
||||
if (!record.get().mTeleport)
|
||||
return QVariant();
|
||||
return QString::fromUtf8(record.get().mDestCell.c_str());
|
||||
}
|
||||
|
||||
@ -1182,6 +1184,26 @@ namespace CSMWorld
|
||||
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>
|
||||
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
|
||||
{
|
||||
@ -1212,7 +1239,9 @@ namespace CSMWorld
|
||||
|
||||
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
|
||||
@ -1282,17 +1311,21 @@ namespace CSMWorld
|
||||
{
|
||||
ESM::Position ESXRecordT::*mPosition;
|
||||
int mIndex;
|
||||
bool mIsDoor;
|
||||
|
||||
PosColumn(ESM::Position ESXRecordT::*position, int index, bool door)
|
||||
: Column<ESXRecordT>((door ? Columns::ColumnId_DoorPositionXPos : Columns::ColumnId_PositionXPos) + index,
|
||||
ColumnBase::Display_Float)
|
||||
, mPosition(position)
|
||||
, mIndex(index)
|
||||
, mIsDoor(door)
|
||||
{
|
||||
}
|
||||
|
||||
QVariant get(const Record<ESXRecordT>& record) const override
|
||||
{
|
||||
if (!record.get().mTeleport && mIsDoor)
|
||||
return QVariant();
|
||||
const ESM::Position& position = record.get().*mPosition;
|
||||
return position.pos[mIndex];
|
||||
}
|
||||
@ -1316,17 +1349,21 @@ namespace CSMWorld
|
||||
{
|
||||
ESM::Position ESXRecordT::*mPosition;
|
||||
int mIndex;
|
||||
bool mIsDoor;
|
||||
|
||||
RotColumn(ESM::Position ESXRecordT::*position, int index, bool door)
|
||||
: Column<ESXRecordT>((door ? Columns::ColumnId_DoorPositionXRot : Columns::ColumnId_PositionXRot) + index,
|
||||
ColumnBase::Display_Double)
|
||||
, mPosition(position)
|
||||
, mIndex(index)
|
||||
, mIsDoor(door)
|
||||
{
|
||||
}
|
||||
|
||||
QVariant get(const Record<ESXRecordT>& record) const override
|
||||
{
|
||||
if (!record.get().mTeleport && mIsDoor)
|
||||
return QVariant();
|
||||
const ESM::Position& position = record.get().*mPosition;
|
||||
return osg::RadiansToDegrees(position.rot[mIndex]);
|
||||
}
|
||||
@ -2052,6 +2089,26 @@ namespace CSMWorld
|
||||
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>
|
||||
struct SchoolColumn : public Column<ESXRecordT>
|
||||
{
|
||||
|
@ -57,8 +57,10 @@ namespace CSMWorld
|
||||
{ ColumnId_Charges, "Charges" },
|
||||
{ ColumnId_Enchantment, "Enchantment" },
|
||||
{ ColumnId_StackCount, "Count" },
|
||||
{ ColumnId_GoldValue, "Value" },
|
||||
{ ColumnId_Teleport, "Teleport" },
|
||||
{ ColumnId_TeleportCell, "Teleport Cell" },
|
||||
{ ColumnId_IsLocked, "Locked" },
|
||||
{ ColumnId_LockLevel, "Lock Level" },
|
||||
{ ColumnId_Key, "Key" },
|
||||
{ ColumnId_Trap, "Trap" },
|
||||
@ -235,6 +237,7 @@ namespace CSMWorld
|
||||
{ ColumnId_RegionSounds, "Sounds" },
|
||||
{ ColumnId_SoundName, "Sound Name" },
|
||||
{ ColumnId_SoundChance, "Chance" },
|
||||
{ ColumnId_SoundProbability, "Probability" },
|
||||
|
||||
{ ColumnId_FactionReactions, "Reactions" },
|
||||
{ ColumnId_FactionRanks, "Ranks" },
|
||||
@ -376,6 +379,7 @@ namespace CSMWorld
|
||||
{ ColumnId_Blocked, "Blocked" },
|
||||
|
||||
{ ColumnId_LevelledCreatureId, "Levelled Creature" },
|
||||
{ ColumnId_ProjectileSpeed, "Projectile Speed" },
|
||||
|
||||
// end marker
|
||||
{ -1, 0 },
|
||||
|
@ -349,6 +349,14 @@ namespace CSMWorld
|
||||
|
||||
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
|
||||
// to extend the number of use values.
|
||||
ColumnId_UseValue1 = 0x10000,
|
||||
|
@ -161,7 +161,7 @@ CSMWorld::Data::Data(ToUTF8::FromType encoding, const Files::PathContainer& data
|
||||
defines["radialFog"] = "0";
|
||||
defines["lightingModel"] = "0";
|
||||
defines["reverseZ"] = "0";
|
||||
defines["refraction_enabled"] = "0";
|
||||
defines["waterRefraction"] = "0";
|
||||
for (const auto& define : shadowDefines)
|
||||
defines[define.first] = define.second;
|
||||
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));
|
||||
index = mRegions.getColumns() - 1;
|
||||
mRegions.addAdapter(std::make_pair(&mRegions.getColumn(index), new RegionWeatherAdapter()));
|
||||
mRegions.getNestableColumn(index)->addColumn(
|
||||
new NestedChildColumn(Columns::ColumnId_WeatherName, ColumnBase::Display_String, false));
|
||||
mRegions.getNestableColumn(index)->addColumn(new NestedChildColumn(
|
||||
Columns::ColumnId_WeatherName, ColumnBase::Display_String, ColumnBase::Flag_Dialogue, false));
|
||||
mRegions.getNestableColumn(index)->addColumn(
|
||||
new NestedChildColumn(Columns::ColumnId_WeatherChance, ColumnBase::Display_UnsignedInteger8));
|
||||
// Region Sounds
|
||||
@ -313,6 +313,8 @@ CSMWorld::Data::Data(ToUTF8::FromType encoding, const Files::PathContainer& data
|
||||
new NestedChildColumn(Columns::ColumnId_SoundName, ColumnBase::Display_Sound));
|
||||
mRegions.getNestableColumn(index)->addColumn(
|
||||
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 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 SchoolColumn<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_Particle));
|
||||
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_AreaSound));
|
||||
mMagicEffects.addColumn(new EffectSoundColumn<ESM::MagicEffect>(Columns::ColumnId_BoltSound));
|
||||
|
||||
mMagicEffects.addColumn(
|
||||
new FlagColumn<ESM::MagicEffect>(Columns::ColumnId_AllowSpellmaking, ESM::MagicEffect::AllowSpellmaking));
|
||||
mMagicEffects.addColumn(
|
||||
@ -589,7 +593,8 @@ CSMWorld::Data::Data(ToUTF8::FromType encoding, const Files::PathContainer& data
|
||||
mRefs.addColumn(new ChargesColumn<CellRef>);
|
||||
mRefs.addColumn(new EnchantmentChargesColumn<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 PosColumn<CellRef>(&CellRef::mDoorDest, 0, 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, 1, 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 KeyColumn<CellRef>);
|
||||
mRefs.addColumn(new TrapColumn<CellRef>);
|
||||
|
@ -63,9 +63,18 @@ bool CSMWorld::IdTableProxyModel::filterAcceptsRow(int sourceRow, const QModelIn
|
||||
|
||||
CSMWorld::IdTableProxyModel::IdTableProxyModel(QObject* parent)
|
||||
: QSortFilterProxyModel(parent)
|
||||
, mFilterTimer{ new QTimer(this) }
|
||||
, mSourceModel(nullptr)
|
||||
{
|
||||
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
|
||||
@ -87,10 +96,8 @@ void CSMWorld::IdTableProxyModel::setSourceModel(QAbstractItemModel* model)
|
||||
|
||||
void CSMWorld::IdTableProxyModel::setFilter(const std::shared_ptr<CSMFilter::Node>& filter)
|
||||
{
|
||||
beginResetModel();
|
||||
mFilter = filter;
|
||||
updateColumnMap();
|
||||
endResetModel();
|
||||
mAwaitingFilter = filter;
|
||||
mFilterTimer->start();
|
||||
}
|
||||
|
||||
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)
|
||||
{
|
||||
refreshFilter();
|
||||
|
@ -10,6 +10,9 @@
|
||||
#include <QModelIndex>
|
||||
#include <QSortFilterProxyModel>
|
||||
#include <QString>
|
||||
#include <QTimer>
|
||||
|
||||
#include "../prefs/state.hpp"
|
||||
|
||||
#include "columns.hpp"
|
||||
|
||||
@ -29,6 +32,8 @@ namespace CSMWorld
|
||||
Q_OBJECT
|
||||
|
||||
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)
|
||||
|
||||
// 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);
|
||||
|
||||
void timerTimeout();
|
||||
|
||||
void settingChanged(const CSMPrefs::Setting* setting);
|
||||
|
||||
signals:
|
||||
|
||||
void rowAdded(const std::string& id);
|
||||
|
@ -38,7 +38,6 @@ namespace CSMWorld
|
||||
point.mZ = 0;
|
||||
point.mAutogenerated = 0;
|
||||
point.mConnectionNum = 0;
|
||||
point.mUnknown = 0;
|
||||
|
||||
points.insert(points.begin() + position, point);
|
||||
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
|
||||
{
|
||||
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");
|
||||
|
||||
ESM::Region::SoundRef soundRef = soundList[subRowIndex];
|
||||
const ESM::Region::SoundRef& soundRef = soundList[subRowIndex];
|
||||
switch (subColIndex)
|
||||
{
|
||||
case 0:
|
||||
return QString(soundRef.mSound.getRefIdString().c_str());
|
||||
case 1:
|
||||
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:
|
||||
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
|
||||
{
|
||||
return 2;
|
||||
return 3;
|
||||
}
|
||||
|
||||
int RegionSoundListAdapter::getRowsCount(const Record<ESM::Region>& record) const
|
||||
@ -996,7 +1007,10 @@ namespace CSMWorld
|
||||
case 5:
|
||||
{
|
||||
if (isInterior && interiorWater)
|
||||
{
|
||||
cell.mWater = value.toFloat();
|
||||
cell.setHasWaterHeightSub(true);
|
||||
}
|
||||
else
|
||||
return; // return without saving
|
||||
break;
|
||||
|
@ -255,20 +255,22 @@ namespace CSMWorld
|
||||
{
|
||||
ESXRecordT magic = record.get();
|
||||
|
||||
std::vector<ESM::ENAMstruct>& effectsList = magic.mEffects.mList;
|
||||
std::vector<ESM::IndexedENAMstruct>& effectsList = magic.mEffects.mList;
|
||||
|
||||
// blank row
|
||||
ESM::ENAMstruct effect;
|
||||
effect.mEffectID = 0;
|
||||
effect.mSkill = -1;
|
||||
effect.mAttribute = -1;
|
||||
effect.mRange = 0;
|
||||
effect.mArea = 0;
|
||||
effect.mDuration = 0;
|
||||
effect.mMagnMin = 0;
|
||||
effect.mMagnMax = 0;
|
||||
ESM::IndexedENAMstruct effect;
|
||||
effect.mIndex = position;
|
||||
effect.mData.mEffectID = 0;
|
||||
effect.mData.mSkill = -1;
|
||||
effect.mData.mAttribute = -1;
|
||||
effect.mData.mRange = 0;
|
||||
effect.mData.mArea = 0;
|
||||
effect.mData.mDuration = 0;
|
||||
effect.mData.mMagnMin = 0;
|
||||
effect.mData.mMagnMax = 0;
|
||||
|
||||
effectsList.insert(effectsList.begin() + position, effect);
|
||||
magic.mEffects.updateIndexes();
|
||||
|
||||
record.setModified(magic);
|
||||
}
|
||||
@ -277,12 +279,13 @@ namespace CSMWorld
|
||||
{
|
||||
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()))
|
||||
throw std::runtime_error("index out of range");
|
||||
|
||||
effectsList.erase(effectsList.begin() + rowToRemove);
|
||||
magic.mEffects.updateIndexes();
|
||||
|
||||
record.setModified(magic);
|
||||
}
|
||||
@ -292,7 +295,7 @@ namespace CSMWorld
|
||||
ESXRecordT magic = record.get();
|
||||
|
||||
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);
|
||||
}
|
||||
@ -300,19 +303,19 @@ namespace CSMWorld
|
||||
NestedTableWrapperBase* table(const Record<ESXRecordT>& record) const override
|
||||
{
|
||||
// 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
|
||||
{
|
||||
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()))
|
||||
throw std::runtime_error("index out of range");
|
||||
|
||||
ESM::ENAMstruct effect = effectsList[subRowIndex];
|
||||
ESM::ENAMstruct effect = effectsList[subRowIndex].mData;
|
||||
switch (subColIndex)
|
||||
{
|
||||
case 0:
|
||||
@ -374,12 +377,12 @@ namespace CSMWorld
|
||||
{
|
||||
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()))
|
||||
throw std::runtime_error("index out of range");
|
||||
|
||||
ESM::ENAMstruct effect = effectsList[subRowIndex];
|
||||
ESM::ENAMstruct effect = effectsList[subRowIndex].mData;
|
||||
switch (subColIndex)
|
||||
{
|
||||
case 0:
|
||||
@ -438,7 +441,7 @@ namespace CSMWorld
|
||||
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);
|
||||
}
|
||||
|
@ -19,6 +19,11 @@ namespace CSMWorld
|
||||
|
||||
State mState;
|
||||
|
||||
explicit RecordBase(State state)
|
||||
: mState(state)
|
||||
{
|
||||
}
|
||||
|
||||
virtual ~RecordBase() = default;
|
||||
|
||||
virtual std::unique_ptr<RecordBase> clone() const = 0;
|
||||
@ -69,21 +74,18 @@ namespace CSMWorld
|
||||
|
||||
template <typename ESXRecordT>
|
||||
Record<ESXRecordT>::Record()
|
||||
: mBase()
|
||||
: RecordBase(State_BaseOnly)
|
||||
, mBase()
|
||||
, mModified()
|
||||
{
|
||||
}
|
||||
|
||||
template <typename ESXRecordT>
|
||||
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>
|
||||
|
@ -33,7 +33,7 @@ QVariant CSMWorld::PotionRefIdAdapter::getData(const RefIdColumn* column, const
|
||||
data.getRecord(RefIdData::LocalIndex(index, UniversalId::Type_Potion)));
|
||||
|
||||
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()
|
||||
if (column == mColumns.mEffects)
|
||||
@ -51,7 +51,7 @@ void CSMWorld::PotionRefIdAdapter::setData(
|
||||
ESM::Potion potion = record.get();
|
||||
|
||||
if (column == mAutoCalc)
|
||||
potion.mData.mAutoCalc = value.toInt();
|
||||
potion.mData.mFlags = value.toBool();
|
||||
else
|
||||
{
|
||||
InventoryRefIdAdapter<ESM::Potion>::setData(column, data, index, value);
|
||||
|
@ -97,7 +97,7 @@ CSMWorld::RefIdCollection::RefIdCollection()
|
||||
inventoryColumns.mIcon = &mColumns.back();
|
||||
mColumns.emplace_back(Columns::ColumnId_Weight, ColumnBase::Display_Float);
|
||||
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();
|
||||
|
||||
IngredientColumns ingredientColumns(inventoryColumns);
|
||||
|
@ -1,7 +1,9 @@
|
||||
#include "regionmap.hpp"
|
||||
|
||||
#include <QApplication>
|
||||
#include <QBrush>
|
||||
#include <QModelIndex>
|
||||
#include <QPalette>
|
||||
#include <QSize>
|
||||
#include <QVariant>
|
||||
|
||||
@ -21,20 +23,33 @@
|
||||
#include "data.hpp"
|
||||
#include "universalid.hpp"
|
||||
|
||||
CSMWorld::RegionMap::CellDescription::CellDescription()
|
||||
: mDeleted(false)
|
||||
namespace CSMWorld
|
||||
{
|
||||
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();
|
||||
|
||||
if (!cell2.isExterior())
|
||||
throw std::logic_error("Interior cell in region map");
|
||||
|
||||
mMaxLandHeight = landHeight;
|
||||
mDeleted = cell.isDeleted();
|
||||
|
||||
mRegion = cell2.mRegion;
|
||||
mName = cell2.mName;
|
||||
}
|
||||
@ -92,7 +107,7 @@ void CSMWorld::RegionMap::buildMap()
|
||||
|
||||
if (cell2.isExterior())
|
||||
{
|
||||
CellDescription description(cell);
|
||||
CellDescription description(cell, getLandHeight(cell2, mData));
|
||||
|
||||
CellCoordinates index = getIndex(cell2);
|
||||
|
||||
@ -140,7 +155,7 @@ void CSMWorld::RegionMap::addCells(int start, int end)
|
||||
{
|
||||
CellCoordinates index = getIndex(cell2);
|
||||
|
||||
CellDescription description(cell);
|
||||
CellDescription description(cell, getLandHeight(cell.get(), mData));
|
||||
|
||||
addCell(index, description);
|
||||
}
|
||||
@ -335,10 +350,11 @@ QVariant CSMWorld::RegionMap::data(const QModelIndex& index, int role) const
|
||||
auto iter = mColours.find(cell->second.mRegion);
|
||||
|
||||
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())
|
||||
return QBrush(Qt::Dense6Pattern); // no region
|
||||
if (cell->second.mRegion.empty()) // no region
|
||||
return QBrush(cell->second.mMaxLandHeight > 0 ? Qt::Dense3Pattern : Qt::Dense6Pattern);
|
||||
|
||||
return QBrush(Qt::red, Qt::Dense6Pattern); // invalid region
|
||||
}
|
||||
|
@ -40,13 +40,12 @@ namespace CSMWorld
|
||||
private:
|
||||
struct CellDescription
|
||||
{
|
||||
float mMaxLandHeight;
|
||||
bool mDeleted;
|
||||
ESM::RefId mRegion;
|
||||
std::string mName;
|
||||
|
||||
CellDescription();
|
||||
|
||||
CellDescription(const Record<Cell>& cell);
|
||||
CellDescription(const Record<Cell>& cell, float landHeight);
|
||||
};
|
||||
|
||||
Data& mData;
|
||||
|
@ -58,7 +58,8 @@ namespace CSVRender
|
||||
|
||||
InstanceSelectionMode::~InstanceSelectionMode()
|
||||
{
|
||||
mParentNode->removeChild(mBaseNode);
|
||||
if (mBaseNode)
|
||||
mParentNode->removeChild(mBaseNode);
|
||||
}
|
||||
|
||||
void InstanceSelectionMode::setDragStart(const osg::Vec3d& dragStart)
|
||||
|
@ -8,7 +8,7 @@
|
||||
#include <osg/Vec4f>
|
||||
#include <osg/ref_ptr>
|
||||
|
||||
#include <components/esm/defs.hpp>
|
||||
#include <components/esm/position.hpp>
|
||||
#include <components/esm/refid.hpp>
|
||||
|
||||
#include "tagbase.hpp"
|
||||
|
@ -48,6 +48,7 @@
|
||||
#include <components/debug/debuglog.hpp>
|
||||
#include <components/resource/resourcesystem.hpp>
|
||||
#include <components/resource/scenemanager.hpp>
|
||||
#include <components/sceneutil/glextensions.hpp>
|
||||
#include <components/sceneutil/lightmanager.hpp>
|
||||
|
||||
#include "../widget/scenetoolmode.hpp"
|
||||
@ -76,6 +77,8 @@ namespace CSVRender
|
||||
= new osgViewer::GraphicsWindowEmbedded(0, 0, width(), height());
|
||||
mWidget->setGraphicsWindowEmbedded(window);
|
||||
|
||||
mRenderer->setRealizeOperation(new SceneUtil::GetGLExtensionsOperation());
|
||||
|
||||
int frameRateLimit = CSMPrefs::get()["Rendering"]["framerate-limit"].toInt();
|
||||
mRenderer->setRunMaxFrameRate(frameRateLimit);
|
||||
mRenderer->setUseConfigureAffinity(false);
|
||||
|
@ -2,17 +2,6 @@
|
||||
|
||||
#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)
|
||||
: QValidator(parent)
|
||||
, mRelaxed(relaxed)
|
||||
@ -92,7 +81,7 @@ QValidator::State CSVWorld::IdValidator::validate(QString& input, int& pos) cons
|
||||
{
|
||||
prevScope = false;
|
||||
|
||||
if (!isValid(*iter, first))
|
||||
if (!iter->isPrint())
|
||||
return QValidator::Invalid;
|
||||
}
|
||||
}
|
||||
|
@ -13,9 +13,6 @@ namespace CSVWorld
|
||||
std::string mNamespace;
|
||||
mutable std::string mError;
|
||||
|
||||
private:
|
||||
bool isValid(const QChar& c, bool first) const;
|
||||
|
||||
public:
|
||||
IdValidator(bool relaxed = false, QObject* parent = nullptr);
|
||||
///< \param relaxed Relaxed rules for IDs that also functino as user visible text
|
||||
|
@ -224,6 +224,10 @@ CSVWorld::RegionMap::RegionMap(const CSMWorld::UniversalId& universalId, CSMDoc:
|
||||
addAction(mViewInTableAction);
|
||||
|
||||
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()
|
||||
@ -358,12 +362,23 @@ std::vector<CSMWorld::UniversalId> CSVWorld::RegionMap::getDraggedRecords() cons
|
||||
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)
|
||||
{
|
||||
QModelIndex index = indexAt(event->pos());
|
||||
|
||||
bool exists = QTableView::model()->data(index, Qt::BackgroundRole) != QBrush(Qt::DiagCrossPattern);
|
||||
|
||||
if (!index.isValid() || !exists)
|
||||
{
|
||||
return;
|
||||
|
@ -59,6 +59,8 @@ namespace CSVWorld
|
||||
|
||||
void mouseMoveEvent(QMouseEvent* event) override;
|
||||
|
||||
void dragMoveEvent(QDragMoveEvent* event) override;
|
||||
|
||||
void dropEvent(QDropEvent* event) override;
|
||||
|
||||
public:
|
||||
|
@ -26,7 +26,7 @@ if (BUILD_WITH_CODE_COVERAGE)
|
||||
target_link_libraries(openmw-cs-tests PRIVATE gcov)
|
||||
endif()
|
||||
|
||||
if (MSVC)
|
||||
if (MSVC AND PRECOMPILE_HEADERS_WITH_MSVC)
|
||||
target_precompile_headers(openmw-cs-tests PRIVATE
|
||||
<gtest/gtest.h>
|
||||
)
|
||||
|
@ -63,8 +63,8 @@ add_openmw_dir (mwlua
|
||||
luamanagerimp object objectlists userdataserializer luaevents engineevents objectvariant
|
||||
context menuscripts globalscripts localscripts playerscripts luabindings objectbindings cellbindings
|
||||
mwscriptbindings camerabindings vfsbindings uibindings soundbindings inputbindings nearbybindings
|
||||
postprocessingbindings stats debugbindings corebindings worldbindings worker magicbindings factionbindings
|
||||
classbindings itemdata inputprocessor animationbindings birthsignbindings
|
||||
postprocessingbindings stats recordstore debugbindings corebindings worldbindings worker magicbindings factionbindings
|
||||
classbindings itemdata inputprocessor animationbindings birthsignbindings racebindings markupbindings
|
||||
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/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
|
||||
aicast aiescort aiface aiactivate aicombat recharge repair enchanting pathfinding pathgrid security spellcasting spellresistance
|
||||
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
|
||||
)
|
||||
|
||||
@ -161,7 +161,7 @@ target_link_libraries(openmw
|
||||
components
|
||||
)
|
||||
|
||||
if (MSVC)
|
||||
if (MSVC AND PRECOMPILE_HEADERS_WITH_MSVC)
|
||||
target_precompile_headers(openmw PRIVATE
|
||||
<boost/program_options/options_description.hpp>
|
||||
|
||||
|
@ -31,6 +31,7 @@
|
||||
#include <components/stereo/multiview.hpp>
|
||||
#include <components/stereo/stereomanager.hpp>
|
||||
|
||||
#include <components/sceneutil/glextensions.hpp>
|
||||
#include <components/sceneutil/workqueue.hpp>
|
||||
|
||||
#include <components/files/configurationmanager.hpp>
|
||||
@ -600,6 +601,7 @@ void OMW::Engine::createWindow()
|
||||
mViewer->setRealizeOperation(realizeOperations);
|
||||
osg::ref_ptr<IdentifyOpenGLOperation> identifyOp = new IdentifyOpenGLOperation();
|
||||
realizeOperations->add(identifyOp);
|
||||
realizeOperations->add(new SceneUtil::GetGLExtensionsOperation());
|
||||
|
||||
if (Debug::shouldDebugOpenGL())
|
||||
realizeOperations->add(new Debug::EnableGLDebugOperation());
|
||||
@ -780,13 +782,13 @@ void OMW::Engine::prepareEngine()
|
||||
// gui needs our shaders path before everything else
|
||||
mResourceSystem->getSceneManager()->setShaderPath(mResDir / "shaders");
|
||||
|
||||
osg::ref_ptr<osg::GLExtensions> exts = osg::GLExtensions::Get(0, false);
|
||||
bool shadersSupported = exts && (exts->glslLanguageVersion >= 1.2f);
|
||||
osg::GLExtensions& exts = SceneUtil::getGLExtensions();
|
||||
bool shadersSupported = exts.glslLanguageVersion >= 1.2f;
|
||||
|
||||
#if OSG_VERSION_LESS_THAN(3, 6, 6)
|
||||
// hack fix for https://github.com/openscenegraph/OpenSceneGraph/issues/1028
|
||||
if (exts)
|
||||
exts->glRenderbufferStorageMultisampleCoverageNV = nullptr;
|
||||
if (!osg::isGLExtensionSupported(exts.contextID, "NV_framebuffer_multisample_coverage"))
|
||||
exts.glRenderbufferStorageMultisampleCoverageNV = nullptr;
|
||||
#endif
|
||||
|
||||
osg::ref_ptr<osg::Group> guiRoot = new osg::Group;
|
||||
@ -963,17 +965,17 @@ void OMW::Engine::go()
|
||||
}
|
||||
|
||||
// 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());
|
||||
mViewer->addEventHandler(resourceshandler);
|
||||
osg::ref_ptr<Resource::StatsHandler> resourcesHandler = new Resource::StatsHandler(stats.is_open(), *mVFS);
|
||||
mViewer->addEventHandler(resourcesHandler);
|
||||
|
||||
if (stats.is_open())
|
||||
Resource::CollectStatistics(mViewer);
|
||||
Resource::collectStatistics(*mViewer);
|
||||
|
||||
// Start the game
|
||||
if (!mSaveGameFile.empty())
|
||||
|
@ -2,6 +2,7 @@
|
||||
#include <components/fallback/fallback.hpp>
|
||||
#include <components/fallback/validate.hpp>
|
||||
#include <components/files/configurationmanager.hpp>
|
||||
#include <components/misc/osgpluginchecker.hpp>
|
||||
#include <components/misc/rng.hpp>
|
||||
#include <components/platform/platform.hpp>
|
||||
#include <components/version/version.hpp>
|
||||
@ -228,6 +229,9 @@ int runApplication(int argc, char* argv[])
|
||||
|
||||
if (parseOptions(argc, argv, *engine, cfgMgr))
|
||||
{
|
||||
if (!Misc::checkRequiredOSGPluginsArePresent())
|
||||
return 1;
|
||||
|
||||
engine->go();
|
||||
}
|
||||
|
||||
|
@ -265,7 +265,7 @@ namespace MWBase
|
||||
virtual bool isReadyToBlock(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;
|
||||
|
||||
|
@ -6,6 +6,8 @@
|
||||
#include <string>
|
||||
#include <string_view>
|
||||
|
||||
#include <components/vfs/pathutil.hpp>
|
||||
|
||||
#include "../mwsound/type.hpp"
|
||||
#include "../mwworld/ptr.hpp"
|
||||
|
||||
@ -129,11 +131,11 @@ namespace MWBase
|
||||
/// \param name of the folder that contains the playlist
|
||||
/// 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.
|
||||
/// \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
|
||||
/// \param filename name of a sound file in the VFS
|
||||
|
||||
|
@ -136,6 +136,7 @@ namespace MWBase
|
||||
|
||||
virtual bool isConsoleMode() const = 0;
|
||||
virtual bool isPostProcessorHudVisible() const = 0;
|
||||
virtual bool isSettingsWindowVisible() const = 0;
|
||||
virtual bool isInteractiveMessageBoxActive() const = 0;
|
||||
|
||||
virtual void toggleVisible(MWGui::GuiWindow wnd) = 0;
|
||||
@ -157,7 +158,6 @@ namespace MWBase
|
||||
virtual MWGui::ConfirmationDialog* getConfirmationDialog() = 0;
|
||||
virtual MWGui::TradeWindow* getTradeWindow() = 0;
|
||||
virtual MWGui::PostProcessorHud* getPostProcessorHud() = 0;
|
||||
virtual MWGui::SettingsWindow* getSettingsWindow() = 0;
|
||||
|
||||
/// Make the player use an item, while updating GUI state accordingly
|
||||
virtual void useItem(const MWWorld::Ptr& item, bool force = false) = 0;
|
||||
@ -202,9 +202,6 @@ namespace MWBase
|
||||
|
||||
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
|
||||
virtual void setDrowningBarVisibility(bool visible) = 0;
|
||||
|
||||
@ -293,7 +290,7 @@ namespace MWBase
|
||||
|
||||
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;
|
||||
|
||||
@ -345,6 +342,7 @@ namespace MWBase
|
||||
virtual void toggleConsole() = 0;
|
||||
virtual void toggleDebugWindow() = 0;
|
||||
virtual void togglePostProcessorHud() = 0;
|
||||
virtual void toggleSettingsWindow() = 0;
|
||||
|
||||
/// Cycle to next or previous spell
|
||||
virtual void cycleSpell(bool next) = 0;
|
||||
|
@ -183,8 +183,6 @@ namespace MWBase
|
||||
/// generate a name.
|
||||
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;
|
||||
//< Remove the script attached to ref from mLocalScripts
|
||||
|
||||
@ -463,7 +461,7 @@ namespace MWBase
|
||||
*/
|
||||
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,
|
||||
const osg::Vec3f& fallbackDirection, ESM::RefNum item)
|
||||
|
@ -104,13 +104,11 @@ namespace MWClass
|
||||
std::string_view name = getName(ptr);
|
||||
info.caption = MyGUI::TextIterator::toTagsString(MyGUI::UString(name)) + MWGui::ToolTips::getCountString(count);
|
||||
|
||||
std::string text;
|
||||
if (MWBase::Environment::get().getWindowManager()->getFullHelp())
|
||||
{
|
||||
text += MWGui::ToolTips::getCellRefString(ptr.getCellRef());
|
||||
text += MWGui::ToolTips::getMiscString(ref->mBase->mScript.getRefIdString(), "Script");
|
||||
info.extra += MWGui::ToolTips::getCellRefString(ptr.getCellRef());
|
||||
info.extra += MWGui::ToolTips::getMiscString(ref->mBase->mScript.getRefIdString(), "Script");
|
||||
}
|
||||
info.text = std::move(text);
|
||||
|
||||
return info;
|
||||
}
|
||||
|
@ -102,8 +102,8 @@ namespace MWClass
|
||||
|
||||
if (MWBase::Environment::get().getWindowManager()->getFullHelp())
|
||||
{
|
||||
text += MWGui::ToolTips::getCellRefString(ptr.getCellRef());
|
||||
text += MWGui::ToolTips::getMiscString(ref->mBase->mScript.getRefIdString(), "Script");
|
||||
info.extra += MWGui::ToolTips::getCellRefString(ptr.getCellRef());
|
||||
info.extra += MWGui::ToolTips::getMiscString(ref->mBase->mScript.getRefIdString(), "Script");
|
||||
}
|
||||
info.text = std::move(text);
|
||||
|
||||
|
@ -257,8 +257,8 @@ namespace MWClass
|
||||
|
||||
if (MWBase::Environment::get().getWindowManager()->getFullHelp())
|
||||
{
|
||||
text += MWGui::ToolTips::getCellRefString(ptr.getCellRef());
|
||||
text += MWGui::ToolTips::getMiscString(ref->mBase->mScript.getRefIdString(), "Script");
|
||||
info.extra += MWGui::ToolTips::getCellRefString(ptr.getCellRef());
|
||||
info.extra += MWGui::ToolTips::getMiscString(ref->mBase->mScript.getRefIdString(), "Script");
|
||||
}
|
||||
|
||||
info.enchant = ref->mBase->mEnchant;
|
||||
|
@ -121,8 +121,8 @@ namespace MWClass
|
||||
|
||||
if (MWBase::Environment::get().getWindowManager()->getFullHelp())
|
||||
{
|
||||
text += MWGui::ToolTips::getCellRefString(ptr.getCellRef());
|
||||
text += MWGui::ToolTips::getMiscString(ref->mBase->mScript.getRefIdString(), "Script");
|
||||
info.extra += MWGui::ToolTips::getCellRefString(ptr.getCellRef());
|
||||
info.extra += MWGui::ToolTips::getMiscString(ref->mBase->mScript.getRefIdString(), "Script");
|
||||
}
|
||||
|
||||
info.enchant = ref->mBase->mEnchant;
|
||||
|
@ -164,8 +164,8 @@ namespace MWClass
|
||||
|
||||
if (MWBase::Environment::get().getWindowManager()->getFullHelp())
|
||||
{
|
||||
text += MWGui::ToolTips::getCellRefString(ptr.getCellRef());
|
||||
text += MWGui::ToolTips::getMiscString(ref->mBase->mScript.getRefIdString(), "Script");
|
||||
info.extra += MWGui::ToolTips::getCellRefString(ptr.getCellRef());
|
||||
info.extra += MWGui::ToolTips::getMiscString(ref->mBase->mScript.getRefIdString(), "Script");
|
||||
}
|
||||
|
||||
info.enchant = ref->mBase->mEnchant;
|
||||
|
@ -265,10 +265,10 @@ namespace MWClass
|
||||
|
||||
if (MWBase::Environment::get().getWindowManager()->getFullHelp())
|
||||
{
|
||||
text += MWGui::ToolTips::getCellRefString(ptr.getCellRef());
|
||||
text += MWGui::ToolTips::getMiscString(ref->mBase->mScript.getRefIdString(), "Script");
|
||||
info.extra += MWGui::ToolTips::getCellRefString(ptr.getCellRef());
|
||||
info.extra += MWGui::ToolTips::getMiscString(ref->mBase->mScript.getRefIdString(), "Script");
|
||||
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);
|
||||
|
@ -316,11 +316,11 @@ namespace MWClass
|
||||
{
|
||||
const unsigned char* attack = nullptr;
|
||||
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)
|
||||
attack = weapon.get<ESM::Weapon>()->mBase->mData.mSlash;
|
||||
attack = weapon.get<ESM::Weapon>()->mBase->mData.mSlash.data();
|
||||
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)
|
||||
{
|
||||
damage = attack[0] + ((attack[1] - attack[0]) * attackStrength);
|
||||
@ -591,10 +591,8 @@ namespace MWClass
|
||||
std::string_view name = getName(ptr);
|
||||
info.caption = MyGUI::TextIterator::toTagsString(MyGUI::UString(name));
|
||||
|
||||
std::string text;
|
||||
if (MWBase::Environment::get().getWindowManager()->getFullHelp())
|
||||
text += MWGui::ToolTips::getMiscString(ref->mBase->mScript.getRefIdString(), "Script");
|
||||
info.text = std::move(text);
|
||||
info.extra += MWGui::ToolTips::getMiscString(ref->mBase->mScript.getRefIdString(), "Script");
|
||||
|
||||
return info;
|
||||
}
|
||||
|
@ -136,7 +136,7 @@ namespace MWClass
|
||||
const ESM::MagicEffect* effect = store.get<ESM::MagicEffect>().find(ESM::MagicEffect::Telekinesis);
|
||||
|
||||
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())
|
||||
{
|
||||
text += MWGui::ToolTips::getCellRefString(ptr.getCellRef());
|
||||
text += MWGui::ToolTips::getMiscString(ref->mBase->mScript.getRefIdString(), "Script");
|
||||
info.extra += MWGui::ToolTips::getCellRefString(ptr.getCellRef());
|
||||
info.extra += MWGui::ToolTips::getMiscString(ref->mBase->mScript.getRefIdString(), "Script");
|
||||
}
|
||||
info.text = std::move(text);
|
||||
|
||||
|
@ -117,8 +117,8 @@ namespace MWClass
|
||||
|
||||
if (MWBase::Environment::get().getWindowManager()->getFullHelp())
|
||||
{
|
||||
text += MWGui::ToolTips::getCellRefString(ptr.getCellRef());
|
||||
text += MWGui::ToolTips::getMiscString(ref->mBase->mScript.getRefIdString(), "Script");
|
||||
info.extra += MWGui::ToolTips::getCellRefString(ptr.getCellRef());
|
||||
info.extra += MWGui::ToolTips::getMiscString(ref->mBase->mScript.getRefIdString(), "Script");
|
||||
}
|
||||
|
||||
MWWorld::Ptr player = MWBase::Environment::get().getWorld()->getPlayerPtr();
|
||||
|
@ -173,8 +173,8 @@ namespace MWClass
|
||||
|
||||
if (MWBase::Environment::get().getWindowManager()->getFullHelp())
|
||||
{
|
||||
text += MWGui::ToolTips::getCellRefString(ptr.getCellRef());
|
||||
text += MWGui::ToolTips::getMiscString(ref->mBase->mScript.getRefIdString(), "Script");
|
||||
info.extra += MWGui::ToolTips::getCellRefString(ptr.getCellRef());
|
||||
info.extra += MWGui::ToolTips::getMiscString(ref->mBase->mScript.getRefIdString(), "Script");
|
||||
}
|
||||
|
||||
info.text = std::move(text);
|
||||
|
@ -118,8 +118,8 @@ namespace MWClass
|
||||
|
||||
if (MWBase::Environment::get().getWindowManager()->getFullHelp())
|
||||
{
|
||||
text += MWGui::ToolTips::getCellRefString(ptr.getCellRef());
|
||||
text += MWGui::ToolTips::getMiscString(ref->mBase->mScript.getRefIdString(), "Script");
|
||||
info.extra += MWGui::ToolTips::getCellRefString(ptr.getCellRef());
|
||||
info.extra += MWGui::ToolTips::getMiscString(ref->mBase->mScript.getRefIdString(), "Script");
|
||||
}
|
||||
|
||||
info.text = std::move(text);
|
||||
|
@ -163,8 +163,8 @@ namespace MWClass
|
||||
|
||||
if (MWBase::Environment::get().getWindowManager()->getFullHelp())
|
||||
{
|
||||
text += MWGui::ToolTips::getCellRefString(ptr.getCellRef());
|
||||
text += MWGui::ToolTips::getMiscString(ref->mBase->mScript.getRefIdString(), "Script");
|
||||
info.extra += MWGui::ToolTips::getCellRefString(ptr.getCellRef());
|
||||
info.extra += MWGui::ToolTips::getMiscString(ref->mBase->mScript.getRefIdString(), "Script");
|
||||
}
|
||||
|
||||
info.text = std::move(text);
|
||||
|
@ -635,11 +635,11 @@ namespace MWClass
|
||||
{
|
||||
const unsigned char* attack = nullptr;
|
||||
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)
|
||||
attack = weapon.get<ESM::Weapon>()->mBase->mData.mSlash;
|
||||
attack = weapon.get<ESM::Weapon>()->mBase->mData.mSlash.data();
|
||||
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)
|
||||
{
|
||||
damage = attack[0] + ((attack[1] - attack[0]) * attackStrength);
|
||||
@ -1118,7 +1118,7 @@ namespace MWClass
|
||||
}
|
||||
|
||||
if (fullHelp)
|
||||
info.text = MWGui::ToolTips::getMiscString(ref->mBase->mScript.getRefIdString(), "Script");
|
||||
info.extra = MWGui::ToolTips::getMiscString(ref->mBase->mScript.getRefIdString(), "Script");
|
||||
|
||||
return info;
|
||||
}
|
||||
|
@ -19,6 +19,7 @@
|
||||
#include "../mwrender/renderinginterface.hpp"
|
||||
|
||||
#include "../mwmechanics/alchemy.hpp"
|
||||
#include "../mwmechanics/spellutil.hpp"
|
||||
|
||||
#include "classmodel.hpp"
|
||||
|
||||
@ -65,9 +66,7 @@ namespace MWClass
|
||||
|
||||
int Potion::getValue(const MWWorld::ConstPtr& ptr) const
|
||||
{
|
||||
const MWWorld::LiveCellRef<ESM::Potion>* ref = ptr.get<ESM::Potion>();
|
||||
|
||||
return ref->mBase->mData.mValue;
|
||||
return MWMechanics::getPotionValue(*ptr.get<ESM::Potion>()->mBase);
|
||||
}
|
||||
|
||||
const ESM::RefId& Potion::getUpSoundId(const MWWorld::ConstPtr& ptr) const
|
||||
@ -101,7 +100,7 @@ namespace MWClass
|
||||
std::string text;
|
||||
|
||||
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);
|
||||
|
||||
@ -114,8 +113,8 @@ namespace MWClass
|
||||
|
||||
if (MWBase::Environment::get().getWindowManager()->getFullHelp())
|
||||
{
|
||||
text += MWGui::ToolTips::getCellRefString(ptr.getCellRef());
|
||||
text += MWGui::ToolTips::getMiscString(ref->mBase->mScript.getRefIdString(), "Script");
|
||||
info.extra += MWGui::ToolTips::getCellRefString(ptr.getCellRef());
|
||||
info.extra += MWGui::ToolTips::getMiscString(ref->mBase->mScript.getRefIdString(), "Script");
|
||||
}
|
||||
|
||||
info.text = std::move(text);
|
||||
|
@ -117,8 +117,8 @@ namespace MWClass
|
||||
|
||||
if (MWBase::Environment::get().getWindowManager()->getFullHelp())
|
||||
{
|
||||
text += MWGui::ToolTips::getCellRefString(ptr.getCellRef());
|
||||
text += MWGui::ToolTips::getMiscString(ref->mBase->mScript.getRefIdString(), "Script");
|
||||
info.extra += MWGui::ToolTips::getCellRefString(ptr.getCellRef());
|
||||
info.extra += MWGui::ToolTips::getMiscString(ref->mBase->mScript.getRefIdString(), "Script");
|
||||
}
|
||||
|
||||
info.text = std::move(text);
|
||||
|
@ -119,8 +119,8 @@ namespace MWClass
|
||||
|
||||
if (MWBase::Environment::get().getWindowManager()->getFullHelp())
|
||||
{
|
||||
text += MWGui::ToolTips::getCellRefString(ptr.getCellRef());
|
||||
text += MWGui::ToolTips::getMiscString(ref->mBase->mScript.getRefIdString(), "Script");
|
||||
info.extra += MWGui::ToolTips::getCellRefString(ptr.getCellRef());
|
||||
info.extra += MWGui::ToolTips::getMiscString(ref->mBase->mScript.getRefIdString(), "Script");
|
||||
}
|
||||
|
||||
info.text = std::move(text);
|
||||
|
@ -239,8 +239,8 @@ namespace MWClass
|
||||
|
||||
if (MWBase::Environment::get().getWindowManager()->getFullHelp())
|
||||
{
|
||||
text += MWGui::ToolTips::getCellRefString(ptr.getCellRef());
|
||||
text += MWGui::ToolTips::getMiscString(ref->mBase->mScript.getRefIdString(), "Script");
|
||||
info.extra += MWGui::ToolTips::getCellRefString(ptr.getCellRef());
|
||||
info.extra += MWGui::ToolTips::getMiscString(ref->mBase->mScript.getRefIdString(), "Script");
|
||||
}
|
||||
|
||||
info.text = std::move(text);
|
||||
|
@ -653,7 +653,7 @@ namespace MWDialogue
|
||||
if (Settings::gui().mSubtitles)
|
||||
winMgr->messageBox(info->mResponse);
|
||||
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())
|
||||
executeScript(info->mResultScript, actor);
|
||||
}
|
||||
|
@ -87,7 +87,7 @@ namespace MWDialogue
|
||||
// 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
|
||||
// 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)
|
||||
{
|
||||
@ -148,11 +148,11 @@ namespace MWDialogue
|
||||
// resolve overlapping keywords
|
||||
while (!matches.empty())
|
||||
{
|
||||
int longestKeywordSize = 0;
|
||||
std::size_t longestKeywordSize = 0;
|
||||
typename std::vector<Match>::iterator longestKeyword = matches.begin();
|
||||
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)
|
||||
{
|
||||
longestKeywordSize = size;
|
||||
@ -199,7 +199,7 @@ namespace MWDialogue
|
||||
|
||||
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);
|
||||
|
||||
|
@ -39,7 +39,7 @@ namespace
|
||||
{
|
||||
const std::string mText;
|
||||
const Response mResponses[3];
|
||||
const std::string mSound;
|
||||
const VFS::Path::Normalized mSound;
|
||||
};
|
||||
|
||||
Step sGenerateClassSteps(int number)
|
||||
|
@ -771,11 +771,6 @@ namespace MWGui
|
||||
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)
|
||||
{
|
||||
if (mPtr == currentPtr)
|
||||
|
@ -47,8 +47,6 @@ namespace MWGui
|
||||
|
||||
void onOpen() override;
|
||||
|
||||
void onResChange(int width, int height) override;
|
||||
|
||||
// Print a message to the console, in specified color.
|
||||
void print(const std::string& msg, std::string_view color = MWBase::WindowManager::sConsoleColor_Default);
|
||||
|
||||
|
@ -273,7 +273,7 @@ namespace MWGui
|
||||
|
||||
void EnchantingDialog::notifyEffectsChanged()
|
||||
{
|
||||
mEffectList.mList = mEffects;
|
||||
mEffectList.populate(mEffects);
|
||||
mEnchanting.setEffect(mEffectList);
|
||||
updateLabels();
|
||||
}
|
||||
|
@ -427,7 +427,7 @@ namespace MWGui
|
||||
{
|
||||
// use the icon of the first effect
|
||||
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::replace(icon.begin(), icon.end(), '/', '\\');
|
||||
size_t slashPos = icon.rfind('\\');
|
||||
|
@ -417,6 +417,8 @@ namespace MWGui
|
||||
|
||||
void InventoryWindow::onWindowResize(MyGUI::Window* _sender)
|
||||
{
|
||||
WindowBase::clampWindowCoordinates(_sender);
|
||||
|
||||
adjustPanes();
|
||||
const WindowSettingValues settings = getModeSettings(mGuiMode);
|
||||
|
||||
|
@ -246,12 +246,12 @@ namespace MWGui
|
||||
|
||||
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);
|
||||
if (wrap)
|
||||
index = (index + keyFocusList.size()) % keyFocusList.size();
|
||||
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];
|
||||
int vertdiff = next->getTop() - focus->getTop();
|
||||
|
@ -99,7 +99,7 @@ namespace MWGui
|
||||
}
|
||||
else if (name == "options")
|
||||
{
|
||||
winMgr->getSettingsWindow()->setVisible(true);
|
||||
winMgr->toggleSettingsWindow();
|
||||
}
|
||||
else if (name == "credits")
|
||||
winMgr->playVideo("mw_credits.bik", true);
|
||||
@ -212,6 +212,12 @@ namespace MWGui
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
|
@ -95,6 +95,13 @@ namespace
|
||||
return std::clamp(
|
||||
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
|
||||
@ -170,12 +177,9 @@ namespace MWGui
|
||||
LocalMapBase::LocalMapBase(
|
||||
CustomMarkerCollection& markers, MWRender::LocalMap* localMapRender, bool fogOfWarEnabled)
|
||||
: mLocalMapRender(localMapRender)
|
||||
, mCurX(0)
|
||||
, mCurY(0)
|
||||
, mInterior(false)
|
||||
, mActiveCell(nullptr)
|
||||
, mLocalMap(nullptr)
|
||||
, mCompass(nullptr)
|
||||
, mChanged(true)
|
||||
, mFogOfWarToggled(true)
|
||||
, mFogOfWarEnabled(fogOfWarEnabled)
|
||||
, mNumCells(1)
|
||||
@ -231,12 +235,6 @@ namespace MWGui
|
||||
}
|
||||
}
|
||||
|
||||
void LocalMapBase::setCellPrefix(const std::string& prefix)
|
||||
{
|
||||
mPrefix = prefix;
|
||||
mChanged = true;
|
||||
}
|
||||
|
||||
bool LocalMapBase::toggleFogOfWar()
|
||||
{
|
||||
mFogOfWarToggled = !mFogOfWarToggled;
|
||||
@ -262,8 +260,8 @@ namespace MWGui
|
||||
{
|
||||
// normalized cell coordinates
|
||||
auto mapWidgetSize = getWidgetSize();
|
||||
return MyGUI::IntPoint(std::round(nX * mapWidgetSize + (mCellDistance + (cellX - mCurX)) * mapWidgetSize),
|
||||
std::round(nY * mapWidgetSize + (mCellDistance - (cellY - mCurY)) * mapWidgetSize));
|
||||
return MyGUI::IntPoint(std::round((nX + mCellDistance + cellX - mActiveCell->getGridX()) * mapWidgetSize),
|
||||
std::round((nY + mCellDistance - cellY + mActiveCell->getGridY()) * mapWidgetSize));
|
||||
}
|
||||
|
||||
MyGUI::IntPoint LocalMapBase::getMarkerPosition(float worldX, float worldY, MarkerUserData& markerPos) const
|
||||
@ -272,7 +270,7 @@ namespace MWGui
|
||||
// normalized cell coordinates
|
||||
float nX, nY;
|
||||
|
||||
if (!mInterior)
|
||||
if (mActiveCell->isExterior())
|
||||
{
|
||||
ESM::ExteriorCellLocation cellPos = ESM::positionToExteriorCellLocation(worldX, worldY);
|
||||
cellIndex.x() = cellPos.mX;
|
||||
@ -336,7 +334,7 @@ namespace MWGui
|
||||
|
||||
std::vector<MyGUI::Widget*>& LocalMapBase::currentDoorMarkersWidgets()
|
||||
{
|
||||
return mInterior ? mInteriorDoorMarkerWidgets : mExteriorDoorMarkerWidgets;
|
||||
return mActiveCell->isExterior() ? mExteriorDoorMarkerWidgets : mInteriorDoorMarkerWidgets;
|
||||
}
|
||||
|
||||
void LocalMapBase::updateCustomMarkers()
|
||||
@ -344,12 +342,14 @@ namespace MWGui
|
||||
for (MyGUI::Widget* widget : mCustomMarkerWidgets)
|
||||
MyGUI::Gui::getInstance().destroyWidget(widget);
|
||||
mCustomMarkerWidgets.clear();
|
||||
|
||||
if (!mActiveCell)
|
||||
return;
|
||||
for (int dX = -mCellDistance; dX <= mCellDistance; ++dX)
|
||||
{
|
||||
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);
|
||||
for (CustomMarkerCollection::ContainerType::const_iterator it = markers.first; it != markers.second;
|
||||
@ -377,16 +377,25 @@ namespace MWGui
|
||||
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
|
||||
|
||||
if (!interior && !(x == mCurX && y == mCurY))
|
||||
const int x = cell.getGridX();
|
||||
const int y = cell.getGridY();
|
||||
|
||||
if (cell.isExterior())
|
||||
{
|
||||
const MyGUI::IntRect intersection
|
||||
= { std::max(x, mCurX) - mCellDistance, std::max(y, mCurY) - mCellDistance,
|
||||
std::min(x, mCurX) + mCellDistance, std::min(y, mCurY) + mCellDistance };
|
||||
int curX = 0;
|
||||
int curY = 0;
|
||||
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 currentView = createRect({ x, y }, mCellDistance);
|
||||
@ -407,17 +416,14 @@ namespace MWGui
|
||||
for (auto& widget : mDoorMarkersToRecycle)
|
||||
widget->setVisible(false);
|
||||
|
||||
for (auto const& cell : mMaps)
|
||||
for (auto const& entry : mMaps)
|
||||
{
|
||||
if (mHasALastActiveCell && !intersection.inside({ cell.mCellX, cell.mCellY }))
|
||||
mLocalMapRender->removeExteriorCell(cell.mCellX, cell.mCellY);
|
||||
if (mHasALastActiveCell && !intersection.inside({ entry.mCellX, entry.mCellY }))
|
||||
mLocalMapRender->removeExteriorCell(entry.mCellX, entry.mCellY);
|
||||
}
|
||||
}
|
||||
|
||||
mCurX = x;
|
||||
mCurY = y;
|
||||
mInterior = interior;
|
||||
mChanged = false;
|
||||
mActiveCell = &cell;
|
||||
|
||||
for (int mx = 0; mx < mNumCells; ++mx)
|
||||
{
|
||||
@ -441,7 +447,7 @@ namespace MWGui
|
||||
for (MyGUI::Widget* widget : currentDoorMarkersWidgets())
|
||||
widget->setCoord(getMarkerCoordinates(widget, 8));
|
||||
|
||||
if (!mInterior)
|
||||
if (mActiveCell->isExterior())
|
||||
mHasALastActiveCell = true;
|
||||
|
||||
updateMagicMarkers();
|
||||
@ -580,7 +586,7 @@ namespace MWGui
|
||||
|
||||
if (!entry.mMapTexture)
|
||||
{
|
||||
if (!mInterior)
|
||||
if (mActiveCell->isExterior())
|
||||
requestMapRender(&MWBase::Environment::get().getWorldModel()->getExterior(
|
||||
ESM::ExteriorCellLocation(entry.mCellX, entry.mCellY, ESM::Cell::sDefaultWorldspaceId)));
|
||||
|
||||
@ -626,12 +632,12 @@ namespace MWGui
|
||||
mDoorMarkersToRecycle.end(), mInteriorDoorMarkerWidgets.begin(), mInteriorDoorMarkerWidgets.end());
|
||||
mInteriorDoorMarkerWidgets.clear();
|
||||
|
||||
if (mInterior)
|
||||
if (!mActiveCell->isExterior())
|
||||
{
|
||||
for (MyGUI::Widget* widget : mExteriorDoorMarkerWidgets)
|
||||
widget->setVisible(false);
|
||||
|
||||
MWWorld::CellStore& cell = worldModel->getInterior(mPrefix);
|
||||
MWWorld::CellStore& cell = worldModel->getInterior(mActiveCell->getNameId());
|
||||
world->getDoorMarkers(cell, doors);
|
||||
}
|
||||
else
|
||||
@ -678,7 +684,7 @@ namespace MWGui
|
||||
}
|
||||
|
||||
currentDoorMarkersWidgets().push_back(markerWidget);
|
||||
if (!mInterior)
|
||||
if (mActiveCell->isExterior())
|
||||
mExteriorDoorsByCell[{ data->cellX, data->cellY }].push_back(markerWidget);
|
||||
}
|
||||
|
||||
@ -701,8 +707,7 @@ namespace MWGui
|
||||
MWWorld::CellStore* markedCell = nullptr;
|
||||
ESM::Position markedPosition;
|
||||
MWBase::Environment::get().getWorld()->getPlayer().getMarkedPosition(markedCell, markedPosition);
|
||||
if (markedCell && markedCell->isExterior() == !mInterior
|
||||
&& (!mInterior || Misc::StringUtils::ciEqual(markedCell->getCell()->getNameId(), mPrefix)))
|
||||
if (markedCell && markedCell->getCell()->getWorldSpace() == mActiveCell->getWorldSpace())
|
||||
{
|
||||
MarkerUserData markerPos(mLocalMapRender);
|
||||
MyGUI::ImageBox* markerWidget = mLocalMap->createWidget<MyGUI::ImageBox>("ImageBox",
|
||||
@ -870,11 +875,11 @@ namespace MWGui
|
||||
int y = (int(widgetPos.top / float(mapWidgetSize)) - mCellDistance) * -1;
|
||||
float nX = widgetPos.left / float(mapWidgetSize) - int(widgetPos.left / float(mapWidgetSize));
|
||||
float nY = widgetPos.top / float(mapWidgetSize) - int(widgetPos.top / float(mapWidgetSize));
|
||||
x += mCurX;
|
||||
y += mCurY;
|
||||
x += mActiveCell->getGridX();
|
||||
y += mActiveCell->getGridY();
|
||||
|
||||
osg::Vec2f worldPos;
|
||||
if (mInterior)
|
||||
if (!mActiveCell->isExterior())
|
||||
{
|
||||
worldPos = mLocalMapRender->interiorMapToWorldPosition(nX, nY, x, y);
|
||||
}
|
||||
@ -886,7 +891,7 @@ namespace MWGui
|
||||
|
||||
mEditingMarker.mWorldX = worldPos.x();
|
||||
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;
|
||||
|
||||
@ -977,7 +982,7 @@ namespace MWGui
|
||||
resizeGlobalMap();
|
||||
|
||||
float x = mCurPos.x(), y = mCurPos.y();
|
||||
if (mInterior)
|
||||
if (!mActiveCell->isExterior())
|
||||
{
|
||||
auto pos = MWBase::Environment::get().getWorld()->getPlayer().getLastKnownExteriorPosition();
|
||||
x = pos.x();
|
||||
@ -1020,7 +1025,7 @@ namespace MWGui
|
||||
resizeGlobalMap();
|
||||
}
|
||||
|
||||
MapWindow::~MapWindow() {}
|
||||
MapWindow::~MapWindow() = default;
|
||||
|
||||
void MapWindow::setCellName(const std::string& cellName)
|
||||
{
|
||||
@ -1289,7 +1294,7 @@ namespace MWGui
|
||||
mMarkers.clear();
|
||||
|
||||
mGlobalMapRender->clear();
|
||||
mChanged = true;
|
||||
mActiveCell = nullptr;
|
||||
|
||||
for (auto& widgetPair : mGlobalMapMarkers)
|
||||
MyGUI::Gui::getInstance().destroyWidget(widgetPair.first.widget);
|
||||
|
@ -27,6 +27,7 @@ namespace ESM
|
||||
|
||||
namespace MWWorld
|
||||
{
|
||||
class Cell;
|
||||
class CellStore;
|
||||
}
|
||||
|
||||
@ -77,8 +78,7 @@ namespace MWGui
|
||||
virtual ~LocalMapBase();
|
||||
void init(MyGUI::ScrollView* widget, MyGUI::ImageBox* compass, int cellDistance = Constants::CellGridRadius);
|
||||
|
||||
void setCellPrefix(const std::string& prefix);
|
||||
void setActiveCell(const int x, const int y, bool interior = false);
|
||||
void setActiveCell(const MWWorld::Cell& cell);
|
||||
void requestMapRender(const MWWorld::CellStore* cell);
|
||||
void setPlayerDir(const float x, const float y);
|
||||
void setPlayerPos(int cellX, int cellY, const float nx, const float ny);
|
||||
@ -115,15 +115,12 @@ namespace MWGui
|
||||
float mLocalMapZoom = 1.f;
|
||||
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;
|
||||
osg::Vec2f mCurPos; // the position of the player in the world (in cell coords)
|
||||
|
||||
bool mInterior;
|
||||
MyGUI::ScrollView* mLocalMap;
|
||||
MyGUI::ImageBox* mCompass;
|
||||
std::string mPrefix;
|
||||
bool mChanged;
|
||||
bool mFogOfWarToggled;
|
||||
bool mFogOfWarEnabled;
|
||||
|
||||
|
@ -28,7 +28,7 @@ namespace MWGui
|
||||
MessageBoxManager::clear();
|
||||
}
|
||||
|
||||
int MessageBoxManager::getMessagesCount()
|
||||
std::size_t MessageBoxManager::getMessagesCount()
|
||||
{
|
||||
return mMessageBoxes.size();
|
||||
}
|
||||
|
@ -29,7 +29,7 @@ namespace MWGui
|
||||
bool immediate = false, int defaultFocus = -1);
|
||||
bool isInteractiveMessageBox();
|
||||
|
||||
int getMessagesCount();
|
||||
std::size_t getMessagesCount();
|
||||
|
||||
const InteractiveMessageBox* getInteractiveMessageBox() const { return mInterMessageBoxe.get(); }
|
||||
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
x
Reference in New Issue
Block a user