mirror of
https://gitlab.com/OpenMW/openmw.git
synced 2025-01-29 18:32:36 +00:00
Merge branch 'master' into feature/pplLauncherSetting
This commit is contained in:
commit
563f5b37a3
@ -210,6 +210,7 @@ Ubuntu_GCC_Debug:
|
||||
CCACHE_SIZE: 3G
|
||||
CMAKE_BUILD_TYPE: Debug
|
||||
CMAKE_CXX_FLAGS_DEBUG: -O0
|
||||
BUILD_SHARED_LIBS: 1
|
||||
# When CCache doesn't exist (e.g. first build on a fork), build takes more than 1h, which is the default for forks.
|
||||
timeout: 2h
|
||||
|
||||
@ -520,19 +521,19 @@ 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
|
||||
|
||||
.Windows_Ninja_Base:
|
||||
tags:
|
||||
- windows
|
||||
- saas-windows-medium-amd64
|
||||
rules:
|
||||
- if: $CI_PIPELINE_SOURCE == "push" || $CI_PIPELINE_SOURCE == "merge_request_event"
|
||||
before_script:
|
||||
@ -569,60 +570,54 @@ macOS13_Xcode14_arm64:
|
||||
- $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_Ninja\.cmake\api\v1\query\codemodel-v2
|
||||
- sh CI/before_script.msvc.sh -c $config -p Win64 -v 2019 -k -V -N -b -t -C $multiview -E
|
||||
- New-Item -Type File -Force -Path MSVC2022_64_Ninja\.cmake\api\v1\query\codemodel-v2
|
||||
- sh CI/before_script.msvc.sh -c $config -p Win64 -v 2022 -k -V -N -b -t -C $multiview -E
|
||||
- Get-Volume
|
||||
- cd MSVC2019_64_Ninja
|
||||
- cd MSVC2022_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}"))/"
|
||||
- Get-ChildItem -Recurse *.ilk | Remove-Item
|
||||
- |
|
||||
if (Get-ChildItem -Recurse *.pdb) {
|
||||
7z a -tzip "..\..\$(Make-SafeFileName("OpenMW_MSVC2019_64_${config}_${CI_COMMIT_REF_NAME}_${CI_JOB_ID}_symbols.zip"))" '*.pdb' CI-ID.txt
|
||||
7z a -tzip "..\..\$(Make-SafeFileName("OpenMW_MSVC2022_64_${config}_${CI_COMMIT_REF_NAME}_${CI_JOB_ID}_symbols.zip"))" '*.pdb' CI-ID.txt
|
||||
if (Test-Path env:AWS_ACCESS_KEY_ID) {
|
||||
aws --endpoint-url https://rgw.ctrl-c.liu.se s3 cp "..\..\$(Make-SafeFileName("OpenMW_MSVC2019_64_${config}_${CI_COMMIT_REF_NAME}_${CI_JOB_ID}_symbols.zip"))" s3://openmw-artifacts/${artifactDirectory}
|
||||
aws --endpoint-url https://rgw.ctrl-c.liu.se s3 cp "..\..\$(Make-SafeFileName("OpenMW_MSVC2022_64_${config}_${CI_COMMIT_REF_NAME}_${CI_JOB_ID}_symbols.zip"))" s3://openmw-artifacts/${artifactDirectory}
|
||||
}
|
||||
Push-Location ..
|
||||
..\CI\Store-Symbols.ps1
|
||||
if (Test-Path env:AWS_ACCESS_KEY_ID) {
|
||||
aws --endpoint-url https://rgw.ctrl-c.liu.se s3 cp --recursive --exclude * --include *.ex_ --include *.dl_ --include *.pd_ .\SymStore s3://openmw-sym
|
||||
}
|
||||
7z a -tzip "..\$(Make-SafeFileName("OpenMW_MSVC2019_64_${config}_${CI_COMMIT_REF_NAME}_${CI_JOB_ID}_sym_store.zip"))" '.\SymStore\*' $config\CI-ID.txt
|
||||
7z a -tzip "..\$(Make-SafeFileName("OpenMW_MSVC2022_64_${config}_${CI_COMMIT_REF_NAME}_${CI_JOB_ID}_sym_store.zip"))" '.\SymStore\*' $config\CI-ID.txt
|
||||
Pop-Location
|
||||
Get-ChildItem -Recurse *.pdb | Remove-Item
|
||||
}
|
||||
- 7z a -tzip "..\..\$(Make-SafeFileName("OpenMW_MSVC2019_64_${config}_${CI_COMMIT_REF_NAME}.zip"))" '*'
|
||||
- 7z a -tzip "..\..\$(Make-SafeFileName("OpenMW_MSVC2022_64_${config}_${CI_COMMIT_REF_NAME}.zip"))" '*'
|
||||
- |
|
||||
if (Test-Path env:AWS_ACCESS_KEY_ID) {
|
||||
aws --endpoint-url https://rgw.ctrl-c.liu.se s3 cp "..\..\$(Make-SafeFileName("OpenMW_MSVC2019_64_${config}_${CI_COMMIT_REF_NAME}.zip"))" s3://openmw-artifacts/${artifactDirectory}
|
||||
aws --endpoint-url https://rgw.ctrl-c.liu.se s3 cp "..\..\$(Make-SafeFileName("OpenMW_MSVC2022_64_${config}_${CI_COMMIT_REF_NAME}.zip"))" s3://openmw-artifacts/${artifactDirectory}
|
||||
}
|
||||
- if ($executables) { foreach ($exe in $executables.Split(',')) { & .\$exe } }
|
||||
after_script:
|
||||
- Get-Volume
|
||||
- Copy-Item C:\ProgramData\chocolatey\logs\chocolatey.log
|
||||
cache:
|
||||
key: ninja-v8
|
||||
key: ninja-2022-v9
|
||||
paths:
|
||||
- ccache
|
||||
- deps
|
||||
- MSVC2019_64_Ninja/deps/Qt
|
||||
- MSVC2022_64_Ninja/deps/Qt
|
||||
artifacts:
|
||||
when: always
|
||||
paths:
|
||||
- "*.zip"
|
||||
- "*.log"
|
||||
- MSVC2019_64_Ninja/*.log
|
||||
- MSVC2019_64_Ninja/*/*.log
|
||||
- MSVC2019_64_Ninja/*/*/*.log
|
||||
- MSVC2019_64_Ninja/*/*/*/*.log
|
||||
- MSVC2019_64_Ninja/*/*/*/*/*.log
|
||||
- MSVC2019_64_Ninja/*/*/*/*/*/*.log
|
||||
- MSVC2019_64_Ninja/*/*/*/*/*/*/*.log
|
||||
- MSVC2019_64_Ninja/*/*/*/*/*/*/*/*.log
|
||||
- MSVC2022_64_Ninja/*.log
|
||||
- MSVC2022_64_Ninja/**/*.log
|
||||
# When CCache doesn't exist (e.g. first build on a fork), build takes more than 1h, which is the default for forks.
|
||||
timeout: 2h
|
||||
|
||||
@ -655,7 +650,7 @@ macOS13_Xcode14_arm64:
|
||||
|
||||
.Windows_MSBuild_Base:
|
||||
tags:
|
||||
- windows
|
||||
- saas-windows-medium-amd64
|
||||
rules:
|
||||
- if: $CI_PIPELINE_SOURCE == "push" || $CI_PIPELINE_SOURCE == "merge_request_event"
|
||||
before_script:
|
||||
@ -665,7 +660,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
|
||||
@ -688,62 +682,51 @@ 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
|
||||
- New-Item -Type File -Force -Path MSVC2022_64\.cmake\api\v1\query\codemodel-v2
|
||||
- sh CI/before_script.msvc.sh -c $config -p Win64 -v 2022 -k -V -b -t -C $multiview -E
|
||||
- cd MSVC2022_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}"))/"
|
||||
- Get-ChildItem -Recurse *.ilk | Remove-Item
|
||||
- |
|
||||
if (Get-ChildItem -Recurse *.pdb) {
|
||||
7z a -tzip "..\..\$(Make-SafeFileName("OpenMW_MSVC2019_64_${config}_${CI_COMMIT_REF_NAME}_${CI_JOB_ID}_symbols.zip"))" '*.pdb' CI-ID.txt
|
||||
7z a -tzip "..\..\$(Make-SafeFileName("OpenMW_MSVC2022_64_${config}_${CI_COMMIT_REF_NAME}_${CI_JOB_ID}_symbols.zip"))" '*.pdb' CI-ID.txt
|
||||
if (Test-Path env:AWS_ACCESS_KEY_ID) {
|
||||
aws --endpoint-url https://rgw.ctrl-c.liu.se s3 cp "..\..\$(Make-SafeFileName("OpenMW_MSVC2019_64_${config}_${CI_COMMIT_REF_NAME}_${CI_JOB_ID}_symbols.zip"))" s3://openmw-artifacts/${artifactDirectory}
|
||||
aws --endpoint-url https://rgw.ctrl-c.liu.se s3 cp "..\..\$(Make-SafeFileName("OpenMW_MSVC2022_64_${config}_${CI_COMMIT_REF_NAME}_${CI_JOB_ID}_symbols.zip"))" s3://openmw-artifacts/${artifactDirectory}
|
||||
}
|
||||
Push-Location ..
|
||||
..\CI\Store-Symbols.ps1
|
||||
if (Test-Path env:AWS_ACCESS_KEY_ID) {
|
||||
aws --endpoint-url https://rgw.ctrl-c.liu.se s3 cp --recursive --exclude * --include *.ex_ --include *.dl_ --include *.pd_ .\SymStore s3://openmw-sym
|
||||
}
|
||||
7z a -tzip "..\$(Make-SafeFileName("OpenMW_MSVC2019_64_${config}_${CI_COMMIT_REF_NAME}_${CI_JOB_ID}_sym_store.zip"))" '.\SymStore\*' $config\CI-ID.txt
|
||||
7z a -tzip "..\$(Make-SafeFileName("OpenMW_MSVC2022_64_${config}_${CI_COMMIT_REF_NAME}_${CI_JOB_ID}_sym_store.zip"))" '.\SymStore\*' $config\CI-ID.txt
|
||||
Pop-Location
|
||||
Get-ChildItem -Recurse *.pdb | Remove-Item
|
||||
}
|
||||
- 7z a -tzip "..\..\$(Make-SafeFileName("OpenMW_MSVC2019_64_${config}_${CI_COMMIT_REF_NAME}.zip"))" '*'
|
||||
- 7z a -tzip "..\..\$(Make-SafeFileName("OpenMW_MSVC2022_64_${config}_${CI_COMMIT_REF_NAME}.zip"))" '*'
|
||||
- |
|
||||
if (Test-Path env:AWS_ACCESS_KEY_ID) {
|
||||
aws --endpoint-url https://rgw.ctrl-c.liu.se s3 cp "..\..\$(Make-SafeFileName("OpenMW_MSVC2019_64_${config}_${CI_COMMIT_REF_NAME}.zip"))" s3://openmw-artifacts/${artifactDirectory}
|
||||
aws --endpoint-url https://rgw.ctrl-c.liu.se s3 cp "..\..\$(Make-SafeFileName("OpenMW_MSVC2022_64_${config}_${CI_COMMIT_REF_NAME}.zip"))" s3://openmw-artifacts/${artifactDirectory}
|
||||
}
|
||||
- if ($executables) { foreach ($exe in $executables.Split(',')) { & .\$exe } }
|
||||
after_script:
|
||||
- Get-Volume
|
||||
- Copy-Item C:\ProgramData\chocolatey\logs\chocolatey.log
|
||||
cache:
|
||||
key: msbuild-v8
|
||||
key: msbuild-2022-v9
|
||||
paths:
|
||||
- ccache
|
||||
- deps
|
||||
- MSVC2019_64/deps/Qt
|
||||
- MSVC2022_64/deps/Qt
|
||||
artifacts:
|
||||
when: always
|
||||
paths:
|
||||
- "*.zip"
|
||||
- "*.log"
|
||||
- MSVC2019_64/*.log
|
||||
- MSVC2019_64/*/*.log
|
||||
- MSVC2019_64/*/*/*.log
|
||||
- MSVC2019_64/*/*/*/*.log
|
||||
- MSVC2019_64/*/*/*/*/*.log
|
||||
- MSVC2019_64/*/*/*/*/*/*.log
|
||||
- MSVC2019_64/*/*/*/*/*/*/*.log
|
||||
- MSVC2019_64/*/*/*/*/*/*/*/*.log
|
||||
- MSVC2022_64/*.log
|
||||
- MSVC2022_64/**/*.log
|
||||
# When CCache doesn't exist (e.g. first build on a fork), build takes more than 1h, which is the default for forks.
|
||||
timeout: 2h
|
||||
|
||||
|
@ -15,6 +15,7 @@ Programmers
|
||||
Nicolay Korslund - Project leader 2008-2010
|
||||
scrawl - Top contributor
|
||||
|
||||
AbduSharif
|
||||
Adam Hogan (aurix)
|
||||
Aesylwinn
|
||||
aegis
|
||||
@ -79,6 +80,7 @@ Programmers
|
||||
Eduard Cot (trombonecot)
|
||||
Eli2
|
||||
Emanuel Guével (potatoesmaster)
|
||||
Epoch
|
||||
Eris Caffee (eris)
|
||||
eroen
|
||||
escondida
|
||||
@ -187,6 +189,7 @@ Programmers
|
||||
pkubik
|
||||
PLkolek
|
||||
PlutonicOverkill
|
||||
Qlonever
|
||||
Radu-Marius Popovici (rpopovici)
|
||||
Rafael Moura (dhustkoder)
|
||||
Randy Davin (Kindi)
|
||||
|
50
CHANGELOG.md
50
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
|
||||
@ -44,9 +46,11 @@
|
||||
Bug #6657: Distant terrain tiles become black when using FWIW mod
|
||||
Bug #6661: Saved games that have no preview screenshot cause issues or crashes
|
||||
Bug #6716: mwscript comparison operator handling is too restrictive
|
||||
Bug #6723: "Turn to movement direction" makes the player rotate wildly with COLLADA
|
||||
Bug #6754: Beast to Non-beast transformation mod is not working on OpenMW
|
||||
Bug #6758: Main menu background video can be stopped by opening the options menu
|
||||
Bug #6807: Ultimate Galleon is not working properly
|
||||
Bug #6846: Launcher only works with default config paths
|
||||
Bug #6893: Lua: Inconsistent behavior with actors affected by Disable and SetDelete commands
|
||||
Bug #6894: Added item combines with equipped stack instead of creating a new unequipped stack
|
||||
Bug #6932: Creatures flee from my followers and we have to chase after them
|
||||
@ -56,6 +60,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 +76,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,24 +101,29 @@
|
||||
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
|
||||
Bug #7636: Animations bug out when switching between 1st and 3rd person, while playing a scripted animation
|
||||
Bug #7637: Actors can sometimes move while playing scripted animations
|
||||
Bug #7639: NPCs don't use hand-to-hand if their other melee skills were damaged during combat
|
||||
@ -128,30 +141,51 @@
|
||||
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
|
||||
Bug #7742: Governing attribute training limit should use the modified attribute
|
||||
Bug #7753: Editor: Actors Don't Scale According to Their Race
|
||||
Bug #7758: Water walking is not taken into account to compute path cost on the water
|
||||
Bug #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
|
||||
Bug #7780: Non-ASCII texture paths in NIF files don't work
|
||||
Bug #7785: OpenMW-CS initialising Skill and Attribute fields to 0 instead of -1 on non-FortifyStat spells
|
||||
Bug #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
|
||||
Bug #7943: Using "addSoulGem" and "dropSoulGem" commands to creatures works only with "Weapon & Shield" flagged ones
|
||||
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 #6149: Dehardcode Lua API_REVISION
|
||||
Feature #5926: Refraction based on water depth
|
||||
Feature #5944: Option to use camera as sound listener
|
||||
Feature #6152: Playing music via lua scripts
|
||||
Feature #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
|
||||
@ -164,16 +198,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
|
||||
@ -183,11 +220,20 @@
|
||||
Feature #7652: Sort inactive post processing shaders list properly
|
||||
Feature #7698: Implement sAbsorb, sDamage, sDrain, sFortify and sRestore
|
||||
Feature #7709: Improve resolution selection in Launcher
|
||||
Feature #7777: Support external Bethesda material files (BGSM/BGEM)
|
||||
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
|
||||
Feature #7923: Don't show non-existent higher ranks for factions with fewer than 9 ranks
|
||||
Feature #7932: Support two-channel normal maps
|
||||
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
|
||||
|
@ -22,7 +22,7 @@ declare -a CMAKE_CONF_OPTS=(
|
||||
-DCMAKE_C_COMPILER_LAUNCHER=ccache
|
||||
-DCMAKE_CXX_COMPILER_LAUNCHER=ccache
|
||||
-DCMAKE_INSTALL_PREFIX=install
|
||||
-DBUILD_SHARED_LIBS=OFF
|
||||
-DBUILD_SHARED_LIBS="${BUILD_SHARED_LIBS:-OFF}"
|
||||
-DUSE_SYSTEM_TINYXML=ON
|
||||
-DOPENMW_USE_SYSTEM_RECASTNAVIGATION=ON
|
||||
-DOPENMW_CXX_FLAGS="-Werror -Werror=implicit-fallthrough" # flags specific to OpenMW project
|
||||
|
@ -347,6 +347,26 @@ add_qt_style_dlls() {
|
||||
QT_STYLES[$CONFIG]="${QT_STYLES[$CONFIG]} $@"
|
||||
}
|
||||
|
||||
declare -A QT_IMAGEFORMATS
|
||||
QT_IMAGEFORMATS["Release"]=""
|
||||
QT_IMAGEFORMATS["Debug"]=""
|
||||
QT_IMAGEFORMATS["RelWithDebInfo"]=""
|
||||
add_qt_image_dlls() {
|
||||
local CONFIG=$1
|
||||
shift
|
||||
QT_IMAGEFORMATS[$CONFIG]="${QT_IMAGEFORMATS[$CONFIG]} $@"
|
||||
}
|
||||
|
||||
declare -A QT_ICONENGINES
|
||||
QT_ICONENGINES["Release"]=""
|
||||
QT_ICONENGINES["Debug"]=""
|
||||
QT_ICONENGINES["RelWithDebInfo"]=""
|
||||
add_qt_icon_dlls() {
|
||||
local CONFIG=$1
|
||||
shift
|
||||
QT_ICONENGINES[$CONFIG]="${QT_ICONENGINES[$CONFIG]} $@"
|
||||
}
|
||||
|
||||
if [ -z $PLATFORM ]; then
|
||||
PLATFORM="$(uname -m)"
|
||||
fi
|
||||
@ -528,8 +548,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
|
||||
@ -549,7 +573,7 @@ ICU_VER="70_1"
|
||||
LUAJIT_VER="v2.1.0-beta3-452-g7a0cf5fd"
|
||||
LZ4_VER="1.9.2"
|
||||
OPENAL_VER="1.23.0"
|
||||
QT_VER="5.15.2"
|
||||
QT_VER="6.6.2"
|
||||
|
||||
OSG_ARCHIVE_NAME="OSGoS 3.6.5"
|
||||
OSG_ARCHIVE="OSGoS-3.6.5-123-g68c5c573d-msvc${OSG_MSVC_YEAR}-win${BITS}"
|
||||
@ -880,7 +904,7 @@ printf "Qt ${QT_VER}... "
|
||||
printf "Exists. "
|
||||
elif [ -z $SKIP_EXTRACT ]; then
|
||||
pushd "$DEPS" > /dev/null
|
||||
AQT_VERSION="v3.1.7"
|
||||
AQT_VERSION="v3.1.12"
|
||||
if ! [ -f "aqt_x64-${AQT_VERSION}.exe" ]; then
|
||||
download "aqt ${AQT_VERSION}"\
|
||||
"https://github.com/miurahr/aqtinstall/releases/download/${AQT_VERSION}/aqt_x64.exe" \
|
||||
@ -901,6 +925,9 @@ printf "Qt ${QT_VER}... "
|
||||
echo Done.
|
||||
fi
|
||||
|
||||
QT_MAJOR_VER=$(echo "${QT_VER}" | awk -F '[.]' '{printf "%d", $1}')
|
||||
QT_MINOR_VER=$(echo "${QT_VER}" | awk -F '[.]' '{printf "%d", $2}')
|
||||
|
||||
cd $QT_SDK
|
||||
for CONFIGURATION in ${CONFIGURATIONS[@]}; do
|
||||
if [ $CONFIGURATION == "Debug" ]; then
|
||||
@ -908,13 +935,24 @@ printf "Qt ${QT_VER}... "
|
||||
else
|
||||
DLLSUFFIX=""
|
||||
fi
|
||||
if [ "${QT_VER:0:1}" -eq "6" ]; then
|
||||
add_runtime_dlls $CONFIGURATION "$(pwd)/bin/Qt${QT_VER:0:1}"{Core,Gui,Network,OpenGL,OpenGLWidgets,Widgets}${DLLSUFFIX}.dll
|
||||
|
||||
if [ "${QT_MAJOR_VER}" -eq 6 ]; then
|
||||
add_runtime_dlls $CONFIGURATION "$(pwd)/bin/Qt${QT_MAJOR_VER}"{Core,Gui,Network,OpenGL,OpenGLWidgets,Widgets,Svg}${DLLSUFFIX}.dll
|
||||
|
||||
# Since Qt 6.7.0 plugin is called "qmodernwindowsstyle"
|
||||
if [ "${QT_MINOR_VER}" -ge 7 ]; then
|
||||
add_qt_style_dlls $CONFIGURATION "$(pwd)/plugins/styles/qmodernwindowsstyle${DLLSUFFIX}.dll"
|
||||
else
|
||||
add_qt_style_dlls $CONFIGURATION "$(pwd)/plugins/styles/qwindowsvistastyle${DLLSUFFIX}.dll"
|
||||
fi
|
||||
else
|
||||
add_runtime_dlls $CONFIGURATION "$(pwd)/bin/Qt${QT_VER:0:1}"{Core,Gui,Network,OpenGL,Widgets}${DLLSUFFIX}.dll
|
||||
add_runtime_dlls $CONFIGURATION "$(pwd)/bin/Qt${QT_MAJOR_VER}"{Core,Gui,Network,OpenGL,Widgets,Svg}${DLLSUFFIX}.dll
|
||||
add_qt_style_dlls $CONFIGURATION "$(pwd)/plugins/styles/qwindowsvistastyle${DLLSUFFIX}.dll"
|
||||
fi
|
||||
|
||||
add_qt_platform_dlls $CONFIGURATION "$(pwd)/plugins/platforms/qwindows${DLLSUFFIX}.dll"
|
||||
add_qt_style_dlls $CONFIGURATION "$(pwd)/plugins/styles/qwindowsvistastyle${DLLSUFFIX}.dll"
|
||||
add_qt_image_dlls $CONFIGURATION "$(pwd)/plugins/imageformats/qsvg${DLLSUFFIX}.dll"
|
||||
add_qt_icon_dlls $CONFIGURATION "$(pwd)/plugins/iconengines/qsvgicon${DLLSUFFIX}.dll"
|
||||
done
|
||||
echo Done.
|
||||
}
|
||||
@ -1109,6 +1147,20 @@ fi
|
||||
cp "$DLL" "${DLL_PREFIX}styles"
|
||||
done
|
||||
echo
|
||||
echo "- Qt Image Format DLLs..."
|
||||
mkdir -p ${DLL_PREFIX}imageformats
|
||||
for DLL in ${QT_IMAGEFORMATS[$CONFIGURATION]}; do
|
||||
echo " $(basename $DLL)"
|
||||
cp "$DLL" "${DLL_PREFIX}imageformats"
|
||||
done
|
||||
echo
|
||||
echo "- Qt Icon Engine DLLs..."
|
||||
mkdir -p ${DLL_PREFIX}iconengines
|
||||
for DLL in ${QT_ICONENGINES[$CONFIGURATION]}; do
|
||||
echo " $(basename $DLL)"
|
||||
cp "$DLL" "${DLL_PREFIX}iconengines"
|
||||
done
|
||||
echo
|
||||
done
|
||||
#fi
|
||||
|
||||
|
@ -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
|
||||
|
@ -36,7 +36,7 @@ declare -rA GROUPED_DEPS=(
|
||||
libsdl2-dev libqt5opengl5-dev qttools5-dev qttools5-dev-tools libopenal-dev
|
||||
libunshield-dev libtinyxml-dev libbullet-dev liblz4-dev libpng-dev libjpeg-dev
|
||||
libluajit-5.1-dev librecast-dev libsqlite3-dev ca-certificates libicu-dev
|
||||
libyaml-cpp-dev
|
||||
libyaml-cpp-dev libqt5svg5 libqt5svg5-dev
|
||||
"
|
||||
|
||||
# These dependencies can alternatively be built and linked statically.
|
||||
|
122
CMakeLists.txt
122
CMakeLists.txt
@ -19,6 +19,14 @@ if(OPENMW_GL4ES_MANUAL_INIT)
|
||||
add_definitions(-DOPENMW_GL4ES_MANUAL_INIT)
|
||||
endif()
|
||||
|
||||
if (APPLE OR WIN32)
|
||||
set(DEPLOY_QT_TRANSLATIONS_DEFAULT ON)
|
||||
else ()
|
||||
set(DEPLOY_QT_TRANSLATIONS_DEFAULT OFF)
|
||||
endif ()
|
||||
|
||||
option(DEPLOY_QT_TRANSLATIONS "Deploy standard Qt translations to resources folder. Needed when OpenMW applications are deployed with Qt libraries" ${DEPLOY_QT_TRANSLATIONS_DEFAULT})
|
||||
|
||||
# Apps and tools
|
||||
option(BUILD_OPENMW "Build OpenMW" ON)
|
||||
option(BUILD_LAUNCHER "Build Launcher" ON)
|
||||
@ -36,6 +44,7 @@ option(BUILD_BENCHMARKS "Build benchmarks with Google Benchmark" OFF)
|
||||
option(BUILD_NAVMESHTOOL "Build navmesh tool" ON)
|
||||
option(BUILD_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.
|
||||
|
||||
@ -72,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 53)
|
||||
set(OPENMW_LUA_API_REVISION 59)
|
||||
set(OPENMW_POSTPROCESSING_API_REVISION 1)
|
||||
|
||||
set(OPENMW_VERSION_COMMITHASH "")
|
||||
@ -81,7 +90,7 @@ set(OPENMW_VERSION_COMMITDATE "")
|
||||
|
||||
set(OPENMW_VERSION "${OPENMW_VERSION_MAJOR}.${OPENMW_VERSION_MINOR}.${OPENMW_VERSION_RELEASE}")
|
||||
|
||||
set(OPENMW_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)
|
||||
@ -182,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
|
||||
@ -209,7 +234,7 @@ else()
|
||||
endif(APPLE)
|
||||
|
||||
if (WIN32)
|
||||
option(USE_DEBUG_CONSOLE "whether a debug console should be enabled for debug builds, if false debug output is redirected to Visual Studio output" ON)
|
||||
option(USE_DEBUG_CONSOLE "Whether a console should be displayed if OpenMW isn't launched from the command line. Does not affect the Release configuration." ON)
|
||||
endif()
|
||||
|
||||
if(MSVC)
|
||||
@ -224,9 +249,9 @@ find_package(LZ4 REQUIRED)
|
||||
if (USE_QT)
|
||||
find_package(QT REQUIRED COMPONENTS Core NAMES Qt6 Qt5)
|
||||
if (QT_VERSION_MAJOR VERSION_EQUAL 5)
|
||||
find_package(Qt5 5.15 COMPONENTS Core Widgets Network OpenGL LinguistTools REQUIRED)
|
||||
find_package(Qt5 5.15 COMPONENTS Core Widgets Network OpenGL LinguistTools Svg REQUIRED)
|
||||
else()
|
||||
find_package(Qt6 COMPONENTS Core Widgets Network OpenGL OpenGLWidgets LinguistTools REQUIRED)
|
||||
find_package(Qt6 COMPONENTS Core Widgets Network OpenGL OpenGLWidgets LinguistTools Svg REQUIRED)
|
||||
endif()
|
||||
message(STATUS "Using Qt${QT_VERSION}")
|
||||
endif()
|
||||
@ -685,9 +710,8 @@ if (WIN32)
|
||||
if (USE_DEBUG_CONSOLE AND BUILD_OPENMW)
|
||||
set_target_properties(openmw PROPERTIES LINK_FLAGS_DEBUG "/SUBSYSTEM:CONSOLE")
|
||||
set_target_properties(openmw PROPERTIES LINK_FLAGS_RELWITHDEBINFO "/SUBSYSTEM:CONSOLE")
|
||||
set_target_properties(openmw PROPERTIES COMPILE_DEFINITIONS $<$<CONFIG:Debug>:_CONSOLE>)
|
||||
elseif (BUILD_OPENMW)
|
||||
# Turn off debug console, debug output will be written to visual studio output instead
|
||||
# Turn off implicit console, you won't see stdout unless launching OpenMW from a command line shell or look at openmw.log
|
||||
set_target_properties(openmw PROPERTIES LINK_FLAGS_DEBUG "/SUBSYSTEM:WINDOWS")
|
||||
set_target_properties(openmw PROPERTIES LINK_FLAGS_RELWITHDEBINFO "/SUBSYSTEM:WINDOWS")
|
||||
endif()
|
||||
@ -710,67 +734,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)
|
||||
|
||||
@ -802,6 +825,18 @@ if (OPENMW_OSX_DEPLOYMENT AND APPLE)
|
||||
get_filename_component(QT_QMACSTYLE_PLUGIN_NAME "${QT_QMACSTYLE_PLUGIN_PATH}" NAME)
|
||||
configure_file("${QT_QMACSTYLE_PLUGIN_PATH}" "${APP_BUNDLE_DIR}/Contents/PlugIns/${QT_QMACSTYLE_PLUGIN_GROUP}/${QT_QMACSTYLE_PLUGIN_NAME}" COPYONLY)
|
||||
|
||||
get_property(QT_QSVG_PLUGIN_PATH TARGET Qt${QT_VERSION_MAJOR}::QSvgPlugin PROPERTY LOCATION_RELEASE)
|
||||
get_filename_component(QT_QSVG_PLUGIN_DIR "${QT_QSVG_PLUGIN_PATH}" DIRECTORY)
|
||||
get_filename_component(QT_QSVG_PLUGIN_GROUP "${QT_QSVG_PLUGIN_DIR}" NAME)
|
||||
get_filename_component(QT_QSVG_PLUGIN_NAME "${QT_QSVG_PLUGIN_PATH}" NAME)
|
||||
configure_file("${QT_QSVG_PLUGIN_PATH}" "${APP_BUNDLE_DIR}/Contents/PlugIns/${QT_QSVG_PLUGIN_GROUP}/${QT_QSVG_PLUGIN_NAME}" COPYONLY)
|
||||
|
||||
get_property(QT_QSVG_ICON_PLUGIN_PATH TARGET Qt${QT_VERSION_MAJOR}::QSvgIconPlugin PROPERTY LOCATION_RELEASE)
|
||||
get_filename_component(QT_QSVG_ICON_PLUGIN_DIR "${QT_QSVG_ICON_PLUGIN_PATH}" DIRECTORY)
|
||||
get_filename_component(QT_QSVG_ICON_PLUGIN_GROUP "${QT_QSVG_ICON_PLUGIN_DIR}" NAME)
|
||||
get_filename_component(QT_QSVG_ICON_PLUGIN_NAME "${QT_QSVG_ICON_PLUGIN_PATH}" NAME)
|
||||
configure_file("${QT_QSVG_ICON_PLUGIN_PATH}" "${APP_BUNDLE_DIR}/Contents/PlugIns/${QT_QSVG_ICON_PLUGIN_GROUP}/${QT_QSVG_ICON_PLUGIN_NAME}" COPYONLY)
|
||||
|
||||
configure_file("${OpenMW_SOURCE_DIR}/files/mac/qt.conf" "${APP_BUNDLE_DIR}/Contents/Resources/qt.conf" COPYONLY)
|
||||
|
||||
if (BUILD_OPENCS)
|
||||
@ -809,6 +844,8 @@ if (OPENMW_OSX_DEPLOYMENT AND APPLE)
|
||||
set(OPENCS_BUNDLE_NAME "${OPENCS_BUNDLE_NAME_TMP}.app")
|
||||
configure_file("${QT_COCOA_PLUGIN_PATH}" "${OPENCS_BUNDLE_NAME}/Contents/PlugIns/${QT_COCOA_PLUGIN_GROUP}/${QT_COCOA_PLUGIN_NAME}" COPYONLY)
|
||||
configure_file("${QT_QMACSTYLE_PLUGIN_PATH}" "${OPENCS_BUNDLE_NAME}/Contents/PlugIns/${QT_QMACSTYLE_PLUGIN_GROUP}/${QT_QMACSTYLE_PLUGIN_NAME}" COPYONLY)
|
||||
configure_file("${QT_QSVG_PLUGIN_PATH}" "${OPENCS_BUNDLE_NAME}/Contents/PlugIns/${QT_QSVG_PLUGIN_GROUP}/${QT_QSVG_PLUGIN_NAME}" COPYONLY)
|
||||
configure_file("${QT_QSVG_ICON_PLUGIN_PATH}" "${OPENCS_BUNDLE_NAME}/Contents/PlugIns/${QT_QSVG_ICON_PLUGIN_GROUP}/${QT_QSVG_ICON_PLUGIN_NAME}" COPYONLY)
|
||||
configure_file("${OpenMW_SOURCE_DIR}/files/mac/qt.conf" "${OPENCS_BUNDLE_NAME}/Contents/Resources/qt.conf" COPYONLY)
|
||||
endif ()
|
||||
|
||||
@ -1082,30 +1119,30 @@ 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)
|
||||
|
||||
if (BUILD_LAUNCHER OR BUILD_WIZARD)
|
||||
if (APPLE)
|
||||
set(QT_TRANSLATIONS_PATH "${APP_BUNDLE_DIR}/Contents/Resources/resources/translations")
|
||||
set(QT_OPENMW_TRANSLATIONS_PATH "${APP_BUNDLE_DIR}/Contents/Resources/resources/translations")
|
||||
else ()
|
||||
get_generator_is_multi_config(multi_config)
|
||||
if (multi_config)
|
||||
set(QT_TRANSLATIONS_PATH "${OpenMW_BINARY_DIR}/$<CONFIG>/resources/translations")
|
||||
set(QT_OPENMW_TRANSLATIONS_PATH "${OpenMW_BINARY_DIR}/$<CONFIG>/resources/translations")
|
||||
else ()
|
||||
set(QT_TRANSLATIONS_PATH "${OpenMW_BINARY_DIR}/resources/translations")
|
||||
set(QT_OPENMW_TRANSLATIONS_PATH "${OpenMW_BINARY_DIR}/resources/translations")
|
||||
endif ()
|
||||
endif ()
|
||||
|
||||
@ -1121,9 +1158,30 @@ if (USE_QT)
|
||||
|
||||
qt_add_translation(QM_FILES ${TS_FILES} OPTIONS -silent)
|
||||
|
||||
if (DEPLOY_QT_TRANSLATIONS)
|
||||
# Once we set a Qt 6.2.0 as a minimum required version, we may use "qtpaths --qt-query" instead.
|
||||
get_target_property(QT_QMAKE_EXECUTABLE Qt::qmake IMPORTED_LOCATION)
|
||||
execute_process(COMMAND "${QT_QMAKE_EXECUTABLE}" -query QT_INSTALL_TRANSLATIONS
|
||||
OUTPUT_VARIABLE QT_TRANSLATIONS_DIR OUTPUT_STRIP_TRAILING_WHITESPACE)
|
||||
|
||||
foreach(QM_FILE ${QM_FILES})
|
||||
get_filename_component(QM_BASENAME ${QM_FILE} NAME)
|
||||
string(REGEX REPLACE "[^_]+_(.*)\\.qm" "\\1" LANG_NAME ${QM_BASENAME})
|
||||
if (EXISTS "${QT_TRANSLATIONS_DIR}/qtbase_${LANG_NAME}.qm")
|
||||
set(QM_FILES ${QM_FILES} "${QT_TRANSLATIONS_DIR}/qtbase_${LANG_NAME}.qm")
|
||||
elseif (EXISTS "${QT_TRANSLATIONS_DIR}/qt_${LANG_NAME}.qm")
|
||||
set(QM_FILES ${QM_FILES} "${QT_TRANSLATIONS_DIR}/qt_${LANG_NAME}.qm")
|
||||
else ()
|
||||
message(FATAL_ERROR "Qt translations for '${LANG_NAME}' locale are not found in the '${QT_TRANSLATIONS_DIR}' folder.")
|
||||
endif ()
|
||||
endforeach(QM_FILE)
|
||||
|
||||
list(REMOVE_DUPLICATES QM_FILES)
|
||||
endif ()
|
||||
|
||||
add_custom_target(qm-files
|
||||
COMMAND ${CMAKE_COMMAND} -E make_directory ${QT_TRANSLATIONS_PATH}
|
||||
COMMAND ${CMAKE_COMMAND} -E copy_if_different ${QM_FILES} ${QT_TRANSLATIONS_PATH}
|
||||
COMMAND ${CMAKE_COMMAND} -E make_directory ${QT_OPENMW_TRANSLATIONS_PATH}
|
||||
COMMAND ${CMAKE_COMMAND} -E copy_if_different ${QM_FILES} ${QT_OPENMW_TRANSLATIONS_PATH}
|
||||
DEPENDS ${QM_FILES}
|
||||
COMMENT "Copy *.qm files to resources folder")
|
||||
endif ()
|
||||
|
@ -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>
|
||||
|
@ -12,6 +12,7 @@
|
||||
#include <components/files/multidircollection.hpp>
|
||||
#include <components/misc/strings/conversion.hpp>
|
||||
#include <components/platform/platform.hpp>
|
||||
#include <components/resource/bgsmfilemanager.hpp>
|
||||
#include <components/resource/bulletshape.hpp>
|
||||
#include <components/resource/bulletshapemanager.hpp>
|
||||
#include <components/resource/foreachbulletobject.hpp>
|
||||
@ -146,7 +147,9 @@ namespace
|
||||
dataDirs.insert(dataDirs.begin(), resDir / "vfs");
|
||||
const Files::Collections fileCollections(dataDirs);
|
||||
const auto& archives = variables["fallback-archive"].as<StringsVector>();
|
||||
const auto& contentFiles = variables["content"].as<StringsVector>();
|
||||
StringsVector contentFiles{ "builtin.omwscripts" };
|
||||
const auto& configContentFiles = variables["content"].as<StringsVector>();
|
||||
contentFiles.insert(contentFiles.end(), configContentFiles.begin(), configContentFiles.end());
|
||||
|
||||
Fallback::Map::init(variables["fallback"].as<Fallback::FallbackMap>().mMap);
|
||||
|
||||
@ -171,7 +174,8 @@ namespace
|
||||
constexpr double expiryDelay = 0;
|
||||
Resource::ImageManager imageManager(&vfs, expiryDelay);
|
||||
Resource::NifFileManager nifFileManager(&vfs, &encoder.getStatelessEncoder());
|
||||
Resource::SceneManager sceneManager(&vfs, &imageManager, &nifFileManager, expiryDelay);
|
||||
Resource::BgsmFileManager bgsmFileManager(&vfs, expiryDelay);
|
||||
Resource::SceneManager sceneManager(&vfs, &imageManager, &nifFileManager, &bgsmFileManager, expiryDelay);
|
||||
Resource::BulletShapeManager bulletShapeManager(&vfs, &sceneManager, &nifFileManager, expiryDelay);
|
||||
|
||||
Resource::forEachBulletObject(
|
||||
|
@ -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,7 @@
|
||||
#include "labels.hpp"
|
||||
|
||||
#include <components/esm3/dialoguecondition.hpp>
|
||||
#include <components/esm3/loadalch.hpp>
|
||||
#include <components/esm3/loadbody.hpp>
|
||||
#include <components/esm3/loadcell.hpp>
|
||||
#include <components/esm3/loadcont.hpp>
|
||||
@ -571,13 +573,14 @@ std::string_view enchantTypeLabel(int idx)
|
||||
|
||||
std::string_view ruleFunction(int idx)
|
||||
{
|
||||
if (idx >= 0 && idx <= 72)
|
||||
if (idx >= ESM::DialogueCondition::Function_FacReactionLowest
|
||||
&& idx <= ESM::DialogueCondition::Function_PcWerewolfKills)
|
||||
{
|
||||
static constexpr std::string_view ruleFunctions[] = {
|
||||
"Reaction Low",
|
||||
"Reaction High",
|
||||
"Lowest Faction Reaction",
|
||||
"Highest Faction Reaction",
|
||||
"Rank Requirement",
|
||||
"NPC? Reputation",
|
||||
"NPC Reputation",
|
||||
"Health Percent",
|
||||
"Player Reputation",
|
||||
"NPC Level",
|
||||
@ -647,6 +650,7 @@ std::string_view ruleFunction(int idx)
|
||||
"Flee",
|
||||
"Should Attack",
|
||||
"Werewolf",
|
||||
"Werewolf Kills",
|
||||
};
|
||||
return ruleFunctions[idx];
|
||||
}
|
||||
@ -987,3 +991,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);
|
||||
|
@ -57,112 +57,82 @@ namespace
|
||||
std::cout << " Cell Name: " << p.mCellName << std::endl;
|
||||
}
|
||||
|
||||
std::string ruleString(const ESM::DialInfo::SelectStruct& ss)
|
||||
std::string ruleString(const ESM::DialogueCondition& ss)
|
||||
{
|
||||
std::string rule = ss.mSelectRule;
|
||||
std::string_view type_str = "INVALID";
|
||||
std::string_view func_str;
|
||||
|
||||
if (rule.length() < 5)
|
||||
return "INVALID";
|
||||
|
||||
char type = rule[1];
|
||||
char indicator = rule[2];
|
||||
|
||||
std::string type_str = "INVALID";
|
||||
std::string func_str = Misc::StringUtils::format("INVALID=%s", rule.substr(1, 3));
|
||||
int func = Misc::StringUtils::toNumeric<int>(rule.substr(2, 2), 0);
|
||||
|
||||
switch (type)
|
||||
switch (ss.mFunction)
|
||||
{
|
||||
case '1':
|
||||
type_str = "Function";
|
||||
func_str = std::string(ruleFunction(func));
|
||||
case ESM::DialogueCondition::Function_Global:
|
||||
type_str = "Global";
|
||||
func_str = ss.mVariable;
|
||||
break;
|
||||
case '2':
|
||||
if (indicator == 's')
|
||||
type_str = "Global short";
|
||||
else if (indicator == 'l')
|
||||
type_str = "Global long";
|
||||
else if (indicator == 'f')
|
||||
type_str = "Global float";
|
||||
case ESM::DialogueCondition::Function_Local:
|
||||
type_str = "Local";
|
||||
func_str = ss.mVariable;
|
||||
break;
|
||||
case '3':
|
||||
if (indicator == 's')
|
||||
type_str = "Local short";
|
||||
else if (indicator == 'l')
|
||||
type_str = "Local long";
|
||||
else if (indicator == 'f')
|
||||
type_str = "Local float";
|
||||
case ESM::DialogueCondition::Function_Journal:
|
||||
type_str = "Journal";
|
||||
func_str = ss.mVariable;
|
||||
break;
|
||||
case '4':
|
||||
if (indicator == 'J')
|
||||
type_str = "Journal";
|
||||
case ESM::DialogueCondition::Function_Item:
|
||||
type_str = "Item count";
|
||||
func_str = ss.mVariable;
|
||||
break;
|
||||
case '5':
|
||||
if (indicator == 'I')
|
||||
type_str = "Item type";
|
||||
case ESM::DialogueCondition::Function_Dead:
|
||||
type_str = "Dead";
|
||||
func_str = ss.mVariable;
|
||||
break;
|
||||
case '6':
|
||||
if (indicator == 'D')
|
||||
type_str = "NPC Dead";
|
||||
case ESM::DialogueCondition::Function_NotId:
|
||||
type_str = "Not ID";
|
||||
func_str = ss.mVariable;
|
||||
break;
|
||||
case '7':
|
||||
if (indicator == 'X')
|
||||
type_str = "Not ID";
|
||||
case ESM::DialogueCondition::Function_NotFaction:
|
||||
type_str = "Not Faction";
|
||||
func_str = ss.mVariable;
|
||||
break;
|
||||
case '8':
|
||||
if (indicator == 'F')
|
||||
type_str = "Not Faction";
|
||||
case ESM::DialogueCondition::Function_NotClass:
|
||||
type_str = "Not Class";
|
||||
func_str = ss.mVariable;
|
||||
break;
|
||||
case '9':
|
||||
if (indicator == 'C')
|
||||
type_str = "Not Class";
|
||||
case ESM::DialogueCondition::Function_NotRace:
|
||||
type_str = "Not Race";
|
||||
func_str = ss.mVariable;
|
||||
break;
|
||||
case 'A':
|
||||
if (indicator == 'R')
|
||||
type_str = "Not Race";
|
||||
case ESM::DialogueCondition::Function_NotCell:
|
||||
type_str = "Not Cell";
|
||||
func_str = ss.mVariable;
|
||||
break;
|
||||
case 'B':
|
||||
if (indicator == 'L')
|
||||
type_str = "Not Cell";
|
||||
break;
|
||||
case 'C':
|
||||
if (indicator == 's')
|
||||
type_str = "Not Local";
|
||||
case ESM::DialogueCondition::Function_NotLocal:
|
||||
type_str = "Not Local";
|
||||
func_str = ss.mVariable;
|
||||
break;
|
||||
default:
|
||||
type_str = "Function";
|
||||
func_str = ruleFunction(ss.mFunction);
|
||||
break;
|
||||
}
|
||||
|
||||
// Append the variable name to the function string if any.
|
||||
if (type != '1')
|
||||
func_str = rule.substr(5);
|
||||
|
||||
// In the previous switch, we assumed that the second char was X
|
||||
// for all types not qual to one. If this wasn't true, go back to
|
||||
// the error message.
|
||||
if (type != '1' && rule[3] != 'X')
|
||||
func_str = Misc::StringUtils::format("INVALID=%s", rule.substr(1, 3));
|
||||
|
||||
char oper = rule[4];
|
||||
std::string oper_str = "??";
|
||||
switch (oper)
|
||||
std::string_view oper_str = "??";
|
||||
switch (ss.mComparison)
|
||||
{
|
||||
case '0':
|
||||
case ESM::DialogueCondition::Comp_Eq:
|
||||
oper_str = "==";
|
||||
break;
|
||||
case '1':
|
||||
case ESM::DialogueCondition::Comp_Ne:
|
||||
oper_str = "!=";
|
||||
break;
|
||||
case '2':
|
||||
case ESM::DialogueCondition::Comp_Gt:
|
||||
oper_str = "> ";
|
||||
break;
|
||||
case '3':
|
||||
case ESM::DialogueCondition::Comp_Ge:
|
||||
oper_str = ">=";
|
||||
break;
|
||||
case '4':
|
||||
case ESM::DialogueCondition::Comp_Ls:
|
||||
oper_str = "< ";
|
||||
break;
|
||||
case '5':
|
||||
case ESM::DialogueCondition::Comp_Le:
|
||||
oper_str = "<=";
|
||||
break;
|
||||
default:
|
||||
@ -170,7 +140,7 @@ namespace
|
||||
}
|
||||
|
||||
std::ostringstream stream;
|
||||
stream << ss.mValue;
|
||||
std::visit([&](auto value) { stream << value; }, ss.mValue);
|
||||
|
||||
std::string result
|
||||
= Misc::StringUtils::format("%-12s %-32s %2s %s", type_str, func_str, oper_str, stream.str());
|
||||
@ -180,22 +150,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 +450,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 +583,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;
|
||||
}
|
||||
@ -722,9 +692,6 @@ namespace EsmTool
|
||||
std::cout << " AI Fight:" << (int)mData.mAiData.mFight << std::endl;
|
||||
std::cout << " AI Flee:" << (int)mData.mAiData.mFlee << std::endl;
|
||||
std::cout << " AI Alarm:" << (int)mData.mAiData.mAlarm << std::endl;
|
||||
std::cout << " AI U1:" << (int)mData.mAiData.mU1 << std::endl;
|
||||
std::cout << " AI U2:" << (int)mData.mAiData.mU2 << std::endl;
|
||||
std::cout << " AI U3:" << (int)mData.mAiData.mU3 << std::endl;
|
||||
std::cout << " AI Services:" << Misc::StringUtils::format("0x%08X", mData.mAiData.mServices) << std::endl;
|
||||
|
||||
for (const ESM::AIPackage& package : mData.mAiPackage.mList)
|
||||
@ -843,10 +810,9 @@ 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)
|
||||
for (const auto& rule : mData.mSelects)
|
||||
std::cout << " Select Rule: " << ruleString(rule) << std::endl;
|
||||
|
||||
if (!mData.mResultScript.empty())
|
||||
@ -901,9 +867,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;
|
||||
@ -1115,9 +1078,6 @@ namespace EsmTool
|
||||
std::cout << " AI Fight:" << (int)mData.mAiData.mFight << std::endl;
|
||||
std::cout << " AI Flee:" << (int)mData.mAiData.mFlee << std::endl;
|
||||
std::cout << " AI Alarm:" << (int)mData.mAiData.mAlarm << std::endl;
|
||||
std::cout << " AI U1:" << (int)mData.mAiData.mU1 << std::endl;
|
||||
std::cout << " AI U2:" << (int)mData.mAiData.mU2 << std::endl;
|
||||
std::cout << " AI U3:" << (int)mData.mAiData.mU3 << std::endl;
|
||||
std::cout << " AI Services:" << Misc::StringUtils::format("0x%08X", mData.mAiData.mServices) << std::endl;
|
||||
|
||||
for (const ESM::AIPackage& package : mData.mAiPackage.mList)
|
||||
@ -1144,7 +1104,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);
|
||||
|
@ -83,7 +83,7 @@ target_link_libraries(openmw-launcher
|
||||
components_qt
|
||||
)
|
||||
|
||||
target_link_libraries(openmw-launcher Qt::Widgets Qt::Core)
|
||||
target_link_libraries(openmw-launcher Qt::Widgets Qt::Core Qt::Svg)
|
||||
|
||||
if (BUILD_WITH_CODE_COVERAGE)
|
||||
target_compile_options(openmw-launcher PRIVATE --coverage)
|
||||
@ -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>
|
||||
|
||||
|
@ -142,7 +142,7 @@ Launcher::DataFilesPage::DataFilesPage(const Files::ConfigurationManager& cfg, C
|
||||
ui.setupUi(this);
|
||||
setObjectName("DataFilesPage");
|
||||
mSelector = new ContentSelectorView::ContentSelector(ui.contentSelectorWidget, /*showOMWScripts=*/true);
|
||||
const QString encoding = mGameSettings.value("encoding", "win1252");
|
||||
const QString encoding = mGameSettings.value("encoding", { "win1252" }).value;
|
||||
mSelector->setEncoding(encoding);
|
||||
|
||||
QVector<std::pair<QString, QString>> languages = { { "English", tr("English") }, { "French", tr("French") },
|
||||
@ -163,11 +163,11 @@ Launcher::DataFilesPage::DataFilesPage(const Files::ConfigurationManager& cfg, C
|
||||
connect(ui.directoryInsertButton, &QPushButton::released, this, [this]() { this->addSubdirectories(false); });
|
||||
connect(ui.directoryUpButton, &QPushButton::released, this, [this]() { this->moveDirectory(-1); });
|
||||
connect(ui.directoryDownButton, &QPushButton::released, this, [this]() { this->moveDirectory(1); });
|
||||
connect(ui.directoryRemoveButton, &QPushButton::released, this, [this]() { this->removeDirectory(); });
|
||||
connect(ui.directoryRemoveButton, &QPushButton::released, this, &DataFilesPage::removeDirectory);
|
||||
connect(ui.archiveUpButton, &QPushButton::released, this, [this]() { this->moveArchives(-1); });
|
||||
connect(ui.archiveDownButton, &QPushButton::released, this, [this]() { this->moveArchives(1); });
|
||||
connect(
|
||||
ui.directoryListWidget->model(), &QAbstractItemModel::rowsMoved, this, [this]() { this->sortDirectories(); });
|
||||
connect(ui.directoryListWidget->model(), &QAbstractItemModel::rowsMoved, this, &DataFilesPage::sortDirectories);
|
||||
connect(ui.archiveListWidget->model(), &QAbstractItemModel::rowsMoved, this, &DataFilesPage::sortArchives);
|
||||
|
||||
buildView();
|
||||
loadSettings();
|
||||
@ -271,65 +271,79 @@ void Launcher::DataFilesPage::populateFileViews(const QString& contentModelName)
|
||||
ui.archiveListWidget->clear();
|
||||
ui.directoryListWidget->clear();
|
||||
|
||||
QStringList directories = mLauncherSettings.getDataDirectoryList(contentModelName);
|
||||
if (directories.isEmpty())
|
||||
directories = mGameSettings.getDataDirs();
|
||||
QList<Config::SettingValue> directories = mGameSettings.getDataDirs();
|
||||
QStringList contentModelDirectories = mLauncherSettings.getDataDirectoryList(contentModelName);
|
||||
if (!contentModelDirectories.isEmpty())
|
||||
{
|
||||
directories.erase(std::remove_if(directories.begin(), directories.end(),
|
||||
[&](const Config::SettingValue& dir) { return mGameSettings.isUserSetting(dir); }),
|
||||
directories.end());
|
||||
for (const auto& dir : contentModelDirectories)
|
||||
directories.push_back({ dir });
|
||||
}
|
||||
|
||||
mDataLocal = mGameSettings.getDataLocal();
|
||||
if (!mDataLocal.isEmpty())
|
||||
directories.insert(0, mDataLocal);
|
||||
directories.insert(0, { mDataLocal });
|
||||
|
||||
const auto& globalDataDir = mGameSettings.getGlobalDataDir();
|
||||
if (!globalDataDir.empty())
|
||||
directories.insert(0, Files::pathToQString(globalDataDir));
|
||||
const auto& resourcesVfs = mGameSettings.getResourcesVfs();
|
||||
if (!resourcesVfs.isEmpty())
|
||||
directories.insert(0, { resourcesVfs });
|
||||
|
||||
std::unordered_set<QString> visitedDirectories;
|
||||
for (const QString& currentDir : directories)
|
||||
for (const Config::SettingValue& currentDir : directories)
|
||||
{
|
||||
// normalize user supplied directories: resolve symlink, convert to native separator, make absolute
|
||||
const QString canonicalDirPath = QDir(QDir::cleanPath(currentDir)).canonicalPath();
|
||||
|
||||
if (!visitedDirectories.insert(canonicalDirPath).second)
|
||||
if (!visitedDirectories.insert(currentDir.value).second)
|
||||
continue;
|
||||
|
||||
// add new achives files presents in current directory
|
||||
addArchivesFromDir(currentDir);
|
||||
addArchivesFromDir(currentDir.value);
|
||||
|
||||
QString tooltip;
|
||||
QStringList tooltip;
|
||||
|
||||
// add content files presents in current directory
|
||||
mSelector->addFiles(currentDir, mNewDataDirs.contains(canonicalDirPath));
|
||||
mSelector->addFiles(currentDir.value, mNewDataDirs.contains(currentDir.value));
|
||||
|
||||
// add current directory to list
|
||||
ui.directoryListWidget->addItem(currentDir);
|
||||
ui.directoryListWidget->addItem(currentDir.originalRepresentation);
|
||||
auto row = ui.directoryListWidget->count() - 1;
|
||||
auto* item = ui.directoryListWidget->item(row);
|
||||
item->setData(Qt::UserRole, QVariant::fromValue(currentDir));
|
||||
|
||||
if (currentDir.value != currentDir.originalRepresentation)
|
||||
tooltip << tr("Resolved as %1").arg(currentDir.value);
|
||||
|
||||
// Display new content with custom formatting
|
||||
if (mNewDataDirs.contains(canonicalDirPath))
|
||||
if (mNewDataDirs.contains(currentDir.value))
|
||||
{
|
||||
tooltip += tr("Will be added to the current profile");
|
||||
tooltip << tr("Will be added to the current profile");
|
||||
QFont font = item->font();
|
||||
font.setBold(true);
|
||||
font.setItalic(true);
|
||||
item->setFont(font);
|
||||
}
|
||||
|
||||
// deactivate data-local and global data directory: they are always included
|
||||
if (currentDir == mDataLocal || Files::pathFromQString(currentDir) == globalDataDir)
|
||||
// deactivate data-local and resources/vfs: they are always included
|
||||
// same for ones from non-user config files
|
||||
if (currentDir.value == mDataLocal || currentDir.value == resourcesVfs
|
||||
|| !mGameSettings.isUserSetting(currentDir))
|
||||
{
|
||||
auto flags = item->flags();
|
||||
item->setFlags(flags & ~(Qt::ItemIsDragEnabled | Qt::ItemIsDropEnabled | Qt::ItemIsEnabled));
|
||||
if (currentDir.value == mDataLocal)
|
||||
tooltip << tr("This is the data-local directory and cannot be disabled");
|
||||
else if (currentDir.value == resourcesVfs)
|
||||
tooltip << tr("This directory is part of OpenMW and cannot be disabled");
|
||||
else
|
||||
tooltip << tr("This directory is enabled in an openmw.cfg other than the user one");
|
||||
}
|
||||
|
||||
// Add a "data file" icon if the directory contains a content file
|
||||
if (mSelector->containsDataFiles(currentDir))
|
||||
if (mSelector->containsDataFiles(currentDir.value))
|
||||
{
|
||||
item->setIcon(QIcon(":/images/openmw-plugin.png"));
|
||||
if (!tooltip.isEmpty())
|
||||
tooltip += "\n";
|
||||
|
||||
tooltip += tr("Contains content file(s)");
|
||||
tooltip << tr("Contains content file(s)");
|
||||
}
|
||||
else
|
||||
{
|
||||
@ -339,19 +353,26 @@ void Launcher::DataFilesPage::populateFileViews(const QString& contentModelName)
|
||||
auto emptyIcon = QIcon(pixmap);
|
||||
item->setIcon(emptyIcon);
|
||||
}
|
||||
item->setToolTip(tooltip);
|
||||
item->setToolTip(tooltip.join('\n'));
|
||||
}
|
||||
mSelector->sortFiles();
|
||||
|
||||
QStringList selectedArchives = mLauncherSettings.getArchiveList(contentModelName);
|
||||
if (selectedArchives.isEmpty())
|
||||
selectedArchives = mGameSettings.getArchiveList();
|
||||
QList<Config::SettingValue> selectedArchives = mGameSettings.getArchiveList();
|
||||
QStringList contentModelSelectedArchives = mLauncherSettings.getArchiveList(contentModelName);
|
||||
if (contentModelSelectedArchives.isEmpty())
|
||||
{
|
||||
selectedArchives.erase(std::remove_if(selectedArchives.begin(), selectedArchives.end(),
|
||||
[&](const Config::SettingValue& dir) { return mGameSettings.isUserSetting(dir); }),
|
||||
selectedArchives.end());
|
||||
for (const auto& dir : contentModelSelectedArchives)
|
||||
selectedArchives.push_back({ dir });
|
||||
}
|
||||
|
||||
// sort and tick BSA according to profile
|
||||
int row = 0;
|
||||
for (const auto& archive : selectedArchives)
|
||||
{
|
||||
const auto match = ui.archiveListWidget->findItems(archive, Qt::MatchExactly);
|
||||
const auto match = ui.archiveListWidget->findItems(archive.value, Qt::MatchExactly);
|
||||
if (match.isEmpty())
|
||||
continue;
|
||||
const auto name = match[0]->text();
|
||||
@ -359,9 +380,25 @@ void Launcher::DataFilesPage::populateFileViews(const QString& contentModelName)
|
||||
ui.archiveListWidget->takeItem(oldrow);
|
||||
ui.archiveListWidget->insertItem(row, name);
|
||||
ui.archiveListWidget->item(row)->setCheckState(Qt::Checked);
|
||||
ui.archiveListWidget->item(row)->setData(Qt::UserRole, QVariant::fromValue(archive));
|
||||
if (!mGameSettings.isUserSetting(archive))
|
||||
{
|
||||
auto flags = ui.archiveListWidget->item(row)->flags();
|
||||
ui.archiveListWidget->item(row)->setFlags(
|
||||
flags & ~(Qt::ItemIsDragEnabled | Qt::ItemIsDropEnabled | Qt::ItemIsEnabled));
|
||||
ui.archiveListWidget->item(row)->setToolTip(
|
||||
tr("This archive is enabled in an openmw.cfg other than the user one"));
|
||||
}
|
||||
row++;
|
||||
}
|
||||
|
||||
QStringList nonUserContent;
|
||||
for (const auto& content : mGameSettings.getContentList())
|
||||
{
|
||||
if (!mGameSettings.isUserSetting(content))
|
||||
nonUserContent.push_back(content.value);
|
||||
}
|
||||
mSelector->setNonUserContent(nonUserContent);
|
||||
mSelector->setProfileContent(mLauncherSettings.getContentListFiles(contentModelName));
|
||||
}
|
||||
|
||||
@ -389,7 +426,19 @@ void Launcher::DataFilesPage::saveSettings(const QString& profile)
|
||||
{
|
||||
fileNames.append(item->fileName());
|
||||
}
|
||||
mLauncherSettings.setContentList(profileName, dirList, selectedArchivePaths(), fileNames);
|
||||
QStringList dirNames;
|
||||
for (const auto& dir : dirList)
|
||||
{
|
||||
if (mGameSettings.isUserSetting(dir))
|
||||
dirNames.push_back(dir.originalRepresentation);
|
||||
}
|
||||
QStringList archiveNames;
|
||||
for (const auto& archive : selectedArchivePaths())
|
||||
{
|
||||
if (mGameSettings.isUserSetting(archive))
|
||||
archiveNames.push_back(archive.originalRepresentation);
|
||||
}
|
||||
mLauncherSettings.setContentList(profileName, dirNames, archiveNames, fileNames);
|
||||
mGameSettings.setContentList(dirList, selectedArchivePaths(), fileNames);
|
||||
|
||||
QString language(mSelector->languageBox()->currentData().toString());
|
||||
@ -398,38 +447,38 @@ void Launcher::DataFilesPage::saveSettings(const QString& profile)
|
||||
|
||||
if (language == QLatin1String("Polish"))
|
||||
{
|
||||
mGameSettings.setValue(QLatin1String("encoding"), QLatin1String("win1250"));
|
||||
mGameSettings.setValue(QLatin1String("encoding"), { "win1250" });
|
||||
}
|
||||
else if (language == QLatin1String("Russian"))
|
||||
{
|
||||
mGameSettings.setValue(QLatin1String("encoding"), QLatin1String("win1251"));
|
||||
mGameSettings.setValue(QLatin1String("encoding"), { "win1251" });
|
||||
}
|
||||
else
|
||||
{
|
||||
mGameSettings.setValue(QLatin1String("encoding"), QLatin1String("win1252"));
|
||||
mGameSettings.setValue(QLatin1String("encoding"), { "win1252" });
|
||||
}
|
||||
}
|
||||
|
||||
QStringList Launcher::DataFilesPage::selectedDirectoriesPaths() const
|
||||
QList<Config::SettingValue> Launcher::DataFilesPage::selectedDirectoriesPaths() const
|
||||
{
|
||||
QStringList dirList;
|
||||
QList<Config::SettingValue> dirList;
|
||||
for (int i = 0; i < ui.directoryListWidget->count(); ++i)
|
||||
{
|
||||
const QListWidgetItem* item = ui.directoryListWidget->item(i);
|
||||
if (item->flags() & Qt::ItemIsEnabled)
|
||||
dirList.append(item->text());
|
||||
dirList.append(qvariant_cast<Config::SettingValue>(item->data(Qt::UserRole)));
|
||||
}
|
||||
return dirList;
|
||||
}
|
||||
|
||||
QStringList Launcher::DataFilesPage::selectedArchivePaths() const
|
||||
QList<Config::SettingValue> Launcher::DataFilesPage::selectedArchivePaths() const
|
||||
{
|
||||
QStringList archiveList;
|
||||
QList<Config::SettingValue> archiveList;
|
||||
for (int i = 0; i < ui.archiveListWidget->count(); ++i)
|
||||
{
|
||||
const QListWidgetItem* item = ui.archiveListWidget->item(i);
|
||||
if (item->checkState() == Qt::Checked)
|
||||
archiveList.append(item->text());
|
||||
archiveList.append(qvariant_cast<Config::SettingValue>(item->data(Qt::UserRole)));
|
||||
}
|
||||
return archiveList;
|
||||
}
|
||||
@ -583,7 +632,20 @@ void Launcher::DataFilesPage::on_cloneProfileAction_triggered()
|
||||
if (profile.isEmpty())
|
||||
return;
|
||||
|
||||
mLauncherSettings.setContentList(profile, selectedDirectoriesPaths(), selectedArchivePaths(), selectedFilePaths());
|
||||
const auto& dirList = selectedDirectoriesPaths();
|
||||
QStringList dirNames;
|
||||
for (const auto& dir : dirList)
|
||||
{
|
||||
if (mGameSettings.isUserSetting(dir))
|
||||
dirNames.push_back(dir.originalRepresentation);
|
||||
}
|
||||
QStringList archiveNames;
|
||||
for (const auto& archive : selectedArchivePaths())
|
||||
{
|
||||
if (mGameSettings.isUserSetting(archive))
|
||||
archiveNames.push_back(archive.originalRepresentation);
|
||||
}
|
||||
mLauncherSettings.setContentList(profile, dirNames, archiveNames, selectedFilePaths());
|
||||
addProfile(profile, true);
|
||||
}
|
||||
|
||||
@ -650,6 +712,9 @@ void Launcher::DataFilesPage::addSubdirectories(bool append)
|
||||
if (!ui.directoryListWidget->findItems(rootPath, Qt::MatchFixedString).isEmpty())
|
||||
return;
|
||||
ui.directoryListWidget->addItem(rootPath);
|
||||
auto row = ui.directoryListWidget->count() - 1;
|
||||
auto* item = ui.directoryListWidget->item(row);
|
||||
item->setData(Qt::UserRole, QVariant::fromValue(Config::SettingValue{ rootPath }));
|
||||
mNewDataDirs.push_back(rootPath);
|
||||
refreshDataFilesView();
|
||||
return;
|
||||
@ -679,8 +744,11 @@ void Launcher::DataFilesPage::addSubdirectories(bool append)
|
||||
const auto* dir = select.dirListWidget->item(i);
|
||||
if (dir->checkState() == Qt::Checked)
|
||||
{
|
||||
ui.directoryListWidget->insertItem(selectedRow++, dir->text());
|
||||
ui.directoryListWidget->insertItem(selectedRow, dir->text());
|
||||
auto* item = ui.directoryListWidget->item(selectedRow);
|
||||
item->setData(Qt::UserRole, QVariant::fromValue(Config::SettingValue{ dir->text() }));
|
||||
mNewDataDirs.push_back(dir->text());
|
||||
++selectedRow;
|
||||
}
|
||||
}
|
||||
|
||||
@ -702,6 +770,21 @@ void Launcher::DataFilesPage::sortDirectories()
|
||||
}
|
||||
}
|
||||
|
||||
void Launcher::DataFilesPage::sortArchives()
|
||||
{
|
||||
// Ensure disabled entries (aka ones from non-user config files) are always at the top.
|
||||
for (auto i = 1; i < ui.archiveListWidget->count(); ++i)
|
||||
{
|
||||
if (!(ui.archiveListWidget->item(i)->flags() & Qt::ItemIsEnabled)
|
||||
&& (ui.archiveListWidget->item(i - 1)->flags() & Qt::ItemIsEnabled))
|
||||
{
|
||||
const auto item = ui.archiveListWidget->takeItem(i);
|
||||
ui.archiveListWidget->insertItem(i - 1, item);
|
||||
ui.archiveListWidget->setCurrentRow(i);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void Launcher::DataFilesPage::moveDirectory(int step)
|
||||
{
|
||||
int selectedRow = ui.directoryListWidget->currentRow();
|
||||
@ -784,9 +867,8 @@ bool Launcher::DataFilesPage::moveArchive(QListWidgetItem* listItem, int step)
|
||||
if (selectedRow == -1 || newRow < 0 || newRow > ui.archiveListWidget->count() - 1)
|
||||
return false;
|
||||
|
||||
const QListWidgetItem* item = ui.archiveListWidget->takeItem(selectedRow);
|
||||
|
||||
addArchive(item->text(), item->checkState(), newRow);
|
||||
QListWidgetItem* item = ui.archiveListWidget->takeItem(selectedRow);
|
||||
ui.archiveListWidget->insertItem(newRow, item);
|
||||
ui.archiveListWidget->setCurrentRow(newRow);
|
||||
return true;
|
||||
}
|
||||
@ -797,6 +879,7 @@ void Launcher::DataFilesPage::addArchive(const QString& name, Qt::CheckState sel
|
||||
row = ui.archiveListWidget->count();
|
||||
ui.archiveListWidget->insertItem(row, name);
|
||||
ui.archiveListWidget->item(row)->setCheckState(selected);
|
||||
ui.archiveListWidget->item(row)->setData(Qt::UserRole, QVariant::fromValue(Config::SettingValue{ name }));
|
||||
if (mKnownArchives.filter(name).isEmpty()) // XXX why contains doesn't work here ???
|
||||
{
|
||||
auto item = ui.archiveListWidget->item(row);
|
||||
@ -819,7 +902,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();
|
||||
|
@ -25,6 +25,7 @@ namespace ContentSelectorView
|
||||
namespace Config
|
||||
{
|
||||
class GameSettings;
|
||||
struct SettingValue;
|
||||
class LauncherSettings;
|
||||
}
|
||||
|
||||
@ -73,6 +74,7 @@ namespace Launcher
|
||||
void updateCloneProfileOkButton(const QString& text);
|
||||
void addSubdirectories(bool append);
|
||||
void sortDirectories();
|
||||
void sortArchives();
|
||||
void removeDirectory();
|
||||
void moveArchives(int step);
|
||||
void moveDirectory(int step);
|
||||
@ -146,8 +148,8 @@ namespace Launcher
|
||||
* @return the file paths of all selected content files
|
||||
*/
|
||||
QStringList selectedFilePaths() const;
|
||||
QStringList selectedArchivePaths() const;
|
||||
QStringList selectedDirectoriesPaths() const;
|
||||
QList<Config::SettingValue> selectedArchivePaths() const;
|
||||
QList<Config::SettingValue> selectedDirectoriesPaths() const;
|
||||
};
|
||||
}
|
||||
#endif
|
||||
|
@ -37,9 +37,9 @@ Launcher::ImportPage::ImportPage(const Files::ConfigurationManager& cfg, Config:
|
||||
// Detect Morrowind configuration files
|
||||
QStringList iniPaths;
|
||||
|
||||
for (const QString& path : mGameSettings.getDataDirs())
|
||||
for (const auto& path : mGameSettings.getDataDirs())
|
||||
{
|
||||
QDir dir(path);
|
||||
QDir dir(path.value);
|
||||
dir.setPath(dir.canonicalPath()); // Resolve symlinks
|
||||
|
||||
if (dir.exists(QString("Morrowind.ini")))
|
||||
@ -125,7 +125,7 @@ void Launcher::ImportPage::on_importerButton_clicked()
|
||||
arguments.append(QString("--fonts"));
|
||||
|
||||
arguments.append(QString("--encoding"));
|
||||
arguments.append(mGameSettings.value(QString("encoding"), QString("win1252")));
|
||||
arguments.append(mGameSettings.value(QString("encoding"), { "win1252" }).value);
|
||||
arguments.append(QString("--ini"));
|
||||
arguments.append(settingsComboBox->currentText());
|
||||
arguments.append(QString("--cfg"));
|
||||
|
@ -1,7 +1,6 @@
|
||||
#include <iostream>
|
||||
|
||||
#include <QDir>
|
||||
#include <QTranslator>
|
||||
|
||||
#include <boost/program_options/options_description.hpp>
|
||||
#include <boost/program_options/variables_map.hpp>
|
||||
@ -9,6 +8,7 @@
|
||||
#include <components/debug/debugging.hpp>
|
||||
#include <components/files/configurationmanager.hpp>
|
||||
#include <components/files/qtconversion.hpp>
|
||||
#include <components/l10n/qttranslations.hpp>
|
||||
#include <components/platform/platform.hpp>
|
||||
|
||||
#ifdef MAC_OS_X_VERSION_MIN_REQUIRED
|
||||
@ -41,16 +41,7 @@ int runLauncher(int argc, char* argv[])
|
||||
resourcesPath = Files::pathToQString(variables["resources"].as<Files::MaybeQuotedPath>().u8string());
|
||||
}
|
||||
|
||||
// Internationalization
|
||||
QString locale = QLocale::system().name().section('_', 0, 0);
|
||||
|
||||
QTranslator appTranslator;
|
||||
appTranslator.load(resourcesPath + "/translations/launcher_" + locale + ".qm");
|
||||
app.installTranslator(&appTranslator);
|
||||
|
||||
QTranslator componentsAppTranslator;
|
||||
componentsAppTranslator.load(resourcesPath + "/translations/components_" + locale + ".qm");
|
||||
app.installTranslator(&componentsAppTranslator);
|
||||
l10n::installQtTranslations(app, "launcher", resourcesPath);
|
||||
|
||||
Launcher::MainDialog mainWin(configurationManager);
|
||||
|
||||
|
@ -292,7 +292,7 @@ bool Launcher::MainDialog::setupLauncherSettings()
|
||||
if (!QFile::exists(path))
|
||||
return true;
|
||||
|
||||
Log(Debug::Verbose) << "Loading config file: " << path.toUtf8().constData();
|
||||
Log(Debug::Info) << "Loading config file: " << path.toUtf8().constData();
|
||||
|
||||
QFile file(path);
|
||||
if (!file.open(QIODevice::ReadOnly | QIODevice::Text))
|
||||
@ -320,7 +320,7 @@ bool Launcher::MainDialog::setupGameSettings()
|
||||
|
||||
QFile file;
|
||||
|
||||
auto loadFile = [&](const QString& path, bool (Config::GameSettings::*reader)(QTextStream&, bool),
|
||||
auto loadFile = [&](const QString& path, bool (Config::GameSettings::*reader)(QTextStream&, const QString&, bool),
|
||||
bool ignoreContent = false) -> std::optional<bool> {
|
||||
file.setFileName(path);
|
||||
if (file.exists())
|
||||
@ -337,7 +337,7 @@ bool Launcher::MainDialog::setupGameSettings()
|
||||
QTextStream stream(&file);
|
||||
Misc::ensureUtf8Encoding(stream);
|
||||
|
||||
(mGameSettings.*reader)(stream, ignoreContent);
|
||||
(mGameSettings.*reader)(stream, QFileInfo(path).dir().path(), ignoreContent);
|
||||
file.close();
|
||||
return true;
|
||||
}
|
||||
@ -349,29 +349,24 @@ bool Launcher::MainDialog::setupGameSettings()
|
||||
if (!loadFile(Files::getUserConfigPathQString(mCfgMgr), &Config::GameSettings::readUserFile))
|
||||
return false;
|
||||
|
||||
// Now the rest - priority: user > local > global
|
||||
if (auto result = loadFile(Files::getLocalConfigPathQString(mCfgMgr), &Config::GameSettings::readFile, true))
|
||||
for (const auto& path : Files::getActiveConfigPathsQString(mCfgMgr))
|
||||
{
|
||||
// Load global if local wasn't found
|
||||
if (!*result && !loadFile(Files::getGlobalConfigPathQString(mCfgMgr), &Config::GameSettings::readFile, true))
|
||||
Log(Debug::Info) << "Loading config file: " << path.toUtf8().constData();
|
||||
if (!loadFile(path, &Config::GameSettings::readFile))
|
||||
return false;
|
||||
}
|
||||
else
|
||||
return false;
|
||||
if (!loadFile(Files::getUserConfigPathQString(mCfgMgr), &Config::GameSettings::readFile))
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool Launcher::MainDialog::setupGameData()
|
||||
{
|
||||
QStringList dataDirs;
|
||||
bool foundData = false;
|
||||
|
||||
// Check if the paths actually contain data files
|
||||
for (const QString& path3 : mGameSettings.getDataDirs())
|
||||
for (const auto& path3 : mGameSettings.getDataDirs())
|
||||
{
|
||||
QDir dir(path3);
|
||||
QDir dir(path3.value);
|
||||
QStringList filters;
|
||||
filters << "*.esp"
|
||||
<< "*.esm"
|
||||
@ -379,10 +374,13 @@ bool Launcher::MainDialog::setupGameData()
|
||||
<< "*.omwaddon";
|
||||
|
||||
if (!dir.entryList(filters).isEmpty())
|
||||
dataDirs.append(path3);
|
||||
{
|
||||
foundData = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (dataDirs.isEmpty())
|
||||
if (!foundData)
|
||||
{
|
||||
QMessageBox msgBox;
|
||||
msgBox.setWindowTitle(tr("Error detecting Morrowind installation"));
|
||||
|
@ -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);
|
||||
|
||||
@ -295,6 +302,7 @@ bool Launcher::SettingsPage::loadSettings()
|
||||
hrtfProfileSelectorComboBox->setCurrentIndex(hrtfProfileIndex);
|
||||
}
|
||||
}
|
||||
loadSettingBool(Settings::sound().mCameraListener, *cameraListenerCheckBox);
|
||||
}
|
||||
|
||||
// Interface Changes
|
||||
@ -338,7 +346,7 @@ bool Launcher::SettingsPage::loadSettings()
|
||||
{
|
||||
loadSettingBool(Settings::input().mGrabCursor, *grabCursorCheckBox);
|
||||
|
||||
bool skipMenu = mGameSettings.value("skip-menu").toInt() == 1;
|
||||
bool skipMenu = mGameSettings.value("skip-menu").value.toInt() == 1;
|
||||
if (skipMenu)
|
||||
{
|
||||
skipMenuCheckBox->setCheckState(Qt::Checked);
|
||||
@ -346,8 +354,8 @@ bool Launcher::SettingsPage::loadSettings()
|
||||
startDefaultCharacterAtLabel->setEnabled(skipMenu);
|
||||
startDefaultCharacterAtField->setEnabled(skipMenu);
|
||||
|
||||
startDefaultCharacterAtField->setText(mGameSettings.value("start"));
|
||||
runScriptAfterStartupField->setText(mGameSettings.value("script-run"));
|
||||
startDefaultCharacterAtField->setText(mGameSettings.value("start").value);
|
||||
runScriptAfterStartupField->setText(mGameSettings.value("script-run").value);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
@ -492,6 +500,9 @@ void Launcher::SettingsPage::saveSettings()
|
||||
Settings::sound().mHrtf.set(hrtfProfileSelectorComboBox->currentText().toStdString());
|
||||
else
|
||||
Settings::sound().mHrtf.set({});
|
||||
|
||||
const bool cCameraListener = cameraListenerCheckBox->checkState() != Qt::Unchecked;
|
||||
Settings::sound().mCameraListener.set(cCameraListener);
|
||||
}
|
||||
|
||||
// Interface Changes
|
||||
@ -532,17 +543,17 @@ void Launcher::SettingsPage::saveSettings()
|
||||
saveSettingBool(*grabCursorCheckBox, Settings::input().mGrabCursor);
|
||||
|
||||
int skipMenu = skipMenuCheckBox->checkState() == Qt::Checked;
|
||||
if (skipMenu != mGameSettings.value("skip-menu").toInt())
|
||||
mGameSettings.setValue("skip-menu", QString::number(skipMenu));
|
||||
if (skipMenu != mGameSettings.value("skip-menu").value.toInt())
|
||||
mGameSettings.setValue("skip-menu", { QString::number(skipMenu) });
|
||||
|
||||
QString startCell = startDefaultCharacterAtField->text();
|
||||
if (startCell != mGameSettings.value("start"))
|
||||
if (startCell != mGameSettings.value("start").value)
|
||||
{
|
||||
mGameSettings.setValue("start", startCell);
|
||||
mGameSettings.setValue("start", { startCell });
|
||||
}
|
||||
QString scriptRun = runScriptAfterStartupField->text();
|
||||
if (scriptRun != mGameSettings.value("script-run"))
|
||||
mGameSettings.setValue("script-run", scriptRun);
|
||||
if (scriptRun != mGameSettings.value("script-run").value)
|
||||
mGameSettings.setValue("script-run", { scriptRun });
|
||||
}
|
||||
}
|
||||
|
||||
@ -581,9 +592,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:
|
||||
|
@ -36,7 +36,7 @@
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string><html><head/><body><p>note: content files that are not part of current Content List are <span style=" font-style:italic;font-weight: bold">highlighted</span></p></body></html></string>
|
||||
<string><html><head/><body><p>Note: content files that are not part of current Content List are <span style=" font-style:italic;font-weight: bold">highlighted</span></p></body></html></string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
@ -160,7 +160,7 @@
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string><html><head/><body><p>note: directories that are not part of current Content List are <span style=" font-style:italic;font-weight: bold">highlighted</span></p></body></html></string>
|
||||
<string><html><head/><body><p>Note: directories that are not part of current Content List are <span style=" font-style:italic;font-weight: bold">highlighted</span></p></body></html></string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
@ -251,7 +251,7 @@
|
||||
<item row="1" column="0" colspan="2">
|
||||
<widget class="QLabel" name="archiveNoteLabel">
|
||||
<property name="text">
|
||||
<string><html><head/><body><p>note: archives that are not part of current Content List are <span style=" font-style:italic;font-weight: bold">highlighted</span></p></body></html></string>
|
||||
<string><html><head/><body><p>Note: archives that are not part of current Content List are <span style=" font-style:italic;font-weight: bold">highlighted</span></p></body></html></string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
@ -305,7 +305,7 @@
|
||||
<item>
|
||||
<widget class="QCheckBox" name="navMeshRemoveUnusedTilesCheckBox">
|
||||
<property name="text">
|
||||
<string>Remove unused tiles</string>
|
||||
<string>Remove Unused Tiles</string>
|
||||
</property>
|
||||
<property name="checked">
|
||||
<bool>true</bool>
|
||||
@ -317,7 +317,7 @@
|
||||
<item>
|
||||
<widget class="QLabel" name="navMeshMaxSizeLabel">
|
||||
<property name="text">
|
||||
<string>Max size</string>
|
||||
<string>Max Size</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
|
@ -26,7 +26,7 @@
|
||||
<item row="3" column="0">
|
||||
<widget class="QLabel" name="windowModeLabel">
|
||||
<property name="text">
|
||||
<string>Window mode</string>
|
||||
<string>Window Mode</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
@ -111,14 +111,14 @@
|
||||
<item row="1" column="0">
|
||||
<widget class="QCheckBox" name="framerateLimitCheckBox">
|
||||
<property name="text">
|
||||
<string>Framerate limit</string>
|
||||
<string>Framerate Limit</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="0" column="0">
|
||||
<widget class="QCheckBox" name="windowBorderCheckBox">
|
||||
<property name="text">
|
||||
<string>Window border</string>
|
||||
<string>Window Border</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
@ -207,14 +207,14 @@
|
||||
<item row="4" column="0">
|
||||
<widget class="QLabel" name="antiAliasingLabel">
|
||||
<property name="text">
|
||||
<string>Anti-aliasing</string>
|
||||
<string>Anti-Aliasing</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="2" column="0">
|
||||
<widget class="QLabel" name="vSyncLabel">
|
||||
<property name="text">
|
||||
<string>Vertical synchronization</string>
|
||||
<string>Vertical Synchronization</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
|
@ -54,7 +54,7 @@
|
||||
<item row="0" column="0">
|
||||
<widget class="QLabel" name="importerLabel">
|
||||
<property name="text">
|
||||
<string>File to import settings from:</string>
|
||||
<string>File to Import Settings From:</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
@ -73,7 +73,7 @@
|
||||
<item>
|
||||
<widget class="QCheckBox" name="addonsCheckBox">
|
||||
<property name="text">
|
||||
<string>Import add-on and plugin selection (creates a new Content List)</string>
|
||||
<string>Import Add-on and Plugin Selection</string>
|
||||
</property>
|
||||
<property name="checked">
|
||||
<bool>true</bool>
|
||||
@ -88,7 +88,7 @@ so OpenMW provides another set of fonts to avoid these issues. These fonts use T
|
||||
to default Morrowind fonts. Check this box if you still prefer original fonts over OpenMW ones or if you use custom bitmap fonts.</string>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Import bitmap fonts setup</string>
|
||||
<string>Import Bitmap Fonts</string>
|
||||
</property>
|
||||
<property name="checked">
|
||||
<bool>true</bool>
|
||||
|
@ -39,7 +39,7 @@
|
||||
<string><html><head/><body><p>Give actors an ability to swim over the water surface when they follow other actor independently from their ability to swim. Has effect only when nav mesh building is enabled.</p></body></html></string>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Always allow actors to follow over water</string>
|
||||
<string>Always Allow Actors to Follow over Water</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
@ -49,7 +49,7 @@
|
||||
<string><html><head/><body><p>Make disposition change of merchants caused by trading permanent.</p></body></html></string>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Permanent barter disposition changes</string>
|
||||
<string>Permanent Barter Disposition Changes</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
@ -59,7 +59,7 @@
|
||||
<string><html><head/><body><p>Don't use race weight in NPC movement speed calculations.</p></body></html></string>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Racial variation in speed fix</string>
|
||||
<string>Racial Variation in Speed Fix</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
@ -69,7 +69,7 @@
|
||||
<string><html><head/><body><p>Stops combat with NPCs affected by Calm spells every frame -- like in Morrowind without the MCP.</p></body></html></string>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Classic Calm spells behavior</string>
|
||||
<string>Classic Calm Spells Behavior</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
@ -79,7 +79,7 @@
|
||||
<string><html><head/><body><p>If enabled NPCs apply evasion maneuver to avoid collisions with others.</p></body></html></string>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>NPCs avoid collisions</string>
|
||||
<string>NPCs Avoid Collisions</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
@ -89,7 +89,7 @@
|
||||
<string><html><head/><body><p>Make the value of filled soul gems dependent only on soul magnitude.</p></body></html></string>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Soulgem values rebalance</string>
|
||||
<string>Soulgem Values Rebalance</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
@ -99,7 +99,7 @@
|
||||
<string><html><head/><body><p>If this setting is true, supporting models will make use of day night switch nodes.</p></body></html></string>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Day night switch nodes</string>
|
||||
<string>Day Night Switch Nodes</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
@ -109,7 +109,7 @@
|
||||
<string><html><head/><body><p>Make player followers and escorters start combat with enemies who have started combat with them or the player. Otherwise they wait for the enemies or the player to do an attack first.</p></body></html></string>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Followers defend immediately</string>
|
||||
<string>Followers Defend Immediately</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
@ -119,7 +119,7 @@
|
||||
<string><html><head/><body><p><a name="docs-internal-guid-f375b85a-7fff-02ff-a5af-c5cff63923c0"/>When enabled, a navigation mesh is built in the background for world geometry to be used for pathfinding. When disabled only the path grid is used to build paths. Single-core CPU systems may have a big performance impact on existing interior location and moving across the exterior world. May slightly affect performance on multi-core CPU systems. Multi-core CPU systems may have different latency for nav mesh update depending on other settings and system performance. Moving across external world, entering/exiting location produce nav mesh update. NPC and creatures may not be able to find path before nav mesh is built around them. Try to disable this if you want to have old fashioned AI which doesn't know where to go when you stand behind that stone and cast a firebolt.</p></body></html></string>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Use navigation mesh for pathfinding</string>
|
||||
<string>Use Navigation Mesh for Pathfinding</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
@ -129,7 +129,7 @@
|
||||
<string><html><head/><body><p>If enabled, a magical ammunition is required to bypass normal weapon resistance or weakness. If disabled, a magical ranged weapon or a magical ammunition is required.</p></body></html></string>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Only magical ammo bypass resistance</string>
|
||||
<string>Only Magical Ammo Bypass Resistance</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
@ -139,7 +139,7 @@
|
||||
<string><html><head/><body><p>If this setting is true, containers supporting graphic herbalism will do so instead of opening the menu.</p></body></html></string>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Graphic herbalism</string>
|
||||
<string>Graphic Herbalism</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
@ -149,7 +149,7 @@
|
||||
<string><html><head/><body><p>Makes player swim a bit upward from the line of sight. Applies only in third person mode. Intended to make simpler swimming without diving.</p></body></html></string>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Swim upward correction</string>
|
||||
<string>Swim Upward Correction</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
@ -159,7 +159,7 @@
|
||||
<string><html><head/><body><p>Make enchanted weapons without Magical flag bypass normal weapons resistance, like in Morrowind.</p></body></html></string>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Enchanted weapons are magical</string>
|
||||
<string>Enchanted Weapons Are Magical</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
@ -169,7 +169,7 @@
|
||||
<string><html><head/><body><p>Prevents merchants from equipping items that are sold to them.</p></body></html></string>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Merchant equipping fix</string>
|
||||
<string>Merchant Equipping Fix</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
@ -179,7 +179,7 @@
|
||||
<string><html><head/><body><p>Trainers now only choose which skills to train using their base skill points, allowing mercantile improving effects to be used without making mercantile an offered skill.</p></body></html></string>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Trainers choose offered skills by base value</string>
|
||||
<string>Trainers Choose Offered Skills by Base Value</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
@ -189,7 +189,7 @@
|
||||
<string><html><head/><body><p>If this setting is true, the player is allowed to loot actors (e.g. summoned creatures) during death animation, if they are not in combat. In this case we have to increment death counter and run disposed actor's script instantly.</p><p>If this setting is false, player has to wait until end of death animation in all cases. Makes using of summoned creatures exploit (looting summoned Dremoras and Golden Saints for expensive weapons) a lot harder. Conflicts with mannequin mods, which use SkipAnim to prevent end of death animation.</p></body></html></string>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Can loot during death animation</string>
|
||||
<string>Can Loot During Death Animation</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
@ -199,7 +199,7 @@
|
||||
<string><html><head/><body><p>Make stealing items from NPCs that were knocked down possible during combat.</p></body></html></string>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Steal from knocked out actors in combat</string>
|
||||
<string>Steal from Knocked out Actors in Combat</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
@ -209,7 +209,7 @@
|
||||
<string><html><head/><body><p>Effects of reflected Absorb spells are not mirrored - like in Morrowind.</p></body></html></string>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Classic reflected Absorb spells behavior</string>
|
||||
<string>Classic Reflected Absorb Spells Behavior</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
@ -219,7 +219,7 @@
|
||||
<string><html><head/><body><p>Makes unarmed creature attacks able to reduce armor condition, just as attacks from NPCs and armed creatures.</p></body></html></string>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Unarmed creature attacks damage armor</string>
|
||||
<string>Unarmed Creature Attacks Damage Armor</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
@ -230,7 +230,7 @@
|
||||
<item row="0" column="0">
|
||||
<widget class="QLabel" name="unarmedFactorsStrengthLabel">
|
||||
<property name="text">
|
||||
<string>Factor strength into hand-to-hand combat</string>
|
||||
<string>Factor Strength into Hand-to-Hand Combat</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
@ -246,12 +246,12 @@
|
||||
</item>
|
||||
<item>
|
||||
<property name="text">
|
||||
<string>Affect werewolves</string>
|
||||
<string>Affect Werewolves</string>
|
||||
</property>
|
||||
</item>
|
||||
<item>
|
||||
<property name="text">
|
||||
<string>Do not affect werewolves</string>
|
||||
<string>Do Not Affect Werewolves</string>
|
||||
</property>
|
||||
</item>
|
||||
</widget>
|
||||
@ -262,7 +262,7 @@
|
||||
<string><html><head/><body><p>How many threads will be spawned to compute physics update in the background. A value of 0 means that the update will be performed in the main thread.</p><p>A value greater than 1 requires the Bullet library be compiled with multithreading support.</p></body></html></string>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Background physics threads</string>
|
||||
<string>Background Physics Threads</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
@ -272,7 +272,7 @@
|
||||
<item row="2" column="0">
|
||||
<widget class="QLabel" name="labelActorCollisionShapeType">
|
||||
<property name="text">
|
||||
<string>Actor collision shape type</string>
|
||||
<string>Actor Collision Shape Type</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
@ -282,16 +282,16 @@
|
||||
<string>Collision is used for both physics simulation and navigation mesh generation for pathfinding. Cylinder gives the best consistency between available navigation paths and ability to move by them. Changing this value affects navigation mesh generation therefore navigation mesh disk cache generated for one value will not be useful with another.</string>
|
||||
</property>
|
||||
<property name="currentText">
|
||||
<string>Axis-aligned bounding box</string>
|
||||
<string>Axis-Aligned Bounding Box</string>
|
||||
</property>
|
||||
<item>
|
||||
<property name="text">
|
||||
<string>Axis-aligned bounding box</string>
|
||||
<string>Axis-Aligned Bounding Box</string>
|
||||
</property>
|
||||
</item>
|
||||
<item>
|
||||
<property name="text">
|
||||
<string>Rotating box</string>
|
||||
<string>Rotating Box</string>
|
||||
</property>
|
||||
</item>
|
||||
<item>
|
||||
@ -343,7 +343,7 @@
|
||||
<string><html><head/><body><p>Makes NPCs and player movement more smooth. Recommended to use with "turn to movement direction" enabled.</p></body></html></string>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Smooth movement</string>
|
||||
<string>Smooth Movement</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
@ -353,7 +353,7 @@
|
||||
<string><html><head/><body><p>Load per-group KF-files and skeleton files from Animations folder</p></body></html></string>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Use additional animation sources</string>
|
||||
<string>Use Additional Animation Sources</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
@ -376,7 +376,7 @@
|
||||
<string><html><head/><body><p>Affects side and diagonal movement. Enabling this setting makes movement more realistic.</p><p>If disabled then the whole character's body is pointed to the direction of view. Diagonal movement has no special animation and causes sliding.</p><p>If enabled then the character turns lower body to the direction of movement. Upper body is turned partially. Head is always pointed to the direction of view. In combat mode it works only for diagonal movement. In non-combat mode it changes straight right and straight left movement as well. Also turns the whole body up or down when swimming according to the movement direction.</p></body></html></string>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Turn to movement direction</string>
|
||||
<string>Turn to Movement Direction</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
@ -389,7 +389,7 @@
|
||||
<string><html><head/><body><p>Render holstered weapons (with quivers and scabbards), requires modded assets.</p></body></html></string>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Weapon sheathing</string>
|
||||
<string>Weapon Sheathing</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
@ -402,7 +402,7 @@
|
||||
<string><html><head/><body><p>Render holstered shield, requires modded assets.</p></body></html></string>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Shield sheathing</string>
|
||||
<string>Shield Sheathing</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
@ -412,7 +412,7 @@
|
||||
<string><html><head/><body><p>In third person, the camera will sway along with the movement animations of the player. Enabling this option disables this swaying by having the player character move independently of its animation. This was the default behavior of OpenMW 0.48 and earlier.</p></body></html></string>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Player movement ignores animation</string>
|
||||
<string>Player Movement Ignores Animation</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
@ -422,7 +422,7 @@
|
||||
<string><html><head/><body><p>Use casting animations for magic items, just as for spells.</p></body></html></string>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Use magic item animation</string>
|
||||
<string>Use Magic Item Animation</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
@ -447,7 +447,7 @@
|
||||
If this option is disabled, normal maps are only used if they are explicitly listed within the mesh file (.nif or .osg file). Affects objects.</p></body></html></string>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Auto use object normal maps</string>
|
||||
<string>Auto Use Object Normal Maps</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
@ -457,7 +457,7 @@
|
||||
<string><html><head/><body><p>Enables soft particles for particle effects. This technique softens the intersection between individual particles and other opaque geometry by blending between them.</p></body></html></string>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Soft particles</string>
|
||||
<string>Soft Particles</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
@ -471,7 +471,7 @@
|
||||
(.osg file, not supported in .nif files). Affects objects.</p></body></html></string>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Auto use object specular maps</string>
|
||||
<string>Auto Use Object Specular Maps</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
@ -481,7 +481,7 @@
|
||||
<string><html><head/><body><p>See 'auto use object normal maps'. Affects terrain.</p></body></html></string>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Auto use terrain normal maps</string>
|
||||
<string>Auto Use Terrain Normal Maps</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
@ -504,7 +504,7 @@
|
||||
<string><html><head/><body><p>If a file with pattern 'terrain specular map pattern' exists, use that file as a 'diffuse specular' map. The texture must contain the layer colour in the RGB channel (as usual), and a specular multiplier in the alpha channel.</p></body></html></string>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Auto use terrain specular maps</string>
|
||||
<string>Auto Use Terrain Specular Maps</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
@ -514,7 +514,7 @@
|
||||
<string><html><head/><body><p>Simulate coverage-preserving mipmaps to prevent alpha-tested meshes shrinking as they get further away. Will cause meshes whose textures have coverage-preserving mipmaps to grow, though, so refer to mod installation instructions for how to set this.</p></body></html></string>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Adjust coverage for alpha test</string>
|
||||
<string>Adjust Coverage for Alpha Test</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
@ -524,7 +524,7 @@
|
||||
<string><html><head/><body><p>Allows MSAA to work with alpha-tested meshes, producing better-looking edges without pixelation. Can negatively impact performance.</p></body></html></string>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Use anti-alias alpha testing</string>
|
||||
<string>Use Anti-Aliased Alpha Testing</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
@ -537,7 +537,7 @@
|
||||
</p></body></html></string>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Bump/reflect map local lighting</string>
|
||||
<string>Bump/Reflect Map Local Lighting</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
@ -547,7 +547,7 @@
|
||||
<string><html><head/><body><p>EXPERIMENTAL: Stop rain and snow from falling through overhangs and roofs.</p></body></html></string>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Weather particle occlusion</string>
|
||||
<string>Weather Particle Occlusion</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
@ -570,7 +570,7 @@
|
||||
<string><html><head/><body><p>Use exponential fog formula. By default, linear fog is used.</p></body></html></string>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Exponential fog</string>
|
||||
<string>Exponential Fog</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
@ -613,7 +613,7 @@
|
||||
This setting makes the fog use the actual eye point distance (or so called Euclidean distance) to calculate the fog, which makes the fog look less artificial, especially if you have a wide FOV.</p></body></html></string>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Radial fog</string>
|
||||
<string>Radial Fog</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
@ -626,7 +626,7 @@
|
||||
<string><html><head/><body><p>The fraction of the maximum distance at which blending with the sky starts.</p></body></html></string>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Sky blending start</string>
|
||||
<string>Sky Blending Start</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
@ -636,7 +636,7 @@
|
||||
<string><html><head/><body><p>Reduce visibility of clipping plane by blending objects with the sky.</p></body></html></string>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Sky blending</string>
|
||||
<string>Sky Blending</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
@ -652,59 +652,16 @@
|
||||
<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="suffix">
|
||||
<string> cells</string>
|
||||
</property>
|
||||
<property name="minimum">
|
||||
<double>0.000000000000000</double>
|
||||
</property>
|
||||
<property name="singleStep">
|
||||
<double>0.500000000000000</double>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="6" column="1">
|
||||
<spacer name="verticalSpacer_15">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Vertical</enum>
|
||||
</property>
|
||||
<property name="sizeHint" stdset="0">
|
||||
<size>
|
||||
<width>20</width>
|
||||
<height>40</height>
|
||||
</size>
|
||||
</property>
|
||||
</spacer>
|
||||
</item>
|
||||
<item row="3" column="0">
|
||||
<widget class="QLabel" name="objectPagingMinSizeLabel">
|
||||
<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>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Object paging min size</string>
|
||||
<string>Object Paging Min Size</string>
|
||||
</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>
|
||||
@ -720,13 +677,59 @@
|
||||
</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>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Active grid object paging</string>
|
||||
<string>Active Grid Object Paging</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
@ -741,16 +744,22 @@
|
||||
<layout class="QHBoxLayout" name="horizontalPostProcessLayout">
|
||||
<item>
|
||||
<layout class="QGridLayout" name="postProcessLayout" columnstretch="0,0">
|
||||
<item row="5" column="0">
|
||||
<widget class="QLabel" name="postprocessHDRTimeLabel">
|
||||
<item row="5" column="1">
|
||||
<widget class="QDoubleSpinBox" name="postprocessHDRTimeComboBox">
|
||||
<property name="enabled">
|
||||
<bool>false</bool>
|
||||
</property>
|
||||
<property name="toolTip">
|
||||
<string><html><head/><body><p>Controls how much eye adaptation can change from frame to frame. Smaller values makes for slower transitions.</p></body></html></string>
|
||||
<property name="decimals">
|
||||
<number>3</number>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Auto exposure speed</string>
|
||||
<property name="minimum">
|
||||
<double>0.010000000000000</double>
|
||||
</property>
|
||||
<property name="maximum">
|
||||
<double>10.000000000000000</double>
|
||||
</property>
|
||||
<property name="singleStep">
|
||||
<double>0.001000000000000</double>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
@ -776,26 +785,20 @@
|
||||
<string><html><head/><body><p>Re-render transparent objects with forced alpha clipping.</p></body></html></string>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Transparent postpass</string>
|
||||
<string>Transparent Postpass</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="5" column="1">
|
||||
<widget class="QDoubleSpinBox" name="postprocessHDRTimeComboBox">
|
||||
<item row="5" column="0">
|
||||
<widget class="QLabel" name="postprocessHDRTimeLabel">
|
||||
<property name="enabled">
|
||||
<bool>false</bool>
|
||||
</property>
|
||||
<property name="decimals">
|
||||
<number>3</number>
|
||||
<property name="toolTip">
|
||||
<string><html><head/><body><p>Controls how much eye adaptation can change from frame to frame. Smaller values makes for slower transitions.</p></body></html></string>
|
||||
</property>
|
||||
<property name="minimum">
|
||||
<double>0.010000000000000</double>
|
||||
</property>
|
||||
<property name="maximum">
|
||||
<double>10.000000000000000</double>
|
||||
</property>
|
||||
<property name="singleStep">
|
||||
<double>0.001000000000000</double>
|
||||
<property name="text">
|
||||
<string>Auto Exposure Speed</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
@ -805,7 +808,7 @@
|
||||
<string><html><head/><body><p>If this setting is true, post processing will be enabled.</p></body></html></string>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Enable post processing</string>
|
||||
<string>Enable Post Processing</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
@ -824,17 +827,17 @@
|
||||
<widget class="QComboBox" name="shadowComputeSceneBoundsComboBox">
|
||||
<item>
|
||||
<property name="text">
|
||||
<string>bounds</string>
|
||||
<string>Bounds</string>
|
||||
</property>
|
||||
</item>
|
||||
<item>
|
||||
<property name="text">
|
||||
<string>primitives</string>
|
||||
<string>Primitives</string>
|
||||
</property>
|
||||
</item>
|
||||
<item>
|
||||
<property name="text">
|
||||
<string>none</string>
|
||||
<string>None</string>
|
||||
</property>
|
||||
</item>
|
||||
</widget>
|
||||
@ -845,7 +848,7 @@
|
||||
<string><html><head/><body><p>Type of "compute scene bounds" computation method to be used. Bounds (default) for good balance between performance and shadow quality, primitives for better looking shadows or none for no computation.</p></body></html></string>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Shadow planes computation method</string>
|
||||
<string>Shadow Planes Computation Method</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
@ -866,6 +869,9 @@
|
||||
<property name="maximum">
|
||||
<number>81920</number>
|
||||
</property>
|
||||
<property name="singleStep">
|
||||
<number>128</number>
|
||||
</property>
|
||||
<property name="value">
|
||||
<number>8192</number>
|
||||
</property>
|
||||
@ -877,7 +883,7 @@
|
||||
<string><html><head/><body><p>Enable shadows for NPCs and creatures besides the player character. May have a minor performance impact.</p></body></html></string>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Enable actor shadows</string>
|
||||
<string>Enable Actor Shadows</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
@ -911,7 +917,7 @@
|
||||
<string><html><head/><body><p>The fraction of the limit above at which shadows begin to gradually fade away.</p></body></html></string>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Fade start multiplier</string>
|
||||
<string>Fade Start Multiplier</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
@ -921,7 +927,7 @@
|
||||
<string><html><head/><body><p>Enable shadows exclusively for the player character. May have a very minor performance impact.</p></body></html></string>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Enable player shadows</string>
|
||||
<string>Enable Player Shadows</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
@ -931,7 +937,7 @@
|
||||
<string><html><head/><body><p>The resolution of each individual shadow map. Increasing it significantly improves shadow quality but may have a minor performance impact.</p></body></html></string>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Shadow map resolution</string>
|
||||
<string>Shadow Map Resolution</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
@ -941,7 +947,7 @@
|
||||
<string><html><head/><body><p>The distance from the camera at which shadows completely disappear.</p></body></html></string>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Shadow distance limit:</string>
|
||||
<string>Shadow Distance Limit:</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
@ -951,7 +957,7 @@
|
||||
<string><html><head/><body><p>Enable shadows for primarily inanimate objects. May have a significant performance impact.</p></body></html></string>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Enable object shadows</string>
|
||||
<string>Enable Object Shadows</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
@ -969,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>
|
||||
@ -993,7 +1002,7 @@
|
||||
<string><html><head/><body><p>Due to limitations with Morrowind's data, only actors can cast shadows indoors, which some might feel is distracting.</p><p>Has no effect if actor/player shadows are not enabled.</p></body></html></string>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Enable indoor shadows</string>
|
||||
<string>Enable Indoor Shadows</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
@ -1003,7 +1012,7 @@
|
||||
<string><html><head/><body><p>Enable shadows for the terrain including distant terrain. May have a significant performance and shadow quality impact.</p></body></html></string>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Enable terrain shadows</string>
|
||||
<string>Enable Terrain Shadows</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
@ -1024,7 +1033,7 @@
|
||||
<string><html><head/><body><p>Maximum distance at which lights will appear (measured in units).</p><p>Set this to 0 to use an unlimited distance.</p></body></html></string>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Lights maximum distance</string>
|
||||
<string>Maximum Light Distance</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
@ -1047,7 +1056,7 @@
|
||||
<string><html><head/><body><p>Maximum number of lights per object.</p><p>A low number near default will cause light popping similar to what you would see with legacy lighting.</p></body></html></string>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Max light sources</string>
|
||||
<string>Max Lights</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
@ -1057,7 +1066,7 @@
|
||||
<string><html><head/><body><p>Fraction of maximum distance at which lights will start to fade.</p><p>Set this to a low value for slower transitions or a high value for quicker transitions.</p></body></html></string>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Lights fade multiplier</string>
|
||||
<string>Fade Start Multiplier</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
@ -1070,7 +1079,7 @@
|
||||
<p> "Shaders" carries all of the benefits that "Shaders (compatibility)" does, but uses a modern approach that allows for a higher max lights count with little to no performance penalties on modern hardware.</p></body></html></string>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Lighting method</string>
|
||||
<string>Lighting Method</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
@ -1099,7 +1108,7 @@
|
||||
<string><html><head/><body><p>Multipler for bounding sphere of lights.</p><p>Higher numbers allows for smooth falloff but require an increase in number of max lights.</p><p>Does not effect the illumination or strength of lights.</p></body></html></string>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Lights bounding sphere multiplier</string>
|
||||
<string>Bounding Sphere Multiplier</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
@ -1119,7 +1128,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>
|
||||
@ -1214,7 +1223,7 @@
|
||||
<string>Select your preferred audio device.</string>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Audio device</string>
|
||||
<string>Audio Device</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
@ -1300,7 +1309,7 @@
|
||||
<string>Select your preferred HRTF profile.</string>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>HRTF profile</string>
|
||||
<string>HRTF Profile</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
@ -1330,6 +1339,16 @@
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QCheckBox" name="cameraListenerCheckBox">
|
||||
<property name="toolTip">
|
||||
<string>In third-person view, use the camera as the sound listener instead of the player character.</string>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Use the Camera as the Sound Listener</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<spacer>
|
||||
<property name="orientation">
|
||||
@ -1374,7 +1393,7 @@
|
||||
</item>
|
||||
<item>
|
||||
<property name="text">
|
||||
<string>Tooltip and crosshair</string>
|
||||
<string>Tooltip and Crosshair</string>
|
||||
</property>
|
||||
</item>
|
||||
</widget>
|
||||
@ -1420,7 +1439,7 @@
|
||||
<string><html><head/><body><p>This setting scales GUI windows. A value of 1.0 results in the normal scale.</p></body></html></string>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>GUI scaling factor</string>
|
||||
<string>GUI Scaling Factor</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
@ -1430,7 +1449,7 @@
|
||||
<string><html><head/><body><p>Show the remaining duration of magic effects and lights if this setting is true. The remaining duration is displayed in the tooltip by hovering over the magical effect. </p><p>The default value is false.</p></body></html></string>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Show effect duration</string>
|
||||
<string>Show Effect Duration</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
@ -1440,7 +1459,7 @@
|
||||
<string><html><head/><body><p>If this setting is true, dialogue topics will have a different color if the topic is specific to the NPC you're talking to or the topic was previously seen. Color can be changed in settings.cfg.</p><p>The default value is false.</p></body></html></string>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Change dialogue topic color</string>
|
||||
<string>Change Dialogue Topic Color</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
@ -1450,7 +1469,7 @@
|
||||
<string>Size of characters in game texts.</string>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Font size</string>
|
||||
<string>Font Size</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
@ -1460,7 +1479,7 @@
|
||||
<string><html><head/><body><p>Enable zooming on local and global maps.</p></body></html></string>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Can zoom on maps</string>
|
||||
<string>Can Zoom on Maps</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
@ -1470,7 +1489,7 @@
|
||||
<string><html><head/><body><p>If this setting is true, damage bonus of arrows and bolts will be shown on item tooltip.</p><p>The default value is false.</p></body></html></string>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Show projectile damage</string>
|
||||
<string>Show Projectile Damage</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
@ -1480,7 +1499,7 @@
|
||||
<string><html><head/><body><p>If this setting is true, melee weapons reach and speed will be shown on item tooltip.</p><p>The default value is false.</p></body></html></string>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Show melee info</string>
|
||||
<string>Show Melee Info</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
@ -1490,14 +1509,14 @@
|
||||
<string><html><head/><body><p>Stretch menus, load screens, etc. to the window aspect ratio.</p></body></html></string>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Stretch menu background</string>
|
||||
<string>Stretch Menu Background</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="0" column="0">
|
||||
<widget class="QLabel" name="showOwnedLabel">
|
||||
<property name="text">
|
||||
<string>Show owned objects</string>
|
||||
<string>Show Owned Objects</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
@ -1507,7 +1526,7 @@
|
||||
<string><html><head/><body><p>Whether or not the chance of success will be displayed in the enchanting menu.</p><p>The default value is false.</p></body></html></string>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Show enchant chance</string>
|
||||
<string>Show Enchant Chance</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
@ -1545,7 +1564,7 @@
|
||||
<string><html><head/><body><p>This setting determines whether the amount of the time the player has spent playing will be displayed for each saved game in the Load menu.</p></body></html></string>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Add "Time Played" to saves</string>
|
||||
<string>Add "Time Played" to Saves</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
@ -1554,7 +1573,7 @@
|
||||
<item>
|
||||
<widget class="QLabel" name="maximumQuicksavesLabel">
|
||||
<property name="text">
|
||||
<string>Maximum quicksaves</string>
|
||||
<string>Maximum Quicksaves</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
@ -1581,7 +1600,7 @@
|
||||
<item>
|
||||
<widget class="QLabel" name="screenshotFormatLabel">
|
||||
<property name="text">
|
||||
<string>Screenshot format</string>
|
||||
<string>Screenshot Format</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
@ -1609,7 +1628,7 @@
|
||||
<item>
|
||||
<widget class="QCheckBox" name="notifyOnSavedScreenshotCheckBox">
|
||||
<property name="text">
|
||||
<string>Notify on saved screenshot</string>
|
||||
<string>Notify on Saved Screenshot</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
@ -1659,14 +1678,14 @@
|
||||
<string><html><head/><body><p>OpenMW will capture control of the cursor if this setting is true.</p><p>In “look mode”, OpenMW will center the cursor regardless of the value of this setting (since the cursor/crosshair is always centered in the OpenMW window). However, in GUI mode, this setting determines the behavior when the cursor is moved outside the OpenMW window. If true, the cursor movement stops at the edge of the window preventing access to other applications. If false, the cursor is allowed to move freely on the desktop.</p><p>This setting does not apply to the screen where escape has been pressed, where the cursor is never captured. Regardless of this setting “Alt-Tab” or some other operating system dependent key sequence can be used to allow the operating system to regain control of the mouse cursor. This setting interacts with the minimize on focus loss setting by affecting what counts as a focus loss. Specifically on a two-screen configuration it may be more convenient to access the second screen with setting disabled.</p><p>Note for developers: it’s desirable to have this setting disabled when running the game in a debugger, to prevent the mouse cursor from becoming unusable when the game pauses on a breakpoint.</p></body></html></string>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Grab cursor</string>
|
||||
<string>Grab Cursor</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QCheckBox" name="skipMenuCheckBox">
|
||||
<property name="text">
|
||||
<string>Skip menu and generate default character</string>
|
||||
<string>Skip Menu and Generate Default Character</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
@ -1691,14 +1710,14 @@
|
||||
<item>
|
||||
<widget class="QLabel" name="startDefaultCharacterAtLabel">
|
||||
<property name="text">
|
||||
<string>Start default character at</string>
|
||||
<string>Start Default Character at</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QLineEdit" name="startDefaultCharacterAtField">
|
||||
<property name="placeholderText">
|
||||
<string>default cell</string>
|
||||
<string>Default Cell</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
@ -1707,7 +1726,7 @@
|
||||
<item>
|
||||
<widget class="QLabel" name="label">
|
||||
<property name="text">
|
||||
<string>Run script after startup:</string>
|
||||
<string>Run Script After Startup:</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
|
@ -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>
|
||||
|
@ -19,6 +19,7 @@
|
||||
#include <components/files/conversion.hpp>
|
||||
#include <components/files/multidircollection.hpp>
|
||||
#include <components/platform/platform.hpp>
|
||||
#include <components/resource/bgsmfilemanager.hpp>
|
||||
#include <components/resource/bulletshapemanager.hpp>
|
||||
#include <components/resource/imagemanager.hpp>
|
||||
#include <components/resource/niffilemanager.hpp>
|
||||
@ -165,7 +166,9 @@ namespace NavMeshTool
|
||||
dataDirs.insert(dataDirs.begin(), resDir / "vfs");
|
||||
const Files::Collections fileCollections(dataDirs);
|
||||
const auto& archives = variables["fallback-archive"].as<StringsVector>();
|
||||
const auto& contentFiles = variables["content"].as<StringsVector>();
|
||||
StringsVector contentFiles{ "builtin.omwscripts" };
|
||||
const auto& configContentFiles = variables["content"].as<StringsVector>();
|
||||
contentFiles.insert(contentFiles.end(), configContentFiles.begin(), configContentFiles.end());
|
||||
const std::size_t threadsNumber = variables["threads"].as<std::size_t>();
|
||||
|
||||
if (threadsNumber < 1)
|
||||
@ -218,7 +221,8 @@ namespace NavMeshTool
|
||||
|
||||
Resource::ImageManager imageManager(&vfs, expiryDelay);
|
||||
Resource::NifFileManager nifFileManager(&vfs, &encoder.getStatelessEncoder());
|
||||
Resource::SceneManager sceneManager(&vfs, &imageManager, &nifFileManager, expiryDelay);
|
||||
Resource::BgsmFileManager bgsmFileManager(&vfs, expiryDelay);
|
||||
Resource::SceneManager sceneManager(&vfs, &imageManager, &nifFileManager, &bgsmFileManager, expiryDelay);
|
||||
Resource::BulletShapeManager bulletShapeManager(&vfs, &sceneManager, &nifFileManager, expiryDelay);
|
||||
DetourNavigator::RecastGlobalAllocator::init();
|
||||
DetourNavigator::Settings navigatorSettings = DetourNavigator::makeSettingsFromSettingsManager();
|
||||
|
@ -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()
|
||||
|
@ -8,6 +8,7 @@
|
||||
#include <utility>
|
||||
#include <vector>
|
||||
|
||||
#include <components/bgsm/file.hpp>
|
||||
#include <components/files/configurationmanager.hpp>
|
||||
#include <components/files/constrainedfilestream.hpp>
|
||||
#include <components/files/conversion.hpp>
|
||||
@ -25,7 +26,7 @@
|
||||
namespace bpo = boost::program_options;
|
||||
|
||||
/// See if the file has the named extension
|
||||
bool hasExtension(const std::filesystem::path& filename, const std::string& extensionToFind)
|
||||
bool hasExtension(const std::filesystem::path& filename, std::string_view extensionToFind)
|
||||
{
|
||||
const auto extension = Files::pathToUnicodeString(filename.extension());
|
||||
return Misc::StringUtils::ciEqual(extension, extensionToFind);
|
||||
@ -36,63 +37,62 @@ bool isNIF(const std::filesystem::path& filename)
|
||||
{
|
||||
return hasExtension(filename, ".nif") || hasExtension(filename, ".kf");
|
||||
}
|
||||
|
||||
/// Check if the file is a material file.
|
||||
bool isMaterial(const std::filesystem::path& filename)
|
||||
{
|
||||
return hasExtension(filename, ".bgem") || hasExtension(filename, ".bgsm");
|
||||
}
|
||||
|
||||
/// See if the file has the "bsa" extension.
|
||||
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;
|
||||
}
|
||||
|
||||
void readNIF(
|
||||
void readFile(
|
||||
const std::filesystem::path& source, const std::filesystem::path& path, const VFS::Manager* vfs, bool quiet)
|
||||
{
|
||||
const std::string pathStr = Files::pathToUnicodeString(path);
|
||||
const bool isNif = isNIF(path);
|
||||
if (!quiet)
|
||||
{
|
||||
if (hasExtension(path, ".kf"))
|
||||
std::cout << "Reading KF file '" << pathStr << "'";
|
||||
if (isNif)
|
||||
std::cout << "Reading " << (hasExtension(path, ".nif") ? "NIF" : "KF") << " file '" << pathStr << "'";
|
||||
else
|
||||
std::cout << "Reading NIF file '" << pathStr << "'";
|
||||
std::cout << "Reading " << (hasExtension(path, ".bgsm") ? "BGSM" : "BGEM") << " file '" << pathStr << "'";
|
||||
if (!source.empty())
|
||||
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::Reader reader(file, nullptr);
|
||||
if (vfs != nullptr)
|
||||
reader.parse(vfs->get(pathStr));
|
||||
if (isNif)
|
||||
{
|
||||
Nif::NIFFile file(Files::pathToUnicodeString(fullPath));
|
||||
Nif::Reader reader(file, nullptr);
|
||||
if (vfs != nullptr)
|
||||
reader.parse(vfs->get(pathStr));
|
||||
else
|
||||
reader.parse(Files::openConstrainedFileStream(fullPath));
|
||||
}
|
||||
else
|
||||
reader.parse(Files::openConstrainedFileStream(fullPath));
|
||||
{
|
||||
if (vfs != nullptr)
|
||||
Bgsm::parse(vfs->get(pathStr));
|
||||
else
|
||||
Bgsm::parse(Files::openConstrainedFileStream(fullPath));
|
||||
}
|
||||
}
|
||||
catch (std::exception& e)
|
||||
{
|
||||
@ -114,27 +114,33 @@ void readVFS(std::unique_ptr<VFS::Archive>&& archive, const std::filesystem::pat
|
||||
vfs.addArchive(std::move(archive));
|
||||
vfs.buildIndex();
|
||||
|
||||
for (const auto& name : vfs.getRecursiveDirectoryIterator(""))
|
||||
for (const auto& name : vfs.getRecursiveDirectoryIterator())
|
||||
{
|
||||
if (isNIF(name.value()))
|
||||
if (isNIF(name.value()) || isMaterial(name.value()))
|
||||
{
|
||||
readNIF(archivePath, name.value(), &vfs, quiet);
|
||||
readFile(archivePath, name.value(), &vfs, quiet);
|
||||
}
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -142,10 +148,10 @@ void readVFS(std::unique_ptr<VFS::Archive>&& archive, const std::filesystem::pat
|
||||
bool parseOptions(int argc, char** argv, Files::PathContainer& files, Files::PathContainer& archives,
|
||||
bool& writeDebugLog, bool& quiet)
|
||||
{
|
||||
bpo::options_description desc(R"(Ensure that OpenMW can use the provided NIF, KF and BSA/BA2 files
|
||||
bpo::options_description desc(R"(Ensure that OpenMW can use the provided NIF, KF, BGEM/BGSM and BSA/BA2 files
|
||||
|
||||
Usages:
|
||||
niftest <nif files, kf files, BSA/BA2 files, or directories>
|
||||
niftest <nif files, kf files, bgem/bgsm files, BSA/BA2 files, or directories>
|
||||
Scan the file or directories for NIF errors.
|
||||
|
||||
Allowed options)");
|
||||
@ -234,9 +240,9 @@ int main(int argc, char** argv)
|
||||
const std::string pathStr = Files::pathToUnicodeString(path);
|
||||
try
|
||||
{
|
||||
if (isNIF(path))
|
||||
if (isNIF(path) || isMaterial(path))
|
||||
{
|
||||
readNIF({}, path, vfs.get(), quiet);
|
||||
readFile({}, path, vfs.get(), quiet);
|
||||
}
|
||||
else if (auto archive = makeArchive(path))
|
||||
{
|
||||
@ -244,7 +250,7 @@ int main(int argc, char** argv)
|
||||
}
|
||||
else
|
||||
{
|
||||
std::cerr << "Error: '" << pathStr << "' is not a NIF/KF file, BSA/BA2 archive, or directory"
|
||||
std::cerr << "Error: '" << pathStr << "' is not a NIF/KF/BGEM/BGSM file, BSA/BA2 archive, or directory"
|
||||
<< std::endl;
|
||||
}
|
||||
}
|
||||
|
@ -172,7 +172,7 @@ else()
|
||||
set (OPENCS_OPENMW_CFG "")
|
||||
endif(APPLE)
|
||||
|
||||
add_library(openmw-cs-lib
|
||||
add_library(openmw-cs-lib STATIC
|
||||
${OPENCS_SRC}
|
||||
${OPENCS_UI_HDR}
|
||||
${OPENCS_MOC_SRC}
|
||||
@ -250,13 +250,14 @@ target_link_libraries(openmw-cs-lib
|
||||
)
|
||||
|
||||
if (QT_VERSION_MAJOR VERSION_EQUAL 6)
|
||||
target_link_libraries(openmw-cs-lib Qt::Widgets Qt::Core Qt::Network Qt::OpenGL Qt::OpenGLWidgets)
|
||||
target_link_libraries(openmw-cs-lib Qt::Widgets Qt::Core Qt::Network Qt::OpenGL Qt::OpenGLWidgets Qt::Svg)
|
||||
else()
|
||||
target_link_libraries(openmw-cs-lib Qt::Widgets Qt::Core Qt::Network Qt::OpenGL)
|
||||
target_link_libraries(openmw-cs-lib Qt::Widgets Qt::Core Qt::Network Qt::OpenGL Qt::Svg)
|
||||
endif()
|
||||
|
||||
if (WIN32)
|
||||
target_link_libraries(openmw-cs-lib ${Boost_LOCALE_LIBRARY})
|
||||
target_sources(openmw-cs PRIVATE ${CMAKE_SOURCE_DIR}/files/windows/openmw-cs.exe.manifest)
|
||||
endif()
|
||||
|
||||
if (WIN32 AND BUILD_OPENCS)
|
||||
@ -292,7 +293,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>
|
||||
|
||||
|
@ -81,7 +81,7 @@ int runApplication(int argc, char* argv[])
|
||||
|
||||
Application application(argc, argv);
|
||||
|
||||
application.setWindowIcon(QIcon(":./openmw-cs.png"));
|
||||
application.setWindowIcon(QIcon(":openmw-cs"));
|
||||
|
||||
CS::Editor editor(argc, argv);
|
||||
#ifdef __linux__
|
||||
|
@ -93,7 +93,6 @@ void CSMDoc::Runner::start(bool delayed)
|
||||
arguments << "--data=\"" + Files::pathToQString(mProjectPath.parent_path()) + "\"";
|
||||
|
||||
arguments << "--replace=content";
|
||||
arguments << "--content=builtin.omwscripts";
|
||||
|
||||
for (const auto& mContentFile : mContentFiles)
|
||||
{
|
||||
|
@ -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())
|
||||
{
|
||||
|
@ -171,10 +171,9 @@ void CSMTools::TopicInfoCheckStage::perform(int stage, CSMDoc::Messages& message
|
||||
|
||||
// Check info conditions
|
||||
|
||||
for (std::vector<ESM::DialInfo::SelectStruct>::const_iterator it = topicInfo.mSelects.begin();
|
||||
it != topicInfo.mSelects.end(); ++it)
|
||||
for (const auto& select : topicInfo.mSelects)
|
||||
{
|
||||
verifySelectStruct((*it), id, messages);
|
||||
verifySelectStruct(select, id, messages);
|
||||
}
|
||||
}
|
||||
|
||||
@ -308,49 +307,15 @@ bool CSMTools::TopicInfoCheckStage::verifyItem(
|
||||
}
|
||||
|
||||
bool CSMTools::TopicInfoCheckStage::verifySelectStruct(
|
||||
const ESM::DialInfo::SelectStruct& select, const CSMWorld::UniversalId& id, CSMDoc::Messages& messages)
|
||||
const ESM::DialogueCondition& select, const CSMWorld::UniversalId& id, CSMDoc::Messages& messages)
|
||||
{
|
||||
CSMWorld::ConstInfoSelectWrapper infoCondition(select);
|
||||
|
||||
if (infoCondition.getFunctionName() == CSMWorld::ConstInfoSelectWrapper::Function_None)
|
||||
if (select.mFunction == ESM::DialogueCondition::Function_None)
|
||||
{
|
||||
messages.add(id, "Invalid condition '" + infoCondition.toString() + "'", "", CSMDoc::Message::Severity_Error);
|
||||
return false;
|
||||
}
|
||||
else if (!infoCondition.variantTypeIsValid())
|
||||
{
|
||||
std::ostringstream stream;
|
||||
stream << "Value of condition '" << infoCondition.toString() << "' has invalid ";
|
||||
|
||||
switch (select.mValue.getType())
|
||||
{
|
||||
case ESM::VT_None:
|
||||
stream << "None";
|
||||
break;
|
||||
case ESM::VT_Short:
|
||||
stream << "Short";
|
||||
break;
|
||||
case ESM::VT_Int:
|
||||
stream << "Int";
|
||||
break;
|
||||
case ESM::VT_Long:
|
||||
stream << "Long";
|
||||
break;
|
||||
case ESM::VT_Float:
|
||||
stream << "Float";
|
||||
break;
|
||||
case ESM::VT_String:
|
||||
stream << "String";
|
||||
break;
|
||||
default:
|
||||
stream << "unknown";
|
||||
break;
|
||||
}
|
||||
stream << " type";
|
||||
|
||||
messages.add(id, stream.str(), "", CSMDoc::Message::Severity_Error);
|
||||
return false;
|
||||
}
|
||||
else if (infoCondition.conditionIsAlwaysTrue())
|
||||
{
|
||||
messages.add(
|
||||
@ -365,48 +330,48 @@ bool CSMTools::TopicInfoCheckStage::verifySelectStruct(
|
||||
}
|
||||
|
||||
// Id checks
|
||||
if (infoCondition.getFunctionName() == CSMWorld::ConstInfoSelectWrapper::Function_Global
|
||||
&& !verifyId(ESM::RefId::stringRefId(infoCondition.getVariableName()), mGlobals, id, messages))
|
||||
if (select.mFunction == ESM::DialogueCondition::Function_Global
|
||||
&& !verifyId(ESM::RefId::stringRefId(select.mVariable), mGlobals, id, messages))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
else if (infoCondition.getFunctionName() == CSMWorld::ConstInfoSelectWrapper::Function_Journal
|
||||
&& !verifyId(ESM::RefId::stringRefId(infoCondition.getVariableName()), mJournals, id, messages))
|
||||
else if (select.mFunction == ESM::DialogueCondition::Function_Journal
|
||||
&& !verifyId(ESM::RefId::stringRefId(select.mVariable), mJournals, id, messages))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
else if (infoCondition.getFunctionName() == CSMWorld::ConstInfoSelectWrapper::Function_Item
|
||||
&& !verifyItem(ESM::RefId::stringRefId(infoCondition.getVariableName()), id, messages))
|
||||
else if (select.mFunction == ESM::DialogueCondition::Function_Item
|
||||
&& !verifyItem(ESM::RefId::stringRefId(select.mVariable), id, messages))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
else if (infoCondition.getFunctionName() == CSMWorld::ConstInfoSelectWrapper::Function_Dead
|
||||
&& !verifyActor(ESM::RefId::stringRefId(infoCondition.getVariableName()), id, messages))
|
||||
else if (select.mFunction == ESM::DialogueCondition::Function_Dead
|
||||
&& !verifyActor(ESM::RefId::stringRefId(select.mVariable), id, messages))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
else if (infoCondition.getFunctionName() == CSMWorld::ConstInfoSelectWrapper::Function_NotId
|
||||
&& !verifyActor(ESM::RefId::stringRefId(infoCondition.getVariableName()), id, messages))
|
||||
else if (select.mFunction == ESM::DialogueCondition::Function_NotId
|
||||
&& !verifyActor(ESM::RefId::stringRefId(select.mVariable), id, messages))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
else if (infoCondition.getFunctionName() == CSMWorld::ConstInfoSelectWrapper::Function_NotFaction
|
||||
&& !verifyId(ESM::RefId::stringRefId(infoCondition.getVariableName()), mFactions, id, messages))
|
||||
else if (select.mFunction == ESM::DialogueCondition::Function_NotFaction
|
||||
&& !verifyId(ESM::RefId::stringRefId(select.mVariable), mFactions, id, messages))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
else if (infoCondition.getFunctionName() == CSMWorld::ConstInfoSelectWrapper::Function_NotClass
|
||||
&& !verifyId(ESM::RefId::stringRefId(infoCondition.getVariableName()), mClasses, id, messages))
|
||||
else if (select.mFunction == ESM::DialogueCondition::Function_NotClass
|
||||
&& !verifyId(ESM::RefId::stringRefId(select.mVariable), mClasses, id, messages))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
else if (infoCondition.getFunctionName() == CSMWorld::ConstInfoSelectWrapper::Function_NotRace
|
||||
&& !verifyId(ESM::RefId::stringRefId(infoCondition.getVariableName()), mRaces, id, messages))
|
||||
else if (select.mFunction == ESM::DialogueCondition::Function_NotRace
|
||||
&& !verifyId(ESM::RefId::stringRefId(select.mVariable), mRaces, id, messages))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
else if (infoCondition.getFunctionName() == CSMWorld::ConstInfoSelectWrapper::Function_NotCell
|
||||
&& !verifyCell(infoCondition.getVariableName(), id, messages))
|
||||
else if (select.mFunction == ESM::DialogueCondition::Function_NotCell
|
||||
&& !verifyCell(select.mVariable, id, messages))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
@ -84,7 +84,7 @@ namespace CSMTools
|
||||
const ESM::RefId& name, int rank, const CSMWorld::UniversalId& id, CSMDoc::Messages& messages);
|
||||
bool verifyItem(const ESM::RefId& name, const CSMWorld::UniversalId& id, CSMDoc::Messages& messages);
|
||||
bool verifySelectStruct(
|
||||
const ESM::DialInfo::SelectStruct& select, const CSMWorld::UniversalId& id, CSMDoc::Messages& messages);
|
||||
const ESM::DialogueCondition& select, const CSMWorld::UniversalId& id, CSMDoc::Messages& messages);
|
||||
bool verifySound(const std::string& name, const CSMWorld::UniversalId& id, CSMDoc::Messages& messages);
|
||||
|
||||
template <typename T>
|
||||
|
@ -67,6 +67,11 @@ namespace CSMWorld
|
||||
return mMaleParts[ESM::getMeshPart(index)];
|
||||
}
|
||||
|
||||
const osg::Vec2f& ActorAdapter::RaceData::getGenderWeightHeight(bool isFemale)
|
||||
{
|
||||
return isFemale ? mWeightsHeights.mFemaleWeightHeight : mWeightsHeights.mMaleWeightHeight;
|
||||
}
|
||||
|
||||
bool ActorAdapter::RaceData::hasDependency(const ESM::RefId& id) const
|
||||
{
|
||||
return mDependencies.find(id) != mDependencies.end();
|
||||
@ -90,10 +95,11 @@ namespace CSMWorld
|
||||
mDependencies.emplace(id);
|
||||
}
|
||||
|
||||
void ActorAdapter::RaceData::reset_data(const ESM::RefId& id, bool isBeast)
|
||||
void ActorAdapter::RaceData::reset_data(const ESM::RefId& id, const WeightsHeights& raceStats, bool isBeast)
|
||||
{
|
||||
mId = id;
|
||||
mIsBeast = isBeast;
|
||||
mWeightsHeights = raceStats;
|
||||
for (auto& str : mFemaleParts)
|
||||
str = ESM::RefId();
|
||||
for (auto& str : mMaleParts)
|
||||
@ -163,6 +169,11 @@ namespace CSMWorld
|
||||
return it->second.first;
|
||||
}
|
||||
|
||||
const osg::Vec2f& ActorAdapter::ActorData::getRaceWeightHeight() const
|
||||
{
|
||||
return mRaceData->getGenderWeightHeight(isFemale());
|
||||
}
|
||||
|
||||
bool ActorAdapter::ActorData::hasDependency(const ESM::RefId& id) const
|
||||
{
|
||||
return mDependencies.find(id) != mDependencies.end();
|
||||
@ -504,7 +515,11 @@ namespace CSMWorld
|
||||
}
|
||||
|
||||
auto& race = raceRecord.get();
|
||||
data->reset_data(id, race.mData.mFlags & ESM::Race::Beast);
|
||||
|
||||
WeightsHeights scaleStats = { osg::Vec2f(race.mData.mMaleWeight, race.mData.mMaleHeight),
|
||||
osg::Vec2f(race.mData.mFemaleWeight, race.mData.mFemaleHeight) };
|
||||
|
||||
data->reset_data(id, scaleStats, race.mData.mFlags & ESM::Race::Beast);
|
||||
|
||||
// Setup body parts
|
||||
for (int i = 0; i < mBodyParts.getSize(); ++i)
|
||||
|
@ -41,6 +41,12 @@ namespace CSMWorld
|
||||
/// Tracks unique strings
|
||||
using RefIdSet = std::unordered_set<ESM::RefId>;
|
||||
|
||||
struct WeightsHeights
|
||||
{
|
||||
osg::Vec2f mMaleWeightHeight;
|
||||
osg::Vec2f mFemaleWeightHeight;
|
||||
};
|
||||
|
||||
/// Contains base race data shared between actors
|
||||
class RaceData
|
||||
{
|
||||
@ -57,6 +63,8 @@ namespace CSMWorld
|
||||
const ESM::RefId& getFemalePart(ESM::PartReferenceType index) const;
|
||||
/// Retrieves the associated body part
|
||||
const ESM::RefId& getMalePart(ESM::PartReferenceType index) const;
|
||||
|
||||
const osg::Vec2f& getGenderWeightHeight(bool isFemale);
|
||||
/// Checks if the race has a data dependency
|
||||
bool hasDependency(const ESM::RefId& id) const;
|
||||
|
||||
@ -67,7 +75,8 @@ namespace CSMWorld
|
||||
/// Marks an additional dependency
|
||||
void addOtherDependency(const ESM::RefId& id);
|
||||
/// Clears parts and dependencies
|
||||
void reset_data(const ESM::RefId& raceId, bool isBeast = false);
|
||||
void reset_data(const ESM::RefId& raceId,
|
||||
const WeightsHeights& raceStats = { osg::Vec2f(1.f, 1.f), osg::Vec2f(1.f, 1.f) }, bool isBeast = false);
|
||||
|
||||
private:
|
||||
bool handles(ESM::PartReferenceType type) const;
|
||||
@ -75,6 +84,7 @@ namespace CSMWorld
|
||||
bool mIsBeast;
|
||||
RacePartList mFemaleParts;
|
||||
RacePartList mMaleParts;
|
||||
WeightsHeights mWeightsHeights;
|
||||
RefIdSet mDependencies;
|
||||
};
|
||||
using RaceDataPtr = std::shared_ptr<RaceData>;
|
||||
@ -96,6 +106,8 @@ namespace CSMWorld
|
||||
std::string getSkeleton() const;
|
||||
/// Retrieves the associated actor part
|
||||
ESM::RefId getPart(ESM::PartReferenceType index) const;
|
||||
|
||||
const osg::Vec2f& getRaceWeightHeight() const;
|
||||
/// Checks if the actor has a data dependency
|
||||
bool hasDependency(const ESM::RefId& id) const;
|
||||
|
||||
|
@ -585,19 +585,22 @@ namespace CSMWorld
|
||||
void set(Record<ESXRecordT>& record, const QVariant& data) override
|
||||
{
|
||||
ESXRecordT record2 = record.get();
|
||||
|
||||
float bodyAttr = std::clamp(data.toFloat(), 0.5f, 2.0f);
|
||||
|
||||
if (mWeight)
|
||||
{
|
||||
if (mMale)
|
||||
record2.mData.mMaleWeight = data.toFloat();
|
||||
record2.mData.mMaleWeight = bodyAttr;
|
||||
else
|
||||
record2.mData.mFemaleWeight = data.toFloat();
|
||||
record2.mData.mFemaleWeight = bodyAttr;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (mMale)
|
||||
record2.mData.mMaleHeight = data.toFloat();
|
||||
record2.mData.mMaleHeight = bodyAttr;
|
||||
else
|
||||
record2.mData.mFemaleHeight = data.toFloat();
|
||||
record2.mData.mFemaleHeight = bodyAttr;
|
||||
}
|
||||
record.setModified(record2);
|
||||
}
|
||||
@ -968,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);
|
||||
}
|
||||
|
||||
@ -1133,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)
|
||||
{
|
||||
}
|
||||
|
||||
@ -1162,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());
|
||||
}
|
||||
|
||||
@ -1179,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>
|
||||
{
|
||||
@ -1187,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
|
||||
{
|
||||
@ -1209,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
|
||||
@ -1279,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];
|
||||
}
|
||||
@ -1313,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]);
|
||||
}
|
||||
@ -2049,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" },
|
||||
@ -321,7 +324,6 @@ namespace CSMWorld
|
||||
{ ColumnId_MaxAttack, "Max Attack" },
|
||||
{ ColumnId_CreatureMisc, "Creature Misc" },
|
||||
|
||||
{ ColumnId_Idle1, "Idle 1" },
|
||||
{ ColumnId_Idle2, "Idle 2" },
|
||||
{ ColumnId_Idle3, "Idle 3" },
|
||||
{ ColumnId_Idle4, "Idle 4" },
|
||||
@ -329,6 +331,7 @@ namespace CSMWorld
|
||||
{ ColumnId_Idle6, "Idle 6" },
|
||||
{ ColumnId_Idle7, "Idle 7" },
|
||||
{ ColumnId_Idle8, "Idle 8" },
|
||||
{ ColumnId_Idle9, "Idle 9" },
|
||||
|
||||
{ ColumnId_RegionWeather, "Weather" },
|
||||
{ ColumnId_WeatherName, "Type" },
|
||||
@ -376,6 +379,7 @@ namespace CSMWorld
|
||||
{ ColumnId_Blocked, "Blocked" },
|
||||
|
||||
{ ColumnId_LevelledCreatureId, "Levelled Creature" },
|
||||
{ ColumnId_ProjectileSpeed, "Projectile Speed" },
|
||||
|
||||
// end marker
|
||||
{ -1, 0 },
|
||||
|
@ -310,14 +310,14 @@ namespace CSMWorld
|
||||
ColumnId_MaxAttack = 284,
|
||||
ColumnId_CreatureMisc = 285,
|
||||
|
||||
ColumnId_Idle1 = 286,
|
||||
ColumnId_Idle2 = 287,
|
||||
ColumnId_Idle3 = 288,
|
||||
ColumnId_Idle4 = 289,
|
||||
ColumnId_Idle5 = 290,
|
||||
ColumnId_Idle6 = 291,
|
||||
ColumnId_Idle7 = 292,
|
||||
ColumnId_Idle8 = 293,
|
||||
ColumnId_Idle2 = 286,
|
||||
ColumnId_Idle3 = 287,
|
||||
ColumnId_Idle4 = 288,
|
||||
ColumnId_Idle5 = 289,
|
||||
ColumnId_Idle6 = 290,
|
||||
ColumnId_Idle7 = 291,
|
||||
ColumnId_Idle8 = 292,
|
||||
ColumnId_Idle9 = 293,
|
||||
|
||||
ColumnId_RegionWeather = 294,
|
||||
ColumnId_WeatherName = 295,
|
||||
@ -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);
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -7,133 +7,13 @@
|
||||
|
||||
#include <components/esm3/loadinfo.hpp>
|
||||
|
||||
namespace ESM
|
||||
{
|
||||
class Variant;
|
||||
}
|
||||
#include <QVariant>
|
||||
|
||||
namespace CSMWorld
|
||||
{
|
||||
// ESM::DialInfo::SelectStruct.mSelectRule
|
||||
// 012345...
|
||||
// ^^^ ^^
|
||||
// ||| ||
|
||||
// ||| |+------------- condition variable string
|
||||
// ||| +-------------- comparison type, ['0'..'5']; e.g. !=, <, >=, etc
|
||||
// ||+---------------- function index (encoded, where function == '1')
|
||||
// |+----------------- function, ['1'..'C']; e.g. Global, Local, Not ID, etc
|
||||
// +------------------ unknown
|
||||
//
|
||||
|
||||
// Wrapper for DialInfo::SelectStruct
|
||||
class ConstInfoSelectWrapper
|
||||
{
|
||||
public:
|
||||
// Order matters
|
||||
enum FunctionName
|
||||
{
|
||||
Function_RankLow = 0,
|
||||
Function_RankHigh,
|
||||
Function_RankRequirement,
|
||||
Function_Reputation,
|
||||
Function_Health_Percent,
|
||||
Function_PcReputation,
|
||||
Function_PcLevel,
|
||||
Function_PcHealthPercent,
|
||||
Function_PcMagicka,
|
||||
Function_PcFatigue,
|
||||
Function_PcStrength,
|
||||
Function_PcBlock,
|
||||
Function_PcArmorer,
|
||||
Function_PcMediumArmor,
|
||||
Function_PcHeavyArmor,
|
||||
Function_PcBluntWeapon,
|
||||
Function_PcLongBlade,
|
||||
Function_PcAxe,
|
||||
Function_PcSpear,
|
||||
Function_PcAthletics,
|
||||
Function_PcEnchant,
|
||||
Function_PcDestruction,
|
||||
Function_PcAlteration,
|
||||
Function_PcIllusion,
|
||||
Function_PcConjuration,
|
||||
Function_PcMysticism,
|
||||
Function_PcRestoration,
|
||||
Function_PcAlchemy,
|
||||
Function_PcUnarmored,
|
||||
Function_PcSecurity,
|
||||
Function_PcSneak,
|
||||
Function_PcAcrobatics,
|
||||
Function_PcLightArmor,
|
||||
Function_PcShortBlade,
|
||||
Function_PcMarksman,
|
||||
Function_PcMerchantile,
|
||||
Function_PcSpeechcraft,
|
||||
Function_PcHandToHand,
|
||||
Function_PcGender,
|
||||
Function_PcExpelled,
|
||||
Function_PcCommonDisease,
|
||||
Function_PcBlightDisease,
|
||||
Function_PcClothingModifier,
|
||||
Function_PcCrimeLevel,
|
||||
Function_SameSex,
|
||||
Function_SameRace,
|
||||
Function_SameFaction,
|
||||
Function_FactionRankDifference,
|
||||
Function_Detected,
|
||||
Function_Alarmed,
|
||||
Function_Choice,
|
||||
Function_PcIntelligence,
|
||||
Function_PcWillpower,
|
||||
Function_PcAgility,
|
||||
Function_PcSpeed,
|
||||
Function_PcEndurance,
|
||||
Function_PcPersonality,
|
||||
Function_PcLuck,
|
||||
Function_PcCorpus,
|
||||
Function_Weather,
|
||||
Function_PcVampire,
|
||||
Function_Level,
|
||||
Function_Attacked,
|
||||
Function_TalkedToPc,
|
||||
Function_PcHealth,
|
||||
Function_CreatureTarget,
|
||||
Function_FriendHit,
|
||||
Function_Fight,
|
||||
Function_Hello,
|
||||
Function_Alarm,
|
||||
Function_Flee,
|
||||
Function_ShouldAttack,
|
||||
Function_Werewolf,
|
||||
Function_PcWerewolfKills = 73,
|
||||
|
||||
Function_Global,
|
||||
Function_Local,
|
||||
Function_Journal,
|
||||
Function_Item,
|
||||
Function_Dead,
|
||||
Function_NotId,
|
||||
Function_NotFaction,
|
||||
Function_NotClass,
|
||||
Function_NotRace,
|
||||
Function_NotCell,
|
||||
Function_NotLocal,
|
||||
|
||||
Function_None
|
||||
};
|
||||
|
||||
enum RelationType
|
||||
{
|
||||
Relation_Equal,
|
||||
Relation_NotEqual,
|
||||
Relation_Greater,
|
||||
Relation_GreaterOrEqual,
|
||||
Relation_Less,
|
||||
Relation_LessOrEqual,
|
||||
|
||||
Relation_None
|
||||
};
|
||||
|
||||
enum ComparisonType
|
||||
{
|
||||
Comparison_Boolean,
|
||||
@ -143,25 +23,13 @@ namespace CSMWorld
|
||||
Comparison_None
|
||||
};
|
||||
|
||||
static const size_t RuleMinSize;
|
||||
|
||||
static const size_t FunctionPrefixOffset;
|
||||
static const size_t FunctionIndexOffset;
|
||||
static const size_t RelationIndexOffset;
|
||||
static const size_t VarNameOffset;
|
||||
|
||||
static const char* FunctionEnumStrings[];
|
||||
static const char* RelationEnumStrings[];
|
||||
static const char* ComparisonEnumStrings[];
|
||||
|
||||
static std::string convertToString(FunctionName name);
|
||||
static std::string convertToString(RelationType type);
|
||||
static std::string convertToString(ComparisonType type);
|
||||
ConstInfoSelectWrapper(const ESM::DialogueCondition& select);
|
||||
|
||||
ConstInfoSelectWrapper(const ESM::DialInfo::SelectStruct& select);
|
||||
|
||||
FunctionName getFunctionName() const;
|
||||
RelationType getRelationType() const;
|
||||
ESM::DialogueCondition::Function getFunctionName() const;
|
||||
ESM::DialogueCondition::Comparison getRelationType() const;
|
||||
ComparisonType getComparisonType() const;
|
||||
|
||||
bool hasVariable() const;
|
||||
@ -169,17 +37,12 @@ namespace CSMWorld
|
||||
|
||||
bool conditionIsAlwaysTrue() const;
|
||||
bool conditionIsNeverTrue() const;
|
||||
bool variantTypeIsValid() const;
|
||||
|
||||
const ESM::Variant& getVariant() const;
|
||||
QVariant getValue() const;
|
||||
|
||||
std::string toString() const;
|
||||
|
||||
protected:
|
||||
void readRule();
|
||||
void readFunctionName();
|
||||
void readRelationType();
|
||||
void readVariableName();
|
||||
void updateHasVariable();
|
||||
void updateComparisonType();
|
||||
|
||||
@ -207,38 +70,29 @@ namespace CSMWorld
|
||||
template <typename Type1, typename Type2>
|
||||
bool conditionIsNeverTrue(std::pair<Type1, Type1> conditionRange, std::pair<Type2, Type2> validRange) const;
|
||||
|
||||
FunctionName mFunctionName;
|
||||
RelationType mRelationType;
|
||||
ComparisonType mComparisonType;
|
||||
|
||||
bool mHasVariable;
|
||||
std::string mVariableName;
|
||||
|
||||
private:
|
||||
const ESM::DialInfo::SelectStruct& mConstSelect;
|
||||
const ESM::DialogueCondition& mConstSelect;
|
||||
};
|
||||
|
||||
// Wrapper for DialInfo::SelectStruct that can modify the wrapped select struct
|
||||
// Wrapper for DialogueCondition that can modify the wrapped select struct
|
||||
class InfoSelectWrapper : public ConstInfoSelectWrapper
|
||||
{
|
||||
public:
|
||||
InfoSelectWrapper(ESM::DialInfo::SelectStruct& select);
|
||||
InfoSelectWrapper(ESM::DialogueCondition& select);
|
||||
|
||||
// Wrapped SelectStruct will not be modified until update() is called
|
||||
void setFunctionName(FunctionName name);
|
||||
void setRelationType(RelationType type);
|
||||
void setFunctionName(ESM::DialogueCondition::Function name);
|
||||
void setRelationType(ESM::DialogueCondition::Comparison type);
|
||||
void setVariableName(const std::string& name);
|
||||
|
||||
// Modified wrapped SelectStruct
|
||||
void update();
|
||||
|
||||
// This sets properties based on the function name to its defaults and updates the wrapped object
|
||||
void setDefaults();
|
||||
|
||||
ESM::Variant& getVariant();
|
||||
void setValue(int value);
|
||||
void setValue(float value);
|
||||
|
||||
private:
|
||||
ESM::DialInfo::SelectStruct& mSelect;
|
||||
ESM::DialogueCondition& mSelect;
|
||||
|
||||
void writeRule();
|
||||
};
|
||||
|
@ -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
|
||||
@ -527,13 +538,11 @@ namespace CSMWorld
|
||||
{
|
||||
Info info = record.get();
|
||||
|
||||
std::vector<ESM::DialInfo::SelectStruct>& conditions = info.mSelects;
|
||||
auto& conditions = info.mSelects;
|
||||
|
||||
// default row
|
||||
ESM::DialInfo::SelectStruct condStruct;
|
||||
condStruct.mSelectRule = "01000";
|
||||
condStruct.mValue = ESM::Variant();
|
||||
condStruct.mValue.setType(ESM::VT_Int);
|
||||
ESM::DialogueCondition condStruct;
|
||||
condStruct.mIndex = conditions.size();
|
||||
|
||||
conditions.insert(conditions.begin() + position, condStruct);
|
||||
|
||||
@ -544,7 +553,7 @@ namespace CSMWorld
|
||||
{
|
||||
Info info = record.get();
|
||||
|
||||
std::vector<ESM::DialInfo::SelectStruct>& conditions = info.mSelects;
|
||||
auto& conditions = info.mSelects;
|
||||
|
||||
if (rowToRemove < 0 || rowToRemove >= static_cast<int>(conditions.size()))
|
||||
throw std::runtime_error("index out of range");
|
||||
@ -558,8 +567,8 @@ namespace CSMWorld
|
||||
{
|
||||
Info info = record.get();
|
||||
|
||||
info.mSelects = static_cast<const NestedTableWrapper<std::vector<ESM::DialInfo::SelectStruct>>&>(nestedTable)
|
||||
.mNestedTable;
|
||||
info.mSelects
|
||||
= static_cast<const NestedTableWrapper<std::vector<ESM::DialogueCondition>>&>(nestedTable).mNestedTable;
|
||||
|
||||
record.setModified(info);
|
||||
}
|
||||
@ -567,14 +576,14 @@ namespace CSMWorld
|
||||
NestedTableWrapperBase* InfoConditionAdapter::table(const Record<Info>& record) const
|
||||
{
|
||||
// deleted by dtor of NestedTableStoring
|
||||
return new NestedTableWrapper<std::vector<ESM::DialInfo::SelectStruct>>(record.get().mSelects);
|
||||
return new NestedTableWrapper<std::vector<ESM::DialogueCondition>>(record.get().mSelects);
|
||||
}
|
||||
|
||||
QVariant InfoConditionAdapter::getData(const Record<Info>& record, int subRowIndex, int subColIndex) const
|
||||
{
|
||||
Info info = record.get();
|
||||
|
||||
std::vector<ESM::DialInfo::SelectStruct>& conditions = info.mSelects;
|
||||
auto& conditions = info.mSelects;
|
||||
|
||||
if (subRowIndex < 0 || subRowIndex >= static_cast<int>(conditions.size()))
|
||||
throw std::runtime_error("index out of range");
|
||||
@ -596,23 +605,11 @@ namespace CSMWorld
|
||||
}
|
||||
case 2:
|
||||
{
|
||||
return infoSelectWrapper.getRelationType();
|
||||
return infoSelectWrapper.getRelationType() - ESM::DialogueCondition::Comp_Eq;
|
||||
}
|
||||
case 3:
|
||||
{
|
||||
switch (infoSelectWrapper.getVariant().getType())
|
||||
{
|
||||
case ESM::VT_Int:
|
||||
{
|
||||
return infoSelectWrapper.getVariant().getInteger();
|
||||
}
|
||||
case ESM::VT_Float:
|
||||
{
|
||||
return infoSelectWrapper.getVariant().getFloat();
|
||||
}
|
||||
default:
|
||||
return QVariant();
|
||||
}
|
||||
return infoSelectWrapper.getValue();
|
||||
}
|
||||
default:
|
||||
throw std::runtime_error("Info condition subcolumn index out of range");
|
||||
@ -624,7 +621,7 @@ namespace CSMWorld
|
||||
{
|
||||
Info info = record.get();
|
||||
|
||||
std::vector<ESM::DialInfo::SelectStruct>& conditions = info.mSelects;
|
||||
auto& conditions = info.mSelects;
|
||||
|
||||
if (subRowIndex < 0 || subRowIndex >= static_cast<int>(conditions.size()))
|
||||
throw std::runtime_error("index out of range");
|
||||
@ -636,27 +633,18 @@ namespace CSMWorld
|
||||
{
|
||||
case 0: // Function
|
||||
{
|
||||
infoSelectWrapper.setFunctionName(static_cast<ConstInfoSelectWrapper::FunctionName>(value.toInt()));
|
||||
|
||||
if (infoSelectWrapper.getComparisonType() != ConstInfoSelectWrapper::Comparison_Numeric
|
||||
&& infoSelectWrapper.getVariant().getType() != ESM::VT_Int)
|
||||
{
|
||||
infoSelectWrapper.getVariant().setType(ESM::VT_Int);
|
||||
}
|
||||
|
||||
infoSelectWrapper.update();
|
||||
infoSelectWrapper.setFunctionName(static_cast<ESM::DialogueCondition::Function>(value.toInt()));
|
||||
break;
|
||||
}
|
||||
case 1: // Variable
|
||||
{
|
||||
infoSelectWrapper.setVariableName(value.toString().toUtf8().constData());
|
||||
infoSelectWrapper.update();
|
||||
break;
|
||||
}
|
||||
case 2: // Relation
|
||||
{
|
||||
infoSelectWrapper.setRelationType(static_cast<ConstInfoSelectWrapper::RelationType>(value.toInt()));
|
||||
infoSelectWrapper.update();
|
||||
infoSelectWrapper.setRelationType(
|
||||
static_cast<ESM::DialogueCondition::Comparison>(value.toInt() + ESM::DialogueCondition::Comp_Eq));
|
||||
break;
|
||||
}
|
||||
case 3: // Value
|
||||
@ -668,13 +656,11 @@ namespace CSMWorld
|
||||
// QVariant seems to have issues converting 0
|
||||
if ((value.toInt(&conversionResult) && conversionResult) || value.toString().compare("0") == 0)
|
||||
{
|
||||
infoSelectWrapper.getVariant().setType(ESM::VT_Int);
|
||||
infoSelectWrapper.getVariant().setInteger(value.toInt());
|
||||
infoSelectWrapper.setValue(value.toInt());
|
||||
}
|
||||
else if (value.toFloat(&conversionResult) && conversionResult)
|
||||
{
|
||||
infoSelectWrapper.getVariant().setType(ESM::VT_Float);
|
||||
infoSelectWrapper.getVariant().setFloat(value.toFloat());
|
||||
infoSelectWrapper.setValue(value.toFloat());
|
||||
}
|
||||
break;
|
||||
}
|
||||
@ -683,8 +669,7 @@ namespace CSMWorld
|
||||
{
|
||||
if ((value.toInt(&conversionResult) && conversionResult) || value.toString().compare("0") == 0)
|
||||
{
|
||||
infoSelectWrapper.getVariant().setType(ESM::VT_Int);
|
||||
infoSelectWrapper.getVariant().setInteger(value.toInt());
|
||||
infoSelectWrapper.setValue(value.toInt());
|
||||
}
|
||||
break;
|
||||
}
|
||||
@ -996,7 +981,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);
|
||||
@ -210,7 +210,6 @@ CSMWorld::RefIdCollection::RefIdCollection()
|
||||
mColumns.back().addColumn(new RefIdColumn(Columns::ColumnId_AiDuration, CSMWorld::ColumnBase::Display_Integer));
|
||||
mColumns.back().addColumn(new RefIdColumn(Columns::ColumnId_AiWanderToD, CSMWorld::ColumnBase::Display_Integer));
|
||||
|
||||
mColumns.back().addColumn(new RefIdColumn(Columns::ColumnId_Idle1, CSMWorld::ColumnBase::Display_Integer));
|
||||
mColumns.back().addColumn(new RefIdColumn(Columns::ColumnId_Idle2, CSMWorld::ColumnBase::Display_Integer));
|
||||
mColumns.back().addColumn(new RefIdColumn(Columns::ColumnId_Idle3, CSMWorld::ColumnBase::Display_Integer));
|
||||
mColumns.back().addColumn(new RefIdColumn(Columns::ColumnId_Idle4, CSMWorld::ColumnBase::Display_Integer));
|
||||
@ -218,6 +217,7 @@ CSMWorld::RefIdCollection::RefIdCollection()
|
||||
mColumns.back().addColumn(new RefIdColumn(Columns::ColumnId_Idle6, CSMWorld::ColumnBase::Display_Integer));
|
||||
mColumns.back().addColumn(new RefIdColumn(Columns::ColumnId_Idle7, CSMWorld::ColumnBase::Display_Integer));
|
||||
mColumns.back().addColumn(new RefIdColumn(Columns::ColumnId_Idle8, CSMWorld::ColumnBase::Display_Integer));
|
||||
mColumns.back().addColumn(new RefIdColumn(Columns::ColumnId_Idle9, CSMWorld::ColumnBase::Display_Integer));
|
||||
|
||||
mColumns.back().addColumn(new RefIdColumn(Columns::ColumnId_AiWanderRepeat, CSMWorld::ColumnBase::Display_Boolean));
|
||||
mColumns.back().addColumn(
|
||||
|
@ -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;
|
||||
|
@ -28,7 +28,7 @@ void CSMWorld::Resources::recreate(const VFS::Manager* vfs, const char* const* e
|
||||
|
||||
size_t baseSize = mBaseDirectory.size();
|
||||
|
||||
for (const auto& filepath : vfs->getRecursiveDirectoryIterator(""))
|
||||
for (const auto& filepath : vfs->getRecursiveDirectoryIterator())
|
||||
{
|
||||
const std::string_view view = filepath.view();
|
||||
if (view.size() < baseSize + 1 || !view.starts_with(mBaseDirectory) || view[baseSize] != '/')
|
||||
|
@ -58,7 +58,7 @@ std::string CSMWorld::TableMimeData::getIcon() const
|
||||
|
||||
if (tmpIcon != id.getIcon())
|
||||
{
|
||||
return ":/multitype.png"; // icon stolen from gnome TODO: get new icon
|
||||
return ":multitype";
|
||||
}
|
||||
|
||||
tmpIcon = id.getIcon();
|
||||
|
@ -23,158 +23,137 @@ namespace
|
||||
constexpr TypeData sNoArg[] = {
|
||||
{ CSMWorld::UniversalId::Class_None, CSMWorld::UniversalId::Type_None, "-", ":placeholder" },
|
||||
{ CSMWorld::UniversalId::Class_RecordList, CSMWorld::UniversalId::Type_Globals, "Global Variables",
|
||||
":./global-variable.png" },
|
||||
{ CSMWorld::UniversalId::Class_RecordList, CSMWorld::UniversalId::Type_Gmsts, "Game Settings", ":./gmst.png" },
|
||||
{ CSMWorld::UniversalId::Class_RecordList, CSMWorld::UniversalId::Type_Skills, "Skills", ":./skill.png" },
|
||||
{ CSMWorld::UniversalId::Class_RecordList, CSMWorld::UniversalId::Type_Classes, "Classes", ":./class.png" },
|
||||
{ CSMWorld::UniversalId::Class_RecordList, CSMWorld::UniversalId::Type_Factions, "Factions", ":./faction.png" },
|
||||
{ CSMWorld::UniversalId::Class_RecordList, CSMWorld::UniversalId::Type_Races, "Races", ":./race.png" },
|
||||
{ CSMWorld::UniversalId::Class_RecordList, CSMWorld::UniversalId::Type_Sounds, "Sounds", ":./sound.png" },
|
||||
{ CSMWorld::UniversalId::Class_RecordList, CSMWorld::UniversalId::Type_Scripts, "Scripts", ":./script.png" },
|
||||
{ CSMWorld::UniversalId::Class_RecordList, CSMWorld::UniversalId::Type_Regions, "Regions", ":./region.png" },
|
||||
{ CSMWorld::UniversalId::Class_RecordList, CSMWorld::UniversalId::Type_Birthsigns, "Birthsigns",
|
||||
":./birthsign.png" },
|
||||
{ CSMWorld::UniversalId::Class_RecordList, CSMWorld::UniversalId::Type_Spells, "Spells", ":./spell.png" },
|
||||
{ CSMWorld::UniversalId::Class_RecordList, CSMWorld::UniversalId::Type_Topics, "Topics",
|
||||
":./dialogue-topics.png" },
|
||||
":global-variable" },
|
||||
{ CSMWorld::UniversalId::Class_RecordList, CSMWorld::UniversalId::Type_Gmsts, "Game Settings", ":gmst" },
|
||||
{ CSMWorld::UniversalId::Class_RecordList, CSMWorld::UniversalId::Type_Skills, "Skills", ":skill" },
|
||||
{ CSMWorld::UniversalId::Class_RecordList, CSMWorld::UniversalId::Type_Classes, "Classes", ":class" },
|
||||
{ CSMWorld::UniversalId::Class_RecordList, CSMWorld::UniversalId::Type_Factions, "Factions", ":faction" },
|
||||
{ CSMWorld::UniversalId::Class_RecordList, CSMWorld::UniversalId::Type_Races, "Races", ":race" },
|
||||
{ CSMWorld::UniversalId::Class_RecordList, CSMWorld::UniversalId::Type_Sounds, "Sounds", ":sound" },
|
||||
{ CSMWorld::UniversalId::Class_RecordList, CSMWorld::UniversalId::Type_Scripts, "Scripts", ":script" },
|
||||
{ CSMWorld::UniversalId::Class_RecordList, CSMWorld::UniversalId::Type_Regions, "Regions", ":region" },
|
||||
{ CSMWorld::UniversalId::Class_RecordList, CSMWorld::UniversalId::Type_Birthsigns, "Birthsigns", ":birthsign" },
|
||||
{ CSMWorld::UniversalId::Class_RecordList, CSMWorld::UniversalId::Type_Spells, "Spells", ":spell" },
|
||||
{ CSMWorld::UniversalId::Class_RecordList, CSMWorld::UniversalId::Type_Topics, "Topics", ":dialogue-topics" },
|
||||
{ CSMWorld::UniversalId::Class_RecordList, CSMWorld::UniversalId::Type_Journals, "Journals",
|
||||
":./journal-topics.png" },
|
||||
":journal-topics" },
|
||||
{ CSMWorld::UniversalId::Class_RecordList, CSMWorld::UniversalId::Type_TopicInfos, "Topic Infos",
|
||||
":./dialogue-topic-infos.png" },
|
||||
":dialogue-info" },
|
||||
{ CSMWorld::UniversalId::Class_RecordList, CSMWorld::UniversalId::Type_JournalInfos, "Journal Infos",
|
||||
":./journal-topic-infos.png" },
|
||||
{ CSMWorld::UniversalId::Class_RecordList, CSMWorld::UniversalId::Type_Cells, "Cells", ":./cell.png" },
|
||||
":journal-topic-infos" },
|
||||
{ CSMWorld::UniversalId::Class_RecordList, CSMWorld::UniversalId::Type_Cells, "Cells", ":cell" },
|
||||
{ CSMWorld::UniversalId::Class_RecordList, CSMWorld::UniversalId::Type_Enchantments, "Enchantments",
|
||||
":./enchantment.png" },
|
||||
{ CSMWorld::UniversalId::Class_RecordList, CSMWorld::UniversalId::Type_BodyParts, "Body Parts",
|
||||
":./body-part.png" },
|
||||
{ CSMWorld::UniversalId::Class_RecordList, CSMWorld::UniversalId::Type_Referenceables, "Objects",
|
||||
":./object.png" },
|
||||
{ CSMWorld::UniversalId::Class_RecordList, CSMWorld::UniversalId::Type_References, "Instances",
|
||||
":./instance.png" },
|
||||
{ CSMWorld::UniversalId::Class_NonRecord, CSMWorld::UniversalId::Type_RegionMap, "Region Map",
|
||||
":./region-map.png" },
|
||||
{ CSMWorld::UniversalId::Class_RecordList, CSMWorld::UniversalId::Type_Filters, "Filters", ":./filter.png" },
|
||||
{ CSMWorld::UniversalId::Class_ResourceList, CSMWorld::UniversalId::Type_Meshes, "Meshes",
|
||||
":./resources-mesh" },
|
||||
{ CSMWorld::UniversalId::Class_ResourceList, CSMWorld::UniversalId::Type_Icons, "Icons", ":./resources-icon" },
|
||||
":enchantment" },
|
||||
{ CSMWorld::UniversalId::Class_RecordList, CSMWorld::UniversalId::Type_BodyParts, "Body Parts", ":body-part" },
|
||||
{ CSMWorld::UniversalId::Class_RecordList, CSMWorld::UniversalId::Type_Referenceables, "Objects", ":object" },
|
||||
{ CSMWorld::UniversalId::Class_RecordList, CSMWorld::UniversalId::Type_References, "Instances", ":instance" },
|
||||
{ CSMWorld::UniversalId::Class_NonRecord, CSMWorld::UniversalId::Type_RegionMap, "Region Map", ":region-map" },
|
||||
{ CSMWorld::UniversalId::Class_RecordList, CSMWorld::UniversalId::Type_Filters, "Filters", ":filter" },
|
||||
{ CSMWorld::UniversalId::Class_ResourceList, CSMWorld::UniversalId::Type_Meshes, "Meshes", ":resources-mesh" },
|
||||
{ CSMWorld::UniversalId::Class_ResourceList, CSMWorld::UniversalId::Type_Icons, "Icons", ":resources-icon" },
|
||||
{ CSMWorld::UniversalId::Class_ResourceList, CSMWorld::UniversalId::Type_Musics, "Music Files",
|
||||
":./resources-music" },
|
||||
":resources-music" },
|
||||
{ CSMWorld::UniversalId::Class_ResourceList, CSMWorld::UniversalId::Type_SoundsRes, "Sound Files",
|
||||
":resources-sound" },
|
||||
{ CSMWorld::UniversalId::Class_ResourceList, CSMWorld::UniversalId::Type_Textures, "Textures",
|
||||
":./resources-texture" },
|
||||
{ CSMWorld::UniversalId::Class_ResourceList, CSMWorld::UniversalId::Type_Videos, "Videos",
|
||||
":./resources-video" },
|
||||
":resources-texture" },
|
||||
{ CSMWorld::UniversalId::Class_ResourceList, CSMWorld::UniversalId::Type_Videos, "Videos", ":resources-video" },
|
||||
{ CSMWorld::UniversalId::Class_RecordList, CSMWorld::UniversalId::Type_DebugProfiles, "Debug Profiles",
|
||||
":./debug-profile.png" },
|
||||
":debug-profile" },
|
||||
{ CSMWorld::UniversalId::Class_RecordList, CSMWorld::UniversalId::Type_SelectionGroup, "Selection Groups", "" },
|
||||
{ CSMWorld::UniversalId::Class_Transient, CSMWorld::UniversalId::Type_RunLog, "Run Log", ":./run-log.png" },
|
||||
{ CSMWorld::UniversalId::Class_Transient, CSMWorld::UniversalId::Type_RunLog, "Run Log", ":run-log" },
|
||||
{ CSMWorld::UniversalId::Class_RecordList, CSMWorld::UniversalId::Type_SoundGens, "Sound Generators",
|
||||
":./sound-generator.png" },
|
||||
":sound-generator" },
|
||||
{ CSMWorld::UniversalId::Class_RecordList, CSMWorld::UniversalId::Type_MagicEffects, "Magic Effects",
|
||||
":./magic-effect.png" },
|
||||
{ CSMWorld::UniversalId::Class_RecordList, CSMWorld::UniversalId::Type_Lands, "Lands",
|
||||
":./land-heightmap.png" },
|
||||
":magic-effect" },
|
||||
{ CSMWorld::UniversalId::Class_RecordList, CSMWorld::UniversalId::Type_Lands, "Lands", ":land-heightmap" },
|
||||
{ CSMWorld::UniversalId::Class_RecordList, CSMWorld::UniversalId::Type_LandTextures, "Land Textures",
|
||||
":./land-texture.png" },
|
||||
{ CSMWorld::UniversalId::Class_RecordList, CSMWorld::UniversalId::Type_Pathgrids, "Pathgrids",
|
||||
":./pathgrid.png" },
|
||||
":land-texture" },
|
||||
{ CSMWorld::UniversalId::Class_RecordList, CSMWorld::UniversalId::Type_Pathgrids, "Pathgrids", ":pathgrid" },
|
||||
{ CSMWorld::UniversalId::Class_RecordList, CSMWorld::UniversalId::Type_StartScripts, "Start Scripts",
|
||||
":./start-script.png" },
|
||||
{ CSMWorld::UniversalId::Class_RecordList, CSMWorld::UniversalId::Type_MetaDatas, "Metadata",
|
||||
":./metadata.png" },
|
||||
":start-script" },
|
||||
{ CSMWorld::UniversalId::Class_RecordList, CSMWorld::UniversalId::Type_MetaDatas, "Metadata", ":metadata" },
|
||||
};
|
||||
|
||||
constexpr TypeData sIdArg[] = {
|
||||
{ CSMWorld::UniversalId::Class_Record, CSMWorld::UniversalId::Type_Global, "Global Variable",
|
||||
":./global-variable.png" },
|
||||
{ CSMWorld::UniversalId::Class_Record, CSMWorld::UniversalId::Type_Gmst, "Game Setting", ":./gmst.png" },
|
||||
{ CSMWorld::UniversalId::Class_Record, CSMWorld::UniversalId::Type_Skill, "Skill", ":./skill.png" },
|
||||
{ CSMWorld::UniversalId::Class_Record, CSMWorld::UniversalId::Type_Class, "Class", ":./class.png" },
|
||||
{ CSMWorld::UniversalId::Class_Record, CSMWorld::UniversalId::Type_Faction, "Faction", ":./faction.png" },
|
||||
{ CSMWorld::UniversalId::Class_Record, CSMWorld::UniversalId::Type_Race, "Race", ":./race.png" },
|
||||
{ CSMWorld::UniversalId::Class_Record, CSMWorld::UniversalId::Type_Sound, "Sound", ":./sound.png" },
|
||||
{ CSMWorld::UniversalId::Class_Record, CSMWorld::UniversalId::Type_Script, "Script", ":./script.png" },
|
||||
{ CSMWorld::UniversalId::Class_Record, CSMWorld::UniversalId::Type_Region, "Region", ":./region.png" },
|
||||
{ CSMWorld::UniversalId::Class_Record, CSMWorld::UniversalId::Type_Birthsign, "Birthsign", ":./birthsign.png" },
|
||||
{ CSMWorld::UniversalId::Class_Record, CSMWorld::UniversalId::Type_Spell, "Spell", ":./spell.png" },
|
||||
{ CSMWorld::UniversalId::Class_Record, CSMWorld::UniversalId::Type_Topic, "Topic", ":./dialogue-topics.png" },
|
||||
{ CSMWorld::UniversalId::Class_Record, CSMWorld::UniversalId::Type_Journal, "Journal",
|
||||
":./journal-topics.png" },
|
||||
":global-variable" },
|
||||
{ CSMWorld::UniversalId::Class_Record, CSMWorld::UniversalId::Type_Gmst, "Game Setting", ":gmst" },
|
||||
{ CSMWorld::UniversalId::Class_Record, CSMWorld::UniversalId::Type_Skill, "Skill", ":skill" },
|
||||
{ CSMWorld::UniversalId::Class_Record, CSMWorld::UniversalId::Type_Class, "Class", ":class" },
|
||||
{ CSMWorld::UniversalId::Class_Record, CSMWorld::UniversalId::Type_Faction, "Faction", ":faction" },
|
||||
{ CSMWorld::UniversalId::Class_Record, CSMWorld::UniversalId::Type_Race, "Race", ":race" },
|
||||
{ CSMWorld::UniversalId::Class_Record, CSMWorld::UniversalId::Type_Sound, "Sound", ":sound" },
|
||||
{ CSMWorld::UniversalId::Class_Record, CSMWorld::UniversalId::Type_Script, "Script", ":script" },
|
||||
{ CSMWorld::UniversalId::Class_Record, CSMWorld::UniversalId::Type_Region, "Region", ":region" },
|
||||
{ CSMWorld::UniversalId::Class_Record, CSMWorld::UniversalId::Type_Birthsign, "Birthsign", ":birthsign" },
|
||||
{ CSMWorld::UniversalId::Class_Record, CSMWorld::UniversalId::Type_Spell, "Spell", ":spell" },
|
||||
{ CSMWorld::UniversalId::Class_Record, CSMWorld::UniversalId::Type_Topic, "Topic", ":dialogue-topics" },
|
||||
{ CSMWorld::UniversalId::Class_Record, CSMWorld::UniversalId::Type_Journal, "Journal", ":journal-topics" },
|
||||
{ CSMWorld::UniversalId::Class_SubRecord, CSMWorld::UniversalId::Type_TopicInfo, "TopicInfo",
|
||||
":./dialogue-topic-infos.png" },
|
||||
":dialogue-info" },
|
||||
{ CSMWorld::UniversalId::Class_SubRecord, CSMWorld::UniversalId::Type_JournalInfo, "JournalInfo",
|
||||
":./journal-topic-infos.png" },
|
||||
{ CSMWorld::UniversalId::Class_Record, CSMWorld::UniversalId::Type_Cell, "Cell", ":./cell.png" },
|
||||
{ CSMWorld::UniversalId::Class_Record, CSMWorld::UniversalId::Type_Cell_Missing, "Cell", ":./cell.png" },
|
||||
{ CSMWorld::UniversalId::Class_Record, CSMWorld::UniversalId::Type_Referenceable, "Object", ":./object.png" },
|
||||
{ CSMWorld::UniversalId::Class_RefRecord, CSMWorld::UniversalId::Type_Activator, "Activator",
|
||||
":./activator.png" },
|
||||
{ CSMWorld::UniversalId::Class_RefRecord, CSMWorld::UniversalId::Type_Potion, "Potion", ":./potion.png" },
|
||||
{ CSMWorld::UniversalId::Class_RefRecord, CSMWorld::UniversalId::Type_Apparatus, "Apparatus",
|
||||
":./apparatus.png" },
|
||||
{ CSMWorld::UniversalId::Class_RefRecord, CSMWorld::UniversalId::Type_Armor, "Armor", ":./armor.png" },
|
||||
{ CSMWorld::UniversalId::Class_RefRecord, CSMWorld::UniversalId::Type_Book, "Book", ":./book.png" },
|
||||
{ CSMWorld::UniversalId::Class_RefRecord, CSMWorld::UniversalId::Type_Clothing, "Clothing", ":./clothing.png" },
|
||||
{ CSMWorld::UniversalId::Class_RefRecord, CSMWorld::UniversalId::Type_Container, "Container",
|
||||
":./container.png" },
|
||||
{ CSMWorld::UniversalId::Class_RefRecord, CSMWorld::UniversalId::Type_Creature, "Creature", ":./creature.png" },
|
||||
{ CSMWorld::UniversalId::Class_RefRecord, CSMWorld::UniversalId::Type_Door, "Door", ":./door.png" },
|
||||
{ CSMWorld::UniversalId::Class_RefRecord, CSMWorld::UniversalId::Type_Ingredient, "Ingredient",
|
||||
":./ingredient.png" },
|
||||
":journal-topic-infos" },
|
||||
{ CSMWorld::UniversalId::Class_Record, CSMWorld::UniversalId::Type_Cell, "Cell", ":cell" },
|
||||
{ CSMWorld::UniversalId::Class_Record, CSMWorld::UniversalId::Type_Cell_Missing, "Cell", ":cell" },
|
||||
{ CSMWorld::UniversalId::Class_Record, CSMWorld::UniversalId::Type_Referenceable, "Object", ":object" },
|
||||
{ CSMWorld::UniversalId::Class_RefRecord, CSMWorld::UniversalId::Type_Activator, "Activator", ":activator" },
|
||||
{ CSMWorld::UniversalId::Class_RefRecord, CSMWorld::UniversalId::Type_Potion, "Potion", ":potion" },
|
||||
{ CSMWorld::UniversalId::Class_RefRecord, CSMWorld::UniversalId::Type_Apparatus, "Apparatus", ":apparatus" },
|
||||
{ CSMWorld::UniversalId::Class_RefRecord, CSMWorld::UniversalId::Type_Armor, "Armor", ":armor" },
|
||||
{ CSMWorld::UniversalId::Class_RefRecord, CSMWorld::UniversalId::Type_Book, "Book", ":book" },
|
||||
{ CSMWorld::UniversalId::Class_RefRecord, CSMWorld::UniversalId::Type_Clothing, "Clothing", ":clothing" },
|
||||
{ CSMWorld::UniversalId::Class_RefRecord, CSMWorld::UniversalId::Type_Container, "Container", ":container" },
|
||||
{ CSMWorld::UniversalId::Class_RefRecord, CSMWorld::UniversalId::Type_Creature, "Creature", ":creature" },
|
||||
{ CSMWorld::UniversalId::Class_RefRecord, CSMWorld::UniversalId::Type_Door, "Door", ":door" },
|
||||
{ CSMWorld::UniversalId::Class_RefRecord, CSMWorld::UniversalId::Type_Ingredient, "Ingredient", ":ingredient" },
|
||||
{ CSMWorld::UniversalId::Class_RefRecord, CSMWorld::UniversalId::Type_CreatureLevelledList,
|
||||
"Creature Levelled List", ":./levelled-creature.png" },
|
||||
"Creature Levelled List", ":levelled-creature" },
|
||||
{ CSMWorld::UniversalId::Class_RefRecord, CSMWorld::UniversalId::Type_ItemLevelledList, "Item Levelled List",
|
||||
":./levelled-item.png" },
|
||||
{ CSMWorld::UniversalId::Class_RefRecord, CSMWorld::UniversalId::Type_Light, "Light", ":./light.png" },
|
||||
{ CSMWorld::UniversalId::Class_RefRecord, CSMWorld::UniversalId::Type_Lockpick, "Lockpick", ":./lockpick.png" },
|
||||
":levelled-item" },
|
||||
{ CSMWorld::UniversalId::Class_RefRecord, CSMWorld::UniversalId::Type_Light, "Light", ":light" },
|
||||
{ CSMWorld::UniversalId::Class_RefRecord, CSMWorld::UniversalId::Type_Lockpick, "Lockpick", ":lockpick" },
|
||||
{ CSMWorld::UniversalId::Class_RefRecord, CSMWorld::UniversalId::Type_Miscellaneous, "Miscellaneous",
|
||||
":./miscellaneous.png" },
|
||||
{ CSMWorld::UniversalId::Class_RefRecord, CSMWorld::UniversalId::Type_Npc, "NPC", ":./npc.png" },
|
||||
{ CSMWorld::UniversalId::Class_RefRecord, CSMWorld::UniversalId::Type_Probe, "Probe", ":./probe.png" },
|
||||
{ CSMWorld::UniversalId::Class_RefRecord, CSMWorld::UniversalId::Type_Repair, "Repair", ":./repair.png" },
|
||||
{ CSMWorld::UniversalId::Class_RefRecord, CSMWorld::UniversalId::Type_Static, "Static", ":./static.png" },
|
||||
{ CSMWorld::UniversalId::Class_RefRecord, CSMWorld::UniversalId::Type_Weapon, "Weapon", ":./weapon.png" },
|
||||
{ CSMWorld::UniversalId::Class_SubRecord, CSMWorld::UniversalId::Type_Reference, "Instance",
|
||||
":./instance.png" },
|
||||
{ CSMWorld::UniversalId::Class_Record, CSMWorld::UniversalId::Type_Filter, "Filter", ":./filter.png" },
|
||||
{ CSMWorld::UniversalId::Class_Collection, CSMWorld::UniversalId::Type_Scene, "Scene", ":./scene.png" },
|
||||
{ CSMWorld::UniversalId::Class_Collection, CSMWorld::UniversalId::Type_Preview, "Preview",
|
||||
":./record-preview.png" },
|
||||
{ CSMWorld::UniversalId::Class_Record, CSMWorld::UniversalId::Type_Enchantment, "Enchantment",
|
||||
":./enchantment.png" },
|
||||
{ CSMWorld::UniversalId::Class_Record, CSMWorld::UniversalId::Type_BodyPart, "Body Part", ":./body-part.png" },
|
||||
{ CSMWorld::UniversalId::Class_Resource, CSMWorld::UniversalId::Type_Mesh, "Mesh", ":./resources-mesh" },
|
||||
{ CSMWorld::UniversalId::Class_Resource, CSMWorld::UniversalId::Type_Icon, "Icon", ":./resources-icon" },
|
||||
{ CSMWorld::UniversalId::Class_Resource, CSMWorld::UniversalId::Type_Music, "Music", ":./resources-music" },
|
||||
":miscellaneous" },
|
||||
{ CSMWorld::UniversalId::Class_RefRecord, CSMWorld::UniversalId::Type_Npc, "NPC", ":npc" },
|
||||
{ CSMWorld::UniversalId::Class_RefRecord, CSMWorld::UniversalId::Type_Probe, "Probe", ":probe" },
|
||||
{ CSMWorld::UniversalId::Class_RefRecord, CSMWorld::UniversalId::Type_Repair, "Repair", ":repair" },
|
||||
{ CSMWorld::UniversalId::Class_RefRecord, CSMWorld::UniversalId::Type_Static, "Static", ":static" },
|
||||
{ CSMWorld::UniversalId::Class_RefRecord, CSMWorld::UniversalId::Type_Weapon, "Weapon", ":weapon" },
|
||||
{ CSMWorld::UniversalId::Class_SubRecord, CSMWorld::UniversalId::Type_Reference, "Instance", ":instance" },
|
||||
{ CSMWorld::UniversalId::Class_Record, CSMWorld::UniversalId::Type_Filter, "Filter", ":filter" },
|
||||
{ CSMWorld::UniversalId::Class_Collection, CSMWorld::UniversalId::Type_Scene, "Scene", ":scene" },
|
||||
{ CSMWorld::UniversalId::Class_Collection, CSMWorld::UniversalId::Type_Preview, "Preview", ":edit-preview" },
|
||||
{ CSMWorld::UniversalId::Class_Record, CSMWorld::UniversalId::Type_Enchantment, "Enchantment", ":enchantment" },
|
||||
{ CSMWorld::UniversalId::Class_Record, CSMWorld::UniversalId::Type_BodyPart, "Body Part", ":body-part" },
|
||||
{ CSMWorld::UniversalId::Class_Resource, CSMWorld::UniversalId::Type_Mesh, "Mesh", ":resources-mesh" },
|
||||
{ CSMWorld::UniversalId::Class_Resource, CSMWorld::UniversalId::Type_Icon, "Icon", ":resources-icon" },
|
||||
{ CSMWorld::UniversalId::Class_Resource, CSMWorld::UniversalId::Type_Music, "Music", ":resources-music" },
|
||||
{ CSMWorld::UniversalId::Class_Resource, CSMWorld::UniversalId::Type_SoundRes, "Sound File",
|
||||
":./resources-sound" },
|
||||
{ CSMWorld::UniversalId::Class_Resource, CSMWorld::UniversalId::Type_Texture, "Texture",
|
||||
":./resources-texture" },
|
||||
{ CSMWorld::UniversalId::Class_Resource, CSMWorld::UniversalId::Type_Video, "Video", ":./resources-video" },
|
||||
":resources-sound" },
|
||||
{ CSMWorld::UniversalId::Class_Resource, CSMWorld::UniversalId::Type_Texture, "Texture", ":resources-texture" },
|
||||
{ CSMWorld::UniversalId::Class_Resource, CSMWorld::UniversalId::Type_Video, "Video", ":resources-video" },
|
||||
{ CSMWorld::UniversalId::Class_Record, CSMWorld::UniversalId::Type_DebugProfile, "Debug Profile",
|
||||
":./debug-profile.png" },
|
||||
":debug-profile" },
|
||||
{ CSMWorld::UniversalId::Class_Record, CSMWorld::UniversalId::Type_SoundGen, "Sound Generator",
|
||||
":./sound-generator.png" },
|
||||
":sound-generator" },
|
||||
{ CSMWorld::UniversalId::Class_Record, CSMWorld::UniversalId::Type_MagicEffect, "Magic Effect",
|
||||
":./magic-effect.png" },
|
||||
{ CSMWorld::UniversalId::Class_Record, CSMWorld::UniversalId::Type_Land, "Land", ":./land-heightmap.png" },
|
||||
":magic-effect" },
|
||||
{ CSMWorld::UniversalId::Class_Record, CSMWorld::UniversalId::Type_Land, "Land", ":land-heightmap" },
|
||||
{ CSMWorld::UniversalId::Class_Record, CSMWorld::UniversalId::Type_LandTexture, "Land Texture",
|
||||
":./land-texture.png" },
|
||||
{ CSMWorld::UniversalId::Class_Record, CSMWorld::UniversalId::Type_Pathgrid, "Pathgrid", ":./pathgrid.png" },
|
||||
":land-texture" },
|
||||
{ CSMWorld::UniversalId::Class_Record, CSMWorld::UniversalId::Type_Pathgrid, "Pathgrid", ":pathgrid" },
|
||||
{ CSMWorld::UniversalId::Class_Record, CSMWorld::UniversalId::Type_StartScript, "Start Script",
|
||||
":./start-script.png" },
|
||||
{ CSMWorld::UniversalId::Class_Record, CSMWorld::UniversalId::Type_MetaData, "Metadata", ":./metadata.png" },
|
||||
":start-script" },
|
||||
{ CSMWorld::UniversalId::Class_Record, CSMWorld::UniversalId::Type_MetaData, "Metadata", ":metadata" },
|
||||
};
|
||||
|
||||
constexpr TypeData sIndexArg[] = {
|
||||
{ CSMWorld::UniversalId::Class_Transient, CSMWorld::UniversalId::Type_VerificationResults,
|
||||
"Verification Results", ":./menu-verify.png" },
|
||||
"Verification Results", ":menu-verify" },
|
||||
{ CSMWorld::UniversalId::Class_Transient, CSMWorld::UniversalId::Type_LoadErrorLog, "Load Error Log",
|
||||
":./error-log.png" },
|
||||
{ CSMWorld::UniversalId::Class_Transient, CSMWorld::UniversalId::Type_Search, "Global Search",
|
||||
":./menu-search.png" },
|
||||
":error-log" },
|
||||
{ CSMWorld::UniversalId::Class_Transient, CSMWorld::UniversalId::Type_Search, "Global Search", ":menu-search" },
|
||||
};
|
||||
|
||||
struct WriteToStream
|
||||
|
@ -10,7 +10,7 @@
|
||||
#include <QScreen>
|
||||
#include <QVBoxLayout>
|
||||
|
||||
QPushButton* CSVDoc::StartupDialogue::addButton(const QString& label, const QIcon& icon)
|
||||
QPushButton* CSVDoc::StartupDialogue::addButton(const QString& label, const QString& icon)
|
||||
{
|
||||
int column = mColumn--;
|
||||
|
||||
@ -39,13 +39,13 @@ QWidget* CSVDoc::StartupDialogue::createButtons()
|
||||
mLayout = new QGridLayout(widget);
|
||||
|
||||
/// \todo add icons
|
||||
QPushButton* loadDocument = addButton("Edit A Content File", QIcon(":startup/edit-content"));
|
||||
QPushButton* loadDocument = addButton("Edit A Content File", ":startup/edit-content");
|
||||
connect(loadDocument, &QPushButton::clicked, this, &StartupDialogue::loadDocument);
|
||||
|
||||
QPushButton* createAddon = addButton("Create A New Addon", QIcon(":startup/create-addon"));
|
||||
QPushButton* createAddon = addButton("Create A New Addon", ":startup/create-addon");
|
||||
connect(createAddon, &QPushButton::clicked, this, &StartupDialogue::createAddon);
|
||||
|
||||
QPushButton* createGame = addButton("Create A New Game", QIcon(":startup/create-game"));
|
||||
QPushButton* createGame = addButton("Create A New Game", ":startup/create-game");
|
||||
connect(createGame, &QPushButton::clicked, this, &StartupDialogue::createGame);
|
||||
|
||||
for (int i = 0; i < 3; ++i)
|
||||
|
@ -20,7 +20,7 @@ namespace CSVDoc
|
||||
int mColumn;
|
||||
QGridLayout* mLayout;
|
||||
|
||||
QPushButton* addButton(const QString& label, const QIcon& icon);
|
||||
QPushButton* addButton(const QString& label, const QString& icon);
|
||||
|
||||
QWidget* createButtons();
|
||||
|
||||
|
@ -71,30 +71,30 @@ void CSVDoc::View::setupFileMenu()
|
||||
{
|
||||
QMenu* file = menuBar()->addMenu(tr("File"));
|
||||
|
||||
QAction* newGame = createMenuEntry("New Game", ":./menu-new-game.png", file, "document-file-newgame");
|
||||
QAction* newGame = createMenuEntry("New Game", ":menu-new-game", file, "document-file-newgame");
|
||||
connect(newGame, &QAction::triggered, this, &View::newGameRequest);
|
||||
|
||||
QAction* newAddon = createMenuEntry("New Addon", ":./menu-new-addon.png", file, "document-file-newaddon");
|
||||
QAction* newAddon = createMenuEntry("New Addon", ":menu-new-addon", file, "document-file-newaddon");
|
||||
connect(newAddon, &QAction::triggered, this, &View::newAddonRequest);
|
||||
|
||||
QAction* open = createMenuEntry("Open", ":./menu-open.png", file, "document-file-open");
|
||||
QAction* open = createMenuEntry("Open", ":menu-open", file, "document-file-open");
|
||||
connect(open, &QAction::triggered, this, &View::loadDocumentRequest);
|
||||
|
||||
QAction* save = createMenuEntry("Save", ":./menu-save.png", file, "document-file-save");
|
||||
QAction* save = createMenuEntry("Save", ":menu-save", file, "document-file-save");
|
||||
connect(save, &QAction::triggered, this, &View::save);
|
||||
mSave = save;
|
||||
|
||||
file->addSeparator();
|
||||
|
||||
QAction* verify = createMenuEntry("Verify", ":./menu-verify.png", file, "document-file-verify");
|
||||
QAction* verify = createMenuEntry("Verify", ":menu-verify", file, "document-file-verify");
|
||||
connect(verify, &QAction::triggered, this, &View::verify);
|
||||
mVerify = verify;
|
||||
|
||||
QAction* merge = createMenuEntry("Merge", ":./menu-merge.png", file, "document-file-merge");
|
||||
QAction* merge = createMenuEntry("Merge", ":menu-merge", file, "document-file-merge");
|
||||
connect(merge, &QAction::triggered, this, &View::merge);
|
||||
mMerge = merge;
|
||||
|
||||
QAction* loadErrors = createMenuEntry("Error Log", ":./error-log.png", file, "document-file-errorlog");
|
||||
QAction* loadErrors = createMenuEntry("Error Log", ":error-log", file, "document-file-errorlog");
|
||||
connect(loadErrors, &QAction::triggered, this, &View::loadErrorLog);
|
||||
|
||||
QAction* meta = createMenuEntry(CSMWorld::UniversalId::Type_MetaDatas, file, "document-file-metadata");
|
||||
@ -102,10 +102,10 @@ void CSVDoc::View::setupFileMenu()
|
||||
|
||||
file->addSeparator();
|
||||
|
||||
QAction* close = createMenuEntry("Close", ":./menu-close.png", file, "document-file-close");
|
||||
QAction* close = createMenuEntry("Close", ":menu-close", file, "document-file-close");
|
||||
connect(close, &QAction::triggered, this, &View::close);
|
||||
|
||||
QAction* exit = createMenuEntry("Exit", ":./menu-exit.png", file, "document-file-exit");
|
||||
QAction* exit = createMenuEntry("Exit", ":menu-exit", file, "document-file-exit");
|
||||
connect(exit, &QAction::triggered, this, &View::exit);
|
||||
|
||||
connect(this, &View::exitApplicationRequest, &mViewManager, &ViewManager::exitApplication);
|
||||
@ -140,17 +140,16 @@ void CSVDoc::View::setupEditMenu()
|
||||
mUndo = mDocument->getUndoStack().createUndoAction(this, tr("Undo"));
|
||||
setupShortcut("document-edit-undo", mUndo);
|
||||
connect(mUndo, &QAction::changed, this, &View::undoActionChanged);
|
||||
mUndo->setIcon(QIcon(QString::fromStdString(":./menu-undo.png")));
|
||||
mUndo->setIcon(QIcon(QString::fromStdString(":menu-undo")));
|
||||
edit->addAction(mUndo);
|
||||
|
||||
mRedo = mDocument->getUndoStack().createRedoAction(this, tr("Redo"));
|
||||
connect(mRedo, &QAction::changed, this, &View::redoActionChanged);
|
||||
setupShortcut("document-edit-redo", mRedo);
|
||||
mRedo->setIcon(QIcon(QString::fromStdString(":./menu-redo.png")));
|
||||
mRedo->setIcon(QIcon(QString::fromStdString(":menu-redo")));
|
||||
edit->addAction(mRedo);
|
||||
|
||||
QAction* userSettings
|
||||
= createMenuEntry("Preferences", ":./menu-preferences.png", edit, "document-edit-preferences");
|
||||
QAction* userSettings = createMenuEntry("Preferences", ":menu-preferences", edit, "document-edit-preferences");
|
||||
connect(userSettings, &QAction::triggered, this, &View::editSettingsRequest);
|
||||
|
||||
QAction* search = createMenuEntry(CSMWorld::UniversalId::Type_Search, edit, "document-edit-search");
|
||||
@ -161,10 +160,10 @@ void CSVDoc::View::setupViewMenu()
|
||||
{
|
||||
QMenu* view = menuBar()->addMenu(tr("View"));
|
||||
|
||||
QAction* newWindow = createMenuEntry("New View", ":./menu-new-window.png", view, "document-view-newview");
|
||||
QAction* newWindow = createMenuEntry("New View", ":menu-new-window", view, "document-view-newview");
|
||||
connect(newWindow, &QAction::triggered, this, &View::newView);
|
||||
|
||||
mShowStatusBar = createMenuEntry("Toggle Status Bar", ":./menu-status-bar.png", view, "document-view-statusbar");
|
||||
mShowStatusBar = createMenuEntry("Toggle Status Bar", ":menu-status-bar", view, "document-view-statusbar");
|
||||
connect(mShowStatusBar, &QAction::toggled, this, &View::toggleShowStatusBar);
|
||||
mShowStatusBar->setCheckable(true);
|
||||
mShowStatusBar->setChecked(CSMPrefs::get()["Windows"]["show-statusbar"].isTrue());
|
||||
@ -289,7 +288,7 @@ void CSVDoc::View::setupAssetsMenu()
|
||||
{
|
||||
QMenu* assets = menuBar()->addMenu(tr("Assets"));
|
||||
|
||||
QAction* reload = createMenuEntry("Reload", ":./menu-reload.png", assets, "document-assets-reload");
|
||||
QAction* reload = createMenuEntry("Reload", ":menu-reload", assets, "document-assets-reload");
|
||||
connect(reload, &QAction::triggered, &mDocument->getData(), &CSMWorld::Data::assetsChanged);
|
||||
|
||||
assets->addSeparator();
|
||||
@ -341,9 +340,9 @@ void CSVDoc::View::setupDebugMenu()
|
||||
QAction* runDebug = debug->addMenu(mGlobalDebugProfileMenu);
|
||||
runDebug->setText(tr("Run OpenMW"));
|
||||
setupShortcut("document-debug-run", runDebug);
|
||||
runDebug->setIcon(QIcon(QString::fromStdString(":./run-openmw.png")));
|
||||
runDebug->setIcon(QIcon(QString::fromStdString(":run-openmw")));
|
||||
|
||||
QAction* stopDebug = createMenuEntry("Stop OpenMW", ":./stop-openmw.png", debug, "document-debug-shutdown");
|
||||
QAction* stopDebug = createMenuEntry("Stop OpenMW", ":stop-openmw", debug, "document-debug-shutdown");
|
||||
connect(stopDebug, &QAction::triggered, this, &View::stop);
|
||||
mStopDebug = stopDebug;
|
||||
|
||||
@ -355,16 +354,16 @@ void CSVDoc::View::setupHelpMenu()
|
||||
{
|
||||
QMenu* help = menuBar()->addMenu(tr("Help"));
|
||||
|
||||
QAction* helpInfo = createMenuEntry("Help", ":/info.png", help, "document-help-help");
|
||||
QAction* helpInfo = createMenuEntry("Help", ":info", help, "document-help-help");
|
||||
connect(helpInfo, &QAction::triggered, this, &View::openHelp);
|
||||
|
||||
QAction* tutorial = createMenuEntry("Tutorial", ":/info.png", help, "document-help-tutorial");
|
||||
QAction* tutorial = createMenuEntry("Tutorial", ":info", help, "document-help-tutorial");
|
||||
connect(tutorial, &QAction::triggered, this, &View::tutorial);
|
||||
|
||||
QAction* about = createMenuEntry("About OpenMW-CS", ":./info.png", help, "document-help-about");
|
||||
QAction* about = createMenuEntry("About OpenMW-CS", ":info", help, "document-help-about");
|
||||
connect(about, &QAction::triggered, this, &View::infoAbout);
|
||||
|
||||
QAction* aboutQt = createMenuEntry("About Qt", ":./qt.png", help, "document-help-qt");
|
||||
QAction* aboutQt = createMenuEntry("About Qt", ":qt", help, "document-help-qt");
|
||||
connect(aboutQt, &QAction::triggered, this, &View::infoAboutQt);
|
||||
}
|
||||
|
||||
@ -1111,7 +1110,16 @@ void CSVDoc::View::updateWidth(bool isGrowLimit, int minSubViewWidth)
|
||||
{
|
||||
QRect rect;
|
||||
if (isGrowLimit)
|
||||
rect = QApplication::screenAt(pos())->geometry();
|
||||
{
|
||||
// Widget position can be negative, we should clamp it.
|
||||
QPoint position = pos();
|
||||
if (position.x() <= 0)
|
||||
position.setX(0);
|
||||
if (position.y() <= 0)
|
||||
position.setY(0);
|
||||
|
||||
rect = QApplication::screenAt(position)->geometry();
|
||||
}
|
||||
else
|
||||
rect = desktopRect();
|
||||
|
||||
|
@ -44,7 +44,7 @@ CSVFilter::EditWidget::EditWidget(CSMWorld::Data& data, QWidget* parent)
|
||||
|
||||
mHelpAction = new QAction(tr("Help"), this);
|
||||
connect(mHelpAction, &QAction::triggered, this, &EditWidget::openHelp);
|
||||
mHelpAction->setIcon(QIcon(":/info.png"));
|
||||
mHelpAction->setIcon(QIcon(":info"));
|
||||
addAction(mHelpAction);
|
||||
auto* openHelpShortcut = new CSMPrefs::Shortcut("help", this);
|
||||
openHelpShortcut->associateAction(mHelpAction);
|
||||
|
@ -7,6 +7,7 @@
|
||||
#include <osg/Group>
|
||||
#include <osg/MatrixTransform>
|
||||
#include <osg/Node>
|
||||
#include <osg/Vec3d>
|
||||
|
||||
#include <apps/opencs/model/world/actoradapter.hpp>
|
||||
#include <apps/opencs/model/world/idcollection.hpp>
|
||||
@ -29,7 +30,7 @@ namespace CSVRender
|
||||
Actor::Actor(const ESM::RefId& id, CSMWorld::Data& data)
|
||||
: mId(id)
|
||||
, mData(data)
|
||||
, mBaseNode(new osg::Group())
|
||||
, mBaseNode(new osg::PositionAttitudeTransform())
|
||||
, mSkeleton(nullptr)
|
||||
{
|
||||
mActorData = mData.getActorAdapter()->getActorData(mId);
|
||||
@ -60,6 +61,10 @@ namespace CSVRender
|
||||
|
||||
// Attach parts to skeleton
|
||||
loadBodyParts();
|
||||
|
||||
const osg::Vec2f& attributes = mActorData->getRaceWeightHeight();
|
||||
|
||||
mBaseNode->setScale(osg::Vec3d(attributes.x(), attributes.x(), attributes.y()));
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -5,6 +5,7 @@
|
||||
#include <string_view>
|
||||
|
||||
#include <osg/Group>
|
||||
#include <osg/PositionAttitudeTransform>
|
||||
#include <osg/ref_ptr>
|
||||
|
||||
#include <QObject>
|
||||
@ -59,9 +60,9 @@ namespace CSVRender
|
||||
CSMWorld::Data& mData;
|
||||
CSMWorld::ActorAdapter::ActorDataPtr mActorData;
|
||||
|
||||
osg::ref_ptr<osg::Group> mBaseNode;
|
||||
osg::ref_ptr<osg::PositionAttitudeTransform> mBaseNode;
|
||||
SceneUtil::Skeleton* mSkeleton;
|
||||
SceneUtil::NodeMapVisitor::NodeMap mNodeMap;
|
||||
SceneUtil::NodeMap mNodeMap;
|
||||
};
|
||||
}
|
||||
|
||||
|
@ -8,7 +8,7 @@
|
||||
class QWidget;
|
||||
|
||||
CSVRender::InstanceMoveMode::InstanceMoveMode(QWidget* parent)
|
||||
: ModeButton(QIcon(QPixmap(":scenetoolbar/transform-move")),
|
||||
: ModeButton(QIcon(":scenetoolbar/transform-move"),
|
||||
"Move selected instances"
|
||||
"<ul><li>Use {scene-edit-primary} to move instances around freely</li>"
|
||||
"<li>Use {scene-edit-secondary} to move instances around within the grid</li>"
|
||||
|
@ -58,7 +58,8 @@ namespace CSVRender
|
||||
|
||||
InstanceSelectionMode::~InstanceSelectionMode()
|
||||
{
|
||||
mParentNode->removeChild(mBaseNode);
|
||||
if (mBaseNode)
|
||||
mParentNode->removeChild(mBaseNode);
|
||||
}
|
||||
|
||||
void InstanceSelectionMode::setDragStart(const osg::Vec3d& dragStart)
|
||||
|
@ -12,11 +12,10 @@ namespace CSVRender
|
||||
{
|
||||
// elements that are part of the actual scene
|
||||
Mask_Hidden = 0x0,
|
||||
Mask_Reference = 0x2,
|
||||
Mask_Pathgrid = 0x4,
|
||||
Mask_Water = 0x8,
|
||||
Mask_Fog = 0x10,
|
||||
Mask_Terrain = 0x20,
|
||||
Mask_Reference = 0x1,
|
||||
Mask_Pathgrid = 0x2,
|
||||
Mask_Water = 0x4,
|
||||
Mask_Terrain = 0x8,
|
||||
|
||||
// used within models
|
||||
Mask_ParticleSystem = 0x100,
|
||||
|
@ -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"
|
||||
|
@ -160,7 +160,6 @@ void CSVRender::PagedWorldspaceWidget::addVisibilitySelectorButtons(CSVWidget::S
|
||||
{
|
||||
WorldspaceWidget::addVisibilitySelectorButtons(tool);
|
||||
tool->addButton(Button_Terrain, Mask_Terrain, "Terrain");
|
||||
tool->addButton(Button_Fog, Mask_Fog, "Fog", "", true);
|
||||
}
|
||||
|
||||
void CSVRender::PagedWorldspaceWidget::addEditModeSelectorButtons(CSVWidget::SceneToolMode* tool)
|
||||
@ -170,9 +169,10 @@ void CSVRender::PagedWorldspaceWidget::addEditModeSelectorButtons(CSVWidget::Sce
|
||||
/// \todo replace EditMode with suitable subclasses
|
||||
tool->addButton(new TerrainShapeMode(this, mRootNode, tool), "terrain-shape");
|
||||
tool->addButton(new TerrainTextureMode(this, mRootNode, tool), "terrain-texture");
|
||||
tool->addButton(
|
||||
new EditMode(this, QIcon(":placeholder"), Mask_Reference, "Terrain vertex paint editing"), "terrain-vertex");
|
||||
tool->addButton(new EditMode(this, QIcon(":placeholder"), Mask_Reference, "Terrain movement"), "terrain-move");
|
||||
const QIcon vertexIcon = QIcon(":scenetoolbar/editing-terrain-vertex-paint");
|
||||
const QIcon movementIcon = QIcon(":scenetoolbar/editing-terrain-movement");
|
||||
tool->addButton(new EditMode(this, vertexIcon, Mask_Reference, "Terrain vertex paint editing"), "terrain-vertex");
|
||||
tool->addButton(new EditMode(this, movementIcon, Mask_Reference, "Terrain movement"), "terrain-move");
|
||||
}
|
||||
|
||||
void CSVRender::PagedWorldspaceWidget::handleInteractionPress(const WorldspaceHitResult& hit, InteractionType type)
|
||||
|
@ -36,8 +36,8 @@ class QWidget;
|
||||
namespace CSVRender
|
||||
{
|
||||
PathgridMode::PathgridMode(WorldspaceWidget* worldspaceWidget, QWidget* parent)
|
||||
: EditMode(worldspaceWidget, QIcon(":placeholder"), Mask_Pathgrid | Mask_Terrain | Mask_Reference, getTooltip(),
|
||||
parent)
|
||||
: EditMode(worldspaceWidget, QIcon(":scenetoolbar/editing-pathgrid"),
|
||||
Mask_Pathgrid | Mask_Terrain | Mask_Reference, getTooltip(), parent)
|
||||
, mDragMode(DragMode_None)
|
||||
, mFromNode(0)
|
||||
, mSelectionMode(nullptr)
|
||||
|
@ -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);
|
||||
|
@ -347,7 +347,6 @@ void CSVRender::UnpagedWorldspaceWidget::addVisibilitySelectorButtons(CSVWidget:
|
||||
{
|
||||
WorldspaceWidget::addVisibilitySelectorButtons(tool);
|
||||
tool->addButton(Button_Terrain, Mask_Terrain, "Terrain", "", true);
|
||||
tool->addButton(Button_Fog, Mask_Fog, "Fog");
|
||||
}
|
||||
|
||||
std::string CSVRender::UnpagedWorldspaceWidget::getStartupInstruction()
|
||||
|
@ -222,8 +222,7 @@ namespace CSVRender
|
||||
Button_Reference = 0x1,
|
||||
Button_Pathgrid = 0x2,
|
||||
Button_Water = 0x4,
|
||||
Button_Fog = 0x8,
|
||||
Button_Terrain = 0x10
|
||||
Button_Terrain = 0x8
|
||||
};
|
||||
|
||||
virtual void addVisibilitySelectorButtons(CSVWidget::SceneToolToggle2* tool);
|
||||
|
@ -94,7 +94,7 @@ void CSVWidget::SceneToolMode::showPanel(const QPoint& position)
|
||||
|
||||
void CSVWidget::SceneToolMode::addButton(const std::string& icon, const std::string& id, const QString& tooltip)
|
||||
{
|
||||
ModeButton* button = new ModeButton(QIcon(QPixmap(icon.c_str())), tooltip, mPanel);
|
||||
ModeButton* button = new ModeButton(QIcon(icon.c_str()), tooltip, mPanel);
|
||||
addButton(button, id);
|
||||
}
|
||||
|
||||
|
@ -60,10 +60,10 @@ CSVWidget::ShapeBrushWindow::ShapeBrushWindow(CSMDoc::Document& document, QWidge
|
||||
: QFrame(parent, Qt::Popup)
|
||||
, mDocument(document)
|
||||
{
|
||||
mButtonPoint = new QPushButton(QIcon(QPixmap(":scenetoolbar/brush-point")), "", this);
|
||||
mButtonSquare = new QPushButton(QIcon(QPixmap(":scenetoolbar/brush-square")), "", this);
|
||||
mButtonCircle = new QPushButton(QIcon(QPixmap(":scenetoolbar/brush-circle")), "", this);
|
||||
mButtonCustom = new QPushButton(QIcon(QPixmap(":scenetoolbar/brush-custom")), "", this);
|
||||
mButtonPoint = new QPushButton(QIcon(":scenetoolbar/brush-point"), "", this);
|
||||
mButtonSquare = new QPushButton(QIcon(":scenetoolbar/brush-square"), "", this);
|
||||
mButtonCircle = new QPushButton(QIcon(":scenetoolbar/brush-circle"), "", this);
|
||||
mButtonCustom = new QPushButton(QIcon(":scenetoolbar/brush-custom"), "", this);
|
||||
|
||||
mSizeSliders = new ShapeBrushSizeControls("Brush size", this);
|
||||
|
||||
@ -201,25 +201,25 @@ void CSVWidget::SceneToolShapeBrush::setButtonIcon(CSVWidget::BrushShape brushSh
|
||||
{
|
||||
case BrushShape_Point:
|
||||
|
||||
setIcon(QIcon(QPixmap(":scenetoolbar/brush-point")));
|
||||
setIcon(QIcon(":scenetoolbar/brush-point"));
|
||||
tooltip += mShapeBrushWindow->toolTipPoint;
|
||||
break;
|
||||
|
||||
case BrushShape_Square:
|
||||
|
||||
setIcon(QIcon(QPixmap(":scenetoolbar/brush-square")));
|
||||
setIcon(QIcon(":scenetoolbar/brush-square"));
|
||||
tooltip += mShapeBrushWindow->toolTipSquare;
|
||||
break;
|
||||
|
||||
case BrushShape_Circle:
|
||||
|
||||
setIcon(QIcon(QPixmap(":scenetoolbar/brush-circle")));
|
||||
setIcon(QIcon(":scenetoolbar/brush-circle"));
|
||||
tooltip += mShapeBrushWindow->toolTipCircle;
|
||||
break;
|
||||
|
||||
case BrushShape_Custom:
|
||||
|
||||
setIcon(QIcon(QPixmap(":scenetoolbar/brush-custom")));
|
||||
setIcon(QIcon(":scenetoolbar/brush-custom"));
|
||||
tooltip += mShapeBrushWindow->toolTipCustom;
|
||||
break;
|
||||
}
|
||||
|
@ -90,10 +90,10 @@ CSVWidget::TextureBrushWindow::TextureBrushWindow(CSMDoc::Document& document, QW
|
||||
mSelectedBrush = new QLabel(QString::fromStdString(mBrushTextureLabel));
|
||||
}
|
||||
|
||||
mButtonPoint = new QPushButton(QIcon(QPixmap(":scenetoolbar/brush-point")), "", this);
|
||||
mButtonSquare = new QPushButton(QIcon(QPixmap(":scenetoolbar/brush-square")), "", this);
|
||||
mButtonCircle = new QPushButton(QIcon(QPixmap(":scenetoolbar/brush-circle")), "", this);
|
||||
mButtonCustom = new QPushButton(QIcon(QPixmap(":scenetoolbar/brush-custom")), "", this);
|
||||
mButtonPoint = new QPushButton(QIcon(":scenetoolbar/brush-point"), "", this);
|
||||
mButtonSquare = new QPushButton(QIcon(":scenetoolbar/brush-square"), "", this);
|
||||
mButtonCircle = new QPushButton(QIcon(":scenetoolbar/brush-circle"), "", this);
|
||||
mButtonCustom = new QPushButton(QIcon(":scenetoolbar/brush-custom"), "", this);
|
||||
|
||||
mSizeSliders = new BrushSizeControls("Brush size", this);
|
||||
|
||||
@ -282,25 +282,25 @@ void CSVWidget::SceneToolTextureBrush::setButtonIcon(CSVWidget::BrushShape brush
|
||||
{
|
||||
case BrushShape_Point:
|
||||
|
||||
setIcon(QIcon(QPixmap(":scenetoolbar/brush-point")));
|
||||
setIcon(QIcon(":scenetoolbar/brush-point"));
|
||||
tooltip += mTextureBrushWindow->toolTipPoint;
|
||||
break;
|
||||
|
||||
case BrushShape_Square:
|
||||
|
||||
setIcon(QIcon(QPixmap(":scenetoolbar/brush-square")));
|
||||
setIcon(QIcon(":scenetoolbar/brush-square"));
|
||||
tooltip += mTextureBrushWindow->toolTipSquare;
|
||||
break;
|
||||
|
||||
case BrushShape_Circle:
|
||||
|
||||
setIcon(QIcon(QPixmap(":scenetoolbar/brush-circle")));
|
||||
setIcon(QIcon(":scenetoolbar/brush-circle"));
|
||||
tooltip += mTextureBrushWindow->toolTipCircle;
|
||||
break;
|
||||
|
||||
case BrushShape_Custom:
|
||||
|
||||
setIcon(QIcon(QPixmap(":scenetoolbar/brush-custom")));
|
||||
setIcon(QIcon(":scenetoolbar/brush-custom"));
|
||||
tooltip += mTextureBrushWindow->toolTipCustom;
|
||||
break;
|
||||
}
|
||||
|
@ -88,7 +88,7 @@ void CSVWidget::SceneToolToggle2::addButton(
|
||||
stream << mSingleIcon << id;
|
||||
|
||||
PushButton* button = new PushButton(
|
||||
QIcon(QPixmap(stream.str().c_str())), PushButton::Type_Toggle, tooltip.isEmpty() ? name : tooltip, mPanel);
|
||||
QIcon(stream.str().c_str()), PushButton::Type_Toggle, tooltip.isEmpty() ? name : tooltip, mPanel);
|
||||
|
||||
button->setSizePolicy(QSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed));
|
||||
button->setIconSize(QSize(mIconSize, mIconSize));
|
||||
|
@ -29,7 +29,7 @@ void CSVWorld::DragRecordTable::startDragFromTable(const CSVWorld::DragRecordTab
|
||||
mime->setIndexAtDragStart(index);
|
||||
QDrag* drag = new QDrag(this);
|
||||
drag->setMimeData(mime);
|
||||
drag->setPixmap(QString::fromUtf8(mime->getIcon().c_str()));
|
||||
drag->setPixmap(QIcon(mime->getIcon().c_str()).pixmap(QSize(16, 16)));
|
||||
drag->exec(Qt::CopyAction);
|
||||
}
|
||||
|
||||
|
@ -46,41 +46,41 @@ QWidget* CSVWorld::IdCompletionDelegate::createEditor(QWidget* parent, const QSt
|
||||
|
||||
switch (conditionFunction)
|
||||
{
|
||||
case CSMWorld::ConstInfoSelectWrapper::Function_Global:
|
||||
case ESM::DialogueCondition::Function_Global:
|
||||
{
|
||||
return createEditor(parent, option, index, CSMWorld::ColumnBase::Display_GlobalVariable);
|
||||
}
|
||||
case CSMWorld::ConstInfoSelectWrapper::Function_Journal:
|
||||
case ESM::DialogueCondition::Function_Journal:
|
||||
{
|
||||
return createEditor(parent, option, index, CSMWorld::ColumnBase::Display_Journal);
|
||||
}
|
||||
case CSMWorld::ConstInfoSelectWrapper::Function_Item:
|
||||
case ESM::DialogueCondition::Function_Item:
|
||||
{
|
||||
return createEditor(parent, option, index, CSMWorld::ColumnBase::Display_Referenceable);
|
||||
}
|
||||
case CSMWorld::ConstInfoSelectWrapper::Function_Dead:
|
||||
case CSMWorld::ConstInfoSelectWrapper::Function_NotId:
|
||||
case ESM::DialogueCondition::Function_Dead:
|
||||
case ESM::DialogueCondition::Function_NotId:
|
||||
{
|
||||
return createEditor(parent, option, index, CSMWorld::ColumnBase::Display_Referenceable);
|
||||
}
|
||||
case CSMWorld::ConstInfoSelectWrapper::Function_NotFaction:
|
||||
case ESM::DialogueCondition::Function_NotFaction:
|
||||
{
|
||||
return createEditor(parent, option, index, CSMWorld::ColumnBase::Display_Faction);
|
||||
}
|
||||
case CSMWorld::ConstInfoSelectWrapper::Function_NotClass:
|
||||
case ESM::DialogueCondition::Function_NotClass:
|
||||
{
|
||||
return createEditor(parent, option, index, CSMWorld::ColumnBase::Display_Class);
|
||||
}
|
||||
case CSMWorld::ConstInfoSelectWrapper::Function_NotRace:
|
||||
case ESM::DialogueCondition::Function_NotRace:
|
||||
{
|
||||
return createEditor(parent, option, index, CSMWorld::ColumnBase::Display_Race);
|
||||
}
|
||||
case CSMWorld::ConstInfoSelectWrapper::Function_NotCell:
|
||||
case ESM::DialogueCondition::Function_NotCell:
|
||||
{
|
||||
return createEditor(parent, option, index, CSMWorld::ColumnBase::Display_Cell);
|
||||
}
|
||||
case CSMWorld::ConstInfoSelectWrapper::Function_Local:
|
||||
case CSMWorld::ConstInfoSelectWrapper::Function_NotLocal:
|
||||
case ESM::DialogueCondition::Function_Local:
|
||||
case ESM::DialogueCondition::Function_NotLocal:
|
||||
{
|
||||
return new CSVWidget::DropLineEdit(display, parent);
|
||||
}
|
||||
|
@ -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
|
||||
|
@ -92,7 +92,7 @@ CSVWorld::RecordButtonBar::RecordButtonBar(const CSMWorld::UniversalId& id, CSMW
|
||||
if (mTable.getFeatures() & CSMWorld::IdTable::Feature_View)
|
||||
{
|
||||
QToolButton* viewButton = new QToolButton(this);
|
||||
viewButton->setIcon(QIcon(":/cell.png"));
|
||||
viewButton->setIcon(QIcon(":cell"));
|
||||
viewButton->setToolTip("Open a scene view of the cell this record is located in");
|
||||
buttonsLayout->addWidget(viewButton);
|
||||
connect(viewButton, &QToolButton::clicked, this, &RecordButtonBar::viewRecord);
|
||||
|
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