Compare commits

...

48 Commits

Author SHA1 Message Date
madeline 99ea28e9f7 maybe fix ook crash 2026-05-20 14:33:48 -07:00
Giorgio Mendieta 31dd069879 docs: Improve building.md file (#1530)
* docs: Improve building.md file

- Fix broken XCode link
- Add MacOS running instructions
- Alphabetize linux packages

* fix: collapse packages sections for readability

* fix: collapse packages sections for readability

* fix: add --dvd flag to specify iso path

* fix: Remove incorrect info about game.iso
2026-05-17 07:51:38 -06:00
SrBananaMan a499877c37 Add an enable texture replacements option in the video tab (#1517)
Co-authored-by: Luke Street <luke@street.dev>
2026-05-17 07:51:15 -06:00
Olivia!! b91a58feab Adds option to unbind using controller only (#1212)
* Adds option to unbind using controller only

* Adds a new cheat to let you transform from the start of the game, without Midna or the Shadow Crystal

* Revert "Adds a new cheat to let you transform from the start of the game, without Midna or the Shadow Crystal"

This reverts commit 51ed736729.

* Do not allow unbinding the A or B buttons to prevent softlocks when no other input sources are available (e.g. playing on a TV)

* change 'and' to '&&' in accordance with code standards
2026-05-17 07:45:08 -06:00
doop c710ea5b38 Use 10% steps for bloom brightness setting (#1423) 2026-05-17 07:44:29 -06:00
Olivia!! cd4b29f8a1 Update controller bindings menu. (#1461)
* Add a button to reset to default controls, and hides the digital L and R binds except on advanced menu.

* Rename Controller mentions to Device + Extra menu sounds

* Shouldn't add a column here

* Changes mentions of controller to device in accordance with #1479

---------

Co-authored-by: MelonSpeedruns <melonspeedruns@stratobox.net>
2026-05-17 07:38:24 -06:00
Loïs 6faa4a3330 Fix mButtonText buffer overflow on long localized action labels (#1491) 2026-05-17 07:34:18 -06:00
Luke Street eed81e9ecc Update aurora 2026-05-17 09:33:26 -04:00
Loïs a773e5489e Fix unresponsive R trigger in dusklight menu (#1424) 2026-05-17 07:27:27 -06:00
Krutonium db6a1835d2 Flake: Update GitHub revision and hash for aurora-src (#1237)
* Flake: Update GitHub revision and hash for aurora-src

Fixes Build Error due to Aurora being out of date in the flake.

* No Required Aurora Hash
2026-05-17 07:26:50 -06:00
David Kanevskyy e10e1f74d5 Feature - remember window position (#1238)
* added .zed/ to gitignore (editor configs)

* remember window position upon closing

* Save window location on SDL_EVENT_WINDOW_MOVED or SDL_EVENT_WINDOW_RESIZED

* Fix code format mistakes

* Also persist window width/height

* Undo change to input::handle_event

* Undo aurora submodule change

---------

Co-authored-by: Luke Street <luke@street.dev>
2026-05-17 07:25:12 -06:00
TakaRikka ff3eb9aa48 Merge pull request #1511 from SailorSnoW/fix/ook-consistency
Fix Ook first jump not matching console behavior
2026-05-16 17:55:41 -07:00
TakaRikka 513fdd2312 Merge pull request #1502 from SailorSnoW/fix/autostart-run
Fix LiveSplit not starting when TV settings screen is skipped
2026-05-16 17:52:25 -07:00
TakaRikka f33c3bdf72 Merge pull request #1380 from TwilitRealm/fast-boots-backwalk-anim-fix
Fix Backwalk Animation Speed with Fast Iron Boots
2026-05-16 17:48:50 -07:00
TakaRikka e08b427650 Merge branch 'main' into fast-boots-backwalk-anim-fix 2026-05-16 17:43:31 -07:00
SailorSnoW 9f0fa12c6e Fix Ook first jump not matching console behavior 2026-05-17 02:12:14 +02:00
SailorSnoW ad4f75bbb6 Fix LiveSplit not starting when TV settings screen is skipped 2026-05-16 19:13:07 +02:00
Loïs 5d2811955c Fix item wheel background capturing interpolated frame instead of current sim (#1447) 2026-05-16 08:19:57 -04:00
Pieter-Jan Briers 3b30c09e79 Fix PAL name keyboard (#1467)
Fixes #1460
2026-05-16 08:15:27 -04:00
MelonSpeedruns 8adc40708e Infinite Rupee now set to max Rupees (#1417)
Co-authored-by: MelonSpeedruns <melonspeedruns@stratobox.net>
2026-05-16 10:28:45 +02:00
SuperDude88 2541c3f293 Update Description (#1439)
Mention that it applies to other cases besides just boots
2026-05-16 10:28:21 +02:00
Loïs 30b003c9d9 fix rein interpolation jitter by rolling snapshot once per sim tick (#1421) 2026-05-15 17:16:36 -04:00
SuperDude88 c77ed40208 Fix Backwalk Animation Speed
Also make one of the other similar checks more concise
2026-05-15 01:52:53 -04:00
Luke Street af8300a77c Update aurora 2026-05-14 23:22:08 -06:00
SuperDude88 1ce1003e1a Bold Back Button Name in Popup (#1376)
* Bold Back Button Name

Makes it stand out more, especially when the back button is called something else that's just a common word

* Just b

---------

Co-authored-by: Luke Street <luke@street.dev>
2026-05-14 23:21:01 -06:00
Loïs 10e2181692 Fix file select softlock when resetting during save (#1293) 2026-05-14 23:17:17 -06:00
Miguel 424d1d7b71 Fixed Debug target not compiling (#1157)
* Update f_op_actor_mng.h

* Update f_op_actor_mng.h
2026-05-14 23:10:09 -06:00
matthewdavidrichardanderson 26be454999 soft reset hotkey on release (#1358)
Co-authored-by: matthewdavidrichardanderson <matthewdavidrichardanderson@mfb.com>
2026-05-14 23:05:08 -06:00
Pieter-Jan Briers cf89da811a Fix fast tears going out of bounds (#1337)
Incorrect decomp from TPHD making the tears think you're always in the Zora River ride

Fixes https://github.com/TwilitRealm/dusklight/issues/1047
2026-05-14 23:04:36 -06:00
tomlube f02c7bd1ac modify gx init fail text (#1332) 2026-05-14 23:04:13 -06:00
Pieter-Jan Briers 53abb8b96d Use safe string copies in d_save.cpp (#1232)
* Use safe string copies in d_save.cpp

Seeing sentry crashes here that I suspect involve buffer overflows here.
2026-05-14 23:03:42 -06:00
Loïs 6a27fa23c8 Fix game mode on MacOS <26 (#1362) 2026-05-14 22:56:28 -06:00
Luke Street 025a425884 Use -fsigned-char on ARM 2026-05-14 22:54:55 -06:00
Irastris 5064385c8c Add styling for <b> tags (#1349) 2026-05-15 03:12:36 +02:00
Luke Street e52d9e9b71 Fix mDoLib_project with safe area 2026-05-14 17:06:58 -06:00
qwertyquerty 3520bb746c better completionist achievement requirements for skybook (#1258) 2026-05-14 22:56:15 +02:00
Irastris 1e10d95936 Disable scrolling the name cursor (#1243) 2026-05-14 22:53:34 +02:00
Loïs a923aa24e1 Fix Rollgoal completion reward to scale with Bigger Wallets (#1296) 2026-05-14 22:45:27 +02:00
tomlube 9c4f61678e update instructions (#1329)
better OS interoperability with iloader and imo much easier to set up too
2026-05-14 22:43:46 +02:00
MelonSpeedruns 7967ee1f66 Fix Autosaves resetting memory card during minigames (#1318)
* Fix autosaves resetting memory card during minigames

* Update description

* remove unused include

---------

Co-authored-by: MelonSpeedruns <melonspeedruns@stratobox.net>
2026-05-14 22:42:39 +02:00
Loïs 2bdc7b6c09 use bit-stable lerp form in frame_interpolation (#1326) 2026-05-14 15:05:54 -04:00
tomlube 232f73365c rebrand fix (#1290) 2026-05-14 16:31:37 +02:00
TakaRikka a913f1699f Merge pull request #1252 from TwilitRealm/erd
clear e_rd static boss ptr on delete
2026-05-13 19:31:35 -07:00
TakaRikka 01b4eaa2fa clear e_rd static boss ptr on delete 2026-05-13 19:27:39 -07:00
SuperDude88 9d2ba3eb49 Rename Settings Preset (#1233)
To match the bloom preset, since that name was updated in #1211
2026-05-13 20:26:30 -04:00
JaxonWasTaken 6026b4bb9b Apply rebrand to bloom setting value name (#1211)
The display name for BloomSetting::Dusk was unchanged in the rebranding
process, and still shows up as "Dusk" in the settings menu. Rename it to
"Dusklight" to bring it in line with the rebrand.
2026-05-13 16:34:14 -04:00
Luke Street 7a77d48954 Use legacy path if migration fails 2026-05-13 09:08:41 -06:00
qwertyquerty 4ee0d8ed4b 1.1.1 fixes (#1168)
* fix keyboard npe

* fix autosave NPE

* hintTalkEvCamera UB

* fix UB in f_pc_base logging

* fix NPE in karg carry logic

* fix link model dangling pointers

* exponential audio slider and better audio default

* fix speedrun mode defaullt layer restore issue
2026-05-13 08:56:16 -06:00
51 changed files with 631 additions and 248 deletions
+1
View File
@@ -1,6 +1,7 @@
# IDE folders
.idea/
.vs/
.zed/
# Caches
__pycache__
+6
View File
@@ -276,6 +276,12 @@ if (DUSK_ENABLE_SENTRY_NATIVE)
endif ()
endif ()
# Use signed char on ARM to match the original game (and x86)
string(TOLOWER "${CMAKE_SYSTEM_PROCESSOR}" _arch)
if(_arch MATCHES "^(arm|aarch64)" AND CMAKE_CXX_COMPILER_FRONTEND_VARIANT STREQUAL "GNU")
add_compile_options(-fsigned-char)
endif()
if (CMAKE_SYSTEM_NAME STREQUAL Windows)
set(PLATFORM_NAME win32)
elseif (CMAKE_SYSTEM_NAME STREQUAL Darwin)
+183 -53
View File
@@ -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**
<details>
<summary>Click to expand</summary>
* 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
```
</details>
<br>
**Arch Linux packages**
<details>
<summary>Click to expand</summary>
* 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
```
</details>
<br>
**Fedora packages**
<details>
<summary>Click to expand</summary>
* 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"
```
</details>
<br>
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.
+23 -21
View File
@@ -1,33 +1,40 @@
# Installing Dusklight on iOS via AltStore
# Installing Dusklight on iOS via iloader
## Prerequisites
- Mac with Homebrew installed
- iPhone connected via USB
- 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)
## 1. Install AltServer
```sh
brew install altserver
open -a AltServer
```
AltServer will appear in your menu bar.
- 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
- Linux WILL require usbmuxd to be installed, this is installed by default in most distros though
## 2. Enable Developer Mode (iOS 16+)
- On your iPhone, go to **Settings > Privacy & Security > Developer Mode**
- Toggle it on and restart when prompted
## 3. Install AltStore on Your iPhone
## 3. Install Dusklight on Your iPhone
- Click AltServer in the menu bar
- Click **Install AltStore > [Your iPhone]**
- Enter your Apple ID credentials when prompted
- On your iPhone, go to **Settings > General > VPN & Device Management**
- Tap your Apple ID under "Developer App" and tap **Trust**
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
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
**NOTE:** *At various stages, you may be prompted to trust your device, do so*
## 3. Getting Dusk 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**
* Tap **Allow** on the pop-up
## 4. Copy Files to Your iPhone
@@ -38,9 +45,4 @@ Transfer the IPA and game disc to your iPhone so they're accessible in the Files
- **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
## 5. Install via AltStore
- Open **AltStore** on your iPhone
- Go to the **My Apps** tab
- Tap the **+** button (top left)
- Open the **Files** app and select the `.ipa` file
You may now use Dusklight on iOS, iPadOS!
+1 -1
+1 -10
View File
@@ -15,12 +15,6 @@
# 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";
hash = "sha256-HXfKTLHtMPwupnFnaflCARtXVPuS/0PoCePXidjE5xs=";
@@ -59,9 +53,6 @@
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
@@ -225,4 +216,4 @@
default = mkDevShell (pkgsFor system);
});
};
}
}
+11
View File
@@ -1,8 +1,19 @@
#pragma once
#include <cmath>
#include <dolphin/types.h>
namespace dusk::audio {
// Converts a 0-1 volume to a linear amplitude multiplier.
// The curve is -4 dB per 10% step: 100% = 0 dB, 90% = -4 dB, ..., 0% = -inf dB
inline f32 MasterVolumeToLinear(f32 v) {
if (v <= 0.0f) {
return 0.0f;
}
return std::pow(10.0f, (v - 1.0f) * 2.0f);
}
/**
* Initialize the audio system and start playing audio.
*/
+1
View File
@@ -5,6 +5,7 @@
#include <m_Do/m_Do_MemCardRWmng.h>
#include <m_Do/m_Do_MemCard.h>
#include <d/actor/d_a_alink.h>
void noAutoSave();
void triggerAutoSave();
+5 -2
View File
@@ -175,6 +175,7 @@ class ConfigVar : public ConfigVarBase {
T defaultValue;
T value;
T overrideValue;
ConfigVarLayer priorLayer = ConfigVarLayer::Default;
public:
/**
@@ -265,6 +266,7 @@ public:
void setSpeedrunValue(T newValue) {
checkRegistered();
if (layer != ConfigVarLayer::Override) {
priorLayer = layer;
overrideValue = std::move(newValue);
layer = ConfigVarLayer::Speedrun;
}
@@ -282,7 +284,7 @@ public:
checkRegistered();
if (layer == ConfigVarLayer::Speedrun) {
overrideValue = {};
layer = ConfigVarLayer::Value;
layer = priorLayer;
}
}
@@ -293,7 +295,8 @@ public:
*/
[[nodiscard]] constexpr const T& getValueForSave() const noexcept {
checkRegistered();
return layer == ConfigVarLayer::Default ? defaultValue : value;
const ConfigVarLayer effectiveLayer = (layer == ConfigVarLayer::Speedrun) ? priorLayer : layer;
return effectiveLayer == ConfigVarLayer::Default ? defaultValue : value;
}
};
+1
View File
@@ -17,6 +17,7 @@ void ensure_initialized();
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 interpolate();
float get_interpolation_step();
+5
View File
@@ -72,6 +72,10 @@ struct UserSettings {
ConfigVar<bool> lockAspectRatio;
ConfigVar<bool> enableFpsOverlay;
ConfigVar<int> fpsOverlayCorner;
ConfigVar<int> windowPositionX;
ConfigVar<int> windowPositionY;
ConfigVar<int> windowWidth;
ConfigVar<int> windowHeight;
} video;
struct {
@@ -123,6 +127,7 @@ struct UserSettings {
ConfigVar<BloomMode> bloomMode;
ConfigVar<float> bloomMultiplier;
ConfigVar<bool> disableWaterRefraction;
ConfigVar<bool> enableTextureReplacements;
ConfigVar<bool> enableFrameInterpolation;
ConfigVar<int> internalResolutionScale;
ConfigVar<int> shadowResolutionMultiplier;
+1 -1
View File
@@ -108,7 +108,7 @@ struct fopAcM_search_prm {
struct fOpAcm_HIO_entry_c : public mDoHIO_entry_c {
virtual ~fOpAcm_HIO_entry_c() {}
#if DEBUG
#if DEBUG && !TARGET_PC
void removeHIO(const fopAc_ac_c* i_this) { removeHIO(*i_this); }
void removeHIO(const fopAc_ac_c& i_this) { removeHIO(i_this.base); }
void removeHIO(const fopEn_enemy_c& i_this) { removeHIO(i_this.base); }
+3 -1
View File
@@ -28,7 +28,9 @@
<string>${MACOSX_BUNDLE_SHORT_VERSION_STRING}</string>
<key>NSHighResolutionCapable</key>
<true/>
<key>LSApplicationCategoryType</key>
<string>public.app-category.adventure-games</string>
<key>LSSupportsGameMode</key>
<true/>
<true/>
</dict>
</plist>
+4
View File
@@ -58,6 +58,10 @@ toast:active {
background-color: rgba(45, 43, 26, 80%);
}*/
b {
font-weight: bold;
}
toast heading {
display: flex;
gap: 18dp;
+4
View File
@@ -14,6 +14,10 @@ body {
color: #E0DBC8;
}
b {
font-weight: bold;
}
window {
display: flex;
flex-flow: column;
+2 -7
View File
@@ -7562,12 +7562,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 +8075,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;
+6 -1
View File
@@ -77,7 +77,12 @@ int daAlink_c::loadModelDVD() {
mpWlMidnaHairModel = NULL;
if (!checkNoResetFlg2(FLG2_UNK_280000)) {
dComIfG_resDelete(&mPhaseReq, mArcName);
if (!dComIfG_resDelete(&mPhaseReq, mArcName)) {
#if TARGET_PC
// resDelete no-ops if load was in-progress; force-unregister before freeAll
dComIfG_deleteObjectResMain(mArcName);
#endif
}
cPhs_Reset(&mPhaseReq);
mpArcHeap->freeAll();
+6
View File
@@ -8723,6 +8723,12 @@ int daAlink_c::procWolfCargoCarry() {
return checkNextActionWolf(0);
}
#if TARGET_PC
if (field_0x280c.getActor() == NULL) {
return checkNextActionWolf(0);
}
#endif
mDoMtx_stack_c::copy(((e_yc_class*)field_0x280c.getActor())->getLegR3Mtx());
mDoMtx_stack_c::transM(-9.0f, -7.0f, -30.0f);
mDoMtx_stack_c::multVecZero(&current.pos);
+18
View File
@@ -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];
}
+6
View File
@@ -7053,6 +7053,12 @@ static int daE_RD_IsDelete(e_rd_class*) {
}
static int daE_RD_Delete(e_rd_class* i_this) {
#if TARGET_PC
if (boss == i_this) {
boss = NULL;
}
#endif
fopEn_enemy_c* enemy = (fopEn_enemy_c*)&i_this->enemy;
fopAcM_RegisterDeleteID(i_this, "E_RD");
+10 -4
View File
@@ -22,6 +22,7 @@
#if TARGET_PC
#include "dusk/dusk.h"
#include "dusk/frame_interpolation.h"
namespace {
// FRAME INTERP NOTE: Sim tick control point snapshots for interpolation
@@ -32,6 +33,7 @@ int s_horseReinSimNumPrev;
int s_horseReinSimNumCurr;
bool s_horseReinSimPrevValid;
bool s_horseReinSimCurrValid;
uint64_t s_horseReinSimRolledSeq;
} // namespace
#endif
@@ -3033,10 +3035,14 @@ void daHorse_c::copyReinPos() {
}
#if TARGET_PC
if (field_0x1204 > 0) {
if (s_horseReinSimCurrValid && s_horseReinSimNumCurr > 0) {
memcpy(s_horseReinSimPrev, s_horseReinSimCurr, s_horseReinSimNumCurr * sizeof(cXyz));
s_horseReinSimNumPrev = s_horseReinSimNumCurr;
s_horseReinSimPrevValid = true;
const uint64_t simSeq = dusk::frame_interp::sim_tick_seq();
if (simSeq != s_horseReinSimRolledSeq) {
s_horseReinSimRolledSeq = simSeq;
if (s_horseReinSimCurrValid && s_horseReinSimNumCurr > 0) {
memcpy(s_horseReinSimPrev, s_horseReinSimCurr, s_horseReinSimNumCurr * sizeof(cXyz));
s_horseReinSimNumPrev = s_horseReinSimNumCurr;
s_horseReinSimPrevValid = true;
}
}
memcpy(s_horseReinSimCurr, m_reinLine.getPos(0), field_0x1204 * sizeof(cXyz));
s_horseReinSimNumCurr = field_0x1204;
+4
View File
@@ -1967,7 +1967,11 @@ static void demo_camera_shop(npc_henna_class* i_this) {
i_this->mMsgFlow.init(actor, 0x365, 0, NULL);
/* dSv_event_flag_c::KORO2_ALLCLEAR - Fishing - After all stages (8-8) of roll goal game cleared */
dComIfGs_onEventBit(dSv_event_flag_c::saveBitLabels[0x335]);
#if TARGET_PC
dComIfGp_setItemRupeeCount(dComIfGs_getRupeeMax());
#else
dComIfGp_setItemRupeeCount(1000);
#endif
} else if ((lbl_82_bss_91 & 0x38) == 0) {
i_this->mMsgFlow.init(actor, 0x34f, 0, NULL);
/* dSv_event_flag_c::F_0469 - Fishing Pond - Reserved for fishing */
+2 -1
View File
@@ -299,7 +299,8 @@ int daObjDrop_c::modeParentWait() {
#if TARGET_PC
static inline BOOL checkGetCargoRide() {
if ((daPy_getPlayerActorClass()->checkCargoCarry() && strcmp(dComIfGp_getStartStageName(), "F_SP112") == 0) ||
if (daPy_getPlayerActorClass()->checkCargoCarry() &&
strcmp(dComIfGp_getStartStageName(), "F_SP112") == 0 &&
dComIfGs_isLightDropGetFlag(dComIfGp_getStartStageDarkArea()))
{
return true;
+1 -2
View File
@@ -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();
}
}
+8
View File
@@ -19,6 +19,7 @@
#include "d/d_timer.h"
#include "f_op/f_op_msg_mng.h"
#include "f_op/f_op_scene_mng.h"
#include "m_Do/m_Do_MemCard.h"
#include "m_Do/m_Do_Reset.h"
#include "m_Do/m_Do_controller_pad.h"
#include "m_Do/m_Do_graphic.h"
@@ -1238,6 +1239,13 @@ BOOL dComIfG_resetToOpening(scene_class* i_scene) {
}
#endif
#ifdef TARGET_PC
if (!mDoMemCd_isCardCommNone()) {
return 0;
}
g_mDoMemCd_control.SaveSync();
#endif
dComIfG_changeOpeningScene(i_scene, fpcNm_OPENING_SCENE_e);
mDoAud_bgmStop(30);
mDoAud_resetProcess();
+4
View File
@@ -3882,7 +3882,11 @@ bool dCamera_c::hintTalkEvCamera() {
cSAngle acStack_1fc(20.0f);
for (i = 0; i < 2; i++) {
#if AVOID_UB
for (j = 0; j < 10; j++) {
#else
for (j = 0; j < 12; j++) {
#endif
cSAngle acStack_200(local_b0[j] * fVar22);
hintTalk->mDirection.U(acStack_1f8 + acStack_200);
hintTalk->mDirection.V(((hintTalk->field_0x28.V() * acStack_200.Cos()) * 0.2f) + acStack_1fc);
+8
View File
@@ -26,6 +26,10 @@
#include "f_op/f_op_overlap_mng.h"
#include "m_Do/m_Do_controller_pad.h"
#ifdef TARGET_PC
#include "dusk/frame_interpolation.h"
#endif
class dDlst_MENU_CAPTURE_c : public dDlst_base_c {
public:
virtual void draw() {
@@ -1088,6 +1092,10 @@ void dMw_c::dMw_ring_create(u8 i_origin) {
}
mpCapture->setCaptureFlag();
#ifdef TARGET_PC
dusk::frame_interp::request_presentation_sync();
#endif
}
bool dMw_c::dMw_ring_delete() {
+13
View File
@@ -18,6 +18,9 @@
#include "d/d_pane_class.h"
#include "dusk/frame_interpolation.h"
#include <cstring>
#if TARGET_PC
#include "dusk/string.hpp"
#endif
#if VERSION == VERSION_GCN_JPN
#define STR_BUF_LEN 528
@@ -2927,6 +2930,12 @@ bool dMeterButton_c::isClose() {
}
void dMeterButton_c::setString(char* i_string, u8 i_button, u8 param_2, u8 param_3) {
#if TARGET_PC
char* i_string_full = i_string;
char i_string_buf[sizeof(mButtonText[0])];
dusk::SafeStringCopyTruncate(i_string_buf, i_string);
i_string = i_string_buf;
#endif
if (strcmp(mButtonText[param_2], i_string) != 0 || field_0x4be[param_2] != i_button) {
if (param_2 == 0 && strcmp(mButtonText[1], i_string) == 0 &&
((i_button == BUTTON_A_e && field_0x4be[1] == BUTTON_A_e) ||
@@ -3022,6 +3031,10 @@ void dMeterButton_c::setString(char* i_string, u8 i_button, u8 param_2, u8 param
strcpy(mButtonText[param_2], i_string);
#if TARGET_PC
i_string = i_string_full;
#endif
if (param_2 == 0) {
if (param_3 != 0) {
field_0x4d9 = param_2;
+10 -7
View File
@@ -77,16 +77,16 @@ static const char* l_mojiEisu[65] = {
// That can't work on a modern platform, so instead I've filled them out ahead of time.
static const char* l_mojiEisuPal_1[65] = {
"A", "N", "\xC0", "\xCF", "1", "B", "O", "\xC1", "\xD0", "2", "C", "P", "\xC2", "\xD1", "3", "D", "Q",
"\xC3", "\xD2", "4", "E", "R", "\xC4", "\xD3", "5", "F", "S", "\xC5", "\xD4", "6", "G", "T", "\xC6", "\xD5",
"7", "H", "U", "\xC7", "\xD6", "8", "I", "V", "\xC8", "\xD7", "9", "J", "W", "\xC9", "\xD8", "0", "K",
"X", "\xCA", "\xD9", ",", "L", "Y", "\xCB", "\xDA", ".", "M", "Z", "\xCC", "\xDB", " ",
"\xC4", "\xD2", "4", "E", "R", "\xC6", "\xD3", "5", "F", "S", "\xC7", "\xD4", "6", "G", "T", "\xC8", "\xD6",
"7", "H", "U", "\xC9", "\x8C", "8", "I", "V", "\xCA", "\xD9", "9", "J", "W", "\xCB", "\xDA", "0", "K",
"X", "\xCC", "\xDB", ",", "L", "Y", "\xCD", "\xDC", ".", "M", "Z", "\xCE", "\x2D", " ",
};
static const char* l_mojiEisuPal_2[65] = {
"a", "n", "\xE0", "\xEF", "1", "b", "o", "\xE1", "\xF0", "2", "c", "p", "\xE2", "\xF1", "3", "d", "q",
"\xE3", "\xF2", "4", "e", "r", "\xE4", "\xF3", "5", "f", "s", "\xE5", "\xF4", "6", "g", "t", "\xE6",
"\xF5", "7", "h", "u", "\xE7", "\xF6", "8", "i", "v", "\xE8", "\xF7", "9", "j", "w", "\xE9", "\xF8", "0",
"k", "x", "\xEA", "\xF9", ",", "l", "y", "\xEB", "\xFA", ".", "m", "z", "\xEC", "\xFB", " ",
"\xE4", "\xF2", "4", "e", "r", "\xE6", "\xF3", "5", "f", "s", "\xE7", "\xF4", "6", "g", "t", "\xE8",
"\xF6", "7", "h", "u", "\xE9", "\x9C", "8", "i", "v", "\xEA", "\xF9", "9", "j", "w", "\xEB", "\xFA", "0",
"k", "x", "\xEC", "\xFB", ",", "l", "y", "\xED", "\xFC", ".", "m", "z", "\xEE", "\xDF", " ",
};
#elif REGION_PAL
static const char* l_mojiEisuPal_1[65] = {
@@ -295,6 +295,7 @@ void dName_c::_move() {
}
} else {
#endif
#if !TARGET_PC
if (mDoCPd_c::getTrigRight(PAD_1)) {
// BUG: this check only fails if the cursor is at exactly 7
// setMoji allows the cursor to reach 8, which is out of bounds here
@@ -311,7 +312,9 @@ void dName_c::_move() {
mCurPos--;
nameCursorMove();
}
} else if (mDoCPd_c::getTrigB(PAD_1)) {
} else
#endif
if (mDoCPd_c::getTrigB(PAD_1)) {
if (mCurPos == 0) {
mDoAud_seStart(Z2SE_SY_MENU_BACK, 0, 0, 0);
field_0x2ac = mSelProc;
+2
View File
@@ -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();
}
}
+3 -5
View File
@@ -30,7 +30,9 @@
#if TARGET_PC
#include "dusk/settings.h"
#include <f_ap/f_ap_game.h>
#include <dusk/autosave.h>
#include "dusk/string.hpp"
#define strcpy dusk::SafeStringCopy
#endif
static u8 dSv_item_rename(u8 i_itemNo) {
@@ -349,10 +351,6 @@ void dSv_player_item_c::setItem(int i_slotNo, u8 i_itemNo) {
dComIfGp_setSelectItem(i);
}
}
#if TARGET_PC
triggerAutoSave();
#endif
}
u8 dSv_player_item_c::getItem(int i_slotNo, bool i_checkCombo) const {
+6 -3
View File
@@ -191,13 +191,17 @@ std::vector<AchievementSystem::Entry> AchievementSystem::makeEntries() {
}
bool hasJewelRod = false;
for (int slot = 0; slot < 24 && !hasJewelRod; ++slot) {
bool hasAncientDoc = false;
for (int slot = 0; slot < 24; ++slot) {
const u8 item = dComIfGs_getItem(slot, false);
if (item == dItemNo_JEWEL_ROD_e || item == dItemNo_JEWEL_BEE_ROD_e || item == dItemNo_JEWEL_WORM_ROD_e) {
hasJewelRod = true;
}
if (item == dItemNo_ANCIENT_DOCUMENT_e || item == dItemNo_ANCIENT_DOCUMENT2_e || item == dItemNo_AIR_LETTER_e) {
hasAncientDoc = true;
}
}
if (!hasJewelRod) {
if (!hasJewelRod || !hasAncientDoc) {
return;
}
@@ -212,7 +216,6 @@ std::vector<AchievementSystem::Entry> AchievementSystem::makeEntries() {
dItemNo_KANTERA_e,
dItemNo_PACHINKO_e,
dItemNo_HAWK_EYE_e,
dItemNo_ANCIENT_DOCUMENT_e,
dItemNo_HORSE_FLUTE_e,
};
for (u8 required : requiredWheelItems) {
+26 -6
View File
@@ -14,9 +14,23 @@ static AutoSaveFuncs AutoSaveFuncsProc[] = {
void noAutoSave() {}
bool canAutoSave() {
daAlink_c* player = (daAlink_c*)daAlink_getAlinkActorClass();
if (player == nullptr) {
return false;
}
if (player->checkCargoCarry() || player->checkCanoeRide()) {
return false;
}
return dusk::getSettings().game.autoSave && shouldAutoSave && mAutoSaveProc == 0 &&
strcmp(dComIfGp_getStartStageName(), "F_SP102") != 0 &&
strcmp(dComIfGp_getStartStageName(), "F_SP112") != 0;
}
void triggerAutoSave() {
if (dusk::getSettings().game.autoSave && shouldAutoSave && mAutoSaveProc == 0 &&
strcmp(dComIfGp_getStartStageName(), "F_SP102") != 0)
if (canAutoSave())
{
mAutoSaveProc = 1;
}
@@ -26,8 +40,12 @@ void updateAutoSave() {
(AutoSaveFuncsProc[mAutoSaveProc])();
}
void writeAutoSave() {
int stageNo = dStage_stagInfo_GetSaveTbl(dComIfGp_getStageStagInfo());
bool writeAutoSave() {
stage_stag_info_class* stagInfo = dComIfGp_getStageStagInfo();
if (stagInfo == nullptr) {
return false;
}
int stageNo = dStage_stagInfo_GetSaveTbl(stagInfo);
dComIfGs_putSave(stageNo);
dComIfGs_setMemoryToCard(mSaveBuffer, dComIfGs_getDataNum());
@@ -40,6 +58,7 @@ void writeAutoSave() {
}
g_mDoMemCd_control.save(mSaveBuffer, sizeof(mSaveBuffer), 0);
return true;
}
void autoSaving() {
@@ -48,8 +67,9 @@ void autoSaving() {
if (cardState == 2) {
mAutoSaveProc = 1;
} else if (cardState == 1) {
writeAutoSave();
mAutoSaveProc = 3;
if (writeAutoSave()) {
mAutoSaveProc = 3;
}
}
}
}
+43 -23
View File
@@ -78,6 +78,7 @@ struct MigrationStats {
std::optional<std::filesystem::path> sConfiguredDataPath;
std::optional<std::filesystem::path> sActiveDescriptorPath;
std::optional<std::filesystem::path> sActivePrefPath;
std::filesystem::path path_from_utf8(std::string_view value) {
return std::filesystem::path{
@@ -86,19 +87,22 @@ std::filesystem::path path_from_utf8(std::string_view value) {
};
}
std::filesystem::path get_legacy_path() {
if (std::string_view{LegacyAppName}.empty()) {
std::filesystem::path legacy_path_for_pref_path(const std::filesystem::path& prefPath) {
if (std::string_view{LegacyAppName}.empty() || prefPath.empty()) {
return {};
}
char* prefPath = SDL_GetPrefPath(OrgName, LegacyAppName);
if (!prefPath) {
Log.fatal("Unable to get PrefPath: {}", SDL_GetError());
auto normalizedPrefPath = prefPath;
if (normalizedPrefPath.filename().empty()) {
normalizedPrefPath = normalizedPrefPath.parent_path();
}
std::filesystem::path result{reinterpret_cast<const char8_t*>(prefPath)};
SDL_free(prefPath);
return result;
const auto parentPath = normalizedPrefPath.parent_path();
if (parentPath.empty()) {
return {};
}
return parentPath / LegacyAppName;
}
std::filesystem::path get_pref_path() {
@@ -112,6 +116,13 @@ std::filesystem::path get_pref_path() {
return result;
}
std::filesystem::path active_pref_path() {
if (sActivePrefPath) {
return *sActivePrefPath;
}
return get_pref_path();
}
std::filesystem::path base_path_relative(const std::filesystem::path& path) {
const auto* basePath = SDL_GetBasePath();
if (!basePath) {
@@ -265,12 +276,12 @@ std::filesystem::path absolute_path(const std::filesystem::path& path) {
return absolute.lexically_normal();
}
void rename_legacy_pref_path(
std::filesystem::path rename_legacy_pref_path(
const std::filesystem::path& legacyPath, const std::filesystem::path& prefPath) {
if (legacyPath.empty() || prefPath.empty() ||
normalized_path(legacyPath) == normalized_path(prefPath))
{
return;
return prefPath;
}
std::error_code ec;
@@ -279,14 +290,14 @@ void rename_legacy_pref_path(
Log.warn("Failed to inspect legacy data directory '{}': {}",
io::fs_path_to_string(legacyPath), ec.message());
}
return;
return prefPath;
}
const bool prefExists = std::filesystem::exists(prefPath, ec);
if (ec) {
Log.warn("Failed to inspect data directory '{}': {}", io::fs_path_to_string(prefPath),
ec.message());
return;
return prefPath;
}
if (prefExists) {
if (!std::filesystem::is_directory(prefPath, ec) ||
@@ -299,14 +310,14 @@ void rename_legacy_pref_path(
Log.info("Skipping legacy data directory rename because '{}' is not empty",
io::fs_path_to_string(prefPath));
}
return;
return prefPath;
}
std::filesystem::remove(prefPath, ec);
if (ec) {
Log.warn("Failed to remove empty data directory '{}' before legacy rename: {}",
io::fs_path_to_string(prefPath), ec.message());
return;
return prefPath;
}
}
@@ -314,11 +325,18 @@ void rename_legacy_pref_path(
if (ec) {
Log.warn("Failed to rename legacy data directory '{}' to '{}': {}",
io::fs_path_to_string(legacyPath), io::fs_path_to_string(prefPath), ec.message());
return;
ec.clear();
if (!std::filesystem::exists(prefPath, ec) && !ec) {
Log.info("Using legacy data directory '{}' because the new data directory is absent",
io::fs_path_to_string(legacyPath));
return legacyPath;
}
return prefPath;
}
Log.info("Renamed legacy data directory '{}' to '{}'", io::fs_path_to_string(legacyPath),
io::fs_path_to_string(prefPath));
return prefPath;
}
bool is_same_or_inside(const std::filesystem::path& root, const std::filesystem::path& path) {
@@ -394,7 +412,7 @@ std::filesystem::path current_data_path() {
if (!ConfigPath.empty()) {
return ConfigPath;
}
const auto prefPath = get_pref_path();
const auto prefPath = active_pref_path();
const auto descriptor = read_location_descriptor(prefPath);
if (descriptor) {
sActiveDescriptorPath = descriptor->path;
@@ -460,7 +478,7 @@ bool write_location_descriptor(LocationMode mode, const std::filesystem::path& t
json["previousPath"] = io::fs_path_to_string(descriptor.previousPath);
}
const auto prefPath = get_pref_path();
const auto prefPath = active_pref_path();
for (const auto& path : descriptor_write_paths(prefPath)) {
if (write_descriptor_json(path, json)) {
sActiveDescriptorPath = path;
@@ -1013,12 +1031,12 @@ bool set_portable_data_path() {
}
bool reset_data_path() {
const auto prefPath = get_pref_path();
const auto prefPath = active_pref_path();
return write_location_descriptor(LocationMode::Default, default_data_path(prefPath));
}
bool is_default_data_path() {
const auto prefPath = get_pref_path();
const auto prefPath = active_pref_path();
return normalized_path(configured_data_path()) == normalized_path(default_data_path(prefPath));
}
@@ -1027,7 +1045,7 @@ std::filesystem::path configured_data_path() {
return *sConfiguredDataPath;
}
const auto prefPath = get_pref_path();
const auto prefPath = active_pref_path();
const auto descriptor = read_location_descriptor(prefPath);
if (descriptor) {
sActiveDescriptorPath = descriptor->path;
@@ -1041,7 +1059,7 @@ std::filesystem::path cache_path() {
if (!CachePath.empty()) {
return CachePath;
}
return get_pref_path();
return active_pref_path();
}
bool is_data_path_restart_pending() {
@@ -1053,8 +1071,10 @@ bool is_data_path_restart_pending() {
}
Paths initialize_data() {
const auto prefPath = get_pref_path();
rename_legacy_pref_path(get_legacy_path(), prefPath);
const auto preferredPrefPath = get_pref_path();
const auto prefPath =
rename_legacy_pref_path(legacy_path_for_pref_path(preferredPrefPath), preferredPrefPath);
sActivePrefPath = prefPath;
const auto descriptor = read_location_descriptor(prefPath);
if (descriptor) {
+11 -6
View File
@@ -21,6 +21,7 @@ bool g_sync_presentation = false;
float g_step = 0.0f;
bool g_is_sim_frame = false;
bool g_ui_tick_pending = false;
uint64_t g_sim_tick_seq = 0;
Recording g_current_recording;
Recording g_previous_recording;
@@ -66,19 +67,18 @@ void copy_view_to_snap(CameraSnapshot* dst, const view_class& v) {
}
inline void lerp_matrix(Mtx out, const Mtx lhs, const Mtx rhs, float step) {
const float old_weight = 1.0f - step;
for (size_t row = 0; row < 3; ++row) {
for (size_t col = 0; col < 4; ++col) {
out[row][col] = lhs[row][col] * old_weight + rhs[row][col] * step;
const float l = lhs[row][col];
out[row][col] = l + (rhs[row][col] - l) * step;
}
}
}
inline void lerp_xyz(cXyz* out, const cXyz& lhs, const cXyz& rhs, float step) {
const float old_weight = 1.0f - step;
out->x = lhs.x * old_weight + rhs.x * step;
out->y = lhs.y * old_weight + rhs.y * step;
out->z = lhs.z * old_weight + rhs.z * step;
out->x = lhs.x + (rhs.x - lhs.x) * step;
out->y = lhs.y + (rhs.y - lhs.y) * step;
out->z = lhs.z + (rhs.z - lhs.z) * step;
}
static s16 lerp_bank(s16 a, s16 b, f32 t) {
@@ -135,6 +135,11 @@ void begin_sim_tick() {
s_interpolationCallBackWork.clear();
s_cam_prev = std::move(s_cam_curr);
++g_sim_tick_seq;
}
uint64_t sim_tick_seq() {
return g_sim_tick_seq;
}
void begin_frame(bool enabled, bool is_sim_frame, float step) {
+3 -3
View File
@@ -263,7 +263,7 @@ namespace dusk {
}
if (getSettings().game.enableResetKeybind && ImGui::GetIO().KeyCtrl &&
ImGui::IsKeyPressed(ImGuiKey_R) && !fpcM_SearchByName(fpcNm_LOGO_SCENE_e))
ImGui::IsKeyReleased(ImGuiKey_R) && !fpcM_SearchByName(fpcNm_LOGO_SCENE_e))
{
JUTGamePad::C3ButtonReset::sResetSwitchPushing = true;
}
@@ -322,8 +322,8 @@ namespace dusk {
}
ImGui::PushFont(ImGuiEngine::fontLarge);
ImGuiTextCenter("Failed to initialize any graphics backend.");
ImGuiTextCenter("\nYour system may be misconfigured, or your hardware may not support the required versions of any of the available backends.");
ImGuiTextCenter("\nA clean reinstall of Dusklight may help. For further assistance, please visit #tech-support on the Twilit Realm Discord server.");
ImGuiTextCenter("\nDusklight requires Vulkan 1.1+, or Direct X 12.0.");
ImGuiTextCenter("\nTry updating your Operating System and GPU drivers.");
const auto& style = ImGui::GetStyle();
const auto retrySize = ImGui::CalcTextSize("Retry (Auto backend)");
const auto quitSize = ImGui::CalcTextSize("Quit");
+14 -1
View File
@@ -1,5 +1,8 @@
#include "dusk/settings.h"
#include "dusk/config.hpp"
#include "dusk/dusk.h"
#include <SDL3/SDL_video.h>
namespace dusk {
@@ -10,10 +13,14 @@ UserSettings g_userSettings = {
.lockAspectRatio {"video.lockAspectRatio", false},
.enableFpsOverlay {"game.enableFpsOverlay", false},
.fpsOverlayCorner {"game.fpsOverlayCorner", 0},
.windowPositionX {"video.windowPositionX", SDL_WINDOWPOS_UNDEFINED},
.windowPositionY {"video.windowPositionY", SDL_WINDOWPOS_UNDEFINED},
.windowWidth {"video.windowWidth", defaultWindowWidth * 2},
.windowHeight {"video.windowHeight", defaultWindowHeight * 2},
},
.audio = {
.masterVolume {"audio.masterVolume", 80},
.masterVolume {"audio.masterVolume", 60},
.mainMusicVolume {"audio.mainMusicVolume", 100},
.subMusicVolume {"audio.subMusicVolume", 100},
.soundEffectsVolume {"audio.soundEffectsVolume", 100},
@@ -58,6 +65,7 @@ UserSettings g_userSettings = {
.bloomMode {"game.bloomMode", BloomMode::Dusk},
.bloomMultiplier {"game.bloomMultiplier", 1.0f},
.disableWaterRefraction {"game.disableWaterRefraction", false},
.enableTextureReplacements {"game.enableTextureReplacements", true},
.enableFrameInterpolation {"game.enableFrameInterpolation", false},
.internalResolutionScale {"game.internalResolutionScale", 0},
.shadowResolutionMultiplier {"game.shadowResolutionMultiplier", 1},
@@ -177,6 +185,10 @@ void registerSettings() {
Register(g_userSettings.video.lockAspectRatio);
Register(g_userSettings.video.enableFpsOverlay);
Register(g_userSettings.video.fpsOverlayCorner);
Register(g_userSettings.video.windowPositionX);
Register(g_userSettings.video.windowPositionY);
Register(g_userSettings.video.windowWidth);
Register(g_userSettings.video.windowHeight);
// Audio
Register(g_userSettings.audio.masterVolume);
@@ -218,6 +230,7 @@ void registerSettings() {
Register(g_userSettings.game.bloomMode);
Register(g_userSettings.game.bloomMultiplier);
Register(g_userSettings.game.disableWaterRefraction);
Register(g_userSettings.game.enableTextureReplacements);
Register(g_userSettings.game.internalResolutionScale);
Register(g_userSettings.game.shadowResolutionMultiplier);
Register(g_userSettings.game.enableDepthOfField);
+83 -48
View File
@@ -37,7 +37,7 @@ Rml::String current_controller_name(int port) {
Rml::String controller_index_name(u32 index) {
const char* name = PADGetNameForControllerIndex(index);
if (name == nullptr) {
return fmt::format("Controller {}", index + 1);
return fmt::format("Device {}", index + 1);
}
return name;
}
@@ -124,7 +124,7 @@ Rml::String native_axis_name(const PADAxisMapping& mapping, SDL_Gamepad* gamepad
return native_button_name(gamepad, static_cast<u32>(mapping.nativeButton));
}
return "Not bound";
return "Not Bound";
}
bool is_dpad_button(PADButton button) {
@@ -162,7 +162,7 @@ bool keyboard_escape_pressed() {
Rml::String keyboard_key_name(s32 scancode) {
if (scancode == PAD_KEY_INVALID) {
return "Not bound";
return "Not Bound";
}
switch (scancode) {
case PAD_KEY_MOUSE_LEFT:
@@ -303,7 +303,7 @@ void ControllerConfigWindow::build_port_tab(Rml::Element* content, int port) {
});
};
addPageButton(Page::Controller, "Controller", [port] { return current_controller_name(port); }, [] { return false; });
addPageButton(Page::Controller, "Device", [port] { return current_controller_name(port); }, [] { return false; });
addPageButton(Page::Buttons, "Buttons", [] { return Rml::String(">"); }, [] { return false; });
addPageButton(Page::Triggers, "Triggers", [] { return Rml::String(">"); }, [] { return false; });
addPageButton(Page::Sticks, "Sticks", [] { return Rml::String(">"); }, [] { return false; });
@@ -349,7 +349,14 @@ void ControllerConfigWindow::build_port_tab(Rml::Element* content, int port) {
rightPane, [](Pane& pane) {
pane.add_text("Treat analog trigger movement as digital L and R button input.");
});
leftPane.register_control(leftPane.add_button("Restore Default Controls").on_pressed([this, port] {
mDoAud_seStartMenu(kSoundClick);
PADRestoreDefaultMapping(port);
}),
rightPane, [](Pane& pane) {
pane.clear();
pane.add_text("Restores all binding configurations for the currently selected device to their defaults.");
});
render_page(rightPane, port, mPage);
}
@@ -365,7 +372,7 @@ void ControllerConfigWindow::render_page(Pane& pane, int port, Page page) {
[port] { return PADGetIndexForPort(port) < 0 && !keyboard_active(port); },
})
.on_pressed([this, port] {
mDoAud_seStartMenu(kSoundItemChange);
mDoAud_seStartMenu(kSoundClick);
cancel_pending_binding();
PADClearPort(port);
PADSetKeyboardActive(static_cast<u32>(port), FALSE);
@@ -378,7 +385,7 @@ void ControllerConfigWindow::render_page(Pane& pane, int port, Page page) {
.isSelected = [port] { return keyboard_active(port); },
})
.on_pressed([this, port] {
mDoAud_seStartMenu(kSoundItemChange);
mDoAud_seStartMenu(kSoundClick);
cancel_pending_binding();
PADClearPort(port);
PADSetKeyboardActive(static_cast<u32>(port), TRUE);
@@ -388,7 +395,7 @@ void ControllerConfigWindow::render_page(Pane& pane, int port, Page page) {
const u32 controllerCount = PADCount();
if (controllerCount == 0) {
pane.add_text("No controllers detected");
pane.add_text("No Device Detected");
break;
}
@@ -400,7 +407,7 @@ void ControllerConfigWindow::render_page(Pane& pane, int port, Page page) {
[port, i] { return PADGetIndexForPort(port) == static_cast<s32>(i); },
})
.on_pressed([this, port, i] {
mDoAud_seStartMenu(kSoundItemChange);
mDoAud_seStartMenu(kSoundClick);
cancel_pending_binding();
PADSetKeyboardActive(static_cast<u32>(port), FALSE);
PADSetPortForIndex(i, port);
@@ -425,17 +432,18 @@ void ControllerConfigWindow::render_page(Pane& pane, int port, Page page) {
PADKeyButtonBinding* bindings =
PADGetKeyButtonBindings(static_cast<u32>(port), &count);
if (bindings == nullptr) {
return Rml::String("Not bound");
return Rml::String("Not Bound");
}
for (u32 i = 0; i < PAD_BUTTON_COUNT; ++i) {
if (bindings[i].padButton == button) {
return keyboard_key_name(bindings[i].scancode);
}
}
return Rml::String("Not bound");
return Rml::String("Not Bound");
},
})
.on_pressed([this, port, button] {
mDoAud_seStartMenu(kSoundClick);
cancel_pending_binding();
mPendingPort = port;
mPendingBindingArmed = false;
@@ -462,7 +470,7 @@ void ControllerConfigWindow::render_page(Pane& pane, int port, Page page) {
u32 buttonCount = 0;
PADButtonMapping* mappings = PADGetButtonMappings(port, &buttonCount);
if (mappings == nullptr) {
pane.add_text("No controller selected");
pane.add_text("No Device Selected");
break;
}
@@ -486,6 +494,7 @@ void ControllerConfigWindow::render_page(Pane& pane, int port, Page page) {
},
})
.on_pressed([this, port, &mapping] {
mDoAud_seStartMenu(kSoundClick);
cancel_pending_binding();
mPendingPort = port;
mPendingBindingArmed = false;
@@ -512,6 +521,7 @@ void ControllerConfigWindow::render_page(Pane& pane, int port, Page page) {
},
})
.on_pressed([this, port, &mapping] {
mDoAud_seStartMenu(kSoundClick);
cancel_pending_binding();
mPendingPort = port;
mPendingBindingArmed = false;
@@ -535,17 +545,18 @@ void ControllerConfigWindow::render_page(Pane& pane, int port, Page page) {
PADKeyButtonBinding* bindings =
PADGetKeyButtonBindings(static_cast<u32>(port), &count);
if (bindings == nullptr) {
return Rml::String("Not bound");
return Rml::String("Not Bound");
}
for (u32 i = 0; i < PAD_BUTTON_COUNT; ++i) {
if (bindings[i].padButton == button) {
return keyboard_key_name(bindings[i].scancode);
}
}
return Rml::String("Not bound");
return Rml::String("Not Bound");
},
})
.on_pressed([this, port, button] {
mDoAud_seStartMenu(kSoundClick);
cancel_pending_binding();
mPendingPort = port;
mPendingBindingArmed = false;
@@ -566,17 +577,18 @@ void ControllerConfigWindow::render_page(Pane& pane, int port, Page page) {
PADKeyAxisBinding* bindings =
PADGetKeyAxisBindings(static_cast<u32>(port), &count);
if (bindings == nullptr) {
return Rml::String("Not bound");
return Rml::String("Not Bound");
}
for (u32 i = 0; i < PAD_AXIS_COUNT; ++i) {
if (bindings[i].padAxis == axis) {
return keyboard_key_name(bindings[i].scancode);
}
}
return Rml::String("Not bound");
return Rml::String("Not Bound");
},
})
.on_pressed([this, port, axis] {
mDoAud_seStartMenu(kSoundClick);
cancel_pending_binding();
mPendingPort = port;
mPendingBindingArmed = false;
@@ -599,7 +611,7 @@ void ControllerConfigWindow::render_page(Pane& pane, int port, Page page) {
u32 buttonCount = 0;
PADButtonMapping* buttons = PADGetButtonMappings(port, &buttonCount);
if (axes == nullptr && buttons == nullptr) {
pane.add_text("No controller selected");
pane.add_text("No Device Selected");
break;
}
@@ -623,6 +635,7 @@ void ControllerConfigWindow::render_page(Pane& pane, int port, Page page) {
},
})
.on_pressed([this, port, &mapping] {
mDoAud_seStartMenu(kSoundClick);
cancel_pending_binding();
mPendingPort = port;
mPendingBindingArmed = false;
@@ -631,30 +644,33 @@ void ControllerConfigWindow::render_page(Pane& pane, int port, Page page) {
}
}
pane.add_section("Digital");
if (buttons != nullptr) {
for (u32 i = 0; i < buttonCount; ++i) {
PADButtonMapping& mapping = buttons[i];
if (mapping.padButton != PAD_TRIGGER_L && mapping.padButton != PAD_TRIGGER_R) {
continue;
if (getSettings().backend.enableAdvancedSettings) {
pane.add_section("Digital");
if (buttons != nullptr) {
for (u32 i = 0; i < buttonCount; ++i) {
PADButtonMapping& mapping = buttons[i];
if (mapping.padButton != PAD_TRIGGER_L && mapping.padButton != PAD_TRIGGER_R) {
continue;
}
pane.add_select_button({
.key = PADGetButtonName(mapping.padButton),
.getValue =
[this, &mapping, gamepad] {
if (mPendingButtonMapping == &mapping) {
return pending_button_label();
}
return native_button_name(
gamepad, mapping.nativeButton);
},
})
.on_pressed([this, port, &mapping] {
mDoAud_seStartMenu(kSoundClick);
cancel_pending_binding();
mPendingPort = port;
mPendingBindingArmed = false;
mPendingButtonMapping = &mapping;
});
}
pane.add_select_button({
.key = PADGetButtonName(mapping.padButton),
.getValue =
[this, &mapping, gamepad] {
if (mPendingButtonMapping == &mapping) {
return pending_button_label();
}
return native_button_name(
gamepad, mapping.nativeButton);
},
})
.on_pressed([this, port, &mapping] {
cancel_pending_binding();
mPendingPort = port;
mPendingBindingArmed = false;
mPendingButtonMapping = &mapping;
});
}
}
@@ -706,17 +722,18 @@ void ControllerConfigWindow::render_page(Pane& pane, int port, Page page) {
PADKeyAxisBinding* bindings =
PADGetKeyAxisBindings(static_cast<u32>(port), &count);
if (bindings == nullptr) {
return Rml::String("Not bound");
return Rml::String("Not Bound");
}
for (u32 i = 0; i < PAD_AXIS_COUNT; ++i) {
if (bindings[i].padAxis == axis) {
return keyboard_key_name(bindings[i].scancode);
}
}
return Rml::String("Not bound");
return Rml::String("Not Bound");
},
})
.on_pressed([this, port, axis] {
mDoAud_seStartMenu(kSoundClick);
cancel_pending_binding();
mPendingPort = port;
mPendingBindingArmed = false;
@@ -741,7 +758,7 @@ void ControllerConfigWindow::render_page(Pane& pane, int port, Page page) {
u32 axisCount = 0;
PADAxisMapping* axes = PADGetAxisMappings(port, &axisCount);
if (axes == nullptr) {
pane.add_text("No controller selected");
pane.add_text("No Device Selected");
break;
}
@@ -762,6 +779,7 @@ void ControllerConfigWindow::render_page(Pane& pane, int port, Page page) {
},
})
.on_pressed([this, port, &mapping] {
mDoAud_seStartMenu(kSoundClick);
cancel_pending_binding();
mPendingPort = port;
mPendingBindingArmed = false;
@@ -907,6 +925,7 @@ void ControllerConfigWindow::render_page(Pane& pane, int port, Page page) {
},
})
.on_pressed([this, port, actionBind] {
mDoAud_seStartMenu(kSoundClick);
cancel_pending_binding();
mPendingPort = port;
mPendingBindingArmed = false;
@@ -926,7 +945,7 @@ void ControllerConfigWindow::render_page(Pane& pane, int port, Page page) {
u32 buttonCount = 0;
PADButtonMapping* mappings = PADGetButtonMappings(port, &buttonCount);
if (mappings == nullptr) {
pane.add_text("No controller selected");
pane.add_text("No Device Selected");
break;
}
@@ -950,6 +969,7 @@ void ControllerConfigWindow::render_page(Pane& pane, int port, Page page) {
},
})
.on_pressed([this, port, actionBind] {
mDoAud_seStartMenu(kSoundClick);
cancel_pending_binding();
mPendingPort = port;
mPendingBindingArmed = false;
@@ -1013,6 +1033,12 @@ void ControllerConfigWindow::poll_pending_binding() {
const s32 nativeButton = PADGetNativeButtonPressed(mPendingPort);
if (nativeButton != -1) {
const int completedPort = mPendingPort;
if (mPendingButtonMapping->nativeButton == static_cast<u32>(nativeButton) &&
(mPendingButtonMapping->padButton != PAD_BUTTON_A &&
mPendingButtonMapping->padButton != PAD_BUTTON_B)) {
unmap_pending_binding();
return;
}
mPendingButtonMapping->nativeButton = static_cast<u32>(nativeButton);
finish_pending_binding(completedPort);
}
@@ -1023,6 +1049,10 @@ void ControllerConfigWindow::poll_pending_binding() {
const PADSignedNativeAxis nativeAxis = PADGetNativeAxisPulled(mPendingPort);
if (nativeAxis.nativeAxis != -1) {
const int completedPort = mPendingPort;
if (mPendingAxisMapping->nativeAxis.nativeAxis == nativeAxis.nativeAxis) {
unmap_pending_binding();
return;
}
mPendingAxisMapping->nativeAxis = nativeAxis;
mPendingAxisMapping->nativeButton = -1;
finish_pending_binding(completedPort);
@@ -1049,6 +1079,10 @@ void ControllerConfigWindow::poll_pending_binding() {
if (button != -1) {
const int completedPort = mPendingPort;
if (mPendingActionBinding->getValue() == button) {
unmap_pending_binding();
return;
}
mPendingActionBinding->setValue(button);
config::Save();
finish_pending_binding(completedPort);
@@ -1058,6 +1092,7 @@ void ControllerConfigWindow::poll_pending_binding() {
}
void ControllerConfigWindow::finish_pending_binding(int completedPort) {
mDoAud_seStartMenu(kSoundBindingChanged);
mPendingButtonMapping = nullptr;
mPendingAxisMapping = nullptr;
mPendingActionBinding = nullptr;
@@ -1110,11 +1145,11 @@ bool ControllerConfigWindow::pending_input_neutral() const {
}
Rml::String ControllerConfigWindow::pending_button_label() const {
return mPendingBindingArmed ? "Press a button..." : "Waiting...";
return mPendingBindingArmed ? "Press a Key or Button..." : "Waiting...";
}
Rml::String ControllerConfigWindow::pending_axis_label() const {
return mPendingBindingArmed ? "Move axis or press a button..." : "Waiting...";
return mPendingBindingArmed ? "Move Axis or press a Key or Button..." : "Waiting...";
}
void ControllerConfigWindow::cancel_pending_binding() {
@@ -1143,7 +1178,7 @@ void ControllerConfigWindow::finish_pending_key_binding() {
}
Rml::String ControllerConfigWindow::pending_key_label() const {
return mPendingBindingArmed ? "Press a key or mouse button..." : "Waiting...";
return mPendingBindingArmed ? "Press a Key or Mouse Button..." : "Waiting...";
}
void ControllerConfigWindow::stop_rumble_test() {
@@ -1159,7 +1194,7 @@ void ControllerConfigWindow::stop_rumble_test() {
Rml::String native_button_name(SDL_Gamepad* gamepad, u32 buttonUntyped) {
if (buttonUntyped == PAD_NATIVE_BUTTON_INVALID) {
return "Not bound";
return "Not Bound";
}
auto button = static_cast<SDL_GamepadButton>(buttonUntyped);
+2 -2
View File
@@ -184,7 +184,7 @@ Rml::String format_graphics_setting_value(GraphicsOption option, int value) {
case BloomMode::Classic:
return "Classic";
case BloomMode::Dusk:
return "Dusk";
return "Dusklight";
}
break;
case GraphicsOption::BloomMultiplier:
@@ -211,7 +211,7 @@ GraphicsTuner::GraphicsTuner(GraphicsTunerProps props, bool prelaunch)
SteppedCarousel::Props{
.min = mValueMin,
.max = mValueMax,
.step = 1,
.step = props.step,
.getValue = [this] { return get_value(mOption); },
.onChange = [this](int value) { set_value(mOption, value); },
.formatValue =
+1
View File
@@ -55,6 +55,7 @@ struct GraphicsTunerProps {
int valueMin = 0;
int valueMax = 0;
int defaultValue = 0;
int step = 1;
};
class GraphicsTuner : public Document {
+20 -11
View File
@@ -454,10 +454,18 @@ bool touch_moved_too_far(
return delta.SquaredMagnitude() > threshold * threshold;
}
void dispatch_menu_key(Rml::Context& context) noexcept {
void emit_key_press(Rml::Context& context, Rml::Input::KeyIdentifier key) noexcept {
context.ProcessMouseLeave();
context.ProcessKeyDown(Rml::Input::KI_F1, 0);
context.ProcessKeyUp(Rml::Input::KI_F1, 0);
context.ProcessKeyDown(key, 0);
}
void emit_key_tap(Rml::Context& context, Rml::Input::KeyIdentifier key) noexcept {
emit_key_press(context, key);
context.ProcessKeyUp(key, 0);
}
void dispatch_menu_key(Rml::Context& context) noexcept {
emit_key_tap(context, Rml::Input::KI_F1);
}
bool handle_touch_menu_tap(Rml::Context& context, const SDL_Event& event) noexcept {
@@ -627,7 +635,9 @@ void process_axis_direction(
if (repeat->held) {
if (released) {
if (!repeat->pending) {
if (repeat->pending) {
emit_key_tap(context, repeat->key);
} else {
context.ProcessKeyUp(repeat->key, 0);
}
set_pad_button_held(port, heldPadButton, false);
@@ -658,8 +668,7 @@ void process_axis_direction(
}
begin_gamepad_key(*repeat, key);
context.ProcessMouseLeave();
context.ProcessKeyDown(key, 0);
emit_key_press(context, key);
}
} // namespace
@@ -747,8 +756,7 @@ void handle_event(const SDL_Event& event) noexcept {
}
}
if (!deferred) {
context->ProcessMouseLeave();
context->ProcessKeyDown(key, 0);
emit_key_press(*context, key);
}
}
} else {
@@ -760,7 +768,9 @@ void handle_event(const SDL_Event& event) noexcept {
if (repeat != nullptr) {
*repeat = {};
}
if (!wasPending) {
if (wasPending) {
emit_key_tap(*context, key);
} else {
context->ProcessKeyUp(key, 0);
}
}
@@ -787,8 +797,7 @@ void update_input() noexcept {
repeat.pressedAt = now;
repeat.nextRepeatAt =
repeat.repeatable ? now + kGamepadRepeatInitialDelay : 0.0;
context->ProcessMouseLeave();
context->ProcessKeyDown(repeat.key, 0);
emit_key_press(*context, repeat.key);
continue;
}
+6 -5
View File
@@ -103,13 +103,13 @@ Rml::Element* create_controller_warning(Rml::Element* parent) {
auto* heading = append(elem, "heading");
auto* title = append(heading, "span");
title->SetInnerRML("No controller assigned");
title->SetInnerRML("No Device Assigned");
auto* icon = append(heading, "icon");
icon->SetClass("warning", true);
auto* message = append(elem, "message");
auto* content = append(message, "span");
content->SetInnerRML("Configure controller port 1 in Settings.");
content->SetInnerRML("Configure <b>Port 1</b> in Settings.");
return elem;
}
@@ -147,7 +147,7 @@ Rml::String back_button_name() {
#if defined(TARGET_ANDROID) || (defined(__APPLE__) && TARGET_OS_IOS && !TARGET_OS_MACCATALYST)
constexpr auto kMenuNotificationPrefix = "3-finger tap or";
#else
constexpr auto kMenuNotificationPrefix = "Press F1 or";
constexpr auto kMenuNotificationPrefix = "Press <b>F1</b> or";
#endif
Rml::Element* create_menu_notification(Rml::Element* parent) {
@@ -169,7 +169,7 @@ Rml::Element* create_menu_notification(Rml::Element* parent) {
append(row, "span")->SetInnerRML(kMenuNotificationPrefix);
auto* icon = append(row, "icon");
icon->SetClass("controller", true);
append(row, "span")->SetInnerRML(escape(padButton));
append(row, "span")->SetInnerRML("<b>" + escape(padButton) + "</b>");
append(row, "span")->SetInnerRML("to open menu");
return elem;
@@ -354,8 +354,9 @@ void Overlay::update() {
}
}
u32 count = 0;
const bool showControllerWarning = PADGetIndexForPort(PAD_CHAN0) < 0 &&
PADGetKeyButtonBindings(PAD_CHAN0, nullptr) == nullptr &&
PADGetKeyButtonBindings(PAD_CHAN0, &count) == nullptr &&
dynamic_cast<Window*>(top_document()) == nullptr &&
dynamic_cast<WindowSmall*>(top_document()) == nullptr;
if (showControllerWarning && mControllerWarning == nullptr) {
+1 -1
View File
@@ -83,7 +83,7 @@ PresetWindow::PresetWindow() : WindowSmall("modal", "modal-dialog") {
"Enhancements disabled to match the GameCube version. "
"Good for speedrunning or simple nostalgia!",
applyPresetClassic},
{"Dusk",
{"Dusklight",
"Graphics & quality of life tweaks, including some from the Wii U version. "
"Our recommended way to play!",
applyPresetDusk},
+17 -11
View File
@@ -793,9 +793,16 @@ SettingsWindow::SettingsWindow(bool prelaunch) : mPrelaunch(prelaunch) {
.valueMin = 0,
.valueMax = 100,
.defaultValue = 100,
.step = 10,
}, mPrelaunch);
leftPane.add_section("Rendering");
config_bool_select(leftPane, rightPane, getSettings().game.enableTextureReplacements,
{
.key = "Use Texture Pack",
.helpText = "Enable installed texture replacements.",
.onChange = [](bool value) { aurora_set_texture_replacements_enabled(value); },
});
config_bool_select(leftPane, rightPane, getSettings().game.enableFrameInterpolation,
{
.key = "Unlock Framerate",
@@ -829,18 +836,18 @@ SettingsWindow::SettingsWindow(bool prelaunch) : mPrelaunch(prelaunch) {
});
};
leftPane.add_section("Controller");
leftPane.register_control(leftPane.add_button("Configure Controller").on_pressed([this] {
leftPane.add_section("Inputs");
leftPane.register_control(leftPane.add_button("Configure Inputs").on_pressed([this] {
push(std::make_unique<ControllerConfigWindow>(mPrelaunch));
}),
rightPane, [](Pane& pane) {
pane.clear();
pane.add_text("Open controller binding configuration.");
pane.add_text("Open input binding configuration.");
});
config_bool_select(leftPane, rightPane, getSettings().game.allowBackgroundInput,
{
.key = "Allow Background Input",
.helpText = "Allow controller input even when the game window is not focused.",
.key = "Allow Background Inputs",
.helpText = "Allow inputs even when the game window is not focused.",
.onChange = [](bool value) { aurora_set_background_input(value); },
});
@@ -953,7 +960,7 @@ SettingsWindow::SettingsWindow(bool prelaunch) : mPrelaunch(prelaunch) {
[](int value) {
getSettings().audio.masterVolume.setValue(value);
config::Save();
audio::SetMasterVolume(value / 100.f);
audio::SetMasterVolume(audio::MasterVolumeToLinear(value / 100.0f));
},
.isModified =
[] {
@@ -1068,8 +1075,7 @@ SettingsWindow::SettingsWindow(bool prelaunch) : mPrelaunch(prelaunch) {
addOption("Faster Tears of Light", getSettings().game.fastTears,
"Tears of Light dropped by Shadow Insects pop out faster like the HD version.");
addSpeedrunDisabledOption("Autosave", getSettings().game.autoSave,
"Autosaves the game when going to a new area, opening a dungeon door, "
"or getting a new item.");
"Autosaves the game when going to a new area or opening a dungeon door.");
addOption("Instant Saves", getSettings().game.instantSaves,
"Skips the delay when writing to the Memory Card.");
addOption("Hold B for Instant Text", getSettings().game.instantText,
@@ -1166,7 +1172,7 @@ SettingsWindow::SettingsWindow(bool prelaunch) : mPrelaunch(prelaunch) {
addCheat("Always Greatspin", getSettings().game.alwaysGreatspin,
"Allows the Great Spin attack without requiring full health.");
addCheat("Fast Iron Boots", getSettings().game.enableFastIronBoots,
"Speeds up movement while wearing the Iron Boots.");
"Speeds up movement while heavy, including wearing the Iron Boots, holding the Ball and Chain, wearing Magic Armor without rupees, etc.");
addCheat("Can Transform Anywhere", getSettings().game.canTransformAnywhere,
"Allows transforming even if NPCs are looking.");
addCheat("Fast Roll", getSettings().game.fastRoll,
@@ -1248,7 +1254,7 @@ SettingsWindow::SettingsWindow(bool prelaunch) : mPrelaunch(prelaunch) {
});
pane.add_button(
{
.text = "Controller",
.text = "Missing Device",
.isSelected =
[] { return getSettings().game.enableControllerToasts.getValue(); },
})
@@ -1301,7 +1307,7 @@ SettingsWindow::SettingsWindow(bool prelaunch) : mPrelaunch(prelaunch) {
config_bool_select(leftPane, rightPane, getSettings().game.enableDiscordPresence,
{
.key = "Enable Discord Rich Presence",
.helpText = "Enable Dusk to integrate with Discord Rich Presence. This allows Discord to show your status in-game.",
.helpText = "Enable Dusklight to integrate with Discord Rich Presence. This allows Discord to show your status in-game.",
.onChange = [](bool enabled) {
if (enabled) {
dusk::discord::initialize();
+16 -2
View File
@@ -11,7 +11,9 @@
#include <ranges>
#include "aurora/lib/window.hpp"
#include "dusk/dusk.h"
#include "dusk/io.hpp"
#include "dusk/config.hpp"
#include "input.hpp"
#include "prelaunch.hpp"
#include "window.hpp"
@@ -130,7 +132,7 @@ void handle_event(const SDL_Event& event) noexcept {
if (getSettings().game.enableControllerToasts) {
const char* name = SDL_GetGamepadName(gamepad);
Rml::String content = fmt::format("<span>{}</span>", name ? name : "[Unknown]");
Rml::String title = "Controller connected";
Rml::String title = "Device Connected";
if (const char* icon = connection_state_icon(SDL_GetGamepadConnectionState(gamepad))) {
title = fmt::format(
"<row><span>{}</span> <icon class=\"connection\">&#x{};</icon></row>", title,
@@ -163,12 +165,24 @@ void handle_event(const SDL_Event& event) noexcept {
const char* name = SDL_GetGamepadNameForID(event.gdevice.which);
push_toast({
.type = "controller",
.title = "Controller disconnected",
.title = "Device Disconnected",
.content = name ? name : "[Unknown]",
.duration = std::chrono::seconds(4),
});
}
sConnectedGamepads.erase(event.gdevice.which);
} else if (event.type == SDL_EVENT_WINDOW_MOVED || event.type == SDL_EVENT_WINDOW_RESIZED) {
int x, y;
if (SDL_GetWindowPosition(aurora::window::get_sdl_window(), &x, &y)) {
getSettings().video.windowPositionX.setValue(x);
getSettings().video.windowPositionY.setValue(y);
}
int width, height;
if (SDL_GetWindowSize(aurora::window::get_sdl_window(), &width, &height)) {
getSettings().video.windowWidth.setValue(width);
getSettings().video.windowHeight.setValue(height);
}
config::Save();
}
input::handle_event(event);
}
+4
View File
@@ -26,6 +26,8 @@ struct Toast {
constexpr u32 kSoundClick = Z2SE_SY_CURSOR_OK;
// "Play" button clicked/pressed
constexpr u32 kSoundPlay = Z2SE_SY_ITEM_COMBINE_ON;
// Input binding changed
constexpr u32 kSoundBindingChanged = Z2SE_SY_ITEM_SET_X;
// Menu button pressed (open/close menu bar or hide/show the active window)
constexpr u32 kSoundMenuOpen = Z2SE_SY_MENU_SUB_IN;
@@ -49,6 +51,8 @@ constexpr u32 kSoundItemDisable = Z2SE_SUBJ_VIEW_OUT;
// Achievement unlocked
constexpr u32 kSoundAchievementUnlock = Z2SE_NAVI_FLY;
// Warning prompt
constexpr u32 kSoundWarning = Z2SE_SY_COW_GET_IN;
struct Insets {
float top = 0.0f;
+1 -1
View File
@@ -807,7 +807,7 @@ static void duskExecute() {
}
if (dusk::getSettings().game.infiniteRupees) {
dComIfGs_setRupee(9999);
dComIfGs_setRupee(dComIfGs_getRupeeMax());
}
if (dusk::getSettings().game.infiniteOxygen) {
+10 -1
View File
@@ -136,8 +136,17 @@ base_process_class* fpcBs_Create(s16 i_profname, fpc_ProcID i_procID, void* i_ap
u32 size;
pprofile = (process_profile_definition*)fpcPf_Get(i_profname);
if (pprofile == NULL) {
#if TARGET_PC
DuskLog.debug("fpcBs_Create: profile not found for profname={}", i_profname);
#endif
return NULL;
}
#if TARGET_PC
const char* procName = getProcName(i_profname);
DuskLog.debug("fpcBs_Create: pid={} profname={} ({}) profile={} procSize={} unkSize={}",
i_procID, getProcName(i_profname), i_profname, (void*)pprofile, pprofile->process_size, pprofile->unk_size);
i_procID, procName ? procName : "(unknown)", i_profname, (void*)pprofile, pprofile->process_size, pprofile->unk_size);
#endif
size = pprofile->process_size + pprofile->unk_size;
pprocess = (base_process_class*)cMl::memalignB(-4, size);
+6
View File
@@ -12,6 +12,12 @@
static int fpcLnIt_MethodCall(create_tag_class* i_createTag, method_filter* i_filter) {
#ifdef TARGET_PC
// on init_state==3 fpcEx_ExecuteQTo already ran (layer_tag.layer is NULL)
if (static_cast<base_process_class*>(i_createTag->mpTagData)->state.init_state == 3) {
return 0;
}
#endif
layer_class* layer = static_cast<base_process_class*>(i_createTag->mpTagData)->layer_tag.layer;
layer_class* save_layer = fpcLy_CurrentLayer();
int ret;
+2 -2
View File
@@ -96,8 +96,8 @@ void mDoLib_project(Vec* src, Vec* dst) {
xSize = FB_WIDTH;
} else {
#if TARGET_PC
xOffset = mDoGph_gInf_c::getSafeMinXF();
xSize = viewPort->width * mDoGph_gInf_c::hudAspectScaleUp;
xOffset = mDoGph_gInf_c::getMinXF();
xSize = mDoGph_gInf_c::getWidthF();
#else
xOffset = viewPort->x_orig;
xSize = viewPort->width;
+6 -6
View File
@@ -551,10 +551,10 @@ int game_main(int argc, char* argv[]) {
config.cachePath = reinterpret_cast<const char*>(cachePathString.c_str());
config.vsync = dusk::getSettings().video.enableVsync;
config.startFullscreen = dusk::getSettings().video.enableFullscreen;
config.windowPosX = -1;
config.windowPosY = -1;
config.windowWidth = defaultWindowWidth * 2;
config.windowHeight = defaultWindowHeight * 2;
config.windowPosX = dusk::getSettings().video.windowPositionX;
config.windowPosY = dusk::getSettings().video.windowPositionY;
config.windowWidth = dusk::getSettings().video.windowWidth;
config.windowHeight = dusk::getSettings().video.windowHeight;
config.desiredBackend = ResolveDesiredBackend(parsed_arg_options);
config.logCallback = &aurora_log_callback;
config.logLevel = startupLogLevel;
@@ -563,7 +563,7 @@ int game_main(int argc, char* argv[]) {
config.allowJoystickBackgroundEvents = dusk::getSettings().game.allowBackgroundInput;
config.pauseOnFocusLost = dusk::getSettings().game.pauseOnFocusLost;
config.imGuiInitCallback = &aurora_imgui_init_callback;
config.allowTextureReplacements = true;
config.allowTextureReplacements = dusk::getSettings().game.enableTextureReplacements;
config.allowTextureDumps = false;
auroraInfo = aurora_initialize(argc, argv, &config);
}
@@ -585,7 +585,7 @@ int game_main(int argc, char* argv[]) {
}
VISetFrameBufferScale(dusk::getSettings().game.internalResolutionScale.getValue());
dusk::audio::SetMasterVolume(dusk::getSettings().audio.masterVolume / 100.0f);
dusk::audio::SetMasterVolume(dusk::audio::MasterVolumeToLinear(dusk::getSettings().audio.masterVolume / 100.0f));
dusk::audio::SetEnableReverb(dusk::getSettings().audio.enableReverb);
dusk::audio::EnableHrtf = dusk::getSettings().audio.enableHrtf;