Compare commits

...

21 Commits

Author SHA1 Message Date
MelonSpeedruns 1c1a849095 Recording Mode & Enable Autosave in Dusk preset (#685)
* branch for recording without a HUD

* no more black bars thanks maddie

* Backslash hotkey

* mute music

* dont check for null twice

* renamed option to recording mode, and added it to the rmlui menu

* Move recording mode to Interface

* re-added & renamed minimal hud option

* Mute all BGM if recording mode is on

* Update Interface section

* Un-experimentalize Autosave & enable in Dusk preset

---------

Co-authored-by: MelonSpeedruns <melonspeedruns@stratobox.net>
Co-authored-by: Irastris <irastris15@gmail.com>
Co-authored-by: Luke Street <luke@street.dev>
2026-05-07 23:26:22 -06:00
Phillip Stephens 89d393e57a Add missing climits include 2026-05-07 22:24:31 -07:00
Phillip Stephens 2f27687d80 Fix OSReport strings corruption with non-trivial format (#709)
* Fix OSReport strings corruption with non-trivial format

* Limit format attempts to 3
2026-05-07 23:10:23 -06:00
SuperDude88 167a50c01d Deselect Sub-Menu On Focus Change (#710)
- Unselect any previous items when focusing a new one

This might be way over-inclusive so it should be scrutinized harshly (but fixes #672)
2026-05-07 23:09:25 -06:00
SuperDude88 313f03f5e5 Dim Carousel Arrows
- Dim carousel arrows if there are no further options in that direction (closes #708)

This sets the color property constantly, not sure if that is a concern for perf (would imagine not since it already sets the rml to mValueElem every frame also?)
2026-05-07 23:05:08 -06:00
Howard Luck 6cfdc3d8a3 add keyboard controls + roll support to fly cam (#705) 2026-05-07 23:04:29 -06:00
Luke Street 9c24a0bc4b Disable Development Mode & move Input Viewer
Resolves #712
2026-05-07 23:03:26 -06:00
TakaRikka b99ad920c4 Merge pull request #704 from TwilitRealm/ira/rmlui-confirmation
Add confirmations modals to Reset and Quit
2026-05-07 13:57:03 -07:00
TakaRikka 912b18eca1 Merge pull request #703 from TwilitRealm/ui/advanced-settings
Advanced Settings
2026-05-07 13:55:13 -07:00
TakaRikka 9e651a51db Merge pull request #700 from TwilitRealm/ira/rmlui-fps
Add FPS counter to RmlUi
2026-05-07 13:51:51 -07:00
TakaRikka c8b6e997a7 Merge pull request #702 from TwilitRealm/ira/rmlui-inputconfig
Add remaining controller config options to RmlUi
2026-05-07 13:45:35 -07:00
Irastris 928e187524 Add mobile layout for prelaunch 2026-05-07 15:57:52 -04:00
Irastris cf12d19860 Resolve RmlUi deprecation warning, add L1/R1 tabbing to MenuBar 2026-05-07 13:48:12 -04:00
Irastris e3a3ac56fb Add confirmations modals to Reset and Quit 2026-05-07 13:32:59 -04:00
MelonSpeedruns d15ed81cd5 Only show Editor if Advanced Settings is enabled 2026-05-07 12:39:37 -04:00
TakaRikka ff054f6f47 update aurora and enable MTX_USE_PS 2026-05-07 09:36:32 -07:00
MelonSpeedruns 667cf70fa0 Add Advanced Settings option & Disable debug hotkeys if it's off 2026-05-07 12:01:32 -04:00
Irastris 73eb401c93 Add remaining controller config options, remove ImGui config 2026-05-07 12:00:35 -04:00
Irastris b11f3add06 Don't immediately dismiss prelaunch if skip config is toggled
Prevents a situation where memcard is not init until restarting after the deferral change
2026-05-07 09:26:41 -04:00
Irastris 92f888a152 Remove blur and shadow from counter, consolidate options 2026-05-07 03:28:30 -04:00
Irastris 78ed5cc716 Add FPS counter 2026-05-07 03:13:08 -04:00
51 changed files with 903 additions and 707 deletions
+2 -1
View File
@@ -102,6 +102,7 @@ set(AURORA_ENABLE_DVD ON CACHE BOOL "Enable DVD API support" FORCE)
set(AURORA_ENABLE_CARD ON CACHE BOOL "Enable CARD API support" FORCE)
set(AURORA_ENABLE_RMLUI ON CACHE BOOL "Enable RmlUi UI support" FORCE)
add_subdirectory(extern/aurora EXCLUDE_FROM_ALL)
target_compile_definitions(aurora_mtx PRIVATE MTX_USE_PS=1)
add_subdirectory(libs/freeverb)
@@ -285,7 +286,7 @@ set(DUSK_COPYRIGHT "Copyright (C) Twilit Realm contributors")
source_group("dolzel" FILES ${DOLZEL_FILES} ${Z2AUDIOLIB_FILES} ${REL_FILES})
source_group("dusk" FILES ${DUSK_FILES})
set(GAME_COMPILE_DEFS TARGET_PC WIDESCREEN_SUPPORT=1 AVOID_UB=1 VERSION=0)
set(GAME_COMPILE_DEFS TARGET_PC WIDESCREEN_SUPPORT=1 AVOID_UB=1 VERSION=0 MTX_USE_PS=1)
set(GAME_INCLUDE_DIRS
include
+1 -1
+6 -1
View File
@@ -57,6 +57,8 @@ struct UserSettings {
ConfigVar<bool> enableFullscreen;
ConfigVar<bool> enableVsync;
ConfigVar<bool> lockAspectRatio;
ConfigVar<bool> enableFpsOverlay;
ConfigVar<int> fpsOverlayCorner;
} video;
struct {
@@ -97,7 +99,7 @@ struct UserSettings {
// Preferences
ConfigVar<bool> enableMirrorMode;
ConfigVar<bool> disableMainHUD;
ConfigVar<bool> minimalHUD;
ConfigVar<bool> pauseOnFocusLost;
ConfigVar<bool> enableLinkDollRotation;
ConfigVar<bool> enableAchievementNotifications;
@@ -132,6 +134,7 @@ struct UserSettings {
ConfigVar<bool> invertCameraYAxis;
ConfigVar<float> freeCameraSensitivity;
ConfigVar<bool> debugFlyCam;
ConfigVar<bool> debugFlyCamLockEvents;
// Cheats
ConfigVar<bool> infiniteHearts;
@@ -158,6 +161,7 @@ struct UserSettings {
// Tools
ConfigVar<bool> speedrunMode;
ConfigVar<bool> liveSplitEnabled;
ConfigVar<bool> recordingMode;
} game;
struct {
@@ -169,6 +173,7 @@ struct UserSettings {
ConfigVar<bool> wasPresetChosen;
ConfigVar<bool> enableCrashReporting;
ConfigVar<int> cardFileType;
ConfigVar<bool> enableAdvancedSettings;
} backend;
};
+41 -2
View File
@@ -20,18 +20,22 @@ body {
pointer-events: none;
}
fps,
toast {
position: absolute;
border: 1dp #92875B;
background-color: rgba(21, 22, 16, 80%);
}
toast {
top: 40dp;
right: 40dp;
display: flex;
flex-flow: column;
border-radius: 14dp;
overflow: hidden;
border: 1dp #92875B;
backdrop-filter: blur(5dp);
box-shadow: 0 0 15dp 3dp;
background-color: rgba(21, 22, 16, 80%);
filter: opacity(0);
transform: scale(0.9);
transform-origin: center;
@@ -186,6 +190,41 @@ icon.warning {
decorator: text("&#xe002;" center center);
}
fps {
display: none;
z-index: 99;
font-size: 18dp;
font-weight: bold;
padding: 9dp 12dp;
border-radius: 7dp;
pointer-events: none;
white-space: nowrap;
}
fps[open] {
display: block;
}
fps[corner=tl] {
top: 12dp;
left: 12dp;
}
fps[corner=tr] {
top: 12dp;
right: 12dp;
}
fps[corner=bl] {
bottom: 12dp;
left: 12dp;
}
fps[corner=br] {
bottom: 12dp;
right: 12dp;
}
logo {
position: absolute;
width: 100dp;
+81
View File
@@ -322,3 +322,84 @@ body.animate-in .intro-item {
.delay-5 {
transition: opacity transform 0.3s 0.6s cubic-in-out;
}
/* Mobile layout */
@media (max-height: 640dp) {
.gradient {
decorator: horizontal-gradient(#00000000 #000000FF);
}
body.mirrored .gradient {
decorator: horizontal-gradient(#000000FF #00000000);
}
menu {
left: 20dp;
right: 20dp;
width: auto;
min-width: 0;
max-width: none;
flex-direction: row;
align-items: center;
justify-content: space-between;
gap: 16dp;
}
body.mirrored menu {
left: 20dp;
right: 20dp;
flex-direction: row-reverse;
}
hero {
flex: 1 1 0;
min-width: 0;
max-width: 48%;
}
body.mirrored hero {
align-items: flex-end;
}
hero img {
width: 100%;
}
#menu-list {
flex: 1 1 0;
min-width: 0;
max-width: 52%;
align-items: flex-end;
}
#menu-list button {
width: 100%;
max-width: 100%;
text-align: right;
}
#menu-list button:hover,
#menu-list button:focus-visible {
decorator: horizontal-gradient(#FEE68500 #FEE685FF);
}
body.mirrored #menu-list {
align-items: flex-start;
}
body.mirrored #menu-list button {
text-align: left;
}
body.mirrored #menu-list button:hover,
body.mirrored #menu-list button:focus-visible {
decorator: horizontal-gradient(#FEE685FF #FEE68500);
}
.eyebrow,
disc-info,
version-info {
display: none;
}
}
+13 -4
View File
@@ -287,6 +287,10 @@ icon.celebration {
decorator: text("&#xea65;" center center);
}
icon.question-mark {
decorator: text("&#xeb8b;" center center);
}
.achievement-row {
display: flex;
align-items: flex-start;
@@ -343,7 +347,7 @@ icon.celebration {
color: rgba(224, 219, 200, 45%);
}
progressbar {
progress {
display: block;
width: 100%;
height: 6dp;
@@ -352,12 +356,12 @@ progressbar {
margin: 6dp 0 2dp 0;
}
progressbar.progress-done fill {
progress.progress-done fill {
background-color: #44aa22;
border-radius: 3dp;
}
progressbar.progress-ongoing fill {
progress.progress-ongoing fill {
background-color: #2255bb;
border-radius: 3dp;
}
@@ -447,6 +451,11 @@ window.modal.danger .modal-header icon {
font-weight: normal;
}
.modal-body span.tip {
font-size: 14dp;
color: #92875B;
}
.verification-progress {
display: flex;
flex-direction: column;
@@ -460,7 +469,7 @@ window.modal.danger .modal-header icon {
color: #FFFFFF;
}
progressbar.verification-progress-bar {
progress.verification-progress-bar {
height: 8dp;
margin: 2dp 0 0 0;
}
+9
View File
@@ -12,6 +12,10 @@
#include "SSystem/SComponent/c_counter.h"
#include <cstring>
#if TARGET_PC
#include "dusk/settings.h"
#endif
#define DRAW_TYPE_YELLOW 0
#define DRAW_TYPE_RED 1
@@ -1422,6 +1426,11 @@ int dAttention_c::Run() {
}
void dAttention_c::Draw() {
#if TARGET_PC
if (dusk::getSettings().game.recordingMode) {
return;
}
#endif
if (mAttParam.CheckFlag(dAttParam_c::EFlag_ARROW_OFF)) {
draw[0].field_0x173 = 3;
draw[1].field_0x173 = 3;
+63 -11
View File
@@ -31,6 +31,7 @@
#if TARGET_PC
#include "dusk/frame_interpolation.h"
#include "dusk/logging.h"
#include "imgui.h"
#endif
namespace {
@@ -7483,6 +7484,8 @@ static constexpr f32 FLYCAM_SPEED = 0.5f;
static constexpr f32 FLYCAM_FAST_SPEED = 4.0f;
static constexpr f32 FLYCAM_ROTATION_SPEED = 0.002f;
static constexpr f32 FLYCAM_TRIGGER_DEADZONE = 20.0f;
static constexpr s16 FLYCAM_ROLL_SPEED = 256;
static ImVec2 sFlyCamLastMousePos = {-1.f, -1.f};
#if TARGET_PC
bool dCamera_c::executeDebugFlyCam() {
@@ -7490,6 +7493,7 @@ bool dCamera_c::executeDebugFlyCam() {
if (mDebugFlyCam.initialized) {
deactivateDebugFlyCam();
}
sFlyCamLastMousePos = {-1.f, -1.f};
return false;
}
@@ -7519,16 +7523,63 @@ bool dCamera_c::executeDebugFlyCam() {
mDebugFlyCam.initialized = true;
}
event->mEventStatus = 1;
dComIfGp_getEventManager().setCameraPlay(1);
if (dusk::getSettings().game.debugFlyCamLockEvents) {
event->mEventStatus = 1;
dComIfGp_getEventManager().setCameraPlay(1);
} else {
if (event->mEventStatus != 0) {
event->mEventStatus = 0;
}
dComIfGp_getEventManager().setCameraPlay(0);
}
interface_of_controller_pad& pad = mDoCPd_c::getCpadInfo(0);
f32 stickY = pad.mMainStickPosY * 72.0f;
f32 stickX = pad.mMainStickPosX * 72.0f;
f32 cStickY = pad.mCStickPosY * 59.0f;
f32 cStickX = pad.mCStickPosX * 59.0f;
f32 trigL = pad.mTriggerLeft * 150.0f;
f32 trigR = pad.mTriggerRight * 150.0f;
f32 stickY = 0.f;
f32 stickX = 0.f;
f32 cStickY = 0.f;
f32 cStickX = 0.f;
f32 trigL = 0.f;
f32 trigR = 0.f;
f32 rollInput = 0.f;
bool fast = false;
if (dusk::getSettings().game.debugFlyCamLockEvents) {
interface_of_controller_pad& pad = mDoCPd_c::getCpadInfo(0);
stickY = pad.mMainStickPosY * 72.0f;
stickX = pad.mMainStickPosX * 72.0f;
cStickY = pad.mCStickPosY * 59.0f;
cStickX = pad.mCStickPosX * 59.0f;
trigL = pad.mTriggerLeft * 150.0f;
trigR = pad.mTriggerRight * 150.0f;
fast = mDoCPd_c::getHoldZ(PAD_1);
if (mDoCPd_c::getHoldY(PAD_1)) rollInput -= 1.f;
if (mDoCPd_c::getHoldX(PAD_1)) rollInput += 1.f;
}
{
ImGuiIO& io = ImGui::GetIO();
if (!io.WantCaptureKeyboard) {
f32 kbX = 0.0f, kbY = 0.0f;
if (ImGui::IsKeyDown(ImGuiKey_W) || ImGui::IsKeyDown(ImGuiKey_UpArrow)) kbY += 1.f;
if (ImGui::IsKeyDown(ImGuiKey_S) || ImGui::IsKeyDown(ImGuiKey_DownArrow)) kbY -= 1.f;
if (ImGui::IsKeyDown(ImGuiKey_D) || ImGui::IsKeyDown(ImGuiKey_RightArrow)) kbX += 1.f;
if (ImGui::IsKeyDown(ImGuiKey_A) || ImGui::IsKeyDown(ImGuiKey_LeftArrow)) kbX -= 1.f;
f32 len = sqrtf(kbX * kbX + kbY * kbY);
if (len > 1.f) { kbX /= len; kbY /= len; }
stickX += kbX * 72.0f;
stickY += kbY * 72.0f;
if (ImGui::IsKeyDown(ImGuiKey_Space)) trigR += 150.0f;
if (ImGui::IsKeyDown(ImGuiKey_LeftCtrl)) trigL += 150.0f;
if (ImGui::IsKeyDown(ImGuiKey_LeftShift)) fast = true;
if (ImGui::IsKeyDown(ImGuiKey_Q)) rollInput -= 1.0f;
if (ImGui::IsKeyDown(ImGuiKey_E)) rollInput += 1.0f;
}
bool mouseValid = !io.WantCaptureMouse && io.MousePos.x >= 0.0f && io.MousePos.y >= 0.0f;
if (mouseValid && sFlyCamLastMousePos.x >= 0.0f) {
cStickX -= (io.MousePos.x - sFlyCamLastMousePos.x) * 2.0f;
cStickY -= (io.MousePos.y - sFlyCamLastMousePos.y) * 2.0f;
}
sFlyCamLastMousePos = mouseValid ? io.MousePos : ImVec2{-1.0f, -1.0f};
}
f32 verticalDisp = 0.0f;
if (trigR >= FLYCAM_TRIGGER_DEADZONE) {
@@ -7542,7 +7593,7 @@ bool dCamera_c::executeDebugFlyCam() {
f32 moveDx = stickY * cosf(mDebugFlyCam.yaw) * cosf(mDebugFlyCam.pitch) - stickX * sinf(mDebugFlyCam.yaw);
f32 moveDz = stickY * sinf(mDebugFlyCam.yaw) * cosf(mDebugFlyCam.pitch) + stickX * cosf(mDebugFlyCam.yaw);
f32 speed = mDoCPd_c::getHoldZ(PAD_1) ? FLYCAM_FAST_SPEED : FLYCAM_SPEED;
f32 speed = fast ? FLYCAM_FAST_SPEED : FLYCAM_SPEED;
mEye.x += speed * moveDx;
mEye.y += speed * moveDy;
@@ -7553,6 +7604,7 @@ bool dCamera_c::executeDebugFlyCam() {
mCenter.z = mEye.z + sinf(mDebugFlyCam.yaw) * cosf(mDebugFlyCam.pitch) * FLYCAM_TARGET_DIST;
mCenter.y = mEye.y + sinf(mDebugFlyCam.pitch) * FLYCAM_TARGET_DIST;
mBank = mBank + static_cast<s16>(rollInput * FLYCAM_ROLL_SPEED * (fast ? FLYCAM_FAST_SPEED / FLYCAM_SPEED : 1.f));
Reset(mCenter, mEye);
f32 yawInput = dusk::getSettings().game.invertCameraXAxis ? cStickX : -cStickX;
@@ -7570,7 +7622,7 @@ void dCamera_c::deactivateDebugFlyCam() {
Reset(mDebugFlyCam.savedCenter, mDebugFlyCam.savedEye, mDebugFlyCam.savedFovy, mDebugFlyCam.savedBank.Val());
dEvt_control_c* event = dComIfGp_getEvent();
if (event != nullptr) {
if (event != nullptr && event->mEventStatus != 0) {
event->mEventStatus = 0;
}
dComIfGp_getEventManager().setCameraPlay(0);
+6 -3
View File
@@ -24,9 +24,10 @@
#include "d/actor/d_a_horse.h"
#include <cstring>
#if TARGET_PC
#include "dusk/memory.h"
#include "dusk/memory.h"
#include "dusk/settings.h"
#endif
int dMeter2_c::_create() {
stage_stag_info_class* stag_info = dComIfGp_getStageStagInfo();
@@ -317,7 +318,9 @@ int dMeter2_c::_execute() {
int dMeter2_c::_draw() {
#if TARGET_PC
if (dusk::getSettings().game.disableMainHUD) {
if (dusk::getSettings().game.recordingMode || dusk::getSettings().game.minimalHUD ||
dusk::getSettings().game.debugFlyCam)
{
return 1;
}
#endif
+9
View File
@@ -6,6 +6,10 @@
#include "d/d_com_inf_game.h"
#include "d/d_pane_class.h"
#if TARGET_PC
#include "dusk/settings.h"
#endif
dMsgScrnArrow_c::dMsgScrnArrow_c() {
mpScreen = JKR_NEW J2DScreen();
JUT_ASSERT(0, mpScreen != NULL);
@@ -65,6 +69,11 @@ dMsgScrnArrow_c::~dMsgScrnArrow_c() {
}
void dMsgScrnArrow_c::draw() {
#if TARGET_PC
if (dusk::getSettings().game.recordingMode) {
return;
}
#endif
J2DGrafContext* graf_ctx = dComIfGp_getCurrentGrafPort();
mpScreen->draw(0.0f, 0.0f, graf_ctx);
}
+24
View File
@@ -8,6 +8,10 @@
#include "d/d_pane_class.h"
#include <cstring>
#if TARGET_PC
#include "dusk/settings.h"
#endif
dMsgScrnBase_c::dMsgScrnBase_c() {
init();
}
@@ -57,12 +61,22 @@ void dMsgScrnBase_c::init() {
}
void dMsgScrnBase_c::multiDraw() {
#if TARGET_PC
if (dusk::getSettings().game.recordingMode) {
return;
}
#endif
if (field_0x48 != NULL) {
dComIfGd_set2DOpa(field_0x48);
}
}
void dMsgScrnBase_c::draw() {
#if TARGET_PC
if (dusk::getSettings().game.recordingMode) {
return;
}
#endif
J2DGrafContext* ctx = dComIfGp_getCurrentGrafPort();
ctx->setup2D();
@@ -72,10 +86,20 @@ void dMsgScrnBase_c::draw() {
}
void dMsgScrnBase_c::drawSelf() {
#if TARGET_PC
if (dusk::getSettings().game.recordingMode) {
return;
}
#endif
drawOutFont(0.0f, 0.0f, 1.0f);
}
void dMsgScrnBase_c::drawOutFont(f32 param_0, f32 param_1, f32 param_2) {
#if TARGET_PC
if (dusk::getSettings().game.recordingMode) {
return;
}
#endif
mpOutFont->draw(NULL, param_0, param_1, param_2);
}
+9
View File
@@ -6,6 +6,10 @@
#include "d/d_msg_object.h"
#include "d/d_pane_class.h"
#if TARGET_PC
#include "dusk/settings.h"
#endif
dMsgScrnBoss_c::dMsgScrnBoss_c() {
static u64 t_tag[7] = {
MULTI_CHAR('sfontb0'), MULTI_CHAR('sfontb1'), MULTI_CHAR('sfontb2'), MULTI_CHAR('sfontl0'), MULTI_CHAR('sfontl1'), MULTI_CHAR('sfontl2'), MULTI_CHAR('sfont00'),
@@ -91,6 +95,11 @@ void dMsgScrnBoss_c::exec() {
}
void dMsgScrnBoss_c::drawSelf() {
#if TARGET_PC
if (dusk::getSettings().game.recordingMode) {
return;
}
#endif
J2DGrafContext* ctx = dComIfGp_getCurrentGrafPort();
ctx->setup2D();
drawOutFont(0.0f, 0.0f, 1.0f);
+9
View File
@@ -13,6 +13,10 @@
#include "d/d_msg_out_font.h"
#include "d/d_pane_class.h"
#if TARGET_PC
#include "dusk/settings.h"
#endif
dMsgScrnKanban_c::dMsgScrnKanban_c(JKRExpHeap* param_0) {
if (param_0 != NULL) {
field_0xd4 = param_0;
@@ -176,6 +180,11 @@ void dMsgScrnKanban_c::exec() {
}
void dMsgScrnKanban_c::draw() {
#if TARGET_PC
if (dusk::getSettings().game.recordingMode) {
return;
}
#endif
J2DGrafContext* grafContext = dComIfGp_getCurrentGrafPort();
grafContext->setup2D();
mpScreen->draw(0.0f, 0.0f, grafContext);
+9
View File
@@ -12,6 +12,10 @@
#include "d/d_msg_object.h"
#include "d/d_pane_class.h"
#if TARGET_PC
#include "dusk/settings.h"
#endif
dMsgScrnPlace_c::dMsgScrnPlace_c() {
static u64 t_tag[7] = {
MULTI_CHAR('sfontb0'), MULTI_CHAR('sfontb1'), MULTI_CHAR('sfontb2'), MULTI_CHAR('sfontl0'), MULTI_CHAR('sfontl1'), MULTI_CHAR('sfontl2'), MULTI_CHAR('sfont00'),
@@ -127,6 +131,11 @@ void dMsgScrnPlace_c::exec() {
}
void dMsgScrnPlace_c::drawSelf() {
#if TARGET_PC
if (dusk::getSettings().game.recordingMode) {
return;
}
#endif
J2DGrafContext* grafContext = dComIfGp_getCurrentGrafPort();
grafContext->setup2D();
drawOutFont(0.0f, 0.0f, 1.0f);
+9
View File
@@ -20,6 +20,10 @@
#include "JSystem/J2DGraph/J2DScreen.h"
#include <cstring>
#if TARGET_PC
#include "dusk/settings.h"
#endif
dMsgScrnTalk_c::dMsgScrnTalk_c(u8 param_1, u8 param_2, JKRExpHeap* param_3) {
if (param_3 != NULL) {
field_0xe4 = param_3;
@@ -303,6 +307,11 @@ void dMsgScrnTalk_c::exec() {
}
void dMsgScrnTalk_c::drawSelf() {
#if TARGET_PC
if (dusk::getSettings().game.recordingMode) {
return;
}
#endif
J2DGrafContext* grafContext[1];
grafContext[0] = dComIfGp_getCurrentGrafPort();
grafContext[0]->setup2D();
+9
View File
@@ -9,6 +9,10 @@
#include "d/d_msg_out_font.h"
#include "d/d_pane_class.h"
#if TARGET_PC
#include "dusk/settings.h"
#endif
dMsgScrnTree_c::dMsgScrnTree_c(JUTFont* param_0, JKRExpHeap* param_1) {
if (param_1 != NULL) {
field_0xd8 = param_1;
@@ -187,6 +191,11 @@ void dMsgScrnTree_c::exec() {
}
void dMsgScrnTree_c::draw() {
#if TARGET_PC
if (dusk::getSettings().game.recordingMode) {
return;
}
#endif
J2DGrafContext* grafContext = dComIfGp_getCurrentGrafPort();
grafContext->setup2D();
mpScreen->draw(0.0f, 0.0f, grafContext);
+31 -8
View File
@@ -21,16 +21,39 @@ static bool checkEnabled() {
return !__OSReport_disable || dusk::OSReportReallyForceEnable;
}
#ifndef va_copy
#define va_copy(d, s) ((d) = (s))
#endif
static std::string FormatToString(const char* msg, va_list list) {
int ret = vsnprintf(nullptr, 0, msg, list);
if (ret <= 0) {
return {};
size_t size = (strlen(msg) * 2) + 50;
std::string str;
va_list ap;
int attempts = 0;
while (true) {
str.resize(size);
va_copy(ap, list);
int n = vsnprintf(str.data(), size, msg, ap);
va_end(ap);
if (n > -1 && n < size) {
str.resize(n);
break;
}
++attempts;
if (attempts >= 3) {
if (n == -1) {
str.clear();
}
break;
}
if (n > -1) {
size = n + 1;
} else {
size *= 2;
}
}
++ret;
std::unique_ptr<char[]> buf(new char[ret]);
vsnprintf(buf.get(), ret, msg, list);
buf[ret - 1] = '\0';
return {buf.get()};
return str;
}
void OSReport(const char* fmt, ...) {
+6 -2
View File
@@ -282,7 +282,9 @@ static void ShowAllJAISeqs() {
}
void dusk::ImGuiMenuTools::ShowAudioDebug() {
if (!ImGuiConsole::CheckMenuViewToggle(ImGuiKey_F10, m_showAudioDebug)) {
if (!getSettings().backend.enableAdvancedSettings ||
!ImGuiConsole::CheckMenuViewToggle(ImGuiKey_F10, m_showAudioDebug))
{
return;
}
@@ -328,7 +330,9 @@ void dusk::ImGuiMenuTools::ShowAudioDebug() {
}
void dusk::ImGuiMenuTools::ShowSaveEditor() {
if (!ImGuiConsole::CheckMenuViewToggle(ImGuiKey_F6, m_showSaveEditor)) {
if (!getSettings().backend.enableAdvancedSettings ||
!ImGuiConsole::CheckMenuViewToggle(ImGuiKey_F6, m_showSaveEditor))
{
return;
}
m_saveEditor.draw(m_showSaveEditor);
+22 -4
View File
@@ -10,7 +10,9 @@
namespace dusk {
void ImGuiMenuTools::ShowCameraOverlay() {
if (!ImGuiConsole::CheckMenuViewToggle(ImGuiKey_F9, m_showCameraOverlay)) {
if (!getSettings().backend.enableAdvancedSettings ||
!ImGuiConsole::CheckMenuViewToggle(ImGuiKey_F9, m_showCameraOverlay))
{
return;
}
@@ -61,16 +63,32 @@ namespace dusk {
ImGui::SetTooltip("Cannot enable while paused or during an active event.");
} else {
ImGui::SetTooltip("Detach camera and fly freely.\n"
"Left stick: move, C-stick: look\n"
"L/R triggers: up/down, Z: fast");
"WASD/Arrows/Left stick: move, Mouse/C-stick: look\n"
"Ctrl/L: down, Space/R: up, Shift/Z: fast\n"
"Q Key/Y: roll left, R Key/X: roll right");
}
}
if (eventRunning) {
ImGui::EndDisabled();
}
if (!getSettings().game.debugFlyCam) {
ImGui::BeginDisabled();
}
config::ImGuiCheckbox("Lock Events", getSettings().game.debugFlyCamLockEvents);
if (ImGui::IsItemHovered(ImGuiHoveredFlags_AllowWhenDisabled)) {
if (!getSettings().game.debugFlyCam) {
ImGui::SetTooltip("Enable Fly Mode first.");
} else {
ImGui::SetTooltip("Freeze game events while flying.");
}
}
if (!getSettings().game.debugFlyCam) {
ImGui::EndDisabled();
}
ShowCornerContextMenu(m_cameraOverlayCorner, 0);
ImGui::End();
}
}
}
+10 -14
View File
@@ -261,12 +261,19 @@ namespace dusk {
}
if (ImGui::IsKeyPressed(ImGuiKey_F11)) {
ImGuiMenuGame::ToggleFullscreen();
getSettings().video.enableFullscreen.setValue(!getSettings().video.enableFullscreen);
VISetWindowFullscreen(getSettings().video.enableFullscreen);
config::Save();
}
if (ImGui::GetIO().KeyShift && ImGui::IsKeyPressed(ImGuiKey_F1)) {
m_isHidden = !m_isHidden;
if (getSettings().backend.enableAdvancedSettings) {
m_isHidden = !m_isHidden;
} else {
m_isHidden = true;
}
}
bool showMenu = !m_isHidden;
// The menu bar renders with ImGuiCol_WindowBg behind it. We just want ImGuiCol_MenuBarBg,
@@ -276,16 +283,6 @@ namespace dusk {
m_menuGame.draw();
m_menuTools.draw();
const auto fpsLabel =
fmt::format(FMT_STRING("FPS: {:.2f}\n"), ImGui::GetIO().Framerate);
const auto fpsSize =
ImGui::CalcTextSize(fpsLabel.data(), fpsLabel.data() + fpsLabel.size());
ImGui::SetCursorPosX(
ImMax(ImGui::GetCursorPosX(), ImGui::GetWindowWidth() -
ImGui::GetStyle().DisplaySafeAreaPadding.x -
fpsSize.x - ImGui::GetStyle().ItemSpacing.x));
ImGuiStringViewText(fpsLabel);
ImGui::EndMainMenuBar();
}
ImGui::PopStyleColor();
@@ -360,8 +357,7 @@ namespace dusk {
ImGui::End();
}
m_menuGame.windowControllerConfig();
m_menuGame.windowInputViewer();
m_menuTools.ShowInputViewer();
m_menuGame.drawSpeedrunTimerOverlay();
if (getSettings().game.liveSplitEnabled) {
+1 -2
View File
@@ -3,12 +3,11 @@
#include "imgui.h"
#include <imgui_internal.h>
#include "ImGuiConsole.hpp"
#include "ImGuiMenuGame.hpp"
#include <dolphin/pad.h>
namespace dusk {
void ImGuiMenuGame::windowInputViewer() {
void ImGuiMenuTools::ShowInputViewer() {
if (!m_showInputViewer) {
return;
}
+3 -1
View File
@@ -22,7 +22,9 @@ namespace dusk {
void ShowHeapDetailed(JKRHeap* heap, OpenHeapData& data, bool& open);
void ImGuiMenuTools::ShowHeapOverlay() {
if (!ImGuiConsole::CheckMenuViewToggle(ImGuiKey_F4, m_showHeapOverlay)) {
if (!getSettings().backend.enableAdvancedSettings ||
!ImGuiConsole::CheckMenuViewToggle(ImGuiKey_F4, m_showHeapOverlay))
{
return;
}
+3 -1
View File
@@ -9,7 +9,9 @@
namespace dusk {
void ImGuiMenuTools::ShowMapLoader() {
if (!ImGuiConsole::CheckMenuViewToggle(ImGuiKey_F7, m_showMapLoader)) {
if (!getSettings().backend.enableAdvancedSettings ||
!ImGuiConsole::CheckMenuViewToggle(ImGuiKey_F7, m_showMapLoader))
{
return;
}
+1 -558
View File
@@ -1,573 +1,16 @@
#include "fmt/format.h"
#include "imgui.h"
#include "ImGuiEngine.hpp"
#include "ImGuiConsole.hpp"
#include "ImGuiConfig.hpp"
#include "dusk/main.h"
#include "dusk/hotkeys.h"
#include "m_Do/m_Do_main.h"
#include <SDL3/SDL_gamepad.h>
namespace dusk {
void ImGuiMenuGame::ToggleFullscreen() {
getSettings().video.enableFullscreen.setValue(!getSettings().video.enableFullscreen);
VISetWindowFullscreen(getSettings().video.enableFullscreen);
config::Save();
}
ImGuiMenuGame::ImGuiMenuGame() {}
void ImGuiMenuGame::draw() {
if (ImGui::BeginMenu("Settings")) {
// TODO: Remove this once Controller Config exists in RmlUi
if (ImGui::Button("Configure Controller")){
m_showControllerConfig = !m_showControllerConfig;
}
ImGui::Checkbox("Show Input Viewer", &m_showInputViewer);
ImGui::EndMenu();
}
}
static void drawVirtualStick(const char* id, const ImVec2& stick) {
float scale = ImGuiScale();
ImGui::SetCursorPos(ImVec2(ImGui::GetCursorPos().x + 45 * scale, ImGui::GetCursorPos().y + 10));
ImGui::BeginChild(id, ImVec2(80 * scale, 80 * scale), 0, ImGuiWindowFlags_NoBackground);
ImDrawList* dl = ImGui::GetWindowDrawList();
ImVec2 p = ImGui::GetCursorScreenPos();
float radius = 30.0f * scale;
ImVec2 pos = ImVec2(p.x + radius, p.y + radius);
constexpr ImU32 stickGray = IM_COL32(150, 150, 150, 255);
constexpr ImU32 white = IM_COL32(255, 255, 255, 255);
constexpr ImU32 red = IM_COL32(230, 0, 0, 255);
dl->AddCircleFilled(pos, radius, stickGray, 8);
dl->AddCircleFilled(ImVec2(pos.x + stick.x * (radius), pos.y + -stick.y * (radius)), 3 * scale, red);
ImGui::EndChild();
}
struct SpecificButtonName {
SDL_GamepadType Type;
const char* Name;
};
struct ButtonNames {
SDL_GamepadButton Button;
std::vector<SpecificButtonName> Names;
};
// clang-format off
static const std::vector<ButtonNames> GamepadButtonNames = {
{ SDL_GAMEPAD_BUTTON_LEFT_STICK, {
{SDL_GAMEPAD_TYPE_PS3, "L3"},
{SDL_GAMEPAD_TYPE_PS4, "L3"},
{SDL_GAMEPAD_TYPE_PS5, "L3"},
{SDL_GAMEPAD_TYPE_XBOX360, "Left Stick"},
{SDL_GAMEPAD_TYPE_XBOXONE, "Left Stick"},
{SDL_GAMEPAD_TYPE_GAMECUBE, "Control Stick"},
}},
{ SDL_GAMEPAD_BUTTON_RIGHT_STICK, {
{SDL_GAMEPAD_TYPE_PS3, "R3"},
{SDL_GAMEPAD_TYPE_PS4, "R3"},
{SDL_GAMEPAD_TYPE_PS5, "R3"},
{SDL_GAMEPAD_TYPE_XBOX360, "Right Stick"},
{SDL_GAMEPAD_TYPE_XBOXONE, "Right Stick"},
{SDL_GAMEPAD_TYPE_GAMECUBE, "C Stick"},
}},
{ SDL_GAMEPAD_BUTTON_LEFT_SHOULDER, {
{SDL_GAMEPAD_TYPE_PS3, "L1"},
{SDL_GAMEPAD_TYPE_PS4, "L1"},
{SDL_GAMEPAD_TYPE_PS5, "L1"},
{SDL_GAMEPAD_TYPE_XBOX360, "LB"},
{SDL_GAMEPAD_TYPE_XBOXONE, "LB"},
}},
{ SDL_GAMEPAD_BUTTON_RIGHT_SHOULDER, {
{SDL_GAMEPAD_TYPE_PS3, "R1"},
{SDL_GAMEPAD_TYPE_PS4, "R1"},
{SDL_GAMEPAD_TYPE_PS5, "R1"},
{SDL_GAMEPAD_TYPE_XBOX360, "RB"},
{SDL_GAMEPAD_TYPE_XBOXONE, "RB"},
{SDL_GAMEPAD_TYPE_GAMECUBE, "Z"},
}},
{ SDL_GAMEPAD_BUTTON_BACK, {
{SDL_GAMEPAD_TYPE_PS3, "Select"},
{SDL_GAMEPAD_TYPE_PS4, "Share"},
{SDL_GAMEPAD_TYPE_PS5, "Create"},
{SDL_GAMEPAD_TYPE_XBOX360, "Back"},
{SDL_GAMEPAD_TYPE_XBOXONE, "View"},
}},
{ SDL_GAMEPAD_BUTTON_START, {
{SDL_GAMEPAD_TYPE_PS3, "Start"},
{SDL_GAMEPAD_TYPE_PS4, "Options"},
{SDL_GAMEPAD_TYPE_PS5, "Options"},
{SDL_GAMEPAD_TYPE_XBOX360, "Start"},
{SDL_GAMEPAD_TYPE_XBOXONE, "Menu"},
{SDL_GAMEPAD_TYPE_GAMECUBE, "Start/Pause"},
}},
};
// clang-format on
static const char* GetNameForGamepadButton(SDL_Gamepad* gamepad, u32 buttonUntyped) {
if (buttonUntyped == PAD_NATIVE_BUTTON_INVALID) {
return "Not bound";
}
auto button = static_cast<SDL_GamepadButton>(buttonUntyped);
auto label = SDL_GetGamepadButtonLabel(gamepad, button);
switch (label) {
case SDL_GAMEPAD_BUTTON_LABEL_A:
return "A";
case SDL_GAMEPAD_BUTTON_LABEL_B:
return "B";
case SDL_GAMEPAD_BUTTON_LABEL_X:
return "X";
case SDL_GAMEPAD_BUTTON_LABEL_Y:
return "Y";
case SDL_GAMEPAD_BUTTON_LABEL_CROSS:
return "Cross";
case SDL_GAMEPAD_BUTTON_LABEL_CIRCLE:
return "Circle";
case SDL_GAMEPAD_BUTTON_LABEL_TRIANGLE:
return "Triangle";
case SDL_GAMEPAD_BUTTON_LABEL_SQUARE:
return "Square";
default:; // Fall through
}
auto padType = SDL_GetGamepadType(gamepad);
for (const auto& buttonNames : GamepadButtonNames) {
if (buttonNames.Button != button) {
continue;
}
for (const auto& name : buttonNames.Names) {
if (name.Type == padType) {
return name.Name;
}
}
}
switch (button) {
case SDL_GAMEPAD_BUTTON_DPAD_LEFT:
return "D-pad left";
case SDL_GAMEPAD_BUTTON_DPAD_RIGHT:
return "D-pad right";
case SDL_GAMEPAD_BUTTON_DPAD_UP:
return "D-pad up";
case SDL_GAMEPAD_BUTTON_DPAD_DOWN:
return "D-pad down";
default:
return PADGetNativeButtonName(buttonUntyped);
}
}
void ImGuiMenuGame::windowControllerConfig() {
if (!m_showControllerConfig) {
return;
}
// if pending for a button mapping, check to set new input
if (m_controllerConfig.m_pendingButtonMapping != nullptr) {
s32 nativeButton = PADGetNativeButtonPressed(m_controllerConfig.m_pendingPort);
if (nativeButton != -1) {
m_controllerConfig.m_pendingButtonMapping->nativeButton = nativeButton;
m_controllerConfig.m_pendingButtonMapping = nullptr;
m_controllerConfig.m_pendingPort = -1;
PADBlockInput(false);
PADSerializeMappings();
}
}
// if pending for an axis mapping, check to set new input
if (m_controllerConfig.m_pendingAxisMapping != nullptr) {
auto nativeAxis = PADGetNativeAxisPulled(m_controllerConfig.m_pendingPort);
if (nativeAxis.nativeAxis != -1) {
m_controllerConfig.m_pendingAxisMapping->nativeAxis = nativeAxis;
m_controllerConfig.m_pendingAxisMapping->nativeButton = -1;
m_controllerConfig.m_pendingAxisMapping = nullptr;
m_controllerConfig.m_pendingPort = -1;
PADBlockInput(false);
PADSerializeMappings();
} else {
auto nativeButton = PADGetNativeButtonPressed(m_controllerConfig.m_pendingPort);
if (nativeButton != -1) {
m_controllerConfig.m_pendingAxisMapping->nativeAxis = {-1, AXIS_SIGN_POSITIVE};
m_controllerConfig.m_pendingAxisMapping->nativeButton = nativeButton;
m_controllerConfig.m_pendingAxisMapping = nullptr;
m_controllerConfig.m_pendingPort = -1;
PADBlockInput(false);
PADSerializeMappings();
}
}
}
float scale = ImGuiScale();
ImGuiWindowFlags windowFlags =
ImGuiWindowFlags_NoResize |
ImGuiWindowFlags_AlwaysAutoResize;
// ImGui::SetNextWindowBgAlpha(0.65f);
if (!ImGui::Begin("Controller Config", &m_showControllerConfig, windowFlags)) {
ImGui::End();
return;
}
// port tabs
ImGui::BeginTabBar("##ControllerTabs");
for (int i = PAD_1; i <= PAD_4; i++) {
if (ImGui::BeginTabItem(fmt::format("Port {}", i + 1).c_str())) {
m_controllerConfig.m_selectedPort = i;
ImGui::EndTabItem();
}
}
ImGui::EndTabBar();
// if tab is changed while waiting for input, cancel pending
if ((m_controllerConfig.m_pendingButtonMapping != nullptr ||
m_controllerConfig.m_pendingAxisMapping != nullptr) &&
m_controllerConfig.m_pendingPort != m_controllerConfig.m_selectedPort)
{
m_controllerConfig.m_pendingButtonMapping = nullptr;
m_controllerConfig.m_pendingAxisMapping = nullptr;
m_controllerConfig.m_pendingPort = -1;
PADBlockInput(false);
}
// get a list of all available controller's names
std::vector<std::string> controllerList;
controllerList.push_back("None");
for (int i = 0; i < PADCount(); i++) {
// attach index to name for unique name
controllerList.push_back(fmt::format("{}-{}", PADGetNameForControllerIndex(i), i));
}
// get current controller name
const char* tmpName = PADGetName(m_controllerConfig.m_selectedPort);
std::string currentName = "None";
if (tmpName != nullptr) {
currentName = fmt::format("{}-{}", tmpName, PADGetIndexForPort(m_controllerConfig.m_selectedPort));
}
// controller selection combo box
bool changedController = false;
int changedControllerIndex = 0;
ImGui::SetNextItemWidth(400.0f * scale);
if (ImGui::BeginCombo("##ControllerDeviceList", currentName.c_str())) {
for (int i = 0; const auto& name : controllerList) {
if (ImGui::Selectable(name.c_str(), currentName == name)) {
changedControllerIndex = i;
changedController = true;
}
i++;
}
ImGui::EndCombo();
}
// handle controller change
if (changedController) {
if (changedControllerIndex > 0) {
PADSetPortForIndex(changedControllerIndex - 1, m_controllerConfig.m_selectedPort);
}
else if (changedControllerIndex == 0) {
// if "None" selected
PADClearPort(m_controllerConfig.m_selectedPort);
}
PADSerializeMappings();
}
// restore defaults button
ImGui::SameLine();
if (ImGui::Button("Default")) {
PADRestoreDefaultMapping(m_controllerConfig.m_selectedPort);
PADSerializeMappings();
}
// buttons panel
const float uiButtonSize = 40 * scale;
ImVec2 btnSize(110.0f * scale, 30.0f * scale);
ImGuiBeginGroupPanel("Buttons", ImVec2(150 * scale, 20 * scale));
SDL_Gamepad* gamepad = PADGetSDLGamepadForIndex(PADGetIndexForPort(m_controllerConfig.m_selectedPort));
u32 buttonCount;
PADButtonMapping* btnMappingList = PADGetButtonMappings(m_controllerConfig.m_selectedPort, &buttonCount);
if (btnMappingList != nullptr) {
for (int i = 0; i < buttonCount; i++) {
const char* btnName = PADGetButtonName(btnMappingList[i].padButton);
ImVec2 len = ImGui::CalcTextSize(btnName);
ImVec2 pos = ImGui::GetCursorPos();
ImGui::SetCursorPosY(pos.y + len.y / 4);
ImGui::SetCursorPosX(pos.x + abs(len.x - uiButtonSize));
ImGui::Text("%s", btnName);
ImGui::SameLine();
ImGui::SetCursorPosY(pos.y);
std::string dispName;
if (m_controllerConfig.m_isReading && m_controllerConfig.m_pendingButtonMapping == &btnMappingList[i]) {
dispName = fmt::format("Press a Key...##{}", btnName);
} else {
const char* nativeName = GetNameForGamepadButton(gamepad, btnMappingList[i].nativeButton);
if (nativeName == nullptr) {
nativeName = "[unbound]";
}
dispName = fmt::format("{0}##-{1}", nativeName, i);
}
bool pressed = ImGui::Button(dispName.c_str(),
btnSize);
if (pressed) {
m_controllerConfig.m_isReading = true;
m_controllerConfig.m_pendingPort = m_controllerConfig.m_selectedPort;
m_controllerConfig.m_pendingButtonMapping = &btnMappingList[i];
PADBlockInput(true);
}
}
}
ImGuiEndGroupPanel();
ImGui::SameLine();
uint32_t axisCount;
PADAxisMapping* axisMappingList = PADGetAxisMappings(m_controllerConfig.m_selectedPort, &axisCount);
ImGuiBeginGroupPanel("Analog Triggers", ImVec2(150 * scale, 20 * scale));
PADAxis triggers[] = {PAD_AXIS_TRIGGER_L, PAD_AXIS_TRIGGER_R};
if (axisMappingList != nullptr) {
for (PADAxis trigger : triggers) {
const char* axisName = PADGetAxisName(axisMappingList[trigger].padAxis);
ImVec2 len = ImGui::CalcTextSize(axisName);
ImVec2 pos = ImGui::GetCursorPos();
ImGui::SetCursorPosY(pos.y + len.y / 4);
ImGui::SetCursorPosX(pos.x + abs(len.x - uiButtonSize));
ImGui::Text("%s", axisName);
ImGui::SameLine();
ImGui::SetCursorPosY(pos.y);
std::string dispName;
if (m_controllerConfig.m_isReading && m_controllerConfig.m_pendingAxisMapping == &axisMappingList[trigger]) {
dispName = fmt::format("Press a Key...##{}", axisName);
} else {
dispName = fmt::format("{0}##-{1}", PADGetNativeAxisName(axisMappingList[trigger].nativeAxis), trigger);
}
bool pressed = ImGui::Button(dispName.c_str(),
btnSize);
if (pressed) {
m_controllerConfig.m_isReading = true;
m_controllerConfig.m_pendingPort = m_controllerConfig.m_selectedPort;
m_controllerConfig.m_pendingAxisMapping = &axisMappingList[trigger];
PADBlockInput(true);
}
}
}
int port = m_controllerConfig.m_selectedPort;
PADDeadZones* deadZones = PADGetDeadZones(port);
if (deadZones != nullptr) {
ImGui::Text("L Threshold");
ImGui::SameLine();
{
float tmp = static_cast<float>(deadZones->leftTriggerActivationZone * 100.f) / 32767.f;
if (ImGui::DragFloat("##LThreshold", &tmp, 0.5f, 0.f, 100.f, "%.3f%%")) {
deadZones->leftTriggerActivationZone = static_cast<u16>((tmp / 100.f) * 32767);
PADSerializeMappings();
}
}
}
if (deadZones != nullptr) {
ImGui::Text("R Threshold");
ImGui::SameLine();
{
float tmp = static_cast<float>(deadZones->rightTriggerActivationZone * 100.f) / 32767.f;
if (ImGui::DragFloat("##RThreshold", &tmp, 0.5f, 0.f, 100.f, "%.3f%%")) {
deadZones->rightTriggerActivationZone = static_cast<u16>((tmp / 100.f) * 32767);
PADSerializeMappings();
}
}
}
ImGuiEndGroupPanel();
ImGui::SameLine();
// main stick panel
ImGuiBeginGroupPanel("Control Stick", ImVec2(150 * scale, 20 * scale));
drawVirtualStick("##mainStick", ImVec2{ mDoCPd_c::getStickX(port), mDoCPd_c::getStickY(port) });
if (axisMappingList != nullptr) {
const PADAxis lStickAxes[] = {PAD_AXIS_LEFT_Y_POS, PAD_AXIS_LEFT_Y_NEG, PAD_AXIS_LEFT_X_NEG, PAD_AXIS_LEFT_X_POS};
for (auto axis : lStickAxes) {
const char* label = PADGetAxisDirectionLabel(axis);
ImVec2 len = ImGui::CalcTextSize(label);
ImVec2 pos = ImGui::GetCursorPos();
ImGui::SetCursorPosY(pos.y + len.y / 4);
ImGui::SetCursorPosX(pos.x + abs(len.x - uiButtonSize));
ImGui::Text("%s", label);
ImGui::SameLine();
ImGui::SetCursorPosY(pos.y);
std::string dispName;
if (m_controllerConfig.m_isReading && m_controllerConfig.m_pendingAxisMapping == &axisMappingList[axis]) {
dispName = fmt::format("Press a Key...##{}", label);
} else {
if (axisMappingList[axis].nativeAxis.nativeAxis != -1) {
const char* signStr;
if (axis == PAD_AXIS_TRIGGER_L || axis == PAD_AXIS_TRIGGER_R) {
signStr = "";
} else if (axisMappingList[axis].nativeAxis.sign == AXIS_SIGN_POSITIVE) {
signStr = "+";
} else {
signStr = "-";
}
dispName = fmt::format("{0}{1}##-{2}", PADGetNativeAxisName(axisMappingList[axis].nativeAxis), signStr, axis);
} else {
assert(axisMappingList[axis].nativeButton != -1);
dispName = fmt::format("{0}##-{1}", PADGetNativeButtonName(axisMappingList[axis].nativeButton), axis);
}
}
bool pressed = ImGui::Button(dispName.c_str(), btnSize);
if (pressed) {
m_controllerConfig.m_isReading = true;
m_controllerConfig.m_pendingPort = m_controllerConfig.m_selectedPort;
m_controllerConfig.m_pendingAxisMapping = &axisMappingList[axis];
PADBlockInput(true);
}
}
}
if (deadZones != nullptr) {
ImGui::Text("Dead Zone");
{
float tmp = static_cast<float>(deadZones->stickDeadZone * 100.f) / 32767.f;
if (ImGui::DragFloat("##mainDeadZone", &tmp, 0.5f, 0.f, 100.f, "%.3f%%")) {
deadZones->stickDeadZone = static_cast<u16>((tmp / 100.f) * 32767);
PADSerializeMappings();
}
}
}
ImGuiEndGroupPanel();
ImGui::SameLine();
// sub stick panel
ImGuiBeginGroupPanel("C Stick", ImVec2(150 * scale, 20 * scale));
drawVirtualStick("##subStick", ImVec2{ mDoCPd_c::getSubStickX(port), mDoCPd_c::getSubStickY(port) });
if (axisMappingList != nullptr) {
const PADAxis rStickAxes[] = {PAD_AXIS_RIGHT_Y_POS, PAD_AXIS_RIGHT_Y_NEG, PAD_AXIS_RIGHT_X_NEG, PAD_AXIS_RIGHT_X_POS};
for (auto axis : rStickAxes) {
const char* label = PADGetAxisDirectionLabel(axisMappingList[axis].padAxis);
ImVec2 len = ImGui::CalcTextSize(label);
ImVec2 pos = ImGui::GetCursorPos();
ImGui::SetCursorPosY(pos.y + len.y / 4);
ImGui::SetCursorPosX(pos.x + abs(len.x - uiButtonSize));
ImGui::Text("%s", label);
ImGui::SameLine();
ImGui::SetCursorPosY(pos.y);
std::string dispName;
if (m_controllerConfig.m_isReading && m_controllerConfig.m_pendingAxisMapping == &axisMappingList[axis]) {
dispName = fmt::format("Press a Key...##sub{}", label);
} else {
if (axisMappingList[axis].nativeAxis.nativeAxis != -1) {
const char* signStr;
if (axis == PAD_AXIS_TRIGGER_L || axis == PAD_AXIS_TRIGGER_R) {
signStr = "";
} else if (axisMappingList[axis].nativeAxis.sign == AXIS_SIGN_POSITIVE) {
signStr = "+";
} else {
signStr = "-";
}
dispName = fmt::format("{0}{1}##-{2}", PADGetNativeAxisName(axisMappingList[axis].nativeAxis), signStr, axis);
} else {
assert(axisMappingList[axis].nativeButton != -1);
dispName = fmt::format("{0}##-{1}", PADGetNativeButtonName(axisMappingList[axis].nativeButton), axis);
}
}
bool pressed = ImGui::Button(fmt::format("{0}##sub{1}", dispName, label).c_str(), btnSize);
if (pressed) {
m_controllerConfig.m_isReading = true;
m_controllerConfig.m_pendingPort = m_controllerConfig.m_selectedPort;
m_controllerConfig.m_pendingAxisMapping = &axisMappingList[axis];
PADBlockInput(true);
}
}
}
if (deadZones != nullptr) {
ImGui::Text("Dead Zone");
{
float tmp = static_cast<float>(deadZones->substickDeadZone * 100.f) / 32767.f;
if (ImGui::DragFloat("##subDeadZone", &tmp, 0.5f, 0.f, 100.f, "%.3f%%")) {
deadZones->substickDeadZone = static_cast<u16>((tmp / 100.f) * 32767);
PADSerializeMappings();
}
}
}
ImGuiEndGroupPanel();
ImGui::SameLine();
// Options panel
ImGuiBeginGroupPanel("Options", ImVec2(150 * scale, -1));
if (deadZones != nullptr) {
if (ImGui::Checkbox("Enable Dead Zones", &deadZones->useDeadzones)) {
PADSerializeMappings();
}
if (ImGui::Checkbox("Emulate Triggers", &deadZones->emulateTriggers)) {
PADSerializeMappings();
}
}
if (PADSupportsRumbleIntensity(m_controllerConfig.m_selectedPort)) {
ImGuiBeginGroupPanel("Rumble Intensity", ImVec2(150 * scale, -1));
u16 low;
u16 high;
(void)PADGetRumbleIntensity(m_controllerConfig.m_selectedPort, &low, &high);
float fLow = (static_cast<float>(low) / 32767.f) * 100.f;
bool changed = ImGui::SliderFloat("Low", &fLow, 0.f, 100.f, "%.0f%%");
float fHigh = (static_cast<float>(high) / 32767.f) * 100.f;
changed |= ImGui::SliderFloat("High", &fHigh, 0.f, 100.f, "%.0f%%");
if (changed) {
PADSetRumbleIntensity(m_controllerConfig.m_selectedPort,
static_cast<u16>((fLow / 100) * 32767),
static_cast<u16>((fHigh / 100) * 32767));
PADSerializeMappings();
}
if (ImGui::Button(fmt::format("{0}...##rumbleTest", m_controllerConfig.m_isRumbling ? "Stop": "Test").c_str(), {-1, 0})) {
PADControlMotor(m_controllerConfig.m_selectedPort, !m_controllerConfig.m_isRumbling ? PAD_MOTOR_RUMBLE : PAD_MOTOR_STOP_HARD);
m_controllerConfig.m_isRumbling ^= 1;
}
ImGuiEndGroupPanel();
}
ImGuiEndGroupPanel();
ImGui::End();
}
void ImGuiMenuGame::draw() {}
static std::string GetFormattedTime(OSTime ticks) {
OSCalendarTime time;
-20
View File
@@ -46,31 +46,11 @@ namespace dusk {
ImGuiMenuGame();
void draw();
void windowInputViewer();
void windowControllerConfig();
void drawSpeedrunTimerOverlay();
static void ToggleFullscreen();
static void resetForSpeedrunMode();
private:
struct {
int m_selectedPort = 0;
bool m_isReading = false;
PADButtonMapping* m_pendingButtonMapping = nullptr;
PADAxisMapping* m_pendingAxisMapping = nullptr;
int m_pendingPort = -1;
bool m_isRumbling = false;
} m_controllerConfig;
bool m_showControllerConfig = false;
bool m_showInputViewer = false;
bool m_showInputViewerGyro = false;
int m_inputOverlayCorner = 3;
std::string m_controllerName;
bool m_showTimerWindow = false;
};
}
+8 -2
View File
@@ -48,6 +48,8 @@ namespace dusk {
ImGui::EndDisabled();
}
ImGui::Separator();
ImGui::Checkbox("Show Input Viewer", &m_showInputViewer);
#if DUSK_CAN_OPEN_DATA_FOLDER
ImGui::Separator();
@@ -119,7 +121,9 @@ namespace dusk {
}
void ImGuiMenuTools::ShowDebugOverlay() {
if (!ImGuiConsole::CheckMenuViewToggle(ImGuiKey_F3, m_showDebugOverlay)) {
if (!getSettings().backend.enableAdvancedSettings ||
!ImGuiConsole::CheckMenuViewToggle(ImGuiKey_F3, m_showDebugOverlay))
{
return;
}
@@ -183,7 +187,9 @@ namespace dusk {
}
void ImGuiMenuTools::ShowPlayerInfo() {
if (!ImGuiConsole::CheckMenuViewToggle(ImGuiKey_F5, m_showPlayerInfo)) {
if (!getSettings().backend.enableAdvancedSettings ||
!ImGuiConsole::CheckMenuViewToggle(ImGuiKey_F5, m_showPlayerInfo))
{
return;
}
+6
View File
@@ -27,6 +27,7 @@ namespace dusk {
void ShowAudioDebug();
void ShowSaveEditor();
void ShowStateShare();
void ShowInputViewer();
private:
bool m_showDebugOverlay = false;
@@ -66,6 +67,11 @@ namespace dusk {
bool m_showStateShare = false;
ImGuiStateShare m_stateShare;
bool m_showInputViewer = false;
bool m_showInputViewerGyro = false;
int m_inputOverlayCorner = 3;
std::string m_controllerName;
};
}
+3 -1
View File
@@ -126,7 +126,9 @@ namespace dusk {
}
void ImGuiMenuTools::ShowProcessManager() {
if (!ImGuiConsole::CheckMenuViewToggle(ImGuiKey_F2, m_showProcessManagement)) {
if (!getSettings().backend.enableAdvancedSettings ||
!ImGuiConsole::CheckMenuViewToggle(ImGuiKey_F2, m_showProcessManagement))
{
return;
}
+3 -1
View File
@@ -417,7 +417,9 @@ void ImGuiStateShare::draw(bool& open) {
}
void ImGuiMenuTools::ShowStateShare() {
if (!ImGuiConsole::CheckMenuViewToggle(ImGuiKey_F8, m_showStateShare)) {
if (!getSettings().backend.enableAdvancedSettings ||
!ImGuiConsole::CheckMenuViewToggle(ImGuiKey_F8, m_showStateShare))
{
return;
}
m_stateShare.draw(m_showStateShare);
+23 -13
View File
@@ -8,6 +8,8 @@ UserSettings g_userSettings = {
.enableFullscreen {"video.enableFullscreen", false},
.enableVsync {"video.enableVsync", true},
.lockAspectRatio {"video.lockAspectRatio", false},
.enableFpsOverlay {"game.enableFpsOverlay", false},
.fpsOverlayCorner {"game.fpsOverlayCorner", 0},
},
.audio = {
@@ -45,9 +47,9 @@ UserSettings g_userSettings = {
// Preferences
.enableMirrorMode {"game.enableMirrorMode", false},
.disableMainHUD {"game.disableMainHUD", false},
.minimalHUD {"game.minimalHUD", false},
.pauseOnFocusLost {"game.pauseOnFocusLost", false},
.enableLinkDollRotation = {"game.enableLinkDollRotation", false},
.enableLinkDollRotation {"game.enableLinkDollRotation", false},
.enableAchievementNotifications {"game.enableAchievementNotifications", true},
// Graphics
@@ -79,18 +81,19 @@ UserSettings g_userSettings = {
.invertCameraYAxis {"game.invertCameraYAxis", false},
.freeCameraSensitivity {"game.freeCameraSensitivity", 1.0f},
.debugFlyCam {"game.debugFlyCam", false},
.debugFlyCamLockEvents {"game.debugFlyCamLockEvents", true},
// Cheats
.infiniteHearts {"game.infiniteHearts", false},
.infiniteArrows{"game.infiniteArrows", false},
.infiniteBombs{"game.infiniteBombs", false},
.infiniteOil{"game.infiniteOil", false},
.infiniteOxygen{"game.infiniteOxygen", false},
.infiniteRupees{"game.infiniteRupees", false},
.infiniteArrows {"game.infiniteArrows", false},
.infiniteBombs {"game.infiniteBombs", false},
.infiniteOil {"game.infiniteOil", false},
.infiniteOxygen {"game.infiniteOxygen", false},
.infiniteRupees {"game.infiniteRupees", false},
.enableIndefiniteItemDrops {"game.enableIndefiniteItemDrops", false},
.moonJump{"game.moonJump", false},
.superClawshot{"game.superClawshot", false},
.alwaysGreatspin{"game.alwaysGreatspin", false},
.moonJump {"game.moonJump", false},
.superClawshot {"game.superClawshot", false},
.alwaysGreatspin {"game.alwaysGreatspin", false},
.enableFastIronBoots {"game.enableFastIronBoots", false},
.canTransformAnywhere {"game.canTransformAnywhere", false},
.fastSpinner {"game.fastSpinner", false},
@@ -104,7 +107,8 @@ UserSettings g_userSettings = {
// Tools
.speedrunMode {"game.speedrunMode", false},
.liveSplitEnabled {"game.liveSplitEnabled", false}
.liveSplitEnabled {"game.liveSplitEnabled", false},
.recordingMode {"game.recordingMode", false}
},
.backend = {
@@ -115,7 +119,8 @@ UserSettings g_userSettings = {
.showPipelineCompilation {"backend.showPipelineCompilation", false},
.wasPresetChosen {"backend.wasPresetChosen", false},
.enableCrashReporting {"backend.enableCrashReporting", true},
.cardFileType {"backend.cardFileType", static_cast<int>(CARD_GCIFOLDER)}
.cardFileType {"backend.cardFileType", static_cast<int>(CARD_GCIFOLDER)},
.enableAdvancedSettings {"backend.enableAdvancedSettings", false},
}
};
@@ -128,6 +133,8 @@ void registerSettings() {
Register(g_userSettings.video.enableFullscreen);
Register(g_userSettings.video.enableVsync);
Register(g_userSettings.video.lockAspectRatio);
Register(g_userSettings.video.enableFpsOverlay);
Register(g_userSettings.video.fpsOverlayCorner);
// Audio
Register(g_userSettings.audio.masterVolume);
@@ -161,7 +168,7 @@ void registerSettings() {
Register(g_userSettings.game.invertCameraXAxis);
Register(g_userSettings.game.invertCameraYAxis);
Register(g_userSettings.game.freeCameraSensitivity);
Register(g_userSettings.game.disableMainHUD);
Register(g_userSettings.game.minimalHUD);
Register(g_userSettings.game.pauseOnFocusLost);
Register(g_userSettings.game.bloomMode);
Register(g_userSettings.game.bloomMultiplier);
@@ -182,6 +189,7 @@ void registerSettings() {
Register(g_userSettings.game.enableTurboKeybind);
Register(g_userSettings.game.speedrunMode);
Register(g_userSettings.game.liveSplitEnabled);
Register(g_userSettings.game.recordingMode);
Register(g_userSettings.game.fastSpinner);
Register(g_userSettings.game.infiniteHearts);
Register(g_userSettings.game.infiniteArrows);
@@ -205,6 +213,7 @@ void registerSettings() {
Register(g_userSettings.game.gyroInvertYaw);
Register(g_userSettings.game.freeCamera);
Register(g_userSettings.game.debugFlyCam);
Register(g_userSettings.game.debugFlyCamLockEvents);
Register(g_userSettings.backend.isoPath);
Register(g_userSettings.backend.isoVerification);
@@ -214,6 +223,7 @@ void registerSettings() {
Register(g_userSettings.backend.wasPresetChosen);
Register(g_userSettings.backend.enableCrashReporting);
Register(g_userSettings.backend.cardFileType);
Register(g_userSettings.backend.enableAdvancedSettings);
}
// Transient settings
+1 -1
View File
@@ -41,7 +41,7 @@ Rml::String build_achievement_info_rml(const Achievement& a) {
if (a.isCounter) {
float fraction = a.goal > 0 ? float(a.progress) / float(a.goal) : 1.0f;
s += fmt::format(
R"(<progressbar value="{:.3f}" class="{}"/>)"
R"(<progress value="{:.3f}" class="{}"/>)"
R"(<span class="achievement-progress">{} / {}</span>)",
fraction,
a.unlocked ? "progress-done" : "progress-ongoing",
+174 -6
View File
@@ -3,7 +3,7 @@
#include "bool_button.hpp"
#include "button.hpp"
#include "pane.hpp"
#include "select_button.hpp"
#include "number_button.hpp"
#include <SDL3/SDL_gamepad.h>
#include <SDL3/SDL_keyboard.h>
@@ -279,6 +279,18 @@ s32 keyboard_key_pressed() {
return PAD_KEY_INVALID;
}
u16 percent_to_raw(int percent) {
return static_cast<u16>((static_cast<float>(percent) / 100.f) * 32767.f);
}
int deadzone_raw_to_percent(u16 raw) {
return static_cast<int>((static_cast<float>(raw) * 100.f) / 32767.f + 0.5f);
}
int rumble_raw_to_percent(u16 raw) {
return static_cast<int>((static_cast<float>(raw) / 32767.f) * 100.f + 0.5f);
}
} // namespace
ControllerConfigWindow::ControllerConfigWindow() {
@@ -308,6 +320,7 @@ ControllerConfigWindow::ControllerConfigWindow() {
}
void ControllerConfigWindow::hide(bool close) {
stop_rumble_test();
cancel_pending_binding();
Window::hide(close);
}
@@ -318,16 +331,18 @@ void ControllerConfigWindow::update() {
}
void ControllerConfigWindow::build_port_tab(Rml::Element* content, int port) {
stop_rumble_test();
auto& leftPane = add_child<Pane>(content, Pane::Type::Controlled);
auto& rightPane = add_child<Pane>(content, Pane::Type::Uncontrolled);
mRightPane = &rightPane;
mActivePort = port;
auto addPageButton = [this, &leftPane, &rightPane, port](
Page page, Rml::String key, auto getValue) {
Page page, Rml::String key, auto getValue, auto isDisabled) {
leftPane.register_control(leftPane.add_select_button({
.key = std::move(key),
.getValue = std::move(getValue),
.isDisabled = std::move(isDisabled),
}),
rightPane, [this, port, page](Pane& pane) {
mPage = page;
@@ -335,10 +350,11 @@ void ControllerConfigWindow::build_port_tab(Rml::Element* content, int port) {
});
};
addPageButton(Page::Controller, "Controller", [port] { return current_controller_name(port); });
addPageButton(Page::Buttons, "Buttons", [] { return Rml::String(">"); });
addPageButton(Page::Triggers, "Triggers", [] { return Rml::String(">"); });
addPageButton(Page::Sticks, "Sticks", [] { return Rml::String(">"); });
addPageButton(Page::Controller, "Controller", [port] { return current_controller_name(port); }, [] { return false; });
addPageButton(Page::Buttons, "Buttons", [] { return Rml::String(">"); }, [] { return false; });
addPageButton(Page::Triggers, "Triggers", [] { return Rml::String(">"); }, [] { return false; });
addPageButton(Page::Sticks, "Sticks", [] { return Rml::String(">"); }, [] { return false; });
addPageButton(Page::Rumble, "Rumble", [] { return Rml::String(">"); }, [port] { return !PADSupportsRumbleIntensity(static_cast<u32>(port)); });
leftPane.add_section("Options");
leftPane.register_control(leftPane.add_child<BoolButton>(BoolButton::Props{
@@ -684,6 +700,38 @@ void ControllerConfigWindow::render_page(Pane& pane, int port, Page page) {
});
}
}
if (PADDeadZones* deadZones = PADGetDeadZones(port)) {
pane.add_section("Emulated Trigger Thresholds");
pane.add_child<NumberButton>(NumberButton::Props{
.key = "L Threshold",
.getValue = [deadZones] { return deadzone_raw_to_percent(deadZones->leftTriggerActivationZone); },
.setValue =
[deadZones](int value) {
deadZones->leftTriggerActivationZone = percent_to_raw(value);
PADSerializeMappings();
},
.isDisabled = [deadZones] { return !deadZones->emulateTriggers; },
.min = 0,
.max = 100,
.step = 1,
.suffix = "%",
});
pane.add_child<NumberButton>(NumberButton::Props{
.key = "R Threshold",
.getValue = [deadZones] { return deadzone_raw_to_percent(deadZones->rightTriggerActivationZone); },
.setValue =
[deadZones](int value) {
deadZones->rightTriggerActivationZone = percent_to_raw(value);
PADSerializeMappings();
},
.isDisabled = [deadZones] { return !deadZones->emulateTriggers; },
.min = 0,
.max = 100,
.step = 1,
.suffix = "%",
});
}
break;
}
case Page::Sticks: {
@@ -769,12 +817,121 @@ void ControllerConfigWindow::render_page(Pane& pane, int port, Page page) {
addAxis(PAD_AXIS_LEFT_Y_NEG);
addAxis(PAD_AXIS_LEFT_X_NEG);
addAxis(PAD_AXIS_LEFT_X_POS);
if (PADDeadZones* deadZones = PADGetDeadZones(port)) {
pane.add_child<NumberButton>(NumberButton::Props{
.key = "Deadzone",
.getValue = [deadZones] { return deadzone_raw_to_percent(deadZones->stickDeadZone); },
.setValue =
[deadZones](int value) {
deadZones->stickDeadZone = percent_to_raw(value);
PADSerializeMappings();
},
.isDisabled = [deadZones] { return !deadZones->useDeadzones; },
.min = 0,
.max = 100,
.step = 1,
.suffix = "%",
});
}
pane.add_section("C Stick");
addAxis(PAD_AXIS_RIGHT_Y_POS);
addAxis(PAD_AXIS_RIGHT_Y_NEG);
addAxis(PAD_AXIS_RIGHT_X_NEG);
addAxis(PAD_AXIS_RIGHT_X_POS);
if (PADDeadZones* deadZones = PADGetDeadZones(port)) {
pane.add_child<NumberButton>(NumberButton::Props{
.key = "Deadzone",
.getValue = [deadZones] { return deadzone_raw_to_percent(deadZones->substickDeadZone); },
.setValue =
[deadZones](int value) {
deadZones->substickDeadZone = percent_to_raw(value);
PADSerializeMappings();
},
.isDisabled = [deadZones] { return !deadZones->useDeadzones; },
.min = 0,
.max = 100,
.step = 1,
.suffix = "%",
});
}
break;
}
case Page::Rumble: {
auto& rumbleTest = pane.add_select_button({
.key = "Test Rumble",
.getValue =
[this, port] {
return (mRumbleTestActive && mRumbleTestPort == port) ? Rml::String("Stop")
: Rml::String("Start");
},
});
rumbleTest.on_pressed([this, port] {
if (!PADSupportsRumbleIntensity(static_cast<u32>(port))) {
return;
}
mDoAud_seStartMenu(kSoundItemChange);
if (mRumbleTestActive && mRumbleTestPort == port) {
PADControlMotor(port, PAD_MOTOR_STOP_HARD);
mRumbleTestActive = false;
mRumbleTestPort = -1;
} else {
if (mRumbleTestActive) {
PADControlMotor(mRumbleTestPort, PAD_MOTOR_STOP_HARD);
}
PADControlMotor(port, PAD_MOTOR_RUMBLE);
mRumbleTestActive = true;
mRumbleTestPort = port;
}
});
pane.add_child<NumberButton>(NumberButton::Props{
.key = "Low Rumble Frequency",
.getValue =
[port] {
u16 low = 0;
u16 high = 0;
PADGetRumbleIntensity(static_cast<u32>(port), &low, &high);
return rumble_raw_to_percent(low);
},
.setValue =
[port](int value) {
u16 low = 0;
u16 high = 0;
PADGetRumbleIntensity(static_cast<u32>(port), &low, &high);
PADSetRumbleIntensity(static_cast<u32>(port), percent_to_raw(value), high);
PADSerializeMappings();
},
.isDisabled = [this] { return mRumbleTestActive; },
.min = 0,
.max = 100,
.step = 1,
.suffix = "%",
});
pane.add_child<NumberButton>(NumberButton::Props{
.key = "High Rumble Frequency",
.getValue =
[port] {
u16 low = 0;
u16 high = 0;
PADGetRumbleIntensity(static_cast<u32>(port), &low, &high);
return rumble_raw_to_percent(high);
},
.setValue =
[port](int value) {
u16 low = 0;
u16 high = 0;
PADGetRumbleIntensity(static_cast<u32>(port), &low, &high);
PADSetRumbleIntensity(static_cast<u32>(port), low, percent_to_raw(value));
PADSerializeMappings();
},
.isDisabled = [this] { return mRumbleTestActive; },
.min = 0,
.max = 100,
.step = 1,
.suffix = "%",
});
pane.add_text("Configure your desired rumble intensities, then run a test to check how they feel.");
break;
}
}
@@ -938,4 +1095,15 @@ Rml::String ControllerConfigWindow::pending_key_label() const {
return mPendingBindingArmed ? "Press a key or mouse button..." : "Waiting...";
}
void ControllerConfigWindow::stop_rumble_test() {
if (!mRumbleTestActive) {
return;
}
if (mRumbleTestPort >= PAD_CHAN0 && mRumbleTestPort < PAD_CHANMAX) {
PADControlMotor(mRumbleTestPort, PAD_MOTOR_STOP_HARD);
}
mRumbleTestActive = false;
mRumbleTestPort = -1;
}
} // namespace dusk::ui
+4
View File
@@ -19,6 +19,7 @@ private:
Buttons,
Triggers,
Sticks,
Rumble,
};
void build_port_tab(Rml::Element* content, int port);
@@ -34,6 +35,7 @@ private:
void cancel_pending_binding();
void finish_pending_key_binding();
Rml::String pending_key_label() const;
void stop_rumble_test();
Page mPage = Page::Controller;
Pane* mRightPane = nullptr;
@@ -46,6 +48,8 @@ private:
PADAxisMapping* mPendingAxisMapping = nullptr;
int mPendingKeyButton = -1;
int mPendingKeyAxis = -1;
bool mRumbleTestActive = false;
int mRumbleTestPort = -1;
};
} // namespace dusk::ui
+13 -5
View File
@@ -91,18 +91,23 @@ Rml::Element* create_stepped_carousel_arrow(
return parent->AppendChild(std::move(button));
}
void update_carousel_arrow_color(Rml::Element* arrow, bool dim) {
const Rml::Colourb& color = Rml::Colourb(255, 255, 255, dim ? 128 : 255);
arrow->SetProperty(Rml::PropertyId::Color, Rml::Property(color, Rml::Unit::COLOUR));
}
} // namespace
SteppedCarousel::SteppedCarousel(Rml::Element* parent, Props props)
: Component(create_stepped_carousel_root(parent)), mProps(std::move(props)) {
Rml::Element* prevElem = create_stepped_carousel_arrow(mRoot, "prev", "&#xe5cb;");
mPrevElem = create_stepped_carousel_arrow(mRoot, "prev", "&#xe5cb;");
mValueElem = append(mRoot, "div");
mValueElem->SetClass("stepped-carousel-value", true);
Rml::Element* nextElem = create_stepped_carousel_arrow(mRoot, "next", "&#xe5cc;");
mNextElem = create_stepped_carousel_arrow(mRoot, "next", "&#xe5cc;");
listen(prevElem, Rml::EventId::Click,
listen(mPrevElem, Rml::EventId::Click,
[this](Rml::Event&) { handle_nav_command(NavCommand::Left); });
listen(nextElem, Rml::EventId::Click,
listen(mNextElem, Rml::EventId::Click,
[this](Rml::Event&) { handle_nav_command(NavCommand::Right); });
listen(mRoot, Rml::EventId::Keydown, [this](Rml::Event& event) {
const auto cmd = map_nav_event(event);
@@ -126,6 +131,9 @@ void SteppedCarousel::update() {
} else {
mValueElem->SetInnerRML(std::to_string(value));
}
update_carousel_arrow_color(mPrevElem, value == mProps.min);
update_carousel_arrow_color(mNextElem, value == mProps.max);
}
bool SteppedCarousel::handle_nav_command(NavCommand cmd) {
@@ -280,4 +288,4 @@ void GraphicsTuner::reset_default() {
set_value(mOption, mDefaultValue);
}
} // namespace dusk::ui
} // namespace dusk::ui
+2
View File
@@ -34,6 +34,8 @@ private:
void apply(int value);
Props mProps;
Rml::Element* mPrevElem = nullptr;
Rml::Element* mNextElem = nullptr;
Rml::Element* mValueElem = nullptr;
};
+59 -7
View File
@@ -13,6 +13,7 @@
#include "f_pc/f_pc_manager.h"
#include "f_pc/f_pc_name.h"
#include "imgui.h"
#include "modal.hpp"
#include "settings.hpp"
#include "ui.hpp"
#include "window.hpp"
@@ -50,17 +51,68 @@ MenuBar::MenuBar() : Document(kDocumentSource), mRoot(mDocument->GetElementById(
// mTabBar->add_tab("Warp", [] {
// // TODO
// });
mTabBar->add_tab("Editor", [this] { push(std::make_unique<EditorWindow>()); });
if (getSettings().backend.enableAdvancedSettings) {
mTabBar->add_tab("Editor", [this] { push(std::make_unique<EditorWindow>()); });
}
mTabBar->add_tab("Achievements", [this] { push(std::make_unique<AchievementsWindow>()); });
mTabBar->add_tab("Reset", [this] {
mTabBar->set_active_tab(-1);
if (fpcM_SearchByName(fpcNm_LOGO_SCENE_e)) {
return;
}
JUTGamePad::C3ButtonReset::sResetSwitchPushing = true;
hide(false);
const auto dismiss = [](Modal& modal) { modal.pop(); };
push(std::make_unique<Modal>(Modal::Props{
.title = "Reset Game",
.bodyRml = "Unsaved progress will be lost.<br/>"
"<span class=\"tip\">Tip: You can also reset by holding Start+X+B</span>",
.actions =
{
ModalAction{
.label = "Cancel",
.onPressed = dismiss,
},
ModalAction{
.label = "Reset",
.onPressed =
[this, dismiss](Modal& modal) {
if (fpcM_SearchByName(fpcNm_LOGO_SCENE_e)) {
dismiss(modal);
return;
}
JUTGamePad::C3ButtonReset::sResetSwitchPushing = true;
dismiss(modal);
hide(false);
},
},
},
.onDismiss = dismiss,
.icon = "question-mark",
}));
});
mTabBar->add_tab("Quit", [this] {
mTabBar->set_active_tab(-1);
const auto dismiss = [](Modal& modal) { modal.pop(); };
push(std::make_unique<Modal>(Modal::Props{
.title = "Quit Dusk",
.bodyRml = "Unsaved progress will be lost.",
.actions =
{
ModalAction{
.label = "Cancel",
.onPressed = dismiss,
},
ModalAction{
.label = "Quit",
.onPressed =
[dismiss](Modal& modal) {
dismiss(modal);
IsRunning = false;
},
},
},
.onDismiss = dismiss,
.icon = "question-mark",
}));
});
mTabBar->add_tab("Quit", [] { IsRunning = false; });
// Hide document after transition completion
listen(mRoot, Rml::EventId::Transitionend, [this](Rml::Event& event) {
+2 -5
View File
@@ -14,12 +14,9 @@ Modal::Modal(Props props) : WindowSmall("modal", "modal-dialog"), mProps(std::mo
title->SetClass("modal-title", true);
title->SetInnerRML(mProps.title);
if (mProps.isWarning) {
if (!mProps.icon.empty()) {
auto* icon = append(header, "icon");
icon->SetClass("warning", true);
} else if (mProps.isError) {
auto* icon = append(header, "icon");
icon->SetClass("error", true);
icon->SetClass(mProps.icon, true);
}
auto* body = append(mDialog, "div");
+1 -2
View File
@@ -19,8 +19,7 @@ public:
std::vector<ModalAction> actions;
std::function<void(Modal&)> onDismiss;
Rml::String variant;
bool isWarning = false;
bool isError = false;
Rml::String icon = "";
};
explicit Modal(Props props);
+2
View File
@@ -2,6 +2,8 @@
#include "string_button.hpp"
#include <climits>
namespace dusk::ui {
class NumberButton : public BaseStringButton {
+70
View File
@@ -6,6 +6,7 @@
#include "window.hpp"
#include <SDL3/SDL_gamepad.h>
#include <SDL3/SDL_timer.h>
#include <algorithm>
#include <dolphin/pad.h>
@@ -19,6 +20,7 @@ const Rml::String kDocumentSource = R"RML(
<link type="text/rcss" href="res/rml/overlay.rcss" />
</head>
<body>
<fps id="fps" />
</body>
</rml>
)RML";
@@ -31,6 +33,8 @@ constexpr std::array<std::pair<const char*, const char*>, 3> kAutoSaveLayers{{
constexpr auto kMenuNotificationDuration = std::chrono::milliseconds(2500);
constexpr std::array<const char*, 4> kFpsCorners = { "tl", "tr", "bl", "br" };
Rml::Element* create_toast(Rml::Element* parent, const Toast& toast) {
if (toast.type == "autosave") {
auto* logo = append(parent, "logo");
@@ -153,7 +157,46 @@ void remove_element(Rml::Element*& elem) noexcept {
} // namespace
// https://vplesko.com/posts/how_to_implement_an_fps_counter.html
void Overlay::advance_fps_counter(float& outFps, Uint64 perfFreq) {
if (perfFreq == 0) {
outFps = 0.f;
return;
}
const Uint64 curr = SDL_GetPerformanceCounter();
if (!mFpsHavePrevCounter) {
mFpsPrevCounter = curr;
mFpsHavePrevCounter = true;
outFps = 0.f;
return;
}
const Uint64 processingTicks = curr - mFpsPrevCounter;
mFpsPrevCounter = curr;
mFpsFrameEvents.push_back({curr, processingTicks});
mFpsSumTicks += processingTicks;
while (!mFpsFrameEvents.empty() && mFpsFrameEvents.front().endCounter + perfFreq < curr) {
mFpsSumTicks -= mFpsFrameEvents.front().processingTicks;
mFpsFrameEvents.pop_front();
}
const auto n = mFpsFrameEvents.size();
if (n == 0 || mFpsSumTicks == 0) {
outFps = 0.f;
return;
}
const double avgSeconds =
static_cast<double>(mFpsSumTicks) / static_cast<double>(n) / static_cast<double>(perfFreq);
outFps = static_cast<float>(1.0 / avgSeconds);
}
Overlay::Overlay() : Document(kDocumentSource) {
mFpsCounter = mDocument->GetElementById("fps");
listen(mDocument, Rml::EventId::Focus, [](Rml::Event&) { Log.warn("Overlay received focus"); });
listen(mDocument, Rml::EventId::Transitionend, [this](Rml::Event& event) {
if (event.GetTargetElement() == mCurrentToast) {
@@ -187,6 +230,33 @@ void Overlay::update() {
return;
}
if (mFpsCounter != nullptr) {
if (getSettings().video.enableFpsOverlay.getValue()) {
const int idx = getSettings().video.fpsOverlayCorner.getValue();
mFpsCounter->SetAttribute("open", "");
mFpsCounter->SetAttribute("corner", kFpsCorners[idx]);
const Uint64 perfFreq = SDL_GetPerformanceFrequency();
float fps = 0.f;
advance_fps_counter(fps, perfFreq);
const Uint64 now = SDL_GetPerformanceCounter();
// Limit updates to twice per second
const bool refreshLabel = perfFreq == 0 || mFpsLastUpdate == 0 ||
static_cast<double>(now - mFpsLastUpdate) >= 0.5 * static_cast<double>(perfFreq);
if (refreshLabel) {
mFpsLastUpdate = now;
mFpsCounter->SetInnerRML(escape(fmt::format("{:.0f} FPS", fps)));
}
} else {
mFpsCounter->RemoveAttribute("open");
mFpsFrameEvents.clear();
mFpsSumTicks = 0;
mFpsHavePrevCounter = false;
mFpsLastUpdate = 0;
}
}
const bool showControllerWarning = PADGetIndexForPort(PAD_CHAN0) < 0 &&
PADGetKeyButtonBindings(PAD_CHAN0, nullptr) == nullptr &&
dynamic_cast<Window*>(top_document()) == nullptr &&
+15
View File
@@ -3,6 +3,7 @@
#include "document.hpp"
#include <chrono>
#include <deque>
namespace dusk::ui {
@@ -16,11 +17,25 @@ public:
protected:
bool handle_nav_command(Rml::Event& event, NavCommand cmd) override;
Rml::Element* mFpsCounter = nullptr;
Rml::Element* mCurrentToast = nullptr;
Rml::Element* mControllerWarning = nullptr;
Rml::Element* mMenuNotification = nullptr;
clock::time_point mCurrentToastStartTime;
clock::time_point mMenuNotificationStartTime;
struct FpsFrameEvent {
Uint64 endCounter;
Uint64 processingTicks;
};
std::deque<FpsFrameEvent> mFpsFrameEvents;
Uint64 mFpsSumTicks = 0;
bool mFpsHavePrevCounter = false;
Uint64 mFpsPrevCounter = 0;
Uint64 mFpsLastUpdate = 0;
void advance_fps_counter(float& outFps, Uint64 perfFreq);
};
} // namespace dusk::ui
+10 -1
View File
@@ -126,11 +126,20 @@ Component& Pane::register_control(
}
});
component.listen(component.root(), Rml::EventId::Focus,
[&component, &nextPane, callback = std::move(callback)](Rml::Event&) {
[this, &component, &nextPane, callback = std::move(callback)](Rml::Event&) {
if (component.disabled()) {
return;
}
nextPane.clear();
// If an item is already selected, deselect
for (const auto& child : mChildren) {
if (child->selected()) {
set_selected_item(-1);
break;
}
}
if (callback) {
callback(nextPane);
}
+4 -10
View File
@@ -278,7 +278,7 @@ public:
mFileName = append(content, "div");
mFileName->SetClass("verification-file", true);
mProgress = append(content, "progressbar");
mProgress = append(content, "progress");
mProgress->SetClass("progress-ongoing", true);
mProgress->SetClass("verification-progress-bar", true);
mProgress->SetAttribute("value", 0.f);
@@ -507,7 +507,7 @@ void try_push_verification_modal(Document& host) {
},
.onDismiss = dismiss,
.variant = "danger",
.isWarning = true,
.icon = "warning",
}));
return;
}
@@ -523,7 +523,7 @@ void try_push_verification_modal(Document& host) {
},
},
.onDismiss = dismiss,
.isError = true,
.icon = "error",
}));
}
@@ -610,9 +610,6 @@ Prelaunch::Prelaunch() : Document(kDocumentSource), mRoot(mDocument->GetElementB
}
IsGameLaunched = true;
if (!getSettings().backend.wasPresetChosen) {
push_document(std::make_unique<dusk::ui::PresetWindow>());
}
hide(true);
});
apply_intro_animation(mMenuButtons.back()->root(), "delay-1");
@@ -624,7 +621,7 @@ Prelaunch::Prelaunch() : Document(kDocumentSource), mRoot(mDocument->GetElementB
});
apply_intro_animation(mMenuButtons.back()->root(), "delay-2");
mMenuButtons.push_back(std::make_unique<Button>(menuList, "Quit To Desktop"));
mMenuButtons.push_back(std::make_unique<Button>(menuList, "Quit"));
mMenuButtons.back()->on_pressed([] { IsRunning = false; });
apply_intro_animation(mMenuButtons.back()->root(), "delay-3");
}
@@ -718,9 +715,6 @@ void Prelaunch::update() {
activeDiscLoaded && state.configuredDiscPath != state.activeDiscPath;
mDocument->SetClass("disc-ready", IsGameLaunched);
if (canLaunchConfiguredDisc) {
if (getSettings().backend.skipPreLaunchUI) {
hide(true);
}
IsGameLaunched = true;
}
+1
View File
@@ -43,6 +43,7 @@ void applyPresetDusk() {
s.game.internalResolutionScale.setValue(0);
s.game.shadowResolutionMultiplier.setValue(4);
s.game.enableGyroAim.setValue(true);
s.game.autoSave.setValue(true);
}
} // namespace
+97 -18
View File
@@ -10,6 +10,7 @@
#include "dusk/livesplit.h"
#include "graphics_tuner.hpp"
#include "m_Do/m_Do_main.h"
#include "menu_bar.hpp"
#include "number_button.hpp"
#include "pane.hpp"
#include "prelaunch.hpp"
@@ -33,6 +34,13 @@ constexpr std::array kCardFileTypes = {
"GCI Folder",
};
constexpr std::array kFpsOverlayCornerNames = {
"Top Left",
"Top Right",
"Bottom Left",
"Bottom Right",
};
bool try_parse_backend(std::string_view backend, AuroraBackend& outBackend) {
if (backend == "auto") {
outBackend = BACKEND_AUTO;
@@ -332,9 +340,7 @@ SettingsWindow::SettingsWindow(bool prelaunch) : mPrelaunch(prelaunch) {
.getValue =
[] {
const auto& state = prelaunch_state();
if (!state.configuredDiscCanLaunch ||
!state.configuredDiscInfo.isPal)
{
if (!state.configuredDiscCanLaunch || !state.configuredDiscInfo.isPal) {
return kLanguageNames[0];
}
const u8 idx = static_cast<u8>(getSettings().game.language.getValue());
@@ -430,7 +436,7 @@ SettingsWindow::SettingsWindow(bool prelaunch) : mPrelaunch(prelaunch) {
});
}
add_tab("Graphics", [this](Rml::Element* content) {
add_tab("Video", [this](Rml::Element* content) {
auto& leftPane = add_child<Pane>(content, Pane::Type::Controlled);
auto& rightPane = add_child<Pane>(content, Pane::Type::Uncontrolled);
@@ -472,6 +478,57 @@ SettingsWindow::SettingsWindow(bool prelaunch) : mPrelaunch(prelaunch) {
.key = "Pause on Focus Lost",
.isDisabled = [] { return IsMobile; },
});
leftPane.register_control(
leftPane.add_select_button({
.key = "Show FPS Counter",
.getValue =
[] {
if (!getSettings().video.enableFpsOverlay.getValue()) {
return Rml::String{"Off"};
}
const int idx = getSettings().video.fpsOverlayCorner.getValue();
return Rml::String{kFpsOverlayCornerNames[idx]};
},
.isModified =
[] {
const auto& enable = getSettings().video.enableFpsOverlay;
const auto& corner = getSettings().video.fpsOverlayCorner;
return enable.getValue() != enable.getDefaultValue() ||
(enable.getValue() && corner.getValue() != corner.getDefaultValue());
},
}),
rightPane, [](Pane& pane) {
pane.add_button(
{
.text = "Off",
.isSelected =
[] { return !getSettings().video.enableFpsOverlay.getValue(); },
})
.on_pressed([] {
mDoAud_seStartMenu(kSoundItemChange);
getSettings().video.enableFpsOverlay.setValue(false);
config::Save();
});
for (int i = 0; i < static_cast<int>(kFpsOverlayCornerNames.size()); ++i) {
pane.add_button(
{
.text = kFpsOverlayCornerNames[i],
.isSelected =
[i] {
return getSettings().video.enableFpsOverlay.getValue() &&
getSettings().video.fpsOverlayCorner.getValue() == i;
},
})
.on_pressed([i] {
mDoAud_seStartMenu(kSoundItemChange);
getSettings().video.enableFpsOverlay.setValue(true);
getSettings().video.fpsOverlayCorner.setValue(i);
config::Save();
});
}
pane.add_rml(
"<br/>Display the current framerate in a corner of the screen while playing.");
});
leftPane.add_section("Resolution");
graphics_tuner_control(*this, leftPane, rightPane,
@@ -687,8 +744,8 @@ SettingsWindow::SettingsWindow(bool prelaunch) : mPrelaunch(prelaunch) {
leftPane.add_section("General");
addOption("Mirror Mode", getSettings().game.enableMirrorMode,
"Mirrors the world horizontally, matching the Wii version of the game.");
addOption("Disable Main HUD", getSettings().game.disableMainHUD,
"Disables the main HUD of the game.<br/>Useful for recording or a more immersive "
addOption("Minimal HUD", getSettings().game.minimalHUD,
"Disables the elements of the main HUD of the game.<br/>Useful for a more immersive "
"experience.");
addOption("Restore Wii 1.0 Glitches", getSettings().game.restoreWiiGlitches,
"Restores patched glitches from Wii USA 1.0, the first released version.");
@@ -736,11 +793,8 @@ SettingsWindow::SettingsWindow(bool prelaunch) : mPrelaunch(prelaunch) {
config_bool_select(leftPane, rightPane, getSettings().game.autoSave,
{
.key = "Autosave",
.icon = "warning",
.helpText =
"Autosaves the game when going to a new area, opening a dungeon door, "
"or getting a new item.<br/><br/><icon class=\"warning\"/> Experimental "
"feature: Use at your own risk.",
.helpText = "Autosaves the game when going to a new area, opening a dungeon door, "
"or getting a new item.",
});
addOption("Instant Saves", getSettings().game.instantSaves,
"Skips the delay when writing to the Memory Card.");
@@ -828,11 +882,11 @@ SettingsWindow::SettingsWindow(bool prelaunch) : mPrelaunch(prelaunch) {
"Lets the magic armor work without consuming rupees.");
});
// TODO: Reorganize all of this?
add_tab("Interface", [this](Rml::Element* content) {
auto& leftPane = add_child<Pane>(content, Pane::Type::Controlled);
auto& rightPane = add_child<Pane>(content, Pane::Type::Uncontrolled);
leftPane.add_section("Dusk");
config_bool_select(leftPane, rightPane, getSettings().game.enableAchievementNotifications,
{
.key = "Achievement Notifications",
@@ -853,19 +907,44 @@ SettingsWindow::SettingsWindow(bool prelaunch) : mPrelaunch(prelaunch) {
config_bool_select(leftPane, rightPane, getSettings().backend.skipPreLaunchUI,
{
.key = "Skip Dusk Main Menu",
.helpText = "When starting Dusk, skips the main menu and boots straight into the "
.helpText = "When starting Dusk, skip the main menu and boot straight into the "
"game if a disc image is available.",
});
config_bool_select(leftPane, rightPane, getSettings().game.hideTvSettingsScreen,
{
.key = "Skip TV Settings Screen",
.helpText = "Skips the TV calibration screen shown when loading a save.",
});
config_bool_select(leftPane, rightPane, getSettings().backend.showPipelineCompilation,
{
.key = "Show Pipeline Compilation",
.helpText = "Show an overlay when shaders are being compiled for your hardware.",
});
config_bool_select(leftPane, rightPane, getSettings().backend.enableAdvancedSettings,
{
.key = "Enable Advanced Settings",
.icon = "warning",
.helpText = "Show advanced settings and debugging tools with "
"Shift+F1.<br/><br/><icon class=\"warning\"/> WARNING: Debugging tools "
"can easily break your game. Do not use on a regular save!",
.onChange =
[](bool) {
for (auto& doc : get_document_stack()) {
if (dynamic_cast<MenuBar*>(doc.get())) {
doc = std::make_unique<MenuBar>();
break;
}
}
},
});
leftPane.add_section("Game");
config_bool_select(leftPane, rightPane, getSettings().game.hideTvSettingsScreen,
{
.key = "Skip TV Settings Screen",
.helpText = "Skips the TV calibration screen shown when loading a save.",
});
config_bool_select(leftPane, rightPane, getSettings().game.recordingMode,
{
.key = "Recording Mode",
.helpText = "Disables the game HUD and all background music.<br/><br/>Useful for "
"recording footage.",
});
});
}
+11 -1
View File
@@ -212,6 +212,15 @@ bool TabBar::handle_nav_command(Rml::Event& event, NavCommand cmd) {
if (activeTab != -1) {
currentComponent = activeTab;
}
} else {
int activeTab = tab_containing(event.GetTargetElement());
if (activeTab != -1) {
currentComponent = activeTab;
} else if (mLastFocusedTabIndex >= 0 &&
mLastFocusedTabIndex < static_cast<int>(mTabs.size()))
{
currentComponent = mLastFocusedTabIndex;
}
}
int direction = isNext ? 1 : -1;
if (currentComponent == -1) {
@@ -221,8 +230,9 @@ bool TabBar::handle_nav_command(Rml::Event& event, NavCommand cmd) {
return false;
}
currentComponent = -1;
} else if (cmd == NavCommand::Next) {
currentComponent = -1;
} else {
// Next/Previous require a currently selected tab to navigate from
return false;
}
}
+4
View File
@@ -363,6 +363,10 @@ void push_toast(Toast toast) noexcept {
sToasts.push_back(std::move(toast));
}
std::vector<std::unique_ptr<Document> >& get_document_stack() noexcept {
return sDocumentStack;
}
std::deque<Toast>& get_toasts() noexcept {
return sToasts;
}
+2
View File
@@ -82,6 +82,8 @@ Rml::Element* append(Rml::Element* parent, const Rml::String& tag) noexcept;
NavCommand map_nav_event(const Rml::Event& event) noexcept;
Insets safe_area_insets(Rml::Context* context) noexcept;
std::vector<std::unique_ptr<Document> >& get_document_stack() noexcept;
void push_toast(Toast toast) noexcept;
std::deque<Toast>& get_toasts() noexcept;
void show_menu_notification() noexcept;
+4
View File
@@ -743,6 +743,10 @@ static void duskExecute() {
handleGamepadColor();
updateAutoSave();
if (dusk::getSettings().game.recordingMode) {
Z2GetSeqMgr()->bgmAllMute(0, 0);
}
if (mDoCPd_c::getHoldR(PAD_1) && mDoCPd_c::getTrigX(PAD_1)) {
if (const auto link = g_dComIfG_gameInfo.play.getPlayer(0)) {
dynamic_cast<daAlink_c*>(link)->handleWolfHowl();
+6
View File
@@ -56,6 +56,7 @@
#include "dusk/gx_helper.h"
#include "dusk/imgui/ImGuiConsole.hpp"
#include "dusk/logging.h"
#include "dusk/settings.h"
#endif
class mDoGph_HIO_c : public JORReflexible {
@@ -1172,6 +1173,11 @@ static void drawDepth2(view_class* param_0, view_port_class* param_1, int param_
}
static void trimming(view_class* param_0, view_port_class* param_1) {
#if TARGET_PC
if (dusk::getSettings().game.recordingMode) {
return;
}
#endif
ZoneScoped;
UNUSED(param_0);
+1 -1
View File
@@ -708,7 +708,7 @@ int game_main(int argc, char* argv[]) {
dComIfG_ct();
// Development Mode
mDoMain::developmentMode = 1; // Force Dev Mode for Debugging
// mDoMain::developmentMode = 1; // Force Dev Mode for Debugging
mDoDvdThd::SyncWidthSound = false;
OSReport("Starting main01 (Game Loop)...\n");