Script 'mail_helper' called by obssrc
Hello community,

here is the log from the commit of package openmw for openSUSE:Factory checked 
in at 2025-06-24 20:47:54
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Comparing /work/SRC/openSUSE:Factory/openmw (Old)
 and      /work/SRC/openSUSE:Factory/.openmw.new.7067 (New)
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

Package is "openmw"

Tue Jun 24 20:47:54 2025 rev:20 rq:1287957 version:0.49rc9

Changes:
--------
--- /work/SRC/openSUSE:Factory/openmw/openmw.changes    2025-06-10 
09:07:57.154050473 +0200
+++ /work/SRC/openSUSE:Factory/.openmw.new.7067/openmw.changes  2025-06-24 
20:49:09.948346317 +0200
@@ -1,0 +2,12 @@
+Mon Jun 23 11:45:41 UTC 2025 - Michael Pujos <pujos.mich...@gmail.com>
+
+- Compiled with Qt6
+- Update to version 0.49rc9
+  * [#8039] Fixed movement accumulation for actors that use Collada models on 
some builds compiled under LLVM
+  * [#8558] OpenMW-Lua: Light record color is now exposed as util.color rather 
than as a number
+  * [#8559] ESSImporter: Fixed selected spell/enchanted item and stolen item 
counter conversion
+  * [#8563] Improved handling of content files that are defined in the 
non-user version of openmw.cfg
+  * [#8567] Token replacement and relative paths work properly when the paths 
are passed through CLI
+  * Improved application detection for default shortcuts
+
+-------------------------------------------------------------------

Old:
----
  openmw-49-rc8.tar.gz

New:
----
  openmw-49-rc9.tar.gz

++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

Other differences:
------------------
++++++ openmw.spec ++++++
--- /var/tmp/diff_new_pack.Xg5C0s/_old  2025-06-24 20:49:10.836383132 +0200
+++ /var/tmp/diff_new_pack.Xg5C0s/_new  2025-06-24 20:49:10.840383298 +0200
@@ -21,9 +21,9 @@
 # are not compatible with it
 # 1.69 is the first boost version that is supposed to work with C++ 20:
 %define min_boost_version 1.69
-%define archive_version 49-rc8
+%define archive_version 49-rc9
 Name:           openmw
-Version:        0.49rc8
+Version:        0.49rc9
 Release:        0
 Summary:        Reimplementation of The Elder Scrolls III: Morrowind
 License:        GPL-3.0-only AND MIT
@@ -40,15 +40,14 @@
 BuildRequires:  libboost_program_options-devel >= %{min_boost_version}
 BuildRequires:  libboost_regex-devel >= %{min_boost_version}
 BuildRequires:  libboost_system-devel >= %{min_boost_version}
-BuildRequires:  libqt5-linguist-devel
-BuildRequires:  pkgconfig
 BuildRequires:  tinyxml-devel
 BuildRequires:  update-desktop-files
-BuildRequires:  pkgconfig(Qt5Core)
-BuildRequires:  pkgconfig(Qt5Network)
-BuildRequires:  pkgconfig(Qt5OpenGL)
-BuildRequires:  pkgconfig(Qt5Svg)
-BuildRequires:  pkgconfig(Qt5Widgets)
+BuildRequires:  pkgconfig(Qt6Core)
+BuildRequires:  pkgconfig(Qt6Linguist)
+BuildRequires:  pkgconfig(Qt6Network)
+BuildRequires:  pkgconfig(Qt6OpenGLWidgets)
+BuildRequires:  pkgconfig(Qt6Svg)
+BuildRequires:  pkgconfig(Qt6Widgets)
 BuildRequires:  pkgconfig(bullet) >= 2.83.0
 BuildRequires:  pkgconfig(icu-i18n)
 BuildRequires:  pkgconfig(icu-uc)

++++++ openmw-49-rc8.tar.gz -> openmw-49-rc9.tar.gz ++++++
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/openmw-openmw-49-rc8/.github/workflows/push.yml 
new/openmw-openmw-49-rc9/.github/workflows/push.yml
--- old/openmw-openmw-49-rc8/.github/workflows/push.yml 2025-06-07 
00:14:32.000000000 +0200
+++ new/openmw-openmw-49-rc9/.github/workflows/push.yml 2025-06-23 
10:59:11.000000000 +0200
@@ -73,7 +73,7 @@
     - uses: actions/checkout@v4
 
     - name: Install Building Dependencies
-      run: CI/before_install.osx.sh
+      run: CI/before_install.macos.sh
 
     - name: Prime ccache
       uses: hendrikmuhs/ccache-action@v1
@@ -82,11 +82,9 @@
         max-size: 1000M
 
     - name: Configure
-      run: CI/before_script.osx.sh
+      run: CI/before_script.macos.sh
     - name: Build
-      run: |
-        cd build
-        make -j $(sysctl -n hw.logicalcpu) package
+      run: CI/macos/build.sh
 
   Output-Envs:
     name: Read .env file and expose it as output
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/openmw-openmw-49-rc8/.gitlab-ci.yml 
new/openmw-openmw-49-rc9/.gitlab-ci.yml
--- old/openmw-openmw-49-rc8/.gitlab-ci.yml     2025-06-07 00:14:32.000000000 
+0200
+++ new/openmw-openmw-49-rc9/.gitlab-ci.yml     2025-06-23 10:59:11.000000000 
+0200
@@ -507,14 +507,15 @@
     paths:
     - ccache/
   script:
-    - CI/before_install.osx.sh
+    - CI/before_install.macos.sh
     - export CCACHE_BASEDIR="$(pwd)"
     - export CCACHE_DIR="$(pwd)/ccache"
     - mkdir -pv "${CCACHE_DIR}"
-    - ccache -z -M "${CCACHE_SIZE}"
-    - CI/before_script.osx.sh
-    - cd build; make -j $(sysctl -n hw.logicalcpu) package
-    - for dmg in *.dmg; do mv "$dmg" 
"${dmg%.dmg}_${CI_COMMIT_REF_NAME##*/}.dmg"; done
+    - CI/macos/ccache_prep.sh
+    - CI/before_script.macos.sh
+    - CI/macos/build.sh
+    - cd build
+    - for dmg in *.dmg; do mv "$dmg" 
"${dmg%.dmg}_${DMG_IDENTIFIER}_${CI_COMMIT_REF_NAME##*/}.dmg"; done
     - |
       if [[ -n "${AWS_ACCESS_KEY_ID}" ]]; then
         echo "[default]" > ~/.s3cfg
@@ -529,11 +530,23 @@
           s3cmd put "${dmg}" s3://openmw-artifacts/${artifactDirectory}
         done
       fi
-    - ccache -s
+    - ../CI/macos/ccache_save.sh
   artifacts:
     paths:
       - build/OpenMW-*.dmg
 
+macOS14_Xcode15_amd64:
+  extends: .MacOS
+  image: macos-14-xcode-15
+  tags:
+    - saas-macos-medium-m1
+  cache:
+    key: macOS14_Xcode15_amd64.v2
+  variables:
+    CCACHE_SIZE: 3G
+    DMG_IDENTIFIER: amd64
+    MACOS_AMD64: true
+
 macOS14_Xcode15_arm64:
   extends: .MacOS
   image: macos-14-xcode-15
@@ -542,6 +555,7 @@
   cache:
     key: macOS14_Xcode15_arm64.v1
   variables:
+    DMG_IDENTIFIER: arm64
     CCACHE_SIZE: 3G
 
 .Compress_And_Upload_Symbols_Base:
@@ -968,7 +982,7 @@
       - flatpak build-bundle ./repo openmw.flatpak org.openmw.OpenMW.devel
     cache:
       key: flatpak
-      paths: 
+      paths:
         - ".flatpak-builder"
     artifacts:
       untracked: false
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/openmw-openmw-49-rc8/CHANGELOG.md 
new/openmw-openmw-49-rc9/CHANGELOG.md
--- old/openmw-openmw-49-rc8/CHANGELOG.md       2025-06-07 00:14:32.000000000 
+0200
+++ new/openmw-openmw-49-rc9/CHANGELOG.md       2025-06-23 10:59:11.000000000 
+0200
@@ -236,6 +236,7 @@
     Bug #8465: Blue screen w/ antialiasing and post-processing on macOS
     Bug #8503: Camera does not handle NaN gracefully
     Bug #8541: Lua: util.color:asHex produces wrong output for some colors
+    Bug #8567: Token replacement does not work via CLI and relative paths 
passed via the command line are not relative to the CWD
     Feature #1415: Infinite fall failsafe
     Feature #2566: Handle NAM9 records for manual cell references
     Feature #3501: OpenMW-CS: Instance Editing - Shortcuts for axial locking
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/openmw-openmw-49-rc8/CI/before_install.macos.sh 
new/openmw-openmw-49-rc9/CI/before_install.macos.sh
--- old/openmw-openmw-49-rc8/CI/before_install.macos.sh 1970-01-01 
01:00:00.000000000 +0100
+++ new/openmw-openmw-49-rc9/CI/before_install.macos.sh 2025-06-23 
10:59:11.000000000 +0200
@@ -0,0 +1,11 @@
+#!/bin/sh -ex
+
+export HOMEBREW_NO_EMOJI=1
+export HOMEBREW_NO_INSTALL_CLEANUP=1
+export HOMEBREW_AUTOREMOVE=1
+
+if [[ "${MACOS_AMD64}" ]]; then
+    ./CI/macos/before_install.amd64.sh
+else
+    ./CI/macos/before_install.arm64.sh
+fi
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/openmw-openmw-49-rc8/CI/before_install.osx.sh 
new/openmw-openmw-49-rc9/CI/before_install.osx.sh
--- old/openmw-openmw-49-rc8/CI/before_install.osx.sh   2025-06-07 
00:14:32.000000000 +0200
+++ new/openmw-openmw-49-rc9/CI/before_install.osx.sh   1970-01-01 
01:00:00.000000000 +0100
@@ -1,30 +0,0 @@
-#!/bin/sh -ex
-
-export HOMEBREW_NO_EMOJI=1
-export HOMEBREW_NO_INSTALL_CLEANUP=1
-export HOMEBREW_AUTOREMOVE=1
-
-brew tap --repair
-brew update --quiet
-
-brew install curl xquartz gd fontconfig freetype harfbuzz brotli s3cmd
-
-command -v ccache >/dev/null 2>&1 || brew install ccache
-command -v cmake >/dev/null 2>&1 || brew install cmake
-command -v qmake >/dev/null 2>&1 || brew install qt@5
-export PATH="/opt/homebrew/opt/qt@5/bin:$PATH"
-
-# Install deps
-brew install openal-soft icu4c yaml-cpp sqlite
-
-ccache --version
-cmake --version
-qmake --version
-
-if [[ "${MACOS_AMD64}" ]]; then
-    curl -fSL -R -J 
https://gitlab.com/OpenMW/openmw-deps/-/raw/main/macos/openmw-deps-20240802.zip 
-o ~/openmw-deps.zip
-    unzip -o ~/openmw-deps.zip -d /tmp > /dev/null
-else
-    curl -fSL -R -J 
https://gitlab.com/OpenMW/openmw-deps/-/raw/main/macos/openmw-deps-20240818-arm64.tar.xz
 -o ~/openmw-deps.tar.xz
-    tar xf ~/openmw-deps.tar.xz -C /tmp > /dev/null
-fi
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/openmw-openmw-49-rc8/CI/before_script.macos.sh 
new/openmw-openmw-49-rc9/CI/before_script.macos.sh
--- old/openmw-openmw-49-rc8/CI/before_script.macos.sh  1970-01-01 
01:00:00.000000000 +0100
+++ new/openmw-openmw-49-rc9/CI/before_script.macos.sh  2025-06-23 
10:59:11.000000000 +0200
@@ -0,0 +1,77 @@
+#!/bin/sh -e
+
+# Silence a git warning
+git config --global advice.detachedHead false
+
+rm -fr build
+mkdir build
+cd build
+
+DEPENDENCIES_ROOT="/tmp/openmw-deps"
+
+if [[ "${MACOS_AMD64}" ]]; then
+    QT_PATH=$(arch -x86_64 /usr/local/bin/brew --prefix qt@6)
+    ICU_PATH=$(arch -x86_64 /usr/local/bin/brew --prefix icu4c)
+    OPENAL_PATH=$(arch -x86_64 /usr/local/bin/brew --prefix openal-soft)
+    CCACHE_EXECUTABLE=$(arch -x86_64 /usr/local/bin/brew --prefix 
ccache)/bin/ccache
+else
+    QT_PATH=$(brew --prefix qt@6)
+    ICU_PATH=$(brew --prefix icu4c)
+    OPENAL_PATH=$(brew --prefix openal-soft)
+    CCACHE_EXECUTABLE=$(brew --prefix ccache)/bin/ccache
+fi
+
+declare -a CMAKE_CONF_OPTS=(
+-D CMAKE_PREFIX_PATH="$DEPENDENCIES_ROOT;$QT_PATH;$OPENAL_PATH"
+-D CMAKE_C_COMPILER_LAUNCHER="$CCACHE_EXECUTABLE"
+-D CMAKE_CXX_COMPILER_LAUNCHER="$CCACHE_EXECUTABLE"
+-D CMAKE_CXX_FLAGS="-stdlib=libc++"
+-D CMAKE_C_COMPILER="clang"
+-D CMAKE_CXX_COMPILER="clang++"
+-D CMAKE_OSX_DEPLOYMENT_TARGET="13.6"
+-D OPENMW_USE_SYSTEM_RECASTNAVIGATION=TRUE
+-D Boost_INCLUDE_DIR="$DEPENDENCIES_ROOT/include"
+-D OSGPlugins_LIB_DIR="$DEPENDENCIES_ROOT/lib/osgPlugins-3.6.5"
+-D ICU_ROOT="$ICU_PATH"
+-D OPENMW_OSX_DEPLOYMENT=TRUE
+)
+
+declare -a BUILD_OPTS=(
+-D BUILD_OPENMW=TRUE
+-D BUILD_OPENCS=TRUE
+-D BUILD_ESMTOOL=TRUE
+-D BUILD_BSATOOL=TRUE
+-D BUILD_ESSIMPORTER=TRUE
+-D BUILD_NIFTEST=TRUE
+-D BUILD_NAVMESHTOOL=TRUE
+-D BUILD_BULLETOBJECTTOOL=TRUE
+-G"Unix Makefiles"
+)
+
+if [[ "${MACOS_AMD64}" ]]; then
+    CMAKE_CONF_OPTS+=(
+        -D CMAKE_OSX_ARCHITECTURES="x86_64"
+    )
+fi
+
+if [[ "${CMAKE_BUILD_TYPE}" ]]; then
+    CMAKE_CONF_OPTS+=(
+        -D CMAKE_BUILD_TYPE=${CMAKE_BUILD_TYPE}
+    )
+else
+    CMAKE_CONF_OPTS+=(
+        -D CMAKE_BUILD_TYPE=RelWithDebInfo
+    )
+fi
+
+if [[ "${MACOS_AMD64}" ]]; then
+    arch -x86_64 cmake \
+        "${CMAKE_CONF_OPTS[@]}" \
+        "${BUILD_OPTS[@]}" \
+        ..
+else
+    cmake \
+        "${CMAKE_CONF_OPTS[@]}" \
+        "${BUILD_OPTS[@]}" \
+        ..
+fi
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/openmw-openmw-49-rc8/CI/before_script.osx.sh 
new/openmw-openmw-49-rc9/CI/before_script.osx.sh
--- old/openmw-openmw-49-rc8/CI/before_script.osx.sh    2025-06-07 
00:14:32.000000000 +0200
+++ new/openmw-openmw-49-rc9/CI/before_script.osx.sh    1970-01-01 
01:00:00.000000000 +0100
@@ -1,53 +0,0 @@
-#!/bin/sh -e
-
-# Silence a git warning
-git config --global advice.detachedHead false
-
-rm -fr build
-mkdir build
-cd build
-
-DEPENDENCIES_ROOT="/tmp/openmw-deps"
-
-QT_PATH=$(brew --prefix qt@5)
-ICU_PATH=$(brew --prefix icu4c)
-OPENAL_PATH=$(brew --prefix openal-soft)
-CCACHE_EXECUTABLE=$(brew --prefix ccache)/bin/ccache
-
-declare -a CMAKE_CONF_OPTS=(
--D CMAKE_PREFIX_PATH="$DEPENDENCIES_ROOT;$QT_PATH;$OPENAL_PATH"
--D CMAKE_C_COMPILER_LAUNCHER="$CCACHE_EXECUTABLE"
--D CMAKE_CXX_COMPILER_LAUNCHER="$CCACHE_EXECUTABLE"
--D CMAKE_CXX_FLAGS="-stdlib=libc++"
--D CMAKE_C_COMPILER="clang"
--D CMAKE_CXX_COMPILER="clang++"
--D CMAKE_OSX_DEPLOYMENT_TARGET="13.6"
--D OPENMW_USE_SYSTEM_RECASTNAVIGATION=TRUE
--D Boost_INCLUDE_DIR="$DEPENDENCIES_ROOT/include"
--D OSGPlugins_LIB_DIR="$DEPENDENCIES_ROOT/lib/osgPlugins-3.6.5"
--D ICU_ROOT="$ICU_PATH"
--D OPENMW_OSX_DEPLOYMENT=TRUE
-)
-
-if [[ "${CMAKE_BUILD_TYPE}" ]]; then
-    CMAKE_CONF_OPTS+=(
-        -D CMAKE_BUILD_TYPE=${CMAKE_BUILD_TYPE}
-    )
-else
-    CMAKE_CONF_OPTS+=(
-        -D CMAKE_BUILD_TYPE=RelWithDebInfo
-    )
-fi
-
-cmake \
-"${CMAKE_CONF_OPTS[@]}" \
--D BUILD_OPENMW=TRUE \
--D BUILD_OPENCS=TRUE \
--D BUILD_ESMTOOL=TRUE \
--D BUILD_BSATOOL=TRUE \
--D BUILD_ESSIMPORTER=TRUE \
--D BUILD_NIFTEST=TRUE \
--D BUILD_NAVMESHTOOL=TRUE \
--D BUILD_BULLETOBJECTTOOL=TRUE \
--G"Unix Makefiles" \
-..
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/openmw-openmw-49-rc8/CI/macos/before_install.amd64.sh 
new/openmw-openmw-49-rc9/CI/macos/before_install.amd64.sh
--- old/openmw-openmw-49-rc8/CI/macos/before_install.amd64.sh   1970-01-01 
01:00:00.000000000 +0100
+++ new/openmw-openmw-49-rc9/CI/macos/before_install.amd64.sh   2025-06-23 
10:59:11.000000000 +0200
@@ -0,0 +1,8 @@
+#!/bin/sh -ex
+
+arch -x86_64 /bin/bash -c "$(curl -fsSL 
https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh)"
+
+arch -x86_64 /usr/local/bin/brew install curl xquartz gd fontconfig freetype 
harfbuzz brotli s3cmd ccache cmake qt@6 openal-soft icu4c yaml-cpp sqlite
+
+curl -fSL -R -J 
https://gitlab.com/OpenMW/openmw-deps/-/raw/main/macos/openmw-deps-20240802.zip 
-o ~/openmw-deps.zip
+unzip -o ~/openmw-deps.zip -d /tmp > /dev/null
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/openmw-openmw-49-rc8/CI/macos/before_install.arm64.sh 
new/openmw-openmw-49-rc9/CI/macos/before_install.arm64.sh
--- old/openmw-openmw-49-rc8/CI/macos/before_install.arm64.sh   1970-01-01 
01:00:00.000000000 +0100
+++ new/openmw-openmw-49-rc9/CI/macos/before_install.arm64.sh   2025-06-23 
10:59:11.000000000 +0200
@@ -0,0 +1,16 @@
+#!/bin/sh -ex
+
+brew tap --repair
+brew update --quiet
+
+brew install curl xquartz gd fontconfig freetype harfbuzz brotli s3cmd
+
+command -v ccache >/dev/null 2>&1 || brew install ccache
+command -v cmake >/dev/null 2>&1 || brew install cmake
+command -v qmake >/dev/null 2>&1 || brew install qt@6
+
+# Install deps
+brew install openal-soft icu4c yaml-cpp sqlite
+
+curl -fSL -R -J 
https://gitlab.com/OpenMW/openmw-deps/-/raw/main/macos/openmw-deps-20240818-arm64.tar.xz
 -o ~/openmw-deps.tar.xz
+tar xf ~/openmw-deps.tar.xz -C /tmp > /dev/null
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/openmw-openmw-49-rc8/CI/macos/build.sh 
new/openmw-openmw-49-rc9/CI/macos/build.sh
--- old/openmw-openmw-49-rc8/CI/macos/build.sh  1970-01-01 01:00:00.000000000 
+0100
+++ new/openmw-openmw-49-rc9/CI/macos/build.sh  2025-06-23 10:59:11.000000000 
+0200
@@ -0,0 +1,9 @@
+#!/bin/sh -ex
+
+cd build
+
+if [[ "${MACOS_AMD64}" ]]; then
+    arch -x86_64 make -j $(sysctl -n hw.logicalcpu) package
+else
+    make -j $(sysctl -n hw.logicalcpu) package
+fi
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/openmw-openmw-49-rc8/CI/macos/ccache_prep.sh 
new/openmw-openmw-49-rc9/CI/macos/ccache_prep.sh
--- old/openmw-openmw-49-rc8/CI/macos/ccache_prep.sh    1970-01-01 
01:00:00.000000000 +0100
+++ new/openmw-openmw-49-rc9/CI/macos/ccache_prep.sh    2025-06-23 
10:59:11.000000000 +0200
@@ -0,0 +1,7 @@
+#!/bin/sh -ex
+
+if [[ "${MACOS_AMD64}" ]]; then
+    arch -x86_64 ccache -z -M "${CCACHE_SIZE}"
+else
+    ccache -z -M "${CCACHE_SIZE}"
+fi
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/openmw-openmw-49-rc8/CI/macos/ccache_save.sh 
new/openmw-openmw-49-rc9/CI/macos/ccache_save.sh
--- old/openmw-openmw-49-rc8/CI/macos/ccache_save.sh    1970-01-01 
01:00:00.000000000 +0100
+++ new/openmw-openmw-49-rc9/CI/macos/ccache_save.sh    2025-06-23 
10:59:11.000000000 +0200
@@ -0,0 +1,7 @@
+#!/bin/sh -ex
+
+if [[ "${MACOS_AMD64}" ]]; then
+    arch -x86_64 ccache -s
+else
+    ccache -s
+fi
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/openmw-openmw-49-rc8/CMakeLists.txt 
new/openmw-openmw-49-rc9/CMakeLists.txt
--- old/openmw-openmw-49-rc8/CMakeLists.txt     2025-06-07 00:14:32.000000000 
+0200
+++ new/openmw-openmw-49-rc9/CMakeLists.txt     2025-06-23 10:59:11.000000000 
+0200
@@ -82,7 +82,7 @@
 set(OPENMW_VERSION_MAJOR 0)
 set(OPENMW_VERSION_MINOR 49)
 set(OPENMW_VERSION_RELEASE 0)
-set(OPENMW_LUA_API_REVISION 75)
+set(OPENMW_LUA_API_REVISION 76)
 set(OPENMW_POSTPROCESSING_API_REVISION 2)
 
 set(OPENMW_VERSION_COMMITHASH "")
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/openmw-openmw-49-rc8/apps/bulletobjecttool/main.cpp 
new/openmw-openmw-49-rc9/apps/bulletobjecttool/main.cpp
--- old/openmw-openmw-49-rc8/apps/bulletobjecttool/main.cpp     2025-06-07 
00:14:32.000000000 +0200
+++ new/openmw-openmw-49-rc9/apps/bulletobjecttool/main.cpp     2025-06-23 
10:59:11.000000000 +0200
@@ -125,6 +125,7 @@
         }
 
         Files::ConfigurationManager config;
+        config.processPaths(variables, std::filesystem::current_path());
         config.readConfiguration(variables, desc);
 
         Debug::setupLogging(config.getLogPath(), applicationName);
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/openmw-openmw-49-rc8/apps/essimporter/converter.hpp 
new/openmw-openmw-49-rc9/apps/essimporter/converter.hpp
--- old/openmw-openmw-49-rc8/apps/essimporter/converter.hpp     2025-06-07 
00:14:32.000000000 +0200
+++ new/openmw-openmw-49-rc9/apps/essimporter/converter.hpp     2025-06-23 
10:59:11.000000000 +0200
@@ -252,7 +252,7 @@
                 for (size_t i = 0; i < invState.mItems.size(); ++i)
                 {
                     // FIXME: in case of conflict (multiple items with this 
refID) use the already equipped one?
-                    if (invState.mItems[i].mRef.mRefID == 
ESM::RefId::stringRefId(refr.mActorData.mSelectedEnchantItem))
+                    if (invState.mItems[i].mRef.mRefID == 
refr.mActorData.mSelectedEnchantItem)
                         invState.mSelectedEnchantItem = i;
                 }
             }
@@ -260,12 +260,12 @@
         void write(ESM::ESMWriter& esm) override
         {
             esm.startRecord(ESM::REC_ASPL);
-            esm.writeHNString("ID__", mSelectedSpell);
+            esm.writeHNRefId("ID__", mSelectedSpell);
             esm.endRecord(ESM::REC_ASPL);
         }
 
     private:
-        std::string mSelectedSpell;
+        ESM::RefId mSelectedSpell;
     };
 
     class ConvertPCDT : public Converter
