mirror of
https://github.com/TwilitRealm/dusklight
synced 2026-07-04 19:25:43 -04:00
Compare commits
22 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 0cdcd71b6a | |||
| 318ad2a00f | |||
| a913f1699f | |||
| 01b4eaa2fa | |||
| 9d2ba3eb49 | |||
| 6026b4bb9b | |||
| 7a77d48954 | |||
| 4ee0d8ed4b | |||
| ce554a107d | |||
| 9ce1ab7d5a | |||
| 8830760d34 | |||
| 9abe89f47f | |||
| 3e62c1e96e | |||
| d9bbea300d | |||
| 1a951511be | |||
| ab0efb7a3b | |||
| 5fdc3c7a54 | |||
| 2978ae145d | |||
| e93773757f | |||
| 6be742b15f | |||
| d6cbc9b6d5 | |||
| b10211c4c2 |
+17
-7
@@ -5,8 +5,19 @@ if (NOT CMAKE_BUILD_TYPE)
|
|||||||
"Build type options: Debug Release RelWithDebInfo MinSizeRel" FORCE)
|
"Build type options: Debug Release RelWithDebInfo MinSizeRel" FORCE)
|
||||||
endif ()
|
endif ()
|
||||||
|
|
||||||
# obtain revision info from git
|
set(DUSK_VERSION_OVERRIDE "" CACHE STRING "Override version string (skips git detection and format validation)")
|
||||||
find_package(Git)
|
|
||||||
|
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_WC_REVISION "")
|
||||||
|
set(DUSK_WC_BRANCH "")
|
||||||
|
set(DUSK_WC_DATE "")
|
||||||
|
message(STATUS "Dusklight version overridden to ${DUSK_WC_DESCRIBE}")
|
||||||
|
else ()
|
||||||
|
# obtain revision info from git
|
||||||
|
find_package(Git)
|
||||||
if (GIT_FOUND)
|
if (GIT_FOUND)
|
||||||
# make sure version information gets re-run when the current Git HEAD changes
|
# make sure version information gets re-run when the current Git HEAD changes
|
||||||
execute_process(WORKING_DIRECTORY ${CMAKE_SOURCE_DIR} COMMAND ${GIT_EXECUTABLE} rev-parse --git-path HEAD
|
execute_process(WORKING_DIRECTORY ${CMAKE_SOURCE_DIR} COMMAND ${GIT_EXECUTABLE} rev-parse --git-path HEAD
|
||||||
@@ -63,6 +74,8 @@ else ()
|
|||||||
set(DUSK_SHORT_VERSION_STRING "0.0.0")
|
set(DUSK_SHORT_VERSION_STRING "0.0.0")
|
||||||
endif ()
|
endif ()
|
||||||
|
|
||||||
|
endif ()
|
||||||
|
|
||||||
# Add version information to CI environment variables
|
# Add version information to CI environment variables
|
||||||
if(DEFINED ENV{GITHUB_ENV})
|
if(DEFINED ENV{GITHUB_ENV})
|
||||||
file(APPEND "$ENV{GITHUB_ENV}" "DUSK_VERSION=${DUSK_WC_DESCRIBE}\n")
|
file(APPEND "$ENV{GITHUB_ENV}" "DUSK_VERSION=${DUSK_WC_DESCRIBE}\n")
|
||||||
@@ -112,11 +125,6 @@ option(DUSK_BUILD_WARNINGS "Enable compiler warnings (off by default)")
|
|||||||
option(DUSK_SELECTED_OPT "If on, selected parts of the project will be compiled with optimizations on Debug, intending to make the game run at 30 FPS. Note for MSVC: you will need to remove '/RTC1' from your debug flags in CMake.")
|
option(DUSK_SELECTED_OPT "If on, selected parts of the project will be compiled with optimizations on Debug, intending to make the game run at 30 FPS. Note for MSVC: you will need to remove '/RTC1' from your debug flags in CMake.")
|
||||||
option(DUSK_MOVIE_SUPPORT "If on, compile against libjpeg-turbo to enable THP file decoding" ON)
|
option(DUSK_MOVIE_SUPPORT "If on, compile against libjpeg-turbo to enable THP file decoding" ON)
|
||||||
option(DUSK_ENABLE_UPDATE_CHECKER "Enable update checking support" ON)
|
option(DUSK_ENABLE_UPDATE_CHECKER "Enable update checking support" ON)
|
||||||
|
|
||||||
if(ANDROID)
|
|
||||||
set(DUSK_MOVIE_SUPPORT OFF)
|
|
||||||
endif ()
|
|
||||||
|
|
||||||
option(DUSK_ENABLE_SENTRY_NATIVE "Enable sentry-native crash reporting support" OFF)
|
option(DUSK_ENABLE_SENTRY_NATIVE "Enable sentry-native crash reporting support" OFF)
|
||||||
set(DUSK_SENTRY_DSN "" CACHE STRING "Sentry DSN")
|
set(DUSK_SENTRY_DSN "" CACHE STRING "Sentry DSN")
|
||||||
set(DUSK_SENTRY_ENVIRONMENT "development" CACHE STRING "Sentry environment")
|
set(DUSK_SENTRY_ENVIRONMENT "development" CACHE STRING "Sentry environment")
|
||||||
@@ -155,6 +163,8 @@ if (DUSK_MOVIE_SUPPORT)
|
|||||||
list(APPEND _jpeg_cmake_args -DCMAKE_TOOLCHAIN_FILE=${_jpeg_toolchain_file})
|
list(APPEND _jpeg_cmake_args -DCMAKE_TOOLCHAIN_FILE=${_jpeg_toolchain_file})
|
||||||
endif ()
|
endif ()
|
||||||
set(_jpeg_passthrough_vars
|
set(_jpeg_passthrough_vars
|
||||||
|
ANDROID_ABI
|
||||||
|
ANDROID_PLATFORM
|
||||||
CMAKE_BUILD_TYPE
|
CMAKE_BUILD_TYPE
|
||||||
CMAKE_C_COMPILER
|
CMAKE_C_COMPILER
|
||||||
CMAKE_C_COMPILER_LAUNCHER
|
CMAKE_C_COMPILER_LAUNCHER
|
||||||
|
|||||||
+10
-25
@@ -249,22 +249,11 @@
|
|||||||
"type": "BOOL",
|
"type": "BOOL",
|
||||||
"value": false
|
"value": false
|
||||||
},
|
},
|
||||||
"CMAKE_DISABLE_FIND_PACKAGE_BZip2": {
|
"CMAKE_DISABLE_FIND_PACKAGE_PkgConfig": {
|
||||||
"type": "BOOL",
|
"type": "BOOL",
|
||||||
"value": true
|
"value": true
|
||||||
},
|
},
|
||||||
"CMAKE_DISABLE_FIND_PACKAGE_LibLZMA": {
|
"CMAKE_IGNORE_PREFIX_PATH": "/opt/homebrew"
|
||||||
"type": "BOOL",
|
|
||||||
"value": true
|
|
||||||
},
|
|
||||||
"CMAKE_DISABLE_FIND_PACKAGE_zstd": {
|
|
||||||
"type": "BOOL",
|
|
||||||
"value": true
|
|
||||||
},
|
|
||||||
"CMAKE_DISABLE_FIND_PACKAGE_Freetype": {
|
|
||||||
"type": "BOOL",
|
|
||||||
"value": true
|
|
||||||
}
|
|
||||||
},
|
},
|
||||||
"vendor": {
|
"vendor": {
|
||||||
"microsoft.com/VisualStudioSettings/CMake/1.0": {
|
"microsoft.com/VisualStudioSettings/CMake/1.0": {
|
||||||
@@ -329,7 +318,11 @@
|
|||||||
"cacheVariables": {
|
"cacheVariables": {
|
||||||
"CMAKE_INSTALL_PREFIX": "${sourceDir}/build/install",
|
"CMAKE_INSTALL_PREFIX": "${sourceDir}/build/install",
|
||||||
"CMAKE_TOOLCHAIN_FILE": "$env{ANDROID_HOME}/ndk/$env{ANDROID_NDK_VERSION}/build/cmake/android.toolchain.cmake",
|
"CMAKE_TOOLCHAIN_FILE": "$env{ANDROID_HOME}/ndk/$env{ANDROID_NDK_VERSION}/build/cmake/android.toolchain.cmake",
|
||||||
"ANDROID_PLATFORM": "android-28"
|
"ANDROID_PLATFORM": "android-28",
|
||||||
|
"BUILD_SHARED_LIBS": {
|
||||||
|
"type": "BOOL",
|
||||||
|
"value": false
|
||||||
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@@ -416,7 +409,7 @@
|
|||||||
},
|
},
|
||||||
"CMAKE_OSX_DEPLOYMENT_TARGET": "11.0",
|
"CMAKE_OSX_DEPLOYMENT_TARGET": "11.0",
|
||||||
"CMAKE_IGNORE_PREFIX_PATH": "/opt/homebrew",
|
"CMAKE_IGNORE_PREFIX_PATH": "/opt/homebrew",
|
||||||
"DUSK_MOVIE_SUPPORT": {
|
"BUILD_SHARED_LIBS": {
|
||||||
"type": "BOOL",
|
"type": "BOOL",
|
||||||
"value": false
|
"value": false
|
||||||
}
|
}
|
||||||
@@ -449,11 +442,7 @@
|
|||||||
],
|
],
|
||||||
"cacheVariables": {
|
"cacheVariables": {
|
||||||
"CMAKE_C_COMPILER_LAUNCHER": "sccache",
|
"CMAKE_C_COMPILER_LAUNCHER": "sccache",
|
||||||
"CMAKE_CXX_COMPILER_LAUNCHER": "sccache",
|
"CMAKE_CXX_COMPILER_LAUNCHER": "sccache"
|
||||||
"DUSK_MOVIE_SUPPORT": {
|
|
||||||
"type": "BOOL",
|
|
||||||
"value": false
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@@ -463,11 +452,7 @@
|
|||||||
],
|
],
|
||||||
"cacheVariables": {
|
"cacheVariables": {
|
||||||
"CMAKE_C_COMPILER_LAUNCHER": "sccache",
|
"CMAKE_C_COMPILER_LAUNCHER": "sccache",
|
||||||
"CMAKE_CXX_COMPILER_LAUNCHER": "sccache",
|
"CMAKE_CXX_COMPILER_LAUNCHER": "sccache"
|
||||||
"DUSK_MOVIE_SUPPORT": {
|
|
||||||
"type": "BOOL",
|
|
||||||
"value": false
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
|||||||
Vendored
+1
-1
Submodule extern/aurora updated: f7f3d52cfc...3643a369ad
+2
-1
@@ -1458,7 +1458,6 @@ set(DUSK_FILES
|
|||||||
src/dusk/imgui/ImGuiHeapOverlay.cpp
|
src/dusk/imgui/ImGuiHeapOverlay.cpp
|
||||||
src/dusk/imgui/ImGuiControllerOverlay.cpp
|
src/dusk/imgui/ImGuiControllerOverlay.cpp
|
||||||
src/dusk/imgui/ImGuiStubLog.cpp
|
src/dusk/imgui/ImGuiStubLog.cpp
|
||||||
src/dusk/imgui/ImGuiMapLoader.cpp
|
|
||||||
src/dusk/imgui/ImGuiSaveEditor.cpp
|
src/dusk/imgui/ImGuiSaveEditor.cpp
|
||||||
src/dusk/imgui/ImGuiStateShare.hpp
|
src/dusk/imgui/ImGuiStateShare.hpp
|
||||||
src/dusk/imgui/ImGuiStateShare.cpp
|
src/dusk/imgui/ImGuiStateShare.cpp
|
||||||
@@ -1509,6 +1508,8 @@ set(DUSK_FILES
|
|||||||
src/dusk/ui/tab_bar.hpp
|
src/dusk/ui/tab_bar.hpp
|
||||||
src/dusk/ui/ui.cpp
|
src/dusk/ui/ui.cpp
|
||||||
src/dusk/ui/ui.hpp
|
src/dusk/ui/ui.hpp
|
||||||
|
src/dusk/ui/warp.cpp
|
||||||
|
src/dusk/ui/warp.hpp
|
||||||
src/dusk/ui/window.cpp
|
src/dusk/ui/window.cpp
|
||||||
src/dusk/ui/window.hpp
|
src/dusk/ui/window.hpp
|
||||||
src/dusk/achievements.cpp
|
src/dusk/achievements.cpp
|
||||||
|
|||||||
@@ -50,7 +50,11 @@
|
|||||||
|
|
||||||
# Dusklight Actual (Linux x86_64 only — relies on prebuilt dawn/nod binaries)
|
# Dusklight Actual (Linux x86_64 only — relies on prebuilt dawn/nod binaries)
|
||||||
mkDusklight = pkgs:
|
mkDusklight = pkgs:
|
||||||
let srcs = buildSources pkgs; in
|
let srcs = buildSources pkgs;
|
||||||
|
versionSuffix = if self ? shortRev && self.shortRev != null
|
||||||
|
then "nix-${self.shortRev}"
|
||||||
|
else "nix-dirty";
|
||||||
|
in
|
||||||
pkgs.stdenv.mkDerivation {
|
pkgs.stdenv.mkDerivation {
|
||||||
name = "dusklight";
|
name = "dusklight";
|
||||||
src = ./.;
|
src = ./.;
|
||||||
@@ -62,6 +66,7 @@
|
|||||||
'';
|
'';
|
||||||
# Remove last line to re-enable tests
|
# Remove last line to re-enable tests
|
||||||
cmakeFlags = [
|
cmakeFlags = [
|
||||||
|
"-DDUSK_VERSION_OVERRIDE=${versionSuffix}"
|
||||||
"-DFETCHCONTENT_FULLY_DISCONNECTED=ON"
|
"-DFETCHCONTENT_FULLY_DISCONNECTED=ON"
|
||||||
"-DFETCHCONTENT_SOURCE_DIR_CXXOPTS=${pkgs.cxxopts.src}"
|
"-DFETCHCONTENT_SOURCE_DIR_CXXOPTS=${pkgs.cxxopts.src}"
|
||||||
"-DFETCHCONTENT_SOURCE_DIR_JSON=${pkgs.nlohmann_json.src}"
|
"-DFETCHCONTENT_SOURCE_DIR_JSON=${pkgs.nlohmann_json.src}"
|
||||||
@@ -83,6 +88,14 @@
|
|||||||
mkdir -p $out/bin
|
mkdir -p $out/bin
|
||||||
cp dusklight $out/bin/dusklight
|
cp dusklight $out/bin/dusklight
|
||||||
cp -r ./res $out/bin/res
|
cp -r ./res $out/bin/res
|
||||||
|
|
||||||
|
mkdir -p $out/share/applications
|
||||||
|
cp $src/platforms/freedesktop/dusklight.desktop $out/share/applications/dusklight.desktop
|
||||||
|
|
||||||
|
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 = [
|
nativeBuildInputs = [
|
||||||
pkgs.cmake
|
pkgs.cmake
|
||||||
|
|||||||
@@ -4059,7 +4059,7 @@ public:
|
|||||||
/* 0x02180 */ daAlink_matAnm_c* field_0x2180[2];
|
/* 0x02180 */ daAlink_matAnm_c* field_0x2180[2];
|
||||||
/* 0x02188 */ dEyeHL_c mEyeHL1;
|
/* 0x02188 */ dEyeHL_c mEyeHL1;
|
||||||
/* 0x0219C */ dEyeHL_c mEyeHL2;
|
/* 0x0219C */ dEyeHL_c mEyeHL2;
|
||||||
/* 0x021B0 */ daPy_anmHeap_c mItemHeap[2];
|
/* 0x021B0 */ daPy_anmHeap_c mItemHeap[3];
|
||||||
/* 0x021D8 */ daPy_anmHeap_c mAnmHeap9;
|
/* 0x021D8 */ daPy_anmHeap_c mAnmHeap9;
|
||||||
/* 0x021EC */ daAlinkHIO_c* mpHIO;
|
/* 0x021EC */ daAlinkHIO_c* mpHIO;
|
||||||
/* 0x021F0 */ daAlink_blur_c m_swordBlur;
|
/* 0x021F0 */ daAlink_blur_c m_swordBlur;
|
||||||
|
|||||||
@@ -47,6 +47,7 @@ enum dEvt_type_e {
|
|||||||
/* 0x5 */ dEvt_type_ITEM_e,
|
/* 0x5 */ dEvt_type_ITEM_e,
|
||||||
/* 0x6 */ dEvt_type_SHOWITEM_X_e,
|
/* 0x6 */ dEvt_type_SHOWITEM_X_e,
|
||||||
/* 0x7 */ dEvt_type_SHOWITEM_Y_e,
|
/* 0x7 */ dEvt_type_SHOWITEM_Y_e,
|
||||||
|
/* 0x8 */ dEvt_type_SHOWITEM_Z_e,
|
||||||
/* 0xA */ dEvt_type_CATCH_e = 10,
|
/* 0xA */ dEvt_type_CATCH_e = 10,
|
||||||
/* 0xB */ dEvt_type_TREASURE_e,
|
/* 0xB */ dEvt_type_TREASURE_e,
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -172,7 +172,7 @@ private:
|
|||||||
/* 0x6A9 */ u8 field_0x6a9; // unused
|
/* 0x6A9 */ u8 field_0x6a9; // unused
|
||||||
/* 0x6AA */ u8 mXButtonSlot;
|
/* 0x6AA */ u8 mXButtonSlot;
|
||||||
/* 0x6AB */ u8 mYButtonSlot;
|
/* 0x6AB */ u8 mYButtonSlot;
|
||||||
/* 0x6AC */ u8 field_0x6ac;
|
/* 0x6AC */ u8 mZButtonSlot;
|
||||||
/* 0x6AD */ u8 field_0x6ad;
|
/* 0x6AD */ u8 field_0x6ad;
|
||||||
/* 0x6AE */ u8 mItemsTotal; // Contains the amount of items which are actually obtained and in
|
/* 0x6AE */ u8 mItemsTotal; // Contains the amount of items which are actually obtained and in
|
||||||
// the item wheel
|
// the item wheel
|
||||||
|
|||||||
@@ -160,7 +160,7 @@ private:
|
|||||||
/* 0x078 */ J2DScreen* mpScreen;
|
/* 0x078 */ J2DScreen* mpScreen;
|
||||||
/* 0x07C */ J2DScreen* mpKanteraScreen;
|
/* 0x07C */ J2DScreen* mpKanteraScreen;
|
||||||
/* 0x080 */ J2DScreen* mpPikariScreen;
|
/* 0x080 */ J2DScreen* mpPikariScreen;
|
||||||
/* 0x084 */ J2DPicture* mpItemNumTex[2][3];
|
/* 0x084 */ J2DPicture* mpItemNumTex[3][3];
|
||||||
/* 0x09C */ CPaneMgr* field_0x9c[3];
|
/* 0x09C */ CPaneMgr* field_0x9c[3];
|
||||||
/* 0x0A8 */ int field_0xa8;
|
/* 0x0A8 */ int field_0xa8;
|
||||||
/* 0x0AC */ dKantera_icon_c* mpKanteraMeter[2];
|
/* 0x0AC */ dKantera_icon_c* mpKanteraMeter[2];
|
||||||
|
|||||||
+2
-1
@@ -12,7 +12,7 @@
|
|||||||
|
|
||||||
static const int DEFAULT_SELECT_ITEM_INDEX = 0;
|
static const int DEFAULT_SELECT_ITEM_INDEX = 0;
|
||||||
static const int MAX_SELECT_ITEM = 4;
|
static const int MAX_SELECT_ITEM = 4;
|
||||||
static const int SELECT_ITEM_NUM = 2;
|
static const int SELECT_ITEM_NUM = 3;
|
||||||
static const int MAX_EQUIPMENT = 6;
|
static const int MAX_EQUIPMENT = 6;
|
||||||
static const int MAX_EVENTS = 256;
|
static const int MAX_EVENTS = 256;
|
||||||
static const int MAX_ITEM_SLOTS = 24;
|
static const int MAX_ITEM_SLOTS = 24;
|
||||||
@@ -123,6 +123,7 @@ enum {
|
|||||||
/* 0x3 */ SELECT_ITEM_B,
|
/* 0x3 */ SELECT_ITEM_B,
|
||||||
/* 0x0 */ SELECT_ITEM_X = SELECT_ITEM_LEFT,
|
/* 0x0 */ SELECT_ITEM_X = SELECT_ITEM_LEFT,
|
||||||
/* 0x1 */ SELECT_ITEM_Y = SELECT_ITEM_RIGHT,
|
/* 0x1 */ SELECT_ITEM_Y = SELECT_ITEM_RIGHT,
|
||||||
|
/* 0x2 */ SELECT_ITEM_Z = SELECT_ITEM_DOWN,
|
||||||
};
|
};
|
||||||
|
|
||||||
enum {
|
enum {
|
||||||
|
|||||||
@@ -1,8 +1,19 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
|
#include <cmath>
|
||||||
#include <dolphin/types.h>
|
#include <dolphin/types.h>
|
||||||
|
|
||||||
namespace dusk::audio {
|
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.
|
* Initialize the audio system and start playing audio.
|
||||||
*/
|
*/
|
||||||
|
|||||||
@@ -175,6 +175,7 @@ class ConfigVar : public ConfigVarBase {
|
|||||||
T defaultValue;
|
T defaultValue;
|
||||||
T value;
|
T value;
|
||||||
T overrideValue;
|
T overrideValue;
|
||||||
|
ConfigVarLayer priorLayer = ConfigVarLayer::Default;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
/**
|
/**
|
||||||
@@ -265,6 +266,7 @@ public:
|
|||||||
void setSpeedrunValue(T newValue) {
|
void setSpeedrunValue(T newValue) {
|
||||||
checkRegistered();
|
checkRegistered();
|
||||||
if (layer != ConfigVarLayer::Override) {
|
if (layer != ConfigVarLayer::Override) {
|
||||||
|
priorLayer = layer;
|
||||||
overrideValue = std::move(newValue);
|
overrideValue = std::move(newValue);
|
||||||
layer = ConfigVarLayer::Speedrun;
|
layer = ConfigVarLayer::Speedrun;
|
||||||
}
|
}
|
||||||
@@ -282,9 +284,20 @@ public:
|
|||||||
checkRegistered();
|
checkRegistered();
|
||||||
if (layer == ConfigVarLayer::Speedrun) {
|
if (layer == ConfigVarLayer::Speedrun) {
|
||||||
overrideValue = {};
|
overrideValue = {};
|
||||||
layer = ConfigVarLayer::Value;
|
layer = priorLayer;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \brief Get the user-persisted value, ignoring any temporary overrides.
|
||||||
|
*
|
||||||
|
* Used by Save() to write the correct value even when a speedrun override is active.
|
||||||
|
*/
|
||||||
|
[[nodiscard]] constexpr const T& getValueForSave() const noexcept {
|
||||||
|
checkRegistered();
|
||||||
|
const ConfigVarLayer effectiveLayer = (layer == ConfigVarLayer::Speedrun) ? priorLayer : layer;
|
||||||
|
return effectiveLayer == ConfigVarLayer::Default ? defaultValue : value;
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
using ActionBindConfigVar = ConfigVar<int>;
|
using ActionBindConfigVar = ConfigVar<int>;
|
||||||
|
|||||||
@@ -14,7 +14,6 @@ constexpr const char* SHOW_DEBUG_OVERLAY = "F3";
|
|||||||
constexpr const char* SHOW_HEAP_VIEWER = "F4";
|
constexpr const char* SHOW_HEAP_VIEWER = "F4";
|
||||||
constexpr const char* SHOW_PLAYER_INFO = "F5";
|
constexpr const char* SHOW_PLAYER_INFO = "F5";
|
||||||
constexpr const char* SHOW_SAVE_EDITOR = "F6";
|
constexpr const char* SHOW_SAVE_EDITOR = "F6";
|
||||||
constexpr const char* SHOW_MAP_LOADER = "F7";
|
|
||||||
constexpr const char* SHOW_STATE_SHARE = "F8";
|
constexpr const char* SHOW_STATE_SHARE = "F8";
|
||||||
constexpr const char* SHOW_DEBUG_CAMERA = "F9";
|
constexpr const char* SHOW_DEBUG_CAMERA = "F9";
|
||||||
constexpr const char* SHOW_AUDIO_DEBUG = "F10";
|
constexpr const char* SHOW_AUDIO_DEBUG = "F10";
|
||||||
|
|||||||
@@ -10,6 +10,7 @@ extern bool IsShuttingDown;
|
|||||||
extern bool IsGameLaunched;
|
extern bool IsGameLaunched;
|
||||||
extern bool RestartRequested;
|
extern bool RestartRequested;
|
||||||
extern std::filesystem::path ConfigPath;
|
extern std::filesystem::path ConfigPath;
|
||||||
|
extern std::filesystem::path CachePath;
|
||||||
|
|
||||||
#if defined(__ANDROID__) || (defined(TARGET_OS_IOS) && TARGET_OS_IOS) || \
|
#if defined(__ANDROID__) || (defined(TARGET_OS_IOS) && TARGET_OS_IOS) || \
|
||||||
(defined(TARGET_OS_TV) && TARGET_OS_TV)
|
(defined(TARGET_OS_TV) && TARGET_OS_TV)
|
||||||
|
|||||||
@@ -158,6 +158,7 @@ struct UserSettings {
|
|||||||
// Cheats
|
// Cheats
|
||||||
ConfigVar<bool> infiniteHearts;
|
ConfigVar<bool> infiniteHearts;
|
||||||
ConfigVar<bool> infiniteArrows;
|
ConfigVar<bool> infiniteArrows;
|
||||||
|
ConfigVar<bool> infiniteSeeds;
|
||||||
ConfigVar<bool> infiniteBombs;
|
ConfigVar<bool> infiniteBombs;
|
||||||
ConfigVar<bool> infiniteOil;
|
ConfigVar<bool> infiniteOil;
|
||||||
ConfigVar<bool> infiniteOxygen;
|
ConfigVar<bool> infiniteOxygen;
|
||||||
@@ -171,6 +172,7 @@ struct UserSettings {
|
|||||||
ConfigVar<bool> fastRoll;
|
ConfigVar<bool> fastRoll;
|
||||||
ConfigVar<bool> fastSpinner;
|
ConfigVar<bool> fastSpinner;
|
||||||
ConfigVar<bool> freeMagicArmor;
|
ConfigVar<bool> freeMagicArmor;
|
||||||
|
ConfigVar<bool> invincibleEnemies;
|
||||||
|
|
||||||
// Technical
|
// Technical
|
||||||
ConfigVar<bool> restoreWiiGlitches;
|
ConfigVar<bool> restoreWiiGlitches;
|
||||||
|
|||||||
+20
-20
@@ -4552,7 +4552,7 @@ void daAlink_c::playerInit() {
|
|||||||
PLAYER_CREATE_ANM_HEAP(mFaceBtkHeap, daPy_anmHeap_c::HEAP_TYPE_2, "daAlink_c::mFaceBtkHeap");
|
PLAYER_CREATE_ANM_HEAP(mFaceBtkHeap, daPy_anmHeap_c::HEAP_TYPE_2, "daAlink_c::mFaceBtkHeap");
|
||||||
PLAYER_CREATE_ANM_HEAP(mFaceBckHeap, daPy_anmHeap_c::HEAP_TYPE_3, "daAlink_c::mFaceBckHeap");
|
PLAYER_CREATE_ANM_HEAP(mFaceBckHeap, daPy_anmHeap_c::HEAP_TYPE_3, "daAlink_c::mFaceBckHeap");
|
||||||
|
|
||||||
for (i = 0; i < 2; i++) {
|
for (i = 0; i < SELECT_ITEM_NUM; i++) {
|
||||||
mItemHeap[i].setBufferSize(0x13200);
|
mItemHeap[i].setBufferSize(0x13200);
|
||||||
PLAYER_CREATE_ANM_HEAP_F(mItemHeap[i], daPy_anmHeap_c::HEAP_TYPE_4, "daAlink_c::mItemHeap[%d]", i);
|
PLAYER_CREATE_ANM_HEAP_F(mItemHeap[i], daPy_anmHeap_c::HEAP_TYPE_4, "daAlink_c::mItemHeap[%d]", i);
|
||||||
}
|
}
|
||||||
@@ -9494,7 +9494,7 @@ void daAlink_c::setStickData() {
|
|||||||
if (mDoCPd_c::getTrigY(PAD_1)) {
|
if (mDoCPd_c::getTrigY(PAD_1)) {
|
||||||
mItemTrigger |= (daAlink_ITEM_BTN)BTN_Y;
|
mItemTrigger |= (daAlink_ITEM_BTN)BTN_Y;
|
||||||
}
|
}
|
||||||
if (mDoCPd_c::getTrigZ(PAD_1)) {
|
if (mDoCPd_c::getTrigZ(PAD_1) && !mDoCPd_c::getHoldR(PAD_1)) {
|
||||||
mItemTrigger |= (daAlink_ITEM_BTN)BTN_Z;
|
mItemTrigger |= (daAlink_ITEM_BTN)BTN_Z;
|
||||||
}
|
}
|
||||||
if (mDoCPd_c::getTrigL(PAD_1)) {
|
if (mDoCPd_c::getTrigL(PAD_1)) {
|
||||||
@@ -11297,8 +11297,8 @@ BOOL daAlink_c::checkUpperItemActionFly() {
|
|||||||
void daAlink_c::checkItemButtonChange() {
|
void daAlink_c::checkItemButtonChange() {
|
||||||
if (mProcID != PROC_CANOE_PADDLE_PUT && mEquipItem != dItemNo_NONE_e && !checkEquipAnime()) {
|
if (mProcID != PROC_CANOE_PADDLE_PUT && mEquipItem != dItemNo_NONE_e && !checkEquipAnime()) {
|
||||||
u8 temp_r0;
|
u8 temp_r0;
|
||||||
for (u8 i = 0; i < 2; i++) {
|
for (u8 i = 0; i < SELECT_ITEM_NUM; i++) {
|
||||||
temp_r0 = (i + 1) % 2;
|
temp_r0 = (i + 1) % SELECT_ITEM_NUM;
|
||||||
if (mEquipItem == dComIfGp_getSelectItem(i) &&
|
if (mEquipItem == dComIfGp_getSelectItem(i) &&
|
||||||
(mEquipItem != dComIfGp_getSelectItem(temp_r0) || mSelectItemId != temp_r0))
|
(mEquipItem != dComIfGp_getSelectItem(temp_r0) || mSelectItemId != temp_r0))
|
||||||
{
|
{
|
||||||
@@ -11468,8 +11468,8 @@ int daAlink_c::orderTalk(int i_checkZTalk) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (!checkWolf() && checkRequestTalkActor(mAttList2, field_0x27f8)) {
|
if (!checkWolf() && checkRequestTalkActor(mAttList2, field_0x27f8)) {
|
||||||
for (int i = 0; i < 2; i++) {
|
for (int i = 0; i < 3; i++) {
|
||||||
// check if pressed X or Y and if item on button is a trade item
|
// check if pressed X or Y or Z and if item on button is a trade item
|
||||||
if (checkTradeItem(dComIfGp_getSelectItem(i)) && itemTriggerCheck(1 << i)) {
|
if (checkTradeItem(dComIfGp_getSelectItem(i)) && itemTriggerCheck(1 << i)) {
|
||||||
fopAcM_orderTalkItemBtnEvent(itemTalkType[i], this, field_0x27f8, 0, 0);
|
fopAcM_orderTalkItemBtnEvent(itemTalkType[i], this, field_0x27f8, 0, 0);
|
||||||
return 1;
|
return 1;
|
||||||
@@ -12107,7 +12107,7 @@ void daAlink_c::allUnequip(BOOL param_0) {
|
|||||||
if (checkNoResetFlg2(FLG2_UNK_1) && param_0 && !checkCanoeRide() &&
|
if (checkNoResetFlg2(FLG2_UNK_1) && param_0 && !checkCanoeRide() &&
|
||||||
mEquipItem != dItemNo_KANTERA_e)
|
mEquipItem != dItemNo_KANTERA_e)
|
||||||
{
|
{
|
||||||
for (u8 i = 0; i < 2; i++) {
|
for (u8 i = 0; i < SELECT_ITEM_NUM; i++) {
|
||||||
if (dComIfGp_getSelectItem(i) == dItemNo_KANTERA_e) {
|
if (dComIfGp_getSelectItem(i) == dItemNo_KANTERA_e) {
|
||||||
mSelectItemId = i;
|
mSelectItemId = i;
|
||||||
}
|
}
|
||||||
@@ -12159,7 +12159,7 @@ BOOL daAlink_c::checkItemChangeFromButton() {
|
|||||||
itemEquip(0x105);
|
itemEquip(0x105);
|
||||||
} else {
|
} else {
|
||||||
u8 i;
|
u8 i;
|
||||||
for (i = 0; i < 2; i++) {
|
for (i = 0; i < SELECT_ITEM_NUM; i++) {
|
||||||
int proc_type = checkNewItemChange(i);
|
int proc_type = checkNewItemChange(i);
|
||||||
if (proc_type != 0 && itemTriggerCheck(1 << i)) {
|
if (proc_type != 0 && itemTriggerCheck(1 << i)) {
|
||||||
BOOL var_r27 = changeItemTriggerKeepProc(i, proc_type);
|
BOOL var_r27 = changeItemTriggerKeepProc(i, proc_type);
|
||||||
@@ -12180,7 +12180,7 @@ BOOL daAlink_c::checkItemChangeFromButton() {
|
|||||||
} else if (mEquipItem == dItemNo_NONE_e && mThrowBoomerangAcKeep.getActor() == NULL &&
|
} else if (mEquipItem == dItemNo_NONE_e && mThrowBoomerangAcKeep.getActor() == NULL &&
|
||||||
!checkCanoeRide() && checkNoUpperAnime() && checkNoResetFlg2(FLG2_UNK_1))
|
!checkCanoeRide() && checkNoUpperAnime() && checkNoResetFlg2(FLG2_UNK_1))
|
||||||
{
|
{
|
||||||
for (i = 0; i < 2; i++) {
|
for (i = 0; i < SELECT_ITEM_NUM; i++) {
|
||||||
if (dComIfGp_getSelectItem(i) == dItemNo_KANTERA_e) {
|
if (dComIfGp_getSelectItem(i) == dItemNo_KANTERA_e) {
|
||||||
mSelectItemId = i;
|
mSelectItemId = i;
|
||||||
}
|
}
|
||||||
@@ -12192,7 +12192,7 @@ BOOL daAlink_c::checkItemChangeFromButton() {
|
|||||||
mEquipItem != 0x102 && (!checkCanoeRide() || !checkFisingRodLure()))
|
mEquipItem != 0x102 && (!checkCanoeRide() || !checkFisingRodLure()))
|
||||||
{
|
{
|
||||||
if (!checkEventRun() || strcmp(dComIfGp_getEventManager().getRunEventName(), "ANGER") != 0) {
|
if (!checkEventRun() || strcmp(dComIfGp_getEventManager().getRunEventName(), "ANGER") != 0) {
|
||||||
if (strcmp(dComIfGp_getEventManager().getRunEventName(), "ANGER2") != 0 && checkItemSetButton(mEquipItem) == 2) {
|
if (strcmp(dComIfGp_getEventManager().getRunEventName(), "ANGER2") != 0 && checkItemSetButton(mEquipItem) == 3) {
|
||||||
allUnequip(1);
|
allUnequip(1);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -14386,7 +14386,7 @@ BOOL daAlink_c::checkGroupItem(int i_itemNo, int i_selItem) const {
|
|||||||
}
|
}
|
||||||
|
|
||||||
int daAlink_c::checkSetItemTrigger(int i_itemNo) {
|
int daAlink_c::checkSetItemTrigger(int i_itemNo) {
|
||||||
for (u8 i = 0; i < 2; i++) {
|
for (u8 i = 0; i < SELECT_ITEM_NUM; i++) {
|
||||||
if (checkGroupItem(i_itemNo, dComIfGp_getSelectItem(i)) && itemTriggerCheck(1 << i)) {
|
if (checkGroupItem(i_itemNo, dComIfGp_getSelectItem(i)) && itemTriggerCheck(1 << i)) {
|
||||||
if (i_itemNo != dItemNo_HVY_BOOTS_e) {
|
if (i_itemNo != dItemNo_HVY_BOOTS_e) {
|
||||||
mSelectItemId = i;
|
mSelectItemId = i;
|
||||||
@@ -14399,13 +14399,13 @@ int daAlink_c::checkSetItemTrigger(int i_itemNo) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
int daAlink_c::checkItemSetButton(int i_itemNo) {
|
int daAlink_c::checkItemSetButton(int i_itemNo) {
|
||||||
for (u8 i = 0; i < 2; i++) {
|
for (u8 i = 0; i < SELECT_ITEM_NUM; i++) {
|
||||||
if (checkGroupItem(i_itemNo, dComIfGp_getSelectItem(i))) {
|
if (checkGroupItem(i_itemNo, dComIfGp_getSelectItem(i))) {
|
||||||
return i;
|
return i;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return 2;
|
return 3;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool daAlink_c::checkField() {
|
bool daAlink_c::checkField() {
|
||||||
@@ -14605,7 +14605,7 @@ int daAlink_c::checkNewItemChange(u8 i_selItemIdx) {
|
|||||||
return ITEM_PROC_BOTTLE_DRINK;
|
return ITEM_PROC_BOTTLE_DRINK;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (checkOilBottleItem(sel_item) && checkItemSetButton(dItemNo_KANTERA_e) != 2) {
|
if (checkOilBottleItem(sel_item) && checkItemSetButton(dItemNo_KANTERA_e) != 3) {
|
||||||
return ITEM_PROC_KANDELAAR_POUR;
|
return ITEM_PROC_KANDELAAR_POUR;
|
||||||
}
|
}
|
||||||
} else if (sel_item == dItemNo_HVY_BOOTS_e) {
|
} else if (sel_item == dItemNo_HVY_BOOTS_e) {
|
||||||
@@ -14650,7 +14650,7 @@ int daAlink_c::checkNewItemChange(u8 i_selItemIdx) {
|
|||||||
return ITEM_PROC_SPINNER_READY;
|
return ITEM_PROC_SPINNER_READY;
|
||||||
} else if (checkDungeonWarpItem(sel_item)) {
|
} else if (checkDungeonWarpItem(sel_item)) {
|
||||||
return ITEM_PROC_DUNGEON_WARP_READY;
|
return ITEM_PROC_DUNGEON_WARP_READY;
|
||||||
} else if (checkItemSetButton(0x108) != 2 &&
|
} else if (checkItemSetButton(0x108) != 3 &&
|
||||||
(sel_item == dItemNo_WORM_e || sel_item == dItemNo_BEE_CHILD_e))
|
(sel_item == dItemNo_WORM_e || sel_item == dItemNo_BEE_CHILD_e))
|
||||||
{
|
{
|
||||||
int itemNo = dComIfGp_getSelectItem(checkItemSetButton(0x108));
|
int itemNo = dComIfGp_getSelectItem(checkItemSetButton(0x108));
|
||||||
@@ -14674,7 +14674,7 @@ int daAlink_c::checkNewItemChange(u8 i_selItemIdx) {
|
|||||||
return ITEM_PROC_NOT_USE_ITEM;
|
return ITEM_PROC_NOT_USE_ITEM;
|
||||||
} else if (sel_item == dItemNo_HORSE_FLUTE_e) {
|
} else if (sel_item == dItemNo_HORSE_FLUTE_e) {
|
||||||
return ITEM_PROC_GRASS_WHISTLE;
|
return ITEM_PROC_GRASS_WHISTLE;
|
||||||
} else if (checkOilBottleItem(sel_item) && checkItemSetButton(0x48) != 2) {
|
} else if (checkOilBottleItem(sel_item) && checkItemSetButton(0x48) != 3) {
|
||||||
return ITEM_PROC_KANDELAAR_POUR;
|
return ITEM_PROC_KANDELAAR_POUR;
|
||||||
} else if (sel_item == dItemNo_HAWK_EYE_e) {
|
} else if (sel_item == dItemNo_HAWK_EYE_e) {
|
||||||
if (acceptSubjectModeChange()) {
|
if (acceptSubjectModeChange()) {
|
||||||
@@ -17826,7 +17826,7 @@ int daAlink_c::execute() {
|
|||||||
|
|
||||||
if (checkNoResetFlg2(FLG2_UNK_1) != FALSE &&
|
if (checkNoResetFlg2(FLG2_UNK_1) != FALSE &&
|
||||||
mEquipItem != dItemNo_KANTERA_e &&
|
mEquipItem != dItemNo_KANTERA_e &&
|
||||||
checkItemSetButton(dItemNo_KANTERA_e) == 2) {
|
checkItemSetButton(dItemNo_KANTERA_e) == 3) {
|
||||||
offKandelaarModel();
|
offKandelaarModel();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -18215,7 +18215,7 @@ int daAlink_c::execute() {
|
|||||||
|
|
||||||
if (checkEquipHeavyBoots()) {
|
if (checkEquipHeavyBoots()) {
|
||||||
int itemButton = checkItemSetButton(dItemNo_HVY_BOOTS_e);
|
int itemButton = checkItemSetButton(dItemNo_HVY_BOOTS_e);
|
||||||
if (itemButton == 2 || checkNotHeavyBootsStage()) {
|
if (itemButton == 3 || checkNotHeavyBootsStage()) {
|
||||||
if (!dComIfGp_checkPlayerStatus1(0, 0x10000) || !checkHookshotRoofLv7Boss()) {
|
if (!dComIfGp_checkPlayerStatus1(0, 0x10000) || !checkHookshotRoofLv7Boss()) {
|
||||||
setHeavyBoots(0);
|
setHeavyBoots(0);
|
||||||
}
|
}
|
||||||
@@ -18737,7 +18737,7 @@ int daAlink_c::execute() {
|
|||||||
|
|
||||||
if (!checkWolf()) {
|
if (!checkWolf()) {
|
||||||
u8 tmp;
|
u8 tmp;
|
||||||
for (u8 i = 0; i < 2; i++) {
|
for (u8 i = 0; i < SELECT_ITEM_NUM; i++) {
|
||||||
tmp = (i + 1) % 2;
|
tmp = (i + 1) % 2;
|
||||||
if (dComIfGp_getSelectItem(i) == dItemNo_EMPTY_BOTTLE_e && (mUseButtonFlags & (1 << i)) &&
|
if (dComIfGp_getSelectItem(i) == dItemNo_EMPTY_BOTTLE_e && (mUseButtonFlags & (1 << i)) &&
|
||||||
dComIfGp_getSelectItem(tmp) == dItemNo_EMPTY_BOTTLE_e)
|
dComIfGp_getSelectItem(tmp) == dItemNo_EMPTY_BOTTLE_e)
|
||||||
@@ -18747,7 +18747,7 @@ int daAlink_c::execute() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
for (int i = 0; i < 2; i++) {
|
for (int i = 0; i < SELECT_ITEM_NUM; i++) {
|
||||||
if (!(mUseButtonFlags & (1 << i)) && !(field_0x2faf & (1 << i))) {
|
if (!(mUseButtonFlags & (1 << i)) && !(field_0x2faf & (1 << i))) {
|
||||||
dMeter2Info_offUseButton(METER2_USEBUTTON_X << i);
|
dMeter2Info_offUseButton(METER2_USEBUTTON_X << i);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -4121,7 +4121,7 @@ int daAlink_c::procDungeonWarpReadyInit() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fpc_ProcID id;
|
fpc_ProcID id;
|
||||||
if (checkItemSetButton(dItemNo_DUNGEON_EXIT_e) != 2) {
|
if (checkItemSetButton(dItemNo_DUNGEON_EXIT_e) != 3) {
|
||||||
id = fopAcM_create(fpcNm_OBJ_TKS_e, 0, ¤t.pos, fopAcM_GetRoomNo(this), &shape_angle,
|
id = fopAcM_create(fpcNm_OBJ_TKS_e, 0, ¤t.pos, fopAcM_GetRoomNo(this), &shape_angle,
|
||||||
NULL, -1);
|
NULL, -1);
|
||||||
} else {
|
} else {
|
||||||
|
|||||||
@@ -211,7 +211,7 @@ int daAlink_c::procSpinnerWait() {
|
|||||||
mProcVar3.field_0x300e = shape_angle.y;
|
mProcVar3.field_0x300e = shape_angle.y;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if (checkSetItemTrigger(dItemNo_SPINNER_e) || swordSwingTrigger() || itemSetBtn == 2) {
|
if (checkSetItemTrigger(dItemNo_SPINNER_e) || swordSwingTrigger() || itemSetBtn == SELECT_ITEM_NUM) {
|
||||||
if (swordSwingTrigger()) {
|
if (swordSwingTrigger()) {
|
||||||
swordEquip(0);
|
swordEquip(0);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -77,7 +77,12 @@ int daAlink_c::loadModelDVD() {
|
|||||||
mpWlMidnaHairModel = NULL;
|
mpWlMidnaHairModel = NULL;
|
||||||
|
|
||||||
if (!checkNoResetFlg2(FLG2_UNK_280000)) {
|
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);
|
cPhs_Reset(&mPhaseReq);
|
||||||
mpArcHeap->freeAll();
|
mpArcHeap->freeAll();
|
||||||
|
|
||||||
|
|||||||
@@ -8723,6 +8723,12 @@ int daAlink_c::procWolfCargoCarry() {
|
|||||||
return checkNextActionWolf(0);
|
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::copy(((e_yc_class*)field_0x280c.getActor())->getLegR3Mtx());
|
||||||
mDoMtx_stack_c::transM(-9.0f, -7.0f, -30.0f);
|
mDoMtx_stack_c::transM(-9.0f, -7.0f, -30.0f);
|
||||||
mDoMtx_stack_c::multVecZero(¤t.pos);
|
mDoMtx_stack_c::multVecZero(¤t.pos);
|
||||||
|
|||||||
@@ -7053,6 +7053,12 @@ static int daE_RD_IsDelete(e_rd_class*) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
static int daE_RD_Delete(e_rd_class* i_this) {
|
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;
|
fopEn_enemy_c* enemy = (fopEn_enemy_c*)&i_this->enemy;
|
||||||
fopAcM_RegisterDeleteID(i_this, "E_RD");
|
fopAcM_RegisterDeleteID(i_this, "E_RD");
|
||||||
|
|
||||||
|
|||||||
@@ -15,6 +15,7 @@
|
|||||||
#include "f_op/f_op_actor_mng.h"
|
#include "f_op/f_op_actor_mng.h"
|
||||||
#if TARGET_PC
|
#if TARGET_PC
|
||||||
#include "dusk/achievements.h"
|
#include "dusk/achievements.h"
|
||||||
|
#include "dusk/settings.h"
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
static int plCutLRC[58] = {
|
static int plCutLRC[58] = {
|
||||||
@@ -429,6 +430,13 @@ fopAc_ac_c* cc_at_check(fopAc_ac_c* i_enemy, dCcU_AtInfo* i_AtInfo) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#if TARGET_PC
|
||||||
|
if (dusk::getSettings().game.invincibleEnemies &&
|
||||||
|
fopAcM_GetGroup(i_enemy) == fopAc_ENEMY_e) {
|
||||||
|
i_AtInfo->mAttackPower = 0;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
if (i_AtInfo->mAttackPower != 0) {
|
if (i_AtInfo->mAttackPower != 0) {
|
||||||
i_enemy->health -= i_AtInfo->mAttackPower;
|
i_enemy->health -= i_AtInfo->mAttackPower;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1952,18 +1952,7 @@ u8 dComIfGs_getMixItemIndex(int i_no) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void dComIfGp_setSelectItem(int i_selItemIdx) {
|
void dComIfGp_setSelectItem(int i_selItemIdx) {
|
||||||
if (i_selItemIdx == SELECT_ITEM_DOWN) {
|
if (dComIfGs_getSelectItemIndex(i_selItemIdx) != 0xFF) {
|
||||||
if (dComIfGs_getSelectItemIndex(i_selItemIdx) != 0xFF) {
|
|
||||||
u8 selItem_slotNo = dComIfGs_getSelectItemIndex(i_selItemIdx);
|
|
||||||
g_dComIfG_gameInfo.play.setSelectItem(i_selItemIdx, selItem_slotNo);
|
|
||||||
|
|
||||||
if (selItem_slotNo == 0xFF) {
|
|
||||||
dComIfGs_setSelectItemIndex(i_selItemIdx, 0xFF);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
g_dComIfG_gameInfo.play.setSelectItem(i_selItemIdx, dItemNo_NONE_e);
|
|
||||||
}
|
|
||||||
} else if (dComIfGs_getSelectItemIndex(i_selItemIdx) != 0xFF) {
|
|
||||||
u8 item = dComIfGs_getItem(dComIfGs_getSelectItemIndex(i_selItemIdx), false);
|
u8 item = dComIfGs_getItem(dComIfGs_getSelectItemIndex(i_selItemIdx), false);
|
||||||
g_dComIfG_gameInfo.play.setSelectItem(i_selItemIdx, item);
|
g_dComIfG_gameInfo.play.setSelectItem(i_selItemIdx, item);
|
||||||
|
|
||||||
@@ -1978,7 +1967,8 @@ void dComIfGp_setSelectItem(int i_selItemIdx) {
|
|||||||
u8 dComIfGp_getSelectItem(int i_selItemIdx) {
|
u8 dComIfGp_getSelectItem(int i_selItemIdx) {
|
||||||
u8 playItem = g_dComIfG_gameInfo.play.getSelectItem(i_selItemIdx);
|
u8 playItem = g_dComIfG_gameInfo.play.getSelectItem(i_selItemIdx);
|
||||||
|
|
||||||
if ((i_selItemIdx == SELECT_ITEM_X || i_selItemIdx == SELECT_ITEM_Y) &&
|
if ((i_selItemIdx == SELECT_ITEM_X || i_selItemIdx == SELECT_ITEM_Y ||
|
||||||
|
i_selItemIdx == SELECT_ITEM_Z) &&
|
||||||
dComIfGs_getMixItemIndex(i_selItemIdx) != 0xFF)
|
dComIfGs_getMixItemIndex(i_selItemIdx) != 0xFF)
|
||||||
{
|
{
|
||||||
u8 saveItem = dComIfGs_getItem(dComIfGs_getMixItemIndex(i_selItemIdx), false);
|
u8 saveItem = dComIfGs_getItem(dComIfGs_getMixItemIndex(i_selItemIdx), false);
|
||||||
|
|||||||
@@ -3882,7 +3882,11 @@ bool dCamera_c::hintTalkEvCamera() {
|
|||||||
|
|
||||||
cSAngle acStack_1fc(20.0f);
|
cSAngle acStack_1fc(20.0f);
|
||||||
for (i = 0; i < 2; i++) {
|
for (i = 0; i < 2; i++) {
|
||||||
|
#if AVOID_UB
|
||||||
|
for (j = 0; j < 10; j++) {
|
||||||
|
#else
|
||||||
for (j = 0; j < 12; j++) {
|
for (j = 0; j < 12; j++) {
|
||||||
|
#endif
|
||||||
cSAngle acStack_200(local_b0[j] * fVar22);
|
cSAngle acStack_200(local_b0[j] * fVar22);
|
||||||
hintTalk->mDirection.U(acStack_1f8 + acStack_200);
|
hintTalk->mDirection.U(acStack_1f8 + acStack_200);
|
||||||
hintTalk->mDirection.V(((hintTalk->field_0x28.V() * acStack_200.Cos()) * 0.2f) + acStack_1fc);
|
hintTalk->mDirection.V(((hintTalk->field_0x28.V() * acStack_200.Cos()) * 0.2f) + acStack_1fc);
|
||||||
|
|||||||
@@ -287,6 +287,10 @@ int dEvt_control_c::talkXyCheck(dEvt_order_c* order) {
|
|||||||
mTalkXyType = 2;
|
mTalkXyType = 2;
|
||||||
itemIndex = SELECT_ITEM_Y;
|
itemIndex = SELECT_ITEM_Y;
|
||||||
break;
|
break;
|
||||||
|
case dEvt_type_SHOWITEM_Z_e:
|
||||||
|
mTalkXyType = 3;
|
||||||
|
itemIndex = SELECT_ITEM_Z;
|
||||||
|
break;
|
||||||
#if PLATFORM_WII || PLATFORM_SHIELD
|
#if PLATFORM_WII || PLATFORM_SHIELD
|
||||||
case 8:
|
case 8:
|
||||||
mTalkXyType = 3;
|
mTalkXyType = 3;
|
||||||
|
|||||||
@@ -446,7 +446,7 @@ void dMenu_ItemExplain_c::move_proc() {
|
|||||||
if (field_0xe7 == 0) {
|
if (field_0xe7 == 0) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (!mDoCPd_c::getTrigX(PAD_1) && !mDoCPd_c::getTrigY(PAD_1)) {
|
if (!mDoCPd_c::getTrigX(PAD_1) && !mDoCPd_c::getTrigY(PAD_1) && !mDoCPd_c::getTrigZ(PAD_1)) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -460,6 +460,8 @@ void dMenu_ItemExplain_c::move_proc() {
|
|||||||
mEndButton = 3;
|
mEndButton = 3;
|
||||||
} else if (mDoCPd_c::getTrigY(PAD_1)) {
|
} else if (mDoCPd_c::getTrigY(PAD_1)) {
|
||||||
mEndButton = 4;
|
mEndButton = 4;
|
||||||
|
} else if (mDoCPd_c::getTrigZ(PAD_1)) {
|
||||||
|
mEndButton = 5;
|
||||||
}
|
}
|
||||||
mStatus = 5;
|
mStatus = 5;
|
||||||
Z2GetAudioMgr()->seStart(Z2SE_SY_EXP_WIN_CLOSE, NULL, 0, 0, 1.0f, 1.0f, -1.0f, -1.0f, 0);
|
Z2GetAudioMgr()->seStart(Z2SE_SY_EXP_WIN_CLOSE, NULL, 0, 0, 1.0f, 1.0f, -1.0f, -1.0f, 0);
|
||||||
|
|||||||
+45
-15
@@ -134,7 +134,7 @@ dMenu_Ring_c::dMenu_Ring_c(JKRExpHeap* i_heap, STControl* i_stick, CSTControl* i
|
|||||||
field_0x6a9 = 0;
|
field_0x6a9 = 0;
|
||||||
mXButtonSlot = 0xff;
|
mXButtonSlot = 0xff;
|
||||||
mYButtonSlot = 0xff;
|
mYButtonSlot = 0xff;
|
||||||
field_0x6ac = 0xff;
|
mZButtonSlot = 0xff;
|
||||||
field_0x6ad = 0xff;
|
field_0x6ad = 0xff;
|
||||||
field_0x670 = 0;
|
field_0x670 = 0;
|
||||||
field_0x67e = 0;
|
field_0x67e = 0;
|
||||||
@@ -244,8 +244,8 @@ dMenu_Ring_c::dMenu_Ring_c(JKRExpHeap* i_heap, STControl* i_stick, CSTControl* i
|
|||||||
if (dComIfGs_getSelectItemIndex(1) == dComIfGs_getLineUpItem(i)) {
|
if (dComIfGs_getSelectItemIndex(1) == dComIfGs_getLineUpItem(i)) {
|
||||||
mYButtonSlot = i;
|
mYButtonSlot = i;
|
||||||
}
|
}
|
||||||
if (dComIfGs_getSelectItemIndex(2) == dComIfGs_getWolfAbility(i)) {
|
if (dComIfGs_getSelectItemIndex(2) == dComIfGs_getLineUpItem(i)) {
|
||||||
field_0x6ac = i;
|
mZButtonSlot = i;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
mRingRadiusH = g_ringHIO.mRingRadiusH;
|
mRingRadiusH = g_ringHIO.mRingRadiusH;
|
||||||
@@ -259,7 +259,7 @@ dMenu_Ring_c::dMenu_Ring_c(JKRExpHeap* i_heap, STControl* i_stick, CSTControl* i
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
field_0x6be[i] = 0;
|
field_0x6be[i] = 0;
|
||||||
if (i == 2) {
|
if (i == MAX_SELECT_ITEM) {
|
||||||
setSelectItem(i, 0);
|
setSelectItem(i, 0);
|
||||||
} else {
|
} else {
|
||||||
setSelectItem(i, 0x43);
|
setSelectItem(i, 0x43);
|
||||||
@@ -977,8 +977,8 @@ void dMenu_Ring_c::setItem() {
|
|||||||
} else {
|
} else {
|
||||||
uVar2 = dItemNo_NONE_e;
|
uVar2 = dItemNo_NONE_e;
|
||||||
}
|
}
|
||||||
if (field_0x6ac != dItemNo_NONE_e) {
|
if (mZButtonSlot != dItemNo_NONE_e) {
|
||||||
uVar3 = mItemSlots[field_0x6ac];
|
uVar3 = mItemSlots[mZButtonSlot];
|
||||||
} else {
|
} else {
|
||||||
uVar3 = dItemNo_NONE_e;
|
uVar3 = dItemNo_NONE_e;
|
||||||
}
|
}
|
||||||
@@ -1058,6 +1058,9 @@ void dMenu_Ring_c::setItem() {
|
|||||||
mixItemIndex1 = dItemNo_NONE_e;
|
mixItemIndex1 = dItemNo_NONE_e;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
} else if (field_0x6b3 == 2) {
|
||||||
|
mZButtonSlot = mCurrentSlot;
|
||||||
|
uVar3 = mItemSlots[mZButtonSlot];
|
||||||
}
|
}
|
||||||
field_0x6b4[0] = uVar1;
|
field_0x6b4[0] = uVar1;
|
||||||
field_0x6b4[1] = uVar2;
|
field_0x6b4[1] = uVar2;
|
||||||
@@ -1073,7 +1076,7 @@ void dMenu_Ring_c::setItem() {
|
|||||||
|
|
||||||
void dMenu_Ring_c::setJumpItem(bool i_useVibrationM) {
|
void dMenu_Ring_c::setJumpItem(bool i_useVibrationM) {
|
||||||
for (int i = 0; i < 4; i++) {
|
for (int i = 0; i < 4; i++) {
|
||||||
if (i == 2) {
|
if (i == 4) {
|
||||||
setSelectItem(i, field_0x6b4[i]);
|
setSelectItem(i, field_0x6b4[i]);
|
||||||
} else if (i == field_0x6cd) {
|
} else if (i == field_0x6cd) {
|
||||||
setSelectItem(i, getItem(field_0x6cb, 0));
|
setSelectItem(i, getItem(field_0x6cb, 0));
|
||||||
@@ -1089,9 +1092,9 @@ void dMenu_Ring_c::setJumpItem(bool i_useVibrationM) {
|
|||||||
field_0x518[1] = mItemSlotPosX[mYButtonSlot];
|
field_0x518[1] = mItemSlotPosX[mYButtonSlot];
|
||||||
field_0x528[1] = mItemSlotPosY[mYButtonSlot];
|
field_0x528[1] = mItemSlotPosY[mYButtonSlot];
|
||||||
}
|
}
|
||||||
if (field_0x6ac != dItemNo_NONE_e) {
|
if (mZButtonSlot != dItemNo_NONE_e) {
|
||||||
field_0x518[2] = mItemSlotPosX[field_0x6ac];
|
field_0x518[2] = mItemSlotPosX[mZButtonSlot];
|
||||||
field_0x528[2] = mItemSlotPosY[field_0x6ac];
|
field_0x528[2] = mItemSlotPosY[mZButtonSlot];
|
||||||
}
|
}
|
||||||
if (field_0x6ad != dItemNo_NONE_e) {
|
if (field_0x6ad != dItemNo_NONE_e) {
|
||||||
field_0x518[3] = mItemSlotPosX[field_0x6ad];
|
field_0x518[3] = mItemSlotPosX[field_0x6ad];
|
||||||
@@ -1117,9 +1120,21 @@ void dMenu_Ring_c::setJumpItem(bool i_useVibrationM) {
|
|||||||
field_0x674[1] = 1;
|
field_0x674[1] = 1;
|
||||||
#if TARGET_PC
|
#if TARGET_PC
|
||||||
mSelectItemSlideElapsed[1] = 0.0f;
|
mSelectItemSlideElapsed[1] = 0.0f;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
} else if (field_0x6b3 == 2) {
|
||||||
|
field_0x538[0] = g_ringHIO.mUnselectItemScale;
|
||||||
|
field_0x538[1] = g_ringHIO.mSelectItemScale;
|
||||||
|
if (field_0x6b4[2] != dComIfGs_getSelectItemIndex(2) ||
|
||||||
|
field_0x6b8[2] != dComIfGs_getMixItemIndex(2))
|
||||||
|
{
|
||||||
|
field_0x674[2] = 1;
|
||||||
|
#if TARGET_PC
|
||||||
|
mSelectItemSlideElapsed[2] = 0.0f;
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (field_0x674[0] == 1) {
|
if (field_0x674[0] == 1) {
|
||||||
if (i_useVibrationM) {
|
if (i_useVibrationM) {
|
||||||
dMeter2Info_set2DVibrationM();
|
dMeter2Info_set2DVibrationM();
|
||||||
@@ -1160,7 +1175,7 @@ void dMenu_Ring_c::setScale() {
|
|||||||
}
|
}
|
||||||
setNameString(itemId);
|
setNameString(itemId);
|
||||||
setItemScale(i, g_ringHIO.mUnselectItemScale);
|
setItemScale(i, g_ringHIO.mUnselectItemScale);
|
||||||
for (int j = 0; j < 2; j++) {
|
for (int j = 0; j < SELECT_ITEM_NUM; j++) {
|
||||||
if (j == field_0x6cf) {
|
if (j == field_0x6cf) {
|
||||||
setButtonScale(j, g_ringHIO.mSelectButtonScale);
|
setButtonScale(j, g_ringHIO.mSelectButtonScale);
|
||||||
} else {
|
} else {
|
||||||
@@ -1180,7 +1195,7 @@ void dMenu_Ring_c::setScale() {
|
|||||||
} else {
|
} else {
|
||||||
setItemScale(i, g_ringHIO.mUnselectItemScale);
|
setItemScale(i, g_ringHIO.mUnselectItemScale);
|
||||||
}
|
}
|
||||||
for (int j = 0; j < 2; j++) {
|
for (int j = 0; j < SELECT_ITEM_NUM; j++) {
|
||||||
setButtonScale(j, g_ringHIO.mUnselectButtonScale);
|
setButtonScale(j, g_ringHIO.mUnselectButtonScale);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1214,6 +1229,7 @@ void dMenu_Ring_c::setNameString(u32 i_stringID) {
|
|||||||
|
|
||||||
void dMenu_Ring_c::setActiveCursor() {
|
void dMenu_Ring_c::setActiveCursor() {
|
||||||
u8 item = dComIfGs_getItem(mItemSlots[mCurrentSlot], false);
|
u8 item = dComIfGs_getItem(mItemSlots[mCurrentSlot], false);
|
||||||
|
|
||||||
if (mStatus == STATUS_WAIT && mOldStatus != STATUS_EXPLAIN_FORCE && mOldStatus != STATUS_EXPLAIN && mpItemExplain->getStatus() == 0) {
|
if (mStatus == STATUS_WAIT && mOldStatus != STATUS_EXPLAIN_FORCE && mOldStatus != STATUS_EXPLAIN && mpItemExplain->getStatus() == 0) {
|
||||||
if (mDoCPd_c::getTrigR(PAD_1) && !mPlayerIsWolf && item != dItemNo_NONE_e) {
|
if (mDoCPd_c::getTrigR(PAD_1) && !mPlayerIsWolf && item != dItemNo_NONE_e) {
|
||||||
for (int i = 0; i < MAX_SELECT_ITEM; i++) {
|
for (int i = 0; i < MAX_SELECT_ITEM; i++) {
|
||||||
@@ -1244,7 +1260,21 @@ void dMenu_Ring_c::setActiveCursor() {
|
|||||||
(this->*stick_init[mStatus])();
|
(this->*stick_init[mStatus])();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else if (mDoCPd_c::getTrigX(PAD_1) || mDoCPd_c::getTrigY(PAD_1)) {
|
} else if (mDoCPd_c::getTrigZ(PAD_1) && !mPlayerIsWolf && item != dItemNo_NONE_e) {
|
||||||
|
for (int i = 0; i < MAX_SELECT_ITEM; i++) {
|
||||||
|
setSelectItemForce(i);
|
||||||
|
}
|
||||||
|
field_0x6b3 = 2;
|
||||||
|
if (!checkCombineBomb(field_0x6b3)) {
|
||||||
|
setItem();
|
||||||
|
if (mpItemExplain->getStatus() == 0) {
|
||||||
|
setStatus(STATUS_WAIT);
|
||||||
|
(this->*stick_init[mStatus])();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else if (mDoCPd_c::getTrigX(PAD_1) || mDoCPd_c::getTrigY(PAD_1) ||
|
||||||
|
mDoCPd_c::getTrigZ(PAD_1))
|
||||||
|
{
|
||||||
// If the player is a wolf or somehow manages to access an item slot with no item, error
|
// If the player is a wolf or somehow manages to access an item slot with no item, error
|
||||||
Z2GetAudioMgr()->seStart(Z2SE_SYS_ERROR, NULL, 0, 0, 1.0f, 1.0f, -1.0f, -1.0f, 0);
|
Z2GetAudioMgr()->seStart(Z2SE_SYS_ERROR, NULL, 0, 0, 1.0f, 1.0f, -1.0f, -1.0f, 0);
|
||||||
}
|
}
|
||||||
@@ -1660,7 +1690,7 @@ void dMenu_Ring_c::drawSelectItem() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void dMenu_Ring_c::setSelectItemForce(int i_idx) {
|
void dMenu_Ring_c::setSelectItemForce(int i_idx) {
|
||||||
if (i_idx == 2) {
|
if (i_idx == SELECT_ITEM_NUM) {
|
||||||
if (field_0x674[i_idx] != 0) {
|
if (field_0x674[i_idx] != 0) {
|
||||||
dComIfGs_setSelectItemIndex(i_idx, field_0x6b4[i_idx]);
|
dComIfGs_setSelectItemIndex(i_idx, field_0x6b4[i_idx]);
|
||||||
field_0x674[i_idx] = 0;
|
field_0x674[i_idx] = 0;
|
||||||
@@ -1669,7 +1699,7 @@ void dMenu_Ring_c::setSelectItemForce(int i_idx) {
|
|||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
} else if (field_0x674[i_idx] != 0) {
|
} else if (field_0x674[i_idx] != 0) {
|
||||||
for (int i = 0; i < 2; i++) {
|
for (int i = 0; i < SELECT_ITEM_NUM; i++) {
|
||||||
dComIfGs_setMixItemIndex(i, field_0x6b8[i]);
|
dComIfGs_setMixItemIndex(i, field_0x6b8[i]);
|
||||||
dComIfGs_setSelectItemIndex(i, field_0x6b4[i]);
|
dComIfGs_setSelectItemIndex(i, field_0x6b4[i]);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1533,6 +1533,8 @@ void dMeter2Info_c::setMiniGameItem(u8 i_minigameFlag) {
|
|||||||
if (mMiniGameItemSetFlag != 3) {
|
if (mMiniGameItemSetFlag != 3) {
|
||||||
dComIfGs_setItem(SLOT_4, dItemNo_BOW_e);
|
dComIfGs_setItem(SLOT_4, dItemNo_BOW_e);
|
||||||
dComIfGp_setItem(SLOT_4, dItemNo_BOW_e);
|
dComIfGp_setItem(SLOT_4, dItemNo_BOW_e);
|
||||||
|
dComIfGs_setMixItemIndex(SELECT_ITEM_Z, 0xFF);
|
||||||
|
dComIfGs_setSelectItemIndex(SELECT_ITEM_Z, 0xFF);
|
||||||
dComIfGs_setMixItemIndex(SELECT_ITEM_Y, 0xFF);
|
dComIfGs_setMixItemIndex(SELECT_ITEM_Y, 0xFF);
|
||||||
dComIfGs_setSelectItemIndex(SELECT_ITEM_Y, 0xFF);
|
dComIfGs_setSelectItemIndex(SELECT_ITEM_Y, 0xFF);
|
||||||
dComIfGs_setMixItemIndex(SELECT_ITEM_X, SLOT_4);
|
dComIfGs_setMixItemIndex(SELECT_ITEM_X, SLOT_4);
|
||||||
|
|||||||
+10
-4
@@ -26,8 +26,12 @@ void updateAutoSave() {
|
|||||||
(AutoSaveFuncsProc[mAutoSaveProc])();
|
(AutoSaveFuncsProc[mAutoSaveProc])();
|
||||||
}
|
}
|
||||||
|
|
||||||
void writeAutoSave() {
|
bool writeAutoSave() {
|
||||||
int stageNo = dStage_stagInfo_GetSaveTbl(dComIfGp_getStageStagInfo());
|
stage_stag_info_class* stagInfo = dComIfGp_getStageStagInfo();
|
||||||
|
if (stagInfo == nullptr) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
int stageNo = dStage_stagInfo_GetSaveTbl(stagInfo);
|
||||||
|
|
||||||
dComIfGs_putSave(stageNo);
|
dComIfGs_putSave(stageNo);
|
||||||
dComIfGs_setMemoryToCard(mSaveBuffer, dComIfGs_getDataNum());
|
dComIfGs_setMemoryToCard(mSaveBuffer, dComIfGs_getDataNum());
|
||||||
@@ -40,6 +44,7 @@ void writeAutoSave() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
g_mDoMemCd_control.save(mSaveBuffer, sizeof(mSaveBuffer), 0);
|
g_mDoMemCd_control.save(mSaveBuffer, sizeof(mSaveBuffer), 0);
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
void autoSaving() {
|
void autoSaving() {
|
||||||
@@ -48,8 +53,9 @@ void autoSaving() {
|
|||||||
if (cardState == 2) {
|
if (cardState == 2) {
|
||||||
mAutoSaveProc = 1;
|
mAutoSaveProc = 1;
|
||||||
} else if (cardState == 1) {
|
} else if (cardState == 1) {
|
||||||
writeAutoSave();
|
if (writeAutoSave()) {
|
||||||
mAutoSaveProc = 3;
|
mAutoSaveProc = 3;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+3
-2
@@ -61,7 +61,7 @@ void ConfigImpl<T>::loadFromJson(ConfigVar<T>& cVar, const json& jsonValue) {
|
|||||||
|
|
||||||
template<ConfigValue T>
|
template<ConfigValue T>
|
||||||
nlohmann::json ConfigImpl<T>::dumpToJson(const ConfigVar<T>& cVar) {
|
nlohmann::json ConfigImpl<T>::dumpToJson(const ConfigVar<T>& cVar) {
|
||||||
return cVar.getValue();
|
return cVar.getValueForSave();
|
||||||
}
|
}
|
||||||
|
|
||||||
template<ConfigValue T> requires std::is_integral_v<T> && std::is_signed_v<T>
|
template<ConfigValue T> requires std::is_integral_v<T> && std::is_signed_v<T>
|
||||||
@@ -249,7 +249,8 @@ void dusk::config::Save() {
|
|||||||
json j;
|
json j;
|
||||||
|
|
||||||
for (const auto& pair : RegisteredConfigVars) {
|
for (const auto& pair : RegisteredConfigVars) {
|
||||||
if (pair.second->getLayer() == ConfigVarLayer::Value) {
|
const auto layer = pair.second->getLayer();
|
||||||
|
if (layer == ConfigVarLayer::Value || layer == ConfigVarLayer::Speedrun) {
|
||||||
j[pair.first] = pair.second->getImpl()->dumpToJson(*pair.second);
|
j[pair.first] = pair.second->getImpl()->dumpToJson(*pair.second);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -61,7 +61,7 @@ std::string release_name() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
std::filesystem::path sentry_database_path() {
|
std::filesystem::path sentry_database_path() {
|
||||||
return dusk::ConfigPath / "sentry";
|
return dusk::CachePath / "sentry";
|
||||||
}
|
}
|
||||||
|
|
||||||
std::filesystem::path log_attachment_path() {
|
std::filesystem::path log_attachment_path() {
|
||||||
|
|||||||
+222
-93
@@ -6,6 +6,7 @@
|
|||||||
#include "dusk/main.h"
|
#include "dusk/main.h"
|
||||||
|
|
||||||
#include <array>
|
#include <array>
|
||||||
|
#include <chrono>
|
||||||
#include <filesystem>
|
#include <filesystem>
|
||||||
#include <optional>
|
#include <optional>
|
||||||
#include <ranges>
|
#include <ranges>
|
||||||
@@ -30,6 +31,21 @@ constexpr auto kLocationDescriptorName = "data_location.json";
|
|||||||
constexpr auto kPipelineCacheName = "pipeline_cache.db";
|
constexpr auto kPipelineCacheName = "pipeline_cache.db";
|
||||||
constexpr auto kInitialPipelineCacheName = "initial_pipeline_cache.db";
|
constexpr auto kInitialPipelineCacheName = "initial_pipeline_cache.db";
|
||||||
|
|
||||||
|
constexpr std::array<std::string_view, 4> kUserDataDirectories = {
|
||||||
|
"texture_replacements",
|
||||||
|
"USA",
|
||||||
|
"EUR",
|
||||||
|
"JAP",
|
||||||
|
};
|
||||||
|
constexpr std::array<std::string_view, 6> kUserDataFiles = {
|
||||||
|
"achievements.json",
|
||||||
|
"config.json",
|
||||||
|
"controller_ports.dat",
|
||||||
|
"imgui.ini",
|
||||||
|
"keyboard_bindings.dat",
|
||||||
|
"states.json",
|
||||||
|
};
|
||||||
|
|
||||||
enum class LocationMode {
|
enum class LocationMode {
|
||||||
Default,
|
Default,
|
||||||
Portable,
|
Portable,
|
||||||
@@ -62,6 +78,7 @@ struct MigrationStats {
|
|||||||
|
|
||||||
std::optional<std::filesystem::path> sConfiguredDataPath;
|
std::optional<std::filesystem::path> sConfiguredDataPath;
|
||||||
std::optional<std::filesystem::path> sActiveDescriptorPath;
|
std::optional<std::filesystem::path> sActiveDescriptorPath;
|
||||||
|
std::optional<std::filesystem::path> sActivePrefPath;
|
||||||
|
|
||||||
std::filesystem::path path_from_utf8(std::string_view value) {
|
std::filesystem::path path_from_utf8(std::string_view value) {
|
||||||
return std::filesystem::path{
|
return std::filesystem::path{
|
||||||
@@ -70,19 +87,22 @@ std::filesystem::path path_from_utf8(std::string_view value) {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
std::filesystem::path get_legacy_path() {
|
std::filesystem::path legacy_path_for_pref_path(const std::filesystem::path& prefPath) {
|
||||||
if (std::string_view{LegacyAppName}.empty()) {
|
if (std::string_view{LegacyAppName}.empty() || prefPath.empty()) {
|
||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
|
|
||||||
char* prefPath = SDL_GetPrefPath(OrgName, LegacyAppName);
|
auto normalizedPrefPath = prefPath;
|
||||||
if (!prefPath) {
|
if (normalizedPrefPath.filename().empty()) {
|
||||||
Log.fatal("Unable to get PrefPath: {}", SDL_GetError());
|
normalizedPrefPath = normalizedPrefPath.parent_path();
|
||||||
}
|
}
|
||||||
|
|
||||||
std::filesystem::path result{reinterpret_cast<const char8_t*>(prefPath)};
|
const auto parentPath = normalizedPrefPath.parent_path();
|
||||||
SDL_free(prefPath);
|
if (parentPath.empty()) {
|
||||||
return result;
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
|
return parentPath / LegacyAppName;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::filesystem::path get_pref_path() {
|
std::filesystem::path get_pref_path() {
|
||||||
@@ -96,6 +116,13 @@ std::filesystem::path get_pref_path() {
|
|||||||
return result;
|
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) {
|
std::filesystem::path base_path_relative(const std::filesystem::path& path) {
|
||||||
const auto* basePath = SDL_GetBasePath();
|
const auto* basePath = SDL_GetBasePath();
|
||||||
if (!basePath) {
|
if (!basePath) {
|
||||||
@@ -249,6 +276,69 @@ std::filesystem::path absolute_path(const std::filesystem::path& path) {
|
|||||||
return absolute.lexically_normal();
|
return absolute.lexically_normal();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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 prefPath;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::error_code ec;
|
||||||
|
if (!std::filesystem::exists(legacyPath, ec)) {
|
||||||
|
if (ec) {
|
||||||
|
Log.warn("Failed to inspect legacy data directory '{}': {}",
|
||||||
|
io::fs_path_to_string(legacyPath), ec.message());
|
||||||
|
}
|
||||||
|
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 prefPath;
|
||||||
|
}
|
||||||
|
if (prefExists) {
|
||||||
|
if (!std::filesystem::is_directory(prefPath, ec) ||
|
||||||
|
!std::filesystem::is_empty(prefPath, ec))
|
||||||
|
{
|
||||||
|
if (ec) {
|
||||||
|
Log.warn("Failed to inspect data directory '{}': {}",
|
||||||
|
io::fs_path_to_string(prefPath), ec.message());
|
||||||
|
} else {
|
||||||
|
Log.info("Skipping legacy data directory rename because '{}' is not empty",
|
||||||
|
io::fs_path_to_string(prefPath));
|
||||||
|
}
|
||||||
|
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 prefPath;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
std::filesystem::rename(legacyPath, prefPath, ec);
|
||||||
|
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());
|
||||||
|
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) {
|
bool is_same_or_inside(const std::filesystem::path& root, const std::filesystem::path& path) {
|
||||||
const auto normalizedRoot = normalized_path(root);
|
const auto normalizedRoot = normalized_path(root);
|
||||||
const auto normalizedPath = normalized_path(path);
|
const auto normalizedPath = normalized_path(path);
|
||||||
@@ -283,85 +373,46 @@ bool should_skip_migration_path(const std::filesystem::path& path,
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool has_location_descriptor(const std::filesystem::path& path) {
|
bool matches_name(std::string_view name, const auto& names) {
|
||||||
std::error_code ec;
|
return std::ranges::find(names, name) != names.end();
|
||||||
return std::filesystem::exists(path / kLocationDescriptorName, ec);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool remove_empty_destination_for_rename(const std::filesystem::path& path) {
|
bool should_migrate_user_data_path(
|
||||||
std::error_code ec;
|
const std::filesystem::path& sourcePath, const std::filesystem::path& from) {
|
||||||
const bool exists = std::filesystem::exists(path, ec);
|
const auto relativePath = sourcePath.lexically_relative(from);
|
||||||
if (ec) {
|
if (relativePath.empty() || relativePath.is_absolute()) {
|
||||||
Log.debug("Could not inspect migration destination '{}': {}", io::fs_path_to_string(path),
|
|
||||||
ec.message());
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
if (!exists) {
|
|
||||||
|
auto it = relativePath.begin();
|
||||||
|
if (it == relativePath.end() || *it == "..") {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
const auto first = io::fs_path_to_string(*it);
|
||||||
|
if (matches_name(first, kUserDataDirectories)) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
const bool canRemove = std::filesystem::is_directory(path, ec) &&
|
++it;
|
||||||
std::filesystem::is_empty(path, ec) && !has_location_descriptor(path);
|
if (it != relativePath.end()) {
|
||||||
if (ec || !canRemove) {
|
|
||||||
if (ec) {
|
|
||||||
Log.debug("Could not inspect migration destination '{}': {}",
|
|
||||||
io::fs_path_to_string(path), ec.message());
|
|
||||||
}
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::filesystem::remove(path, ec);
|
const auto filename = io::fs_path_to_string(relativePath.filename());
|
||||||
if (ec) {
|
if (matches_name(filename, kUserDataFiles)) {
|
||||||
Log.debug("Could not remove empty migration destination '{}': {}",
|
return true;
|
||||||
io::fs_path_to_string(path), ec.message());
|
|
||||||
return false;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return true;
|
return relativePath.extension() == ".controller" || relativePath.extension() == ".gci" ||
|
||||||
}
|
(filename.starts_with("MemoryCard") && filename.ends_with(".raw"));
|
||||||
|
|
||||||
bool try_rename_directory_migration(
|
|
||||||
const std::filesystem::path& from, const std::filesystem::path& to) {
|
|
||||||
std::error_code ec;
|
|
||||||
if (!std::filesystem::is_directory(from, ec)) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
if (ec) {
|
|
||||||
Log.debug("Could not inspect migration source '{}': {}", io::fs_path_to_string(from),
|
|
||||||
ec.message());
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
if (has_location_descriptor(from)) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
if (!remove_empty_destination_for_rename(to)) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
std::filesystem::create_directories(to.parent_path(), ec);
|
|
||||||
if (ec) {
|
|
||||||
Log.debug("Could not create migration destination parent '{}': {}",
|
|
||||||
io::fs_path_to_string(to.parent_path()), ec.message());
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
std::filesystem::rename(from, to, ec);
|
|
||||||
if (ec) {
|
|
||||||
Log.debug("Could not rename data directory '{}' to '{}': {}", io::fs_path_to_string(from),
|
|
||||||
io::fs_path_to_string(to), ec.message());
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
Log.info("Renamed data directory '{}' to '{}'", io::fs_path_to_string(from),
|
|
||||||
io::fs_path_to_string(to));
|
|
||||||
return true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
std::filesystem::path current_data_path() {
|
std::filesystem::path current_data_path() {
|
||||||
if (!ConfigPath.empty()) {
|
if (!ConfigPath.empty()) {
|
||||||
return ConfigPath;
|
return ConfigPath;
|
||||||
}
|
}
|
||||||
const auto prefPath = get_pref_path();
|
const auto prefPath = active_pref_path();
|
||||||
const auto descriptor = read_location_descriptor(prefPath);
|
const auto descriptor = read_location_descriptor(prefPath);
|
||||||
if (descriptor) {
|
if (descriptor) {
|
||||||
sActiveDescriptorPath = descriptor->path;
|
sActiveDescriptorPath = descriptor->path;
|
||||||
@@ -427,7 +478,7 @@ bool write_location_descriptor(LocationMode mode, const std::filesystem::path& t
|
|||||||
json["previousPath"] = io::fs_path_to_string(descriptor.previousPath);
|
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)) {
|
for (const auto& path : descriptor_write_paths(prefPath)) {
|
||||||
if (write_descriptor_json(path, json)) {
|
if (write_descriptor_json(path, json)) {
|
||||||
sActiveDescriptorPath = path;
|
sActiveDescriptorPath = path;
|
||||||
@@ -439,6 +490,61 @@ bool write_location_descriptor(LocationMode mode, const std::filesystem::path& t
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void set_error(std::string* errorOut, std::string error) {
|
||||||
|
if (errorOut != nullptr) {
|
||||||
|
*errorOut = std::move(error);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool validate_writable_data_path(const std::filesystem::path& path, std::string* errorOut) {
|
||||||
|
if (path.empty()) {
|
||||||
|
set_error(errorOut, "Choose a folder.");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::error_code ec;
|
||||||
|
std::filesystem::create_directories(path, ec);
|
||||||
|
if (ec) {
|
||||||
|
set_error(errorOut, fmt::format("{} could not create the selected folder.", AppName));
|
||||||
|
Log.warn("Failed to create custom data folder '{}': {}", io::fs_path_to_string(path),
|
||||||
|
ec.message());
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!std::filesystem::is_directory(path, ec)) {
|
||||||
|
set_error(errorOut, "The selected path is not a folder.");
|
||||||
|
if (ec) {
|
||||||
|
Log.warn("Failed to inspect custom data folder '{}': {}", io::fs_path_to_string(path),
|
||||||
|
ec.message());
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
const auto probePath = path / fmt::format(".write-probe-{}.tmp",
|
||||||
|
std::chrono::steady_clock::now().time_since_epoch().count());
|
||||||
|
try {
|
||||||
|
io::FileStream::WriteAllText(probePath, "dusk");
|
||||||
|
} catch (const std::exception& e) {
|
||||||
|
set_error(errorOut, fmt::format("{} could not write to the selected folder.", AppName));
|
||||||
|
Log.warn("Failed write probe for custom data folder '{}': {}", io::fs_path_to_string(path),
|
||||||
|
e.what());
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::filesystem::remove(probePath, ec);
|
||||||
|
if (ec) {
|
||||||
|
set_error(
|
||||||
|
errorOut, fmt::format("{} could write to the selected folder, but could not remove "
|
||||||
|
"the test file it created.",
|
||||||
|
AppName));
|
||||||
|
Log.warn("Failed to remove custom data folder write probe '{}': {}",
|
||||||
|
io::fs_path_to_string(probePath), ec.message());
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
std::uintmax_t remove_empty_directories(const std::filesystem::path& root, bool includeRoot) {
|
std::uintmax_t remove_empty_directories(const std::filesystem::path& root, bool includeRoot) {
|
||||||
std::error_code ec;
|
std::error_code ec;
|
||||||
std::vector<std::filesystem::path> directories;
|
std::vector<std::filesystem::path> directories;
|
||||||
@@ -647,14 +753,6 @@ void migrate_directory(const std::filesystem::path& from, const std::filesystem:
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (try_rename_directory_migration(from, to)) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (try_rename_directory_migration(from, to)) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
std::filesystem::create_directories(to, ec);
|
std::filesystem::create_directories(to, ec);
|
||||||
if (ec) {
|
if (ec) {
|
||||||
++stats.failures;
|
++stats.failures;
|
||||||
@@ -700,6 +798,16 @@ void migrate_directory(const std::filesystem::path& from, const std::filesystem:
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!should_migrate_user_data_path(sourcePath, from)) {
|
||||||
|
++stats.skippedUnsupportedEntries;
|
||||||
|
if (std::filesystem::is_directory(status)) {
|
||||||
|
it.disable_recursion_pending();
|
||||||
|
}
|
||||||
|
ec.clear();
|
||||||
|
it.increment(ec);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
const auto relativePath = sourcePath.lexically_relative(from);
|
const auto relativePath = sourcePath.lexically_relative(from);
|
||||||
if (relativePath.empty() || relativePath.is_absolute()) {
|
if (relativePath.empty() || relativePath.is_absolute()) {
|
||||||
++stats.failures;
|
++stats.failures;
|
||||||
@@ -761,8 +869,6 @@ void migrate_data(const std::filesystem::path& prefPath, const std::filesystem::
|
|||||||
const LocationDescriptor* descriptor) {
|
const LocationDescriptor* descriptor) {
|
||||||
if (descriptor && !descriptor->previousPath.empty()) {
|
if (descriptor && !descriptor->previousPath.empty()) {
|
||||||
migrate_directory(descriptor->previousPath, dataPath, prefPath);
|
migrate_directory(descriptor->previousPath, dataPath, prefPath);
|
||||||
} else if (const auto legacyPath = get_legacy_path(); !legacyPath.empty()) {
|
|
||||||
migrate_directory(legacyPath, dataPath, prefPath);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -899,17 +1005,25 @@ bool open_data_path() {
|
|||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
bool set_custom_data_path(const std::filesystem::path& path) {
|
bool set_custom_data_path(const std::filesystem::path& path, std::string* errorOut) {
|
||||||
if (path.empty()) {
|
if (!validate_writable_data_path(path, errorOut)) {
|
||||||
Log.warn("Ignoring empty custom data path");
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
return write_location_descriptor(LocationMode::Custom, path);
|
if (!write_location_descriptor(LocationMode::Custom, path)) {
|
||||||
|
set_error(errorOut, fmt::format("{} could not save the data folder setting.", AppName));
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool set_custom_data_path(const char* path) {
|
bool set_custom_data_path(const char* path, std::string* errorOut) {
|
||||||
return set_custom_data_path(path_from_utf8(path));
|
if (path == nullptr) {
|
||||||
|
set_error(errorOut, "Choose a folder.");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return set_custom_data_path(path_from_utf8(path), errorOut);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool set_portable_data_path() {
|
bool set_portable_data_path() {
|
||||||
@@ -917,12 +1031,12 @@ bool set_portable_data_path() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
bool reset_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));
|
return write_location_descriptor(LocationMode::Default, default_data_path(prefPath));
|
||||||
}
|
}
|
||||||
|
|
||||||
bool is_default_data_path() {
|
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));
|
return normalized_path(configured_data_path()) == normalized_path(default_data_path(prefPath));
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -931,7 +1045,7 @@ std::filesystem::path configured_data_path() {
|
|||||||
return *sConfiguredDataPath;
|
return *sConfiguredDataPath;
|
||||||
}
|
}
|
||||||
|
|
||||||
const auto prefPath = get_pref_path();
|
const auto prefPath = active_pref_path();
|
||||||
const auto descriptor = read_location_descriptor(prefPath);
|
const auto descriptor = read_location_descriptor(prefPath);
|
||||||
if (descriptor) {
|
if (descriptor) {
|
||||||
sActiveDescriptorPath = descriptor->path;
|
sActiveDescriptorPath = descriptor->path;
|
||||||
@@ -941,6 +1055,13 @@ std::filesystem::path configured_data_path() {
|
|||||||
return *sConfiguredDataPath;
|
return *sConfiguredDataPath;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
std::filesystem::path cache_path() {
|
||||||
|
if (!CachePath.empty()) {
|
||||||
|
return CachePath;
|
||||||
|
}
|
||||||
|
return active_pref_path();
|
||||||
|
}
|
||||||
|
|
||||||
bool is_data_path_restart_pending() {
|
bool is_data_path_restart_pending() {
|
||||||
if (ConfigPath.empty()) {
|
if (ConfigPath.empty()) {
|
||||||
return false;
|
return false;
|
||||||
@@ -949,8 +1070,12 @@ bool is_data_path_restart_pending() {
|
|||||||
return normalized_path(ConfigPath) != normalized_path(configured_data_path());
|
return normalized_path(ConfigPath) != normalized_path(configured_data_path());
|
||||||
}
|
}
|
||||||
|
|
||||||
std::filesystem::path initialize_data() {
|
Paths initialize_data() {
|
||||||
const auto prefPath = get_pref_path();
|
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);
|
const auto descriptor = read_location_descriptor(prefPath);
|
||||||
if (descriptor) {
|
if (descriptor) {
|
||||||
sActiveDescriptorPath = descriptor->path;
|
sActiveDescriptorPath = descriptor->path;
|
||||||
@@ -963,9 +1088,13 @@ std::filesystem::path initialize_data() {
|
|||||||
|
|
||||||
migrate_data(prefPath, dataPath, descriptor ? &descriptor->descriptor : nullptr);
|
migrate_data(prefPath, dataPath, descriptor ? &descriptor->descriptor : nullptr);
|
||||||
ensure_data_directory(dataPath);
|
ensure_data_directory(dataPath);
|
||||||
ensure_initial_pipeline_cache(dataPath);
|
ensure_data_directory(prefPath);
|
||||||
|
ensure_initial_pipeline_cache(prefPath);
|
||||||
|
|
||||||
return dataPath;
|
return Paths{
|
||||||
|
.userPath = dataPath,
|
||||||
|
.cachePath = prefPath,
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace dusk::data
|
} // namespace dusk::data
|
||||||
|
|||||||
+11
-4
@@ -1,6 +1,7 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include <filesystem>
|
#include <filesystem>
|
||||||
|
#include <string>
|
||||||
|
|
||||||
#if defined(__APPLE__)
|
#if defined(__APPLE__)
|
||||||
#include <TargetConditionals.h>
|
#include <TargetConditionals.h>
|
||||||
@@ -14,7 +15,7 @@
|
|||||||
#define DUSK_CAN_OPEN_DATA_FOLDER 0
|
#define DUSK_CAN_OPEN_DATA_FOLDER 0
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#if defined(__APPLE__) && TARGET_OS_IOS && !TARGET_OS_MACCATALYST
|
#if (defined(__APPLE__) && TARGET_OS_IOS && !TARGET_OS_MACCATALYST) || defined(__ANDROID__)
|
||||||
#define DUSK_CAN_CHANGE_DATA_FOLDER 0
|
#define DUSK_CAN_CHANGE_DATA_FOLDER 0
|
||||||
#else
|
#else
|
||||||
#define DUSK_CAN_CHANGE_DATA_FOLDER 1
|
#define DUSK_CAN_CHANGE_DATA_FOLDER 1
|
||||||
@@ -22,11 +23,17 @@
|
|||||||
|
|
||||||
namespace dusk::data {
|
namespace dusk::data {
|
||||||
|
|
||||||
std::filesystem::path initialize_data();
|
struct Paths {
|
||||||
|
std::filesystem::path userPath;
|
||||||
|
std::filesystem::path cachePath;
|
||||||
|
};
|
||||||
|
|
||||||
|
Paths initialize_data();
|
||||||
std::filesystem::path configured_data_path();
|
std::filesystem::path configured_data_path();
|
||||||
|
std::filesystem::path cache_path();
|
||||||
bool open_data_path();
|
bool open_data_path();
|
||||||
bool set_custom_data_path(const char* path);
|
bool set_custom_data_path(const char* path, std::string* errorOut);
|
||||||
bool set_custom_data_path(const std::filesystem::path& path);
|
bool set_custom_data_path(const std::filesystem::path& path, std::string* errorOut);
|
||||||
bool set_portable_data_path();
|
bool set_portable_data_path();
|
||||||
bool reset_data_path();
|
bool reset_data_path();
|
||||||
bool is_default_data_path();
|
bool is_default_data_path();
|
||||||
|
|||||||
@@ -368,7 +368,6 @@ namespace dusk {
|
|||||||
m_menuTools.ShowProcessManager();
|
m_menuTools.ShowProcessManager();
|
||||||
m_menuTools.ShowHeapOverlay();
|
m_menuTools.ShowHeapOverlay();
|
||||||
m_menuTools.ShowStubLog();
|
m_menuTools.ShowStubLog();
|
||||||
m_menuTools.ShowMapLoader();
|
|
||||||
m_menuTools.ShowBloomWindow();
|
m_menuTools.ShowBloomWindow();
|
||||||
m_menuTools.ShowPlayerInfo();
|
m_menuTools.ShowPlayerInfo();
|
||||||
m_menuTools.ShowAudioDebug();
|
m_menuTools.ShowAudioDebug();
|
||||||
|
|||||||
@@ -1,149 +0,0 @@
|
|||||||
#include "d/d_com_inf_game.h"
|
|
||||||
|
|
||||||
#include "imgui.h"
|
|
||||||
#include <imgui_internal.h>
|
|
||||||
#include "ImGuiConsole.hpp"
|
|
||||||
#include "ImGuiMenuTools.hpp"
|
|
||||||
#include "dusk/map_loader_definitions.h"
|
|
||||||
#include "fmt/format.h"
|
|
||||||
|
|
||||||
namespace dusk {
|
|
||||||
void ImGuiMenuTools::ShowMapLoader() {
|
|
||||||
if (!getSettings().backend.enableAdvancedSettings ||
|
|
||||||
!ImGuiConsole::CheckMenuViewToggle(ImGuiKey_F7, m_showMapLoader))
|
|
||||||
{
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
ImGuiWindowFlags windowFlags = ImGuiWindowFlags_AlwaysAutoResize |
|
|
||||||
ImGuiWindowFlags_NoFocusOnAppearing | ImGuiWindowFlags_NoNav;
|
|
||||||
|
|
||||||
// ImGui::SetNextWindowBgAlpha(0.65f);
|
|
||||||
|
|
||||||
if (!ImGui::Begin("Map Loader", &m_showMapLoader, windowFlags)) {
|
|
||||||
ImGui::End();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
ImGui::Checkbox("Show Internal Names", &m_mapLoaderInfo.showInternalNames);
|
|
||||||
|
|
||||||
const char* previewRegion = "None";
|
|
||||||
if (m_mapLoaderInfo.regionIdx != -1) {
|
|
||||||
previewRegion = gameRegions[m_mapLoaderInfo.regionIdx].regionName;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (ImGui::BeginCombo("Select Region", previewRegion)) {
|
|
||||||
int idx = 0;
|
|
||||||
for (const auto& region : gameRegions) {
|
|
||||||
if (ImGui::Selectable(region.regionName)) {
|
|
||||||
if (m_mapLoaderInfo.regionIdx != idx) {
|
|
||||||
m_mapLoaderInfo.mapIdx = 0;
|
|
||||||
m_mapLoaderInfo.roomNoIdx = 0;
|
|
||||||
m_mapLoaderInfo.pointNoIdx = 0;
|
|
||||||
}
|
|
||||||
m_mapLoaderInfo.regionIdx = idx;
|
|
||||||
}
|
|
||||||
idx++;
|
|
||||||
}
|
|
||||||
ImGui::EndCombo();
|
|
||||||
}
|
|
||||||
|
|
||||||
if (m_mapLoaderInfo.regionIdx != -1) {
|
|
||||||
const auto& region = gameRegions[m_mapLoaderInfo.regionIdx];
|
|
||||||
|
|
||||||
std::string previewMap = "None";
|
|
||||||
if (m_mapLoaderInfo.mapIdx != -1) {
|
|
||||||
const auto& map = region.maps[m_mapLoaderInfo.mapIdx];
|
|
||||||
previewMap = m_mapLoaderInfo.showInternalNames ? fmt::format("{} ({})", map.mapName, map.mapFile) : map.mapName;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (ImGui::BeginCombo("Select Map", previewMap.data())) {
|
|
||||||
int prevMapIdx = m_mapLoaderInfo.mapIdx;
|
|
||||||
for (int i = 0; i < region.maps.size(); ++i) {
|
|
||||||
const auto& map = region.maps[i];
|
|
||||||
std::string label = m_mapLoaderInfo.showInternalNames ? fmt::format("{} ({})", map.mapName, map.mapFile) : map.mapName;
|
|
||||||
if (ImGui::Selectable(label.data())) {
|
|
||||||
m_mapLoaderInfo.mapIdx = i;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
ImGui::EndCombo();
|
|
||||||
if (m_mapLoaderInfo.mapIdx != prevMapIdx) {
|
|
||||||
m_mapLoaderInfo.roomNoIdx = 0;
|
|
||||||
m_mapLoaderInfo.pointNoIdx = 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
ImGui::Text("No region selected.");
|
|
||||||
}
|
|
||||||
|
|
||||||
if (m_mapLoaderInfo.regionIdx != -1 && m_mapLoaderInfo.mapIdx != -1) {
|
|
||||||
const auto& region = gameRegions[m_mapLoaderInfo.regionIdx];
|
|
||||||
const auto& map = region.maps[m_mapLoaderInfo.mapIdx];
|
|
||||||
const auto& room = map.mapRooms[m_mapLoaderInfo.roomNoIdx];
|
|
||||||
|
|
||||||
if (map.mapRooms.size() > 1) {
|
|
||||||
ImGui::Text("Selected Room: %2d", room.roomNo);
|
|
||||||
ImGui::SameLine();
|
|
||||||
if (ImGui::Button("-###RoomNoIdxDec")) {
|
|
||||||
m_mapLoaderInfo.roomNoIdx--;
|
|
||||||
if (m_mapLoaderInfo.roomNoIdx < 0) {
|
|
||||||
m_mapLoaderInfo.roomNoIdx = map.mapRooms.size() - 1;
|
|
||||||
}
|
|
||||||
m_mapLoaderInfo.pointNoIdx = 0;
|
|
||||||
}
|
|
||||||
ImGui::SameLine();
|
|
||||||
if (ImGui::Button("+###RoomNoIdxInc")) {
|
|
||||||
m_mapLoaderInfo.roomNoIdx++;
|
|
||||||
if (m_mapLoaderInfo.roomNoIdx >= map.mapRooms.size()) {
|
|
||||||
m_mapLoaderInfo.roomNoIdx = 0;
|
|
||||||
}
|
|
||||||
m_mapLoaderInfo.pointNoIdx = 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
constexpr int MAX_LAYER = 14;
|
|
||||||
|
|
||||||
ImGui::Text("Selected Layer: %3d", m_mapLoaderInfo.layer);
|
|
||||||
ImGui::SameLine();
|
|
||||||
if (ImGui::Button("-###layerDec")) {
|
|
||||||
m_mapLoaderInfo.layer--;
|
|
||||||
if (m_mapLoaderInfo.layer < -1) {
|
|
||||||
m_mapLoaderInfo.layer = MAX_LAYER;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
ImGui::SameLine();
|
|
||||||
if (ImGui::Button("+###layerInc")) {
|
|
||||||
m_mapLoaderInfo.layer++;
|
|
||||||
if (m_mapLoaderInfo.layer > MAX_LAYER) {
|
|
||||||
m_mapLoaderInfo.layer = -1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (room.roomPoints.size() > 1) {
|
|
||||||
ImGui::Text("Selected Point: %3d", room.roomPoints[m_mapLoaderInfo.pointNoIdx]);
|
|
||||||
ImGui::SameLine();
|
|
||||||
if (ImGui::Button("-###PointNoIdxDec")) {
|
|
||||||
m_mapLoaderInfo.pointNoIdx--;
|
|
||||||
if (m_mapLoaderInfo.pointNoIdx < 0) {
|
|
||||||
m_mapLoaderInfo.pointNoIdx = room.roomPoints.size() - 1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
ImGui::SameLine();
|
|
||||||
if (ImGui::Button("+###PointNoIdxInc")) {
|
|
||||||
m_mapLoaderInfo.pointNoIdx++;
|
|
||||||
if (m_mapLoaderInfo.pointNoIdx >= room.roomPoints.size()) {
|
|
||||||
m_mapLoaderInfo.pointNoIdx = 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (ImGui::Button("Warp")) {
|
|
||||||
dComIfGp_setNextStage(map.mapFile, room.roomPoints[m_mapLoaderInfo.pointNoIdx], room.roomNo, m_mapLoaderInfo.layer);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
ImGui::End();
|
|
||||||
}
|
|
||||||
|
|
||||||
} // namespace dusk
|
|
||||||
@@ -40,7 +40,6 @@ namespace dusk {
|
|||||||
ImGui::BeginDisabled(getSettings().game.speedrunMode);
|
ImGui::BeginDisabled(getSettings().game.speedrunMode);
|
||||||
|
|
||||||
ImGui::MenuItem("Save Editor", hotkeys::SHOW_SAVE_EDITOR, &m_showSaveEditor);
|
ImGui::MenuItem("Save Editor", hotkeys::SHOW_SAVE_EDITOR, &m_showSaveEditor);
|
||||||
ImGui::MenuItem("Map Loader", hotkeys::SHOW_MAP_LOADER, &m_showMapLoader);
|
|
||||||
ImGui::MenuItem("State Share", hotkeys::SHOW_STATE_SHARE, &m_showStateShare);
|
ImGui::MenuItem("State Share", hotkeys::SHOW_STATE_SHARE, &m_showStateShare);
|
||||||
|
|
||||||
ImGui::EndDisabled();
|
ImGui::EndDisabled();
|
||||||
|
|||||||
@@ -21,7 +21,6 @@ namespace dusk {
|
|||||||
void ShowProcessManager();
|
void ShowProcessManager();
|
||||||
void ShowHeapOverlay();
|
void ShowHeapOverlay();
|
||||||
void ShowStubLog();
|
void ShowStubLog();
|
||||||
void ShowMapLoader();
|
|
||||||
void ShowBloomWindow();
|
void ShowBloomWindow();
|
||||||
void ShowPlayerInfo();
|
void ShowPlayerInfo();
|
||||||
void ShowAudioDebug();
|
void ShowAudioDebug();
|
||||||
@@ -43,22 +42,9 @@ namespace dusk {
|
|||||||
|
|
||||||
bool m_showStubLog = false;
|
bool m_showStubLog = false;
|
||||||
|
|
||||||
bool m_showMapLoader = false;
|
|
||||||
|
|
||||||
bool m_showBloomWindow = false;
|
bool m_showBloomWindow = false;
|
||||||
|
|
||||||
bool m_showAudioDebug = false;
|
bool m_showAudioDebug = false;
|
||||||
struct {
|
|
||||||
int mapIdx = -1;
|
|
||||||
int regionIdx = -1;
|
|
||||||
int roomNoIdx = 0;
|
|
||||||
int pointNoIdx = 0;
|
|
||||||
int roomNo = -1;
|
|
||||||
int pointNo = -1;
|
|
||||||
int spawnId = 0;
|
|
||||||
int layer = -1;
|
|
||||||
bool showInternalNames = false;
|
|
||||||
} m_mapLoaderInfo;
|
|
||||||
|
|
||||||
bool m_showPlayerInfo = false;
|
bool m_showPlayerInfo = false;
|
||||||
int m_playerInfoOverlayCorner = 1; // top-right
|
int m_playerInfoOverlayCorner = 1; // top-right
|
||||||
|
|||||||
@@ -13,7 +13,7 @@ UserSettings g_userSettings = {
|
|||||||
},
|
},
|
||||||
|
|
||||||
.audio = {
|
.audio = {
|
||||||
.masterVolume {"audio.masterVolume", 80},
|
.masterVolume {"audio.masterVolume", 60},
|
||||||
.mainMusicVolume {"audio.mainMusicVolume", 100},
|
.mainMusicVolume {"audio.mainMusicVolume", 100},
|
||||||
.subMusicVolume {"audio.subMusicVolume", 100},
|
.subMusicVolume {"audio.subMusicVolume", 100},
|
||||||
.soundEffectsVolume {"audio.soundEffectsVolume", 100},
|
.soundEffectsVolume {"audio.soundEffectsVolume", 100},
|
||||||
@@ -93,6 +93,7 @@ UserSettings g_userSettings = {
|
|||||||
// Cheats
|
// Cheats
|
||||||
.infiniteHearts {"game.infiniteHearts", false},
|
.infiniteHearts {"game.infiniteHearts", false},
|
||||||
.infiniteArrows {"game.infiniteArrows", false},
|
.infiniteArrows {"game.infiniteArrows", false},
|
||||||
|
.infiniteSeeds {"game.infiniteSeeds", false},
|
||||||
.infiniteBombs {"game.infiniteBombs", false},
|
.infiniteBombs {"game.infiniteBombs", false},
|
||||||
.infiniteOil {"game.infiniteOil", false},
|
.infiniteOil {"game.infiniteOil", false},
|
||||||
.infiniteOxygen {"game.infiniteOxygen", false},
|
.infiniteOxygen {"game.infiniteOxygen", false},
|
||||||
@@ -106,6 +107,7 @@ UserSettings g_userSettings = {
|
|||||||
.fastRoll {"game.fastRoll", false},
|
.fastRoll {"game.fastRoll", false},
|
||||||
.fastSpinner {"game.fastSpinner", false},
|
.fastSpinner {"game.fastSpinner", false},
|
||||||
.freeMagicArmor {"game.freeMagicArmor", false},
|
.freeMagicArmor {"game.freeMagicArmor", false},
|
||||||
|
.invincibleEnemies {"game.invincibleEnemies", false},
|
||||||
|
|
||||||
// Technical
|
// Technical
|
||||||
.restoreWiiGlitches {"game.restoreWiiGlitches", false},
|
.restoreWiiGlitches {"game.restoreWiiGlitches", false},
|
||||||
@@ -243,6 +245,7 @@ void registerSettings() {
|
|||||||
Register(g_userSettings.game.fastSpinner);
|
Register(g_userSettings.game.fastSpinner);
|
||||||
Register(g_userSettings.game.infiniteHearts);
|
Register(g_userSettings.game.infiniteHearts);
|
||||||
Register(g_userSettings.game.infiniteArrows);
|
Register(g_userSettings.game.infiniteArrows);
|
||||||
|
Register(g_userSettings.game.infiniteSeeds);
|
||||||
Register(g_userSettings.game.infiniteBombs);
|
Register(g_userSettings.game.infiniteBombs);
|
||||||
Register(g_userSettings.game.infiniteOil);
|
Register(g_userSettings.game.infiniteOil);
|
||||||
Register(g_userSettings.game.infiniteOxygen);
|
Register(g_userSettings.game.infiniteOxygen);
|
||||||
@@ -251,6 +254,7 @@ void registerSettings() {
|
|||||||
Register(g_userSettings.game.moonJump);
|
Register(g_userSettings.game.moonJump);
|
||||||
Register(g_userSettings.game.superClawshot);
|
Register(g_userSettings.game.superClawshot);
|
||||||
Register(g_userSettings.game.alwaysGreatspin);
|
Register(g_userSettings.game.alwaysGreatspin);
|
||||||
|
Register(g_userSettings.game.invincibleEnemies);
|
||||||
Register(g_userSettings.game.enableFrameInterpolation);
|
Register(g_userSettings.game.enableFrameInterpolation);
|
||||||
Register(g_userSettings.game.gyroMode);
|
Register(g_userSettings.game.gyroMode);
|
||||||
Register(g_userSettings.game.enableGyroAim);
|
Register(g_userSettings.game.enableGyroAim);
|
||||||
|
|||||||
@@ -20,6 +20,7 @@ void resetForSpeedrunMode() {
|
|||||||
|
|
||||||
getSettings().game.infiniteHearts.setSpeedrunValue(false);
|
getSettings().game.infiniteHearts.setSpeedrunValue(false);
|
||||||
getSettings().game.infiniteArrows.setSpeedrunValue(false);
|
getSettings().game.infiniteArrows.setSpeedrunValue(false);
|
||||||
|
getSettings().game.infiniteSeeds.setSpeedrunValue(false);
|
||||||
getSettings().game.infiniteBombs.setSpeedrunValue(false);
|
getSettings().game.infiniteBombs.setSpeedrunValue(false);
|
||||||
getSettings().game.infiniteOil.setSpeedrunValue(false);
|
getSettings().game.infiniteOil.setSpeedrunValue(false);
|
||||||
getSettings().game.infiniteOxygen.setSpeedrunValue(false);
|
getSettings().game.infiniteOxygen.setSpeedrunValue(false);
|
||||||
|
|||||||
+37
-38
@@ -26,6 +26,43 @@
|
|||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
||||||
namespace dusk::ui {
|
namespace dusk::ui {
|
||||||
|
|
||||||
|
Rml::String stage_option_label(const MapEntry& map, bool showInternalNames) {
|
||||||
|
return showInternalNames ? fmt::format("{} ({})", map.mapName, map.mapFile) : map.mapName;
|
||||||
|
}
|
||||||
|
|
||||||
|
Rml::String stage_label_for_file(const Rml::String& stageFile, bool showInternalNames) {
|
||||||
|
for (const auto& region : gameRegions) {
|
||||||
|
for (const auto& map : region.maps) {
|
||||||
|
if (stageFile == map.mapFile) {
|
||||||
|
return stage_option_label(map, showInternalNames);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return stageFile;
|
||||||
|
}
|
||||||
|
|
||||||
|
void populate_stage_picker(Pane& pane, std::function<Rml::String()> getStageFile,
|
||||||
|
std::function<void(const char*)> setStageFile, bool showInternalNames) {
|
||||||
|
pane.clear();
|
||||||
|
for (const auto& region : gameRegions) {
|
||||||
|
pane.add_section(region.regionName);
|
||||||
|
for (const auto& map : region.maps) {
|
||||||
|
pane.add_button({
|
||||||
|
.text = stage_option_label(map, showInternalNames),
|
||||||
|
.isSelected =
|
||||||
|
[getStageFile, stageFile = map.mapFile] {
|
||||||
|
return getStageFile() == stageFile;
|
||||||
|
},
|
||||||
|
})
|
||||||
|
.on_pressed([setStageFile, stageFile = map.mapFile] {
|
||||||
|
mDoAud_seStartMenu(kSoundItemChange);
|
||||||
|
setStageFile(stageFile);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
namespace {
|
namespace {
|
||||||
|
|
||||||
bool has_save_data() {
|
bool has_save_data() {
|
||||||
@@ -155,44 +192,6 @@ bool parse_vec3(const Rml::String& value, float& x, float& y, float& z) {
|
|||||||
return *cursor == '\0';
|
return *cursor == '\0';
|
||||||
}
|
}
|
||||||
|
|
||||||
Rml::String stage_option_label(const MapEntry& map) {
|
|
||||||
// TODO: option to show internal name?
|
|
||||||
// return fmt::format("{} ({})", map.mapName, map.mapFile);
|
|
||||||
return map.mapName;
|
|
||||||
}
|
|
||||||
|
|
||||||
Rml::String stage_label_for_file(const Rml::String& stageFile) {
|
|
||||||
for (const auto& region : gameRegions) {
|
|
||||||
for (const auto& map : region.maps) {
|
|
||||||
if (stageFile == map.mapFile) {
|
|
||||||
return stage_option_label(map);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return stageFile;
|
|
||||||
}
|
|
||||||
|
|
||||||
void populate_stage_picker(Pane& pane, std::function<Rml::String()> getStageFile,
|
|
||||||
std::function<void(const char*)> setStageFile) {
|
|
||||||
pane.clear();
|
|
||||||
for (const auto& region : gameRegions) {
|
|
||||||
pane.add_section(region.regionName);
|
|
||||||
for (const auto& map : region.maps) {
|
|
||||||
pane.add_button({
|
|
||||||
.text = stage_option_label(map),
|
|
||||||
.isSelected =
|
|
||||||
[getStageFile, stageFile = map.mapFile] {
|
|
||||||
return getStageFile() == stageFile;
|
|
||||||
},
|
|
||||||
})
|
|
||||||
.on_pressed([setStageFile, stageFile = map.mapFile] {
|
|
||||||
mDoAud_seStartMenu(kSoundItemChange);
|
|
||||||
setStageFile(stageFile);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Rml::String get_player_name() {
|
Rml::String get_player_name() {
|
||||||
if (!has_save_data()) {
|
if (!has_save_data()) {
|
||||||
return "";
|
return "";
|
||||||
|
|||||||
@@ -1,8 +1,19 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include "window.hpp"
|
#include "window.hpp"
|
||||||
|
|
||||||
|
struct MapEntry;
|
||||||
|
|
||||||
namespace dusk::ui {
|
namespace dusk::ui {
|
||||||
|
|
||||||
|
class Pane;
|
||||||
|
|
||||||
|
Rml::String stage_option_label(const MapEntry& map, bool showInternalNames = false);
|
||||||
|
Rml::String stage_label_for_file(const Rml::String& stageFile, bool showInternalNames = false);
|
||||||
|
void populate_stage_picker(Pane& pane, std::function<Rml::String()> getStageFile,
|
||||||
|
std::function<void(const char*)> setStageFile,
|
||||||
|
bool showInternalNames = false);
|
||||||
|
|
||||||
class EditorWindow : public Window {
|
class EditorWindow : public Window {
|
||||||
public:
|
public:
|
||||||
EditorWindow();
|
EditorWindow();
|
||||||
|
|||||||
@@ -184,7 +184,7 @@ Rml::String format_graphics_setting_value(GraphicsOption option, int value) {
|
|||||||
case BloomMode::Classic:
|
case BloomMode::Classic:
|
||||||
return "Classic";
|
return "Classic";
|
||||||
case BloomMode::Dusk:
|
case BloomMode::Dusk:
|
||||||
return "Dusk";
|
return "Dusklight";
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case GraphicsOption::BloomMultiplier:
|
case GraphicsOption::BloomMultiplier:
|
||||||
|
|||||||
@@ -18,6 +18,7 @@
|
|||||||
#include "modal.hpp"
|
#include "modal.hpp"
|
||||||
#include "settings.hpp"
|
#include "settings.hpp"
|
||||||
#include "ui.hpp"
|
#include "ui.hpp"
|
||||||
|
#include "warp.hpp"
|
||||||
#include "window.hpp"
|
#include "window.hpp"
|
||||||
|
|
||||||
#include <chrono>
|
#include <chrono>
|
||||||
@@ -51,11 +52,9 @@ MenuBar::MenuBar() : Document(kDocumentSource), mRoot(mDocument->GetElementById(
|
|||||||
.autoSelect = false,
|
.autoSelect = false,
|
||||||
});
|
});
|
||||||
mTabBar->add_tab("Settings", [this] { push(std::make_unique<SettingsWindow>()); });
|
mTabBar->add_tab("Settings", [this] { push(std::make_unique<SettingsWindow>()); });
|
||||||
// mTabBar->add_tab("Warp", [] {
|
|
||||||
// // TODO
|
|
||||||
// });
|
|
||||||
|
|
||||||
if (getSettings().backend.enableAdvancedSettings) {
|
if (getSettings().backend.enableAdvancedSettings) {
|
||||||
|
mTabBar->add_tab("Warp", [this] { push(std::make_unique<WarpWindow>()); });
|
||||||
mTabBar->add_tab("Editor", [this] { push(std::make_unique<EditorWindow>()); });
|
mTabBar->add_tab("Editor", [this] { push(std::make_unique<EditorWindow>()); });
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -354,8 +354,9 @@ void Overlay::update() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
u32 count = 0;
|
||||||
const bool showControllerWarning = PADGetIndexForPort(PAD_CHAN0) < 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<Window*>(top_document()) == nullptr &&
|
||||||
dynamic_cast<WindowSmall*>(top_document()) == nullptr;
|
dynamic_cast<WindowSmall*>(top_document()) == nullptr;
|
||||||
if (showControllerWarning && mControllerWarning == nullptr) {
|
if (showControllerWarning && mControllerWarning == nullptr) {
|
||||||
|
|||||||
@@ -83,7 +83,7 @@ PresetWindow::PresetWindow() : WindowSmall("modal", "modal-dialog") {
|
|||||||
"Enhancements disabled to match the GameCube version. "
|
"Enhancements disabled to match the GameCube version. "
|
||||||
"Good for speedrunning or simple nostalgia!",
|
"Good for speedrunning or simple nostalgia!",
|
||||||
applyPresetClassic},
|
applyPresetClassic},
|
||||||
{"Dusk",
|
{"Dusklight",
|
||||||
"Graphics & quality of life tweaks, including some from the Wii U version. "
|
"Graphics & quality of life tweaks, including some from the Wii U version. "
|
||||||
"Our recommended way to play!",
|
"Our recommended way to play!",
|
||||||
applyPresetDusk},
|
applyPresetDusk},
|
||||||
|
|||||||
@@ -3,6 +3,7 @@
|
|||||||
#include "aurora/gfx.h"
|
#include "aurora/gfx.h"
|
||||||
#include "bool_button.hpp"
|
#include "bool_button.hpp"
|
||||||
#include "controller_config.hpp"
|
#include "controller_config.hpp"
|
||||||
|
#include "dusk/app_info.hpp"
|
||||||
#include "dusk/audio/DuskAudioSystem.h"
|
#include "dusk/audio/DuskAudioSystem.h"
|
||||||
#include "dusk/audio/DuskDsp.hpp"
|
#include "dusk/audio/DuskDsp.hpp"
|
||||||
#include "dusk/config.hpp"
|
#include "dusk/config.hpp"
|
||||||
@@ -17,6 +18,7 @@
|
|||||||
#include "graphics_tuner.hpp"
|
#include "graphics_tuner.hpp"
|
||||||
#include "m_Do/m_Do_main.h"
|
#include "m_Do/m_Do_main.h"
|
||||||
#include "menu_bar.hpp"
|
#include "menu_bar.hpp"
|
||||||
|
#include "modal.hpp"
|
||||||
#include "number_button.hpp"
|
#include "number_button.hpp"
|
||||||
#include "menu_bar.hpp"
|
#include "menu_bar.hpp"
|
||||||
#include "pane.hpp"
|
#include "pane.hpp"
|
||||||
@@ -25,6 +27,7 @@
|
|||||||
|
|
||||||
#include <aurora/lib/window.hpp>
|
#include <aurora/lib/window.hpp>
|
||||||
#include <SDL3/SDL_filesystem.h>
|
#include <SDL3/SDL_filesystem.h>
|
||||||
|
#include <fmt/format.h>
|
||||||
|
|
||||||
#if DUSK_ENABLE_SENTRY_NATIVE
|
#if DUSK_ENABLE_SENTRY_NATIVE
|
||||||
#include "dusk/crash_reporting.h"
|
#include "dusk/crash_reporting.h"
|
||||||
@@ -184,6 +187,7 @@ void reset_for_speedrun_mode() {
|
|||||||
|
|
||||||
getSettings().game.infiniteHearts.setSpeedrunValue(false);
|
getSettings().game.infiniteHearts.setSpeedrunValue(false);
|
||||||
getSettings().game.infiniteArrows.setSpeedrunValue(false);
|
getSettings().game.infiniteArrows.setSpeedrunValue(false);
|
||||||
|
getSettings().game.infiniteSeeds.setSpeedrunValue(false);
|
||||||
getSettings().game.infiniteBombs.setSpeedrunValue(false);
|
getSettings().game.infiniteBombs.setSpeedrunValue(false);
|
||||||
getSettings().game.infiniteOil.setSpeedrunValue(false);
|
getSettings().game.infiniteOil.setSpeedrunValue(false);
|
||||||
getSettings().game.infiniteOxygen.setSpeedrunValue(false);
|
getSettings().game.infiniteOxygen.setSpeedrunValue(false);
|
||||||
@@ -197,6 +201,7 @@ void reset_for_speedrun_mode() {
|
|||||||
getSettings().game.fastRoll.setSpeedrunValue(false);
|
getSettings().game.fastRoll.setSpeedrunValue(false);
|
||||||
getSettings().game.fastSpinner.setSpeedrunValue(false);
|
getSettings().game.fastSpinner.setSpeedrunValue(false);
|
||||||
getSettings().game.freeMagicArmor.setSpeedrunValue(false);
|
getSettings().game.freeMagicArmor.setSpeedrunValue(false);
|
||||||
|
getSettings().game.invincibleEnemies.setSpeedrunValue(false);
|
||||||
|
|
||||||
getSettings().game.pauseOnFocusLost.setSpeedrunValue(false);
|
getSettings().game.pauseOnFocusLost.setSpeedrunValue(false);
|
||||||
aurora_set_pause_on_focus_lost(false);
|
aurora_set_pause_on_focus_lost(false);
|
||||||
@@ -295,13 +300,49 @@ private:
|
|||||||
Rml::String mCurrentRml;
|
Rml::String mCurrentRml;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
void show_data_folder_error_modal(std::string_view message) {
|
||||||
|
auto dismiss = [](Modal& modal) {
|
||||||
|
mDoAud_seStartMenu(kSoundWindowClose);
|
||||||
|
modal.pop();
|
||||||
|
};
|
||||||
|
push_document(std::make_unique<Modal>(Modal::Props{
|
||||||
|
.title = "Data Folder Not Changed",
|
||||||
|
.bodyRml = escape(message),
|
||||||
|
.actions =
|
||||||
|
{
|
||||||
|
ModalAction{
|
||||||
|
.label = "OK",
|
||||||
|
.onPressed = dismiss,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
.onDismiss = dismiss,
|
||||||
|
.icon = "warning",
|
||||||
|
}));
|
||||||
|
if (auto* doc = top_document()) {
|
||||||
|
doc->focus();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void data_folder_dialog_callback(void*, const char* path, const char* error) {
|
void data_folder_dialog_callback(void*, const char* path, const char* error) {
|
||||||
if (error != nullptr || path == nullptr) {
|
if (error != nullptr) {
|
||||||
|
show_data_folder_error_modal(error);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (data::set_custom_data_path(path)) {
|
if (path == nullptr) {
|
||||||
mDoAud_seStartMenu(kSoundItemChange);
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
std::string dataPathError;
|
||||||
|
if (data::set_custom_data_path(path, &dataPathError)) {
|
||||||
|
mDoAud_seStartMenu(kSoundItemChange);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (dataPathError.empty()) {
|
||||||
|
dataPathError =
|
||||||
|
fmt::format("{} could not use the selected folder as its data folder.", AppName);
|
||||||
|
}
|
||||||
|
show_data_folder_error_modal(dataPathError);
|
||||||
}
|
}
|
||||||
|
|
||||||
const Rml::String kInternalResolutionHelpText =
|
const Rml::String kInternalResolutionHelpText =
|
||||||
@@ -912,7 +953,7 @@ SettingsWindow::SettingsWindow(bool prelaunch) : mPrelaunch(prelaunch) {
|
|||||||
[](int value) {
|
[](int value) {
|
||||||
getSettings().audio.masterVolume.setValue(value);
|
getSettings().audio.masterVolume.setValue(value);
|
||||||
config::Save();
|
config::Save();
|
||||||
audio::SetMasterVolume(value / 100.f);
|
audio::SetMasterVolume(audio::MasterVolumeToLinear(value / 100.0f));
|
||||||
},
|
},
|
||||||
.isModified =
|
.isModified =
|
||||||
[] {
|
[] {
|
||||||
@@ -1107,6 +1148,7 @@ SettingsWindow::SettingsWindow(bool prelaunch) : mPrelaunch(prelaunch) {
|
|||||||
addCheat("Infinite Hearts", getSettings().game.infiniteHearts, "Keeps your health full.");
|
addCheat("Infinite Hearts", getSettings().game.infiniteHearts, "Keeps your health full.");
|
||||||
addCheat(
|
addCheat(
|
||||||
"Infinite Arrows", getSettings().game.infiniteArrows, "Keeps your arrow count full.");
|
"Infinite Arrows", getSettings().game.infiniteArrows, "Keeps your arrow count full.");
|
||||||
|
addCheat("Infinite Seeds", getSettings().game.infiniteSeeds, "Keeps your slingshot pellets (seeds) full.");
|
||||||
addCheat("Infinite Bombs", getSettings().game.infiniteBombs, "Keeps all bomb bags full.");
|
addCheat("Infinite Bombs", getSettings().game.infiniteBombs, "Keeps all bomb bags full.");
|
||||||
addCheat("Infinite Oil", getSettings().game.infiniteOil, "Keeps your lantern oil full.");
|
addCheat("Infinite Oil", getSettings().game.infiniteOil, "Keeps your lantern oil full.");
|
||||||
addCheat("Infinite Oxygen", getSettings().game.infiniteOxygen,
|
addCheat("Infinite Oxygen", getSettings().game.infiniteOxygen,
|
||||||
@@ -1133,6 +1175,8 @@ SettingsWindow::SettingsWindow(bool prelaunch) : mPrelaunch(prelaunch) {
|
|||||||
"Speeds up Spinner movement while holding R.");
|
"Speeds up Spinner movement while holding R.");
|
||||||
addCheat("Free Magic Armor", getSettings().game.freeMagicArmor,
|
addCheat("Free Magic Armor", getSettings().game.freeMagicArmor,
|
||||||
"Lets the magic armor work without consuming rupees.");
|
"Lets the magic armor work without consuming rupees.");
|
||||||
|
addCheat("Invincible Enemies", getSettings().game.invincibleEnemies,
|
||||||
|
"Prevents enemies from taking damage.");
|
||||||
});
|
});
|
||||||
|
|
||||||
add_tab("Interface", [this](Rml::Element* content) {
|
add_tab("Interface", [this](Rml::Element* content) {
|
||||||
|
|||||||
@@ -0,0 +1,334 @@
|
|||||||
|
#include "warp.hpp"
|
||||||
|
|
||||||
|
#include "editor.hpp"
|
||||||
|
#include "pane.hpp"
|
||||||
|
|
||||||
|
#include "dusk/map_loader_definitions.h"
|
||||||
|
#include "fmt/format.h"
|
||||||
|
|
||||||
|
namespace dusk::ui {
|
||||||
|
namespace {
|
||||||
|
|
||||||
|
constexpr int kMinLayer = -1;
|
||||||
|
constexpr int kMaxLayer = 14;
|
||||||
|
|
||||||
|
struct WarpSelectionState {
|
||||||
|
int regionIdx = 0;
|
||||||
|
int mapIdx = 0;
|
||||||
|
int roomIdx = 0;
|
||||||
|
int pointIdx = 0;
|
||||||
|
int layer = -1;
|
||||||
|
bool showInternalNames = false;
|
||||||
|
};
|
||||||
|
|
||||||
|
WarpSelectionState& selection_state() {
|
||||||
|
static WarpSelectionState state;
|
||||||
|
return state;
|
||||||
|
}
|
||||||
|
|
||||||
|
const RegionEntry* selected_region(const WarpSelectionState& state) {
|
||||||
|
if (state.regionIdx < 0 || state.regionIdx >= static_cast<int>(gameRegions.size())) {
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
return &gameRegions[state.regionIdx];
|
||||||
|
}
|
||||||
|
|
||||||
|
const MapEntry* selected_map(const WarpSelectionState& state) {
|
||||||
|
const auto* region = selected_region(state);
|
||||||
|
if (region == nullptr || state.mapIdx < 0 || state.mapIdx >= static_cast<int>(region->maps.size())) {
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
return ®ion->maps[state.mapIdx];
|
||||||
|
}
|
||||||
|
|
||||||
|
const RoomEntry* selected_room(const WarpSelectionState& state) {
|
||||||
|
const auto* map = selected_map(state);
|
||||||
|
if (map == nullptr || state.roomIdx < 0 || state.roomIdx >= static_cast<int>(map->mapRooms.size())) {
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
return &map->mapRooms[state.roomIdx];
|
||||||
|
}
|
||||||
|
|
||||||
|
const s16* selected_point(const WarpSelectionState& state) {
|
||||||
|
const auto* room = selected_room(state);
|
||||||
|
if (room == nullptr || state.pointIdx < 0 ||
|
||||||
|
state.pointIdx >= static_cast<int>(room->roomPoints.size()))
|
||||||
|
{
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
return &room->roomPoints[state.pointIdx];
|
||||||
|
}
|
||||||
|
|
||||||
|
void clamp_indices(WarpSelectionState& state) {
|
||||||
|
if (gameRegions.empty()) {
|
||||||
|
state.regionIdx = -1;
|
||||||
|
state.mapIdx = -1;
|
||||||
|
state.roomIdx = -1;
|
||||||
|
state.pointIdx = -1;
|
||||||
|
state.layer = std::clamp(state.layer, kMinLayer, kMaxLayer);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
state.regionIdx = std::clamp(state.regionIdx, 0, static_cast<int>(gameRegions.size()) - 1);
|
||||||
|
const auto& region = gameRegions[state.regionIdx];
|
||||||
|
if (region.maps.empty()) {
|
||||||
|
state.mapIdx = -1;
|
||||||
|
state.roomIdx = -1;
|
||||||
|
state.pointIdx = -1;
|
||||||
|
state.layer = std::clamp(state.layer, kMinLayer, kMaxLayer);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
state.mapIdx = std::clamp(state.mapIdx, 0, static_cast<int>(region.maps.size()) - 1);
|
||||||
|
const auto& map = region.maps[state.mapIdx];
|
||||||
|
if (map.mapRooms.empty()) {
|
||||||
|
state.roomIdx = -1;
|
||||||
|
state.pointIdx = -1;
|
||||||
|
state.layer = std::clamp(state.layer, kMinLayer, kMaxLayer);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
state.roomIdx = std::clamp(state.roomIdx, 0, static_cast<int>(map.mapRooms.size()) - 1);
|
||||||
|
const auto& room = map.mapRooms[state.roomIdx];
|
||||||
|
if (room.roomPoints.empty()) {
|
||||||
|
state.pointIdx = -1;
|
||||||
|
} else {
|
||||||
|
state.pointIdx = std::clamp(state.pointIdx, 0, static_cast<int>(room.roomPoints.size()) - 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
state.layer = std::clamp(state.layer, kMinLayer, kMaxLayer);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool can_warp(const WarpSelectionState& state) {
|
||||||
|
return selected_point(state) != nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
void reset_selection(WarpSelectionState& state) {
|
||||||
|
state.roomIdx = 0;
|
||||||
|
state.pointIdx = 0;
|
||||||
|
state.layer = kMinLayer;
|
||||||
|
clamp_indices(state);
|
||||||
|
}
|
||||||
|
|
||||||
|
void populate_map_picker(Pane& pane, WarpSelectionState& state) {
|
||||||
|
pane.clear();
|
||||||
|
clamp_indices(state);
|
||||||
|
if (state.regionIdx < 0 || state.regionIdx >= static_cast<int>(gameRegions.size())) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
pane.add_button({
|
||||||
|
.text = "Show Internal Names",
|
||||||
|
.isSelected = [&state] { return state.showInternalNames; },
|
||||||
|
})
|
||||||
|
.on_pressed([&pane, &state] {
|
||||||
|
mDoAud_seStartMenu(kSoundItemChange);
|
||||||
|
state.showInternalNames = !state.showInternalNames;
|
||||||
|
populate_map_picker(pane, state);
|
||||||
|
});
|
||||||
|
|
||||||
|
pane.add_section("Maps");
|
||||||
|
const auto& region = gameRegions[state.regionIdx];
|
||||||
|
for (int i = 0; i < static_cast<int>(region.maps.size()); ++i) {
|
||||||
|
pane.add_button({
|
||||||
|
.text = stage_option_label(region.maps[i], state.showInternalNames),
|
||||||
|
.isSelected = [i, &state] { return state.mapIdx == i; },
|
||||||
|
})
|
||||||
|
.on_pressed([i, &state] {
|
||||||
|
mDoAud_seStartMenu(kSoundItemChange);
|
||||||
|
if (state.mapIdx != i) {
|
||||||
|
state.mapIdx = i;
|
||||||
|
reset_selection(state);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace
|
||||||
|
|
||||||
|
WarpWindow::WarpWindow() {
|
||||||
|
add_tab("Warp", [this](Rml::Element* content) {
|
||||||
|
auto& leftPane = add_child<Pane>(content, Pane::Type::Controlled);
|
||||||
|
auto& rightPane = add_child<Pane>(content, Pane::Type::Uncontrolled);
|
||||||
|
auto& state = selection_state();
|
||||||
|
clamp_indices(state);
|
||||||
|
|
||||||
|
leftPane.add_section("Destination");
|
||||||
|
leftPane.register_control(
|
||||||
|
leftPane.add_select_button({
|
||||||
|
.key = "Region",
|
||||||
|
.getValue =
|
||||||
|
[&state] {
|
||||||
|
clamp_indices(state);
|
||||||
|
const auto* region = selected_region(state);
|
||||||
|
return region == nullptr ? Rml::String{"None"} :
|
||||||
|
Rml::String{region->regionName};
|
||||||
|
},
|
||||||
|
}),
|
||||||
|
rightPane, [&state](Pane& pane) {
|
||||||
|
pane.clear();
|
||||||
|
for (int i = 0; i < static_cast<int>(gameRegions.size()); ++i) {
|
||||||
|
pane.add_button({
|
||||||
|
.text = gameRegions[i].regionName,
|
||||||
|
.isSelected = [i, &state] { return state.regionIdx == i; },
|
||||||
|
})
|
||||||
|
.on_pressed([i, &state] {
|
||||||
|
mDoAud_seStartMenu(kSoundItemChange);
|
||||||
|
if (state.regionIdx != i) {
|
||||||
|
state.regionIdx = i;
|
||||||
|
state.mapIdx = 0;
|
||||||
|
reset_selection(state);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
leftPane.register_control(
|
||||||
|
leftPane.add_select_button({
|
||||||
|
.key = "Map",
|
||||||
|
.getValue =
|
||||||
|
[&state] {
|
||||||
|
clamp_indices(state);
|
||||||
|
const auto* map = selected_map(state);
|
||||||
|
return map == nullptr ? Rml::String{"None"} :
|
||||||
|
stage_option_label(*map, state.showInternalNames);
|
||||||
|
},
|
||||||
|
}),
|
||||||
|
rightPane, [&state](Pane& pane) { populate_map_picker(pane, state); });
|
||||||
|
|
||||||
|
leftPane.register_control(
|
||||||
|
leftPane.add_select_button({
|
||||||
|
.key = "Room",
|
||||||
|
.getValue = [&state] {
|
||||||
|
clamp_indices(state);
|
||||||
|
const auto* room = selected_room(state);
|
||||||
|
return room == nullptr ? Rml::String{"None"} :
|
||||||
|
fmt::format("{}", room->roomNo);
|
||||||
|
},
|
||||||
|
.isDisabled = [&state] {
|
||||||
|
clamp_indices(state);
|
||||||
|
const auto* map = selected_map(state);
|
||||||
|
return map == nullptr || map->mapRooms.size() <= 1;
|
||||||
|
},
|
||||||
|
}),
|
||||||
|
rightPane, [&state](Pane& pane) {
|
||||||
|
pane.clear();
|
||||||
|
clamp_indices(state);
|
||||||
|
if (state.regionIdx < 0 || state.regionIdx >= static_cast<int>(gameRegions.size())) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
const auto& region = gameRegions[state.regionIdx];
|
||||||
|
if (state.mapIdx < 0 || state.mapIdx >= static_cast<int>(region.maps.size())) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
const auto& map = region.maps[state.mapIdx];
|
||||||
|
for (int i = 0; i < static_cast<int>(map.mapRooms.size()); ++i) {
|
||||||
|
pane.add_button({
|
||||||
|
.text = fmt::format("{}", map.mapRooms[i].roomNo),
|
||||||
|
.isSelected = [i, &state] { return state.roomIdx == i; },
|
||||||
|
})
|
||||||
|
.on_pressed([i, &state] {
|
||||||
|
mDoAud_seStartMenu(kSoundItemChange);
|
||||||
|
if (state.roomIdx != i) {
|
||||||
|
state.roomIdx = i;
|
||||||
|
state.pointIdx = 0;
|
||||||
|
clamp_indices(state);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
leftPane.register_control(
|
||||||
|
leftPane.add_select_button({
|
||||||
|
.key = "Point",
|
||||||
|
.getValue = [&state] {
|
||||||
|
clamp_indices(state);
|
||||||
|
const auto* point = selected_point(state);
|
||||||
|
return point == nullptr ? Rml::String{"None"} : fmt::format("{}", *point);
|
||||||
|
},
|
||||||
|
.isDisabled = [&state] {
|
||||||
|
clamp_indices(state);
|
||||||
|
const auto* room = selected_room(state);
|
||||||
|
return room == nullptr || room->roomPoints.size() <= 1;
|
||||||
|
},
|
||||||
|
}),
|
||||||
|
rightPane, [&state](Pane& pane) {
|
||||||
|
pane.clear();
|
||||||
|
clamp_indices(state);
|
||||||
|
if (state.regionIdx < 0 || state.regionIdx >= static_cast<int>(gameRegions.size())) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
const auto& region = gameRegions[state.regionIdx];
|
||||||
|
if (state.mapIdx < 0 || state.mapIdx >= static_cast<int>(region.maps.size())) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
const auto& map = region.maps[state.mapIdx];
|
||||||
|
if (state.roomIdx < 0 || state.roomIdx >= static_cast<int>(map.mapRooms.size())) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
const auto& room = map.mapRooms[state.roomIdx];
|
||||||
|
for (int i = 0; i < static_cast<int>(room.roomPoints.size()); ++i) {
|
||||||
|
pane.add_button({
|
||||||
|
.text = fmt::format("{}", room.roomPoints[i]),
|
||||||
|
.isSelected = [i, &state] { return state.pointIdx == i; },
|
||||||
|
})
|
||||||
|
.on_pressed([i, &state] {
|
||||||
|
if (state.pointIdx != i) {
|
||||||
|
mDoAud_seStartMenu(kSoundItemChange);
|
||||||
|
state.pointIdx = i;
|
||||||
|
clamp_indices(state);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
leftPane.register_control(
|
||||||
|
leftPane.add_select_button({
|
||||||
|
.key = "Layer",
|
||||||
|
.getValue = [&state] { return fmt::format("{}", state.layer); },
|
||||||
|
}),
|
||||||
|
rightPane, [&state](Pane& pane) {
|
||||||
|
pane.clear();
|
||||||
|
for (int layer = kMinLayer; layer <= kMaxLayer; ++layer) {
|
||||||
|
pane.add_button({
|
||||||
|
.text = fmt::format("{}", layer),
|
||||||
|
.isSelected = [layer, &state] { return state.layer == layer; },
|
||||||
|
})
|
||||||
|
.on_pressed([layer, &state] {
|
||||||
|
if (state.layer != layer) {
|
||||||
|
mDoAud_seStartMenu(kSoundItemChange);
|
||||||
|
state.layer = layer;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
leftPane.add_section("Action");
|
||||||
|
leftPane.register_control(
|
||||||
|
leftPane.add_button({
|
||||||
|
.text = "Warp",
|
||||||
|
.isDisabled = [&state] {
|
||||||
|
clamp_indices(state);
|
||||||
|
return !can_warp(state);
|
||||||
|
},
|
||||||
|
})
|
||||||
|
.on_pressed([&state] {
|
||||||
|
clamp_indices(state);
|
||||||
|
if (!can_warp(state)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
mDoAud_seStartMenu(kSoundClick);
|
||||||
|
const auto& region = gameRegions[state.regionIdx];
|
||||||
|
const auto& map = region.maps[state.mapIdx];
|
||||||
|
const auto& room = map.mapRooms[state.roomIdx];
|
||||||
|
dComIfGp_setNextStage( map.mapFile, room.roomPoints[state.pointIdx], room.roomNo, state.layer);
|
||||||
|
}),
|
||||||
|
rightPane, [](Pane& pane) {
|
||||||
|
pane.clear();
|
||||||
|
pane.add_text("Warp to the selected destination.");
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace dusk::ui
|
||||||
@@ -0,0 +1,12 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "window.hpp"
|
||||||
|
|
||||||
|
namespace dusk::ui {
|
||||||
|
|
||||||
|
class WarpWindow : public Window {
|
||||||
|
public:
|
||||||
|
WarpWindow();
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace dusk::ui
|
||||||
@@ -792,6 +792,10 @@ static void duskExecute() {
|
|||||||
dComIfGs_setArrowNum(dComIfGs_getArrowMax());
|
dComIfGs_setArrowNum(dComIfGs_getArrowMax());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (dusk::getSettings().game.infiniteSeeds) {
|
||||||
|
dComIfGs_setPachinkoNum(dComIfGs_getPachinkoMax());
|
||||||
|
}
|
||||||
|
|
||||||
if (dusk::getSettings().game.infiniteBombs) {
|
if (dusk::getSettings().game.infiniteBombs) {
|
||||||
dComIfGs_setBombNum(0, 99);
|
dComIfGs_setBombNum(0, 99);
|
||||||
dComIfGs_setBombNum(1, 99);
|
dComIfGs_setBombNum(1, 99);
|
||||||
|
|||||||
+10
-1
@@ -136,8 +136,17 @@ base_process_class* fpcBs_Create(s16 i_profname, fpc_ProcID i_procID, void* i_ap
|
|||||||
u32 size;
|
u32 size;
|
||||||
|
|
||||||
pprofile = (process_profile_definition*)fpcPf_Get(i_profname);
|
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={}",
|
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;
|
size = pprofile->process_size + pprofile->unk_size;
|
||||||
|
|
||||||
pprocess = (base_process_class*)cMl::memalignB(-4, size);
|
pprocess = (base_process_class*)cMl::memalignB(-4, size);
|
||||||
|
|||||||
+14
-5
@@ -80,6 +80,7 @@
|
|||||||
#include "dusk/audio/DuskAudioSystem.h"
|
#include "dusk/audio/DuskAudioSystem.h"
|
||||||
#include "dusk/audio/DuskDsp.hpp"
|
#include "dusk/audio/DuskDsp.hpp"
|
||||||
#include "dusk/config.hpp"
|
#include "dusk/config.hpp"
|
||||||
|
#include "dusk/speedrun.h"
|
||||||
#include "dusk/settings.h"
|
#include "dusk/settings.h"
|
||||||
#include "dusk/io.hpp"
|
#include "dusk/io.hpp"
|
||||||
#include "dusk/version.hpp"
|
#include "dusk/version.hpp"
|
||||||
@@ -119,6 +120,7 @@ bool dusk::IsShuttingDown = false;
|
|||||||
bool dusk::IsGameLaunched = false;
|
bool dusk::IsGameLaunched = false;
|
||||||
bool dusk::RestartRequested = false;
|
bool dusk::RestartRequested = false;
|
||||||
std::filesystem::path dusk::ConfigPath;
|
std::filesystem::path dusk::ConfigPath;
|
||||||
|
std::filesystem::path dusk::CachePath;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
void dusk::RequestRestart() noexcept {
|
void dusk::RequestRestart() noexcept {
|
||||||
@@ -513,12 +515,17 @@ int game_main(int argc, char* argv[]) {
|
|||||||
|
|
||||||
const auto startupLogLevel =
|
const auto startupLogLevel =
|
||||||
static_cast<AuroraLogLevel>(parsed_arg_options["log-level"].as<uint8_t>());
|
static_cast<AuroraLogLevel>(parsed_arg_options["log-level"].as<uint8_t>());
|
||||||
dusk::ConfigPath = dusk::data::initialize_data();
|
const auto dataPaths = dusk::data::initialize_data();
|
||||||
dusk::InitializeFileLogging(dusk::ConfigPath, startupLogLevel);
|
dusk::ConfigPath = dataPaths.userPath;
|
||||||
|
dusk::CachePath = dataPaths.cachePath;
|
||||||
|
dusk::InitializeFileLogging(dusk::CachePath, startupLogLevel);
|
||||||
|
|
||||||
log_build_info();
|
log_build_info();
|
||||||
|
|
||||||
dusk::config::LoadFromUserPreferences();
|
dusk::config::LoadFromUserPreferences();
|
||||||
|
if (dusk::getSettings().game.speedrunMode) {
|
||||||
|
dusk::resetForSpeedrunMode();
|
||||||
|
}
|
||||||
ApplyCVarOverrides(parsed_arg_options["cvar"]);
|
ApplyCVarOverrides(parsed_arg_options["cvar"]);
|
||||||
dusk::crash_reporting::initialize();
|
dusk::crash_reporting::initialize();
|
||||||
// TODO: How to handle this?
|
// TODO: How to handle this?
|
||||||
@@ -536,10 +543,12 @@ int game_main(int argc, char* argv[]) {
|
|||||||
SDL_SetAppMetadata("Dusklight", DUSK_VERSION_STRING, "dev.twilitrealm.dusk");
|
SDL_SetAppMetadata("Dusklight", DUSK_VERSION_STRING, "dev.twilitrealm.dusk");
|
||||||
|
|
||||||
{
|
{
|
||||||
const auto configPathString = dusk::ConfigPath.u8string();
|
const auto userPathString = dusk::ConfigPath.u8string();
|
||||||
|
const auto cachePathString = dusk::CachePath.u8string();
|
||||||
AuroraConfig config{};
|
AuroraConfig config{};
|
||||||
config.appName = dusk::AppName;
|
config.appName = dusk::AppName;
|
||||||
config.configPath = reinterpret_cast<const char*>(configPathString.c_str());
|
config.userPath = reinterpret_cast<const char*>(userPathString.c_str());
|
||||||
|
config.cachePath = reinterpret_cast<const char*>(cachePathString.c_str());
|
||||||
config.vsync = dusk::getSettings().video.enableVsync;
|
config.vsync = dusk::getSettings().video.enableVsync;
|
||||||
config.startFullscreen = dusk::getSettings().video.enableFullscreen;
|
config.startFullscreen = dusk::getSettings().video.enableFullscreen;
|
||||||
config.windowPosX = -1;
|
config.windowPosX = -1;
|
||||||
@@ -576,7 +585,7 @@ int game_main(int argc, char* argv[]) {
|
|||||||
}
|
}
|
||||||
VISetFrameBufferScale(dusk::getSettings().game.internalResolutionScale.getValue());
|
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::SetEnableReverb(dusk::getSettings().audio.enableReverb);
|
||||||
dusk::audio::EnableHrtf = dusk::getSettings().audio.enableHrtf;
|
dusk::audio::EnableHrtf = dusk::getSettings().audio.enableHrtf;
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user