mirror of
https://github.com/TwilitRealm/dusklight
synced 2026-08-03 16:31:56 -04:00
feat: Make gamepad status lighting optional (#1705)
* feat: Status Lighting option * wip: rename to "Enable Controller LED" * wip: setting for all four ports individually * wip: fix detection + code cleanup * wip: increase led speed for dusk preset * wip: use aurora API * bump aurora to 2b07d55 * wip: remove isSupported + fix namespace comment * wip: add value override to BoolButton * Style nit & remove unused * Undo change --------- Co-authored-by: Luke Street <luke@street.dev>
This commit is contained in:
@@ -3,6 +3,9 @@
|
||||
#ifndef GAMEPAD_COLOR_H
|
||||
#define GAMEPAD_COLOR_H
|
||||
|
||||
void handleGamepadColor();
|
||||
namespace dusk::input {
|
||||
void handleGamepadColor();
|
||||
bool pad_has_led(int port) noexcept;
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -209,6 +209,7 @@ struct UserSettings {
|
||||
ConfigVar<bool> debugFlyCam;
|
||||
ConfigVar<bool> debugFlyCamLockEvents;
|
||||
ConfigVar<bool> allowBackgroundInput;
|
||||
std::array<ConfigVar<bool>, 4> enableLED;
|
||||
ConfigVar<bool> swapDirectSelect;
|
||||
|
||||
// Cheats
|
||||
|
||||
+100
-78
@@ -5,102 +5,124 @@
|
||||
#include <d/actor/d_a_alink.h>
|
||||
#include <dusk/gamepad_color.h>
|
||||
|
||||
cXyz currentGamepadColor = {0, 0, 0};
|
||||
cXyz finalGamepadColor = {0, 0, 0};
|
||||
cXyz additionalGamepadColor = {0, 0, 0};
|
||||
#include "ui/controller_config.hpp"
|
||||
|
||||
float lerpSpeed = 0.0f;
|
||||
#include <pad.h>
|
||||
|
||||
const cXyz duskColor = {50, 50, -50};
|
||||
const cXyz noColor = {0, 0, 0};
|
||||
namespace dusk::input {
|
||||
|
||||
cXyz LerpColor(cXyz a, cXyz b, float t) {
|
||||
return {std::lerp(a.x, b.x, t), std::lerp(a.y, b.y, t), std::lerp(a.z, b.z, t)};
|
||||
}
|
||||
namespace {
|
||||
cXyz currentColor = {0, 0, 0};
|
||||
float lerpSpeed = 0.0f;
|
||||
|
||||
void FadeLED(cXyz newColor, float speed) {
|
||||
finalGamepadColor = newColor;
|
||||
lerpSpeed = speed / 30.0f;
|
||||
}
|
||||
enum ColorVariations : u8 {
|
||||
NO_COLOR = 0,
|
||||
DUSK_COLOR = 1,
|
||||
ZHINT = 2,
|
||||
LINK_WOLF = 3,
|
||||
LINK_CASUAL = 4,
|
||||
LINK_KOKIRI = 5,
|
||||
LINK_ZORA = 6,
|
||||
LINK_MAGIC = 7,
|
||||
LINK_MAGIC_HEAVY = 8,
|
||||
};
|
||||
|
||||
void SetLED(cXyz newColor) {
|
||||
currentGamepadColor = newColor;
|
||||
finalGamepadColor = newColor;
|
||||
}
|
||||
struct ColorSetting {
|
||||
cXyz color;
|
||||
float speed;
|
||||
};
|
||||
|
||||
void SetGamepadAdditionalColor(cXyz addColor) {
|
||||
additionalGamepadColor.x = addColor.x;
|
||||
additionalGamepadColor.y = addColor.y;
|
||||
additionalGamepadColor.z = addColor.z;
|
||||
}
|
||||
const ColorSetting kColorTable[] = {
|
||||
/* 0: NO_COLOR */ { {0, 0, 0}, 2.0f },
|
||||
/* 1: DUSK_COLOR */ { {50, 50, -50}, 2.0f },
|
||||
/* 2: ZHINT */ { {50, 50, 175}, 2.0f },
|
||||
/* 3: LINK_WOLF */ { {115, 115, 75}, 5.0f },
|
||||
/* 4: LINK_CASUAL */ { {235, 230, 115}, 5.0f },
|
||||
/* 5: LINK_KOKIRI */ { {0, 100, 0}, 5.0f },
|
||||
/* 6: LINK_ZORA */ { {0, 0, 100}, 5.0f },
|
||||
/* 7: LINK_MAGIC */ { {100, 0, 5}, 5.0f },
|
||||
/* 8: LINK_MAGIC_HEAVY */ { {5, 100, 100}, 5.0f },
|
||||
};
|
||||
|
||||
void handleGamepadColor() {
|
||||
bool setColor = false;
|
||||
|
||||
fopAc_ac_c* zhint = dComIfGp_att_getZHint();
|
||||
if (zhint != NULL) {
|
||||
FadeLED({50, 50, 175}, 2.0f);
|
||||
setColor = true;
|
||||
cXyz LerpColor(const cXyz a, const cXyz b, const float t) {
|
||||
return {std::lerp(a.x, b.x, t), std::lerp(a.y, b.y, t), std::lerp(a.z, b.z, t)};
|
||||
}
|
||||
|
||||
daPy_py_c* player = daPy_getPlayerActorClass();
|
||||
daAlink_c* link = daAlink_getAlinkActorClass();
|
||||
void clamp(cXyz& color) {
|
||||
color.x = std::clamp(color.x, 0.0f, 255.0f);
|
||||
color.y = std::clamp(color.y, 0.0f, 255.0f);
|
||||
color.z = std::clamp(color.z, 0.0f, 255.0f);
|
||||
}
|
||||
|
||||
ColorSetting getColorSetting() {
|
||||
const fopAc_ac_c* zHint = dComIfGp_att_getZHint();
|
||||
if (zHint != nullptr) {
|
||||
return kColorTable[ZHINT];
|
||||
}
|
||||
|
||||
const daAlink_c* link = daAlink_getAlinkActorClass();
|
||||
|
||||
if (link == nullptr)
|
||||
return kColorTable[DUSK_COLOR];
|
||||
|
||||
if (link != nullptr && !setColor) {
|
||||
if (link->checkWolf()) {
|
||||
FadeLED({115, 115, 75}, 5.0f);
|
||||
setColor = true;
|
||||
} else {
|
||||
switch (dComIfGs_getSelectEquipClothes()) {
|
||||
case dItemNo_WEAR_KOKIRI_e:
|
||||
FadeLED({0, 100, 0}, 5.0f);
|
||||
setColor = true;
|
||||
break;
|
||||
case dItemNo_WEAR_ZORA_e:
|
||||
FadeLED({0, 0, 100}, 5.0f);
|
||||
setColor = true;
|
||||
break;
|
||||
case dItemNo_ARMOR_e:
|
||||
if (link->checkMagicArmorHeavy()) {
|
||||
FadeLED({5, 100, 100}, 5.0f);
|
||||
} else {
|
||||
FadeLED({100, 0, 5}, 5.0f);
|
||||
}
|
||||
setColor = true;
|
||||
break;
|
||||
case dItemNo_WEAR_CASUAL_e:
|
||||
FadeLED({235, 230, 115}, 5.0f);
|
||||
setColor = true;
|
||||
break;
|
||||
return kColorTable[LINK_WOLF];
|
||||
}
|
||||
|
||||
switch (dComIfGs_getSelectEquipClothes()) {
|
||||
case dItemNo_WEAR_KOKIRI_e:
|
||||
return kColorTable[LINK_KOKIRI];
|
||||
case dItemNo_WEAR_ZORA_e:
|
||||
return kColorTable[LINK_ZORA];
|
||||
case dItemNo_ARMOR_e:
|
||||
if (link->checkMagicArmorHeavy()) {
|
||||
return kColorTable[LINK_MAGIC_HEAVY];
|
||||
}
|
||||
|
||||
return kColorTable[LINK_MAGIC];
|
||||
case dItemNo_WEAR_CASUAL_e:
|
||||
return kColorTable[LINK_CASUAL];
|
||||
default:
|
||||
return kColorTable[LINK_KOKIRI];
|
||||
}
|
||||
}
|
||||
|
||||
if (dKy_darkworld_check()) {
|
||||
SetGamepadAdditionalColor(duskColor);
|
||||
} else {
|
||||
SetGamepadAdditionalColor(noColor);
|
||||
cXyz getAdditionalColor() {
|
||||
if (dKy_darkworld_check()) {
|
||||
return kColorTable[DUSK_COLOR].color;
|
||||
}
|
||||
|
||||
return kColorTable[NO_COLOR].color;
|
||||
}
|
||||
|
||||
f32 finalRed = finalGamepadColor.x + additionalGamepadColor.x;
|
||||
f32 finalGreen = finalGamepadColor.y + additionalGamepadColor.y;
|
||||
f32 finalBlue = finalGamepadColor.z + additionalGamepadColor.z;
|
||||
} // namespace
|
||||
|
||||
if (finalRed > 255)
|
||||
finalRed = 255;
|
||||
if (finalRed < 0)
|
||||
finalRed = 0;
|
||||
bool pad_has_led(const int port) noexcept {
|
||||
if (port > PAD_MAX_CONTROLLERS || port < 0)
|
||||
return false;
|
||||
|
||||
if (finalGreen > 255)
|
||||
finalGreen = 255;
|
||||
if (finalGreen < 0)
|
||||
finalGreen = 0;
|
||||
return PADHasLED(port);
|
||||
}
|
||||
|
||||
if (finalBlue > 255)
|
||||
finalBlue = 255;
|
||||
if (finalBlue < 0)
|
||||
finalBlue = 0;
|
||||
void handleGamepadColor() {
|
||||
auto [color, speed] = getColorSetting();
|
||||
const cXyz additionalColor = getAdditionalColor();
|
||||
cXyz finalColor = color + additionalColor;
|
||||
lerpSpeed = speed / 30.0f;
|
||||
|
||||
currentGamepadColor = LerpColor(currentGamepadColor, cXyz{finalRed, finalGreen, finalBlue}, lerpSpeed);
|
||||
PADSetColor(PAD_CHAN0, (u8)currentGamepadColor.x, (u8)currentGamepadColor.y, (u8)currentGamepadColor.z);
|
||||
}
|
||||
clamp(finalColor);
|
||||
currentColor = LerpColor(currentColor, finalColor, lerpSpeed);
|
||||
|
||||
for (int i = 0; i < 4; i++) {
|
||||
if (pad_has_led(i) && getSettings().game.enableLED[i]) {
|
||||
PADSetColor(
|
||||
i,
|
||||
static_cast<u8>(currentColor.x),
|
||||
static_cast<u8>(currentColor.y),
|
||||
static_cast<u8>(currentColor.z)
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace dusk::input
|
||||
@@ -97,6 +97,12 @@ UserSettings g_userSettings = {
|
||||
.debugFlyCam {"game.debugFlyCam", false},
|
||||
.debugFlyCamLockEvents {"game.debugFlyCamLockEvents", true},
|
||||
.allowBackgroundInput {"game.allowBackgroundInput", true},
|
||||
.enableLED {
|
||||
ConfigVar<bool>{"game.enableLED_port0", true},
|
||||
ConfigVar<bool>{"game.enableLED_port1", true},
|
||||
ConfigVar<bool>{"game.enableLED_port2", true},
|
||||
ConfigVar<bool>{"game.enableLED_port3", true},
|
||||
},
|
||||
.swapDirectSelect {"game.swapDirectSelect", false},
|
||||
|
||||
// Cheats
|
||||
@@ -289,6 +295,10 @@ void registerSettings() {
|
||||
Register(g_userSettings.game.debugFlyCam);
|
||||
Register(g_userSettings.game.debugFlyCamLockEvents);
|
||||
Register(g_userSettings.game.allowBackgroundInput);
|
||||
Register(g_userSettings.game.enableLED[0]);
|
||||
Register(g_userSettings.game.enableLED[1]);
|
||||
Register(g_userSettings.game.enableLED[2]);
|
||||
Register(g_userSettings.game.enableLED[3]);
|
||||
Register(g_userSettings.game.swapDirectSelect);
|
||||
|
||||
Register(g_userSettings.backend.isoPath);
|
||||
|
||||
@@ -12,7 +12,8 @@ BoolButton::BoolButton(Rml::Element* parent, Props props)
|
||||
.icon = std::move(props.icon),
|
||||
}),
|
||||
mGetValue(std::move(props.getValue)), mSetValue(std::move(props.setValue)),
|
||||
mIsDisabled(std::move(props.isDisabled)), mIsModified(std::move(props.isModified)) {}
|
||||
mIsDisabled(std::move(props.isDisabled)), mIsModified(std::move(props.isModified)),
|
||||
mValueOverride(std::move(props.valueOverride)) {}
|
||||
|
||||
bool BoolButton::modified() const {
|
||||
if (mIsModified) {
|
||||
@@ -29,6 +30,12 @@ bool BoolButton::disabled() const {
|
||||
}
|
||||
|
||||
Rml::String BoolButton::format_value() {
|
||||
if (mValueOverride) {
|
||||
if (std::string value = mValueOverride(); !value.empty()) {
|
||||
return value;
|
||||
}
|
||||
}
|
||||
|
||||
return mGetValue() ? "On" : "Off";
|
||||
}
|
||||
|
||||
|
||||
@@ -12,6 +12,7 @@ public:
|
||||
std::function<void(bool)> setValue;
|
||||
std::function<bool()> isDisabled;
|
||||
std::function<bool()> isModified;
|
||||
std::function<Rml::String()> valueOverride;
|
||||
};
|
||||
|
||||
BoolButton(Rml::Element* parent, Props props);
|
||||
@@ -28,6 +29,7 @@ private:
|
||||
std::function<void(int)> mSetValue;
|
||||
std::function<bool()> mIsDisabled;
|
||||
std::function<bool()> mIsModified;
|
||||
std::function<Rml::String()> mValueOverride;
|
||||
};
|
||||
|
||||
} // namespace dusk::ui
|
||||
|
||||
@@ -17,6 +17,7 @@
|
||||
|
||||
#include "dusk/action_bindings.h"
|
||||
#include "dusk/config.hpp"
|
||||
#include "dusk/gamepad_color.h"
|
||||
|
||||
namespace dusk::ui {
|
||||
namespace {
|
||||
@@ -254,7 +255,9 @@ ControllerConfigWindow::ControllerConfigWindow(bool prelaunch) {
|
||||
event.StopPropagation();
|
||||
}
|
||||
},
|
||||
true);
|
||||
true
|
||||
);
|
||||
|
||||
if (auto* context = mDocument != nullptr ? mDocument->GetContext() : nullptr) {
|
||||
if (auto* root = context->GetRootElement()) {
|
||||
mListeners.emplace_back(std::make_unique<ScopedEventListener>(
|
||||
@@ -312,6 +315,28 @@ void ControllerConfigWindow::build_port_tab(Rml::Element* content, int port) {
|
||||
addPageButton(Page::Actions, "Custom Action Bindings", [] {return Rml::String(">"); }, [] { return false; });
|
||||
|
||||
leftPane.add_section("Options");
|
||||
leftPane.register_control(leftPane.add_child<BoolButton>(BoolButton::Props{
|
||||
.key = "Enable LED Status",
|
||||
.getValue =
|
||||
[port] {
|
||||
return getSettings().game.enableLED[port].getValue();
|
||||
},
|
||||
.setValue =
|
||||
[port](const bool value) {
|
||||
getSettings().game.enableLED[port].setValue(value);
|
||||
},
|
||||
.isDisabled = [port] {
|
||||
return !input::pad_has_led(port);
|
||||
},
|
||||
.valueOverride = [port] {
|
||||
if (!input::pad_has_led(port))
|
||||
return "Not Supported";
|
||||
|
||||
return "";
|
||||
}}),
|
||||
rightPane, [](Pane& pane) {
|
||||
pane.add_text("Sets the controller's lighting color based on the game's state.");
|
||||
});
|
||||
leftPane.register_control(leftPane.add_child<BoolButton>(BoolButton::Props{
|
||||
.key = "Enable Dead Zones",
|
||||
.getValue =
|
||||
@@ -379,6 +404,7 @@ void ControllerConfigWindow::render_page(Pane& pane, int port, Page page) {
|
||||
PADSetKeyboardActive(static_cast<u32>(port), FALSE);
|
||||
PADSerializeMappings();
|
||||
ClearAllActionBindings(port);
|
||||
refresh_controller_page();
|
||||
});
|
||||
|
||||
pane.add_button({
|
||||
|
||||
@@ -743,7 +743,7 @@ static void fapGm_AfterRecord() {
|
||||
BOOL isRecording = false;
|
||||
|
||||
static void duskExecute() {
|
||||
handleGamepadColor();
|
||||
dusk::input::handleGamepadColor();
|
||||
updateAutoSave();
|
||||
|
||||
if (dusk::getSettings().game.recordingMode) {
|
||||
|
||||
Reference in New Issue
Block a user