@@ -374,16 +374,16 @@
         void write(ESM::ESMWriter& esm) override
         {
             esm.startRecord(ESM::REC_DCOU);
-            for (auto it = mKillCounter.begin(); it != mKillCounter.end(); 
++it)
+            for (const auto& [id, count] : mKillCounter)
             {
-                esm.writeHNString("ID__", it->first);
-                esm.writeHNT("COUN", it->second);
+                esm.writeHNRefId("ID__", id);
+                esm.writeHNT("COUN", count);
             }
             esm.endRecord(ESM::REC_DCOU);
         }
 
     private:
-        std::map<std::string, int> mKillCounter;
+        std::map<ESM::RefId, int> mKillCounter;
     };
 
     class ConvertFACT : public Converter
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/openmw-openmw-49-rc8/apps/essimporter/importacdt.hpp 
new/openmw-openmw-49-rc9/apps/essimporter/importacdt.hpp
--- old/openmw-openmw-49-rc8/apps/essimporter/importacdt.hpp    2025-06-07 
00:14:32.000000000 +0200
+++ new/openmw-openmw-49-rc9/apps/essimporter/importacdt.hpp    2025-06-23 
10:59:11.000000000 +0200
@@ -75,8 +75,8 @@
         // to change them ingame
         int mCombatStats[3][2];
 
