diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml
index 139b0654d3..7c0cc1b846 100644
--- a/.github/workflows/build.yml
+++ b/.github/workflows/build.yml
@@ -7,6 +7,10 @@ on:
- '*LICENSE'
pull_request:
+concurrency:
+ group: ${{ github.workflow }}-${{ github.event_name == 'pull_request' && format('pr-{0}', github.event.pull_request.number) || format('run-{0}', github.run_id) }}
+ cancel-in-progress: ${{ github.event_name == 'pull_request' }}
+
env:
SCCACHE_GHA_ENABLED: "true"
RUSTC_WRAPPER: "sccache"
@@ -22,13 +26,13 @@ jobs:
matrix:
include:
- name: GCC x86_64
- runner: ubuntu-latest
+ runner: ubuntu-24.04
preset: gcc
artifact_arch: x86_64
- # - name: GCC aarch64
- # runner: ubuntu-24.04-arm
- # preset: gcc
- # artifact_arch: aarch64
+ - name: GCC aarch64
+ runner: ubuntu-24.04-arm
+ preset: gcc
+ artifact_arch: aarch64
# - name: Clang x86_64
# runner: ubuntu-latest
# preset: clang
@@ -221,12 +225,12 @@ jobs:
msvc_arch: amd64
vcpkg_arch: x64
artifact_arch: x86_64
- # - name: MSVC arm64
- # runner: windows-11-arm
- # preset: arm64-msvc
- # msvc_arch: arm64
- # vcpkg_arch: arm64
- # artifact_arch: arm64
+ - name: MSVC arm64
+ runner: windows-latest
+ preset: arm64-msvc
+ msvc_arch: amd64_arm64
+ vcpkg_arch: arm64
+ artifact_arch: arm64
# - name: Clang x86_64
# runner: windows-latest
# preset: clang
@@ -255,7 +259,7 @@ jobs:
- name: Install dependencies
run: |
choco install ninja
- vcpkg install freetype:${{matrix.vcpkg_arch}}-windows-static zstd:${{matrix.vcpkg_arch}}-windows-static
+ vcpkg install freetype:${{matrix.vcpkg_arch}}-windows zstd:${{matrix.vcpkg_arch}}-windows
- name: Configure CMake
run: cmake --preset x-windows-ci-${{matrix.preset}}
diff --git a/CMakeLists.txt b/CMakeLists.txt
index fff82f17a2..5cb2e5a600 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -11,6 +11,7 @@ if (DUSK_VERSION_OVERRIDE)
set(DUSK_WC_DESCRIBE "${DUSK_VERSION_OVERRIDE}")
set(DUSK_VERSION_STRING "0.0.0.0")
set(DUSK_SHORT_VERSION_STRING "0.0.0")
+ set(DUSK_VERSION_CODE "1")
set(DUSK_WC_REVISION "")
set(DUSK_WC_BRANCH "")
set(DUSK_WC_DATE "")
@@ -61,6 +62,9 @@ endif ()
if (DUSK_WC_DESCRIBE MATCHES "^v([0-9]+)\\.([0-9]+)\\.([0-9]+)([-+].*)?$")
set(DUSK_SHORT_VERSION_STRING "${CMAKE_MATCH_1}.${CMAKE_MATCH_2}.${CMAKE_MATCH_3}")
+ set(_ver_major ${CMAKE_MATCH_1})
+ set(_ver_minor ${CMAKE_MATCH_2})
+ set(_ver_patch ${CMAKE_MATCH_3})
set(DUSK_VERSION_TWEAK "0")
if (DUSK_WC_DESCRIBE MATCHES "^v[0-9]+\\.[0-9]+\\.[0-9]+-([0-9]+)(-dirty)?$")
set(DUSK_VERSION_TWEAK "${CMAKE_MATCH_1}")
@@ -68,10 +72,19 @@ if (DUSK_WC_DESCRIBE MATCHES "^v([0-9]+)\\.([0-9]+)\\.([0-9]+)([-+].*)?$")
set(DUSK_VERSION_TWEAK "${CMAKE_MATCH_1}")
endif ()
set(DUSK_VERSION_STRING "${DUSK_SHORT_VERSION_STRING}.${DUSK_VERSION_TWEAK}")
+ if(DUSK_VERSION_TWEAK GREATER 999)
+ set(_tweak 999)
+ else()
+ set(_tweak ${DUSK_VERSION_TWEAK})
+ endif()
+ # encoding: major*1e7 + minor*1e5 + patch*1e3 + tweak; collision-free for major<210, minor<100, patch<100, tweak<=999
+ math(EXPR DUSK_VERSION_CODE
+ "${_ver_major} * 10000000 + ${_ver_minor} * 100000 + ${_ver_patch} * 1000 + ${_tweak}")
else ()
set(DUSK_WC_DESCRIBE "UNKNOWN-VERSION")
set(DUSK_VERSION_STRING "0.0.0.0")
set(DUSK_SHORT_VERSION_STRING "0.0.0")
+ set(DUSK_VERSION_CODE "1")
endif ()
endif ()
@@ -79,6 +92,7 @@ endif ()
# Add version information to CI environment variables
if(DEFINED ENV{GITHUB_ENV})
file(APPEND "$ENV{GITHUB_ENV}" "DUSK_VERSION=${DUSK_WC_DESCRIBE}\n")
+ file(APPEND "$ENV{GITHUB_ENV}" "DUSK_VERSION_CODE=${DUSK_VERSION_CODE}\n")
endif()
message(STATUS "Dusklight version set to ${DUSK_WC_DESCRIBE}")
message(STATUS "Build type: ${CMAKE_BUILD_TYPE}")
@@ -86,6 +100,8 @@ project(dusklight LANGUAGES C CXX VERSION ${DUSK_VERSION_STRING})
if (APPLE)
enable_language(OBJC OBJCXX)
endif ()
+# Adjust CMAKE_SYSTEM_PROCESSOR on Windows to match compiler target
+include(cmake/WindowsTargetProcessor.cmake)
if (APPLE AND NOT TVOS AND CMAKE_SYSTEM_NAME STREQUAL tvOS)
# ios.toolchain.cmake hack for SDL
set(TVOS ON)
@@ -161,6 +177,7 @@ if (DUSK_MOVIE_SUPPORT)
endif ()
set(_jpeg_cmake_args
-DCMAKE_INSTALL_PREFIX=${_jpeg_install_dir}
+ -DCMAKE_PROJECT_INCLUDE=${CMAKE_CURRENT_SOURCE_DIR}/cmake/WindowsTargetProcessor.cmake
-DENABLE_SHARED=OFF
-DWITH_TURBOJPEG=ON
-DWITH_JAVA=OFF
@@ -381,6 +398,10 @@ endif ()
if (WIN32)
list(APPEND GAME_LIBS Ws2_32)
+ if (CMAKE_BUILD_TYPE STREQUAL Debug)
+ list(APPEND GAME_LIBS dbghelp)
+ list(APPEND GAME_COMPILE_DEFS DUSK_CRASH_DBGHELP=1)
+ endif ()
endif ()
set(DUSK_HTTP_BACKEND_SOURCE src/dusk/http/no_backend.cpp)
@@ -548,6 +569,10 @@ if (ANDROID)
target_link_options(${DUSK_MAIN_TARGET} PRIVATE "-Wl,-u,SDL_main")
endif ()
+if (CMAKE_SYSTEM_NAME STREQUAL Linux)
+ target_link_options(dusklight PRIVATE "-Wl,--build-id=sha1")
+endif ()
+
if (NOT APPLE)
add_custom_command(TARGET dusklight POST_BUILD
COMMAND ${CMAKE_COMMAND} -E copy_directory
diff --git a/CMakePresets.json b/CMakePresets.json
index 0201c61ed6..748c4df396 100644
--- a/CMakePresets.json
+++ b/CMakePresets.json
@@ -33,7 +33,11 @@
"value": true
},
"DUSK_SENTRY_DSN": "$env{SENTRY_DSN}",
- "DUSK_SENTRY_ENVIRONMENT": "production"
+ "DUSK_SENTRY_ENVIRONMENT": "production",
+ "Rust_RUSTUP_INSTALL_MISSING_TARGET": {
+ "type": "BOOL",
+ "value": true
+ }
}
},
{
@@ -322,7 +326,9 @@
"BUILD_SHARED_LIBS": {
"type": "BOOL",
"value": false
- }
+ },
+ "AURORA_SDL3_VERSION": "3.4.8",
+ "AURORA_SDL3_REF": "refs/tags/release-3.4.8"
}
},
{
@@ -430,7 +436,6 @@
"x-macos-ci"
],
"cacheVariables": {
- "AURORA_DAWN_PROVIDER": "vendor",
"CMAKE_OSX_ARCHITECTURES": "x86_64",
"Rust_CARGO_TARGET": "x86_64-apple-darwin"
}
@@ -490,7 +495,10 @@
"inherits": [
"x-windows-ci",
"windows-arm64-msvc"
- ]
+ ],
+ "cacheVariables": {
+ "VCPKG_TARGET_TRIPLET": "arm64-windows"
+ }
}
],
"buildPresets": [
diff --git a/README.md b/README.md
index 106d2c0a0e..5a9701bede 100644
--- a/README.md
+++ b/README.md
@@ -22,16 +22,11 @@ It aims to be as accurate as possible to the original while also providing new o
> [!IMPORTANT]
> At a minimum, Dusklight requires a GPU with support for either D3D12, Vulkan, or Metal. Your experience with specific hardware, operating systems, and drivers may vary. In particular, older Intel iGPUs have a high likelihood of incompatibility. We are also aware of a number of issues on devices with Adreno GPUs and are working to resolve them.
-### 1. Verify your dump
+### 1. Dump your game
-First, make sure your dump of the game is clean and supported by Dusklight. You can do this by checking the SHA-1 hash of your dump against this list of supported versions:
+You must dump your own copy of the game, please see [this article](https://wiki.dolphin-emu.org/index.php?title=Ripping_Games) for instructions. After dumping, you can use a program like [Dolphin](https://dolphin-emu.org/) or [nodtool](https://github.com/encounter/nod/releases) to convert the `.iso` to a `.rvz` to save space.
-| Version | SHA-1 hash |
-|--------------| ------------------------------------------ |
-| GameCube USA | `75edd3ddff41f125d1b4ce1a40378f1b565519e7` |
-| GameCube EUR | `2601822a488eeb86fb89db16ca8f29c2c953e1ca` |
-
-*Support for other versions of the game is planned in the future.
+Currently, only the GameCube USA and EUR releases are supported. Support for other versions of the game is planned in the future.
### 2. Download [Dusklight](https://github.com/TwilitRealm/dusklight/releases)
diff --git a/ci/build-appimage.sh b/ci/build-appimage.sh
index 6653876f71..e12f1163b9 100755
--- a/ci/build-appimage.sh
+++ b/ci/build-appimage.sh
@@ -6,6 +6,7 @@ fi
build_dir="$PWD/build"
linuxdeploy="$build_dir/linuxdeploy-$(uname -m).AppImage"
+lib_dir="/usr/lib/$(uname -m)-linux-gnu"
# Get linuxdeploy
mkdir -p "$build_dir"
@@ -19,8 +20,8 @@ for install_path in build/install/*; do
cp -r "$install_path" build/appdir/usr/bin
done
cp -r platforms/freedesktop/{16x16,32x32,48x48,64x64,128x128,256x256,512x512,1024x1024} build/appdir/usr/share/icons/hicolor
-cp platforms/freedesktop/dusklight.desktop build/appdir/usr/share/applications
+cp platforms/freedesktop/dev.twilitrealm.dusk.desktop build/appdir/usr/share/applications
cd build/install
VERSION="$DUSK_VERSION" NO_STRIP=1 "$linuxdeploy" \
- -l /usr/lib/x86_64-linux-gnu/libusb-1.0.so --appdir "$build_dir/appdir" --output appimage
+ -l "$lib_dir/libusb-1.0.so" --appdir "$build_dir/appdir" --output appimage
diff --git a/cmake/WindowsTargetProcessor.cmake b/cmake/WindowsTargetProcessor.cmake
new file mode 100644
index 0000000000..0fba82add5
--- /dev/null
+++ b/cmake/WindowsTargetProcessor.cmake
@@ -0,0 +1,9 @@
+if (CMAKE_SYSTEM_NAME STREQUAL "Windows")
+ if (CMAKE_C_COMPILER_ARCHITECTURE_ID STREQUAL "ARM64" OR CMAKE_C_COMPILER_ARCHITECTURE_ID STREQUAL "ARM64EC")
+ set(CMAKE_SYSTEM_PROCESSOR "ARM64")
+ elseif (CMAKE_C_COMPILER_ARCHITECTURE_ID STREQUAL "x64")
+ set(CMAKE_SYSTEM_PROCESSOR "AMD64")
+ elseif (CMAKE_C_COMPILER_ARCHITECTURE_ID STREQUAL "X86")
+ set(CMAKE_SYSTEM_PROCESSOR "X86")
+ endif ()
+endif ()
diff --git a/docs/building.md b/docs/building.md
index 1001c42788..9f7879ab48 100644
--- a/docs/building.md
+++ b/docs/building.md
@@ -1,50 +1,164 @@
-### Building
-#### Prerequisites
+# Building Dusklight
+
+## Dependencies
+
+The following dependencies are required:
+
* [CMake 3.25+](https://cmake.org)
- * Windows: Install `CMake Tools` in Visual Studio
- * macOS: `brew install cmake`
* [Python 3+](https://python.org)
- * Windows: [Microsoft Store](https://go.microsoft.com/fwlink?linkID=2082640)
- * Verify it's added to `%PATH%` by typing `python` in `cmd`.
- * macOS: `brew install python@3`
-* **[Windows]** [Visual Studio 2026 Community](https://www.visualstudio.com/en-us/products/visual-studio-community-vs.aspx)
- * Select `C++ Development` and verify the following packages are included:
- * `Windows 11 SDK`
- * `CMake Tools`
- * `C++ Clang Compiler`
- * `C++ Clang-cl`
-* **[macOS]** [Xcode 16.4+](https://developer.apple.com/xcode/download/)
-* **[Linux]** Actively tested on Ubuntu 24.04, Arch Linux & derivatives.
- * Ubuntu 24.04+ packages
- ```
- build-essential curl git ninja-build clang lld zlib1g-dev libcurl4-openssl-dev \
- libglu1-mesa-dev libdbus-1-dev libvulkan-dev libxi-dev libxrandr-dev libasound2-dev libpulse-dev \
- libudev-dev libpng-dev libncurses5-dev cmake libx11-xcb-dev python3 python-is-python3 \
- libclang-dev libfreetype-dev libxinerama-dev libxcursor-dev python3-markupsafe libgtk-3-dev \
- libxss-dev libxtst-dev
- ```
- * Arch Linux packages
- ```
- base-devel cmake ninja llvm vulkan-headers python python-markupsafe clang lld alsa-lib libpulse libxrandr freetype2
- ```
- * Fedora packages
- ```
- cmake vulkan-headers ninja-build clang-devel llvm-devel libpng-devel
- ```
- * It's also important that you install the developer tools and libraries
- ```
- sudo dnf groupinstall "Development Tools" "Development Libraries"
- ```
-#### Setup
-Clone and initialize the Dusklight repository
+
+### Windows
+
+* Install [CMake 3.25+](https://cmake.org) by searching `CMake Tools` in Visual Studio
+* Install Python 3 from the [Microsoft Store](https://go.microsoft.com/fwlink?linkID=2082640) and verify it's added to `%PATH%` by typing `python` in `cmd`.
+
+Recommended IDEs:
+
+* [Visual Studio 2026 Community](https://www.visualstudio.com/en-us/products/visual-studio-community-vs.aspx). During installation:
+ * Select `C++ Development` and verify the following packages are included:
+ * `Windows 11 SDK`
+ * `CMake Tools`
+ * `C++ Clang Compiler`
+ * `C++ Clang-cl`
+
+### macOS
+
+* Make sure [Homebrew](https://brew.sh) is installed
+* Install [CMake 3.25+](https://cmake.org)
+
```sh
-git clone --recursive https://github.com/TwilitRealm/dusklight.git
-cd dusklight
-git pull
-git submodule update --init --recursive
+brew install cmake
```
-#### Building
+* Install Python 3
+
+```sh
+brew install python@3
+```
+
+Recommended IDEs:
+
+* [Xcode 16.4 or later](https://developer.apple.com/xcode/)
+* [Visual Studio Code](https://code.visualstudio.com/download/)
+* [CLion](https://www.jetbrains.com/clion/)
+
+### Linux
+
+Actively tested on Ubuntu 24.04, Arch Linux & derivatives.
+
+**Ubuntu 24.04+ packages**
+
+
+Click to expand
+
+* Run the following command to install the required dependencies:
+
+```sh
+sudo apt update && sudo apt install -y \
+ build-essential \
+ clang \
+ cmake \
+ curl \
+ git \
+ libasound2-dev \
+ libclang-dev \
+ libcurl4-openssl-dev \
+ libdbus-1-dev \
+ libfreetype-dev \
+ libglu1-mesa-dev \
+ libgtk-3-dev \
+ libncurses5-dev \
+ libpng-dev \
+ libpulse-dev \
+ libudev-dev \
+ libvulkan-dev \
+ libx11-xcb-dev \
+ libxcursor-dev \
+ libxi-dev \
+ libxinerama-dev \
+ libxrandr-dev \
+ libxss-dev \
+ libxtst-dev \
+ lld \
+ ninja-build \
+ python-is-python3 \
+ python3 \
+ python3-markupsafe \
+ zlib1g-dev
+```
+
+
+
+
+**Arch Linux packages**
+
+
+Click to expand
+
+* Run the following command to install the required dependencies:
+
+```sh
+sudo pacman -S --needed \
+ alsa-lib \
+ base-devel \
+ clang \
+ cmake \
+ freetype2 \
+ libpulse \
+ libxrandr \
+ lld \
+ llvm \
+ ninja \
+ python \
+ python-markupsafe \
+ vulkan-headers
+```
+
+
+
+
+**Fedora packages**
+
+
+Click to expand
+
+* Run the following command to install the required dependencies:
+
+```sh
+sudo dnf install -y \
+ clang-devel \
+ cmake \
+ libpng-devel \
+ llvm-devel \
+ ninja-build \
+ vulkan-headers
+```
+
+* It's also important that you install the developer tools and libraries
+
+```sh
+sudo dnf groupinstall \
+ "Development Libraries" "Development Tools"
+```
+
+
+
+
+Recommended IDEs:
+
+* [CLion](https://www.jetbrains.com/clion/)
+* [Visual Studio Code](https://code.visualstudio.com/download/)
+
+## Building
+
+* Clone and initialize the Dusklight repository:
+
+```sh
+git clone --recursive https://github.com/TwilitRealm/dusklight.git
+git pull
+cd dusklight
+git submodule update --init --recursive
+```
**CLion (Windows / macOS / Linux)**
@@ -64,7 +178,8 @@ cmake --build --preset macos-default-relwithdebinfo
```
Alternate presets available:
-- `macos-default-debug`: Clang, Debug
+
+* `macos-default-debug`: Clang, Debug
**ninja (Linux)**
@@ -74,9 +189,10 @@ cmake --build --preset linux-default-relwithdebinfo
```
Alternate presets available:
-- `linux-default-debug`: GCC, Debug
-- `linux-clang-relwithdebinfo`: Clang, RelWithDebInfo
-- `linux-clang-debug`: Clang, Debug
+
+* `linux-default-debug`: GCC, Debug
+* `linux-clang-relwithdebinfo`: Clang, RelWithDebInfo
+* `linux-clang-debug`: Clang, Debug
**ninja (Windows)**
@@ -86,13 +202,27 @@ cmake --build --preset windows-msvc-relwithdebinfo
```
Alternate presets available:
-- `windows-msvc-debug`: MSVC, Debug
-- `windows-clang-relwithdebinfo`: Clang-cl, RelWithDebInfo
-- `windows-clang-debug`: Clang-cl, Debug
-#### Running
-Pass the disc image as a positional argument. Supported formats: ISO (GCM), RVZ, WIA, WBFS, CISO, GCZ
+* `windows-msvc-debug`: MSVC, Debug
+* `windows-clang-relwithdebinfo`: Clang-cl, RelWithDebInfo
+* `windows-clang-debug`: Clang-cl, Debug
+
+## Running
+
+**Windows / Linux**
+
+* Pass the disc image as a positional argument using the `--dvd` flag. Supported formats are: ISO (GCM), RVZ, WIA, WBFS, CISO, GCZ
+
```sh
-build/{preset}/dusklight/path/to/game.rvz
+build/{preset}/dusklight --dvd /path/to/game.iso
+```
+
+**macOS**
+
+macOS builds an `.app` bundle which contains the executable and all necessary resources.
+
+* Pass the disc image as a positional argument using the `--dvd` flag. Supported formats are: ISO (GCM), RVZ, WIA, WBFS, CISO, GCZ
+
+```sh
+build/{preset}/Dusklight.app/Contents/MacOS/Dusklight --dvd /path/to/game.iso
```
-If no path is specified, Dusklight defaults to `game.iso` in the current working directory.
diff --git a/docs/ios-install-altstore.md b/docs/ios-install-altstore.md
index c82bfec5c3..5c0f071878 100644
--- a/docs/ios-install-altstore.md
+++ b/docs/ios-install-altstore.md
@@ -4,10 +4,10 @@
- A Windows, Linux, or macOS device
- iOS device connected to computer via USB
-- Dusklight IPA file (download the latest `Dusklight-vX.X.X-ios-arm64.ipa` from the [releases page](https://github.com/TwilitRealm/dusk/releases))
-- Game disc - `GZ2E01` (Gamecube USA) or `GZ2PE01` (Gamecube PAL)
+- Dusklight IPA file (download the latest `Dusklight-vX.X.X-ios-arm64.ipa` from the [releases page](https://github.com/TwilitRealm/dusklight/releases))
+- Legally acquired game disc - `GZ2E01` (Gamecube USA) or `GZ2PE01` (Gamecube PAL)
-## 1. Install AltServer
+## 1. Install iloader
- Executable bundles can be installed from [iloader's main page](https://iloader.app/) or [their GitHub](https://github.com/nab138/iloader) for Windows, Linux, and macOS.
- Windows WILL require iTunes to be installed
@@ -16,21 +16,21 @@
## 2. Enable Developer Mode (iOS 16+)
- On your iPhone, go to **Settings > Privacy & Security > Developer Mode**
-- Toggle it on and restart when prompted
+- Toggle it on, put in your device passcode, and restart when prompted
## 3. Install Dusklight on Your iPhone
-1. Sign into your Apple ID (this is required for registering app IDs, it is sent securely and not stored by iloader)
- * You may be prompted to put in a code from your iOS device, do so
+1. Sign into your Apple ID (this is required for registering app IDs, it is sent securely directly to Apple and not stored by iloader)
+ * You may be prompted to put in a code from your iOS device if you have 2FA enabled, do so
2. Plug in your iOS device via USB into your PC. If you're missing a dependency, an error pop-up will tell you to install it
* You will need to hit `Refresh` after plugging it in at this stage so that it can be detected, it does not automatically refresh
3. Leave settings unchanged (the Anisette server should stay Sidestore (.io))
3.(a) Installing SideStore directly is not required, but provides you a way to install Dusklight on your phone without being plugged into a computer later
-4. Press `Import IPA` and choose your downloaded `Dusk-v.X.X.X-ios-arm64.ipa`, it will begin installing on your device
+4. Press `Import IPA` and choose your downloaded `Dusklight-v.X.X.X-ios-arm64.ipa`, it will begin installing on your device
**NOTE:** *At various stages, you may be prompted to trust your device, do so*
-## 3. Getting Dusk trusted
+## 3. Getting Dusklight trusted
When installing sideloaded iOS applications, at first you will need to manually trust the app due to Apple's security policies
* Go to **Settings > General > VPN & Device Management**
* Tap the Apple ID you signed into iloader with under "Developer App" and tap **Trust**
@@ -38,11 +38,11 @@ When installing sideloaded iOS applications, at first you will need to manually
## 4. Copy Files to Your iPhone
-Transfer the IPA and game disc to your iPhone so they're accessible in the Files app. A few ways to do this:
+Transfer the game disc (and optionally, the Dusklight IPA) to your iPhone so they are accessible in the Files app. A few ways to do this:
- **AirDrop** - Right-click the files on your Mac and choose Share > AirDrop
- **iCloud Drive** - Place files in iCloud Drive on your Mac and they'll sync to Files on your iPhone
- **USB transfer** - Connect your iPhone and drag files via Finder's sidebar
- **Cloud storage** - Upload to Google Drive, Dropbox, etc. and download on your iPhone
-You may now use Dusklight on iOS, iPadOS!
\ No newline at end of file
+You may now use Dusklight on iOS and iPadOS!
\ No newline at end of file
diff --git a/extern/aurora b/extern/aurora
index 40913d532e..cb2c340d6c 160000
--- a/extern/aurora
+++ b/extern/aurora
@@ -1 +1 @@
-Subproject commit 40913d532e5859a68e56b88d8aaec6bff1b88a2e
+Subproject commit cb2c340d6cde6827387f14c31ce19e5f28a40e09
diff --git a/files.cmake b/files.cmake
index a0370df464..bdc214597b 100644
--- a/files.cmake
+++ b/files.cmake
@@ -1420,6 +1420,7 @@ set(DUSK_FILES
src/d/actor/d_a_alink_dusk.cpp
src/dusk/asserts.cpp
src/dusk/config.cpp
+ src/dusk/crash_handler.cpp
src/dusk/crash_reporting.cpp
src/dusk/data.cpp
src/dusk/data.hpp
@@ -1439,6 +1440,7 @@ set(DUSK_FILES
src/dusk/logging.cpp
src/dusk/settings.cpp
src/dusk/speedrun.cpp
+ src/dusk/string.cpp
src/dusk/stubs.cpp
src/dusk/update_check.cpp
src/dusk/update_check.hpp
diff --git a/flake.lock b/flake.lock
index 8ec14d2852..08dc0f458c 100644
--- a/flake.lock
+++ b/flake.lock
@@ -2,11 +2,11 @@
"nodes": {
"nixpkgs": {
"locked": {
- "lastModified": 1775710090,
- "narHash": "sha256-ar3rofg+awPB8QXDaFJhJ2jJhu+KqN/PRCXeyuXR76E=",
+ "lastModified": 1778869304,
+ "narHash": "sha256-30sZNZoA1cqF5JNO9fVX+wgiQYjB7HJqqJ4ztCDeBZE=",
"owner": "nixos",
"repo": "nixpkgs",
- "rev": "4c1018dae018162ec878d42fec712642d214fdfa",
+ "rev": "d233902339c02a9c334e7e593de68855ad26c4cb",
"type": "github"
},
"original": {
diff --git a/flake.nix b/flake.nix
index edba703a3d..0a2156a4d5 100644
--- a/flake.nix
+++ b/flake.nix
@@ -1,228 +1,374 @@
{
- inputs = {
- nixpkgs.url = "github:nixos/nixpkgs?ref=nixos-unstable";
- };
- outputs = { self, nixpkgs }:
+ description = "Dusklight — native PC port of the Twilight Princess decompilation";
+
+ inputs.nixpkgs.url = "github:nixos/nixpkgs?ref=nixos-unstable";
+
+ outputs =
+ { self, nixpkgs }:
let
+ inherit (nixpkgs) lib;
+
supportedSystems = [
"x86_64-linux"
"aarch64-linux"
"x86_64-darwin"
"aarch64-darwin"
];
- forAllSystems = nixpkgs.lib.genAttrs supportedSystems;
- pkgsFor = system: import nixpkgs { inherit system; };
+ forAllSystems = lib.genAttrs supportedSystems;
- # Dependencies that are not packaged in nixpkgs (used by the Linux package build):
- buildSources = pkgs: {
- aurora-src = pkgs.fetchFromGitHub {
- owner = "encounter";
- repo = "aurora";
- rev = "63606a43265a3bc18dafd500ab4d7a2108f109e6";
- hash = "sha256-xBvnAwGwNzav67Ac6oUz7RqDUwqgL2bsME3OOMn8Tqw=";
- };
- dawn-src = pkgs.fetchzip {
- url = "https://github.com/encounter/dawn-build/releases/download/v20260423.175430/dawn-linux-x86_64.tar.gz";
+ dawnVersion = "v20260423.175430";
+ nodVersion = "v2.0.0-alpha.8";
+ versionSuffix = "nix-" + (self.shortRev or self.dirtyShortRev or "dirty");
+
+ dawnInfo = {
+ "x86_64-linux" = {
+ triple = "linux-x86_64";
hash = "sha256-HXfKTLHtMPwupnFnaflCARtXVPuS/0PoCePXidjE5xs=";
- stripRoot = false;
};
- nod-src = pkgs.fetchzip {
- url = "https://github.com/encounter/nod/releases/download/v2.0.0-alpha.8/libnod-linux-x86_64.tar.gz";
- hash = "sha256-mUqvLsbsqaZ+HAjMmHYPYO+MgtanGRTw7Gzn5uXR5rE=";
- stripRoot = false;
+ "aarch64-linux" = {
+ triple = "linux-aarch64";
+ hash = "sha256-34yyFpfqBZUwoFXQ41F0AwAU78FaNihOSY0oriwn6B0=";
};
- # The version of imgui on nixpkgs does not map cleanly.
- imgui-src = pkgs.fetchFromGitHub {
- owner = "ocornut";
- repo = "imgui";
- rev = "v1.91.9b-docking";
- hash = "sha256-mQOJ6jCN+7VopgZ61yzaCnt4R1QLrW7+47xxMhFRHLQ=";
+ "aarch64-darwin" = {
+ triple = "darwin-arm64";
+ hash = "sha256-eQnzrBp6gjiBek1VYQ9A5W13ClYWrDDKjIqv/7eNTR4=";
};
- sqlite-src = pkgs.fetchzip {
- url = "https://sqlite.org/2026/sqlite-amalgamation-3510300.zip";
- hash = "sha256-pNMR8zxaaqfAzQ0AQBOXMct4usdjey1Q0Gnitg06UhM=";
- };
- rmlui-src = pkgs.fetchzip {
- url = "https://github.com/mikke89/RmlUi/archive/f9b8c9e2935d5df2c7dff2c190d3968e99b0c3dc.tar.gz";
- hash = "sha256-g4O/JZUrrcseOz8o2QJRt+2CeuiLnVeuDJc906xvuIg=";
+ "x86_64-darwin" = {
+ triple = "darwin-x86_64";
+ hash = "sha256-QGWiGdxiI9kci3NPXH6QFFirxn16851zB/w3jqhIBJ4=";
};
};
- # Dusklight Actual (Linux x86_64 only — relies on prebuilt dawn/nod binaries)
- mkDusklight = pkgs:
- let srcs = buildSources pkgs;
- versionSuffix = if self ? shortRev && self.shortRev != null
- then "nix-${self.shortRev}"
- else "nix-dirty";
- in
- pkgs.stdenv.mkDerivation {
- name = "dusklight";
- src = ./.;
- postUnpack = ''
- mkdir -p $sourceRoot/extern/aurora
- cp -r ${srcs.aurora-src}/. $sourceRoot/extern/aurora/
- chmod -R u+w $sourceRoot/extern/aurora
- sed -i '/add_subdirectory(tests)/d' $sourceRoot/extern/aurora/CMakeLists.txt
- '';
- # Remove last line to re-enable tests
- cmakeFlags = [
- "-DDUSK_VERSION_OVERRIDE=${versionSuffix}"
- "-DFETCHCONTENT_FULLY_DISCONNECTED=ON"
- "-DFETCHCONTENT_SOURCE_DIR_CXXOPTS=${pkgs.cxxopts.src}"
- "-DFETCHCONTENT_SOURCE_DIR_JSON=${pkgs.nlohmann_json.src}"
- "-DFETCHCONTENT_SOURCE_DIR_DAWN_PREBUILT=${srcs.dawn-src}"
- "-DFETCHCONTENT_SOURCE_DIR_XXHASH=${pkgs.xxHash.src}"
- "-DFETCHCONTENT_SOURCE_DIR_FMT=${pkgs.fmt.src}"
- "-DFETCHCONTENT_SOURCE_DIR_TRACY=${pkgs.tracy.src}"
- "-DAURORA_SDL3_PROVIDER=system"
- "-DFETCHCONTENT_SOURCE_DIR_NOD_PREBUILT=${srcs.nod-src}"
- "-DAURORA_NOD_PROVIDER=package"
- "-DFETCHCONTENT_SOURCE_DIR_FREETYPE=${pkgs.freetype.src}"
- "-DFETCHCONTENT_SOURCE_DIR_ZSTD=${pkgs.zstd.src}"
- "-DFETCHCONTENT_SOURCE_DIR_SQLITE3=${srcs.sqlite-src}"
- "-DFETCHCONTENT_SOURCE_DIR_IMGUI=${srcs.imgui-src}"
- "-DFETCHCONTENT_SOURCE_DIR_RMLUI=${srcs.rmlui-src}"
- "-DCMAKE_CROSSCOMPILING=ON" # Tests are not working as I didn't want to work through getting google's test suite working as well. This is the only guard I could find to disable it.
- ];
- installPhase = ''
- mkdir -p $out/bin
- cp dusklight $out/bin/dusklight
- cp -r ./res $out/bin/res
+ nodPrebuiltInfo = {
+ "x86_64-linux" = {
+ triple = "linux-x86_64";
+ hash = "sha256-mUqvLsbsqaZ+HAjMmHYPYO+MgtanGRTw7Gzn5uXR5rE=";
+ };
+ "aarch64-darwin" = {
+ triple = "macos-arm64";
+ hash = "sha256-UPy1ywCcv0K6VJOU3uUelJuUdBh3UNaPRlyP5LOBeDw=";
+ };
+ };
- mkdir -p $out/share/applications
- cp $src/platforms/freedesktop/dusklight.desktop $out/share/applications/dusklight.desktop
+ perSystem =
+ system:
+ let
+ pkgs = import nixpkgs { inherit system; };
+ inherit (pkgs.stdenv.hostPlatform) isDarwin;
+ hasNodPrebuilt = nodPrebuiltInfo ? ${system};
- for size in 16 32 48 64 128 256 512 1024; do
- install -Dm644 $src/platforms/freedesktop/''${size}x''${size}/apps/dusklight.png \
- $out/share/icons/hicolor/''${size}x''${size}/apps/dusklight.png
- done
- '';
- nativeBuildInputs = [
+ aurora = pkgs.fetchFromGitHub {
+ owner = "encounter";
+ repo = "aurora";
+ rev = "10006618ee493f248b8597e4dfa1d2871d76a1d9";
+ hash = "sha256-lY2xuVyB7aPJ9+2wwLRB3F5U/BuPSxdSpegdG+qNd9o=";
+ };
+
+ dawn = pkgs.fetchzip {
+ url = "https://github.com/encounter/dawn-build/releases/download/${dawnVersion}/dawn-${dawnInfo.${system}.triple}.tar.gz";
+ hash = dawnInfo.${system}.hash;
+ stripRoot = false;
+ };
+
+ corrosion = pkgs.fetchFromGitHub {
+ owner = "corrosion-rs";
+ repo = "corrosion";
+ rev = "v0.6.1";
+ hash = "sha256-ppuDNObfKhneD9AlnPAvyCRHKW3BidXKglD1j/LE9CM=";
+ };
+
+ nodFromSource = pkgs.stdenv.mkDerivation (finalAttrs: {
+ pname = "nod";
+ version = nodVersion;
+ src = pkgs.fetchFromGitHub {
+ owner = "encounter";
+ repo = "nod";
+ rev = nodVersion;
+ hash = "sha256-+zrtVzjo0+X/6uMcNUn1+FaSR+jOhrcQSDNBFjw0NDs=";
+ };
+ cargoDeps = pkgs.rustPlatform.importCargoLock {
+ lockFile = "${finalAttrs.src}/Cargo.lock";
+ };
+ postPatch = ''
+ substituteInPlace CMakeLists.txt \
+ --replace-warn "add_subdirectory(nod-ffi/examples)" ""
+ '';
+ nativeBuildInputs = [
+ pkgs.cmake
+ pkgs.ninja
+ pkgs.rustPlatform.cargoSetupHook
+ pkgs.cargo
+ pkgs.rustc
+ ];
+ CARGO_NET_OFFLINE = "true";
+ cmakeFlags = [
+ "-DFETCHCONTENT_FULLY_DISCONNECTED=ON"
+ "-DFETCHCONTENT_SOURCE_DIR_CORROSION=${corrosion}"
+ "-DNOD_ENABLE_INSTALL=ON"
+ "-DBUILD_SHARED_LIBS=OFF"
+ ];
+ doCheck = false;
+ });
+
+ nod =
+ if hasNodPrebuilt then
+ pkgs.fetchzip {
+ url = "https://github.com/encounter/nod/releases/download/${nodVersion}/libnod-${
+ nodPrebuiltInfo.${system}.triple
+ }.tar.gz";
+ hash = nodPrebuiltInfo.${system}.hash;
+ stripRoot = false;
+ }
+ else
+ nodFromSource;
+
+ fetchContentDirs = {
+ DAWN_PREBUILT = dawn;
+ NOD_PREBUILT = nod;
+ CXXOPTS = pkgs.cxxopts.src;
+ JSON = pkgs.nlohmann_json.src;
+ XXHASH = pkgs.xxHash.src;
+ ZSTD = pkgs.zstd.src;
+ FMT = pkgs.fetchzip {
+ url = "https://github.com/fmtlib/fmt/archive/refs/tags/11.1.4.tar.gz";
+ hash = "sha256-sUbxlYi/Aupaox3JjWFqXIjcaQa0LFjclQAOleT+FRA=";
+ };
+ TRACY = pkgs.fetchzip {
+ url = "https://github.com/wolfpld/tracy/archive/a64b9a20294d59421a2f57aeca3c6383d8c48169.tar.gz";
+ hash = "sha256-hbNGOsGeyGSvCJ2No8RkwOib1lX2on3vNZSzyVkZdXw=";
+ };
+ IMGUI = pkgs.fetchFromGitHub {
+ owner = "ocornut";
+ repo = "imgui";
+ rev = "v1.91.9b-docking";
+ hash = "sha256-mQOJ6jCN+7VopgZ61yzaCnt4R1QLrW7+47xxMhFRHLQ=";
+ };
+ SQLITE3 = pkgs.fetchzip {
+ url = "https://sqlite.org/2026/sqlite-amalgamation-3510300.zip";
+ hash = "sha256-pNMR8zxaaqfAzQ0AQBOXMct4usdjey1Q0Gnitg06UhM=";
+ };
+ RMLUI = pkgs.fetchzip {
+ url = "https://github.com/mikke89/RmlUi/archive/f9b8c9e2935d5df2c7dff2c190d3968e99b0c3dc.tar.gz";
+ hash = "sha256-g4O/JZUrrcseOz8o2QJRt+2CeuiLnVeuDJc906xvuIg=";
+ };
+ };
+
+ dusklight = pkgs.stdenv.mkDerivation {
+ pname = "dusklight";
+ version = versionSuffix;
+ src = ./.;
+
+ postUnpack = ''
+ chmod -R u+w "$sourceRoot"
+ rm -rf "$sourceRoot/extern/aurora"
+ mkdir -p "$sourceRoot/extern"
+ cp -r ${aurora} "$sourceRoot/extern/aurora"
+ chmod -R u+w "$sourceRoot/extern/aurora"
+ substituteInPlace "$sourceRoot/extern/aurora/CMakeLists.txt" \
+ --replace-warn "add_subdirectory(tests)" ""
+ '';
+
+ nativeBuildInputs = [
+ pkgs.cmake
+ pkgs.ninja
+ pkgs.pkg-config
+ pkgs.python3
+ pkgs.python3Packages.markupsafe
+ ]
+ ++ lib.optionals (!isDarwin) [ pkgs.autoPatchelfHook ];
+
+ buildInputs = [
+ pkgs.sdl3
+ pkgs.freetype
+ pkgs.zstd
+ pkgs.cxxopts
+ pkgs.nlohmann_json
+ pkgs.xxHash
+ pkgs.abseil-cpp
+ pkgs.zlib
+ pkgs.libpng
+ pkgs.libjpeg_turbo
+ pkgs.curl
+ pkgs.openssl
+ ]
+ ++ lib.optionals isDarwin [
+ pkgs.apple-sdk_15
+ pkgs.libiconv
+ ]
+ ++ lib.optionals (!isDarwin) [
+ pkgs.libGL
+ pkgs.libGLU
+ pkgs.libglvnd
+ pkgs.vulkan-loader
+ pkgs.libX11
+ pkgs.libxcb
+ pkgs.libXcursor
+ pkgs.libxi
+ pkgs.libxrandr
+ pkgs.libxscrnsaver
+ pkgs.libxtst
+ pkgs.libxinerama
+ pkgs.libxkbcommon
+ pkgs.wayland
+ pkgs.libdecor
+ pkgs.alsa-lib
+ pkgs.libpulseaudio
+ pkgs.pipewire
+ pkgs.dbus
+ pkgs.udev
+ pkgs.libusb1
+ pkgs.libunwind
+ pkgs.gtk3
+ ];
+
+ cmakeBuildType = "RelWithDebInfo";
+ ninjaFlags = [ "dusklight" ];
+
+ cmakeFlags = [
+ "-DDUSK_VERSION_OVERRIDE=${versionSuffix}"
+ "-DFETCHCONTENT_FULLY_DISCONNECTED=ON"
+ "-DAURORA_DAWN_PROVIDER=package"
+ "-DAURORA_DAWN_LINKAGE=static"
+ "-DAURORA_NOD_PROVIDER=package"
+ "-DAURORA_NOD_LINKAGE=static"
+ "-DAURORA_SDL3_PROVIDER=system"
+ ]
+ ++ lib.mapAttrsToList (key: src: "-DFETCHCONTENT_SOURCE_DIR_${key}=${src}") fetchContentDirs;
+
+ installPhase =
+ if isDarwin then
+ ''
+ runHook preInstall
+ mkdir -p "$out/Applications"
+ cp -r Dusklight.app "$out/Applications/Dusklight.app"
+ runHook postInstall
+ ''
+ else
+ ''
+ runHook preInstall
+ install -Dm755 dusklight "$out/bin/dusklight"
+ cp -r "$src/res" "$out/bin/res"
+ install -Dm644 "$src/platforms/freedesktop/dev.twilitrealm.dusk.desktop" \
+ "$out/share/applications/dev.twilitrealm.dusk.desktop"
+ for size in 16 32 48 64 128 256 512 1024; do
+ install -Dm644 "$src/platforms/freedesktop/''${size}x''${size}/apps/dev.twilitrealm.dusk.png" \
+ "$out/share/icons/hicolor/''${size}x''${size}/apps/dev.twilitrealm.dusk.png"
+ done
+ runHook postInstall
+ '';
+
+ dontStrip = true;
+
+ meta = {
+ description = "Dusklight — native PC port of the Twilight Princess decompilation";
+ homepage = "https://github.com/zeldaret/tp";
+ platforms = supportedSystems;
+ mainProgram = "dusklight";
+ };
+ };
+
+ # Tooling common to every supported host (Linux and macOS).
+ commonDevTools = [
pkgs.cmake
+ pkgs.ninja
pkgs.pkg-config
- pkgs.wayland
+ pkgs.git
+ pkgs.python3
+ pkgs.python3Packages.markupsafe
+ pkgs.rustc
+ pkgs.cargo
+ pkgs.sccache
];
- buildInputs = [
- pkgs.libGL
- pkgs.libX11
- pkgs.libXcursor
- pkgs.libxi
- pkgs.libxcb
- pkgs.libxrandr
- pkgs.libxscrnsaver
- pkgs.libxtst
- pkgs.libjpeg8
- pkgs.libxkbcommon
- pkgs.libglvnd
+
+ # Linux-only system libraries — mirrors the apt deps from .github/workflows/build.yml
+ # so the cmake presets resolve the same set of headers as CI.
+ linuxDevDeps = [
+ # Compilers / linkers
+ pkgs.clang
+ pkgs.lld
+ # C/C++ utilities
+ pkgs.curl
+ pkgs.openssl
+ pkgs.zlib
+ pkgs.libpng
+ pkgs.libjpeg_turbo
+ pkgs.freetype
+ pkgs.zstd
+ pkgs.fmt
+ pkgs.tracy
pkgs.cxxopts
pkgs.abseil-cpp
pkgs.sdl3
- pkgs.fmt
- pkgs.tracy
- pkgs.freetype
- pkgs.zstd
+ pkgs.ncurses
+ pkgs.libunwind
+ pkgs.libusb1
+ pkgs.fuse
+ # Wayland / display server
+ pkgs.wayland
+ pkgs.wayland-protocols
+ pkgs.libxkbcommon
+ pkgs.libdecor
+ # OpenGL / Vulkan
+ pkgs.libGL
+ pkgs.libGLU
+ pkgs.libglvnd
+ pkgs.vulkan-headers
+ pkgs.vulkan-loader
+ # X11
+ pkgs.libX11
+ pkgs.libxcb
+ pkgs.libXcursor
+ pkgs.libxi
+ pkgs.libxrandr
+ pkgs.libxscrnsaver
+ pkgs.libxtst
+ pkgs.libxinerama
+ # Audio
+ pkgs.alsa-lib
+ pkgs.libpulseaudio
+ pkgs.pipewire
+ # System integration
+ pkgs.dbus
+ pkgs.udev
+ pkgs.gtk3
];
+
+ # On macOS we deliberately avoid pulling Nix's cc-wrapper so CMake picks up
+ # Apple Clang and the Xcode SDK directly, matching the macOS CI workflow.
+ darwinShell = pkgs.mkShellNoCC {
+ packages = commonDevTools;
+ shellHook = ''
+ echo "Dusklight dev shell (macOS)"
+ echo "Requires Xcode Command Line Tools for Apple Clang and the macOS SDK."
+ echo "Configure: cmake --preset macos-default-relwithdebinfo"
+ echo "Build: cmake --build --preset macos-default-relwithdebinfo"
+ '';
+ };
+
+ linuxShell = pkgs.mkShell {
+ packages = commonDevTools ++ linuxDevDeps;
+ shellHook = ''
+ echo "Dusklight dev shell (Linux)"
+ echo "Configure: cmake --preset linux-default-relwithdebinfo"
+ echo " cmake --preset linux-clang-relwithdebinfo"
+ echo "Build: cmake --build --preset "
+ '';
+ };
+ in
+ {
+ packages = {
+ default = dusklight;
+ dusklight = dusklight;
+ }
+ // lib.optionalAttrs (!hasNodPrebuilt) { nod = nodFromSource; };
+
+ devShells.default = if isDarwin then darwinShell else linuxShell;
};
- # Tooling common to every supported host (Linux and macOS).
- commonDevTools = pkgs: [
- pkgs.cmake
- pkgs.ninja
- pkgs.pkg-config
- pkgs.git
- pkgs.python3
- pkgs.python3Packages.markupsafe
- pkgs.rustc
- pkgs.cargo
- pkgs.sccache
- ];
-
- # Linux-only system libraries — mirrors the apt deps from .github/workflows/build.yml
- # so the cmake presets resolve the same set of headers as CI.
- linuxDevDeps = pkgs: [
- # Compilers / linkers
- pkgs.clang
- pkgs.lld
- # C/C++ utilities
- pkgs.curl
- pkgs.openssl
- pkgs.zlib
- pkgs.libpng
- pkgs.libjpeg_turbo
- pkgs.freetype
- pkgs.zstd
- pkgs.fmt
- pkgs.tracy
- pkgs.cxxopts
- pkgs.abseil-cpp
- pkgs.sdl3
- pkgs.ncurses
- pkgs.libunwind
- pkgs.libusb1
- pkgs.fuse
- # Wayland / display server
- pkgs.wayland
- pkgs.wayland-protocols
- pkgs.libxkbcommon
- pkgs.libdecor
- # OpenGL / Vulkan
- pkgs.libGL
- pkgs.libGLU
- pkgs.libglvnd
- pkgs.vulkan-headers
- pkgs.vulkan-loader
- # X11
- pkgs.libX11
- pkgs.libxcb
- pkgs.libXcursor
- pkgs.libxi
- pkgs.libxrandr
- pkgs.libxscrnsaver
- pkgs.libxtst
- pkgs.libxinerama
- # Audio
- pkgs.alsa-lib
- pkgs.libpulseaudio
- pkgs.pipewire
- # System integration
- pkgs.dbus
- pkgs.udev
- pkgs.gtk3
- ];
-
- # On macOS we deliberately avoid pulling Nix's cc-wrapper so CMake picks up
- # Apple Clang and the Xcode SDK directly, matching the macOS CI workflow.
- mkDarwinShell = pkgs:
- pkgs.mkShellNoCC {
- packages = commonDevTools pkgs;
- shellHook = ''
- echo "Dusklight dev shell (macOS)"
- echo "Requires Xcode Command Line Tools for Apple Clang and the macOS SDK."
- echo "Configure: cmake --preset macos-default-relwithdebinfo"
- echo "Build: cmake --build --preset macos-default-relwithdebinfo"
- '';
- };
-
- mkLinuxShell = pkgs:
- pkgs.mkShell {
- packages = (commonDevTools pkgs) ++ (linuxDevDeps pkgs);
- shellHook = ''
- echo "Dusklight dev shell (Linux)"
- echo "Configure: cmake --preset linux-default-relwithdebinfo"
- echo " cmake --preset linux-clang-relwithdebinfo"
- echo "Build: cmake --build --preset "
- '';
- };
-
- mkDevShell = pkgs:
- if pkgs.stdenv.isDarwin
- then mkDarwinShell pkgs
- else mkLinuxShell pkgs;
- in {
- packages.x86_64-linux.default = mkDusklight (pkgsFor "x86_64-linux");
-
- devShells = forAllSystems (system: {
- default = mkDevShell (pkgsFor system);
- });
+ systems = forAllSystems perSystem;
+ in
+ {
+ packages = lib.mapAttrs (_: s: s.packages) systems;
+ devShells = lib.mapAttrs (_: s: s.devShells) systems;
};
-}
\ No newline at end of file
+}
diff --git a/include/d/actor/d_a_alink.h b/include/d/actor/d_a_alink.h
index 107afc1ed3..8f6a40ae13 100644
--- a/include/d/actor/d_a_alink.h
+++ b/include/d/actor/d_a_alink.h
@@ -4564,6 +4564,7 @@ public:
cXyz mIBChainInterpCurrHandRoot;
bool mIBChainInterpPrevValid;
bool mIBChainInterpCurrValid;
+ bool mIsRollstab = false;
#endif
}; // Size: 0x385C
diff --git a/include/d/actor/d_a_movie_player.h b/include/d/actor/d_a_movie_player.h
index 0e666ae470..c382e0d1f7 100644
--- a/include/d/actor/d_a_movie_player.h
+++ b/include/d/actor/d_a_movie_player.h
@@ -5,6 +5,7 @@
#include
#else
#include
+#include
#endif
#include "f_op/f_op_actor.h"
#include "d/d_drawlist.h"
@@ -125,6 +126,7 @@ struct daMP_THPPlayer {
/* 0x0D4 */ s32 curCount;
#if TARGET_PC
/* 0x0D8 */ std::atomic videoDecodeCount;
+ std::chrono::steady_clock::time_point thpPlaybackClock;
#else
/* 0x0D8 */ s32 videoDecodeCount;
#endif
diff --git a/include/d/actor/d_a_player.h b/include/d/actor/d_a_player.h
index 41a11ff662..698e3b03cd 100644
--- a/include/d/actor/d_a_player.h
+++ b/include/d/actor/d_a_player.h
@@ -77,7 +77,7 @@ private:
#define PLAYER_CREATE_ANM_HEAP_F(heap, type, fmt, ...) \
{ \
char pcah_name_buf[32]; \
- sprintf(pcah_name_buf, fmt, ##__VA_ARGS__); \
+ snprintf(pcah_name_buf, sizeof(pcah_name_buf), fmt, ##__VA_ARGS__); \
(heap).createHeap(type, pcah_name_buf); \
\
}
diff --git a/include/d/d_camera.h b/include/d/d_camera.h
index c481262a46..b694933461 100644
--- a/include/d/d_camera.h
+++ b/include/d/d_camera.h
@@ -444,8 +444,7 @@ public:
/* 0x1C */ f32 mFovy;
/* 0x20 */ f32 mBank;
/* 0x24 */ fopAc_ac_c* mRelActor;
- /* 0x28 */ char mRelUseMask;
- /* 0x29 */ char field_0x29;
+ /* 0x28 */ char mRelUseMask[4];
/* 0x2C */ int mTimer;
/* 0x30 */ bool field_0x30;
/* 0x34 */ cXyz mBasePos;
@@ -526,7 +525,7 @@ public:
/* 0x3C */ fopAc_ac_c* field_0x3c;
/* 0x40 */ fopAc_ac_c* field_0x40;
/* 0x44 */ fpc_ProcID field_0x44;
- /* 0x48 */ char field_0x48;
+ /* 0x48 */ char field_0x48[4];
/* 0x4C */ int field_0x4c;
};
@@ -541,11 +540,7 @@ public:
/* 0x3C */ f32 field_0x3c;
/* 0x40 */ fopAc_ac_c* mRelActor;
/* 0x44 */ fpc_ProcID mRelActorID;
- /* 0x48 */ char mRelUseMask;
- /* 0x49 */ char field_0x49;
- /* 0x4A */ char field_0x4a;
- /* 0x4B */ char field_0x4b;
- /* 0x4C */ u8 field_0x4c[4];
+ /* 0x48 */ char mRelUseMask[8];
/* 0x50 */ int mTimer;
/* 0x54 */ int mTransType;
/* 0x58 */ f32 mCushion;
@@ -696,8 +691,7 @@ public:
/* 0x24 */ f32* field_0x24;
/* 0x28 */ f32 field_0x28;
/* 0x2C */ fopAc_ac_c* mRelActor;
- /* 0x30 */ char mRelUseMask;
- /* 0x31 */ char field_0x31;
+ /* 0x30 */ char mRelUseMask[4];
/* 0x34 */ int mTimer;
/* 0x38 */ int field_0x38;
/* 0x3C */ int mChoice;
@@ -780,8 +774,7 @@ public:
/* 0xAC */ f32 field_0xac;
/* 0xB0 */ fopAc_ac_c* mRelActor;
/* 0xB4 */ fpc_ProcID mRelActorID;
- /* 0xB8 */ char mRelUseMask;
- /* 0xB9 */ char field_0xb9;
+ /* 0xB8 */ char mRelUseMask[4];
/* 0xBC */ f32 mCushion;
/* 0xC0 */ u32 field_0xc0[6];
};
@@ -917,7 +910,12 @@ public:
char* getEvStringPntData(char*, char*);
char* getEvStringPntData(char*);
bool getEvXyzData(cXyz*, char*, cXyz);
+#if TARGET_PC
+ template
+ bool getEvStringData(char (&)[N], char*, char*);
+#else
bool getEvStringData(char*, char*, char*);
+#endif
fopAc_ac_c* getEvActor(char*);
fopAc_ac_c* getEvActor(char*, char*);
bool pauseEvCamera();
diff --git a/include/d/d_com_inf_game.h b/include/d/d_com_inf_game.h
index e67406f3a3..69f0a08a05 100644
--- a/include/d/d_com_inf_game.h
+++ b/include/d/d_com_inf_game.h
@@ -1851,7 +1851,7 @@ inline u16 dComIfGs_getDeathCount() {
}
#endif
-inline char* dComIfGs_getPlayerName() {
+inline TEXT_SPAN dComIfGs_getPlayerName() {
return g_dComIfG_gameInfo.info.getPlayer().getPlayerInfo().getPlayerName();
}
@@ -1859,7 +1859,7 @@ inline void dComIfGs_setPlayerName(const char* i_name) {
g_dComIfG_gameInfo.info.getPlayer().getPlayerInfo().setPlayerName(i_name);
}
-inline char* dComIfGs_getHorseName() {
+inline TEXT_SPAN dComIfGs_getHorseName() {
return g_dComIfG_gameInfo.info.getPlayer().getPlayerInfo().getHorseName();
}
diff --git a/include/d/d_file_sel_info.h b/include/d/d_file_sel_info.h
index 73641bc770..973349c469 100644
--- a/include/d/d_file_sel_info.h
+++ b/include/d/d_file_sel_info.h
@@ -46,10 +46,10 @@ private:
/* 0x22 */ u8 field_0x22;
/* 0x24 */ CPaneMgrAlpha* mDatBase;
/* 0x28 */ CPaneMgrAlpha* mNoDatBase;
- /* 0x2C */ char* mPlayerName;
- /* 0x30 */ char* mSaveDate;
- /* 0x34 */ char* mPlayTime;
- /* 0x38 */ char* mSaveStatus;
+ /* 0x2C */ TEXT_SPAN mPlayerName;
+ /* 0x30 */ TEXT_SPAN mSaveDate;
+ /* 0x34 */ TEXT_SPAN mPlayTime;
+ /* 0x38 */ TEXT_SPAN mSaveStatus;
};
typedef void (dFile_info_c::*warningFunc)(void);
diff --git a/include/d/d_file_select.h b/include/d/d_file_select.h
index cf081a3b10..d219a5a11e 100644
--- a/include/d/d_file_select.h
+++ b/include/d/d_file_select.h
@@ -11,7 +11,42 @@
class dFile_info_c;
class J2DPicture;
+#if TARGET_PC
+static bool cachedPanes = false;
+struct PaneCache {
+ u64 tag;
+ f32 origTransX;
+ f32 origTransY;
+ bool cached;
+};
+
+static PaneCache mSelDtPanes[] = {
+ {MULTI_CHAR('tate_n0'), 0.0f, false},
+ {MULTI_CHAR('tate_n1'), 0.0f, false},
+ {MULTI_CHAR('ken_n0'), 0.0f, false},
+ {MULTI_CHAR('ken_n1'), 0.0f, false},
+ {MULTI_CHAR('fuku_n0'), 0.0f, false},
+ {MULTI_CHAR('fuku_n1'), 0.0f, false},
+ {MULTI_CHAR('fuku_n2'), 0.0f, false},
+ {MULTI_CHAR('gray_n'), 0.0f, false},
+ {MULTI_CHAR('b_base'), 0.0f, false},
+ {MULTI_CHAR('b_base1'), 0.0f, false},
+};
+
+static PaneCache fileSelPanes[] = {
+ {MULTI_CHAR('w_uzu00'), 0.0f, false},
+ {MULTI_CHAR('w_uzu01'), 0.0f, false},
+ {MULTI_CHAR('w_uzu02'), 0.0f, false},
+ {MULTI_CHAR('w_uzu03'), 0.0f, false},
+ {MULTI_CHAR('w_uzu04'), 0.0f, false},
+ {MULTI_CHAR('w_uzu05'), 0.0f, false},
+ {MULTI_CHAR('w_uzu06'), 0.0f, false},
+ {MULTI_CHAR('w_uzu07'), 0.0f, false},
+ {MULTI_CHAR('w_uzu08'), 0.0f, false},
+ {MULTI_CHAR('w_uzu09'), 0.0f, false},
+};
+#endif
class dDlst_FileSel_c : public dDlst_base_c {
public:
void draw();
@@ -530,7 +565,7 @@ public:
/* 0x0130 */ int field_0x0130;
/* 0x0134 */ int field_0x0134;
/* 0x0138 */ CPaneMgrAlpha* mErrorMsgTxtPane[2];
- /* 0x0140 */ char* mErrorMsgStringPtr[2];
+ /* 0x0140 */ TEXT_SPAN mErrorMsgStringPtr[2];
/* 0x0148 */ u8 mErrorTxtDispIdx;
/* 0x0149 */ u8 field_0x0149;
/* 0x014A */ bool field_0x014a;
@@ -574,7 +609,7 @@ public:
/* 0x020A */ u8 mFadeTimer;
/* 0x020B */ u8 field_0x020b;
/* 0x020C */ CPaneMgrAlpha* mHeaderTxtPane[2];
- /* 0x0214 */ char* mHeaderStringPtr[2];
+ /* 0x0214 */ TEXT_SPAN mHeaderStringPtr[2];
/* 0x021C */ u8 mHeaderTxtDispIdx;
/* 0x021D */ u8 field_0x021d;
/* 0x021E */ u8 field_0x021e;
@@ -591,7 +626,7 @@ public:
/* 0x024B */ u8 field_0x024b;
/* 0x024C */ u8 field_0x024c;
/* 0x024B */ u8 field_0x024d[3];
- /* 0x0250 */ char* mModoruStringPtr;
+ /* 0x0250 */ TEXT_SPAN mModoruStringPtr;
/* 0x0254 */ STControl* stick;
/* 0x0258 */ u8 mIsDataNew[3];
/* 0x025B */ u8 mIsNoData[3];
diff --git a/include/d/d_menu_collect.h b/include/d/d_menu_collect.h
index 55d5373c71..d259027a65 100644
--- a/include/d/d_menu_collect.h
+++ b/include/d/d_menu_collect.h
@@ -15,6 +15,49 @@ class dMenu_Fishing_c;
class dMenu_Skill_c;
class dMenu_Insect_c;
class dSelect_cursor_c;
+#if TARGET_PC
+static bool cachedPanes = false;
+
+struct PaneCache {
+ u64 tag;
+ f32 origTransX;
+ f32 origTransY;
+ bool cached;
+};
+
+static PaneCache mpScreenPanes[] = {
+ {MULTI_CHAR('sa_tex_n'), 0.0f, false},
+ {MULTI_CHAR('op_tex_n'), 0.0f, false},
+ {MULTI_CHAR('heart_n'), 0.0f, false},
+ {MULTI_CHAR('wolf_n'), 0.0f, false},
+ {MULTI_CHAR('item_0_n'), 0.0f, false},
+ {MULTI_CHAR('item_1_n'), 0.0f, false},
+ {MULTI_CHAR('item_2_n'), 0.0f, false},
+ {MULTI_CHAR('fish_3_n'), 0.0f, false},
+ {MULTI_CHAR('lett_4_n'), 0.0f, false},
+ {MULTI_CHAR('maki_5_n'), 0.0f, false},
+ {MULTI_CHAR('fuku_n0'), 0.0f, false},
+ {MULTI_CHAR('fuku_n1'), 0.0f, false},
+ {MULTI_CHAR('fuku_n2'), 0.0f, false},
+ {MULTI_CHAR('tate_n0'), 0.0f, false},
+ {MULTI_CHAR('tate_n1'), 0.0f, false},
+ {MULTI_CHAR('ken_n0'), 0.0f, false},
+ {MULTI_CHAR('ken_n1'), 0.0f, false},
+ {MULTI_CHAR('kabu_6n'), 0.0f, false},
+ {MULTI_CHAR('t_t00'), 0.0f, false},
+ {MULTI_CHAR('f_t00'), 0.0f, false},
+ {MULTI_CHAR('itemn_n'), 0.0f, false},
+ {MULTI_CHAR('infotxtn'), 0.0f, false},
+ {MULTI_CHAR('sa_op_n'), 0.0f, false},
+ {MULTI_CHAR('title_n'), 0.0f, false},
+ {MULTI_CHAR('menu_n'), 0.0f, false},
+ {MULTI_CHAR('w_er_n'), 0.0f, false},
+ {MULTI_CHAR('center_n'), 0.0f, false},
+ {MULTI_CHAR('info_n'), 0.0f, false},
+ {MULTI_CHAR('lavel_n'), 0.0f, false},
+ {MULTI_CHAR('modelbgn'), 0.0f, false},
+};
+#endif
class dMenu_Collect2D_c;
class dMenu_Collect2DTop_c : public dDlst_base_c {
diff --git a/include/d/d_menu_dmap.h b/include/d/d_menu_dmap.h
index 81baea1446..7740927f4e 100644
--- a/include/d/d_menu_dmap.h
+++ b/include/d/d_menu_dmap.h
@@ -183,6 +183,11 @@ public:
/* 0xDD8 */ u8 field_0xdd8;
/* 0xDD9 */ u8 field_0xdd9;
/* 0xDDA */ u8 field_0xdda;
+
+#if TARGET_PC
+ J2DTextBox* mpPoeCountPane;
+ J2DPicture* mpPoeCountIcon;
+#endif
};
class dMenu_Dmap_c {
diff --git a/include/d/d_menu_fmap2D.h b/include/d/d_menu_fmap2D.h
index 7df78bb6d0..3c37c3da74 100644
--- a/include/d/d_menu_fmap2D.h
+++ b/include/d/d_menu_fmap2D.h
@@ -421,6 +421,12 @@ public:
/* 0xC2 */ u8 mAlphaButtonZ;
/* 0xC3 */ u8 mAlphaAnalogStick;
/* 0xC4 */ u8 mAlphaDpad;
+
+#if TARGET_PC
+ J2DTextBox* mpPoeCountPane;
+ J2DPicture* mpPoeCountIcon;
+ u8 mSelectRegionNo;
+#endif
};
#endif /* D_MENU_D_MENU_FMAP2D_H */
diff --git a/include/d/d_menu_map_common.h b/include/d/d_menu_map_common.h
index de50d775ca..55de3d0f6c 100644
--- a/include/d/d_menu_map_common.h
+++ b/include/d/d_menu_map_common.h
@@ -76,6 +76,11 @@ public:
}
#endif
+#if TARGET_PC
+ static void getDmapPoeCount(const std::string& stageName, int& nowCount, int& totalCount);
+ static void getFmapPoeCount(const int regionNo, int& nowCount, int& totalCount);
+#endif
+
struct Stage_c {
// Incomplete class
diff --git a/include/d/d_menu_save.h b/include/d/d_menu_save.h
index 4a70d1d045..116795f7be 100644
--- a/include/d/d_menu_save.h
+++ b/include/d/d_menu_save.h
@@ -313,7 +313,7 @@ private:
/* 0x00B8 */ int field_0xb8;
/* 0x00BC */ int field_0xbc;
/* 0x00C0 */ CPaneMgrAlpha* mpErrTxtPane[2];
- /* 0x00C8 */ char* mpErrTxt[2];
+ /* 0x00C8 */ TEXT_SPAN mpErrTxt[2];
/* 0x00D0 */ u8 mErrTxtType;
/* 0x00D1 */ u8 mErrTxtAnmComplete;
/* 0x00D2 */ u8 field_0xd2;
@@ -344,7 +344,7 @@ private:
/* 0x0160 */ J2DAnmTevRegKey* field_0x160;
/* 0x0164 */ int field_0x164;
/* 0x0168 */ CPaneMgrAlpha* mpHeaderTxtPane[2];
- /* 0x0170 */ char* mpHeaderTxt[2];
+ /* 0x0170 */ TEXT_SPAN mpHeaderTxt[2];
/* 0x0178 */ u8 mHeaderTxtType; // 0: Select Menu 1: YesNo Menu
/* 0x0179 */ u8 mHeaderAnmComplete;
/* 0x017A */ u8 field_0x17a;
diff --git a/include/d/d_meter2_info.h b/include/d/d_meter2_info.h
index a941d68cb9..875bb04710 100644
--- a/include/d/d_meter2_info.h
+++ b/include/d/d_meter2_info.h
@@ -68,9 +68,9 @@ public:
s16 decFloatingMessageTimer();
void resetFloatingMessage();
void decMsgKeyWaitTimer();
- void getString(u32 i_stringID, char* o_string, JMSMesgEntry_c* i_msgEntry);
- void getStringKana(u32 i_stringID, char* o_string, JMSMesgEntry_c* i_msgEntry);
- void getStringKanji(u32 i_stringID, char* o_string, JMSMesgEntry_c* i_msgEntry);
+ void getString(u32 i_stringID, TEXT_SPAN o_string, JMSMesgEntry_c* i_msgEntry);
+ void getStringKana(u32 i_stringID, TEXT_SPAN o_string, JMSMesgEntry_c* i_msgEntry);
+ void getStringKanji(u32 i_stringID, TEXT_SPAN o_string, JMSMesgEntry_c* i_msgEntry);
f32 getStringLength(J2DTextBox* i_textbox, char* i_string);
f32 getStringLength(JUTFont* i_font, f32 param_2, f32 param_3, char* i_string);
void onDirectUseItem(int);
@@ -349,15 +349,15 @@ inline CPaneMgr* dMeter2Info_getMeterItemPanePtr(s32 i_idx) {
return g_meter2_info.getMeterItemPanePtr(i_idx);
}
-inline void dMeter2Info_getString(u32 i_stringID, char* o_string, JMSMesgEntry_c* i_msgEntry) {
+inline void dMeter2Info_getString(u32 i_stringID, TEXT_SPAN o_string, JMSMesgEntry_c* i_msgEntry) {
g_meter2_info.getString(i_stringID, o_string, i_msgEntry);
}
-inline void dMeter2Info_getStringKanji(u32 i_stringID, char* o_string, JMSMesgEntry_c* i_msgEntry) {
+inline void dMeter2Info_getStringKanji(u32 i_stringID, TEXT_SPAN o_string, JMSMesgEntry_c* i_msgEntry) {
g_meter2_info.getStringKanji(i_stringID, o_string, i_msgEntry);
}
-inline void dMeter2Info_getStringKana(u32 i_stringID, char* o_string, JMSMesgEntry_c* i_msgEntry) {
+inline void dMeter2Info_getStringKana(u32 i_stringID, TEXT_SPAN o_string, JMSMesgEntry_c* i_msgEntry) {
g_meter2_info.getStringKana(i_stringID, o_string, i_msgEntry);
}
diff --git a/include/d/d_meter_button.h b/include/d/d_meter_button.h
index 0f05d32440..2d9a4bb5d8 100644
--- a/include/d/d_meter_button.h
+++ b/include/d/d_meter_button.h
@@ -1,6 +1,7 @@
#ifndef D_METER_D_METER_BUTTON_H
#define D_METER_D_METER_BUTTON_H
+#include "global.h"
#include "JSystem/J2DGraph/J2DScreen.h"
#include "JSystem/J2DGraph/J2DTextBox.h"
#include "d/d_drawlist.h"
@@ -194,7 +195,7 @@ public:
/* 0x0FC */ CPaneMgr* field_0x0fc[4];
/* 0x10C */ JKRHeap* mpHeap;
/* 0x110 */ void* mpFishingTex;
- /* 0x114 */ char mButtonText[2][15];
+ /* 0x114 */ char mButtonText[2][DUSK_IF_ELSE(32, 15)];
/* 0x132 */ u8 field_0x132[0x134 - 0x132];
/* 0x134 */ f32 field_0x134;
/* 0x138 */ f32 field_0x138;
diff --git a/include/d/d_msg_class.h b/include/d/d_msg_class.h
index 8ebf3ff5b7..307d48f291 100644
--- a/include/d/d_msg_class.h
+++ b/include/d/d_msg_class.h
@@ -5,6 +5,7 @@
#include "JSystem/JMessage/JMessage.h"
#include "SSystem/SComponent/c_xyz.h"
#include "dusk/endian.h"
+#include "dusk/string.hpp"
#if REGION_JPN
#define D_MSG_CLASS_PAGE_CNT_MAX 30
@@ -67,7 +68,7 @@ struct jmessage_tReference : public JMessage::TReference {
void pageSend();
void selectMessage();
void inputNumber();
- char* getWord(int);
+ TEXT_SPAN getWord(int);
void resetWord();
void setCharactor(u16);
void addCharactor(u16);
@@ -228,11 +229,11 @@ struct jmessage_tReference : public JMessage::TReference {
f32 getSelRubyCharSpace() { return mSelRubyCharSpace; }
f32 getRubySize() { return mRubySize; }
f32 getRubyCharSpace() { return mRubyCharSpace; }
- char* getSelTextPtr(int idx) { return mSelText[idx]; }
- char* getSelRubyPtr(int idx) { return mSelRuby[idx]; }
- char* getTextPtr() { return mText; }
- char* getTextSPtr() { return mTextS; }
- char* getRubyPtr() { return mRuby; }
+ TEXT_SPAN getSelTextPtr(int idx) { return mSelText[idx]; }
+ TEXT_SPAN getSelRubyPtr(int idx) { return mSelRuby[idx]; }
+ TEXT_SPAN getTextPtr() { return mText; }
+ TEXT_SPAN getTextSPtr() { return mTextS; }
+ TEXT_SPAN getRubyPtr() { return mRuby; }
u8 getSelectRubyFlag() { return mSelectRubyFlag; }
f32 getSelTBoxWidth() { return mSelTBoxWidth; }
u8 getSelectPos() { return mSelectPos; }
@@ -463,7 +464,7 @@ struct jmessage_tRenderingProcessor : public JMessage::TRenderingProcessor {
f32 getLineLength(int);
void do_strcat(char*, bool, bool, bool);
void do_rubyset(void const*, u32);
- void do_rubystrcat(char*, char*, f32, f32);
+ void do_rubystrcat(char*, TEXT_SPAN, f32, f32);
void do_name1();
void do_numset(s16);
void push_word();
diff --git a/include/d/d_msg_object.h b/include/d/d_msg_object.h
index d2ac4ecb2a..6cf9ea7681 100644
--- a/include/d/d_msg_object.h
+++ b/include/d/d_msg_object.h
@@ -53,8 +53,8 @@ public:
void demoMessageGroupLocal();
void endFlowGroupLocal();
void changeGroupLocal(s16);
- bool getStringLocal(u32, J2DTextBox*, J2DTextBox*, JUTFont*, COutFont_c*, char*,
- char*, char*, s16*);
+ bool getStringLocal(u32, J2DTextBox*, J2DTextBox*, JUTFont*, COutFont_c*, TEXT_SPAN,
+ TEXT_SPAN, TEXT_SPAN, s16*);
bool isGetItemMessage();
bool isKanbanMessage();
bool isHowlMessage();
@@ -121,7 +121,7 @@ public:
static void endFlowGroup();
static void changeGroup(s16);
static bool getString(u32, J2DTextBox*, J2DTextBox*, JUTFont*, COutFont_c*,
- char*, char*, char*, s16*);
+ TEXT_SPAN, TEXT_SPAN, TEXT_SPAN, s16*);
static void* getMsgDtPtr();
static void setProcessID(fpc_ProcID);
static msg_class* getActor();
@@ -246,12 +246,12 @@ public:
static void setWord(const char* i_word);
void setWordLocal(const char* i_word) {
- strcpy(mWord, i_word);
+ SAFE_STRCPY(mWord, i_word);
}
static void setSelectWord(int i_no, const char* i_word);
void setSelectWordLocal(int i_no, const char* i_word) {
- strcpy(mSelectWord[i_no], i_word);
+ SAFE_STRCPY(mSelectWord[i_no], i_word);
}
jmessage_tSequenceProcessor* getSequenceProcessor() { return mpSeqProc; }
@@ -426,8 +426,8 @@ inline void dMsgObject_setTalkActor(fopAc_ac_c* actor) {
}
inline bool dMsgObject_getString(u32 i_msgId, J2DTextBox* i_tbox, J2DTextBox* i_rubyTbox,
- JUTFont* i_font, COutFont_c* i_outFont, char* o_text,
- char* o_ruby, char* o_textS, s16* param_8) {
+ JUTFont* i_font, COutFont_c* i_outFont, TEXT_SPAN o_text,
+ TEXT_SPAN o_ruby, TEXT_SPAN o_textS, s16* param_8) {
return dMsgObject_getMsgObjectClass()->getString(i_msgId, i_tbox, i_rubyTbox, i_font, i_outFont, o_text, o_ruby,
o_textS, param_8);
}
diff --git a/include/d/d_msg_string_base.h b/include/d/d_msg_string_base.h
index 6f3a751b22..4624393f06 100644
--- a/include/d/d_msg_string_base.h
+++ b/include/d/d_msg_string_base.h
@@ -20,12 +20,12 @@ public:
f32 getStringPageLocal(u32, u8, u8, J2DTextBox*, J2DTextBox*, JUTFont*,
COutFont_c*, u8);
u8 getPageMax(int);
- f32 getMessageLocal(u32, char*);
+ f32 getMessageLocal(u32, TEXT_SPAN);
virtual f32 getString(u32, J2DTextBox*, J2DTextBox*, JUTFont*, COutFont_c*, u8);
virtual f32 getStringPage(u32, u8, u8, J2DTextBox*, J2DTextBox*, JUTFont*, COutFont_c*,
u8);
- virtual f32 getMessage(u32, char*);
+ virtual f32 getMessage(u32, TEXT_SPAN);
virtual void resetStringLocal(J2DTextBox*);
virtual void drawOutFontLocal(J2DTextBox*, f32);
virtual void drawFontLocal(J2DTextBox*, u8, f32, f32, f32, f32, u32, u8);
diff --git a/include/d/d_msg_unit.h b/include/d/d_msg_unit.h
index 400df98f25..47e40e31cf 100644
--- a/include/d/d_msg_unit.h
+++ b/include/d/d_msg_unit.h
@@ -6,14 +6,14 @@
class dMsgUnit_c {
public:
dMsgUnit_c();
- void setTag(int, int, char*, bool);
+ void setTag(int, int, TEXT_SPAN, bool);
virtual ~dMsgUnit_c();
};
extern dMsgUnit_c g_msg_unit;
-inline void dMsgUnit_setTag(int param_0, int param_1, char* param_2) {
+inline void dMsgUnit_setTag(int param_0, int param_1, TEXT_SPAN param_2) {
g_msg_unit.setTag(param_0, param_1, param_2, true);
}
diff --git a/include/d/d_name.h b/include/d/d_name.h
index 3ac6592457..ddd99127c6 100644
--- a/include/d/d_name.h
+++ b/include/d/d_name.h
@@ -127,7 +127,7 @@ public:
u8 isInputEnd() { return mIsInputEnd; }
char* getInputStrPtr() { return mInputStr; }
void hideIcon() { mSelIcon->setAlphaRate(0.0f); }
- void setNextNameStr(char* i_name) { strcpy(mNextNameStr,i_name); }
+ void setNextNameStr(char* i_name) { SAFE_STRCPY(mNextNameStr,i_name); }
void draw() { _draw(); }
private:
@@ -140,9 +140,9 @@ private:
/* 0x02C */ J2DAnmTextureSRTKey* mCursorTexKey;
/* 0x030 */ int mCurTexAnmF;
/* 0x034 */ CPaneMgrAlpha* mNameCursor[8];
- /* 0x054 */ char* mNameText[8];
+ /* 0x054 */ TEXT_SPAN mNameText[8];
/* 0x074 */ CPaneMgr* mMojiIcon[65];
- /* 0x178 */ char* mMojiText[65];
+ /* 0x178 */ TEXT_SPAN mMojiText[65];
/* 0x27C */ J2DPane* mMojiPane;
/* 0x280 */ J2DPane* mMenuPane;
/* 0x284 */ CPaneMgr* mMenuIcon[4];
diff --git a/include/d/d_save.h b/include/d/d_save.h
index e2719e0a98..69d4d3174d 100644
--- a/include/d/d_save.h
+++ b/include/d/d_save.h
@@ -488,21 +488,25 @@ public:
}
#if TARGET_PC
u16 getDeathCount() const { return mDeathCount; }
-#endif
+ TEXT_SPAN getPlayerName() const { return const_cast(mPlayerName); }
+#else
char* getPlayerName() const { return const_cast(mPlayerName); }
+#endif
void setPlayerName(const char* i_name) {
#if AVOID_UB
- strncpy(mPlayerName, i_name, sizeof(mPlayerName) - 1);
- mPlayerName[sizeof(mPlayerName) - 1] = '\0';
+ dusk::SafeStringCopyTruncate(mPlayerName, i_name);
#else
strcpy(mPlayerName, i_name);
#endif
}
+#if TARGET_PC
+ TEXT_SPAN getHorseName() const { return const_cast(mHorseName); }
+#else
char* getHorseName() const { return const_cast(mHorseName); }
+#endif
void setHorseName(const char* i_name) {
#if AVOID_UB
- strncpy(mHorseName, i_name, sizeof(mHorseName) - 1);
- mHorseName[sizeof(mHorseName) - 1] = '\0';
+ dusk::SafeStringCopyTruncate(mHorseName, i_name);
#else
strcpy(mHorseName, i_name);
#endif
diff --git a/include/d/d_select_cursor.h b/include/d/d_select_cursor.h
index 1ca226611b..e98db19731 100644
--- a/include/d/d_select_cursor.h
+++ b/include/d/d_select_cursor.h
@@ -51,7 +51,7 @@ public:
f32 getPositionX() const { return mPositionX; }
f32 getPositionY() const { return mPositionY; }
- void refreshAspectScale();
+ void refreshAspectScale(f32 param_0);
#endif
void onUpdateFlag() { mUpdateFlag = true; }
diff --git a/include/d/d_stage.h b/include/d/d_stage.h
index bd8e7d5728..04a6115fd0 100644
--- a/include/d/d_stage.h
+++ b/include/d/d_stage.h
@@ -1225,7 +1225,7 @@ public:
#endif
}
static JKRExpHeap* getMemoryBlockHeap(int i_no) { return mMemoryBlock[i_no]; }
- static char* getDemoArcName() { return mDemoArcName; }
+ static TEXT_SPAN getDemoArcName() { return mDemoArcName; }
static void offNoChangeRoom() { mNoChangeRoom = false; }
static void onNoChangeRoom() { mNoChangeRoom = true; }
diff --git a/include/dusk/achievements.h b/include/dusk/achievements.h
index 5c2758b6b7..c93ea5d626 100644
--- a/include/dusk/achievements.h
+++ b/include/dusk/achievements.h
@@ -5,7 +5,7 @@
#include
#include
#include
-#include
+#include
#include
#include "nlohmann/json.hpp"
@@ -47,6 +47,7 @@ public:
// Signals are visible to all achievement checks within the same tick, then cleared.
void signal(const char* key);
bool hasSignal(const char* key) const;
+ int signalCount(const char* key) const;
std::vector getAchievements() const;
@@ -62,7 +63,7 @@ private:
void processEntry(Entry& e);
std::vector m_entries;
- std::unordered_set m_signals;
+ std::unordered_map m_signals;
bool m_loaded = false;
bool m_dirty = false;
};
diff --git a/include/dusk/crash_handler.h b/include/dusk/crash_handler.h
new file mode 100644
index 0000000000..c2cfadf5d1
--- /dev/null
+++ b/include/dusk/crash_handler.h
@@ -0,0 +1,7 @@
+#pragma once
+
+namespace dusk::crash_handler {
+
+void install();
+
+} // namespace dusk::crash_handler
diff --git a/include/dusk/endian.h b/include/dusk/endian.h
index 0fec59411f..d16d0aa80c 100644
--- a/include/dusk/endian.h
+++ b/include/dusk/endian.h
@@ -227,6 +227,28 @@ struct BE {
}
};
+typedef f32 Mtx23[2][3];
+template <>
+struct BE {
+ BE contents[2][3];
+
+ auto& operator[](int x) {
+ return contents[x];
+ }
+
+ auto& operator[](int x) const {
+ return contents[x];
+ }
+
+ void to_host(Mtx23& mtx) const {
+ for (int i = 0; i < 2; i++) {
+ for (int j = 0; j < 3; j++) {
+ mtx[i][j] = contents[i][j];
+ }
+ }
+ }
+};
+
template
void be_swap(T& val) {
val = BE::swap(val);
diff --git a/include/dusk/frame_interpolation.h b/include/dusk/frame_interpolation.h
index 0fa8c208bd..5f2f3d134b 100644
--- a/include/dusk/frame_interpolation.h
+++ b/include/dusk/frame_interpolation.h
@@ -4,6 +4,7 @@
#include
#include
#include
+#include "settings.h"
class camera_process_class;
class view_class;
@@ -18,7 +19,7 @@ void begin_record();
void end_record();
void begin_sim_tick();
uint64_t sim_tick_seq();
-void begin_frame(bool enabled, bool is_sim_frame, float step);
+void begin_frame(FrameInterpMode mode, bool is_sim_frame, float step);
void interpolate();
float get_interpolation_step();
diff --git a/include/dusk/io.hpp b/include/dusk/io.hpp
index 2efc4a8d3b..aba6bf8a48 100644
--- a/include/dusk/io.hpp
+++ b/include/dusk/io.hpp
@@ -30,6 +30,11 @@ public:
~FileStream();
+ /**
+ * \brief Flush buffered writes and throw if the flush fails.
+ */
+ void Flush();
+
/**
* \brief Open a file for reading at the given path.
*/
diff --git a/include/dusk/logging.h b/include/dusk/logging.h
index 9b31b96bf2..54350af4bf 100644
--- a/include/dusk/logging.h
+++ b/include/dusk/logging.h
@@ -12,6 +12,7 @@ namespace dusk {
void InitializeFileLogging(const std::filesystem::path& configDir, AuroraLogLevel logLevel);
void ShutdownFileLogging();
const char* GetLogFilePath();
+ int GetLogFileDescriptor();
void SendToStubLog(AuroraLogLevel level, const char* module, const char* message);
}
@@ -19,7 +20,11 @@ extern bool StubLogEnabled;
extern aurora::Module DuskLog;
+#ifndef NDEBUG
#define STUB_LOG() DuskLog.debug("{} is a stub", __FUNCTION__)
+#else
+#define STUB_LOG()
+#endif
#if TARGET_PC
#define STUB_RET(...) \
diff --git a/include/dusk/settings.h b/include/dusk/settings.h
index 43e565ed5e..923a1e9fc6 100644
--- a/include/dusk/settings.h
+++ b/include/dusk/settings.h
@@ -15,6 +15,17 @@ enum class BloomMode : int {
Dusk = 2,
};
+enum class DepthOfFieldMode : int {
+ Off = 0,
+ Classic = 1,
+ Dusk = 2,
+};
+
+enum class Resampler : int {
+ Bilinear = 0,
+ Area = 1,
+};
+
enum class GameLanguage : u8 {
English = OS_LANGUAGE_ENGLISH,
German = OS_LANGUAGE_GERMAN,
@@ -34,6 +45,18 @@ enum class GyroMode : u8 {
Mouse = 1,
};
+enum class FrameInterpMode : u8 {
+ Off = 0,
+ Capped = 1,
+ Unlimited = 2,
+};
+
+enum class MenuScaling : u8 {
+ GameCube = 0,
+ Wii = 1,
+ Dusklight = 2,
+};
+
namespace config {
template <>
struct ConfigEnumRange {
@@ -41,6 +64,18 @@ struct ConfigEnumRange {
static constexpr auto max = BloomMode::Dusk;
};
+template <>
+struct ConfigEnumRange {
+ static constexpr auto min = DepthOfFieldMode::Off;
+ static constexpr auto max = DepthOfFieldMode::Dusk;
+};
+
+template <>
+struct ConfigEnumRange {
+ static constexpr auto min = Resampler::Bilinear;
+ static constexpr auto max = Resampler::Area;
+};
+
template <>
struct ConfigEnumRange {
static constexpr auto min = GameLanguage::English;
@@ -58,7 +93,19 @@ struct ConfigEnumRange {
static constexpr auto min = GyroMode::Sensor;
static constexpr auto max = GyroMode::Mouse;
};
-}
+
+template <>
+struct ConfigEnumRange {
+ static constexpr auto min = FrameInterpMode::Off;
+ static constexpr auto max = FrameInterpMode::Unlimited;
+};
+
+template <>
+struct ConfigEnumRange {
+ static constexpr auto min = MenuScaling::GameCube;
+ static constexpr auto max = MenuScaling::Dusklight;
+};
+} // namespace config
// Persistent user settings
@@ -72,6 +119,7 @@ struct UserSettings {
ConfigVar lockAspectRatio;
ConfigVar enableFpsOverlay;
ConfigVar fpsOverlayCorner;
+ ConfigVar maxFrameRate;
} video;
struct {
@@ -109,6 +157,7 @@ struct UserSettings {
ConfigVar instantText;
ConfigVar sunsSong;
ConfigVar autoSave;
+ ConfigVar enhancedMapMenus;
// Preferences
ConfigVar enableMirrorMode;
@@ -118,15 +167,18 @@ struct UserSettings {
ConfigVar enableAchievementToasts;
ConfigVar enableControllerToasts;
ConfigVar enableDiscordPresence;
+ ConfigVar menuScalingMode;
// Graphics
ConfigVar bloomMode;
ConfigVar bloomMultiplier;
+ ConfigVar depthOfFieldMode;
ConfigVar disableWaterRefraction;
- ConfigVar enableFrameInterpolation;
+ ConfigVar enableTextureReplacements;
+ ConfigVar enableFrameInterpolation;
ConfigVar internalResolutionScale;
ConfigVar shadowResolutionMultiplier;
- ConfigVar enableDepthOfField;
+ ConfigVar resampler;
ConfigVar enableMapBackground;
ConfigVar disableCutscenePillarboxing;
@@ -150,6 +202,8 @@ struct UserSettings {
ConfigVar invertCameraYAxis;
ConfigVar invertFirstPersonXAxis;
ConfigVar invertFirstPersonYAxis;
+ ConfigVar invertAirSwimX;
+ ConfigVar invertAirSwimY;
ConfigVar freeCameraSensitivity;
ConfigVar debugFlyCam;
ConfigVar debugFlyCamLockEvents;
@@ -186,6 +240,7 @@ struct UserSettings {
ConfigVar liveSplitEnabled;
ConfigVar showSpeedrunRTATimer;
ConfigVar recordingMode;
+ ConfigVar removeQuestMapMarkers;
ConfigVar showInputViewer;
ConfigVar showInputViewerGyro;
} game;
diff --git a/include/dusk/string.hpp b/include/dusk/string.hpp
index 7de1b1ad75..af91ff8fe9 100644
--- a/include/dusk/string.hpp
+++ b/include/dusk/string.hpp
@@ -1,22 +1,55 @@
#ifndef DUSK_STRING_HPP
#define DUSK_STRING_HPP
-
-#include "global.h"
-#include
-#include
+#include
namespace dusk {
-inline void strncpyProxy(char* dst, const char* src, size_t count) {
-#if _MSC_VER
-#pragma warning(push)
-#pragma warning(disable : 4996)
+struct TextSpan {
+ char* buffer;
+ size_t size;
+
+ constexpr operator char*() const {
+ return buffer;
+ }
+
+ constexpr TextSpan(char* buffer, size_t size) : buffer(buffer), size(size) { }
+
+ template
+ constexpr TextSpan(char (&buffer)[BufSize]) : buffer(buffer), size(BufSize) {
+ }
+
+ constexpr TextSpan() : buffer(nullptr), size(0) { }
+
+ constexpr TextSpan operator++(int) {
+ const auto prev = *this;
+
+ if (size > 0) [[likely]] {
+ size--;
+ }
+ buffer++;
+
+ return prev;
+ }
+
+ constexpr char& operator*() const {
+ if (size == 0) [[unlikely]] {
+ CrashSpawnEmpty();
+ }
+
+ return *buffer;
+ }
+
+private:
+ static void CrashSpawnEmpty();
+};
+
+#if TARGET_PC
+#define TEXT_SPAN dusk::TextSpan
+#else
+#define TEXT_SPAN char*
#endif
- strncpy(dst, src, count);
-#if _MSC_VER
-#pragma warning(pop)
-#endif
-}
+
+void SafeStringCopyTruncate(char* buffer, size_t bufSize, const char* src);
/**
* Copy a string to a fixed-size array.
@@ -25,13 +58,28 @@ inline void strncpyProxy(char* dst, const char* src, size_t count) {
template
void SafeStringCopyTruncate(char (&buffer)[BufSize], const char* src) {
static_assert(BufSize > 0, "Target buffer cannot be size zero");
+ SafeStringCopyTruncate(buffer, BufSize, src);
+}
- if (buffer == src) {
- CRASH("Cannot copy string to same buffer");
- }
+void SafeStringCopy(char* buffer, size_t bufSize, const char* src);
+void SafeStringCat(char* buffer, size_t bufSize, const char* src);
+int SafeStringVPrintf(char* buffer, size_t bufSize, const char* src, std::va_list args);
- strncpyProxy(buffer, src, BufSize);
- buffer[BufSize - 1] = 0;
+inline void SafeStringCopy(TextSpan dst, const char* src) {
+ SafeStringCopy(dst.buffer, dst.size, src);
+}
+
+inline void SafeStringCat(TextSpan dst, const char* src) {
+ SafeStringCat(dst.buffer, dst.size, src);
+}
+
+inline int SafeStringPrintf(TextSpan dst, const char* format, ...) {
+ std::va_list args;
+ va_start(args, format);
+ const auto ret = SafeStringVPrintf(dst.buffer, dst.size, format, args);
+ va_end(args);
+
+ return ret;
}
/**
@@ -41,18 +89,40 @@ void SafeStringCopyTruncate(char (&buffer)[BufSize], const char* src) {
template
void SafeStringCopy(char (&buffer)[BufSize], const char* src) {
static_assert(BufSize > 0, "Target buffer cannot be size zero");
- if (buffer == src) {
- CRASH("Cannot copy string to same buffer");
- }
-
- if (strlen(src) > BufSize - 1) {
- CRASH("Destination buffer too small!");
- }
-
- strncpyProxy(buffer, src, BufSize);
- buffer[BufSize - 1] = 0;
+ SafeStringCopy(buffer, BufSize, src);
}
+template
+void SafeStringCat(char (&buffer)[BufSize], const char* src) {
+ static_assert(BufSize > 0, "Target buffer cannot be size zero");
+ SafeStringCat(buffer, BufSize, src);
+}
+
+template
+int SafeStringPrintf(char (&buffer)[BufSize], const char* format, ...) {
+ static_assert(BufSize > 0, "Target buffer cannot be size zero");
+
+ std::va_list args;
+ va_start(args, format);
+ const auto ret = SafeStringVPrintf(buffer, BufSize, format, args);
+ va_end(args);
+
+ return ret;
+}
+
+#if TARGET_PC
+#define SAFE_STRCPY dusk::SafeStringCopy
+#define SAFE_STRCAT dusk::SafeStringCat
+#define SAFE_SPRINTF dusk::SafeStringPrintf
+#define SAFE_STRCPY_BOUNDED dusk::SafeStringCopy
+#define SAFE_STRCAT_BOUNDED dusk::SafeStringCat
+#else
+#define SAFE_STRCPY strcpy
+#define SAFE_STRCAT strcat
+#define SAFE_SPRINTF sprintf
+#define SAFE_STRCPY_BOUNDED strcpy
+#define SAFE_STRCPY_BOUNDED strcat
+#endif
}
#endif // DUSK_STRING_HPP
diff --git a/include/dusk/time.h b/include/dusk/time.h
index c43437f639..ead946188b 100644
--- a/include/dusk/time.h
+++ b/include/dusk/time.h
@@ -17,16 +17,24 @@
#include
#include
#endif
+#ifdef __APPLE__
+#include
+#if defined(__x86_64__) || defined(__i386__)
+#include
+#endif
+#endif
class Limiter {
public:
using duration_t = Uint64;
- void Reset() { m_oldTime = SDL_GetTicksNS(); }
+ void Reset() {
+ m_oldTime = SDL_GetTicksNS();
+ }
- void Sleep(duration_t targetFrameTime) {
+ duration_t Sleep(duration_t targetFrameTime) {
if (targetFrameTime == 0) {
- return;
+ return 0;
}
const Uint64 start = SDL_GetTicksNS();
@@ -41,6 +49,8 @@ public:
}
}
Reset();
+
+ return adjustedSleepTime;
}
duration_t SleepTime(duration_t targetFrameTime) {
@@ -74,7 +84,6 @@ private:
if (!initialized || numSleeps++ % 1000 == 0) {
LARGE_INTEGER freq;
if (QueryPerformanceFrequency(&freq) == 0) {
- DuskLog.warn("QueryPerformanceFrequency failed: {}", GetLastError());
return;
}
countPerNs = static_cast(freq.QuadPart) / 1e9;
@@ -98,6 +107,33 @@ private:
#endif
} while (current.QuadPart - start.QuadPart < ticksToWait);
}
+#elif defined (__APPLE__)
+ void NanoSleep(const duration_t duration) {
+ // Hybrid approach using Apple Mach
+ uint64_t start_mach = mach_absolute_time();
+
+ mach_timebase_info_data_t timebase_info;
+ mach_timebase_info(&timebase_info);
+
+ uint64_t total_mach_ticks = (duration * timebase_info.denom) / timebase_info.numer;
+ uint64_t target_mach = start_mach + total_mach_ticks;
+
+ uint64_t buffer_ns = 2'000'000ULL;
+ uint64_t buffer_mach_ticks = (buffer_ns * timebase_info.denom) / timebase_info.numer;
+
+ if (total_mach_ticks > buffer_mach_ticks) {
+ uint64_t sleep_until_mach = target_mach - buffer_mach_ticks;
+ mach_wait_until(sleep_until_mach);
+ }
+
+ while (mach_absolute_time() < target_mach) {
+#if defined(__aarch64__) || defined(__arm__)
+ asm volatile("yield" ::: "memory"); // Hardware hint, not a scheduler hint.
+#else
+ _mm_pause();
+#endif
+ }
+ }
#else
void NanoSleep(const duration_t duration) { SDL_DelayPrecise(duration); }
#endif
diff --git a/include/f_op/f_op_msg_mng.h b/include/f_op/f_op_msg_mng.h
index 9bb8bc0ff3..330347fc18 100644
--- a/include/f_op/f_op_msg_mng.h
+++ b/include/f_op/f_op_msg_mng.h
@@ -50,7 +50,7 @@ fpc_ProcID fopMsgM_messageSet(u32 i_msgIdx, fopAc_ac_c* i_talkActor, u32 param_2
fpc_ProcID fopMsgM_messageSet(u32 i_msgIdx, u32 param_1);
fpc_ProcID fopMsgM_messageSetDemo(u32 i_msgidx);
msg_class* fopMsgM_SearchByID(fpc_ProcID i_id);
-char* fopMsgM_messageGet(char* i_stringBuf, u32 i_msgId);
+TEXT_SPAN fopMsgM_messageGet(TEXT_SPAN i_stringBuf, u32 i_msgId);
fpc_ProcID fop_Timer_create(s16 i_procName, u8 i_mode, u32 i_limitMs, u8 i_type, u8 param_4,
f32 param_5, f32 param_6, f32 param_7, f32 param_8,
fopMsgCreateFunc i_createFunc);
diff --git a/libs/JSystem/include/JSystem/J2DGraph/J2DTevs.h b/libs/JSystem/include/JSystem/J2DGraph/J2DTevs.h
index 2d5f3ca2d6..ea81bc869f 100644
--- a/libs/JSystem/include/JSystem/J2DGraph/J2DTevs.h
+++ b/libs/JSystem/include/JSystem/J2DGraph/J2DTevs.h
@@ -116,7 +116,7 @@ private:
*
*/
struct J2DIndTexMtxInfo {
- /* 0x00 */ Mtx23 mMtx;
+ /* 0x00 */ BE(Mtx23) mMtx;
/* 0x18 */ s8 mScaleExp;
J2DIndTexMtxInfo& operator=(const J2DIndTexMtxInfo& other) {
diff --git a/libs/JSystem/include/JSystem/J2DGraph/J2DTextBox.h b/libs/JSystem/include/JSystem/J2DGraph/J2DTextBox.h
index f4d5345507..0d875ad652 100644
--- a/libs/JSystem/include/JSystem/J2DGraph/J2DTextBox.h
+++ b/libs/JSystem/include/JSystem/J2DGraph/J2DTextBox.h
@@ -4,6 +4,7 @@
#include "JSystem/J2DGraph/J2DMaterial.h"
#include "JSystem/J2DGraph/J2DPane.h"
#include "dusk/endian.h"
+#include "dusk/string.hpp"
class J2DMaterial;
class JUTFont;
@@ -98,7 +99,8 @@ public:
void initiate(ResFONT const*, char const*, s16, J2DTextBoxHBinding,
J2DTextBoxVBinding);
void private_readStream(J2DPane*, JSURandomInputStream*, JKRArchive*);
- char* getStringPtr() const;
+ TEXT_SPAN getStringPtr() const;
+ dusk::TextSpan getSpan() const;
s32 setString(s16, char const*, ...);
s32 setString(char const*, ...);
diff --git a/libs/JSystem/include/JSystem/J3DGraphBase/J3DMatBlock.h b/libs/JSystem/include/JSystem/J3DGraphBase/J3DMatBlock.h
index a959609f45..859bd6943e 100644
--- a/libs/JSystem/include/JSystem/J3DGraphBase/J3DMatBlock.h
+++ b/libs/JSystem/include/JSystem/J3DGraphBase/J3DMatBlock.h
@@ -1575,6 +1575,12 @@ struct J3DAlphaComp {
u8 getRef1() const { return mRef1; }
void load() const {
+#ifdef AVOID_UB
+ if (mID > 255) {
+ J3DGDSetAlphaCompare(GX_ALWAYS, 0, GX_AOP_OR, GX_ALWAYS, 0);
+ return;
+ }
+#endif
J3DGDSetAlphaCompare((GXCompare)getComp0(), mRef0, (GXAlphaOp)getOp(), (GXCompare)getComp1(), mRef1);
}
diff --git a/libs/JSystem/include/JSystem/JAudio2/JASHeapCtrl.h b/libs/JSystem/include/JSystem/JAudio2/JASHeapCtrl.h
index 7a3ae12470..996fef6fef 100644
--- a/libs/JSystem/include/JSystem/JAudio2/JASHeapCtrl.h
+++ b/libs/JSystem/include/JSystem/JAudio2/JASHeapCtrl.h
@@ -287,28 +287,28 @@ template
class JASPoolAllocObject {
public:
#if TARGET_PC
- static void* operator new(size_t n, JKRHeapToken) {
+ static void* operator new(size_t n, JKRHeapToken) IF_DUSK(noexcept) {
return operator new(n);
}
#endif
- static void* operator new(size_t n) {
+ static void* operator new(size_t n) IF_DUSK(noexcept) {
#if PLATFORM_GCN
JASMemPool& memPool_ = getMemPool_();
#endif
return memPool_.alloc(n);
}
- static void* operator new(size_t n, void* ptr) {
+ static void* operator new(size_t n, void* ptr) IF_DUSK(noexcept) {
return ptr;
}
#if TARGET_PC
- static void operator delete(void* ptr, size_t n, JKRHeapToken) {
+ static void operator delete(void* ptr, size_t n, JKRHeapToken) IF_DUSK(noexcept) {
operator delete(ptr, n);
}
#endif
- static void operator delete(void* ptr, size_t n) {
+ static void operator delete(void* ptr, size_t n) IF_DUSK(noexcept) {
#if PLATFORM_GCN
JASMemPool& memPool_ = getMemPool_();
#endif
@@ -402,28 +402,28 @@ template
class JASPoolAllocObject_MultiThreaded {
public:
#if TARGET_PC
- static void* operator new(size_t n, JKRHeapToken) {
+ static void* operator new(size_t n, JKRHeapToken) IF_DUSK(noexcept) {
return operator new(n);
}
#endif
- static void* operator new(size_t n) {
+ static void* operator new(size_t n) IF_DUSK(noexcept) {
#if PLATFORM_GCN
JASMemPool_MultiThreaded& memPool_ = getMemPool();
#endif
return memPool_.alloc(n);
}
- static void* operator new(size_t n, void* ptr) {
+ static void* operator new(size_t n, void* ptr) IF_DUSK(noexcept) {
return ptr;
}
#if TARGET_PC
- static void operator delete(void* ptr, size_t n, JKRHeapToken) {
+ static void operator delete(void* ptr, size_t n, JKRHeapToken) IF_DUSK(noexcept) {
return operator delete(ptr, n);
}
#endif
- static void operator delete(void* ptr, size_t n) {
+ static void operator delete(void* ptr, size_t n) IF_DUSK(noexcept) {
#if PLATFORM_GCN
JASMemPool_MultiThreaded& memPool_ = getMemPool();
#endif
diff --git a/libs/JSystem/include/JSystem/JKernel/JKRHeap.h b/libs/JSystem/include/JSystem/JKernel/JKRHeap.h
index d3710bd5df..d1b27a0fd0 100644
--- a/libs/JSystem/include/JSystem/JKernel/JKRHeap.h
+++ b/libs/JSystem/include/JSystem/JKernel/JKRHeap.h
@@ -237,11 +237,11 @@ enum class JKRHeapToken {
Dummy
};
-inline void* operator new(size_t, JKRHeapToken, void* where) {
+inline void* operator new(size_t, JKRHeapToken, void* where) noexcept {
return where;
}
-inline void* operator new[](size_t, JKRHeapToken, void* where) {
+inline void* operator new[](size_t, JKRHeapToken, void* where) noexcept {
return where;
}
@@ -264,21 +264,21 @@ inline void* operator new[](size_t, JKRHeapToken, void* where) {
#define JKR_HEAP_TOKEN_PARAM
#endif
-void* operator new(size_t size JKR_HEAP_TOKEN_PARAM);
-void* operator new(size_t size JKR_HEAP_TOKEN_PARAM, int alignment);
-void* operator new(size_t size JKR_HEAP_TOKEN_PARAM, JKRHeap* heap, int alignment);
+void* operator new(size_t size JKR_HEAP_TOKEN_PARAM) IF_DUSK(noexcept);
+void* operator new(size_t size JKR_HEAP_TOKEN_PARAM, int alignment) IF_DUSK(noexcept);
+void* operator new(size_t size JKR_HEAP_TOKEN_PARAM, JKRHeap* heap, int alignment) IF_DUSK(noexcept);
// On PC, these new[] overloads are only used to catch usages of JKR_NEW with [].
-void* operator new[](size_t size JKR_HEAP_TOKEN_PARAM);
-void* operator new[](size_t size JKR_HEAP_TOKEN_PARAM, int alignment);
-void* operator new[](size_t size JKR_HEAP_TOKEN_PARAM, JKRHeap* heap, int alignment);
+void* operator new[](size_t size JKR_HEAP_TOKEN_PARAM) IF_DUSK(noexcept);
+void* operator new[](size_t size JKR_HEAP_TOKEN_PARAM, int alignment) IF_DUSK(noexcept);
+void* operator new[](size_t size JKR_HEAP_TOKEN_PARAM, JKRHeap* heap, int alignment) IF_DUSK(noexcept);
-void operator delete(void* ptr JKR_HEAP_TOKEN_PARAM);
-void operator delete[](void* ptr JKR_HEAP_TOKEN_PARAM);
+void operator delete(void* ptr JKR_HEAP_TOKEN_PARAM) IF_DUSK(noexcept);
+void operator delete[](void* ptr JKR_HEAP_TOKEN_PARAM) IF_DUSK(noexcept);
#if TARGET_PC
template
-void jkrDelete(T* ptr) {
+void jkrDelete(T* ptr) IF_DUSK(noexcept) {
if (ptr == nullptr) {
return;
}
@@ -298,7 +298,7 @@ void jkrDelete(T* ptr) {
}
template<>
-inline void jkrDelete(void* ptr) {
+inline void jkrDelete(void* ptr) IF_DUSK(noexcept) {
if (ptr == nullptr) {
return;
}
@@ -322,7 +322,7 @@ constexpr bool newArgsHasCustomAlignment() {
}
template
-T* jkrNewArray(size_t count, std::in_place_type_t, Args&&... args) {
+T* jkrNewArray(size_t count, std::in_place_type_t, Args&&... args) IF_DUSK(noexcept) {
size_t allocSize = count * sizeof(T);
if constexpr (!std::is_trivially_destructible()) {
static_assert(
@@ -333,6 +333,10 @@ T* jkrNewArray(size_t count, std::in_place_type_t, Args&&... args) {
}
void* ptr = operator new(allocSize, JKRHeapToken::Dummy, args...);
+ if (!ptr) {
+ return nullptr;
+ }
+
T* dataPtr;
if constexpr (!std::is_trivially_destructible()) {
auto length = static_cast(ptr);
@@ -352,7 +356,7 @@ T* jkrNewArray(size_t count, std::in_place_type_t, Args&&... args) {
}
template
-void jkrDeleteArray(T* pointer) {
+void jkrDeleteArray(T* pointer) IF_DUSK(noexcept) {
if (pointer == nullptr) {
return;
}
@@ -372,7 +376,7 @@ void jkrDeleteArray(T* pointer) {
}
template<>
-inline void jkrDeleteArray(void* pointer) {
+inline void jkrDeleteArray(void* pointer) IF_DUSK(noexcept) {
if (pointer == nullptr) {
return;
}
diff --git a/libs/JSystem/src/J2DGraph/J2DMaterialFactory.cpp b/libs/JSystem/src/J2DGraph/J2DMaterialFactory.cpp
index beb9e0075a..2cede2c49a 100644
--- a/libs/JSystem/src/J2DGraph/J2DMaterialFactory.cpp
+++ b/libs/JSystem/src/J2DGraph/J2DMaterialFactory.cpp
@@ -8,6 +8,8 @@
#include
#include
+#include "dusk/string.hpp"
+
J2DMaterialFactory::J2DMaterialFactory(J2DMaterialBlock const& param_0) {
mMaterialNum = param_0.field_0x8;
mpMaterialInitData = JSUConvertOffsetToPtr(¶m_0, param_0.field_0xc);
@@ -92,7 +94,7 @@ J2DMaterial* J2DMaterialFactory::create(J2DMaterial* param_0, int index, u32 par
}
if (local_380 == NULL && J2DScreen::getDataManage() != NULL) {
char acStack_230[257];
- strcpy(acStack_230, param_3->getName(texNo));
+ SAFE_STRCPY(acStack_230, param_3->getName(texNo));
local_380 = J2DScreen::getDataManage()->get(acStack_230);
}
}
@@ -111,7 +113,7 @@ J2DMaterial* J2DMaterialFactory::create(J2DMaterial* param_0, int index, u32 par
}
if (local_388 == NULL && J2DScreen::getDataManage() != NULL) {
char acStack_334[257];
- strcpy(acStack_334, param_4->getName(param_0->getTevBlock()->getFontNo()));
+ SAFE_STRCPY(acStack_334, param_4->getName(param_0->getTevBlock()->getFontNo()));
local_388 = J2DScreen::getDataManage()->get(acStack_334);
}
}
diff --git a/libs/JSystem/src/J2DGraph/J2DTevs.cpp b/libs/JSystem/src/J2DGraph/J2DTevs.cpp
index 8daf82872c..33a65dd273 100644
--- a/libs/JSystem/src/J2DGraph/J2DTevs.cpp
+++ b/libs/JSystem/src/J2DGraph/J2DTevs.cpp
@@ -68,8 +68,14 @@ void J2DIndTevStage::load(u8 tevStage) {
}
void J2DIndTexMtx::load(u8 indTexMtx) {
+#ifdef TARGET_PC
+ Mtx23 mtx;
+ mIndTexMtxInfo.mMtx.to_host(mtx);
+ GXSetIndTexMtx((GXIndTexMtxID)(GX_ITM_0 + indTexMtx), mtx, mIndTexMtxInfo.mScaleExp);
+#else
GXSetIndTexMtx((GXIndTexMtxID)(GX_ITM_0 + indTexMtx), mIndTexMtxInfo.mMtx,
mIndTexMtxInfo.mScaleExp);
+#endif
}
void J2DIndTexCoordScale::load(u8 indTexStage) {
diff --git a/libs/JSystem/src/J2DGraph/J2DTextBox.cpp b/libs/JSystem/src/J2DGraph/J2DTextBox.cpp
index 970f120140..d999b51b9f 100644
--- a/libs/JSystem/src/J2DGraph/J2DTextBox.cpp
+++ b/libs/JSystem/src/J2DGraph/J2DTextBox.cpp
@@ -309,8 +309,12 @@ void J2DTextBox::draw(f32 posX, f32 posY, f32 param_2, J2DTextBoxHBinding hBind)
}
}
-char* J2DTextBox::getStringPtr() const {
+TEXT_SPAN J2DTextBox::getStringPtr() const {
+#if TARGET_PC
+ return { mStringPtr, mStringLength };
+#else
return mStringPtr;
+#endif
}
s32 J2DTextBox::setString(char const* string, ...) {
@@ -330,7 +334,7 @@ s32 J2DTextBox::setString(char const* string, ...) {
if (mStringPtr) {
mStringLength = len + 1;
- strcpy(mStringPtr, string);
+ SAFE_STRCPY_BOUNDED(mStringPtr, mStringLength, string);
}
va_end(args);
diff --git a/libs/JSystem/src/JAHostIO/JAHVirtualNode.cpp b/libs/JSystem/src/JAHostIO/JAHVirtualNode.cpp
index b9cd8acb15..71068a3591 100644
--- a/libs/JSystem/src/JAHostIO/JAHVirtualNode.cpp
+++ b/libs/JSystem/src/JAHostIO/JAHVirtualNode.cpp
@@ -2,6 +2,8 @@
#include
#include
+#include "dusk/string.hpp"
+
u32 JAHVirtualNode::smVirNodeNum;
void JAHVirtualNode::virtualMessage(JAHControl& control) {
@@ -77,7 +79,7 @@ void JAHVirtualNode::setVirNodeName(const char* name) {
// clang-format off
JUT_ASSERT(141, size<32);
// clang-format on
- strcpy(mName, name);
+ SAFE_STRCPY(mName, name);
}
JAHVirtualNode::JAHVirtualNode(const char* name) : mTree(this) {
diff --git a/libs/JSystem/src/JAHostIO/JAHioNode.cpp b/libs/JSystem/src/JAHostIO/JAHioNode.cpp
index 9a30991e4f..e6c342eeeb 100644
--- a/libs/JSystem/src/JAHostIO/JAHioNode.cpp
+++ b/libs/JSystem/src/JAHostIO/JAHioNode.cpp
@@ -4,7 +4,9 @@
#include "JSystem/JAHostIO/JAHioMessage.h"
#include "JSystem/JAHostIO/JAHioMgr.h"
#include "JSystem/JAHostIO/JAHioNode.h"
+
#include "JSystem/JHostIO/JORServer.h"
+#include "dusk/string.hpp"
JAHioNode* JAHioNode::smCurrentNode;
@@ -32,7 +34,7 @@ void JAHioNode::updateNode() {
void JAHioNode::setNodeName(const char* name) {
int size = strlen(name) + 1;
JUT_ASSERT(51, size < 32);
- strcpy(mName, name);
+ SAFE_STRCPY(mName, name);
}
void JAHioNode::genMessage(JORMContext* mctx) {
diff --git a/libs/JSystem/src/JAudio2/JASWaveArcLoader.cpp b/libs/JSystem/src/JAudio2/JASWaveArcLoader.cpp
index d14ff70298..41ad35380d 100644
--- a/libs/JSystem/src/JAudio2/JASWaveArcLoader.cpp
+++ b/libs/JSystem/src/JAudio2/JASWaveArcLoader.cpp
@@ -9,6 +9,8 @@
#include
#include
+#include "dusk/string.hpp"
+
JASHeap* JASWaveArcLoader::sAramHeap;
JASHeap* JASWaveArcLoader::getRootHeap() {
@@ -22,7 +24,7 @@ char JASWaveArcLoader::sCurrentDir[DIR_MAX] = "/AudioRes/Waves/";
void JASWaveArcLoader::setCurrentDir(char const* dir) {
JUT_ASSERT(40, std::strlen(dir) < DIR_MAX - 1);
- strcpy(sCurrentDir, dir);
+ SAFE_STRCPY(sCurrentDir, dir);
u32 len = strlen(sCurrentDir);
if (sCurrentDir[len - 1] != '/') {
JUT_ASSERT(45, len + 1 < DIR_MAX);
@@ -170,8 +172,8 @@ void JASWaveArc::setFileName(char const* fileName) {
length = length + strlen(fileName);
char* path = JKR_NEW_ARRAY_ARGS(char, length + 1, JASKernel::getSystemHeap(), -4);
JUT_ASSERT(322, path);
- strcpy(path, currentDir);
- strcat(path, fileName);
+ SAFE_STRCPY_BOUNDED(path, length + 1, currentDir);
+ SAFE_STRCAT_BOUNDED(path, length + 1, fileName);
path[length] = '\0';
int entryNum = DVDConvertPathToEntrynum(path);
JKR_DELETE_ARRAY(path);
diff --git a/libs/JSystem/src/JFramework/JFWDisplay.cpp b/libs/JSystem/src/JFramework/JFWDisplay.cpp
index b8054e2130..2d4c9c7126 100644
--- a/libs/JSystem/src/JFramework/JFWDisplay.cpp
+++ b/libs/JSystem/src/JFramework/JFWDisplay.cpp
@@ -370,28 +370,28 @@ constexpr auto FRAME_PERIOD = std::chrono::duration_cast(sleepTime) / static_cast(targetNs));
- limiter.Sleep(targetNs);
}
#endif
static void waitForTick(u32 p1, u16 p2) {
#if TARGET_PC
- if (dusk::getSettings().game.enableFrameInterpolation && !dusk::getTransientSettings().skipFrameRateLimit) {
- dusk::frameUsagePct = 0.f;
- return;
+ static Limiter limiter;
+
+ if (dusk::frame_interp::is_enabled() && !dusk::getTransientSettings().skipFrameRateLimit) {
+ dusk::frameUsagePct = 0.f;
+ return;
}
+
if (dusk::getTransientSettings().skipFrameRateLimit) {
p1 = OS_TIMER_CLOCK / 120;
}
- #if TARGET_PC
if (fopOvlpM_IsPeek() && dusk::getTransientSettings().stateShareLoadActive) {
return;
}
- #endif
ZoneScopedC(tracy::Color::DimGray);
#endif
diff --git a/libs/JSystem/src/JKernel/JKRFileCache.cpp b/libs/JSystem/src/JKernel/JKRFileCache.cpp
index 97b0d6fdde..1a97ddefa3 100644
--- a/libs/JSystem/src/JKernel/JKRFileCache.cpp
+++ b/libs/JSystem/src/JKernel/JKRFileCache.cpp
@@ -8,6 +8,7 @@
#include
#include
+#include "dusk/string.hpp"
#include "global.h"
JKRFileCache* JKRFileCache::mount(const char* path, JKRHeap* heap, const char* param_3) {
diff --git a/libs/JSystem/src/JKernel/JKRFileLoader.cpp b/libs/JSystem/src/JKernel/JKRFileLoader.cpp
index e0e531aaa9..4a7fa00d10 100644
--- a/libs/JSystem/src/JKernel/JKRFileLoader.cpp
+++ b/libs/JSystem/src/JKernel/JKRFileLoader.cpp
@@ -4,10 +4,11 @@
#define MSL_USE_INLINES 1 // needed to inline tolower call. not inlined elsewhere in the repo
-#include
#include
+#include
#include
#include "JSystem/JKernel/JKRHeap.h"
+#include "dusk/string.hpp"
#include "global.h"
JKRFileLoader* JKRFileLoader::sCurrentVolume;
@@ -104,7 +105,7 @@ const char* JKRFileLoader::fetchVolumeName(char* buffer, s32 bufferSize, const c
static char rootPath[2] = "/";
if (strcmp(path, "/") == 0) {
- strcpy(buffer, rootPath);
+ SAFE_STRCPY_BOUNDED(buffer, bufferSize, rootPath);
return rootPath;
}
diff --git a/libs/JSystem/src/JKernel/JKRHeap.cpp b/libs/JSystem/src/JKernel/JKRHeap.cpp
index ce1899a4ba..c4849437ac 100644
--- a/libs/JSystem/src/JKernel/JKRHeap.cpp
+++ b/libs/JSystem/src/JKernel/JKRHeap.cpp
@@ -559,7 +559,7 @@ void* operator new(size_t size) {
return JKRHeap::alloc(size, 4, NULL);
}
#else
-void* operator new(size_t size JKR_HEAP_TOKEN_PARAM) {
+void* operator new(size_t size JKR_HEAP_TOKEN_PARAM) noexcept {
if (sCurrentHeap == NULL) {
return fallback_alloc(size, 0, false);
}
@@ -576,7 +576,7 @@ void* operator new(size_t size, int alignment) {
return JKRHeap::alloc(size, alignment, NULL);
}
#else
-void* operator new(size_t size JKR_HEAP_TOKEN_PARAM, int alignment) {
+void* operator new(size_t size JKR_HEAP_TOKEN_PARAM, int alignment) noexcept {
void* mem = JKRHeap::alloc(size, alignment, nullptr);
if (mem == nullptr) {
return fallback_alloc(size, abs(alignment), true);
@@ -585,7 +585,7 @@ void* operator new(size_t size JKR_HEAP_TOKEN_PARAM, int alignment) {
}
#endif
-void* operator new(size_t size JKR_HEAP_TOKEN_PARAM, JKRHeap* heap, int alignment) {
+void* operator new(size_t size JKR_HEAP_TOKEN_PARAM, JKRHeap* heap, int alignment) IF_DUSK(noexcept) {
void* mem = JKRHeap::alloc(size, alignment, heap);
#if TARGET_PC
if (mem == nullptr) {
@@ -600,7 +600,7 @@ void* operator new[](size_t size) {
return JKRHeap::alloc(size, 4, NULL);
}
#else
-void* operator new[](size_t JKR_HEAP_TOKEN_PARAM) {
+void* operator new[](size_t JKR_HEAP_TOKEN_PARAM) IF_DUSK(noexcept) {
OSPanic(__FILE__, __LINE__, "Allocation should go through JKR_NEW_ARRAY instead");
}
#endif
@@ -610,12 +610,12 @@ void* operator new[](size_t size, int alignment) {
return JKRHeap::alloc(size, alignment, NULL);
}
#else
-void* operator new[](size_t JKR_HEAP_TOKEN_PARAM, int) {
+void* operator new[](size_t JKR_HEAP_TOKEN_PARAM, int) IF_DUSK(noexcept) {
OSPanic(__FILE__, __LINE__, "Allocation should go through JKR_NEW_ARRAY instead");
}
#endif
-void* operator new[](size_t JKR_HEAP_TOKEN_PARAM, JKRHeap*, int) {
+void* operator new[](size_t JKR_HEAP_TOKEN_PARAM, JKRHeap*, int) IF_DUSK(noexcept) {
OSPanic(__FILE__, __LINE__, "Allocation should go through JKR_NEW_ARRAY instead");
}
@@ -624,7 +624,7 @@ void operator delete(void* ptr) {
JKRHeap::free(ptr, NULL);
}
#else
-void operator delete(void* ptr JKR_HEAP_TOKEN_PARAM) {
+void operator delete(void* ptr JKR_HEAP_TOKEN_PARAM) IF_DUSK(noexcept) {
if (ptr == NULL)
return;
JKRHeap* heap = JKRHeap::findFromRoot(ptr);
@@ -645,7 +645,7 @@ void operator delete[](void* ptr) {
JKRHeap::free(ptr, NULL);
}
#else
-void operator delete[](void* ptr JKR_HEAP_TOKEN_PARAM) {
+void operator delete[](void* ptr JKR_HEAP_TOKEN_PARAM) IF_DUSK(noexcept) {
if (ptr == NULL)
return;
JKRHeap* heap = JKRHeap::findFromRoot(ptr);
diff --git a/libs/JSystem/src/JKernel/JKRThread.cpp b/libs/JSystem/src/JKernel/JKRThread.cpp
index 31c2cbe6e5..8c945aba32 100644
--- a/libs/JSystem/src/JKernel/JKRThread.cpp
+++ b/libs/JSystem/src/JKernel/JKRThread.cpp
@@ -7,6 +7,8 @@
#include "global.h"
#include
+#include "dusk/string.hpp"
+
#if TARGET_PC
#include "dusk/os.h"
#endif
@@ -274,7 +276,7 @@ void JKRThreadSwitch::draw(JKRThreadName_* thread_name_list, JUTConsole* console
if (!thread_print_name) {
char buffer[16];
- sprintf(buffer, "%d", loadInfo->getId());
+ SAFE_SPRINTF(buffer, "%d", loadInfo->getId());
thread_print_name = buffer;
}
diff --git a/libs/JSystem/src/JParticle/JPABaseShape.cpp b/libs/JSystem/src/JParticle/JPABaseShape.cpp
index ff346984cd..add61135fe 100644
--- a/libs/JSystem/src/JParticle/JPABaseShape.cpp
+++ b/libs/JSystem/src/JParticle/JPABaseShape.cpp
@@ -76,6 +76,7 @@ void JPARegistAlpha(JPAEmitterWorkData* work, JPABaseParticle* ptcl) {
}
void JPARegistPrmAlpha(JPAEmitterWorkData* work, JPABaseParticle* ptcl) {
+ ZoneScoped;
JPABaseEmitter* emtr = work->mpEmtr;
GXColor prm = ptcl->mPrmClr;
prm.r = COLOR_MULTI(prm.r, emtr->mGlobalPrmClr.r);
@@ -87,6 +88,7 @@ void JPARegistPrmAlpha(JPAEmitterWorkData* work, JPABaseParticle* ptcl) {
}
void JPARegistPrmAlphaEnv(JPAEmitterWorkData* work, JPABaseParticle* ptcl) {
+ ZoneScoped;
JPABaseEmitter* emtr = work->mpEmtr;
GXColor prm = ptcl->mPrmClr;
GXColor env = ptcl->mEnvClr;
@@ -225,6 +227,7 @@ void JPAGenTexCrdMtxPrj(JPAEmitterWorkData* param_0) {
}
void JPAGenCalcTexCrdMtxAnm(JPAEmitterWorkData* work) {
+ ZoneScoped;
JPABaseShape* shape = work->mpRes->getBsp();
f32 dVar16 = work->mpEmtr->mTick;
f32 dVar15 = 0.5f * (1.0f + shape->getTilingS());
@@ -256,6 +259,7 @@ void JPAGenCalcTexCrdMtxAnm(JPAEmitterWorkData* work) {
}
void JPALoadCalcTexCrdMtxAnm(JPAEmitterWorkData* work, JPABaseParticle* param_1) {
+ ZoneScoped;
JPABaseShape* shape = work->mpRes->getBsp();
f32 dVar16 = param_1->mAge;
f32 dVar15 = 0.5f * (1.0f + shape->getTilingS());
@@ -286,14 +290,17 @@ void JPALoadCalcTexCrdMtxAnm(JPAEmitterWorkData* work, JPABaseParticle* param_1)
}
void JPALoadTex(JPAEmitterWorkData* work) {
+ ZoneScoped;
work->mpResMgr->load(work->mpRes->getTexIdx(work->mpRes->getBsp()->getTexIdx()), GX_TEXMAP0);
}
void JPALoadTexAnm(JPAEmitterWorkData* work) {
+ ZoneScoped;
work->mpResMgr->load(work->mpRes->getTexIdx(work->mpEmtr->mTexAnmIdx), GX_TEXMAP0);
}
void JPALoadTexAnm(JPAEmitterWorkData* work, JPABaseParticle* ptcl) {
+ ZoneScoped;
work->mpResMgr->load(work->mpRes->getTexIdx(ptcl->mTexAnmIdx), GX_TEXMAP0);
}
@@ -446,6 +453,7 @@ void JPADrawBillboard(JPAEmitterWorkData* work, JPABaseParticle* ptcl) {
return;
}
+ ZoneScoped;
JGeometry::TVec3 pos;
#if TARGET_PC
Mtx ptclPosMtx;
@@ -475,6 +483,7 @@ void JPADrawRotBillboard(JPAEmitterWorkData* work, JPABaseParticle* ptcl) {
return;
}
+ ZoneScoped;
if (work->mpRes->getUsrIdx() == 0x89d7) {
int a = 0;
}
@@ -518,6 +527,7 @@ void JPADrawYBillboard(JPAEmitterWorkData* work, JPABaseParticle* param_1) {
return;
}
+ ZoneScoped;
JGeometry::TVec3 local_48;
MTXMultVec(work->mPosCamMtx, ¶m_1->mPosition, &local_48);
Mtx local_38;
@@ -542,6 +552,7 @@ void JPADrawRotYBillboard(JPAEmitterWorkData* work, JPABaseParticle* param_1) {
return;
}
+ ZoneScoped;
JGeometry::TVec3 local_48;
MTXMultVec(work->mPosCamMtx, ¶m_1->mPosition, &local_48);
f32 sinRot = JMASSin(param_1->mRotateAngle);
@@ -1268,6 +1279,8 @@ void JPADrawStripeX(JPAEmitterWorkData* param_0) {
}
void JPADrawEmitterCallBackB(JPAEmitterWorkData* work) {
+ ZoneScoped;
+
JPABaseEmitter* emtr = work->mpEmtr;
if (emtr->mpEmtrCallBack == NULL) {
return;
@@ -1282,6 +1295,7 @@ void JPADrawParticleCallBack(JPAEmitterWorkData* work, JPABaseParticle* ptcl) {
return;
}
+ ZoneScoped;
emtr->mpPtclCallBack->draw(emtr, ptcl);
}
diff --git a/libs/JSystem/src/JParticle/JPAExTexShape.cpp b/libs/JSystem/src/JParticle/JPAExTexShape.cpp
index bb9510050e..cba10eb119 100644
--- a/libs/JSystem/src/JParticle/JPAExTexShape.cpp
+++ b/libs/JSystem/src/JParticle/JPAExTexShape.cpp
@@ -6,6 +6,8 @@
#include
void JPALoadExTex(JPAEmitterWorkData* work) {
+ ZoneScoped;
+
JPAExTexShape* ets = work->mpRes->getEts();
GXTexCoordID secTexCoordID = GX_TEXCOORD1;
diff --git a/libs/JSystem/src/JStudio/JStudio/jstudio-object.cpp b/libs/JSystem/src/JStudio/JStudio/jstudio-object.cpp
index ee99429ee2..864dec39fc 100644
--- a/libs/JSystem/src/JStudio/JStudio/jstudio-object.cpp
+++ b/libs/JSystem/src/JStudio/JStudio/jstudio-object.cpp
@@ -655,7 +655,7 @@ value_or_fun:
value:
#if TARGET_PC
- if (dusk::getSettings().game.enableFrameInterpolation && u <= 5 &&
+ if (dusk::frame_interp::is_enabled() && u <= 5 &&
(operation == data::UNK_0x2 || operation == data::UNK_0x3 || operation == data::UNK_0x12))
{
dusk::frame_interp::request_presentation_sync();
@@ -666,7 +666,7 @@ value:
value_n:
#if TARGET_PC
- if (dusk::getSettings().game.enableFrameInterpolation &&
+ if (dusk::frame_interp::is_enabled() &&
(pN == TAdaptor_camera::sauVariableValue_3_POSITION_XYZ || pN == TAdaptor_camera::sauVariableValue_3_TARGET_POSITION_XYZ) &&
(operation == data::UNK_0x2 || operation == data::UNK_0x3 || operation == data::UNK_0x12))
{
diff --git a/libs/JSystem/src/JUtility/JUTConsole.cpp b/libs/JSystem/src/JUtility/JUTConsole.cpp
index 3be4a370ef..c2c023a2d8 100644
--- a/libs/JSystem/src/JUtility/JUTConsole.cpp
+++ b/libs/JSystem/src/JUtility/JUTConsole.cpp
@@ -1,13 +1,14 @@
#include "JSystem/JSystem.h" // IWYU pragma: keep
-#include "JSystem/JUtility/JUTConsole.h"
+#include
+#include
#include "JSystem/J2DGraph/J2DOrthoGraph.h"
#include "JSystem/JKernel/JKRHeap.h"
#include "JSystem/JUtility/JUTAssert.h"
+#include "JSystem/JUtility/JUTConsole.h"
#include "JSystem/JUtility/JUTDirectPrint.h"
#include "JSystem/JUtility/JUTVideo.h"
-#include
-#include
+#include "dusk/string.hpp"
#include "global.h"
JUTConsoleManager* JUTConsoleManager::sManager;
@@ -204,10 +205,10 @@ void JUTConsole::doDraw(JUTConsole::EConsoleType consoleType) const {
mFont->drawString_scale((int)f31, sp94, mFontSizeX, mFontSizeY, spA8, TRUE);
f31 += mFontSizeX * 13.0f;
if (sp88) {
- sprintf(spB8, "ALL");
+ SAFE_SPRINTF(spB8, "ALL");
} else {
f32 f29 = sp8C / (f32)(sp90 - mHeight);
- sprintf(spB8, "%3d%%(%dL)", (int)(100.0 * f29), sp90);
+ SAFE_SPRINTF(spB8, "%3d%%(%dL)", (int)(100.0 * f29), sp90);
}
mFont->drawString_scale(f31, sp94, mFontSizeX, mFontSizeY, spB8, TRUE);
}
diff --git a/libs/JSystem/src/JUtility/JUTException.cpp b/libs/JSystem/src/JUtility/JUTException.cpp
index 514ec6dd8a..54b234118c 100644
--- a/libs/JSystem/src/JUtility/JUTException.cpp
+++ b/libs/JSystem/src/JUtility/JUTException.cpp
@@ -9,6 +9,8 @@
#include
#include
#include
+
+#include "dusk/string.hpp"
#ifdef __REVOLUTION_SDK__
#include
#else
@@ -845,8 +847,8 @@ bool JUTException::queryMapAddress(char* mapPath, u32 address, s32 section_id, u
bool begin_with_newline) {
if (mapPath) {
char buffer[80];
- strcpy(buffer, mapPath);
- strcat(buffer, ".map");
+ SAFE_STRCPY(buffer, mapPath);
+ SAFE_STRCAT(buffer, ".map");
if (queryMapAddress_single(buffer, address, section_id, out_addr, out_size, out_line,
line_length, print, begin_with_newline) == true)
{
diff --git a/libs/freeverb/denormals.h b/libs/freeverb/denormals.h
index d68cb444f7..9193798abe 100644
--- a/libs/freeverb/denormals.h
+++ b/libs/freeverb/denormals.h
@@ -13,20 +13,33 @@ inline denormal_state denormals_enable()
}
inline void denormals_restore(denormal_state saved) { _mm_setcsr(saved); }
-#elif defined(__aarch64__) || defined(_M_ARM64)
+#elif defined(__aarch64__) || defined(_M_ARM64) || defined(_M_ARM64EC)
#include
+#if defined(_MSC_VER) && !defined(__clang__) && (defined(_M_ARM64) || defined(_M_ARM64EC))
+#include
+#endif
using denormal_state = uint64_t;
inline denormal_state denormals_enable()
{
+#if defined(_MSC_VER) && !defined(__clang__) && (defined(_M_ARM64) || defined(_M_ARM64EC))
+ denormal_state saved = static_cast(_ReadStatusReg(ARM64_FPCR));
+ _WriteStatusReg(ARM64_FPCR, static_cast<__int64>(saved | (1ULL << 24))); // FZ
+ return saved;
+#else
denormal_state saved;
asm volatile("mrs %0, fpcr" : "=r"(saved));
asm volatile("msr fpcr, %0" :: "r"(saved | (1ULL << 24))); // FZ
return saved;
+#endif
}
inline void denormals_restore(denormal_state saved)
{
+#if defined(_MSC_VER) && !defined(__clang__) && (defined(_M_ARM64) || defined(_M_ARM64EC))
+ _WriteStatusReg(ARM64_FPCR, static_cast<__int64>(saved));
+#else
asm volatile("msr fpcr, %0" :: "r"(saved));
+#endif
}
#elif defined(__arm__) || defined(_M_ARM)
diff --git a/platforms/android/app/build.gradle b/platforms/android/app/build.gradle
index 2dc8575f86..8527cd1f4d 100644
--- a/platforms/android/app/build.gradle
+++ b/platforms/android/app/build.gradle
@@ -2,6 +2,9 @@ plugins {
id 'com.android.application'
}
+def versionNameStr = (System.getenv("DUSK_VERSION") ?: "v0.1.0").replaceFirst("^v", "")
+def versionCodeInt = (System.getenv("DUSK_VERSION_CODE") ?: "100000").toInteger()
+
def duskRepoDir = rootProject.projectDir.parentFile.parentFile
def duskGeneratedAssetsDir = layout.buildDirectory.dir('generated/assets/dusklight').get().asFile
def syncDuskAssets = tasks.register('syncDuskAssets', Sync) {
@@ -20,8 +23,8 @@ android {
applicationId 'dev.twilitrealm.dusk'
minSdk 26
targetSdk 36
- versionCode 1
- versionName '0.1.0'
+ versionCode versionCodeInt
+ versionName versionNameStr
}
buildTypes {
diff --git a/platforms/android/app/src/main/AndroidManifest.xml b/platforms/android/app/src/main/AndroidManifest.xml
index f5a0365856..cd687963e1 100644
--- a/platforms/android/app/src/main/AndroidManifest.xml
+++ b/platforms/android/app/src/main/AndroidManifest.xml
@@ -11,6 +11,7 @@
+
{
Intent intent = new Intent(Intent.ACTION_OPEN_DOCUMENT_TREE);
intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION |
@@ -185,9 +204,71 @@ public class DuskActivity extends SDLActivity {
finishFolderDialog(Activity.RESULT_CANCELED, null);
}
});
+ }
+
+ private boolean requiresManageStoragePermission() {
+ return Build.VERSION.SDK_INT >= Build.VERSION_CODES.R;
+ }
+
+ private boolean hasManageStoragePermission() {
+ return !requiresManageStoragePermission() || Environment.isExternalStorageManager();
+ }
+
+ private boolean requestManageStoragePermission() {
+ if (!requiresManageStoragePermission()) {
+ return true;
+ }
+
+ awaitingManageStoragePermission = true;
+ runOnUiThread(() -> {
+ if (tryStartManageStorageIntent(
+ new Intent(Settings.ACTION_MANAGE_APP_ALL_FILES_ACCESS_PERMISSION)
+ .setData(Uri.parse("package:" + getPackageName()))) ||
+ tryStartManageStorageIntent(
+ new Intent(Settings.ACTION_MANAGE_ALL_FILES_ACCESS_PERMISSION)))
+ {
+ return;
+ }
+
+ finishFolderDialogWithError("Unable to request Android file access permission");
+ });
return true;
}
+ private boolean tryStartManageStorageIntent(Intent intent) {
+ try {
+ startActivityForResult(intent, MANAGE_STORAGE_REQUEST_CODE);
+ return true;
+ } catch (ActivityNotFoundException e) {
+ Log.w(TAG, "Unable to open all-files access settings.", e);
+ return false;
+ }
+ }
+
+ private void resumeFolderDialogAfterPermissionGrant() {
+ awaitingManageStoragePermission = false;
+ if (folderDialogUserdata == 0) {
+ return;
+ }
+
+ if (hasManageStoragePermission()) {
+ openFolderDialog();
+ return;
+ }
+
+ finishFolderDialogWithError(
+ "Allow \"All files access\" for Dusklight before choosing a custom data folder");
+ }
+
+ private void finishFolderDialogWithError(String error) {
+ long userdata = folderDialogUserdata;
+ folderDialogUserdata = 0;
+ awaitingManageStoragePermission = false;
+ if (userdata != 0) {
+ nativeFolderDialogResult(userdata, null, error);
+ }
+ }
+
private void finishFolderDialog(int resultCode, Intent data) {
long userdata = folderDialogUserdata;
folderDialogUserdata = 0;
diff --git a/platforms/android/app/src/main/java/org/libsdl/app/SDLActivity.java b/platforms/android/app/src/main/java/org/libsdl/app/SDLActivity.java
index 42f5a911f7..5c54cde863 100644
--- a/platforms/android/app/src/main/java/org/libsdl/app/SDLActivity.java
+++ b/platforms/android/app/src/main/java/org/libsdl/app/SDLActivity.java
@@ -61,7 +61,7 @@ public class SDLActivity extends Activity implements View.OnSystemUiVisibilityCh
private static final String TAG = "SDL";
private static final int SDL_MAJOR_VERSION = 3;
private static final int SDL_MINOR_VERSION = 4;
- private static final int SDL_MICRO_VERSION = 4;
+ private static final int SDL_MICRO_VERSION = 8;
/*
// Display InputType.SOURCE/CLASS of events and devices
//
@@ -570,7 +570,7 @@ public class SDLActivity extends Activity implements View.OnSystemUiVisibilityCh
public static int getNaturalOrientation() {
int result = SDL_ORIENTATION_UNKNOWN;
- Activity activity = (Activity)getContext();
+ Activity activity = getContext();
if (activity != null) {
Configuration config = activity.getResources().getConfiguration();
Display display = activity.getWindowManager().getDefaultDisplay();
@@ -590,7 +590,7 @@ public class SDLActivity extends Activity implements View.OnSystemUiVisibilityCh
public static int getCurrentRotation() {
int result = 0;
- Activity activity = (Activity)getContext();
+ Activity activity = getContext();
if (activity != null) {
Display display = activity.getWindowManager().getDefaultDisplay();
switch (display.getRotation()) {
@@ -1292,7 +1292,7 @@ public class SDLActivity extends Activity implements View.OnSystemUiVisibilityCh
public static double getDiagonal()
{
DisplayMetrics metrics = new DisplayMetrics();
- Activity activity = (Activity)getContext();
+ Activity activity = getContext();
if (activity == null) {
return 0.0;
}
@@ -1940,7 +1940,7 @@ public class SDLActivity extends Activity implements View.OnSystemUiVisibilityCh
return;
}
- Activity activity = (Activity)getContext();
+ Activity activity = getContext();
if (activity.checkSelfPermission(permission) != PackageManager.PERMISSION_GRANTED) {
activity.requestPermissions(new String[]{permission}, requestCode);
} else {
diff --git a/platforms/freedesktop/1024x1024/apps/dusklight.png b/platforms/freedesktop/1024x1024/apps/dev.twilitrealm.dusk.png
similarity index 100%
rename from platforms/freedesktop/1024x1024/apps/dusklight.png
rename to platforms/freedesktop/1024x1024/apps/dev.twilitrealm.dusk.png
diff --git a/platforms/freedesktop/128x128/apps/dusklight.png b/platforms/freedesktop/128x128/apps/dev.twilitrealm.dusk.png
similarity index 100%
rename from platforms/freedesktop/128x128/apps/dusklight.png
rename to platforms/freedesktop/128x128/apps/dev.twilitrealm.dusk.png
diff --git a/platforms/freedesktop/16x16/apps/dusklight.png b/platforms/freedesktop/16x16/apps/dev.twilitrealm.dusk.png
similarity index 100%
rename from platforms/freedesktop/16x16/apps/dusklight.png
rename to platforms/freedesktop/16x16/apps/dev.twilitrealm.dusk.png
diff --git a/platforms/freedesktop/256x256/apps/dusklight.png b/platforms/freedesktop/256x256/apps/dev.twilitrealm.dusk.png
similarity index 100%
rename from platforms/freedesktop/256x256/apps/dusklight.png
rename to platforms/freedesktop/256x256/apps/dev.twilitrealm.dusk.png
diff --git a/platforms/freedesktop/32x32/apps/dusklight.png b/platforms/freedesktop/32x32/apps/dev.twilitrealm.dusk.png
similarity index 100%
rename from platforms/freedesktop/32x32/apps/dusklight.png
rename to platforms/freedesktop/32x32/apps/dev.twilitrealm.dusk.png
diff --git a/platforms/freedesktop/48x48/apps/dusklight.png b/platforms/freedesktop/48x48/apps/dev.twilitrealm.dusk.png
similarity index 100%
rename from platforms/freedesktop/48x48/apps/dusklight.png
rename to platforms/freedesktop/48x48/apps/dev.twilitrealm.dusk.png
diff --git a/platforms/freedesktop/512x512/apps/dusklight.png b/platforms/freedesktop/512x512/apps/dev.twilitrealm.dusk.png
similarity index 100%
rename from platforms/freedesktop/512x512/apps/dusklight.png
rename to platforms/freedesktop/512x512/apps/dev.twilitrealm.dusk.png
diff --git a/platforms/freedesktop/64x64/apps/dusklight.png b/platforms/freedesktop/64x64/apps/dev.twilitrealm.dusk.png
similarity index 100%
rename from platforms/freedesktop/64x64/apps/dusklight.png
rename to platforms/freedesktop/64x64/apps/dev.twilitrealm.dusk.png
diff --git a/platforms/freedesktop/dusklight.desktop b/platforms/freedesktop/dev.twilitrealm.dusk.desktop
similarity index 86%
rename from platforms/freedesktop/dusklight.desktop
rename to platforms/freedesktop/dev.twilitrealm.dusk.desktop
index 4f6ba034a9..b1ad2831a2 100644
--- a/platforms/freedesktop/dusklight.desktop
+++ b/platforms/freedesktop/dev.twilitrealm.dusk.desktop
@@ -3,7 +3,7 @@ Name=Dusklight
GenericName=Dusklight
Comment=PC port of a classic adventure game
Exec=dusklight
-Icon=dusklight
+Icon=dev.twilitrealm.dusk
Terminal=false
Type=Application
Categories=Game;
diff --git a/res/rml/prelaunch.rcss b/res/rml/prelaunch.rcss
index f5d7240d56..73efc18086 100644
--- a/res/rml/prelaunch.rcss
+++ b/res/rml/prelaunch.rcss
@@ -447,6 +447,7 @@ body.animate-in .intro-item {
top: auto;
text-align: right;
font-size: 16dp;
+ gap: 8dp;
}
#disc-status {
@@ -468,6 +469,7 @@ body.animate-in .intro-item {
top: 32dp;
text-align: right;
font-size: 16dp;
+ gap: 8dp;
}
.update {
diff --git a/src/Z2AudioLib/Z2SoundMgr.cpp b/src/Z2AudioLib/Z2SoundMgr.cpp
index b861475118..6978a61585 100644
--- a/src/Z2AudioLib/Z2SoundMgr.cpp
+++ b/src/Z2AudioLib/Z2SoundMgr.cpp
@@ -183,7 +183,7 @@ bool Z2SoundMgr::startSound(JAISoundID soundID, JAISoundHandle* handle, const JG
return streamMgr_.startSound(soundID, handle, posPtr);
default:
char error[64];
- sprintf(error, "Unknown Sound-Type id :%08x\n", (u32)soundID);
+ SAFE_SPRINTF(error, "Unknown Sound-Type id :%08x\n", (u32)soundID);
JUT_WARN(277, "%s", error);
}
diff --git a/src/d/actor/d_a_alink.cpp b/src/d/actor/d_a_alink.cpp
index 498d3de173..9bec9da6d0 100644
--- a/src/d/actor/d_a_alink.cpp
+++ b/src/d/actor/d_a_alink.cpp
@@ -57,6 +57,7 @@
#include "dusk/settings.h"
#include "res/Object/Alink.h"
#include
+#include
#endif
static int daAlink_Create(fopAc_ac_c* i_this);
@@ -5990,7 +5991,7 @@ void daAlink_c::setItemMatrix(int param_0) {
mDoMtx_stack_c::XrotS(-0x8000);
#ifdef TARGET_PC
- if (dusk::getSettings().game.enableFrameInterpolation) {
+ if (dusk::frame_interp::is_enabled()) {
Mtx boot_mtx;
mDoMtx_concat(mpLinkModel->getAnmMtx(0x18), mDoMtx_stack_c::get(), boot_mtx);
mpLinkBootModels[1]->setAnmMtx(1, boot_mtx);
@@ -7562,12 +7563,7 @@ void daAlink_c::setBlendMoveAnime(f32 i_morf) {
f32 sp2C;
f32 sp28 = mpHIO->mMove.m.mFootPositionRatio;
BOOL sp24 = checkEventRun();
- BOOL sp20 = checkBootsMoveAnime(1);
-#if TARGET_PC
- if (dusk::getSettings().game.enableFastIronBoots) {
- sp20 = FALSE;
- }
-#endif
+ BOOL sp20 = checkBootsMoveAnime(1) IF_DUSK(&& !dusk::getSettings().game.enableFastIronBoots);
f32 var_f29;
@@ -8080,7 +8076,7 @@ void daAlink_c::setBlendAtnBackMoveAnime(f32 i_morf) {
daAlink_ANM var_r27;
daAlink_ANM var_r29;
- if (checkBootsMoveAnime(1)) {
+ if (checkBootsMoveAnime(1) IF_DUSK(&& !dusk::getSettings().game.enableFastIronBoots)) {
mMaxSpeed = mpHIO->mAtnMove.m.mMaxBackwardsSpeed;
var_f27 = mpHIO->mAtnMove.m.mMinBackWalkFrame;
var_f31 = mpHIO->mAtnMove.m.mBackWalkChangeRate;
@@ -19772,7 +19768,7 @@ int daAlink_c::draw() {
dComIfGd_getOpaListDark()->entryImm(mpHookChain, 0);
#if TARGET_PC
- if (dusk::getSettings().game.enableFrameInterpolation &&
+ if (dusk::frame_interp::is_enabled() &&
mEquipItem == dItemNo_IRONBALL_e &&
mIronBallChainPos != NULL && mIronBallChainAngle != NULL)
{
diff --git a/src/d/actor/d_a_alink_cut.inc b/src/d/actor/d_a_alink_cut.inc
index f33d2935c5..ba3c0ba89e 100644
--- a/src/d/actor/d_a_alink_cut.inc
+++ b/src/d/actor/d_a_alink_cut.inc
@@ -1165,6 +1165,10 @@ int daAlink_c::procCutFinishInit(int i_type) {
const daAlink_cutParamTbl* cutParams = &cutParamTable[i_type];
BOOL is_proc_frontRoll = mProcID == PROC_FRONT_ROLL;
+#if TARGET_PC
+ mIsRollstab = (is_proc_frontRoll != FALSE) && (i_type == CUT_FINISH_PARAM_STAB);
+#endif
+
commonProcInit(PROC_CUT_FINISH);
setCutType(cutParams->m_cutType);
field_0x3198 = cutParams->m_recoilAnmID;
diff --git a/src/d/actor/d_a_alink_demo.inc b/src/d/actor/d_a_alink_demo.inc
index 55e261cc13..b1eb71a85d 100644
--- a/src/d/actor/d_a_alink_demo.inc
+++ b/src/d/actor/d_a_alink_demo.inc
@@ -4359,7 +4359,7 @@ void daAlink_c::dungeonReturnWarp() {
s16 angle = dComIfGs_getWarpPlayerAngleY();
s8 room = dComIfGs_getWarpRoomNo();
char name[8];
- strcpy(name, dComIfGs_getWarpStageName());
+ SAFE_STRCPY(name, dComIfGs_getWarpStageName());
dComIfGs_setRestartRoom(pos, angle, room);
dComIfGp_setNextStage(name, -1, dComIfGs_getRestartRoomNo(), -1, 0.0f, 12, 0,
@@ -4535,7 +4535,7 @@ int daAlink_c::procCoWarpInit(int param_0, int param_1) {
if (checkBossRoom() && fopAcM_GetRoomNo(this) == 50) {
char stageName[32];
- strcpy(stageName, dComIfGp_getStartStageName());
+ SAFE_STRCPY(stageName, dComIfGp_getStartStageName());
for (int i = 0; i < 32; i++) {
if ((s64)stageName[i] == 0) {
diff --git a/src/d/actor/d_a_alink_swim.inc b/src/d/actor/d_a_alink_swim.inc
index 038d710e80..19131e404a 100644
--- a/src/d/actor/d_a_alink_swim.inc
+++ b/src/d/actor/d_a_alink_swim.inc
@@ -216,7 +216,7 @@ void daAlink_c::setSpeedAndAngleSwim() {
if (checkEventRun()) {
var_r28 = mMoveAngle;
} else {
- var_r28 = shape_angle.y + (16384.0f * cM_ssin(mStickAngle));
+ var_r28 = shape_angle.y + (16384.0f * cM_ssin(mStickAngle) IF_DUSK(* (dusk::getSettings().game.invertAirSwimX ? -1.0f : 1.0f)));
}
cLib_addCalcAngleS(&shape_angle.y, var_r28, mpHIO->mSwim.m.mUnderwaterTurnRate, mpHIO->mSwim.m.mUnderwaterMaxTurn, mpHIO->mSwim.m.mUnderwaterMinTurn);
@@ -835,7 +835,7 @@ void daAlink_c::setSwimMoveAnime() {
} else {
s16 var_r24;
if (checkInputOnR() && !checkEventRun()) {
- var_r24 = 13653.0f * cM_scos(mStickAngle);
+ var_r24 = 13653.0f * cM_scos(mStickAngle) IF_DUSK(* (dusk::getSettings().game.invertAirSwimY ? -1.0f : 1.0f));
} else {
var_r24 = 0;
}
diff --git a/src/d/actor/d_a_alink_wolf.inc b/src/d/actor/d_a_alink_wolf.inc
index 67fde3a7a7..43b60e9d42 100644
--- a/src/d/actor/d_a_alink_wolf.inc
+++ b/src/d/actor/d_a_alink_wolf.inc
@@ -4005,7 +4005,13 @@ int daAlink_c::procWolfHowlDemoInit() {
} else if (name == fpcNm_Tag_WaraHowl_e) {
mZ2WolfHowlMgr.setCorrectCurve(static_cast(field_0x27f4)->getTuneId());
} else {
+ #if TARGET_PC
+ if (mZ2WolfHowlMgr.getCorrectCurveID() != 9) {
+ mZ2WolfHowlMgr.setCorrectCurve(-1);
+ }
+ #else
mZ2WolfHowlMgr.setCorrectCurve(-1);
+ #endif
}
} else {
#if TARGET_PC
diff --git a/src/d/actor/d_a_b_gnd.cpp b/src/d/actor/d_a_b_gnd.cpp
index f5b03be1b1..0f982e59e8 100644
--- a/src/d/actor/d_a_b_gnd.cpp
+++ b/src/d/actor/d_a_b_gnd.cpp
@@ -397,7 +397,7 @@ static int daB_GND_Draw(b_gnd_class* i_this) {
i_this->field_0x21e8.update(2, l_color, &a_this->tevStr);
dComIfGd_set3DlineMat(&i_this->field_0x21e8);
#if TARGET_PC
- if (dusk::getSettings().game.enableFrameInterpolation) {
+ if (dusk::frame_interp::is_enabled()) {
if (i_this->mReinsInterpCurrValid) {
memcpy(i_this->mReinsInterpPrev, i_this->mReinsInterpCurr, sizeof(i_this->mReinsInterpCurr));
memcpy(i_this->mReinsTexInterpPrev, i_this->mReinsTexInterpCurr, sizeof(i_this->mReinsTexInterpCurr));
@@ -2192,6 +2192,9 @@ static void damage_check(b_gnd_class* i_this) {
i_this->mDamageInvulnerabilityTimer = 100;
}
}
+ #if TARGET_PC
+ dusk::AchievementSystem::get().signal("ganondorf_hit");
+ #endif
}
cXyz hitmark_size(1.0f, 1.0f, 1.0f);
@@ -2218,6 +2221,7 @@ static void damage_check(b_gnd_class* i_this) {
i_this->field_0xc7c = 0;
dScnPly_c::setPauseTimer(7);
a_this->health = 100;
+ dusk::AchievementSystem::get().signal("ganondorf_knocked_down");
}
break;
}
diff --git a/src/d/actor/d_a_bg_obj.cpp b/src/d/actor/d_a_bg_obj.cpp
index 7d4adb9e47..026ef1a7fd 100644
--- a/src/d/actor/d_a_bg_obj.cpp
+++ b/src/d/actor/d_a_bg_obj.cpp
@@ -5,24 +5,25 @@
#include "d/dolzel_rel.h" // IWYU pragma: keep
-#include "d/actor/d_a_bg_obj.h"
-#include "JSystem/J3DGraphBase/J3DMaterial.h"
#include
-#include
#include
+#include
+#include "JSystem/J3DGraphBase/J3DMaterial.h"
+#include "SSystem/SComponent/c_math.h"
+#include "d/actor/d_a_bg_obj.h"
#include "d/actor/d_a_set_bgobj.h"
#include "d/d_s_play.h"
-#include "SSystem/SComponent/c_math.h"
+#include "dusk/string.hpp"
static const char* getBmdName(int param_0, int param_1) {
static char l_bmdName[16];
switch (param_1) {
case 0:
- sprintf(l_bmdName, "model%d.bmd", param_0);
+ SAFE_SPRINTF(l_bmdName, "model%d.bmd", param_0);
break;
default:
- sprintf(l_bmdName, "model%d_%d.bmd", param_0, param_1);
+ SAFE_SPRINTF(l_bmdName, "model%d_%d.bmd", param_0, param_1);
break;
}
@@ -34,10 +35,10 @@ static const char* getBtkName(int param_0, int param_1) {
switch (param_1) {
case 0:
- sprintf(l_btkName, "model%d.btk", param_0);
+ SAFE_SPRINTF(l_btkName, "model%d.btk", param_0);
break;
default:
- sprintf(l_btkName, "model%d_%d.btk", param_0, param_1);
+ SAFE_SPRINTF(l_btkName, "model%d_%d.btk", param_0, param_1);
break;
}
@@ -49,10 +50,10 @@ static const char* getBrkName(int param_0, int param_1) {
switch (param_1) {
case 0:
- sprintf(l_brkName, "model%d.brk", param_0);
+ SAFE_SPRINTF(l_brkName, "model%d.brk", param_0);
break;
default:
- sprintf(l_brkName, "model%d_%d.brk", param_0, param_1);
+ SAFE_SPRINTF(l_brkName, "model%d_%d.brk", param_0, param_1);
break;
}
@@ -62,7 +63,7 @@ static const char* getBrkName(int param_0, int param_1) {
static const char* getDzbName(int param_0) {
static char l_dzbName[16];
- sprintf(l_dzbName, "model%d.dzb", param_0);
+ SAFE_SPRINTF(l_dzbName, "model%d.dzb", param_0);
return l_dzbName;
}
@@ -95,12 +96,12 @@ u8* daBgObj_c::spec_data_c::initTexShareBlock(u8* i_dataPtr) {
u8* dataPos = i_dataPtr + 8;
for (; i < mTexShareNum; i++) {
- strcpy(sp48, (char*)dataPos);
+ SAFE_STRCPY(sp48, (char*)dataPos);
int len = strlen((char*)dataPos);
dataPos += len + 1;
if (*dataPos != 0) {
- strcpy(sp8, (char*)dataPos);
+ SAFE_STRCPY(sp8, (char*)dataPos);
dataPos += strlen((char*)dataPos) + 1;
} else if (*dataPos == 0 && dataPos[1] == 1) {
dataPos += 2;
@@ -646,14 +647,14 @@ void daBgObj_c::doShareTexture() {
u8* spec_res_name = mSpecData.mpTexShareBlock + 8;
for (int i = 0; i < mSpecData.mTexShareNum; i++) {
- strcpy(res_name, (char*)spec_res_name);
+ SAFE_STRCPY(res_name, (char*)spec_res_name);
spec_res_name += strlen((char*)spec_res_name) + 1;
J3DModelData* modelData =
(J3DModelData*)dComIfG_getObjectRes(daSetBgObj_c::getArcName(this), res_name);
if (*spec_res_name != 0) {
- strcpy(share_res_name, (char*)spec_res_name);
+ SAFE_STRCPY(share_res_name, (char*)spec_res_name);
spec_res_name += strlen((char*)spec_res_name) + 1;
J3DModelData* shareModelData =
diff --git a/src/d/actor/d_a_door_dbdoor00.cpp b/src/d/actor/d_a_door_dbdoor00.cpp
index c659a47cb2..edac3c14f8 100644
--- a/src/d/actor/d_a_door_dbdoor00.cpp
+++ b/src/d/actor/d_a_door_dbdoor00.cpp
@@ -51,7 +51,7 @@ static char* l_bmd_base_name = "door-pushDouble_";
char* daDbDoor00_c::getBmdName() {
static char l_bmdName[32];
- sprintf(l_bmdName, "%s%02d.bmd", l_bmd_base_name, door_param2_c::getDoorModel(this));
+ SAFE_SPRINTF(l_bmdName, "%s%02d.bmd", l_bmd_base_name, door_param2_c::getDoorModel(this));
return l_bmdName;
}
diff --git a/src/d/actor/d_a_door_knob00.cpp b/src/d/actor/d_a_door_knob00.cpp
index 50d5723261..ea4a9c8679 100644
--- a/src/d/actor/d_a_door_knob00.cpp
+++ b/src/d/actor/d_a_door_knob00.cpp
@@ -55,7 +55,7 @@ static char* l_bmd_base_name = "door-knob_";
char* daKnob20_c::getBmd() {
static char l_bmdName[32];
- sprintf(l_bmdName, "%s%02d.bmd", l_bmd_base_name, knob_param_c::getDoorModel(this));
+ SAFE_SPRINTF(l_bmdName, "%s%02d.bmd", l_bmd_base_name, knob_param_c::getDoorModel(this));
return l_bmdName;
}
diff --git a/src/d/actor/d_a_door_shutter.cpp b/src/d/actor/d_a_door_shutter.cpp
index ebd1c9a185..ba825fe4bd 100644
--- a/src/d/actor/d_a_door_shutter.cpp
+++ b/src/d/actor/d_a_door_shutter.cpp
@@ -65,10 +65,10 @@ char* daDoor20_c::getBmdName() {
case 10:
case 12:
default:
- sprintf(bmdName, "door-shutter_%02d.bmd", door_param2_c::getDoorModel(this));
+ SAFE_SPRINTF(bmdName, "door-shutter_%02d.bmd", door_param2_c::getDoorModel(this));
break;
case 9:
- sprintf(bmdName, "door-knob_%02d.bmd", door_param2_c::getDoorModel(this));
+ SAFE_SPRINTF(bmdName, "door-knob_%02d.bmd", door_param2_c::getDoorModel(this));
break;
}
return bmdName;
diff --git a/src/d/actor/d_a_door_spiral.cpp b/src/d/actor/d_a_door_spiral.cpp
index b7c7567787..d0c34c6dbd 100644
--- a/src/d/actor/d_a_door_spiral.cpp
+++ b/src/d/actor/d_a_door_spiral.cpp
@@ -94,9 +94,9 @@ const char* daSpiral_c::getBmd(int i_type) {
const char* daSpiral_c::getBmd2(int i_type) {
static char bmdName[32];
if (i_type == daSpiral_TYPE_DOWN_e) {
- sprintf(bmdName, "door-stairSpiralU.bmd");
+ SAFE_SPRINTF(bmdName, "door-stairSpiralU.bmd");
} else {
- sprintf(bmdName, "door-stairSpiralD.bmd");
+ SAFE_SPRINTF(bmdName, "door-stairSpiralD.bmd");
}
return bmdName;
diff --git a/src/d/actor/d_a_e_arrow.cpp b/src/d/actor/d_a_e_arrow.cpp
index 11746e3a76..155f36e2fb 100644
--- a/src/d/actor/d_a_e_arrow.cpp
+++ b/src/d/actor/d_a_e_arrow.cpp
@@ -674,7 +674,29 @@ static int daE_ARROW_Create(fopAc_ac_c* i_this) {
}
int phase_state = dComIfG_resLoad(&a_this->mPhase, a_this->mResName);
+#if TARGET_PC
+ static int s_create_frames = 0;
+ static bool s_first_arrow = true;
+ static fpc_ProcID s_last_scene_id = 0;
+
+ s_create_frames++;
+ fpc_ProcID cur_scene_id = dStage_roomControl_c::getProcID();
+
+ if (cur_scene_id != s_last_scene_id) {
+ s_first_arrow = true;
+ s_last_scene_id = cur_scene_id;
+ }
+
+ if (phase_state == cPhs_COMPLEATE_e && s_first_arrow && s_create_frames < 4) {
+ return cPhs_INIT_e;
+ }
+#endif
if (phase_state == cPhs_COMPLEATE_e) {
+#if TARGET_PC
+ s_create_frames = 0;
+ s_first_arrow = false;
+#endif
+
a_this->mArrowType = fopAcM_GetParam(a_this) & 0xF;
a_this->mFlags = fopAcM_GetParam(a_this) & 0xF0;
diff --git a/src/d/actor/d_a_e_db.cpp b/src/d/actor/d_a_e_db.cpp
index 4d60fbd6f6..6a4ed52aba 100644
--- a/src/d/actor/d_a_e_db.cpp
+++ b/src/d/actor/d_a_e_db.cpp
@@ -116,7 +116,7 @@ static int daE_DB_Draw(e_db_class* i_this) {
i_this->stalkLine.update(12, l_color, &actor->tevStr);
dComIfGd_set3DlineMat(&i_this->stalkLine);
#if TARGET_PC
- if (dusk::getSettings().game.enableFrameInterpolation) {
+ if (dusk::frame_interp::is_enabled()) {
if (i_this->mStalkLineInterpCurrValid) {
memcpy(i_this->mStalkLineInterpPrev, i_this->mStalkLineInterpCurr, sizeof(i_this->mStalkLineInterpCurr));
i_this->mStalkLineInterpPrevValid = true;
diff --git a/src/d/actor/d_a_e_hb.cpp b/src/d/actor/d_a_e_hb.cpp
index 8ed9058c6f..2b13b8a153 100644
--- a/src/d/actor/d_a_e_hb.cpp
+++ b/src/d/actor/d_a_e_hb.cpp
@@ -103,7 +103,7 @@ static int daE_HB_Draw(e_hb_class* i_this) {
i_this->stalkLine.update(12, l_color, &actor->tevStr);
dComIfGd_set3DlineMat(&i_this->stalkLine);
#if TARGET_PC
- if (dusk::getSettings().game.enableFrameInterpolation) {
+ if (dusk::frame_interp::is_enabled()) {
if (i_this->mStalkLineInterpCurrValid) {
memcpy(i_this->mStalkLineInterpPrev, i_this->mStalkLineInterpCurr, sizeof(i_this->mStalkLineInterpCurr));
i_this->mStalkLineInterpPrevValid = true;
diff --git a/src/d/actor/d_a_e_mb.cpp b/src/d/actor/d_a_e_mb.cpp
index aa77a99612..31352f92cf 100644
--- a/src/d/actor/d_a_e_mb.cpp
+++ b/src/d/actor/d_a_e_mb.cpp
@@ -105,7 +105,7 @@ static int daE_MB_Draw(e_mb_class* i_this) {
i_this->mRopeMat.update(16, l_color, &a_this->tevStr);
dComIfGd_set3DlineMat(&i_this->mRopeMat);
#if TARGET_PC
- if (dusk::getSettings().game.enableFrameInterpolation) {
+ if (dusk::frame_interp::is_enabled()) {
if (i_this->mRopeInterpCurrValid) {
memcpy(i_this->mRopeInterpPrev, i_this->mRopeInterpCurr, sizeof(i_this->mRopeInterpCurr));
i_this->mRopeInterpPrevValid = true;
diff --git a/src/d/actor/d_a_e_mk.cpp b/src/d/actor/d_a_e_mk.cpp
index c3a684ea8e..8099419410 100644
--- a/src/d/actor/d_a_e_mk.cpp
+++ b/src/d/actor/d_a_e_mk.cpp
@@ -157,6 +157,21 @@ static void* s_h_sub(void* i_actor, void* i_data) {
return NULL;
}
+#if TARGET_PC
+static void sort_target_info_by_id() {
+ for (int i = 1; i < target_info_count; i++) {
+ void* key = target_info[i];
+ fpc_ProcID key_id = fopAcM_GetID(key);
+ int j = i - 1;
+ while (j >= 0 && fopAcM_GetID(target_info[j]) > key_id) {
+ target_info[j + 1] = target_info[j];
+ j--;
+ }
+ target_info[j + 1] = key;
+ }
+}
+#endif
+
static daPillar_c* search_hasira(e_mk_class* i_this) {
fopEn_enemy_c* actor = (fopEn_enemy_c*)&i_this->actor;
daPillar_c* pillar_p;
@@ -170,6 +185,9 @@ static daPillar_c* search_hasira(e_mk_class* i_this) {
if (i_this->firstHasiraFlag == 0) {
i_this->firstHasiraFlag++;
+#if TARGET_PC
+ sort_target_info_by_id();
+#endif
return (daPillar_c*)target_info[TREG_S(7) + 5];
}
diff --git a/src/d/actor/d_a_e_s1.cpp b/src/d/actor/d_a_e_s1.cpp
index a5a05fce20..c4455f02d1 100644
--- a/src/d/actor/d_a_e_s1.cpp
+++ b/src/d/actor/d_a_e_s1.cpp
@@ -117,6 +117,13 @@ static void daE_S1_interp_callback(bool isSimFrame, void* pUserWork) {
dst[i] = p0 + (p1 - p0) * alpha;
}
}
+ GXColor line_color;
+ line_color.r = JREG_S(0) + 5;
+ line_color.g = JREG_S(1) + 10;
+ line_color.b = JREG_S(2) + 10;
+ line_color.a = 0xFF;
+
+ i_this->mLineMat.update(16, line_color, &i_this->tevStr);
}
#endif
@@ -154,7 +161,7 @@ static int daE_S1_Draw(e_s1_class* i_this) {
dComIfGd_set3DlineMatDark(&i_this->mLineMat);
#if TARGET_PC
- if (dusk::getSettings().game.enableFrameInterpolation) {
+ if (dusk::frame_interp::is_enabled()) {
if (i_this->mHairInterpCurrValid) {
memcpy(i_this->mHairInterpPrev, i_this->mHairInterpCurr, sizeof(i_this->mHairInterpCurr));
i_this->mHairInterpPrevValid = true;
diff --git a/src/d/actor/d_a_e_wb.cpp b/src/d/actor/d_a_e_wb.cpp
index 47004737cb..a353ea3e87 100644
--- a/src/d/actor/d_a_e_wb.cpp
+++ b/src/d/actor/d_a_e_wb.cpp
@@ -535,7 +535,7 @@ static int daE_WB_Draw(e_wb_class* i_this) {
i_this->himo_tex.update(2, l_color, &actor->tevStr);
dComIfGd_set3DlineMat(&i_this->himo_tex);
#if TARGET_PC
- if (dusk::getSettings().game.enableFrameInterpolation) {
+ if (dusk::frame_interp::is_enabled()) {
if (i_this->himo_interp_curr_valid) {
memcpy(i_this->himo_mat_interp_prev, i_this->himo_mat_interp_curr, sizeof(i_this->himo_mat_interp_curr));
memcpy(i_this->himo_tex_interp_prev, i_this->himo_tex_interp_curr, sizeof(i_this->himo_tex_interp_curr));
diff --git a/src/d/actor/d_a_e_yd.cpp b/src/d/actor/d_a_e_yd.cpp
index 18809e05ea..a10f47240c 100644
--- a/src/d/actor/d_a_e_yd.cpp
+++ b/src/d/actor/d_a_e_yd.cpp
@@ -107,7 +107,7 @@ static s32 daE_YD_Draw(e_yd_class* i_this) {
i_this->mLineMat.update(12, l_color, &i_this->actor.tevStr);
dComIfGd_set3DlineMat(&i_this->mLineMat);
#if TARGET_PC
- if (dusk::getSettings().game.enableFrameInterpolation) {
+ if (dusk::frame_interp::is_enabled()) {
if (i_this->mLineMatInterpCurrValid) {
memcpy(i_this->mLineMatInterpPrev, i_this->mLineMatInterpCurr, sizeof(i_this->mLineMatInterpCurr));
i_this->mLineMatInterpPrevValid = true;
diff --git a/src/d/actor/d_a_e_yg.cpp b/src/d/actor/d_a_e_yg.cpp
index 44a8aee249..9eae74b1af 100644
--- a/src/d/actor/d_a_e_yg.cpp
+++ b/src/d/actor/d_a_e_yg.cpp
@@ -139,6 +139,7 @@ static BOOL pl_check(e_yg_class* i_this, f32 i_dist) {
#if TARGET_PC
static void daE_YG_interp_callback(bool isSimFrame, void* pUserWork) {
e_yg_class* i_this = (e_yg_class*)pUserWork;
+ fopAc_ac_c* actor = (fopAc_ac_c*)&i_this->actor;
if (!i_this->mTentacleInterpPrevValid || !i_this->mTentacleInterpCurrValid) {
return;
}
@@ -152,6 +153,13 @@ static void daE_YG_interp_callback(bool isSimFrame, void* pUserWork) {
dst[i] = p0 + (p1 - p0) * alpha;
}
}
+ GXColor color;
+ color.r = JREG_S(0) + 20;
+ color.g = JREG_S(1) + 20;
+ color.b = JREG_S(2) + 20;
+ color.a = 0xFF;
+
+ i_this->mLineMat.update(10, color, &actor->tevStr);
}
#endif
@@ -183,7 +191,7 @@ static int daE_YG_Draw(e_yg_class* i_this) {
dComIfGd_set3DlineMatDark(&i_this->mLineMat);
#if TARGET_PC
- if (dusk::getSettings().game.enableFrameInterpolation) {
+ if (dusk::frame_interp::is_enabled()) {
if (i_this->mTentacleInterpCurrValid) {
memcpy(i_this->mTentacleInterpPrev, i_this->mTentacleInterpCurr, sizeof(i_this->mTentacleInterpCurr));
i_this->mTentacleInterpPrevValid = true;
diff --git a/src/d/actor/d_a_e_yh.cpp b/src/d/actor/d_a_e_yh.cpp
index cf9955a7db..bf71e18818 100644
--- a/src/d/actor/d_a_e_yh.cpp
+++ b/src/d/actor/d_a_e_yh.cpp
@@ -135,7 +135,7 @@ static int daE_YH_Draw(e_yh_class* i_this) {
i_this->mLine.update(12, l_color, &a_this->tevStr);
dComIfGd_set3DlineMat(&i_this->mLine);
#if TARGET_PC
- if (dusk::getSettings().game.enableFrameInterpolation) {
+ if (dusk::frame_interp::is_enabled()) {
if (i_this->mLineInterpCurrValid) {
memcpy(i_this->mLineInterpPrev, i_this->mLineInterpCurr, sizeof(i_this->mLineInterpCurr));
i_this->mLineInterpPrevValid = true;
diff --git a/src/d/actor/d_a_horse.cpp b/src/d/actor/d_a_horse.cpp
index 16790d42ff..42f2c9b8ce 100644
--- a/src/d/actor/d_a_horse.cpp
+++ b/src/d/actor/d_a_horse.cpp
@@ -3165,7 +3165,7 @@ void daHorse_c::setReinPosNormalSubstance() {
#if TARGET_PC
void daHorse_c::lerpControlPoints(f32 alpha) {
// FRAME INTERP NOTE: Currently only lerping points for Epona's reins. Need a more global solution.
- if (!dusk::getSettings().game.enableFrameInterpolation || !s_horseReinSimPrevValid || !s_horseReinSimCurrValid) {
+ if (!dusk::frame_interp::is_enabled() || !s_horseReinSimPrevValid || !s_horseReinSimCurrValid) {
return;
}
const int nCurr = s_horseReinSimNumCurr;
diff --git a/src/d/actor/d_a_kago.cpp b/src/d/actor/d_a_kago.cpp
index 9444237f12..efdad44516 100644
--- a/src/d/actor/d_a_kago.cpp
+++ b/src/d/actor/d_a_kago.cpp
@@ -3530,6 +3530,15 @@ void daKago_c::action() {
#endif
mStickY = mDoCPd_c::getStickY(PAD_1);
+#ifdef TARGET_PC
+ if(dusk::getSettings().game.invertAirSwimX) {
+ mStickX = -mStickX;
+ }
+ if(dusk::getSettings().game.invertAirSwimY) {
+ mStickY = -mStickY;
+ }
+#endif
+
u8 prevIsWaterfall = mIsWaterfall;
mIsWaterfall = FALSE;
fpcM_Search(s_waterfall, this);
diff --git a/src/d/actor/d_a_mg_rod.cpp b/src/d/actor/d_a_mg_rod.cpp
index 956a9e3cff..3471cd342a 100644
--- a/src/d/actor/d_a_mg_rod.cpp
+++ b/src/d/actor/d_a_mg_rod.cpp
@@ -25,7 +25,10 @@
#include
#include
+#if TARGET_PC
+#include "dusk/settings.h"
#include "dusk/version.hpp"
+#endif
class dmg_rod_HIO_c : public JORReflexible {
public:
@@ -1137,8 +1140,14 @@ static int lure_standby(dmg_rod_class* i_this) {
dComIfGp_setDoStatusForce(42, 0);
}
- i_this->rod_stick_x = mDoCPd_c::getStickX3D(PAD_1) * mDoCPd_c::getStickX3D(PAD_1);
- if (mDoCPd_c::getStickX3D(PAD_1) < 0.0f) {
+ f32 stick_x = mDoCPd_c::getStickX3D(PAD_1);
+#if TARGET_PC
+ if (dusk::getSettings().game.enableMirrorMode) {
+ stick_x = -stick_x;
+ }
+#endif
+ i_this->rod_stick_x = stick_x * stick_x;
+ if (stick_x < 0.0f) {
i_this->rod_stick_x *= -1.0f;
}
@@ -3671,7 +3680,13 @@ static void uki_standby(dmg_rod_class* i_this) {
cLib_addCalc2(&i_this->field_0x150c, substickX, 0.5f, 0.2f);
if (i_this->field_0x1508 > 0.3f && i_this->play_cam_mode < 5) {
- ANGLE_ADD(i_this->field_0x1418, (-500.0f + VREG_F(3)) * mDoCPd_c::getStickX3D(PAD_1));
+ f32 stick_x = mDoCPd_c::getStickX3D(PAD_1);
+#if TARGET_PC
+ if (dusk::getSettings().game.enableMirrorMode) {
+ stick_x = -stick_x;
+ }
+#endif
+ ANGLE_ADD(i_this->field_0x1418, (-500.0f + VREG_F(3)) * stick_x);
}
cMtx_YrotS(*calc_mtx, i_this->field_0x1418);
@@ -5043,8 +5058,15 @@ static void play_camera(dmg_rod_class* i_this) {
static f32 old_stick_x = 0.0f;
static f32 old_stick_sx = 0.0f;
+ f32 stick_x = mDoCPd_c::getStickX3D(PAD_1);
+#if TARGET_PC
+ if (dusk::getSettings().game.enableMirrorMode) {
+ stick_x = -stick_x;
+ }
+#endif
+
if (
- (mDoCPd_c::getStickX3D(PAD_1) >= 0.8f && old_stick_x < 0.8f) || (mDoCPd_c::getStickX3D(PAD_1) <= -0.8f && old_stick_x > -0.8f)
+ (stick_x >= 0.8f && old_stick_x < 0.8f) || (stick_x <= -0.8f && old_stick_x > -0.8f)
#if VERSION != VERSION_SHIELD_DEBUG
|| (mDoCPd_c::getSubStickX3D(PAD_1) >= 0.8f && old_stick_sx < 0.8f) || (mDoCPd_c::getSubStickX3D(PAD_1) <= -0.8f && old_stick_sx > -0.8f)
#endif
@@ -5060,7 +5082,7 @@ static void play_camera(dmg_rod_class* i_this) {
}
if (i_this->play_cam_timer >= 15) {
- if (mDoCPd_c::getStickX3D(PAD_1) >= 0.5f
+ if (stick_x >= 0.5f
#if VERSION != VERSION_SHIELD_DEBUG
|| mDoCPd_c::getSubStickX3D(PAD_1) >= 0.5f
#endif
@@ -5082,8 +5104,8 @@ static void play_camera(dmg_rod_class* i_this) {
}
}
- old_stick_x = mDoCPd_c::getStickX3D(PAD_1);
- old_stick_sx = mDoCPd_c::getSubStickX(PAD_1);
+ old_stick_x = stick_x;
+ old_stick_sx = mDoCPd_c::getSubStickX3D(PAD_1);
if (i_this->play_cam_timer == 1) {
if (i_this->field_0xf81 == 0) {
@@ -5788,7 +5810,14 @@ static int dmg_rod_Execute(dmg_rod_class* i_this) {
i_this->rod_stick_x = mDoCPd_c::getStickX3D(PAD_1);
i_this->rod_stick_y = mDoCPd_c::getStickY(PAD_1);
+#if TARGET_PC
+ if (dusk::getSettings().game.enableMirrorMode) {
+ i_this->rod_stick_x = -i_this->rod_stick_x;
+ }
+ i_this->rod_substick_x = mDoCPd_c::getSubStickX3D(PAD_1);
+#else
i_this->rod_substick_x = mDoCPd_c::getSubStickX(PAD_1);
+#endif
i_this->prev_rod_substick_y = i_this->rod_substick_y;
i_this->rod_substick_y = mDoCPd_c::getSubStickY(PAD_1);
diff --git a/src/d/actor/d_a_movie_player.cpp b/src/d/actor/d_a_movie_player.cpp
index 1f8bdeecd7..1760fa713b 100644
--- a/src/d/actor/d_a_movie_player.cpp
+++ b/src/d/actor/d_a_movie_player.cpp
@@ -26,15 +26,16 @@
#include "f_op/f_op_overlap_mng.h"
+#include "JSystem/JAudio2/JASCriticalSection.h"
+
+#if TARGET_PC
#include "dusk/gx_helper.h"
#include "dusk/os.h"
#include "dusk/layout.hpp"
-
-#include "JSystem/JAudio2/JASCriticalSection.h"
-
#if MOVIE_SUPPORT
#include "turbojpeg.h"
#endif
+#endif
inline s32 daMP_NEXT_READ_SIZE(daMP_THPReadBuffer* readBuf) {
return *(BE(s32)*)readBuf->ptr;
@@ -3912,13 +3913,20 @@ static BOOL daMP_ProperTimingForGettingNextFrame() {
return TRUE;
}
} else {
- s32 frameRate = daMP_ActivePlayer.header.frameRate * 100.0f;
#if TARGET_PC
- // DUSK HACK: We only fire retrace callbacks *half* as often as the game expects,
- // because we only run them once per frame, and normally there should be two scans
- // per game frame.
- frameRate *= 2;
-#endif
+ const f32 fps = daMP_ActivePlayer.header.frameRate;
+ if (fps > 0.0f) {
+ const f32 elapsed = std::chrono::duration(
+ std::chrono::steady_clock::now() - daMP_ActivePlayer.thpPlaybackClock).count();
+ const s32 desired = static_cast(elapsed * fps);
+ if (desired != daMP_ActivePlayer.prevCount) {
+ daMP_ActivePlayer.prevCount = desired;
+ daMP_ActivePlayer.curCount = desired;
+ return TRUE;
+ }
+ }
+#else
+ s32 frameRate = daMP_ActivePlayer.header.frameRate * 100.0f;
if (VIGetTvFormat() == VI_PAL) {
daMP_ActivePlayer.curCount = daMP_ActivePlayer.retaceCount * frameRate / 5000;
} else {
@@ -3929,6 +3937,7 @@ static BOOL daMP_ProperTimingForGettingNextFrame() {
daMP_ActivePlayer.prevCount = daMP_ActivePlayer.curCount;
return TRUE;
}
+#endif
}
return FALSE;
@@ -4133,6 +4142,9 @@ static BOOL daMP_THPPlayerPlay() {
daMP_ActivePlayer.prevCount = 0;
daMP_ActivePlayer.curCount = 0;
daMP_ActivePlayer.retaceCount = -1;
+#if TARGET_PC
+ daMP_ActivePlayer.thpPlaybackClock = std::chrono::steady_clock::now();
+#endif
return TRUE;
}
@@ -4482,7 +4494,7 @@ int daMP_c::daMP_c_Init() {
JUT_ASSERT(9507, 0 <= movieNo && movieNo <= 99);
char path[32];
- sprintf(path, "/Movie/demo_movie%02d_%02d.thp", demoNo, movieNo);
+ SAFE_SPRINTF(path, "/Movie/demo_movie%02d_%02d.thp", demoNo, movieNo);
if (!daMP_ActivePlayer_Init(path)) {
daMP_Fail_alloc = TRUE;
diff --git a/src/d/actor/d_a_ni.cpp b/src/d/actor/d_a_ni.cpp
index 8d97925078..b569b28e04 100644
--- a/src/d/actor/d_a_ni.cpp
+++ b/src/d/actor/d_a_ni.cpp
@@ -943,6 +943,11 @@ static int ni_play(ni_class* i_this) {
s16 var_r28 = 0x4000;
i_this->mPadMainStickX = mDoCPd_c::getStickX3D(PAD_1);
+#if TARGET_PC
+ if (dusk::getSettings().game.enableMirrorMode) {
+ i_this->mPadMainStickX = -i_this->mPadMainStickX;
+ }
+#endif
i_this->mPadMainStickY = mDoCPd_c::getStickY(PAD_1);
i_this->mPadSubStickY = mDoCPd_c::getSubStickY(PAD_1);
i_this->mPadSubStickX = mDoCPd_c::getSubStickX(PAD_1);
diff --git a/src/d/actor/d_a_npc_hanjo.cpp b/src/d/actor/d_a_npc_hanjo.cpp
index ef5d1671d0..175bee3d1e 100644
--- a/src/d/actor/d_a_npc_hanjo.cpp
+++ b/src/d/actor/d_a_npc_hanjo.cpp
@@ -15,6 +15,8 @@
#include "Z2AudioLib/Z2Instances.h"
#include
+#include "dusk/string.hpp"
+
static int l_bmdData[4][2] = {
{14, 1}, {26, 2},
{25, 2}, {3, 4},
@@ -1336,8 +1338,8 @@ int daNpc_Hanjo_c::cutAppearHawker(int param_1) {
home.angle.y += 0x8000;
setAngle(home.angle.y);
initTalk(0xcf, NULL);
- strcpy(acStack_98, l_evtList[9].eventName);
- strcat(acStack_98, "@");
+ SAFE_STRCPY(acStack_98, l_evtList[9].eventName);
+ SAFE_STRCAT(acStack_98, "@");
dComIfGp_getEvent()->setSkipZev(this, acStack_98);
dComIfGp_getEvent()->onSkipFade();
dComIfGp_getVibration().StartShock( 9, 15, cXyz(0.0f, 1.0f, 0.0f));
diff --git a/src/d/actor/d_a_npc_saru.cpp b/src/d/actor/d_a_npc_saru.cpp
index 500daea704..366ed865a8 100644
--- a/src/d/actor/d_a_npc_saru.cpp
+++ b/src/d/actor/d_a_npc_saru.cpp
@@ -11,6 +11,8 @@
#include "d/actor/d_a_e_ym.h"
#include
+#include "dusk/string.hpp"
+
enum saru_TW_RES_File_ID {
/* BMDR */
/* 0x4 */ BMDR_SARU_BARA_TW = 0x4,
@@ -956,8 +958,8 @@ int daNpc_Saru_c::cutYmLook(int param_1) {
if (dComIfGp_getEventManager().getIsAddvance(param_1) != 0) {
switch (iVar1) {
case 0:
- strcpy(acStack_88, l_evtList[2].eventName);
- strcat(acStack_88, "@");
+ SAFE_STRCPY(acStack_88, l_evtList[2].eventName);
+ SAFE_STRCAT(acStack_88, "@");
dComIfGp_getEvent()->setSkipZev(this, acStack_88);
dComIfGp_getEvent()->onSkipFade();
field_0xfd9 = 1;
diff --git a/src/d/actor/d_a_npc_shop0.cpp b/src/d/actor/d_a_npc_shop0.cpp
index 1dd4b3e31f..6743a1b859 100644
--- a/src/d/actor/d_a_npc_shop0.cpp
+++ b/src/d/actor/d_a_npc_shop0.cpp
@@ -8,6 +8,8 @@
#include "d/actor/d_a_npc_shop0.h"
#include
+#include "dusk/string.hpp"
+
static int createHeapCallBack(fopAc_ac_c* i_this) {
return static_cast(i_this)->createHeap();
}
@@ -184,8 +186,8 @@ int daNpc_Shop0_c::init() {
static char l_fileName[21];
J3DAnmTransform* daNpc_Shop0_c::getTrnsfrmAnmP(int i_fileIndex, char** i_fileName) {
- strcpy(l_fileName, i_fileName[i_fileIndex]);
- strcat(l_fileName, ".bck");
+ SAFE_STRCPY(l_fileName, i_fileName[i_fileIndex]);
+ SAFE_STRCAT(l_fileName, ".bck");
return (J3DAnmTransform*) dComIfG_getObjectRes(getResName(), l_fileName);
}
diff --git a/src/d/actor/d_a_npc_yelia.cpp b/src/d/actor/d_a_npc_yelia.cpp
index 67b1cbcffc..80d6df02a6 100644
--- a/src/d/actor/d_a_npc_yelia.cpp
+++ b/src/d/actor/d_a_npc_yelia.cpp
@@ -9,6 +9,8 @@
#include "d/actor/d_a_demo_item.h"
#include
+#include "dusk/string.hpp"
+
static daNpc_GetParam1 l_bmdData[3] = {
{3, 1},
{3, 4},
@@ -1137,8 +1139,8 @@ BOOL daNpc_Yelia_c::cutTakeWoodStatue(int i_staffId) {
mItemId = fpcM_ERROR_PROCESS_ID_e;
mEventTimer = timer;
Z2GetAudioMgr()->muteSceneBgm(90, 0.0f);
- strcpy(name, l_evtList[EVENT_TAKE_WOODSTATUE].eventName);
- strcat(name, "@");
+ SAFE_STRCPY(name, l_evtList[EVENT_TAKE_WOODSTATUE].eventName);
+ SAFE_STRCAT(name, "@");
dComIfGp_getEvent()->setSkipZev(this, name);
dComIfGp_getEvent()->onSkipFade();
break;
diff --git a/src/d/actor/d_a_npc_ykw.cpp b/src/d/actor/d_a_npc_ykw.cpp
index e2c97df58a..468445063a 100644
--- a/src/d/actor/d_a_npc_ykw.cpp
+++ b/src/d/actor/d_a_npc_ykw.cpp
@@ -20,6 +20,8 @@
#include "m_Do/m_Do_ext.h"
#include
+#include "dusk/string.hpp"
+
#if DEBUG
class daNpc_ykW_HIO_c : public mDoHIO_entry_c {
public:
@@ -1411,11 +1413,11 @@ int daNpc_ykW_c::cutGoIntoBossRoom(int param_0) {
if (skip != 0 && (prm == 0 || prm == 4)) {
if (prm == 0) {
- strcpy(unkStrBuf1, l_evtList[4].eventName);
+ SAFE_STRCPY(unkStrBuf1, l_evtList[4].eventName);
} else {
- strcpy(unkStrBuf1, l_evtList[5].eventName);
+ SAFE_STRCPY(unkStrBuf1, l_evtList[5].eventName);
}
- strcat(unkStrBuf1, "@");
+ SAFE_STRCAT(unkStrBuf1, "@");
dComIfGp_getEvent()->setSkipZev(this, unkStrBuf1);
}
}
diff --git a/src/d/actor/d_a_obj_fchain.cpp b/src/d/actor/d_a_obj_fchain.cpp
index 024b4ecf8b..acd3610b6e 100644
--- a/src/d/actor/d_a_obj_fchain.cpp
+++ b/src/d/actor/d_a_obj_fchain.cpp
@@ -325,7 +325,7 @@ int daObjFchain_c::draw() {
dComIfGd_getOpaListDark()->entryImm(&mShape, 0);
#if TARGET_PC
- if (dusk::getSettings().game.enableFrameInterpolation) {
+ if (dusk::frame_interp::is_enabled()) {
if (mChainInterpCurrValid) {
memcpy(mChainInterpPrev, mChainInterpCurr, sizeof(mChainInterpCurr));
mChainInterpPrevValid = true;
diff --git a/src/d/actor/d_a_obj_flag.cpp b/src/d/actor/d_a_obj_flag.cpp
index b3f55ff1d2..dcf0640e6b 100644
--- a/src/d/actor/d_a_obj_flag.cpp
+++ b/src/d/actor/d_a_obj_flag.cpp
@@ -192,7 +192,7 @@ inline int daObjFlag_c::createHeap() {
tmp = true;
char resName[12];
- sprintf(resName, "flag%02d.bmd", angle);
+ SAFE_SPRINTF(resName, "flag%02d.bmd", angle);
shape_angle.setall(0);
current.angle.setall(0);
diff --git a/src/d/actor/d_a_obj_flag2.cpp b/src/d/actor/d_a_obj_flag2.cpp
index 4741f4d5a3..35e0cac3bc 100644
--- a/src/d/actor/d_a_obj_flag2.cpp
+++ b/src/d/actor/d_a_obj_flag2.cpp
@@ -370,7 +370,7 @@ int daObjFlag2_c::createHeap() {
s8 flagNum = (u8)shape_angle.x;
if (mFlagValid) {
char acStack_40[16];
- sprintf(acStack_40, "flag%02d.bti", flagNum);
+ SAFE_SPRINTF(acStack_40, "flag%02d.bti", flagNum);
shape_angle.setall(0);
current.angle.setall(0);
ResTIMG* image = (ResTIMG*)dComIfG_getObjectRes(mFlagName, "flag.bti");
@@ -409,7 +409,7 @@ int daObjFlag2_c::create() {
mFlagValid = false;
} else {
mFlagValid = true;
- sprintf(mFlagName, "FlagObj%02d", flagNum);
+ SAFE_SPRINTF(mFlagName, "FlagObj%02d", flagNum);
int rv = dComIfG_resLoad(&mFlagPhase, mFlagName);
if (rv != cPhs_COMPLEATE_e) {
return rv;
diff --git a/src/d/actor/d_a_obj_flag3.cpp b/src/d/actor/d_a_obj_flag3.cpp
index fc696db1ab..501cb792f6 100644
--- a/src/d/actor/d_a_obj_flag3.cpp
+++ b/src/d/actor/d_a_obj_flag3.cpp
@@ -299,7 +299,7 @@ int daObjFlag3_c::createHeap() {
s8 flagNum = (u8)shape_angle.x;
if (mFlagValid) {
char acStack_40[16];
- sprintf(acStack_40, "flag%02d.bti", flagNum);
+ SAFE_SPRINTF(acStack_40, "flag%02d.bti", flagNum);
shape_angle.setall(0);
current.angle.setall(0);
ResTIMG* image = (ResTIMG*)dComIfG_getObjectRes(mFlagName, "flag.bti");
@@ -486,7 +486,7 @@ int daObjFlag3_c::create() {
mFlagValid = false;
} else {
mFlagValid = true;
- sprintf(mFlagName, "FlagObj%02d", flagNum);
+ SAFE_SPRINTF(mFlagName, "FlagObj%02d", flagNum);
int rv = dComIfG_resLoad(&mFlagPhase, mFlagName);
if (rv != cPhs_COMPLEATE_e) {
return rv;
diff --git a/src/d/actor/d_a_obj_gra2.cpp b/src/d/actor/d_a_obj_gra2.cpp
index 550b680e06..ff52818c42 100644
--- a/src/d/actor/d_a_obj_gra2.cpp
+++ b/src/d/actor/d_a_obj_gra2.cpp
@@ -5,13 +5,14 @@
#include "d/dolzel_rel.h" // IWYU pragma: keep
-#include "d/actor/d_a_obj_gra2.h"
#include "d/actor/d_a_npc4.h"
+#include "d/actor/d_a_obj_gra2.h"
#include "d/actor/d_a_tag_gra.h"
#include "d/d_bg_w.h"
#include "d/d_cc_uty.h"
-#include "d/d_com_inf_game.h"
#include "d/d_com_inf_actor.h"
+#include "d/d_com_inf_game.h"
+#include "dusk/string.hpp"
#if DEBUG
#include "d/d_debug_viewer.h"
#endif
@@ -539,7 +540,7 @@ const char* daObj_GrA_c::getResName() {
u8 daObj_GrA_c::getMode() {
u32 uVar1 = fopAcM_GetParam(this) >> 28 & 3;
- strcpy(field_0x744, "Obj_grA");
+ SAFE_STRCPY(field_0x744, "Obj_grA");
switch (uVar1) {
case 1:
diff --git a/src/d/actor/d_a_obj_item.cpp b/src/d/actor/d_a_obj_item.cpp
index e45de1933d..2c95c040be 100644
--- a/src/d/actor/d_a_obj_item.cpp
+++ b/src/d/actor/d_a_obj_item.cpp
@@ -268,6 +268,11 @@ int daItem_c::_daItem_create() {
}
m_itemNo = daItem_prm::getItemNo(this);
+#if TARGET_PC
+ if (dusk::getSettings().game.noHeartDrops && isHeart(m_itemNo)) {
+ return cPhs_ERROR_e;
+ }
+#endif
BOOL flag = dItem_data::chkFlag(m_itemNo, 2);
#if DEBUG
diff --git a/src/d/actor/d_a_obj_klift00.cpp b/src/d/actor/d_a_obj_klift00.cpp
index e44cce7467..c7cede3b0e 100644
--- a/src/d/actor/d_a_obj_klift00.cpp
+++ b/src/d/actor/d_a_obj_klift00.cpp
@@ -493,7 +493,7 @@ int daObjKLift00_c::Draw() {
dComIfGd_setList();
#if TARGET_PC
- if (dusk::getSettings().game.enableFrameInterpolation) {
+ if (dusk::frame_interp::is_enabled()) {
if (mChainInterpCurrValid) {
memcpy(mChainInterpPrev, mChainInterpCurr, mNumChains * sizeof(cXyz));
mChainInterpPrevValid = true;
diff --git a/src/d/actor/d_a_obj_sekizoa.cpp b/src/d/actor/d_a_obj_sekizoa.cpp
index 19f4446b87..ac0ca0d5b1 100644
--- a/src/d/actor/d_a_obj_sekizoa.cpp
+++ b/src/d/actor/d_a_obj_sekizoa.cpp
@@ -8,6 +8,8 @@
#include "d/actor/d_a_tag_kmsg.h"
#include
#include
+
+#include "dusk/string.hpp"
#include "f_op/f_op_actor_mng.h"
#include "f_op/f_op_msg.h"
@@ -1364,8 +1366,8 @@ int daObj_Sekizoa_c::cutStart(int i_staffIdx) {
daObj_SMTile_c* actor_4 = (daObj_SMTile_c*)mActorMngrs[4].getActorP();
actor_4->reset();
dComIfGp_getEvent()->setPt2(actor_4);
- strcpy(acStack_90, l_evtList[2].eventName);
- strcat(acStack_90, "@");
+ SAFE_STRCPY(acStack_90, l_evtList[2].eventName);
+ SAFE_STRCAT(acStack_90, "@");
dComIfGp_getEvent()->setSkipZev(this, acStack_90);
dComIfGp_getEvent()->onSkipFade();
if (daNpcT_getPlayerInfoFromPlayerList(1, fopAcM_GetRoomNo(this), &c_stack_9c,
@@ -1856,8 +1858,8 @@ int daObj_Sekizoa_c::cutGoal(int i_staffIdx) {
switch (prm) {
case 0:
if (mType == TYPE_0) {
- strcpy(acStack_9c, l_evtList[6].eventName);
- strcat(acStack_9c, "@");
+ SAFE_STRCPY(acStack_9c, l_evtList[6].eventName);
+ SAFE_STRCAT(acStack_9c, "@");
dComIfGp_getEvent()->setSkipZev(this, acStack_9c);
dComIfGp_getEvent()->onSkipFade();
}
@@ -2222,8 +2224,8 @@ int daObj_Sekizoa_c::cutExtinction(int i_staffIdx) {
cStack_b0 += actor_0->current.pos;
daPy_getPlayerActorClass()->setPlayerPosAndAngle(&cStack_b0,
actor_0->shape_angle.y - -0x8000, 0);
- strcpy(acStack_a4, l_evtList[9].eventName);
- strcat(acStack_a4, "@");
+ SAFE_STRCPY(acStack_a4, l_evtList[9].eventName);
+ SAFE_STRCAT(acStack_a4, "@");
dComIfGp_getEvent()->setSkipZev(actor_0, acStack_a4);
dComIfGp_getEvent()->onSkipFade();
actor_0->pullMasterSword();
diff --git a/src/d/actor/d_a_set_bgobj.cpp b/src/d/actor/d_a_set_bgobj.cpp
index 792f14840a..f898f34ffb 100644
--- a/src/d/actor/d_a_set_bgobj.cpp
+++ b/src/d/actor/d_a_set_bgobj.cpp
@@ -26,7 +26,7 @@ int daSetBgObj_c::CreateInit() {
int daSetBgObj_c::create() {
fopAcM_ct(this, daSetBgObj_c);
- sprintf(mArcName, "%s", getArcName(this));
+ SAFE_SPRINTF(mArcName, "%s", getArcName(this));
int phase = dComIfG_resLoad(&mPhase, mArcName);
if (phase == cPhs_COMPLEATE_e) {
diff --git a/src/d/actor/d_a_tag_evt.cpp b/src/d/actor/d_a_tag_evt.cpp
index 8dc5954ef0..e68c980b23 100644
--- a/src/d/actor/d_a_tag_evt.cpp
+++ b/src/d/actor/d_a_tag_evt.cpp
@@ -8,6 +8,8 @@
#include "f_op/f_op_actor_mng.h"
#include
+#include "dusk/string.hpp"
+
static char* l_evtNameList[] = {
NULL,
"JUMP_DEMOSTAGE",
@@ -26,7 +28,7 @@ int daTag_Evt_c::create() {
cPhs_Step phase = dComIfG_resLoad(&mPhase, l_resFileName);
if (phase == cPhs_COMPLEATE_e) {
eventInfo.setArchiveName(l_resFileName);
- strcpy(field_0x568, "TagEvt");
+ SAFE_STRCPY(field_0x568, "TagEvt");
getParam();
field_0x572 = -1;
}
diff --git a/src/d/actor/d_a_tag_msg.cpp b/src/d/actor/d_a_tag_msg.cpp
index 6e052f74ea..55b135964a 100644
--- a/src/d/actor/d_a_tag_msg.cpp
+++ b/src/d/actor/d_a_tag_msg.cpp
@@ -11,6 +11,8 @@
#include "d/d_debug_viewer.h"
#include
+#include "dusk/string.hpp"
+
static int createHeapCallBack(fopAc_ac_c* i_this) {
daTag_Msg_c* msg = (daTag_Msg_c*)i_this;
return msg->createHeap();
@@ -219,7 +221,7 @@ void daTag_Msg_c::getParam() {
scale.x *= 100.0f;
scale.y *= 100.0f;
- strcpy(mStaffName, "Tag_ms");
+ SAFE_STRCPY(mStaffName, "Tag_ms");
}
char* daTag_Msg_c::mEvtCutTBL[2] = {
diff --git a/src/d/actor/d_a_title.cpp b/src/d/actor/d_a_title.cpp
index a75a96cb2e..cfe4003158 100644
--- a/src/d/actor/d_a_title.cpp
+++ b/src/d/actor/d_a_title.cpp
@@ -170,7 +170,7 @@ int daTitle_c::Execute() {
}
#ifdef TARGET_PC
- if (!dusk::getSettings().game.enableFrameInterpolation) {
+ if (!dusk::frame_interp::is_enabled()) {
#endif
dMenu_Collect3D_c::setViewPortOffsetY(0.0f);
#ifdef TARGET_PC
@@ -250,7 +250,7 @@ void daTitle_c::loadWait_proc() {
text[i]->setFont(mpFont);
text[i]->setString(0x80, "");
- char* msg = text[i]->getStringPtr();
+ TEXT_SPAN msg = text[i]->getStringPtr();
fopMsgM_messageGet(msg, 100);
}
@@ -354,7 +354,7 @@ void daTitle_c::fastLogoDispInit() {
mProcID = 5;
#ifdef TARGET_PC
- if (dusk::getSettings().game.enableFrameInterpolation) {
+ if (dusk::frame_interp::is_enabled()) {
dusk::frame_interp::request_presentation_sync();
}
#endif
diff --git a/src/d/d_bg_parts.cpp b/src/d/d_bg_parts.cpp
index 3c378bf325..9dc7be181d 100644
--- a/src/d/d_bg_parts.cpp
+++ b/src/d/d_bg_parts.cpp
@@ -8,6 +8,8 @@
#include "JSystem/JKernel/JKRSolidHeap.h"
#include
+#include "dusk/string.hpp"
+
void dBgp_c::material_c::draw() {
material_c* material = this;
do {
@@ -255,7 +257,7 @@ void dBgp_c::share_c::reset() {
const char* dBgp_c::share_c::getArcName() {
static char arcName[8];
- sprintf(arcName, "@mt%04x", mId);
+ SAFE_SPRINTF(arcName, "@mt%04x", mId);
return arcName;
}
@@ -430,7 +432,7 @@ dBgp_c::packet_c::packet_c() {
void dBgp_c::create(s8 i_roomNo, void* i_data) {
mPointer = i_data;
mPacket.setRoomNo(i_roomNo);
- strcpy(mArcName, dComIfG_getRoomArcName(i_roomNo));
+ SAFE_STRCPY(mArcName, dComIfG_getRoomArcName(i_roomNo));
if (mPointer != NULL) {
JKRExpHeap* block = dStage_roomControl_c::getMemoryBlock(i_roomNo);
@@ -457,7 +459,7 @@ void dBgp_c::create(s8 i_roomNo, void* i_data) {
unit_group_class* unitGroup = mapUnit->groups;
for (int i = 0; i < mapUnit->num; i++) {
char resName[16];
- sprintf(resName, "bp%04d.dzb", i);
+ SAFE_SPRINTF(resName, "bp%04d.dzb", i);
cBgD_t* dzb = (cBgD_t*)dComIfG_getStageRes(mArcName, resName);
if (dzb != NULL) {
@@ -534,7 +536,7 @@ int dBgp_c::remove() {
const char* dBgp_c::getArcName(u16 i_id, u16 i_arg) {
static char arcName[8];
- sprintf(arcName, "@%03x%03x", i_id, i_arg);
+ SAFE_SPRINTF(arcName, "@%03x%03x", i_id, i_arg);
return arcName;
}
diff --git a/src/d/d_bright_check.cpp b/src/d/d_bright_check.cpp
index fc6924c9e7..ccb04c69e5 100644
--- a/src/d/d_bright_check.cpp
+++ b/src/d/d_bright_check.cpp
@@ -143,13 +143,12 @@ void dBrightCheck_c::modeMove() {
if (mDoCPd_c::getTrigA(PAD_1) || mDoCPd_c::getTrigStart(PAD_1)) {
mDoAud_seStart(Z2SE_ENTER_GAME, NULL, 0, 0);
#ifdef TARGET_PC
- dusk::speedrun::start();
-
if (dusk::getSettings().game.speedrunMode && !dusk::getSettings().game.hideTvSettingsScreen) {
// start a new run if a run isn't already in progress
if (!dusk::m_speedrunInfo.m_isRunStarted) {
dusk::resetForSpeedrunMode();
dusk::m_speedrunInfo.startRun();
+ dusk::speedrun::start();
}
}
diff --git a/src/d/d_camera.cpp b/src/d/d_camera.cpp
index bfc4c809c9..0de75747f2 100644
--- a/src/d/d_camera.cpp
+++ b/src/d/d_camera.cpp
@@ -10431,7 +10431,7 @@ bool dCamera_c::eventCamera(s32 param_0) {
#endif
#if TARGET_PC
- if (dusk::getSettings().game.enableFrameInterpolation) {
+ if (dusk::frame_interp::is_enabled()) {
switch (var_r29) {
case 3:
case 4:
@@ -11322,7 +11322,7 @@ static int camera_execute(camera_process_class* i_this) {
#ifdef TARGET_PC
widezoom_correction(i_this, i_this->mCamera.TrimHeight());
- if (dusk::getSettings().game.enableFrameInterpolation) {
+ if (dusk::frame_interp::is_enabled()) {
dusk::frame_interp::add_interpolation_callback([](bool _, void* pUserWork) {
const auto i_this = static_cast(pUserWork);
const auto camera = &i_this->mCamera;
diff --git a/src/d/d_cc_uty.cpp b/src/d/d_cc_uty.cpp
index 218cb362f4..91fc6677c1 100644
--- a/src/d/d_cc_uty.cpp
+++ b/src/d/d_cc_uty.cpp
@@ -16,6 +16,7 @@
#if TARGET_PC
#include "dusk/achievements.h"
#include "dusk/settings.h"
+#include "d/actor/d_a_alink.h"
#endif
static int plCutLRC[58] = {
@@ -448,6 +449,10 @@ fopAc_ac_c* cc_at_check(fopAc_ac_c* i_enemy, dCcU_AtInfo* i_AtInfo) {
#if TARGET_PC
if (fopAcM_GetGroup(i_enemy) == fopAc_ENEMY_e) {
dusk::AchievementSystem::get().signal("enemy_killed");
+ const auto* link = static_cast(daPy_getPlayerActorClass());
+ if (link != nullptr && link->mProcID == daAlink_c::PROC_CUT_FINISH && link->mIsRollstab) {
+ dusk::AchievementSystem::get().signal("rollstab_kill");
+ }
}
#endif
}
diff --git a/src/d/d_com_inf_game.cpp b/src/d/d_com_inf_game.cpp
index 7e17cb501e..93fc15ca8f 100644
--- a/src/d/d_com_inf_game.cpp
+++ b/src/d/d_com_inf_game.cpp
@@ -26,6 +26,8 @@
#include
#include
+#include "dusk/string.hpp"
+
void dComIfG_play_c::ct() {
mWindowNum = 0;
mParticle = NULL;
@@ -2649,7 +2651,7 @@ static void dComIfGs_setWarpItemData(int param_0, char const* i_stage, cXyz i_po
void dComIfG_play_c::setWarpItemData(char const* i_stage, cXyz i_pos, s16 i_angle, s8 i_roomNo,
u8 param_4, u8 param_5) {
- strcpy(mItemInfo.mWarpItemData.mWarpItemStage, i_stage);
+ SAFE_STRCPY(mItemInfo.mWarpItemData.mWarpItemStage, i_stage);
mItemInfo.mWarpItemData.mWarpItemPos.set(i_pos);
mItemInfo.mWarpItemData.mWarpItemAngle = i_angle;
mItemInfo.mWarpItemData.mWarpItemRoom = i_roomNo;
@@ -2736,7 +2738,7 @@ void* dComIfG_getOldStageRes(char const* i_resName) {
char* dComIfG_getRoomArcName(int i_roomNo) {
static char buf[32];
- sprintf(buf, "R%02d_00", i_roomNo);
+ SAFE_SPRINTF(buf, "R%02d_00", i_roomNo);
return buf;
}
diff --git a/src/d/d_com_static.cpp b/src/d/d_com_static.cpp
index ee05d34170..585d39869b 100644
--- a/src/d/d_com_static.cpp
+++ b/src/d/d_com_static.cpp
@@ -351,13 +351,13 @@ const char* daSetBgObj_c::getArcName(fopAc_ac_c* i_this) {
u32 r30 = fopAcM_GetParam(i_this);
u16 r29 = fopAcM_GetParam(i_this);
- sprintf(arcName, "@bg%04x", r29);
+ SAFE_SPRINTF(arcName, "@bg%04x", r29);
if (DEBUG && r30 & 0x80000000) {
OS_REPORT("\e[43;30m旧仕様の地形ユニットMoveBGが残っています!!!\n\e[m");
u16 r28 = r30 >> 12 & 0x1FF;
u16 r27 = r30 & 0xFFF;
- sprintf(arcName, "@%03x%03x", r28, (u16)r27);
+ SAFE_SPRINTF(arcName, "@%03x%03x", r28, (u16)r27);
}
return arcName;
}
diff --git a/src/d/d_debug_camera.cpp b/src/d/d_debug_camera.cpp
index 131a2c05ae..9ff5b0fcf8 100644
--- a/src/d/d_debug_camera.cpp
+++ b/src/d/d_debug_camera.cpp
@@ -1349,11 +1349,11 @@ void dDbgCamera_c::monitor() {
for (var_r27 = 0; var_r27 < 4; var_r27++) {
if (var_r27 == mCmdMode) {
- strcat(spC0, "____ ");
+ SAFE_STRCAT(spC0, "____ ");
break;
}
- strcat(spC0, " ");
+ SAFE_STRCAT(spC0, " ");
}
Report(pos_x, pos_y, 7, " %s", spC0);
diff --git a/src/d/d_ev_camera.cpp b/src/d/d_ev_camera.cpp
index 736f9f7a82..fad6d1a523 100644
--- a/src/d/d_ev_camera.cpp
+++ b/src/d/d_ev_camera.cpp
@@ -13,6 +13,8 @@
#include "d/actor/d_a_alink.h"
#include
+#include "dusk/string.hpp"
+
#ifdef __MWERKS__
#define LOAD_4BYTE_STRING_LITERAL(x) (*(u32*)(x))
#else
@@ -46,7 +48,7 @@ int dCamera_c::StartEventCamera(int param_0, int param_1, ...) {
for (int i = 0; i < 8; i++) {
char* param_name = va_arg(args, char*);
if (param_name != NULL) {
- strcpy(mEventData.mEventParams[i].name, param_name);
+ SAFE_STRCPY(mEventData.mEventParams[i].name, param_name);
mEventData.mEventParams[i].field_0x10 = va_arg(args, int);
mEventData.mEventParams[i].value = va_arg(args, uintptr_t);
} else {
@@ -341,18 +343,23 @@ bool dCamera_c::getEvXyzData(cXyz* i_data, char* i_event, cXyz param_2) {
return 1;
}
+#if TARGET_PC
+template
+bool dCamera_c::getEvStringData(char (&i_data)[N], char* i_event, char* param_2) {
+#else
bool dCamera_c::getEvStringData(char* i_data, char* i_event, char* param_2) {
+#endif
if (chkFlag(0x20000000)) {
int index = searchEventArgData(i_event);
if (index == -1) {
- strcpy(i_data, param_2);
+ SAFE_STRCPY(i_data, param_2);
} else {
- strcpy(i_data, (char*)mEventData.mEventParams[index].value);
+ SAFE_STRCPY(i_data, (char*)mEventData.mEventParams[index].value);
}
} else if (dComIfGp_evmng_getMySubstanceNum(mEventData.mStaffIdx, i_event) != 0) {
- strcpy(i_data, dComIfGp_evmng_getMyStringP(mEventData.mStaffIdx, i_event));
+ SAFE_STRCPY(i_data, dComIfGp_evmng_getMyStringP(mEventData.mStaffIdx, i_event));
} else {
- strcpy(i_data, param_2);
+ SAFE_STRCPY(i_data, param_2);
#if DEBUG
if (mCurCamStyleTimer == 0 && mCamSetup.CheckFlag(0x40)) {
OS_REPORT("camera: event: %16s: %s (d)\n", i_event, i_data);
@@ -369,6 +376,11 @@ bool dCamera_c::getEvStringData(char* i_data, char* i_event, char* param_2) {
return 1;
}
+#if TARGET_PC
+// Used in another TU, so force instantiation to avoid linker issues.
+template bool dCamera_c::getEvStringData(char (&i_data)[12], char* i_event, char* param_2);
+#endif
+
char* dCamera_c::getEvStringPntData(char* i_event, char* param_1) {
char* string = NULL;
@@ -520,7 +532,7 @@ bool dCamera_c::fixedFrameEvCamera() {
#if DEBUG
if (strlen(fframe_p->mRelUseMask) != 2) {
OSReport("camera: event: bad length -> xx\n");
- strcpy(fframe_p->mRelUseMask, "xx");
+ SAFE_STRCPY(fframe_p->mRelUseMask, "xx");
JUTAssertion::showAssert(JUTAssertion::getSDevice(), "d_ev_camera.cpp", 0x32e, "0");
OSPanic("d_ev_camera.cpp", 0x32e, "Halt");
}
@@ -613,7 +625,7 @@ bool dCamera_c::fixedFrameEvCamera() {
}
fframe_p->field_0x4 = relationalPos(fframe_p->mpRelActor, &sp44);
- } else if (fframe_p->mRelUseMask[1] == 116) {
+ } else if (fframe_p->mRelUseMask[1] == 't') {
fframe_p->field_0x4 = attentionPos(fframe_p->mpRelActor) + sp44;
} else {
fframe_p->field_0x4 = sp44;
@@ -866,7 +878,7 @@ bool dCamera_c::fixedPositionEvCamera() {
getEvFloatData(&fpos_p->field_0x38, "Radius", 100000.0f);
getEvFloatData(&fpos_p->field_0x34, "StartRadius", fpos_p->field_0x38);
fpos_p->field_0x1 = getEvFloatData(&fpos_p->field_0x2c, "Bank", 0.0f);
- getEvStringData(&fpos_p->field_0x48, "RelUseMask", "o");
+ getEvStringData(fpos_p->field_0x48, "RelUseMask", "o");
fpos_p->field_0x0 = getEvIntData(&fpos_p->field_0x4c, "Timer", -1);
if ((fpos_p->field_0x40 = getEvActor("Target", "@PLAYER")) == NULL) {
@@ -877,7 +889,7 @@ bool dCamera_c::fixedPositionEvCamera() {
fpos_p->field_0x44 = fopAcM_GetID(fpos_p->field_0x40);
fpos_p->field_0x3c = getEvActor("RelActor");
- if (fpos_p->field_0x3c && isRelChar(fpos_p->field_0x48)) {
+ if (fpos_p->field_0x3c && isRelChar(fpos_p->field_0x48[0])) {
fpos_p->field_0x4 = relationalPos(fpos_p->field_0x3c, &sp24);
} else {
fpos_p->field_0x4 = sp24;
@@ -1021,7 +1033,7 @@ bool dCamera_c::transEvCamera(int param_1) {
getEvIntData(&trans->mTransType, "TransType", 0);
trans->mRelActor = getEvActor("RelActor");
- getEvStringData(&trans->mRelUseMask, "RelUseMask", "--oo");
+ getEvStringData(trans->mRelUseMask, "RelUseMask", "--oo");
getEvFloatData(&trans->mCushion, "Cushion", 1.0f);
if (trans->mRelActor) {
@@ -1034,36 +1046,36 @@ bool dCamera_c::transEvCamera(int param_1) {
mAdditionVec = MidnaAdditionVec;
}
- if (trans->mRelUseMask == 119) {
+ if (trans->mRelUseMask[0] == 'w') {
trans->mStartCenter += mAdditionVec;
}
- if (trans->mRelUseMask == 87) {
+ if (trans->mRelUseMask[0] == 'W') {
trans->mStartCenter -= mAdditionVec;
}
- if (trans->field_0x49 == 119) {
+ if (trans->mRelUseMask[1] == 'w') {
trans->mStartEye += mAdditionVec;
}
- if (trans->field_0x49 == 87) {
+ if (trans->mRelUseMask[1] == 'W') {
trans->mStartEye -= mAdditionVec;
}
- if (trans->field_0x4a == 119) {
+ if (trans->mRelUseMask[2] == 'w') {
trans->mCenter += mAdditionVec;
}
- if (trans->field_0x4a == 87) {
+ if (trans->mRelUseMask[2] == 'W') {
trans->mCenter -= mAdditionVec;
}
- if (trans->field_0x4b == 119) {
+ if (trans->mRelUseMask[3] == 'w') {
trans->mEye += mAdditionVec;
}
- if (trans->field_0x4b == 87) {
+ if (trans->mRelUseMask[3] == 'W') {
trans->mEye -= mAdditionVec;
}
}
- if (trans->field_0x49 == 114) {
+ if (trans->mRelUseMask[1] == 'r') {
my_vec_0 = relationalPos(trans->mRelActor, &trans->mStartCenter);
if ((mTicks & 1) != 0) {
trans->mStartEye.x = -trans->mStartEye.x;
@@ -1075,14 +1087,14 @@ bool dCamera_c::transEvCamera(int param_1) {
}
}
- if (trans->mRelUseMask == 110 || trans->field_0x49 == 110) {
+ if (trans->mRelUseMask[0] == 'n' || trans->mRelUseMask[1] == 'n') {
cSGlobe cStack_7b8(mEye - positionOf(trans->mRelActor));
cSAngle acStack_898 = cStack_7b8.U() - directionOf(trans->mRelActor);
if (acStack_898 < cSAngle::_0) {
- if (trans->mRelUseMask == 110) {
+ if (trans->mRelUseMask[0] == 'n') {
trans->mStartCenter.x = -trans->mStartCenter.x;
}
- if (trans->field_0x49 == 110) {
+ if (trans->mRelUseMask[1] == 'n') {
trans->mStartEye.x = -trans->mStartEye.x;
}
}
@@ -1094,15 +1106,15 @@ bool dCamera_c::transEvCamera(int param_1) {
}
}
- if (trans->field_0x4a == 110 || trans->field_0x4b == 110) {
+ if (trans->mRelUseMask[2] == 'n' || trans->mRelUseMask[3] == 'n') {
cSGlobe cStack_7c0(mEye - positionOf(trans->mRelActor));
cSAngle acStack_89c = cStack_7c0.U() - directionOf(trans->mRelActor);
if (acStack_89c < cSAngle::_0) {
- if (trans->field_0x4a == 110) {
+ if (trans->mRelUseMask[2] == 'n') {
trans->mCenter.x = -trans->mCenter.x;
}
- if (trans->field_0x4b == 110) {
+ if (trans->mRelUseMask[3] == 'n') {
trans->mEye.x = -trans->mEye.x;
}
}
@@ -1114,15 +1126,15 @@ bool dCamera_c::transEvCamera(int param_1) {
}
}
- if (trans->mRelUseMask == 78 || trans->field_0x49 == 78) {
+ if (trans->mRelUseMask[0] == 'N' || trans->mRelUseMask[1] == 'N') {
cSGlobe cStack_7c8(mEye - positionOf(trans->mRelActor));
cSAngle acStack_8a0 = cStack_7c8.U() - directionOf(trans->mRelActor);
if (acStack_8a0 > cSAngle::_0) {
- if (trans->mRelUseMask == 78) {
+ if (trans->mRelUseMask[0] == 'N') {
trans->mStartCenter.x = -trans->mStartCenter.x;
}
- if (trans->field_0x49 == 78) {
+ if (trans->mRelUseMask[1] == 'N') {
trans->mStartEye.x = -trans->mStartEye.x;
}
}
@@ -1134,15 +1146,15 @@ bool dCamera_c::transEvCamera(int param_1) {
}
}
- if (trans->field_0x4a == 78 || trans->field_0x4b == 78) {
+ if (trans->mRelUseMask[2] == 'N' || trans->mRelUseMask[3] == 'N') {
cSGlobe cStack_7d0(mEye - positionOf(trans->mRelActor));
cSAngle acStack_8a4 = cStack_7d0.U() - directionOf(trans->mRelActor);
if (acStack_8a4 > cSAngle::_0) {
- if (trans->field_0x4a == 78) {
+ if (trans->mRelUseMask[2] == 'N') {
trans->mCenter.x = -trans->mCenter.x;
}
- if (trans->field_0x4b == 78) {
+ if (trans->mRelUseMask[3] == 'N') {
trans->mEye.x = -trans->mEye.x;
}
}
@@ -1154,21 +1166,21 @@ bool dCamera_c::transEvCamera(int param_1) {
}
}
- if (trans->mRelUseMask == 102) {
+ if (trans->mRelUseMask[0] == 'f') {
cSGlobe cStack_7d8(trans->mStartCenter);
cStack_7d8.U(directionOf(trans->mRelActor) + cStack_7d8.U());
trans->mStartCenter = attentionPos(trans->mRelActor) + cStack_7d8.Xyz();
- trans->mRelUseMask = 120;
+ trans->mRelUseMask[0] = 'x';
}
- if (trans->field_0x49 == 102) {
+ if (trans->mRelUseMask[1] == 'f') {
cSGlobe cStack_7e0(trans->mStartEye);
cStack_7e0.U(directionOf(trans->mRelActor) + cStack_7e0.U());
trans->mStartEye = attentionPos(trans->mRelActor) + cStack_7e0.Xyz();
- trans->field_0x49 = 120;
+ trans->mRelUseMask[1] = 'x';
}
- if (trans->field_0x4a == 112) {
+ if (trans->mRelUseMask[2] == 'p') {
cXyz sp114(trans->mCenter);
cXyz sp120 = relationalPos(trans->mRelActor, &sp114);
f32 fVar1 = cXyz(sp120 - positionOf(mpPlayerActor)).abs();
@@ -1178,14 +1190,14 @@ bool dCamera_c::transEvCamera(int param_1) {
if (fVar1 < fVar2) {
trans->mCenter.x = -trans->mCenter.x;
}
- } else if (trans->field_0x4a == 102) {
+ } else if (trans->mRelUseMask[2] == 'f') {
cSGlobe cStack_7e8(trans->mCenter);
cStack_7e8.U(directionOf(trans->mRelActor) + cStack_7e8.U());
trans->mCenter = attentionPos(trans->mRelActor) + cStack_7e8.Xyz();
- trans->field_0x4a = 120;
+ trans->mRelUseMask[2] = 'x';
}
- if (trans->field_0x4b == 112) {
+ if (trans->mRelUseMask[3] == 'p') {
cXyz sp12c = trans->mEye;
cXyz sp138(relationalPos(trans->mRelActor, &sp12c));
f32 fVar3 = cXyz(sp138 - positionOf(mpPlayerActor)).abs();
@@ -1195,7 +1207,7 @@ bool dCamera_c::transEvCamera(int param_1) {
if (fVar3 < fVar4) {
trans->mEye.x = -trans->mEye.x;
}
- } else if (trans->field_0x4b == 114) {
+ } else if (trans->mRelUseMask[3] == 'r') {
my_vec_0 = relationalPos(trans->mRelActor, &trans->mCenter);
if ((mTicks & 1) != 0) {
trans->mEye.x = -trans->mEye.x;
@@ -1205,19 +1217,19 @@ bool dCamera_c::transEvCamera(int param_1) {
if (lineBGCheck(&my_vec_0, &my_vec_1, 0x4007)) {
trans->mEye.x = -trans->mEye.x;
}
- } else if (trans->field_0x4b == 102) {
+ } else if (trans->mRelUseMask[3] == 'f') {
cSGlobe cStack_7f0(trans->mEye);
cStack_7f0.U(directionOf(trans->mRelActor) + cStack_7f0.U());
trans->mEye = attentionPos(trans->mRelActor) + cStack_7f0.Xyz();
- trans->field_0x4b = 120;
+ trans->mRelUseMask[3] = 'x';
}
} else {
- if (trans->field_0x4a == 97) {
+ if (trans->mRelUseMask[2] == 'a') {
cXyz cStack_320 = dCamMath::xyzRotateY(trans->mCenter, cSAngle(mViewCache.mDirection.U().Inv()));
trans->mCenter = mViewCache.mCenter + cStack_320;
}
- if (trans->field_0x4b == 97) {
+ if (trans->mRelUseMask[3] == 'a') {
cXyz cStack_32c = dCamMath::xyzRotateY(trans->mEye, cSAngle(mViewCache.mDirection.U().Inv()));
trans->mEye = mViewCache.mEye + cStack_32c;
}
@@ -1246,47 +1258,47 @@ bool dCamera_c::transEvCamera(int param_1) {
}
if (trans->mRelActor) {
- if (trans->mRelUseMask == 116) {
+ if (trans->mRelUseMask[0] == 't') {
pos.mXyz_1 = attentionPos(trans->mRelActor) + trans->mStartCenter;
- } else if (trans->mRelUseMask == 99) {
+ } else if (trans->mRelUseMask[0] == 'c') {
cSGlobe cStack_7f8(trans->mStartCenter);
cStack_7f8.U(trans->field_0x60.U() + cStack_7f8.U());
pos.mXyz_1 = attentionPos(trans->mRelActor) + cStack_7f8.Xyz();
- } else if (trans->mRelUseMask == 119 || trans->mRelUseMask == 87) {
+ } else if (trans->mRelUseMask[0] == 'w' || trans->mRelUseMask[0] == 'W') {
pos.mXyz_1 = relationalPos(trans->mRelActor, &trans->mStartCenter);
} else {
- if (isRelChar(trans->mRelUseMask)) {
+ if (isRelChar(trans->mRelUseMask[0])) {
pos.mXyz_1 = relationalPos(trans->mRelActor, &trans->mStartCenter);
} else {
pos.mXyz_1 = trans->mStartCenter;
}
}
- if (trans->field_0x49 == 116) {
+ if (trans->mRelUseMask[1] == 't') {
pos.mXyz_0 = attentionPos(trans->mRelActor) + trans->mStartEye;
- } else if (trans->field_0x49 == 99) {
+ } else if (trans->mRelUseMask[1] == 'c') {
cSGlobe cStack_800(trans->mStartEye);
cStack_800.U(trans->field_0x60.U() + cStack_800.U());
pos.mXyz_0 = attentionPos(trans->mRelActor) + cStack_800.Xyz();
- } else if (trans->field_0x49 == 119 || trans->field_0x49 == 87) {
+ } else if (trans->mRelUseMask[1] == 'w' || trans->mRelUseMask[1] == 'W') {
pos.mXyz_0 = relationalPos(trans->mRelActor, &trans->mStartEye);
} else {
- if (isRelChar(trans->field_0x49)) {
+ if (isRelChar(trans->mRelUseMask[1])) {
pos.mXyz_0 = relationalPos(trans->mRelActor, &trans->mStartEye);
} else {
pos.mXyz_0 = trans->mStartEye;
}
}
- if (trans->field_0x4a == 116) {
+ if (trans->mRelUseMask[2] == 't') {
pos2.mXyz_1 = attentionPos(trans->mRelActor) + trans->mCenter;
- } else if (trans->field_0x4a == 99) {
+ } else if (trans->mRelUseMask[2] == 'c') {
cSGlobe cStack_808(trans->mCenter);
cStack_808.U(trans->field_0x60.U() + cStack_808.U());
pos2.mXyz_1 = attentionPos(trans->mRelActor) + cStack_808.Xyz();
- } else if (trans->field_0x4a == 119 || trans->field_0x4a == 87) {
+ } else if (trans->mRelUseMask[2] == 'w' || trans->mRelUseMask[2] == 'W') {
pos2.mXyz_1 = relationalPos(trans->mRelActor, &trans->mCenter);
- } else if (isRelChar(trans->field_0x4a)) {
+ } else if (isRelChar(trans->mRelUseMask[2])) {
pos2.mXyz_1 = relationalPos(trans->mRelActor, &trans->mCenter);
} else if (trans->mTransType == 2) {
pos2.mXyz_1 = dCamMath::xyzRotateY(trans->mCenter, directionOf(trans->mRelActor));
@@ -1294,16 +1306,16 @@ bool dCamera_c::transEvCamera(int param_1) {
pos2.mXyz_1 = trans->mCenter;
}
- if (trans->field_0x4b == 116) {
+ if (trans->mRelUseMask[3] == 't') {
pos2.mXyz_0 = attentionPos(trans->mRelActor) + trans->mEye;
- } else if (trans->field_0x4b == 99) {
+ } else if (trans->mRelUseMask[3] == 'c') {
cSGlobe cStack_810(trans->mEye);
cStack_810.U(trans->field_0x60.U() + cStack_810.U());
pos2.mXyz_0 = attentionPos(trans->mRelActor) + cStack_810.Xyz();
} else {
- if (trans->field_0x4b == 119 || trans->field_0x4b == 87) {
+ if (trans->mRelUseMask[3] == 'w' || trans->mRelUseMask[3] == 'W') {
pos2.mXyz_0 = relationalPos(trans->mRelActor, &trans->mEye);
- } else if (isRelChar(trans->field_0x4b)) {
+ } else if (isRelChar(trans->mRelUseMask[3])) {
pos2.mXyz_0 = relationalPos(trans->mRelActor, &trans->mEye);
} else if (trans->mTransType == 2) {
pos2.mXyz_0 = dCamMath::xyzRotateY(trans->mEye, directionOf(trans->mRelActor));
@@ -3420,11 +3432,11 @@ bool dCamera_c::fixedFramesEvCamera() {
fframes_p->field_0x0 = getEvIntData(&fframes_p->mTimer, "Timer", const_1_val);
- getEvStringData(&fframes_p->mRelUseMask, "RelUseMask", "oo");
+ getEvStringData(fframes_p->mRelUseMask, "RelUseMask", "oo");
#if DEBUG
- if (strlen(&fframes_p->mRelUseMask) != 2) {
+ if (strlen(fframes_p->mRelUseMask) != 2) {
OSReport("camera: event: bad length -> xx\n");
- strcpy(&fframes_p->mRelUseMask, "xx");
+ SAFE_STRCPY(fframes_p->mRelUseMask, "xx");
JUTAssertion::showAssert(JUTAssertion::getSDevice(), "d_ev_camera.cpp", 0x129c, "Halt");
OSPanic("d_ev_camera.cpp", 0x129c, "Halt");
}
@@ -3442,13 +3454,13 @@ bool dCamera_c::fixedFramesEvCamera() {
sp30 = fframes_p->field_0x1c[1][iVar1];
sp3c = fframes_p->field_0x1c[0][iVar1];
- if (fframes_p->mRelActor && fframes_p->mRelUseMask == 111) {
+ if (fframes_p->mRelActor && fframes_p->mRelUseMask[0] == 111) {
fframes_p->field_0x4 = relationalPos(fframes_p->mRelActor, &sp30);
} else {
fframes_p->field_0x4 = sp30;
}
- if (fframes_p->mRelActor && fframes_p->field_0x31 == 111) {
+ if (fframes_p->mRelActor && fframes_p->mRelUseMask[1] == 111) {
fframes_p->field_0x10 = relationalPos(fframes_p->mRelActor, &sp3c);
} else {
fframes_p->field_0x10 = sp3c;
@@ -3959,7 +3971,7 @@ bool dCamera_c::bspTransEvCamera() {
bspTrans->mSet1 = 0;
char use1[8];
- strcpy(use1, "xxxxxx");
+ SAFE_STRCPY(use1, "xxxxxx");
iVar1 = getEvFloatListData(&bspTrans->mSet1, "Set1");
if (iVar1 != 0) {
@@ -3970,7 +3982,7 @@ bool dCamera_c::bspTransEvCamera() {
#if DEBUG
if (strlen(use1) != 6) {
OSReport("camera: event: bad length -> xxxxxx\n");
- strcpy(use1, "xxxxxx");
+ SAFE_STRCPY(use1, "xxxxxx");
JUTAssertion::showAssert(JUTAssertion::getSDevice(), "d_ev_camera.cpp", 0x14f9, "0");
OSPanic("d_ev_camera.cpp", 0x14f9, "Halt");
}
@@ -3979,7 +3991,7 @@ bool dCamera_c::bspTransEvCamera() {
bspTrans->mSet2 = 0;
char use2[8];
- strcpy(use2, "xxxxxx");
+ SAFE_STRCPY(use2, "xxxxxx");
iVar1 = getEvFloatListData(&bspTrans->mSet2, "Set2");
if (iVar1 != 0) {
@@ -3990,7 +4002,7 @@ bool dCamera_c::bspTransEvCamera() {
#if DEBUG
if (strlen(use2) != 6) {
OSReport_Error("camera: event: bad length -> xxxxxx\n");
- strcpy(use2, "xxxxxx");
+ SAFE_STRCPY(use2, "xxxxxx");
JUTAssertion::showAssert(JUTAssertion::getSDevice(), "d_ev_camera.cpp", 0x1509, "0");
OSPanic("d_ev_camera.cpp", 0x1509, "Halt");
}
@@ -4000,12 +4012,12 @@ bool dCamera_c::bspTransEvCamera() {
bspTrans->mRelActorID = -1;
bspTrans->mRelActor = getEvActor("RelActor");
if (bspTrans->mRelActor) {
- getEvStringData(&bspTrans->mRelUseMask, "RelUseMask", "oo");
+ getEvStringData(bspTrans->mRelUseMask, "RelUseMask", "oo");
#if DEBUG
- if (strlen(&bspTrans->mRelUseMask) != 2) {
+ if (strlen(bspTrans->mRelUseMask) != 2) {
OSReport_Error("camera: event: bad length -> xx\n");
- strcpy(&bspTrans->mRelUseMask, "xx");
+ SAFE_STRCPY(bspTrans->mRelUseMask, "xx");
JUTAssertion::showAssert(JUTAssertion::getSDevice(), "d_ev_camera.cpp", 0x1515, "0");
OSPanic("d_ev_camera.cpp", 0x1515, "Halt");
}
@@ -4041,13 +4053,13 @@ bool dCamera_c::bspTransEvCamera() {
} pos;
if (bspTrans->mRelActor != NULL) {
- if (isRelChar(bspTrans->mRelUseMask)) {
+ if (isRelChar(bspTrans->mRelUseMask[0])) {
pos.sp48 = relationalPos(bspTrans->mRelActor, &bspTrans->field_0x94);
} else {
pos.sp48 = bspTrans->field_0x94;
}
- if (isRelChar(bspTrans->field_0xb9)) {
+ if (isRelChar(bspTrans->mRelUseMask[1])) {
pos.sp3c = relationalPos(bspTrans->mRelActor, &bspTrans->field_0xa0);
} else {
pos.sp3c = bspTrans->field_0xa0;
diff --git a/src/d/d_event.cpp b/src/d/d_event.cpp
index 73891276df..3eba7aa041 100644
--- a/src/d/d_event.cpp
+++ b/src/d/d_event.cpp
@@ -13,6 +13,8 @@
#include "SSystem/SComponent/c_counter.h"
#include
+#include "dusk/string.hpp"
+
namespace {
static u8 event_debug_evnt() {
#if DEBUG
@@ -756,8 +758,8 @@ int dEv_defaultSkipZev(void* actor, int parameter) {
char* skipName;
switch (parameter) {
case 0:
- strcpy(eventName, data->data.event_name);
- strcat(eventName, "$0");
+ SAFE_STRCPY(eventName, data->data.event_name);
+ SAFE_STRCAT(eventName, "$0");
eventID = dComIfGp_getEventManager().getEventIdx(eventName, 0xFF, -1);
OS_REPORT("%06d: event: [%d] %s!\n", g_Counter.mCounter0, eventID, eventName);
break;
@@ -804,8 +806,8 @@ int dEv_defaultSkipStb(void* actor, int parameter) {
char* skipName;
switch (parameter) {
case 0:
- strcpy(eventName, data->data.event_name);
- strcat(eventName, "$0");
+ SAFE_STRCPY(eventName, data->data.event_name);
+ SAFE_STRCAT(eventName, "$0");
eventID = dComIfGp_getEventManager().getEventIdx(eventName, 0xFF, -1);
OS_REPORT("%06d: event: [%d] %s!\n", g_Counter.mCounter0, eventID, eventName);
break;
@@ -851,7 +853,7 @@ void dEvt_control_c::setSkipProc(void* skipActor, dEvt_SkipCb skipCb, int skipPa
void dEvt_control_c::setSkipZev(void* skipActor, char* eventName) {
setSkipProc(skipActor, dEv_defaultSkipZev, 1);
- strcpy(mSkipEventName, eventName);
+ SAFE_STRCPY(mSkipEventName, eventName);
}
void dEvt_control_c::onSkipFade() {
diff --git a/src/d/d_event_manager.cpp b/src/d/d_event_manager.cpp
index 598b973b84..d1d56be90f 100644
--- a/src/d/d_event_manager.cpp
+++ b/src/d/d_event_manager.cpp
@@ -15,6 +15,8 @@
#include "SSystem/SComponent/c_counter.h"
#include
+#include "dusk/string.hpp"
+
#if DEBUG
static dEvM_HIO_c l_HIO;
#endif
@@ -388,7 +390,7 @@ void dEvent_manager_c::roomInit(int roomNo) {
}
char arcname[8];
- strcpy(arcname, dComIfG_getRoomArcName(roomNo));
+ SAFE_STRCPY(arcname, dComIfG_getRoomArcName(roomNo));
char* res = (char*)dComIfG_getStageRes(arcname, DataFileName);
int i;
@@ -836,7 +838,7 @@ s16 dEvent_manager_c::getEventIdx(const char* eventName, u8 mapToolID, s32 roomN
case dStage_MapEvent_dt_TYPE_STB:
return getEventIdx(mapdata->data.event_name, 0xFF, roomNo);
case dStage_MapEvent_dt_TYPE_MAPTOOLCAMERA:
- sprintf(map_tool_name, "MapToolCamera%d", mapToolID);
+ SAFE_SPRINTF(map_tool_name, "MapToolCamera%d", mapToolID);
return getEventIdx(map_tool_name, 0xFF, roomNo);
default:
JUT_ASSERT(1278, FALSE);
@@ -876,7 +878,7 @@ s16 dEvent_manager_c::getEventIdx(fopAc_ac_c* actor, u8 mapToolID) {
case dStage_MapEvent_dt_TYPE_STB:
return getEventIdx(actor, mapdata->data.event_name, 0xFF);
case dStage_MapEvent_dt_TYPE_MAPTOOLCAMERA:
- sprintf(map_tool_name, "MapToolCamera%d", mapToolID);
+ SAFE_SPRINTF(map_tool_name, "MapToolCamera%d", mapToolID);
return getEventIdx(actor, map_tool_name, 0xFF);
default:
JUT_ASSERT(1341, FALSE);
@@ -901,7 +903,7 @@ s16 dEvent_manager_c::getEventIdx(fopAc_ac_c* actor, const char* eventName, u8 m
case dStage_MapEvent_dt_TYPE_STB:
return getEventIdx(actor, mapdata->data.event_name, 0xFF);
case dStage_MapEvent_dt_TYPE_MAPTOOLCAMERA:
- sprintf(map_tool_name, "MapToolCamera%d", mapToolID);
+ SAFE_SPRINTF(map_tool_name, "MapToolCamera%d", mapToolID);
return getEventIdx(actor, map_tool_name, 0xFF);
default:
JUT_ASSERT(1376, FALSE);
@@ -1040,7 +1042,7 @@ int dEvent_manager_c::getMyStaffId(const char* staffName, fopAc_ac_c* actor, int
dEvDtStaff_c* staff = getBase().getStaffP(staff_id);
if (staff->getType() != dEvDtStaff_c::TYPE_ALL) {
char buf[20];
- strcpy(buf, staff->getName());
+ SAFE_STRCPY(buf, staff->getName());
char* ptr = NULL;
if (!hasDp) {
@@ -1310,7 +1312,7 @@ void dEvent_manager_c::issueStaff(const char* staffname) {
fopAcM_Search((fopAcIt_JudgeFunc)extraOnObjectCallBack, NULL);
} else {
char nameBuf[32];
- strcpy(nameBuf, staffname);
+ SAFE_STRCPY(nameBuf, staffname);
fopAc_ac_c* actor = fopAcM_searchFromName4Event(nameBuf, -1);
fopAcM_OnStatus(actor, fopAcStts_STAFF_EXTRA_e);
}
@@ -1321,7 +1323,7 @@ void dEvent_manager_c::cancelStaff(const char* staffname) {
fopAcM_Search((fopAcIt_JudgeFunc)extraOffObjectCallBack, NULL);
} else {
char nameBuf[32];
- strcpy(nameBuf, staffname);
+ SAFE_STRCPY(nameBuf, staffname);
fopAc_ac_c* actor = fopAcM_searchFromName4Event(nameBuf, -1);
fopAcM_OffStatus(actor, fopAcStts_STAFF_EXTRA_e);
}
diff --git a/src/d/d_file_sel_info.cpp b/src/d/d_file_sel_info.cpp
index 0c987e6d63..d54bc4424d 100644
--- a/src/d/d_file_sel_info.cpp
+++ b/src/d/d_file_sel_info.cpp
@@ -14,6 +14,7 @@
#include
#include
+#include "dusk/string.hpp"
#include "dusk/version.hpp"
dFile_info_c::dFile_info_c(JKRArchive* i_archive, u8 param_1) {
@@ -80,9 +81,11 @@ void dFile_info_c::screenSet() {
info_text[2] = (J2DTextBox*)mFileInfo.Scr->search(MULTI_CHAR('w_time01'));
info_text[3] = (J2DTextBox*)mFileInfo.Scr->search(MULTI_CHAR('w_ptim01'));
+#define INFO_TEXT_SIZE 0x40
+
for (int i = 0; i < 4; i++) {
info_text[i]->setFont(mFileInfo.mFont);
- info_text[i]->setString(0x40, "");
+ info_text[i]->setString(INFO_TEXT_SIZE, "");
}
mPlayerName = info_text[0]->getStringPtr();
mSaveStatus = info_text[1]->getStringPtr();
@@ -99,9 +102,9 @@ int dFile_info_c::setSaveData(dSv_save_c* i_savedata, BOOL i_validChksum, u8 i_d
i_savedata->getPlayer().getPlayerStatusA().setLife(dComIfGs_getLife());
setHeartCnt(i_savedata);
i_savedata->getPlayer().getPlayerStatusA().setLife(12);
- strcpy(mPlayerName, dComIfGs_getPlayerName());
- strcpy(mSaveDate, "");
- strcpy(mPlayTime, "");
+ SAFE_STRCPY(mPlayerName, dComIfGs_getPlayerName());
+ SAFE_STRCPY(mSaveDate, "");
+ SAFE_STRCPY(mPlayTime, "");
dMeter2Info_getString(0x4D, mSaveStatus, NULL); // New Quest Log
result = 2;
} else {
@@ -110,7 +113,7 @@ int dFile_info_c::setSaveData(dSv_save_c* i_savedata, BOOL i_validChksum, u8 i_d
}
} else {
setHeartCnt(i_savedata);
- strcpy(mPlayerName, player_name);
+ SAFE_STRCPY(mPlayerName, player_name);
setSaveDate(i_savedata);
setPlayTime(i_savedata);
result = 0;
@@ -173,13 +176,13 @@ void dFile_info_c::setSaveDate(dSv_save_c* i_savedata) {
#if TARGET_PC
if (dusk::version::isRegionJpn()) {
- sprintf(mSaveDate, "%d.%02d.%02d %02d:%02d", time.year, time.mon + 1, time.mday,
+ SAFE_SPRINTF(mSaveDate, "%d.%02d.%02d %02d:%02d", time.year, time.mon + 1, time.mday,
time.hour, time.min);
} else if (dusk::version::isRegionPal() && dComIfGs_getPalLanguage() != dSv_player_config_c::LANGUAGE_ENGLISH) {
- sprintf(mSaveDate, "%02d/%02d/%d %02d:%02d", time.mday, time.mon + 1, time.year, time.hour,
+ SAFE_SPRINTF(mSaveDate, "%02d/%02d/%d %02d:%02d", time.mday, time.mon + 1, time.year, time.hour,
time.min);
} else {
- sprintf(mSaveDate, "%02d/%02d/%d %02d:%02d", time.mon + 1, time.mday, time.year, time.hour,
+ SAFE_SPRINTF(mSaveDate, "%02d/%02d/%d %02d:%02d", time.mon + 1, time.mday, time.year, time.hour,
time.min);
}
#elif (VERSION == VERSION_GCN_JPN) || (VERSION == VERSION_WII_JPN)
@@ -204,11 +207,11 @@ void dFile_info_c::setPlayTime(dSv_save_c* i_savedata) {
// 3599940 = 999:59 in seconds
if (time >= 3599940) {
- sprintf(mPlayTime, "999:59");
+ SAFE_SPRINTF(mPlayTime, "999:59");
} else {
u32 min = (time % 3600) / 60;
u32 hours = time / 3600;
- sprintf(mPlayTime, "%d:%02d", hours, min);
+ SAFE_SPRINTF(mPlayTime, "%d:%02d", hours, min);
}
}
diff --git a/src/d/d_file_select.cpp b/src/d/d_file_select.cpp
index 17d5f2c4e4..40962abf0a 100644
--- a/src/d/d_file_select.cpp
+++ b/src/d/d_file_select.cpp
@@ -23,6 +23,8 @@
#include "m_Do/m_Do_graphic.h"
#include
+#include "dusk/string.hpp"
+
static s32 SelStartFrameTbl[3] = {
59,
99,
@@ -3507,7 +3509,7 @@ void dFile_select_c::headerTxtSet(u16 i_msgId, u8 i_type, u8 param_3) {
}
if (i_msgId == 0xFFFF) {
- strcpy(mHeaderStringPtr[dispIdx], "");
+ SAFE_STRCPY(mHeaderStringPtr[dispIdx], "");
} else {
static f32 fontsize[2] = {21.0f, 27.0f};
#if VERSION == VERSION_GCN_JPN
@@ -3750,74 +3752,220 @@ bool dFile_select_c::yesnoWakuAlpahAnm(u8 param_1) {
#if TARGET_PC
void dFile_select_c::fileSelectWide() {
- mYnSel.ScrYn->scale(mDoGph_gInf_c::hudAspectScaleUp, 1.0f);
- mYnSel.ScrYn->translate(mDoGph_gInf_c::getSafeMinXF(), 0.0f);
-
- mYnSel.ScrYn->search(MULTI_CHAR('w_no_t'))->scale(mDoGph_gInf_c::hudAspectScaleDown, 1.0f);
- mYnSel.ScrYn->search(MULTI_CHAR('f_no_t'))->scale(mDoGph_gInf_c::hudAspectScaleDown, 1.0f);
- mYnSel.ScrYn->search(MULTI_CHAR('w_yes_t'))->scale(mDoGph_gInf_c::hudAspectScaleDown, 1.0f);
- mYnSel.ScrYn->search(MULTI_CHAR('f_yes_t'))->scale(mDoGph_gInf_c::hudAspectScaleDown, 1.0f);
-
- m3mSel.Scr3m->scale(mDoGph_gInf_c::hudAspectScaleUp, 1.0f);
- m3mSel.Scr3m->translate(mDoGph_gInf_c::getSafeMinXF(), 0.0f);
-
- m3mSel.Scr3m->search(MULTI_CHAR('w_sta'))->scale(mDoGph_gInf_c::hudAspectScaleDown, 1.0f);
- m3mSel.Scr3m->search(MULTI_CHAR('f_sta'))->scale(mDoGph_gInf_c::hudAspectScaleDown, 1.0f);
- m3mSel.Scr3m->search(MULTI_CHAR('w_del'))->scale(mDoGph_gInf_c::hudAspectScaleDown, 1.0f);
- m3mSel.Scr3m->search(MULTI_CHAR('f_del'))->scale(mDoGph_gInf_c::hudAspectScaleDown, 1.0f);
- m3mSel.Scr3m->search(MULTI_CHAR('w_cop_t'))->scale(mDoGph_gInf_c::hudAspectScaleDown, 1.0f);
- m3mSel.Scr3m->search(MULTI_CHAR('f_cop_t'))->scale(mDoGph_gInf_c::hudAspectScaleDown, 1.0f);
-
- fileSel.Scr->scale(mDoGph_gInf_c::hudAspectScaleUp, 1.0f);
- fileSel.Scr->translate(mDoGph_gInf_c::getSafeMinXF(), 0.0f);
-
- fileSel.Scr->search(MULTI_CHAR('t_for'))->scale(mDoGph_gInf_c::hudAspectScaleDown, 1.0f);
- fileSel.Scr->search(MULTI_CHAR('t_for1'))->scale(mDoGph_gInf_c::hudAspectScaleDown, 1.0f);
-
- fileSel.Scr->search(MULTI_CHAR('w_btn_n'))->scale(mDoGph_gInf_c::hudAspectScaleDown, 1.0f);
-
- fileSel.Scr->search(MULTI_CHAR('w_n_bk00'))->scale(mDoGph_gInf_c::hudAspectScaleDown, 1.0f);
- fileSel.Scr->search(MULTI_CHAR('w_n_bk01'))->scale(mDoGph_gInf_c::hudAspectScaleDown, 1.0f);
- fileSel.Scr->search(MULTI_CHAR('w_n_bk02'))->scale(mDoGph_gInf_c::hudAspectScaleDown, 1.0f);
-
- fileSel.Scr->search(MULTI_CHAR('w_dat_i0'))->scale(mDoGph_gInf_c::hudAspectScaleDown, 1.0f);
- fileSel.Scr->search(MULTI_CHAR('w_dat_i1'))->scale(mDoGph_gInf_c::hudAspectScaleDown, 1.0f);
- fileSel.Scr->search(MULTI_CHAR('w_dat_i2'))->scale(mDoGph_gInf_c::hudAspectScaleDown, 1.0f);
-
- mCpSel.Scr->search(MULTI_CHAR('w_dat_i1'))->scale(mDoGph_gInf_c::hudAspectScaleDown, 1.0f);
- mCpSel.Scr->search(MULTI_CHAR('w_dat_i2'))->scale(mDoGph_gInf_c::hudAspectScaleDown, 1.0f);
- mCpSel.Scr->search(MULTI_CHAR('w_n_bk01'))->scale(mDoGph_gInf_c::hudAspectScaleDown, 1.0f);
- mCpSel.Scr->search(MULTI_CHAR('w_n_bk02'))->scale(mDoGph_gInf_c::hudAspectScaleDown, 1.0f);
-
- mSelDt.ScrDt->search(MULTI_CHAR('tate_n0'))->scale(mDoGph_gInf_c::hudAspectScaleDown, 1.0f);
- mSelDt.ScrDt->search(MULTI_CHAR('tate_n1'))->scale(mDoGph_gInf_c::hudAspectScaleDown, 1.0f);
- mSelDt.ScrDt->search(MULTI_CHAR('ken_n0'))->scale(mDoGph_gInf_c::hudAspectScaleDown, 1.0f);
- mSelDt.ScrDt->search(MULTI_CHAR('ken_n1'))->scale(mDoGph_gInf_c::hudAspectScaleDown, 1.0f);
- mSelDt.ScrDt->search(MULTI_CHAR('fuku_n0'))->scale(mDoGph_gInf_c::hudAspectScaleDown, 1.0f);
- mSelDt.ScrDt->search(MULTI_CHAR('fuku_n1'))->scale(mDoGph_gInf_c::hudAspectScaleDown, 1.0f);
- mSelDt.ScrDt->search(MULTI_CHAR('fuku_n2'))->scale(mDoGph_gInf_c::hudAspectScaleDown, 1.0f);
-
- // Spirals
- fileSel.Scr->search(MULTI_CHAR('w_uzu00'))->scale(mDoGph_gInf_c::hudAspectScaleDown, 1.0f);
- fileSel.Scr->search(MULTI_CHAR('w_uzu01'))->scale(mDoGph_gInf_c::hudAspectScaleDown, 1.0f);
- fileSel.Scr->search(MULTI_CHAR('w_uzu02'))->scale(mDoGph_gInf_c::hudAspectScaleDown, 1.0f);
- fileSel.Scr->search(MULTI_CHAR('w_uzu03'))->scale(mDoGph_gInf_c::hudAspectScaleDown, 1.0f);
- fileSel.Scr->search(MULTI_CHAR('w_uzu04'))->scale(mDoGph_gInf_c::hudAspectScaleDown, 1.0f);
- fileSel.Scr->search(MULTI_CHAR('w_uzu05'))->scale(mDoGph_gInf_c::hudAspectScaleDown, 1.0f);
- fileSel.Scr->search(MULTI_CHAR('w_uzu06'))->scale(mDoGph_gInf_c::hudAspectScaleDown, 1.0f);
- fileSel.Scr->search(MULTI_CHAR('w_uzu07'))->scale(mDoGph_gInf_c::hudAspectScaleDown, 1.0f);
- fileSel.Scr->search(MULTI_CHAR('w_uzu08'))->scale(mDoGph_gInf_c::hudAspectScaleDown, 1.0f);
- fileSel.Scr->search(MULTI_CHAR('w_uzu09'))->scale(mDoGph_gInf_c::hudAspectScaleDown, 1.0f);
-
- #if TARGET_PC
- if (mSelIcon) {
- mSelIcon->refreshAspectScale();
+ // Get pre-scale values for each pane
+ if (!cachedPanes) {
+ for (PaneCache& entry : mSelDtPanes) {
+ J2DPane* pane = mSelDt.ScrDt->search(entry.tag);
+ if (!entry.cached) {
+ entry.origTransX = pane->getTranslateX();
+ entry.origTransY = pane->getTranslateY();
+ entry.cached = true;
+ }
+ }
+ for (PaneCache& entry : fileSelPanes) {
+ J2DPane* pane = fileSel.Scr->search(entry.tag);
+ if (!entry.cached) {
+ entry.origTransX = pane->getTranslateX();
+ entry.origTransY = pane->getTranslateY();
+ entry.cached = true;
+ }
+ }
+ cachedPanes = true;
}
-
- if (mSelIcon2) {
- mSelIcon2->refreshAspectScale();
+
+ // Reset all panes
+ mSelDt.ScrDt->scale(1.0f, 1.0f);
+ mSelDt.ScrDt->translate(0.0f, 0.0f);
+ for (PaneCache& entry : mSelDtPanes) {
+ J2DPane* pane = mSelDt.ScrDt->search(entry.tag);
+ pane->setBasePosition(J2DBasePosition_4);
+ pane->scale(1.0f, 1.0f);
+ pane->translate(entry.origTransX, entry.origTransY);
+ }
+ for (PaneCache& entry : fileSelPanes) {
+ J2DPane* pane = fileSel.Scr->search(entry.tag);
+ pane->setBasePosition(J2DBasePosition_4);
+ pane->scale(1.0f, 1.0f);
+ pane->translate(entry.origTransX, entry.origTransY);
+ }
+
+ bool wideScaling = dusk::getSettings().game.menuScalingMode.getValue() != dusk::MenuScaling::GameCube;
+ const f32 rootScale = wideScaling ? mDoGph_gInf_c::hudAspectScaleUp : 1.0f;
+ const f32 childScale = wideScaling ? mDoGph_gInf_c::hudAspectScaleDown : 1.0f;
+ const f32 rootTransX = wideScaling ? mDoGph_gInf_c::getSafeMinXF() : 0.0f;
+
+ mYnSel.ScrYn->scale(rootScale, 1.0f);
+ mYnSel.ScrYn->translate(rootTransX, 0.0f);
+
+ mYnSel.ScrYn->search(MULTI_CHAR('w_no_t'))->scale(childScale, 1.0f);
+ mYnSel.ScrYn->search(MULTI_CHAR('f_no_t'))->scale(childScale, 1.0f);
+ mYnSel.ScrYn->search(MULTI_CHAR('w_yes_t'))->scale(childScale, 1.0f);
+ mYnSel.ScrYn->search(MULTI_CHAR('f_yes_t'))->scale(childScale, 1.0f);
+
+ m3mSel.Scr3m->scale(rootScale, 1.0f);
+ m3mSel.Scr3m->translate(rootTransX, 0.0f);
+
+ m3mSel.Scr3m->search(MULTI_CHAR('w_sta'))->scale(childScale, 1.0f);
+ m3mSel.Scr3m->search(MULTI_CHAR('f_sta'))->scale(childScale, 1.0f);
+ m3mSel.Scr3m->search(MULTI_CHAR('w_del'))->scale(childScale, 1.0f);
+ m3mSel.Scr3m->search(MULTI_CHAR('f_del'))->scale(childScale, 1.0f);
+ m3mSel.Scr3m->search(MULTI_CHAR('w_cop_t'))->scale(childScale, 1.0f);
+ m3mSel.Scr3m->search(MULTI_CHAR('f_cop_t'))->scale(childScale, 1.0f);
+
+ fileSel.Scr->scale(rootScale, 1.0f);
+ fileSel.Scr->translate(rootTransX, 0.0f);
+
+ fileSel.Scr->search(MULTI_CHAR('t_for'))->scale(childScale, 1.0f);
+ fileSel.Scr->search(MULTI_CHAR('t_for1'))->scale(childScale, 1.0f);
+
+ fileSel.Scr->search(MULTI_CHAR('w_btn_n'))->scale(childScale, 1.0f);
+
+ fileSel.Scr->search(MULTI_CHAR('w_n_bk00'))->scale(childScale, 1.0f);
+ fileSel.Scr->search(MULTI_CHAR('w_n_bk01'))->scale(childScale, 1.0f);
+ fileSel.Scr->search(MULTI_CHAR('w_n_bk02'))->scale(childScale, 1.0f);
+
+ fileSel.Scr->search(MULTI_CHAR('w_dat_i0'))->scale(childScale, 1.0f);
+ fileSel.Scr->search(MULTI_CHAR('w_dat_i1'))->scale(childScale, 1.0f);
+ fileSel.Scr->search(MULTI_CHAR('w_dat_i2'))->scale(childScale, 1.0f);
+
+ mCpSel.Scr->search(MULTI_CHAR('w_dat_i1'))->scale(childScale, 1.0f);
+ mCpSel.Scr->search(MULTI_CHAR('w_dat_i2'))->scale(childScale, 1.0f);
+ mCpSel.Scr->search(MULTI_CHAR('w_n_bk01'))->scale(childScale, 1.0f);
+ mCpSel.Scr->search(MULTI_CHAR('w_n_bk02'))->scale(childScale, 1.0f);
+
+ switch (dusk::getSettings().game.menuScalingMode) {
+ case (dusk::MenuScaling::GameCube):
+ // Selection Cursor
+ if (mSelIcon) {
+ mSelIcon->refreshAspectScale(1.0f);
+ }
+ if (mSelIcon2) {
+ mSelIcon2->refreshAspectScale(1.0f);
+ }
+ break;
+ case (dusk::MenuScaling::Wii):
+ // Icons
+ mSelDt.ScrDt->search(MULTI_CHAR('tate_n0'))->scale(mDoGph_gInf_c::hudAspectScaleDown, 1.0f);
+ mSelDt.ScrDt->search(MULTI_CHAR('tate_n1'))->scale(mDoGph_gInf_c::hudAspectScaleDown, 1.0f);
+ mSelDt.ScrDt->search(MULTI_CHAR('ken_n0'))->scale(mDoGph_gInf_c::hudAspectScaleDown, 1.0f);
+ mSelDt.ScrDt->search(MULTI_CHAR('ken_n1'))->scale(mDoGph_gInf_c::hudAspectScaleDown, 1.0f);
+ mSelDt.ScrDt->search(MULTI_CHAR('fuku_n0'))->scale(mDoGph_gInf_c::hudAspectScaleDown, 1.0f);
+ mSelDt.ScrDt->search(MULTI_CHAR('fuku_n1'))->scale(mDoGph_gInf_c::hudAspectScaleDown, 1.0f);
+ mSelDt.ScrDt->search(MULTI_CHAR('fuku_n2'))->scale(mDoGph_gInf_c::hudAspectScaleDown, 1.0f);
+
+ // Spirals
+ fileSel.Scr->search(MULTI_CHAR('w_uzu00'))->scale(mDoGph_gInf_c::hudAspectScaleDown, 1.0f);
+ fileSel.Scr->search(MULTI_CHAR('w_uzu01'))->scale(mDoGph_gInf_c::hudAspectScaleDown, 1.0f);
+ fileSel.Scr->search(MULTI_CHAR('w_uzu02'))->scale(mDoGph_gInf_c::hudAspectScaleDown, 1.0f);
+ fileSel.Scr->search(MULTI_CHAR('w_uzu03'))->scale(mDoGph_gInf_c::hudAspectScaleDown, 1.0f);
+ fileSel.Scr->search(MULTI_CHAR('w_uzu04'))->scale(mDoGph_gInf_c::hudAspectScaleDown, 1.0f);
+ fileSel.Scr->search(MULTI_CHAR('w_uzu05'))->scale(mDoGph_gInf_c::hudAspectScaleDown, 1.0f);
+ fileSel.Scr->search(MULTI_CHAR('w_uzu06'))->scale(mDoGph_gInf_c::hudAspectScaleDown, 1.0f);
+ fileSel.Scr->search(MULTI_CHAR('w_uzu07'))->scale(mDoGph_gInf_c::hudAspectScaleDown, 1.0f);
+ fileSel.Scr->search(MULTI_CHAR('w_uzu08'))->scale(mDoGph_gInf_c::hudAspectScaleDown, 1.0f);
+ fileSel.Scr->search(MULTI_CHAR('w_uzu09'))->scale(mDoGph_gInf_c::hudAspectScaleDown, 1.0f);
+
+ // Selection Cursor
+ if (mSelIcon) {
+ mSelIcon->refreshAspectScale(mDoGph_gInf_c::hudAspectScaleUp);
+ }
+
+ if (mSelIcon2) {
+ mSelIcon2->refreshAspectScale(mDoGph_gInf_c::hudAspectScaleUp);
+ }
+ break;
+ case (dusk::MenuScaling::Dusklight):
+ constexpr f32 minAspect = 4.0f / 2.94f;
+ constexpr f32 wideAspect = 16.0f / 9.0f + 0.05f;
+ constexpr f32 ultraAspect = 21.0f / 9.0f + 0.05f;
+ const f32 screenAspect = mDoGph_gInf_c::getAspect();
+
+ const f32 wideScaleFactor = 1.0f + 0.16f * (mDoGph_gInf_c::hudAspectScaleUp - 1.0f);
+ const f32 ultraScaleFactor = 1.0f + 0.115f * (mDoGph_gInf_c::hudAspectScaleUp - 1.0f);
+
+ const f32 wideShiftFactor = mSelDt.ScrDt->search(MULTI_CHAR('gray_n'))->getTranslateX() * (wideScaleFactor - mDoGph_gInf_c::hudAspectScaleDown);
+ const f32 ultraShiftFactor = mSelDt.ScrDt->search(MULTI_CHAR('gray_n'))->getTranslateX() * (ultraScaleFactor - mDoGph_gInf_c::hudAspectScaleDown);
+
+ for (PaneCache& entry : mSelDtPanes) {
+ const size_t index = &entry - mSelDtPanes;
+ J2DPane* pane = mSelDt.ScrDt->search(entry.tag);
+ pane->setBasePosition(J2DBasePosition_0);
+ pane->scale(mDoGph_gInf_c::hudAspectScaleDown, 1.0f);
+ if (screenAspect >= minAspect && screenAspect <= wideAspect) { // Handle widescreen
+ if (entry.tag == MULTI_CHAR('b_base')) { // Slots BG
+ if (screenAspect > 1.75f) {
+ pane->translate((entry.origTransX + 11.0f) * wideScaleFactor, pane->getTranslateY());
+ } else { // Between 4:3 and 16:9
+ pane->translate((entry.origTransX + 8.0f) * wideScaleFactor, pane->getTranslateY());
+ }
+ }
+ if (entry.tag == MULTI_CHAR('b_base1')) { // Magic Armor Slot BG
+ if (screenAspect > 1.75f) {
+ pane->translate((entry.origTransX - 21.5f) * wideScaleFactor, pane->getTranslateY());
+ } else { // Between 4:3 and 16:9
+ pane->translate((entry.origTransX - 12.0f) * wideScaleFactor, pane->getTranslateY());
+ }
+ }
+ if (entry.tag == MULTI_CHAR('gray_n')) { // Slots
+ pane->translate(entry.origTransX * wideScaleFactor, pane->getTranslateY());
+ }
+ if (index <= 6) { // Icons
+ pane->translate(mDoGph_gInf_c::hudAspectScaleDown * entry.origTransX + wideShiftFactor - 60.0f * (1.0f - mDoGph_gInf_c::hudAspectScaleDown), pane->getTranslateY());
+ }
+ } else if (screenAspect >= minAspect && screenAspect >= wideAspect && screenAspect <= ultraAspect) // Handle ultrawide
+ {
+ if (entry.tag == MULTI_CHAR('b_base')) { // Slots BG
+ pane->translate((entry.origTransX + 18.0f) * ultraScaleFactor, pane->getTranslateY());
+ }
+ if (entry.tag == MULTI_CHAR('b_base1')) { // Magic Armor Slot BG
+ pane->translate((entry.origTransX - 40.0f) * ultraScaleFactor, pane->getTranslateY());
+ }
+ if (entry.tag == MULTI_CHAR('gray_n')) { // Slots
+ pane->translate(entry.origTransX * ultraScaleFactor, pane->getTranslateY());
+ }
+ if (index <= 6) { // Icons
+ pane->translate(mDoGph_gInf_c::hudAspectScaleDown * entry.origTransX + ultraShiftFactor - 62.0f * (1.0f - mDoGph_gInf_c::hudAspectScaleDown), pane->getTranslateY());
+ }
+ } else { // 4:3/default behavior
+ pane->setBasePosition(J2DBasePosition_4);
+ pane->translate(entry.origTransX, pane->getTranslateY());
+ if (entry.tag == MULTI_CHAR('gray_n')) { // Slots
+ pane->scale(1.0f, 1.0f);
+ }
+ if (entry.tag == MULTI_CHAR('b_base')) { // Slots BG
+ pane->scale(1.0f, 1.0f);
+ }
+ if (entry.tag == MULTI_CHAR('b_base1')) { // Magic Armor Slot BG
+ pane->scale(1.0f, 1.0f);
+ }
+ if (index <= 6) { // Icons
+ pane->scale(mDoGph_gInf_c::hudAspectScaleDown, 1.0f);
+ }
+ }
+ }
+
+ // Selection Cursor
+ if (mSelIcon) {
+ mSelIcon->refreshAspectScale(mDoGph_gInf_c::hudAspectScaleUp);
+ }
+
+ if (mSelIcon2) {
+ mSelIcon2->refreshAspectScale(mDoGph_gInf_c::hudAspectScaleUp);
+ }
+
+ // Spirals
+ fileSel.Scr->search(MULTI_CHAR('w_uzu00'))->scale(mDoGph_gInf_c::hudAspectScaleDown, 1.0f);
+ fileSel.Scr->search(MULTI_CHAR('w_uzu01'))->scale(mDoGph_gInf_c::hudAspectScaleDown, 1.0f);
+ fileSel.Scr->search(MULTI_CHAR('w_uzu02'))->scale(mDoGph_gInf_c::hudAspectScaleDown, 1.0f);
+ fileSel.Scr->search(MULTI_CHAR('w_uzu03'))->scale(mDoGph_gInf_c::hudAspectScaleDown, 1.0f);
+ fileSel.Scr->search(MULTI_CHAR('w_uzu04'))->scale(mDoGph_gInf_c::hudAspectScaleDown, 1.0f);
+ fileSel.Scr->search(MULTI_CHAR('w_uzu05'))->scale(mDoGph_gInf_c::hudAspectScaleDown, 1.0f);
+ fileSel.Scr->search(MULTI_CHAR('w_uzu06'))->scale(mDoGph_gInf_c::hudAspectScaleDown, 1.0f);
+ fileSel.Scr->search(MULTI_CHAR('w_uzu07'))->scale(mDoGph_gInf_c::hudAspectScaleDown, 1.0f);
+ fileSel.Scr->search(MULTI_CHAR('w_uzu08'))->scale(mDoGph_gInf_c::hudAspectScaleDown, 1.0f);
+ fileSel.Scr->search(MULTI_CHAR('w_uzu09'))->scale(mDoGph_gInf_c::hudAspectScaleDown, 1.0f);
+ break;
}
- #endif
}
#endif
@@ -4036,7 +4184,7 @@ void dFile_select_c::errDispInitSet(char* i_errMesg) {
mErrorMsgTxtPane[mErrorTxtDispIdx]->setAlpha(0xFF);
mErrorMsgTxtPane[mErrorTxtDispIdx ^ 1]->setAlpha(0);
- strcpy(mErrorMsgStringPtr[mErrorTxtDispIdx], i_errMesg);
+ SAFE_STRCPY_BOUNDED(mErrorMsgStringPtr[mErrorTxtDispIdx], i_errMesg);
if (field_0x014a) {
errorMoveAnmInitSet(2859, 2849);
@@ -4245,7 +4393,7 @@ void dFile_select_c::MemCardLoadWait() {
if (mDoMemCd_getDataVersion() != 6) {
char errmsg[264];
// "Savedata version is different\n\nVersion %d\n\nFormatting data."
- sprintf(errmsg, "セーブデータのバージョンが違います\n\nバージョン %d\n\nデータを初期化します。", mDoMemCd_getDataVersion());
+ SAFE_SPRINTF(errmsg, "セーブデータのバージョンが違います\n\nバージョン %d\n\nデータを初期化します。", mDoMemCd_getDataVersion());
errDispInitSet(errmsg);
field_0x0280 = false;
mWindowCloseMsgDispCb = NULL;
@@ -5091,7 +5239,7 @@ void dFile_select_c::MemCardErrYesNoCursorMoveAnm() {
void dFile_select_c::errorTxtSet(u16 i_msgId) {
if (i_msgId == 0xffff) {
- strcpy(mErrorMsgStringPtr[mErrorTxtDispIdx ^ 1], "");
+ SAFE_STRCPY(mErrorMsgStringPtr[mErrorTxtDispIdx ^ 1], "");
} else {
fileSel.mMessageString->getString(
i_msgId, (J2DTextBox*)mErrorMsgTxtPane[mErrorTxtDispIdx ^ 1]->getPanePtr(), NULL,
diff --git a/src/d/d_map.cpp b/src/d/d_map.cpp
index fa9049fb00..8cecead15a 100644
--- a/src/d/d_map.cpp
+++ b/src/d/d_map.cpp
@@ -931,6 +931,13 @@ bool renderingAmap_c::isDrawIconSingle2(dTres_c::data_s const* i_data, bool para
}
break;
case 5:
+#if TARGET_PC
+ if (dusk::getSettings().game.removeQuestMapMarkers &&
+ dComIfGs_isEventBit(dSv_event_flag_c::saveBitLabels[0x190]))
+ {
+ break;
+ }
+#endif
if (((i_data->mNo == 255 || (i_data->mNo != 255 && !dComIfGs_isTbox(i_data->mNo))) &&
(i_data->mSwBit == 255 ||
(i_data->mSwBit != 255 && dComIfGs_isSwitch(i_data->mSwBit, i_data->mRoomNo)))) &&
diff --git a/src/d/d_menu_calibration.cpp b/src/d/d_menu_calibration.cpp
index 0cc238e5d2..bc256547d7 100644
--- a/src/d/d_menu_calibration.cpp
+++ b/src/d/d_menu_calibration.cpp
@@ -14,7 +14,10 @@
#include "m_Do/m_Do_controller_pad.h"
#include
-// Need 0xC bytes of padding with no symbol between dMenu_Calibration_c::__vtable and the end of .data
+#include "dusk/string.hpp"
+
+// Need 0xC bytes of padding with no symbol between dMenu_Calibration_c::__vtable and the end of
+// .data
// This is likely caused by the vtable of an abstract base class getting put there and then stripped out.
// Not sure which abstract base class could go there though, so we simulate it with some dummy classes for now.
class dummy_abstract_class {
@@ -252,7 +255,7 @@ void dMenu_Calibration_c::setCalibrationValue() {
void dMenu_Calibration_c::setAButtonString(u16 i_stringID) {
if (i_stringID == 0) {
for (int i = 0; i < 5; i++) {
- strcpy(mpAButtonString[i]->getStringPtr(), "");
+ SAFE_STRCPY(mpAButtonString[i]->getStringPtr(), "");
}
} else {
for (int i = 0; i < 5; i++) {
@@ -264,7 +267,7 @@ void dMenu_Calibration_c::setAButtonString(u16 i_stringID) {
void dMenu_Calibration_c::setBButtonString(u16 i_stringID) {
if (i_stringID == 0) {
for (int i = 0; i < 5; i++) {
- strcpy(mpBButtonString[i]->getStringPtr(), "");
+ SAFE_STRCPY(mpBButtonString[i]->getStringPtr(), "");
}
} else {
for (int i = 0; i < 5; i++) {
@@ -276,7 +279,7 @@ void dMenu_Calibration_c::setBButtonString(u16 i_stringID) {
void dMenu_Calibration_c::setStepString(u16 i_stringID) {
if (i_stringID == 0) {
for (int i = 0; i < 3; i++) {
- strcpy(mpStepString[i]->getStringPtr(), "");
+ SAFE_STRCPY(mpStepString[i]->getStringPtr(), "");
}
} else {
for (int i = 0; i < 3; i++) {
@@ -288,7 +291,7 @@ void dMenu_Calibration_c::setStepString(u16 i_stringID) {
void dMenu_Calibration_c::setExplainString(u16 i_stringID) {
if (i_stringID == 0) {
for (int i = 0; i < 3; i++) {
- strcpy(mpExplainString[i]->getStringPtr(), "");
+ SAFE_STRCPY(mpExplainString[i]->getStringPtr(), "");
}
} else {
for (int i = 0; i < 3; i++) {
diff --git a/src/d/d_menu_collect.cpp b/src/d/d_menu_collect.cpp
index 612806d372..e9b477d1ea 100644
--- a/src/d/d_menu_collect.cpp
+++ b/src/d/d_menu_collect.cpp
@@ -97,79 +97,157 @@ dMenu_Collect2D_c::~dMenu_Collect2D_c() {
#if TARGET_PC
void dMenu_Collect2D_c::menuCollectWide() {
- // Main Canvas
- mpScreen->scale(mDoGph_gInf_c::hudAspectScaleUp, 1.0f);
- mpScreen->translate(mDoGph_gInf_c::getSafeMinXF(), 0.0f);
-
- // Pieces of Heart
- mpScreen->search(MULTI_CHAR('heart_n'))->scale(mDoGph_gInf_c::hudAspectScaleDown, 1.0f);
-
- // Scents
- mpScreen->search(MULTI_CHAR('wolf_n'))->scale(mDoGph_gInf_c::hudAspectScaleDown, 1.0f);
-
- // Quiver
- mpScreen->search(MULTI_CHAR('item_0_n'))->scale(mDoGph_gInf_c::hudAspectScaleDown, 1.0f);
-
- // Wallet
- mpScreen->search(MULTI_CHAR('item_1_n'))->scale(mDoGph_gInf_c::hudAspectScaleDown, 1.0f);
-
- // Poes
- mpScreen->search(MULTI_CHAR('item_2_n'))->scale(mDoGph_gInf_c::hudAspectScaleDown, 1.0f);
-
- // Fish Bestiary
- mpScreen->search(MULTI_CHAR('fish_3_n'))->scale(mDoGph_gInf_c::hudAspectScaleDown, 1.0f);
-
- // Letters
- mpScreen->search(MULTI_CHAR('lett_4_n'))->scale(mDoGph_gInf_c::hudAspectScaleDown, 1.0f);
-
- // Hidden Skills
- mpScreen->search(MULTI_CHAR('maki_5_n'))->scale(mDoGph_gInf_c::hudAspectScaleDown, 1.0f);
-
- // Green Tunic
- mpScreen->search(MULTI_CHAR('fuku_n0'))->scale(mDoGph_gInf_c::hudAspectScaleDown, 1.0f);
-
- // Zora Armor
- mpScreen->search(MULTI_CHAR('fuku_n1'))->scale(mDoGph_gInf_c::hudAspectScaleDown, 1.0f);
-
- // Magic Armor
- mpScreen->search(MULTI_CHAR('fuku_n2'))->scale(mDoGph_gInf_c::hudAspectScaleDown, 1.0f);
-
- // Ordon Shield
- mpScreen->search(MULTI_CHAR('tate_n0'))->scale(mDoGph_gInf_c::hudAspectScaleDown, 1.0f);
-
- // Hylian Shield
- mpScreen->search(MULTI_CHAR('tate_n1'))->scale(mDoGph_gInf_c::hudAspectScaleDown, 1.0f);
-
- // Ordon Sword
- mpScreen->search(MULTI_CHAR('ken_n0'))->scale(mDoGph_gInf_c::hudAspectScaleDown, 1.0f);
-
- // Master Sword
- mpScreen->search(MULTI_CHAR('ken_n1'))->scale(mDoGph_gInf_c::hudAspectScaleDown, 1.0f);
-
- // Bugs
- mpScreen->search(MULTI_CHAR('kabu_6n'))->scale(mDoGph_gInf_c::hudAspectScaleDown, 1.0f);
-
- // "Collection" Text
- mpScreen->search(MULTI_CHAR('t_t00'))->scale(mDoGph_gInf_c::hudAspectScaleDown, 1.0f);
- mpScreen->search(MULTI_CHAR('f_t00'))->scale(mDoGph_gInf_c::hudAspectScaleDown, 1.0f);
-
- // "Save" Text
- mpScreen->search(MULTI_CHAR('sa_tex_n'))->scale(mDoGph_gInf_c::hudAspectScaleDown, 1.0f);
-
- // "Options" Text
- mpScreen->search(MULTI_CHAR('op_tex_n'))->scale(mDoGph_gInf_c::hudAspectScaleDown, 1.0f);
-
- // Item Name Text
- mpScreen->search(MULTI_CHAR('itemn_n'))->scale(mDoGph_gInf_c::hudAspectScaleDown, 1.0f);
-
- // Item Description Text
- mpScreen->search(MULTI_CHAR('infotxtn'))->scale(mDoGph_gInf_c::hudAspectScaleDown, 1.0f);
-
- #if TARGET_PC
- if (mpDrawCursor) {
- mpDrawCursor->refreshAspectScale();
+ // Get pre-scale values for each pane
+ if (!cachedPanes) {
+ for (PaneCache& entry : mpScreenPanes) {
+ J2DPane* pane = mpScreen->search(entry.tag);
+ if (!entry.cached) {
+ entry.origTransX = pane->getTranslateX();
+ entry.origTransY = pane->getTranslateY();
+ entry.cached = true;
+ }
+ }
+ cachedPanes = true;
+ }
+
+ // Reset all panes
+ mpScreen->scale(1.0f, 1.0f);
+ mpScreen->translate(0.0f, 0.0f);
+ for (PaneCache& entry : mpScreenPanes) {
+ J2DPane* pane = mpScreen->search(entry.tag);
+ pane->scale(1.0f, 1.0f);
+ pane->translate(entry.origTransX, entry.origTransY);
+ }
+
+ // Reset button overlay
+ mpScreenIcon->translate(0.0f, 0.0f);
+
+ switch (dusk::getSettings().game.menuScalingMode) {
+ case dusk::MenuScaling::GameCube:
+ // Selection Cursor
+ if (mpDrawCursor) {
+ mpDrawCursor->refreshAspectScale(1.0f);
+ }
+ break;
+ case dusk::MenuScaling::Wii:
+ // Main Canvas
+ mpScreen->scale(mDoGph_gInf_c::hudAspectScaleUp, 1.0f);
+ mpScreen->translate(mDoGph_gInf_c::getSafeMinXF(), 0.0f);
+
+ // Button Overlay
+ mpScreenIcon->translate(-mDoGph_gInf_c::getSafeMinXF(), 0.0f);
+
+ // "Save" Text
+ mpScreen->search(MULTI_CHAR('sa_tex_n'))->scale(mDoGph_gInf_c::hudAspectScaleDown, 1.0f);
+
+ // "Options" Text
+ mpScreen->search(MULTI_CHAR('op_tex_n'))->scale(mDoGph_gInf_c::hudAspectScaleDown, 1.0f);
+
+ // Pieces of Heart
+ mpScreen->search(MULTI_CHAR('heart_n'))->scale(mDoGph_gInf_c::hudAspectScaleDown, 1.0f);
+
+ // Scents
+ mpScreen->search(MULTI_CHAR('wolf_n'))->scale(mDoGph_gInf_c::hudAspectScaleDown, 1.0f);
+
+ // Quiver
+ mpScreen->search(MULTI_CHAR('item_0_n'))->scale(mDoGph_gInf_c::hudAspectScaleDown, 1.0f);
+
+ // Wallet
+ mpScreen->search(MULTI_CHAR('item_1_n'))->scale(mDoGph_gInf_c::hudAspectScaleDown, 1.0f);
+
+ // Poes
+ mpScreen->search(MULTI_CHAR('item_2_n'))->scale(mDoGph_gInf_c::hudAspectScaleDown, 1.0f);
+
+ // Fish Bestiary
+ mpScreen->search(MULTI_CHAR('fish_3_n'))->scale(mDoGph_gInf_c::hudAspectScaleDown, 1.0f);
+
+ // Letters
+ mpScreen->search(MULTI_CHAR('lett_4_n'))->scale(mDoGph_gInf_c::hudAspectScaleDown, 1.0f);
+
+ // Hidden Skills
+ mpScreen->search(MULTI_CHAR('maki_5_n'))->scale(mDoGph_gInf_c::hudAspectScaleDown, 1.0f);
+
+ // Green Tunic
+ mpScreen->search(MULTI_CHAR('fuku_n0'))->scale(mDoGph_gInf_c::hudAspectScaleDown, 1.0f);
+
+ // Zora Armor
+ mpScreen->search(MULTI_CHAR('fuku_n1'))->scale(mDoGph_gInf_c::hudAspectScaleDown, 1.0f);
+
+ // Magic Armor
+ mpScreen->search(MULTI_CHAR('fuku_n2'))->scale(mDoGph_gInf_c::hudAspectScaleDown, 1.0f);
+
+ // Ordon Shield
+ mpScreen->search(MULTI_CHAR('tate_n0'))->scale(mDoGph_gInf_c::hudAspectScaleDown, 1.0f);
+
+ // Hylian Shield
+ mpScreen->search(MULTI_CHAR('tate_n1'))->scale(mDoGph_gInf_c::hudAspectScaleDown, 1.0f);
+
+ // Ordon Sword
+ mpScreen->search(MULTI_CHAR('ken_n0'))->scale(mDoGph_gInf_c::hudAspectScaleDown, 1.0f);
+
+ // Master Sword
+ mpScreen->search(MULTI_CHAR('ken_n1'))->scale(mDoGph_gInf_c::hudAspectScaleDown, 1.0f);
+
+ // Bugs
+ mpScreen->search(MULTI_CHAR('kabu_6n'))->scale(mDoGph_gInf_c::hudAspectScaleDown, 1.0f);
+
+ // "Collection" Text
+ mpScreen->search(MULTI_CHAR('t_t00'))->scale(mDoGph_gInf_c::hudAspectScaleDown, 1.0f);
+ mpScreen->search(MULTI_CHAR('f_t00'))->scale(mDoGph_gInf_c::hudAspectScaleDown, 1.0f);
+
+ // Item Name Text
+ mpScreen->search(MULTI_CHAR('itemn_n'))->scale(mDoGph_gInf_c::hudAspectScaleDown, 1.0f);
+
+ // Item Description Text
+ mpScreen->search(MULTI_CHAR('infotxtn'))->scale(mDoGph_gInf_c::hudAspectScaleDown, 1.0f);
+
+ // Selection Cursor
+ if (mpDrawCursor) {
+ mpDrawCursor->refreshAspectScale(mDoGph_gInf_c::hudAspectScaleUp);
+ }
+ break;
+ case dusk::MenuScaling::Dusklight:
+ // Main Canvas
+ mpScreen->scale(mDoGph_gInf_c::hudAspectScaleUp, 1.0f);
+ mpScreen->translate(mDoGph_gInf_c::getSafeMinXF(), 0.0f);
+
+ // Save/Options Buttons
+ mpScreen->search(MULTI_CHAR('sa_op_n'))->scale(mDoGph_gInf_c::hudAspectScaleDown, 1.0f);
+
+ // "Collection" Title Bar
+ mpScreen->search(MULTI_CHAR('title_n'))->scale(mDoGph_gInf_c::hudAspectScaleDown, 1.0f);
+
+ // Main Central Elements
+ mpScreen->search(MULTI_CHAR('menu_n'))->scale(mDoGph_gInf_c::hudAspectScaleDown, 1.0f);
+ mpScreen->search(MULTI_CHAR('w_er_n'))->scale(mDoGph_gInf_c::hudAspectScaleDown, 1.0f);
+ mpScreen->search(MULTI_CHAR('center_n'))->scale(mDoGph_gInf_c::hudAspectScaleDown, 1.0f);
+
+ const f32 leftShift = 48.0f * (mDoGph_gInf_c::hudAspectScaleUp - 1.0f); // Shifting certain items left to keep center (> 4:3 only)
+
+ // Item Name/Description Text
+ J2DPane* info_n = mpScreen->search(MULTI_CHAR('info_n'));
+ static f32 infoTransX_orig = info_n->getTranslateX();
+ info_n->translate(infoTransX_orig - leftShift, info_n->getTranslateY());
+
+ // Designs
+ J2DPane* lavel_n = mpScreen->search(MULTI_CHAR('lavel_n'));
+ static f32 lavelTransX_orig = lavel_n->getTranslateX();
+ lavel_n->translate(lavelTransX_orig - leftShift, lavel_n->getTranslateY());
+
+ // Fused Shadow/Mirror Background
+ J2DPane* modelbgn = mpScreen->search(MULTI_CHAR('modelbgn'));
+ static f32 modelbgnTransX_orig = modelbgn->getTranslateX(); // Get pre-scale value
+ modelbgn->setBasePosition(J2DBasePosition_0);
+ modelbgn->scale(mDoGph_gInf_c::hudAspectScaleDown, 1.3f);
+ f32 modelbgn_scaleFactor = 1.0f + 0.16f * (mDoGph_gInf_c::hudAspectScaleDown - 1.0f);
+ modelbgn->translate((modelbgnTransX_orig - 12.0f) * modelbgn_scaleFactor, modelbgn->getTranslateY());
+
+ // Selection Cursor
+ if (mpDrawCursor) {
+ mpDrawCursor->refreshAspectScale(1.0f);
+ }
+ break;
}
- #endif
}
#endif
@@ -2167,18 +2245,18 @@ void dMenu_Collect2D_c::_draw() {
if (mItemNameString == 0) {
#if REGION_JPN
- char* stringPtr1 = static_cast(mpScreen->search(MULTI_CHAR('i_text1')))->getStringPtr();
+ TEXT_SPAN stringPtr1 = static_cast(mpScreen->search(MULTI_CHAR('i_text1')))->getStringPtr();
#else
- char* stringPtr1 = static_cast(mpScreen->search(MULTI_CHAR('f_text1')))->getStringPtr();
+ TEXT_SPAN stringPtr1 = static_cast(mpScreen->search(MULTI_CHAR('f_text1')))->getStringPtr();
#endif
- strcpy(stringPtr1, "");
+ SAFE_STRCPY(stringPtr1, "");
#if REGION_JPN
- char* stringPtr0 = static_cast(mpScreen->search(MULTI_CHAR('i_text0')))->getStringPtr();
+ TEXT_SPAN stringPtr0 = static_cast(mpScreen->search(MULTI_CHAR('i_text0')))->getStringPtr();
#else
- char* stringPtr0 = static_cast(mpScreen->search(MULTI_CHAR('f_text0')))->getStringPtr();
+ TEXT_SPAN stringPtr0 = static_cast(mpScreen->search(MULTI_CHAR('f_text0')))->getStringPtr();
#endif
- strcpy(stringPtr0, "");
+ SAFE_STRCPY(stringPtr0, "");
} else {
#if REGION_JPN
J2DTextBox* textBox1 = static_cast(mpScreen->search(MULTI_CHAR('i_text1')));
@@ -2229,13 +2307,13 @@ void dMenu_Collect2D_c::setAButtonString(u16 i_stringID) {
if (i_stringID == 0) {
for (int i = 0; i < 5; i++) {
- char* stringPtr =
+ TEXT_SPAN stringPtr =
static_cast(mpScreenIcon->search(text_a_tag[i]))->getStringPtr();
- strcpy(stringPtr, "");
+ SAFE_STRCPY(stringPtr, "");
}
} else {
for (int i = 0; i < 5; i++) {
- char* stringPtr =
+ TEXT_SPAN stringPtr =
static_cast(mpScreenIcon->search(text_a_tag[i]))->getStringPtr();
dMeter2Info_getStringKanji(i_stringID, stringPtr, NULL);
}
@@ -2253,13 +2331,13 @@ void dMenu_Collect2D_c::setBButtonString(u16 i_stringID) {
if (i_stringID == 0) {
for (int i = 0; i < 5; i++) {
- char* stringPtr =
+ TEXT_SPAN stringPtr =
static_cast(mpScreenIcon->search(text_b_tag[i]))->getStringPtr();
- strcpy(stringPtr, "");
+ SAFE_STRCPY(stringPtr, "");
}
} else {
for (int i = 0; i < 5; i++) {
- char* stringPtr =
+ TEXT_SPAN stringPtr =
static_cast(mpScreenIcon->search(text_b_tag[i]))->getStringPtr();
dMeter2Info_getStringKanji(i_stringID, stringPtr, NULL);
}
@@ -2278,7 +2356,7 @@ void dMenu_Collect2D_c::setItemNameString(u8 param_0, u8 param_1) {
setItemNameStringNull();
} else {
#if REGION_JPN
- char* stringPtr =
+ TEXT_SPAN stringPtr =
static_cast(mpScreen->search(MULTI_CHAR('item_n00')))->getStringPtr();
dMeter2Info_getStringKanji(uVar6, stringPtr, NULL);
stringPtr = static_cast(mpScreen->search(MULTI_CHAR('item_n01')))->getStringPtr();
@@ -2288,7 +2366,7 @@ void dMenu_Collect2D_c::setItemNameString(u8 param_0, u8 param_1) {
stringPtr = static_cast(mpScreen->search(MULTI_CHAR('item_n03')))->getStringPtr();
dMeter2Info_getStringKanji(uVar6, stringPtr, NULL);
#else
- char* stringPtr =
+ TEXT_SPAN stringPtr =
static_cast(mpScreen->search(MULTI_CHAR('item_n04')))->getStringPtr();
dMeter2Info_getStringKanji(uVar6, stringPtr, NULL);
stringPtr = static_cast(mpScreen->search(MULTI_CHAR('item_n05')))->getStringPtr();
@@ -2306,22 +2384,22 @@ void dMenu_Collect2D_c::setItemNameStringNull() {
mItemNameString = 0;
#if REGION_JPN
J2DTextBox* textBox = (J2DTextBox*)mpScreen->search(MULTI_CHAR('item_n00'));
- strcpy(textBox->getStringPtr(), "");
+ SAFE_STRCPY(textBox->getStringPtr(), "");
textBox = (J2DTextBox*)mpScreen->search(MULTI_CHAR('item_n01'));
- strcpy(textBox->getStringPtr(), "");
+ SAFE_STRCPY(textBox->getStringPtr(), "");
textBox = (J2DTextBox*)mpScreen->search(MULTI_CHAR('item_n02'));
- strcpy(textBox->getStringPtr(), "");
+ SAFE_STRCPY(textBox->getStringPtr(), "");
textBox = (J2DTextBox*)mpScreen->search(MULTI_CHAR('item_n03'));
#else
J2DTextBox* textBox = (J2DTextBox*)mpScreen->search(MULTI_CHAR('item_n04'));
- strcpy(textBox->getStringPtr(), "");
+ SAFE_STRCPY(textBox->getStringPtr(), "");
textBox = (J2DTextBox*)mpScreen->search(MULTI_CHAR('item_n05'));
- strcpy(textBox->getStringPtr(), "");
+ SAFE_STRCPY(textBox->getStringPtr(), "");
textBox = (J2DTextBox*)mpScreen->search(MULTI_CHAR('item_n06'));
- strcpy(textBox->getStringPtr(), "");
+ SAFE_STRCPY(textBox->getStringPtr(), "");
textBox = (J2DTextBox*)mpScreen->search(MULTI_CHAR('item_n07'));
#endif
- strcpy(textBox->getStringPtr(), "");
+ SAFE_STRCPY(textBox->getStringPtr(), "");
}
dMenu_Collect3D_c::dMenu_Collect3D_c(JKRExpHeap* param_0, dMenu_Collect2D_c* param_1,
diff --git a/src/d/d_menu_dmap.cpp b/src/d/d_menu_dmap.cpp
index b39c9bb287..609d8ef6be 100644
--- a/src/d/d_menu_dmap.cpp
+++ b/src/d/d_menu_dmap.cpp
@@ -26,6 +26,8 @@
#include "m_Do/m_Do_graphic.h"
#include
+#include "dusk/string.hpp"
+
#if (PLATFORM_WII || PLATFORM_SHIELD)
#define POINTER_OPT dComIfGs_getOptPointer()
#else
@@ -116,9 +118,9 @@ dMenu_DmapBg_c::dMenu_DmapBg_c(JKRExpHeap* i_heap, STControl* i_stick) {
mapScreenInit();
char archive_path[32];
- strcpy(archive_path, "/res/FieldMap/D_MN10.arc");
+ SAFE_STRCPY(archive_path, "/res/FieldMap/D_MN10.arc");
char stage_name[8];
- strcpy(stage_name, dComIfGp_getStartStageName());
+ SAFE_STRCPY(stage_name, dComIfGp_getStartStageName());
archive_path[18] = stage_name[4];
archive_path[19] = stage_name[5];
@@ -135,6 +137,16 @@ dMenu_DmapBg_c::dMenu_DmapBg_c(JKRExpHeap* i_heap, STControl* i_stick) {
memset(&field_0xd80, 0, 20);
buttonIconScreenInit();
field_0xdd0 = 0;
+
+#if TARGET_PC
+ mpPoeCountIcon = JKR_NEW J2DPicture((ResTIMG*)JKRGetNameResource("ni_item_icon_pou.bti", dComIfGp_getItemIconArchive()));
+
+ mpPoeCountPane = JKR_NEW J2DTextBox();
+ if (mpPoeCountPane != nullptr) {
+ mpPoeCountPane->setFontSize(15.0f, 15.0f);
+ mpPoeCountPane->setFont(mDoExt_getMesgFont());
+ }
+#endif
}
void dMenu_DmapBg_c::mapScreenInit() {
@@ -382,7 +394,7 @@ void dMenu_DmapBg_c::setAButtonString(u32 i_msgNo) {
};
for (int i = 0; i < 5; i++) {
if (i_msgNo == 0) {
- strcpy(((J2DTextBox*)mButtonScreen->search(cont_at[i]))->getStringPtr(), "");
+ SAFE_STRCPY(((J2DTextBox*)mButtonScreen->search(cont_at[i]))->getStringPtr(), "");
} else {
dMeter2Info_getStringKanji(i_msgNo, ((J2DTextBox*)mButtonScreen->search(cont_at[i]))->getStringPtr(), NULL);
}
@@ -399,7 +411,7 @@ void dMenu_DmapBg_c::setBButtonString(u32 i_msgNo) {
};
for (int i = 0; i < 5; i++) {
if (i_msgNo == 0) {
- strcpy(((J2DTextBox*)mButtonScreen->search(cont_bt[i]))->getStringPtr(), "");
+ SAFE_STRCPY(((J2DTextBox*)mButtonScreen->search(cont_bt[i]))->getStringPtr(), "");
} else {
dMeter2Info_getStringKanji(i_msgNo, ((J2DTextBox*)mButtonScreen->search(cont_bt[i]))->getStringPtr(), NULL);
}
@@ -431,7 +443,7 @@ void dMenu_DmapBg_c::setCButtonString(u32 i_msgNo) {
if (msgNo == 0) {
for (i = 0; i < 2; i++) {
- strcpy(((J2DTextBox*)mButtonScreen->search(c_tag[i]))->getStringPtr(), "");
+ SAFE_STRCPY(((J2DTextBox*)mButtonScreen->search(c_tag[i]))->getStringPtr(), "");
}
mpCButton->setAlphaRate(0.5f);
} else {
@@ -762,6 +774,14 @@ dMenu_DmapBg_c::~dMenu_DmapBg_c() {
mDoExt_destroyExpHeap(mpTalkHeap);
mpTalkHeap = NULL;
}
+
+#if TARGET_PC
+ JKR_DELETE(mpPoeCountIcon);
+ mpPoeCountIcon = NULL;
+
+ JKR_DELETE(mpPoeCountPane);
+ mpPoeCountPane = NULL;
+#endif
}
void dMenu_DmapBg_c::setAllAlphaRate(f32 i_rate, bool param_2) {
@@ -991,7 +1011,7 @@ void dMenu_DmapBg_c::draw() {
-35.0f + (local_224.x - local_218.x),
-35.0f + (local_224.y - local_218.y));
#if TARGET_PC
- if (!dusk::getSettings().game.enableFrameInterpolation) {
+ if (!dusk::frame_interp::is_enabled()) {
field_0xdda = 0;
}
#else
@@ -1014,6 +1034,35 @@ void dMenu_DmapBg_c::draw() {
}
mButtonScreen->draw(field_0xd94, field_0xd98, grafContext);
+
+#if TARGET_PC
+ if (dusk::getSettings().game.enhancedMapMenus) {
+ int nowPoeCount = 0;
+ int totalPoeCount = 0;
+ dMenuMapCommon_c::getDmapPoeCount(dComIfGp_getStartStageName(), nowPoeCount, totalPoeCount);
+ if (dComIfGs_isEventBit(dSv_event_flag_c::F_0456) && totalPoeCount > 0) {
+ const f32 x = field_0xd94 + mDoGph_gInf_c::ScaleHUDXLeft(80.0f);
+ const f32 y = 410.0f;
+ constexpr f32 iconsize = 48.0f * 0.8f;
+
+ if (mpPoeCountIcon != nullptr)
+ mpPoeCountIcon->draw(x - 35.0f, y - 25.0f, iconsize, iconsize, false, false, false);
+
+ char counter_text[6];
+ snprintf(counter_text, sizeof(counter_text), "%d/%d", nowPoeCount, totalPoeCount);
+ mpPoeCountPane->setString(counter_text);
+
+ mpPoeCountPane->setCharColor(0x000000FF);
+ mpPoeCountPane->setGradColor(0x000000FF);
+ mpPoeCountPane->draw(x + 1, y + 1, FB_WIDTH, HBIND_LEFT);
+
+ mpPoeCountPane->setCharColor(0xC8C8C8FF);
+ mpPoeCountPane->setGradColor(0xC8C8C8FF);
+ mpPoeCountPane->draw(x, y, FB_WIDTH, HBIND_LEFT);
+ }
+ }
+#endif
+
grafContext->scissor(scissor_left, scissor_top, scissor_width, scissor_height);
grafContext->setScissor();
grafContext->setup2D();
@@ -2624,7 +2673,7 @@ void dMenu_Dmap_c::zoomIn_proc() {
void dMenu_Dmap_c::zoomOut_init_proc() {
#if TARGET_PC
- if (dusk::getSettings().game.enableFrameInterpolation) {
+ if (dusk::frame_interp::is_enabled()) {
mpDrawBg->resetScrollArrowMask();
}
#endif
diff --git a/src/d/d_menu_dmap_map.cpp b/src/d/d_menu_dmap_map.cpp
index 0bb9717952..c4029b766e 100644
--- a/src/d/d_menu_dmap_map.cpp
+++ b/src/d/d_menu_dmap_map.cpp
@@ -69,6 +69,13 @@ bool renderingDmap_c::isDrawIconSingle2(dTres_c::data_s const* i_data, bool para
JUT_ASSERT(1044, FALSE);
break;
case 5:
+#if TARGET_PC
+ if (dusk::getSettings().game.removeQuestMapMarkers &&
+ dComIfGs_isEventBit(dSv_event_flag_c::saveBitLabels[0x190]))
+ {
+ break;
+ }
+#endif
if ((i_data->mNo == 0xFF || (i_data->mNo != 0xFF && !dComIfGs_isTbox(i_data->mNo))) && (i_data->mSwBit == 0xFF || (i_data->mSwBit != 0xFF && dComIfGs_isSwitch(i_data->mSwBit, i_data->mRoomNo))) && param_1) {
rt = true;
}
@@ -352,7 +359,14 @@ f32 dMenu_StageMapCtrl_c::getPixelStageSizeZ() const {
f32 dMenu_StageMapCtrl_c::getPixelCenterX() const {
f32 var_f31 = dMpath_c::getCenterX();
+ #if TARGET_PC
+ if (dusk::getSettings().game.enableMirrorMode) {
+ return (1.0f / field_0xbc) * (field_0x9c + var_f31);
+ }
+ else return (1.0f / field_0xbc) * (field_0x9c - var_f31);
+ #else
return (1.0f / field_0xbc) * (field_0x9c - var_f31);
+ #endif
}
f32 dMenu_StageMapCtrl_c::getPixelCenterZ() const {
@@ -411,7 +425,18 @@ inline static f32 rightModeCnvPos(f32 param_0) {
void dMenu_StageMapCtrl_c::cnvPosTo2Dpos(f32 param_0, f32 param_1, f32* param_2,
f32* param_3) const {
if (param_2 != NULL) {
+ #if TARGET_PC
+ if (dusk::getSettings().game.enableMirrorMode) {
+ *param_2 =
+ (0.5f * field_0x94) + rightModeCnvPos((1.0f / field_0xbc) * (field_0x9c + param_0));
+ } else {
+ *param_2 =
+ (0.5f * field_0x94) + rightModeCnvPos((1.0f / field_0xbc) * (param_0 - field_0x9c));
+ }
+ #else
*param_2 = (0.5f * field_0x94) + rightModeCnvPos((1.0f / field_0xbc) * (param_0 - field_0x9c));
+ #endif
+
}
if (param_3 != NULL) {
@@ -908,7 +933,9 @@ void dMenu_StageMapCtrl_c::move() {
void dMenu_DmapMapCtrl_c::draw() {
if (field_0xef != 0) {
- setPos(field_0xeb, field_0xec, field_0x9c, field_0xa0, field_0xbc, true, field_0xd8);
+ setPos(field_0xeb, field_0xec,
+ IF_DUSK(dusk::getSettings().game.enableMirrorMode ? -field_0x9c :) field_0x9c,
+ field_0xa0, field_0xbc, true, field_0xd8);
}
}
diff --git a/src/d/d_menu_fishing.cpp b/src/d/d_menu_fishing.cpp
index 5e1b124b38..6a3d0aefe8 100644
--- a/src/d/d_menu_fishing.cpp
+++ b/src/d/d_menu_fishing.cpp
@@ -16,6 +16,7 @@
#include "m_Do/m_Do_graphic.h"
#include
+#include "dusk/string.hpp"
#include "dusk/version.hpp"
typedef void (dMenu_Fishing_c::*initFunc)();
@@ -372,7 +373,7 @@ void dMenu_Fishing_c::screenSetDoIcon() {
void dMenu_Fishing_c::setAButtonString(u16 i_stringID) {
if (i_stringID == 0) {
for (int i = 0; i < 5; i++) {
- strcpy(mpAButtonString[i]->getStringPtr(), "");
+ SAFE_STRCPY(mpAButtonString[i]->getStringPtr(), "");
}
} else {
for (int i = 0; i < 5; i++) {
@@ -384,7 +385,7 @@ void dMenu_Fishing_c::setAButtonString(u16 i_stringID) {
void dMenu_Fishing_c::setBButtonString(u16 i_stringID) {
if (i_stringID == 0) {
for (int i = 0; i < 5; i++) {
- strcpy(mpBButtonString[i]->getStringPtr(), "");
+ SAFE_STRCPY(mpBButtonString[i]->getStringPtr(), "");
}
} else {
for (int i = 0; i < 5; i++) {
@@ -419,29 +420,29 @@ void dMenu_Fishing_c::setFishParam(int i_fishIdx, u16 i_fishCount, u8 i_fishSize
dComIfGp_setMessageCountNumber(i_fishSize);
mpString->getString(0x597, field_0x10c[i][i_fishIdx], NULL, NULL, NULL, 0); // "inches"
char* stringPtr = field_0x10c[i][i_fishIdx]->getStringPtr();
- strcpy(strBuff1, stringPtr);
+ SAFE_STRCPY(strBuff1, stringPtr);
int j;
for (j = 0; strBuff1[j + fishSizeFigure] != 0; j++) {
strBuff2[j] = strBuff1[j + fishSizeFigure];
}
strBuff2[j] = 0;
strBuff1[fishSizeFigure] = 0;
- strcpy(field_0x10c[i][i_fishIdx]->getStringPtr(), strBuff1);
- strcpy(field_0x16c[i][i_fishIdx]->getStringPtr(), strBuff2);
+ SAFE_STRCPY(field_0x10c[i][i_fishIdx]->getStringPtr(), strBuff1);
+ SAFE_STRCPY(field_0x16c[i][i_fishIdx]->getStringPtr(), strBuff2);
// part two, i_fishCount
dComIfGp_setMessageCountNumber(i_fishCount);
mpString->getString(0x598, field_0x13c[i][i_fishIdx], NULL, NULL, NULL, 0); // "fish"
stringPtr = field_0x13c[i][i_fishIdx]->getStringPtr();
- strcpy(strBuff1, stringPtr);
+ SAFE_STRCPY(strBuff1, stringPtr);
int k;
for (k = 0; strBuff1[k + fishCountFigure] != 0; k++) {
strBuff2[k] = strBuff1[k + fishCountFigure];
}
strBuff2[k] = 0;
strBuff1[fishCountFigure] = 0;
- strcpy(field_0x13c[i][i_fishIdx]->getStringPtr(), strBuff1);
- strcpy(field_0x19c[i][i_fishIdx]->getStringPtr(), strBuff2);
+ SAFE_STRCPY(field_0x13c[i][i_fishIdx]->getStringPtr(), strBuff1);
+ SAFE_STRCPY(field_0x19c[i][i_fishIdx]->getStringPtr(), strBuff2);
}
}
diff --git a/src/d/d_menu_fmap.cpp b/src/d/d_menu_fmap.cpp
index d2b06e962c..b8a69ddc55 100644
--- a/src/d/d_menu_fmap.cpp
+++ b/src/d/d_menu_fmap.cpp
@@ -22,6 +22,7 @@
#include "d/d_msg_scrn_explain.h"
#include "d/d_stage.h"
#include "dusk/memory.h"
+#include "dusk/string.hpp"
#include "f_op/f_op_msg_mng.h"
static dMf_HIO_c g_fmHIO;
@@ -126,7 +127,7 @@ const char* dMenuFmap_getStartStageName(void* i_fieldData) {
if (!strcmp(dComIfGp_getStartStageName(), data[i].mStageName)) {
// !@bug: probably supposed to be data[i].mVirtualStageName, but doesn't matter
// because the two entries have the same virtual stage name
- strcpy(virtual_stage, data->mVirtualStageName);
+ SAFE_STRCPY(virtual_stage, data->mVirtualStageName);
return virtual_stage;
}
}
@@ -197,7 +198,7 @@ dMenu_Fmap_c::dMenu_Fmap_c(JKRExpHeap* i_heap, STControl* i_stick, CSTControl* i
mIsWarpMap = false;
mProcess = PROC_REGION_MAP;
- strcpy(mMarkedStageName, "");
+ SAFE_STRCPY(mMarkedStageName, "");
if (g_fmapHIO.mpArcData != NULL && g_fmapHIO.mpArcData->isMounted()) {
mProcess = i_process;
mpMapArchive = g_fmapHIO.mpArcData;
@@ -525,6 +526,16 @@ void dMenu_Fmap_c::_move() {
}
mpDraw2DBack->setSpotTextureFadeAlpha(mSpotTextureFadeAlpha);
}
+
+#if TARGET_PC
+ u8 region = mpDraw2DBack->getSelectRegion();
+ if (region != 0xFF && mpDraw2DBack->isShowRegion(region)) {
+ mpDraw2DTop->mSelectRegionNo = region;
+ } else {
+ mpDraw2DTop->mSelectRegionNo = 0xFF;
+ }
+
+#endif
}
void dMenu_Fmap_c::_draw() {
@@ -1146,7 +1157,7 @@ void dMenu_Fmap_c::zoom_spot_to_region_init() {
field_0x1ec = 1.0f;
#if TARGET_PC
// Frame interp note: field_0x122d used to be set every draw, causing flickering. Do it here instead.
- if (dusk::getSettings().game.enableFrameInterpolation) {
+ if (dusk::frame_interp::is_enabled()) {
mpDraw2DBack->resetScrollArrowMask();
}
#endif
@@ -1853,7 +1864,7 @@ bool dMenu_Fmap_c::isRoomCheck(int i_stageNo, int i_roomNo) {
for (; i < mDataNumMax; i++) {
if (checked_data[i]) continue;
- strcpy(stage_name, stages[i].mName);
+ SAFE_STRCPY(stage_name, stages[i].mName);
for (int k = 0; k < 64; k++) {
local_e0[k] = false;
@@ -2072,14 +2083,14 @@ bool dMenu_Fmap_c::readAreaData(u8 i_regionNo, bool i_isSelectedRegion) {
for (; i < mDataNumMax; i++) {
if (checked_data[i]) continue;
- strcpy(tmp_stage_name, mTmpStageName);
+ SAFE_STRCPY(tmp_stage_name, mTmpStageName);
resetRoomDataBit();
if (i_isSelectedRegion) {
- strcpy(mTmpStageName, stages[i].mName);
+ SAFE_STRCPY(mTmpStageName, stages[i].mName);
} else {
- strcpy(mTmpStageName, tmp_stage_name);
+ SAFE_STRCPY(mTmpStageName, tmp_stage_name);
}
- strcpy(tmp_stage_name, stages[i].mName);
+ SAFE_STRCPY(tmp_stage_name, stages[i].mName);
for (int k = 0; k < 64; k++) {
local_e0[k] = false;
@@ -2155,7 +2166,7 @@ bool dMenu_Fmap_c::readAreaData(u8 i_regionNo, bool i_isSelectedRegion) {
mpDraw2DBack->setStageOriginXZ(mSpotNum, stages[stage_index].mOffsetX,
stages[stage_index].mOffsetZ);
mAreaName[mSpotNum] = stages[stage_index].mAreaName;
- strcpy(mStageName[mSpotNum], stage_name);
+ SAFE_STRCPY(mStageName[mSpotNum], stage_name);
mSpotNum++;
}
@@ -2203,7 +2214,7 @@ bool dMenu_Fmap_c::readRoomData(char const* i_stageName, dMenu_Fmap_stage_data_c
dMenu_Fmap_stage_arc_data_c* room_data = NULL;
char stage_path[20];
- sprintf(stage_path, "%s/stage.dat", i_stageName);
+ SAFE_SPRINTF(stage_path, "%s/stage.dat", i_stageName);
if (readFieldMapData((void**)&room_data, stage_path, false, false)) {
((dMenuMapCommon_c::RoomData_c*)o_roomData)->setRoomData(room_data);
}
@@ -2217,7 +2228,7 @@ bool dMenu_Fmap_c::readRoomData(char const* i_stageName, dMenu_Fmap_stage_data_c
void* dzs_data = NULL;
char room_path[20];
- sprintf(room_path, "%s/room%d.dzs", i_stageName, room_nos[i]);
+ SAFE_SPRINTF(room_path, "%s/room%d.dzs", i_stageName, room_nos[i]);
if (readRoomDzsData(&dzs_data, 0x1500, room_path)) {
dMenu_Fmap_data_c* map_data = JKR_NEW dMenu_Fmap_data_c();
@@ -2308,9 +2319,9 @@ void dMenu_Fmap_c::decodeFieldMapData() {
bool local_3f = false;
if (j == 7) {
local_3f = true;
- sprintf(tex_path, "tex/region8.bti");
+ SAFE_SPRINTF(tex_path, "tex/region8.bti");
} else {
- sprintf(tex_path, "tex/region%d.bti", regions[i].mTextureReadNum);
+ SAFE_SPRINTF(tex_path, "tex/region%d.bti", regions[i].mTextureReadNum);
}
if (readFieldMapData((void**)&mRegionTexture[j], tex_path, true, local_3f)) {
@@ -2428,7 +2439,7 @@ bool dMenu_Fmap_c::removeAreaData() {
}
for (int i = 0; i < 20; i++) {
- strcpy(mStageName[i], "");
+ SAFE_STRCPY(mStageName[i], "");
}
field_0x305 = false;
@@ -2539,11 +2550,11 @@ void dMenu_Fmap_c::drawIcon(f32 param_0, bool param_1) {
fopAc_ac_c* player = daPy_getPlayerActorClass();
pos.set(dMapInfo_n::getMapPlayerPos());
angle = player->shape_angle.y;
- strcpy(stage_name, dMenuFmap_getStartStageName(mpFieldDat));
+ SAFE_STRCPY(stage_name, dMenuFmap_getStartStageName(mpFieldDat));
} else {
pos = dComIfGs_getPlayerFieldLastStayPos();
angle = dComIfGs_getPlayerFieldLastStayAngleY();
- strcpy(stage_name, dComIfGs_getPlayerFieldLastStayName());
+ SAFE_STRCPY(stage_name, dComIfGs_getPlayerFieldLastStayName());
}
u8 is_portal_demo1 = 0;
@@ -2600,6 +2611,13 @@ void dMenu_Fmap_c::drawLightDropIcon() {
}
void dMenu_Fmap_c::drawBatsumarkIcon() {
+#if TARGET_PC
+ if (dusk::getSettings().game.removeQuestMapMarkers &&
+ dComIfGs_isEventBit(dSv_event_flag_c::saveBitLabels[0x190]))
+ {
+ return;
+ }
+#endif
drawIcon(5, 0x12);
}
@@ -2625,11 +2643,11 @@ void dMenu_Fmap_c::drawPlayEnterIcon() {
if (dComIfGs_isPlayerFieldLastStayFieldDataExistFlag()) {
pos.set(dMapInfo_n::getMapRestartPos());
angle = dComIfGs_getRestartRoomAngleY();
- strcpy(stage_name, dMenuFmap_getStartStageName(mpFieldDat));
+ SAFE_STRCPY(stage_name, dMenuFmap_getStartStageName(mpFieldDat));
} else {
pos = dComIfGs_getPlayerFieldLastStayPos();
angle = dComIfGs_getPlayerFieldLastStayAngleY();
- strcpy(stage_name, dComIfGs_getPlayerFieldLastStayName());
+ SAFE_STRCPY(stage_name, dComIfGs_getPlayerFieldLastStayName());
}
mpDraw2DBack->setIcon2DPos(0x15, stage_name, pos.x, pos.z, cM_sht2d(angle), 0, false);
}
@@ -2771,10 +2789,10 @@ void dMenu_Fmap_c::arrowPosInit() {
char stage_name[8];
if (dComIfGs_isPlayerFieldLastStayFieldDataExistFlag()) {
pos.set(dMapInfo_n::getMapPlayerPos());
- strcpy(stage_name, dMenuFmap_getStartStageName(mpFieldDat));
+ SAFE_STRCPY(stage_name, dMenuFmap_getStartStageName(mpFieldDat));
} else {
pos = dComIfGs_getPlayerFieldLastStayPos();
- strcpy(stage_name, dComIfGs_getPlayerFieldLastStayName());
+ SAFE_STRCPY(stage_name, dComIfGs_getPlayerFieldLastStayName());
}
f32 fVar1 = 0.0f;
@@ -2827,7 +2845,7 @@ void dMenu_Fmap_c::tableArrowPosInit(bool param_0) {
}
static char* stage_name[4] = {"F_SP115", "F_SP113", "F_SP109", "F_SP108"};
- strcpy(mMarkedStageName, stage_name[iVar5]);
+ SAFE_STRCPY(mMarkedStageName, stage_name[iVar5]);
if (param_0) {
f32 pos1_x, pos2_x, pos1_z, pos2_z, icon_x, icon_z;
@@ -2856,7 +2874,7 @@ void dMenu_Fmap_c::yamibossArrowPosInit() {
void dMenu_Fmap_c::howlArrowPosInit() {
u8 type = dMeter2Info_getGoldWolfMapType();
static char* stage_name[6] = {"F_SP104", "F_SP122", "F_SP122", "F_SP124", "F_SP111", "F_SP116"};
- strcpy(mMarkedStageName, stage_name[type - 2]);
+ SAFE_STRCPY(mMarkedStageName, stage_name[type - 2]);
static const int i_swBit[6] = {0x41, 0x29, 0x2a, 0x32, 0x79, 0x32};
f32 icon_x, icon_z;
if (searchIcon(6, i_swBit[type - 2], &icon_x, &icon_z)) {
@@ -2893,10 +2911,10 @@ cXyz* dMenu_Fmap_c::getPlayerPos2D() {
char stage_name[8];
if (dComIfGs_isPlayerFieldLastStayFieldDataExistFlag()) {
pos.set(dMapInfo_n::getMapPlayerPos());
- strcpy(stage_name, dMenuFmap_getStartStageName(mpFieldDat));
+ SAFE_STRCPY(stage_name, dMenuFmap_getStartStageName(mpFieldDat));
} else {
pos = dComIfGs_getPlayerFieldLastStayPos();
- strcpy(stage_name, dComIfGs_getPlayerFieldLastStayName());
+ SAFE_STRCPY(stage_name, dComIfGs_getPlayerFieldLastStayName());
}
mpDraw2DBack->calcAllMapPos2D(stage_name, pos.x - mpDraw2DBack->getStageTransX(),
pos.z - mpDraw2DBack->getStageTransZ(),
diff --git a/src/d/d_menu_fmap2D.cpp b/src/d/d_menu_fmap2D.cpp
index d62f7d1037..cbfffc3fc2 100644
--- a/src/d/d_menu_fmap2D.cpp
+++ b/src/d/d_menu_fmap2D.cpp
@@ -437,7 +437,7 @@ void dMenu_Fmap2DBack_c::draw() {
if (field_0x122d) {
mpMeterHaihai->drawHaihai(field_0x122d);
#if TARGET_PC
- if (!dusk::getSettings().game.enableFrameInterpolation) {
+ if (!dusk::frame_interp::is_enabled()) {
field_0x122d = 0;
}
#else
@@ -1973,6 +1973,11 @@ void dMenu_Fmap2DBack_c::stageMapMove(STControl* i_stick, u8 param_1, bool param
if (stick_value >= slow_bound && param_2 && field_0x1238 != 2) {
bVar6 = true;
s16 angle = i_stick->getAngleStick();
+#if TARGET_PC
+ if (dusk::getSettings().game.enableMirrorMode) {
+ angle = -angle;
+ }
+#endif
f32 local_68 = mTexMaxX - mTexMinX;
f32 spot_zoom = getSpotMapZoomRate();
f32 region_zoom = getRegionMapZoomRate(mRegionCursor);
@@ -2482,6 +2487,18 @@ dMenu_Fmap2DTop_c::dMenu_Fmap2DTop_c(JKRExpHeap* i_heap, STControl* i_stick) {
set3DStickString(0x524);
#endif
+#if TARGET_PC
+ mpPoeCountIcon = JKR_NEW J2DPicture((ResTIMG*)JKRGetNameResource("ni_item_icon_pou.bti", dComIfGp_getItemIconArchive()));
+
+ mpPoeCountPane = JKR_NEW J2DTextBox();
+ if (mpPoeCountPane != nullptr) {
+ mpPoeCountPane->setFontSize(15.0f, 15.0f);
+ mpPoeCountPane->setFont(mDoExt_getMesgFont());
+ }
+
+ mSelectRegionNo = 0xFF;
+#endif
+
setHIO(true);
}
@@ -2540,6 +2557,14 @@ dMenu_Fmap2DTop_c::~dMenu_Fmap2DTop_c() {
}
JKR_DELETE(mpAnm);
mpAnm = NULL;
+
+#if TARGET_PC
+ JKR_DELETE(mpPoeCountIcon);
+ mpPoeCountIcon = NULL;
+
+ JKR_DELETE(mpPoeCountPane);
+ mpPoeCountPane = NULL;
+#endif
}
void dMenu_Fmap2DTop_c::_execute() {
@@ -2636,6 +2661,35 @@ void dMenu_Fmap2DTop_c::draw() {
ctx->scissor(mTransX, 0.0f, FB_WIDTH, FB_HEIGHT);
ctx->setScissor();
mpTitleScreen->draw(mTransX, mTransY, ctx);
+
+#if TARGET_PC
+ if (dusk::getSettings().game.enhancedMapMenus) {
+ int nowPoeCount = 0;
+ int totalPoeCount = 0;
+ dMenuMapCommon_c::getFmapPoeCount(mSelectRegionNo, nowPoeCount, totalPoeCount);
+ if (dComIfGs_isEventBit(dSv_event_flag_c::F_0456) && totalPoeCount > 0) {
+ const f32 x = mTransX + mDoGph_gInf_c::ScaleHUDXRight(485.0f);
+ const f32 y = 380.0f;
+ constexpr f32 iconsize = 48.0f * 0.8f;
+
+ if (mpPoeCountIcon != nullptr)
+ mpPoeCountIcon->draw(x - 35.0f, y - 25.0f, iconsize, iconsize, false, false, false);
+
+ char counter_text[6];
+ snprintf(counter_text, sizeof(counter_text), "%d/%d", nowPoeCount, totalPoeCount);
+ mpPoeCountPane->setString(counter_text);
+
+ mpPoeCountPane->setCharColor(0x000000FF);
+ mpPoeCountPane->setGradColor(0x000000FF);
+ mpPoeCountPane->draw(x + 1, y + 1, FB_WIDTH, HBIND_LEFT);
+
+ mpPoeCountPane->setCharColor(0xC8C8C8FF);
+ mpPoeCountPane->setGradColor(0xC8C8C8FF);
+ mpPoeCountPane->draw(x, y, FB_WIDTH, HBIND_LEFT);
+ }
+ }
+#endif
+
ctx->scissor(scissor_left, scissor_top, scissor_width, scissor_height);
ctx->setScissor();
if (mpScrnExplain) {
@@ -2681,7 +2735,7 @@ void dMenu_Fmap2DTop_c::setTitleNameString(u32 param_0) {
#endif
for (int i = 0; i < 7; i++) {
if (param_0 == 0) {
- strcpy(((J2DTextBox*)(mpTitleScreen->search(setTitleNameString_font_name[i])))
+ SAFE_STRCPY(((J2DTextBox*)(mpTitleScreen->search(setTitleNameString_font_name[i])))
->getStringPtr(),
"");
} else {
@@ -2704,7 +2758,7 @@ void dMenu_Fmap2DTop_c::setAreaNameString(u32 param_0) {
#endif
for (int i = 0; i < 3; i++) {
if (param_0 == 0) {
- strcpy(((J2DTextBox*)(mpTitleScreen->search(setAreaNameString_area_name[i])))
+ SAFE_STRCPY(((J2DTextBox*)(mpTitleScreen->search(setAreaNameString_area_name[i])))
->getStringPtr(),
"");
} else {
@@ -2817,7 +2871,7 @@ void dMenu_Fmap2DTop_c::setCrossLRString(u32 param_0) {
if (param_0 == 0) {
for (int i = 0; i < 5; i++) {
J2DTextBox* text_box = static_cast(mpTitleScreen->search(juji_c[i]));
- strcpy(text_box->getStringPtr(), "");
+ SAFE_STRCPY(text_box->getStringPtr(), "");
}
mpTitleScreen->search(MULTI_CHAR('juy_sha0'))->show();
mAlphaDpad = 1;
@@ -2842,7 +2896,7 @@ void dMenu_Fmap2DTop_c::set3DStickString(u32 param_0) {
if (param_0 == 0) {
for (int i = 0; i < 5; i++) {
J2DTextBox* text_box = static_cast(mpTitleScreen->search(ast_c[i]));
- strcpy(text_box->getStringPtr(), "");
+ SAFE_STRCPY(text_box->getStringPtr(), "");
}
mpTitleScreen->search(MULTI_CHAR('as_sha0'))->show();
mAlphaAnalogStick = 1;
diff --git a/src/d/d_menu_insect.cpp b/src/d/d_menu_insect.cpp
index 88e05226e8..8e6ad49b5b 100644
--- a/src/d/d_menu_insect.cpp
+++ b/src/d/d_menu_insect.cpp
@@ -352,12 +352,12 @@ void dMenu_Insect_c::explain_open_init() {
"\x1B"
"CR[%d]",
(int)(0.5f * (length - stringLength1)));
- strcat(local_b8, local_78);
+ SAFE_STRCAT(local_b8, local_78);
snprintf(cStack_d8, 32,
"\x1B"
"CR[%d]",
(int)(0.5f * (length - stringLength2)));
- strcat(cStack_d8, local_98);
+ SAFE_STRCAT(cStack_d8, local_98);
mpSelect_c->setString("", local_b8, cStack_d8);
mpSelect_c->setRubyString("", "", "");
mpSelect_c->selAnimeInit(2, field_0xf7 + 1, 0, length, 0);
@@ -730,7 +730,7 @@ u8 dMenu_Insect_c::dpdMove() {
void dMenu_Insect_c::setAButtonString(u16 i_stringID) {
if (i_stringID == 0) {
for (int i = 0; i < 5; i++) {
- strcpy(mpAButtonString[i]->getStringPtr(), "");
+ SAFE_STRCPY(mpAButtonString[i]->getStringPtr(), "");
}
} else {
for (int i = 0; i < 5; i++) {
@@ -742,7 +742,7 @@ void dMenu_Insect_c::setAButtonString(u16 i_stringID) {
void dMenu_Insect_c::setBButtonString(u16 i_stringID) {
if (i_stringID == 0) {
for (int i = 0; i < 5; i++) {
- strcpy(mpBButtonString[i]->getStringPtr(), "");
+ SAFE_STRCPY(mpBButtonString[i]->getStringPtr(), "");
}
} else {
for (int i = 0; i < 5; i++) {
diff --git a/src/d/d_menu_item_explain.cpp b/src/d/d_menu_item_explain.cpp
index dd3af54571..bebcb2cdb0 100644
--- a/src/d/d_menu_item_explain.cpp
+++ b/src/d/d_menu_item_explain.cpp
@@ -508,12 +508,12 @@ void dMenu_ItemExplain_c::move_select_init() {
"\x1B"
"CR[%d]",
(int)(0.5f * (length - stringLength1)));
- strcat(local_64, local_88);
+ SAFE_STRCAT(local_64, local_88);
snprintf(cStack78, 20,
"\x1B"
"CR[%d]",
(int)(0.5f * (length - stringLength2)));
- strcat(cStack78, local_80);
+ SAFE_STRCAT(cStack78, local_80);
mpSelect_c->setString("", local_64, cStack78);
mpSelect_c->setRubyString("", "", "");
mpSelect_c->selAnimeInit(2, field_0xe2 + 1, 0, length, 0);
diff --git a/src/d/d_menu_letter.cpp b/src/d/d_menu_letter.cpp
index 4bfda4b9cd..cd7da6a6f4 100644
--- a/src/d/d_menu_letter.cpp
+++ b/src/d/d_menu_letter.cpp
@@ -501,10 +501,10 @@ void dMenu_Letter_c::read_open_init() {
field_0x3e2 = mpString->getPageMax(D_MENU_LETTER_LINE_MAX);
if (field_0x3e2 > 1) {
char acStack_30[20];
- sprintf(acStack_30, "%d/%d", field_0x3e3, field_0x3e2);
+ SAFE_SPRINTF(acStack_30, "%d/%d", field_0x3e3, field_0x3e2);
for (int i = 0; i < 2; i++) {
field_0x1e4[i]->show();
- strcpy(field_0x1e4[i]->getStringPtr(), acStack_30);
+ SAFE_STRCPY(field_0x1e4[i]->getStringPtr(), acStack_30);
}
} else {
for (int i = 0; i < 2; i++) {
@@ -654,10 +654,10 @@ void dMenu_Letter_c::read_next_fadein_init() {
D_MENU_LETTER_LINE_MAX, text2, text1, NULL, NULL, 0);
}
char acStack_30[10];
- sprintf(acStack_30, "%d/%d", field_0x3e3, field_0x3e2);
+ SAFE_SPRINTF(acStack_30, "%d/%d", field_0x3e3, field_0x3e2);
for (int i = 0; i < 2; i++) {
field_0x1e4[i]->show();
- strcpy(field_0x1e4[i]->getStringPtr(), acStack_30);
+ SAFE_STRCPY(field_0x1e4[i]->getStringPtr(), acStack_30);
}
}
@@ -1273,7 +1273,7 @@ void dMenu_Letter_c::copyDMYMenu() {
void dMenu_Letter_c::setAButtonString(u16 i_stringID) {
if (i_stringID == 0) {
for (int i = 0; i < 5; i++) {
- strcpy(mpAButtonString[i]->getStringPtr(), "");
+ SAFE_STRCPY(mpAButtonString[i]->getStringPtr(), "");
}
} else {
for (int i = 0; i < 5; i++) {
@@ -1286,7 +1286,7 @@ void dMenu_Letter_c::setAButtonString(u16 i_stringID) {
void dMenu_Letter_c::setBButtonString(u16 i_stringID) {
if (i_stringID == 0) {
for (int i = 0; i < 5; i++) {
- strcpy(mpBButtonString[i]->getStringPtr(), "");
+ SAFE_STRCPY(mpBButtonString[i]->getStringPtr(), "");
}
} else {
for (int i = 0; i < 5; i++) {
diff --git a/src/d/d_menu_map_common.cpp b/src/d/d_menu_map_common.cpp
index 0017975c4e..5ae820931a 100644
--- a/src/d/d_menu_map_common.cpp
+++ b/src/d/d_menu_map_common.cpp
@@ -394,8 +394,21 @@ void dMenuMapCommon_c::drawIcon(f32 i_posX, f32 i_posY, f32 param_3, f32 param_4
icon_size_y *= _c7c;
}
+#if TARGET_PC
+ f32 rotation = mIconInfo[info_idx].rotation;
+ if (dusk::getSettings().game.enableMirrorMode &&
+ (mIconInfo[info_idx].icon_no == ICON_LINK_e ||
+ mIconInfo[info_idx].icon_no == ICON_LINK_ENTER_e))
+ {
+ rotation = -rotation;
+ }
+
+ mPictures[mIconInfo[info_idx].icon_no]->rotate(icon_size_x / 2, icon_size_y / 2, ROTATE_Z,
+ rotation);
+#else
mPictures[mIconInfo[info_idx].icon_no]->rotate(icon_size_x / 2, icon_size_y / 2, ROTATE_Z,
mIconInfo[info_idx].rotation);
+#endif
if (mIconInfo[info_idx].icon_no == ICON_LIGHT_DROP_e) {
mPictures[mIconInfo[info_idx].icon_no]->setAlpha((180.0f * _c80) / 255.0f);
@@ -747,3 +760,113 @@ void dMenuMapCommon_c::debugIcon() {
setIconInfo(ICON_LV8_WARP_e, pos_x, pos_y, 0.0f, scale, 1.0f, 1);
}
}
+
+#if TARGET_PC
+static constexpr struct {
+ std::string_view stagename;
+ u8 switch_no;
+ s8 region_id;
+ u8 save_id;
+} l_poeInfo[] = {
+ // Dungeons
+ {"D_MN06", 0x19, -1, 0x15},
+ {"D_MN06", 0x18, -1, 0x15},
+ {"D_MN07", 0x54, -1, 0x16},
+ {"D_MN07", 0x55, -1, 0x16},
+ {"D_MN10", 0x1E, -1, 0x13},
+ {"D_MN10", 0x1F, -1, 0x13},
+ {"D_MN10", 0x20, -1, 0x13},
+ {"D_MN10", 0x21, -1, 0x13},
+ {"D_MN11", 0x72, -1, 0x14},
+ {"D_MN11", 0x15, -1, 0x14},
+ {"D_MN11", 0x7F, -1, 0x14},
+
+ // Sub-Dungeons
+ {"D_SB01", 0x45, 4, 0x19},
+ {"D_SB01", 0x46, 4, 0x19},
+ {"D_SB01", 0x47, 4, 0x19},
+ {"D_SB02", 0x60, 2, 0x19},
+ {"D_SB03", 0x5E, 3, 0x1A},
+ {"D_SB03", 0x5F, 3, 0x1A},
+ {"D_SB03", 0x5D, 3, 0x1A},
+ {"D_SB05", 0xA, 3, 0x1B},
+ {"D_SB05", 0xB, 3, 0x1B},
+ {"D_SB07", 0xF, 4, 0x1B},
+ {"D_SB07", 0x10, 4, 0x1B},
+
+ // Field Spots
+ {"F_SP108", 0x5D, 1, 0x2},
+ {"F_SP109", 0x5E, 2, 0x3},
+ {"F_SP109", 0x5F, 2, 0x3},
+ {"F_SP110", 0x59, 2, 0x3},
+ {"F_SP111", 0x57, 2, 0x3},
+ {"F_SP111", 0x58, 2, 0x3},
+ {"F_SP113", 0x49, 3, 0x4},
+ {"F_SP113", 0x4A, 3, 0x4},
+ {"F_SP114", 0x7C, 5, 0x8},
+ {"F_SP114", 0x7D, 5, 0x8},
+ {"F_SP114", 0x7B, 5, 0x8},
+ {"F_SP114", 0x7E, 5, 0x8},
+ {"F_SP114", 0x7F, 5, 0x8},
+ {"F_SP115", 0x46, 3, 0x4},
+ {"F_SP115", 0x47, 3, 0x4},
+ {"F_SP115", 0x4B, 3, 0x4},
+ {"F_SP115", 0x4C, 3, 0x4},
+ {"F_SP115", 0x4D, 3, 0x4},
+ {"F_SP117", 0xF, 1, 0x7},
+ {"F_SP117", 0x1E, 1, 0x7},
+ {"F_SP117", 0x10, 1, 0x7},
+ {"F_SP117", 0x11, 1, 0x7},
+ {"F_SP118", 0x78, 4, 0xA},
+ {"F_SP118", 0x5A, 4, 0xA},
+ {"F_SP121", 0x3A, 2, 0x6},
+ {"F_SP121", 0x39, 1, 0x6},
+ {"F_SP121", 0x33, 3, 0x6},
+ {"F_SP121", 0x3B, 3, 0x6},
+ {"F_SP122", 0x49, 3, 0x6},
+ {"F_SP122", 0x30, 3, 0x6},
+ {"F_SP122", 0x47, 3, 0x6},
+ {"F_SP124", 0x5B, 4, 0xA},
+ {"F_SP124", 0x5C, 4, 0xA},
+ {"F_SP124", 0x5D, 4, 0xA},
+ {"F_SP124", 0x33, 4, 0xA},
+ {"F_SP126", 0x48, 3, 0x4},
+ {"F_SP128", 0x40, 2, 0x3},
+ {"R_SP160", 0x1F, 3, 0x9},
+};
+
+void dMenuMapCommon_c::getDmapPoeCount(const std::string& stageName, int& nowCount, int& totalCount) {
+ nowCount = 0;
+ totalCount = 0;
+
+ for (const auto& i : l_poeInfo) {
+ if (stageName == i.stagename) {
+ if (dStage_stagInfo_GetSaveTbl(dComIfGp_getStageStagInfo()) == i.save_id) {
+ nowCount += dComIfGs_isSwitch(i.switch_no, -1);
+ } else {
+ nowCount += dComIfGs_isSaveSwitch(i.save_id, i.switch_no);
+ }
+ totalCount++;
+ }
+ }
+}
+
+void dMenuMapCommon_c::getFmapPoeCount(const int regionNo, int& nowCount, int& totalCount) {
+ nowCount = 0;
+ totalCount = 0;
+
+ if (regionNo < 0)
+ return;
+
+ for (const auto& i : l_poeInfo) {
+ if (regionNo == i.region_id) {
+ if (dStage_stagInfo_GetSaveTbl(dComIfGp_getStageStagInfo()) == i.save_id) {
+ nowCount += dComIfGs_isSwitch(i.switch_no, -1);
+ } else {
+ nowCount += dComIfGs_isSaveSwitch(i.save_id, i.switch_no);
+ }
+ totalCount++;
+ }
+ }
+}
+#endif
\ No newline at end of file
diff --git a/src/d/d_menu_option.cpp b/src/d/d_menu_option.cpp
index af322a1c01..62f30d2d99 100644
--- a/src/d/d_menu_option.cpp
+++ b/src/d/d_menu_option.cpp
@@ -2107,7 +2107,7 @@ void dMenu_Option_c::setAButtonString(u16 i_stringID) {
if (stringId == 0) {
for (int i = 0; i < 5; i++) {
J2DTextBox* textBox = (J2DTextBox*)mpScreenIcon->search(text_a_tag[i]);
- strcpy(textBox->getStringPtr(), "");
+ SAFE_STRCPY(textBox->getStringPtr(), "");
}
} else {
for (int i = 0; i < 5; i++) {
@@ -2127,7 +2127,7 @@ void dMenu_Option_c::setBButtonString(u16 i_stringID) {
if (stringId == 0) {
for (int i = 0; i < 5; i++) {
J2DTextBox* textBox = (J2DTextBox*)mpScreenIcon->search(text_b_tag[i]);
- strcpy(textBox->getStringPtr(), "");
+ SAFE_STRCPY(textBox->getStringPtr(), "");
}
} else {
for (int i = 0; i < 5; i++) {
diff --git a/src/d/d_menu_ring.cpp b/src/d/d_menu_ring.cpp
index ba2b86b760..5cdb8fbc04 100644
--- a/src/d/d_menu_ring.cpp
+++ b/src/d/d_menu_ring.cpp
@@ -1203,7 +1203,7 @@ void dMenu_Ring_c::setNameString(u32 i_stringID) {
if (mNameStringID != i_stringID) {
for (int i = 0; i < 4; i++) {
if (i_stringID == 0) {
- strcpy(textBox[i]->getStringPtr(), "");
+ SAFE_STRCPY(textBox[i]->getStringPtr(), "");
} else {
mpString->getString(i_stringID, textBox[i], NULL, NULL, NULL, 0);
}
diff --git a/src/d/d_menu_save.cpp b/src/d/d_menu_save.cpp
index 53dbe37ca4..d73e4ff5e8 100644
--- a/src/d/d_menu_save.cpp
+++ b/src/d/d_menu_save.cpp
@@ -816,8 +816,8 @@ void dMenu_save_c::saveQuestion() {
field_0x9c = 0;
field_0x17a = 0;
- strcpy(mpHeaderTxt[mHeaderTxtType], "");
- strcpy(mpHeaderTxt[mHeaderTxtType ^ 1], "");
+ SAFE_STRCPY(mpHeaderTxt[mHeaderTxtType], "");
+ SAFE_STRCPY(mpHeaderTxt[mHeaderTxtType ^ 1], "");
field_0x64 = 0;
field_0x50 = 1;
field_0x40->setFrame(field_0x50);
@@ -2033,7 +2033,7 @@ void dMenu_save_c::saveYesNoCancelMove() {
void dMenu_save_c::headerTxtSet(u16 msgID) {
if (msgID == 0xFFFF) {
- strcpy(mpHeaderTxt[mHeaderTxtType ^ 1], "");
+ SAFE_STRCPY(mpHeaderTxt[mHeaderTxtType ^ 1], "");
} else {
mSaveSel.mMsgString->getString(
msgID, (J2DTextBox*)mpHeaderTxtPane[mHeaderTxtType ^ 1]->getPanePtr(), NULL,
@@ -2230,7 +2230,7 @@ void dMenu_save_c::errYesNoCursorMoveAnm() {
void dMenu_save_c::errorTxtSet(u16 msgID) {
if (msgID == 0xFFFF) {
- strcpy(mpErrTxt[mErrTxtType ^ 1], "");
+ SAFE_STRCPY(mpErrTxt[mErrTxtType ^ 1], "");
} else {
J2DTextBox* tbox = (J2DTextBox*)mpErrTxtPane[mErrTxtType ^ 1]->getPanePtr();
mSaveSel.mMsgString->getString(msgID, tbox, NULL, mSaveSel.font[0], NULL, 0);
@@ -2817,7 +2817,7 @@ void dMenu_save_c::menuSaveWide() {
#if TARGET_PC
if (mSelIcon) {
- mSelIcon->refreshAspectScale();
+ mSelIcon->refreshAspectScale(mDoGph_gInf_c::hudAspectScaleUp);
}
#endif
}
diff --git a/src/d/d_menu_skill.cpp b/src/d/d_menu_skill.cpp
index 78ab82af94..2692d33c3f 100644
--- a/src/d/d_menu_skill.cpp
+++ b/src/d/d_menu_skill.cpp
@@ -610,7 +610,7 @@ void dMenu_Skill_c::setPageText() {
void dMenu_Skill_c::setAButtonString(u16 i_stringID) {
if (i_stringID == 0) {
for (int i = 0; i < 5; i++) {
- strcpy(mpAButtonString[i]->getStringPtr(), "");
+ SAFE_STRCPY(mpAButtonString[i]->getStringPtr(), "");
}
} else {
for (int i = 0; i < 5; i++) {
@@ -622,7 +622,7 @@ void dMenu_Skill_c::setAButtonString(u16 i_stringID) {
void dMenu_Skill_c::setBButtonString(u16 i_stringID) {
if (i_stringID == 0) {
for (int i = 0; i < 5; i++) {
- strcpy(mpBButtonString[i]->getStringPtr(), "");
+ SAFE_STRCPY(mpBButtonString[i]->getStringPtr(), "");
}
} else {
for (int i = 0; i < 5; i++) {
@@ -634,7 +634,7 @@ void dMenu_Skill_c::setBButtonString(u16 i_stringID) {
void dMenu_Skill_c::setNameString(u16 i_stringID) {
if (i_stringID == 0) {
for (int i = 0; i < 4; i++) {
- strcpy(mpNameString[i]->getStringPtr(), "");
+ SAFE_STRCPY(mpNameString[i]->getStringPtr(), "");
}
} else {
for (int i = 0; i < 4; i++) {
diff --git a/src/d/d_meter2_draw.cpp b/src/d/d_meter2_draw.cpp
index 8e824f583b..3c342ea7d4 100644
--- a/src/d/d_meter2_draw.cpp
+++ b/src/d/d_meter2_draw.cpp
@@ -2245,11 +2245,11 @@ void dMeter2Draw_c::drawButtonA(u8 i_action, f32 i_posX, f32 i_posY, f32 i_textP
mp_string = getActionString(0x15, 1, NULL);
for (int i = 0; i < 5; i++) {
- strcpy(static_cast(mpAText[i]->getPanePtr())->getStringPtr(), mp_string);
+ SAFE_STRCPY(static_cast(mpAText[i]->getPanePtr())->getStringPtr(), mp_string);
}
} else {
for (int i = 0; i < 5; i++) {
- strcpy(static_cast(mpAText[i]->getPanePtr())->getStringPtr(), mp_string);
+ SAFE_STRCPY(static_cast(mpAText[i]->getPanePtr())->getStringPtr(), mp_string);
}
}
@@ -2308,7 +2308,7 @@ void dMeter2Draw_c::drawButtonB(u8 i_action, bool param_1, f32 i_posX, f32 i_pos
JUT_ASSERT(0, strlen(mp_string) < (64));
for (int i = 0; i < 5; i++) {
- strcpy(static_cast(mpBText[i]->getPanePtr())->getStringPtr(), mp_string);
+ SAFE_STRCPY(static_cast(mpBText[i]->getPanePtr())->getStringPtr(), mp_string);
}
if (i_action == 0x26 || i_action == 0x2E) {
@@ -2391,7 +2391,7 @@ void dMeter2Draw_c::drawButtonZ(u8 i_action) {
JUT_ASSERT(0, strlen(mp_string) < (64));
for (int i = 0; i < 5; i++) {
- strcpy(static_cast(mpXYText[i][2]->getPanePtr())->getStringPtr(), mp_string);
+ SAFE_STRCPY(static_cast(mpXYText[i][2]->getPanePtr())->getStringPtr(), mp_string);
}
mpButtonXY[2]->scale(g_drawHIO.mButtonZScale, g_drawHIO.mButtonZScale);
@@ -2490,7 +2490,7 @@ void dMeter2Draw_c::drawButtonXY(int i_no, u8 i_itemNo, u8 i_action, bool param_
JUT_ASSERT(0, strlen(mp_string) < (64));
for (int i = 0; i < 5; i++) {
- strcpy(static_cast(mpXYText[i][i_no]->getPanePtr())->getStringPtr(),
+ SAFE_STRCPY(static_cast(mpXYText[i][i_no]->getPanePtr())->getStringPtr(),
mp_string);
}
@@ -3243,7 +3243,7 @@ char* dMeter2Draw_c::getActionString(u8 i_action, u8 i_type, u8* param_2) {
};
static char i_text_buf[32];
- strcpy(i_text_buf, "");
+ SAFE_STRCPY(i_text_buf, "");
if (param_2 != NULL) {
*param_2 = 1;
diff --git a/src/d/d_meter2_info.cpp b/src/d/d_meter2_info.cpp
index ba527c7685..31d381a154 100644
--- a/src/d/d_meter2_info.cpp
+++ b/src/d/d_meter2_info.cpp
@@ -15,6 +15,8 @@
#include
+#include "dusk/string.hpp"
+
enum ITEMICON_RES_FILE_ID {
ITEMICON_BTI_ARI_MESU_00=0x3,
ITEMICON_BTI_ARI_OSU_00=0x4,
@@ -350,8 +352,8 @@ void dMeter2Info_c::decMsgKeyWaitTimer() {
}
}
-void dMeter2Info_c::getString(u32 i_stringID, char* o_string, JMSMesgEntry_c* i_msgEntry) {
- strcpy(o_string, "");
+void dMeter2Info_c::getString(u32 i_stringID, TEXT_SPAN o_string, JMSMesgEntry_c* i_msgEntry) {
+ SAFE_STRCPY(o_string, "");
u8* msgRes;
if (mMsgResource == NULL) {
@@ -372,7 +374,7 @@ void dMeter2Info_c::getString(u32 i_stringID, char* o_string, JMSMesgEntry_c* i_
// check if i_stringID equals the message entry "Message ID"
if (i_stringID == bmg_inf->entries[i].message_id) {
string_ptr = (char*)(string_data + bmg_inf->entries[i].string_offset); // use entry "String Offset" to get string pointer
- strcpy(o_string, string_ptr);
+ SAFE_STRCPY(o_string, string_ptr);
if (i_msgEntry != NULL) {
memcpy(i_msgEntry, &bmg_inf->entries[i], sizeof(JMSMesgEntry_c));
@@ -387,8 +389,8 @@ void dMeter2Info_c::getString(u32 i_stringID, char* o_string, JMSMesgEntry_c* i_
}
}
-void dMeter2Info_c::getStringKana(u32 i_stringID, char* o_string, JMSMesgEntry_c* i_msgEntry) {
- strcpy(o_string, "");
+void dMeter2Info_c::getStringKana(u32 i_stringID, TEXT_SPAN o_string, JMSMesgEntry_c* i_msgEntry) {
+ SAFE_STRCPY(o_string, "");
u8* msgRes;
if (mMsgResource == NULL) {
@@ -456,8 +458,8 @@ void dMeter2Info_c::getStringKana(u32 i_stringID, char* o_string, JMSMesgEntry_c
}
}
-void dMeter2Info_c::getStringKanji(u32 i_stringID, char* o_string, JMSMesgEntry_c* i_msgEntry) {
- strcpy(o_string, "");
+void dMeter2Info_c::getStringKanji(u32 i_stringID, TEXT_SPAN o_string, JMSMesgEntry_c* i_msgEntry) {
+ SAFE_STRCPY(o_string, "");
u8* msgRes;
if (mMsgResource == NULL) {
@@ -668,7 +670,7 @@ void dMeter2Info_c::resetMeterString() {
void dMeter2Info_c::setWarpInfo(const char* i_stageName, const cXyz& i_position, s16 i_angle,
u8 i_roomNo, u8 param_4, u8 i_warpPlayerNo) {
- strcpy(mWarpInfo.mStageName, i_stageName);
+ SAFE_STRCPY(mWarpInfo.mStageName, i_stageName);
mWarpInfo.mPosition = i_position;
mWarpInfo.mAngle = (s16)i_angle;
mWarpInfo.mRoomNo = (u8)i_roomNo;
@@ -1592,7 +1594,7 @@ void dMeter2Info_c::setMiniGameCount(s8 i_count) {
}
void dMeter2Info_c::setSaveStageName(const char* i_stageName) {
- strcpy(mSaveStageName, i_stageName);
+ SAFE_STRCPY(mSaveStageName, i_stageName);
}
s16 dMeter2Info_getNowLifeGauge() {
diff --git a/src/d/d_meter_button.cpp b/src/d/d_meter_button.cpp
index e55b42bc1a..1f47969f47 100644
--- a/src/d/d_meter_button.cpp
+++ b/src/d/d_meter_button.cpp
@@ -18,6 +18,11 @@
#include "d/d_pane_class.h"
#include "dusk/frame_interpolation.h"
#include
+#if TARGET_PC
+#include "dusk/string.hpp"
+#endif
+
+#include "dusk/string.hpp"
#if VERSION == VERSION_GCN_JPN
#define STR_BUF_LEN 528
@@ -254,7 +259,7 @@ void dMeterButton_c::draw() {
if (mMsgID != 0xFFFF) {
char tmp_buf[STR_BUF_LEN];
- strcpy(tmp_buf, static_cast(mpTm_c[0]->getPanePtr())->getStringPtr());
+ SAFE_STRCPY(tmp_buf, static_cast(mpTm_c[0]->getPanePtr())->getStringPtr());
mpTextScreen->draw(0.0f, 0.0f, graf_ctx);
#if VERSION == VERSION_GCN_JPN
@@ -265,7 +270,7 @@ void dMeterButton_c::draw() {
NULL, 8);
#endif
mpString_c->drawOutFont(static_cast(mpTm_c[0]->getPanePtr()), -1.0f);
- strcpy(static_cast(mpTm_c[0]->getPanePtr())->getStringPtr(), tmp_buf);
+ SAFE_STRCPY(static_cast(mpTm_c[0]->getPanePtr())->getStringPtr(), tmp_buf);
}
for (int i = 0; i < 2; i++) {
@@ -1207,7 +1212,7 @@ void dMeterButton_c::screenInitButton() {
field_0x360 = mpTextBox[0]->getBounds().i.x;
for (int i = 0; i < 2; i++) {
- strcpy(mButtonText[i], "");
+ SAFE_STRCPY(mButtonText[i], "");
field_0x2e8[i] = 0.0f;
field_0x4be[i] = BUTTON_NONE_e;
field_0x2f4[i] = 0.0f;
@@ -1903,12 +1908,12 @@ void dMeterButton_c::updateText(u32 i_flags) {
if (getString)
{
mMsgID = dMeter2Info_getFloatingMessageID();
- strcpy(static_cast(mpTm_c[0]->getPanePtr())->getStringPtr(), buf1);
- strcpy(static_cast(mpTm_c[1]->getPanePtr())->getStringPtr(), buf3);
+ SAFE_STRCPY(static_cast(mpTm_c[0]->getPanePtr())->getStringPtr(), buf1);
+ SAFE_STRCPY(static_cast(mpTm_c[1]->getPanePtr())->getStringPtr(), buf3);
for (int i = 0; i < 2; i++) {
if (field_0x0ec[i] != NULL) {
- strcpy(
+ SAFE_STRCPY(
static_cast(field_0x0ec[i]->getPanePtr())->getStringPtr(),
buf2);
}
@@ -3020,7 +3025,7 @@ void dMeterButton_c::setString(char* i_string, u8 i_button, u8 param_2, u8 param
}
}
- strcpy(mButtonText[param_2], i_string);
+ SAFE_STRCPY(mButtonText[param_2], i_string);
if (param_2 == 0) {
if (param_3 != 0) {
@@ -3030,7 +3035,7 @@ void dMeterButton_c::setString(char* i_string, u8 i_button, u8 param_2, u8 param
}
for (int i = 0; i < 5; i++) {
- strcpy(mpTextBox[i]->getStringPtr(), i_string);
+ SAFE_STRCPY(mpTextBox[i]->getStringPtr(), i_string);
}
return;
}
@@ -3042,7 +3047,7 @@ void dMeterButton_c::setString(char* i_string, u8 i_button, u8 param_2, u8 param
}
for (int i = 0; i < 5; i++) {
- strcpy(mpTextBox[5 + i]->getStringPtr(), i_string);
+ SAFE_STRCPY(mpTextBox[5 + i]->getStringPtr(), i_string);
}
}
@@ -3297,7 +3302,7 @@ void dMeterButton_c::hide_button(u8 i_button) {
field_0x4b8[1] = 0;
field_0x4bc[1] = 0;
- strcpy(mButtonText[1], "");
+ SAFE_STRCPY(mButtonText[1], "");
mpText[0]->alphaAnimeStart(mpText[1]->getAlphaTimer());
mpText[0]->setAlphaRate(mpText[1]->getAlphaRate());
mpText[1]->alphaAnimeStart(0);
@@ -3307,14 +3312,14 @@ void dMeterButton_c::hide_button(u8 i_button) {
field_0x4be[0] = BUTTON_NONE_e;
field_0x4b8[0] = 0;
field_0x4bc[0] = 0;
- strcpy(mButtonText[0], "");
+ SAFE_STRCPY(mButtonText[0], "");
}
} else if (field_0x4be[1] == i_button) {
field_0x4be[1] = BUTTON_NONE_e;
field_0x4b8[1] = 0;
field_0x4bc[1] = 0;
field_0x2f4[0] = 0.0f;
- strcpy(mButtonText[1], "");
+ SAFE_STRCPY(mButtonText[1], "");
}
}
diff --git a/src/d/d_meter_string.cpp b/src/d/d_meter_string.cpp
index c28d6d5481..c99e7c564e 100644
--- a/src/d/d_meter_string.cpp
+++ b/src/d/d_meter_string.cpp
@@ -186,8 +186,8 @@ int dMeterString_c::_delete() {
int dMeterString_c::createString(int i_stringID) {
char str_buf[32];
dMeter2Info_getString(i_stringID, str_buf, NULL);
- strcpy(static_cast(mpScreen->search(MULTI_CHAR('get_in_s')))->getStringPtr(), str_buf);
- strcpy(static_cast(mpScreen->search(MULTI_CHAR('get_in')))->getStringPtr(), str_buf);
+ SAFE_STRCPY(static_cast(mpScreen->search(MULTI_CHAR('get_in_s')))->getStringPtr(), str_buf);
+ SAFE_STRCPY(static_cast(mpScreen->search(MULTI_CHAR('get_in')))->getStringPtr(), str_buf);
mAnimFrame = 40.0f;
mPikariAnimFrame = -1.0f;
diff --git a/src/d/d_model.cpp b/src/d/d_model.cpp
index 80dfbc0953..36e77e55fa 100644
--- a/src/d/d_model.cpp
+++ b/src/d/d_model.cpp
@@ -45,6 +45,20 @@ void dMdl_c::create(J3DModelData* i_modelData, u16 i_materialId, dKy_tevstr_c* i
}
void dMdl_c::entryObj(dMdl_obj_c* i_obj) {
+#ifdef TARGET_PC
+ // if field_0x1a is false, this dMdl_c is not in the drawlist
+ // if true, we need to make sure with interp enabled
+ if (dusk::frame_interp::is_enabled() && field_0x1a) {
+ auto pkt = dComIfGd_getListPacket()->mpBuffer[0];
+ while (pkt && pkt != this) {
+ pkt = pkt->getNextPacket();
+ }
+ if (!pkt) {
+ field_0x1a = false;
+ }
+ }
+#endif
+
if (!field_0x1a) {
dComIfGd_getListPacket()->entryImm(this, 0);
field_0x1a = true;
diff --git a/src/d/d_msg_class.cpp b/src/d/d_msg_class.cpp
index f67d6054e6..01d2ab48e6 100644
--- a/src/d/d_msg_class.cpp
+++ b/src/d/d_msg_class.cpp
@@ -308,33 +308,33 @@ static u8 getOutFontNumberType(int param_0) {
}
#if TARGET_PC || VERSION == VERSION_GCN_PAL
-static void setPlayerName(char* i_player_name, u8 param_2) {
+static void setPlayerName(TEXT_SPAN i_player_name, u8 param_2) {
if (param_2 != 0) {
- strcpy(i_player_name, dComIfGs_getPlayerName());
+ SAFE_STRCPY(i_player_name, dComIfGs_getPlayerName());
u32 name_length = strlen(i_player_name);
char last = i_player_name[name_length - 1];
if (last == 0x73 || last == 0x53 || last == 0x7a || last == 0x5a || last == 0x78 || last == 0x58 || last == 0xdf) {
- strcat(i_player_name, "'");
+ SAFE_STRCAT(i_player_name, "'");
} else {
- strcat(i_player_name, "s");
+ SAFE_STRCAT(i_player_name, "s");
}
} else {
- strcpy(i_player_name, dComIfGs_getPlayerName());
+ SAFE_STRCPY(i_player_name, dComIfGs_getPlayerName());
}
}
-static void setHorseName(char* i_horse_name, u8 param_2) {
+static void setHorseName(TEXT_SPAN i_horse_name, u8 param_2) {
if (param_2 != 0) {
- strcpy(i_horse_name, dComIfGs_getHorseName());
+ SAFE_STRCPY(i_horse_name, dComIfGs_getHorseName());
u32 name_length = strlen(i_horse_name);
char last = i_horse_name[name_length - 1];
if (last == 0x73 || last == 0x53 || last == 0x7a || last == 0x5a || last == 0x78 || last == 0x58 || last == 0xdf) {
- strcat(i_horse_name, "'");
+ SAFE_STRCAT(i_horse_name, "'");
} else {
- strcat(i_horse_name, "s");
+ SAFE_STRCAT(i_horse_name, "s");
}
} else {
- strcpy(i_horse_name, dComIfGs_getHorseName());
+ SAFE_STRCPY(i_horse_name, dComIfGs_getHorseName());
}
}
#endif
@@ -707,7 +707,7 @@ void jmessage_tReference::inputNumber() {
getObjectPtr()->setInputValue(new_input_val);
}
-char* jmessage_tReference::getWord(int i_no) {
+TEXT_SPAN jmessage_tReference::getWord(int i_no) {
if (i_no >= 10) {
JUT_WARN(1093, "%s", "message stack over!!");
JUT_ASSERT(1094, i_no < (10));
@@ -1093,14 +1093,14 @@ bool jmessage_tMeasureProcessor::do_tag(u32 i_tag, void const* i_data, u32 i_siz
case MSGTAG_CURRENT_LETTER_PAGE: {
char buffer[4];
int number = dComIfGp_getMessageCountNumber() / 100;
- sprintf(buffer, "%d", number);
+ SAFE_SPRINTF(buffer, "%d", number);
push_word(buffer);
return true;
}
case MSGTAG_MAX_LETTER_PAGE: {
char buffer[4];
int number = dComIfGp_getMessageCountNumber() % 100;
- sprintf(buffer, "%d", number);
+ SAFE_SPRINTF(buffer, "%d", number);
push_word(buffer);
return true;
}
@@ -1120,7 +1120,7 @@ bool jmessage_tMeasureProcessor::do_tag(u32 i_tag, void const* i_data, u32 i_siz
}
char player_name[100];
- strcpy(player_name, dComIfGs_getPlayerName());
+ SAFE_STRCPY(player_name, dComIfGs_getPlayerName());
push_word(player_name);
return true;
}
@@ -1130,7 +1130,7 @@ bool jmessage_tMeasureProcessor::do_tag(u32 i_tag, void const* i_data, u32 i_siz
}
char horse_name[100];
- strcpy(horse_name, dComIfGs_getHorseName());
+ SAFE_STRCPY(horse_name, dComIfGs_getHorseName());
push_word(horse_name);
return true;
}
@@ -1779,7 +1779,7 @@ void jmessage_tMeasureProcessor::do_rubyset(void const* i_data, u32 i_size) {
void jmessage_tMeasureProcessor::push_word(char* i_word) {
jmessage_tReference* pReference = (jmessage_tReference*)getReference();
- strcpy(pReference->getWord(field_0x4b), i_word);
+ SAFE_STRCPY(pReference->getWord(field_0x4b), i_word);
stack_pushCurrent(pReference->getWord(field_0x4b));
field_0x4b++;
}
@@ -2403,7 +2403,7 @@ bool jmessage_tSequenceProcessor::do_tag(u32 i_tag, void const* i_data, u32 i_si
u8 sel_bomb_num = objectPtr->getSelectBombNum();
dMsgUnit_setTag(7, sel_bomb_num, buffer);
- strcpy((char*)pReference->getWord(field_0xb5), buffer);
+ SAFE_STRCPY((TEXT_SPAN)pReference->getWord(field_0xb5), buffer);
push_word();
return true;
}
@@ -2413,7 +2413,7 @@ bool jmessage_tSequenceProcessor::do_tag(u32 i_tag, void const* i_data, u32 i_si
s16 sel_bomb_price = objectPtr->getSelectBombPrice();
dMsgUnit_setTag(1, sel_bomb_price, buffer);
- strcpy((char*)pReference->getWord(field_0xb5), buffer);
+ SAFE_STRCPY((TEXT_SPAN)pReference->getWord(field_0xb5), buffer);
push_word();
return true;
}
@@ -2760,13 +2760,13 @@ void jmessage_tRenderingProcessor::do_begin(void const* pEntry, char const* pszT
}
field_0x11c = 0;
- strcpy(pReference->getTextPtr(), "");
- strcpy(pReference->getTextSPtr(), "");
- strcpy(pReference->getRubyPtr(), "");
+ SAFE_STRCPY(pReference->getTextPtr(), "");
+ SAFE_STRCPY(pReference->getTextSPtr(), "");
+ SAFE_STRCPY(pReference->getRubyPtr(), "");
for (int i = 0; i < 3; i++) {
- strcpy(pReference->getSelTextPtr(i), "");
- strcpy(pReference->getSelRubyPtr(i), "");
+ SAFE_STRCPY(pReference->getSelTextPtr(i), "");
+ SAFE_STRCPY(pReference->getSelRubyPtr(i), "");
}
if (1.0f != pReference->getDistanceScale()) {
@@ -2791,12 +2791,12 @@ void jmessage_tRenderingProcessor::do_end() {
if (dMsgObject_getSelectWordFlag() != 0) {
for (int i = 0; i < dMsgObject_getSelectWordFlag(); i++) {
char buffer[200];
- strcpy(buffer, dMsgObject_getSelectWord(i));
+ SAFE_STRCPY(buffer, dMsgObject_getSelectWord(i));
if (pReference->getSelectNum() == 2) {
- strcat(pReference->getSelTextPtr(i + 1), buffer);
+ SAFE_STRCAT(pReference->getSelTextPtr(i + 1), buffer);
} else if (pReference->getSelectNum() == 3) {
- strcat(pReference->getSelTextPtr(i), buffer);
+ SAFE_STRCAT(pReference->getSelTextPtr(i), buffer);
}
}
}
@@ -3108,7 +3108,7 @@ bool jmessage_tRenderingProcessor::do_tag(u32 i_tag, void const* i_data, u32 i_s
char buffer[40];
u8 bombNum = pReference->getObjectPtr()->getSelectBombNum();
dMsgUnit_setTag(7, bombNum, buffer);
- strcpy(pReference->getWord(field_0x14f), buffer);
+ SAFE_STRCPY(pReference->getWord(field_0x14f), buffer);
push_word();
return 1;
}
@@ -3116,7 +3116,7 @@ bool jmessage_tRenderingProcessor::do_tag(u32 i_tag, void const* i_data, u32 i_s
char buffer[40];
s16 bombPrice = pReference->getObjectPtr()->getSelectBombPrice();
dMsgUnit_setTag(1, bombPrice, buffer);
- strcpy(pReference->getWord(field_0x14f), buffer);
+ SAFE_STRCPY(pReference->getWord(field_0x14f), buffer);
push_word();
return 1;
}
@@ -3501,7 +3501,7 @@ void jmessage_tRenderingProcessor::do_color(u8 i_colorNo) {
mGCColor = getFontGCColorTable(i_colorNo, reference_p->getFukiKind());
char buffer[40];
- sprintf(buffer,
+ SAFE_SPRINTF(buffer,
"\x1B"
"CC[%08x]"
"\x1B"
@@ -3529,7 +3529,7 @@ void jmessage_tRenderingProcessor::do_scale(f32 param_1) {
}
char buffer[32];
- sprintf(buffer,
+ SAFE_SPRINTF(buffer,
"\x1B"
"FX[%d]"
"\x1B"
@@ -3541,7 +3541,7 @@ void jmessage_tRenderingProcessor::do_scale(f32 param_1) {
void jmessage_tRenderingProcessor::do_linedown(s16 param_0) {
char buffer[16];
- sprintf(buffer, "\x1B" "CD[%d]", param_0);
+ SAFE_SPRINTF(buffer, "\x1B" "CD[%d]", param_0);
do_strcat(buffer, false, true, false);
}
@@ -3551,11 +3551,11 @@ void jmessage_tRenderingProcessor::do_transY(s16 i_transY, bool unused) {
char buffer1[16];
if (i_transY < 0) {
- sprintf(buffer0, "\x1B" "CU[%d]", -i_transY);
- sprintf(buffer1, "\x1B" "CD[%d]", -i_transY);
+ SAFE_SPRINTF(buffer0, "\x1B" "CU[%d]", -i_transY);
+ SAFE_SPRINTF(buffer1, "\x1B" "CD[%d]", -i_transY);
} else {
- sprintf(buffer0, "\x1B" "CD[%d]", i_transY);
- sprintf(buffer1, "\x1B" "CU[%d]", i_transY);
+ SAFE_SPRINTF(buffer0, "\x1B" "CD[%d]", i_transY);
+ SAFE_SPRINTF(buffer1, "\x1B" "CU[%d]", i_transY);
}
field_0x4c -= i_transY;
@@ -3643,7 +3643,7 @@ void jmessage_tRenderingProcessor::do_strcat(char* i_str, bool param_2, bool par
field_0x11c += strlen(i_str);
if (field_0x14e != 0) {
if (field_0x11c < 50) {
- strcat(pReference->getSelTextPtr(field_0x14e - 1), i_str);
+ SAFE_STRCAT(pReference->getSelTextPtr(field_0x14e - 1), i_str);
} else {
JUT_WARN(5316, "%s", "TextBox Alloc Byte Over!!");
}
@@ -3662,22 +3662,22 @@ void jmessage_tRenderingProcessor::do_strcat(char* i_str, bool param_2, bool par
if (pReference->getCharAlpha() < 255.0f) {
pReference->addCharAlpha();
if (field_0x148 != 0) {
- char* textPtr = pReference->getTextPtr();
+ TEXT_SPAN textPtr = pReference->getTextPtr();
textPtr[field_0x148] = 0;
- strcat(textPtr, field_0x184);
+ SAFE_STRCAT(textPtr, field_0x184);
}
if (field_0x14a != 0) {
- char* textPtr = pReference->getTextSPtr();
+ TEXT_SPAN textPtr = pReference->getTextSPtr();
textPtr[field_0x14a] = 0;
- strcat(textPtr, field_0x184);
+ SAFE_STRCAT(textPtr, field_0x184);
}
u32 charColor = (mCCColor & 0xFFFFFF00) | ((int)pReference->getCharAlpha() & 0xFF);
u32 gradColor = (mGCColor & 0xFFFFFF00) | ((int)pReference->getCharAlpha() & 0xFF);
char buffer[36];
- sprintf(buffer, "\x1b" "CC[%08x]" "\x1b" "GC[%08x]", charColor, gradColor);
+ SAFE_SPRINTF(buffer, "\x1b" "CC[%08x]" "\x1b" "GC[%08x]", charColor, gradColor);
int length = 0;
length = strlen(buffer);
@@ -3686,9 +3686,9 @@ void jmessage_tRenderingProcessor::do_strcat(char* i_str, bool param_2, bool par
field_0x148 = strlen(pReference->getTextPtr());
field_0x14a = strlen(pReference->getTextSPtr());
- strcpy(field_0x184, i_str);
- strcat(pReference->getTextPtr(), buffer);
- strcat(pReference->getTextSPtr(), buffer);
+ SAFE_STRCPY(field_0x184, i_str);
+ SAFE_STRCAT(pReference->getTextPtr(), buffer);
+ SAFE_STRCAT(pReference->getTextSPtr(), buffer);
} else {
JUT_WARN(5362, "%s", "TextBox Alloc Byte Over!!");
}
@@ -3699,9 +3699,9 @@ void jmessage_tRenderingProcessor::do_strcat(char* i_str, bool param_2, bool par
field_0x14a = 0;
}
- strcat(pReference->getTextPtr(), i_str);
+ SAFE_STRCAT(pReference->getTextPtr(), i_str);
if (param_3) {
- strcat(pReference->getTextSPtr(), i_str);
+ SAFE_STRCAT(pReference->getTextSPtr(), i_str);
}
} else {
JUT_WARN(5380, "%s", "TextBox Alloc Byte Over!!");
@@ -3729,7 +3729,7 @@ void jmessage_tRenderingProcessor::do_rubyset(void const* i_data, u32 i_size) {
buffer[0] = pRuby[index++];
buffer[1] = pRuby[index++];
buffer[2] = 0;
- strcat(field_0x152, (const char*)buffer);
+ SAFE_STRCAT(field_0x152, (const char*)buffer);
int character = (((char)buffer[0] & 0xFF) << 8) | ((char)buffer[1] & 0xFF);
if (field_0x14e != 0) {
@@ -3751,7 +3751,7 @@ void jmessage_tRenderingProcessor::do_rubyset(void const* i_data, u32 i_size) {
}
}
-void jmessage_tRenderingProcessor::do_rubystrcat(char* i_src, char* i_dst, f32 i_charSpace, f32 param_4) {
+void jmessage_tRenderingProcessor::do_rubystrcat(char* i_src, TEXT_SPAN i_dst, f32 i_charSpace, f32 param_4) {
jmessage_tReference* pReference = (jmessage_tReference*)getReference();
if (pReference->isCharSend()) {
if (0.0f != param_4) {
@@ -3760,18 +3760,18 @@ void jmessage_tRenderingProcessor::do_rubystrcat(char* i_src, char* i_dst, f32 i
if (cursor_trans >= 1.0f) {
char buffer[16];
snprintf(buffer, sizeof(buffer) - 1, "\x1B" "CR[%d]", (int)cursor_trans);
- strcat(i_dst, buffer);
+ SAFE_STRCAT(i_dst, buffer);
field_0x12c += (int)cursor_trans;
} else if (cursor_trans <= -1.0f) {
char buffer[16];
snprintf(buffer, sizeof(buffer) - 1, "\x1B" "CL[%d]", (int)-cursor_trans);
- strcat(i_dst, buffer);
+ SAFE_STRCAT(i_dst, buffer);
field_0x12c += (int)cursor_trans;
}
field_0x12c += field_0x128 + i_charSpace;
}
- strcat(i_dst, i_src);
+ SAFE_STRCAT(i_dst, i_src);
}
}
@@ -4046,13 +4046,13 @@ bool jmessage_string_tMeasureProcessor::do_tag(u32 i_tag, void const* i_data, u3
break;
case MSGTAG_CURRENT_LETTER_PAGE: {
char buffer[4];
- sprintf(buffer, "%d", dComIfGp_getMessageCountNumber() / 100);
+ SAFE_SPRINTF(buffer, "%d", dComIfGp_getMessageCountNumber() / 100);
stack_pushCurrent(buffer);
break;
}
case MSGTAG_MAX_LETTER_PAGE: {
char buffer[4];
- sprintf(buffer, "%d", dComIfGp_getMessageCountNumber() % 100);
+ SAFE_SPRINTF(buffer, "%d", dComIfGp_getMessageCountNumber() % 100);
stack_pushCurrent(buffer);
break;
}
@@ -4469,11 +4469,11 @@ void jmessage_string_tRenderingProcessor::do_begin(void const* pEntry, char cons
void jmessage_string_tRenderingProcessor::do_end() {
if (mpReference->getPanePtr() != NULL) {
- strcpy(mpReference->getPanePtr()->getStringPtr(), field_0x54);
+ SAFE_STRCPY(mpReference->getPanePtr()->getStringPtr(), field_0x54);
}
if (mpReference->getRubyPanePtr() != NULL) {
- strcpy(mpReference->getRubyPanePtr()->getStringPtr(), field_0x254);
+ SAFE_STRCPY(mpReference->getRubyPanePtr()->getStringPtr(), field_0x254);
}
}
@@ -4604,13 +4604,13 @@ bool jmessage_string_tRenderingProcessor::do_tag(u32 i_tag, void const* i_data,
break;
case MSGTAG_CURRENT_LETTER_PAGE: {
char buffer[4];
- sprintf(buffer, "%d", dComIfGp_getMessageCountNumber() / 100);
+ SAFE_SPRINTF(buffer, "%d", dComIfGp_getMessageCountNumber() / 100);
push_word(buffer);
break;
}
case MSGTAG_MAX_LETTER_PAGE: {
char buffer[4];
- sprintf(buffer, "%d", dComIfGp_getMessageCountNumber() % 100);
+ SAFE_SPRINTF(buffer, "%d", dComIfGp_getMessageCountNumber() % 100);
push_word(buffer);
break;
}
@@ -5086,7 +5086,7 @@ void jmessage_string_tRenderingProcessor::do_strcat(char* i_str) {
if (getLineCountNowPage() >= 0) {
field_0x54e += strlen(i_str);
if (field_0x54e < ARRAY_SIZE(field_0x54)) {
- strcat(field_0x54, i_str);
+ SAFE_STRCAT(field_0x54, i_str);
} else {
JUT_WARN(7531, "%s", "Message Alloc Byte Over!!");
}
@@ -5117,7 +5117,7 @@ void jmessage_string_tRenderingProcessor::do_rubyset(void const* i_data, u32 i_s
bytes[0] = pRuby[i++];
bytes[1] = pRuby[i++];
bytes[2] = 0;
- strcat(field_0x454, (const char*)bytes);
+ SAFE_STRCAT(field_0x454, (const char*)bytes);
int character = (((char)bytes[0] & 0xFF) << 8) | ((char)bytes[1] & 0xFF);
field_0x44 += charSpace + fontSize.mSizeX * ((f32)pFont->getWidth(character) / pFont->getCellWidth());
@@ -5135,7 +5135,7 @@ void jmessage_string_tRenderingProcessor::do_rubystrcat(char* i_str) {
if (getLineCountNowPage() >= 0) {
field_0x550 += strlen(i_str);
if (field_0x550 < ARRAY_SIZE(field_0x254)) {
- strcat(field_0x254, i_str);
+ SAFE_STRCAT(field_0x254, i_str);
} else {
JUT_WARN(7613, "%s", "Message Alloc Byte Over!!");
}
@@ -5209,7 +5209,7 @@ void jmessage_string_tRenderingProcessor::do_color(u8 i_colorNo) {
}
char buffer[32];
- sprintf(buffer, "\x1b" "CC[%08x]" "\x1b" "GC[%08x]", ccColor, gcColor);
+ SAFE_SPRINTF(buffer, "\x1b" "CC[%08x]" "\x1b" "GC[%08x]", ccColor, gcColor);
do_strcat(buffer);
}
@@ -5220,13 +5220,13 @@ void jmessage_string_tRenderingProcessor::do_scale(f32 i_scale) {
s16 scaleY = 0.5f + fontSize.mSizeY * i_scale;
char buffer[32];
- sprintf(buffer, "\x1b" "FX[%d]" "\x1b" "FY[%d]", scaleX, scaleY);
+ SAFE_SPRINTF(buffer, "\x1b" "FX[%d]" "\x1b" "FY[%d]", scaleX, scaleY);
do_strcat(buffer);
}
void jmessage_string_tRenderingProcessor::do_linedown(s16 i_lineNo) {
char buffer[16];
- sprintf(buffer, "\x1B" "CD[%d]", i_lineNo);
+ SAFE_SPRINTF(buffer, "\x1B" "CD[%d]", i_lineNo);
do_strcat(buffer);
}
@@ -5245,6 +5245,6 @@ void jmessage_string_tRenderingProcessor::do_numset(s16 i_num) {
}
void jmessage_string_tRenderingProcessor::push_word(char const* i_word) {
- strcpy(field_0x486, i_word);
+ SAFE_STRCPY(field_0x486, i_word);
stack_pushCurrent(field_0x486);
}
diff --git a/src/d/d_msg_object.cpp b/src/d/d_msg_object.cpp
index 44b5c66571..d4cff01f31 100644
--- a/src/d/d_msg_object.cpp
+++ b/src/d/d_msg_object.cpp
@@ -461,12 +461,12 @@ int dMsgObject_c::_execute() {
mpCtrl->setMessageCode(mpRefer->getRevoMessageID());
mpRefer->setRevoMessageID(0);
jmessage_tReference* pRef = (jmessage_tReference*)mpRenProc->getReference();
- strcpy(pRef->getTextPtr(), "");
- strcpy(pRef->getTextSPtr(), "");
- strcpy(pRef->getRubyPtr(), "");
+ SAFE_STRCPY(pRef->getTextPtr(), "");
+ SAFE_STRCPY(pRef->getTextSPtr(), "");
+ SAFE_STRCPY(pRef->getRubyPtr(), "");
for (int i = 0; i < 3; i++) {
- strcpy(pRef->getSelTextPtr(i), "");
- strcpy(pRef->getSelRubyPtr(i), "");
+ SAFE_STRCPY(pRef->getSelTextPtr(i), "");
+ SAFE_STRCPY(pRef->getSelRubyPtr(i), "");
}
}
field_0x4ca = mpCtrl->update();
@@ -1021,12 +1021,12 @@ void dMsgObject_c::continueProc() {
offAutoMessageFlagLocal();
setMessageIndex(field_0x100->msg_idx, field_0x100->field_0xf0, true);
mpScrnDraw->fukiPosCalc(pRef->getFukiPosType());
- strcpy(pRef->getTextPtr(), "");
- strcpy(pRef->getTextSPtr(), "");
- strcpy(pRef->getRubyPtr(), "");
+ SAFE_STRCPY(pRef->getTextPtr(), "");
+ SAFE_STRCPY(pRef->getTextSPtr(), "");
+ SAFE_STRCPY(pRef->getRubyPtr(), "");
for (int i = 0; i < 3; i++) {
- strcpy(pRef->getSelTextPtr(i), "");
- strcpy(pRef->getSelRubyPtr(i), "");
+ SAFE_STRCPY(pRef->getSelTextPtr(i), "");
+ SAFE_STRCPY(pRef->getSelRubyPtr(i), "");
}
mpScrnDraw->arwAnimeInit();
mpRenProc->setTextInitPos(mpScrnDraw->getTextBoxPosX(), mpScrnDraw->getTextBoxPosY());
@@ -1737,8 +1737,8 @@ void dMsgObject_c::changeGroupLocal(s16 param_1) {
}
bool dMsgObject_c::getStringLocal(u32 param_1, J2DTextBox* param_2, J2DTextBox* param_3,
- JUTFont* param_4, COutFont_c* param_5, char* param_6,
- char* param_7, char* param_8, s16* param_9) {
+ JUTFont* param_4, COutFont_c* param_5, TEXT_SPAN param_6,
+ TEXT_SPAN param_7, TEXT_SPAN param_8, s16* param_9) {
if (field_0x4cd == 0) {
if (getStatusLocal() == 1) {
s16 groupID = getMessageGroup(param_1);
@@ -1781,13 +1781,13 @@ bool dMsgObject_c::getStringLocal(u32 param_1, J2DTextBox* param_2, J2DTextBox*
*param_9 = mpRefer->getCharSoundInfo().field_0x40e;
}
if (param_6 != NULL) {
- strcpy(param_6, pRef->getTextPtr());
+ SAFE_STRCPY(param_6, pRef->getTextPtr());
}
if (param_7 != NULL) {
- strcpy(param_7, pRef->getRubyPtr());
+ SAFE_STRCPY(param_7, pRef->getRubyPtr());
}
if (param_8 != NULL) {
- strcpy(param_8, pRef->getTextSPtr());
+ SAFE_STRCPY(param_8, pRef->getTextSPtr());
}
mpCtrl->reset();
mpCtrl->resetResourceCache();
@@ -2309,8 +2309,8 @@ void dMsgObject_c::changeGroup(s16 param_0) {
}
bool dMsgObject_c::getString(u32 param_0, J2DTextBox* param_1, J2DTextBox* param_2,
- JUTFont* param_3, COutFont_c* param_4, char* param_5, char* param_6,
- char* param_7, s16* param_8) {
+ JUTFont* param_3, COutFont_c* param_4, TEXT_SPAN param_5, TEXT_SPAN param_6,
+ TEXT_SPAN param_7, s16* param_8) {
return dMsgObject_getMsgObjectClass()->getStringLocal(
param_0, param_1, param_2, param_3, param_4, param_5, param_6, param_7, param_8);
}
diff --git a/src/d/d_msg_scrn_3select.cpp b/src/d/d_msg_scrn_3select.cpp
index 27a0bf5e1b..216135b10c 100644
--- a/src/d/d_msg_scrn_3select.cpp
+++ b/src/d/d_msg_scrn_3select.cpp
@@ -294,15 +294,15 @@ void dMsgScrn3Select_c::setString(char* mpText0, char* mpText1, char* mpText2) {
}
if (mpTmSel_c[0] != NULL) {
- strcpy(((J2DTextBox*)(mpTmSel_c[0]->getPanePtr()))->getStringPtr(), mpText0);
+ SAFE_STRCPY(((J2DTextBox*)(mpTmSel_c[0]->getPanePtr()))->getStringPtr(), mpText0);
}
if (mpTmSel_c[1] != NULL) {
- strcpy(((J2DTextBox*)(mpTmSel_c[1]->getPanePtr()))->getStringPtr(), mpText1);
+ SAFE_STRCPY(((J2DTextBox*)(mpTmSel_c[1]->getPanePtr()))->getStringPtr(), mpText1);
}
if (mpTmSel_c[2] != NULL) {
- strcpy(((J2DTextBox*)(mpTmSel_c[2]->getPanePtr()))->getStringPtr(), mpText2);
+ SAFE_STRCPY(((J2DTextBox*)(mpTmSel_c[2]->getPanePtr()))->getStringPtr(), mpText2);
}
}
@@ -323,15 +323,15 @@ void dMsgScrn3Select_c::setRubyString(char* pText0, char* pText1, char* pText2)
}
if (mpTmrSel_c[0] != NULL) {
- strcpy(((J2DTextBox*)(mpTmrSel_c[0]->getPanePtr()))->getStringPtr(), pText0);
+ SAFE_STRCPY(((J2DTextBox*)(mpTmrSel_c[0]->getPanePtr()))->getStringPtr(), pText0);
}
if (mpTmrSel_c[1] != NULL) {
- strcpy(((J2DTextBox*)(mpTmrSel_c[1]->getPanePtr()))->getStringPtr(), pText1);
+ SAFE_STRCPY(((J2DTextBox*)(mpTmrSel_c[1]->getPanePtr()))->getStringPtr(), pText1);
}
if (mpTmrSel_c[2] != NULL) {
- strcpy(((J2DTextBox*)(mpTmrSel_c[2]->getPanePtr()))->getStringPtr(), pText2);
+ SAFE_STRCPY(((J2DTextBox*)(mpTmrSel_c[2]->getPanePtr()))->getStringPtr(), pText2);
}
}
diff --git a/src/d/d_msg_scrn_base.cpp b/src/d/d_msg_scrn_base.cpp
index fdd9e57f9c..f402f8983b 100644
--- a/src/d/d_msg_scrn_base.cpp
+++ b/src/d/d_msg_scrn_base.cpp
@@ -108,9 +108,9 @@ void dMsgScrnBase_c::setString(char* mpText, char* i_stringB) {
if (mpTm_c[i] != NULL) {
JUT_ASSERT(262, ((J2DTextBox*)(mpTm_c[i]->getPanePtr()))->getStringAllocByte() > strlen(mpText));
if (i == 0) {
- strcpy(((J2DTextBox*)mpTm_c[i]->getPanePtr())->getStringPtr(), mpText);
+ SAFE_STRCPY(((J2DTextBox*)mpTm_c[i]->getPanePtr())->getStringPtr(), mpText);
} else {
- strcpy(((J2DTextBox*)mpTm_c[i]->getPanePtr())->getStringPtr(), i_stringB);
+ SAFE_STRCPY(((J2DTextBox*)mpTm_c[i]->getPanePtr())->getStringPtr(), i_stringB);
}
}
}
@@ -120,7 +120,7 @@ void dMsgScrnBase_c::setRubyString(char* mpText) {
for (int i = 0; i < 3; i++) {
if (mpTmr_c[i] != NULL) {
JUT_ASSERT(288, ((J2DTextBox*)(mpTmr_c[i]->getPanePtr()))->getStringAllocByte() > strlen(mpText));
- strcpy(((J2DTextBox*)mpTmr_c[i]->getPanePtr())->getStringPtr(), mpText);
+ SAFE_STRCPY(((J2DTextBox*)mpTmr_c[i]->getPanePtr())->getStringPtr(), mpText);
}
}
}
diff --git a/src/d/d_msg_scrn_explain.cpp b/src/d/d_msg_scrn_explain.cpp
index 945f75e927..bc6275e10c 100644
--- a/src/d/d_msg_scrn_explain.cpp
+++ b/src/d/d_msg_scrn_explain.cpp
@@ -317,7 +317,7 @@ void dMsgScrnExplain_c::draw(J2DOrthoGraph* i_graf) {
}
char string_buf[STR_BUF_LEN];
- strcpy(string_buf, ((J2DTextBox*)mpTm_c[0]->getPanePtr())->getStringPtr());
+ SAFE_STRCPY(string_buf, ((J2DTextBox*)mpTm_c[0]->getPanePtr())->getStringPtr());
mpTxScreen->draw(0.0f, 0.0f, (J2DGrafContext*)i_graf);
#if VERSION == VERSION_GCN_JPN
@@ -327,7 +327,7 @@ void dMsgScrnExplain_c::draw(J2DOrthoGraph* i_graf) {
#endif
mpString_c->drawOutFont((J2DTextBox*)mpTm_c[0]->getPanePtr(), -1.0f);
- strcpy(((J2DTextBox*)mpTm_c[0]->getPanePtr())->getStringPtr(), string_buf);
+ SAFE_STRCPY(((J2DTextBox*)mpTm_c[0]->getPanePtr())->getStringPtr(), string_buf);
if (mpSelect_c != NULL && (field_0x64 == 1 || field_0x64 == 2)) {
// the magic numbers here are relative to the framebuffer size, but were likely
@@ -370,11 +370,11 @@ void dMsgScrnExplain_c::open_request_proc() {
bool rt = dMsgObject_getString(mOpenMsgId, tbox, rubyTbox, mDoExt_getMesgFont(), mpOutFont, text,
ruby, textShadow, &field_0x5c);
if (rt) {
- strcpy(((J2DTextBox*)mpTm_c[0]->getPanePtr())->getStringPtr(), text);
- strcpy(((J2DTextBox*)mpTm_c[1]->getPanePtr())->getStringPtr(), textShadow);
+ SAFE_STRCPY(((J2DTextBox*)mpTm_c[0]->getPanePtr())->getStringPtr(), text);
+ SAFE_STRCPY(((J2DTextBox*)mpTm_c[1]->getPanePtr())->getStringPtr(), textShadow);
for (int i = 0; i < 2; i++) {
if (mpTmr_c[i] != NULL) {
- strcpy(((J2DTextBox*)mpTmr_c[i]->getPanePtr())->getStringPtr(), ruby);
+ SAFE_STRCPY(((J2DTextBox*)mpTmr_c[i]->getPanePtr())->getStringPtr(), ruby);
}
}
@@ -483,12 +483,12 @@ void dMsgScrnExplain_c::move_select_init() {
"\x1B"
"CR[%d]",
(int)var_f28);
- strcat(string_buf_yes, msg_buf_yes);
+ SAFE_STRCAT(string_buf_yes, msg_buf_yes);
snprintf(string_buf_no, 20,
"\x1B"
"CR[%d]",
(int)var_f27);
- strcat(string_buf_no, msg_buf_no);
+ SAFE_STRCAT(string_buf_no, msg_buf_no);
mpSelect_c->setString("", string_buf_yes, string_buf_no);
mpSelect_c->setRubyString("", "", "");
diff --git a/src/d/d_msg_scrn_tree.cpp b/src/d/d_msg_scrn_tree.cpp
index d17ced9bd8..899a8f449a 100644
--- a/src/d/d_msg_scrn_tree.cpp
+++ b/src/d/d_msg_scrn_tree.cpp
@@ -188,6 +188,14 @@ void dMsgScrnTree_c::exec() {
fukiAlpha(1.0f);
}
mpPmP_c->scale(g_MsgObject_HIO_c.mBoxWoodScaleX, g_MsgObject_HIO_c.mBoxWoodScaleY);
+
+#if TARGET_PC
+ const f32 hudScale = mDoGph_gInf_c::hudAspectScaleUp;
+ if (hudScale > 1.0f) {
+ field_0xc4->getPanePtr()->setBasePosition(J2DBasePosition_4);
+ field_0xc4->getPanePtr()->scale(hudScale, 1.0f);
+ }
+#endif
}
void dMsgScrnTree_c::draw() {
diff --git a/src/d/d_msg_string_base.cpp b/src/d/d_msg_string_base.cpp
index 7346047661..003375d6b4 100644
--- a/src/d/d_msg_string_base.cpp
+++ b/src/d/d_msg_string_base.cpp
@@ -126,7 +126,7 @@ u8 dMsgStringBase_c::getPageMax(int param_0) {
return pageMax;
}
-f32 dMsgStringBase_c::getMessageLocal(u32 param_1, char* param_2) {
+f32 dMsgStringBase_c::getMessageLocal(u32 param_1, TEXT_SPAN param_2) {
if (dMeter2Info_getMsgResource() != NULL) {
if (param_1 > 5000) {
if (field_0x1c != dMeter2Info_getStageMsgResource()) {
@@ -146,7 +146,7 @@ f32 dMsgStringBase_c::getMessageLocal(u32 param_1, char* param_2) {
mpCtrl->render();
mpCtrl->reset();
mpCtrl->resetResourceCache();
- strcpy(param_2, mpRenProc->getString());
+ SAFE_STRCPY(param_2, mpRenProc->getString());
return 0.0f;
}
@@ -165,7 +165,7 @@ f32 dMsgStringBase_c::getStringPage(u32 param_0, u8 param_1, u8 param_2, J2DText
return getStringPageLocal(param_0, param_1, param_2, param_3, param_4, param_5, param_6, param_7);
}
-f32 dMsgStringBase_c::getMessage(u32 param_0, char* param_1) {
+f32 dMsgStringBase_c::getMessage(u32 param_0, TEXT_SPAN param_1) {
return getMessageLocal(param_0, param_1);
}
diff --git a/src/d/d_msg_unit.cpp b/src/d/d_msg_unit.cpp
index 7bbe8b3d70..55fc588d4e 100644
--- a/src/d/d_msg_unit.cpp
+++ b/src/d/d_msg_unit.cpp
@@ -42,21 +42,21 @@ dMsgUnit_c::dMsgUnit_c() {}
dMsgUnit_c::~dMsgUnit_c() {}
#if REGION_JPN
-void dMsgUnit_c::setTag(int i_type, int i_value, char* o_buffer, bool param_4) {
+void dMsgUnit_c::setTag(int i_type, int i_value, TEXT_SPAN o_buffer, bool param_4) {
*o_buffer = 0;
bool stack9 = false;
bool stack8 = false;
int value = i_value;
if (i_type == 0x10000) {
- sprintf(o_buffer, "%d", i_value);
+ SAFE_SPRINTF(o_buffer, "%d", i_value);
return;
}
if (i_type == 0x10001) {
int tens_digit = i_value / 10;
int ones_digit = i_value % 10;
- sprintf(o_buffer, "%d-%d", tens_digit, ones_digit);
+ SAFE_SPRINTF(o_buffer, "%d-%d", tens_digit, ones_digit);
return;
}
@@ -108,7 +108,7 @@ void dMsgUnit_c::setTag(int i_type, int i_value, char* o_buffer, bool param_4) {
}
if (i_type == 9 && param_4 == true) {
- sprintf(o_buffer, "%d", i_value);
+ SAFE_SPRINTF(o_buffer, "%d", i_value);
stack8 = true;
}
@@ -170,9 +170,9 @@ void dMsgUnit_c::setTag(int i_type, int i_value, char* o_buffer, bool param_4) {
int uVar5Len = strlen(uVar5);
if (uVar5Len == 0) {
if (stack8) {
- strcat(o_buffer, value2);
+ SAFE_STRCAT(o_buffer, value2);
} else {
- sprintf(o_buffer, "%d%s", i_value, value2);
+ SAFE_SPRINTF(o_buffer, "%d%s", i_value, value2);
}
} else {
char unkCharArr[7];
@@ -185,11 +185,11 @@ void dMsgUnit_c::setTag(int i_type, int i_value, char* o_buffer, bool param_4) {
unkCharArr[6] = 0;
if (stack8) {
- strcat(o_buffer, unkCharArr);
- strcat(o_buffer, uVar5);
- strcat(o_buffer, value2);
+ SAFE_STRCAT(o_buffer, unkCharArr);
+ SAFE_STRCAT(o_buffer, uVar5);
+ SAFE_STRCAT(o_buffer, value2);
} else {
- sprintf(o_buffer, "%d%s%s%s", i_value, unkCharArr, uVar5, value2);
+ SAFE_SPRINTF(o_buffer, "%d%s%s%s", i_value, unkCharArr, uVar5, value2);
}
}
}
@@ -197,17 +197,17 @@ void dMsgUnit_c::setTag(int i_type, int i_value, char* o_buffer, bool param_4) {
if (i_type == 3 && param_4 == true) {
char buffer[20];
setTag(4, 0, buffer, false);
- strcat(o_buffer, buffer);
+ SAFE_STRCAT(o_buffer, buffer);
}
if (i_type == 4 && param_4 == true) {
char buffer[20];
setTag(5, value, buffer, false);
- strcat(o_buffer, buffer);
+ SAFE_STRCAT(o_buffer, buffer);
}
}
#else
-void dMsgUnit_c::setTag(int i_type, int i_value, char* o_buffer, bool param_4) {
+void dMsgUnit_c::setTag(int i_type, int i_value, TEXT_SPAN o_buffer, bool param_4) {
*o_buffer = 0;
bool stack9 = false;
bool stack8 = false;
@@ -218,14 +218,14 @@ void dMsgUnit_c::setTag(int i_type, int i_value, char* o_buffer, bool param_4) {
int minutes; // sp34
if (i_type == 0x10000) {
- sprintf(o_buffer, "%d", i_value);
+ SAFE_SPRINTF(o_buffer, "%d", i_value);
return;
}
if (i_type == 0x10001) {
tens_digit = i_value / 10;
ones_digit = i_value % 10;
- sprintf(o_buffer, "%d-%d", tens_digit, ones_digit);
+ SAFE_SPRINTF(o_buffer, "%d-%d", tens_digit, ones_digit);
return;
}
@@ -238,7 +238,7 @@ void dMsgUnit_c::setTag(int i_type, int i_value, char* o_buffer, bool param_4) {
seconds = 59;
}
if (minutes != 0 || seconds != 0) {
- sprintf(o_buffer, "%d:%02d", minutes, seconds);
+ SAFE_SPRINTF(o_buffer, "%d:%02d", minutes, seconds);
}
return;
@@ -254,11 +254,11 @@ void dMsgUnit_c::setTag(int i_type, int i_value, char* o_buffer, bool param_4) {
iVar8b = ((s32)(1000000.0f * dayTime) % 250000) / 1000000.0f;
f32 iVar9 = 60.0f * (iVar8b / 0.25f);
- sprintf(o_buffer, "%d:%02d", (s32)hour, (s32)minute);
+ SAFE_SPRINTF(o_buffer, "%d:%02d", (s32)hour, (s32)minute);
} else {
if (i_type == 9 && param_4 == true) {
int value = i_value;
- sprintf(o_buffer, "%d", value);
+ SAFE_SPRINTF(o_buffer, "%d", value);
stack8 = true;
}
@@ -359,21 +359,21 @@ void dMsgUnit_c::setTag(int i_type, int i_value, char* o_buffer, bool param_4) {
}
if (strcmp(uVar5, "") == 0) {
- sprintf(o_buffer, "%d%s", i_value, uVar5);
+ SAFE_SPRINTF(o_buffer, "%d%s", i_value, uVar5);
} else {
- sprintf(o_buffer, "%d %s", i_value, uVar5);
+ SAFE_SPRINTF(o_buffer, "%d %s", i_value, uVar5);
}
}
if (i_type == 3 && param_4 == true) {
char buffer[20];
setTag(4, 0, buffer, false);
- strcat(o_buffer, buffer);
+ SAFE_STRCAT(o_buffer, buffer);
}
if (i_type == 4 && param_4 == true) {
char buffer[20];
setTag(5, param_2b, buffer, false);
- strcat(o_buffer, buffer);
+ SAFE_STRCAT(o_buffer, buffer);
}
}
}
diff --git a/src/d/d_name.cpp b/src/d/d_name.cpp
index abc7512f14..e4c2a0f8f0 100644
--- a/src/d/d_name.cpp
+++ b/src/d/d_name.cpp
@@ -908,7 +908,7 @@ void dName_c::setNameText() {
#if REGION_JPN
if (mChrInfo[i].mMojiSet == 2) {
#endif
- sprintf(mNameText[i],
+ SAFE_SPRINTF(mNameText[i],
"\x1b"
"CD\x1b"
"CR\x1b"
@@ -919,7 +919,7 @@ void dName_c::setNameText() {
);
#if REGION_JPN
} else {
- sprintf(mNameText[i],
+ SAFE_SPRINTF(mNameText[i],
"\x1b"
"CD\x1b"
"CR\x1b"
@@ -1330,7 +1330,7 @@ void dName_c::mojiListChange() {
char buf[74];
for (int i = 0; i < 65; i++) {
- strcpy(buf, "\x1B"
+ SAFE_STRCPY(buf, "\x1B"
"CD"
"\x1B"
"CR"
@@ -1338,15 +1338,15 @@ void dName_c::mojiListChange() {
"CC[000000]"
"\x1B"
"GM[0]");
- strcat(buf, mojiSet[i]);
- strcat(buf, "\x1B"
+ SAFE_STRCAT(buf, mojiSet[i]);
+ SAFE_STRCAT(buf, "\x1B"
"HM"
"\x1B"
"CC[ffffff]"
"\x1B"
"GM[0]");
- strcat(buf, mojiSet[i]);
- strcpy(mMojiText[i], buf);
+ SAFE_STRCAT(buf, mojiSet[i]);
+ SAFE_STRCPY(mMojiText[i], buf);
}
#if TARGET_PC || REGION_PAL || REGION_JPN
@@ -1430,10 +1430,10 @@ void dName_c::selectCursorPosSet(int row) {
#if TARGET_PC
void dName_c::nameWide() {
- //Resize Select Icon
+ // Resize Select Icon
#if TARGET_PC
if (mSelIcon) {
- mSelIcon->refreshAspectScale();
+ mSelIcon->refreshAspectScale(mDoGph_gInf_c::hudAspectScaleUp);
}
#endif
diff --git a/src/d/d_particle.cpp b/src/d/d_particle.cpp
index 9b89afc7b1..1c53313826 100644
--- a/src/d/d_particle.cpp
+++ b/src/d/d_particle.cpp
@@ -1263,7 +1263,7 @@ bool dPa_control_c::readScene(u8 param_0, mDoDvdThd_toMainRam_c** param_1) {
JUT_ASSERT(2647, !mSceneCount++);
field_0x18 = param_0;
static char jpcName[32];
- sprintf(jpcName, "/res/Particle/Pscene%03d.jpc", param_0);
+ SAFE_SPRINTF(jpcName, "/res/Particle/Pscene%03d.jpc", param_0);
*param_1 = mDoDvdThd_toMainRam_c::create(jpcName, 0, m_resHeap);
return 1;
}
diff --git a/src/d/d_s_name.cpp b/src/d/d_s_name.cpp
index c3ae12e992..92f5a6c518 100644
--- a/src/d/d_s_name.cpp
+++ b/src/d/d_s_name.cpp
@@ -10,6 +10,7 @@
#include "d/d_meter2_info.h"
#include "d/d_s_name.h"
#include "dusk/imgui/ImGuiConsole.hpp"
+#include "dusk/livesplit.h"
#include "dusk/memory.h"
#include "dusk/speedrun.h"
#include "dusk/settings.h"
@@ -422,6 +423,7 @@ void dScnName_c::changeGameScene() {
if (!dusk::m_speedrunInfo.m_isRunStarted) {
dusk::resetForSpeedrunMode();
dusk::m_speedrunInfo.startRun();
+ dusk::speedrun::start();
}
}
diff --git a/src/d/d_s_play.cpp b/src/d/d_s_play.cpp
index f2e7d5d926..4445d9d1bb 100644
--- a/src/d/d_s_play.cpp
+++ b/src/d/d_s_play.cpp
@@ -163,22 +163,22 @@ void dScnPly_reg_childHIO_c::genMessage(JORMContext* mctx) {
char textbuf[8];
for (int i = 0; i < 20; i++) {
- sprintf(textbuf, " F(%02d)", i);
+ SAFE_SPRINTF(textbuf, " F(%02d)", i);
mctx->genSlider(textbuf, &mFloatReg[i], -100000.0f, 100000.0f);
}
for (int i = 20; i < 25; i++) {
- sprintf(textbuf, " F(%02d)", i);
+ SAFE_SPRINTF(textbuf, " F(%02d)", i);
mctx->genSlider(textbuf, &mFloatReg[i], 0.0f, 1.0f);
}
for (int i = 25; i < 30; i++) {
- sprintf(textbuf, " F(%02d)", i);
+ SAFE_SPRINTF(textbuf, " F(%02d)", i);
mctx->genSlider(textbuf, &mFloatReg[i], -1.0f, 1.0f);
}
for (int i = 0; i < 10; i++) {
- sprintf(textbuf, " S(%02d)", i);
+ SAFE_SPRINTF(textbuf, " S(%02d)", i);
mctx->genSlider(textbuf, &mShortReg[i], -0x8000, 0x7FFF);
}
}
diff --git a/src/d/d_s_room.cpp b/src/d/d_s_room.cpp
index 0fcdb58ac0..259bc37e3b 100644
--- a/src/d/d_s_room.cpp
+++ b/src/d/d_s_room.cpp
@@ -178,7 +178,7 @@ static int loadDemoArchive(int i_roomNo) {
int bank2 = entries[dComIfG_play_c::getLayerNo(i_roomNo)].bank2;
JUT_ASSERT(353, 0 <= bank2 && bank2 < 100);
- sprintf(dStage_roomControl_c::getDemoArcName(), "Demo%02d_%02d", bank, bank2);
+ SAFE_SPRINTF(dStage_roomControl_c::getDemoArcName(), "Demo%02d_%02d", bank, bank2);
if (!dComIfG_setObjectRes(dStage_roomControl_c::getDemoArcName(), 0, (JKRHeap*)NULL)) {
const char* name = dStage_roomControl_c::getDemoArcName();
*dStage_roomControl_c::getDemoArcName() = 0;
diff --git a/src/d/d_save.cpp b/src/d/d_save.cpp
index fc1cbc4efe..af2a6db28a 100644
--- a/src/d/d_save.cpp
+++ b/src/d/d_save.cpp
@@ -2034,7 +2034,7 @@ void flagFile_c::listenPropertyEvent(const JORPropertyEvent* i_event) {
const char* start_stage_name = dComIfGp_getStartStageName();
char filename[64];
- sprintf(filename, "_%02d%02d%02d%02d%02d-%s.zff", time.mon + 1, time.mday, time.hour, time.min, time.sec, start_stage_name);
+ SAFE_SPRINTF(filename, "_%02d%02d%02d%02d%02d-%s.zff", time.mon + 1, time.mday, time.hour, time.min, time.sec, start_stage_name);
OS_REPORT("write to %s\n", filename);
JORFile file;
diff --git a/src/d/d_select_cursor.cpp b/src/d/d_select_cursor.cpp
index 0773433b4d..1268865cb6 100644
--- a/src/d/d_select_cursor.cpp
+++ b/src/d/d_select_cursor.cpp
@@ -577,7 +577,7 @@ void dSelect_cursor_c::moveCenter(J2DPane* i_pane, f32 i_x, f32 i_y) {
}
#ifdef TARGET_PC
-void dSelect_cursor_c::refreshAspectScale() {
- mParam1 = mBaseParam1 * mDoGph_gInf_c::hudAspectScaleUp;
+void dSelect_cursor_c::refreshAspectScale(f32 param_0) {
+ mParam1 = mBaseParam1 * param_0;
}
#endif
diff --git a/src/d/d_stage.cpp b/src/d/d_stage.cpp
index f3cdfed17b..5836feccd2 100644
--- a/src/d/d_stage.cpp
+++ b/src/d/d_stage.cpp
@@ -482,7 +482,7 @@ void* dStage_roomControl_c::roomDzs_c::add(u8 i_no, u8 roomNo) {
void** dzs = m_dzs + i_no;
if (*dzs == NULL) {
char dzsName[20];
- sprintf(dzsName, "%s/room%d.dzs", dComIfGp_getStartStageName(), roomNo);
+ SAFE_SPRINTF(dzsName, "%s/room%d.dzs", dComIfGp_getStartStageName(), roomNo);
JUT_ASSERT(1167, strlen(dzsName) <= sizeof(dzsName));
u32 expandSize =
@@ -2396,7 +2396,7 @@ static void readMult(dStage_dt_c* i_stage, dStage_Multi_c* multi, bool useOldRes
if (dzs == NULL) {
char dzsName[11];
- sprintf(dzsName, "room%d.dzs", info->mRoomNo);
+ SAFE_SPRINTF(dzsName, "room%d.dzs", info->mRoomNo);
JUT_ASSERT(3548, strlen(dzsName) <= sizeof(dzsName));
if (useOldRes) {
diff --git a/src/d/d_timer.cpp b/src/d/d_timer.cpp
index cb40e3444a..8bc5cac570 100644
--- a/src/d/d_timer.cpp
+++ b/src/d/d_timer.cpp
@@ -1224,8 +1224,8 @@ BOOL dDlst_TimerScrnDraw_c::closeAnime() {
int dDlst_TimerScrnDraw_c::createGetIn(cXyz i_pos) {
char string[104];
dMeter2Info_getString(0x3E4, string, NULL); // "GOAT IN!"
- strcpy(static_cast(mpGetInScreen->search(MULTI_CHAR('get_in_s')))->getStringPtr(), string);
- strcpy(static_cast(mpGetInScreen->search(MULTI_CHAR('get_in')))->getStringPtr(), string);
+ SAFE_STRCPY(static_cast(mpGetInScreen->search(MULTI_CHAR('get_in_s')))->getStringPtr(), string);
+ SAFE_STRCPY(static_cast(mpGetInScreen->search(MULTI_CHAR('get_in')))->getStringPtr(), string);
if (mCowID < 50) {
m_getin_info[mCowID].bck_frame = 40.0f;
@@ -1313,8 +1313,8 @@ int dDlst_TimerScrnDraw_c::createGetIn(cXyz i_pos) {
s32 dDlst_TimerScrnDraw_c::createStart(u16 i_messageID) {
char string[112];
dMeter2Info_getString(i_messageID, string, NULL);
- strcpy(static_cast(mpGetInScreen->search(MULTI_CHAR('get_in_s')))->getStringPtr(), string);
- strcpy(static_cast(mpGetInScreen->search(MULTI_CHAR('get_in')))->getStringPtr(), string);
+ SAFE_STRCPY(static_cast(mpGetInScreen->search(MULTI_CHAR('get_in_s')))->getStringPtr(), string);
+ SAFE_STRCPY(static_cast(mpGetInScreen->search(MULTI_CHAR('get_in')))->getStringPtr(), string);
if (mCowID == 0) {
m_getin_info[mCowID].bck_frame = 40.0f;
diff --git a/src/dusk/achievements.cpp b/src/dusk/achievements.cpp
index a8e4ff3916..6c4de43487 100644
--- a/src/dusk/achievements.cpp
+++ b/src/dusk/achievements.cpp
@@ -11,6 +11,7 @@
#include "d/actor/d_a_alink.h"
#include "d/actor/d_a_ni.h"
#include "d/actor/d_a_npc4.h"
+#include "d/actor/d_a_b_gnd.h"
#include "d/actor/d_a_b_ob.h"
#include "d/actor/d_a_player.h"
#include "d/d_demo.h"
@@ -18,6 +19,7 @@
#include "f_pc/f_pc_name.h"
#include "f_op/f_op_actor_mng.h"
#include "f_pc/f_pc_name.h"
+#include "dusk/logging.h"
#include
#include
@@ -35,6 +37,9 @@ static void* s_cucco_play_search(void* i_actor, void*) {
}
static void checkGoatHerding(Achievement& a, int32_t threshMs) {
+ if (strcmp(dComIfGp_getStartStageName(), "F_SP00") != 0) {
+ return;
+ }
if (dMeter2Info_getMaxCount() != 20 || dMeter2Info_getNowCount() != 20) {
return;
}
@@ -65,6 +70,25 @@ std::vector AchievementSystem::makeEntries() {
},
{}
},
+ {
+ {
+ "three_heart_clear",
+ "Hero Mode",
+ "Defeat Ganondorf with only 3 heart containers.",
+ AchievementCategory::Challenge,
+ false, 0, 0, false
+ },
+ [](Achievement& a, json&) {
+ const auto* link = static_cast(daPy_getPlayerActorClass());
+ if (link == nullptr || link->mProcID != daAlink_c::PROC_GANON_FINISH) {
+ return;
+ }
+ if (dComIfGs_getMaxLife() < 20) {
+ a.progress = 1;
+ }
+ },
+ {}
+ },
{
{
"completionist",
@@ -201,7 +225,7 @@ std::vector AchievementSystem::makeEntries() {
hasAncientDoc = true;
}
}
- if (!hasJewelRod || !hasAncientDoc) {
+ if (!hasJewelRod || (!hasAncientDoc && !dComIfGs_isEventBit(dSv_event_flag_c::F_0302))) {
return;
}
@@ -265,7 +289,7 @@ std::vector AchievementSystem::makeEntries() {
{
"hylian_loach",
"Legendary Catch",
- "Catch a Hylian Loach.",
+ "Obtain the Hylian Loach in your fishing journal.",
AchievementCategory::Collection,
false, 0, 0, false
},
@@ -280,7 +304,7 @@ std::vector AchievementSystem::makeEntries() {
{
"all_fish",
"Gone Fishin'",
- "Catch all 6 species of fish.",
+ "Obtain all 6 species of fish in your fishing journal.",
AchievementCategory::Collection,
true, 6, 0, false
},
@@ -392,7 +416,7 @@ std::vector AchievementSystem::makeEntries() {
false, 0, 0, false
},
[](Achievement& a, json&) {
- if (daNpcF_chkEvtBit(0x1F9) && dComIfGs_getMaxLife() <= 15) {
+ if (daNpcF_chkEvtBit(0x1F9) && dComIfGs_getMaxLife() < 20) {
a.progress = 1;
}
},
@@ -442,7 +466,7 @@ std::vector AchievementSystem::makeEntries() {
{
"dark_hammer_one_hit",
"Mortal Edge",
- "Defeat Dark Hammer in a single hit.",
+ "Defeat Darkhammer in a single hit.",
AchievementCategory::Misc,
false, 0, 0, false
},
@@ -506,6 +530,29 @@ std::vector AchievementSystem::makeEntries() {
},
{}
},
+ {
+ {
+ "rollstab_triple",
+ "Surgical Skewer",
+ "Kill 3 enemies with a single rollstab.",
+ AchievementCategory::Misc,
+ false, 0, 0, false
+ },
+ [](Achievement& a, json&) {
+ static int rollstabKills = 0;
+ const auto* link = static_cast(daPy_getPlayerActorClass());
+ const bool inRollstab = link != nullptr && link->mProcID == daAlink_c::PROC_CUT_FINISH && link->mIsRollstab;
+ if (!inRollstab) {
+ rollstabKills = 0;
+ return;
+ }
+ rollstabKills += AchievementSystem::get().signalCount("rollstab_kill");
+ if (rollstabKills >= 3) {
+ a.progress = 1;
+ }
+ },
+ {}
+ },
// Minigame
{
{
@@ -600,6 +647,9 @@ std::vector AchievementSystem::makeEntries() {
false, 0, 0, false
},
[](Achievement& a, json&) {
+ if (strcmp(dComIfGp_getStartStageName(), "F_SP114") != 0) {
+ return;
+ }
const int32_t bestMs = dComIfGs_getRaceGameTime();
if (dComIfGs_isEventBit(dSv_event_flag_c::F_0481) &&
bestMs > 0 && bestMs <= 70000) {
@@ -681,7 +731,7 @@ std::vector AchievementSystem::makeEntries() {
{
"long_jump_attack",
"Long Jump Attack",
- "Travel more than 20 meters in a single jump attack before landing.",
+ "Travel more than 15 meters in a single jump attack before landing.",
AchievementCategory::Misc,
false, 0, 0, false
},
@@ -711,7 +761,7 @@ std::vector AchievementSystem::makeEntries() {
inJump = false;
const float dx = link->current.pos.x - startX;
const float dz = link->current.pos.z - startZ;
- if (dx * dx + dz * dz >= 2000.0f * 2000.0f) {
+ if (dx * dx + dz * dz >= 1500.0f * 1500.0f) {
a.progress = 1;
}
} else if (link->mProcID != daAlink_c::PROC_CUT_JUMP) {
@@ -800,6 +850,66 @@ std::vector AchievementSystem::makeEntries() {
},
{}
},
+ {
+ {
+ "ganondorf_3hit",
+ "Autospin Annihilation",
+ "Finish off Ganondorf in the final duel after only 3 attacks.",
+ AchievementCategory::Misc,
+ false, 0, 0, false
+ },
+ [](Achievement& a, json&) {
+ auto& sys = AchievementSystem::get();
+ const auto* link = static_cast(daPy_getPlayerActorClass());
+
+ static int autospinCount = 0;
+ static int pendingHits = 0;
+ static bool invalidated = false;
+ static bool wasInFight = false;
+
+ auto* gnd = static_cast(fopAcM_SearchByName(fpcNm_B_GND_e));
+ const bool inFight = gnd != nullptr && !gnd->checkRide();
+
+ if (inFight && !wasInFight) {
+ autospinCount = 0;
+ pendingHits = 0;
+ invalidated = false;
+ }
+ wasInFight = inFight;
+
+ if (!inFight) {
+ return;
+ }
+
+ const bool hitOccurred = sys.hasSignal("ganondorf_hit");
+ const bool knockedDown = sys.hasSignal("ganondorf_knocked_down");
+
+ if (hitOccurred && knockedDown) {
+ // Spin completing an autospin: pendingHits should be exactly 1 (the spin attack)
+ if (pendingHits == 1) {
+ autospinCount++;
+ pendingHits = 0;
+ } else {
+ invalidated = true;
+ }
+ } else if (hitOccurred) {
+ pendingHits++;
+ if (pendingHits > 1) {
+ invalidated = true;
+ }
+ }
+
+ if (link != nullptr && link->mProcID == daAlink_c::PROC_GANON_FINISH) {
+ if (!invalidated && autospinCount == 3) {
+ a.progress = 1;
+ }
+ autospinCount = 0;
+ pendingHits = 0;
+ invalidated = false;
+ }
+ },
+ {}
+ },
// Glitched
{
{
@@ -1012,6 +1122,55 @@ std::vector AchievementSystem::makeEntries() {
a.progress = 1;
},
{}
+ },
+ {
+ {
+ "early_city",
+ "Early City",
+ "Obtain the Double Clawshots without obtaining the Dominion Rod.",
+ AchievementCategory::Glitched,
+ false, 0, 0, false
+ },
+ [](Achievement& a, json&) {
+ if (daPy_getPlayerActorClass() == nullptr) {
+ return;
+ }
+ bool hasDoubleClawshot = false;
+ bool hasDominionRod = false;
+ for (int i = 0; i < 24; ++i) {
+ const auto item = dComIfGs_getItem(i, false);
+ if (item == dItemNo_W_HOOKSHOT_e) {
+ hasDoubleClawshot = true;
+ }
+ if (item == dItemNo_COPY_ROD_e || item == dItemNo_COPY_ROD_2_e) {
+ hasDominionRod = true;
+ }
+ }
+ if (hasDoubleClawshot && !hasDominionRod) {
+ a.progress = 1;
+ }
+ },
+ {}
+ },
+ {
+ {
+ "early_kakariko",
+ "Gorge Skip",
+ "Collect the Kakariko warp portal without warping the gorge bridge.",
+ AchievementCategory::Glitched,
+ false, 0, 0, false
+ },
+ [](Achievement& a, json&) {
+ if (dComIfGs_isEventBit(dSv_event_flag_c::M_018) || dComIfGp_getStageStagInfo() == nullptr) {
+ return;
+ }
+ const bool savedPortal = g_dComIfG_gameInfo.info.getSavedata().getSave(dStage_SaveTbl_ELDIN).getBit().isSwitch(31);
+ const bool livePortal = dStage_stagInfo_GetSaveTbl(dComIfGp_getStageStagInfo()) == dStage_SaveTbl_ELDIN && dComIfGs_isSaveSwitch(31);
+ if (savedPortal || livePortal) {
+ a.progress = 1;
+ }
+ },
+ {}
}
};
}
@@ -1088,11 +1247,17 @@ void AchievementSystem::clearAll() {
}
void AchievementSystem::signal(const char* key) {
- m_signals.insert(key);
+ m_signals[key]++;
}
bool AchievementSystem::hasSignal(const char* key) const {
- return m_signals.count(key) > 0;
+ const auto it = m_signals.find(key);
+ return it != m_signals.end() && it->second > 0;
+}
+
+int AchievementSystem::signalCount(const char* key) const {
+ const auto it = m_signals.find(key);
+ return it != m_signals.end() ? it->second : 0;
}
void AchievementSystem::clearOne(const char* key) {
diff --git a/src/dusk/config.cpp b/src/dusk/config.cpp
index f0a4b986bd..aed43089c4 100644
--- a/src/dusk/config.cpp
+++ b/src/dusk/config.cpp
@@ -8,6 +8,8 @@
#include "dusk/settings.h"
#include
+#include
+#include
#include
#include "dusk/main.h"
@@ -24,8 +26,24 @@ aurora::Module DuskConfigLog("dusk::config");
static absl::flat_hash_map RegisteredConfigVars;
static bool RegistrationDone = false;
-static std::u8string GetConfigJsonPath() {
- return (dusk::ConfigPath / ConfigFileName).u8string();
+static std::filesystem::path GetConfigJsonPath() {
+ return dusk::ConfigPath / ConfigFileName;
+}
+
+static std::filesystem::path GetTempConfigJsonPath(const std::filesystem::path& configJsonPath) {
+ auto tempPath = configJsonPath;
+ tempPath.replace_filename(fmt::format(".{}.tmp", configJsonPath.filename().string()));
+ return tempPath;
+}
+
+static void ReplaceFile(const std::filesystem::path& source, const std::filesystem::path& target) {
+ std::error_code ec;
+ std::filesystem::rename(source, target, ec);
+ if (ec) {
+ const auto renameError = ec;
+ std::filesystem::remove(source, ec);
+ throw std::system_error(renameError);
+ }
}
ConfigVarBase::ConfigVarBase(const char* name, const ConfigImplBase* impl) : name(name), registered(false), layer(ConfigVarLayer::Default), impl(impl) {
@@ -56,6 +74,23 @@ static T sanitizeEnumValue(const ConfigVar& cVar, T value) {
template
void ConfigImpl::loadFromJson(ConfigVar