-        std::string mSelectedSpell;
-        std::string mSelectedEnchantItem;
+        ESM::RefId mSelectedSpell;
+        ESM::RefId mSelectedEnchantItem;
 
         SCRI mSCRI;
 
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/openmw-openmw-49-rc8/apps/essimporter/importcellref.cpp 
new/openmw-openmw-49-rc9/apps/essimporter/importcellref.cpp
--- old/openmw-openmw-49-rc8/apps/essimporter/importcellref.cpp 2025-06-07 
00:14:32.000000000 +0200
+++ new/openmw-openmw-49-rc9/apps/essimporter/importcellref.cpp 2025-06-23 
10:59:11.000000000 +0200
@@ -107,12 +107,12 @@
 
         if (esm.isNextSub("WNAM"))
         {
-            std::string id = esm.getHString();
+            ESM::RefId spellRefId = esm.getRefId();
 
             if (esm.isNextSub("XNAM"))
-                mActorData.mSelectedEnchantItem = esm.getHString();
+                mActorData.mSelectedEnchantItem = esm.getRefId();
             else
-                mActorData.mSelectedSpell = std::move(id);
+                mActorData.mSelectedSpell = std::move(spellRefId);
 
             if (esm.isNextSub("YNAM"))
                 esm.skipHSub(); // 4 byte, 0
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/openmw-openmw-49-rc8/apps/essimporter/importinfo.cpp 
new/openmw-openmw-49-rc9/apps/essimporter/importinfo.cpp
--- old/openmw-openmw-49-rc8/apps/essimporter/importinfo.cpp    2025-06-07 
00:14:32.000000000 +0200
+++ new/openmw-openmw-49-rc9/apps/essimporter/importinfo.cpp    2025-06-23 
10:59:11.000000000 +0200
@@ -7,7 +7,19 @@
 
     void INFO::load(ESM::ESMReader& esm)
     {
-        mInfo = esm.getHNString("INAM");
+        if (esm.peekNextSub("XNAM"))
+        {
+            // TODO: Support older saves by turning XNAM into a RefId.
+            // XNAM is probably the number of the topic response within the 
topic record's linked list.
+            // Resolving this value will likely require loading Morrowind.esm.
+
+            esm.getSubName();
+            esm.skipHSub();
+            mInfo = ESM::RefId();
+        }
+        else
+            mInfo = esm.getHNRefId("INAM");
+
         mActorRefId = esm.getHNString("ACDT");
     }
 
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/openmw-openmw-49-rc8/apps/essimporter/importinfo.hpp 
new/openmw-openmw-49-rc9/apps/essimporter/importinfo.hpp
--- old/openmw-openmw-49-rc8/apps/essimporter/importinfo.hpp    2025-06-07 
00:14:32.000000000 +0200
+++ new/openmw-openmw-49-rc9/apps/essimporter/importinfo.hpp    2025-06-23 
10:59:11.000000000 +0200
@@ -3,6 +3,8 @@
 
 #include <string>
 
+#include <components/esm/refid.hpp>
+
 namespace ESM
 {
     class ESMReader;
@@ -13,7 +15,7 @@
 
     struct INFO
     {
-        std::string mInfo;
+        ESM::RefId mInfo;
         std::string mActorRefId;
 
         void load(ESM::ESMReader& esm);
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/openmw-openmw-49-rc8/apps/essimporter/importklst.cpp 
new/openmw-openmw-49-rc9/apps/essimporter/importklst.cpp
--- old/openmw-openmw-49-rc8/apps/essimporter/importklst.cpp    2025-06-07 
00:14:32.000000000 +0200
+++ new/openmw-openmw-49-rc9/apps/essimporter/importklst.cpp    2025-06-23 
10:59:11.000000000 +0200
@@ -9,7 +9,7 @@
     {
         while (esm.isNextSub("KNAM"))
         {
-            std::string refId = esm.getHString();
+            ESM::RefId refId = esm.getRefId();
             int32_t count;
             esm.getHNT(count, "CNAM");
             mKillCounter[refId] = count;
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/openmw-openmw-49-rc8/apps/essimporter/importklst.hpp 
new/openmw-openmw-49-rc9/apps/essimporter/importklst.hpp
--- old/openmw-openmw-49-rc8/apps/essimporter/importklst.hpp    2025-06-07 
00:14:32.000000000 +0200
+++ new/openmw-openmw-49-rc9/apps/essimporter/importklst.hpp    2025-06-23 
10:59:11.000000000 +0200
@@ -3,7 +3,8 @@
 
 #include <cstdint>
 #include <map>
-#include <string>
+
+#include <components/esm/refid.hpp>
 
 namespace ESM
 {
@@ -18,8 +19,7 @@
     {
         void load(ESM::ESMReader& esm);
 
-        /// RefId, kill count
-        std::map<std::string, int32_t> mKillCounter;
+        std::map<ESM::RefId, int32_t> mKillCounter;
 
         int32_t mWerewolfKills;
     };
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/openmw-openmw-49-rc8/apps/essimporter/main.cpp 
new/openmw-openmw-49-rc9/apps/essimporter/main.cpp
--- old/openmw-openmw-49-rc8/apps/essimporter/main.cpp  2025-06-07 
00:14:32.000000000 +0200
+++ new/openmw-openmw-49-rc9/apps/essimporter/main.cpp  2025-06-23 
10:59:11.000000000 +0200
@@ -40,6 +40,7 @@
         bpo::notify(variables);
 
         Files::ConfigurationManager cfgManager(true);
+        cfgManager.processPaths(variables, std::filesystem::current_path());
         cfgManager.readConfiguration(variables, desc);
 
         const auto& essFile = variables["mwsave"].as<Files::MaybeQuotedPath>();
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/openmw-openmw-49-rc8/apps/navmeshtool/main.cpp 
new/openmw-openmw-49-rc9/apps/navmeshtool/main.cpp
--- old/openmw-openmw-49-rc8/apps/navmeshtool/main.cpp  2025-06-07 
00:14:32.000000000 +0200
+++ new/openmw-openmw-49-rc9/apps/navmeshtool/main.cpp  2025-06-23 
10:59:11.000000000 +0200
@@ -143,6 +143,7 @@
             }
 
             Files::ConfigurationManager config;
+            config.processPaths(variables, std::filesystem::current_path());
             config.readConfiguration(variables, desc);
 
             Debug::setupLogging(config.getLogPath(), applicationName);
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/openmw-openmw-49-rc8/apps/opencs/model/doc/runner.cpp 
new/openmw-openmw-49-rc9/apps/opencs/model/doc/runner.cpp
--- old/openmw-openmw-49-rc8/apps/opencs/model/doc/runner.cpp   2025-06-07 
00:14:32.000000000 +0200
+++ new/openmw-openmw-49-rc9/apps/opencs/model/doc/runner.cpp   2025-06-23 
10:59:11.000000000 +0200
@@ -2,11 +2,8 @@
 
 #include <utility>
 
-#if defined(Q_OS_MAC)
 #include <QCoreApplication>
 #include <QDir>
-#endif
-
 #include <QProcess>
 #include <QString>
 #include <QStringList>
@@ -55,16 +52,17 @@
 
         QString path = "openmw";
 #ifdef Q_OS_WIN
-        path.append(QString(".exe"));
-#elif defined(Q_OS_MAC)
+        path.append(QLatin1String(".exe"));
+#endif
         QDir dir(QCoreApplication::applicationDirPath());
+#ifdef Q_OS_MAC
+        // the CS and engine are in separate .app directories
         dir.cdUp();
         dir.cdUp();
         dir.cdUp();
-        path = 
dir.absoluteFilePath(path.prepend("OpenMW.app/Contents/MacOS/"));
-#else
-        path.prepend(QString("./"));
+        path.prepend("OpenMW.app/Contents/MacOS/");
 #endif
+        path = dir.absoluteFilePath(path);
 
         mStartup = new QTemporaryFile(this);
         mStartup->open();
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/openmw-openmw-49-rc8/apps/openmw/CMakeLists.txt 
new/openmw-openmw-49-rc9/apps/openmw/CMakeLists.txt
--- old/openmw-openmw-49-rc8/apps/openmw/CMakeLists.txt 2025-06-07 
00:14:32.000000000 +0200
+++ new/openmw-openmw-49-rc9/apps/openmw/CMakeLists.txt 2025-06-23 
10:59:11.000000000 +0200
@@ -138,6 +138,12 @@
     endif()
 
     target_link_libraries(openmw openmw-lib)
+
+    # Workaround necessary to ensure osgAnimation::MatrixLinearSampler dynamic 
casts work under Clang
+    # NOTE: it's unclear whether the broken behavior is spec-compliant
+    if (CMAKE_CXX_COMPILER_ID STREQUAL Clang)
+        set_target_properties(openmw PROPERTIES ENABLE_EXPORTS ON)
+    endif()
 endif()
 
 # Sound stuff - here so CMake doesn't stupidly recompile EVERYTHING
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/openmw-openmw-49-rc8/apps/openmw/main.cpp 
new/openmw-openmw-49-rc9/apps/openmw/main.cpp
--- old/openmw-openmw-49-rc8/apps/openmw/main.cpp       2025-06-07 
00:14:32.000000000 +0200
+++ new/openmw-openmw-49-rc9/apps/openmw/main.cpp       2025-06-23 
10:59:11.000000000 +0200
@@ -61,6 +61,8 @@
         return false;
     }
 
+    cfgMgr.processPaths(variables, std::filesystem::current_path());
+
     cfgMgr.readConfiguration(variables, desc);
 
     Debug::setupLogging(cfgMgr.getLogPath(), "OpenMW");
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/openmw-openmw-49-rc8/apps/openmw/mwlua/types/light.cpp 
new/openmw-openmw-49-rc9/apps/openmw/mwlua/types/light.cpp
--- old/openmw-openmw-49-rc8/apps/openmw/mwlua/types/light.cpp  2025-06-07 
00:14:32.000000000 +0200
+++ new/openmw-openmw-49-rc9/apps/openmw/mwlua/types/light.cpp  2025-06-23 
10:59:11.000000000 +0200
@@ -5,6 +5,7 @@
 #include <components/esm3/loadligh.hpp>
 #include <components/lua/luastate.hpp>
 #include <components/lua/util.hpp>
+#include <components/misc/color.hpp>
 #include <components/misc/resourcehelpers.hpp>
 #include <components/resource/resourcesystem.hpp>
 
@@ -62,7 +63,13 @@
         if (rec["radius"] != sol::nil)
             light.mData.mRadius = rec["radius"];
         if (rec["color"] != sol::nil)
-            light.mData.mColor = rec["color"];
+        {
+            sol::object color = rec["color"];
+            if (color.is<Misc::Color>())
+                light.mData.mColor = color.as<Misc::Color>().toRGBA();
+            else
+                light.mData.mColor = color.as<uint32_t>();
+        }
         setRecordFlag(rec, "isCarriable", ESM::Light::Carry, light);
         setRecordFlag(rec, "isDynamic", ESM::Light::Dynamic, light);
         setRecordFlag(rec, "isFire", ESM::Light::Fire, light);
@@ -104,7 +111,8 @@
         record["value"] = sol::readonly_property([](const ESM::Light& rec) -> 
int { return rec.mData.mValue; });
         record["duration"] = sol::readonly_property([](const ESM::Light& rec) 
-> int { return rec.mData.mTime; });
         record["radius"] = sol::readonly_property([](const ESM::Light& rec) -> 
int { return rec.mData.mRadius; });
-        record["color"] = sol::readonly_property([](const ESM::Light& rec) -> 
int { return rec.mData.mColor; });
+        record["color"] = sol::readonly_property(
+            [](const ESM::Light& rec) -> Misc::Color { return 
Misc::Color::fromRGB(rec.mData.mColor); });
         record["isCarriable"] = sol::readonly_property(
             [](const ESM::Light& rec) -> bool { return rec.mData.mFlags & 
ESM::Light::Carry; });
         record["isDynamic"] = sol::readonly_property(
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/openmw-openmw-49-rc8/components/config/gamesettings.cpp 
new/openmw-openmw-49-rc9/components/config/gamesettings.cpp
--- old/openmw-openmw-49-rc8/components/config/gamesettings.cpp 2025-06-07 
00:14:32.000000000 +0200
+++ new/openmw-openmw-49-rc9/components/config/gamesettings.cpp 2025-06-23 
10:59:11.000000000 +0200
@@ -189,19 +189,16 @@
             if (ignoreContent && (key == QLatin1String("content") || key == 
QLatin1String("data")))
                 continue;
 
-            QList<SettingValue> values = cache.values(key);
-            values.append(settings.values(key));
-
-            bool exists = false;
-            for (const auto& existingValue : values)
-            {
-                if (existingValue.value == value.value)
+            auto containsValue = [&](const QMultiMap<QString, SettingValue>& 
map) {
+                for (auto [itr, end] = map.equal_range(key); itr != end; ++itr)
                 {
-                    exists = true;
-                    break;
+                    if (itr->value == value.value)
+                        return true;
                 }
-            }
-            if (!exists)
+                return false;
+            };
+
+            if (!containsValue(cache) && !containsValue(settings))
             {
                 cache.insert(key, value);
             }
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/openmw-openmw-49-rc8/components/contentselector/model/contentmodel.cpp 
new/openmw-openmw-49-rc9/components/contentselector/model/contentmodel.cpp
--- old/openmw-openmw-49-rc8/components/contentselector/model/contentmodel.cpp  
2025-06-07 00:14:32.000000000 +0200
+++ new/openmw-openmw-49-rc9/components/contentselector/model/contentmodel.cpp  
2025-06-23 10:59:11.000000000 +0200
@@ -129,7 +129,7 @@
     {
         if (depFile->isGameFile() && 
file->gameFiles().contains(depFile->fileName(), Qt::CaseInsensitive))
         {
-            if (!depFile->builtIn() && !depFile->fromAnotherConfigFile() && 
!mCheckedFiles.contains(depFile))
+            if (!isChecked(depFile))
                 break;
 
             return Qt::ItemIsEnabled | Qt::ItemIsSelectable | 
Qt::ItemIsUserCheckable | Qt::ItemIsDragEnabled;
@@ -215,8 +215,7 @@
             if (file == mGameFile)
                 return QVariant();
 
-            return (file->builtIn() || file->fromAnotherConfigFile() || 
mCheckedFiles.contains(file)) ? Qt::Checked
-                                                                               
                       : Qt::Unchecked;
+            return isChecked(file) ? Qt::Checked : Qt::Unchecked;
         }
 
         case Qt::UserRole:
@@ -230,7 +229,7 @@
         }
 
         case Qt::UserRole + 1:
-            return mCheckedFiles.contains(file);
+            return isChecked(file);
     }
     return QVariant();
 }
@@ -264,9 +263,9 @@
         {
             int checkValue = value.toInt();
             if (checkValue == Qt::Checked)
-                return mCheckedFiles.contains(file) || setCheckState(file, 
true);
+                return isChecked(file) || setCheckState(file, true);
             if (checkValue == Qt::Unchecked)
-                return !mCheckedFiles.contains(file) || setCheckState(file, 
false);
+                return !isChecked(file) || setCheckState(file, false);
         }
     }
 
@@ -606,6 +605,14 @@
     emit layoutChanged();
 }
 
+bool ContentSelectorModel::ContentModel::isChecked(const EsmFile* file) const
+{
+    if (file == nullptr)
+        return false;
+
+    return file->builtIn() || file->fromAnotherConfigFile() || 
mCheckedFiles.contains(file);
+}
+
 bool ContentSelectorModel::ContentModel::isEnabled(const QModelIndex& index) 
const
 {
     return (flags(index) & Qt::ItemIsEnabled);
@@ -691,7 +698,7 @@
         }
         else
         {
-            if (!mCheckedFiles.contains(dependentFile))
+            if (!isChecked(dependentFile))
             {
                 
errors.append(LoadOrderError(LoadOrderError::ErrorCode_InactiveDependency, 
dependentfileName));
             }
@@ -706,7 +713,7 @@
     {
         // Warn the user if Bloodmoon is loaded before Tribunal (Tribunal is 
not a hard dependency)
         const EsmFile* tribunalFile = item("Tribunal.esm");
-        if (tribunalFile != nullptr && mCheckedFiles.contains(tribunalFile) && 
row < indexFromItem(tribunalFile).row())
+        if (isChecked(tribunalFile) && row < indexFromItem(tribunalFile).row())
             errors.append(LoadOrderError(LoadOrderError::ErrorCode_LoadOrder, 
"Tribunal.esm"));
     }
 
@@ -770,8 +777,9 @@
         for (const QString& upstreamName : file->gameFiles())
         {
             const EsmFile* upstreamFile = item(upstreamName);
-            if (upstreamFile == nullptr || 
!mCheckedFiles.insert(upstreamFile).second)
+            if (upstreamFile == nullptr || isChecked(upstreamFile))
                 continue;
+            mCheckedFiles.insert(upstreamFile);
             QModelIndex upstreamIndex = indexFromItem(upstreamFile);
             emit dataChanged(upstreamIndex, upstreamIndex);
         }
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/openmw-openmw-49-rc8/components/contentselector/model/contentmodel.hpp 
new/openmw-openmw-49-rc9/components/contentselector/model/contentmodel.hpp
--- old/openmw-openmw-49-rc8/components/contentselector/model/contentmodel.hpp  
2025-06-07 00:14:32.000000000 +0200
+++ new/openmw-openmw-49-rc9/components/contentselector/model/contentmodel.hpp  
2025-06-23 10:59:11.000000000 +0200
@@ -58,6 +58,7 @@
         QStringList gameFiles() const;
         void setCurrentGameFile(const EsmFile* file);
 
+        bool isChecked(const EsmFile* file) const;
         bool isEnabled(const QModelIndex& index) const;
         bool setCheckState(const EsmFile* file, bool isChecked);
         bool isNew(const QString& filepath) const;
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/openmw-openmw-49-rc8/components/contentselector/view/contentselector.cpp 
new/openmw-openmw-49-rc9/components/contentselector/view/contentselector.cpp
--- 
old/openmw-openmw-49-rc8/components/contentselector/view/contentselector.cpp    
    2025-06-07 00:14:32.000000000 +0200
+++ 
new/openmw-openmw-49-rc9/components/contentselector/view/contentselector.cpp    
    2025-06-23 10:59:11.000000000 +0200
@@ -157,7 +157,7 @@
         index = ui->gameFileView->findText(file->fileName());
 
         // verify that the current index is also checked in the model
-        if (!mContentModel->setCheckState(file, true))
+        if (!mContentModel->isChecked(file) && 
!mContentModel->setCheckState(file, true))
         {
             // throw error in case file not found?
             return;
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/openmw-openmw-49-rc8/components/crashcatcher/windows_crashcatcher.cpp 
new/openmw-openmw-49-rc9/components/crashcatcher/windows_crashcatcher.cpp
--- old/openmw-openmw-49-rc8/components/crashcatcher/windows_crashcatcher.cpp   
2025-06-07 00:14:32.000000000 +0200
+++ new/openmw-openmw-49-rc9/components/crashcatcher/windows_crashcatcher.cpp   
2025-06-23 10:59:11.000000000 +0200
@@ -129,6 +129,8 @@
         if (mShm == nullptr)
             throw std::runtime_error("Failed to map crash catcher shared 
memory");
 
+        mShm->mMonitorStatus = CrashSHM::Status::Uninitialised;
+
         mShmMutex = CreateMutexW(&attributes, FALSE, NULL);
         if (mShmMutex == nullptr)
             throw std::runtime_error("Failed to create crash catcher shared 
memory mutex");
@@ -147,10 +149,15 @@
 
     void CrashCatcher::waitMonitor()
     {
-        if (WaitForSingleObject(mSignalAppEvent, CrashCatcherTimeout) != 
WAIT_OBJECT_0)
+        if (!waitMonitorNoThrow())
             throw std::runtime_error("Waiting for monitor failed");
     }
 
+    bool CrashCatcher::waitMonitorNoThrow()
+    {
+        return WaitForSingleObject(mSignalAppEvent, CrashCatcherTimeout) == 
WAIT_OBJECT_0;
+    }
+
     void CrashCatcher::signalMonitor()
     {
         SetEvent(mSignalMonitorEvent);
@@ -234,13 +241,23 @@
 
         signalMonitor();
 
-        // must remain until monitor has finished
-        waitMonitor();
+        // give monitor a chance to start dumping
+        // as we're suspended, this might time out even if it's successful, so 
mMonitorStatus is the source of truth
+        waitMonitorNoThrow();
 
-        std::string message = "OpenMW has encountered a fatal error.\nCrash 
dump saved to '"
-            + 
Misc::StringUtils::u8StringToString(getCrashDumpPath(*mShm).u8string())
-            + "'.\nPlease report this to 
https://gitlab.com/OpenMW/openmw/issues !";
-        SDL_ShowSimpleMessageBox(0, "Fatal Error", message.c_str(), nullptr);
+        shmLock();
+        CrashSHM::Status monitorStatus = mShm->mMonitorStatus;
+        shmUnlock();
+
+        if (monitorStatus == CrashSHM::Status::DumpedSuccessfully)
+        {
+            std::string message = "OpenMW has encountered a fatal 
error.\nCrash dump saved to '"
+                + 
Misc::StringUtils::u8StringToString(getCrashDumpPath(*mShm).u8string())
+                + "'.\nPlease report this to 
https://gitlab.com/OpenMW/openmw/issues !";
+            SDL_ShowSimpleMessageBox(0, "Fatal Error", message.c_str(), 
nullptr);
+        }
+        else if (monitorStatus == CrashSHM::Status::Dumping)
+            SDL_ShowSimpleMessageBox(0, "Fatal Error", "Timed out while 
creating crash dump", nullptr);
     }
 
 } // namespace Crash
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/openmw-openmw-49-rc8/components/crashcatcher/windows_crashcatcher.hpp 
new/openmw-openmw-49-rc9/components/crashcatcher/windows_crashcatcher.hpp
--- old/openmw-openmw-49-rc8/components/crashcatcher/windows_crashcatcher.hpp   
2025-06-07 00:14:32.000000000 +0200
+++ new/openmw-openmw-49-rc9/components/crashcatcher/windows_crashcatcher.hpp   
2025-06-23 10:59:11.000000000 +0200
@@ -66,6 +66,7 @@
             const std::filesystem::path& freezeDumpName);
 
         void waitMonitor();
+        bool waitMonitorNoThrow();
 
         void signalMonitor();
 
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/openmw-openmw-49-rc8/components/crashcatcher/windows_crashmonitor.cpp 
new/openmw-openmw-49-rc9/components/crashcatcher/windows_crashmonitor.cpp
--- old/openmw-openmw-49-rc8/components/crashcatcher/windows_crashmonitor.cpp   
2025-06-07 00:14:32.000000000 +0200
+++ new/openmw-openmw-49-rc9/components/crashcatcher/windows_crashmonitor.cpp   
2025-06-23 10:59:11.000000000 +0200
@@ -163,6 +163,7 @@
 
     void CrashMonitor::run()
     {
+        mShm->mMonitorStatus = CrashSHM::Status::Monitoring;
         try
         {
             // app waits for monitor start up, let it continue
@@ -231,6 +232,18 @@
 
     void CrashMonitor::handleCrash(bool isFreeze)
     {
+        shmLock();
+        mShm->mMonitorStatus = CrashSHM::Status::Dumping;
+        shmUnlock();
+
+        auto failedDumping = [this](const std::string& message) {
+            Log(Debug::Error) << "CrashMonitor: " << message;
+            shmLock();
+            mShm->mMonitorStatus = CrashSHM::Status::FailedDumping;
+            shmUnlock();
+            SDL_ShowSimpleMessageBox(0, "Failed to create crash dump", 
message.c_str(), nullptr);
+        };
+
         DWORD processId = GetProcessId(mAppProcessHandle);
         const char* env = getenv("OPENMW_FULL_MEMDUMP");
 
@@ -238,7 +251,10 @@
         {
             HMODULE dbghelp = LoadLibraryA("dbghelp.dll");
             if (dbghelp == NULL)
+            {
+                failedDumping("Could not load dbghelp.dll");
                 return;
+            }
 
             using MiniDumpWirteDumpFn = BOOL(WINAPI*)(HANDLE hProcess, DWORD 
ProcessId, HANDLE hFile,
                 MINIDUMP_TYPE DumpType, PMINIDUMP_EXCEPTION_INFORMATION 
ExceptionParam,
@@ -246,11 +262,17 @@
 
             MiniDumpWirteDumpFn miniDumpWriteDump = 
(MiniDumpWirteDumpFn)GetProcAddress(dbghelp, "MiniDumpWriteDump");
             if (miniDumpWriteDump == NULL)
+            {
+                failedDumping("Could not get MiniDumpWriteDump address");
                 return;
+            }
 
             std::wstring utf16Path = (isFreeze ? getFreezeDumpPath(*mShm) : 
getCrashDumpPath(*mShm)).native();
             if (utf16Path.empty())
+            {
+                failedDumping("Empty dump path");
                 return;
+            }
 
             if (utf16Path.length() > MAX_PATH)
                 utf16Path = LR"(\\?\)" + utf16Path;
@@ -258,9 +280,17 @@
             HANDLE hCrashLog = CreateFileW(utf16Path.c_str(), GENERIC_READ | 
GENERIC_WRITE, 0, nullptr, CREATE_ALWAYS,
                 FILE_ATTRIBUTE_NORMAL, nullptr);
             if (hCrashLog == NULL || hCrashLog == INVALID_HANDLE_VALUE)
+            {
+                failedDumping("Bad dump file handle");
                 return;
+            }
             if (auto err = GetLastError(); err != ERROR_ALREADY_EXISTS && err 
!= 0)
+            {
+                std::stringstream ss;
+                ss << "Error opening dump file: " << std::hex << err;
+                failedDumping(ss.str());
                 return;
+            }
 
             EXCEPTION_POINTERS exp;
             exp.ContextRecord = &mShm->mCrashed.mContext;
@@ -274,15 +304,26 @@
             if (env)
                 type = static_cast<MINIDUMP_TYPE>(type | 
MiniDumpWithFullMemory);
 
-            miniDumpWriteDump(mAppProcessHandle, processId, hCrashLog, type, 
&infos, 0, 0);
+            if (!miniDumpWriteDump(mAppProcessHandle, processId, hCrashLog, 
type, &infos, 0, 0))
+            {
+                auto err = GetLastError();
+                std::stringstream ss;
+                ss << "Error while writing dump: " << std::hex << err;
+                failedDumping(ss.str());
+                return;
+            }
+
+            shmLock();
+            mShm->mMonitorStatus = CrashSHM::Status::DumpedSuccessfully;
+            shmUnlock();
         }
         catch (const std::exception& e)
         {
-            Log(Debug::Error) << "CrashMonitor: " << e.what();
+            failedDumping(e.what());
         }
         catch (...)
         {
-            Log(Debug::Error) << "CrashMonitor: unknown exception";
+            failedDumping("Unknown exception");
         }
     }
 
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/openmw-openmw-49-rc8/components/crashcatcher/windows_crashshm.hpp 
new/openmw-openmw-49-rc9/components/crashcatcher/windows_crashshm.hpp
--- old/openmw-openmw-49-rc8/components/crashcatcher/windows_crashshm.hpp       
2025-06-07 00:14:32.000000000 +0200
+++ new/openmw-openmw-49-rc9/components/crashcatcher/windows_crashshm.hpp       
2025-06-23 10:59:11.000000000 +0200
@@ -22,6 +22,17 @@
 
         Event mEvent;
 
+        enum class Status
+        {
+            Uninitialised,
+            Monitoring,
+            Dumping,
+            DumpedSuccessfully,
+            FailedDumping
+        };
+
+        Status mMonitorStatus;
+
         struct Startup
         {
             HANDLE mAppProcessHandle;
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/openmw-openmw-49-rc8/components/files/linuxpath.cpp 
new/openmw-openmw-49-rc9/components/files/linuxpath.cpp
--- old/openmw-openmw-49-rc8/components/files/linuxpath.cpp     2025-06-07 
00:14:32.000000000 +0200
+++ new/openmw-openmw-49-rc9/components/files/linuxpath.cpp     2025-06-23 
10:59:11.000000000 +0200
@@ -7,7 +7,6 @@
 #include <pwd.h>
 #include <unistd.h>
 
-#include <components/debug/debuglog.hpp>
 #include <components/misc/strings/lower.hpp>
 
 namespace
@@ -51,14 +50,6 @@
     LinuxPath::LinuxPath(const std::string& application_name)
         : mName(application_name)
     {
-        std::error_code ec;
-        current_path(getLocalPath(), ec);
-        const auto err = ec.value();
-        if (err != 0)
-        {
-            Log(Debug::Warning) << "Error " << err << " " << 
std::generic_category().message(errno)
-                                << " when changing current directory";
-        }
     }
 
     std::filesystem::path LinuxPath::getUserConfigPath() const
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/openmw-openmw-49-rc8/components/files/macospath.cpp 
new/openmw-openmw-49-rc9/components/files/macospath.cpp
--- old/openmw-openmw-49-rc8/components/files/macospath.cpp     2025-06-07 
00:14:32.000000000 +0200
+++ new/openmw-openmw-49-rc9/components/files/macospath.cpp     2025-06-23 
10:59:11.000000000 +0200
@@ -64,11 +64,6 @@
     MacOsPath::MacOsPath(const std::string& application_name)
         : mName(application_name)
     {
-        std::filesystem::path binary_path = getBinaryPath();
-        std::error_code ec;
-        std::filesystem::current_path(binary_path.parent_path(), ec);
-        if (ec.value() != 0)
-            Log(Debug::Warning) << "Error " << ec.message() << " when changing 
current directory";
     }
 
     std::filesystem::path MacOsPath::getUserConfigPath() const
@@ -102,7 +97,7 @@
 
     std::filesystem::path MacOsPath::getLocalPath() const
     {
-        return std::filesystem::path("../Resources/");
+        return getBinaryPath().parent_path().parent_path() / "Resources";
     }
 
     std::filesystem::path MacOsPath::getGlobalDataPath() const
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/openmw-openmw-49-rc8/components/files/windowspath.cpp 
new/openmw-openmw-49-rc9/components/files/windowspath.cpp
--- old/openmw-openmw-49-rc8/components/files/windowspath.cpp   2025-06-07 
00:14:32.000000000 +0200
+++ new/openmw-openmw-49-rc9/components/files/windowspath.cpp   2025-06-23 
10:59:11.000000000 +0200
@@ -26,10 +26,6 @@
     WindowsPath::WindowsPath(const std::string& application_name)
         : mName(application_name)
     {
-        std::error_code ec;
-        current_path(getLocalPath(), ec);
-        if (ec.value() != 0)
-            Log(Debug::Warning) << "Error " << ec.value() << " when changing 
current directory";
     }
 
     std::filesystem::path WindowsPath::getUserConfigPath() const
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/openmw-openmw-49-rc8/components/lua/utilpackage.cpp 
new/openmw-openmw-49-rc9/components/lua/utilpackage.cpp
--- old/openmw-openmw-49-rc8/components/lua/utilpackage.cpp     2025-06-07 
00:14:32.000000000 +0200
+++ new/openmw-openmw-49-rc9/components/lua/utilpackage.cpp     2025-06-23 
10:59:11.000000000 +0200
@@ -237,6 +237,7 @@
         colorType["asRgba"] = [](const Misc::Color& c) { return Vec4(c.r(), 
c.g(), c.b(), c.a()); };
         colorType["asRgb"] = [](const Misc::Color& c) { return Vec3(c.r(), 
c.g(), c.b()); };
         colorType["asHex"] = [](const Misc::Color& c) { return c.toHex(); };
+        colorType[sol::meta_function::equal_to] = [](const Misc::Color& a, 
const Misc::Color& b) { return a == b; };
 
         sol::table color(lua, sol::create);
         color["rgba"] = [](float r, float g, float b, float a) { return 
Misc::Color(r, g, b, a); };
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/openmw-openmw-49-rc8/components/misc/color.cpp 
new/openmw-openmw-49-rc9/components/misc/color.cpp
--- old/openmw-openmw-49-rc8/components/misc/color.cpp  2025-06-07 
00:14:32.000000000 +0200
+++ new/openmw-openmw-49-rc9/components/misc/color.cpp  2025-06-23 
10:59:11.000000000 +0200
@@ -6,13 +6,12 @@
 #include <sstream>
 #include <system_error>
 
+#include <components/sceneutil/util.hpp>
+
 namespace Misc
 {
     Color::Color(float r, float g, float b, float a)
-        : mR(std::clamp(r, 0.f, 1.f))
-        , mG(std::clamp(g, 0.f, 1.f))
-        , mB(std::clamp(b, 0.f, 1.f))
-        , mA(std::clamp(a, 0.f, 1.f))
+        : mValue(std::clamp(r, 0.f, 1.f), std::clamp(g, 0.f, 1.f), 
std::clamp(b, 0.f, 1.f), std::clamp(a, 0.f, 1.f))
     {
     }
 
@@ -27,26 +26,31 @@
     {
         if (hex.size() != 6)
             throw std::logic_error(std::string("Invalid hex color: ") += hex);
-        std::array<float, 3> rgb;
-        for (size_t i = 0; i < rgb.size(); i++)
+        Color col;
+        col.mValue.a() = 1;
+        for (size_t i = 0; i < 3; i++)
         {
             auto sub = hex.substr(i * 2, 2);
             int v = 0;
             auto [_, ec] = std::from_chars(sub.data(), sub.data() + 
sub.size(), v, 16);
             if (ec != std::errc())
                 throw std::logic_error(std::string("Invalid hex color: ") += 
hex);
-            rgb[i] = v / 255.0f;
+            col.mValue[i] = v / 255.0f;
         }
-        return Color(rgb[0], rgb[1], rgb[2], 1);
+        return col;
+    }
+
+    Color Color::fromRGB(unsigned int value)
+    {
+        return Color(SceneUtil::colourFromRGB(value));
     }
 
     std::string Color::toHex() const
     {
         std::string result(6, '0');
-        std::array<float, 3> rgb = { mR, mG, mB };
-        for (size_t i = 0; i < rgb.size(); i++)
+        for (size_t i = 0; i < 3; i++)
         {
-            int b = static_cast<int>(rgb[i] * 255.0f);
+            int b = static_cast<int>(mValue[i] * 255.0f);
             char* start = result.data() + i * 2;
             if (b < 16)
                 start++;
@@ -59,6 +63,6 @@
 
     bool operator==(const Color& l, const Color& r)
     {
-        return l.mR == r.mR && l.mG == r.mG && l.mB == r.mB && l.mA == r.mA;
+        return l.mValue == r.mValue;
     }
 }
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/openmw-openmw-49-rc8/components/misc/color.hpp 
new/openmw-openmw-49-rc9/components/misc/color.hpp
--- old/openmw-openmw-49-rc8/components/misc/color.hpp  2025-06-07 
00:14:32.000000000 +0200
+++ new/openmw-openmw-49-rc9/components/misc/color.hpp  2025-06-23 
10:59:11.000000000 +0200
@@ -3,31 +3,38 @@
 
 #include <string>
 
+#include <osg/Vec4>
+
 namespace Misc
 {
     class Color
     {
+        explicit Color(osg::Vec4&& value)
+            : mValue(value)
+        {
+        }
+
     public:
+        Color() = default;
         Color(float r, float g, float b, float a);
 
-        float r() const { return mR; }
-        float g() const { return mG; }
-        float b() const { return mB; }
-        float a() const { return mA; }
+        float r() const { return mValue.r(); }
+        float g() const { return mValue.g(); }
+        float b() const { return mValue.b(); }
+        float a() const { return mValue.a(); }
 
         std::string toString() const;
 
         static Color fromHex(std::string_view hex);
+        static Color fromRGB(unsigned int value);
 
         std::string toHex() const;
+        unsigned int toRGBA() const { return mValue.asRGBA(); }
 
         friend bool operator==(const Color& l, const Color& r);
 
     private:
-        float mR;
-        float mG;
-        float mB;
-        float mA;
+        osg::Vec4 mValue;
     };
 }
 
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/openmw-openmw-49-rc8/components/process/processinvoker.cpp 
new/openmw-openmw-49-rc9/components/process/processinvoker.cpp
--- old/openmw-openmw-49-rc8/components/process/processinvoker.cpp      
2025-06-07 00:14:32.000000000 +0200
+++ new/openmw-openmw-49-rc9/components/process/processinvoker.cpp      
2025-06-23 10:59:11.000000000 +0200
@@ -1,14 +1,11 @@
 #include "processinvoker.hpp"
 
+#include <QCoreApplication>
 #include <QDir>
 #include <QMessageBox>
 #include <QString>
 #include <QStringList>
 
-#if defined(Q_OS_MAC)
-#include <QCoreApplication>
-#endif
-
 Process::ProcessInvoker::ProcessInvoker(QObject* parent)
     : QObject(parent)
 {
@@ -60,12 +57,9 @@
     QString path(name);
 #ifdef Q_OS_WIN
     path.append(QLatin1String(".exe"));
-#elif defined(Q_OS_MAC)
-    QDir dir(QCoreApplication::applicationDirPath());
-    path = dir.absoluteFilePath(name);
-#else
-    path.prepend(QLatin1String("./"));
 #endif
+    QDir dir(QCoreApplication::applicationDirPath());
+    path = dir.absoluteFilePath(path);
 
     QFileInfo info(path);
 
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/openmw-openmw-49-rc8/docs/source/reference/modding/paths.rst 
new/openmw-openmw-49-rc9/docs/source/reference/modding/paths.rst
--- old/openmw-openmw-49-rc8/docs/source/reference/modding/paths.rst    
2025-06-07 00:14:32.000000000 +0200
+++ new/openmw-openmw-49-rc9/docs/source/reference/modding/paths.rst    
2025-06-23 10:59:11.000000000 +0200
@@ -75,6 +75,7 @@
 
 Configuration for OpenMW is composed from several sources.
 From lowest to highest priority, these are:
+
 * The local or global ``openmw.cfg``.
 * Any ``openmw.cfg`` files in any other directories specified with the 
``config`` option.
 * Options specified on the command line.
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/openmw-openmw-49-rc8/files/lua_api/openmw/core.lua 
new/openmw-openmw-49-rc9/files/lua_api/openmw/core.lua
--- old/openmw-openmw-49-rc8/files/lua_api/openmw/core.lua      2025-06-07 
00:14:32.000000000 +0200
+++ new/openmw-openmw-49-rc9/files/lua_api/openmw/core.lua      2025-06-23 
10:59:11.000000000 +0200
@@ -635,7 +635,7 @@
 -- @usage local spell = core.magic.spells.records[1]  -- get by index
 -- @usage -- Print all powers
 -- for _, spell in pairs(core.magic.spells.records) do
---     if spell.types == core.magic.SPELL_TYPE.Power then
+--     if spell.type == core.magic.SPELL_TYPE.Power then
 --         print(spell.name)
 --     end
 -- end
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/openmw-openmw-49-rc8/files/lua_api/openmw/types.lua 
new/openmw-openmw-49-rc9/files/lua_api/openmw/types.lua
--- old/openmw-openmw-49-rc8/files/lua_api/openmw/types.lua     2025-06-07 
00:14:32.000000000 +0200
+++ new/openmw-openmw-49-rc9/files/lua_api/openmw/types.lua     2025-06-23 
10:59:11.000000000 +0200
@@ -808,8 +808,8 @@
 -- A read-only list of all @{#CreatureRecord}s in the world database, may be 
indexed by recordId.
 -- Implements [iterables#List](iterables.html#List) of #CreatureRecord.
 -- @field [parent=#Creature] #list<#CreatureRecord> records
--- @usage local record = types.NPC.classes['example_recordid']
--- @usage local record = types.NPC.classes[1]
+-- @usage local creature = types.Creature.records['creature id']  -- get by id
+-- @usage local creature = types.Creature.records[1]  -- get by index
 
 ---
 -- Whether the object is a creature.
@@ -876,8 +876,8 @@
 -- A read-only list of all @{#NpcRecord}s in the world database, may be 
indexed by recordId.
 -- Implements [iterables#List](iterables.html#List) of #NpcRecord.
 -- @field [parent=#NPC] #map<#NpcRecord> records
--- @usage local record = types.NPC.classes['example_recordid']
--- @usage local record = types.NPC.classes[1]
+-- @usage local npc = types.NPC.records['npc id']  -- get by id
+-- @usage local npc = types.NPC.records[1]  -- get by index
 
 ---
 -- Whether the object is an NPC or a Player.
@@ -1048,8 +1048,8 @@
 -- A read-only list of all @{#ClassRecord}s in the world database, may be 
indexed by recordId.
 -- Implements [iterables#List](iterables.html#List) of #ClassRecord.
 -- @field [parent=#Classes] #list<#ClassRecord> records
--- @usage local record = types.NPC.classes['example_recordid']
--- @usage local record = types.NPC.classes[1]
+-- @usage local class = types.NPC.classes.records['class id']  -- get by id
+-- @usage local class = types.NPC.classes.records[1]  -- get by index
 
 ---
 -- Returns a read-only @{#ClassRecord}
@@ -1088,8 +1088,8 @@
 -- A read-only list of all @{#RaceRecord}s in the world database.
 -- Implements [iterables#List](iterables.html#List) of #RaceRecord.
 -- @field [parent=#Races] #list<#RaceRecord> records
--- @usage local record = types.NPC.classes['example_recordid']
--- @usage local record = types.NPC.classes[1]
+-- @usage local race = types.NPC.races.records['race id']  -- get by id
+-- @usage local race = types.NPC.races.records[1]  -- get by index
 
 ---
 -- Returns a read-only @{#RaceRecord}
@@ -1275,8 +1275,8 @@
 -- A read-only list of all @{#BirthSignRecord}s in the world database.
 -- Implements [iterables#List](iterables.html#List) of #BirthSignRecord.
 -- @field [parent=#BirthSigns] #list<#BirthSignRecord> records
--- @usage local record = types.NPC.classes['example_recordid']
--- @usage local record = types.NPC.classes[1]
+-- @usage local birthSign = types.Player.birthSigns.records['birthsign id']  
-- get by id
+-- @usage local birthSign = types.Player.birthSigns.records[1]  -- get by index
 
 ---
 -- Returns a read-only @{#BirthSignRecord}
@@ -1673,7 +1673,7 @@
 -- @field #number value
 -- @field #number duration
 -- @field #number radius
--- @field #number color
+-- @field openmw.util#Color color
 -- @field #boolean isCarriable True if the light can be carried by actors and 
appears up in their inventory.
 -- @field #boolean isDynamic If true, the light will apply to actors and other 
moving objects
 -- @field #boolean isFire True if the light acts like a fire.
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/openmw-openmw-49-rc8/files/org.openmw.cs.desktop 
new/openmw-openmw-49-rc9/files/org.openmw.cs.desktop
--- old/openmw-openmw-49-rc8/files/org.openmw.cs.desktop        2025-06-07 
00:14:32.000000000 +0200
+++ new/openmw-openmw-49-rc9/files/org.openmw.cs.desktop        2025-06-23 
10:59:11.000000000 +0200
@@ -8,3 +8,4 @@
 Exec=openmw-cs
 Icon=openmw-cs
 Categories=Game;RolePlaying;
+StartupWMClass=openmw-cs
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/openmw-openmw-49-rc8/files/org.openmw.launcher.desktop 
new/openmw-openmw-49-rc9/files/org.openmw.launcher.desktop
--- old/openmw-openmw-49-rc8/files/org.openmw.launcher.desktop  2025-06-07 
00:14:32.000000000 +0200
+++ new/openmw-openmw-49-rc9/files/org.openmw.launcher.desktop  2025-06-23 
10:59:11.000000000 +0200
@@ -8,3 +8,4 @@
 Exec=openmw-launcher
 Icon=openmw
 Categories=Game;RolePlaying;
+StartupWMClass=openmw-launcher
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/openmw-openmw-49-rc8/scripts/data/integration_tests/test_lua_api/global.lua 
new/openmw-openmw-49-rc9/scripts/data/integration_tests/test_lua_api/global.lua
--- 
old/openmw-openmw-49-rc8/scripts/data/integration_tests/test_lua_api/global.lua 
    2025-06-07 00:14:32.000000000 +0200
+++ 
new/openmw-openmw-49-rc9/scripts/data/integration_tests/test_lua_api/global.lua 
    2025-06-23 10:59:11.000000000 +0200
@@ -157,7 +157,7 @@
         value = 10,
         duration = 12,
         radius = 30,
-        color = 5,
+        color = util.color.hex('123456'),
         name = "TestLight",
         model = "meshes/marker_door.dae"
     }

Reply via email to